diff --git a/.clang-format b/.clang-format index 0bbb1991defead..ccc9b93972a99e 100644 --- a/.clang-format +++ b/.clang-format @@ -82,11 +82,16 @@ ForEachMacros: - '__for_each_thread' - '__hlist_for_each_rcu' - '__map__for_each_symbol_by_name' + - '__pci_bus_for_each_res0' + - '__pci_bus_for_each_res1' + - '__pci_dev_for_each_res0' + - '__pci_dev_for_each_res1' - '__perf_evlist__for_each_entry' - '__perf_evlist__for_each_entry_reverse' - '__perf_evlist__for_each_entry_safe' - '__rq_for_each_bio' - '__shost_for_each_device' + - '__sym_for_each' - 'apei_estatus_for_each_section' - 'ata_for_each_dev' - 'ata_for_each_link' @@ -105,13 +110,12 @@ ForEachMacros: - 'bip_for_each_vec' - 'bond_for_each_slave' - 'bond_for_each_slave_rcu' - - 'bpf__perf_for_each_map' - - 'bpf__perf_for_each_map_named' + - 'bpf_for_each' + - 'bpf_for_each_reg_in_vstate' + - 'bpf_for_each_reg_in_vstate_mask' - 'bpf_for_each_spilled_reg' - 'bpf_object__for_each_map' - 'bpf_object__for_each_program' - - 'bpf_object__for_each_safe' - - 'bpf_perf_object__for_each' - 'btree_for_each_safe128' - 'btree_for_each_safe32' - 'btree_for_each_safe64' @@ -119,6 +123,7 @@ ForEachMacros: - 'card_for_each_dev' - 'cgroup_taskset_for_each' - 'cgroup_taskset_for_each_leader' + - 'cpu_aggr_map__for_each_idx' - 'cpufreq_for_each_efficient_entry_idx' - 'cpufreq_for_each_entry' - 'cpufreq_for_each_entry_idx' @@ -128,11 +133,14 @@ ForEachMacros: - 'css_for_each_descendant_post' - 'css_for_each_descendant_pre' - 'damon_for_each_region' + - 'damon_for_each_region_from' - 'damon_for_each_region_safe' - 'damon_for_each_scheme' - 'damon_for_each_scheme_safe' - 'damon_for_each_target' - 'damon_for_each_target_safe' + - 'damos_for_each_filter' + - 'damos_for_each_filter_safe' - 'data__for_each_file' - 'data__for_each_file_new' - 'data__for_each_file_start' @@ -151,6 +159,8 @@ ForEachMacros: - 'drm_client_for_each_connector_iter' - 'drm_client_for_each_modeset' - 'drm_connector_for_each_possible_encoder' + - 'drm_exec_for_each_locked_object' + - 'drm_exec_for_each_locked_object_reverse' - 'drm_for_each_bridge_in_chain' - 'drm_for_each_connector_iter' - 'drm_for_each_crtc' @@ -162,22 +172,32 @@ ForEachMacros: - 'drm_for_each_plane' - 'drm_for_each_plane_mask' - 'drm_for_each_privobj' + - 'drm_gem_for_each_gpuva' + - 'drm_gem_for_each_gpuva_safe' + - 'drm_gpuva_for_each_op' + - 'drm_gpuva_for_each_op_from_reverse' + - 'drm_gpuva_for_each_op_safe' + - 'drm_gpuvm_for_each_va' + - 'drm_gpuvm_for_each_va_range' + - 'drm_gpuvm_for_each_va_range_safe' + - 'drm_gpuvm_for_each_va_safe' - 'drm_mm_for_each_hole' - 'drm_mm_for_each_node' - 'drm_mm_for_each_node_in_range' - 'drm_mm_for_each_node_safe' - 'dsa_switch_for_each_available_port' - 'dsa_switch_for_each_cpu_port' + - 'dsa_switch_for_each_cpu_port_continue_reverse' - 'dsa_switch_for_each_port' - 'dsa_switch_for_each_port_continue_reverse' - 'dsa_switch_for_each_port_safe' - 'dsa_switch_for_each_user_port' + - 'dsa_tree_for_each_cpu_port' - 'dsa_tree_for_each_user_port' + - 'dsa_tree_for_each_user_port_continue_reverse' - 'dso__for_each_symbol' - 'dsos__for_each_with_build_id' - 'elf_hash_for_each_possible' - - 'elf_section__for_each_rel' - - 'elf_section__for_each_rela' - 'elf_symtab__for_each_symbol' - 'evlist__for_each_cpu' - 'evlist__for_each_entry' @@ -186,12 +206,15 @@ ForEachMacros: - 'evlist__for_each_entry_reverse' - 'evlist__for_each_entry_safe' - 'flow_action_for_each' + - 'for_each_acpi_consumer_dev' - 'for_each_acpi_dev_match' - 'for_each_active_dev_scope' - 'for_each_active_drhd_unit' - 'for_each_active_iommu' - 'for_each_active_route' - 'for_each_aggr_pgid' + - 'for_each_and_bit' + - 'for_each_andnot_bit' - 'for_each_available_child_of_node' - 'for_each_bench' - 'for_each_bio' @@ -222,10 +245,13 @@ ForEachMacros: - 'for_each_compatible_node' - 'for_each_component_dais' - 'for_each_component_dais_safe' + - 'for_each_conduit' - 'for_each_console' - 'for_each_console_srcu' - 'for_each_cpu' - 'for_each_cpu_and' + - 'for_each_cpu_andnot' + - 'for_each_cpu_or' - 'for_each_cpu_wrap' - 'for_each_dapm_widgets' - 'for_each_dedup_cand' @@ -254,9 +280,11 @@ ForEachMacros: - 'for_each_free_mem_range' - 'for_each_free_mem_range_reverse' - 'for_each_func_rsrc' - - 'for_each_group_device' + - 'for_each_gpiochip_node' - 'for_each_group_evsel' + - 'for_each_group_evsel_head' - 'for_each_group_member' + - 'for_each_group_member_head' - 'for_each_hstate' - 'for_each_if' - 'for_each_inject_fn' @@ -273,6 +301,7 @@ ForEachMacros: - 'for_each_lru' - 'for_each_matching_node' - 'for_each_matching_node_and_match' + - 'for_each_media_entity_data_link' - 'for_each_mem_pfn_range' - 'for_each_mem_range' - 'for_each_mem_range_rev' @@ -281,6 +310,8 @@ ForEachMacros: - 'for_each_memory' - 'for_each_migratetype_order' - 'for_each_missing_reg' + - 'for_each_mle_subelement' + - 'for_each_mod_mem_type' - 'for_each_net' - 'for_each_net_continue_reverse' - 'for_each_net_rcu' @@ -288,6 +319,7 @@ ForEachMacros: - 'for_each_netdev_continue' - 'for_each_netdev_continue_rcu' - 'for_each_netdev_continue_reverse' + - 'for_each_netdev_dump' - 'for_each_netdev_feature' - 'for_each_netdev_in_bond_rcu' - 'for_each_netdev_rcu' @@ -308,6 +340,7 @@ ForEachMacros: - 'for_each_node_with_cpus' - 'for_each_node_with_property' - 'for_each_nonreserved_multicast_dest_pgid' + - 'for_each_numa_hop_mask' - 'for_each_of_allnodes' - 'for_each_of_allnodes_from' - 'for_each_of_cpu_node' @@ -326,6 +359,7 @@ ForEachMacros: - 'for_each_online_cpu' - 'for_each_online_node' - 'for_each_online_pgdat' + - 'for_each_or_bit' - 'for_each_path' - 'for_each_pci_bridge' - 'for_each_pci_dev' @@ -333,6 +367,7 @@ ForEachMacros: - 'for_each_physmem_range' - 'for_each_populated_zone' - 'for_each_possible_cpu' + - 'for_each_present_blessed_reg' - 'for_each_present_cpu' - 'for_each_prime_number' - 'for_each_prime_number_from' @@ -348,7 +383,8 @@ ForEachMacros: - 'for_each_property_of_node' - 'for_each_reg' - 'for_each_reg_filtered' - - 'for_each_registered_fb' + - 'for_each_reloc' + - 'for_each_reloc_from' - 'for_each_requested_gpio' - 'for_each_requested_gpio_in_range' - 'for_each_reserved_mem_range' @@ -357,10 +393,12 @@ ForEachMacros: - 'for_each_rtd_components' - 'for_each_rtd_cpu_dais' - 'for_each_rtd_dais' + - 'for_each_sband_iftype_data' - 'for_each_script' - 'for_each_sec' - 'for_each_set_bit' - 'for_each_set_bit_from' + - 'for_each_set_bit_wrap' - 'for_each_set_bitrange' - 'for_each_set_bitrange_from' - 'for_each_set_clump8' @@ -371,8 +409,8 @@ ForEachMacros: - 'for_each_sgtable_dma_sg' - 'for_each_sgtable_page' - 'for_each_sgtable_sg' - - 'for_each_shell_test' - 'for_each_sibling_event' + - 'for_each_sta_active_link' - 'for_each_subelement' - 'for_each_subelement_extid' - 'for_each_subelement_id' @@ -380,10 +418,15 @@ ForEachMacros: - 'for_each_subsystem' - 'for_each_supported_activate_fn' - 'for_each_supported_inject_fn' + - 'for_each_sym' - 'for_each_test' - 'for_each_thread' - 'for_each_token' - 'for_each_unicast_dest_pgid' + - 'for_each_valid_link' + - 'for_each_vif_active_link' + - 'for_each_vma' + - 'for_each_vma_range' - 'for_each_vsi' - 'for_each_wakeup_source' - 'for_each_zone' @@ -392,10 +435,12 @@ ForEachMacros: - 'func_for_each_insn' - 'fwnode_for_each_available_child_node' - 'fwnode_for_each_child_node' + - 'fwnode_for_each_parent_node' - 'fwnode_graph_for_each_endpoint' - 'gadget_for_each_ep' - 'genradix_for_each' - 'genradix_for_each_from' + - 'genradix_for_each_reverse' - 'hash_for_each' - 'hash_for_each_possible' - 'hash_for_each_possible_rcu' @@ -439,14 +484,9 @@ ForEachMacros: - 'in_dev_for_each_ifa_rcu' - 'in_dev_for_each_ifa_rtnl' - 'inet_bind_bucket_for_each' - - 'inet_lhash2_for_each_icsk' - - 'inet_lhash2_for_each_icsk_continue' - - 'inet_lhash2_for_each_icsk_rcu' - - 'interval_tree_for_each_double_span' - 'interval_tree_for_each_span' - 'intlist__for_each_entry' - 'intlist__for_each_entry_safe' - - 'iopt_for_each_contig_area' - 'kcore_copy__for_each_phdr' - 'key_for_each' - 'key_for_each_safe' @@ -483,28 +523,38 @@ ForEachMacros: - 'list_for_each_from' - 'list_for_each_prev' - 'list_for_each_prev_safe' + - 'list_for_each_rcu' + - 'list_for_each_reverse' - 'list_for_each_safe' - 'llist_for_each' - 'llist_for_each_entry' - 'llist_for_each_entry_safe' - 'llist_for_each_safe' + - 'lwq_for_each_safe' - 'map__for_each_symbol' - 'map__for_each_symbol_by_name' - - 'map_for_each_event' - - 'map_for_each_metric' - 'maps__for_each_entry' - 'maps__for_each_entry_safe' + - 'mas_for_each' - 'mci_for_each_dimm' - 'media_device_for_each_entity' - 'media_device_for_each_intf' - 'media_device_for_each_link' - 'media_device_for_each_pad' + - 'media_entity_for_each_pad' + - 'media_pipeline_for_each_entity' + - 'media_pipeline_for_each_pad' + - 'mlx5_lag_for_each_peer_mdev' + - 'msi_domain_for_each_desc' - 'msi_for_each_desc' + - 'mt_for_each' - 'nanddev_io_for_each_page' - 'netdev_for_each_lower_dev' - 'netdev_for_each_lower_private' - 'netdev_for_each_lower_private_rcu' - 'netdev_for_each_mc_addr' + - 'netdev_for_each_synced_mc_addr' + - 'netdev_for_each_synced_uc_addr' - 'netdev_for_each_uc_addr' - 'netdev_for_each_upper_dev_rcu' - 'netdev_hw_addr_list_for_each' @@ -529,6 +579,7 @@ ForEachMacros: - 'perf_config_sections__for_each_entry' - 'perf_config_set__for_each_entry' - 'perf_cpu_map__for_each_cpu' + - 'perf_cpu_map__for_each_idx' - 'perf_evlist__for_each_entry' - 'perf_evlist__for_each_entry_reverse' - 'perf_evlist__for_each_entry_safe' @@ -538,9 +589,7 @@ ForEachMacros: - 'perf_hpp_list__for_each_format_safe' - 'perf_hpp_list__for_each_sort_list' - 'perf_hpp_list__for_each_sort_list_safe' - - 'perf_pmu__for_each_hybrid_pmu' - - 'ping_portaddr_for_each_entry' - - 'ping_portaddr_for_each_entry_rcu' + - 'perf_tool_event__for_each_event' - 'plist_for_each' - 'plist_for_each_continue' - 'plist_for_each_entry' @@ -577,6 +626,7 @@ ForEachMacros: - 'rq_for_each_segment' - 'rq_list_for_each' - 'rq_list_for_each_safe' + - 'sample_read_group__for_each' - 'scsi_for_each_prot_sg' - 'scsi_for_each_sg' - 'sctp_for_each_hentry' @@ -584,10 +634,12 @@ ForEachMacros: - 'sec_for_each_insn' - 'sec_for_each_insn_continue' - 'sec_for_each_insn_from' + - 'sec_for_each_sym' - 'shdma_for_each_chan' - 'shost_for_each_device' - 'sk_for_each' - 'sk_for_each_bound' + - 'sk_for_each_bound_bhash2' - 'sk_for_each_entry_offset_rcu' - 'sk_for_each_from' - 'sk_for_each_rcu' @@ -609,6 +661,8 @@ ForEachMacros: - 'tb_property_for_each' - 'tcf_act_for_each_action' - 'tcf_exts_for_each_action' + - 'ttm_resource_manager_for_each_res' + - 'twsk_for_each_bound_bhash2' - 'udp_portaddr_for_each_entry' - 'udp_portaddr_for_each_entry_rcu' - 'usb_hub_for_each_child' diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000000000..854773350cc5a9 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: GPL-2.0-only + +root = true + +[{*.{awk,c,dts,dtsi,dtso,h,mk,s,S},Kconfig,Makefile,Makefile.*}] +charset = utf-8 +end_of_line = lf +trim_trailing_whitespace = true +insert_final_newline = true +indent_style = tab +indent_size = 8 + +[*.{json,py,rs}] +charset = utf-8 +end_of_line = lf +trim_trailing_whitespace = true +insert_final_newline = true +indent_style = space +indent_size = 4 + +# this must be below the general *.py to overwrite it +[tools/{perf,power,rcu,testing/kunit}/**.py,] +indent_style = tab +indent_size = 8 + +[*.yaml] +charset = utf-8 +end_of_line = lf +trim_trailing_whitespace = unset +insert_final_newline = true +indent_style = space +indent_size = 2 diff --git a/.gitignore b/.gitignore index 98274e1160d7b1..689a4fa3f5477a 100644 --- a/.gitignore +++ b/.gitignore @@ -96,6 +96,7 @@ modules.order # !.clang-format !.cocciconfig +!.editorconfig !.get_maintainer.ignore !.gitattributes !.gitignore diff --git a/.mailmap b/.mailmap index ac1d4692e2e82c..04998f7bda8181 100644 --- a/.mailmap +++ b/.mailmap @@ -363,7 +363,6 @@ Maheshwar Ajja Malathi Gottam Manikanta Pubbisetty Manivannan Sadhasivam -Manivannan Sadhasivam Manoj Basapathi Marcin Nowakowski Marc Zyngier @@ -391,9 +390,10 @@ Matthias Fuchs Matthieu Baerts Matthieu CASTET Matti Vaittinen -Matt Ranostay -Matt Ranostay Matthew Ranostay -Matt Ranostay +Matt Ranostay +Matt Ranostay +Matt Ranostay Matthew Ranostay +Matt Ranostay Matt Redfearn Maulik Shah Mauro Carvalho Chehab @@ -478,6 +478,8 @@ Paul E. McKenney Paul E. McKenney Paul Mackerras Paul Mackerras +Paul Moore +Paul Moore Pavankumar Kondeti Peter A Jonsson Peter Oruba @@ -502,6 +504,9 @@ Ralf Baechle Ralf Wildenhues Ram Chandra Jangir Randy Dunlap +Randy Dunlap +Randy Dunlap +Randy Dunlap Ravi Kumar Bokka Ravi Kumar Siddojigari Rémi Denis-Courmont @@ -542,6 +547,8 @@ Sebastian Reichel Sebastian Reichel Sedat Dilek Senthilkumar N L +Serge Hallyn +Serge Hallyn Seth Forshee Shannon Nelson Shannon Nelson @@ -578,6 +585,7 @@ Surabhi Vishnoi Takashi YOSHII Tamizh Chelvam Raja Taniya Das +Tanzir Hasan Tejun Heo Tomeu Vizoso Thomas Graf @@ -604,6 +612,9 @@ Uwe Kleine-König Uwe Kleine-König Uwe Kleine-König Uwe Kleine-König +Vadim Fedorenko +Vadim Fedorenko +Vadim Fedorenko Valdis Kletnieks Vara Reddy Varadarajan Narayanan diff --git a/CREDITS b/CREDITS index d9adc4e489a7ed..5797e8f7e92b06 100644 --- a/CREDITS +++ b/CREDITS @@ -9,10 +9,6 @@ Linus ---------- -N: Matt Mackal -E: mpm@selenic.com -D: SLOB slab allocator - N: Matti Aarnio E: mea@nic.funet.fi D: Alpha systems hacking, IPv6 and other network related stuff @@ -183,6 +179,7 @@ E: ralf@gnu.org P: 1024/AF7B30C1 CF 97 C2 CC 6D AE A7 FE C8 BA 9C FC 88 DE 32 C3 D: Linux/MIPS port D: Linux/68k hacker +D: AX25 maintainer S: Hauptstrasse 19 S: 79837 St. Blasien S: Germany @@ -323,6 +320,9 @@ N: Ohad Ben Cohen E: ohad@wizery.com D: Remote Processor (remoteproc) subsystem D: Remote Processor Messaging (rpmsg) subsystem +D: Hardware spinlock (hwspinlock) subsystem +D: OMAP hwspinlock driver +D: OMAP remoteproc driver N: Krzysztof Benedyczak E: golbi@mat.uni.torun.pl @@ -678,6 +678,10 @@ D: Media subsystem (V4L/DVB) drivers and core D: EDAC drivers and EDAC 3.0 core rework S: Brazil +N: Landen Chao +E: Landen.Chao@mediatek.com +D: MT7531 Ethernet switch support + N: Raymond Chen E: raymondc@microsoft.com D: Author of Configure script @@ -815,6 +819,10 @@ D: Support for Xircom PGSDB9 (firmware and host driver) S: Bucharest S: Romania +N: John Crispin +E: john@phrozen.org +D: MediaTek MT7623 Gigabit ethernet support + N: Laurence Culhane E: loz@holmes.demon.co.uk D: Wrote the initial alpha SLIP code @@ -1425,6 +1433,10 @@ S: University of Stellenbosch S: Stellenbosch, Western Cape S: South Africa +N: Andy Gross +E: agross@kernel.org +D: Qualcomm SoC subsystem and drivers + N: Grant Grundler E: grantgrundler@gmail.com W: http://obmouse.sourceforge.net/ @@ -1535,6 +1547,10 @@ N: Andrew Haylett E: ajh@primag.co.uk D: Selection mechanism +N: Johan Hedberg +E: johan.hedberg@gmail.com +D: Bluetooth subsystem maintainer + N: Andre Hedrick E: andre@linux-ide.org E: andre@linuxdiskcert.org @@ -1572,6 +1588,10 @@ S: Ampferstr. 50 / 4 S: 6020 Innsbruck S: Austria +N: Mark Hemment +E: markhe@nextd.demon.co.uk +D: SLAB allocator implementation + N: Richard Henderson E: rth@twiddle.net E: rth@cygnus.com @@ -1828,6 +1848,13 @@ S: K osmidomkum 723 S: 160 00 Praha 6 S: Czech Republic +N: Michael Kerrisk +E: mtk.manpages@gmail.com +W: https://man7.org/ +P: 4096R/3A35CE5E E522 595B 52ED A4E6 BFCC CB5E 8561 9911 3A35 CE5E +D: Maintainer of the Linux man-pages project +D: Linux man pages online, at + N: Niels Kristian Bech Jensen E: nkbj1970@hotmail.com D: Miscellaneous kernel updates and fixes. @@ -2445,6 +2472,10 @@ D: work on suspend-to-ram/disk, killing duplicates from ioctl32, D: Altera SoCFPGA and Nokia N900 support. S: Czech Republic +N: Olivia Mackall +E: olivia@selenic.com +D: SLOB slab allocator + N: Paul Mackerras E: paulus@samba.org D: PPP driver @@ -3034,6 +3065,10 @@ S: Demonstratsii 8-382 S: Tula 300000 S: Russia +N: Thomas Petazzoni +E: thomas.petazzoni@bootlin.com +D: Driver for the Marvell Armada 370/XP network unit. + N: Gordon Peters E: GordPeters@smarttech.com D: Isochronous receive for IEEE 1394 driver (OHCI module). @@ -3932,6 +3967,10 @@ S: 21513 Conradia Ct S: Cupertino, CA 95014 S: USA +N: Manohar Vanga +E: manohar.vanga@gmail.com +D: VME subsystem maintainer + N: Thibaut Varène E: hacks+kernel@slashdirt.org W: http://hacks.slashdirt.org/ @@ -4032,6 +4071,10 @@ D: Fixes for the NE/2-driver D: Miscellaneous MCA-support D: Cleanup of the Config-files +N: Martyn Welch +E: martyn@welchs.me.uk +D: VME subsystem maintainer + N: Matt Welsh E: mdw@metalab.unc.edu W: http://www.cs.berkeley.edu/~mdw diff --git a/Documentation/ABI/testing/debugfs-driver-habanalabs b/Documentation/ABI/testing/debugfs-driver-habanalabs index 042fd125fbc96a..a7a432dc40156c 100644 --- a/Documentation/ABI/testing/debugfs-driver-habanalabs +++ b/Documentation/ABI/testing/debugfs-driver-habanalabs @@ -1,4 +1,4 @@ -What: /sys/kernel/debug/accel//addr +What: /sys/kernel/debug/accel//addr Date: Jan 2019 KernelVersion: 5.1 Contact: ogabbay@kernel.org @@ -8,34 +8,34 @@ Description: Sets the device address to be used for read or write through only when the IOMMU is disabled. The acceptable value is a string that starts with "0x" -What: /sys/kernel/debug/accel//clk_gate +What: /sys/kernel/debug/accel//clk_gate Date: May 2020 KernelVersion: 5.8 Contact: ogabbay@kernel.org Description: This setting is now deprecated as clock gating is handled solely by the f/w -What: /sys/kernel/debug/accel//command_buffers +What: /sys/kernel/debug/accel//command_buffers Date: Jan 2019 KernelVersion: 5.1 Contact: ogabbay@kernel.org Description: Displays a list with information about the currently allocated command buffers -What: /sys/kernel/debug/accel//command_submission +What: /sys/kernel/debug/accel//command_submission Date: Jan 2019 KernelVersion: 5.1 Contact: ogabbay@kernel.org Description: Displays a list with information about the currently active command submissions -What: /sys/kernel/debug/accel//command_submission_jobs +What: /sys/kernel/debug/accel//command_submission_jobs Date: Jan 2019 KernelVersion: 5.1 Contact: ogabbay@kernel.org Description: Displays a list with detailed information about each JOB (CB) of each active command submission -What: /sys/kernel/debug/accel//data32 +What: /sys/kernel/debug/accel//data32 Date: Jan 2019 KernelVersion: 5.1 Contact: ogabbay@kernel.org @@ -50,7 +50,7 @@ Description: Allows the root user to read or write directly through the If the IOMMU is disabled, it also allows the root user to read or write from the host a device VA of a host mapped memory -What: /sys/kernel/debug/accel//data64 +What: /sys/kernel/debug/accel//data64 Date: Jan 2020 KernelVersion: 5.6 Contact: ogabbay@kernel.org @@ -65,7 +65,7 @@ Description: Allows the root user to read or write 64 bit data directly If the IOMMU is disabled, it also allows the root user to read or write from the host a device VA of a host mapped memory -What: /sys/kernel/debug/accel//data_dma +What: /sys/kernel/debug/accel//data_dma Date: Apr 2021 KernelVersion: 5.13 Contact: ogabbay@kernel.org @@ -83,7 +83,7 @@ Description: Allows the root user to read from the device's internal workloads. Only supported on GAUDI at this stage. -What: /sys/kernel/debug/accel//device +What: /sys/kernel/debug/accel//device Date: Jan 2019 KernelVersion: 5.1 Contact: ogabbay@kernel.org @@ -91,14 +91,14 @@ Description: Enables the root user to set the device to specific state. Valid values are "disable", "enable", "suspend", "resume". User can read this property to see the valid values -What: /sys/kernel/debug/accel//device_release_watchdog_timeout +What: /sys/kernel/debug/accel//device_release_watchdog_timeout Date: Oct 2022 KernelVersion: 6.2 Contact: ttayar@habana.ai Description: The watchdog timeout value in seconds for a device release upon certain error cases, after which the device is reset. -What: /sys/kernel/debug/accel//dma_size +What: /sys/kernel/debug/accel//dma_size Date: Apr 2021 KernelVersion: 5.13 Contact: ogabbay@kernel.org @@ -108,7 +108,7 @@ Description: Specify the size of the DMA transaction when using DMA to read When the write is finished, the user can read the "data_dma" blob -What: /sys/kernel/debug/accel//dump_razwi_events +What: /sys/kernel/debug/accel//dump_razwi_events Date: Aug 2022 KernelVersion: 5.20 Contact: fkassabri@habana.ai @@ -117,7 +117,7 @@ Description: Dumps all razwi events to dmesg if exist. the routine will clear the status register. Usage: cat dump_razwi_events -What: /sys/kernel/debug/accel//dump_security_violations +What: /sys/kernel/debug/accel//dump_security_violations Date: Jan 2021 KernelVersion: 5.12 Contact: ogabbay@kernel.org @@ -125,14 +125,14 @@ Description: Dumps all security violations to dmesg. This will also ack all security violations meanings those violations will not be dumped next time user calls this API -What: /sys/kernel/debug/accel//engines +What: /sys/kernel/debug/accel//engines Date: Jul 2019 KernelVersion: 5.3 Contact: ogabbay@kernel.org Description: Displays the status registers values of the device engines and their derived idle status -What: /sys/kernel/debug/accel//i2c_addr +What: /sys/kernel/debug/accel//i2c_addr Date: Jan 2019 KernelVersion: 5.1 Contact: ogabbay@kernel.org @@ -140,7 +140,7 @@ Description: Sets I2C device address for I2C transaction that is generated by the device's CPU, Not available when device is loaded with secured firmware -What: /sys/kernel/debug/accel//i2c_bus +What: /sys/kernel/debug/accel//i2c_bus Date: Jan 2019 KernelVersion: 5.1 Contact: ogabbay@kernel.org @@ -148,7 +148,7 @@ Description: Sets I2C bus address for I2C transaction that is generated by the device's CPU, Not available when device is loaded with secured firmware -What: /sys/kernel/debug/accel//i2c_data +What: /sys/kernel/debug/accel//i2c_data Date: Jan 2019 KernelVersion: 5.1 Contact: ogabbay@kernel.org @@ -157,7 +157,7 @@ Description: Triggers an I2C transaction that is generated by the device's reading from the file generates a read transaction, Not available when device is loaded with secured firmware -What: /sys/kernel/debug/accel//i2c_len +What: /sys/kernel/debug/accel//i2c_len Date: Dec 2021 KernelVersion: 5.17 Contact: obitton@habana.ai @@ -165,7 +165,7 @@ Description: Sets I2C length in bytes for I2C transaction that is generated b the device's CPU, Not available when device is loaded with secured firmware -What: /sys/kernel/debug/accel//i2c_reg +What: /sys/kernel/debug/accel//i2c_reg Date: Jan 2019 KernelVersion: 5.1 Contact: ogabbay@kernel.org @@ -173,35 +173,35 @@ Description: Sets I2C register id for I2C transaction that is generated by the device's CPU, Not available when device is loaded with secured firmware -What: /sys/kernel/debug/accel//led0 +What: /sys/kernel/debug/accel//led0 Date: Jan 2019 KernelVersion: 5.1 Contact: ogabbay@kernel.org Description: Sets the state of the first S/W led on the device, Not available when device is loaded with secured firmware -What: /sys/kernel/debug/accel//led1 +What: /sys/kernel/debug/accel//led1 Date: Jan 2019 KernelVersion: 5.1 Contact: ogabbay@kernel.org Description: Sets the state of the second S/W led on the device, Not available when device is loaded with secured firmware -What: /sys/kernel/debug/accel//led2 +What: /sys/kernel/debug/accel//led2 Date: Jan 2019 KernelVersion: 5.1 Contact: ogabbay@kernel.org Description: Sets the state of the third S/W led on the device, Not available when device is loaded with secured firmware -What: /sys/kernel/debug/accel//memory_scrub +What: /sys/kernel/debug/accel//memory_scrub Date: May 2022 KernelVersion: 5.19 Contact: dhirschfeld@habana.ai Description: Allows the root user to scrub the dram memory. The scrubbing value can be set using the debugfs file memory_scrub_val. -What: /sys/kernel/debug/accel//memory_scrub_val +What: /sys/kernel/debug/accel//memory_scrub_val Date: May 2022 KernelVersion: 5.19 Contact: dhirschfeld@habana.ai @@ -209,7 +209,7 @@ Description: The value to which the dram will be set to when the user scrubs the dram using 'memory_scrub' debugfs file and the scrubbing value when using module param 'memory_scrub' -What: /sys/kernel/debug/accel//mmu +What: /sys/kernel/debug/accel//mmu Date: Jan 2019 KernelVersion: 5.1 Contact: ogabbay@kernel.org @@ -219,7 +219,7 @@ Description: Displays the hop values and physical address for a given ASID e.g. to display info about VA 0x1000 for ASID 1 you need to do: echo "1 0x1000" > /sys/kernel/debug/accel/0/mmu -What: /sys/kernel/debug/accel//mmu_error +What: /sys/kernel/debug/accel//mmu_error Date: Mar 2021 KernelVersion: 5.12 Contact: fkassabri@habana.ai @@ -229,7 +229,7 @@ Description: Check and display page fault or access violation mmu errors for echo "0x200" > /sys/kernel/debug/accel/0/mmu_error cat /sys/kernel/debug/accel/0/mmu_error -What: /sys/kernel/debug/accel//monitor_dump +What: /sys/kernel/debug/accel//monitor_dump Date: Mar 2022 KernelVersion: 5.19 Contact: osharabi@habana.ai @@ -243,7 +243,7 @@ Description: Allows the root user to dump monitors status from the device's This interface doesn't support concurrency in the same device. Only supported on GAUDI. -What: /sys/kernel/debug/accel//monitor_dump_trig +What: /sys/kernel/debug/accel//monitor_dump_trig Date: Mar 2022 KernelVersion: 5.19 Contact: osharabi@habana.ai @@ -253,14 +253,14 @@ Description: Triggers dump of monitor data. The value to trigger the operatio When the write is finished, the user can read the "monitor_dump" blob -What: /sys/kernel/debug/accel//set_power_state +What: /sys/kernel/debug/accel//set_power_state Date: Jan 2019 KernelVersion: 5.1 Contact: ogabbay@kernel.org Description: Sets the PCI power state. Valid values are "1" for D0 and "2" for D3Hot -What: /sys/kernel/debug/accel//skip_reset_on_timeout +What: /sys/kernel/debug/accel//skip_reset_on_timeout Date: Jun 2021 KernelVersion: 5.13 Contact: ynudelman@habana.ai @@ -268,7 +268,7 @@ Description: Sets the skip reset on timeout option for the device. Value of "0" means device will be reset in case some CS has timed out, otherwise it will not be reset. -What: /sys/kernel/debug/accel//state_dump +What: /sys/kernel/debug/accel//state_dump Date: Oct 2021 KernelVersion: 5.15 Contact: ynudelman@habana.ai @@ -279,7 +279,7 @@ Description: Gets the state dump occurring on a CS timeout or failure. Writing an integer X discards X state dumps, so that the next read would return X+1-st newest state dump. -What: /sys/kernel/debug/accel//stop_on_err +What: /sys/kernel/debug/accel//stop_on_err Date: Mar 2020 KernelVersion: 5.6 Contact: ogabbay@kernel.org @@ -287,13 +287,13 @@ Description: Sets the stop-on_error option for the device engines. Value of "0" is for disable, otherwise enable. Relevant only for GOYA and GAUDI. -What: /sys/kernel/debug/accel//timeout_locked +What: /sys/kernel/debug/accel//timeout_locked Date: Sep 2021 KernelVersion: 5.16 Contact: obitton@habana.ai Description: Sets the command submission timeout value in seconds. -What: /sys/kernel/debug/accel//userptr +What: /sys/kernel/debug/accel//userptr Date: Jan 2019 KernelVersion: 5.1 Contact: ogabbay@kernel.org @@ -301,7 +301,7 @@ Description: Displays a list with information about the current user pointers (user virtual addresses) that are pinned and mapped to DMA addresses -What: /sys/kernel/debug/accel//userptr_lookup +What: /sys/kernel/debug/accel//userptr_lookup Date: Oct 2021 KernelVersion: 5.15 Contact: ogabbay@kernel.org @@ -309,7 +309,7 @@ Description: Allows to search for specific user pointers (user virtual addresses) that are pinned and mapped to DMA addresses, and see their resolution to the specific dma address. -What: /sys/kernel/debug/accel//vm +What: /sys/kernel/debug/accel//vm Date: Jan 2019 KernelVersion: 5.1 Contact: ogabbay@kernel.org diff --git a/Documentation/ABI/testing/debugfs-driver-qat_telemetry b/Documentation/ABI/testing/debugfs-driver-qat_telemetry new file mode 100644 index 00000000000000..eacee207208827 --- /dev/null +++ b/Documentation/ABI/testing/debugfs-driver-qat_telemetry @@ -0,0 +1,228 @@ +What: /sys/kernel/debug/qat__/telemetry/control +Date: March 2024 +KernelVersion: 6.8 +Contact: qat-linux@intel.com +Description: (RW) Enables/disables the reporting of telemetry metrics. + + Allowed values to write: + ======================== + * 0: disable telemetry + * 1: enable telemetry + * 2, 3, 4: enable telemetry and calculate minimum, maximum + and average for each counter over 2, 3 or 4 samples + + Returned values: + ================ + * 1-4: telemetry is enabled and running + * 0: telemetry is disabled + + Example. + + Writing '3' to this file starts the collection of + telemetry metrics. Samples are collected every second and + stored in a circular buffer of size 3. These values are then + used to calculate the minimum, maximum and average for each + counter. After enabling, counters can be retrieved through + the ``device_data`` file:: + + echo 3 > /sys/kernel/debug/qat_4xxx_0000:6b:00.0/telemetry/control + + Writing '0' to this file stops the collection of telemetry + metrics:: + + echo 0 > /sys/kernel/debug/qat_4xxx_0000:6b:00.0/telemetry/control + + This attribute is only available for qat_4xxx devices. + +What: /sys/kernel/debug/qat__/telemetry/device_data +Date: March 2024 +KernelVersion: 6.8 +Contact: qat-linux@intel.com +Description: (RO) Reports device telemetry counters. + Reads report metrics about performance and utilization of + a QAT device: + + ======================= ======================================== + Field Description + ======================= ======================================== + sample_cnt number of acquisitions of telemetry data + from the device. Reads are performed + every 1000 ms. + pci_trans_cnt number of PCIe partial transactions + max_rd_lat maximum logged read latency [ns] (could + be any read operation) + rd_lat_acc_avg average read latency [ns] + max_gp_lat max get to put latency [ns] (only takes + samples for AE0) + gp_lat_acc_avg average get to put latency [ns] + bw_in PCIe, write bandwidth [Mbps] + bw_out PCIe, read bandwidth [Mbps] + at_page_req_lat_avg Address Translator(AT), average page + request latency [ns] + at_trans_lat_avg AT, average page translation latency [ns] + at_max_tlb_used AT, maximum uTLB used + util_cpr utilization of Compression slice N [%] + exec_cpr execution count of Compression slice N + util_xlt utilization of Translator slice N [%] + exec_xlt execution count of Translator slice N + util_dcpr utilization of Decompression slice N [%] + exec_dcpr execution count of Decompression slice N + util_pke utilization of PKE N [%] + exec_pke execution count of PKE N + util_ucs utilization of UCS slice N [%] + exec_ucs execution count of UCS slice N + util_wat utilization of Wireless Authentication + slice N [%] + exec_wat execution count of Wireless Authentication + slice N + util_wcp utilization of Wireless Cipher slice N [%] + exec_wcp execution count of Wireless Cipher slice N + util_cph utilization of Cipher slice N [%] + exec_cph execution count of Cipher slice N + util_ath utilization of Authentication slice N [%] + exec_ath execution count of Authentication slice N + ======================= ======================================== + + The telemetry report file can be read with the following command:: + + cat /sys/kernel/debug/qat_4xxx_0000:6b:00.0/telemetry/device_data + + If ``control`` is set to 1, only the current values of the + counters are displayed:: + + + + If ``control`` is 2, 3 or 4, counters are displayed in the + following format:: + + + + If a device lacks of a specific accelerator, the corresponding + attribute is not reported. + + This attribute is only available for qat_4xxx devices. + +What: /sys/kernel/debug/qat__/telemetry/rp__data +Date: March 2024 +KernelVersion: 6.8 +Contact: qat-linux@intel.com +Description: (RW) Selects up to 4 Ring Pairs (RP) to monitor, one per file, + and report telemetry counters related to each. + + Allowed values to write: + ======================== + * 0 to ````: + Ring pair to be monitored. The value of ``num_rps`` can be + retrieved through ``/sys/bus/pci/devices//qat/num_rps``. + See Documentation/ABI/testing/sysfs-driver-qat. + + Reads report metrics about performance and utilization of + the selected RP: + + ======================= ======================================== + Field Description + ======================= ======================================== + sample_cnt number of acquisitions of telemetry data + from the device. Reads are performed + every 1000 ms + rp_num RP number associated with slot + service_type service associated to the RP + pci_trans_cnt number of PCIe partial transactions + gp_lat_acc_avg average get to put latency [ns] + bw_in PCIe, write bandwidth [Mbps] + bw_out PCIe, read bandwidth [Mbps] + at_glob_devtlb_hit Message descriptor DevTLB hit rate + at_glob_devtlb_miss Message descriptor DevTLB miss rate + tl_at_payld_devtlb_hit Payload DevTLB hit rate + tl_at_payld_devtlb_miss Payload DevTLB miss rate + ======================= ======================================== + + Example. + + Writing the value '32' to the file ``rp_C_data`` starts the + collection of telemetry metrics for ring pair 32:: + + echo 32 > /sys/kernel/debug/qat_4xxx_0000:6b:00.0/telemetry/rp_C_data + + Once a ring pair is selected, statistics can be read accessing + the file:: + + cat /sys/kernel/debug/qat_4xxx_0000:6b:00.0/telemetry/rp_C_data + + If ``control`` is set to 1, only the current values of the + counters are displayed:: + + + + If ``control`` is 2, 3 or 4, counters are displayed in the + following format:: + + + + + On QAT GEN4 devices there are 64 RPs on a PF, so the allowed + values are 0..63. This number is absolute to the device. + If Virtual Functions (VF) are used, the ring pair number can + be derived from the Bus, Device, Function of the VF: + + ============ ====== ====== ====== ====== + PCI BDF/VF RP0 RP1 RP2 RP3 + ============ ====== ====== ====== ====== + 0000:6b:0.1 RP 0 RP 1 RP 2 RP 3 + 0000:6b:0.2 RP 4 RP 5 RP 6 RP 7 + 0000:6b:0.3 RP 8 RP 9 RP 10 RP 11 + 0000:6b:0.4 RP 12 RP 13 RP 14 RP 15 + 0000:6b:0.5 RP 16 RP 17 RP 18 RP 19 + 0000:6b:0.6 RP 20 RP 21 RP 22 RP 23 + 0000:6b:0.7 RP 24 RP 25 RP 26 RP 27 + 0000:6b:1.0 RP 28 RP 29 RP 30 RP 31 + 0000:6b:1.1 RP 32 RP 33 RP 34 RP 35 + 0000:6b:1.2 RP 36 RP 37 RP 38 RP 39 + 0000:6b:1.3 RP 40 RP 41 RP 42 RP 43 + 0000:6b:1.4 RP 44 RP 45 RP 46 RP 47 + 0000:6b:1.5 RP 48 RP 49 RP 50 RP 51 + 0000:6b:1.6 RP 52 RP 53 RP 54 RP 55 + 0000:6b:1.7 RP 56 RP 57 RP 58 RP 59 + 0000:6b:2.0 RP 60 RP 61 RP 62 RP 63 + ============ ====== ====== ====== ====== + + The mapping is only valid for the BDFs of VFs on the host. + + + The service provided on a ring-pair varies depending on the + configuration. The configuration for a given device can be + queried and set using ``cfg_services``. + See Documentation/ABI/testing/sysfs-driver-qat for details. + + The following table reports how ring pairs are mapped to VFs + on the PF 0000:6b:0.0 configured for `sym;asym` or `asym;sym`: + + =========== ============ =========== ============ =========== + PCI BDF/VF RP0/service RP1/service RP2/service RP3/service + =========== ============ =========== ============ =========== + 0000:6b:0.1 RP 0 asym RP 1 sym RP 2 asym RP 3 sym + 0000:6b:0.2 RP 4 asym RP 5 sym RP 6 asym RP 7 sym + 0000:6b:0.3 RP 8 asym RP 9 sym RP10 asym RP11 sym + ... ... ... ... ... + =========== ============ =========== ============ =========== + + All VFs follow the same pattern. + + + The following table reports how ring pairs are mapped to VFs on + the PF 0000:6b:0.0 configured for `dc`: + + =========== ============ =========== ============ =========== + PCI BDF/VF RP0/service RP1/service RP2/service RP3/service + =========== ============ =========== ============ =========== + 0000:6b:0.1 RP 0 dc RP 1 dc RP 2 dc RP 3 dc + 0000:6b:0.2 RP 4 dc RP 5 dc RP 6 dc RP 7 dc + 0000:6b:0.3 RP 8 dc RP 9 dc RP10 dc RP11 dc + ... ... ... ... ... + =========== ============ =========== ============ =========== + + The mapping of a RP to a service can be retrieved using + ``rp2srv`` from sysfs. + See Documentation/ABI/testing/sysfs-driver-qat for details. + + This attribute is only available for qat_4xxx devices. diff --git a/Documentation/ABI/testing/debugfs-hisi-hpre b/Documentation/ABI/testing/debugfs-hisi-hpre index 82abf92df429fd..8e8de49c5cc669 100644 --- a/Documentation/ABI/testing/debugfs-hisi-hpre +++ b/Documentation/ABI/testing/debugfs-hisi-hpre @@ -101,7 +101,7 @@ What: /sys/kernel/debug/hisi_hpre//qm/status Date: Apr 2020 Contact: linux-crypto@vger.kernel.org Description: Dump the status of the QM. - Four states: initiated, started, stopped and closed. + Two states: work, stop. Available for both PF and VF, and take no other effect on HPRE. What: /sys/kernel/debug/hisi_hpre//qm/diff_regs diff --git a/Documentation/ABI/testing/debugfs-hisi-sec b/Documentation/ABI/testing/debugfs-hisi-sec index 93c530d1bf0fcb..deeefe2c735ed7 100644 --- a/Documentation/ABI/testing/debugfs-hisi-sec +++ b/Documentation/ABI/testing/debugfs-hisi-sec @@ -81,7 +81,7 @@ What: /sys/kernel/debug/hisi_sec2//qm/status Date: Apr 2020 Contact: linux-crypto@vger.kernel.org Description: Dump the status of the QM. - Four states: initiated, started, stopped and closed. + Two states: work, stop. Available for both PF and VF, and take no other effect on SEC. What: /sys/kernel/debug/hisi_sec2//qm/diff_regs diff --git a/Documentation/ABI/testing/debugfs-hisi-zip b/Documentation/ABI/testing/debugfs-hisi-zip index fd3f314cf8d1c7..593714afaed249 100644 --- a/Documentation/ABI/testing/debugfs-hisi-zip +++ b/Documentation/ABI/testing/debugfs-hisi-zip @@ -94,7 +94,7 @@ What: /sys/kernel/debug/hisi_zip//qm/status Date: Apr 2020 Contact: linux-crypto@vger.kernel.org Description: Dump the status of the QM. - Four states: initiated, started, stopped and closed. + Two states: work, stop. Available for both PF and VF, and take no other effect on ZIP. What: /sys/kernel/debug/hisi_zip//qm/diff_regs diff --git a/Documentation/ABI/testing/debugfs-vfio b/Documentation/ABI/testing/debugfs-vfio new file mode 100644 index 00000000000000..90f7c262f59130 --- /dev/null +++ b/Documentation/ABI/testing/debugfs-vfio @@ -0,0 +1,25 @@ +What: /sys/kernel/debug/vfio +Date: December 2023 +KernelVersion: 6.8 +Contact: Longfang Liu +Description: This debugfs file directory is used for debugging + of vfio devices, it's a common directory for all vfio devices. + Vfio core will create a device subdirectory under this + directory. + +What: /sys/kernel/debug/vfio//migration +Date: December 2023 +KernelVersion: 6.8 +Contact: Longfang Liu +Description: This debugfs file directory is used for debugging + of vfio devices that support live migration. + The debugfs of each vfio device that supports live migration + could be created under this directory. + +What: /sys/kernel/debug/vfio//migration/state +Date: December 2023 +KernelVersion: 6.8 +Contact: Longfang Liu +Description: Read the live migration status of the vfio device. + The contents of the state file reflects the migration state + relative to those defined in the vfio_device_mig_state enum diff --git a/Documentation/ABI/testing/sysfs-bus-cdx b/Documentation/ABI/testing/sysfs-bus-cdx index 8c067ff99e5474..e84277531414b1 100644 --- a/Documentation/ABI/testing/sysfs-bus-cdx +++ b/Documentation/ABI/testing/sysfs-bus-cdx @@ -98,6 +98,13 @@ Description: # echo 1 > /sys/bus/cdx/devices/.../remove +What: /sys/bus/cdx/devices/.../resource +Date: July 2023 +Contact: puneet.gupta@amd.com +Description: + The resource binary file contains the content of the memory + regions. These files can be m'maped from userspace. + What: /sys/bus/cdx/devices/.../modalias Date: July 2023 Contact: nipun.gupta@amd.com diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tmc b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tmc index 6aa527296c7108..96aafa66b4a580 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tmc +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tmc @@ -91,3 +91,19 @@ Contact: Mathieu Poirier Description: (RW) Size of the trace buffer for TMC-ETR when used in SYSFS mode. Writable only for TMC-ETR configurations. The value should be aligned to the kernel pagesize. + +What: /sys/bus/coresight/devices/.tmc/buf_modes_available +Date: August 2023 +KernelVersion: 6.7 +Contact: Anshuman Khandual +Description: (Read) Shows all supported Coresight TMC-ETR buffer modes available + for the users to configure explicitly. This file is avaialble only + for TMC ETR devices. + +What: /sys/bus/coresight/devices/.tmc/buf_mode_preferred +Date: August 2023 +KernelVersion: 6.7 +Contact: Anshuman Khandual +Description: (RW) Current Coresight TMC-ETR buffer mode selected. But user could + only provide a mode which is supported for a given ETR device. This + file is available only for TMC ETR devices. diff --git a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm index 4a58e649550d58..4dd49b159543b6 100644 --- a/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm +++ b/Documentation/ABI/testing/sysfs-bus-coresight-devices-tpdm @@ -11,3 +11,162 @@ Description: Accepts only one of the 2 values - 1 or 2. 1 : Generate 64 bits data 2 : Generate 32 bits data + +What: /sys/bus/coresight/devices//reset_dataset +Date: March 2023 +KernelVersion 6.7 +Contact: Jinlong Mao (QUIC) , Tao Zhang (QUIC) +Description: + (Write) Reset the dataset of the tpdm. + + Accepts only one value - 1. + 1 : Reset the dataset of the tpdm + +What: /sys/bus/coresight/devices//dsb_trig_type +Date: March 2023 +KernelVersion 6.7 +Contact: Jinlong Mao (QUIC) , Tao Zhang (QUIC) +Description: + (RW) Set/Get the trigger type of the DSB for tpdm. + + Accepts only one of the 2 values - 0 or 1. + 0 : Set the DSB trigger type to false + 1 : Set the DSB trigger type to true + +What: /sys/bus/coresight/devices//dsb_trig_ts +Date: March 2023 +KernelVersion 6.7 +Contact: Jinlong Mao (QUIC) , Tao Zhang (QUIC) +Description: + (RW) Set/Get the trigger timestamp of the DSB for tpdm. + + Accepts only one of the 2 values - 0 or 1. + 0 : Set the DSB trigger type to false + 1 : Set the DSB trigger type to true + +What: /sys/bus/coresight/devices//dsb_mode +Date: March 2023 +KernelVersion 6.7 +Contact: Jinlong Mao (QUIC) , Tao Zhang (QUIC) +Description: + (RW) Set/Get the programming mode of the DSB for tpdm. + + Accepts the value needs to be greater than 0. What data + bits do is listed below. + Bit[0:1] : Test mode control bit for choosing the inputs. + Bit[3] : Set to 0 for low performance mode. Set to 1 for high + performance mode. + Bit[4:8] : Select byte lane for high performance mode. + +What: /sys/bus/coresight/devices//dsb_edge/ctrl_idx +Date: March 2023 +KernelVersion 6.7 +Contact: Jinlong Mao (QUIC) , Tao Zhang (QUIC) +Description: + (RW) Set/Get the index number of the edge detection for the DSB + subunit TPDM. Since there are at most 256 edge detections, this + value ranges from 0 to 255. + +What: /sys/bus/coresight/devices//dsb_edge/ctrl_val +Date: March 2023 +KernelVersion 6.7 +Contact: Jinlong Mao (QUIC) , Tao Zhang (QUIC) +Description: + Write a data to control the edge detection corresponding to + the index number. Before writing data to this sysfs file, + "ctrl_idx" should be written first to configure the index + number of the edge detection which needs to be controlled. + + Accepts only one of the following values. + 0 - Rising edge detection + 1 - Falling edge detection + 2 - Rising and falling edge detection (toggle detection) + + +What: /sys/bus/coresight/devices//dsb_edge/ctrl_mask +Date: March 2023 +KernelVersion 6.7 +Contact: Jinlong Mao (QUIC) , Tao Zhang (QUIC) +Description: + Write a data to mask the edge detection corresponding to the index + number. Before writing data to this sysfs file, "ctrl_idx" should + be written first to configure the index number of the edge detection + which needs to be masked. + + Accepts only one of the 2 values - 0 or 1. + +What: /sys/bus/coresight/devices//dsb_edge/edcr[0:15] +Date: March 2023 +KernelVersion 6.7 +Contact: Jinlong Mao (QUIC) , Tao Zhang (QUIC) +Description: + Read a set of the edge control value of the DSB in TPDM. + +What: /sys/bus/coresight/devices//dsb_edge/edcmr[0:7] +Date: March 2023 +KernelVersion 6.7 +Contact: Jinlong Mao (QUIC) , Tao Zhang (QUIC) +Description: + Read a set of the edge control mask of the DSB in TPDM. + +What: /sys/bus/coresight/devices//dsb_trig_patt/xpr[0:7] +Date: March 2023 +KernelVersion 6.7 +Contact: Jinlong Mao (QUIC) , Tao Zhang (QUIC) +Description: + (RW) Set/Get the value of the trigger pattern for the DSB + subunit TPDM. + +What: /sys/bus/coresight/devices//dsb_trig_patt/xpmr[0:7] +Date: March 2023 +KernelVersion 6.7 +Contact: Jinlong Mao (QUIC) , Tao Zhang (QUIC) +Description: + (RW) Set/Get the mask of the trigger pattern for the DSB + subunit TPDM. + +What: /sys/bus/coresight/devices//dsb_patt/tpr[0:7] +Date: March 2023 +KernelVersion 6.7 +Contact: Jinlong Mao (QUIC) , Tao Zhang (QUIC) +Description: + (RW) Set/Get the value of the pattern for the DSB subunit TPDM. + +What: /sys/bus/coresight/devices//dsb_patt/tpmr[0:7] +Date: March 2023 +KernelVersion 6.7 +Contact: Jinlong Mao (QUIC) , Tao Zhang (QUIC) +Description: + (RW) Set/Get the mask of the pattern for the DSB subunit TPDM. + +What: /sys/bus/coresight/devices//dsb_patt/enable_ts +Date: March 2023 +KernelVersion 6.7 +Contact: Jinlong Mao (QUIC) , Tao Zhang (QUIC) +Description: + (Write) Set the pattern timestamp of DSB tpdm. Read + the pattern timestamp of DSB tpdm. + + Accepts only one of the 2 values - 0 or 1. + 0 : Disable DSB pattern timestamp. + 1 : Enable DSB pattern timestamp. + +What: /sys/bus/coresight/devices//dsb_patt/set_type +Date: March 2023 +KernelVersion 6.7 +Contact: Jinlong Mao (QUIC) , Tao Zhang (QUIC) +Description: + (Write) Set the pattern type of DSB tpdm. Read + the pattern type of DSB tpdm. + + Accepts only one of the 2 values - 0 or 1. + 0 : Set the DSB pattern type to value. + 1 : Set the DSB pattern type to toggle. + +What: /sys/bus/coresight/devices//dsb_msr/msr[0:31] +Date: March 2023 +KernelVersion 6.7 +Contact: Jinlong Mao (QUIC) , Tao Zhang (QUIC) +Description: + (RW) Set/Get the MSR(mux select register) for the DSB subunit + TPDM. diff --git a/Documentation/ABI/testing/sysfs-bus-cxl b/Documentation/ABI/testing/sysfs-bus-cxl index e76c3600607f8c..fff2581b803358 100644 --- a/Documentation/ABI/testing/sysfs-bus-cxl +++ b/Documentation/ABI/testing/sysfs-bus-cxl @@ -28,6 +28,23 @@ Description: Payload in the CXL-2.0 specification. +What: /sys/bus/cxl/devices/memX/ram/qos_class +Date: May, 2023 +KernelVersion: v6.8 +Contact: linux-cxl@vger.kernel.org +Description: + (RO) For CXL host platforms that support "QoS Telemmetry" + this attribute conveys a comma delimited list of platform + specific cookies that identifies a QoS performance class + for the volatile partition of the CXL mem device. These + class-ids can be compared against a similar "qos_class" + published for a root decoder. While it is not required + that the endpoints map their local memory-class to a + matching platform class, mismatches are not recommended + and there are platform specific performance related + side-effects that may result. First class-id is displayed. + + What: /sys/bus/cxl/devices/memX/pmem/size Date: December, 2020 KernelVersion: v5.12 @@ -38,6 +55,23 @@ Description: Payload in the CXL-2.0 specification. +What: /sys/bus/cxl/devices/memX/pmem/qos_class +Date: May, 2023 +KernelVersion: v6.8 +Contact: linux-cxl@vger.kernel.org +Description: + (RO) For CXL host platforms that support "QoS Telemmetry" + this attribute conveys a comma delimited list of platform + specific cookies that identifies a QoS performance class + for the persistent partition of the CXL mem device. These + class-ids can be compared against a similar "qos_class" + published for a root decoder. While it is not required + that the endpoints map their local memory-class to a + matching platform class, mismatches are not recommended + and there are platform specific performance related + side-effects that may result. First class-id is displayed. + + What: /sys/bus/cxl/devices/memX/serial Date: January, 2022 KernelVersion: v5.18 diff --git a/Documentation/ABI/testing/sysfs-bus-event_source-devices-caps b/Documentation/ABI/testing/sysfs-bus-event_source-devices-caps index 8757dcf41c0825..a5f506f7d4819e 100644 --- a/Documentation/ABI/testing/sysfs-bus-event_source-devices-caps +++ b/Documentation/ABI/testing/sysfs-bus-event_source-devices-caps @@ -16,3 +16,9 @@ Description: Example output in powerpc: grep . /sys/bus/event_source/devices/cpu/caps/* /sys/bus/event_source/devices/cpu/caps/pmu_name:POWER9 + + The "branch_counter_nr" in the supported platform exposes the + maximum number of counters which can be shown in the u64 counters + of PERF_SAMPLE_BRANCH_COUNTERS, while the "branch_counter_width" + exposes the width of each counter. Both of them can be used by + the perf tool to parse the logged counters in each branch. diff --git a/Documentation/ABI/testing/sysfs-bus-i3c b/Documentation/ABI/testing/sysfs-bus-i3c index e5248fd67a563b..c812ab180ff40c 100644 --- a/Documentation/ABI/testing/sysfs-bus-i3c +++ b/Documentation/ABI/testing/sysfs-bus-i3c @@ -88,6 +88,21 @@ Description: This entry describes the HDRCAP of the master controller driving the bus. +What: /sys/bus/i3c/devices/i3c-/hotjoin +KernelVersion: 6.8 +Contact: linux-i3c@vger.kernel.org +Description: + I3C’s Hot-Join mechanism allows an I3C Device to inform the + Active Controller that a newly-joined Target is present on the + I3C Bus and is ready to receive a Dynamic Address, in order to + become fully functional on the Bus. Hot-Join is used when the + Target is mounted on the same I3C bus and remains depowered + until needed or until the Target is physically inserted into the + I3C bus + + This entry allows to enable or disable Hot-join of the Current + Controller driving the bus. + What: /sys/bus/i3c/devices/i3c-/- KernelVersion: 5.0 Contact: linux-i3c@vger.kernel.org diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 19cde14f386929..2e6d5ebfd3c73d 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -362,10 +362,21 @@ Description: What: /sys/bus/iio/devices/iio:deviceX/in_accel_x_peak_raw What: /sys/bus/iio/devices/iio:deviceX/in_accel_y_peak_raw What: /sys/bus/iio/devices/iio:deviceX/in_accel_z_peak_raw +What: /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_peak_raw +What: /sys/bus/iio/devices/iio:deviceX/in_temp_peak_raw KernelVersion: 2.6.36 Contact: linux-iio@vger.kernel.org Description: - Highest value since some reset condition. These + Highest value since some reset condition. These + attributes allow access to this and are otherwise + the direct equivalent of the Y[_name]_raw attributes. + +What: /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_trough_raw +What: /sys/bus/iio/devices/iio:deviceX/in_temp_trough_raw +KernelVersion: 6.7 +Contact: linux-iio@vger.kernel.org +Description: + Lowest value since some reset condition. These attributes allow access to this and are otherwise the direct equivalent of the Y[_name]_raw attributes. @@ -618,7 +629,9 @@ KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: If a discrete set of scale values is available, they - are listed in this attribute. + are listed in this attribute. Unlike illumination, + multiplying intensity by intensity_scale does not + yield value with any standardized unit. What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_hardwaregain What: /sys/bus/iio/devices/iio:deviceX/in_intensity_hardwaregain @@ -1574,6 +1587,8 @@ What: /sys/.../iio:deviceX/in_intensityY_raw What: /sys/.../iio:deviceX/in_intensityY_ir_raw What: /sys/.../iio:deviceX/in_intensityY_both_raw What: /sys/.../iio:deviceX/in_intensityY_uv_raw +What: /sys/.../iio:deviceX/in_intensityY_uva_raw +What: /sys/.../iio:deviceX/in_intensityY_uvb_raw What: /sys/.../iio:deviceX/in_intensityY_duv_raw KernelVersion: 3.4 Contact: linux-iio@vger.kernel.org @@ -1582,8 +1597,9 @@ Description: that measurements contain visible and infrared light components or just infrared light, respectively. Modifier uv indicates that measurements contain ultraviolet light - components. Modifier duv indicates that measurements - contain deep ultraviolet light components. + components. Modifiers uva, uvb and duv indicate that + measurements contain A, B or deep (C) ultraviolet light + components respectively. What: /sys/.../iio:deviceX/in_uvindex_input KernelVersion: 4.6 @@ -2254,3 +2270,21 @@ Description: If a label is defined for this event add that to the event specific attributes. This is useful for userspace to be able to better identify an individual event. + +What: /sys/.../events/in_accel_gesture_tap_wait_timeout +KernelVersion: 6.7 +Contact: linux-iio@vger.kernel.org +Description: + Enable tap gesture confirmation with timeout. + +What: /sys/.../events/in_accel_gesture_tap_wait_dur +KernelVersion: 6.7 +Contact: linux-iio@vger.kernel.org +Description: + Timeout value in seconds for tap gesture confirmation. + +What: /sys/.../events/in_accel_gesture_tap_wait_dur_available +KernelVersion: 6.7 +Contact: linux-iio@vger.kernel.org +Description: + List of available timeout value for tap gesture confirmation. diff --git a/Documentation/ABI/testing/sysfs-bus-spi-devices-spi-nor b/Documentation/ABI/testing/sysfs-bus-spi-devices-spi-nor index c800621eff95f6..9ed5582ddea220 100644 --- a/Documentation/ABI/testing/sysfs-bus-spi-devices-spi-nor +++ b/Documentation/ABI/testing/sysfs-bus-spi-devices-spi-nor @@ -25,6 +25,9 @@ KernelVersion: 5.14 Contact: linux-mtd@lists.infradead.org Description: (RO) Part name of the SPI NOR flash. + The attribute is optional. User space should not rely on + it to be present or even correct. Instead, user space + should read the jedec_id attribute. What: /sys/bus/spi/devices/.../spi-nor/sfdp Date: April 2021 diff --git a/Documentation/ABI/testing/sysfs-class-devfreq b/Documentation/ABI/testing/sysfs-class-devfreq index 5e6b74f304062a..1e7e0bb4c14ecb 100644 --- a/Documentation/ABI/testing/sysfs-class-devfreq +++ b/Documentation/ABI/testing/sysfs-class-devfreq @@ -52,6 +52,9 @@ Description: echo 0 > /sys/class/devfreq/.../trans_stat + If the transition table is bigger than PAGE_SIZE, reading + this will return an -EFBIG error. + What: /sys/class/devfreq/.../available_frequencies Date: October 2012 Contact: Nishanth Menon diff --git a/Documentation/ABI/testing/sysfs-class-hwmon b/Documentation/ABI/testing/sysfs-class-hwmon index 638f4c6d4ec704..3dac923c9b0ef0 100644 --- a/Documentation/ABI/testing/sysfs-class-hwmon +++ b/Documentation/ABI/testing/sysfs-class-hwmon @@ -381,6 +381,15 @@ Description: RW +What: /sys/class/hwmon/hwmonX/tempY_max_alarm +Description: + Maximum temperature alarm flag. + + - 0: OK + - 1: temperature has reached tempY_max + + RO + What: /sys/class/hwmon/hwmonX/tempY_min Description: Temperature min value. @@ -389,6 +398,15 @@ Description: RW +What: /sys/class/hwmon/hwmonX/tempY_min_alarm +Description: + Minimum temperature alarm flag. + + - 0: OK + - 1: temperature has reached tempY_min + + RO + What: /sys/class/hwmon/hwmonX/tempY_max_hyst Description: Temperature hysteresis value for max limit. @@ -434,12 +452,7 @@ Description: - 0: OK - 1: temperature has reached tempY_crit - RW - - Contrary to regular alarm flags which clear themselves - automatically when read, this one sticks until cleared by - the user. This is done by writing 0 to the file. Writing - other values is unsupported. + RO What: /sys/class/hwmon/hwmonX/tempY_crit_hyst Description: @@ -462,6 +475,15 @@ Description: RW +What: /sys/class/hwmon/hwmonX/tempY_emergency_alarm +Description: + Emergency high temperature alarm flag. + + - 0: OK + - 1: temperature has reached tempY_emergency + + RO + What: /sys/class/hwmon/hwmonX/tempY_emergency_hyst Description: Temperature hysteresis value for emergency limit. @@ -887,15 +909,15 @@ Description: RW -What: /sys/class/hwmon/hwmonX/humidityY_input +What: /sys/class/hwmon/hwmonX/humidityY_alarm Description: - Humidity + Humidity limit detection - Unit: milli-percent (per cent mille, pcm) + - 0: OK + - 1: Humidity limit has been reached RO - What: /sys/class/hwmon/hwmonX/humidityY_enable Description: Enable or disable the sensors @@ -908,6 +930,74 @@ Description: RW +What: /sys/class/hwmon/hwmonX/humidityY_fault +Description: + Reports a humidity sensor failure. + + - 1: Failed + - 0: Ok + + RO + +What: /sys/class/hwmon/hwmonX/humidityY_input +Description: + Humidity + + Unit: milli-percent (per cent mille, pcm) + + RO + +What: /sys/class/hwmon/hwmonX/humidityY_label +Description: + Suggested humidity channel label. + + Text string + + Should only be created if the driver has hints about what + this humidity channel is being used for, and user-space + doesn't. In all other cases, the label is provided by + user-space. + + RO + +What: /sys/class/hwmon/hwmonX/humidityY_max +Description: + Humidity max value. + + Unit: milli-percent (per cent mille, pcm) + + RW + +What: /sys/class/hwmon/hwmonX/humidityY_max_hyst +Description: + Humidity hysteresis value for max limit. + + Unit: milli-percent (per cent mille, pcm) + + Must be reported as an absolute humidity, NOT a delta + from the max value. + + RW + +What: /sys/class/hwmon/hwmonX/humidityY_min +Description: + Humidity min value. + + Unit: milli-percent (per cent mille, pcm) + + RW + +What: /sys/class/hwmon/hwmonX/humidityY_min_hyst +Description: + Humidity hysteresis value for min limit. + + Unit: milli-percent (per cent mille, pcm) + + Must be reported as an absolute humidity, NOT a delta + from the min value. + + RW + What: /sys/class/hwmon/hwmonX/humidityY_rated_min Description: Minimum rated humidity. diff --git a/Documentation/ABI/testing/sysfs-class-led-trigger-netdev b/Documentation/ABI/testing/sysfs-class-led-trigger-netdev index f6d9d72ce77b70..a6c307c4befa09 100644 --- a/Documentation/ABI/testing/sysfs-class-led-trigger-netdev +++ b/Documentation/ABI/testing/sysfs-class-led-trigger-netdev @@ -114,6 +114,45 @@ Description: speed of 1000Mbps of the named network device. Setting this value also immediately changes the LED state. +What: /sys/class/leds//link_2500 +Date: Nov 2023 +KernelVersion: 6.8 +Contact: linux-leds@vger.kernel.org +Description: + Signal the link speed state of 2500Mbps of the named network device. + + If set to 0 (default), the LED's normal state is off. + + If set to 1, the LED's normal state reflects the link state + speed of 2500Mbps of the named network device. + Setting this value also immediately changes the LED state. + +What: /sys/class/leds//link_5000 +Date: Nov 2023 +KernelVersion: 6.8 +Contact: linux-leds@vger.kernel.org +Description: + Signal the link speed state of 5000Mbps of the named network device. + + If set to 0 (default), the LED's normal state is off. + + If set to 1, the LED's normal state reflects the link state + speed of 5000Mbps of the named network device. + Setting this value also immediately changes the LED state. + +What: /sys/class/leds//link_10000 +Date: Nov 2023 +KernelVersion: 6.8 +Contact: linux-leds@vger.kernel.org +Description: + Signal the link speed state of 10000Mbps of the named network device. + + If set to 0 (default), the LED's normal state is off. + + If set to 1, the LED's normal state reflects the link state + speed of 10000Mbps of the named network device. + Setting this value also immediately changes the LED state. + What: /sys/class/leds//half_duplex Date: Jun 2023 KernelVersion: 6.5 diff --git a/Documentation/ABI/testing/sysfs-class-led-trigger-tty b/Documentation/ABI/testing/sysfs-class-led-trigger-tty index 2bf6b24e781b06..30cef9ac0f493a 100644 --- a/Documentation/ABI/testing/sysfs-class-led-trigger-tty +++ b/Documentation/ABI/testing/sysfs-class-led-trigger-tty @@ -4,3 +4,59 @@ KernelVersion: 5.10 Contact: linux-leds@vger.kernel.org Description: Specifies the tty device name of the triggering tty + +What: /sys/class/leds//rx +Date: February 2024 +KernelVersion: 6.8 +Description: + Signal reception (rx) of data on the named tty device. + If set to 0, the LED will not blink on reception. + If set to 1 (default), the LED will blink on reception. + +What: /sys/class/leds//tx +Date: February 2024 +KernelVersion: 6.8 +Description: + Signal transmission (tx) of data on the named tty device. + If set to 0, the LED will not blink on transmission. + If set to 1 (default), the LED will blink on transmission. + +What: /sys/class/leds//cts +Date: February 2024 +KernelVersion: 6.8 +Description: + CTS = Clear To Send + DCE is ready to accept data from the DTE. + If the line state is detected, the LED is switched on. + If set to 0 (default), the LED will not evaluate CTS. + If set to 1, the LED will evaluate CTS. + +What: /sys/class/leds//dsr +Date: February 2024 +KernelVersion: 6.8 +Description: + DSR = Data Set Ready + DCE is ready to receive and send data. + If the line state is detected, the LED is switched on. + If set to 0 (default), the LED will not evaluate DSR. + If set to 1, the LED will evaluate DSR. + +What: /sys/class/leds//dcd +Date: February 2024 +KernelVersion: 6.8 +Description: + DCD = Data Carrier Detect + DTE is receiving a carrier from the DCE. + If the line state is detected, the LED is switched on. + If set to 0 (default), the LED will not evaluate CAR (DCD). + If set to 1, the LED will evaluate CAR (DCD). + +What: /sys/class/leds//rng +Date: February 2024 +KernelVersion: 6.8 +Description: + RNG = Ring Indicator + DCE has detected an incoming ring signal on the telephone + line. If the line state is detected, the LED is switched on. + If set to 0 (default), the LED will not evaluate RNG. + If set to 1, the LED will evaluate RNG. diff --git a/Documentation/ABI/testing/sysfs-devices-platform-kunpeng_hccs b/Documentation/ABI/testing/sysfs-devices-platform-kunpeng_hccs index fdb4e36310fb5d..1666340820f75a 100644 --- a/Documentation/ABI/testing/sysfs-devices-platform-kunpeng_hccs +++ b/Documentation/ABI/testing/sysfs-devices-platform-kunpeng_hccs @@ -3,7 +3,7 @@ What: /sys/devices/platform/HISI04Bx:00/chipX/linked_full_lane What: /sys/devices/platform/HISI04Bx:00/chipX/crc_err_cnt Date: November 2023 KernelVersion: 6.6 -Contact: Huisong Li +Contact: Huisong Li Description: The /sys/devices/platform/HISI04Bx:00/chipX/ directory contains read-only attributes exposing some summarization @@ -26,7 +26,7 @@ What: /sys/devices/platform/HISI04Bx:00/chipX/dieY/linked_full_lane What: /sys/devices/platform/HISI04Bx:00/chipX/dieY/crc_err_cnt Date: November 2023 KernelVersion: 6.6 -Contact: Huisong Li +Contact: Huisong Li Description: The /sys/devices/platform/HISI04Bx:00/chipX/dieY/ directory contains read-only attributes exposing some summarization @@ -54,7 +54,7 @@ What: /sys/devices/platform/HISI04Bx:00/chipX/dieY/hccsN/lane_mask What: /sys/devices/platform/HISI04Bx:00/chipX/dieY/hccsN/crc_err_cnt Date: November 2023 KernelVersion: 6.6 -Contact: Huisong Li +Contact: Huisong Li Description: The /sys/devices/platform/HISI04Bx/chipX/dieX/hccsN/ directory contains read-only attributes exposing information about diff --git a/Documentation/ABI/testing/sysfs-driver-habanalabs b/Documentation/ABI/testing/sysfs-driver-habanalabs index c63ca1ad500d15..4244f5af4b54b3 100644 --- a/Documentation/ABI/testing/sysfs-driver-habanalabs +++ b/Documentation/ABI/testing/sysfs-driver-habanalabs @@ -149,6 +149,18 @@ Contact: ogabbay@kernel.org Description: Displays the current clock frequency, in Hz, of the MME compute engine. This property is valid only for the Goya ASIC family +What: /sys/class/accel/accel/device/module_id +Date: Nov 2023 +KernelVersion: not yet upstreamed +Contact: ogabbay@kernel.org +Description: Displays the device's module id + +What: /sys/class/accel/accel/device/parent_device +Date: Nov 2023 +KernelVersion: 6.8 +Contact: ttayar@habana.ai +Description: Displays the name of the parent device of the accel device + What: /sys/class/accel/accel/device/pci_addr Date: Jan 2019 KernelVersion: 5.1 diff --git a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon new file mode 100644 index 00000000000000..8c321bc9dc0440 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon @@ -0,0 +1,70 @@ +What: /sys/devices/.../hwmon/hwmon/power1_max +Date: September 2023 +KernelVersion: 6.5 +Contact: intel-xe@lists.freedesktop.org +Description: RW. Card reactive sustained (PL1) power limit in microwatts. + + The power controller will throttle the operating frequency + if the power averaged over a window (typically seconds) + exceeds this limit. A read value of 0 means that the PL1 + power limit is disabled, writing 0 disables the + limit. Writing values > 0 and <= TDP will enable the power limit. + + Only supported for particular Intel xe graphics platforms. + +What: /sys/devices/.../hwmon/hwmon/power1_rated_max +Date: September 2023 +KernelVersion: 6.5 +Contact: intel-xe@lists.freedesktop.org +Description: RO. Card default power limit (default TDP setting). + + Only supported for particular Intel xe graphics platforms. + +What: /sys/devices/.../hwmon/hwmon/power1_crit +Date: September 2023 +KernelVersion: 6.5 +Contact: intel-xe@lists.freedesktop.org +Description: RW. Card reactive critical (I1) power limit in microwatts. + + Card reactive critical (I1) power limit in microwatts is exposed + for client products. The power controller will throttle the + operating frequency if the power averaged over a window exceeds + this limit. + + Only supported for particular Intel xe graphics platforms. + +What: /sys/devices/.../hwmon/hwmon/curr1_crit +Date: September 2023 +KernelVersion: 6.5 +Contact: intel-xe@lists.freedesktop.org +Description: RW. Card reactive critical (I1) power limit in milliamperes. + + Card reactive critical (I1) power limit in milliamperes is + exposed for server products. The power controller will throttle + the operating frequency if the power averaged over a window + exceeds this limit. + +What: /sys/devices/.../hwmon/hwmon/in0_input +Date: September 2023 +KernelVersion: 6.5 +Contact: intel-xe@lists.freedesktop.org +Description: RO. Current Voltage in millivolt. + + Only supported for particular Intel xe graphics platforms. + +What: /sys/devices/.../hwmon/hwmon/energy1_input +Date: September 2023 +KernelVersion: 6.5 +Contact: intel-xe@lists.freedesktop.org +Description: RO. Energy input of device in microjoules. + + Only supported for particular Intel xe graphics platforms. + +What: /sys/devices/.../hwmon/hwmon/power1_max_interval +Date: October 2023 +KernelVersion: 6.6 +Contact: intel-xe@lists.freedesktop.org +Description: RW. Sustained power limit interval (Tau in PL1/Tau) in + milliseconds over which sustained power is averaged. + + Only supported for particular Intel xe graphics platforms. diff --git a/Documentation/ABI/testing/sysfs-driver-ufs b/Documentation/ABI/testing/sysfs-driver-ufs index 0c7efaf62de0c0..5bf7073b4f75be 100644 --- a/Documentation/ABI/testing/sysfs-driver-ufs +++ b/Documentation/ABI/testing/sysfs-driver-ufs @@ -1223,6 +1223,55 @@ Description: This file shows the total latency (in micro seconds) of write The file is read only. +What: /sys/bus/platform/drivers/ufshcd/*/power_info/lane +What: /sys/bus/platform/devices/*.ufs/power_info/lane +Date: September 2023 +Contact: Can Guo +Description: This file shows how many lanes are enabled on the UFS link, + i.e., an output 2 means UFS link is operating with 2 lanes. + + The file is read only. + +What: /sys/bus/platform/drivers/ufshcd/*/power_info/mode +What: /sys/bus/platform/devices/*.ufs/power_info/mode +Date: September 2023 +Contact: Can Guo +Description: This file shows the PA power mode of UFS. + + The file is read only. + +What: /sys/bus/platform/drivers/ufshcd/*/power_info/rate +What: /sys/bus/platform/devices/*.ufs/power_info/rate +Date: September 2023 +Contact: Can Guo +Description: This file shows the speed rate of UFS link. + + The file is read only. + +What: /sys/bus/platform/drivers/ufshcd/*/power_info/gear +What: /sys/bus/platform/devices/*.ufs/power_info/gear +Date: September 2023 +Contact: Can Guo +Description: This file shows the gear of UFS link. + + The file is read only. + +What: /sys/bus/platform/drivers/ufshcd/*/power_info/dev_pm +What: /sys/bus/platform/devices/*.ufs/power_info/dev_pm +Date: September 2023 +Contact: Can Guo +Description: This file shows the UFS device power mode. + + The file is read only. + +What: /sys/bus/platform/drivers/ufshcd/*/power_info/link_state +What: /sys/bus/platform/devices/*.ufs/power_info/link_state +Date: September 2023 +Contact: Can Guo +Description: This file shows the state of UFS link. + + The file is read only. + What: /sys/bus/platform/drivers/ufshcd/*/device_descriptor/wb_presv_us_en What: /sys/bus/platform/devices/*.ufs/device_descriptor/wb_presv_us_en Date: June 2020 @@ -1474,3 +1523,10 @@ Description: Indicates status of Write Booster. The file is read only. +What: /sys/bus/platform/drivers/ufshcd/*/rtc_update_ms +What: /sys/bus/platform/devices/*.ufs/rtc_update_ms +Date: November 2023 +Contact: Bean Huo +Description: + rtc_update_ms indicates how often the host should synchronize or update the + UFS RTC. If set to 0, this will disable UFS RTC periodic update. diff --git a/Documentation/ABI/testing/sysfs-firmware-initrd b/Documentation/ABI/testing/sysfs-firmware-initrd new file mode 100644 index 00000000000000..20bf7cf77a1910 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-firmware-initrd @@ -0,0 +1,8 @@ +What: /sys/firmware/initrd +Date: December 2023 +Contact: Alexander Graf +Description: + When the kernel was booted with an initrd and the + "retain_initrd" option is set on the kernel command + line, /sys/firmware/initrd contains the contents of the + initrd that the kernel was booted with. diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs index 36c3cb5479013a..99fa87a43926e6 100644 --- a/Documentation/ABI/testing/sysfs-fs-f2fs +++ b/Documentation/ABI/testing/sysfs-fs-f2fs @@ -498,6 +498,21 @@ Description: Show status of f2fs checkpoint in real time. CP_RESIZEFS_FLAG 0x00004000 =============================== ============================== +What: /sys/fs/f2fs//stat/issued_discard +Date: December 2023 +Contact: "Zhiguo Niu" +Description: Shows the number of issued discard. + +What: /sys/fs/f2fs//stat/queued_discard +Date: December 2023 +Contact: "Zhiguo Niu" +Description: Shows the number of queued discard. + +What: /sys/fs/f2fs//stat/undiscard_blks +Date: December 2023 +Contact: "Zhiguo Niu" +Description: Shows the total number of undiscard blocks. + What: /sys/fs/f2fs//ckpt_thread_ioprio Date: January 2021 Contact: "Daeho Jeong" @@ -740,3 +755,9 @@ Description: When compress cache is on, it controls cached page If cached page percent exceed threshold, then deny caching compress page. The value should be in range of (0, 100], by default it was initialized as 20(%). + +What: /sys/fs/f2fs//discard_io_aware +Date: November 2023 +Contact: "Chao Yu" +Description: It controls to enable/disable IO aware feature for background discard. + By default, the value is 1 which indicates IO aware is on. diff --git a/Documentation/ABI/testing/sysfs-kernel-mm-damon b/Documentation/ABI/testing/sysfs-kernel-mm-damon index b35649a46a2f04..bfa5b8288d8d11 100644 --- a/Documentation/ABI/testing/sysfs-kernel-mm-damon +++ b/Documentation/ABI/testing/sysfs-kernel-mm-damon @@ -25,12 +25,14 @@ Description: Writing 'on' or 'off' to this file makes the kdamond starts or stops, respectively. Reading the file returns the keywords based on the current status. Writing 'commit' to this file makes the kdamond reads the user inputs in the sysfs files - except 'state' again. Writing 'update_schemes_stats' to the - file updates contents of schemes stats files of the kdamond. - Writing 'update_schemes_tried_regions' to the file updates - contents of 'tried_regions' directory of every scheme directory - of this kdamond. Writing 'update_schemes_tried_bytes' to the - file updates only '.../tried_regions/total_bytes' files of this + except 'state' again. Writing 'commit_schemes_quota_goals' to + this file makes the kdamond reads the quota goal files again. + Writing 'update_schemes_stats' to the file updates contents of + schemes stats files of the kdamond. Writing + 'update_schemes_tried_regions' to the file updates contents of + 'tried_regions' directory of every scheme directory of this + kdamond. Writing 'update_schemes_tried_bytes' to the file + updates only '.../tried_regions/total_bytes' files of this kdamond. Writing 'clear_schemes_tried_regions' to the file removes contents of the 'tried_regions' directory. @@ -212,6 +214,25 @@ Contact: SeongJae Park Description: Writing to and reading from this file sets and gets the quotas charge reset interval of the scheme in milliseconds. +What: /sys/kernel/mm/damon/admin/kdamonds//contexts//schemes//quotas/goals/nr_goals +Date: Nov 2023 +Contact: SeongJae Park +Description: Writing a number 'N' to this file creates the number of + directories for setting automatic tuning of the scheme's + aggressiveness named '0' to 'N-1' under the goals/ directory. + +What: /sys/kernel/mm/damon/admin/kdamonds//contexts//schemes//quotas/goals//target_value +Date: Nov 2023 +Contact: SeongJae Park +Description: Writing to and reading from this file sets and gets the target + value of the goal metric. + +What: /sys/kernel/mm/damon/admin/kdamonds//contexts//schemes//quotas/goals//current_value +Date: Nov 2023 +Contact: SeongJae Park +Description: Writing to and reading from this file sets and gets the current + value of the goal metric. + What: /sys/kernel/mm/damon/admin/kdamonds//contexts//schemes//quotas/weights/sz_permil Date: Mar 2022 Contact: SeongJae Park diff --git a/Documentation/ABI/testing/sysfs-nvmem-cells b/Documentation/ABI/testing/sysfs-nvmem-cells new file mode 100644 index 00000000000000..7af70adf3690e3 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-nvmem-cells @@ -0,0 +1,21 @@ +What: /sys/bus/nvmem/devices/.../cells/ +Date: May 2023 +KernelVersion: 6.5 +Contact: Miquel Raynal +Description: + The "cells" folder contains one file per cell exposed by the + NVMEM device. The name of the file is: @, with + being the cell name and its location in the NVMEM + device, in hexadecimal (without the '0x' prefix, to mimic device + tree node names). The length of the file is the size of the cell + (when known). The content of the file is the binary content of + the cell (may sometimes be ASCII, likely without trailing + character). + Note: This file is only present if CONFIG_NVMEM_SYSFS + is enabled. + + Example:: + + hexdump -C /sys/bus/nvmem/devices/1-00563/cells/product-name@d + 00000000 54 4e 34 38 4d 2d 50 2d 44 4e |TN48M-P-DN| + 0000000a diff --git a/Documentation/ABI/testing/sysfs-platform-silicom b/Documentation/ABI/testing/sysfs-platform-silicom new file mode 100644 index 00000000000000..4d1cc5bdbcc5f9 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-platform-silicom @@ -0,0 +1,30 @@ +What: /sys/devices/platform/silicom-platform/uc_version +Date: November 2023 +KernelVersion: 6.7 +Contact: Henry Shi +Description: + This file allows to read microcontroller firmware + version of current platform. + +What: /sys/devices/platform/silicom-platform/power_cycle +Date: November 2023 +KernelVersion: 6.7 +Contact: Henry Shi +Description: + This file allow user to power cycle the platform. + Default value is 0; when set to 1, it powers down + the platform, waits 5 seconds, then powers on the + device. It returns to default value after power cycle. + + 0 - default value. + +What: /sys/devices/platform/silicom-platform/efuse_status +Date: November 2023 +KernelVersion: 6.7 +Contact: Henry Shi +Description: + This file is read only. It returns the current + OTP status: + + 0 - not programmed. + 1 - programmed. diff --git a/Documentation/Makefile b/Documentation/Makefile index 2f35793acd2a18..3885bbe260eb23 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -97,7 +97,21 @@ quiet_cmd_sphinx = SPHINX $@ --> file://$(abspath $(BUILDDIR)/$3/$4) cp $(if $(patsubst /%,,$(DOCS_CSS)),$(abspath $(srctree)/$(DOCS_CSS)),$(DOCS_CSS)) $(BUILDDIR)/$3/_static/; \ fi -htmldocs: +YNL_INDEX:=$(srctree)/Documentation/networking/netlink_spec/index.rst +YNL_RST_DIR:=$(srctree)/Documentation/networking/netlink_spec +YNL_YAML_DIR:=$(srctree)/Documentation/netlink/specs +YNL_TOOL:=$(srctree)/tools/net/ynl/ynl-gen-rst.py + +YNL_RST_FILES_TMP := $(patsubst %.yaml,%.rst,$(wildcard $(YNL_YAML_DIR)/*.yaml)) +YNL_RST_FILES := $(patsubst $(YNL_YAML_DIR)%,$(YNL_RST_DIR)%, $(YNL_RST_FILES_TMP)) + +$(YNL_INDEX): $(YNL_RST_FILES) + $(Q)$(YNL_TOOL) -o $@ -x + +$(YNL_RST_DIR)/%.rst: $(YNL_YAML_DIR)/%.yaml $(YNL_TOOL) + $(Q)$(YNL_TOOL) -i $< -o $@ + +htmldocs: $(YNL_INDEX) @$(srctree)/scripts/sphinx-pre-install --version-check @+$(foreach var,$(SPHINXDIRS),$(call loop_cmd,sphinx,html,$(var),,$(var))) diff --git a/Documentation/PCI/boot-interrupts.rst b/Documentation/PCI/boot-interrupts.rst index 2ec70121bfca5f..931077bb09535d 100644 --- a/Documentation/PCI/boot-interrupts.rst +++ b/Documentation/PCI/boot-interrupts.rst @@ -61,7 +61,7 @@ Conditions ========== The use of threaded interrupts is the most likely condition to trigger -this problem today. Threaded interrupts may not be reenabled after the IRQ +this problem today. Threaded interrupts may not be re-enabled after the IRQ handler wakes. These "one shot" conditions mean that the threaded interrupt needs to keep the interrupt line masked until the threaded handler has run. Especially when dealing with high data rate interrupts, the thread needs to diff --git a/Documentation/PCI/msi-howto.rst b/Documentation/PCI/msi-howto.rst index c9400f02333bf1..783d30b7bb428a 100644 --- a/Documentation/PCI/msi-howto.rst +++ b/Documentation/PCI/msi-howto.rst @@ -236,7 +236,7 @@ including a full 'lspci -v' so we can add the quirks to the kernel. Disabling MSIs below a bridge ----------------------------- -Some PCI bridges are not able to route MSIs between busses properly. +Some PCI bridges are not able to route MSIs between buses properly. In this case, MSIs must be disabled on all devices behind the bridge. Some bridges allow you to enable MSIs by changing some bits in their diff --git a/Documentation/RAS/ras.rst b/Documentation/RAS/ras.rst new file mode 100644 index 00000000000000..2556b397cd271f --- /dev/null +++ b/Documentation/RAS/ras.rst @@ -0,0 +1,26 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Reliability, Availability and Serviceability features +===================================================== + +This documents different aspects of the RAS functionality present in the +kernel. + +Error decoding +--------------- + +* x86 + +Error decoding on AMD systems should be done using the rasdaemon tool: +https://github.com/mchehab/rasdaemon/ + +While the daemon is running, it would automatically log and decode +errors. If not, one can still decode such errors by supplying the +hardware information from the error:: + + $ rasdaemon -p --status --ipid --smca + +Also, the user can pass particular family and model to decode the error +string:: + + $ rasdaemon -p --status --ipid --smca --family --model --bank diff --git a/Documentation/RCU/checklist.rst b/Documentation/RCU/checklist.rst index bd3c58c44befdd..2d42998a89a637 100644 --- a/Documentation/RCU/checklist.rst +++ b/Documentation/RCU/checklist.rst @@ -241,15 +241,22 @@ over a rather long period of time, but improvements are always welcome! srcu_struct. The rules for the expedited RCU grace-period-wait primitives are the same as for their non-expedited counterparts. - If the updater uses call_rcu_tasks() or synchronize_rcu_tasks(), - then the readers must refrain from executing voluntary - context switches, that is, from blocking. If the updater uses - call_rcu_tasks_trace() or synchronize_rcu_tasks_trace(), then - the corresponding readers must use rcu_read_lock_trace() and - rcu_read_unlock_trace(). If an updater uses call_rcu_tasks_rude() - or synchronize_rcu_tasks_rude(), then the corresponding readers - must use anything that disables preemption, for example, - preempt_disable() and preempt_enable(). + Similarly, it is necessary to correctly use the RCU Tasks flavors: + + a. If the updater uses synchronize_rcu_tasks() or + call_rcu_tasks(), then the readers must refrain from + executing voluntary context switches, that is, from + blocking. + + b. If the updater uses call_rcu_tasks_trace() + or synchronize_rcu_tasks_trace(), then the + corresponding readers must use rcu_read_lock_trace() + and rcu_read_unlock_trace(). + + c. If an updater uses call_rcu_tasks_rude() or + synchronize_rcu_tasks_rude(), then the corresponding + readers must use anything that disables preemption, + for example, preempt_disable() and preempt_enable(). Mixing things up will result in confusion and broken kernels, and has even resulted in an exploitable security issue. Therefore, diff --git a/Documentation/RCU/rcu_dereference.rst b/Documentation/RCU/rcu_dereference.rst index 3b739f6243c85e..659d5913784d0d 100644 --- a/Documentation/RCU/rcu_dereference.rst +++ b/Documentation/RCU/rcu_dereference.rst @@ -3,13 +3,26 @@ PROPER CARE AND FEEDING OF RETURN VALUES FROM rcu_dereference() =============================================================== -Most of the time, you can use values from rcu_dereference() or one of -the similar primitives without worries. Dereferencing (prefix "*"), -field selection ("->"), assignment ("="), address-of ("&"), addition and -subtraction of constants, and casts all work quite naturally and safely. - -It is nevertheless possible to get into trouble with other operations. -Follow these rules to keep your RCU code working properly: +Proper care and feeding of address and data dependencies is critically +important to correct use of things like RCU. To this end, the pointers +returned from the rcu_dereference() family of primitives carry address and +data dependencies. These dependencies extend from the rcu_dereference() +macro's load of the pointer to the later use of that pointer to compute +either the address of a later memory access (representing an address +dependency) or the value written by a later memory access (representing +a data dependency). + +Most of the time, these dependencies are preserved, permitting you to +freely use values from rcu_dereference(). For example, dereferencing +(prefix "*"), field selection ("->"), assignment ("="), address-of +("&"), casts, and addition or subtraction of constants all work quite +naturally and safely. However, because current compilers do not take +either address or data dependencies into account it is still possible +to get into trouble. + +Follow these rules to preserve the address and data dependencies emanating +from your calls to rcu_dereference() and friends, thus keeping your RCU +readers working properly: - You must use one of the rcu_dereference() family of primitives to load an RCU-protected pointer, otherwise CONFIG_PROVE_RCU diff --git a/Documentation/RCU/torture.rst b/Documentation/RCU/torture.rst index b3b6dfa85248ea..49e7beea6ae151 100644 --- a/Documentation/RCU/torture.rst +++ b/Documentation/RCU/torture.rst @@ -185,7 +185,7 @@ argument. Not all changes require that all scenarios be run. For example, a change to Tree SRCU might run only the SRCU-N and SRCU-P scenarios using the --configs argument to kvm.sh as follows: "--configs 'SRCU-N SRCU-P'". -Large systems can run multiple copies of of the full set of scenarios, +Large systems can run multiple copies of the full set of scenarios, for example, a system with 448 hardware threads can run five instances of the full set concurrently. To make this happen:: diff --git a/Documentation/accel/introduction.rst b/Documentation/accel/introduction.rst index 89984dfececf0b..ae30301366379d 100644 --- a/Documentation/accel/introduction.rst +++ b/Documentation/accel/introduction.rst @@ -101,8 +101,8 @@ External References email threads ------------- -* `Initial discussion on the New subsystem for acceleration devices `_ - Oded Gabbay (2022) -* `patch-set to add the new subsystem `_ - Oded Gabbay (2022) +* `Initial discussion on the New subsystem for acceleration devices `_ - Oded Gabbay (2022) +* `patch-set to add the new subsystem `_ - Oded Gabbay (2022) Conference talks ---------------- diff --git a/Documentation/accel/qaic/aic100.rst b/Documentation/accel/qaic/aic100.rst index c80d0f1307dbba..590dae77ea124f 100644 --- a/Documentation/accel/qaic/aic100.rst +++ b/Documentation/accel/qaic/aic100.rst @@ -36,8 +36,9 @@ AIC100 DID (0xa100). AIC100 does not implement FLR (function level reset). -AIC100 implements MSI but does not implement MSI-X. AIC100 requires 17 MSIs to -operate (1 for MHI, 16 for the DMA Bridge). +AIC100 implements MSI but does not implement MSI-X. AIC100 prefers 17 MSIs to +operate (1 for MHI, 16 for the DMA Bridge). Falling back to 1 MSI is possible in +scenarios where reserving 32 MSIs isn't feasible. As a PCIe device, AIC100 utilizes BARs to provide host interfaces to the device hardware. AIC100 provides 3, 64-bit BARs. @@ -220,10 +221,14 @@ of the defined channels, and their uses. +----------------+---------+----------+----------------------------------------+ | QAIC_DEBUG | 18 & 19 | AMSS | Not used. | +----------------+---------+----------+----------------------------------------+ -| QAIC_TIMESYNC | 20 & 21 | SBL/AMSS | Used to synchronize timestamps in the | +| QAIC_TIMESYNC | 20 & 21 | SBL | Used to synchronize timestamps in the | | | | | device side logs with the host time | | | | | source. | +----------------+---------+----------+----------------------------------------+ +| QAIC_TIMESYNC | 22 & 23 | AMSS | Used to periodically synchronize | +| _PERIODIC | | | timestamps in the device side logs with| +| | | | the host time source. | ++----------------+---------+----------+----------------------------------------+ DMA Bridge ========== diff --git a/Documentation/accel/qaic/qaic.rst b/Documentation/accel/qaic/qaic.rst index c885023831367b..efb7771273bbc3 100644 --- a/Documentation/accel/qaic/qaic.rst +++ b/Documentation/accel/qaic/qaic.rst @@ -10,6 +10,9 @@ accelerator products. Interrupts ========== +IRQ Storm Mitigation +-------------------- + While the AIC100 DMA Bridge hardware implements an IRQ storm mitigation mechanism, it is still possible for an IRQ storm to occur. A storm can happen if the workload is particularly quick, and the host is responsive. If the host @@ -35,6 +38,26 @@ generates 100k IRQs per second (per /proc/interrupts) is reduced to roughly 64 IRQs over 5 minutes while keeping the host system stable, and having the same workload throughput performance (within run to run noise variation). +Single MSI Mode +--------------- + +MultiMSI is not well supported on all systems; virtualized ones even less so +(circa 2023). Between hypervisors masking the PCIe MSI capability structure to +large memory requirements for vIOMMUs (required for supporting MultiMSI), it is +useful to be able to fall back to a single MSI when needed. + +To support this fallback, we allow the case where only one MSI is able to be +allocated, and share that one MSI between MHI and the DBCs. The device detects +when only one MSI has been configured and directs the interrupts for the DBCs +to the interrupt normally used for MHI. Unfortunately this means that the +interrupt handlers for every DBC and MHI wake up for every interrupt that +arrives; however, the DBC threaded irq handlers only are started when work to be +done is detected (MHI will always start its threaded handler). + +If the DBC is configured to force MSI interrupts, this can circumvent the +software IRQ storm mitigation mentioned above. Since the MSI is shared it is +never disabled, allowing each new entry to the FIFO to trigger a new interrupt. + Neural Network Control (NNC) Protocol ===================================== @@ -70,8 +93,15 @@ commands (does not impact QAIC). uAPI ==== +QAIC creates an accel device per phsyical PCIe device. This accel device exists +for as long as the PCIe device is known to Linux. + +The PCIe device may not be in the state to accept requests from userspace at +all times. QAIC will trigger KOBJ_ONLINE/OFFLINE uevents to advertise when the +device can accept requests (ONLINE) and when the device is no longer accepting +requests (OFFLINE) because of a reset or other state transition. + QAIC defines a number of driver specific IOCTLs as part of the userspace API. -This section describes those APIs. DRM_IOCTL_QAIC_MANAGE This IOCTL allows userspace to send a NNC request to the QSM. The call will @@ -178,3 +208,8 @@ overrides this for that call. Default is 5000 (5 seconds). Sets the polling interval in microseconds (us) when datapath polling is active. Takes effect at the next polling interval. Default is 100 (100 us). + +**timesync_delay_ms (unsigned int)** + +Sets the time interval in milliseconds (ms) between two consecutive timesync +operations. Default is 1000 (1000 ms). diff --git a/Documentation/admin-guide/abi-obsolete.rst b/Documentation/admin-guide/abi-obsolete.rst index d095867899c59a..594e697aa1b2f4 100644 --- a/Documentation/admin-guide/abi-obsolete.rst +++ b/Documentation/admin-guide/abi-obsolete.rst @@ -7,5 +7,5 @@ marked to be removed at some later point in time. The description of the interface will document the reason why it is obsolete and when it can be expected to be removed. -.. kernel-abi:: $srctree/Documentation/ABI/obsolete +.. kernel-abi:: ABI/obsolete :rst: diff --git a/Documentation/admin-guide/abi-removed.rst b/Documentation/admin-guide/abi-removed.rst index f7e9e43023c136..f9e000c81828e5 100644 --- a/Documentation/admin-guide/abi-removed.rst +++ b/Documentation/admin-guide/abi-removed.rst @@ -1,5 +1,5 @@ ABI removed symbols =================== -.. kernel-abi:: $srctree/Documentation/ABI/removed +.. kernel-abi:: ABI/removed :rst: diff --git a/Documentation/admin-guide/abi-stable.rst b/Documentation/admin-guide/abi-stable.rst index 70490736e0d301..fc3361d847b123 100644 --- a/Documentation/admin-guide/abi-stable.rst +++ b/Documentation/admin-guide/abi-stable.rst @@ -10,5 +10,5 @@ for at least 2 years. Most interfaces (like syscalls) are expected to never change and always be available. -.. kernel-abi:: $srctree/Documentation/ABI/stable +.. kernel-abi:: ABI/stable :rst: diff --git a/Documentation/admin-guide/abi-testing.rst b/Documentation/admin-guide/abi-testing.rst index b205b16a72d08a..19767926b34407 100644 --- a/Documentation/admin-guide/abi-testing.rst +++ b/Documentation/admin-guide/abi-testing.rst @@ -16,5 +16,5 @@ Programs that use these interfaces are strongly encouraged to add their name to the description of these interfaces, so that the kernel developers can easily notify them if any changes occur. -.. kernel-abi:: $srctree/Documentation/ABI/testing +.. kernel-abi:: ABI/testing :rst: diff --git a/Documentation/admin-guide/acpi/cppc_sysfs.rst b/Documentation/admin-guide/acpi/cppc_sysfs.rst index e53d76365aa707..36981c66782320 100644 --- a/Documentation/admin-guide/acpi/cppc_sysfs.rst +++ b/Documentation/admin-guide/acpi/cppc_sysfs.rst @@ -75,4 +75,4 @@ taking two different snapshots of feedback counters at time T1 and T2. delivered_counter_delta = fbc_t2[del] - fbc_t1[del] reference_counter_delta = fbc_t2[ref] - fbc_t1[ref] - delivered_perf = (refernce_perf x delivered_counter_delta) / reference_counter_delta + delivered_perf = (reference_perf x delivered_counter_delta) / reference_counter_delta diff --git a/Documentation/admin-guide/blockdev/zram.rst b/Documentation/admin-guide/blockdev/zram.rst index e4551579cb128e..ee2b0030d4168a 100644 --- a/Documentation/admin-guide/blockdev/zram.rst +++ b/Documentation/admin-guide/blockdev/zram.rst @@ -328,7 +328,7 @@ as idle:: From now on, any pages on zram are idle pages. The idle mark will be removed until someone requests access of the block. IOW, unless there is access request, those pages are still idle pages. -Additionally, when CONFIG_ZRAM_MEMORY_TRACKING is enabled pages can be +Additionally, when CONFIG_ZRAM_TRACK_ENTRY_ACTIME is enabled pages can be marked as idle based on how long (in seconds) it's been since they were last accessed:: diff --git a/Documentation/admin-guide/cgroup-v2.rst b/Documentation/admin-guide/cgroup-v2.rst index 3f85254f3cef2c..17e6e956515640 100644 --- a/Documentation/admin-guide/cgroup-v2.rst +++ b/Documentation/admin-guide/cgroup-v2.rst @@ -1093,7 +1093,11 @@ All time durations are in microseconds. A read-write single value file which exists on non-root cgroups. The default is "100". - The weight in the range [1, 10000]. + For non idle groups (cpu.idle = 0), the weight is in the + range [1, 10000]. + + If the cgroup has been configured to be SCHED_IDLE (cpu.idle = 1), + then the weight will show as a 0. cpu.weight.nice A read-write single value file which exists on non-root @@ -1157,6 +1161,16 @@ All time durations are in microseconds. values similar to the sched_setattr(2). This maximum utilization value is used to clamp the task specific maximum utilization clamp. + cpu.idle + A read-write single value file which exists on non-root cgroups. + The default is 0. + + This is the cgroup analog of the per-task SCHED_IDLE sched policy. + Setting this value to a 1 will make the scheduling policy of the + cgroup SCHED_IDLE. The threads inside the cgroup will retain their + own relative priorities, but the cgroup itself will be treated as + very low priority relative to its peers. + Memory @@ -1679,6 +1693,21 @@ PAGE_SIZE multiple when read back. limit, it will refuse to take any more stores before existing entries fault back in or are written out to disk. + memory.zswap.writeback + A read-write single value file. The default value is "1". The + initial value of the root cgroup is 1, and when a new cgroup is + created, it inherits the current value of its parent. + + When this is set to 0, all swapping attempts to swapping devices + are disabled. This included both zswap writebacks, and swapping due + to zswap store failures. If the zswap store failures are recurring + (for e.g if the pages are incompressible), users can observe + reclaim inefficiency after disabling writeback (because the same + pages might be rejected again and again). + + Note that this is subtly different from setting memory.swap.max to + 0, as it still allows for pages to be written to the zswap pool. + memory.pressure A read-only nested-keyed file. @@ -2316,6 +2345,13 @@ Cpuset Interface Files treated to have an implicit value of "cpuset.cpus" in the formation of local partition. + cpuset.cpus.isolated + A read-only and root cgroup only multiple values file. + + This file shows the set of all isolated CPUs used in existing + isolated partitions. It will be empty if no isolated partition + is created. + cpuset.cpus.partition A read-write single value file which exists on non-root cpuset-enabled cgroups. This flag is owned by the parent cgroup @@ -2358,11 +2394,11 @@ Cpuset Interface Files partition or scheduling domain. The set of exclusive CPUs is determined by the value of its "cpuset.cpus.exclusive.effective". - When set to "isolated", the CPUs in that partition will - be in an isolated state without any load balancing from the - scheduler. Tasks placed in such a partition with multiple - CPUs should be carefully distributed and bound to each of the - individual CPUs for optimal performance. + When set to "isolated", the CPUs in that partition will be in + an isolated state without any load balancing from the scheduler + and excluded from the unbound workqueues. Tasks placed in such + a partition with multiple CPUs should be carefully distributed + and bound to each of the individual CPUs for optimal performance. A partition root ("root" or "isolated") can be in one of the two possible states - valid or invalid. An invalid partition diff --git a/Documentation/admin-guide/cifs/todo.rst b/Documentation/admin-guide/cifs/todo.rst index 2646ed2e2d3e32..9a65c670774ee8 100644 --- a/Documentation/admin-guide/cifs/todo.rst +++ b/Documentation/admin-guide/cifs/todo.rst @@ -2,7 +2,8 @@ TODO ==== -Version 2.14 December 21, 2018 +As of 6.7 kernel. See https://wiki.samba.org/index.php/LinuxCIFSKernel +for list of features added by release A Partial List of Missing Features ================================== @@ -12,22 +13,22 @@ for visible, important contributions to this module. Here is a partial list of the known problems and missing features: a) SMB3 (and SMB3.1.1) missing optional features: + multichannel performance optimizations, algorithmic channel selection, + directory leases optimizations, + support for faster packet signing (GMAC), + support for compression over the network, + T10 copy offload ie "ODX" (copy chunk, and "Duplicate Extents" ioctl + are currently the only two server side copy mechanisms supported) - - multichannel (partially integrated), integration of multichannel with RDMA - - directory leases (improved metadata caching). Currently only implemented for root dir - - T10 copy offload ie "ODX" (copy chunk, and "Duplicate Extents" ioctl - currently the only two server side copy mechanisms supported) +b) Better optimized compounding and error handling for sparse file support, + perhaps addition of new optional SMB3.1.1 fsctls to make collapse range + and insert range more atomic -b) improved sparse file support (fiemap and SEEK_HOLE are implemented - but additional features would be supportable by the protocol such - as FALLOC_FL_COLLAPSE_RANGE and FALLOC_FL_INSERT_RANGE) - -c) Directory entry caching relies on a 1 second timer, rather than - using Directory Leases, currently only the root file handle is cached longer - by leveraging Directory Leases +c) Support for SMB3.1.1 over QUIC (and perhaps other socket based protocols + like SCTP) d) quota support (needs minor kernel change since quota calls otherwise - won't make it to network filesystems or deviceless filesystems). + won't make it to network filesystems or deviceless filesystems). e) Additional use cases can be optimized to use "compounding" (e.g. open/query/close and open/setinfo/close) to reduce the number of @@ -92,23 +93,20 @@ t) split cifs and smb3 support into separate modules so legacy (and less v) Additional testing of POSIX Extensions for SMB3.1.1 -w) Add support for additional strong encryption types, and additional spnego - authentication mechanisms (see MS-SMB2). GCM-256 is now partially implemented. +w) Support for the Mac SMB3.1.1 extensions to improve interop with Apple servers + +x) Support for additional authentication options (e.g. IAKERB, peer-to-peer + Kerberos, SCRAM and others supported by existing servers) -x) Finish support for SMB3.1.1 compression +y) Improved tracing, more eBPF trace points, better scripts for performance + analysis Known Bugs ========== See https://bugzilla.samba.org - search on product "CifsVFS" for current bug list. Also check http://bugzilla.kernel.org (Product = File System, Component = CIFS) - -1) existing symbolic links (Windows reparse points) are recognized but - can not be created remotely. They are implemented for Samba and those that - support the CIFS Unix extensions, although earlier versions of Samba - overly restrict the pathnames. -2) follow_link and readdir code does not follow dfs junctions - but recognizes them +and xfstest results e.g. https://wiki.samba.org/index.php/Xfstest-results-smb3 Misc testing to do ================== diff --git a/Documentation/admin-guide/cifs/usage.rst b/Documentation/admin-guide/cifs/usage.rst index 5f936b4b601881..aa8290a29dc88b 100644 --- a/Documentation/admin-guide/cifs/usage.rst +++ b/Documentation/admin-guide/cifs/usage.rst @@ -81,7 +81,7 @@ much older and less secure than the default dialect SMB3 which includes many advanced security features such as downgrade attack detection and encrypted shares and stronger signing and authentication algorithms. There are additional mount options that may be helpful for SMB3 to get -improved POSIX behavior (NB: can use vers=3.0 to force only SMB3, never 2.1): +improved POSIX behavior (NB: can use vers=3 to force SMB3 or later, never 2.1): ``mfsymlinks`` and either ``cifsacl`` or ``modefromsid`` (usually with ``idsfromsid``) @@ -715,6 +715,7 @@ DebugData Displays information about active CIFS sessions and Stats Lists summary resource usage information as well as per share statistics. open_files List all the open file handles on all active SMB sessions. +mount_params List of all mount parameters available for the module ======================= ======================================================= Configuration pseudo-files: @@ -864,6 +865,11 @@ i.e.:: echo "value" > /sys/module/cifs/parameters/ +More detailed descriptions of the available module parameters and their values +can be seen by doing: + + modinfo cifs (or modinfo smb3) + ================= ========================================================== 1. enable_oplocks Enable or disable oplocks. Oplocks are enabled by default. [Y/y/1]. To disable use any of [N/n/0]. diff --git a/Documentation/admin-guide/devices.txt b/Documentation/admin-guide/devices.txt index 8390549235304f..94c98be1329a42 100644 --- a/Documentation/admin-guide/devices.txt +++ b/Documentation/admin-guide/devices.txt @@ -2704,6 +2704,9 @@ ... 185 = /dev/ttyNX15 Hilscher netX serial port 15 186 = /dev/ttyJ0 JTAG1 DCC protocol based serial port emulation + + If maximum number of uartlite serial ports is more than 4, then the driver + uses dynamic allocation instead of static allocation for major number. 187 = /dev/ttyUL0 Xilinx uartlite - port 0 ... 190 = /dev/ttyUL3 Xilinx uartlite - port 3 diff --git a/Documentation/admin-guide/dynamic-debug-howto.rst b/Documentation/admin-guide/dynamic-debug-howto.rst index 0c526dac8428a8..0e9b48daf6902f 100644 --- a/Documentation/admin-guide/dynamic-debug-howto.rst +++ b/Documentation/admin-guide/dynamic-debug-howto.rst @@ -321,13 +321,13 @@ Examples :#> ddcmd 'format "nfsd: READ" +p' // enable messages in files of which the paths include string "usb" - :#> ddcmd 'file *usb* +p' > /proc/dynamic_debug/control + :#> ddcmd 'file *usb* +p' // enable all messages - :#> ddcmd '+p' > /proc/dynamic_debug/control + :#> ddcmd '+p' // add module, function to all enabled messages - :#> ddcmd '+mf' > /proc/dynamic_debug/control + :#> ddcmd '+mf' // boot-args example, with newlines and comments for readability Kernel command line: ... diff --git a/Documentation/admin-guide/features.rst b/Documentation/admin-guide/features.rst index 8c167082a84f9e..7651eca38227d0 100644 --- a/Documentation/admin-guide/features.rst +++ b/Documentation/admin-guide/features.rst @@ -1,3 +1,3 @@ .. SPDX-License-Identifier: GPL-2.0 -.. kernel-feat:: $srctree/Documentation/features +.. kernel-feat:: features diff --git a/Documentation/admin-guide/hw_random.rst b/Documentation/admin-guide/hw_random.rst index d494601717f1f6..bfc39f1cf470e6 100644 --- a/Documentation/admin-guide/hw_random.rst +++ b/Documentation/admin-guide/hw_random.rst @@ -14,10 +14,9 @@ into that core. To make the most effective use of these mechanisms, you should download the support software as well. Download the -latest version of the "rng-tools" package from the -hw_random driver's official Web site: +latest version of the "rng-tools" package from: - http://sourceforge.net/projects/gkernel/ + https://github.com/nhorman/rng-tools Those tools use /dev/hwrng to fill the kernel entropy pool, which is used internally and exported by the /dev/urandom and diff --git a/Documentation/admin-guide/index.rst b/Documentation/admin-guide/index.rst index 43ea35613dfcd4..fb40a1f6f79e18 100644 --- a/Documentation/admin-guide/index.rst +++ b/Documentation/admin-guide/index.rst @@ -119,6 +119,7 @@ configure specific aspects of kernel behavior to your liking. parport perf-security pm/index + pmf pnp rapidio ras diff --git a/Documentation/admin-guide/kdump/vmcoreinfo.rst b/Documentation/admin-guide/kdump/vmcoreinfo.rst index 78e4d2e7ba1447..bced9e4b6e0899 100644 --- a/Documentation/admin-guide/kdump/vmcoreinfo.rst +++ b/Documentation/admin-guide/kdump/vmcoreinfo.rst @@ -172,7 +172,7 @@ variables. Offset of the free_list's member. This value is used to compute the number of free pages. -Each zone has a free_area structure array called free_area[MAX_ORDER + 1]. +Each zone has a free_area structure array called free_area[NR_PAGE_ORDERS]. The free_list represents a linked list of free page blocks. (list_head, next|prev) @@ -189,11 +189,11 @@ Offsets of the vmap_area's members. They carry vmalloc-specific information. Makedumpfile gets the start address of the vmalloc region from this. -(zone.free_area, MAX_ORDER + 1) -------------------------------- +(zone.free_area, NR_PAGE_ORDERS) +-------------------------------- Free areas descriptor. User-space tools use this value to iterate the -free_area ranges. MAX_ORDER is used by the zone buddy allocator. +free_area ranges. NR_PAGE_ORDERS is used by the zone buddy allocator. prb --- diff --git a/Documentation/admin-guide/kernel-parameters.rst b/Documentation/admin-guide/kernel-parameters.rst index 102937bc8443a2..4410384596a90b 100644 --- a/Documentation/admin-guide/kernel-parameters.rst +++ b/Documentation/admin-guide/kernel-parameters.rst @@ -218,8 +218,3 @@ bytes respectively. Such letter suffixes can also be entirely omitted: .. include:: kernel-parameters.txt :literal: - -Todo ----- - - Add more DRM drivers. diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 65731b060e3fef..31b3a25680d08c 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -1,3 +1,14 @@ + accept_memory= [MM] + Format: { eager | lazy } + default: lazy + By default, unaccepted memory is accepted lazily to + avoid prolonged boot times. The lazy option will add + some runtime overhead until all memory is eventually + accepted. In most cases the overhead is negligible. + For some workloads or for debugging purposes + accept_memory=eager can be used to accept all memory + at once during boot. + acpi= [HW,ACPI,X86,ARM64,RISCV64] Advanced Configuration and Power Interface Format: { force | on | off | strict | noirq | rsdt | @@ -877,9 +888,9 @@ memory region [offset, offset + size] for that kernel image. If '@offset' is omitted, then a suitable offset is selected automatically. - [KNL, X86-64, ARM64, RISCV] Select a region under 4G first, and - fall back to reserve region above 4G when '@offset' - hasn't been specified. + [KNL, X86-64, ARM64, RISCV, LoongArch] Select a region + under 4G first, and fall back to reserve region above + 4G when '@offset' hasn't been specified. See Documentation/admin-guide/kdump/kdump.rst for further details. crashkernel=range1:size1[,range2:size2,...][@offset] @@ -890,25 +901,27 @@ Documentation/admin-guide/kdump/kdump.rst for an example. crashkernel=size[KMG],high - [KNL, X86-64, ARM64, RISCV] range could be above 4G. + [KNL, X86-64, ARM64, RISCV, LoongArch] range could be + above 4G. Allow kernel to allocate physical memory region from top, so could be above 4G if system have more than 4G ram installed. Otherwise memory region will be allocated below 4G, if available. It will be ignored if crashkernel=X is specified. crashkernel=size[KMG],low - [KNL, X86-64, ARM64, RISCV] range under 4G. When crashkernel=X,high - is passed, kernel could allocate physical memory region - above 4G, that cause second kernel crash on system - that require some amount of low memory, e.g. swiotlb - requires at least 64M+32K low memory, also enough extra - low memory is needed to make sure DMA buffers for 32-bit - devices won't run out. Kernel would try to allocate + [KNL, X86-64, ARM64, RISCV, LoongArch] range under 4G. + When crashkernel=X,high is passed, kernel could allocate + physical memory region above 4G, that cause second kernel + crash on system that require some amount of low memory, + e.g. swiotlb requires at least 64M+32K low memory, also + enough extra low memory is needed to make sure DMA buffers + for 32-bit devices won't run out. Kernel would try to allocate default size of memory below 4G automatically. The default size is platform dependent. --> x86: max(swiotlb_size_or_default() + 8MiB, 256MiB) --> arm64: 128MiB --> riscv: 128MiB + --> loongarch: 128MiB This one lets the user specify own low range under 4G for second kernel instead. 0: to disable low allocation. @@ -970,17 +983,17 @@ buddy allocator. Bigger value increase the probability of catching random memory corruption, but reduce the amount of memory for normal system use. The maximum - possible value is MAX_ORDER/2. Setting this parameter - to 1 or 2 should be enough to identify most random - memory corruption problems caused by bugs in kernel or - driver code when a CPU writes to (or reads from) a - random memory location. Note that there exists a class - of memory corruptions problems caused by buggy H/W or - F/W or by drivers badly programming DMA (basically when - memory is written at bus level and the CPU MMU is - bypassed) which are not detectable by - CONFIG_DEBUG_PAGEALLOC, hence this option will not help - tracking down these problems. + possible value is MAX_PAGE_ORDER/2. Setting this + parameter to 1 or 2 should be enough to identify most + random memory corruption problems caused by bugs in + kernel or driver code when a CPU writes to (or reads + from) a random memory location. Note that there exists + a class of memory corruptions problems caused by buggy + H/W or F/W or by drivers badly programming DMA + (basically when memory is written at bus level and the + CPU MMU is bypassed) which are not detectable by + CONFIG_DEBUG_PAGEALLOC, hence this option will not + help tracking down these problems. debug_pagealloc= [KNL] When CONFIG_DEBUG_PAGEALLOC is set, this parameter @@ -2438,7 +2451,7 @@ between unregistering the boot console and initializing the real console. - keepinitrd [HW,ARM] + keepinitrd [HW,ARM] See retain_initrd. kernelcore= [KNL,X86,IA-64,PPC] Format: nn[KMGTPE] | nn% | "mirror" @@ -3985,9 +3998,9 @@ vulnerability. System may allow data leaks with this option. - no-steal-acc [X86,PV_OPS,ARM64,PPC/PSERIES] Disable paravirtualized - steal time accounting. steal time is computed, but - won't influence scheduler behaviour + no-steal-acc [X86,PV_OPS,ARM64,PPC/PSERIES,RISCV] Disable + paravirtualized steal time accounting. steal time is + computed, but won't influence scheduler behaviour nosync [HW,M68K] Disables sync negotiation for all devices. @@ -4136,7 +4149,7 @@ [KNL] Minimal page reporting order Format: Adjust the minimal page reporting order. The page - reporting is disabled when it exceeds MAX_ORDER. + reporting is disabled when it exceeds MAX_PAGE_ORDER. panic= [KNL] Kernel behaviour on panic: delay timeout > 0: seconds before rebooting @@ -5302,6 +5315,12 @@ Dump ftrace buffer after reporting RCU CPU stall warning. + rcupdate.rcu_cpu_stall_notifiers= [KNL] + Provide RCU CPU stall notifiers, but see the + warnings in the RCU_CPU_STALL_NOTIFIER Kconfig + option's help text. TL;DR: You almost certainly + do not want rcupdate.rcu_cpu_stall_notifiers. + rcupdate.rcu_cpu_stall_suppress= [KNL] Suppress RCU CPU stall warning messages. @@ -5544,6 +5563,13 @@ print every Nth verbose statement, where N is the value specified. + regulator_ignore_unused + [REGULATOR] + Prevents regulator framework from disabling regulators + that are unused, due no driver claiming them. This may + be useful for debug and development, but should not be + needed on a platform with proper driver support. + relax_domain_level= [KNL, SMP] Set scheduler's default relax_domain_level. See Documentation/admin-guide/cgroup-v1/cpusets.rst. @@ -5580,7 +5606,8 @@ Useful for devices that are detected asynchronously (e.g. USB and MMC devices). - retain_initrd [RAM] Keep initrd memory after extraction + retain_initrd [RAM] Keep initrd memory after extraction. After boot, it will + be accessible via /sys/firmware/initrd. retbleed= [X86] Control mitigation of RETBleed (Arbitrary Speculative Code Execution with Return Instructions) @@ -6908,6 +6935,9 @@ pause after every control message); o = USB_QUIRK_HUB_SLOW_RESET (Hub needs extra delay after resetting its port); + p = USB_QUIRK_SHORT_SET_ADDRESS_REQ_TIMEOUT + (Reduce timeout of the SET_ADDRESS + request from 5000 ms to 500 ms); Example: quirks=0781:5580:bk,0a5c:5834:gij usbhid.mousepoll= diff --git a/Documentation/admin-guide/kernel-per-CPU-kthreads.rst b/Documentation/admin-guide/kernel-per-CPU-kthreads.rst index 993c2a05f5eeab..b6aeae3327ceb5 100644 --- a/Documentation/admin-guide/kernel-per-CPU-kthreads.rst +++ b/Documentation/admin-guide/kernel-per-CPU-kthreads.rst @@ -243,13 +243,9 @@ To reduce its OS jitter, do any of the following: 3. Do any of the following needed to avoid jitter that your application cannot tolerate: - a. Build your kernel with CONFIG_SLUB=y rather than - CONFIG_SLAB=y, thus avoiding the slab allocator's periodic - use of each CPU's workqueues to run its cache_reap() - function. - b. Avoid using oprofile, thus avoiding OS jitter from + a. Avoid using oprofile, thus avoiding OS jitter from wq_sync_buffer(). - c. Limit your CPU frequency so that a CPU-frequency + b. Limit your CPU frequency so that a CPU-frequency governor is not required, possibly enlisting the aid of special heatsinks or other cooling technologies. If done correctly, and if you CPU architecture permits, you should @@ -259,7 +255,7 @@ To reduce its OS jitter, do any of the following: WARNING: Please check your CPU specifications to make sure that this is safe on your particular system. - d. As of v3.18, Christoph Lameter's on-demand vmstat workers + c. As of v3.18, Christoph Lameter's on-demand vmstat workers commit prevents OS jitter due to vmstat_update() on CONFIG_SMP=y systems. Before v3.18, is not possible to entirely get rid of the OS jitter, but you can @@ -274,7 +270,7 @@ To reduce its OS jitter, do any of the following: (based on an earlier one from Gilad Ben-Yossef) that reduces or even eliminates vmstat overhead for some workloads at https://lore.kernel.org/r/00000140e9dfd6bd-40db3d4f-c1be-434f-8132-7820f81bb586-000000@email.amazonses.com. - e. If running on high-end powerpc servers, build with + d. If running on high-end powerpc servers, build with CONFIG_PPC_RTAS_DAEMON=n. This prevents the RTAS daemon from running on each CPU every second or so. (This will require editing Kconfig files and will defeat @@ -282,12 +278,12 @@ To reduce its OS jitter, do any of the following: due to the rtas_event_scan() function. WARNING: Please check your CPU specifications to make sure that this is safe on your particular system. - f. If running on Cell Processor, build your kernel with + e. If running on Cell Processor, build your kernel with CBE_CPUFREQ_SPU_GOVERNOR=n to avoid OS jitter from spu_gov_work(). WARNING: Please check your CPU specifications to make sure that this is safe on your particular system. - g. If running on PowerMAC, build your kernel with + f. If running on PowerMAC, build your kernel with CONFIG_PMAC_RACKMETER=n to disable the CPU-meter, avoiding OS jitter from rackmeter_do_timer(). diff --git a/Documentation/admin-guide/media/index.rst b/Documentation/admin-guide/media/index.rst index 43f4a292b24590..be7e0e4482ca51 100644 --- a/Documentation/admin-guide/media/index.rst +++ b/Documentation/admin-guide/media/index.rst @@ -20,16 +20,8 @@ Documentation/driver-api/media/index.rst - for driver development information and Kernel APIs used by media devices; -The media subsystem -=================== - -.. only:: html - - .. class:: toc-title - - Table of Contents - .. toctree:: + :caption: Table of Contents :maxdepth: 2 :numbered: diff --git a/Documentation/admin-guide/media/starfive_camss.rst b/Documentation/admin-guide/media/starfive_camss.rst new file mode 100644 index 00000000000000..ca42e9447c47be --- /dev/null +++ b/Documentation/admin-guide/media/starfive_camss.rst @@ -0,0 +1,72 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: + +================================ +Starfive Camera Subsystem driver +================================ + +Introduction +------------ + +This file documents the driver for the Starfive Camera Subsystem found on +Starfive JH7110 SoC. The driver is located under drivers/staging/media/starfive/ +camss. + +The driver implements V4L2, Media controller and v4l2_subdev interfaces. Camera +sensor using V4L2 subdev interface in the kernel is supported. + +The driver has been successfully used on the Gstreamer 1.18.5 with v4l2src +plugin. + + +Starfive Camera Subsystem hardware +---------------------------------- + +The Starfive Camera Subsystem hardware consists of:: + + |\ +---------------+ +-----------+ + +----------+ | \ | | | | + | | | | | | | | + | MIPI |----->| |----->| ISP |----->| | + | | | | | | | | + +----------+ | | | | | Memory | + |MUX| +---------------+ | Interface | + +----------+ | | | | + | | | |---------------------------->| | + | Parallel |----->| | | | + | | | | | | + +----------+ | / | | + |/ +-----------+ + +- MIPI: The MIPI interface, receiving data from a MIPI CSI-2 camera sensor. + +- Parallel: The parallel interface, receiving data from a parallel sensor. + +- ISP: The ISP, processing raw Bayer data from an image sensor and producing + YUV frames. + + +Topology +-------- + +The media controller pipeline graph is as follows: + +.. _starfive_camss_graph: + +.. kernel-figure:: starfive_camss_graph.dot + :alt: starfive_camss_graph.dot + :align: center + +The driver has 2 video devices: + +- capture_raw: The capture device, capturing image data directly from a sensor. +- capture_yuv: The capture device, capturing YUV frame data processed by the + ISP module + +The driver has 3 subdevices: + +- stf_isp: is responsible for all the isp operations, outputs YUV frames. +- cdns_csi2rx: a CSI-2 bridge supporting up to 4 CSI lanes in input, and 4 + different pixel streams in output. +- imx219: an image sensor, image data is sent through MIPI CSI-2. diff --git a/Documentation/admin-guide/media/starfive_camss_graph.dot b/Documentation/admin-guide/media/starfive_camss_graph.dot new file mode 100644 index 00000000000000..8eff1f161ac7fa --- /dev/null +++ b/Documentation/admin-guide/media/starfive_camss_graph.dot @@ -0,0 +1,12 @@ +digraph board { + rankdir=TB + n00000001 [label="{{ 0} | stf_isp\n/dev/v4l-subdev0 | { 1}}", shape=Mrecord, style=filled, fillcolor=green] + n00000001:port1 -> n00000008 [style=dashed] + n00000004 [label="capture_raw\n/dev/video0", shape=box, style=filled, fillcolor=yellow] + n00000008 [label="capture_yuv\n/dev/video1", shape=box, style=filled, fillcolor=yellow] + n0000000e [label="{{ 0} | cdns_csi2rx.19800000.csi-bridge\n | { 1 | 2 | 3 | 4}}", shape=Mrecord, style=filled, fillcolor=green] + n0000000e:port1 -> n00000001:port0 [style=dashed] + n0000000e:port1 -> n00000004 [style=dashed] + n00000018 [label="{{} | imx219 6-0010\n/dev/v4l-subdev1 | { 0}}", shape=Mrecord, style=filled, fillcolor=green] + n00000018:port0 -> n0000000e:port0 [style=bold] +} diff --git a/Documentation/admin-guide/media/v4l-drivers.rst b/Documentation/admin-guide/media/v4l-drivers.rst index 61283d67ceefb9..f4bb2605f07e3b 100644 --- a/Documentation/admin-guide/media/v4l-drivers.rst +++ b/Documentation/admin-guide/media/v4l-drivers.rst @@ -28,6 +28,7 @@ Video4Linux (V4L) driver-specific documentation si470x si4713 si476x + starfive_camss vimc visl vivid diff --git a/Documentation/admin-guide/media/visl.rst b/Documentation/admin-guide/media/visl.rst index 4328c6c72d305a..db1ef29438e16c 100644 --- a/Documentation/admin-guide/media/visl.rst +++ b/Documentation/admin-guide/media/visl.rst @@ -71,6 +71,7 @@ The following codecs are supported: - VP9 - H.264 - HEVC +- AV1 visl trace events ----------------- @@ -79,6 +80,7 @@ The trace events are defined on a per-codec basis, e.g.: .. code-block:: bash $ ls /sys/kernel/tracing/events/ | grep visl + visl_av1_controls visl_fwht_controls visl_h264_controls visl_hevc_controls diff --git a/Documentation/admin-guide/mm/damon/usage.rst b/Documentation/admin-guide/mm/damon/usage.rst index da94feb97ed161..9d23144bf98501 100644 --- a/Documentation/admin-guide/mm/damon/usage.rst +++ b/Documentation/admin-guide/mm/damon/usage.rst @@ -59,41 +59,47 @@ Files Hierarchy The files hierarchy of DAMON sysfs interface is shown below. In the below figure, parents-children relations are represented with indentations, each directory is having ``/`` suffix, and files in each directory are separated by -comma (","). :: - - /sys/kernel/mm/damon/admin - │ kdamonds/nr_kdamonds - │ │ 0/state,pid - │ │ │ contexts/nr_contexts - │ │ │ │ 0/avail_operations,operations - │ │ │ │ │ monitoring_attrs/ +comma (","). + +.. parsed-literal:: + + :ref:`/sys/kernel/mm/damon `/admin + │ :ref:`kdamonds `/nr_kdamonds + │ │ :ref:`0 `/state,pid + │ │ │ :ref:`contexts `/nr_contexts + │ │ │ │ :ref:`0 `/avail_operations,operations + │ │ │ │ │ :ref:`monitoring_attrs `/ │ │ │ │ │ │ intervals/sample_us,aggr_us,update_us │ │ │ │ │ │ nr_regions/min,max - │ │ │ │ │ targets/nr_targets - │ │ │ │ │ │ 0/pid_target - │ │ │ │ │ │ │ regions/nr_regions - │ │ │ │ │ │ │ │ 0/start,end + │ │ │ │ │ :ref:`targets `/nr_targets + │ │ │ │ │ │ :ref:`0 `/pid_target + │ │ │ │ │ │ │ :ref:`regions `/nr_regions + │ │ │ │ │ │ │ │ :ref:`0 `/start,end │ │ │ │ │ │ │ │ ... │ │ │ │ │ │ ... - │ │ │ │ │ schemes/nr_schemes - │ │ │ │ │ │ 0/action,apply_interval_us - │ │ │ │ │ │ │ access_pattern/ + │ │ │ │ │ :ref:`schemes `/nr_schemes + │ │ │ │ │ │ :ref:`0 `/action,apply_interval_us + │ │ │ │ │ │ │ :ref:`access_pattern `/ │ │ │ │ │ │ │ │ sz/min,max │ │ │ │ │ │ │ │ nr_accesses/min,max │ │ │ │ │ │ │ │ age/min,max - │ │ │ │ │ │ │ quotas/ms,bytes,reset_interval_ms + │ │ │ │ │ │ │ :ref:`quotas `/ms,bytes,reset_interval_ms │ │ │ │ │ │ │ │ weights/sz_permil,nr_accesses_permil,age_permil - │ │ │ │ │ │ │ watermarks/metric,interval_us,high,mid,low - │ │ │ │ │ │ │ filters/nr_filters + │ │ │ │ │ │ │ │ :ref:`goals `/nr_goals + │ │ │ │ │ │ │ │ │ 0/target_value,current_value + │ │ │ │ │ │ │ :ref:`watermarks `/metric,interval_us,high,mid,low + │ │ │ │ │ │ │ :ref:`filters `/nr_filters │ │ │ │ │ │ │ │ 0/type,matching,memcg_id - │ │ │ │ │ │ │ stats/nr_tried,sz_tried,nr_applied,sz_applied,qt_exceeds - │ │ │ │ │ │ │ tried_regions/total_bytes + │ │ │ │ │ │ │ :ref:`stats `/nr_tried,sz_tried,nr_applied,sz_applied,qt_exceeds + │ │ │ │ │ │ │ :ref:`tried_regions `/total_bytes │ │ │ │ │ │ │ │ 0/start,end,nr_accesses,age │ │ │ │ │ │ │ │ ... │ │ │ │ │ │ ... │ │ │ │ ... │ │ ... +.. _sysfs_root: + Root ---- @@ -102,6 +108,8 @@ has one directory named ``admin``. The directory contains the files for privileged user space programs' control of DAMON. User space tools or daemons having the root permission could use this directory. +.. _sysfs_kdamonds: + kdamonds/ --------- @@ -113,6 +121,8 @@ details) exists. In the beginning, this directory has only one file, child directories named ``0`` to ``N-1``. Each directory represents each kdamond. +.. _sysfs_kdamond: + kdamonds// ------------- @@ -120,29 +130,37 @@ In each kdamond directory, two files (``state`` and ``pid``) and one directory (``contexts``) exist. Reading ``state`` returns ``on`` if the kdamond is currently running, or -``off`` if it is not running. Writing ``on`` or ``off`` makes the kdamond be -in the state. Writing ``commit`` to the ``state`` file makes kdamond reads the -user inputs in the sysfs files except ``state`` file again. Writing -``update_schemes_stats`` to ``state`` file updates the contents of stats files -for each DAMON-based operation scheme of the kdamond. For details of the -stats, please refer to :ref:`stats section `. - -Writing ``update_schemes_tried_regions`` to ``state`` file updates the -DAMON-based operation scheme action tried regions directory for each -DAMON-based operation scheme of the kdamond. Writing -``update_schemes_tried_bytes`` to ``state`` file updates only -``.../tried_regions/total_bytes`` files. Writing -``clear_schemes_tried_regions`` to ``state`` file clears the DAMON-based -operating scheme action tried regions directory for each DAMON-based operation -scheme of the kdamond. For details of the DAMON-based operation scheme action -tried regions directory, please refer to :ref:`tried_regions section -`. +``off`` if it is not running. + +Users can write below commands for the kdamond to the ``state`` file. + +- ``on``: Start running. +- ``off``: Stop running. +- ``commit``: Read the user inputs in the sysfs files except ``state`` file + again. +- ``commit_schemes_quota_goals``: Read the DAMON-based operation schemes' + :ref:`quota goals `. +- ``update_schemes_stats``: Update the contents of stats files for each + DAMON-based operation scheme of the kdamond. For details of the stats, + please refer to :ref:`stats section `. +- ``update_schemes_tried_regions``: Update the DAMON-based operation scheme + action tried regions directory for each DAMON-based operation scheme of the + kdamond. For details of the DAMON-based operation scheme action tried + regions directory, please refer to + :ref:`tried_regions section `. +- ``update_schemes_tried_bytes``: Update only ``.../tried_regions/total_bytes`` + files. +- ``clear_schemes_tried_regions``: Clear the DAMON-based operating scheme + action tried regions directory for each DAMON-based operation scheme of the + kdamond. If the state is ``on``, reading ``pid`` shows the pid of the kdamond thread. ``contexts`` directory contains files for controlling the monitoring contexts that this kdamond will execute. +.. _sysfs_contexts: + kdamonds//contexts/ ---------------------- @@ -153,7 +171,7 @@ number (``N``) to the file creates the number of child directories named as details). At the moment, only one context per kdamond is supported, so only ``0`` or ``1`` can be written to the file. -.. _sysfs_contexts: +.. _sysfs_context: contexts// ------------- @@ -203,6 +221,8 @@ writing to and rading from the files. For more details about the intervals and monitoring regions range, please refer to the Design document (:doc:`/mm/damon/design`). +.. _sysfs_targets: + contexts//targets/ --------------------- @@ -210,6 +230,8 @@ In the beginning, this directory has only one file, ``nr_targets``. Writing a number (``N``) to the file creates the number of child directories named ``0`` to ``N-1``. Each directory represents each monitoring target. +.. _sysfs_target: + targets// ------------ @@ -244,6 +266,8 @@ In the beginning, this directory has only one file, ``nr_regions``. Writing a number (``N``) to the file creates the number of child directories named ``0`` to ``N-1``. Each directory represents each initial monitoring target region. +.. _sysfs_region: + regions// ------------ @@ -254,6 +278,8 @@ region by writing to and reading from the files, respectively. Each region should not overlap with others. ``end`` of directory ``N`` should be equal or smaller than ``start`` of directory ``N+1``. +.. _sysfs_schemes: + contexts//schemes/ --------------------- @@ -265,6 +291,8 @@ In the beginning, this directory has only one file, ``nr_schemes``. Writing a number (``N``) to the file creates the number of child directories named ``0`` to ``N-1``. Each directory represents each DAMON-based operation scheme. +.. _sysfs_scheme: + schemes// ------------ @@ -277,7 +305,7 @@ The ``action`` file is for setting and getting the scheme's :ref:`action from the file and their meaning are as below. Note that support of each action depends on the running DAMON operations set -:ref:`implementation `. +:ref:`implementation `. - ``willneed``: Call ``madvise()`` for the region with ``MADV_WILLNEED``. Supported by ``vaddr`` and ``fvaddr`` operations set. @@ -299,6 +327,8 @@ Note that support of each action depends on the running DAMON operations set The ``apply_interval_us`` file is for setting and getting the scheme's :ref:`apply_interval ` in microseconds. +.. _sysfs_access_pattern: + schemes//access_pattern/ --------------------------- @@ -312,6 +342,8 @@ to and reading from the ``min`` and ``max`` files under ``sz``, ``nr_accesses``, and ``age`` directories, respectively. Note that the ``min`` and the ``max`` form a closed interval. +.. _sysfs_quotas: + schemes//quotas/ ------------------- @@ -319,8 +351,7 @@ The directory for the :ref:`quotas ` of the given DAMON-based operation scheme. Under ``quotas`` directory, three files (``ms``, ``bytes``, -``reset_interval_ms``) and one directory (``weights``) having three files -(``sz_permil``, ``nr_accesses_permil``, and ``age_permil``) in it exist. +``reset_interval_ms``) and two directores (``weights`` and ``goals``) exist. You can set the ``time quota`` in milliseconds, ``size quota`` in bytes, and ``reset interval`` in milliseconds by writing the values to the three files, @@ -330,11 +361,37 @@ apply the action to only up to ``bytes`` bytes of memory regions within the ``reset_interval_ms``. Setting both ``ms`` and ``bytes`` zero disables the quota limits. -You can also set the :ref:`prioritization weights +Under ``weights`` directory, three files (``sz_permil``, +``nr_accesses_permil``, and ``age_permil``) exist. +You can set the :ref:`prioritization weights ` for size, access frequency, and age in per-thousand unit by writing the values to the three files under the ``weights`` directory. +.. _sysfs_schemes_quota_goals: + +schemes//quotas/goals/ +------------------------- + +The directory for the :ref:`automatic quota tuning goals +` of the given DAMON-based operation +scheme. + +In the beginning, this directory has only one file, ``nr_goals``. Writing a +number (``N``) to the file creates the number of child directories named ``0`` +to ``N-1``. Each directory represents each goal and current achievement. +Among the multiple feedback, the best one is used. + +Each goal directory contains two files, namely ``target_value`` and +``current_value``. Users can set and get any number to those files to set the +feedback. User space main workload's latency or throughput, system metrics +like free memory ratio or memory pressure stall time (PSI) could be example +metrics for the values. Note that users should write +``commit_schemes_quota_goals`` to the ``state`` file of the :ref:`kdamond +directory ` to pass the feedback to DAMON. + +.. _sysfs_watermarks: + schemes//watermarks/ ----------------------- @@ -354,6 +411,8 @@ as below. The ``interval`` should written in microseconds unit. +.. _sysfs_filters: + schemes//filters/ -------------------- @@ -394,7 +453,7 @@ pages of all memory cgroups except ``/having_care_already``.:: echo N > 1/matching Note that ``anon`` and ``memcg`` filters are currently supported only when -``paddr`` :ref:`implementation ` is being used. +``paddr`` :ref:`implementation ` is being used. Also, memory regions that are filtered out by ``addr`` or ``target`` filters are not counted as the scheme has tried to those, while regions that filtered @@ -449,6 +508,8 @@ and query-like efficient data access monitoring results retrievals. For the latter use case, in particular, users can set the ``action`` as ``stat`` and set the ``access pattern`` as their interested pattern that they want to query. +.. _sysfs_schemes_tried_region: + tried_regions// ------------------ diff --git a/Documentation/admin-guide/mm/ksm.rst b/Documentation/admin-guide/mm/ksm.rst index e59231ac6bb712..a639cac124777f 100644 --- a/Documentation/admin-guide/mm/ksm.rst +++ b/Documentation/admin-guide/mm/ksm.rst @@ -80,6 +80,9 @@ pages_to_scan how many pages to scan before ksmd goes to sleep e.g. ``echo 100 > /sys/kernel/mm/ksm/pages_to_scan``. + The pages_to_scan value cannot be changed if ``advisor_mode`` has + been set to scan-time. + Default: 100 (chosen for demonstration purposes) sleep_millisecs @@ -164,6 +167,29 @@ smart_scan optimization is enabled. The ``pages_skipped`` metric shows how effective the setting is. +advisor_mode + The ``advisor_mode`` selects the current advisor. Two modes are + supported: none and scan-time. The default is none. By setting + ``advisor_mode`` to scan-time, the scan time advisor is enabled. + The section about ``advisor`` explains in detail how the scan time + advisor works. + +adivsor_max_cpu + specifies the upper limit of the cpu percent usage of the ksmd + background thread. The default is 70. + +advisor_target_scan_time + specifies the target scan time in seconds to scan all the candidate + pages. The default value is 200 seconds. + +advisor_min_pages_to_scan + specifies the lower limit of the ``pages_to_scan`` parameter of the + scan time advisor. The default is 500. + +adivsor_max_pages_to_scan + specifies the upper limit of the ``pages_to_scan`` parameter of the + scan time advisor. The default is 30000. + The effectiveness of KSM and MADV_MERGEABLE is shown in ``/sys/kernel/mm/ksm/``: general_profit @@ -263,6 +289,35 @@ ksm_swpin_copy note that KSM page might be copied when swapping in because do_swap_page() cannot do all the locking needed to reconstitute a cross-anon_vma KSM page. +Advisor +======= + +The number of candidate pages for KSM is dynamic. It can be often observed +that during the startup of an application more candidate pages need to be +processed. Without an advisor the ``pages_to_scan`` parameter needs to be +sized for the maximum number of candidate pages. The scan time advisor can +changes the ``pages_to_scan`` parameter based on demand. + +The advisor can be enabled, so KSM can automatically adapt to changes in the +number of candidate pages to scan. Two advisors are implemented: none and +scan-time. With none, no advisor is enabled. The default is none. + +The scan time advisor changes the ``pages_to_scan`` parameter based on the +observed scan times. The possible values for the ``pages_to_scan`` parameter is +limited by the ``advisor_max_cpu`` parameter. In addition there is also the +``advisor_target_scan_time`` parameter. This parameter sets the target time to +scan all the KSM candidate pages. The parameter ``advisor_target_scan_time`` +decides how aggressive the scan time advisor scans candidate pages. Lower +values make the scan time advisor to scan more aggresively. This is the most +important parameter for the configuration of the scan time advisor. + +The initial value and the maximum value can be changed with +``advisor_min_pages_to_scan`` and ``advisor_max_pages_to_scan``. The default +values are sufficient for most workloads and use cases. + +The ``pages_to_scan`` parameter is re-calculated after a scan has been completed. + + -- Izik Eidus, Hugh Dickins, 17 Nov 2009 diff --git a/Documentation/admin-guide/mm/pagemap.rst b/Documentation/admin-guide/mm/pagemap.rst index fe17cf21042651..f5f065c67615d3 100644 --- a/Documentation/admin-guide/mm/pagemap.rst +++ b/Documentation/admin-guide/mm/pagemap.rst @@ -253,6 +253,7 @@ Following flags about pages are currently supported: - ``PAGE_IS_SWAPPED`` - Page is in swapped - ``PAGE_IS_PFNZERO`` - Page has zero PFN - ``PAGE_IS_HUGE`` - Page is THP or Hugetlb backed +- ``PAGE_IS_SOFT_DIRTY`` - Page is soft-dirty The ``struct pm_scan_arg`` is used as the argument of the IOCTL. diff --git a/Documentation/admin-guide/mm/transhuge.rst b/Documentation/admin-guide/mm/transhuge.rst index b0cc8243e09340..04eb45a2f94069 100644 --- a/Documentation/admin-guide/mm/transhuge.rst +++ b/Documentation/admin-guide/mm/transhuge.rst @@ -45,10 +45,25 @@ components: the two is using hugepages just because of the fact the TLB miss is going to run faster. +Modern kernels support "multi-size THP" (mTHP), which introduces the +ability to allocate memory in blocks that are bigger than a base page +but smaller than traditional PMD-size (as described above), in +increments of a power-of-2 number of pages. mTHP can back anonymous +memory (for example 16K, 32K, 64K, etc). These THPs continue to be +PTE-mapped, but in many cases can still provide similar benefits to +those outlined above: Page faults are significantly reduced (by a +factor of e.g. 4, 8, 16, etc), but latency spikes are much less +prominent because the size of each page isn't as huge as the PMD-sized +variant and there is less memory to clear in each page fault. Some +architectures also employ TLB compression mechanisms to squeeze more +entries in when a set of PTEs are virtually and physically contiguous +and approporiately aligned. In this case, TLB misses will occur less +often. + THP can be enabled system wide or restricted to certain tasks or even memory ranges inside task's address space. Unless THP is completely disabled, there is ``khugepaged`` daemon that scans memory and -collapses sequences of basic pages into huge pages. +collapses sequences of basic pages into PMD-sized huge pages. The THP behaviour is controlled via :ref:`sysfs ` interface and using madvise(2) and prctl(2) system calls. @@ -95,12 +110,40 @@ Global THP controls Transparent Hugepage Support for anonymous memory can be entirely disabled (mostly for debugging purposes) or only enabled inside MADV_HUGEPAGE regions (to avoid the risk of consuming more memory resources) or enabled -system wide. This can be achieved with one of:: +system wide. This can be achieved per-supported-THP-size with one of:: + + echo always >/sys/kernel/mm/transparent_hugepage/hugepages-kB/enabled + echo madvise >/sys/kernel/mm/transparent_hugepage/hugepages-kB/enabled + echo never >/sys/kernel/mm/transparent_hugepage/hugepages-kB/enabled + +where is the hugepage size being addressed, the available sizes +for which vary by system. + +For example:: + + echo always >/sys/kernel/mm/transparent_hugepage/hugepages-2048kB/enabled + +Alternatively it is possible to specify that a given hugepage size +will inherit the top-level "enabled" value:: + + echo inherit >/sys/kernel/mm/transparent_hugepage/hugepages-kB/enabled + +For example:: + + echo inherit >/sys/kernel/mm/transparent_hugepage/hugepages-2048kB/enabled + +The top-level setting (for use with "inherit") can be set by issuing +one of the following commands:: echo always >/sys/kernel/mm/transparent_hugepage/enabled echo madvise >/sys/kernel/mm/transparent_hugepage/enabled echo never >/sys/kernel/mm/transparent_hugepage/enabled +By default, PMD-sized hugepages have enabled="inherit" and all other +hugepage sizes have enabled="never". If enabling multiple hugepage +sizes, the kernel will select the most appropriate enabled size for a +given allocation. + It's also possible to limit defrag efforts in the VM to generate anonymous hugepages in case they're not immediately free to madvise regions or to never try to defrag memory and simply fallback to regular @@ -146,25 +189,34 @@ madvise never should be self-explanatory. -By default kernel tries to use huge zero page on read page fault to -anonymous mapping. It's possible to disable huge zero page by writing 0 -or enable it back by writing 1:: +By default kernel tries to use huge, PMD-mappable zero page on read +page fault to anonymous mapping. It's possible to disable huge zero +page by writing 0 or enable it back by writing 1:: echo 0 >/sys/kernel/mm/transparent_hugepage/use_zero_page echo 1 >/sys/kernel/mm/transparent_hugepage/use_zero_page -Some userspace (such as a test program, or an optimized memory allocation -library) may want to know the size (in bytes) of a transparent hugepage:: +Some userspace (such as a test program, or an optimized memory +allocation library) may want to know the size (in bytes) of a +PMD-mappable transparent hugepage:: cat /sys/kernel/mm/transparent_hugepage/hpage_pmd_size -khugepaged will be automatically started when -transparent_hugepage/enabled is set to "always" or "madvise, and it'll -be automatically shutdown if it's set to "never". +khugepaged will be automatically started when one or more hugepage +sizes are enabled (either by directly setting "always" or "madvise", +or by setting "inherit" while the top-level enabled is set to "always" +or "madvise"), and it'll be automatically shutdown when the last +hugepage size is disabled (either by directly setting "never", or by +setting "inherit" while the top-level enabled is set to "never"). Khugepaged controls ------------------- +.. note:: + khugepaged currently only searches for opportunities to collapse to + PMD-sized THP and no attempt is made to collapse to other THP + sizes. + khugepaged runs usually at low frequency so while one may not want to invoke defrag algorithms synchronously during the page faults, it should be worth invoking defrag at least in khugepaged. However it's @@ -282,19 +334,26 @@ force Need of application restart =========================== -The transparent_hugepage/enabled values and tmpfs mount option only affect -future behavior. So to make them effective you need to restart any -application that could have been using hugepages. This also applies to the -regions registered in khugepaged. +The transparent_hugepage/enabled and +transparent_hugepage/hugepages-kB/enabled values and tmpfs mount +option only affect future behavior. So to make them effective you need +to restart any application that could have been using hugepages. This +also applies to the regions registered in khugepaged. Monitoring usage ================ -The number of anonymous transparent huge pages currently used by the +.. note:: + Currently the below counters only record events relating to + PMD-sized THP. Events relating to other THP sizes are not included. + +The number of PMD-sized anonymous transparent huge pages currently used by the system is available by reading the AnonHugePages field in ``/proc/meminfo``. -To identify what applications are using anonymous transparent huge pages, -it is necessary to read ``/proc/PID/smaps`` and count the AnonHugePages fields -for each mapping. +To identify what applications are using PMD-sized anonymous transparent huge +pages, it is necessary to read ``/proc/PID/smaps`` and count the AnonHugePages +fields for each mapping. (Note that AnonHugePages only applies to traditional +PMD-sized THP for historical reasons and should have been called +AnonHugePmdMapped). The number of file transparent huge pages mapped to userspace is available by reading ShmemPmdMapped and ShmemHugePages fields in ``/proc/meminfo``. @@ -413,7 +472,7 @@ for huge pages. Optimizing the applications =========================== -To be guaranteed that the kernel will map a 2M page immediately in any +To be guaranteed that the kernel will map a THP immediately in any memory region, the mmap region has to be hugepage naturally aligned. posix_memalign() can provide that guarantee. diff --git a/Documentation/admin-guide/mm/userfaultfd.rst b/Documentation/admin-guide/mm/userfaultfd.rst index 203e26da5f920d..e5cc8848dcb39f 100644 --- a/Documentation/admin-guide/mm/userfaultfd.rst +++ b/Documentation/admin-guide/mm/userfaultfd.rst @@ -113,6 +113,9 @@ events, except page fault notifications, may be generated: areas. ``UFFD_FEATURE_MINOR_SHMEM`` is the analogous feature indicating support for shmem virtual memory areas. +- ``UFFD_FEATURE_MOVE`` indicates that the kernel supports moving an + existing page contents from userspace. + The userland application should set the feature flags it intends to use when invoking the ``UFFDIO_API`` ioctl, to request that those features be enabled if supported. diff --git a/Documentation/admin-guide/mm/zswap.rst b/Documentation/admin-guide/mm/zswap.rst index 45b98390e938d0..b42132969e3157 100644 --- a/Documentation/admin-guide/mm/zswap.rst +++ b/Documentation/admin-guide/mm/zswap.rst @@ -153,6 +153,26 @@ attribute, e. g.:: Setting this parameter to 100 will disable the hysteresis. +Some users cannot tolerate the swapping that comes with zswap store failures +and zswap writebacks. Swapping can be disabled entirely (without disabling +zswap itself) on a cgroup-basis as follows: + + echo 0 > /sys/fs/cgroup//memory.zswap.writeback + +Note that if the store failures are recurring (for e.g if the pages are +incompressible), users can observe reclaim inefficiency after disabling +writeback (because the same pages might be rejected again and again). + +When there is a sizable amount of cold memory residing in the zswap pool, it +can be advantageous to proactively write these cold pages to swap and reclaim +the memory for other use cases. By default, the zswap shrinker is disabled. +User can enable it as follows: + + echo Y > /sys/module/zswap/parameters/shrinker_enabled + +This can be enabled at the boot time if ``CONFIG_ZSWAP_SHRINKER_DEFAULT_ON`` is +selected. + A debugfs interface is provided for various statistic about pool size, number of pages stored, same-value filled pages and various counters for the reasons pages are rejected. diff --git a/Documentation/admin-guide/perf/dwc_pcie_pmu.rst b/Documentation/admin-guide/perf/dwc_pcie_pmu.rst new file mode 100644 index 00000000000000..d47cd229d7106f --- /dev/null +++ b/Documentation/admin-guide/perf/dwc_pcie_pmu.rst @@ -0,0 +1,94 @@ +====================================================================== +Synopsys DesignWare Cores (DWC) PCIe Performance Monitoring Unit (PMU) +====================================================================== + +DesignWare Cores (DWC) PCIe PMU +=============================== + +The PMU is a PCIe configuration space register block provided by each PCIe Root +Port in a Vendor-Specific Extended Capability named RAS D.E.S (Debug, Error +injection, and Statistics). + +As the name indicates, the RAS DES capability supports system level +debugging, AER error injection, and collection of statistics. To facilitate +collection of statistics, Synopsys DesignWare Cores PCIe controller +provides the following two features: + +- one 64-bit counter for Time Based Analysis (RX/TX data throughput and + time spent in each low-power LTSSM state) and +- one 32-bit counter for Event Counting (error and non-error events for + a specified lane) + +Note: There is no interrupt for counter overflow. + +Time Based Analysis +------------------- + +Using this feature you can obtain information regarding RX/TX data +throughput and time spent in each low-power LTSSM state by the controller. +The PMU measures data in two categories: + +- Group#0: Percentage of time the controller stays in LTSSM states. +- Group#1: Amount of data processed (Units of 16 bytes). + +Lane Event counters +------------------- + +Using this feature you can obtain Error and Non-Error information in +specific lane by the controller. The PMU event is selected by all of: + +- Group i +- Event j within the Group i +- Lane k + +Some of the events only exist for specific configurations. + +DesignWare Cores (DWC) PCIe PMU Driver +======================================= + +This driver adds PMU devices for each PCIe Root Port named based on the BDF of +the Root Port. For example, + + 30:03.0 PCI bridge: Device 1ded:8000 (rev 01) + +the PMU device name for this Root Port is dwc_rootport_3018. + +The DWC PCIe PMU driver registers a perf PMU driver, which provides +description of available events and configuration options in sysfs, see +/sys/bus/event_source/devices/dwc_rootport_{bdf}. + +The "format" directory describes format of the config fields of the +perf_event_attr structure. The "events" directory provides configuration +templates for all documented events. For example, +"Rx_PCIe_TLP_Data_Payload" is an equivalent of "eventid=0x22,type=0x1". + +The "perf list" command shall list the available events from sysfs, e.g.:: + + $# perf list | grep dwc_rootport + <...> + dwc_rootport_3018/Rx_PCIe_TLP_Data_Payload/ [Kernel PMU event] + <...> + dwc_rootport_3018/rx_memory_read,lane=?/ [Kernel PMU event] + +Time Based Analysis Event Usage +------------------------------- + +Example usage of counting PCIe RX TLP data payload (Units of bytes):: + + $# perf stat -a -e dwc_rootport_3018/Rx_PCIe_TLP_Data_Payload/ + +The average RX/TX bandwidth can be calculated using the following formula: + + PCIe RX Bandwidth = Rx_PCIe_TLP_Data_Payload / Measure_Time_Window + PCIe TX Bandwidth = Tx_PCIe_TLP_Data_Payload / Measure_Time_Window + +Lane Event Usage +------------------------------- + +Each lane has the same event set and to avoid generating a list of hundreds +of events, the user need to specify the lane ID explicitly, e.g.:: + + $# perf stat -a -e dwc_rootport_3018/rx_memory_read,lane=4/ + +The driver does not support sampling, therefore "perf record" will not +work. Per-task (without "-a") perf sessions are not supported. diff --git a/Documentation/admin-guide/perf/imx-ddr.rst b/Documentation/admin-guide/perf/imx-ddr.rst index 90926d0fb8eca4..77418ae5a29075 100644 --- a/Documentation/admin-guide/perf/imx-ddr.rst +++ b/Documentation/admin-guide/perf/imx-ddr.rst @@ -13,8 +13,8 @@ is one register for each counter. Counter 0 is special in that it always counts interrupt is raised. If any other counter overflows, it continues counting, and no interrupt is raised. -The "format" directory describes format of the config (event ID) and config1 -(AXI filtering) fields of the perf_event_attr structure, see /sys/bus/event_source/ +The "format" directory describes format of the config (event ID) and config1/2 +(AXI filter setting) fields of the perf_event_attr structure, see /sys/bus/event_source/ devices/imx8_ddr0/format/. The "events" directory describes the events types hardware supported that can be used with perf tool, see /sys/bus/event_source/ devices/imx8_ddr0/events/. The "caps" directory describes filter features implemented @@ -28,12 +28,11 @@ in DDR PMU, see /sys/bus/events_source/devices/imx8_ddr0/caps/. AXI filtering is only used by CSV modes 0x41 (axid-read) and 0x42 (axid-write) to count reading or writing matches filter setting. Filter setting is various from different DRAM controller implementations, which is distinguished by quirks -in the driver. You also can dump info from userspace, filter in "caps" directory -indicates whether PMU supports AXI ID filter or not; enhanced_filter indicates -whether PMU supports enhanced AXI ID filter or not. Value 0 for un-supported, and -value 1 for supported. +in the driver. You also can dump info from userspace, "caps" directory show the +type of AXI filter (filter, enhanced_filter and super_filter). Value 0 for +un-supported, and value 1 for supported. -* With DDR_CAP_AXI_ID_FILTER quirk(filter: 1, enhanced_filter: 0). +* With DDR_CAP_AXI_ID_FILTER quirk(filter: 1, enhanced_filter: 0, super_filter: 0). Filter is defined with two configuration parts: --AXI_ID defines AxID matching value. --AXI_MASKING defines which bits of AxID are meaningful for the matching. @@ -65,7 +64,37 @@ value 1 for supported. perf stat -a -e imx8_ddr0/axid-read,axi_id=0x12/ cmd, which will monitor ARID=0x12 -* With DDR_CAP_AXI_ID_FILTER_ENHANCED quirk(filter: 1, enhanced_filter: 1). +* With DDR_CAP_AXI_ID_FILTER_ENHANCED quirk(filter: 1, enhanced_filter: 1, super_filter: 0). This is an extension to the DDR_CAP_AXI_ID_FILTER quirk which permits counting the number of bytes (as opposed to the number of bursts) from DDR read and write transactions concurrently with another set of data counters. + +* With DDR_CAP_AXI_ID_PORT_CHANNEL_FILTER quirk(filter: 0, enhanced_filter: 0, super_filter: 1). + There is a limitation in previous AXI filter, it cannot filter different IDs + at the same time as the filter is shared between counters. This quirk is the + extension of AXI ID filter. One improvement is that counter 1-3 has their own + filter, means that it supports concurrently filter various IDs. Another + improvement is that counter 1-3 supports AXI PORT and CHANNEL selection. Support + selecting address channel or data channel. + + Filter is defined with 2 configuration registers per counter 1-3. + --Counter N MASK COMP register - including AXI_ID and AXI_MASKING. + --Counter N MUX CNTL register - including AXI CHANNEL and AXI PORT. + + - 0: address channel + - 1: data channel + + PMU in DDR subsystem, only one single port0 exists, so axi_port is reserved + which should be 0. + + .. code-block:: bash + + perf stat -a -e imx8_ddr0/axid-read,axi_mask=0xMMMM,axi_id=0xDDDD,axi_channel=0xH/ cmd + perf stat -a -e imx8_ddr0/axid-write,axi_mask=0xMMMM,axi_id=0xDDDD,axi_channel=0xH/ cmd + + .. note:: + + axi_channel is inverted in userspace, and it will be reverted in driver + automatically. So that users do not need specify axi_channel if want to + monitor data channel from DDR transactions, since data channel is more + meaningful. diff --git a/Documentation/admin-guide/perf/index.rst b/Documentation/admin-guide/perf/index.rst index a2e6f2c81146b0..f4a4513c526f05 100644 --- a/Documentation/admin-guide/perf/index.rst +++ b/Documentation/admin-guide/perf/index.rst @@ -19,6 +19,7 @@ Performance monitor support arm_dsu_pmu thunderx2-pmu alibaba_pmu + dwc_pcie_pmu nvidia-pmu meson-ddr-pmu cxl diff --git a/Documentation/admin-guide/pm/amd-pstate.rst b/Documentation/admin-guide/pm/amd-pstate.rst index 1cf40f69278cd2..9eb26014d34b6c 100644 --- a/Documentation/admin-guide/pm/amd-pstate.rst +++ b/Documentation/admin-guide/pm/amd-pstate.rst @@ -361,7 +361,7 @@ Global Attributes ``amd-pstate`` exposes several global attributes (files) in ``sysfs`` to control its functionality at the system level. They are located in the -``/sys/devices/system/cpu/amd-pstate/`` directory and affect all CPUs. +``/sys/devices/system/cpu/amd_pstate/`` directory and affect all CPUs. ``status`` Operation mode of the driver: "active", "passive" or "disable". diff --git a/Documentation/admin-guide/pmf.rst b/Documentation/admin-guide/pmf.rst new file mode 100644 index 00000000000000..9ee729ffc19bc1 --- /dev/null +++ b/Documentation/admin-guide/pmf.rst @@ -0,0 +1,24 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Set udev rules for PMF Smart PC Builder +--------------------------------------- + +AMD PMF(Platform Management Framework) Smart PC Solution builder has to set the system states +like S0i3, Screen lock, hibernate etc, based on the output actions provided by the PMF +TA (Trusted Application). + +In order for this to work the PMF driver generates a uevent for userspace to react to. Below are +sample udev rules that can facilitate this experience when a machine has PMF Smart PC solution builder +enabled. + +Please add the following line(s) to +``/etc/udev/rules.d/99-local.rules``:: + + DRIVERS=="amd-pmf", ACTION=="change", ENV{EVENT_ID}=="0", RUN+="/usr/bin/systemctl suspend" + DRIVERS=="amd-pmf", ACTION=="change", ENV{EVENT_ID}=="1", RUN+="/usr/bin/systemctl hibernate" + DRIVERS=="amd-pmf", ACTION=="change", ENV{EVENT_ID}=="2", RUN+="/bin/loginctl lock-sessions" + +EVENT_ID values: +0= Put the system to S0i3/S2Idle +1= Put the system to hibernate +2= Lock the screen diff --git a/Documentation/admin-guide/sysctl/net.rst b/Documentation/admin-guide/sysctl/net.rst index c7525942f12ce9..3960916519557f 100644 --- a/Documentation/admin-guide/sysctl/net.rst +++ b/Documentation/admin-guide/sysctl/net.rst @@ -345,7 +345,10 @@ optmem_max ---------- Maximum ancillary buffer size allowed per socket. Ancillary data is a sequence -of struct cmsghdr structures with appended data. +of struct cmsghdr structures with appended data. TCP tx zerocopy also uses +optmem_max as a limit for its internal structures. + +Default : 128 KB fb_tunnels_only_for_init_net ---------------------------- diff --git a/Documentation/admin-guide/sysrq.rst b/Documentation/admin-guide/sysrq.rst index 51906e47327b62..2f2e5bd440f9b3 100644 --- a/Documentation/admin-guide/sysrq.rst +++ b/Documentation/admin-guide/sysrq.rst @@ -75,10 +75,19 @@ On other submit a patch to be included in this section. On all - Write a character to /proc/sysrq-trigger. e.g.:: + Write a single character to /proc/sysrq-trigger. + Only the first character is processed, the rest of the string is + ignored. However, it is not recommended to write any extra characters + as the behavior is undefined and might change in the future versions. + E.g.:: echo t > /proc/sysrq-trigger + Alternatively, write multiple characters prepended by underscore. + This way, all characters will be processed. E.g.:: + + echo _reisub > /proc/sysrq-trigger + The :kbd:`` is case sensitive. What are the 'command' keys? diff --git a/Documentation/arch/arc/features.rst b/Documentation/arch/arc/features.rst index b793583d688a46..49ff446ff744cc 100644 --- a/Documentation/arch/arc/features.rst +++ b/Documentation/arch/arc/features.rst @@ -1,3 +1,3 @@ .. SPDX-License-Identifier: GPL-2.0 -.. kernel-feat:: $srctree/Documentation/features arc +.. kernel-feat:: features arc diff --git a/Documentation/arch/arm/features.rst b/Documentation/arch/arm/features.rst index 7414ec03dd157c..0e76aaf68ecab2 100644 --- a/Documentation/arch/arm/features.rst +++ b/Documentation/arch/arm/features.rst @@ -1,3 +1,3 @@ .. SPDX-License-Identifier: GPL-2.0 -.. kernel-feat:: $srctree/Documentation/features arm +.. kernel-feat:: features arm diff --git a/Documentation/arch/arm64/arm-acpi.rst b/Documentation/arch/arm64/arm-acpi.rst index a46c34fa96044c..e59e4505d0d999 100644 --- a/Documentation/arch/arm64/arm-acpi.rst +++ b/Documentation/arch/arm64/arm-acpi.rst @@ -130,7 +130,7 @@ When an Arm system boots, it can either have DT information, ACPI tables, or in some very unusual cases, both. If no command line parameters are used, the kernel will try to use DT for device enumeration; if there is no DT present, the kernel will try to use ACPI tables, but only if they are present. -In neither is available, the kernel will not boot. If acpi=force is used +If neither is available, the kernel will not boot. If acpi=force is used on the command line, the kernel will attempt to use ACPI tables first, but fall back to DT if there are no ACPI tables present. The basic idea is that the kernel will not fail to boot unless it absolutely has no other choice. diff --git a/Documentation/arch/arm64/features.rst b/Documentation/arch/arm64/features.rst index dfa4cb3cd3efa5..03321f4309d0be 100644 --- a/Documentation/arch/arm64/features.rst +++ b/Documentation/arch/arm64/features.rst @@ -1,3 +1,3 @@ .. SPDX-License-Identifier: GPL-2.0 -.. kernel-feat:: $srctree/Documentation/features arm64 +.. kernel-feat:: features arm64 diff --git a/Documentation/arch/arm64/perf.rst b/Documentation/arch/arm64/perf.rst index 1f87b57c233240..997fd716b82f76 100644 --- a/Documentation/arch/arm64/perf.rst +++ b/Documentation/arch/arm64/perf.rst @@ -164,3 +164,75 @@ and should be used to mask the upper bits as needed. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/perf/arch/arm64/tests/user-events.c .. _tools/lib/perf/tests/test-evsel.c: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/lib/perf/tests/test-evsel.c + +Event Counting Threshold +========================================== + +Overview +-------- + +FEAT_PMUv3_TH (Armv8.8) permits a PMU counter to increment only on +events whose count meets a specified threshold condition. For example if +threshold_compare is set to 2 ('Greater than or equal'), and the +threshold is set to 2, then the PMU counter will now only increment by +when an event would have previously incremented the PMU counter by 2 or +more on a single processor cycle. + +To increment by 1 after passing the threshold condition instead of the +number of events on that cycle, add the 'threshold_count' option to the +commandline. + +How-to +------ + +These are the parameters for controlling the feature: + +.. list-table:: + :header-rows: 1 + + * - Parameter + - Description + * - threshold + - Value to threshold the event by. A value of 0 means that + thresholding is disabled and the other parameters have no effect. + * - threshold_compare + - | Comparison function to use, with the following values supported: + | + | 0: Not-equal + | 1: Equals + | 2: Greater-than-or-equal + | 3: Less-than + * - threshold_count + - If this is set, count by 1 after passing the threshold condition + instead of the value of the event on this cycle. + +The threshold, threshold_compare and threshold_count values can be +provided per event, for example: + +.. code-block:: sh + + perf stat -e stall_slot/threshold=2,threshold_compare=2/ \ + -e dtlb_walk/threshold=10,threshold_compare=3,threshold_count/ + +In this example the stall_slot event will count by 2 or more on every +cycle where 2 or more stalls happen. And dtlb_walk will count by 1 on +every cycle where the number of dtlb walks were less than 10. + +The maximum supported threshold value can be read from the caps of each +PMU, for example: + +.. code-block:: sh + + cat /sys/bus/event_source/devices/armv8_pmuv3/caps/threshold_max + + 0x000000ff + +If a value higher than this is given, then opening the event will result +in an error. The highest possible maximum is 4095, as the config field +for threshold is limited to 12 bits, and the Perf tool will refuse to +parse higher values. + +If the PMU doesn't support FEAT_PMUv3_TH, then threshold_max will read +0, and attempting to set a threshold value will also result in an error. +threshold_max will also read as 0 on aarch32 guests, even if the host +is running on hardware with the feature. diff --git a/Documentation/arch/arm64/silicon-errata.rst b/Documentation/arch/arm64/silicon-errata.rst index f47f63bcf67c91..e8c2ce1f9df68d 100644 --- a/Documentation/arch/arm64/silicon-errata.rst +++ b/Documentation/arch/arm64/silicon-errata.rst @@ -71,6 +71,8 @@ stable kernels. +----------------+-----------------+-----------------+-----------------------------+ | ARM | Cortex-A510 | #2658417 | ARM64_ERRATUM_2658417 | +----------------+-----------------+-----------------+-----------------------------+ +| ARM | Cortex-A510 | #3117295 | ARM64_ERRATUM_3117295 | ++----------------+-----------------+-----------------+-----------------------------+ | ARM | Cortex-A520 | #2966298 | ARM64_ERRATUM_2966298 | +----------------+-----------------+-----------------+-----------------------------+ | ARM | Cortex-A53 | #826319 | ARM64_ERRATUM_826319 | @@ -117,6 +119,10 @@ stable kernels. +----------------+-----------------+-----------------+-----------------------------+ | ARM | Cortex-A76 | #1463225 | ARM64_ERRATUM_1463225 | +----------------+-----------------+-----------------+-----------------------------+ +| ARM | Cortex-A76 | #1490853 | N/A | ++----------------+-----------------+-----------------+-----------------------------+ +| ARM | Cortex-A77 | #1491015 | N/A | ++----------------+-----------------+-----------------+-----------------------------+ | ARM | Cortex-A77 | #1508412 | ARM64_ERRATUM_1508412 | +----------------+-----------------+-----------------+-----------------------------+ | ARM | Cortex-A710 | #2119858 | ARM64_ERRATUM_2119858 | @@ -127,6 +133,8 @@ stable kernels. +----------------+-----------------+-----------------+-----------------------------+ | ARM | Cortex-A715 | #2645198 | ARM64_ERRATUM_2645198 | +----------------+-----------------+-----------------+-----------------------------+ +| ARM | Cortex-X1 | #1502854 | N/A | ++----------------+-----------------+-----------------+-----------------------------+ | ARM | Cortex-X2 | #2119858 | ARM64_ERRATUM_2119858 | +----------------+-----------------+-----------------+-----------------------------+ | ARM | Cortex-X2 | #2224489 | ARM64_ERRATUM_2224489 | @@ -135,6 +143,8 @@ stable kernels. +----------------+-----------------+-----------------+-----------------------------+ | ARM | Neoverse-N1 | #1349291 | N/A | +----------------+-----------------+-----------------+-----------------------------+ +| ARM | Neoverse-N1 | #1490853 | N/A | ++----------------+-----------------+-----------------+-----------------------------+ | ARM | Neoverse-N1 | #1542419 | ARM64_ERRATUM_1542419 | +----------------+-----------------+-----------------+-----------------------------+ | ARM | Neoverse-N2 | #2139208 | ARM64_ERRATUM_2139208 | @@ -143,6 +153,8 @@ stable kernels. +----------------+-----------------+-----------------+-----------------------------+ | ARM | Neoverse-N2 | #2253138 | ARM64_ERRATUM_2253138 | +----------------+-----------------+-----------------+-----------------------------+ +| ARM | Neoverse-V1 | #1619801 | N/A | ++----------------+-----------------+-----------------+-----------------------------+ | ARM | MMU-500 | #841119,826419 | N/A | +----------------+-----------------+-----------------+-----------------------------+ | ARM | MMU-600 | #1076982,1209401| N/A | @@ -225,11 +237,9 @@ stable kernels. +----------------+-----------------+-----------------+-----------------------------+ | Rockchip | RK3588 | #3588001 | ROCKCHIP_ERRATUM_3588001 | +----------------+-----------------+-----------------+-----------------------------+ - +----------------+-----------------+-----------------+-----------------------------+ | Fujitsu | A64FX | E#010001 | FUJITSU_ERRATUM_010001 | +----------------+-----------------+-----------------+-----------------------------+ - +----------------+-----------------+-----------------+-----------------------------+ | ASR | ASR8601 | #8601001 | N/A | +----------------+-----------------+-----------------+-----------------------------+ diff --git a/Documentation/arch/loongarch/features.rst b/Documentation/arch/loongarch/features.rst index ebacade3ea454e..009f44c7951f8a 100644 --- a/Documentation/arch/loongarch/features.rst +++ b/Documentation/arch/loongarch/features.rst @@ -1,3 +1,3 @@ .. SPDX-License-Identifier: GPL-2.0 -.. kernel-feat:: $srctree/Documentation/features loongarch +.. kernel-feat:: features loongarch diff --git a/Documentation/arch/m68k/features.rst b/Documentation/arch/m68k/features.rst index 5107a21194724e..de7f0ccf7fc8ed 100644 --- a/Documentation/arch/m68k/features.rst +++ b/Documentation/arch/m68k/features.rst @@ -1,3 +1,3 @@ .. SPDX-License-Identifier: GPL-2.0 -.. kernel-feat:: $srctree/Documentation/features m68k +.. kernel-feat:: features m68k diff --git a/Documentation/arch/mips/features.rst b/Documentation/arch/mips/features.rst index 1973d729b29a98..6e0ffe3e735400 100644 --- a/Documentation/arch/mips/features.rst +++ b/Documentation/arch/mips/features.rst @@ -1,3 +1,3 @@ .. SPDX-License-Identifier: GPL-2.0 -.. kernel-feat:: $srctree/Documentation/features mips +.. kernel-feat:: features mips diff --git a/Documentation/arch/nios2/features.rst b/Documentation/arch/nios2/features.rst index 8449e63f69b2b4..89913810ccb5a0 100644 --- a/Documentation/arch/nios2/features.rst +++ b/Documentation/arch/nios2/features.rst @@ -1,3 +1,3 @@ .. SPDX-License-Identifier: GPL-2.0 -.. kernel-feat:: $srctree/Documentation/features nios2 +.. kernel-feat:: features nios2 diff --git a/Documentation/arch/openrisc/features.rst b/Documentation/arch/openrisc/features.rst index 3f7c40d219f2cc..bae2e25adfd642 100644 --- a/Documentation/arch/openrisc/features.rst +++ b/Documentation/arch/openrisc/features.rst @@ -1,3 +1,3 @@ .. SPDX-License-Identifier: GPL-2.0 -.. kernel-feat:: $srctree/Documentation/features openrisc +.. kernel-feat:: features openrisc diff --git a/Documentation/arch/parisc/features.rst b/Documentation/arch/parisc/features.rst index 501d7c45003790..b3aa4d243b9362 100644 --- a/Documentation/arch/parisc/features.rst +++ b/Documentation/arch/parisc/features.rst @@ -1,3 +1,3 @@ .. SPDX-License-Identifier: GPL-2.0 -.. kernel-feat:: $srctree/Documentation/features parisc +.. kernel-feat:: features parisc diff --git a/Documentation/arch/powerpc/features.rst b/Documentation/arch/powerpc/features.rst index aeae73df86b0c5..ee4b95e04202d3 100644 --- a/Documentation/arch/powerpc/features.rst +++ b/Documentation/arch/powerpc/features.rst @@ -1,3 +1,3 @@ .. SPDX-License-Identifier: GPL-2.0 -.. kernel-feat:: $srctree/Documentation/features powerpc +.. kernel-feat:: features powerpc diff --git a/Documentation/arch/riscv/features.rst b/Documentation/arch/riscv/features.rst index c70ef6ac2368c9..36e90144adabd1 100644 --- a/Documentation/arch/riscv/features.rst +++ b/Documentation/arch/riscv/features.rst @@ -1,3 +1,3 @@ .. SPDX-License-Identifier: GPL-2.0 -.. kernel-feat:: $srctree/Documentation/features riscv +.. kernel-feat:: features riscv diff --git a/Documentation/arch/riscv/hwprobe.rst b/Documentation/arch/riscv/hwprobe.rst index 7b2384de471f8f..b2bcc9eed9aa9d 100644 --- a/Documentation/arch/riscv/hwprobe.rst +++ b/Documentation/arch/riscv/hwprobe.rst @@ -12,7 +12,7 @@ is defined in :: }; long sys_riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, - size_t cpu_count, cpu_set_t *cpus, + size_t cpusetsize, cpu_set_t *cpus, unsigned int flags); The arguments are split into three groups: an array of key-value pairs, a CPU @@ -20,12 +20,26 @@ set, and some flags. The key-value pairs are supplied with a count. Userspace must prepopulate the key field for each element, and the kernel will fill in the value if the key is recognized. If a key is unknown to the kernel, its key field will be cleared to -1, and its value set to 0. The CPU set is defined by -CPU_SET(3). For value-like keys (eg. vendor/arch/impl), the returned value will -be only be valid if all CPUs in the given set have the same value. Otherwise -1 -will be returned. For boolean-like keys, the value returned will be a logical -AND of the values for the specified CPUs. Usermode can supply NULL for cpus and -0 for cpu_count as a shortcut for all online CPUs. There are currently no flags, -this value must be zero for future compatibility. +CPU_SET(3) with size ``cpusetsize`` bytes. For value-like keys (eg. vendor, +arch, impl), the returned value will only be valid if all CPUs in the given set +have the same value. Otherwise -1 will be returned. For boolean-like keys, the +value returned will be a logical AND of the values for the specified CPUs. +Usermode can supply NULL for ``cpus`` and 0 for ``cpusetsize`` as a shortcut for +all online CPUs. The currently supported flags are: + +* :c:macro:`RISCV_HWPROBE_WHICH_CPUS`: This flag basically reverses the behavior + of sys_riscv_hwprobe(). Instead of populating the values of keys for a given + set of CPUs, the values of each key are given and the set of CPUs is reduced + by sys_riscv_hwprobe() to only those which match each of the key-value pairs. + How matching is done depends on the key type. For value-like keys, matching + means to be the exact same as the value. For boolean-like keys, matching + means the result of a logical AND of the pair's value with the CPU's value is + exactly the same as the pair's value. Additionally, when ``cpus`` is an empty + set, then it is initialized to all online CPUs which fit within it, i.e. the + CPU set returned is the reduction of all the online CPUs which can be + represented with a CPU set of size ``cpusetsize``. + +All other flags are reserved for future compatibility and must be zero. On success 0 is returned, on failure a negative error code is returned. @@ -80,6 +94,100 @@ The following keys are defined: * :c:macro:`RISCV_HWPROBE_EXT_ZICBOZ`: The Zicboz extension is supported, as ratified in commit 3dd606f ("Create cmobase-v1.0.pdf") of riscv-CMOs. + * :c:macro:`RISCV_HWPROBE_EXT_ZBC` The Zbc extension is supported, as defined + in version 1.0 of the Bit-Manipulation ISA extensions. + + * :c:macro:`RISCV_HWPROBE_EXT_ZBKB` The Zbkb extension is supported, as + defined in version 1.0 of the Scalar Crypto ISA extensions. + + * :c:macro:`RISCV_HWPROBE_EXT_ZBKC` The Zbkc extension is supported, as + defined in version 1.0 of the Scalar Crypto ISA extensions. + + * :c:macro:`RISCV_HWPROBE_EXT_ZBKX` The Zbkx extension is supported, as + defined in version 1.0 of the Scalar Crypto ISA extensions. + + * :c:macro:`RISCV_HWPROBE_EXT_ZKND` The Zknd extension is supported, as + defined in version 1.0 of the Scalar Crypto ISA extensions. + + * :c:macro:`RISCV_HWPROBE_EXT_ZKNE` The Zkne extension is supported, as + defined in version 1.0 of the Scalar Crypto ISA extensions. + + * :c:macro:`RISCV_HWPROBE_EXT_ZKNH` The Zknh extension is supported, as + defined in version 1.0 of the Scalar Crypto ISA extensions. + + * :c:macro:`RISCV_HWPROBE_EXT_ZKSED` The Zksed extension is supported, as + defined in version 1.0 of the Scalar Crypto ISA extensions. + + * :c:macro:`RISCV_HWPROBE_EXT_ZKSH` The Zksh extension is supported, as + defined in version 1.0 of the Scalar Crypto ISA extensions. + + * :c:macro:`RISCV_HWPROBE_EXT_ZKT` The Zkt extension is supported, as defined + in version 1.0 of the Scalar Crypto ISA extensions. + + * :c:macro:`RISCV_HWPROBE_EXT_ZVBB`: The Zvbb extension is supported as + defined in version 1.0 of the RISC-V Cryptography Extensions Volume II. + + * :c:macro:`RISCV_HWPROBE_EXT_ZVBC`: The Zvbc extension is supported as + defined in version 1.0 of the RISC-V Cryptography Extensions Volume II. + + * :c:macro:`RISCV_HWPROBE_EXT_ZVKB`: The Zvkb extension is supported as + defined in version 1.0 of the RISC-V Cryptography Extensions Volume II. + + * :c:macro:`RISCV_HWPROBE_EXT_ZVKG`: The Zvkg extension is supported as + defined in version 1.0 of the RISC-V Cryptography Extensions Volume II. + + * :c:macro:`RISCV_HWPROBE_EXT_ZVKNED`: The Zvkned extension is supported as + defined in version 1.0 of the RISC-V Cryptography Extensions Volume II. + + * :c:macro:`RISCV_HWPROBE_EXT_ZVKNHA`: The Zvknha extension is supported as + defined in version 1.0 of the RISC-V Cryptography Extensions Volume II. + + * :c:macro:`RISCV_HWPROBE_EXT_ZVKNHB`: The Zvknhb extension is supported as + defined in version 1.0 of the RISC-V Cryptography Extensions Volume II. + + * :c:macro:`RISCV_HWPROBE_EXT_ZVKSED`: The Zvksed extension is supported as + defined in version 1.0 of the RISC-V Cryptography Extensions Volume II. + + * :c:macro:`RISCV_HWPROBE_EXT_ZVKSH`: The Zvksh extension is supported as + defined in version 1.0 of the RISC-V Cryptography Extensions Volume II. + + * :c:macro:`RISCV_HWPROBE_EXT_ZVKT`: The Zvkt extension is supported as + defined in version 1.0 of the RISC-V Cryptography Extensions Volume II. + + * :c:macro:`RISCV_HWPROBE_EXT_ZFH`: The Zfh extension version 1.0 is supported + as defined in the RISC-V ISA manual. + + * :c:macro:`RISCV_HWPROBE_EXT_ZFHMIN`: The Zfhmin extension version 1.0 is + supported as defined in the RISC-V ISA manual. + + * :c:macro:`RISCV_HWPROBE_EXT_ZIHINTNTL`: The Zihintntl extension version 1.0 + is supported as defined in the RISC-V ISA manual. + + * :c:macro:`RISCV_HWPROBE_EXT_ZVFH`: The Zvfh extension is supported as + defined in the RISC-V Vector manual starting from commit e2ccd0548d6c + ("Remove draft warnings from Zvfh[min]"). + + * :c:macro:`RISCV_HWPROBE_EXT_ZVFHMIN`: The Zvfhmin extension is supported as + defined in the RISC-V Vector manual starting from commit e2ccd0548d6c + ("Remove draft warnings from Zvfh[min]"). + + * :c:macro:`RISCV_HWPROBE_EXT_ZFA`: The Zfa extension is supported as + defined in the RISC-V ISA manual starting from commit 056b6ff467c7 + ("Zfa is ratified"). + + * :c:macro:`RISCV_HWPROBE_EXT_ZTSO`: The Ztso extension is supported as + defined in the RISC-V ISA manual starting from commit 5618fb5a216b + ("Ztso is now ratified.") + + * :c:macro:`RISCV_HWPROBE_EXT_ZACAS`: The Zacas extension is supported as + defined in the Atomic Compare-and-Swap (CAS) instructions manual starting + from commit 5059e0ca641c ("update to ratified"). + + * :c:macro:`RISCV_HWPROBE_EXT_ZICOND`: The Zicond extension is supported as + defined in the RISC-V Integer Conditional (Zicond) operations extension + manual starting from commit 95cf1f9 ("Add changes requested by Ved + during signoff") + * :c:macro:`RISCV_HWPROBE_KEY_CPUPERF_0`: A bitmask that contains performance information about the selected set of processors. diff --git a/Documentation/arch/s390/features.rst b/Documentation/arch/s390/features.rst index 57c296a9d8f30d..2883dc95068173 100644 --- a/Documentation/arch/s390/features.rst +++ b/Documentation/arch/s390/features.rst @@ -1,3 +1,3 @@ .. SPDX-License-Identifier: GPL-2.0 -.. kernel-feat:: $srctree/Documentation/features s390 +.. kernel-feat:: features s390 diff --git a/Documentation/arch/sh/features.rst b/Documentation/arch/sh/features.rst index f722af3b6c9934..fae48fe81e9bd0 100644 --- a/Documentation/arch/sh/features.rst +++ b/Documentation/arch/sh/features.rst @@ -1,3 +1,3 @@ .. SPDX-License-Identifier: GPL-2.0 -.. kernel-feat:: $srctree/Documentation/features sh +.. kernel-feat:: features sh diff --git a/Documentation/arch/sparc/features.rst b/Documentation/arch/sparc/features.rst index c0c92468b0fe90..96835b6d598a1a 100644 --- a/Documentation/arch/sparc/features.rst +++ b/Documentation/arch/sparc/features.rst @@ -1,3 +1,3 @@ .. SPDX-License-Identifier: GPL-2.0 -.. kernel-feat:: $srctree/Documentation/features sparc +.. kernel-feat:: features sparc diff --git a/Documentation/arch/x86/boot.rst b/Documentation/arch/x86/boot.rst index 22cc7a040dae05..c513855a54bb99 100644 --- a/Documentation/arch/x86/boot.rst +++ b/Documentation/arch/x86/boot.rst @@ -71,7 +71,7 @@ Protocol 2.13 (Kernel 3.14) Support 32- and 64-bit flags being set in Protocol 2.14 BURNT BY INCORRECT COMMIT ae7e1238e68f2a472a125673ab506d49158c1889 - (x86/boot: Add ACPI RSDP address to setup_header) + ("x86/boot: Add ACPI RSDP address to setup_header") DO NOT USE!!! ASSUME SAME AS 2.13. Protocol 2.15 (Kernel 5.5) Added the kernel_info and kernel_info.setup_type_max. diff --git a/Documentation/arch/x86/cpuinfo.rst b/Documentation/arch/x86/cpuinfo.rst index 08246e8ac83542..8895784d478418 100644 --- a/Documentation/arch/x86/cpuinfo.rst +++ b/Documentation/arch/x86/cpuinfo.rst @@ -7,27 +7,74 @@ x86 Feature Flags Introduction ============ -On x86, flags appearing in /proc/cpuinfo have an X86_FEATURE definition -in arch/x86/include/asm/cpufeatures.h. If the kernel cares about a feature -or KVM want to expose the feature to a KVM guest, it can and should have -an X86_FEATURE_* defined. These flags represent hardware features as -well as software features. - -If users want to know if a feature is available on a given system, they -try to find the flag in /proc/cpuinfo. If a given flag is present, it -means that the kernel supports it and is currently making it available. -If such flag represents a hardware feature, it also means that the -hardware supports it. - -If the expected flag does not appear in /proc/cpuinfo, things are murkier. -Users need to find out the reason why the flag is missing and find the way -how to enable it, which is not always easy. There are several factors that -can explain missing flags: the expected feature failed to enable, the feature -is missing in hardware, platform firmware did not enable it, the feature is -disabled at build or run time, an old kernel is in use, or the kernel does -not support the feature and thus has not enabled it. In general, /proc/cpuinfo -shows features which the kernel supports. For a full list of CPUID flags -which the CPU supports, use tools/arch/x86/kcpuid. +The list of feature flags in /proc/cpuinfo is not complete and +represents an ill-fated attempt from long time ago to put feature flags +in an easy to find place for userspace. + +However, the amount of feature flags is growing by the CPU generation, +leading to unparseable and unwieldy /proc/cpuinfo. + +What is more, those feature flags do not even need to be in that file +because userspace doesn't care about them - glibc et al already use +CPUID to find out what the target machine supports and what not. + +And even if it doesn't show a particular feature flag - although the CPU +still does have support for the respective hardware functionality and +said CPU supports CPUID faulting - userspace can simply probe for the +feature and figure out if it is supported or not, regardless of whether +it is being advertised somewhere. + +Furthermore, those flag strings become an ABI the moment they appear +there and maintaining them forever when nothing even uses them is a lot +of wasted effort. + +So, the current use of /proc/cpuinfo is to show features which the +kernel has *enabled* and *supports*. As in: the CPUID feature flag is +there, there's an additional setup which the kernel has done while +booting and the functionality is ready to use. A perfect example for +that is "user_shstk" where additional code enablement is present in the +kernel to support shadow stack for user programs. + +So, if users want to know if a feature is available on a given system, +they try to find the flag in /proc/cpuinfo. If a given flag is present, +it means that + +* the kernel knows about the feature enough to have an X86_FEATURE bit + +* the kernel supports it and is currently making it available either to + userspace or some other part of the kernel + +* if the flag represents a hardware feature the hardware supports it. + +The absence of a flag in /proc/cpuinfo by itself means almost nothing to +an end user. + +On the one hand, a feature like "vaes" might be fully available to user +applications on a kernel that has not defined X86_FEATURE_VAES and thus +there is no "vaes" in /proc/cpuinfo. + +On the other hand, a new kernel running on non-VAES hardware would also +have no "vaes" in /proc/cpuinfo. There's no way for an application or +user to tell the difference. + +The end result is that the flags field in /proc/cpuinfo is marginally +useful for kernel debugging, but not really for anything else. +Applications should instead use things like the glibc facilities for +querying CPU support. Users should rely on tools like +tools/arch/x86/kcpuid and cpuid(1). + +Regarding implementation, flags appearing in /proc/cpuinfo have an +X86_FEATURE definition in arch/x86/include/asm/cpufeatures.h. These flags +represent hardware features as well as software features. + +If the kernel cares about a feature or KVM want to expose the feature to +a KVM guest, it should only then expose it to the guest when the guest +needs to parse /proc/cpuinfo. Which, as mentioned above, is highly +unlikely. KVM can synthesize the CPUID bit and the KVM guest can simply +query CPUID and figure out what the hypervisor supports and what not. As +already stated, /proc/cpuinfo is not a dumping ground for useless +feature flags. + How are feature flags created? ============================== diff --git a/Documentation/arch/x86/features.rst b/Documentation/arch/x86/features.rst index b663f15053ce85..a33616346a388c 100644 --- a/Documentation/arch/x86/features.rst +++ b/Documentation/arch/x86/features.rst @@ -1,3 +1,3 @@ .. SPDX-License-Identifier: GPL-2.0 -.. kernel-feat:: $srctree/Documentation/features x86 +.. kernel-feat:: features x86 diff --git a/Documentation/arch/x86/pti.rst b/Documentation/arch/x86/pti.rst index 4b858a9bad8d38..e08d35177bc028 100644 --- a/Documentation/arch/x86/pti.rst +++ b/Documentation/arch/x86/pti.rst @@ -81,11 +81,9 @@ this protection comes at a cost: and exit (it can be skipped when the kernel is interrupted, though.) Moves to CR3 are on the order of a hundred cycles, and are required at every entry and exit. - b. A "trampoline" must be used for SYSCALL entry. This - trampoline depends on a smaller set of resources than the - non-PTI SYSCALL entry code, so requires mapping fewer - things into the userspace page tables. The downside is - that stacks must be switched at entry time. + b. Percpu TSS is mapped into the user page tables to allow SYSCALL64 path + to work under PTI. This doesn't have a direct runtime cost but it can + be argued it opens certain timing attack scenarios. c. Global pages are disabled for all kernel structures not mapped into both kernel and userspace page tables. This feature of the MMU allows different processes to share TLB @@ -167,7 +165,7 @@ that are worth noting here. * Failures of the selftests/x86 code. Usually a bug in one of the more obscure corners of entry_64.S * Crashes in early boot, especially around CPU bringup. Bugs - in the trampoline code or mappings cause these. + in the mappings cause these. * Crashes at the first interrupt. Caused by bugs in entry_64.S, like screwing up a page table switch. Also caused by incorrectly mapping the IRQ handler entry code. diff --git a/Documentation/arch/x86/tdx.rst b/Documentation/arch/x86/tdx.rst index dc8d9fd2c3f76c..719043cd8b4699 100644 --- a/Documentation/arch/x86/tdx.rst +++ b/Documentation/arch/x86/tdx.rst @@ -10,6 +10,191 @@ encrypting the guest memory. In TDX, a special module running in a special mode sits between the host and the guest and manages the guest/host separation. +TDX Host Kernel Support +======================= + +TDX introduces a new CPU mode called Secure Arbitration Mode (SEAM) and +a new isolated range pointed by the SEAM Ranger Register (SEAMRR). A +CPU-attested software module called 'the TDX module' runs inside the new +isolated range to provide the functionalities to manage and run protected +VMs. + +TDX also leverages Intel Multi-Key Total Memory Encryption (MKTME) to +provide crypto-protection to the VMs. TDX reserves part of MKTME KeyIDs +as TDX private KeyIDs, which are only accessible within the SEAM mode. +BIOS is responsible for partitioning legacy MKTME KeyIDs and TDX KeyIDs. + +Before the TDX module can be used to create and run protected VMs, it +must be loaded into the isolated range and properly initialized. The TDX +architecture doesn't require the BIOS to load the TDX module, but the +kernel assumes it is loaded by the BIOS. + +TDX boot-time detection +----------------------- + +The kernel detects TDX by detecting TDX private KeyIDs during kernel +boot. Below dmesg shows when TDX is enabled by BIOS:: + + [..] virt/tdx: BIOS enabled: private KeyID range: [16, 64) + +TDX module initialization +--------------------------------------- + +The kernel talks to the TDX module via the new SEAMCALL instruction. The +TDX module implements SEAMCALL leaf functions to allow the kernel to +initialize it. + +If the TDX module isn't loaded, the SEAMCALL instruction fails with a +special error. In this case the kernel fails the module initialization +and reports the module isn't loaded:: + + [..] virt/tdx: module not loaded + +Initializing the TDX module consumes roughly ~1/256th system RAM size to +use it as 'metadata' for the TDX memory. It also takes additional CPU +time to initialize those metadata along with the TDX module itself. Both +are not trivial. The kernel initializes the TDX module at runtime on +demand. + +Besides initializing the TDX module, a per-cpu initialization SEAMCALL +must be done on one cpu before any other SEAMCALLs can be made on that +cpu. + +The kernel provides two functions, tdx_enable() and tdx_cpu_enable() to +allow the user of TDX to enable the TDX module and enable TDX on local +cpu respectively. + +Making SEAMCALL requires VMXON has been done on that CPU. Currently only +KVM implements VMXON. For now both tdx_enable() and tdx_cpu_enable() +don't do VMXON internally (not trivial), but depends on the caller to +guarantee that. + +To enable TDX, the caller of TDX should: 1) temporarily disable CPU +hotplug; 2) do VMXON and tdx_enable_cpu() on all online cpus; 3) call +tdx_enable(). For example:: + + cpus_read_lock(); + on_each_cpu(vmxon_and_tdx_cpu_enable()); + ret = tdx_enable(); + cpus_read_unlock(); + if (ret) + goto no_tdx; + // TDX is ready to use + +And the caller of TDX must guarantee the tdx_cpu_enable() has been +successfully done on any cpu before it wants to run any other SEAMCALL. +A typical usage is do both VMXON and tdx_cpu_enable() in CPU hotplug +online callback, and refuse to online if tdx_cpu_enable() fails. + +User can consult dmesg to see whether the TDX module has been initialized. + +If the TDX module is initialized successfully, dmesg shows something +like below:: + + [..] virt/tdx: 262668 KBs allocated for PAMT + [..] virt/tdx: module initialized + +If the TDX module failed to initialize, dmesg also shows it failed to +initialize:: + + [..] virt/tdx: module initialization failed ... + +TDX Interaction to Other Kernel Components +------------------------------------------ + +TDX Memory Policy +~~~~~~~~~~~~~~~~~ + +TDX reports a list of "Convertible Memory Region" (CMR) to tell the +kernel which memory is TDX compatible. The kernel needs to build a list +of memory regions (out of CMRs) as "TDX-usable" memory and pass those +regions to the TDX module. Once this is done, those "TDX-usable" memory +regions are fixed during module's lifetime. + +To keep things simple, currently the kernel simply guarantees all pages +in the page allocator are TDX memory. Specifically, the kernel uses all +system memory in the core-mm "at the time of TDX module initialization" +as TDX memory, and in the meantime, refuses to online any non-TDX-memory +in the memory hotplug. + +Physical Memory Hotplug +~~~~~~~~~~~~~~~~~~~~~~~ + +Note TDX assumes convertible memory is always physically present during +machine's runtime. A non-buggy BIOS should never support hot-removal of +any convertible memory. This implementation doesn't handle ACPI memory +removal but depends on the BIOS to behave correctly. + +CPU Hotplug +~~~~~~~~~~~ + +TDX module requires the per-cpu initialization SEAMCALL must be done on +one cpu before any other SEAMCALLs can be made on that cpu. The kernel +provides tdx_cpu_enable() to let the user of TDX to do it when the user +wants to use a new cpu for TDX task. + +TDX doesn't support physical (ACPI) CPU hotplug. During machine boot, +TDX verifies all boot-time present logical CPUs are TDX compatible before +enabling TDX. A non-buggy BIOS should never support hot-add/removal of +physical CPU. Currently the kernel doesn't handle physical CPU hotplug, +but depends on the BIOS to behave correctly. + +Note TDX works with CPU logical online/offline, thus the kernel still +allows to offline logical CPU and online it again. + +Kexec() +~~~~~~~ + +TDX host support currently lacks the ability to handle kexec. For +simplicity only one of them can be enabled in the Kconfig. This will be +fixed in the future. + +Erratum +~~~~~~~ + +The first few generations of TDX hardware have an erratum. A partial +write to a TDX private memory cacheline will silently "poison" the +line. Subsequent reads will consume the poison and generate a machine +check. + +A partial write is a memory write where a write transaction of less than +cacheline lands at the memory controller. The CPU does these via +non-temporal write instructions (like MOVNTI), or through UC/WC memory +mappings. Devices can also do partial writes via DMA. + +Theoretically, a kernel bug could do partial write to TDX private memory +and trigger unexpected machine check. What's more, the machine check +code will present these as "Hardware error" when they were, in fact, a +software-triggered issue. But in the end, this issue is hard to trigger. + +If the platform has such erratum, the kernel prints additional message in +machine check handler to tell user the machine check may be caused by +kernel bug on TDX private memory. + +Interaction vs S3 and deeper states +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +TDX cannot survive from S3 and deeper states. The hardware resets and +disables TDX completely when platform goes to S3 and deeper. Both TDX +guests and the TDX module get destroyed permanently. + +The kernel uses S3 for suspend-to-ram, and use S4 and deeper states for +hibernation. Currently, for simplicity, the kernel chooses to make TDX +mutually exclusive with S3 and hibernation. + +The kernel disables TDX during early boot when hibernation support is +available:: + + [..] virt/tdx: initialization failed: Hibernation support is enabled + +Add 'nohibernate' kernel command line to disable hibernation in order to +use TDX. + +ACPI S3 is disabled during kernel early boot if TDX is enabled. The user +needs to turn off TDX in the BIOS in order to use S3. + +TDX Guest Support +================= Since the host cannot directly access guest registers or memory, much normal functionality of a hypervisor must be moved into the guest. This is implemented using a Virtualization Exception (#VE) that is handled by the @@ -20,7 +205,7 @@ TDX includes new hypercall-like mechanisms for communicating from the guest to the hypervisor or the TDX module. New TDX Exceptions -================== +------------------ TDX guests behave differently from bare-metal and traditional VMX guests. In TDX guests, otherwise normal instructions or memory accesses can cause @@ -30,7 +215,7 @@ Instructions marked with an '*' conditionally cause exceptions. The details for these instructions are discussed below. Instruction-based #VE ---------------------- +~~~~~~~~~~~~~~~~~~~~~ - Port I/O (INS, OUTS, IN, OUT) - HLT @@ -41,7 +226,7 @@ Instruction-based #VE - CPUID* Instruction-based #GP ---------------------- +~~~~~~~~~~~~~~~~~~~~~ - All VMX instructions: INVEPT, INVVPID, VMCLEAR, VMFUNC, VMLAUNCH, VMPTRLD, VMPTRST, VMREAD, VMRESUME, VMWRITE, VMXOFF, VMXON @@ -52,7 +237,7 @@ Instruction-based #GP - RDMSR*,WRMSR* RDMSR/WRMSR Behavior --------------------- +~~~~~~~~~~~~~~~~~~~~ MSR access behavior falls into three categories: @@ -73,7 +258,7 @@ trapping and handling in the TDX module. Other than possibly being slow, these MSRs appear to function just as they would on bare metal. CPUID Behavior --------------- +~~~~~~~~~~~~~~ For some CPUID leaves and sub-leaves, the virtualized bit fields of CPUID return values (in guest EAX/EBX/ECX/EDX) are configurable by the @@ -93,7 +278,7 @@ not know how to handle. The guest kernel may ask the hypervisor for the value with a hypercall. #VE on Memory Accesses -====================== +---------------------- There are essentially two classes of TDX memory: private and shared. Private memory receives full TDX protections. Its content is protected @@ -107,7 +292,7 @@ entries. This helps ensure that a guest does not place sensitive information in shared memory, exposing it to the untrusted hypervisor. #VE on Shared Memory --------------------- +~~~~~~~~~~~~~~~~~~~~ Access to shared mappings can cause a #VE. The hypervisor ultimately controls whether a shared memory access causes a #VE, so the guest must be @@ -127,7 +312,7 @@ be careful not to access device MMIO regions unless it is also prepared to handle a #VE. #VE on Private Pages --------------------- +~~~~~~~~~~~~~~~~~~~~ An access to private mappings can also cause a #VE. Since all kernel memory is also private memory, the kernel might theoretically need to @@ -145,7 +330,7 @@ The hypervisor is permitted to unilaterally move accepted pages to a to handle the exception. Linux #VE handler -================= +----------------- Just like page faults or #GP's, #VE exceptions can be either handled or be fatal. Typically, an unhandled userspace #VE results in a SIGSEGV. @@ -167,7 +352,7 @@ While the block is in place, any #VE is elevated to a double fault (#DF) which is not recoverable. MMIO handling -============= +------------- In non-TDX VMs, MMIO is usually implemented by giving a guest access to a mapping which will cause a VMEXIT on access, and then the hypervisor @@ -189,7 +374,7 @@ MMIO access via other means (like structure overlays) may result in an oops. Shared Memory Conversions -========================= +------------------------- All TDX guest memory starts out as private at boot. This memory can not be accessed by the hypervisor. However, some kernel users like device diff --git a/Documentation/arch/xtensa/features.rst b/Documentation/arch/xtensa/features.rst index 6b92c7bfa19daa..28dcce1759be4b 100644 --- a/Documentation/arch/xtensa/features.rst +++ b/Documentation/arch/xtensa/features.rst @@ -1,3 +1,3 @@ .. SPDX-License-Identifier: GPL-2.0 -.. kernel-feat:: $srctree/Documentation/features xtensa +.. kernel-feat:: features xtensa diff --git a/Documentation/block/ioprio.rst b/Documentation/block/ioprio.rst index a25c6d5df87b20..4662e1ff3d81f2 100644 --- a/Documentation/block/ioprio.rst +++ b/Documentation/block/ioprio.rst @@ -6,17 +6,16 @@ Block io priorities Intro ----- -With the introduction of cfq v3 (aka cfq-ts or time sliced cfq), basic io -priorities are supported for reads on files. This enables users to io nice -processes or process groups, similar to what has been possible with cpu -scheduling for ages. This document mainly details the current possibilities -with cfq; other io schedulers do not support io priorities thus far. +The io priority feature enables users to io nice processes or process groups, +similar to what has been possible with cpu scheduling for ages. Support for io +priorities is io scheduler dependent and currently supported by bfq and +mq-deadline. Scheduling classes ------------------ -CFQ implements three generic scheduling classes that determine how io is -served for a process. +Three generic scheduling classes are implemented for io priorities that +determine how io is served for a process. IOPRIO_CLASS_RT: This is the realtime io class. This scheduling class is given higher priority than any other in the system, processes from this class are diff --git a/Documentation/bpf/btf.rst b/Documentation/bpf/btf.rst index e43c2fdafcd785..257a7e1cdf5d0d 100644 --- a/Documentation/bpf/btf.rst +++ b/Documentation/bpf/btf.rst @@ -272,10 +272,8 @@ In this case, if the base type is an int type, it must be a regular int type: * ``BTF_INT_OFFSET()`` must be 0. * ``BTF_INT_BITS()`` must be equal to ``{1,2,4,8,16} * 8``. -The following kernel patch introduced ``kind_flag`` and explained why both -modes exist: - - https://github.com/torvalds/linux/commit/9d5f9f701b1891466fb3dbb1806ad97716f95cc3#diff-fa650a64fdd3968396883d2fe8215ff3 +Commit 9d5f9f701b18 introduced ``kind_flag`` and explains why both modes +exist. 2.2.6 BTF_KIND_ENUM ~~~~~~~~~~~~~~~~~~~ diff --git a/Documentation/bpf/cpumasks.rst b/Documentation/bpf/cpumasks.rst index a22b6ad105fbb5..b5d47a04da5d8d 100644 --- a/Documentation/bpf/cpumasks.rst +++ b/Documentation/bpf/cpumasks.rst @@ -352,7 +352,7 @@ can be used to query the contents of cpumasks. .. kernel-doc:: kernel/bpf/cpumask.c :identifiers: bpf_cpumask_first bpf_cpumask_first_zero bpf_cpumask_first_and - bpf_cpumask_test_cpu + bpf_cpumask_test_cpu bpf_cpumask_weight .. kernel-doc:: kernel/bpf/cpumask.c :identifiers: bpf_cpumask_equal bpf_cpumask_intersects bpf_cpumask_subset diff --git a/Documentation/bpf/fs_kfuncs.rst b/Documentation/bpf/fs_kfuncs.rst new file mode 100644 index 00000000000000..8762c3233a3d18 --- /dev/null +++ b/Documentation/bpf/fs_kfuncs.rst @@ -0,0 +1,21 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. _fs_kfuncs-header-label: + +===================== +BPF filesystem kfuncs +===================== + +BPF LSM programs need to access filesystem data from LSM hooks. The following +BPF kfuncs can be used to get these data. + + * ``bpf_get_file_xattr()`` + + * ``bpf_get_fsverity_digest()`` + +To avoid recursions, these kfuncs follow the following rules: + +1. These kfuncs are only permitted from BPF LSM function. +2. These kfuncs should not call into other LSM hooks, i.e. security_*(). For + example, ``bpf_get_file_xattr()`` does not use ``vfs_getxattr()``, because + the latter calls LSM hook ``security_inode_getxattr``. diff --git a/Documentation/bpf/index.rst b/Documentation/bpf/index.rst index aeaeb35e6d4a70..0bb5cb8157f133 100644 --- a/Documentation/bpf/index.rst +++ b/Documentation/bpf/index.rst @@ -21,6 +21,7 @@ that goes into great technical depth about the BPF Architecture. helpers kfuncs cpumasks + fs_kfuncs programs maps bpf_prog_run diff --git a/Documentation/bpf/kfuncs.rst b/Documentation/bpf/kfuncs.rst index 723408e399abd8..7985c6615f3c2f 100644 --- a/Documentation/bpf/kfuncs.rst +++ b/Documentation/bpf/kfuncs.rst @@ -135,6 +135,30 @@ Either way, the returned buffer is either NULL, or of size buffer_szk. Without t annotation, the verifier will reject the program if a null pointer is passed in with a nonzero size. +2.2.5 __str Annotation +---------------------------- +This annotation is used to indicate that the argument is a constant string. + +An example is given below:: + + __bpf_kfunc bpf_get_file_xattr(..., const char *name__str, ...) + { + ... + } + +In this case, ``bpf_get_file_xattr()`` can be called as:: + + bpf_get_file_xattr(..., "xattr_name", ...); + +Or:: + + const char name[] = "xattr_name"; /* This need to be global */ + int BPF_PROG(...) + { + ... + bpf_get_file_xattr(..., name, ...); + ... + } .. _BPF_kfunc_nodef: diff --git a/Documentation/conf.py b/Documentation/conf.py index d4fdf6a3875a83..5830b01c56429d 100644 --- a/Documentation/conf.py +++ b/Documentation/conf.py @@ -47,7 +47,7 @@ from load_config import loadConfig # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. -needs_sphinx = '1.7' +needs_sphinx = '2.4.4' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom @@ -55,7 +55,7 @@ needs_sphinx = '1.7' extensions = ['kerneldoc', 'rstFlatTable', 'kernel_include', 'kfigure', 'sphinx.ext.ifconfig', 'automarkup', 'maintainers_include', 'sphinx.ext.autosectionlabel', - 'kernel_abi', 'kernel_feat'] + 'kernel_abi', 'kernel_feat', 'translations'] if major >= 3: if (major > 3) or (minor > 0 or patch >= 2): @@ -106,6 +106,7 @@ if major >= 3: "__weak", "noinline", "__fix_address", + "__counted_by", # include/linux/memblock.h: "__init_memblock", @@ -357,6 +358,10 @@ html_sidebars = { '**': ['searchbox.html', 'kernel-toc.html', 'sourcelink.html'] if html_theme == 'alabaster': html_sidebars['**'].insert(0, 'about.html') +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +html_logo = 'images/logo.svg' + # Output file base name for HTML help builder. htmlhelp_basename = 'TheLinuxKerneldoc' diff --git a/Documentation/core-api/dma-api-howto.rst b/Documentation/core-api/dma-api-howto.rst index 72f6cdb6be1c01..e8a55f9d61dbca 100644 --- a/Documentation/core-api/dma-api-howto.rst +++ b/Documentation/core-api/dma-api-howto.rst @@ -8,7 +8,7 @@ Dynamic DMA mapping Guide This is a guide to device driver writers on how to use the DMA API with example pseudo-code. For a concise description of the API, see -DMA-API.txt. +Documentation/core-api/dma-api.rst. CPU and DMA addresses ===================== diff --git a/Documentation/core-api/dma-api.rst b/Documentation/core-api/dma-api.rst index 829f20a193cabb..8e3cce3d0a230b 100644 --- a/Documentation/core-api/dma-api.rst +++ b/Documentation/core-api/dma-api.rst @@ -448,7 +448,7 @@ DMA address entries returned. Synchronise a single contiguous or scatter/gather mapping for the CPU and device. With the sync_sg API, all the parameters must be the same -as those passed into the single mapping API. With the sync_single API, +as those passed into the sg mapping API. With the sync_single API, you can use dma_handle and size parameters that aren't identical to those passed into the single mapping API to do a partial sync. diff --git a/Documentation/core-api/maple_tree.rst b/Documentation/core-api/maple_tree.rst index 96f3d5f076b57c..ccdd1615cf974f 100644 --- a/Documentation/core-api/maple_tree.rst +++ b/Documentation/core-api/maple_tree.rst @@ -81,6 +81,9 @@ section. Sometimes it is necessary to ensure the next call to store to a maple tree does not allocate memory, please see :ref:`maple-tree-advanced-api` for this use case. +You can use mtree_dup() to duplicate an entire maple tree. It is a more +efficient way than inserting all elements one by one into a new tree. + Finally, you can remove all entries from a maple tree by calling mtree_destroy(). If the maple tree entries are pointers, you may wish to free the entries first. @@ -112,6 +115,7 @@ Takes ma_lock internally: * mtree_insert() * mtree_insert_range() * mtree_erase() + * mtree_dup() * mtree_destroy() * mt_set_in_rcu() * mt_clear_in_rcu() diff --git a/Documentation/core-api/mm-api.rst b/Documentation/core-api/mm-api.rst index 2d091c873d1edc..af8151db88b28c 100644 --- a/Documentation/core-api/mm-api.rst +++ b/Documentation/core-api/mm-api.rst @@ -37,7 +37,7 @@ The Slab Cache .. kernel-doc:: include/linux/slab.h :internal: -.. kernel-doc:: mm/slab.c +.. kernel-doc:: mm/slub.c :export: .. kernel-doc:: mm/slab_common.c diff --git a/Documentation/core-api/pin_user_pages.rst b/Documentation/core-api/pin_user_pages.rst index d3c1f6d8c0e0ec..6b5f7e6e7155fb 100644 --- a/Documentation/core-api/pin_user_pages.rst +++ b/Documentation/core-api/pin_user_pages.rst @@ -153,6 +153,8 @@ NOTE: Some pages, such as DAX pages, cannot be pinned with longterm pins. That's because DAX pages do not have a separate page cache, and so "pinning" implies locking down file system blocks, which is not (yet) supported in that way. +.. _mmu-notifier-registration-case: + CASE 3: MMU notifier registration, with or without page faulting hardware ------------------------------------------------------------------------- Device drivers can pin pages via get_user_pages*(), and register for mmu diff --git a/Documentation/core-api/workqueue.rst b/Documentation/core-api/workqueue.rst index 0046af06531a6e..3599cf9267b476 100644 --- a/Documentation/core-api/workqueue.rst +++ b/Documentation/core-api/workqueue.rst @@ -379,7 +379,7 @@ Workqueue currently supports the following affinity scopes. cases. This is the default affinity scope. ``numa`` - CPUs are grouped according to NUMA bounaries. + CPUs are grouped according to NUMA boundaries. ``system`` All CPUs are put in the same group. Workqueue makes no effort to process a @@ -446,7 +446,7 @@ The command used: :: There are 24 issuers, each issuing 64 IOs concurrently. ``--verify=sha512`` makes ``fio`` generate and read back the content each time which makes -execution locality matter between the issuer and ``kcryptd``. The followings +execution locality matter between the issuer and ``kcryptd``. The following are the read bandwidths and CPU utilizations depending on different affinity scope settings on ``kcryptd`` measured over five runs. Bandwidths are in MiBps, and CPU util in percents. diff --git a/Documentation/crypto/api.rst b/Documentation/crypto/api.rst index b91b31736df8b7..ff31c30561d4f6 100644 --- a/Documentation/crypto/api.rst +++ b/Documentation/crypto/api.rst @@ -1,11 +1,8 @@ Programming Interface ===================== -.. class:: toc-title - - Table of contents - .. toctree:: + :caption: Table of contents :maxdepth: 2 api-skcipher diff --git a/Documentation/crypto/device_drivers/index.rst b/Documentation/crypto/device_drivers/index.rst new file mode 100644 index 00000000000000..c81d311ac61b89 --- /dev/null +++ b/Documentation/crypto/device_drivers/index.rst @@ -0,0 +1,9 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Hardware Device Driver Specific Documentation +--------------------------------------------- + +.. toctree:: + :maxdepth: 1 + + octeontx2 diff --git a/Documentation/crypto/device_drivers/octeontx2.rst b/Documentation/crypto/device_drivers/octeontx2.rst new file mode 100644 index 00000000000000..7e469b173ac87c --- /dev/null +++ b/Documentation/crypto/device_drivers/octeontx2.rst @@ -0,0 +1,25 @@ +.. SPDX-License-Identifier: GPL-2.0 + +========================= +octeontx2 devlink support +========================= + +This document describes the devlink features implemented by the ``octeontx2 CPT`` +device drivers. + +Parameters +========== + +The ``octeontx2`` driver implements the following driver-specific parameters. + +.. list-table:: Driver-specific parameters implemented + :widths: 5 5 5 85 + + * - Name + - Type + - Mode + - Description + * - ``t106_mode`` + - u8 + - runtime + - Used to configure CN10KA B0/CN10KB CPT to work as CN10KA A0/A1. diff --git a/Documentation/crypto/index.rst b/Documentation/crypto/index.rst index da5d5ad2bdf332..92eec78b571322 100644 --- a/Documentation/crypto/index.rst +++ b/Documentation/crypto/index.rst @@ -9,11 +9,8 @@ This documentation outlines the Linux kernel crypto API with its concepts, details about developing cipher implementations, employment of the API for cryptographic use cases, as well as programming examples. -.. class:: toc-title - - Table of contents - .. toctree:: + :caption: Table of contents :maxdepth: 2 intro @@ -28,3 +25,4 @@ for cryptographic use cases, as well as programming examples. api api-samples descore-readme + device_drivers/index diff --git a/Documentation/dev-tools/checkuapi.rst b/Documentation/dev-tools/checkuapi.rst new file mode 100644 index 00000000000000..9072f21b50b0c0 --- /dev/null +++ b/Documentation/dev-tools/checkuapi.rst @@ -0,0 +1,477 @@ +.. SPDX-License-Identifier: GPL-2.0-only + +============ +UAPI Checker +============ + +The UAPI checker (``scripts/check-uapi.sh``) is a shell script which +checks UAPI header files for userspace backwards-compatibility across +the git tree. + +Options +======= + +This section will describe the options with which ``check-uapi.sh`` +can be run. + +Usage:: + + check-uapi.sh [-b BASE_REF] [-p PAST_REF] [-j N] [-l ERROR_LOG] [-i] [-q] [-v] + +Available options:: + + -b BASE_REF Base git reference to use for comparison. If unspecified or empty, + will use any dirty changes in tree to UAPI files. If there are no + dirty changes, HEAD will be used. + -p PAST_REF Compare BASE_REF to PAST_REF (e.g. -p v6.1). If unspecified or empty, + will use BASE_REF^1. Must be an ancestor of BASE_REF. Only headers + that exist on PAST_REF will be checked for compatibility. + -j JOBS Number of checks to run in parallel (default: number of CPU cores). + -l ERROR_LOG Write error log to file (default: no error log is generated). + -i Ignore ambiguous changes that may or may not break UAPI compatibility. + -q Quiet operation. + -v Verbose operation (print more information about each header being checked). + +Environmental args:: + + ABIDIFF Custom path to abidiff binary + CC C compiler (default is "gcc") + ARCH Target architecture of C compiler (default is host arch) + +Exit codes:: + + 0) Success + 1) ABI difference detected + 2) Prerequisite not met + +Examples +======== + +Basic Usage +----------- + +First, let's try making a change to a UAPI header file that obviously +won't break userspace:: + + cat << 'EOF' | patch -l -p1 + --- a/include/uapi/linux/acct.h + +++ b/include/uapi/linux/acct.h + @@ -21,7 +21,9 @@ + #include + #include + + -/* + +#define FOO + + + +/* + * comp_t is a 16-bit "floating" point number with a 3-bit base 8 + * exponent and a 13-bit fraction. + * comp2_t is 24-bit with 5-bit base 2 exponent and 20 bit fraction + diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h + EOF + +Now, let's use the script to validate:: + + % ./scripts/check-uapi.sh + Installing user-facing UAPI headers from dirty tree... OK + Installing user-facing UAPI headers from HEAD... OK + Checking changes to UAPI headers between HEAD and dirty tree... + All 912 UAPI headers compatible with x86 appear to be backwards compatible + +Let's add another change that *might* break userspace:: + + cat << 'EOF' | patch -l -p1 + --- a/include/uapi/linux/bpf.h + +++ b/include/uapi/linux/bpf.h + @@ -74,7 +74,7 @@ struct bpf_insn { + __u8 dst_reg:4; /* dest register */ + __u8 src_reg:4; /* source register */ + __s16 off; /* signed offset */ + - __s32 imm; /* signed immediate constant */ + + __u32 imm; /* unsigned immediate constant */ + }; + + /* Key of an a BPF_MAP_TYPE_LPM_TRIE entry */ + EOF + +The script will catch this:: + + % ./scripts/check-uapi.sh + Installing user-facing UAPI headers from dirty tree... OK + Installing user-facing UAPI headers from HEAD... OK + Checking changes to UAPI headers between HEAD and dirty tree... + ==== ABI differences detected in include/linux/bpf.h from HEAD -> dirty tree ==== + [C] 'struct bpf_insn' changed: + type size hasn't changed + 1 data member change: + type of '__s32 imm' changed: + typedef name changed from __s32 to __u32 at int-ll64.h:27:1 + underlying type 'int' changed: + type name changed from 'int' to 'unsigned int' + type size hasn't changed + ================================================================================== + + error - 1/912 UAPI headers compatible with x86 appear _not_ to be backwards compatible + +In this case, the script is reporting the type change because it could +break a userspace program that passes in a negative number. Now, let's +say you know that no userspace program could possibly be using a negative +value in ``imm``, so changing to an unsigned type there shouldn't hurt +anything. You can pass the ``-i`` flag to the script to ignore changes +in which the userspace backwards compatibility is ambiguous:: + + % ./scripts/check-uapi.sh -i + Installing user-facing UAPI headers from dirty tree... OK + Installing user-facing UAPI headers from HEAD... OK + Checking changes to UAPI headers between HEAD and dirty tree... + All 912 UAPI headers compatible with x86 appear to be backwards compatible + +Now, let's make a similar change that *will* break userspace:: + + cat << 'EOF' | patch -l -p1 + --- a/include/uapi/linux/bpf.h + +++ b/include/uapi/linux/bpf.h + @@ -71,8 +71,8 @@ enum { + + struct bpf_insn { + __u8 code; /* opcode */ + - __u8 dst_reg:4; /* dest register */ + __u8 src_reg:4; /* source register */ + + __u8 dst_reg:4; /* dest register */ + __s16 off; /* signed offset */ + __s32 imm; /* signed immediate constant */ + }; + EOF + +Since we're re-ordering an existing struct member, there's no ambiguity, +and the script will report the breakage even if you pass ``-i``:: + + % ./scripts/check-uapi.sh -i + Installing user-facing UAPI headers from dirty tree... OK + Installing user-facing UAPI headers from HEAD... OK + Checking changes to UAPI headers between HEAD and dirty tree... + ==== ABI differences detected in include/linux/bpf.h from HEAD -> dirty tree ==== + [C] 'struct bpf_insn' changed: + type size hasn't changed + 2 data member changes: + '__u8 dst_reg' offset changed from 8 to 12 (in bits) (by +4 bits) + '__u8 src_reg' offset changed from 12 to 8 (in bits) (by -4 bits) + ================================================================================== + + error - 1/912 UAPI headers compatible with x86 appear _not_ to be backwards compatible + +Let's commit the breaking change, then commit the innocuous change:: + + % git commit -m 'Breaking UAPI change' include/uapi/linux/bpf.h + [detached HEAD f758e574663a] Breaking UAPI change + 1 file changed, 1 insertion(+), 1 deletion(-) + % git commit -m 'Innocuous UAPI change' include/uapi/linux/acct.h + [detached HEAD 2e87df769081] Innocuous UAPI change + 1 file changed, 3 insertions(+), 1 deletion(-) + +Now, let's run the script again with no arguments:: + + % ./scripts/check-uapi.sh + Installing user-facing UAPI headers from HEAD... OK + Installing user-facing UAPI headers from HEAD^1... OK + Checking changes to UAPI headers between HEAD^1 and HEAD... + All 912 UAPI headers compatible with x86 appear to be backwards compatible + +It doesn't catch any breaking change because, by default, it only +compares ``HEAD`` to ``HEAD^1``. The breaking change was committed on +``HEAD~2``. If we wanted the search scope to go back further, we'd have to +use the ``-p`` option to pass a different past reference. In this case, +let's pass ``-p HEAD~2`` to the script so it checks UAPI changes between +``HEAD~2`` and ``HEAD``:: + + % ./scripts/check-uapi.sh -p HEAD~2 + Installing user-facing UAPI headers from HEAD... OK + Installing user-facing UAPI headers from HEAD~2... OK + Checking changes to UAPI headers between HEAD~2 and HEAD... + ==== ABI differences detected in include/linux/bpf.h from HEAD~2 -> HEAD ==== + [C] 'struct bpf_insn' changed: + type size hasn't changed + 2 data member changes: + '__u8 dst_reg' offset changed from 8 to 12 (in bits) (by +4 bits) + '__u8 src_reg' offset changed from 12 to 8 (in bits) (by -4 bits) + ============================================================================== + + error - 1/912 UAPI headers compatible with x86 appear _not_ to be backwards compatible + +Alternatively, we could have also run with ``-b HEAD~``. This would set the +base reference to ``HEAD~`` so then the script would compare it to ``HEAD~^1``. + +Architecture-specific Headers +----------------------------- + +Consider this change:: + + cat << 'EOF' | patch -l -p1 + --- a/arch/arm64/include/uapi/asm/sigcontext.h + +++ b/arch/arm64/include/uapi/asm/sigcontext.h + @@ -70,6 +70,7 @@ struct sigcontext { + struct _aarch64_ctx { + __u32 magic; + __u32 size; + + __u32 new_var; + }; + + #define FPSIMD_MAGIC 0x46508001 + EOF + +This is a change to an arm64-specific UAPI header file. In this example, I'm +running the script from an x86 machine with an x86 compiler, so, by default, +the script only checks x86-compatible UAPI header files:: + + % ./scripts/check-uapi.sh + Installing user-facing UAPI headers from dirty tree... OK + Installing user-facing UAPI headers from HEAD... OK + No changes to UAPI headers were applied between HEAD and dirty tree + +With an x86 compiler, we can't check header files in ``arch/arm64``, so the +script doesn't even try. + +If we want to check the header file, we'll have to use an arm64 compiler and +set ``ARCH`` accordingly:: + + % CC=aarch64-linux-gnu-gcc ARCH=arm64 ./scripts/check-uapi.sh + Installing user-facing UAPI headers from dirty tree... OK + Installing user-facing UAPI headers from HEAD... OK + Checking changes to UAPI headers between HEAD and dirty tree... + ==== ABI differences detected in include/asm/sigcontext.h from HEAD -> dirty tree ==== + [C] 'struct _aarch64_ctx' changed: + type size changed from 64 to 96 (in bits) + 1 data member insertion: + '__u32 new_var', at offset 64 (in bits) at sigcontext.h:73:1 + -- snip -- + [C] 'struct zt_context' changed: + type size changed from 128 to 160 (in bits) + 2 data member changes (1 filtered): + '__u16 nregs' offset changed from 64 to 96 (in bits) (by +32 bits) + '__u16 __reserved[3]' offset changed from 80 to 112 (in bits) (by +32 bits) + ======================================================================================= + + error - 1/884 UAPI headers compatible with arm64 appear _not_ to be backwards compatible + +We can see with ``ARCH`` and ``CC`` set properly for the file, the ABI +change is reported properly. Also notice that the total number of UAPI +header files checked by the script changes. This is because the number +of headers installed for arm64 platforms is different than x86. + +Cross-Dependency Breakages +-------------------------- + +Consider this change:: + + cat << 'EOF' | patch -l -p1 + --- a/include/uapi/linux/types.h + +++ b/include/uapi/linux/types.h + @@ -52,7 +52,7 @@ typedef __u32 __bitwise __wsum; + #define __aligned_be64 __be64 __attribute__((aligned(8))) + #define __aligned_le64 __le64 __attribute__((aligned(8))) + + -typedef unsigned __bitwise __poll_t; + +typedef unsigned short __bitwise __poll_t; + + #endif /* __ASSEMBLY__ */ + #endif /* _UAPI_LINUX_TYPES_H */ + EOF + +Here, we're changing a ``typedef`` in ``types.h``. This doesn't break +a UAPI in ``types.h``, but other UAPIs in the tree may break due to +this change:: + + % ./scripts/check-uapi.sh + Installing user-facing UAPI headers from dirty tree... OK + Installing user-facing UAPI headers from HEAD... OK + Checking changes to UAPI headers between HEAD and dirty tree... + ==== ABI differences detected in include/linux/eventpoll.h from HEAD -> dirty tree ==== + [C] 'struct epoll_event' changed: + type size changed from 96 to 80 (in bits) + 2 data member changes: + type of '__poll_t events' changed: + underlying type 'unsigned int' changed: + type name changed from 'unsigned int' to 'unsigned short int' + type size changed from 32 to 16 (in bits) + '__u64 data' offset changed from 32 to 16 (in bits) (by -16 bits) + ======================================================================================== + include/linux/eventpoll.h did not change between HEAD and dirty tree... + It's possible a change to one of the headers it includes caused this error: + #include + #include + +Note that the script noticed the failing header file did not change, +so it assumes one of its includes must have caused the breakage. Indeed, +we can see ``linux/types.h`` is used from ``eventpoll.h``. + +UAPI Header Removals +-------------------- + +Consider this change:: + + cat << 'EOF' | patch -l -p1 + diff --git a/include/uapi/asm-generic/Kbuild b/include/uapi/asm-generic/Kbuild + index ebb180aac74e..a9c88b0a8b3b 100644 + --- a/include/uapi/asm-generic/Kbuild + +++ b/include/uapi/asm-generic/Kbuild + @@ -31,6 +31,6 @@ mandatory-y += stat.h + mandatory-y += statfs.h + mandatory-y += swab.h + mandatory-y += termbits.h + -mandatory-y += termios.h + +#mandatory-y += termios.h + mandatory-y += types.h + mandatory-y += unistd.h + EOF + +This script removes a UAPI header file from the install list. Let's run +the script:: + + % ./scripts/check-uapi.sh + Installing user-facing UAPI headers from dirty tree... OK + Installing user-facing UAPI headers from HEAD... OK + Checking changes to UAPI headers between HEAD and dirty tree... + ==== UAPI header include/asm/termios.h was removed between HEAD and dirty tree ==== + + error - 1/912 UAPI headers compatible with x86 appear _not_ to be backwards compatible + +Removing a UAPI header is considered a breaking change, and the script +will flag it as such. + +Checking Historic UAPI Compatibility +------------------------------------ + +You can use the ``-b`` and ``-p`` options to examine different chunks of your +git tree. For example, to check all changed UAPI header files between tags +v6.0 and v6.1, you'd run:: + + % ./scripts/check-uapi.sh -b v6.1 -p v6.0 + Installing user-facing UAPI headers from v6.1... OK + Installing user-facing UAPI headers from v6.0... OK + Checking changes to UAPI headers between v6.0 and v6.1... + + --- snip --- + error - 37/907 UAPI headers compatible with x86 appear _not_ to be backwards compatible + +Note: Before v5.3, a header file needed by the script is not present, +so the script is unable to check changes before then. + +You'll notice that the script detected many UAPI changes that are not +backwards compatible. Knowing that kernel UAPIs are supposed to be stable +forever, this is an alarming result. This brings us to the next section: +caveats. + +Caveats +======= + +The UAPI checker makes no assumptions about the author's intention, so some +types of changes may be flagged even though they intentionally break UAPI. + +Removals For Refactoring or Deprecation +--------------------------------------- + +Sometimes drivers for very old hardware are removed, such as in this example:: + + % ./scripts/check-uapi.sh -b ba47652ba655 + Installing user-facing UAPI headers from ba47652ba655... OK + Installing user-facing UAPI headers from ba47652ba655^1... OK + Checking changes to UAPI headers between ba47652ba655^1 and ba47652ba655... + ==== UAPI header include/linux/meye.h was removed between ba47652ba655^1 and ba47652ba655 ==== + + error - 1/910 UAPI headers compatible with x86 appear _not_ to be backwards compatible + +The script will always flag removals (even if they're intentional). + +Struct Expansions +----------------- + +Depending on how a structure is handled in kernelspace, a change which +expands a struct could be non-breaking. + +If a struct is used as the argument to an ioctl, then the kernel driver +must be able to handle ioctl commands of any size. Beyond that, you need +to be careful when copying data from the user. Say, for example, that +``struct foo`` is changed like this:: + + struct foo { + __u64 a; /* added in version 1 */ + + __u32 b; /* added in version 2 */ + + __u32 c; /* added in version 2 */ + } + +By default, the script will flag this kind of change for further review:: + + [C] 'struct foo' changed: + type size changed from 64 to 128 (in bits) + 2 data member insertions: + '__u32 b', at offset 64 (in bits) + '__u32 c', at offset 96 (in bits) + +However, it is possible that this change was made safely. + +If a userspace program was built with version 1, it will think +``sizeof(struct foo)`` is 8. That size will be encoded in the +ioctl value that gets sent to the kernel. If the kernel is built +with version 2, it will think the ``sizeof(struct foo)`` is 16. + +The kernel can use the ``_IOC_SIZE`` macro to get the size encoded +in the ioctl code that the user passed in and then use +``copy_struct_from_user()`` to safely copy the value:: + + int handle_ioctl(unsigned long cmd, unsigned long arg) + { + switch _IOC_NR(cmd) { + 0x01: { + struct foo my_cmd; /* size 16 in the kernel */ + + ret = copy_struct_from_user(&my_cmd, arg, sizeof(struct foo), _IOC_SIZE(cmd)); + ... + +``copy_struct_from_user`` will zero the struct in the kernel and then copy +only the bytes passed in from the user (leaving new members zeroized). +If the user passed in a larger struct, the extra members are ignored. + +If you know this situation is accounted for in the kernel code, you can +pass ``-i`` to the script, and struct expansions like this will be ignored. + +Flex Array Migration +-------------------- + +While the script handles expansion into an existing flex array, it does +still flag initial migration to flex arrays from 1-element fake flex +arrays. For example:: + + struct foo { + __u32 x; + - __u32 flex[1]; /* fake flex */ + + __u32 flex[]; /* real flex */ + }; + +This change would be flagged by the script:: + + [C] 'struct foo' changed: + type size changed from 64 to 32 (in bits) + 1 data member change: + type of '__u32 flex[1]' changed: + type name changed from '__u32[1]' to '__u32[]' + array type size changed from 32 to 'unknown' + array type subrange 1 changed length from 1 to 'unknown' + +At this time, there's no way to filter these types of changes, so be +aware of this possible false positive. + +Summary +------- + +While many types of false positives are filtered out by the script, +it's possible there are some cases where the script flags a change +which does not break UAPI. It's also possible a change which *does* +break userspace would not be flagged by this script. While the script +has been run on much of the kernel history, there could still be corner +cases that are not accounted for. + +The intention is for this script to be used as a quick check for +maintainers or automated tooling, not as the end-all authority on +patch compatibility. It's best to remember: use your best judgment +(and ideally a unit test in userspace) to make sure your UAPI changes +are backwards-compatible! diff --git a/Documentation/dev-tools/index.rst b/Documentation/dev-tools/index.rst index 6b0663075dc04e..efa49cdc8e2eb3 100644 --- a/Documentation/dev-tools/index.rst +++ b/Documentation/dev-tools/index.rst @@ -10,11 +10,8 @@ whole; patches welcome! A brief overview of testing-specific tools can be found in Documentation/dev-tools/testing-overview.rst -.. class:: toc-title - - Table of contents - .. toctree:: + :caption: Table of contents :maxdepth: 2 testing-overview @@ -34,6 +31,7 @@ Documentation/dev-tools/testing-overview.rst kselftest kunit/index ktap + checkuapi .. only:: subproject and html diff --git a/Documentation/dev-tools/kunit/api/resource.rst b/Documentation/dev-tools/kunit/api/resource.rst index 0a94f831259e85..ec6002a6b0dbc2 100644 --- a/Documentation/dev-tools/kunit/api/resource.rst +++ b/Documentation/dev-tools/kunit/api/resource.rst @@ -11,3 +11,12 @@ state on a per-test basis, register custom cleanup actions, and more. .. kernel-doc:: include/kunit/resource.h :internal: + +Managed Devices +--------------- + +Functions for using KUnit-managed struct device and struct device_driver. +Include ``kunit/device.h`` to use these. + +.. kernel-doc:: include/kunit/device.h + :internal: diff --git a/Documentation/dev-tools/kunit/run_manual.rst b/Documentation/dev-tools/kunit/run_manual.rst index e7b46421f247e1..699d9288507508 100644 --- a/Documentation/dev-tools/kunit/run_manual.rst +++ b/Documentation/dev-tools/kunit/run_manual.rst @@ -49,9 +49,52 @@ loaded. The results will appear in TAP format in ``dmesg``. +debugfs +======= + +KUnit can be accessed from userspace via the debugfs filesystem (See more +information about debugfs at Documentation/filesystems/debugfs.rst). + +If ``CONFIG_KUNIT_DEBUGFS`` is enabled, the KUnit debugfs filesystem is +mounted at /sys/kernel/debug/kunit. You can use this filesystem to perform +the following actions. + +Retrieve Test Results +===================== + +You can use debugfs to retrieve KUnit test results. The test results are +accessible from the debugfs filesystem in the following read-only file: + +.. code-block :: bash + + /sys/kernel/debug/kunit//results + +The test results are printed in a KTAP document. Note this document is separate +to the kernel log and thus, may have different test suite numbering. + +Run Tests After Kernel Has Booted +================================= + +You can use the debugfs filesystem to trigger built-in tests to run after +boot. To run the test suite, you can use the following command to write to +the ``/sys/kernel/debug/kunit//run`` file: + +.. code-block :: bash + + echo "any string" > /sys/kernel/debugfs/kunit//run + +As a result, the test suite runs and the results are printed to the kernel +log. + +However, this feature is not available with KUnit suites that use init data, +because init data may have been discarded after the kernel boots. KUnit +suites that use init data should be defined using the +kunit_test_init_section_suites() macro. + +Also, you cannot use this feature to run tests concurrently. Instead a test +will wait to run until other tests have completed or failed. + .. note :: - If ``CONFIG_KUNIT_DEBUGFS`` is enabled, KUnit test results will - be accessible from the ``debugfs`` filesystem (if mounted). - They will be in ``/sys/kernel/debug/kunit//results``, in - TAP format. + For test authors, to use this feature, tests will need to correctly initialise + and/or clean up any data, so the test runs correctly a second time. diff --git a/Documentation/dev-tools/kunit/running_tips.rst b/Documentation/dev-tools/kunit/running_tips.rst index 766f9cdea0fad3..bd689db6fdd201 100644 --- a/Documentation/dev-tools/kunit/running_tips.rst +++ b/Documentation/dev-tools/kunit/running_tips.rst @@ -139,6 +139,17 @@ If your installed version of gcc doesn't work, you can tweak the steps: $ ./tools/testing/kunit/kunit.py run --make_options=CC=/usr/bin/gcc-6 $ lcov -t "my_kunit_tests" -o coverage.info -c -d .kunit/ --gcov-tool=/usr/bin/gcov-6 +Alternatively, LLVM-based toolchains can also be used: + +.. code-block:: bash + + # Build with LLVM and append coverage options to the current config + $ ./tools/testing/kunit/kunit.py run --make_options LLVM=1 --kunitconfig=.kunit/ --kunitconfig=tools/testing/kunit/configs/coverage_uml.config + $ llvm-profdata merge -sparse default.profraw -o default.profdata + $ llvm-cov export --format=lcov .kunit/vmlinux -instr-profile default.profdata > coverage.info + # The coverage.info file is in lcov-compatible format and it can be used to e.g. generate HTML report + $ genhtml -o /tmp/coverage_html coverage.info + Running tests manually ====================== @@ -428,3 +439,10 @@ This attribute indicates the name of the module associated with the test. This attribute is automatically saved as a string and is printed for each suite. Tests can also be filtered using this attribute. + +``is_init`` + +This attribute indicates whether the test uses init data or functions. + +This attribute is automatically saved as a boolean and tests can also be +filtered using this attribute. diff --git a/Documentation/dev-tools/kunit/usage.rst b/Documentation/dev-tools/kunit/usage.rst index c27e1646ecd9ca..a9efab50eed83e 100644 --- a/Documentation/dev-tools/kunit/usage.rst +++ b/Documentation/dev-tools/kunit/usage.rst @@ -566,13 +566,9 @@ By reusing the same ``cases`` array from above, we can write the test as a }, }; - // Need a helper function to generate a name for each test case. - static void case_to_desc(const struct sha1_test_case *t, char *desc) - { - strcpy(desc, t->str); - } - // Creates `sha1_gen_params()` to iterate over `cases`. - KUNIT_ARRAY_PARAM(sha1, cases, case_to_desc); + // Creates `sha1_gen_params()` to iterate over `cases` while using + // the struct member `str` for the case description. + KUNIT_ARRAY_PARAM_DESC(sha1, cases, str); // Looks no different from a normal test. static void sha1_test(struct kunit *test) @@ -588,7 +584,7 @@ By reusing the same ``cases`` array from above, we can write the test as a } // Instead of KUNIT_CASE, we use KUNIT_CASE_PARAM and pass in the - // function declared by KUNIT_ARRAY_PARAM. + // function declared by KUNIT_ARRAY_PARAM or KUNIT_ARRAY_PARAM_DESC. static struct kunit_case sha1_test_cases[] = { KUNIT_CASE_PARAM(sha1_test, sha1_gen_params), {} @@ -651,12 +647,16 @@ For example: } Note that, for functions like device_unregister which only accept a single -pointer-sized argument, it's possible to directly cast that function to -a ``kunit_action_t`` rather than writing a wrapper function, for example: +pointer-sized argument, it's possible to automatically generate a wrapper +with the ``KUNIT_DEFINE_ACTION_WRAPPER()`` macro, for example: .. code-block:: C - kunit_add_action(test, (kunit_action_t *)&device_unregister, &dev); + KUNIT_DEFINE_ACTION_WRAPPER(device_unregister, device_unregister_wrapper, struct device *); + kunit_add_action(test, &device_unregister_wrapper, &dev); + +You should do this in preference to manually casting to the ``kunit_action_t`` type, +as casting function pointers will break Control Flow Integrity (CFI). ``kunit_add_action`` can fail if, for example, the system is out of memory. You can use ``kunit_add_action_or_reset`` instead which runs the action @@ -793,3 +793,53 @@ structures as shown below: KUnit is not enabled, or if no test is running in the current task, it will do nothing. This compiles down to either a no-op or a static key check, so will have a negligible performance impact when no test is running. + +Managing Fake Devices and Drivers +--------------------------------- + +When testing drivers or code which interacts with drivers, many functions will +require a ``struct device`` or ``struct device_driver``. In many cases, setting +up a real device is not required to test any given function, so a fake device +can be used instead. + +KUnit provides helper functions to create and manage these fake devices, which +are internally of type ``struct kunit_device``, and are attached to a special +``kunit_bus``. These devices support managed device resources (devres), as +described in Documentation/driver-api/driver-model/devres.rst + +To create a KUnit-managed ``struct device_driver``, use ``kunit_driver_create()``, +which will create a driver with the given name, on the ``kunit_bus``. This driver +will automatically be destroyed when the corresponding test finishes, but can also +be manually destroyed with ``driver_unregister()``. + +To create a fake device, use the ``kunit_device_register()``, which will create +and register a device, using a new KUnit-managed driver created with ``kunit_driver_create()``. +To provide a specific, non-KUnit-managed driver, use ``kunit_device_register_with_driver()`` +instead. Like with managed drivers, KUnit-managed fake devices are automatically +cleaned up when the test finishes, but can be manually cleaned up early with +``kunit_device_unregister()``. + +The KUnit devices should be used in preference to ``root_device_register()``, and +instead of ``platform_device_register()`` in cases where the device is not otherwise +a platform device. + +For example: + +.. code-block:: c + + #include + + static void test_my_device(struct kunit *test) + { + struct device *fake_device; + const char *dev_managed_string; + + // Create a fake device. + fake_device = kunit_device_register(test, "my_device"); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fake_device) + + // Pass it to functions which need a device. + dev_managed_string = devm_kstrdup(fake_device, "Hello, World!"); + + // Everything is cleaned up automatically when the test ends. + } \ No newline at end of file diff --git a/Documentation/devicetree/bindings/Makefile b/Documentation/devicetree/bindings/Makefile index 3e886194b043bb..2323fd5b7cdae1 100644 --- a/Documentation/devicetree/bindings/Makefile +++ b/Documentation/devicetree/bindings/Makefile @@ -28,7 +28,7 @@ $(obj)/%.example.dts: $(src)/%.yaml check_dtschema_version FORCE find_all_cmd = find $(srctree)/$(src) \( -name '*.yaml' ! \ -name 'processed-schema*' \) -find_cmd = $(find_all_cmd) | grep -F -e "$(subst :," -e ",$(DT_SCHEMA_FILES))" +find_cmd = $(find_all_cmd) | sed 's|^$(srctree)/$(src)/||' | grep -F -e "$(subst :," -e ",$(DT_SCHEMA_FILES))" | sed 's|^|$(srctree)/$(src)/|' CHK_DT_DOCS := $(shell $(find_cmd)) quiet_cmd_yamllint = LINT $(src) diff --git a/Documentation/devicetree/bindings/arm/calxeda/l2ecc.yaml b/Documentation/devicetree/bindings/arm/calxeda/l2ecc.yaml index a9fe01238a885d..76b65ea149b65e 100644 --- a/Documentation/devicetree/bindings/arm/calxeda/l2ecc.yaml +++ b/Documentation/devicetree/bindings/arm/calxeda/l2ecc.yaml @@ -16,7 +16,7 @@ maintainers: properties: compatible: - const: "calxeda,hb-sregs-l2-ecc" + const: calxeda,hb-sregs-l2-ecc reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/arm/cpus.yaml b/Documentation/devicetree/bindings/arm/cpus.yaml index ffd526363fda61..cc5a21b47e26a7 100644 --- a/Documentation/devicetree/bindings/arm/cpus.yaml +++ b/Documentation/devicetree/bindings/arm/cpus.yaml @@ -198,6 +198,7 @@ properties: - qcom,kryo660 - qcom,kryo685 - qcom,kryo780 + - qcom,oryon - qcom,scorpion enable-method: diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml index 32b195852a75c5..228dcc5c7d6f3e 100644 --- a/Documentation/devicetree/bindings/arm/fsl.yaml +++ b/Documentation/devicetree/bindings/arm/fsl.yaml @@ -967,6 +967,7 @@ properties: - menlo,mx8menlo # Verdin iMX8M Mini Module on i.MX8MM Menlo board - toradex,verdin-imx8mm-nonwifi-dahlia # Verdin iMX8M Mini Module on Dahlia - toradex,verdin-imx8mm-nonwifi-dev # Verdin iMX8M Mini Module on Verdin Development Board + - toradex,verdin-imx8mm-nonwifi-mallow # Verdin iMX8M Mini Module on Mallow - toradex,verdin-imx8mm-nonwifi-yavia # Verdin iMX8M Mini Module on Yavia - const: toradex,verdin-imx8mm-nonwifi # Verdin iMX8M Mini Module without Wi-Fi / BT - const: toradex,verdin-imx8mm # Verdin iMX8M Mini Module @@ -977,6 +978,7 @@ properties: - enum: - toradex,verdin-imx8mm-wifi-dahlia # Verdin iMX8M Mini Wi-Fi / BT Module on Dahlia - toradex,verdin-imx8mm-wifi-dev # Verdin iMX8M Mini Wi-Fi / BT M. on Verdin Development B. + - toradex,verdin-imx8mm-wifi-mallow # Verdin iMX8M Mini Wi-Fi / BT Module on Mallow - toradex,verdin-imx8mm-wifi-yavia # Verdin iMX8M Mini Wi-Fi / BT Module on Yavia - const: toradex,verdin-imx8mm-wifi # Verdin iMX8M Mini Wi-Fi / BT Module - const: toradex,verdin-imx8mm # Verdin iMX8M Mini Module @@ -1022,7 +1024,10 @@ properties: - description: Variscite VAR-SOM-MX8MN based boards items: - - const: variscite,var-som-mx8mn-symphony + - enum: + - dimonoff,gateway-evk # i.MX8MN Dimonoff Gateway EVK Board + - rve,rve-gateway # i.MX8MN RVE Gateway Board + - variscite,var-som-mx8mn-symphony - const: variscite,var-som-mx8mn - const: fsl,imx8mn @@ -1048,6 +1053,9 @@ properties: - gateworks,imx8mp-gw73xx-2x # i.MX8MP Gateworks Board - gateworks,imx8mp-gw74xx # i.MX8MP Gateworks Board - gateworks,imx8mp-gw7905-2x # i.MX8MP Gateworks Board + - skov,imx8mp-skov-revb-hdmi # SKOV i.MX8MP climate control without panel + - skov,imx8mp-skov-revb-lt6 # SKOV i.MX8MP climate control with 7” panel + - skov,imx8mp-skov-revb-mi1010ait-1cp1 # SKOV i.MX8MP climate control with 10.1" panel - toradex,verdin-imx8mp # Verdin iMX8M Plus Modules - toradex,verdin-imx8mp-nonwifi # Verdin iMX8M Plus Modules without Wi-Fi / BT - toradex,verdin-imx8mp-wifi # Verdin iMX8M Plus Wi-Fi / BT Modules @@ -1100,6 +1108,7 @@ properties: - enum: - toradex,verdin-imx8mp-nonwifi-dahlia # Verdin iMX8M Plus Module on Dahlia - toradex,verdin-imx8mp-nonwifi-dev # Verdin iMX8M Plus Module on Verdin Development Board + - toradex,verdin-imx8mp-nonwifi-mallow # Verdin iMX8M Plus Module on Mallow - toradex,verdin-imx8mp-nonwifi-yavia # Verdin iMX8M Plus Module on Yavia - const: toradex,verdin-imx8mp-nonwifi # Verdin iMX8M Plus Module without Wi-Fi / BT - const: toradex,verdin-imx8mp # Verdin iMX8M Plus Module @@ -1110,6 +1119,7 @@ properties: - enum: - toradex,verdin-imx8mp-wifi-dahlia # Verdin iMX8M Plus Wi-Fi / BT Module on Dahlia - toradex,verdin-imx8mp-wifi-dev # Verdin iMX8M Plus Wi-Fi / BT M. on Verdin Development B. + - toradex,verdin-imx8mp-wifi-mallow # Verdin iMX8M Plus Wi-Fi / BT Module on Mallow - toradex,verdin-imx8mp-wifi-yavia # Verdin iMX8M Plus Wi-Fi / BT Module on Yavia - const: toradex,verdin-imx8mp-wifi # Verdin iMX8M Plus Wi-Fi / BT Module - const: toradex,verdin-imx8mp # Verdin iMX8M Plus Module @@ -1476,6 +1486,16 @@ properties: - const: solidrun,lx2162a-som - const: fsl,lx2160a + - description: + TQ-Systems TQMLX2160A is a series of socketable SOM featuring + LX2160A system-on-chip variants. MBLX2160A mainboard can be used a + starterkit. + items: + - enum: + - tq,lx2160a-tqmlx2160a-mblx2160a + - const: tq,lx2160a-tqmlx2160a + - const: fsl,lx2160a + - description: S32G2 based Boards items: - enum: diff --git a/Documentation/devicetree/bindings/arm/google.yaml b/Documentation/devicetree/bindings/arm/google.yaml new file mode 100644 index 00000000000000..e20b5c9b16bc94 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/google.yaml @@ -0,0 +1,53 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/arm/google.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Google Tensor platforms + +maintainers: + - Peter Griffin + +description: | + ARM platforms using SoCs designed by Google branded "Tensor" used in Pixel + devices. + + Currently upstream this is devices using "gs101" SoC which is found in Pixel + 6, Pixel 6 Pro and Pixel 6a. + + Google have a few different names for the SoC: + - Marketing name ("Tensor") + - Codename ("Whitechapel") + - SoC ID ("gs101") + - Die ID ("S5P9845") + + Likewise there are a couple of names for the actual device + - Marketing name ("Pixel 6") + - Codename ("Oriole") + + Devicetrees should use the lowercased SoC ID and lowercased board codename, + e.g. gs101 and gs101-oriole. + +properties: + $nodename: + const: '/' + compatible: + oneOf: + - description: Google Pixel 6 / Oriole + items: + - enum: + - google,gs101-oriole + - const: google,gs101 + + # Bootloader requires empty ect node to be present + ect: + type: object + additionalProperties: false + +required: + - ect + +additionalProperties: true + +... diff --git a/Documentation/devicetree/bindings/arm/hisilicon/controller/sysctrl.yaml b/Documentation/devicetree/bindings/arm/hisilicon/controller/sysctrl.yaml index 5a53d433b6f089..7a221e1c09dfec 100644 --- a/Documentation/devicetree/bindings/arm/hisilicon/controller/sysctrl.yaml +++ b/Documentation/devicetree/bindings/arm/hisilicon/controller/sysctrl.yaml @@ -82,6 +82,23 @@ properties: ranges: true +patternProperties: + '^clock@': + type: object + additionalProperties: false + + properties: + compatible: + enum: + - hisilicon,hi3620-clock + - hisilicon,hi3620-mmc-clock + + reg: + maxItems: 1 + + '#clock-cells': + const: 1 + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml b/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml index 52d78521e4124c..16d2e132d3d1bf 100644 --- a/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml +++ b/Documentation/devicetree/bindings/arm/marvell/armada-7k-8k.yaml @@ -60,4 +60,26 @@ properties: - const: marvell,armada-ap807-quad - const: marvell,armada-ap807 + - description: + Alleycat5X (98DX35xx) Reference Design as COM Express Carrier plus + Armada CN9130 COM Express CPU module + items: + - const: marvell,cn9130-ac5x-carrier + - const: marvell,rd-ac5x-carrier + - const: marvell,cn9130-cpu-module + - const: marvell,cn9130 + - const: marvell,armada-ap807-quad + - const: marvell,armada-ap807 + + - description: + Alleycat5X (98DX35xx) Reference Design as COM Express Carrier plus + Armada CN9131 COM Express CPU module + items: + - const: marvell,cn9131-ac5x-carrier + - const: marvell,rd-ac5x-carrier + - const: marvell,cn9131-cpu-module + - const: marvell,cn9131 + - const: marvell,armada-ap807-quad + - const: marvell,armada-ap807 + additionalProperties: true diff --git a/Documentation/devicetree/bindings/arm/mediatek.yaml b/Documentation/devicetree/bindings/arm/mediatek.yaml index a5999b3afc3505..6f2f64ae76fcf3 100644 --- a/Documentation/devicetree/bindings/arm/mediatek.yaml +++ b/Documentation/devicetree/bindings/arm/mediatek.yaml @@ -174,6 +174,10 @@ properties: - enum: - mediatek,mt8186-evb - const: mediatek,mt8186 + - items: + - enum: + - mediatek,mt8188-evb + - const: mediatek,mt8188 - items: - enum: - mediatek,mt8192-evb @@ -235,6 +239,13 @@ properties: items: - const: google,kappa - const: mediatek,mt8183 + - description: Google Katsu (ASUS Chromebook Detachable CZ1) + items: + - enum: + - google,katsu-sku32 + - google,katsu-sku38 + - const: google,katsu + - const: mediatek,mt8183 - description: Google Kodama (Lenovo 10e Chromebook Tablet) items: - enum: @@ -244,6 +255,20 @@ properties: - google,kodama-sku32 - const: google,kodama - const: mediatek,mt8183 + - description: Google Makomo (Lenovo 100e Chromebook 2nd Gen MTK 2) + items: + - enum: + - google,makomo-sku0 + - google,makomo-sku1 + - const: google,makomo + - const: mediatek,mt8183 + - description: Google Pico (Acer Chromebook Spin 311) + items: + - enum: + - google,pico-sku1 + - google,pico-sku2 + - const: google,pico + - const: mediatek,mt8183 - description: Google Willow (Acer Chromebook 311 C722/C722T) items: - enum: diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,audsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,audsys.txt deleted file mode 100644 index 699776be1dd348..00000000000000 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,audsys.txt +++ /dev/null @@ -1,39 +0,0 @@ -MediaTek AUDSYS controller -============================ - -The MediaTek AUDSYS controller provides various clocks to the system. - -Required Properties: - -- compatible: Should be one of: - - "mediatek,mt2701-audsys", "syscon" - - "mediatek,mt6765-audsys", "syscon" - - "mediatek,mt6779-audio", "syscon" - - "mediatek,mt7622-audsys", "syscon" - - "mediatek,mt7623-audsys", "mediatek,mt2701-audsys", "syscon" - - "mediatek,mt8167-audiosys", "syscon" - - "mediatek,mt8183-audiosys", "syscon" - - "mediatek,mt8192-audsys", "syscon" - - "mediatek,mt8516-audsys", "syscon" -- #clock-cells: Must be 1 - -The AUDSYS controller uses the common clk binding from -Documentation/devicetree/bindings/clock/clock-bindings.txt -The available clocks are defined in dt-bindings/clock/mt*-clk.h. - -Required sub-nodes: -------- -For common binding part and usage, refer to -../sonud/mt2701-afe-pcm.txt. - -Example: - - audsys: clock-controller@11220000 { - compatible = "mediatek,mt7622-audsys", "syscon"; - reg = <0 0x11220000 0 0x2000>; - #clock-cells = <1>; - - afe: audio-controller { - ... - }; - }; diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,audsys.yaml b/Documentation/devicetree/bindings/arm/mediatek/mediatek,audsys.yaml new file mode 100644 index 00000000000000..45d4a6620041b1 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,audsys.yaml @@ -0,0 +1,153 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/arm/mediatek/mediatek,audsys.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek AUDSYS controller + +maintainers: + - Eugen Hristev + +description: + The MediaTek AUDSYS controller provides various clocks to the system. + +properties: + compatible: + oneOf: + - items: + - enum: + - mediatek,mt2701-audsys + - mediatek,mt6765-audsys + - mediatek,mt6779-audsys + - mediatek,mt7622-audsys + - mediatek,mt8167-audsys + - mediatek,mt8173-audsys + - mediatek,mt8183-audsys + - mediatek,mt8186-audsys + - mediatek,mt8192-audsys + - mediatek,mt8516-audsys + - const: syscon + - items: + # Special case for mt7623 for backward compatibility + - const: mediatek,mt7623-audsys + - const: mediatek,mt2701-audsys + - const: syscon + + reg: + maxItems: 1 + + '#clock-cells': + const: 1 + + audio-controller: + $ref: /schemas/sound/mediatek,mt2701-audio.yaml# + type: object + +required: + - compatible + - '#clock-cells' + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + soc { + #address-cells = <2>; + #size-cells = <2>; + audsys: clock-controller@11220000 { + compatible = "mediatek,mt7622-audsys", "syscon"; + reg = <0 0x11220000 0 0x2000>; + #clock-cells = <1>; + + afe: audio-controller { + compatible = "mediatek,mt2701-audio"; + interrupts = , + ; + interrupt-names = "afe", "asys"; + power-domains = <&scpsys MT2701_POWER_DOMAIN_IFR_MSC>; + + clocks = <&infracfg CLK_INFRA_AUDIO>, + <&topckgen CLK_TOP_AUD_MUX1_SEL>, + <&topckgen CLK_TOP_AUD_MUX2_SEL>, + <&topckgen CLK_TOP_AUD_48K_TIMING>, + <&topckgen CLK_TOP_AUD_44K_TIMING>, + <&topckgen CLK_TOP_AUD_K1_SRC_SEL>, + <&topckgen CLK_TOP_AUD_K2_SRC_SEL>, + <&topckgen CLK_TOP_AUD_K3_SRC_SEL>, + <&topckgen CLK_TOP_AUD_K4_SRC_SEL>, + <&topckgen CLK_TOP_AUD_K1_SRC_DIV>, + <&topckgen CLK_TOP_AUD_K2_SRC_DIV>, + <&topckgen CLK_TOP_AUD_K3_SRC_DIV>, + <&topckgen CLK_TOP_AUD_K4_SRC_DIV>, + <&topckgen CLK_TOP_AUD_I2S1_MCLK>, + <&topckgen CLK_TOP_AUD_I2S2_MCLK>, + <&topckgen CLK_TOP_AUD_I2S3_MCLK>, + <&topckgen CLK_TOP_AUD_I2S4_MCLK>, + <&audsys CLK_AUD_I2SO1>, + <&audsys CLK_AUD_I2SO2>, + <&audsys CLK_AUD_I2SO3>, + <&audsys CLK_AUD_I2SO4>, + <&audsys CLK_AUD_I2SIN1>, + <&audsys CLK_AUD_I2SIN2>, + <&audsys CLK_AUD_I2SIN3>, + <&audsys CLK_AUD_I2SIN4>, + <&audsys CLK_AUD_ASRCO1>, + <&audsys CLK_AUD_ASRCO2>, + <&audsys CLK_AUD_ASRCO3>, + <&audsys CLK_AUD_ASRCO4>, + <&audsys CLK_AUD_AFE>, + <&audsys CLK_AUD_AFE_CONN>, + <&audsys CLK_AUD_A1SYS>, + <&audsys CLK_AUD_A2SYS>, + <&audsys CLK_AUD_AFE_MRGIF>; + + clock-names = "infra_sys_audio_clk", + "top_audio_mux1_sel", + "top_audio_mux2_sel", + "top_audio_a1sys_hp", + "top_audio_a2sys_hp", + "i2s0_src_sel", + "i2s1_src_sel", + "i2s2_src_sel", + "i2s3_src_sel", + "i2s0_src_div", + "i2s1_src_div", + "i2s2_src_div", + "i2s3_src_div", + "i2s0_mclk_en", + "i2s1_mclk_en", + "i2s2_mclk_en", + "i2s3_mclk_en", + "i2so0_hop_ck", + "i2so1_hop_ck", + "i2so2_hop_ck", + "i2so3_hop_ck", + "i2si0_hop_ck", + "i2si1_hop_ck", + "i2si2_hop_ck", + "i2si3_hop_ck", + "asrc0_out_ck", + "asrc1_out_ck", + "asrc2_out_ck", + "asrc3_out_ck", + "audio_afe_pd", + "audio_afe_conn_pd", + "audio_a1sys_pd", + "audio_a2sys_pd", + "audio_mrgif_pd"; + + assigned-clocks = <&topckgen CLK_TOP_AUD_MUX1_SEL>, + <&topckgen CLK_TOP_AUD_MUX2_SEL>, + <&topckgen CLK_TOP_AUD_MUX1_DIV>, + <&topckgen CLK_TOP_AUD_MUX2_DIV>; + assigned-clock-parents = <&topckgen CLK_TOP_AUD1PLL_98M>, + <&topckgen CLK_TOP_AUD2PLL_90M>; + assigned-clock-rates = <0>, <0>, <49152000>, <45158400>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,ethsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,ethsys.txt deleted file mode 100644 index eccd4b706a78dd..00000000000000 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,ethsys.txt +++ /dev/null @@ -1,29 +0,0 @@ -Mediatek ethsys controller -============================ - -The Mediatek ethsys controller provides various clocks to the system. - -Required Properties: - -- compatible: Should be: - - "mediatek,mt2701-ethsys", "syscon" - - "mediatek,mt7622-ethsys", "syscon" - - "mediatek,mt7623-ethsys", "mediatek,mt2701-ethsys", "syscon" - - "mediatek,mt7629-ethsys", "syscon" - - "mediatek,mt7981-ethsys", "syscon" - - "mediatek,mt7986-ethsys", "syscon" -- #clock-cells: Must be 1 -- #reset-cells: Must be 1 - -The ethsys controller uses the common clk binding from -Documentation/devicetree/bindings/clock/clock-bindings.txt -The available clocks are defined in dt-bindings/clock/mt*-clk.h. - -Example: - -ethsys: clock-controller@1b000000 { - compatible = "mediatek,mt2701-ethsys", "syscon"; - reg = <0 0x1b000000 0 0x1000>; - #clock-cells = <1>; - #reset-cells = <1>; -}; diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.yaml b/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.yaml index ea98043c6ba3d3..230b5188a88dbe 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.yaml +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.yaml @@ -30,6 +30,7 @@ properties: - mediatek,mt7629-infracfg - mediatek,mt7981-infracfg - mediatek,mt7986-infracfg + - mediatek,mt7988-infracfg - mediatek,mt8135-infracfg - mediatek,mt8167-infracfg - mediatek,mt8173-infracfg diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.yaml b/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.yaml index 536f5a5ebd2468..b3c6888c14573d 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.yaml +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.yaml @@ -32,6 +32,9 @@ properties: - mediatek,mt8183-mmsys - mediatek,mt8186-mmsys - mediatek,mt8188-vdosys0 + - mediatek,mt8188-vdosys1 + - mediatek,mt8188-vppsys0 + - mediatek,mt8188-vppsys1 - mediatek,mt8192-mmsys - mediatek,mt8195-vdosys1 - mediatek,mt8195-vppsys0 diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.yaml b/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.yaml index 26158d0d72f3bb..33c94c491828e2 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.yaml +++ b/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.yaml @@ -28,6 +28,7 @@ properties: - mediatek,mt8173-pericfg - mediatek,mt8183-pericfg - mediatek,mt8186-pericfg + - mediatek,mt8188-pericfg - mediatek,mt8195-pericfg - mediatek,mt8516-pericfg - const: syscon diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,idle-state.txt b/Documentation/devicetree/bindings/arm/msm/qcom,idle-state.txt deleted file mode 100644 index 606b4b1b709da8..00000000000000 --- a/Documentation/devicetree/bindings/arm/msm/qcom,idle-state.txt +++ /dev/null @@ -1,84 +0,0 @@ -QCOM Idle States for cpuidle driver - -ARM provides idle-state node to define the cpuidle states, as defined in [1]. -cpuidle-qcom is the cpuidle driver for Qualcomm SoCs and uses these idle -states. Idle states have different enter/exit latency and residency values. -The idle states supported by the QCOM SoC are defined as - - - * Standby - * Retention - * Standalone Power Collapse (Standalone PC or SPC) - * Power Collapse (PC) - -Standby: Standby does a little more in addition to architectural clock gating. -When the WFI instruction is executed the ARM core would gate its internal -clocks. In addition to gating the clocks, QCOM cpus use this instruction as a -trigger to execute the SPM state machine. The SPM state machine waits for the -interrupt to trigger the core back in to active. This triggers the cache -hierarchy to enter standby states, when all cpus are idle. An interrupt brings -the SPM state machine out of its wait, the next step is to ensure that the -cache hierarchy is also out of standby, and then the cpu is allowed to resume -execution. This state is defined as a generic ARM WFI state by the ARM cpuidle -driver and is not defined in the DT. The SPM state machine should be -configured to execute this state by default and after executing every other -state below. - -Retention: Retention is a low power state where the core is clock gated and -the memory and the registers associated with the core are retained. The -voltage may be reduced to the minimum value needed to keep the processor -registers active. The SPM should be configured to execute the retention -sequence and would wait for interrupt, before restoring the cpu to execution -state. Retention may have a slightly higher latency than Standby. - -Standalone PC: A cpu can power down and warmboot if there is a sufficient time -between the time it enters idle and the next known wake up. SPC mode is used -to indicate a core entering a power down state without consulting any other -cpu or the system resources. This helps save power only on that core. The SPM -sequence for this idle state is programmed to power down the supply to the -core, wait for the interrupt, restore power to the core, and ensure the -system state including cache hierarchy is ready before allowing core to -resume. Applying power and resetting the core causes the core to warmboot -back into Elevation Level (EL) which trampolines the control back to the -kernel. Entering a power down state for the cpu, needs to be done by trapping -into a EL. Failing to do so, would result in a crash enforced by the warm boot -code in the EL for the SoC. On SoCs with write-back L1 cache, the cache has to -be flushed in s/w, before powering down the core. - -Power Collapse: This state is similar to the SPC mode, but distinguishes -itself in that the cpu acknowledges and permits the SoC to enter deeper sleep -modes. In a hierarchical power domain SoC, this means L2 and other caches can -be flushed, system bus, clocks - lowered, and SoC main XO clock gated and -voltages reduced, provided all cpus enter this state. Since the span of low -power modes possible at this state is vast, the exit latency and the residency -of this low power mode would be considered high even though at a cpu level, -this essentially is cpu power down. The SPM in this state also may handshake -with the Resource power manager (RPM) processor in the SoC to indicate a -complete application processor subsystem shut down. - -The idle-state for QCOM SoCs are distinguished by the compatible property of -the idle-states device node. - -The devicetree representation of the idle state should be - - -Required properties: - -- compatible: Must be one of - - "qcom,idle-state-ret", - "qcom,idle-state-spc", - "qcom,idle-state-pc", - and "arm,idle-state". - -Other required and optional properties are specified in [1]. - -Example: - - idle-states { - CPU_SPC: spc { - compatible = "qcom,idle-state-spc", "arm,idle-state"; - entry-latency-us = <150>; - exit-latency-us = <200>; - min-residency-us = <2000>; - }; - }; - -[1]. Documentation/devicetree/bindings/cpu/idle-states.yaml diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-remote-etm.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-remote-etm.yaml new file mode 100644 index 00000000000000..4fd5752978cd03 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/qcom,coresight-remote-etm.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/arm/qcom,coresight-remote-etm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Coresight Remote ETM(Embedded Trace Macrocell) + +maintainers: + - Jinlong Mao + - Tao Zhang + +description: + Support for ETM trace collection on remote processor using coresight + framework. Enabling this will allow turning on ETM tracing on remote + processor like modem processor via sysfs and collecting the trace + via coresight TMC sinks. + +properties: + compatible: + const: qcom,coresight-remote-etm + + out-ports: + $ref: /schemas/graph.yaml#/properties/ports + additionalProperties: false + + properties: + port: + description: Output connection to the CoreSight Trace bus. + $ref: /schemas/graph.yaml#/properties/port + +required: + - compatible + - out-ports + +additionalProperties: false + +examples: + - | + etm { + compatible = "qcom,coresight-remote-etm"; + + out-ports { + port { + modem_etm0_out_funnel_modem: endpoint { + remote-endpoint = <&funnel_modem_in_modem_etm0>; + }; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml b/Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml index 3bad47b7b02bb9..61ddc3b5b247b0 100644 --- a/Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml +++ b/Documentation/devicetree/bindings/arm/qcom,coresight-tpdm.yaml @@ -44,6 +44,23 @@ properties: minItems: 1 maxItems: 2 + qcom,dsb-element-size: + description: + Specifies the DSB(Discrete Single Bit) element size supported by + the monitor. The associated aggregator will read this size before it + is enabled. DSB element size currently only supports 32-bit and 64-bit. + $ref: /schemas/types.yaml#/definitions/uint8 + enum: [32, 64] + + qcom,dsb-msrs-num: + description: + Specifies the number of DSB(Discrete Single Bit) MSR(mux select register) + registers supported by the monitor. If this property is not configured + or set to 0, it means this DSB TPDM doesn't support MSR. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 32 + clocks: maxItems: 1 @@ -77,6 +94,9 @@ examples: compatible = "qcom,coresight-tpdm", "arm,primecell"; reg = <0x0684c000 0x1000>; + qcom,dsb-element-size = /bits/ 8 <32>; + qcom,dsb-msrs-num = <16>; + clocks = <&aoss_qmp>; clock-names = "apb_pclk"; diff --git a/Documentation/devicetree/bindings/arm/qcom-soc.yaml b/Documentation/devicetree/bindings/arm/qcom-soc.yaml index 97621c92a1ab31..d0751a572af39e 100644 --- a/Documentation/devicetree/bindings/arm/qcom-soc.yaml +++ b/Documentation/devicetree/bindings/arm/qcom-soc.yaml @@ -23,7 +23,7 @@ description: | select: properties: compatible: - pattern: "^qcom,.*(apq|ipq|mdm|msm|qcm|qcs|sa|sc|sdm|sdx|sm)[0-9]+.*$" + pattern: "^qcom,.*(apq|ipq|mdm|msm|qcm|qcs|q[dr]u|sa|sc|sd[amx]|sm|x1e)[0-9]+.*$" required: - compatible @@ -31,17 +31,17 @@ properties: compatible: oneOf: # Preferred naming style for compatibles of SoC components: - - pattern: "^qcom,(apq|ipq|mdm|msm|qcm|qcs|sa|sc|sdm|sdx|sm)[0-9]+(pro)?-.*$" + - pattern: "^qcom,(apq|ipq|mdm|msm|qcm|qcs|q[dr]u|sa|sc|sd[amx]|sm|x1e)[0-9]+(pro)?-.*$" - pattern: "^qcom,(sa|sc)8[0-9]+[a-z][a-z]?-.*$" # Legacy namings - variations of existing patterns/compatibles are OK, # but do not add completely new entries to these: - - pattern: "^qcom,[ak]pss-wdt-(apq|ipq|mdm|msm|qcm|qcs|sa|sc|sdm|sdx|sm)[0-9]+.*$" - - pattern: "^qcom,gcc-(apq|ipq|mdm|msm|qcm|qcs|sa|sc|sdm|sdx|sm)[0-9]+.*$" - - pattern: "^qcom,mmcc-(apq|ipq|mdm|msm|qcm|qcs|sa|sc|sdm|sdx|sm)[0-9]+.*$" - - pattern: "^qcom,pcie-(apq|ipq|mdm|msm|qcm|qcs|sa|sc|sdm|sdx|sm)[0-9]+.*$" - - pattern: "^qcom,rpm-(apq|ipq|mdm|msm|qcm|qcs|sa|sc|sdm|sdx|sm)[0-9]+.*$" - - pattern: "^qcom,scm-(apq|ipq|mdm|msm|qcm|qcs|sa|sc|sdm|sdx|sm)[0-9]+.*$" + - pattern: "^qcom,[ak]pss-wdt-(apq|ipq|mdm|msm|qcm|qcs|q[dr]u|sa|sc|sd[amx]|sm)[0-9]+.*$" + - pattern: "^qcom,gcc-(apq|ipq|mdm|msm|qcm|qcs|q[dr]u|sa|sc|sd[amx]|sm)[0-9]+.*$" + - pattern: "^qcom,mmcc-(apq|ipq|mdm|msm|qcm|qcs|q[dr]u|sa|sc|sd[amx]|sm)[0-9]+.*$" + - pattern: "^qcom,pcie-(apq|ipq|mdm|msm|qcm|qcs|q[dr]u|sa|sc|sd[amx]|sm|x1e)[0-9]+.*$" + - pattern: "^qcom,rpm-(apq|ipq|mdm|msm|qcm|qcs|q[dr]u|sa|sc|sd[amx]|sm)[0-9]+.*$" + - pattern: "^qcom,scm-(apq|ipq|mdm|msm|qcm|qcs|q[dr]u|sa|sc|sd[amx]|sm|x1e)[0-9]+.*$" - enum: - qcom,dsi-ctrl-6g-qcm2290 - qcom,gpucc-sdm630 diff --git a/Documentation/devicetree/bindings/arm/qcom.yaml b/Documentation/devicetree/bindings/arm/qcom.yaml index 7f80f48a09544a..1a5fb889a4440f 100644 --- a/Documentation/devicetree/bindings/arm/qcom.yaml +++ b/Documentation/devicetree/bindings/arm/qcom.yaml @@ -87,29 +87,18 @@ description: | sm8350 sm8450 sm8550 + sm8650 + x1e80100 The 'board' element must be one of the following strings: adp - ap-al02-c2 - ap-al02-c6 - ap-al02-c7 - ap-al02-c8 - ap-al02-c9 - ap-mi01.2 - ap-mi01.3 - ap-mi01.6 - ap-mi01.9 cdp - cp01-c1 dragonboard - hk01 - hk10-c1 - hk10-c2 idp liquid - rdp432-c2 mtp + qcp qrd rb2 ride @@ -138,7 +127,7 @@ description: | There are many devices in the list below that run the standard ChromeOS bootloader setup and use the open source depthcharge bootloader to boot the OS. These devices do not use the scheme described above. For details, see: - https://docs.kernel.org/arm/google/chromebook-boot-flow.html + https://docs.kernel.org/arch/arm/google/chromebook-boot-flow.html properties: $nodename: @@ -186,11 +175,24 @@ properties: - items: - enum: + - microsoft,dempsey + - microsoft,makepeace + - microsoft,moneypenny - samsung,s3ve3g - const: qcom,msm8226 - items: - enum: + - htc,memul + - microsoft,superman-lte + - microsoft,tesla + - motorola,peregrine + - const: qcom,msm8926 + - const: qcom,msm8226 + + - items: + - enum: + - huawei,kiwi - longcheer,l9100 - samsung,a7 - sony,kanuti-tulip @@ -397,6 +399,8 @@ properties: - items: - enum: - fairphone,fp5 + - qcom,qcm6490-idp + - qcom,qcs6490-rb3gen2 - const: qcom,qcm6490 - description: Qualcomm Technologies, Inc. Distributed Unit 1000 platform @@ -1009,6 +1013,7 @@ properties: - sony,pdx203-generic - sony,pdx206-generic - xiaomi,elish + - xiaomi,pipa - const: qcom,sm8250 - items: @@ -1034,6 +1039,18 @@ properties: - qcom,sm8550-qrd - const: qcom,sm8550 + - items: + - enum: + - qcom,sm8650-mtp + - qcom,sm8650-qrd + - const: qcom,sm8650 + + - items: + - enum: + - qcom,x1e80100-crd + - qcom,x1e80100-qcp + - const: qcom,x1e80100 + # Board compatibles go above qcom,msm-id: diff --git a/Documentation/devicetree/bindings/arm/rockchip.yaml b/Documentation/devicetree/bindings/arm/rockchip.yaml index 5f7c6c4aad8f13..5cf5cbef2cf550 100644 --- a/Documentation/devicetree/bindings/arm/rockchip.yaml +++ b/Documentation/devicetree/bindings/arm/rockchip.yaml @@ -30,9 +30,11 @@ properties: - const: amarula,vyasa-rk3288 - const: rockchip,rk3288 - - description: Anbernic RG351M + - description: Anbernic RK3326 Handheld Gaming Console items: - - const: anbernic,rg351m + - enum: + - anbernic,rg351m + - anbernic,rg351v - const: rockchip,rk3326 - description: Anbernic RG353P @@ -95,22 +97,30 @@ properties: - const: chipspark,rayeager-px2 - const: rockchip,rk3066a + - description: Cool Pi Compute Module 5(CM5) EVB + items: + - enum: + - coolpi,pi-cm5-evb + - const: coolpi,pi-cm5 + - const: rockchip,rk3588 + + - description: Cool Pi 4 Model B + items: + - const: coolpi,pi-4b + - const: rockchip,rk3588s + - description: Edgeble Neural Compute Module 2(Neu2) SoM based boards items: - const: edgeble,neural-compute-module-2-io # Edgeble Neural Compute Module 2 IO Board - const: edgeble,neural-compute-module-2 # Edgeble Neural Compute Module 2 SoM - const: rockchip,rv1126 - - description: Edgeble Neural Compute Module 6(Neu6) Model A SoM based boards - items: - - const: edgeble,neural-compute-module-6a-io # Edgeble Neural Compute Module 6A IO Board - - const: edgeble,neural-compute-module-6a # Edgeble Neural Compute Module 6A SoM - - const: rockchip,rk3588 - - - description: Edgeble Neural Compute Module 6(Neu6) Model B SoM based boards + - description: Edgeble Neural Compute Module 6(Neu6) SoM based boards items: - - const: edgeble,neural-compute-module-6b-io # Edgeble Neural Compute Module 6B IO Board - - const: edgeble,neural-compute-module-6b # Edgeble Neural Compute Module 6B SoM + - const: edgeble,neural-compute-module-6a-io # Edgeble NCM6A-IO Board + - enum: + - edgeble,neural-compute-module-6a # Edgeble Neural Compute Module 6A SoM + - edgeble,neural-compute-module-6b # Edgeble Neural Compute Module 6B SoM - const: rockchip,rk3588 - description: Elgin RV1108 R1 @@ -237,6 +247,11 @@ properties: - const: geekbuying,geekbox - const: rockchip,rk3368 + - description: Geniatech XPI-3128 + items: + - const: geniatech,xpi-3128 + - const: rockchip,rk3128 + - description: Google Bob (Asus Chromebook Flip C101PA) items: - const: google,bob-rev13 @@ -674,9 +689,12 @@ properties: - const: pine64,soquartz - const: rockchip,rk3566 - - description: Powkiddy RGB30 + - description: Powkiddy RK3566 Handheld Gaming Console items: - - const: powkiddy,rgb30 + - enum: + - powkiddy,rgb30 + - powkiddy,rk2023 + - powkiddy,x55 - const: rockchip,rk3566 - description: Radxa Compute Module 3(CM3) @@ -875,6 +893,11 @@ properties: - const: tsd,rk3399-puma-haikou - const: rockchip,rk3399 + - description: Theobroma Systems RK3588-SBC Jaguar + items: + - const: tsd,rk3588-jaguar + - const: rockchip,rk3588 + - description: Tronsmart Orion R68 Meta items: - const: tronsmart,orion-r68-meta @@ -922,6 +945,13 @@ properties: - const: rockchip,rk3568-bpi-r2pro - const: rockchip,rk3568 + - description: Sonoff iHost Smart Home Hub + items: + - const: itead,sonoff-ihost + - enum: + - rockchip,rv1126 + - rockchip,rv1109 + additionalProperties: true ... diff --git a/Documentation/devicetree/bindings/arm/samsung/samsung-boards.yaml b/Documentation/devicetree/bindings/arm/samsung/samsung-boards.yaml index e3ffd8159ab6c6..01dcbd8aa70303 100644 --- a/Documentation/devicetree/bindings/arm/samsung/samsung-boards.yaml +++ b/Documentation/devicetree/bindings/arm/samsung/samsung-boards.yaml @@ -230,6 +230,12 @@ properties: - samsung,exynosautov9-sadk # Samsung Exynos Auto v9 SADK - const: samsung,exynosautov9 + - description: Exynos Auto v920 based boards + items: + - enum: + - samsung,exynosautov920-sadk # Samsung Exynos Auto v920 SADK + - const: samsung,exynosautov920 + required: - compatible diff --git a/Documentation/devicetree/bindings/arm/sprd/sprd.yaml b/Documentation/devicetree/bindings/arm/sprd/sprd.yaml index eaa67b8e0d6c74..40fc3c8b9dceec 100644 --- a/Documentation/devicetree/bindings/arm/sprd/sprd.yaml +++ b/Documentation/devicetree/bindings/arm/sprd/sprd.yaml @@ -35,6 +35,11 @@ properties: - sprd,ums512-1h10 - const: sprd,ums512 + - items: + - enum: + - sprd,ums9620-2h10 + - const: sprd,ums9620 + additionalProperties: true ... diff --git a/Documentation/devicetree/bindings/arm/stm32/stm32.yaml b/Documentation/devicetree/bindings/arm/stm32/stm32.yaml index df087c81c69ebf..bc2f43330ae42c 100644 --- a/Documentation/devicetree/bindings/arm/stm32/stm32.yaml +++ b/Documentation/devicetree/bindings/arm/stm32/stm32.yaml @@ -82,29 +82,19 @@ properties: - shiratech,stm32mp157a-iot-box # IoT Box - shiratech,stm32mp157a-stinger96 # Stinger96 - st,stm32mp157c-ed1 + - st,stm32mp157c-ed1-scmi - st,stm32mp157a-dk1 + - st,stm32mp157a-dk1-scmi - st,stm32mp157c-dk2 + - st,stm32mp157c-dk2-scmi - const: st,stm32mp157 - - items: - - const: st,stm32mp157a-dk1-scmi - - const: st,stm32mp157a-dk1 - - const: st,stm32mp157 - - items: - - const: st,stm32mp157c-dk2-scmi - - const: st,stm32mp157c-dk2 - - const: st,stm32mp157 - - items: - - const: st,stm32mp157c-ed1-scmi - - const: st,stm32mp157c-ed1 - - const: st,stm32mp157 - items: - const: st,stm32mp157c-ev1 - const: st,stm32mp157c-ed1 - const: st,stm32mp157 - items: - const: st,stm32mp157c-ev1-scmi - - const: st,stm32mp157c-ev1 - const: st,stm32mp157c-ed1 - const: st,stm32mp157 diff --git a/Documentation/devicetree/bindings/arm/sunxi.yaml b/Documentation/devicetree/bindings/arm/sunxi.yaml index 11c5ce941dd7e3..a9d8e85565b899 100644 --- a/Documentation/devicetree/bindings/arm/sunxi.yaml +++ b/Documentation/devicetree/bindings/arm/sunxi.yaml @@ -868,6 +868,11 @@ properties: - const: topwise,a721 - const: allwinner,sun4i-a10 + - description: Transpeed 8K618-T + items: + - const: transpeed,8k618-t + - const: allwinner,sun50i-h618 + - description: Utoo P66 items: - const: utoo,p66 @@ -1013,6 +1018,11 @@ properties: - const: xunlong,orangepi-zero2 - const: allwinner,sun50i-h616 + - description: Xunlong OrangePi Zero 2W + items: + - const: xunlong,orangepi-zero2w + - const: allwinner,sun50i-h618 + - description: Xunlong OrangePi Zero 3 items: - const: xunlong,orangepi-zero3 diff --git a/Documentation/devicetree/bindings/arm/ti/k3.yaml b/Documentation/devicetree/bindings/arm/ti/k3.yaml index 03d2a0d79fb06c..c6506bccfe88fa 100644 --- a/Documentation/devicetree/bindings/arm/ti/k3.yaml +++ b/Documentation/devicetree/bindings/arm/ti/k3.yaml @@ -50,6 +50,7 @@ properties: - enum: - toradex,verdin-am62-nonwifi-dahlia # Verdin AM62 Module on Dahlia - toradex,verdin-am62-nonwifi-dev # Verdin AM62 Module on Verdin Development Board + - toradex,verdin-am62-nonwifi-mallow # Verdin AM62 Module on Mallow - toradex,verdin-am62-nonwifi-yavia # Verdin AM62 Module on Yavia - const: toradex,verdin-am62-nonwifi # Verdin AM62 Module without Wi-Fi / BT - const: toradex,verdin-am62 # Verdin AM62 Module @@ -60,6 +61,7 @@ properties: - enum: - toradex,verdin-am62-wifi-dahlia # Verdin AM62 Wi-Fi / BT Module on Dahlia - toradex,verdin-am62-wifi-dev # Verdin AM62 Wi-Fi / BT M. on Verdin Development B. + - toradex,verdin-am62-wifi-mallow # Verdin AM62 Wi-Fi / BT Module on Mallow - toradex,verdin-am62-wifi-yavia # Verdin AM62 Wi-Fi / BT Module on Yavia - const: toradex,verdin-am62-wifi # Verdin AM62 Wi-Fi / BT Module - const: toradex,verdin-am62 # Verdin AM62 Module diff --git a/Documentation/devicetree/bindings/arm/ti/omap.yaml b/Documentation/devicetree/bindings/arm/ti/omap.yaml index b18fc046390a44..93e04a109a12fa 100644 --- a/Documentation/devicetree/bindings/arm/ti/omap.yaml +++ b/Documentation/devicetree/bindings/arm/ti/omap.yaml @@ -134,6 +134,8 @@ properties: - amazon,omap4-kc1 # Amazon Kindle Fire (first generation) - motorola,droid4 # Motorola Droid 4 XT894 - motorola,droid-bionic # Motorola Droid Bionic XT875 + - motorola,xyboard-mz609 + - motorola,xyboard-mz617 - ti,omap4-panda - ti,omap4-sdp - const: ti,omap4430 diff --git a/Documentation/devicetree/bindings/arm/xilinx.yaml b/Documentation/devicetree/bindings/arm/xilinx.yaml deleted file mode 100644 index f57ed0347894ba..00000000000000 --- a/Documentation/devicetree/bindings/arm/xilinx.yaml +++ /dev/null @@ -1,137 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/arm/xilinx.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Xilinx Zynq Platforms - -maintainers: - - Michal Simek - -description: | - Xilinx boards with Zynq-7000 SOC or Zynq UltraScale+ MPSoC - -properties: - $nodename: - const: '/' - compatible: - oneOf: - - items: - - enum: - - adapteva,parallella - - digilent,zynq-zybo - - digilent,zynq-zybo-z7 - - ebang,ebaz4205 - - myir,zynq-zturn-v5 - - myir,zynq-zturn - - xlnx,zynq-cc108 - - xlnx,zynq-zc702 - - xlnx,zynq-zc706 - - xlnx,zynq-zc770-xm010 - - xlnx,zynq-zc770-xm011 - - xlnx,zynq-zc770-xm012 - - xlnx,zynq-zc770-xm013 - - const: xlnx,zynq-7000 - - - items: - - const: avnet,zynq-microzed - - const: xlnx,zynq-microzed - - const: xlnx,zynq-7000 - - - items: - - const: avnet,zynq-zed - - const: xlnx,zynq-zed - - const: xlnx,zynq-7000 - - - items: - - enum: - - xlnx,zynqmp-zc1751 - - const: xlnx,zynqmp - - - description: Xilinx internal board zc1232 - items: - - const: xlnx,zynqmp-zc1232-revA - - const: xlnx,zynqmp-zc1232 - - const: xlnx,zynqmp - - - description: Xilinx internal board zc1254 - items: - - const: xlnx,zynqmp-zc1254-revA - - const: xlnx,zynqmp-zc1254 - - const: xlnx,zynqmp - - - description: Xilinx evaluation board zcu1275 - items: - - const: xlnx,zynqmp-zcu1275-revA - - const: xlnx,zynqmp-zcu1275 - - const: xlnx,zynqmp - - - description: Xilinx 96boards compatible board zcu100 - items: - - const: xlnx,zynqmp-zcu100-revC - - const: xlnx,zynqmp-zcu100 - - const: xlnx,zynqmp - - - description: Xilinx 96boards compatible board Ultra96 - items: - - const: avnet,ultra96-rev1 - - const: avnet,ultra96 - - const: xlnx,zynqmp-zcu100-revC - - const: xlnx,zynqmp-zcu100 - - const: xlnx,zynqmp - - - description: Xilinx evaluation board zcu102 - items: - - enum: - - xlnx,zynqmp-zcu102-revA - - xlnx,zynqmp-zcu102-revB - - xlnx,zynqmp-zcu102-rev1.0 - - xlnx,zynqmp-zcu102-rev1.1 - - const: xlnx,zynqmp-zcu102 - - const: xlnx,zynqmp - - - description: Xilinx evaluation board zcu104 - items: - - enum: - - xlnx,zynqmp-zcu104-revA - - xlnx,zynqmp-zcu104-revC - - xlnx,zynqmp-zcu104-rev1.0 - - const: xlnx,zynqmp-zcu104 - - const: xlnx,zynqmp - - - description: Xilinx evaluation board zcu106 - items: - - enum: - - xlnx,zynqmp-zcu106-revA - - xlnx,zynqmp-zcu106-rev1.0 - - const: xlnx,zynqmp-zcu106 - - const: xlnx,zynqmp - - - description: Xilinx evaluation board zcu111 - items: - - enum: - - xlnx,zynqmp-zcu111-revA - - xlnx,zynqmp-zcu111-rev1.0 - - const: xlnx,zynqmp-zcu111 - - const: xlnx,zynqmp - - - description: Xilinx Kria SOMs - items: - - const: xlnx,zynqmp-sm-k26-rev1 - - const: xlnx,zynqmp-sm-k26-revB - - const: xlnx,zynqmp-sm-k26-revA - - const: xlnx,zynqmp-sm-k26 - - const: xlnx,zynqmp - - - description: Xilinx Kria SOMs (starter) - items: - - const: xlnx,zynqmp-smk-k26-rev1 - - const: xlnx,zynqmp-smk-k26-revB - - const: xlnx,zynqmp-smk-k26-revA - - const: xlnx,zynqmp-smk-k26 - - const: xlnx,zynqmp - -additionalProperties: true - -... diff --git a/Documentation/devicetree/bindings/auxdisplay/hit,hd44780.yaml b/Documentation/devicetree/bindings/auxdisplay/hit,hd44780.yaml index fde07e4b119dfb..406a922a714e8f 100644 --- a/Documentation/devicetree/bindings/auxdisplay/hit,hd44780.yaml +++ b/Documentation/devicetree/bindings/auxdisplay/hit,hd44780.yaml @@ -113,7 +113,7 @@ examples: hd44780 { compatible = "hit,hd44780"; display-height-chars = <2>; - display-width-chars = <16>; + display-width-chars = <16>; data-gpios = <&pcf8574 4 0>, <&pcf8574 5 0>, <&pcf8574 6 0>, diff --git a/Documentation/devicetree/bindings/cache/qcom,llcc.yaml b/Documentation/devicetree/bindings/cache/qcom,llcc.yaml index 580f9a97ddf782..07ccbda4a0ab54 100644 --- a/Documentation/devicetree/bindings/cache/qcom,llcc.yaml +++ b/Documentation/devicetree/bindings/cache/qcom,llcc.yaml @@ -33,6 +33,8 @@ properties: - qcom,sm8350-llcc - qcom,sm8450-llcc - qcom,sm8550-llcc + - qcom,sm8650-llcc + - qcom,x1e80100-llcc reg: minItems: 2 @@ -64,6 +66,7 @@ allOf: compatible: contains: enum: + - qcom,qdu1000-llcc - qcom,sc7180-llcc - qcom,sm6350-llcc then: @@ -101,9 +104,9 @@ allOf: compatible: contains: enum: - - qcom,qdu1000-llcc - qcom,sc8180x-llcc - qcom,sc8280xp-llcc + - qcom,x1e80100-llcc then: properties: reg: diff --git a/Documentation/devicetree/bindings/cache/sifive,ccache0.yaml b/Documentation/devicetree/bindings/cache/sifive,ccache0.yaml index 8a6a78e1a7ab88..7e8cebe215846c 100644 --- a/Documentation/devicetree/bindings/cache/sifive,ccache0.yaml +++ b/Documentation/devicetree/bindings/cache/sifive,ccache0.yaml @@ -38,7 +38,9 @@ properties: - sifive,fu740-c000-ccache - const: cache - items: - - const: starfive,jh7110-ccache + - enum: + - starfive,jh7100-ccache + - starfive,jh7110-ccache - const: sifive,ccache0 - const: cache - items: @@ -88,6 +90,7 @@ allOf: contains: enum: - sifive,fu740-c000-ccache + - starfive,jh7100-ccache - starfive,jh7110-ccache - microchip,mpfs-ccache @@ -111,6 +114,7 @@ allOf: contains: enum: - sifive,fu740-c000-ccache + - starfive,jh7100-ccache - starfive,jh7110-ccache then: diff --git a/Documentation/devicetree/bindings/clock/baikal,bt1-ccu-pll.yaml b/Documentation/devicetree/bindings/clock/baikal,bt1-ccu-pll.yaml index 624984d51c1064..7f8d98226437e4 100644 --- a/Documentation/devicetree/bindings/clock/baikal,bt1-ccu-pll.yaml +++ b/Documentation/devicetree/bindings/clock/baikal,bt1-ccu-pll.yaml @@ -125,7 +125,7 @@ examples: clk25m: clock-oscillator-25m { compatible = "fixed-clock"; #clock-cells = <0>; - clock-frequency = <25000000>; + clock-frequency = <25000000>; clock-output-names = "clk25m"; }; ... diff --git a/Documentation/devicetree/bindings/clock/brcm,kona-ccu.txt b/Documentation/devicetree/bindings/clock/brcm,kona-ccu.txt deleted file mode 100644 index 8e5a7d868557bc..00000000000000 --- a/Documentation/devicetree/bindings/clock/brcm,kona-ccu.txt +++ /dev/null @@ -1,138 +0,0 @@ -Broadcom Kona Family Clocks - -This binding is associated with Broadcom SoCs having "Kona" style -clock control units (CCUs). A CCU is a clock provider that manages -a set of clock signals. Each CCU is represented by a node in the -device tree. - -This binding uses the common clock binding: - Documentation/devicetree/bindings/clock/clock-bindings.txt - -Required properties: -- compatible - Shall have a value of the form "brcm,--ccu", - where is a Broadcom SoC model number and is - the name of a defined CCU. For example: - "brcm,bcm11351-root-ccu" - The compatible strings used for each supported SoC family - are defined below. -- reg - Shall define the base and range of the address space - containing clock control registers -- #clock-cells - Shall have value <1>. The permitted clock-specifier values - are defined below. -- clock-output-names - Shall be an ordered list of strings defining the names of - the clocks provided by the CCU. - -Device tree example: - - slave_ccu: slave_ccu { - compatible = "brcm,bcm11351-slave-ccu"; - reg = <0x3e011000 0x0f00>; - #clock-cells = <1>; - clock-output-names = "uartb", - "uartb2", - "uartb3", - "uartb4"; - }; - - ref_crystal_clk: ref_crystal { - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <26000000>; - }; - - uart@3e002000 { - compatible = "brcm,bcm11351-dw-apb-uart", "snps,dw-apb-uart"; - reg = <0x3e002000 0x1000>; - clocks = <&slave_ccu BCM281XX_SLAVE_CCU_UARTB3>; - interrupts = ; - reg-shift = <2>; - reg-io-width = <4>; - }; - -BCM281XX family ---------------- -CCU compatible string values for SoCs in the BCM281XX family are: - "brcm,bcm11351-root-ccu" - "brcm,bcm11351-aon-ccu" - "brcm,bcm11351-hub-ccu" - "brcm,bcm11351-master-ccu" - "brcm,bcm11351-slave-ccu" - -The following table defines the set of CCUs and clock specifiers for -BCM281XX family clocks. When a clock consumer references a clocks, -its symbolic specifier (rather than its numeric index value) should -be used. These specifiers are defined in: - "include/dt-bindings/clock/bcm281xx.h" - - CCU Clock Type Index Specifier - --- ----- ---- ----- --------- - root frac_1m peri 0 BCM281XX_ROOT_CCU_FRAC_1M - - aon hub_timer peri 0 BCM281XX_AON_CCU_HUB_TIMER - aon pmu_bsc peri 1 BCM281XX_AON_CCU_PMU_BSC - aon pmu_bsc_var peri 2 BCM281XX_AON_CCU_PMU_BSC_VAR - - hub tmon_1m peri 0 BCM281XX_HUB_CCU_TMON_1M - - master sdio1 peri 0 BCM281XX_MASTER_CCU_SDIO1 - master sdio2 peri 1 BCM281XX_MASTER_CCU_SDIO2 - master sdio3 peri 2 BCM281XX_MASTER_CCU_SDIO3 - master sdio4 peri 3 BCM281XX_MASTER_CCU_SDIO4 - master dmac peri 4 BCM281XX_MASTER_CCU_DMAC - master usb_ic peri 5 BCM281XX_MASTER_CCU_USB_IC - master hsic2_48m peri 6 BCM281XX_MASTER_CCU_HSIC_48M - master hsic2_12m peri 7 BCM281XX_MASTER_CCU_HSIC_12M - - slave uartb peri 0 BCM281XX_SLAVE_CCU_UARTB - slave uartb2 peri 1 BCM281XX_SLAVE_CCU_UARTB2 - slave uartb3 peri 2 BCM281XX_SLAVE_CCU_UARTB3 - slave uartb4 peri 3 BCM281XX_SLAVE_CCU_UARTB4 - slave ssp0 peri 4 BCM281XX_SLAVE_CCU_SSP0 - slave ssp2 peri 5 BCM281XX_SLAVE_CCU_SSP2 - slave bsc1 peri 6 BCM281XX_SLAVE_CCU_BSC1 - slave bsc2 peri 7 BCM281XX_SLAVE_CCU_BSC2 - slave bsc3 peri 8 BCM281XX_SLAVE_CCU_BSC3 - slave pwm peri 9 BCM281XX_SLAVE_CCU_PWM - - -BCM21664 family ---------------- -CCU compatible string values for SoCs in the BCM21664 family are: - "brcm,bcm21664-root-ccu" - "brcm,bcm21664-aon-ccu" - "brcm,bcm21664-master-ccu" - "brcm,bcm21664-slave-ccu" - -The following table defines the set of CCUs and clock specifiers for -BCM21664 family clocks. When a clock consumer references a clocks, -its symbolic specifier (rather than its numeric index value) should -be used. These specifiers are defined in: - "include/dt-bindings/clock/bcm21664.h" - - CCU Clock Type Index Specifier - --- ----- ---- ----- --------- - root frac_1m peri 0 BCM21664_ROOT_CCU_FRAC_1M - - aon hub_timer peri 0 BCM21664_AON_CCU_HUB_TIMER - - master sdio1 peri 0 BCM21664_MASTER_CCU_SDIO1 - master sdio2 peri 1 BCM21664_MASTER_CCU_SDIO2 - master sdio3 peri 2 BCM21664_MASTER_CCU_SDIO3 - master sdio4 peri 3 BCM21664_MASTER_CCU_SDIO4 - master sdio1_sleep peri 4 BCM21664_MASTER_CCU_SDIO1_SLEEP - master sdio2_sleep peri 5 BCM21664_MASTER_CCU_SDIO2_SLEEP - master sdio3_sleep peri 6 BCM21664_MASTER_CCU_SDIO3_SLEEP - master sdio4_sleep peri 7 BCM21664_MASTER_CCU_SDIO4_SLEEP - - slave uartb peri 0 BCM21664_SLAVE_CCU_UARTB - slave uartb2 peri 1 BCM21664_SLAVE_CCU_UARTB2 - slave uartb3 peri 2 BCM21664_SLAVE_CCU_UARTB3 - slave uartb4 peri 3 BCM21664_SLAVE_CCU_UARTB4 - slave bsc1 peri 4 BCM21664_SLAVE_CCU_BSC1 - slave bsc2 peri 5 BCM21664_SLAVE_CCU_BSC2 - slave bsc3 peri 6 BCM21664_SLAVE_CCU_BSC3 - slave bsc4 peri 7 BCM21664_SLAVE_CCU_BSC4 diff --git a/Documentation/devicetree/bindings/clock/brcm,kona-ccu.yaml b/Documentation/devicetree/bindings/clock/brcm,kona-ccu.yaml new file mode 100644 index 00000000000000..e5656950b3bd0a --- /dev/null +++ b/Documentation/devicetree/bindings/clock/brcm,kona-ccu.yaml @@ -0,0 +1,181 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/brcm,kona-ccu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Broadcom Kona family clock control units (CCU) + +maintainers: + - Florian Fainelli + - Ray Jui + - Scott Branden + +description: | + Broadcom "Kona" style clock control unit (CCU) is a clock provider that + manages a set of clock signals. + + All available clock IDs are defined in + - include/dt-bindings/clock/bcm281xx.h for BCM281XX family + - include/dt-bindings/clock/bcm21664.h for BCM21664 family + +properties: + compatible: + enum: + - brcm,bcm11351-aon-ccu + - brcm,bcm11351-hub-ccu + - brcm,bcm11351-master-ccu + - brcm,bcm11351-root-ccu + - brcm,bcm11351-slave-ccu + - brcm,bcm21664-aon-ccu + - brcm,bcm21664-master-ccu + - brcm,bcm21664-root-ccu + - brcm,bcm21664-slave-ccu + + reg: + maxItems: 1 + + '#clock-cells': + const: 1 + + clock-output-names: + minItems: 1 + maxItems: 10 + +required: + - compatible + - reg + - '#clock-cells' + - clock-output-names + +allOf: + - if: + properties: + compatible: + contains: + const: brcm,bcm11351-aon-ccu + then: + properties: + clock-output-names: + items: + - const: hub_timer + - const: pmu_bsc + - const: pmu_bsc_var + - if: + properties: + compatible: + contains: + const: brcm,bcm11351-hub-ccu + then: + properties: + clock-output-names: + const: tmon_1m + - if: + properties: + compatible: + contains: + const: brcm,bcm11351-master-ccu + then: + properties: + clock-output-names: + items: + - const: sdio1 + - const: sdio2 + - const: sdio3 + - const: sdio4 + - const: usb_ic + - const: hsic2_48m + - const: hsic2_12m + - if: + properties: + compatible: + contains: + enum: + - brcm,bcm11351-root-ccu + - brcm,bcm21664-root-ccu + then: + properties: + clock-output-names: + const: frac_1m + - if: + properties: + compatible: + contains: + const: brcm,bcm11351-slave-ccu + then: + properties: + clock-output-names: + items: + - const: uartb + - const: uartb2 + - const: uartb3 + - const: uartb4 + - const: ssp0 + - const: ssp2 + - const: bsc1 + - const: bsc2 + - const: bsc3 + - const: pwm + - if: + properties: + compatible: + contains: + const: brcm,bcm21664-aon-ccu + then: + properties: + clock-output-names: + const: hub_timer + - if: + properties: + compatible: + contains: + const: brcm,bcm21664-master-ccu + then: + properties: + clock-output-names: + items: + - const: sdio1 + - const: sdio2 + - const: sdio3 + - const: sdio4 + - const: sdio1_sleep + - const: sdio2_sleep + - const: sdio3_sleep + - const: sdio4_sleep + - if: + properties: + compatible: + contains: + const: brcm,bcm21664-slave-ccu + then: + properties: + clock-output-names: + items: + - const: uartb + - const: uartb2 + - const: uartb3 + - const: bsc1 + - const: bsc2 + - const: bsc3 + - const: bsc4 + +additionalProperties: false + +examples: + - | + clock-controller@3e011000 { + compatible = "brcm,bcm11351-slave-ccu"; + reg = <0x3e011000 0x0f00>; + #clock-cells = <1>; + clock-output-names = "uartb", + "uartb2", + "uartb3", + "uartb4", + "ssp0", + "ssp2", + "bsc1", + "bsc2", + "bsc3", + "pwm"; + }; +... diff --git a/Documentation/devicetree/bindings/clock/fsl,imx93-anatop.yaml b/Documentation/devicetree/bindings/clock/fsl,imx93-anatop.yaml new file mode 100644 index 00000000000000..8a3b2476419ae1 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/fsl,imx93-anatop.yaml @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/fsl,imx93-anatop.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP i.MX93 ANATOP Clock Module + +maintainers: + - Peng Fan + +description: | + NXP i.MX93 ANATOP module which contains PLL and OSC to Clock Controller + Module. + +properties: + compatible: + items: + - const: fsl,imx93-anatop + + reg: + maxItems: 1 + + '#clock-cells': + const: 1 + +required: + - compatible + - reg + - '#clock-cells' + +additionalProperties: false + +examples: + - | + clock-controller@44480000 { + compatible = "fsl,imx93-anatop"; + reg = <0x44480000 0x2000>; + #clock-cells = <1>; + }; + +... diff --git a/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml b/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml new file mode 100644 index 00000000000000..3eebc03a309be2 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/google,gs101-clock.yaml @@ -0,0 +1,106 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/google,gs101-clock.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Google GS101 SoC clock controller + +maintainers: + - Peter Griffin + +description: | + Google GS101 clock controller is comprised of several CMU units, generating + clocks for different domains. Those CMU units are modeled as separate device + tree nodes, and might depend on each other. The root clock in that clock tree + is OSCCLK (24.576 MHz). That external clock must be defined as a fixed-rate + clock in dts. + + CMU_TOP is a top-level CMU, where all base clocks are prepared using PLLs and + dividers; all other leaf clocks (other CMUs) are usually derived from CMU_TOP. + + Each clock is assigned an identifier and client nodes can use this identifier + to specify the clock which they consume. All clocks available for usage + in clock consumer nodes are defined as preprocessor macros in + 'dt-bindings/clock/gs101.h' header. + +properties: + compatible: + enum: + - google,gs101-cmu-top + - google,gs101-cmu-apm + - google,gs101-cmu-misc + + clocks: + minItems: 1 + maxItems: 2 + + clock-names: + minItems: 1 + maxItems: 2 + + "#clock-cells": + const: 1 + + reg: + maxItems: 1 + +required: + - compatible + - "#clock-cells" + - clocks + - clock-names + - reg + +allOf: + - if: + properties: + compatible: + contains: + enum: + - google,gs101-cmu-top + - google,gs101-cmu-apm + then: + properties: + clocks: + items: + - description: External reference clock (24.576 MHz) + + clock-names: + items: + - const: oscclk + + - if: + properties: + compatible: + contains: + const: google,gs101-cmu-misc + + then: + properties: + clocks: + items: + - description: Misc bus clock (from CMU_TOP) + - description: Misc sss clock (from CMU_TOP) + + clock-names: + items: + - const: dout_cmu_misc_bus + - const: dout_cmu_misc_sss + +additionalProperties: false + +examples: + # Clock controller node for CMU_TOP + - | + #include + + cmu_top: clock-controller@1e080000 { + compatible = "google,gs101-cmu-top"; + reg = <0x1e080000 0x8000>; + #clock-cells = <1>; + clocks = <&ext_24_5m>; + clock-names = "oscclk"; + }; + +... diff --git a/Documentation/devicetree/bindings/clock/hi3620-clock.txt b/Documentation/devicetree/bindings/clock/hi3620-clock.txt deleted file mode 100644 index dad6269f52c5a6..00000000000000 --- a/Documentation/devicetree/bindings/clock/hi3620-clock.txt +++ /dev/null @@ -1,20 +0,0 @@ -* Hisilicon Hi3620 Clock Controller - -The Hi3620 clock controller generates and supplies clock to various -controllers within the Hi3620 SoC. - -Required Properties: - -- compatible: should be one of the following. - - "hisilicon,hi3620-clock" - controller compatible with Hi3620 SoC. - - "hisilicon,hi3620-mmc-clock" - controller specific for Hi3620 mmc. - -- reg: physical base address of the controller and length of memory mapped - region. - -- #clock-cells: should be 1. - -Each clock is assigned an identifier and client nodes use this identifier -to specify the clock which they consume. - -All these identifier could be found in . diff --git a/Documentation/devicetree/bindings/clock/mediatek,apmixedsys.yaml b/Documentation/devicetree/bindings/clock/mediatek,apmixedsys.yaml index 372c1d744bc27b..685535846cbb7f 100644 --- a/Documentation/devicetree/bindings/clock/mediatek,apmixedsys.yaml +++ b/Documentation/devicetree/bindings/clock/mediatek,apmixedsys.yaml @@ -22,6 +22,7 @@ properties: - mediatek,mt7622-apmixedsys - mediatek,mt7981-apmixedsys - mediatek,mt7986-apmixedsys + - mediatek,mt7988-apmixedsys - mediatek,mt8135-apmixedsys - mediatek,mt8173-apmixedsys - mediatek,mt8516-apmixedsys diff --git a/Documentation/devicetree/bindings/clock/mediatek,ethsys.yaml b/Documentation/devicetree/bindings/clock/mediatek,ethsys.yaml new file mode 100644 index 00000000000000..f9cddacc2eae18 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/mediatek,ethsys.yaml @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/mediatek,ethsys.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Mediatek ethsys controller + +description: + The available clocks are defined in dt-bindings/clock/mt*-clk.h. + +maintainers: + - James Liao + +properties: + compatible: + oneOf: + - items: + - enum: + - mediatek,mt2701-ethsys + - mediatek,mt7622-ethsys + - mediatek,mt7629-ethsys + - mediatek,mt7981-ethsys + - mediatek,mt7986-ethsys + - mediatek,mt7988-ethsys + - const: syscon + - items: + - const: mediatek,mt7623-ethsys + - const: mediatek,mt2701-ethsys + - const: syscon + + reg: + maxItems: 1 + + "#clock-cells": + const: 1 + + "#reset-cells": + const: 1 + +required: + - reg + - "#clock-cells" + - "#reset-cells" + +additionalProperties: false + +examples: + - | + clock-controller@1b000000 { + compatible = "mediatek,mt2701-ethsys", "syscon"; + reg = <0x1b000000 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt7988-ethwarp.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt7988-ethwarp.yaml new file mode 100644 index 00000000000000..e32a0251ff6ac2 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/mediatek,mt7988-ethwarp.yaml @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/mediatek,mt7988-ethwarp.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek MT7988 ethwarp Controller + +maintainers: + - Daniel Golle + +description: + The Mediatek MT7988 ethwarp controller provides clocks and resets for the + Ethernet related subsystems found the MT7988 SoC. + The clock values can be found in . + +properties: + compatible: + items: + - const: mediatek,mt7988-ethwarp + + reg: + maxItems: 1 + + '#clock-cells': + const: 1 + + '#reset-cells': + const: 1 + +required: + - compatible + - reg + - '#clock-cells' + - '#reset-cells' + +additionalProperties: false + +examples: + - | + #include + soc { + #address-cells = <2>; + #size-cells = <2>; + + clock-controller@15031000 { + compatible = "mediatek,mt7988-ethwarp"; + reg = <0 0x15031000 0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + }; diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt7988-xfi-pll.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt7988-xfi-pll.yaml new file mode 100644 index 00000000000000..192f1451f0afc3 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/mediatek,mt7988-xfi-pll.yaml @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/mediatek,mt7988-xfi-pll.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek MT7988 XFI PLL Clock Controller + +maintainers: + - Daniel Golle + +description: + The MediaTek XFI PLL controller provides the 156.25MHz clock for the + Ethernet SerDes PHY from the 40MHz top_xtal clock. + +properties: + compatible: + const: mediatek,mt7988-xfi-pll + + reg: + maxItems: 1 + + resets: + maxItems: 1 + + '#clock-cells': + const: 1 + +required: + - compatible + - reg + - resets + - '#clock-cells' + +additionalProperties: false + +examples: + - | + soc { + #address-cells = <2>; + #size-cells = <2>; + clock-controller@11f40000 { + compatible = "mediatek,mt7988-xfi-pll"; + reg = <0 0x11f40000 0 0x1000>; + resets = <&watchdog 16>; + #clock-cells = <1>; + }; + }; diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt8188-clock.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt8188-clock.yaml index d7214d97b2ba48..860570320545dc 100644 --- a/Documentation/devicetree/bindings/clock/mediatek,mt8188-clock.yaml +++ b/Documentation/devicetree/bindings/clock/mediatek,mt8188-clock.yaml @@ -43,8 +43,6 @@ properties: - mediatek,mt8188-vdecsys - mediatek,mt8188-vdecsys-soc - mediatek,mt8188-vencsys - - mediatek,mt8188-vppsys0 - - mediatek,mt8188-vppsys1 - mediatek,mt8188-wpesys - mediatek,mt8188-wpesys-vpp0 diff --git a/Documentation/devicetree/bindings/clock/mediatek,topckgen.yaml b/Documentation/devicetree/bindings/clock/mediatek,topckgen.yaml index 6d087ded7437ab..bdf3b55bd56fd4 100644 --- a/Documentation/devicetree/bindings/clock/mediatek,topckgen.yaml +++ b/Documentation/devicetree/bindings/clock/mediatek,topckgen.yaml @@ -37,6 +37,8 @@ properties: - mediatek,mt7629-topckgen - mediatek,mt7981-topckgen - mediatek,mt7986-topckgen + - mediatek,mt7988-mcusys + - mediatek,mt7988-topckgen - mediatek,mt8167-topckgen - mediatek,mt8183-topckgen - const: syscon diff --git a/Documentation/devicetree/bindings/clock/qcom,a53pll.yaml b/Documentation/devicetree/bindings/clock/qcom,a53pll.yaml index 9436266828afaf..5ca927a8b1d538 100644 --- a/Documentation/devicetree/bindings/clock/qcom,a53pll.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,a53pll.yaml @@ -16,6 +16,7 @@ description: properties: compatible: enum: + - qcom,ipq5018-a53pll - qcom,ipq5332-a53pll - qcom,ipq6018-a53pll - qcom,ipq8074-a53pll diff --git a/Documentation/devicetree/bindings/clock/qcom,camcc-sm8250.yaml b/Documentation/devicetree/bindings/clock/qcom,camcc-sm8250.yaml index 426335a2841c92..3fd3dc1069fb17 100644 --- a/Documentation/devicetree/bindings/clock/qcom,camcc-sm8250.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,camcc-sm8250.yaml @@ -15,6 +15,9 @@ description: | See also:: include/dt-bindings/clock/qcom,camcc-sm8250.h +allOf: + - $ref: qcom,gcc.yaml# + properties: compatible: const: qcom,sm8250-camcc @@ -33,15 +36,6 @@ properties: - const: bi_tcxo_ao - const: sleep_clk - '#clock-cells': - const: 1 - - '#reset-cells': - const: 1 - - '#power-domain-cells': - const: 1 - power-domains: items: - description: MMCX power domain @@ -56,14 +50,10 @@ properties: required: - compatible - - reg - clocks - clock-names - - '#clock-cells' - - '#reset-cells' - - '#power-domain-cells' -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc-ipq6018.yaml b/Documentation/devicetree/bindings/clock/qcom,gcc-ipq6018.yaml new file mode 100644 index 00000000000000..af5d883cfdc86b --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,gcc-ipq6018.yaml @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/qcom,gcc-ipq6018.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Global Clock & Reset Controller on IPQ6018 + +maintainers: + - Stephen Boyd + - Taniya Das + - Robert Marko + +description: | + Qualcomm global clock control module provides the clocks, resets and power + domains on IPQ6018. + + See also:: + include/dt-bindings/clock/qcom,gcc-ipq6018.h + include/dt-bindings/reset/qcom,gcc-ipq6018.h + +allOf: + - $ref: qcom,gcc.yaml# + +properties: + compatible: + const: qcom,gcc-ipq6018 + + clocks: + items: + - description: board XO clock + - description: sleep clock + + clock-names: + items: + - const: xo + - const: sleep_clk + +required: + - compatible + - clocks + - clock-names + +unevaluatedProperties: false + +examples: + - | + clock-controller@1800000 { + compatible = "qcom,gcc-ipq6018"; + reg = <0x01800000 0x80000>; + clocks = <&xo>, <&sleep_clk>; + clock-names = "xo", "sleep_clk"; + #clock-cells = <1>; + #power-domain-cells = <1>; + #reset-cells = <1>; + }; +... diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc-ipq8074.yaml b/Documentation/devicetree/bindings/clock/qcom,gcc-ipq8074.yaml index 52e7831a8d6dca..2d44ddc45aabb2 100644 --- a/Documentation/devicetree/bindings/clock/qcom,gcc-ipq8074.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,gcc-ipq8074.yaml @@ -27,11 +27,15 @@ properties: items: - description: board XO clock - description: sleep clock + - description: Gen3 QMP PCIe PHY PIPE clock + - description: Gen2 QMP PCIe PHY PIPE clock clock-names: items: - const: xo - const: sleep_clk + - const: pcie0_pipe + - const: pcie1_pipe required: - compatible diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc-other.yaml b/Documentation/devicetree/bindings/clock/qcom,gcc-other.yaml index 559fc21435c8dd..7d05f0f63cef2e 100644 --- a/Documentation/devicetree/bindings/clock/qcom,gcc-other.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,gcc-other.yaml @@ -15,8 +15,6 @@ description: | domains. See also:: - include/dt-bindings/clock/qcom,gcc-ipq6018.h - include/dt-bindings/reset/qcom,gcc-ipq6018.h include/dt-bindings/clock/qcom,gcc-msm8953.h include/dt-bindings/clock/qcom,gcc-mdm9607.h @@ -26,7 +24,6 @@ allOf: properties: compatible: enum: - - qcom,gcc-ipq6018 - qcom,gcc-mdm9607 required: diff --git a/Documentation/devicetree/bindings/clock/qcom,qdu1000-ecpricc.yaml b/Documentation/devicetree/bindings/clock/qcom,qdu1000-ecpricc.yaml new file mode 100644 index 00000000000000..fd21df0e76976e --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,qdu1000-ecpricc.yaml @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/qcom,qdu1000-ecpricc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm ECPRI Clock & Reset Controller for QDU1000 and QRU1000 + +maintainers: + - Taniya Das + - Imran Shaik + +description: | + Qualcomm ECPRI Specification V2.0 Common Public Radio Interface clock control + module which supports the clocks, resets on QDU1000 and QRU1000 + + See also:: include/dt-bindings/clock/qcom,qdu1000-ecpricc.h + +properties: + compatible: + enum: + - qcom,qdu1000-ecpricc + + reg: + maxItems: 1 + + clocks: + items: + - description: Board XO source + - description: GPLL0 source from GCC + - description: GPLL1 source from GCC + - description: GPLL2 source from GCC + - description: GPLL3 source from GCC + - description: GPLL4 source from GCC + - description: GPLL5 source from GCC + + '#clock-cells': + const: 1 + + '#reset-cells': + const: 1 + +required: + - compatible + - reg + - clocks + - '#clock-cells' + - '#reset-cells' + +additionalProperties: false + +examples: + - | + #include + #include + clock-controller@280000 { + compatible = "qcom,qdu1000-ecpricc"; + reg = <0x00280000 0x31c00>; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&gcc GCC_ECPRI_CC_GPLL0_CLK_SRC>, + <&gcc GCC_ECPRI_CC_GPLL1_EVEN_CLK_SRC>, + <&gcc GCC_ECPRI_CC_GPLL2_EVEN_CLK_SRC>, + <&gcc GCC_ECPRI_CC_GPLL3_CLK_SRC>, + <&gcc GCC_ECPRI_CC_GPLL4_CLK_SRC>, + <&gcc GCC_ECPRI_CC_GPLL5_EVEN_CLK_SRC>; + #clock-cells = <1>; + #reset-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml b/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml index 4eb5e59f67724c..ca857942ed6c08 100644 --- a/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml @@ -35,6 +35,8 @@ properties: - qcom,sm8350-rpmh-clk - qcom,sm8450-rpmh-clk - qcom,sm8550-rpmh-clk + - qcom,sm8650-rpmh-clk + - qcom,x1e80100-rpmh-clk clocks: maxItems: 1 diff --git a/Documentation/devicetree/bindings/clock/qcom,sc7180-camcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sc7180-camcc.yaml index 2dfc2a4f191826..c7fe6400ea13b1 100644 --- a/Documentation/devicetree/bindings/clock/qcom,sc7180-camcc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,sc7180-camcc.yaml @@ -15,6 +15,9 @@ description: | See also:: include/dt-bindings/clock/qcom,camcc-sc7180.h +allOf: + - $ref: qcom,gcc.yaml# + properties: compatible: const: qcom,sc7180-camcc @@ -31,28 +34,15 @@ properties: - const: iface - const: xo - '#clock-cells': - const: 1 - - '#reset-cells': - const: 1 - - '#power-domain-cells': - const: 1 - reg: maxItems: 1 required: - compatible - - reg - clocks - clock-names - - '#clock-cells' - - '#reset-cells' - - '#power-domain-cells' -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/clock/qcom,sc7280-camcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sc7280-camcc.yaml index 01feef1cab0a0e..dcef8de3a905ad 100644 --- a/Documentation/devicetree/bindings/clock/qcom,sc7280-camcc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,sc7280-camcc.yaml @@ -15,6 +15,9 @@ description: | See also:: include/dt-bindings/clock/qcom,camcc-sc7280.h +allOf: + - $ref: qcom,gcc.yaml# + properties: compatible: const: qcom,sc7280-camcc @@ -31,28 +34,15 @@ properties: - const: bi_tcxo_ao - const: sleep_clk - '#clock-cells': - const: 1 - - '#reset-cells': - const: 1 - - '#power-domain-cells': - const: 1 - reg: maxItems: 1 required: - compatible - - reg - clocks - clock-names - - '#clock-cells' - - '#reset-cells' - - '#power-domain-cells' -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/clock/qcom,sdm845-camcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sdm845-camcc.yaml index 91d1f7918037b0..810b852ae3719d 100644 --- a/Documentation/devicetree/bindings/clock/qcom,sdm845-camcc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,sdm845-camcc.yaml @@ -15,6 +15,9 @@ description: | See also:: include/dt-bindings/clock/qcom,camcc-sm845.h +allOf: + - $ref: qcom,gcc.yaml# + properties: compatible: const: qcom,sdm845-camcc @@ -27,28 +30,15 @@ properties: items: - const: bi_tcxo - '#clock-cells': - const: 1 - - '#reset-cells': - const: 1 - - '#power-domain-cells': - const: 1 - reg: maxItems: 1 required: - compatible - - reg - clocks - clock-names - - '#clock-cells' - - '#reset-cells' - - '#power-domain-cells' -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml index dc3c18e4ead728..48986460f9947d 100644 --- a/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml @@ -16,10 +16,15 @@ description: | See also:: include/dt-bindings/clock/qcom,sm8450-camcc.h include/dt-bindings/clock/qcom,sm8550-camcc.h + include/dt-bindings/clock/qcom,sc8280xp-camcc.h + +allOf: + - $ref: qcom,gcc.yaml# properties: compatible: enum: + - qcom,sc8280xp-camcc - qcom,sm8450-camcc - qcom,sm8550-camcc @@ -40,29 +45,16 @@ properties: description: A phandle to an OPP node describing required MMCX performance point. - '#clock-cells': - const: 1 - - '#reset-cells': - const: 1 - - '#power-domain-cells': - const: 1 - reg: maxItems: 1 required: - compatible - - reg - clocks - power-domains - required-opps - - '#clock-cells' - - '#reset-cells' - - '#power-domain-cells' -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8450-gpucc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8450-gpucc.yaml index 2320be920a5f76..1a384e8532a59c 100644 --- a/Documentation/devicetree/bindings/clock/qcom,sm8450-gpucc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,sm8450-gpucc.yaml @@ -17,12 +17,14 @@ description: | include/dt-bindings/clock/qcom,sm8450-gpucc.h include/dt-bindings/clock/qcom,sm8550-gpucc.h include/dt-bindings/reset/qcom,sm8450-gpucc.h + include/dt-bindings/reset/qcom,sm8650-gpucc.h properties: compatible: enum: - qcom,sm8450-gpucc - qcom,sm8550-gpucc + - qcom,sm8650-gpucc clocks: items: diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml index 1bf1a41fd89c2b..af16b05eac96e4 100644 --- a/Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml @@ -13,12 +13,16 @@ description: | Qualcomm TCSR clock control module provides the clocks, resets and power domains on SM8550 - See also:: include/dt-bindings/clock/qcom,sm8550-tcsr.h + See also: + - include/dt-bindings/clock/qcom,sm8550-tcsr.h + - include/dt-bindings/clock/qcom,sm8650-tcsr.h properties: compatible: items: - - const: qcom,sm8550-tcsr + - enum: + - qcom,sm8550-tcsr + - qcom,sm8650-tcsr - const: syscon clocks: diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8650-dispcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8650-dispcc.yaml new file mode 100644 index 00000000000000..5e0c45c380f5d1 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,sm8650-dispcc.yaml @@ -0,0 +1,106 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/qcom,sm8650-dispcc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Display Clock & Reset Controller for SM8650 + +maintainers: + - Bjorn Andersson + - Neil Armstrong + +description: | + Qualcomm display clock control module provides the clocks, resets and power + domains on SM8650. + + See also:: include/dt-bindings/clock/qcom,sm8650-dispcc.h + +properties: + compatible: + enum: + - qcom,sm8650-dispcc + + clocks: + items: + - description: Board XO source + - description: Board Always On XO source + - description: Display's AHB clock + - description: sleep clock + - description: Byte clock from DSI PHY0 + - description: Pixel clock from DSI PHY0 + - description: Byte clock from DSI PHY1 + - description: Pixel clock from DSI PHY1 + - description: Link clock from DP PHY0 + - description: VCO DIV clock from DP PHY0 + - description: Link clock from DP PHY1 + - description: VCO DIV clock from DP PHY1 + - description: Link clock from DP PHY2 + - description: VCO DIV clock from DP PHY2 + - description: Link clock from DP PHY3 + - description: VCO DIV clock from DP PHY3 + + '#clock-cells': + const: 1 + + '#reset-cells': + const: 1 + + '#power-domain-cells': + const: 1 + + reg: + maxItems: 1 + + power-domains: + description: + A phandle and PM domain specifier for the MMCX power domain. + maxItems: 1 + + required-opps: + description: + A phandle to an OPP node describing required MMCX performance point. + maxItems: 1 + +required: + - compatible + - reg + - clocks + - '#clock-cells' + - '#reset-cells' + - '#power-domain-cells' + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + clock-controller@af00000 { + compatible = "qcom,sm8650-dispcc"; + reg = <0x0af00000 0x10000>; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&rpmhcc RPMH_CXO_CLK_A>, + <&gcc GCC_DISP_AHB_CLK>, + <&sleep_clk>, + <&dsi0_phy 0>, + <&dsi0_phy 1>, + <&dsi1_phy 0>, + <&dsi1_phy 1>, + <&dp0_phy 0>, + <&dp0_phy 1>, + <&dp1_phy 0>, + <&dp1_phy 1>, + <&dp2_phy 0>, + <&dp2_phy 1>, + <&dp3_phy 0>, + <&dp3_phy 1>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + power-domains = <&rpmhpd RPMHPD_MMCX>; + required-opps = <&rpmhpd_opp_low_svs>; + }; +... diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8650-gcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8650-gcc.yaml new file mode 100644 index 00000000000000..b54761cc8674b3 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,sm8650-gcc.yaml @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/qcom,sm8650-gcc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Global Clock & Reset Controller on SM8650 + +maintainers: + - Bjorn Andersson + +description: | + Qualcomm global clock control module provides the clocks, resets and power + domains on SM8650 + + See also:: include/dt-bindings/clock/qcom,sm8650-gcc.h + +properties: + compatible: + const: qcom,sm8650-gcc + + clocks: + items: + - description: Board XO source + - description: Board Always On XO source + - description: Sleep clock source + - description: PCIE 0 Pipe clock source + - description: PCIE 1 Pipe clock source + - description: PCIE 1 Phy Auxiliary clock source + - description: UFS Phy Rx symbol 0 clock source + - description: UFS Phy Rx symbol 1 clock source + - description: UFS Phy Tx symbol 0 clock source + - description: USB3 Phy wrapper pipe clock source + +required: + - compatible + - clocks + +allOf: + - $ref: qcom,gcc.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + clock-controller@100000 { + compatible = "qcom,sm8650-gcc"; + reg = <0x00100000 0x001f4200>; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&rpmhcc RPMH_CXO_CLK_A>, + <&sleep_clk>, + <&pcie0_phy>, + <&pcie1_phy>, + <&pcie_1_phy_aux_clk>, + <&ufs_mem_phy 0>, + <&ufs_mem_phy 1>, + <&ufs_mem_phy 2>, + <&usb_1_qmpphy>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; + +... diff --git a/Documentation/devicetree/bindings/clock/qcom,x1e80100-gcc.yaml b/Documentation/devicetree/bindings/clock/qcom,x1e80100-gcc.yaml new file mode 100644 index 00000000000000..14a796dbf8bc62 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/qcom,x1e80100-gcc.yaml @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/qcom,x1e80100-gcc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Global Clock & Reset Controller on X1E80100 + +maintainers: + - Rajendra Nayak + +description: | + Qualcomm global clock control module provides the clocks, resets and power + domains on X1E80100 + + See also:: include/dt-bindings/clock/qcom,x1e80100-gcc.h + +properties: + compatible: + const: qcom,x1e80100-gcc + + clocks: + items: + - description: Board XO source + - description: Sleep clock source + - description: PCIe 3 pipe clock + - description: PCIe 4 pipe clock + - description: PCIe 5 pipe clock + - description: PCIe 6a pipe clock + - description: PCIe 6b pipe clock + - description: USB QMP Phy 0 clock source + - description: USB QMP Phy 1 clock source + - description: USB QMP Phy 2 clock source + + power-domains: + description: + A phandle and PM domain specifier for the CX power domain. + maxItems: 1 + +required: + - compatible + - clocks + - power-domains + +allOf: + - $ref: qcom,gcc.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + clock-controller@100000 { + compatible = "qcom,x1e80100-gcc"; + reg = <0x00100000 0x200000>; + clocks = <&bi_tcxo_div2>, + <&sleep_clk>, + <&pcie3_phy>, + <&pcie4_phy>, + <&pcie5_phy>, + <&pcie6a_phy>, + <&pcie6b_phy>, + <&usb_1_ss0_qmpphy 0>, + <&usb_1_ss1_qmpphy 1>, + <&usb_1_ss2_qmpphy 2>; + power-domains = <&rpmhpd RPMHPD_CX>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; + +... diff --git a/Documentation/devicetree/bindings/clock/renesas,9series.yaml b/Documentation/devicetree/bindings/clock/renesas,9series.yaml index 3afdebdb52ad4b..af6319697b1c04 100644 --- a/Documentation/devicetree/bindings/clock/renesas,9series.yaml +++ b/Documentation/devicetree/bindings/clock/renesas,9series.yaml @@ -21,6 +21,15 @@ description: | 1 -- DIF1 2 -- DIF2 3 -- DIF3 + - 9FGV0841: + 0 -- DIF0 + 1 -- DIF1 + 2 -- DIF2 + 3 -- DIF3 + 4 -- DIF4 + 5 -- DIF5 + 6 -- DIF6 + 7 -- DIF7 maintainers: - Marek Vasut @@ -30,6 +39,7 @@ properties: enum: - renesas,9fgv0241 - renesas,9fgv0441 + - renesas,9fgv0841 reg: description: I2C device address diff --git a/Documentation/devicetree/bindings/clock/silabs,si5351.txt b/Documentation/devicetree/bindings/clock/silabs,si5351.txt deleted file mode 100644 index bfda6af76beeb5..00000000000000 --- a/Documentation/devicetree/bindings/clock/silabs,si5351.txt +++ /dev/null @@ -1,126 +0,0 @@ -Binding for Silicon Labs Si5351a/b/c programmable i2c clock generator. - -Reference -[1] Si5351A/B/C Data Sheet - https://www.skyworksinc.com/-/media/Skyworks/SL/documents/public/data-sheets/Si5351-B.pdf - -The Si5351a/b/c are programmable i2c clock generators with up to 8 output -clocks. Si5351a also has a reduced pin-count package (MSOP10) where only -3 output clocks are accessible. The internal structure of the clock -generators can be found in [1]. - -==I2C device node== - -Required properties: -- compatible: shall be one of the following: - "silabs,si5351a" - Si5351a, QFN20 package - "silabs,si5351a-msop" - Si5351a, MSOP10 package - "silabs,si5351b" - Si5351b, QFN20 package - "silabs,si5351c" - Si5351c, QFN20 package -- reg: i2c device address, shall be 0x60 or 0x61. -- #clock-cells: from common clock binding; shall be set to 1. -- clocks: from common clock binding; list of parent clock - handles, shall be xtal reference clock or xtal and clkin for - si5351c only. Corresponding clock input names are "xtal" and - "clkin" respectively. -- #address-cells: shall be set to 1. -- #size-cells: shall be set to 0. - -Optional properties: -- silabs,pll-source: pair of (number, source) for each pll. Allows - to overwrite clock source of pll A (number=0) or B (number=1). - -==Child nodes== - -Each of the clock outputs can be overwritten individually by -using a child node to the I2C device node. If a child node for a clock -output is not set, the eeprom configuration is not overwritten. - -Required child node properties: -- reg: number of clock output. - -Optional child node properties: -- silabs,clock-source: source clock of the output divider stage N, shall be - 0 = multisynth N - 1 = multisynth 0 for output clocks 0-3, else multisynth4 - 2 = xtal - 3 = clkin (si5351c only) -- silabs,drive-strength: output drive strength in mA, shall be one of {2,4,6,8}. -- silabs,multisynth-source: source pll A(0) or B(1) of corresponding multisynth - divider. -- silabs,pll-master: boolean, multisynth can change pll frequency. -- silabs,pll-reset: boolean, clock output can reset its pll. -- silabs,disable-state : clock output disable state, shall be - 0 = clock output is driven LOW when disabled - 1 = clock output is driven HIGH when disabled - 2 = clock output is FLOATING (HIGH-Z) when disabled - 3 = clock output is NEVER disabled - -==Example== - -/* 25MHz reference crystal */ -ref25: ref25M { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <25000000>; -}; - -i2c-master-node { - - /* Si5351a msop10 i2c clock generator */ - si5351a: clock-generator@60 { - compatible = "silabs,si5351a-msop"; - reg = <0x60>; - #address-cells = <1>; - #size-cells = <0>; - #clock-cells = <1>; - - /* connect xtal input to 25MHz reference */ - clocks = <&ref25>; - clock-names = "xtal"; - - /* connect xtal input as source of pll0 and pll1 */ - silabs,pll-source = <0 0>, <1 0>; - - /* - * overwrite clkout0 configuration with: - * - 8mA output drive strength - * - pll0 as clock source of multisynth0 - * - multisynth0 as clock source of output divider - * - multisynth0 can change pll0 - * - set initial clock frequency of 74.25MHz - */ - clkout0 { - reg = <0>; - silabs,drive-strength = <8>; - silabs,multisynth-source = <0>; - silabs,clock-source = <0>; - silabs,pll-master; - clock-frequency = <74250000>; - }; - - /* - * overwrite clkout1 configuration with: - * - 4mA output drive strength - * - pll1 as clock source of multisynth1 - * - multisynth1 as clock source of output divider - * - multisynth1 can change pll1 - */ - clkout1 { - reg = <1>; - silabs,drive-strength = <4>; - silabs,multisynth-source = <1>; - silabs,clock-source = <0>; - pll-master; - }; - - /* - * overwrite clkout2 configuration with: - * - xtal as clock source of output divider - */ - clkout2 { - reg = <2>; - silabs,clock-source = <2>; - }; - }; -}; diff --git a/Documentation/devicetree/bindings/clock/silabs,si5351.yaml b/Documentation/devicetree/bindings/clock/silabs,si5351.yaml new file mode 100644 index 00000000000000..d3e0ec29993b12 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/silabs,si5351.yaml @@ -0,0 +1,265 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/silabs,si5351.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Silicon Labs Si5351A/B/C programmable I2C clock generators + +description: | + The Silicon Labs Si5351A/B/C are programmable I2C clock generators with up to + 8 outputs. Si5351A also has a reduced pin-count package (10-MSOP) where only 3 + output clocks are accessible. The internal structure of the clock generators + can be found in [1]. + + [1] Si5351A/B/C Data Sheet + https://www.skyworksinc.com/-/media/Skyworks/SL/documents/public/data-sheets/Si5351-B.pdf + +maintainers: + - Alvin Šipraga + +properties: + compatible: + enum: + - silabs,si5351a # Si5351A, 20-QFN package + - silabs,si5351a-msop # Si5351A, 10-MSOP package + - silabs,si5351b # Si5351B, 20-QFN package + - silabs,si5351c # Si5351C, 20-QFN package + + reg: + enum: + - 0x60 + - 0x61 + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + "#clock-cells": + const: 1 + + clocks: + minItems: 1 + maxItems: 2 + + clock-names: + minItems: 1 + items: + - const: xtal + - const: clkin + + silabs,pll-source: + $ref: /schemas/types.yaml#/definitions/uint32-matrix + description: | + A list of cell pairs containing a PLL index and its source. Allows to + overwrite clock source of the internal PLLs. + items: + items: + - description: PLL A (0) or PLL B (1) + enum: [ 0, 1 ] + - description: PLL source, XTAL (0) or CLKIN (1, Si5351C only). + enum: [ 0, 1 ] + + silabs,pll-reset-mode: + $ref: /schemas/types.yaml#/definitions/uint32-matrix + minItems: 1 + maxItems: 2 + description: A list of cell pairs containing a PLL index and its reset mode. + items: + items: + - description: PLL A (0) or PLL B (1) + enum: [ 0, 1 ] + - description: | + Reset mode for the PLL. Mode can be one of: + + 0 - reset whenever PLL rate is adjusted (default mode) + 1 - do not reset when PLL rate is adjusted + + In mode 1, the PLL is only reset if the silabs,pll-reset is + specified in one of the clock output child nodes that also sources + the PLL. This mode may be preferable if output clocks are expected + to be adjusted without glitches. + enum: [ 0, 1 ] + +patternProperties: + "^clkout@[0-7]$": + type: object + + additionalProperties: false + + properties: + reg: + description: Clock output number. + + clock-frequency: true + + silabs,clock-source: + $ref: /schemas/types.yaml#/definitions/uint32 + description: | + Source clock of the this output's divider stage. + + 0 - use multisynth N for this output, where N is the output number + 1 - use either multisynth 0 (if output number is 0-3) or multisynth 4 + (otherwise) for this output + 2 - use XTAL for this output + 3 - use CLKIN for this output (Si5351C only) + + silabs,drive-strength: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [ 2, 4, 6, 8 ] + description: Output drive strength in mA. + + silabs,multisynth-source: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [ 0, 1 ] + description: + Source PLL A (0) or B (1) for the corresponding multisynth divider. + + silabs,pll-master: + type: boolean + description: | + The frequency of the source PLL is allowed to be changed by the + multisynth when setting the rate of this clock output. + + silabs,pll-reset: + type: boolean + description: Reset the source PLL when enabling this clock output. + + silabs,disable-state: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [ 0, 1, 2, 3 ] + description: | + Clock output disable state. The state can be one of: + + 0 - clock output is driven LOW when disabled + 1 - clock output is driven HIGH when disabled + 2 - clock output is FLOATING (HIGH-Z) when disabled + 3 - clock output is never disabled + + allOf: + - if: + properties: + compatible: + contains: + const: silabs,si5351a-msop + then: + properties: + reg: + maximum: 2 + else: + properties: + reg: + maximum: 7 + + - if: + properties: + compatible: + contains: + const: silabs,si5351c + then: + properties: + silabs,clock-source: + enum: [ 0, 1, 2, 3 ] + else: + properties: + silabs,clock-source: + enum: [ 0, 1, 2 ] + + required: + - reg + +allOf: + - if: + properties: + compatible: + contains: + enum: + - silabs,si5351a + - silabs,si5351a-msop + - silabs,si5351b + then: + properties: + clocks: + maxItems: 1 + clock-names: + maxItems: 1 + +required: + - reg + - "#address-cells" + - "#size-cells" + - "#clock-cells" + - clocks + - clock-names + +unevaluatedProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + clock-generator@60 { + compatible = "silabs,si5351a-msop"; + reg = <0x60>; + #address-cells = <1>; + #size-cells = <0>; + #clock-cells = <1>; + + /* Connect XTAL input to 25MHz reference */ + clocks = <&ref25>; + clock-names = "xtal"; + + /* Use XTAL input as source of PLL0 and PLL1 */ + silabs,pll-source = <0 0>, <1 0>; + + /* Don't reset PLL1 on rate adjustment */ + silabs,pll-reset-mode = <1 1>; + + /* + * Overwrite CLK0 configuration with: + * - 8 mA output drive strength + * - PLL0 as clock source of multisynth 0 + * - Multisynth 0 as clock source of output divider + * - Multisynth 0 can change PLL0 + * - Set initial clock frequency of 74.25MHz + */ + clkout@0 { + reg = <0>; + silabs,drive-strength = <8>; + silabs,multisynth-source = <0>; + silabs,clock-source = <0>; + silabs,pll-master; + clock-frequency = <74250000>; + }; + + /* + * Overwrite CLK1 configuration with: + * - 4 mA output drive strength + * - PLL1 as clock source of multisynth 1 + * - Multisynth 1 as clock source of output divider + * - Multisynth 1 can change PLL1 + * - Reset PLL1 when enabling this clock output + */ + clkout@1 { + reg = <1>; + silabs,drive-strength = <4>; + silabs,multisynth-source = <1>; + silabs,clock-source = <0>; + silabs,pll-master; + silabs,pll-reset; + }; + + /* + * Overwrite CLK2 configuration with: + * - XTAL as clock source of output divider + */ + clkout@2 { + reg = <2>; + silabs,clock-source = <2>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/clock/sophgo,cv1800-clk.yaml b/Documentation/devicetree/bindings/clock/sophgo,cv1800-clk.yaml new file mode 100644 index 00000000000000..c1dc24673c0d76 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/sophgo,cv1800-clk.yaml @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/sophgo,cv1800-clk.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Sophgo CV1800 Series Clock Controller + +maintainers: + - Inochi Amaoto + +properties: + compatible: + enum: + - sophgo,cv1800-clk + - sophgo,cv1810-clk + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + "#clock-cells": + const: 1 + description: + See for valid indices. + +required: + - compatible + - reg + - clocks + - "#clock-cells" + +additionalProperties: false + +examples: + - | + clock-controller@3002000 { + compatible = "sophgo,cv1800-clk"; + reg = <0x03002000 0x1000>; + clocks = <&osc>; + #clock-cells = <1>; + }; + +... diff --git a/Documentation/devicetree/bindings/clock/st,stm32mp25-rcc.yaml b/Documentation/devicetree/bindings/clock/st,stm32mp25-rcc.yaml new file mode 100644 index 00000000000000..7732e79a42b905 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/st,stm32mp25-rcc.yaml @@ -0,0 +1,76 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/st,stm32mp25-rcc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: STM32MP25 Reset Clock Controller + +maintainers: + - Gabriel Fernandez + +description: | + The RCC hardware block is both a reset and a clock controller. + RCC makes also power management (resume/supend). + + See also:: + include/dt-bindings/clock/st,stm32mp25-rcc.h + include/dt-bindings/reset/st,stm32mp25-rcc.h + +properties: + compatible: + enum: + - st,stm32mp25-rcc + + reg: + maxItems: 1 + + '#clock-cells': + const: 1 + + '#reset-cells': + const: 1 + + clocks: + items: + - description: CK_SCMI_HSE High Speed External oscillator (8 to 48 MHz) + - description: CK_SCMI_HSI High Speed Internal oscillator (~ 64 MHz) + - description: CK_SCMI_MSI Low Power Internal oscillator (~ 4 MHz or ~ 16 MHz) + - description: CK_SCMI_LSE Low Speed External oscillator (32 KHz) + - description: CK_SCMI_LSI Low Speed Internal oscillator (~ 32 KHz) + + clock-names: + items: + - const: hse + - const: hsi + - const: msi + - const: lse + - const: lsi + +required: + - compatible + - reg + - '#clock-cells' + - '#reset-cells' + - clocks + - clock-names + +additionalProperties: false + +examples: + - | + #include + + rcc: clock-controller@44200000 { + compatible = "st,stm32mp25-rcc"; + reg = <0x44200000 0x10000>; + #clock-cells = <1>; + #reset-cells = <1>; + clock-names = "hse", "hsi", "msi", "lse", "lsi"; + clocks = <&scmi_clk CK_SCMI_HSE>, + <&scmi_clk CK_SCMI_HSI>, + <&scmi_clk CK_SCMI_MSI>, + <&scmi_clk CK_SCMI_LSE>, + <&scmi_clk CK_SCMI_LSI>; + }; +... diff --git a/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml b/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml index 02bd556bd91a66..9d5324dc1027a3 100644 --- a/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml +++ b/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml @@ -20,6 +20,7 @@ properties: - xlnx,clocking-wizard - xlnx,clocking-wizard-v5.2 - xlnx,clocking-wizard-v6.0 + - xlnx,versal-clk-wizard reg: diff --git a/Documentation/devicetree/bindings/clock/xlnx,versal-clk.yaml b/Documentation/devicetree/bindings/clock/xlnx,versal-clk.yaml index 1ba687d433b123..bef109d163a820 100644 --- a/Documentation/devicetree/bindings/clock/xlnx,versal-clk.yaml +++ b/Documentation/devicetree/bindings/clock/xlnx,versal-clk.yaml @@ -31,11 +31,11 @@ properties: clocks: description: List of clock specifiers which are external input clocks to the given clock controller. - minItems: 3 + minItems: 2 maxItems: 8 clock-names: - minItems: 3 + minItems: 2 maxItems: 8 required: @@ -59,15 +59,34 @@ allOf: clocks: items: - description: reference clock - - description: alternate reference clock - description: alternate reference clock for programmable logic clock-names: items: - const: ref - - const: alt_ref - const: pl_alt_ref + - if: + properties: + compatible: + contains: + enum: + - xlnx,versal-net-clk + + then: + properties: + clocks: + items: + - description: reference clock + - description: alternate reference clock for programmable logic + - description: alternate reference clock + + clock-names: + items: + - const: ref + - const: pl_alt_ref + - const: alt_ref + - if: properties: compatible: @@ -110,8 +129,8 @@ examples: versal_clk: clock-controller { #clock-cells = <1>; compatible = "xlnx,versal-clk"; - clocks = <&ref>, <&alt_ref>, <&pl_alt_ref>; - clock-names = "ref", "alt_ref", "pl_alt_ref"; + clocks = <&ref>, <&pl_alt_ref>; + clock-names = "ref", "pl_alt_ref"; }; }; }; diff --git a/Documentation/devicetree/bindings/connector/usb-connector.yaml b/Documentation/devicetree/bindings/connector/usb-connector.yaml index 7c8a3e8430d306..fb216ce68bb357 100644 --- a/Documentation/devicetree/bindings/connector/usb-connector.yaml +++ b/Documentation/devicetree/bindings/connector/usb-connector.yaml @@ -66,7 +66,6 @@ properties: Particularly, if use an output GPIO to control a VBUS regulator, should model it as a regulator. See bindings/regulator/fixed-regulator.yaml - # The following are optional properties for "usb-c-connector". power-role: description: Determines the power role that the Type C connector will support. "dual" refers to Dual Role Port (DRP). @@ -119,30 +118,6 @@ properties: # The following are optional properties for "usb-c-connector" with power # delivery support. - source-pdos: - description: An array of u32 with each entry providing supported power - source data object(PDO), the detailed bit definitions of PDO can be found - in "Universal Serial Bus Power Delivery Specification" chapter 6.4.1.2 - Source_Capabilities Message, the order of each entry(PDO) should follow - the PD spec chapter 6.4.1. Required for power source and power dual role. - User can specify the source PDO array via PDO_FIXED/BATT/VAR/PPS_APDO() - defined in dt-bindings/usb/pd.h. - minItems: 1 - maxItems: 7 - $ref: /schemas/types.yaml#/definitions/uint32-array - - sink-pdos: - description: An array of u32 with each entry providing supported power sink - data object(PDO), the detailed bit definitions of PDO can be found in - "Universal Serial Bus Power Delivery Specification" chapter 6.4.1.3 - Sink Capabilities Message, the order of each entry(PDO) should follow the - PD spec chapter 6.4.1. Required for power sink and power dual role. User - can specify the sink PDO array via PDO_FIXED/BATT/VAR/PPS_APDO() defined - in dt-bindings/usb/pd.h. - minItems: 1 - maxItems: 7 - $ref: /schemas/types.yaml#/definitions/uint32-array - sink-vdos: description: An array of u32 with each entry, a Vendor Defined Message Object (VDO), providing additional information corresponding to the product, the detailed bit @@ -166,10 +141,43 @@ properties: maxItems: 6 $ref: /schemas/types.yaml#/definitions/uint32-array - op-sink-microwatt: - description: Sink required operating power in microwatt, if source can't - offer the power, Capability Mismatch is set. Required for power sink and - power dual role. + accessory-mode-audio: + type: boolean + description: Whether the device supports Audio Adapter Accessory Mode. This + is only necessary if there are no other means to discover supported + alternative modes (e.g. through the UCSI firmware interface). + + accessory-mode-debug: + type: boolean + description: Whether the device supports Debug Accessory Mode. This + is only necessary if there are no other means to discover supported + alternative modes (e.g. through the UCSI firmware interface). + + altmodes: + type: object + description: List of Alternative Modes supported by the schematics on the + particular device. This is only necessary if there are no other means to + discover supported alternative modes (e.g. through the UCSI firmware + interface). + + additionalProperties: false + + patternProperties: + "^(displayport)$": + type: object + description: + A single USB-C Alternative Mode as supported by the USB-C connector logic. + + additionalProperties: false + + properties: + svid: + $ref: /schemas/types.yaml#/definitions/uint16 + description: Unique value assigned by USB-IF to the Vendor / AltMode. + enum: [ 0xff01 ] + vdo: + $ref: /schemas/types.yaml#/definitions/uint32 + description: VDO returned by Discover Modes USB PD command. port: $ref: /schemas/graph.yaml#/properties/port @@ -231,6 +239,20 @@ properties: SNK_READY for non-pd link. type: boolean + capabilities: + description: A child node to contain all the selectable USB Power Delivery capabilities. + type: object + + patternProperties: + "^caps-[0-9]+$": + description: Child nodes under "capabilities" node. Each node contains a selectable USB + Power Delivery capability. + type: object + $ref: "#/$defs/capabilities" + unevaluatedProperties: false + + additionalProperties: false + dependencies: sink-vdos-v1: [ sink-vdos ] sink-vdos: [ sink-vdos-v1 ] @@ -238,7 +260,42 @@ dependencies: required: - compatible +$defs: + capabilities: + type: object + + properties: + source-pdos: + description: An array of u32 with each entry providing supported power + source data object(PDO), the detailed bit definitions of PDO can be found + in "Universal Serial Bus Power Delivery Specification" chapter 6.4.1.2 + Source_Capabilities Message, the order of each entry(PDO) should follow + the PD spec chapter 6.4.1. Required for power source and power dual role. + User can specify the source PDO array via PDO_FIXED/BATT/VAR/PPS_APDO() + defined in dt-bindings/usb/pd.h. + minItems: 1 + maxItems: 7 + $ref: /schemas/types.yaml#/definitions/uint32-array + + sink-pdos: + description: An array of u32 with each entry providing supported power sink + data object(PDO), the detailed bit definitions of PDO can be found in + "Universal Serial Bus Power Delivery Specification" chapter 6.4.1.3 + Sink Capabilities Message, the order of each entry(PDO) should follow the + PD spec chapter 6.4.1. Required for power sink and power dual role. User + can specify the sink PDO array via PDO_FIXED/BATT/VAR/PPS_APDO() defined + in dt-bindings/usb/pd.h. + minItems: 1 + maxItems: 7 + $ref: /schemas/types.yaml#/definitions/uint32-array + + op-sink-microwatt: + description: Sink required operating power in microwatt, if source can't + offer the power, Capability Mismatch is set. Required for power sink and + power dual role. + allOf: + - $ref: "#/$defs/capabilities" - if: properties: compatible: @@ -267,7 +324,7 @@ anyOf: - typec-power-opmode - new-source-frs-typec-current -additionalProperties: false +unevaluatedProperties: false examples: # Micro-USB connector with HS lines routed via controller (MUIC). @@ -289,6 +346,13 @@ examples: compatible = "usb-c-connector"; label = "USB-C"; + altmodes { + displayport { + svid = /bits/ 16 <0xff01>; + vdo = <0x00001c46>; + }; + }; + ports { #address-cells = <1>; #size-cells = <0>; diff --git a/Documentation/devicetree/bindings/cpu/idle-states.yaml b/Documentation/devicetree/bindings/cpu/idle-states.yaml index b3a5356f9916e9..239480ef7c30d3 100644 --- a/Documentation/devicetree/bindings/cpu/idle-states.yaml +++ b/Documentation/devicetree/bindings/cpu/idle-states.yaml @@ -243,7 +243,64 @@ description: |+ just supports idle_standby, an idle-states node is not required. =========================================== - 6 - References + 6 - Qualcomm specific STATES + =========================================== + + Idle states have different enter/exit latency and residency values. + The idle states supported by the QCOM SoC are defined as - + + * Standby + * Retention + * Standalone Power Collapse (Standalone PC or SPC) + * Power Collapse (PC) + + Standby: Standby does a little more in addition to architectural clock gating. + When the WFI instruction is executed the ARM core would gate its internal + clocks. In addition to gating the clocks, QCOM cpus use this instruction as a + trigger to execute the SPM state machine. The SPM state machine waits for the + interrupt to trigger the core back in to active. This triggers the cache + hierarchy to enter standby states, when all cpus are idle. An interrupt brings + the SPM state machine out of its wait, the next step is to ensure that the + cache hierarchy is also out of standby, and then the cpu is allowed to resume + execution. This state is defined as a generic ARM WFI state by the ARM cpuidle + driver and is not defined in the DT. The SPM state machine should be + configured to execute this state by default and after executing every other + state below. + + Retention: Retention is a low power state where the core is clock gated and + the memory and the registers associated with the core are retained. The + voltage may be reduced to the minimum value needed to keep the processor + registers active. The SPM should be configured to execute the retention + sequence and would wait for interrupt, before restoring the cpu to execution + state. Retention may have a slightly higher latency than Standby. + + Standalone PC: A cpu can power down and warmboot if there is a sufficient time + between the time it enters idle and the next known wake up. SPC mode is used + to indicate a core entering a power down state without consulting any other + cpu or the system resources. This helps save power only on that core. The SPM + sequence for this idle state is programmed to power down the supply to the + core, wait for the interrupt, restore power to the core, and ensure the + system state including cache hierarchy is ready before allowing core to + resume. Applying power and resetting the core causes the core to warmboot + back into Elevation Level (EL) which trampolines the control back to the + kernel. Entering a power down state for the cpu, needs to be done by trapping + into a EL. Failing to do so, would result in a crash enforced by the warm boot + code in the EL for the SoC. On SoCs with write-back L1 cache, the cache has to + be flushed in s/w, before powering down the core. + + Power Collapse: This state is similar to the SPC mode, but distinguishes + itself in that the cpu acknowledges and permits the SoC to enter deeper sleep + modes. In a hierarchical power domain SoC, this means L2 and other caches can + be flushed, system bus, clocks - lowered, and SoC main XO clock gated and + voltages reduced, provided all cpus enter this state. Since the span of low + power modes possible at this state is vast, the exit latency and the residency + of this low power mode would be considered high even though at a cpu level, + this essentially is cpu power down. The SPM in this state also may handshake + with the Resource power manager (RPM) processor in the SoC to indicate a + complete application processor subsystem shut down. + + =========================================== + 7 - References =========================================== [1] ARM Linux Kernel documentation - CPUs bindings @@ -301,9 +358,16 @@ patternProperties: properties: compatible: - enum: - - arm,idle-state - - riscv,idle-state + oneOf: + - items: + - enum: + - qcom,idle-state-ret + - qcom,idle-state-spc + - qcom,idle-state-pc + - const: arm,idle-state + - enum: + - arm,idle-state + - riscv,idle-state arm,psci-suspend-param: $ref: /schemas/types.yaml#/definitions/uint32 @@ -852,4 +916,13 @@ examples: }; }; + // Example 4 - Qualcomm SPC + idle-states { + cpu_spc: cpu-spc { + compatible = "qcom,idle-state-spc", "arm,idle-state"; + entry-latency-us = <150>; + exit-latency-us = <200>; + min-residency-us = <2000>; + }; + }; ... diff --git a/Documentation/devicetree/bindings/crypto/inside-secure,safexcel.yaml b/Documentation/devicetree/bindings/crypto/inside-secure,safexcel.yaml new file mode 100644 index 00000000000000..ef07258d16c1db --- /dev/null +++ b/Documentation/devicetree/bindings/crypto/inside-secure,safexcel.yaml @@ -0,0 +1,86 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/crypto/inside-secure,safexcel.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Inside Secure SafeXcel cryptographic engine + +maintainers: + - Antoine Tenart + +properties: + compatible: + oneOf: + - const: inside-secure,safexcel-eip197b + - const: inside-secure,safexcel-eip197d + - const: inside-secure,safexcel-eip97ies + - const: inside-secure,safexcel-eip197 + description: Equivalent of inside-secure,safexcel-eip197b + deprecated: true + - const: inside-secure,safexcel-eip97 + description: Equivalent of inside-secure,safexcel-eip97ies + deprecated: true + + reg: + maxItems: 1 + + interrupts: + maxItems: 6 + + interrupt-names: + items: + - const: ring0 + - const: ring1 + - const: ring2 + - const: ring3 + - const: eip + - const: mem + + clocks: + minItems: 1 + maxItems: 2 + + clock-names: + minItems: 1 + items: + - const: core + - const: reg + +required: + - reg + - interrupts + - interrupt-names + +allOf: + - if: + properties: + clocks: + minItems: 2 + then: + properties: + clock-names: + minItems: 2 + required: + - clock-names + +additionalProperties: false + +examples: + - | + #include + #include + + crypto@800000 { + compatible = "inside-secure,safexcel-eip197b"; + reg = <0x800000 0x200000>; + interrupts = , + , + , + , + , + ; + interrupt-names = "ring0", "ring1", "ring2", "ring3", "eip", "mem"; + clocks = <&cpm_syscon0 1 26>; + clock-names = "core"; + }; diff --git a/Documentation/devicetree/bindings/crypto/inside-secure-safexcel.txt b/Documentation/devicetree/bindings/crypto/inside-secure-safexcel.txt deleted file mode 100644 index 3bbf144c9988e6..00000000000000 --- a/Documentation/devicetree/bindings/crypto/inside-secure-safexcel.txt +++ /dev/null @@ -1,40 +0,0 @@ -Inside Secure SafeXcel cryptographic engine - -Required properties: -- compatible: Should be "inside-secure,safexcel-eip197b", - "inside-secure,safexcel-eip197d" or - "inside-secure,safexcel-eip97ies". -- reg: Base physical address of the engine and length of memory mapped region. -- interrupts: Interrupt numbers for the rings and engine. -- interrupt-names: Should be "ring0", "ring1", "ring2", "ring3", "eip", "mem". - -Optional properties: -- clocks: Reference to the crypto engine clocks, the second clock is - needed for the Armada 7K/8K SoCs. -- clock-names: mandatory if there is a second clock, in this case the - name must be "core" for the first clock and "reg" for - the second one. - -Backward compatibility: -Two compatibles are kept for backward compatibility, but shouldn't be used for -new submissions: -- "inside-secure,safexcel-eip197" is equivalent to - "inside-secure,safexcel-eip197b". -- "inside-secure,safexcel-eip97" is equivalent to - "inside-secure,safexcel-eip97ies". - -Example: - - crypto: crypto@800000 { - compatible = "inside-secure,safexcel-eip197b"; - reg = <0x800000 0x200000>; - interrupts = , - , - , - , - , - ; - interrupt-names = "mem", "ring0", "ring1", "ring2", "ring3", - "eip"; - clocks = <&cpm_syscon0 1 26>; - }; diff --git a/Documentation/devicetree/bindings/crypto/qcom,inline-crypto-engine.yaml b/Documentation/devicetree/bindings/crypto/qcom,inline-crypto-engine.yaml index ca4f7d1cefaa99..09e43157cc71fe 100644 --- a/Documentation/devicetree/bindings/crypto/qcom,inline-crypto-engine.yaml +++ b/Documentation/devicetree/bindings/crypto/qcom,inline-crypto-engine.yaml @@ -16,6 +16,7 @@ properties: - qcom,sa8775p-inline-crypto-engine - qcom,sm8450-inline-crypto-engine - qcom,sm8550-inline-crypto-engine + - qcom,sm8650-inline-crypto-engine - const: qcom,inline-crypto-engine reg: diff --git a/Documentation/devicetree/bindings/crypto/qcom,prng.yaml b/Documentation/devicetree/bindings/crypto/qcom,prng.yaml index 13070db0f70ccc..89c88004b41bf5 100644 --- a/Documentation/devicetree/bindings/crypto/qcom,prng.yaml +++ b/Documentation/devicetree/bindings/crypto/qcom,prng.yaml @@ -21,6 +21,7 @@ properties: - qcom,sc7280-trng - qcom,sm8450-trng - qcom,sm8550-trng + - qcom,sm8650-trng - const: qcom,trng reg: diff --git a/Documentation/devicetree/bindings/crypto/qcom-qce.yaml b/Documentation/devicetree/bindings/crypto/qcom-qce.yaml index 8e665d910e6e68..a48bd381063aaf 100644 --- a/Documentation/devicetree/bindings/crypto/qcom-qce.yaml +++ b/Documentation/devicetree/bindings/crypto/qcom-qce.yaml @@ -44,10 +44,12 @@ properties: - items: - enum: + - qcom,sc7280-qce - qcom,sm8250-qce - qcom,sm8350-qce - qcom,sm8450-qce - qcom,sm8550-qce + - qcom,sm8650-qce - const: qcom,sm8150-qce - const: qcom,qce @@ -96,6 +98,7 @@ allOf: - qcom,crypto-v5.4 - qcom,ipq6018-qce - qcom,ipq8074-qce + - qcom,ipq9574-qce - qcom,msm8996-qce - qcom,sdm845-qce then: @@ -129,6 +132,17 @@ allOf: - clocks - clock-names + - if: + properties: + compatible: + contains: + enum: + - qcom,sm8150-qce + then: + properties: + clocks: false + clock-names: false + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/display/bridge/lontium,lt8912b.yaml b/Documentation/devicetree/bindings/display/bridge/lontium,lt8912b.yaml index f201ae4af4fbd7..2cef2521579859 100644 --- a/Documentation/devicetree/bindings/display/bridge/lontium,lt8912b.yaml +++ b/Documentation/devicetree/bindings/display/bridge/lontium,lt8912b.yaml @@ -55,6 +55,27 @@ properties: - port@0 - port@1 + vcchdmipll-supply: + description: A 1.8V supply that powers the HDMI PLL. + + vcchdmitx-supply: + description: A 1.8V supply that powers the HDMI TX part. + + vcclvdspll-supply: + description: A 1.8V supply that powers the LVDS PLL. + + vcclvdstx-supply: + description: A 1.8V supply that powers the LVDS TX part. + + vccmipirx-supply: + description: A 1.8V supply that powers the MIPI RX part. + + vccsysclk-supply: + description: A 1.8V supply that powers the SYSCLK. + + vdd-supply: + description: A 1.8V supply that powers the digital part. + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,aal.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,aal.yaml index 7fd42c8fdc3282..b4c28e96dd5553 100644 --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,aal.yaml +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,aal.yaml @@ -24,6 +24,7 @@ properties: - enum: - mediatek,mt8173-disp-aal - mediatek,mt8183-disp-aal + - mediatek,mt8195-mdp3-aal - items: - enum: - mediatek,mt2712-disp-aal diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,color.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,color.yaml index f21e4409204367..b886ca0d89ea15 100644 --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,color.yaml +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,color.yaml @@ -26,6 +26,7 @@ properties: - mediatek,mt2701-disp-color - mediatek,mt8167-disp-color - mediatek,mt8173-disp-color + - mediatek,mt8195-mdp3-color - items: - enum: - mediatek,mt7623-disp-color diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,dsi.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,dsi.yaml index ed24b617090b06..8611319bed2eaf 100644 --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,dsi.yaml +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,dsi.yaml @@ -34,6 +34,10 @@ properties: - enum: - mediatek,mt6795-dsi - const: mediatek,mt8173-dsi + - items: + - enum: + - mediatek,mt8195-dsi + - const: mediatek,mt8183-dsi reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,ethdr.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,ethdr.yaml index 801fa66ae61501..677882348eded7 100644 --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,ethdr.yaml +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,ethdr.yaml @@ -23,7 +23,11 @@ description: properties: compatible: - const: mediatek,mt8195-disp-ethdr + oneOf: + - const: mediatek,mt8195-disp-ethdr + - items: + - const: mediatek,mt8188-disp-ethdr + - const: mediatek,mt8195-disp-ethdr reg: maxItems: 7 diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,mdp-rdma.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,mdp-rdma.yaml deleted file mode 100644 index dd12e2ff685c2f..00000000000000 --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,mdp-rdma.yaml +++ /dev/null @@ -1,88 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/display/mediatek/mediatek,mdp-rdma.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: MediaTek MDP RDMA - -maintainers: - - Chun-Kuang Hu - - Philipp Zabel - -description: - The MediaTek MDP RDMA stands for Read Direct Memory Access. - It provides real time data to the back-end panel driver, such as DSI, - DPI and DP_INTF. - It contains one line buffer to store the sufficient pixel data. - RDMA device node must be siblings to the central MMSYS_CONFIG node. - For a description of the MMSYS_CONFIG binding, see - Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.yaml for details. - -properties: - compatible: - const: mediatek,mt8195-vdo1-rdma - - reg: - maxItems: 1 - - interrupts: - maxItems: 1 - - power-domains: - maxItems: 1 - - clocks: - items: - - description: RDMA Clock - - iommus: - maxItems: 1 - - mediatek,gce-client-reg: - description: - The register of display function block to be set by gce. There are 4 arguments, - such as gce node, subsys id, offset and register size. The subsys id that is - mapping to the register of display function blocks is defined in the gce header - include/dt-bindings/gce/-gce.h of each chips. - $ref: /schemas/types.yaml#/definitions/phandle-array - items: - items: - - description: phandle of GCE - - description: GCE subsys id - - description: register offset - - description: register size - maxItems: 1 - -required: - - compatible - - reg - - power-domains - - clocks - - iommus - - mediatek,gce-client-reg - -additionalProperties: false - -examples: - - | - #include - #include - #include - #include - #include - - soc { - #address-cells = <2>; - #size-cells = <2>; - - rdma@1c104000 { - compatible = "mediatek,mt8195-vdo1-rdma"; - reg = <0 0x1c104000 0 0x1000>; - interrupts = ; - clocks = <&vdosys1 CLK_VDO1_MDP_RDMA0>; - power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>; - iommus = <&iommu_vdo M4U_PORT_L2_MDP_RDMA0>; - mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0x4000 0x1000>; - }; - }; diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,merge.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,merge.yaml index eead5cb8636edb..dae839279950bf 100644 --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,merge.yaml +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,merge.yaml @@ -24,9 +24,13 @@ properties: - enum: - mediatek,mt8173-disp-merge - mediatek,mt8195-disp-merge + - mediatek,mt8195-mdp3-merge - items: - const: mediatek,mt6795-disp-merge - const: mediatek,mt8173-disp-merge + - items: + - const: mediatek,mt8188-disp-merge + - const: mediatek,mt8195-disp-merge reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,ovl.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,ovl.yaml index 3e1069b00b56ef..c471a181d125bd 100644 --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,ovl.yaml +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,ovl.yaml @@ -26,6 +26,7 @@ properties: - mediatek,mt8173-disp-ovl - mediatek,mt8183-disp-ovl - mediatek,mt8192-disp-ovl + - mediatek,mt8195-mdp3-ovl - items: - enum: - mediatek,mt7623-disp-ovl diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,padding.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,padding.yaml new file mode 100644 index 00000000000000..be07bbdc54e343 --- /dev/null +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,padding.yaml @@ -0,0 +1,83 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/mediatek/mediatek,padding.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek Display Padding + +maintainers: + - Chun-Kuang Hu + - Philipp Zabel + +description: + Padding provides ability to add pixels to width and height of a layer with + specified colors. Due to hardware design, Mixer in VDOSYS1 requires + width of a layer to be 2-pixel-align, or 4-pixel-align when ETHDR is enabled, + we need Padding to deal with odd width. + Please notice that even if the Padding is in bypass mode, settings in + register must be cleared to 0, or undefined behaviors could happen. + +properties: + compatible: + enum: + - mediatek,mt8188-disp-padding + - mediatek,mt8195-mdp3-padding + + reg: + maxItems: 1 + + power-domains: + maxItems: 1 + + clocks: + items: + - description: Padding's clocks + + mediatek,gce-client-reg: + description: + GCE (Global Command Engine) is a multi-core micro processor that helps + its clients to execute commands without interrupting CPU. This property + describes GCE client's information that is composed by 4 fields. + 1. Phandle of the GCE (there may be several GCE processors) + 2. Sub-system ID defined in the dt-binding like a user ID + (Please refer to include/dt-bindings/gce/-gce.h) + 3. Offset from base address of the subsys you are at + 4. Size of the register the client needs + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + items: + - description: Phandle of the GCE + - description: Subsys ID defined in the dt-binding + - description: Offset from base address of the subsys + - description: Size of register + maxItems: 1 + +required: + - compatible + - reg + - power-domains + - clocks + - mediatek,gce-client-reg + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + padding0: padding@1c11d000 { + compatible = "mediatek,mt8188-disp-padding"; + reg = <0 0x1c11d000 0 0x1000>; + clocks = <&vdosys1 CLK_VDO1_PADDING0>; + power-domains = <&spm MT8188_POWER_DOMAIN_VDOSYS1>; + mediatek,gce-client-reg = <&gce0 SUBSYS_1c11XXXX 0xd000 0x1000>; + }; + }; diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,split.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,split.yaml index a8a5c9608598f0..e4affc854f3dd2 100644 --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,split.yaml +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,split.yaml @@ -23,6 +23,7 @@ properties: oneOf: - enum: - mediatek,mt8173-disp-split + - mediatek,mt8195-mdp3-split - items: - const: mediatek,mt6795-disp-split - const: mediatek,mt8173-disp-split @@ -38,6 +39,21 @@ properties: the power controller specified by phandle. See Documentation/devicetree/bindings/power/power-domain.yaml for details. + mediatek,gce-client-reg: + description: + The register of display function block to be set by gce. There are 4 arguments, + such as gce node, subsys id, offset and register size. The subsys id that is + mapping to the register of display function blocks is defined in the gce header + include/dt-bindings/gce/-gce.h of each chips. + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + items: + - description: phandle of GCE + - description: GCE subsys id + - description: register offset + - description: register size + maxItems: 1 + clocks: items: - description: SPLIT Clock @@ -48,6 +64,17 @@ required: - power-domains - clocks +allOf: + - if: + properties: + compatible: + contains: + const: mediatek,mt8195-mdp3-split + + then: + required: + - mediatek,gce-client-reg + additionalProperties: false examples: diff --git a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml index dbe398f84ffb3c..ae53cbfb21932f 100644 --- a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml +++ b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml @@ -26,8 +26,10 @@ properties: - qcom,sc8280xp-edp - qcom,sdm845-dp - qcom,sm8350-dp + - qcom,sm8650-dp - items: - enum: + - qcom,sm8150-dp - qcom,sm8250-dp - qcom,sm8450-dp - qcom,sm8550-dp diff --git a/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml b/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml index c6dbab65d5f705..4219936eda5a17 100644 --- a/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml +++ b/Documentation/devicetree/bindings/display/msm/dsi-controller-main.yaml @@ -25,6 +25,7 @@ properties: - qcom,sc7180-dsi-ctrl - qcom,sc7280-dsi-ctrl - qcom,sdm660-dsi-ctrl + - qcom,sdm670-dsi-ctrl - qcom,sdm845-dsi-ctrl - qcom,sm6115-dsi-ctrl - qcom,sm6125-dsi-ctrl @@ -35,6 +36,7 @@ properties: - qcom,sm8350-dsi-ctrl - qcom,sm8450-dsi-ctrl - qcom,sm8550-dsi-ctrl + - qcom,sm8650-dsi-ctrl - const: qcom,mdss-dsi-ctrl - enum: - qcom,dsi-ctrl-6g-qcm2290 @@ -333,6 +335,7 @@ allOf: - qcom,sm8350-dsi-ctrl - qcom,sm8450-dsi-ctrl - qcom,sm8550-dsi-ctrl + - qcom,sm8650-dsi-ctrl then: properties: clocks: diff --git a/Documentation/devicetree/bindings/display/msm/dsi-phy-7nm.yaml b/Documentation/devicetree/bindings/display/msm/dsi-phy-7nm.yaml index dd6619555a126a..7e764eac3ef318 100644 --- a/Documentation/devicetree/bindings/display/msm/dsi-phy-7nm.yaml +++ b/Documentation/devicetree/bindings/display/msm/dsi-phy-7nm.yaml @@ -22,6 +22,7 @@ properties: - qcom,sm8350-dsi-phy-5nm - qcom,sm8450-dsi-phy-5nm - qcom,sm8550-dsi-phy-4nm + - qcom,sm8650-dsi-phy-4nm reg: items: diff --git a/Documentation/devicetree/bindings/display/msm/mdss-common.yaml b/Documentation/devicetree/bindings/display/msm/mdss-common.yaml index f69196e4cc7657..c6305a6e033467 100644 --- a/Documentation/devicetree/bindings/display/msm/mdss-common.yaml +++ b/Documentation/devicetree/bindings/display/msm/mdss-common.yaml @@ -61,17 +61,27 @@ properties: ranges: true + # This is not a perfect description, but it's impossible to discern and match + # the entries like we do with interconnect-names interconnects: minItems: 1 items: - description: Interconnect path from mdp0 (or a single mdp) port to the data bus - description: Interconnect path from mdp1 port to the data bus + - description: Interconnect path from CPU to the reg bus interconnect-names: - minItems: 1 - items: - - const: mdp0-mem - - const: mdp1-mem + oneOf: + - minItems: 1 + items: + - const: mdp0-mem + - const: cpu-cfg + + - minItems: 2 + items: + - const: mdp0-mem + - const: mdp1-mem + - const: cpu-cfg resets: items: diff --git a/Documentation/devicetree/bindings/display/msm/qcom,qcm2290-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,qcm2290-mdss.yaml index 5ad155612b6cf5..f0cdb542268851 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,qcm2290-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,qcm2290-mdss.yaml @@ -36,10 +36,14 @@ properties: maxItems: 2 interconnects: - maxItems: 1 + items: + - description: Interconnect path from mdp0 port to the data bus + - description: Interconnect path from CPU to the reg bus interconnect-names: - maxItems: 1 + items: + - const: mdp0-mem + - const: cpu-cfg patternProperties: "^display-controller@[0-9a-f]+$": @@ -56,7 +60,9 @@ patternProperties: properties: compatible: - const: qcom,dsi-ctrl-6g-qcm2290 + items: + - const: qcom,qcm2290-dsi-ctrl + - const: qcom,mdss-dsi-ctrl "^phy@[0-9a-f]+$": type: object @@ -96,8 +102,10 @@ examples: interrupt-controller; #interrupt-cells = <1>; - interconnects = <&mmrt_virt MASTER_MDP0 &bimc SLAVE_EBI1>; - interconnect-names = "mdp0-mem"; + interconnects = <&mmrt_virt MASTER_MDP0 &bimc SLAVE_EBI1>, + <&bimc MASTER_APPSS_PROC &config_noc SLAVE_DISPLAY_CFG>; + interconnect-names = "mdp0-mem", + "cpu-cfg"; iommus = <&apps_smmu 0x420 0x2>, <&apps_smmu 0x421 0x0>; @@ -136,7 +144,8 @@ examples: }; dsi@5e94000 { - compatible = "qcom,dsi-ctrl-6g-qcm2290"; + compatible = "qcom,qcm2290-dsi-ctrl", + "qcom,mdss-dsi-ctrl"; reg = <0x05e94000 0x400>; reg-names = "dsi_ctrl"; diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sc7180-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sc7180-mdss.yaml index 3432a2407caa64..7a0555b15ddf1e 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sc7180-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sc7180-mdss.yaml @@ -36,10 +36,14 @@ properties: maxItems: 1 interconnects: - maxItems: 1 + items: + - description: Interconnect path from mdp0 port to the data bus + - description: Interconnect path from CPU to the reg bus interconnect-names: - maxItems: 1 + items: + - const: mdp0-mem + - const: cpu-cfg patternProperties: "^display-controller@[0-9a-f]+$": @@ -106,8 +110,10 @@ examples: interrupt-controller; #interrupt-cells = <1>; - interconnects = <&mmss_noc MASTER_MDP0 &mc_virt SLAVE_EBI1>; - interconnect-names = "mdp0-mem"; + interconnects = <&mmss_noc MASTER_MDP0 &mc_virt SLAVE_EBI1>, + <&gem_noc MASTER_APPSS_PROC &config_noc SLAVE_DISPLAY_CFG>; + interconnect-names = "mdp0-mem", + "cpu-cfg"; iommus = <&apps_smmu 0x800 0x2>; ranges; diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sc7280-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sc7280-mdss.yaml index bbb727831fcabb..2947f27e058521 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sc7280-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sc7280-mdss.yaml @@ -36,10 +36,14 @@ properties: maxItems: 1 interconnects: - maxItems: 1 + items: + - description: Interconnect path from mdp0 port to the data bus + - description: Interconnect path from CPU to the reg bus interconnect-names: - maxItems: 1 + items: + - const: mdp0-mem + - const: cpu-cfg patternProperties: "^display-controller@[0-9a-f]+$": @@ -118,8 +122,10 @@ examples: interrupt-controller; #interrupt-cells = <1>; - interconnects = <&mmss_noc MASTER_MDP0 &mc_virt SLAVE_EBI1>; - interconnect-names = "mdp0-mem"; + interconnects = <&mmss_noc MASTER_MDP0 &mc_virt SLAVE_EBI1>, + <&gem_noc MASTER_APPSS_PROC &cnoc2 SLAVE_DISPLAY_CFG>; + interconnect-names = "mdp0-mem", + "cpu-cfg"; iommus = <&apps_smmu 0x900 0x402>; ranges; diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sdm670-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sdm670-mdss.yaml new file mode 100644 index 00000000000000..7dc269322b8e49 --- /dev/null +++ b/Documentation/devicetree/bindings/display/msm/qcom,sdm670-mdss.yaml @@ -0,0 +1,292 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/msm/qcom,sdm670-mdss.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SDM670 Display MDSS + +maintainers: + - Richard Acayan + +description: + SDM670 MSM Mobile Display Subsystem (MDSS), which encapsulates sub-blocks + like DPU display controller, DSI and DP interfaces etc. + +$ref: /schemas/display/msm/mdss-common.yaml# + +properties: + compatible: + const: qcom,sdm670-mdss + + clocks: + items: + - description: Display AHB clock from gcc + - description: Display core clock + + clock-names: + items: + - const: iface + - const: core + + iommus: + maxItems: 2 + + interconnects: + maxItems: 2 + + interconnect-names: + maxItems: 2 + +patternProperties: + "^display-controller@[0-9a-f]+$": + type: object + additionalProperties: true + + properties: + compatible: + const: qcom,sdm670-dpu + + "^displayport-controller@[0-9a-f]+$": + type: object + additionalProperties: true + + properties: + compatible: + const: qcom,sdm670-dp + + "^dsi@[0-9a-f]+$": + type: object + additionalProperties: true + + properties: + compatible: + contains: + const: qcom,sdm670-dsi-ctrl + + "^phy@[0-9a-f]+$": + type: object + additionalProperties: true + + properties: + compatible: + const: qcom,dsi-phy-10nm + +required: + - compatible + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + #include + #include + #include + + display-subsystem@ae00000 { + compatible = "qcom,sdm670-mdss"; + reg = <0x0ae00000 0x1000>; + reg-names = "mdss"; + power-domains = <&dispcc MDSS_GDSC>; + + clocks = <&gcc GCC_DISP_AHB_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>; + clock-names = "iface", "core"; + + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + + interconnects = <&mmss_noc MASTER_MDP_PORT0 0 &mem_noc SLAVE_EBI_CH0 0>, + <&mmss_noc MASTER_MDP_PORT1 0 &mem_noc SLAVE_EBI_CH0 0>; + interconnect-names = "mdp0-mem", "mdp1-mem"; + + iommus = <&apps_smmu 0x880 0x8>, + <&apps_smmu 0xc80 0x8>; + + #address-cells = <1>; + #size-cells = <1>; + ranges; + + display-controller@ae01000 { + compatible = "qcom,sdm670-dpu"; + reg = <0x0ae01000 0x8f000>, + <0x0aeb0000 0x2008>; + reg-names = "mdp", "vbif"; + + clocks = <&gcc GCC_DISP_AXI_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_AXI_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>, + <&dispcc DISP_CC_MDSS_VSYNC_CLK>; + clock-names = "gcc-bus", "iface", "bus", "core", "vsync"; + + interrupt-parent = <&mdss>; + interrupts = <0>; + power-domains = <&rpmhpd SDM670_CX>; + operating-points-v2 = <&mdp_opp_table>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dpu_intf1_out: endpoint { + remote-endpoint = <&mdss_dsi0_in>; + }; + }; + + port@1 { + reg = <1>; + dpu_intf2_out: endpoint { + remote-endpoint = <&mdss_dsi1_in>; + }; + }; + }; + }; + + dsi@ae94000 { + compatible = "qcom,sdm670-dsi-ctrl", "qcom,mdss-dsi-ctrl"; + reg = <0x0ae94000 0x400>; + reg-names = "dsi_ctrl"; + + interrupt-parent = <&mdss>; + interrupts = <4>; + + clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK>, + <&dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>, + <&dispcc DISP_CC_MDSS_PCLK0_CLK>, + <&dispcc DISP_CC_MDSS_ESC0_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_AXI_CLK>; + clock-names = "byte", + "byte_intf", + "pixel", + "core", + "iface", + "bus"; + assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>, + <&dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>; + assigned-clock-parents = <&mdss_dsi0_phy 0>, <&mdss_dsi0_phy 1>; + + operating-points-v2 = <&dsi_opp_table>; + power-domains = <&rpmhpd SDM670_CX>; + + phys = <&mdss_dsi0_phy>; + phy-names = "dsi"; + + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + mdss_dsi0_in: endpoint { + remote-endpoint = <&dpu_intf1_out>; + }; + }; + + port@1 { + reg = <1>; + mdss_dsi0_out: endpoint { + }; + }; + }; + }; + + mdss_dsi0_phy: phy@ae94400 { + compatible = "qcom,dsi-phy-10nm"; + reg = <0x0ae94400 0x200>, + <0x0ae94600 0x280>, + <0x0ae94a00 0x1e0>; + reg-names = "dsi_phy", + "dsi_phy_lane", + "dsi_pll"; + + #clock-cells = <1>; + #phy-cells = <0>; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&rpmhcc RPMH_CXO_CLK>; + clock-names = "iface", "ref"; + vdds-supply = <&vreg_dsi_phy>; + }; + + dsi@ae96000 { + compatible = "qcom,sdm670-dsi-ctrl", "qcom,mdss-dsi-ctrl"; + reg = <0x0ae96000 0x400>; + reg-names = "dsi_ctrl"; + + interrupt-parent = <&mdss>; + interrupts = <5>; + + clocks = <&dispcc DISP_CC_MDSS_BYTE1_CLK>, + <&dispcc DISP_CC_MDSS_BYTE1_INTF_CLK>, + <&dispcc DISP_CC_MDSS_PCLK1_CLK>, + <&dispcc DISP_CC_MDSS_ESC1_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_AXI_CLK>; + clock-names = "byte", + "byte_intf", + "pixel", + "core", + "iface", + "bus"; + assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE1_CLK_SRC>, + <&dispcc DISP_CC_MDSS_PCLK1_CLK_SRC>; + assigned-clock-parents = <&dsi1_phy 0>, <&dsi1_phy 1>; + + operating-points-v2 = <&dsi_opp_table>; + power-domains = <&rpmhpd SDM670_CX>; + + phys = <&dsi1_phy>; + phy-names = "dsi"; + + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + mdss_dsi1_in: endpoint { + remote-endpoint = <&dpu_intf2_out>; + }; + }; + + port@1 { + reg = <1>; + mdss_dsi1_out: endpoint { + }; + }; + }; + }; + + mdss_dsi1_phy: phy@ae96400 { + compatible = "qcom,dsi-phy-10nm"; + reg = <0x0ae96400 0x200>, + <0x0ae96600 0x280>, + <0x0ae96a00 0x10e>; + reg-names = "dsi_phy", + "dsi_phy_lane", + "dsi_pll"; + + #clock-cells = <1>; + #phy-cells = <0>; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&rpmhcc RPMH_CXO_CLK>; + clock-names = "iface", "ref"; + vdds-supply = <&vreg_dsi_phy>; + }; + }; +... diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sdm845-dpu.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sdm845-dpu.yaml index b917064bdf3342..dc11fd421a27fa 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sdm845-dpu.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sdm845-dpu.yaml @@ -13,7 +13,9 @@ $ref: /schemas/display/msm/dpu-common.yaml# properties: compatible: - const: qcom,sdm845-dpu + enum: + - qcom,sdm670-dpu + - qcom,sdm845-dpu reg: items: diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm6115-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm6115-mdss.yaml index dde5c2acead5d1..309de1953c88fc 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm6115-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm6115-mdss.yaml @@ -29,6 +29,16 @@ properties: iommus: maxItems: 2 + interconnects: + items: + - description: Interconnect path from mdp0 port to the data bus + - description: Interconnect path from CPU to the reg bus + + interconnect-names: + items: + - const: mdp0-mem + - const: cpu-cfg + patternProperties: "^display-controller@[0-9a-f]+$": type: object diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm6125-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm6125-mdss.yaml index 671c2c2aa89659..3deb9dc81c9c39 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm6125-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm6125-mdss.yaml @@ -35,10 +35,14 @@ properties: maxItems: 1 interconnects: - maxItems: 2 + items: + - description: Interconnect path from mdp0 port to the data bus + - description: Interconnect path from CPU to the reg bus interconnect-names: - maxItems: 2 + items: + - const: mdp0-mem + - const: cpu-cfg patternProperties: "^display-controller@[0-9a-f]+$": diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm6350-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm6350-mdss.yaml index e1dcb453762ecf..c9ba1fae80425e 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm6350-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm6350-mdss.yaml @@ -35,10 +35,14 @@ properties: maxItems: 1 interconnects: - maxItems: 2 + items: + - description: Interconnect path from mdp0 port to the data bus + - description: Interconnect path from CPU to the reg bus interconnect-names: - maxItems: 2 + items: + - const: mdp0-mem + - const: cpu-cfg patternProperties: "^display-controller@[0-9a-f]+$": diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm6375-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm6375-mdss.yaml index b15c3950f09dbb..8e8a288d318c34 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm6375-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm6375-mdss.yaml @@ -35,10 +35,14 @@ properties: maxItems: 1 interconnects: - maxItems: 2 + items: + - description: Interconnect path from mdp0 port to the data bus + - description: Interconnect path from CPU to the reg bus interconnect-names: - maxItems: 2 + items: + - const: mdp0-mem + - const: cpu-cfg patternProperties: "^display-controller@[0-9a-f]+$": diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8150-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8150-mdss.yaml index a2a8be7f64a9c1..c0d6a4fdff97e3 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm8150-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm8150-mdss.yaml @@ -69,7 +69,7 @@ patternProperties: properties: compatible: - const: qcom,dsi-phy-7nm + const: qcom,dsi-phy-7nm-8150 unevaluatedProperties: false @@ -247,7 +247,7 @@ examples: }; dsi0_phy: phy@ae94400 { - compatible = "qcom,dsi-phy-7nm"; + compatible = "qcom,dsi-phy-7nm-8150"; reg = <0x0ae94400 0x200>, <0x0ae94600 0x280>, <0x0ae94900 0x260>; @@ -318,7 +318,7 @@ examples: }; dsi1_phy: phy@ae96400 { - compatible = "qcom,dsi-phy-7nm"; + compatible = "qcom,dsi-phy-7nm-8150"; reg = <0x0ae96400 0x200>, <0x0ae96600 0x280>, <0x0ae96900 0x260>; diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8250-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8250-mdss.yaml index 994975909fea54..51368cda7b2fe7 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm8250-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm8250-mdss.yaml @@ -52,6 +52,16 @@ patternProperties: compatible: const: qcom,sm8250-dpu + "^displayport-controller@[0-9a-f]+$": + type: object + additionalProperties: true + + properties: + compatible: + items: + - const: qcom,sm8250-dp + - const: qcom,sm8350-dp + "^dsi@[0-9a-f]+$": type: object additionalProperties: true diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8450-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8450-mdss.yaml index 001b26e6530120..747a2e9665f4fd 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm8450-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm8450-mdss.yaml @@ -30,10 +30,10 @@ properties: maxItems: 1 interconnects: - maxItems: 2 + maxItems: 3 interconnect-names: - maxItems: 2 + maxItems: 3 patternProperties: "^display-controller@[0-9a-f]+$": @@ -91,9 +91,12 @@ examples: reg = <0x0ae00000 0x1000>; reg-names = "mdss"; - interconnects = <&mmss_noc MASTER_MDP_DISP 0 &mc_virt SLAVE_EBI1_DISP 0>, - <&mmss_noc MASTER_MDP_DISP 0 &mc_virt SLAVE_EBI1_DISP 0>; - interconnect-names = "mdp0-mem", "mdp1-mem"; + interconnects = <&mmss_noc MASTER_MDP_DISP &mc_virt SLAVE_EBI1_DISP>, + <&mmss_noc MASTER_MDP_DISP &mc_virt SLAVE_EBI1_DISP>, + <&gem_noc MASTER_APPSS_PROC &config_noc SLAVE_DISPLAY_CFG>; + interconnect-names = "mdp0-mem", + "mdp1-mem", + "cpu-cfg"; resets = <&dispcc DISP_CC_MDSS_CORE_BCR>; diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8650-dpu.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8650-dpu.yaml new file mode 100644 index 00000000000000..a01d15a033176d --- /dev/null +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm8650-dpu.yaml @@ -0,0 +1,127 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/msm/qcom,sm8650-dpu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SM8650 Display DPU + +maintainers: + - Neil Armstrong + +$ref: /schemas/display/msm/dpu-common.yaml# + +properties: + compatible: + const: qcom,sm8650-dpu + + reg: + items: + - description: Address offset and size for mdp register set + - description: Address offset and size for vbif register set + + reg-names: + items: + - const: mdp + - const: vbif + + clocks: + items: + - description: Display hf axi + - description: Display MDSS ahb + - description: Display lut + - description: Display core + - description: Display vsync + + clock-names: + items: + - const: nrt_bus + - const: iface + - const: lut + - const: core + - const: vsync + +required: + - compatible + - reg + - reg-names + - clocks + - clock-names + +unevaluatedProperties: false + +examples: + - | + #include + #include + + display-controller@ae01000 { + compatible = "qcom,sm8650-dpu"; + reg = <0x0ae01000 0x8f000>, + <0x0aeb0000 0x2008>; + reg-names = "mdp", "vbif"; + + clocks = <&gcc_axi_clk>, + <&dispcc_ahb_clk>, + <&dispcc_mdp_lut_clk>, + <&dispcc_mdp_clk>, + <&dispcc_vsync_clk>; + clock-names = "nrt_bus", + "iface", + "lut", + "core", + "vsync"; + + assigned-clocks = <&dispcc_vsync_clk>; + assigned-clock-rates = <19200000>; + + operating-points-v2 = <&mdp_opp_table>; + power-domains = <&rpmhpd RPMHPD_MMCX>; + + interrupt-parent = <&mdss>; + interrupts = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dpu_intf1_out: endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; + + port@1 { + reg = <1>; + dpu_intf2_out: endpoint { + remote-endpoint = <&dsi1_in>; + }; + }; + }; + + mdp_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-325000000 { + opp-hz = /bits/ 64 <325000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-375000000 { + opp-hz = /bits/ 64 <375000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-514000000 { + opp-hz = /bits/ 64 <514000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8650-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8650-mdss.yaml new file mode 100644 index 00000000000000..bd11119dc93daf --- /dev/null +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm8650-mdss.yaml @@ -0,0 +1,328 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/msm/qcom,sm8650-mdss.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SM8650 Display MDSS + +maintainers: + - Neil Armstrong + +description: + SM8650 MSM Mobile Display Subsystem(MDSS), which encapsulates sub-blocks like + DPU display controller, DSI and DP interfaces etc. + +$ref: /schemas/display/msm/mdss-common.yaml# + +properties: + compatible: + const: qcom,sm8650-mdss + + clocks: + items: + - description: Display AHB + - description: Display hf AXI + - description: Display core + + iommus: + maxItems: 1 + + interconnects: + maxItems: 2 + + interconnect-names: + maxItems: 2 + +patternProperties: + "^display-controller@[0-9a-f]+$": + type: object + properties: + compatible: + const: qcom,sm8650-dpu + + "^displayport-controller@[0-9a-f]+$": + type: object + properties: + compatible: + const: qcom,sm8650-dp + + "^dsi@[0-9a-f]+$": + type: object + properties: + compatible: + items: + - const: qcom,sm8650-dsi-ctrl + - const: qcom,mdss-dsi-ctrl + + "^phy@[0-9a-f]+$": + type: object + properties: + compatible: + const: qcom,sm8650-dsi-phy-4nm + +required: + - compatible + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + + display-subsystem@ae00000 { + compatible = "qcom,sm8650-mdss"; + reg = <0x0ae00000 0x1000>; + reg-names = "mdss"; + + resets = <&dispcc_core_bcr>; + + power-domains = <&dispcc_gdsc>; + + clocks = <&gcc_ahb_clk>, + <&gcc_axi_clk>, + <&dispcc_mdp_clk>; + clock-names = "bus", "nrt_bus", "core"; + + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + + iommus = <&apps_smmu 0x1c00 0x2>; + + #address-cells = <1>; + #size-cells = <1>; + ranges; + + display-controller@ae01000 { + compatible = "qcom,sm8650-dpu"; + reg = <0x0ae01000 0x8f000>, + <0x0aeb0000 0x2008>; + reg-names = "mdp", "vbif"; + + clocks = <&gcc_axi_clk>, + <&dispcc_ahb_clk>, + <&dispcc_mdp_lut_clk>, + <&dispcc_mdp_clk>, + <&dispcc_mdp_vsync_clk>; + clock-names = "nrt_bus", + "iface", + "lut", + "core", + "vsync"; + + assigned-clocks = <&dispcc_mdp_vsync_clk>; + assigned-clock-rates = <19200000>; + + operating-points-v2 = <&mdp_opp_table>; + power-domains = <&rpmhpd RPMHPD_MMCX>; + + interrupt-parent = <&mdss>; + interrupts = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dpu_intf1_out: endpoint { + remote-endpoint = <&dsi0_in>; + }; + }; + + port@1 { + reg = <1>; + dpu_intf2_out: endpoint { + remote-endpoint = <&dsi1_in>; + }; + }; + }; + + mdp_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-325000000 { + opp-hz = /bits/ 64 <325000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-375000000 { + opp-hz = /bits/ 64 <375000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-514000000 { + opp-hz = /bits/ 64 <514000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + dsi@ae94000 { + compatible = "qcom,sm8650-dsi-ctrl", "qcom,mdss-dsi-ctrl"; + reg = <0x0ae94000 0x400>; + reg-names = "dsi_ctrl"; + + interrupt-parent = <&mdss>; + interrupts = <4>; + + clocks = <&dispc_byte_clk>, + <&dispcc_intf_clk>, + <&dispcc_pclk>, + <&dispcc_esc_clk>, + <&dispcc_ahb_clk>, + <&gcc_bus_clk>; + clock-names = "byte", + "byte_intf", + "pixel", + "core", + "iface", + "bus"; + + assigned-clocks = <&dispcc_byte_clk>, + <&dispcc_pclk>; + assigned-clock-parents = <&dsi0_phy 0>, <&dsi0_phy 1>; + + operating-points-v2 = <&dsi_opp_table>; + power-domains = <&rpmhpd RPMHPD_MMCX>; + + phys = <&dsi0_phy>; + phy-names = "dsi"; + + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dsi0_in: endpoint { + remote-endpoint = <&dpu_intf1_out>; + }; + }; + + port@1 { + reg = <1>; + dsi0_out: endpoint { + }; + }; + }; + + dsi_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-187500000 { + opp-hz = /bits/ 64 <187500000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-358000000 { + opp-hz = /bits/ 64 <358000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + }; + }; + + dsi0_phy: phy@ae94400 { + compatible = "qcom,sm8650-dsi-phy-4nm"; + reg = <0x0ae95000 0x200>, + <0x0ae95200 0x280>, + <0x0ae95500 0x400>; + reg-names = "dsi_phy", + "dsi_phy_lane", + "dsi_pll"; + + #clock-cells = <1>; + #phy-cells = <0>; + + clocks = <&dispcc_iface_clk>, + <&rpmhcc_ref_clk>; + clock-names = "iface", "ref"; + }; + + dsi@ae96000 { + compatible = "qcom,sm8650-dsi-ctrl", "qcom,mdss-dsi-ctrl"; + reg = <0x0ae96000 0x400>; + reg-names = "dsi_ctrl"; + + interrupt-parent = <&mdss>; + interrupts = <5>; + + clocks = <&dispc_byte_clk>, + <&dispcc_intf_clk>, + <&dispcc_pclk>, + <&dispcc_esc_clk>, + <&dispcc_ahb_clk>, + <&gcc_bus_clk>; + clock-names = "byte", + "byte_intf", + "pixel", + "core", + "iface", + "bus"; + + assigned-clocks = <&dispcc_byte_clk>, + <&dispcc_pclk>; + assigned-clock-parents = <&dsi1_phy 0>, <&dsi1_phy 1>; + + operating-points-v2 = <&dsi_opp_table>; + power-domains = <&rpmhpd RPMHPD_MMCX>; + + phys = <&dsi1_phy>; + phy-names = "dsi"; + + #address-cells = <1>; + #size-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dsi1_in: endpoint { + remote-endpoint = <&dpu_intf2_out>; + }; + }; + + port@1 { + reg = <1>; + dsi1_out: endpoint { + }; + }; + }; + }; + + dsi1_phy: phy@ae96400 { + compatible = "qcom,sm8650-dsi-phy-4nm"; + reg = <0x0ae97000 0x200>, + <0x0ae97200 0x280>, + <0x0ae97500 0x400>; + reg-names = "dsi_phy", + "dsi_phy_lane", + "dsi_pll"; + + #clock-cells = <1>; + #phy-cells = <0>; + + clocks = <&dispcc_iface_clk>, + <&rpmhcc_ref_clk>; + clock-names = "iface", "ref"; + }; + }; +... diff --git a/Documentation/devicetree/bindings/display/panel/fascontek,fs035vg158.yaml b/Documentation/devicetree/bindings/display/panel/fascontek,fs035vg158.yaml new file mode 100644 index 00000000000000..d13c4bd26de462 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/fascontek,fs035vg158.yaml @@ -0,0 +1,56 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/fascontek,fs035vg158.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Fascontek FS035VG158 3.5" (640x480 pixels) 24-bit IPS LCD panel + +maintainers: + - John Watts + +allOf: + - $ref: panel-common.yaml# + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +properties: + compatible: + const: fascontek,fs035vg158 + + spi-3wire: true + +required: + - compatible + - reg + - port + - power-supply + - reset-gpios + +unevaluatedProperties: false + +examples: + - | + #include + + spi { + #address-cells = <1>; + #size-cells = <0>; + panel@0 { + compatible = "fascontek,fs035vg158"; + reg = <0>; + + spi-3wire; + spi-max-frequency = <3125000>; + + reset-gpios = <&gpe 2 GPIO_ACTIVE_LOW>; + + backlight = <&backlight>; + power-supply = <&vcc>; + + port { + panel_input: endpoint { + remote-endpoint = <&panel_output>; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/display/panel/himax,hx8394.yaml b/Documentation/devicetree/bindings/display/panel/himax,hx8394.yaml index ffb35288ffbb4e..916bb7f9420629 100644 --- a/Documentation/devicetree/bindings/display/panel/himax,hx8394.yaml +++ b/Documentation/devicetree/bindings/display/panel/himax,hx8394.yaml @@ -23,6 +23,7 @@ properties: items: - enum: - hannstar,hsd060bhw4 + - powkiddy,x55-panel - const: himax,hx8394 reg: true @@ -31,6 +32,8 @@ properties: backlight: true + rotation: true + port: true vcc-supply: diff --git a/Documentation/devicetree/bindings/display/panel/ilitek,ili9805.yaml b/Documentation/devicetree/bindings/display/panel/ilitek,ili9805.yaml new file mode 100644 index 00000000000000..f4f91f93f4903c --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/ilitek,ili9805.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/ilitek,ili9805.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Ilitek ILI9805 based MIPI-DSI panels + +maintainers: + - Michael Trimarchi + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + items: + - enum: + - giantplus,gpm1790a0 + - tianma,tm041xdhg01 + - const: ilitek,ili9805 + + avdd-supply: true + dvdd-supply: true + reg: true + +required: + - compatible + - avdd-supply + - dvdd-supply + - reg + - reset-gpios + - port + - backlight + +unevaluatedProperties: false + +examples: + - | + #include + + dsi { + #address-cells = <1>; + #size-cells = <0>; + + panel@0 { + compatible = "giantplus,gpm1790a0", "ilitek,ili9805"; + reg = <0>; + avdd-supply = <&avdd_display>; + dvdd-supply = <&dvdd_display>; + reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_LOW>; /* PL05 */ + backlight = <&backlight>; + + port { + panel_in: endpoint { + remote-endpoint = <&mipi_dsi_out>; + }; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml b/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml index e7ab6224b52e09..b1e624be3e3349 100644 --- a/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml +++ b/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml @@ -16,6 +16,7 @@ properties: compatible: items: - enum: + - ampire,am8001280g - bananapi,lhr050h41 - feixin,k101-im2byl02 - tdo,tl050hdv35 diff --git a/Documentation/devicetree/bindings/display/panel/leadtek,ltk035c5444t.yaml b/Documentation/devicetree/bindings/display/panel/leadtek,ltk035c5444t.yaml index ebdca5f5a00117..7a55961e1a3d35 100644 --- a/Documentation/devicetree/bindings/display/panel/leadtek,ltk035c5444t.yaml +++ b/Documentation/devicetree/bindings/display/panel/leadtek,ltk035c5444t.yaml @@ -18,16 +18,12 @@ properties: compatible: const: leadtek,ltk035c5444t - backlight: true - port: true - power-supply: true - reg: true - reset-gpios: true - spi-3wire: true required: - compatible + - reg + - port - power-supply - reset-gpios diff --git a/Documentation/devicetree/bindings/display/panel/newvision,nv3051d.yaml b/Documentation/devicetree/bindings/display/panel/newvision,nv3051d.yaml index cce775a87f8717..7a634fbc465e04 100644 --- a/Documentation/devicetree/bindings/display/panel/newvision,nv3051d.yaml +++ b/Documentation/devicetree/bindings/display/panel/newvision,nv3051d.yaml @@ -21,7 +21,7 @@ properties: - enum: - anbernic,rg351v-panel - anbernic,rg353p-panel - - anbernic,rg353v-panel + - powkiddy,rk2023-panel - const: newvision,nv3051d reg: true diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple-lvds-dual-ports.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple-lvds-dual-ports.yaml index a5a596ff8e7521..716ece5f397842 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-simple-lvds-dual-ports.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-simple-lvds-dual-ports.yaml @@ -33,6 +33,8 @@ properties: # AU Optronics Corporation 13.3" FHD (1920x1080) TFT LCD panel - auo,g133han01 + # AU Optronics Corporation 15.6" FHD (1920x1080) TFT LCD panel + - auo,g156han04 # AU Optronics Corporation 18.5" FHD (1920x1080) TFT LCD panel - auo,g185han01 # AU Optronics Corporation 19.0" (1280x1024) TFT LCD panel diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml index 11422af3477e58..634a10c6f2dddd 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml @@ -73,6 +73,8 @@ properties: - auo,t215hvn01 # Shanghai AVIC Optoelectronics 7" 1024x600 color TFT-LCD panel - avic,tm070ddh03 + # BOE BP101WX1-100 10.1" WXGA (1280x800) LVDS panel + - boe,bp101wx1-100 # BOE EV121WXM-N10-1850 12.1" WXGA (1280x800) TFT LCD panel - boe,ev121wxm-n10-1850 # BOE HV070WSA-100 7.01" WSVGA TFT LCD panel @@ -144,6 +146,8 @@ properties: - edt,etmv570g2dhu # E Ink VB3300-KCA - eink,vb3300-kca + # Evervision Electronics Co. Ltd. VGG644804 5.7" VGA TFT LCD Panel + - evervision,vgg644804 # Evervision Electronics Co. Ltd. VGG804821 5.0" WVGA TFT LCD Panel - evervision,vgg804821 # Foxlink Group 5" WVGA TFT LCD panel diff --git a/Documentation/devicetree/bindings/display/panel/sitronix,st7701.yaml b/Documentation/devicetree/bindings/display/panel/sitronix,st7701.yaml index 4dc0cd4a6a7722..b348f5bf0a9809 100644 --- a/Documentation/devicetree/bindings/display/panel/sitronix,st7701.yaml +++ b/Documentation/devicetree/bindings/display/panel/sitronix,st7701.yaml @@ -27,6 +27,7 @@ properties: compatible: items: - enum: + - anbernic,rg-arc-panel - densitron,dmt028vghmcmi-1a - elida,kd50t048a - techstar,ts8550b diff --git a/Documentation/devicetree/bindings/display/panel/synaptics,r63353.yaml b/Documentation/devicetree/bindings/display/panel/synaptics,r63353.yaml new file mode 100644 index 00000000000000..e5617d125567d2 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/synaptics,r63353.yaml @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/synaptics,r63353.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Synaptics R63353 based MIPI-DSI panels + +maintainers: + - Michael Trimarchi + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + items: + - enum: + - sharp,ls068b3sx02 + - const: syna,r63353 + + avdd-supply: true + dvdd-supply: true + reg: true + +required: + - compatible + - avdd-supply + - dvdd-supply + - reg + - reset-gpios + - port + - backlight + +unevaluatedProperties: false + +examples: + - | + #include + + dsi { + #address-cells = <1>; + #size-cells = <0>; + + panel@0 { + compatible = "sharp,ls068b3sx02", "syna,r63353"; + reg = <0>; + avdd-supply = <&avdd_display>; + dvdd-supply = <&dvdd_display>; + reset-gpios = <&r_pio 0 5 GPIO_ACTIVE_LOW>; /* PL05 */ + backlight = <&backlight>; + + port { + panel_in: endpoint { + remote-endpoint = <&mipi_dsi_out>; + }; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt deleted file mode 100644 index cec21714f0e0a3..00000000000000 --- a/Documentation/devicetree/bindings/display/rockchip/inno_hdmi-rockchip.txt +++ /dev/null @@ -1,49 +0,0 @@ -Rockchip specific extensions to the Innosilicon HDMI -================================ - -Required properties: -- compatible: - "rockchip,rk3036-inno-hdmi"; -- reg: - Physical base address and length of the controller's registers. -- clocks, clock-names: - Phandle to hdmi controller clock, name should be "pclk" -- interrupts: - HDMI interrupt number -- ports: - Contain one port node with endpoint definitions as defined in - Documentation/devicetree/bindings/graph.txt. -- pinctrl-0, pinctrl-name: - Switch the iomux of HPD/CEC pins to HDMI function. - -Example: -hdmi: hdmi@20034000 { - compatible = "rockchip,rk3036-inno-hdmi"; - reg = <0x20034000 0x4000>; - interrupts = ; - clocks = <&cru PCLK_HDMI>; - clock-names = "pclk"; - pinctrl-names = "default"; - pinctrl-0 = <&hdmi_ctl>; - - hdmi_in: port { - #address-cells = <1>; - #size-cells = <0>; - hdmi_in_lcdc: endpoint@0 { - reg = <0>; - remote-endpoint = <&lcdc_out_hdmi>; - }; - }; -}; - -&pinctrl { - hdmi { - hdmi_ctl: hdmi-ctl { - rockchip,pins = <1 8 RK_FUNC_1 &pcfg_pull_none>, - <1 9 RK_FUNC_1 &pcfg_pull_none>, - <1 10 RK_FUNC_1 &pcfg_pull_none>, - <1 11 RK_FUNC_1 &pcfg_pull_none>; - }; - }; - -}; diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,inno-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,inno-hdmi.yaml new file mode 100644 index 00000000000000..be78dcfa1c7629 --- /dev/null +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,inno-hdmi.yaml @@ -0,0 +1,139 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/rockchip/rockchip,inno-hdmi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Rockchip Innosilicon HDMI controller + +maintainers: + - Sandy Huang + - Heiko Stuebner + +properties: + compatible: + enum: + - rockchip,rk3036-inno-hdmi + - rockchip,rk3128-inno-hdmi + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + minItems: 1 + items: + - description: The HDMI controller main clock + - description: The HDMI PHY reference clock + + clock-names: + minItems: 1 + items: + - const: pclk + - const: ref + + power-domains: + maxItems: 1 + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: + Port node with one endpoint connected to a vop node. + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: + Port node with one endpoint connected to a hdmi-connector node. + + required: + - port@0 + - port@1 + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - pinctrl-0 + - pinctrl-names + - ports + +allOf: + - if: + properties: + compatible: + contains: + const: rockchip,rk3036-inno-hdmi + + then: + properties: + power-domains: false + + - if: + properties: + compatible: + contains: + const: rockchip,rk3128-inno-hdmi + + then: + properties: + clocks: + minItems: 2 + clock-names: + minItems: 2 + required: + - power-domains + +additionalProperties: false + +examples: + - | + #include + #include + #include + hdmi: hdmi@20034000 { + compatible = "rockchip,rk3036-inno-hdmi"; + reg = <0x20034000 0x4000>; + interrupts = ; + clocks = <&cru PCLK_HDMI>; + clock-names = "pclk"; + pinctrl-names = "default"; + pinctrl-0 = <&hdmi_ctl>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + hdmi_in: port@0 { + reg = <0>; + hdmi_in_vop: endpoint { + remote-endpoint = <&vop_out_hdmi>; + }; + }; + + hdmi_out: port@1 { + reg = <1>; + hdmi_out_con: endpoint { + remote-endpoint = <&hdmi_con_in>; + }; + }; + }; + }; + + pinctrl { + hdmi { + hdmi_ctl: hdmi-ctl { + rockchip,pins = <1 RK_PB0 1 &pcfg_pull_none>, + <1 RK_PB1 1 &pcfg_pull_none>, + <1 RK_PB2 1 &pcfg_pull_none>, + <1 RK_PB3 1 &pcfg_pull_none>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml index b60b90472d42e5..2531726af306bd 100644 --- a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop2.yaml @@ -8,8 +8,8 @@ title: Rockchip SoC display controller (VOP2) description: VOP2 (Video Output Processor v2) is the display controller for the Rockchip - series of SoCs which transfers the image data from a video memory - buffer to an external LCD interface. + series of SoCs which transfers the image data from a video memory buffer to + an external LCD interface. maintainers: - Sandy Huang @@ -20,6 +20,7 @@ properties: enum: - rockchip,rk3566-vop - rockchip,rk3568-vop + - rockchip,rk3588-vop reg: items: @@ -27,8 +28,8 @@ properties: Must contain one entry corresponding to the base address and length of the register space. - description: - Can optionally contain a second entry corresponding to - the CRTC gamma LUT address. + Can optionally contain a second entry corresponding to the CRTC gamma + LUT address. reg-names: items: @@ -41,45 +42,63 @@ properties: The VOP interrupt is shared by several interrupt sources, such as frame start (VSYNC), line flag and other status interrupts. + # See compatible-specific constraints below. clocks: + minItems: 5 items: - - description: Clock for ddr buffer transfer. - - description: Clock for the ahb bus to R/W the phy regs. + - description: Clock for ddr buffer transfer via axi. + - description: Clock for the ahb bus to R/W the regs. - description: Pixel clock for video port 0. - description: Pixel clock for video port 1. - description: Pixel clock for video port 2. + - description: Pixel clock for video port 3. + - description: Peripheral(vop grf/dsi) clock. clock-names: + minItems: 5 items: - const: aclk - const: hclk - const: dclk_vp0 - const: dclk_vp1 - const: dclk_vp2 + - const: dclk_vp3 + - const: pclk_vop rockchip,grf: $ref: /schemas/types.yaml#/definitions/phandle description: - Phandle to GRF regs used for misc control + Phandle to GRF regs used for control the polarity of dclk/hsync/vsync of DPI, + also used for query vop memory bisr enable status, etc. + + rockchip,vo1-grf: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Phandle to VO GRF regs used for control the polarity of dclk/hsync/vsync of hdmi + on rk3588. + + rockchip,vop-grf: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Phandle to VOP GRF regs used for control data path between vopr and hdmi/edp. + + rockchip,pmu: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Phandle to PMU GRF used for query vop memory bisr status on rk3588. ports: $ref: /schemas/graph.yaml#/properties/ports - properties: - port@0: + patternProperties: + "^port@[0-3]$": $ref: /schemas/graph.yaml#/properties/port - description: - Output endpoint of VP0 + description: Output endpoint of VP0/1/2/3. - port@1: - $ref: /schemas/graph.yaml#/properties/port - description: - Output endpoint of VP1 + required: + - port@0 - port@2: - $ref: /schemas/graph.yaml#/properties/port - description: - Output endpoint of VP2 + unevaluatedProperties: false iommus: maxItems: 1 @@ -96,6 +115,49 @@ required: - clock-names - ports +allOf: + - if: + properties: + compatible: + contains: + const: rockchip,rk3588-vop + then: + properties: + clocks: + minItems: 7 + clock-names: + minItems: 7 + + ports: + required: + - port@0 + - port@1 + - port@2 + - port@3 + + required: + - rockchip,grf + - rockchip,vo1-grf + - rockchip,vop-grf + - rockchip,pmu + + else: + properties: + rockchip,vo1-grf: false + rockchip,vop-grf: false + rockchip,pmu: false + + clocks: + maxItems: 5 + clock-names: + maxItems: 5 + + ports: + required: + - port@0 + - port@1 + - port@2 + additionalProperties: false examples: diff --git a/Documentation/devicetree/bindings/display/samsung/samsung,exynos-mixer.yaml b/Documentation/devicetree/bindings/display/samsung/samsung,exynos-mixer.yaml index 25d53fde92e110..597c9cc6a312ac 100644 --- a/Documentation/devicetree/bindings/display/samsung/samsung,exynos-mixer.yaml +++ b/Documentation/devicetree/bindings/display/samsung/samsung,exynos-mixer.yaml @@ -85,7 +85,7 @@ allOf: clocks: minItems: 6 maxItems: 6 - regs: + reg: minItems: 2 maxItems: 2 @@ -99,7 +99,7 @@ allOf: clocks: minItems: 4 maxItems: 4 - regs: + reg: minItems: 2 maxItems: 2 @@ -116,7 +116,7 @@ allOf: clocks: minItems: 3 maxItems: 3 - regs: + reg: minItems: 1 maxItems: 1 diff --git a/Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml b/Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml index ae09cd3cbce1fc..b6767ef0d24dec 100644 --- a/Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml +++ b/Documentation/devicetree/bindings/display/ti/ti,am65x-dss.yaml @@ -23,6 +23,7 @@ properties: compatible: enum: - ti,am625-dss + - ti,am62a7,dss - ti,am65x-dss reg: @@ -87,6 +88,7 @@ properties: For AM65x DSS, the OLDI output port node from video port 1. For AM625 DSS, the internal DPI output port node from video port 1. + For AM62A7 DSS, the port is tied off inside the SoC. port@1: $ref: /schemas/graph.yaml#/properties/port @@ -108,6 +110,18 @@ properties: Input memory (from main memory to dispc) bandwidth limit in bytes per second +allOf: + - if: + properties: + compatible: + contains: + const: ti,am62a7-dss + then: + properties: + ports: + properties: + port@0: false + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/dma/dma-controller.yaml b/Documentation/devicetree/bindings/dma/dma-controller.yaml index 04d150d4d15d3c..e6afca558c2dfa 100644 --- a/Documentation/devicetree/bindings/dma/dma-controller.yaml +++ b/Documentation/devicetree/bindings/dma/dma-controller.yaml @@ -19,19 +19,4 @@ properties: additionalProperties: true -examples: - - | - dma: dma-controller@48000000 { - compatible = "ti,omap-sdma"; - reg = <0x48000000 0x1000>; - interrupts = <0 12 0x4>, - <0 13 0x4>, - <0 14 0x4>, - <0 15 0x4>; - #dma-cells = <1>; - dma-channels = <32>; - dma-requests = <127>; - dma-channel-mask = <0xfffe>; - }; - ... diff --git a/Documentation/devicetree/bindings/dma/dma-router.yaml b/Documentation/devicetree/bindings/dma/dma-router.yaml index 346fe0fa4460e3..5ad2febc581e23 100644 --- a/Documentation/devicetree/bindings/dma/dma-router.yaml +++ b/Documentation/devicetree/bindings/dma/dma-router.yaml @@ -40,15 +40,4 @@ required: additionalProperties: true -examples: - - | - sdma_xbar: dma-router@4a002b78 { - compatible = "ti,dra7-dma-crossbar"; - reg = <0x4a002b78 0xfc>; - #dma-cells = <1>; - dma-requests = <205>; - ti,dma-safe-map = <0>; - dma-masters = <&sdma>; - }; - ... diff --git a/Documentation/devicetree/bindings/dma/loongson,ls2x-apbdma.yaml b/Documentation/devicetree/bindings/dma/loongson,ls2x-apbdma.yaml new file mode 100644 index 00000000000000..6a1b49a49a646b --- /dev/null +++ b/Documentation/devicetree/bindings/dma/loongson,ls2x-apbdma.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/dma/loongson,ls2x-apbdma.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Loongson LS2X APB DMA controller + +description: + The Loongson LS2X APB DMA controller is used for transferring data + between system memory and the peripherals on the APB bus. + +maintainers: + - Binbin Zhou + +allOf: + - $ref: dma-controller.yaml# + +properties: + compatible: + oneOf: + - const: loongson,ls2k1000-apbdma + - items: + - const: loongson,ls2k0500-apbdma + - const: loongson,ls2k1000-apbdma + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + '#dma-cells': + const: 1 + +required: + - compatible + - reg + - interrupts + - clocks + - '#dma-cells' + +additionalProperties: false + +examples: + - | + #include + #include + + dma-controller@1fe00c00 { + compatible = "loongson,ls2k1000-apbdma"; + reg = <0x1fe00c00 0x8>; + interrupt-parent = <&liointc1>; + interrupts = <12 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_APB_CLK>; + #dma-cells = <1>; + }; + +... diff --git a/Documentation/devicetree/bindings/dma/nvidia,tegra210-adma.yaml b/Documentation/devicetree/bindings/dma/nvidia,tegra210-adma.yaml index 4003dbe94940c2..877147e95ecc5d 100644 --- a/Documentation/devicetree/bindings/dma/nvidia,tegra210-adma.yaml +++ b/Documentation/devicetree/bindings/dma/nvidia,tegra210-adma.yaml @@ -53,6 +53,9 @@ properties: ADMA_CHn_CTRL register. const: 1 + dma-channel-mask: + maxItems: 1 + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/dma/qcom,gpi.yaml b/Documentation/devicetree/bindings/dma/qcom,gpi.yaml index 88d0de3d1b46b8..deb64cb9ca3eac 100644 --- a/Documentation/devicetree/bindings/dma/qcom,gpi.yaml +++ b/Documentation/devicetree/bindings/dma/qcom,gpi.yaml @@ -32,6 +32,8 @@ properties: - qcom,sm8350-gpi-dma - qcom,sm8450-gpi-dma - qcom,sm8550-gpi-dma + - qcom,sm8650-gpi-dma + - qcom,x1e80100-gpi-dma - const: qcom,sm6350-gpi-dma - items: - enum: diff --git a/Documentation/devicetree/bindings/dma/renesas,rz-dmac.yaml b/Documentation/devicetree/bindings/dma/renesas,rz-dmac.yaml index c284abc6784aec..a42b6a26a6d3f2 100644 --- a/Documentation/devicetree/bindings/dma/renesas,rz-dmac.yaml +++ b/Documentation/devicetree/bindings/dma/renesas,rz-dmac.yaml @@ -16,7 +16,7 @@ properties: compatible: items: - enum: - - renesas,r9a07g043-dmac # RZ/G2UL + - renesas,r9a07g043-dmac # RZ/G2UL and RZ/Five - renesas,r9a07g044-dmac # RZ/G2{L,LC} - renesas,r9a07g054-dmac # RZ/V2L - const: renesas,rz-dmac diff --git a/Documentation/devicetree/bindings/dma/sifive,fu540-c000-pdma.yaml b/Documentation/devicetree/bindings/dma/sifive,fu540-c000-pdma.yaml index a1af0b90636537..3b22183a1a3792 100644 --- a/Documentation/devicetree/bindings/dma/sifive,fu540-c000-pdma.yaml +++ b/Documentation/devicetree/bindings/dma/sifive,fu540-c000-pdma.yaml @@ -29,6 +29,7 @@ properties: compatible: items: - enum: + - microchip,mpfs-pdma - sifive,fu540-c000-pdma - const: sifive,pdma0 description: diff --git a/Documentation/devicetree/bindings/dma/ti/k3-bcdma.yaml b/Documentation/devicetree/bindings/dma/ti/k3-bcdma.yaml index 4ca300a42a99c2..27b8e163656006 100644 --- a/Documentation/devicetree/bindings/dma/ti/k3-bcdma.yaml +++ b/Documentation/devicetree/bindings/dma/ti/k3-bcdma.yaml @@ -37,11 +37,11 @@ properties: reg: minItems: 3 - maxItems: 5 + maxItems: 9 reg-names: minItems: 3 - maxItems: 5 + maxItems: 9 "#dma-cells": const: 3 @@ -141,7 +141,10 @@ allOf: ti,sci-rm-range-tchan: false reg: - maxItems: 3 + items: + - description: BCDMA Control /Status Registers region + - description: RX Channel Realtime Registers region + - description: Ring Realtime Registers region reg-names: items: @@ -161,14 +164,29 @@ allOf: properties: reg: minItems: 5 + items: + - description: BCDMA Control /Status Registers region + - description: Block Copy Channel Realtime Registers region + - description: RX Channel Realtime Registers region + - description: TX Channel Realtime Registers region + - description: Ring Realtime Registers region + - description: Ring Configuration Registers region + - description: TX Channel Configuration Registers region + - description: RX Channel Configuration Registers region + - description: Block Copy Channel Configuration Registers region reg-names: + minItems: 5 items: - const: gcfg - const: bchanrt - const: rchanrt - const: tchanrt - const: ringrt + - const: ring + - const: tchan + - const: rchan + - const: bchan required: - ti,sci-rm-range-bchan @@ -184,7 +202,11 @@ allOf: ti,sci-rm-range-bchan: false reg: - maxItems: 4 + items: + - description: BCDMA Control /Status Registers region + - description: RX Channel Realtime Registers region + - description: TX Channel Realtime Registers region + - description: Ring Realtime Registers region reg-names: items: @@ -220,8 +242,13 @@ examples: <0x0 0x4c000000 0x0 0x20000>, <0x0 0x4a820000 0x0 0x20000>, <0x0 0x4aa40000 0x0 0x20000>, - <0x0 0x4bc00000 0x0 0x100000>; - reg-names = "gcfg", "bchanrt", "rchanrt", "tchanrt", "ringrt"; + <0x0 0x4bc00000 0x0 0x100000>, + <0x0 0x48600000 0x0 0x8000>, + <0x0 0x484a4000 0x0 0x2000>, + <0x0 0x484c2000 0x0 0x2000>, + <0x0 0x48420000 0x0 0x2000>; + reg-names = "gcfg", "bchanrt", "rchanrt", "tchanrt", "ringrt", + "ring", "tchan", "rchan", "bchan"; msi-parent = <&inta_main_dmss>; #dma-cells = <3>; diff --git a/Documentation/devicetree/bindings/dma/ti/k3-pktdma.yaml b/Documentation/devicetree/bindings/dma/ti/k3-pktdma.yaml index a69f62f854d8c3..11e064c0299466 100644 --- a/Documentation/devicetree/bindings/dma/ti/k3-pktdma.yaml +++ b/Documentation/devicetree/bindings/dma/ti/k3-pktdma.yaml @@ -45,14 +45,28 @@ properties: The second cell is the ASEL value for the channel reg: - maxItems: 4 + minItems: 4 + items: + - description: Packet DMA Control /Status Registers region + - description: RX Channel Realtime Registers region + - description: TX Channel Realtime Registers region + - description: Ring Realtime Registers region + - description: Ring Configuration Registers region + - description: TX Configuration Registers region + - description: RX Configuration Registers region + - description: RX Flow Configuration Registers region reg-names: + minItems: 4 items: - const: gcfg - const: rchanrt - const: tchanrt - const: ringrt + - const: ring + - const: tchan + - const: rchan + - const: rflow msi-parent: true @@ -136,8 +150,14 @@ examples: reg = <0x0 0x485c0000 0x0 0x100>, <0x0 0x4a800000 0x0 0x20000>, <0x0 0x4aa00000 0x0 0x40000>, - <0x0 0x4b800000 0x0 0x400000>; - reg-names = "gcfg", "rchanrt", "tchanrt", "ringrt"; + <0x0 0x4b800000 0x0 0x400000>, + <0x0 0x485e0000 0x0 0x20000>, + <0x0 0x484a0000 0x0 0x4000>, + <0x0 0x484c0000 0x0 0x2000>, + <0x0 0x48430000 0x0 0x4000>; + reg-names = "gcfg", "rchanrt", "tchanrt", "ringrt", + "ring", "tchan", "rchan", "rflow"; + msi-parent = <&inta_main_dmss>; #dma-cells = <2>; diff --git a/Documentation/devicetree/bindings/dma/ti/k3-udma.yaml b/Documentation/devicetree/bindings/dma/ti/k3-udma.yaml index 22f6c5e2f7f4b9..b18cf2bfdb5b14 100644 --- a/Documentation/devicetree/bindings/dma/ti/k3-udma.yaml +++ b/Documentation/devicetree/bindings/dma/ti/k3-udma.yaml @@ -69,13 +69,24 @@ properties: - ti,j721e-navss-mcu-udmap reg: - maxItems: 3 + minItems: 3 + items: + - description: UDMA-P Control /Status Registers region + - description: RX Channel Realtime Registers region + - description: TX Channel Realtime Registers region + - description: TX Configuration Registers region + - description: RX Configuration Registers region + - description: RX Flow Configuration Registers region reg-names: + minItems: 3 items: - const: gcfg - const: rchanrt - const: tchanrt + - const: tchan + - const: rchan + - const: rflow msi-parent: true @@ -158,8 +169,11 @@ examples: compatible = "ti,am654-navss-main-udmap"; reg = <0x0 0x31150000 0x0 0x100>, <0x0 0x34000000 0x0 0x100000>, - <0x0 0x35000000 0x0 0x100000>; - reg-names = "gcfg", "rchanrt", "tchanrt"; + <0x0 0x35000000 0x0 0x100000>, + <0x0 0x30b00000 0x0 0x20000>, + <0x0 0x30c00000 0x0 0x8000>, + <0x0 0x30d00000 0x0 0x4000>; + reg-names = "gcfg", "rchanrt", "tchanrt", "tchan", "rchan", "rflow"; #dma-cells = <1>; ti,ringacc = <&ringacc>; diff --git a/Documentation/devicetree/bindings/dts-coding-style.rst b/Documentation/devicetree/bindings/dts-coding-style.rst new file mode 100644 index 00000000000000..a9bdd2b59dcab6 --- /dev/null +++ b/Documentation/devicetree/bindings/dts-coding-style.rst @@ -0,0 +1,196 @@ +.. SPDX-License-Identifier: GPL-2.0 + +===================================== +Devicetree Sources (DTS) Coding Style +===================================== + +When writing Devicetree Sources (DTS) please observe below guidelines. They +should be considered complementary to any rules expressed already in +the Devicetree Specification and the dtc compiler (including W=1 and W=2 +builds). + +Individual architectures and subarchitectures can define additional rules, +making the coding style stricter. + +Naming and Valid Characters +--------------------------- + +The Devicetree Specification allows a broad range of characters in node +and property names, but this coding style narrows the range down to achieve +better code readability. + +1. Node and property names can use only the following characters: + + * Lowercase characters: [a-z] + * Digits: [0-9] + * Dash: - + +2. Labels can use only the following characters: + + * Lowercase characters: [a-z] + * Digits: [0-9] + * Underscore: _ + +3. Unless a bus defines differently, unit addresses shall use lowercase + hexadecimal digits, without leading zeros (padding). + +4. Hex values in properties, e.g. "reg", shall use lowercase hex. The address + part can be padded with leading zeros. + +Example:: + + gpi_dma2: dma-controller@a00000 { + compatible = "qcom,sm8550-gpi-dma", "qcom,sm6350-gpi-dma"; + reg = <0x0 0x00a00000 0x0 0x60000>; + } + +Order of Nodes +-------------- + +1. Nodes on any bus, thus using unit addresses for children, shall be + ordered by unit address in ascending order. + Alternatively for some subarchitectures, nodes of the same type can be + grouped together, e.g. all I2C controllers one after another even if this + breaks unit address ordering. + +2. Nodes without unit addresses shall be ordered alpha-numerically by the node + name. For a few node types, they can be ordered by the main property, e.g. + pin configuration states ordered by value of "pins" property. + +3. When extending nodes in the board DTS via &label, the entries shall be + ordered either alpha-numerically or by keeping the order from DTSI, where + the choice depends on the subarchitecture. + +The above-described ordering rules are easy to enforce during review, reduce +chances of conflicts for simultaneous additions of new nodes to a file and help +in navigating through the DTS source. + +Example:: + + /* SoC DTSI */ + + / { + cpus { + /* ... */ + }; + + psci { + /* ... */ + }; + + soc@0 { + dma: dma-controller@10000 { + /* ... */ + }; + + clk: clock-controller@80000 { + /* ... */ + }; + }; + }; + + /* Board DTS - alphabetical order */ + + &clk { + /* ... */ + }; + + &dma { + /* ... */ + }; + + /* Board DTS - alternative order, keep as DTSI */ + + &dma { + /* ... */ + }; + + &clk { + /* ... */ + }; + +Order of Properties in Device Node +---------------------------------- + +The following order of properties in device nodes is preferred: + +1. "compatible" +2. "reg" +3. "ranges" +4. Standard/common properties (defined by common bindings, e.g. without + vendor-prefixes) +5. Vendor-specific properties +6. "status" (if applicable) +7. Child nodes, where each node is preceded with a blank line + +The "status" property is by default "okay", thus it can be omitted. + +The above-described ordering follows this approach: + +1. Most important properties start the node: compatible then bus addressing to + match unit address. +2. Each node will have common properties in similar place. +3. Status is the last information to annotate that device node is or is not + finished (board resources are needed). + +Example:: + + /* SoC DTSI */ + + device_node: device-class@6789abc { + compatible = "vendor,device"; + reg = <0x0 0x06789abc 0x0 0xa123>; + ranges = <0x0 0x0 0x06789abc 0x1000>; + #dma-cells = <1>; + clocks = <&clock_controller 0>, <&clock_controller 1>; + clock-names = "bus", "host"; + vendor,custom-property = <2>; + status = "disabled"; + + child_node: child-class@100 { + reg = <0x100 0x200>; + /* ... */ + }; + }; + + /* Board DTS */ + + &device_node { + vdd-supply = <&board_vreg1>; + status = "okay"; + } + +Indentation +----------- + +1. Use indentation according to Documentation/process/coding-style.rst. +2. Each entry in arrays with multiple cells, e.g. "reg" with two IO addresses, + shall be enclosed in <>. +3. For arrays spanning across lines, it is preferred to align the continued + entries with opening < from the first line. + +Example:: + + thermal-sensor@c271000 { + compatible = "qcom,sm8550-tsens", "qcom,tsens-v2"; + reg = <0x0 0x0c271000 0x0 0x1000>, + <0x0 0x0c222000 0x0 0x1000>; + }; + +Organizing DTSI and DTS +----------------------- + +The DTSI and DTS files shall be organized in a way representing the common, +reusable parts of hardware. Typically, this means organizing DTSI and DTS files +into several files: + +1. DTSI with contents of the entire SoC, without nodes for hardware not present + on the SoC. +2. If applicable: DTSI with common or re-usable parts of the hardware, e.g. + entire System-on-Module. +3. DTS representing the board. + +Hardware components that are present on the board shall be placed in the +board DTS, not in the SoC or SoM DTSI. A partial exception is a common +external reference SoC input clock, which could be coded as a fixed-clock in +the SoC DTSI with its frequency provided by each board DTS. diff --git a/Documentation/devicetree/bindings/eeprom/at24.yaml b/Documentation/devicetree/bindings/eeprom/at24.yaml index b6864d0ee81e4b..1812ef31d5f1e9 100644 --- a/Documentation/devicetree/bindings/eeprom/at24.yaml +++ b/Documentation/devicetree/bindings/eeprom/at24.yaml @@ -123,6 +123,7 @@ properties: - enum: - onnn,cat24c04 - onnn,cat24c05 + - rohm,br24g04 - const: atmel,24c04 - items: - const: renesas,r1ex24016 diff --git a/Documentation/devicetree/bindings/firmware/qcom,scm.yaml b/Documentation/devicetree/bindings/firmware/qcom,scm.yaml index 0613a37a851af4..47d3d2d52acd2e 100644 --- a/Documentation/devicetree/bindings/firmware/qcom,scm.yaml +++ b/Documentation/devicetree/bindings/firmware/qcom,scm.yaml @@ -63,7 +63,9 @@ properties: - qcom,scm-sm8350 - qcom,scm-sm8450 - qcom,scm-sm8550 + - qcom,scm-sm8650 - qcom,scm-qcs404 + - qcom,scm-x1e80100 - const: qcom,scm clocks: @@ -178,21 +180,6 @@ allOf: minItems: 3 maxItems: 3 - # Interconnects - - if: - not: - properties: - compatible: - contains: - enum: - - qcom,scm-qdu1000 - - qcom,scm-sc8280xp - - qcom,scm-sm8450 - - qcom,scm-sm8550 - then: - properties: - interconnects: false - # Interrupts - if: not: @@ -202,6 +189,7 @@ allOf: enum: - qcom,scm-sm8450 - qcom,scm-sm8550 + - qcom,scm-sm8650 then: properties: interrupts: false diff --git a/Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.yaml b/Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.yaml index 822864488dcbad..8e584857ddd4fb 100644 --- a/Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.yaml +++ b/Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.yaml @@ -95,8 +95,8 @@ examples: versal_clk: clock-controller { #clock-cells = <1>; compatible = "xlnx,versal-clk"; - clocks = <&ref>, <&alt_ref>, <&pl_alt_ref>; - clock-names = "ref", "alt_ref", "pl_alt_ref"; + clocks = <&ref>, <&pl_alt_ref>; + clock-names = "ref", "pl_alt_ref"; }; }; diff --git a/Documentation/devicetree/bindings/fpga/altera-fpga2sdram-bridge.txt b/Documentation/devicetree/bindings/fpga/altera-fpga2sdram-bridge.txt deleted file mode 100644 index 5dd0ff0f7b4efe..00000000000000 --- a/Documentation/devicetree/bindings/fpga/altera-fpga2sdram-bridge.txt +++ /dev/null @@ -1,13 +0,0 @@ -Altera FPGA To SDRAM Bridge Driver - -Required properties: -- compatible : Should contain "altr,socfpga-fpga2sdram-bridge" - -See Documentation/devicetree/bindings/fpga/fpga-bridge.txt for generic bindings. - -Example: - fpga_bridge3: fpga-bridge@ffc25080 { - compatible = "altr,socfpga-fpga2sdram-bridge"; - reg = <0xffc25080 0x4>; - bridge-enable = <0>; - }; diff --git a/Documentation/devicetree/bindings/fpga/altera-freeze-bridge.txt b/Documentation/devicetree/bindings/fpga/altera-freeze-bridge.txt deleted file mode 100644 index 8b26fbcff3c62b..00000000000000 --- a/Documentation/devicetree/bindings/fpga/altera-freeze-bridge.txt +++ /dev/null @@ -1,20 +0,0 @@ -Altera Freeze Bridge Controller Driver - -The Altera Freeze Bridge Controller manages one or more freeze bridges. -The controller can freeze/disable the bridges which prevents signal -changes from passing through the bridge. The controller can also -unfreeze/enable the bridges which allows traffic to pass through the -bridge normally. - -Required properties: -- compatible : Should contain "altr,freeze-bridge-controller" -- regs : base address and size for freeze bridge module - -See Documentation/devicetree/bindings/fpga/fpga-bridge.txt for generic bindings. - -Example: - freeze-controller@100000450 { - compatible = "altr,freeze-bridge-controller"; - regs = <0x1000 0x10>; - bridge-enable = <0>; - }; diff --git a/Documentation/devicetree/bindings/fpga/altera-hps2fpga-bridge.txt b/Documentation/devicetree/bindings/fpga/altera-hps2fpga-bridge.txt deleted file mode 100644 index 68cce3945b103d..00000000000000 --- a/Documentation/devicetree/bindings/fpga/altera-hps2fpga-bridge.txt +++ /dev/null @@ -1,36 +0,0 @@ -Altera FPGA/HPS Bridge Driver - -Required properties: -- regs : base address and size for AXI bridge module -- compatible : Should contain one of: - "altr,socfpga-lwhps2fpga-bridge", - "altr,socfpga-hps2fpga-bridge", or - "altr,socfpga-fpga2hps-bridge" -- resets : Phandle and reset specifier for this bridge's reset -- clocks : Clocks used by this module. - -See Documentation/devicetree/bindings/fpga/fpga-bridge.txt for generic bindings. - -Example: - fpga_bridge0: fpga-bridge@ff400000 { - compatible = "altr,socfpga-lwhps2fpga-bridge"; - reg = <0xff400000 0x100000>; - resets = <&rst LWHPS2FPGA_RESET>; - clocks = <&l4_main_clk>; - bridge-enable = <0>; - }; - - fpga_bridge1: fpga-bridge@ff500000 { - compatible = "altr,socfpga-hps2fpga-bridge"; - reg = <0xff500000 0x10000>; - resets = <&rst HPS2FPGA_RESET>; - clocks = <&l4_main_clk>; - bridge-enable = <1>; - }; - - fpga_bridge2: fpga-bridge@ff600000 { - compatible = "altr,socfpga-fpga2hps-bridge"; - reg = <0xff600000 0x100000>; - resets = <&rst FPGA2HPS_RESET>; - clocks = <&l4_main_clk>; - }; diff --git a/Documentation/devicetree/bindings/fpga/altr,freeze-bridge-controller.yaml b/Documentation/devicetree/bindings/fpga/altr,freeze-bridge-controller.yaml new file mode 100644 index 00000000000000..fccffeebb2560f --- /dev/null +++ b/Documentation/devicetree/bindings/fpga/altr,freeze-bridge-controller.yaml @@ -0,0 +1,41 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/fpga/altr,freeze-bridge-controller.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Altera Freeze Bridge Controller + +description: + The Altera Freeze Bridge Controller manages one or more freeze bridges. + The controller can freeze/disable the bridges which prevents signal + changes from passing through the bridge. The controller can also + unfreeze/enable the bridges which allows traffic to pass through the bridge + normally. + +maintainers: + - Xu Yilun + +allOf: + - $ref: fpga-bridge.yaml# + +properties: + compatible: + const: altr,freeze-bridge-controller + + reg: + maxItems: 1 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + fpga-bridge@100000450 { + compatible = "altr,freeze-bridge-controller"; + reg = <0x1000 0x10>; + bridge-enable = <0>; + }; diff --git a/Documentation/devicetree/bindings/fpga/altr,socfpga-fpga2sdram-bridge.yaml b/Documentation/devicetree/bindings/fpga/altr,socfpga-fpga2sdram-bridge.yaml new file mode 100644 index 00000000000000..22b58453c5ff52 --- /dev/null +++ b/Documentation/devicetree/bindings/fpga/altr,socfpga-fpga2sdram-bridge.yaml @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/fpga/altr,socfpga-fpga2sdram-bridge.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Altera FPGA To SDRAM Bridge + +maintainers: + - Xu Yilun + +allOf: + - $ref: fpga-bridge.yaml# + +properties: + compatible: + const: altr,socfpga-fpga2sdram-bridge + + reg: + maxItems: 1 + +required: + - compatible + +unevaluatedProperties: false + +examples: + - | + fpga-bridge@ffc25080 { + compatible = "altr,socfpga-fpga2sdram-bridge"; + reg = <0xffc25080 0x4>; + bridge-enable = <0>; + }; diff --git a/Documentation/devicetree/bindings/fpga/altr,socfpga-hps2fpga-bridge.yaml b/Documentation/devicetree/bindings/fpga/altr,socfpga-hps2fpga-bridge.yaml new file mode 100644 index 00000000000000..d19c6660d6c9a8 --- /dev/null +++ b/Documentation/devicetree/bindings/fpga/altr,socfpga-hps2fpga-bridge.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/fpga/altr,socfpga-hps2fpga-bridge.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Altera FPGA/HPS Bridge + +maintainers: + - Xu Yilun + +allOf: + - $ref: fpga-bridge.yaml# + +properties: + compatible: + enum: + - altr,socfpga-lwhps2fpga-bridge + - altr,socfpga-hps2fpga-bridge + - altr,socfpga-fpga2hps-bridge + + reg: + maxItems: 1 + + resets: + maxItems: 1 + + clocks: + maxItems: 1 + +required: + - compatible + - reg + - clocks + - resets + +unevaluatedProperties: false + +examples: + - | + #include + + fpga-bridge@ff400000 { + compatible = "altr,socfpga-lwhps2fpga-bridge"; + reg = <0xff400000 0x100000>; + bridge-enable = <0>; + clocks = <&l4_main_clk>; + resets = <&rst LWHPS2FPGA_RESET>; + }; diff --git a/Documentation/devicetree/bindings/fpga/fpga-bridge.txt b/Documentation/devicetree/bindings/fpga/fpga-bridge.txt deleted file mode 100644 index 72e06917288aa2..00000000000000 --- a/Documentation/devicetree/bindings/fpga/fpga-bridge.txt +++ /dev/null @@ -1,13 +0,0 @@ -FPGA Bridge Device Tree Binding - -Optional properties: -- bridge-enable : 0 if driver should disable bridge at startup - 1 if driver should enable bridge at startup - Default is to leave bridge in current state. - -Example: - fpga_bridge3: fpga-bridge@ffc25080 { - compatible = "altr,socfpga-fpga2sdram-bridge"; - reg = <0xffc25080 0x4>; - bridge-enable = <0>; - }; diff --git a/Documentation/devicetree/bindings/fpga/fpga-bridge.yaml b/Documentation/devicetree/bindings/fpga/fpga-bridge.yaml new file mode 100644 index 00000000000000..1ccb2aa187269b --- /dev/null +++ b/Documentation/devicetree/bindings/fpga/fpga-bridge.yaml @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/fpga/fpga-bridge.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: FPGA Bridge + +maintainers: + - Michal Simek + +properties: + $nodename: + pattern: "^fpga-bridge(@.*|-([0-9]|[1-9][0-9]+))?$" + + bridge-enable: + description: | + 0 if driver should disable bridge at startup + 1 if driver should enable bridge at startup + Default is to leave bridge in current state. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [ 0, 1 ] + +additionalProperties: true + +examples: + - | + fpga-bridge { + bridge-enable = <0>; + }; diff --git a/Documentation/devicetree/bindings/fpga/xlnx,pr-decoupler.yaml b/Documentation/devicetree/bindings/fpga/xlnx,pr-decoupler.yaml index a7d4b8e59e1930..5bf731f9d99a35 100644 --- a/Documentation/devicetree/bindings/fpga/xlnx,pr-decoupler.yaml +++ b/Documentation/devicetree/bindings/fpga/xlnx,pr-decoupler.yaml @@ -9,6 +9,9 @@ title: Xilinx LogiCORE Partial Reconfig Decoupler/AXI shutdown manager Softcore maintainers: - Nava kishore Manne +allOf: + - $ref: fpga-bridge.yaml# + description: | The Xilinx LogiCORE Partial Reconfig(PR) Decoupler manages one or more decouplers/fpga bridges. The controller can decouple/disable the bridges @@ -51,7 +54,7 @@ required: - clocks - clock-names -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/gnss/u-blox,neo-6m.yaml b/Documentation/devicetree/bindings/gnss/u-blox,neo-6m.yaml index 4835a280b3bff5..cd80668182b608 100644 --- a/Documentation/devicetree/bindings/gnss/u-blox,neo-6m.yaml +++ b/Documentation/devicetree/bindings/gnss/u-blox,neo-6m.yaml @@ -28,6 +28,9 @@ properties: port or the USB host-controller port to which this device is attached, depending on the bus used. Required for the DDC, SPI or USB busses. + reset-gpios: + maxItems: 1 + vcc-supply: description: > Main voltage regulator @@ -49,10 +52,13 @@ unevaluatedProperties: false examples: - | + #include + serial { gnss { compatible = "u-blox,neo-8"; v-bckp-supply = <&gnss_v_bckp_reg>; vcc-supply = <&gnss_vcc_reg>; + reset-gpios = <&gpio 1 GPIO_ACTIVE_LOW>; }; }; diff --git a/Documentation/devicetree/bindings/gpio/brcm,brcmstb-gpio.yaml b/Documentation/devicetree/bindings/gpio/brcm,brcmstb-gpio.yaml index 4a896ff7edc5fa..a1e71c974e79ce 100644 --- a/Documentation/devicetree/bindings/gpio/brcm,brcmstb-gpio.yaml +++ b/Documentation/devicetree/bindings/gpio/brcm,brcmstb-gpio.yaml @@ -72,7 +72,7 @@ required: - reg - gpio-controller - "#gpio-cells" - - "brcm,gpio-bank-widths" + - brcm,gpio-bank-widths additionalProperties: false diff --git a/Documentation/devicetree/bindings/gpio/nuvoton,sgpio.yaml b/Documentation/devicetree/bindings/gpio/nuvoton,sgpio.yaml new file mode 100644 index 00000000000000..9e32e54aeb244d --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/nuvoton,sgpio.yaml @@ -0,0 +1,87 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpio/nuvoton,sgpio.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Nuvoton SGPIO controller + +maintainers: + - Jim LIU + +description: | + This SGPIO controller is for NUVOTON NPCM7xx and NPCM8xx SoC and detailed + information is in the NPCM7XX/8XX SERIAL I/O EXPANSION INTERFACE section. + Nuvoton NPCM7xx SGPIO module is combines a serial to parallel IC (HC595) + and a parallel to serial IC (HC165). + Clock is a division of the APB3 clock. + This interface has 4 pins (D_out , D_in, S_CLK, LDSH). + NPCM7xx/NPCM8xx have two sgpio modules. Each module can support up + to 64 output pins, and up to 64 input pins, the pin is only for GPI or GPO. + GPIO pins can be programmed to support the following options + - Support interrupt option for each input port and various interrupt + sensitivity options (level-high, level-low, edge-high, edge-low) + - ngpios is number of nuvoton,input-ngpios GPIO lines and nuvoton,output-ngpios GPIO lines. + nuvoton,input-ngpios GPIO lines is only for GPI. + nuvoton,output-ngpios GPIO lines is only for GPO. + +properties: + compatible: + enum: + - nuvoton,npcm750-sgpio + - nuvoton,npcm845-sgpio + + reg: + maxItems: 1 + + gpio-controller: true + + '#gpio-cells': + const: 2 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + nuvoton,input-ngpios: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + The numbers of GPIO's exposed. GPIO lines are only for GPI. + minimum: 0 + maximum: 64 + + nuvoton,output-ngpios: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + The numbers of GPIO's exposed. GPIO lines are only for GPO. + minimum: 0 + maximum: 64 + +required: + - compatible + - reg + - gpio-controller + - '#gpio-cells' + - interrupts + - nuvoton,input-ngpios + - nuvoton,output-ngpios + - clocks + +additionalProperties: false + +examples: + - | + #include + #include + gpio8: gpio@101000 { + compatible = "nuvoton,npcm750-sgpio"; + reg = <0x101000 0x200>; + clocks = <&clk NPCM7XX_CLK_APB3>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + nuvoton,input-ngpios = <64>; + nuvoton,output-ngpios = <64>; + }; diff --git a/Documentation/devicetree/bindings/gpio/realtek,rtd-gpio.yaml b/Documentation/devicetree/bindings/gpio/realtek,rtd-gpio.yaml new file mode 100644 index 00000000000000..dd768db37a986f --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/realtek,rtd-gpio.yaml @@ -0,0 +1,69 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +# Copyright 2023 Realtek Semiconductor Corporation +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpio/realtek,rtd-gpio.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Realtek DHC GPIO controller + +maintainers: + - Tzuyi Chang + +description: + The GPIO controller is designed for the Realtek DHC (Digital Home Center) + RTD series SoC family, which are high-definition media processor SoCs. + +properties: + compatible: + enum: + - realtek,rtd1295-misc-gpio + - realtek,rtd1295-iso-gpio + - realtek,rtd1315e-iso-gpio + - realtek,rtd1319-iso-gpio + - realtek,rtd1319d-iso-gpio + - realtek,rtd1395-iso-gpio + - realtek,rtd1619-iso-gpio + - realtek,rtd1619b-iso-gpio + + reg: + items: + - description: GPIO controller registers + - description: GPIO interrupt registers + + interrupts: + items: + - description: Interrupt number of the assert GPIO interrupt, which is + triggered when there is a rising edge. + - description: Interrupt number of the deassert GPIO interrupt, which is + triggered when there is a falling edge. + + gpio-ranges: true + + gpio-controller: true + + "#gpio-cells": + const: 2 + +required: + - compatible + - reg + - interrupts + - gpio-ranges + - gpio-controller + - "#gpio-cells" + +additionalProperties: false + +examples: + - | + gpio@100 { + compatible = "realtek,rtd1319d-iso-gpio"; + reg = <0x100 0x100>, + <0x0 0xb0>; + interrupt-parent = <&iso_irq_mux>; + interrupts = <19>, <20>; + gpio-ranges = <&pinctrl 0 0 82>; + gpio-controller; + #gpio-cells = <2>; + }; diff --git a/Documentation/devicetree/bindings/gpio/rockchip,gpio-bank.yaml b/Documentation/devicetree/bindings/gpio/rockchip,gpio-bank.yaml index affd823c881d27..d76987ce8e50e6 100644 --- a/Documentation/devicetree/bindings/gpio/rockchip,gpio-bank.yaml +++ b/Documentation/devicetree/bindings/gpio/rockchip,gpio-bank.yaml @@ -41,6 +41,13 @@ properties: "#interrupt-cells": const: 2 +patternProperties: + "^.+-hog(-[0-9]+)?$": + type: object + + required: + - gpio-hog + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/gpio/snps,dw-apb-gpio.yaml b/Documentation/devicetree/bindings/gpio/snps,dw-apb-gpio.yaml index eefe7b345286f5..ab2afc0e4153dc 100644 --- a/Documentation/devicetree/bindings/gpio/snps,dw-apb-gpio.yaml +++ b/Documentation/devicetree/bindings/gpio/snps,dw-apb-gpio.yaml @@ -65,6 +65,8 @@ patternProperties: minItems: 1 maxItems: 32 + gpio-ranges: true + ngpios: default: 32 minimum: 1 diff --git a/Documentation/devicetree/bindings/gpio/xlnx,gpio-xilinx.yaml b/Documentation/devicetree/bindings/gpio/xlnx,gpio-xilinx.yaml index c1060e5fcef3a9..d3d8a2e143ed25 100644 --- a/Documentation/devicetree/bindings/gpio/xlnx,gpio-xilinx.yaml +++ b/Documentation/devicetree/bindings/gpio/xlnx,gpio-xilinx.yaml @@ -126,7 +126,7 @@ examples: - | #include - gpio@e000a000 { + gpio@a0020000 { compatible = "xlnx,xps-gpio-1.00.a"; reg = <0xa0020000 0x10000>; #gpio-cells = <2>; diff --git a/Documentation/devicetree/bindings/gpio/xlnx,zynqmp-gpio-modepin.yaml b/Documentation/devicetree/bindings/gpio/xlnx,zynqmp-gpio-modepin.yaml index 56143f1fe84ac7..b1fd632718d496 100644 --- a/Documentation/devicetree/bindings/gpio/xlnx,zynqmp-gpio-modepin.yaml +++ b/Documentation/devicetree/bindings/gpio/xlnx,zynqmp-gpio-modepin.yaml @@ -23,6 +23,8 @@ properties: "#gpio-cells": const: 2 + label: true + required: - compatible - gpio-controller @@ -37,6 +39,7 @@ examples: compatible = "xlnx,zynqmp-gpio-modepin"; gpio-controller; #gpio-cells = <2>; + label = "modepin"; }; }; diff --git a/Documentation/devicetree/bindings/gpu/arm,mali-midgard.yaml b/Documentation/devicetree/bindings/gpu/arm,mali-midgard.yaml index ca02baba5526de..0801da33a385b4 100644 --- a/Documentation/devicetree/bindings/gpu/arm,mali-midgard.yaml +++ b/Documentation/devicetree/bindings/gpu/arm,mali-midgard.yaml @@ -40,6 +40,11 @@ properties: - rockchip,rk3288-mali - samsung,exynos5433-mali - const: arm,mali-t760 + - items: + - enum: + - samsung,exynos7-mali + - const: samsung,exynos5433-mali + - const: arm,mali-t760 - items: - enum: - rockchip,rk3399-mali diff --git a/Documentation/devicetree/bindings/gpu/arm,mali-utgard.yaml b/Documentation/devicetree/bindings/gpu/arm,mali-utgard.yaml index 0fae1ef013be8b..abd4aa335fbceb 100644 --- a/Documentation/devicetree/bindings/gpu/arm,mali-utgard.yaml +++ b/Documentation/devicetree/bindings/gpu/arm,mali-utgard.yaml @@ -29,6 +29,7 @@ properties: - allwinner,sun50i-a64-mali - rockchip,rk3036-mali - rockchip,rk3066-mali + - rockchip,rk3128-mali - rockchip,rk3188-mali - rockchip,rk3228-mali - samsung,exynos4210-mali diff --git a/Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml b/Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml index dae55b8a267b08..dc078ceeca9ac3 100644 --- a/Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml +++ b/Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml @@ -17,6 +17,7 @@ properties: compatible: enum: - brcm,2711-v3d + - brcm,2712-v3d - brcm,7268-v3d - brcm,7278-v3d diff --git a/Documentation/devicetree/bindings/gpu/img,powervr.yaml b/Documentation/devicetree/bindings/gpu/img,powervr.yaml new file mode 100644 index 00000000000000..a13298f1a18275 --- /dev/null +++ b/Documentation/devicetree/bindings/gpu/img,powervr.yaml @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (c) 2023 Imagination Technologies Ltd. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpu/img,powervr.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Imagination Technologies PowerVR and IMG GPU + +maintainers: + - Frank Binns + +properties: + compatible: + items: + - enum: + - ti,am62-gpu + - const: img,img-axe # IMG AXE GPU model/revision is fully discoverable + + reg: + maxItems: 1 + + clocks: + minItems: 1 + maxItems: 3 + + clock-names: + items: + - const: core + - const: mem + - const: sys + minItems: 1 + + interrupts: + maxItems: 1 + + power-domains: + maxItems: 1 + +required: + - compatible + - reg + - clocks + - clock-names + - interrupts + +additionalProperties: false + +allOf: + - if: + properties: + compatible: + contains: + const: ti,am62-gpu + then: + properties: + clocks: + maxItems: 1 + +examples: + - | + #include + #include + #include + + gpu@fd00000 { + compatible = "ti,am62-gpu", "img,img-axe"; + reg = <0x0fd00000 0x20000>; + clocks = <&k3_clks 187 0>; + clock-names = "core"; + interrupts = ; + power-domains = <&k3_pds 187 TI_SCI_PD_EXCLUSIVE>; + }; diff --git a/Documentation/devicetree/bindings/gpu/samsung-g2d.yaml b/Documentation/devicetree/bindings/gpu/samsung-g2d.yaml index e7daae86257890..132aaa49597b6b 100644 --- a/Documentation/devicetree/bindings/gpu/samsung-g2d.yaml +++ b/Documentation/devicetree/bindings/gpu/samsung-g2d.yaml @@ -22,36 +22,20 @@ properties: interrupts: maxItems: 1 - clocks: {} - clock-names: {} - iommus: {} - power-domains: {} - -if: - properties: - compatible: - contains: - const: samsung,exynos5250-g2d - -then: - properties: - clocks: - items: - - description: fimg2d clock - clock-names: - items: - - const: fimg2d - -else: - properties: - clocks: - items: - - description: sclk_fimg2d clock - - description: fimg2d clock - clock-names: - items: - - const: sclk_fimg2d - - const: fimg2d + clocks: + minItems: 1 + maxItems: 2 + + clock-names: + minItems: 1 + maxItems: 2 + + iommus: + minItems: 1 + maxItems: 2 + + power-domains: + maxItems: 1 required: - compatible @@ -60,6 +44,33 @@ required: - clocks - clock-names +allOf: + - if: + properties: + compatible: + contains: + const: samsung,exynos5250-g2d + + then: + properties: + clocks: + items: + - description: fimg2d clock + clock-names: + items: + - const: fimg2d + + else: + properties: + clocks: + items: + - description: sclk_fimg2d clock + - description: fimg2d clock + clock-names: + items: + - const: sclk_fimg2d + - const: fimg2d + additionalProperties: false examples: diff --git a/Documentation/devicetree/bindings/gpu/samsung-rotator.yaml b/Documentation/devicetree/bindings/gpu/samsung-rotator.yaml index d60626ffb28e22..18bf44e06e8f30 100644 --- a/Documentation/devicetree/bindings/gpu/samsung-rotator.yaml +++ b/Documentation/devicetree/bindings/gpu/samsung-rotator.yaml @@ -12,10 +12,11 @@ maintainers: properties: compatible: enum: - - "samsung,s5pv210-rotator" - - "samsung,exynos4210-rotator" - - "samsung,exynos4212-rotator" - - "samsung,exynos5250-rotator" + - samsung,s5pv210-rotator + - samsung,exynos4210-rotator + - samsung,exynos4212-rotator + - samsung,exynos5250-rotator + reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/gpu/samsung-scaler.yaml b/Documentation/devicetree/bindings/gpu/samsung-scaler.yaml index 5317ac64426af7..9fb530e65d0e8b 100644 --- a/Documentation/devicetree/bindings/gpu/samsung-scaler.yaml +++ b/Documentation/devicetree/bindings/gpu/samsung-scaler.yaml @@ -21,40 +21,20 @@ properties: interrupts: maxItems: 1 - clocks: {} - clock-names: {} - iommus: {} - power-domains: {} - -if: - properties: - compatible: - contains: - const: samsung,exynos5420-scaler - -then: - properties: - clocks: - items: - - description: mscl clock - - clock-names: - items: - - const: mscl - -else: - properties: - clocks: - items: - - description: pclk clock - - description: aclk clock - - description: aclk_xiu clock - - clock-names: - items: - - const: pclk - - const: aclk - - const: aclk_xiu + clocks: + minItems: 1 + maxItems: 3 + + clock-names: + minItems: 1 + maxItems: 3 + + iommus: + minItems: 1 + maxItems: 2 + + power-domains: + maxItems: 1 required: - compatible @@ -63,6 +43,39 @@ required: - clocks - clock-names +allOf: + - if: + properties: + compatible: + contains: + const: samsung,exynos5420-scaler + + then: + properties: + clocks: + items: + - description: mscl clock + clock-names: + items: + - const: mscl + iommus: + minItems: 2 + + else: + properties: + clocks: + items: + - description: pclk clock + - description: aclk clock + - description: aclk_xiu clock + clock-names: + items: + - const: pclk + - const: aclk + - const: aclk_xiu + iommus: + maxItems: 1 + additionalProperties: false examples: diff --git a/Documentation/devicetree/bindings/hwinfo/samsung,exynos-chipid.yaml b/Documentation/devicetree/bindings/hwinfo/samsung,exynos-chipid.yaml index 95cbdcb56efe41..780ccb5ee9b466 100644 --- a/Documentation/devicetree/bindings/hwinfo/samsung,exynos-chipid.yaml +++ b/Documentation/devicetree/bindings/hwinfo/samsung,exynos-chipid.yaml @@ -11,9 +11,21 @@ maintainers: properties: compatible: - enum: - - samsung,exynos4210-chipid - - samsung,exynos850-chipid + oneOf: + - enum: + - samsung,exynos4210-chipid + - samsung,exynos850-chipid + - items: + - enum: + - samsung,exynos5433-chipid + - samsung,exynos7-chipid + - const: samsung,exynos4210-chipid + - items: + - enum: + - samsung,exynos7885-chipid + - samsung,exynosautov9-chipid + - samsung,exynosautov920-chipid + - const: samsung,exynos850-chipid reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/hwmon/gpio-fan.txt b/Documentation/devicetree/bindings/hwmon/gpio-fan.txt deleted file mode 100644 index f4cfa350f6a144..00000000000000 --- a/Documentation/devicetree/bindings/hwmon/gpio-fan.txt +++ /dev/null @@ -1,41 +0,0 @@ -Bindings for fan connected to GPIO lines - -Required properties: -- compatible : "gpio-fan" - -Optional properties: -- gpios: Specifies the pins that map to bits in the control value, - ordered MSB-->LSB. -- gpio-fan,speed-map: A mapping of possible fan RPM speeds and the - control value that should be set to achieve them. This array - must have the RPM values in ascending order. -- alarm-gpios: This pin going active indicates something is wrong with - the fan, and a udev event will be fired. -- #cooling-cells: If used as a cooling device, must be <2> - Also see: - Documentation/devicetree/bindings/thermal/thermal-cooling-devices.yaml - min and max states are derived from the speed-map of the fan. - -Note: At least one the "gpios" or "alarm-gpios" properties must be set. - -Examples: - - gpio_fan { - compatible = "gpio-fan"; - gpios = <&gpio1 14 1 - &gpio1 13 1>; - gpio-fan,speed-map = <0 0 - 3000 1 - 6000 2>; - alarm-gpios = <&gpio1 15 1>; - }; - gpio_fan_cool: gpio_fan { - compatible = "gpio-fan"; - gpios = <&gpio2 14 1 - &gpio2 13 1>; - gpio-fan,speed-map = <0 0>, - <3000 1>, - <6000 2>; - alarm-gpios = <&gpio2 15 1>; - #cooling-cells = <2>; /* min followed by max */ - }; diff --git a/Documentation/devicetree/bindings/hwmon/gpio-fan.yaml b/Documentation/devicetree/bindings/hwmon/gpio-fan.yaml new file mode 100644 index 00000000000000..7f30cfc8735067 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/gpio-fan.yaml @@ -0,0 +1,60 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/hwmon/gpio-fan.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Fan connected to GPIO lines + +maintainers: + - Rob Herring + +properties: + compatible: + const: gpio-fan + + gpios: + description: | + Specifies the pins that map to bits in the control value, + ordered MSB-->LSB. + minItems: 1 + maxItems: 7 + + alarm-gpios: + maxItems: 1 + + gpio-fan,speed-map: + $ref: /schemas/types.yaml#/definitions/uint32-matrix + minItems: 2 + maxItems: 127 + items: + items: + - description: fan speed in RPMs + - description: control value + description: | + A mapping of possible fan RPM speeds and the + control value that should be set to achieve them. This array + must have the RPM values in ascending order. + + '#cooling-cells': + const: 2 + +required: + - compatible + - gpios + - gpio-fan,speed-map + +additionalProperties: false + +examples: + - | + gpio-fan { + compatible = "gpio-fan"; + gpios = <&gpio2 14 1 + &gpio2 13 1>; + gpio-fan,speed-map = < 0 0>, + <3000 1>, + <6000 2>; + alarm-gpios = <&gpio2 15 1>; + #cooling-cells = <2>; /* min followed by max */ + }; diff --git a/Documentation/devicetree/bindings/hwmon/iio-hwmon.yaml b/Documentation/devicetree/bindings/hwmon/iio-hwmon.yaml index e5b24782f4481e..be5c7d4579bb07 100644 --- a/Documentation/devicetree/bindings/hwmon/iio-hwmon.yaml +++ b/Documentation/devicetree/bindings/hwmon/iio-hwmon.yaml @@ -19,7 +19,7 @@ properties: io-channels: minItems: 1 - maxItems: 8 # Should be enough + maxItems: 51 # Should be enough description: > List of phandles to ADC channels to read the monitoring values diff --git a/Documentation/devicetree/bindings/hwmon/lltc,ltc4286.yaml b/Documentation/devicetree/bindings/hwmon/lltc,ltc4286.yaml new file mode 100644 index 00000000000000..98ca163d348688 --- /dev/null +++ b/Documentation/devicetree/bindings/hwmon/lltc,ltc4286.yaml @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/hwmon/lltc,ltc4286.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: LTC4286 power monitors + +maintainers: + - Delphine CC Chiu + +properties: + compatible: + enum: + - lltc,ltc4286 + - lltc,ltc4287 + + reg: + maxItems: 1 + + adi,vrange-low-enable: + description: + This property is a bool parameter to represent the + voltage range is 25.6 volts or 102.4 volts for this chip. + The default is 102.4 volts. + type: boolean + + shunt-resistor-micro-ohms: + description: + Resistor value micro-ohms. + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + power-monitor@40 { + compatible = "lltc,ltc4286"; + reg = <0x40>; + adi,vrange-low-enable; + shunt-resistor-micro-ohms = <300>; + }; + }; diff --git a/Documentation/devicetree/bindings/hwmon/lm75.yaml b/Documentation/devicetree/bindings/hwmon/lm75.yaml index 0b69897f0c63fc..ed269e428a3d93 100644 --- a/Documentation/devicetree/bindings/hwmon/lm75.yaml +++ b/Documentation/devicetree/bindings/hwmon/lm75.yaml @@ -14,6 +14,7 @@ properties: compatible: enum: - adi,adt75 + - ams,as6200 - atmel,at30ts74 - dallas,ds1775 - dallas,ds75 @@ -48,10 +49,28 @@ properties: vs-supply: description: phandle to the regulator that provides the +VS supply + interrupts: + maxItems: 1 + required: - compatible - reg +allOf: + - if: + not: + properties: + compatible: + contains: + enum: + - ams,as6200 + - ti,tmp100 + - ti,tmp101 + - ti,tmp112 + then: + properties: + interrupts: false + additionalProperties: false examples: @@ -66,3 +85,17 @@ examples: vs-supply = <&vs>; }; }; + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + temperature-sensor@48 { + compatible = "ams,as6200"; + reg = <0x48>; + vs-supply = <&vs>; + interrupt-parent = <&gpio1>; + interrupts = <17 IRQ_TYPE_EDGE_BOTH>; + }; + }; diff --git a/Documentation/devicetree/bindings/i2c/i2c-exynos5.yaml b/Documentation/devicetree/bindings/i2c/i2c-exynos5.yaml index 3e52a0db6c41b1..df9c57bca2a89c 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-exynos5.yaml +++ b/Documentation/devicetree/bindings/i2c/i2c-exynos5.yaml @@ -25,7 +25,16 @@ properties: - samsung,exynos5250-hsi2c # Exynos5250 and Exynos5420 - samsung,exynos5260-hsi2c # Exynos5260 - samsung,exynos7-hsi2c # Exynos7 - - samsung,exynosautov9-hsi2c # ExynosAutoV9 and Exynos850 + - samsung,exynosautov9-hsi2c + - items: + - enum: + - samsung,exynos5433-hsi2c + - tesla,fsd-hsi2c + - const: samsung,exynos7-hsi2c + - items: + - enum: + - samsung,exynos850-hsi2c + - const: samsung,exynosautov9-hsi2c - const: samsung,exynos5-hsi2c # Exynos5250 and Exynos5420 deprecated: true diff --git a/Documentation/devicetree/bindings/i2c/samsung,s3c2410-i2c.yaml b/Documentation/devicetree/bindings/i2c/samsung,s3c2410-i2c.yaml index b204e35e4f8d11..1303502cf26553 100644 --- a/Documentation/devicetree/bindings/i2c/samsung,s3c2410-i2c.yaml +++ b/Documentation/devicetree/bindings/i2c/samsung,s3c2410-i2c.yaml @@ -11,14 +11,20 @@ maintainers: properties: compatible: - enum: - - samsung,s3c2410-i2c - - samsung,s3c2440-i2c - # For s3c2440-like I2C used inside HDMIPHY block found on several SoCs: - - samsung,s3c2440-hdmiphy-i2c - # For s3c2440-like I2C used as a host to SATA PHY controller on an - # internal bus: - - samsung,exynos5-sata-phy-i2c + oneOf: + - enum: + - samsung,s3c2410-i2c + - samsung,s3c2440-i2c + # For s3c2440-like I2C used inside HDMIPHY block found on several SoCs: + - samsung,s3c2440-hdmiphy-i2c + # For s3c2440-like I2C used as a host to SATA PHY controller on an + # internal bus: + - samsung,exynos5-sata-phy-i2c + - items: + - enum: + - samsung,exynos7885-i2c + - samsung,exynos850-i2c + - const: samsung,s3c2440-i2c '#address-cells': const: 1 diff --git a/Documentation/devicetree/bindings/i2c/st,stm32-i2c.yaml b/Documentation/devicetree/bindings/i2c/st,stm32-i2c.yaml index 94b75d9f66cdb7..1b31b87c1800a0 100644 --- a/Documentation/devicetree/bindings/i2c/st,stm32-i2c.yaml +++ b/Documentation/devicetree/bindings/i2c/st,stm32-i2c.yaml @@ -19,6 +19,7 @@ allOf: - st,stm32f7-i2c - st,stm32mp13-i2c - st,stm32mp15-i2c + - st,stm32mp25-i2c then: properties: i2c-scl-rising-time-ns: @@ -41,6 +42,30 @@ allOf: clock-frequency: enum: [100000, 400000] + - if: + properties: + compatible: + contains: + enum: + - st,stm32f4-i2c + - st,stm32f7-i2c + - st,stm32mp13-i2c + - st,stm32mp15-i2c + then: + properties: + interrupts: + minItems: 2 + + interrupt-names: + minItems: 2 + else: + properties: + interrupts: + maxItems: 1 + + interrupt-names: + maxItems: 1 + properties: compatible: enum: @@ -48,6 +73,7 @@ properties: - st,stm32f7-i2c - st,stm32mp13-i2c - st,stm32mp15-i2c + - st,stm32mp25-i2c reg: maxItems: 1 @@ -56,11 +82,13 @@ properties: items: - description: interrupt ID for I2C event - description: interrupt ID for I2C error + minItems: 1 interrupt-names: items: - const: event - const: error + minItems: 1 resets: maxItems: 1 diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml index ce7ba634643c69..ddec9747436c29 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7091r5.yaml @@ -4,36 +4,92 @@ $id: http://devicetree.org/schemas/iio/adc/adi,ad7091r5.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Analog Devices AD7091R5 4-Channel 12-Bit ADC +title: Analog Devices AD7091R-2/-4/-5/-8 Multi-Channel 12-Bit ADCs maintainers: - Michael Hennerich + - Marcelo Schmitt description: | - Analog Devices AD7091R5 4-Channel 12-Bit ADC + Analog Devices AD7091R5 4-Channel 12-Bit ADC supporting I2C interface https://www.analog.com/media/en/technical-documentation/data-sheets/ad7091r-5.pdf + Analog Devices AD7091R-2/AD7091R-4/AD7091R-8 2-/4-/8-Channel 12-Bit ADCs + supporting SPI interface + https://www.analog.com/media/en/technical-documentation/data-sheets/AD7091R-2_7091R-4_7091R-8.pdf properties: compatible: enum: + - adi,ad7091r2 + - adi,ad7091r4 - adi,ad7091r5 + - adi,ad7091r8 reg: maxItems: 1 + vdd-supply: + description: + Provide VDD power to the sensor (VDD range is from 2.7V to 5.25V). + + vdrive-supply: + description: + Determines the voltage level at which the interface logic will operate. + The V_drive voltage range is from 1.8V to 5.25V and must not exceed VDD by + more than 0.3V. + vref-supply: description: Phandle to the vref power supply - interrupts: + convst-gpios: + description: + GPIO connected to the CONVST pin. + This logic input is used to initiate conversions on the analog + input channels. maxItems: 1 + reset-gpios: + maxItems: 1 + + interrupts: + description: + Interrupt for signaling when conversion results exceed the high limit for + ADC readings or fall below the low limit for them. Interrupt source must + be attached to ALERT/BUSY/GPO0 pin. + maxItems: 1 required: - compatible - reg -additionalProperties: false +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + + # AD7091R-2 does not have ALERT/BUSY/GPO pin + - if: + properties: + compatible: + contains: + enum: + - adi,ad7091r2 + then: + properties: + interrupts: false + + - if: + properties: + compatible: + contains: + enum: + - adi,ad7091r2 + - adi,ad7091r4 + - adi,ad7091r8 + then: + required: + - convst-gpios + +unevaluatedProperties: false examples: - | @@ -51,4 +107,22 @@ examples: interrupt-parent = <&gpio>; }; }; + - | + #include + #include + spi { + #address-cells = <1>; + #size-cells = <0>; + + adc@0 { + compatible = "adi,ad7091r8"; + reg = <0x0>; + spi-max-frequency = <1000000>; + vref-supply = <&adc_vref>; + convst-gpios = <&gpio 25 GPIO_ACTIVE_LOW>; + reset-gpios = <&gpio 27 GPIO_ACTIVE_LOW>; + interrupts = <22 IRQ_TYPE_EDGE_FALLING>; + interrupt-parent = <&gpio>; + }; + }; ... diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml index 5fcc8dd012f17c..be2616ff9af685 100644 --- a/Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml +++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7780.yaml @@ -80,9 +80,9 @@ examples: compatible = "adi,ad7780"; reg = <0>; - avdd-supply = <&vdd_supply>; - powerdown-gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>; - adi,gain-gpios = <&gpio1 5 GPIO_ACTIVE_LOW>; + avdd-supply = <&vdd_supply>; + powerdown-gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>; + adi,gain-gpios = <&gpio1 5 GPIO_ACTIVE_LOW>; adi,filter-gpios = <&gpio2 15 GPIO_ACTIVE_LOW>; }; }; diff --git a/Documentation/devicetree/bindings/iio/adc/maxim,max34408.yaml b/Documentation/devicetree/bindings/iio/adc/maxim,max34408.yaml new file mode 100644 index 00000000000000..4cba856e8d4732 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/maxim,max34408.yaml @@ -0,0 +1,139 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/maxim,max34408.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Maxim MAX34408/MAX34409 current monitors with overcurrent control + +maintainers: + - Ivan Mikhaylov + +description: | + The MAX34408/MAX34409 are two- and four-channel current monitors that are + configured and monitored with a standard I2C/SMBus serial interface. Each + unidirectional current sensor offers precision high-side operation with a + low full-scale sense voltage. The devices automatically sequence through + two or four channels and collect the current-sense samples and average them + to reduce the effect of impulse noise. The raw ADC samples are compared to + user-programmable digital thresholds to indicate overcurrent conditions. + Overcurrent conditions trigger a hardware output to provide an immediate + indication to shut down any necessary external circuitry. + + Specifications about the devices can be found at: + https://www.analog.com/media/en/technical-documentation/data-sheets/MAX34408-MAX34409.pdf + +properties: + compatible: + enum: + - maxim,max34408 + - maxim,max34409 + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + powerdown-gpios: + description: + Shutdown Output. Open-drain output. This output transitions to high impedance + when any of the digital comparator thresholds are exceeded as long as the ENA + pin is high. + maxItems: 1 + + powerdown-status-gpios: + description: + SHTDN Enable Input. CMOS digital input. Connect to GND to clear the latch and + unconditionally deassert (force low) the SHTDN output and reset the shutdown + delay. Connect to VDD to enable normal latch operation of the SHTDN output. + maxItems: 1 + + vdd-supply: true + +patternProperties: + "^channel@[0-3]$": + $ref: adc.yaml + type: object + description: + Represents the internal channels of the ADC. + + properties: + reg: + items: + - minimum: 0 + maximum: 3 + + maxim,rsense-val-micro-ohms: + description: + Adjust the Rsense value to monitor higher or lower current levels for + input. + enum: [250, 500, 1000, 5000, 10000, 50000, 100000, 200000, 500000] + default: 1000 + + required: + - reg + - maxim,rsense-val-micro-ohms + + unevaluatedProperties: false + +required: + - compatible + - reg + +allOf: + - if: + properties: + compatible: + contains: + const: maxim,max34408 + then: + patternProperties: + "^channel@[2-3]$": false + "^channel@[0-1]$": + properties: + reg: + maximum: 1 + else: + patternProperties: + "^channel@[0-3]$": + properties: + reg: + maximum: 3 + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + adc@1e { + compatible = "maxim,max34409"; + reg = <0x1e>; + powerdown-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>; + powerdown-status-gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>; + + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0x0>; + maxim,rsense-val-micro-ohms = <5000>; + }; + + channel@1 { + reg = <0x1>; + maxim,rsense-val-micro-ohms = <10000>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/iio/adc/qcom,spmi-iadc.yaml b/Documentation/devicetree/bindings/iio/adc/qcom,spmi-iadc.yaml index 73def67fbe015b..5ed893ef5c189d 100644 --- a/Documentation/devicetree/bindings/iio/adc/qcom,spmi-iadc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/qcom,spmi-iadc.yaml @@ -25,7 +25,7 @@ properties: - const: qcom,spmi-iadc reg: - description: IADC base address and length in the SPMI PMIC register map + description: IADC base address in the SPMI PMIC register map maxItems: 1 qcom,external-resistor-micro-ohms: @@ -50,15 +50,17 @@ additionalProperties: false examples: - | #include - spmi { + + pmic { #address-cells = <1>; #size-cells = <0>; - pmic_iadc: adc@3600 { + + adc@3600 { compatible = "qcom,pm8941-iadc", "qcom,spmi-iadc"; reg = <0x3600>; interrupts = <0x0 0x36 0x0 IRQ_TYPE_EDGE_RISING>; qcom,external-resistor-micro-ohms = <10000>; - #io-channel-cells = <1>; + #io-channel-cells = <1>; }; }; ... diff --git a/Documentation/devicetree/bindings/iio/adc/qcom,spmi-rradc.yaml b/Documentation/devicetree/bindings/iio/adc/qcom,spmi-rradc.yaml index b3a626389870f1..f39bc92c2b99bb 100644 --- a/Documentation/devicetree/bindings/iio/adc/qcom,spmi-rradc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/qcom,spmi-rradc.yaml @@ -43,9 +43,9 @@ examples: #address-cells = <1>; #size-cells = <0>; - pmic_rradc: adc@4500 { + adc@4500 { compatible = "qcom,pmi8998-rradc"; reg = <0x4500>; - #io-channel-cells = <1>; + #io-channel-cells = <1>; }; }; diff --git a/Documentation/devicetree/bindings/iio/adc/qcom,spmi-vadc.yaml b/Documentation/devicetree/bindings/iio/adc/qcom,spmi-vadc.yaml index ad7d6fc49de58e..40fa0710f1f0f8 100644 --- a/Documentation/devicetree/bindings/iio/adc/qcom,spmi-vadc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/qcom,spmi-vadc.yaml @@ -236,11 +236,11 @@ additionalProperties: false examples: - | - spmi { + pmic { #address-cells = <1>; #size-cells = <0>; - /* VADC node */ - pmic_vadc: adc@3100 { + + adc@3100 { compatible = "qcom,spmi-vadc"; reg = <0x3100>; interrupts = <0x0 0x31 0x0 0x1>; @@ -281,9 +281,10 @@ examples: #include #include - spmi { + pmic { #address-cells = <1>; #size-cells = <0>; + adc@3100 { reg = <0x3100>; compatible = "qcom,spmi-adc7"; diff --git a/Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.yaml b/Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.yaml index 582d0a03b8147d..4e40f6bed5dbe1 100644 --- a/Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.yaml @@ -11,18 +11,23 @@ maintainers: properties: compatible: - enum: - - samsung,exynos-adc-v1 # Exynos5250 - - samsung,exynos-adc-v2 - - samsung,exynos3250-adc - - samsung,exynos4212-adc # Exynos4212 and Exynos4412 - - samsung,exynos7-adc - - samsung,s3c2410-adc - - samsung,s3c2416-adc - - samsung,s3c2440-adc - - samsung,s3c2443-adc - - samsung,s3c6410-adc - - samsung,s5pv210-adc + oneOf: + - enum: + - samsung,exynos-adc-v1 # Exynos5250 + - samsung,exynos-adc-v2 + - samsung,exynos3250-adc + - samsung,exynos4212-adc # Exynos4212 and Exynos4412 + - samsung,exynos7-adc + - samsung,s3c2410-adc + - samsung,s3c2416-adc + - samsung,s3c2440-adc + - samsung,s3c2443-adc + - samsung,s3c6410-adc + - samsung,s5pv210-adc + - items: + - enum: + - samsung,exynos5433-adc + - const: samsung,exynos7-adc reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/iio/adc/ti,palmas-gpadc.yaml b/Documentation/devicetree/bindings/iio/adc/ti,palmas-gpadc.yaml index 720c16a108d4e2..f94057d8f60586 100644 --- a/Documentation/devicetree/bindings/iio/adc/ti,palmas-gpadc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/ti,palmas-gpadc.yaml @@ -67,19 +67,4 @@ required: - compatible - "#io-channel-cells" -examples: - - | - #include - pmic { - compatible = "ti,twl6035-pmic", "ti,palmas-pmic"; - adc { - compatible = "ti,palmas-gpadc"; - interrupts = <18 0>, - <16 0>, - <17 0>; - #io-channel-cells = <1>; - ti,channel0-current-microamp = <5>; - ti,channel3-current-microamp = <10>; - }; - }; ... diff --git a/Documentation/devicetree/bindings/iio/amplifiers/adi,hmc425a.yaml b/Documentation/devicetree/bindings/iio/amplifiers/adi,hmc425a.yaml index 2ee6080deac7c6..67de9d4e3a1df6 100644 --- a/Documentation/devicetree/bindings/iio/amplifiers/adi,hmc425a.yaml +++ b/Documentation/devicetree/bindings/iio/amplifiers/adi,hmc425a.yaml @@ -12,6 +12,9 @@ maintainers: description: | Digital Step Attenuator IIO devices with gpio interface. Offer various frequency and attenuation ranges. + ADRF5750 2 dB LSB, 4-Bit, Silicon Digital Attenuator, 10 MHz to 60 GHz + https://www.analog.com/media/en/technical-documentation/data-sheets/adrf5740.pdf + HMC425A 0.5 dB LSB GaAs MMIC 6-BIT DIGITAL POSITIVE CONTROL ATTENUATOR, 2.2 - 8.0 GHz https://www.analog.com/media/en/technical-documentation/data-sheets/hmc425A.pdf @@ -22,6 +25,7 @@ description: | properties: compatible: enum: + - adi,adrf5740 - adi,hmc425a - adi,hmc540s diff --git a/Documentation/devicetree/bindings/iio/chemical/aosong,ags02ma.yaml b/Documentation/devicetree/bindings/iio/chemical/aosong,ags02ma.yaml new file mode 100644 index 00000000000000..35e7b094e878ad --- /dev/null +++ b/Documentation/devicetree/bindings/iio/chemical/aosong,ags02ma.yaml @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/chemical/aosong,ags02ma.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Aosong AGS02MA VOC Sensor + +description: | + AGS02MA is an TVOC (Total Volatile Organic Compounds) i2c sensor with default + address of 0x1a. + + Datasheet: + https://asairsensors.com/wp-content/uploads/2021/09/AGS02MA.pdf + +maintainers: + - Anshul Dalal + +properties: + compatible: + enum: + - aosong,ags02ma + + reg: + maxItems: 1 + + vdd-supply: true + +required: + - compatible + - reg + - vdd-supply + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + voc-sensor@1a { + compatible = "aosong,ags02ma"; + reg = <0x1a>; + vdd-supply = <&vdd_regulator>; + }; + }; diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5791.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5791.yaml index 3a84739736f620..c81285d84db7a2 100644 --- a/Documentation/devicetree/bindings/iio/dac/adi,ad5791.yaml +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5791.yaml @@ -26,6 +26,11 @@ properties: vdd-supply: true vss-supply: true + adi,rbuf-gain2-en: + description: Specify to allow an external amplifier to be connected in a + gain of two configuration. + type: boolean + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/iio/dac/microchip,mcp4821.yaml b/Documentation/devicetree/bindings/iio/dac/microchip,mcp4821.yaml new file mode 100644 index 00000000000000..0dc577c339181d --- /dev/null +++ b/Documentation/devicetree/bindings/iio/dac/microchip,mcp4821.yaml @@ -0,0 +1,86 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/dac/microchip,mcp4821.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Microchip MCP4821 and similar DACs + +description: | + Supports MCP48x1 (single channel) and MCP48x2 (dual channel) series of DACs. + Device supports simplex communication over SPI in Mode 0 and Mode 3. + + +---------+--------------+-------------+ + | Device | Resolution | Channels | + |---------|--------------|-------------| + | MCP4801 | 8-bit | 1 | + | MCP4802 | 8-bit | 2 | + | MCP4811 | 10-bit | 1 | + | MCP4812 | 10-bit | 2 | + | MCP4821 | 12-bit | 1 | + | MCP4822 | 12-bit | 2 | + +---------+--------------+-------------+ + + Datasheet: + MCP48x1: https://ww1.microchip.com/downloads/en/DeviceDoc/22244B.pdf + MCP48x2: https://ww1.microchip.com/downloads/en/DeviceDoc/20002249B.pdf + +maintainers: + - Anshul Dalal + +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +properties: + compatible: + enum: + - microchip,mcp4801 + - microchip,mcp4802 + - microchip,mcp4811 + - microchip,mcp4812 + - microchip,mcp4821 + - microchip,mcp4822 + + reg: + maxItems: 1 + + vdd-supply: true + + ldac-gpios: + description: | + Active Low LDAC (Latch DAC Input) pin used to update the DAC output. + maxItems: 1 + + powerdown-gpios: + description: | + Active Low SHDN pin used to enter the shutdown mode. + maxItems: 1 + + spi-cpha: true + spi-cpol: true + +required: + - compatible + - reg + - vdd-supply + +additionalProperties: false + +examples: + - | + #include + + spi { + #address-cells = <1>; + #size-cells = <0>; + + dac@0 { + compatible = "microchip,mcp4821"; + reg = <0>; + vdd-supply = <&vdd_regulator>; + ldac-gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>; + powerdown-gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>; + spi-cpha; + spi-cpol; + }; + }; diff --git a/Documentation/devicetree/bindings/iio/humidity/ti,hdc3020.yaml b/Documentation/devicetree/bindings/iio/humidity/ti,hdc3020.yaml new file mode 100644 index 00000000000000..7f6d0f9edc75e3 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/humidity/ti,hdc3020.yaml @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/humidity/ti,hdc3020.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: HDC3020/HDC3021/HDC3022 humidity and temperature iio sensors + +maintainers: + - Li peiyu <579lpy@gmail.com> + - Javier Carrasco + +description: + https://www.ti.com/lit/ds/symlink/hdc3020.pdf + + The HDC302x is an integrated capacitive based relative humidity (RH) + and temperature sensor. + +properties: + compatible: + oneOf: + - items: + - enum: + - ti,hdc3021 + - ti,hdc3022 + - const: ti,hdc3020 + - const: ti,hdc3020 + + interrupts: + maxItems: 1 + + vdd-supply: true + + reg: + maxItems: 1 + +required: + - compatible + - reg + - vdd-supply + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + humidity-sensor@47 { + compatible = "ti,hdc3021", "ti,hdc3020"; + reg = <0x47>; + vdd-supply = <&vcc_3v3>; + }; + }; diff --git a/Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml b/Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml index 4e43c80e5119f0..4cacc9948726f0 100644 --- a/Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml +++ b/Documentation/devicetree/bindings/iio/imu/adi,adis16460.yaml @@ -25,6 +25,10 @@ properties: spi-cpol: true + spi-cs-inactive-delay-ns: + minimum: 16000 + default: 16000 + interrupts: maxItems: 1 diff --git a/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml index c73533c54588b1..9b7ad609f7dbe1 100644 --- a/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml +++ b/Documentation/devicetree/bindings/iio/imu/adi,adis16475.yaml @@ -47,6 +47,10 @@ properties: spi-max-frequency: maximum: 2000000 + spi-cs-inactive-delay-ns: + minimum: 16000 + default: 16000 + interrupts: maxItems: 1 diff --git a/Documentation/devicetree/bindings/iio/imu/bosch,bmi323.yaml b/Documentation/devicetree/bindings/iio/imu/bosch,bmi323.yaml new file mode 100644 index 00000000000000..64ef26e1966964 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/imu/bosch,bmi323.yaml @@ -0,0 +1,77 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/imu/bosch,bmi323.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Bosch BMI323 6-Axis IMU + +maintainers: + - Jagath Jog J + +description: + BMI323 is a 6-axis inertial measurement unit that supports acceleration and + gyroscopic measurements with hardware fifo buffering. Sensor also provides + events information such as motion, steps, orientation, single and double + tap detection. + +properties: + compatible: + const: bosch,bmi323 + + reg: + maxItems: 1 + + vdd-supply: true + vddio-supply: true + + interrupts: + minItems: 1 + maxItems: 2 + + interrupt-names: + minItems: 1 + maxItems: 2 + items: + enum: + - INT1 + - INT2 + + drive-open-drain: + description: + set if the specified interrupt pin should be configured as + open drain. If not set, defaults to push-pull. + + mount-matrix: + description: + an optional 3x3 mounting rotation matrix. + +required: + - compatible + - reg + - vdd-supply + - vddio-supply + +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +unevaluatedProperties: false + +examples: + - | + // Example for I2C + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + imu@68 { + compatible = "bosch,bmi323"; + reg = <0x68>; + vddio-supply = <&vddio>; + vdd-supply = <&vdd>; + interrupt-parent = <&gpio1>; + interrupts = <29 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "INT1"; + }; + }; diff --git a/Documentation/devicetree/bindings/iio/light/liteon,ltr390.yaml b/Documentation/devicetree/bindings/iio/light/liteon,ltr390.yaml new file mode 100644 index 00000000000000..5d98ef2af74d66 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/light/liteon,ltr390.yaml @@ -0,0 +1,56 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/light/liteon,ltr390.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Lite-On LTR390 ALS and UV Sensor + +description: | + The Lite-On LTR390 is an ALS (Ambient Light Sensor) and a UV sensor in a + single package with i2c address of 0x53. + + Datasheet: + https://optoelectronics.liteon.com/upload/download/DS86-2015-0004/LTR-390UV_Final_%20DS_V1%201.pdf + +maintainers: + - Anshul Dalal + +properties: + compatible: + enum: + - liteon,ltr390 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + description: | + Level interrupt pin with open drain output. + The sensor pulls this pin low when the measured reading is greater than + some configured threshold. + + vdd-supply: true + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + light-sensor@53 { + compatible = "liteon,ltr390"; + reg = <0x53>; + interrupts = <18 IRQ_TYPE_EDGE_FALLING>; + vdd-supply = <&vdd_regulator>; + }; + }; diff --git a/Documentation/devicetree/bindings/iio/light/vishay,veml6075.yaml b/Documentation/devicetree/bindings/iio/light/vishay,veml6075.yaml new file mode 100644 index 00000000000000..abee04cd126e41 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/light/vishay,veml6075.yaml @@ -0,0 +1,39 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/light/vishay,veml6075.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Vishay VEML6075 UVA and UVB sensor + +maintainers: + - Javier Carrasco + +properties: + compatible: + const: vishay,veml6075 + + reg: + maxItems: 1 + + vdd-supply: true + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + uv-sensor@10 { + compatible = "vishay,veml6075"; + reg = <0x10>; + vdd-supply = <&vdd_reg>; + }; + }; +... diff --git a/Documentation/devicetree/bindings/iio/pressure/honeywell,hsc030pa.yaml b/Documentation/devicetree/bindings/iio/pressure/honeywell,hsc030pa.yaml new file mode 100644 index 00000000000000..65a24ed67b3ccd --- /dev/null +++ b/Documentation/devicetree/bindings/iio/pressure/honeywell,hsc030pa.yaml @@ -0,0 +1,142 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/pressure/honeywell,hsc030pa.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Honeywell TruStability HSC and SSC pressure sensor series + +description: | + support for Honeywell TruStability HSC and SSC digital pressure sensor + series. + + These sensors have either an I2C, an SPI or an analog interface. Only the + digital versions are supported by this driver. + + There are 118 models with different pressure ranges available in each family. + The vendor calls them "HSC series" and "SSC series". All of them have an + identical programming model but differ in pressure range, unit and transfer + function. + + To support different models one needs to specify the pressure range as well + as the transfer function. Pressure range can either be provided via + pressure-triplet (directly extracted from the part number) or in case it's + a custom chip via numerical range limits converted to pascals. + + The transfer function defines the ranges of raw conversion values delivered + by the sensor. pmin-pascal and pmax-pascal corespond to the minimum and + maximum pressure that can be measured. + + Please note that in case of an SPI-based sensor, the clock signal should not + exceed 800kHz and the MOSI signal is not required. + + Specifications about the devices can be found at: + https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/trustability-hsc-series/documents/sps-siot-trustability-hsc-series-high-accuracy-board-mount-pressure-sensors-50099148-a-en-ciid-151133.pdf + https://prod-edam.honeywell.com/content/dam/honeywell-edam/sps/siot/en-us/products/sensors/pressure-sensors/board-mount-pressure-sensors/trustability-ssc-series/documents/sps-siot-trustability-ssc-series-standard-accuracy-board-mount-pressure-sensors-50099533-a-en-ciid-151134.pdf + +maintainers: + - Petre Rodan + +properties: + compatible: + const: honeywell,hsc030pa + + reg: + maxItems: 1 + + honeywell,transfer-function: + description: | + Transfer function which defines the range of valid values delivered by + the sensor. + 0 - A, 10% to 90% of 2^14 + 1 - B, 5% to 95% of 2^14 + 2 - C, 5% to 85% of 2^14 + 3 - F, 4% to 94% of 2^14 + enum: [0, 1, 2, 3] + $ref: /schemas/types.yaml#/definitions/uint32 + + honeywell,pressure-triplet: + description: | + Case-sensitive five character string that defines pressure range, unit + and type as part of the device nomenclature. In the unlikely case of a + custom chip, set to "NA" and provide pmin-pascal and pmax-pascal. + enum: [001BA, 1.6BA, 2.5BA, 004BA, 006BA, 010BA, 1.6MD, 2.5MD, 004MD, + 006MD, 010MD, 016MD, 025MD, 040MD, 060MD, 100MD, 160MD, 250MD, + 400MD, 600MD, 001BD, 1.6BD, 2.5BD, 004BD, 2.5MG, 004MG, 006MG, + 010MG, 016MG, 025MG, 040MG, 060MG, 100MG, 160MG, 250MG, 400MG, + 600MG, 001BG, 1.6BG, 2.5BG, 004BG, 006BG, 010BG, 100KA, 160KA, + 250KA, 400KA, 600KA, 001GA, 160LD, 250LD, 400LD, 600LD, 001KD, + 1.6KD, 2.5KD, 004KD, 006KD, 010KD, 016KD, 025KD, 040KD, 060KD, + 100KD, 160KD, 250KD, 400KD, 250LG, 400LG, 600LG, 001KG, 1.6KG, + 2.5KG, 004KG, 006KG, 010KG, 016KG, 025KG, 040KG, 060KG, 100KG, + 160KG, 250KG, 400KG, 600KG, 001GG, 015PA, 030PA, 060PA, 100PA, + 150PA, 0.5ND, 001ND, 002ND, 004ND, 005ND, 010ND, 020ND, 030ND, + 001PD, 005PD, 015PD, 030PD, 060PD, 001NG, 002NG, 004NG, 005NG, + 010NG, 020NG, 030NG, 001PG, 005PG, 015PG, 030PG, 060PG, 100PG, + 150PG, NA] + $ref: /schemas/types.yaml#/definitions/string + + honeywell,pmin-pascal: + description: | + Minimum pressure value the sensor can measure in pascal. + To be specified only if honeywell,pressure-triplet is set to "NA". + + honeywell,pmax-pascal: + description: | + Maximum pressure value the sensor can measure in pascal. + To be specified only if honeywell,pressure-triplet is set to "NA". + + vdd-supply: + description: + Provide VDD power to the sensor (either 3.3V or 5V depending on the chip) + + spi-max-frequency: + maximum: 800000 + +required: + - compatible + - reg + - honeywell,transfer-function + - honeywell,pressure-triplet + +additionalProperties: false + +dependentSchemas: + honeywell,pmin-pascal: + properties: + honeywell,pressure-triplet: + const: NA + honeywell,pmax-pascal: + properties: + honeywell,pressure-triplet: + const: NA + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + pressure@28 { + compatible = "honeywell,hsc030pa"; + reg = <0x28>; + honeywell,transfer-function = <0>; + honeywell,pressure-triplet = "030PA"; + }; + }; + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + + pressure@0 { + compatible = "honeywell,hsc030pa"; + reg = <0>; + spi-max-frequency = <800000>; + honeywell,transfer-function = <0>; + honeywell,pressure-triplet = "NA"; + honeywell,pmin-pascal = <0>; + honeywell,pmax-pascal = <200000>; + }; + }; +... diff --git a/Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml b/Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml index b31f8120f14ed8..d9e903fbfd99ea 100644 --- a/Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml +++ b/Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml @@ -53,12 +53,10 @@ properties: honeywell,pmin-pascal: description: Minimum pressure value the sensor can measure in pascal. - $ref: /schemas/types.yaml#/definitions/uint32 honeywell,pmax-pascal: description: Maximum pressure value the sensor can measure in pascal. - $ref: /schemas/types.yaml#/definitions/uint32 honeywell,transfer-function: description: | diff --git a/Documentation/devicetree/bindings/iio/temperature/melexis,mlx90632.yaml b/Documentation/devicetree/bindings/iio/temperature/melexis,mlx90632.yaml index 4a55e7f25ae7cb..03bb5d4fa8b579 100644 --- a/Documentation/devicetree/bindings/iio/temperature/melexis,mlx90632.yaml +++ b/Documentation/devicetree/bindings/iio/temperature/melexis,mlx90632.yaml @@ -4,7 +4,7 @@ $id: http://devicetree.org/schemas/iio/temperature/melexis,mlx90632.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Melexis MLX90632 contactless Infra Red temperature sensor +title: Melexis MLX90632 and MLX90635 contactless Infra Red temperature sensor maintainers: - Crt Mori @@ -27,9 +27,24 @@ description: | Since measured object emissivity effects Infra Red energy emitted, emissivity should be set before requesting the object temperature. + https://www.melexis.com/en/documents/documentation/datasheets/datasheet-mlx90635 + + MLX90635 is most suitable for consumer applications where + measured object temperature is in range between -20 to 100 degrees + Celsius with relative error of measurement 2 degree Celsius in + object temperature range for industrial applications, while just 0.2 + degree Celsius for human body measurement applications. Since it can + operate and measure ambient temperature in range of -20 to 85 degrees + Celsius it is suitable also for outdoor use. + + Since measured object emissivity effects Infra Red energy emitted, + emissivity should be set before requesting the object temperature. + properties: compatible: - const: melexis,mlx90632 + enum: + - melexis,mlx90632 + - melexis,mlx90635 reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml b/Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml new file mode 100644 index 00000000000000..d2cafa38a5442e --- /dev/null +++ b/Documentation/devicetree/bindings/iio/temperature/microchip,mcp9600.yaml @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/temperature/microchip,mcp9600.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Microchip MCP9600 thermocouple EMF converter + +maintainers: + - Andrew Hepp + +description: + https://ww1.microchip.com/downloads/en/DeviceDoc/MCP960X-Data-Sheet-20005426.pdf + +properties: + compatible: + const: microchip,mcp9600 + + reg: + maxItems: 1 + + interrupts: + minItems: 1 + maxItems: 6 + + interrupt-names: + minItems: 1 + maxItems: 6 + items: + enum: + - open-circuit + - short-circuit + - alert1 + - alert2 + - alert3 + - alert4 + + thermocouple-type: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Type of thermocouple (THERMOCOUPLE_TYPE_K if omitted). + Use defines in dt-bindings/iio/temperature/thermocouple.h. + Supported types are B, E, J, K, N, R, S, T. + + vdd-supply: true + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #include + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + temperature-sensor@60 { + compatible = "microchip,mcp9600"; + reg = <0x60>; + interrupt-parent = <&gpio>; + interrupts = <25 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "open-circuit"; + thermocouple-type = ; + vdd-supply = <&vdd>; + }; + }; diff --git a/Documentation/devicetree/bindings/index.rst b/Documentation/devicetree/bindings/index.rst index d9002a3a0abb36..cc1fbdc0565726 100644 --- a/Documentation/devicetree/bindings/index.rst +++ b/Documentation/devicetree/bindings/index.rst @@ -4,6 +4,7 @@ :maxdepth: 1 ABI + dts-coding-style writing-bindings writing-schema submitting-patches diff --git a/Documentation/devicetree/bindings/input/adafruit,seesaw-gamepad.yaml b/Documentation/devicetree/bindings/input/adafruit,seesaw-gamepad.yaml new file mode 100644 index 00000000000000..5e86f6de69784c --- /dev/null +++ b/Documentation/devicetree/bindings/input/adafruit,seesaw-gamepad.yaml @@ -0,0 +1,63 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/adafruit,seesaw-gamepad.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Adafruit Mini I2C Gamepad with seesaw + +maintainers: + - Anshul Dalal + +description: | + Adafruit Mini I2C Gamepad + + +-----------------------------+ + | ___ | + | / \ (X) | + | | S | __ __ (Y) (A) | + | \___/ |ST| |SE| (B) | + | | + +-----------------------------+ + + S -> 10-bit precision bidirectional analog joystick + ST -> Start + SE -> Select + X, A, B, Y -> Digital action buttons + + Datasheet: https://cdn-learn.adafruit.com/downloads/pdf/gamepad-qt.pdf + Product page: https://www.adafruit.com/product/5743 + Arduino Driver: https://github.com/adafruit/Adafruit_Seesaw + +properties: + compatible: + const: adafruit,seesaw-gamepad + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + description: + The gamepad's IRQ pin triggers a rising edge if interrupts are enabled. + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + joystick@50 { + compatible = "adafruit,seesaw-gamepad"; + interrupts = <18 IRQ_TYPE_EDGE_RISING>; + reg = <0x50>; + }; + }; diff --git a/Documentation/devicetree/bindings/input/elan,ekth6915.yaml b/Documentation/devicetree/bindings/input/elan,ekth6915.yaml index 3e2d216c6432b2..dc4ac41f244117 100644 --- a/Documentation/devicetree/bindings/input/elan,ekth6915.yaml +++ b/Documentation/devicetree/bindings/input/elan,ekth6915.yaml @@ -18,8 +18,9 @@ allOf: properties: compatible: - items: - - const: elan,ekth6915 + enum: + - elan,ekth6915 + - ilitek,ili2901 reg: const: 0x10 diff --git a/Documentation/devicetree/bindings/input/gpio-keys.yaml b/Documentation/devicetree/bindings/input/gpio-keys.yaml index 159cd9d9fe573c..cc78c215292130 100644 --- a/Documentation/devicetree/bindings/input/gpio-keys.yaml +++ b/Documentation/devicetree/bindings/input/gpio-keys.yaml @@ -31,7 +31,23 @@ patternProperties: maxItems: 1 interrupts: - maxItems: 1 + oneOf: + - items: + - description: Optional key interrupt or wakeup interrupt + - items: + - description: Key interrupt + - description: Wakeup interrupt + + interrupt-names: + description: + Optional interrupt names, can be used to specify a separate dedicated + wake-up interrupt in addition to the gpio irq + oneOf: + - items: + - enum: [ irq, wakeup ] + - items: + - const: irq + - const: wakeup label: description: Descriptive name of the key. @@ -97,6 +113,20 @@ patternProperties: - required: - gpios + allOf: + - if: + properties: + interrupts: + minItems: 2 + required: + - interrupts + then: + properties: + interrupt-names: + minItems: 2 + required: + - interrupt-names + dependencies: wakeup-event-action: [ wakeup-source ] linux,input-value: [ gpios ] @@ -137,6 +167,15 @@ examples: linux,code = <108>; interrupts = <1 IRQ_TYPE_EDGE_FALLING>; }; + + key-wakeup { + label = "GPIO Key WAKEUP"; + linux,code = <143>; + interrupts-extended = <&intc 2 IRQ_TYPE_EDGE_FALLING>, + <&intc_wakeup 0 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "irq", "wakeup"; + wakeup-source; + }; }; ... diff --git a/Documentation/devicetree/bindings/input/gpio-mouse.txt b/Documentation/devicetree/bindings/input/gpio-mouse.txt deleted file mode 100644 index 519510a11af981..00000000000000 --- a/Documentation/devicetree/bindings/input/gpio-mouse.txt +++ /dev/null @@ -1,32 +0,0 @@ -Device-Tree bindings for GPIO attached mice - -This simply uses standard GPIO handles to define a simple mouse connected -to 5-7 GPIO lines. - -Required properties: - - compatible: must be "gpio-mouse" - - scan-interval-ms: The scanning interval in milliseconds - - up-gpios: GPIO line phandle to the line indicating "up" - - down-gpios: GPIO line phandle to the line indicating "down" - - left-gpios: GPIO line phandle to the line indicating "left" - - right-gpios: GPIO line phandle to the line indicating "right" - -Optional properties: - - button-left-gpios: GPIO line handle to the left mouse button - - button-middle-gpios: GPIO line handle to the middle mouse button - - button-right-gpios: GPIO line handle to the right mouse button -Example: - -#include - -gpio-mouse { - compatible = "gpio-mouse"; - scan-interval-ms = <50>; - up-gpios = <&gpio0 0 GPIO_ACTIVE_LOW>; - down-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>; - left-gpios = <&gpio0 2 GPIO_ACTIVE_LOW>; - right-gpios = <&gpio0 3 GPIO_ACTIVE_LOW>; - button-left-gpios = <&gpio0 4 GPIO_ACTIVE_LOW>; - button-middle-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>; - button-right-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>; -}; diff --git a/Documentation/devicetree/bindings/input/gpio-mouse.yaml b/Documentation/devicetree/bindings/input/gpio-mouse.yaml new file mode 100644 index 00000000000000..3928ec6aff1dcd --- /dev/null +++ b/Documentation/devicetree/bindings/input/gpio-mouse.yaml @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/gpio-mouse.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: GPIO attached mouse + +description: | + This simply uses standard GPIO handles to define a simple mouse connected + to 5-7 GPIO lines. + +maintainers: + - Anshul Dalal + +properties: + compatible: + const: gpio-mouse + + scan-interval-ms: + maxItems: 1 + + up-gpios: + maxItems: 1 + + down-gpios: + maxItems: 1 + + left-gpios: + maxItems: 1 + + right-gpios: + maxItems: 1 + + button-left-gpios: + maxItems: 1 + + button-middle-gpios: + maxItems: 1 + + button-right-gpios: + maxItems: 1 + +required: + - compatible + - scan-interval-ms + - up-gpios + - down-gpios + - left-gpios + - right-gpios + +additionalProperties: false + +examples: + - | + #include + + gpio-mouse { + compatible = "gpio-mouse"; + scan-interval-ms = <50>; + up-gpios = <&gpio0 0 GPIO_ACTIVE_LOW>; + down-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>; + left-gpios = <&gpio0 2 GPIO_ACTIVE_LOW>; + right-gpios = <&gpio0 3 GPIO_ACTIVE_LOW>; + button-left-gpios = <&gpio0 4 GPIO_ACTIVE_LOW>; + button-middle-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>; + button-right-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>; + }; diff --git a/Documentation/devicetree/bindings/input/iqs269a.yaml b/Documentation/devicetree/bindings/input/iqs269a.yaml index 3c430d38594f11..2c3f693b8982c4 100644 --- a/Documentation/devicetree/bindings/input/iqs269a.yaml +++ b/Documentation/devicetree/bindings/input/iqs269a.yaml @@ -9,6 +9,9 @@ title: Azoteq IQS269A Capacitive Touch Controller maintainers: - Jeff LaBundy +allOf: + - $ref: input.yaml# + description: | The Azoteq IQS269A is an 8-channel capacitive touch controller that features additional Hall-effect and inductive sensing capabilities. @@ -17,7 +20,10 @@ description: | properties: compatible: - const: azoteq,iqs269a + enum: + - azoteq,iqs269a + - azoteq,iqs269a-00 + - azoteq,iqs269a-d0 reg: maxItems: 1 @@ -204,6 +210,73 @@ properties: default: 1 description: Specifies the slider coordinate filter strength. + azoteq,touch-hold-ms: + multipleOf: 256 + minimum: 256 + maximum: 65280 + default: 5120 + description: + Specifies the length of time (in ms) for which the channel selected by + 'azoteq,gpio3-select' must be held in a state of touch in order for an + approximately 60-ms pulse to be asserted on the GPIO4 pin. + + linux,keycodes: + minItems: 1 + maxItems: 8 + description: | + Specifies the numeric keycodes associated with each available gesture in + the following order (enter 0 for unused gestures): + 0: Slider 0 tap + 1: Slider 0 hold + 2: Slider 0 positive flick or swipe + 3: Slider 0 negative flick or swipe + 4: Slider 1 tap + 5: Slider 1 hold + 6: Slider 1 positive flick or swipe + 7: Slider 1 negative flick or swipe + + azoteq,gesture-swipe: + type: boolean + description: + Directs the device to interpret axial gestures as a swipe (finger remains + on slider) instead of a flick (finger leaves slider). + + azoteq,timeout-tap-ms: + multipleOf: 16 + minimum: 0 + maximum: 4080 + default: 400 + description: + Specifies the length of time (in ms) within which a slider touch must be + released in order to be interpreted as a tap. Default and maximum values + as well as step size are reduced by a factor of 4 with device version 2. + + azoteq,timeout-swipe-ms: + multipleOf: 16 + minimum: 0 + maximum: 4080 + default: 2000 + description: + Specifies the length of time (in ms) within which an axial gesture must be + completed in order to be interpreted as a flick or swipe. Default and max- + imum values as well as step size are reduced by a factor of 4 with device + version 2. + + azoteq,thresh-swipe: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 255 + default: 128 + description: + Specifies the number of points across which an axial gesture must travel + in order to be interpreted as a flick or swipe. + +dependencies: + azoteq,gesture-swipe: ["linux,keycodes"] + azoteq,timeout-tap-ms: ["linux,keycodes"] + azoteq,timeout-swipe-ms: ["linux,keycodes"] + azoteq,thresh-swipe: ["linux,keycodes"] + patternProperties: "^channel@[0-7]$": type: object @@ -454,6 +527,21 @@ patternProperties: additionalProperties: false +if: + properties: + compatible: + contains: + enum: + - azoteq,iqs269a-d0 +then: + patternProperties: + "^channel@[0-7]$": + properties: + azoteq,slider1-select: false +else: + properties: + azoteq,touch-hold-ms: false + required: - compatible - reg @@ -484,6 +572,14 @@ examples: azoteq,hall-enable; azoteq,suspend-mode = <2>; + linux,keycodes = , + , + , + ; + + azoteq,timeout-tap-ms = <400>; + azoteq,timeout-swipe-ms = <800>; + channel@0 { reg = <0x0>; diff --git a/Documentation/devicetree/bindings/input/mediatek,pmic-keys.yaml b/Documentation/devicetree/bindings/input/mediatek,pmic-keys.yaml index e34c9e78d38d8c..70567d92c746ef 100644 --- a/Documentation/devicetree/bindings/input/mediatek,pmic-keys.yaml +++ b/Documentation/devicetree/bindings/input/mediatek,pmic-keys.yaml @@ -90,26 +90,4 @@ required: unevaluatedProperties: false -examples: - - | - #include - #include - - pmic { - compatible = "mediatek,mt6397"; - - keys { - compatible = "mediatek,mt6397-keys"; - mediatek,long-press-mode = <1>; - power-off-time-sec = <0>; - - key-power { - linux,keycodes = ; - wakeup-source; - }; - - key-home { - linux,keycodes = ; - }; - }; - }; +... diff --git a/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml b/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml index 5b5d4f7d34827a..7ade03f1b32b81 100644 --- a/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml +++ b/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml @@ -45,13 +45,13 @@ properties: Enables the Linux input system's autorepeat feature on the input device. linux,keycodes: - minItems: 6 - maxItems: 6 + minItems: 3 + maxItems: 8 description: | Specifies an array of numeric keycode values to be used for the channels. If this property is omitted, KEY_A, KEY_B, etc are used as defaults. - The array must have exactly six entries. + The number of entries must correspond to the number of channels. microchip,sensor-gain: $ref: /schemas/types.yaml#/definitions/uint32 @@ -70,6 +70,59 @@ properties: open drain. This property allows using the active high push-pull output. + microchip,sensitivity-delta-sense: + $ref: /schemas/types.yaml#/definitions/uint32 + default: 32 + enum: [1, 2, 4, 8, 16, 32, 64, 128] + description: + Controls the sensitivity multiplier of a touch detection. + Higher value means more sensitive settings. + At the more sensitive settings, touches are detected for a smaller delta + capacitance corresponding to a "lighter" touch. + + microchip,signal-guard: + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 3 + maxItems: 8 + items: + enum: [0, 1] + description: | + 0 - off + 1 - on + The signal guard isolates the signal from virtual grounds. + If enabled then the behavior of the channel is changed to signal guard. + The number of entries must correspond to the number of channels. + + microchip,input-threshold: + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 3 + maxItems: 8 + items: + minimum: 0 + maximum: 127 + description: + Specifies the delta threshold that is used to determine if a touch has + been detected. A higher value means a larger difference in capacitance + is required for a touch to be registered, making the touch sensor less + sensitive. + The number of entries must correspond to the number of channels. + + microchip,calib-sensitivity: + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 3 + maxItems: 8 + items: + enum: [1, 2, 4] + description: | + Specifies an array of numeric values that controls the gain + used by the calibration routine to enable sensor inputs + to be more sensitive for proximity detection. + Gain is based on touch pad capacitance range + 1 - 5-50pF + 2 - 0-25pF + 4 - 0-12.5pF + The number of entries must correspond to the number of channels. + patternProperties: "^led@[0-7]$": type: object @@ -99,10 +152,29 @@ allOf: contains: enum: - microchip,cap1106 + - microchip,cap1203 + - microchip,cap1206 + - microchip,cap1293 + - microchip,cap1298 then: patternProperties: "^led@[0-7]$": false + - if: + properties: + compatible: + contains: + enum: + - microchip,cap1106 + - microchip,cap1126 + - microchip,cap1188 + - microchip,cap1203 + - microchip,cap1206 + then: + properties: + microchip,signal-guard: false + microchip,calib-sensitivity: false + required: - compatible - interrupts @@ -122,6 +194,8 @@ examples: reg = <0x28>; autorepeat; microchip,sensor-gain = <2>; + microchip,sensitivity-delta-sense = <16>; + microchip,input-threshold = <21>, <18>, <46>, <46>, <46>, <21>; linux,keycodes = <103>, /* KEY_UP */ <106>, /* KEY_RIGHT */ diff --git a/Documentation/devicetree/bindings/input/sprd,sc27xx-vibrator.yaml b/Documentation/devicetree/bindings/input/sprd,sc27xx-vibrator.yaml index a401a0bfcbec21..4c8d303ff93c94 100644 --- a/Documentation/devicetree/bindings/input/sprd,sc27xx-vibrator.yaml +++ b/Documentation/devicetree/bindings/input/sprd,sc27xx-vibrator.yaml @@ -28,21 +28,4 @@ required: additionalProperties: false -examples: - - | - #include - sc2731_pmic: pmic@0 { - compatible = "sprd,sc2731"; - reg = <0 0>; - spi-max-frequency = <26000000>; - interrupts = ; - interrupt-controller; - #interrupt-cells = <2>; - #address-cells = <1>; - #size-cells = <0>; - - vibrator@eb4 { - compatible = "sprd,sc2731-vibrator"; - reg = <0xeb4>; - }; - }; +... diff --git a/Documentation/devicetree/bindings/input/ti,drv2665.txt b/Documentation/devicetree/bindings/input/ti,drv2665.txt deleted file mode 100644 index 1ba97ac0430587..00000000000000 --- a/Documentation/devicetree/bindings/input/ti,drv2665.txt +++ /dev/null @@ -1,17 +0,0 @@ -* Texas Instruments - drv2665 Haptics driver - -Required properties: - - compatible - "ti,drv2665" - DRV2665 - - reg - I2C slave address - - vbat-supply - Required supply regulator - -Example: - -haptics: haptics@59 { - compatible = "ti,drv2665"; - reg = <0x59>; - vbat-supply = <&vbat>; -}; - -For more product information please see the link below: -http://www.ti.com/product/drv2665 diff --git a/Documentation/devicetree/bindings/input/ti,drv2667.txt b/Documentation/devicetree/bindings/input/ti,drv2667.txt deleted file mode 100644 index 996382cf994a12..00000000000000 --- a/Documentation/devicetree/bindings/input/ti,drv2667.txt +++ /dev/null @@ -1,17 +0,0 @@ -* Texas Instruments - drv2667 Haptics driver - -Required properties: - - compatible - "ti,drv2667" - DRV2667 - - reg - I2C slave address - - vbat-supply - Required supply regulator - -Example: - -haptics: haptics@59 { - compatible = "ti,drv2667"; - reg = <0x59>; - vbat-supply = <&vbat>; -}; - -For more product information please see the link below: -http://www.ti.com/product/drv2667 diff --git a/Documentation/devicetree/bindings/input/ti,drv266x.yaml b/Documentation/devicetree/bindings/input/ti,drv266x.yaml new file mode 100644 index 00000000000000..da181882437385 --- /dev/null +++ b/Documentation/devicetree/bindings/input/ti,drv266x.yaml @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/ti,drv266x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments - drv266x Haptics driver + +description: | + Product Page: + http://www.ti.com/product/drv2665 + http://www.ti.com/product/drv2667 + +maintainers: + - Anshul Dalal + +properties: + compatible: + enum: + - ti,drv2665 + - ti,drv2667 + + reg: + maxItems: 1 + + vbat-supply: + description: Required supply regulator + +required: + - compatible + - reg + - vbat-supply + +additionalProperties: false + +examples: + - | + #include + + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + haptics@59 { + compatible = "ti,drv2667"; + reg = <0x59>; + vbat-supply = <&vbat>; + }; + }; diff --git a/Documentation/devicetree/bindings/input/touchscreen/neonode,zforce.yaml b/Documentation/devicetree/bindings/input/touchscreen/neonode,zforce.yaml new file mode 100644 index 00000000000000..c2ee89b76ea138 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/neonode,zforce.yaml @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/touchscreen/neonode,zforce.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Neonode infrared touchscreen controller + +maintainers: + - Heiko Stuebner + +allOf: + - $ref: touchscreen.yaml# + +properties: + compatible: + const: neonode,zforce + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + reset-gpios: + maxItems: 1 + + irq-gpios: + maxItems: 1 + + x-size: + deprecated: true + $ref: /schemas/types.yaml#/definitions/uint32 + + y-size: + deprecated: true + $ref: /schemas/types.yaml#/definitions/uint32 + + vdd-supply: true + +required: + - compatible + - reg + - interrupts + - reset-gpios + +unevaluatedProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + touchscreen@50 { + compatible = "neonode,zforce"; + reg = <0x50>; + interrupts = <2 0>; + vdd-supply = <®_zforce_vdd>; + + reset-gpios = <&gpio5 9 0>; /* RST */ + irq-gpios = <&gpio5 6 0>; /* IRQ, optional */ + + touchscreen-min-x = <0>; + touchscreen-size-x = <800>; + touchscreen-min-y = <0>; + touchscreen-size-y = <600>; + }; + }; +... diff --git a/Documentation/devicetree/bindings/input/touchscreen/samsung,s6sy761.txt b/Documentation/devicetree/bindings/input/touchscreen/samsung,s6sy761.txt deleted file mode 100644 index 6805d10d226d39..00000000000000 --- a/Documentation/devicetree/bindings/input/touchscreen/samsung,s6sy761.txt +++ /dev/null @@ -1,32 +0,0 @@ -* Samsung S6SY761 touchscreen controller - -Required properties: -- compatible : must be "samsung,s6sy761" -- reg : I2C slave address, (e.g. 0x48) -- interrupts : interrupt specification -- avdd-supply : analogic power supply -- vdd-supply : power supply - -Optional properties: -- touchscreen-size-x : see touchscreen.txt. This property is embedded in the - device. If defined it forces a different x resolution. -- touchscreen-size-y : see touchscreen.txt. This property is embedded in the - device. If defined it forces a different y resolution. - -Example: - -i2c@00000000 { - - /* ... */ - - touchscreen@48 { - compatible = "samsung,s6sy761"; - reg = <0x48>; - interrupt-parent = <&gpa1>; - interrupts = <1 IRQ_TYPE_NONE>; - avdd-supply = <&ldo30_reg>; - vdd-supply = <&ldo31_reg>; - touchscreen-size-x = <4096>; - touchscreen-size-y = <4096>; - }; -}; diff --git a/Documentation/devicetree/bindings/input/touchscreen/samsung,s6sy761.yaml b/Documentation/devicetree/bindings/input/touchscreen/samsung,s6sy761.yaml new file mode 100644 index 00000000000000..1ffd17af3c53f1 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/samsung,s6sy761.yaml @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/touchscreen/samsung,s6sy761.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Samsung S6SY761 touchscreen controller + +maintainers: + - Andi Shyti + +allOf: + - $ref: touchscreen.yaml# + +properties: + compatible: + const: samsung,s6sy761 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + avdd-supply: true + vdd-supply: true + +unevaluatedProperties: false + +required: + - compatible + - reg + - interrupts + - avdd-supply + - vdd-supply + +examples: + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + touchscreen@48 { + compatible = "samsung,s6sy761"; + reg = <0x48>; + interrupt-parent = <&gpa1>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH>; + avdd-supply = <&ldo30_reg>; + vdd-supply = <&ldo31_reg>; + touchscreen-size-x = <4096>; + touchscreen-size-y = <4096>; + }; + }; diff --git a/Documentation/devicetree/bindings/input/touchscreen/zforce_ts.txt b/Documentation/devicetree/bindings/input/touchscreen/zforce_ts.txt deleted file mode 100644 index e3c27c4fd9c851..00000000000000 --- a/Documentation/devicetree/bindings/input/touchscreen/zforce_ts.txt +++ /dev/null @@ -1,34 +0,0 @@ -* Neonode infrared touchscreen controller - -Required properties: -- compatible: must be "neonode,zforce" -- reg: I2C address of the chip -- interrupts: interrupt to which the chip is connected -- reset-gpios: reset gpio the chip is connected to -- x-size: horizontal resolution of touchscreen -- y-size: vertical resolution of touchscreen - -Optional properties: -- irq-gpios : interrupt gpio the chip is connected to -- vdd-supply: Regulator controlling the controller supply - -Example: - - i2c@00000000 { - /* ... */ - - zforce_ts@50 { - compatible = "neonode,zforce"; - reg = <0x50>; - interrupts = <2 0>; - vdd-supply = <®_zforce_vdd>; - - reset-gpios = <&gpio5 9 0>; /* RST */ - irq-gpios = <&gpio5 6 0>; /* IRQ, optional */ - - x-size = <800>; - y-size = <600>; - }; - - /* ... */ - }; diff --git a/Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml b/Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml index 73f809cdb783cf..05067e197abe81 100644 --- a/Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml +++ b/Documentation/devicetree/bindings/interconnect/qcom,msm8998-bwmon.yaml @@ -25,13 +25,16 @@ properties: - const: qcom,msm8998-bwmon # BWMON v4 - items: - enum: + - qcom,qcm2290-cpu-bwmon - qcom,sc7180-cpu-bwmon - qcom,sc7280-cpu-bwmon - qcom,sc8280xp-cpu-bwmon - qcom,sdm845-cpu-bwmon + - qcom,sm6115-cpu-bwmon - qcom,sm6350-llcc-bwmon - qcom,sm8250-cpu-bwmon - qcom,sm8550-cpu-bwmon + - qcom,sm8650-cpu-bwmon - const: qcom,sdm845-bwmon # BWMON v4, unified register space - items: - enum: @@ -40,6 +43,7 @@ properties: - qcom,sm6350-cpu-bwmon - qcom,sm8250-llcc-bwmon - qcom,sm8550-llcc-bwmon + - qcom,sm8650-llcc-bwmon - const: qcom,sc7280-llcc-bwmon - const: qcom,sc7280-llcc-bwmon # BWMON v5 - const: qcom,sdm845-llcc-bwmon # BWMON v5 diff --git a/Documentation/devicetree/bindings/interconnect/qcom,sm6115.yaml b/Documentation/devicetree/bindings/interconnect/qcom,sm6115.yaml new file mode 100644 index 00000000000000..14b1a0b08e736e --- /dev/null +++ b/Documentation/devicetree/bindings/interconnect/qcom,sm6115.yaml @@ -0,0 +1,152 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interconnect/qcom,sm6115.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SM6115 Network-On-Chip interconnect + +maintainers: + - Konrad Dybcio + +description: + The Qualcomm SM6115 interconnect providers support adjusting the + bandwidth requirements between the various NoC fabrics. + +properties: + compatible: + enum: + - qcom,sm6115-bimc + - qcom,sm6115-cnoc + - qcom,sm6115-snoc + + reg: + maxItems: 1 + + clocks: + minItems: 1 + maxItems: 4 + + clock-names: + minItems: 1 + maxItems: 4 + +# Child node's properties +patternProperties: + '^interconnect-[a-z0-9]+$': + type: object + description: + The interconnect providers do not have a separate QoS register space, + but share parent's space. + + $ref: qcom,rpm-common.yaml# + + properties: + compatible: + enum: + - qcom,sm6115-clk-virt + - qcom,sm6115-mmrt-virt + - qcom,sm6115-mmnrt-virt + + required: + - compatible + + unevaluatedProperties: false + +required: + - compatible + - reg + +allOf: + - $ref: qcom,rpm-common.yaml# + - if: + properties: + compatible: + const: qcom,sm6115-cnoc + + then: + properties: + clocks: + items: + - description: USB-NoC AXI clock + + clock-names: + items: + - const: usb_axi + + - if: + properties: + compatible: + const: qcom,sm6115-snoc + + then: + properties: + clocks: + items: + - description: CPU-NoC AXI clock. + - description: UFS-NoC AXI clock. + - description: USB-NoC AXI clock. + - description: IPA clock. + + clock-names: + items: + - const: cpu_axi + - const: ufs_axi + - const: usb_axi + - const: ipa + + - if: + properties: + compatible: + enum: + - qcom,sm6115-bimc + - qcom,sm6115-clk-virt + - qcom,sm6115-mmrt-virt + - qcom,sm6115-mmnrt-virt + + then: + properties: + clocks: false + clock-names: false + +unevaluatedProperties: false + +examples: + - | + #include + #include + + snoc: interconnect@1880000 { + compatible = "qcom,sm6115-snoc"; + reg = <0x01880000 0x60200>; + clocks = <&gcc GCC_SYS_NOC_CPUSS_AHB_CLK>, + <&gcc GCC_SYS_NOC_UFS_PHY_AXI_CLK>, + <&gcc GCC_SYS_NOC_USB3_PRIM_AXI_CLK>, + <&rpmcc RPM_SMD_IPA_CLK>; + clock-names = "cpu_axi", + "ufs_axi", + "usb_axi", + "ipa"; + #interconnect-cells = <1>; + + qup_virt: interconnect-clk { + compatible = "qcom,sm6115-clk-virt"; + #interconnect-cells = <1>; + }; + + mmnrt_virt: interconnect-mmnrt { + compatible = "qcom,sm6115-mmnrt-virt"; + #interconnect-cells = <1>; + }; + + mmrt_virt: interconnect-mmrt { + compatible = "qcom,sm6115-mmrt-virt"; + #interconnect-cells = <1>; + }; + }; + + cnoc: interconnect@1900000 { + compatible = "qcom,sm6115-cnoc"; + reg = <0x01900000 0x8200>; + #interconnect-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/interconnect/qcom,sm8650-rpmh.yaml b/Documentation/devicetree/bindings/interconnect/qcom,sm8650-rpmh.yaml new file mode 100644 index 00000000000000..f9322de7cd61e6 --- /dev/null +++ b/Documentation/devicetree/bindings/interconnect/qcom,sm8650-rpmh.yaml @@ -0,0 +1,136 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interconnect/qcom,sm8650-rpmh.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm RPMh Network-On-Chip Interconnect on SM8650 + +maintainers: + - Abel Vesa + - Neil Armstrong + +description: | + RPMh interconnect providers support system bandwidth requirements through + RPMh hardware accelerators known as Bus Clock Manager (BCM). The provider is + able to communicate with the BCM through the Resource State Coordinator (RSC) + associated with each execution environment. Provider nodes must point to at + least one RPMh device child node pertaining to their RSC and each provider + can map to multiple RPMh resources. + + See also:: include/dt-bindings/interconnect/qcom,sm8650-rpmh.h + +properties: + compatible: + enum: + - qcom,sm8650-aggre1-noc + - qcom,sm8650-aggre2-noc + - qcom,sm8650-clk-virt + - qcom,sm8650-cnoc-main + - qcom,sm8650-config-noc + - qcom,sm8650-gem-noc + - qcom,sm8650-lpass-ag-noc + - qcom,sm8650-lpass-lpiaon-noc + - qcom,sm8650-lpass-lpicx-noc + - qcom,sm8650-mc-virt + - qcom,sm8650-mmss-noc + - qcom,sm8650-nsp-noc + - qcom,sm8650-pcie-anoc + - qcom,sm8650-system-noc + + reg: + maxItems: 1 + + clocks: + minItems: 1 + maxItems: 2 + +required: + - compatible + +allOf: + - $ref: qcom,rpmh-common.yaml# + - if: + properties: + compatible: + contains: + enum: + - qcom,sm8650-clk-virt + - qcom,sm8650-mc-virt + then: + properties: + reg: false + else: + required: + - reg + + - if: + properties: + compatible: + contains: + enum: + - qcom,sm8650-pcie-anoc + then: + properties: + clocks: + items: + - description: aggre-NOC PCIe AXI clock + - description: cfg-NOC PCIe a-NOC AHB clock + + - if: + properties: + compatible: + contains: + enum: + - qcom,sm8650-aggre1-noc + then: + properties: + clocks: + items: + - description: aggre UFS PHY AXI clock + - description: aggre USB3 PRIM AXI clock + + - if: + properties: + compatible: + contains: + enum: + - qcom,sm8650-aggre2-noc + then: + properties: + clocks: + items: + - description: RPMH CC IPA clock + + - if: + properties: + compatible: + contains: + enum: + - qcom,sm8650-aggre1-noc + - qcom,sm8650-aggre2-noc + - qcom,sm8650-pcie-anoc + then: + required: + - clocks + else: + properties: + clocks: false + +unevaluatedProperties: false + +examples: + - | + clk_virt: interconnect-0 { + compatible = "qcom,sm8650-clk-virt"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + aggre1_noc: interconnect@16e0000 { + compatible = "qcom,sm8650-aggre1-noc"; + reg = <0x016e0000 0x14400>; + #interconnect-cells = <2>; + clocks = <&gcc_phy_axi_clk>, <&gcc_prim_axi_clk>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; diff --git a/Documentation/devicetree/bindings/interconnect/qcom,x1e80100-rpmh.yaml b/Documentation/devicetree/bindings/interconnect/qcom,x1e80100-rpmh.yaml new file mode 100644 index 00000000000000..08b0210e0e5960 --- /dev/null +++ b/Documentation/devicetree/bindings/interconnect/qcom,x1e80100-rpmh.yaml @@ -0,0 +1,83 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interconnect/qcom,x1e80100-rpmh.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm RPMh Network-On-Chip Interconnect on X1E80100 + +maintainers: + - Rajendra Nayak + - Abel Vesa + +description: | + RPMh interconnect providers support system bandwidth requirements through + RPMh hardware accelerators known as Bus Clock Manager (BCM). The provider is + able to communicate with the BCM through the Resource State Coordinator (RSC) + associated with each execution environment. Provider nodes must point to at + least one RPMh device child node pertaining to their RSC and each provider + can map to multiple RPMh resources. + + See also:: include/dt-bindings/interconnect/qcom,x1e80100-rpmh.h + +properties: + compatible: + enum: + - qcom,x1e80100-aggre1-noc + - qcom,x1e80100-aggre2-noc + - qcom,x1e80100-clk-virt + - qcom,x1e80100-cnoc-cfg + - qcom,x1e80100-cnoc-main + - qcom,x1e80100-gem-noc + - qcom,x1e80100-lpass-ag-noc + - qcom,x1e80100-lpass-lpiaon-noc + - qcom,x1e80100-lpass-lpicx-noc + - qcom,x1e80100-mc-virt + - qcom,x1e80100-mmss-noc + - qcom,x1e80100-nsp-noc + - qcom,x1e80100-pcie-center-anoc + - qcom,x1e80100-pcie-north-anoc + - qcom,x1e80100-pcie-south-anoc + - qcom,x1e80100-system-noc + - qcom,x1e80100-usb-center-anoc + - qcom,x1e80100-usb-north-anoc + - qcom,x1e80100-usb-south-anoc + + reg: + maxItems: 1 + +required: + - compatible + +allOf: + - $ref: qcom,rpmh-common.yaml# + - if: + properties: + compatible: + contains: + enum: + - qcom,x1e80100-clk-virt + - qcom,x1e80100-mc-virt + then: + properties: + reg: false + else: + required: + - reg + +unevaluatedProperties: false + +examples: + - | + clk_virt: interconnect-0 { + compatible = "qcom,x1e80100-clk-virt"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + aggre1_noc: interconnect@16e0000 { + compatible = "qcom,x1e80100-aggre1-noc"; + reg = <0x016e0000 0x14400>; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; diff --git a/Documentation/devicetree/bindings/interrupt-controller/loongson,liointc.yaml b/Documentation/devicetree/bindings/interrupt-controller/loongson,liointc.yaml index 00b570c8290397..60441f0c5d7211 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/loongson,liointc.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/loongson,liointc.yaml @@ -11,8 +11,13 @@ maintainers: description: | This interrupt controller is found in the Loongson-3 family of chips and - Loongson-2K1000 chip, as the primary package interrupt controller which + Loongson-2K series chips, as the primary package interrupt controller which can route local I/O interrupt to interrupt lines of cores. + Be aware of the following points. + 1.The Loongson-2K0500 is a single core CPU; + 2.The Loongson-2K0500/2K1000 has 64 device interrupt sources as inputs, so we + need to define two nodes in dts{i} to describe the "0-31" and "32-61" interrupt + sources respectively. allOf: - $ref: /schemas/interrupt-controller.yaml# @@ -33,6 +38,7 @@ properties: - const: main - const: isr0 - const: isr1 + minItems: 2 interrupt-controller: true @@ -45,11 +51,9 @@ properties: interrupt-names: description: List of names for the parent interrupts. items: - - const: int0 - - const: int1 - - const: int2 - - const: int3 + pattern: int[0-3] minItems: 1 + maxItems: 4 '#interrupt-cells': const: 2 @@ -69,6 +73,7 @@ required: - compatible - reg - interrupts + - interrupt-names - interrupt-controller - '#interrupt-cells' - loongson,parent_int_map @@ -86,7 +91,8 @@ if: then: properties: reg: - minItems: 3 + minItems: 2 + maxItems: 3 required: - reg-names diff --git a/Documentation/devicetree/bindings/interrupt-controller/qcom,mpm.yaml b/Documentation/devicetree/bindings/interrupt-controller/qcom,mpm.yaml index 6a206111d4e0f0..ebb40c48950ab3 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/qcom,mpm.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/qcom,mpm.yaml @@ -29,6 +29,12 @@ properties: maxItems: 1 description: Specifies the base address and size of vMPM registers in RPM MSG RAM. + deprecated: true + + qcom,rpm-msg-ram: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Phandle to the APSS MPM slice of the RPM Message RAM interrupts: maxItems: 1 @@ -67,34 +73,46 @@ properties: required: - compatible - - reg - interrupts - mboxes - interrupt-controller - '#interrupt-cells' - qcom,mpm-pin-count - qcom,mpm-pin-map + - qcom,rpm-msg-ram additionalProperties: false examples: - | #include - mpm: interrupt-controller@45f01b8 { - compatible = "qcom,mpm"; - interrupts = ; - reg = <0x45f01b8 0x1000>; - mboxes = <&apcs_glb 1>; - interrupt-controller; - #interrupt-cells = <2>; - interrupt-parent = <&intc>; - qcom,mpm-pin-count = <96>; - qcom,mpm-pin-map = <2 275>, - <5 296>, - <12 422>, - <24 79>, - <86 183>, - <90 260>, - <91 260>; - #power-domain-cells = <0>; + + remoteproc-rpm { + compatible = "qcom,msm8998-rpm-proc", "qcom,rpm-proc"; + + glink-edge { + compatible = "qcom,glink-rpm"; + + interrupts = ; + qcom,rpm-msg-ram = <&rpm_msg_ram>; + mboxes = <&apcs_glb 0>; + }; + + mpm: interrupt-controller { + compatible = "qcom,mpm"; + qcom,rpm-msg-ram = <&apss_mpm>; + interrupts = ; + mboxes = <&apcs_glb 1>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&intc>; + qcom,mpm-pin-count = <96>; + qcom,mpm-pin-map = <2 275>, + <5 296>, + <12 422>, + <24 79>, + <86 183>, + <91 260>; + #power-domain-cells = <0>; + }; }; diff --git a/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml b/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml index 86d61896f59135..4bdc8321904bd0 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml @@ -35,12 +35,16 @@ properties: - qcom,sdm845-pdc - qcom,sdx55-pdc - qcom,sdx65-pdc + - qcom,sdx75-pdc - qcom,sm4450-pdc - qcom,sm6350-pdc - qcom,sm8150-pdc - qcom,sm8250-pdc - qcom,sm8350-pdc - qcom,sm8450-pdc + - qcom,sm8550-pdc + - qcom,sm8650-pdc + - qcom,x1e80100-pdc - const: qcom,pdc reg: diff --git a/Documentation/devicetree/bindings/interrupt-controller/renesas,rzg2l-irqc.yaml b/Documentation/devicetree/bindings/interrupt-controller/renesas,rzg2l-irqc.yaml index 2ef3081eaaf36a..d3b5aec0a3f74d 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/renesas,rzg2l-irqc.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/renesas,rzg2l-irqc.yaml @@ -26,6 +26,7 @@ properties: - renesas,r9a07g043u-irqc # RZ/G2UL - renesas,r9a07g044-irqc # RZ/G2{L,LC} - renesas,r9a07g054-irqc # RZ/V2L + - renesas,r9a08g045-irqc # RZ/G3S - const: renesas,rzg2l-irqc '#interrupt-cells': @@ -167,7 +168,9 @@ allOf: properties: compatible: contains: - const: renesas,r9a07g043u-irqc + enum: + - renesas,r9a07g043u-irqc + - renesas,r9a08g045-irqc then: properties: interrupts: diff --git a/Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml b/Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml index 0c07e8dda4452c..709b2211276bd9 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml @@ -66,6 +66,7 @@ properties: - enum: - allwinner,sun20i-d1-plic - sophgo,cv1800b-plic + - sophgo,cv1812h-plic - sophgo,sg2042-plic - thead,th1520-plic - const: thead,c900-plic diff --git a/Documentation/devicetree/bindings/interrupt-controller/st,stih407-irq-syscfg.yaml b/Documentation/devicetree/bindings/interrupt-controller/st,stih407-irq-syscfg.yaml index 2b153d7c542163..e44e4e5708a722 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/st,stih407-irq-syscfg.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/st,stih407-irq-syscfg.yaml @@ -55,8 +55,8 @@ examples: - | #include irq-syscfg { - compatible = "st,stih407-irq-syscfg"; - st,syscfg = <&syscfg_cpu>; + compatible = "st,stih407-irq-syscfg"; + st,syscfg = <&syscfg_cpu>; st,irq-device = , ; st,fiq-device = , diff --git a/Documentation/devicetree/bindings/iommu/apple,dart.yaml b/Documentation/devicetree/bindings/iommu/apple,dart.yaml index 903edf85d72e40..7adb1de455a5b3 100644 --- a/Documentation/devicetree/bindings/iommu/apple,dart.yaml +++ b/Documentation/devicetree/bindings/iommu/apple,dart.yaml @@ -24,6 +24,7 @@ properties: compatible: enum: - apple,t8103-dart + - apple,t8103-usb4-dart - apple,t8110-dart - apple,t6000-dart diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml index aa9e1c0895a508..a4042ae2477024 100644 --- a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml @@ -56,6 +56,8 @@ properties: - qcom,sm8350-smmu-500 - qcom,sm8450-smmu-500 - qcom,sm8550-smmu-500 + - qcom,sm8650-smmu-500 + - qcom,x1e80100-smmu-500 - const: qcom,smmu-500 - const: arm,mmu-500 @@ -89,6 +91,8 @@ properties: - qcom,sm8150-smmu-500 - qcom,sm8250-smmu-500 - qcom,sm8350-smmu-500 + - qcom,sm8450-smmu-500 + - qcom,sm8550-smmu-500 - const: qcom,adreno-smmu - const: qcom,smmu-500 - const: arm,mmu-500 @@ -429,6 +433,30 @@ allOf: - description: interface clock required to access smmu's registers through the TCU's programming interface. + - if: + properties: + compatible: + items: + - enum: + - qcom,sm8350-smmu-500 + - const: qcom,adreno-smmu + - const: qcom,smmu-500 + - const: arm,mmu-500 + then: + properties: + clock-names: + items: + - const: bus + - const: iface + - const: ahb + - const: hlos1_vote_gpu_smmu + - const: cx_gmu + - const: hub_cx_int + - const: hub_aon + clocks: + minItems: 7 + maxItems: 7 + - if: properties: compatible: @@ -453,6 +481,50 @@ allOf: - description: Voter clock required for HLOS SMMU access - description: Interface clock required for register access + - if: + properties: + compatible: + const: qcom,sm8450-smmu-500 + then: + properties: + clock-names: + items: + - const: gmu + - const: hub + - const: hlos + - const: bus + - const: iface + - const: ahb + + clocks: + items: + - description: GMU clock + - description: GPU HUB clock + - description: HLOS vote clock + - description: GPU memory bus clock + - description: GPU SNoC bus clock + - description: GPU AHB clock + + - if: + properties: + compatible: + const: qcom,sm8550-smmu-500 + then: + properties: + clock-names: + items: + - const: hlos + - const: bus + - const: iface + - const: ahb + + clocks: + items: + - description: HLOS vote clock + - description: GPU memory bus clock + - description: GPU SNoC bus clock + - description: GPU AHB clock + # Disallow clocks for all other platforms with specific compatibles - if: properties: @@ -472,9 +544,8 @@ allOf: - qcom,sdx65-smmu-500 - qcom,sm6350-smmu-500 - qcom,sm6375-smmu-500 - - qcom,sm8350-smmu-500 - - qcom,sm8450-smmu-500 - - qcom,sm8550-smmu-500 + - qcom,sm8650-smmu-500 + - qcom,x1e80100-smmu-500 then: properties: clock-names: false diff --git a/Documentation/devicetree/bindings/iommu/rockchip,iommu.yaml b/Documentation/devicetree/bindings/iommu/rockchip,iommu.yaml index ba9124f721f151..621dde0e45d851 100644 --- a/Documentation/devicetree/bindings/iommu/rockchip,iommu.yaml +++ b/Documentation/devicetree/bindings/iommu/rockchip,iommu.yaml @@ -19,9 +19,14 @@ description: |+ properties: compatible: - enum: - - rockchip,iommu - - rockchip,rk3568-iommu + oneOf: + - enum: + - rockchip,iommu + - rockchip,rk3568-iommu + - items: + - enum: + - rockchip,rk3588-iommu + - const: rockchip,rk3568-iommu reg: items: diff --git a/Documentation/devicetree/bindings/leds/allwinner,sun50i-a100-ledc.yaml b/Documentation/devicetree/bindings/leds/allwinner,sun50i-a100-ledc.yaml new file mode 100644 index 00000000000000..760cb336dccb5c --- /dev/null +++ b/Documentation/devicetree/bindings/leds/allwinner,sun50i-a100-ledc.yaml @@ -0,0 +1,137 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/allwinner,sun50i-a100-ledc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Allwinner A100 LED Controller + +maintainers: + - Samuel Holland + +description: + The LED controller found in Allwinner sunxi SoCs uses a one-wire serial + interface to drive up to 1024 RGB LEDs. + +properties: + compatible: + oneOf: + - const: allwinner,sun50i-a100-ledc + - items: + - enum: + - allwinner,sun20i-d1-ledc + - allwinner,sun50i-r329-ledc + - const: allwinner,sun50i-a100-ledc + + reg: + maxItems: 1 + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: Bus clock + - description: Module clock + + clock-names: + items: + - const: bus + - const: mod + + resets: + maxItems: 1 + + dmas: + maxItems: 1 + description: TX DMA channel + + dma-names: + const: tx + + allwinner,pixel-format: + description: Pixel format (subpixel transmission order), default is "grb" + enum: + - bgr + - brg + - gbr + - grb + - rbg + - rgb + + allwinner,t0h-ns: + default: 336 + description: Length of high pulse when transmitting a "0" bit + + allwinner,t0l-ns: + default: 840 + description: Length of low pulse when transmitting a "0" bit + + allwinner,t1h-ns: + default: 882 + description: Length of high pulse when transmitting a "1" bit + + allwinner,t1l-ns: + default: 294 + description: Length of low pulse when transmitting a "1" bit + + allwinner,treset-ns: + default: 300000 + description: Minimum delay between transmission frames + +patternProperties: + "^multi-led@[0-9a-f]+$": + type: object + $ref: leds-class-multicolor.yaml# + unevaluatedProperties: false + properties: + reg: + minimum: 0 + maximum: 1023 + description: Index of the LED in the series (must be contiguous) + + required: + - reg + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - resets + +additionalProperties: false + +examples: + - | + #include + #include + + ledc: led-controller@2008000 { + compatible = "allwinner,sun20i-d1-ledc", + "allwinner,sun50i-a100-ledc"; + reg = <0x2008000 0x400>; + interrupts = <36 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&ccu 12>, <&ccu 34>; + clock-names = "bus", "mod"; + resets = <&ccu 12>; + dmas = <&dma 42>; + dma-names = "tx"; + #address-cells = <1>; + #size-cells = <0>; + + multi-led@0 { + reg = <0x0>; + color = ; + function = LED_FUNCTION_INDICATOR; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/leds/awinic,aw200xx.yaml b/Documentation/devicetree/bindings/leds/awinic,aw200xx.yaml index feb5febaf361ae..54d6d1f08e2489 100644 --- a/Documentation/devicetree/bindings/leds/awinic,aw200xx.yaml +++ b/Documentation/devicetree/bindings/leds/awinic,aw200xx.yaml @@ -10,15 +10,19 @@ maintainers: - Martin Kurbanov description: | - This controller is present on AW20036/AW20054/AW20072. - It is a 3x12/6x9/6x12 matrix LED programmed via - an I2C interface, up to 36/54/72 LEDs or 12/18/24 RGBs, - 3 pattern controllers for auto breathing or group dimming control. + It is a matrix LED driver programmed via an I2C interface. Devices have + a set of individually controlled leds and support 3 pattern controllers + for auto breathing or group dimming control. Supported devices: + - AW20036 (3x12) 36 LEDs + - AW20054 (6x9) 54 LEDs + - AW20072 (6x12) 72 LEDs + - AW20108 (9x12) 108 LEDs For more product information please see the link below: aw20036 - https://www.awinic.com/en/productDetail/AW20036QNR#tech-docs aw20054 - https://www.awinic.com/en/productDetail/AW20054QNR#tech-docs aw20072 - https://www.awinic.com/en/productDetail/AW20072QNR#tech-docs + aw20108 - https://www.awinic.com/en/productDetail/AW20108QNR#tech-docs properties: compatible: @@ -26,6 +30,7 @@ properties: - awinic,aw20036 - awinic,aw20054 - awinic,aw20072 + - awinic,aw20108 reg: maxItems: 1 @@ -36,13 +41,11 @@ properties: "#size-cells": const: 0 - awinic,display-rows: - $ref: /schemas/types.yaml#/definitions/uint32 - description: - Leds matrix size + enable-gpios: + maxItems: 1 patternProperties: - "^led@[0-9a-f]$": + "^led@[0-9a-f]+$": type: object $ref: common.yaml# unevaluatedProperties: false @@ -60,16 +63,11 @@ patternProperties: since the chip has a single global setting. The maximum output current of each LED is calculated by the following formula: - IMAXled = 160000 * (592 / 600.5) * (1 / display-rows) + IMAXled = 160000 * (592 / 600.5) * (1 / max-current-switch-number) And the minimum output current formula: - IMINled = 3300 * (592 / 600.5) * (1 / display-rows) - -required: - - compatible - - reg - - "#address-cells" - - "#size-cells" - - awinic,display-rows + IMINled = 3300 * (592 / 600.5) * (1 / max-current-switch-number) + where max-current-switch-number is determinated by led configuration + and depends on how leds are physically connected to the led driver. allOf: - if: @@ -78,18 +76,67 @@ allOf: contains: const: awinic,aw20036 then: + patternProperties: + "^led@[0-9a-f]+$": + properties: + reg: + items: + minimum: 0 + maximum: 36 + + - if: properties: - awinic,display-rows: - enum: [1, 2, 3] - else: + compatible: + contains: + const: awinic,aw20054 + then: + patternProperties: + "^led@[0-9a-f]+$": + properties: + reg: + items: + minimum: 0 + maximum: 54 + + - if: properties: - awinic,display-rows: - enum: [1, 2, 3, 4, 5, 6, 7] + compatible: + contains: + const: awinic,aw20072 + then: + patternProperties: + "^led@[0-9a-f]+$": + properties: + reg: + items: + minimum: 0 + maximum: 72 + + - if: + properties: + compatible: + contains: + const: awinic,aw20108 + then: + patternProperties: + "^led@[0-9a-f]+$": + properties: + reg: + items: + minimum: 0 + maximum: 108 + +required: + - compatible + - reg + - "#address-cells" + - "#size-cells" additionalProperties: false examples: - | + #include #include i2c { @@ -101,7 +148,7 @@ examples: reg = <0x3a>; #address-cells = <1>; #size-cells = <0>; - awinic,display-rows = <3>; + enable-gpios = <&gpio 3 GPIO_ACTIVE_HIGH>; led@0 { reg = <0x0>; diff --git a/Documentation/devicetree/bindings/leds/backlight/mps,mp3309c.yaml b/Documentation/devicetree/bindings/leds/backlight/mps,mp3309c.yaml index 4191e33626f51a..527a37368ed742 100644 --- a/Documentation/devicetree/bindings/leds/backlight/mps,mp3309c.yaml +++ b/Documentation/devicetree/bindings/leds/backlight/mps,mp3309c.yaml @@ -14,8 +14,8 @@ description: | programmable switching frequency to optimize efficiency. It supports two different dimming modes: - - analog mode, via I2C commands (default) - - PWM controlled mode. + - analog mode, via I2C commands, as default mode (32 dimming levels) + - PWM controlled mode (optional) The datasheet is available at: https://www.monolithicpower.com/en/mp3309c.html @@ -50,8 +50,6 @@ properties: required: - compatible - reg - - max-brightness - - default-brightness unevaluatedProperties: false @@ -66,8 +64,8 @@ examples: compatible = "mps,mp3309c"; reg = <0x17>; pwms = <&pwm1 0 3333333 0>; /* 300 Hz --> (1/f) * 1*10^9 */ - max-brightness = <100>; - default-brightness = <80>; + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness = <6>; mps,overvoltage-protection-microvolt = <24000000>; }; }; diff --git a/Documentation/devicetree/bindings/leds/common.yaml b/Documentation/devicetree/bindings/leds/common.yaml index c8d0ba5f232764..55a8d1385e2104 100644 --- a/Documentation/devicetree/bindings/leds/common.yaml +++ b/Documentation/devicetree/bindings/leds/common.yaml @@ -167,7 +167,7 @@ properties: Note that this flag is mainly used for PWM-LEDs, where it is not possible to map brightness to current. Drivers for other controllers should use led-max-microamp. - $ref: /schemas/types.yaml#definitions/uint32 + $ref: /schemas/types.yaml#/definitions/uint32 panic-indicator: description: diff --git a/Documentation/devicetree/bindings/leds/qcom,spmi-flash-led.yaml b/Documentation/devicetree/bindings/leds/qcom,spmi-flash-led.yaml index a8736fd5a5390e..1ba607685f5f9b 100644 --- a/Documentation/devicetree/bindings/leds/qcom,spmi-flash-led.yaml +++ b/Documentation/devicetree/bindings/leds/qcom,spmi-flash-led.yaml @@ -89,9 +89,11 @@ additionalProperties: false examples: - | #include - spmi { + + pmic { #address-cells = <1>; #size-cells = <0>; + led-controller@ee00 { compatible = "qcom,pm8350c-flash-led", "qcom,spmi-flash-led"; reg = <0xee00>; diff --git a/Documentation/devicetree/bindings/loongarch/cpus.yaml b/Documentation/devicetree/bindings/loongarch/cpus.yaml new file mode 100644 index 00000000000000..f175872995e117 --- /dev/null +++ b/Documentation/devicetree/bindings/loongarch/cpus.yaml @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/loongarch/cpus.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: LoongArch CPUs + +maintainers: + - Binbin Zhou + +description: + This document describes the list of LoongArch CPU cores that support FDT, + it describe the layout of CPUs in a system through the "cpus" node. + +allOf: + - $ref: /schemas/cpu.yaml# + +properties: + compatible: + enum: + - loongson,la264 + - loongson,la364 + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + +required: + - compatible + - reg + - clocks + +unevaluatedProperties: false + +examples: + - | + #include + + cpus { + #size-cells = <0>; + #address-cells = <1>; + + cpu@0 { + compatible = "loongson,la264"; + device_type = "cpu"; + reg = <0>; + clocks = <&clk LOONGSON2_NODE_CLK>; + }; + + cpu@1 { + compatible = "loongson,la264"; + device_type = "cpu"; + reg = <1>; + clocks = <&clk LOONGSON2_NODE_CLK>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/loongarch/loongson.yaml b/Documentation/devicetree/bindings/loongarch/loongson.yaml new file mode 100644 index 00000000000000..e1a4a97b7576c9 --- /dev/null +++ b/Documentation/devicetree/bindings/loongarch/loongson.yaml @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/loongarch/loongson.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Loongson SoC-based boards + +maintainers: + - Binbin Zhou + +properties: + $nodename: + const: '/' + compatible: + oneOf: + - description: Loongson-2K0500 processor based boards + items: + - const: loongson,ls2k0500-ref + - const: loongson,ls2k0500 + + - description: Loongson-2K1000 processor based boards + items: + - const: loongson,ls2k1000-ref + - const: loongson,ls2k1000 + + - description: Loongson-2K2000 processor based boards + items: + - const: loongson,ls2k2000-ref + - const: loongson,ls2k2000 + +additionalProperties: true + +... diff --git a/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.yaml b/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.yaml index a38413f8d1321b..79eb523b843644 100644 --- a/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.yaml +++ b/Documentation/devicetree/bindings/mailbox/qcom,apcs-kpss-global.yaml @@ -23,6 +23,24 @@ properties: - qcom,ipq8074-apcs-apps-global - qcom,ipq9574-apcs-apps-global - const: qcom,ipq6018-apcs-apps-global + - items: + - enum: + - qcom,qcs404-apcs-apps-global + - const: qcom,msm8916-apcs-kpss-global + - const: syscon + - items: + - enum: + - qcom,msm8976-apcs-kpss-global + - const: qcom,msm8994-apcs-kpss-global + - const: syscon + - items: + - enum: + - qcom,msm8998-apcs-hmss-global + - qcom,sdm660-apcs-hmss-global + - qcom,sm4250-apcs-hmss-global + - qcom,sm6115-apcs-hmss-global + - qcom,sm6125-apcs-hmss-global + - const: qcom,msm8994-apcs-kpss-global - items: - enum: - qcom,sc7180-apss-shared @@ -34,22 +52,14 @@ properties: - qcom,msm8916-apcs-kpss-global - qcom,msm8939-apcs-kpss-global - qcom,msm8953-apcs-kpss-global - - qcom,msm8976-apcs-kpss-global - qcom,msm8994-apcs-kpss-global - - qcom,qcs404-apcs-apps-global - qcom,sdx55-apcs-gcc - const: syscon - enum: - qcom,ipq6018-apcs-apps-global - - qcom,ipq8074-apcs-apps-global - qcom,msm8996-apcs-hmss-global - - qcom,msm8998-apcs-hmss-global - qcom,qcm2290-apcs-hmss-global - - qcom,sdm660-apcs-hmss-global - qcom,sdm845-apss-shared - - qcom,sm4250-apcs-hmss-global - - qcom,sm6115-apcs-hmss-global - - qcom,sm6125-apcs-hmss-global reg: maxItems: 1 @@ -80,20 +90,38 @@ allOf: - if: properties: compatible: - enum: - - qcom,msm8916-apcs-kpss-global - - qcom,msm8939-apcs-kpss-global - - qcom,qcs404-apcs-apps-global + contains: + enum: + - qcom,msm8916-apcs-kpss-global + then: + properties: + clocks: + items: + - description: primary pll parent of the clock driver + - description: auxiliary parent + clock-names: + items: + - const: pll + - const: aux + + - if: + properties: + compatible: + contains: + enum: + - qcom,msm8939-apcs-kpss-global then: properties: clocks: items: - description: primary pll parent of the clock driver - description: auxiliary parent + - description: reference clock clock-names: items: - const: pll - const: aux + - const: ref - if: properties: @@ -113,6 +141,7 @@ allOf: - const: ref - const: pll - const: aux + - if: properties: compatible: @@ -137,16 +166,10 @@ allOf: compatible: enum: - qcom,msm8953-apcs-kpss-global - - qcom,msm8976-apcs-kpss-global - qcom,msm8994-apcs-kpss-global - qcom,msm8996-apcs-hmss-global - - qcom,msm8998-apcs-hmss-global - qcom,qcm2290-apcs-hmss-global - - qcom,sdm660-apcs-hmss-global - qcom,sdm845-apss-shared - - qcom,sm4250-apcs-hmss-global - - qcom,sm6115-apcs-hmss-global - - qcom,sm6125-apcs-hmss-global then: properties: clocks: false @@ -192,7 +215,8 @@ examples: #define GCC_APSS_AHB_CLK_SRC 1 #define GCC_GPLL0_AO_OUT_MAIN 123 apcs: mailbox@b011000 { - compatible = "qcom,qcs404-apcs-apps-global", "syscon"; + compatible = "qcom,qcs404-apcs-apps-global", + "qcom,msm8916-apcs-kpss-global", "syscon"; reg = <0x0b011000 0x1000>; #mbox-cells = <1>; clocks = <&apcs_hfpll>, <&gcc GCC_GPLL0_AO_OUT_MAIN>; diff --git a/Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml b/Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml index a35f9483dc716e..8f004868aad988 100644 --- a/Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml +++ b/Documentation/devicetree/bindings/mailbox/qcom-ipcc.yaml @@ -35,6 +35,7 @@ properties: - qcom,sm8450-ipcc - qcom,sm8550-ipcc - qcom,sm8650-ipcc + - qcom,x1e80100-ipcc - const: qcom,ipcc reg: diff --git a/Documentation/devicetree/bindings/mailbox/xlnx,zynqmp-ipi-mailbox.yaml b/Documentation/devicetree/bindings/mailbox/xlnx,zynqmp-ipi-mailbox.yaml index 8b15a0532120f7..fe83b5cb1278d5 100644 --- a/Documentation/devicetree/bindings/mailbox/xlnx,zynqmp-ipi-mailbox.yaml +++ b/Documentation/devicetree/bindings/mailbox/xlnx,zynqmp-ipi-mailbox.yaml @@ -37,7 +37,9 @@ maintainers: properties: compatible: - const: xlnx,zynqmp-ipi-mailbox + enum: + - xlnx,zynqmp-ipi-mailbox + - xlnx,versal-ipi-mailbox method: description: | @@ -58,6 +60,12 @@ properties: '#size-cells': const: 2 + reg: + maxItems: 2 + + reg-names: + maxItems: 2 + xlnx,ipi-id: description: | Remote Xilinx IPI agent ID of which the mailbox is connected to. @@ -76,7 +84,17 @@ patternProperties: properties: compatible: - const: xlnx,zynqmp-ipi-dest-mailbox + enum: + - xlnx,zynqmp-ipi-dest-mailbox + - xlnx,versal-ipi-dest-mailbox + + reg: + minItems: 1 + maxItems: 4 + + reg-names: + minItems: 1 + maxItems: 4 xlnx,ipi-id: description: @@ -88,23 +106,44 @@ patternProperties: description: It contains tx(0) or rx(1) channel IPI id number. - reg: - maxItems: 4 - - reg-names: - items: - - const: local_request_region - - const: local_response_region - - const: remote_request_region - - const: remote_response_region + allOf: + - if: + properties: + compatible: + contains: + enum: + - xlnx,zynqmp-ipi-dest-mailbox + then: + properties: + reg: + maxItems: 4 + + reg-names: + items: + - const: local_request_region + - const: local_response_region + - const: remote_request_region + - const: remote_response_region + else: + properties: + reg: + minItems: 1 + items: + - description: Remote IPI agent control register region + - description: Remote IPI agent optional message buffers + + reg-names: + minItems: 1 + items: + - const: ctrl + - const: msg required: - compatible - reg - reg-names - "#mbox-cells" - -additionalProperties: false + - xlnx,ipi-id required: - compatible @@ -113,6 +152,36 @@ required: - '#size-cells' - xlnx,ipi-id +allOf: + - if: + properties: + compatible: + contains: + enum: + - xlnx,zynqmp-ipi-mailbox + then: + properties: + reg: false + reg-names: false + + else: + properties: + reg: + items: + - description: Host IPI agent control register region + - description: Host IPI agent optional message buffers + + reg-names: + items: + - const: ctrl + - const: msg + + required: + - reg + - reg-names + +additionalProperties: false + examples: - | #include @@ -144,4 +213,41 @@ examples: }; }; + - | + #include + + bus { + #address-cells = <2>; + #size-cells = <2>; + mailbox@ff300000 { + compatible = "xlnx,versal-ipi-mailbox"; + interrupts = ; + #address-cells = <2>; + #size-cells = <2>; + reg = <0x0 0xff300000 0x0 0x1000>, + <0x0 0xff990000 0x0 0x1ff>; + reg-names = "ctrl", "msg"; + xlnx,ipi-id = <0>; + ranges; + + /* buffered IPI */ + mailbox@ff340000 { + compatible = "xlnx,versal-ipi-dest-mailbox"; + reg = <0x0 0xff340000 0x0 0x1000>, + <0x0 0xff990400 0x0 0x1ff>; + reg-names = "ctrl", "msg"; + #mbox-cells = <1>; + xlnx,ipi-id = <4>; + }; + + /* bufferless IPI */ + mailbox@ff370000 { + compatible = "xlnx,versal-ipi-dest-mailbox"; + reg = <0x0 0xff370000 0x0 0x1000>; + reg-names = "ctrl"; + #mbox-cells = <1>; + xlnx,ipi-id = <7>; + }; + }; + }; ... diff --git a/Documentation/devicetree/bindings/media/cnm,wave521c.yaml b/Documentation/devicetree/bindings/media/cnm,wave521c.yaml new file mode 100644 index 00000000000000..6a11c1d11fb5f9 --- /dev/null +++ b/Documentation/devicetree/bindings/media/cnm,wave521c.yaml @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/cnm,wave521c.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Chips&Media Wave 5 Series multi-standard codec IP + +maintainers: + - Nas Chung + - Jackson Lee + +description: + The Chips&Media WAVE codec IP is a multi format video encoder/decoder + +properties: + compatible: + items: + - enum: + - ti,j721s2-wave521c + - const: cnm,wave521c + + reg: + maxItems: 1 + + clocks: + items: + - description: VCODEC clock + + interrupts: + maxItems: 1 + + power-domains: + maxItems: 1 + + resets: + maxItems: 1 + + sram: + $ref: /schemas/types.yaml#/definitions/phandle + description: + The VPU uses the SRAM to store some of the reference data instead of + storing it on DMA memory. It is mainly used for the purpose of reducing + bandwidth. + +required: + - compatible + - reg + - clocks + +additionalProperties: false + +examples: + - | + vpu: video-codec@12345678 { + compatible = "ti,j721s2-wave521c", "cnm,wave521c"; + reg = <0x12345678 0x1000>; + clocks = <&clks 42>; + interrupts = <42>; + sram = <&sram>; + }; diff --git a/Documentation/devicetree/bindings/media/i2c/alliedvision,alvium-csi2.yaml b/Documentation/devicetree/bindings/media/i2c/alliedvision,alvium-csi2.yaml new file mode 100644 index 00000000000000..d3329e991d1652 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/alliedvision,alvium-csi2.yaml @@ -0,0 +1,81 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/alliedvision,alvium-csi2.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Allied Vision Alvium Camera + +maintainers: + - Tommaso Merciai + - Martin Hecht + +allOf: + - $ref: /schemas/media/video-interface-devices.yaml# + +properties: + compatible: + const: alliedvision,alvium-csi2 + + reg: + maxItems: 1 + + vcc-ext-in-supply: + description: | + The regulator that supplies power to the VCC_EXT_IN pins. + + port: + description: Digital Output Port + $ref: /schemas/graph.yaml#/$defs/port-base + additionalProperties: false + + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + unevaluatedProperties: false + + properties: + link-frequencies: true + + data-lanes: + minItems: 1 + items: + - const: 1 + - const: 2 + - const: 3 + - const: 4 + + required: + - data-lanes + - link-frequencies + +required: + - compatible + - reg + - vcc-ext-in-supply + - port + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + alvium: camera@3c { + compatible = "alliedvision,alvium-csi2"; + reg = <0x3c>; + vcc-ext-in-supply = <®_vcc_ext_in>; + + port { + alvium_out: endpoint { + remote-endpoint = <&mipi_csi_0_in>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <681250000>; + }; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/media/i2c/asahi-kasei,ak7375.yaml b/Documentation/devicetree/bindings/media/i2c/asahi-kasei,ak7375.yaml index 22a810fc722239..fe312cc6a87310 100644 --- a/Documentation/devicetree/bindings/media/i2c/asahi-kasei,ak7375.yaml +++ b/Documentation/devicetree/bindings/media/i2c/asahi-kasei,ak7375.yaml @@ -15,7 +15,9 @@ description: properties: compatible: - const: asahi-kasei,ak7375 + enum: + - asahi-kasei,ak7345 + - asahi-kasei,ak7375 reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/media/i2c/galaxycore,gc0308.yaml b/Documentation/devicetree/bindings/media/i2c/galaxycore,gc0308.yaml new file mode 100644 index 00000000000000..f81e7daed67b61 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/galaxycore,gc0308.yaml @@ -0,0 +1,108 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/galaxycore,gc0308.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Galaxycore GC0308 and GC0309 Image Sensors + +maintainers: + - Sebastian Reichel + +description: | + The GalaxyCore GC0308 (1/6.5") and GC0309 (1/9") are 640x480 VGA sensors + programmable through an I2C interface and connected via parallel bus. + They include an ISP capable of auto exposure and auto white balance. + +allOf: + - $ref: ../video-interface-devices.yaml# + +properties: + compatible: + oneOf: + - const: galaxycore,gc0308 + - items: + - const: galaxycore,gc0309 + - const: galaxycore,gc0308 + + reg: + const: 0x21 + + clocks: + description: Reference to the xclk clock. + maxItems: 1 + + reset-gpios: + description: GPIO descriptor for the reset pin. + maxItems: 1 + + powerdown-gpios: + description: GPIO descriptor for the powerdown pin. + maxItems: 1 + + vdd28-supply: + description: 2.8V supply + + port: + $ref: /schemas/graph.yaml#/$defs/port-base + description: | + Video output port. + + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + unevaluatedProperties: false + + properties: + bus-width: true + data-shift: true + hsync-active: true + vsync-active: true + data-active: true + pclk-sample: true + + required: + - bus-width + + additionalProperties: false + +required: + - compatible + - reg + - clocks + - powerdown-gpios + - port + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + camera-sensor@21 { + compatible = "galaxycore,gc0308"; + reg = <0x21>; + clocks = <&camera_clk>; + powerdown-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio1 6 GPIO_ACTIVE_LOW>; + vdd28-supply = <&vdd28>; + + port { + gc0308_ep: endpoint { + remote-endpoint = <¶llel_from_gc0308>; + bus-width = <8>; + data-shift = <2>; /* lines 9:2 are used */ + hsync-active = <1>; /* active high */ + vsync-active = <1>; /* active high */ + data-active = <1>; /* active high */ + pclk-sample = <1>; /* sample on rising edge */ + }; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/media/i2c/galaxycore,gc2145.yaml b/Documentation/devicetree/bindings/media/i2c/galaxycore,gc2145.yaml new file mode 100644 index 00000000000000..1726ecca4c77e4 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/galaxycore,gc2145.yaml @@ -0,0 +1,113 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/galaxycore,gc2145.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Galaxy Core 1/5'' UXGA CMOS Image Sensor + +maintainers: + - Alain Volmat + +description: + The Galaxy Core GC2145 is a 2 Megapixel CMOS image sensor, for mobile + phone camera applications and digital camera products. GC2145 incorporates a + 1616V x 1232H active pixel array, on-chip 10-bit ADC, and image signal + processor allowing AE/AWB/interpolation/de-noise/color-conversion and + gamma correction. Bayer RGB, RGB565 and YCbCr 4:2:2 can be provided by the + sensor. It is programmable through an I2C interface. Image data is sent + either through a parallel interface or through MIPI CSI-2. + +allOf: + - $ref: ../video-interface-devices.yaml# + +properties: + compatible: + const: galaxycore,gc2145 + + reg: + const: 0x3c + + clocks: + maxItems: 1 + + powerdown-gpios: + maxItems: 1 + + reset-gpios: + maxItems: 1 + + iovdd-supply: + description: Power Supply for I/O circuits (1.7 - 3V). + + avdd-supply: + description: Power for analog circuit/sensor array (2.7 - 3V). + + dvdd-supply: + description: Power for digital core (1.7 - 1.9V). + + orientation: true + + rotation: true + + port: + $ref: /schemas/graph.yaml#/$defs/port-base + + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + unevaluatedProperties: false + + properties: + link-frequencies: true + + required: + - link-frequencies + + required: + - endpoint + + additionalProperties: false + +required: + - compatible + - reg + - clocks + - powerdown-gpios + - reset-gpios + - iovdd-supply + - avdd-supply + - dvdd-supply + - port + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + camera@3c { + compatible = "galaxycore,gc2145"; + reg = <0x3c>; + clocks = <&clk_ext_camera>; + iovdd-supply = <&scmi_v3v3_sw>; + avdd-supply = <&scmi_v3v3_sw>; + dvdd-supply = <&scmi_v3v3_sw>; + powerdown-gpios = <&mcp23017 3 (GPIO_ACTIVE_LOW | GPIO_PUSH_PULL)>; + reset-gpios = <&mcp23017 4 (GPIO_ACTIVE_LOW | GPIO_PUSH_PULL)>; + + port { + endpoint { + remote-endpoint = <&mipid02_0>; + data-lanes = <1 2>; + link-frequencies = /bits/ 64 <120000000 192000000 240000000>; + }; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/media/i2c/ov8856.yaml b/Documentation/devicetree/bindings/media/i2c/ov8856.yaml index 57f5e48fd8e03c..816dac9c6f6091 100644 --- a/Documentation/devicetree/bindings/media/i2c/ov8856.yaml +++ b/Documentation/devicetree/bindings/media/i2c/ov8856.yaml @@ -67,19 +67,17 @@ properties: properties: data-lanes: - description: |- - The driver only supports four-lane operation. - items: - - const: 1 - - const: 2 - - const: 3 - - const: 4 - - link-frequencies: - description: Frequencies listed are driver, not h/w limitations. - maxItems: 2 - items: - enum: [ 360000000, 180000000 ] + oneOf: + - items: + - const: 1 + - items: + - const: 1 + - const: 2 + - items: + - const: 1 + - const: 2 + - const: 3 + - const: 4 required: - link-frequencies diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov64a40.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov64a40.yaml new file mode 100644 index 00000000000000..2b6143aff39139 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov64a40.yaml @@ -0,0 +1,103 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/ovti,ov64a40.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: OmniVision OV64A40 Image Sensor + +maintainers: + - Jacopo Mondi + +allOf: + - $ref: /schemas/media/video-interface-devices.yaml# + +properties: + compatible: + const: ovti,ov64a40 + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + avdd-supply: + description: Analog voltage supply, 2.8 volts + + dvdd-supply: + description: Digital core voltage supply, 1.1 volts + + dovdd-supply: + description: Digital I/O voltage supply, 1.8 volts + + powerdown-gpios: + maxItems: 1 + + reset-gpios: + maxItems: 1 + + port: + $ref: /schemas/graph.yaml#/$defs/port-base + additionalProperties: false + + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + additionalProperties: false + + properties: + bus-type: + enum: + - 1 # MIPI CSI-2 C-PHY + - 4 # MIPI CSI-2 D-PHY + data-lanes: true + link-frequencies: true + clock-noncontinuous: true + remote-endpoint: true + + required: + - bus-type + - data-lanes + - link-frequencies + +required: + - compatible + - reg + - clocks + - port + +unevaluatedProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + camera@36 { + compatible = "ovti,ov64a40"; + reg = <0x36>; + clocks = <&camera_clk>; + dovdd-supply = <&vgen4_reg>; + avdd-supply = <&vgen3_reg>; + dvdd-supply = <&vgen2_reg>; + powerdown-gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>; + rotation = <180>; + orientation = <2>; + + port { + endpoint { + remote-endpoint = <&mipi_csi2_in>; + bus-type = <4>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <456000000>; + }; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx335.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx335.yaml index a167dcdb3a32e5..106c36ee966db0 100644 --- a/Documentation/devicetree/bindings/media/i2c/sony,imx335.yaml +++ b/Documentation/devicetree/bindings/media/i2c/sony,imx335.yaml @@ -32,6 +32,15 @@ properties: description: Clock frequency from 6 to 27 MHz, 37.125MHz, 74.25MHz maxItems: 1 + avdd-supply: + description: Analog power supply (2.9V) + + ovdd-supply: + description: Interface power supply (1.8V) + + dvdd-supply: + description: Digital power supply (1.2V) + reset-gpios: description: Reference to the GPIO connected to the XCLR pin, if any. maxItems: 1 @@ -79,6 +88,10 @@ examples: assigned-clock-parents = <&imx335_clk_parent>; assigned-clock-rates = <24000000>; + avdd-supply = <&camera_vdda_2v9>; + ovdd-supply = <&camera_vddo_1v8>; + dvdd-supply = <&camera_vddd_1v2>; + port { imx335: endpoint { remote-endpoint = <&cam>; diff --git a/Documentation/devicetree/bindings/media/i2c/techwell,tw9900.yaml b/Documentation/devicetree/bindings/media/i2c/techwell,tw9900.yaml new file mode 100644 index 00000000000000..e37317f810722d --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/techwell,tw9900.yaml @@ -0,0 +1,137 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/techwell,tw9900.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Techwell TW9900 NTSC/PAL video decoder + +maintainers: + - Mehdi Djait + +description: + The tw9900 is a multi-standard video decoder, supporting NTSC, PAL standards + with auto-detection features. + +properties: + compatible: + const: techwell,tw9900 + + reg: + maxItems: 1 + + vdd-supply: + description: VDD power supply + + reset-gpios: + description: GPIO descriptor for the RESET input pin + maxItems: 1 + + powerdown-gpios: + description: GPIO descriptor for the POWERDOWN input pin + maxItems: 1 + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + properties: + port@0: + $ref: /schemas/graph.yaml#/$defs/port-base + description: Analog input port + + properties: + endpoint@0: + $ref: /schemas/graph.yaml#/properties/endpoint + description: CVBS over MUX0 + + endpoint@1: + $ref: /schemas/graph.yaml#/properties/endpoint + description: CVBS over MUX1 + + endpoint@2: + $ref: /schemas/graph.yaml#/properties/endpoint + description: Chroma over CIN0 and Y over MUX0 + + endpoint@3: + $ref: /schemas/graph.yaml#/properties/endpoint + description: Chroma over CIN0 and Y over MUX1 + + oneOf: + - required: + - endpoint@0 + - required: + - endpoint@1 + - required: + - endpoint@2 + - required: + - endpoint@3 + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: Video port for the decoder output. + + + required: + - port@0 + - port@1 + +required: + - compatible + - ports + - reg + - vdd-supply + +additionalProperties: false + +examples: + - | + #include + #include + + composite_connector { + compatible = "composite-video-connector"; + label = "tv"; + sdtv-standards = <(SDTV_STD_PAL | SDTV_STD_NTSC)>; + + port { + composite_to_tw9900: endpoint { + remote-endpoint = <&tw9900_to_composite>; + }; + }; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + video-decoder@44 { + compatible = "techwell,tw9900"; + reg = <0x44>; + + vdd-supply = <&tw9900_supply>; + reset-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + #address-cells = <1>; + #size-cells = <0>; + + reg = <0>; + tw9900_to_composite: endpoint@0 { + reg = <0>; + remote-endpoint = <&composite_to_tw9900>; + }; + }; + + port@1 { + reg = <1>; + endpoint { + remote-endpoint = <&cif_in>; + }; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/media/i2c/thine,thp7312.yaml b/Documentation/devicetree/bindings/media/i2c/thine,thp7312.yaml new file mode 100644 index 00000000000000..1978fbb77a6ce5 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/thine,thp7312.yaml @@ -0,0 +1,224 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (c) 2023 Ideas on Board +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/thine,thp7312.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: THine THP7312 + +maintainers: + - Paul Elder + +description: + The THP7312 is a standalone ISP controlled over i2c, and is capable of + various image processing and correction functions, including 3A control. It + can be connected to CMOS image sensors from various vendors, supporting both + MIPI CSI-2 and parallel interfaces. It can also output on either MIPI CSI-2 + or parallel. The hardware is capable of transmitting and receiving MIPI + interlaved data strams with data types or multiple virtual channel + identifiers. + +allOf: + - $ref: /schemas/media/video-interface-devices.yaml# + +properties: + compatible: + const: thine,thp7312 + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + description: CLKI clock input + + thine,boot-mode: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 1 + default: 1 + description: + Boot mode of the THP7312, reflecting the value of the BOOT[0] pin strap. + 0 is for the SPI/2-wire slave boot, 1 is for the SPI master boot (from + external flash ROM). + + reset-gpios: + maxItems: 1 + description: + Reference to the GPIO connected to the RESET_N pin, if any. + Must be released (set high) after all supplies are applied. + + vddcore-supply: + description: + 1.2V supply for core, PLL, MIPI rx and MIPI tx. + + vhtermrx-supply: + description: + Supply for input (RX). 1.8V for MIPI, or 1.8/2.8/3.3V for parallel. + + vddtx-supply: + description: + Supply for output (TX). 1.8V for MIPI, or 1.8/2.8/3.3V for parallel. + + vddhost-supply: + description: + Supply for host interface. 1.8V, 2.8V, or 3.3V. + + vddcmos-supply: + description: + Supply for sensor interface. 1.8V, 2.8V, or 3.3V. + + vddgpio-0-supply: + description: + Supply for GPIO_0. 1.8V, 2.8V, or 3.3V. + + vddgpio-1-supply: + description: + Supply for GPIO_1. 1.8V, 2.8V, or 3.3V. + + orientation: true + rotation: true + + port: + $ref: /schemas/graph.yaml#/$defs/port-base + additionalProperties: false + + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + unevaluatedProperties: false + + properties: + bus-type: + const: 4 # CSI-2 D-PHY + + data-lanes: + description: + This property is for lane reordering between the THP7312 and the + SoC. The sensor supports either two-lane, or four-lane operation. + If this property is omitted four-lane operation is assumed. For + two-lane operation the property must be set to <1 2>. + minItems: 2 + maxItems: 4 + items: + maximum: 4 + + sensors: + type: object + description: List of connected sensors + + properties: + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + patternProperties: + "^sensor@[01]$": + type: object + description: + Sensors connected to the first and second input, with one node per + sensor. + + properties: + thine,model: + $ref: /schemas/types.yaml#/definitions/string + description: + Model of the connected sensors. Must be a valid compatible string. + + reg: + description: THP7312 input port number + items: + - maximum: 1 + + data-lanes: + $ref: /schemas/media/video-interfaces.yaml#/properties/data-lanes + items: + maxItems: 4 + description: + This property is for lane reordering between the THP7312 and the imaging + sensor that it is connected to. + + required: + - reg + - data-lanes + + additionalProperties: false + + required: + - "#address-cells" + - "#size-cells" + + additionalProperties: false + +required: + - compatible + - reg + - reset-gpios + - clocks + - vddcore-supply + - vhtermrx-supply + - vddtx-supply + - vddhost-supply + - vddcmos-supply + - vddgpio-0-supply + - vddgpio-1-supply + - sensors + - port + +additionalProperties: false + +examples: + - | + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + camera@61 { + compatible = "thine,thp7312"; + reg = <0x61>; + + pinctrl-names = "default"; + pinctrl-0 = <&cam1_pins_default>; + + reset-gpios = <&pio 119 GPIO_ACTIVE_LOW>; + clocks = <&camera61_clk>; + + vddcore-supply = <&vsys_v4p2>; + vhtermrx-supply = <&vsys_v4p2>; + vddtx-supply = <&vsys_v4p2>; + vddhost-supply = <&vsys_v4p2>; + vddcmos-supply = <&vsys_v4p2>; + vddgpio-0-supply = <&vsys_v4p2>; + vddgpio-1-supply = <&vsys_v4p2>; + + orientation = <0>; + rotation = <0>; + + sensors { + #address-cells = <1>; + #size-cells = <0>; + + sensor@0 { + thine,model = "sony,imx258"; + reg = <0>; + + data-lanes = <4 1 3 2>; + }; + }; + + port { + thp7312_2_endpoint: endpoint { + remote-endpoint = <&mipi_thp7312_2>; + bus-type = ; + data-lanes = <4 2 1 3>; + }; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/media/mediatek,mdp3-fg.yaml b/Documentation/devicetree/bindings/media/mediatek,mdp3-fg.yaml new file mode 100644 index 00000000000000..03f31b0090855e --- /dev/null +++ b/Documentation/devicetree/bindings/media/mediatek,mdp3-fg.yaml @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/mediatek,mdp3-fg.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek Media Data Path 3 Film Grain + +maintainers: + - Matthias Brugger + - Moudy Ho + +description: + Film Grain (FG) is a Media Data Path 3 (MDP3) component used to add + the film grain according to the AOMedia Video 1 (AV1) standard. + +properties: + compatible: + enum: + - mediatek,mt8195-mdp3-fg + + reg: + maxItems: 1 + + mediatek,gce-client-reg: + description: + The register of display function block to be set by gce. There are 4 arguments, + such as gce node, subsys id, offset and register size. The subsys id that is + mapping to the register of display function blocks is defined in the gce header + include/dt-bindings/gce/-gce.h of each chips. + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + items: + - description: phandle of GCE + - description: GCE subsys id + - description: register offset + - description: register size + maxItems: 1 + + clocks: + maxItems: 1 + +required: + - compatible + - reg + - mediatek,gce-client-reg + - clocks + +additionalProperties: false + +examples: + - | + #include + #include + + display@14002000 { + compatible = "mediatek,mt8195-mdp3-fg"; + reg = <0x14002000 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_1400XXXX 0x2000 0x1000>; + clocks = <&vppsys0 CLK_VPP0_MDP_FG>; + }; diff --git a/Documentation/devicetree/bindings/media/mediatek,mdp3-hdr.yaml b/Documentation/devicetree/bindings/media/mediatek,mdp3-hdr.yaml new file mode 100644 index 00000000000000..d4609bba657870 --- /dev/null +++ b/Documentation/devicetree/bindings/media/mediatek,mdp3-hdr.yaml @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/mediatek,mdp3-hdr.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek Media Data Path 3 HDR + +maintainers: + - Matthias Brugger + - Moudy Ho + +description: + A Media Data Path 3 (MDP3) component used to perform conversion from + High Dynamic Range (HDR) to Standard Dynamic Range (SDR). + +properties: + compatible: + enum: + - mediatek,mt8195-mdp3-hdr + + reg: + maxItems: 1 + + mediatek,gce-client-reg: + description: + The register of display function block to be set by gce. There are 4 arguments, + such as gce node, subsys id, offset and register size. The subsys id that is + mapping to the register of display function blocks is defined in the gce header + include/dt-bindings/gce/-gce.h of each chips. + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + items: + - description: phandle of GCE + - description: GCE subsys id + - description: register offset + - description: register size + maxItems: 1 + + clocks: + maxItems: 1 + +required: + - compatible + - reg + - mediatek,gce-client-reg + - clocks + +additionalProperties: false + +examples: + - | + #include + #include + + display@14004000 { + compatible = "mediatek,mt8195-mdp3-hdr"; + reg = <0x14004000 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_1400XXXX 0x4000 0x1000>; + clocks = <&vppsys0 CLK_VPP0_MDP_HDR>; + }; diff --git a/Documentation/devicetree/bindings/media/mediatek,mdp3-rdma.yaml b/Documentation/devicetree/bindings/media/mediatek,mdp3-rdma.yaml index 7032c7e1503900..59db8306485b32 100644 --- a/Documentation/devicetree/bindings/media/mediatek,mdp3-rdma.yaml +++ b/Documentation/devicetree/bindings/media/mediatek,mdp3-rdma.yaml @@ -20,8 +20,14 @@ description: | properties: compatible: - items: - - const: mediatek,mt8183-mdp3-rdma + oneOf: + - enum: + - mediatek,mt8183-mdp3-rdma + - mediatek,mt8195-mdp3-rdma + - mediatek,mt8195-vdo1-rdma + - items: + - const: mediatek,mt8188-vdo1-rdma + - const: mediatek,mt8195-vdo1-rdma reg: maxItems: 1 @@ -45,6 +51,14 @@ properties: include/dt-bindings/gce/-gce.h of each chips. $ref: /schemas/types.yaml#/definitions/uint32-array + mediatek,scp: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Phandle to the System Control Processor (SCP) used for initializing + and stopping the MDP3, for sending frame data locations to the MDP3's + VPU and to install Inter-Processor Interrupt handlers to control + processing states. + power-domains: maxItems: 1 @@ -52,6 +66,7 @@ properties: items: - description: RDMA clock - description: RSZ clock + minItems: 1 iommus: maxItems: 1 @@ -60,16 +75,72 @@ properties: items: - description: used for 1st data pipe from RDMA - description: used for 2nd data pipe from RDMA + - description: used for 3rd data pipe from RDMA + - description: used for 4th data pipe from RDMA + - description: used for the data pipe from SPLIT + minItems: 1 + + interrupts: + maxItems: 1 + + '#dma-cells': + const: 1 required: - compatible - reg - mediatek,gce-client-reg - - mediatek,gce-events - power-domains - clocks - iommus - - mboxes + - '#dma-cells' + +allOf: + - if: + properties: + compatible: + contains: + const: mediatek,mt8183-mdp3-rdma + + then: + properties: + clocks: + minItems: 2 + + mboxes: + minItems: 2 + + required: + - mboxes + - mediatek,gce-events + + - if: + properties: + compatible: + contains: + const: mediatek,mt8195-mdp3-rdma + + then: + properties: + clocks: + maxItems: 1 + + mboxes: + minItems: 5 + + required: + - mediatek,gce-events + + - if: + properties: + compatible: + contains: + const: mediatek,mt8195-vdo1-rdma + + then: + properties: + clocks: + maxItems: 1 additionalProperties: false @@ -80,16 +151,17 @@ examples: #include #include - mdp3_rdma0: mdp3-rdma0@14001000 { - compatible = "mediatek,mt8183-mdp3-rdma"; - reg = <0x14001000 0x1000>; - mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0x1000 0x1000>; - mediatek,gce-events = , - ; - power-domains = <&spm MT8183_POWER_DOMAIN_DISP>; - clocks = <&mmsys CLK_MM_MDP_RDMA0>, - <&mmsys CLK_MM_MDP_RSZ1>; - iommus = <&iommu>; - mboxes = <&gce 20 CMDQ_THR_PRIO_LOWEST>, - <&gce 21 CMDQ_THR_PRIO_LOWEST>; + dma-controller@14001000 { + compatible = "mediatek,mt8183-mdp3-rdma"; + reg = <0x14001000 0x1000>; + mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0x1000 0x1000>; + mediatek,gce-events = , + ; + power-domains = <&spm MT8183_POWER_DOMAIN_DISP>; + clocks = <&mmsys CLK_MM_MDP_RDMA0>, + <&mmsys CLK_MM_MDP_RSZ1>; + iommus = <&iommu>; + mboxes = <&gce 20 CMDQ_THR_PRIO_LOWEST>, + <&gce 21 CMDQ_THR_PRIO_LOWEST>; + #dma-cells = <1>; }; diff --git a/Documentation/devicetree/bindings/media/mediatek,mdp3-rsz.yaml b/Documentation/devicetree/bindings/media/mediatek,mdp3-rsz.yaml index 78f9de6192ef47..f5676bec43266e 100644 --- a/Documentation/devicetree/bindings/media/mediatek,mdp3-rsz.yaml +++ b/Documentation/devicetree/bindings/media/mediatek,mdp3-rsz.yaml @@ -15,9 +15,13 @@ description: | properties: compatible: - items: + oneOf: - enum: - mediatek,mt8183-mdp3-rsz + - items: + - enum: + - mediatek,mt8195-mdp3-rsz + - const: mediatek,mt8183-mdp3-rsz reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/media/mediatek,mdp3-stitch.yaml b/Documentation/devicetree/bindings/media/mediatek,mdp3-stitch.yaml new file mode 100644 index 00000000000000..d815bea29154b9 --- /dev/null +++ b/Documentation/devicetree/bindings/media/mediatek,mdp3-stitch.yaml @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/mediatek,mdp3-stitch.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek Media Data Path 3 STITCH + +maintainers: + - Matthias Brugger + - Moudy Ho + +description: + One of Media Data Path 3 (MDP3) components used to combine multiple video frame + with overlapping fields of view to produce a segmented panorame. + +properties: + compatible: + enum: + - mediatek,mt8195-mdp3-stitch + + reg: + maxItems: 1 + + mediatek,gce-client-reg: + description: + The register of display function block to be set by gce. There are 4 arguments, + such as gce node, subsys id, offset and register size. The subsys id that is + mapping to the register of display function blocks is defined in the gce header + include/dt-bindings/gce/-gce.h of each chips. + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + items: + - description: phandle of GCE + - description: GCE subsys id + - description: register offset + - description: register size + maxItems: 1 + + clocks: + maxItems: 1 + +required: + - compatible + - reg + - mediatek,gce-client-reg + - clocks + +additionalProperties: false + +examples: + - | + #include + #include + + display@14003000 { + compatible = "mediatek,mt8195-mdp3-stitch"; + reg = <0x14003000 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_1400XXXX 0x3000 0x1000>; + clocks = <&vppsys0 CLK_VPP0_STITCH>; + }; diff --git a/Documentation/devicetree/bindings/media/mediatek,mdp3-tcc.yaml b/Documentation/devicetree/bindings/media/mediatek,mdp3-tcc.yaml new file mode 100644 index 00000000000000..14ea556d4f82a6 --- /dev/null +++ b/Documentation/devicetree/bindings/media/mediatek,mdp3-tcc.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/mediatek,mdp3-tcc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek Media Data Path 3 Tone Curve Conversion + +maintainers: + - Matthias Brugger + +description: + Tone Curve Conversion (TCC) is one of Media Profile Path 3 (MDP3) components. + It is used to handle the tone mapping of various gamma curves in order to + achieve HDR10 effects. This helps adapt the content to the color and + brightness range that standard display devices typically support. + +properties: + compatible: + enum: + - mediatek,mt8195-mdp3-tcc + + reg: + maxItems: 1 + + mediatek,gce-client-reg: + description: + The register of display function block to be set by gce. There are 4 arguments, + such as gce node, subsys id, offset and register size. The subsys id that is + mapping to the register of display function blocks is defined in the gce header + include/dt-bindings/gce/-gce.h of each chips. + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + items: + - description: phandle of GCE + - description: GCE subsys id + - description: register offset + - description: register size + maxItems: 1 + + clocks: + maxItems: 1 + +required: + - compatible + - reg + - mediatek,gce-client-reg + - clocks + +additionalProperties: false + +examples: + - | + #include + #include + + display@1400b000 { + compatible = "mediatek,mt8195-mdp3-tcc"; + reg = <0x1400b000 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_1400XXXX 0xb000 0x1000>; + clocks = <&vppsys0 CLK_VPP0_MDP_TCC>; + }; diff --git a/Documentation/devicetree/bindings/media/mediatek,mdp3-tdshp.yaml b/Documentation/devicetree/bindings/media/mediatek,mdp3-tdshp.yaml new file mode 100644 index 00000000000000..8ab7f2d8e148fb --- /dev/null +++ b/Documentation/devicetree/bindings/media/mediatek,mdp3-tdshp.yaml @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/mediatek,mdp3-tdshp.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek Media Data Path 3 Two-Dimensional Sharpness + +maintainers: + - Matthias Brugger + - Moudy Ho + +description: + Two-Dimensional Sharpness (TDSHP) is a Media Profile Path 3 (MDP3) component + used to perform image edge sharpening and enhance vividness and contrast. + +properties: + compatible: + enum: + - mediatek,mt8195-mdp3-tdshp + + reg: + maxItems: 1 + + mediatek,gce-client-reg: + description: + The register of display function block to be set by gce. There are 4 arguments, + such as gce node, subsys id, offset and register size. The subsys id that is + mapping to the register of display function blocks is defined in the gce header + include/dt-bindings/gce/-gce.h of each chips. + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + items: + - description: phandle of GCE + - description: GCE subsys id + - description: register offset + - description: register size + maxItems: 1 + + clocks: + maxItems: 1 + +required: + - compatible + - reg + - mediatek,gce-client-reg + - clocks + +additionalProperties: false + +examples: + - | + #include + #include + + display@14007000 { + compatible = "mediatek,mt8195-mdp3-tdshp"; + reg = <0x14007000 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_1400XXXX 0x7000 0x1000>; + clocks = <&vppsys0 CLK_VPP0_MDP_TDSHP>; + }; diff --git a/Documentation/devicetree/bindings/media/mediatek,mdp3-wrot.yaml b/Documentation/devicetree/bindings/media/mediatek,mdp3-wrot.yaml index 0baa77198fa217..53a67933840256 100644 --- a/Documentation/devicetree/bindings/media/mediatek,mdp3-wrot.yaml +++ b/Documentation/devicetree/bindings/media/mediatek,mdp3-wrot.yaml @@ -15,9 +15,13 @@ description: | properties: compatible: - items: + oneOf: - enum: - mediatek,mt8183-mdp3-wrot + - items: + - enum: + - mediatek,mt8195-mdp3-wrot + - const: mediatek,mt8183-mdp3-wrot reg: maxItems: 1 @@ -50,6 +54,9 @@ properties: iommus: maxItems: 1 + '#dma-cells': + const: 1 + required: - compatible - reg @@ -58,6 +65,7 @@ required: - power-domains - clocks - iommus + - '#dma-cells' additionalProperties: false @@ -68,13 +76,14 @@ examples: #include #include - mdp3_wrot0: mdp3-wrot0@14005000 { - compatible = "mediatek,mt8183-mdp3-wrot"; - reg = <0x14005000 0x1000>; - mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0x5000 0x1000>; - mediatek,gce-events = , - ; - power-domains = <&spm MT8183_POWER_DOMAIN_DISP>; - clocks = <&mmsys CLK_MM_MDP_WROT0>; - iommus = <&iommu>; + dma-controller@14005000 { + compatible = "mediatek,mt8183-mdp3-wrot"; + reg = <0x14005000 0x1000>; + mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0x5000 0x1000>; + mediatek,gce-events = , + ; + power-domains = <&spm MT8183_POWER_DOMAIN_DISP>; + clocks = <&mmsys CLK_MM_MDP_WROT0>; + iommus = <&iommu>; + #dma-cells = <1>; }; diff --git a/Documentation/devicetree/bindings/media/rockchip-isp1.yaml b/Documentation/devicetree/bindings/media/rockchip-isp1.yaml index e466dff8286d2b..afcaa427d48b09 100644 --- a/Documentation/devicetree/bindings/media/rockchip-isp1.yaml +++ b/Documentation/devicetree/bindings/media/rockchip-isp1.yaml @@ -90,15 +90,16 @@ properties: description: connection point for input on the parallel interface properties: - bus-type: - enum: [5, 6] - endpoint: $ref: video-interfaces.yaml# unevaluatedProperties: false - required: - - bus-type + properties: + bus-type: + enum: [5, 6] + + required: + - bus-type anyOf: - required: diff --git a/Documentation/devicetree/bindings/media/samsung,s5p-mfc.yaml b/Documentation/devicetree/bindings/media/samsung,s5p-mfc.yaml index 084b44582a434d..b46cc780703c6c 100644 --- a/Documentation/devicetree/bindings/media/samsung,s5p-mfc.yaml +++ b/Documentation/devicetree/bindings/media/samsung,s5p-mfc.yaml @@ -24,6 +24,7 @@ properties: - samsung,mfc-v7 # Exynos5420 - samsung,mfc-v8 # Exynos5800 - samsung,mfc-v10 # Exynos7880 + - tesla,fsd-mfc # Tesla FSD - items: - enum: - samsung,exynos3250-mfc # Exynos3250 @@ -49,7 +50,9 @@ properties: iommu-names: minItems: 1 - maxItems: 2 + items: + - const: left + - const: right power-domains: maxItems: 1 @@ -84,7 +87,7 @@ allOf: - const: sclk_mfc iommus: maxItems: 1 - iommus-names: false + iommu-names: false - if: properties: @@ -102,11 +105,9 @@ allOf: - const: aclk - const: aclk_xiu iommus: - maxItems: 2 - iommus-names: - items: - - const: left - - const: right + minItems: 2 + iommu-names: + minItems: 2 - if: properties: @@ -123,11 +124,9 @@ allOf: - const: mfc - const: sclk_mfc iommus: - maxItems: 2 - iommus-names: - items: - - const: left - - const: right + minItems: 2 + iommu-names: + minItems: 2 - if: properties: @@ -144,11 +143,9 @@ allOf: items: - const: mfc iommus: - maxItems: 2 - iommus-names: - items: - - const: left - - const: right + minItems: 2 + iommu-names: + minItems: 2 - if: properties: @@ -161,9 +158,23 @@ allOf: clocks: minItems: 1 maxItems: 2 + + - if: + properties: + compatible: + contains: + enum: + - tesla,fsd-mfc + then: + properties: + clocks: + maxItems: 1 + clock-names: + items: + - const: mfc iommus: - minItems: 1 maxItems: 2 + iommus-names: false examples: - | diff --git a/Documentation/devicetree/bindings/media/st,stm32-dcmipp.yaml b/Documentation/devicetree/bindings/media/st,stm32-dcmipp.yaml new file mode 100644 index 00000000000000..87731f3ce7bd52 --- /dev/null +++ b/Documentation/devicetree/bindings/media/st,stm32-dcmipp.yaml @@ -0,0 +1,89 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/st,stm32-dcmipp.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: STMicroelectronics STM32 DCMIPP Digital Camera Memory Interface Pixel Processor + +maintainers: + - Hugues Fruchet + - Alain Volmat + +properties: + compatible: + const: st,stm32mp13-dcmipp + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + resets: + maxItems: 1 + + port: + $ref: /schemas/graph.yaml#/$defs/port-base + unevaluatedProperties: false + description: + DCMIPP supports a single port node with parallel bus. + + properties: + endpoint: + $ref: video-interfaces.yaml# + unevaluatedProperties: false + + properties: + bus-type: + enum: [5, 6] + default: 5 + + bus-width: + enum: [8, 10, 12, 14] + default: 8 + + pclk-sample: true + hsync-active: true + vsync-active: true + + required: + - pclk-sample + +required: + - compatible + - reg + - interrupts + - clocks + - resets + - port + +additionalProperties: false + +examples: + - | + #include + #include + #include + dcmipp@5a000000 { + compatible = "st,stm32mp13-dcmipp"; + reg = <0x5a000000 0x400>; + interrupts = ; + resets = <&rcc DCMIPP_R>; + clocks = <&rcc DCMIPP_K>; + + port { + endpoint { + remote-endpoint = <&mipid02_2>; + bus-width = <8>; + hsync-active = <0>; + vsync-active = <0>; + pclk-sample = <0>; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/media/starfive,jh7110-camss.yaml b/Documentation/devicetree/bindings/media/starfive,jh7110-camss.yaml new file mode 100644 index 00000000000000..c66586d90fa2b4 --- /dev/null +++ b/Documentation/devicetree/bindings/media/starfive,jh7110-camss.yaml @@ -0,0 +1,180 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/starfive,jh7110-camss.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Starfive SoC CAMSS ISP + +maintainers: + - Jack Zhu + - Changhuang Liang + +description: + The Starfive CAMSS ISP is a Camera interface for Starfive JH7110 SoC. It + consists of a VIN controller (Video In Controller, a top-level control unit) + and an ISP. + +properties: + compatible: + const: starfive,jh7110-camss + + reg: + maxItems: 2 + + reg-names: + items: + - const: syscon + - const: isp + + clocks: + maxItems: 7 + + clock-names: + items: + - const: apb_func + - const: wrapper_clk_c + - const: dvp_inv + - const: axiwr + - const: mipi_rx0_pxl + - const: ispcore_2x + - const: isp_axi + + resets: + maxItems: 6 + + reset-names: + items: + - const: wrapper_p + - const: wrapper_c + - const: axird + - const: axiwr + - const: isp_top_n + - const: isp_top_axi + + power-domains: + items: + - description: JH7110 ISP Power Domain Switch Controller. + + interrupts: + maxItems: 4 + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + properties: + port@0: + $ref: /schemas/graph.yaml#/$defs/port-base + unevaluatedProperties: false + description: Input port for receiving DVP data. + + properties: + endpoint: + $ref: video-interfaces.yaml# + unevaluatedProperties: false + + properties: + bus-type: + enum: [5, 6] + + bus-width: + enum: [8, 10, 12] + + data-shift: + enum: [0, 2] + default: 0 + + hsync-active: + enum: [0, 1] + default: 1 + + vsync-active: + enum: [0, 1] + default: 1 + + required: + - bus-type + - bus-width + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: Input port for receiving CSI data. + + required: + - port@0 + - port@1 + +required: + - compatible + - reg + - reg-names + - clocks + - clock-names + - resets + - reset-names + - power-domains + - interrupts + - ports + +additionalProperties: false + +examples: + - | + isp@19840000 { + compatible = "starfive,jh7110-camss"; + reg = <0x19840000 0x10000>, + <0x19870000 0x30000>; + reg-names = "syscon", "isp"; + clocks = <&ispcrg 0>, + <&ispcrg 13>, + <&ispcrg 2>, + <&ispcrg 12>, + <&ispcrg 1>, + <&syscrg 51>, + <&syscrg 52>; + clock-names = "apb_func", + "wrapper_clk_c", + "dvp_inv", + "axiwr", + "mipi_rx0_pxl", + "ispcore_2x", + "isp_axi"; + resets = <&ispcrg 0>, + <&ispcrg 1>, + <&ispcrg 10>, + <&ispcrg 11>, + <&syscrg 41>, + <&syscrg 42>; + reset-names = "wrapper_p", + "wrapper_c", + "axird", + "axiwr", + "isp_top_n", + "isp_top_axi"; + power-domains = <&pwrc 5>; + interrupts = <92>, <87>, <88>, <90>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + vin_from_sc2235: endpoint { + remote-endpoint = <&sc2235_to_vin>; + bus-type = <5>; + bus-width = <8>; + data-shift = <2>; + hsync-active = <1>; + vsync-active = <0>; + pclk-sample = <1>; + }; + }; + + port@1 { + reg = <1>; + vin_from_csi2rx: endpoint { + remote-endpoint = <&csi2rx_to_vin>; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/mfd/ams,as3711.yaml b/Documentation/devicetree/bindings/mfd/ams,as3711.yaml new file mode 100644 index 00000000000000..ad8649cbb2ccef --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/ams,as3711.yaml @@ -0,0 +1,223 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/ams,as3711.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Austria MicroSystems AS3711 Quad Buck High Current PMIC with Charger + +maintainers: + - Guennadi Liakhovetski + +description: + AS3711 is an I2C PMIC from Austria MicroSystems with multiple DC/DC and LDO + power supplies, a battery charger and an RTC. So far only bindings for the + two step-up DC/DC converters are defined. + +properties: + compatible: + const: ams,as3711 + + reg: + maxItems: 1 + + backlight: + description: + Step-up converter configuration, to be used as a backlight source + type: object + additionalProperties: false + properties: + compatible: + const: ams,as3711-bl + + su1-dev: + description: Framebuffer phandle for the first step-up converter + $ref: /schemas/types.yaml#/definitions/phandle + + su1-max-uA: + description: Maximum current for the first step-up converter + $ref: /schemas/types.yaml#/definitions/uint32 + + su2-dev: + description: Framebuffer phandle for the second step-up converter + $ref: /schemas/types.yaml#/definitions/phandle + + su2-max-uA: + description: Maximum current for the second step-up converter + $ref: /schemas/types.yaml#/definitions/uint32 + + su2-feedback-voltage: + description: Second step-up converter uses voltage feedback + type: boolean + + su2-feedback-curr1: + description: + Second step-up converter uses CURR1 input for current feedback + type: boolean + + su2-feedback-curr2: + description: + Second step-up converter uses CURR2 input for current feedback + type: boolean + + su2-feedback-curr3: + description: + Second step-up converter uses CURR3 input for current feedback + type: boolean + + su2-feedback-curr-auto: + description: + Second step-up converter uses automatic current feedback selection + type: boolean + + su2-fbprot-lx-sd4: + description: + Second step-up converter uses LX_SD4 for over-voltage protection + type: boolean + + su2-fbprot-gpio2: + description: + Second step-up converter uses GPIO2 for over-voltage protection + type: boolean + + su2-fbprot-gpio3: + description: + Second step-up converter uses GPIO3 for over-voltage protection + type: boolean + + su2-fbprot-gpio4: + description: + Second step-up converter uses GPIO4 for over-voltage protection + type: boolean + + su2-auto-curr1: + description: + Second step-up converter uses CURR1 input for automatic current + feedback + type: boolean + + su2-auto-curr2: + description: + Second step-up converter uses CURR2 input for automatic current + feedback + type: boolean + + su2-auto-curr3: + description: + Second step-up converter uses CURR3 input for automatic current + feedback + type: boolean + + required: + - compatible + + dependentRequired: + # To use the SU1 converter as a backlight source the following two + # properties must be provided: + su1-dev: [ su1-max-uA ] + su1-max-uA: [ su1-dev ] + + # To use the SU2 converter as a backlight source the following two + # properties must be provided: + su2-dev: [ su2-max-uA ] + su2-max-uA: [ su2-dev ] + + su2-feedback-voltage: [ su2-dev ] + su2-feedback-curr1: [ su2-dev ] + su2-feedback-curr2: [ su2-dev ] + su2-feedback-curr3: [ su2-dev ] + su2-feedback-curr-auto: [ su2-dev ] + su2-fbprot-lx-sd4: [ su2-dev ] + su2-fbprot-gpio2: [ su2-dev ] + su2-fbprot-gpio3: [ su2-dev ] + su2-fbprot-gpio4: [ su2-dev ] + su2-auto-curr1: [ su2-feedback-curr-auto ] + su2-auto-curr2: [ su2-feedback-curr-auto ] + su2-auto-curr3: [ su2-feedback-curr-auto ] + + dependentSchemas: + su2-dev: + allOf: + - oneOf: + - required: + - su2-feedback-voltage + - required: + - su2-feedback-curr1 + - required: + - su2-feedback-curr2 + - required: + - su2-feedback-curr3 + - required: + - su2-feedback-curr-auto + - oneOf: + - required: + - su2-fbprot-lx-sd4 + - required: + - su2-fbprot-gpio2 + - required: + - su2-fbprot-gpio3 + - required: + - su2-fbprot-gpio4 + + su2-feedback-curr-auto: + anyOf: + - required: + - su2-auto-curr1 + - required: + - su2-auto-curr2 + - required: + - su2-auto-curr3 + + regulators: + description: Other DC/DC and LDO supplies + type: object + unevaluatedProperties: false + patternProperties: + "^(sd[1-4]|ldo[1-8])$": + type: object + $ref: /schemas/regulator/regulator.yaml# + unevaluatedProperties: false + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + pmic@40 { + compatible = "ams,as3711"; + reg = <0x40>; + + regulators { + sd4 { + regulator-name = "1.215V"; + regulator-min-microvolt = <1215000>; + regulator-max-microvolt = <1235000>; + }; + ldo2 { + regulator-name = "2.8V CPU"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-always-on; + regulator-boot-on; + }; + }; + + backlight { + compatible = "ams,as3711-bl"; + su2-dev = <&lcdc>; + su2-max-uA = <36000>; + su2-feedback-curr-auto; + su2-fbprot-gpio4; + su2-auto-curr1; + su2-auto-curr2; + su2-auto-curr3; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/mfd/as3711.txt b/Documentation/devicetree/bindings/mfd/as3711.txt deleted file mode 100644 index d98cf18c721ceb..00000000000000 --- a/Documentation/devicetree/bindings/mfd/as3711.txt +++ /dev/null @@ -1,73 +0,0 @@ -AS3711 is an I2C PMIC from Austria MicroSystems with multiple DCDC and LDO power -supplies, a battery charger and an RTC. So far only bindings for the two stepup -DCDC converters are defined. Other DCDC and LDO supplies are configured, using -standard regulator properties, they must belong to a sub-node, called -"regulators" and be called "sd1" to "sd4" and "ldo1" to "ldo8." Stepup converter -configuration should be placed in a subnode, called "backlight." - -Compulsory properties: -- compatible : must be "ams,as3711" -- reg : specifies the I2C address - -To use the SU1 converter as a backlight source the following two properties must -be provided: -- su1-dev : framebuffer phandle -- su1-max-uA : maximum current - -To use the SU2 converter as a backlight source the following two properties must -be provided: -- su2-dev : framebuffer phandle -- su1-max-uA : maximum current - -Additionally one of these properties must be provided to select the type of -feedback used: -- su2-feedback-voltage : voltage feedback is used -- su2-feedback-curr1 : CURR1 input used for current feedback -- su2-feedback-curr2 : CURR2 input used for current feedback -- su2-feedback-curr3 : CURR3 input used for current feedback -- su2-feedback-curr-auto: automatic current feedback selection - -and one of these to select the over-voltage protection pin -- su2-fbprot-lx-sd4 : LX_SD4 is used for over-voltage protection -- su2-fbprot-gpio2 : GPIO2 is used for over-voltage protection -- su2-fbprot-gpio3 : GPIO3 is used for over-voltage protection -- su2-fbprot-gpio4 : GPIO4 is used for over-voltage protection - -If "su2-feedback-curr-auto" is selected, one or more of the following properties -have to be specified: -- su2-auto-curr1 : use CURR1 input for current feedback -- su2-auto-curr2 : use CURR2 input for current feedback -- su2-auto-curr3 : use CURR3 input for current feedback - -Example: - -as3711@40 { - compatible = "ams,as3711"; - reg = <0x40>; - - regulators { - sd4 { - regulator-name = "1.215V"; - regulator-min-microvolt = <1215000>; - regulator-max-microvolt = <1235000>; - }; - ldo2 { - regulator-name = "2.8V CPU"; - regulator-min-microvolt = <2800000>; - regulator-max-microvolt = <2800000>; - regulator-always-on; - regulator-boot-on; - }; - }; - - backlight { - compatible = "ams,as3711-bl"; - su2-dev = <&lcdc>; - su2-max-uA = <36000>; - su2-feedback-curr-auto; - su2-fbprot-gpio4; - su2-auto-curr1; - su2-auto-curr2; - su2-auto-curr3; - }; -}; diff --git a/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml b/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml index bdff5b6534538d..6a824351834ee0 100644 --- a/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml +++ b/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml @@ -17,7 +17,7 @@ description: | node. The SPMI controller part is provided by - Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml + Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml properties: $nodename: @@ -42,13 +42,6 @@ properties: additionalProperties: false - properties: - '#address-cells': - const: 1 - - '#size-cells': - const: 0 - patternProperties: '^ldo[0-9]+$': type: object @@ -66,72 +59,75 @@ additionalProperties: false examples: - | + #include - pmic: pmic@0 { - compatible = "hisilicon,hi6421v600-spmi"; - reg = <0 0>; - - #interrupt-cells = <2>; - interrupt-controller; - interrupt-parent = <&gpio28>; - interrupts = <0 0>; - - regulators { - #address-cells = <1>; + spmi { + #address-cells = <2>; #size-cells = <0>; - ldo3: ldo3 { - regulator-name = "ldo3"; - regulator-min-microvolt = <1500000>; - regulator-max-microvolt = <2000000>; - regulator-boot-on; - }; - - ldo4: ldo4 { - regulator-name = "ldo4"; - regulator-min-microvolt = <1725000>; - regulator-max-microvolt = <1900000>; - regulator-boot-on; - }; - - ldo9: ldo9 { - regulator-name = "ldo9"; - regulator-min-microvolt = <1750000>; - regulator-max-microvolt = <3300000>; - regulator-boot-on; - }; - - ldo15: ldo15 { - regulator-name = "ldo15"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <3000000>; - regulator-always-on; - }; - - ldo16: ldo16 { - regulator-name = "ldo16"; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <3000000>; - regulator-boot-on; - }; - - ldo17: ldo17 { - regulator-name = "ldo17"; - regulator-min-microvolt = <2500000>; - regulator-max-microvolt = <3300000>; - }; - - ldo33: ldo33 { - regulator-name = "ldo33"; - regulator-min-microvolt = <2500000>; - regulator-max-microvolt = <3300000>; - regulator-boot-on; - }; - - ldo34: ldo34 { - regulator-name = "ldo34"; - regulator-min-microvolt = <2600000>; - regulator-max-microvolt = <3300000>; + pmic@0 { + compatible = "hisilicon,hi6421v600-spmi"; + reg = <0 SPMI_USID>; + + #interrupt-cells = <2>; + interrupt-controller; + interrupt-parent = <&gpio28>; + interrupts = <0 0>; + + regulators { + ldo3 { + regulator-name = "ldo3"; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <2000000>; + regulator-boot-on; + }; + + ldo4 { + regulator-name = "ldo4"; + regulator-min-microvolt = <1725000>; + regulator-max-microvolt = <1900000>; + regulator-boot-on; + }; + + ldo9 { + regulator-name = "ldo9"; + regulator-min-microvolt = <1750000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + }; + + ldo15 { + regulator-name = "ldo15"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3000000>; + regulator-always-on; + }; + + ldo16 { + regulator-name = "ldo16"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3000000>; + regulator-boot-on; + }; + + ldo17 { + regulator-name = "ldo17"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <3300000>; + }; + + ldo33 { + regulator-name = "ldo33"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + }; + + ldo34 { + regulator-name = "ldo34"; + regulator-min-microvolt = <2600000>; + regulator-max-microvolt = <3300000>; + }; + }; }; - }; }; diff --git a/Documentation/devicetree/bindings/mfd/qcom,pm8008.yaml b/Documentation/devicetree/bindings/mfd/qcom,pm8008.yaml index 9e4eed34dae8af..0c75d8bde56882 100644 --- a/Documentation/devicetree/bindings/mfd/qcom,pm8008.yaml +++ b/Documentation/devicetree/bindings/mfd/qcom,pm8008.yaml @@ -99,10 +99,12 @@ examples: - | #include #include - qupv3_se13_i2c { + + i2c { #address-cells = <1>; #size-cells = <0>; - pm8008i@8 { + + pmic@8 { compatible = "qcom,pm8008"; reg = <0x8>; #address-cells = <1>; diff --git a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml index 9fa56860393069..8103fb61a16cc9 100644 --- a/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml +++ b/Documentation/devicetree/bindings/mfd/qcom,spmi-pmic.yaml @@ -66,6 +66,7 @@ properties: - qcom,pm8841 - qcom,pm8909 - qcom,pm8916 + - qcom,pm8937 - qcom,pm8941 - qcom,pm8950 - qcom,pm8953 @@ -134,9 +135,15 @@ patternProperties: type: object $ref: /schemas/sound/qcom,pm8916-wcd-analog-codec.yaml# + "^battery@[0-9a-f]+$": + type: object + oneOf: + - $ref: /schemas/power/supply/qcom,pm8916-bms-vm.yaml# + "^charger@[0-9a-f]+$": type: object oneOf: + - $ref: /schemas/power/supply/qcom,pm8916-lbc.yaml# - $ref: /schemas/power/supply/qcom,pm8941-charger.yaml# - $ref: /schemas/power/supply/qcom,pm8941-coincell.yaml# - $ref: /schemas/power/supply/qcom,pmi8998-charger.yaml# diff --git a/Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml b/Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml index 33c3d023a10681..798705ab6a4601 100644 --- a/Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml +++ b/Documentation/devicetree/bindings/mfd/qcom,tcsr.yaml @@ -29,6 +29,8 @@ properties: - qcom,sdx65-tcsr - qcom,sm4450-tcsr - qcom,sm8150-tcsr + - qcom,sm8250-tcsr + - qcom,sm8350-tcsr - qcom,sm8450-tcsr - qcom,tcsr-apq8064 - qcom,tcsr-apq8084 diff --git a/Documentation/devicetree/bindings/mfd/samsung,exynos5433-lpass.yaml b/Documentation/devicetree/bindings/mfd/samsung,exynos5433-lpass.yaml index b97b0684872931..f154103f32cc2f 100644 --- a/Documentation/devicetree/bindings/mfd/samsung,exynos5433-lpass.yaml +++ b/Documentation/devicetree/bindings/mfd/samsung,exynos5433-lpass.yaml @@ -85,7 +85,7 @@ examples: }; i2s@11440000 { - compatible = "samsung,exynos7-i2s"; + compatible = "samsung,exynos5433-i2s", "samsung,exynos7-i2s"; reg = <0x11440000 0x100>; dmas = <&adma 0>, <&adma 2>; dma-names = "tx", "rx"; diff --git a/Documentation/devicetree/bindings/mfd/sprd,ums512-glbreg.yaml b/Documentation/devicetree/bindings/mfd/sprd,ums512-glbreg.yaml index 996bd4a17ca357..a750fa23d7e7c2 100644 --- a/Documentation/devicetree/bindings/mfd/sprd,ums512-glbreg.yaml +++ b/Documentation/devicetree/bindings/mfd/sprd,ums512-glbreg.yaml @@ -19,7 +19,9 @@ description: properties: compatible: items: - - const: sprd,ums512-glbregs + - enum: + - sprd,ums512-glbregs + - sprd,ums9620-glbregs - const: syscon - const: simple-mfd diff --git a/Documentation/devicetree/bindings/mfd/ti,am3359-tscadc.yaml b/Documentation/devicetree/bindings/mfd/ti,am3359-tscadc.yaml index 23a63265be3c8c..70b5dfce07d29b 100644 --- a/Documentation/devicetree/bindings/mfd/ti,am3359-tscadc.yaml +++ b/Documentation/devicetree/bindings/mfd/ti,am3359-tscadc.yaml @@ -61,8 +61,6 @@ required: - interrupts - clocks - clock-names - - dmas - - dma-names additionalProperties: false diff --git a/Documentation/devicetree/bindings/misc/fsl,dpaa2-console.yaml b/Documentation/devicetree/bindings/misc/fsl,dpaa2-console.yaml index 8cc951feb7df4b..59b83ea5e05eef 100644 --- a/Documentation/devicetree/bindings/misc/fsl,dpaa2-console.yaml +++ b/Documentation/devicetree/bindings/misc/fsl,dpaa2-console.yaml @@ -12,7 +12,7 @@ maintainers: properties: compatible: - const: "fsl,dpaa2-console" + const: fsl,dpaa2-console reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml b/Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml index 3e99801f77d21d..9075add020bf02 100644 --- a/Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml +++ b/Documentation/devicetree/bindings/mmc/arasan,sdhci.yaml @@ -226,8 +226,8 @@ examples: interrupt-parent = <&gic>; interrupts = <0 48 4>; reg = <0xff160000 0x1000>; - clocks = <&clk200>, <&clk200>; - clock-names = "clk_xin", "clk_ahb"; + clocks = <&clk200>, <&clk200>, <&clk1200>; + clock-names = "clk_xin", "clk_ahb", "gate"; clock-output-names = "clk_out_sd0", "clk_in_sd0"; #clock-cells = <1>; clk-phase-sd-hs = <63>, <72>; @@ -239,8 +239,8 @@ examples: interrupt-parent = <&gic>; interrupts = <0 126 4>; reg = <0xf1040000 0x10000>; - clocks = <&clk200>, <&clk200>; - clock-names = "clk_xin", "clk_ahb"; + clocks = <&clk200>, <&clk200>, <&clk1200>; + clock-names = "clk_xin", "clk_ahb", "gate"; clock-output-names = "clk_out_sd0", "clk_in_sd0"; #clock-cells = <1>; clk-phase-sd-hs = <132>, <60>; diff --git a/Documentation/devicetree/bindings/mmc/arm,pl18x.yaml b/Documentation/devicetree/bindings/mmc/arm,pl18x.yaml index 2459a55ed540b8..940b1268816746 100644 --- a/Documentation/devicetree/bindings/mmc/arm,pl18x.yaml +++ b/Documentation/devicetree/bindings/mmc/arm,pl18x.yaml @@ -203,7 +203,7 @@ examples: bus-width = <4>; cap-sd-highspeed; cap-mmc-highspeed; - cd-gpios = <&gpio2 31 0x4>; + cd-gpios = <&gpio2 31 0x4>; st,sig-dir-dat0; st,sig-dir-dat2; st,sig-dir-cmd; diff --git a/Documentation/devicetree/bindings/mmc/brcm,sdhci-brcmstb.yaml b/Documentation/devicetree/bindings/mmc/brcm,sdhci-brcmstb.yaml index c028039bc477ce..cbd3d6c6c77f81 100644 --- a/Documentation/devicetree/bindings/mmc/brcm,sdhci-brcmstb.yaml +++ b/Documentation/devicetree/bindings/mmc/brcm,sdhci-brcmstb.yaml @@ -20,10 +20,8 @@ properties: - const: brcm,sdhci-brcmstb - items: - enum: + - brcm,bcm74165b0-sdhci - brcm,bcm7445-sdhci - - const: brcm,sdhci-brcmstb - - items: - - enum: - brcm,bcm7425-sdhci - const: brcm,sdhci-brcmstb diff --git a/Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.yaml b/Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.yaml index 3a8e74894ae018..cfe6237716f4ea 100644 --- a/Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.yaml +++ b/Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.yaml @@ -27,7 +27,9 @@ properties: - marvell,armada-ap806-sdhci - items: - - const: marvell,armada-ap807-sdhci + - enum: + - marvell,armada-ap807-sdhci + - marvell,ac5-sdhci - const: marvell,armada-ap806-sdhci - items: diff --git a/Documentation/devicetree/bindings/mmc/mtk-sd.yaml b/Documentation/devicetree/bindings/mmc/mtk-sd.yaml index 3fffa467e4e1c3..c532ec92d2d9c6 100644 --- a/Documentation/devicetree/bindings/mmc/mtk-sd.yaml +++ b/Documentation/devicetree/bindings/mmc/mtk-sd.yaml @@ -145,6 +145,15 @@ properties: minimum: 0 maximum: 7 + mediatek,tuning-step: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Some SoCs need extend tuning step for better delay value to avoid CRC issue. + If not present, default tuning step is 32. For eMMC and SD, this can yield + satisfactory calibration results in most cases. + enum: [32, 64] + default: 32 + resets: maxItems: 1 diff --git a/Documentation/devicetree/bindings/mmc/renesas,sdhi.yaml b/Documentation/devicetree/bindings/mmc/renesas,sdhi.yaml index 94e22878763054..f7a4c6bc70f6ca 100644 --- a/Documentation/devicetree/bindings/mmc/renesas,sdhi.yaml +++ b/Documentation/devicetree/bindings/mmc/renesas,sdhi.yaml @@ -56,7 +56,7 @@ properties: - renesas,sdhi-r8a77980 # R-Car V3H - renesas,sdhi-r8a77990 # R-Car E3 - renesas,sdhi-r8a77995 # R-Car D3 - - renesas,sdhi-r9a07g043 # RZ/G2UL + - renesas,sdhi-r9a07g043 # RZ/G2UL and RZ/Five - renesas,sdhi-r9a07g044 # RZ/G2{L,LC} - renesas,sdhi-r9a07g054 # RZ/V2L - renesas,sdhi-r9a08g045 # RZ/G3S diff --git a/Documentation/devicetree/bindings/mmc/samsung,exynos-dw-mshc.yaml b/Documentation/devicetree/bindings/mmc/samsung,exynos-dw-mshc.yaml index 6ee78a38bd7466..5fe65795f7963e 100644 --- a/Documentation/devicetree/bindings/mmc/samsung,exynos-dw-mshc.yaml +++ b/Documentation/devicetree/bindings/mmc/samsung,exynos-dw-mshc.yaml @@ -14,15 +14,22 @@ maintainers: properties: compatible: - enum: - - samsung,exynos4210-dw-mshc - - samsung,exynos4412-dw-mshc - - samsung,exynos5250-dw-mshc - - samsung,exynos5420-dw-mshc - - samsung,exynos5420-dw-mshc-smu - - samsung,exynos7-dw-mshc - - samsung,exynos7-dw-mshc-smu - - axis,artpec8-dw-mshc + oneOf: + - enum: + - axis,artpec8-dw-mshc + - samsung,exynos4210-dw-mshc + - samsung,exynos4412-dw-mshc + - samsung,exynos5250-dw-mshc + - samsung,exynos5420-dw-mshc + - samsung,exynos5420-dw-mshc-smu + - samsung,exynos7-dw-mshc + - samsung,exynos7-dw-mshc-smu + - items: + - enum: + - samsung,exynos5433-dw-mshc-smu + - samsung,exynos7885-dw-mshc-smu + - samsung,exynos850-dw-mshc-smu + - const: samsung,exynos7-dw-mshc-smu reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml b/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml index 86fae733d9a0ab..c24c537f62b13f 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml @@ -22,6 +22,8 @@ properties: - items: - enum: - qcom,apq8084-sdhci + - qcom,ipq4019-sdhci + - qcom,ipq8074-sdhci - qcom,msm8226-sdhci - qcom,msm8953-sdhci - qcom,msm8974-sdhci diff --git a/Documentation/devicetree/bindings/mmc/sdhci-pxa.yaml b/Documentation/devicetree/bindings/mmc/sdhci-pxa.yaml index 09455f9fa8deb2..4869ddef36fd89 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-pxa.yaml +++ b/Documentation/devicetree/bindings/mmc/sdhci-pxa.yaml @@ -18,7 +18,7 @@ allOf: const: marvell,armada-380-sdhci then: properties: - regs: + reg: minItems: 3 reg-names: minItems: 3 @@ -26,7 +26,7 @@ allOf: - reg-names else: properties: - regs: + reg: maxItems: 1 reg-names: maxItems: 1 diff --git a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml index a43eb837f8dae0..42804d95529342 100644 --- a/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml +++ b/Documentation/devicetree/bindings/mmc/snps,dwcmshc-sdhci.yaml @@ -19,6 +19,7 @@ properties: - rockchip,rk3568-dwcmshc - rockchip,rk3588-dwcmshc - snps,dwcmshc-sdhci + - thead,th1520-dwcmshc reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.yaml b/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.yaml index b13b5166d20a86..a6292777e37643 100644 --- a/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.yaml +++ b/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.yaml @@ -35,6 +35,9 @@ properties: - const: biu - const: ciu + iommus: + maxItems: 1 + altr,sysmgr-syscon: $ref: /schemas/types.yaml#/definitions/phandle-array items: @@ -62,6 +65,7 @@ allOf: altr,sysmgr-syscon: true else: properties: + iommus: false altr,sysmgr-syscon: false required: diff --git a/Documentation/devicetree/bindings/mtd/partitions/u-boot.yaml b/Documentation/devicetree/bindings/mtd/partitions/u-boot.yaml index 3c56efe48efdd8..327fa872c00178 100644 --- a/Documentation/devicetree/bindings/mtd/partitions/u-boot.yaml +++ b/Documentation/devicetree/bindings/mtd/partitions/u-boot.yaml @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: U-Boot bootloader partition description: | - U-Boot is a bootlodaer commonly used in embedded devices. It's almost always + U-Boot is a bootloader commonly used in embedded devices. It's almost always located on some kind of flash device. Device configuration is stored as a set of environment variables that are diff --git a/Documentation/devicetree/bindings/net/dsa/dsa.yaml b/Documentation/devicetree/bindings/net/dsa/dsa.yaml index 6107189d276a2b..2abd036578d150 100644 --- a/Documentation/devicetree/bindings/net/dsa/dsa.yaml +++ b/Documentation/devicetree/bindings/net/dsa/dsa.yaml @@ -46,4 +46,10 @@ $defs: $ref: dsa-port.yaml# unevaluatedProperties: false +oneOf: + - required: + - ports + - required: + - ethernet-ports + ... diff --git a/Documentation/devicetree/bindings/net/dsa/marvell,mv88e6060.yaml b/Documentation/devicetree/bindings/net/dsa/marvell,mv88e6060.yaml new file mode 100644 index 00000000000000..4f1adf00431a87 --- /dev/null +++ b/Documentation/devicetree/bindings/net/dsa/marvell,mv88e6060.yaml @@ -0,0 +1,88 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/dsa/marvell,mv88e6060.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Marvell MV88E6060 DSA switch + +maintainers: + - Andrew Lunn + +description: + The Marvell MV88E6060 switch has been produced and sold by Marvell + since at least 2008. The switch has one pin ADDR4 that controls the + MDIO address of the switch to be 0x10 or 0x00, and on the MDIO bus + connected to the switch, the PHYs inside the switch appear as + independent devices on address 0x00-0x04 or 0x10-0x14, so in difference + from many other DSA switches this switch does not have an internal + MDIO bus for the PHY devices. + +properties: + compatible: + const: marvell,mv88e6060 + description: + The MV88E6060 is the oldest Marvell DSA switch product, and + as such a bit limited in features compared to later hardware. + + reg: + maxItems: 1 + + reset-gpios: + description: + GPIO to be used to reset the whole device + maxItems: 1 + +allOf: + - $ref: dsa.yaml#/$defs/ethernet-ports + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include + #include + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethernet-switch@16 { + compatible = "marvell,mv88e6060"; + reg = <16>; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + + ethernet-port@0 { + reg = <0>; + label = "lan1"; + }; + ethernet-port@1 { + reg = <1>; + label = "lan2"; + }; + ethernet-port@2 { + reg = <2>; + label = "lan3"; + }; + ethernet-port@3 { + reg = <3>; + label = "lan4"; + }; + ethernet-port@5 { + reg = <5>; + phy-mode = "rev-mii"; + ethernet = <ðc>; + fixed-link { + speed = <100>; + full-duplex; + }; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/net/dsa/marvell,mv88e6xxx.yaml b/Documentation/devicetree/bindings/net/dsa/marvell,mv88e6xxx.yaml new file mode 100644 index 00000000000000..19f15bdd1c9769 --- /dev/null +++ b/Documentation/devicetree/bindings/net/dsa/marvell,mv88e6xxx.yaml @@ -0,0 +1,337 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/dsa/marvell,mv88e6xxx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Marvell MV88E6xxx DSA switch family + +maintainers: + - Andrew Lunn + +description: + The Marvell MV88E6xxx switch series has been produced and sold + by Marvell since at least 2008. The switch has a few compatibles which + just indicate the base address of the switch, then operating systems + can investigate switch ID registers to find out which actual version + of the switch it is dealing with. + +properties: + compatible: + oneOf: + - enum: + - marvell,mv88e6085 + - marvell,mv88e6190 + - marvell,mv88e6250 + description: | + marvell,mv88e6085: This switch uses base address 0x10. + This switch and its siblings will be autodetected from + ID registers found in the switch, so only "marvell,mv88e6085" should be + specified. This includes the following list of MV88Exxxx switches: + 6085, 6095, 6097, 6123, 6131, 6141, 6161, 6165, 6171, 6172, 6175, 6176, + 6185, 6240, 6320, 6321, 6341, 6350, 6351, 6352 + marvell,mv88e6190: This switch uses base address 0x00. + This switch and its siblings will be autodetected from + ID registers found in the switch, so only "marvell,mv88e6190" should be + specified. This includes the following list of MV88Exxxx switches: + 6190, 6190X, 6191, 6290, 6361, 6390, 6390X + marvell,mv88e6250: This switch uses base address 0x08 or 0x18. + This switch and its siblings will be autodetected from + ID registers found in the switch, so only "marvell,mv88e6250" should be + specified. This includes the following list of MV88Exxxx switches: + 6220, 6250 + - items: + - const: marvell,turris-mox-mv88e6085 + - const: marvell,mv88e6085 + - items: + - const: marvell,turris-mox-mv88e6190 + - const: marvell,mv88e6190 + + reg: + maxItems: 1 + + eeprom-length: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Set to the length of an EEPROM connected to the switch. Must be + set if the switch can not detect the presence and/or size of a connected + EEPROM, otherwise optional. + + reset-gpios: + description: + GPIO to be used to reset the whole device + maxItems: 1 + + interrupts: + description: The switch provides an external interrupt line, but it is + not always used by target systems. + maxItems: 1 + + interrupt-controller: + description: The switch has an internal interrupt controller used by + the different sub-blocks. + + '#interrupt-cells': + description: The internal interrupt controller only supports triggering + on active high level interrupts so the second cell must alway be set to + IRQ_TYPE_LEVEL_HIGH. + const: 2 + + mdio: + $ref: /schemas/net/mdio.yaml# + unevaluatedProperties: false + description: Marvell MV88E6xxx switches have an varying combination of + internal and external MDIO buses, in some cases a combined bus that + can be used both internally and externally. This node is for the + primary bus, used internally and sometimes also externally. + + mdio-external: + $ref: /schemas/net/mdio.yaml# + unevaluatedProperties: false + description: Marvell MV88E6xxx switches that have a separate external + MDIO bus use this port to access external components on the MDIO bus. + + properties: + compatible: + const: marvell,mv88e6xxx-mdio-external + + required: + - compatible + +allOf: + - $ref: dsa.yaml#/$defs/ethernet-ports + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethernet-switch@0 { + compatible = "marvell,mv88e6085"; + reg = <0>; + reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + sw_phy0: ethernet-phy@0 { + reg = <0x0>; + }; + + sw_phy1: ethernet-phy@1 { + reg = <0x1>; + }; + + sw_phy2: ethernet-phy@2 { + reg = <0x2>; + }; + + sw_phy3: ethernet-phy@3 { + reg = <0x3>; + }; + }; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + + ethernet-port@0 { + reg = <0>; + label = "lan4"; + phy-handle = <&sw_phy0>; + phy-mode = "internal"; + }; + + ethernet-port@1 { + reg = <1>; + label = "lan3"; + phy-handle = <&sw_phy1>; + phy-mode = "internal"; + }; + + ethernet-port@2 { + reg = <2>; + label = "lan2"; + phy-handle = <&sw_phy2>; + phy-mode = "internal"; + }; + + ethernet-port@3 { + reg = <3>; + label = "lan1"; + phy-handle = <&sw_phy3>; + phy-mode = "internal"; + }; + + ethernet-port@5 { + reg = <5>; + ethernet = <&fec>; + phy-mode = "rgmii-id"; + + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + }; + }; + }; + - | + #include + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethernet-switch@0 { + compatible = "marvell,mv88e6190"; + #interrupt-cells = <2>; + interrupt-controller; + interrupt-parent = <&gpio1>; + interrupts = <7 IRQ_TYPE_LEVEL_LOW>; + pinctrl-0 = <&switch_interrupt_pins>; + pinctrl-names = "default"; + reg = <0>; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + switch0phy1: ethernet-phy@1 { + reg = <0x1>; + }; + + switch0phy2: ethernet-phy@2 { + reg = <0x2>; + }; + + switch0phy3: ethernet-phy@3 { + reg = <0x3>; + }; + + switch0phy4: ethernet-phy@4 { + reg = <0x4>; + }; + + switch0phy5: ethernet-phy@5 { + reg = <0x5>; + }; + + switch0phy6: ethernet-phy@6 { + reg = <0x6>; + }; + + switch0phy7: ethernet-phy@7 { + reg = <0x7>; + }; + + switch0phy8: ethernet-phy@8 { + reg = <0x8>; + }; + }; + + mdio-external { + compatible = "marvell,mv88e6xxx-mdio-external"; + #address-cells = <1>; + #size-cells = <0>; + + phy1: ethernet-phy@b { + reg = <0xb>; + compatible = "ethernet-phy-ieee802.3-c45"; + }; + + phy2: ethernet-phy@c { + reg = <0xc>; + compatible = "ethernet-phy-ieee802.3-c45"; + }; + }; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + + ethernet-port@0 { + ethernet = <ð0>; + phy-mode = "rgmii"; + reg = <0>; + + fixed-link { + full-duplex; + pause; + speed = <1000>; + }; + }; + + ethernet-port@1 { + label = "lan1"; + phy-handle = <&switch0phy1>; + reg = <1>; + }; + + ethernet-port@2 { + label = "lan2"; + phy-handle = <&switch0phy2>; + reg = <2>; + }; + + ethernet-port@3 { + label = "lan3"; + phy-handle = <&switch0phy3>; + reg = <3>; + }; + + ethernet-port@4 { + label = "lan4"; + phy-handle = <&switch0phy4>; + reg = <4>; + }; + + ethernet-port@5 { + label = "lan5"; + phy-handle = <&switch0phy5>; + reg = <5>; + }; + + ethernet-port@6 { + label = "lan6"; + phy-handle = <&switch0phy6>; + reg = <6>; + }; + + ethernet-port@7 { + label = "lan7"; + phy-handle = <&switch0phy7>; + reg = <7>; + }; + + ethernet-port@8 { + label = "lan8"; + phy-handle = <&switch0phy8>; + reg = <8>; + }; + + ethernet-port@9 { + /* 88X3310P external phy */ + label = "lan9"; + phy-handle = <&phy1>; + phy-mode = "xaui"; + reg = <9>; + }; + + ethernet-port@a { + /* 88X3310P external phy */ + label = "lan10"; + phy-handle = <&phy2>; + phy-mode = "xaui"; + reg = <0xa>; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/net/dsa/marvell.txt b/Documentation/devicetree/bindings/net/dsa/marvell.txt deleted file mode 100644 index 6ec0c181b6db21..00000000000000 --- a/Documentation/devicetree/bindings/net/dsa/marvell.txt +++ /dev/null @@ -1,109 +0,0 @@ -Marvell DSA Switch Device Tree Bindings ---------------------------------------- - -WARNING: This binding is currently unstable. Do not program it into a -FLASH never to be changed again. Once this binding is stable, this -warning will be removed. - -If you need a stable binding, use the old dsa.txt binding. - -Marvell Switches are MDIO devices. The following properties should be -placed as a child node of an mdio device. - -The properties described here are those specific to Marvell devices. -Additional required and optional properties can be found in dsa.txt. - -The compatibility string is used only to find an identification register, -which is at a different MDIO base address in different switch families. -- "marvell,mv88e6085" : Switch has base address 0x10. Use with models: - 6085, 6095, 6097, 6123, 6131, 6141, 6161, 6165, - 6171, 6172, 6175, 6176, 6185, 6240, 6320, 6321, - 6341, 6350, 6351, 6352 -- "marvell,mv88e6190" : Switch has base address 0x00. Use with models: - 6190, 6190X, 6191, 6290, 6361, 6390, 6390X -- "marvell,mv88e6250" : Switch has base address 0x08 or 0x18. Use with model: - 6220, 6250 - -Required properties: -- compatible : Should be one of "marvell,mv88e6085", - "marvell,mv88e6190" or "marvell,mv88e6250" as - indicated above -- reg : Address on the MII bus for the switch. - -Optional properties: - -- reset-gpios : Should be a gpio specifier for a reset line -- interrupts : Interrupt from the switch -- interrupt-controller : Indicates the switch is itself an interrupt - controller. This is used for the PHY interrupts. -#interrupt-cells = <2> : Controller uses two cells, number and flag -- eeprom-length : Set to the length of an EEPROM connected to the - switch. Must be set if the switch can not detect - the presence and/or size of a connected EEPROM, - otherwise optional. -- mdio : Container of PHY and devices on the switches MDIO - bus. -- mdio? : Container of PHYs and devices on the external MDIO - bus. The node must contains a compatible string of - "marvell,mv88e6xxx-mdio-external" - -Example: - - mdio { - #address-cells = <1>; - #size-cells = <0>; - interrupt-parent = <&gpio0>; - interrupts = <27 IRQ_TYPE_LEVEL_LOW>; - interrupt-controller; - #interrupt-cells = <2>; - - switch0: switch@0 { - compatible = "marvell,mv88e6085"; - reg = <0>; - reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>; - - mdio { - #address-cells = <1>; - #size-cells = <0>; - switch1phy0: switch1phy0@0 { - reg = <0>; - interrupt-parent = <&switch0>; - interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; - }; - }; - }; - }; - - mdio { - #address-cells = <1>; - #size-cells = <0>; - interrupt-parent = <&gpio0>; - interrupts = <27 IRQ_TYPE_LEVEL_LOW>; - interrupt-controller; - #interrupt-cells = <2>; - - switch0: switch@0 { - compatible = "marvell,mv88e6190"; - reg = <0>; - reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>; - - mdio { - #address-cells = <1>; - #size-cells = <0>; - switch1phy0: switch1phy0@0 { - reg = <0>; - interrupt-parent = <&switch0>; - interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; - }; - }; - - mdio1 { - compatible = "marvell,mv88e6xxx-mdio-external"; - #address-cells = <1>; - #size-cells = <0>; - switch1phy9: switch1phy0@9 { - reg = <9>; - }; - }; - }; - }; diff --git a/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml b/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml index b3029c64d0d5a3..c963dc09e8e12a 100644 --- a/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml +++ b/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml @@ -11,7 +11,6 @@ maintainers: - Woojung Huh allOf: - - $ref: dsa.yaml#/$defs/ethernet-ports - $ref: /schemas/spi/spi-peripheral-props.yaml# properties: @@ -78,6 +77,39 @@ required: - compatible - reg +if: + not: + properties: + compatible: + enum: + - microchip,ksz8863 + - microchip,ksz8873 +then: + $ref: dsa.yaml#/$defs/ethernet-ports +else: + patternProperties: + "^(ethernet-)?ports$": + patternProperties: + "^(ethernet-)?port@[0-2]$": + $ref: dsa-port.yaml# + unevaluatedProperties: false + properties: + microchip,rmii-clk-internal: + $ref: /schemas/types.yaml#/definitions/flag + description: + When ksz88x3 is acting as clock provier (via REFCLKO) it + can select between internal and external RMII reference + clock. Internal reference clock means that the clock for + the RMII of ksz88x3 is provided by the ksz88x3 internally + and the REFCLKI pin is unconnected. For the external + reference clock, the clock needs to be fed back to ksz88x3 + via REFCLKI. + If microchip,rmii-clk-internal is set, ksz88x3 will provide + rmii reference clock internally, otherwise reference clock + should be provided externally. + dependencies: + microchip,rmii-clk-internal: [ethernet] + unevaluatedProperties: false examples: diff --git a/Documentation/devicetree/bindings/net/ethernet-switch.yaml b/Documentation/devicetree/bindings/net/ethernet-switch.yaml index 72ac67ca341513..b3b7e1a1b12787 100644 --- a/Documentation/devicetree/bindings/net/ethernet-switch.yaml +++ b/Documentation/devicetree/bindings/net/ethernet-switch.yaml @@ -20,9 +20,26 @@ description: select: false -properties: - $nodename: - pattern: "^(ethernet-)?switch(@.*)?$" +allOf: + # This condition is here to satisfy the case where certain device + # nodes have to preserve non-standard names because of + # backward-compatibility with boot loaders inspecting certain + # node names. + - if: + properties: + compatible: + contains: + enum: + - marvell,turris-mox-mv88e6085 + - marvell,turris-mox-mv88e6190 + then: + properties: + $nodename: + pattern: "switch[0-3]@[0-3]+$" + else: + properties: + $nodename: + pattern: "^(ethernet-)?switch(@.*)?$" patternProperties: "^(ethernet-)?ports$": diff --git a/Documentation/devicetree/bindings/net/lantiq,pef2256.yaml b/Documentation/devicetree/bindings/net/lantiq,pef2256.yaml new file mode 100644 index 00000000000000..7da8370e246892 --- /dev/null +++ b/Documentation/devicetree/bindings/net/lantiq,pef2256.yaml @@ -0,0 +1,213 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/lantiq,pef2256.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Lantiq PEF2256 + +maintainers: + - Herve Codina + +description: + The Lantiq PEF2256, also known as Infineon PEF2256 or FALC56, is a framer and + line interface component designed to fulfill all required interfacing between + an analog E1/T1/J1 line and the digital PCM system highway/H.100 bus. + +properties: + compatible: + items: + - const: lantiq,pef2256 + + reg: + maxItems: 1 + + clocks: + items: + - description: Master Clock + - description: System Clock Receive + - description: System Clock Transmit + + clock-names: + items: + - const: mclk + - const: sclkr + - const: sclkx + + interrupts: + maxItems: 1 + + reset-gpios: + description: + GPIO used to reset the device. + maxItems: 1 + + pinctrl: + $ref: /schemas/pinctrl/pinctrl.yaml# + additionalProperties: false + + patternProperties: + '-pins$': + type: object + $ref: /schemas/pinctrl/pinmux-node.yaml# + additionalProperties: false + + properties: + pins: + enum: [ RPA, RPB, RPC, RPD, XPA, XPB, XPC, XPD ] + + function: + enum: [ SYPR, RFM, RFMB, RSIGM, RSIG, DLR, FREEZE, RFSP, LOS, + SYPX, XFMS, XSIG, TCLK, XMFB, XSIGM, DLX, XCLK, XLT, + GPI, GPOH, GPOL ] + + required: + - pins + - function + + lantiq,data-rate-bps: + enum: [2048000, 4096000, 8192000, 16384000] + default: 2048000 + description: + Data rate (bit per seconds) on the system highway. + + lantiq,clock-falling-edge: + $ref: /schemas/types.yaml#/definitions/flag + description: + Data is sent on falling edge of the clock (and received on the rising + edge). If 'clock-falling-edge' is not present, data is sent on the + rising edge (and received on the falling edge). + + lantiq,channel-phase: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1, 2, 3, 4, 5, 6, 7] + default: 0 + description: | + The pef2256 delivers a full frame (32 8-bit time-slots in E1 and 24 8-bit + time-slots 8 8-bit signaling in E1/J1) every 125us. This lead to a data + rate of 2048000 bit/s. When lantiq,data-rate-bps is more than 2048000 + bit/s, the data (all 32 8-bit) present in the frame are interleave with + unused time-slots. The lantiq,channel-phase property allows to set the + correct alignment of the interleave mechanism. + For instance, suppose lantiq,data-rate-bps = 8192000 (ie 4*2048000), and + lantiq,channel-phase = 2, the interleave schema with unused time-slots + (nu) and used time-slots (XX) for TSi is + nu nu XX nu nu nu XX nu nu nu XX nu + <-- TSi --> <- TSi+1 -> <- TSi+2 -> + With lantiq,data-rate-bps = 8192000, and lantiq,channel-phase = 1, the + interleave schema is + nu XX nu nu nu XX nu nu nu XX nu nu + <-- TSi --> <- TSi+1 -> <- TSi+2 -> + With lantiq,data-rate-bps = 4096000 (ie 2*2048000), and + lantiq,channel-phase = 1, the interleave schema is + nu XX nu XX nu XX + <-- TSi --> <- TSi+1 -> <- TSi+2 -> + +patternProperties: + '^codec(-([0-9]|[1-2][0-9]|3[0-1]))?$': + type: object + $ref: /schemas/sound/dai-common.yaml + unevaluatedProperties: false + description: + Codec provided by the pef2256. This codec allows to use some of the PCM + system highway time-slots as audio channels to transport audio data over + the E1/T1/J1 lines. + The time-slots used by the codec must be set and so, the properties + 'dai-tdm-slot-num', 'dai-tdm-slot-width', 'dai-tdm-slot-tx-mask' and + 'dai-tdm-slot-rx-mask' must be present in the sound card node for + sub-nodes that involve the codec. The codec uses 8-bit time-slots. + 'dai-tdm-tdm-slot-with' must be set to 8. + The tx and rx masks define the pef2256 time-slots assigned to the codec. + + properties: + compatible: + const: lantiq,pef2256-codec + + '#sound-dai-cells': + const: 0 + + required: + - compatible + - '#sound-dai-cells' + +required: + - compatible + - reg + - clocks + - clock-names + - interrupts + +additionalProperties: false + +examples: + - | + #include + #include + + pef2256: framer@2000000 { + compatible = "lantiq,pef2256"; + reg = <0x2000000 0x100>; + interrupts = <8 IRQ_TYPE_LEVEL_LOW>; + interrupt-parent = <&intc>; + clocks = <&clk_mclk>, <&clk_sclkr>, <&clk_sclkx>; + clock-names = "mclk", "sclkr", "sclkx"; + reset-gpios = <&gpio 11 GPIO_ACTIVE_LOW>; + lantiq,data-rate-bps = <4096000>; + + pinctrl { + pef2256_rpa_sypr: rpa-pins { + pins = "RPA"; + function = "SYPR"; + }; + pef2256_xpa_sypx: xpa-pins { + pins = "XPA"; + function = "SYPX"; + }; + }; + + pef2256_codec0: codec-0 { + compatible = "lantiq,pef2256-codec"; + #sound-dai-cells = <0>; + sound-name-prefix = "PEF2256_0"; + }; + + pef2256_codec1: codec-1 { + compatible = "lantiq,pef2256-codec"; + #sound-dai-cells = <0>; + sound-name-prefix = "PEF2256_1"; + }; + }; + + sound { + compatible = "simple-audio-card"; + #address-cells = <1>; + #size-cells = <0>; + simple-audio-card,dai-link@0 { /* CPU DAI1 - pef2256 codec 1 */ + reg = <0>; + cpu { + sound-dai = <&cpu_dai1>; + }; + codec { + sound-dai = <&pef2256_codec0>; + dai-tdm-slot-num = <4>; + dai-tdm-slot-width = <8>; + /* TS 1, 2, 3, 4 */ + dai-tdm-slot-tx-mask = <0 1 1 1 1>; + dai-tdm-slot-rx-mask = <0 1 1 1 1>; + }; + }; + simple-audio-card,dai-link@1 { /* CPU DAI2 - pef2256 codec 2 */ + reg = <1>; + cpu { + sound-dai = <&cpu_dai2>; + }; + codec { + sound-dai = <&pef2256_codec1>; + dai-tdm-slot-num = <4>; + dai-tdm-slot-width = <8>; + /* TS 5, 6, 7, 8 */ + dai-tdm-slot-tx-mask = <0 0 0 0 0 1 1 1 1>; + dai-tdm-slot-rx-mask = <0 0 0 0 0 1 1 1 1>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/net/marvell,aquantia.yaml b/Documentation/devicetree/bindings/net/marvell,aquantia.yaml new file mode 100644 index 00000000000000..9854fab4c4db08 --- /dev/null +++ b/Documentation/devicetree/bindings/net/marvell,aquantia.yaml @@ -0,0 +1,116 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/marvell,aquantia.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Marvell Aquantia Ethernet PHY + +maintainers: + - Christian Marangi + +description: | + Marvell Aquantia Ethernet PHY require a firmware to be loaded to actually + work. + + This can be done and is implemented by OEM in 3 different way: + - Attached SPI flash directly to the PHY with the firmware. The PHY + will self load the firmware in the presence of this configuration. + - Read from a dedicated partition on system NAND declared in an + NVMEM cell, and loaded to the PHY using its mailbox interface. + - Manually provided firmware loaded from a file in the filesystem. + +allOf: + - $ref: ethernet-phy.yaml# + +select: + properties: + compatible: + contains: + enum: + - ethernet-phy-id03a1.b445 + - ethernet-phy-id03a1.b460 + - ethernet-phy-id03a1.b4a2 + - ethernet-phy-id03a1.b4d0 + - ethernet-phy-id03a1.b4e0 + - ethernet-phy-id03a1.b5c2 + - ethernet-phy-id03a1.b4b0 + - ethernet-phy-id03a1.b662 + - ethernet-phy-id03a1.b712 + - ethernet-phy-id31c3.1c12 + required: + - compatible + +properties: + reg: + maxItems: 1 + + firmware-name: + description: specify the name of PHY firmware to load + + nvmem-cells: + description: phandle to the firmware nvmem cell + maxItems: 1 + + nvmem-cell-names: + const: firmware + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethernet-phy@0 { + compatible = "ethernet-phy-id31c3.1c12", + "ethernet-phy-ieee802.3-c45"; + + reg = <0>; + firmware-name = "AQR-G4_v5.4.C-AQR_CIG_WF-1945_0x8_ID44776_VER1630.cld"; + }; + + ethernet-phy@1 { + compatible = "ethernet-phy-id31c3.1c12", + "ethernet-phy-ieee802.3-c45"; + + reg = <1>; + nvmem-cells = <&aqr_fw>; + nvmem-cell-names = "firmware"; + }; + }; + + flash { + compatible = "jedec,spi-nor"; + #address-cells = <1>; + #size-cells = <1>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* ... */ + + partition@650000 { + compatible = "nvmem-cells"; + label = "0:ethphyfw"; + reg = <0x650000 0x80000>; + read-only; + #address-cells = <1>; + #size-cells = <1>; + + aqr_fw: aqr_fw@0 { + reg = <0x0 0x5f42a>; + }; + }; + + /* ... */ + + }; + }; diff --git a/Documentation/devicetree/bindings/net/marvell,mvusb.yaml b/Documentation/devicetree/bindings/net/marvell,mvusb.yaml index 3a332516804808..ab838c1ffeed09 100644 --- a/Documentation/devicetree/bindings/net/marvell,mvusb.yaml +++ b/Documentation/devicetree/bindings/net/marvell,mvusb.yaml @@ -50,11 +50,14 @@ examples: #address-cells = <1>; #size-cells = <0>; - switch@0 { + ethernet-switch@0 { compatible = "marvell,mv88e6190"; reg = <0x0>; - ports { + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + /* Port definitions */ }; diff --git a/Documentation/devicetree/bindings/net/marvell,orion-mdio.yaml b/Documentation/devicetree/bindings/net/marvell,orion-mdio.yaml index e35da8b01dc257..73429855d5848f 100644 --- a/Documentation/devicetree/bindings/net/marvell,orion-mdio.yaml +++ b/Documentation/devicetree/bindings/net/marvell,orion-mdio.yaml @@ -39,28 +39,6 @@ required: allOf: - $ref: mdio.yaml# - - if: - required: - - interrupts - - then: - properties: - reg: - items: - - items: - - $ref: /schemas/types.yaml#/definitions/cell - - const: 0x84 - - else: - properties: - reg: - items: - - items: - - $ref: /schemas/types.yaml#/definitions/cell - - enum: - - 0x4 - - 0x10 - unevaluatedProperties: false examples: diff --git a/Documentation/devicetree/bindings/net/pcs/mediatek,sgmiisys.yaml b/Documentation/devicetree/bindings/net/pcs/mediatek,sgmiisys.yaml index 66a95191bd7766..1bacc0eeff7573 100644 --- a/Documentation/devicetree/bindings/net/pcs/mediatek,sgmiisys.yaml +++ b/Documentation/devicetree/bindings/net/pcs/mediatek,sgmiisys.yaml @@ -15,15 +15,22 @@ description: properties: compatible: - items: - - enum: - - mediatek,mt7622-sgmiisys - - mediatek,mt7629-sgmiisys - - mediatek,mt7981-sgmiisys_0 - - mediatek,mt7981-sgmiisys_1 - - mediatek,mt7986-sgmiisys_0 - - mediatek,mt7986-sgmiisys_1 - - const: syscon + oneOf: + - items: + - enum: + - mediatek,mt7622-sgmiisys + - mediatek,mt7629-sgmiisys + - mediatek,mt7981-sgmiisys_0 + - mediatek,mt7981-sgmiisys_1 + - mediatek,mt7986-sgmiisys_0 + - mediatek,mt7986-sgmiisys_1 + - const: syscon + - items: + - enum: + - mediatek,mt7988-sgmiisys0 + - mediatek,mt7988-sgmiisys1 + - const: simple-mfd + - const: syscon reg: maxItems: 1 @@ -35,11 +42,51 @@ properties: description: Invert polarity of the SGMII data lanes type: boolean + pcs: + type: object + description: MediaTek LynxI HSGMII PCS + properties: + compatible: + const: mediatek,mt7988-sgmii + + clocks: + maxItems: 3 + + clock-names: + items: + - const: sgmii_sel + - const: sgmii_tx + - const: sgmii_rx + + required: + - compatible + - clocks + - clock-names + + additionalProperties: false + required: - compatible - reg - '#clock-cells' +allOf: + - if: + properties: + compatible: + contains: + enum: + - mediatek,mt7988-sgmiisys0 + - mediatek,mt7988-sgmiisys1 + + then: + required: + - pcs + + else: + properties: + pcs: false + additionalProperties: false examples: diff --git a/Documentation/devicetree/bindings/net/qcom,ipa.yaml b/Documentation/devicetree/bindings/net/qcom,ipa.yaml index 2d5e4ffb2f9ef8..c30218684cfe46 100644 --- a/Documentation/devicetree/bindings/net/qcom,ipa.yaml +++ b/Documentation/devicetree/bindings/net/qcom,ipa.yaml @@ -43,15 +43,21 @@ description: properties: compatible: - enum: - - qcom,msm8998-ipa - - qcom,sc7180-ipa - - qcom,sc7280-ipa - - qcom,sdm845-ipa - - qcom,sdx55-ipa - - qcom,sdx65-ipa - - qcom,sm6350-ipa - - qcom,sm8350-ipa + oneOf: + - enum: + - qcom,msm8998-ipa + - qcom,sc7180-ipa + - qcom,sc7280-ipa + - qcom,sdm845-ipa + - qcom,sdx55-ipa + - qcom,sdx65-ipa + - qcom,sm6350-ipa + - qcom,sm8350-ipa + - qcom,sm8550-ipa + - items: + - enum: + - qcom,sm8650-ipa + - const: qcom,sm8550-ipa reg: items: diff --git a/Documentation/devicetree/bindings/net/renesas,etheravb.yaml b/Documentation/devicetree/bindings/net/renesas,etheravb.yaml index 5d074f27d46203..890f7858d0dc4c 100644 --- a/Documentation/devicetree/bindings/net/renesas,etheravb.yaml +++ b/Documentation/devicetree/bindings/net/renesas,etheravb.yaml @@ -55,9 +55,10 @@ properties: - items: - enum: - - renesas,r9a07g043-gbeth # RZ/G2UL + - renesas,r9a07g043-gbeth # RZ/G2UL and RZ/Five - renesas,r9a07g044-gbeth # RZ/G2{L,LC} - renesas,r9a07g054-gbeth # RZ/V2L + - renesas,r9a08g045-gbeth # RZ/G3S - const: renesas,rzg2l-gbeth # RZ/{G2L,G2UL,V2L} family reg: true diff --git a/Documentation/devicetree/bindings/net/renesas,ethertsn.yaml b/Documentation/devicetree/bindings/net/renesas,ethertsn.yaml new file mode 100644 index 00000000000000..475aff7714d641 --- /dev/null +++ b/Documentation/devicetree/bindings/net/renesas,ethertsn.yaml @@ -0,0 +1,133 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/renesas,ethertsn.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Renesas Ethernet TSN End-station + +maintainers: + - Niklas Söderlund + +description: + The RTSN device provides Ethernet network using a 10 Mbps, 100 Mbps, or 1 + Gbps full-duplex link via MII/GMII/RMII/RGMII. Depending on the connected PHY. + +allOf: + - $ref: ethernet-controller.yaml# + +properties: + compatible: + items: + - enum: + - renesas,r8a779g0-ethertsn # R-Car V4H + - const: renesas,rcar-gen4-ethertsn + + reg: + items: + - description: TSN End Station target + - description: generalized Precision Time Protocol target + + reg-names: + items: + - const: tsnes + - const: gptp + + interrupts: + items: + - description: TX data interrupt + - description: RX data interrupt + + interrupt-names: + items: + - const: tx + - const: rx + + clocks: + maxItems: 1 + + power-domains: + maxItems: 1 + + resets: + maxItems: 1 + + phy-mode: + contains: + enum: + - mii + - rgmii + + phy-handle: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Specifies a reference to a node representing a PHY device. + + rx-internal-delay-ps: + enum: [0, 1800] + + tx-internal-delay-ps: + enum: [0, 2000] + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + +patternProperties: + "^ethernet-phy@[0-9a-f]$": + type: object + $ref: ethernet-phy.yaml# + unevaluatedProperties: false + +required: + - compatible + - reg + - reg-names + - interrupts + - interrupt-names + - clocks + - power-domains + - resets + - phy-mode + - phy-handle + - '#address-cells' + - '#size-cells' + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + + tsn0: ethernet@e6460000 { + compatible = "renesas,r8a779g0-ethertsn", "renesas,rcar-gen4-ethertsn"; + reg = <0xe6460000 0x7000>, + <0xe6449000 0x500>; + reg-names = "tsnes", "gptp"; + interrupts = , + ; + interrupt-names = "tx", "rx"; + clocks = <&cpg CPG_MOD 2723>; + power-domains = <&sysc R8A779G0_PD_ALWAYS_ON>; + resets = <&cpg 2723>; + + phy-mode = "rgmii"; + tx-internal-delay-ps = <2000>; + phy-handle = <&phy3>; + + #address-cells = <1>; + #size-cells = <0>; + + phy3: ethernet-phy@3 { + compatible = "ethernet-phy-ieee802.3-c45"; + reg = <0>; + interrupt-parent = <&gpio4>; + interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + reset-gpios = <&gpio1 23 GPIO_ACTIVE_LOW>; + }; + }; diff --git a/Documentation/devicetree/bindings/net/sff,sfp.yaml b/Documentation/devicetree/bindings/net/sff,sfp.yaml index 973e478a399d37..bf6cbc7c2ba3b5 100644 --- a/Documentation/devicetree/bindings/net/sff,sfp.yaml +++ b/Documentation/devicetree/bindings/net/sff,sfp.yaml @@ -120,7 +120,7 @@ examples: pinctrl-names = "default"; pinctrl-0 = <&cps_sfpp0_pins>; tx-disable-gpios = <&cps_gpio1 29 GPIO_ACTIVE_HIGH>; - tx-fault-gpios = <&cps_gpio1 26 GPIO_ACTIVE_HIGH>; + tx-fault-gpios = <&cps_gpio1 26 GPIO_ACTIVE_HIGH>; }; mdio { diff --git a/Documentation/devicetree/bindings/net/xlnx,axi-ethernet.yaml b/Documentation/devicetree/bindings/net/xlnx,axi-ethernet.yaml index 1d33d80af11c3c..bbe89ea9590ceb 100644 --- a/Documentation/devicetree/bindings/net/xlnx,axi-ethernet.yaml +++ b/Documentation/devicetree/bindings/net/xlnx,axi-ethernet.yaml @@ -122,6 +122,20 @@ properties: and "phy-handle" should point to an external PHY if exists. maxItems: 1 + dmas: + minItems: 2 + maxItems: 32 + description: TX and RX DMA channel phandle + + dma-names: + items: + pattern: "^[tr]x_chan([0-9]|1[0-5])$" + description: + Should be "tx_chan0", "tx_chan1" ... "tx_chan15" for DMA Tx channel + Should be "rx_chan0", "rx_chan1" ... "rx_chan15" for DMA Rx channel + minItems: 2 + maxItems: 32 + required: - compatible - interrupts @@ -143,6 +157,8 @@ examples: clocks = <&axi_clk>, <&axi_clk>, <&pl_enet_ref_clk>, <&mgt_clk>; phy-mode = "mii"; reg = <0x40c00000 0x40000>,<0x50c00000 0x40000>; + dmas = <&xilinx_dma 0>, <&xilinx_dma 1>; + dma-names = "tx_chan0", "rx_chan0"; xlnx,rxcsum = <0x2>; xlnx,rxmem = <0x800>; xlnx,txcsum = <0x2>; diff --git a/Documentation/devicetree/bindings/nvmem/st,stm32-romem.yaml b/Documentation/devicetree/bindings/nvmem/st,stm32-romem.yaml index a69de3e9228283..92bfe25f0571eb 100644 --- a/Documentation/devicetree/bindings/nvmem/st,stm32-romem.yaml +++ b/Documentation/devicetree/bindings/nvmem/st,stm32-romem.yaml @@ -24,6 +24,7 @@ properties: - st,stm32f4-otp - st,stm32mp13-bsec - st,stm32mp15-bsec + - st,stm32mp25-bsec reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml b/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml index 7e15aae7d69e97..22491f7f88521c 100644 --- a/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml +++ b/Documentation/devicetree/bindings/pci/brcm,stb-pcie.yaml @@ -64,6 +64,24 @@ properties: aspm-no-l0s: true + brcm,clkreq-mode: + description: A string that determines the operating + clkreq mode of the PCIe RC HW with respect to controlling the refclk + signal. There are three different modes -- "safe", which drives the + refclk signal unconditionally and will work for all devices but does + not provide any power savings; "no-l1ss" -- which provides Clock + Power Management, L0s, and L1, but cannot provide L1 substate (L1SS) + power savings. If the downstream device connected to the RC is L1SS + capable AND the OS enables L1SS, all PCIe traffic may abruptly halt, + potentially hanging the system; "default" -- which provides L0s, L1, + and L1SS, but not compliant to provide Clock Power Management; + specifically, may not be able to meet the T_CLRon max timing of 400ns + as specified in "Dynamic Clock Control", section 3.2.5.2.2 PCI + Express Mini CEM 2.1 specification. This situation is atypical and + should happen only with older devices. + $ref: /schemas/types.yaml#/definitions/string + enum: [ safe, no-l1ss, default ] + brcm,scb-sizes: description: u64 giving the 64bit PCIe memory viewport size of a memory controller. There may be up to diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie.yaml index eadba38171e135..a93ab3b5406664 100644 --- a/Documentation/devicetree/bindings/pci/qcom,pcie.yaml +++ b/Documentation/devicetree/bindings/pci/qcom,pcie.yaml @@ -41,6 +41,10 @@ properties: - qcom,pcie-sm8450-pcie0 - qcom,pcie-sm8450-pcie1 - qcom,pcie-sm8550 + - items: + - enum: + - qcom,pcie-sm8650 + - const: qcom,pcie-sm8550 - items: - const: qcom,pcie-msm8998 - const: qcom,pcie-msm8996 @@ -62,7 +66,8 @@ properties: maxItems: 8 iommu-map: - maxItems: 2 + minItems: 1 + maxItems: 16 # Common definitions for clocks, clock-names and reset. # Platform constraints are described later. @@ -88,7 +93,7 @@ properties: minItems: 1 maxItems: 12 - resets-names: + reset-names: minItems: 1 maxItems: 12 @@ -478,6 +483,33 @@ allOf: items: - const: pci # PCIe core reset + - if: + properties: + compatible: + contains: + enum: + - qcom,pcie-sc8180x + then: + properties: + clocks: + minItems: 8 + maxItems: 8 + clock-names: + items: + - const: pipe # PIPE clock + - const: aux # Auxiliary clock + - const: cfg # Configuration clock + - const: bus_master # Master AXI clock + - const: bus_slave # Slave AXI clock + - const: slave_q2a # Slave Q2A clock + - const: ref # REFERENCE clock + - const: tbu # PCIe TBU clock + resets: + maxItems: 1 + reset-names: + items: + - const: pci # PCIe core reset + - if: properties: compatible: @@ -526,8 +558,33 @@ allOf: compatible: contains: enum: - - qcom,pcie-sc8180x - qcom,pcie-sm8150 + then: + properties: + clocks: + minItems: 8 + maxItems: 8 + clock-names: + items: + - const: pipe # PIPE clock + - const: aux # Auxiliary clock + - const: cfg # Configuration clock + - const: bus_master # Master AXI clock + - const: bus_slave # Slave AXI clock + - const: slave_q2a # Slave Q2A clock + - const: tbu # PCIe TBU clock + - const: ref # REFERENCE clock + resets: + maxItems: 1 + reset-names: + items: + - const: pci # PCIe core reset + + - if: + properties: + compatible: + contains: + enum: - qcom,pcie-sm8250 then: oneOf: diff --git a/Documentation/devicetree/bindings/pci/rcar-pci-host.yaml b/Documentation/devicetree/bindings/pci/rcar-pci-host.yaml index 8fdfbc763d7045..b6a7cb32f61e5d 100644 --- a/Documentation/devicetree/bindings/pci/rcar-pci-host.yaml +++ b/Documentation/devicetree/bindings/pci/rcar-pci-host.yaml @@ -68,6 +68,15 @@ properties: phy-names: const: pcie + vpcie1v5-supply: + description: The 1.5v regulator to use for PCIe. + + vpcie3v3-supply: + description: The 3.3v regulator to use for PCIe. + + vpcie12v-supply: + description: The 12v regulator to use for PCIe. + required: - compatible - reg @@ -121,5 +130,7 @@ examples: clock-names = "pcie", "pcie_bus"; power-domains = <&sysc R8A7791_PD_ALWAYS_ON>; resets = <&cpg 319>; + vpcie3v3-supply = <&pcie_3v3>; + vpcie12v-supply = <&pcie_12v>; }; }; diff --git a/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml b/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml index 1ae8dcfa072cea..5f719218c472c8 100644 --- a/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml +++ b/Documentation/devicetree/bindings/pci/rockchip-dw-pcie.yaml @@ -49,6 +49,7 @@ properties: - description: APB clock for PCIe - description: Auxiliary clock for PCIe - description: PIPE clock + - description: Reference clock for PCIe clock-names: minItems: 5 @@ -59,6 +60,7 @@ properties: - const: pclk - const: aux - const: pipe + - const: ref interrupts: items: diff --git a/Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml b/Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml index 62292185fe2e46..97f2579ea90822 100644 --- a/Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml +++ b/Documentation/devicetree/bindings/pci/ti,j721e-pci-ep.yaml @@ -10,13 +10,11 @@ title: TI J721E PCI EP (PCIe Wrapper) maintainers: - Kishon Vijay Abraham I -allOf: - - $ref: cdns-pcie-ep.yaml# - properties: compatible: oneOf: - const: ti,j721e-pcie-ep + - const: ti,j784s4-pcie-ep - description: PCIe EP controller in AM64 items: - const: ti,am64-pcie-ep @@ -65,6 +63,41 @@ properties: items: - const: link_state +allOf: + - $ref: cdns-pcie-ep.yaml# + - if: + properties: + compatible: + enum: + - ti,am64-pcie-ep + then: + properties: + num-lanes: + const: 1 + + - if: + properties: + compatible: + enum: + - ti,j7200-pcie-ep + - ti,j721e-pcie-ep + then: + properties: + num-lanes: + minimum: 1 + maximum: 2 + + - if: + properties: + compatible: + enum: + - ti,j784s4-pcie-ep + then: + properties: + num-lanes: + minimum: 1 + maximum: 4 + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml b/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml index a2c5eaea57f503..b7a534cef24d31 100644 --- a/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml +++ b/Documentation/devicetree/bindings/pci/ti,j721e-pci-host.yaml @@ -10,13 +10,11 @@ title: TI J721E PCI Host (PCIe Wrapper) maintainers: - Kishon Vijay Abraham I -allOf: - - $ref: cdns-pcie-host.yaml# - properties: compatible: oneOf: - const: ti,j721e-pcie-host + - const: ti,j784s4-pcie-host - description: PCIe controller in AM64 items: - const: ti,am64-pcie-host @@ -94,6 +92,41 @@ properties: interrupts: maxItems: 1 +allOf: + - $ref: cdns-pcie-host.yaml# + - if: + properties: + compatible: + enum: + - ti,am64-pcie-host + then: + properties: + num-lanes: + const: 1 + + - if: + properties: + compatible: + enum: + - ti,j7200-pcie-host + - ti,j721e-pcie-host + then: + properties: + num-lanes: + minimum: 1 + maximum: 2 + + - if: + properties: + compatible: + enum: + - ti,j784s4-pcie-host + then: + properties: + num-lanes: + minimum: 1 + maximum: 4 + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/pci/toshiba,visconti-pcie.yaml b/Documentation/devicetree/bindings/pci/toshiba,visconti-pcie.yaml index 53da2edd7c9abe..120e3bb1e5454a 100644 --- a/Documentation/devicetree/bindings/pci/toshiba,visconti-pcie.yaml +++ b/Documentation/devicetree/bindings/pci/toshiba,visconti-pcie.yaml @@ -83,7 +83,7 @@ examples: <0x0 0x28050000 0x0 0x00010000>, <0x0 0x24200000 0x0 0x00002000>, <0x0 0x24162000 0x0 0x00001000>; - reg-names = "dbi", "config", "ulreg", "smu", "mpu"; + reg-names = "dbi", "config", "ulreg", "smu", "mpu"; device_type = "pci"; bus-range = <0x00 0xff>; num-lanes = <2>; diff --git a/Documentation/devicetree/bindings/perf/fsl-imx-ddr.yaml b/Documentation/devicetree/bindings/perf/fsl-imx-ddr.yaml index e9fad4b3de6840..6c96a4204e5d68 100644 --- a/Documentation/devicetree/bindings/perf/fsl-imx-ddr.yaml +++ b/Documentation/devicetree/bindings/perf/fsl-imx-ddr.yaml @@ -27,6 +27,9 @@ properties: - fsl,imx8mq-ddr-pmu - fsl,imx8mp-ddr-pmu - const: fsl,imx8m-ddr-pmu + - items: + - const: fsl,imx8dxl-ddr-pmu + - const: fsl,imx8-ddr-pmu reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/phy/amlogic,g12a-mipi-dphy-analog.yaml b/Documentation/devicetree/bindings/phy/amlogic,g12a-mipi-dphy-analog.yaml index c8c83acfb871d0..81c2654b7e57e9 100644 --- a/Documentation/devicetree/bindings/phy/amlogic,g12a-mipi-dphy-analog.yaml +++ b/Documentation/devicetree/bindings/phy/amlogic,g12a-mipi-dphy-analog.yaml @@ -16,20 +16,8 @@ properties: "#phy-cells": const: 0 - reg: - maxItems: 1 - required: - compatible - - reg - "#phy-cells" additionalProperties: false - -examples: - - | - phy@0 { - compatible = "amlogic,g12a-mipi-dphy-analog"; - reg = <0x0 0xc>; - #phy-cells = <0>; - }; diff --git a/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml b/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml index 009a3980831856..70def36e5688d0 100644 --- a/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml +++ b/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml @@ -9,16 +9,6 @@ title: Amlogic AXG shared MIPI/PCIE analog PHY maintainers: - Remi Pommarel -description: |+ - The Everything-Else Power Domains node should be the child of a syscon - node with the required property: - - - compatible: Should be the following: - "amlogic,meson-gx-hhi-sysctrl", "simple-mfd", "syscon" - - Refer to the bindings described in - Documentation/devicetree/bindings/mfd/syscon.yaml - properties: compatible: const: amlogic,axg-mipi-pcie-analog-phy @@ -31,10 +21,3 @@ required: - "#phy-cells" additionalProperties: false - -examples: - - | - mpphy: phy { - compatible = "amlogic,axg-mipi-pcie-analog-phy"; - #phy-cells = <0>; - }; diff --git a/Documentation/devicetree/bindings/phy/mediatek,dsi-phy.yaml b/Documentation/devicetree/bindings/phy/mediatek,dsi-phy.yaml index 6703689fcdbe10..f6e494d0d89b82 100644 --- a/Documentation/devicetree/bindings/phy/mediatek,dsi-phy.yaml +++ b/Documentation/devicetree/bindings/phy/mediatek,dsi-phy.yaml @@ -31,6 +31,7 @@ properties: - items: - enum: - mediatek,mt8188-mipi-tx + - mediatek,mt8195-mipi-tx - mediatek,mt8365-mipi-tx - const: mediatek,mt8183-mipi-tx - const: mediatek,mt2701-mipi-tx diff --git a/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml b/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml index 2bb91542e984e7..acba0720125ddd 100644 --- a/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml +++ b/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml @@ -235,6 +235,15 @@ patternProperties: Specify the flag to enable BC1.2 if support it type: boolean + mediatek,force-mode: + description: + The force mode is used to manually switch the shared phy mode between + USB3 and PCIe, when USB3 phy type is selected by the consumer, and + force-mode is set, will cause phy's power and pipe toggled and force + phy as USB3 mode which switched from default PCIe mode. But perfer to + use the property "mediatek,syscon-type" for newer SoCs that support it. + type: boolean + mediatek,syscon-type: $ref: /schemas/types.yaml#/definitions/phandle-array maxItems: 1 diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml index 2c3d6553a7bac6..6c03f2d5fca3cc 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml @@ -36,6 +36,8 @@ properties: - qcom,sm8450-qmp-gen4x2-pcie-phy - qcom,sm8550-qmp-gen3x2-pcie-phy - qcom,sm8550-qmp-gen4x2-pcie-phy + - qcom,sm8650-qmp-gen3x2-pcie-phy + - qcom,sm8650-qmp-gen4x2-pcie-phy reg: minItems: 1 @@ -147,6 +149,8 @@ allOf: - qcom,sm8450-qmp-gen3x2-pcie-phy - qcom,sm8550-qmp-gen3x2-pcie-phy - qcom,sm8550-qmp-gen4x2-pcie-phy + - qcom,sm8650-qmp-gen3x2-pcie-phy + - qcom,sm8650-qmp-gen4x2-pcie-phy then: properties: clocks: @@ -189,6 +193,7 @@ allOf: contains: enum: - qcom,sm8550-qmp-gen4x2-pcie-phy + - qcom,sm8650-qmp-gen4x2-pcie-phy then: properties: resets: diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml index f3a3296c811cb3..8474eef8d0ff52 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-ufs-phy.yaml @@ -32,6 +32,7 @@ properties: - qcom,sm8350-qmp-ufs-phy - qcom,sm8450-qmp-ufs-phy - qcom,sm8550-qmp-ufs-phy + - qcom,sm8650-qmp-ufs-phy reg: maxItems: 1 @@ -112,6 +113,7 @@ allOf: - qcom,sm8250-qmp-ufs-phy - qcom,sm8350-qmp-ufs-phy - qcom,sm8550-qmp-ufs-phy + - qcom,sm8650-qmp-ufs-phy then: properties: clocks: diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb3-uni-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb3-uni-phy.yaml index 57702f7f2a46cf..15d82c67f157b6 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb3-uni-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb3-uni-phy.yaml @@ -32,6 +32,7 @@ properties: - qcom,sm8150-qmp-usb3-uni-phy - qcom,sm8250-qmp-usb3-uni-phy - qcom,sm8350-qmp-usb3-uni-phy + - qcom,x1e80100-qmp-usb3-uni-phy reg: @@ -135,6 +136,7 @@ allOf: - qcom,sm8150-qmp-usb3-uni-phy - qcom,sm8250-qmp-usb3-uni-phy - qcom,sm8350-qmp-usb3-uni-phy + - qcom,x1e80100-qmp-usb3-uni-phy then: properties: clocks: @@ -171,6 +173,7 @@ allOf: enum: - qcom,sa8775p-qmp-usb3-uni-phy - qcom,sc8280xp-qmp-usb3-uni-phy + - qcom,x1e80100-qmp-usb3-uni-phy then: required: - power-domains diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml index 9af203dc8793f3..2d0d7e9e643117 100644 --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-usb43dp-phy.yaml @@ -27,6 +27,8 @@ properties: - qcom,sm8350-qmp-usb3-dp-phy - qcom,sm8450-qmp-usb3-dp-phy - qcom,sm8550-qmp-usb3-dp-phy + - qcom,sm8650-qmp-usb3-dp-phy + - qcom,x1e80100-qmp-usb3-dp-phy reg: maxItems: 1 @@ -62,12 +64,12 @@ properties: "#clock-cells": const: 1 description: - See include/dt-bindings/dt-bindings/phy/phy-qcom-qmp.h + See include/dt-bindings/phy/phy-qcom-qmp.h "#phy-cells": const: 1 description: - See include/dt-bindings/dt-bindings/phy/phy-qcom-qmp.h + See include/dt-bindings/phy/phy-qcom-qmp.h orientation-switch: description: @@ -128,6 +130,8 @@ allOf: - qcom,sc8280xp-qmp-usb43dp-phy - qcom,sm6350-qmp-usb3-dp-phy - qcom,sm8550-qmp-usb3-dp-phy + - qcom,sm8650-qmp-usb3-dp-phy + - qcom,x1e80100-qmp-usb3-dp-phy then: required: - power-domains diff --git a/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-phy.yaml index c95828607ab6bc..b82f7f5731ed4a 100644 --- a/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,snps-eusb2-phy.yaml @@ -18,6 +18,8 @@ properties: - items: - enum: - qcom,sdx75-snps-eusb2-phy + - qcom,sm8650-snps-eusb2-phy + - qcom,x1e80100-snps-eusb2-phy - const: qcom,sm8550-snps-eusb2-phy - const: qcom,sm8550-snps-eusb2-phy diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.yaml b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.yaml index 45a307d3ce1672..c11495524dd267 100644 --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.yaml +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.yaml @@ -31,6 +31,7 @@ properties: - ti,omap3-padconf - ti,omap4-padconf - ti,omap5-padconf + - ti,j7200-padconf - const: pinctrl-single reg: diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,ipq5018-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,ipq5018-tlmm.yaml index fad0118fd5219c..23300606547c55 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,ipq5018-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,ipq5018-tlmm.yaml @@ -23,13 +23,6 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true - "#gpio-cells": true - gpio-ranges: true - wakeup-parent: true - gpio-reserved-ranges: minItems: 1 maxItems: 24 @@ -95,7 +88,10 @@ required: - compatible - reg -additionalProperties: false +allOf: + - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml# + +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,ipq5332-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,ipq5332-tlmm.yaml index 3d3086ae1ba694..e571cd64418f27 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,ipq5332-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,ipq5332-tlmm.yaml @@ -26,13 +26,6 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true - "#gpio-cells": true - gpio-ranges: true - wakeup-parent: true - gpio-reserved-ranges: minItems: 1 maxItems: 27 @@ -100,7 +93,7 @@ required: - compatible - reg -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,ipq6018-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,ipq6018-pinctrl.yaml index 7c3e5e043f078d..ed00fbaec11b05 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,ipq6018-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,ipq6018-pinctrl.yaml @@ -22,12 +22,6 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true - "#gpio-cells": true - gpio-ranges: true - patternProperties: "-state$": oneOf: @@ -100,7 +94,7 @@ required: - compatible - reg -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,ipq8074-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,ipq8074-pinctrl.yaml index e053fbd588b51e..6f90dbbdbdcce2 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,ipq8074-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,ipq8074-pinctrl.yaml @@ -23,13 +23,6 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true - "#gpio-cells": true - gpio-ranges: true - wakeup-parent: true - gpio-reserved-ranges: minItems: 1 maxItems: 35 @@ -103,7 +96,7 @@ required: - compatible - reg -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,ipq9574-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,ipq9574-tlmm.yaml index e5e9962b2174fd..bca903b5da6d01 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,ipq9574-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,ipq9574-tlmm.yaml @@ -23,13 +23,6 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true - "#gpio-cells": true - gpio-ranges: true - wakeup-parent: true - gpio-reserved-ranges: minItems: 1 maxItems: 33 @@ -97,7 +90,7 @@ required: - compatible - reg -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,lpass-lpi-common.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,lpass-lpi-common.yaml new file mode 100644 index 00000000000000..3b5045730471fd --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/qcom,lpass-lpi-common.yaml @@ -0,0 +1,75 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/qcom,lpass-lpi-common.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SoC LPASS LPI TLMM Common Properties + +maintainers: + - Bjorn Andersson + - Srinivas Kandagatla + - Krzysztof Kozlowski + +description: + Common properties for the Top Level Mode Multiplexer pin controllers in the + Low Power Audio SubSystem (LPASS) Low Power Island (LPI) of Qualcomm SoCs. + +properties: + gpio-controller: true + + "#gpio-cells": + description: + Specifying the pin number and flags, as defined in + include/dt-bindings/gpio/gpio.h + const: 2 + + gpio-ranges: + maxItems: 1 + +required: + - gpio-controller + - "#gpio-cells" + - gpio-ranges + +allOf: + - $ref: pinctrl.yaml# + +additionalProperties: true + +$defs: + qcom-tlmm-state: + properties: + drive-strength: + enum: [2, 4, 6, 8, 10, 12, 14, 16] + default: 2 + description: + Selects the drive strength for the specified pins, in mA. + + slew-rate: + enum: [0, 1, 2, 3] + default: 0 + description: | + 0: No adjustments + 1: Higher Slew rate (faster edges) + 2: Lower Slew rate (slower edges) + 3: Reserved (No adjustments) + + bias-bus-hold: true + bias-pull-down: true + bias-pull-up: true + bias-disable: true + input-enable: true + output-high: true + output-low: true + + required: + - pins + - function + + allOf: + - $ref: pincfg-node.yaml# + - $ref: pinmux-node.yaml# + + additionalProperties: true + diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,mdm9607-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,mdm9607-tlmm.yaml index 5ece3b9d676b3d..bd3cbb44c99a46 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,mdm9607-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,mdm9607-tlmm.yaml @@ -25,19 +25,7 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true gpio-reserved-ranges: true - "#gpio-cells": true - gpio-ranges: true - wakeup-parent: true - -required: - - compatible - - reg - -additionalProperties: false patternProperties: "-state$": @@ -110,6 +98,12 @@ $defs: required: - pins +required: + - compatible + - reg + +unevaluatedProperties: false + examples: - | #include diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,mdm9615-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,mdm9615-pinctrl.yaml index 5885aee95c98e2..299e0b4b0ab425 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,mdm9615-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,mdm9615-pinctrl.yaml @@ -23,18 +23,6 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - '#interrupt-cells': true - gpio-controller: true - '#gpio-cells': true - gpio-ranges: true - -required: - - compatible - - reg - -additionalProperties: false - patternProperties: "-state$": oneOf: @@ -74,6 +62,12 @@ $defs: required: - pins +required: + - compatible + - reg + +unevaluatedProperties: false + examples: - | #include diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8226-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8226-pinctrl.yaml index a602bf0d27fbc6..68d3fa2105b857 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8226-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8226-pinctrl.yaml @@ -23,12 +23,6 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true - "#gpio-cells": true - gpio-ranges: true - gpio-reserved-ranges: maxItems: 1 @@ -82,7 +76,7 @@ required: - compatible - reg -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8660-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8660-pinctrl.yaml index a0597161178094..61f5be21f30cc0 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8660-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8660-pinctrl.yaml @@ -23,13 +23,6 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true - "#gpio-cells": true - gpio-ranges: true - wakeup-parent: true - gpio-reserved-ranges: minItems: 1 maxItems: 86 @@ -92,7 +85,7 @@ required: - compatible - reg -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8909-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8909-tlmm.yaml index 5095e86fe9a213..295dd5fcf4c3d2 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8909-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8909-tlmm.yaml @@ -25,19 +25,7 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true gpio-reserved-ranges: true - "#gpio-cells": true - gpio-ranges: true - wakeup-parent: true - -required: - - compatible - - reg - -additionalProperties: false patternProperties: "-state$": @@ -108,6 +96,12 @@ $defs: required: - pins +required: + - compatible + - reg + +unevaluatedProperties: false + examples: - | #include diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8916-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8916-pinctrl.yaml index 063d004967bbeb..904af87f9eaff6 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8916-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8916-pinctrl.yaml @@ -23,13 +23,6 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true - "#gpio-cells": true - gpio-ranges: true - wakeup-parent: true - gpio-reserved-ranges: minItems: 1 maxItems: 61 @@ -114,7 +107,7 @@ required: - compatible - reg -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8953-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8953-pinctrl.yaml index 798aac9e6e31b2..8a3a962f6c0073 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8953-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8953-pinctrl.yaml @@ -22,12 +22,7 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true gpio-reserved-ranges: true - "#gpio-cells": true - gpio-ranges: true patternProperties: "-state$": @@ -117,7 +112,7 @@ required: - compatible - reg -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8960-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8960-pinctrl.yaml index 9172b50f7a9825..46618740bd312b 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8960-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8960-pinctrl.yaml @@ -23,13 +23,6 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true - "#gpio-cells": true - gpio-ranges: true - wakeup-parent: true - gpio-reserved-ranges: minItems: 1 maxItems: 76 @@ -108,7 +101,7 @@ required: - compatible - reg -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8974-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8974-pinctrl.yaml index 8a3be65c51edee..840fdaabde1277 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8974-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8974-pinctrl.yaml @@ -23,13 +23,6 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true - "#gpio-cells": true - gpio-ranges: true - wakeup-parent: true - gpio-reserved-ranges: minItems: 1 maxItems: 73 @@ -124,7 +117,7 @@ required: - compatible - reg -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8976-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8976-pinctrl.yaml index ca95de0b87a6a1..d4391c194ff7c6 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8976-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8976-pinctrl.yaml @@ -23,13 +23,6 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true - "#gpio-cells": true - gpio-ranges: true - wakeup-parent: true - gpio-reserved-ranges: minItems: 1 maxItems: 73 @@ -104,7 +97,7 @@ required: - compatible - reg -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8994-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8994-pinctrl.yaml index 41525ecfa8e3a4..fa90981db40b38 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8994-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8994-pinctrl.yaml @@ -25,13 +25,6 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true - "#gpio-cells": true - gpio-ranges: true - wakeup-parent: true - gpio-reserved-ranges: minItems: 1 maxItems: 73 @@ -114,7 +107,7 @@ required: - compatible - reg -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8996-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8996-pinctrl.yaml index 59d406b609574f..c5010c175b2386 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8996-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8996-pinctrl.yaml @@ -23,13 +23,6 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true - "#gpio-cells": true - gpio-ranges: true - wakeup-parent: true - gpio-reserved-ranges: minItems: 1 maxItems: 75 @@ -133,7 +126,7 @@ required: - compatible - reg -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8998-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,msm8998-pinctrl.yaml index bd6d7caf499afb..bcaa231adaf784 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,msm8998-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8998-pinctrl.yaml @@ -23,13 +23,6 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true - "#gpio-cells": true - gpio-ranges: true - wakeup-parent: true - gpio-reserved-ranges: minItems: 1 maxItems: 75 @@ -118,7 +111,7 @@ required: - compatible - reg -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.yaml index 80f96067185704..fe717d8d479824 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.yaml @@ -158,34 +158,40 @@ examples: - | #include - pm8841_mpp: mpps@a000 { - compatible = "qcom,pm8841-mpp", "qcom,spmi-mpp"; - reg = <0xa000 0>; - gpio-controller; - #gpio-cells = <2>; - gpio-ranges = <&pm8841_mpp 0 0 4>; - gpio-line-names = "VDD_PX_BIAS", "WLAN_LED_CTRL", - "BT_LED_CTRL", "GPIO-F"; - interrupt-controller; - #interrupt-cells = <2>; - - pinctrl-names = "default"; - pinctrl-0 = <&pm8841_default>; - - mpp1-state { - pins = "mpp1"; - function = "digital"; - input-enable; - power-source = ; - }; - - default-state { - gpio-pins { - pins = "mpp1", "mpp2", "mpp3", "mpp4"; - function = "digital"; - input-enable; - power-source = ; + pmic { + #address-cells = <1>; + #size-cells = <0>; + + pm8841_mpp: mpps@a000 { + compatible = "qcom,pm8841-mpp", "qcom,spmi-mpp"; + reg = <0xa000>; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pm8841_mpp 0 0 4>; + gpio-line-names = "VDD_PX_BIAS", "WLAN_LED_CTRL", + "BT_LED_CTRL", "GPIO-F"; + interrupt-controller; + #interrupt-cells = <2>; + + pinctrl-names = "default"; + pinctrl-0 = <&pm8841_default>; + + mpp1-state { + pins = "mpp1"; + function = "digital"; + input-enable; + power-source = ; + }; + + default-state { + gpio-pins { + pins = "mpp1", "mpp2", "mpp3", "mpp4"; + function = "digital"; + input-enable; + power-source = ; + }; + }; }; - }; }; ... diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,qcm2290-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,qcm2290-tlmm.yaml index c323f6d495a449..e123beb33aef5e 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,qcm2290-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,qcm2290-tlmm.yaml @@ -22,13 +22,6 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true - "#gpio-cells": true - gpio-ranges: true - wakeup-parent: true - patternProperties: "-state$": oneOf: @@ -92,7 +85,7 @@ required: - compatible - reg -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,qcs404-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,qcs404-pinctrl.yaml index b1b9cd319e50a3..4009501b3414f4 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,qcs404-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,qcs404-pinctrl.yaml @@ -29,13 +29,6 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true - "#gpio-cells": true - gpio-ranges: true - wakeup-parent: true - gpio-reserved-ranges: minItems: 1 maxItems: 60 @@ -130,7 +123,7 @@ required: - compatible - reg -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,qdu1000-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,qdu1000-tlmm.yaml index 237cac4f6ce1df..88afeae530c682 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,qdu1000-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,qdu1000-tlmm.yaml @@ -23,10 +23,8 @@ properties: reg: maxItems: 1 - interrupts: true - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true + interrupts: + maxItems: 1 gpio-reserved-ranges: minItems: 1 @@ -35,10 +33,6 @@ properties: gpio-line-names: maxItems: 151 - "#gpio-cells": true - gpio-ranges: true - wakeup-parent: true - patternProperties: "-state$": oneOf: @@ -101,7 +95,7 @@ required: - compatible - reg -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sa8775p-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sa8775p-tlmm.yaml index 2173c5255638bd..e9abbf2c0689bc 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sa8775p-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sa8775p-tlmm.yaml @@ -22,13 +22,8 @@ properties: reg: maxItems: 1 - interrupts: true - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true - "#gpio-cells": true - gpio-ranges: true - wakeup-parent: true + interrupts: + maxItems: 1 gpio-reserved-ranges: minItems: 1 @@ -37,12 +32,6 @@ properties: gpio-line-names: maxItems: 148 -required: - - compatible - - reg - -additionalProperties: false - patternProperties: "-state$": oneOf: @@ -108,6 +97,12 @@ $defs: required: - pins +required: + - compatible + - reg + +unevaluatedProperties: false + examples: - | #include diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sc7180-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sc7180-pinctrl.yaml index 573e459b1c44a1..5606f2136ad101 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sc7180-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sc7180-pinctrl.yaml @@ -29,13 +29,6 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true - "#gpio-cells": true - gpio-ranges: true - wakeup-parent: true - gpio-reserved-ranges: minItems: 1 maxItems: 60 @@ -112,7 +105,7 @@ required: - reg - reg-names -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sc7280-lpass-lpi-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sc7280-lpass-lpi-pinctrl.yaml index 00c5a00e35fce2..08801cc4e476ff 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sc7280-lpass-lpi-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sc7280-lpass-lpi-pinctrl.yaml @@ -20,16 +20,6 @@ properties: reg: maxItems: 2 - gpio-controller: true - - "#gpio-cells": - description: Specifying the pin number and flags, as defined in - include/dt-bindings/gpio/gpio.h - const: 2 - - gpio-ranges: - maxItems: 1 - patternProperties: "-state$": oneOf: @@ -45,7 +35,8 @@ $defs: description: Pinctrl node's client devices use subnodes for desired pin configuration. Client device subnodes use below standard properties. - $ref: /schemas/pinctrl/pincfg-node.yaml + $ref: qcom,lpass-lpi-common.yaml#/$defs/qcom-tlmm-state + unevaluatedProperties: false properties: pins: @@ -68,42 +59,14 @@ $defs: Specify the alternative function to be configured for the specified pins. - drive-strength: - enum: [2, 4, 6, 8, 10, 12, 14, 16] - default: 2 - description: - Selects the drive strength for the specified pins, in mA. - - slew-rate: - enum: [0, 1, 2, 3] - default: 0 - description: | - 0: No adjustments - 1: Higher Slew rate (faster edges) - 2: Lower Slew rate (slower edges) - 3: Reserved (No adjustments) - - bias-pull-down: true - bias-pull-up: true - bias-bus-hold: true - bias-disable: true - output-high: true - output-low: true - - required: - - pins - - function - - additionalProperties: false - required: - compatible - reg - - gpio-controller - - "#gpio-cells" - - gpio-ranges -additionalProperties: false +allOf: + - $ref: qcom,lpass-lpi-common.yaml# + +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sc7280-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sc7280-pinctrl.yaml index c8735ab97e407d..5329fe2a439789 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sc7280-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sc7280-pinctrl.yaml @@ -23,24 +23,6 @@ properties: description: Specifies the TLMM summary IRQ maxItems: 1 - interrupt-controller: true - - '#interrupt-cells': - description: - Specifies the PIN numbers and Flags, as defined in defined in - include/dt-bindings/interrupt-controller/irq.h - const: 2 - - gpio-controller: true - - '#gpio-cells': - description: Specifying the pin number and flags, as defined in - include/dt-bindings/gpio/gpio.h - const: 2 - - gpio-ranges: - maxItems: 1 - gpio-reserved-ranges: minItems: 1 maxItems: 88 @@ -48,8 +30,6 @@ properties: gpio-line-names: maxItems: 175 - wakeup-parent: true - patternProperties: "-state$": oneOf: @@ -124,14 +104,8 @@ allOf: required: - compatible - reg - - interrupts - - interrupt-controller - - '#interrupt-cells' - - gpio-controller - - '#gpio-cells' - - gpio-ranges - -additionalProperties: false + +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sc8180x-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sc8180x-tlmm.yaml index b086a5184235a6..c122bb849f0f72 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sc8180x-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sc8180x-tlmm.yaml @@ -31,20 +31,7 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - '#interrupt-cells': true - gpio-controller: true gpio-reserved-ranges: true - '#gpio-cells': true - gpio-ranges: true - wakeup-parent: true - -required: - - compatible - - reg - - reg-names - -additionalProperties: false patternProperties: "-state$": @@ -106,6 +93,13 @@ $defs: required: - pins +required: + - compatible + - reg + - reg-names + +unevaluatedProperties: false + examples: - | #include diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sc8280xp-lpass-lpi-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sc8280xp-lpass-lpi-pinctrl.yaml index a9167dac9ab58b..240e6d45cc95e9 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sc8280xp-lpass-lpi-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sc8280xp-lpass-lpi-pinctrl.yaml @@ -32,16 +32,6 @@ properties: - const: core - const: audio - gpio-controller: true - - "#gpio-cells": - description: Specifying the pin number and flags, as defined in - include/dt-bindings/gpio/gpio.h - const: 2 - - gpio-ranges: - maxItems: 1 - patternProperties: "-state$": oneOf: @@ -57,7 +47,8 @@ $defs: description: Pinctrl node's client devices use subnodes for desired pin configuration. Client device subnodes use below standard properties. - $ref: /schemas/pinctrl/pincfg-node.yaml + $ref: qcom,lpass-lpi-common.yaml#/$defs/qcom-tlmm-state + unevaluatedProperties: false properties: pins: @@ -79,48 +70,16 @@ $defs: Specify the alternative function to be configured for the specified pins. - drive-strength: - enum: [2, 4, 6, 8, 10, 12, 14, 16] - default: 2 - description: - Selects the drive strength for the specified pins, in mA. - - slew-rate: - enum: [0, 1, 2, 3] - default: 0 - description: | - 0: No adjustments - 1: Higher Slew rate (faster edges) - 2: Lower Slew rate (slower edges) - 3: Reserved (No adjustments) - - bias-bus-hold: true - bias-pull-down: true - bias-pull-up: true - bias-disable: true - input-enable: true - output-high: true - output-low: true - - required: - - pins - - function - - additionalProperties: false - allOf: - - $ref: pinctrl.yaml# + - $ref: qcom,lpass-lpi-common.yaml# required: - compatible - reg - clocks - clock-names - - gpio-controller - - "#gpio-cells" - - gpio-ranges -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sc8280xp-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sc8280xp-tlmm.yaml index 4bd6d7977d3e87..ed344deaf8b9e4 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sc8280xp-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sc8280xp-tlmm.yaml @@ -25,19 +25,7 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true gpio-reserved-ranges: true - "#gpio-cells": true - gpio-ranges: true - wakeup-parent: true - -required: - - compatible - - reg - -additionalProperties: false patternProperties: "-state$": @@ -108,6 +96,12 @@ $defs: required: - pins +required: + - compatible + - reg + +unevaluatedProperties: false + examples: - | #include diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sdm630-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sdm630-pinctrl.yaml index 508e0633b253e4..a00cb43df144b5 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sdm630-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sdm630-pinctrl.yaml @@ -34,10 +34,6 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true - gpio-reserved-ranges: minItems: 1 maxItems: 57 @@ -45,10 +41,6 @@ properties: gpio-line-names: maxItems: 114 - "#gpio-cells": true - gpio-ranges: true - wakeup-parent: true - patternProperties: "-state$": oneOf: @@ -130,7 +122,7 @@ required: - compatible - reg -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sdm670-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sdm670-tlmm.yaml index 84a15f77e710a5..b56e717aa28e77 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sdm670-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sdm670-tlmm.yaml @@ -25,23 +25,10 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true gpio-reserved-ranges: minItems: 1 maxItems: 75 - "#gpio-cells": true - gpio-ranges: true - wakeup-parent: true - -required: - - compatible - - reg - -additionalProperties: false - patternProperties: "-state$": oneOf: @@ -98,6 +85,12 @@ $defs: required: - pins +required: + - compatible + - reg + +unevaluatedProperties: false + examples: - | #include diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sdm845-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sdm845-pinctrl.yaml index d301881ddfa8e0..dfe5616b9b858f 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sdm845-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sdm845-pinctrl.yaml @@ -26,10 +26,6 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true - gpio-reserved-ranges: minItems: 1 maxItems: 75 @@ -37,10 +33,6 @@ properties: gpio-line-names: maxItems: 150 - "#gpio-cells": true - gpio-ranges: true - wakeup-parent: true - patternProperties: "-state$": oneOf: @@ -110,7 +102,7 @@ required: - compatible - reg -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sdx55-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sdx55-pinctrl.yaml index 67af99dd8f147b..edbcff92bbf91f 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sdx55-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sdx55-pinctrl.yaml @@ -23,12 +23,6 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true - "#gpio-cells": true - gpio-ranges: true - gpio-reserved-ranges: maxItems: 1 @@ -102,7 +96,7 @@ required: - compatible - reg -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sdx65-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sdx65-tlmm.yaml index 27319782d94be5..a31b638c456d11 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sdx65-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sdx65-tlmm.yaml @@ -22,12 +22,6 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true - "#gpio-cells": true - gpio-ranges: true - gpio-reserved-ranges: maxItems: 1 @@ -122,7 +116,7 @@ required: - compatible - reg -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sdx75-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sdx75-tlmm.yaml index 7cb96aa75b08bd..cb1d978d02c9a5 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sdx75-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sdx75-tlmm.yaml @@ -22,10 +22,8 @@ properties: reg: maxItems: 1 - interrupts: true - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true + interrupts: + maxItems: 1 gpio-reserved-ranges: minItems: 1 @@ -34,10 +32,6 @@ properties: gpio-line-names: maxItems: 133 - "#gpio-cells": true - gpio-ranges: true - wakeup-parent: true - patternProperties: "-state$": oneOf: @@ -100,7 +94,7 @@ required: - compatible - reg -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm4450-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm4450-tlmm.yaml new file mode 100644 index 00000000000000..bb08ca5a1509e3 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm4450-tlmm.yaml @@ -0,0 +1,151 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/qcom,sm4450-tlmm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Technologies, Inc. SM4450 TLMM block + +maintainers: + - Tengfei Fan + +description: + Top Level Mode Multiplexer pin controller in Qualcomm SM4450 SoC. + +allOf: + - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml# + +properties: + compatible: + const: qcom,sm4450-pinctrl + + reg: + maxItems: 1 + + interrupts: true + interrupt-controller: true + "#interrupt-cells": true + gpio-controller: true + + gpio-reserved-ranges: + minItems: 1 + maxItems: 68 + + gpio-line-names: + maxItems: 136 + + "#gpio-cells": true + gpio-ranges: true + wakeup-parent: true + +patternProperties: + "-state$": + oneOf: + - $ref: "#/$defs/qcom-sm4450-tlmm-state" + - patternProperties: + "-pins$": + $ref: "#/$defs/qcom-sm4450-tlmm-state" + additionalProperties: false + +$defs: + qcom-sm4450-tlmm-state: + type: object + description: + Pinctrl node's client devices use subnodes for desired pin configuration. + Client device subnodes use below standard properties. + $ref: qcom,tlmm-common.yaml#/$defs/qcom-tlmm-state + unevaluatedProperties: false + + properties: + pins: + description: + List of gpio pins affected by the properties specified in this + subnode. + items: + oneOf: + - pattern: "^gpio([0-9]|[1-9][0-9]|1[0-2][0-9]|13[0-5])$" + - enum: [ sdc2_clk, sdc2_cmd, sdc2_data, ufs_reset ] + minItems: 1 + maxItems: 36 + + function: + description: + Specify the alternative function to be configured for the specified + pins. + enum: [ gpio, atest_char, atest_char0, atest_char1, atest_char2, + atest_char3, atest_usb0, atest_usb00, atest_usb01, atest_usb02, + atest_usb03, audio_ref, cam_mclk, cci_async, cci_i2c, + cci_timer0, cci_timer1, cci_timer2, cci_timer3, cci_timer4, + cmu_rng0, cmu_rng1, cmu_rng2, cmu_rng3, coex_uart1, cri_trng, + cri_trng0, cri_trng1, dbg_out, ddr_bist, ddr_pxi0, ddr_pxi1, + dp0_hot, gcc_gp1, gcc_gp2, gcc_gp3, host2wlan_sol, ibi_i3c, + jitter_bist, mdp_vsync, mdp_vsync0, mdp_vsync1, mdp_vsync2, + mdp_vsync3, mi2s0_data0, mi2s0_data1, mi2s0_sck, mi2s0_ws, + mi2s2_data0, mi2s2_data1, mi2s2_sck, mi2s2_ws, mi2s_mclk0, + mi2s_mclk1, nav_gpio0, nav_gpio1, nav_gpio2, pcie0_clk, + phase_flag0, phase_flag1, phase_flag10, phase_flag11, + phase_flag12, phase_flag13, phase_flag14, phase_flag15, + phase_flag16, phase_flag17, phase_flag18, phase_flag19, + phase_flag2, phase_flag20, phase_flag21, phase_flag22, + phase_flag23, phase_flag24, phase_flag25, phase_flag26, + phase_flag27, phase_flag28, phase_flag29, phase_flag3, + phase_flag30, phase_flag31, phase_flag4, phase_flag5, + phase_flag6, phase_flag7, phase_flag8, phase_flag9, + pll_bist, pll_clk, prng_rosc0, prng_rosc1, prng_rosc2, + prng_rosc3, qdss_cti, qdss_gpio, qdss_gpio0, qdss_gpio1, + qdss_gpio10, qdss_gpio11, qdss_gpio12, qdss_gpio13, qdss_gpio14, + qdss_gpio15, qdss_gpio2, qdss_gpio3, qdss_gpio4, qdss_gpio5, + qdss_gpio6, qdss_gpio7, qdss_gpio8, qdss_gpio9, qlink0_enable, + qlink0_request, qlink0_wmss, qlink1_enable, qlink1_request, + qlink1_wmss, qlink2_enable, qlink2_request, qlink2_wmss, + qup0_se0, qup0_se1, qup0_se2, qup0_se3, qup0_se4, qup0_se5, + qup0_se6, qup0_se7, qup1_se0, qup1_se1, qup1_se2, qup1_se3, + qup1_se4, qup1_se5, qup1_se6, sd_write, tb_trig, tgu_ch0, + tgu_ch1, tgu_ch2, tgu_ch3, tmess_prng0, tmess_prng1, + tmess_prng2, tmess_prng3, tsense_pwm1, tsense_pwm2, uim0_clk, + uim0_data, uim0_present, uim0_reset, uim1_clk, uim1_data, + uim1_present, uim1_reset, usb0_hs, usb0_phy, vfr_0, vfr_1, + vsense_trigger ] + + required: + - pins + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + #include + tlmm: pinctrl@f100000 { + compatible = "qcom,sm4450-tlmm"; + reg = <0x0f100000 0x300000>; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&tlmm 0 0 137>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + + gpio-wo-state { + pins = "gpio1"; + function = "gpio"; + }; + + uart-w-state { + rx-pins { + pins = "gpio23"; + function = "qup1_se2"; + bias-pull-up; + }; + + tx-pins { + pins = "gpio22"; + function = "qup1_se2"; + bias-disable; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm6115-lpass-lpi-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm6115-lpass-lpi-pinctrl.yaml index abac3311fc5507..f4cf2ce86fcd42 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sm6115-lpass-lpi-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm6115-lpass-lpi-pinctrl.yaml @@ -31,16 +31,6 @@ properties: items: - const: audio - gpio-controller: true - - "#gpio-cells": - description: Specifying the pin number and flags, as defined in - include/dt-bindings/gpio/gpio.h - const: 2 - - gpio-ranges: - maxItems: 1 - patternProperties: "-state$": oneOf: @@ -56,7 +46,8 @@ $defs: description: Pinctrl node's client devices use subnodes for desired pin configuration. Client device subnodes use below standard properties. - $ref: /schemas/pinctrl/pincfg-node.yaml + $ref: qcom,lpass-lpi-common.yaml#/$defs/qcom-tlmm-state + unevaluatedProperties: false properties: pins: @@ -75,48 +66,17 @@ $defs: Specify the alternative function to be configured for the specified pins. - drive-strength: - enum: [2, 4, 6, 8, 10, 12, 14, 16] - default: 2 - description: - Selects the drive strength for the specified pins, in mA. - - slew-rate: - enum: [0, 1, 2, 3] - default: 0 - description: | - 0: No adjustments - 1: Higher Slew rate (faster edges) - 2: Lower Slew rate (slower edges) - 3: Reserved (No adjustments) - - bias-bus-hold: true - bias-pull-down: true - bias-pull-up: true - bias-disable: true - input-enable: true - output-high: true - output-low: true - - required: - - pins - - function - - additionalProperties: false allOf: - - $ref: pinctrl.yaml# + - $ref: qcom,lpass-lpi-common.yaml# required: - compatible - reg - clocks - clock-names - - gpio-controller - - "#gpio-cells" - - gpio-ranges -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm6115-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm6115-tlmm.yaml index 871df54f69a2eb..7f36f9b9333309 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sm6115-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm6115-tlmm.yaml @@ -29,13 +29,7 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true - "#gpio-cells": true - gpio-ranges: true gpio-reserved-ranges: true - wakeup-parent: true patternProperties: "-state$": @@ -97,7 +91,7 @@ required: - reg - reg-names -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm6125-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm6125-tlmm.yaml index 8d77707b02b9fe..ddeaeaa9a450ab 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sm6125-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm6125-tlmm.yaml @@ -30,20 +30,7 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true gpio-reserved-ranges: true - "#gpio-cells": true - gpio-ranges: true - wakeup-parent: true - -required: - - compatible - - reg - - reg-names - -additionalProperties: false patternProperties: "-state$": @@ -105,6 +92,13 @@ $defs: required: - pins +required: + - compatible + - reg + - reg-names + +unevaluatedProperties: false + examples: - | #include diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm6350-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm6350-tlmm.yaml index 27af379cf791aa..a4771f87d93645 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sm6350-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm6350-tlmm.yaml @@ -26,10 +26,6 @@ properties: minItems: 9 maxItems: 9 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true - gpio-reserved-ranges: minItems: 1 maxItems: 78 @@ -37,16 +33,6 @@ properties: gpio-line-names: maxItems: 156 - "#gpio-cells": true - gpio-ranges: true - wakeup-parent: true - -required: - - compatible - - reg - -additionalProperties: false - patternProperties: "-state$": oneOf: @@ -112,6 +98,12 @@ $defs: required: - pins +required: + - compatible + - reg + +unevaluatedProperties: false + examples: - | #include diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm6375-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm6375-tlmm.yaml index 6e02ba24825f11..047f82863f9bbf 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sm6375-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm6375-tlmm.yaml @@ -25,19 +25,7 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true gpio-reserved-ranges: true - "#gpio-cells": true - gpio-ranges: true - wakeup-parent: true - -required: - - compatible - - reg - -additionalProperties: false patternProperties: "-state$": @@ -113,6 +101,12 @@ $defs: required: - pins +required: + - compatible + - reg + +unevaluatedProperties: false + examples: - | #include diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm7150-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm7150-tlmm.yaml index ede0f3acad9c4f..7f23f939ad3257 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sm7150-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm7150-tlmm.yaml @@ -32,13 +32,6 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true - "#gpio-cells": true - gpio-ranges: true - wakeup-parent: true - gpio-reserved-ranges: minItems: 1 maxItems: 60 @@ -111,7 +104,7 @@ required: - reg - reg-names -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8150-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm8150-pinctrl.yaml index c6439626464ef9..bdb7ed4be02675 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sm8150-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8150-pinctrl.yaml @@ -30,13 +30,6 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true - "#gpio-cells": true - gpio-ranges: true - wakeup-parent: true - gpio-reserved-ranges: minItems: 1 maxItems: 88 @@ -113,7 +106,7 @@ required: - reg - reg-names -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8250-lpass-lpi-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm8250-lpass-lpi-pinctrl.yaml index 4b4be7efc150ac..750c996c10a713 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sm8250-lpass-lpi-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8250-lpass-lpi-pinctrl.yaml @@ -30,16 +30,6 @@ properties: - const: core - const: audio - gpio-controller: true - - "#gpio-cells": - description: Specifying the pin number and flags, as defined in - include/dt-bindings/gpio/gpio.h - const: 2 - - gpio-ranges: - maxItems: 1 - patternProperties: "-state$": oneOf: @@ -55,7 +45,8 @@ $defs: description: Pinctrl node's client devices use subnodes for desired pin configuration. Client device subnodes use below standard properties. - $ref: /schemas/pinctrl/pincfg-node.yaml + $ref: qcom,lpass-lpi-common.yaml#/$defs/qcom-tlmm-state + unevaluatedProperties: false properties: pins: @@ -78,48 +69,16 @@ $defs: Specify the alternative function to be configured for the specified pins. - drive-strength: - enum: [2, 4, 6, 8, 10, 12, 14, 16] - default: 2 - description: - Selects the drive strength for the specified pins, in mA. - - slew-rate: - enum: [0, 1, 2, 3] - default: 0 - description: | - 0: No adjustments - 1: Higher Slew rate (faster edges) - 2: Lower Slew rate (slower edges) - 3: Reserved (No adjustments) - - bias-pull-down: true - bias-pull-up: true - bias-bus-hold: true - bias-disable: true - input-enable: true - output-high: true - output-low: true - - required: - - pins - - function - - additionalProperties: false - allOf: - - $ref: pinctrl.yaml# + - $ref: qcom,lpass-lpi-common.yaml# required: - compatible - reg - clocks - clock-names - - gpio-controller - - "#gpio-cells" - - gpio-ranges -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8250-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm8250-pinctrl.yaml index 021c5470852469..b5d04347c064d5 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sm8250-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8250-pinctrl.yaml @@ -28,13 +28,6 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true - "#gpio-cells": true - gpio-ranges: true - wakeup-parent: true - gpio-reserved-ranges: minItems: 1 maxItems: 90 @@ -106,7 +99,7 @@ required: - reg - reg-names -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8350-lpass-lpi-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm8350-lpass-lpi-pinctrl.yaml index 2e65ae08dd2112..9d782f910b318c 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sm8350-lpass-lpi-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8350-lpass-lpi-pinctrl.yaml @@ -33,16 +33,6 @@ properties: - const: core - const: audio - gpio-controller: true - - "#gpio-cells": - description: Specifying the pin number and flags, as defined in - include/dt-bindings/gpio/gpio.h - const: 2 - - gpio-ranges: - maxItems: 1 - patternProperties: "-state$": oneOf: @@ -58,7 +48,8 @@ $defs: description: Pinctrl node's client devices use subnodes for desired pin configuration. Client device subnodes use below standard properties. - $ref: /schemas/pinctrl/pincfg-node.yaml + $ref: qcom,lpass-lpi-common.yaml#/$defs/qcom-tlmm-state + unevaluatedProperties: false properties: pins: @@ -81,48 +72,16 @@ $defs: Specify the alternative function to be configured for the specified pins. - drive-strength: - enum: [2, 4, 6, 8, 10, 12, 14, 16] - default: 2 - description: - Selects the drive strength for the specified pins, in mA. - - slew-rate: - enum: [0, 1, 2, 3] - default: 0 - description: | - 0: No adjustments - 1: Higher Slew rate (faster edges) - 2: Lower Slew rate (slower edges) - 3: Reserved (No adjustments) - - bias-bus-hold: true - bias-pull-down: true - bias-pull-up: true - bias-disable: true - input-enable: true - output-high: true - output-low: true - - required: - - pins - - function - - additionalProperties: false - allOf: - - $ref: pinctrl.yaml# + - $ref: qcom,lpass-lpi-common.yaml# required: - compatible - reg - clocks - clock-names - - gpio-controller - - "#gpio-cells" - - gpio-ranges -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8350-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm8350-tlmm.yaml index 6e8f41ff0a76be..ec5e09611d810c 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sm8350-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8350-tlmm.yaml @@ -25,10 +25,6 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true - gpio-reserved-ranges: minItems: 1 maxItems: 102 @@ -36,16 +32,6 @@ properties: gpio-line-names: maxItems: 203 - "#gpio-cells": true - gpio-ranges: true - wakeup-parent: true - -required: - - compatible - - reg - -additionalProperties: false - patternProperties: "-state$": oneOf: @@ -108,6 +94,12 @@ $defs: required: - pins +required: + - compatible + - reg + +unevaluatedProperties: false + examples: - | #include diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8450-lpass-lpi-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm8450-lpass-lpi-pinctrl.yaml index 1eefa9aa6a86cc..e7565592da8624 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sm8450-lpass-lpi-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8450-lpass-lpi-pinctrl.yaml @@ -32,16 +32,6 @@ properties: - const: core - const: audio - gpio-controller: true - - "#gpio-cells": - description: Specifying the pin number and flags, as defined in - include/dt-bindings/gpio/gpio.h - const: 2 - - gpio-ranges: - maxItems: 1 - patternProperties: "-state$": oneOf: @@ -57,7 +47,8 @@ $defs: description: Pinctrl node's client devices use subnodes for desired pin configuration. Client device subnodes use below standard properties. - $ref: /schemas/pinctrl/pincfg-node.yaml + $ref: qcom,lpass-lpi-common.yaml#/$defs/qcom-tlmm-state + unevaluatedProperties: false properties: pins: @@ -81,48 +72,16 @@ $defs: Specify the alternative function to be configured for the specified pins. - drive-strength: - enum: [2, 4, 6, 8, 10, 12, 14, 16] - default: 2 - description: - Selects the drive strength for the specified pins, in mA. - - slew-rate: - enum: [0, 1, 2, 3] - default: 0 - description: | - 0: No adjustments - 1: Higher Slew rate (faster edges) - 2: Lower Slew rate (slower edges) - 3: Reserved (No adjustments) - - bias-bus-hold: true - bias-pull-down: true - bias-pull-up: true - bias-disable: true - input-enable: true - output-high: true - output-low: true - - required: - - pins - - function - - additionalProperties: false - allOf: - - $ref: pinctrl.yaml# + - $ref: qcom,lpass-lpi-common.yaml# required: - compatible - reg - clocks - clock-names - - gpio-controller - - "#gpio-cells" - - gpio-ranges -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8450-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm8450-tlmm.yaml index 5163fe3f536520..16fd2c5e233931 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sm8450-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8450-tlmm.yaml @@ -25,10 +25,6 @@ properties: interrupts: maxItems: 1 - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true - gpio-reserved-ranges: minItems: 1 maxItems: 105 @@ -36,16 +32,6 @@ properties: gpio-line-names: maxItems: 210 - "#gpio-cells": true - gpio-ranges: true - wakeup-parent: true - -required: - - compatible - - reg - -additionalProperties: false - patternProperties: "-state$": oneOf: @@ -107,6 +93,12 @@ $defs: required: - pins +required: + - compatible + - reg + +unevaluatedProperties: false + examples: - | #include diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8550-lpass-lpi-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm8550-lpass-lpi-pinctrl.yaml index ef974324684987..bf4a72facae1d5 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sm8550-lpass-lpi-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8550-lpass-lpi-pinctrl.yaml @@ -16,7 +16,11 @@ description: properties: compatible: - const: qcom,sm8550-lpass-lpi-pinctrl + oneOf: + - const: qcom,sm8550-lpass-lpi-pinctrl + - items: + - const: qcom,x1e80100-lpass-lpi-pinctrl + - const: qcom,sm8550-lpass-lpi-pinctrl reg: items: @@ -33,16 +37,6 @@ properties: - const: core - const: audio - gpio-controller: true - - "#gpio-cells": - description: Specifying the pin number and flags, as defined in - include/dt-bindings/gpio/gpio.h - const: 2 - - gpio-ranges: - maxItems: 1 - patternProperties: "-state$": oneOf: @@ -58,7 +52,8 @@ $defs: description: Pinctrl node's client devices use subnodes for desired pin configuration. Client device subnodes use below standard properties. - $ref: /schemas/pinctrl/pincfg-node.yaml + $ref: qcom,lpass-lpi-common.yaml#/$defs/qcom-tlmm-state + unevaluatedProperties: false properties: pins: @@ -81,48 +76,16 @@ $defs: Specify the alternative function to be configured for the specified pins. - drive-strength: - enum: [2, 4, 6, 8, 10, 12, 14, 16] - default: 2 - description: - Selects the drive strength for the specified pins, in mA. - - slew-rate: - enum: [0, 1, 2, 3] - default: 0 - description: | - 0: No adjustments - 1: Higher Slew rate (faster edges) - 2: Lower Slew rate (slower edges) - 3: Reserved (No adjustments) - - bias-bus-hold: true - bias-pull-down: true - bias-pull-up: true - bias-disable: true - input-enable: true - output-high: true - output-low: true - - required: - - pins - - function - - additionalProperties: false - allOf: - - $ref: pinctrl.yaml# + - $ref: qcom,lpass-lpi-common.yaml# required: - compatible - reg - clocks - clock-names - - gpio-controller - - "#gpio-cells" - - gpio-ranges -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8550-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm8550-tlmm.yaml index f789c7753a92ce..c2ae79df424fda 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,sm8550-tlmm.yaml +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8550-tlmm.yaml @@ -22,10 +22,8 @@ properties: reg: maxItems: 1 - interrupts: true - interrupt-controller: true - "#interrupt-cells": true - gpio-controller: true + interrupts: + maxItems: 1 gpio-reserved-ranges: minItems: 1 @@ -34,10 +32,6 @@ properties: gpio-line-names: maxItems: 210 - "#gpio-cells": true - gpio-ranges: true - wakeup-parent: true - patternProperties: "-state$": oneOf: @@ -117,7 +111,7 @@ required: - compatible - reg -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8650-lpass-lpi-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm8650-lpass-lpi-pinctrl.yaml new file mode 100644 index 00000000000000..db721436230181 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8650-lpass-lpi-pinctrl.yaml @@ -0,0 +1,107 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/qcom,sm8650-lpass-lpi-pinctrl.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SM8650 SoC LPASS LPI TLMM + +maintainers: + - Krzysztof Kozlowski + - Srinivas Kandagatla + +description: + Top Level Mode Multiplexer pin controller in the Low Power Audio SubSystem + (LPASS) Low Power Island (LPI) of Qualcomm SM8650 SoC. + +properties: + compatible: + const: qcom,sm8650-lpass-lpi-pinctrl + + reg: + items: + - description: LPASS LPI TLMM Control and Status registers + + clocks: + items: + - description: LPASS Core voting clock + - description: LPASS Audio voting clock + + clock-names: + items: + - const: core + - const: audio + +patternProperties: + "-state$": + oneOf: + - $ref: "#/$defs/qcom-sm8650-lpass-state" + - patternProperties: + "-pins$": + $ref: "#/$defs/qcom-sm8650-lpass-state" + additionalProperties: false + +$defs: + qcom-sm8650-lpass-state: + type: object + description: + Pinctrl node's client devices use subnodes for desired pin configuration. + Client device subnodes use below standard properties. + $ref: qcom,lpass-lpi-common.yaml#/$defs/qcom-tlmm-state + unevaluatedProperties: false + + properties: + pins: + description: + List of gpio pins affected by the properties specified in this + subnode. + items: + pattern: "^gpio([0-9]|1[0-9]|2[0-2])$" + + function: + enum: [ dmic1_clk, dmic1_data, dmic2_clk, dmic2_data, dmic3_clk, + dmic3_data, dmic4_clk, dmic4_data, ext_mclk1_a, ext_mclk1_b, + ext_mclk1_c, ext_mclk1_d, ext_mclk1_e, gpio, i2s0_clk, + i2s0_data, i2s0_ws, i2s1_clk, i2s1_data, i2s1_ws, i2s2_clk, + i2s2_data, i2s2_ws, i2s3_clk, i2s3_data, i2s3_ws, i2s4_clk, + i2s4_data, i2s4_ws, qca_swr_clk, qca_swr_data, slimbus_clk, + slimbus_data, swr_rx_clk, swr_rx_data, swr_tx_clk, swr_tx_data, + wsa_swr_clk, wsa_swr_data, wsa2_swr_clk, wsa2_swr_data ] + description: + Specify the alternative function to be configured for the specified + pins. + +allOf: + - $ref: qcom,lpass-lpi-common.yaml# + +required: + - compatible + - reg + - clocks + - clock-names + +unevaluatedProperties: false + +examples: + - | + #include + + lpass_tlmm: pinctrl@6e80000 { + compatible = "qcom,sm8650-lpass-lpi-pinctrl"; + reg = <0x06e80000 0x20000>; + + clocks = <&q6prmcc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&q6prmcc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>; + clock-names = "core", "audio"; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&lpass_tlmm 0 0 23>; + + tx-swr-sleep-clk-state { + pins = "gpio0"; + function = "swr_tx_clk"; + drive-strength = <2>; + bias-pull-down; + }; + }; diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,sm8650-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,sm8650-tlmm.yaml new file mode 100644 index 00000000000000..c0a06abf851d30 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/qcom,sm8650-tlmm.yaml @@ -0,0 +1,141 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/qcom,sm8650-tlmm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Technologies, Inc. SM8650 TLMM block + +maintainers: + - Bjorn Andersson + +description: + Top Level Mode Multiplexer pin controller in Qualcomm SM8650 SoC. + +allOf: + - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml# + +properties: + compatible: + const: qcom,sm8650-tlmm + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + gpio-reserved-ranges: + minItems: 1 + maxItems: 105 + + gpio-line-names: + maxItems: 210 + +patternProperties: + "-state$": + oneOf: + - $ref: "#/$defs/qcom-sm8650-tlmm-state" + - patternProperties: + "-pins$": + $ref: "#/$defs/qcom-sm8650-tlmm-state" + additionalProperties: false + +$defs: + qcom-sm8650-tlmm-state: + type: object + description: + Pinctrl node's client devices use subnodes for desired pin configuration. + Client device subnodes use below standard properties. + $ref: qcom,tlmm-common.yaml#/$defs/qcom-tlmm-state + unevaluatedProperties: false + + properties: + pins: + description: + List of gpio pins affected by the properties specified in this + subnode. + items: + oneOf: + - pattern: "^gpio([0-9]|[1-9][0-9]|1[0-9][0-9]|20[0-9])$" + - enum: [ ufs_reset, sdc2_clk, sdc2_cmd, sdc2_data ] + minItems: 1 + maxItems: 36 + + function: + description: + Specify the alternative function to be configured for the specified + pins. + enum: [ gpio, aoss_cti, atest_char, atest_usb, audio_ext_mclk0, + audio_ext_mclk1, audio_ref_clk, cam_aon_mclk2, cam_aon_mclk4, + cam_mclk, cci_async_in, cci_i2c_scl, cci_i2c_sda, cci_timer, + cmu_rng, coex_uart1_rx, coex_uart1_tx, coex_uart2_rx, + coex_uart2_tx, cri_trng, dbg_out_clk, ddr_bist_complete, + ddr_bist_fail, ddr_bist_start, ddr_bist_stop, ddr_pxi0, + ddr_pxi1, ddr_pxi2, ddr_pxi3, do_not, dp_hot, gcc_gp1, + gcc_gp2, gcc_gp3, gnss_adc0, gnss_adc1, i2chub0_se0, + i2chub0_se1, i2chub0_se2, i2chub0_se3, i2chub0_se4, + i2chub0_se5, i2chub0_se6, i2chub0_se7, i2chub0_se8, + i2chub0_se9, i2s0_data0, i2s0_data1, i2s0_sck, i2s0_ws, + i2s1_data0, i2s1_data1, i2s1_sck, i2s1_ws, ibi_i3c, + jitter_bist, mdp_vsync, mdp_vsync0_out, mdp_vsync1_out, + mdp_vsync2_out, mdp_vsync3_out, mdp_vsync_e, nav_gpio0, + nav_gpio1, nav_gpio2, nav_gpio3, pcie0_clk_req_n, + pcie1_clk_req_n, phase_flag, pll_bist_sync, pll_clk_aux, + prng_rosc0, prng_rosc1, prng_rosc2, prng_rosc3, qdss_cti, + qdss_gpio, qlink_big_enable, qlink_big_request, + qlink_little_enable, qlink_little_request, qlink_wmss, + qspi0, qspi1, qspi2, qspi3, qspi_clk, qspi_cs, qup1_se0, + qup1_se1, qup1_se2, qup1_se3, qup1_se4, qup1_se5, qup1_se6, + qup1_se7, qup2_se0, qup2_se1, qup2_se2, qup2_se3, qup2_se4, + qup2_se5, qup2_se6, qup2_se7, sd_write_protect, sdc40, sdc41, + sdc42, sdc43, sdc4_clk, sdc4_cmd, tb_trig_sdc2, tb_trig_sdc4, + tgu_ch0_trigout, tgu_ch1_trigout, tgu_ch2_trigout, + tgu_ch3_trigout, tmess_prng0, tmess_prng1, tmess_prng2, + tmess_prng3, tsense_pwm1, tsense_pwm2, tsense_pwm3, uim0_clk, + uim0_data, uim0_present, uim0_reset, uim1_clk, uim1_data, + uim1_present, uim1_reset, usb1_hs, usb_phy, vfr_0, vfr_1, + vsense_trigger_mirnat ] + + required: + - pins + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include + tlmm: pinctrl@f100000 { + compatible = "qcom,sm8650-tlmm"; + reg = <0x0f100000 0x300000>; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&tlmm 0 0 211>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + + gpio-wo-state { + pins = "gpio1"; + function = "gpio"; + }; + + uart-w-state { + rx-pins { + pins = "gpio60"; + function = "qup1_se7"; + bias-pull-up; + }; + + tx-pins { + pins = "gpio61"; + function = "qup1_se7"; + bias-disable; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,x1e80100-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,x1e80100-tlmm.yaml new file mode 100644 index 00000000000000..a1333e0743a9c8 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/qcom,x1e80100-tlmm.yaml @@ -0,0 +1,137 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pinctrl/qcom,x1e80100-tlmm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Technologies, Inc. X1E80100 TLMM block + +maintainers: + - Rajendra Nayak + +description: + Top Level Mode Multiplexer pin controller in Qualcomm X1E80100 SoC. + +allOf: + - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml# + +properties: + compatible: + const: qcom,x1e80100-tlmm + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + gpio-reserved-ranges: + minItems: 1 + maxItems: 119 + + gpio-line-names: + maxItems: 238 + +patternProperties: + "-state$": + oneOf: + - $ref: "#/$defs/qcom-x1e80100-tlmm-state" + - patternProperties: + "-pins$": + $ref: "#/$defs/qcom-x1e80100-tlmm-state" + additionalProperties: false + +$defs: + qcom-x1e80100-tlmm-state: + type: object + description: + Pinctrl node's client devices use subnodes for desired pin configuration. + Client device subnodes use below standard properties. + $ref: qcom,tlmm-common.yaml#/$defs/qcom-tlmm-state + unevaluatedProperties: false + + properties: + pins: + description: + List of gpio pins affected by the properties specified in this + subnode. + items: + oneOf: + - pattern: "^gpio([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-2][0-9]|23[0-7])$" + - enum: [ ufs_reset, sdc2_clk, sdc2_cmd, sdc2_data ] + minItems: 1 + maxItems: 36 + + function: + description: + Specify the alternative function to be configured for the specified + pins. + enum: [ aon_cci, aoss_cti, atest_char, atest_char0, + atest_char1, atest_char2, atest_char3, atest_usb, + audio_ext, audio_ref, cam_aon, cam_mclk, cci_async, + cci_i2c, cci_timer0, cci_timer1, cci_timer2, cci_timer3, + cci_timer4, cmu_rng0, cmu_rng1, cmu_rng2, cmu_rng3, + cri_trng, dbg_out, ddr_bist, ddr_pxi0, ddr_pxi1, + ddr_pxi2, ddr_pxi3, ddr_pxi4, ddr_pxi5, ddr_pxi6, ddr_pxi7, + edp0_hot, edp0_lcd, edp1_hot, edp1_lcd, eusb0_ac, eusb1_ac, + eusb2_ac, eusb3_ac, eusb5_ac, eusb6_ac, gcc_gp1, gcc_gp2, + gcc_gp3, gpio, i2s0_data0, i2s0_data1, i2s0_sck, i2s0_ws, i2s1_data0, + i2s1_data1, i2s1_sck, i2s1_ws, ibi_i3c, jitter_bist, mdp_vsync0, + mdp_vsync1, mdp_vsync2, mdp_vsync3, mdp_vsync4, mdp_vsync5, + mdp_vsync6, mdp_vsync7, mdp_vsync8, pcie3_clk, pcie4_clk, + pcie5_clk, pcie6a_clk, pcie6b_clk, phase_flag, pll_bist, pll_clk, + prng_rosc0, prng_rosc1, prng_rosc2, prng_rosc3, qdss_cti, + qdss_gpio, qspi00, qspi01, qspi02, qspi03, qspi0_clk, qspi0_cs0, + qspi0_cs1, qup0_se0, qup0_se1, qup0_se2, qup0_se3, qup0_se4, + qup0_se5, qup0_se6, qup0_se7, qup1_se0, qup1_se1, qup1_se2, qup1_se3, + qup1_se4, qup1_se5, qup1_se6, qup1_se7, qup2_se0, qup2_se1, qup2_se2, + qup2_se3, qup2_se4, qup2_se5, qup2_se6, qup2_se7, sd_write, sdc4_clk, + sdc4_cmd, sdc4_data0, sdc4_data1, sdc4_data2, sdc4_data3, sys_throttle, + tb_trig, tgu_ch0, tgu_ch1, tgu_ch2, tgu_ch3, tgu_ch4, tgu_ch5, + tgu_ch6, tgu_ch7, tmess_prng0, tmess_prng1, tmess_prng2, tmess_prng3, + tsense_pwm1, tsense_pwm2, sense_pwm3, tsense_pwm4, usb0_dp, usb0_phy, + usb0_sbrx, usb0_sbtx, usb1_dp, usb1_phy, usb1_sbrx, usb1_sbtx, + usb2_dp, usb2_phy, usb2_sbrx, usb2_sbtx, vsense_trigger ] + + required: + - pins + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include + tlmm: pinctrl@f100000 { + compatible = "qcom,x1e80100-tlmm"; + reg = <0x0f100000 0xf00000>; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&tlmm 0 0 239>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + + gpio-wo-state { + pins = "gpio1"; + function = "gpio"; + }; + + uart-w-state { + rx-pins { + pins = "gpio26"; + function = "qup2_se7"; + bias-pull-up; + }; + + tx-pins { + pins = "gpio27"; + function = "qup2_se7"; + bias-disable; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/pinctrl/renesas,rza2-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/renesas,rza2-pinctrl.yaml index 8271e7b2c162a3..8b8e4e1a000f62 100644 --- a/Documentation/devicetree/bindings/pinctrl/renesas,rza2-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/renesas,rza2-pinctrl.yaml @@ -20,7 +20,7 @@ description: properties: compatible: - const: "renesas,r7s9210-pinctrl" # RZ/A2M + const: renesas,r7s9210-pinctrl # RZ/A2M reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.yaml index b5ca40d0e251dc..d476de82e5c3f4 100644 --- a/Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/renesas,rzg2l-pinctrl.yaml @@ -185,17 +185,17 @@ examples: sd1_mux { pinmux = , /* CD */ ; /* WP */ - power-source = <3300>; + power-source = <3300>; }; sd1_data { pins = "SD1_DATA0", "SD1_DATA1", "SD1_DATA2", "SD1_DATA3"; - power-source = <3300>; + power-source = <3300>; }; sd1_ctrl { pins = "SD1_CLK", "SD1_CMD"; - power-source = <3300>; + power-source = <3300>; }; }; }; diff --git a/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl-wakeup-interrupt.yaml b/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl-wakeup-interrupt.yaml index 1de91a51234df4..4dfb49b0e07f73 100644 --- a/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl-wakeup-interrupt.yaml +++ b/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl-wakeup-interrupt.yaml @@ -28,15 +28,27 @@ description: | properties: compatible: - enum: - - samsung,s3c2410-wakeup-eint - - samsung,s3c2412-wakeup-eint - - samsung,s3c64xx-wakeup-eint - - samsung,s5pv210-wakeup-eint - - samsung,exynos4210-wakeup-eint - - samsung,exynos7-wakeup-eint - - samsung,exynos850-wakeup-eint - - samsung,exynosautov9-wakeup-eint + oneOf: + - enum: + - samsung,s3c2410-wakeup-eint + - samsung,s3c2412-wakeup-eint + - samsung,s3c64xx-wakeup-eint + - samsung,s5pv210-wakeup-eint + - samsung,exynos4210-wakeup-eint + - samsung,exynos7-wakeup-eint + - samsung,exynosautov920-wakeup-eint + - items: + - enum: + - samsung,exynos5433-wakeup-eint + - samsung,exynos7885-wakeup-eint + - samsung,exynos850-wakeup-eint + - const: samsung,exynos7-wakeup-eint + - items: + - enum: + - google,gs101-wakeup-eint + - samsung,exynosautov9-wakeup-eint + - const: samsung,exynos850-wakeup-eint + - const: samsung,exynos7-wakeup-eint interrupts: description: @@ -79,11 +91,14 @@ allOf: - if: properties: compatible: - contains: - enum: - - samsung,s5pv210-wakeup-eint - - samsung,exynos4210-wakeup-eint - - samsung,exynos7-wakeup-eint + # Match without "contains", to skip newer variants which are still + # compatible with samsung,exynos7-wakeup-eint + enum: + - samsung,s5pv210-wakeup-eint + - samsung,exynos4210-wakeup-eint + - samsung,exynos5433-wakeup-eint + - samsung,exynos7-wakeup-eint + - samsung,exynos7885-wakeup-eint then: properties: interrupts: @@ -98,7 +113,7 @@ allOf: contains: enum: - samsung,exynos850-wakeup-eint - - samsung,exynosautov9-wakeup-eint + - samsung,exynosautov920-wakeup-eint then: properties: interrupts: false diff --git a/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml index 26614621774a5d..118549c2597657 100644 --- a/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/samsung,pinctrl.yaml @@ -35,6 +35,7 @@ properties: compatible: enum: + - google,gs101-pinctrl - samsung,s3c2412-pinctrl - samsung,s3c2416-pinctrl - samsung,s3c2440-pinctrl @@ -53,6 +54,7 @@ properties: - samsung,exynos7885-pinctrl - samsung,exynos850-pinctrl - samsung,exynosautov9-pinctrl + - samsung,exynosautov920-pinctrl - tesla,fsd-pinctrl interrupts: @@ -313,7 +315,8 @@ examples: pinctrl-0 = <&initial_alive>; wakeup-interrupt-controller { - compatible = "samsung,exynos7-wakeup-eint"; + compatible = "samsung,exynos5433-wakeup-eint", + "samsung,exynos7-wakeup-eint"; interrupts = ; }; diff --git a/Documentation/devicetree/bindings/pinctrl/xlnx,zynq-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/xlnx,zynq-pinctrl.yaml index b85f9e36ce4b77..d2676f92ef5bb8 100644 --- a/Documentation/devicetree/bindings/pinctrl/xlnx,zynq-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/xlnx,zynq-pinctrl.yaml @@ -39,7 +39,7 @@ properties: phandle to the SLCR. patternProperties: - '^(.*-)?(default|gpio)$': + '^(.*-)?(default|gpio-grp)$': type: object patternProperties: '^mux': diff --git a/Documentation/devicetree/bindings/pinctrl/xlnx,zynqmp-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/xlnx,zynqmp-pinctrl.yaml index 01b6f2b578437b..f13d315b5d5e8e 100644 --- a/Documentation/devicetree/bindings/pinctrl/xlnx,zynqmp-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/xlnx,zynqmp-pinctrl.yaml @@ -31,7 +31,7 @@ properties: const: xlnx,zynqmp-pinctrl patternProperties: - '^(.*-)?(default|gpio)$': + '^(.*-)?(default|gpio-grp)$': type: object patternProperties: '^mux': diff --git a/Documentation/devicetree/bindings/power/fsl,scu-pd.yaml b/Documentation/devicetree/bindings/power/fsl,scu-pd.yaml index 407b7cfec783cd..7a0f1a40086815 100644 --- a/Documentation/devicetree/bindings/power/fsl,scu-pd.yaml +++ b/Documentation/devicetree/bindings/power/fsl,scu-pd.yaml @@ -20,6 +20,7 @@ properties: compatible: items: - enum: + - fsl,imx8dl-scu-pd - fsl,imx8qm-scu-pd - fsl,imx8qxp-scu-pd - const: fsl,scu-pd diff --git a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml index da9c5846f4e117..2ff246cf8b81dd 100644 --- a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml +++ b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml @@ -39,7 +39,6 @@ properties: - qcom,sc7280-rpmhpd - qcom,sc8180x-rpmhpd - qcom,sc8280xp-rpmhpd - - qcom,sc8380xp-rpmhpd - qcom,sdm660-rpmpd - qcom,sdm670-rpmhpd - qcom,sdm845-rpmhpd @@ -57,6 +56,7 @@ properties: - qcom,sm8450-rpmhpd - qcom,sm8550-rpmhpd - qcom,sm8650-rpmhpd + - qcom,x1e80100-rpmhpd - items: - enum: - qcom,msm8937-rpmpd diff --git a/Documentation/devicetree/bindings/power/reset/nvmem-reboot-mode.yaml b/Documentation/devicetree/bindings/power/reset/nvmem-reboot-mode.yaml index 14a262bcbf7cd2..627f8a6078c299 100644 --- a/Documentation/devicetree/bindings/power/reset/nvmem-reboot-mode.yaml +++ b/Documentation/devicetree/bindings/power/reset/nvmem-reboot-mode.yaml @@ -28,17 +28,15 @@ properties: items: - const: reboot-mode -patternProperties: - "^mode-.+": - $ref: /schemas/types.yaml#/definitions/uint32 - description: Vendor-specific mode value written to the mode register +allOf: + - $ref: reboot-mode.yaml# required: - compatible - nvmem-cells - nvmem-cell-names -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/power/reset/qcom,pon.yaml b/Documentation/devicetree/bindings/power/reset/qcom,pon.yaml index 5e460128b0d109..fc8105a7b9b268 100644 --- a/Documentation/devicetree/bindings/power/reset/qcom,pon.yaml +++ b/Documentation/devicetree/bindings/power/reset/qcom,pon.yaml @@ -111,21 +111,24 @@ examples: #include #include #include - spmi_bus: spmi@c440000 { + + spmi@c440000 { reg = <0x0c440000 0x1100>; #address-cells = <2>; #size-cells = <0>; - pmk8350: pmic@0 { + + pmic@0 { reg = <0x0 SPMI_USID>; #address-cells = <1>; #size-cells = <0>; - pmk8350_pon: pon_hlos@1300 { - reg = <0x1300>; + + pon@800 { compatible = "qcom,pm8998-pon"; + reg = <0x800>; pwrkey { compatible = "qcom,pm8941-pwrkey"; - interrupts = < 0x0 0x8 0 IRQ_TYPE_EDGE_BOTH >; + interrupts = <0x0 0x8 0 IRQ_TYPE_EDGE_BOTH>; debounce = <15625>; bias-pull-up; linux,code = ; diff --git a/Documentation/devicetree/bindings/power/reset/syscon-reboot-mode.yaml b/Documentation/devicetree/bindings/power/reset/syscon-reboot-mode.yaml index 9b1ffceefe3dec..b6acff199cdece 100644 --- a/Documentation/devicetree/bindings/power/reset/syscon-reboot-mode.yaml +++ b/Documentation/devicetree/bindings/power/reset/syscon-reboot-mode.yaml @@ -29,12 +29,10 @@ properties: $ref: /schemas/types.yaml#/definitions/uint32 description: Offset in the register map for the mode register (in bytes) -patternProperties: - "^mode-.+": - $ref: /schemas/types.yaml#/definitions/uint32 - description: Vendor-specific mode value written to the mode register +allOf: + - $ref: reboot-mode.yaml# -additionalProperties: false +unevaluatedProperties: false required: - compatible diff --git a/Documentation/devicetree/bindings/power/reset/xlnx,zynqmp-power.yaml b/Documentation/devicetree/bindings/power/reset/xlnx,zynqmp-power.yaml index 45792e216981a9..799831636194f5 100644 --- a/Documentation/devicetree/bindings/power/reset/xlnx,zynqmp-power.yaml +++ b/Documentation/devicetree/bindings/power/reset/xlnx,zynqmp-power.yaml @@ -57,7 +57,7 @@ examples: firmware { zynqmp-firmware { - zynqmp-power { + power-management { compatible = "xlnx,zynqmp-power"; interrupts = <0 35 4>; }; @@ -70,7 +70,7 @@ examples: firmware { zynqmp-firmware { - zynqmp-power { + power-management { compatible = "xlnx,zynqmp-power"; interrupt-parent = <&gic>; interrupts = <0 35 4>; diff --git a/Documentation/devicetree/bindings/power/supply/bq24190.yaml b/Documentation/devicetree/bindings/power/supply/bq24190.yaml index d3ebc9de8c0b49..131b7e57d22f46 100644 --- a/Documentation/devicetree/bindings/power/supply/bq24190.yaml +++ b/Documentation/devicetree/bindings/power/supply/bq24190.yaml @@ -20,6 +20,7 @@ properties: - ti,bq24192 - ti,bq24192i - ti,bq24196 + - ti,bq24296 reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/power/supply/richtek,rt9455.yaml b/Documentation/devicetree/bindings/power/supply/richtek,rt9455.yaml index 07e38be39f1bc3..89f9603499b460 100644 --- a/Documentation/devicetree/bindings/power/supply/richtek,rt9455.yaml +++ b/Documentation/devicetree/bindings/power/supply/richtek,rt9455.yaml @@ -79,10 +79,10 @@ examples: interrupt-parent = <&gpio1>; interrupts = <0 IRQ_TYPE_LEVEL_LOW>; - richtek,output-charge-current = <500000>; - richtek,end-of-charge-percentage = <10>; - richtek,battery-regulation-voltage = <4200000>; - richtek,boost-output-voltage = <5050000>; + richtek,output-charge-current = <500000>; + richtek,end-of-charge-percentage = <10>; + richtek,battery-regulation-voltage = <4200000>; + richtek,boost-output-voltage = <5050000>; richtek,min-input-voltage-regulation = <4500000>; richtek,avg-input-current-regulation = <500000>; diff --git a/Documentation/devicetree/bindings/power/wakeup-source.txt b/Documentation/devicetree/bindings/power/wakeup-source.txt index 697333a56d5e22..75bc20b95688f6 100644 --- a/Documentation/devicetree/bindings/power/wakeup-source.txt +++ b/Documentation/devicetree/bindings/power/wakeup-source.txt @@ -3,16 +3,20 @@ Specifying wakeup capability for devices Any device nodes ---------------- -Nodes that describe devices which has wakeup capability must contain an +Nodes that describe devices which have wakeup capability may contain a "wakeup-source" boolean property. -Also, if device is marked as a wakeup source, then all the primary -interrupt(s) can be used as wakeup interrupt(s). +If the device is marked as a wakeup-source, interrupt wake capability depends +on the device specific "interrupt-names" property. If no interrupts are labeled +as wake capable, then it is up to the device to determine which interrupts can +wake the system. -However if the devices have dedicated interrupt as the wakeup source -then they need to specify/identify the same using device specific -interrupt name. In such cases only that interrupt can be used as wakeup -interrupt. +However if a device has a dedicated interrupt as the wakeup source, then it +needs to specify/identify it using a device specific interrupt name. In such +cases only that interrupt can be used as a wakeup interrupt. + +While various legacy interrupt names exist, new devices should use "wakeup" as +the canonical interrupt name. List of legacy properties and respective binding document --------------------------------------------------------- diff --git a/Documentation/devicetree/bindings/pwm/mediatek,pwm-disp.yaml b/Documentation/devicetree/bindings/pwm/mediatek,pwm-disp.yaml index 153e146df7d4b2..afcdeed4e88af6 100644 --- a/Documentation/devicetree/bindings/pwm/mediatek,pwm-disp.yaml +++ b/Documentation/devicetree/bindings/pwm/mediatek,pwm-disp.yaml @@ -8,7 +8,6 @@ title: MediaTek DISP_PWM Controller maintainers: - Jitao Shi - - Xinlei Lee allOf: - $ref: pwm.yaml# diff --git a/Documentation/devicetree/bindings/pwm/pwm-omap-dmtimer.txt b/Documentation/devicetree/bindings/pwm/pwm-omap-dmtimer.txt deleted file mode 100644 index 25ecfe14c69896..00000000000000 --- a/Documentation/devicetree/bindings/pwm/pwm-omap-dmtimer.txt +++ /dev/null @@ -1,22 +0,0 @@ -* OMAP PWM for dual-mode timers - -Required properties: -- compatible: Shall contain "ti,omap-dmtimer-pwm". -- ti,timers: phandle to PWM capable OMAP timer. See timer/ti,timer-dm.yaml for info - about these timers. -- #pwm-cells: Should be 3. See pwm.yaml in this directory for a description of - the cells format. - -Optional properties: -- ti,prescaler: Should be a value between 0 and 7, see the timers datasheet -- ti,clock-source: Set dmtimer parent clock, values between 0 and 2: - - 0x00 - high-frequency system clock (timer_sys_ck) - - 0x01 - 32-kHz always-on clock (timer_32k_ck) - - 0x02 - external clock (timer_ext_ck, OMAP2 only) - -Example: - pwm9: dmtimer-pwm@9 { - compatible = "ti,omap-dmtimer-pwm"; - ti,timers = <&timer9>; - #pwm-cells = <3>; - }; diff --git a/Documentation/devicetree/bindings/pwm/pwm-samsung.yaml b/Documentation/devicetree/bindings/pwm/pwm-samsung.yaml index 2162f661ed5a8d..17a2b927af3370 100644 --- a/Documentation/devicetree/bindings/pwm/pwm-samsung.yaml +++ b/Documentation/devicetree/bindings/pwm/pwm-samsung.yaml @@ -29,7 +29,11 @@ properties: - samsung,exynos4210-pwm # 32-bit, Exynos - items: - enum: + - samsung,exynos5433-pwm + - samsung,exynos7-pwm - samsung,exynosautov9-pwm + - samsung,exynosautov920-pwm + - tesla,fsd-pwm - const: samsung,exynos4210-pwm reg: diff --git a/Documentation/devicetree/bindings/pwm/ti,omap-dmtimer-pwm.yaml b/Documentation/devicetree/bindings/pwm/ti,omap-dmtimer-pwm.yaml new file mode 100644 index 00000000000000..1e8e094aad74b9 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/ti,omap-dmtimer-pwm.yaml @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pwm/ti,omap-dmtimer-pwm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI dual mode timer PWM controller + +maintainers: + - Tony Lindgren + +description: + TI dual mode timer instances have an IO pin for PWM capability + +allOf: + - $ref: pwm.yaml# + +properties: + compatible: + const: ti,omap-dmtimer-pwm + + "#pwm-cells": + const: 3 + + ti,timers: + description: Timer instance phandle for the PWM + $ref: /schemas/types.yaml#/definitions/phandle + + ti,prescaler: + description: | + Legacy clock prescaler for timer. The timer counter is prescaled + with 2^n where n is the prescaler. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [ 0, 1, 2, 3, 4, 5, 6, 7 ] + deprecated: true + + ti,clock-source: + description: | + Legacy clock for timer, please use assigned-clocks instead. + 0x00 - high-frequency system clock (timer_sys_ck) + 0x01 - 32-kHz always-on clock (timer_32k_ck) + 0x02 - external clock (timer_ext_ck, OMAP2 only) + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [ 0, 1, 2 ] + deprecated: true + +required: + - compatible + - ti,timers + +unevaluatedProperties: false + +examples: + - | + pwm9: pwm { + compatible = "ti,omap-dmtimer-pwm"; + ti,timers = <&timer9>; + #pwm-cells = <3>; + }; diff --git a/Documentation/devicetree/bindings/regulator/fixed-regulator.yaml b/Documentation/devicetree/bindings/regulator/fixed-regulator.yaml index ce7751b9129ce7..9ff9abf2691a50 100644 --- a/Documentation/devicetree/bindings/regulator/fixed-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/fixed-regulator.yaml @@ -105,6 +105,8 @@ properties: description: Interrupt signaling a critical under-voltage event. + system-critical-regulator: true + required: - compatible - regulator-name diff --git a/Documentation/devicetree/bindings/regulator/mps,mp5416.yaml b/Documentation/devicetree/bindings/regulator/mps,mp5416.yaml index 0221397eb51ec5..f825ee9efd8105 100644 --- a/Documentation/devicetree/bindings/regulator/mps,mp5416.yaml +++ b/Documentation/devicetree/bindings/regulator/mps,mp5416.yaml @@ -62,8 +62,8 @@ examples: regulator-name = "buck1"; regulator-min-microvolt = <600000>; regulator-max-microvolt = <2187500>; - regulator-min-microamp = <3800000>; - regulator-max-microamp = <6800000>; + regulator-min-microamp = <3800000>; + regulator-max-microamp = <6800000>; regulator-boot-on; }; diff --git a/Documentation/devicetree/bindings/regulator/mps,mpq7920.yaml b/Documentation/devicetree/bindings/regulator/mps,mpq7920.yaml index 6de5b027f99038..0d34af98403f84 100644 --- a/Documentation/devicetree/bindings/regulator/mps,mpq7920.yaml +++ b/Documentation/devicetree/bindings/regulator/mps,mpq7920.yaml @@ -98,8 +98,8 @@ examples: regulator-name = "buck1"; regulator-min-microvolt = <400000>; regulator-max-microvolt = <3587500>; - regulator-min-microamp = <460000>; - regulator-max-microamp = <7600000>; + regulator-min-microamp = <460000>; + regulator-max-microamp = <7600000>; regulator-boot-on; mps,buck-ovp-disable; mps,buck-phase-delay = /bits/ 8 <2>; diff --git a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml index acd37f28ef53fc..27c6d5152413fc 100644 --- a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml @@ -42,6 +42,7 @@ description: | For PM7325, smps1 - smps8, ldo1 - ldo19 For PM8005, smps1 - smps4 For PM8009, smps1 - smps2, ldo1 - ldo7 + For PM8010, ldo1 - ldo7 For PM8150, smps1 - smps10, ldo1 - ldo18 For PM8150L, smps1 - smps8, ldo1 - ldo11, bob, flash, rgb For PM8350, smps1 - smps12, ldo1 - ldo10 @@ -68,6 +69,7 @@ properties: - qcom,pm8005-rpmh-regulators - qcom,pm8009-rpmh-regulators - qcom,pm8009-1-rpmh-regulators + - qcom,pm8010-rpmh-regulators - qcom,pm8150-rpmh-regulators - qcom,pm8150l-rpmh-regulators - qcom,pm8350-rpmh-regulators @@ -238,6 +240,18 @@ allOf: "^vdd-l[1-47]-supply$": true "^vdd-s[1-2]-supply$": true + - if: + properties: + compatible: + enum: + - qcom,pm8010-rpmh-regulators + then: + properties: + vdd-l1-l2-supply: true + vdd-l3-l4-supply: true + patternProperties: + "^vdd-l[5-7]-supply$": true + - if: properties: compatible: diff --git a/Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.yaml b/Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.yaml index 9ea8ac0786acce..f2fd2df68a9ed9 100644 --- a/Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.yaml @@ -47,6 +47,9 @@ description: For pm8916, s1, s2, s3, s4, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18 + For pm8937, s1, s2, s3, s4, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, + l11, l12, l13, l14, l15, l16, l17, l18, l19, l20, l21, l22, l23 + For pm8941, s1, s2, s3, s4, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12, l13, l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, lvs1, lvs2, lvs3, 5vs1, 5vs2 @@ -92,6 +95,7 @@ properties: - qcom,rpm-pm8841-regulators - qcom,rpm-pm8909-regulators - qcom,rpm-pm8916-regulators + - qcom,rpm-pm8937-regulators - qcom,rpm-pm8941-regulators - qcom,rpm-pm8950-regulators - qcom,rpm-pm8953-regulators diff --git a/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.yaml b/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.yaml index 7a1b7d2abbd454..aea849e8eadf12 100644 --- a/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.yaml @@ -22,6 +22,7 @@ properties: - qcom,pm8841-regulators - qcom,pm8909-regulators - qcom,pm8916-regulators + - qcom,pm8937-regulators - qcom,pm8941-regulators - qcom,pm8950-regulators - qcom,pm8994-regulators @@ -291,6 +292,24 @@ allOf: patternProperties: "^vdd_s[1-3]-supply$": true + - if: + properties: + compatible: + contains: + enum: + - qcom,pm8937-regulators + then: + properties: + vdd_l1_l19-supply: true + vdd_l20_l21-supply: true + vdd_l2_l23-supply: true + vdd_l3-supply: true + vdd_l4_l5_l6_l7_l16-supply: true + vdd_l8_l11_l12_l17_l22-supply: true + vdd_l9_l10_l13_l14_l15_l18-supply: true + patternProperties: + "^vdd_s[1-6]-supply$": true + - if: properties: compatible: diff --git a/Documentation/devicetree/bindings/regulator/qcom,usb-vbus-regulator.yaml b/Documentation/devicetree/bindings/regulator/qcom,usb-vbus-regulator.yaml index 89c564dfa5db5a..534f87e9871630 100644 --- a/Documentation/devicetree/bindings/regulator/qcom,usb-vbus-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/qcom,usb-vbus-regulator.yaml @@ -36,10 +36,11 @@ unevaluatedProperties: false examples: - | - pm8150b { + pmic { #address-cells = <1>; #size-cells = <0>; - pm8150b_vbus: usb-vbus-regulator@1100 { + + usb-vbus-regulator@1100 { compatible = "qcom,pm8150b-vbus-reg"; reg = <0x1100>; regulator-min-microamp = <500000>; diff --git a/Documentation/devicetree/bindings/regulator/regulator.yaml b/Documentation/devicetree/bindings/regulator/regulator.yaml index 9daf0fc2465ff2..1ef380d1515ec7 100644 --- a/Documentation/devicetree/bindings/regulator/regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/regulator.yaml @@ -114,6 +114,11 @@ properties: description: Enable pull down resistor when the regulator is disabled. type: boolean + system-critical-regulator: + description: Set if the regulator is critical to system stability or + functionality. + type: boolean + regulator-over-current-protection: description: Enable over current protection. type: boolean @@ -181,6 +186,14 @@ properties: be enabled but limit setting can be omitted. Limit is given as microvolt offset from voltage set to regulator. + regulator-uv-less-critical-window-ms: + description: Specifies the time window (in milliseconds) following a + critical under-voltage event during which the system can continue to + operate safely while performing less critical operations. This property + provides a defined duration before a more severe reaction to the + under-voltage event is needed, allowing for certain non-urgent actions to + be carried out in preparation for potential power loss. + regulator-temp-protection-kelvin: description: Set over temperature protection limit. This is a limit where hardware performs emergency shutdown. Zero can be passed to disable diff --git a/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml b/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml index 30632efdad8bb2..df36e29d974ca0 100644 --- a/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml +++ b/Documentation/devicetree/bindings/remoteproc/fsl,imx-rproc.yaml @@ -113,10 +113,10 @@ examples: }; imx7d-cm4 { - compatible = "fsl,imx7d-cm4"; - memory-region = <&m4_reserved_sysmem1>, <&m4_reserved_sysmem2>; - syscon = <&src>; - clocks = <&clks IMX7D_ARM_M4_ROOT_CLK>; + compatible = "fsl,imx7d-cm4"; + memory-region = <&m4_reserved_sysmem1>, <&m4_reserved_sysmem2>; + syscon = <&src>; + clocks = <&clks IMX7D_ARM_M4_ROOT_CLK>; }; - | diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,sc7180-pas.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,sc7180-pas.yaml index f10f329677d84d..c054b84fdcd5c5 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,sc7180-pas.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,sc7180-pas.yaml @@ -18,7 +18,10 @@ properties: enum: - qcom,sc7180-adsp-pas - qcom,sc7180-mpss-pas + - qcom,sc7280-adsp-pas + - qcom,sc7280-cdsp-pas - qcom,sc7280-mpss-pas + - qcom,sc7280-wpss-pas reg: maxItems: 1 @@ -75,6 +78,7 @@ allOf: compatible: enum: - qcom,sc7180-adsp-pas + - qcom,sc7280-adsp-pas then: properties: power-domains: @@ -109,6 +113,23 @@ allOf: compatible: enum: - qcom,sc7280-mpss-pas + then: + properties: + power-domains: + items: + - description: CX power domain + - description: MSS power domain + power-domain-names: + items: + - const: cx + - const: mss + + - if: + properties: + compatible: + enum: + - qcom,sc7280-cdsp-pas + - qcom,sc7280-wpss-pas then: properties: power-domains: diff --git a/Documentation/devicetree/bindings/reset/amlogic,meson-reset.yaml b/Documentation/devicetree/bindings/reset/amlogic,meson-reset.yaml index d3fdee89d4f845..f0c6c0df0ce3f3 100644 --- a/Documentation/devicetree/bindings/reset/amlogic,meson-reset.yaml +++ b/Documentation/devicetree/bindings/reset/amlogic,meson-reset.yaml @@ -18,6 +18,7 @@ properties: - amlogic,meson-axg-reset # Reset Controller on AXG and compatible SoCs - amlogic,meson-a1-reset # Reset Controller on A1 and compatible SoCs - amlogic,meson-s4-reset # Reset Controller on S4 and compatible SoCs + - amlogic,c3-reset # Reset Controller on C3 and compatible SoCs reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/reset/fsl,imx-src.yaml b/Documentation/devicetree/bindings/reset/fsl,imx-src.yaml index b11ac533f914ca..f5ec1d54aa5122 100644 --- a/Documentation/devicetree/bindings/reset/fsl,imx-src.yaml +++ b/Documentation/devicetree/bindings/reset/fsl,imx-src.yaml @@ -28,28 +28,17 @@ description: | properties: compatible: oneOf: - - const: "fsl,imx51-src" + - const: fsl,imx51-src - items: - - const: "fsl,imx50-src" - - const: "fsl,imx51-src" - - items: - - const: "fsl,imx53-src" - - const: "fsl,imx51-src" - - items: - - const: "fsl,imx6q-src" - - const: "fsl,imx51-src" - - items: - - const: "fsl,imx6sx-src" - - const: "fsl,imx51-src" - - items: - - const: "fsl,imx6sl-src" - - const: "fsl,imx51-src" - - items: - - const: "fsl,imx6ul-src" - - const: "fsl,imx51-src" - - items: - - const: "fsl,imx6sll-src" - - const: "fsl,imx51-src" + - enum: + - fsl,imx50-src + - fsl,imx53-src + - fsl,imx6q-src + - fsl,imx6sx-src + - fsl,imx6sl-src + - fsl,imx6ul-src + - fsl,imx6sll-src + - const: fsl,imx51-src reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/reset/hisilicon,hi3660-reset.yaml b/Documentation/devicetree/bindings/reset/hisilicon,hi3660-reset.yaml index cdfcf32c53fa93..e4de002d690320 100644 --- a/Documentation/devicetree/bindings/reset/hisilicon,hi3660-reset.yaml +++ b/Documentation/devicetree/bindings/reset/hisilicon,hi3660-reset.yaml @@ -50,32 +50,9 @@ additionalProperties: false examples: - | - #include - #include - #include - - iomcu: iomcu@ffd7e000 { - compatible = "hisilicon,hi3660-iomcu", "syscon"; - reg = <0xffd7e000 0x1000>; - }; - - iomcu_rst: iomcu_rst_controller { + iomcu_rst_controller { compatible = "hisilicon,hi3660-reset"; hisilicon,rst-syscon = <&iomcu>; #reset-cells = <2>; }; - - /* Specifying reset lines connected to IP modules */ - i2c@ffd71000 { - compatible = "snps,designware-i2c"; - reg = <0xffd71000 0x1000>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - clock-frequency = <400000>; - clocks = <&crg_ctrl HI3660_CLK_GATE_I2C0>; - resets = <&iomcu_rst 0x20 3>; - pinctrl-names = "default"; - pinctrl-0 = <&i2c0_pmx_func &i2c0_cfg_func>; - }; ... diff --git a/Documentation/devicetree/bindings/reset/qcom,aoss-reset.yaml b/Documentation/devicetree/bindings/reset/qcom,aoss-reset.yaml index d92e2b3cc83f9c..24beb712b56d8b 100644 --- a/Documentation/devicetree/bindings/reset/qcom,aoss-reset.yaml +++ b/Documentation/devicetree/bindings/reset/qcom,aoss-reset.yaml @@ -18,17 +18,17 @@ properties: oneOf: - description: on SC7180 SoCs the following compatibles must be specified items: - - const: "qcom,sc7180-aoss-cc" - - const: "qcom,sdm845-aoss-cc" + - const: qcom,sc7180-aoss-cc + - const: qcom,sdm845-aoss-cc - description: on SC7280 SoCs the following compatibles must be specified items: - - const: "qcom,sc7280-aoss-cc" - - const: "qcom,sdm845-aoss-cc" + - const: qcom,sc7280-aoss-cc + - const: qcom,sdm845-aoss-cc - description: on SDM845 SoCs the following compatibles must be specified items: - - const: "qcom,sdm845-aoss-cc" + - const: qcom,sdm845-aoss-cc reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/reset/qcom,pdc-global.yaml b/Documentation/devicetree/bindings/reset/qcom,pdc-global.yaml index ca5d79332189bc..f514363aa47493 100644 --- a/Documentation/devicetree/bindings/reset/qcom,pdc-global.yaml +++ b/Documentation/devicetree/bindings/reset/qcom,pdc-global.yaml @@ -18,16 +18,16 @@ properties: oneOf: - description: on SC7180 SoCs the following compatibles must be specified items: - - const: "qcom,sc7180-pdc-global" - - const: "qcom,sdm845-pdc-global" + - const: qcom,sc7180-pdc-global + - const: qcom,sdm845-pdc-global - description: on SC7280 SoCs the following compatibles must be specified items: - - const: "qcom,sc7280-pdc-global" + - const: qcom,sc7280-pdc-global - description: on SDM845 SoCs the following compatibles must be specified items: - - const: "qcom,sdm845-pdc-global" + - const: qcom,sdm845-pdc-global reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/reset/renesas,rzg2l-usbphy-ctrl.yaml b/Documentation/devicetree/bindings/reset/renesas,rzg2l-usbphy-ctrl.yaml index 731b8ce01525c2..03c18611e42d19 100644 --- a/Documentation/devicetree/bindings/reset/renesas,rzg2l-usbphy-ctrl.yaml +++ b/Documentation/devicetree/bindings/reset/renesas,rzg2l-usbphy-ctrl.yaml @@ -17,7 +17,7 @@ properties: compatible: items: - enum: - - renesas,r9a07g043-usbphy-ctrl # RZ/G2UL + - renesas,r9a07g043-usbphy-ctrl # RZ/G2UL and RZ/Five - renesas,r9a07g044-usbphy-ctrl # RZ/G2{L,LC} - renesas,r9a07g054-usbphy-ctrl # RZ/V2L - const: renesas,rzg2l-usbphy-ctrl diff --git a/Documentation/devicetree/bindings/riscv/cpus.yaml b/Documentation/devicetree/bindings/riscv/cpus.yaml index f392e367d673f5..9d8670c00e3b3b 100644 --- a/Documentation/devicetree/bindings/riscv/cpus.yaml +++ b/Documentation/devicetree/bindings/riscv/cpus.yaml @@ -32,6 +32,7 @@ properties: oneOf: - items: - enum: + - amd,mbv32 - andestech,ax45mp - canaan,k210 - sifive,bullet0 @@ -62,8 +63,8 @@ properties: mmu-type: description: - Identifies the MMU address translation mode used on this - hart. These values originate from the RISC-V Privileged + Identifies the largest MMU address translation mode supported by + this hart. These values originate from the RISC-V Privileged Specification document, available from https://riscv.org/specifications/ $ref: /schemas/types.yaml#/definitions/string @@ -79,6 +80,11 @@ properties: description: The blocksize in bytes for the Zicbom cache operations. + riscv,cbop-block-size: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + The blocksize in bytes for the Zicbop cache operations. + riscv,cboz-block-size: $ref: /schemas/types.yaml#/definitions/uint32 description: diff --git a/Documentation/devicetree/bindings/riscv/extensions.yaml b/Documentation/devicetree/bindings/riscv/extensions.yaml index c91ab0e4664820..63d81dc895e5ce 100644 --- a/Documentation/devicetree/bindings/riscv/extensions.yaml +++ b/Documentation/devicetree/bindings/riscv/extensions.yaml @@ -48,7 +48,7 @@ properties: insensitive, letters in the riscv,isa string must be all lowercase. $ref: /schemas/types.yaml#/definitions/string - pattern: ^rv(?:64|32)imaf?d?q?c?b?k?j?p?v?h?(?:[hsxz](?:[a-z])+)?(?:_[hsxz](?:[a-z])+)*$ + pattern: ^rv(?:64|32)imaf?d?q?c?b?k?j?p?v?h?(?:[hsxz](?:[0-9a-z])+)?(?:_[hsxz](?:[0-9a-z])+)*$ deprecated: true riscv,isa-base: @@ -171,6 +171,12 @@ properties: memory types as ratified in the 20191213 version of the privileged ISA specification. + - const: zacas + description: | + The Zacas extension for Atomic Compare-and-Swap (CAS) instructions + is supported as ratified at commit 5059e0ca641c ("update to + ratified") of the riscv-zacas. + - const: zba description: | The standard Zba bit-manipulation extension for address generation @@ -190,12 +196,111 @@ properties: multiplication as ratified at commit 6d33919 ("Merge pull request #158 from hirooih/clmul-fix-loop-end-condition") of riscv-bitmanip. + - const: zbkb + description: + The standard Zbkb bitmanip instructions for cryptography as ratified + in version 1.0 of RISC-V Cryptography Extensions Volume I + specification. + + - const: zbkc + description: + The standard Zbkc carry-less multiply instructions as ratified + in version 1.0 of RISC-V Cryptography Extensions Volume I + specification. + + - const: zbkx + description: + The standard Zbkx crossbar permutation instructions as ratified + in version 1.0 of RISC-V Cryptography Extensions Volume I + specification. + - const: zbs description: | The standard Zbs bit-manipulation extension for single-bit instructions as ratified at commit 6d33919 ("Merge pull request #158 from hirooih/clmul-fix-loop-end-condition") of riscv-bitmanip. + - const: zfa + description: + The standard Zfa extension for additional floating point + instructions, as ratified in commit 056b6ff ("Zfa is ratified") of + riscv-isa-manual. + + - const: zfh + description: + The standard Zfh extension for 16-bit half-precision binary + floating-point instructions, as ratified in commit 64074bc ("Update + version numbers for Zfh/Zfinx") of riscv-isa-manual. + + - const: zfhmin + description: + The standard Zfhmin extension which provides minimal support for + 16-bit half-precision binary floating-point instructions, as ratified + in commit 64074bc ("Update version numbers for Zfh/Zfinx") of + riscv-isa-manual. + + - const: zk + description: + The standard Zk Standard Scalar cryptography extension as ratified + in version 1.0 of RISC-V Cryptography Extensions Volume I + specification. + + - const: zkn + description: + The standard Zkn NIST algorithm suite extensions as ratified in + version 1.0 of RISC-V Cryptography Extensions Volume I + specification. + + - const: zknd + description: | + The standard Zknd for NIST suite: AES decryption instructions as + ratified in version 1.0 of RISC-V Cryptography Extensions Volume I + specification. + + - const: zkne + description: | + The standard Zkne for NIST suite: AES encryption instructions as + ratified in version 1.0 of RISC-V Cryptography Extensions Volume I + specification. + + - const: zknh + description: | + The standard Zknh for NIST suite: hash function instructions as + ratified in version 1.0 of RISC-V Cryptography Extensions Volume I + specification. + + - const: zkr + description: + The standard Zkr entropy source extension as ratified in version + 1.0 of RISC-V Cryptography Extensions Volume I specification. + This string being present means that the CSR associated to this + extension is accessible at the privilege level to which that + device-tree has been provided. + + - const: zks + description: + The standard Zks ShangMi algorithm suite extensions as ratified in + version 1.0 of RISC-V Cryptography Extensions Volume I + specification. + + - const: zksed + description: | + The standard Zksed for ShangMi suite: SM4 block cipher instructions + as ratified in version 1.0 of RISC-V Cryptography Extensions + Volume I specification. + + - const: zksh + description: | + The standard Zksh for ShangMi suite: SM3 hash function instructions + as ratified in version 1.0 of RISC-V Cryptography Extensions + Volume I specification. + + - const: zkt + description: + The standard Zkt for data independent execution latency as ratified + in version 1.0 of RISC-V Cryptography Extensions Volume I + specification. + - const: zicbom description: The standard Zicbom extension for base cache management operations as @@ -246,6 +351,12 @@ properties: The standard Zihintpause extension for pause hints, as ratified in commit d8ab5c7 ("Zihintpause is ratified") of the riscv-isa-manual. + - const: zihintntl + description: + The standard Zihintntl extension for non-temporal locality hints, as + ratified in commit 0dc91f5 ("Zihintntl is ratified") of the + riscv-isa-manual. + - const: zihpm description: The standard Zihpm extension for hardware performance counters, as @@ -258,5 +369,113 @@ properties: in commit 2e5236 ("Ztso is now ratified.") of the riscv-isa-manual. + - const: zvbb + description: + The standard Zvbb extension for vectored basic bit-manipulation + instructions, as ratified in commit 56ed795 ("Update + riscv-crypto-spec-vector.adoc") of riscv-crypto. + + - const: zvbc + description: + The standard Zvbc extension for vectored carryless multiplication + instructions, as ratified in commit 56ed795 ("Update + riscv-crypto-spec-vector.adoc") of riscv-crypto. + + - const: zvfh + description: + The standard Zvfh extension for vectored half-precision + floating-point instructions, as ratified in commit e2ccd05 + ("Remove draft warnings from Zvfh[min]") of riscv-v-spec. + + - const: zvfhmin + description: + The standard Zvfhmin extension for vectored minimal half-precision + floating-point instructions, as ratified in commit e2ccd05 + ("Remove draft warnings from Zvfh[min]") of riscv-v-spec. + + - const: zvkb + description: + The standard Zvkb extension for vector cryptography bit-manipulation + instructions, as ratified in commit 56ed795 ("Update + riscv-crypto-spec-vector.adoc") of riscv-crypto. + + - const: zvkg + description: + The standard Zvkg extension for vector GCM/GMAC instructions, as + ratified in commit 56ed795 ("Update riscv-crypto-spec-vector.adoc") + of riscv-crypto. + + - const: zvkn + description: + The standard Zvkn extension for NIST algorithm suite instructions, as + ratified in commit 56ed795 ("Update riscv-crypto-spec-vector.adoc") + of riscv-crypto. + + - const: zvknc + description: + The standard Zvknc extension for NIST algorithm suite with carryless + multiply instructions, as ratified in commit 56ed795 ("Update + riscv-crypto-spec-vector.adoc") of riscv-crypto. + + - const: zvkned + description: + The standard Zvkned extension for Vector AES block cipher + instructions, as ratified in commit 56ed795 ("Update + riscv-crypto-spec-vector.adoc") of riscv-crypto. + + - const: zvkng + description: + The standard Zvkng extension for NIST algorithm suite with GCM + instructions, as ratified in commit 56ed795 ("Update + riscv-crypto-spec-vector.adoc") of riscv-crypto. + + - const: zvknha + description: | + The standard Zvknha extension for NIST suite: vector SHA-2 secure, + hash (SHA-256 only) instructions, as ratified in commit + 56ed795 ("Update riscv-crypto-spec-vector.adoc") of riscv-crypto. + + - const: zvknhb + description: | + The standard Zvknhb extension for NIST suite: vector SHA-2 secure, + hash (SHA-256 and SHA-512) instructions, as ratified in commit + 56ed795 ("Update riscv-crypto-spec-vector.adoc") of riscv-crypto. + + - const: zvks + description: + The standard Zvks extension for ShangMi algorithm suite + instructions, as ratified in commit 56ed795 ("Update + riscv-crypto-spec-vector.adoc") of riscv-crypto. + + - const: zvksc + description: + The standard Zvksc extension for ShangMi algorithm suite with + carryless multiplication instructions, as ratified in commit 56ed795 + ("Update riscv-crypto-spec-vector.adoc") of riscv-crypto. + + - const: zvksed + description: | + The standard Zvksed extension for ShangMi suite: SM4 block cipher + instructions, as ratified in commit 56ed795 ("Update + riscv-crypto-spec-vector.adoc") of riscv-crypto. + + - const: zvksh + description: | + The standard Zvksh extension for ShangMi suite: SM3 secure hash + instructions, as ratified in commit 56ed795 ("Update + riscv-crypto-spec-vector.adoc") of riscv-crypto. + + - const: zvksg + description: + The standard Zvksg extension for ShangMi algorithm suite with GCM + instructions, as ratified in commit 56ed795 ("Update + riscv-crypto-spec-vector.adoc") of riscv-crypto. + + - const: zvkt + description: + The standard Zvkt extension for vector data-independent execution + latency, as ratified in commit 56ed795 ("Update + riscv-crypto-spec-vector.adoc") of riscv-crypto. + additionalProperties: true ... diff --git a/Documentation/devicetree/bindings/riscv/sophgo.yaml b/Documentation/devicetree/bindings/riscv/sophgo.yaml index 86748c5390bea6..9bc813dad0987a 100644 --- a/Documentation/devicetree/bindings/riscv/sophgo.yaml +++ b/Documentation/devicetree/bindings/riscv/sophgo.yaml @@ -22,6 +22,10 @@ properties: - enum: - milkv,duo - const: sophgo,cv1800b + - items: + - enum: + - sophgo,huashan-pi + - const: sophgo,cv1812h - items: - enum: - milkv,pioneer diff --git a/Documentation/devicetree/bindings/rng/starfive,jh7110-trng.yaml b/Documentation/devicetree/bindings/rng/starfive,jh7110-trng.yaml index 2b76ce25acc4aa..4639247e9e510d 100644 --- a/Documentation/devicetree/bindings/rng/starfive,jh7110-trng.yaml +++ b/Documentation/devicetree/bindings/rng/starfive,jh7110-trng.yaml @@ -11,7 +11,11 @@ maintainers: properties: compatible: - const: starfive,jh7110-trng + oneOf: + - items: + - const: starfive,jh8100-trng + - const: starfive,jh7110-trng + - const: starfive,jh7110-trng reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/rtc/adi,max31335.yaml b/Documentation/devicetree/bindings/rtc/adi,max31335.yaml new file mode 100644 index 00000000000000..0125cf6727cc3d --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/adi,max31335.yaml @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/rtc/adi,max31335.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices MAX31335 RTC + +maintainers: + - Antoniu Miclaus + +description: + Analog Devices MAX31335 I2C RTC ±2ppm Automotive Real-Time Clock with + Integrated MEMS Resonator. + +allOf: + - $ref: rtc.yaml# + +properties: + compatible: + const: adi,max31335 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + "#clock-cells": + description: + RTC can be used as a clock source through its clock output pin. + const: 0 + + adi,tc-diode: + description: + Select the diode configuration for the trickle charger. + schottky - Schottky diode in series. + standard+schottky - standard diode + Schottky diode in series. + enum: [schottky, standard+schottky] + + trickle-resistor-ohms: + description: + Selected resistor for trickle charger. Should be specified if trickle + charger should be enabled. + enum: [3000, 6000, 11000] + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + rtc@68 { + compatible = "adi,max31335"; + reg = <0x68>; + pinctrl-0 = <&rtc_nint_pins>; + interrupts-extended = <&gpio1 16 IRQ_TYPE_LEVEL_HIGH>; + aux-voltage-chargeable = <1>; + trickle-resistor-ohms = <6000>; + adi,tc-diode = "schottky"; + }; + }; +... diff --git a/Documentation/devicetree/bindings/rtc/epson,rx8900.yaml b/Documentation/devicetree/bindings/rtc/epson,rx8900.yaml index 1df7c45d95c18e..b770149c5fd677 100644 --- a/Documentation/devicetree/bindings/rtc/epson,rx8900.yaml +++ b/Documentation/devicetree/bindings/rtc/epson,rx8900.yaml @@ -29,6 +29,8 @@ properties: trickle-diode-disable: true + wakeup-source: true + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/rtc/nuvoton,ma35d1-rtc.yaml b/Documentation/devicetree/bindings/rtc/nuvoton,ma35d1-rtc.yaml new file mode 100644 index 00000000000000..5e4ade803eed1e --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/nuvoton,ma35d1-rtc.yaml @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/rtc/nuvoton,ma35d1-rtc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Nuvoton MA35D1 Real Time Clock + +maintainers: + - Min-Jen Chen + +allOf: + - $ref: rtc.yaml# + +properties: + compatible: + enum: + - nuvoton,ma35d1-rtc + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks + +unevaluatedProperties: false + +examples: + - | + #include + #include + rtc@40410000 { + compatible = "nuvoton,ma35d1-rtc"; + reg = <0x40410000 0x200>; + interrupts = ; + clocks = <&clk RTC_GATE>; + }; + +... diff --git a/Documentation/devicetree/bindings/rtc/qcom-pm8xxx-rtc.yaml b/Documentation/devicetree/bindings/rtc/qcom-pm8xxx-rtc.yaml index b95a69cc9ae0fe..d274bb7a534b55 100644 --- a/Documentation/devicetree/bindings/rtc/qcom-pm8xxx-rtc.yaml +++ b/Documentation/devicetree/bindings/rtc/qcom-pm8xxx-rtc.yaml @@ -61,27 +61,27 @@ additionalProperties: false examples: - | + #include #include - spmi_bus: spmi@c440000 { - reg = <0x0c440000 0x1100>; - #address-cells = <2>; - #size-cells = <0>; - pmicintc: pmic@0 { - reg = <0x0 SPMI_USID>; - compatible = "qcom,pm8921"; - interrupts = <104 8>; - #interrupt-cells = <2>; - interrupt-controller; - #address-cells = <1>; + + spmi { + #address-cells = <2>; #size-cells = <0>; - pm8921_rtc: rtc@11d { - compatible = "qcom,pm8921-rtc"; - reg = <0x11d>; - interrupts = <0x27 0>; - nvmem-cells = <&rtc_offset>; - nvmem-cell-names = "offset"; + pmic@0 { + compatible = "qcom,pm8941", "qcom,spmi-pmic"; + reg = <0x0 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + rtc@6000 { + compatible = "qcom,pm8941-rtc"; + reg = <0x6000>, <0x6100>; + reg-names = "rtc", "alarm"; + interrupts = <0x0 0x61 0x1 IRQ_TYPE_EDGE_RISING>; + nvmem-cells = <&rtc_offset>; + nvmem-cell-names = "offset"; + }; }; - }; }; ... diff --git a/Documentation/devicetree/bindings/rtc/s3c-rtc.yaml b/Documentation/devicetree/bindings/rtc/s3c-rtc.yaml index d51b236939bf36..bf4e11d6dffbb7 100644 --- a/Documentation/devicetree/bindings/rtc/s3c-rtc.yaml +++ b/Documentation/devicetree/bindings/rtc/s3c-rtc.yaml @@ -17,6 +17,11 @@ properties: - samsung,s3c2416-rtc - samsung,s3c2443-rtc - samsung,s3c6410-rtc + - items: + - enum: + - samsung,exynos7-rtc + - samsung,exynos850-rtc + - const: samsung,s3c6410-rtc - const: samsung,exynos3250-rtc deprecated: true diff --git a/Documentation/devicetree/bindings/security/tpm/google,cr50.txt b/Documentation/devicetree/bindings/security/tpm/google,cr50.txt deleted file mode 100644 index cd69c2efdd3716..00000000000000 --- a/Documentation/devicetree/bindings/security/tpm/google,cr50.txt +++ /dev/null @@ -1,19 +0,0 @@ -* H1 Secure Microcontroller with Cr50 Firmware on SPI Bus. - -H1 Secure Microcontroller running Cr50 firmware provides several -functions, including TPM-like functionality. It communicates over -SPI using the FIFO protocol described in the PTP Spec, section 6. - -Required properties: -- compatible: Should be "google,cr50". -- spi-max-frequency: Maximum SPI frequency. - -Example: - -&spi0 { - tpm@0 { - compatible = "google,cr50"; - reg = <0>; - spi-max-frequency = <800000>; - }; -}; diff --git a/Documentation/devicetree/bindings/security/tpm/ibmvtpm.txt b/Documentation/devicetree/bindings/security/tpm/ibmvtpm.txt deleted file mode 100644 index d89f99971368c3..00000000000000 --- a/Documentation/devicetree/bindings/security/tpm/ibmvtpm.txt +++ /dev/null @@ -1,41 +0,0 @@ -* Device Tree Bindings for IBM Virtual Trusted Platform Module(vtpm) - -Required properties: - -- compatible : property name that conveys the platform architecture - identifiers, as 'IBM,vtpm' -- device_type : specifies type of virtual device -- interrupts : property specifying the interrupt source number and - sense code associated with this virtual I/O Adapters -- ibm,my-drc-index : integer index for the connector between the device - and its parent - present only if Dynamic - Reconfiguration(DR) Connector is enabled -- ibm,#dma-address-cells: specifies the number of cells that are used to - encode the physical address field of dma-window - properties -- ibm,#dma-size-cells : specifies the number of cells that are used to - encode the size field of dma-window properties -- ibm,my-dma-window : specifies DMA window associated with this virtual - IOA -- ibm,loc-code : specifies the unique and persistent location code - associated with this virtual I/O Adapters -- linux,sml-base : 64-bit base address of the reserved memory allocated - for the firmware event log -- linux,sml-size : size of the memory allocated for the firmware event log - -Example (IBM Virtual Trusted Platform Module) ---------------------------------------------- - - vtpm@30000003 { - ibm,#dma-size-cells = <0x2>; - compatible = "IBM,vtpm"; - device_type = "IBM,vtpm"; - ibm,my-drc-index = <0x30000003>; - ibm,#dma-address-cells = <0x2>; - linux,sml-base = <0xc60e 0x0>; - interrupts = <0xa0003 0x0>; - ibm,my-dma-window = <0x10000003 0x0 0x0 0x0 0x10000000>; - ibm,loc-code = "U8286.41A.10082DV-V3-C3"; - reg = <0x30000003>; - linux,sml-size = <0xbce10200>; - }; diff --git a/Documentation/devicetree/bindings/security/tpm/st33zp24-i2c.txt b/Documentation/devicetree/bindings/security/tpm/st33zp24-i2c.txt deleted file mode 100644 index 0dc121b6eace9a..00000000000000 --- a/Documentation/devicetree/bindings/security/tpm/st33zp24-i2c.txt +++ /dev/null @@ -1,34 +0,0 @@ -* STMicroelectronics SAS. ST33ZP24 TPM SoC - -Required properties: -- compatible: Should be "st,st33zp24-i2c". -- clock-frequency: I²C work frequency. -- reg: address on the bus - -Optional ST33ZP24 Properties: -- interrupts: GPIO interrupt to which the chip is connected -- lpcpd-gpios: Output GPIO pin used for ST33ZP24 power management D1/D2 state. -If set, power must be present when the platform is going into sleep/hibernate mode. - -Optional SoC Specific Properties: -- pinctrl-names: Contains only one value - "default". -- pintctrl-0: Specifies the pin control groups used for this controller. - -Example (for ARM-based BeagleBoard xM with ST33ZP24 on I2C2): - -&i2c2 { - - - st33zp24: st33zp24@13 { - - compatible = "st,st33zp24-i2c"; - - reg = <0x13>; - clock-frequency = <400000>; - - interrupt-parent = <&gpio5>; - interrupts = <7 IRQ_TYPE_LEVEL_HIGH>; - - lpcpd-gpios = <&gpio5 15 GPIO_ACTIVE_HIGH>; - }; -}; diff --git a/Documentation/devicetree/bindings/security/tpm/st33zp24-spi.txt b/Documentation/devicetree/bindings/security/tpm/st33zp24-spi.txt deleted file mode 100644 index 37198971f17b64..00000000000000 --- a/Documentation/devicetree/bindings/security/tpm/st33zp24-spi.txt +++ /dev/null @@ -1,32 +0,0 @@ -* STMicroelectronics SAS. ST33ZP24 TPM SoC - -Required properties: -- compatible: Should be "st,st33zp24-spi". -- spi-max-frequency: Maximum SPI frequency (<= 10000000). - -Optional ST33ZP24 Properties: -- interrupts: GPIO interrupt to which the chip is connected -- lpcpd-gpios: Output GPIO pin used for ST33ZP24 power management D1/D2 state. -If set, power must be present when the platform is going into sleep/hibernate mode. - -Optional SoC Specific Properties: -- pinctrl-names: Contains only one value - "default". -- pintctrl-0: Specifies the pin control groups used for this controller. - -Example (for ARM-based BeagleBoard xM with ST33ZP24 on SPI4): - -&mcspi4 { - - - st33zp24@0 { - - compatible = "st,st33zp24-spi"; - - spi-max-frequency = <10000000>; - - interrupt-parent = <&gpio5>; - interrupts = <7 IRQ_TYPE_LEVEL_HIGH>; - - lpcpd-gpios = <&gpio5 15 GPIO_ACTIVE_HIGH>; - }; -}; diff --git a/Documentation/devicetree/bindings/security/tpm/tpm-i2c.txt b/Documentation/devicetree/bindings/security/tpm/tpm-i2c.txt deleted file mode 100644 index a65d7b71e81a2a..00000000000000 --- a/Documentation/devicetree/bindings/security/tpm/tpm-i2c.txt +++ /dev/null @@ -1,26 +0,0 @@ -* Device Tree Bindings for I2C based Trusted Platform Module(TPM) - -Required properties: - -- compatible : 'manufacturer,model', eg. nuvoton,npct650 -- label : human readable string describing the device, eg. "tpm" -- linux,sml-base : 64-bit base address of the reserved memory allocated for - the firmware event log -- linux,sml-size : size of the memory allocated for the firmware event log - -Optional properties: - -- powered-while-suspended: present when the TPM is left powered on between - suspend and resume (makes the suspend/resume - callbacks do nothing). - -Example (for OpenPower Systems with Nuvoton TPM 2.0 on I2C) ----------------------------------------------------------- - -tpm@57 { - reg = <0x57>; - label = "tpm"; - compatible = "nuvoton,npct650", "nuvoton,npct601"; - linux,sml-base = <0x7f 0xfd450000>; - linux,sml-size = <0x10000>; -}; diff --git a/Documentation/devicetree/bindings/security/tpm/tpm_tis_mmio.txt b/Documentation/devicetree/bindings/security/tpm/tpm_tis_mmio.txt deleted file mode 100644 index 7c6304426da1a5..00000000000000 --- a/Documentation/devicetree/bindings/security/tpm/tpm_tis_mmio.txt +++ /dev/null @@ -1,25 +0,0 @@ -Trusted Computing Group MMIO Trusted Platform Module - -The TCG defines multi vendor standard for accessing a TPM chip, this -is the standard protocol defined to access the TPM via MMIO. Typically -this interface will be implemented over Intel's LPC bus. - -Refer to the 'TCG PC Client Specific TPM Interface Specification (TIS)' TCG -publication for the specification. - -Required properties: - -- compatible: should contain a string below for the chip, followed by - "tcg,tpm-tis-mmio". Valid chip strings are: - * "atmel,at97sc3204" -- reg: The location of the MMIO registers, should be at least 0x5000 bytes -- interrupts: An optional interrupt indicating command completion. - -Example: - - tpm_tis@90000 { - compatible = "atmel,at97sc3204", "tcg,tpm-tis-mmio"; - reg = <0x90000 0x5000>; - interrupt-parent = <&EIC0>; - interrupts = <1 2>; - }; diff --git a/Documentation/devicetree/bindings/security/tpm/tpm_tis_spi.txt b/Documentation/devicetree/bindings/security/tpm/tpm_tis_spi.txt deleted file mode 100644 index b800667da92b82..00000000000000 --- a/Documentation/devicetree/bindings/security/tpm/tpm_tis_spi.txt +++ /dev/null @@ -1,23 +0,0 @@ -Required properties: -- compatible: should be one of the following - "st,st33htpm-spi" - "infineon,slb9670" - "tcg,tpm_tis-spi" -- spi-max-frequency: Maximum SPI frequency (depends on TPMs). - -Optional SoC Specific Properties: -- pinctrl-names: Contains only one value - "default". -- pintctrl-0: Specifies the pin control groups used for this controller. - -Example (for ARM-based BeagleBoard xM with TPM_TIS on SPI4): - -&mcspi4 { - - - tpm_tis@0 { - - compatible = "tcg,tpm_tis-spi"; - - spi-max-frequency = <10000000>; - }; -}; diff --git a/Documentation/devicetree/bindings/serial/arm,dcc.yaml b/Documentation/devicetree/bindings/serial/arm,dcc.yaml new file mode 100644 index 00000000000000..fd0589356617ae --- /dev/null +++ b/Documentation/devicetree/bindings/serial/arm,dcc.yaml @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/serial/arm,dcc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ARM DCC (Data communication channel) serial emulation + +maintainers: + - Michal Simek + +description: | + ARM DCC (Data communication channel) serial emulation interface available + via JTAG can be also used as one of serial line tightly coupled with every + ARM CPU available in the system. + +properties: + compatible: + const: arm,dcc + +required: + - compatible + +additionalProperties: false + +examples: + - | + serial { + compatible = "arm,dcc"; + }; diff --git a/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml b/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml index 920539926d7e23..7a105551fa6a89 100644 --- a/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml +++ b/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml @@ -13,7 +13,7 @@ description: | https://www.nxp.com/webapp/Download?colCode=S32V234RM. maintainers: - - Chester Lin + - Chester Lin allOf: - $ref: serial.yaml# diff --git a/Documentation/devicetree/bindings/serial/fsl-imx-uart.yaml b/Documentation/devicetree/bindings/serial/fsl-imx-uart.yaml index 83035553044a23..9c6dc16f88a6f0 100644 --- a/Documentation/devicetree/bindings/serial/fsl-imx-uart.yaml +++ b/Documentation/devicetree/bindings/serial/fsl-imx-uart.yaml @@ -9,10 +9,6 @@ title: Freescale i.MX Universal Asynchronous Receiver/Transmitter (UART) maintainers: - Fabio Estevam -allOf: - - $ref: serial.yaml# - - $ref: rs485.yaml# - properties: compatible: oneOf: @@ -68,7 +64,11 @@ properties: - const: tx interrupts: - maxItems: 1 + items: + - description: UART RX Interrupt + - description: UART TX Interrupt + - description: UART RTS Interrupt + minItems: 1 wakeup-source: true @@ -110,6 +110,25 @@ required: - clock-names - interrupts +allOf: + - $ref: serial.yaml# + - $ref: rs485.yaml# + + - if: + properties: + compatible: + contains: + const: fsl,imx1-uart + then: + properties: + interrupts: + minItems: 3 + maxItems: 3 + else: + properties: + interrupts: + maxItems: 1 + unevaluatedProperties: false examples: diff --git a/Documentation/devicetree/bindings/serial/qcom,msm-uartdm.yaml b/Documentation/devicetree/bindings/serial/qcom,msm-uartdm.yaml index ee52bf8e8917d4..e0fa363ad7e2e5 100644 --- a/Documentation/devicetree/bindings/serial/qcom,msm-uartdm.yaml +++ b/Documentation/devicetree/bindings/serial/qcom,msm-uartdm.yaml @@ -48,9 +48,17 @@ properties: - const: tx - const: rx + interconnects: + maxItems: 1 + interrupts: maxItems: 1 + operating-points-v2: true + + power-domains: + maxItems: 1 + qcom,rx-crci: $ref: /schemas/types.yaml#/definitions/uint32 description: @@ -99,7 +107,9 @@ unevaluatedProperties: false examples: - | + #include #include + #include serial@f991e000 { compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; @@ -109,4 +119,7 @@ examples: clock-names = "core", "iface"; dmas = <&dma0 0>, <&dma0 1>; dma-names = "tx", "rx"; + power-domains = <&rpmpd MSM8996_VDDCX>; + operating-points-v2 = <&uart_opp_table>; + interconnects = <&pnoc MASTER_BLSP_1 &bimc SLAVE_EBI_CH0>; }; diff --git a/Documentation/devicetree/bindings/serial/renesas,sci.yaml b/Documentation/devicetree/bindings/serial/renesas,sci.yaml index 9f7305200c47e9..64d3db6e54e5c3 100644 --- a/Documentation/devicetree/bindings/serial/renesas,sci.yaml +++ b/Documentation/devicetree/bindings/serial/renesas,sci.yaml @@ -17,7 +17,7 @@ properties: oneOf: - items: - enum: - - renesas,r9a07g043-sci # RZ/G2UL + - renesas,r9a07g043-sci # RZ/G2UL and RZ/Five - renesas,r9a07g044-sci # RZ/G2{L,LC} - renesas,r9a07g054-sci # RZ/V2L - const: renesas,sci # generic SCI compatible UART diff --git a/Documentation/devicetree/bindings/serial/samsung_uart.yaml b/Documentation/devicetree/bindings/serial/samsung_uart.yaml index ac60ab1e35e313..133259ed3a34c5 100644 --- a/Documentation/devicetree/bindings/serial/samsung_uart.yaml +++ b/Documentation/devicetree/bindings/serial/samsung_uart.yaml @@ -18,17 +18,29 @@ description: |+ properties: compatible: oneOf: - - items: - - const: samsung,exynosautov9-uart - - const: samsung,exynos850-uart - enum: - apple,s5l-uart - axis,artpec8-uart + - google,gs101-uart - samsung,s3c6400-uart - samsung,s5pv210-uart - samsung,exynos4210-uart - samsung,exynos5433-uart - samsung,exynos850-uart + - items: + - enum: + - samsung,exynos7-uart + - tesla,fsd-uart + - const: samsung,exynos4210-uart + - items: + - enum: + - samsung,exynos7885-uart + - const: samsung,exynos5433-uart + - items: + - enum: + - samsung,exynosautov9-uart + - samsung,exynosautov920-uart + - const: samsung,exynos850-uart reg: maxItems: 1 @@ -122,6 +134,16 @@ allOf: - const: uart - const: clk_uart_baud0 + - if: + properties: + compatible: + contains: + enum: + - google,gs101-uart + then: + required: + - samsung,uart-fifosize + unevaluatedProperties: false examples: diff --git a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml index 17c553123f96ed..1001d2a6ace85f 100644 --- a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml +++ b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml @@ -11,6 +11,7 @@ maintainers: allOf: - $ref: serial.yaml# + - $ref: rs485.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/serial/sprd-uart.yaml b/Documentation/devicetree/bindings/serial/sprd-uart.yaml index 28ff77aa86c854..f4dbb6dc2b6ef2 100644 --- a/Documentation/devicetree/bindings/serial/sprd-uart.yaml +++ b/Documentation/devicetree/bindings/serial/sprd-uart.yaml @@ -20,6 +20,7 @@ properties: - sprd,sc9860-uart - sprd,sc9863a-uart - sprd,ums512-uart + - sprd,ums9620-uart - const: sprd,sc9836-uart - const: sprd,sc9836-uart diff --git a/Documentation/devicetree/bindings/soc/amlogic/amlogic,meson-gx-hhi-sysctrl.yaml b/Documentation/devicetree/bindings/soc/amlogic/amlogic,meson-gx-hhi-sysctrl.yaml index 16977e4e4357b7..c6bce40946d4af 100644 --- a/Documentation/devicetree/bindings/soc/amlogic/amlogic,meson-gx-hhi-sysctrl.yaml +++ b/Documentation/devicetree/bindings/soc/amlogic/amlogic,meson-gx-hhi-sysctrl.yaml @@ -158,3 +158,36 @@ examples: }; }; }; + + - | + system-controller@ff63c000 { + compatible = "amlogic,meson-axg-hhi-sysctrl", "simple-mfd", "syscon"; + reg = <0xff63c000 0x400>; + + clock-controller { + compatible = "amlogic,axg-clkc"; + #clock-cells = <1>; + clocks = <&xtal>; + clock-names = "xtal"; + }; + + power-controller { + compatible = "amlogic,meson-axg-pwrc"; + #power-domain-cells = <1>; + amlogic,ao-sysctrl = <&sysctrl_AO>; + + resets = <&reset_viu>, + <&reset_venc>, + <&reset_vcbus>, + <&reset_vencl>, + <&reset_vid_lock>; + reset-names = "viu", "venc", "vcbus", "vencl", "vid_lock"; + clocks = <&clk_vpu>, <&clk_vapb>; + clock-names = "vpu", "vapb"; + }; + + phy { + compatible = "amlogic,axg-mipi-pcie-analog-phy"; + #phy-cells = <0>; + }; + }; diff --git a/Documentation/devicetree/bindings/soc/mediatek/mediatek,pwrap.yaml b/Documentation/devicetree/bindings/soc/mediatek/mediatek,pwrap.yaml index a06ac2177444eb..4737e5f45d5410 100644 --- a/Documentation/devicetree/bindings/soc/mediatek/mediatek,pwrap.yaml +++ b/Documentation/devicetree/bindings/soc/mediatek/mediatek,pwrap.yaml @@ -41,7 +41,6 @@ properties: - mediatek,mt8173-pwrap - mediatek,mt8183-pwrap - mediatek,mt8186-pwrap - - mediatek,mt8188-pwrap - mediatek,mt8195-pwrap - mediatek,mt8365-pwrap - mediatek,mt8516-pwrap @@ -50,6 +49,11 @@ properties: - mediatek,mt8186-pwrap - mediatek,mt8195-pwrap - const: syscon + - items: + - enum: + - mediatek,mt8188-pwrap + - const: mediatek,mt8195-pwrap + - const: syscon reg: minItems: 1 diff --git a/Documentation/devicetree/bindings/soc/mediatek/mtk-svs.yaml b/Documentation/devicetree/bindings/soc/mediatek/mtk-svs.yaml index 7eda63d5682f13..742b91d1d28eb4 100644 --- a/Documentation/devicetree/bindings/soc/mediatek/mtk-svs.yaml +++ b/Documentation/devicetree/bindings/soc/mediatek/mtk-svs.yaml @@ -22,8 +22,10 @@ properties: compatible: enum: - mediatek,mt8183-svs + - mediatek,mt8186-svs - mediatek,mt8188-svs - mediatek,mt8192-svs + - mediatek,mt8195-svs reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/soc/microchip/microchip,mpfs-sys-controller.yaml b/Documentation/devicetree/bindings/soc/microchip/microchip,mpfs-sys-controller.yaml index 365a9fed59147e..a3fa04f3a1bd93 100644 --- a/Documentation/devicetree/bindings/soc/microchip/microchip,mpfs-sys-controller.yaml +++ b/Documentation/devicetree/bindings/soc/microchip/microchip,mpfs-sys-controller.yaml @@ -26,6 +26,16 @@ properties: compatible: const: microchip,mpfs-sys-controller + microchip,bitstream-flash: + $ref: /schemas/types.yaml#/definitions/phandle + description: + The SPI flash connected to the system controller's QSPI controller. + The system controller may retrieve FPGA bitstreams from this flash to + perform In-Application Programming (IAP) or during device initialisation + for Auto Update. The MSS and system controller have separate QSPI + controllers and this flash is connected to both. Software running in the + MSS can write bitstreams to the flash. + required: - compatible - mboxes diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml index d1c7c2be865f30..b4478f417edc32 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml @@ -38,6 +38,8 @@ properties: - qcom,sm8350-aoss-qmp - qcom,sm8450-aoss-qmp - qcom,sm8550-aoss-qmp + - qcom,sm8650-aoss-qmp + - qcom,x1e80100-aoss-qmp - const: qcom,aoss-qmp reg: diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml index 422921cf1f827f..61df97ffe1e409 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml @@ -20,14 +20,20 @@ description: properties: compatible: - items: - - enum: - - qcom,sc8180x-pmic-glink - - qcom,sc8280xp-pmic-glink - - qcom,sm8350-pmic-glink - - qcom,sm8450-pmic-glink - - qcom,sm8550-pmic-glink - - const: qcom,pmic-glink + oneOf: + - items: + - enum: + - qcom,sc8180x-pmic-glink + - qcom,sc8280xp-pmic-glink + - qcom,sm8350-pmic-glink + - qcom,sm8450-pmic-glink + - qcom,sm8550-pmic-glink + - const: qcom,pmic-glink + - items: + - enum: + - qcom,sm8650-pmic-glink + - const: qcom,sm8550-pmic-glink + - const: qcom,pmic-glink '#address-cells': const: 1 diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom-stats.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom-stats.yaml index 96a7f18220225a..686a7ef2f48af1 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom-stats.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom-stats.yaml @@ -31,10 +31,24 @@ properties: reg: maxItems: 1 + qcom,qmp: + $ref: /schemas/types.yaml#/definitions/phandle + description: Reference to the AOSS side-channel message RAM + required: - compatible - reg +allOf: + - if: + not: + properties: + compatible: + const: qcom,rpmh-stats + then: + properties: + qcom,qmp: false + additionalProperties: false examples: diff --git a/Documentation/devicetree/bindings/soc/rockchip/grf.yaml b/Documentation/devicetree/bindings/soc/rockchip/grf.yaml index 1309bf5ae0cdd1..9793ea6f0fe65d 100644 --- a/Documentation/devicetree/bindings/soc/rockchip/grf.yaml +++ b/Documentation/devicetree/bindings/soc/rockchip/grf.yaml @@ -28,6 +28,8 @@ properties: - rockchip,rk3588-sys-grf - rockchip,rk3588-pcie3-phy-grf - rockchip,rk3588-pcie3-pipe-grf + - rockchip,rk3588-vo-grf + - rockchip,rk3588-vop-grf - rockchip,rv1108-usbgrf - const: syscon - items: diff --git a/Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml b/Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml index e1d716df5dfa66..15fcd8f1d8bc7b 100644 --- a/Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml +++ b/Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml @@ -15,6 +15,7 @@ select: compatible: contains: enum: + - google,gs101-pmu - samsung,exynos3250-pmu - samsung,exynos4210-pmu - samsung,exynos4212-pmu @@ -35,6 +36,7 @@ properties: oneOf: - items: - enum: + - google,gs101-pmu - samsung,exynos3250-pmu - samsung,exynos4210-pmu - samsung,exynos4212-pmu @@ -48,6 +50,14 @@ properties: - samsung,exynos850-pmu - samsung-s5pv210-pmu - const: syscon + - items: + - enum: + - samsung,exynos7885-pmu + - samsung,exynosautov9-pmu + - samsung,exynosautov920-pmu + - tesla,fsd-pmu + - const: samsung,exynos7-pmu + - const: syscon - items: - enum: - samsung,exynos3250-pmu diff --git a/Documentation/devicetree/bindings/soc/samsung/exynos-usi.yaml b/Documentation/devicetree/bindings/soc/samsung/exynos-usi.yaml index a6836904a4f835..8b478d6cdc303c 100644 --- a/Documentation/devicetree/bindings/soc/samsung/exynos-usi.yaml +++ b/Documentation/devicetree/bindings/soc/samsung/exynos-usi.yaml @@ -24,7 +24,10 @@ properties: compatible: oneOf: - items: - - const: samsung,exynosautov9-usi + - enum: + - google,gs101-usi + - samsung,exynosautov9-usi + - samsung,exynosautov920-usi - const: samsung,exynos850-usi - enum: - samsung,exynos850-usi @@ -155,7 +158,7 @@ examples: }; hsi2c_0: i2c@13820000 { - compatible = "samsung,exynosautov9-hsi2c"; + compatible = "samsung,exynos850-hsi2c", "samsung,exynosautov9-hsi2c"; reg = <0x13820000 0xc0>; interrupts = ; #address-cells = <1>; diff --git a/Documentation/devicetree/bindings/soc/samsung/samsung,exynos-sysreg.yaml b/Documentation/devicetree/bindings/soc/samsung/samsung,exynos-sysreg.yaml index 163e912e9cadcd..1794e3799f2110 100644 --- a/Documentation/devicetree/bindings/soc/samsung/samsung,exynos-sysreg.yaml +++ b/Documentation/devicetree/bindings/soc/samsung/samsung,exynos-sysreg.yaml @@ -14,9 +14,14 @@ properties: oneOf: - items: - enum: + - google,gs101-apm-sysreg + - google,gs101-peric0-sysreg + - google,gs101-peric1-sysreg - samsung,exynos3-sysreg - samsung,exynos4-sysreg - samsung,exynos5-sysreg + - samsung,exynosautov920-peric0-sysreg + - samsung,exynosautov920-peric1-sysreg - tesla,fsd-cam-sysreg - tesla,fsd-fsys0-sysreg - tesla,fsd-fsys1-sysreg diff --git a/Documentation/devicetree/bindings/soc/xilinx/xilinx.yaml b/Documentation/devicetree/bindings/soc/xilinx/xilinx.yaml new file mode 100644 index 00000000000000..d4c0fe1fe43580 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/xilinx/xilinx.yaml @@ -0,0 +1,142 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/soc/xilinx/xilinx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Xilinx Zynq Platforms + +maintainers: + - Michal Simek + +description: | + Xilinx boards with Zynq-7000 SOC or Zynq UltraScale+ MPSoC + +properties: + $nodename: + const: '/' + compatible: + oneOf: + - items: + - enum: + - adapteva,parallella + - digilent,zynq-zybo + - digilent,zynq-zybo-z7 + - ebang,ebaz4205 + - myir,zynq-zturn-v5 + - myir,zynq-zturn + - xlnx,zynq-cc108 + - xlnx,zynq-zc702 + - xlnx,zynq-zc706 + - xlnx,zynq-zc770-xm010 + - xlnx,zynq-zc770-xm011 + - xlnx,zynq-zc770-xm012 + - xlnx,zynq-zc770-xm013 + - const: xlnx,zynq-7000 + + - items: + - const: avnet,zynq-microzed + - const: xlnx,zynq-microzed + - const: xlnx,zynq-7000 + + - items: + - const: avnet,zynq-zed + - const: xlnx,zynq-zed + - const: xlnx,zynq-7000 + + - items: + - enum: + - xlnx,zynqmp-zc1751 + - const: xlnx,zynqmp + + - description: Xilinx internal board zc1232 + items: + - const: xlnx,zynqmp-zc1232-revA + - const: xlnx,zynqmp-zc1232 + - const: xlnx,zynqmp + + - description: Xilinx internal board zc1254 + items: + - const: xlnx,zynqmp-zc1254-revA + - const: xlnx,zynqmp-zc1254 + - const: xlnx,zynqmp + + - description: Xilinx evaluation board zcu1275 + items: + - const: xlnx,zynqmp-zcu1275-revA + - const: xlnx,zynqmp-zcu1275 + - const: xlnx,zynqmp + + - description: Xilinx 96boards compatible board zcu100 + items: + - const: xlnx,zynqmp-zcu100-revC + - const: xlnx,zynqmp-zcu100 + - const: xlnx,zynqmp + + - description: Xilinx 96boards compatible board Ultra96 + items: + - const: avnet,ultra96-rev1 + - const: avnet,ultra96 + - const: xlnx,zynqmp-zcu100-revC + - const: xlnx,zynqmp-zcu100 + - const: xlnx,zynqmp + + - description: Xilinx evaluation board zcu102 + items: + - enum: + - xlnx,zynqmp-zcu102-revA + - xlnx,zynqmp-zcu102-revB + - xlnx,zynqmp-zcu102-rev1.0 + - xlnx,zynqmp-zcu102-rev1.1 + - const: xlnx,zynqmp-zcu102 + - const: xlnx,zynqmp + + - description: Xilinx evaluation board zcu104 + items: + - enum: + - xlnx,zynqmp-zcu104-revA + - xlnx,zynqmp-zcu104-revC + - xlnx,zynqmp-zcu104-rev1.0 + - const: xlnx,zynqmp-zcu104 + - const: xlnx,zynqmp + + - description: Xilinx evaluation board zcu106 + items: + - enum: + - xlnx,zynqmp-zcu106-revA + - xlnx,zynqmp-zcu106-rev1.0 + - const: xlnx,zynqmp-zcu106 + - const: xlnx,zynqmp + + - description: Xilinx evaluation board zcu111 + items: + - enum: + - xlnx,zynqmp-zcu111-revA + - xlnx,zynqmp-zcu111-rev1.0 + - const: xlnx,zynqmp-zcu111 + - const: xlnx,zynqmp + + - description: Xilinx Kria SOMs + items: + - const: xlnx,zynqmp-sm-k26-rev1 + - const: xlnx,zynqmp-sm-k26-revB + - const: xlnx,zynqmp-sm-k26-revA + - const: xlnx,zynqmp-sm-k26 + - const: xlnx,zynqmp + + - description: Xilinx Kria SOMs (starter) + items: + - const: xlnx,zynqmp-smk-k26-rev1 + - const: xlnx,zynqmp-smk-k26-revB + - const: xlnx,zynqmp-smk-k26-revA + - const: xlnx,zynqmp-smk-k26 + - const: xlnx,zynqmp + + - description: AMD MicroBlaze V (QEMU) + items: + - const: qemu,mbv + - const: amd,mbv + +additionalProperties: true + +... diff --git a/Documentation/devicetree/bindings/sound/adi,max98363.yaml b/Documentation/devicetree/bindings/sound/adi,max98363.yaml index a844b63f393051..c388cda560113b 100644 --- a/Documentation/devicetree/bindings/sound/adi,max98363.yaml +++ b/Documentation/devicetree/bindings/sound/adi,max98363.yaml @@ -39,7 +39,7 @@ unevaluatedProperties: false examples: - | - soundwire-controller@3250000 { + soundwire@3250000 { #address-cells = <2>; #size-cells = <0>; reg = <0x3250000 0x2000>; diff --git a/Documentation/devicetree/bindings/sound/audio-graph-port.yaml b/Documentation/devicetree/bindings/sound/audio-graph-port.yaml index 60b5e3fd1115fe..b13c08de505e41 100644 --- a/Documentation/devicetree/bindings/sound/audio-graph-port.yaml +++ b/Documentation/devicetree/bindings/sound/audio-graph-port.yaml @@ -19,6 +19,12 @@ definitions: properties: mclk-fs: $ref: simple-card.yaml#/definitions/mclk-fs + playback-only: + description: port connection used only for playback + $ref: /schemas/types.yaml#/definitions/flag + capture-only: + description: port connection used only for capture + $ref: /schemas/types.yaml#/definitions/flag endpoint-base: allOf: diff --git a/Documentation/devicetree/bindings/sound/es8328.txt b/Documentation/devicetree/bindings/sound/es8328.txt deleted file mode 100644 index 33fbf058c997c6..00000000000000 --- a/Documentation/devicetree/bindings/sound/es8328.txt +++ /dev/null @@ -1,38 +0,0 @@ -Everest ES8328 audio CODEC - -This device supports both I2C and SPI. - -Required properties: - - - compatible : Should be "everest,es8328" or "everest,es8388" - - DVDD-supply : Regulator providing digital core supply voltage 1.8 - 3.6V - - AVDD-supply : Regulator providing analog supply voltage 3.3V - - PVDD-supply : Regulator providing digital IO supply voltage 1.8 - 3.6V - - IPVDD-supply : Regulator providing analog output voltage 3.3V - - clocks : A 22.5792 or 11.2896 MHz clock - - reg : the I2C address of the device for I2C, the chip select number for SPI - -Pins on the device (for linking into audio routes): - - * LOUT1 - * LOUT2 - * ROUT1 - * ROUT2 - * LINPUT1 - * RINPUT1 - * LINPUT2 - * RINPUT2 - * Mic Bias - - -Example: - -codec: es8328@11 { - compatible = "everest,es8328"; - DVDD-supply = <®_3p3v>; - AVDD-supply = <®_3p3v>; - PVDD-supply = <®_3p3v>; - HPVDD-supply = <®_3p3v>; - clocks = <&clks 169>; - reg = <0x11>; -}; diff --git a/Documentation/devicetree/bindings/sound/everest,es8328.yaml b/Documentation/devicetree/bindings/sound/everest,es8328.yaml new file mode 100644 index 00000000000000..a0f4670fa38c84 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/everest,es8328.yaml @@ -0,0 +1,77 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/everest,es8328.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Everest ES8328 audio CODEC + +description: + Everest Audio Codec, which can be connected via I2C or SPI. + Pins on the device (for linking into audio routes) are + * LOUT1 + * LOUT2 + * ROUT1 + * ROUT2 + * LINPUT1 + * RINPUT1 + * LINPUT2 + * RINPUT2 + * Mic Bias + +maintainers: + - David Yang + +properties: + compatible: + enum: + - everest,es8328 + - everest,es8388 + + reg: + maxItems: 1 + + "#sound-dai-cells": + const: 0 + + clocks: + items: + - description: A 22.5792 or 11.2896 MHz clock + + DVDD-supply: + description: Regulator providing digital core supply voltage 1.8 - 3.6V + + AVDD-supply: + description: Regulator providing analog supply voltage 3.3V + + PVDD-supply: + description: Regulator providing digital IO supply voltage 1.8 - 3.6V + + HPVDD-supply: + description: Regulator providing analog output voltage 3.3V + +required: + - compatible + - clocks + - DVDD-supply + - AVDD-supply + - PVDD-supply + - HPVDD-supply + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + es8328: codec@11 { + compatible = "everest,es8328"; + reg = <0x11>; + AVDD-supply = <®_3p3v>; + DVDD-supply = <®_3p3v>; + HPVDD-supply = <®_3p3v>; + PVDD-supply = <®_3p3v>; + clocks = <&clks 169>; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/fsl,mqs.txt b/Documentation/devicetree/bindings/sound/fsl,mqs.txt deleted file mode 100644 index d66284b8bef29b..00000000000000 --- a/Documentation/devicetree/bindings/sound/fsl,mqs.txt +++ /dev/null @@ -1,36 +0,0 @@ -fsl,mqs audio CODEC - -Required properties: - - compatible : Must contain one of "fsl,imx6sx-mqs", "fsl,codec-mqs" - "fsl,imx8qm-mqs", "fsl,imx8qxp-mqs", "fsl,imx93-mqs". - - clocks : A list of phandles + clock-specifiers, one for each entry in - clock-names - - clock-names : "mclk" - must required. - "core" - required if compatible is "fsl,imx8qm-mqs", it - is for register access. - - gpr : A phandle of General Purpose Registers in IOMUX Controller. - Required if compatible is "fsl,imx6sx-mqs". - -Required if compatible is "fsl,imx8qm-mqs": - - power-domains: A phandle of PM domain provider node. - - reg: Offset and length of the register set for the device. - -Example: - -mqs: mqs { - compatible = "fsl,imx6sx-mqs"; - gpr = <&gpr>; - clocks = <&clks IMX6SX_CLK_SAI1>; - clock-names = "mclk"; - status = "disabled"; -}; - -mqs: mqs@59850000 { - compatible = "fsl,imx8qm-mqs"; - reg = <0x59850000 0x10000>; - clocks = <&clk IMX8QM_AUD_MQS_IPG>, - <&clk IMX8QM_AUD_MQS_HMCLK>; - clock-names = "core", "mclk"; - power-domains = <&pd_mqs0>; - status = "disabled"; -}; diff --git a/Documentation/devicetree/bindings/sound/fsl,mqs.yaml b/Documentation/devicetree/bindings/sound/fsl,mqs.yaml new file mode 100644 index 00000000000000..8b33353a80ca7e --- /dev/null +++ b/Documentation/devicetree/bindings/sound/fsl,mqs.yaml @@ -0,0 +1,105 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/fsl,mqs.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP Medium Quality Sound (MQS) + +maintainers: + - Shengjiu Wang + - Chancel Liu + +description: | + Medium quality sound (MQS) is used to generate medium quality audio + via a standard GPIO in the pinmux, allowing the user to connect + stereo speakers or headphones to a power amplifier without an + additional DAC chip. + +properties: + compatible: + enum: + - fsl,imx6sx-mqs + - fsl,imx8qm-mqs + - fsl,imx8qxp-mqs + - fsl,imx93-mqs + + clocks: + minItems: 1 + maxItems: 2 + + clock-names: + minItems: 1 + maxItems: 2 + + gpr: + $ref: /schemas/types.yaml#/definitions/phandle + description: The phandle to the General Purpose Register (GPR) node + + reg: + maxItems: 1 + + power-domains: + maxItems: 1 + + resets: + maxItems: 1 + +required: + - compatible + - clocks + - clock-names + +allOf: + - if: + properties: + compatible: + contains: + enum: + - fsl,imx8qm-mqs + - fsl,imx8qxp-mqs + then: + properties: + clocks: + items: + - description: Master clock + - description: Clock for register access + clock-names: + items: + - const: mclk + - const: core + required: + - reg + - power-domains + else: + properties: + clocks: + items: + - description: Master clock + clock-names: + items: + - const: mclk + required: + - gpr + +additionalProperties: false + +examples: + - | + #include + mqs0: mqs { + compatible = "fsl,imx6sx-mqs"; + gpr = <&gpr>; + clocks = <&clks IMX6SX_CLK_SAI1>; + clock-names = "mclk"; + }; + + - | + #include + mqs1: mqs@59850000 { + compatible = "fsl,imx8qm-mqs"; + reg = <0x59850000 0x10000>; + clocks = <&mqs0_lpcg 0>, <&mqs0_lpcg 1>; + clock-names = "mclk", "core"; + power-domains = <&pd IMX_SC_R_MQS_0>; + }; diff --git a/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml b/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml index 799b362ba4987c..0eb0c1ba8710dc 100644 --- a/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml +++ b/Documentation/devicetree/bindings/sound/fsl,xcvr.yaml @@ -38,7 +38,10 @@ properties: - const: txfifo interrupts: - maxItems: 1 + items: + - description: WAKEUPMIX Audio XCVR Interrupt 1 + - description: WAKEUPMIX Audio XCVR Interrupt 2 + minItems: 1 clocks: items: @@ -78,6 +81,23 @@ required: - dma-names - resets +allOf: + - if: + properties: + compatible: + contains: + enum: + - fsl,imx93-xcvr + then: + properties: + interrupts: + minItems: 2 + maxItems: 2 + else: + properties: + interrupts: + maxItems: 1 + additionalProperties: false examples: diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt2701-audio.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt2701-audio.yaml new file mode 100644 index 00000000000000..45382c4d86aa35 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/mediatek,mt2701-audio.yaml @@ -0,0 +1,116 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/mediatek,mt2701-audio.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek Audio Front End (AFE) PCM controller for mt2701 + +description: + The AFE PCM node must be a subnode of the MediaTek audsys device tree node. + +maintainers: + - Eugen Hristev + +properties: + compatible: + enum: + - mediatek,mt2701-audio + - mediatek,mt7622-audio + + interrupts: + items: + - description: AFE interrupt + - description: ASYS interrupt + + interrupt-names: + items: + - const: afe + - const: asys + + power-domains: + maxItems: 1 + + clocks: + items: + - description: audio infra sys clock + - description: top audio mux 1 + - description: top audio mux 2 + - description: top audio sys a1 clock + - description: top audio sys a2 clock + - description: i2s0 source selection + - description: i2s1 source selection + - description: i2s2 source selection + - description: i2s3 source selection + - description: i2s0 source divider + - description: i2s1 source divider + - description: i2s2 source divider + - description: i2s3 source divider + - description: i2s0 master clock + - description: i2s1 master clock + - description: i2s2 master clock + - description: i2s3 master clock + - description: i2so0 hopping clock + - description: i2so1 hopping clock + - description: i2so2 hopping clock + - description: i2so3 hopping clock + - description: i2si0 hopping clock + - description: i2si1 hopping clock + - description: i2si2 hopping clock + - description: i2si3 hopping clock + - description: asrc0 output clock + - description: asrc1 output clock + - description: asrc2 output clock + - description: asrc3 output clock + - description: audio front end pd clock + - description: audio front end conn pd clock + - description: top audio a1 sys pd + - description: top audio a2 sys pd + - description: audio merge interface pd + + clock-names: + items: + - const: infra_sys_audio_clk + - const: top_audio_mux1_sel + - const: top_audio_mux2_sel + - const: top_audio_a1sys_hp + - const: top_audio_a2sys_hp + - const: i2s0_src_sel + - const: i2s1_src_sel + - const: i2s2_src_sel + - const: i2s3_src_sel + - const: i2s0_src_div + - const: i2s1_src_div + - const: i2s2_src_div + - const: i2s3_src_div + - const: i2s0_mclk_en + - const: i2s1_mclk_en + - const: i2s2_mclk_en + - const: i2s3_mclk_en + - const: i2so0_hop_ck + - const: i2so1_hop_ck + - const: i2so2_hop_ck + - const: i2so3_hop_ck + - const: i2si0_hop_ck + - const: i2si1_hop_ck + - const: i2si2_hop_ck + - const: i2si3_hop_ck + - const: asrc0_out_ck + - const: asrc1_out_ck + - const: asrc2_out_ck + - const: asrc3_out_ck + - const: audio_afe_pd + - const: audio_afe_conn_pd + - const: audio_a1sys_pd + - const: audio_a2sys_pd + - const: audio_mrgif_pd + +required: + - compatible + - interrupts + - interrupt-names + - power-domains + - clocks + - clock-names + +additionalProperties: false diff --git a/Documentation/devicetree/bindings/sound/mediatek,mt8188-mt6359.yaml b/Documentation/devicetree/bindings/sound/mediatek,mt8188-mt6359.yaml index 4c8c95057ef7ca..f94ad0715e3239 100644 --- a/Documentation/devicetree/bindings/sound/mediatek,mt8188-mt6359.yaml +++ b/Documentation/devicetree/bindings/sound/mediatek,mt8188-mt6359.yaml @@ -15,6 +15,7 @@ allOf: properties: compatible: enum: + - mediatek,mt8188-es8326 - mediatek,mt8188-mt6359-evb - mediatek,mt8188-nau8825 - mediatek,mt8188-rt5682s diff --git a/Documentation/devicetree/bindings/sound/mt2701-afe-pcm.txt b/Documentation/devicetree/bindings/sound/mt2701-afe-pcm.txt deleted file mode 100644 index f548e6a58240d6..00000000000000 --- a/Documentation/devicetree/bindings/sound/mt2701-afe-pcm.txt +++ /dev/null @@ -1,146 +0,0 @@ -Mediatek AFE PCM controller for mt2701 - -Required properties: -- compatible: should be one of the following. - - "mediatek,mt2701-audio" - - "mediatek,mt7622-audio" -- interrupts: should contain AFE and ASYS interrupts -- interrupt-names: should be "afe" and "asys" -- power-domains: should define the power domain -- clocks: Must contain an entry for each entry in clock-names - See ../clocks/clock-bindings.txt for details -- clock-names: should have these clock names: - "infra_sys_audio_clk", - "top_audio_mux1_sel", - "top_audio_mux2_sel", - "top_audio_a1sys_hp", - "top_audio_a2sys_hp", - "i2s0_src_sel", - "i2s1_src_sel", - "i2s2_src_sel", - "i2s3_src_sel", - "i2s0_src_div", - "i2s1_src_div", - "i2s2_src_div", - "i2s3_src_div", - "i2s0_mclk_en", - "i2s1_mclk_en", - "i2s2_mclk_en", - "i2s3_mclk_en", - "i2so0_hop_ck", - "i2so1_hop_ck", - "i2so2_hop_ck", - "i2so3_hop_ck", - "i2si0_hop_ck", - "i2si1_hop_ck", - "i2si2_hop_ck", - "i2si3_hop_ck", - "asrc0_out_ck", - "asrc1_out_ck", - "asrc2_out_ck", - "asrc3_out_ck", - "audio_afe_pd", - "audio_afe_conn_pd", - "audio_a1sys_pd", - "audio_a2sys_pd", - "audio_mrgif_pd"; -- assigned-clocks: list of input clocks and dividers for the audio system. - See ../clocks/clock-bindings.txt for details. -- assigned-clocks-parents: parent of input clocks of assigned clocks. -- assigned-clock-rates: list of clock frequencies of assigned clocks. - -Must be a subnode of MediaTek audsys device tree node. -See ../arm/mediatek/mediatek,audsys.txt for details about the parent node. - -Example: - - audsys: audio-subsystem@11220000 { - compatible = "mediatek,mt2701-audsys", "syscon"; - ... - - afe: audio-controller { - compatible = "mediatek,mt2701-audio"; - interrupts = , - ; - interrupt-names = "afe", "asys"; - power-domains = <&scpsys MT2701_POWER_DOMAIN_IFR_MSC>; - - clocks = <&infracfg CLK_INFRA_AUDIO>, - <&topckgen CLK_TOP_AUD_MUX1_SEL>, - <&topckgen CLK_TOP_AUD_MUX2_SEL>, - <&topckgen CLK_TOP_AUD_48K_TIMING>, - <&topckgen CLK_TOP_AUD_44K_TIMING>, - <&topckgen CLK_TOP_AUD_K1_SRC_SEL>, - <&topckgen CLK_TOP_AUD_K2_SRC_SEL>, - <&topckgen CLK_TOP_AUD_K3_SRC_SEL>, - <&topckgen CLK_TOP_AUD_K4_SRC_SEL>, - <&topckgen CLK_TOP_AUD_K1_SRC_DIV>, - <&topckgen CLK_TOP_AUD_K2_SRC_DIV>, - <&topckgen CLK_TOP_AUD_K3_SRC_DIV>, - <&topckgen CLK_TOP_AUD_K4_SRC_DIV>, - <&topckgen CLK_TOP_AUD_I2S1_MCLK>, - <&topckgen CLK_TOP_AUD_I2S2_MCLK>, - <&topckgen CLK_TOP_AUD_I2S3_MCLK>, - <&topckgen CLK_TOP_AUD_I2S4_MCLK>, - <&audsys CLK_AUD_I2SO1>, - <&audsys CLK_AUD_I2SO2>, - <&audsys CLK_AUD_I2SO3>, - <&audsys CLK_AUD_I2SO4>, - <&audsys CLK_AUD_I2SIN1>, - <&audsys CLK_AUD_I2SIN2>, - <&audsys CLK_AUD_I2SIN3>, - <&audsys CLK_AUD_I2SIN4>, - <&audsys CLK_AUD_ASRCO1>, - <&audsys CLK_AUD_ASRCO2>, - <&audsys CLK_AUD_ASRCO3>, - <&audsys CLK_AUD_ASRCO4>, - <&audsys CLK_AUD_AFE>, - <&audsys CLK_AUD_AFE_CONN>, - <&audsys CLK_AUD_A1SYS>, - <&audsys CLK_AUD_A2SYS>, - <&audsys CLK_AUD_AFE_MRGIF>; - - clock-names = "infra_sys_audio_clk", - "top_audio_mux1_sel", - "top_audio_mux2_sel", - "top_audio_a1sys_hp", - "top_audio_a2sys_hp", - "i2s0_src_sel", - "i2s1_src_sel", - "i2s2_src_sel", - "i2s3_src_sel", - "i2s0_src_div", - "i2s1_src_div", - "i2s2_src_div", - "i2s3_src_div", - "i2s0_mclk_en", - "i2s1_mclk_en", - "i2s2_mclk_en", - "i2s3_mclk_en", - "i2so0_hop_ck", - "i2so1_hop_ck", - "i2so2_hop_ck", - "i2so3_hop_ck", - "i2si0_hop_ck", - "i2si1_hop_ck", - "i2si2_hop_ck", - "i2si3_hop_ck", - "asrc0_out_ck", - "asrc1_out_ck", - "asrc2_out_ck", - "asrc3_out_ck", - "audio_afe_pd", - "audio_afe_conn_pd", - "audio_a1sys_pd", - "audio_a2sys_pd", - "audio_mrgif_pd"; - - assigned-clocks = <&topckgen CLK_TOP_AUD_MUX1_SEL>, - <&topckgen CLK_TOP_AUD_MUX2_SEL>, - <&topckgen CLK_TOP_AUD_MUX1_DIV>, - <&topckgen CLK_TOP_AUD_MUX2_DIV>; - assigned-clock-parents = <&topckgen CLK_TOP_AUD1PLL_98M>, - <&topckgen CLK_TOP_AUD2PLL_90M>; - assigned-clock-rates = <0>, <0>, <49152000>, <45158400>; - }; - }; diff --git a/Documentation/devicetree/bindings/sound/nuvoton,nau8821.yaml b/Documentation/devicetree/bindings/sound/nuvoton,nau8821.yaml index 3e54abd4ca7473..054b53954ac3d8 100644 --- a/Documentation/devicetree/bindings/sound/nuvoton,nau8821.yaml +++ b/Documentation/devicetree/bindings/sound/nuvoton,nau8821.yaml @@ -89,6 +89,14 @@ properties: $ref: /schemas/types.yaml#/definitions/uint32 default: 3072000 + nuvoton,dmic-slew-rate: + description: The range 0 to 7 represents the speed of DMIC slew rate. + The lowest value 0 means the slowest rate and the highest value + 7 means the fastest rate. + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 7 + default: 0 + nuvoton,left-input-single-end: description: Enable left input with single-ended settings if set. For the headset mic application, the single-ended control is @@ -127,6 +135,7 @@ examples: nuvoton,jack-insert-debounce = <7>; nuvoton,jack-eject-debounce = <0>; nuvoton,dmic-clk-threshold = <3072000>; + nuvoton,dmic-slew-rate = <0>; #sound-dai-cells = <0>; }; }; diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml index ec4b0ac8ad68c0..b8540b30741e32 100644 --- a/Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,lpass-rx-macro.yaml @@ -11,12 +11,18 @@ maintainers: properties: compatible: - enum: - - qcom,sc7280-lpass-rx-macro - - qcom,sm8250-lpass-rx-macro - - qcom,sm8450-lpass-rx-macro - - qcom,sm8550-lpass-rx-macro - - qcom,sc8280xp-lpass-rx-macro + oneOf: + - enum: + - qcom,sc7280-lpass-rx-macro + - qcom,sm8250-lpass-rx-macro + - qcom,sm8450-lpass-rx-macro + - qcom,sm8550-lpass-rx-macro + - qcom,sc8280xp-lpass-rx-macro + - items: + - enum: + - qcom,sm8650-lpass-rx-macro + - qcom,x1e80100-lpass-rx-macro + - const: qcom,sm8550-lpass-rx-macro reg: maxItems: 1 @@ -96,8 +102,9 @@ allOf: - if: properties: compatible: - enum: - - qcom,sm8550-lpass-rx-macro + contains: + enum: + - qcom,sm8550-lpass-rx-macro then: properties: clocks: diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml index 962701e9eb42a4..3e2ae16c6aba63 100644 --- a/Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,lpass-tx-macro.yaml @@ -11,13 +11,19 @@ maintainers: properties: compatible: - enum: - - qcom,sc7280-lpass-tx-macro - - qcom,sm6115-lpass-tx-macro - - qcom,sm8250-lpass-tx-macro - - qcom,sm8450-lpass-tx-macro - - qcom,sm8550-lpass-tx-macro - - qcom,sc8280xp-lpass-tx-macro + oneOf: + - enum: + - qcom,sc7280-lpass-tx-macro + - qcom,sm6115-lpass-tx-macro + - qcom,sm8250-lpass-tx-macro + - qcom,sm8450-lpass-tx-macro + - qcom,sm8550-lpass-tx-macro + - qcom,sc8280xp-lpass-tx-macro + - items: + - enum: + - qcom,sm8650-lpass-tx-macro + - qcom,x1e80100-lpass-tx-macro + - const: qcom,sm8550-lpass-tx-macro reg: maxItems: 1 @@ -118,8 +124,9 @@ allOf: - if: properties: compatible: - enum: - - qcom,sm8550-lpass-tx-macro + contains: + enum: + - qcom,sm8550-lpass-tx-macro then: properties: clocks: diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml index 4a56108c444b8a..6b483fa3c428e6 100644 --- a/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,lpass-va-macro.yaml @@ -11,12 +11,18 @@ maintainers: properties: compatible: - enum: - - qcom,sc7280-lpass-va-macro - - qcom,sm8250-lpass-va-macro - - qcom,sm8450-lpass-va-macro - - qcom,sm8550-lpass-va-macro - - qcom,sc8280xp-lpass-va-macro + oneOf: + - enum: + - qcom,sc7280-lpass-va-macro + - qcom,sm8250-lpass-va-macro + - qcom,sm8450-lpass-va-macro + - qcom,sm8550-lpass-va-macro + - qcom,sc8280xp-lpass-va-macro + - items: + - enum: + - qcom,sm8650-lpass-va-macro + - qcom,x1e80100-lpass-va-macro + - const: qcom,sm8550-lpass-va-macro reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml index eea7609d1b3349..06b5f7be360829 100644 --- a/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,lpass-wsa-macro.yaml @@ -11,12 +11,18 @@ maintainers: properties: compatible: - enum: - - qcom,sc7280-lpass-wsa-macro - - qcom,sm8250-lpass-wsa-macro - - qcom,sm8450-lpass-wsa-macro - - qcom,sm8550-lpass-wsa-macro - - qcom,sc8280xp-lpass-wsa-macro + oneOf: + - enum: + - qcom,sc7280-lpass-wsa-macro + - qcom,sm8250-lpass-wsa-macro + - qcom,sm8450-lpass-wsa-macro + - qcom,sm8550-lpass-wsa-macro + - qcom,sc8280xp-lpass-wsa-macro + - items: + - enum: + - qcom,sm8650-lpass-wsa-macro + - qcom,x1e80100-lpass-wsa-macro + - const: qcom,sm8550-lpass-wsa-macro reg: maxItems: 1 @@ -94,8 +100,9 @@ allOf: - if: properties: compatible: - enum: - - qcom,sm8550-lpass-wsa-macro + contains: + enum: + - qcom,sm8550-lpass-wsa-macro then: properties: clocks: diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml index e082a4fe095d01..6f419747273e37 100644 --- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml @@ -21,6 +21,11 @@ properties: - lenovo,yoga-c630-sndcard - qcom,db845c-sndcard - const: qcom,sdm845-sndcard + - items: + - enum: + - qcom,sm8550-sndcard + - qcom,sm8650-sndcard + - const: qcom,sm8450-sndcard - enum: - qcom,apq8016-sbc-sndcard - qcom,msm8916-qdsp6-sndcard @@ -30,6 +35,7 @@ properties: - qcom,sdm845-sndcard - qcom,sm8250-sndcard - qcom,sm8450-sndcard + - qcom,x1e80100-sndcard audio-routing: $ref: /schemas/types.yaml#/definitions/non-unique-string-array diff --git a/Documentation/devicetree/bindings/sound/qcom,wcd934x.yaml b/Documentation/devicetree/bindings/sound/qcom,wcd934x.yaml index 4df59f3b7b018c..beb0ff0245b0ab 100644 --- a/Documentation/devicetree/bindings/sound/qcom,wcd934x.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,wcd934x.yaml @@ -201,9 +201,9 @@ examples: - | codec@1,0{ compatible = "slim217,250"; - reg = <1 0>; + reg = <1 0>; reset-gpios = <&tlmm 64 0>; - slim-ifc-dev = <&wcd9340_ifd>; + slim-ifc-dev = <&wcd9340_ifd>; #sound-dai-cells = <1>; interrupt-parent = <&tlmm>; interrupts = <54 4>; diff --git a/Documentation/devicetree/bindings/sound/qcom,wcd938x-sdw.yaml b/Documentation/devicetree/bindings/sound/qcom,wcd938x-sdw.yaml index b430dd3e1841ac..7b31bf93f1a193 100644 --- a/Documentation/devicetree/bindings/sound/qcom,wcd938x-sdw.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,wcd938x-sdw.yaml @@ -51,7 +51,7 @@ examples: reg = <0x03210000 0x2000>; wcd938x_rx: codec@0,4 { compatible = "sdw20217010d00"; - reg = <0 4>; + reg = <0 4>; qcom,rx-port-mapping = <1 2 3 4 5>; }; }; @@ -62,7 +62,7 @@ examples: reg = <0x03230000 0x2000>; wcd938x_tx: codec@0,3 { compatible = "sdw20217010d00"; - reg = <0 3>; + reg = <0 3>; qcom,tx-port-mapping = <2 3 4 5>; }; }; diff --git a/Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml b/Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml index 018565793a3ec2..adbfa67f88ed93 100644 --- a/Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml @@ -137,7 +137,7 @@ examples: reg = <0x03210000 0x2000>; wcd938x_rx: codec@0,4 { compatible = "sdw20217010d00"; - reg = <0 4>; + reg = <0 4>; qcom,rx-port-mapping = <1 2 3 4 5>; }; }; @@ -148,7 +148,7 @@ examples: reg = <0x03230000 0x2000>; wcd938x_tx: codec@0,3 { compatible = "sdw20217010d00"; - reg = <0 3>; + reg = <0 3>; qcom,tx-port-mapping = <2 3 4 5>; }; }; diff --git a/Documentation/devicetree/bindings/sound/qcom,wsa883x.yaml b/Documentation/devicetree/bindings/sound/qcom,wsa883x.yaml index ba572a7f4f3c01..8e462cdf0018f3 100644 --- a/Documentation/devicetree/bindings/sound/qcom,wsa883x.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,wsa883x.yaml @@ -52,7 +52,7 @@ examples: - | #include - soundwire-controller@3250000 { + soundwire@3250000 { #address-cells = <2>; #size-cells = <0>; reg = <0x3250000 0x2000>; diff --git a/Documentation/devicetree/bindings/sound/qcom,wsa8840.yaml b/Documentation/devicetree/bindings/sound/qcom,wsa8840.yaml index e6723c9e312a07..d717017b0fdbc6 100644 --- a/Documentation/devicetree/bindings/sound/qcom,wsa8840.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,wsa8840.yaml @@ -48,7 +48,7 @@ examples: - | #include - soundwire-controller { + soundwire { #address-cells = <2>; #size-cells = <0>; diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml b/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml index 13a5a0a10fe6cc..0d7a6b576d8802 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.yaml @@ -9,20 +9,6 @@ title: Renesas R-Car Sound Driver maintainers: - Kuninori Morimoto -definitions: - port-def: - $ref: audio-graph-port.yaml#/definitions/port-base - unevaluatedProperties: false - patternProperties: - "^endpoint(@[0-9a-f]+)?": - $ref: audio-graph-port.yaml#/definitions/endpoint-base - properties: - playback: - $ref: /schemas/types.yaml#/definitions/phandle-array - capture: - $ref: /schemas/types.yaml#/definitions/phandle-array - unevaluatedProperties: false - properties: compatible: @@ -125,7 +111,17 @@ properties: # ports is below port: - $ref: "#/definitions/port-def" + $ref: audio-graph-port.yaml#/definitions/port-base + unevaluatedProperties: false + patternProperties: + "^endpoint(@[0-9a-f]+)?": + $ref: audio-graph-port.yaml#/definitions/endpoint-base + properties: + playback: + $ref: /schemas/types.yaml#/definitions/phandle-array + capture: + $ref: /schemas/types.yaml#/definitions/phandle-array + unevaluatedProperties: false rcar_sound,dvc: description: DVC subnode. @@ -269,7 +265,7 @@ patternProperties: unevaluatedProperties: false patternProperties: '^port(@[0-9a-f]+)?$': - $ref: "#/definitions/port-def" + $ref: "#/properties/port" required: - compatible @@ -501,19 +497,19 @@ examples: rcar_sound,dai { dai0 { playback = <&ssi5>, <&src5>; - capture = <&ssi6>; + capture = <&ssi6>; }; dai1 { playback = <&ssi3>; }; dai2 { - capture = <&ssi4>; + capture = <&ssi4>; }; dai3 { playback = <&ssi7>; }; dai4 { - capture = <&ssi8>; + capture = <&ssi8>; }; }; @@ -527,7 +523,7 @@ examples: frame-master = <&rsnd_endpoint0>; playback = <&ssi0>, <&src0>, <&dvc0>; - capture = <&ssi1>, <&src1>, <&dvc1>; + capture = <&ssi1>, <&src1>, <&dvc1>; }; }; }; diff --git a/Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml b/Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml index 3b5ae45eee4adc..8b9695f5deccb9 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml +++ b/Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml @@ -16,7 +16,7 @@ properties: compatible: items: - enum: - - renesas,r9a07g043-ssi # RZ/G2UL + - renesas,r9a07g043-ssi # RZ/G2UL and RZ/Five - renesas,r9a07g044-ssi # RZ/G2{L,LC} - renesas,r9a07g054-ssi # RZ/V2L - const: renesas,rz-ssi diff --git a/Documentation/devicetree/bindings/sound/samsung-i2s.yaml b/Documentation/devicetree/bindings/sound/samsung-i2s.yaml index 30b3b6e9824b7e..f45f73b5056d11 100644 --- a/Documentation/devicetree/bindings/sound/samsung-i2s.yaml +++ b/Documentation/devicetree/bindings/sound/samsung-i2s.yaml @@ -44,13 +44,18 @@ properties: frequencies supported by Exynos7 I2S and 7.1 channel TDM support for playback and capture TDM (Time division multiplexing) to allow transfer of multiple channel audio data on single data line. - enum: - - samsung,s3c6410-i2s - - samsung,s5pv210-i2s - - samsung,exynos5420-i2s - - samsung,exynos7-i2s - - samsung,exynos7-i2s1 - - tesla,fsd-i2s + oneOf: + - enum: + - samsung,s3c6410-i2s + - samsung,s5pv210-i2s + - samsung,exynos5420-i2s + - samsung,exynos7-i2s + - samsung,exynos7-i2s1 + - tesla,fsd-i2s + - items: + - enum: + - samsung,exynos5433-i2s + - const: samsung,exynos7-i2s '#address-cells': const: 1 diff --git a/Documentation/devicetree/bindings/sound/sound-card-common.yaml b/Documentation/devicetree/bindings/sound/sound-card-common.yaml index 3a941177f6840a..721950f65748b0 100644 --- a/Documentation/devicetree/bindings/sound/sound-card-common.yaml +++ b/Documentation/devicetree/bindings/sound/sound-card-common.yaml @@ -17,6 +17,13 @@ properties: pair of strings, the first being the connection's sink, the second being the connection's source. + ignore-suspend-widgets: + $ref: /schemas/types.yaml#/definitions/non-unique-string-array + description: | + A list of audio sound widgets which are marked ignoring system suspend. + Paths between these endpoints are still active over suspend of the main + application processor that the current operating system is running. + model: $ref: /schemas/types.yaml#/definitions/string description: User specified audio sound card name diff --git a/Documentation/devicetree/bindings/sound/tas2562.yaml b/Documentation/devicetree/bindings/sound/tas2562.yaml index f01c0dde0cf740..d28c102c0ce7f0 100644 --- a/Documentation/devicetree/bindings/sound/tas2562.yaml +++ b/Documentation/devicetree/bindings/sound/tas2562.yaml @@ -18,7 +18,6 @@ description: | Specifications about the audio amplifier can be found at: https://www.ti.com/lit/gpn/tas2562 - https://www.ti.com/lit/gpn/tas2563 https://www.ti.com/lit/gpn/tas2564 https://www.ti.com/lit/gpn/tas2110 @@ -29,7 +28,6 @@ properties: compatible: enum: - ti,tas2562 - - ti,tas2563 - ti,tas2564 - ti,tas2110 diff --git a/Documentation/devicetree/bindings/sound/ti,tas2781.yaml b/Documentation/devicetree/bindings/sound/ti,tas2781.yaml index a69e6c223308e6..97623868924951 100644 --- a/Documentation/devicetree/bindings/sound/ti,tas2781.yaml +++ b/Documentation/devicetree/bindings/sound/ti,tas2781.yaml @@ -5,36 +5,46 @@ $id: http://devicetree.org/schemas/sound/ti,tas2781.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Texas Instruments TAS2781 SmartAMP +title: Texas Instruments TAS2563/TAS2781 SmartAMP maintainers: - Shenghao Ding -description: - The TAS2781 is a mono, digital input Class-D audio amplifier - optimized for efficiently driving high peak power into small - loudspeakers. An integrated on-chip DSP supports Texas Instruments - Smart Amp speaker protection algorithm. The integrated speaker - voltage and current sense provides for real time +description: | + The TAS2563/TAS2781 is a mono, digital input Class-D audio + amplifier optimized for efficiently driving high peak power into + small loudspeakers. An integrated on-chip DSP supports Texas + Instruments Smart Amp speaker protection algorithm. The + integrated speaker voltage and current sense provides for real time monitoring of loudspeaker behavior. -allOf: - - $ref: dai-common.yaml# + Specifications about the audio amplifier can be found at: + https://www.ti.com/lit/gpn/tas2563 + https://www.ti.com/lit/gpn/tas2781 properties: compatible: - enum: - - ti,tas2781 + description: | + ti,tas2563: 6.1-W Boosted Class-D Audio Amplifier With Integrated + DSP and IV Sense, 16/20/24/32bit stereo I2S or multichannel TDM. + + ti,tas2781: 24-V Class-D Amplifier with Real Time Integrated Speaker + Protection and Audio Processing, 16/20/24/32bit stereo I2S or + multichannel TDM. + oneOf: + - items: + - enum: + - ti,tas2563 + - const: ti,tas2781 + - enum: + - ti,tas2781 reg: description: - I2C address, in multiple tas2781s case, all the i2c address + I2C address, in multiple-AMP case, all the i2c address aggregate as one Audio Device to support multiple audio slots. maxItems: 8 minItems: 1 - items: - minimum: 0x38 - maximum: 0x3f reset-gpios: maxItems: 1 @@ -49,6 +59,44 @@ required: - compatible - reg +allOf: + - $ref: dai-common.yaml# + - if: + properties: + compatible: + contains: + enum: + - ti,tas2563 + then: + properties: + reg: + description: + I2C address, in multiple-AMP case, all the i2c address + aggregate as one Audio Device to support multiple audio slots. + maxItems: 4 + minItems: 1 + items: + minimum: 0x4c + maximum: 0x4f + + - if: + properties: + compatible: + contains: + enum: + - ti,tas2781 + then: + properties: + reg: + description: + I2C address, in multiple-AMP case, all the i2c address + aggregate as one Audio Device to support multiple audio slots. + maxItems: 8 + minItems: 1 + items: + minimum: 0x38 + maximum: 0x3f + additionalProperties: false examples: diff --git a/Documentation/devicetree/bindings/sound/ti,tlv320aic32x4.yaml b/Documentation/devicetree/bindings/sound/ti,tlv320aic32x4.yaml index a7cc9aa3446848..4783e6dbb5c471 100644 --- a/Documentation/devicetree/bindings/sound/ti,tlv320aic32x4.yaml +++ b/Documentation/devicetree/bindings/sound/ti,tlv320aic32x4.yaml @@ -90,7 +90,7 @@ examples: ldoin-supply = <®_3v3>; clocks = <&clks 201>; clock-names = "mclk"; - aic32x4-gpio-func= < + aic32x4-gpio-func = < 0xff /* AIC32X4_MFPX_DEFAULT_VALUE */ 0xff /* AIC32X4_MFPX_DEFAULT_VALUE */ 0x04 /* MFP3 AIC32X4_MFP3_GPIO_ENABLED */ diff --git a/Documentation/devicetree/bindings/spi/adi,axi-spi-engine.txt b/Documentation/devicetree/bindings/spi/adi,axi-spi-engine.txt deleted file mode 100644 index 8a18d71e68791f..00000000000000 --- a/Documentation/devicetree/bindings/spi/adi,axi-spi-engine.txt +++ /dev/null @@ -1,31 +0,0 @@ -Analog Devices AXI SPI Engine controller Device Tree Bindings - -Required properties: -- compatible : Must be "adi,axi-spi-engine-1.00.a"" -- reg : Physical base address and size of the register map. -- interrupts : Property with a value describing the interrupt - number. -- clock-names : List of input clock names - "s_axi_aclk", "spi_clk" -- clocks : Clock phandles and specifiers (See clock bindings for - details on clock-names and clocks). -- #address-cells : Must be <1> -- #size-cells : Must be <0> - -Optional subnodes: - Subnodes are use to represent the SPI slave devices connected to the SPI - master. They follow the generic SPI bindings as outlined in spi-bus.txt. - -Example: - - spi@@44a00000 { - compatible = "adi,axi-spi-engine-1.00.a"; - reg = <0x44a00000 0x1000>; - interrupts = <0 56 4>; - clocks = <&clkc 15 &clkc 15>; - clock-names = "s_axi_aclk", "spi_clk"; - - #address-cells = <1>; - #size-cells = <0>; - - /* SPI devices */ - }; diff --git a/Documentation/devicetree/bindings/spi/adi,axi-spi-engine.yaml b/Documentation/devicetree/bindings/spi/adi,axi-spi-engine.yaml new file mode 100644 index 00000000000000..d48faa42d025b0 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/adi,axi-spi-engine.yaml @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spi/adi,axi-spi-engine.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analog Devices AXI SPI Engine Controller + +description: | + The AXI SPI Engine controller is part of the SPI Engine framework[1] and + allows memory mapped access to the SPI Engine control bus. This allows it + to be used as a general purpose software driven SPI controller as well as + some optional advanced acceleration and offloading capabilities. + + [1] https://wiki.analog.com/resources/fpga/peripherals/spi_engine + +maintainers: + - Michael Hennerich + - Nuno Sá + +allOf: + - $ref: /schemas/spi/spi-controller.yaml# + +properties: + compatible: + const: adi,axi-spi-engine-1.00.a + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: The AXI interconnect clock. + - description: The SPI controller clock. + + clock-names: + items: + - const: s_axi_aclk + - const: spi_clk + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + +unevaluatedProperties: false + +examples: + - | + spi@44a00000 { + compatible = "adi,axi-spi-engine-1.00.a"; + reg = <0x44a00000 0x1000>; + interrupts = <0 56 4>; + clocks = <&clkc 15>, <&clkc 15>; + clock-names = "s_axi_aclk", "spi_clk"; + + #address-cells = <1>; + #size-cells = <0>; + + /* SPI devices */ + }; diff --git a/Documentation/devicetree/bindings/spi/renesas,rspi.yaml b/Documentation/devicetree/bindings/spi/renesas,rspi.yaml index 4d8ec69214c971..0ef3f842198698 100644 --- a/Documentation/devicetree/bindings/spi/renesas,rspi.yaml +++ b/Documentation/devicetree/bindings/spi/renesas,rspi.yaml @@ -21,7 +21,7 @@ properties: - enum: - renesas,rspi-r7s72100 # RZ/A1H - renesas,rspi-r7s9210 # RZ/A2 - - renesas,r9a07g043-rspi # RZ/G2UL + - renesas,r9a07g043-rspi # RZ/G2UL and RZ/Five - renesas,r9a07g044-rspi # RZ/G2{L,LC} - renesas,r9a07g054-rspi # RZ/V2L - const: renesas,rspi-rz diff --git a/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml b/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml index 6348a387a21c31..fde3776a558bcd 100644 --- a/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml +++ b/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml @@ -72,8 +72,6 @@ properties: - const: snps,dw-apb-ssi - description: Intel Keem Bay SPI Controller const: intel,keembay-ssi - - description: Intel Thunder Bay SPI Controller - const: intel,thunderbay-ssi - description: Intel Mount Evans Integrated Management Complex SPI Controller const: intel,mountevans-imc-ssi - description: AMD Pensando Elba SoC SPI Controller diff --git a/Documentation/devicetree/bindings/spi/st,stm32-spi.yaml b/Documentation/devicetree/bindings/spi/st,stm32-spi.yaml index ae0f082bd3772f..4bd9aeb8120859 100644 --- a/Documentation/devicetree/bindings/spi/st,stm32-spi.yaml +++ b/Documentation/devicetree/bindings/spi/st,stm32-spi.yaml @@ -23,7 +23,9 @@ properties: compatible: enum: - st,stm32f4-spi + - st,stm32f7-spi - st,stm32h7-spi + - st,stm32mp25-spi reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/thermal/allwinner,sun8i-a83t-ths.yaml b/Documentation/devicetree/bindings/thermal/allwinner,sun8i-a83t-ths.yaml index fbd4212285e285..9b2272a9ec15d8 100644 --- a/Documentation/devicetree/bindings/thermal/allwinner,sun8i-a83t-ths.yaml +++ b/Documentation/devicetree/bindings/thermal/allwinner,sun8i-a83t-ths.yaml @@ -16,6 +16,7 @@ properties: - allwinner,sun8i-a83t-ths - allwinner,sun8i-h3-ths - allwinner,sun8i-r40-ths + - allwinner,sun20i-d1-ths - allwinner,sun50i-a64-ths - allwinner,sun50i-a100-ths - allwinner,sun50i-h5-ths @@ -61,6 +62,7 @@ allOf: compatible: contains: enum: + - allwinner,sun20i-d1-ths - allwinner,sun50i-a100-ths - allwinner,sun50i-h6-ths @@ -84,7 +86,9 @@ allOf: properties: compatible: contains: - const: allwinner,sun8i-h3-ths + enum: + - allwinner,sun8i-h3-ths + - allwinner,sun20i-d1-ths then: properties: @@ -103,6 +107,7 @@ allOf: enum: - allwinner,sun8i-h3-ths - allwinner,sun8i-r40-ths + - allwinner,sun20i-d1-ths - allwinner,sun50i-a64-ths - allwinner,sun50i-a100-ths - allwinner,sun50i-h5-ths diff --git a/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml b/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml index 7538469997f9e1..b634f57cd011d7 100644 --- a/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml +++ b/Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml @@ -10,6 +10,9 @@ maintainers: - zhanghongchen - Yinbo Zhu +allOf: + - $ref: /schemas/thermal/thermal-sensor.yaml# + properties: compatible: oneOf: @@ -26,12 +29,16 @@ properties: interrupts: maxItems: 1 + '#thermal-sensor-cells': + const: 1 + required: - compatible - reg - interrupts + - '#thermal-sensor-cells' -additionalProperties: false +unevaluatedProperties: false examples: - | @@ -41,4 +48,5 @@ examples: reg = <0x1fe01500 0x30>; interrupt-parent = <&liointc0>; interrupts = <7 IRQ_TYPE_LEVEL_LOW>; + #thermal-sensor-cells = <1>; }; diff --git a/Documentation/devicetree/bindings/thermal/mediatek,thermal.yaml b/Documentation/devicetree/bindings/thermal/mediatek,thermal.yaml new file mode 100644 index 00000000000000..d96a2e32bd8fd3 --- /dev/null +++ b/Documentation/devicetree/bindings/thermal/mediatek,thermal.yaml @@ -0,0 +1,99 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/thermal/mediatek,thermal.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Mediatek thermal controller for on-SoC temperatures + +maintainers: + - Sascha Hauer + +description: + This device does not have its own ADC, instead it directly controls the AUXADC + via AHB bus accesses. For this reason it needs phandles to the AUXADC. Also it + controls a mux in the apmixedsys register space via AHB bus accesses, so a + phandle to the APMIXEDSYS is also needed. + +allOf: + - $ref: thermal-sensor.yaml# + +properties: + compatible: + enum: + - mediatek,mt2701-thermal + - mediatek,mt2712-thermal + - mediatek,mt7622-thermal + - mediatek,mt7981-thermal + - mediatek,mt7986-thermal + - mediatek,mt8173-thermal + - mediatek,mt8183-thermal + - mediatek,mt8365-thermal + - mediatek,mt8516-thermal + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: Main clock needed for register access + - description: The AUXADC clock + + clock-names: + items: + - const: therm + - const: auxadc + + mediatek,auxadc: + $ref: /schemas/types.yaml#/definitions/phandle + description: A phandle to the AUXADC which the thermal controller uses + + mediatek,apmixedsys: + $ref: /schemas/types.yaml#/definitions/phandle + description: A phandle to the APMIXEDSYS controller + + resets: + description: Reset controller controlling the thermal controller + + nvmem-cells: + items: + - description: + NVMEM cell with EEPROMA phandle to the calibration data provided by an + NVMEM device. If unspecified default values shall be used. + + nvmem-cell-names: + items: + - const: calibration-data + +required: + - reg + - interrupts + - clocks + - clock-names + - mediatek,auxadc + - mediatek,apmixedsys + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + + thermal@1100b000 { + compatible = "mediatek,mt8173-thermal"; + reg = <0x1100b000 0x1000>; + interrupts = <0 70 IRQ_TYPE_LEVEL_LOW>; + clocks = <&pericfg CLK_PERI_THERM>, <&pericfg CLK_PERI_AUXADC>; + clock-names = "therm", "auxadc"; + resets = <&pericfg MT8173_PERI_THERM_SW_RST>; + mediatek,auxadc = <&auxadc>; + mediatek,apmixedsys = <&apmixedsys>; + nvmem-cells = <&thermal_calibration_data>; + nvmem-cell-names = "calibration-data"; + #thermal-sensor-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/thermal/mediatek-thermal.txt b/Documentation/devicetree/bindings/thermal/mediatek-thermal.txt deleted file mode 100644 index ac39c7156fdec8..00000000000000 --- a/Documentation/devicetree/bindings/thermal/mediatek-thermal.txt +++ /dev/null @@ -1,52 +0,0 @@ -* Mediatek Thermal - -This describes the device tree binding for the Mediatek thermal controller -which measures the on-SoC temperatures. This device does not have its own ADC, -instead it directly controls the AUXADC via AHB bus accesses. For this reason -this device needs phandles to the AUXADC. Also it controls a mux in the -apmixedsys register space via AHB bus accesses, so a phandle to the APMIXEDSYS -is also needed. - -Required properties: -- compatible: - - "mediatek,mt8173-thermal" : For MT8173 family of SoCs - - "mediatek,mt2701-thermal" : For MT2701 family of SoCs - - "mediatek,mt2712-thermal" : For MT2712 family of SoCs - - "mediatek,mt7622-thermal" : For MT7622 SoC - - "mediatek,mt7981-thermal", "mediatek,mt7986-thermal" : For MT7981 SoC - - "mediatek,mt7986-thermal" : For MT7986 SoC - - "mediatek,mt8183-thermal" : For MT8183 family of SoCs - - "mediatek,mt8365-thermal" : For MT8365 family of SoCs - - "mediatek,mt8516-thermal", "mediatek,mt2701-thermal : For MT8516 family of SoCs -- reg: Address range of the thermal controller -- interrupts: IRQ for the thermal controller -- clocks, clock-names: Clocks needed for the thermal controller. required - clocks are: - "therm": Main clock needed for register access - "auxadc": The AUXADC clock -- mediatek,auxadc: A phandle to the AUXADC which the thermal controller uses -- mediatek,apmixedsys: A phandle to the APMIXEDSYS controller. -- #thermal-sensor-cells : Should be 0. See Documentation/devicetree/bindings/thermal/thermal-sensor.yaml for a description. - -Optional properties: -- resets: Reference to the reset controller controlling the thermal controller. -- nvmem-cells: A phandle to the calibration data provided by a nvmem device. If - unspecified default values shall be used. -- nvmem-cell-names: Should be "calibration-data" - -Example: - - thermal: thermal@1100b000 { - #thermal-sensor-cells = <1>; - compatible = "mediatek,mt8173-thermal"; - reg = <0 0x1100b000 0 0x1000>; - interrupts = <0 70 IRQ_TYPE_LEVEL_LOW>; - clocks = <&pericfg CLK_PERI_THERM>, <&pericfg CLK_PERI_AUXADC>; - clock-names = "therm", "auxadc"; - resets = <&pericfg MT8173_PERI_THERM_SW_RST>; - reset-names = "therm"; - mediatek,auxadc = <&auxadc>; - mediatek,apmixedsys = <&apmixedsys>; - nvmem-cells = <&thermal_calibration_data>; - nvmem-cell-names = "calibration-data"; - }; diff --git a/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm-hc.yaml b/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm-hc.yaml index 01253d58bf9fa3..7541e27704cad6 100644 --- a/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm-hc.yaml +++ b/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm-hc.yaml @@ -114,12 +114,14 @@ examples: - | #include #include - spmi_bus { + + pmic { #address-cells = <1>; #size-cells = <0>; + pm8998_adc: adc@3100 { - reg = <0x3100>; compatible = "qcom,spmi-adc-rev2"; + reg = <0x3100>; #address-cells = <1>; #size-cells = <0>; #io-channel-cells = <1>; @@ -130,7 +132,7 @@ examples: }; }; - pm8998_adc_tm: adc-tm@3400 { + adc-tm@3400 { compatible = "qcom,spmi-adc-tm-hc"; reg = <0x3400>; interrupts = <0x2 0x34 0x0 IRQ_TYPE_EDGE_RISING>; diff --git a/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm5.yaml b/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm5.yaml index 3c81def03c84c7..d9d2657287cb48 100644 --- a/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm5.yaml +++ b/Documentation/devicetree/bindings/thermal/qcom-spmi-adc-tm5.yaml @@ -167,12 +167,14 @@ examples: - | #include #include - spmi_bus { + + pmic { #address-cells = <1>; #size-cells = <0>; + pm8150b_adc: adc@3100 { - reg = <0x3100>; compatible = "qcom,spmi-adc5"; + reg = <0x3100>; #address-cells = <1>; #size-cells = <0>; #io-channel-cells = <1>; @@ -186,7 +188,7 @@ examples: }; }; - pm8150b_adc_tm: adc-tm@3500 { + adc-tm@3500 { compatible = "qcom,spmi-adc-tm5"; reg = <0x3500>; interrupts = <0x2 0x35 0x0 IRQ_TYPE_EDGE_RISING>; @@ -207,12 +209,14 @@ examples: #include #include #include - spmi_bus { + + pmic { #address-cells = <1>; #size-cells = <0>; + pmk8350_vadc: adc@3100 { - reg = <0x3100>; compatible = "qcom,spmi-adc7"; + reg = <0x3100>; #address-cells = <1>; #size-cells = <0>; #io-channel-cells = <1>; @@ -233,7 +237,7 @@ examples: }; }; - pmk8350_adc_tm: adc-tm@3400 { + adc-tm@3400 { compatible = "qcom,spmi-adc-tm5-gen2"; reg = <0x3400>; interrupts = <0x0 0x34 0x0 IRQ_TYPE_EDGE_RISING>; diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml index 437b74732886fe..99d9c526c0b6b4 100644 --- a/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml +++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.yaml @@ -66,6 +66,7 @@ properties: - qcom,sm8350-tsens - qcom,sm8450-tsens - qcom,sm8550-tsens + - qcom,sm8650-tsens - const: qcom,tsens-v2 - description: v2 of TSENS with combined interrupt diff --git a/Documentation/devicetree/bindings/thermal/thermal-zones.yaml b/Documentation/devicetree/bindings/thermal/thermal-zones.yaml index 4a8dabc481700e..dbd52620d29306 100644 --- a/Documentation/devicetree/bindings/thermal/thermal-zones.yaml +++ b/Documentation/devicetree/bindings/thermal/thermal-zones.yaml @@ -75,6 +75,22 @@ patternProperties: framework and assumes that the thermal sensors in this zone support interrupts. + critical-action: + $ref: /schemas/types.yaml#/definitions/string + description: | + The action the OS should perform after the critical temperature is reached. + By default the system will shutdown as a safe action to prevent damage + to the hardware, if the property is not set. + The shutdown action should be always the default and preferred one. + Choose 'reboot' with care, as the hardware may be in thermal stress, + thus leading to infinite reboots that may cause damage to the hardware. + Make sure the firmware/bootloader will act as the last resort and take + over the thermal control. + + enum: + - shutdown + - reboot + thermal-sensors: $ref: /schemas/types.yaml#/definitions/phandle-array maxItems: 1 diff --git a/Documentation/devicetree/bindings/timer/sifive,clint.yaml b/Documentation/devicetree/bindings/timer/sifive,clint.yaml index e8be6c4703640f..fced6f2d8ecbb3 100644 --- a/Documentation/devicetree/bindings/timer/sifive,clint.yaml +++ b/Documentation/devicetree/bindings/timer/sifive,clint.yaml @@ -33,11 +33,13 @@ properties: - sifive,fu540-c000-clint # SiFive FU540 - starfive,jh7100-clint # StarFive JH7100 - starfive,jh7110-clint # StarFive JH7110 + - starfive,jh8100-clint # StarFive JH8100 - const: sifive,clint0 # SiFive CLINT v0 IP block - items: - enum: - allwinner,sun20i-d1-clint - sophgo,cv1800b-clint + - sophgo,cv1812h-clint - thead,th1520-clint - const: thead,c900-clint - items: diff --git a/Documentation/devicetree/bindings/timer/thead,c900-aclint-mtimer.yaml b/Documentation/devicetree/bindings/timer/thead,c900-aclint-mtimer.yaml index fbd235650e52cc..2e92bcdeb423ab 100644 --- a/Documentation/devicetree/bindings/timer/thead,c900-aclint-mtimer.yaml +++ b/Documentation/devicetree/bindings/timer/thead,c900-aclint-mtimer.yaml @@ -17,7 +17,12 @@ properties: - const: thead,c900-aclint-mtimer reg: - maxItems: 1 + items: + - description: MTIMECMP Registers + + reg-names: + items: + - const: mtimecmp interrupts-extended: minItems: 1 @@ -28,6 +33,7 @@ additionalProperties: false required: - compatible - reg + - reg-names - interrupts-extended examples: @@ -39,5 +45,6 @@ examples: <&cpu3intc 7>, <&cpu4intc 7>; reg = <0xac000000 0x00010000>; + reg-names = "mtimecmp"; }; ... diff --git a/Documentation/devicetree/bindings/tpm/google,cr50.yaml b/Documentation/devicetree/bindings/tpm/google,cr50.yaml new file mode 100644 index 00000000000000..9302e12e9fc7f9 --- /dev/null +++ b/Documentation/devicetree/bindings/tpm/google,cr50.yaml @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/tpm/google,cr50.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Google Security Chip H1 (running Cr50 firmware) + +maintainers: + - Andrey Pronin + +description: | + Google has designed a family of security chips called "Titan". + One member is the H1 built into Chromebooks and running Cr50 firmware: + https://www.osfc.io/2018/talks/google-secure-microcontroller-and-ccd-closed-case-debugging/ + + The chip provides several functions, including TPM 2.0 like functionality. + It communicates over SPI or I²C using the FIFO protocol described in the + TCG PC Client Platform TPM Profile Specification for TPM 2.0 (PTP), sec 6: + https://trustedcomputinggroup.org/resource/pc-client-platform-tpm-profile-ptp-specification/ + +properties: + compatible: + const: google,cr50 + +allOf: + - $ref: tpm-common.yaml# + +anyOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + - $ref: tcg,tpm-tis-i2c.yaml#/properties/reg + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + + tpm@0 { + reg = <0>; + compatible = "google,cr50"; + spi-max-frequency = <800000>; + }; + }; + + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + tpm@50 { + compatible = "google,cr50"; + reg = <0x50>; + interrupts-extended = <&pio 88 IRQ_TYPE_EDGE_FALLING>; + pinctrl-names = "default"; + pinctrl-0 = <&cr50_int>; + }; + }; diff --git a/Documentation/devicetree/bindings/tpm/ibm,vtpm.yaml b/Documentation/devicetree/bindings/tpm/ibm,vtpm.yaml new file mode 100644 index 00000000000000..50a3fd31241cb3 --- /dev/null +++ b/Documentation/devicetree/bindings/tpm/ibm,vtpm.yaml @@ -0,0 +1,104 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/tpm/ibm,vtpm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: IBM Virtual Trusted Platform Module (vTPM) + +maintainers: + - Nayna Jain + +description: | + Virtual TPM is used on IBM POWER7+ and POWER8 systems running POWERVM. + It is supported through the adjunct partition with firmware release 740 + or higher. With vTPM support, each lpar is able to have its own vTPM + without the physical TPM hardware. The TPM functionality is provided by + communicating with the vTPM adjunct partition through Hypervisor calls + (Hcalls) and Command/Response Queue (CRQ) commands. + +properties: + compatible: + enum: + - IBM,vtpm + - IBM,vtpm20 + + device_type: + description: + type of virtual device + enum: + - IBM,vtpm + - IBM,vtpm20 + + reg: + maxItems: 1 + + 'ibm,#dma-address-cells': + description: + number of cells that are used to encode the physical address field of + dma-window properties + $ref: /schemas/types.yaml#/definitions/uint32-array + + 'ibm,#dma-size-cells': + description: + number of cells that are used to encode the size field of + dma-window properties + $ref: /schemas/types.yaml#/definitions/uint32-array + + ibm,my-dma-window: + description: + DMA window associated with this virtual I/O Adapter + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 5 + maxItems: 5 + + ibm,my-drc-index: + description: + integer index for the connector between the device and its parent; + present only if Dynamic Reconfiguration (DR) Connector is enabled + $ref: /schemas/types.yaml#/definitions/uint32 + + ibm,loc-code: + description: + unique and persistent location code associated with this virtual + I/O Adapter + $ref: /schemas/types.yaml#/definitions/string + +required: + - compatible + - device_type + - reg + - interrupts + - ibm,#dma-address-cells + - ibm,#dma-size-cells + - ibm,my-dma-window + - ibm,my-drc-index + - ibm,loc-code + - linux,sml-base + - linux,sml-size + +allOf: + - $ref: tpm-common.yaml# + +unevaluatedProperties: false + +examples: + - | + soc { + #address-cells = <1>; + #size-cells = <0>; + + tpm@30000003 { + compatible = "IBM,vtpm"; + device_type = "IBM,vtpm"; + reg = <0x30000003>; + interrupts = <0xa0003 0x0>; + ibm,#dma-address-cells = <0x2>; + ibm,#dma-size-cells = <0x2>; + ibm,my-dma-window = <0x10000003 0x0 0x0 0x0 0x10000000>; + ibm,my-drc-index = <0x30000003>; + ibm,loc-code = "U8286.41A.10082DV-V3-C3"; + linux,sml-base = <0xc60e 0x0>; + linux,sml-size = <0xbce10200>; + }; + }; diff --git a/Documentation/devicetree/bindings/tpm/microsoft,ftpm.yaml b/Documentation/devicetree/bindings/tpm/microsoft,ftpm.yaml new file mode 100644 index 00000000000000..fdb81968f03d66 --- /dev/null +++ b/Documentation/devicetree/bindings/tpm/microsoft,ftpm.yaml @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/tpm/microsoft,ftpm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Microsoft firmware-based Trusted Platform Module (fTPM) + +maintainers: + - Thirupathaiah Annapureddy + - Sasha Levin + +description: | + Commodity CPU architectures, such as ARM and Intel CPUs, have started to + offer trusted computing features in their CPUs aimed at displacing dedicated + trusted hardware. Unfortunately, these CPU architectures raise serious + challenges to building trusted systems because they omit providing secure + resources outside the CPU perimeter. + + Microsoft's firmware-based TPM 2.0 (fTPM) leverages ARM TrustZone to overcome + these challenges and provide software with security guarantees similar to + those of dedicated trusted hardware. + + https://www.microsoft.com/en-us/research/publication/ftpm-software-implementation-tpm-chip/ + https://github.com/Microsoft/ms-tpm-20-ref/tree/main/Samples/ARM32-FirmwareTPM + +properties: + compatible: + const: microsoft,ftpm + +required: + - compatible + - linux,sml-base + - linux,sml-size + +allOf: + - $ref: tpm-common.yaml# + +unevaluatedProperties: false + +examples: + - | + tpm { + compatible = "microsoft,ftpm"; + linux,sml-base = <0x0 0xc0000000>; + linux,sml-size = <0x10000>; + }; diff --git a/Documentation/devicetree/bindings/tpm/tcg,tpm-tis-i2c.yaml b/Documentation/devicetree/bindings/tpm/tcg,tpm-tis-i2c.yaml new file mode 100644 index 00000000000000..3ab4434b73524f --- /dev/null +++ b/Documentation/devicetree/bindings/tpm/tcg,tpm-tis-i2c.yaml @@ -0,0 +1,90 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/tpm/tcg,tpm-tis-i2c.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: I²C-attached Trusted Platform Module conforming to TCG TIS specification + +maintainers: + - Lukas Wunner + +description: | + The Trusted Computing Group (TCG) has defined a multi-vendor standard + for accessing a TPM chip. It can be transported over various buses, + one of them being I²C. The standard is named: + TCG PC Client Specific TPM Interface Specification (TIS) + https://trustedcomputinggroup.org/resource/pc-client-work-group-pc-client-specific-tpm-interface-specification-tis/ + + The I²C interface was not originally part of the standard, but added + in 2017 with a separate document: + TCG PC Client Platform TPM Profile Specification for TPM 2.0 (PTP) + https://trustedcomputinggroup.org/resource/pc-client-platform-tpm-profile-ptp-specification/ + + Recent TPM 2.0 chips conform to this generic interface, others use a + vendor-specific I²C interface. + +properties: + compatible: + oneOf: + - description: Generic TPM 2.0 chips conforming to TCG PTP interface + items: + - enum: + - infineon,slb9673 + - nuvoton,npct75x + - const: tcg,tpm-tis-i2c + + - description: TPM 1.2 and 2.0 chips with vendor-specific I²C interface + items: + - enum: + - atmel,at97sc3204t # TPM 1.2 + - infineon,slb9635tt # TPM 1.2 (maximum 100 kHz) + - infineon,slb9645tt # TPM 1.2 (maximum 400 kHz) + - infineon,tpm_i2c_infineon # TPM 1.2 + - nuvoton,npct501 # TPM 1.2 + - nuvoton,npct601 # TPM 2.0 + - st,st33zp24-i2c # TPM 2.0 + - winbond,wpct301 # TPM 1.2 + + reg: + description: address of TPM on the I²C bus + +allOf: + - $ref: tpm-common.yaml# + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + tpm@57 { + label = "tpm"; + compatible = "nuvoton,npct601"; + reg = <0x57>; + linux,sml-base = <0x7f 0xfd450000>; + linux,sml-size = <0x10000>; + }; + }; + + - | + #include + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + tpm@13 { + reg = <0x13>; + compatible = "st,st33zp24-i2c"; + interrupt-parent = <&gpio5>; + interrupts = <7 IRQ_TYPE_LEVEL_HIGH>; + lpcpd-gpios = <&gpio5 15 GPIO_ACTIVE_HIGH>; + }; + }; diff --git a/Documentation/devicetree/bindings/tpm/tcg,tpm-tis-mmio.yaml b/Documentation/devicetree/bindings/tpm/tcg,tpm-tis-mmio.yaml new file mode 100644 index 00000000000000..87bce0692129f3 --- /dev/null +++ b/Documentation/devicetree/bindings/tpm/tcg,tpm-tis-mmio.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/tpm/tcg,tpm-tis-mmio.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MMIO-accessed Trusted Platform Module conforming to TCG TIS specification + +maintainers: + - Lukas Wunner + +description: | + The Trusted Computing Group (TCG) has defined a multi-vendor standard + for accessing a TPM chip. It can be transported over various buses, + one of them being LPC (via MMIO). The standard is named: + TCG PC Client Specific TPM Interface Specification (TIS) + https://trustedcomputinggroup.org/resource/pc-client-work-group-pc-client-specific-tpm-interface-specification-tis/ + +properties: + compatible: + items: + - enum: + - at97sc3201 + - atmel,at97sc3204 + - socionext,synquacer-tpm-mmio + - const: tcg,tpm-tis-mmio + + reg: + description: + location and length of the MMIO registers, length should be + at least 0x5000 bytes + +allOf: + - $ref: tpm-common.yaml# + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + tpm@90000 { + compatible = "atmel,at97sc3204", "tcg,tpm-tis-mmio"; + reg = <0x90000 0x5000>; + interrupt-parent = <&EIC0>; + interrupts = <1 2>; + }; diff --git a/Documentation/devicetree/bindings/tpm/tcg,tpm_tis-spi.yaml b/Documentation/devicetree/bindings/tpm/tcg,tpm_tis-spi.yaml new file mode 100644 index 00000000000000..c3413b47ac3df9 --- /dev/null +++ b/Documentation/devicetree/bindings/tpm/tcg,tpm_tis-spi.yaml @@ -0,0 +1,75 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/tpm/tcg,tpm_tis-spi.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: SPI-attached Trusted Platform Module conforming to TCG TIS specification + +maintainers: + - Lukas Wunner + +description: | + The Trusted Computing Group (TCG) has defined a multi-vendor standard + for accessing a TPM chip. It can be transported over various buses, + one of them being SPI. The standard is named: + TCG PC Client Specific TPM Interface Specification (TIS) + https://trustedcomputinggroup.org/resource/pc-client-work-group-pc-client-specific-tpm-interface-specification-tis/ + +properties: + compatible: + items: + - enum: + - infineon,slb9670 + - st,st33htpm-spi + - st,st33zp24-spi + - const: tcg,tpm_tis-spi + +allOf: + - $ref: tpm-common.yaml# + - $ref: /schemas/spi/spi-peripheral-props.yaml# + - if: + properties: + compatible: + contains: + const: st,st33zp24-spi + then: + properties: + spi-max-frequency: + maximum: 10000000 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + + tpm@0 { + reg = <0>; + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; + spi-max-frequency = <10000000>; + }; + }; + + - | + #include + #include + spi { + #address-cells = <1>; + #size-cells = <0>; + + tpm@0 { + reg = <0>; + compatible = "st,st33zp24-spi", "tcg,tpm_tis-spi"; + spi-max-frequency = <10000000>; + interrupt-parent = <&gpio5>; + interrupts = <7 IRQ_TYPE_LEVEL_HIGH>; + lpcpd-gpios = <&gpio5 15 GPIO_ACTIVE_HIGH>; + }; + }; diff --git a/Documentation/devicetree/bindings/tpm/tpm-common.yaml b/Documentation/devicetree/bindings/tpm/tpm-common.yaml new file mode 100644 index 00000000000000..90390624a8be5e --- /dev/null +++ b/Documentation/devicetree/bindings/tpm/tpm-common.yaml @@ -0,0 +1,87 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/tpm/tpm-common.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Trusted Platform Module common properties + +maintainers: + - Lukas Wunner + +properties: + $nodename: + pattern: '^tpm(@[0-9a-f]+)?$' + + interrupts: + description: indicates command completion + maxItems: 1 + + label: + description: human readable string describing the device, e.g. "tpm" + + linux,sml-base: + description: + base address of reserved memory allocated for firmware event log + $ref: /schemas/types.yaml#/definitions/uint64 + + linux,sml-size: + description: + size of reserved memory allocated for firmware event log + $ref: /schemas/types.yaml#/definitions/uint32 + + memory-region: + description: reserved memory allocated for firmware event log + maxItems: 1 + + powered-while-suspended: + description: + present when the TPM is left powered on between suspend and resume + (makes the suspend/resume callbacks do nothing) + type: boolean + + resets: + description: Reset controller to reset the TPM + $ref: /schemas/types.yaml#/definitions/phandle + + reset-gpios: + description: Output GPIO pin to reset the TPM + maxItems: 1 + +# must always have both linux,sml-base and linux,sml-size +dependentRequired: + linux,sml-base: ['linux,sml-size'] + linux,sml-size: ['linux,sml-base'] + +# must only have either memory-region or linux,sml-base +# as well as either resets or reset-gpios +dependentSchemas: + memory-region: + properties: + linux,sml-base: false + linux,sml-base: + properties: + memory-region: false + resets: + properties: + reset-gpios: false + reset-gpios: + properties: + resets: false + +allOf: + - if: + properties: + compatible: + contains: + pattern: '^st,st33zp24' + then: + properties: + lpcpd-gpios: + description: + Output GPIO pin used for ST33ZP24 power management of D1/D2 state. + If set, power must be present when the platform is going into + sleep/hibernate mode. + maxItems: 1 + +additionalProperties: true diff --git a/Documentation/devicetree/bindings/trivial-devices.yaml b/Documentation/devicetree/bindings/trivial-devices.yaml index c3190f2a168a22..79dcd92c4a4345 100644 --- a/Documentation/devicetree/bindings/trivial-devices.yaml +++ b/Documentation/devicetree/bindings/trivial-devices.yaml @@ -49,8 +49,6 @@ properties: - ams,iaq-core # i2c serial eeprom (24cxx) - at,24c08 - # i2c trusted platform module (TPM) - - atmel,at97sc3204t # ATSHA204 - i2c h/w symmetric crypto module - atmel,atsha204 # ATSHA204A - i2c h/w symmetric crypto module @@ -117,6 +115,10 @@ properties: - fsl,mpl3115 # MPR121: Proximity Capacitive Touch Sensor Controller - fsl,mpr121 + # Monolithic Power Systems Inc. multi-phase controller mp2856 + - mps,mp2856 + # Monolithic Power Systems Inc. multi-phase controller mp2857 + - mps,mp2857 # Monolithic Power Systems Inc. multi-phase controller mp2888 - mps,mp2888 # Monolithic Power Systems Inc. multi-phase controller mp2971 @@ -125,6 +127,8 @@ properties: - mps,mp2973 # Monolithic Power Systems Inc. multi-phase controller mp2975 - mps,mp2975 + # Monolithic Power Systems Inc. multi-phase hot-swap controller mp5990 + - mps,mp5990 # Honeywell Humidicon HIH-6130 humidity/temperature sensor - honeywell,hi6130 # IBM Common Form Factor Power Supply Versions (all versions) @@ -145,12 +149,6 @@ properties: - infineon,ir38263 # Infineon IRPS5401 Voltage Regulator (PMIC) - infineon,irps5401 - # Infineon SLB9635 (Soft-) I2C TPM (old protocol, max 100khz) - - infineon,slb9635tt - # Infineon SLB9645 I2C TPM (new protocol, max 400khz) - - infineon,slb9645tt - # Infineon SLB9673 I2C TPM 2.0 - - infineon,slb9673 # Infineon TLV493D-A1B6 I2C 3D Magnetic Sensor - infineon,tlv493d-a1b6 # Infineon Multi-phase Digital VR Controller xdpe11280 @@ -179,6 +177,8 @@ properties: - isil,isl29030 # Intersil ISL68137 Digital Output Configurable PWM Controller - isil,isl68137 + # Intersil ISL76682 Ambient Light Sensor + - isil,isl76682 # Linear Technology LTC2488 - lineartechnology,ltc2488 # 5 Bit Programmable, Pulse-Width Modulator @@ -301,10 +301,6 @@ properties: - national,lm85 # I2C ±0.33°C Accurate, 12-Bit + Sign Temperature Sensor and Thermal Window Comparator - national,lm92 - # i2c trusted platform module (TPM) - - nuvoton,npct501 - # i2c trusted platform module (TPM2) - - nuvoton,npct601 # Nuvoton Temperature Sensor - nuvoton,w83773g # OKI ML86V7667 video decoder @@ -349,8 +345,6 @@ properties: - silabs,si7020 # Skyworks SKY81452: Six-Channel White LED Driver with Touch Panel Bias Supply - skyworks,sky81452 - # Socionext SynQuacer TPM MMIO module - - socionext,synquacer-tpm-mmio # SparkFun Qwiic Joystick (COM-15168) with i2c interface - sparkfun,qwiic-joystick # i2c serial eeprom (24cxx) @@ -405,8 +399,6 @@ properties: - winbond,w83793 # Vicor Corporation Digital Supervisor - vicor,pli1209bc - # i2c trusted platform module (TPM) - - winbond,wpct301 required: - compatible diff --git a/Documentation/devicetree/bindings/ufs/qcom,ufs.yaml b/Documentation/devicetree/bindings/ufs/qcom,ufs.yaml index 2cf3d016db42c1..10c146424baa1e 100644 --- a/Documentation/devicetree/bindings/ufs/qcom,ufs.yaml +++ b/Documentation/devicetree/bindings/ufs/qcom,ufs.yaml @@ -27,6 +27,7 @@ properties: - qcom,msm8996-ufshc - qcom,msm8998-ufshc - qcom,sa8775p-ufshc + - qcom,sc7280-ufshc - qcom,sc8280xp-ufshc - qcom,sdm845-ufshc - qcom,sm6115-ufshc @@ -118,6 +119,7 @@ allOf: enum: - qcom,msm8998-ufshc - qcom,sa8775p-ufshc + - qcom,sc7280-ufshc - qcom,sc8280xp-ufshc - qcom,sm8250-ufshc - qcom,sm8350-ufshc diff --git a/Documentation/devicetree/bindings/ufs/ufs-common.yaml b/Documentation/devicetree/bindings/ufs/ufs-common.yaml index 985ea8f64de803..31fe7f30ff5b8d 100644 --- a/Documentation/devicetree/bindings/ufs/ufs-common.yaml +++ b/Documentation/devicetree/bindings/ufs/ufs-common.yaml @@ -87,6 +87,8 @@ properties: description: Specifies max. load that can be drawn from VCCQ2 supply. + msi-parent: true + dependencies: freq-table-hz: [ clocks ] operating-points-v2: [ clocks, clock-names ] diff --git a/Documentation/devicetree/bindings/usb/generic-xhci.yaml b/Documentation/devicetree/bindings/usb/generic-xhci.yaml index 594ebb3ee43203..6ceafa4af29221 100644 --- a/Documentation/devicetree/bindings/usb/generic-xhci.yaml +++ b/Documentation/devicetree/bindings/usb/generic-xhci.yaml @@ -9,9 +9,6 @@ title: USB xHCI Controller maintainers: - Mathias Nyman -allOf: - - $ref: usb-xhci.yaml# - properties: compatible: oneOf: @@ -25,6 +22,11 @@ properties: - marvell,armada-380-xhci - marvell,armada-8k-xhci - const: generic-xhci + - description: Broadcom SoCs with power domains + items: + - enum: + - brcm,bcm2711-xhci + - const: brcm,xhci-brcm-v2 - description: Broadcom STB SoCs with xHCI enum: - brcm,xhci-brcm-v2 @@ -49,6 +51,9 @@ properties: - const: core - const: reg + power-domains: + maxItems: 1 + unevaluatedProperties: false required: @@ -56,6 +61,20 @@ required: - reg - interrupts +allOf: + - $ref: usb-xhci.yaml# + - if: + properties: + compatible: + contains: + const: brcm,bcm2711-xhci + then: + required: + - power-domains + else: + properties: + power-domains: false + examples: - | usb@f0931000 { diff --git a/Documentation/devicetree/bindings/usb/genesys,gl850g.yaml b/Documentation/devicetree/bindings/usb/genesys,gl850g.yaml index ee08b9c3721f89..37cf5249e526bb 100644 --- a/Documentation/devicetree/bindings/usb/genesys,gl850g.yaml +++ b/Documentation/devicetree/bindings/usb/genesys,gl850g.yaml @@ -29,6 +29,11 @@ properties: description: the regulator that provides 3.3V core power to the hub. + peer-hub: + $ref: /schemas/types.yaml#/definitions/phandle + description: + phandle to the peer hub on the controller. + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml index e9644e333d7813..924fd3d748a881 100644 --- a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml +++ b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml @@ -124,6 +124,17 @@ properties: defined in the xHCI spec on MTK's controller. default: 5000 + rx-fifo-depth: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + It is a quirk used to work around Gen1 isoc-in endpoint transfer issue + that still send out unexpected ACK after device finishes the burst + transfer with a short packet and cause an exception, specially on a 4K + camera device, it happens on controller before about IPM v1.6.0; + the side-effect is that it may cause performance drop about 10%, + including bulk transfer, prefer to use 3k here. The size is in bytes. + enum: [1024, 2048, 3072, 4096] + # the following properties are only used for case 1 wakeup-source: description: enable USB remote wakeup, see power/wakeup-source.txt diff --git a/Documentation/devicetree/bindings/usb/nxp,ptn5110.yaml b/Documentation/devicetree/bindings/usb/nxp,ptn5110.yaml index 28eb25ecba74ee..eaedb4cc6b6cce 100644 --- a/Documentation/devicetree/bindings/usb/nxp,ptn5110.yaml +++ b/Documentation/devicetree/bindings/usb/nxp,ptn5110.yaml @@ -4,7 +4,7 @@ $id: http://devicetree.org/schemas/usb/nxp,ptn5110.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: NXP PTN5110 Typec Port Cotroller +title: NXP PTN5110 Type-C Port Controller maintainers: - Li Jun diff --git a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml index 915c8205623b3a..63d150b216c528 100644 --- a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml @@ -46,6 +46,8 @@ properties: - qcom,sm8350-dwc3 - qcom,sm8450-dwc3 - qcom,sm8550-dwc3 + - qcom,sm8650-dwc3 + - qcom,x1e80100-dwc3 - const: qcom,dwc3 reg: @@ -97,12 +99,29 @@ properties: - const: apps-usb interrupts: - minItems: 1 - maxItems: 4 + description: | + Different types of interrupts are used based on HS PHY used on target: + - pwr_event: Used for wakeup based on other power events. + - hs_phY_irq: Apart from DP/DM/QUSB2 PHY interrupts, there is + hs_phy_irq which is not triggered by default and its + functionality is mutually exclusive to that of + {dp/dm}_hs_phy_irq and qusb2_phy_irq. + - qusb2_phy: SoCs with QUSB2 PHY do not have separate DP/DM IRQs and + expose only a single IRQ whose behavior can be modified + by the QUSB2PHY_INTR_CTRL register. The required DPSE/ + DMSE configuration is done in QUSB2PHY_INTR_CTRL register + of PHY address space. + - {dp/dm}_hs_phy_irq: These IRQ's directly reflect changes on the DP/ + DM pads of the SoC. These are used for wakeup + only on SoCs with non-QUSB2 targets with + exception of SDM670/SDM845/SM6350. + - ss_phy_irq: Used for remote wakeup in Super Speed mode of operation. + minItems: 2 + maxItems: 5 interrupt-names: - minItems: 1 - maxItems: 4 + minItems: 2 + maxItems: 5 qcom,select-utmi-as-pipe-clk: description: @@ -263,6 +282,7 @@ allOf: contains: enum: - qcom,sc8280xp-dwc3 + - qcom,x1e80100-dwc3 then: properties: clocks: @@ -288,8 +308,8 @@ allOf: then: properties: clocks: - minItems: 5 - maxItems: 6 + minItems: 4 + maxItems: 5 clock-names: oneOf: - items: @@ -298,13 +318,11 @@ allOf: - const: iface - const: sleep - const: mock_utmi - - const: bus - items: - const: cfg_noc - const: core - const: sleep - const: mock_utmi - - const: bus - if: properties: @@ -318,6 +336,7 @@ allOf: - qcom,sm8250-dwc3 - qcom,sm8450-dwc3 - qcom,sm8550-dwc3 + - qcom,sm8650-dwc3 then: properties: clocks: @@ -357,59 +376,20 @@ allOf: compatible: contains: enum: - - qcom,ipq4019-dwc3 + - qcom,ipq5018-dwc3 - qcom,ipq6018-dwc3 - - qcom,ipq8064-dwc3 - qcom,ipq8074-dwc3 - - qcom,msm8994-dwc3 - - qcom,qcs404-dwc3 - - qcom,sc7180-dwc3 - - qcom,sdm670-dwc3 - - qcom,sdm845-dwc3 - - qcom,sdx55-dwc3 - - qcom,sdx65-dwc3 - - qcom,sdx75-dwc3 - - qcom,sm4250-dwc3 - - qcom,sm6125-dwc3 - - qcom,sm6350-dwc3 - - qcom,sm8150-dwc3 - - qcom,sm8250-dwc3 - - qcom,sm8350-dwc3 - - qcom,sm8450-dwc3 - - qcom,sm8550-dwc3 - then: - properties: - interrupts: - items: - - description: The interrupt that is asserted - when a wakeup event is received on USB2 bus. - - description: The interrupt that is asserted - when a wakeup event is received on USB3 bus. - - description: Wakeup event on DM line. - - description: Wakeup event on DP line. - interrupt-names: - items: - - const: hs_phy_irq - - const: ss_phy_irq - - const: dm_hs_phy_irq - - const: dp_hs_phy_irq - - - if: - properties: - compatible: - contains: - enum: - qcom,msm8953-dwc3 - - qcom,msm8996-dwc3 - qcom,msm8998-dwc3 - - qcom,sm6115-dwc3 then: properties: interrupts: - maxItems: 2 + minItems: 2 + maxItems: 3 interrupt-names: items: - - const: hs_phy_irq + - const: pwr_event + - const: qusb2_phy - const: ss_phy_irq - if: @@ -417,37 +397,21 @@ allOf: compatible: contains: enum: - - qcom,ipq5018-dwc3 - - qcom,ipq5332-dwc3 + - qcom,msm8996-dwc3 + - qcom,qcs404-dwc3 - qcom,sdm660-dwc3 - then: - properties: - interrupts: - minItems: 1 - maxItems: 2 - interrupt-names: - minItems: 1 - items: - - const: hs_phy_irq - - const: ss_phy_irq - - - if: - properties: - compatible: - contains: - enum: - - qcom,sc7280-dwc3 + - qcom,sm6115-dwc3 + - qcom,sm6125-dwc3 then: properties: interrupts: minItems: 3 maxItems: 4 interrupt-names: - minItems: 3 items: + - const: pwr_event + - const: qusb2_phy - const: hs_phy_irq - - const: dp_hs_phy_irq - - const: dm_hs_phy_irq - const: ss_phy_irq - if: @@ -455,7 +419,8 @@ allOf: compatible: contains: enum: - - qcom,sc8280xp-dwc3 + - qcom,ipq5332-dwc3 + - qcom,x1e80100-dwc3 then: properties: interrupts: @@ -472,16 +437,35 @@ allOf: compatible: contains: enum: + - qcom,ipq4019-dwc3 + - qcom,ipq8064-dwc3 + - qcom,msm8994-dwc3 - qcom,sa8775p-dwc3 + - qcom,sc7180-dwc3 + - qcom,sc7280-dwc3 + - qcom,sc8280xp-dwc3 + - qcom,sdm670-dwc3 + - qcom,sdm845-dwc3 + - qcom,sdx55-dwc3 + - qcom,sdx65-dwc3 + - qcom,sdx75-dwc3 + - qcom,sm4250-dwc3 + - qcom,sm6350-dwc3 + - qcom,sm8150-dwc3 + - qcom,sm8250-dwc3 + - qcom,sm8350-dwc3 + - qcom,sm8450-dwc3 + - qcom,sm8550-dwc3 + - qcom,sm8650-dwc3 then: properties: interrupts: - minItems: 3 - maxItems: 4 + minItems: 4 + maxItems: 5 interrupt-names: - minItems: 3 items: - const: pwr_event + - const: hs_phy_irq - const: dp_hs_phy_irq - const: dm_hs_phy_irq - const: ss_phy_irq @@ -519,12 +503,13 @@ examples: <&gcc GCC_USB30_PRIM_MASTER_CLK>; assigned-clock-rates = <19200000>, <150000000>; - interrupts = , - , + interrupts = , + , + , , - ; - interrupt-names = "hs_phy_irq", "ss_phy_irq", - "dm_hs_phy_irq", "dp_hs_phy_irq"; + ; + interrupt-names = "pwr_event", "hs_phy_irq", + "dp_hs_phy_irq", "dm_hs_phy_irq", "ss_phy_irq"; power-domains = <&gcc USB30_PRIM_GDSC>; diff --git a/Documentation/devicetree/bindings/usb/qcom,wcd939x-usbss.yaml b/Documentation/devicetree/bindings/usb/qcom,wcd939x-usbss.yaml new file mode 100644 index 00000000000000..7ddfd3313a1858 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/qcom,wcd939x-usbss.yaml @@ -0,0 +1,102 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/qcom,wcd939x-usbss.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm WCD9380/WCD9385 USB SubSystem Altmode/Analog Audio Switch + +maintainers: + - Neil Armstrong + +description: + Qualcomm WCD9390/WCD9395 is a standalone Hi-Fi audio codec IC with a + functionally separate USB SubSystem for Altmode/Analog Audio Switch + accessible over an I2C interface. + The Audio Headphone and Microphone data path between the Codec and the + USB-C Mux subsystems are external to the IC, thus requiring DT port-endpoint + graph description to handle USB-C altmode & orientation switching for Audio + Accessory Mode. + +properties: + compatible: + oneOf: + - const: qcom,wcd9390-usbss + - items: + - const: qcom,wcd9395-usbss + - const: qcom,wcd9390-usbss + + reg: + maxItems: 1 + + reset-gpios: + maxItems: 1 + + vdd-supply: + description: USBSS VDD power supply + + mode-switch: + description: Flag the port as possible handle of altmode switching + type: boolean + + orientation-switch: + description: Flag the port as possible handler of orientation switching + type: boolean + + ports: + $ref: /schemas/graph.yaml#/properties/ports + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: + A port node to link the WCD939x USB SubSystem to a TypeC controller for the + purpose of handling altmode muxing and orientation switching. + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: + A port node to link the WCD939x USB SubSystem to the Codec SubSystem for the + purpose of handling USB-C Audio Accessory Mode muxing and orientation switching. + +required: + - compatible + - reg + - ports + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + typec-mux@42 { + compatible = "qcom,wcd9390-usbss"; + reg = <0x42>; + + vdd-supply = <&vreg_bob>; + + mode-switch; + orientation-switch; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + wcd9390_usbss_sbu: endpoint { + remote-endpoint = <&typec_sbu>; + }; + }; + port@1 { + reg = <1>; + wcd9390_usbss_codec: endpoint { + remote-endpoint = <&wcd9390_codec_usbss>; + }; + }; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml b/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml index bad55dfb2fa036..40ada78f232889 100644 --- a/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml +++ b/Documentation/devicetree/bindings/usb/renesas,usbhs.yaml @@ -19,7 +19,7 @@ properties: - items: - enum: - renesas,usbhs-r7s9210 # RZ/A2 - - renesas,usbhs-r9a07g043 # RZ/G2UL + - renesas,usbhs-r9a07g043 # RZ/G2UL and RZ/Five - renesas,usbhs-r9a07g044 # RZ/G2{L,LC} - renesas,usbhs-r9a07g054 # RZ/V2L - const: renesas,rza2-usbhs diff --git a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml index ee5af4b381b1bc..203a1eb66691f6 100644 --- a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml @@ -432,6 +432,10 @@ properties: items: enum: [1, 4, 8, 16, 32, 64, 128, 256] + num-hc-interrupters: + maximum: 8 + default: 1 + port: $ref: /schemas/graph.yaml#/properties/port description: diff --git a/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml b/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml index 323d664ae06a4d..1745e28b311052 100644 --- a/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml +++ b/Documentation/devicetree/bindings/usb/ti,tps6598x.yaml @@ -38,6 +38,10 @@ properties: - const: main - const: patch-address + reset-gpios: + description: GPIO used for the HRESET pin. + maxItems: 1 + wakeup-source: true interrupts: @@ -90,6 +94,7 @@ additionalProperties: false examples: - | + #include #include i2c { #address-cells = <1>; @@ -106,6 +111,7 @@ examples: pinctrl-names = "default"; pinctrl-0 = <&typec_pins>; + reset-gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>; typec_con: connector { compatible = "usb-c-connector"; diff --git a/Documentation/devicetree/bindings/usb/usb-xhci.yaml b/Documentation/devicetree/bindings/usb/usb-xhci.yaml index 180a261c3e8f37..4238ae896ef6f5 100644 --- a/Documentation/devicetree/bindings/usb/usb-xhci.yaml +++ b/Documentation/devicetree/bindings/usb/usb-xhci.yaml @@ -29,6 +29,12 @@ properties: description: Interrupt moderation interval default: 5000 + num-hc-interrupters: + description: Maximum number of interrupters to allocate + $ref: /schemas/types.yaml#/definitions/uint16 + minimum: 1 + maximum: 1024 + additionalProperties: true examples: diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 309b94c328c849..1a0dc04f1db478 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -79,6 +79,8 @@ patternProperties: description: ALFA Network Inc. "^allegro,.*": description: Allegro DVT + "^alliedvision,.*": + description: Allied Vision Technologies GmbH "^allo,.*": description: Allo.com "^allwinner,.*": @@ -119,6 +121,8 @@ patternProperties: description: Andes Technology Corporation "^anvo,.*": description: Anvo-Systems Dresden GmbH + "^aosong,.*": + description: Guangzhou Aosong Electronic Co., Ltd. "^apm,.*": description: Applied Micro Circuits Corporation (APM) "^apple,.*": @@ -294,6 +298,8 @@ patternProperties: description: CompuLab Ltd. "^congatec,.*": description: congatec GmbH + "^coolpi,.*": + description: cool-pi.com "^coreriver,.*": description: CORERIVER Semiconductor Co.,Ltd. "^corpro,.*": @@ -352,6 +358,8 @@ patternProperties: description: Digi International Inc. "^digilent,.*": description: Diglent, Inc. + "^dimonoff,.*": + description: Dimonoff inc. "^diodes,.*": description: Diodes, Inc. "^dioo,.*": @@ -474,6 +482,8 @@ patternProperties: description: Fairphone B.V. "^faraday,.*": description: Faraday Technology Corporation + "^fascontek,.*": + description: Fascontek "^fastrax,.*": description: Fastrax Oy "^fcs,.*": @@ -502,6 +512,8 @@ patternProperties: description: Fujitsu Ltd. "^fxtec,.*": description: FX Technology Ltd. + "^galaxycore,.*": + description: GalaxyCore Inc. "^gardena,.*": description: GARDENA GmbH "^gateway,.*": @@ -597,6 +609,8 @@ patternProperties: description: Hewlett Packard Enterprise "^hsg,.*": description: HannStar Display Co. + "^htc,.*": + description: HTC Corporation "^huawei,.*": description: Huawei Technologies Co., Ltd. "^hugsun,.*": @@ -1179,6 +1193,8 @@ patternProperties: description: Shenzhen Roofull Technology Co, Ltd "^roseapplepi,.*": description: RoseapplePi.org + "^rve,.*": + description: Recharge Véhicule Électrique (RVE) inc. "^saef,.*": description: Saef Technology Limited "^samsung,.*": @@ -1281,6 +1297,8 @@ patternProperties: description: Skyworks Solutions, Inc. "^smartlabs,.*": description: SmartLabs LLC + "^smi,.*": + description: Silicon Motion Technology Corporation "^smsc,.*": description: Standard Microsystems Corporation "^snps,.*": @@ -1381,6 +1399,8 @@ patternProperties: description: Technologic Systems "^techstar,.*": description: Shenzhen Techstar Electronics Co., Ltd. + "^techwell,.*": + description: Techwell, Inc. "^teejet,.*": description: TeeJet "^teltonika,.*": @@ -1434,6 +1454,8 @@ patternProperties: description: TPO "^tq,.*": description: TQ-Systems GmbH + "^transpeed,.*": + description: Transpeed "^traverse,.*": description: Traverse Technologies Australia Pty Ltd "^tronfy,.*": diff --git a/Documentation/devicetree/bindings/w1/amd,axi-1wire-host.yaml b/Documentation/devicetree/bindings/w1/amd,axi-1wire-host.yaml new file mode 100644 index 00000000000000..ef70fa2c0c5da6 --- /dev/null +++ b/Documentation/devicetree/bindings/w1/amd,axi-1wire-host.yaml @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/w1/amd,axi-1wire-host.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: AMD AXI 1-wire bus host for programmable logic + +maintainers: + - Kris Chaplin + +properties: + compatible: + const: amd,axi-1wire-host + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - clocks + - interrupts + +additionalProperties: false + +examples: + - | + #include + + onewire@a0000000 { + compatible = "amd,axi-1wire-host"; + reg = <0xa0000000 0x10000>; + clocks = <&zynqmp_clk 0x47>; + interrupts = ; + }; + +... diff --git a/Documentation/devicetree/bindings/watchdog/allwinner,sun4i-a10-wdt.yaml b/Documentation/devicetree/bindings/watchdog/allwinner,sun4i-a10-wdt.yaml index 274519fc24fd05..64c8f73938099c 100644 --- a/Documentation/devicetree/bindings/watchdog/allwinner,sun4i-a10-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/allwinner,sun4i-a10-wdt.yaml @@ -6,13 +6,13 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Allwinner A10 Watchdog -allOf: - - $ref: watchdog.yaml# - maintainers: - Chen-Yu Tsai - Maxime Ripard +allOf: + - $ref: watchdog.yaml# + properties: compatible: oneOf: diff --git a/Documentation/devicetree/bindings/watchdog/alphascale,asm9260-wdt.yaml b/Documentation/devicetree/bindings/watchdog/alphascale,asm9260-wdt.yaml index fea84f5b7e6d4e..6425fe51d20cc9 100644 --- a/Documentation/devicetree/bindings/watchdog/alphascale,asm9260-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/alphascale,asm9260-wdt.yaml @@ -6,12 +6,12 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Alphascale asm9260 Watchdog timer -allOf: - - $ref: watchdog.yaml# - maintainers: - Oleksij Rempel +allOf: + - $ref: watchdog.yaml# + properties: compatible: const: alphascale,asm9260-wdt diff --git a/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml b/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml index 929681127df041..21872e15916cad 100644 --- a/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml @@ -6,12 +6,12 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Apple SoC Watchdog -allOf: - - $ref: watchdog.yaml# - maintainers: - Sven Peter +allOf: + - $ref: watchdog.yaml# + properties: compatible: items: diff --git a/Documentation/devicetree/bindings/watchdog/arm-smc-wdt.yaml b/Documentation/devicetree/bindings/watchdog/arm-smc-wdt.yaml index b5573852ef5aa1..8e9d0b7e824440 100644 --- a/Documentation/devicetree/bindings/watchdog/arm-smc-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/arm-smc-wdt.yaml @@ -6,12 +6,12 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: ARM Secure Monitor Call based watchdog -allOf: - - $ref: watchdog.yaml# - maintainers: - Julius Werner +allOf: + - $ref: watchdog.yaml# + properties: compatible: enum: diff --git a/Documentation/devicetree/bindings/watchdog/brcm,bcm7038-wdt.yaml b/Documentation/devicetree/bindings/watchdog/brcm,bcm7038-wdt.yaml index 526ff908d134df..e898167ef6287e 100644 --- a/Documentation/devicetree/bindings/watchdog/brcm,bcm7038-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/brcm,bcm7038-wdt.yaml @@ -6,14 +6,14 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: BCM63xx and BCM7038 watchdog timer -allOf: - - $ref: watchdog.yaml# - maintainers: - Florian Fainelli - Justin Chen - Rafał Miłecki +allOf: + - $ref: watchdog.yaml# + properties: compatible: enum: @@ -29,11 +29,11 @@ properties: The clock running the watchdog. If no clock is found the driver will default to 27000000 Hz. -unevaluatedProperties: false - required: - reg +unevaluatedProperties: false + examples: - | watchdog@f040a7e8 { diff --git a/Documentation/devicetree/bindings/watchdog/cnxt,cx92755-wdt.yaml b/Documentation/devicetree/bindings/watchdog/cnxt,cx92755-wdt.yaml index 1844d7e026fe42..13236ee61f6f96 100644 --- a/Documentation/devicetree/bindings/watchdog/cnxt,cx92755-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/cnxt,cx92755-wdt.yaml @@ -12,12 +12,12 @@ description: | timer counters. The first timer (called "Timer A") is the only one that can be used as watchdog. -allOf: - - $ref: watchdog.yaml# - maintainers: - Baruch Siach +allOf: + - $ref: watchdog.yaml# + properties: compatible: const: cnxt,cx92755-wdt diff --git a/Documentation/devicetree/bindings/watchdog/dlg,da9062-watchdog.yaml b/Documentation/devicetree/bindings/watchdog/dlg,da9062-watchdog.yaml index f058628bb63294..c8f69812059725 100644 --- a/Documentation/devicetree/bindings/watchdog/dlg,da9062-watchdog.yaml +++ b/Documentation/devicetree/bindings/watchdog/dlg,da9062-watchdog.yaml @@ -4,7 +4,7 @@ $id: http://devicetree.org/schemas/watchdog/dlg,da9062-watchdog.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: Dialog Semiconductor DA9062/61 Watchdog Timer +title: Dialog Semiconductor DA906{1,2,3} Watchdog Timer maintainers: - Steve Twiss @@ -14,9 +14,13 @@ allOf: properties: compatible: - enum: - - dlg,da9061-watchdog - - dlg,da9062-watchdog + oneOf: + - enum: + - dlg,da9062-watchdog + - dlg,da9063-watchdog + - items: + - const: dlg,da9061-watchdog + - const: dlg,da9062-watchdog dlg,use-sw-pm: type: boolean diff --git a/Documentation/devicetree/bindings/watchdog/intel,keembay-wdt.yaml b/Documentation/devicetree/bindings/watchdog/intel,keembay-wdt.yaml index 1437ff8a122f2b..8231dde2bfa602 100644 --- a/Documentation/devicetree/bindings/watchdog/intel,keembay-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/intel,keembay-wdt.yaml @@ -9,6 +9,9 @@ title: Intel Keem Bay SoC non-secure Watchdog Timer maintainers: - Wan Ahmad Zainie +allOf: + - $ref: watchdog.yaml# + properties: compatible: enum: @@ -37,7 +40,7 @@ required: - interrupt-names - clocks -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/watchdog/maxim,max63xx.yaml b/Documentation/devicetree/bindings/watchdog/maxim,max63xx.yaml index 1a6490c43d89a6..442c21f12a3b27 100644 --- a/Documentation/devicetree/bindings/watchdog/maxim,max63xx.yaml +++ b/Documentation/devicetree/bindings/watchdog/maxim,max63xx.yaml @@ -6,14 +6,14 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Maxim 63xx Watchdog Timers -allOf: - - $ref: watchdog.yaml# - - $ref: /schemas/memory-controllers/mc-peripheral-props.yaml# - maintainers: - Marc Zyngier - Linus Walleij +allOf: + - $ref: watchdog.yaml# + - $ref: /schemas/memory-controllers/mc-peripheral-props.yaml# + properties: compatible: enum: diff --git a/Documentation/devicetree/bindings/watchdog/mediatek,mtk-wdt.yaml b/Documentation/devicetree/bindings/watchdog/mediatek,mtk-wdt.yaml index cc502838bc398a..8d2520241e37f0 100644 --- a/Documentation/devicetree/bindings/watchdog/mediatek,mtk-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/mediatek,mtk-wdt.yaml @@ -25,6 +25,7 @@ properties: - mediatek,mt6735-wdt - mediatek,mt6795-wdt - mediatek,mt7986-wdt + - mediatek,mt7988-wdt - mediatek,mt8183-wdt - mediatek,mt8186-wdt - mediatek,mt8188-wdt diff --git a/Documentation/devicetree/bindings/watchdog/nxp,pnx4008-wdt.yaml b/Documentation/devicetree/bindings/watchdog/nxp,pnx4008-wdt.yaml new file mode 100644 index 00000000000000..35ef940cbabe89 --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/nxp,pnx4008-wdt.yaml @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/watchdog/nxp,pnx4008-wdt.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP PNX watchdog timer + +maintainers: + - Roland Stigge + +allOf: + - $ref: watchdog.yaml# + +properties: + compatible: + const: nxp,pnx4008-wdt + + reg: + maxItems: 1 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + watchdog@4003c000 { + compatible = "nxp,pnx4008-wdt"; + reg = <0x4003c000 0x1000>; + timeout-sec = <10>; + }; diff --git a/Documentation/devicetree/bindings/watchdog/pnx4008-wdt.txt b/Documentation/devicetree/bindings/watchdog/pnx4008-wdt.txt deleted file mode 100644 index 4b76bec62af9d4..00000000000000 --- a/Documentation/devicetree/bindings/watchdog/pnx4008-wdt.txt +++ /dev/null @@ -1,17 +0,0 @@ -* NXP PNX watchdog timer - -Required properties: -- compatible: must be "nxp,pnx4008-wdt" -- reg: physical base address of the controller and length of memory mapped - region. - -Optional properties: -- timeout-sec: contains the watchdog timeout in seconds. - -Example: - - watchdog@4003c000 { - compatible = "nxp,pnx4008-wdt"; - reg = <0x4003C000 0x1000>; - timeout-sec = <10>; - }; diff --git a/Documentation/devicetree/bindings/watchdog/qca,ar7130-wdt.yaml b/Documentation/devicetree/bindings/watchdog/qca,ar7130-wdt.yaml new file mode 100644 index 00000000000000..82040ca10eda50 --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/qca,ar7130-wdt.yaml @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/watchdog/qca,ar7130-wdt.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Atheros AR7130 Watchdog Timer (WDT) Controller + +maintainers: + - Gabor Juhos + +allOf: + - $ref: watchdog.yaml# + +properties: + compatible: + const: qca,ar7130-wdt + + reg: + maxItems: 1 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + watchdog@18060008 { + compatible = "qca,ar7130-wdt"; + reg = <0x18060008 0x8>; + }; diff --git a/Documentation/devicetree/bindings/watchdog/qca-ar7130-wdt.txt b/Documentation/devicetree/bindings/watchdog/qca-ar7130-wdt.txt deleted file mode 100644 index 7a89e5f8541534..00000000000000 --- a/Documentation/devicetree/bindings/watchdog/qca-ar7130-wdt.txt +++ /dev/null @@ -1,13 +0,0 @@ -* Qualcomm Atheros AR7130 Watchdog Timer (WDT) Controller - -Required properties: -- compatible: must be "qca,ar7130-wdt" -- reg: physical base address of the controller and length of memory mapped - region. - -Example: - -wdt@18060008 { - compatible = "qca,ar9330-wdt", "qca,ar7130-wdt"; - reg = <0x18060008 0x8>; -}; diff --git a/Documentation/devicetree/bindings/watchdog/qcom,pm8916-wdt.yaml b/Documentation/devicetree/bindings/watchdog/qcom,pm8916-wdt.yaml index 568eb8480fc31e..dc6af204e8af52 100644 --- a/Documentation/devicetree/bindings/watchdog/qcom,pm8916-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/qcom,pm8916-wdt.yaml @@ -30,22 +30,27 @@ examples: #include #include - pmic@0 { - compatible = "qcom,pm8916", "qcom,spmi-pmic"; - reg = <0x0 SPMI_USID>; - #address-cells = <1>; + spmi { + #address-cells = <2>; #size-cells = <0>; - pon@800 { - compatible = "qcom,pm8916-pon"; - reg = <0x800>; - mode-bootloader = <0x2>; - mode-recovery = <0x1>; - - watchdog { - compatible = "qcom,pm8916-wdt"; - interrupts = <0x0 0x8 6 IRQ_TYPE_EDGE_RISING>; - timeout-sec = <60>; + pmic@0 { + compatible = "qcom,pm8916", "qcom,spmi-pmic"; + reg = <0x0 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + pon@800 { + compatible = "qcom,pm8916-pon"; + reg = <0x800>; + mode-bootloader = <0x2>; + mode-recovery = <0x1>; + + watchdog { + compatible = "qcom,pm8916-wdt"; + interrupts = <0x0 0x8 6 IRQ_TYPE_EDGE_RISING>; + timeout-sec = <60>; + }; }; }; }; diff --git a/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml b/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml index c12bc852aedc4e..a4f35c598cdb54 100644 --- a/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml @@ -123,7 +123,7 @@ examples: compatible = "qcom,apss-wdt-sm8150", "qcom,kpss-wdt"; reg = <0x17c10000 0x1000>; clocks = <&sleep_clk>; - interrupts = ; + interrupts = ; timeout-sec = <10>; }; diff --git a/Documentation/devicetree/bindings/watchdog/realtek,rtd119x.txt b/Documentation/devicetree/bindings/watchdog/realtek,rtd119x.txt deleted file mode 100644 index 05653054bd5b24..00000000000000 --- a/Documentation/devicetree/bindings/watchdog/realtek,rtd119x.txt +++ /dev/null @@ -1,17 +0,0 @@ -Realtek RTD1295 Watchdog -======================== - -Required properties: - -- compatible : Should be "realtek,rtd1295-watchdog" -- reg : Specifies the physical base address and size of registers -- clocks : Specifies one clock input - - -Example: - - watchdog@98007680 { - compatible = "realtek,rtd1295-watchdog"; - reg = <0x98007680 0x100>; - clocks = <&osc27M>; - }; diff --git a/Documentation/devicetree/bindings/watchdog/realtek,rtd1295-watchdog.yaml b/Documentation/devicetree/bindings/watchdog/realtek,rtd1295-watchdog.yaml new file mode 100644 index 00000000000000..2a0ea1696317c6 --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/realtek,rtd1295-watchdog.yaml @@ -0,0 +1,38 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/watchdog/realtek,rtd1295-watchdog.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Realtek RTD1295 Watchdog + +maintainers: + - Andreas Färber + +allOf: + - $ref: watchdog.yaml# + +properties: + compatible: + const: realtek,rtd1295-watchdog + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + +required: + - compatible + - reg + - clocks + +unevaluatedProperties: false + +examples: + - | + watchdog@98007680 { + compatible = "realtek,rtd1295-watchdog"; + reg = <0x98007680 0x100>; + clocks = <&osc27M>; + }; diff --git a/Documentation/devicetree/bindings/watchdog/samsung-wdt.yaml b/Documentation/devicetree/bindings/watchdog/samsung-wdt.yaml index 8fb6656ba0c28d..77a5ddd0426ebc 100644 --- a/Documentation/devicetree/bindings/watchdog/samsung-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/samsung-wdt.yaml @@ -16,14 +16,20 @@ description: |+ properties: compatible: - enum: - - samsung,s3c2410-wdt # for S3C2410 - - samsung,s3c6410-wdt # for S3C6410, S5PV210 and Exynos4 - - samsung,exynos5250-wdt # for Exynos5250 - - samsung,exynos5420-wdt # for Exynos5420 - - samsung,exynos7-wdt # for Exynos7 - - samsung,exynos850-wdt # for Exynos850 - - samsung,exynosautov9-wdt # for Exynosautov9 + oneOf: + - enum: + - google,gs101-wdt # for Google gs101 + - samsung,s3c2410-wdt # for S3C2410 + - samsung,s3c6410-wdt # for S3C6410, S5PV210 and Exynos4 + - samsung,exynos5250-wdt # for Exynos5250 + - samsung,exynos5420-wdt # for Exynos5420 + - samsung,exynos7-wdt # for Exynos7 + - samsung,exynos850-wdt # for Exynos850 + - samsung,exynosautov9-wdt # for Exynosautov9 + - items: + - enum: + - tesla,fsd-wdt + - const: samsung,exynos7-wdt reg: maxItems: 1 @@ -42,13 +48,14 @@ properties: samsung,cluster-index: $ref: /schemas/types.yaml#/definitions/uint32 description: - Index of CPU cluster on which watchdog is running (in case of Exynos850) + Index of CPU cluster on which watchdog is running (in case of Exynos850 + or Google gs101). samsung,syscon-phandle: $ref: /schemas/types.yaml#/definitions/phandle description: Phandle to the PMU system controller node (in case of Exynos5250, - Exynos5420, Exynos7 and Exynos850). + Exynos5420, Exynos7, Exynos850 and gs101). required: - compatible @@ -64,6 +71,7 @@ allOf: compatible: contains: enum: + - google,gs101-wdt - samsung,exynos5250-wdt - samsung,exynos5420-wdt - samsung,exynos7-wdt @@ -77,6 +85,7 @@ allOf: compatible: contains: enum: + - google,gs101-wdt - samsung,exynos850-wdt - samsung,exynosautov9-wdt then: diff --git a/Documentation/devicetree/bindings/watchdog/snps,dw-wdt.yaml b/Documentation/devicetree/bindings/watchdog/snps,dw-wdt.yaml index 76eceeddd1507d..c7aab0418a3202 100644 --- a/Documentation/devicetree/bindings/watchdog/snps,dw-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/snps,dw-wdt.yaml @@ -6,12 +6,12 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: Synopsys Designware Watchdog Timer -allOf: - - $ref: watchdog.yaml# - maintainers: - Jamie Iles +allOf: + - $ref: watchdog.yaml# + properties: compatible: oneOf: @@ -73,13 +73,13 @@ properties: minItems: 16 maxItems: 16 -unevaluatedProperties: false - required: - compatible - reg - clocks +unevaluatedProperties: false + examples: - | watchdog@ffd02000 { diff --git a/Documentation/devicetree/bindings/watchdog/technologic,ts7200-wdt.yaml b/Documentation/devicetree/bindings/watchdog/technologic,ts7200-wdt.yaml new file mode 100644 index 00000000000000..7e4bfef152f828 --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/technologic,ts7200-wdt.yaml @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/watchdog/technologic,ts7200-wdt.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Technologic Systems TS-72xx based SBCs watchdog + +maintainers: + - Nikita Shubin + +allOf: + - $ref: watchdog.yaml# + +properties: + compatible: + oneOf: + - const: technologic,ts7200-wdt + - items: + - enum: + - technologic,ts7300-wdt + - technologic,ts7260-wdt + - technologic,ts7250-wdt + - const: technologic,ts7200-wdt + + reg: + items: + - description: control register + - description: feed register + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + watchdog@23800000 { + compatible = "technologic,ts7200-wdt"; + reg = <0x23800000 0x01>, <0x23c00000 0x01>; + timeout-sec = <30>; + }; + +... diff --git a/Documentation/doc-guide/sphinx.rst b/Documentation/doc-guide/sphinx.rst index cd8ad79044910c..3d125fb4139d24 100644 --- a/Documentation/doc-guide/sphinx.rst +++ b/Documentation/doc-guide/sphinx.rst @@ -28,7 +28,7 @@ Sphinx Install ============== The ReST markups currently used by the Documentation/ files are meant to be -built with ``Sphinx`` version 1.7 or higher. +built with ``Sphinx`` version 2.4.4 or higher. There's a script that checks for the Sphinx requirements. Please see :ref:`sphinx-pre-install` for further details. @@ -435,6 +435,15 @@ path. For information on cross-referencing to kernel-doc functions or types, see Documentation/doc-guide/kernel-doc.rst. +Referencing commits +~~~~~~~~~~~~~~~~~~~ + +References to git commits are automatically hyperlinked given that they are +written in one of these formats:: + + commit 72bf4f1767f0 + commit 72bf4f1767f0 ("net: do not leave an empty skb in write queue") + .. _sphinx_kfigure: Figures & Images diff --git a/Documentation/driver-api/crypto/iaa/iaa-crypto.rst b/Documentation/driver-api/crypto/iaa/iaa-crypto.rst new file mode 100644 index 00000000000000..de587cf9cbed45 --- /dev/null +++ b/Documentation/driver-api/crypto/iaa/iaa-crypto.rst @@ -0,0 +1,824 @@ +.. SPDX-License-Identifier: GPL-2.0 + +========================================= +IAA Compression Accelerator Crypto Driver +========================================= + +Tom Zanussi + +The IAA crypto driver supports compression/decompression compatible +with the DEFLATE compression standard described in RFC 1951, which is +the compression/decompression algorithm exported by this module. + +The IAA hardware spec can be found here: + + https://cdrdv2.intel.com/v1/dl/getContent/721858 + +The iaa_crypto driver is designed to work as a layer underneath +higher-level compression devices such as zswap. + +Users can select IAA compress/decompress acceleration by specifying +one of the supported IAA compression algorithms in whatever facility +allows compression algorithms to be selected. + +For example, a zswap device can select the IAA 'fixed' mode +represented by selecting the 'deflate-iaa' crypto compression +algorithm:: + + # echo deflate-iaa > /sys/module/zswap/parameters/compressor + +This will tell zswap to use the IAA 'fixed' compression mode for all +compresses and decompresses. + +Currently, there is only one compression modes available, 'fixed' +mode. + +The 'fixed' compression mode implements the compression scheme +specified by RFC 1951 and is given the crypto algorithm name +'deflate-iaa'. (Because the IAA hardware has a 4k history-window +limitation, only buffers <= 4k, or that have been compressed using a +<= 4k history window, are technically compliant with the deflate spec, +which allows for a window of up to 32k. Because of this limitation, +the IAA fixed mode deflate algorithm is given its own algorithm name +rather than simply 'deflate'). + + +Config options and other setup +============================== + +The IAA crypto driver is available via menuconfig using the following +path:: + + Cryptographic API -> Hardware crypto devices -> Support for Intel(R) IAA Compression Accelerator + +In the configuration file the option called CONFIG_CRYPTO_DEV_IAA_CRYPTO. + +The IAA crypto driver also supports statistics, which are available +via menuconfig using the following path:: + + Cryptographic API -> Hardware crypto devices -> Support for Intel(R) IAA Compression -> Enable Intel(R) IAA Compression Accelerator Statistics + +In the configuration file the option called CONFIG_CRYPTO_DEV_IAA_CRYPTO_STATS. + +The following config options should also be enabled:: + + CONFIG_IRQ_REMAP=y + CONFIG_INTEL_IOMMU=y + CONFIG_INTEL_IOMMU_SVM=y + CONFIG_PCI_ATS=y + CONFIG_PCI_PRI=y + CONFIG_PCI_PASID=y + CONFIG_INTEL_IDXD=m + CONFIG_INTEL_IDXD_SVM=y + +IAA is one of the first Intel accelerator IPs that can work in +conjunction with the Intel IOMMU. There are multiple modes that exist +for testing. Based on IOMMU configuration, there are 3 modes:: + + - Scalable + - Legacy + - No IOMMU + + +Scalable mode +------------- + +Scalable mode supports Shared Virtual Memory (SVM or SVA). It is +entered when using the kernel boot commandline:: + + intel_iommu=on,sm_on + +with VT-d turned on in BIOS. + +With scalable mode, both shared and dedicated workqueues are available +for use. + +For scalable mode, the following BIOS settings should be enabled:: + + Socket Configuration > IIO Configuration > Intel VT for Directed I/O (VT-d) > Intel VT for Directed I/O + + Socket Configuration > IIO Configuration > PCIe ENQCMD > ENQCMDS + + +Legacy mode +----------- + +Legacy mode is entered when using the kernel boot commandline:: + + intel_iommu=off + +or VT-d is not turned on in BIOS. + +If you have booted into Linux and not sure if VT-d is on, do a "dmesg +| grep -i dmar". If you don't see a number of DMAR devices enumerated, +most likely VT-d is not on. + +With legacy mode, only dedicated workqueues are available for use. + + +No IOMMU mode +------------- + +No IOMMU mode is entered when using the kernel boot commandline:: + + iommu=off. + +With no IOMMU mode, only dedicated workqueues are available for use. + + +Usage +===== + +accel-config +------------ + +When loaded, the iaa_crypto driver automatically creates a default +configuration and enables it, and assigns default driver attributes. +If a different configuration or set of driver attributes is required, +the user must first disable the IAA devices and workqueues, reset the +configuration, and then re-register the deflate-iaa algorithm with the +crypto subsystem by removing and reinserting the iaa_crypto module. + +The :ref:`iaa_disable_script` in the 'Use Cases' +section below can be used to disable the default configuration. + +See :ref:`iaa_default_config` below for details of the default +configuration. + +More likely than not, however, and because of the complexity and +configurability of the accelerator devices, the user will want to +configure the device and manually enable the desired devices and +workqueues. + +The userspace tool to help doing that is called accel-config. Using +accel-config to configure device or loading a previously saved config +is highly recommended. The device can be controlled via sysfs +directly but comes with the warning that you should do this ONLY if +you know exactly what you are doing. The following sections will not +cover the sysfs interface but assumes you will be using accel-config. + +The :ref:`iaa_sysfs_config` section in the appendix below can be +consulted for the sysfs interface details if interested. + +The accel-config tool along with instructions for building it can be +found here: + + https://github.com/intel/idxd-config/#readme + +Typical usage +------------- + +In order for the iaa_crypto module to actually do any +compression/decompression work on behalf of a facility, one or more +IAA workqueues need to be bound to the iaa_crypto driver. + +For instance, here's an example of configuring an IAA workqueue and +binding it to the iaa_crypto driver (note that device names are +specified as 'iax' rather than 'iaa' - this is because upstream still +has the old 'iax' device naming in place) :: + + # configure wq1.0 + + accel-config config-wq --group-id=0 --mode=dedicated --type=kernel --name="iaa_crypto" --device_name="crypto" iax1/wq1.0 + + # enable IAA device iax1 + + accel-config enable-device iax1 + + # enable wq1.0 on IAX device iax1 + + accel-config enable-wq iax1/wq1.0 + +Whenever a new workqueue is bound to or unbound from the iaa_crypto +driver, the available workqueues are 'rebalanced' such that work +submitted from a particular CPU is given to the most appropriate +workqueue available. Current best practice is to configure and bind +at least one workqueue for each IAA device, but as long as there is at +least one workqueue configured and bound to any IAA device in the +system, the iaa_crypto driver will work, albeit most likely not as +efficiently. + +The IAA crypto algorigthms is operational and compression and +decompression operations are fully enabled following the successful +binding of the first IAA workqueue to the iaa_crypto driver. + +Similarly, the IAA crypto algorithm is not operational and compression +and decompression operations are disabled following the unbinding of +the last IAA worqueue to the iaa_crypto driver. + +As a result, the IAA crypto algorithms and thus the IAA hardware are +only available when one or more workques are bound to the iaa_crypto +driver. + +When there are no IAA workqueues bound to the driver, the IAA crypto +algorithms can be unregistered by removing the module. + + +Driver attributes +----------------- + +There are a couple user-configurable driver attributes that can be +used to configure various modes of operation. They're listed below, +along with their default values. To set any of these attributes, echo +the appropriate values to the attribute file located under +/sys/bus/dsa/drivers/crypto/ + +The attribute settings at the time the IAA algorithms are registered +are captured in each algorithm's crypto_ctx and used for all compresses +and decompresses when using that algorithm. + +The available attributes are: + + - verify_compress + + Toggle compression verification. If set, each compress will be + internally decompressed and the contents verified, returning error + codes if unsuccessful. This can be toggled with 0/1:: + + echo 0 > /sys/bus/dsa/drivers/crypto/verify_compress + + The default setting is '1' - verify all compresses. + + - sync_mode + + Select mode to be used to wait for completion of each compresses + and decompress operation. + + The crypto async interface support implemented by iaa_crypto + provides an implementation that satisfies the interface but does + so in a synchronous manner - it fills and submits the IDXD + descriptor and then loops around waiting for it to complete before + returning. This isn't a problem at the moment, since all existing + callers (e.g. zswap) wrap any asynchronous callees in a + synchronous wrapper anyway. + + The iaa_crypto driver does however provide true asynchronous + support for callers that can make use of it. In this mode, it + fills and submits the IDXD descriptor, then returns immediately + with -EINPROGRESS. The caller can then either poll for completion + itself, which requires specific code in the caller which currently + nothing in the upstream kernel implements, or go to sleep and wait + for an interrupt signaling completion. This latter mode is + supported by current users in the kernel such as zswap via + synchronous wrappers. Although it is supported this mode is + significantly slower than the synchronous mode that does the + polling in the iaa_crypto driver previously mentioned. + + This mode can be enabled by writing 'async_irq' to the sync_mode + iaa_crypto driver attribute:: + + echo async_irq > /sys/bus/dsa/drivers/crypto/sync_mode + + Async mode without interrupts (caller must poll) can be enabled by + writing 'async' to it:: + + echo async > /sys/bus/dsa/drivers/crypto/sync_mode + + The mode that does the polling in the iaa_crypto driver can be + enabled by writing 'sync' to it:: + + echo sync > /sys/bus/dsa/drivers/crypto/sync_mode + + The default mode is 'sync'. + +.. _iaa_default_config: + +IAA Default Configuration +------------------------- + +When the iaa_crypto driver is loaded, each IAA device has a single +work queue configured for it, with the following attributes:: + + mode "dedicated" + threshold 0 + size Total WQ Size from WQCAP + priority 10 + type IDXD_WQT_KERNEL + group 0 + name "iaa_crypto" + driver_name "crypto" + +The devices and workqueues are also enabled and therefore the driver +is ready to be used without any additional configuration. + +The default driver attributes in effect when the driver is loaded are:: + + sync_mode "sync" + verify_compress 1 + +In order to change either the device/work queue or driver attributes, +the enabled devices and workqueues must first be disabled. In order +to have the new configuration applied to the deflate-iaa crypto +algorithm, it needs to be re-registered by removing and reinserting +the iaa_crypto module. The :ref:`iaa_disable_script` in the 'Use +Cases' section below can be used to disable the default configuration. + +Statistics +========== + +If the optional debugfs statistics support is enabled, the IAA crypto +driver will generate statistics which can be accessed in debugfs at:: + + # ls -al /sys/kernel/debug/iaa-crypto/ + total 0 + drwxr-xr-x 2 root root 0 Mar 3 09:35 . + drwx------ 47 root root 0 Mar 3 09:35 .. + -rw-r--r-- 1 root root 0 Mar 3 09:35 max_acomp_delay_ns + -rw-r--r-- 1 root root 0 Mar 3 09:35 max_adecomp_delay_ns + -rw-r--r-- 1 root root 0 Mar 3 09:35 max_comp_delay_ns + -rw-r--r-- 1 root root 0 Mar 3 09:35 max_decomp_delay_ns + -rw-r--r-- 1 root root 0 Mar 3 09:35 stats_reset + -rw-r--r-- 1 root root 0 Mar 3 09:35 total_comp_bytes_out + -rw-r--r-- 1 root root 0 Mar 3 09:35 total_comp_calls + -rw-r--r-- 1 root root 0 Mar 3 09:35 total_decomp_bytes_in + -rw-r--r-- 1 root root 0 Mar 3 09:35 total_decomp_calls + -rw-r--r-- 1 root root 0 Mar 3 09:35 wq_stats + +Most of the above statisticss are self-explanatory. The wq_stats file +shows per-wq stats, a set for each iaa device and wq in addition to +some global stats:: + + # cat wq_stats + global stats: + total_comp_calls: 100 + total_decomp_calls: 100 + total_comp_bytes_out: 22800 + total_decomp_bytes_in: 22800 + total_completion_einval_errors: 0 + total_completion_timeout_errors: 0 + total_completion_comp_buf_overflow_errors: 0 + + iaa device: + id: 1 + n_wqs: 1 + comp_calls: 0 + comp_bytes: 0 + decomp_calls: 0 + decomp_bytes: 0 + wqs: + name: iaa_crypto + comp_calls: 0 + comp_bytes: 0 + decomp_calls: 0 + decomp_bytes: 0 + + iaa device: + id: 3 + n_wqs: 1 + comp_calls: 0 + comp_bytes: 0 + decomp_calls: 0 + decomp_bytes: 0 + wqs: + name: iaa_crypto + comp_calls: 0 + comp_bytes: 0 + decomp_calls: 0 + decomp_bytes: 0 + + iaa device: + id: 5 + n_wqs: 1 + comp_calls: 100 + comp_bytes: 22800 + decomp_calls: 100 + decomp_bytes: 22800 + wqs: + name: iaa_crypto + comp_calls: 100 + comp_bytes: 22800 + decomp_calls: 100 + decomp_bytes: 22800 + +Writing 0 to 'stats_reset' resets all the stats, including the +per-device and per-wq stats:: + + # echo 0 > stats_reset + # cat wq_stats + global stats: + total_comp_calls: 0 + total_decomp_calls: 0 + total_comp_bytes_out: 0 + total_decomp_bytes_in: 0 + total_completion_einval_errors: 0 + total_completion_timeout_errors: 0 + total_completion_comp_buf_overflow_errors: 0 + ... + + +Use cases +========= + +Simple zswap test +----------------- + +For this example, the kernel should be configured according to the +dedicated mode options described above, and zswap should be enabled as +well:: + + CONFIG_ZSWAP=y + +This is a simple test that uses iaa_compress as the compressor for a +swap (zswap) device. It sets up the zswap device and then uses the +memory_memadvise program listed below to forcibly swap out and in a +specified number of pages, demonstrating both compress and decompress. + +The zswap test expects the work queues for each IAA device on the +system to be configured properly as a kernel workqueue with a +workqueue driver_name of "crypto". + +The first step is to make sure the iaa_crypto module is loaded:: + + modprobe iaa_crypto + +If the IAA devices and workqueues haven't previously been disabled and +reconfigured, then the default configuration should be in place and no +further IAA configuration is necessary. See :ref:`iaa_default_config` +below for details of the default configuration. + +If the default configuration is in place, you should see the iaa +devices and wq0s enabled:: + + # cat /sys/bus/dsa/devices/iax1/state + enabled + # cat /sys/bus/dsa/devices/iax1/wq1.0/state + enabled + +To demonstrate that the following steps work as expected, these +commands can be used to enable debug output:: + + # echo -n 'module iaa_crypto +p' > /sys/kernel/debug/dynamic_debug/control + # echo -n 'module idxd +p' > /sys/kernel/debug/dynamic_debug/control + +Use the following commands to enable zswap:: + + # echo 0 > /sys/module/zswap/parameters/enabled + # echo 50 > /sys/module/zswap/parameters/max_pool_percent + # echo deflate-iaa > /sys/module/zswap/parameters/compressor + # echo zsmalloc > /sys/module/zswap/parameters/zpool + # echo 1 > /sys/module/zswap/parameters/enabled + # echo 0 > /sys/module/zswap/parameters/same_filled_pages_enabled + # echo 100 > /proc/sys/vm/swappiness + # echo never > /sys/kernel/mm/transparent_hugepage/enabled + # echo 1 > /proc/sys/vm/overcommit_memory + +Now you can now run the zswap workload you want to measure. For +example, using the memory_memadvise code below, the following command +will swap in and out 100 pages:: + + ./memory_madvise 100 + + Allocating 100 pages to swap in/out + Swapping out 100 pages + Swapping in 100 pages + Swapped out and in 100 pages + +You should see something like the following in the dmesg output:: + + [ 404.202972] idxd 0000:e7:02.0: iaa_comp_acompress: dma_map_sg, src_addr 223925c000, nr_sgs 1, req->src 00000000ee7cb5e6, req->slen 4096, sg_dma_len(sg) 4096 + [ 404.202973] idxd 0000:e7:02.0: iaa_comp_acompress: dma_map_sg, dst_addr 21dadf8000, nr_sgs 1, req->dst 000000008d6acea8, req->dlen 4096, sg_dma_len(sg) 8192 + [ 404.202975] idxd 0000:e7:02.0: iaa_compress: desc->src1_addr 223925c000, desc->src1_size 4096, desc->dst_addr 21dadf8000, desc->max_dst_size 4096, desc->src2_addr 2203543000, desc->src2_size 1568 + [ 404.202981] idxd 0000:e7:02.0: iaa_compress_verify: (verify) desc->src1_addr 21dadf8000, desc->src1_size 228, desc->dst_addr 223925c000, desc->max_dst_size 4096, desc->src2_addr 0, desc->src2_size 0 + ... + +Now that basic functionality has been demonstrated, the defaults can +be erased and replaced with a different configuration. To do that, +first disable zswap:: + + # echo lzo > /sys/module/zswap/parameters/compressor + # swapoff -a + # echo 0 > /sys/module/zswap/parameters/accept_threshold_percent + # echo 0 > /sys/module/zswap/parameters/max_pool_percent + # echo 0 > /sys/module/zswap/parameters/enabled + # echo 0 > /sys/module/zswap/parameters/enabled + +Then run the :ref:`iaa_disable_script` in the 'Use Cases' section +below to disable the default configuration. + +Finally turn swap back on:: + + # swapon -a + +Following all that the IAA device(s) can now be re-configured and +enabled as desired for further testing. Below is one example. + +The zswap test expects the work queues for each IAA device on the +system to be configured properly as a kernel workqueue with a +workqueue driver_name of "crypto". + +The below script automatically does that:: + + #!/bin/bash + + echo "IAA devices:" + lspci -d:0cfe + echo "# IAA devices:" + lspci -d:0cfe | wc -l + + # + # count iaa instances + # + iaa_dev_id="0cfe" + num_iaa=$(lspci -d:${iaa_dev_id} | wc -l) + echo "Found ${num_iaa} IAA instances" + + # + # disable iaa wqs and devices + # + echo "Disable IAA" + + for ((i = 1; i < ${num_iaa} * 2; i += 2)); do + echo disable wq iax${i}/wq${i}.0 + accel-config disable-wq iax${i}/wq${i}.0 + echo disable iaa iax${i} + accel-config disable-device iax${i} + done + + echo "End Disable IAA" + + # + # configure iaa wqs and devices + # + echo "Configure IAA" + for ((i = 1; i < ${num_iaa} * 2; i += 2)); do + accel-config config-wq --group-id=0 --mode=dedicated --size=128 --priority=10 --type=kernel --name="iaa_crypto" --driver_name="crypto" iax${i}/wq${i} + done + + echo "End Configure IAA" + + # + # enable iaa wqs and devices + # + echo "Enable IAA" + + for ((i = 1; i < ${num_iaa} * 2; i += 2)); do + echo enable iaa iaa${i} + accel-config enable-device iaa${i} + echo enable wq iaa${i}/wq${i}.0 + accel-config enable-wq iaa${i}/wq${i}.0 + done + + echo "End Enable IAA" + +When the workqueues are bound to the iaa_crypto driver, you should +see something similar to the following in dmesg output if you've +enabled debug output (echo -n 'module iaa_crypto +p' > +/sys/kernel/debug/dynamic_debug/control):: + + [ 60.752344] idxd 0000:f6:02.0: add_iaa_wq: added wq 000000004068d14d to iaa 00000000c9585ba2, n_wq 1 + [ 60.752346] iaa_crypto: rebalance_wq_table: nr_nodes=2, nr_cpus 160, nr_iaa 8, cpus_per_iaa 20 + [ 60.752347] iaa_crypto: rebalance_wq_table: iaa=0 + [ 60.752349] idxd 0000:6a:02.0: request_iaa_wq: getting wq from iaa_device 0000000042d7bc52 (0) + [ 60.752350] idxd 0000:6a:02.0: request_iaa_wq: returning unused wq 00000000c8bb4452 (0) from iaa device 0000000042d7bc52 (0) + [ 60.752352] iaa_crypto: rebalance_wq_table: assigned wq for cpu=0, node=0 = wq 00000000c8bb4452 + [ 60.752354] iaa_crypto: rebalance_wq_table: iaa=0 + [ 60.752355] idxd 0000:6a:02.0: request_iaa_wq: getting wq from iaa_device 0000000042d7bc52 (0) + [ 60.752356] idxd 0000:6a:02.0: request_iaa_wq: returning unused wq 00000000c8bb4452 (0) from iaa device 0000000042d7bc52 (0) + [ 60.752358] iaa_crypto: rebalance_wq_table: assigned wq for cpu=1, node=0 = wq 00000000c8bb4452 + [ 60.752359] iaa_crypto: rebalance_wq_table: iaa=0 + [ 60.752360] idxd 0000:6a:02.0: request_iaa_wq: getting wq from iaa_device 0000000042d7bc52 (0) + [ 60.752361] idxd 0000:6a:02.0: request_iaa_wq: returning unused wq 00000000c8bb4452 (0) from iaa device 0000000042d7bc52 (0) + [ 60.752362] iaa_crypto: rebalance_wq_table: assigned wq for cpu=2, node=0 = wq 00000000c8bb4452 + [ 60.752364] iaa_crypto: rebalance_wq_table: iaa=0 + . + . + . + +Once the workqueues and devices have been enabled, the IAA crypto +algorithms are enabled and available. When the IAA crypto algorithms +have been successfully enabled, you should see the following dmesg +output:: + + [ 64.893759] iaa_crypto: iaa_crypto_enable: iaa_crypto now ENABLED + +Now run the following zswap-specific setup commands to have zswap use +the 'fixed' compression mode:: + + echo 0 > /sys/module/zswap/parameters/enabled + echo 50 > /sys/module/zswap/parameters/max_pool_percent + echo deflate-iaa > /sys/module/zswap/parameters/compressor + echo zsmalloc > /sys/module/zswap/parameters/zpool + echo 1 > /sys/module/zswap/parameters/enabled + echo 0 > /sys/module/zswap/parameters/same_filled_pages_enabled + + echo 100 > /proc/sys/vm/swappiness + echo never > /sys/kernel/mm/transparent_hugepage/enabled + echo 1 > /proc/sys/vm/overcommit_memory + +Finally, you can now run the zswap workload you want to measure. For +example, using the code below, the following command will swap in and +out 100 pages:: + + ./memory_madvise 100 + + Allocating 100 pages to swap in/out + Swapping out 100 pages + Swapping in 100 pages + Swapped out and in 100 pages + +You should see something like the following in the dmesg output if +you've enabled debug output (echo -n 'module iaa_crypto +p' > +/sys/kernel/debug/dynamic_debug/control):: + + [ 404.202972] idxd 0000:e7:02.0: iaa_comp_acompress: dma_map_sg, src_addr 223925c000, nr_sgs 1, req->src 00000000ee7cb5e6, req->slen 4096, sg_dma_len(sg) 4096 + [ 404.202973] idxd 0000:e7:02.0: iaa_comp_acompress: dma_map_sg, dst_addr 21dadf8000, nr_sgs 1, req->dst 000000008d6acea8, req->dlen 4096, sg_dma_len(sg) 8192 + [ 404.202975] idxd 0000:e7:02.0: iaa_compress: desc->src1_addr 223925c000, desc->src1_size 4096, desc->dst_addr 21dadf8000, desc->max_dst_size 4096, desc->src2_addr 2203543000, desc->src2_size 1568 + [ 404.202981] idxd 0000:e7:02.0: iaa_compress_verify: (verify) desc->src1_addr 21dadf8000, desc->src1_size 228, desc->dst_addr 223925c000, desc->max_dst_size 4096, desc->src2_addr 0, desc->src2_size 0 + [ 409.203227] idxd 0000:e7:02.0: iaa_comp_adecompress: dma_map_sg, src_addr 21ddd8b100, nr_sgs 1, req->src 0000000084adab64, req->slen 228, sg_dma_len(sg) 228 + [ 409.203235] idxd 0000:e7:02.0: iaa_comp_adecompress: dma_map_sg, dst_addr 21ee3dc000, nr_sgs 1, req->dst 000000004e2990d0, req->dlen 4096, sg_dma_len(sg) 4096 + [ 409.203239] idxd 0000:e7:02.0: iaa_decompress: desc->src1_addr 21ddd8b100, desc->src1_size 228, desc->dst_addr 21ee3dc000, desc->max_dst_size 4096, desc->src2_addr 0, desc->src2_size 0 + [ 409.203254] idxd 0000:e7:02.0: iaa_comp_adecompress: dma_map_sg, src_addr 21ddd8b100, nr_sgs 1, req->src 0000000084adab64, req->slen 228, sg_dma_len(sg) 228 + [ 409.203256] idxd 0000:e7:02.0: iaa_comp_adecompress: dma_map_sg, dst_addr 21f1551000, nr_sgs 1, req->dst 000000004e2990d0, req->dlen 4096, sg_dma_len(sg) 4096 + [ 409.203257] idxd 0000:e7:02.0: iaa_decompress: desc->src1_addr 21ddd8b100, desc->src1_size 228, desc->dst_addr 21f1551000, desc->max_dst_size 4096, desc->src2_addr 0, desc->src2_size 0 + +In order to unregister the IAA crypto algorithms, and register new +ones using different parameters, any users of the current algorithm +should be stopped and the IAA workqueues and devices disabled. + +In the case of zswap, remove the IAA crypto algorithm as the +compressor and turn off swap (to remove all references to +iaa_crypto):: + + echo lzo > /sys/module/zswap/parameters/compressor + swapoff -a + + echo 0 > /sys/module/zswap/parameters/accept_threshold_percent + echo 0 > /sys/module/zswap/parameters/max_pool_percent + echo 0 > /sys/module/zswap/parameters/enabled + +Once zswap is disabled and no longer using iaa_crypto, the IAA wqs and +devices can be disabled. + +.. _iaa_disable_script: + +IAA disable script +------------------ + +The below script automatically does that:: + + #!/bin/bash + + echo "IAA devices:" + lspci -d:0cfe + echo "# IAA devices:" + lspci -d:0cfe | wc -l + + # + # count iaa instances + # + iaa_dev_id="0cfe" + num_iaa=$(lspci -d:${iaa_dev_id} | wc -l) + echo "Found ${num_iaa} IAA instances" + + # + # disable iaa wqs and devices + # + echo "Disable IAA" + + for ((i = 1; i < ${num_iaa} * 2; i += 2)); do + echo disable wq iax${i}/wq${i}.0 + accel-config disable-wq iax${i}/wq${i}.0 + echo disable iaa iax${i} + accel-config disable-device iax${i} + done + + echo "End Disable IAA" + +Finally, at this point the iaa_crypto module can be removed, which +will unregister the current IAA crypto algorithms:: + + rmmod iaa_crypto + + +memory_madvise.c (gcc -o memory_memadvise memory_madvise.c):: + + #include + #include + #include + #include + #include + #include + + #ifndef MADV_PAGEOUT + #define MADV_PAGEOUT 21 /* force pages out immediately */ + #endif + + #define PG_SZ 4096 + + int main(int argc, char **argv) + { + int i, nr_pages = 1; + int64_t *dump_ptr; + char *addr, *a; + int loop = 1; + + if (argc > 1) + nr_pages = atoi(argv[1]); + + printf("Allocating %d pages to swap in/out\n", nr_pages); + + /* allocate pages */ + addr = mmap(NULL, nr_pages * PG_SZ, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + *addr = 1; + + /* initialize data in page to all '*' chars */ + memset(addr, '*', nr_pages * PG_SZ); + + printf("Swapping out %d pages\n", nr_pages); + + /* Tell kernel to swap it out */ + madvise(addr, nr_pages * PG_SZ, MADV_PAGEOUT); + + while (loop > 0) { + /* Wait for swap out to finish */ + sleep(5); + + a = addr; + + printf("Swapping in %d pages\n", nr_pages); + + /* Access the page ... this will swap it back in again */ + for (i = 0; i < nr_pages; i++) { + if (a[0] != '*') { + printf("Bad data from decompress!!!!!\n"); + + dump_ptr = (int64_t *)a; + for (int j = 0; j < 100; j++) { + printf(" page %d data: %#llx\n", i, *dump_ptr); + dump_ptr++; + } + } + + a += PG_SZ; + } + + loop --; + } + + printf("Swapped out and in %d pages\n", nr_pages); + +Appendix +======== + +.. _iaa_sysfs_config: + +IAA sysfs config interface +-------------------------- + +Below is a description of the IAA sysfs interface, which as mentioned +in the main document, should only be used if you know exactly what you +are doing. Even then, there's no compelling reason to use it directly +since accel-config can do everything the sysfs interface can and in +fact accel-config is based on it under the covers. + +The 'IAA config path' is /sys/bus/dsa/devices and contains +subdirectories representing each IAA device, workqueue, engine, and +group. Note that in the sysfs interface, the IAA devices are actually +named using iax e.g. iax1, iax3, etc. (Note that IAA devices are the +odd-numbered devices; the even-numbered devices are DSA devices and +can be ignored for IAA). + +The 'IAA device bind path' is /sys/bus/dsa/drivers/idxd/bind and is +the file that is written to enable an IAA device. + +The 'IAA workqueue bind path' is /sys/bus/dsa/drivers/crypto/bind and +is the file that is written to enable an IAA workqueue. + +Similarly /sys/bus/dsa/drivers/idxd/unbind and +/sys/bus/dsa/drivers/crypto/unbind are used to disable IAA devices and +workqueues. + +The basic sequence of commands needed to set up the IAA devices and +workqueues is: + +For each device:: + 1) Disable any workqueues enabled on the device. For example to + disable workques 0 and 1 on IAA device 3:: + + # echo wq3.0 > /sys/bus/dsa/drivers/crypto/unbind + # echo wq3.1 > /sys/bus/dsa/drivers/crypto/unbind + + 2) Disable the device. For example to disable IAA device 3:: + + # echo iax3 > /sys/bus/dsa/drivers/idxd/unbind + + 3) configure the desired workqueues. For example, to configure + workqueue 3 on IAA device 3:: + + # echo dedicated > /sys/bus/dsa/devices/iax3/wq3.3/mode + # echo 128 > /sys/bus/dsa/devices/iax3/wq3.3/size + # echo 0 > /sys/bus/dsa/devices/iax3/wq3.3/group_id + # echo 10 > /sys/bus/dsa/devices/iax3/wq3.3/priority + # echo "kernel" > /sys/bus/dsa/devices/iax3/wq3.3/type + # echo "iaa_crypto" > /sys/bus/dsa/devices/iax3/wq3.3/name + # echo "crypto" > /sys/bus/dsa/devices/iax3/wq3.3/driver_name + + 4) Enable the device. For example to enable IAA device 3:: + + # echo iax3 > /sys/bus/dsa/drivers/idxd/bind + + 5) Enable the desired workqueues on the device. For example to + enable workques 0 and 1 on IAA device 3:: + + # echo wq3.0 > /sys/bus/dsa/drivers/crypto/bind + # echo wq3.1 > /sys/bus/dsa/drivers/crypto/bind diff --git a/Documentation/driver-api/crypto/iaa/index.rst b/Documentation/driver-api/crypto/iaa/index.rst new file mode 100644 index 00000000000000..aa6837e272643f --- /dev/null +++ b/Documentation/driver-api/crypto/iaa/index.rst @@ -0,0 +1,20 @@ +.. SPDX-License-Identifier: GPL-2.0 + +================================= +IAA (Intel Analytics Accelerator) +================================= + +IAA provides hardware compression and decompression via the crypto +API. + +.. toctree:: + :maxdepth: 1 + + iaa-crypto + +.. only:: subproject and html + + Indices + ======= + + * :ref:`genindex` diff --git a/Documentation/driver-api/crypto/index.rst b/Documentation/driver-api/crypto/index.rst new file mode 100644 index 00000000000000..fb9709b98beaab --- /dev/null +++ b/Documentation/driver-api/crypto/index.rst @@ -0,0 +1,20 @@ +.. SPDX-License-Identifier: GPL-2.0 + +============== +Crypto Drivers +============== + +Documentation for crypto drivers that may need more involved setup and +configuration. + +.. toctree:: + :maxdepth: 1 + + iaa/index + +.. only:: subproject and html + + Indices + ======= + + * :ref:`genindex` diff --git a/Documentation/driver-api/dcdbas.rst b/Documentation/driver-api/dcdbas.rst deleted file mode 100644 index 309cc57a7c1c8a..00000000000000 --- a/Documentation/driver-api/dcdbas.rst +++ /dev/null @@ -1,99 +0,0 @@ -=================================== -Dell Systems Management Base Driver -=================================== - -Overview -======== - -The Dell Systems Management Base Driver provides a sysfs interface for -systems management software such as Dell OpenManage to perform system -management interrupts and host control actions (system power cycle or -power off after OS shutdown) on certain Dell systems. - -Dell OpenManage requires this driver on the following Dell PowerEdge systems: -300, 1300, 1400, 400SC, 500SC, 1500SC, 1550, 600SC, 1600SC, 650, 1655MC, -700, and 750. Other Dell software such as the open source libsmbios project -is expected to make use of this driver, and it may include the use of this -driver on other Dell systems. - -The Dell libsmbios project aims towards providing access to as much BIOS -information as possible. See http://linux.dell.com/libsmbios/main/ for -more information about the libsmbios project. - - -System Management Interrupt -=========================== - -On some Dell systems, systems management software must access certain -management information via a system management interrupt (SMI). The SMI data -buffer must reside in 32-bit address space, and the physical address of the -buffer is required for the SMI. The driver maintains the memory required for -the SMI and provides a way for the application to generate the SMI. -The driver creates the following sysfs entries for systems management -software to perform these system management interrupts:: - - /sys/devices/platform/dcdbas/smi_data - /sys/devices/platform/dcdbas/smi_data_buf_phys_addr - /sys/devices/platform/dcdbas/smi_data_buf_size - /sys/devices/platform/dcdbas/smi_request - -Systems management software must perform the following steps to execute -a SMI using this driver: - -1) Lock smi_data. -2) Write system management command to smi_data. -3) Write "1" to smi_request to generate a calling interface SMI or - "2" to generate a raw SMI. -4) Read system management command response from smi_data. -5) Unlock smi_data. - - -Host Control Action -=================== - -Dell OpenManage supports a host control feature that allows the administrator -to perform a power cycle or power off of the system after the OS has finished -shutting down. On some Dell systems, this host control feature requires that -a driver perform a SMI after the OS has finished shutting down. - -The driver creates the following sysfs entries for systems management software -to schedule the driver to perform a power cycle or power off host control -action after the system has finished shutting down: - -/sys/devices/platform/dcdbas/host_control_action -/sys/devices/platform/dcdbas/host_control_smi_type -/sys/devices/platform/dcdbas/host_control_on_shutdown - -Dell OpenManage performs the following steps to execute a power cycle or -power off host control action using this driver: - -1) Write host control action to be performed to host_control_action. -2) Write type of SMI that driver needs to perform to host_control_smi_type. -3) Write "1" to host_control_on_shutdown to enable host control action. -4) Initiate OS shutdown. - (Driver will perform host control SMI when it is notified that the OS - has finished shutting down.) - - -Host Control SMI Type -===================== - -The following table shows the value to write to host_control_smi_type to -perform a power cycle or power off host control action: - -=================== ===================== -PowerEdge System Host Control SMI Type -=================== ===================== - 300 HC_SMITYPE_TYPE1 - 1300 HC_SMITYPE_TYPE1 - 1400 HC_SMITYPE_TYPE2 - 500SC HC_SMITYPE_TYPE2 - 1500SC HC_SMITYPE_TYPE2 - 1550 HC_SMITYPE_TYPE2 - 600SC HC_SMITYPE_TYPE2 - 1600SC HC_SMITYPE_TYPE2 - 650 HC_SMITYPE_TYPE2 - 1655MC HC_SMITYPE_TYPE2 - 700 HC_SMITYPE_TYPE3 - 750 HC_SMITYPE_TYPE3 -=================== ===================== diff --git a/Documentation/driver-api/device-io.rst b/Documentation/driver-api/device-io.rst index 2c7abd234f4e24..d55384b106bd4e 100644 --- a/Documentation/driver-api/device-io.rst +++ b/Documentation/driver-api/device-io.rst @@ -408,11 +408,12 @@ functions for details on the CPU side of things. ioremap_uc() ------------ -ioremap_uc() behaves like ioremap() except that on the x86 architecture without -'PAT' mode, it marks memory as uncached even when the MTRR has designated -it as cacheable, see Documentation/arch/x86/pat.rst. +ioremap_uc() is only meaningful on old x86-32 systems with the PAT extension, +and on ia64 with its slightly unconventional ioremap() behavior, everywhere +elss ioremap_uc() defaults to return NULL. -Portable drivers should avoid the use of ioremap_uc(). + +Portable drivers should avoid the use of ioremap_uc(), use ioremap() instead. ioremap_cache() --------------- diff --git a/Documentation/driver-api/index.rst b/Documentation/driver-api/index.rst index f549a68951d70f..eba851605388e8 100644 --- a/Documentation/driver-api/index.rst +++ b/Documentation/driver-api/index.rst @@ -9,11 +9,8 @@ of device drivers. This document is an only somewhat organized collection of some of those interfaces — it will hopefully get better over time! The available subsections can be seen below. -.. class:: toc-title - - Table of contents - .. toctree:: + :caption: Table of contents :maxdepth: 2 driver-model/index @@ -81,10 +78,8 @@ available subsections can be seen below. backlight/lp855x-driver.rst connector console - dcdbas eisa isa - isapnp io-mapping io_ordering generic-counter @@ -115,6 +110,9 @@ available subsections can be seen below. hte/index wmi dpll + wbrf + crypto/index + tee .. only:: subproject and html diff --git a/Documentation/driver-api/isapnp.rst b/Documentation/driver-api/isapnp.rst deleted file mode 100644 index 8d0840ac847bfc..00000000000000 --- a/Documentation/driver-api/isapnp.rst +++ /dev/null @@ -1,15 +0,0 @@ -========================================================== -ISA Plug & Play support by Jaroslav Kysela -========================================================== - -Interface /proc/isapnp -====================== - -The interface has been removed. See pnp.txt for more details. - -Interface /proc/bus/isapnp -========================== - -This directory allows access to ISA PnP cards and logical devices. -The regular files contain the contents of ISA PnP registers for -a logical device. diff --git a/Documentation/driver-api/media/camera-sensor.rst b/Documentation/driver-api/media/camera-sensor.rst index 6456145f96ed00..b4920b34cebcc7 100644 --- a/Documentation/driver-api/media/camera-sensor.rst +++ b/Documentation/driver-api/media/camera-sensor.rst @@ -9,8 +9,8 @@ This document covers the in-kernel APIs only. For the best practices on userspace API implementation in camera sensor drivers, please see :ref:`media_using_camera_sensor_drivers`. -CSI-2 and parallel (BT.601 and BT.656) busses ---------------------------------------------- +CSI-2, parallel and BT.656 buses +-------------------------------- Please see :ref:`transmitter-receiver`. @@ -60,7 +60,8 @@ management over the pipeline. Camera sensor drivers are responsible for controlling the power state of the device they otherwise control as well. They shall use runtime PM to manage power states. Runtime PM shall be enabled at probe time and disabled at remove -time. Drivers should enable runtime PM autosuspend. +time. Drivers should enable runtime PM autosuspend. Also see +:ref:`async sub-device registration `. The runtime PM handlers shall handle clocks, regulators, GPIOs, and other system resources required to power the sensor up and down. For drivers that diff --git a/Documentation/driver-api/media/drivers/ccs/mk-ccs-regs b/Documentation/driver-api/media/drivers/ccs/mk-ccs-regs index 2a4edc7e051afc..3d3152b458219e 100755 --- a/Documentation/driver-api/media/drivers/ccs/mk-ccs-regs +++ b/Documentation/driver-api/media/drivers/ccs/mk-ccs-regs @@ -82,14 +82,6 @@ for my $fh ($H, $LH) { print $fh "/* $license */\n$copyright$note\n"; } -sub bit_def($) { - my $bit = shift @_; - - return "BIT($bit)" if defined $kernel; - return "(1U << $bit)" if $bit =~ /^[a-zA-Z0-9_]+$/; - return "(1U << ($bit))"; -} - print $H <\n\n" if defined $kernel; - print $H < + +#include + EOF - ; + if defined $kernel; + +print $H "#define CCS_FL_BASE " . + (defined $kernel ? "CCI_REG_PRIVATE_SHIFT" : 16) . "\n"; + +my $flag = -1; +my $all_flags; + +sub bit_def($) { + my $bit = shift @_; + + if (defined $kernel) { + return "BIT$bit" if $bit =~ /^\(.*\)$/; + return "BIT($bit)"; + } + return "(1U << $bit)"; +} + +sub flag_str($$) { + my ($flag, $check) = @_; -print $H "#define CCS_FL_16BIT " . bit_def("CCS_FL_BASE") . "\n"; -print $H "#define CCS_FL_32BIT " . bit_def("CCS_FL_BASE + 1") . "\n"; -print $H "#define CCS_FL_FLOAT_IREAL " . bit_def("CCS_FL_BASE + 2") . "\n"; -print $H "#define CCS_FL_IREAL " . bit_def("CCS_FL_BASE + 3") . "\n"; + $$flag++; + + my $flag_str = !$$flag ? "CCS_FL_BASE" : "(CCS_FL_BASE + $$flag)"; + + $flag_str = bit_def($flag_str); + + $$check .= " | " if defined $$check; + + $$check .= $flag_str; + + return $flag_str; +} + +if (! defined $kernel) { + print $H "#define CCS_FL_16BIT " . flag_str(\$flag, \$all_flags) . "\n"; + print $H "#define CCS_FL_32BIT " . flag_str(\$flag, \$all_flags) . "\n"; +} + +print $H "#define CCS_FL_FLOAT_IREAL " . flag_str(\$flag, \$all_flags) . "\n"; +print $H "#define CCS_FL_IREAL " . flag_str(\$flag, \$all_flags) . "\n"; +print $H "#define CCS_BUILD_BUG \\ + BUILD_BUG_ON(~CCI_REG_PRIVATE_MASK & ($all_flags))\n" + if defined $kernel; print $H < @@ -189,12 +221,12 @@ sub tabconv($) { return (join "\n", @l) . "\n"; } -sub elem_size(@) { +sub elem_bits(@) { my @flags = @_; - return 2 if grep /^16$/, @flags; - return 4 if grep /^32$/, @flags; - return 1; + return 16 if grep /^16$/, @flags; + return 32 if grep /^32$/, @flags; + return 8; } sub arr_size($) { @@ -296,9 +328,13 @@ while (<$R>) { next if $#{$this{args}} + 1 != scalar keys %{$this{argparams}}; - my $reg_formula = "($this{addr}"; + my $reg_formula = "$this{addr}"; my $lim_formula; + chop $reg_formula; + + $reg_formula = "(" . $reg_formula if $this{flagstring} ne ""; + foreach my $arg (@{$this{args}}) { my $d = $h->{$arg}->{discontig}; my $times = $h->{$arg}->{elsize} != 1 ? @@ -315,11 +351,13 @@ while (<$R>) { $lim_formula .= (defined $lim_formula ? " + " : "") . "($arg)$times"; } - $reg_formula .= ")\n"; + $reg_formula .= ")"; $lim_formula =~ s/^\(([a-z0-9]+)\)$/$1/i; print $H tabconv sprintf("#define %-62s %s", "CCS_R_" . (uc $this{name}) . - $this{arglist}, $reg_formula); + $this{arglist}, $reg_formula . + (($this{flagstring} eq "") ? "" : + " | " . $this{flagstring} . ")") . "\n"); print $H tabconv $hdr_data; undef $hdr_data; @@ -369,16 +407,23 @@ while (<$R>) { $name =~ s/[,\.-]/_/g; my $flagstring = ""; - my $size = elem_size(@flags); - $flagstring .= "| CCS_FL_16BIT " if $size eq "2"; - $flagstring .= "| CCS_FL_32BIT " if $size eq "4"; + my $bits = elem_bits(@flags); + if (! defined $kernel) { + $flagstring .= "| CCS_FL_16BIT " if $bits == 16; + $flagstring .= "| CCS_FL_32BIT " if $bits == 32; + } $flagstring .= "| CCS_FL_FLOAT_IREAL " if grep /^float_ireal$/, @flags; $flagstring .= "| CCS_FL_IREAL " if grep /^ireal$/, @flags; $flagstring =~ s/^\| //; $flagstring =~ s/ $//; $flagstring = "($flagstring)" if $flagstring =~ /\|/; my $base_addr = $addr; - $addr = "($addr | $flagstring)" if $flagstring ne ""; + $addr = "CCI_REG$bits($addr)" if defined $kernel; + + if ($flagstring ne "" && !@$args) { + $addr = "($addr | $flagstring)"; + $flagstring = ""; + } my $arglist = @$args ? "(" . (join ", ", @$args) . ")" : ""; $hdr_data .= sprintf "#define %-62s %s\n", "CCS_R_" . (uc $name), $addr @@ -388,11 +433,12 @@ while (<$R>) { %this = ( name => $name, addr => $addr, + flagstring => $flagstring, base_addr => $base_addr, argparams => {}, args => $args, arglist => $arglist, - elsize => $size, + elsize => $bits / 8, ); if (!@$args) { diff --git a/Documentation/driver-api/media/index.rst b/Documentation/driver-api/media/index.rst index 08e206567408cd..d5593182a3f969 100644 --- a/Documentation/driver-api/media/index.rst +++ b/Documentation/driver-api/media/index.rst @@ -20,13 +20,8 @@ Documentation/userspace-api/media/index.rst - for the userspace APIs used on media devices. -.. only:: html - - .. class:: toc-title - - Table of Contents - .. toctree:: + :caption: Table of Contents :maxdepth: 5 :numbered: diff --git a/Documentation/driver-api/media/tx-rx.rst b/Documentation/driver-api/media/tx-rx.rst index e1e9258dd86246..29d66a47b56e95 100644 --- a/Documentation/driver-api/media/tx-rx.rst +++ b/Documentation/driver-api/media/tx-rx.rst @@ -6,8 +6,8 @@ Pixel data transmitter and receiver drivers =========================================== V4L2 supports various devices that transmit and receive pixel data. Examples of -these devices include a camera sensor, a TV tuner and a parallel or a CSI-2 -receiver in an SoC. +these devices include a camera sensor, a TV tuner and a parallel, a BT.656 or a +CSI-2 receiver in an SoC. Bus types --------- @@ -22,12 +22,13 @@ the host SoC. It is defined by the `MIPI alliance`_. .. _`MIPI alliance`: https://www.mipi.org/ -Parallel -^^^^^^^^ +Parallel and BT.656 +^^^^^^^^^^^^^^^^^^^ -`BT.601`_ and `BT.656`_ are the most common parallel busses. +The parallel and `BT.656`_ buses transport one bit of data on each clock cycle +per data line. The parallel bus uses synchronisation and other additional +signals whereas BT.656 embeds synchronisation. -.. _`BT.601`: https://en.wikipedia.org/wiki/Rec._601 .. _`BT.656`: https://en.wikipedia.org/wiki/ITU-R_BT.656 Transmitter drivers @@ -90,8 +91,8 @@ where pixel rate on the camera sensor's pixel array which is indicated by the :ref:`V4L2_CID_PIXEL_RATE ` control. -LP-11 and LP-111 modes -^^^^^^^^^^^^^^^^^^^^^^ +LP-11 and LP-111 states +^^^^^^^^^^^^^^^^^^^^^^^ As part of transitioning to high speed mode, a CSI-2 transmitter typically briefly sets the bus to LP-11 or LP-111 state, depending on the PHY. This period @@ -105,7 +106,7 @@ in software, especially when there is no interrupt telling something is happening. One way to address this is to configure the transmitter side explicitly to LP-11 -or LP-111 mode, which requires support from the transmitter hardware. This is +or LP-111 state, which requires support from the transmitter hardware. This is not universally available. Many devices return to this state once streaming is stopped while the state after power-on is LP-00 or LP-000. @@ -116,11 +117,11 @@ transitioning to streaming state, but not yet start streaming. Similarly, the to call ``.post_streamoff()`` for each successful call of ``.pre_streamon()``. In the context of CSI-2, the ``.pre_streamon()`` callback is used to transition -the transmitter to the LP-11 or LP-111 mode. This also requires powering on the +the transmitter to the LP-11 or LP-111 state. This also requires powering on the device, so this should be only done when it is needed. -Receiver drivers that do not need explicit LP-11 or LP-111 mode setup are waived -from calling the two callbacks. +Receiver drivers that do not need explicit LP-11 or LP-111 state setup are +waived from calling the two callbacks. Stopping the transmitter ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/Documentation/driver-api/media/v4l2-subdev.rst b/Documentation/driver-api/media/v4l2-subdev.rst index e56b50b3f203ee..1db2ba27c54c3d 100644 --- a/Documentation/driver-api/media/v4l2-subdev.rst +++ b/Documentation/driver-api/media/v4l2-subdev.rst @@ -181,6 +181,8 @@ You can unregister a sub-device using: Afterwards the subdev module can be unloaded and :c:type:`sd `->dev == ``NULL``. +.. _media-registering-async-subdevs: + Registering asynchronous sub-devices ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -195,6 +197,11 @@ performed using the :c:func:`v4l2_async_unregister_subdev` call. Subdevices registered this way are stored in a global list of subdevices, ready to be picked up by bridge drivers. +Drivers must complete all initialization of the sub-device before +registering it using :c:func:`v4l2_async_register_subdev`, including +enabling runtime PM. This is because the sub-device becomes accessible +as soon as it gets registered. + Asynchronous sub-device notifiers ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -562,8 +569,8 @@ device configuration. This is often implemented as e.g. an array of struct v4l2_mbus_framefmt, one entry for each pad, and similarly for crop and compose rectangles. -In addition to the active configuration, each subdev file handle has an array of -struct v4l2_subdev_pad_config, managed by the V4L2 core, which contains the try +In addition to the active configuration, each subdev file handle has a struct +v4l2_subdev_state, managed by the V4L2 core, which contains the try configuration. To simplify the subdev drivers the V4L2 subdev API now optionally supports a diff --git a/Documentation/driver-api/mei/index.rst b/Documentation/driver-api/mei/index.rst index 3a22b522ee782b..eae6f18f18cff6 100644 --- a/Documentation/driver-api/mei/index.rst +++ b/Documentation/driver-api/mei/index.rst @@ -9,13 +9,8 @@ Intel(R) Management Engine Interface (Intel(R) MEI) **Copyright** |copy| 2019 Intel Corporation -.. only:: html - - .. class:: toc-title - - Table of Contents - .. toctree:: + :caption: Table of Contents :maxdepth: 3 mei diff --git a/Documentation/driver-api/mtd/spi-nor.rst b/Documentation/driver-api/mtd/spi-nor.rst index c22f8c0f7950e1..148fa4288760b6 100644 --- a/Documentation/driver-api/mtd/spi-nor.rst +++ b/Documentation/driver-api/mtd/spi-nor.rst @@ -2,64 +2,204 @@ SPI NOR framework ================= -Part I - Why do we need this framework? ---------------------------------------- - -SPI bus controllers (drivers/spi/) only deal with streams of bytes; the bus -controller operates agnostic of the specific device attached. However, some -controllers (such as Freescale's QuadSPI controller) cannot easily handle -arbitrary streams of bytes, but rather are designed specifically for SPI NOR. - -In particular, Freescale's QuadSPI controller must know the NOR commands to -find the right LUT sequence. Unfortunately, the SPI subsystem has no notion of -opcodes, addresses, or data payloads; a SPI controller simply knows to send or -receive bytes (Tx and Rx). Therefore, we must define a new layering scheme under -which the controller driver is aware of the opcodes, addressing, and other -details of the SPI NOR protocol. - -Part II - How does the framework work? --------------------------------------- - -This framework just adds a new layer between the MTD and the SPI bus driver. -With this new layer, the SPI NOR controller driver does not depend on the -m25p80 code anymore. - -Before this framework, the layer is like:: - - MTD - ------------------------ - m25p80 - ------------------------ - SPI bus driver - ------------------------ - SPI NOR chip - -After this framework, the layer is like:: - - MTD - ------------------------ - SPI NOR framework - ------------------------ - m25p80 - ------------------------ - SPI bus driver - ------------------------ - SPI NOR chip - -With the SPI NOR controller driver (Freescale QuadSPI), it looks like:: - - MTD - ------------------------ - SPI NOR framework - ------------------------ - fsl-quadSPI - ------------------------ - SPI NOR chip - -Part III - How can drivers use the framework? ---------------------------------------------- - -The main API is spi_nor_scan(). Before you call the hook, a driver should -initialize the necessary fields for spi_nor{}. Please see -drivers/mtd/spi-nor/spi-nor.c for detail. Please also refer to spi-fsl-qspi.c -when you want to write a new driver for a SPI NOR controller. +How to propose a new flash addition +----------------------------------- + +Most SPI NOR flashes comply with the JEDEC JESD216 +Serial Flash Discoverable Parameter (SFDP) standard. SFDP describes +the functional and feature capabilities of serial flash devices in a +standard set of internal read-only parameter tables. + +The SPI NOR driver queries the SFDP tables in order to determine the +flash's parameters and settings. If the flash defines the SFDP tables +it's likely that you won't need a flash entry at all, and instead +rely on the generic flash driver which probes the flash solely based +on its SFDP data. All one has to do is to specify the "jedec,spi-nor" +compatible in the device tree. + +There are cases however where you need to define an explicit flash +entry. This typically happens when the flash has settings or support +that is not covered by the SFDP tables (e.g. Block Protection), or +when the flash contains mangled SFDP data. If the later, one needs +to implement the ``spi_nor_fixups`` hooks in order to amend the SFDP +parameters with the correct values. + +Minimum testing requirements +----------------------------- + +Do all the tests from below and paste them in the commit's comments +section, after the ``---`` marker. + +1) Specify the controller that you used to test the flash and specify + the frequency at which the flash was operated, e.g.:: + + This flash is populated on the X board and was tested at Y + frequency using the Z (put compatible) SPI controller. + +2) Dump the sysfs entries and print the md5/sha1/sha256 SFDP checksum:: + + root@1:~# cat /sys/bus/spi/devices/spi0.0/spi-nor/partname + sst26vf064b + root@1:~# cat /sys/bus/spi/devices/spi0.0/spi-nor/jedec_id + bf2643 + root@1:~# cat /sys/bus/spi/devices/spi0.0/spi-nor/manufacturer + sst + root@1:~# xxd -p /sys/bus/spi/devices/spi0.0/spi-nor/sfdp + 53464450060102ff00060110300000ff81000106000100ffbf0001180002 + 0001fffffffffffffffffffffffffffffffffd20f1ffffffff0344eb086b + 083b80bbfeffffffffff00ffffff440b0c200dd80fd810d820914824806f + 1d81ed0f773830b030b0f7ffffff29c25cfff030c080ffffffffffffffff + ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + ffffffffffffffffffffffffffffffffff0004fff37f0000f57f0000f9ff + 7d00f57f0000f37f0000ffffffffffffffffffffffffffffffffffffffff + ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + ffffbf2643ffb95ffdff30f260f332ff0a122346ff0f19320f1919ffffff + ffffffff00669938ff05013506040232b03072428de89888a585c09faf5a + ffff06ec060c0003080bffffffffff07ffff0202ff060300fdfd040700fc + 0300fefe0202070e + root@1:~# sha256sum /sys/bus/spi/devices/spi0.0/spi-nor/sfdp + 428f34d0461876f189ac97f93e68a05fa6428c6650b3b7baf736a921e5898ed1 /sys/bus/spi/devices/spi0.0/spi-nor/sfdp + + Please dump the SFDP tables using ``xxd -p``. It enables us to do + the reverse operation and convert the hexdump to binary with + ``xxd -rp``. Dumping the SFDP data with ``hexdump -Cv`` is accepted, + but less desirable. + +3) Dump debugfs data:: + + root@1:~# cat /sys/kernel/debug/spi-nor/spi0.0/capabilities + Supported read modes by the flash + 1S-1S-1S + opcode 0x03 + mode cycles 0 + dummy cycles 0 + 1S-1S-1S (fast read) + opcode 0x0b + mode cycles 0 + dummy cycles 8 + 1S-1S-2S + opcode 0x3b + mode cycles 0 + dummy cycles 8 + 1S-2S-2S + opcode 0xbb + mode cycles 4 + dummy cycles 0 + 1S-1S-4S + opcode 0x6b + mode cycles 0 + dummy cycles 8 + 1S-4S-4S + opcode 0xeb + mode cycles 2 + dummy cycles 4 + 4S-4S-4S + opcode 0x0b + mode cycles 2 + dummy cycles 4 + + Supported page program modes by the flash + 1S-1S-1S + opcode 0x02 + + root@1:~# cat /sys/kernel/debug/spi-nor/spi0.0/params + name sst26vf064b + id bf 26 43 bf 26 43 + size 8.00 MiB + write size 1 + page size 256 + address nbytes 3 + flags HAS_LOCK | HAS_16BIT_SR | SOFT_RESET | SWP_IS_VOLATILE + + opcodes + read 0xeb + dummy cycles 6 + erase 0x20 + program 0x02 + 8D extension none + + protocols + read 1S-4S-4S + write 1S-1S-1S + register 1S-1S-1S + + erase commands + 20 (4.00 KiB) [0] + d8 (8.00 KiB) [1] + d8 (32.0 KiB) [2] + d8 (64.0 KiB) [3] + c7 (8.00 MiB) + + sector map + region (in hex) | erase mask | flags + ------------------+------------+---------- + 00000000-00007fff | [01 ] | + 00008000-0000ffff | [0 2 ] | + 00010000-007effff | [0 3] | + 007f0000-007f7fff | [0 2 ] | + 007f8000-007fffff | [01 ] | + +4) Use `mtd-utils `__ + and verify that erase, read and page program operations work fine:: + + root@1:~# dd if=/dev/urandom of=./spi_test bs=1M count=2 + 2+0 records in + 2+0 records out + 2097152 bytes (2.1 MB, 2.0 MiB) copied, 0.848566 s, 2.5 MB/s + + root@1:~# mtd_debug erase /dev/mtd0 0 2097152 + Erased 2097152 bytes from address 0x00000000 in flash + + root@1:~# mtd_debug read /dev/mtd0 0 2097152 spi_read + Copied 2097152 bytes from address 0x00000000 in flash to spi_read + + root@1:~# hexdump spi_read + 0000000 ffff ffff ffff ffff ffff ffff ffff ffff + * + 0200000 + + root@1:~# sha256sum spi_read + 4bda3a28f4ffe603c0ec1258c0034d65a1a0d35ab7bd523a834608adabf03cc5 spi_read + + root@1:~# mtd_debug write /dev/mtd0 0 2097152 spi_test + Copied 2097152 bytes from spi_test to address 0x00000000 in flash + + root@1:~# mtd_debug read /dev/mtd0 0 2097152 spi_read + Copied 2097152 bytes from address 0x00000000 in flash to spi_read + + root@1:~# sha256sum spi* + c444216a6ba2a4a66cccd60a0dd062bce4b865dd52b200ef5e21838c4b899ac8 spi_read + c444216a6ba2a4a66cccd60a0dd062bce4b865dd52b200ef5e21838c4b899ac8 spi_test + + If the flash comes erased by default and the previous erase was ignored, + we won't catch it, thus test the erase again:: + + root@1:~# mtd_debug erase /dev/mtd0 0 2097152 + Erased 2097152 bytes from address 0x00000000 in flash + + root@1:~# mtd_debug read /dev/mtd0 0 2097152 spi_read + Copied 2097152 bytes from address 0x00000000 in flash to spi_read + + root@1:~# sha256sum spi* + 4bda3a28f4ffe603c0ec1258c0034d65a1a0d35ab7bd523a834608adabf03cc5 spi_read + c444216a6ba2a4a66cccd60a0dd062bce4b865dd52b200ef5e21838c4b899ac8 spi_test + + Dump some other relevant data:: + + root@1:~# mtd_debug info /dev/mtd0 + mtd.type = MTD_NORFLASH + mtd.flags = MTD_CAP_NORFLASH + mtd.size = 8388608 (8M) + mtd.erasesize = 4096 (4K) + mtd.writesize = 1 + mtd.oobsize = 0 + regions = 0 diff --git a/Documentation/driver-api/nvmem.rst b/Documentation/driver-api/nvmem.rst index de221e91c8e34d..5d9500d21ecc42 100644 --- a/Documentation/driver-api/nvmem.rst +++ b/Documentation/driver-api/nvmem.rst @@ -41,7 +41,7 @@ A NVMEM provider can register with NVMEM core by supplying relevant nvmem configuration to nvmem_register(), on success core would return a valid nvmem_device pointer. -nvmem_unregister(nvmem) is used to unregister a previously registered provider. +nvmem_unregister() is used to unregister a previously registered provider. For example, a simple nvram case:: @@ -200,3 +200,9 @@ and let you add cells dynamically. Another use case for layouts is the post processing of cells. With layouts, it is possible to associate a custom post processing hook to a cell. It even possible to add this hook to cells not created by the layout itself. + +9. Internal kernel API +====================== + +.. kernel-doc:: drivers/nvmem/core.c + :export: diff --git a/Documentation/driver-api/pci/index.rst b/Documentation/driver-api/pci/index.rst index c6cf1fef61cec8..a38e475cdbe3bd 100644 --- a/Documentation/driver-api/pci/index.rst +++ b/Documentation/driver-api/pci/index.rst @@ -4,11 +4,8 @@ The Linux PCI driver implementer's API guide ============================================ -.. class:: toc-title - - Table of contents - .. toctree:: + :caption: Table of contents :maxdepth: 2 pci diff --git a/Documentation/driver-api/pci/p2pdma.rst b/Documentation/driver-api/pci/p2pdma.rst index 44deb52beeb476..d0b241628cf13d 100644 --- a/Documentation/driver-api/pci/p2pdma.rst +++ b/Documentation/driver-api/pci/p2pdma.rst @@ -83,19 +83,9 @@ this to include other types of resources like doorbells. Client Drivers -------------- -A client driver typically only has to conditionally change its DMA map -routine to use the mapping function :c:func:`pci_p2pdma_map_sg()` instead -of the usual :c:func:`dma_map_sg()` function. Memory mapped in this -way does not need to be unmapped. - -The client may also, optionally, make use of -:c:func:`is_pci_p2pdma_page()` to determine when to use the P2P mapping -functions and when to use the regular mapping functions. In some -situations, it may be more appropriate to use a flag to indicate a -given request is P2P memory and map appropriately. It is important to -ensure that struct pages that back P2P memory stay out of code that -does not have support for them as other code may treat the pages as -regular memory which may not be appropriate. +A client driver only has to use the mapping API :c:func:`dma_map_sg()` +and :c:func:`dma_unmap_sg()` functions as usual, and the implementation +will do the right thing for the P2P capable memory. Orchestrator Drivers diff --git a/Documentation/driver-api/pwm.rst b/Documentation/driver-api/pwm.rst index bb264490a87a16..3c28ccc4b61133 100644 --- a/Documentation/driver-api/pwm.rst +++ b/Documentation/driver-api/pwm.rst @@ -41,11 +41,20 @@ the getter, devm_pwm_get() and devm_fwnode_pwm_get(), also exist. After being requested, a PWM has to be configured using:: - int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state); + int pwm_apply_might_sleep(struct pwm_device *pwm, struct pwm_state *state); This API controls both the PWM period/duty_cycle config and the enable/disable state. +PWM devices can be used from atomic context, if the PWM does not sleep. You +can check if this the case with:: + + bool pwm_might_sleep(struct pwm_device *pwm); + +If false, the PWM can also be configured from atomic context with:: + + int pwm_apply_atomic(struct pwm_device *pwm, struct pwm_state *state); + As a consumer, don't rely on the output's state for a disabled PWM. If it's easily possible, drivers are supposed to emit the inactive state, but some drivers cannot. If you rely on getting the inactive state, use .duty_cycle=0, @@ -57,13 +66,13 @@ If supported by the driver, the signal can be optimized, for example to improve EMI by phase shifting the individual channels of a chip. The pwm_config(), pwm_enable() and pwm_disable() functions are just wrappers -around pwm_apply_state() and should not be used if the user wants to change +around pwm_apply_might_sleep() and should not be used if the user wants to change several parameter at once. For example, if you see pwm_config() and pwm_{enable,disable}() calls in the same function, this probably means you -should switch to pwm_apply_state(). +should switch to pwm_apply_might_sleep(). The PWM user API also allows one to query the PWM state that was passed to the -last invocation of pwm_apply_state() using pwm_get_state(). Note this is +last invocation of pwm_apply_might_sleep() using pwm_get_state(). Note this is different to what the driver has actually implemented if the request cannot be satisfied exactly with the hardware in use. There is currently no way for consumers to get the actually implemented settings. diff --git a/Documentation/driver-api/surface_aggregator/ssh.rst b/Documentation/driver-api/surface_aggregator/ssh.rst index b955b673838bae..58a757319931c6 100644 --- a/Documentation/driver-api/surface_aggregator/ssh.rst +++ b/Documentation/driver-api/surface_aggregator/ssh.rst @@ -39,7 +39,7 @@ Note that the standard disclaimer for this subsystem also applies to this document: All of this has been reverse-engineered and may thus be erroneous and/or incomplete. -All CRCs used in the following are two-byte ``crc_ccitt_false(0xffff, ...)``. +All CRCs used in the following are two-byte ``crc_itu_t(0xffff, ...)``. All multi-byte values are little-endian, there is no implicit padding between values. diff --git a/Documentation/driver-api/tee.rst b/Documentation/driver-api/tee.rst new file mode 100644 index 00000000000000..5eaeb810398889 --- /dev/null +++ b/Documentation/driver-api/tee.rst @@ -0,0 +1,66 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=============================================== +TEE (Trusted Execution Environment) driver API +=============================================== + +Kernel provides a TEE bus infrastructure where a Trusted Application is +represented as a device identified via Universally Unique Identifier (UUID) and +client drivers register a table of supported device UUIDs. + +TEE bus infrastructure registers following APIs: + +match(): + iterates over the client driver UUID table to find a corresponding + match for device UUID. If a match is found, then this particular device is + probed via corresponding probe API registered by the client driver. This + process happens whenever a device or a client driver is registered with TEE + bus. + +uevent(): + notifies user-space (udev) whenever a new device is registered on + TEE bus for auto-loading of modularized client drivers. + +TEE bus device enumeration is specific to underlying TEE implementation, so it +is left open for TEE drivers to provide corresponding implementation. + +Then TEE client driver can talk to a matched Trusted Application using APIs +listed in include/linux/tee_drv.h. + +TEE client driver example +------------------------- + +Suppose a TEE client driver needs to communicate with a Trusted Application +having UUID: ``ac6a4085-0e82-4c33-bf98-8eb8e118b6c2``, so driver registration +snippet would look like:: + + static const struct tee_client_device_id client_id_table[] = { + {UUID_INIT(0xac6a4085, 0x0e82, 0x4c33, + 0xbf, 0x98, 0x8e, 0xb8, 0xe1, 0x18, 0xb6, 0xc2)}, + {} + }; + + MODULE_DEVICE_TABLE(tee, client_id_table); + + static struct tee_client_driver client_driver = { + .id_table = client_id_table, + .driver = { + .name = DRIVER_NAME, + .bus = &tee_bus_type, + .probe = client_probe, + .remove = client_remove, + }, + }; + + static int __init client_init(void) + { + return driver_register(&client_driver.driver); + } + + static void __exit client_exit(void) + { + driver_unregister(&client_driver.driver); + } + + module_init(client_init); + module_exit(client_exit); diff --git a/Documentation/driver-api/wbrf.rst b/Documentation/driver-api/wbrf.rst new file mode 100644 index 00000000000000..f48bfa02981348 --- /dev/null +++ b/Documentation/driver-api/wbrf.rst @@ -0,0 +1,78 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +================================= +WBRF - Wifi Band RFI Mitigations +================================= + +Due to electrical and mechanical constraints in certain platform designs +there may be likely interference of relatively high-powered harmonics of +the GPU memory clocks with local radio module frequency bands used by +certain Wifi bands. + +To mitigate possible RFI interference producers can advertise the +frequencies in use and consumers can use this information to avoid using +these frequencies for sensitive features. + +When a platform is known to have this issue with any contained devices, +the platform designer will advertise the availability of this feature via +ACPI devices with a device specific method (_DSM). +* Producers with this _DSM will be able to advertise the frequencies in use. +* Consumers with this _DSM will be able to register for notifications of +frequencies in use. + +Some general terms +================== + +Producer: such component who can produce high-powered radio frequency +Consumer: such component who can adjust its in-use frequency in +response to the radio frequencies of other components to mitigate the +possible RFI. + +To make the mechanism function, those producers should notify active use +of their particular frequencies so that other consumers can make relative +internal adjustments as necessary to avoid this resonance. + +ACPI interface +============== + +Although initially used by for wifi + dGPU use cases, the ACPI interface +can be scaled to any type of device that a platform designer discovers +can cause interference. + +The GUID used for the _DSM is 7B7656CF-DC3D-4C1C-83E9-66E721DE3070. + +3 functions are available in this _DSM: + +* 0: discover # of functions available +* 1: record RF bands in use +* 2: retrieve RF bands in use + +Driver programming interface +============================ + +.. kernel-doc:: drivers/platform/x86/amd/wbrf.c + +Sample Usage +============= + +The expected flow for the producers: +1. During probe, call `acpi_amd_wbrf_supported_producer` to check if WBRF +can be enabled for the device. +2. On using some frequency band, call `acpi_amd_wbrf_add_remove` with 'add' +param to get other consumers properly notified. +3. Or on stopping using some frequency band, call +`acpi_amd_wbrf_add_remove` with 'remove' param to get other consumers notified. + +The expected flow for the consumers: +1. During probe, call `acpi_amd_wbrf_supported_consumer` to check if WBRF +can be enabled for the device. +2. Call `amd_wbrf_register_notifier` to register for notification +of frequency band change(add or remove) from other producers. +3. Call the `amd_wbrf_retrieve_freq_band` initally to retrieve +current active frequency bands considering some producers may broadcast +such information before the consumer is up. +4. On receiving a notification for frequency band change, run +`amd_wbrf_retrieve_freq_band` again to retrieve the latest +active frequency bands. +5. During driver cleanup, call `amd_wbrf_unregister_notifier` to +unregister the notifier. diff --git a/Documentation/fb/index.rst b/Documentation/fb/index.rst index baf02393d8eead..33e3c49f885695 100644 --- a/Documentation/fb/index.rst +++ b/Documentation/fb/index.rst @@ -19,7 +19,6 @@ Frame Buffer framebuffer gxfb intel810 - intelfb internals lxfb matroxfb diff --git a/Documentation/fb/intelfb.rst b/Documentation/fb/intelfb.rst deleted file mode 100644 index e2d0903f4efb44..00000000000000 --- a/Documentation/fb/intelfb.rst +++ /dev/null @@ -1,155 +0,0 @@ -============================================================= -Intel 830M/845G/852GM/855GM/865G/915G/945G Framebuffer driver -============================================================= - -A. Introduction -=============== - -This is a framebuffer driver for various Intel 8xx/9xx compatible -graphics devices. These would include: - - - Intel 830M - - Intel 845G - - Intel 852GM - - Intel 855GM - - Intel 865G - - Intel 915G - - Intel 915GM - - Intel 945G - - Intel 945GM - - Intel 945GME - - Intel 965G - - Intel 965GM - -B. List of available options -============================= - - a. "video=intelfb" - enables the intelfb driver - - Recommendation: required - - b. "mode=x[-][@]" - select mode - - Recommendation: user preference - (default = 1024x768-32@70) - - c. "vram=" - select amount of system RAM in MB to allocate for the video memory - if not enough RAM was already allocated by the BIOS. - - Recommendation: 1 - 4 MB. - (default = 4 MB) - - d. "voffset=" - select at what offset in MB of the logical memory to allocate the - framebuffer memory. The intent is to avoid the memory blocks - used by standard graphics applications (XFree86). Depending on your - usage, adjust the value up or down, (0 for maximum usage, 63/127 MB - for the least amount). Note, an arbitrary setting may conflict - with XFree86. - - Recommendation: do not set - (default = 48 MB) - - e. "accel" - enable text acceleration. This can be enabled/reenabled anytime - by using 'fbset -accel true/false'. - - Recommendation: enable - (default = set) - - f. "hwcursor" - enable cursor acceleration. - - Recommendation: enable - (default = set) - - g. "mtrr" - enable MTRR. This allows data transfers to the framebuffer memory - to occur in bursts which can significantly increase performance. - Not very helpful with the intel chips because of 'shared memory'. - - Recommendation: set - (default = set) - - h. "fixed" - disable mode switching. - - Recommendation: do not set - (default = not set) - - The binary parameters can be unset with a "no" prefix, example "noaccel". - The default parameter (not named) is the mode. - -C. Kernel booting -================= - -Separate each option/option-pair by commas (,) and the option from its value -with an equals sign (=) as in the following:: - - video=intelfb:option1,option2=value2 - -Sample Usage ------------- - -In /etc/lilo.conf, add the line:: - - append="video=intelfb:mode=800x600-32@75,accel,hwcursor,vram=8" - -This will initialize the framebuffer to 800x600 at 32bpp and 75Hz. The -framebuffer will use 8 MB of System RAM. hw acceleration of text and cursor -will be enabled. - -Remarks -------- - -If setting this parameter doesn't work (you stay in a 80x25 text-mode), -you might need to set the "vga=" parameter too - see vesafb.txt -in this directory. - - -D. Module options -================== - -The module parameters are essentially similar to the kernel -parameters. The main difference is that you need to include a Boolean value -(1 for TRUE, and 0 for FALSE) for those options which don't need a value. - -Example, to enable MTRR, include "mtrr=1". - -Sample Usage ------------- - -Using the same setup as described above, load the module like this:: - - modprobe intelfb mode=800x600-32@75 vram=8 accel=1 hwcursor=1 - -Or just add the following to a configuration file in /etc/modprobe.d/:: - - options intelfb mode=800x600-32@75 vram=8 accel=1 hwcursor=1 - -and just do a:: - - modprobe intelfb - - -E. Acknowledgment: -=================== - - 1. Geert Uytterhoeven - his excellent howto and the virtual - framebuffer driver code made this possible. - - 2. Jeff Hartmann for his agpgart code. - - 3. David Dawes for his original kernel 2.4 code. - - 4. The X developers. Insights were provided just by reading the - XFree86 source code. - - 5. Antonino A. Daplas for his inspiring i810fb driver. - - 6. Andrew Morton for his kernel patches maintenance. - -Sylvain diff --git a/Documentation/features/vm/TLB/arch-support.txt b/Documentation/features/vm/TLB/arch-support.txt index 8fd22073a847e9..d222bd3ee7495b 100644 --- a/Documentation/features/vm/TLB/arch-support.txt +++ b/Documentation/features/vm/TLB/arch-support.txt @@ -20,7 +20,7 @@ | openrisc: | .. | | parisc: | TODO | | powerpc: | TODO | - | riscv: | TODO | + | riscv: | ok | | s390: | TODO | | sh: | TODO | | sparc: | TODO | diff --git a/Documentation/filesystems/directory-locking.rst b/Documentation/filesystems/directory-locking.rst index dccd61c7c5c3be..05ea387bc9fbcf 100644 --- a/Documentation/filesystems/directory-locking.rst +++ b/Documentation/filesystems/directory-locking.rst @@ -11,129 +11,268 @@ When taking the i_rwsem on multiple non-directory objects, we always acquire the locks in order by increasing address. We'll call that "inode pointer" order in the following. -For our purposes all operations fall in 5 classes: -1) read access. Locking rules: caller locks directory we are accessing. -The lock is taken shared. +Primitives +========== -2) object creation. Locking rules: same as above, but the lock is taken -exclusive. +For our purposes all operations fall in 6 classes: -3) object removal. Locking rules: caller locks parent, finds victim, -locks victim and calls the method. Locks are exclusive. +1. read access. Locking rules: -4) rename() that is _not_ cross-directory. Locking rules: caller locks the -parent and finds source and target. We lock both (provided they exist). If we -need to lock two inodes of different type (dir vs non-dir), we lock directory -first. If we need to lock two inodes of the same type, lock them in inode -pointer order. Then call the method. All locks are exclusive. -NB: we might get away with locking the source (and target in exchange -case) shared. + * lock the directory we are accessing (shared) -5) link creation. Locking rules: +2. object creation. Locking rules: - * lock parent - * check that source is not a directory - * lock source - * call the method. + * lock the directory we are accessing (exclusive) -All locks are exclusive. +3. object removal. Locking rules: -6) cross-directory rename. The trickiest in the whole bunch. Locking -rules: + * lock the parent (exclusive) + * find the victim + * lock the victim (exclusive) - * lock the filesystem - * lock parents in "ancestors first" order. If one is not ancestor of - the other, lock them in inode pointer order. - * find source and target. - * if old parent is equal to or is a descendent of target - fail with -ENOTEMPTY - * if new parent is equal to or is a descendent of source - fail with -ELOOP - * Lock both the source and the target provided they exist. If we - need to lock two inodes of different type (dir vs non-dir), we lock - the directory first. If we need to lock two inodes of the same type, - lock them in inode pointer order. - * call the method. - -All ->i_rwsem are taken exclusive. Again, we might get away with locking -the source (and target in exchange case) shared. - -The rules above obviously guarantee that all directories that are going to be -read, modified or removed by method will be locked by caller. +4. link creation. Locking rules: + + * lock the parent (exclusive) + * check that the source is not a directory + * lock the source (exclusive; probably could be weakened to shared) + +5. rename that is _not_ cross-directory. Locking rules: + + * lock the parent (exclusive) + * find the source and target + * decide which of the source and target need to be locked. + The source needs to be locked if it's a non-directory, target - if it's + a non-directory or about to be removed. + * take the locks that need to be taken (exlusive), in inode pointer order + if need to take both (that can happen only when both source and target + are non-directories - the source because it wouldn't need to be locked + otherwise and the target because mixing directory and non-directory is + allowed only with RENAME_EXCHANGE, and that won't be removing the target). +6. cross-directory rename. The trickiest in the whole bunch. Locking rules: + + * lock the filesystem + * if the parents don't have a common ancestor, fail the operation. + * lock the parents in "ancestors first" order (exclusive). If neither is an + ancestor of the other, lock the parent of source first. + * find the source and target. + * verify that the source is not a descendent of the target and + target is not a descendent of source; fail the operation otherwise. + * lock the subdirectories involved (exclusive), source before target. + * lock the non-directories involved (exclusive), in inode pointer order. + +The rules above obviously guarantee that all directories that are going +to be read, modified or removed by method will be locked by the caller. + + +Splicing +======== + +There is one more thing to consider - splicing. It's not an operation +in its own right; it may happen as part of lookup. We speak of the +operations on directory trees, but we obviously do not have the full +picture of those - especially for network filesystems. What we have +is a bunch of subtrees visible in dcache and locking happens on those. +Trees grow as we do operations; memory pressure prunes them. Normally +that's not a problem, but there is a nasty twist - what should we do +when one growing tree reaches the root of another? That can happen in +several scenarios, starting from "somebody mounted two nested subtrees +from the same NFS4 server and doing lookups in one of them has reached +the root of another"; there's also open-by-fhandle stuff, and there's a +possibility that directory we see in one place gets moved by the server +to another and we run into it when we do a lookup. + +For a lot of reasons we want to have the same directory present in dcache +only once. Multiple aliases are not allowed. So when lookup runs into +a subdirectory that already has an alias, something needs to be done with +dcache trees. Lookup is already holding the parent locked. If alias is +a root of separate tree, it gets attached to the directory we are doing a +lookup in, under the name we'd been looking for. If the alias is already +a child of the directory we are looking in, it changes name to the one +we'd been looking for. No extra locking is involved in these two cases. +However, if it's a child of some other directory, the things get trickier. +First of all, we verify that it is *not* an ancestor of our directory +and fail the lookup if it is. Then we try to lock the filesystem and the +current parent of the alias. If either trylock fails, we fail the lookup. +If trylocks succeed, we detach the alias from its current parent and +attach to our directory, under the name we are looking for. + +Note that splicing does *not* involve any modification of the filesystem; +all we change is the view in dcache. Moreover, holding a directory locked +exclusive prevents such changes involving its children and holding the +filesystem lock prevents any changes of tree topology, other than having a +root of one tree becoming a child of directory in another. In particular, +if two dentries have been found to have a common ancestor after taking +the filesystem lock, their relationship will remain unchanged until +the lock is dropped. So from the directory operations' point of view +splicing is almost irrelevant - the only place where it matters is one +step in cross-directory renames; we need to be careful when checking if +parents have a common ancestor. + + +Multiple-filesystem stuff +========================= + +For some filesystems a method can involve a directory operation on +another filesystem; it may be ecryptfs doing operation in the underlying +filesystem, overlayfs doing something to the layers, network filesystem +using a local one as a cache, etc. In all such cases the operations +on other filesystems must follow the same locking rules. Moreover, "a +directory operation on this filesystem might involve directory operations +on that filesystem" should be an asymmetric relation (or, if you will, +it should be possible to rank the filesystems so that directory operation +on a filesystem could trigger directory operations only on higher-ranked +ones - in these terms overlayfs ranks lower than its layers, network +filesystem ranks lower than whatever it caches on, etc.) + + +Deadlock avoidance +================== If no directory is its own ancestor, the scheme above is deadlock-free. Proof: - First of all, at any moment we have a linear ordering of the - objects - A < B iff (A is an ancestor of B) or (B is not an ancestor - of A and ptr(A) < ptr(B)). - - That ordering can change. However, the following is true: - -(1) if object removal or non-cross-directory rename holds lock on A and - attempts to acquire lock on B, A will remain the parent of B until we - acquire the lock on B. (Proof: only cross-directory rename can change - the parent of object and it would have to lock the parent). - -(2) if cross-directory rename holds the lock on filesystem, order will not - change until rename acquires all locks. (Proof: other cross-directory - renames will be blocked on filesystem lock and we don't start changing - the order until we had acquired all locks). - -(3) locks on non-directory objects are acquired only after locks on - directory objects, and are acquired in inode pointer order. - (Proof: all operations but renames take lock on at most one - non-directory object, except renames, which take locks on source and - target in inode pointer order in the case they are not directories.) - -Now consider the minimal deadlock. Each process is blocked on -attempt to acquire some lock and already holds at least one lock. Let's -consider the set of contended locks. First of all, filesystem lock is -not contended, since any process blocked on it is not holding any locks. -Thus all processes are blocked on ->i_rwsem. - -By (3), any process holding a non-directory lock can only be -waiting on another non-directory lock with a larger address. Therefore -the process holding the "largest" such lock can always make progress, and -non-directory objects are not included in the set of contended locks. - -Thus link creation can't be a part of deadlock - it can't be -blocked on source and it means that it doesn't hold any locks. - -Any contended object is either held by cross-directory rename or -has a child that is also contended. Indeed, suppose that it is held by -operation other than cross-directory rename. Then the lock this operation -is blocked on belongs to child of that object due to (1). - -It means that one of the operations is cross-directory rename. -Otherwise the set of contended objects would be infinite - each of them -would have a contended child and we had assumed that no object is its -own descendent. Moreover, there is exactly one cross-directory rename -(see above). - -Consider the object blocking the cross-directory rename. One -of its descendents is locked by cross-directory rename (otherwise we -would again have an infinite set of contended objects). But that -means that cross-directory rename is taking locks out of order. Due -to (2) the order hadn't changed since we had acquired filesystem lock. -But locking rules for cross-directory rename guarantee that we do not -try to acquire lock on descendent before the lock on ancestor. -Contradiction. I.e. deadlock is impossible. Q.E.D. - +There is a ranking on the locks, such that all primitives take +them in order of non-decreasing rank. Namely, + + * rank ->i_rwsem of non-directories on given filesystem in inode pointer + order. + * put ->i_rwsem of all directories on a filesystem at the same rank, + lower than ->i_rwsem of any non-directory on the same filesystem. + * put ->s_vfs_rename_mutex at rank lower than that of any ->i_rwsem + on the same filesystem. + * among the locks on different filesystems use the relative + rank of those filesystems. + +For example, if we have NFS filesystem caching on a local one, we have + + 1. ->s_vfs_rename_mutex of NFS filesystem + 2. ->i_rwsem of directories on that NFS filesystem, same rank for all + 3. ->i_rwsem of non-directories on that filesystem, in order of + increasing address of inode + 4. ->s_vfs_rename_mutex of local filesystem + 5. ->i_rwsem of directories on the local filesystem, same rank for all + 6. ->i_rwsem of non-directories on local filesystem, in order of + increasing address of inode. + +It's easy to verify that operations never take a lock with rank +lower than that of an already held lock. + +Suppose deadlocks are possible. Consider the minimal deadlocked +set of threads. It is a cycle of several threads, each blocked on a lock +held by the next thread in the cycle. + +Since the locking order is consistent with the ranking, all +contended locks in the minimal deadlock will be of the same rank, +i.e. they all will be ->i_rwsem of directories on the same filesystem. +Moreover, without loss of generality we can assume that all operations +are done directly to that filesystem and none of them has actually +reached the method call. + +In other words, we have a cycle of threads, T1,..., Tn, +and the same number of directories (D1,...,Dn) such that + + T1 is blocked on D1 which is held by T2 + + T2 is blocked on D2 which is held by T3 + + ... + + Tn is blocked on Dn which is held by T1. + +Each operation in the minimal cycle must have locked at least +one directory and blocked on attempt to lock another. That leaves +only 3 possible operations: directory removal (locks parent, then +child), same-directory rename killing a subdirectory (ditto) and +cross-directory rename of some sort. + +There must be a cross-directory rename in the set; indeed, +if all operations had been of the "lock parent, then child" sort +we would have Dn a parent of D1, which is a parent of D2, which is +a parent of D3, ..., which is a parent of Dn. Relationships couldn't +have changed since the moment directory locks had been acquired, +so they would all hold simultaneously at the deadlock time and +we would have a loop. + +Since all operations are on the same filesystem, there can't be +more than one cross-directory rename among them. Without loss of +generality we can assume that T1 is the one doing a cross-directory +rename and everything else is of the "lock parent, then child" sort. + +In other words, we have a cross-directory rename that locked +Dn and blocked on attempt to lock D1, which is a parent of D2, which is +a parent of D3, ..., which is a parent of Dn. Relationships between +D1,...,Dn all hold simultaneously at the deadlock time. Moreover, +cross-directory rename does not get to locking any directories until it +has acquired filesystem lock and verified that directories involved have +a common ancestor, which guarantees that ancestry relationships between +all of them had been stable. + +Consider the order in which directories are locked by the +cross-directory rename; parents first, then possibly their children. +Dn and D1 would have to be among those, with Dn locked before D1. +Which pair could it be? + +It can't be the parents - indeed, since D1 is an ancestor of Dn, +it would be the first parent to be locked. Therefore at least one of the +children must be involved and thus neither of them could be a descendent +of another - otherwise the operation would not have progressed past +locking the parents. + +It can't be a parent and its child; otherwise we would've had +a loop, since the parents are locked before the children, so the parent +would have to be a descendent of its child. + +It can't be a parent and a child of another parent either. +Otherwise the child of the parent in question would've been a descendent +of another child. + +That leaves only one possibility - namely, both Dn and D1 are +among the children, in some order. But that is also impossible, since +neither of the children is a descendent of another. + +That concludes the proof, since the set of operations with the +properties requiered for a minimal deadlock can not exist. + +Note that the check for having a common ancestor in cross-directory +rename is crucial - without it a deadlock would be possible. Indeed, +suppose the parents are initially in different trees; we would lock the +parent of source, then try to lock the parent of target, only to have +an unrelated lookup splice a distant ancestor of source to some distant +descendent of the parent of target. At that point we have cross-directory +rename holding the lock on parent of source and trying to lock its +distant ancestor. Add a bunch of rmdir() attempts on all directories +in between (all of those would fail with -ENOTEMPTY, had they ever gotten +the locks) and voila - we have a deadlock. + +Loop avoidance +============== These operations are guaranteed to avoid loop creation. Indeed, the only operation that could introduce loops is cross-directory rename. -Since the only new (parent, child) pair added by rename() is (new parent, -source), such loop would have to contain these objects and the rest of it -would have to exist before rename(). I.e. at the moment of loop creation -rename() responsible for that would be holding filesystem lock and new parent -would have to be equal to or a descendent of source. But that means that -new parent had been equal to or a descendent of source since the moment when -we had acquired filesystem lock and rename() would fail with -ELOOP in that -case. +Suppose after the operation there is a loop; since there hadn't been such +loops before the operation, at least on of the nodes in that loop must've +had its parent changed. In other words, the loop must be passing through +the source or, in case of exchange, possibly the target. + +Since the operation has succeeded, neither source nor target could have +been ancestors of each other. Therefore the chain of ancestors starting +in the parent of source could not have passed through the target and +vice versa. On the other hand, the chain of ancestors of any node could +not have passed through the node itself, or we would've had a loop before +the operation. But everything other than source and target has kept +the parent after the operation, so the operation does not change the +chains of ancestors of (ex-)parents of source and target. In particular, +those chains must end after a finite number of steps. + +Now consider the loop created by the operation. It passes through either +source or target; the next node in the loop would be the ex-parent of +target or source resp. After that the loop would follow the chain of +ancestors of that parent. But as we have just shown, that chain must +end after a finite number of steps, which means that it can't be a part +of any loop. Q.E.D. While this locking scheme works for arbitrary DAGs, it relies on ability to check that directory is a descendent of another object. Current diff --git a/Documentation/filesystems/fscrypt.rst b/Documentation/filesystems/fscrypt.rst index 1b84f818e574e8..e86b886b64d0e9 100644 --- a/Documentation/filesystems/fscrypt.rst +++ b/Documentation/filesystems/fscrypt.rst @@ -31,15 +31,15 @@ However, except for filenames, fscrypt does not encrypt filesystem metadata. Unlike eCryptfs, which is a stacked filesystem, fscrypt is integrated -directly into supported filesystems --- currently ext4, F2FS, and -UBIFS. This allows encrypted files to be read and written without -caching both the decrypted and encrypted pages in the pagecache, -thereby nearly halving the memory used and bringing it in line with -unencrypted files. Similarly, half as many dentries and inodes are -needed. eCryptfs also limits encrypted filenames to 143 bytes, -causing application compatibility issues; fscrypt allows the full 255 -bytes (NAME_MAX). Finally, unlike eCryptfs, the fscrypt API can be -used by unprivileged users, with no need to mount anything. +directly into supported filesystems --- currently ext4, F2FS, UBIFS, +and CephFS. This allows encrypted files to be read and written +without caching both the decrypted and encrypted pages in the +pagecache, thereby nearly halving the memory used and bringing it in +line with unencrypted files. Similarly, half as many dentries and +inodes are needed. eCryptfs also limits encrypted filenames to 143 +bytes, causing application compatibility issues; fscrypt allows the +full 255 bytes (NAME_MAX). Finally, unlike eCryptfs, the fscrypt API +can be used by unprivileged users, with no need to mount anything. fscrypt does not support encrypting files in-place. Instead, it supports marking an empty directory as encrypted. Then, after @@ -1382,7 +1382,8 @@ directory.) These structs are defined as follows:: u8 contents_encryption_mode; u8 filenames_encryption_mode; u8 flags; - u8 __reserved[4]; + u8 log2_data_unit_size; + u8 __reserved[3]; u8 master_key_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE]; u8 nonce[FSCRYPT_FILE_NONCE_SIZE]; }; diff --git a/Documentation/filesystems/index.rst b/Documentation/filesystems/index.rst index 09cade7eaefc8c..e18bc5ae3b35f8 100644 --- a/Documentation/filesystems/index.rst +++ b/Documentation/filesystems/index.rst @@ -121,8 +121,5 @@ Documentation for filesystem implementations. udf virtiofs vfat - xfs-delayed-logging-design - xfs-maintainer-entry-profile - xfs-self-describing-metadata - xfs-online-fsck-design + xfs/index zonefs diff --git a/Documentation/filesystems/locking.rst b/Documentation/filesystems/locking.rst index 7be2900806c853..d5bf4b6b7509b0 100644 --- a/Documentation/filesystems/locking.rst +++ b/Documentation/filesystems/locking.rst @@ -101,7 +101,7 @@ symlink: exclusive mkdir: exclusive unlink: exclusive (both) rmdir: exclusive (both)(see below) -rename: exclusive (all) (see below) +rename: exclusive (both parents, some children) (see below) readlink: no get_link: no setattr: exclusive @@ -123,6 +123,9 @@ get_offset_ctx no Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_rwsem exclusive on victim. cross-directory ->rename() has (per-superblock) ->s_vfs_rename_sem. + ->unlink() and ->rename() have ->i_rwsem exclusive on all non-directories + involved. + ->rename() has ->i_rwsem exclusive on any subdirectory that changes parent. See Documentation/filesystems/directory-locking.rst for more detailed discussion of the locking scheme for directory operations. @@ -261,7 +264,7 @@ prototypes:: struct folio *src, enum migrate_mode); int (*launder_folio)(struct folio *); bool (*is_partially_uptodate)(struct folio *, size_t from, size_t count); - int (*error_remove_page)(struct address_space *, struct page *); + int (*error_remove_folio)(struct address_space *, struct folio *); int (*swap_activate)(struct swap_info_struct *sis, struct file *f, sector_t *span) int (*swap_deactivate)(struct file *); int (*swap_rw)(struct kiocb *iocb, struct iov_iter *iter); @@ -287,7 +290,7 @@ direct_IO: migrate_folio: yes (both) launder_folio: yes is_partially_uptodate: yes -error_remove_page: yes +error_remove_folio: yes swap_activate: no swap_deactivate: no swap_rw: yes, unlocks diff --git a/Documentation/filesystems/netfs_library.rst b/Documentation/filesystems/netfs_library.rst index 48b95d04f72d5a..4cc657d743f7f3 100644 --- a/Documentation/filesystems/netfs_library.rst +++ b/Documentation/filesystems/netfs_library.rst @@ -295,7 +295,6 @@ through which it can issue requests and negotiate:: struct netfs_request_ops { void (*init_request)(struct netfs_io_request *rreq, struct file *file); void (*free_request)(struct netfs_io_request *rreq); - int (*begin_cache_operation)(struct netfs_io_request *rreq); void (*expand_readahead)(struct netfs_io_request *rreq); bool (*clamp_length)(struct netfs_io_subrequest *subreq); void (*issue_read)(struct netfs_io_subrequest *subreq); @@ -317,20 +316,6 @@ The operations are as follows: [Optional] This is called as the request is being deallocated so that the filesystem can clean up any state it has attached there. - * ``begin_cache_operation()`` - - [Optional] This is called to ask the network filesystem to call into the - cache (if present) to initialise the caching state for this read. The netfs - library module cannot access the cache directly, so the cache should call - something like fscache_begin_read_operation() to do this. - - The cache gets to store its state in ->cache_resources and must set a table - of operations of its own there (though of a different type). - - This should return 0 on success and an error code otherwise. If an error is - reported, the operation may proceed anyway, just without local caching (only - out of memory and interruption errors cause failure here). - * ``expand_readahead()`` [Optional] This is called to allow the filesystem to expand the size of a @@ -460,14 +445,14 @@ When implementing a local cache to be used by the read helpers, two things are required: some way for the network filesystem to initialise the caching for a read request and a table of operations for the helpers to call. -The network filesystem's ->begin_cache_operation() method is called to set up a -cache and this must call into the cache to do the work. If using fscache, for -example, the cache would call:: +To begin a cache operation on an fscache object, the following function is +called:: int fscache_begin_read_operation(struct netfs_io_request *rreq, struct fscache_cookie *cookie); -passing in the request pointer and the cookie corresponding to the file. +passing in the request pointer and the cookie corresponding to the file. This +fills in the cache resources mentioned below. The netfs_io_request object contains a place for the cache to hang its state:: diff --git a/Documentation/filesystems/overlayfs.rst b/Documentation/filesystems/overlayfs.rst index 0407f361f32a23..16551440144183 100644 --- a/Documentation/filesystems/overlayfs.rst +++ b/Documentation/filesystems/overlayfs.rst @@ -39,7 +39,7 @@ objects in the original filesystem. On 64bit systems, even if all overlay layers are not on the same underlying filesystem, the same compliant behavior could be achieved with the "xino" feature. The "xino" feature composes a unique object -identifier from the real object st_ino and an underlying fsid index. +identifier from the real object st_ino and an underlying fsid number. The "xino" feature uses the high inode number bits for fsid, because the underlying filesystems rarely use the high inode number bits. In case the underlying inode number does overflow into the high xino bits, overlay @@ -118,7 +118,7 @@ Where both upper and lower objects are directories, a merged directory is formed. At mount time, the two directories given as mount options "lowerdir" and -"upperdir" are combined into a merged directory: +"upperdir" are combined into a merged directory:: mount -t overlay overlay -olowerdir=/lower,upperdir=/upper,\ workdir=/work /merged @@ -145,7 +145,9 @@ filesystem, an overlay filesystem needs to record in the upper filesystem that files have been removed. This is done using whiteouts and opaque directories (non-directories are always opaque). -A whiteout is created as a character device with 0/0 device number. +A whiteout is created as a character device with 0/0 device number or +as a zero-size regular file with the xattr "trusted.overlay.whiteout". + When a whiteout is found in the upper level of a merged directory, any matching name in the lower level is ignored, and the whiteout itself is also hidden. @@ -154,6 +156,13 @@ A directory is made opaque by setting the xattr "trusted.overlay.opaque" to "y". Where the upper filesystem contains an opaque directory, any directory in the lower filesystem with the same name is ignored. +An opaque directory should not conntain any whiteouts, because they do not +serve any purpose. A merge directory containing regular files with the xattr +"trusted.overlay.whiteout", should be additionally marked by setting the xattr +"trusted.overlay.opaque" to "x" on the merge directory itself. +This is needed to avoid the overhead of checking the "trusted.overlay.whiteout" +on all entries during readdir in the common case. + readdir ------- @@ -172,12 +181,12 @@ directory is being read. This is unlikely to be noticed by many programs. seek offsets are assigned sequentially when the directories are read. -Thus if +Thus if: - - read part of a directory - - remember an offset, and close the directory - - re-open the directory some time later - - seek to the remembered offset + - read part of a directory + - remember an offset, and close the directory + - re-open the directory some time later + - seek to the remembered offset there may be little correlation between the old and new locations in the list of filenames, particularly if anything has changed in the @@ -290,9 +299,9 @@ Permission checking in the overlay filesystem follows these principles: 2) task creating the overlay mount MUST NOT gain additional privileges 3) non-mounting task MAY gain additional privileges through the overlay, - compared to direct access on underlying lower or upper filesystems + compared to direct access on underlying lower or upper filesystems -This is achieved by performing two permission checks on each access +This is achieved by performing two permission checks on each access: a) check if current task is allowed access based on local DAC (owner, group, mode and posix acl), as well as MAC checks @@ -311,11 +320,11 @@ to create setups where the consistency rule (1) does not hold; normally, however, the mounting task will have sufficient privileges to perform all operations. -Another way to demonstrate this model is drawing parallels between +Another way to demonstrate this model is drawing parallels between:: mount -t overlay overlay -olowerdir=/lower,upperdir=/upper,... /merged -and +and:: cp -a /lower /upper mount --bind /upper /merged @@ -328,7 +337,7 @@ Multiple lower layers --------------------- Multiple lower layers can now be given using the colon (":") as a -separator character between the directory names. For example: +separator character between the directory names. For example:: mount -t overlay overlay -olowerdir=/lower1:/lower2:/lower3 /merged @@ -340,13 +349,13 @@ rightmost one and going left. In the above example lower1 will be the top, lower2 the middle and lower3 the bottom layer. Note: directory names containing colons can be provided as lower layer by -escaping the colons with a single backslash. For example: +escaping the colons with a single backslash. For example:: mount -t overlay overlay -olowerdir=/a\:lower\:\:dir /merged Since kernel version v6.8, directory names containing colons can also be configured as lower layer using the "lowerdir+" mount options and the -fsconfig syscall from new mount api. For example: +fsconfig syscall from new mount api. For example:: fsconfig(fs_fd, FSCONFIG_SET_STRING, "lowerdir+", "/a:lower::dir", 0); @@ -356,7 +365,7 @@ as an octal characters (\072) when displayed in /proc/self/mountinfo. Metadata only copy up --------------------- -When metadata only copy up feature is enabled, overlayfs will only copy +When the "metacopy" feature is enabled, overlayfs will only copy up metadata (as opposed to whole file), when a metadata specific operation like chown/chmod is performed. Full file will be copied up later when file is opened for WRITE operation. @@ -405,7 +414,7 @@ A normal lower layer is not allowed to be below a data-only layer, so single colon separators are not allowed to the right of double colon ("::") separators. -For example: +For example:: mount -t overlay overlay -olowerdir=/l1:/l2:/l3::/do1::/do2 /merged @@ -419,7 +428,7 @@ to the absolute path of the "lower data" file in the "data-only" lower layer. Since kernel version v6.8, "data-only" lower layers can also be added using the "datadir+" mount options and the fsconfig syscall from new mount api. -For example: +For example:: fsconfig(fs_fd, FSCONFIG_SET_STRING, "lowerdir+", "/l1", 0); fsconfig(fs_fd, FSCONFIG_SET_STRING, "lowerdir+", "/l2", 0); @@ -429,7 +438,7 @@ For example: fs-verity support ----------------------- +----------------- During metadata copy up of a lower file, if the source file has fs-verity enabled and overlay verity support is enabled, then the @@ -492,27 +501,27 @@ though it will not result in a crash or deadlock. Mounting an overlay using an upper layer path, where the upper layer path was previously used by another mounted overlay in combination with a -different lower layer path, is allowed, unless the "inodes index" feature -or "metadata only copy up" feature is enabled. +different lower layer path, is allowed, unless the "index" or "metacopy" +features are enabled. -With the "inodes index" feature, on the first time mount, an NFS file +With the "index" feature, on the first time mount, an NFS file handle of the lower layer root directory, along with the UUID of the lower filesystem, are encoded and stored in the "trusted.overlay.origin" extended attribute on the upper layer root directory. On subsequent mount attempts, the lower root directory file handle and lower filesystem UUID are compared to the stored origin in upper root directory. On failure to verify the lower root origin, mount will fail with ESTALE. An overlayfs mount with -"inodes index" enabled will fail with EOPNOTSUPP if the lower filesystem +"index" enabled will fail with EOPNOTSUPP if the lower filesystem does not support NFS export, lower filesystem does not have a valid UUID or if the upper filesystem does not support extended attributes. -For "metadata only copy up" feature there is no verification mechanism at +For the "metacopy" feature, there is no verification mechanism at mount time. So if same upper is mounted with different set of lower, mount probably will succeed but expect the unexpected later on. So don't do it. It is quite a common practice to copy overlay layers to a different directory tree on the same or different underlying filesystem, and even -to a different machine. With the "inodes index" feature, trying to mount +to a different machine. With the "index" feature, trying to mount the copied layers will fail the verification of the lower root file handle. Nesting overlayfs mounts @@ -534,8 +543,9 @@ A lower dir with a regular whiteout will always be handled by the overlayfs mount, so to support storing an effective whiteout file in an overlayfs mount an alternative form of whiteout is supported. This form is a regular, zero-size file with the "overlay.whiteout" xattr set, inside a directory with the -"overlay.whiteouts" xattr set. Such whiteouts are never created by overlayfs, -but can be used by userspace tools (like containers) that generate lower layers. +"overlay.opaque" xattr set to "x" (see `whiteouts and opaque directories`_). +These alternative whiteouts are never created by overlayfs, but can be used by +userspace tools (like containers) that generate lower layers. These alternative whiteouts can be escaped using the standard xattr escape mechanism in order to properly nest to any depth. @@ -547,20 +557,21 @@ filesystem. This is the list of cases that overlayfs doesn't currently handle: -a) POSIX mandates updating st_atime for reads. This is currently not -done in the case when the file resides on a lower layer. + a) POSIX mandates updating st_atime for reads. This is currently not + done in the case when the file resides on a lower layer. -b) If a file residing on a lower layer is opened for read-only and then -memory mapped with MAP_SHARED, then subsequent changes to the file are not -reflected in the memory mapping. + b) If a file residing on a lower layer is opened for read-only and then + memory mapped with MAP_SHARED, then subsequent changes to the file are not + reflected in the memory mapping. -c) If a file residing on a lower layer is being executed, then opening that -file for write or truncating the file will not be denied with ETXTBSY. + c) If a file residing on a lower layer is being executed, then opening that + file for write or truncating the file will not be denied with ETXTBSY. The following options allow overlayfs to act more like a standards compliant filesystem: -1) "redirect_dir" +redirect_dir +```````````` Enabled with the mount option or module option: "redirect_dir=on" or with the kernel config option CONFIG_OVERLAY_FS_REDIRECT_DIR=y. @@ -568,7 +579,8 @@ the kernel config option CONFIG_OVERLAY_FS_REDIRECT_DIR=y. If this feature is disabled, then rename(2) on a lower or merged directory will fail with EXDEV ("Invalid cross-device link"). -2) "inode index" +index +````` Enabled with the mount option or module option "index=on" or with the kernel config option CONFIG_OVERLAY_FS_INDEX=y. @@ -577,7 +589,8 @@ If this feature is disabled and a file with multiple hard links is copied up, then this will "break" the link. Changes will not be propagated to other names referring to the same inode. -3) "xino" +xino +```` Enabled with the mount option "xino=auto" or "xino=on", with the module option "xino_auto=on" or with the kernel config option @@ -604,7 +617,7 @@ a crash or deadlock. Offline changes, when the overlay is not mounted, are allowed to the upper tree. Offline changes to the lower tree are only allowed if the -"metadata only copy up", "inode index", "xino" and "redirect_dir" features +"metacopy", "index", "xino" and "redirect_dir" features have not been used. If the lower tree is modified and any of these features has been used, the behavior of the overlay is undefined, though it will not result in a crash or deadlock. @@ -644,12 +657,13 @@ directory inode. When encoding a file handle from an overlay filesystem object, the following rules apply: -1. For a non-upper object, encode a lower file handle from lower inode -2. For an indexed object, encode a lower file handle from copy_up origin -3. For a pure-upper object and for an existing non-indexed upper object, - encode an upper file handle from upper inode + 1. For a non-upper object, encode a lower file handle from lower inode + 2. For an indexed object, encode a lower file handle from copy_up origin + 3. For a pure-upper object and for an existing non-indexed upper object, + encode an upper file handle from upper inode The encoded overlay file handle includes: + - Header including path type information (e.g. lower/upper) - UUID of the underlying filesystem - Underlying filesystem encoding of underlying inode @@ -659,15 +673,15 @@ are stored in extended attribute "trusted.overlay.origin". When decoding an overlay file handle, the following steps are followed: -1. Find underlying layer by UUID and path type information. -2. Decode the underlying filesystem file handle to underlying dentry. -3. For a lower file handle, lookup the handle in index directory by name. -4. If a whiteout is found in index, return ESTALE. This represents an - overlay object that was deleted after its file handle was encoded. -5. For a non-directory, instantiate a disconnected overlay dentry from the - decoded underlying dentry, the path type and index inode, if found. -6. For a directory, use the connected underlying decoded dentry, path type - and index, to lookup a connected overlay dentry. + 1. Find underlying layer by UUID and path type information. + 2. Decode the underlying filesystem file handle to underlying dentry. + 3. For a lower file handle, lookup the handle in index directory by name. + 4. If a whiteout is found in index, return ESTALE. This represents an + overlay object that was deleted after its file handle was encoded. + 5. For a non-directory, instantiate a disconnected overlay dentry from the + decoded underlying dentry, the path type and index inode, if found. + 6. For a directory, use the connected underlying decoded dentry, path type + and index, to lookup a connected overlay dentry. Decoding a non-directory file handle may return a disconnected dentry. copy_up of that disconnected dentry will create an upper index entry with @@ -770,9 +784,9 @@ Testsuite There's a testsuite originally developed by David Howells and currently maintained by Amir Goldstein at: - https://github.com/amir73il/unionmount-testsuite.git +https://github.com/amir73il/unionmount-testsuite.git -Run as root: +Run as root:: # cd unionmount-testsuite # ./run --ov --verify diff --git a/Documentation/filesystems/porting.rst b/Documentation/filesystems/porting.rst index 878e72b2f8b76a..1be76ef117b3f8 100644 --- a/Documentation/filesystems/porting.rst +++ b/Documentation/filesystems/porting.rst @@ -1061,3 +1061,76 @@ export_operations ->encode_fh() no longer has a default implementation to encode FILEID_INO32_GEN* file handles. Filesystems that used the default implementation may use the generic helper generic_encode_ino32_fh() explicitly. + +--- + +**mandatory** + +If ->rename() update of .. on cross-directory move needs an exclusion with +directory modifications, do *not* lock the subdirectory in question in your +->rename() - it's done by the caller now [that item should've been added in +28eceeda130f "fs: Lock moved directories"]. + +--- + +**mandatory** + +On same-directory ->rename() the (tautological) update of .. is not protected +by any locks; just don't do it if the old parent is the same as the new one. +We really can't lock two subdirectories in same-directory rename - not without +deadlocks. + +--- + +**mandatory** + +lock_rename() and lock_rename_child() may fail in cross-directory case, if +their arguments do not have a common ancestor. In that case ERR_PTR(-EXDEV) +is returned, with no locks taken. In-tree users updated; out-of-tree ones +would need to do so. + +--- + +**mandatory** + +The list of children anchored in parent dentry got turned into hlist now. +Field names got changed (->d_children/->d_sib instead of ->d_subdirs/->d_child +for anchor/entries resp.), so any affected places will be immediately caught +by compiler. + +--- + +**mandatory** + +->d_delete() instances are now called for dentries with ->d_lock held +and refcount equal to 0. They are not permitted to drop/regain ->d_lock. +None of in-tree instances did anything of that sort. Make sure yours do not... + +--- + +**mandatory** + +->d_prune() instances are now called without ->d_lock held on the parent. +->d_lock on dentry itself is still held; if you need per-parent exclusions (none +of the in-tree instances did), use your own spinlock. + +->d_iput() and ->d_release() are called with victim dentry still in the +list of parent's children. It is still unhashed, marked killed, etc., just not +removed from parent's ->d_children yet. + +Anyone iterating through the list of children needs to be aware of the +half-killed dentries that might be seen there; taking ->d_lock on those will +see them negative, unhashed and with negative refcount, which means that most +of the in-kernel users would've done the right thing anyway without any adjustment. + +--- + +**recommended** + +Block device freezing and thawing have been moved to holder operations. + +Before this change, get_active_super() would only be able to find the +superblock of the main block device, i.e., the one stored in sb->s_bdev. Block +device freezing now works for any block device owned by a given superblock, not +just the main block device. The get_active_super() helper and bd_fsfreeze_sb +pointer are gone. diff --git a/Documentation/filesystems/proc.rst b/Documentation/filesystems/proc.rst index 49ef12df631b7a..104c6d047d9b57 100644 --- a/Documentation/filesystems/proc.rst +++ b/Documentation/filesystems/proc.rst @@ -528,9 +528,9 @@ replaced by copy-on-write) part of the underlying shmem object out on swap. does not take into account swapped out page of underlying shmem objects. "Locked" indicates whether the mapping is locked in memory or not. -"THPeligible" indicates whether the mapping is eligible for allocating THP -pages as well as the THP is PMD mappable or not - 1 if true, 0 otherwise. -It just shows the current status. +"THPeligible" indicates whether the mapping is eligible for allocating +naturally aligned THP pages of any currently enabled size. 1 if true, 0 +otherwise. "VmFlags" field deserves a separate description. This member represents the kernel flags associated with the particular virtual memory area in two letter diff --git a/Documentation/filesystems/smb/ksmbd.rst b/Documentation/filesystems/smb/ksmbd.rst index 7bed96d794fc26..6b30e43a0d11f4 100644 --- a/Documentation/filesystems/smb/ksmbd.rst +++ b/Documentation/filesystems/smb/ksmbd.rst @@ -73,15 +73,14 @@ Auto Negotiation Supported. Compound Request Supported. Oplock Cache Mechanism Supported. SMB2 leases(v1 lease) Supported. -Directory leases(v2 lease) Planned for future. +Directory leases(v2 lease) Supported. Multi-credits Supported. NTLM/NTLMv2 Supported. HMAC-SHA256 Signing Supported. Secure negotiate Supported. Signing Update Supported. Pre-authentication integrity Supported. -SMB3 encryption(CCM, GCM) Supported. (CCM and GCM128 supported, GCM256 in - progress) +SMB3 encryption(CCM, GCM) Supported. (CCM/GCM128 and CCM/GCM256 supported) SMB direct(RDMA) Supported. SMB3 Multi-channel Partially Supported. Planned to implement replay/retry mechanisms for future. @@ -112,6 +111,10 @@ DCE/RPC support Partially Supported. a few calls(NetShareEnumAll, for Witness protocol e.g.) ksmbd/nfsd interoperability Planned for future. The features that ksmbd support are Leases, Notify, ACLs and Share modes. +SMB3.1.1 Compression Planned for future. +SMB3.1.1 over QUIC Planned for future. +Signing/Encryption over RDMA Planned for future. +SMB3.1.1 GMAC signing support Planned for future. ============================== ================================================= diff --git a/Documentation/filesystems/squashfs.rst b/Documentation/filesystems/squashfs.rst index df42106bae710e..4af8d6207509eb 100644 --- a/Documentation/filesystems/squashfs.rst +++ b/Documentation/filesystems/squashfs.rst @@ -64,6 +64,66 @@ obtained from this site also. The squashfs-tools development tree is now located on kernel.org git://git.kernel.org/pub/scm/fs/squashfs/squashfs-tools.git +2.1 Mount options +----------------- +=================== ========================================================= +errors=%s Specify whether squashfs errors trigger a kernel panic + or not + + ========== ============================================= + continue errors don't trigger a panic (default) + panic trigger a panic when errors are encountered, + similar to several other filesystems (e.g. + btrfs, ext4, f2fs, GFS2, jfs, ntfs, ubifs) + + This allows a kernel dump to be saved, + useful for analyzing and debugging the + corruption. + ========== ============================================= +threads=%s Select the decompression mode or the number of threads + + If SQUASHFS_CHOICE_DECOMP_BY_MOUNT is set: + + ========== ============================================= + single use single-threaded decompression (default) + + Only one block (data or metadata) can be + decompressed at any one time. This limits + CPU and memory usage to a minimum, but it + also gives poor performance on parallel I/O + workloads when using multiple CPU machines + due to waiting on decompressor availability. + multi use up to two parallel decompressors per core + + If you have a parallel I/O workload and your + system has enough memory, using this option + may improve overall I/O performance. It + dynamically allocates decompressors on a + demand basis. + percpu use a maximum of one decompressor per core + + It uses percpu variables to ensure + decompression is load-balanced across the + cores. + 1|2|3|... configure the number of threads used for + decompression + + The upper limit is num_online_cpus() * 2. + ========== ============================================= + + If SQUASHFS_CHOICE_DECOMP_BY_MOUNT is **not** set and + SQUASHFS_DECOMP_MULTI, SQUASHFS_MOUNT_DECOMP_THREADS are + both set: + + ========== ============================================= + 2|3|... configure the number of threads used for + decompression + + The upper limit is num_online_cpus() * 2. + ========== ============================================= + +=================== ========================================================= + 3. Squashfs Filesystem Design ----------------------------- diff --git a/Documentation/filesystems/vfs.rst b/Documentation/filesystems/vfs.rst index 99acc2e9867391..eebcc0f9e2bcd1 100644 --- a/Documentation/filesystems/vfs.rst +++ b/Documentation/filesystems/vfs.rst @@ -437,7 +437,7 @@ field. This is a pointer to a "struct inode_operations" which describes the methods that can be performed on individual inodes. -struct xattr_handlers +struct xattr_handler --------------------- On filesystems that support extended attributes (xattrs), the s_xattr @@ -823,7 +823,7 @@ cache in your filesystem. The following members are defined: bool (*is_partially_uptodate) (struct folio *, size_t from, size_t count); void (*is_dirty_writeback)(struct folio *, bool *, bool *); - int (*error_remove_page) (struct mapping *mapping, struct page *page); + int (*error_remove_folio)(struct mapping *mapping, struct folio *); int (*swap_activate)(struct swap_info_struct *sis, struct file *f, sector_t *span) int (*swap_deactivate)(struct file *); int (*swap_rw)(struct kiocb *iocb, struct iov_iter *iter); @@ -1034,8 +1034,8 @@ cache in your filesystem. The following members are defined: VM if a folio should be treated as dirty or writeback for the purposes of stalling. -``error_remove_page`` - normally set to generic_error_remove_page if truncation is ok +``error_remove_folio`` + normally set to generic_error_remove_folio if truncation is ok for this address space. Used for memory failure handling. Setting this implies you deal with pages going away under you, unless you have them locked or reference counts increased. diff --git a/Documentation/filesystems/xfs-delayed-logging-design.rst b/Documentation/filesystems/xfs-delayed-logging-design.rst deleted file mode 100644 index 6402ab8e370c81..00000000000000 --- a/Documentation/filesystems/xfs-delayed-logging-design.rst +++ /dev/null @@ -1,1087 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -================== -XFS Logging Design -================== - -Preamble -======== - -This document describes the design and algorithms that the XFS journalling -subsystem is based on. This document describes the design and algorithms that -the XFS journalling subsystem is based on so that readers may familiarize -themselves with the general concepts of how transaction processing in XFS works. - -We begin with an overview of transactions in XFS, followed by describing how -transaction reservations are structured and accounted, and then move into how we -guarantee forwards progress for long running transactions with finite initial -reservations bounds. At this point we need to explain how relogging works. With -the basic concepts covered, the design of the delayed logging mechanism is -documented. - - -Introduction -============ - -XFS uses Write Ahead Logging for ensuring changes to the filesystem metadata -are atomic and recoverable. For reasons of space and time efficiency, the -logging mechanisms are varied and complex, combining intents, logical and -physical logging mechanisms to provide the necessary recovery guarantees the -filesystem requires. - -Some objects, such as inodes and dquots, are logged in logical format where the -details logged are made up of the changes to in-core structures rather than -on-disk structures. Other objects - typically buffers - have their physical -changes logged. Long running atomic modifications have individual changes -chained together by intents, ensuring that journal recovery can restart and -finish an operation that was only partially done when the system stopped -functioning. - -The reason for these differences is to keep the amount of log space and CPU time -required to process objects being modified as small as possible and hence the -logging overhead as low as possible. Some items are very frequently modified, -and some parts of objects are more frequently modified than others, so keeping -the overhead of metadata logging low is of prime importance. - -The method used to log an item or chain modifications together isn't -particularly important in the scope of this document. It suffices to know that -the method used for logging a particular object or chaining modifications -together are different and are dependent on the object and/or modification being -performed. The logging subsystem only cares that certain specific rules are -followed to guarantee forwards progress and prevent deadlocks. - - -Transactions in XFS -=================== - -XFS has two types of high level transactions, defined by the type of log space -reservation they take. These are known as "one shot" and "permanent" -transactions. Permanent transaction reservations can take reservations that span -commit boundaries, whilst "one shot" transactions are for a single atomic -modification. - -The type and size of reservation must be matched to the modification taking -place. This means that permanent transactions can be used for one-shot -modifications, but one-shot reservations cannot be used for permanent -transactions. - -In the code, a one-shot transaction pattern looks somewhat like this:: - - tp = xfs_trans_alloc() - - - - xfs_trans_commit(tp); - -As items are modified in the transaction, the dirty regions in those items are -tracked via the transaction handle. Once the transaction is committed, all -resources joined to it are released, along with the remaining unused reservation -space that was taken at the transaction allocation time. - -In contrast, a permanent transaction is made up of multiple linked individual -transactions, and the pattern looks like this:: - - tp = xfs_trans_alloc() - xfs_ilock(ip, XFS_ILOCK_EXCL) - - loop { - xfs_trans_ijoin(tp, 0); - - xfs_trans_log_inode(tp, ip); - xfs_trans_roll(&tp); - } - - xfs_trans_commit(tp); - xfs_iunlock(ip, XFS_ILOCK_EXCL); - -While this might look similar to a one-shot transaction, there is an important -difference: xfs_trans_roll() performs a specific operation that links two -transactions together:: - - ntp = xfs_trans_dup(tp); - xfs_trans_commit(tp); - xfs_trans_reserve(ntp); - -This results in a series of "rolling transactions" where the inode is locked -across the entire chain of transactions. Hence while this series of rolling -transactions is running, nothing else can read from or write to the inode and -this provides a mechanism for complex changes to appear atomic from an external -observer's point of view. - -It is important to note that a series of rolling transactions in a permanent -transaction does not form an atomic change in the journal. While each -individual modification is atomic, the chain is *not atomic*. If we crash half -way through, then recovery will only replay up to the last transactional -modification the loop made that was committed to the journal. - -This affects long running permanent transactions in that it is not possible to -predict how much of a long running operation will actually be recovered because -there is no guarantee of how much of the operation reached stale storage. Hence -if a long running operation requires multiple transactions to fully complete, -the high level operation must use intents and deferred operations to guarantee -recovery can complete the operation once the first transactions is persisted in -the on-disk journal. - - -Transactions are Asynchronous -============================= - -In XFS, all high level transactions are asynchronous by default. This means that -xfs_trans_commit() does not guarantee that the modification has been committed -to stable storage when it returns. Hence when a system crashes, not all the -completed transactions will be replayed during recovery. - -However, the logging subsystem does provide global ordering guarantees, such -that if a specific change is seen after recovery, all metadata modifications -that were committed prior to that change will also be seen. - -For single shot operations that need to reach stable storage immediately, or -ensuring that a long running permanent transaction is fully committed once it is -complete, we can explicitly tag a transaction as synchronous. This will trigger -a "log force" to flush the outstanding committed transactions to stable storage -in the journal and wait for that to complete. - -Synchronous transactions are rarely used, however, because they limit logging -throughput to the IO latency limitations of the underlying storage. Instead, we -tend to use log forces to ensure modifications are on stable storage only when -a user operation requires a synchronisation point to occur (e.g. fsync). - - -Transaction Reservations -======================== - -It has been mentioned a number of times now that the logging subsystem needs to -provide a forwards progress guarantee so that no modification ever stalls -because it can't be written to the journal due to a lack of space in the -journal. This is achieved by the transaction reservations that are made when -a transaction is first allocated. For permanent transactions, these reservations -are maintained as part of the transaction rolling mechanism. - -A transaction reservation provides a guarantee that there is physical log space -available to write the modification into the journal before we start making -modifications to objects and items. As such, the reservation needs to be large -enough to take into account the amount of metadata that the change might need to -log in the worst case. This means that if we are modifying a btree in the -transaction, we have to reserve enough space to record a full leaf-to-root split -of the btree. As such, the reservations are quite complex because we have to -take into account all the hidden changes that might occur. - -For example, a user data extent allocation involves allocating an extent from -free space, which modifies the free space trees. That's two btrees. Inserting -the extent into the inode's extent map might require a split of the extent map -btree, which requires another allocation that can modify the free space trees -again. Then we might have to update reverse mappings, which modifies yet -another btree which might require more space. And so on. Hence the amount of -metadata that a "simple" operation can modify can be quite large. - -This "worst case" calculation provides us with the static "unit reservation" -for the transaction that is calculated at mount time. We must guarantee that the -log has this much space available before the transaction is allowed to proceed -so that when we come to write the dirty metadata into the log we don't run out -of log space half way through the write. - -For one-shot transactions, a single unit space reservation is all that is -required for the transaction to proceed. For permanent transactions, however, we -also have a "log count" that affects the size of the reservation that is to be -made. - -While a permanent transaction can get by with a single unit of space -reservation, it is somewhat inefficient to do this as it requires the -transaction rolling mechanism to re-reserve space on every transaction roll. We -know from the implementation of the permanent transactions how many transaction -rolls are likely for the common modifications that need to be made. - -For example, an inode allocation is typically two transactions - one to -physically allocate a free inode chunk on disk, and another to allocate an inode -from an inode chunk that has free inodes in it. Hence for an inode allocation -transaction, we might set the reservation log count to a value of 2 to indicate -that the common/fast path transaction will commit two linked transactions in a -chain. Each time a permanent transaction rolls, it consumes an entire unit -reservation. - -Hence when the permanent transaction is first allocated, the log space -reservation is increased from a single unit reservation to multiple unit -reservations. That multiple is defined by the reservation log count, and this -means we can roll the transaction multiple times before we have to re-reserve -log space when we roll the transaction. This ensures that the common -modifications we make only need to reserve log space once. - -If the log count for a permanent transaction reaches zero, then it needs to -re-reserve physical space in the log. This is somewhat complex, and requires -an understanding of how the log accounts for space that has been reserved. - - -Log Space Accounting -==================== - -The position in the log is typically referred to as a Log Sequence Number (LSN). -The log is circular, so the positions in the log are defined by the combination -of a cycle number - the number of times the log has been overwritten - and the -offset into the log. A LSN carries the cycle in the upper 32 bits and the -offset in the lower 32 bits. The offset is in units of "basic blocks" (512 -bytes). Hence we can do realtively simple LSN based math to keep track of -available space in the log. - -Log space accounting is done via a pair of constructs called "grant heads". The -position of the grant heads is an absolute value, so the amount of space -available in the log is defined by the distance between the position of the -grant head and the current log tail. That is, how much space can be -reserved/consumed before the grant heads would fully wrap the log and overtake -the tail position. - -The first grant head is the "reserve" head. This tracks the byte count of the -reservations currently held by active transactions. It is a purely in-memory -accounting of the space reservation and, as such, actually tracks byte offsets -into the log rather than basic blocks. Hence it technically isn't using LSNs to -represent the log position, but it is still treated like a split {cycle,offset} -tuple for the purposes of tracking reservation space. - -The reserve grant head is used to accurately account for exact transaction -reservations amounts and the exact byte count that modifications actually make -and need to write into the log. The reserve head is used to prevent new -transactions from taking new reservations when the head reaches the current -tail. It will block new reservations in a FIFO queue and as the log tail moves -forward it will wake them in order once sufficient space is available. This FIFO -mechanism ensures no transaction is starved of resources when log space -shortages occur. - -The other grant head is the "write" head. Unlike the reserve head, this grant -head contains an LSN and it tracks the physical space usage in the log. While -this might sound like it is accounting the same state as the reserve grant head -- and it mostly does track exactly the same location as the reserve grant head - -there are critical differences in behaviour between them that provides the -forwards progress guarantees that rolling permanent transactions require. - -These differences when a permanent transaction is rolled and the internal "log -count" reaches zero and the initial set of unit reservations have been -exhausted. At this point, we still require a log space reservation to continue -the next transaction in the sequeunce, but we have none remaining. We cannot -sleep during the transaction commit process waiting for new log space to become -available, as we may end up on the end of the FIFO queue and the items we have -locked while we sleep could end up pinning the tail of the log before there is -enough free space in the log to fulfill all of the pending reservations and -then wake up transaction commit in progress. - -To take a new reservation without sleeping requires us to be able to take a -reservation even if there is no reservation space currently available. That is, -we need to be able to *overcommit* the log reservation space. As has already -been detailed, we cannot overcommit physical log space. However, the reserve -grant head does not track physical space - it only accounts for the amount of -reservations we currently have outstanding. Hence if the reserve head passes -over the tail of the log all it means is that new reservations will be throttled -immediately and remain throttled until the log tail is moved forward far enough -to remove the overcommit and start taking new reservations. In other words, we -can overcommit the reserve head without violating the physical log head and tail -rules. - -As a result, permanent transactions only "regrant" reservation space during -xfs_trans_commit() calls, while the physical log space reservation - tracked by -the write head - is then reserved separately by a call to xfs_log_reserve() -after the commit completes. Once the commit completes, we can sleep waiting for -physical log space to be reserved from the write grant head, but only if one -critical rule has been observed:: - - Code using permanent reservations must always log the items they hold - locked across each transaction they roll in the chain. - -"Re-logging" the locked items on every transaction roll ensures that the items -attached to the transaction chain being rolled are always relocated to the -physical head of the log and so do not pin the tail of the log. If a locked item -pins the tail of the log when we sleep on the write reservation, then we will -deadlock the log as we cannot take the locks needed to write back that item and -move the tail of the log forwards to free up write grant space. Re-logging the -locked items avoids this deadlock and guarantees that the log reservation we are -making cannot self-deadlock. - -If all rolling transactions obey this rule, then they can all make forwards -progress independently because nothing will block the progress of the log -tail moving forwards and hence ensuring that write grant space is always -(eventually) made available to permanent transactions no matter how many times -they roll. - - -Re-logging Explained -==================== - -XFS allows multiple separate modifications to a single object to be carried in -the log at any given time. This allows the log to avoid needing to flush each -change to disk before recording a new change to the object. XFS does this via a -method called "re-logging". Conceptually, this is quite simple - all it requires -is that any new change to the object is recorded with a *new copy* of all the -existing changes in the new transaction that is written to the log. - -That is, if we have a sequence of changes A through to F, and the object was -written to disk after change D, we would see in the log the following series -of transactions, their contents and the log sequence number (LSN) of the -transaction:: - - Transaction Contents LSN - A A X - B A+B X+n - C A+B+C X+n+m - D A+B+C+D X+n+m+o - - E E Y (> X+n+m+o) - F E+F Y+p - -In other words, each time an object is relogged, the new transaction contains -the aggregation of all the previous changes currently held only in the log. - -This relogging technique allows objects to be moved forward in the log so that -an object being relogged does not prevent the tail of the log from ever moving -forward. This can be seen in the table above by the changing (increasing) LSN -of each subsequent transaction, and it's the technique that allows us to -implement long-running, multiple-commit permanent transactions. - -A typical example of a rolling transaction is the removal of extents from an -inode which can only be done at a rate of two extents per transaction because -of reservation size limitations. Hence a rolling extent removal transaction -keeps relogging the inode and btree buffers as they get modified in each -removal operation. This keeps them moving forward in the log as the operation -progresses, ensuring that current operation never gets blocked by itself if the -log wraps around. - -Hence it can be seen that the relogging operation is fundamental to the correct -working of the XFS journalling subsystem. From the above description, most -people should be able to see why the XFS metadata operations writes so much to -the log - repeated operations to the same objects write the same changes to -the log over and over again. Worse is the fact that objects tend to get -dirtier as they get relogged, so each subsequent transaction is writing more -metadata into the log. - -It should now also be obvious how relogging and asynchronous transactions go -hand in hand. That is, transactions don't get written to the physical journal -until either a log buffer is filled (a log buffer can hold multiple -transactions) or a synchronous operation forces the log buffers holding the -transactions to disk. This means that XFS is doing aggregation of transactions -in memory - batching them, if you like - to minimise the impact of the log IO on -transaction throughput. - -The limitation on asynchronous transaction throughput is the number and size of -log buffers made available by the log manager. By default there are 8 log -buffers available and the size of each is 32kB - the size can be increased up -to 256kB by use of a mount option. - -Effectively, this gives us the maximum bound of outstanding metadata changes -that can be made to the filesystem at any point in time - if all the log -buffers are full and under IO, then no more transactions can be committed until -the current batch completes. It is now common for a single current CPU core to -be to able to issue enough transactions to keep the log buffers full and under -IO permanently. Hence the XFS journalling subsystem can be considered to be IO -bound. - -Delayed Logging: Concepts -========================= - -The key thing to note about the asynchronous logging combined with the -relogging technique XFS uses is that we can be relogging changed objects -multiple times before they are committed to disk in the log buffers. If we -return to the previous relogging example, it is entirely possible that -transactions A through D are committed to disk in the same log buffer. - -That is, a single log buffer may contain multiple copies of the same object, -but only one of those copies needs to be there - the last one "D", as it -contains all the changes from the previous changes. In other words, we have one -necessary copy in the log buffer, and three stale copies that are simply -wasting space. When we are doing repeated operations on the same set of -objects, these "stale objects" can be over 90% of the space used in the log -buffers. It is clear that reducing the number of stale objects written to the -log would greatly reduce the amount of metadata we write to the log, and this -is the fundamental goal of delayed logging. - -From a conceptual point of view, XFS is already doing relogging in memory (where -memory == log buffer), only it is doing it extremely inefficiently. It is using -logical to physical formatting to do the relogging because there is no -infrastructure to keep track of logical changes in memory prior to physically -formatting the changes in a transaction to the log buffer. Hence we cannot avoid -accumulating stale objects in the log buffers. - -Delayed logging is the name we've given to keeping and tracking transactional -changes to objects in memory outside the log buffer infrastructure. Because of -the relogging concept fundamental to the XFS journalling subsystem, this is -actually relatively easy to do - all the changes to logged items are already -tracked in the current infrastructure. The big problem is how to accumulate -them and get them to the log in a consistent, recoverable manner. -Describing the problems and how they have been solved is the focus of this -document. - -One of the key changes that delayed logging makes to the operation of the -journalling subsystem is that it disassociates the amount of outstanding -metadata changes from the size and number of log buffers available. In other -words, instead of there only being a maximum of 2MB of transaction changes not -written to the log at any point in time, there may be a much greater amount -being accumulated in memory. Hence the potential for loss of metadata on a -crash is much greater than for the existing logging mechanism. - -It should be noted that this does not change the guarantee that log recovery -will result in a consistent filesystem. What it does mean is that as far as the -recovered filesystem is concerned, there may be many thousands of transactions -that simply did not occur as a result of the crash. This makes it even more -important that applications that care about their data use fsync() where they -need to ensure application level data integrity is maintained. - -It should be noted that delayed logging is not an innovative new concept that -warrants rigorous proofs to determine whether it is correct or not. The method -of accumulating changes in memory for some period before writing them to the -log is used effectively in many filesystems including ext3 and ext4. Hence -no time is spent in this document trying to convince the reader that the -concept is sound. Instead it is simply considered a "solved problem" and as -such implementing it in XFS is purely an exercise in software engineering. - -The fundamental requirements for delayed logging in XFS are simple: - - 1. Reduce the amount of metadata written to the log by at least - an order of magnitude. - 2. Supply sufficient statistics to validate Requirement #1. - 3. Supply sufficient new tracing infrastructure to be able to debug - problems with the new code. - 4. No on-disk format change (metadata or log format). - 5. Enable and disable with a mount option. - 6. No performance regressions for synchronous transaction workloads. - -Delayed Logging: Design -======================= - -Storing Changes ---------------- - -The problem with accumulating changes at a logical level (i.e. just using the -existing log item dirty region tracking) is that when it comes to writing the -changes to the log buffers, we need to ensure that the object we are formatting -is not changing while we do this. This requires locking the object to prevent -concurrent modification. Hence flushing the logical changes to the log would -require us to lock every object, format them, and then unlock them again. - -This introduces lots of scope for deadlocks with transactions that are already -running. For example, a transaction has object A locked and modified, but needs -the delayed logging tracking lock to commit the transaction. However, the -flushing thread has the delayed logging tracking lock already held, and is -trying to get the lock on object A to flush it to the log buffer. This appears -to be an unsolvable deadlock condition, and it was solving this problem that -was the barrier to implementing delayed logging for so long. - -The solution is relatively simple - it just took a long time to recognise it. -Put simply, the current logging code formats the changes to each item into an -vector array that points to the changed regions in the item. The log write code -simply copies the memory these vectors point to into the log buffer during -transaction commit while the item is locked in the transaction. Instead of -using the log buffer as the destination of the formatting code, we can use an -allocated memory buffer big enough to fit the formatted vector. - -If we then copy the vector into the memory buffer and rewrite the vector to -point to the memory buffer rather than the object itself, we now have a copy of -the changes in a format that is compatible with the log buffer writing code. -that does not require us to lock the item to access. This formatting and -rewriting can all be done while the object is locked during transaction commit, -resulting in a vector that is transactionally consistent and can be accessed -without needing to lock the owning item. - -Hence we avoid the need to lock items when we need to flush outstanding -asynchronous transactions to the log. The differences between the existing -formatting method and the delayed logging formatting can be seen in the -diagram below. - -Current format log vector:: - - Object +---------------------------------------------+ - Vector 1 +----+ - Vector 2 +----+ - Vector 3 +----------+ - -After formatting:: - - Log Buffer +-V1-+-V2-+----V3----+ - -Delayed logging vector:: - - Object +---------------------------------------------+ - Vector 1 +----+ - Vector 2 +----+ - Vector 3 +----------+ - -After formatting:: - - Memory Buffer +-V1-+-V2-+----V3----+ - Vector 1 +----+ - Vector 2 +----+ - Vector 3 +----------+ - -The memory buffer and associated vector need to be passed as a single object, -but still need to be associated with the parent object so if the object is -relogged we can replace the current memory buffer with a new memory buffer that -contains the latest changes. - -The reason for keeping the vector around after we've formatted the memory -buffer is to support splitting vectors across log buffer boundaries correctly. -If we don't keep the vector around, we do not know where the region boundaries -are in the item, so we'd need a new encapsulation method for regions in the log -buffer writing (i.e. double encapsulation). This would be an on-disk format -change and as such is not desirable. It also means we'd have to write the log -region headers in the formatting stage, which is problematic as there is per -region state that needs to be placed into the headers during the log write. - -Hence we need to keep the vector, but by attaching the memory buffer to it and -rewriting the vector addresses to point at the memory buffer we end up with a -self-describing object that can be passed to the log buffer write code to be -handled in exactly the same manner as the existing log vectors are handled. -Hence we avoid needing a new on-disk format to handle items that have been -relogged in memory. - - -Tracking Changes ----------------- - -Now that we can record transactional changes in memory in a form that allows -them to be used without limitations, we need to be able to track and accumulate -them so that they can be written to the log at some later point in time. The -log item is the natural place to store this vector and buffer, and also makes sense -to be the object that is used to track committed objects as it will always -exist once the object has been included in a transaction. - -The log item is already used to track the log items that have been written to -the log but not yet written to disk. Such log items are considered "active" -and as such are stored in the Active Item List (AIL) which is a LSN-ordered -double linked list. Items are inserted into this list during log buffer IO -completion, after which they are unpinned and can be written to disk. An object -that is in the AIL can be relogged, which causes the object to be pinned again -and then moved forward in the AIL when the log buffer IO completes for that -transaction. - -Essentially, this shows that an item that is in the AIL can still be modified -and relogged, so any tracking must be separate to the AIL infrastructure. As -such, we cannot reuse the AIL list pointers for tracking committed items, nor -can we store state in any field that is protected by the AIL lock. Hence the -committed item tracking needs its own locks, lists and state fields in the log -item. - -Similar to the AIL, tracking of committed items is done through a new list -called the Committed Item List (CIL). The list tracks log items that have been -committed and have formatted memory buffers attached to them. It tracks objects -in transaction commit order, so when an object is relogged it is removed from -its place in the list and re-inserted at the tail. This is entirely arbitrary -and done to make it easy for debugging - the last items in the list are the -ones that are most recently modified. Ordering of the CIL is not necessary for -transactional integrity (as discussed in the next section) so the ordering is -done for convenience/sanity of the developers. - - -Delayed Logging: Checkpoints ----------------------------- - -When we have a log synchronisation event, commonly known as a "log force", -all the items in the CIL must be written into the log via the log buffers. -We need to write these items in the order that they exist in the CIL, and they -need to be written as an atomic transaction. The need for all the objects to be -written as an atomic transaction comes from the requirements of relogging and -log replay - all the changes in all the objects in a given transaction must -either be completely replayed during log recovery, or not replayed at all. If -a transaction is not replayed because it is not complete in the log, then -no later transactions should be replayed, either. - -To fulfill this requirement, we need to write the entire CIL in a single log -transaction. Fortunately, the XFS log code has no fixed limit on the size of a -transaction, nor does the log replay code. The only fundamental limit is that -the transaction cannot be larger than just under half the size of the log. The -reason for this limit is that to find the head and tail of the log, there must -be at least one complete transaction in the log at any given time. If a -transaction is larger than half the log, then there is the possibility that a -crash during the write of a such a transaction could partially overwrite the -only complete previous transaction in the log. This will result in a recovery -failure and an inconsistent filesystem and hence we must enforce the maximum -size of a checkpoint to be slightly less than a half the log. - -Apart from this size requirement, a checkpoint transaction looks no different -to any other transaction - it contains a transaction header, a series of -formatted log items and a commit record at the tail. From a recovery -perspective, the checkpoint transaction is also no different - just a lot -bigger with a lot more items in it. The worst case effect of this is that we -might need to tune the recovery transaction object hash size. - -Because the checkpoint is just another transaction and all the changes to log -items are stored as log vectors, we can use the existing log buffer writing -code to write the changes into the log. To do this efficiently, we need to -minimise the time we hold the CIL locked while writing the checkpoint -transaction. The current log write code enables us to do this easily with the -way it separates the writing of the transaction contents (the log vectors) from -the transaction commit record, but tracking this requires us to have a -per-checkpoint context that travels through the log write process through to -checkpoint completion. - -Hence a checkpoint has a context that tracks the state of the current -checkpoint from initiation to checkpoint completion. A new context is initiated -at the same time a checkpoint transaction is started. That is, when we remove -all the current items from the CIL during a checkpoint operation, we move all -those changes into the current checkpoint context. We then initialise a new -context and attach that to the CIL for aggregation of new transactions. - -This allows us to unlock the CIL immediately after transfer of all the -committed items and effectively allows new transactions to be issued while we -are formatting the checkpoint into the log. It also allows concurrent -checkpoints to be written into the log buffers in the case of log force heavy -workloads, just like the existing transaction commit code does. This, however, -requires that we strictly order the commit records in the log so that -checkpoint sequence order is maintained during log replay. - -To ensure that we can be writing an item into a checkpoint transaction at -the same time another transaction modifies the item and inserts the log item -into the new CIL, then checkpoint transaction commit code cannot use log items -to store the list of log vectors that need to be written into the transaction. -Hence log vectors need to be able to be chained together to allow them to be -detached from the log items. That is, when the CIL is flushed the memory -buffer and log vector attached to each log item needs to be attached to the -checkpoint context so that the log item can be released. In diagrammatic form, -the CIL would look like this before the flush:: - - CIL Head - | - V - Log Item <-> log vector 1 -> memory buffer - | -> vector array - V - Log Item <-> log vector 2 -> memory buffer - | -> vector array - V - ...... - | - V - Log Item <-> log vector N-1 -> memory buffer - | -> vector array - V - Log Item <-> log vector N -> memory buffer - -> vector array - -And after the flush the CIL head is empty, and the checkpoint context log -vector list would look like:: - - Checkpoint Context - | - V - log vector 1 -> memory buffer - | -> vector array - | -> Log Item - V - log vector 2 -> memory buffer - | -> vector array - | -> Log Item - V - ...... - | - V - log vector N-1 -> memory buffer - | -> vector array - | -> Log Item - V - log vector N -> memory buffer - -> vector array - -> Log Item - -Once this transfer is done, the CIL can be unlocked and new transactions can -start, while the checkpoint flush code works over the log vector chain to -commit the checkpoint. - -Once the checkpoint is written into the log buffers, the checkpoint context is -attached to the log buffer that the commit record was written to along with a -completion callback. Log IO completion will call that callback, which can then -run transaction committed processing for the log items (i.e. insert into AIL -and unpin) in the log vector chain and then free the log vector chain and -checkpoint context. - -Discussion Point: I am uncertain as to whether the log item is the most -efficient way to track vectors, even though it seems like the natural way to do -it. The fact that we walk the log items (in the CIL) just to chain the log -vectors and break the link between the log item and the log vector means that -we take a cache line hit for the log item list modification, then another for -the log vector chaining. If we track by the log vectors, then we only need to -break the link between the log item and the log vector, which means we should -dirty only the log item cachelines. Normally I wouldn't be concerned about one -vs two dirty cachelines except for the fact I've seen upwards of 80,000 log -vectors in one checkpoint transaction. I'd guess this is a "measure and -compare" situation that can be done after a working and reviewed implementation -is in the dev tree.... - -Delayed Logging: Checkpoint Sequencing --------------------------------------- - -One of the key aspects of the XFS transaction subsystem is that it tags -committed transactions with the log sequence number of the transaction commit. -This allows transactions to be issued asynchronously even though there may be -future operations that cannot be completed until that transaction is fully -committed to the log. In the rare case that a dependent operation occurs (e.g. -re-using a freed metadata extent for a data extent), a special, optimised log -force can be issued to force the dependent transaction to disk immediately. - -To do this, transactions need to record the LSN of the commit record of the -transaction. This LSN comes directly from the log buffer the transaction is -written into. While this works just fine for the existing transaction -mechanism, it does not work for delayed logging because transactions are not -written directly into the log buffers. Hence some other method of sequencing -transactions is required. - -As discussed in the checkpoint section, delayed logging uses per-checkpoint -contexts, and as such it is simple to assign a sequence number to each -checkpoint. Because the switching of checkpoint contexts must be done -atomically, it is simple to ensure that each new context has a monotonically -increasing sequence number assigned to it without the need for an external -atomic counter - we can just take the current context sequence number and add -one to it for the new context. - -Then, instead of assigning a log buffer LSN to the transaction commit LSN -during the commit, we can assign the current checkpoint sequence. This allows -operations that track transactions that have not yet completed know what -checkpoint sequence needs to be committed before they can continue. As a -result, the code that forces the log to a specific LSN now needs to ensure that -the log forces to a specific checkpoint. - -To ensure that we can do this, we need to track all the checkpoint contexts -that are currently committing to the log. When we flush a checkpoint, the -context gets added to a "committing" list which can be searched. When a -checkpoint commit completes, it is removed from the committing list. Because -the checkpoint context records the LSN of the commit record for the checkpoint, -we can also wait on the log buffer that contains the commit record, thereby -using the existing log force mechanisms to execute synchronous forces. - -It should be noted that the synchronous forces may need to be extended with -mitigation algorithms similar to the current log buffer code to allow -aggregation of multiple synchronous transactions if there are already -synchronous transactions being flushed. Investigation of the performance of the -current design is needed before making any decisions here. - -The main concern with log forces is to ensure that all the previous checkpoints -are also committed to disk before the one we need to wait for. Therefore we -need to check that all the prior contexts in the committing list are also -complete before waiting on the one we need to complete. We do this -synchronisation in the log force code so that we don't need to wait anywhere -else for such serialisation - it only matters when we do a log force. - -The only remaining complexity is that a log force now also has to handle the -case where the forcing sequence number is the same as the current context. That -is, we need to flush the CIL and potentially wait for it to complete. This is a -simple addition to the existing log forcing code to check the sequence numbers -and push if required. Indeed, placing the current sequence checkpoint flush in -the log force code enables the current mechanism for issuing synchronous -transactions to remain untouched (i.e. commit an asynchronous transaction, then -force the log at the LSN of that transaction) and so the higher level code -behaves the same regardless of whether delayed logging is being used or not. - -Delayed Logging: Checkpoint Log Space Accounting ------------------------------------------------- - -The big issue for a checkpoint transaction is the log space reservation for the -transaction. We don't know how big a checkpoint transaction is going to be -ahead of time, nor how many log buffers it will take to write out, nor the -number of split log vector regions are going to be used. We can track the -amount of log space required as we add items to the commit item list, but we -still need to reserve the space in the log for the checkpoint. - -A typical transaction reserves enough space in the log for the worst case space -usage of the transaction. The reservation accounts for log record headers, -transaction and region headers, headers for split regions, buffer tail padding, -etc. as well as the actual space for all the changed metadata in the -transaction. While some of this is fixed overhead, much of it is dependent on -the size of the transaction and the number of regions being logged (the number -of log vectors in the transaction). - -An example of the differences would be logging directory changes versus logging -inode changes. If you modify lots of inode cores (e.g. ``chmod -R g+w *``), then -there are lots of transactions that only contain an inode core and an inode log -format structure. That is, two vectors totaling roughly 150 bytes. If we modify -10,000 inodes, we have about 1.5MB of metadata to write in 20,000 vectors. Each -vector is 12 bytes, so the total to be logged is approximately 1.75MB. In -comparison, if we are logging full directory buffers, they are typically 4KB -each, so we in 1.5MB of directory buffers we'd have roughly 400 buffers and a -buffer format structure for each buffer - roughly 800 vectors or 1.51MB total -space. From this, it should be obvious that a static log space reservation is -not particularly flexible and is difficult to select the "optimal value" for -all workloads. - -Further, if we are going to use a static reservation, which bit of the entire -reservation does it cover? We account for space used by the transaction -reservation by tracking the space currently used by the object in the CIL and -then calculating the increase or decrease in space used as the object is -relogged. This allows for a checkpoint reservation to only have to account for -log buffer metadata used such as log header records. - -However, even using a static reservation for just the log metadata is -problematic. Typically log record headers use at least 16KB of log space per -1MB of log space consumed (512 bytes per 32k) and the reservation needs to be -large enough to handle arbitrary sized checkpoint transactions. This -reservation needs to be made before the checkpoint is started, and we need to -be able to reserve the space without sleeping. For a 8MB checkpoint, we need a -reservation of around 150KB, which is a non-trivial amount of space. - -A static reservation needs to manipulate the log grant counters - we can take a -permanent reservation on the space, but we still need to make sure we refresh -the write reservation (the actual space available to the transaction) after -every checkpoint transaction completion. Unfortunately, if this space is not -available when required, then the regrant code will sleep waiting for it. - -The problem with this is that it can lead to deadlocks as we may need to commit -checkpoints to be able to free up log space (refer back to the description of -rolling transactions for an example of this). Hence we *must* always have -space available in the log if we are to use static reservations, and that is -very difficult and complex to arrange. It is possible to do, but there is a -simpler way. - -The simpler way of doing this is tracking the entire log space used by the -items in the CIL and using this to dynamically calculate the amount of log -space required by the log metadata. If this log metadata space changes as a -result of a transaction commit inserting a new memory buffer into the CIL, then -the difference in space required is removed from the transaction that causes -the change. Transactions at this level will *always* have enough space -available in their reservation for this as they have already reserved the -maximal amount of log metadata space they require, and such a delta reservation -will always be less than or equal to the maximal amount in the reservation. - -Hence we can grow the checkpoint transaction reservation dynamically as items -are added to the CIL and avoid the need for reserving and regranting log space -up front. This avoids deadlocks and removes a blocking point from the -checkpoint flush code. - -As mentioned early, transactions can't grow to more than half the size of the -log. Hence as part of the reservation growing, we need to also check the size -of the reservation against the maximum allowed transaction size. If we reach -the maximum threshold, we need to push the CIL to the log. This is effectively -a "background flush" and is done on demand. This is identical to -a CIL push triggered by a log force, only that there is no waiting for the -checkpoint commit to complete. This background push is checked and executed by -transaction commit code. - -If the transaction subsystem goes idle while we still have items in the CIL, -they will be flushed by the periodic log force issued by the xfssyncd. This log -force will push the CIL to disk, and if the transaction subsystem stays idle, -allow the idle log to be covered (effectively marked clean) in exactly the same -manner that is done for the existing logging method. A discussion point is -whether this log force needs to be done more frequently than the current rate -which is once every 30s. - - -Delayed Logging: Log Item Pinning ---------------------------------- - -Currently log items are pinned during transaction commit while the items are -still locked. This happens just after the items are formatted, though it could -be done any time before the items are unlocked. The result of this mechanism is -that items get pinned once for every transaction that is committed to the log -buffers. Hence items that are relogged in the log buffers will have a pin count -for every outstanding transaction they were dirtied in. When each of these -transactions is completed, they will unpin the item once. As a result, the item -only becomes unpinned when all the transactions complete and there are no -pending transactions. Thus the pinning and unpinning of a log item is symmetric -as there is a 1:1 relationship with transaction commit and log item completion. - -For delayed logging, however, we have an asymmetric transaction commit to -completion relationship. Every time an object is relogged in the CIL it goes -through the commit process without a corresponding completion being registered. -That is, we now have a many-to-one relationship between transaction commit and -log item completion. The result of this is that pinning and unpinning of the -log items becomes unbalanced if we retain the "pin on transaction commit, unpin -on transaction completion" model. - -To keep pin/unpin symmetry, the algorithm needs to change to a "pin on -insertion into the CIL, unpin on checkpoint completion". In other words, the -pinning and unpinning becomes symmetric around a checkpoint context. We have to -pin the object the first time it is inserted into the CIL - if it is already in -the CIL during a transaction commit, then we do not pin it again. Because there -can be multiple outstanding checkpoint contexts, we can still see elevated pin -counts, but as each checkpoint completes the pin count will retain the correct -value according to its context. - -Just to make matters slightly more complex, this checkpoint level context -for the pin count means that the pinning of an item must take place under the -CIL commit/flush lock. If we pin the object outside this lock, we cannot -guarantee which context the pin count is associated with. This is because of -the fact pinning the item is dependent on whether the item is present in the -current CIL or not. If we don't pin the CIL first before we check and pin the -object, we have a race with CIL being flushed between the check and the pin -(or not pinning, as the case may be). Hence we must hold the CIL flush/commit -lock to guarantee that we pin the items correctly. - -Delayed Logging: Concurrent Scalability ---------------------------------------- - -A fundamental requirement for the CIL is that accesses through transaction -commits must scale to many concurrent commits. The current transaction commit -code does not break down even when there are transactions coming from 2048 -processors at once. The current transaction code does not go any faster than if -there was only one CPU using it, but it does not slow down either. - -As a result, the delayed logging transaction commit code needs to be designed -for concurrency from the ground up. It is obvious that there are serialisation -points in the design - the three important ones are: - - 1. Locking out new transaction commits while flushing the CIL - 2. Adding items to the CIL and updating item space accounting - 3. Checkpoint commit ordering - -Looking at the transaction commit and CIL flushing interactions, it is clear -that we have a many-to-one interaction here. That is, the only restriction on -the number of concurrent transactions that can be trying to commit at once is -the amount of space available in the log for their reservations. The practical -limit here is in the order of several hundred concurrent transactions for a -128MB log, which means that it is generally one per CPU in a machine. - -The amount of time a transaction commit needs to hold out a flush is a -relatively long period of time - the pinning of log items needs to be done -while we are holding out a CIL flush, so at the moment that means it is held -across the formatting of the objects into memory buffers (i.e. while memcpy()s -are in progress). Ultimately a two pass algorithm where the formatting is done -separately to the pinning of objects could be used to reduce the hold time of -the transaction commit side. - -Because of the number of potential transaction commit side holders, the lock -really needs to be a sleeping lock - if the CIL flush takes the lock, we do not -want every other CPU in the machine spinning on the CIL lock. Given that -flushing the CIL could involve walking a list of tens of thousands of log -items, it will get held for a significant time and so spin contention is a -significant concern. Preventing lots of CPUs spinning doing nothing is the -main reason for choosing a sleeping lock even though nothing in either the -transaction commit or CIL flush side sleeps with the lock held. - -It should also be noted that CIL flushing is also a relatively rare operation -compared to transaction commit for asynchronous transaction workloads - only -time will tell if using a read-write semaphore for exclusion will limit -transaction commit concurrency due to cache line bouncing of the lock on the -read side. - -The second serialisation point is on the transaction commit side where items -are inserted into the CIL. Because transactions can enter this code -concurrently, the CIL needs to be protected separately from the above -commit/flush exclusion. It also needs to be an exclusive lock but it is only -held for a very short time and so a spin lock is appropriate here. It is -possible that this lock will become a contention point, but given the short -hold time once per transaction I think that contention is unlikely. - -The final serialisation point is the checkpoint commit record ordering code -that is run as part of the checkpoint commit and log force sequencing. The code -path that triggers a CIL flush (i.e. whatever triggers the log force) will enter -an ordering loop after writing all the log vectors into the log buffers but -before writing the commit record. This loop walks the list of committing -checkpoints and needs to block waiting for checkpoints to complete their commit -record write. As a result it needs a lock and a wait variable. Log force -sequencing also requires the same lock, list walk, and blocking mechanism to -ensure completion of checkpoints. - -These two sequencing operations can use the mechanism even though the -events they are waiting for are different. The checkpoint commit record -sequencing needs to wait until checkpoint contexts contain a commit LSN -(obtained through completion of a commit record write) while log force -sequencing needs to wait until previous checkpoint contexts are removed from -the committing list (i.e. they've completed). A simple wait variable and -broadcast wakeups (thundering herds) has been used to implement these two -serialisation queues. They use the same lock as the CIL, too. If we see too -much contention on the CIL lock, or too many context switches as a result of -the broadcast wakeups these operations can be put under a new spinlock and -given separate wait lists to reduce lock contention and the number of processes -woken by the wrong event. - - -Lifecycle Changes ------------------ - -The existing log item life cycle is as follows:: - - 1. Transaction allocate - 2. Transaction reserve - 3. Lock item - 4. Join item to transaction - If not already attached, - Allocate log item - Attach log item to owner item - Attach log item to transaction - 5. Modify item - Record modifications in log item - 6. Transaction commit - Pin item in memory - Format item into log buffer - Write commit LSN into transaction - Unlock item - Attach transaction to log buffer - - - - - 7. Transaction completion - Mark log item committed - Insert log item into AIL - Write commit LSN into log item - Unpin log item - 8. AIL traversal - Lock item - Mark log item clean - Flush item to disk - - - - 9. Log item removed from AIL - Moves log tail - Item unlocked - -Essentially, steps 1-6 operate independently from step 7, which is also -independent of steps 8-9. An item can be locked in steps 1-6 or steps 8-9 -at the same time step 7 is occurring, but only steps 1-6 or 8-9 can occur -at the same time. If the log item is in the AIL or between steps 6 and 7 -and steps 1-6 are re-entered, then the item is relogged. Only when steps 8-9 -are entered and completed is the object considered clean. - -With delayed logging, there are new steps inserted into the life cycle:: - - 1. Transaction allocate - 2. Transaction reserve - 3. Lock item - 4. Join item to transaction - If not already attached, - Allocate log item - Attach log item to owner item - Attach log item to transaction - 5. Modify item - Record modifications in log item - 6. Transaction commit - Pin item in memory if not pinned in CIL - Format item into log vector + buffer - Attach log vector and buffer to log item - Insert log item into CIL - Write CIL context sequence into transaction - Unlock item - - - - 7. CIL push - lock CIL flush - Chain log vectors and buffers together - Remove items from CIL - unlock CIL flush - write log vectors into log - sequence commit records - attach checkpoint context to log buffer - - - - - 8. Checkpoint completion - Mark log item committed - Insert item into AIL - Write commit LSN into log item - Unpin log item - 9. AIL traversal - Lock item - Mark log item clean - Flush item to disk - - 10. Log item removed from AIL - Moves log tail - Item unlocked - -From this, it can be seen that the only life cycle differences between the two -logging methods are in the middle of the life cycle - they still have the same -beginning and end and execution constraints. The only differences are in the -committing of the log items to the log itself and the completion processing. -Hence delayed logging should not introduce any constraints on log item -behaviour, allocation or freeing that don't already exist. - -As a result of this zero-impact "insertion" of delayed logging infrastructure -and the design of the internal structures to avoid on disk format changes, we -can basically switch between delayed logging and the existing mechanism with a -mount option. Fundamentally, there is no reason why the log manager would not -be able to swap methods automatically and transparently depending on load -characteristics, but this should not be necessary if delayed logging works as -designed. diff --git a/Documentation/filesystems/xfs-maintainer-entry-profile.rst b/Documentation/filesystems/xfs-maintainer-entry-profile.rst deleted file mode 100644 index 32b6ac4ca9d61f..00000000000000 --- a/Documentation/filesystems/xfs-maintainer-entry-profile.rst +++ /dev/null @@ -1,194 +0,0 @@ -XFS Maintainer Entry Profile -============================ - -Overview --------- -XFS is a well known high-performance filesystem in the Linux kernel. -The aim of this project is to provide and maintain a robust and -performant filesystem. - -Patches are generally merged to the for-next branch of the appropriate -git repository. -After a testing period, the for-next branch is merged to the master -branch. - -Kernel code are merged to the xfs-linux tree[0]. -Userspace code are merged to the xfsprogs tree[1]. -Test cases are merged to the xfstests tree[2]. -Ondisk format documentation are merged to the xfs-documentation tree[3]. - -All patchsets involving XFS *must* be cc'd in their entirety to the mailing -list linux-xfs@vger.kernel.org. - -Roles ------ -There are eight key roles in the XFS project. -A person can take on multiple roles, and a role can be filled by -multiple people. -Anyone taking on a role is advised to check in with themselves and -others on a regular basis about burnout. - -- **Outside Contributor**: Anyone who sends a patch but is not involved - in the XFS project on a regular basis. - These folks are usually people who work on other filesystems or - elsewhere in the kernel community. - -- **Developer**: Someone who is familiar with the XFS codebase enough to - write new code, documentation, and tests. - - Developers can often be found in the IRC channel mentioned by the ``C:`` - entry in the kernel MAINTAINERS file. - -- **Senior Developer**: A developer who is very familiar with at least - some part of the XFS codebase and/or other subsystems in the kernel. - These people collectively decide the long term goals of the project - and nudge the community in that direction. - They should help prioritize development and review work for each release - cycle. - - Senior developers tend to be more active participants in the IRC channel. - -- **Reviewer**: Someone (most likely also a developer) who reads code - submissions to decide: - - 0. Is the idea behind the contribution sound? - 1. Does the idea fit the goals of the project? - 2. Is the contribution designed correctly? - 3. Is the contribution polished? - 4. Can the contribution be tested effectively? - - Reviewers should identify themselves with an ``R:`` entry in the kernel - and fstests MAINTAINERS files. - -- **Testing Lead**: This person is responsible for setting the test - coverage goals of the project, negotiating with developers to decide - on new tests for new features, and making sure that developers and - release managers execute on the testing. - - The testing lead should identify themselves with an ``M:`` entry in - the XFS section of the fstests MAINTAINERS file. - -- **Bug Triager**: Someone who examines incoming bug reports in just - enough detail to identify the person to whom the report should be - forwarded. - - The bug triagers should identify themselves with a ``B:`` entry in - the kernel MAINTAINERS file. - -- **Release Manager**: This person merges reviewed patchsets into an - integration branch, tests the result locally, pushes the branch to a - public git repository, and sends pull requests further upstream. - The release manager is not expected to work on new feature patchsets. - If a developer and a reviewer fail to reach a resolution on some point, - the release manager must have the ability to intervene to try to drive a - resolution. - - The release manager should identify themselves with an ``M:`` entry in - the kernel MAINTAINERS file. - -- **Community Manager**: This person calls and moderates meetings of as many - XFS participants as they can get when mailing list discussions prove - insufficient for collective decisionmaking. - They may also serve as liaison between managers of the organizations - sponsoring work on any part of XFS. - -- **LTS Maintainer**: Someone who backports and tests bug fixes from - uptream to the LTS kernels. - There tend to be six separate LTS trees at any given time. - - The maintainer for a given LTS release should identify themselves with an - ``M:`` entry in the MAINTAINERS file for that LTS tree. - Unmaintained LTS kernels should be marked with status ``S: Orphan`` in that - same file. - -Submission Checklist Addendum ------------------------------ -Please follow these additional rules when submitting to XFS: - -- Patches affecting only the filesystem itself should be based against - the latest -rc or the for-next branch. - These patches will be merged back to the for-next branch. - -- Authors of patches touching other subsystems need to coordinate with - the maintainers of XFS and the relevant subsystems to decide how to - proceed with a merge. - -- Any patchset changing XFS should be cc'd in its entirety to linux-xfs. - Do not send partial patchsets; that makes analysis of the broader - context of the changes unnecessarily difficult. - -- Anyone making kernel changes that have corresponding changes to the - userspace utilities should send the userspace changes as separate - patchsets immediately after the kernel patchsets. - -- Authors of bug fix patches are expected to use fstests[2] to perform - an A/B test of the patch to determine that there are no regressions. - When possible, a new regression test case should be written for - fstests. - -- Authors of new feature patchsets must ensure that fstests will have - appropriate functional and input corner-case test cases for the new - feature. - -- When implementing a new feature, it is strongly suggested that the - developers write a design document to answer the following questions: - - * **What** problem is this trying to solve? - - * **Who** will benefit from this solution, and **where** will they - access it? - - * **How** will this new feature work? This should touch on major data - structures and algorithms supporting the solution at a higher level - than code comments. - - * **What** userspace interfaces are necessary to build off of the new - features? - - * **How** will this work be tested to ensure that it solves the - problems laid out in the design document without causing new - problems? - - The design document should be committed in the kernel documentation - directory. - It may be omitted if the feature is already well known to the - community. - -- Patchsets for the new tests should be submitted as separate patchsets - immediately after the kernel and userspace code patchsets. - -- Changes to the on-disk format of XFS must be described in the ondisk - format document[3] and submitted as a patchset after the fstests - patchsets. - -- Patchsets implementing bug fixes and further code cleanups should put - the bug fixes at the beginning of the series to ease backporting. - -Key Release Cycle Dates ------------------------ -Bug fixes may be sent at any time, though the release manager may decide to -defer a patch when the next merge window is close. - -Code submissions targeting the next merge window should be sent between --rc1 and -rc6. -This gives the community time to review the changes, to suggest other changes, -and for the author to retest those changes. - -Code submissions also requiring changes to fs/iomap and targeting the -next merge window should be sent between -rc1 and -rc4. -This allows the broader kernel community adequate time to test the -infrastructure changes. - -Review Cadence --------------- -In general, please wait at least one week before pinging for feedback. -To find reviewers, either consult the MAINTAINERS file, or ask -developers that have Reviewed-by tags for XFS changes to take a look and -offer their opinion. - -References ----------- -| [0] https://git.kernel.org/pub/scm/fs/xfs/xfs-linux.git/ -| [1] https://git.kernel.org/pub/scm/fs/xfs/xfsprogs-dev.git/ -| [2] https://git.kernel.org/pub/scm/fs/xfs/xfstests-dev.git/ -| [3] https://git.kernel.org/pub/scm/fs/xfs/xfs-documentation.git/ diff --git a/Documentation/filesystems/xfs-online-fsck-design.rst b/Documentation/filesystems/xfs-online-fsck-design.rst deleted file mode 100644 index a0678101a7d02d..00000000000000 --- a/Documentation/filesystems/xfs-online-fsck-design.rst +++ /dev/null @@ -1,5315 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 -.. _xfs_online_fsck_design: - -.. - Mapping of heading styles within this document: - Heading 1 uses "====" above and below - Heading 2 uses "====" - Heading 3 uses "----" - Heading 4 uses "````" - Heading 5 uses "^^^^" - Heading 6 uses "~~~~" - Heading 7 uses "...." - - Sections are manually numbered because apparently that's what everyone - does in the kernel. - -====================== -XFS Online Fsck Design -====================== - -This document captures the design of the online filesystem check feature for -XFS. -The purpose of this document is threefold: - -- To help kernel distributors understand exactly what the XFS online fsck - feature is, and issues about which they should be aware. - -- To help people reading the code to familiarize themselves with the relevant - concepts and design points before they start digging into the code. - -- To help developers maintaining the system by capturing the reasons - supporting higher level decision making. - -As the online fsck code is merged, the links in this document to topic branches -will be replaced with links to code. - -This document is licensed under the terms of the GNU Public License, v2. -The primary author is Darrick J. Wong. - -This design document is split into seven parts. -Part 1 defines what fsck tools are and the motivations for writing a new one. -Parts 2 and 3 present a high level overview of how online fsck process works -and how it is tested to ensure correct functionality. -Part 4 discusses the user interface and the intended usage modes of the new -program. -Parts 5 and 6 show off the high level components and how they fit together, and -then present case studies of how each repair function actually works. -Part 7 sums up what has been discussed so far and speculates about what else -might be built atop online fsck. - -.. contents:: Table of Contents - :local: - -1. What is a Filesystem Check? -============================== - -A Unix filesystem has four main responsibilities: - -- Provide a hierarchy of names through which application programs can associate - arbitrary blobs of data for any length of time, - -- Virtualize physical storage media across those names, and - -- Retrieve the named data blobs at any time. - -- Examine resource usage. - -Metadata directly supporting these functions (e.g. files, directories, space -mappings) are sometimes called primary metadata. -Secondary metadata (e.g. reverse mapping and directory parent pointers) support -operations internal to the filesystem, such as internal consistency checking -and reorganization. -Summary metadata, as the name implies, condense information contained in -primary metadata for performance reasons. - -The filesystem check (fsck) tool examines all the metadata in a filesystem -to look for errors. -In addition to looking for obvious metadata corruptions, fsck also -cross-references different types of metadata records with each other to look -for inconsistencies. -People do not like losing data, so most fsck tools also contains some ability -to correct any problems found. -As a word of caution -- the primary goal of most Linux fsck tools is to restore -the filesystem metadata to a consistent state, not to maximize the data -recovered. -That precedent will not be challenged here. - -Filesystems of the 20th century generally lacked any redundancy in the ondisk -format, which means that fsck can only respond to errors by erasing files until -errors are no longer detected. -More recent filesystem designs contain enough redundancy in their metadata that -it is now possible to regenerate data structures when non-catastrophic errors -occur; this capability aids both strategies. - -+--------------------------------------------------------------------------+ -| **Note**: | -+--------------------------------------------------------------------------+ -| System administrators avoid data loss by increasing the number of | -| separate storage systems through the creation of backups; and they avoid | -| downtime by increasing the redundancy of each storage system through the | -| creation of RAID arrays. | -| fsck tools address only the first problem. | -+--------------------------------------------------------------------------+ - -TLDR; Show Me the Code! ------------------------ - -Code is posted to the kernel.org git trees as follows: -`kernel changes `_, -`userspace changes `_, and -`QA test changes `_. -Each kernel patchset adding an online repair function will use the same branch -name across the kernel, xfsprogs, and fstests git repos. - -Existing Tools --------------- - -The online fsck tool described here will be the third tool in the history of -XFS (on Linux) to check and repair filesystems. -Two programs precede it: - -The first program, ``xfs_check``, was created as part of the XFS debugger -(``xfs_db``) and can only be used with unmounted filesystems. -It walks all metadata in the filesystem looking for inconsistencies in the -metadata, though it lacks any ability to repair what it finds. -Due to its high memory requirements and inability to repair things, this -program is now deprecated and will not be discussed further. - -The second program, ``xfs_repair``, was created to be faster and more robust -than the first program. -Like its predecessor, it can only be used with unmounted filesystems. -It uses extent-based in-memory data structures to reduce memory consumption, -and tries to schedule readahead IO appropriately to reduce I/O waiting time -while it scans the metadata of the entire filesystem. -The most important feature of this tool is its ability to respond to -inconsistencies in file metadata and directory tree by erasing things as needed -to eliminate problems. -Space usage metadata are rebuilt from the observed file metadata. - -Problem Statement ------------------ - -The current XFS tools leave several problems unsolved: - -1. **User programs** suddenly **lose access** to the filesystem when unexpected - shutdowns occur as a result of silent corruptions in the metadata. - These occur **unpredictably** and often without warning. - -2. **Users** experience a **total loss of service** during the recovery period - after an **unexpected shutdown** occurs. - -3. **Users** experience a **total loss of service** if the filesystem is taken - offline to **look for problems** proactively. - -4. **Data owners** cannot **check the integrity** of their stored data without - reading all of it. - This may expose them to substantial billing costs when a linear media scan - performed by the storage system administrator might suffice. - -5. **System administrators** cannot **schedule** a maintenance window to deal - with corruptions if they **lack the means** to assess filesystem health - while the filesystem is online. - -6. **Fleet monitoring tools** cannot **automate periodic checks** of filesystem - health when doing so requires **manual intervention** and downtime. - -7. **Users** can be tricked into **doing things they do not desire** when - malicious actors **exploit quirks of Unicode** to place misleading names - in directories. - -Given this definition of the problems to be solved and the actors who would -benefit, the proposed solution is a third fsck tool that acts on a running -filesystem. - -This new third program has three components: an in-kernel facility to check -metadata, an in-kernel facility to repair metadata, and a userspace driver -program to drive fsck activity on a live filesystem. -``xfs_scrub`` is the name of the driver program. -The rest of this document presents the goals and use cases of the new fsck -tool, describes its major design points in connection to those goals, and -discusses the similarities and differences with existing tools. - -+--------------------------------------------------------------------------+ -| **Note**: | -+--------------------------------------------------------------------------+ -| Throughout this document, the existing offline fsck tool can also be | -| referred to by its current name "``xfs_repair``". | -| The userspace driver program for the new online fsck tool can be | -| referred to as "``xfs_scrub``". | -| The kernel portion of online fsck that validates metadata is called | -| "online scrub", and portion of the kernel that fixes metadata is called | -| "online repair". | -+--------------------------------------------------------------------------+ - -The naming hierarchy is broken up into objects known as directories and files -and the physical space is split into pieces known as allocation groups. -Sharding enables better performance on highly parallel systems and helps to -contain the damage when corruptions occur. -The division of the filesystem into principal objects (allocation groups and -inodes) means that there are ample opportunities to perform targeted checks and -repairs on a subset of the filesystem. - -While this is going on, other parts continue processing IO requests. -Even if a piece of filesystem metadata can only be regenerated by scanning the -entire system, the scan can still be done in the background while other file -operations continue. - -In summary, online fsck takes advantage of resource sharding and redundant -metadata to enable targeted checking and repair operations while the system -is running. -This capability will be coupled to automatic system management so that -autonomous self-healing of XFS maximizes service availability. - -2. Theory of Operation -====================== - -Because it is necessary for online fsck to lock and scan live metadata objects, -online fsck consists of three separate code components. -The first is the userspace driver program ``xfs_scrub``, which is responsible -for identifying individual metadata items, scheduling work items for them, -reacting to the outcomes appropriately, and reporting results to the system -administrator. -The second and third are in the kernel, which implements functions to check -and repair each type of online fsck work item. - -+------------------------------------------------------------------+ -| **Note**: | -+------------------------------------------------------------------+ -| For brevity, this document shortens the phrase "online fsck work | -| item" to "scrub item". | -+------------------------------------------------------------------+ - -Scrub item types are delineated in a manner consistent with the Unix design -philosophy, which is to say that each item should handle one aspect of a -metadata structure, and handle it well. - -Scope ------ - -In principle, online fsck should be able to check and to repair everything that -the offline fsck program can handle. -However, online fsck cannot be running 100% of the time, which means that -latent errors may creep in after a scrub completes. -If these errors cause the next mount to fail, offline fsck is the only -solution. -This limitation means that maintenance of the offline fsck tool will continue. -A second limitation of online fsck is that it must follow the same resource -sharing and lock acquisition rules as the regular filesystem. -This means that scrub cannot take *any* shortcuts to save time, because doing -so could lead to concurrency problems. -In other words, online fsck is not a complete replacement for offline fsck, and -a complete run of online fsck may take longer than online fsck. -However, both of these limitations are acceptable tradeoffs to satisfy the -different motivations of online fsck, which are to **minimize system downtime** -and to **increase predictability of operation**. - -.. _scrubphases: - -Phases of Work --------------- - -The userspace driver program ``xfs_scrub`` splits the work of checking and -repairing an entire filesystem into seven phases. -Each phase concentrates on checking specific types of scrub items and depends -on the success of all previous phases. -The seven phases are as follows: - -1. Collect geometry information about the mounted filesystem and computer, - discover the online fsck capabilities of the kernel, and open the - underlying storage devices. - -2. Check allocation group metadata, all realtime volume metadata, and all quota - files. - Each metadata structure is scheduled as a separate scrub item. - If corruption is found in the inode header or inode btree and ``xfs_scrub`` - is permitted to perform repairs, then those scrub items are repaired to - prepare for phase 3. - Repairs are implemented by using the information in the scrub item to - resubmit the kernel scrub call with the repair flag enabled; this is - discussed in the next section. - Optimizations and all other repairs are deferred to phase 4. - -3. Check all metadata of every file in the filesystem. - Each metadata structure is also scheduled as a separate scrub item. - If repairs are needed and ``xfs_scrub`` is permitted to perform repairs, - and there were no problems detected during phase 2, then those scrub items - are repaired immediately. - Optimizations, deferred repairs, and unsuccessful repairs are deferred to - phase 4. - -4. All remaining repairs and scheduled optimizations are performed during this - phase, if the caller permits them. - Before starting repairs, the summary counters are checked and any necessary - repairs are performed so that subsequent repairs will not fail the resource - reservation step due to wildly incorrect summary counters. - Unsuccessful repairs are requeued as long as forward progress on repairs is - made somewhere in the filesystem. - Free space in the filesystem is trimmed at the end of phase 4 if the - filesystem is clean. - -5. By the start of this phase, all primary and secondary filesystem metadata - must be correct. - Summary counters such as the free space counts and quota resource counts - are checked and corrected. - Directory entry names and extended attribute names are checked for - suspicious entries such as control characters or confusing Unicode sequences - appearing in names. - -6. If the caller asks for a media scan, read all allocated and written data - file extents in the filesystem. - The ability to use hardware-assisted data file integrity checking is new - to online fsck; neither of the previous tools have this capability. - If media errors occur, they will be mapped to the owning files and reported. - -7. Re-check the summary counters and presents the caller with a summary of - space usage and file counts. - -This allocation of responsibilities will be :ref:`revisited ` -later in this document. - -Steps for Each Scrub Item -------------------------- - -The kernel scrub code uses a three-step strategy for checking and repairing -the one aspect of a metadata object represented by a scrub item: - -1. The scrub item of interest is checked for corruptions; opportunities for - optimization; and for values that are directly controlled by the system - administrator but look suspicious. - If the item is not corrupt or does not need optimization, resource are - released and the positive scan results are returned to userspace. - If the item is corrupt or could be optimized but the caller does not permit - this, resources are released and the negative scan results are returned to - userspace. - Otherwise, the kernel moves on to the second step. - -2. The repair function is called to rebuild the data structure. - Repair functions generally choose rebuild a structure from other metadata - rather than try to salvage the existing structure. - If the repair fails, the scan results from the first step are returned to - userspace. - Otherwise, the kernel moves on to the third step. - -3. In the third step, the kernel runs the same checks over the new metadata - item to assess the efficacy of the repairs. - The results of the reassessment are returned to userspace. - -Classification of Metadata --------------------------- - -Each type of metadata object (and therefore each type of scrub item) is -classified as follows: - -Primary Metadata -```````````````` - -Metadata structures in this category should be most familiar to filesystem -users either because they are directly created by the user or they index -objects created by the user -Most filesystem objects fall into this class: - -- Free space and reference count information - -- Inode records and indexes - -- Storage mapping information for file data - -- Directories - -- Extended attributes - -- Symbolic links - -- Quota limits - -Scrub obeys the same rules as regular filesystem accesses for resource and lock -acquisition. - -Primary metadata objects are the simplest for scrub to process. -The principal filesystem object (either an allocation group or an inode) that -owns the item being scrubbed is locked to guard against concurrent updates. -The check function examines every record associated with the type for obvious -errors and cross-references healthy records against other metadata to look for -inconsistencies. -Repairs for this class of scrub item are simple, since the repair function -starts by holding all the resources acquired in the previous step. -The repair function scans available metadata as needed to record all the -observations needed to complete the structure. -Next, it stages the observations in a new ondisk structure and commits it -atomically to complete the repair. -Finally, the storage from the old data structure are carefully reaped. - -Because ``xfs_scrub`` locks a primary object for the duration of the repair, -this is effectively an offline repair operation performed on a subset of the -filesystem. -This minimizes the complexity of the repair code because it is not necessary to -handle concurrent updates from other threads, nor is it necessary to access -any other part of the filesystem. -As a result, indexed structures can be rebuilt very quickly, and programs -trying to access the damaged structure will be blocked until repairs complete. -The only infrastructure needed by the repair code are the staging area for -observations and a means to write new structures to disk. -Despite these limitations, the advantage that online repair holds is clear: -targeted work on individual shards of the filesystem avoids total loss of -service. - -This mechanism is described in section 2.1 ("Off-Line Algorithm") of -V. Srinivasan and M. J. Carey, `"Performance of On-Line Index Construction -Algorithms" `_, -*Extending Database Technology*, pp. 293-309, 1992. - -Most primary metadata repair functions stage their intermediate results in an -in-memory array prior to formatting the new ondisk structure, which is very -similar to the list-based algorithm discussed in section 2.3 ("List-Based -Algorithms") of Srinivasan. -However, any data structure builder that maintains a resource lock for the -duration of the repair is *always* an offline algorithm. - -.. _secondary_metadata: - -Secondary Metadata -`````````````````` - -Metadata structures in this category reflect records found in primary metadata, -but are only needed for online fsck or for reorganization of the filesystem. - -Secondary metadata include: - -- Reverse mapping information - -- Directory parent pointers - -This class of metadata is difficult for scrub to process because scrub attaches -to the secondary object but needs to check primary metadata, which runs counter -to the usual order of resource acquisition. -Frequently, this means that full filesystems scans are necessary to rebuild the -metadata. -Check functions can be limited in scope to reduce runtime. -Repairs, however, require a full scan of primary metadata, which can take a -long time to complete. -Under these conditions, ``xfs_scrub`` cannot lock resources for the entire -duration of the repair. - -Instead, repair functions set up an in-memory staging structure to store -observations. -Depending on the requirements of the specific repair function, the staging -index will either have the same format as the ondisk structure or a design -specific to that repair function. -The next step is to release all locks and start the filesystem scan. -When the repair scanner needs to record an observation, the staging data are -locked long enough to apply the update. -While the filesystem scan is in progress, the repair function hooks the -filesystem so that it can apply pending filesystem updates to the staging -information. -Once the scan is done, the owning object is re-locked, the live data is used to -write a new ondisk structure, and the repairs are committed atomically. -The hooks are disabled and the staging staging area is freed. -Finally, the storage from the old data structure are carefully reaped. - -Introducing concurrency helps online repair avoid various locking problems, but -comes at a high cost to code complexity. -Live filesystem code has to be hooked so that the repair function can observe -updates in progress. -The staging area has to become a fully functional parallel structure so that -updates can be merged from the hooks. -Finally, the hook, the filesystem scan, and the inode locking model must be -sufficiently well integrated that a hook event can decide if a given update -should be applied to the staging structure. - -In theory, the scrub implementation could apply these same techniques for -primary metadata, but doing so would make it massively more complex and less -performant. -Programs attempting to access the damaged structures are not blocked from -operation, which may cause application failure or an unplanned filesystem -shutdown. - -Inspiration for the secondary metadata repair strategy was drawn from section -2.4 of Srinivasan above, and sections 2 ("NSF: Inded Build Without Side-File") -and 3.1.1 ("Duplicate Key Insert Problem") in C. Mohan, `"Algorithms for -Creating Indexes for Very Large Tables Without Quiescing Updates" -`_, 1992. - -The sidecar index mentioned above bears some resemblance to the side file -method mentioned in Srinivasan and Mohan. -Their method consists of an index builder that extracts relevant record data to -build the new structure as quickly as possible; and an auxiliary structure that -captures all updates that would be committed to the index by other threads were -the new index already online. -After the index building scan finishes, the updates recorded in the side file -are applied to the new index. -To avoid conflicts between the index builder and other writer threads, the -builder maintains a publicly visible cursor that tracks the progress of the -scan through the record space. -To avoid duplication of work between the side file and the index builder, side -file updates are elided when the record ID for the update is greater than the -cursor position within the record ID space. - -To minimize changes to the rest of the codebase, XFS online repair keeps the -replacement index hidden until it's completely ready to go. -In other words, there is no attempt to expose the keyspace of the new index -while repair is running. -The complexity of such an approach would be very high and perhaps more -appropriate to building *new* indices. - -**Future Work Question**: Can the full scan and live update code used to -facilitate a repair also be used to implement a comprehensive check? - -*Answer*: In theory, yes. Check would be much stronger if each scrub function -employed these live scans to build a shadow copy of the metadata and then -compared the shadow records to the ondisk records. -However, doing that is a fair amount more work than what the checking functions -do now. -The live scans and hooks were developed much later. -That in turn increases the runtime of those scrub functions. - -Summary Information -``````````````````` - -Metadata structures in this last category summarize the contents of primary -metadata records. -These are often used to speed up resource usage queries, and are many times -smaller than the primary metadata which they represent. - -Examples of summary information include: - -- Summary counts of free space and inodes - -- File link counts from directories - -- Quota resource usage counts - -Check and repair require full filesystem scans, but resource and lock -acquisition follow the same paths as regular filesystem accesses. - -The superblock summary counters have special requirements due to the underlying -implementation of the incore counters, and will be treated separately. -Check and repair of the other types of summary counters (quota resource counts -and file link counts) employ the same filesystem scanning and hooking -techniques as outlined above, but because the underlying data are sets of -integer counters, the staging data need not be a fully functional mirror of the -ondisk structure. - -Inspiration for quota and file link count repair strategies were drawn from -sections 2.12 ("Online Index Operations") through 2.14 ("Incremental View -Maintenance") of G. Graefe, `"Concurrent Queries and Updates in Summary Views -and Their Indexes" -`_, 2011. - -Since quotas are non-negative integer counts of resource usage, online -quotacheck can use the incremental view deltas described in section 2.14 to -track pending changes to the block and inode usage counts in each transaction, -and commit those changes to a dquot side file when the transaction commits. -Delta tracking is necessary for dquots because the index builder scans inodes, -whereas the data structure being rebuilt is an index of dquots. -Link count checking combines the view deltas and commit step into one because -it sets attributes of the objects being scanned instead of writing them to a -separate data structure. -Each online fsck function will be discussed as case studies later in this -document. - -Risk Management ---------------- - -During the development of online fsck, several risk factors were identified -that may make the feature unsuitable for certain distributors and users. -Steps can be taken to mitigate or eliminate those risks, though at a cost to -functionality. - -- **Decreased performance**: Adding metadata indices to the filesystem - increases the time cost of persisting changes to disk, and the reverse space - mapping and directory parent pointers are no exception. - System administrators who require the maximum performance can disable the - reverse mapping features at format time, though this choice dramatically - reduces the ability of online fsck to find inconsistencies and repair them. - -- **Incorrect repairs**: As with all software, there might be defects in the - software that result in incorrect repairs being written to the filesystem. - Systematic fuzz testing (detailed in the next section) is employed by the - authors to find bugs early, but it might not catch everything. - The kernel build system provides Kconfig options (``CONFIG_XFS_ONLINE_SCRUB`` - and ``CONFIG_XFS_ONLINE_REPAIR``) to enable distributors to choose not to - accept this risk. - The xfsprogs build system has a configure option (``--enable-scrub=no``) that - disables building of the ``xfs_scrub`` binary, though this is not a risk - mitigation if the kernel functionality remains enabled. - -- **Inability to repair**: Sometimes, a filesystem is too badly damaged to be - repairable. - If the keyspaces of several metadata indices overlap in some manner but a - coherent narrative cannot be formed from records collected, then the repair - fails. - To reduce the chance that a repair will fail with a dirty transaction and - render the filesystem unusable, the online repair functions have been - designed to stage and validate all new records before committing the new - structure. - -- **Misbehavior**: Online fsck requires many privileges -- raw IO to block - devices, opening files by handle, ignoring Unix discretionary access control, - and the ability to perform administrative changes. - Running this automatically in the background scares people, so the systemd - background service is configured to run with only the privileges required. - Obviously, this cannot address certain problems like the kernel crashing or - deadlocking, but it should be sufficient to prevent the scrub process from - escaping and reconfiguring the system. - The cron job does not have this protection. - -- **Fuzz Kiddiez**: There are many people now who seem to think that running - automated fuzz testing of ondisk artifacts to find mischievous behavior and - spraying exploit code onto the public mailing list for instant zero-day - disclosure is somehow of some social benefit. - In the view of this author, the benefit is realized only when the fuzz - operators help to **fix** the flaws, but this opinion apparently is not - widely shared among security "researchers". - The XFS maintainers' continuing ability to manage these events presents an - ongoing risk to the stability of the development process. - Automated testing should front-load some of the risk while the feature is - considered EXPERIMENTAL. - -Many of these risks are inherent to software programming. -Despite this, it is hoped that this new functionality will prove useful in -reducing unexpected downtime. - -3. Testing Plan -=============== - -As stated before, fsck tools have three main goals: - -1. Detect inconsistencies in the metadata; - -2. Eliminate those inconsistencies; and - -3. Minimize further loss of data. - -Demonstrations of correct operation are necessary to build users' confidence -that the software behaves within expectations. -Unfortunately, it was not really feasible to perform regular exhaustive testing -of every aspect of a fsck tool until the introduction of low-cost virtual -machines with high-IOPS storage. -With ample hardware availability in mind, the testing strategy for the online -fsck project involves differential analysis against the existing fsck tools and -systematic testing of every attribute of every type of metadata object. -Testing can be split into four major categories, as discussed below. - -Integrated Testing with fstests -------------------------------- - -The primary goal of any free software QA effort is to make testing as -inexpensive and widespread as possible to maximize the scaling advantages of -community. -In other words, testing should maximize the breadth of filesystem configuration -scenarios and hardware setups. -This improves code quality by enabling the authors of online fsck to find and -fix bugs early, and helps developers of new features to find integration -issues earlier in their development effort. - -The Linux filesystem community shares a common QA testing suite, -`fstests `_, for -functional and regression testing. -Even before development work began on online fsck, fstests (when run on XFS) -would run both the ``xfs_check`` and ``xfs_repair -n`` commands on the test and -scratch filesystems between each test. -This provides a level of assurance that the kernel and the fsck tools stay in -alignment about what constitutes consistent metadata. -During development of the online checking code, fstests was modified to run -``xfs_scrub -n`` between each test to ensure that the new checking code -produces the same results as the two existing fsck tools. - -To start development of online repair, fstests was modified to run -``xfs_repair`` to rebuild the filesystem's metadata indices between tests. -This ensures that offline repair does not crash, leave a corrupt filesystem -after it exists, or trigger complaints from the online check. -This also established a baseline for what can and cannot be repaired offline. -To complete the first phase of development of online repair, fstests was -modified to be able to run ``xfs_scrub`` in a "force rebuild" mode. -This enables a comparison of the effectiveness of online repair as compared to -the existing offline repair tools. - -General Fuzz Testing of Metadata Blocks ---------------------------------------- - -XFS benefits greatly from having a very robust debugging tool, ``xfs_db``. - -Before development of online fsck even began, a set of fstests were created -to test the rather common fault that entire metadata blocks get corrupted. -This required the creation of fstests library code that can create a filesystem -containing every possible type of metadata object. -Next, individual test cases were created to create a test filesystem, identify -a single block of a specific type of metadata object, trash it with the -existing ``blocktrash`` command in ``xfs_db``, and test the reaction of a -particular metadata validation strategy. - -This earlier test suite enabled XFS developers to test the ability of the -in-kernel validation functions and the ability of the offline fsck tool to -detect and eliminate the inconsistent metadata. -This part of the test suite was extended to cover online fsck in exactly the -same manner. - -In other words, for a given fstests filesystem configuration: - -* For each metadata object existing on the filesystem: - - * Write garbage to it - - * Test the reactions of: - - 1. The kernel verifiers to stop obviously bad metadata - 2. Offline repair (``xfs_repair``) to detect and fix - 3. Online repair (``xfs_scrub``) to detect and fix - -Targeted Fuzz Testing of Metadata Records ------------------------------------------ - -The testing plan for online fsck includes extending the existing fs testing -infrastructure to provide a much more powerful facility: targeted fuzz testing -of every metadata field of every metadata object in the filesystem. -``xfs_db`` can modify every field of every metadata structure in every -block in the filesystem to simulate the effects of memory corruption and -software bugs. -Given that fstests already contains the ability to create a filesystem -containing every metadata format known to the filesystem, ``xfs_db`` can be -used to perform exhaustive fuzz testing! - -For a given fstests filesystem configuration: - -* For each metadata object existing on the filesystem... - - * For each record inside that metadata object... - - * For each field inside that record... - - * For each conceivable type of transformation that can be applied to a bit field... - - 1. Clear all bits - 2. Set all bits - 3. Toggle the most significant bit - 4. Toggle the middle bit - 5. Toggle the least significant bit - 6. Add a small quantity - 7. Subtract a small quantity - 8. Randomize the contents - - * ...test the reactions of: - - 1. The kernel verifiers to stop obviously bad metadata - 2. Offline checking (``xfs_repair -n``) - 3. Offline repair (``xfs_repair``) - 4. Online checking (``xfs_scrub -n``) - 5. Online repair (``xfs_scrub``) - 6. Both repair tools (``xfs_scrub`` and then ``xfs_repair`` if online repair doesn't succeed) - -This is quite the combinatoric explosion! - -Fortunately, having this much test coverage makes it easy for XFS developers to -check the responses of XFS' fsck tools. -Since the introduction of the fuzz testing framework, these tests have been -used to discover incorrect repair code and missing functionality for entire -classes of metadata objects in ``xfs_repair``. -The enhanced testing was used to finalize the deprecation of ``xfs_check`` by -confirming that ``xfs_repair`` could detect at least as many corruptions as -the older tool. - -These tests have been very valuable for ``xfs_scrub`` in the same ways -- they -allow the online fsck developers to compare online fsck against offline fsck, -and they enable XFS developers to find deficiencies in the code base. - -Proposed patchsets include -`general fuzzer improvements -`_, -`fuzzing baselines -`_, -and `improvements in fuzz testing comprehensiveness -`_. - -Stress Testing --------------- - -A unique requirement to online fsck is the ability to operate on a filesystem -concurrently with regular workloads. -Although it is of course impossible to run ``xfs_scrub`` with *zero* observable -impact on the running system, the online repair code should never introduce -inconsistencies into the filesystem metadata, and regular workloads should -never notice resource starvation. -To verify that these conditions are being met, fstests has been enhanced in -the following ways: - -* For each scrub item type, create a test to exercise checking that item type - while running ``fsstress``. -* For each scrub item type, create a test to exercise repairing that item type - while running ``fsstress``. -* Race ``fsstress`` and ``xfs_scrub -n`` to ensure that checking the whole - filesystem doesn't cause problems. -* Race ``fsstress`` and ``xfs_scrub`` in force-rebuild mode to ensure that - force-repairing the whole filesystem doesn't cause problems. -* Race ``xfs_scrub`` in check and force-repair mode against ``fsstress`` while - freezing and thawing the filesystem. -* Race ``xfs_scrub`` in check and force-repair mode against ``fsstress`` while - remounting the filesystem read-only and read-write. -* The same, but running ``fsx`` instead of ``fsstress``. (Not done yet?) - -Success is defined by the ability to run all of these tests without observing -any unexpected filesystem shutdowns due to corrupted metadata, kernel hang -check warnings, or any other sort of mischief. - -Proposed patchsets include `general stress testing -`_ -and the `evolution of existing per-function stress testing -`_. - -4. User Interface -================= - -The primary user of online fsck is the system administrator, just like offline -repair. -Online fsck presents two modes of operation to administrators: -A foreground CLI process for online fsck on demand, and a background service -that performs autonomous checking and repair. - -Checking on Demand ------------------- - -For administrators who want the absolute freshest information about the -metadata in a filesystem, ``xfs_scrub`` can be run as a foreground process on -a command line. -The program checks every piece of metadata in the filesystem while the -administrator waits for the results to be reported, just like the existing -``xfs_repair`` tool. -Both tools share a ``-n`` option to perform a read-only scan, and a ``-v`` -option to increase the verbosity of the information reported. - -A new feature of ``xfs_scrub`` is the ``-x`` option, which employs the error -correction capabilities of the hardware to check data file contents. -The media scan is not enabled by default because it may dramatically increase -program runtime and consume a lot of bandwidth on older storage hardware. - -The output of a foreground invocation is captured in the system log. - -The ``xfs_scrub_all`` program walks the list of mounted filesystems and -initiates ``xfs_scrub`` for each of them in parallel. -It serializes scans for any filesystems that resolve to the same top level -kernel block device to prevent resource overconsumption. - -Background Service ------------------- - -To reduce the workload of system administrators, the ``xfs_scrub`` package -provides a suite of `systemd `_ timers and services that -run online fsck automatically on weekends by default. -The background service configures scrub to run with as little privilege as -possible, the lowest CPU and IO priority, and in a CPU-constrained single -threaded mode. -This can be tuned by the systemd administrator at any time to suit the latency -and throughput requirements of customer workloads. - -The output of the background service is also captured in the system log. -If desired, reports of failures (either due to inconsistencies or mere runtime -errors) can be emailed automatically by setting the ``EMAIL_ADDR`` environment -variable in the following service files: - -* ``xfs_scrub_fail@.service`` -* ``xfs_scrub_media_fail@.service`` -* ``xfs_scrub_all_fail.service`` - -The decision to enable the background scan is left to the system administrator. -This can be done by enabling either of the following services: - -* ``xfs_scrub_all.timer`` on systemd systems -* ``xfs_scrub_all.cron`` on non-systemd systems - -This automatic weekly scan is configured out of the box to perform an -additional media scan of all file data once per month. -This is less foolproof than, say, storing file data block checksums, but much -more performant if application software provides its own integrity checking, -redundancy can be provided elsewhere above the filesystem, or the storage -device's integrity guarantees are deemed sufficient. - -The systemd unit file definitions have been subjected to a security audit -(as of systemd 249) to ensure that the xfs_scrub processes have as little -access to the rest of the system as possible. -This was performed via ``systemd-analyze security``, after which privileges -were restricted to the minimum required, sandboxing was set up to the maximal -extent possible with sandboxing and system call filtering; and access to the -filesystem tree was restricted to the minimum needed to start the program and -access the filesystem being scanned. -The service definition files restrict CPU usage to 80% of one CPU core, and -apply as nice of a priority to IO and CPU scheduling as possible. -This measure was taken to minimize delays in the rest of the filesystem. -No such hardening has been performed for the cron job. - -Proposed patchset: -`Enabling the xfs_scrub background service -`_. - -Health Reporting ----------------- - -XFS caches a summary of each filesystem's health status in memory. -The information is updated whenever ``xfs_scrub`` is run, or whenever -inconsistencies are detected in the filesystem metadata during regular -operations. -System administrators should use the ``health`` command of ``xfs_spaceman`` to -download this information into a human-readable format. -If problems have been observed, the administrator can schedule a reduced -service window to run the online repair tool to correct the problem. -Failing that, the administrator can decide to schedule a maintenance window to -run the traditional offline repair tool to correct the problem. - -**Future Work Question**: Should the health reporting integrate with the new -inotify fs error notification system? -Would it be helpful for sysadmins to have a daemon to listen for corruption -notifications and initiate a repair? - -*Answer*: These questions remain unanswered, but should be a part of the -conversation with early adopters and potential downstream users of XFS. - -Proposed patchsets include -`wiring up health reports to correction returns -`_ -and -`preservation of sickness info during memory reclaim -`_. - -5. Kernel Algorithms and Data Structures -======================================== - -This section discusses the key algorithms and data structures of the kernel -code that provide the ability to check and repair metadata while the system -is running. -The first chapters in this section reveal the pieces that provide the -foundation for checking metadata. -The remainder of this section presents the mechanisms through which XFS -regenerates itself. - -Self Describing Metadata ------------------------- - -Starting with XFS version 5 in 2012, XFS updated the format of nearly every -ondisk block header to record a magic number, a checksum, a universally -"unique" identifier (UUID), an owner code, the ondisk address of the block, -and a log sequence number. -When loading a block buffer from disk, the magic number, UUID, owner, and -ondisk address confirm that the retrieved block matches the specific owner of -the current filesystem, and that the information contained in the block is -supposed to be found at the ondisk address. -The first three components enable checking tools to disregard alleged metadata -that doesn't belong to the filesystem, and the fourth component enables the -filesystem to detect lost writes. - -Whenever a file system operation modifies a block, the change is submitted -to the log as part of a transaction. -The log then processes these transactions marking them done once they are -safely persisted to storage. -The logging code maintains the checksum and the log sequence number of the last -transactional update. -Checksums are useful for detecting torn writes and other discrepancies that can -be introduced between the computer and its storage devices. -Sequence number tracking enables log recovery to avoid applying out of date -log updates to the filesystem. - -These two features improve overall runtime resiliency by providing a means for -the filesystem to detect obvious corruption when reading metadata blocks from -disk, but these buffer verifiers cannot provide any consistency checking -between metadata structures. - -For more information, please see the documentation for -Documentation/filesystems/xfs-self-describing-metadata.rst - -Reverse Mapping ---------------- - -The original design of XFS (circa 1993) is an improvement upon 1980s Unix -filesystem design. -In those days, storage density was expensive, CPU time was scarce, and -excessive seek time could kill performance. -For performance reasons, filesystem authors were reluctant to add redundancy to -the filesystem, even at the cost of data integrity. -Filesystems designers in the early 21st century choose different strategies to -increase internal redundancy -- either storing nearly identical copies of -metadata, or more space-efficient encoding techniques. - -For XFS, a different redundancy strategy was chosen to modernize the design: -a secondary space usage index that maps allocated disk extents back to their -owners. -By adding a new index, the filesystem retains most of its ability to scale -well to heavily threaded workloads involving large datasets, since the primary -file metadata (the directory tree, the file block map, and the allocation -groups) remain unchanged. -Like any system that improves redundancy, the reverse-mapping feature increases -overhead costs for space mapping activities. -However, it has two critical advantages: first, the reverse index is key to -enabling online fsck and other requested functionality such as free space -defragmentation, better media failure reporting, and filesystem shrinking. -Second, the different ondisk storage format of the reverse mapping btree -defeats device-level deduplication because the filesystem requires real -redundancy. - -+--------------------------------------------------------------------------+ -| **Sidebar**: | -+--------------------------------------------------------------------------+ -| A criticism of adding the secondary index is that it does nothing to | -| improve the robustness of user data storage itself. | -| This is a valid point, but adding a new index for file data block | -| checksums increases write amplification by turning data overwrites into | -| copy-writes, which age the filesystem prematurely. | -| In keeping with thirty years of precedent, users who want file data | -| integrity can supply as powerful a solution as they require. | -| As for metadata, the complexity of adding a new secondary index of space | -| usage is much less than adding volume management and storage device | -| mirroring to XFS itself. | -| Perfection of RAID and volume management are best left to existing | -| layers in the kernel. | -+--------------------------------------------------------------------------+ - -The information captured in a reverse space mapping record is as follows: - -.. code-block:: c - - struct xfs_rmap_irec { - xfs_agblock_t rm_startblock; /* extent start block */ - xfs_extlen_t rm_blockcount; /* extent length */ - uint64_t rm_owner; /* extent owner */ - uint64_t rm_offset; /* offset within the owner */ - unsigned int rm_flags; /* state flags */ - }; - -The first two fields capture the location and size of the physical space, -in units of filesystem blocks. -The owner field tells scrub which metadata structure or file inode have been -assigned this space. -For space allocated to files, the offset field tells scrub where the space was -mapped within the file fork. -Finally, the flags field provides extra information about the space usage -- -is this an attribute fork extent? A file mapping btree extent? Or an -unwritten data extent? - -Online filesystem checking judges the consistency of each primary metadata -record by comparing its information against all other space indices. -The reverse mapping index plays a key role in the consistency checking process -because it contains a centralized alternate copy of all space allocation -information. -Program runtime and ease of resource acquisition are the only real limits to -what online checking can consult. -For example, a file data extent mapping can be checked against: - -* The absence of an entry in the free space information. -* The absence of an entry in the inode index. -* The absence of an entry in the reference count data if the file is not - marked as having shared extents. -* The correspondence of an entry in the reverse mapping information. - -There are several observations to make about reverse mapping indices: - -1. Reverse mappings can provide a positive affirmation of correctness if any of - the above primary metadata are in doubt. - The checking code for most primary metadata follows a path similar to the - one outlined above. - -2. Proving the consistency of secondary metadata with the primary metadata is - difficult because that requires a full scan of all primary space metadata, - which is very time intensive. - For example, checking a reverse mapping record for a file extent mapping - btree block requires locking the file and searching the entire btree to - confirm the block. - Instead, scrub relies on rigorous cross-referencing during the primary space - mapping structure checks. - -3. Consistency scans must use non-blocking lock acquisition primitives if the - required locking order is not the same order used by regular filesystem - operations. - For example, if the filesystem normally takes a file ILOCK before taking - the AGF buffer lock but scrub wants to take a file ILOCK while holding - an AGF buffer lock, scrub cannot block on that second acquisition. - This means that forward progress during this part of a scan of the reverse - mapping data cannot be guaranteed if system load is heavy. - -In summary, reverse mappings play a key role in reconstruction of primary -metadata. -The details of how these records are staged, written to disk, and committed -into the filesystem are covered in subsequent sections. - -Checking and Cross-Referencing ------------------------------- - -The first step of checking a metadata structure is to examine every record -contained within the structure and its relationship with the rest of the -system. -XFS contains multiple layers of checking to try to prevent inconsistent -metadata from wreaking havoc on the system. -Each of these layers contributes information that helps the kernel to make -three decisions about the health of a metadata structure: - -- Is a part of this structure obviously corrupt (``XFS_SCRUB_OFLAG_CORRUPT``) ? -- Is this structure inconsistent with the rest of the system - (``XFS_SCRUB_OFLAG_XCORRUPT``) ? -- Is there so much damage around the filesystem that cross-referencing is not - possible (``XFS_SCRUB_OFLAG_XFAIL``) ? -- Can the structure be optimized to improve performance or reduce the size of - metadata (``XFS_SCRUB_OFLAG_PREEN``) ? -- Does the structure contain data that is not inconsistent but deserves review - by the system administrator (``XFS_SCRUB_OFLAG_WARNING``) ? - -The following sections describe how the metadata scrubbing process works. - -Metadata Buffer Verification -```````````````````````````` - -The lowest layer of metadata protection in XFS are the metadata verifiers built -into the buffer cache. -These functions perform inexpensive internal consistency checking of the block -itself, and answer these questions: - -- Does the block belong to this filesystem? - -- Does the block belong to the structure that asked for the read? - This assumes that metadata blocks only have one owner, which is always true - in XFS. - -- Is the type of data stored in the block within a reasonable range of what - scrub is expecting? - -- Does the physical location of the block match the location it was read from? - -- Does the block checksum match the data? - -The scope of the protections here are very limited -- verifiers can only -establish that the filesystem code is reasonably free of gross corruption bugs -and that the storage system is reasonably competent at retrieval. -Corruption problems observed at runtime cause the generation of health reports, -failed system calls, and in the extreme case, filesystem shutdowns if the -corrupt metadata force the cancellation of a dirty transaction. - -Every online fsck scrubbing function is expected to read every ondisk metadata -block of a structure in the course of checking the structure. -Corruption problems observed during a check are immediately reported to -userspace as corruption; during a cross-reference, they are reported as a -failure to cross-reference once the full examination is complete. -Reads satisfied by a buffer already in cache (and hence already verified) -bypass these checks. - -Internal Consistency Checks -``````````````````````````` - -After the buffer cache, the next level of metadata protection is the internal -record verification code built into the filesystem. -These checks are split between the buffer verifiers, the in-filesystem users of -the buffer cache, and the scrub code itself, depending on the amount of higher -level context required. -The scope of checking is still internal to the block. -These higher level checking functions answer these questions: - -- Does the type of data stored in the block match what scrub is expecting? - -- Does the block belong to the owning structure that asked for the read? - -- If the block contains records, do the records fit within the block? - -- If the block tracks internal free space information, is it consistent with - the record areas? - -- Are the records contained inside the block free of obvious corruptions? - -Record checks in this category are more rigorous and more time-intensive. -For example, block pointers and inumbers are checked to ensure that they point -within the dynamically allocated parts of an allocation group and within -the filesystem. -Names are checked for invalid characters, and flags are checked for invalid -combinations. -Other record attributes are checked for sensible values. -Btree records spanning an interval of the btree keyspace are checked for -correct order and lack of mergeability (except for file fork mappings). -For performance reasons, regular code may skip some of these checks unless -debugging is enabled or a write is about to occur. -Scrub functions, of course, must check all possible problems. - -Validation of Userspace-Controlled Record Attributes -```````````````````````````````````````````````````` - -Various pieces of filesystem metadata are directly controlled by userspace. -Because of this nature, validation work cannot be more precise than checking -that a value is within the possible range. -These fields include: - -- Superblock fields controlled by mount options -- Filesystem labels -- File timestamps -- File permissions -- File size -- File flags -- Names present in directory entries, extended attribute keys, and filesystem - labels -- Extended attribute key namespaces -- Extended attribute values -- File data block contents -- Quota limits -- Quota timer expiration (if resource usage exceeds the soft limit) - -Cross-Referencing Space Metadata -```````````````````````````````` - -After internal block checks, the next higher level of checking is -cross-referencing records between metadata structures. -For regular runtime code, the cost of these checks is considered to be -prohibitively expensive, but as scrub is dedicated to rooting out -inconsistencies, it must pursue all avenues of inquiry. -The exact set of cross-referencing is highly dependent on the context of the -data structure being checked. - -The XFS btree code has keyspace scanning functions that online fsck uses to -cross reference one structure with another. -Specifically, scrub can scan the key space of an index to determine if that -keyspace is fully, sparsely, or not at all mapped to records. -For the reverse mapping btree, it is possible to mask parts of the key for the -purposes of performing a keyspace scan so that scrub can decide if the rmap -btree contains records mapping a certain extent of physical space without the -sparsenses of the rest of the rmap keyspace getting in the way. - -Btree blocks undergo the following checks before cross-referencing: - -- Does the type of data stored in the block match what scrub is expecting? - -- Does the block belong to the owning structure that asked for the read? - -- Do the records fit within the block? - -- Are the records contained inside the block free of obvious corruptions? - -- Are the name hashes in the correct order? - -- Do node pointers within the btree point to valid block addresses for the type - of btree? - -- Do child pointers point towards the leaves? - -- Do sibling pointers point across the same level? - -- For each node block record, does the record key accurate reflect the contents - of the child block? - -Space allocation records are cross-referenced as follows: - -1. Any space mentioned by any metadata structure are cross-referenced as - follows: - - - Does the reverse mapping index list only the appropriate owner as the - owner of each block? - - - Are none of the blocks claimed as free space? - - - If these aren't file data blocks, are none of the blocks claimed as space - shared by different owners? - -2. Btree blocks are cross-referenced as follows: - - - Everything in class 1 above. - - - If there's a parent node block, do the keys listed for this block match the - keyspace of this block? - - - Do the sibling pointers point to valid blocks? Of the same level? - - - Do the child pointers point to valid blocks? Of the next level down? - -3. Free space btree records are cross-referenced as follows: - - - Everything in class 1 and 2 above. - - - Does the reverse mapping index list no owners of this space? - - - Is this space not claimed by the inode index for inodes? - - - Is it not mentioned by the reference count index? - - - Is there a matching record in the other free space btree? - -4. Inode btree records are cross-referenced as follows: - - - Everything in class 1 and 2 above. - - - Is there a matching record in free inode btree? - - - Do cleared bits in the holemask correspond with inode clusters? - - - Do set bits in the freemask correspond with inode records with zero link - count? - -5. Inode records are cross-referenced as follows: - - - Everything in class 1. - - - Do all the fields that summarize information about the file forks actually - match those forks? - - - Does each inode with zero link count correspond to a record in the free - inode btree? - -6. File fork space mapping records are cross-referenced as follows: - - - Everything in class 1 and 2 above. - - - Is this space not mentioned by the inode btrees? - - - If this is a CoW fork mapping, does it correspond to a CoW entry in the - reference count btree? - -7. Reference count records are cross-referenced as follows: - - - Everything in class 1 and 2 above. - - - Within the space subkeyspace of the rmap btree (that is to say, all - records mapped to a particular space extent and ignoring the owner info), - are there the same number of reverse mapping records for each block as the - reference count record claims? - -Proposed patchsets are the series to find gaps in -`refcount btree -`_, -`inode btree -`_, and -`rmap btree -`_ records; -to find -`mergeable records -`_; -and to -`improve cross referencing with rmap -`_ -before starting a repair. - -Checking Extended Attributes -```````````````````````````` - -Extended attributes implement a key-value store that enable fragments of data -to be attached to any file. -Both the kernel and userspace can access the keys and values, subject to -namespace and privilege restrictions. -Most typically these fragments are metadata about the file -- origins, security -contexts, user-supplied labels, indexing information, etc. - -Names can be as long as 255 bytes and can exist in several different -namespaces. -Values can be as large as 64KB. -A file's extended attributes are stored in blocks mapped by the attr fork. -The mappings point to leaf blocks, remote value blocks, or dabtree blocks. -Block 0 in the attribute fork is always the top of the structure, but otherwise -each of the three types of blocks can be found at any offset in the attr fork. -Leaf blocks contain attribute key records that point to the name and the value. -Names are always stored elsewhere in the same leaf block. -Values that are less than 3/4 the size of a filesystem block are also stored -elsewhere in the same leaf block. -Remote value blocks contain values that are too large to fit inside a leaf. -If the leaf information exceeds a single filesystem block, a dabtree (also -rooted at block 0) is created to map hashes of the attribute names to leaf -blocks in the attr fork. - -Checking an extended attribute structure is not so straightforward due to the -lack of separation between attr blocks and index blocks. -Scrub must read each block mapped by the attr fork and ignore the non-leaf -blocks: - -1. Walk the dabtree in the attr fork (if present) to ensure that there are no - irregularities in the blocks or dabtree mappings that do not point to - attr leaf blocks. - -2. Walk the blocks of the attr fork looking for leaf blocks. - For each entry inside a leaf: - - a. Validate that the name does not contain invalid characters. - - b. Read the attr value. - This performs a named lookup of the attr name to ensure the correctness - of the dabtree. - If the value is stored in a remote block, this also validates the - integrity of the remote value block. - -Checking and Cross-Referencing Directories -`````````````````````````````````````````` - -The filesystem directory tree is a directed acylic graph structure, with files -constituting the nodes, and directory entries (dirents) constituting the edges. -Directories are a special type of file containing a set of mappings from a -255-byte sequence (name) to an inumber. -These are called directory entries, or dirents for short. -Each directory file must have exactly one directory pointing to the file. -A root directory points to itself. -Directory entries point to files of any type. -Each non-directory file may have multiple directories point to it. - -In XFS, directories are implemented as a file containing up to three 32GB -partitions. -The first partition contains directory entry data blocks. -Each data block contains variable-sized records associating a user-provided -name with an inumber and, optionally, a file type. -If the directory entry data grows beyond one block, the second partition (which -exists as post-EOF extents) is populated with a block containing free space -information and an index that maps hashes of the dirent names to directory data -blocks in the first partition. -This makes directory name lookups very fast. -If this second partition grows beyond one block, the third partition is -populated with a linear array of free space information for faster -expansions. -If the free space has been separated and the second partition grows again -beyond one block, then a dabtree is used to map hashes of dirent names to -directory data blocks. - -Checking a directory is pretty straightforward: - -1. Walk the dabtree in the second partition (if present) to ensure that there - are no irregularities in the blocks or dabtree mappings that do not point to - dirent blocks. - -2. Walk the blocks of the first partition looking for directory entries. - Each dirent is checked as follows: - - a. Does the name contain no invalid characters? - - b. Does the inumber correspond to an actual, allocated inode? - - c. Does the child inode have a nonzero link count? - - d. If a file type is included in the dirent, does it match the type of the - inode? - - e. If the child is a subdirectory, does the child's dotdot pointer point - back to the parent? - - f. If the directory has a second partition, perform a named lookup of the - dirent name to ensure the correctness of the dabtree. - -3. Walk the free space list in the third partition (if present) to ensure that - the free spaces it describes are really unused. - -Checking operations involving :ref:`parents ` and -:ref:`file link counts ` are discussed in more detail in later -sections. - -Checking Directory/Attribute Btrees -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -As stated in previous sections, the directory/attribute btree (dabtree) index -maps user-provided names to improve lookup times by avoiding linear scans. -Internally, it maps a 32-bit hash of the name to a block offset within the -appropriate file fork. - -The internal structure of a dabtree closely resembles the btrees that record -fixed-size metadata records -- each dabtree block contains a magic number, a -checksum, sibling pointers, a UUID, a tree level, and a log sequence number. -The format of leaf and node records are the same -- each entry points to the -next level down in the hierarchy, with dabtree node records pointing to dabtree -leaf blocks, and dabtree leaf records pointing to non-dabtree blocks elsewhere -in the fork. - -Checking and cross-referencing the dabtree is very similar to what is done for -space btrees: - -- Does the type of data stored in the block match what scrub is expecting? - -- Does the block belong to the owning structure that asked for the read? - -- Do the records fit within the block? - -- Are the records contained inside the block free of obvious corruptions? - -- Are the name hashes in the correct order? - -- Do node pointers within the dabtree point to valid fork offsets for dabtree - blocks? - -- Do leaf pointers within the dabtree point to valid fork offsets for directory - or attr leaf blocks? - -- Do child pointers point towards the leaves? - -- Do sibling pointers point across the same level? - -- For each dabtree node record, does the record key accurate reflect the - contents of the child dabtree block? - -- For each dabtree leaf record, does the record key accurate reflect the - contents of the directory or attr block? - -Cross-Referencing Summary Counters -`````````````````````````````````` - -XFS maintains three classes of summary counters: available resources, quota -resource usage, and file link counts. - -In theory, the amount of available resources (data blocks, inodes, realtime -extents) can be found by walking the entire filesystem. -This would make for very slow reporting, so a transactional filesystem can -maintain summaries of this information in the superblock. -Cross-referencing these values against the filesystem metadata should be a -simple matter of walking the free space and inode metadata in each AG and the -realtime bitmap, but there are complications that will be discussed in -:ref:`more detail ` later. - -:ref:`Quota usage ` and :ref:`file link count ` -checking are sufficiently complicated to warrant separate sections. - -Post-Repair Reverification -`````````````````````````` - -After performing a repair, the checking code is run a second time to validate -the new structure, and the results of the health assessment are recorded -internally and returned to the calling process. -This step is critical for enabling system administrator to monitor the status -of the filesystem and the progress of any repairs. -For developers, it is a useful means to judge the efficacy of error detection -and correction in the online and offline checking tools. - -Eventual Consistency vs. Online Fsck ------------------------------------- - -Complex operations can make modifications to multiple per-AG data structures -with a chain of transactions. -These chains, once committed to the log, are restarted during log recovery if -the system crashes while processing the chain. -Because the AG header buffers are unlocked between transactions within a chain, -online checking must coordinate with chained operations that are in progress to -avoid incorrectly detecting inconsistencies due to pending chains. -Furthermore, online repair must not run when operations are pending because -the metadata are temporarily inconsistent with each other, and rebuilding is -not possible. - -Only online fsck has this requirement of total consistency of AG metadata, and -should be relatively rare as compared to filesystem change operations. -Online fsck coordinates with transaction chains as follows: - -* For each AG, maintain a count of intent items targeting that AG. - The count should be bumped whenever a new item is added to the chain. - The count should be dropped when the filesystem has locked the AG header - buffers and finished the work. - -* When online fsck wants to examine an AG, it should lock the AG header - buffers to quiesce all transaction chains that want to modify that AG. - If the count is zero, proceed with the checking operation. - If it is nonzero, cycle the buffer locks to allow the chain to make forward - progress. - -This may lead to online fsck taking a long time to complete, but regular -filesystem updates take precedence over background checking activity. -Details about the discovery of this situation are presented in the -:ref:`next section `, and details about the solution -are presented :ref:`after that`. - -.. _chain_coordination: - -Discovery of the Problem -```````````````````````` - -Midway through the development of online scrubbing, the fsstress tests -uncovered a misinteraction between online fsck and compound transaction chains -created by other writer threads that resulted in false reports of metadata -inconsistency. -The root cause of these reports is the eventual consistency model introduced by -the expansion of deferred work items and compound transaction chains when -reverse mapping and reflink were introduced. - -Originally, transaction chains were added to XFS to avoid deadlocks when -unmapping space from files. -Deadlock avoidance rules require that AGs only be locked in increasing order, -which makes it impossible (say) to use a single transaction to free a space -extent in AG 7 and then try to free a now superfluous block mapping btree block -in AG 3. -To avoid these kinds of deadlocks, XFS creates Extent Freeing Intent (EFI) log -items to commit to freeing some space in one transaction while deferring the -actual metadata updates to a fresh transaction. -The transaction sequence looks like this: - -1. The first transaction contains a physical update to the file's block mapping - structures to remove the mapping from the btree blocks. - It then attaches to the in-memory transaction an action item to schedule - deferred freeing of space. - Concretely, each transaction maintains a list of ``struct - xfs_defer_pending`` objects, each of which maintains a list of ``struct - xfs_extent_free_item`` objects. - Returning to the example above, the action item tracks the freeing of both - the unmapped space from AG 7 and the block mapping btree (BMBT) block from - AG 3. - Deferred frees recorded in this manner are committed in the log by creating - an EFI log item from the ``struct xfs_extent_free_item`` object and - attaching the log item to the transaction. - When the log is persisted to disk, the EFI item is written into the ondisk - transaction record. - EFIs can list up to 16 extents to free, all sorted in AG order. - -2. The second transaction contains a physical update to the free space btrees - of AG 3 to release the former BMBT block and a second physical update to the - free space btrees of AG 7 to release the unmapped file space. - Observe that the physical updates are resequenced in the correct order - when possible. - Attached to the transaction is a an extent free done (EFD) log item. - The EFD contains a pointer to the EFI logged in transaction #1 so that log - recovery can tell if the EFI needs to be replayed. - -If the system goes down after transaction #1 is written back to the filesystem -but before #2 is committed, a scan of the filesystem metadata would show -inconsistent filesystem metadata because there would not appear to be any owner -of the unmapped space. -Happily, log recovery corrects this inconsistency for us -- when recovery finds -an intent log item but does not find a corresponding intent done item, it will -reconstruct the incore state of the intent item and finish it. -In the example above, the log must replay both frees described in the recovered -EFI to complete the recovery phase. - -There are subtleties to XFS' transaction chaining strategy to consider: - -* Log items must be added to a transaction in the correct order to prevent - conflicts with principal objects that are not held by the transaction. - In other words, all per-AG metadata updates for an unmapped block must be - completed before the last update to free the extent, and extents should not - be reallocated until that last update commits to the log. - -* AG header buffers are released between each transaction in a chain. - This means that other threads can observe an AG in an intermediate state, - but as long as the first subtlety is handled, this should not affect the - correctness of filesystem operations. - -* Unmounting the filesystem flushes all pending work to disk, which means that - offline fsck never sees the temporary inconsistencies caused by deferred - work item processing. - -In this manner, XFS employs a form of eventual consistency to avoid deadlocks -and increase parallelism. - -During the design phase of the reverse mapping and reflink features, it was -decided that it was impractical to cram all the reverse mapping updates for a -single filesystem change into a single transaction because a single file -mapping operation can explode into many small updates: - -* The block mapping update itself -* A reverse mapping update for the block mapping update -* Fixing the freelist -* A reverse mapping update for the freelist fix - -* A shape change to the block mapping btree -* A reverse mapping update for the btree update -* Fixing the freelist (again) -* A reverse mapping update for the freelist fix - -* An update to the reference counting information -* A reverse mapping update for the refcount update -* Fixing the freelist (a third time) -* A reverse mapping update for the freelist fix - -* Freeing any space that was unmapped and not owned by any other file -* Fixing the freelist (a fourth time) -* A reverse mapping update for the freelist fix - -* Freeing the space used by the block mapping btree -* Fixing the freelist (a fifth time) -* A reverse mapping update for the freelist fix - -Free list fixups are not usually needed more than once per AG per transaction -chain, but it is theoretically possible if space is very tight. -For copy-on-write updates this is even worse, because this must be done once to -remove the space from a staging area and again to map it into the file! - -To deal with this explosion in a calm manner, XFS expands its use of deferred -work items to cover most reverse mapping updates and all refcount updates. -This reduces the worst case size of transaction reservations by breaking the -work into a long chain of small updates, which increases the degree of eventual -consistency in the system. -Again, this generally isn't a problem because XFS orders its deferred work -items carefully to avoid resource reuse conflicts between unsuspecting threads. - -However, online fsck changes the rules -- remember that although physical -updates to per-AG structures are coordinated by locking the buffers for AG -headers, buffer locks are dropped between transactions. -Once scrub acquires resources and takes locks for a data structure, it must do -all the validation work without releasing the lock. -If the main lock for a space btree is an AG header buffer lock, scrub may have -interrupted another thread that is midway through finishing a chain. -For example, if a thread performing a copy-on-write has completed a reverse -mapping update but not the corresponding refcount update, the two AG btrees -will appear inconsistent to scrub and an observation of corruption will be -recorded. This observation will not be correct. -If a repair is attempted in this state, the results will be catastrophic! - -Several other solutions to this problem were evaluated upon discovery of this -flaw and rejected: - -1. Add a higher level lock to allocation groups and require writer threads to - acquire the higher level lock in AG order before making any changes. - This would be very difficult to implement in practice because it is - difficult to determine which locks need to be obtained, and in what order, - without simulating the entire operation. - Performing a dry run of a file operation to discover necessary locks would - make the filesystem very slow. - -2. Make the deferred work coordinator code aware of consecutive intent items - targeting the same AG and have it hold the AG header buffers locked across - the transaction roll between updates. - This would introduce a lot of complexity into the coordinator since it is - only loosely coupled with the actual deferred work items. - It would also fail to solve the problem because deferred work items can - generate new deferred subtasks, but all subtasks must be complete before - work can start on a new sibling task. - -3. Teach online fsck to walk all transactions waiting for whichever lock(s) - protect the data structure being scrubbed to look for pending operations. - The checking and repair operations must factor these pending operations into - the evaluations being performed. - This solution is a nonstarter because it is *extremely* invasive to the main - filesystem. - -.. _intent_drains: - -Intent Drains -````````````` - -Online fsck uses an atomic intent item counter and lock cycling to coordinate -with transaction chains. -There are two key properties to the drain mechanism. -First, the counter is incremented when a deferred work item is *queued* to a -transaction, and it is decremented after the associated intent done log item is -*committed* to another transaction. -The second property is that deferred work can be added to a transaction without -holding an AG header lock, but per-AG work items cannot be marked done without -locking that AG header buffer to log the physical updates and the intent done -log item. -The first property enables scrub to yield to running transaction chains, which -is an explicit deprioritization of online fsck to benefit file operations. -The second property of the drain is key to the correct coordination of scrub, -since scrub will always be able to decide if a conflict is possible. - -For regular filesystem code, the drain works as follows: - -1. Call the appropriate subsystem function to add a deferred work item to a - transaction. - -2. The function calls ``xfs_defer_drain_bump`` to increase the counter. - -3. When the deferred item manager wants to finish the deferred work item, it - calls ``->finish_item`` to complete it. - -4. The ``->finish_item`` implementation logs some changes and calls - ``xfs_defer_drain_drop`` to decrease the sloppy counter and wake up any threads - waiting on the drain. - -5. The subtransaction commits, which unlocks the resource associated with the - intent item. - -For scrub, the drain works as follows: - -1. Lock the resource(s) associated with the metadata being scrubbed. - For example, a scan of the refcount btree would lock the AGI and AGF header - buffers. - -2. If the counter is zero (``xfs_defer_drain_busy`` returns false), there are no - chains in progress and the operation may proceed. - -3. Otherwise, release the resources grabbed in step 1. - -4. Wait for the intent counter to reach zero (``xfs_defer_drain_intents``), then go - back to step 1 unless a signal has been caught. - -To avoid polling in step 4, the drain provides a waitqueue for scrub threads to -be woken up whenever the intent count drops to zero. - -The proposed patchset is the -`scrub intent drain series -`_. - -.. _jump_labels: - -Static Keys (aka Jump Label Patching) -````````````````````````````````````` - -Online fsck for XFS separates the regular filesystem from the checking and -repair code as much as possible. -However, there are a few parts of online fsck (such as the intent drains, and -later, live update hooks) where it is useful for the online fsck code to know -what's going on in the rest of the filesystem. -Since it is not expected that online fsck will be constantly running in the -background, it is very important to minimize the runtime overhead imposed by -these hooks when online fsck is compiled into the kernel but not actively -running on behalf of userspace. -Taking locks in the hot path of a writer thread to access a data structure only -to find that no further action is necessary is expensive -- on the author's -computer, this have an overhead of 40-50ns per access. -Fortunately, the kernel supports dynamic code patching, which enables XFS to -replace a static branch to hook code with ``nop`` sleds when online fsck isn't -running. -This sled has an overhead of however long it takes the instruction decoder to -skip past the sled, which seems to be on the order of less than 1ns and -does not access memory outside of instruction fetching. - -When online fsck enables the static key, the sled is replaced with an -unconditional branch to call the hook code. -The switchover is quite expensive (~22000ns) but is paid entirely by the -program that invoked online fsck, and can be amortized if multiple threads -enter online fsck at the same time, or if multiple filesystems are being -checked at the same time. -Changing the branch direction requires taking the CPU hotplug lock, and since -CPU initialization requires memory allocation, online fsck must be careful not -to change a static key while holding any locks or resources that could be -accessed in the memory reclaim paths. -To minimize contention on the CPU hotplug lock, care should be taken not to -enable or disable static keys unnecessarily. - -Because static keys are intended to minimize hook overhead for regular -filesystem operations when xfs_scrub is not running, the intended usage -patterns are as follows: - -- The hooked part of XFS should declare a static-scoped static key that - defaults to false. - The ``DEFINE_STATIC_KEY_FALSE`` macro takes care of this. - The static key itself should be declared as a ``static`` variable. - -- When deciding to invoke code that's only used by scrub, the regular - filesystem should call the ``static_branch_unlikely`` predicate to avoid the - scrub-only hook code if the static key is not enabled. - -- The regular filesystem should export helper functions that call - ``static_branch_inc`` to enable and ``static_branch_dec`` to disable the - static key. - Wrapper functions make it easy to compile out the relevant code if the kernel - distributor turns off online fsck at build time. - -- Scrub functions wanting to turn on scrub-only XFS functionality should call - the ``xchk_fsgates_enable`` from the setup function to enable a specific - hook. - This must be done before obtaining any resources that are used by memory - reclaim. - Callers had better be sure they really need the functionality gated by the - static key; the ``TRY_HARDER`` flag is useful here. - -Online scrub has resource acquisition helpers (e.g. ``xchk_perag_lock``) to -handle locking AGI and AGF buffers for all scrubber functions. -If it detects a conflict between scrub and the running transactions, it will -try to wait for intents to complete. -If the caller of the helper has not enabled the static key, the helper will -return -EDEADLOCK, which should result in the scrub being restarted with the -``TRY_HARDER`` flag set. -The scrub setup function should detect that flag, enable the static key, and -try the scrub again. -Scrub teardown disables all static keys obtained by ``xchk_fsgates_enable``. - -For more information, please see the kernel documentation of -Documentation/staging/static-keys.rst. - -.. _xfile: - -Pageable Kernel Memory ----------------------- - -Some online checking functions work by scanning the filesystem to build a -shadow copy of an ondisk metadata structure in memory and comparing the two -copies. -For online repair to rebuild a metadata structure, it must compute the record -set that will be stored in the new structure before it can persist that new -structure to disk. -Ideally, repairs complete with a single atomic commit that introduces -a new data structure. -To meet these goals, the kernel needs to collect a large amount of information -in a place that doesn't require the correct operation of the filesystem. - -Kernel memory isn't suitable because: - -* Allocating a contiguous region of memory to create a C array is very - difficult, especially on 32-bit systems. - -* Linked lists of records introduce double pointer overhead which is very high - and eliminate the possibility of indexed lookups. - -* Kernel memory is pinned, which can drive the system into OOM conditions. - -* The system might not have sufficient memory to stage all the information. - -At any given time, online fsck does not need to keep the entire record set in -memory, which means that individual records can be paged out if necessary. -Continued development of online fsck demonstrated that the ability to perform -indexed data storage would also be very useful. -Fortunately, the Linux kernel already has a facility for byte-addressable and -pageable storage: tmpfs. -In-kernel graphics drivers (most notably i915) take advantage of tmpfs files -to store intermediate data that doesn't need to be in memory at all times, so -that usage precedent is already established. -Hence, the ``xfile`` was born! - -+--------------------------------------------------------------------------+ -| **Historical Sidebar**: | -+--------------------------------------------------------------------------+ -| The first edition of online repair inserted records into a new btree as | -| it found them, which failed because filesystem could shut down with a | -| built data structure, which would be live after recovery finished. | -| | -| The second edition solved the half-rebuilt structure problem by storing | -| everything in memory, but frequently ran the system out of memory. | -| | -| The third edition solved the OOM problem by using linked lists, but the | -| memory overhead of the list pointers was extreme. | -+--------------------------------------------------------------------------+ - -xfile Access Models -``````````````````` - -A survey of the intended uses of xfiles suggested these use cases: - -1. Arrays of fixed-sized records (space management btrees, directory and - extended attribute entries) - -2. Sparse arrays of fixed-sized records (quotas and link counts) - -3. Large binary objects (BLOBs) of variable sizes (directory and extended - attribute names and values) - -4. Staging btrees in memory (reverse mapping btrees) - -5. Arbitrary contents (realtime space management) - -To support the first four use cases, high level data structures wrap the xfile -to share functionality between online fsck functions. -The rest of this section discusses the interfaces that the xfile presents to -four of those five higher level data structures. -The fifth use case is discussed in the :ref:`realtime summary ` case -study. - -The most general storage interface supported by the xfile enables the reading -and writing of arbitrary quantities of data at arbitrary offsets in the xfile. -This capability is provided by ``xfile_pread`` and ``xfile_pwrite`` functions, -which behave similarly to their userspace counterparts. -XFS is very record-based, which suggests that the ability to load and store -complete records is important. -To support these cases, a pair of ``xfile_obj_load`` and ``xfile_obj_store`` -functions are provided to read and persist objects into an xfile. -They are internally the same as pread and pwrite, except that they treat any -error as an out of memory error. -For online repair, squashing error conditions in this manner is an acceptable -behavior because the only reaction is to abort the operation back to userspace. -All five xfile usecases can be serviced by these four functions. - -However, no discussion of file access idioms is complete without answering the -question, "But what about mmap?" -It is convenient to access storage directly with pointers, just like userspace -code does with regular memory. -Online fsck must not drive the system into OOM conditions, which means that -xfiles must be responsive to memory reclamation. -tmpfs can only push a pagecache folio to the swap cache if the folio is neither -pinned nor locked, which means the xfile must not pin too many folios. - -Short term direct access to xfile contents is done by locking the pagecache -folio and mapping it into kernel address space. -Programmatic access (e.g. pread and pwrite) uses this mechanism. -Folio locks are not supposed to be held for long periods of time, so long -term direct access to xfile contents is done by bumping the folio refcount, -mapping it into kernel address space, and dropping the folio lock. -These long term users *must* be responsive to memory reclaim by hooking into -the shrinker infrastructure to know when to release folios. - -The ``xfile_get_page`` and ``xfile_put_page`` functions are provided to -retrieve the (locked) folio that backs part of an xfile and to release it. -The only code to use these folio lease functions are the xfarray -:ref:`sorting` algorithms and the :ref:`in-memory -btrees`. - -xfile Access Coordination -````````````````````````` - -For security reasons, xfiles must be owned privately by the kernel. -They are marked ``S_PRIVATE`` to prevent interference from the security system, -must never be mapped into process file descriptor tables, and their pages must -never be mapped into userspace processes. - -To avoid locking recursion issues with the VFS, all accesses to the shmfs file -are performed by manipulating the page cache directly. -xfile writers call the ``->write_begin`` and ``->write_end`` functions of the -xfile's address space to grab writable pages, copy the caller's buffer into the -page, and release the pages. -xfile readers call ``shmem_read_mapping_page_gfp`` to grab pages directly -before copying the contents into the caller's buffer. -In other words, xfiles ignore the VFS read and write code paths to avoid -having to create a dummy ``struct kiocb`` and to avoid taking inode and -freeze locks. -tmpfs cannot be frozen, and xfiles must not be exposed to userspace. - -If an xfile is shared between threads to stage repairs, the caller must provide -its own locks to coordinate access. -For example, if a scrub function stores scan results in an xfile and needs -other threads to provide updates to the scanned data, the scrub function must -provide a lock for all threads to share. - -.. _xfarray: - -Arrays of Fixed-Sized Records -````````````````````````````` - -In XFS, each type of indexed space metadata (free space, inodes, reference -counts, file fork space, and reverse mappings) consists of a set of fixed-size -records indexed with a classic B+ tree. -Directories have a set of fixed-size dirent records that point to the names, -and extended attributes have a set of fixed-size attribute keys that point to -names and values. -Quota counters and file link counters index records with numbers. -During a repair, scrub needs to stage new records during the gathering step and -retrieve them during the btree building step. - -Although this requirement can be satisfied by calling the read and write -methods of the xfile directly, it is simpler for callers for there to be a -higher level abstraction to take care of computing array offsets, to provide -iterator functions, and to deal with sparse records and sorting. -The ``xfarray`` abstraction presents a linear array for fixed-size records atop -the byte-accessible xfile. - -.. _xfarray_access_patterns: - -Array Access Patterns -^^^^^^^^^^^^^^^^^^^^^ - -Array access patterns in online fsck tend to fall into three categories. -Iteration of records is assumed to be necessary for all cases and will be -covered in the next section. - -The first type of caller handles records that are indexed by position. -Gaps may exist between records, and a record may be updated multiple times -during the collection step. -In other words, these callers want a sparse linearly addressed table file. -The typical use case are quota records or file link count records. -Access to array elements is performed programmatically via ``xfarray_load`` and -``xfarray_store`` functions, which wrap the similarly-named xfile functions to -provide loading and storing of array elements at arbitrary array indices. -Gaps are defined to be null records, and null records are defined to be a -sequence of all zero bytes. -Null records are detected by calling ``xfarray_element_is_null``. -They are created either by calling ``xfarray_unset`` to null out an existing -record or by never storing anything to an array index. - -The second type of caller handles records that are not indexed by position -and do not require multiple updates to a record. -The typical use case here is rebuilding space btrees and key/value btrees. -These callers can add records to the array without caring about array indices -via the ``xfarray_append`` function, which stores a record at the end of the -array. -For callers that require records to be presentable in a specific order (e.g. -rebuilding btree data), the ``xfarray_sort`` function can arrange the sorted -records; this function will be covered later. - -The third type of caller is a bag, which is useful for counting records. -The typical use case here is constructing space extent reference counts from -reverse mapping information. -Records can be put in the bag in any order, they can be removed from the bag -at any time, and uniqueness of records is left to callers. -The ``xfarray_store_anywhere`` function is used to insert a record in any -null record slot in the bag; and the ``xfarray_unset`` function removes a -record from the bag. - -The proposed patchset is the -`big in-memory array -`_. - -Iterating Array Elements -^^^^^^^^^^^^^^^^^^^^^^^^ - -Most users of the xfarray require the ability to iterate the records stored in -the array. -Callers can probe every possible array index with the following: - -.. code-block:: c - - xfarray_idx_t i; - foreach_xfarray_idx(array, i) { - xfarray_load(array, i, &rec); - - /* do something with rec */ - } - -All users of this idiom must be prepared to handle null records or must already -know that there aren't any. - -For xfarray users that want to iterate a sparse array, the ``xfarray_iter`` -function ignores indices in the xfarray that have never been written to by -calling ``xfile_seek_data`` (which internally uses ``SEEK_DATA``) to skip areas -of the array that are not populated with memory pages. -Once it finds a page, it will skip the zeroed areas of the page. - -.. code-block:: c - - xfarray_idx_t i = XFARRAY_CURSOR_INIT; - while ((ret = xfarray_iter(array, &i, &rec)) == 1) { - /* do something with rec */ - } - -.. _xfarray_sort: - -Sorting Array Elements -^^^^^^^^^^^^^^^^^^^^^^ - -During the fourth demonstration of online repair, a community reviewer remarked -that for performance reasons, online repair ought to load batches of records -into btree record blocks instead of inserting records into a new btree one at a -time. -The btree insertion code in XFS is responsible for maintaining correct ordering -of the records, so naturally the xfarray must also support sorting the record -set prior to bulk loading. - -Case Study: Sorting xfarrays -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The sorting algorithm used in the xfarray is actually a combination of adaptive -quicksort and a heapsort subalgorithm in the spirit of -`Sedgewick `_ and -`pdqsort `_, with customizations for the Linux -kernel. -To sort records in a reasonably short amount of time, ``xfarray`` takes -advantage of the binary subpartitioning offered by quicksort, but it also uses -heapsort to hedge against performance collapse if the chosen quicksort pivots -are poor. -Both algorithms are (in general) O(n * lg(n)), but there is a wide performance -gulf between the two implementations. - -The Linux kernel already contains a reasonably fast implementation of heapsort. -It only operates on regular C arrays, which limits the scope of its usefulness. -There are two key places where the xfarray uses it: - -* Sorting any record subset backed by a single xfile page. - -* Loading a small number of xfarray records from potentially disparate parts - of the xfarray into a memory buffer, and sorting the buffer. - -In other words, ``xfarray`` uses heapsort to constrain the nested recursion of -quicksort, thereby mitigating quicksort's worst runtime behavior. - -Choosing a quicksort pivot is a tricky business. -A good pivot splits the set to sort in half, leading to the divide and conquer -behavior that is crucial to O(n * lg(n)) performance. -A poor pivot barely splits the subset at all, leading to O(n\ :sup:`2`) -runtime. -The xfarray sort routine tries to avoid picking a bad pivot by sampling nine -records into a memory buffer and using the kernel heapsort to identify the -median of the nine. - -Most modern quicksort implementations employ Tukey's "ninther" to select a -pivot from a classic C array. -Typical ninther implementations pick three unique triads of records, sort each -of the triads, and then sort the middle value of each triad to determine the -ninther value. -As stated previously, however, xfile accesses are not entirely cheap. -It turned out to be much more performant to read the nine elements into a -memory buffer, run the kernel's in-memory heapsort on the buffer, and choose -the 4th element of that buffer as the pivot. -Tukey's ninthers are described in J. W. Tukey, `The ninther, a technique for -low-effort robust (resistant) location in large samples`, in *Contributions to -Survey Sampling and Applied Statistics*, edited by H. David, (Academic Press, -1978), pp. 251–257. - -The partitioning of quicksort is fairly textbook -- rearrange the record -subset around the pivot, then set up the current and next stack frames to -sort with the larger and the smaller halves of the pivot, respectively. -This keeps the stack space requirements to log2(record count). - -As a final performance optimization, the hi and lo scanning phase of quicksort -keeps examined xfile pages mapped in the kernel for as long as possible to -reduce map/unmap cycles. -Surprisingly, this reduces overall sort runtime by nearly half again after -accounting for the application of heapsort directly onto xfile pages. - -.. _xfblob: - -Blob Storage -```````````` - -Extended attributes and directories add an additional requirement for staging -records: arbitrary byte sequences of finite length. -Each directory entry record needs to store entry name, -and each extended attribute needs to store both the attribute name and value. -The names, keys, and values can consume a large amount of memory, so the -``xfblob`` abstraction was created to simplify management of these blobs -atop an xfile. - -Blob arrays provide ``xfblob_load`` and ``xfblob_store`` functions to retrieve -and persist objects. -The store function returns a magic cookie for every object that it persists. -Later, callers provide this cookie to the ``xblob_load`` to recall the object. -The ``xfblob_free`` function frees a specific blob, and the ``xfblob_truncate`` -function frees them all because compaction is not needed. - -The details of repairing directories and extended attributes will be discussed -in a subsequent section about atomic extent swapping. -However, it should be noted that these repair functions only use blob storage -to cache a small number of entries before adding them to a temporary ondisk -file, which is why compaction is not required. - -The proposed patchset is at the start of the -`extended attribute repair -`_ series. - -.. _xfbtree: - -In-Memory B+Trees -````````````````` - -The chapter about :ref:`secondary metadata` mentioned that -checking and repairing of secondary metadata commonly requires coordination -between a live metadata scan of the filesystem and writer threads that are -updating that metadata. -Keeping the scan data up to date requires requires the ability to propagate -metadata updates from the filesystem into the data being collected by the scan. -This *can* be done by appending concurrent updates into a separate log file and -applying them before writing the new metadata to disk, but this leads to -unbounded memory consumption if the rest of the system is very busy. -Another option is to skip the side-log and commit live updates from the -filesystem directly into the scan data, which trades more overhead for a lower -maximum memory requirement. -In both cases, the data structure holding the scan results must support indexed -access to perform well. - -Given that indexed lookups of scan data is required for both strategies, online -fsck employs the second strategy of committing live updates directly into -scan data. -Because xfarrays are not indexed and do not enforce record ordering, they -are not suitable for this task. -Conveniently, however, XFS has a library to create and maintain ordered reverse -mapping records: the existing rmap btree code! -If only there was a means to create one in memory. - -Recall that the :ref:`xfile ` abstraction represents memory pages as a -regular file, which means that the kernel can create byte or block addressable -virtual address spaces at will. -The XFS buffer cache specializes in abstracting IO to block-oriented address -spaces, which means that adaptation of the buffer cache to interface with -xfiles enables reuse of the entire btree library. -Btrees built atop an xfile are collectively known as ``xfbtrees``. -The next few sections describe how they actually work. - -The proposed patchset is the -`in-memory btree -`_ -series. - -Using xfiles as a Buffer Cache Target -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Two modifications are necessary to support xfiles as a buffer cache target. -The first is to make it possible for the ``struct xfs_buftarg`` structure to -host the ``struct xfs_buf`` rhashtable, because normally those are held by a -per-AG structure. -The second change is to modify the buffer ``ioapply`` function to "read" cached -pages from the xfile and "write" cached pages back to the xfile. -Multiple access to individual buffers is controlled by the ``xfs_buf`` lock, -since the xfile does not provide any locking on its own. -With this adaptation in place, users of the xfile-backed buffer cache use -exactly the same APIs as users of the disk-backed buffer cache. -The separation between xfile and buffer cache implies higher memory usage since -they do not share pages, but this property could some day enable transactional -updates to an in-memory btree. -Today, however, it simply eliminates the need for new code. - -Space Management with an xfbtree -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Space management for an xfile is very simple -- each btree block is one memory -page in size. -These blocks use the same header format as an on-disk btree, but the in-memory -block verifiers ignore the checksums, assuming that xfile memory is no more -corruption-prone than regular DRAM. -Reusing existing code here is more important than absolute memory efficiency. - -The very first block of an xfile backing an xfbtree contains a header block. -The header describes the owner, height, and the block number of the root -xfbtree block. - -To allocate a btree block, use ``xfile_seek_data`` to find a gap in the file. -If there are no gaps, create one by extending the length of the xfile. -Preallocate space for the block with ``xfile_prealloc``, and hand back the -location. -To free an xfbtree block, use ``xfile_discard`` (which internally uses -``FALLOC_FL_PUNCH_HOLE``) to remove the memory page from the xfile. - -Populating an xfbtree -^^^^^^^^^^^^^^^^^^^^^ - -An online fsck function that wants to create an xfbtree should proceed as -follows: - -1. Call ``xfile_create`` to create an xfile. - -2. Call ``xfs_alloc_memory_buftarg`` to create a buffer cache target structure - pointing to the xfile. - -3. Pass the buffer cache target, buffer ops, and other information to - ``xfbtree_create`` to write an initial tree header and root block to the - xfile. - Each btree type should define a wrapper that passes necessary arguments to - the creation function. - For example, rmap btrees define ``xfs_rmapbt_mem_create`` to take care of - all the necessary details for callers. - A ``struct xfbtree`` object will be returned. - -4. Pass the xfbtree object to the btree cursor creation function for the - btree type. - Following the example above, ``xfs_rmapbt_mem_cursor`` takes care of this - for callers. - -5. Pass the btree cursor to the regular btree functions to make queries against - and to update the in-memory btree. - For example, a btree cursor for an rmap xfbtree can be passed to the - ``xfs_rmap_*`` functions just like any other btree cursor. - See the :ref:`next section` for information on dealing with - xfbtree updates that are logged to a transaction. - -6. When finished, delete the btree cursor, destroy the xfbtree object, free the - buffer target, and the destroy the xfile to release all resources. - -.. _xfbtree_commit: - -Committing Logged xfbtree Buffers -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Although it is a clever hack to reuse the rmap btree code to handle the staging -structure, the ephemeral nature of the in-memory btree block storage presents -some challenges of its own. -The XFS transaction manager must not commit buffer log items for buffers backed -by an xfile because the log format does not understand updates for devices -other than the data device. -An ephemeral xfbtree probably will not exist by the time the AIL checkpoints -log transactions back into the filesystem, and certainly won't exist during -log recovery. -For these reasons, any code updating an xfbtree in transaction context must -remove the buffer log items from the transaction and write the updates into the -backing xfile before committing or cancelling the transaction. - -The ``xfbtree_trans_commit`` and ``xfbtree_trans_cancel`` functions implement -this functionality as follows: - -1. Find each buffer log item whose buffer targets the xfile. - -2. Record the dirty/ordered status of the log item. - -3. Detach the log item from the buffer. - -4. Queue the buffer to a special delwri list. - -5. Clear the transaction dirty flag if the only dirty log items were the ones - that were detached in step 3. - -6. Submit the delwri list to commit the changes to the xfile, if the updates - are being committed. - -After removing xfile logged buffers from the transaction in this manner, the -transaction can be committed or cancelled. - -Bulk Loading of Ondisk B+Trees ------------------------------- - -As mentioned previously, early iterations of online repair built new btree -structures by creating a new btree and adding observations individually. -Loading a btree one record at a time had a slight advantage of not requiring -the incore records to be sorted prior to commit, but was very slow and leaked -blocks if the system went down during a repair. -Loading records one at a time also meant that repair could not control the -loading factor of the blocks in the new btree. - -Fortunately, the venerable ``xfs_repair`` tool had a more efficient means for -rebuilding a btree index from a collection of records -- bulk btree loading. -This was implemented rather inefficiently code-wise, since ``xfs_repair`` -had separate copy-pasted implementations for each btree type. - -To prepare for online fsck, each of the four bulk loaders were studied, notes -were taken, and the four were refactored into a single generic btree bulk -loading mechanism. -Those notes in turn have been refreshed and are presented below. - -Geometry Computation -```````````````````` - -The zeroth step of bulk loading is to assemble the entire record set that will -be stored in the new btree, and sort the records. -Next, call ``xfs_btree_bload_compute_geometry`` to compute the shape of the -btree from the record set, the type of btree, and any load factor preferences. -This information is required for resource reservation. - -First, the geometry computation computes the minimum and maximum records that -will fit in a leaf block from the size of a btree block and the size of the -block header. -Roughly speaking, the maximum number of records is:: - - maxrecs = (block_size - header_size) / record_size - -The XFS design specifies that btree blocks should be merged when possible, -which means the minimum number of records is half of maxrecs:: - - minrecs = maxrecs / 2 - -The next variable to determine is the desired loading factor. -This must be at least minrecs and no more than maxrecs. -Choosing minrecs is undesirable because it wastes half the block. -Choosing maxrecs is also undesirable because adding a single record to each -newly rebuilt leaf block will cause a tree split, which causes a noticeable -drop in performance immediately afterwards. -The default loading factor was chosen to be 75% of maxrecs, which provides a -reasonably compact structure without any immediate split penalties:: - - default_load_factor = (maxrecs + minrecs) / 2 - -If space is tight, the loading factor will be set to maxrecs to try to avoid -running out of space:: - - leaf_load_factor = enough space ? default_load_factor : maxrecs - -Load factor is computed for btree node blocks using the combined size of the -btree key and pointer as the record size:: - - maxrecs = (block_size - header_size) / (key_size + ptr_size) - minrecs = maxrecs / 2 - node_load_factor = enough space ? default_load_factor : maxrecs - -Once that's done, the number of leaf blocks required to store the record set -can be computed as:: - - leaf_blocks = ceil(record_count / leaf_load_factor) - -The number of node blocks needed to point to the next level down in the tree -is computed as:: - - n_blocks = (n == 0 ? leaf_blocks : node_blocks[n]) - node_blocks[n + 1] = ceil(n_blocks / node_load_factor) - -The entire computation is performed recursively until the current level only -needs one block. -The resulting geometry is as follows: - -- For AG-rooted btrees, this level is the root level, so the height of the new - tree is ``level + 1`` and the space needed is the summation of the number of - blocks on each level. - -- For inode-rooted btrees where the records in the top level do not fit in the - inode fork area, the height is ``level + 2``, the space needed is the - summation of the number of blocks on each level, and the inode fork points to - the root block. - -- For inode-rooted btrees where the records in the top level can be stored in - the inode fork area, then the root block can be stored in the inode, the - height is ``level + 1``, and the space needed is one less than the summation - of the number of blocks on each level. - This only becomes relevant when non-bmap btrees gain the ability to root in - an inode, which is a future patchset and only included here for completeness. - -.. _newbt: - -Reserving New B+Tree Blocks -``````````````````````````` - -Once repair knows the number of blocks needed for the new btree, it allocates -those blocks using the free space information. -Each reserved extent is tracked separately by the btree builder state data. -To improve crash resilience, the reservation code also logs an Extent Freeing -Intent (EFI) item in the same transaction as each space allocation and attaches -its in-memory ``struct xfs_extent_free_item`` object to the space reservation. -If the system goes down, log recovery will use the unfinished EFIs to free the -unused space, the free space, leaving the filesystem unchanged. - -Each time the btree builder claims a block for the btree from a reserved -extent, it updates the in-memory reservation to reflect the claimed space. -Block reservation tries to allocate as much contiguous space as possible to -reduce the number of EFIs in play. - -While repair is writing these new btree blocks, the EFIs created for the space -reservations pin the tail of the ondisk log. -It's possible that other parts of the system will remain busy and push the head -of the log towards the pinned tail. -To avoid livelocking the filesystem, the EFIs must not pin the tail of the log -for too long. -To alleviate this problem, the dynamic relogging capability of the deferred ops -mechanism is reused here to commit a transaction at the log head containing an -EFD for the old EFI and new EFI at the head. -This enables the log to release the old EFI to keep the log moving forwards. - -EFIs have a role to play during the commit and reaping phases; please see the -next section and the section about :ref:`reaping` for more details. - -Proposed patchsets are the -`bitmap rework -`_ -and the -`preparation for bulk loading btrees -`_. - - -Writing the New Tree -```````````````````` - -This part is pretty simple -- the btree builder (``xfs_btree_bulkload``) claims -a block from the reserved list, writes the new btree block header, fills the -rest of the block with records, and adds the new leaf block to a list of -written blocks:: - - ┌────┐ - │leaf│ - │RRR │ - └────┘ - -Sibling pointers are set every time a new block is added to the level:: - - ┌────┐ ┌────┐ ┌────┐ ┌────┐ - │leaf│→│leaf│→│leaf│→│leaf│ - │RRR │←│RRR │←│RRR │←│RRR │ - └────┘ └────┘ └────┘ └────┘ - -When it finishes writing the record leaf blocks, it moves on to the node -blocks -To fill a node block, it walks each block in the next level down in the tree -to compute the relevant keys and write them into the parent node:: - - ┌────┐ ┌────┐ - │node│──────→│node│ - │PP │←──────│PP │ - └────┘ └────┘ - ↙ ↘ ↙ ↘ - ┌────┐ ┌────┐ ┌────┐ ┌────┐ - │leaf│→│leaf│→│leaf│→│leaf│ - │RRR │←│RRR │←│RRR │←│RRR │ - └────┘ └────┘ └────┘ └────┘ - -When it reaches the root level, it is ready to commit the new btree!:: - - ┌─────────┐ - │ root │ - │ PP │ - └─────────┘ - ↙ ↘ - ┌────┐ ┌────┐ - │node│──────→│node│ - │PP │←──────│PP │ - └────┘ └────┘ - ↙ ↘ ↙ ↘ - ┌────┐ ┌────┐ ┌────┐ ┌────┐ - │leaf│→│leaf│→│leaf│→│leaf│ - │RRR │←│RRR │←│RRR │←│RRR │ - └────┘ └────┘ └────┘ └────┘ - -The first step to commit the new btree is to persist the btree blocks to disk -synchronously. -This is a little complicated because a new btree block could have been freed -in the recent past, so the builder must use ``xfs_buf_delwri_queue_here`` to -remove the (stale) buffer from the AIL list before it can write the new blocks -to disk. -Blocks are queued for IO using a delwri list and written in one large batch -with ``xfs_buf_delwri_submit``. - -Once the new blocks have been persisted to disk, control returns to the -individual repair function that called the bulk loader. -The repair function must log the location of the new root in a transaction, -clean up the space reservations that were made for the new btree, and reap the -old metadata blocks: - -1. Commit the location of the new btree root. - -2. For each incore reservation: - - a. Log Extent Freeing Done (EFD) items for all the space that was consumed - by the btree builder. The new EFDs must point to the EFIs attached to - the reservation to prevent log recovery from freeing the new blocks. - - b. For unclaimed portions of incore reservations, create a regular deferred - extent free work item to be free the unused space later in the - transaction chain. - - c. The EFDs and EFIs logged in steps 2a and 2b must not overrun the - reservation of the committing transaction. - If the btree loading code suspects this might be about to happen, it must - call ``xrep_defer_finish`` to clear out the deferred work and obtain a - fresh transaction. - -3. Clear out the deferred work a second time to finish the commit and clean - the repair transaction. - -The transaction rolling in steps 2c and 3 represent a weakness in the repair -algorithm, because a log flush and a crash before the end of the reap step can -result in space leaking. -Online repair functions minimize the chances of this occurring by using very -large transactions, which each can accommodate many thousands of block freeing -instructions. -Repair moves on to reaping the old blocks, which will be presented in a -subsequent :ref:`section` after a few case studies of bulk loading. - -Case Study: Rebuilding the Inode Index -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The high level process to rebuild the inode index btree is: - -1. Walk the reverse mapping records to generate ``struct xfs_inobt_rec`` - records from the inode chunk information and a bitmap of the old inode btree - blocks. - -2. Append the records to an xfarray in inode order. - -3. Use the ``xfs_btree_bload_compute_geometry`` function to compute the number - of blocks needed for the inode btree. - If the free space inode btree is enabled, call it again to estimate the - geometry of the finobt. - -4. Allocate the number of blocks computed in the previous step. - -5. Use ``xfs_btree_bload`` to write the xfarray records to btree blocks and - generate the internal node blocks. - If the free space inode btree is enabled, call it again to load the finobt. - -6. Commit the location of the new btree root block(s) to the AGI. - -7. Reap the old btree blocks using the bitmap created in step 1. - -Details are as follows. - -The inode btree maps inumbers to the ondisk location of the associated -inode records, which means that the inode btrees can be rebuilt from the -reverse mapping information. -Reverse mapping records with an owner of ``XFS_RMAP_OWN_INOBT`` marks the -location of the old inode btree blocks. -Each reverse mapping record with an owner of ``XFS_RMAP_OWN_INODES`` marks the -location of at least one inode cluster buffer. -A cluster is the smallest number of ondisk inodes that can be allocated or -freed in a single transaction; it is never smaller than 1 fs block or 4 inodes. - -For the space represented by each inode cluster, ensure that there are no -records in the free space btrees nor any records in the reference count btree. -If there are, the space metadata inconsistencies are reason enough to abort the -operation. -Otherwise, read each cluster buffer to check that its contents appear to be -ondisk inodes and to decide if the file is allocated -(``xfs_dinode.i_mode != 0``) or free (``xfs_dinode.i_mode == 0``). -Accumulate the results of successive inode cluster buffer reads until there is -enough information to fill a single inode chunk record, which is 64 consecutive -numbers in the inumber keyspace. -If the chunk is sparse, the chunk record may include holes. - -Once the repair function accumulates one chunk's worth of data, it calls -``xfarray_append`` to add the inode btree record to the xfarray. -This xfarray is walked twice during the btree creation step -- once to populate -the inode btree with all inode chunk records, and a second time to populate the -free inode btree with records for chunks that have free non-sparse inodes. -The number of records for the inode btree is the number of xfarray records, -but the record count for the free inode btree has to be computed as inode chunk -records are stored in the xfarray. - -The proposed patchset is the -`AG btree repair -`_ -series. - -Case Study: Rebuilding the Space Reference Counts -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Reverse mapping records are used to rebuild the reference count information. -Reference counts are required for correct operation of copy on write for shared -file data. -Imagine the reverse mapping entries as rectangles representing extents of -physical blocks, and that the rectangles can be laid down to allow them to -overlap each other. -From the diagram below, it is apparent that a reference count record must start -or end wherever the height of the stack changes. -In other words, the record emission stimulus is level-triggered:: - - █ ███ - ██ █████ ████ ███ ██████ - ██ ████ ███████████ ████ █████████ - ████████████████████████████████ ███████████ - ^ ^ ^^ ^^ ^ ^^ ^^^ ^^^^ ^ ^^ ^ ^ ^ - 2 1 23 21 3 43 234 2123 1 01 2 3 0 - -The ondisk reference count btree does not store the refcount == 0 cases because -the free space btree already records which blocks are free. -Extents being used to stage copy-on-write operations should be the only records -with refcount == 1. -Single-owner file blocks aren't recorded in either the free space or the -reference count btrees. - -The high level process to rebuild the reference count btree is: - -1. Walk the reverse mapping records to generate ``struct xfs_refcount_irec`` - records for any space having more than one reverse mapping and add them to - the xfarray. - Any records owned by ``XFS_RMAP_OWN_COW`` are also added to the xfarray - because these are extents allocated to stage a copy on write operation and - are tracked in the refcount btree. - - Use any records owned by ``XFS_RMAP_OWN_REFC`` to create a bitmap of old - refcount btree blocks. - -2. Sort the records in physical extent order, putting the CoW staging extents - at the end of the xfarray. - This matches the sorting order of records in the refcount btree. - -3. Use the ``xfs_btree_bload_compute_geometry`` function to compute the number - of blocks needed for the new tree. - -4. Allocate the number of blocks computed in the previous step. - -5. Use ``xfs_btree_bload`` to write the xfarray records to btree blocks and - generate the internal node blocks. - -6. Commit the location of new btree root block to the AGF. - -7. Reap the old btree blocks using the bitmap created in step 1. - -Details are as follows; the same algorithm is used by ``xfs_repair`` to -generate refcount information from reverse mapping records. - -- Until the reverse mapping btree runs out of records: - - - Retrieve the next record from the btree and put it in a bag. - - - Collect all records with the same starting block from the btree and put - them in the bag. - - - While the bag isn't empty: - - - Among the mappings in the bag, compute the lowest block number where the - reference count changes. - This position will be either the starting block number of the next - unprocessed reverse mapping or the next block after the shortest mapping - in the bag. - - - Remove all mappings from the bag that end at this position. - - - Collect all reverse mappings that start at this position from the btree - and put them in the bag. - - - If the size of the bag changed and is greater than one, create a new - refcount record associating the block number range that we just walked to - the size of the bag. - -The bag-like structure in this case is a type 2 xfarray as discussed in the -:ref:`xfarray access patterns` section. -Reverse mappings are added to the bag using ``xfarray_store_anywhere`` and -removed via ``xfarray_unset``. -Bag members are examined through ``xfarray_iter`` loops. - -The proposed patchset is the -`AG btree repair -`_ -series. - -Case Study: Rebuilding File Fork Mapping Indices -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The high level process to rebuild a data/attr fork mapping btree is: - -1. Walk the reverse mapping records to generate ``struct xfs_bmbt_rec`` - records from the reverse mapping records for that inode and fork. - Append these records to an xfarray. - Compute the bitmap of the old bmap btree blocks from the ``BMBT_BLOCK`` - records. - -2. Use the ``xfs_btree_bload_compute_geometry`` function to compute the number - of blocks needed for the new tree. - -3. Sort the records in file offset order. - -4. If the extent records would fit in the inode fork immediate area, commit the - records to that immediate area and skip to step 8. - -5. Allocate the number of blocks computed in the previous step. - -6. Use ``xfs_btree_bload`` to write the xfarray records to btree blocks and - generate the internal node blocks. - -7. Commit the new btree root block to the inode fork immediate area. - -8. Reap the old btree blocks using the bitmap created in step 1. - -There are some complications here: -First, it's possible to move the fork offset to adjust the sizes of the -immediate areas if the data and attr forks are not both in BMBT format. -Second, if there are sufficiently few fork mappings, it may be possible to use -EXTENTS format instead of BMBT, which may require a conversion. -Third, the incore extent map must be reloaded carefully to avoid disturbing -any delayed allocation extents. - -The proposed patchset is the -`file mapping repair -`_ -series. - -.. _reaping: - -Reaping Old Metadata Blocks ---------------------------- - -Whenever online fsck builds a new data structure to replace one that is -suspect, there is a question of how to find and dispose of the blocks that -belonged to the old structure. -The laziest method of course is not to deal with them at all, but this slowly -leads to service degradations as space leaks out of the filesystem. -Hopefully, someone will schedule a rebuild of the free space information to -plug all those leaks. -Offline repair rebuilds all space metadata after recording the usage of -the files and directories that it decides not to clear, hence it can build new -structures in the discovered free space and avoid the question of reaping. - -As part of a repair, online fsck relies heavily on the reverse mapping records -to find space that is owned by the corresponding rmap owner yet truly free. -Cross referencing rmap records with other rmap records is necessary because -there may be other data structures that also think they own some of those -blocks (e.g. crosslinked trees). -Permitting the block allocator to hand them out again will not push the system -towards consistency. - -For space metadata, the process of finding extents to dispose of generally -follows this format: - -1. Create a bitmap of space used by data structures that must be preserved. - The space reservations used to create the new metadata can be used here if - the same rmap owner code is used to denote all of the objects being rebuilt. - -2. Survey the reverse mapping data to create a bitmap of space owned by the - same ``XFS_RMAP_OWN_*`` number for the metadata that is being preserved. - -3. Use the bitmap disunion operator to subtract (1) from (2). - The remaining set bits represent candidate extents that could be freed. - The process moves on to step 4 below. - -Repairs for file-based metadata such as extended attributes, directories, -symbolic links, quota files and realtime bitmaps are performed by building a -new structure attached to a temporary file and swapping the forks. -Afterward, the mappings in the old file fork are the candidate blocks for -disposal. - -The process for disposing of old extents is as follows: - -4. For each candidate extent, count the number of reverse mapping records for - the first block in that extent that do not have the same rmap owner for the - data structure being repaired. - - - If zero, the block has a single owner and can be freed. - - - If not, the block is part of a crosslinked structure and must not be - freed. - -5. Starting with the next block in the extent, figure out how many more blocks - have the same zero/nonzero other owner status as that first block. - -6. If the region is crosslinked, delete the reverse mapping entry for the - structure being repaired and move on to the next region. - -7. If the region is to be freed, mark any corresponding buffers in the buffer - cache as stale to prevent log writeback. - -8. Free the region and move on. - -However, there is one complication to this procedure. -Transactions are of finite size, so the reaping process must be careful to roll -the transactions to avoid overruns. -Overruns come from two sources: - -a. EFIs logged on behalf of space that is no longer occupied - -b. Log items for buffer invalidations - -This is also a window in which a crash during the reaping process can leak -blocks. -As stated earlier, online repair functions use very large transactions to -minimize the chances of this occurring. - -The proposed patchset is the -`preparation for bulk loading btrees -`_ -series. - -Case Study: Reaping After a Regular Btree Repair -```````````````````````````````````````````````` - -Old reference count and inode btrees are the easiest to reap because they have -rmap records with special owner codes: ``XFS_RMAP_OWN_REFC`` for the refcount -btree, and ``XFS_RMAP_OWN_INOBT`` for the inode and free inode btrees. -Creating a list of extents to reap the old btree blocks is quite simple, -conceptually: - -1. Lock the relevant AGI/AGF header buffers to prevent allocation and frees. - -2. For each reverse mapping record with an rmap owner corresponding to the - metadata structure being rebuilt, set the corresponding range in a bitmap. - -3. Walk the current data structures that have the same rmap owner. - For each block visited, clear that range in the above bitmap. - -4. Each set bit in the bitmap represents a block that could be a block from the - old data structures and hence is a candidate for reaping. - In other words, ``(rmap_records_owned_by & ~blocks_reachable_by_walk)`` - are the blocks that might be freeable. - -If it is possible to maintain the AGF lock throughout the repair (which is the -common case), then step 2 can be performed at the same time as the reverse -mapping record walk that creates the records for the new btree. - -Case Study: Rebuilding the Free Space Indices -````````````````````````````````````````````` - -The high level process to rebuild the free space indices is: - -1. Walk the reverse mapping records to generate ``struct xfs_alloc_rec_incore`` - records from the gaps in the reverse mapping btree. - -2. Append the records to an xfarray. - -3. Use the ``xfs_btree_bload_compute_geometry`` function to compute the number - of blocks needed for each new tree. - -4. Allocate the number of blocks computed in the previous step from the free - space information collected. - -5. Use ``xfs_btree_bload`` to write the xfarray records to btree blocks and - generate the internal node blocks for the free space by length index. - Call it again for the free space by block number index. - -6. Commit the locations of the new btree root blocks to the AGF. - -7. Reap the old btree blocks by looking for space that is not recorded by the - reverse mapping btree, the new free space btrees, or the AGFL. - -Repairing the free space btrees has three key complications over a regular -btree repair: - -First, free space is not explicitly tracked in the reverse mapping records. -Hence, the new free space records must be inferred from gaps in the physical -space component of the keyspace of the reverse mapping btree. - -Second, free space repairs cannot use the common btree reservation code because -new blocks are reserved out of the free space btrees. -This is impossible when repairing the free space btrees themselves. -However, repair holds the AGF buffer lock for the duration of the free space -index reconstruction, so it can use the collected free space information to -supply the blocks for the new free space btrees. -It is not necessary to back each reserved extent with an EFI because the new -free space btrees are constructed in what the ondisk filesystem thinks is -unowned space. -However, if reserving blocks for the new btrees from the collected free space -information changes the number of free space records, repair must re-estimate -the new free space btree geometry with the new record count until the -reservation is sufficient. -As part of committing the new btrees, repair must ensure that reverse mappings -are created for the reserved blocks and that unused reserved blocks are -inserted into the free space btrees. -Deferrred rmap and freeing operations are used to ensure that this transition -is atomic, similar to the other btree repair functions. - -Third, finding the blocks to reap after the repair is not overly -straightforward. -Blocks for the free space btrees and the reverse mapping btrees are supplied by -the AGFL. -Blocks put onto the AGFL have reverse mapping records with the owner -``XFS_RMAP_OWN_AG``. -This ownership is retained when blocks move from the AGFL into the free space -btrees or the reverse mapping btrees. -When repair walks reverse mapping records to synthesize free space records, it -creates a bitmap (``ag_owner_bitmap``) of all the space claimed by -``XFS_RMAP_OWN_AG`` records. -The repair context maintains a second bitmap corresponding to the rmap btree -blocks and the AGFL blocks (``rmap_agfl_bitmap``). -When the walk is complete, the bitmap disunion operation ``(ag_owner_bitmap & -~rmap_agfl_bitmap)`` computes the extents that are used by the old free space -btrees. -These blocks can then be reaped using the methods outlined above. - -The proposed patchset is the -`AG btree repair -`_ -series. - -.. _rmap_reap: - -Case Study: Reaping After Repairing Reverse Mapping Btrees -`````````````````````````````````````````````````````````` - -Old reverse mapping btrees are less difficult to reap after a repair. -As mentioned in the previous section, blocks on the AGFL, the two free space -btree blocks, and the reverse mapping btree blocks all have reverse mapping -records with ``XFS_RMAP_OWN_AG`` as the owner. -The full process of gathering reverse mapping records and building a new btree -are described in the case study of -:ref:`live rebuilds of rmap data `, but a crucial point from that -discussion is that the new rmap btree will not contain any records for the old -rmap btree, nor will the old btree blocks be tracked in the free space btrees. -The list of candidate reaping blocks is computed by setting the bits -corresponding to the gaps in the new rmap btree records, and then clearing the -bits corresponding to extents in the free space btrees and the current AGFL -blocks. -The result ``(new_rmapbt_gaps & ~(agfl | bnobt_records))`` are reaped using the -methods outlined above. - -The rest of the process of rebuildng the reverse mapping btree is discussed -in a separate :ref:`case study`. - -The proposed patchset is the -`AG btree repair -`_ -series. - -Case Study: Rebuilding the AGFL -``````````````````````````````` - -The allocation group free block list (AGFL) is repaired as follows: - -1. Create a bitmap for all the space that the reverse mapping data claims is - owned by ``XFS_RMAP_OWN_AG``. - -2. Subtract the space used by the two free space btrees and the rmap btree. - -3. Subtract any space that the reverse mapping data claims is owned by any - other owner, to avoid re-adding crosslinked blocks to the AGFL. - -4. Once the AGFL is full, reap any blocks leftover. - -5. The next operation to fix the freelist will right-size the list. - -See `fs/xfs/scrub/agheader_repair.c `_ for more details. - -Inode Record Repairs --------------------- - -Inode records must be handled carefully, because they have both ondisk records -("dinodes") and an in-memory ("cached") representation. -There is a very high potential for cache coherency issues if online fsck is not -careful to access the ondisk metadata *only* when the ondisk metadata is so -badly damaged that the filesystem cannot load the in-memory representation. -When online fsck wants to open a damaged file for scrubbing, it must use -specialized resource acquisition functions that return either the in-memory -representation *or* a lock on whichever object is necessary to prevent any -update to the ondisk location. - -The only repairs that should be made to the ondisk inode buffers are whatever -is necessary to get the in-core structure loaded. -This means fixing whatever is caught by the inode cluster buffer and inode fork -verifiers, and retrying the ``iget`` operation. -If the second ``iget`` fails, the repair has failed. - -Once the in-memory representation is loaded, repair can lock the inode and can -subject it to comprehensive checks, repairs, and optimizations. -Most inode attributes are easy to check and constrain, or are user-controlled -arbitrary bit patterns; these are both easy to fix. -Dealing with the data and attr fork extent counts and the file block counts is -more complicated, because computing the correct value requires traversing the -forks, or if that fails, leaving the fields invalid and waiting for the fork -fsck functions to run. - -The proposed patchset is the -`inode -`_ -repair series. - -Quota Record Repairs --------------------- - -Similar to inodes, quota records ("dquots") also have both ondisk records and -an in-memory representation, and hence are subject to the same cache coherency -issues. -Somewhat confusingly, both are known as dquots in the XFS codebase. - -The only repairs that should be made to the ondisk quota record buffers are -whatever is necessary to get the in-core structure loaded. -Once the in-memory representation is loaded, the only attributes needing -checking are obviously bad limits and timer values. - -Quota usage counters are checked, repaired, and discussed separately in the -section about :ref:`live quotacheck `. - -The proposed patchset is the -`quota -`_ -repair series. - -.. _fscounters: - -Freezing to Fix Summary Counters --------------------------------- - -Filesystem summary counters track availability of filesystem resources such -as free blocks, free inodes, and allocated inodes. -This information could be compiled by walking the free space and inode indexes, -but this is a slow process, so XFS maintains a copy in the ondisk superblock -that should reflect the ondisk metadata, at least when the filesystem has been -unmounted cleanly. -For performance reasons, XFS also maintains incore copies of those counters, -which are key to enabling resource reservations for active transactions. -Writer threads reserve the worst-case quantities of resources from the -incore counter and give back whatever they don't use at commit time. -It is therefore only necessary to serialize on the superblock when the -superblock is being committed to disk. - -The lazy superblock counter feature introduced in XFS v5 took this even further -by training log recovery to recompute the summary counters from the AG headers, -which eliminated the need for most transactions even to touch the superblock. -The only time XFS commits the summary counters is at filesystem unmount. -To reduce contention even further, the incore counter is implemented as a -percpu counter, which means that each CPU is allocated a batch of blocks from a -global incore counter and can satisfy small allocations from the local batch. - -The high-performance nature of the summary counters makes it difficult for -online fsck to check them, since there is no way to quiesce a percpu counter -while the system is running. -Although online fsck can read the filesystem metadata to compute the correct -values of the summary counters, there's no way to hold the value of a percpu -counter stable, so it's quite possible that the counter will be out of date by -the time the walk is complete. -Earlier versions of online scrub would return to userspace with an incomplete -scan flag, but this is not a satisfying outcome for a system administrator. -For repairs, the in-memory counters must be stabilized while walking the -filesystem metadata to get an accurate reading and install it in the percpu -counter. - -To satisfy this requirement, online fsck must prevent other programs in the -system from initiating new writes to the filesystem, it must disable background -garbage collection threads, and it must wait for existing writer programs to -exit the kernel. -Once that has been established, scrub can walk the AG free space indexes, the -inode btrees, and the realtime bitmap to compute the correct value of all -four summary counters. -This is very similar to a filesystem freeze, though not all of the pieces are -necessary: - -- The final freeze state is set one higher than ``SB_FREEZE_COMPLETE`` to - prevent other threads from thawing the filesystem, or other scrub threads - from initiating another fscounters freeze. - -- It does not quiesce the log. - -With this code in place, it is now possible to pause the filesystem for just -long enough to check and correct the summary counters. - -+--------------------------------------------------------------------------+ -| **Historical Sidebar**: | -+--------------------------------------------------------------------------+ -| The initial implementation used the actual VFS filesystem freeze | -| mechanism to quiesce filesystem activity. | -| With the filesystem frozen, it is possible to resolve the counter values | -| with exact precision, but there are many problems with calling the VFS | -| methods directly: | -| | -| - Other programs can unfreeze the filesystem without our knowledge. | -| This leads to incorrect scan results and incorrect repairs. | -| | -| - Adding an extra lock to prevent others from thawing the filesystem | -| required the addition of a ``->freeze_super`` function to wrap | -| ``freeze_fs()``. | -| This in turn caused other subtle problems because it turns out that | -| the VFS ``freeze_super`` and ``thaw_super`` functions can drop the | -| last reference to the VFS superblock, and any subsequent access | -| becomes a UAF bug! | -| This can happen if the filesystem is unmounted while the underlying | -| block device has frozen the filesystem. | -| This problem could be solved by grabbing extra references to the | -| superblock, but it felt suboptimal given the other inadequacies of | -| this approach. | -| | -| - The log need not be quiesced to check the summary counters, but a VFS | -| freeze initiates one anyway. | -| This adds unnecessary runtime to live fscounter fsck operations. | -| | -| - Quiescing the log means that XFS flushes the (possibly incorrect) | -| counters to disk as part of cleaning the log. | -| | -| - A bug in the VFS meant that freeze could complete even when | -| sync_filesystem fails to flush the filesystem and returns an error. | -| This bug was fixed in Linux 5.17. | -+--------------------------------------------------------------------------+ - -The proposed patchset is the -`summary counter cleanup -`_ -series. - -Full Filesystem Scans ---------------------- - -Certain types of metadata can only be checked by walking every file in the -entire filesystem to record observations and comparing the observations against -what's recorded on disk. -Like every other type of online repair, repairs are made by writing those -observations to disk in a replacement structure and committing it atomically. -However, it is not practical to shut down the entire filesystem to examine -hundreds of billions of files because the downtime would be excessive. -Therefore, online fsck must build the infrastructure to manage a live scan of -all the files in the filesystem. -There are two questions that need to be solved to perform a live walk: - -- How does scrub manage the scan while it is collecting data? - -- How does the scan keep abreast of changes being made to the system by other - threads? - -.. _iscan: - -Coordinated Inode Scans -``````````````````````` - -In the original Unix filesystems of the 1970s, each directory entry contained -an index number (*inumber*) which was used as an index into on ondisk array -(*itable*) of fixed-size records (*inodes*) describing a file's attributes and -its data block mapping. -This system is described by J. Lions, `"inode (5659)" -`_ in *Lions' Commentary on -UNIX, 6th Edition*, (Dept. of Computer Science, the University of New South -Wales, November 1977), pp. 18-2; and later by D. Ritchie and K. Thompson, -`"Implementation of the File System" -`_, from *The UNIX -Time-Sharing System*, (The Bell System Technical Journal, July 1978), pp. -1913-4. - -XFS retains most of this design, except now inumbers are search keys over all -the space in the data section filesystem. -They form a continuous keyspace that can be expressed as a 64-bit integer, -though the inodes themselves are sparsely distributed within the keyspace. -Scans proceed in a linear fashion across the inumber keyspace, starting from -``0x0`` and ending at ``0xFFFFFFFFFFFFFFFF``. -Naturally, a scan through a keyspace requires a scan cursor object to track the -scan progress. -Because this keyspace is sparse, this cursor contains two parts. -The first part of this scan cursor object tracks the inode that will be -examined next; call this the examination cursor. -Somewhat less obviously, the scan cursor object must also track which parts of -the keyspace have already been visited, which is critical for deciding if a -concurrent filesystem update needs to be incorporated into the scan data. -Call this the visited inode cursor. - -Advancing the scan cursor is a multi-step process encapsulated in -``xchk_iscan_iter``: - -1. Lock the AGI buffer of the AG containing the inode pointed to by the visited - inode cursor. - This guarantee that inodes in this AG cannot be allocated or freed while - advancing the cursor. - -2. Use the per-AG inode btree to look up the next inumber after the one that - was just visited, since it may not be keyspace adjacent. - -3. If there are no more inodes left in this AG: - - a. Move the examination cursor to the point of the inumber keyspace that - corresponds to the start of the next AG. - - b. Adjust the visited inode cursor to indicate that it has "visited" the - last possible inode in the current AG's inode keyspace. - XFS inumbers are segmented, so the cursor needs to be marked as having - visited the entire keyspace up to just before the start of the next AG's - inode keyspace. - - c. Unlock the AGI and return to step 1 if there are unexamined AGs in the - filesystem. - - d. If there are no more AGs to examine, set both cursors to the end of the - inumber keyspace. - The scan is now complete. - -4. Otherwise, there is at least one more inode to scan in this AG: - - a. Move the examination cursor ahead to the next inode marked as allocated - by the inode btree. - - b. Adjust the visited inode cursor to point to the inode just prior to where - the examination cursor is now. - Because the scanner holds the AGI buffer lock, no inodes could have been - created in the part of the inode keyspace that the visited inode cursor - just advanced. - -5. Get the incore inode for the inumber of the examination cursor. - By maintaining the AGI buffer lock until this point, the scanner knows that - it was safe to advance the examination cursor across the entire keyspace, - and that it has stabilized this next inode so that it cannot disappear from - the filesystem until the scan releases the incore inode. - -6. Drop the AGI lock and return the incore inode to the caller. - -Online fsck functions scan all files in the filesystem as follows: - -1. Start a scan by calling ``xchk_iscan_start``. - -2. Advance the scan cursor (``xchk_iscan_iter``) to get the next inode. - If one is provided: - - a. Lock the inode to prevent updates during the scan. - - b. Scan the inode. - - c. While still holding the inode lock, adjust the visited inode cursor - (``xchk_iscan_mark_visited``) to point to this inode. - - d. Unlock and release the inode. - -8. Call ``xchk_iscan_teardown`` to complete the scan. - -There are subtleties with the inode cache that complicate grabbing the incore -inode for the caller. -Obviously, it is an absolute requirement that the inode metadata be consistent -enough to load it into the inode cache. -Second, if the incore inode is stuck in some intermediate state, the scan -coordinator must release the AGI and push the main filesystem to get the inode -back into a loadable state. - -The proposed patches are the -`inode scanner -`_ -series. -The first user of the new functionality is the -`online quotacheck -`_ -series. - -Inode Management -```````````````` - -In regular filesystem code, references to allocated XFS incore inodes are -always obtained (``xfs_iget``) outside of transaction context because the -creation of the incore context for an existing file does not require metadata -updates. -However, it is important to note that references to incore inodes obtained as -part of file creation must be performed in transaction context because the -filesystem must ensure the atomicity of the ondisk inode btree index updates -and the initialization of the actual ondisk inode. - -References to incore inodes are always released (``xfs_irele``) outside of -transaction context because there are a handful of activities that might -require ondisk updates: - -- The VFS may decide to kick off writeback as part of a ``DONTCACHE`` inode - release. - -- Speculative preallocations need to be unreserved. - -- An unlinked file may have lost its last reference, in which case the entire - file must be inactivated, which involves releasing all of its resources in - the ondisk metadata and freeing the inode. - -These activities are collectively called inode inactivation. -Inactivation has two parts -- the VFS part, which initiates writeback on all -dirty file pages, and the XFS part, which cleans up XFS-specific information -and frees the inode if it was unlinked. -If the inode is unlinked (or unconnected after a file handle operation), the -kernel drops the inode into the inactivation machinery immediately. - -During normal operation, resource acquisition for an update follows this order -to avoid deadlocks: - -1. Inode reference (``iget``). - -2. Filesystem freeze protection, if repairing (``mnt_want_write_file``). - -3. Inode ``IOLOCK`` (VFS ``i_rwsem``) lock to control file IO. - -4. Inode ``MMAPLOCK`` (page cache ``invalidate_lock``) lock for operations that - can update page cache mappings. - -5. Log feature enablement. - -6. Transaction log space grant. - -7. Space on the data and realtime devices for the transaction. - -8. Incore dquot references, if a file is being repaired. - Note that they are not locked, merely acquired. - -9. Inode ``ILOCK`` for file metadata updates. - -10. AG header buffer locks / Realtime metadata inode ILOCK. - -11. Realtime metadata buffer locks, if applicable. - -12. Extent mapping btree blocks, if applicable. - -Resources are often released in the reverse order, though this is not required. -However, online fsck differs from regular XFS operations because it may examine -an object that normally is acquired in a later stage of the locking order, and -then decide to cross-reference the object with an object that is acquired -earlier in the order. -The next few sections detail the specific ways in which online fsck takes care -to avoid deadlocks. - -iget and irele During a Scrub -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -An inode scan performed on behalf of a scrub operation runs in transaction -context, and possibly with resources already locked and bound to it. -This isn't much of a problem for ``iget`` since it can operate in the context -of an existing transaction, as long as all of the bound resources are acquired -before the inode reference in the regular filesystem. - -When the VFS ``iput`` function is given a linked inode with no other -references, it normally puts the inode on an LRU list in the hope that it can -save time if another process re-opens the file before the system runs out -of memory and frees it. -Filesystem callers can short-circuit the LRU process by setting a ``DONTCACHE`` -flag on the inode to cause the kernel to try to drop the inode into the -inactivation machinery immediately. - -In the past, inactivation was always done from the process that dropped the -inode, which was a problem for scrub because scrub may already hold a -transaction, and XFS does not support nesting transactions. -On the other hand, if there is no scrub transaction, it is desirable to drop -otherwise unused inodes immediately to avoid polluting caches. -To capture these nuances, the online fsck code has a separate ``xchk_irele`` -function to set or clear the ``DONTCACHE`` flag to get the required release -behavior. - -Proposed patchsets include fixing -`scrub iget usage -`_ and -`dir iget usage -`_. - -.. _ilocking: - -Locking Inodes -^^^^^^^^^^^^^^ - -In regular filesystem code, the VFS and XFS will acquire multiple IOLOCK locks -in a well-known order: parent → child when updating the directory tree, and -in numerical order of the addresses of their ``struct inode`` object otherwise. -For regular files, the MMAPLOCK can be acquired after the IOLOCK to stop page -faults. -If two MMAPLOCKs must be acquired, they are acquired in numerical order of -the addresses of their ``struct address_space`` objects. -Due to the structure of existing filesystem code, IOLOCKs and MMAPLOCKs must be -acquired before transactions are allocated. -If two ILOCKs must be acquired, they are acquired in inumber order. - -Inode lock acquisition must be done carefully during a coordinated inode scan. -Online fsck cannot abide these conventions, because for a directory tree -scanner, the scrub process holds the IOLOCK of the file being scanned and it -needs to take the IOLOCK of the file at the other end of the directory link. -If the directory tree is corrupt because it contains a cycle, ``xfs_scrub`` -cannot use the regular inode locking functions and avoid becoming trapped in an -ABBA deadlock. - -Solving both of these problems is straightforward -- any time online fsck -needs to take a second lock of the same class, it uses trylock to avoid an ABBA -deadlock. -If the trylock fails, scrub drops all inode locks and use trylock loops to -(re)acquire all necessary resources. -Trylock loops enable scrub to check for pending fatal signals, which is how -scrub avoids deadlocking the filesystem or becoming an unresponsive process. -However, trylock loops means that online fsck must be prepared to measure the -resource being scrubbed before and after the lock cycle to detect changes and -react accordingly. - -.. _dirparent: - -Case Study: Finding a Directory Parent -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Consider the directory parent pointer repair code as an example. -Online fsck must verify that the dotdot dirent of a directory points up to a -parent directory, and that the parent directory contains exactly one dirent -pointing down to the child directory. -Fully validating this relationship (and repairing it if possible) requires a -walk of every directory on the filesystem while holding the child locked, and -while updates to the directory tree are being made. -The coordinated inode scan provides a way to walk the filesystem without the -possibility of missing an inode. -The child directory is kept locked to prevent updates to the dotdot dirent, but -if the scanner fails to lock a parent, it can drop and relock both the child -and the prospective parent. -If the dotdot entry changes while the directory is unlocked, then a move or -rename operation must have changed the child's parentage, and the scan can -exit early. - -The proposed patchset is the -`directory repair -`_ -series. - -.. _fshooks: - -Filesystem Hooks -````````````````` - -The second piece of support that online fsck functions need during a full -filesystem scan is the ability to stay informed about updates being made by -other threads in the filesystem, since comparisons against the past are useless -in a dynamic environment. -Two pieces of Linux kernel infrastructure enable online fsck to monitor regular -filesystem operations: filesystem hooks and :ref:`static keys`. - -Filesystem hooks convey information about an ongoing filesystem operation to -a downstream consumer. -In this case, the downstream consumer is always an online fsck function. -Because multiple fsck functions can run in parallel, online fsck uses the Linux -notifier call chain facility to dispatch updates to any number of interested -fsck processes. -Call chains are a dynamic list, which means that they can be configured at -run time. -Because these hooks are private to the XFS module, the information passed along -contains exactly what the checking function needs to update its observations. - -The current implementation of XFS hooks uses SRCU notifier chains to reduce the -impact to highly threaded workloads. -Regular blocking notifier chains use a rwsem and seem to have a much lower -overhead for single-threaded applications. -However, it may turn out that the combination of blocking chains and static -keys are a more performant combination; more study is needed here. - -The following pieces are necessary to hook a certain point in the filesystem: - -- A ``struct xfs_hooks`` object must be embedded in a convenient place such as - a well-known incore filesystem object. - -- Each hook must define an action code and a structure containing more context - about the action. - -- Hook providers should provide appropriate wrapper functions and structs - around the ``xfs_hooks`` and ``xfs_hook`` objects to take advantage of type - checking to ensure correct usage. - -- A callsite in the regular filesystem code must be chosen to call - ``xfs_hooks_call`` with the action code and data structure. - This place should be adjacent to (and not earlier than) the place where - the filesystem update is committed to the transaction. - In general, when the filesystem calls a hook chain, it should be able to - handle sleeping and should not be vulnerable to memory reclaim or locking - recursion. - However, the exact requirements are very dependent on the context of the hook - caller and the callee. - -- The online fsck function should define a structure to hold scan data, a lock - to coordinate access to the scan data, and a ``struct xfs_hook`` object. - The scanner function and the regular filesystem code must acquire resources - in the same order; see the next section for details. - -- The online fsck code must contain a C function to catch the hook action code - and data structure. - If the object being updated has already been visited by the scan, then the - hook information must be applied to the scan data. - -- Prior to unlocking inodes to start the scan, online fsck must call - ``xfs_hooks_setup`` to initialize the ``struct xfs_hook``, and - ``xfs_hooks_add`` to enable the hook. - -- Online fsck must call ``xfs_hooks_del`` to disable the hook once the scan is - complete. - -The number of hooks should be kept to a minimum to reduce complexity. -Static keys are used to reduce the overhead of filesystem hooks to nearly -zero when online fsck is not running. - -.. _liveupdate: - -Live Updates During a Scan -`````````````````````````` - -The code paths of the online fsck scanning code and the :ref:`hooked` -filesystem code look like this:: - - other program - ↓ - inode lock ←────────────────────┐ - ↓ │ - AG header lock │ - ↓ │ - filesystem function │ - ↓ │ - notifier call chain │ same - ↓ ├─── inode - scrub hook function │ lock - ↓ │ - scan data mutex ←──┐ same │ - ↓ ├─── scan │ - update scan data │ lock │ - ↑ │ │ - scan data mutex ←──┘ │ - ↑ │ - inode lock ←────────────────────┘ - ↑ - scrub function - ↑ - inode scanner - ↑ - xfs_scrub - -These rules must be followed to ensure correct interactions between the -checking code and the code making an update to the filesystem: - -- Prior to invoking the notifier call chain, the filesystem function being - hooked must acquire the same lock that the scrub scanning function acquires - to scan the inode. - -- The scanning function and the scrub hook function must coordinate access to - the scan data by acquiring a lock on the scan data. - -- Scrub hook function must not add the live update information to the scan - observations unless the inode being updated has already been scanned. - The scan coordinator has a helper predicate (``xchk_iscan_want_live_update``) - for this. - -- Scrub hook functions must not change the caller's state, including the - transaction that it is running. - They must not acquire any resources that might conflict with the filesystem - function being hooked. - -- The hook function can abort the inode scan to avoid breaking the other rules. - -The inode scan APIs are pretty simple: - -- ``xchk_iscan_start`` starts a scan - -- ``xchk_iscan_iter`` grabs a reference to the next inode in the scan or - returns zero if there is nothing left to scan - -- ``xchk_iscan_want_live_update`` to decide if an inode has already been - visited in the scan. - This is critical for hook functions to decide if they need to update the - in-memory scan information. - -- ``xchk_iscan_mark_visited`` to mark an inode as having been visited in the - scan - -- ``xchk_iscan_teardown`` to finish the scan - -This functionality is also a part of the -`inode scanner -`_ -series. - -.. _quotacheck: - -Case Study: Quota Counter Checking -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -It is useful to compare the mount time quotacheck code to the online repair -quotacheck code. -Mount time quotacheck does not have to contend with concurrent operations, so -it does the following: - -1. Make sure the ondisk dquots are in good enough shape that all the incore - dquots will actually load, and zero the resource usage counters in the - ondisk buffer. - -2. Walk every inode in the filesystem. - Add each file's resource usage to the incore dquot. - -3. Walk each incore dquot. - If the incore dquot is not being flushed, add the ondisk buffer backing the - incore dquot to a delayed write (delwri) list. - -4. Write the buffer list to disk. - -Like most online fsck functions, online quotacheck can't write to regular -filesystem objects until the newly collected metadata reflect all filesystem -state. -Therefore, online quotacheck records file resource usage to a shadow dquot -index implemented with a sparse ``xfarray``, and only writes to the real dquots -once the scan is complete. -Handling transactional updates is tricky because quota resource usage updates -are handled in phases to minimize contention on dquots: - -1. The inodes involved are joined and locked to a transaction. - -2. For each dquot attached to the file: - - a. The dquot is locked. - - b. A quota reservation is added to the dquot's resource usage. - The reservation is recorded in the transaction. - - c. The dquot is unlocked. - -3. Changes in actual quota usage are tracked in the transaction. - -4. At transaction commit time, each dquot is examined again: - - a. The dquot is locked again. - - b. Quota usage changes are logged and unused reservation is given back to - the dquot. - - c. The dquot is unlocked. - -For online quotacheck, hooks are placed in steps 2 and 4. -The step 2 hook creates a shadow version of the transaction dquot context -(``dqtrx``) that operates in a similar manner to the regular code. -The step 4 hook commits the shadow ``dqtrx`` changes to the shadow dquots. -Notice that both hooks are called with the inode locked, which is how the -live update coordinates with the inode scanner. - -The quotacheck scan looks like this: - -1. Set up a coordinated inode scan. - -2. For each inode returned by the inode scan iterator: - - a. Grab and lock the inode. - - b. Determine that inode's resource usage (data blocks, inode counts, - realtime blocks) and add that to the shadow dquots for the user, group, - and project ids associated with the inode. - - c. Unlock and release the inode. - -3. For each dquot in the system: - - a. Grab and lock the dquot. - - b. Check the dquot against the shadow dquots created by the scan and updated - by the live hooks. - -Live updates are key to being able to walk every quota record without -needing to hold any locks for a long duration. -If repairs are desired, the real and shadow dquots are locked and their -resource counts are set to the values in the shadow dquot. - -The proposed patchset is the -`online quotacheck -`_ -series. - -.. _nlinks: - -Case Study: File Link Count Checking -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -File link count checking also uses live update hooks. -The coordinated inode scanner is used to visit all directories on the -filesystem, and per-file link count records are stored in a sparse ``xfarray`` -indexed by inumber. -During the scanning phase, each entry in a directory generates observation -data as follows: - -1. If the entry is a dotdot (``'..'``) entry of the root directory, the - directory's parent link count is bumped because the root directory's dotdot - entry is self referential. - -2. If the entry is a dotdot entry of a subdirectory, the parent's backref - count is bumped. - -3. If the entry is neither a dot nor a dotdot entry, the target file's parent - count is bumped. - -4. If the target is a subdirectory, the parent's child link count is bumped. - -A crucial point to understand about how the link count inode scanner interacts -with the live update hooks is that the scan cursor tracks which *parent* -directories have been scanned. -In other words, the live updates ignore any update about ``A → B`` when A has -not been scanned, even if B has been scanned. -Furthermore, a subdirectory A with a dotdot entry pointing back to B is -accounted as a backref counter in the shadow data for A, since child dotdot -entries affect the parent's link count. -Live update hooks are carefully placed in all parts of the filesystem that -create, change, or remove directory entries, since those operations involve -bumplink and droplink. - -For any file, the correct link count is the number of parents plus the number -of child subdirectories. -Non-directories never have children of any kind. -The backref information is used to detect inconsistencies in the number of -links pointing to child subdirectories and the number of dotdot entries -pointing back. - -After the scan completes, the link count of each file can be checked by locking -both the inode and the shadow data, and comparing the link counts. -A second coordinated inode scan cursor is used for comparisons. -Live updates are key to being able to walk every inode without needing to hold -any locks between inodes. -If repairs are desired, the inode's link count is set to the value in the -shadow information. -If no parents are found, the file must be :ref:`reparented ` to the -orphanage to prevent the file from being lost forever. - -The proposed patchset is the -`file link count repair -`_ -series. - -.. _rmap_repair: - -Case Study: Rebuilding Reverse Mapping Records -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Most repair functions follow the same pattern: lock filesystem resources, -walk the surviving ondisk metadata looking for replacement metadata records, -and use an :ref:`in-memory array ` to store the gathered observations. -The primary advantage of this approach is the simplicity and modularity of the -repair code -- code and data are entirely contained within the scrub module, -do not require hooks in the main filesystem, and are usually the most efficient -in memory use. -A secondary advantage of this repair approach is atomicity -- once the kernel -decides a structure is corrupt, no other threads can access the metadata until -the kernel finishes repairing and revalidating the metadata. - -For repairs going on within a shard of the filesystem, these advantages -outweigh the delays inherent in locking the shard while repairing parts of the -shard. -Unfortunately, repairs to the reverse mapping btree cannot use the "standard" -btree repair strategy because it must scan every space mapping of every fork of -every file in the filesystem, and the filesystem cannot stop. -Therefore, rmap repair foregoes atomicity between scrub and repair. -It combines a :ref:`coordinated inode scanner `, :ref:`live update hooks -`, and an :ref:`in-memory rmap btree ` to complete the -scan for reverse mapping records. - -1. Set up an xfbtree to stage rmap records. - -2. While holding the locks on the AGI and AGF buffers acquired during the - scrub, generate reverse mappings for all AG metadata: inodes, btrees, CoW - staging extents, and the internal log. - -3. Set up an inode scanner. - -4. Hook into rmap updates for the AG being repaired so that the live scan data - can receive updates to the rmap btree from the rest of the filesystem during - the file scan. - -5. For each space mapping found in either fork of each file scanned, - decide if the mapping matches the AG of interest. - If so: - - a. Create a btree cursor for the in-memory btree. - - b. Use the rmap code to add the record to the in-memory btree. - - c. Use the :ref:`special commit function ` to write the - xfbtree changes to the xfile. - -6. For each live update received via the hook, decide if the owner has already - been scanned. - If so, apply the live update into the scan data: - - a. Create a btree cursor for the in-memory btree. - - b. Replay the operation into the in-memory btree. - - c. Use the :ref:`special commit function ` to write the - xfbtree changes to the xfile. - This is performed with an empty transaction to avoid changing the - caller's state. - -7. When the inode scan finishes, create a new scrub transaction and relock the - two AG headers. - -8. Compute the new btree geometry using the number of rmap records in the - shadow btree, like all other btree rebuilding functions. - -9. Allocate the number of blocks computed in the previous step. - -10. Perform the usual btree bulk loading and commit to install the new rmap - btree. - -11. Reap the old rmap btree blocks as discussed in the case study about how - to :ref:`reap after rmap btree repair `. - -12. Free the xfbtree now that it not needed. - -The proposed patchset is the -`rmap repair -`_ -series. - -Staging Repairs with Temporary Files on Disk --------------------------------------------- - -XFS stores a substantial amount of metadata in file forks: directories, -extended attributes, symbolic link targets, free space bitmaps and summary -information for the realtime volume, and quota records. -File forks map 64-bit logical file fork space extents to physical storage space -extents, similar to how a memory management unit maps 64-bit virtual addresses -to physical memory addresses. -Therefore, file-based tree structures (such as directories and extended -attributes) use blocks mapped in the file fork offset address space that point -to other blocks mapped within that same address space, and file-based linear -structures (such as bitmaps and quota records) compute array element offsets in -the file fork offset address space. - -Because file forks can consume as much space as the entire filesystem, repairs -cannot be staged in memory, even when a paging scheme is available. -Therefore, online repair of file-based metadata createas a temporary file in -the XFS filesystem, writes a new structure at the correct offsets into the -temporary file, and atomically swaps the fork mappings (and hence the fork -contents) to commit the repair. -Once the repair is complete, the old fork can be reaped as necessary; if the -system goes down during the reap, the iunlink code will delete the blocks -during log recovery. - -**Note**: All space usage and inode indices in the filesystem *must* be -consistent to use a temporary file safely! -This dependency is the reason why online repair can only use pageable kernel -memory to stage ondisk space usage information. - -Swapping metadata extents with a temporary file requires the owner field of the -block headers to match the file being repaired and not the temporary file. The -directory, extended attribute, and symbolic link functions were all modified to -allow callers to specify owner numbers explicitly. - -There is a downside to the reaping process -- if the system crashes during the -reap phase and the fork extents are crosslinked, the iunlink processing will -fail because freeing space will find the extra reverse mappings and abort. - -Temporary files created for repair are similar to ``O_TMPFILE`` files created -by userspace. -They are not linked into a directory and the entire file will be reaped when -the last reference to the file is lost. -The key differences are that these files must have no access permission outside -the kernel at all, they must be specially marked to prevent them from being -opened by handle, and they must never be linked into the directory tree. - -+--------------------------------------------------------------------------+ -| **Historical Sidebar**: | -+--------------------------------------------------------------------------+ -| In the initial iteration of file metadata repair, the damaged metadata | -| blocks would be scanned for salvageable data; the extents in the file | -| fork would be reaped; and then a new structure would be built in its | -| place. | -| This strategy did not survive the introduction of the atomic repair | -| requirement expressed earlier in this document. | -| | -| The second iteration explored building a second structure at a high | -| offset in the fork from the salvage data, reaping the old extents, and | -| using a ``COLLAPSE_RANGE`` operation to slide the new extents into | -| place. | -| | -| This had many drawbacks: | -| | -| - Array structures are linearly addressed, and the regular filesystem | -| codebase does not have the concept of a linear offset that could be | -| applied to the record offset computation to build an alternate copy. | -| | -| - Extended attributes are allowed to use the entire attr fork offset | -| address space. | -| | -| - Even if repair could build an alternate copy of a data structure in a | -| different part of the fork address space, the atomic repair commit | -| requirement means that online repair would have to be able to perform | -| a log assisted ``COLLAPSE_RANGE`` operation to ensure that the old | -| structure was completely replaced. | -| | -| - A crash after construction of the secondary tree but before the range | -| collapse would leave unreachable blocks in the file fork. | -| This would likely confuse things further. | -| | -| - Reaping blocks after a repair is not a simple operation, and | -| initiating a reap operation from a restarted range collapse operation | -| during log recovery is daunting. | -| | -| - Directory entry blocks and quota records record the file fork offset | -| in the header area of each block. | -| An atomic range collapse operation would have to rewrite this part of | -| each block header. | -| Rewriting a single field in block headers is not a huge problem, but | -| it's something to be aware of. | -| | -| - Each block in a directory or extended attributes btree index contains | -| sibling and child block pointers. | -| Were the atomic commit to use a range collapse operation, each block | -| would have to be rewritten very carefully to preserve the graph | -| structure. | -| Doing this as part of a range collapse means rewriting a large number | -| of blocks repeatedly, which is not conducive to quick repairs. | -| | -| This lead to the introduction of temporary file staging. | -+--------------------------------------------------------------------------+ - -Using a Temporary File -`````````````````````` - -Online repair code should use the ``xrep_tempfile_create`` function to create a -temporary file inside the filesystem. -This allocates an inode, marks the in-core inode private, and attaches it to -the scrub context. -These files are hidden from userspace, may not be added to the directory tree, -and must be kept private. - -Temporary files only use two inode locks: the IOLOCK and the ILOCK. -The MMAPLOCK is not needed here, because there must not be page faults from -userspace for data fork blocks. -The usage patterns of these two locks are the same as for any other XFS file -- -access to file data are controlled via the IOLOCK, and access to file metadata -are controlled via the ILOCK. -Locking helpers are provided so that the temporary file and its lock state can -be cleaned up by the scrub context. -To comply with the nested locking strategy laid out in the :ref:`inode -locking` section, it is recommended that scrub functions use the -xrep_tempfile_ilock*_nowait lock helpers. - -Data can be written to a temporary file by two means: - -1. ``xrep_tempfile_copyin`` can be used to set the contents of a regular - temporary file from an xfile. - -2. The regular directory, symbolic link, and extended attribute functions can - be used to write to the temporary file. - -Once a good copy of a data file has been constructed in a temporary file, it -must be conveyed to the file being repaired, which is the topic of the next -section. - -The proposed patches are in the -`repair temporary files -`_ -series. - -Atomic Extent Swapping ----------------------- - -Once repair builds a temporary file with a new data structure written into -it, it must commit the new changes into the existing file. -It is not possible to swap the inumbers of two files, so instead the new -metadata must replace the old. -This suggests the need for the ability to swap extents, but the existing extent -swapping code used by the file defragmenting tool ``xfs_fsr`` is not sufficient -for online repair because: - -a. When the reverse-mapping btree is enabled, the swap code must keep the - reverse mapping information up to date with every exchange of mappings. - Therefore, it can only exchange one mapping per transaction, and each - transaction is independent. - -b. Reverse-mapping is critical for the operation of online fsck, so the old - defragmentation code (which swapped entire extent forks in a single - operation) is not useful here. - -c. Defragmentation is assumed to occur between two files with identical - contents. - For this use case, an incomplete exchange will not result in a user-visible - change in file contents, even if the operation is interrupted. - -d. Online repair needs to swap the contents of two files that are by definition - *not* identical. - For directory and xattr repairs, the user-visible contents might be the - same, but the contents of individual blocks may be very different. - -e. Old blocks in the file may be cross-linked with another structure and must - not reappear if the system goes down mid-repair. - -These problems are overcome by creating a new deferred operation and a new type -of log intent item to track the progress of an operation to exchange two file -ranges. -The new deferred operation type chains together the same transactions used by -the reverse-mapping extent swap code. -The new log item records the progress of the exchange to ensure that once an -exchange begins, it will always run to completion, even there are -interruptions. -The new ``XFS_SB_FEAT_INCOMPAT_LOG_ATOMIC_SWAP`` log-incompatible feature flag -in the superblock protects these new log item records from being replayed on -old kernels. - -The proposed patchset is the -`atomic extent swap -`_ -series. - -+--------------------------------------------------------------------------+ -| **Sidebar: Using Log-Incompatible Feature Flags** | -+--------------------------------------------------------------------------+ -| Starting with XFS v5, the superblock contains a | -| ``sb_features_log_incompat`` field to indicate that the log contains | -| records that might not readable by all kernels that could mount this | -| filesystem. | -| In short, log incompat features protect the log contents against kernels | -| that will not understand the contents. | -| Unlike the other superblock feature bits, log incompat bits are | -| ephemeral because an empty (clean) log does not need protection. | -| The log cleans itself after its contents have been committed into the | -| filesystem, either as part of an unmount or because the system is | -| otherwise idle. | -| Because upper level code can be working on a transaction at the same | -| time that the log cleans itself, it is necessary for upper level code to | -| communicate to the log when it is going to use a log incompatible | -| feature. | -| | -| The log coordinates access to incompatible features through the use of | -| one ``struct rw_semaphore`` for each feature. | -| The log cleaning code tries to take this rwsem in exclusive mode to | -| clear the bit; if the lock attempt fails, the feature bit remains set. | -| Filesystem code signals its intention to use a log incompat feature in a | -| transaction by calling ``xlog_use_incompat_feat``, which takes the rwsem | -| in shared mode. | -| The code supporting a log incompat feature should create wrapper | -| functions to obtain the log feature and call | -| ``xfs_add_incompat_log_feature`` to set the feature bits in the primary | -| superblock. | -| The superblock update is performed transactionally, so the wrapper to | -| obtain log assistance must be called just prior to the creation of the | -| transaction that uses the functionality. | -| For a file operation, this step must happen after taking the IOLOCK | -| and the MMAPLOCK, but before allocating the transaction. | -| When the transaction is complete, the ``xlog_drop_incompat_feat`` | -| function is called to release the feature. | -| The feature bit will not be cleared from the superblock until the log | -| becomes clean. | -| | -| Log-assisted extended attribute updates and atomic extent swaps both use | -| log incompat features and provide convenience wrappers around the | -| functionality. | -+--------------------------------------------------------------------------+ - -Mechanics of an Atomic Extent Swap -`````````````````````````````````` - -Swapping entire file forks is a complex task. -The goal is to exchange all file fork mappings between two file fork offset -ranges. -There are likely to be many extent mappings in each fork, and the edges of -the mappings aren't necessarily aligned. -Furthermore, there may be other updates that need to happen after the swap, -such as exchanging file sizes, inode flags, or conversion of fork data to local -format. -This is roughly the format of the new deferred extent swap work item: - -.. code-block:: c - - struct xfs_swapext_intent { - /* Inodes participating in the operation. */ - struct xfs_inode *sxi_ip1; - struct xfs_inode *sxi_ip2; - - /* File offset range information. */ - xfs_fileoff_t sxi_startoff1; - xfs_fileoff_t sxi_startoff2; - xfs_filblks_t sxi_blockcount; - - /* Set these file sizes after the operation, unless negative. */ - xfs_fsize_t sxi_isize1; - xfs_fsize_t sxi_isize2; - - /* XFS_SWAP_EXT_* log operation flags */ - uint64_t sxi_flags; - }; - -The new log intent item contains enough information to track two logical fork -offset ranges: ``(inode1, startoff1, blockcount)`` and ``(inode2, startoff2, -blockcount)``. -Each step of a swap operation exchanges the largest file range mapping possible -from one file to the other. -After each step in the swap operation, the two startoff fields are incremented -and the blockcount field is decremented to reflect the progress made. -The flags field captures behavioral parameters such as swapping the attr fork -instead of the data fork and other work to be done after the extent swap. -The two isize fields are used to swap the file size at the end of the operation -if the file data fork is the target of the swap operation. - -When the extent swap is initiated, the sequence of operations is as follows: - -1. Create a deferred work item for the extent swap. - At the start, it should contain the entirety of the file ranges to be - swapped. - -2. Call ``xfs_defer_finish`` to process the exchange. - This is encapsulated in ``xrep_tempswap_contents`` for scrub operations. - This will log an extent swap intent item to the transaction for the deferred - extent swap work item. - -3. Until ``sxi_blockcount`` of the deferred extent swap work item is zero, - - a. Read the block maps of both file ranges starting at ``sxi_startoff1`` and - ``sxi_startoff2``, respectively, and compute the longest extent that can - be swapped in a single step. - This is the minimum of the two ``br_blockcount`` s in the mappings. - Keep advancing through the file forks until at least one of the mappings - contains written blocks. - Mutual holes, unwritten extents, and extent mappings to the same physical - space are not exchanged. - - For the next few steps, this document will refer to the mapping that came - from file 1 as "map1", and the mapping that came from file 2 as "map2". - - b. Create a deferred block mapping update to unmap map1 from file 1. - - c. Create a deferred block mapping update to unmap map2 from file 2. - - d. Create a deferred block mapping update to map map1 into file 2. - - e. Create a deferred block mapping update to map map2 into file 1. - - f. Log the block, quota, and extent count updates for both files. - - g. Extend the ondisk size of either file if necessary. - - h. Log an extent swap done log item for the extent swap intent log item - that was read at the start of step 3. - - i. Compute the amount of file range that has just been covered. - This quantity is ``(map1.br_startoff + map1.br_blockcount - - sxi_startoff1)``, because step 3a could have skipped holes. - - j. Increase the starting offsets of ``sxi_startoff1`` and ``sxi_startoff2`` - by the number of blocks computed in the previous step, and decrease - ``sxi_blockcount`` by the same quantity. - This advances the cursor. - - k. Log a new extent swap intent log item reflecting the advanced state of - the work item. - - l. Return the proper error code (EAGAIN) to the deferred operation manager - to inform it that there is more work to be done. - The operation manager completes the deferred work in steps 3b-3e before - moving back to the start of step 3. - -4. Perform any post-processing. - This will be discussed in more detail in subsequent sections. - -If the filesystem goes down in the middle of an operation, log recovery will -find the most recent unfinished extent swap log intent item and restart from -there. -This is how extent swapping guarantees that an outside observer will either see -the old broken structure or the new one, and never a mismash of both. - -Preparation for Extent Swapping -``````````````````````````````` - -There are a few things that need to be taken care of before initiating an -atomic extent swap operation. -First, regular files require the page cache to be flushed to disk before the -operation begins, and directio writes to be quiesced. -Like any filesystem operation, extent swapping must determine the maximum -amount of disk space and quota that can be consumed on behalf of both files in -the operation, and reserve that quantity of resources to avoid an unrecoverable -out of space failure once it starts dirtying metadata. -The preparation step scans the ranges of both files to estimate: - -- Data device blocks needed to handle the repeated updates to the fork - mappings. -- Change in data and realtime block counts for both files. -- Increase in quota usage for both files, if the two files do not share the - same set of quota ids. -- The number of extent mappings that will be added to each file. -- Whether or not there are partially written realtime extents. - User programs must never be able to access a realtime file extent that maps - to different extents on the realtime volume, which could happen if the - operation fails to run to completion. - -The need for precise estimation increases the run time of the swap operation, -but it is very important to maintain correct accounting. -The filesystem must not run completely out of free space, nor can the extent -swap ever add more extent mappings to a fork than it can support. -Regular users are required to abide the quota limits, though metadata repairs -may exceed quota to resolve inconsistent metadata elsewhere. - -Special Features for Swapping Metadata File Extents -``````````````````````````````````````````````````` - -Extended attributes, symbolic links, and directories can set the fork format to -"local" and treat the fork as a literal area for data storage. -Metadata repairs must take extra steps to support these cases: - -- If both forks are in local format and the fork areas are large enough, the - swap is performed by copying the incore fork contents, logging both forks, - and committing. - The atomic extent swap mechanism is not necessary, since this can be done - with a single transaction. - -- If both forks map blocks, then the regular atomic extent swap is used. - -- Otherwise, only one fork is in local format. - The contents of the local format fork are converted to a block to perform the - swap. - The conversion to block format must be done in the same transaction that - logs the initial extent swap intent log item. - The regular atomic extent swap is used to exchange the mappings. - Special flags are set on the swap operation so that the transaction can be - rolled one more time to convert the second file's fork back to local format - so that the second file will be ready to go as soon as the ILOCK is dropped. - -Extended attributes and directories stamp the owning inode into every block, -but the buffer verifiers do not actually check the inode number! -Although there is no verification, it is still important to maintain -referential integrity, so prior to performing the extent swap, online repair -builds every block in the new data structure with the owner field of the file -being repaired. - -After a successful swap operation, the repair operation must reap the old fork -blocks by processing each fork mapping through the standard :ref:`file extent -reaping ` mechanism that is done post-repair. -If the filesystem should go down during the reap part of the repair, the -iunlink processing at the end of recovery will free both the temporary file and -whatever blocks were not reaped. -However, this iunlink processing omits the cross-link detection of online -repair, and is not completely foolproof. - -Swapping Temporary File Extents -``````````````````````````````` - -To repair a metadata file, online repair proceeds as follows: - -1. Create a temporary repair file. - -2. Use the staging data to write out new contents into the temporary repair - file. - The same fork must be written to as is being repaired. - -3. Commit the scrub transaction, since the swap estimation step must be - completed before transaction reservations are made. - -4. Call ``xrep_tempswap_trans_alloc`` to allocate a new scrub transaction with - the appropriate resource reservations, locks, and fill out a ``struct - xfs_swapext_req`` with the details of the swap operation. - -5. Call ``xrep_tempswap_contents`` to swap the contents. - -6. Commit the transaction to complete the repair. - -.. _rtsummary: - -Case Study: Repairing the Realtime Summary File -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -In the "realtime" section of an XFS filesystem, free space is tracked via a -bitmap, similar to Unix FFS. -Each bit in the bitmap represents one realtime extent, which is a multiple of -the filesystem block size between 4KiB and 1GiB in size. -The realtime summary file indexes the number of free extents of a given size to -the offset of the block within the realtime free space bitmap where those free -extents begin. -In other words, the summary file helps the allocator find free extents by -length, similar to what the free space by count (cntbt) btree does for the data -section. - -The summary file itself is a flat file (with no block headers or checksums!) -partitioned into ``log2(total rt extents)`` sections containing enough 32-bit -counters to match the number of blocks in the rt bitmap. -Each counter records the number of free extents that start in that bitmap block -and can satisfy a power-of-two allocation request. - -To check the summary file against the bitmap: - -1. Take the ILOCK of both the realtime bitmap and summary files. - -2. For each free space extent recorded in the bitmap: - - a. Compute the position in the summary file that contains a counter that - represents this free extent. - - b. Read the counter from the xfile. - - c. Increment it, and write it back to the xfile. - -3. Compare the contents of the xfile against the ondisk file. - -To repair the summary file, write the xfile contents into the temporary file -and use atomic extent swap to commit the new contents. -The temporary file is then reaped. - -The proposed patchset is the -`realtime summary repair -`_ -series. - -Case Study: Salvaging Extended Attributes -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -In XFS, extended attributes are implemented as a namespaced name-value store. -Values are limited in size to 64KiB, but there is no limit in the number of -names. -The attribute fork is unpartitioned, which means that the root of the attribute -structure is always in logical block zero, but attribute leaf blocks, dabtree -index blocks, and remote value blocks are intermixed. -Attribute leaf blocks contain variable-sized records that associate -user-provided names with the user-provided values. -Values larger than a block are allocated separate extents and written there. -If the leaf information expands beyond a single block, a directory/attribute -btree (``dabtree``) is created to map hashes of attribute names to entries -for fast lookup. - -Salvaging extended attributes is done as follows: - -1. Walk the attr fork mappings of the file being repaired to find the attribute - leaf blocks. - When one is found, - - a. Walk the attr leaf block to find candidate keys. - When one is found, - - 1. Check the name for problems, and ignore the name if there are. - - 2. Retrieve the value. - If that succeeds, add the name and value to the staging xfarray and - xfblob. - -2. If the memory usage of the xfarray and xfblob exceed a certain amount of - memory or there are no more attr fork blocks to examine, unlock the file and - add the staged extended attributes to the temporary file. - -3. Use atomic extent swapping to exchange the new and old extended attribute - structures. - The old attribute blocks are now attached to the temporary file. - -4. Reap the temporary file. - -The proposed patchset is the -`extended attribute repair -`_ -series. - -Fixing Directories ------------------- - -Fixing directories is difficult with currently available filesystem features, -since directory entries are not redundant. -The offline repair tool scans all inodes to find files with nonzero link count, -and then it scans all directories to establish parentage of those linked files. -Damaged files and directories are zapped, and files with no parent are -moved to the ``/lost+found`` directory. -It does not try to salvage anything. - -The best that online repair can do at this time is to read directory data -blocks and salvage any dirents that look plausible, correct link counts, and -move orphans back into the directory tree. -The salvage process is discussed in the case study at the end of this section. -The :ref:`file link count fsck ` code takes care of fixing link counts -and moving orphans to the ``/lost+found`` directory. - -Case Study: Salvaging Directories -````````````````````````````````` - -Unlike extended attributes, directory blocks are all the same size, so -salvaging directories is straightforward: - -1. Find the parent of the directory. - If the dotdot entry is not unreadable, try to confirm that the alleged - parent has a child entry pointing back to the directory being repaired. - Otherwise, walk the filesystem to find it. - -2. Walk the first partition of data fork of the directory to find the directory - entry data blocks. - When one is found, - - a. Walk the directory data block to find candidate entries. - When an entry is found: - - i. Check the name for problems, and ignore the name if there are. - - ii. Retrieve the inumber and grab the inode. - If that succeeds, add the name, inode number, and file type to the - staging xfarray and xblob. - -3. If the memory usage of the xfarray and xfblob exceed a certain amount of - memory or there are no more directory data blocks to examine, unlock the - directory and add the staged dirents into the temporary directory. - Truncate the staging files. - -4. Use atomic extent swapping to exchange the new and old directory structures. - The old directory blocks are now attached to the temporary file. - -5. Reap the temporary file. - -**Future Work Question**: Should repair revalidate the dentry cache when -rebuilding a directory? - -*Answer*: Yes, it should. - -In theory it is necessary to scan all dentry cache entries for a directory to -ensure that one of the following apply: - -1. The cached dentry reflects an ondisk dirent in the new directory. - -2. The cached dentry no longer has a corresponding ondisk dirent in the new - directory and the dentry can be purged from the cache. - -3. The cached dentry no longer has an ondisk dirent but the dentry cannot be - purged. - This is the problem case. - -Unfortunately, the current dentry cache design doesn't provide a means to walk -every child dentry of a specific directory, which makes this a hard problem. -There is no known solution. - -The proposed patchset is the -`directory repair -`_ -series. - -Parent Pointers -``````````````` - -A parent pointer is a piece of file metadata that enables a user to locate the -file's parent directory without having to traverse the directory tree from the -root. -Without them, reconstruction of directory trees is hindered in much the same -way that the historic lack of reverse space mapping information once hindered -reconstruction of filesystem space metadata. -The parent pointer feature, however, makes total directory reconstruction -possible. - -XFS parent pointers include the dirent name and location of the entry within -the parent directory. -In other words, child files use extended attributes to store pointers to -parents in the form ``(parent_inum, parent_gen, dirent_pos) → (dirent_name)``. -The directory checking process can be strengthened to ensure that the target of -each dirent also contains a parent pointer pointing back to the dirent. -Likewise, each parent pointer can be checked by ensuring that the target of -each parent pointer is a directory and that it contains a dirent matching -the parent pointer. -Both online and offline repair can use this strategy. - -**Note**: The ondisk format of parent pointers is not yet finalized. - -+--------------------------------------------------------------------------+ -| **Historical Sidebar**: | -+--------------------------------------------------------------------------+ -| Directory parent pointers were first proposed as an XFS feature more | -| than a decade ago by SGI. | -| Each link from a parent directory to a child file is mirrored with an | -| extended attribute in the child that could be used to identify the | -| parent directory. | -| Unfortunately, this early implementation had major shortcomings and was | -| never merged into Linux XFS: | -| | -| 1. The XFS codebase of the late 2000s did not have the infrastructure to | -| enforce strong referential integrity in the directory tree. | -| It did not guarantee that a change in a forward link would always be | -| followed up with the corresponding change to the reverse links. | -| | -| 2. Referential integrity was not integrated into offline repair. | -| Checking and repairs were performed on mounted filesystems without | -| taking any kernel or inode locks to coordinate access. | -| It is not clear how this actually worked properly. | -| | -| 3. The extended attribute did not record the name of the directory entry | -| in the parent, so the SGI parent pointer implementation cannot be | -| used to reconnect the directory tree. | -| | -| 4. Extended attribute forks only support 65,536 extents, which means | -| that parent pointer attribute creation is likely to fail at some | -| point before the maximum file link count is achieved. | -| | -| The original parent pointer design was too unstable for something like | -| a file system repair to depend on. | -| Allison Henderson, Chandan Babu, and Catherine Hoang are working on a | -| second implementation that solves all shortcomings of the first. | -| During 2022, Allison introduced log intent items to track physical | -| manipulations of the extended attribute structures. | -| This solves the referential integrity problem by making it possible to | -| commit a dirent update and a parent pointer update in the same | -| transaction. | -| Chandan increased the maximum extent counts of both data and attribute | -| forks, thereby ensuring that the extended attribute structure can grow | -| to handle the maximum hardlink count of any file. | -+--------------------------------------------------------------------------+ - -Case Study: Repairing Directories with Parent Pointers -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Directory rebuilding uses a :ref:`coordinated inode scan ` and -a :ref:`directory entry live update hook ` as follows: - -1. Set up a temporary directory for generating the new directory structure, - an xfblob for storing entry names, and an xfarray for stashing directory - updates. - -2. Set up an inode scanner and hook into the directory entry code to receive - updates on directory operations. - -3. For each parent pointer found in each file scanned, decide if the parent - pointer references the directory of interest. - If so: - - a. Stash an addname entry for this dirent in the xfarray for later. - - b. When finished scanning that file, flush the stashed updates to the - temporary directory. - -4. For each live directory update received via the hook, decide if the child - has already been scanned. - If so: - - a. Stash an addname or removename entry for this dirent update in the - xfarray for later. - We cannot write directly to the temporary directory because hook - functions are not allowed to modify filesystem metadata. - Instead, we stash updates in the xfarray and rely on the scanner thread - to apply the stashed updates to the temporary directory. - -5. When the scan is complete, atomically swap the contents of the temporary - directory and the directory being repaired. - The temporary directory now contains the damaged directory structure. - -6. Reap the temporary directory. - -7. Update the dirent position field of parent pointers as necessary. - This may require the queuing of a substantial number of xattr log intent - items. - -The proposed patchset is the -`parent pointers directory repair -`_ -series. - -**Unresolved Question**: How will repair ensure that the ``dirent_pos`` fields -match in the reconstructed directory? - -*Answer*: There are a few ways to solve this problem: - -1. The field could be designated advisory, since the other three values are - sufficient to find the entry in the parent. - However, this makes indexed key lookup impossible while repairs are ongoing. - -2. We could allow creating directory entries at specified offsets, which solves - the referential integrity problem but runs the risk that dirent creation - will fail due to conflicts with the free space in the directory. - - These conflicts could be resolved by appending the directory entry and - amending the xattr code to support updating an xattr key and reindexing the - dabtree, though this would have to be performed with the parent directory - still locked. - -3. Same as above, but remove the old parent pointer entry and add a new one - atomically. - -4. Change the ondisk xattr format to ``(parent_inum, name) → (parent_gen)``, - which would provide the attr name uniqueness that we require, without - forcing repair code to update the dirent position. - Unfortunately, this requires changes to the xattr code to support attr - names as long as 263 bytes. - -5. Change the ondisk xattr format to ``(parent_inum, hash(name)) → - (name, parent_gen)``. - If the hash is sufficiently resistant to collisions (e.g. sha256) then - this should provide the attr name uniqueness that we require. - Names shorter than 247 bytes could be stored directly. - -Discussion is ongoing under the `parent pointers patch deluge -`_. - -Case Study: Repairing Parent Pointers -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Online reconstruction of a file's parent pointer information works similarly to -directory reconstruction: - -1. Set up a temporary file for generating a new extended attribute structure, - an `xfblob` for storing parent pointer names, and an xfarray for - stashing parent pointer updates. - -2. Set up an inode scanner and hook into the directory entry code to receive - updates on directory operations. - -3. For each directory entry found in each directory scanned, decide if the - dirent references the file of interest. - If so: - - a. Stash an addpptr entry for this parent pointer in the xfblob and xfarray - for later. - - b. When finished scanning the directory, flush the stashed updates to the - temporary directory. - -4. For each live directory update received via the hook, decide if the parent - has already been scanned. - If so: - - a. Stash an addpptr or removepptr entry for this dirent update in the - xfarray for later. - We cannot write parent pointers directly to the temporary file because - hook functions are not allowed to modify filesystem metadata. - Instead, we stash updates in the xfarray and rely on the scanner thread - to apply the stashed parent pointer updates to the temporary file. - -5. Copy all non-parent pointer extended attributes to the temporary file. - -6. When the scan is complete, atomically swap the attribute fork of the - temporary file and the file being repaired. - The temporary file now contains the damaged extended attribute structure. - -7. Reap the temporary file. - -The proposed patchset is the -`parent pointers repair -`_ -series. - -Digression: Offline Checking of Parent Pointers -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Examining parent pointers in offline repair works differently because corrupt -files are erased long before directory tree connectivity checks are performed. -Parent pointer checks are therefore a second pass to be added to the existing -connectivity checks: - -1. After the set of surviving files has been established (i.e. phase 6), - walk the surviving directories of each AG in the filesystem. - This is already performed as part of the connectivity checks. - -2. For each directory entry found, record the name in an xfblob, and store - ``(child_ag_inum, parent_inum, parent_gen, dirent_pos)`` tuples in a - per-AG in-memory slab. - -3. For each AG in the filesystem, - - a. Sort the per-AG tuples in order of child_ag_inum, parent_inum, and - dirent_pos. - - b. For each inode in the AG, - - 1. Scan the inode for parent pointers. - Record the names in a per-file xfblob, and store ``(parent_inum, - parent_gen, dirent_pos)`` tuples in a per-file slab. - - 2. Sort the per-file tuples in order of parent_inum, and dirent_pos. - - 3. Position one slab cursor at the start of the inode's records in the - per-AG tuple slab. - This should be trivial since the per-AG tuples are in child inumber - order. - - 4. Position a second slab cursor at the start of the per-file tuple slab. - - 5. Iterate the two cursors in lockstep, comparing the parent_ino and - dirent_pos fields of the records under each cursor. - - a. Tuples in the per-AG list but not the per-file list are missing and - need to be written to the inode. - - b. Tuples in the per-file list but not the per-AG list are dangling - and need to be removed from the inode. - - c. For tuples in both lists, update the parent_gen and name components - of the parent pointer if necessary. - -4. Move on to examining link counts, as we do today. - -The proposed patchset is the -`offline parent pointers repair -`_ -series. - -Rebuilding directories from parent pointers in offline repair is very -challenging because it currently uses a single-pass scan of the filesystem -during phase 3 to decide which files are corrupt enough to be zapped. -This scan would have to be converted into a multi-pass scan: - -1. The first pass of the scan zaps corrupt inodes, forks, and attributes - much as it does now. - Corrupt directories are noted but not zapped. - -2. The next pass records parent pointers pointing to the directories noted - as being corrupt in the first pass. - This second pass may have to happen after the phase 4 scan for duplicate - blocks, if phase 4 is also capable of zapping directories. - -3. The third pass resets corrupt directories to an empty shortform directory. - Free space metadata has not been ensured yet, so repair cannot yet use the - directory building code in libxfs. - -4. At the start of phase 6, space metadata have been rebuilt. - Use the parent pointer information recorded during step 2 to reconstruct - the dirents and add them to the now-empty directories. - -This code has not yet been constructed. - -.. _orphanage: - -The Orphanage -------------- - -Filesystems present files as a directed, and hopefully acyclic, graph. -In other words, a tree. -The root of the filesystem is a directory, and each entry in a directory points -downwards either to more subdirectories or to non-directory files. -Unfortunately, a disruption in the directory graph pointers result in a -disconnected graph, which makes files impossible to access via regular path -resolution. - -Without parent pointers, the directory parent pointer online scrub code can -detect a dotdot entry pointing to a parent directory that doesn't have a link -back to the child directory and the file link count checker can detect a file -that isn't pointed to by any directory in the filesystem. -If such a file has a positive link count, the file is an orphan. - -With parent pointers, directories can be rebuilt by scanning parent pointers -and parent pointers can be rebuilt by scanning directories. -This should reduce the incidence of files ending up in ``/lost+found``. - -When orphans are found, they should be reconnected to the directory tree. -Offline fsck solves the problem by creating a directory ``/lost+found`` to -serve as an orphanage, and linking orphan files into the orphanage by using the -inumber as the name. -Reparenting a file to the orphanage does not reset any of its permissions or -ACLs. - -This process is more involved in the kernel than it is in userspace. -The directory and file link count repair setup functions must use the regular -VFS mechanisms to create the orphanage directory with all the necessary -security attributes and dentry cache entries, just like a regular directory -tree modification. - -Orphaned files are adopted by the orphanage as follows: - -1. Call ``xrep_orphanage_try_create`` at the start of the scrub setup function - to try to ensure that the lost and found directory actually exists. - This also attaches the orphanage directory to the scrub context. - -2. If the decision is made to reconnect a file, take the IOLOCK of both the - orphanage and the file being reattached. - The ``xrep_orphanage_iolock_two`` function follows the inode locking - strategy discussed earlier. - -3. Call ``xrep_orphanage_compute_blkres`` and ``xrep_orphanage_compute_name`` - to compute the new name in the orphanage and the block reservation required. - -4. Use ``xrep_orphanage_adoption_prep`` to reserve resources to the repair - transaction. - -5. Call ``xrep_orphanage_adopt`` to reparent the orphaned file into the lost - and found, and update the kernel dentry cache. - -The proposed patches are in the -`orphanage adoption -`_ -series. - -6. Userspace Algorithms and Data Structures -=========================================== - -This section discusses the key algorithms and data structures of the userspace -program, ``xfs_scrub``, that provide the ability to drive metadata checks and -repairs in the kernel, verify file data, and look for other potential problems. - -.. _scrubcheck: - -Checking Metadata ------------------ - -Recall the :ref:`phases of fsck work` outlined earlier. -That structure follows naturally from the data dependencies designed into the -filesystem from its beginnings in 1993. -In XFS, there are several groups of metadata dependencies: - -a. Filesystem summary counts depend on consistency within the inode indices, - the allocation group space btrees, and the realtime volume space - information. - -b. Quota resource counts depend on consistency within the quota file data - forks, inode indices, inode records, and the forks of every file on the - system. - -c. The naming hierarchy depends on consistency within the directory and - extended attribute structures. - This includes file link counts. - -d. Directories, extended attributes, and file data depend on consistency within - the file forks that map directory and extended attribute data to physical - storage media. - -e. The file forks depends on consistency within inode records and the space - metadata indices of the allocation groups and the realtime volume. - This includes quota and realtime metadata files. - -f. Inode records depends on consistency within the inode metadata indices. - -g. Realtime space metadata depend on the inode records and data forks of the - realtime metadata inodes. - -h. The allocation group metadata indices (free space, inodes, reference count, - and reverse mapping btrees) depend on consistency within the AG headers and - between all the AG metadata btrees. - -i. ``xfs_scrub`` depends on the filesystem being mounted and kernel support - for online fsck functionality. - -Therefore, a metadata dependency graph is a convenient way to schedule checking -operations in the ``xfs_scrub`` program: - -- Phase 1 checks that the provided path maps to an XFS filesystem and detect - the kernel's scrubbing abilities, which validates group (i). - -- Phase 2 scrubs groups (g) and (h) in parallel using a threaded workqueue. - -- Phase 3 scans inodes in parallel. - For each inode, groups (f), (e), and (d) are checked, in that order. - -- Phase 4 repairs everything in groups (i) through (d) so that phases 5 and 6 - may run reliably. - -- Phase 5 starts by checking groups (b) and (c) in parallel before moving on - to checking names. - -- Phase 6 depends on groups (i) through (b) to find file data blocks to verify, - to read them, and to report which blocks of which files are affected. - -- Phase 7 checks group (a), having validated everything else. - -Notice that the data dependencies between groups are enforced by the structure -of the program flow. - -Parallel Inode Scans --------------------- - -An XFS filesystem can easily contain hundreds of millions of inodes. -Given that XFS targets installations with large high-performance storage, -it is desirable to scrub inodes in parallel to minimize runtime, particularly -if the program has been invoked manually from a command line. -This requires careful scheduling to keep the threads as evenly loaded as -possible. - -Early iterations of the ``xfs_scrub`` inode scanner naïvely created a single -workqueue and scheduled a single workqueue item per AG. -Each workqueue item walked the inode btree (with ``XFS_IOC_INUMBERS``) to find -inode chunks and then called bulkstat (``XFS_IOC_BULKSTAT``) to gather enough -information to construct file handles. -The file handle was then passed to a function to generate scrub items for each -metadata object of each inode. -This simple algorithm leads to thread balancing problems in phase 3 if the -filesystem contains one AG with a few large sparse files and the rest of the -AGs contain many smaller files. -The inode scan dispatch function was not sufficiently granular; it should have -been dispatching at the level of individual inodes, or, to constrain memory -consumption, inode btree records. - -Thanks to Dave Chinner, bounded workqueues in userspace enable ``xfs_scrub`` to -avoid this problem with ease by adding a second workqueue. -Just like before, the first workqueue is seeded with one workqueue item per AG, -and it uses INUMBERS to find inode btree chunks. -The second workqueue, however, is configured with an upper bound on the number -of items that can be waiting to be run. -Each inode btree chunk found by the first workqueue's workers are queued to the -second workqueue, and it is this second workqueue that queries BULKSTAT, -creates a file handle, and passes it to a function to generate scrub items for -each metadata object of each inode. -If the second workqueue is too full, the workqueue add function blocks the -first workqueue's workers until the backlog eases. -This doesn't completely solve the balancing problem, but reduces it enough to -move on to more pressing issues. - -The proposed patchsets are the scrub -`performance tweaks -`_ -and the -`inode scan rebalance -`_ -series. - -.. _scrubrepair: - -Scheduling Repairs ------------------- - -During phase 2, corruptions and inconsistencies reported in any AGI header or -inode btree are repaired immediately, because phase 3 relies on proper -functioning of the inode indices to find inodes to scan. -Failed repairs are rescheduled to phase 4. -Problems reported in any other space metadata are deferred to phase 4. -Optimization opportunities are always deferred to phase 4, no matter their -origin. - -During phase 3, corruptions and inconsistencies reported in any part of a -file's metadata are repaired immediately if all space metadata were validated -during phase 2. -Repairs that fail or cannot be repaired immediately are scheduled for phase 4. - -In the original design of ``xfs_scrub``, it was thought that repairs would be -so infrequent that the ``struct xfs_scrub_metadata`` objects used to -communicate with the kernel could also be used as the primary object to -schedule repairs. -With recent increases in the number of optimizations possible for a given -filesystem object, it became much more memory-efficient to track all eligible -repairs for a given filesystem object with a single repair item. -Each repair item represents a single lockable object -- AGs, metadata files, -individual inodes, or a class of summary information. - -Phase 4 is responsible for scheduling a lot of repair work in as quick a -manner as is practical. -The :ref:`data dependencies ` outlined earlier still apply, which -means that ``xfs_scrub`` must try to complete the repair work scheduled by -phase 2 before trying repair work scheduled by phase 3. -The repair process is as follows: - -1. Start a round of repair with a workqueue and enough workers to keep the CPUs - as busy as the user desires. - - a. For each repair item queued by phase 2, - - i. Ask the kernel to repair everything listed in the repair item for a - given filesystem object. - - ii. Make a note if the kernel made any progress in reducing the number - of repairs needed for this object. - - iii. If the object no longer requires repairs, revalidate all metadata - associated with this object. - If the revalidation succeeds, drop the repair item. - If not, requeue the item for more repairs. - - b. If any repairs were made, jump back to 1a to retry all the phase 2 items. - - c. For each repair item queued by phase 3, - - i. Ask the kernel to repair everything listed in the repair item for a - given filesystem object. - - ii. Make a note if the kernel made any progress in reducing the number - of repairs needed for this object. - - iii. If the object no longer requires repairs, revalidate all metadata - associated with this object. - If the revalidation succeeds, drop the repair item. - If not, requeue the item for more repairs. - - d. If any repairs were made, jump back to 1c to retry all the phase 3 items. - -2. If step 1 made any repair progress of any kind, jump back to step 1 to start - another round of repair. - -3. If there are items left to repair, run them all serially one more time. - Complain if the repairs were not successful, since this is the last chance - to repair anything. - -Corruptions and inconsistencies encountered during phases 5 and 7 are repaired -immediately. -Corrupt file data blocks reported by phase 6 cannot be recovered by the -filesystem. - -The proposed patchsets are the -`repair warning improvements -`_, -refactoring of the -`repair data dependency -`_ -and -`object tracking -`_, -and the -`repair scheduling -`_ -improvement series. - -Checking Names for Confusable Unicode Sequences ------------------------------------------------ - -If ``xfs_scrub`` succeeds in validating the filesystem metadata by the end of -phase 4, it moves on to phase 5, which checks for suspicious looking names in -the filesystem. -These names consist of the filesystem label, names in directory entries, and -the names of extended attributes. -Like most Unix filesystems, XFS imposes the sparest of constraints on the -contents of a name: - -- Slashes and null bytes are not allowed in directory entries. - -- Null bytes are not allowed in userspace-visible extended attributes. - -- Null bytes are not allowed in the filesystem label. - -Directory entries and attribute keys store the length of the name explicitly -ondisk, which means that nulls are not name terminators. -For this section, the term "naming domain" refers to any place where names are -presented together -- all the names in a directory, or all the attributes of a -file. - -Although the Unix naming constraints are very permissive, the reality of most -modern-day Linux systems is that programs work with Unicode character code -points to support international languages. -These programs typically encode those code points in UTF-8 when interfacing -with the C library because the kernel expects null-terminated names. -In the common case, therefore, names found in an XFS filesystem are actually -UTF-8 encoded Unicode data. - -To maximize its expressiveness, the Unicode standard defines separate control -points for various characters that render similarly or identically in writing -systems around the world. -For example, the character "Cyrillic Small Letter A" U+0430 "а" often renders -identically to "Latin Small Letter A" U+0061 "a". - -The standard also permits characters to be constructed in multiple ways -- -either by using a defined code point, or by combining one code point with -various combining marks. -For example, the character "Angstrom Sign U+212B "Å" can also be expressed -as "Latin Capital Letter A" U+0041 "A" followed by "Combining Ring Above" -U+030A "◌̊". -Both sequences render identically. - -Like the standards that preceded it, Unicode also defines various control -characters to alter the presentation of text. -For example, the character "Right-to-Left Override" U+202E can trick some -programs into rendering "moo\\xe2\\x80\\xaegnp.txt" as "mootxt.png". -A second category of rendering problems involves whitespace characters. -If the character "Zero Width Space" U+200B is encountered in a file name, the -name will render identically to a name that does not have the zero width -space. - -If two names within a naming domain have different byte sequences but render -identically, a user may be confused by it. -The kernel, in its indifference to upper level encoding schemes, permits this. -Most filesystem drivers persist the byte sequence names that are given to them -by the VFS. - -Techniques for detecting confusable names are explained in great detail in -sections 4 and 5 of the -`Unicode Security Mechanisms `_ -document. -When ``xfs_scrub`` detects UTF-8 encoding in use on a system, it uses the -Unicode normalization form NFD in conjunction with the confusable name -detection component of -`libicu `_ -to identify names with a directory or within a file's extended attributes that -could be confused for each other. -Names are also checked for control characters, non-rendering characters, and -mixing of bidirectional characters. -All of these potential issues are reported to the system administrator during -phase 5. - -Media Verification of File Data Extents ---------------------------------------- - -The system administrator can elect to initiate a media scan of all file data -blocks. -This scan after validation of all filesystem metadata (except for the summary -counters) as phase 6. -The scan starts by calling ``FS_IOC_GETFSMAP`` to scan the filesystem space map -to find areas that are allocated to file data fork extents. -Gaps between data fork extents that are smaller than 64k are treated as if -they were data fork extents to reduce the command setup overhead. -When the space map scan accumulates a region larger than 32MB, a media -verification request is sent to the disk as a directio read of the raw block -device. - -If the verification read fails, ``xfs_scrub`` retries with single-block reads -to narrow down the failure to the specific region of the media and recorded. -When it has finished issuing verification requests, it again uses the space -mapping ioctl to map the recorded media errors back to metadata structures -and report what has been lost. -For media errors in blocks owned by files, parent pointers can be used to -construct file paths from inode numbers for user-friendly reporting. - -7. Conclusion and Future Work -============================= - -It is hoped that the reader of this document has followed the designs laid out -in this document and now has some familiarity with how XFS performs online -rebuilding of its metadata indices, and how filesystem users can interact with -that functionality. -Although the scope of this work is daunting, it is hoped that this guide will -make it easier for code readers to understand what has been built, for whom it -has been built, and why. -Please feel free to contact the XFS mailing list with questions. - -FIEXCHANGE_RANGE ----------------- - -As discussed earlier, a second frontend to the atomic extent swap mechanism is -a new ioctl call that userspace programs can use to commit updates to files -atomically. -This frontend has been out for review for several years now, though the -necessary refinements to online repair and lack of customer demand mean that -the proposal has not been pushed very hard. - -Extent Swapping with Regular User Files -``````````````````````````````````````` - -As mentioned earlier, XFS has long had the ability to swap extents between -files, which is used almost exclusively by ``xfs_fsr`` to defragment files. -The earliest form of this was the fork swap mechanism, where the entire -contents of data forks could be exchanged between two files by exchanging the -raw bytes in each inode fork's immediate area. -When XFS v5 came along with self-describing metadata, this old mechanism grew -some log support to continue rewriting the owner fields of BMBT blocks during -log recovery. -When the reverse mapping btree was later added to XFS, the only way to maintain -the consistency of the fork mappings with the reverse mapping index was to -develop an iterative mechanism that used deferred bmap and rmap operations to -swap mappings one at a time. -This mechanism is identical to steps 2-3 from the procedure above except for -the new tracking items, because the atomic extent swap mechanism is an -iteration of an existing mechanism and not something totally novel. -For the narrow case of file defragmentation, the file contents must be -identical, so the recovery guarantees are not much of a gain. - -Atomic extent swapping is much more flexible than the existing swapext -implementations because it can guarantee that the caller never sees a mix of -old and new contents even after a crash, and it can operate on two arbitrary -file fork ranges. -The extra flexibility enables several new use cases: - -- **Atomic commit of file writes**: A userspace process opens a file that it - wants to update. - Next, it opens a temporary file and calls the file clone operation to reflink - the first file's contents into the temporary file. - Writes to the original file should instead be written to the temporary file. - Finally, the process calls the atomic extent swap system call - (``FIEXCHANGE_RANGE``) to exchange the file contents, thereby committing all - of the updates to the original file, or none of them. - -.. _swapext_if_unchanged: - -- **Transactional file updates**: The same mechanism as above, but the caller - only wants the commit to occur if the original file's contents have not - changed. - To make this happen, the calling process snapshots the file modification and - change timestamps of the original file before reflinking its data to the - temporary file. - When the program is ready to commit the changes, it passes the timestamps - into the kernel as arguments to the atomic extent swap system call. - The kernel only commits the changes if the provided timestamps match the - original file. - -- **Emulation of atomic block device writes**: Export a block device with a - logical sector size matching the filesystem block size to force all writes - to be aligned to the filesystem block size. - Stage all writes to a temporary file, and when that is complete, call the - atomic extent swap system call with a flag to indicate that holes in the - temporary file should be ignored. - This emulates an atomic device write in software, and can support arbitrary - scattered writes. - -Vectorized Scrub ----------------- - -As it turns out, the :ref:`refactoring ` of repair items mentioned -earlier was a catalyst for enabling a vectorized scrub system call. -Since 2018, the cost of making a kernel call has increased considerably on some -systems to mitigate the effects of speculative execution attacks. -This incentivizes program authors to make as few system calls as possible to -reduce the number of times an execution path crosses a security boundary. - -With vectorized scrub, userspace pushes to the kernel the identity of a -filesystem object, a list of scrub types to run against that object, and a -simple representation of the data dependencies between the selected scrub -types. -The kernel executes as much of the caller's plan as it can until it hits a -dependency that cannot be satisfied due to a corruption, and tells userspace -how much was accomplished. -It is hoped that ``io_uring`` will pick up enough of this functionality that -online fsck can use that instead of adding a separate vectored scrub system -call to XFS. - -The relevant patchsets are the -`kernel vectorized scrub -`_ -and -`userspace vectorized scrub -`_ -series. - -Quality of Service Targets for Scrub ------------------------------------- - -One serious shortcoming of the online fsck code is that the amount of time that -it can spend in the kernel holding resource locks is basically unbounded. -Userspace is allowed to send a fatal signal to the process which will cause -``xfs_scrub`` to exit when it reaches a good stopping point, but there's no way -for userspace to provide a time budget to the kernel. -Given that the scrub codebase has helpers to detect fatal signals, it shouldn't -be too much work to allow userspace to specify a timeout for a scrub/repair -operation and abort the operation if it exceeds budget. -However, most repair functions have the property that once they begin to touch -ondisk metadata, the operation cannot be cancelled cleanly, after which a QoS -timeout is no longer useful. - -Defragmenting Free Space ------------------------- - -Over the years, many XFS users have requested the creation of a program to -clear a portion of the physical storage underlying a filesystem so that it -becomes a contiguous chunk of free space. -Call this free space defragmenter ``clearspace`` for short. - -The first piece the ``clearspace`` program needs is the ability to read the -reverse mapping index from userspace. -This already exists in the form of the ``FS_IOC_GETFSMAP`` ioctl. -The second piece it needs is a new fallocate mode -(``FALLOC_FL_MAP_FREE_SPACE``) that allocates the free space in a region and -maps it to a file. -Call this file the "space collector" file. -The third piece is the ability to force an online repair. - -To clear all the metadata out of a portion of physical storage, clearspace -uses the new fallocate map-freespace call to map any free space in that region -to the space collector file. -Next, clearspace finds all metadata blocks in that region by way of -``GETFSMAP`` and issues forced repair requests on the data structure. -This often results in the metadata being rebuilt somewhere that is not being -cleared. -After each relocation, clearspace calls the "map free space" function again to -collect any newly freed space in the region being cleared. - -To clear all the file data out of a portion of the physical storage, clearspace -uses the FSMAP information to find relevant file data blocks. -Having identified a good target, it uses the ``FICLONERANGE`` call on that part -of the file to try to share the physical space with a dummy file. -Cloning the extent means that the original owners cannot overwrite the -contents; any changes will be written somewhere else via copy-on-write. -Clearspace makes its own copy of the frozen extent in an area that is not being -cleared, and uses ``FIEDEUPRANGE`` (or the :ref:`atomic extent swap -` feature) to change the target file's data extent -mapping away from the area being cleared. -When all other mappings have been moved, clearspace reflinks the space into the -space collector file so that it becomes unavailable. - -There are further optimizations that could apply to the above algorithm. -To clear a piece of physical storage that has a high sharing factor, it is -strongly desirable to retain this sharing factor. -In fact, these extents should be moved first to maximize sharing factor after -the operation completes. -To make this work smoothly, clearspace needs a new ioctl -(``FS_IOC_GETREFCOUNTS``) to report reference count information to userspace. -With the refcount information exposed, clearspace can quickly find the longest, -most shared data extents in the filesystem, and target them first. - -**Future Work Question**: How might the filesystem move inode chunks? - -*Answer*: To move inode chunks, Dave Chinner constructed a prototype program -that creates a new file with the old contents and then locklessly runs around -the filesystem updating directory entries. -The operation cannot complete if the filesystem goes down. -That problem isn't totally insurmountable: create an inode remapping table -hidden behind a jump label, and a log item that tracks the kernel walking the -filesystem to update directory entries. -The trouble is, the kernel can't do anything about open files, since it cannot -revoke them. - -**Future Work Question**: Can static keys be used to minimize the cost of -supporting ``revoke()`` on XFS files? - -*Answer*: Yes. -Until the first revocation, the bailout code need not be in the call path at -all. - -The relevant patchsets are the -`kernel freespace defrag -`_ -and -`userspace freespace defrag -`_ -series. - -Shrinking Filesystems ---------------------- - -Removing the end of the filesystem ought to be a simple matter of evacuating -the data and metadata at the end of the filesystem, and handing the freed space -to the shrink code. -That requires an evacuation of the space at end of the filesystem, which is a -use of free space defragmentation! diff --git a/Documentation/filesystems/xfs-self-describing-metadata.rst b/Documentation/filesystems/xfs-self-describing-metadata.rst deleted file mode 100644 index a10c4ae6955e7a..00000000000000 --- a/Documentation/filesystems/xfs-self-describing-metadata.rst +++ /dev/null @@ -1,353 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 -.. _xfs_self_describing_metadata: - -============================ -XFS Self Describing Metadata -============================ - -Introduction -============ - -The largest scalability problem facing XFS is not one of algorithmic -scalability, but of verification of the filesystem structure. Scalabilty of the -structures and indexes on disk and the algorithms for iterating them are -adequate for supporting PB scale filesystems with billions of inodes, however it -is this very scalability that causes the verification problem. - -Almost all metadata on XFS is dynamically allocated. The only fixed location -metadata is the allocation group headers (SB, AGF, AGFL and AGI), while all -other metadata structures need to be discovered by walking the filesystem -structure in different ways. While this is already done by userspace tools for -validating and repairing the structure, there are limits to what they can -verify, and this in turn limits the supportable size of an XFS filesystem. - -For example, it is entirely possible to manually use xfs_db and a bit of -scripting to analyse the structure of a 100TB filesystem when trying to -determine the root cause of a corruption problem, but it is still mainly a -manual task of verifying that things like single bit errors or misplaced writes -weren't the ultimate cause of a corruption event. It may take a few hours to a -few days to perform such forensic analysis, so for at this scale root cause -analysis is entirely possible. - -However, if we scale the filesystem up to 1PB, we now have 10x as much metadata -to analyse and so that analysis blows out towards weeks/months of forensic work. -Most of the analysis work is slow and tedious, so as the amount of analysis goes -up, the more likely that the cause will be lost in the noise. Hence the primary -concern for supporting PB scale filesystems is minimising the time and effort -required for basic forensic analysis of the filesystem structure. - - -Self Describing Metadata -======================== - -One of the problems with the current metadata format is that apart from the -magic number in the metadata block, we have no other way of identifying what it -is supposed to be. We can't even identify if it is the right place. Put simply, -you can't look at a single metadata block in isolation and say "yes, it is -supposed to be there and the contents are valid". - -Hence most of the time spent on forensic analysis is spent doing basic -verification of metadata values, looking for values that are in range (and hence -not detected by automated verification checks) but are not correct. Finding and -understanding how things like cross linked block lists (e.g. sibling -pointers in a btree end up with loops in them) are the key to understanding what -went wrong, but it is impossible to tell what order the blocks were linked into -each other or written to disk after the fact. - -Hence we need to record more information into the metadata to allow us to -quickly determine if the metadata is intact and can be ignored for the purpose -of analysis. We can't protect against every possible type of error, but we can -ensure that common types of errors are easily detectable. Hence the concept of -self describing metadata. - -The first, fundamental requirement of self describing metadata is that the -metadata object contains some form of unique identifier in a well known -location. This allows us to identify the expected contents of the block and -hence parse and verify the metadata object. IF we can't independently identify -the type of metadata in the object, then the metadata doesn't describe itself -very well at all! - -Luckily, almost all XFS metadata has magic numbers embedded already - only the -AGFL, remote symlinks and remote attribute blocks do not contain identifying -magic numbers. Hence we can change the on-disk format of all these objects to -add more identifying information and detect this simply by changing the magic -numbers in the metadata objects. That is, if it has the current magic number, -the metadata isn't self identifying. If it contains a new magic number, it is -self identifying and we can do much more expansive automated verification of the -metadata object at runtime, during forensic analysis or repair. - -As a primary concern, self describing metadata needs some form of overall -integrity checking. We cannot trust the metadata if we cannot verify that it has -not been changed as a result of external influences. Hence we need some form of -integrity check, and this is done by adding CRC32c validation to the metadata -block. If we can verify the block contains the metadata it was intended to -contain, a large amount of the manual verification work can be skipped. - -CRC32c was selected as metadata cannot be more than 64k in length in XFS and -hence a 32 bit CRC is more than sufficient to detect multi-bit errors in -metadata blocks. CRC32c is also now hardware accelerated on common CPUs so it is -fast. So while CRC32c is not the strongest of possible integrity checks that -could be used, it is more than sufficient for our needs and has relatively -little overhead. Adding support for larger integrity fields and/or algorithms -does really provide any extra value over CRC32c, but it does add a lot of -complexity and so there is no provision for changing the integrity checking -mechanism. - -Self describing metadata needs to contain enough information so that the -metadata block can be verified as being in the correct place without needing to -look at any other metadata. This means it needs to contain location information. -Just adding a block number to the metadata is not sufficient to protect against -mis-directed writes - a write might be misdirected to the wrong LUN and so be -written to the "correct block" of the wrong filesystem. Hence location -information must contain a filesystem identifier as well as a block number. - -Another key information point in forensic analysis is knowing who the metadata -block belongs to. We already know the type, the location, that it is valid -and/or corrupted, and how long ago that it was last modified. Knowing the owner -of the block is important as it allows us to find other related metadata to -determine the scope of the corruption. For example, if we have a extent btree -object, we don't know what inode it belongs to and hence have to walk the entire -filesystem to find the owner of the block. Worse, the corruption could mean that -no owner can be found (i.e. it's an orphan block), and so without an owner field -in the metadata we have no idea of the scope of the corruption. If we have an -owner field in the metadata object, we can immediately do top down validation to -determine the scope of the problem. - -Different types of metadata have different owner identifiers. For example, -directory, attribute and extent tree blocks are all owned by an inode, while -freespace btree blocks are owned by an allocation group. Hence the size and -contents of the owner field are determined by the type of metadata object we are -looking at. The owner information can also identify misplaced writes (e.g. -freespace btree block written to the wrong AG). - -Self describing metadata also needs to contain some indication of when it was -written to the filesystem. One of the key information points when doing forensic -analysis is how recently the block was modified. Correlation of set of corrupted -metadata blocks based on modification times is important as it can indicate -whether the corruptions are related, whether there's been multiple corruption -events that lead to the eventual failure, and even whether there are corruptions -present that the run-time verification is not detecting. - -For example, we can determine whether a metadata object is supposed to be free -space or still allocated if it is still referenced by its owner by looking at -when the free space btree block that contains the block was last written -compared to when the metadata object itself was last written. If the free space -block is more recent than the object and the object's owner, then there is a -very good chance that the block should have been removed from the owner. - -To provide this "written timestamp", each metadata block gets the Log Sequence -Number (LSN) of the most recent transaction it was modified on written into it. -This number will always increase over the life of the filesystem, and the only -thing that resets it is running xfs_repair on the filesystem. Further, by use of -the LSN we can tell if the corrupted metadata all belonged to the same log -checkpoint and hence have some idea of how much modification occurred between -the first and last instance of corrupt metadata on disk and, further, how much -modification occurred between the corruption being written and when it was -detected. - -Runtime Validation -================== - -Validation of self-describing metadata takes place at runtime in two places: - - - immediately after a successful read from disk - - immediately prior to write IO submission - -The verification is completely stateless - it is done independently of the -modification process, and seeks only to check that the metadata is what it says -it is and that the metadata fields are within bounds and internally consistent. -As such, we cannot catch all types of corruption that can occur within a block -as there may be certain limitations that operational state enforces of the -metadata, or there may be corruption of interblock relationships (e.g. corrupted -sibling pointer lists). Hence we still need stateful checking in the main code -body, but in general most of the per-field validation is handled by the -verifiers. - -For read verification, the caller needs to specify the expected type of metadata -that it should see, and the IO completion process verifies that the metadata -object matches what was expected. If the verification process fails, then it -marks the object being read as EFSCORRUPTED. The caller needs to catch this -error (same as for IO errors), and if it needs to take special action due to a -verification error it can do so by catching the EFSCORRUPTED error value. If we -need more discrimination of error type at higher levels, we can define new -error numbers for different errors as necessary. - -The first step in read verification is checking the magic number and determining -whether CRC validating is necessary. If it is, the CRC32c is calculated and -compared against the value stored in the object itself. Once this is validated, -further checks are made against the location information, followed by extensive -object specific metadata validation. If any of these checks fail, then the -buffer is considered corrupt and the EFSCORRUPTED error is set appropriately. - -Write verification is the opposite of the read verification - first the object -is extensively verified and if it is OK we then update the LSN from the last -modification made to the object, After this, we calculate the CRC and insert it -into the object. Once this is done the write IO is allowed to continue. If any -error occurs during this process, the buffer is again marked with a EFSCORRUPTED -error for the higher layers to catch. - -Structures -========== - -A typical on-disk structure needs to contain the following information:: - - struct xfs_ondisk_hdr { - __be32 magic; /* magic number */ - __be32 crc; /* CRC, not logged */ - uuid_t uuid; /* filesystem identifier */ - __be64 owner; /* parent object */ - __be64 blkno; /* location on disk */ - __be64 lsn; /* last modification in log, not logged */ - }; - -Depending on the metadata, this information may be part of a header structure -separate to the metadata contents, or may be distributed through an existing -structure. The latter occurs with metadata that already contains some of this -information, such as the superblock and AG headers. - -Other metadata may have different formats for the information, but the same -level of information is generally provided. For example: - - - short btree blocks have a 32 bit owner (ag number) and a 32 bit block - number for location. The two of these combined provide the same - information as @owner and @blkno in eh above structure, but using 8 - bytes less space on disk. - - - directory/attribute node blocks have a 16 bit magic number, and the - header that contains the magic number has other information in it as - well. hence the additional metadata headers change the overall format - of the metadata. - -A typical buffer read verifier is structured as follows:: - - #define XFS_FOO_CRC_OFF offsetof(struct xfs_ondisk_hdr, crc) - - static void - xfs_foo_read_verify( - struct xfs_buf *bp) - { - struct xfs_mount *mp = bp->b_mount; - - if ((xfs_sb_version_hascrc(&mp->m_sb) && - !xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length), - XFS_FOO_CRC_OFF)) || - !xfs_foo_verify(bp)) { - XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); - xfs_buf_ioerror(bp, EFSCORRUPTED); - } - } - -The code ensures that the CRC is only checked if the filesystem has CRCs enabled -by checking the superblock of the feature bit, and then if the CRC verifies OK -(or is not needed) it verifies the actual contents of the block. - -The verifier function will take a couple of different forms, depending on -whether the magic number can be used to determine the format of the block. In -the case it can't, the code is structured as follows:: - - static bool - xfs_foo_verify( - struct xfs_buf *bp) - { - struct xfs_mount *mp = bp->b_mount; - struct xfs_ondisk_hdr *hdr = bp->b_addr; - - if (hdr->magic != cpu_to_be32(XFS_FOO_MAGIC)) - return false; - - if (!xfs_sb_version_hascrc(&mp->m_sb)) { - if (!uuid_equal(&hdr->uuid, &mp->m_sb.sb_uuid)) - return false; - if (bp->b_bn != be64_to_cpu(hdr->blkno)) - return false; - if (hdr->owner == 0) - return false; - } - - /* object specific verification checks here */ - - return true; - } - -If there are different magic numbers for the different formats, the verifier -will look like:: - - static bool - xfs_foo_verify( - struct xfs_buf *bp) - { - struct xfs_mount *mp = bp->b_mount; - struct xfs_ondisk_hdr *hdr = bp->b_addr; - - if (hdr->magic == cpu_to_be32(XFS_FOO_CRC_MAGIC)) { - if (!uuid_equal(&hdr->uuid, &mp->m_sb.sb_uuid)) - return false; - if (bp->b_bn != be64_to_cpu(hdr->blkno)) - return false; - if (hdr->owner == 0) - return false; - } else if (hdr->magic != cpu_to_be32(XFS_FOO_MAGIC)) - return false; - - /* object specific verification checks here */ - - return true; - } - -Write verifiers are very similar to the read verifiers, they just do things in -the opposite order to the read verifiers. A typical write verifier:: - - static void - xfs_foo_write_verify( - struct xfs_buf *bp) - { - struct xfs_mount *mp = bp->b_mount; - struct xfs_buf_log_item *bip = bp->b_fspriv; - - if (!xfs_foo_verify(bp)) { - XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); - xfs_buf_ioerror(bp, EFSCORRUPTED); - return; - } - - if (!xfs_sb_version_hascrc(&mp->m_sb)) - return; - - - if (bip) { - struct xfs_ondisk_hdr *hdr = bp->b_addr; - hdr->lsn = cpu_to_be64(bip->bli_item.li_lsn); - } - xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length), XFS_FOO_CRC_OFF); - } - -This will verify the internal structure of the metadata before we go any -further, detecting corruptions that have occurred as the metadata has been -modified in memory. If the metadata verifies OK, and CRCs are enabled, we then -update the LSN field (when it was last modified) and calculate the CRC on the -metadata. Once this is done, we can issue the IO. - -Inodes and Dquots -================= - -Inodes and dquots are special snowflakes. They have per-object CRC and -self-identifiers, but they are packed so that there are multiple objects per -buffer. Hence we do not use per-buffer verifiers to do the work of per-object -verification and CRC calculations. The per-buffer verifiers simply perform basic -identification of the buffer - that they contain inodes or dquots, and that -there are magic numbers in all the expected spots. All further CRC and -verification checks are done when each inode is read from or written back to the -buffer. - -The structure of the verifiers and the identifiers checks is very similar to the -buffer code described above. The only difference is where they are called. For -example, inode read verification is done in xfs_inode_from_disk() when the inode -is first read out of the buffer and the struct xfs_inode is instantiated. The -inode is already extensively verified during writeback in xfs_iflush_int, so the -only addition here is to add the LSN and CRC to the inode as it is copied back -into the buffer. - -XXX: inode unlinked list modification doesn't recalculate the inode CRC! None of -the unlinked list modifications check or update CRCs, neither during unlink nor -log recovery. So, it's gone unnoticed until now. This won't matter immediately - -repair will probably complain about it - but it needs to be fixed. diff --git a/Documentation/filesystems/xfs/index.rst b/Documentation/filesystems/xfs/index.rst new file mode 100644 index 00000000000000..ab66c57a5d18ea --- /dev/null +++ b/Documentation/filesystems/xfs/index.rst @@ -0,0 +1,14 @@ +.. SPDX-License-Identifier: GPL-2.0 + +============================ +XFS Filesystem Documentation +============================ + +.. toctree:: + :maxdepth: 2 + :numbered: + + xfs-delayed-logging-design + xfs-maintainer-entry-profile + xfs-self-describing-metadata + xfs-online-fsck-design diff --git a/Documentation/filesystems/xfs/xfs-delayed-logging-design.rst b/Documentation/filesystems/xfs/xfs-delayed-logging-design.rst new file mode 100644 index 00000000000000..6402ab8e370c81 --- /dev/null +++ b/Documentation/filesystems/xfs/xfs-delayed-logging-design.rst @@ -0,0 +1,1087 @@ +.. SPDX-License-Identifier: GPL-2.0 + +================== +XFS Logging Design +================== + +Preamble +======== + +This document describes the design and algorithms that the XFS journalling +subsystem is based on. This document describes the design and algorithms that +the XFS journalling subsystem is based on so that readers may familiarize +themselves with the general concepts of how transaction processing in XFS works. + +We begin with an overview of transactions in XFS, followed by describing how +transaction reservations are structured and accounted, and then move into how we +guarantee forwards progress for long running transactions with finite initial +reservations bounds. At this point we need to explain how relogging works. With +the basic concepts covered, the design of the delayed logging mechanism is +documented. + + +Introduction +============ + +XFS uses Write Ahead Logging for ensuring changes to the filesystem metadata +are atomic and recoverable. For reasons of space and time efficiency, the +logging mechanisms are varied and complex, combining intents, logical and +physical logging mechanisms to provide the necessary recovery guarantees the +filesystem requires. + +Some objects, such as inodes and dquots, are logged in logical format where the +details logged are made up of the changes to in-core structures rather than +on-disk structures. Other objects - typically buffers - have their physical +changes logged. Long running atomic modifications have individual changes +chained together by intents, ensuring that journal recovery can restart and +finish an operation that was only partially done when the system stopped +functioning. + +The reason for these differences is to keep the amount of log space and CPU time +required to process objects being modified as small as possible and hence the +logging overhead as low as possible. Some items are very frequently modified, +and some parts of objects are more frequently modified than others, so keeping +the overhead of metadata logging low is of prime importance. + +The method used to log an item or chain modifications together isn't +particularly important in the scope of this document. It suffices to know that +the method used for logging a particular object or chaining modifications +together are different and are dependent on the object and/or modification being +performed. The logging subsystem only cares that certain specific rules are +followed to guarantee forwards progress and prevent deadlocks. + + +Transactions in XFS +=================== + +XFS has two types of high level transactions, defined by the type of log space +reservation they take. These are known as "one shot" and "permanent" +transactions. Permanent transaction reservations can take reservations that span +commit boundaries, whilst "one shot" transactions are for a single atomic +modification. + +The type and size of reservation must be matched to the modification taking +place. This means that permanent transactions can be used for one-shot +modifications, but one-shot reservations cannot be used for permanent +transactions. + +In the code, a one-shot transaction pattern looks somewhat like this:: + + tp = xfs_trans_alloc() + + + + xfs_trans_commit(tp); + +As items are modified in the transaction, the dirty regions in those items are +tracked via the transaction handle. Once the transaction is committed, all +resources joined to it are released, along with the remaining unused reservation +space that was taken at the transaction allocation time. + +In contrast, a permanent transaction is made up of multiple linked individual +transactions, and the pattern looks like this:: + + tp = xfs_trans_alloc() + xfs_ilock(ip, XFS_ILOCK_EXCL) + + loop { + xfs_trans_ijoin(tp, 0); + + xfs_trans_log_inode(tp, ip); + xfs_trans_roll(&tp); + } + + xfs_trans_commit(tp); + xfs_iunlock(ip, XFS_ILOCK_EXCL); + +While this might look similar to a one-shot transaction, there is an important +difference: xfs_trans_roll() performs a specific operation that links two +transactions together:: + + ntp = xfs_trans_dup(tp); + xfs_trans_commit(tp); + xfs_trans_reserve(ntp); + +This results in a series of "rolling transactions" where the inode is locked +across the entire chain of transactions. Hence while this series of rolling +transactions is running, nothing else can read from or write to the inode and +this provides a mechanism for complex changes to appear atomic from an external +observer's point of view. + +It is important to note that a series of rolling transactions in a permanent +transaction does not form an atomic change in the journal. While each +individual modification is atomic, the chain is *not atomic*. If we crash half +way through, then recovery will only replay up to the last transactional +modification the loop made that was committed to the journal. + +This affects long running permanent transactions in that it is not possible to +predict how much of a long running operation will actually be recovered because +there is no guarantee of how much of the operation reached stale storage. Hence +if a long running operation requires multiple transactions to fully complete, +the high level operation must use intents and deferred operations to guarantee +recovery can complete the operation once the first transactions is persisted in +the on-disk journal. + + +Transactions are Asynchronous +============================= + +In XFS, all high level transactions are asynchronous by default. This means that +xfs_trans_commit() does not guarantee that the modification has been committed +to stable storage when it returns. Hence when a system crashes, not all the +completed transactions will be replayed during recovery. + +However, the logging subsystem does provide global ordering guarantees, such +that if a specific change is seen after recovery, all metadata modifications +that were committed prior to that change will also be seen. + +For single shot operations that need to reach stable storage immediately, or +ensuring that a long running permanent transaction is fully committed once it is +complete, we can explicitly tag a transaction as synchronous. This will trigger +a "log force" to flush the outstanding committed transactions to stable storage +in the journal and wait for that to complete. + +Synchronous transactions are rarely used, however, because they limit logging +throughput to the IO latency limitations of the underlying storage. Instead, we +tend to use log forces to ensure modifications are on stable storage only when +a user operation requires a synchronisation point to occur (e.g. fsync). + + +Transaction Reservations +======================== + +It has been mentioned a number of times now that the logging subsystem needs to +provide a forwards progress guarantee so that no modification ever stalls +because it can't be written to the journal due to a lack of space in the +journal. This is achieved by the transaction reservations that are made when +a transaction is first allocated. For permanent transactions, these reservations +are maintained as part of the transaction rolling mechanism. + +A transaction reservation provides a guarantee that there is physical log space +available to write the modification into the journal before we start making +modifications to objects and items. As such, the reservation needs to be large +enough to take into account the amount of metadata that the change might need to +log in the worst case. This means that if we are modifying a btree in the +transaction, we have to reserve enough space to record a full leaf-to-root split +of the btree. As such, the reservations are quite complex because we have to +take into account all the hidden changes that might occur. + +For example, a user data extent allocation involves allocating an extent from +free space, which modifies the free space trees. That's two btrees. Inserting +the extent into the inode's extent map might require a split of the extent map +btree, which requires another allocation that can modify the free space trees +again. Then we might have to update reverse mappings, which modifies yet +another btree which might require more space. And so on. Hence the amount of +metadata that a "simple" operation can modify can be quite large. + +This "worst case" calculation provides us with the static "unit reservation" +for the transaction that is calculated at mount time. We must guarantee that the +log has this much space available before the transaction is allowed to proceed +so that when we come to write the dirty metadata into the log we don't run out +of log space half way through the write. + +For one-shot transactions, a single unit space reservation is all that is +required for the transaction to proceed. For permanent transactions, however, we +also have a "log count" that affects the size of the reservation that is to be +made. + +While a permanent transaction can get by with a single unit of space +reservation, it is somewhat inefficient to do this as it requires the +transaction rolling mechanism to re-reserve space on every transaction roll. We +know from the implementation of the permanent transactions how many transaction +rolls are likely for the common modifications that need to be made. + +For example, an inode allocation is typically two transactions - one to +physically allocate a free inode chunk on disk, and another to allocate an inode +from an inode chunk that has free inodes in it. Hence for an inode allocation +transaction, we might set the reservation log count to a value of 2 to indicate +that the common/fast path transaction will commit two linked transactions in a +chain. Each time a permanent transaction rolls, it consumes an entire unit +reservation. + +Hence when the permanent transaction is first allocated, the log space +reservation is increased from a single unit reservation to multiple unit +reservations. That multiple is defined by the reservation log count, and this +means we can roll the transaction multiple times before we have to re-reserve +log space when we roll the transaction. This ensures that the common +modifications we make only need to reserve log space once. + +If the log count for a permanent transaction reaches zero, then it needs to +re-reserve physical space in the log. This is somewhat complex, and requires +an understanding of how the log accounts for space that has been reserved. + + +Log Space Accounting +==================== + +The position in the log is typically referred to as a Log Sequence Number (LSN). +The log is circular, so the positions in the log are defined by the combination +of a cycle number - the number of times the log has been overwritten - and the +offset into the log. A LSN carries the cycle in the upper 32 bits and the +offset in the lower 32 bits. The offset is in units of "basic blocks" (512 +bytes). Hence we can do realtively simple LSN based math to keep track of +available space in the log. + +Log space accounting is done via a pair of constructs called "grant heads". The +position of the grant heads is an absolute value, so the amount of space +available in the log is defined by the distance between the position of the +grant head and the current log tail. That is, how much space can be +reserved/consumed before the grant heads would fully wrap the log and overtake +the tail position. + +The first grant head is the "reserve" head. This tracks the byte count of the +reservations currently held by active transactions. It is a purely in-memory +accounting of the space reservation and, as such, actually tracks byte offsets +into the log rather than basic blocks. Hence it technically isn't using LSNs to +represent the log position, but it is still treated like a split {cycle,offset} +tuple for the purposes of tracking reservation space. + +The reserve grant head is used to accurately account for exact transaction +reservations amounts and the exact byte count that modifications actually make +and need to write into the log. The reserve head is used to prevent new +transactions from taking new reservations when the head reaches the current +tail. It will block new reservations in a FIFO queue and as the log tail moves +forward it will wake them in order once sufficient space is available. This FIFO +mechanism ensures no transaction is starved of resources when log space +shortages occur. + +The other grant head is the "write" head. Unlike the reserve head, this grant +head contains an LSN and it tracks the physical space usage in the log. While +this might sound like it is accounting the same state as the reserve grant head +- and it mostly does track exactly the same location as the reserve grant head - +there are critical differences in behaviour between them that provides the +forwards progress guarantees that rolling permanent transactions require. + +These differences when a permanent transaction is rolled and the internal "log +count" reaches zero and the initial set of unit reservations have been +exhausted. At this point, we still require a log space reservation to continue +the next transaction in the sequeunce, but we have none remaining. We cannot +sleep during the transaction commit process waiting for new log space to become +available, as we may end up on the end of the FIFO queue and the items we have +locked while we sleep could end up pinning the tail of the log before there is +enough free space in the log to fulfill all of the pending reservations and +then wake up transaction commit in progress. + +To take a new reservation without sleeping requires us to be able to take a +reservation even if there is no reservation space currently available. That is, +we need to be able to *overcommit* the log reservation space. As has already +been detailed, we cannot overcommit physical log space. However, the reserve +grant head does not track physical space - it only accounts for the amount of +reservations we currently have outstanding. Hence if the reserve head passes +over the tail of the log all it means is that new reservations will be throttled +immediately and remain throttled until the log tail is moved forward far enough +to remove the overcommit and start taking new reservations. In other words, we +can overcommit the reserve head without violating the physical log head and tail +rules. + +As a result, permanent transactions only "regrant" reservation space during +xfs_trans_commit() calls, while the physical log space reservation - tracked by +the write head - is then reserved separately by a call to xfs_log_reserve() +after the commit completes. Once the commit completes, we can sleep waiting for +physical log space to be reserved from the write grant head, but only if one +critical rule has been observed:: + + Code using permanent reservations must always log the items they hold + locked across each transaction they roll in the chain. + +"Re-logging" the locked items on every transaction roll ensures that the items +attached to the transaction chain being rolled are always relocated to the +physical head of the log and so do not pin the tail of the log. If a locked item +pins the tail of the log when we sleep on the write reservation, then we will +deadlock the log as we cannot take the locks needed to write back that item and +move the tail of the log forwards to free up write grant space. Re-logging the +locked items avoids this deadlock and guarantees that the log reservation we are +making cannot self-deadlock. + +If all rolling transactions obey this rule, then they can all make forwards +progress independently because nothing will block the progress of the log +tail moving forwards and hence ensuring that write grant space is always +(eventually) made available to permanent transactions no matter how many times +they roll. + + +Re-logging Explained +==================== + +XFS allows multiple separate modifications to a single object to be carried in +the log at any given time. This allows the log to avoid needing to flush each +change to disk before recording a new change to the object. XFS does this via a +method called "re-logging". Conceptually, this is quite simple - all it requires +is that any new change to the object is recorded with a *new copy* of all the +existing changes in the new transaction that is written to the log. + +That is, if we have a sequence of changes A through to F, and the object was +written to disk after change D, we would see in the log the following series +of transactions, their contents and the log sequence number (LSN) of the +transaction:: + + Transaction Contents LSN + A A X + B A+B X+n + C A+B+C X+n+m + D A+B+C+D X+n+m+o + + E E Y (> X+n+m+o) + F E+F Y+p + +In other words, each time an object is relogged, the new transaction contains +the aggregation of all the previous changes currently held only in the log. + +This relogging technique allows objects to be moved forward in the log so that +an object being relogged does not prevent the tail of the log from ever moving +forward. This can be seen in the table above by the changing (increasing) LSN +of each subsequent transaction, and it's the technique that allows us to +implement long-running, multiple-commit permanent transactions. + +A typical example of a rolling transaction is the removal of extents from an +inode which can only be done at a rate of two extents per transaction because +of reservation size limitations. Hence a rolling extent removal transaction +keeps relogging the inode and btree buffers as they get modified in each +removal operation. This keeps them moving forward in the log as the operation +progresses, ensuring that current operation never gets blocked by itself if the +log wraps around. + +Hence it can be seen that the relogging operation is fundamental to the correct +working of the XFS journalling subsystem. From the above description, most +people should be able to see why the XFS metadata operations writes so much to +the log - repeated operations to the same objects write the same changes to +the log over and over again. Worse is the fact that objects tend to get +dirtier as they get relogged, so each subsequent transaction is writing more +metadata into the log. + +It should now also be obvious how relogging and asynchronous transactions go +hand in hand. That is, transactions don't get written to the physical journal +until either a log buffer is filled (a log buffer can hold multiple +transactions) or a synchronous operation forces the log buffers holding the +transactions to disk. This means that XFS is doing aggregation of transactions +in memory - batching them, if you like - to minimise the impact of the log IO on +transaction throughput. + +The limitation on asynchronous transaction throughput is the number and size of +log buffers made available by the log manager. By default there are 8 log +buffers available and the size of each is 32kB - the size can be increased up +to 256kB by use of a mount option. + +Effectively, this gives us the maximum bound of outstanding metadata changes +that can be made to the filesystem at any point in time - if all the log +buffers are full and under IO, then no more transactions can be committed until +the current batch completes. It is now common for a single current CPU core to +be to able to issue enough transactions to keep the log buffers full and under +IO permanently. Hence the XFS journalling subsystem can be considered to be IO +bound. + +Delayed Logging: Concepts +========================= + +The key thing to note about the asynchronous logging combined with the +relogging technique XFS uses is that we can be relogging changed objects +multiple times before they are committed to disk in the log buffers. If we +return to the previous relogging example, it is entirely possible that +transactions A through D are committed to disk in the same log buffer. + +That is, a single log buffer may contain multiple copies of the same object, +but only one of those copies needs to be there - the last one "D", as it +contains all the changes from the previous changes. In other words, we have one +necessary copy in the log buffer, and three stale copies that are simply +wasting space. When we are doing repeated operations on the same set of +objects, these "stale objects" can be over 90% of the space used in the log +buffers. It is clear that reducing the number of stale objects written to the +log would greatly reduce the amount of metadata we write to the log, and this +is the fundamental goal of delayed logging. + +From a conceptual point of view, XFS is already doing relogging in memory (where +memory == log buffer), only it is doing it extremely inefficiently. It is using +logical to physical formatting to do the relogging because there is no +infrastructure to keep track of logical changes in memory prior to physically +formatting the changes in a transaction to the log buffer. Hence we cannot avoid +accumulating stale objects in the log buffers. + +Delayed logging is the name we've given to keeping and tracking transactional +changes to objects in memory outside the log buffer infrastructure. Because of +the relogging concept fundamental to the XFS journalling subsystem, this is +actually relatively easy to do - all the changes to logged items are already +tracked in the current infrastructure. The big problem is how to accumulate +them and get them to the log in a consistent, recoverable manner. +Describing the problems and how they have been solved is the focus of this +document. + +One of the key changes that delayed logging makes to the operation of the +journalling subsystem is that it disassociates the amount of outstanding +metadata changes from the size and number of log buffers available. In other +words, instead of there only being a maximum of 2MB of transaction changes not +written to the log at any point in time, there may be a much greater amount +being accumulated in memory. Hence the potential for loss of metadata on a +crash is much greater than for the existing logging mechanism. + +It should be noted that this does not change the guarantee that log recovery +will result in a consistent filesystem. What it does mean is that as far as the +recovered filesystem is concerned, there may be many thousands of transactions +that simply did not occur as a result of the crash. This makes it even more +important that applications that care about their data use fsync() where they +need to ensure application level data integrity is maintained. + +It should be noted that delayed logging is not an innovative new concept that +warrants rigorous proofs to determine whether it is correct or not. The method +of accumulating changes in memory for some period before writing them to the +log is used effectively in many filesystems including ext3 and ext4. Hence +no time is spent in this document trying to convince the reader that the +concept is sound. Instead it is simply considered a "solved problem" and as +such implementing it in XFS is purely an exercise in software engineering. + +The fundamental requirements for delayed logging in XFS are simple: + + 1. Reduce the amount of metadata written to the log by at least + an order of magnitude. + 2. Supply sufficient statistics to validate Requirement #1. + 3. Supply sufficient new tracing infrastructure to be able to debug + problems with the new code. + 4. No on-disk format change (metadata or log format). + 5. Enable and disable with a mount option. + 6. No performance regressions for synchronous transaction workloads. + +Delayed Logging: Design +======================= + +Storing Changes +--------------- + +The problem with accumulating changes at a logical level (i.e. just using the +existing log item dirty region tracking) is that when it comes to writing the +changes to the log buffers, we need to ensure that the object we are formatting +is not changing while we do this. This requires locking the object to prevent +concurrent modification. Hence flushing the logical changes to the log would +require us to lock every object, format them, and then unlock them again. + +This introduces lots of scope for deadlocks with transactions that are already +running. For example, a transaction has object A locked and modified, but needs +the delayed logging tracking lock to commit the transaction. However, the +flushing thread has the delayed logging tracking lock already held, and is +trying to get the lock on object A to flush it to the log buffer. This appears +to be an unsolvable deadlock condition, and it was solving this problem that +was the barrier to implementing delayed logging for so long. + +The solution is relatively simple - it just took a long time to recognise it. +Put simply, the current logging code formats the changes to each item into an +vector array that points to the changed regions in the item. The log write code +simply copies the memory these vectors point to into the log buffer during +transaction commit while the item is locked in the transaction. Instead of +using the log buffer as the destination of the formatting code, we can use an +allocated memory buffer big enough to fit the formatted vector. + +If we then copy the vector into the memory buffer and rewrite the vector to +point to the memory buffer rather than the object itself, we now have a copy of +the changes in a format that is compatible with the log buffer writing code. +that does not require us to lock the item to access. This formatting and +rewriting can all be done while the object is locked during transaction commit, +resulting in a vector that is transactionally consistent and can be accessed +without needing to lock the owning item. + +Hence we avoid the need to lock items when we need to flush outstanding +asynchronous transactions to the log. The differences between the existing +formatting method and the delayed logging formatting can be seen in the +diagram below. + +Current format log vector:: + + Object +---------------------------------------------+ + Vector 1 +----+ + Vector 2 +----+ + Vector 3 +----------+ + +After formatting:: + + Log Buffer +-V1-+-V2-+----V3----+ + +Delayed logging vector:: + + Object +---------------------------------------------+ + Vector 1 +----+ + Vector 2 +----+ + Vector 3 +----------+ + +After formatting:: + + Memory Buffer +-V1-+-V2-+----V3----+ + Vector 1 +----+ + Vector 2 +----+ + Vector 3 +----------+ + +The memory buffer and associated vector need to be passed as a single object, +but still need to be associated with the parent object so if the object is +relogged we can replace the current memory buffer with a new memory buffer that +contains the latest changes. + +The reason for keeping the vector around after we've formatted the memory +buffer is to support splitting vectors across log buffer boundaries correctly. +If we don't keep the vector around, we do not know where the region boundaries +are in the item, so we'd need a new encapsulation method for regions in the log +buffer writing (i.e. double encapsulation). This would be an on-disk format +change and as such is not desirable. It also means we'd have to write the log +region headers in the formatting stage, which is problematic as there is per +region state that needs to be placed into the headers during the log write. + +Hence we need to keep the vector, but by attaching the memory buffer to it and +rewriting the vector addresses to point at the memory buffer we end up with a +self-describing object that can be passed to the log buffer write code to be +handled in exactly the same manner as the existing log vectors are handled. +Hence we avoid needing a new on-disk format to handle items that have been +relogged in memory. + + +Tracking Changes +---------------- + +Now that we can record transactional changes in memory in a form that allows +them to be used without limitations, we need to be able to track and accumulate +them so that they can be written to the log at some later point in time. The +log item is the natural place to store this vector and buffer, and also makes sense +to be the object that is used to track committed objects as it will always +exist once the object has been included in a transaction. + +The log item is already used to track the log items that have been written to +the log but not yet written to disk. Such log items are considered "active" +and as such are stored in the Active Item List (AIL) which is a LSN-ordered +double linked list. Items are inserted into this list during log buffer IO +completion, after which they are unpinned and can be written to disk. An object +that is in the AIL can be relogged, which causes the object to be pinned again +and then moved forward in the AIL when the log buffer IO completes for that +transaction. + +Essentially, this shows that an item that is in the AIL can still be modified +and relogged, so any tracking must be separate to the AIL infrastructure. As +such, we cannot reuse the AIL list pointers for tracking committed items, nor +can we store state in any field that is protected by the AIL lock. Hence the +committed item tracking needs its own locks, lists and state fields in the log +item. + +Similar to the AIL, tracking of committed items is done through a new list +called the Committed Item List (CIL). The list tracks log items that have been +committed and have formatted memory buffers attached to them. It tracks objects +in transaction commit order, so when an object is relogged it is removed from +its place in the list and re-inserted at the tail. This is entirely arbitrary +and done to make it easy for debugging - the last items in the list are the +ones that are most recently modified. Ordering of the CIL is not necessary for +transactional integrity (as discussed in the next section) so the ordering is +done for convenience/sanity of the developers. + + +Delayed Logging: Checkpoints +---------------------------- + +When we have a log synchronisation event, commonly known as a "log force", +all the items in the CIL must be written into the log via the log buffers. +We need to write these items in the order that they exist in the CIL, and they +need to be written as an atomic transaction. The need for all the objects to be +written as an atomic transaction comes from the requirements of relogging and +log replay - all the changes in all the objects in a given transaction must +either be completely replayed during log recovery, or not replayed at all. If +a transaction is not replayed because it is not complete in the log, then +no later transactions should be replayed, either. + +To fulfill this requirement, we need to write the entire CIL in a single log +transaction. Fortunately, the XFS log code has no fixed limit on the size of a +transaction, nor does the log replay code. The only fundamental limit is that +the transaction cannot be larger than just under half the size of the log. The +reason for this limit is that to find the head and tail of the log, there must +be at least one complete transaction in the log at any given time. If a +transaction is larger than half the log, then there is the possibility that a +crash during the write of a such a transaction could partially overwrite the +only complete previous transaction in the log. This will result in a recovery +failure and an inconsistent filesystem and hence we must enforce the maximum +size of a checkpoint to be slightly less than a half the log. + +Apart from this size requirement, a checkpoint transaction looks no different +to any other transaction - it contains a transaction header, a series of +formatted log items and a commit record at the tail. From a recovery +perspective, the checkpoint transaction is also no different - just a lot +bigger with a lot more items in it. The worst case effect of this is that we +might need to tune the recovery transaction object hash size. + +Because the checkpoint is just another transaction and all the changes to log +items are stored as log vectors, we can use the existing log buffer writing +code to write the changes into the log. To do this efficiently, we need to +minimise the time we hold the CIL locked while writing the checkpoint +transaction. The current log write code enables us to do this easily with the +way it separates the writing of the transaction contents (the log vectors) from +the transaction commit record, but tracking this requires us to have a +per-checkpoint context that travels through the log write process through to +checkpoint completion. + +Hence a checkpoint has a context that tracks the state of the current +checkpoint from initiation to checkpoint completion. A new context is initiated +at the same time a checkpoint transaction is started. That is, when we remove +all the current items from the CIL during a checkpoint operation, we move all +those changes into the current checkpoint context. We then initialise a new +context and attach that to the CIL for aggregation of new transactions. + +This allows us to unlock the CIL immediately after transfer of all the +committed items and effectively allows new transactions to be issued while we +are formatting the checkpoint into the log. It also allows concurrent +checkpoints to be written into the log buffers in the case of log force heavy +workloads, just like the existing transaction commit code does. This, however, +requires that we strictly order the commit records in the log so that +checkpoint sequence order is maintained during log replay. + +To ensure that we can be writing an item into a checkpoint transaction at +the same time another transaction modifies the item and inserts the log item +into the new CIL, then checkpoint transaction commit code cannot use log items +to store the list of log vectors that need to be written into the transaction. +Hence log vectors need to be able to be chained together to allow them to be +detached from the log items. That is, when the CIL is flushed the memory +buffer and log vector attached to each log item needs to be attached to the +checkpoint context so that the log item can be released. In diagrammatic form, +the CIL would look like this before the flush:: + + CIL Head + | + V + Log Item <-> log vector 1 -> memory buffer + | -> vector array + V + Log Item <-> log vector 2 -> memory buffer + | -> vector array + V + ...... + | + V + Log Item <-> log vector N-1 -> memory buffer + | -> vector array + V + Log Item <-> log vector N -> memory buffer + -> vector array + +And after the flush the CIL head is empty, and the checkpoint context log +vector list would look like:: + + Checkpoint Context + | + V + log vector 1 -> memory buffer + | -> vector array + | -> Log Item + V + log vector 2 -> memory buffer + | -> vector array + | -> Log Item + V + ...... + | + V + log vector N-1 -> memory buffer + | -> vector array + | -> Log Item + V + log vector N -> memory buffer + -> vector array + -> Log Item + +Once this transfer is done, the CIL can be unlocked and new transactions can +start, while the checkpoint flush code works over the log vector chain to +commit the checkpoint. + +Once the checkpoint is written into the log buffers, the checkpoint context is +attached to the log buffer that the commit record was written to along with a +completion callback. Log IO completion will call that callback, which can then +run transaction committed processing for the log items (i.e. insert into AIL +and unpin) in the log vector chain and then free the log vector chain and +checkpoint context. + +Discussion Point: I am uncertain as to whether the log item is the most +efficient way to track vectors, even though it seems like the natural way to do +it. The fact that we walk the log items (in the CIL) just to chain the log +vectors and break the link between the log item and the log vector means that +we take a cache line hit for the log item list modification, then another for +the log vector chaining. If we track by the log vectors, then we only need to +break the link between the log item and the log vector, which means we should +dirty only the log item cachelines. Normally I wouldn't be concerned about one +vs two dirty cachelines except for the fact I've seen upwards of 80,000 log +vectors in one checkpoint transaction. I'd guess this is a "measure and +compare" situation that can be done after a working and reviewed implementation +is in the dev tree.... + +Delayed Logging: Checkpoint Sequencing +-------------------------------------- + +One of the key aspects of the XFS transaction subsystem is that it tags +committed transactions with the log sequence number of the transaction commit. +This allows transactions to be issued asynchronously even though there may be +future operations that cannot be completed until that transaction is fully +committed to the log. In the rare case that a dependent operation occurs (e.g. +re-using a freed metadata extent for a data extent), a special, optimised log +force can be issued to force the dependent transaction to disk immediately. + +To do this, transactions need to record the LSN of the commit record of the +transaction. This LSN comes directly from the log buffer the transaction is +written into. While this works just fine for the existing transaction +mechanism, it does not work for delayed logging because transactions are not +written directly into the log buffers. Hence some other method of sequencing +transactions is required. + +As discussed in the checkpoint section, delayed logging uses per-checkpoint +contexts, and as such it is simple to assign a sequence number to each +checkpoint. Because the switching of checkpoint contexts must be done +atomically, it is simple to ensure that each new context has a monotonically +increasing sequence number assigned to it without the need for an external +atomic counter - we can just take the current context sequence number and add +one to it for the new context. + +Then, instead of assigning a log buffer LSN to the transaction commit LSN +during the commit, we can assign the current checkpoint sequence. This allows +operations that track transactions that have not yet completed know what +checkpoint sequence needs to be committed before they can continue. As a +result, the code that forces the log to a specific LSN now needs to ensure that +the log forces to a specific checkpoint. + +To ensure that we can do this, we need to track all the checkpoint contexts +that are currently committing to the log. When we flush a checkpoint, the +context gets added to a "committing" list which can be searched. When a +checkpoint commit completes, it is removed from the committing list. Because +the checkpoint context records the LSN of the commit record for the checkpoint, +we can also wait on the log buffer that contains the commit record, thereby +using the existing log force mechanisms to execute synchronous forces. + +It should be noted that the synchronous forces may need to be extended with +mitigation algorithms similar to the current log buffer code to allow +aggregation of multiple synchronous transactions if there are already +synchronous transactions being flushed. Investigation of the performance of the +current design is needed before making any decisions here. + +The main concern with log forces is to ensure that all the previous checkpoints +are also committed to disk before the one we need to wait for. Therefore we +need to check that all the prior contexts in the committing list are also +complete before waiting on the one we need to complete. We do this +synchronisation in the log force code so that we don't need to wait anywhere +else for such serialisation - it only matters when we do a log force. + +The only remaining complexity is that a log force now also has to handle the +case where the forcing sequence number is the same as the current context. That +is, we need to flush the CIL and potentially wait for it to complete. This is a +simple addition to the existing log forcing code to check the sequence numbers +and push if required. Indeed, placing the current sequence checkpoint flush in +the log force code enables the current mechanism for issuing synchronous +transactions to remain untouched (i.e. commit an asynchronous transaction, then +force the log at the LSN of that transaction) and so the higher level code +behaves the same regardless of whether delayed logging is being used or not. + +Delayed Logging: Checkpoint Log Space Accounting +------------------------------------------------ + +The big issue for a checkpoint transaction is the log space reservation for the +transaction. We don't know how big a checkpoint transaction is going to be +ahead of time, nor how many log buffers it will take to write out, nor the +number of split log vector regions are going to be used. We can track the +amount of log space required as we add items to the commit item list, but we +still need to reserve the space in the log for the checkpoint. + +A typical transaction reserves enough space in the log for the worst case space +usage of the transaction. The reservation accounts for log record headers, +transaction and region headers, headers for split regions, buffer tail padding, +etc. as well as the actual space for all the changed metadata in the +transaction. While some of this is fixed overhead, much of it is dependent on +the size of the transaction and the number of regions being logged (the number +of log vectors in the transaction). + +An example of the differences would be logging directory changes versus logging +inode changes. If you modify lots of inode cores (e.g. ``chmod -R g+w *``), then +there are lots of transactions that only contain an inode core and an inode log +format structure. That is, two vectors totaling roughly 150 bytes. If we modify +10,000 inodes, we have about 1.5MB of metadata to write in 20,000 vectors. Each +vector is 12 bytes, so the total to be logged is approximately 1.75MB. In +comparison, if we are logging full directory buffers, they are typically 4KB +each, so we in 1.5MB of directory buffers we'd have roughly 400 buffers and a +buffer format structure for each buffer - roughly 800 vectors or 1.51MB total +space. From this, it should be obvious that a static log space reservation is +not particularly flexible and is difficult to select the "optimal value" for +all workloads. + +Further, if we are going to use a static reservation, which bit of the entire +reservation does it cover? We account for space used by the transaction +reservation by tracking the space currently used by the object in the CIL and +then calculating the increase or decrease in space used as the object is +relogged. This allows for a checkpoint reservation to only have to account for +log buffer metadata used such as log header records. + +However, even using a static reservation for just the log metadata is +problematic. Typically log record headers use at least 16KB of log space per +1MB of log space consumed (512 bytes per 32k) and the reservation needs to be +large enough to handle arbitrary sized checkpoint transactions. This +reservation needs to be made before the checkpoint is started, and we need to +be able to reserve the space without sleeping. For a 8MB checkpoint, we need a +reservation of around 150KB, which is a non-trivial amount of space. + +A static reservation needs to manipulate the log grant counters - we can take a +permanent reservation on the space, but we still need to make sure we refresh +the write reservation (the actual space available to the transaction) after +every checkpoint transaction completion. Unfortunately, if this space is not +available when required, then the regrant code will sleep waiting for it. + +The problem with this is that it can lead to deadlocks as we may need to commit +checkpoints to be able to free up log space (refer back to the description of +rolling transactions for an example of this). Hence we *must* always have +space available in the log if we are to use static reservations, and that is +very difficult and complex to arrange. It is possible to do, but there is a +simpler way. + +The simpler way of doing this is tracking the entire log space used by the +items in the CIL and using this to dynamically calculate the amount of log +space required by the log metadata. If this log metadata space changes as a +result of a transaction commit inserting a new memory buffer into the CIL, then +the difference in space required is removed from the transaction that causes +the change. Transactions at this level will *always* have enough space +available in their reservation for this as they have already reserved the +maximal amount of log metadata space they require, and such a delta reservation +will always be less than or equal to the maximal amount in the reservation. + +Hence we can grow the checkpoint transaction reservation dynamically as items +are added to the CIL and avoid the need for reserving and regranting log space +up front. This avoids deadlocks and removes a blocking point from the +checkpoint flush code. + +As mentioned early, transactions can't grow to more than half the size of the +log. Hence as part of the reservation growing, we need to also check the size +of the reservation against the maximum allowed transaction size. If we reach +the maximum threshold, we need to push the CIL to the log. This is effectively +a "background flush" and is done on demand. This is identical to +a CIL push triggered by a log force, only that there is no waiting for the +checkpoint commit to complete. This background push is checked and executed by +transaction commit code. + +If the transaction subsystem goes idle while we still have items in the CIL, +they will be flushed by the periodic log force issued by the xfssyncd. This log +force will push the CIL to disk, and if the transaction subsystem stays idle, +allow the idle log to be covered (effectively marked clean) in exactly the same +manner that is done for the existing logging method. A discussion point is +whether this log force needs to be done more frequently than the current rate +which is once every 30s. + + +Delayed Logging: Log Item Pinning +--------------------------------- + +Currently log items are pinned during transaction commit while the items are +still locked. This happens just after the items are formatted, though it could +be done any time before the items are unlocked. The result of this mechanism is +that items get pinned once for every transaction that is committed to the log +buffers. Hence items that are relogged in the log buffers will have a pin count +for every outstanding transaction they were dirtied in. When each of these +transactions is completed, they will unpin the item once. As a result, the item +only becomes unpinned when all the transactions complete and there are no +pending transactions. Thus the pinning and unpinning of a log item is symmetric +as there is a 1:1 relationship with transaction commit and log item completion. + +For delayed logging, however, we have an asymmetric transaction commit to +completion relationship. Every time an object is relogged in the CIL it goes +through the commit process without a corresponding completion being registered. +That is, we now have a many-to-one relationship between transaction commit and +log item completion. The result of this is that pinning and unpinning of the +log items becomes unbalanced if we retain the "pin on transaction commit, unpin +on transaction completion" model. + +To keep pin/unpin symmetry, the algorithm needs to change to a "pin on +insertion into the CIL, unpin on checkpoint completion". In other words, the +pinning and unpinning becomes symmetric around a checkpoint context. We have to +pin the object the first time it is inserted into the CIL - if it is already in +the CIL during a transaction commit, then we do not pin it again. Because there +can be multiple outstanding checkpoint contexts, we can still see elevated pin +counts, but as each checkpoint completes the pin count will retain the correct +value according to its context. + +Just to make matters slightly more complex, this checkpoint level context +for the pin count means that the pinning of an item must take place under the +CIL commit/flush lock. If we pin the object outside this lock, we cannot +guarantee which context the pin count is associated with. This is because of +the fact pinning the item is dependent on whether the item is present in the +current CIL or not. If we don't pin the CIL first before we check and pin the +object, we have a race with CIL being flushed between the check and the pin +(or not pinning, as the case may be). Hence we must hold the CIL flush/commit +lock to guarantee that we pin the items correctly. + +Delayed Logging: Concurrent Scalability +--------------------------------------- + +A fundamental requirement for the CIL is that accesses through transaction +commits must scale to many concurrent commits. The current transaction commit +code does not break down even when there are transactions coming from 2048 +processors at once. The current transaction code does not go any faster than if +there was only one CPU using it, but it does not slow down either. + +As a result, the delayed logging transaction commit code needs to be designed +for concurrency from the ground up. It is obvious that there are serialisation +points in the design - the three important ones are: + + 1. Locking out new transaction commits while flushing the CIL + 2. Adding items to the CIL and updating item space accounting + 3. Checkpoint commit ordering + +Looking at the transaction commit and CIL flushing interactions, it is clear +that we have a many-to-one interaction here. That is, the only restriction on +the number of concurrent transactions that can be trying to commit at once is +the amount of space available in the log for their reservations. The practical +limit here is in the order of several hundred concurrent transactions for a +128MB log, which means that it is generally one per CPU in a machine. + +The amount of time a transaction commit needs to hold out a flush is a +relatively long period of time - the pinning of log items needs to be done +while we are holding out a CIL flush, so at the moment that means it is held +across the formatting of the objects into memory buffers (i.e. while memcpy()s +are in progress). Ultimately a two pass algorithm where the formatting is done +separately to the pinning of objects could be used to reduce the hold time of +the transaction commit side. + +Because of the number of potential transaction commit side holders, the lock +really needs to be a sleeping lock - if the CIL flush takes the lock, we do not +want every other CPU in the machine spinning on the CIL lock. Given that +flushing the CIL could involve walking a list of tens of thousands of log +items, it will get held for a significant time and so spin contention is a +significant concern. Preventing lots of CPUs spinning doing nothing is the +main reason for choosing a sleeping lock even though nothing in either the +transaction commit or CIL flush side sleeps with the lock held. + +It should also be noted that CIL flushing is also a relatively rare operation +compared to transaction commit for asynchronous transaction workloads - only +time will tell if using a read-write semaphore for exclusion will limit +transaction commit concurrency due to cache line bouncing of the lock on the +read side. + +The second serialisation point is on the transaction commit side where items +are inserted into the CIL. Because transactions can enter this code +concurrently, the CIL needs to be protected separately from the above +commit/flush exclusion. It also needs to be an exclusive lock but it is only +held for a very short time and so a spin lock is appropriate here. It is +possible that this lock will become a contention point, but given the short +hold time once per transaction I think that contention is unlikely. + +The final serialisation point is the checkpoint commit record ordering code +that is run as part of the checkpoint commit and log force sequencing. The code +path that triggers a CIL flush (i.e. whatever triggers the log force) will enter +an ordering loop after writing all the log vectors into the log buffers but +before writing the commit record. This loop walks the list of committing +checkpoints and needs to block waiting for checkpoints to complete their commit +record write. As a result it needs a lock and a wait variable. Log force +sequencing also requires the same lock, list walk, and blocking mechanism to +ensure completion of checkpoints. + +These two sequencing operations can use the mechanism even though the +events they are waiting for are different. The checkpoint commit record +sequencing needs to wait until checkpoint contexts contain a commit LSN +(obtained through completion of a commit record write) while log force +sequencing needs to wait until previous checkpoint contexts are removed from +the committing list (i.e. they've completed). A simple wait variable and +broadcast wakeups (thundering herds) has been used to implement these two +serialisation queues. They use the same lock as the CIL, too. If we see too +much contention on the CIL lock, or too many context switches as a result of +the broadcast wakeups these operations can be put under a new spinlock and +given separate wait lists to reduce lock contention and the number of processes +woken by the wrong event. + + +Lifecycle Changes +----------------- + +The existing log item life cycle is as follows:: + + 1. Transaction allocate + 2. Transaction reserve + 3. Lock item + 4. Join item to transaction + If not already attached, + Allocate log item + Attach log item to owner item + Attach log item to transaction + 5. Modify item + Record modifications in log item + 6. Transaction commit + Pin item in memory + Format item into log buffer + Write commit LSN into transaction + Unlock item + Attach transaction to log buffer + + + + + 7. Transaction completion + Mark log item committed + Insert log item into AIL + Write commit LSN into log item + Unpin log item + 8. AIL traversal + Lock item + Mark log item clean + Flush item to disk + + + + 9. Log item removed from AIL + Moves log tail + Item unlocked + +Essentially, steps 1-6 operate independently from step 7, which is also +independent of steps 8-9. An item can be locked in steps 1-6 or steps 8-9 +at the same time step 7 is occurring, but only steps 1-6 or 8-9 can occur +at the same time. If the log item is in the AIL or between steps 6 and 7 +and steps 1-6 are re-entered, then the item is relogged. Only when steps 8-9 +are entered and completed is the object considered clean. + +With delayed logging, there are new steps inserted into the life cycle:: + + 1. Transaction allocate + 2. Transaction reserve + 3. Lock item + 4. Join item to transaction + If not already attached, + Allocate log item + Attach log item to owner item + Attach log item to transaction + 5. Modify item + Record modifications in log item + 6. Transaction commit + Pin item in memory if not pinned in CIL + Format item into log vector + buffer + Attach log vector and buffer to log item + Insert log item into CIL + Write CIL context sequence into transaction + Unlock item + + + + 7. CIL push + lock CIL flush + Chain log vectors and buffers together + Remove items from CIL + unlock CIL flush + write log vectors into log + sequence commit records + attach checkpoint context to log buffer + + + + + 8. Checkpoint completion + Mark log item committed + Insert item into AIL + Write commit LSN into log item + Unpin log item + 9. AIL traversal + Lock item + Mark log item clean + Flush item to disk + + 10. Log item removed from AIL + Moves log tail + Item unlocked + +From this, it can be seen that the only life cycle differences between the two +logging methods are in the middle of the life cycle - they still have the same +beginning and end and execution constraints. The only differences are in the +committing of the log items to the log itself and the completion processing. +Hence delayed logging should not introduce any constraints on log item +behaviour, allocation or freeing that don't already exist. + +As a result of this zero-impact "insertion" of delayed logging infrastructure +and the design of the internal structures to avoid on disk format changes, we +can basically switch between delayed logging and the existing mechanism with a +mount option. Fundamentally, there is no reason why the log manager would not +be able to swap methods automatically and transparently depending on load +characteristics, but this should not be necessary if delayed logging works as +designed. diff --git a/Documentation/filesystems/xfs/xfs-maintainer-entry-profile.rst b/Documentation/filesystems/xfs/xfs-maintainer-entry-profile.rst new file mode 100644 index 00000000000000..32b6ac4ca9d61f --- /dev/null +++ b/Documentation/filesystems/xfs/xfs-maintainer-entry-profile.rst @@ -0,0 +1,194 @@ +XFS Maintainer Entry Profile +============================ + +Overview +-------- +XFS is a well known high-performance filesystem in the Linux kernel. +The aim of this project is to provide and maintain a robust and +performant filesystem. + +Patches are generally merged to the for-next branch of the appropriate +git repository. +After a testing period, the for-next branch is merged to the master +branch. + +Kernel code are merged to the xfs-linux tree[0]. +Userspace code are merged to the xfsprogs tree[1]. +Test cases are merged to the xfstests tree[2]. +Ondisk format documentation are merged to the xfs-documentation tree[3]. + +All patchsets involving XFS *must* be cc'd in their entirety to the mailing +list linux-xfs@vger.kernel.org. + +Roles +----- +There are eight key roles in the XFS project. +A person can take on multiple roles, and a role can be filled by +multiple people. +Anyone taking on a role is advised to check in with themselves and +others on a regular basis about burnout. + +- **Outside Contributor**: Anyone who sends a patch but is not involved + in the XFS project on a regular basis. + These folks are usually people who work on other filesystems or + elsewhere in the kernel community. + +- **Developer**: Someone who is familiar with the XFS codebase enough to + write new code, documentation, and tests. + + Developers can often be found in the IRC channel mentioned by the ``C:`` + entry in the kernel MAINTAINERS file. + +- **Senior Developer**: A developer who is very familiar with at least + some part of the XFS codebase and/or other subsystems in the kernel. + These people collectively decide the long term goals of the project + and nudge the community in that direction. + They should help prioritize development and review work for each release + cycle. + + Senior developers tend to be more active participants in the IRC channel. + +- **Reviewer**: Someone (most likely also a developer) who reads code + submissions to decide: + + 0. Is the idea behind the contribution sound? + 1. Does the idea fit the goals of the project? + 2. Is the contribution designed correctly? + 3. Is the contribution polished? + 4. Can the contribution be tested effectively? + + Reviewers should identify themselves with an ``R:`` entry in the kernel + and fstests MAINTAINERS files. + +- **Testing Lead**: This person is responsible for setting the test + coverage goals of the project, negotiating with developers to decide + on new tests for new features, and making sure that developers and + release managers execute on the testing. + + The testing lead should identify themselves with an ``M:`` entry in + the XFS section of the fstests MAINTAINERS file. + +- **Bug Triager**: Someone who examines incoming bug reports in just + enough detail to identify the person to whom the report should be + forwarded. + + The bug triagers should identify themselves with a ``B:`` entry in + the kernel MAINTAINERS file. + +- **Release Manager**: This person merges reviewed patchsets into an + integration branch, tests the result locally, pushes the branch to a + public git repository, and sends pull requests further upstream. + The release manager is not expected to work on new feature patchsets. + If a developer and a reviewer fail to reach a resolution on some point, + the release manager must have the ability to intervene to try to drive a + resolution. + + The release manager should identify themselves with an ``M:`` entry in + the kernel MAINTAINERS file. + +- **Community Manager**: This person calls and moderates meetings of as many + XFS participants as they can get when mailing list discussions prove + insufficient for collective decisionmaking. + They may also serve as liaison between managers of the organizations + sponsoring work on any part of XFS. + +- **LTS Maintainer**: Someone who backports and tests bug fixes from + uptream to the LTS kernels. + There tend to be six separate LTS trees at any given time. + + The maintainer for a given LTS release should identify themselves with an + ``M:`` entry in the MAINTAINERS file for that LTS tree. + Unmaintained LTS kernels should be marked with status ``S: Orphan`` in that + same file. + +Submission Checklist Addendum +----------------------------- +Please follow these additional rules when submitting to XFS: + +- Patches affecting only the filesystem itself should be based against + the latest -rc or the for-next branch. + These patches will be merged back to the for-next branch. + +- Authors of patches touching other subsystems need to coordinate with + the maintainers of XFS and the relevant subsystems to decide how to + proceed with a merge. + +- Any patchset changing XFS should be cc'd in its entirety to linux-xfs. + Do not send partial patchsets; that makes analysis of the broader + context of the changes unnecessarily difficult. + +- Anyone making kernel changes that have corresponding changes to the + userspace utilities should send the userspace changes as separate + patchsets immediately after the kernel patchsets. + +- Authors of bug fix patches are expected to use fstests[2] to perform + an A/B test of the patch to determine that there are no regressions. + When possible, a new regression test case should be written for + fstests. + +- Authors of new feature patchsets must ensure that fstests will have + appropriate functional and input corner-case test cases for the new + feature. + +- When implementing a new feature, it is strongly suggested that the + developers write a design document to answer the following questions: + + * **What** problem is this trying to solve? + + * **Who** will benefit from this solution, and **where** will they + access it? + + * **How** will this new feature work? This should touch on major data + structures and algorithms supporting the solution at a higher level + than code comments. + + * **What** userspace interfaces are necessary to build off of the new + features? + + * **How** will this work be tested to ensure that it solves the + problems laid out in the design document without causing new + problems? + + The design document should be committed in the kernel documentation + directory. + It may be omitted if the feature is already well known to the + community. + +- Patchsets for the new tests should be submitted as separate patchsets + immediately after the kernel and userspace code patchsets. + +- Changes to the on-disk format of XFS must be described in the ondisk + format document[3] and submitted as a patchset after the fstests + patchsets. + +- Patchsets implementing bug fixes and further code cleanups should put + the bug fixes at the beginning of the series to ease backporting. + +Key Release Cycle Dates +----------------------- +Bug fixes may be sent at any time, though the release manager may decide to +defer a patch when the next merge window is close. + +Code submissions targeting the next merge window should be sent between +-rc1 and -rc6. +This gives the community time to review the changes, to suggest other changes, +and for the author to retest those changes. + +Code submissions also requiring changes to fs/iomap and targeting the +next merge window should be sent between -rc1 and -rc4. +This allows the broader kernel community adequate time to test the +infrastructure changes. + +Review Cadence +-------------- +In general, please wait at least one week before pinging for feedback. +To find reviewers, either consult the MAINTAINERS file, or ask +developers that have Reviewed-by tags for XFS changes to take a look and +offer their opinion. + +References +---------- +| [0] https://git.kernel.org/pub/scm/fs/xfs/xfs-linux.git/ +| [1] https://git.kernel.org/pub/scm/fs/xfs/xfsprogs-dev.git/ +| [2] https://git.kernel.org/pub/scm/fs/xfs/xfstests-dev.git/ +| [3] https://git.kernel.org/pub/scm/fs/xfs/xfs-documentation.git/ diff --git a/Documentation/filesystems/xfs/xfs-online-fsck-design.rst b/Documentation/filesystems/xfs/xfs-online-fsck-design.rst new file mode 100644 index 00000000000000..352516feef6ffe --- /dev/null +++ b/Documentation/filesystems/xfs/xfs-online-fsck-design.rst @@ -0,0 +1,5315 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. _xfs_online_fsck_design: + +.. + Mapping of heading styles within this document: + Heading 1 uses "====" above and below + Heading 2 uses "====" + Heading 3 uses "----" + Heading 4 uses "````" + Heading 5 uses "^^^^" + Heading 6 uses "~~~~" + Heading 7 uses "...." + + Sections are manually numbered because apparently that's what everyone + does in the kernel. + +====================== +XFS Online Fsck Design +====================== + +This document captures the design of the online filesystem check feature for +XFS. +The purpose of this document is threefold: + +- To help kernel distributors understand exactly what the XFS online fsck + feature is, and issues about which they should be aware. + +- To help people reading the code to familiarize themselves with the relevant + concepts and design points before they start digging into the code. + +- To help developers maintaining the system by capturing the reasons + supporting higher level decision making. + +As the online fsck code is merged, the links in this document to topic branches +will be replaced with links to code. + +This document is licensed under the terms of the GNU Public License, v2. +The primary author is Darrick J. Wong. + +This design document is split into seven parts. +Part 1 defines what fsck tools are and the motivations for writing a new one. +Parts 2 and 3 present a high level overview of how online fsck process works +and how it is tested to ensure correct functionality. +Part 4 discusses the user interface and the intended usage modes of the new +program. +Parts 5 and 6 show off the high level components and how they fit together, and +then present case studies of how each repair function actually works. +Part 7 sums up what has been discussed so far and speculates about what else +might be built atop online fsck. + +.. contents:: Table of Contents + :local: + +1. What is a Filesystem Check? +============================== + +A Unix filesystem has four main responsibilities: + +- Provide a hierarchy of names through which application programs can associate + arbitrary blobs of data for any length of time, + +- Virtualize physical storage media across those names, and + +- Retrieve the named data blobs at any time. + +- Examine resource usage. + +Metadata directly supporting these functions (e.g. files, directories, space +mappings) are sometimes called primary metadata. +Secondary metadata (e.g. reverse mapping and directory parent pointers) support +operations internal to the filesystem, such as internal consistency checking +and reorganization. +Summary metadata, as the name implies, condense information contained in +primary metadata for performance reasons. + +The filesystem check (fsck) tool examines all the metadata in a filesystem +to look for errors. +In addition to looking for obvious metadata corruptions, fsck also +cross-references different types of metadata records with each other to look +for inconsistencies. +People do not like losing data, so most fsck tools also contains some ability +to correct any problems found. +As a word of caution -- the primary goal of most Linux fsck tools is to restore +the filesystem metadata to a consistent state, not to maximize the data +recovered. +That precedent will not be challenged here. + +Filesystems of the 20th century generally lacked any redundancy in the ondisk +format, which means that fsck can only respond to errors by erasing files until +errors are no longer detected. +More recent filesystem designs contain enough redundancy in their metadata that +it is now possible to regenerate data structures when non-catastrophic errors +occur; this capability aids both strategies. + ++--------------------------------------------------------------------------+ +| **Note**: | ++--------------------------------------------------------------------------+ +| System administrators avoid data loss by increasing the number of | +| separate storage systems through the creation of backups; and they avoid | +| downtime by increasing the redundancy of each storage system through the | +| creation of RAID arrays. | +| fsck tools address only the first problem. | ++--------------------------------------------------------------------------+ + +TLDR; Show Me the Code! +----------------------- + +Code is posted to the kernel.org git trees as follows: +`kernel changes `_, +`userspace changes `_, and +`QA test changes `_. +Each kernel patchset adding an online repair function will use the same branch +name across the kernel, xfsprogs, and fstests git repos. + +Existing Tools +-------------- + +The online fsck tool described here will be the third tool in the history of +XFS (on Linux) to check and repair filesystems. +Two programs precede it: + +The first program, ``xfs_check``, was created as part of the XFS debugger +(``xfs_db``) and can only be used with unmounted filesystems. +It walks all metadata in the filesystem looking for inconsistencies in the +metadata, though it lacks any ability to repair what it finds. +Due to its high memory requirements and inability to repair things, this +program is now deprecated and will not be discussed further. + +The second program, ``xfs_repair``, was created to be faster and more robust +than the first program. +Like its predecessor, it can only be used with unmounted filesystems. +It uses extent-based in-memory data structures to reduce memory consumption, +and tries to schedule readahead IO appropriately to reduce I/O waiting time +while it scans the metadata of the entire filesystem. +The most important feature of this tool is its ability to respond to +inconsistencies in file metadata and directory tree by erasing things as needed +to eliminate problems. +Space usage metadata are rebuilt from the observed file metadata. + +Problem Statement +----------------- + +The current XFS tools leave several problems unsolved: + +1. **User programs** suddenly **lose access** to the filesystem when unexpected + shutdowns occur as a result of silent corruptions in the metadata. + These occur **unpredictably** and often without warning. + +2. **Users** experience a **total loss of service** during the recovery period + after an **unexpected shutdown** occurs. + +3. **Users** experience a **total loss of service** if the filesystem is taken + offline to **look for problems** proactively. + +4. **Data owners** cannot **check the integrity** of their stored data without + reading all of it. + This may expose them to substantial billing costs when a linear media scan + performed by the storage system administrator might suffice. + +5. **System administrators** cannot **schedule** a maintenance window to deal + with corruptions if they **lack the means** to assess filesystem health + while the filesystem is online. + +6. **Fleet monitoring tools** cannot **automate periodic checks** of filesystem + health when doing so requires **manual intervention** and downtime. + +7. **Users** can be tricked into **doing things they do not desire** when + malicious actors **exploit quirks of Unicode** to place misleading names + in directories. + +Given this definition of the problems to be solved and the actors who would +benefit, the proposed solution is a third fsck tool that acts on a running +filesystem. + +This new third program has three components: an in-kernel facility to check +metadata, an in-kernel facility to repair metadata, and a userspace driver +program to drive fsck activity on a live filesystem. +``xfs_scrub`` is the name of the driver program. +The rest of this document presents the goals and use cases of the new fsck +tool, describes its major design points in connection to those goals, and +discusses the similarities and differences with existing tools. + ++--------------------------------------------------------------------------+ +| **Note**: | ++--------------------------------------------------------------------------+ +| Throughout this document, the existing offline fsck tool can also be | +| referred to by its current name "``xfs_repair``". | +| The userspace driver program for the new online fsck tool can be | +| referred to as "``xfs_scrub``". | +| The kernel portion of online fsck that validates metadata is called | +| "online scrub", and portion of the kernel that fixes metadata is called | +| "online repair". | ++--------------------------------------------------------------------------+ + +The naming hierarchy is broken up into objects known as directories and files +and the physical space is split into pieces known as allocation groups. +Sharding enables better performance on highly parallel systems and helps to +contain the damage when corruptions occur. +The division of the filesystem into principal objects (allocation groups and +inodes) means that there are ample opportunities to perform targeted checks and +repairs on a subset of the filesystem. + +While this is going on, other parts continue processing IO requests. +Even if a piece of filesystem metadata can only be regenerated by scanning the +entire system, the scan can still be done in the background while other file +operations continue. + +In summary, online fsck takes advantage of resource sharding and redundant +metadata to enable targeted checking and repair operations while the system +is running. +This capability will be coupled to automatic system management so that +autonomous self-healing of XFS maximizes service availability. + +2. Theory of Operation +====================== + +Because it is necessary for online fsck to lock and scan live metadata objects, +online fsck consists of three separate code components. +The first is the userspace driver program ``xfs_scrub``, which is responsible +for identifying individual metadata items, scheduling work items for them, +reacting to the outcomes appropriately, and reporting results to the system +administrator. +The second and third are in the kernel, which implements functions to check +and repair each type of online fsck work item. + ++------------------------------------------------------------------+ +| **Note**: | ++------------------------------------------------------------------+ +| For brevity, this document shortens the phrase "online fsck work | +| item" to "scrub item". | ++------------------------------------------------------------------+ + +Scrub item types are delineated in a manner consistent with the Unix design +philosophy, which is to say that each item should handle one aspect of a +metadata structure, and handle it well. + +Scope +----- + +In principle, online fsck should be able to check and to repair everything that +the offline fsck program can handle. +However, online fsck cannot be running 100% of the time, which means that +latent errors may creep in after a scrub completes. +If these errors cause the next mount to fail, offline fsck is the only +solution. +This limitation means that maintenance of the offline fsck tool will continue. +A second limitation of online fsck is that it must follow the same resource +sharing and lock acquisition rules as the regular filesystem. +This means that scrub cannot take *any* shortcuts to save time, because doing +so could lead to concurrency problems. +In other words, online fsck is not a complete replacement for offline fsck, and +a complete run of online fsck may take longer than online fsck. +However, both of these limitations are acceptable tradeoffs to satisfy the +different motivations of online fsck, which are to **minimize system downtime** +and to **increase predictability of operation**. + +.. _scrubphases: + +Phases of Work +-------------- + +The userspace driver program ``xfs_scrub`` splits the work of checking and +repairing an entire filesystem into seven phases. +Each phase concentrates on checking specific types of scrub items and depends +on the success of all previous phases. +The seven phases are as follows: + +1. Collect geometry information about the mounted filesystem and computer, + discover the online fsck capabilities of the kernel, and open the + underlying storage devices. + +2. Check allocation group metadata, all realtime volume metadata, and all quota + files. + Each metadata structure is scheduled as a separate scrub item. + If corruption is found in the inode header or inode btree and ``xfs_scrub`` + is permitted to perform repairs, then those scrub items are repaired to + prepare for phase 3. + Repairs are implemented by using the information in the scrub item to + resubmit the kernel scrub call with the repair flag enabled; this is + discussed in the next section. + Optimizations and all other repairs are deferred to phase 4. + +3. Check all metadata of every file in the filesystem. + Each metadata structure is also scheduled as a separate scrub item. + If repairs are needed and ``xfs_scrub`` is permitted to perform repairs, + and there were no problems detected during phase 2, then those scrub items + are repaired immediately. + Optimizations, deferred repairs, and unsuccessful repairs are deferred to + phase 4. + +4. All remaining repairs and scheduled optimizations are performed during this + phase, if the caller permits them. + Before starting repairs, the summary counters are checked and any necessary + repairs are performed so that subsequent repairs will not fail the resource + reservation step due to wildly incorrect summary counters. + Unsuccessful repairs are requeued as long as forward progress on repairs is + made somewhere in the filesystem. + Free space in the filesystem is trimmed at the end of phase 4 if the + filesystem is clean. + +5. By the start of this phase, all primary and secondary filesystem metadata + must be correct. + Summary counters such as the free space counts and quota resource counts + are checked and corrected. + Directory entry names and extended attribute names are checked for + suspicious entries such as control characters or confusing Unicode sequences + appearing in names. + +6. If the caller asks for a media scan, read all allocated and written data + file extents in the filesystem. + The ability to use hardware-assisted data file integrity checking is new + to online fsck; neither of the previous tools have this capability. + If media errors occur, they will be mapped to the owning files and reported. + +7. Re-check the summary counters and presents the caller with a summary of + space usage and file counts. + +This allocation of responsibilities will be :ref:`revisited ` +later in this document. + +Steps for Each Scrub Item +------------------------- + +The kernel scrub code uses a three-step strategy for checking and repairing +the one aspect of a metadata object represented by a scrub item: + +1. The scrub item of interest is checked for corruptions; opportunities for + optimization; and for values that are directly controlled by the system + administrator but look suspicious. + If the item is not corrupt or does not need optimization, resource are + released and the positive scan results are returned to userspace. + If the item is corrupt or could be optimized but the caller does not permit + this, resources are released and the negative scan results are returned to + userspace. + Otherwise, the kernel moves on to the second step. + +2. The repair function is called to rebuild the data structure. + Repair functions generally choose rebuild a structure from other metadata + rather than try to salvage the existing structure. + If the repair fails, the scan results from the first step are returned to + userspace. + Otherwise, the kernel moves on to the third step. + +3. In the third step, the kernel runs the same checks over the new metadata + item to assess the efficacy of the repairs. + The results of the reassessment are returned to userspace. + +Classification of Metadata +-------------------------- + +Each type of metadata object (and therefore each type of scrub item) is +classified as follows: + +Primary Metadata +```````````````` + +Metadata structures in this category should be most familiar to filesystem +users either because they are directly created by the user or they index +objects created by the user +Most filesystem objects fall into this class: + +- Free space and reference count information + +- Inode records and indexes + +- Storage mapping information for file data + +- Directories + +- Extended attributes + +- Symbolic links + +- Quota limits + +Scrub obeys the same rules as regular filesystem accesses for resource and lock +acquisition. + +Primary metadata objects are the simplest for scrub to process. +The principal filesystem object (either an allocation group or an inode) that +owns the item being scrubbed is locked to guard against concurrent updates. +The check function examines every record associated with the type for obvious +errors and cross-references healthy records against other metadata to look for +inconsistencies. +Repairs for this class of scrub item are simple, since the repair function +starts by holding all the resources acquired in the previous step. +The repair function scans available metadata as needed to record all the +observations needed to complete the structure. +Next, it stages the observations in a new ondisk structure and commits it +atomically to complete the repair. +Finally, the storage from the old data structure are carefully reaped. + +Because ``xfs_scrub`` locks a primary object for the duration of the repair, +this is effectively an offline repair operation performed on a subset of the +filesystem. +This minimizes the complexity of the repair code because it is not necessary to +handle concurrent updates from other threads, nor is it necessary to access +any other part of the filesystem. +As a result, indexed structures can be rebuilt very quickly, and programs +trying to access the damaged structure will be blocked until repairs complete. +The only infrastructure needed by the repair code are the staging area for +observations and a means to write new structures to disk. +Despite these limitations, the advantage that online repair holds is clear: +targeted work on individual shards of the filesystem avoids total loss of +service. + +This mechanism is described in section 2.1 ("Off-Line Algorithm") of +V. Srinivasan and M. J. Carey, `"Performance of On-Line Index Construction +Algorithms" `_, +*Extending Database Technology*, pp. 293-309, 1992. + +Most primary metadata repair functions stage their intermediate results in an +in-memory array prior to formatting the new ondisk structure, which is very +similar to the list-based algorithm discussed in section 2.3 ("List-Based +Algorithms") of Srinivasan. +However, any data structure builder that maintains a resource lock for the +duration of the repair is *always* an offline algorithm. + +.. _secondary_metadata: + +Secondary Metadata +`````````````````` + +Metadata structures in this category reflect records found in primary metadata, +but are only needed for online fsck or for reorganization of the filesystem. + +Secondary metadata include: + +- Reverse mapping information + +- Directory parent pointers + +This class of metadata is difficult for scrub to process because scrub attaches +to the secondary object but needs to check primary metadata, which runs counter +to the usual order of resource acquisition. +Frequently, this means that full filesystems scans are necessary to rebuild the +metadata. +Check functions can be limited in scope to reduce runtime. +Repairs, however, require a full scan of primary metadata, which can take a +long time to complete. +Under these conditions, ``xfs_scrub`` cannot lock resources for the entire +duration of the repair. + +Instead, repair functions set up an in-memory staging structure to store +observations. +Depending on the requirements of the specific repair function, the staging +index will either have the same format as the ondisk structure or a design +specific to that repair function. +The next step is to release all locks and start the filesystem scan. +When the repair scanner needs to record an observation, the staging data are +locked long enough to apply the update. +While the filesystem scan is in progress, the repair function hooks the +filesystem so that it can apply pending filesystem updates to the staging +information. +Once the scan is done, the owning object is re-locked, the live data is used to +write a new ondisk structure, and the repairs are committed atomically. +The hooks are disabled and the staging staging area is freed. +Finally, the storage from the old data structure are carefully reaped. + +Introducing concurrency helps online repair avoid various locking problems, but +comes at a high cost to code complexity. +Live filesystem code has to be hooked so that the repair function can observe +updates in progress. +The staging area has to become a fully functional parallel structure so that +updates can be merged from the hooks. +Finally, the hook, the filesystem scan, and the inode locking model must be +sufficiently well integrated that a hook event can decide if a given update +should be applied to the staging structure. + +In theory, the scrub implementation could apply these same techniques for +primary metadata, but doing so would make it massively more complex and less +performant. +Programs attempting to access the damaged structures are not blocked from +operation, which may cause application failure or an unplanned filesystem +shutdown. + +Inspiration for the secondary metadata repair strategy was drawn from section +2.4 of Srinivasan above, and sections 2 ("NSF: Inded Build Without Side-File") +and 3.1.1 ("Duplicate Key Insert Problem") in C. Mohan, `"Algorithms for +Creating Indexes for Very Large Tables Without Quiescing Updates" +`_, 1992. + +The sidecar index mentioned above bears some resemblance to the side file +method mentioned in Srinivasan and Mohan. +Their method consists of an index builder that extracts relevant record data to +build the new structure as quickly as possible; and an auxiliary structure that +captures all updates that would be committed to the index by other threads were +the new index already online. +After the index building scan finishes, the updates recorded in the side file +are applied to the new index. +To avoid conflicts between the index builder and other writer threads, the +builder maintains a publicly visible cursor that tracks the progress of the +scan through the record space. +To avoid duplication of work between the side file and the index builder, side +file updates are elided when the record ID for the update is greater than the +cursor position within the record ID space. + +To minimize changes to the rest of the codebase, XFS online repair keeps the +replacement index hidden until it's completely ready to go. +In other words, there is no attempt to expose the keyspace of the new index +while repair is running. +The complexity of such an approach would be very high and perhaps more +appropriate to building *new* indices. + +**Future Work Question**: Can the full scan and live update code used to +facilitate a repair also be used to implement a comprehensive check? + +*Answer*: In theory, yes. Check would be much stronger if each scrub function +employed these live scans to build a shadow copy of the metadata and then +compared the shadow records to the ondisk records. +However, doing that is a fair amount more work than what the checking functions +do now. +The live scans and hooks were developed much later. +That in turn increases the runtime of those scrub functions. + +Summary Information +``````````````````` + +Metadata structures in this last category summarize the contents of primary +metadata records. +These are often used to speed up resource usage queries, and are many times +smaller than the primary metadata which they represent. + +Examples of summary information include: + +- Summary counts of free space and inodes + +- File link counts from directories + +- Quota resource usage counts + +Check and repair require full filesystem scans, but resource and lock +acquisition follow the same paths as regular filesystem accesses. + +The superblock summary counters have special requirements due to the underlying +implementation of the incore counters, and will be treated separately. +Check and repair of the other types of summary counters (quota resource counts +and file link counts) employ the same filesystem scanning and hooking +techniques as outlined above, but because the underlying data are sets of +integer counters, the staging data need not be a fully functional mirror of the +ondisk structure. + +Inspiration for quota and file link count repair strategies were drawn from +sections 2.12 ("Online Index Operations") through 2.14 ("Incremental View +Maintenance") of G. Graefe, `"Concurrent Queries and Updates in Summary Views +and Their Indexes" +`_, 2011. + +Since quotas are non-negative integer counts of resource usage, online +quotacheck can use the incremental view deltas described in section 2.14 to +track pending changes to the block and inode usage counts in each transaction, +and commit those changes to a dquot side file when the transaction commits. +Delta tracking is necessary for dquots because the index builder scans inodes, +whereas the data structure being rebuilt is an index of dquots. +Link count checking combines the view deltas and commit step into one because +it sets attributes of the objects being scanned instead of writing them to a +separate data structure. +Each online fsck function will be discussed as case studies later in this +document. + +Risk Management +--------------- + +During the development of online fsck, several risk factors were identified +that may make the feature unsuitable for certain distributors and users. +Steps can be taken to mitigate or eliminate those risks, though at a cost to +functionality. + +- **Decreased performance**: Adding metadata indices to the filesystem + increases the time cost of persisting changes to disk, and the reverse space + mapping and directory parent pointers are no exception. + System administrators who require the maximum performance can disable the + reverse mapping features at format time, though this choice dramatically + reduces the ability of online fsck to find inconsistencies and repair them. + +- **Incorrect repairs**: As with all software, there might be defects in the + software that result in incorrect repairs being written to the filesystem. + Systematic fuzz testing (detailed in the next section) is employed by the + authors to find bugs early, but it might not catch everything. + The kernel build system provides Kconfig options (``CONFIG_XFS_ONLINE_SCRUB`` + and ``CONFIG_XFS_ONLINE_REPAIR``) to enable distributors to choose not to + accept this risk. + The xfsprogs build system has a configure option (``--enable-scrub=no``) that + disables building of the ``xfs_scrub`` binary, though this is not a risk + mitigation if the kernel functionality remains enabled. + +- **Inability to repair**: Sometimes, a filesystem is too badly damaged to be + repairable. + If the keyspaces of several metadata indices overlap in some manner but a + coherent narrative cannot be formed from records collected, then the repair + fails. + To reduce the chance that a repair will fail with a dirty transaction and + render the filesystem unusable, the online repair functions have been + designed to stage and validate all new records before committing the new + structure. + +- **Misbehavior**: Online fsck requires many privileges -- raw IO to block + devices, opening files by handle, ignoring Unix discretionary access control, + and the ability to perform administrative changes. + Running this automatically in the background scares people, so the systemd + background service is configured to run with only the privileges required. + Obviously, this cannot address certain problems like the kernel crashing or + deadlocking, but it should be sufficient to prevent the scrub process from + escaping and reconfiguring the system. + The cron job does not have this protection. + +- **Fuzz Kiddiez**: There are many people now who seem to think that running + automated fuzz testing of ondisk artifacts to find mischievous behavior and + spraying exploit code onto the public mailing list for instant zero-day + disclosure is somehow of some social benefit. + In the view of this author, the benefit is realized only when the fuzz + operators help to **fix** the flaws, but this opinion apparently is not + widely shared among security "researchers". + The XFS maintainers' continuing ability to manage these events presents an + ongoing risk to the stability of the development process. + Automated testing should front-load some of the risk while the feature is + considered EXPERIMENTAL. + +Many of these risks are inherent to software programming. +Despite this, it is hoped that this new functionality will prove useful in +reducing unexpected downtime. + +3. Testing Plan +=============== + +As stated before, fsck tools have three main goals: + +1. Detect inconsistencies in the metadata; + +2. Eliminate those inconsistencies; and + +3. Minimize further loss of data. + +Demonstrations of correct operation are necessary to build users' confidence +that the software behaves within expectations. +Unfortunately, it was not really feasible to perform regular exhaustive testing +of every aspect of a fsck tool until the introduction of low-cost virtual +machines with high-IOPS storage. +With ample hardware availability in mind, the testing strategy for the online +fsck project involves differential analysis against the existing fsck tools and +systematic testing of every attribute of every type of metadata object. +Testing can be split into four major categories, as discussed below. + +Integrated Testing with fstests +------------------------------- + +The primary goal of any free software QA effort is to make testing as +inexpensive and widespread as possible to maximize the scaling advantages of +community. +In other words, testing should maximize the breadth of filesystem configuration +scenarios and hardware setups. +This improves code quality by enabling the authors of online fsck to find and +fix bugs early, and helps developers of new features to find integration +issues earlier in their development effort. + +The Linux filesystem community shares a common QA testing suite, +`fstests `_, for +functional and regression testing. +Even before development work began on online fsck, fstests (when run on XFS) +would run both the ``xfs_check`` and ``xfs_repair -n`` commands on the test and +scratch filesystems between each test. +This provides a level of assurance that the kernel and the fsck tools stay in +alignment about what constitutes consistent metadata. +During development of the online checking code, fstests was modified to run +``xfs_scrub -n`` between each test to ensure that the new checking code +produces the same results as the two existing fsck tools. + +To start development of online repair, fstests was modified to run +``xfs_repair`` to rebuild the filesystem's metadata indices between tests. +This ensures that offline repair does not crash, leave a corrupt filesystem +after it exists, or trigger complaints from the online check. +This also established a baseline for what can and cannot be repaired offline. +To complete the first phase of development of online repair, fstests was +modified to be able to run ``xfs_scrub`` in a "force rebuild" mode. +This enables a comparison of the effectiveness of online repair as compared to +the existing offline repair tools. + +General Fuzz Testing of Metadata Blocks +--------------------------------------- + +XFS benefits greatly from having a very robust debugging tool, ``xfs_db``. + +Before development of online fsck even began, a set of fstests were created +to test the rather common fault that entire metadata blocks get corrupted. +This required the creation of fstests library code that can create a filesystem +containing every possible type of metadata object. +Next, individual test cases were created to create a test filesystem, identify +a single block of a specific type of metadata object, trash it with the +existing ``blocktrash`` command in ``xfs_db``, and test the reaction of a +particular metadata validation strategy. + +This earlier test suite enabled XFS developers to test the ability of the +in-kernel validation functions and the ability of the offline fsck tool to +detect and eliminate the inconsistent metadata. +This part of the test suite was extended to cover online fsck in exactly the +same manner. + +In other words, for a given fstests filesystem configuration: + +* For each metadata object existing on the filesystem: + + * Write garbage to it + + * Test the reactions of: + + 1. The kernel verifiers to stop obviously bad metadata + 2. Offline repair (``xfs_repair``) to detect and fix + 3. Online repair (``xfs_scrub``) to detect and fix + +Targeted Fuzz Testing of Metadata Records +----------------------------------------- + +The testing plan for online fsck includes extending the existing fs testing +infrastructure to provide a much more powerful facility: targeted fuzz testing +of every metadata field of every metadata object in the filesystem. +``xfs_db`` can modify every field of every metadata structure in every +block in the filesystem to simulate the effects of memory corruption and +software bugs. +Given that fstests already contains the ability to create a filesystem +containing every metadata format known to the filesystem, ``xfs_db`` can be +used to perform exhaustive fuzz testing! + +For a given fstests filesystem configuration: + +* For each metadata object existing on the filesystem... + + * For each record inside that metadata object... + + * For each field inside that record... + + * For each conceivable type of transformation that can be applied to a bit field... + + 1. Clear all bits + 2. Set all bits + 3. Toggle the most significant bit + 4. Toggle the middle bit + 5. Toggle the least significant bit + 6. Add a small quantity + 7. Subtract a small quantity + 8. Randomize the contents + + * ...test the reactions of: + + 1. The kernel verifiers to stop obviously bad metadata + 2. Offline checking (``xfs_repair -n``) + 3. Offline repair (``xfs_repair``) + 4. Online checking (``xfs_scrub -n``) + 5. Online repair (``xfs_scrub``) + 6. Both repair tools (``xfs_scrub`` and then ``xfs_repair`` if online repair doesn't succeed) + +This is quite the combinatoric explosion! + +Fortunately, having this much test coverage makes it easy for XFS developers to +check the responses of XFS' fsck tools. +Since the introduction of the fuzz testing framework, these tests have been +used to discover incorrect repair code and missing functionality for entire +classes of metadata objects in ``xfs_repair``. +The enhanced testing was used to finalize the deprecation of ``xfs_check`` by +confirming that ``xfs_repair`` could detect at least as many corruptions as +the older tool. + +These tests have been very valuable for ``xfs_scrub`` in the same ways -- they +allow the online fsck developers to compare online fsck against offline fsck, +and they enable XFS developers to find deficiencies in the code base. + +Proposed patchsets include +`general fuzzer improvements +`_, +`fuzzing baselines +`_, +and `improvements in fuzz testing comprehensiveness +`_. + +Stress Testing +-------------- + +A unique requirement to online fsck is the ability to operate on a filesystem +concurrently with regular workloads. +Although it is of course impossible to run ``xfs_scrub`` with *zero* observable +impact on the running system, the online repair code should never introduce +inconsistencies into the filesystem metadata, and regular workloads should +never notice resource starvation. +To verify that these conditions are being met, fstests has been enhanced in +the following ways: + +* For each scrub item type, create a test to exercise checking that item type + while running ``fsstress``. +* For each scrub item type, create a test to exercise repairing that item type + while running ``fsstress``. +* Race ``fsstress`` and ``xfs_scrub -n`` to ensure that checking the whole + filesystem doesn't cause problems. +* Race ``fsstress`` and ``xfs_scrub`` in force-rebuild mode to ensure that + force-repairing the whole filesystem doesn't cause problems. +* Race ``xfs_scrub`` in check and force-repair mode against ``fsstress`` while + freezing and thawing the filesystem. +* Race ``xfs_scrub`` in check and force-repair mode against ``fsstress`` while + remounting the filesystem read-only and read-write. +* The same, but running ``fsx`` instead of ``fsstress``. (Not done yet?) + +Success is defined by the ability to run all of these tests without observing +any unexpected filesystem shutdowns due to corrupted metadata, kernel hang +check warnings, or any other sort of mischief. + +Proposed patchsets include `general stress testing +`_ +and the `evolution of existing per-function stress testing +`_. + +4. User Interface +================= + +The primary user of online fsck is the system administrator, just like offline +repair. +Online fsck presents two modes of operation to administrators: +A foreground CLI process for online fsck on demand, and a background service +that performs autonomous checking and repair. + +Checking on Demand +------------------ + +For administrators who want the absolute freshest information about the +metadata in a filesystem, ``xfs_scrub`` can be run as a foreground process on +a command line. +The program checks every piece of metadata in the filesystem while the +administrator waits for the results to be reported, just like the existing +``xfs_repair`` tool. +Both tools share a ``-n`` option to perform a read-only scan, and a ``-v`` +option to increase the verbosity of the information reported. + +A new feature of ``xfs_scrub`` is the ``-x`` option, which employs the error +correction capabilities of the hardware to check data file contents. +The media scan is not enabled by default because it may dramatically increase +program runtime and consume a lot of bandwidth on older storage hardware. + +The output of a foreground invocation is captured in the system log. + +The ``xfs_scrub_all`` program walks the list of mounted filesystems and +initiates ``xfs_scrub`` for each of them in parallel. +It serializes scans for any filesystems that resolve to the same top level +kernel block device to prevent resource overconsumption. + +Background Service +------------------ + +To reduce the workload of system administrators, the ``xfs_scrub`` package +provides a suite of `systemd `_ timers and services that +run online fsck automatically on weekends by default. +The background service configures scrub to run with as little privilege as +possible, the lowest CPU and IO priority, and in a CPU-constrained single +threaded mode. +This can be tuned by the systemd administrator at any time to suit the latency +and throughput requirements of customer workloads. + +The output of the background service is also captured in the system log. +If desired, reports of failures (either due to inconsistencies or mere runtime +errors) can be emailed automatically by setting the ``EMAIL_ADDR`` environment +variable in the following service files: + +* ``xfs_scrub_fail@.service`` +* ``xfs_scrub_media_fail@.service`` +* ``xfs_scrub_all_fail.service`` + +The decision to enable the background scan is left to the system administrator. +This can be done by enabling either of the following services: + +* ``xfs_scrub_all.timer`` on systemd systems +* ``xfs_scrub_all.cron`` on non-systemd systems + +This automatic weekly scan is configured out of the box to perform an +additional media scan of all file data once per month. +This is less foolproof than, say, storing file data block checksums, but much +more performant if application software provides its own integrity checking, +redundancy can be provided elsewhere above the filesystem, or the storage +device's integrity guarantees are deemed sufficient. + +The systemd unit file definitions have been subjected to a security audit +(as of systemd 249) to ensure that the xfs_scrub processes have as little +access to the rest of the system as possible. +This was performed via ``systemd-analyze security``, after which privileges +were restricted to the minimum required, sandboxing was set up to the maximal +extent possible with sandboxing and system call filtering; and access to the +filesystem tree was restricted to the minimum needed to start the program and +access the filesystem being scanned. +The service definition files restrict CPU usage to 80% of one CPU core, and +apply as nice of a priority to IO and CPU scheduling as possible. +This measure was taken to minimize delays in the rest of the filesystem. +No such hardening has been performed for the cron job. + +Proposed patchset: +`Enabling the xfs_scrub background service +`_. + +Health Reporting +---------------- + +XFS caches a summary of each filesystem's health status in memory. +The information is updated whenever ``xfs_scrub`` is run, or whenever +inconsistencies are detected in the filesystem metadata during regular +operations. +System administrators should use the ``health`` command of ``xfs_spaceman`` to +download this information into a human-readable format. +If problems have been observed, the administrator can schedule a reduced +service window to run the online repair tool to correct the problem. +Failing that, the administrator can decide to schedule a maintenance window to +run the traditional offline repair tool to correct the problem. + +**Future Work Question**: Should the health reporting integrate with the new +inotify fs error notification system? +Would it be helpful for sysadmins to have a daemon to listen for corruption +notifications and initiate a repair? + +*Answer*: These questions remain unanswered, but should be a part of the +conversation with early adopters and potential downstream users of XFS. + +Proposed patchsets include +`wiring up health reports to correction returns +`_ +and +`preservation of sickness info during memory reclaim +`_. + +5. Kernel Algorithms and Data Structures +======================================== + +This section discusses the key algorithms and data structures of the kernel +code that provide the ability to check and repair metadata while the system +is running. +The first chapters in this section reveal the pieces that provide the +foundation for checking metadata. +The remainder of this section presents the mechanisms through which XFS +regenerates itself. + +Self Describing Metadata +------------------------ + +Starting with XFS version 5 in 2012, XFS updated the format of nearly every +ondisk block header to record a magic number, a checksum, a universally +"unique" identifier (UUID), an owner code, the ondisk address of the block, +and a log sequence number. +When loading a block buffer from disk, the magic number, UUID, owner, and +ondisk address confirm that the retrieved block matches the specific owner of +the current filesystem, and that the information contained in the block is +supposed to be found at the ondisk address. +The first three components enable checking tools to disregard alleged metadata +that doesn't belong to the filesystem, and the fourth component enables the +filesystem to detect lost writes. + +Whenever a file system operation modifies a block, the change is submitted +to the log as part of a transaction. +The log then processes these transactions marking them done once they are +safely persisted to storage. +The logging code maintains the checksum and the log sequence number of the last +transactional update. +Checksums are useful for detecting torn writes and other discrepancies that can +be introduced between the computer and its storage devices. +Sequence number tracking enables log recovery to avoid applying out of date +log updates to the filesystem. + +These two features improve overall runtime resiliency by providing a means for +the filesystem to detect obvious corruption when reading metadata blocks from +disk, but these buffer verifiers cannot provide any consistency checking +between metadata structures. + +For more information, please see the documentation for +Documentation/filesystems/xfs/xfs-self-describing-metadata.rst + +Reverse Mapping +--------------- + +The original design of XFS (circa 1993) is an improvement upon 1980s Unix +filesystem design. +In those days, storage density was expensive, CPU time was scarce, and +excessive seek time could kill performance. +For performance reasons, filesystem authors were reluctant to add redundancy to +the filesystem, even at the cost of data integrity. +Filesystems designers in the early 21st century choose different strategies to +increase internal redundancy -- either storing nearly identical copies of +metadata, or more space-efficient encoding techniques. + +For XFS, a different redundancy strategy was chosen to modernize the design: +a secondary space usage index that maps allocated disk extents back to their +owners. +By adding a new index, the filesystem retains most of its ability to scale +well to heavily threaded workloads involving large datasets, since the primary +file metadata (the directory tree, the file block map, and the allocation +groups) remain unchanged. +Like any system that improves redundancy, the reverse-mapping feature increases +overhead costs for space mapping activities. +However, it has two critical advantages: first, the reverse index is key to +enabling online fsck and other requested functionality such as free space +defragmentation, better media failure reporting, and filesystem shrinking. +Second, the different ondisk storage format of the reverse mapping btree +defeats device-level deduplication because the filesystem requires real +redundancy. + ++--------------------------------------------------------------------------+ +| **Sidebar**: | ++--------------------------------------------------------------------------+ +| A criticism of adding the secondary index is that it does nothing to | +| improve the robustness of user data storage itself. | +| This is a valid point, but adding a new index for file data block | +| checksums increases write amplification by turning data overwrites into | +| copy-writes, which age the filesystem prematurely. | +| In keeping with thirty years of precedent, users who want file data | +| integrity can supply as powerful a solution as they require. | +| As for metadata, the complexity of adding a new secondary index of space | +| usage is much less than adding volume management and storage device | +| mirroring to XFS itself. | +| Perfection of RAID and volume management are best left to existing | +| layers in the kernel. | ++--------------------------------------------------------------------------+ + +The information captured in a reverse space mapping record is as follows: + +.. code-block:: c + + struct xfs_rmap_irec { + xfs_agblock_t rm_startblock; /* extent start block */ + xfs_extlen_t rm_blockcount; /* extent length */ + uint64_t rm_owner; /* extent owner */ + uint64_t rm_offset; /* offset within the owner */ + unsigned int rm_flags; /* state flags */ + }; + +The first two fields capture the location and size of the physical space, +in units of filesystem blocks. +The owner field tells scrub which metadata structure or file inode have been +assigned this space. +For space allocated to files, the offset field tells scrub where the space was +mapped within the file fork. +Finally, the flags field provides extra information about the space usage -- +is this an attribute fork extent? A file mapping btree extent? Or an +unwritten data extent? + +Online filesystem checking judges the consistency of each primary metadata +record by comparing its information against all other space indices. +The reverse mapping index plays a key role in the consistency checking process +because it contains a centralized alternate copy of all space allocation +information. +Program runtime and ease of resource acquisition are the only real limits to +what online checking can consult. +For example, a file data extent mapping can be checked against: + +* The absence of an entry in the free space information. +* The absence of an entry in the inode index. +* The absence of an entry in the reference count data if the file is not + marked as having shared extents. +* The correspondence of an entry in the reverse mapping information. + +There are several observations to make about reverse mapping indices: + +1. Reverse mappings can provide a positive affirmation of correctness if any of + the above primary metadata are in doubt. + The checking code for most primary metadata follows a path similar to the + one outlined above. + +2. Proving the consistency of secondary metadata with the primary metadata is + difficult because that requires a full scan of all primary space metadata, + which is very time intensive. + For example, checking a reverse mapping record for a file extent mapping + btree block requires locking the file and searching the entire btree to + confirm the block. + Instead, scrub relies on rigorous cross-referencing during the primary space + mapping structure checks. + +3. Consistency scans must use non-blocking lock acquisition primitives if the + required locking order is not the same order used by regular filesystem + operations. + For example, if the filesystem normally takes a file ILOCK before taking + the AGF buffer lock but scrub wants to take a file ILOCK while holding + an AGF buffer lock, scrub cannot block on that second acquisition. + This means that forward progress during this part of a scan of the reverse + mapping data cannot be guaranteed if system load is heavy. + +In summary, reverse mappings play a key role in reconstruction of primary +metadata. +The details of how these records are staged, written to disk, and committed +into the filesystem are covered in subsequent sections. + +Checking and Cross-Referencing +------------------------------ + +The first step of checking a metadata structure is to examine every record +contained within the structure and its relationship with the rest of the +system. +XFS contains multiple layers of checking to try to prevent inconsistent +metadata from wreaking havoc on the system. +Each of these layers contributes information that helps the kernel to make +three decisions about the health of a metadata structure: + +- Is a part of this structure obviously corrupt (``XFS_SCRUB_OFLAG_CORRUPT``) ? +- Is this structure inconsistent with the rest of the system + (``XFS_SCRUB_OFLAG_XCORRUPT``) ? +- Is there so much damage around the filesystem that cross-referencing is not + possible (``XFS_SCRUB_OFLAG_XFAIL``) ? +- Can the structure be optimized to improve performance or reduce the size of + metadata (``XFS_SCRUB_OFLAG_PREEN``) ? +- Does the structure contain data that is not inconsistent but deserves review + by the system administrator (``XFS_SCRUB_OFLAG_WARNING``) ? + +The following sections describe how the metadata scrubbing process works. + +Metadata Buffer Verification +```````````````````````````` + +The lowest layer of metadata protection in XFS are the metadata verifiers built +into the buffer cache. +These functions perform inexpensive internal consistency checking of the block +itself, and answer these questions: + +- Does the block belong to this filesystem? + +- Does the block belong to the structure that asked for the read? + This assumes that metadata blocks only have one owner, which is always true + in XFS. + +- Is the type of data stored in the block within a reasonable range of what + scrub is expecting? + +- Does the physical location of the block match the location it was read from? + +- Does the block checksum match the data? + +The scope of the protections here are very limited -- verifiers can only +establish that the filesystem code is reasonably free of gross corruption bugs +and that the storage system is reasonably competent at retrieval. +Corruption problems observed at runtime cause the generation of health reports, +failed system calls, and in the extreme case, filesystem shutdowns if the +corrupt metadata force the cancellation of a dirty transaction. + +Every online fsck scrubbing function is expected to read every ondisk metadata +block of a structure in the course of checking the structure. +Corruption problems observed during a check are immediately reported to +userspace as corruption; during a cross-reference, they are reported as a +failure to cross-reference once the full examination is complete. +Reads satisfied by a buffer already in cache (and hence already verified) +bypass these checks. + +Internal Consistency Checks +``````````````````````````` + +After the buffer cache, the next level of metadata protection is the internal +record verification code built into the filesystem. +These checks are split between the buffer verifiers, the in-filesystem users of +the buffer cache, and the scrub code itself, depending on the amount of higher +level context required. +The scope of checking is still internal to the block. +These higher level checking functions answer these questions: + +- Does the type of data stored in the block match what scrub is expecting? + +- Does the block belong to the owning structure that asked for the read? + +- If the block contains records, do the records fit within the block? + +- If the block tracks internal free space information, is it consistent with + the record areas? + +- Are the records contained inside the block free of obvious corruptions? + +Record checks in this category are more rigorous and more time-intensive. +For example, block pointers and inumbers are checked to ensure that they point +within the dynamically allocated parts of an allocation group and within +the filesystem. +Names are checked for invalid characters, and flags are checked for invalid +combinations. +Other record attributes are checked for sensible values. +Btree records spanning an interval of the btree keyspace are checked for +correct order and lack of mergeability (except for file fork mappings). +For performance reasons, regular code may skip some of these checks unless +debugging is enabled or a write is about to occur. +Scrub functions, of course, must check all possible problems. + +Validation of Userspace-Controlled Record Attributes +```````````````````````````````````````````````````` + +Various pieces of filesystem metadata are directly controlled by userspace. +Because of this nature, validation work cannot be more precise than checking +that a value is within the possible range. +These fields include: + +- Superblock fields controlled by mount options +- Filesystem labels +- File timestamps +- File permissions +- File size +- File flags +- Names present in directory entries, extended attribute keys, and filesystem + labels +- Extended attribute key namespaces +- Extended attribute values +- File data block contents +- Quota limits +- Quota timer expiration (if resource usage exceeds the soft limit) + +Cross-Referencing Space Metadata +```````````````````````````````` + +After internal block checks, the next higher level of checking is +cross-referencing records between metadata structures. +For regular runtime code, the cost of these checks is considered to be +prohibitively expensive, but as scrub is dedicated to rooting out +inconsistencies, it must pursue all avenues of inquiry. +The exact set of cross-referencing is highly dependent on the context of the +data structure being checked. + +The XFS btree code has keyspace scanning functions that online fsck uses to +cross reference one structure with another. +Specifically, scrub can scan the key space of an index to determine if that +keyspace is fully, sparsely, or not at all mapped to records. +For the reverse mapping btree, it is possible to mask parts of the key for the +purposes of performing a keyspace scan so that scrub can decide if the rmap +btree contains records mapping a certain extent of physical space without the +sparsenses of the rest of the rmap keyspace getting in the way. + +Btree blocks undergo the following checks before cross-referencing: + +- Does the type of data stored in the block match what scrub is expecting? + +- Does the block belong to the owning structure that asked for the read? + +- Do the records fit within the block? + +- Are the records contained inside the block free of obvious corruptions? + +- Are the name hashes in the correct order? + +- Do node pointers within the btree point to valid block addresses for the type + of btree? + +- Do child pointers point towards the leaves? + +- Do sibling pointers point across the same level? + +- For each node block record, does the record key accurate reflect the contents + of the child block? + +Space allocation records are cross-referenced as follows: + +1. Any space mentioned by any metadata structure are cross-referenced as + follows: + + - Does the reverse mapping index list only the appropriate owner as the + owner of each block? + + - Are none of the blocks claimed as free space? + + - If these aren't file data blocks, are none of the blocks claimed as space + shared by different owners? + +2. Btree blocks are cross-referenced as follows: + + - Everything in class 1 above. + + - If there's a parent node block, do the keys listed for this block match the + keyspace of this block? + + - Do the sibling pointers point to valid blocks? Of the same level? + + - Do the child pointers point to valid blocks? Of the next level down? + +3. Free space btree records are cross-referenced as follows: + + - Everything in class 1 and 2 above. + + - Does the reverse mapping index list no owners of this space? + + - Is this space not claimed by the inode index for inodes? + + - Is it not mentioned by the reference count index? + + - Is there a matching record in the other free space btree? + +4. Inode btree records are cross-referenced as follows: + + - Everything in class 1 and 2 above. + + - Is there a matching record in free inode btree? + + - Do cleared bits in the holemask correspond with inode clusters? + + - Do set bits in the freemask correspond with inode records with zero link + count? + +5. Inode records are cross-referenced as follows: + + - Everything in class 1. + + - Do all the fields that summarize information about the file forks actually + match those forks? + + - Does each inode with zero link count correspond to a record in the free + inode btree? + +6. File fork space mapping records are cross-referenced as follows: + + - Everything in class 1 and 2 above. + + - Is this space not mentioned by the inode btrees? + + - If this is a CoW fork mapping, does it correspond to a CoW entry in the + reference count btree? + +7. Reference count records are cross-referenced as follows: + + - Everything in class 1 and 2 above. + + - Within the space subkeyspace of the rmap btree (that is to say, all + records mapped to a particular space extent and ignoring the owner info), + are there the same number of reverse mapping records for each block as the + reference count record claims? + +Proposed patchsets are the series to find gaps in +`refcount btree +`_, +`inode btree +`_, and +`rmap btree +`_ records; +to find +`mergeable records +`_; +and to +`improve cross referencing with rmap +`_ +before starting a repair. + +Checking Extended Attributes +```````````````````````````` + +Extended attributes implement a key-value store that enable fragments of data +to be attached to any file. +Both the kernel and userspace can access the keys and values, subject to +namespace and privilege restrictions. +Most typically these fragments are metadata about the file -- origins, security +contexts, user-supplied labels, indexing information, etc. + +Names can be as long as 255 bytes and can exist in several different +namespaces. +Values can be as large as 64KB. +A file's extended attributes are stored in blocks mapped by the attr fork. +The mappings point to leaf blocks, remote value blocks, or dabtree blocks. +Block 0 in the attribute fork is always the top of the structure, but otherwise +each of the three types of blocks can be found at any offset in the attr fork. +Leaf blocks contain attribute key records that point to the name and the value. +Names are always stored elsewhere in the same leaf block. +Values that are less than 3/4 the size of a filesystem block are also stored +elsewhere in the same leaf block. +Remote value blocks contain values that are too large to fit inside a leaf. +If the leaf information exceeds a single filesystem block, a dabtree (also +rooted at block 0) is created to map hashes of the attribute names to leaf +blocks in the attr fork. + +Checking an extended attribute structure is not so straightforward due to the +lack of separation between attr blocks and index blocks. +Scrub must read each block mapped by the attr fork and ignore the non-leaf +blocks: + +1. Walk the dabtree in the attr fork (if present) to ensure that there are no + irregularities in the blocks or dabtree mappings that do not point to + attr leaf blocks. + +2. Walk the blocks of the attr fork looking for leaf blocks. + For each entry inside a leaf: + + a. Validate that the name does not contain invalid characters. + + b. Read the attr value. + This performs a named lookup of the attr name to ensure the correctness + of the dabtree. + If the value is stored in a remote block, this also validates the + integrity of the remote value block. + +Checking and Cross-Referencing Directories +`````````````````````````````````````````` + +The filesystem directory tree is a directed acylic graph structure, with files +constituting the nodes, and directory entries (dirents) constituting the edges. +Directories are a special type of file containing a set of mappings from a +255-byte sequence (name) to an inumber. +These are called directory entries, or dirents for short. +Each directory file must have exactly one directory pointing to the file. +A root directory points to itself. +Directory entries point to files of any type. +Each non-directory file may have multiple directories point to it. + +In XFS, directories are implemented as a file containing up to three 32GB +partitions. +The first partition contains directory entry data blocks. +Each data block contains variable-sized records associating a user-provided +name with an inumber and, optionally, a file type. +If the directory entry data grows beyond one block, the second partition (which +exists as post-EOF extents) is populated with a block containing free space +information and an index that maps hashes of the dirent names to directory data +blocks in the first partition. +This makes directory name lookups very fast. +If this second partition grows beyond one block, the third partition is +populated with a linear array of free space information for faster +expansions. +If the free space has been separated and the second partition grows again +beyond one block, then a dabtree is used to map hashes of dirent names to +directory data blocks. + +Checking a directory is pretty straightforward: + +1. Walk the dabtree in the second partition (if present) to ensure that there + are no irregularities in the blocks or dabtree mappings that do not point to + dirent blocks. + +2. Walk the blocks of the first partition looking for directory entries. + Each dirent is checked as follows: + + a. Does the name contain no invalid characters? + + b. Does the inumber correspond to an actual, allocated inode? + + c. Does the child inode have a nonzero link count? + + d. If a file type is included in the dirent, does it match the type of the + inode? + + e. If the child is a subdirectory, does the child's dotdot pointer point + back to the parent? + + f. If the directory has a second partition, perform a named lookup of the + dirent name to ensure the correctness of the dabtree. + +3. Walk the free space list in the third partition (if present) to ensure that + the free spaces it describes are really unused. + +Checking operations involving :ref:`parents ` and +:ref:`file link counts ` are discussed in more detail in later +sections. + +Checking Directory/Attribute Btrees +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +As stated in previous sections, the directory/attribute btree (dabtree) index +maps user-provided names to improve lookup times by avoiding linear scans. +Internally, it maps a 32-bit hash of the name to a block offset within the +appropriate file fork. + +The internal structure of a dabtree closely resembles the btrees that record +fixed-size metadata records -- each dabtree block contains a magic number, a +checksum, sibling pointers, a UUID, a tree level, and a log sequence number. +The format of leaf and node records are the same -- each entry points to the +next level down in the hierarchy, with dabtree node records pointing to dabtree +leaf blocks, and dabtree leaf records pointing to non-dabtree blocks elsewhere +in the fork. + +Checking and cross-referencing the dabtree is very similar to what is done for +space btrees: + +- Does the type of data stored in the block match what scrub is expecting? + +- Does the block belong to the owning structure that asked for the read? + +- Do the records fit within the block? + +- Are the records contained inside the block free of obvious corruptions? + +- Are the name hashes in the correct order? + +- Do node pointers within the dabtree point to valid fork offsets for dabtree + blocks? + +- Do leaf pointers within the dabtree point to valid fork offsets for directory + or attr leaf blocks? + +- Do child pointers point towards the leaves? + +- Do sibling pointers point across the same level? + +- For each dabtree node record, does the record key accurate reflect the + contents of the child dabtree block? + +- For each dabtree leaf record, does the record key accurate reflect the + contents of the directory or attr block? + +Cross-Referencing Summary Counters +`````````````````````````````````` + +XFS maintains three classes of summary counters: available resources, quota +resource usage, and file link counts. + +In theory, the amount of available resources (data blocks, inodes, realtime +extents) can be found by walking the entire filesystem. +This would make for very slow reporting, so a transactional filesystem can +maintain summaries of this information in the superblock. +Cross-referencing these values against the filesystem metadata should be a +simple matter of walking the free space and inode metadata in each AG and the +realtime bitmap, but there are complications that will be discussed in +:ref:`more detail ` later. + +:ref:`Quota usage ` and :ref:`file link count ` +checking are sufficiently complicated to warrant separate sections. + +Post-Repair Reverification +`````````````````````````` + +After performing a repair, the checking code is run a second time to validate +the new structure, and the results of the health assessment are recorded +internally and returned to the calling process. +This step is critical for enabling system administrator to monitor the status +of the filesystem and the progress of any repairs. +For developers, it is a useful means to judge the efficacy of error detection +and correction in the online and offline checking tools. + +Eventual Consistency vs. Online Fsck +------------------------------------ + +Complex operations can make modifications to multiple per-AG data structures +with a chain of transactions. +These chains, once committed to the log, are restarted during log recovery if +the system crashes while processing the chain. +Because the AG header buffers are unlocked between transactions within a chain, +online checking must coordinate with chained operations that are in progress to +avoid incorrectly detecting inconsistencies due to pending chains. +Furthermore, online repair must not run when operations are pending because +the metadata are temporarily inconsistent with each other, and rebuilding is +not possible. + +Only online fsck has this requirement of total consistency of AG metadata, and +should be relatively rare as compared to filesystem change operations. +Online fsck coordinates with transaction chains as follows: + +* For each AG, maintain a count of intent items targeting that AG. + The count should be bumped whenever a new item is added to the chain. + The count should be dropped when the filesystem has locked the AG header + buffers and finished the work. + +* When online fsck wants to examine an AG, it should lock the AG header + buffers to quiesce all transaction chains that want to modify that AG. + If the count is zero, proceed with the checking operation. + If it is nonzero, cycle the buffer locks to allow the chain to make forward + progress. + +This may lead to online fsck taking a long time to complete, but regular +filesystem updates take precedence over background checking activity. +Details about the discovery of this situation are presented in the +:ref:`next section `, and details about the solution +are presented :ref:`after that`. + +.. _chain_coordination: + +Discovery of the Problem +```````````````````````` + +Midway through the development of online scrubbing, the fsstress tests +uncovered a misinteraction between online fsck and compound transaction chains +created by other writer threads that resulted in false reports of metadata +inconsistency. +The root cause of these reports is the eventual consistency model introduced by +the expansion of deferred work items and compound transaction chains when +reverse mapping and reflink were introduced. + +Originally, transaction chains were added to XFS to avoid deadlocks when +unmapping space from files. +Deadlock avoidance rules require that AGs only be locked in increasing order, +which makes it impossible (say) to use a single transaction to free a space +extent in AG 7 and then try to free a now superfluous block mapping btree block +in AG 3. +To avoid these kinds of deadlocks, XFS creates Extent Freeing Intent (EFI) log +items to commit to freeing some space in one transaction while deferring the +actual metadata updates to a fresh transaction. +The transaction sequence looks like this: + +1. The first transaction contains a physical update to the file's block mapping + structures to remove the mapping from the btree blocks. + It then attaches to the in-memory transaction an action item to schedule + deferred freeing of space. + Concretely, each transaction maintains a list of ``struct + xfs_defer_pending`` objects, each of which maintains a list of ``struct + xfs_extent_free_item`` objects. + Returning to the example above, the action item tracks the freeing of both + the unmapped space from AG 7 and the block mapping btree (BMBT) block from + AG 3. + Deferred frees recorded in this manner are committed in the log by creating + an EFI log item from the ``struct xfs_extent_free_item`` object and + attaching the log item to the transaction. + When the log is persisted to disk, the EFI item is written into the ondisk + transaction record. + EFIs can list up to 16 extents to free, all sorted in AG order. + +2. The second transaction contains a physical update to the free space btrees + of AG 3 to release the former BMBT block and a second physical update to the + free space btrees of AG 7 to release the unmapped file space. + Observe that the physical updates are resequenced in the correct order + when possible. + Attached to the transaction is a an extent free done (EFD) log item. + The EFD contains a pointer to the EFI logged in transaction #1 so that log + recovery can tell if the EFI needs to be replayed. + +If the system goes down after transaction #1 is written back to the filesystem +but before #2 is committed, a scan of the filesystem metadata would show +inconsistent filesystem metadata because there would not appear to be any owner +of the unmapped space. +Happily, log recovery corrects this inconsistency for us -- when recovery finds +an intent log item but does not find a corresponding intent done item, it will +reconstruct the incore state of the intent item and finish it. +In the example above, the log must replay both frees described in the recovered +EFI to complete the recovery phase. + +There are subtleties to XFS' transaction chaining strategy to consider: + +* Log items must be added to a transaction in the correct order to prevent + conflicts with principal objects that are not held by the transaction. + In other words, all per-AG metadata updates for an unmapped block must be + completed before the last update to free the extent, and extents should not + be reallocated until that last update commits to the log. + +* AG header buffers are released between each transaction in a chain. + This means that other threads can observe an AG in an intermediate state, + but as long as the first subtlety is handled, this should not affect the + correctness of filesystem operations. + +* Unmounting the filesystem flushes all pending work to disk, which means that + offline fsck never sees the temporary inconsistencies caused by deferred + work item processing. + +In this manner, XFS employs a form of eventual consistency to avoid deadlocks +and increase parallelism. + +During the design phase of the reverse mapping and reflink features, it was +decided that it was impractical to cram all the reverse mapping updates for a +single filesystem change into a single transaction because a single file +mapping operation can explode into many small updates: + +* The block mapping update itself +* A reverse mapping update for the block mapping update +* Fixing the freelist +* A reverse mapping update for the freelist fix + +* A shape change to the block mapping btree +* A reverse mapping update for the btree update +* Fixing the freelist (again) +* A reverse mapping update for the freelist fix + +* An update to the reference counting information +* A reverse mapping update for the refcount update +* Fixing the freelist (a third time) +* A reverse mapping update for the freelist fix + +* Freeing any space that was unmapped and not owned by any other file +* Fixing the freelist (a fourth time) +* A reverse mapping update for the freelist fix + +* Freeing the space used by the block mapping btree +* Fixing the freelist (a fifth time) +* A reverse mapping update for the freelist fix + +Free list fixups are not usually needed more than once per AG per transaction +chain, but it is theoretically possible if space is very tight. +For copy-on-write updates this is even worse, because this must be done once to +remove the space from a staging area and again to map it into the file! + +To deal with this explosion in a calm manner, XFS expands its use of deferred +work items to cover most reverse mapping updates and all refcount updates. +This reduces the worst case size of transaction reservations by breaking the +work into a long chain of small updates, which increases the degree of eventual +consistency in the system. +Again, this generally isn't a problem because XFS orders its deferred work +items carefully to avoid resource reuse conflicts between unsuspecting threads. + +However, online fsck changes the rules -- remember that although physical +updates to per-AG structures are coordinated by locking the buffers for AG +headers, buffer locks are dropped between transactions. +Once scrub acquires resources and takes locks for a data structure, it must do +all the validation work without releasing the lock. +If the main lock for a space btree is an AG header buffer lock, scrub may have +interrupted another thread that is midway through finishing a chain. +For example, if a thread performing a copy-on-write has completed a reverse +mapping update but not the corresponding refcount update, the two AG btrees +will appear inconsistent to scrub and an observation of corruption will be +recorded. This observation will not be correct. +If a repair is attempted in this state, the results will be catastrophic! + +Several other solutions to this problem were evaluated upon discovery of this +flaw and rejected: + +1. Add a higher level lock to allocation groups and require writer threads to + acquire the higher level lock in AG order before making any changes. + This would be very difficult to implement in practice because it is + difficult to determine which locks need to be obtained, and in what order, + without simulating the entire operation. + Performing a dry run of a file operation to discover necessary locks would + make the filesystem very slow. + +2. Make the deferred work coordinator code aware of consecutive intent items + targeting the same AG and have it hold the AG header buffers locked across + the transaction roll between updates. + This would introduce a lot of complexity into the coordinator since it is + only loosely coupled with the actual deferred work items. + It would also fail to solve the problem because deferred work items can + generate new deferred subtasks, but all subtasks must be complete before + work can start on a new sibling task. + +3. Teach online fsck to walk all transactions waiting for whichever lock(s) + protect the data structure being scrubbed to look for pending operations. + The checking and repair operations must factor these pending operations into + the evaluations being performed. + This solution is a nonstarter because it is *extremely* invasive to the main + filesystem. + +.. _intent_drains: + +Intent Drains +````````````` + +Online fsck uses an atomic intent item counter and lock cycling to coordinate +with transaction chains. +There are two key properties to the drain mechanism. +First, the counter is incremented when a deferred work item is *queued* to a +transaction, and it is decremented after the associated intent done log item is +*committed* to another transaction. +The second property is that deferred work can be added to a transaction without +holding an AG header lock, but per-AG work items cannot be marked done without +locking that AG header buffer to log the physical updates and the intent done +log item. +The first property enables scrub to yield to running transaction chains, which +is an explicit deprioritization of online fsck to benefit file operations. +The second property of the drain is key to the correct coordination of scrub, +since scrub will always be able to decide if a conflict is possible. + +For regular filesystem code, the drain works as follows: + +1. Call the appropriate subsystem function to add a deferred work item to a + transaction. + +2. The function calls ``xfs_defer_drain_bump`` to increase the counter. + +3. When the deferred item manager wants to finish the deferred work item, it + calls ``->finish_item`` to complete it. + +4. The ``->finish_item`` implementation logs some changes and calls + ``xfs_defer_drain_drop`` to decrease the sloppy counter and wake up any threads + waiting on the drain. + +5. The subtransaction commits, which unlocks the resource associated with the + intent item. + +For scrub, the drain works as follows: + +1. Lock the resource(s) associated with the metadata being scrubbed. + For example, a scan of the refcount btree would lock the AGI and AGF header + buffers. + +2. If the counter is zero (``xfs_defer_drain_busy`` returns false), there are no + chains in progress and the operation may proceed. + +3. Otherwise, release the resources grabbed in step 1. + +4. Wait for the intent counter to reach zero (``xfs_defer_drain_intents``), then go + back to step 1 unless a signal has been caught. + +To avoid polling in step 4, the drain provides a waitqueue for scrub threads to +be woken up whenever the intent count drops to zero. + +The proposed patchset is the +`scrub intent drain series +`_. + +.. _jump_labels: + +Static Keys (aka Jump Label Patching) +````````````````````````````````````` + +Online fsck for XFS separates the regular filesystem from the checking and +repair code as much as possible. +However, there are a few parts of online fsck (such as the intent drains, and +later, live update hooks) where it is useful for the online fsck code to know +what's going on in the rest of the filesystem. +Since it is not expected that online fsck will be constantly running in the +background, it is very important to minimize the runtime overhead imposed by +these hooks when online fsck is compiled into the kernel but not actively +running on behalf of userspace. +Taking locks in the hot path of a writer thread to access a data structure only +to find that no further action is necessary is expensive -- on the author's +computer, this have an overhead of 40-50ns per access. +Fortunately, the kernel supports dynamic code patching, which enables XFS to +replace a static branch to hook code with ``nop`` sleds when online fsck isn't +running. +This sled has an overhead of however long it takes the instruction decoder to +skip past the sled, which seems to be on the order of less than 1ns and +does not access memory outside of instruction fetching. + +When online fsck enables the static key, the sled is replaced with an +unconditional branch to call the hook code. +The switchover is quite expensive (~22000ns) but is paid entirely by the +program that invoked online fsck, and can be amortized if multiple threads +enter online fsck at the same time, or if multiple filesystems are being +checked at the same time. +Changing the branch direction requires taking the CPU hotplug lock, and since +CPU initialization requires memory allocation, online fsck must be careful not +to change a static key while holding any locks or resources that could be +accessed in the memory reclaim paths. +To minimize contention on the CPU hotplug lock, care should be taken not to +enable or disable static keys unnecessarily. + +Because static keys are intended to minimize hook overhead for regular +filesystem operations when xfs_scrub is not running, the intended usage +patterns are as follows: + +- The hooked part of XFS should declare a static-scoped static key that + defaults to false. + The ``DEFINE_STATIC_KEY_FALSE`` macro takes care of this. + The static key itself should be declared as a ``static`` variable. + +- When deciding to invoke code that's only used by scrub, the regular + filesystem should call the ``static_branch_unlikely`` predicate to avoid the + scrub-only hook code if the static key is not enabled. + +- The regular filesystem should export helper functions that call + ``static_branch_inc`` to enable and ``static_branch_dec`` to disable the + static key. + Wrapper functions make it easy to compile out the relevant code if the kernel + distributor turns off online fsck at build time. + +- Scrub functions wanting to turn on scrub-only XFS functionality should call + the ``xchk_fsgates_enable`` from the setup function to enable a specific + hook. + This must be done before obtaining any resources that are used by memory + reclaim. + Callers had better be sure they really need the functionality gated by the + static key; the ``TRY_HARDER`` flag is useful here. + +Online scrub has resource acquisition helpers (e.g. ``xchk_perag_lock``) to +handle locking AGI and AGF buffers for all scrubber functions. +If it detects a conflict between scrub and the running transactions, it will +try to wait for intents to complete. +If the caller of the helper has not enabled the static key, the helper will +return -EDEADLOCK, which should result in the scrub being restarted with the +``TRY_HARDER`` flag set. +The scrub setup function should detect that flag, enable the static key, and +try the scrub again. +Scrub teardown disables all static keys obtained by ``xchk_fsgates_enable``. + +For more information, please see the kernel documentation of +Documentation/staging/static-keys.rst. + +.. _xfile: + +Pageable Kernel Memory +---------------------- + +Some online checking functions work by scanning the filesystem to build a +shadow copy of an ondisk metadata structure in memory and comparing the two +copies. +For online repair to rebuild a metadata structure, it must compute the record +set that will be stored in the new structure before it can persist that new +structure to disk. +Ideally, repairs complete with a single atomic commit that introduces +a new data structure. +To meet these goals, the kernel needs to collect a large amount of information +in a place that doesn't require the correct operation of the filesystem. + +Kernel memory isn't suitable because: + +* Allocating a contiguous region of memory to create a C array is very + difficult, especially on 32-bit systems. + +* Linked lists of records introduce double pointer overhead which is very high + and eliminate the possibility of indexed lookups. + +* Kernel memory is pinned, which can drive the system into OOM conditions. + +* The system might not have sufficient memory to stage all the information. + +At any given time, online fsck does not need to keep the entire record set in +memory, which means that individual records can be paged out if necessary. +Continued development of online fsck demonstrated that the ability to perform +indexed data storage would also be very useful. +Fortunately, the Linux kernel already has a facility for byte-addressable and +pageable storage: tmpfs. +In-kernel graphics drivers (most notably i915) take advantage of tmpfs files +to store intermediate data that doesn't need to be in memory at all times, so +that usage precedent is already established. +Hence, the ``xfile`` was born! + ++--------------------------------------------------------------------------+ +| **Historical Sidebar**: | ++--------------------------------------------------------------------------+ +| The first edition of online repair inserted records into a new btree as | +| it found them, which failed because filesystem could shut down with a | +| built data structure, which would be live after recovery finished. | +| | +| The second edition solved the half-rebuilt structure problem by storing | +| everything in memory, but frequently ran the system out of memory. | +| | +| The third edition solved the OOM problem by using linked lists, but the | +| memory overhead of the list pointers was extreme. | ++--------------------------------------------------------------------------+ + +xfile Access Models +``````````````````` + +A survey of the intended uses of xfiles suggested these use cases: + +1. Arrays of fixed-sized records (space management btrees, directory and + extended attribute entries) + +2. Sparse arrays of fixed-sized records (quotas and link counts) + +3. Large binary objects (BLOBs) of variable sizes (directory and extended + attribute names and values) + +4. Staging btrees in memory (reverse mapping btrees) + +5. Arbitrary contents (realtime space management) + +To support the first four use cases, high level data structures wrap the xfile +to share functionality between online fsck functions. +The rest of this section discusses the interfaces that the xfile presents to +four of those five higher level data structures. +The fifth use case is discussed in the :ref:`realtime summary ` case +study. + +The most general storage interface supported by the xfile enables the reading +and writing of arbitrary quantities of data at arbitrary offsets in the xfile. +This capability is provided by ``xfile_pread`` and ``xfile_pwrite`` functions, +which behave similarly to their userspace counterparts. +XFS is very record-based, which suggests that the ability to load and store +complete records is important. +To support these cases, a pair of ``xfile_obj_load`` and ``xfile_obj_store`` +functions are provided to read and persist objects into an xfile. +They are internally the same as pread and pwrite, except that they treat any +error as an out of memory error. +For online repair, squashing error conditions in this manner is an acceptable +behavior because the only reaction is to abort the operation back to userspace. +All five xfile usecases can be serviced by these four functions. + +However, no discussion of file access idioms is complete without answering the +question, "But what about mmap?" +It is convenient to access storage directly with pointers, just like userspace +code does with regular memory. +Online fsck must not drive the system into OOM conditions, which means that +xfiles must be responsive to memory reclamation. +tmpfs can only push a pagecache folio to the swap cache if the folio is neither +pinned nor locked, which means the xfile must not pin too many folios. + +Short term direct access to xfile contents is done by locking the pagecache +folio and mapping it into kernel address space. +Programmatic access (e.g. pread and pwrite) uses this mechanism. +Folio locks are not supposed to be held for long periods of time, so long +term direct access to xfile contents is done by bumping the folio refcount, +mapping it into kernel address space, and dropping the folio lock. +These long term users *must* be responsive to memory reclaim by hooking into +the shrinker infrastructure to know when to release folios. + +The ``xfile_get_page`` and ``xfile_put_page`` functions are provided to +retrieve the (locked) folio that backs part of an xfile and to release it. +The only code to use these folio lease functions are the xfarray +:ref:`sorting` algorithms and the :ref:`in-memory +btrees`. + +xfile Access Coordination +````````````````````````` + +For security reasons, xfiles must be owned privately by the kernel. +They are marked ``S_PRIVATE`` to prevent interference from the security system, +must never be mapped into process file descriptor tables, and their pages must +never be mapped into userspace processes. + +To avoid locking recursion issues with the VFS, all accesses to the shmfs file +are performed by manipulating the page cache directly. +xfile writers call the ``->write_begin`` and ``->write_end`` functions of the +xfile's address space to grab writable pages, copy the caller's buffer into the +page, and release the pages. +xfile readers call ``shmem_read_mapping_page_gfp`` to grab pages directly +before copying the contents into the caller's buffer. +In other words, xfiles ignore the VFS read and write code paths to avoid +having to create a dummy ``struct kiocb`` and to avoid taking inode and +freeze locks. +tmpfs cannot be frozen, and xfiles must not be exposed to userspace. + +If an xfile is shared between threads to stage repairs, the caller must provide +its own locks to coordinate access. +For example, if a scrub function stores scan results in an xfile and needs +other threads to provide updates to the scanned data, the scrub function must +provide a lock for all threads to share. + +.. _xfarray: + +Arrays of Fixed-Sized Records +````````````````````````````` + +In XFS, each type of indexed space metadata (free space, inodes, reference +counts, file fork space, and reverse mappings) consists of a set of fixed-size +records indexed with a classic B+ tree. +Directories have a set of fixed-size dirent records that point to the names, +and extended attributes have a set of fixed-size attribute keys that point to +names and values. +Quota counters and file link counters index records with numbers. +During a repair, scrub needs to stage new records during the gathering step and +retrieve them during the btree building step. + +Although this requirement can be satisfied by calling the read and write +methods of the xfile directly, it is simpler for callers for there to be a +higher level abstraction to take care of computing array offsets, to provide +iterator functions, and to deal with sparse records and sorting. +The ``xfarray`` abstraction presents a linear array for fixed-size records atop +the byte-accessible xfile. + +.. _xfarray_access_patterns: + +Array Access Patterns +^^^^^^^^^^^^^^^^^^^^^ + +Array access patterns in online fsck tend to fall into three categories. +Iteration of records is assumed to be necessary for all cases and will be +covered in the next section. + +The first type of caller handles records that are indexed by position. +Gaps may exist between records, and a record may be updated multiple times +during the collection step. +In other words, these callers want a sparse linearly addressed table file. +The typical use case are quota records or file link count records. +Access to array elements is performed programmatically via ``xfarray_load`` and +``xfarray_store`` functions, which wrap the similarly-named xfile functions to +provide loading and storing of array elements at arbitrary array indices. +Gaps are defined to be null records, and null records are defined to be a +sequence of all zero bytes. +Null records are detected by calling ``xfarray_element_is_null``. +They are created either by calling ``xfarray_unset`` to null out an existing +record or by never storing anything to an array index. + +The second type of caller handles records that are not indexed by position +and do not require multiple updates to a record. +The typical use case here is rebuilding space btrees and key/value btrees. +These callers can add records to the array without caring about array indices +via the ``xfarray_append`` function, which stores a record at the end of the +array. +For callers that require records to be presentable in a specific order (e.g. +rebuilding btree data), the ``xfarray_sort`` function can arrange the sorted +records; this function will be covered later. + +The third type of caller is a bag, which is useful for counting records. +The typical use case here is constructing space extent reference counts from +reverse mapping information. +Records can be put in the bag in any order, they can be removed from the bag +at any time, and uniqueness of records is left to callers. +The ``xfarray_store_anywhere`` function is used to insert a record in any +null record slot in the bag; and the ``xfarray_unset`` function removes a +record from the bag. + +The proposed patchset is the +`big in-memory array +`_. + +Iterating Array Elements +^^^^^^^^^^^^^^^^^^^^^^^^ + +Most users of the xfarray require the ability to iterate the records stored in +the array. +Callers can probe every possible array index with the following: + +.. code-block:: c + + xfarray_idx_t i; + foreach_xfarray_idx(array, i) { + xfarray_load(array, i, &rec); + + /* do something with rec */ + } + +All users of this idiom must be prepared to handle null records or must already +know that there aren't any. + +For xfarray users that want to iterate a sparse array, the ``xfarray_iter`` +function ignores indices in the xfarray that have never been written to by +calling ``xfile_seek_data`` (which internally uses ``SEEK_DATA``) to skip areas +of the array that are not populated with memory pages. +Once it finds a page, it will skip the zeroed areas of the page. + +.. code-block:: c + + xfarray_idx_t i = XFARRAY_CURSOR_INIT; + while ((ret = xfarray_iter(array, &i, &rec)) == 1) { + /* do something with rec */ + } + +.. _xfarray_sort: + +Sorting Array Elements +^^^^^^^^^^^^^^^^^^^^^^ + +During the fourth demonstration of online repair, a community reviewer remarked +that for performance reasons, online repair ought to load batches of records +into btree record blocks instead of inserting records into a new btree one at a +time. +The btree insertion code in XFS is responsible for maintaining correct ordering +of the records, so naturally the xfarray must also support sorting the record +set prior to bulk loading. + +Case Study: Sorting xfarrays +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The sorting algorithm used in the xfarray is actually a combination of adaptive +quicksort and a heapsort subalgorithm in the spirit of +`Sedgewick `_ and +`pdqsort `_, with customizations for the Linux +kernel. +To sort records in a reasonably short amount of time, ``xfarray`` takes +advantage of the binary subpartitioning offered by quicksort, but it also uses +heapsort to hedge against performance collapse if the chosen quicksort pivots +are poor. +Both algorithms are (in general) O(n * lg(n)), but there is a wide performance +gulf between the two implementations. + +The Linux kernel already contains a reasonably fast implementation of heapsort. +It only operates on regular C arrays, which limits the scope of its usefulness. +There are two key places where the xfarray uses it: + +* Sorting any record subset backed by a single xfile page. + +* Loading a small number of xfarray records from potentially disparate parts + of the xfarray into a memory buffer, and sorting the buffer. + +In other words, ``xfarray`` uses heapsort to constrain the nested recursion of +quicksort, thereby mitigating quicksort's worst runtime behavior. + +Choosing a quicksort pivot is a tricky business. +A good pivot splits the set to sort in half, leading to the divide and conquer +behavior that is crucial to O(n * lg(n)) performance. +A poor pivot barely splits the subset at all, leading to O(n\ :sup:`2`) +runtime. +The xfarray sort routine tries to avoid picking a bad pivot by sampling nine +records into a memory buffer and using the kernel heapsort to identify the +median of the nine. + +Most modern quicksort implementations employ Tukey's "ninther" to select a +pivot from a classic C array. +Typical ninther implementations pick three unique triads of records, sort each +of the triads, and then sort the middle value of each triad to determine the +ninther value. +As stated previously, however, xfile accesses are not entirely cheap. +It turned out to be much more performant to read the nine elements into a +memory buffer, run the kernel's in-memory heapsort on the buffer, and choose +the 4th element of that buffer as the pivot. +Tukey's ninthers are described in J. W. Tukey, `The ninther, a technique for +low-effort robust (resistant) location in large samples`, in *Contributions to +Survey Sampling and Applied Statistics*, edited by H. David, (Academic Press, +1978), pp. 251–257. + +The partitioning of quicksort is fairly textbook -- rearrange the record +subset around the pivot, then set up the current and next stack frames to +sort with the larger and the smaller halves of the pivot, respectively. +This keeps the stack space requirements to log2(record count). + +As a final performance optimization, the hi and lo scanning phase of quicksort +keeps examined xfile pages mapped in the kernel for as long as possible to +reduce map/unmap cycles. +Surprisingly, this reduces overall sort runtime by nearly half again after +accounting for the application of heapsort directly onto xfile pages. + +.. _xfblob: + +Blob Storage +```````````` + +Extended attributes and directories add an additional requirement for staging +records: arbitrary byte sequences of finite length. +Each directory entry record needs to store entry name, +and each extended attribute needs to store both the attribute name and value. +The names, keys, and values can consume a large amount of memory, so the +``xfblob`` abstraction was created to simplify management of these blobs +atop an xfile. + +Blob arrays provide ``xfblob_load`` and ``xfblob_store`` functions to retrieve +and persist objects. +The store function returns a magic cookie for every object that it persists. +Later, callers provide this cookie to the ``xblob_load`` to recall the object. +The ``xfblob_free`` function frees a specific blob, and the ``xfblob_truncate`` +function frees them all because compaction is not needed. + +The details of repairing directories and extended attributes will be discussed +in a subsequent section about atomic extent swapping. +However, it should be noted that these repair functions only use blob storage +to cache a small number of entries before adding them to a temporary ondisk +file, which is why compaction is not required. + +The proposed patchset is at the start of the +`extended attribute repair +`_ series. + +.. _xfbtree: + +In-Memory B+Trees +````````````````` + +The chapter about :ref:`secondary metadata` mentioned that +checking and repairing of secondary metadata commonly requires coordination +between a live metadata scan of the filesystem and writer threads that are +updating that metadata. +Keeping the scan data up to date requires requires the ability to propagate +metadata updates from the filesystem into the data being collected by the scan. +This *can* be done by appending concurrent updates into a separate log file and +applying them before writing the new metadata to disk, but this leads to +unbounded memory consumption if the rest of the system is very busy. +Another option is to skip the side-log and commit live updates from the +filesystem directly into the scan data, which trades more overhead for a lower +maximum memory requirement. +In both cases, the data structure holding the scan results must support indexed +access to perform well. + +Given that indexed lookups of scan data is required for both strategies, online +fsck employs the second strategy of committing live updates directly into +scan data. +Because xfarrays are not indexed and do not enforce record ordering, they +are not suitable for this task. +Conveniently, however, XFS has a library to create and maintain ordered reverse +mapping records: the existing rmap btree code! +If only there was a means to create one in memory. + +Recall that the :ref:`xfile ` abstraction represents memory pages as a +regular file, which means that the kernel can create byte or block addressable +virtual address spaces at will. +The XFS buffer cache specializes in abstracting IO to block-oriented address +spaces, which means that adaptation of the buffer cache to interface with +xfiles enables reuse of the entire btree library. +Btrees built atop an xfile are collectively known as ``xfbtrees``. +The next few sections describe how they actually work. + +The proposed patchset is the +`in-memory btree +`_ +series. + +Using xfiles as a Buffer Cache Target +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Two modifications are necessary to support xfiles as a buffer cache target. +The first is to make it possible for the ``struct xfs_buftarg`` structure to +host the ``struct xfs_buf`` rhashtable, because normally those are held by a +per-AG structure. +The second change is to modify the buffer ``ioapply`` function to "read" cached +pages from the xfile and "write" cached pages back to the xfile. +Multiple access to individual buffers is controlled by the ``xfs_buf`` lock, +since the xfile does not provide any locking on its own. +With this adaptation in place, users of the xfile-backed buffer cache use +exactly the same APIs as users of the disk-backed buffer cache. +The separation between xfile and buffer cache implies higher memory usage since +they do not share pages, but this property could some day enable transactional +updates to an in-memory btree. +Today, however, it simply eliminates the need for new code. + +Space Management with an xfbtree +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Space management for an xfile is very simple -- each btree block is one memory +page in size. +These blocks use the same header format as an on-disk btree, but the in-memory +block verifiers ignore the checksums, assuming that xfile memory is no more +corruption-prone than regular DRAM. +Reusing existing code here is more important than absolute memory efficiency. + +The very first block of an xfile backing an xfbtree contains a header block. +The header describes the owner, height, and the block number of the root +xfbtree block. + +To allocate a btree block, use ``xfile_seek_data`` to find a gap in the file. +If there are no gaps, create one by extending the length of the xfile. +Preallocate space for the block with ``xfile_prealloc``, and hand back the +location. +To free an xfbtree block, use ``xfile_discard`` (which internally uses +``FALLOC_FL_PUNCH_HOLE``) to remove the memory page from the xfile. + +Populating an xfbtree +^^^^^^^^^^^^^^^^^^^^^ + +An online fsck function that wants to create an xfbtree should proceed as +follows: + +1. Call ``xfile_create`` to create an xfile. + +2. Call ``xfs_alloc_memory_buftarg`` to create a buffer cache target structure + pointing to the xfile. + +3. Pass the buffer cache target, buffer ops, and other information to + ``xfbtree_create`` to write an initial tree header and root block to the + xfile. + Each btree type should define a wrapper that passes necessary arguments to + the creation function. + For example, rmap btrees define ``xfs_rmapbt_mem_create`` to take care of + all the necessary details for callers. + A ``struct xfbtree`` object will be returned. + +4. Pass the xfbtree object to the btree cursor creation function for the + btree type. + Following the example above, ``xfs_rmapbt_mem_cursor`` takes care of this + for callers. + +5. Pass the btree cursor to the regular btree functions to make queries against + and to update the in-memory btree. + For example, a btree cursor for an rmap xfbtree can be passed to the + ``xfs_rmap_*`` functions just like any other btree cursor. + See the :ref:`next section` for information on dealing with + xfbtree updates that are logged to a transaction. + +6. When finished, delete the btree cursor, destroy the xfbtree object, free the + buffer target, and the destroy the xfile to release all resources. + +.. _xfbtree_commit: + +Committing Logged xfbtree Buffers +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Although it is a clever hack to reuse the rmap btree code to handle the staging +structure, the ephemeral nature of the in-memory btree block storage presents +some challenges of its own. +The XFS transaction manager must not commit buffer log items for buffers backed +by an xfile because the log format does not understand updates for devices +other than the data device. +An ephemeral xfbtree probably will not exist by the time the AIL checkpoints +log transactions back into the filesystem, and certainly won't exist during +log recovery. +For these reasons, any code updating an xfbtree in transaction context must +remove the buffer log items from the transaction and write the updates into the +backing xfile before committing or cancelling the transaction. + +The ``xfbtree_trans_commit`` and ``xfbtree_trans_cancel`` functions implement +this functionality as follows: + +1. Find each buffer log item whose buffer targets the xfile. + +2. Record the dirty/ordered status of the log item. + +3. Detach the log item from the buffer. + +4. Queue the buffer to a special delwri list. + +5. Clear the transaction dirty flag if the only dirty log items were the ones + that were detached in step 3. + +6. Submit the delwri list to commit the changes to the xfile, if the updates + are being committed. + +After removing xfile logged buffers from the transaction in this manner, the +transaction can be committed or cancelled. + +Bulk Loading of Ondisk B+Trees +------------------------------ + +As mentioned previously, early iterations of online repair built new btree +structures by creating a new btree and adding observations individually. +Loading a btree one record at a time had a slight advantage of not requiring +the incore records to be sorted prior to commit, but was very slow and leaked +blocks if the system went down during a repair. +Loading records one at a time also meant that repair could not control the +loading factor of the blocks in the new btree. + +Fortunately, the venerable ``xfs_repair`` tool had a more efficient means for +rebuilding a btree index from a collection of records -- bulk btree loading. +This was implemented rather inefficiently code-wise, since ``xfs_repair`` +had separate copy-pasted implementations for each btree type. + +To prepare for online fsck, each of the four bulk loaders were studied, notes +were taken, and the four were refactored into a single generic btree bulk +loading mechanism. +Those notes in turn have been refreshed and are presented below. + +Geometry Computation +```````````````````` + +The zeroth step of bulk loading is to assemble the entire record set that will +be stored in the new btree, and sort the records. +Next, call ``xfs_btree_bload_compute_geometry`` to compute the shape of the +btree from the record set, the type of btree, and any load factor preferences. +This information is required for resource reservation. + +First, the geometry computation computes the minimum and maximum records that +will fit in a leaf block from the size of a btree block and the size of the +block header. +Roughly speaking, the maximum number of records is:: + + maxrecs = (block_size - header_size) / record_size + +The XFS design specifies that btree blocks should be merged when possible, +which means the minimum number of records is half of maxrecs:: + + minrecs = maxrecs / 2 + +The next variable to determine is the desired loading factor. +This must be at least minrecs and no more than maxrecs. +Choosing minrecs is undesirable because it wastes half the block. +Choosing maxrecs is also undesirable because adding a single record to each +newly rebuilt leaf block will cause a tree split, which causes a noticeable +drop in performance immediately afterwards. +The default loading factor was chosen to be 75% of maxrecs, which provides a +reasonably compact structure without any immediate split penalties:: + + default_load_factor = (maxrecs + minrecs) / 2 + +If space is tight, the loading factor will be set to maxrecs to try to avoid +running out of space:: + + leaf_load_factor = enough space ? default_load_factor : maxrecs + +Load factor is computed for btree node blocks using the combined size of the +btree key and pointer as the record size:: + + maxrecs = (block_size - header_size) / (key_size + ptr_size) + minrecs = maxrecs / 2 + node_load_factor = enough space ? default_load_factor : maxrecs + +Once that's done, the number of leaf blocks required to store the record set +can be computed as:: + + leaf_blocks = ceil(record_count / leaf_load_factor) + +The number of node blocks needed to point to the next level down in the tree +is computed as:: + + n_blocks = (n == 0 ? leaf_blocks : node_blocks[n]) + node_blocks[n + 1] = ceil(n_blocks / node_load_factor) + +The entire computation is performed recursively until the current level only +needs one block. +The resulting geometry is as follows: + +- For AG-rooted btrees, this level is the root level, so the height of the new + tree is ``level + 1`` and the space needed is the summation of the number of + blocks on each level. + +- For inode-rooted btrees where the records in the top level do not fit in the + inode fork area, the height is ``level + 2``, the space needed is the + summation of the number of blocks on each level, and the inode fork points to + the root block. + +- For inode-rooted btrees where the records in the top level can be stored in + the inode fork area, then the root block can be stored in the inode, the + height is ``level + 1``, and the space needed is one less than the summation + of the number of blocks on each level. + This only becomes relevant when non-bmap btrees gain the ability to root in + an inode, which is a future patchset and only included here for completeness. + +.. _newbt: + +Reserving New B+Tree Blocks +``````````````````````````` + +Once repair knows the number of blocks needed for the new btree, it allocates +those blocks using the free space information. +Each reserved extent is tracked separately by the btree builder state data. +To improve crash resilience, the reservation code also logs an Extent Freeing +Intent (EFI) item in the same transaction as each space allocation and attaches +its in-memory ``struct xfs_extent_free_item`` object to the space reservation. +If the system goes down, log recovery will use the unfinished EFIs to free the +unused space, the free space, leaving the filesystem unchanged. + +Each time the btree builder claims a block for the btree from a reserved +extent, it updates the in-memory reservation to reflect the claimed space. +Block reservation tries to allocate as much contiguous space as possible to +reduce the number of EFIs in play. + +While repair is writing these new btree blocks, the EFIs created for the space +reservations pin the tail of the ondisk log. +It's possible that other parts of the system will remain busy and push the head +of the log towards the pinned tail. +To avoid livelocking the filesystem, the EFIs must not pin the tail of the log +for too long. +To alleviate this problem, the dynamic relogging capability of the deferred ops +mechanism is reused here to commit a transaction at the log head containing an +EFD for the old EFI and new EFI at the head. +This enables the log to release the old EFI to keep the log moving forwards. + +EFIs have a role to play during the commit and reaping phases; please see the +next section and the section about :ref:`reaping` for more details. + +Proposed patchsets are the +`bitmap rework +`_ +and the +`preparation for bulk loading btrees +`_. + + +Writing the New Tree +```````````````````` + +This part is pretty simple -- the btree builder (``xfs_btree_bulkload``) claims +a block from the reserved list, writes the new btree block header, fills the +rest of the block with records, and adds the new leaf block to a list of +written blocks:: + + ┌────┐ + │leaf│ + │RRR │ + └────┘ + +Sibling pointers are set every time a new block is added to the level:: + + ┌────┐ ┌────┐ ┌────┐ ┌────┐ + │leaf│→│leaf│→│leaf│→│leaf│ + │RRR │←│RRR │←│RRR │←│RRR │ + └────┘ └────┘ └────┘ └────┘ + +When it finishes writing the record leaf blocks, it moves on to the node +blocks +To fill a node block, it walks each block in the next level down in the tree +to compute the relevant keys and write them into the parent node:: + + ┌────┐ ┌────┐ + │node│──────→│node│ + │PP │←──────│PP │ + └────┘ └────┘ + ↙ ↘ ↙ ↘ + ┌────┐ ┌────┐ ┌────┐ ┌────┐ + │leaf│→│leaf│→│leaf│→│leaf│ + │RRR │←│RRR │←│RRR │←│RRR │ + └────┘ └────┘ └────┘ └────┘ + +When it reaches the root level, it is ready to commit the new btree!:: + + ┌─────────┐ + │ root │ + │ PP │ + └─────────┘ + ↙ ↘ + ┌────┐ ┌────┐ + │node│──────→│node│ + │PP │←──────│PP │ + └────┘ └────┘ + ↙ ↘ ↙ ↘ + ┌────┐ ┌────┐ ┌────┐ ┌────┐ + │leaf│→│leaf│→│leaf│→│leaf│ + │RRR │←│RRR │←│RRR │←│RRR │ + └────┘ └────┘ └────┘ └────┘ + +The first step to commit the new btree is to persist the btree blocks to disk +synchronously. +This is a little complicated because a new btree block could have been freed +in the recent past, so the builder must use ``xfs_buf_delwri_queue_here`` to +remove the (stale) buffer from the AIL list before it can write the new blocks +to disk. +Blocks are queued for IO using a delwri list and written in one large batch +with ``xfs_buf_delwri_submit``. + +Once the new blocks have been persisted to disk, control returns to the +individual repair function that called the bulk loader. +The repair function must log the location of the new root in a transaction, +clean up the space reservations that were made for the new btree, and reap the +old metadata blocks: + +1. Commit the location of the new btree root. + +2. For each incore reservation: + + a. Log Extent Freeing Done (EFD) items for all the space that was consumed + by the btree builder. The new EFDs must point to the EFIs attached to + the reservation to prevent log recovery from freeing the new blocks. + + b. For unclaimed portions of incore reservations, create a regular deferred + extent free work item to be free the unused space later in the + transaction chain. + + c. The EFDs and EFIs logged in steps 2a and 2b must not overrun the + reservation of the committing transaction. + If the btree loading code suspects this might be about to happen, it must + call ``xrep_defer_finish`` to clear out the deferred work and obtain a + fresh transaction. + +3. Clear out the deferred work a second time to finish the commit and clean + the repair transaction. + +The transaction rolling in steps 2c and 3 represent a weakness in the repair +algorithm, because a log flush and a crash before the end of the reap step can +result in space leaking. +Online repair functions minimize the chances of this occurring by using very +large transactions, which each can accommodate many thousands of block freeing +instructions. +Repair moves on to reaping the old blocks, which will be presented in a +subsequent :ref:`section` after a few case studies of bulk loading. + +Case Study: Rebuilding the Inode Index +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The high level process to rebuild the inode index btree is: + +1. Walk the reverse mapping records to generate ``struct xfs_inobt_rec`` + records from the inode chunk information and a bitmap of the old inode btree + blocks. + +2. Append the records to an xfarray in inode order. + +3. Use the ``xfs_btree_bload_compute_geometry`` function to compute the number + of blocks needed for the inode btree. + If the free space inode btree is enabled, call it again to estimate the + geometry of the finobt. + +4. Allocate the number of blocks computed in the previous step. + +5. Use ``xfs_btree_bload`` to write the xfarray records to btree blocks and + generate the internal node blocks. + If the free space inode btree is enabled, call it again to load the finobt. + +6. Commit the location of the new btree root block(s) to the AGI. + +7. Reap the old btree blocks using the bitmap created in step 1. + +Details are as follows. + +The inode btree maps inumbers to the ondisk location of the associated +inode records, which means that the inode btrees can be rebuilt from the +reverse mapping information. +Reverse mapping records with an owner of ``XFS_RMAP_OWN_INOBT`` marks the +location of the old inode btree blocks. +Each reverse mapping record with an owner of ``XFS_RMAP_OWN_INODES`` marks the +location of at least one inode cluster buffer. +A cluster is the smallest number of ondisk inodes that can be allocated or +freed in a single transaction; it is never smaller than 1 fs block or 4 inodes. + +For the space represented by each inode cluster, ensure that there are no +records in the free space btrees nor any records in the reference count btree. +If there are, the space metadata inconsistencies are reason enough to abort the +operation. +Otherwise, read each cluster buffer to check that its contents appear to be +ondisk inodes and to decide if the file is allocated +(``xfs_dinode.i_mode != 0``) or free (``xfs_dinode.i_mode == 0``). +Accumulate the results of successive inode cluster buffer reads until there is +enough information to fill a single inode chunk record, which is 64 consecutive +numbers in the inumber keyspace. +If the chunk is sparse, the chunk record may include holes. + +Once the repair function accumulates one chunk's worth of data, it calls +``xfarray_append`` to add the inode btree record to the xfarray. +This xfarray is walked twice during the btree creation step -- once to populate +the inode btree with all inode chunk records, and a second time to populate the +free inode btree with records for chunks that have free non-sparse inodes. +The number of records for the inode btree is the number of xfarray records, +but the record count for the free inode btree has to be computed as inode chunk +records are stored in the xfarray. + +The proposed patchset is the +`AG btree repair +`_ +series. + +Case Study: Rebuilding the Space Reference Counts +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Reverse mapping records are used to rebuild the reference count information. +Reference counts are required for correct operation of copy on write for shared +file data. +Imagine the reverse mapping entries as rectangles representing extents of +physical blocks, and that the rectangles can be laid down to allow them to +overlap each other. +From the diagram below, it is apparent that a reference count record must start +or end wherever the height of the stack changes. +In other words, the record emission stimulus is level-triggered:: + + █ ███ + ██ █████ ████ ███ ██████ + ██ ████ ███████████ ████ █████████ + ████████████████████████████████ ███████████ + ^ ^ ^^ ^^ ^ ^^ ^^^ ^^^^ ^ ^^ ^ ^ ^ + 2 1 23 21 3 43 234 2123 1 01 2 3 0 + +The ondisk reference count btree does not store the refcount == 0 cases because +the free space btree already records which blocks are free. +Extents being used to stage copy-on-write operations should be the only records +with refcount == 1. +Single-owner file blocks aren't recorded in either the free space or the +reference count btrees. + +The high level process to rebuild the reference count btree is: + +1. Walk the reverse mapping records to generate ``struct xfs_refcount_irec`` + records for any space having more than one reverse mapping and add them to + the xfarray. + Any records owned by ``XFS_RMAP_OWN_COW`` are also added to the xfarray + because these are extents allocated to stage a copy on write operation and + are tracked in the refcount btree. + + Use any records owned by ``XFS_RMAP_OWN_REFC`` to create a bitmap of old + refcount btree blocks. + +2. Sort the records in physical extent order, putting the CoW staging extents + at the end of the xfarray. + This matches the sorting order of records in the refcount btree. + +3. Use the ``xfs_btree_bload_compute_geometry`` function to compute the number + of blocks needed for the new tree. + +4. Allocate the number of blocks computed in the previous step. + +5. Use ``xfs_btree_bload`` to write the xfarray records to btree blocks and + generate the internal node blocks. + +6. Commit the location of new btree root block to the AGF. + +7. Reap the old btree blocks using the bitmap created in step 1. + +Details are as follows; the same algorithm is used by ``xfs_repair`` to +generate refcount information from reverse mapping records. + +- Until the reverse mapping btree runs out of records: + + - Retrieve the next record from the btree and put it in a bag. + + - Collect all records with the same starting block from the btree and put + them in the bag. + + - While the bag isn't empty: + + - Among the mappings in the bag, compute the lowest block number where the + reference count changes. + This position will be either the starting block number of the next + unprocessed reverse mapping or the next block after the shortest mapping + in the bag. + + - Remove all mappings from the bag that end at this position. + + - Collect all reverse mappings that start at this position from the btree + and put them in the bag. + + - If the size of the bag changed and is greater than one, create a new + refcount record associating the block number range that we just walked to + the size of the bag. + +The bag-like structure in this case is a type 2 xfarray as discussed in the +:ref:`xfarray access patterns` section. +Reverse mappings are added to the bag using ``xfarray_store_anywhere`` and +removed via ``xfarray_unset``. +Bag members are examined through ``xfarray_iter`` loops. + +The proposed patchset is the +`AG btree repair +`_ +series. + +Case Study: Rebuilding File Fork Mapping Indices +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The high level process to rebuild a data/attr fork mapping btree is: + +1. Walk the reverse mapping records to generate ``struct xfs_bmbt_rec`` + records from the reverse mapping records for that inode and fork. + Append these records to an xfarray. + Compute the bitmap of the old bmap btree blocks from the ``BMBT_BLOCK`` + records. + +2. Use the ``xfs_btree_bload_compute_geometry`` function to compute the number + of blocks needed for the new tree. + +3. Sort the records in file offset order. + +4. If the extent records would fit in the inode fork immediate area, commit the + records to that immediate area and skip to step 8. + +5. Allocate the number of blocks computed in the previous step. + +6. Use ``xfs_btree_bload`` to write the xfarray records to btree blocks and + generate the internal node blocks. + +7. Commit the new btree root block to the inode fork immediate area. + +8. Reap the old btree blocks using the bitmap created in step 1. + +There are some complications here: +First, it's possible to move the fork offset to adjust the sizes of the +immediate areas if the data and attr forks are not both in BMBT format. +Second, if there are sufficiently few fork mappings, it may be possible to use +EXTENTS format instead of BMBT, which may require a conversion. +Third, the incore extent map must be reloaded carefully to avoid disturbing +any delayed allocation extents. + +The proposed patchset is the +`file mapping repair +`_ +series. + +.. _reaping: + +Reaping Old Metadata Blocks +--------------------------- + +Whenever online fsck builds a new data structure to replace one that is +suspect, there is a question of how to find and dispose of the blocks that +belonged to the old structure. +The laziest method of course is not to deal with them at all, but this slowly +leads to service degradations as space leaks out of the filesystem. +Hopefully, someone will schedule a rebuild of the free space information to +plug all those leaks. +Offline repair rebuilds all space metadata after recording the usage of +the files and directories that it decides not to clear, hence it can build new +structures in the discovered free space and avoid the question of reaping. + +As part of a repair, online fsck relies heavily on the reverse mapping records +to find space that is owned by the corresponding rmap owner yet truly free. +Cross referencing rmap records with other rmap records is necessary because +there may be other data structures that also think they own some of those +blocks (e.g. crosslinked trees). +Permitting the block allocator to hand them out again will not push the system +towards consistency. + +For space metadata, the process of finding extents to dispose of generally +follows this format: + +1. Create a bitmap of space used by data structures that must be preserved. + The space reservations used to create the new metadata can be used here if + the same rmap owner code is used to denote all of the objects being rebuilt. + +2. Survey the reverse mapping data to create a bitmap of space owned by the + same ``XFS_RMAP_OWN_*`` number for the metadata that is being preserved. + +3. Use the bitmap disunion operator to subtract (1) from (2). + The remaining set bits represent candidate extents that could be freed. + The process moves on to step 4 below. + +Repairs for file-based metadata such as extended attributes, directories, +symbolic links, quota files and realtime bitmaps are performed by building a +new structure attached to a temporary file and swapping the forks. +Afterward, the mappings in the old file fork are the candidate blocks for +disposal. + +The process for disposing of old extents is as follows: + +4. For each candidate extent, count the number of reverse mapping records for + the first block in that extent that do not have the same rmap owner for the + data structure being repaired. + + - If zero, the block has a single owner and can be freed. + + - If not, the block is part of a crosslinked structure and must not be + freed. + +5. Starting with the next block in the extent, figure out how many more blocks + have the same zero/nonzero other owner status as that first block. + +6. If the region is crosslinked, delete the reverse mapping entry for the + structure being repaired and move on to the next region. + +7. If the region is to be freed, mark any corresponding buffers in the buffer + cache as stale to prevent log writeback. + +8. Free the region and move on. + +However, there is one complication to this procedure. +Transactions are of finite size, so the reaping process must be careful to roll +the transactions to avoid overruns. +Overruns come from two sources: + +a. EFIs logged on behalf of space that is no longer occupied + +b. Log items for buffer invalidations + +This is also a window in which a crash during the reaping process can leak +blocks. +As stated earlier, online repair functions use very large transactions to +minimize the chances of this occurring. + +The proposed patchset is the +`preparation for bulk loading btrees +`_ +series. + +Case Study: Reaping After a Regular Btree Repair +```````````````````````````````````````````````` + +Old reference count and inode btrees are the easiest to reap because they have +rmap records with special owner codes: ``XFS_RMAP_OWN_REFC`` for the refcount +btree, and ``XFS_RMAP_OWN_INOBT`` for the inode and free inode btrees. +Creating a list of extents to reap the old btree blocks is quite simple, +conceptually: + +1. Lock the relevant AGI/AGF header buffers to prevent allocation and frees. + +2. For each reverse mapping record with an rmap owner corresponding to the + metadata structure being rebuilt, set the corresponding range in a bitmap. + +3. Walk the current data structures that have the same rmap owner. + For each block visited, clear that range in the above bitmap. + +4. Each set bit in the bitmap represents a block that could be a block from the + old data structures and hence is a candidate for reaping. + In other words, ``(rmap_records_owned_by & ~blocks_reachable_by_walk)`` + are the blocks that might be freeable. + +If it is possible to maintain the AGF lock throughout the repair (which is the +common case), then step 2 can be performed at the same time as the reverse +mapping record walk that creates the records for the new btree. + +Case Study: Rebuilding the Free Space Indices +````````````````````````````````````````````` + +The high level process to rebuild the free space indices is: + +1. Walk the reverse mapping records to generate ``struct xfs_alloc_rec_incore`` + records from the gaps in the reverse mapping btree. + +2. Append the records to an xfarray. + +3. Use the ``xfs_btree_bload_compute_geometry`` function to compute the number + of blocks needed for each new tree. + +4. Allocate the number of blocks computed in the previous step from the free + space information collected. + +5. Use ``xfs_btree_bload`` to write the xfarray records to btree blocks and + generate the internal node blocks for the free space by length index. + Call it again for the free space by block number index. + +6. Commit the locations of the new btree root blocks to the AGF. + +7. Reap the old btree blocks by looking for space that is not recorded by the + reverse mapping btree, the new free space btrees, or the AGFL. + +Repairing the free space btrees has three key complications over a regular +btree repair: + +First, free space is not explicitly tracked in the reverse mapping records. +Hence, the new free space records must be inferred from gaps in the physical +space component of the keyspace of the reverse mapping btree. + +Second, free space repairs cannot use the common btree reservation code because +new blocks are reserved out of the free space btrees. +This is impossible when repairing the free space btrees themselves. +However, repair holds the AGF buffer lock for the duration of the free space +index reconstruction, so it can use the collected free space information to +supply the blocks for the new free space btrees. +It is not necessary to back each reserved extent with an EFI because the new +free space btrees are constructed in what the ondisk filesystem thinks is +unowned space. +However, if reserving blocks for the new btrees from the collected free space +information changes the number of free space records, repair must re-estimate +the new free space btree geometry with the new record count until the +reservation is sufficient. +As part of committing the new btrees, repair must ensure that reverse mappings +are created for the reserved blocks and that unused reserved blocks are +inserted into the free space btrees. +Deferrred rmap and freeing operations are used to ensure that this transition +is atomic, similar to the other btree repair functions. + +Third, finding the blocks to reap after the repair is not overly +straightforward. +Blocks for the free space btrees and the reverse mapping btrees are supplied by +the AGFL. +Blocks put onto the AGFL have reverse mapping records with the owner +``XFS_RMAP_OWN_AG``. +This ownership is retained when blocks move from the AGFL into the free space +btrees or the reverse mapping btrees. +When repair walks reverse mapping records to synthesize free space records, it +creates a bitmap (``ag_owner_bitmap``) of all the space claimed by +``XFS_RMAP_OWN_AG`` records. +The repair context maintains a second bitmap corresponding to the rmap btree +blocks and the AGFL blocks (``rmap_agfl_bitmap``). +When the walk is complete, the bitmap disunion operation ``(ag_owner_bitmap & +~rmap_agfl_bitmap)`` computes the extents that are used by the old free space +btrees. +These blocks can then be reaped using the methods outlined above. + +The proposed patchset is the +`AG btree repair +`_ +series. + +.. _rmap_reap: + +Case Study: Reaping After Repairing Reverse Mapping Btrees +`````````````````````````````````````````````````````````` + +Old reverse mapping btrees are less difficult to reap after a repair. +As mentioned in the previous section, blocks on the AGFL, the two free space +btree blocks, and the reverse mapping btree blocks all have reverse mapping +records with ``XFS_RMAP_OWN_AG`` as the owner. +The full process of gathering reverse mapping records and building a new btree +are described in the case study of +:ref:`live rebuilds of rmap data `, but a crucial point from that +discussion is that the new rmap btree will not contain any records for the old +rmap btree, nor will the old btree blocks be tracked in the free space btrees. +The list of candidate reaping blocks is computed by setting the bits +corresponding to the gaps in the new rmap btree records, and then clearing the +bits corresponding to extents in the free space btrees and the current AGFL +blocks. +The result ``(new_rmapbt_gaps & ~(agfl | bnobt_records))`` are reaped using the +methods outlined above. + +The rest of the process of rebuildng the reverse mapping btree is discussed +in a separate :ref:`case study`. + +The proposed patchset is the +`AG btree repair +`_ +series. + +Case Study: Rebuilding the AGFL +``````````````````````````````` + +The allocation group free block list (AGFL) is repaired as follows: + +1. Create a bitmap for all the space that the reverse mapping data claims is + owned by ``XFS_RMAP_OWN_AG``. + +2. Subtract the space used by the two free space btrees and the rmap btree. + +3. Subtract any space that the reverse mapping data claims is owned by any + other owner, to avoid re-adding crosslinked blocks to the AGFL. + +4. Once the AGFL is full, reap any blocks leftover. + +5. The next operation to fix the freelist will right-size the list. + +See `fs/xfs/scrub/agheader_repair.c `_ for more details. + +Inode Record Repairs +-------------------- + +Inode records must be handled carefully, because they have both ondisk records +("dinodes") and an in-memory ("cached") representation. +There is a very high potential for cache coherency issues if online fsck is not +careful to access the ondisk metadata *only* when the ondisk metadata is so +badly damaged that the filesystem cannot load the in-memory representation. +When online fsck wants to open a damaged file for scrubbing, it must use +specialized resource acquisition functions that return either the in-memory +representation *or* a lock on whichever object is necessary to prevent any +update to the ondisk location. + +The only repairs that should be made to the ondisk inode buffers are whatever +is necessary to get the in-core structure loaded. +This means fixing whatever is caught by the inode cluster buffer and inode fork +verifiers, and retrying the ``iget`` operation. +If the second ``iget`` fails, the repair has failed. + +Once the in-memory representation is loaded, repair can lock the inode and can +subject it to comprehensive checks, repairs, and optimizations. +Most inode attributes are easy to check and constrain, or are user-controlled +arbitrary bit patterns; these are both easy to fix. +Dealing with the data and attr fork extent counts and the file block counts is +more complicated, because computing the correct value requires traversing the +forks, or if that fails, leaving the fields invalid and waiting for the fork +fsck functions to run. + +The proposed patchset is the +`inode +`_ +repair series. + +Quota Record Repairs +-------------------- + +Similar to inodes, quota records ("dquots") also have both ondisk records and +an in-memory representation, and hence are subject to the same cache coherency +issues. +Somewhat confusingly, both are known as dquots in the XFS codebase. + +The only repairs that should be made to the ondisk quota record buffers are +whatever is necessary to get the in-core structure loaded. +Once the in-memory representation is loaded, the only attributes needing +checking are obviously bad limits and timer values. + +Quota usage counters are checked, repaired, and discussed separately in the +section about :ref:`live quotacheck `. + +The proposed patchset is the +`quota +`_ +repair series. + +.. _fscounters: + +Freezing to Fix Summary Counters +-------------------------------- + +Filesystem summary counters track availability of filesystem resources such +as free blocks, free inodes, and allocated inodes. +This information could be compiled by walking the free space and inode indexes, +but this is a slow process, so XFS maintains a copy in the ondisk superblock +that should reflect the ondisk metadata, at least when the filesystem has been +unmounted cleanly. +For performance reasons, XFS also maintains incore copies of those counters, +which are key to enabling resource reservations for active transactions. +Writer threads reserve the worst-case quantities of resources from the +incore counter and give back whatever they don't use at commit time. +It is therefore only necessary to serialize on the superblock when the +superblock is being committed to disk. + +The lazy superblock counter feature introduced in XFS v5 took this even further +by training log recovery to recompute the summary counters from the AG headers, +which eliminated the need for most transactions even to touch the superblock. +The only time XFS commits the summary counters is at filesystem unmount. +To reduce contention even further, the incore counter is implemented as a +percpu counter, which means that each CPU is allocated a batch of blocks from a +global incore counter and can satisfy small allocations from the local batch. + +The high-performance nature of the summary counters makes it difficult for +online fsck to check them, since there is no way to quiesce a percpu counter +while the system is running. +Although online fsck can read the filesystem metadata to compute the correct +values of the summary counters, there's no way to hold the value of a percpu +counter stable, so it's quite possible that the counter will be out of date by +the time the walk is complete. +Earlier versions of online scrub would return to userspace with an incomplete +scan flag, but this is not a satisfying outcome for a system administrator. +For repairs, the in-memory counters must be stabilized while walking the +filesystem metadata to get an accurate reading and install it in the percpu +counter. + +To satisfy this requirement, online fsck must prevent other programs in the +system from initiating new writes to the filesystem, it must disable background +garbage collection threads, and it must wait for existing writer programs to +exit the kernel. +Once that has been established, scrub can walk the AG free space indexes, the +inode btrees, and the realtime bitmap to compute the correct value of all +four summary counters. +This is very similar to a filesystem freeze, though not all of the pieces are +necessary: + +- The final freeze state is set one higher than ``SB_FREEZE_COMPLETE`` to + prevent other threads from thawing the filesystem, or other scrub threads + from initiating another fscounters freeze. + +- It does not quiesce the log. + +With this code in place, it is now possible to pause the filesystem for just +long enough to check and correct the summary counters. + ++--------------------------------------------------------------------------+ +| **Historical Sidebar**: | ++--------------------------------------------------------------------------+ +| The initial implementation used the actual VFS filesystem freeze | +| mechanism to quiesce filesystem activity. | +| With the filesystem frozen, it is possible to resolve the counter values | +| with exact precision, but there are many problems with calling the VFS | +| methods directly: | +| | +| - Other programs can unfreeze the filesystem without our knowledge. | +| This leads to incorrect scan results and incorrect repairs. | +| | +| - Adding an extra lock to prevent others from thawing the filesystem | +| required the addition of a ``->freeze_super`` function to wrap | +| ``freeze_fs()``. | +| This in turn caused other subtle problems because it turns out that | +| the VFS ``freeze_super`` and ``thaw_super`` functions can drop the | +| last reference to the VFS superblock, and any subsequent access | +| becomes a UAF bug! | +| This can happen if the filesystem is unmounted while the underlying | +| block device has frozen the filesystem. | +| This problem could be solved by grabbing extra references to the | +| superblock, but it felt suboptimal given the other inadequacies of | +| this approach. | +| | +| - The log need not be quiesced to check the summary counters, but a VFS | +| freeze initiates one anyway. | +| This adds unnecessary runtime to live fscounter fsck operations. | +| | +| - Quiescing the log means that XFS flushes the (possibly incorrect) | +| counters to disk as part of cleaning the log. | +| | +| - A bug in the VFS meant that freeze could complete even when | +| sync_filesystem fails to flush the filesystem and returns an error. | +| This bug was fixed in Linux 5.17. | ++--------------------------------------------------------------------------+ + +The proposed patchset is the +`summary counter cleanup +`_ +series. + +Full Filesystem Scans +--------------------- + +Certain types of metadata can only be checked by walking every file in the +entire filesystem to record observations and comparing the observations against +what's recorded on disk. +Like every other type of online repair, repairs are made by writing those +observations to disk in a replacement structure and committing it atomically. +However, it is not practical to shut down the entire filesystem to examine +hundreds of billions of files because the downtime would be excessive. +Therefore, online fsck must build the infrastructure to manage a live scan of +all the files in the filesystem. +There are two questions that need to be solved to perform a live walk: + +- How does scrub manage the scan while it is collecting data? + +- How does the scan keep abreast of changes being made to the system by other + threads? + +.. _iscan: + +Coordinated Inode Scans +``````````````````````` + +In the original Unix filesystems of the 1970s, each directory entry contained +an index number (*inumber*) which was used as an index into on ondisk array +(*itable*) of fixed-size records (*inodes*) describing a file's attributes and +its data block mapping. +This system is described by J. Lions, `"inode (5659)" +`_ in *Lions' Commentary on +UNIX, 6th Edition*, (Dept. of Computer Science, the University of New South +Wales, November 1977), pp. 18-2; and later by D. Ritchie and K. Thompson, +`"Implementation of the File System" +`_, from *The UNIX +Time-Sharing System*, (The Bell System Technical Journal, July 1978), pp. +1913-4. + +XFS retains most of this design, except now inumbers are search keys over all +the space in the data section filesystem. +They form a continuous keyspace that can be expressed as a 64-bit integer, +though the inodes themselves are sparsely distributed within the keyspace. +Scans proceed in a linear fashion across the inumber keyspace, starting from +``0x0`` and ending at ``0xFFFFFFFFFFFFFFFF``. +Naturally, a scan through a keyspace requires a scan cursor object to track the +scan progress. +Because this keyspace is sparse, this cursor contains two parts. +The first part of this scan cursor object tracks the inode that will be +examined next; call this the examination cursor. +Somewhat less obviously, the scan cursor object must also track which parts of +the keyspace have already been visited, which is critical for deciding if a +concurrent filesystem update needs to be incorporated into the scan data. +Call this the visited inode cursor. + +Advancing the scan cursor is a multi-step process encapsulated in +``xchk_iscan_iter``: + +1. Lock the AGI buffer of the AG containing the inode pointed to by the visited + inode cursor. + This guarantee that inodes in this AG cannot be allocated or freed while + advancing the cursor. + +2. Use the per-AG inode btree to look up the next inumber after the one that + was just visited, since it may not be keyspace adjacent. + +3. If there are no more inodes left in this AG: + + a. Move the examination cursor to the point of the inumber keyspace that + corresponds to the start of the next AG. + + b. Adjust the visited inode cursor to indicate that it has "visited" the + last possible inode in the current AG's inode keyspace. + XFS inumbers are segmented, so the cursor needs to be marked as having + visited the entire keyspace up to just before the start of the next AG's + inode keyspace. + + c. Unlock the AGI and return to step 1 if there are unexamined AGs in the + filesystem. + + d. If there are no more AGs to examine, set both cursors to the end of the + inumber keyspace. + The scan is now complete. + +4. Otherwise, there is at least one more inode to scan in this AG: + + a. Move the examination cursor ahead to the next inode marked as allocated + by the inode btree. + + b. Adjust the visited inode cursor to point to the inode just prior to where + the examination cursor is now. + Because the scanner holds the AGI buffer lock, no inodes could have been + created in the part of the inode keyspace that the visited inode cursor + just advanced. + +5. Get the incore inode for the inumber of the examination cursor. + By maintaining the AGI buffer lock until this point, the scanner knows that + it was safe to advance the examination cursor across the entire keyspace, + and that it has stabilized this next inode so that it cannot disappear from + the filesystem until the scan releases the incore inode. + +6. Drop the AGI lock and return the incore inode to the caller. + +Online fsck functions scan all files in the filesystem as follows: + +1. Start a scan by calling ``xchk_iscan_start``. + +2. Advance the scan cursor (``xchk_iscan_iter``) to get the next inode. + If one is provided: + + a. Lock the inode to prevent updates during the scan. + + b. Scan the inode. + + c. While still holding the inode lock, adjust the visited inode cursor + (``xchk_iscan_mark_visited``) to point to this inode. + + d. Unlock and release the inode. + +8. Call ``xchk_iscan_teardown`` to complete the scan. + +There are subtleties with the inode cache that complicate grabbing the incore +inode for the caller. +Obviously, it is an absolute requirement that the inode metadata be consistent +enough to load it into the inode cache. +Second, if the incore inode is stuck in some intermediate state, the scan +coordinator must release the AGI and push the main filesystem to get the inode +back into a loadable state. + +The proposed patches are the +`inode scanner +`_ +series. +The first user of the new functionality is the +`online quotacheck +`_ +series. + +Inode Management +```````````````` + +In regular filesystem code, references to allocated XFS incore inodes are +always obtained (``xfs_iget``) outside of transaction context because the +creation of the incore context for an existing file does not require metadata +updates. +However, it is important to note that references to incore inodes obtained as +part of file creation must be performed in transaction context because the +filesystem must ensure the atomicity of the ondisk inode btree index updates +and the initialization of the actual ondisk inode. + +References to incore inodes are always released (``xfs_irele``) outside of +transaction context because there are a handful of activities that might +require ondisk updates: + +- The VFS may decide to kick off writeback as part of a ``DONTCACHE`` inode + release. + +- Speculative preallocations need to be unreserved. + +- An unlinked file may have lost its last reference, in which case the entire + file must be inactivated, which involves releasing all of its resources in + the ondisk metadata and freeing the inode. + +These activities are collectively called inode inactivation. +Inactivation has two parts -- the VFS part, which initiates writeback on all +dirty file pages, and the XFS part, which cleans up XFS-specific information +and frees the inode if it was unlinked. +If the inode is unlinked (or unconnected after a file handle operation), the +kernel drops the inode into the inactivation machinery immediately. + +During normal operation, resource acquisition for an update follows this order +to avoid deadlocks: + +1. Inode reference (``iget``). + +2. Filesystem freeze protection, if repairing (``mnt_want_write_file``). + +3. Inode ``IOLOCK`` (VFS ``i_rwsem``) lock to control file IO. + +4. Inode ``MMAPLOCK`` (page cache ``invalidate_lock``) lock for operations that + can update page cache mappings. + +5. Log feature enablement. + +6. Transaction log space grant. + +7. Space on the data and realtime devices for the transaction. + +8. Incore dquot references, if a file is being repaired. + Note that they are not locked, merely acquired. + +9. Inode ``ILOCK`` for file metadata updates. + +10. AG header buffer locks / Realtime metadata inode ILOCK. + +11. Realtime metadata buffer locks, if applicable. + +12. Extent mapping btree blocks, if applicable. + +Resources are often released in the reverse order, though this is not required. +However, online fsck differs from regular XFS operations because it may examine +an object that normally is acquired in a later stage of the locking order, and +then decide to cross-reference the object with an object that is acquired +earlier in the order. +The next few sections detail the specific ways in which online fsck takes care +to avoid deadlocks. + +iget and irele During a Scrub +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +An inode scan performed on behalf of a scrub operation runs in transaction +context, and possibly with resources already locked and bound to it. +This isn't much of a problem for ``iget`` since it can operate in the context +of an existing transaction, as long as all of the bound resources are acquired +before the inode reference in the regular filesystem. + +When the VFS ``iput`` function is given a linked inode with no other +references, it normally puts the inode on an LRU list in the hope that it can +save time if another process re-opens the file before the system runs out +of memory and frees it. +Filesystem callers can short-circuit the LRU process by setting a ``DONTCACHE`` +flag on the inode to cause the kernel to try to drop the inode into the +inactivation machinery immediately. + +In the past, inactivation was always done from the process that dropped the +inode, which was a problem for scrub because scrub may already hold a +transaction, and XFS does not support nesting transactions. +On the other hand, if there is no scrub transaction, it is desirable to drop +otherwise unused inodes immediately to avoid polluting caches. +To capture these nuances, the online fsck code has a separate ``xchk_irele`` +function to set or clear the ``DONTCACHE`` flag to get the required release +behavior. + +Proposed patchsets include fixing +`scrub iget usage +`_ and +`dir iget usage +`_. + +.. _ilocking: + +Locking Inodes +^^^^^^^^^^^^^^ + +In regular filesystem code, the VFS and XFS will acquire multiple IOLOCK locks +in a well-known order: parent → child when updating the directory tree, and +in numerical order of the addresses of their ``struct inode`` object otherwise. +For regular files, the MMAPLOCK can be acquired after the IOLOCK to stop page +faults. +If two MMAPLOCKs must be acquired, they are acquired in numerical order of +the addresses of their ``struct address_space`` objects. +Due to the structure of existing filesystem code, IOLOCKs and MMAPLOCKs must be +acquired before transactions are allocated. +If two ILOCKs must be acquired, they are acquired in inumber order. + +Inode lock acquisition must be done carefully during a coordinated inode scan. +Online fsck cannot abide these conventions, because for a directory tree +scanner, the scrub process holds the IOLOCK of the file being scanned and it +needs to take the IOLOCK of the file at the other end of the directory link. +If the directory tree is corrupt because it contains a cycle, ``xfs_scrub`` +cannot use the regular inode locking functions and avoid becoming trapped in an +ABBA deadlock. + +Solving both of these problems is straightforward -- any time online fsck +needs to take a second lock of the same class, it uses trylock to avoid an ABBA +deadlock. +If the trylock fails, scrub drops all inode locks and use trylock loops to +(re)acquire all necessary resources. +Trylock loops enable scrub to check for pending fatal signals, which is how +scrub avoids deadlocking the filesystem or becoming an unresponsive process. +However, trylock loops means that online fsck must be prepared to measure the +resource being scrubbed before and after the lock cycle to detect changes and +react accordingly. + +.. _dirparent: + +Case Study: Finding a Directory Parent +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Consider the directory parent pointer repair code as an example. +Online fsck must verify that the dotdot dirent of a directory points up to a +parent directory, and that the parent directory contains exactly one dirent +pointing down to the child directory. +Fully validating this relationship (and repairing it if possible) requires a +walk of every directory on the filesystem while holding the child locked, and +while updates to the directory tree are being made. +The coordinated inode scan provides a way to walk the filesystem without the +possibility of missing an inode. +The child directory is kept locked to prevent updates to the dotdot dirent, but +if the scanner fails to lock a parent, it can drop and relock both the child +and the prospective parent. +If the dotdot entry changes while the directory is unlocked, then a move or +rename operation must have changed the child's parentage, and the scan can +exit early. + +The proposed patchset is the +`directory repair +`_ +series. + +.. _fshooks: + +Filesystem Hooks +````````````````` + +The second piece of support that online fsck functions need during a full +filesystem scan is the ability to stay informed about updates being made by +other threads in the filesystem, since comparisons against the past are useless +in a dynamic environment. +Two pieces of Linux kernel infrastructure enable online fsck to monitor regular +filesystem operations: filesystem hooks and :ref:`static keys`. + +Filesystem hooks convey information about an ongoing filesystem operation to +a downstream consumer. +In this case, the downstream consumer is always an online fsck function. +Because multiple fsck functions can run in parallel, online fsck uses the Linux +notifier call chain facility to dispatch updates to any number of interested +fsck processes. +Call chains are a dynamic list, which means that they can be configured at +run time. +Because these hooks are private to the XFS module, the information passed along +contains exactly what the checking function needs to update its observations. + +The current implementation of XFS hooks uses SRCU notifier chains to reduce the +impact to highly threaded workloads. +Regular blocking notifier chains use a rwsem and seem to have a much lower +overhead for single-threaded applications. +However, it may turn out that the combination of blocking chains and static +keys are a more performant combination; more study is needed here. + +The following pieces are necessary to hook a certain point in the filesystem: + +- A ``struct xfs_hooks`` object must be embedded in a convenient place such as + a well-known incore filesystem object. + +- Each hook must define an action code and a structure containing more context + about the action. + +- Hook providers should provide appropriate wrapper functions and structs + around the ``xfs_hooks`` and ``xfs_hook`` objects to take advantage of type + checking to ensure correct usage. + +- A callsite in the regular filesystem code must be chosen to call + ``xfs_hooks_call`` with the action code and data structure. + This place should be adjacent to (and not earlier than) the place where + the filesystem update is committed to the transaction. + In general, when the filesystem calls a hook chain, it should be able to + handle sleeping and should not be vulnerable to memory reclaim or locking + recursion. + However, the exact requirements are very dependent on the context of the hook + caller and the callee. + +- The online fsck function should define a structure to hold scan data, a lock + to coordinate access to the scan data, and a ``struct xfs_hook`` object. + The scanner function and the regular filesystem code must acquire resources + in the same order; see the next section for details. + +- The online fsck code must contain a C function to catch the hook action code + and data structure. + If the object being updated has already been visited by the scan, then the + hook information must be applied to the scan data. + +- Prior to unlocking inodes to start the scan, online fsck must call + ``xfs_hooks_setup`` to initialize the ``struct xfs_hook``, and + ``xfs_hooks_add`` to enable the hook. + +- Online fsck must call ``xfs_hooks_del`` to disable the hook once the scan is + complete. + +The number of hooks should be kept to a minimum to reduce complexity. +Static keys are used to reduce the overhead of filesystem hooks to nearly +zero when online fsck is not running. + +.. _liveupdate: + +Live Updates During a Scan +`````````````````````````` + +The code paths of the online fsck scanning code and the :ref:`hooked` +filesystem code look like this:: + + other program + ↓ + inode lock ←────────────────────┐ + ↓ │ + AG header lock │ + ↓ │ + filesystem function │ + ↓ │ + notifier call chain │ same + ↓ ├─── inode + scrub hook function │ lock + ↓ │ + scan data mutex ←──┐ same │ + ↓ ├─── scan │ + update scan data │ lock │ + ↑ │ │ + scan data mutex ←──┘ │ + ↑ │ + inode lock ←────────────────────┘ + ↑ + scrub function + ↑ + inode scanner + ↑ + xfs_scrub + +These rules must be followed to ensure correct interactions between the +checking code and the code making an update to the filesystem: + +- Prior to invoking the notifier call chain, the filesystem function being + hooked must acquire the same lock that the scrub scanning function acquires + to scan the inode. + +- The scanning function and the scrub hook function must coordinate access to + the scan data by acquiring a lock on the scan data. + +- Scrub hook function must not add the live update information to the scan + observations unless the inode being updated has already been scanned. + The scan coordinator has a helper predicate (``xchk_iscan_want_live_update``) + for this. + +- Scrub hook functions must not change the caller's state, including the + transaction that it is running. + They must not acquire any resources that might conflict with the filesystem + function being hooked. + +- The hook function can abort the inode scan to avoid breaking the other rules. + +The inode scan APIs are pretty simple: + +- ``xchk_iscan_start`` starts a scan + +- ``xchk_iscan_iter`` grabs a reference to the next inode in the scan or + returns zero if there is nothing left to scan + +- ``xchk_iscan_want_live_update`` to decide if an inode has already been + visited in the scan. + This is critical for hook functions to decide if they need to update the + in-memory scan information. + +- ``xchk_iscan_mark_visited`` to mark an inode as having been visited in the + scan + +- ``xchk_iscan_teardown`` to finish the scan + +This functionality is also a part of the +`inode scanner +`_ +series. + +.. _quotacheck: + +Case Study: Quota Counter Checking +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +It is useful to compare the mount time quotacheck code to the online repair +quotacheck code. +Mount time quotacheck does not have to contend with concurrent operations, so +it does the following: + +1. Make sure the ondisk dquots are in good enough shape that all the incore + dquots will actually load, and zero the resource usage counters in the + ondisk buffer. + +2. Walk every inode in the filesystem. + Add each file's resource usage to the incore dquot. + +3. Walk each incore dquot. + If the incore dquot is not being flushed, add the ondisk buffer backing the + incore dquot to a delayed write (delwri) list. + +4. Write the buffer list to disk. + +Like most online fsck functions, online quotacheck can't write to regular +filesystem objects until the newly collected metadata reflect all filesystem +state. +Therefore, online quotacheck records file resource usage to a shadow dquot +index implemented with a sparse ``xfarray``, and only writes to the real dquots +once the scan is complete. +Handling transactional updates is tricky because quota resource usage updates +are handled in phases to minimize contention on dquots: + +1. The inodes involved are joined and locked to a transaction. + +2. For each dquot attached to the file: + + a. The dquot is locked. + + b. A quota reservation is added to the dquot's resource usage. + The reservation is recorded in the transaction. + + c. The dquot is unlocked. + +3. Changes in actual quota usage are tracked in the transaction. + +4. At transaction commit time, each dquot is examined again: + + a. The dquot is locked again. + + b. Quota usage changes are logged and unused reservation is given back to + the dquot. + + c. The dquot is unlocked. + +For online quotacheck, hooks are placed in steps 2 and 4. +The step 2 hook creates a shadow version of the transaction dquot context +(``dqtrx``) that operates in a similar manner to the regular code. +The step 4 hook commits the shadow ``dqtrx`` changes to the shadow dquots. +Notice that both hooks are called with the inode locked, which is how the +live update coordinates with the inode scanner. + +The quotacheck scan looks like this: + +1. Set up a coordinated inode scan. + +2. For each inode returned by the inode scan iterator: + + a. Grab and lock the inode. + + b. Determine that inode's resource usage (data blocks, inode counts, + realtime blocks) and add that to the shadow dquots for the user, group, + and project ids associated with the inode. + + c. Unlock and release the inode. + +3. For each dquot in the system: + + a. Grab and lock the dquot. + + b. Check the dquot against the shadow dquots created by the scan and updated + by the live hooks. + +Live updates are key to being able to walk every quota record without +needing to hold any locks for a long duration. +If repairs are desired, the real and shadow dquots are locked and their +resource counts are set to the values in the shadow dquot. + +The proposed patchset is the +`online quotacheck +`_ +series. + +.. _nlinks: + +Case Study: File Link Count Checking +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +File link count checking also uses live update hooks. +The coordinated inode scanner is used to visit all directories on the +filesystem, and per-file link count records are stored in a sparse ``xfarray`` +indexed by inumber. +During the scanning phase, each entry in a directory generates observation +data as follows: + +1. If the entry is a dotdot (``'..'``) entry of the root directory, the + directory's parent link count is bumped because the root directory's dotdot + entry is self referential. + +2. If the entry is a dotdot entry of a subdirectory, the parent's backref + count is bumped. + +3. If the entry is neither a dot nor a dotdot entry, the target file's parent + count is bumped. + +4. If the target is a subdirectory, the parent's child link count is bumped. + +A crucial point to understand about how the link count inode scanner interacts +with the live update hooks is that the scan cursor tracks which *parent* +directories have been scanned. +In other words, the live updates ignore any update about ``A → B`` when A has +not been scanned, even if B has been scanned. +Furthermore, a subdirectory A with a dotdot entry pointing back to B is +accounted as a backref counter in the shadow data for A, since child dotdot +entries affect the parent's link count. +Live update hooks are carefully placed in all parts of the filesystem that +create, change, or remove directory entries, since those operations involve +bumplink and droplink. + +For any file, the correct link count is the number of parents plus the number +of child subdirectories. +Non-directories never have children of any kind. +The backref information is used to detect inconsistencies in the number of +links pointing to child subdirectories and the number of dotdot entries +pointing back. + +After the scan completes, the link count of each file can be checked by locking +both the inode and the shadow data, and comparing the link counts. +A second coordinated inode scan cursor is used for comparisons. +Live updates are key to being able to walk every inode without needing to hold +any locks between inodes. +If repairs are desired, the inode's link count is set to the value in the +shadow information. +If no parents are found, the file must be :ref:`reparented ` to the +orphanage to prevent the file from being lost forever. + +The proposed patchset is the +`file link count repair +`_ +series. + +.. _rmap_repair: + +Case Study: Rebuilding Reverse Mapping Records +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Most repair functions follow the same pattern: lock filesystem resources, +walk the surviving ondisk metadata looking for replacement metadata records, +and use an :ref:`in-memory array ` to store the gathered observations. +The primary advantage of this approach is the simplicity and modularity of the +repair code -- code and data are entirely contained within the scrub module, +do not require hooks in the main filesystem, and are usually the most efficient +in memory use. +A secondary advantage of this repair approach is atomicity -- once the kernel +decides a structure is corrupt, no other threads can access the metadata until +the kernel finishes repairing and revalidating the metadata. + +For repairs going on within a shard of the filesystem, these advantages +outweigh the delays inherent in locking the shard while repairing parts of the +shard. +Unfortunately, repairs to the reverse mapping btree cannot use the "standard" +btree repair strategy because it must scan every space mapping of every fork of +every file in the filesystem, and the filesystem cannot stop. +Therefore, rmap repair foregoes atomicity between scrub and repair. +It combines a :ref:`coordinated inode scanner `, :ref:`live update hooks +`, and an :ref:`in-memory rmap btree ` to complete the +scan for reverse mapping records. + +1. Set up an xfbtree to stage rmap records. + +2. While holding the locks on the AGI and AGF buffers acquired during the + scrub, generate reverse mappings for all AG metadata: inodes, btrees, CoW + staging extents, and the internal log. + +3. Set up an inode scanner. + +4. Hook into rmap updates for the AG being repaired so that the live scan data + can receive updates to the rmap btree from the rest of the filesystem during + the file scan. + +5. For each space mapping found in either fork of each file scanned, + decide if the mapping matches the AG of interest. + If so: + + a. Create a btree cursor for the in-memory btree. + + b. Use the rmap code to add the record to the in-memory btree. + + c. Use the :ref:`special commit function ` to write the + xfbtree changes to the xfile. + +6. For each live update received via the hook, decide if the owner has already + been scanned. + If so, apply the live update into the scan data: + + a. Create a btree cursor for the in-memory btree. + + b. Replay the operation into the in-memory btree. + + c. Use the :ref:`special commit function ` to write the + xfbtree changes to the xfile. + This is performed with an empty transaction to avoid changing the + caller's state. + +7. When the inode scan finishes, create a new scrub transaction and relock the + two AG headers. + +8. Compute the new btree geometry using the number of rmap records in the + shadow btree, like all other btree rebuilding functions. + +9. Allocate the number of blocks computed in the previous step. + +10. Perform the usual btree bulk loading and commit to install the new rmap + btree. + +11. Reap the old rmap btree blocks as discussed in the case study about how + to :ref:`reap after rmap btree repair `. + +12. Free the xfbtree now that it not needed. + +The proposed patchset is the +`rmap repair +`_ +series. + +Staging Repairs with Temporary Files on Disk +-------------------------------------------- + +XFS stores a substantial amount of metadata in file forks: directories, +extended attributes, symbolic link targets, free space bitmaps and summary +information for the realtime volume, and quota records. +File forks map 64-bit logical file fork space extents to physical storage space +extents, similar to how a memory management unit maps 64-bit virtual addresses +to physical memory addresses. +Therefore, file-based tree structures (such as directories and extended +attributes) use blocks mapped in the file fork offset address space that point +to other blocks mapped within that same address space, and file-based linear +structures (such as bitmaps and quota records) compute array element offsets in +the file fork offset address space. + +Because file forks can consume as much space as the entire filesystem, repairs +cannot be staged in memory, even when a paging scheme is available. +Therefore, online repair of file-based metadata createas a temporary file in +the XFS filesystem, writes a new structure at the correct offsets into the +temporary file, and atomically swaps the fork mappings (and hence the fork +contents) to commit the repair. +Once the repair is complete, the old fork can be reaped as necessary; if the +system goes down during the reap, the iunlink code will delete the blocks +during log recovery. + +**Note**: All space usage and inode indices in the filesystem *must* be +consistent to use a temporary file safely! +This dependency is the reason why online repair can only use pageable kernel +memory to stage ondisk space usage information. + +Swapping metadata extents with a temporary file requires the owner field of the +block headers to match the file being repaired and not the temporary file. The +directory, extended attribute, and symbolic link functions were all modified to +allow callers to specify owner numbers explicitly. + +There is a downside to the reaping process -- if the system crashes during the +reap phase and the fork extents are crosslinked, the iunlink processing will +fail because freeing space will find the extra reverse mappings and abort. + +Temporary files created for repair are similar to ``O_TMPFILE`` files created +by userspace. +They are not linked into a directory and the entire file will be reaped when +the last reference to the file is lost. +The key differences are that these files must have no access permission outside +the kernel at all, they must be specially marked to prevent them from being +opened by handle, and they must never be linked into the directory tree. + ++--------------------------------------------------------------------------+ +| **Historical Sidebar**: | ++--------------------------------------------------------------------------+ +| In the initial iteration of file metadata repair, the damaged metadata | +| blocks would be scanned for salvageable data; the extents in the file | +| fork would be reaped; and then a new structure would be built in its | +| place. | +| This strategy did not survive the introduction of the atomic repair | +| requirement expressed earlier in this document. | +| | +| The second iteration explored building a second structure at a high | +| offset in the fork from the salvage data, reaping the old extents, and | +| using a ``COLLAPSE_RANGE`` operation to slide the new extents into | +| place. | +| | +| This had many drawbacks: | +| | +| - Array structures are linearly addressed, and the regular filesystem | +| codebase does not have the concept of a linear offset that could be | +| applied to the record offset computation to build an alternate copy. | +| | +| - Extended attributes are allowed to use the entire attr fork offset | +| address space. | +| | +| - Even if repair could build an alternate copy of a data structure in a | +| different part of the fork address space, the atomic repair commit | +| requirement means that online repair would have to be able to perform | +| a log assisted ``COLLAPSE_RANGE`` operation to ensure that the old | +| structure was completely replaced. | +| | +| - A crash after construction of the secondary tree but before the range | +| collapse would leave unreachable blocks in the file fork. | +| This would likely confuse things further. | +| | +| - Reaping blocks after a repair is not a simple operation, and | +| initiating a reap operation from a restarted range collapse operation | +| during log recovery is daunting. | +| | +| - Directory entry blocks and quota records record the file fork offset | +| in the header area of each block. | +| An atomic range collapse operation would have to rewrite this part of | +| each block header. | +| Rewriting a single field in block headers is not a huge problem, but | +| it's something to be aware of. | +| | +| - Each block in a directory or extended attributes btree index contains | +| sibling and child block pointers. | +| Were the atomic commit to use a range collapse operation, each block | +| would have to be rewritten very carefully to preserve the graph | +| structure. | +| Doing this as part of a range collapse means rewriting a large number | +| of blocks repeatedly, which is not conducive to quick repairs. | +| | +| This lead to the introduction of temporary file staging. | ++--------------------------------------------------------------------------+ + +Using a Temporary File +`````````````````````` + +Online repair code should use the ``xrep_tempfile_create`` function to create a +temporary file inside the filesystem. +This allocates an inode, marks the in-core inode private, and attaches it to +the scrub context. +These files are hidden from userspace, may not be added to the directory tree, +and must be kept private. + +Temporary files only use two inode locks: the IOLOCK and the ILOCK. +The MMAPLOCK is not needed here, because there must not be page faults from +userspace for data fork blocks. +The usage patterns of these two locks are the same as for any other XFS file -- +access to file data are controlled via the IOLOCK, and access to file metadata +are controlled via the ILOCK. +Locking helpers are provided so that the temporary file and its lock state can +be cleaned up by the scrub context. +To comply with the nested locking strategy laid out in the :ref:`inode +locking` section, it is recommended that scrub functions use the +xrep_tempfile_ilock*_nowait lock helpers. + +Data can be written to a temporary file by two means: + +1. ``xrep_tempfile_copyin`` can be used to set the contents of a regular + temporary file from an xfile. + +2. The regular directory, symbolic link, and extended attribute functions can + be used to write to the temporary file. + +Once a good copy of a data file has been constructed in a temporary file, it +must be conveyed to the file being repaired, which is the topic of the next +section. + +The proposed patches are in the +`repair temporary files +`_ +series. + +Atomic Extent Swapping +---------------------- + +Once repair builds a temporary file with a new data structure written into +it, it must commit the new changes into the existing file. +It is not possible to swap the inumbers of two files, so instead the new +metadata must replace the old. +This suggests the need for the ability to swap extents, but the existing extent +swapping code used by the file defragmenting tool ``xfs_fsr`` is not sufficient +for online repair because: + +a. When the reverse-mapping btree is enabled, the swap code must keep the + reverse mapping information up to date with every exchange of mappings. + Therefore, it can only exchange one mapping per transaction, and each + transaction is independent. + +b. Reverse-mapping is critical for the operation of online fsck, so the old + defragmentation code (which swapped entire extent forks in a single + operation) is not useful here. + +c. Defragmentation is assumed to occur between two files with identical + contents. + For this use case, an incomplete exchange will not result in a user-visible + change in file contents, even if the operation is interrupted. + +d. Online repair needs to swap the contents of two files that are by definition + *not* identical. + For directory and xattr repairs, the user-visible contents might be the + same, but the contents of individual blocks may be very different. + +e. Old blocks in the file may be cross-linked with another structure and must + not reappear if the system goes down mid-repair. + +These problems are overcome by creating a new deferred operation and a new type +of log intent item to track the progress of an operation to exchange two file +ranges. +The new deferred operation type chains together the same transactions used by +the reverse-mapping extent swap code. +The new log item records the progress of the exchange to ensure that once an +exchange begins, it will always run to completion, even there are +interruptions. +The new ``XFS_SB_FEAT_INCOMPAT_LOG_ATOMIC_SWAP`` log-incompatible feature flag +in the superblock protects these new log item records from being replayed on +old kernels. + +The proposed patchset is the +`atomic extent swap +`_ +series. + ++--------------------------------------------------------------------------+ +| **Sidebar: Using Log-Incompatible Feature Flags** | ++--------------------------------------------------------------------------+ +| Starting with XFS v5, the superblock contains a | +| ``sb_features_log_incompat`` field to indicate that the log contains | +| records that might not readable by all kernels that could mount this | +| filesystem. | +| In short, log incompat features protect the log contents against kernels | +| that will not understand the contents. | +| Unlike the other superblock feature bits, log incompat bits are | +| ephemeral because an empty (clean) log does not need protection. | +| The log cleans itself after its contents have been committed into the | +| filesystem, either as part of an unmount or because the system is | +| otherwise idle. | +| Because upper level code can be working on a transaction at the same | +| time that the log cleans itself, it is necessary for upper level code to | +| communicate to the log when it is going to use a log incompatible | +| feature. | +| | +| The log coordinates access to incompatible features through the use of | +| one ``struct rw_semaphore`` for each feature. | +| The log cleaning code tries to take this rwsem in exclusive mode to | +| clear the bit; if the lock attempt fails, the feature bit remains set. | +| Filesystem code signals its intention to use a log incompat feature in a | +| transaction by calling ``xlog_use_incompat_feat``, which takes the rwsem | +| in shared mode. | +| The code supporting a log incompat feature should create wrapper | +| functions to obtain the log feature and call | +| ``xfs_add_incompat_log_feature`` to set the feature bits in the primary | +| superblock. | +| The superblock update is performed transactionally, so the wrapper to | +| obtain log assistance must be called just prior to the creation of the | +| transaction that uses the functionality. | +| For a file operation, this step must happen after taking the IOLOCK | +| and the MMAPLOCK, but before allocating the transaction. | +| When the transaction is complete, the ``xlog_drop_incompat_feat`` | +| function is called to release the feature. | +| The feature bit will not be cleared from the superblock until the log | +| becomes clean. | +| | +| Log-assisted extended attribute updates and atomic extent swaps both use | +| log incompat features and provide convenience wrappers around the | +| functionality. | ++--------------------------------------------------------------------------+ + +Mechanics of an Atomic Extent Swap +`````````````````````````````````` + +Swapping entire file forks is a complex task. +The goal is to exchange all file fork mappings between two file fork offset +ranges. +There are likely to be many extent mappings in each fork, and the edges of +the mappings aren't necessarily aligned. +Furthermore, there may be other updates that need to happen after the swap, +such as exchanging file sizes, inode flags, or conversion of fork data to local +format. +This is roughly the format of the new deferred extent swap work item: + +.. code-block:: c + + struct xfs_swapext_intent { + /* Inodes participating in the operation. */ + struct xfs_inode *sxi_ip1; + struct xfs_inode *sxi_ip2; + + /* File offset range information. */ + xfs_fileoff_t sxi_startoff1; + xfs_fileoff_t sxi_startoff2; + xfs_filblks_t sxi_blockcount; + + /* Set these file sizes after the operation, unless negative. */ + xfs_fsize_t sxi_isize1; + xfs_fsize_t sxi_isize2; + + /* XFS_SWAP_EXT_* log operation flags */ + uint64_t sxi_flags; + }; + +The new log intent item contains enough information to track two logical fork +offset ranges: ``(inode1, startoff1, blockcount)`` and ``(inode2, startoff2, +blockcount)``. +Each step of a swap operation exchanges the largest file range mapping possible +from one file to the other. +After each step in the swap operation, the two startoff fields are incremented +and the blockcount field is decremented to reflect the progress made. +The flags field captures behavioral parameters such as swapping the attr fork +instead of the data fork and other work to be done after the extent swap. +The two isize fields are used to swap the file size at the end of the operation +if the file data fork is the target of the swap operation. + +When the extent swap is initiated, the sequence of operations is as follows: + +1. Create a deferred work item for the extent swap. + At the start, it should contain the entirety of the file ranges to be + swapped. + +2. Call ``xfs_defer_finish`` to process the exchange. + This is encapsulated in ``xrep_tempswap_contents`` for scrub operations. + This will log an extent swap intent item to the transaction for the deferred + extent swap work item. + +3. Until ``sxi_blockcount`` of the deferred extent swap work item is zero, + + a. Read the block maps of both file ranges starting at ``sxi_startoff1`` and + ``sxi_startoff2``, respectively, and compute the longest extent that can + be swapped in a single step. + This is the minimum of the two ``br_blockcount`` s in the mappings. + Keep advancing through the file forks until at least one of the mappings + contains written blocks. + Mutual holes, unwritten extents, and extent mappings to the same physical + space are not exchanged. + + For the next few steps, this document will refer to the mapping that came + from file 1 as "map1", and the mapping that came from file 2 as "map2". + + b. Create a deferred block mapping update to unmap map1 from file 1. + + c. Create a deferred block mapping update to unmap map2 from file 2. + + d. Create a deferred block mapping update to map map1 into file 2. + + e. Create a deferred block mapping update to map map2 into file 1. + + f. Log the block, quota, and extent count updates for both files. + + g. Extend the ondisk size of either file if necessary. + + h. Log an extent swap done log item for the extent swap intent log item + that was read at the start of step 3. + + i. Compute the amount of file range that has just been covered. + This quantity is ``(map1.br_startoff + map1.br_blockcount - + sxi_startoff1)``, because step 3a could have skipped holes. + + j. Increase the starting offsets of ``sxi_startoff1`` and ``sxi_startoff2`` + by the number of blocks computed in the previous step, and decrease + ``sxi_blockcount`` by the same quantity. + This advances the cursor. + + k. Log a new extent swap intent log item reflecting the advanced state of + the work item. + + l. Return the proper error code (EAGAIN) to the deferred operation manager + to inform it that there is more work to be done. + The operation manager completes the deferred work in steps 3b-3e before + moving back to the start of step 3. + +4. Perform any post-processing. + This will be discussed in more detail in subsequent sections. + +If the filesystem goes down in the middle of an operation, log recovery will +find the most recent unfinished extent swap log intent item and restart from +there. +This is how extent swapping guarantees that an outside observer will either see +the old broken structure or the new one, and never a mismash of both. + +Preparation for Extent Swapping +``````````````````````````````` + +There are a few things that need to be taken care of before initiating an +atomic extent swap operation. +First, regular files require the page cache to be flushed to disk before the +operation begins, and directio writes to be quiesced. +Like any filesystem operation, extent swapping must determine the maximum +amount of disk space and quota that can be consumed on behalf of both files in +the operation, and reserve that quantity of resources to avoid an unrecoverable +out of space failure once it starts dirtying metadata. +The preparation step scans the ranges of both files to estimate: + +- Data device blocks needed to handle the repeated updates to the fork + mappings. +- Change in data and realtime block counts for both files. +- Increase in quota usage for both files, if the two files do not share the + same set of quota ids. +- The number of extent mappings that will be added to each file. +- Whether or not there are partially written realtime extents. + User programs must never be able to access a realtime file extent that maps + to different extents on the realtime volume, which could happen if the + operation fails to run to completion. + +The need for precise estimation increases the run time of the swap operation, +but it is very important to maintain correct accounting. +The filesystem must not run completely out of free space, nor can the extent +swap ever add more extent mappings to a fork than it can support. +Regular users are required to abide the quota limits, though metadata repairs +may exceed quota to resolve inconsistent metadata elsewhere. + +Special Features for Swapping Metadata File Extents +``````````````````````````````````````````````````` + +Extended attributes, symbolic links, and directories can set the fork format to +"local" and treat the fork as a literal area for data storage. +Metadata repairs must take extra steps to support these cases: + +- If both forks are in local format and the fork areas are large enough, the + swap is performed by copying the incore fork contents, logging both forks, + and committing. + The atomic extent swap mechanism is not necessary, since this can be done + with a single transaction. + +- If both forks map blocks, then the regular atomic extent swap is used. + +- Otherwise, only one fork is in local format. + The contents of the local format fork are converted to a block to perform the + swap. + The conversion to block format must be done in the same transaction that + logs the initial extent swap intent log item. + The regular atomic extent swap is used to exchange the mappings. + Special flags are set on the swap operation so that the transaction can be + rolled one more time to convert the second file's fork back to local format + so that the second file will be ready to go as soon as the ILOCK is dropped. + +Extended attributes and directories stamp the owning inode into every block, +but the buffer verifiers do not actually check the inode number! +Although there is no verification, it is still important to maintain +referential integrity, so prior to performing the extent swap, online repair +builds every block in the new data structure with the owner field of the file +being repaired. + +After a successful swap operation, the repair operation must reap the old fork +blocks by processing each fork mapping through the standard :ref:`file extent +reaping ` mechanism that is done post-repair. +If the filesystem should go down during the reap part of the repair, the +iunlink processing at the end of recovery will free both the temporary file and +whatever blocks were not reaped. +However, this iunlink processing omits the cross-link detection of online +repair, and is not completely foolproof. + +Swapping Temporary File Extents +``````````````````````````````` + +To repair a metadata file, online repair proceeds as follows: + +1. Create a temporary repair file. + +2. Use the staging data to write out new contents into the temporary repair + file. + The same fork must be written to as is being repaired. + +3. Commit the scrub transaction, since the swap estimation step must be + completed before transaction reservations are made. + +4. Call ``xrep_tempswap_trans_alloc`` to allocate a new scrub transaction with + the appropriate resource reservations, locks, and fill out a ``struct + xfs_swapext_req`` with the details of the swap operation. + +5. Call ``xrep_tempswap_contents`` to swap the contents. + +6. Commit the transaction to complete the repair. + +.. _rtsummary: + +Case Study: Repairing the Realtime Summary File +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In the "realtime" section of an XFS filesystem, free space is tracked via a +bitmap, similar to Unix FFS. +Each bit in the bitmap represents one realtime extent, which is a multiple of +the filesystem block size between 4KiB and 1GiB in size. +The realtime summary file indexes the number of free extents of a given size to +the offset of the block within the realtime free space bitmap where those free +extents begin. +In other words, the summary file helps the allocator find free extents by +length, similar to what the free space by count (cntbt) btree does for the data +section. + +The summary file itself is a flat file (with no block headers or checksums!) +partitioned into ``log2(total rt extents)`` sections containing enough 32-bit +counters to match the number of blocks in the rt bitmap. +Each counter records the number of free extents that start in that bitmap block +and can satisfy a power-of-two allocation request. + +To check the summary file against the bitmap: + +1. Take the ILOCK of both the realtime bitmap and summary files. + +2. For each free space extent recorded in the bitmap: + + a. Compute the position in the summary file that contains a counter that + represents this free extent. + + b. Read the counter from the xfile. + + c. Increment it, and write it back to the xfile. + +3. Compare the contents of the xfile against the ondisk file. + +To repair the summary file, write the xfile contents into the temporary file +and use atomic extent swap to commit the new contents. +The temporary file is then reaped. + +The proposed patchset is the +`realtime summary repair +`_ +series. + +Case Study: Salvaging Extended Attributes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In XFS, extended attributes are implemented as a namespaced name-value store. +Values are limited in size to 64KiB, but there is no limit in the number of +names. +The attribute fork is unpartitioned, which means that the root of the attribute +structure is always in logical block zero, but attribute leaf blocks, dabtree +index blocks, and remote value blocks are intermixed. +Attribute leaf blocks contain variable-sized records that associate +user-provided names with the user-provided values. +Values larger than a block are allocated separate extents and written there. +If the leaf information expands beyond a single block, a directory/attribute +btree (``dabtree``) is created to map hashes of attribute names to entries +for fast lookup. + +Salvaging extended attributes is done as follows: + +1. Walk the attr fork mappings of the file being repaired to find the attribute + leaf blocks. + When one is found, + + a. Walk the attr leaf block to find candidate keys. + When one is found, + + 1. Check the name for problems, and ignore the name if there are. + + 2. Retrieve the value. + If that succeeds, add the name and value to the staging xfarray and + xfblob. + +2. If the memory usage of the xfarray and xfblob exceed a certain amount of + memory or there are no more attr fork blocks to examine, unlock the file and + add the staged extended attributes to the temporary file. + +3. Use atomic extent swapping to exchange the new and old extended attribute + structures. + The old attribute blocks are now attached to the temporary file. + +4. Reap the temporary file. + +The proposed patchset is the +`extended attribute repair +`_ +series. + +Fixing Directories +------------------ + +Fixing directories is difficult with currently available filesystem features, +since directory entries are not redundant. +The offline repair tool scans all inodes to find files with nonzero link count, +and then it scans all directories to establish parentage of those linked files. +Damaged files and directories are zapped, and files with no parent are +moved to the ``/lost+found`` directory. +It does not try to salvage anything. + +The best that online repair can do at this time is to read directory data +blocks and salvage any dirents that look plausible, correct link counts, and +move orphans back into the directory tree. +The salvage process is discussed in the case study at the end of this section. +The :ref:`file link count fsck ` code takes care of fixing link counts +and moving orphans to the ``/lost+found`` directory. + +Case Study: Salvaging Directories +````````````````````````````````` + +Unlike extended attributes, directory blocks are all the same size, so +salvaging directories is straightforward: + +1. Find the parent of the directory. + If the dotdot entry is not unreadable, try to confirm that the alleged + parent has a child entry pointing back to the directory being repaired. + Otherwise, walk the filesystem to find it. + +2. Walk the first partition of data fork of the directory to find the directory + entry data blocks. + When one is found, + + a. Walk the directory data block to find candidate entries. + When an entry is found: + + i. Check the name for problems, and ignore the name if there are. + + ii. Retrieve the inumber and grab the inode. + If that succeeds, add the name, inode number, and file type to the + staging xfarray and xblob. + +3. If the memory usage of the xfarray and xfblob exceed a certain amount of + memory or there are no more directory data blocks to examine, unlock the + directory and add the staged dirents into the temporary directory. + Truncate the staging files. + +4. Use atomic extent swapping to exchange the new and old directory structures. + The old directory blocks are now attached to the temporary file. + +5. Reap the temporary file. + +**Future Work Question**: Should repair revalidate the dentry cache when +rebuilding a directory? + +*Answer*: Yes, it should. + +In theory it is necessary to scan all dentry cache entries for a directory to +ensure that one of the following apply: + +1. The cached dentry reflects an ondisk dirent in the new directory. + +2. The cached dentry no longer has a corresponding ondisk dirent in the new + directory and the dentry can be purged from the cache. + +3. The cached dentry no longer has an ondisk dirent but the dentry cannot be + purged. + This is the problem case. + +Unfortunately, the current dentry cache design doesn't provide a means to walk +every child dentry of a specific directory, which makes this a hard problem. +There is no known solution. + +The proposed patchset is the +`directory repair +`_ +series. + +Parent Pointers +``````````````` + +A parent pointer is a piece of file metadata that enables a user to locate the +file's parent directory without having to traverse the directory tree from the +root. +Without them, reconstruction of directory trees is hindered in much the same +way that the historic lack of reverse space mapping information once hindered +reconstruction of filesystem space metadata. +The parent pointer feature, however, makes total directory reconstruction +possible. + +XFS parent pointers include the dirent name and location of the entry within +the parent directory. +In other words, child files use extended attributes to store pointers to +parents in the form ``(parent_inum, parent_gen, dirent_pos) → (dirent_name)``. +The directory checking process can be strengthened to ensure that the target of +each dirent also contains a parent pointer pointing back to the dirent. +Likewise, each parent pointer can be checked by ensuring that the target of +each parent pointer is a directory and that it contains a dirent matching +the parent pointer. +Both online and offline repair can use this strategy. + +**Note**: The ondisk format of parent pointers is not yet finalized. + ++--------------------------------------------------------------------------+ +| **Historical Sidebar**: | ++--------------------------------------------------------------------------+ +| Directory parent pointers were first proposed as an XFS feature more | +| than a decade ago by SGI. | +| Each link from a parent directory to a child file is mirrored with an | +| extended attribute in the child that could be used to identify the | +| parent directory. | +| Unfortunately, this early implementation had major shortcomings and was | +| never merged into Linux XFS: | +| | +| 1. The XFS codebase of the late 2000s did not have the infrastructure to | +| enforce strong referential integrity in the directory tree. | +| It did not guarantee that a change in a forward link would always be | +| followed up with the corresponding change to the reverse links. | +| | +| 2. Referential integrity was not integrated into offline repair. | +| Checking and repairs were performed on mounted filesystems without | +| taking any kernel or inode locks to coordinate access. | +| It is not clear how this actually worked properly. | +| | +| 3. The extended attribute did not record the name of the directory entry | +| in the parent, so the SGI parent pointer implementation cannot be | +| used to reconnect the directory tree. | +| | +| 4. Extended attribute forks only support 65,536 extents, which means | +| that parent pointer attribute creation is likely to fail at some | +| point before the maximum file link count is achieved. | +| | +| The original parent pointer design was too unstable for something like | +| a file system repair to depend on. | +| Allison Henderson, Chandan Babu, and Catherine Hoang are working on a | +| second implementation that solves all shortcomings of the first. | +| During 2022, Allison introduced log intent items to track physical | +| manipulations of the extended attribute structures. | +| This solves the referential integrity problem by making it possible to | +| commit a dirent update and a parent pointer update in the same | +| transaction. | +| Chandan increased the maximum extent counts of both data and attribute | +| forks, thereby ensuring that the extended attribute structure can grow | +| to handle the maximum hardlink count of any file. | ++--------------------------------------------------------------------------+ + +Case Study: Repairing Directories with Parent Pointers +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Directory rebuilding uses a :ref:`coordinated inode scan ` and +a :ref:`directory entry live update hook ` as follows: + +1. Set up a temporary directory for generating the new directory structure, + an xfblob for storing entry names, and an xfarray for stashing directory + updates. + +2. Set up an inode scanner and hook into the directory entry code to receive + updates on directory operations. + +3. For each parent pointer found in each file scanned, decide if the parent + pointer references the directory of interest. + If so: + + a. Stash an addname entry for this dirent in the xfarray for later. + + b. When finished scanning that file, flush the stashed updates to the + temporary directory. + +4. For each live directory update received via the hook, decide if the child + has already been scanned. + If so: + + a. Stash an addname or removename entry for this dirent update in the + xfarray for later. + We cannot write directly to the temporary directory because hook + functions are not allowed to modify filesystem metadata. + Instead, we stash updates in the xfarray and rely on the scanner thread + to apply the stashed updates to the temporary directory. + +5. When the scan is complete, atomically swap the contents of the temporary + directory and the directory being repaired. + The temporary directory now contains the damaged directory structure. + +6. Reap the temporary directory. + +7. Update the dirent position field of parent pointers as necessary. + This may require the queuing of a substantial number of xattr log intent + items. + +The proposed patchset is the +`parent pointers directory repair +`_ +series. + +**Unresolved Question**: How will repair ensure that the ``dirent_pos`` fields +match in the reconstructed directory? + +*Answer*: There are a few ways to solve this problem: + +1. The field could be designated advisory, since the other three values are + sufficient to find the entry in the parent. + However, this makes indexed key lookup impossible while repairs are ongoing. + +2. We could allow creating directory entries at specified offsets, which solves + the referential integrity problem but runs the risk that dirent creation + will fail due to conflicts with the free space in the directory. + + These conflicts could be resolved by appending the directory entry and + amending the xattr code to support updating an xattr key and reindexing the + dabtree, though this would have to be performed with the parent directory + still locked. + +3. Same as above, but remove the old parent pointer entry and add a new one + atomically. + +4. Change the ondisk xattr format to ``(parent_inum, name) → (parent_gen)``, + which would provide the attr name uniqueness that we require, without + forcing repair code to update the dirent position. + Unfortunately, this requires changes to the xattr code to support attr + names as long as 263 bytes. + +5. Change the ondisk xattr format to ``(parent_inum, hash(name)) → + (name, parent_gen)``. + If the hash is sufficiently resistant to collisions (e.g. sha256) then + this should provide the attr name uniqueness that we require. + Names shorter than 247 bytes could be stored directly. + +Discussion is ongoing under the `parent pointers patch deluge +`_. + +Case Study: Repairing Parent Pointers +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Online reconstruction of a file's parent pointer information works similarly to +directory reconstruction: + +1. Set up a temporary file for generating a new extended attribute structure, + an `xfblob` for storing parent pointer names, and an xfarray for + stashing parent pointer updates. + +2. Set up an inode scanner and hook into the directory entry code to receive + updates on directory operations. + +3. For each directory entry found in each directory scanned, decide if the + dirent references the file of interest. + If so: + + a. Stash an addpptr entry for this parent pointer in the xfblob and xfarray + for later. + + b. When finished scanning the directory, flush the stashed updates to the + temporary directory. + +4. For each live directory update received via the hook, decide if the parent + has already been scanned. + If so: + + a. Stash an addpptr or removepptr entry for this dirent update in the + xfarray for later. + We cannot write parent pointers directly to the temporary file because + hook functions are not allowed to modify filesystem metadata. + Instead, we stash updates in the xfarray and rely on the scanner thread + to apply the stashed parent pointer updates to the temporary file. + +5. Copy all non-parent pointer extended attributes to the temporary file. + +6. When the scan is complete, atomically swap the attribute fork of the + temporary file and the file being repaired. + The temporary file now contains the damaged extended attribute structure. + +7. Reap the temporary file. + +The proposed patchset is the +`parent pointers repair +`_ +series. + +Digression: Offline Checking of Parent Pointers +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Examining parent pointers in offline repair works differently because corrupt +files are erased long before directory tree connectivity checks are performed. +Parent pointer checks are therefore a second pass to be added to the existing +connectivity checks: + +1. After the set of surviving files has been established (i.e. phase 6), + walk the surviving directories of each AG in the filesystem. + This is already performed as part of the connectivity checks. + +2. For each directory entry found, record the name in an xfblob, and store + ``(child_ag_inum, parent_inum, parent_gen, dirent_pos)`` tuples in a + per-AG in-memory slab. + +3. For each AG in the filesystem, + + a. Sort the per-AG tuples in order of child_ag_inum, parent_inum, and + dirent_pos. + + b. For each inode in the AG, + + 1. Scan the inode for parent pointers. + Record the names in a per-file xfblob, and store ``(parent_inum, + parent_gen, dirent_pos)`` tuples in a per-file slab. + + 2. Sort the per-file tuples in order of parent_inum, and dirent_pos. + + 3. Position one slab cursor at the start of the inode's records in the + per-AG tuple slab. + This should be trivial since the per-AG tuples are in child inumber + order. + + 4. Position a second slab cursor at the start of the per-file tuple slab. + + 5. Iterate the two cursors in lockstep, comparing the parent_ino and + dirent_pos fields of the records under each cursor. + + a. Tuples in the per-AG list but not the per-file list are missing and + need to be written to the inode. + + b. Tuples in the per-file list but not the per-AG list are dangling + and need to be removed from the inode. + + c. For tuples in both lists, update the parent_gen and name components + of the parent pointer if necessary. + +4. Move on to examining link counts, as we do today. + +The proposed patchset is the +`offline parent pointers repair +`_ +series. + +Rebuilding directories from parent pointers in offline repair is very +challenging because it currently uses a single-pass scan of the filesystem +during phase 3 to decide which files are corrupt enough to be zapped. +This scan would have to be converted into a multi-pass scan: + +1. The first pass of the scan zaps corrupt inodes, forks, and attributes + much as it does now. + Corrupt directories are noted but not zapped. + +2. The next pass records parent pointers pointing to the directories noted + as being corrupt in the first pass. + This second pass may have to happen after the phase 4 scan for duplicate + blocks, if phase 4 is also capable of zapping directories. + +3. The third pass resets corrupt directories to an empty shortform directory. + Free space metadata has not been ensured yet, so repair cannot yet use the + directory building code in libxfs. + +4. At the start of phase 6, space metadata have been rebuilt. + Use the parent pointer information recorded during step 2 to reconstruct + the dirents and add them to the now-empty directories. + +This code has not yet been constructed. + +.. _orphanage: + +The Orphanage +------------- + +Filesystems present files as a directed, and hopefully acyclic, graph. +In other words, a tree. +The root of the filesystem is a directory, and each entry in a directory points +downwards either to more subdirectories or to non-directory files. +Unfortunately, a disruption in the directory graph pointers result in a +disconnected graph, which makes files impossible to access via regular path +resolution. + +Without parent pointers, the directory parent pointer online scrub code can +detect a dotdot entry pointing to a parent directory that doesn't have a link +back to the child directory and the file link count checker can detect a file +that isn't pointed to by any directory in the filesystem. +If such a file has a positive link count, the file is an orphan. + +With parent pointers, directories can be rebuilt by scanning parent pointers +and parent pointers can be rebuilt by scanning directories. +This should reduce the incidence of files ending up in ``/lost+found``. + +When orphans are found, they should be reconnected to the directory tree. +Offline fsck solves the problem by creating a directory ``/lost+found`` to +serve as an orphanage, and linking orphan files into the orphanage by using the +inumber as the name. +Reparenting a file to the orphanage does not reset any of its permissions or +ACLs. + +This process is more involved in the kernel than it is in userspace. +The directory and file link count repair setup functions must use the regular +VFS mechanisms to create the orphanage directory with all the necessary +security attributes and dentry cache entries, just like a regular directory +tree modification. + +Orphaned files are adopted by the orphanage as follows: + +1. Call ``xrep_orphanage_try_create`` at the start of the scrub setup function + to try to ensure that the lost and found directory actually exists. + This also attaches the orphanage directory to the scrub context. + +2. If the decision is made to reconnect a file, take the IOLOCK of both the + orphanage and the file being reattached. + The ``xrep_orphanage_iolock_two`` function follows the inode locking + strategy discussed earlier. + +3. Call ``xrep_orphanage_compute_blkres`` and ``xrep_orphanage_compute_name`` + to compute the new name in the orphanage and the block reservation required. + +4. Use ``xrep_orphanage_adoption_prep`` to reserve resources to the repair + transaction. + +5. Call ``xrep_orphanage_adopt`` to reparent the orphaned file into the lost + and found, and update the kernel dentry cache. + +The proposed patches are in the +`orphanage adoption +`_ +series. + +6. Userspace Algorithms and Data Structures +=========================================== + +This section discusses the key algorithms and data structures of the userspace +program, ``xfs_scrub``, that provide the ability to drive metadata checks and +repairs in the kernel, verify file data, and look for other potential problems. + +.. _scrubcheck: + +Checking Metadata +----------------- + +Recall the :ref:`phases of fsck work` outlined earlier. +That structure follows naturally from the data dependencies designed into the +filesystem from its beginnings in 1993. +In XFS, there are several groups of metadata dependencies: + +a. Filesystem summary counts depend on consistency within the inode indices, + the allocation group space btrees, and the realtime volume space + information. + +b. Quota resource counts depend on consistency within the quota file data + forks, inode indices, inode records, and the forks of every file on the + system. + +c. The naming hierarchy depends on consistency within the directory and + extended attribute structures. + This includes file link counts. + +d. Directories, extended attributes, and file data depend on consistency within + the file forks that map directory and extended attribute data to physical + storage media. + +e. The file forks depends on consistency within inode records and the space + metadata indices of the allocation groups and the realtime volume. + This includes quota and realtime metadata files. + +f. Inode records depends on consistency within the inode metadata indices. + +g. Realtime space metadata depend on the inode records and data forks of the + realtime metadata inodes. + +h. The allocation group metadata indices (free space, inodes, reference count, + and reverse mapping btrees) depend on consistency within the AG headers and + between all the AG metadata btrees. + +i. ``xfs_scrub`` depends on the filesystem being mounted and kernel support + for online fsck functionality. + +Therefore, a metadata dependency graph is a convenient way to schedule checking +operations in the ``xfs_scrub`` program: + +- Phase 1 checks that the provided path maps to an XFS filesystem and detect + the kernel's scrubbing abilities, which validates group (i). + +- Phase 2 scrubs groups (g) and (h) in parallel using a threaded workqueue. + +- Phase 3 scans inodes in parallel. + For each inode, groups (f), (e), and (d) are checked, in that order. + +- Phase 4 repairs everything in groups (i) through (d) so that phases 5 and 6 + may run reliably. + +- Phase 5 starts by checking groups (b) and (c) in parallel before moving on + to checking names. + +- Phase 6 depends on groups (i) through (b) to find file data blocks to verify, + to read them, and to report which blocks of which files are affected. + +- Phase 7 checks group (a), having validated everything else. + +Notice that the data dependencies between groups are enforced by the structure +of the program flow. + +Parallel Inode Scans +-------------------- + +An XFS filesystem can easily contain hundreds of millions of inodes. +Given that XFS targets installations with large high-performance storage, +it is desirable to scrub inodes in parallel to minimize runtime, particularly +if the program has been invoked manually from a command line. +This requires careful scheduling to keep the threads as evenly loaded as +possible. + +Early iterations of the ``xfs_scrub`` inode scanner naïvely created a single +workqueue and scheduled a single workqueue item per AG. +Each workqueue item walked the inode btree (with ``XFS_IOC_INUMBERS``) to find +inode chunks and then called bulkstat (``XFS_IOC_BULKSTAT``) to gather enough +information to construct file handles. +The file handle was then passed to a function to generate scrub items for each +metadata object of each inode. +This simple algorithm leads to thread balancing problems in phase 3 if the +filesystem contains one AG with a few large sparse files and the rest of the +AGs contain many smaller files. +The inode scan dispatch function was not sufficiently granular; it should have +been dispatching at the level of individual inodes, or, to constrain memory +consumption, inode btree records. + +Thanks to Dave Chinner, bounded workqueues in userspace enable ``xfs_scrub`` to +avoid this problem with ease by adding a second workqueue. +Just like before, the first workqueue is seeded with one workqueue item per AG, +and it uses INUMBERS to find inode btree chunks. +The second workqueue, however, is configured with an upper bound on the number +of items that can be waiting to be run. +Each inode btree chunk found by the first workqueue's workers are queued to the +second workqueue, and it is this second workqueue that queries BULKSTAT, +creates a file handle, and passes it to a function to generate scrub items for +each metadata object of each inode. +If the second workqueue is too full, the workqueue add function blocks the +first workqueue's workers until the backlog eases. +This doesn't completely solve the balancing problem, but reduces it enough to +move on to more pressing issues. + +The proposed patchsets are the scrub +`performance tweaks +`_ +and the +`inode scan rebalance +`_ +series. + +.. _scrubrepair: + +Scheduling Repairs +------------------ + +During phase 2, corruptions and inconsistencies reported in any AGI header or +inode btree are repaired immediately, because phase 3 relies on proper +functioning of the inode indices to find inodes to scan. +Failed repairs are rescheduled to phase 4. +Problems reported in any other space metadata are deferred to phase 4. +Optimization opportunities are always deferred to phase 4, no matter their +origin. + +During phase 3, corruptions and inconsistencies reported in any part of a +file's metadata are repaired immediately if all space metadata were validated +during phase 2. +Repairs that fail or cannot be repaired immediately are scheduled for phase 4. + +In the original design of ``xfs_scrub``, it was thought that repairs would be +so infrequent that the ``struct xfs_scrub_metadata`` objects used to +communicate with the kernel could also be used as the primary object to +schedule repairs. +With recent increases in the number of optimizations possible for a given +filesystem object, it became much more memory-efficient to track all eligible +repairs for a given filesystem object with a single repair item. +Each repair item represents a single lockable object -- AGs, metadata files, +individual inodes, or a class of summary information. + +Phase 4 is responsible for scheduling a lot of repair work in as quick a +manner as is practical. +The :ref:`data dependencies ` outlined earlier still apply, which +means that ``xfs_scrub`` must try to complete the repair work scheduled by +phase 2 before trying repair work scheduled by phase 3. +The repair process is as follows: + +1. Start a round of repair with a workqueue and enough workers to keep the CPUs + as busy as the user desires. + + a. For each repair item queued by phase 2, + + i. Ask the kernel to repair everything listed in the repair item for a + given filesystem object. + + ii. Make a note if the kernel made any progress in reducing the number + of repairs needed for this object. + + iii. If the object no longer requires repairs, revalidate all metadata + associated with this object. + If the revalidation succeeds, drop the repair item. + If not, requeue the item for more repairs. + + b. If any repairs were made, jump back to 1a to retry all the phase 2 items. + + c. For each repair item queued by phase 3, + + i. Ask the kernel to repair everything listed in the repair item for a + given filesystem object. + + ii. Make a note if the kernel made any progress in reducing the number + of repairs needed for this object. + + iii. If the object no longer requires repairs, revalidate all metadata + associated with this object. + If the revalidation succeeds, drop the repair item. + If not, requeue the item for more repairs. + + d. If any repairs were made, jump back to 1c to retry all the phase 3 items. + +2. If step 1 made any repair progress of any kind, jump back to step 1 to start + another round of repair. + +3. If there are items left to repair, run them all serially one more time. + Complain if the repairs were not successful, since this is the last chance + to repair anything. + +Corruptions and inconsistencies encountered during phases 5 and 7 are repaired +immediately. +Corrupt file data blocks reported by phase 6 cannot be recovered by the +filesystem. + +The proposed patchsets are the +`repair warning improvements +`_, +refactoring of the +`repair data dependency +`_ +and +`object tracking +`_, +and the +`repair scheduling +`_ +improvement series. + +Checking Names for Confusable Unicode Sequences +----------------------------------------------- + +If ``xfs_scrub`` succeeds in validating the filesystem metadata by the end of +phase 4, it moves on to phase 5, which checks for suspicious looking names in +the filesystem. +These names consist of the filesystem label, names in directory entries, and +the names of extended attributes. +Like most Unix filesystems, XFS imposes the sparest of constraints on the +contents of a name: + +- Slashes and null bytes are not allowed in directory entries. + +- Null bytes are not allowed in userspace-visible extended attributes. + +- Null bytes are not allowed in the filesystem label. + +Directory entries and attribute keys store the length of the name explicitly +ondisk, which means that nulls are not name terminators. +For this section, the term "naming domain" refers to any place where names are +presented together -- all the names in a directory, or all the attributes of a +file. + +Although the Unix naming constraints are very permissive, the reality of most +modern-day Linux systems is that programs work with Unicode character code +points to support international languages. +These programs typically encode those code points in UTF-8 when interfacing +with the C library because the kernel expects null-terminated names. +In the common case, therefore, names found in an XFS filesystem are actually +UTF-8 encoded Unicode data. + +To maximize its expressiveness, the Unicode standard defines separate control +points for various characters that render similarly or identically in writing +systems around the world. +For example, the character "Cyrillic Small Letter A" U+0430 "а" often renders +identically to "Latin Small Letter A" U+0061 "a". + +The standard also permits characters to be constructed in multiple ways -- +either by using a defined code point, or by combining one code point with +various combining marks. +For example, the character "Angstrom Sign U+212B "Å" can also be expressed +as "Latin Capital Letter A" U+0041 "A" followed by "Combining Ring Above" +U+030A "◌̊". +Both sequences render identically. + +Like the standards that preceded it, Unicode also defines various control +characters to alter the presentation of text. +For example, the character "Right-to-Left Override" U+202E can trick some +programs into rendering "moo\\xe2\\x80\\xaegnp.txt" as "mootxt.png". +A second category of rendering problems involves whitespace characters. +If the character "Zero Width Space" U+200B is encountered in a file name, the +name will render identically to a name that does not have the zero width +space. + +If two names within a naming domain have different byte sequences but render +identically, a user may be confused by it. +The kernel, in its indifference to upper level encoding schemes, permits this. +Most filesystem drivers persist the byte sequence names that are given to them +by the VFS. + +Techniques for detecting confusable names are explained in great detail in +sections 4 and 5 of the +`Unicode Security Mechanisms `_ +document. +When ``xfs_scrub`` detects UTF-8 encoding in use on a system, it uses the +Unicode normalization form NFD in conjunction with the confusable name +detection component of +`libicu `_ +to identify names with a directory or within a file's extended attributes that +could be confused for each other. +Names are also checked for control characters, non-rendering characters, and +mixing of bidirectional characters. +All of these potential issues are reported to the system administrator during +phase 5. + +Media Verification of File Data Extents +--------------------------------------- + +The system administrator can elect to initiate a media scan of all file data +blocks. +This scan after validation of all filesystem metadata (except for the summary +counters) as phase 6. +The scan starts by calling ``FS_IOC_GETFSMAP`` to scan the filesystem space map +to find areas that are allocated to file data fork extents. +Gaps between data fork extents that are smaller than 64k are treated as if +they were data fork extents to reduce the command setup overhead. +When the space map scan accumulates a region larger than 32MB, a media +verification request is sent to the disk as a directio read of the raw block +device. + +If the verification read fails, ``xfs_scrub`` retries with single-block reads +to narrow down the failure to the specific region of the media and recorded. +When it has finished issuing verification requests, it again uses the space +mapping ioctl to map the recorded media errors back to metadata structures +and report what has been lost. +For media errors in blocks owned by files, parent pointers can be used to +construct file paths from inode numbers for user-friendly reporting. + +7. Conclusion and Future Work +============================= + +It is hoped that the reader of this document has followed the designs laid out +in this document and now has some familiarity with how XFS performs online +rebuilding of its metadata indices, and how filesystem users can interact with +that functionality. +Although the scope of this work is daunting, it is hoped that this guide will +make it easier for code readers to understand what has been built, for whom it +has been built, and why. +Please feel free to contact the XFS mailing list with questions. + +FIEXCHANGE_RANGE +---------------- + +As discussed earlier, a second frontend to the atomic extent swap mechanism is +a new ioctl call that userspace programs can use to commit updates to files +atomically. +This frontend has been out for review for several years now, though the +necessary refinements to online repair and lack of customer demand mean that +the proposal has not been pushed very hard. + +Extent Swapping with Regular User Files +``````````````````````````````````````` + +As mentioned earlier, XFS has long had the ability to swap extents between +files, which is used almost exclusively by ``xfs_fsr`` to defragment files. +The earliest form of this was the fork swap mechanism, where the entire +contents of data forks could be exchanged between two files by exchanging the +raw bytes in each inode fork's immediate area. +When XFS v5 came along with self-describing metadata, this old mechanism grew +some log support to continue rewriting the owner fields of BMBT blocks during +log recovery. +When the reverse mapping btree was later added to XFS, the only way to maintain +the consistency of the fork mappings with the reverse mapping index was to +develop an iterative mechanism that used deferred bmap and rmap operations to +swap mappings one at a time. +This mechanism is identical to steps 2-3 from the procedure above except for +the new tracking items, because the atomic extent swap mechanism is an +iteration of an existing mechanism and not something totally novel. +For the narrow case of file defragmentation, the file contents must be +identical, so the recovery guarantees are not much of a gain. + +Atomic extent swapping is much more flexible than the existing swapext +implementations because it can guarantee that the caller never sees a mix of +old and new contents even after a crash, and it can operate on two arbitrary +file fork ranges. +The extra flexibility enables several new use cases: + +- **Atomic commit of file writes**: A userspace process opens a file that it + wants to update. + Next, it opens a temporary file and calls the file clone operation to reflink + the first file's contents into the temporary file. + Writes to the original file should instead be written to the temporary file. + Finally, the process calls the atomic extent swap system call + (``FIEXCHANGE_RANGE``) to exchange the file contents, thereby committing all + of the updates to the original file, or none of them. + +.. _swapext_if_unchanged: + +- **Transactional file updates**: The same mechanism as above, but the caller + only wants the commit to occur if the original file's contents have not + changed. + To make this happen, the calling process snapshots the file modification and + change timestamps of the original file before reflinking its data to the + temporary file. + When the program is ready to commit the changes, it passes the timestamps + into the kernel as arguments to the atomic extent swap system call. + The kernel only commits the changes if the provided timestamps match the + original file. + +- **Emulation of atomic block device writes**: Export a block device with a + logical sector size matching the filesystem block size to force all writes + to be aligned to the filesystem block size. + Stage all writes to a temporary file, and when that is complete, call the + atomic extent swap system call with a flag to indicate that holes in the + temporary file should be ignored. + This emulates an atomic device write in software, and can support arbitrary + scattered writes. + +Vectorized Scrub +---------------- + +As it turns out, the :ref:`refactoring ` of repair items mentioned +earlier was a catalyst for enabling a vectorized scrub system call. +Since 2018, the cost of making a kernel call has increased considerably on some +systems to mitigate the effects of speculative execution attacks. +This incentivizes program authors to make as few system calls as possible to +reduce the number of times an execution path crosses a security boundary. + +With vectorized scrub, userspace pushes to the kernel the identity of a +filesystem object, a list of scrub types to run against that object, and a +simple representation of the data dependencies between the selected scrub +types. +The kernel executes as much of the caller's plan as it can until it hits a +dependency that cannot be satisfied due to a corruption, and tells userspace +how much was accomplished. +It is hoped that ``io_uring`` will pick up enough of this functionality that +online fsck can use that instead of adding a separate vectored scrub system +call to XFS. + +The relevant patchsets are the +`kernel vectorized scrub +`_ +and +`userspace vectorized scrub +`_ +series. + +Quality of Service Targets for Scrub +------------------------------------ + +One serious shortcoming of the online fsck code is that the amount of time that +it can spend in the kernel holding resource locks is basically unbounded. +Userspace is allowed to send a fatal signal to the process which will cause +``xfs_scrub`` to exit when it reaches a good stopping point, but there's no way +for userspace to provide a time budget to the kernel. +Given that the scrub codebase has helpers to detect fatal signals, it shouldn't +be too much work to allow userspace to specify a timeout for a scrub/repair +operation and abort the operation if it exceeds budget. +However, most repair functions have the property that once they begin to touch +ondisk metadata, the operation cannot be cancelled cleanly, after which a QoS +timeout is no longer useful. + +Defragmenting Free Space +------------------------ + +Over the years, many XFS users have requested the creation of a program to +clear a portion of the physical storage underlying a filesystem so that it +becomes a contiguous chunk of free space. +Call this free space defragmenter ``clearspace`` for short. + +The first piece the ``clearspace`` program needs is the ability to read the +reverse mapping index from userspace. +This already exists in the form of the ``FS_IOC_GETFSMAP`` ioctl. +The second piece it needs is a new fallocate mode +(``FALLOC_FL_MAP_FREE_SPACE``) that allocates the free space in a region and +maps it to a file. +Call this file the "space collector" file. +The third piece is the ability to force an online repair. + +To clear all the metadata out of a portion of physical storage, clearspace +uses the new fallocate map-freespace call to map any free space in that region +to the space collector file. +Next, clearspace finds all metadata blocks in that region by way of +``GETFSMAP`` and issues forced repair requests on the data structure. +This often results in the metadata being rebuilt somewhere that is not being +cleared. +After each relocation, clearspace calls the "map free space" function again to +collect any newly freed space in the region being cleared. + +To clear all the file data out of a portion of the physical storage, clearspace +uses the FSMAP information to find relevant file data blocks. +Having identified a good target, it uses the ``FICLONERANGE`` call on that part +of the file to try to share the physical space with a dummy file. +Cloning the extent means that the original owners cannot overwrite the +contents; any changes will be written somewhere else via copy-on-write. +Clearspace makes its own copy of the frozen extent in an area that is not being +cleared, and uses ``FIEDEUPRANGE`` (or the :ref:`atomic extent swap +` feature) to change the target file's data extent +mapping away from the area being cleared. +When all other mappings have been moved, clearspace reflinks the space into the +space collector file so that it becomes unavailable. + +There are further optimizations that could apply to the above algorithm. +To clear a piece of physical storage that has a high sharing factor, it is +strongly desirable to retain this sharing factor. +In fact, these extents should be moved first to maximize sharing factor after +the operation completes. +To make this work smoothly, clearspace needs a new ioctl +(``FS_IOC_GETREFCOUNTS``) to report reference count information to userspace. +With the refcount information exposed, clearspace can quickly find the longest, +most shared data extents in the filesystem, and target them first. + +**Future Work Question**: How might the filesystem move inode chunks? + +*Answer*: To move inode chunks, Dave Chinner constructed a prototype program +that creates a new file with the old contents and then locklessly runs around +the filesystem updating directory entries. +The operation cannot complete if the filesystem goes down. +That problem isn't totally insurmountable: create an inode remapping table +hidden behind a jump label, and a log item that tracks the kernel walking the +filesystem to update directory entries. +The trouble is, the kernel can't do anything about open files, since it cannot +revoke them. + +**Future Work Question**: Can static keys be used to minimize the cost of +supporting ``revoke()`` on XFS files? + +*Answer*: Yes. +Until the first revocation, the bailout code need not be in the call path at +all. + +The relevant patchsets are the +`kernel freespace defrag +`_ +and +`userspace freespace defrag +`_ +series. + +Shrinking Filesystems +--------------------- + +Removing the end of the filesystem ought to be a simple matter of evacuating +the data and metadata at the end of the filesystem, and handing the freed space +to the shrink code. +That requires an evacuation of the space at end of the filesystem, which is a +use of free space defragmentation! diff --git a/Documentation/filesystems/xfs/xfs-self-describing-metadata.rst b/Documentation/filesystems/xfs/xfs-self-describing-metadata.rst new file mode 100644 index 00000000000000..a10c4ae6955e7a --- /dev/null +++ b/Documentation/filesystems/xfs/xfs-self-describing-metadata.rst @@ -0,0 +1,353 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. _xfs_self_describing_metadata: + +============================ +XFS Self Describing Metadata +============================ + +Introduction +============ + +The largest scalability problem facing XFS is not one of algorithmic +scalability, but of verification of the filesystem structure. Scalabilty of the +structures and indexes on disk and the algorithms for iterating them are +adequate for supporting PB scale filesystems with billions of inodes, however it +is this very scalability that causes the verification problem. + +Almost all metadata on XFS is dynamically allocated. The only fixed location +metadata is the allocation group headers (SB, AGF, AGFL and AGI), while all +other metadata structures need to be discovered by walking the filesystem +structure in different ways. While this is already done by userspace tools for +validating and repairing the structure, there are limits to what they can +verify, and this in turn limits the supportable size of an XFS filesystem. + +For example, it is entirely possible to manually use xfs_db and a bit of +scripting to analyse the structure of a 100TB filesystem when trying to +determine the root cause of a corruption problem, but it is still mainly a +manual task of verifying that things like single bit errors or misplaced writes +weren't the ultimate cause of a corruption event. It may take a few hours to a +few days to perform such forensic analysis, so for at this scale root cause +analysis is entirely possible. + +However, if we scale the filesystem up to 1PB, we now have 10x as much metadata +to analyse and so that analysis blows out towards weeks/months of forensic work. +Most of the analysis work is slow and tedious, so as the amount of analysis goes +up, the more likely that the cause will be lost in the noise. Hence the primary +concern for supporting PB scale filesystems is minimising the time and effort +required for basic forensic analysis of the filesystem structure. + + +Self Describing Metadata +======================== + +One of the problems with the current metadata format is that apart from the +magic number in the metadata block, we have no other way of identifying what it +is supposed to be. We can't even identify if it is the right place. Put simply, +you can't look at a single metadata block in isolation and say "yes, it is +supposed to be there and the contents are valid". + +Hence most of the time spent on forensic analysis is spent doing basic +verification of metadata values, looking for values that are in range (and hence +not detected by automated verification checks) but are not correct. Finding and +understanding how things like cross linked block lists (e.g. sibling +pointers in a btree end up with loops in them) are the key to understanding what +went wrong, but it is impossible to tell what order the blocks were linked into +each other or written to disk after the fact. + +Hence we need to record more information into the metadata to allow us to +quickly determine if the metadata is intact and can be ignored for the purpose +of analysis. We can't protect against every possible type of error, but we can +ensure that common types of errors are easily detectable. Hence the concept of +self describing metadata. + +The first, fundamental requirement of self describing metadata is that the +metadata object contains some form of unique identifier in a well known +location. This allows us to identify the expected contents of the block and +hence parse and verify the metadata object. IF we can't independently identify +the type of metadata in the object, then the metadata doesn't describe itself +very well at all! + +Luckily, almost all XFS metadata has magic numbers embedded already - only the +AGFL, remote symlinks and remote attribute blocks do not contain identifying +magic numbers. Hence we can change the on-disk format of all these objects to +add more identifying information and detect this simply by changing the magic +numbers in the metadata objects. That is, if it has the current magic number, +the metadata isn't self identifying. If it contains a new magic number, it is +self identifying and we can do much more expansive automated verification of the +metadata object at runtime, during forensic analysis or repair. + +As a primary concern, self describing metadata needs some form of overall +integrity checking. We cannot trust the metadata if we cannot verify that it has +not been changed as a result of external influences. Hence we need some form of +integrity check, and this is done by adding CRC32c validation to the metadata +block. If we can verify the block contains the metadata it was intended to +contain, a large amount of the manual verification work can be skipped. + +CRC32c was selected as metadata cannot be more than 64k in length in XFS and +hence a 32 bit CRC is more than sufficient to detect multi-bit errors in +metadata blocks. CRC32c is also now hardware accelerated on common CPUs so it is +fast. So while CRC32c is not the strongest of possible integrity checks that +could be used, it is more than sufficient for our needs and has relatively +little overhead. Adding support for larger integrity fields and/or algorithms +does really provide any extra value over CRC32c, but it does add a lot of +complexity and so there is no provision for changing the integrity checking +mechanism. + +Self describing metadata needs to contain enough information so that the +metadata block can be verified as being in the correct place without needing to +look at any other metadata. This means it needs to contain location information. +Just adding a block number to the metadata is not sufficient to protect against +mis-directed writes - a write might be misdirected to the wrong LUN and so be +written to the "correct block" of the wrong filesystem. Hence location +information must contain a filesystem identifier as well as a block number. + +Another key information point in forensic analysis is knowing who the metadata +block belongs to. We already know the type, the location, that it is valid +and/or corrupted, and how long ago that it was last modified. Knowing the owner +of the block is important as it allows us to find other related metadata to +determine the scope of the corruption. For example, if we have a extent btree +object, we don't know what inode it belongs to and hence have to walk the entire +filesystem to find the owner of the block. Worse, the corruption could mean that +no owner can be found (i.e. it's an orphan block), and so without an owner field +in the metadata we have no idea of the scope of the corruption. If we have an +owner field in the metadata object, we can immediately do top down validation to +determine the scope of the problem. + +Different types of metadata have different owner identifiers. For example, +directory, attribute and extent tree blocks are all owned by an inode, while +freespace btree blocks are owned by an allocation group. Hence the size and +contents of the owner field are determined by the type of metadata object we are +looking at. The owner information can also identify misplaced writes (e.g. +freespace btree block written to the wrong AG). + +Self describing metadata also needs to contain some indication of when it was +written to the filesystem. One of the key information points when doing forensic +analysis is how recently the block was modified. Correlation of set of corrupted +metadata blocks based on modification times is important as it can indicate +whether the corruptions are related, whether there's been multiple corruption +events that lead to the eventual failure, and even whether there are corruptions +present that the run-time verification is not detecting. + +For example, we can determine whether a metadata object is supposed to be free +space or still allocated if it is still referenced by its owner by looking at +when the free space btree block that contains the block was last written +compared to when the metadata object itself was last written. If the free space +block is more recent than the object and the object's owner, then there is a +very good chance that the block should have been removed from the owner. + +To provide this "written timestamp", each metadata block gets the Log Sequence +Number (LSN) of the most recent transaction it was modified on written into it. +This number will always increase over the life of the filesystem, and the only +thing that resets it is running xfs_repair on the filesystem. Further, by use of +the LSN we can tell if the corrupted metadata all belonged to the same log +checkpoint and hence have some idea of how much modification occurred between +the first and last instance of corrupt metadata on disk and, further, how much +modification occurred between the corruption being written and when it was +detected. + +Runtime Validation +================== + +Validation of self-describing metadata takes place at runtime in two places: + + - immediately after a successful read from disk + - immediately prior to write IO submission + +The verification is completely stateless - it is done independently of the +modification process, and seeks only to check that the metadata is what it says +it is and that the metadata fields are within bounds and internally consistent. +As such, we cannot catch all types of corruption that can occur within a block +as there may be certain limitations that operational state enforces of the +metadata, or there may be corruption of interblock relationships (e.g. corrupted +sibling pointer lists). Hence we still need stateful checking in the main code +body, but in general most of the per-field validation is handled by the +verifiers. + +For read verification, the caller needs to specify the expected type of metadata +that it should see, and the IO completion process verifies that the metadata +object matches what was expected. If the verification process fails, then it +marks the object being read as EFSCORRUPTED. The caller needs to catch this +error (same as for IO errors), and if it needs to take special action due to a +verification error it can do so by catching the EFSCORRUPTED error value. If we +need more discrimination of error type at higher levels, we can define new +error numbers for different errors as necessary. + +The first step in read verification is checking the magic number and determining +whether CRC validating is necessary. If it is, the CRC32c is calculated and +compared against the value stored in the object itself. Once this is validated, +further checks are made against the location information, followed by extensive +object specific metadata validation. If any of these checks fail, then the +buffer is considered corrupt and the EFSCORRUPTED error is set appropriately. + +Write verification is the opposite of the read verification - first the object +is extensively verified and if it is OK we then update the LSN from the last +modification made to the object, After this, we calculate the CRC and insert it +into the object. Once this is done the write IO is allowed to continue. If any +error occurs during this process, the buffer is again marked with a EFSCORRUPTED +error for the higher layers to catch. + +Structures +========== + +A typical on-disk structure needs to contain the following information:: + + struct xfs_ondisk_hdr { + __be32 magic; /* magic number */ + __be32 crc; /* CRC, not logged */ + uuid_t uuid; /* filesystem identifier */ + __be64 owner; /* parent object */ + __be64 blkno; /* location on disk */ + __be64 lsn; /* last modification in log, not logged */ + }; + +Depending on the metadata, this information may be part of a header structure +separate to the metadata contents, or may be distributed through an existing +structure. The latter occurs with metadata that already contains some of this +information, such as the superblock and AG headers. + +Other metadata may have different formats for the information, but the same +level of information is generally provided. For example: + + - short btree blocks have a 32 bit owner (ag number) and a 32 bit block + number for location. The two of these combined provide the same + information as @owner and @blkno in eh above structure, but using 8 + bytes less space on disk. + + - directory/attribute node blocks have a 16 bit magic number, and the + header that contains the magic number has other information in it as + well. hence the additional metadata headers change the overall format + of the metadata. + +A typical buffer read verifier is structured as follows:: + + #define XFS_FOO_CRC_OFF offsetof(struct xfs_ondisk_hdr, crc) + + static void + xfs_foo_read_verify( + struct xfs_buf *bp) + { + struct xfs_mount *mp = bp->b_mount; + + if ((xfs_sb_version_hascrc(&mp->m_sb) && + !xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length), + XFS_FOO_CRC_OFF)) || + !xfs_foo_verify(bp)) { + XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); + xfs_buf_ioerror(bp, EFSCORRUPTED); + } + } + +The code ensures that the CRC is only checked if the filesystem has CRCs enabled +by checking the superblock of the feature bit, and then if the CRC verifies OK +(or is not needed) it verifies the actual contents of the block. + +The verifier function will take a couple of different forms, depending on +whether the magic number can be used to determine the format of the block. In +the case it can't, the code is structured as follows:: + + static bool + xfs_foo_verify( + struct xfs_buf *bp) + { + struct xfs_mount *mp = bp->b_mount; + struct xfs_ondisk_hdr *hdr = bp->b_addr; + + if (hdr->magic != cpu_to_be32(XFS_FOO_MAGIC)) + return false; + + if (!xfs_sb_version_hascrc(&mp->m_sb)) { + if (!uuid_equal(&hdr->uuid, &mp->m_sb.sb_uuid)) + return false; + if (bp->b_bn != be64_to_cpu(hdr->blkno)) + return false; + if (hdr->owner == 0) + return false; + } + + /* object specific verification checks here */ + + return true; + } + +If there are different magic numbers for the different formats, the verifier +will look like:: + + static bool + xfs_foo_verify( + struct xfs_buf *bp) + { + struct xfs_mount *mp = bp->b_mount; + struct xfs_ondisk_hdr *hdr = bp->b_addr; + + if (hdr->magic == cpu_to_be32(XFS_FOO_CRC_MAGIC)) { + if (!uuid_equal(&hdr->uuid, &mp->m_sb.sb_uuid)) + return false; + if (bp->b_bn != be64_to_cpu(hdr->blkno)) + return false; + if (hdr->owner == 0) + return false; + } else if (hdr->magic != cpu_to_be32(XFS_FOO_MAGIC)) + return false; + + /* object specific verification checks here */ + + return true; + } + +Write verifiers are very similar to the read verifiers, they just do things in +the opposite order to the read verifiers. A typical write verifier:: + + static void + xfs_foo_write_verify( + struct xfs_buf *bp) + { + struct xfs_mount *mp = bp->b_mount; + struct xfs_buf_log_item *bip = bp->b_fspriv; + + if (!xfs_foo_verify(bp)) { + XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); + xfs_buf_ioerror(bp, EFSCORRUPTED); + return; + } + + if (!xfs_sb_version_hascrc(&mp->m_sb)) + return; + + + if (bip) { + struct xfs_ondisk_hdr *hdr = bp->b_addr; + hdr->lsn = cpu_to_be64(bip->bli_item.li_lsn); + } + xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length), XFS_FOO_CRC_OFF); + } + +This will verify the internal structure of the metadata before we go any +further, detecting corruptions that have occurred as the metadata has been +modified in memory. If the metadata verifies OK, and CRCs are enabled, we then +update the LSN field (when it was last modified) and calculate the CRC on the +metadata. Once this is done, we can issue the IO. + +Inodes and Dquots +================= + +Inodes and dquots are special snowflakes. They have per-object CRC and +self-identifiers, but they are packed so that there are multiple objects per +buffer. Hence we do not use per-buffer verifiers to do the work of per-object +verification and CRC calculations. The per-buffer verifiers simply perform basic +identification of the buffer - that they contain inodes or dquots, and that +there are magic numbers in all the expected spots. All further CRC and +verification checks are done when each inode is read from or written back to the +buffer. + +The structure of the verifiers and the identifiers checks is very similar to the +buffer code described above. The only difference is where they are called. For +example, inode read verification is done in xfs_inode_from_disk() when the inode +is first read out of the buffer and the struct xfs_inode is instantiated. The +inode is already extensively verified during writeback in xfs_iflush_int, so the +only addition here is to add the LSN and CRC to the inode as it is copied back +into the buffer. + +XXX: inode unlinked list modification doesn't recalculate the inode CRC! None of +the unlinked list modifications check or update CRCs, neither during unlink nor +log recovery. So, it's gone unnoticed until now. This won't matter immediately - +repair will probably complain about it - but it needs to be fixed. diff --git a/Documentation/gpu/amdgpu/apu-asic-info-table.csv b/Documentation/gpu/amdgpu/apu-asic-info-table.csv index 2e76b427ba1ee5..18868abe2a913f 100644 --- a/Documentation/gpu/amdgpu/apu-asic-info-table.csv +++ b/Documentation/gpu/amdgpu/apu-asic-info-table.csv @@ -7,6 +7,7 @@ SteamDeck, VANGOGH, DCN 3.0.1, 10.3.1, VCN 3.1.0, 5.2.1, 11.5.0 Ryzen 5000 series / Ryzen 7x30 series, GREEN SARDINE / Cezanne / Barcelo / Barcelo-R, DCN 2.1, 9.3, VCN 2.2, 4.1.1, 12.0.1 Ryzen 6000 series / Ryzen 7x35 series / Ryzen 7x36 series, YELLOW CARP / Rembrandt / Rembrandt-R, 3.1.2, 10.3.3, VCN 3.1.1, 5.2.3, 13.0.3 Ryzen 7000 series (AM5), Raphael, 3.1.5, 10.3.6, 3.1.2, 5.2.6, 13.0.5 -Ryzen 7x45 series (FL1), / Dragon Range, 3.1.5, 10.3.6, 3.1.2, 5.2.6, 13.0.5 +Ryzen 7x45 series (FL1), Dragon Range, 3.1.5, 10.3.6, 3.1.2, 5.2.6, 13.0.5 Ryzen 7x20 series, Mendocino, 3.1.6, 10.3.7, 3.1.1, 5.2.7, 13.0.8 -Ryzen 7x40 series, Phoenix, 3.1.4, 11.0.1 / 11.0.4, 4.0.2, 6.0.1, 13.0.4 / 13.0.11 \ No newline at end of file +Ryzen 7x40 series, Phoenix, 3.1.4, 11.0.1 / 11.0.4, 4.0.2, 6.0.1, 13.0.4 / 13.0.11 +Ryzen 8x40 series, Hawk Point, 3.1.4, 11.0.1 / 11.0.4, 4.0.2, 6.0.1, 13.0.4 / 13.0.11 diff --git a/Documentation/gpu/amdgpu/display/dc-debug.rst b/Documentation/gpu/amdgpu/display/dc-debug.rst index 40c55a61891872..817631b1dbf33b 100644 --- a/Documentation/gpu/amdgpu/display/dc-debug.rst +++ b/Documentation/gpu/amdgpu/display/dc-debug.rst @@ -75,3 +75,44 @@ change in real-time by using something like:: When reporting a bug related to DC, consider attaching this log before and after you reproduce the bug. + +DMUB Firmware Debug +=================== + +Sometimes, dmesg logs aren't enough. This is especially true if a feature is +implemented primarily in DMUB firmware. In such cases, all we see in dmesg when +an issue arises is some generic timeout error. So, to get more relevant +information, we can trace DMUB commands by enabling the relevant bits in +`amdgpu_dm_dmub_trace_mask`. + +Currently, we support the tracing of the following groups: + +Trace Groups +------------ + +.. csv-table:: + :header-rows: 1 + :widths: 1, 1 + :file: ./trace-groups-table.csv + +**Note: Not all ASICs support all of the listed trace groups** + +So, to enable just PSR tracing you can use the following command:: + + # echo 0x8020 > /sys/kernel/debug/dri/0/amdgpu_dm_dmub_trace_mask + +Then, you need to enable logging trace events to the buffer, which you can do +using the following:: + + # echo 1 > /sys/kernel/debug/dri/0/amdgpu_dm_dmcub_trace_event_en + +Lastly, after you are able to reproduce the issue you are trying to debug, +you can disable tracing and read the trace log by using the following:: + + # echo 0 > /sys/kernel/debug/dri/0/amdgpu_dm_dmcub_trace_event_en + # cat /sys/kernel/debug/dri/0/amdgpu_dm_dmub_tracebuffer + +So, when reporting bugs related to features such as PSR and ABM, consider +enabling the relevant bits in the mask before reproducing the issue and +attach the log that you obtain from the trace buffer in any bug reports that you +create. diff --git a/Documentation/gpu/amdgpu/display/trace-groups-table.csv b/Documentation/gpu/amdgpu/display/trace-groups-table.csv new file mode 100644 index 00000000000000..3f6a50d1d8831d --- /dev/null +++ b/Documentation/gpu/amdgpu/display/trace-groups-table.csv @@ -0,0 +1,29 @@ +Name, Mask Value +INFO, 0x1 +IRQ SVC, 0x2 +VBIOS, 0x4 +REGISTER, 0x8 +PHY DBG, 0x10 +PSR, 0x20 +AUX, 0x40 +SMU, 0x80 +MALL, 0x100 +ABM, 0x200 +ALPM, 0x400 +TIMER, 0x800 +HW LOCK MGR, 0x1000 +INBOX1, 0x2000 +PHY SEQ, 0x4000 +PSR STATE, 0x8000 +ZSTATE, 0x10000 +TRANSMITTER CTL, 0x20000 +PANEL CNTL, 0x40000 +FAMS, 0x80000 +DPIA, 0x100000 +SUBVP, 0x200000 +INBOX0, 0x400000 +SDP, 0x4000000 +REPLAY, 0x8000000 +REPLAY RESIDENCY, 0x20000000 +CURSOR INFO, 0x80000000 +IPS, 0x100000000 diff --git a/Documentation/gpu/automated_testing.rst b/Documentation/gpu/automated_testing.rst index 240e29d5ba68ba..2d5a28866afe7e 100644 --- a/Documentation/gpu/automated_testing.rst +++ b/Documentation/gpu/automated_testing.rst @@ -69,14 +69,15 @@ the result. They will still be run. Each new flake entry must be associated with a link to the email reporting the bug to the author of the affected driver, the board name or Device Tree name of -the board, the first kernel version affected, and an approximation of the -failure rate. +the board, the first kernel version affected, the IGT version used for tests, +and an approximation of the failure rate. They should be provided under the following format:: # Bug Report: $LORE_OR_PATCHWORK_URL # Board Name: broken-board.dtb - # Version: 6.6-rc1 + # Linux Version: 6.6-rc1 + # IGT Version: 1.28-gd2af13d9f # Failure Rate: 100 flaky-test diff --git a/Documentation/gpu/driver-uapi.rst b/Documentation/gpu/driver-uapi.rst index c08bcbb95fb30d..e5070a0e95ab97 100644 --- a/Documentation/gpu/driver-uapi.rst +++ b/Documentation/gpu/driver-uapi.rst @@ -17,3 +17,8 @@ VM_BIND / EXEC uAPI :doc: Overview .. kernel-doc:: include/uapi/drm/nouveau_drm.h + +drm/xe uAPI +=========== + +.. kernel-doc:: include/uapi/drm/xe_drm.h diff --git a/Documentation/gpu/drivers.rst b/Documentation/gpu/drivers.rst index 45a12e552091b9..b899cbc5c2b488 100644 --- a/Documentation/gpu/drivers.rst +++ b/Documentation/gpu/drivers.rst @@ -3,9 +3,11 @@ GPU Driver Documentation ======================== .. toctree:: + :maxdepth: 3 amdgpu/index i915 + imagination/index mcde meson pl111 @@ -16,6 +18,7 @@ GPU Driver Documentation vkms bridge/dw-hdmi xen-front + xe/index afbc komeda-kms panfrost diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst index b748b8ae70b2a9..59cfe8a7a8bace 100644 --- a/Documentation/gpu/drm-kms-helpers.rst +++ b/Documentation/gpu/drm-kms-helpers.rst @@ -363,6 +363,12 @@ EDID Helper Functions Reference .. kernel-doc:: drivers/gpu/drm/drm_edid.c :export: +.. kernel-doc:: include/drm/drm_eld.h + :internal: + +.. kernel-doc:: drivers/gpu/drm/drm_eld.c + :export: + SCDC Helper Functions Reference =============================== diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 270d320407c7c0..13d3627d8bc083 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -548,6 +548,8 @@ Plane Composition Properties .. kernel-doc:: drivers/gpu/drm/drm_blend.c :doc: overview +.. _damage_tracking_properties: + Damage Tracking Properties -------------------------- @@ -579,6 +581,12 @@ Variable Refresh Properties .. kernel-doc:: drivers/gpu/drm/drm_connector.c :doc: Variable refresh properties +Cursor Hotspot Properties +--------------------------- + +.. kernel-doc:: drivers/gpu/drm/drm_plane.c + :doc: hotspot properties + Existing KMS Properties ----------------------- diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst index 602010cb6894c3..d55751cad67cf9 100644 --- a/Documentation/gpu/drm-mm.rst +++ b/Documentation/gpu/drm-mm.rst @@ -466,6 +466,8 @@ DRM MM Range Allocator Function References .. kernel-doc:: drivers/gpu/drm/drm_mm.c :export: +.. _drm_gpuvm: + DRM GPUVM ========= @@ -481,6 +483,8 @@ Split and Merge .. kernel-doc:: drivers/gpu/drm/drm_gpuvm.c :doc: Split and Merge +.. _drm_gpuvm_locking: + Locking ------- @@ -552,6 +556,12 @@ Overview .. kernel-doc:: drivers/gpu/drm/scheduler/sched_main.c :doc: Overview +Flow Control +------------ + +.. kernel-doc:: drivers/gpu/drm/scheduler/sched_main.c + :doc: Flow Control + Scheduler Function References ----------------------------- diff --git a/Documentation/gpu/drm-vm-bind-locking.rst b/Documentation/gpu/drm-vm-bind-locking.rst new file mode 100644 index 00000000000000..a345aa513d12b3 --- /dev/null +++ b/Documentation/gpu/drm-vm-bind-locking.rst @@ -0,0 +1,582 @@ +.. SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +=============== +VM_BIND locking +=============== + +This document attempts to describe what's needed to get VM_BIND locking right, +including the userptr mmu_notifier locking. It also discusses some +optimizations to get rid of the looping through of all userptr mappings and +external / shared object mappings that is needed in the simplest +implementation. In addition, there is a section describing the VM_BIND locking +required for implementing recoverable pagefaults. + +The DRM GPUVM set of helpers +============================ + +There is a set of helpers for drivers implementing VM_BIND, and this +set of helpers implements much, but not all of the locking described +in this document. In particular, it is currently lacking a userptr +implementation. This document does not intend to describe the DRM GPUVM +implementation in detail, but it is covered in :ref:`its own +documentation `. It is highly recommended for any driver +implementing VM_BIND to use the DRM GPUVM helpers and to extend it if +common functionality is missing. + +Nomenclature +============ + +* ``gpu_vm``: Abstraction of a virtual GPU address space with + meta-data. Typically one per client (DRM file-private), or one per + execution context. +* ``gpu_vma``: Abstraction of a GPU address range within a gpu_vm with + associated meta-data. The backing storage of a gpu_vma can either be + a GEM object or anonymous or page-cache pages mapped also into the CPU + address space for the process. +* ``gpu_vm_bo``: Abstracts the association of a GEM object and + a VM. The GEM object maintains a list of gpu_vm_bos, where each gpu_vm_bo + maintains a list of gpu_vmas. +* ``userptr gpu_vma or just userptr``: A gpu_vma, whose backing store + is anonymous or page-cache pages as described above. +* ``revalidating``: Revalidating a gpu_vma means making the latest version + of the backing store resident and making sure the gpu_vma's + page-table entries point to that backing store. +* ``dma_fence``: A struct dma_fence that is similar to a struct completion + and which tracks GPU activity. When the GPU activity is finished, + the dma_fence signals. Please refer to the ``DMA Fences`` section of + the :doc:`dma-buf doc `. +* ``dma_resv``: A struct dma_resv (a.k.a reservation object) that is used + to track GPU activity in the form of multiple dma_fences on a + gpu_vm or a GEM object. The dma_resv contains an array / list + of dma_fences and a lock that needs to be held when adding + additional dma_fences to the dma_resv. The lock is of a type that + allows deadlock-safe locking of multiple dma_resvs in arbitrary + order. Please refer to the ``Reservation Objects`` section of the + :doc:`dma-buf doc `. +* ``exec function``: An exec function is a function that revalidates all + affected gpu_vmas, submits a GPU command batch and registers the + dma_fence representing the GPU command's activity with all affected + dma_resvs. For completeness, although not covered by this document, + it's worth mentioning that an exec function may also be the + revalidation worker that is used by some drivers in compute / + long-running mode. +* ``local object``: A GEM object which is only mapped within a + single VM. Local GEM objects share the gpu_vm's dma_resv. +* ``external object``: a.k.a shared object: A GEM object which may be shared + by multiple gpu_vms and whose backing storage may be shared with + other drivers. + +Locks and locking order +======================= + +One of the benefits of VM_BIND is that local GEM objects share the gpu_vm's +dma_resv object and hence the dma_resv lock. So, even with a huge +number of local GEM objects, only one lock is needed to make the exec +sequence atomic. + +The following locks and locking orders are used: + +* The ``gpu_vm->lock`` (optionally an rwsem). Protects the gpu_vm's + data structure keeping track of gpu_vmas. It can also protect the + gpu_vm's list of userptr gpu_vmas. With a CPU mm analogy this would + correspond to the mmap_lock. An rwsem allows several readers to walk + the VM tree concurrently, but the benefit of that concurrency most + likely varies from driver to driver. +* The ``userptr_seqlock``. This lock is taken in read mode for each + userptr gpu_vma on the gpu_vm's userptr list, and in write mode during mmu + notifier invalidation. This is not a real seqlock but described in + ``mm/mmu_notifier.c`` as a "Collision-retry read-side/write-side + 'lock' a lot like a seqcount. However this allows multiple + write-sides to hold it at once...". The read side critical section + is enclosed by ``mmu_interval_read_begin() / + mmu_interval_read_retry()`` with ``mmu_interval_read_begin()`` + sleeping if the write side is held. + The write side is held by the core mm while calling mmu interval + invalidation notifiers. +* The ``gpu_vm->resv`` lock. Protects the gpu_vm's list of gpu_vmas needing + rebinding, as well as the residency state of all the gpu_vm's local + GEM objects. + Furthermore, it typically protects the gpu_vm's list of evicted and + external GEM objects. +* The ``gpu_vm->userptr_notifier_lock``. This is an rwsem that is + taken in read mode during exec and write mode during a mmu notifier + invalidation. The userptr notifier lock is per gpu_vm. +* The ``gem_object->gpuva_lock`` This lock protects the GEM object's + list of gpu_vm_bos. This is usually the same lock as the GEM + object's dma_resv, but some drivers protects this list differently, + see below. +* The ``gpu_vm list spinlocks``. With some implementations they are needed + to be able to update the gpu_vm evicted- and external object + list. For those implementations, the spinlocks are grabbed when the + lists are manipulated. However, to avoid locking order violations + with the dma_resv locks, a special scheme is needed when iterating + over the lists. + +.. _gpu_vma lifetime: + +Protection and lifetime of gpu_vm_bos and gpu_vmas +================================================== + +The GEM object's list of gpu_vm_bos, and the gpu_vm_bo's list of gpu_vmas +is protected by the ``gem_object->gpuva_lock``, which is typically the +same as the GEM object's dma_resv, but if the driver +needs to access these lists from within a dma_fence signalling +critical section, it can instead choose to protect it with a +separate lock, which can be locked from within the dma_fence signalling +critical section. Such drivers then need to pay additional attention +to what locks need to be taken from within the loop when iterating +over the gpu_vm_bo and gpu_vma lists to avoid locking-order violations. + +The DRM GPUVM set of helpers provide lockdep asserts that this lock is +held in relevant situations and also provides a means of making itself +aware of which lock is actually used: :c:func:`drm_gem_gpuva_set_lock`. + +Each gpu_vm_bo holds a reference counted pointer to the underlying GEM +object, and each gpu_vma holds a reference counted pointer to the +gpu_vm_bo. When iterating over the GEM object's list of gpu_vm_bos and +over the gpu_vm_bo's list of gpu_vmas, the ``gem_object->gpuva_lock`` must +not be dropped, otherwise, gpu_vmas attached to a gpu_vm_bo may +disappear without notice since those are not reference-counted. A +driver may implement its own scheme to allow this at the expense of +additional complexity, but this is outside the scope of this document. + +In the DRM GPUVM implementation, each gpu_vm_bo and each gpu_vma +holds a reference count on the gpu_vm itself. Due to this, and to avoid circular +reference counting, cleanup of the gpu_vm's gpu_vmas must not be done from the +gpu_vm's destructor. Drivers typically implements a gpu_vm close +function for this cleanup. The gpu_vm close function will abort gpu +execution using this VM, unmap all gpu_vmas and release page-table memory. + +Revalidation and eviction of local objects +========================================== + +Note that in all the code examples given below we use simplified +pseudo-code. In particular, the dma_resv deadlock avoidance algorithm +as well as reserving memory for dma_resv fences is left out. + +Revalidation +____________ +With VM_BIND, all local objects need to be resident when the gpu is +executing using the gpu_vm, and the objects need to have valid +gpu_vmas set up pointing to them. Typically, each gpu command buffer +submission is therefore preceded with a re-validation section: + +.. code-block:: C + + dma_resv_lock(gpu_vm->resv); + + // Validation section starts here. + for_each_gpu_vm_bo_on_evict_list(&gpu_vm->evict_list, &gpu_vm_bo) { + validate_gem_bo(&gpu_vm_bo->gem_bo); + + // The following list iteration needs the Gem object's + // dma_resv to be held (it protects the gpu_vm_bo's list of + // gpu_vmas, but since local gem objects share the gpu_vm's + // dma_resv, it is already held at this point. + for_each_gpu_vma_of_gpu_vm_bo(&gpu_vm_bo, &gpu_vma) + move_gpu_vma_to_rebind_list(&gpu_vma, &gpu_vm->rebind_list); + } + + for_each_gpu_vma_on_rebind_list(&gpu vm->rebind_list, &gpu_vma) { + rebind_gpu_vma(&gpu_vma); + remove_gpu_vma_from_rebind_list(&gpu_vma); + } + // Validation section ends here, and job submission starts. + + add_dependencies(&gpu_job, &gpu_vm->resv); + job_dma_fence = gpu_submit(&gpu_job)); + + add_dma_fence(job_dma_fence, &gpu_vm->resv); + dma_resv_unlock(gpu_vm->resv); + +The reason for having a separate gpu_vm rebind list is that there +might be userptr gpu_vmas that are not mapping a buffer object that +also need rebinding. + +Eviction +________ + +Eviction of one of these local objects will then look similar to the +following: + +.. code-block:: C + + obj = get_object_from_lru(); + + dma_resv_lock(obj->resv); + for_each_gpu_vm_bo_of_obj(obj, &gpu_vm_bo); + add_gpu_vm_bo_to_evict_list(&gpu_vm_bo, &gpu_vm->evict_list); + + add_dependencies(&eviction_job, &obj->resv); + job_dma_fence = gpu_submit(&eviction_job); + add_dma_fence(&obj->resv, job_dma_fence); + + dma_resv_unlock(&obj->resv); + put_object(obj); + +Note that since the object is local to the gpu_vm, it will share the gpu_vm's +dma_resv lock such that ``obj->resv == gpu_vm->resv``. +The gpu_vm_bos marked for eviction are put on the gpu_vm's evict list, +which is protected by ``gpu_vm->resv``. During eviction all local +objects have their dma_resv locked and, due to the above equality, also +the gpu_vm's dma_resv protecting the gpu_vm's evict list is locked. + +With VM_BIND, gpu_vmas don't need to be unbound before eviction, +since the driver must ensure that the eviction blit or copy will wait +for GPU idle or depend on all previous GPU activity. Furthermore, any +subsequent attempt by the GPU to access freed memory through the +gpu_vma will be preceded by a new exec function, with a revalidation +section which will make sure all gpu_vmas are rebound. The eviction +code holding the object's dma_resv while revalidating will ensure a +new exec function may not race with the eviction. + +A driver can be implemented in such a way that, on each exec function, +only a subset of vmas are selected for rebind. In this case, all vmas that are +*not* selected for rebind must be unbound before the exec +function workload is submitted. + +Locking with external buffer objects +==================================== + +Since external buffer objects may be shared by multiple gpu_vm's they +can't share their reservation object with a single gpu_vm. Instead +they need to have a reservation object of their own. The external +objects bound to a gpu_vm using one or many gpu_vmas are therefore put on a +per-gpu_vm list which is protected by the gpu_vm's dma_resv lock or +one of the :ref:`gpu_vm list spinlocks `. Once +the gpu_vm's reservation object is locked, it is safe to traverse the +external object list and lock the dma_resvs of all external +objects. However, if instead a list spinlock is used, a more elaborate +iteration scheme needs to be used. + +At eviction time, the gpu_vm_bos of *all* the gpu_vms an external +object is bound to need to be put on their gpu_vm's evict list. +However, when evicting an external object, the dma_resvs of the +gpu_vms the object is bound to are typically not held. Only +the object's private dma_resv can be guaranteed to be held. If there +is a ww_acquire context at hand at eviction time we could grab those +dma_resvs but that could cause expensive ww_mutex rollbacks. A simple +option is to just mark the gpu_vm_bos of the evicted gem object with +an ``evicted`` bool that is inspected before the next time the +corresponding gpu_vm evicted list needs to be traversed. For example, when +traversing the list of external objects and locking them. At that time, +both the gpu_vm's dma_resv and the object's dma_resv is held, and the +gpu_vm_bo marked evicted, can then be added to the gpu_vm's list of +evicted gpu_vm_bos. The ``evicted`` bool is formally protected by the +object's dma_resv. + +The exec function becomes + +.. code-block:: C + + dma_resv_lock(gpu_vm->resv); + + // External object list is protected by the gpu_vm->resv lock. + for_each_gpu_vm_bo_on_extobj_list(gpu_vm, &gpu_vm_bo) { + dma_resv_lock(gpu_vm_bo.gem_obj->resv); + if (gpu_vm_bo_marked_evicted(&gpu_vm_bo)) + add_gpu_vm_bo_to_evict_list(&gpu_vm_bo, &gpu_vm->evict_list); + } + + for_each_gpu_vm_bo_on_evict_list(&gpu_vm->evict_list, &gpu_vm_bo) { + validate_gem_bo(&gpu_vm_bo->gem_bo); + + for_each_gpu_vma_of_gpu_vm_bo(&gpu_vm_bo, &gpu_vma) + move_gpu_vma_to_rebind_list(&gpu_vma, &gpu_vm->rebind_list); + } + + for_each_gpu_vma_on_rebind_list(&gpu vm->rebind_list, &gpu_vma) { + rebind_gpu_vma(&gpu_vma); + remove_gpu_vma_from_rebind_list(&gpu_vma); + } + + add_dependencies(&gpu_job, &gpu_vm->resv); + job_dma_fence = gpu_submit(&gpu_job)); + + add_dma_fence(job_dma_fence, &gpu_vm->resv); + for_each_external_obj(gpu_vm, &obj) + add_dma_fence(job_dma_fence, &obj->resv); + dma_resv_unlock_all_resv_locks(); + +And the corresponding shared-object aware eviction would look like: + +.. code-block:: C + + obj = get_object_from_lru(); + + dma_resv_lock(obj->resv); + for_each_gpu_vm_bo_of_obj(obj, &gpu_vm_bo) + if (object_is_vm_local(obj)) + add_gpu_vm_bo_to_evict_list(&gpu_vm_bo, &gpu_vm->evict_list); + else + mark_gpu_vm_bo_evicted(&gpu_vm_bo); + + add_dependencies(&eviction_job, &obj->resv); + job_dma_fence = gpu_submit(&eviction_job); + add_dma_fence(&obj->resv, job_dma_fence); + + dma_resv_unlock(&obj->resv); + put_object(obj); + +.. _Spinlock iteration: + +Accessing the gpu_vm's lists without the dma_resv lock held +=========================================================== + +Some drivers will hold the gpu_vm's dma_resv lock when accessing the +gpu_vm's evict list and external objects lists. However, there are +drivers that need to access these lists without the dma_resv lock +held, for example due to asynchronous state updates from within the +dma_fence signalling critical path. In such cases, a spinlock can be +used to protect manipulation of the lists. However, since higher level +sleeping locks need to be taken for each list item while iterating +over the lists, the items already iterated over need to be +temporarily moved to a private list and the spinlock released +while processing each item: + +.. code block:: C + + struct list_head still_in_list; + + INIT_LIST_HEAD(&still_in_list); + + spin_lock(&gpu_vm->list_lock); + do { + struct list_head *entry = list_first_entry_or_null(&gpu_vm->list, head); + + if (!entry) + break; + + list_move_tail(&entry->head, &still_in_list); + list_entry_get_unless_zero(entry); + spin_unlock(&gpu_vm->list_lock); + + process(entry); + + spin_lock(&gpu_vm->list_lock); + list_entry_put(entry); + } while (true); + + list_splice_tail(&still_in_list, &gpu_vm->list); + spin_unlock(&gpu_vm->list_lock); + +Due to the additional locking and atomic operations, drivers that *can* +avoid accessing the gpu_vm's list outside of the dma_resv lock +might want to avoid also this iteration scheme. Particularly, if the +driver anticipates a large number of list items. For lists where the +anticipated number of list items is small, where list iteration doesn't +happen very often or if there is a significant additional cost +associated with each iteration, the atomic operation overhead +associated with this type of iteration is, most likely, negligible. Note that +if this scheme is used, it is necessary to make sure this list +iteration is protected by an outer level lock or semaphore, since list +items are temporarily pulled off the list while iterating, and it is +also worth mentioning that the local list ``still_in_list`` should +also be considered protected by the ``gpu_vm->list_lock``, and it is +thus possible that items can be removed also from the local list +concurrently with list iteration. + +Please refer to the :ref:`DRM GPUVM locking section +` and its internal +:c:func:`get_next_vm_bo_from_list` function. + + +userptr gpu_vmas +================ + +A userptr gpu_vma is a gpu_vma that, instead of mapping a buffer object to a +GPU virtual address range, directly maps a CPU mm range of anonymous- +or file page-cache pages. +A very simple approach would be to just pin the pages using +pin_user_pages() at bind time and unpin them at unbind time, but this +creates a Denial-Of-Service vector since a single user-space process +would be able to pin down all of system memory, which is not +desirable. (For special use-cases and assuming proper accounting pinning might +still be a desirable feature, though). What we need to do in the +general case is to obtain a reference to the desired pages, make sure +we are notified using a MMU notifier just before the CPU mm unmaps the +pages, dirty them if they are not mapped read-only to the GPU, and +then drop the reference. +When we are notified by the MMU notifier that CPU mm is about to drop the +pages, we need to stop GPU access to the pages by waiting for VM idle +in the MMU notifier and make sure that before the next time the GPU +tries to access whatever is now present in the CPU mm range, we unmap +the old pages from the GPU page tables and repeat the process of +obtaining new page references. (See the :ref:`notifier example +` below). Note that when the core mm decides to +laundry pages, we get such an unmap MMU notification and can mark the +pages dirty again before the next GPU access. We also get similar MMU +notifications for NUMA accounting which the GPU driver doesn't really +need to care about, but so far it has proven difficult to exclude +certain notifications. + +Using a MMU notifier for device DMA (and other methods) is described in +:ref:`the pin_user_pages() documentation `. + +Now, the method of obtaining struct page references using +get_user_pages() unfortunately can't be used under a dma_resv lock +since that would violate the locking order of the dma_resv lock vs the +mmap_lock that is grabbed when resolving a CPU pagefault. This means +the gpu_vm's list of userptr gpu_vmas needs to be protected by an +outer lock, which in our example below is the ``gpu_vm->lock``. + +The MMU interval seqlock for a userptr gpu_vma is used in the following +way: + +.. code-block:: C + + // Exclusive locking mode here is strictly needed only if there are + // invalidated userptr gpu_vmas present, to avoid concurrent userptr + // revalidations of the same userptr gpu_vma. + down_write(&gpu_vm->lock); + retry: + + // Note: mmu_interval_read_begin() blocks until there is no + // invalidation notifier running anymore. + seq = mmu_interval_read_begin(&gpu_vma->userptr_interval); + if (seq != gpu_vma->saved_seq) { + obtain_new_page_pointers(&gpu_vma); + dma_resv_lock(&gpu_vm->resv); + add_gpu_vma_to_revalidate_list(&gpu_vma, &gpu_vm); + dma_resv_unlock(&gpu_vm->resv); + gpu_vma->saved_seq = seq; + } + + // The usual revalidation goes here. + + // Final userptr sequence validation may not happen before the + // submission dma_fence is added to the gpu_vm's resv, from the POW + // of the MMU invalidation notifier. Hence the + // userptr_notifier_lock that will make them appear atomic. + + add_dependencies(&gpu_job, &gpu_vm->resv); + down_read(&gpu_vm->userptr_notifier_lock); + if (mmu_interval_read_retry(&gpu_vma->userptr_interval, gpu_vma->saved_seq)) { + up_read(&gpu_vm->userptr_notifier_lock); + goto retry; + } + + job_dma_fence = gpu_submit(&gpu_job)); + + add_dma_fence(job_dma_fence, &gpu_vm->resv); + + for_each_external_obj(gpu_vm, &obj) + add_dma_fence(job_dma_fence, &obj->resv); + + dma_resv_unlock_all_resv_locks(); + up_read(&gpu_vm->userptr_notifier_lock); + up_write(&gpu_vm->lock); + +The code between ``mmu_interval_read_begin()`` and the +``mmu_interval_read_retry()`` marks the read side critical section of +what we call the ``userptr_seqlock``. In reality, the gpu_vm's userptr +gpu_vma list is looped through, and the check is done for *all* of its +userptr gpu_vmas, although we only show a single one here. + +The userptr gpu_vma MMU invalidation notifier might be called from +reclaim context and, again, to avoid locking order violations, we can't +take any dma_resv lock nor the gpu_vm->lock from within it. + +.. _Invalidation example: +.. code-block:: C + + bool gpu_vma_userptr_invalidate(userptr_interval, cur_seq) + { + // Make sure the exec function either sees the new sequence + // and backs off or we wait for the dma-fence: + + down_write(&gpu_vm->userptr_notifier_lock); + mmu_interval_set_seq(userptr_interval, cur_seq); + up_write(&gpu_vm->userptr_notifier_lock); + + // At this point, the exec function can't succeed in + // submitting a new job, because cur_seq is an invalid + // sequence number and will always cause a retry. When all + // invalidation callbacks, the mmu notifier core will flip + // the sequence number to a valid one. However we need to + // stop gpu access to the old pages here. + + dma_resv_wait_timeout(&gpu_vm->resv, DMA_RESV_USAGE_BOOKKEEP, + false, MAX_SCHEDULE_TIMEOUT); + return true; + } + +When this invalidation notifier returns, the GPU can no longer be +accessing the old pages of the userptr gpu_vma and needs to redo the +page-binding before a new GPU submission can succeed. + +Efficient userptr gpu_vma exec_function iteration +_________________________________________________ + +If the gpu_vm's list of userptr gpu_vmas becomes large, it's +inefficient to iterate through the complete lists of userptrs on each +exec function to check whether each userptr gpu_vma's saved +sequence number is stale. A solution to this is to put all +*invalidated* userptr gpu_vmas on a separate gpu_vm list and +only check the gpu_vmas present on this list on each exec +function. This list will then lend itself very-well to the spinlock +locking scheme that is +:ref:`described in the spinlock iteration section `, since +in the mmu notifier, where we add the invalidated gpu_vmas to the +list, it's not possible to take any outer locks like the +``gpu_vm->lock`` or the ``gpu_vm->resv`` lock. Note that the +``gpu_vm->lock`` still needs to be taken while iterating to ensure the list is +complete, as also mentioned in that section. + +If using an invalidated userptr list like this, the retry check in the +exec function trivially becomes a check for invalidated list empty. + +Locking at bind and unbind time +=============================== + +At bind time, assuming a GEM object backed gpu_vma, each +gpu_vma needs to be associated with a gpu_vm_bo and that +gpu_vm_bo in turn needs to be added to the GEM object's +gpu_vm_bo list, and possibly to the gpu_vm's external object +list. This is referred to as *linking* the gpu_vma, and typically +requires that the ``gpu_vm->lock`` and the ``gem_object->gpuva_lock`` +are held. When unlinking a gpu_vma the same locks should be held, +and that ensures that when iterating over ``gpu_vmas`, either under +the ``gpu_vm->resv`` or the GEM object's dma_resv, that the gpu_vmas +stay alive as long as the lock under which we iterate is not released. For +userptr gpu_vmas it's similarly required that during vma destroy, the +outer ``gpu_vm->lock`` is held, since otherwise when iterating over +the invalidated userptr list as described in the previous section, +there is nothing keeping those userptr gpu_vmas alive. + +Locking for recoverable page-fault page-table updates +===================================================== + +There are two important things we need to ensure with locking for +recoverable page-faults: + +* At the time we return pages back to the system / allocator for + reuse, there should be no remaining GPU mappings and any GPU TLB + must have been flushed. +* The unmapping and mapping of a gpu_vma must not race. + +Since the unmapping (or zapping) of GPU ptes is typically taking place +where it is hard or even impossible to take any outer level locks we +must either introduce a new lock that is held at both mapping and +unmapping time, or look at the locks we do hold at unmapping time and +make sure that they are held also at mapping time. For userptr +gpu_vmas, the ``userptr_seqlock`` is held in write mode in the mmu +invalidation notifier where zapping happens. Hence, if the +``userptr_seqlock`` as well as the ``gpu_vm->userptr_notifier_lock`` +is held in read mode during mapping, it will not race with the +zapping. For GEM object backed gpu_vmas, zapping will take place under +the GEM object's dma_resv and ensuring that the dma_resv is held also +when populating the page-tables for any gpu_vma pointing to the GEM +object, will similarly ensure we are race-free. + +If any part of the mapping is performed asynchronously +under a dma-fence with these locks released, the zapping will need to +wait for that dma-fence to signal under the relevant lock before +starting to modify the page-table. + +Since modifying the +page-table structure in a way that frees up page-table memory +might also require outer level locks, the zapping of GPU ptes +typically focuses only on zeroing page-table or page-directory entries +and flushing TLB, whereas freeing of page-table memory is deferred to +unbind or rebind time. diff --git a/Documentation/gpu/imagination/index.rst b/Documentation/gpu/imagination/index.rst new file mode 100644 index 00000000000000..0c1e247cea41eb --- /dev/null +++ b/Documentation/gpu/imagination/index.rst @@ -0,0 +1,13 @@ +======================================= +drm/imagination PowerVR Graphics Driver +======================================= + +.. kernel-doc:: drivers/gpu/drm/imagination/pvr_drv.c + :doc: PowerVR (Series 6 and later) and IMG Graphics Driver + +Contents +======== +.. toctree:: + :maxdepth: 2 + + uapi diff --git a/Documentation/gpu/imagination/uapi.rst b/Documentation/gpu/imagination/uapi.rst new file mode 100644 index 00000000000000..7502413d0a939b --- /dev/null +++ b/Documentation/gpu/imagination/uapi.rst @@ -0,0 +1,171 @@ +==== +UAPI +==== +The sources associated with this section can be found in ``pvr_drm.h``. + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: PowerVR UAPI + +OBJECT ARRAYS +============= +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_obj_array + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: DRM_PVR_OBJ_ARRAY + +IOCTLS +====== +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: PowerVR IOCTL interface + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: PVR_IOCTL + +DEV_QUERY +--------- +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: PowerVR IOCTL DEV_QUERY interface + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_dev_query + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_ioctl_dev_query_args + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_dev_query_gpu_info + drm_pvr_dev_query_runtime_info + drm_pvr_dev_query_hwrt_info + drm_pvr_dev_query_quirks + drm_pvr_dev_query_enhancements + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_heap_id + drm_pvr_heap + drm_pvr_dev_query_heap_info + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_static_data_area_usage + drm_pvr_static_data_area + drm_pvr_dev_query_static_data_areas + +CREATE_BO +--------- +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: PowerVR IOCTL CREATE_BO interface + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_ioctl_create_bo_args + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: Flags for CREATE_BO + +GET_BO_MMAP_OFFSET +------------------ +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: PowerVR IOCTL GET_BO_MMAP_OFFSET interface + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_ioctl_get_bo_mmap_offset_args + +CREATE_VM_CONTEXT and DESTROY_VM_CONTEXT +---------------------------------------- +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: PowerVR IOCTL CREATE_VM_CONTEXT and DESTROY_VM_CONTEXT interfaces + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_ioctl_create_vm_context_args + drm_pvr_ioctl_destroy_vm_context_args + +VM_MAP and VM_UNMAP +------------------- +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: PowerVR IOCTL VM_MAP and VM_UNMAP interfaces + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_ioctl_vm_map_args + drm_pvr_ioctl_vm_unmap_args + +CREATE_CONTEXT and DESTROY_CONTEXT +---------------------------------- +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: PowerVR IOCTL CREATE_CONTEXT and DESTROY_CONTEXT interfaces + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_ioctl_create_context_args + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_ctx_priority + drm_pvr_ctx_type + drm_pvr_static_render_context_state + drm_pvr_static_render_context_state_format + drm_pvr_reset_framework + drm_pvr_reset_framework_format + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_ioctl_destroy_context_args + +CREATE_FREE_LIST and DESTROY_FREE_LIST +-------------------------------------- +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: PowerVR IOCTL CREATE_FREE_LIST and DESTROY_FREE_LIST interfaces + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_ioctl_create_free_list_args + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_ioctl_destroy_free_list_args + +CREATE_HWRT_DATASET and DESTROY_HWRT_DATASET +-------------------------------------------- +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: PowerVR IOCTL CREATE_HWRT_DATASET and DESTROY_HWRT_DATASET interfaces + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_ioctl_create_hwrt_dataset_args + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_create_hwrt_geom_data_args + drm_pvr_create_hwrt_rt_data_args + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_ioctl_destroy_hwrt_dataset_args + +SUBMIT_JOBS +----------- +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: PowerVR IOCTL SUBMIT_JOBS interface + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: Flags for the drm_pvr_sync_op object. + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_ioctl_submit_jobs_args + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: Flags for SUBMIT_JOB ioctl geometry command. + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: Flags for SUBMIT_JOB ioctl fragment command. + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: Flags for SUBMIT_JOB ioctl compute command. + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :doc: Flags for SUBMIT_JOB ioctl transfer command. + +.. kernel-doc:: include/uapi/drm/pvr_drm.h + :identifiers: drm_pvr_sync_op + drm_pvr_job_type + drm_pvr_hwrt_data_ref + drm_pvr_job + +Internal notes +============== +.. kernel-doc:: drivers/gpu/drm/imagination/pvr_device.h + :doc: IOCTL validation helpers + +.. kernel-doc:: drivers/gpu/drm/imagination/pvr_device.h + :identifiers: PVR_STATIC_ASSERT_64BIT_ALIGNED PVR_IOCTL_UNION_PADDING_CHECK + pvr_ioctl_union_padding_check diff --git a/Documentation/gpu/implementation_guidelines.rst b/Documentation/gpu/implementation_guidelines.rst index 138e637dcc6b24..dbccfa72f1c9d6 100644 --- a/Documentation/gpu/implementation_guidelines.rst +++ b/Documentation/gpu/implementation_guidelines.rst @@ -7,3 +7,4 @@ Misc DRM driver uAPI- and feature implementation guidelines .. toctree:: drm-vm-bind-async + drm-vm-bind-locking diff --git a/Documentation/gpu/rfc/xe.rst b/Documentation/gpu/rfc/xe.rst index c29113a0ac3011..97cf87578f973b 100644 --- a/Documentation/gpu/rfc/xe.rst +++ b/Documentation/gpu/rfc/xe.rst @@ -70,35 +70,42 @@ When the time comes for Xe, the protection will be lifted on Xe and kept in i915 Xe – Pre-Merge Goals - Work-in-Progress ======================================= -Drm_scheduler -------------- -Xe primarily uses Firmware based scheduling (GuC FW). However, it will use -drm_scheduler as the scheduler ‘frontend’ for userspace submission in order to -resolve syncobj and dma-buf implicit sync dependencies. However, drm_scheduler is -not yet prepared to handle the 1-to-1 relationship between drm_gpu_scheduler and -drm_sched_entity. +Display integration with i915 +----------------------------- +In order to share the display code with the i915 driver so that there is maximum +reuse, the i915/display/ code is built twice, once for i915.ko and then for +xe.ko. Currently, the i915/display code in Xe tree is polluted with many 'ifdefs' +depending on the build target. The goal is to refactor both Xe and i915/display +code simultaneously in order to get a clean result before they land upstream, so +that display can already be part of the initial pull request towards drm-next. -Deeper changes to drm_scheduler should *not* be required to get Xe accepted, but -some consensus needs to be reached between Xe and other community drivers that -could also benefit from this work, for coupling FW based/assisted submission such -as the ARM’s new Mali GPU driver, and others. +However, display code should not gate the acceptance of Xe in upstream. Xe +patches will be refactored in a way that display code can be removed, if needed, +from the first pull request of Xe towards drm-next. The expectation is that when +both drivers are part of the drm-tip, the introduction of cleaner patches will be +easier and speed up. -As a key measurable result, the patch series introducing Xe itself shall not -depend on any other patch touching drm_scheduler itself that was not yet merged -through drm-misc. This, by itself, already includes the reach of an agreement for -uniform 1 to 1 relationship implementation / usage across drivers. +Xe – uAPI high level overview +============================= -ASYNC VM_BIND -------------- -Although having a common DRM level IOCTL for VM_BIND is not a requirement to get -Xe merged, it is mandatory to have a consensus with other drivers and Mesa. -It needs to be clear how to handle async VM_BIND and interactions with userspace -memory fences. Ideally with helper support so people don't get it wrong in all -possible ways. +...Warning: To be done in follow up patches after/when/where the main consensus in various items are individually reached. -As a key measurable result, the benefits of ASYNC VM_BIND and a discussion of -various flavors, error handling and sample API suggestions are documented in -:doc:`The ASYNC VM_BIND document `. +Xe – Pre-Merge Goals - Completed +================================ + +Drm_exec +-------- +Helper to make dma_resv locking for a big number of buffers is getting removed in +the drm_exec series proposed in https://patchwork.freedesktop.org/patch/524376/ +If that happens, Xe needs to change and incorporate the changes in the driver. +The goal is to engage with the Community to understand if the best approach is to +move that to the drivers that are using it or if we should keep the helpers in +place waiting for Xe to get merged. + +This item ties into the GPUVA, VM_BIND, and even long-running compute support. + +As a key measurable result, we need to have a community consensus documented in +this document and the Xe driver prepared for the changes, if necessary. Userptr integration and vm_bind ------------------------------- @@ -123,10 +130,45 @@ Documentation should include: * O(1) complexity under VM_BIND. +The document is now included in the drm documentation :doc:`here `. + Some parts of userptr like mmu_notifiers should become GPUVA or DRM helpers when the second driver supporting VM_BIND+userptr appears. Details to be defined when the time comes. +The DRM GPUVM helpers do not yet include the userptr parts, but discussions +about implementing them are ongoing. + +ASYNC VM_BIND +------------- +Although having a common DRM level IOCTL for VM_BIND is not a requirement to get +Xe merged, it is mandatory to have a consensus with other drivers and Mesa. +It needs to be clear how to handle async VM_BIND and interactions with userspace +memory fences. Ideally with helper support so people don't get it wrong in all +possible ways. + +As a key measurable result, the benefits of ASYNC VM_BIND and a discussion of +various flavors, error handling and sample API suggestions are documented in +:doc:`The ASYNC VM_BIND document `. + +Drm_scheduler +------------- +Xe primarily uses Firmware based scheduling (GuC FW). However, it will use +drm_scheduler as the scheduler ‘frontend’ for userspace submission in order to +resolve syncobj and dma-buf implicit sync dependencies. However, drm_scheduler is +not yet prepared to handle the 1-to-1 relationship between drm_gpu_scheduler and +drm_sched_entity. + +Deeper changes to drm_scheduler should *not* be required to get Xe accepted, but +some consensus needs to be reached between Xe and other community drivers that +could also benefit from this work, for coupling FW based/assisted submission such +as the ARM’s new Mali GPU driver, and others. + +As a key measurable result, the patch series introducing Xe itself shall not +depend on any other patch touching drm_scheduler itself that was not yet merged +through drm-misc. This, by itself, already includes the reach of an agreement for +uniform 1 to 1 relationship implementation / usage across drivers. + Long running compute: minimal data structure/scaffolding -------------------------------------------------------- The generic scheduler code needs to include the handling of endless compute @@ -139,46 +181,6 @@ this minimal drm/scheduler work, if needed, merged to drm-misc in a way that any drm driver, including Xe, could re-use and add their own individual needs on top in a next stage. However, this should not block the initial merge. -This is a non-blocker item since the driver without the support for the long -running compute enabled is not a showstopper. - -Display integration with i915 ------------------------------ -In order to share the display code with the i915 driver so that there is maximum -reuse, the i915/display/ code is built twice, once for i915.ko and then for -xe.ko. Currently, the i915/display code in Xe tree is polluted with many 'ifdefs' -depending on the build target. The goal is to refactor both Xe and i915/display -code simultaneously in order to get a clean result before they land upstream, so -that display can already be part of the initial pull request towards drm-next. - -However, display code should not gate the acceptance of Xe in upstream. Xe -patches will be refactored in a way that display code can be removed, if needed, -from the first pull request of Xe towards drm-next. The expectation is that when -both drivers are part of the drm-tip, the introduction of cleaner patches will be -easier and speed up. - -Drm_exec --------- -Helper to make dma_resv locking for a big number of buffers is getting removed in -the drm_exec series proposed in https://patchwork.freedesktop.org/patch/524376/ -If that happens, Xe needs to change and incorporate the changes in the driver. -The goal is to engage with the Community to understand if the best approach is to -move that to the drivers that are using it or if we should keep the helpers in -place waiting for Xe to get merged. - -This item ties into the GPUVA, VM_BIND, and even long-running compute support. - -As a key measurable result, we need to have a community consensus documented in -this document and the Xe driver prepared for the changes, if necessary. - -Xe – uAPI high level overview -============================= - -...Warning: To be done in follow up patches after/when/where the main consensus in various items are individually reached. - -Xe – Pre-Merge Goals - Completed -================================ - Dev_coredump ------------ diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index 03fe5d1247be28..41a264bf84ce02 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -337,8 +337,8 @@ connector register/unregister fixes Level: Intermediate -Remove load/unload callbacks from all non-DRIVER_LEGACY drivers ---------------------------------------------------------------- +Remove load/unload callbacks +---------------------------- The load/unload callbacks in struct &drm_driver are very much midlayers, plus for historical reasons they get the ordering wrong (and we can't fix that) @@ -347,8 +347,7 @@ between setting up the &drm_driver structure and calling drm_dev_register(). - Rework drivers to no longer use the load/unload callbacks, directly coding the load/unload sequence into the driver's probe function. -- Once all non-DRIVER_LEGACY drivers are converted, disallow the load/unload - callbacks for all modern drivers. +- Once all drivers are converted, remove the load/unload callbacks. Contact: Daniel Vetter @@ -621,6 +620,23 @@ Contact: Javier Martinez Canillas Level: Intermediate +Clean up and document former selftests suites +--------------------------------------------- + +Some KUnit test suites (drm_buddy, drm_cmdline_parser, drm_damage_helper, +drm_format, drm_framebuffer, drm_dp_mst_helper, drm_mm, drm_plane_helper and +drm_rect) are former selftests suites that have been converted over when KUnit +was first introduced. + +These suites were fairly undocumented, and with different goals than what unit +tests can be. Trying to identify what each test in these suites actually test +for, whether that makes sense for a unit test, and either remove it if it +doesn't or document it if it does would be of great help. + +Contact: Maxime Ripard + +Level: Intermediate + Enable trinity for DRM ---------------------- @@ -765,6 +781,29 @@ Contact: Hans de Goede Level: Advanced +Buffer age or other damage accumulation algorithm for buffer damage +=================================================================== + +Drivers that do per-buffer uploads, need a buffer damage handling (rather than +frame damage like drivers that do per-plane or per-CRTC uploads), but there is +no support to get the buffer age or any other damage accumulation algorithm. + +For this reason, the damage helpers just fallback to a full plane update if the +framebuffer attached to a plane has changed since the last page-flip. Drivers +set &drm_plane_state.ignore_damage_clips to true as indication to +drm_atomic_helper_damage_iter_init() and drm_atomic_helper_damage_iter_next() +helpers that the damage clips should be ignored. + +This should be improved to get damage tracking properly working on drivers that +do per-buffer uploads. + +More information about damage tracking and references to learning materials can +be found in :ref:`damage_tracking_properties`. + +Contact: Javier Martinez Canillas + +Level: Advanced + Outside DRM =========== diff --git a/Documentation/gpu/xe/index.rst b/Documentation/gpu/xe/index.rst new file mode 100644 index 00000000000000..c224ecaee81e15 --- /dev/null +++ b/Documentation/gpu/xe/index.rst @@ -0,0 +1,25 @@ +.. SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +======================= +drm/xe Intel GFX Driver +======================= + +The drm/xe driver supports some future GFX cards with rendering, display, +compute and media. Support for currently available platforms like TGL, ADL, +DG2, etc is provided to prototype the driver. + +.. toctree:: + :titlesonly: + + xe_mm + xe_map + xe_migrate + xe_cs + xe_pm + xe_pcode + xe_gt_mcr + xe_wa + xe_rtp + xe_firmware + xe_tile + xe_debugging diff --git a/Documentation/gpu/xe/xe_cs.rst b/Documentation/gpu/xe/xe_cs.rst new file mode 100644 index 00000000000000..e379aed4f5a862 --- /dev/null +++ b/Documentation/gpu/xe/xe_cs.rst @@ -0,0 +1,8 @@ +.. SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +================== +Command submission +================== + +.. kernel-doc:: drivers/gpu/drm/xe/xe_exec.c + :doc: Execbuf (User GPU command submission) diff --git a/Documentation/gpu/xe/xe_debugging.rst b/Documentation/gpu/xe/xe_debugging.rst new file mode 100644 index 00000000000000..d65e56ff350034 --- /dev/null +++ b/Documentation/gpu/xe/xe_debugging.rst @@ -0,0 +1,7 @@ +.. SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +========= +Debugging +========= + +.. kernel-doc:: drivers/gpu/drm/xe/xe_assert.h diff --git a/Documentation/gpu/xe/xe_firmware.rst b/Documentation/gpu/xe/xe_firmware.rst new file mode 100644 index 00000000000000..afcb561cd37db2 --- /dev/null +++ b/Documentation/gpu/xe/xe_firmware.rst @@ -0,0 +1,37 @@ +.. SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +======== +Firmware +======== + +Firmware Layout +=============== + +.. kernel-doc:: drivers/gpu/drm/xe/xe_uc_fw_abi.h + :doc: CSS-based Firmware Layout + +.. kernel-doc:: drivers/gpu/drm/xe/xe_uc_fw_abi.h + :doc: GSC-based Firmware Layout + +Write Once Protected Content Memory (WOPCM) Layout +================================================== + +.. kernel-doc:: drivers/gpu/drm/xe/xe_wopcm.c + :doc: Write Once Protected Content Memory (WOPCM) Layout + +GuC CTB Blob +============ + +.. kernel-doc:: drivers/gpu/drm/xe/xe_guc_ct.c + :doc: GuC CTB Blob + +GuC Power Conservation (PC) +=========================== + +.. kernel-doc:: drivers/gpu/drm/xe/xe_guc_pc.c + :doc: GuC Power Conservation (PC) + +Internal API +============ + +TODO diff --git a/Documentation/gpu/xe/xe_gt_mcr.rst b/Documentation/gpu/xe/xe_gt_mcr.rst new file mode 100644 index 00000000000000..848c07bc36d0f4 --- /dev/null +++ b/Documentation/gpu/xe/xe_gt_mcr.rst @@ -0,0 +1,13 @@ +.. SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +============================================== +GT Multicast/Replicated (MCR) Register Support +============================================== + +.. kernel-doc:: drivers/gpu/drm/xe/xe_gt_mcr.c + :doc: GT Multicast/Replicated (MCR) Register Support + +Internal API +============ + +TODO diff --git a/Documentation/gpu/xe/xe_map.rst b/Documentation/gpu/xe/xe_map.rst new file mode 100644 index 00000000000000..a098cfd2df04d7 --- /dev/null +++ b/Documentation/gpu/xe/xe_map.rst @@ -0,0 +1,8 @@ +.. SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +========= +Map Layer +========= + +.. kernel-doc:: drivers/gpu/drm/xe/xe_map.h + :doc: Map layer diff --git a/Documentation/gpu/xe/xe_migrate.rst b/Documentation/gpu/xe/xe_migrate.rst new file mode 100644 index 00000000000000..f92faec0ac9431 --- /dev/null +++ b/Documentation/gpu/xe/xe_migrate.rst @@ -0,0 +1,8 @@ +.. SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +============= +Migrate Layer +============= + +.. kernel-doc:: drivers/gpu/drm/xe/xe_migrate_doc.h + :doc: Migrate Layer diff --git a/Documentation/gpu/xe/xe_mm.rst b/Documentation/gpu/xe/xe_mm.rst new file mode 100644 index 00000000000000..6c8fd8b4a4667a --- /dev/null +++ b/Documentation/gpu/xe/xe_mm.rst @@ -0,0 +1,14 @@ +.. SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +================= +Memory Management +================= + +.. kernel-doc:: drivers/gpu/drm/xe/xe_bo_doc.h + :doc: Buffer Objects (BO) + +Pagetable building +================== + +.. kernel-doc:: drivers/gpu/drm/xe/xe_pt.c + :doc: Pagetable building diff --git a/Documentation/gpu/xe/xe_pcode.rst b/Documentation/gpu/xe/xe_pcode.rst new file mode 100644 index 00000000000000..d2e22cc45061f3 --- /dev/null +++ b/Documentation/gpu/xe/xe_pcode.rst @@ -0,0 +1,14 @@ +.. SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +===== +Pcode +===== + +.. kernel-doc:: drivers/gpu/drm/xe/xe_pcode.c + :doc: PCODE + +Internal API +============ + +.. kernel-doc:: drivers/gpu/drm/xe/xe_pcode.c + :internal: diff --git a/Documentation/gpu/xe/xe_pm.rst b/Documentation/gpu/xe/xe_pm.rst new file mode 100644 index 00000000000000..6781cdfb24f6ed --- /dev/null +++ b/Documentation/gpu/xe/xe_pm.rst @@ -0,0 +1,14 @@ +.. SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +======================== +Runtime Power Management +======================== + +.. kernel-doc:: drivers/gpu/drm/xe/xe_pm.c + :doc: Xe Power Management + +Internal API +============ + +.. kernel-doc:: drivers/gpu/drm/xe/xe_pm.c + :internal: diff --git a/Documentation/gpu/xe/xe_rtp.rst b/Documentation/gpu/xe/xe_rtp.rst new file mode 100644 index 00000000000000..7fdf4b6c1a04fa --- /dev/null +++ b/Documentation/gpu/xe/xe_rtp.rst @@ -0,0 +1,20 @@ +.. SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +========================= +Register Table Processing +========================= + +.. kernel-doc:: drivers/gpu/drm/xe/xe_rtp.c + :doc: Register Table Processing + +Internal API +============ + +.. kernel-doc:: drivers/gpu/drm/xe/xe_rtp_types.h + :internal: + +.. kernel-doc:: drivers/gpu/drm/xe/xe_rtp.h + :internal: + +.. kernel-doc:: drivers/gpu/drm/xe/xe_rtp.c + :internal: diff --git a/Documentation/gpu/xe/xe_tile.rst b/Documentation/gpu/xe/xe_tile.rst new file mode 100644 index 00000000000000..c33f68dd95b6be --- /dev/null +++ b/Documentation/gpu/xe/xe_tile.rst @@ -0,0 +1,14 @@ +.. SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +================== +Multi-tile Devices +================== + +.. kernel-doc:: drivers/gpu/drm/xe/xe_tile.c + :doc: Multi-tile Design + +Internal API +============ + +.. kernel-doc:: drivers/gpu/drm/xe/xe_tile.c + :internal: diff --git a/Documentation/gpu/xe/xe_wa.rst b/Documentation/gpu/xe/xe_wa.rst new file mode 100644 index 00000000000000..f8811cc6adccbf --- /dev/null +++ b/Documentation/gpu/xe/xe_wa.rst @@ -0,0 +1,14 @@ +.. SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +==================== +Hardware workarounds +==================== + +.. kernel-doc:: drivers/gpu/drm/xe/xe_wa.c + :doc: Hardware workarounds + +Internal API +============ + +.. kernel-doc:: drivers/gpu/drm/xe/xe_wa.c + :internal: diff --git a/Documentation/hwmon/dell-smm-hwmon.rst b/Documentation/hwmon/dell-smm-hwmon.rst index d8f1d6859b964b..977263cb57a837 100644 --- a/Documentation/hwmon/dell-smm-hwmon.rst +++ b/Documentation/hwmon/dell-smm-hwmon.rst @@ -186,8 +186,7 @@ SMM Interface The driver uses the SMM interface to send commands to the system BIOS. This interface is normally used by Dell's 32-bit diagnostic program or on newer notebook models by the buildin BIOS diagnostics. -The SMM is triggered by writing to the special ioports ``0xb2`` and ``0x84``, -and may cause short hangs when the BIOS code is taking too long to +The SMM may cause short hangs when the BIOS code is taking too long to execute. The SMM handler inside the system BIOS looks at the contents of the @@ -210,7 +209,40 @@ The SMM handler can signal a failure by either: - setting the lower sixteen bits of ``eax`` to ``0xffff`` - not modifying ``eax`` at all -- setting the carry flag +- setting the carry flag (legacy SMM interface only) + +Legacy SMM Interface +-------------------- + +When using the legacy SMM interface, a SMM is triggered by writing the least significant byte +of the command code to the special ioports ``0xb2`` and ``0x84``. This interface is not +described inside the ACPI tables and can thus only be detected by issuing a test SMM call. + +WMI SMM Interface +----------------- + +On modern Dell machines, the SMM calls are done over ACPI WMI: + +:: + + #pragma namespace("\\\\.\\root\\dcim\\sysman\\diagnostics") + [WMI, Provider("Provider_DiagnosticsServices"), Dynamic, Locale("MS\\0x409"), + Description("RunDellDiag"), guid("{F1DDEE52-063C-4784-A11E-8A06684B9B01}")] + class LegacyDiags { + [key, read] string InstanceName; + [read] boolean Active; + + [WmiMethodId(1), Implemented, read, write, Description("Legacy Method ")] + void Execute([in, out] uint32 EaxLen, [in, out, WmiSizeIs("EaxLen") : ToInstance] uint8 EaxVal[], + [in, out] uint32 EbxLen, [in, out, WmiSizeIs("EbxLen") : ToInstance] uint8 EbxVal[], + [in, out] uint32 EcxLen, [in, out, WmiSizeIs("EcxLen") : ToInstance] uint8 EcxVal[], + [in, out] uint32 EdxLen, [in, out, WmiSizeIs("EdxLen") : ToInstance] uint8 EdxVal[]); + }; + +Some machines support only the WMI SMM interface, while some machines support both interfaces. +The driver automatically detects which interfaces are present and will use the WMI SMM interface +if the legacy SMM interface is not present. The WMI SMM interface is usually slower than the +legacy SMM interface since ACPI methods need to be called in order to trigger a SMM. SMM command codes ----------------- diff --git a/Documentation/hwmon/gigabyte_waterforce.rst b/Documentation/hwmon/gigabyte_waterforce.rst new file mode 100644 index 00000000000000..d47f3e8516ee74 --- /dev/null +++ b/Documentation/hwmon/gigabyte_waterforce.rst @@ -0,0 +1,47 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Kernel driver gigabyte_waterforce +================================= + +Supported devices: + +* Gigabyte AORUS WATERFORCE X240 +* Gigabyte AORUS WATERFORCE X280 +* Gigabyte AORUS WATERFORCE X360 + +Author: Aleksa Savic + +Description +----------- + +This driver enables hardware monitoring support for the listed Gigabyte Waterforce +all-in-one CPU liquid coolers. Available sensors are pump and fan speed in RPM, as +well as coolant temperature. Also available through debugfs is the firmware version. + +Attaching a fan is optional and allows it to be controlled from the device. If +it's not connected, the fan-related sensors will report zeroes. + +The addressable RGB LEDs and LCD screen are not supported in this driver and should +be controlled through userspace tools. + +Usage notes +----------- + +As these are USB HIDs, the driver can be loaded automatically by the kernel and +supports hot swapping. + +Sysfs entries +------------- + +=========== ============================================= +fan1_input Fan speed (in rpm) +fan2_input Pump speed (in rpm) +temp1_input Coolant temperature (in millidegrees Celsius) +=========== ============================================= + +Debugfs entries +--------------- + +================ ======================= +firmware_version Device firmware version +================ ======================= diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst index 72f4e6065baede..c7ed1f73ac0661 100644 --- a/Documentation/hwmon/index.rst +++ b/Documentation/hwmon/index.rst @@ -73,6 +73,7 @@ Hardware Monitoring Kernel Drivers ftsteutates g760a g762 + gigabyte_waterforce gsc-hwmon gl518sm gxp-fan-ctrl @@ -128,6 +129,7 @@ Hardware Monitoring Kernel Drivers ltc4245 ltc4260 ltc4261 + ltc4286 max127 max15301 max16064 @@ -156,9 +158,11 @@ Hardware Monitoring Kernel Drivers mcp3021 menf21bmc mlxreg-fan + mp2856 mp2888 mp2975 mp5023 + mp5990 nct6683 nct6775 nct7802 diff --git a/Documentation/hwmon/lm75.rst b/Documentation/hwmon/lm75.rst index 8d0ab4ad5fb525..6adab608dd05c1 100644 --- a/Documentation/hwmon/lm75.rst +++ b/Documentation/hwmon/lm75.rst @@ -133,6 +133,16 @@ Supported chips: https://www.nxp.com/docs/en/data-sheet/PCT2075.pdf + * AMS OSRAM AS6200 + + Prefix: 'as6200' + + Addresses scanned: none + + Datasheet: Publicly available at the AMS website + + https://ams.com/documents/20143/36005/AS6200_DS000449_4-00.pdf + Author: Frodo Looijaard Description diff --git a/Documentation/hwmon/ltc4286.rst b/Documentation/hwmon/ltc4286.rst new file mode 100644 index 00000000000000..2cd149676d8636 --- /dev/null +++ b/Documentation/hwmon/ltc4286.rst @@ -0,0 +1,95 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Kernel driver ltc4286 +===================== + +Supported chips: + + * Analog Devices LTC4286 + + Prefix: 'ltc4286' + + Addresses scanned: - + + Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ltc4286.pdf + + * Analog Devices LTC4287 + + Prefix: 'ltc4287' + + Addresses scanned: - + + Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ltc4287.pdf + +Author: Delphine CC Chiu + + +Description +----------- + +This driver supports hardware monitoring for Analog Devices LTC4286 +and LTC4287 Hot-Swap Controller and Digital Power Monitors. + +LTC4286 and LTC4287 are hot-swap controllers that allow a circuit board +to be removed from or inserted into a live backplane. They also feature +current and voltage readback via an integrated 12 bit analog-to-digital +converter (ADC), accessed using a PMBus interface. + +The driver is a client driver to the core PMBus driver. Please see +Documentation/hwmon/pmbus.rst for details on PMBus client drivers. + + +Usage Notes +----------- + +This driver does not auto-detect devices. You will have to instantiate the +devices explicitly. Please see Documentation/i2c/instantiating-devices.rst for +details. + +The shunt value in micro-ohms can be set via device tree at compile-time. Please +refer to the Documentation/devicetree/bindings/hwmon/lltc,ltc4286.yaml for bindings +if the device tree is used. + + +Platform data support +--------------------- + +The driver supports standard PMBus driver platform data. Please see +Documentation/hwmon/pmbus.rst for details. + + +Sysfs entries +------------- + +The following attributes are supported. Limits are read-write, history reset +attributes are write-only, all other attributes are read-only. + +======================= ======================================================= +in1_label "vin" +in1_input Measured voltage. +in1_alarm Input voltage alarm. +in1_min Minimum input voltage. +in1_max Maximum input voltage. + +in2_label "vout1" +in2_input Measured voltage. +in2_alarm Output voltage alarm. +in2_min Minimum output voltage. +in2_max Maximum output voltage. + +curr1_label "iout1" +curr1_input Measured current. +curr1_alarm Output current alarm. +curr1_max Maximum current. + +power1_label "pin" +power1_input Input power. +power1_alarm Input power alarm. +power1_max Maximum poewr. + +temp1_input Chip temperature. +temp1_min Minimum chip temperature. +temp1_max Maximum chip temperature. +temp1_crit Critical chip temperature. +temp1_alarm Chip temperature alarm. +======================= ======================================================= diff --git a/Documentation/hwmon/max31827.rst b/Documentation/hwmon/max31827.rst index 9a1055a007cf38..44ab9dc064cb38 100644 --- a/Documentation/hwmon/max31827.rst +++ b/Documentation/hwmon/max31827.rst @@ -52,13 +52,21 @@ MAX31827 has low and over temperature alarms with an effective value and a hysteresis value: -40 and -30 degrees for under temperature alarm and +100 and +90 degrees for over temperature alarm. -The alarm can be configured in comparator and interrupt mode. Currently only -comparator mode is implemented. In Comparator mode, the OT/UT status bits have a -value of 1 when the temperature rises above the TH value or falls below TL, -which is also subject to the Fault Queue selection. OT status returns to 0 when -the temperature drops below the TH_HYST value or when shutdown mode is entered. -Similarly, UT status returns to 0 when the temperature rises above TL_HYST value -or when shutdown mode is entered. +The alarm can be configured in comparator and interrupt mode from the +devicetree. In Comparator mode, the OT/UT status bits have a value of 1 when the +temperature rises above the TH value or falls below TL, which is also subject to +the Fault Queue selection. OT status returns to 0 when the temperature drops +below the TH_HYST value or when shutdown mode is entered. Similarly, UT status +returns to 0 when the temperature rises above TL_HYST value or when shutdown +mode is entered. + +In interrupt mode exceeding TH also sets OT status to 1, which remains set until +a read operation is performed on the configuration/status register (max or min +attribute); at this point, it returns to 0. Once OT status is set to 1 from +exceeding TH and reset, it is set to 1 again only when the temperature drops +below TH_HYST. The output remains asserted until it is reset by a read. It is +set again if the temperature rises above TH, and so on. The same logic applies +to the operation of the UT status bit. Putting the MAX31827 into shutdown mode also resets the OT/UT status bits. Note that if the mode is changed while OT/UT status bits are set, an OT/UT status @@ -68,13 +76,42 @@ clear the status bits before changing the operating mode. The conversions can be manual with the one-shot functionality and automatic with a set frequency. When powered on, the chip measures temperatures with 1 conv/s. +The conversion rate can be modified with update_interval attribute of the chip. +Conversion/second = 1/update_interval. Thus, the available options according to +the data sheet are: + +- 64000 (ms) = 1 conv/64 sec +- 32000 (ms) = 1 conv/32 sec +- 16000 (ms) = 1 conv/16 sec +- 4000 (ms) = 1 conv/4 sec +- 1000 (ms) = 1 conv/sec (default) +- 250 (ms) = 4 conv/sec +- 125 (ms) = 8 conv/sec + Enabling the device when it is already enabled has the side effect of setting the conversion frequency to 1 conv/s. The conversion time varies depending on -the resolution. The conversion time doubles with every bit of increased -resolution. For 10 bit resolution 35ms are needed, while for 12 bit resolution -(default) 140ms. When chip is in shutdown mode and a read operation is -requested, one-shot is triggered, the device waits for 140 (conversion time) ms, -and only after that is the temperature value register read. +the resolution. + +The conversion time doubles with every bit of increased resolution. The +available resolutions are: + +- 8 bit -> 8.75 ms conversion time +- 9 bit -> 17.5 ms conversion time +- 10 bit -> 35 ms conversion time +- 12 bit (default) -> 140 ms conversion time + +There is a temp1_resolution attribute which indicates the unit change in the +input temperature in milli-degrees C. + +- 1000 mC -> 8 bit +- 500 mC -> 9 bit +- 250 mC -> 10 bit +- 62 mC -> 12 bit (default) - actually this is 62.5, but the fil returns 62 + +When chip is in shutdown mode and a read operation is requested, one-shot is +triggered, the device waits for ms, and only after that is +the temperature value register read. Note that the conversion times are rounded +up to the nearest possible integer. The LSB of the temperature values is 0.0625 degrees Celsius, but the values of the temperatures are displayed in milli-degrees. This means, that some data is @@ -83,8 +120,18 @@ in the writing of alarm values too. For positive numbers the user-input value will always be rounded down to the nearest possible value, for negative numbers the user-input will always be rounded up to the nearest possible value. +Bus timeout resets the I2C-compatible interface when SCL is low for more than +30ms (nominal). + +Alarm polarity determines if the active state of the alarm is low or high. The +behavior for both settings is dependent on the Fault Queue setting. The ALARM +pin is an open-drain output and requires a pullup resistor to operate. + +The Fault Queue bits select how many consecutive temperature faults must occur +before overtemperature or undertemperature faults are indicated in the +corresponding status bits. + Notes ----- -Currently fault queue, alarm polarity and resolution cannot be modified. -PEC is not implemented either. +PEC is not implemented. diff --git a/Documentation/hwmon/mp2856.rst b/Documentation/hwmon/mp2856.rst new file mode 100644 index 00000000000000..af625c22b6ea7e --- /dev/null +++ b/Documentation/hwmon/mp2856.rst @@ -0,0 +1,98 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Kernel driver mp2856 +==================== + +Supported chips: + + * MPS MP2856 + + Prefix: 'mp2856' + + * MPS MP2857 + + Prefix: 'mp2857' + +Author: + + Peter Yin + +Description +----------- + +This driver implements support for Monolithic Power Systems, Inc. (MPS) +vendor dual-loop, digital, multi-phase controller MP2856/MP2857 + +This device: + +- Supports up to two power rail. +- Supports two pages 0 and 1 for and also pages 2 for configuration. +- Can configured VOUT readout in direct or VID format and allows + setting of different formats on rails 1 and 2. For VID the following + protocols are available: AMD SVI3 mode with 5-mV/LSB. + +Device supports: + +- SVID interface. +- AVSBus interface. + +Device compliant with: + +- PMBus rev 1.3 interface. + +Device supports direct format for reading output current, output voltage, +input and output power and temperature. +Device supports linear format for reading input voltage and input power. +Device supports VID and direct formats for reading output voltage. +The below VID modes are supported: AMD SVI3. + +The driver provides the following sysfs attributes for current measurements: + +- indexes 1 for "iin"; +- indexes 2, 3 for "iout"; + +**curr[1-3]_alarm** + +**curr[1-3]_input** + +**curr[1-3]_label** + +The driver provides the following sysfs attributes for voltage measurements. + +- indexes 1 for "vin"; +- indexes 2, 3 for "vout"; + +**in[1-3]_crit** + +**in[1-3]_crit_alarm** + +**in[1-3]_input** + +**in[1-3]_label** + +**in[1-3]_lcrit** + +**in[1-3]_lcrit_alarm** + +The driver provides the following sysfs attributes for power measurements. + +- indexes 1 for "pin"; +- indexes 2, 3 for "pout"; + +**power[1-3]_alarm** + +**power[1-3]_input** + +**power[1-3]_label** + +The driver provides the following sysfs attributes for temperature measurements. + +**temp[1-2]_crit** + +**temp[1-2]_crit_alarm** + +**temp[1-2]_input** + +**temp[1-2]_max** + +**temp[1-2]_max_alarm** diff --git a/Documentation/hwmon/mp5990.rst b/Documentation/hwmon/mp5990.rst new file mode 100644 index 00000000000000..6f2f0c099d449d --- /dev/null +++ b/Documentation/hwmon/mp5990.rst @@ -0,0 +1,84 @@ +.. SPDX-License-Identifier: GPL-2.0 + +Kernel driver mp5990 +==================== + +Supported chips: + + * MPS MP5990 + + Prefix: 'mp5990' + + * Datasheet + + Publicly available at the MPS website : https://www.monolithicpower.com/en/mp5990.html + +Author: + + Peter Yin + +Description +----------- + +This driver implements support for Monolithic Power Systems, Inc. (MPS) +MP5990 Hot-Swap Controller. + +Device compliant with: + +- PMBus rev 1.3 interface. + +Device supports direct and linear format for reading input voltage, +output voltage, output current, input power and temperature. + +The driver exports the following attributes via the 'sysfs' files +for input voltage: + +**in1_input** + +**in1_label** + +**in1_max** + +**in1_max_alarm** + +**in1_min** + +**in1_min_alarm** + +The driver provides the following attributes for output voltage: + +**in2_input** + +**in2_label** + +**in2_alarm** + +The driver provides the following attributes for output current: + +**curr1_input** + +**curr1_label** + +**curr1_alarm** + +**curr1_max** + +The driver provides the following attributes for input power: + +**power1_input** + +**power1_label** + +**power1_alarm** + +The driver provides the following attributes for temperature: + +**temp1_input** + +**temp1_max** + +**temp1_max_alarm** + +**temp1_crit** + +**temp1_crit_alarm** diff --git a/Documentation/hwmon/sht3x.rst b/Documentation/hwmon/sht3x.rst index 87864ffd1777d0..957c854f5d088c 100644 --- a/Documentation/hwmon/sht3x.rst +++ b/Documentation/hwmon/sht3x.rst @@ -9,7 +9,19 @@ Supported chips: Addresses scanned: none - Datasheet: https://www.sensirion.com/file/datasheet_sht3x_digital + Datasheets: + - https://sensirion.com/media/documents/213E6A3B/63A5A569/Datasheet_SHT3x_DIS.pdf + - https://sensirion.com/media/documents/051DF50B/639C8101/Sensirion_Humidity_and_Temperature_Sensors_Datasheet_SHT33.pdf + + * Sensirion STS3x-DIS + + Prefix: 'sts3x' + + Addresses scanned: none + + Datasheets: + - https://sensirion.com/media/documents/1DA31AFD/61641F76/Sensirion_Temperature_Sensors_STS3x_Datasheet.pdf + - https://sensirion.com/media/documents/292A335C/65537BAF/Sensirion_Datasheet_STS32_STS33.pdf Author: @@ -19,16 +31,17 @@ Author: Description ----------- -This driver implements support for the Sensirion SHT3x-DIS chip, a humidity -and temperature sensor. Temperature is measured in degrees celsius, relative -humidity is expressed as a percentage. In the sysfs interface, all values are -scaled by 1000, i.e. the value for 31.5 degrees celsius is 31500. +This driver implements support for the Sensirion SHT3x-DIS and STS3x-DIS +series of humidity and temperature sensors. Temperature is measured in degrees +celsius, relative humidity is expressed as a percentage. In the sysfs interface, +all values are scaled by 1000, i.e. the value for 31.5 degrees celsius is 31500. The device communicates with the I2C protocol. Sensors can have the I2C -addresses 0x44 or 0x45, depending on the wiring. See -Documentation/i2c/instantiating-devices.rst for methods to instantiate the device. +addresses 0x44 or 0x45 (0x4a or 0x4b for sts3x), depending on the wiring. See +Documentation/i2c/instantiating-devices.rst for methods to instantiate the +device. -Even if sht3x sensor supports clock-strech(blocking mode) and non-strench +Even if sht3x sensor supports clock-stretch (blocking mode) and non-stretch (non-blocking mode) in single-shot mode, this driver only supports the latter. The sht3x sensor supports a single shot mode as well as 5 periodic measure diff --git a/Documentation/index.rst b/Documentation/index.rst index 9dfdc826618c08..36e61783437c10 100644 --- a/Documentation/index.rst +++ b/Documentation/index.rst @@ -113,6 +113,7 @@ to ReStructured Text format, or are simply too old. :maxdepth: 1 staging/index + RAS/ras Translations diff --git a/Documentation/input/input_kapi.rst b/Documentation/input/input_kapi.rst index 41f1b7e6b78ea5..9937522daa9bd8 100644 --- a/Documentation/input/input_kapi.rst +++ b/Documentation/input/input_kapi.rst @@ -4,11 +4,8 @@ Linux Input Subsystem kernel API ################################ -.. class:: toc-title - - Table of Contents - .. toctree:: + :caption: Table of Contents :maxdepth: 2 :numbered: diff --git a/Documentation/input/input_uapi.rst b/Documentation/input/input_uapi.rst index 4a0391609327a1..8275b4223a841f 100644 --- a/Documentation/input/input_uapi.rst +++ b/Documentation/input/input_uapi.rst @@ -4,11 +4,8 @@ Linux Input Subsystem userspace API ################################### -.. class:: toc-title - - Table of Contents - .. toctree:: + :caption: Table of Contents :maxdepth: 2 :numbered: diff --git a/Documentation/input/joydev/index.rst b/Documentation/input/joydev/index.rst index ebcff43056e2db..d03d6f6cbfab88 100644 --- a/Documentation/input/joydev/index.rst +++ b/Documentation/input/joydev/index.rst @@ -6,11 +6,8 @@ Linux Joystick support :Copyright: |copy| 1996-2000 Vojtech Pavlik - Sponsored by SuSE -.. class:: toc-title - - Table of Contents - .. toctree:: + :caption: Table of Contents :maxdepth: 3 joystick diff --git a/Documentation/livepatch/callbacks.rst b/Documentation/livepatch/callbacks.rst index 470944aa865811..914445784ce482 100644 --- a/Documentation/livepatch/callbacks.rst +++ b/Documentation/livepatch/callbacks.rst @@ -110,7 +110,7 @@ Global data update ------------------ A pre-patch callback can be useful to update a global variable. For -example, 75ff39ccc1bd ("tcp: make challenge acks less predictable") +example, commit 75ff39ccc1bd ("tcp: make challenge acks less predictable") changes a global sysctl, as well as patches the tcp_send_challenge_ack() function. @@ -126,7 +126,7 @@ Although __init and probe functions are not directly livepatch-able, it may be possible to implement similar updates via pre/post-patch callbacks. -The commit ``48900cb6af42 ("virtio-net: drop NETIF_F_FRAGLIST")`` change the way that +The commit 48900cb6af42 ("virtio-net: drop NETIF_F_FRAGLIST") change the way that virtnet_probe() initialized its driver's net_device features. A pre/post-patch callback could iterate over all such devices, making a similar change to their hw_features value. (Client functions of the diff --git a/Documentation/locking/mutex-design.rst b/Documentation/locking/mutex-design.rst index 78540cd7f54b20..7c30b4aa5e28fc 100644 --- a/Documentation/locking/mutex-design.rst +++ b/Documentation/locking/mutex-design.rst @@ -101,6 +101,24 @@ features that make lock debugging easier and faster: - Detects multi-task circular deadlocks and prints out all affected locks and tasks (and only those tasks). +Mutexes - and most other sleeping locks like rwsems - do not provide an +implicit reference for the memory they occupy, which reference is released +with mutex_unlock(). + +[ This is in contrast with spin_unlock() [or completion_done()], which + APIs can be used to guarantee that the memory is not touched by the + lock implementation after spin_unlock()/completion_done() releases + the lock. ] + +mutex_unlock() may access the mutex structure even after it has internally +released the lock already - so it's not safe for another context to +acquire the mutex and assume that the mutex_unlock() context is not using +the structure anymore. + +The mutex user must ensure that the mutex is not destroyed while a +release operation is still in progress - in other words, callers of +mutex_unlock() must ensure that the mutex stays alive until mutex_unlock() +has returned. Interfaces ---------- diff --git a/Documentation/maintainer/maintainer-entry-profile.rst b/Documentation/maintainer/maintainer-entry-profile.rst index 7ad4bfc2cc038a..18cee1edaecb6f 100644 --- a/Documentation/maintainer/maintainer-entry-profile.rst +++ b/Documentation/maintainer/maintainer-entry-profile.rst @@ -105,4 +105,4 @@ to do something different in the near future. ../driver-api/media/maintainer-entry-profile ../driver-api/vfio-pci-device-specific-driver-acceptance ../nvme/feature-and-quirk-policy - ../filesystems/xfs-maintainer-entry-profile + ../filesystems/xfs/xfs-maintainer-entry-profile diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt index d414e145f912c2..4202174a6262c5 100644 --- a/Documentation/memory-barriers.txt +++ b/Documentation/memory-barriers.txt @@ -396,10 +396,11 @@ Memory barriers come in four basic varieties: (2) Address-dependency barriers (historical). - [!] This section is marked as HISTORICAL: For more up-to-date - information, including how compiler transformations related to pointer - comparisons can sometimes cause problems, see - Documentation/RCU/rcu_dereference.rst. + [!] This section is marked as HISTORICAL: it covers the long-obsolete + smp_read_barrier_depends() macro, the semantics of which are now + implicit in all marked accesses. For more up-to-date information, + including how compiler transformations can sometimes break address + dependencies, see Documentation/RCU/rcu_dereference.rst. An address-dependency barrier is a weaker form of read barrier. In the case where two loads are performed such that the second depends on the @@ -560,9 +561,11 @@ There are certain things that the Linux kernel memory barriers do not guarantee: ADDRESS-DEPENDENCY BARRIERS (HISTORICAL) ---------------------------------------- -[!] This section is marked as HISTORICAL: For more up-to-date information, -including how compiler transformations related to pointer comparisons can -sometimes cause problems, see Documentation/RCU/rcu_dereference.rst. +[!] This section is marked as HISTORICAL: it covers the long-obsolete +smp_read_barrier_depends() macro, the semantics of which are now implicit +in all marked accesses. For more up-to-date information, including +how compiler transformations can sometimes break address dependencies, +see Documentation/RCU/rcu_dereference.rst. As of v4.15 of the Linux kernel, an smp_mb() was added to READ_ONCE() for DEC Alpha, which means that about the only people who need to pay attention diff --git a/Documentation/misc-devices/index.rst b/Documentation/misc-devices/index.rst index 7de16797987afc..2d0ce913858808 100644 --- a/Documentation/misc-devices/index.rst +++ b/Documentation/misc-devices/index.rst @@ -7,11 +7,8 @@ Assorted Miscellaneous Devices Documentation This documentation contains information for assorted devices that do not fit into other categories. -.. class:: toc-title - - Table of contents - .. toctree:: + :caption: Table of contents :maxdepth: 2 ad525x_dpot diff --git a/Documentation/mm/arch_pgtable_helpers.rst b/Documentation/mm/arch_pgtable_helpers.rst index c82e3ee20e51ee..2466d3363af79f 100644 --- a/Documentation/mm/arch_pgtable_helpers.rst +++ b/Documentation/mm/arch_pgtable_helpers.rst @@ -18,8 +18,6 @@ PTE Page Table Helpers +---------------------------+--------------------------------------------------+ | pte_same | Tests whether both PTE entries are the same | +---------------------------+--------------------------------------------------+ -| pte_bad | Tests a non-table mapped PTE | -+---------------------------+--------------------------------------------------+ | pte_present | Tests a valid mapped PTE | +---------------------------+--------------------------------------------------+ | pte_young | Tests a young PTE | diff --git a/Documentation/mm/damon/design.rst b/Documentation/mm/damon/design.rst index 1f7e0586b5fafe..1bb69524a62ea6 100644 --- a/Documentation/mm/damon/design.rst +++ b/Documentation/mm/damon/design.rst @@ -5,6 +5,18 @@ Design ====== +.. _damon_design_execution_model_and_data_structures: + +Execution Model and Data Structures +=================================== + +The monitoring-related information including the monitoring request +specification and DAMON-based operation schemes are stored in a data structure +called DAMON ``context``. DAMON executes each context with a kernel thread +called ``kdamond``. Multiple kdamonds could run in parallel, for different +types of monitoring. + + Overall Architecture ==================== @@ -346,6 +358,19 @@ the weight will be respected are up to the underlying prioritization mechanism implementation. +.. _damon_design_damos_quotas_auto_tuning: + +Aim-oriented Feedback-driven Auto-tuning +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Automatic feedback-driven quota tuning. Instead of setting the absolute quota +value, users can repeatedly provide numbers representing how much of their goal +for the scheme is achieved as feedback. DAMOS then automatically tunes the +aggressiveness (the quota) of the corresponding scheme. For example, if DAMOS +is under achieving the goal, DAMOS automatically increases the quota. If DAMOS +is over achieving the goal, it decreases the quota. + + .. _damon_design_damos_watermarks: Watermarks @@ -477,15 +502,3 @@ modules for proactive reclamation and LRU lists manipulation are provided. For more detail, please read the usage documents for those (:doc:`/admin-guide/mm/damon/reclaim` and :doc:`/admin-guide/mm/damon/lru_sort`). - - -.. _damon_design_execution_model_and_data_structures: - -Execution Model and Data Structures -=================================== - -The monitoring-related information including the monitoring request -specification and DAMON-based operation schemes are stored in a data structure -called DAMON ``context``. DAMON executes each context with a kernel thread -called ``kdamond``. Multiple kdamonds could run in parallel, for different -types of monitoring. diff --git a/Documentation/mm/transhuge.rst b/Documentation/mm/transhuge.rst index 9a607059ea11cf..93c9239b9ebe23 100644 --- a/Documentation/mm/transhuge.rst +++ b/Documentation/mm/transhuge.rst @@ -117,7 +117,7 @@ pages: - map/unmap of a PMD entry for the whole THP increment/decrement folio->_entire_mapcount and also increment/decrement - folio->_nr_pages_mapped by COMPOUND_MAPPED when _entire_mapcount + folio->_nr_pages_mapped by ENTIRELY_MAPPED when _entire_mapcount goes from -1 to 0 or 0 to -1. - map/unmap of individual pages with PTE entry increment/decrement @@ -156,7 +156,7 @@ Partial unmap and deferred_split_folio() Unmapping part of THP (with munmap() or other way) is not going to free memory immediately. Instead, we detect that a subpage of THP is not in use -in page_remove_rmap() and queue the THP for splitting if memory pressure +in folio_remove_rmap_*() and queue the THP for splitting if memory pressure comes. Splitting will free up unused subpages. Splitting the page right away is not an option due to locking context in diff --git a/Documentation/mm/unevictable-lru.rst b/Documentation/mm/unevictable-lru.rst index 67f1338440a50a..b6a07a26b10d58 100644 --- a/Documentation/mm/unevictable-lru.rst +++ b/Documentation/mm/unevictable-lru.rst @@ -486,7 +486,7 @@ munlock the pages if we're removing the last VM_LOCKED VMA that maps the pages. Before the unevictable/mlock changes, mlocking did not mark the pages in any way, so unmapping them required no processing. -For each PTE (or PMD) being unmapped from a VMA, page_remove_rmap() calls +For each PTE (or PMD) being unmapped from a VMA, folio_remove_rmap_*() calls munlock_vma_folio(), which calls munlock_folio() when the VMA is VM_LOCKED (unless it was a PTE mapping of a part of a transparent huge page). @@ -511,7 +511,7 @@ userspace; truncation even unmaps and deletes any private anonymous pages which had been Copied-On-Write from the file pages now being truncated. Mlocked pages can be munlocked and deleted in this way: like with munmap(), -for each PTE (or PMD) being unmapped from a VMA, page_remove_rmap() calls +for each PTE (or PMD) being unmapped from a VMA, folio_remove_rmap_*() calls munlock_vma_folio(), which calls munlock_folio() when the VMA is VM_LOCKED (unless it was a PTE mapping of a part of a transparent huge page). diff --git a/Documentation/netlink/netlink-raw.yaml b/Documentation/netlink/netlink-raw.yaml index 775cce8c548a4c..04b92f1a5cd6ef 100644 --- a/Documentation/netlink/netlink-raw.yaml +++ b/Documentation/netlink/netlink-raw.yaml @@ -126,8 +126,10 @@ properties: name: type: string type: - description: The netlink attribute type - enum: [ u8, u16, u32, u64, s8, s16, s32, s64, string, binary ] + description: | + The netlink attribute type. Members of type 'binary' or 'pad' + must also have the 'len' property set. + enum: [ u8, u16, u32, u64, s8, s16, s32, s64, string, binary, pad ] len: $ref: '#/$defs/len-or-define' byte-order: @@ -150,6 +152,14 @@ properties: the right formatting mechanism when displaying values of this type. enum: [ hex, mac, fddi, ipv4, ipv6, uuid ] + if: + properties: + type: + oneOf: + - const: binary + - const: pad + then: + required: [ len ] # End genetlink-legacy attribute-sets: @@ -200,8 +210,10 @@ properties: type: string type: &attr-type description: The netlink attribute type - enum: [ unused, pad, flag, binary, u8, u16, u32, u64, s32, s64, - string, nest, array-nest, nest-type-value ] + enum: [ unused, pad, flag, binary, bitfield32, + u8, u16, u32, u64, s8, s16, s32, s64, + string, nest, array-nest, nest-type-value, + sub-message ] doc: description: Documentation of the attribute. type: string @@ -260,6 +272,17 @@ properties: description: Name of the struct type used for the attribute. type: string # End genetlink-legacy + # Start netlink-raw + sub-message: + description: | + Name of the sub-message definition to use for the attribute. + type: string + selector: + description: | + Name of the attribute to use for dynamic selection of sub-message + format specifier. + type: string + # End netlink-raw # Make sure name-prefix does not appear in subsets (subsets inherit naming) dependencies: @@ -282,6 +305,43 @@ properties: items: required: [ type ] + # Start netlink-raw + sub-messages: + description: Definition of sub message attributes + type: array + items: + type: object + additionalProperties: False + required: [ name, formats ] + properties: + name: + description: Name of the sub-message definition + type: string + formats: + description: Dynamically selected format specifiers + type: array + items: + type: object + additionalProperties: False + required: [ value ] + properties: + value: + description: | + Value to match for dynamic selection of sub-message format + specifier. + type: string + fixed-header: + description: | + Name of the struct definition to use as the fixed header + for the sub message. + type: string + attribute-set: + description: | + Name of the attribute space from which to resolve attributes + in the sub message. + type: string + # End netlink-raw + operations: description: Operations supported by the protocol. type: object diff --git a/Documentation/netlink/specs/devlink.yaml b/Documentation/netlink/specs/devlink.yaml index 572d83a414d0d0..cf6eaa0da821b3 100644 --- a/Documentation/netlink/specs/devlink.yaml +++ b/Documentation/netlink/specs/devlink.yaml @@ -75,6 +75,14 @@ definitions: name: ipsec-crypto-bit - name: ipsec-packet-bit + - + type: enum + name: rate-type + entries: + - + name: leaf + - + name: node - type: enum name: sb-threshold-type @@ -111,6 +119,16 @@ definitions: name: none - name: basic + - + type: enum + name: dpipe-header-id + entries: + - + name: ethernet + - + name: ipv4 + - + name: ipv6 - type: enum name: dpipe-match-type @@ -174,6 +192,16 @@ definitions: name: trap - name: mirror + - + type: enum + name: trap-type + entries: + - + name: drop + - + name: exception + - + name: control attribute-sets: - @@ -194,27 +222,45 @@ attribute-sets: name: port-type type: u16 enum: port-type - - # TODO: fill in the attributes in between - + - + name: port-desired-type + type: u16 + - + name: port-netdev-ifindex + type: u32 + - + name: port-netdev-name + type: string + - + name: port-ibdev-name + type: string - name: port-split-count type: u32 - value: 9 - - # TODO: fill in the attributes in between - + - + name: port-split-group + type: u32 - name: sb-index type: u32 - value: 11 - - # TODO: fill in the attributes in between - + - + name: sb-size + type: u32 + - + name: sb-ingress-pool-count + type: u16 + - + name: sb-egress-pool-count + type: u16 + - + name: sb-ingress-tc-count + type: u16 + - + name: sb-egress-tc-count + type: u16 - name: sb-pool-index type: u16 - value: 17 - name: sb-pool-type type: u8 @@ -232,16 +278,16 @@ attribute-sets: - name: sb-tc-index type: u16 - value: 22 - - # TODO: fill in the attributes in between - + - + name: sb-occ-cur + type: u32 + - + name: sb-occ-max + type: u32 - name: eswitch-mode type: u16 - value: 25 enum: eswitch-mode - - name: eswitch-inline-mode type: u16 @@ -347,6 +393,7 @@ attribute-sets: - name: dpipe-header-id type: u32 + enum: dpipe-header-id - name: dpipe-header-fields type: nest @@ -381,7 +428,6 @@ attribute-sets: - name: eswitch-encap-mode type: u8 - value: 62 enum: eswitch-encap-mode - name: resource-list @@ -433,20 +479,25 @@ attribute-sets: name: port-flavour type: u16 enum: port-flavour - - # TODO: fill in the attributes in between - + - + name: port-number + type: u32 + - + name: port-split-subport-number + type: u32 + - + name: param + type: nest + nested-attributes: dl-param - name: param-name type: string - value: 81 - - # TODO: fill in the attributes in between - + - + name: param-generic + type: flag - name: param-type type: u8 - value: 83 # TODO: fill in the attributes in between @@ -458,20 +509,34 @@ attribute-sets: - name: region-name type: string - - # TODO: fill in the attributes in between - + - + name: region-size + type: u64 + - + name: region-snapshots + type: nest + nested-attributes: dl-region-snapshots + - + name: region-snapshot + type: nest + nested-attributes: dl-region-snapshot - name: region-snapshot-id type: u32 - value: 92 - - # TODO: fill in the attributes in between - + - + name: region-chunks + type: nest + nested-attributes: dl-region-chunks + - + name: region-chunk + type: nest + nested-attributes: dl-region-chunk + - + name: region-chunk-data + type: binary - name: region-chunk-addr type: u64 - value: 96 - name: region-chunk-len type: u64 @@ -502,14 +567,13 @@ attribute-sets: - name: info-version-value type: string - - # TODO: fill in the attributes in between - + - + name: sb-pool-cell-size + type: u32 - name: fmsg type: nest nested-attributes: dl-fmsg - value: 106 - name: fmsg-obj-nest-start type: flag @@ -525,20 +589,35 @@ attribute-sets: - name: fmsg-obj-name type: string + - + name: fmsg-obj-value-type + type: u8 # TODO: fill in the attributes in between + - + name: health-reporter + type: nest + value: 114 + nested-attributes: dl-health-reporter - name: health-reporter-name type: string - value: 115 - - # TODO: fill in the attributes in between - + - + name: health-reporter-state + type: u8 + - + name: health-reporter-err-count + type: u64 + - + name: health-reporter-recover-count + type: u64 + - + name: health-reporter-dump-ts + type: u64 - name: health-reporter-graceful-period type: u64 - value: 120 - name: health-reporter-auto-recover type: u8 @@ -548,55 +627,64 @@ attribute-sets: - name: flash-update-component type: string - - # TODO: fill in the attributes in between - + - + name: flash-update-status-msg + type: string + - + name: flash-update-status-done + type: u64 + - + name: flash-update-status-total + type: u64 - name: port-pci-pf-number type: u16 - value: 127 - - # TODO: fill in the attributes in between - + - + name: port-pci-vf-number + type: u16 + - + name: stats + type: nest + nested-attributes: dl-attr-stats - name: trap-name type: string - value: 130 - name: trap-action type: u8 enum: trap-action - - # TODO: fill in the attributes in between - + - + name: trap-type + type: u8 + enum: trap-type + - + name: trap-generic + type: flag + - + name: trap-metadata + type: nest + nested-attributes: dl-trap-metadata - name: trap-group-name type: string - value: 135 - - name: reload-failed type: u8 - - # TODO: fill in the attributes in between - + - + name: health-reporter-dump-ts-ns + type: u64 - name: netns-fd type: u32 - value: 138 - name: netns-pid type: u32 - name: netns-id type: u32 - - # TODO: fill in the attributes in between - - name: health-reporter-auto-dump type: u8 - value: 141 - name: trap-policer-id type: u32 @@ -610,22 +698,29 @@ attribute-sets: name: port-function type: nest nested-attributes: dl-port-function - - # TODO: fill in the attributes in between - + - + name: info-board-serial-number + type: string + - + name: port-lanes + type: u32 + - + name: port-splittable + type: u8 + - + name: port-external + type: u8 - name: port-controller-number type: u32 - value: 150 - - # TODO: fill in the attributes in between - + - + name: flash-update-status-timeout + type: u64 - name: flash-update-overwrite-mask type: bitfield32 enum: flash-overwrite enum-as-flags: True - value: 152 - name: reload-action type: u8 @@ -673,20 +768,16 @@ attribute-sets: type: nest multi-attr: true nested-attributes: dl-reload-act-stats - - # TODO: fill in the attributes in between - - name: port-pci-sf-number type: u32 - value: 164 - - # TODO: fill in the attributes in between - + - + name: rate-type + type: u16 + enum: rate-type - name: rate-tx-share type: u64 - value: 166 - name: rate-tx-max type: u64 @@ -696,20 +787,22 @@ attribute-sets: - name: rate-parent-node-name type: string - - # TODO: fill in the attributes in between - + - + name: region-max-snapshots + type: u32 - name: linecard-index type: u32 - value: 171 - - # TODO: fill in the attributes in between - + - + name: linecard-state + type: u8 - name: linecard-type type: string - value: 173 + - + name: linecard-supported-types + type: nest + nested-attributes: dl-linecard-supported-types # TODO: fill in the attributes in between @@ -736,12 +829,14 @@ attribute-sets: name: reload-stats - name: remote-reload-stats + - name: dl-reload-stats subset-of: devlink attributes: - name: reload-action-info + - name: dl-reload-act-info subset-of: devlink @@ -750,12 +845,14 @@ attribute-sets: name: reload-action - name: reload-action-stats + - name: dl-reload-act-stats subset-of: devlink attributes: - name: reload-stats-entry + - name: dl-reload-stats-entry subset-of: devlink @@ -764,6 +861,7 @@ attribute-sets: name: reload-stats-limit - name: reload-stats-value + - name: dl-info-version subset-of: devlink @@ -772,6 +870,7 @@ attribute-sets: name: info-version-name - name: info-version-value + - name: dl-port-function name-prefix: devlink-port-fn-attr- @@ -1005,6 +1104,49 @@ attribute-sets: - name: resource + - + name: dl-param + subset-of: devlink + attributes: + - + name: param-name + - + name: param-generic + - + name: param-type + + # TODO: fill in the attribute param-value-list + + - + name: dl-region-snapshots + subset-of: devlink + attributes: + - + name: region-snapshot + + - + name: dl-region-snapshot + subset-of: devlink + attributes: + - + name: region-snapshot-id + + - + name: dl-region-chunks + subset-of: devlink + attributes: + - + name: region-chunk + + - + name: dl-region-chunk + subset-of: devlink + attributes: + - + name: region-chunk-data + - + name: region-chunk-addr + - name: dl-fmsg subset-of: devlink @@ -1020,6 +1162,62 @@ attribute-sets: - name: fmsg-obj-name + - + name: dl-health-reporter + subset-of: devlink + attributes: + - + name: health-reporter-name + - + name: health-reporter-state + - + name: health-reporter-err-count + - + name: health-reporter-recover-count + - + name: health-reporter-graceful-period + - + name: health-reporter-auto-recover + - + name: health-reporter-dump-ts + - + name: health-reporter-dump-ts-ns + - + name: health-reporter-auto-dump + + - + name: dl-attr-stats + name-prefix: devlink-attr- + attributes: + - name: stats-rx-packets + type: u64 + value: 0 + - + name: stats-rx-bytes + type: u64 + - + name: stats-rx-dropped + type: u64 + + - + name: dl-trap-metadata + name-prefix: devlink-attr- + attributes: + - + name: trap-metadata-type-in-port + type: flag + value: 0 + - + name: trap-metadata-type-fa-cookie + type: flag + + - + name: dl-linecard-supported-types + subset-of: devlink + attributes: + - + name: linecard-type + - name: dl-selftest-id name-prefix: devlink-attr-selftest-id- @@ -1077,6 +1275,7 @@ operations: reply: value: 3 # due to a bug, port dump returns DEVLINK_CMD_NEW attributes: *port-id-attrs + - name: port-set doc: Set devlink port instances. @@ -1484,8 +1683,8 @@ operations: dont-validate: [ strict ] flags: [ admin-perm ] do: - pre: devlink-nl-pre-doit - post: devlink-nl-post-doit + pre: devlink-nl-pre-doit-dev-lock + post: devlink-nl-post-doit-dev-lock request: attributes: - bus-name @@ -2055,3 +2254,14 @@ operations: - bus-name - dev-name - selftests + + - + name: notify-filter-set + doc: Set notification messages socket filter. + attribute-set: devlink + do: + request: + attributes: + - bus-name + - dev-name + - port-index diff --git a/Documentation/netlink/specs/dpll.yaml b/Documentation/netlink/specs/dpll.yaml index cf8abe1c0550fc..b14aed18065f43 100644 --- a/Documentation/netlink/specs/dpll.yaml +++ b/Documentation/netlink/specs/dpll.yaml @@ -296,6 +296,16 @@ attribute-sets: - name: phase-offset type: s64 + - + name: fractional-frequency-offset + type: sint + doc: | + The FFO (Fractional Frequency Offset) between the RX and TX + symbol rate on the media associated with the pin: + (rx_frequency-tx_frequency)/rx_frequency + Value is in PPM (parts per million). + This may be implemented for example for pin of type + PIN_TYPE_SYNCE_ETH_PORT. - name: pin-parent-device subset-of: pin @@ -460,6 +470,7 @@ operations: - phase-adjust-min - phase-adjust-max - phase-adjust + - fractional-frequency-offset dump: pre: dpll-lock-dumpit diff --git a/Documentation/netlink/specs/ethtool.yaml b/Documentation/netlink/specs/ethtool.yaml index 5c7a65b009b429..197208f419dce6 100644 --- a/Documentation/netlink/specs/ethtool.yaml +++ b/Documentation/netlink/specs/ethtool.yaml @@ -908,6 +908,9 @@ attribute-sets: - name: hkey type: binary + - + name: input_xfrm + type: u32 - name: plca attributes: @@ -1598,6 +1601,7 @@ operations: - hfunc - indir - hkey + - input_xfrm dump: *rss-get-op - name: plca-get-cfg diff --git a/Documentation/netlink/specs/mptcp.yaml b/Documentation/netlink/specs/mptcp.yaml deleted file mode 100644 index 49f90cfb469894..00000000000000 --- a/Documentation/netlink/specs/mptcp.yaml +++ /dev/null @@ -1,393 +0,0 @@ -# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) - -name: mptcp_pm -protocol: genetlink-legacy -doc: Multipath TCP. - -c-family-name: mptcp-pm-name -c-version-name: mptcp-pm-ver -max-by-define: true -kernel-policy: per-op -cmd-cnt-name: --mptcp-pm-cmd-after-last - -definitions: - - - type: enum - name: event-type - enum-name: mptcp-event-type - name-prefix: mptcp-event- - entries: - - - name: unspec - doc: unused event - - - name: created - doc: - token, family, saddr4 | saddr6, daddr4 | daddr6, sport, dport - A new MPTCP connection has been created. It is the good time to - allocate memory and send ADD_ADDR if needed. Depending on the - traffic-patterns it can take a long time until the - MPTCP_EVENT_ESTABLISHED is sent. - - - name: established - doc: - token, family, saddr4 | saddr6, daddr4 | daddr6, sport, dport - A MPTCP connection is established (can start new subflows). - - - name: closed - doc: - token - A MPTCP connection has stopped. - - - name: announced - value: 6 - doc: - token, rem_id, family, daddr4 | daddr6 [, dport] - A new address has been announced by the peer. - - - name: removed - doc: - token, rem_id - An address has been lost by the peer. - - - name: sub-established - value: 10 - doc: - token, family, loc_id, rem_id, saddr4 | saddr6, daddr4 | daddr6, sport, - dport, backup, if_idx [, error] - A new subflow has been established. 'error' should not be set. - - - name: sub-closed - doc: - token, family, loc_id, rem_id, saddr4 | saddr6, daddr4 | daddr6, sport, - dport, backup, if_idx [, error] - A subflow has been closed. An error (copy of sk_err) could be set if an - error has been detected for this subflow. - - - name: sub-priority - value: 13 - doc: - token, family, loc_id, rem_id, saddr4 | saddr6, daddr4 | daddr6, sport, - dport, backup, if_idx [, error] - The priority of a subflow has changed. 'error' should not be set. - - - name: listener-created - value: 15 - doc: - family, sport, saddr4 | saddr6 - A new PM listener is created. - - - name: listener-closed - doc: - family, sport, saddr4 | saddr6 - A PM listener is closed. - -attribute-sets: - - - name: address - name-prefix: mptcp-pm-addr-attr- - attributes: - - - name: unspec - type: unused - value: 0 - - - name: family - type: u16 - - - name: id - type: u8 - - - name: addr4 - type: u32 - byte-order: big-endian - - - name: addr6 - type: binary - checks: - exact-len: 16 - - - name: port - type: u16 - byte-order: big-endian - - - name: flags - type: u32 - - - name: if-idx - type: s32 - - - name: subflow-attribute - name-prefix: mptcp-subflow-attr- - attributes: - - - name: unspec - type: unused - value: 0 - - - name: token-rem - type: u32 - - - name: token-loc - type: u32 - - - name: relwrite-seq - type: u32 - - - name: map-seq - type: u64 - - - name: map-sfseq - type: u32 - - - name: ssn-offset - type: u32 - - - name: map-datalen - type: u16 - - - name: flags - type: u32 - - - name: id-rem - type: u8 - - - name: id-loc - type: u8 - - - name: pad - type: pad - - - name: endpoint - name-prefix: mptcp-pm-endpoint- - attributes: - - - name: addr - type: nest - nested-attributes: address - - - name: attr - name-prefix: mptcp-pm-attr- - attr-cnt-name: --mptcp-attr-after-last - attributes: - - - name: unspec - type: unused - value: 0 - - - name: addr - type: nest - nested-attributes: address - - - name: rcv-add-addrs - type: u32 - - - name: subflows - type: u32 - - - name: token - type: u32 - - - name: loc-id - type: u8 - - - name: addr-remote - type: nest - nested-attributes: address - - - name: event-attr - enum-name: mptcp-event-attr - name-prefix: mptcp-attr- - attributes: - - - name: unspec - type: unused - value: 0 - - - name: token - type: u32 - - - name: family - type: u16 - - - name: loc-id - type: u8 - - - name: rem-id - type: u8 - - - name: saddr4 - type: u32 - byte-order: big-endian - - - name: saddr6 - type: binary - checks: - min-len: 16 - - - name: daddr4 - type: u32 - byte-order: big-endian - - - name: daddr6 - type: binary - checks: - min-len: 16 - - - name: sport - type: u16 - byte-order: big-endian - - - name: dport - type: u16 - byte-order: big-endian - - - name: backup - type: u8 - - - name: error - type: u8 - - - name: flags - type: u16 - - - name: timeout - type: u32 - - - name: if_idx - type: u32 - - - name: reset-reason - type: u32 - - - name: reset-flags - type: u32 - - - name: server-side - type: u8 - -operations: - list: - - - name: unspec - doc: unused - value: 0 - - - name: add-addr - doc: Add endpoint - attribute-set: endpoint - dont-validate: [ strict ] - flags: [ uns-admin-perm ] - do: &add-addr-attrs - request: - attributes: - - addr - - - name: del-addr - doc: Delete endpoint - attribute-set: endpoint - dont-validate: [ strict ] - flags: [ uns-admin-perm ] - do: *add-addr-attrs - - - name: get-addr - doc: Get endpoint information - attribute-set: endpoint - dont-validate: [ strict ] - flags: [ uns-admin-perm ] - do: &get-addr-attrs - request: - attributes: - - addr - reply: - attributes: - - addr - dump: - reply: - attributes: - - addr - - - name: flush-addrs - doc: flush addresses - attribute-set: endpoint - dont-validate: [ strict ] - flags: [ uns-admin-perm ] - do: *add-addr-attrs - - - name: set-limits - doc: Set protocol limits - attribute-set: attr - dont-validate: [ strict ] - flags: [ uns-admin-perm ] - do: &mptcp-limits - request: - attributes: - - rcv-add-addrs - - subflows - - - name: get-limits - doc: Get protocol limits - attribute-set: attr - dont-validate: [ strict ] - do: &mptcp-get-limits - request: - attributes: - - rcv-add-addrs - - subflows - reply: - attributes: - - rcv-add-addrs - - subflows - - - name: set-flags - doc: Change endpoint flags - attribute-set: attr - dont-validate: [ strict ] - flags: [ uns-admin-perm ] - do: &mptcp-set-flags - request: - attributes: - - addr - - token - - addr-remote - - - name: announce - doc: announce new sf - attribute-set: attr - dont-validate: [ strict ] - flags: [ uns-admin-perm ] - do: &announce-add - request: - attributes: - - addr - - token - - - name: remove - doc: announce removal - attribute-set: attr - dont-validate: [ strict ] - flags: [ uns-admin-perm ] - do: - request: - attributes: - - token - - loc-id - - - name: subflow-create - doc: todo - attribute-set: attr - dont-validate: [ strict ] - flags: [ uns-admin-perm ] - do: &sf-create - request: - attributes: - - addr - - token - - addr-remote - - - name: subflow-destroy - doc: todo - attribute-set: attr - dont-validate: [ strict ] - flags: [ uns-admin-perm ] - do: *sf-create diff --git a/Documentation/netlink/specs/mptcp_pm.yaml b/Documentation/netlink/specs/mptcp_pm.yaml new file mode 100644 index 00000000000000..49f90cfb469894 --- /dev/null +++ b/Documentation/netlink/specs/mptcp_pm.yaml @@ -0,0 +1,393 @@ +# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) + +name: mptcp_pm +protocol: genetlink-legacy +doc: Multipath TCP. + +c-family-name: mptcp-pm-name +c-version-name: mptcp-pm-ver +max-by-define: true +kernel-policy: per-op +cmd-cnt-name: --mptcp-pm-cmd-after-last + +definitions: + - + type: enum + name: event-type + enum-name: mptcp-event-type + name-prefix: mptcp-event- + entries: + - + name: unspec + doc: unused event + - + name: created + doc: + token, family, saddr4 | saddr6, daddr4 | daddr6, sport, dport + A new MPTCP connection has been created. It is the good time to + allocate memory and send ADD_ADDR if needed. Depending on the + traffic-patterns it can take a long time until the + MPTCP_EVENT_ESTABLISHED is sent. + - + name: established + doc: + token, family, saddr4 | saddr6, daddr4 | daddr6, sport, dport + A MPTCP connection is established (can start new subflows). + - + name: closed + doc: + token + A MPTCP connection has stopped. + - + name: announced + value: 6 + doc: + token, rem_id, family, daddr4 | daddr6 [, dport] + A new address has been announced by the peer. + - + name: removed + doc: + token, rem_id + An address has been lost by the peer. + - + name: sub-established + value: 10 + doc: + token, family, loc_id, rem_id, saddr4 | saddr6, daddr4 | daddr6, sport, + dport, backup, if_idx [, error] + A new subflow has been established. 'error' should not be set. + - + name: sub-closed + doc: + token, family, loc_id, rem_id, saddr4 | saddr6, daddr4 | daddr6, sport, + dport, backup, if_idx [, error] + A subflow has been closed. An error (copy of sk_err) could be set if an + error has been detected for this subflow. + - + name: sub-priority + value: 13 + doc: + token, family, loc_id, rem_id, saddr4 | saddr6, daddr4 | daddr6, sport, + dport, backup, if_idx [, error] + The priority of a subflow has changed. 'error' should not be set. + - + name: listener-created + value: 15 + doc: + family, sport, saddr4 | saddr6 + A new PM listener is created. + - + name: listener-closed + doc: + family, sport, saddr4 | saddr6 + A PM listener is closed. + +attribute-sets: + - + name: address + name-prefix: mptcp-pm-addr-attr- + attributes: + - + name: unspec + type: unused + value: 0 + - + name: family + type: u16 + - + name: id + type: u8 + - + name: addr4 + type: u32 + byte-order: big-endian + - + name: addr6 + type: binary + checks: + exact-len: 16 + - + name: port + type: u16 + byte-order: big-endian + - + name: flags + type: u32 + - + name: if-idx + type: s32 + - + name: subflow-attribute + name-prefix: mptcp-subflow-attr- + attributes: + - + name: unspec + type: unused + value: 0 + - + name: token-rem + type: u32 + - + name: token-loc + type: u32 + - + name: relwrite-seq + type: u32 + - + name: map-seq + type: u64 + - + name: map-sfseq + type: u32 + - + name: ssn-offset + type: u32 + - + name: map-datalen + type: u16 + - + name: flags + type: u32 + - + name: id-rem + type: u8 + - + name: id-loc + type: u8 + - + name: pad + type: pad + - + name: endpoint + name-prefix: mptcp-pm-endpoint- + attributes: + - + name: addr + type: nest + nested-attributes: address + - + name: attr + name-prefix: mptcp-pm-attr- + attr-cnt-name: --mptcp-attr-after-last + attributes: + - + name: unspec + type: unused + value: 0 + - + name: addr + type: nest + nested-attributes: address + - + name: rcv-add-addrs + type: u32 + - + name: subflows + type: u32 + - + name: token + type: u32 + - + name: loc-id + type: u8 + - + name: addr-remote + type: nest + nested-attributes: address + - + name: event-attr + enum-name: mptcp-event-attr + name-prefix: mptcp-attr- + attributes: + - + name: unspec + type: unused + value: 0 + - + name: token + type: u32 + - + name: family + type: u16 + - + name: loc-id + type: u8 + - + name: rem-id + type: u8 + - + name: saddr4 + type: u32 + byte-order: big-endian + - + name: saddr6 + type: binary + checks: + min-len: 16 + - + name: daddr4 + type: u32 + byte-order: big-endian + - + name: daddr6 + type: binary + checks: + min-len: 16 + - + name: sport + type: u16 + byte-order: big-endian + - + name: dport + type: u16 + byte-order: big-endian + - + name: backup + type: u8 + - + name: error + type: u8 + - + name: flags + type: u16 + - + name: timeout + type: u32 + - + name: if_idx + type: u32 + - + name: reset-reason + type: u32 + - + name: reset-flags + type: u32 + - + name: server-side + type: u8 + +operations: + list: + - + name: unspec + doc: unused + value: 0 + - + name: add-addr + doc: Add endpoint + attribute-set: endpoint + dont-validate: [ strict ] + flags: [ uns-admin-perm ] + do: &add-addr-attrs + request: + attributes: + - addr + - + name: del-addr + doc: Delete endpoint + attribute-set: endpoint + dont-validate: [ strict ] + flags: [ uns-admin-perm ] + do: *add-addr-attrs + - + name: get-addr + doc: Get endpoint information + attribute-set: endpoint + dont-validate: [ strict ] + flags: [ uns-admin-perm ] + do: &get-addr-attrs + request: + attributes: + - addr + reply: + attributes: + - addr + dump: + reply: + attributes: + - addr + - + name: flush-addrs + doc: flush addresses + attribute-set: endpoint + dont-validate: [ strict ] + flags: [ uns-admin-perm ] + do: *add-addr-attrs + - + name: set-limits + doc: Set protocol limits + attribute-set: attr + dont-validate: [ strict ] + flags: [ uns-admin-perm ] + do: &mptcp-limits + request: + attributes: + - rcv-add-addrs + - subflows + - + name: get-limits + doc: Get protocol limits + attribute-set: attr + dont-validate: [ strict ] + do: &mptcp-get-limits + request: + attributes: + - rcv-add-addrs + - subflows + reply: + attributes: + - rcv-add-addrs + - subflows + - + name: set-flags + doc: Change endpoint flags + attribute-set: attr + dont-validate: [ strict ] + flags: [ uns-admin-perm ] + do: &mptcp-set-flags + request: + attributes: + - addr + - token + - addr-remote + - + name: announce + doc: announce new sf + attribute-set: attr + dont-validate: [ strict ] + flags: [ uns-admin-perm ] + do: &announce-add + request: + attributes: + - addr + - token + - + name: remove + doc: announce removal + attribute-set: attr + dont-validate: [ strict ] + flags: [ uns-admin-perm ] + do: + request: + attributes: + - token + - loc-id + - + name: subflow-create + doc: todo + attribute-set: attr + dont-validate: [ strict ] + flags: [ uns-admin-perm ] + do: &sf-create + request: + attributes: + - addr + - token + - addr-remote + - + name: subflow-destroy + doc: todo + attribute-set: attr + dont-validate: [ strict ] + flags: [ uns-admin-perm ] + do: *sf-create diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml index 14511b13f305dc..3addac97068048 100644 --- a/Documentation/netlink/specs/netdev.yaml +++ b/Documentation/netlink/specs/netdev.yaml @@ -45,7 +45,6 @@ definitions: - type: flags name: xdp-rx-metadata - render-max: true entries: - name: timestamp @@ -55,6 +54,26 @@ definitions: name: hash doc: Device is capable of exposing receive packet hash via bpf_xdp_metadata_rx_hash(). + - + name: vlan-tag + doc: + Device is capable of exposing receive packet VLAN tag via bpf_xdp_metadata_rx_vlan_tag(). + - + type: flags + name: xsk-flags + entries: + - + name: tx-timestamp + doc: + HW timestamping egress packets is supported by the driver. + - + name: tx-checksum + doc: + L3 checksum HW offload is supported by the driver. + - + name: queue-type + type: enum + entries: [ rx, tx ] attribute-sets: - @@ -86,6 +105,165 @@ attribute-sets: See Documentation/networking/xdp-rx-metadata.rst for more details. type: u64 enum: xdp-rx-metadata + - + name: xsk-features + doc: Bitmask of enabled AF_XDP features. + type: u64 + enum: xsk-flags + - + name: page-pool + attributes: + - + name: id + doc: Unique ID of a Page Pool instance. + type: uint + checks: + min: 1 + max: u32-max + - + name: ifindex + doc: | + ifindex of the netdev to which the pool belongs. + May be reported as 0 if the page pool was allocated for a netdev + which got destroyed already (page pools may outlast their netdevs + because they wait for all memory to be returned). + type: u32 + checks: + min: 1 + max: s32-max + - + name: napi-id + doc: Id of NAPI using this Page Pool instance. + type: uint + checks: + min: 1 + max: u32-max + - + name: inflight + type: uint + doc: | + Number of outstanding references to this page pool (allocated + but yet to be freed pages). Allocated pages may be held in + socket receive queues, driver receive ring, page pool recycling + ring, the page pool cache, etc. + - + name: inflight-mem + type: uint + doc: | + Amount of memory held by inflight pages. + - + name: detach-time + type: uint + doc: | + Seconds in CLOCK_BOOTTIME of when Page Pool was detached by + the driver. Once detached Page Pool can no longer be used to + allocate memory. + Page Pools wait for all the memory allocated from them to be freed + before truly disappearing. "Detached" Page Pools cannot be + "re-attached", they are just waiting to disappear. + Attribute is absent if Page Pool has not been detached, and + can still be used to allocate new memory. + - + name: page-pool-info + subset-of: page-pool + attributes: + - + name: id + - + name: ifindex + - + name: page-pool-stats + doc: | + Page pool statistics, see docs for struct page_pool_stats + for information about individual statistics. + attributes: + - + name: info + doc: Page pool identifying information. + type: nest + nested-attributes: page-pool-info + - + name: alloc-fast + type: uint + value: 8 # reserve some attr ids in case we need more metadata later + - + name: alloc-slow + type: uint + - + name: alloc-slow-high-order + type: uint + - + name: alloc-empty + type: uint + - + name: alloc-refill + type: uint + - + name: alloc-waive + type: uint + - + name: recycle-cached + type: uint + - + name: recycle-cache-full + type: uint + - + name: recycle-ring + type: uint + - + name: recycle-ring-full + type: uint + - + name: recycle-released-refcnt + type: uint + + - + name: napi + attributes: + - + name: ifindex + doc: ifindex of the netdevice to which NAPI instance belongs. + type: u32 + checks: + min: 1 + - + name: id + doc: ID of the NAPI instance. + type: u32 + - + name: irq + doc: The associated interrupt vector number for the napi + type: u32 + - + name: pid + doc: PID of the napi thread, if NAPI is configured to operate in + threaded mode. If NAPI is not in threaded mode (i.e. uses normal + softirq context), the attribute will be absent. + type: u32 + - + name: queue + attributes: + - + name: id + doc: Queue index; most queue types are indexed like a C array, with + indexes starting at 0 and ending at queue count - 1. Queue indexes + are scoped to an interface and queue type. + type: u32 + - + name: ifindex + doc: ifindex of the netdevice to which the queue belongs. + type: u32 + checks: + min: 1 + - + name: type + doc: Queue type as rx, tx. Each queue type defines a separate ID space. + type: u32 + enum: queue-type + - + name: napi-id + doc: ID of the NAPI instance which services this queue. + type: u32 operations: list: @@ -103,6 +281,7 @@ operations: - xdp-features - xdp-zc-max-segs - xdp-rx-metadata-features + - xsk-features dump: reply: *dev-all - @@ -120,8 +299,116 @@ operations: doc: Notification about device configuration being changed. notify: dev-get mcgrp: mgmt + - + name: page-pool-get + doc: | + Get / dump information about Page Pools. + (Only Page Pools associated with a net_device can be listed.) + attribute-set: page-pool + do: + request: + attributes: + - id + reply: &pp-reply + attributes: + - id + - ifindex + - napi-id + - inflight + - inflight-mem + - detach-time + dump: + reply: *pp-reply + config-cond: page-pool + - + name: page-pool-add-ntf + doc: Notification about page pool appearing. + notify: page-pool-get + mcgrp: page-pool + config-cond: page-pool + - + name: page-pool-del-ntf + doc: Notification about page pool disappearing. + notify: page-pool-get + mcgrp: page-pool + config-cond: page-pool + - + name: page-pool-change-ntf + doc: Notification about page pool configuration being changed. + notify: page-pool-get + mcgrp: page-pool + config-cond: page-pool + - + name: page-pool-stats-get + doc: Get page pool statistics. + attribute-set: page-pool-stats + do: + request: + attributes: + - info + reply: &pp-stats-reply + attributes: + - info + - alloc-fast + - alloc-slow + - alloc-slow-high-order + - alloc-empty + - alloc-refill + - alloc-waive + - recycle-cached + - recycle-cache-full + - recycle-ring + - recycle-ring-full + - recycle-released-refcnt + dump: + reply: *pp-stats-reply + config-cond: page-pool-stats + - + name: queue-get + doc: Get queue information from the kernel. + Only configured queues will be reported (as opposed to all available + hardware queues). + attribute-set: queue + do: + request: + attributes: + - ifindex + - type + - id + reply: &queue-get-op + attributes: + - id + - type + - napi-id + - ifindex + dump: + request: + attributes: + - ifindex + reply: *queue-get-op + - + name: napi-get + doc: Get information about NAPI instances configured on the system. + attribute-set: napi + do: + request: + attributes: + - id + reply: &napi-get-op + attributes: + - id + - ifindex + - irq + - pid + dump: + request: + attributes: + - ifindex + reply: *napi-get-op mcast-groups: list: - name: mgmt + - + name: page-pool diff --git a/Documentation/netlink/specs/ovs_datapath.yaml b/Documentation/netlink/specs/ovs_datapath.yaml index f709c26c3e92d4..edc8c95ca6f5ca 100644 --- a/Documentation/netlink/specs/ovs_datapath.yaml +++ b/Documentation/netlink/specs/ovs_datapath.yaml @@ -20,6 +20,7 @@ definitions: name: user-features type: flags name-prefix: ovs-dp-f- + enum-name: entries: - name: unaligned @@ -142,7 +143,6 @@ operations: do: request: attributes: - - dp-ifindex - name - upcall-pid - user-features @@ -154,7 +154,6 @@ operations: do: request: attributes: - - dp-ifindex - name mcast-groups: diff --git a/Documentation/netlink/specs/ovs_flow.yaml b/Documentation/netlink/specs/ovs_flow.yaml index 109ca1f57b6c6f..4fdfc6b5cae952 100644 --- a/Documentation/netlink/specs/ovs_flow.yaml +++ b/Documentation/netlink/specs/ovs_flow.yaml @@ -124,6 +124,7 @@ definitions: - name: ovs-frag-type name-prefix: ovs-frag-type- + enum-name: ovs-frag-type type: enum entries: - @@ -269,6 +270,7 @@ definitions: - name: ovs-ufid-flags name-prefix: ovs-ufid-f- + enum-name: type: flags entries: - omit-key @@ -288,6 +290,7 @@ definitions: doc: Basis used for computing hash. - name: ovs-hash-alg + enum-name: ovs-hash-alg type: enum doc: | Data path hash algorithm for computing Datapath hash. The algorithm type only specifies @@ -339,6 +342,7 @@ definitions: MPLS tunnel attributes. - name: ct-state-flags + enum-name: type: flags name-prefix: ovs-cs-f- entries: @@ -947,13 +951,11 @@ operations: do: &flow-get-op request: attributes: - - dp-ifindex - key - ufid - ufid-flags reply: attributes: - - dp-ifindex - key - ufid - mask @@ -968,7 +970,6 @@ operations: do: request: attributes: - - dp-ifindex - key - ufid - mask diff --git a/Documentation/netlink/specs/ovs_vport.yaml b/Documentation/netlink/specs/ovs_vport.yaml index f65ce62cd60de1..86ba9ac2a52103 100644 --- a/Documentation/netlink/specs/ovs_vport.yaml +++ b/Documentation/netlink/specs/ovs_vport.yaml @@ -135,7 +135,6 @@ operations: - name - type - upcall-pid - - dp-ifindex - ifindex - options - @@ -146,7 +145,6 @@ operations: do: request: attributes: - - dp-ifindex - port-no - type - name @@ -158,11 +156,9 @@ operations: do: &vport-get-op request: attributes: - - dp-ifindex - name reply: &dev-all attributes: - - dp-ifindex - port-no - type - name diff --git a/Documentation/netlink/specs/rt_link.yaml b/Documentation/netlink/specs/rt_link.yaml index d86a68f8475ca8..1ad01d52a8638d 100644 --- a/Documentation/netlink/specs/rt_link.yaml +++ b/Documentation/netlink/specs/rt_link.yaml @@ -66,8 +66,9 @@ definitions: name: ifi-family type: u8 - - name: padding - type: u8 + name: pad + type: pad + len: 1 - name: ifi-type type: u16 @@ -82,6 +83,18 @@ definitions: - name: ifi-change type: u32 + - + name: ifla-bridge-id + type: struct + members: + - + name: prio + type: u16 + - + name: addr + type: binary + len: 6 + display-hint: mac - name: ifla-cacheinfo type: struct @@ -707,11 +720,9 @@ definitions: name: family type: u8 - - name: pad1 - type: u8 - - - name: pad2 - type: u16 + name: pad + type: pad + len: 3 - name: ifindex type: u32 @@ -966,8 +977,9 @@ attribute-sets: type: string - name: data - type: binary - # kind specific nest, e.g. linkinfo-bridge-attrs + type: sub-message + sub-message: linkinfo-data-msg + selector: kind - name: xstats type: binary @@ -976,10 +988,12 @@ attribute-sets: type: string - name: slave-data - type: binary - # kind specific nest + type: sub-message + sub-message: linkinfo-member-data-msg + selector: slave-kind - name: linkinfo-bridge-attrs + name-prefix: ifla-br- attributes: - name: forward-delay @@ -1011,9 +1025,11 @@ attribute-sets: - name: root-id type: binary + struct: ifla-bridge-id - name: bridge-id type: binary + struct: ifla-bridge-id - name: root-port type: u16 @@ -1041,6 +1057,7 @@ attribute-sets: - name: group-addr type: binary + display-hint: mac - name: fdb-flush type: binary @@ -1123,6 +1140,376 @@ attribute-sets: - name: mcast-querier-state type: binary + - + name: linkinfo-brport-attrs + name-prefix: ifla-brport- + attributes: + - + name: state + type: u8 + - + name: priority + type: u16 + - + name: cost + type: u32 + - + name: mode + type: flag + - + name: guard + type: flag + - + name: protect + type: flag + - + name: fast-leave + type: flag + - + name: learning + type: flag + - + name: unicast-flood + type: flag + - + name: proxyarp + type: flag + - + name: learning-sync + type: flag + - + name: proxyarp-wifi + type: flag + - + name: root-id + type: binary + struct: ifla-bridge-id + - + name: bridge-id + type: binary + struct: ifla-bridge-id + - + name: designated-port + type: u16 + - + name: designated-cost + type: u16 + - + name: id + type: u16 + - + name: "no" + type: u16 + - + name: topology-change-ack + type: u8 + - + name: config-pending + type: u8 + - + name: message-age-timer + type: u64 + - + name: forward-delay-timer + type: u64 + - + name: hold-timer + type: u64 + - + name: flush + type: flag + - + name: multicast-router + type: u8 + - + name: pad + type: pad + - + name: mcast-flood + type: flag + - + name: mcast-to-ucast + type: flag + - + name: vlan-tunnel + type: flag + - + name: bcast-flood + type: flag + - + name: group-fwd-mask + type: u16 + - + name: neigh-suppress + type: flag + - + name: isolated + type: flag + - + name: backup-port + type: u32 + - + name: mrp-ring-open + type: flag + - + name: mrp-in-open + type: flag + - + name: mcast-eht-hosts-limit + type: u32 + - + name: mcast-eht-hosts-cnt + type: u32 + - + name: locked + type: flag + - + name: mab + type: flag + - + name: mcast-n-groups + type: u32 + - + name: mcast-max-groups + type: u32 + - + name: neigh-vlan-suppress + type: flag + - + name: backup-nhid + type: u32 + - + name: linkinfo-gre-attrs + name-prefix: ifla-gre- + attributes: + - + name: link + type: u32 + - + name: iflags + type: u16 + - + name: oflags + type: u16 + - + name: ikey + type: u32 + - + name: okey + type: u32 + - + name: local + type: binary + display-hint: ipv4 + - + name: remote + type: binary + display-hint: ipv4 + - + name: ttl + type: u8 + - + name: tos + type: u8 + - + name: pmtudisc + type: u8 + - + name: encap-limit + type: u32 + - + name: flowinfo + type: u32 + - + name: flags + type: u32 + - + name: encap-type + type: u16 + - + name: encap-flags + type: u16 + - + name: encap-sport + type: u16 + - + name: encap-dport + type: u16 + - + name: collect-metadata + type: flag + - + name: ignore-df + type: u8 + - + name: fwmark + type: u32 + - + name: erspan-index + type: u32 + - + name: erspan-ver + type: u8 + - + name: erspan-dir + type: u8 + - + name: erspan-hwid + type: u16 + - + name: linkinfo-geneve-attrs + name-prefix: ifla-geneve- + attributes: + - + name: id + type: u32 + - + name: remote + type: binary + display-hint: ipv4 + - + name: ttl + type: u8 + - + name: tos + type: u8 + - + name: port + type: u16 + - + name: collect-metadata + type: flag + - + name: remote6 + type: binary + display-hint: ipv6 + - + name: udp-csum + type: u8 + - + name: udp-zero-csum6-tx + type: u8 + - + name: udp-zero-csum6-rx + type: u8 + - + name: label + type: u32 + - + name: ttl-inherit + type: u8 + - + name: df + type: u8 + - + name: inner-proto-inherit + type: flag + - + name: linkinfo-iptun-attrs + name-prefix: ifla-iptun- + attributes: + - + name: link + type: u32 + - + name: local + type: binary + display-hint: ipv4 + - + name: remote + type: binary + display-hint: ipv4 + - + name: ttl + type: u8 + - + name: tos + type: u8 + - + name: encap-limit + type: u8 + - + name: flowinfo + type: u32 + - + name: flags + type: u16 + - + name: proto + type: u8 + - + name: pmtudisc + type: u8 + - + name: 6rd-prefix + type: binary + display-hint: ipv6 + - + name: 6rd-relay-prefix + type: binary + display-hint: ipv4 + - + name: 6rd-prefixlen + type: u16 + - + name: 6rd-relay-prefixlen + type: u16 + - + name: encap-type + type: u16 + - + name: encap-flags + type: u16 + - + name: encap-sport + type: u16 + - + name: encap-dport + type: u16 + - + name: collect-metadata + type: flag + - + name: fwmark + type: u32 + - + name: linkinfo-tun-attrs + name-prefix: ifla-tun- + attributes: + - + name: owner + type: u32 + - + name: group + type: u32 + - + name: type + type: u8 + - + name: pi + type: u8 + - + name: vnet-hdr + type: u8 + - + name: persist + type: u8 + - + name: multi-queue + type: u8 + - + name: num-queues + type: u32 + - + name: num-disabled-queues + type: u32 + - + name: linkinfo-vrf-attrs + name-prefix: ifla-vrf- + attributes: + - + name: table + type: u32 - name: xdp-attrs attributes: @@ -1241,6 +1628,46 @@ attribute-sets: name: used type: u8 +sub-messages: + - + name: linkinfo-data-msg + formats: + - + value: bridge + attribute-set: linkinfo-bridge-attrs + - + value: erspan + attribute-set: linkinfo-gre-attrs + - + value: gre + attribute-set: linkinfo-gre-attrs + - + value: gretap + attribute-set: linkinfo-gre-attrs + - + value: geneve + attribute-set: linkinfo-geneve-attrs + - + value: ipip + attribute-set: linkinfo-iptun-attrs + - + value: sit + attribute-set: linkinfo-iptun-attrs + - + value: tun + attribute-set: linkinfo-tun-attrs + - + value: vrf + attribute-set: linkinfo-vrf-attrs + - + name: linkinfo-member-data-msg + formats: + - + value: bridge + attribute-set: linkinfo-brport-attrs + - + value: bond + operations: enum-model: directional list: diff --git a/Documentation/netlink/specs/tc.yaml b/Documentation/netlink/specs/tc.yaml new file mode 100644 index 00000000000000..4346fa402fc91d --- /dev/null +++ b/Documentation/netlink/specs/tc.yaml @@ -0,0 +1,2031 @@ +# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) + +name: tc +protocol: netlink-raw +protonum: 0 + +doc: + Netlink raw family for tc qdisc, chain, class and filter configuration + over rtnetlink. + +definitions: + - + name: tcmsg + type: struct + members: + - + name: family + type: u8 + - + name: pad + type: pad + len: 3 + - + name: ifindex + type: s32 + - + name: handle + type: u32 + - + name: parent + type: u32 + - + name: info + type: u32 + - + name: tc-cls-flags + type: flags + entries: + - skip-hw + - skip-sw + - in-hw + - not-in-nw + - verbose + - + name: tc-stats + type: struct + members: + - + name: bytes + type: u64 + - + name: packets + type: u32 + - + name: drops + type: u32 + - + name: overlimits + type: u32 + - + name: bps + type: u32 + - + name: pps + type: u32 + - + name: qlen + type: u32 + - + name: backlog + type: u32 + - + name: tc-cbs-qopt + type: struct + members: + - + name: offload + type: u8 + - + name: pad + type: pad + len: 3 + - + name: hicredit + type: s32 + - + name: locredit + type: s32 + - + name: idleslope + type: s32 + - + name: sendslope + type: s32 + - + name: tc-etf-qopt + type: struct + members: + - + name: delta + type: s32 + - + name: clockid + type: s32 + - + name: flags + type: s32 + - + name: tc-fifo-qopt + type: struct + members: + - + name: limit + type: u32 + - + name: tc-htb-opt + type: struct + members: + - + name: rate + type: binary + len: 12 + - + name: ceil + type: binary + len: 12 + - + name: buffer + type: u32 + - + name: cbuffer + type: u32 + - + name: quantum + type: u32 + - + name: level + type: u32 + - + name: prio + type: u32 + - + name: tc-htb-glob + type: struct + members: + - + name: version + type: u32 + - + name: rate2quantum + type: u32 + - + name: defcls + type: u32 + - + name: debug + type: u32 + - + name: direct-pkts + type: u32 + - + name: tc-gred-qopt + type: struct + members: + - + name: limit + type: u32 + - + name: qth-min + type: u32 + - + name: qth-max + type: u32 + - + name: DP + type: u32 + - + name: backlog + type: u32 + - + name: qave + type: u32 + - + name: forced + type: u32 + - + name: early + type: u32 + - + name: other + type: u32 + - + name: pdrop + type: u32 + - + name: Wlog + type: u8 + - + name: Plog + type: u8 + - + name: Scell_log + type: u8 + - + name: prio + type: u8 + - + name: packets + type: u32 + - + name: bytesin + type: u32 + - + name: tc-gred-sopt + type: struct + members: + - + name: DPs + type: u32 + - + name: def_DP + type: u32 + - + name: grio + type: u8 + - + name: flags + type: u8 + - + name: pad + type: pad + len: 2 + - + name: tc-hfsc-qopt + type: struct + members: + - + name: defcls + type: u16 + - + name: tc-mqprio-qopt + type: struct + members: + - + name: num-tc + type: u8 + - + name: prio-tc-map + type: binary + len: 16 + - + name: hw + type: u8 + - + name: count + type: binary + len: 32 + - + name: offset + type: binary + len: 32 + - + name: tc-multiq-qopt + type: struct + members: + - + name: bands + type: u16 + - + name: max-bands + type: u16 + - + name: tc-netem-qopt + type: struct + members: + - + name: latency + type: u32 + - + name: limit + type: u32 + - + name: loss + type: u32 + - + name: gap + type: u32 + - + name: duplicate + type: u32 + - + name: jitter + type: u32 + - + name: tc-plug-qopt + type: struct + members: + - + name: action + type: s32 + - + name: limit + type: u32 + - + name: tc-prio-qopt + type: struct + members: + - + name: bands + type: u16 + - + name: priomap + type: binary + len: 16 + - + name: tc-red-qopt + type: struct + members: + - + name: limit + type: u32 + - + name: qth-min + type: u32 + - + name: qth-max + type: u32 + - + name: Wlog + type: u8 + - + name: Plog + type: u8 + - + name: Scell-log + type: u8 + - + name: flags + type: u8 + - + name: tc-sfb-qopt + type: struct + members: + - + name: rehash-interval + type: u32 + - + name: warmup-time + type: u32 + - + name: max + type: u32 + - + name: bin-size + type: u32 + - + name: increment + type: u32 + - + name: decrement + type: u32 + - + name: limit + type: u32 + - + name: penalty-rate + type: u32 + - + name: penalty-burst + type: u32 + - + name: tc-sfq-qopt-v1 # TODO nested structs + type: struct + members: + - + name: quantum + type: u32 + - + name: perturb-period + type: s32 + - + name: limit + type: u32 + - + name: divisor + type: u32 + - + name: flows + type: u32 + - + name: depth + type: u32 + - + name: headdrop + type: u32 + - + name: limit + type: u32 + - + name: qth-min + type: u32 + - + name: qth-mac + type: u32 + - + name: Wlog + type: u8 + - + name: Plog + type: u8 + - + name: Scell-log + type: u8 + - + name: flags + type: u8 + - + name: max-P + type: u32 + - + name: prob-drop + type: u32 + - + name: forced-drop + type: u32 + - + name: prob-mark + type: u32 + - + name: forced-mark + type: u32 + - + name: prob-mark-head + type: u32 + - + name: forced-mark-head + type: u32 + - + name: tc-tbf-qopt + type: struct + members: + - + name: rate + type: binary # TODO nested struct tc_ratespec + len: 12 + - + name: peakrate + type: binary # TODO nested struct tc_ratespec + len: 12 + - + name: limit + type: u32 + - + name: buffer + type: u32 + - + name: mtu + type: u32 + - + name: tc-sizespec + type: struct + members: + - + name: cell-log + type: u8 + - + name: size-log + type: u8 + - + name: cell-align + type: s16 + - + name: overhead + type: s32 + - + name: linklayer + type: u32 + - + name: mpu + type: u32 + - + name: mtu + type: u32 + - + name: tsize + type: u32 + - + name: gnet-estimator + type: struct + members: + - + name: interval + type: s8 + - + name: ewma-log + type: u8 +attribute-sets: + - + name: tc-attrs + attributes: + - + name: kind + type: string + - + name: options + type: sub-message + sub-message: tc-options-msg + selector: kind + - + name: stats + type: binary + struct: tc-stats + - + name: xstats + type: binary + - + name: rate + type: binary + struct: gnet-estimator + - + name: fcnt + type: u32 + - + name: stats2 + type: nest + nested-attributes: tca-stats-attrs + - + name: stab + type: nest + nested-attributes: tca-stab-attrs + - + name: pad + type: pad + - + name: dump-invisible + type: flag + - + name: chain + type: u32 + - + name: hw-offload + type: u8 + - + name: ingress-block + type: u32 + - + name: egress-block + type: u32 + - + name: dump-flags + type: bitfield32 + - + name: ext-warn-msg + type: string + - + name: tc-cake-attrs + attributes: + - + name: pad + type: pad + - + name: base-rate64 + type: u64 + - + name: diffserv-mode + type: u32 + - + name: atm + type: u32 + - + name: flow-mode + type: u32 + - + name: overhead + type: u32 + - + name: rtt + type: u32 + - + name: target + type: u32 + - + name: autorate + type: u32 + - + name: memory + type: u32 + - + name: nat + type: u32 + - + name: raw + type: u32 + - + name: wash + type: u32 + - + name: mpu + type: u32 + - + name: ingress + type: u32 + - + name: ack-filter + type: u32 + - + name: split-gso + type: u32 + - + name: fwmark + type: u32 + - + name: tc-cake-stats-attrs + attributes: + - + name: pad + type: pad + - + name: capacity-estimate64 + type: u64 + - + name: memory-limit + type: u32 + - + name: memory-used + type: u32 + - + name: avg-netoff + type: u32 + - + name: min-netlen + type: u32 + - + name: max-netlen + type: u32 + - + name: min-adjlen + type: u32 + - + name: max-adjlen + type: u32 + - + name: tin-stats + type: binary + - + name: deficit + type: s32 + - + name: cobalt-count + type: u32 + - + name: dropping + type: u32 + - + name: drop-next-us + type: s32 + - + name: p-drop + type: u32 + - + name: blue-timer-us + type: s32 + - + name: tc-cbs-attrs + attributes: + - + name: parms + type: binary + struct: tc-cbs-qopt + - + name: tc-choke-attrs + attributes: + - + name: parms + type: binary + struct: tc-red-qopt + - + name: stab + type: binary + - + name: max-p + type: u32 + - + name: tc-codel-attrs + attributes: + - + name: target + type: u32 + - + name: limit + type: u32 + - + name: interval + type: u32 + - + name: ecn + type: u32 + - + name: ce-threshold + type: u32 + - + name: tc-drr-attrs + attributes: + - + name: quantum + type: u32 + - + name: tc-flower-attrs + attributes: + - + name: classid + type: u32 + - + name: indev + type: string + - + name: act + type: array-nest + nested-attributes: tc-act-attrs + - + name: key-eth-dst + type: binary + display-hint: mac + - + name: key-eth-dst-mask + type: binary + display-hint: mac + - + name: key-eth-src + type: binary + display-hint: mac + - + name: key-eth-src-mask + type: binary + display-hint: mac + - + name: key-eth-type + type: u16 + byte-order: big-endian + - + name: key-ip-proto + type: u8 + - + name: key-ipv4-src + type: u32 + byte-order: big-endian + display-hint: ipv4 + - + name: key-ipv4-src-mask + type: u32 + byte-order: big-endian + display-hint: ipv4 + - + name: key-ipv4-dst + type: u32 + byte-order: big-endian + display-hint: ipv4 + - + name: key-ipv4-dst-mask + type: u32 + byte-order: big-endian + display-hint: ipv4 + - + name: key-ipv6-src + type: binary + display-hint: ipv6 + - + name: key-ipv6-src-mask + type: binary + display-hint: ipv6 + - + name: key-ipv6-dst + type: binary + display-hint: ipv6 + - + name: key-ipv6-dst-mask + type: binary + display-hint: ipv6 + - + name: key-tcp-src + type: u16 + byte-order: big-endian + - + name: key-tcp-dst + type: u16 + byte-order: big-endian + - + name: key-udp-src + type: u16 + byte-order: big-endian + - + name: key-udp-dst + type: u16 + byte-order: big-endian + - + name: flags + type: u32 + enum: tc-cls-flags + enum-as-flags: true + - + name: key-vlan-id + type: u16 + byte-order: big-endian + - + name: key-vlan-prio + type: u8 + - + name: key-vlan-eth-type + type: u16 + byte-order: big-endian + - + name: key-enc-key-id + type: u32 + byte-order: big-endian + - + name: key-enc-ipv4-src + type: u32 + byte-order: big-endian + display-hint: ipv4 + - + name: key-enc-ipv4-src-mask + type: u32 + byte-order: big-endian + display-hint: ipv4 + - + name: key-enc-ipv4-dst + type: u32 + byte-order: big-endian + display-hint: ipv4 + - + name: key-enc-ipv4-dst-mask + type: u32 + byte-order: big-endian + display-hint: ipv4 + - + name: key-enc-ipv6-src + type: binary + display-hint: ipv6 + - + name: key-enc-ipv6-src-mask + type: binary + display-hint: ipv6 + - + name: key-enc-ipv6-dst + type: binary + display-hint: ipv6 + - + name: key-enc-ipv6-dst-mask + type: binary + display-hint: ipv6 + - + name: key-tcp-src-mask + type: u16 + byte-order: big-endian + - + name: key-tcp-dst-mask + type: u16 + byte-order: big-endian + - + name: key-udp-src-mask + type: u16 + byte-order: big-endian + - + name: key-udp-dst-mask + type: u16 + byte-order: big-endian + - + name: key-sctp-src-mask + type: u16 + byte-order: big-endian + - + name: key-sctp-dst-mask + type: u16 + byte-order: big-endian + - + name: key-sctp-src + type: u16 + byte-order: big-endian + - + name: key-sctp-dst + type: u16 + byte-order: big-endian + - + name: key-enc-udp-src-port + type: u16 + byte-order: big-endian + - + name: key-enc-udp-src-port-mask + type: u16 + byte-order: big-endian + - + name: key-enc-udp-dst-port + type: u16 + byte-order: big-endian + - + name: key-enc-udp-dst-port-mask + type: u16 + byte-order: big-endian + - + name: key-flags + type: u32 + byte-order: big-endian + - + name: key-flags-mask + type: u32 + byte-order: big-endian + - + name: key-icmpv4-code + type: u8 + - + name: key-icmpv4-code-mask + type: u8 + - + name: key-icmpv4-type + type: u8 + - + name: key-icmpv4-type-mask + type: u8 + - + name: key-icmpv6-code + type: u8 + - + name: key-icmpv6-code-mask + type: u8 + - + name: key-icmpv6-type + type: u8 + - + name: key-icmpv6-type-mask + type: u8 + - + name: key-arp-sip + type: u32 + byte-order: big-endian + - + name: key-arp-sip-mask + type: u32 + byte-order: big-endian + - + name: key-arp-tip + type: u32 + byte-order: big-endian + - + name: key-arp-tip-mask + type: u32 + byte-order: big-endian + - + name: key-arp-op + type: u8 + - + name: key-arp-op-mask + type: u8 + - + name: key-arp-sha + type: binary + - + name: key-arp-sha-mask + type: binary + - + name: key-arp-tha + type: binary + - + name: key-arp-tha-mask + type: binary + - + name: key-mpls-ttl + type: u8 + - + name: key-mpls-bos + type: u8 + - + name: key-mpls-tc + type: u8 + - + name: key-mpls-label + type: u32 + byte-order: big-endian + - + name: key-tcp-flags + type: u16 + byte-order: big-endian + - + name: key-tcp-flags-mask + type: u16 + byte-order: big-endian + - + name: key-ip-tos + type: u8 + - + name: key-ip-tos-mask + type: u8 + - + name: key-ip-ttl + type: u8 + - + name: key-ip-ttl-mask + type: u8 + - + name: key-cvlan-id + type: u16 + byte-order: big-endian + - + name: key-cvlan-prio + type: u8 + - + name: key-cvlan-eth-type + type: u16 + byte-order: big-endian + - + name: key-enc-ip-tos + type: u8 + - + name: key-enc-ip-tos-mask + type: u8 + - + name: key-enc-ip-ttl + type: u8 + - + name: key-enc-ip-ttl-mask + type: u8 + - + name: key-enc-opts + type: binary + - + name: key-enc-opts-mask + type: binary + - + name: in-hw-count + type: u32 + - + name: key-port-src-min + type: u16 + byte-order: big-endian + - + name: key-port-src-max + type: u16 + byte-order: big-endian + - + name: key-port-dst-min + type: u16 + byte-order: big-endian + - + name: key-port-dst-max + type: u16 + byte-order: big-endian + - + name: key-ct-state + type: u16 + - + name: key-ct-state-mask + type: u16 + - + name: key-ct-zone + type: u16 + - + name: key-ct-zone-mask + type: u16 + - + name: key-ct-mark + type: u32 + - + name: key-ct-mark-mask + type: u32 + - + name: key-ct-labels + type: binary + - + name: key-ct-labels-mask + type: binary + - + name: key-mpls-opts + type: binary + - + name: key-hash + type: u32 + - + name: key-hash-mask + type: u32 + - + name: key-num-of-vlans + type: u8 + - + name: key-pppoe-sid + type: u16 + byte-order: big-endian + - + name: key-ppp-proto + type: u16 + byte-order: big-endian + - + name: key-l2-tpv3-sid + type: u32 + byte-order: big-endian + - + name: tc-gred-attrs + attributes: + - + name: parms + type: binary # array of struct: tc-gred-qopt + - + name: stab + type: binary + sub-type: u8 + - + name: dps + type: binary + struct: tc-gred-sopt + - + name: max-p + type: binary + sub-type: u32 + - + name: limit + type: u32 + - + name: vq-list + type: nest + nested-attributes: tca-gred-vq-list-attrs + - + name: tca-gred-vq-list-attrs + attributes: + - + name: entry + type: nest + nested-attributes: tca-gred-vq-entry-attrs + multi-attr: true + - + name: tca-gred-vq-entry-attrs + attributes: + - + name: pad + type: pad + - + name: dp + type: u32 + - + name: stat-bytes + type: u32 + - + name: stat-packets + type: u32 + - + name: stat-backlog + type: u32 + - + name: stat-prob-drop + type: u32 + - + name: stat-prob-mark + type: u32 + - + name: stat-forced-drop + type: u32 + - + name: stat-forced-mark + type: u32 + - + name: stat-pdrop + type: u32 + - + name: stat-other + type: u32 + - + name: flags + type: u32 + - + name: tc-hfsc-attrs + attributes: + - + name: rsc + type: binary + - + name: fsc + type: binary + - + name: usc + type: binary + - + name: tc-hhf-attrs + attributes: + - + name: backlog-limit + type: u32 + - + name: quantum + type: u32 + - + name: hh-flows-limit + type: u32 + - + name: reset-timeout + type: u32 + - + name: admit-bytes + type: u32 + - + name: evict-timeout + type: u32 + - + name: non-hh-weight + type: u32 + - + name: tc-htb-attrs + attributes: + - + name: parms + type: binary + struct: tc-htb-opt + - + name: init + type: binary + struct: tc-htb-glob + - + name: ctab + type: binary + - + name: rtab + type: binary + - + name: direct-qlen + type: u32 + - + name: rate64 + type: u64 + - + name: ceil64 + type: u64 + - + name: pad + type: pad + - + name: offload + type: flag + - + name: tc-act-attrs + attributes: + - + name: kind + type: string + - + name: options + type: sub-message + sub-message: tc-act-options-msg + selector: kind + - + name: index + type: u32 + - + name: stats + type: binary + - + name: pad + type: pad + - + name: cookie + type: binary + - + name: flags + type: bitfield32 + - + name: hw-stats + type: bitfield32 + - + name: used-hw-stats + type: bitfield32 + - + name: in-hw-count + type: u32 + - + name: tc-etf-attrs + attributes: + - + name: parms + type: binary + struct: tc-etf-qopt + - + name: tc-ets-attrs + attributes: + - + name: nbands + type: u8 + - + name: nstrict + type: u8 + - + name: quanta + type: nest + nested-attributes: tc-ets-attrs + - + name: quanta-band + type: u32 + multi-attr: true + - + name: priomap + type: nest + nested-attributes: tc-ets-attrs + - + name: priomap-band + type: u8 + multi-attr: true + - + name: tc-fq-attrs + attributes: + - + name: plimit + type: u32 + - + name: flow-plimit + type: u32 + - + name: quantum + type: u32 + - + name: initial-quantum + type: u32 + - + name: rate-enable + type: u32 + - + name: flow-default-rate + type: u32 + - + name: flow-max-rate + type: u32 + - + name: buckets-log + type: u32 + - + name: flow-refill-delay + type: u32 + - + name: orphan-mask + type: u32 + - + name: low-rate-threshold + type: u32 + - + name: ce-threshold + type: u32 + - + name: timer-slack + type: u32 + - + name: horizon + type: u32 + - + name: horizon-drop + type: u8 + - + name: tc-fq-codel-attrs + attributes: + - + name: target + type: u32 + - + name: limit + type: u32 + - + name: interval + type: u32 + - + name: ecn + type: u32 + - + name: flows + type: u32 + - + name: quantum + type: u32 + - + name: ce-threshold + type: u32 + - + name: drop-batch-size + type: u32 + - + name: memory-limit + type: u32 + - + name: ce-threshold-selector + type: u8 + - + name: ce-threshold-mask + type: u8 + - + name: tc-fq-pie-attrs + attributes: + - + name: limit + type: u32 + - + name: flows + type: u32 + - + name: target + type: u32 + - + name: tupdate + type: u32 + - + name: alpha + type: u32 + - + name: beta + type: u32 + - + name: quantum + type: u32 + - + name: memory-limit + type: u32 + - + name: ecn-prob + type: u32 + - + name: ecn + type: u32 + - + name: bytemode + type: u32 + - + name: dq-rate-estimator + type: u32 + - + name: tc-netem-attrs + attributes: + - + name: corr + type: binary + - + name: delay-dist + type: binary + sub-type: s16 + - + name: reorder + type: binary + - + name: corrupt + type: binary + - + name: loss + type: binary + - + name: rate + type: binary + - + name: ecn + type: u32 + - + name: rate64 + type: u64 + - + name: pad + type: u32 + - + name: latency64 + type: s64 + - + name: jitter64 + type: s64 + - + name: slot + type: binary + - + name: slot-dist + type: binary + sub-type: s16 + - + name: tc-pie-attrs + attributes: + - + name: target + type: u32 + - + name: limit + type: u32 + - + name: tupdate + type: u32 + - + name: alpha + type: u32 + - + name: beta + type: u32 + - + name: ecn + type: u32 + - + name: bytemode + type: u32 + - + name: dq-rate-estimator + type: u32 + - + name: tc-qfq-attrs + attributes: + - + name: weight + type: u32 + - + name: lmax + type: u32 + - + name: tc-red-attrs + attributes: + - + name: parms + type: binary + struct: tc-red-qopt + - + name: stab + type: binary + - + name: max-p + type: u32 + - + name: flags + type: binary + - + name: early-drop-block + type: u32 + - + name: mark-block + type: u32 + - + name: tc-taprio-attrs + attributes: + - + name: priomap + type: binary + struct: tc-mqprio-qopt + - + name: sched-entry-list + type: nest + nested-attributes: tc-taprio-sched-entry-list + - + name: sched-base-time + type: s64 + - + name: sched-single-entry + type: nest + nested-attributes: tc-taprio-sched-entry + - + name: sched-clockid + type: s32 + - + name: pad + type: pad + - + name: admin-sched + type: binary + - + name: sched-cycle-time + type: s64 + - + name: sched-cycle-time-extension + type: s64 + - + name: flags + type: u32 + - + name: txtime-delay + type: u32 + - + name: tc-entry + type: nest + nested-attributes: tc-taprio-tc-entry-attrs + - + name: tc-taprio-sched-entry-list + attributes: + - + name: entry + type: nest + nested-attributes: tc-taprio-sched-entry + - + name: tc-taprio-sched-entry + attributes: + - + name: index + type: u32 + - + name: cmd + type: u8 + - + name: gate-mask + type: u32 + - + name: interval + type: u32 + - + name: tc-taprio-tc-entry-attrs + attributes: + - + name: index + type: u32 + - + name: max-sdu + type: u32 + - + name: fp + type: u32 + - + name: tc-tbf-attrs + attributes: + - + name: parms + type: binary + struct: tc-tbf-qopt + - + name: rtab + type: binary + - + name: ptab + type: binary + - + name: rate64 + type: u64 + - + name: prate4 + type: u64 + - + name: burst + type: u32 + - + name: pburst + type: u32 + - + name: pad + type: pad + - + name: tca-gact-attrs + attributes: + - + name: tm + type: binary + - + name: parms + type: binary + - + name: prob + type: binary + - + name: pad + type: pad + - + name: tca-stab-attrs + attributes: + - + name: base + type: binary + struct: tc-sizespec + - + name: data + type: binary + - + name: tca-stats-attrs + attributes: + - + name: basic + type: binary + - + name: rate-est + type: binary + - + name: queue + type: binary + - + name: app + type: binary # TODO sub-message needs 2+ level deep lookup + sub-message: tca-stats-app-msg + selector: kind + - + name: rate-est64 + type: binary + - + name: pad + type: pad + - + name: basic-hw + type: binary + - + name: pkt64 + type: binary + +sub-messages: + - + name: tc-options-msg + formats: + - + value: bfifo + fixed-header: tc-fifo-qopt + - + value: cake + attribute-set: tc-cake-attrs + - + value: cbs + attribute-set: tc-cbs-attrs + - + value: choke + attribute-set: tc-choke-attrs + - + value: clsact # no content + - + value: codel + attribute-set: tc-codel-attrs + - + value: drr + attribute-set: tc-drr-attrs + - + value: etf + attribute-set: tc-etf-attrs + - + value: ets + attribute-set: tc-ets-attrs + - + value: fq + attribute-set: tc-fq-attrs + - + value: fq_codel + attribute-set: tc-fq-codel-attrs + - + value: fq_pie + attribute-set: tc-fq-pie-attrs + - + value: flower + attribute-set: tc-flower-attrs + - + value: gred + attribute-set: tc-gred-attrs + - + value: hfsc + fixed-header: tc-hfsc-qopt + - + value: hhf + attribute-set: tc-hhf-attrs + - + value: htb + attribute-set: tc-htb-attrs + - + value: ingress # no content + - + value: mq # no content + - + value: mqprio + fixed-header: tc-mqprio-qopt + - + value: multiq + fixed-header: tc-multiq-qopt + - + value: netem + fixed-header: tc-netem-qopt + attribute-set: tc-netem-attrs + - + value: pfifo + fixed-header: tc-fifo-qopt + - + value: pfifo_fast + fixed-header: tc-prio-qopt + - + value: pfifo_head_drop + fixed-header: tc-fifo-qopt + - + value: pie + attribute-set: tc-pie-attrs + - + value: plug + fixed-header: tc-plug-qopt + - + value: prio + fixed-header: tc-prio-qopt + - + value: qfq + attribute-set: tc-qfq-attrs + - + value: red + attribute-set: tc-red-attrs + - + value: sfb + fixed-header: tc-sfb-qopt + - + value: sfq + fixed-header: tc-sfq-qopt-v1 + - + value: taprio + attribute-set: tc-taprio-attrs + - + value: tbf + attribute-set: tc-tbf-attrs + - + name: tc-act-options-msg + formats: + - + value: gact + attribute-set: tca-gact-attrs + - + name: tca-stats-app-msg + formats: + - + value: bfifo + - + value: blackhole + - + value: cake + attribute-set: tc-cake-stats-attrs + - + value: cbs + - + value: choke + - + value: clsact + - + value: codel + - + value: drr + - + value: etf + - + value: ets + - + value: fq + - + value: fq_codel + - + value: fq_pie + - + value: flower + - + value: gred + - + value: hfsc + - + value: hhf + - + value: htb + - + value: ingress + - + value: mq + - + value: mqprio + - + value: multiq + - + value: netem + - + value: noqueue + - + value: pfifo + - + value: pfifo_fast + - + value: pfifo_head_drop + - + value: pie + - + value: plug + - + value: prio + - + value: qfq + - + value: red + - + value: sfb + - + value: sfq + - + value: taprio + - + value: tbf + +operations: + enum-model: directional + list: + - + name: newqdisc + doc: Create new tc qdisc. + attribute-set: tc-attrs + fixed-header: tcmsg + do: + request: + value: 36 + attributes: &create-params + - kind + - options + - rate + - chain + - ingress-block + - egress-block + - + name: delqdisc + doc: Delete existing tc qdisc. + attribute-set: tc-attrs + fixed-header: tcmsg + do: + request: + value: 37 + - + name: getqdisc + doc: Get / dump tc qdisc information. + attribute-set: tc-attrs + fixed-header: tcmsg + do: + request: + value: 38 + attributes: + - dump-invisible + reply: + value: 36 + attributes: &tc-all + - kind + - options + - stats + - xstats + - rate + - fcnt + - stats2 + - stab + - chain + - ingress-block + - egress-block + - + name: newtclass + doc: Get / dump tc traffic class information. + attribute-set: tc-attrs + fixed-header: tcmsg + do: + request: + value: 40 + attributes: *create-params + - + name: deltclass + doc: Get / dump tc traffic class information. + attribute-set: tc-attrs + fixed-header: tcmsg + do: + request: + value: 41 + - + name: gettclass + doc: Get / dump tc traffic class information. + attribute-set: tc-attrs + fixed-header: tcmsg + do: + request: + value: 42 + reply: + value: 40 + attributes: *tc-all + - + name: newtfilter + doc: Get / dump tc filter information. + attribute-set: tc-attrs + fixed-header: tcmsg + do: + request: + value: 44 + attributes: *create-params + - + name: deltfilter + doc: Get / dump tc filter information. + attribute-set: tc-attrs + fixed-header: tcmsg + do: + request: + value: 45 + attributes: + - chain + - kind + - + name: gettfilter + doc: Get / dump tc filter information. + attribute-set: tc-attrs + fixed-header: tcmsg + do: + request: + value: 46 + attributes: + - chain + - kind + reply: + value: 44 + attributes: *tc-all + dump: + request: + value: 46 + attributes: + - chain + - dump-flags + reply: + value: 44 + attributes: *tc-all + - + name: newchain + doc: Get / dump tc chain information. + attribute-set: tc-attrs + fixed-header: tcmsg + do: + request: + value: 100 + attributes: *create-params + - + name: delchain + doc: Get / dump tc chain information. + attribute-set: tc-attrs + fixed-header: tcmsg + do: + request: + value: 101 + attributes: + - chain + - + name: getchain + doc: Get / dump tc chain information. + attribute-set: tc-attrs + fixed-header: tcmsg + do: + request: + value: 102 + attributes: + - chain + reply: + value: 100 + attributes: *tc-all + +mcast-groups: + list: + - + name: rtnlgrp-tc + value: 4 diff --git a/Documentation/networking/bridge.rst b/Documentation/networking/bridge.rst index c859f3c1636edf..ba14e7b07869c9 100644 --- a/Documentation/networking/bridge.rst +++ b/Documentation/networking/bridge.rst @@ -4,18 +4,332 @@ Ethernet Bridging ================= -In order to use the Ethernet bridging functionality, you'll need the -userspace tools. +Introduction +============ -Documentation for Linux bridging is on: - https://wiki.linuxfoundation.org/networking/bridge +The IEEE 802.1Q-2022 (Bridges and Bridged Networks) standard defines the +operation of bridges in computer networks. A bridge, in the context of this +standard, is a device that connects two or more network segments and operates +at the data link layer (Layer 2) of the OSI (Open Systems Interconnection) +model. The purpose of a bridge is to filter and forward frames between +different segments based on the destination MAC (Media Access Control) address. -The bridge-utilities are maintained at: - git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/bridge-utils.git +Bridge kAPI +=========== -Additionally, the iproute2 utilities can be used to configure -bridge devices. +Here are some core structures of bridge code. Note that the kAPI is *unstable*, +and can be changed at any time. -If you still have questions, don't hesitate to post to the mailing list -(more info https://lists.linux-foundation.org/mailman/listinfo/bridge). +.. kernel-doc:: net/bridge/br_private.h + :identifiers: net_bridge_vlan +Bridge uAPI +=========== + +Modern Linux bridge uAPI is accessed via Netlink interface. You can find +below files where the bridge and bridge port netlink attributes are defined. + +Bridge netlink attributes +------------------------- + +.. kernel-doc:: include/uapi/linux/if_link.h + :doc: Bridge enum definition + +Bridge port netlink attributes +------------------------------ + +.. kernel-doc:: include/uapi/linux/if_link.h + :doc: Bridge port enum definition + +Bridge sysfs +------------ + +The sysfs interface is deprecated and should not be extended if new +options are added. + +STP +=== + +The STP (Spanning Tree Protocol) implementation in the Linux bridge driver +is a critical feature that helps prevent loops and broadcast storms in +Ethernet networks by identifying and disabling redundant links. In a Linux +bridge context, STP is crucial for network stability and availability. + +STP is a Layer 2 protocol that operates at the Data Link Layer of the OSI +model. It was originally developed as IEEE 802.1D and has since evolved into +multiple versions, including Rapid Spanning Tree Protocol (RSTP) and +`Multiple Spanning Tree Protocol (MSTP) +`_. + +The 802.1D-2004 removed the original Spanning Tree Protocol, instead +incorporating the Rapid Spanning Tree Protocol (RSTP). By 2014, all the +functionality defined by IEEE 802.1D has been incorporated into either +IEEE 802.1Q (Bridges and Bridged Networks) or IEEE 802.1AC (MAC Service +Definition). 802.1D has been officially withdrawn in 2022. + +Bridge Ports and STP States +--------------------------- + +In the context of STP, bridge ports can be in one of the following states: + * Blocking: The port is disabled for data traffic and only listens for + BPDUs (Bridge Protocol Data Units) from other devices to determine the + network topology. + * Listening: The port begins to participate in the STP process and listens + for BPDUs. + * Learning: The port continues to listen for BPDUs and begins to learn MAC + addresses from incoming frames but does not forward data frames. + * Forwarding: The port is fully operational and forwards both BPDUs and + data frames. + * Disabled: The port is administratively disabled and does not participate + in the STP process. The data frames forwarding are also disabled. + +Root Bridge and Convergence +--------------------------- + +In the context of networking and Ethernet bridging in Linux, the root bridge +is a designated switch in a bridged network that serves as a reference point +for the spanning tree algorithm to create a loop-free topology. + +Here's how the STP works and root bridge is chosen: + 1. Bridge Priority: Each bridge running a spanning tree protocol, has a + configurable Bridge Priority value. The lower the value, the higher the + priority. By default, the Bridge Priority is set to a standard value + (e.g., 32768). + 2. Bridge ID: The Bridge ID is composed of two components: Bridge Priority + and the MAC address of the bridge. It uniquely identifies each bridge + in the network. The Bridge ID is used to compare the priorities of + different bridges. + 3. Bridge Election: When the network starts, all bridges initially assume + that they are the root bridge. They start advertising Bridge Protocol + Data Units (BPDU) to their neighbors, containing their Bridge ID and + other information. + 4. BPDU Comparison: Bridges exchange BPDUs to determine the root bridge. + Each bridge examines the received BPDUs, including the Bridge Priority + and Bridge ID, to determine if it should adjust its own priorities. + The bridge with the lowest Bridge ID will become the root bridge. + 5. Root Bridge Announcement: Once the root bridge is determined, it sends + BPDUs with information about the root bridge to all other bridges in the + network. This information is used by other bridges to calculate the + shortest path to the root bridge and, in doing so, create a loop-free + topology. + 6. Forwarding Ports: After the root bridge is selected and the spanning tree + topology is established, each bridge determines which of its ports should + be in the forwarding state (used for data traffic) and which should be in + the blocking state (used to prevent loops). The root bridge's ports are + all in the forwarding state. while other bridges have some ports in the + blocking state to avoid loops. + 7. Root Ports: After the root bridge is selected and the spanning tree + topology is established, each non-root bridge processes incoming + BPDUs and determines which of its ports provides the shortest path to the + root bridge based on the information in the received BPDUs. This port is + designated as the root port. And it is in the Forwarding state, allowing + it to actively forward network traffic. + 8. Designated ports: A designated port is the port through which the non-root + bridge will forward traffic towards the designated segment. Designated ports + are placed in the Forwarding state. All other ports on the non-root + bridge that are not designated for specific segments are placed in the + Blocking state to prevent network loops. + +STP ensures network convergence by calculating the shortest path and disabling +redundant links. When network topology changes occur (e.g., a link failure), +STP recalculates the network topology to restore connectivity while avoiding loops. + +Proper configuration of STP parameters, such as the bridge priority, can +influence network performance, path selection and which bridge becomes the +Root Bridge. + +User space STP helper +--------------------- + +The user space STP helper *bridge-stp* is a program to control whether to use +user mode spanning tree. The ``/sbin/bridge-stp `` is +called by the kernel when STP is enabled/disabled on a bridge +(via ``brctl stp `` or ``ip link set type bridge +stp_state <0|1>``). The kernel enables user_stp mode if that command returns +0, or enables kernel_stp mode if that command returns any other value. + +VLAN +==== + +A LAN (Local Area Network) is a network that covers a small geographic area, +typically within a single building or a campus. LANs are used to connect +computers, servers, printers, and other networked devices within a localized +area. LANs can be wired (using Ethernet cables) or wireless (using Wi-Fi). + +A VLAN (Virtual Local Area Network) is a logical segmentation of a physical +network into multiple isolated broadcast domains. VLANs are used to divide +a single physical LAN into multiple virtual LANs, allowing different groups of +devices to communicate as if they were on separate physical networks. + +Typically there are two VLAN implementations, IEEE 802.1Q and IEEE 802.1ad +(also known as QinQ). IEEE 802.1Q is a standard for VLAN tagging in Ethernet +networks. It allows network administrators to create logical VLANs on a +physical network and tag Ethernet frames with VLAN information, which is +called *VLAN-tagged frames*. IEEE 802.1ad, commonly known as QinQ or Double +VLAN, is an extension of the IEEE 802.1Q standard. QinQ allows for the +stacking of multiple VLAN tags within a single Ethernet frame. The Linux +bridge supports both the IEEE 802.1Q and `802.1AD +`_ +protocol for VLAN tagging. + +`VLAN filtering `_ +on a bridge is disabled by default. After enabling VLAN filtering on a bridge, +it will start forwarding frames to appropriate destinations based on their +destination MAC address and VLAN tag (both must match). + +Multicast +========= + +The Linux bridge driver has multicast support allowing it to process Internet +Group Management Protocol (IGMP) or Multicast Listener Discovery (MLD) +messages, and to efficiently forward multicast data packets. The bridge +driver supports IGMPv2/IGMPv3 and MLDv1/MLDv2. + +Multicast snooping +------------------ + +Multicast snooping is a networking technology that allows network switches +to intelligently manage multicast traffic within a local area network (LAN). + +The switch maintains a multicast group table, which records the association +between multicast group addresses and the ports where hosts have joined these +groups. The group table is dynamically updated based on the IGMP/MLD messages +received. With the multicast group information gathered through snooping, the +switch optimizes the forwarding of multicast traffic. Instead of blindly +broadcasting the multicast traffic to all ports, it sends the multicast +traffic based on the destination MAC address only to ports which have +subscribed the respective destination multicast group. + +When created, the Linux bridge devices have multicast snooping enabled by +default. It maintains a Multicast forwarding database (MDB) which keeps track +of port and group relationships. + +IGMPv3/MLDv2 EHT support +------------------------ + +The Linux bridge supports IGMPv3/MLDv2 EHT (Explicit Host Tracking), which +was added by `474ddb37fa3a ("net: bridge: multicast: add EHT allow/block handling") +`_ + +The explicit host tracking enables the device to keep track of each +individual host that is joined to a particular group or channel. The main +benefit of the explicit host tracking in IGMP is to allow minimal leave +latencies when a host leaves a multicast group or channel. + +The length of time between a host wanting to leave and a device stopping +traffic forwarding is called the IGMP leave latency. A device configured +with IGMPv3 or MLDv2 and explicit tracking can immediately stop forwarding +traffic if the last host to request to receive traffic from the device +indicates that it no longer wants to receive traffic. The leave latency +is thus bound only by the packet transmission latencies in the multiaccess +network and the processing time in the device. + +Other multicast features +------------------------ + +The Linux bridge also supports `per-VLAN multicast snooping +`_, +which is disabled by default but can be enabled. And `Multicast Router Discovery +`_, +which help identify the location of multicast routers. + +Switchdev +========= + +Linux Bridge Switchdev is a feature in the Linux kernel that extends the +capabilities of the traditional Linux bridge to work more efficiently with +hardware switches that support switchdev. With Linux Bridge Switchdev, certain +networking functions like forwarding, filtering, and learning of Ethernet +frames can be offloaded to a hardware switch. This offloading reduces the +burden on the Linux kernel and CPU, leading to improved network performance +and lower latency. + +To use Linux Bridge Switchdev, you need hardware switches that support the +switchdev interface. This means that the switch hardware needs to have the +necessary drivers and functionality to work in conjunction with the Linux +kernel. + +Please see the :ref:`switchdev` document for more details. + +Netfilter +========= + +The bridge netfilter module is a legacy feature that allows to filter bridged +packets with iptables and ip6tables. Its use is discouraged. Users should +consider using nftables for packet filtering. + +The older ebtables tool is more feature-limited compared to nftables, but +just like nftables it doesn't need this module either to function. + +The br_netfilter module intercepts packets entering the bridge, performs +minimal sanity tests on ipv4 and ipv6 packets and then pretends that +these packets are being routed, not bridged. br_netfilter then calls +the ip and ipv6 netfilter hooks from the bridge layer, i.e. ip(6)tables +rulesets will also see these packets. + +br_netfilter is also the reason for the iptables *physdev* match: +This match is the only way to reliably tell routed and bridged packets +apart in an iptables ruleset. + +Note that ebtables and nftables will work fine without the br_netfilter module. +iptables/ip6tables/arptables do not work for bridged traffic because they +plug in the routing stack. nftables rules in ip/ip6/inet/arp families won't +see traffic that is forwarded by a bridge either, but that's very much how it +should be. + +Historically the feature set of ebtables was very limited (it still is), +this module was added to pretend packets are routed and invoke the ipv4/ipv6 +netfilter hooks from the bridge so users had access to the more feature-rich +iptables matching capabilities (including conntrack). nftables doesn't have +this limitation, pretty much all features work regardless of the protocol family. + +So, br_netfilter is only needed if users, for some reason, need to use +ip(6)tables to filter packets forwarded by the bridge, or NAT bridged +traffic. For pure link layer filtering, this module isn't needed. + +Other Features +============== + +The Linux bridge also supports `IEEE 802.11 Proxy ARP +`_, +`Media Redundancy Protocol (MRP) +`_, +`Media Redundancy Protocol (MRP) LC mode +`_, +`IEEE 802.1X port authentication +`_, +and `MAC Authentication Bypass (MAB) +`_. + +FAQ +=== + +What does a bridge do? +---------------------- + +A bridge transparently forwards traffic between multiple network interfaces. +In plain English this means that a bridge connects two or more physical +Ethernet networks, to form one larger (logical) Ethernet network. + +Is it L3 protocol independent? +------------------------------ + +Yes. The bridge sees all frames, but it *uses* only L2 headers/information. +As such, the bridging functionality is protocol independent, and there should +be no trouble forwarding IPX, NetBEUI, IP, IPv6, etc. + +Contact Info +============ + +The code is currently maintained by Roopa Prabhu and +Nikolay Aleksandrov . Bridge bugs and enhancements +are discussed on the linux-netdev mailing list netdev@vger.kernel.org and +bridge@lists.linux-foundation.org. + +The list is open to anyone interested: http://vger.kernel.org/vger-lists.html#netdev + +External Links +============== + +The old Documentation for Linux bridging is on: +https://wiki.linuxfoundation.org/networking/bridge diff --git a/Documentation/networking/device_drivers/ethernet/amazon/ena.rst b/Documentation/networking/device_drivers/ethernet/amazon/ena.rst index 5eaa3ab6c73e7f..b842bcb14255b5 100644 --- a/Documentation/networking/device_drivers/ethernet/amazon/ena.rst +++ b/Documentation/networking/device_drivers/ethernet/amazon/ena.rst @@ -54,6 +54,7 @@ ena_common_defs.h Common definitions for ena_com layer. ena_regs_defs.h Definition of ENA PCI memory-mapped (MMIO) registers. ena_netdev.[ch] Main Linux kernel driver. ena_ethtool.c ethtool callbacks. +ena_xdp.[ch] XDP files ena_pci_id_tbl.h Supported device IDs. ================= ====================================================== diff --git a/Documentation/networking/device_drivers/ethernet/intel/ice.rst b/Documentation/networking/device_drivers/ethernet/intel/ice.rst index e4d065c55ea8d1..5038e54586af66 100644 --- a/Documentation/networking/device_drivers/ethernet/intel/ice.rst +++ b/Documentation/networking/device_drivers/ethernet/intel/ice.rst @@ -895,6 +895,147 @@ driver writes raw bytes by the GNSS object to the receiver through i2c. Please refer to the hardware GNSS module documentation for configuration details. +Firmware (FW) logging +--------------------- +The driver supports FW logging via the debugfs interface on PF 0 only. The FW +running on the NIC must support FW logging; if the FW doesn't support FW logging +the 'fwlog' file will not get created in the ice debugfs directory. + +Module configuration +~~~~~~~~~~~~~~~~~~~~ +Firmware logging is configured on a per module basis. Each module can be set to +a value independent of the other modules (unless the module 'all' is specified). +The modules will be instantiated under the 'fwlog/modules' directory. + +The user can set the log level for a module by writing to the module file like +this:: + + # echo > /sys/kernel/debug/ice/0000\:18\:00.0/fwlog/modules/ + +where + +* log_level is a name as described below. Each level includes the + messages from the previous/lower level + + * none + * error + * warning + * normal + * verbose + +* module is a name that represents the module to receive events for. The + module names are + + * general + * ctrl + * link + * link_topo + * dnl + * i2c + * sdp + * mdio + * adminq + * hdma + * lldp + * dcbx + * dcb + * xlr + * nvm + * auth + * vpd + * iosf + * parser + * sw + * scheduler + * txq + * rsvd + * post + * watchdog + * task_dispatch + * mng + * synce + * health + * tsdrv + * pfreg + * mdlver + * all + +The name 'all' is special and allows the user to set all of the modules to the +specified log_level or to read the log_level of all of the modules. + +Example usage to configure the modules +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To set a single module to 'verbose':: + + # echo verbose > /sys/kernel/debug/ice/0000\:18\:00.0/fwlog/modules/link + +To set multiple modules then issue the command multiple times:: + + # echo verbose > /sys/kernel/debug/ice/0000\:18\:00.0/fwlog/modules/link + # echo warning > /sys/kernel/debug/ice/0000\:18\:00.0/fwlog/modules/ctrl + # echo none > /sys/kernel/debug/ice/0000\:18\:00.0/fwlog/modules/dcb + +To set all the modules to the same value:: + + # echo normal > /sys/kernel/debug/ice/0000\:18\:00.0/fwlog/modules/all + +To read the log_level of a specific module (e.g. module 'general'):: + + # cat /sys/kernel/debug/ice/0000\:18\:00.0/fwlog/modules/general + +To read the log_level of all the modules:: + + # cat /sys/kernel/debug/ice/0000\:18\:00.0/fwlog/modules/all + +Enabling FW log +~~~~~~~~~~~~~~~ +Configuring the modules indicates to the FW that the configured modules should +generate events that the driver is interested in, but it **does not** send the +events to the driver until the enable message is sent to the FW. To do this +the user can write a 1 (enable) or 0 (disable) to 'fwlog/enable'. An example +is:: + + # echo 1 > /sys/kernel/debug/ice/0000\:18\:00.0/fwlog/enable + +Retrieving FW log data +~~~~~~~~~~~~~~~~~~~~~~ +The FW log data can be retrieved by reading from 'fwlog/data'. The user can +write any value to 'fwlog/data' to clear the data. The data can only be cleared +when FW logging is disabled. The FW log data is a binary file that is sent to +Intel and used to help debug user issues. + +An example to read the data is:: + + # cat /sys/kernel/debug/ice/0000\:18\:00.0/fwlog/data > fwlog.bin + +An example to clear the data is:: + + # echo 0 > /sys/kernel/debug/ice/0000\:18\:00.0/fwlog/data + +Changing how often the log events are sent to the driver +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The driver receives FW log data from the Admin Receive Queue (ARQ). The +frequency that the FW sends the ARQ events can be configured by writing to +'fwlog/nr_messages'. The range is 1-128 (1 means push every log message, 128 +means push only when the max AQ command buffer is full). The suggested value is +10. The user can see what the value is configured to by reading +'fwlog/nr_messages'. An example to set the value is:: + + # echo 50 > /sys/kernel/debug/ice/0000\:18\:00.0/fwlog/nr_messages + +Configuring the amount of memory used to store FW log data +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The driver stores FW log data within the driver. The default size of the memory +used to store the data is 1MB. Some use cases may require more or less data so +the user can change the amount of memory that is allocated for FW log data. +To change the amount of memory then write to 'fwlog/log_size'. The value must be +one of: 128K, 256K, 512K, 1M, or 2M. FW logging must be disabled to change the +value. An example of changing the value is:: + + # echo 128K > /sys/kernel/debug/ice/0000\:18\:00.0/fwlog/log_size + + Performance Optimization ======================== Driver defaults are meant to fit a wide variety of workloads, but if further diff --git a/Documentation/networking/device_drivers/ethernet/marvell/octeon_ep.rst b/Documentation/networking/device_drivers/ethernet/marvell/octeon_ep.rst index cad96c8d1f97dd..c96d262b30beef 100644 --- a/Documentation/networking/device_drivers/ethernet/marvell/octeon_ep.rst +++ b/Documentation/networking/device_drivers/ethernet/marvell/octeon_ep.rst @@ -22,8 +22,13 @@ EndPoint NIC. Supported Devices ================= Currently, this driver support following devices: + * Network controller: Cavium, Inc. Device b100 * Network controller: Cavium, Inc. Device b200 * Network controller: Cavium, Inc. Device b400 + * Network controller: Cavium, Inc. Device b900 + * Network controller: Cavium, Inc. Device ba00 + * Network controller: Cavium, Inc. Device bc00 + * Network controller: Cavium, Inc. Device bd00 Interface Control ================= diff --git a/Documentation/networking/device_drivers/wifi/index.rst b/Documentation/networking/device_drivers/wifi/index.rst index bf91a87c7acffc..fb394f5de4a945 100644 --- a/Documentation/networking/device_drivers/wifi/index.rst +++ b/Documentation/networking/device_drivers/wifi/index.rst @@ -10,7 +10,6 @@ Contents: intel/ipw2100 intel/ipw2200 - ray_cs .. only:: subproject and html diff --git a/Documentation/networking/device_drivers/wifi/ray_cs.rst b/Documentation/networking/device_drivers/wifi/ray_cs.rst deleted file mode 100644 index 9a46d1ae8f2097..00000000000000 --- a/Documentation/networking/device_drivers/wifi/ray_cs.rst +++ /dev/null @@ -1,165 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -.. include:: - -========================= -Raylink wireless LAN card -========================= - -September 21, 1999 - -Copyright |copy| 1998 Corey Thomas (corey@world.std.com) - -This file is the documentation for the Raylink Wireless LAN card driver for -Linux. The Raylink wireless LAN card is a PCMCIA card which provides IEEE -802.11 compatible wireless network connectivity at 1 and 2 megabits/second. -See http://www.raytheon.com/micro/raylink/ for more information on the Raylink -card. This driver is in early development and does have bugs. See the known -bugs and limitations at the end of this document for more information. -This driver also works with WebGear's Aviator 2.4 and Aviator Pro -wireless LAN cards. - -As of kernel 2.3.18, the ray_cs driver is part of the Linux kernel -source. My web page for the development of ray_cs is at -http://web.ralinktech.com/ralink/Home/Support/Linux.html -and I can be emailed at corey@world.std.com - -The kernel driver is based on ray_cs-1.62.tgz - -The driver at my web page is intended to be used as an add on to -David Hinds pcmcia package. All the command line parameters are -available when compiled as a module. When built into the kernel, only -the essid= string parameter is available via the kernel command line. -This will change after the method of sorting out parameters for all -the PCMCIA drivers is agreed upon. If you must have a built in driver -with nondefault parameters, they can be edited in -/usr/src/linux/drivers/net/pcmcia/ray_cs.c. Searching for module_param -will find them all. - -Information on card services is available at: - - http://pcmcia-cs.sourceforge.net/ - - -Card services user programs are still required for PCMCIA devices. -pcmcia-cs-3.1.1 or greater is required for the kernel version of -the driver. - -Currently, ray_cs is not part of David Hinds card services package, -so the following magic is required. - -At the end of the /etc/pcmcia/config.opts file, add the line: -source ./ray_cs.opts -This will make card services read the ray_cs.opts file -when starting. Create the file /etc/pcmcia/ray_cs.opts containing the -following:: - - #### start of /etc/pcmcia/ray_cs.opts ################### - # Configuration options for Raylink Wireless LAN PCMCIA card - device "ray_cs" - class "network" module "misc/ray_cs" - - card "RayLink PC Card WLAN Adapter" - manfid 0x01a6, 0x0000 - bind "ray_cs" - - module "misc/ray_cs" opts "" - #### end of /etc/pcmcia/ray_cs.opts ##################### - - -To join an existing network with -different parameters, contact the network administrator for the -configuration information, and edit /etc/pcmcia/ray_cs.opts. -Add the parameters below between the empty quotes. - -Parameters for ray_cs driver which may be specified in ray_cs.opts: - -=============== =============== ============================================= -bc integer 0 = normal mode (802.11 timing), - 1 = slow down inter frame timing to allow - operation with older breezecom access - points. - -beacon_period integer beacon period in Kilo-microseconds, - - legal values = must be integer multiple - of hop dwell - - default = 256 - -country integer 1 = USA (default), - 2 = Europe, - 3 = Japan, - 4 = Korea, - 5 = Spain, - 6 = France, - 7 = Israel, - 8 = Australia - -essid string ESS ID - network name to join - - string with maximum length of 32 chars - default value = "ADHOC_ESSID" - -hop_dwell integer hop dwell time in Kilo-microseconds - - legal values = 16,32,64,128(default),256 - -irq_mask integer linux standard 16 bit value 1bit/IRQ - - lsb is IRQ 0, bit 1 is IRQ 1 etc. - Used to restrict choice of IRQ's to use. - Recommended method for controlling - interrupts is in /etc/pcmcia/config.opts - -net_type integer 0 (default) = adhoc network, - 1 = infrastructure - -phy_addr string string containing new MAC address in - hex, must start with x eg - x00008f123456 - -psm integer 0 = continuously active, - 1 = power save mode (not useful yet) - -pc_debug integer (0-5) larger values for more verbose - logging. Replaces ray_debug. - -ray_debug integer Replaced with pc_debug - -ray_mem_speed integer defaults to 500 - -sniffer integer 0 = not sniffer (default), - 1 = sniffer which can be used to record all - network traffic using tcpdump or similar, - but no normal network use is allowed. - -translate integer 0 = no translation (encapsulate frames), - 1 = translation (RFC1042/802.1) -=============== =============== ============================================= - -More on sniffer mode: - -tcpdump does not understand 802.11 headers, so it can't -interpret the contents, but it can record to a file. This is only -useful for debugging 802.11 lowlevel protocols that are not visible to -linux. If you want to watch ftp xfers, or do similar things, you -don't need to use sniffer mode. Also, some packet types are never -sent up by the card, so you will never see them (ack, rts, cts, probe -etc.) There is a simple program (showcap) included in the ray_cs -package which parses the 802.11 headers. - -Known Problems and missing features - - Does not work with non x86 - - Does not work with SMP - - Support for defragmenting frames is not yet debugged, and in - fact is known to not work. I have never encountered a net set - up to fragment, but still, it should be fixed. - - The ioctl support is incomplete. The hardware address cannot be set - using ifconfig yet. If a different hardware address is needed, it may - be set using the phy_addr parameter in ray_cs.opts. This requires - a card insertion to take effect. diff --git a/Documentation/networking/devlink/devlink-reload.rst b/Documentation/networking/devlink/devlink-reload.rst index 505d22da027d1b..2fb0269b2054f9 100644 --- a/Documentation/networking/devlink/devlink-reload.rst +++ b/Documentation/networking/devlink/devlink-reload.rst @@ -22,8 +22,17 @@ By default ``driver_reinit`` action is selected. * - ``driver-reinit`` - Devlink driver entities re-initialization, including applying new values to devlink entities which are used during driver - load such as ``devlink-params`` in configuration mode - ``driverinit`` or ``devlink-resources`` + load which are: + + * ``devlink-params`` in configuration mode ``driverinit`` + * ``devlink-resources`` + + Other devlink entities may stay over the re-initialization: + + * ``devlink-health-reporter`` + * ``devlink-region`` + + The rest of the devlink entities have to be removed and readded. * - ``fw_activate`` - Firmware activate. Activates new firmware if such image is stored and pending activation. If no limitation specified this action may involve diff --git a/Documentation/networking/devlink/ice.rst b/Documentation/networking/devlink/ice.rst index 2f60e34ab9267b..7f30ebd5debb75 100644 --- a/Documentation/networking/devlink/ice.rst +++ b/Documentation/networking/devlink/ice.rst @@ -38,6 +38,10 @@ The ``ice`` driver reports the following versions - fixed - K65390-000 - The Product Board Assembly (PBA) identifier of the board. + * - ``cgu.id`` + - fixed + - 36 + - The Clock Generation Unit (CGU) hardware revision identifier. * - ``fw.mgmt`` - running - 2.1.7 @@ -104,6 +108,11 @@ The ``ice`` driver reports the following versions - running - 0xee16ced7 - The first 4 bytes of the hash of the netlist module contents. + * - ``fw.cgu`` + - running + - 8032.16973825.6021 + - The version of Clock Generation Unit (CGU). Format: + ... Flash Update ============ diff --git a/Documentation/networking/ethtool-netlink.rst b/Documentation/networking/ethtool-netlink.rst index 2540c70952ff21..d583d9abf2f806 100644 --- a/Documentation/networking/ethtool-netlink.rst +++ b/Documentation/networking/ethtool-netlink.rst @@ -223,6 +223,9 @@ Userspace to kernel: ``ETHTOOL_MSG_PSE_SET`` set PSE parameters ``ETHTOOL_MSG_PSE_GET`` get PSE parameters ``ETHTOOL_MSG_RSS_GET`` get RSS settings + ``ETHTOOL_MSG_PLCA_GET_CFG`` get PLCA RS parameters + ``ETHTOOL_MSG_PLCA_SET_CFG`` set PLCA RS parameters + ``ETHTOOL_MSG_PLCA_GET_STATUS`` get PLCA RS status ``ETHTOOL_MSG_MM_GET`` get MAC merge layer state ``ETHTOOL_MSG_MM_SET`` set MAC merge layer parameters ===================================== ================================= @@ -267,6 +270,9 @@ Kernel to userspace: ``ETHTOOL_MSG_MODULE_GET_REPLY`` transceiver module parameters ``ETHTOOL_MSG_PSE_GET_REPLY`` PSE parameters ``ETHTOOL_MSG_RSS_GET_REPLY`` RSS settings + ``ETHTOOL_MSG_PLCA_GET_CFG_REPLY`` PLCA RS parameters + ``ETHTOOL_MSG_PLCA_GET_STATUS_REPLY`` PLCA RS status + ``ETHTOOL_MSG_PLCA_NTF`` PLCA RS parameters ``ETHTOOL_MSG_MM_GET_REPLY`` MAC merge layer status ======================================== ================================= @@ -1768,12 +1774,16 @@ Kernel response contents: ``ETHTOOL_A_RSS_HFUNC`` u32 RSS hash func ``ETHTOOL_A_RSS_INDIR`` binary Indir table bytes ``ETHTOOL_A_RSS_HKEY`` binary Hash key bytes + ``ETHTOOL_A_RSS_INPUT_XFRM`` u32 RSS input data transformation ===================================== ====== ========================== ETHTOOL_A_RSS_HFUNC attribute is bitmap indicating the hash function being used. Current supported options are toeplitz, xor or crc32. -ETHTOOL_A_RSS_INDIR attribute returns RSS indrection table where each byte +ETHTOOL_A_RSS_INDIR attribute returns RSS indirection table where each byte indicates queue number. +ETHTOOL_A_RSS_INPUT_XFRM attribute is a bitmap indicating the type of +transformation applied to the input protocol fields before given to the RSS +hfunc. Current supported option is symmetric-xor. PLCA_GET_CFG ============ diff --git a/Documentation/networking/index.rst b/Documentation/networking/index.rst index 683eb42309cc5b..69f3d6dcd9fd81 100644 --- a/Documentation/networking/index.rst +++ b/Documentation/networking/index.rst @@ -55,6 +55,7 @@ Contents: filter generic-hdlc generic_netlink + netlink_spec/index gen_stats gtp ila @@ -74,6 +75,7 @@ Contents: mptcp-sysctl multiqueue napi + net_cachelines/index netconsole netdev-features netdevices @@ -123,6 +125,7 @@ Contents: xfrm_sync xfrm_sysctl xdp-rx-metadata + xsk-tx-metadata .. only:: subproject and html diff --git a/Documentation/networking/net_cachelines/index.rst b/Documentation/networking/net_cachelines/index.rst new file mode 100644 index 00000000000000..2669e4cda086b6 --- /dev/null +++ b/Documentation/networking/net_cachelines/index.rst @@ -0,0 +1,16 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. Copyright (C) 2023 Google LLC + +=================================== +Common Networking Struct Cachelines +=================================== + +.. toctree:: + :maxdepth: 1 + + inet_connection_sock + inet_sock + net_device + netns_ipv4_sysctl + snmp + tcp_sock diff --git a/Documentation/networking/net_cachelines/inet_connection_sock.rst b/Documentation/networking/net_cachelines/inet_connection_sock.rst new file mode 100644 index 00000000000000..7a911dc95652ea --- /dev/null +++ b/Documentation/networking/net_cachelines/inet_connection_sock.rst @@ -0,0 +1,50 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. Copyright (C) 2023 Google LLC + +===================================================== +inet_connection_sock struct fast path usage breakdown +===================================================== + +Type Name fastpath_tx_access fastpath_rx_access comment +..struct ..inet_connection_sock +struct_inet_sock icsk_inet read_mostly read_mostly tcp_init_buffer_space,tcp_init_transfer,tcp_finish_connect,tcp_connect,tcp_send_rcvq,tcp_send_syn_data +struct_request_sock_queue icsk_accept_queue - - +struct_inet_bind_bucket icsk_bind_hash read_mostly - tcp_set_state +struct_inet_bind2_bucket icsk_bind2_hash read_mostly - tcp_set_state,inet_put_port +unsigned_long icsk_timeout read_mostly - inet_csk_reset_xmit_timer,tcp_connect +struct_timer_list icsk_retransmit_timer read_mostly - inet_csk_reset_xmit_timer,tcp_connect +struct_timer_list icsk_delack_timer read_mostly - inet_csk_reset_xmit_timer,tcp_connect +u32 icsk_rto read_write - tcp_cwnd_validate,tcp_schedule_loss_probe,tcp_connect_init,tcp_connect,tcp_write_xmit,tcp_push_one +u32 icsk_rto_min - - +u32 icsk_delack_max - - +u32 icsk_pmtu_cookie read_write - tcp_sync_mss,tcp_current_mss,tcp_send_syn_data,tcp_connect_init,tcp_connect +struct_tcp_congestion_ops icsk_ca_ops read_write - tcp_cwnd_validate,tcp_tso_segs,tcp_ca_dst_init,tcp_connect_init,tcp_connect,tcp_write_xmit +struct_inet_connection_sock_af_ops icsk_af_ops read_mostly - tcp_finish_connect,tcp_send_syn_data,tcp_mtup_init,tcp_mtu_check_reprobe,tcp_mtu_probe,tcp_connect_init,tcp_connect,__tcp_transmit_skb +struct_tcp_ulp_ops* icsk_ulp_ops - - +void* icsk_ulp_data - - +u8:5 icsk_ca_state read_write - tcp_cwnd_application_limited,tcp_set_ca_state,tcp_enter_cwr,tcp_tso_should_defer,tcp_mtu_probe,tcp_schedule_loss_probe,tcp_write_xmit,__tcp_transmit_skb +u8:1 icsk_ca_initialized read_write - tcp_init_transfer,tcp_init_congestion_control,tcp_init_transfer,tcp_finish_connect,tcp_connect +u8:1 icsk_ca_setsockopt - - +u8:1 icsk_ca_dst_locked write_mostly - tcp_ca_dst_init,tcp_connect_init,tcp_connect +u8 icsk_retransmits write_mostly - tcp_connect_init,tcp_connect +u8 icsk_pending read_write - inet_csk_reset_xmit_timer,tcp_connect,tcp_check_probe_timer,__tcp_push_pending_frames,tcp_rearm_rto,tcp_event_new_data_sent,tcp_event_new_data_sent +u8 icsk_backoff write_mostly - tcp_write_queue_purge,tcp_connect_init +u8 icsk_syn_retries - - +u8 icsk_probes_out - - +u16 icsk_ext_hdr_len read_mostly - __tcp_mtu_to_mss,tcp_mtu_to_rss,tcp_mtu_probe,tcp_write_xmit,tcp_mtu_to_mss, +struct_icsk_ack_u8 pending read_write read_write inet_csk_ack_scheduled,__tcp_cleanup_rbuf,tcp_cleanup_rbuf,inet_csk_clear_xmit_timer,tcp_event_ack-sent,inet_csk_reset_xmit_timer +struct_icsk_ack_u8 quick read_write write_mostly tcp_dec_quickack_mode,tcp_event_ack_sent,__tcp_transmit_skb,__tcp_select_window,__tcp_cleanup_rbuf +struct_icsk_ack_u8 pingpong - - +struct_icsk_ack_u8 retry write_mostly read_write inet_csk_clear_xmit_timer,tcp_rearm_rto,tcp_event_new_data_sent,tcp_write_xmit,__tcp_send_ack,tcp_send_ack, +struct_icsk_ack_u8 ato read_mostly write_mostly tcp_dec_quickack_mode,tcp_event_ack_sent,__tcp_transmit_skb,__tcp_send_ack,tcp_send_ack +struct_icsk_ack_unsigned_long timeout read_write read_write inet_csk_reset_xmit_timer,tcp_connect +struct_icsk_ack_u32 lrcvtime read_write - tcp_finish_connect,tcp_connect,tcp_event_data_sent,__tcp_transmit_skb +struct_icsk_ack_u16 rcv_mss write_mostly read_mostly __tcp_select_window,__tcp_cleanup_rbuf,tcp_initialize_rcv_mss,tcp_connect_init +struct_icsk_mtup_int search_high read_write - tcp_mtup_init,tcp_sync_mss,tcp_connect_init,tcp_mtu_check_reprobe,tcp_write_xmit +struct_icsk_mtup_int search_low read_write - tcp_mtu_probe,tcp_mtu_check_reprobe,tcp_write_xmit,tcp_sync_mss,tcp_connect_init,tcp_mtup_init +struct_icsk_mtup_u32:31 probe_size read_write - tcp_mtup_init,tcp_connect_init,__tcp_transmit_skb +struct_icsk_mtup_u32:1 enabled read_write - tcp_mtup_init,tcp_sync_mss,tcp_connect_init,tcp_mtu_probe,tcp_write_xmit +struct_icsk_mtup_u32 probe_timestamp read_write - tcp_mtup_init,tcp_connect_init,tcp_mtu_check_reprobe,tcp_mtu_probe +u32 icsk_probes_tstamp - - +u32 icsk_user_timeout - - +u64[104/sizeof(u64)] icsk_ca_priv - - diff --git a/Documentation/networking/net_cachelines/inet_sock.rst b/Documentation/networking/net_cachelines/inet_sock.rst new file mode 100644 index 00000000000000..a2babd0d7954e6 --- /dev/null +++ b/Documentation/networking/net_cachelines/inet_sock.rst @@ -0,0 +1,44 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. Copyright (C) 2023 Google LLC + +===================================================== +inet_connection_sock struct fast path usage breakdown +===================================================== + +Type Name fastpath_tx_access fastpath_rx_access comment +..struct ..inet_sock +struct_sock sk read_mostly read_mostly tcp_init_buffer_space,tcp_init_transfer,tcp_finish_connect,tcp_connect,tcp_send_rcvq,tcp_send_syn_data +struct_ipv6_pinfo* pinet6 - - +be16 inet_sport read_mostly - __tcp_transmit_skb +be32 inet_daddr read_mostly - ip_select_ident_segs +be32 inet_rcv_saddr - - +be16 inet_dport read_mostly - __tcp_transmit_skb +u16 inet_num - - +be32 inet_saddr - - +s16 uc_ttl read_mostly - __ip_queue_xmit/ip_select_ttl +u16 cmsg_flags - - +struct_ip_options_rcu* inet_opt read_mostly - __ip_queue_xmit +u16 inet_id read_mostly - ip_select_ident_segs +u8 tos read_mostly - ip_queue_xmit +u8 min_ttl - - +u8 mc_ttl - - +u8 pmtudisc - - +u8:1 recverr - - +u8:1 is_icsk - - +u8:1 freebind - - +u8:1 hdrincl - - +u8:1 mc_loop - - +u8:1 transparent - - +u8:1 mc_all - - +u8:1 nodefrag - - +u8:1 bind_address_no_port - - +u8:1 recverr_rfc4884 - - +u8:1 defer_connect read_mostly - tcp_sendmsg_fastopen +u8 rcv_tos - - +u8 convert_csum - - +int uc_index - - +int mc_index - - +be32 mc_addr - - +struct_ip_mc_socklist* mc_list - - +struct_inet_cork_full cork read_mostly - __tcp_transmit_skb +struct local_port_range - - diff --git a/Documentation/networking/net_cachelines/net_device.rst b/Documentation/networking/net_cachelines/net_device.rst new file mode 100644 index 00000000000000..e75a53593bb960 --- /dev/null +++ b/Documentation/networking/net_cachelines/net_device.rst @@ -0,0 +1,178 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. Copyright (C) 2023 Google LLC + +=========================================== +net_device struct fast path usage breakdown +=========================================== + +Type Name fastpath_tx_access fastpath_rx_access Comments +..struct ..net_device +char name[16] - - +struct_netdev_name_node* name_node +struct_dev_ifalias* ifalias +unsigned_long mem_end +unsigned_long mem_start +unsigned_long base_addr +unsigned_long state +struct_list_head dev_list +struct_list_head napi_list +struct_list_head unreg_list +struct_list_head close_list +struct_list_head ptype_all read_mostly - dev_nit_active(tx) +struct_list_head ptype_specific read_mostly deliver_ptype_list_skb/__netif_receive_skb_core(rx) +struct adj_list +unsigned_int flags read_mostly read_mostly __dev_queue_xmit,__dev_xmit_skb,ip6_output,__ip6_finish_output(tx);ip6_rcv_core(rx) +xdp_features_t xdp_features +unsigned_long_long priv_flags read_mostly - __dev_queue_xmit(tx) +struct_net_device_ops* netdev_ops read_mostly - netdev_core_pick_tx,netdev_start_xmit(tx) +struct_xdp_metadata_ops* xdp_metadata_ops +int ifindex - read_mostly ip6_rcv_core +unsigned_short gflags +unsigned_short hard_header_len read_mostly read_mostly ip6_xmit(tx);gro_list_prepare(rx) +unsigned_int mtu read_mostly - ip_finish_output2 +unsigned_short needed_headroom read_mostly - LL_RESERVED_SPACE/ip_finish_output2 +unsigned_short needed_tailroom +netdev_features_t features read_mostly read_mostly HARD_TX_LOCK,netif_skb_features,sk_setup_caps(tx);netif_elide_gro(rx) +netdev_features_t hw_features +netdev_features_t wanted_features +netdev_features_t vlan_features +netdev_features_t hw_enc_features - - netif_skb_features +netdev_features_t mpls_features +netdev_features_t gso_partial_features read_mostly gso_features_check +unsigned_int min_mtu +unsigned_int max_mtu +unsigned_short type +unsigned_char min_header_len +unsigned_char name_assign_type +int group +struct_net_device_stats stats +struct_net_device_core_stats* core_stats +atomic_t carrier_up_count +atomic_t carrier_down_count +struct_iw_handler_def* wireless_handlers +struct_iw_public_data* wireless_data +struct_ethtool_ops* ethtool_ops +struct_l3mdev_ops* l3mdev_ops +struct_ndisc_ops* ndisc_ops +struct_xfrmdev_ops* xfrmdev_ops +struct_tlsdev_ops* tlsdev_ops +struct_header_ops* header_ops read_mostly - ip_finish_output2,ip6_finish_output2(tx) +unsigned_char operstate +unsigned_char link_mode +unsigned_char if_port +unsigned_char dma +unsigned_char perm_addr[32] +unsigned_char addr_assign_type +unsigned_char addr_len +unsigned_char upper_level +unsigned_char lower_level +unsigned_short neigh_priv_len +unsigned_short padded +unsigned_short dev_id +unsigned_short dev_port +spinlock_t addr_list_lock +int irq +struct_netdev_hw_addr_list uc +struct_netdev_hw_addr_list mc +struct_netdev_hw_addr_list dev_addrs +struct_kset* queues_kset +struct_list_head unlink_list +unsigned_int promiscuity +unsigned_int allmulti +bool uc_promisc +unsigned_char nested_level +struct_in_device* ip_ptr read_mostly read_mostly __in_dev_get +struct_inet6_dev* ip6_ptr read_mostly read_mostly __in6_dev_get +struct_vlan_info* vlan_info +struct_dsa_port* dsa_ptr +struct_tipc_bearer* tipc_ptr +void* atalk_ptr +void* ax25_ptr +struct_wireless_dev* ieee80211_ptr +struct_wpan_dev* ieee802154_ptr +struct_mpls_dev* mpls_ptr +struct_mctp_dev* mctp_ptr +unsigned_char* dev_addr +struct_netdev_queue* _rx read_mostly - netdev_get_rx_queue(rx) +unsigned_int num_rx_queues +unsigned_int real_num_rx_queues - read_mostly get_rps_cpu +struct_bpf_prog* xdp_prog - read_mostly netif_elide_gro() +unsigned_long gro_flush_timeout - read_mostly napi_complete_done +int napi_defer_hard_irqs - read_mostly napi_complete_done +unsigned_int gro_max_size - read_mostly skb_gro_receive +unsigned_int gro_ipv4_max_size - read_mostly skb_gro_receive +rx_handler_func_t* rx_handler read_mostly - __netif_receive_skb_core +void* rx_handler_data read_mostly - +struct_netdev_queue* ingress_queue read_mostly - +struct_bpf_mprog_entry tcx_ingress - read_mostly sch_handle_ingress +struct_nf_hook_entries* nf_hooks_ingress +unsigned_char broadcast[32] +struct_cpu_rmap* rx_cpu_rmap +struct_hlist_node index_hlist +struct_netdev_queue* _tx read_mostly - netdev_get_tx_queue(tx) +unsigned_int num_tx_queues - - +unsigned_int real_num_tx_queues read_mostly - skb_tx_hash,netdev_core_pick_tx(tx) +unsigned_int tx_queue_len +spinlock_t tx_global_lock +struct_xdp_dev_bulk_queue__percpu* xdp_bulkq +struct_xps_dev_maps* xps_maps[2] read_mostly - __netif_set_xps_queue +struct_bpf_mprog_entry tcx_egress read_mostly - sch_handle_egress +struct_nf_hook_entries* nf_hooks_egress read_mostly - +struct_hlist_head qdisc_hash[16] +struct_timer_list watchdog_timer +int watchdog_timeo +u32 proto_down_reason +struct_list_head todo_list +int__percpu* pcpu_refcnt +refcount_t dev_refcnt +struct_ref_tracker_dir refcnt_tracker +struct_list_head link_watch_list +enum:8 reg_state +bool dismantle +enum:16 rtnl_link_state +bool needs_free_netdev +void*priv_destructor struct_net_device +struct_netpoll_info* npinfo - read_mostly napi_poll/napi_poll_lock +possible_net_t nd_net - read_mostly (dev_net)napi_busy_loop,tcp_v(4/6)_rcv,ip(v6)_rcv,ip(6)_input,ip(6)_input_finish +void* ml_priv +enum_netdev_ml_priv_type ml_priv_type +struct_pcpu_lstats__percpu* lstats +struct_pcpu_sw_netstats__percpu* tstats +struct_pcpu_dstats__percpu* dstats +struct_garp_port* garp_port +struct_mrp_port* mrp_port +struct_dm_hw_stat_delta* dm_private +struct_device dev - - +struct_attribute_group* sysfs_groups[4] +struct_attribute_group* sysfs_rx_queue_group +struct_rtnl_link_ops* rtnl_link_ops +unsigned_int gso_max_size read_mostly - sk_dst_gso_max_size +unsigned_int tso_max_size +u16 gso_max_segs read_mostly - gso_max_segs +u16 tso_max_segs +unsigned_int gso_ipv4_max_size read_mostly - sk_dst_gso_max_size +struct_dcbnl_rtnl_ops* dcbnl_ops +s16 num_tc read_mostly - skb_tx_hash +struct_netdev_tc_txq tc_to_txq[16] read_mostly - skb_tx_hash +u8 prio_tc_map[16] +unsigned_int fcoe_ddp_xid +struct_netprio_map* priomap +struct_phy_device* phydev +struct_sfp_bus* sfp_bus +struct_lock_class_key* qdisc_tx_busylock +bool proto_down +unsigned:1 wol_enabled +unsigned:1 threaded - - napi_poll(napi_enable,dev_set_threaded) +struct_list_head net_notifier_list +struct_macsec_ops* macsec_ops +struct_udp_tunnel_nic_info* udp_tunnel_nic_info +struct_udp_tunnel_nic* udp_tunnel_nic +unsigned_int xdp_zc_max_segs +struct_bpf_xdp_entity xdp_state[3] +u8 dev_addr_shadow[32] +netdevice_tracker linkwatch_dev_tracker +netdevice_tracker watchdog_dev_tracker +netdevice_tracker dev_registered_tracker +struct_rtnl_hw_stats64* offload_xstats_l3 +struct_devlink_port* devlink_port +struct_dpll_pin* dpll_pin diff --git a/Documentation/networking/net_cachelines/netns_ipv4_sysctl.rst b/Documentation/networking/net_cachelines/netns_ipv4_sysctl.rst new file mode 100644 index 00000000000000..9b87089a84c61e --- /dev/null +++ b/Documentation/networking/net_cachelines/netns_ipv4_sysctl.rst @@ -0,0 +1,158 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. Copyright (C) 2023 Google LLC + +=========================================== +netns_ipv4 struct fast path usage breakdown +=========================================== + +Type Name fastpath_tx_access fastpath_rx_access comment +..struct ..netns_ipv4 +struct_inet_timewait_death_row tcp_death_row +struct_udp_table* udp_table +struct_ctl_table_header* forw_hdr +struct_ctl_table_header* frags_hdr +struct_ctl_table_header* ipv4_hdr +struct_ctl_table_header* route_hdr +struct_ctl_table_header* xfrm4_hdr +struct_ipv4_devconf* devconf_all +struct_ipv4_devconf* devconf_dflt +struct_ip_ra_chain ra_chain +struct_mutex ra_mutex +struct_fib_rules_ops* rules_ops +struct_fib_table fib_main +struct_fib_table fib_default +unsigned_int fib_rules_require_fldissect +bool fib_has_custom_rules +bool fib_has_custom_local_routes +bool fib_offload_disabled +atomic_t fib_num_tclassid_users +struct_hlist_head* fib_table_hash +struct_sock* fibnl +struct_sock* mc_autojoin_sk +struct_inet_peer_base* peers +struct_fqdir* fqdir +u8 sysctl_icmp_echo_ignore_all +u8 sysctl_icmp_echo_enable_probe +u8 sysctl_icmp_echo_ignore_broadcasts +u8 sysctl_icmp_ignore_bogus_error_responses +u8 sysctl_icmp_errors_use_inbound_ifaddr +int sysctl_icmp_ratelimit +int sysctl_icmp_ratemask +u32 ip_rt_min_pmtu - - +int ip_rt_mtu_expires - - +int ip_rt_min_advmss - - +struct_local_ports ip_local_ports - - +u8 sysctl_tcp_ecn - - +u8 sysctl_tcp_ecn_fallback - - +u8 sysctl_ip_default_ttl - - ip4_dst_hoplimit/ip_select_ttl +u8 sysctl_ip_no_pmtu_disc - - +u8 sysctl_ip_fwd_use_pmtu read_mostly - ip_dst_mtu_maybe_forward/ip_skb_dst_mtu +u8 sysctl_ip_fwd_update_priority - - ip_forward +u8 sysctl_ip_nonlocal_bind - - +u8 sysctl_ip_autobind_reuse - - +u8 sysctl_ip_dynaddr - - +u8 sysctl_ip_early_demux - read_mostly ip(6)_rcv_finish_core +u8 sysctl_raw_l3mdev_accept - - +u8 sysctl_tcp_early_demux - read_mostly ip(6)_rcv_finish_core +u8 sysctl_udp_early_demux +u8 sysctl_nexthop_compat_mode - - +u8 sysctl_fwmark_reflect - - +u8 sysctl_tcp_fwmark_accept - - +u8 sysctl_tcp_l3mdev_accept - - +u8 sysctl_tcp_mtu_probing - - +int sysctl_tcp_mtu_probe_floor - - +int sysctl_tcp_base_mss - - +int sysctl_tcp_min_snd_mss read_mostly - __tcp_mtu_to_mss(tcp_write_xmit) +int sysctl_tcp_probe_threshold - - tcp_mtu_probe(tcp_write_xmit) +u32 sysctl_tcp_probe_interval - - tcp_mtu_check_reprobe(tcp_write_xmit) +int sysctl_tcp_keepalive_time - - +int sysctl_tcp_keepalive_intvl - - +u8 sysctl_tcp_keepalive_probes - - +u8 sysctl_tcp_syn_retries - - +u8 sysctl_tcp_synack_retries - - +u8 sysctl_tcp_syncookies - - generated_on_syn +u8 sysctl_tcp_migrate_req - - reuseport +u8 sysctl_tcp_comp_sack_nr - - __tcp_ack_snd_check +int sysctl_tcp_reordering - read_mostly tcp_may_raise_cwnd/tcp_cong_control +u8 sysctl_tcp_retries1 - - +u8 sysctl_tcp_retries2 - - +u8 sysctl_tcp_orphan_retries - - +u8 sysctl_tcp_tw_reuse - - timewait_sock_ops +int sysctl_tcp_fin_timeout - - TCP_LAST_ACK/tcp_rcv_state_process +unsigned_int sysctl_tcp_notsent_lowat read_mostly - tcp_notsent_lowat/tcp_stream_memory_free +u8 sysctl_tcp_sack - - tcp_syn_options +u8 sysctl_tcp_window_scaling - - tcp_syn_options,tcp_parse_options +u8 sysctl_tcp_timestamps +u8 sysctl_tcp_early_retrans read_mostly - tcp_schedule_loss_probe(tcp_write_xmit) +u8 sysctl_tcp_recovery - - tcp_fastretrans_alert +u8 sysctl_tcp_thin_linear_timeouts - - tcp_retrans_timer(on_thin_streams) +u8 sysctl_tcp_slow_start_after_idle - - unlikely(tcp_cwnd_validate-network-not-starved) +u8 sysctl_tcp_retrans_collapse - - +u8 sysctl_tcp_stdurg - - unlikely(tcp_check_urg) +u8 sysctl_tcp_rfc1337 - - +u8 sysctl_tcp_abort_on_overflow - - +u8 sysctl_tcp_fack - - +int sysctl_tcp_max_reordering - - tcp_check_sack_reordering +int sysctl_tcp_adv_win_scale - - tcp_init_buffer_space +u8 sysctl_tcp_dsack - - partial_packet_or_retrans_in_tcp_data_queue +u8 sysctl_tcp_app_win - - tcp_win_from_space +u8 sysctl_tcp_frto - - tcp_enter_loss +u8 sysctl_tcp_nometrics_save - - TCP_LAST_ACK/tcp_update_metrics +u8 sysctl_tcp_no_ssthresh_metrics_save - - TCP_LAST_ACK/tcp_(update/init)_metrics +u8 sysctl_tcp_moderate_rcvbuf read_mostly read_mostly tcp_tso_should_defer(tx);tcp_rcv_space_adjust(rx) +u8 sysctl_tcp_tso_win_divisor read_mostly - tcp_tso_should_defer(tcp_write_xmit) +u8 sysctl_tcp_workaround_signed_windows - - tcp_select_window +int sysctl_tcp_limit_output_bytes read_mostly - tcp_small_queue_check(tcp_write_xmit) +int sysctl_tcp_challenge_ack_limit - - +int sysctl_tcp_min_rtt_wlen read_mostly - tcp_ack_update_rtt +u8 sysctl_tcp_min_tso_segs - - unlikely(icsk_ca_ops-written) +u8 sysctl_tcp_tso_rtt_log read_mostly - tcp_tso_autosize +u8 sysctl_tcp_autocorking read_mostly - tcp_push/tcp_should_autocork +u8 sysctl_tcp_reflect_tos - - tcp_v(4/6)_send_synack +int sysctl_tcp_invalid_ratelimit - - +int sysctl_tcp_pacing_ss_ratio - - default_cong_cont(tcp_update_pacing_rate) +int sysctl_tcp_pacing_ca_ratio - - default_cong_cont(tcp_update_pacing_rate) +int sysctl_tcp_wmem[3] read_mostly - tcp_wmem_schedule(sendmsg/sendpage) +int sysctl_tcp_rmem[3] - read_mostly __tcp_grow_window(tx),tcp_rcv_space_adjust(rx) +unsigned_int sysctl_tcp_child_ehash_entries +unsigned_long sysctl_tcp_comp_sack_delay_ns - - __tcp_ack_snd_check +unsigned_long sysctl_tcp_comp_sack_slack_ns - - __tcp_ack_snd_check +int sysctl_max_syn_backlog - - +int sysctl_tcp_fastopen - - +struct_tcp_congestion_ops tcp_congestion_control - - init_cc +struct_tcp_fastopen_context tcp_fastopen_ctx - - +unsigned_int sysctl_tcp_fastopen_blackhole_timeout - - +atomic_t tfo_active_disable_times - - +unsigned_long tfo_active_disable_stamp - - +u32 tcp_challenge_timestamp - - +u32 tcp_challenge_count - - +u8 sysctl_tcp_plb_enabled - - +u8 sysctl_tcp_plb_idle_rehash_rounds - - +u8 sysctl_tcp_plb_rehash_rounds - - +u8 sysctl_tcp_plb_suspend_rto_sec - - +int sysctl_tcp_plb_cong_thresh - - +int sysctl_udp_wmem_min +int sysctl_udp_rmem_min +u8 sysctl_fib_notify_on_flag_change +u8 sysctl_udp_l3mdev_accept +u8 sysctl_igmp_llm_reports +int sysctl_igmp_max_memberships +int sysctl_igmp_max_msf +int sysctl_igmp_qrv +struct_ping_group_range ping_group_range +atomic_t dev_addr_genid +unsigned_int sysctl_udp_child_hash_entries +unsigned_long* sysctl_local_reserved_ports +int sysctl_ip_prot_sock +struct_mr_table* mrt +struct_list_head mr_tables +struct_fib_rules_ops* mr_rules_ops +u32 sysctl_fib_multipath_hash_fields +u8 sysctl_fib_multipath_use_neigh +u8 sysctl_fib_multipath_hash_policy +struct_fib_notifier_ops* notifier_ops +unsigned_int fib_seq +struct_fib_notifier_ops* ipmr_notifier_ops +unsigned_int ipmr_seq +atomic_t rt_genid +siphash_key_t ip_id_key diff --git a/Documentation/networking/net_cachelines/snmp.rst b/Documentation/networking/net_cachelines/snmp.rst new file mode 100644 index 00000000000000..6a071538566c2a --- /dev/null +++ b/Documentation/networking/net_cachelines/snmp.rst @@ -0,0 +1,135 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. Copyright (C) 2023 Google LLC + +=========================================== +netns_ipv4 enum fast path usage breakdown +=========================================== + +Type Name fastpath_tx_access fastpath_rx_access comment +..enum +unsigned_long LINUX_MIB_TCPKEEPALIVE write_mostly - tcp_keepalive_timer +unsigned_long LINUX_MIB_DELAYEDACKS write_mostly - tcp_delack_timer_handler,tcp_delack_timer +unsigned_long LINUX_MIB_DELAYEDACKLOCKED write_mostly - tcp_delack_timer_handler,tcp_delack_timer +unsigned_long LINUX_MIB_TCPAUTOCORKING write_mostly - tcp_push,tcp_sendmsg_locked +unsigned_long LINUX_MIB_TCPFROMZEROWINDOWADV write_mostly - tcp_select_window,tcp_transmit-skb +unsigned_long LINUX_MIB_TCPTOZEROWINDOWADV write_mostly - tcp_select_window,tcp_transmit-skb +unsigned_long LINUX_MIB_TCPWANTZEROWINDOWADV write_mostly - tcp_select_window,tcp_transmit-skb +unsigned_long LINUX_MIB_TCPORIGDATASENT write_mostly - tcp_write_xmit +unsigned_long LINUX_MIB_TCPHPHITS - write_mostly tcp_rcv_established,tcp_v4_do_rcv,tcp_v6_do_rcv +unsigned_long LINUX_MIB_TCPRCVCOALESCE - write_mostly tcp_try_coalesce,tcp_queue_rcv,tcp_rcv_established +unsigned_long LINUX_MIB_TCPPUREACKS - write_mostly tcp_ack,tcp_rcv_established +unsigned_long LINUX_MIB_TCPHPACKS - write_mostly tcp_ack,tcp_rcv_established +unsigned_long LINUX_MIB_TCPDELIVERED - write_mostly tcp_newly_delivered,tcp_ack,tcp_rcv_established +unsigned_long LINUX_MIB_SYNCOOKIESSENT +unsigned_long LINUX_MIB_SYNCOOKIESRECV +unsigned_long LINUX_MIB_SYNCOOKIESFAILED +unsigned_long LINUX_MIB_EMBRYONICRSTS +unsigned_long LINUX_MIB_PRUNECALLED +unsigned_long LINUX_MIB_RCVPRUNED +unsigned_long LINUX_MIB_OFOPRUNED +unsigned_long LINUX_MIB_OUTOFWINDOWICMPS +unsigned_long LINUX_MIB_LOCKDROPPEDICMPS +unsigned_long LINUX_MIB_ARPFILTER +unsigned_long LINUX_MIB_TIMEWAITED +unsigned_long LINUX_MIB_TIMEWAITRECYCLED +unsigned_long LINUX_MIB_TIMEWAITKILLED +unsigned_long LINUX_MIB_PAWSACTIVEREJECTED +unsigned_long LINUX_MIB_PAWSESTABREJECTED +unsigned_long LINUX_MIB_DELAYEDACKLOST +unsigned_long LINUX_MIB_LISTENOVERFLOWS +unsigned_long LINUX_MIB_LISTENDROPS +unsigned_long LINUX_MIB_TCPRENORECOVERY +unsigned_long LINUX_MIB_TCPSACKRECOVERY +unsigned_long LINUX_MIB_TCPSACKRENEGING +unsigned_long LINUX_MIB_TCPSACKREORDER +unsigned_long LINUX_MIB_TCPRENOREORDER +unsigned_long LINUX_MIB_TCPTSREORDER +unsigned_long LINUX_MIB_TCPFULLUNDO +unsigned_long LINUX_MIB_TCPPARTIALUNDO +unsigned_long LINUX_MIB_TCPDSACKUNDO +unsigned_long LINUX_MIB_TCPLOSSUNDO +unsigned_long LINUX_MIB_TCPLOSTRETRANSMIT +unsigned_long LINUX_MIB_TCPRENOFAILURES +unsigned_long LINUX_MIB_TCPSACKFAILURES +unsigned_long LINUX_MIB_TCPLOSSFAILURES +unsigned_long LINUX_MIB_TCPFASTRETRANS +unsigned_long LINUX_MIB_TCPSLOWSTARTRETRANS +unsigned_long LINUX_MIB_TCPTIMEOUTS +unsigned_long LINUX_MIB_TCPLOSSPROBES +unsigned_long LINUX_MIB_TCPLOSSPROBERECOVERY +unsigned_long LINUX_MIB_TCPRENORECOVERYFAIL +unsigned_long LINUX_MIB_TCPSACKRECOVERYFAIL +unsigned_long LINUX_MIB_TCPRCVCOLLAPSED +unsigned_long LINUX_MIB_TCPDSACKOLDSENT +unsigned_long LINUX_MIB_TCPDSACKOFOSENT +unsigned_long LINUX_MIB_TCPDSACKRECV +unsigned_long LINUX_MIB_TCPDSACKOFORECV +unsigned_long LINUX_MIB_TCPABORTONDATA +unsigned_long LINUX_MIB_TCPABORTONCLOSE +unsigned_long LINUX_MIB_TCPABORTONMEMORY +unsigned_long LINUX_MIB_TCPABORTONTIMEOUT +unsigned_long LINUX_MIB_TCPABORTONLINGER +unsigned_long LINUX_MIB_TCPABORTFAILED +unsigned_long LINUX_MIB_TCPMEMORYPRESSURES +unsigned_long LINUX_MIB_TCPMEMORYPRESSURESCHRONO +unsigned_long LINUX_MIB_TCPSACKDISCARD +unsigned_long LINUX_MIB_TCPDSACKIGNOREDOLD +unsigned_long LINUX_MIB_TCPDSACKIGNOREDNOUNDO +unsigned_long LINUX_MIB_TCPSPURIOUSRTOS +unsigned_long LINUX_MIB_TCPMD5NOTFOUND +unsigned_long LINUX_MIB_TCPMD5UNEXPECTED +unsigned_long LINUX_MIB_TCPMD5FAILURE +unsigned_long LINUX_MIB_SACKSHIFTED +unsigned_long LINUX_MIB_SACKMERGED +unsigned_long LINUX_MIB_SACKSHIFTFALLBACK +unsigned_long LINUX_MIB_TCPBACKLOGDROP +unsigned_long LINUX_MIB_PFMEMALLOCDROP +unsigned_long LINUX_MIB_TCPMINTTLDROP +unsigned_long LINUX_MIB_TCPDEFERACCEPTDROP +unsigned_long LINUX_MIB_IPRPFILTER +unsigned_long LINUX_MIB_TCPTIMEWAITOVERFLOW +unsigned_long LINUX_MIB_TCPREQQFULLDOCOOKIES +unsigned_long LINUX_MIB_TCPREQQFULLDROP +unsigned_long LINUX_MIB_TCPRETRANSFAIL +unsigned_long LINUX_MIB_TCPBACKLOGCOALESCE +unsigned_long LINUX_MIB_TCPOFOQUEUE +unsigned_long LINUX_MIB_TCPOFODROP +unsigned_long LINUX_MIB_TCPOFOMERGE +unsigned_long LINUX_MIB_TCPCHALLENGEACK +unsigned_long LINUX_MIB_TCPSYNCHALLENGE +unsigned_long LINUX_MIB_TCPFASTOPENACTIVE +unsigned_long LINUX_MIB_TCPFASTOPENACTIVEFAIL +unsigned_long LINUX_MIB_TCPFASTOPENPASSIVE +unsigned_long LINUX_MIB_TCPFASTOPENPASSIVEFAIL +unsigned_long LINUX_MIB_TCPFASTOPENLISTENOVERFLOW +unsigned_long LINUX_MIB_TCPFASTOPENCOOKIEREQD +unsigned_long LINUX_MIB_TCPFASTOPENBLACKHOLE +unsigned_long LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES +unsigned_long LINUX_MIB_BUSYPOLLRXPACKETS +unsigned_long LINUX_MIB_TCPSYNRETRANS +unsigned_long LINUX_MIB_TCPHYSTARTTRAINDETECT +unsigned_long LINUX_MIB_TCPHYSTARTTRAINCWND +unsigned_long LINUX_MIB_TCPHYSTARTDELAYDETECT +unsigned_long LINUX_MIB_TCPHYSTARTDELAYCWND +unsigned_long LINUX_MIB_TCPACKSKIPPEDSYNRECV +unsigned_long LINUX_MIB_TCPACKSKIPPEDPAWS +unsigned_long LINUX_MIB_TCPACKSKIPPEDSEQ +unsigned_long LINUX_MIB_TCPACKSKIPPEDFINWAIT2 +unsigned_long LINUX_MIB_TCPACKSKIPPEDTIMEWAIT +unsigned_long LINUX_MIB_TCPACKSKIPPEDCHALLENGE +unsigned_long LINUX_MIB_TCPWINPROBE +unsigned_long LINUX_MIB_TCPMTUPFAIL +unsigned_long LINUX_MIB_TCPMTUPSUCCESS +unsigned_long LINUX_MIB_TCPDELIVEREDCE +unsigned_long LINUX_MIB_TCPACKCOMPRESSED +unsigned_long LINUX_MIB_TCPZEROWINDOWDROP +unsigned_long LINUX_MIB_TCPRCVQDROP +unsigned_long LINUX_MIB_TCPWQUEUETOOBIG +unsigned_long LINUX_MIB_TCPFASTOPENPASSIVEALTKEY +unsigned_long LINUX_MIB_TCPTIMEOUTREHASH +unsigned_long LINUX_MIB_TCPDUPLICATEDATAREHASH +unsigned_long LINUX_MIB_TCPDSACKRECVSEGS +unsigned_long LINUX_MIB_TCPDSACKIGNOREDDUBIOUS +unsigned_long LINUX_MIB_TCPMIGRATEREQSUCCESS +unsigned_long LINUX_MIB_TCPMIGRATEREQFAILURE +unsigned_long __LINUX_MIB_MAX diff --git a/Documentation/networking/net_cachelines/tcp_sock.rst b/Documentation/networking/net_cachelines/tcp_sock.rst new file mode 100644 index 00000000000000..97d7a5c8e01c02 --- /dev/null +++ b/Documentation/networking/net_cachelines/tcp_sock.rst @@ -0,0 +1,157 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. Copyright (C) 2023 Google LLC + +========================================= +tcp_sock struct fast path usage breakdown +========================================= + +Type Name fastpath_tx_access fastpath_rx_access Comments +..struct ..tcp_sock +struct_inet_connection_sock inet_conn +u16 tcp_header_len read_mostly read_mostly tcp_bound_to_half_wnd,tcp_current_mss(tx);tcp_rcv_established(rx) +u16 gso_segs read_mostly - tcp_xmit_size_goal +__be32 pred_flags read_write read_mostly tcp_select_window(tx);tcp_rcv_established(rx) +u64 bytes_received - read_write tcp_rcv_nxt_update(rx) +u32 segs_in - read_write tcp_v6_rcv(rx) +u32 data_segs_in - read_write tcp_v6_rcv(rx) +u32 rcv_nxt read_mostly read_write tcp_cleanup_rbuf,tcp_send_ack,tcp_inq_hint,tcp_transmit_skb,tcp_receive_window(tx);tcp_v6_do_rcv,tcp_rcv_established,tcp_data_queue,tcp_receive_window,tcp_rcv_nxt_update(write)(rx) +u32 copied_seq - read_mostly tcp_cleanup_rbuf,tcp_rcv_space_adjust,tcp_inq_hint +u32 rcv_wup - read_write __tcp_cleanup_rbuf,tcp_receive_window,tcp_receive_established +u32 snd_nxt read_write read_mostly tcp_rate_check_app_limited,__tcp_transmit_skb,tcp_event_new_data_sent(write)(tx);tcp_rcv_established,tcp_ack,tcp_clean_rtx_queue(rx) +u32 segs_out read_write - __tcp_transmit_skb +u32 data_segs_out read_write - __tcp_transmit_skb,tcp_update_skb_after_send +u64 bytes_sent read_write - __tcp_transmit_skb +u64 bytes_acked - read_write tcp_snd_una_update/tcp_ack +u32 dsack_dups +u32 snd_una read_mostly read_write tcp_wnd_end,tcp_urg_mode,tcp_minshall_check,tcp_cwnd_validate(tx);tcp_ack,tcp_may_update_window,tcp_clean_rtx_queue(write),tcp_ack_tstamp(rx) +u32 snd_sml read_write - tcp_minshall_check,tcp_minshall_update +u32 rcv_tstamp - read_mostly tcp_ack +u32 lsndtime read_write - tcp_slow_start_after_idle_check,tcp_event_data_sent +u32 last_oow_ack_time +u32 compressed_ack_rcv_nxt +u32 tsoffset read_mostly read_mostly tcp_established_options(tx);tcp_fast_parse_options(rx) +struct_list_head tsq_node - - +struct_list_head tsorted_sent_queue read_write - tcp_update_skb_after_send +u32 snd_wl1 - read_mostly tcp_may_update_window +u32 snd_wnd read_mostly read_mostly tcp_wnd_end,tcp_tso_should_defer(tx);tcp_fast_path_on(rx) +u32 max_window read_mostly - tcp_bound_to_half_wnd,forced_push +u32 mss_cache read_mostly read_mostly tcp_rate_check_app_limited,tcp_current_mss,tcp_sync_mss,tcp_sndbuf_expand,tcp_tso_should_defer(tx);tcp_update_pacing_rate,tcp_clean_rtx_queue(rx) +u32 window_clamp read_mostly read_write tcp_rcv_space_adjust,__tcp_select_window +u32 rcv_ssthresh read_mostly - __tcp_select_window +u82 scaling_ratio +struct tcp_rack +u16 advmss - read_mostly tcp_rcv_space_adjust +u8 compressed_ack +u8:2 dup_ack_counter +u8:1 tlp_retrans +u8:1 tcp_usec_ts +u32 chrono_start read_write - tcp_chrono_start/stop(tcp_write_xmit,tcp_cwnd_validate,tcp_send_syn_data) +u32[3] chrono_stat read_write - tcp_chrono_start/stop(tcp_write_xmit,tcp_cwnd_validate,tcp_send_syn_data) +u8:2 chrono_type read_write - tcp_chrono_start/stop(tcp_write_xmit,tcp_cwnd_validate,tcp_send_syn_data) +u8:1 rate_app_limited - read_write tcp_rate_gen +u8:1 fastopen_connect +u8:1 fastopen_no_cookie +u8:1 is_sack_reneg - read_mostly tcp_skb_entail,tcp_ack +u8:2 fastopen_client_fail +u8:4 nonagle read_write - tcp_skb_entail,tcp_push_pending_frames +u8:1 thin_lto +u8:1 recvmsg_inq +u8:1 repair read_mostly - tcp_write_xmit +u8:1 frto +u8 repair_queue - - +u8:2 save_syn +u8:1 syn_data +u8:1 syn_fastopen +u8:1 syn_fastopen_exp +u8:1 syn_fastopen_ch +u8:1 syn_data_acked +u8:1 is_cwnd_limited read_mostly - tcp_cwnd_validate,tcp_is_cwnd_limited +u32 tlp_high_seq - read_mostly tcp_ack +u32 tcp_tx_delay +u64 tcp_wstamp_ns read_write - tcp_pacing_check,tcp_tso_should_defer,tcp_update_skb_after_send +u64 tcp_clock_cache read_write read_write tcp_mstamp_refresh(tcp_write_xmit/tcp_rcv_space_adjust),__tcp_transmit_skb,tcp_tso_should_defer;timer +u64 tcp_mstamp read_write read_write tcp_mstamp_refresh(tcp_write_xmit/tcp_rcv_space_adjust)(tx);tcp_rcv_space_adjust,tcp_rate_gen,tcp_clean_rtx_queue,tcp_ack_update_rtt/tcp_time_stamp(rx);timer +u32 srtt_us read_mostly read_write tcp_tso_should_defer(tx);tcp_update_pacing_rate,__tcp_set_rto,tcp_rtt_estimator(rx) +u32 mdev_us read_write - tcp_rtt_estimator +u32 mdev_max_us +u32 rttvar_us - read_mostly __tcp_set_rto +u32 rtt_seq read_write tcp_rtt_estimator +struct_minmax rtt_min - read_mostly tcp_min_rtt/tcp_rate_gen,tcp_min_rtttcp_update_rtt_min +u32 packets_out read_write read_write tcp_packets_in_flight(tx/rx);tcp_slow_start_after_idle_check,tcp_nagle_check,tcp_rate_skb_sent,tcp_event_new_data_sent,tcp_cwnd_validate,tcp_write_xmit(tx);tcp_ack,tcp_clean_rtx_queue,tcp_update_pacing_rate(rx) +u32 retrans_out - read_mostly tcp_packets_in_flight,tcp_rate_check_app_limited +u32 max_packets_out - read_write tcp_cwnd_validate +u32 cwnd_usage_seq - read_write tcp_cwnd_validate +u16 urg_data - read_mostly tcp_fast_path_check +u8 ecn_flags read_write - tcp_ecn_send +u8 keepalive_probes +u32 reordering read_mostly - tcp_sndbuf_expand +u32 reord_seen +u32 snd_up read_write read_mostly tcp_mark_urg,tcp_urg_mode,__tcp_transmit_skb(tx);tcp_clean_rtx_queue(rx) +struct_tcp_options_received rx_opt read_mostly read_write tcp_established_options(tx);tcp_fast_path_on,tcp_ack_update_window,tcp_is_sack,tcp_data_queue,tcp_rcv_established,tcp_ack_update_rtt(rx) +u32 snd_ssthresh - read_mostly tcp_update_pacing_rate +u32 snd_cwnd read_mostly read_mostly tcp_snd_cwnd,tcp_rate_check_app_limited,tcp_tso_should_defer(tx);tcp_update_pacing_rate +u32 snd_cwnd_cnt +u32 snd_cwnd_clamp +u32 snd_cwnd_used +u32 snd_cwnd_stamp +u32 prior_cwnd +u32 prr_delivered +u32 prr_out read_mostly read_mostly tcp_rate_skb_sent,tcp_newly_delivered(tx);tcp_ack,tcp_rate_gen,tcp_clean_rtx_queue(rx) +u32 delivered read_mostly read_write tcp_rate_skb_sent, tcp_newly_delivered(tx);tcp_ack, tcp_rate_gen, tcp_clean_rtx_queue (rx) +u32 delivered_ce read_mostly read_write tcp_rate_skb_sent(tx);tcp_rate_gen(rx) +u32 lost - read_mostly tcp_ack +u32 app_limited read_write read_mostly tcp_rate_check_app_limited,tcp_rate_skb_sent(tx);tcp_rate_gen(rx) +u64 first_tx_mstamp read_write - tcp_rate_skb_sent +u64 delivered_mstamp read_write - tcp_rate_skb_sent +u32 rate_delivered - read_mostly tcp_rate_gen +u32 rate_interval_us - read_mostly rate_delivered,rate_app_limited +u32 rcv_wnd read_write read_mostly tcp_select_window,tcp_receive_window,tcp_fast_path_check +u32 write_seq read_write - tcp_rate_check_app_limited,tcp_write_queue_empty,tcp_skb_entail,forced_push,tcp_mark_push +u32 notsent_lowat read_mostly - tcp_stream_memory_free +u32 pushed_seq read_write - tcp_mark_push,forced_push +u32 lost_out read_mostly read_mostly tcp_left_out(tx);tcp_packets_in_flight(tx/rx);tcp_rate_check_app_limited(rx) +u32 sacked_out read_mostly read_mostly tcp_left_out(tx);tcp_packets_in_flight(tx/rx);tcp_clean_rtx_queue(rx) +struct_hrtimer pacing_timer +struct_hrtimer compressed_ack_timer +struct_sk_buff* lost_skb_hint read_mostly tcp_clean_rtx_queue +struct_sk_buff* retransmit_skb_hint read_mostly - tcp_clean_rtx_queue +struct_rb_root out_of_order_queue - read_mostly tcp_data_queue,tcp_fast_path_check +struct_sk_buff* ooo_last_skb +struct_tcp_sack_block[1] duplicate_sack +struct_tcp_sack_block[4] selective_acks +struct_tcp_sack_block[4] recv_sack_cache +struct_sk_buff* highest_sack read_write - tcp_event_new_data_sent +int lost_cnt_hint +u32 prior_ssthresh +u32 high_seq +u32 retrans_stamp +u32 undo_marker +int undo_retrans +u64 bytes_retrans +u32 total_retrans +u32 rto_stamp +u16 total_rto +u16 total_rto_recoveries +u32 total_rto_time +u32 urg_seq - - +unsigned_int keepalive_time +unsigned_int keepalive_intvl +int linger2 +u8 bpf_sock_ops_cb_flags +u8:1 bpf_chg_cc_inprogress +u16 timeout_rehash +u32 rcv_ooopack +u32 rcv_rtt_last_tsecr +struct rcv_rtt_est - read_write tcp_rcv_space_adjust,tcp_rcv_established +struct rcvq_space - read_write tcp_rcv_space_adjust +struct mtu_probe +u32 plb_rehash +u32 mtu_info +bool is_mptcp +bool smc_hs_congested +bool syn_smc +struct_tcp_sock_af_ops* af_specific +struct_tcp_md5sig_info* md5sig_info +struct_tcp_fastopen_request* fastopen_req +struct_request_sock* fastopen_rsk +struct_saved_syn* saved_syn \ No newline at end of file diff --git a/Documentation/networking/netlink_spec/.gitignore b/Documentation/networking/netlink_spec/.gitignore new file mode 100644 index 00000000000000..30d85567b5921c --- /dev/null +++ b/Documentation/networking/netlink_spec/.gitignore @@ -0,0 +1 @@ +*.rst diff --git a/Documentation/networking/netlink_spec/readme.txt b/Documentation/networking/netlink_spec/readme.txt new file mode 100644 index 00000000000000..6763f99d216c13 --- /dev/null +++ b/Documentation/networking/netlink_spec/readme.txt @@ -0,0 +1,4 @@ +SPDX-License-Identifier: GPL-2.0 + +This file is populated during the build of the documentation (htmldocs) by the +tools/net/ynl/ynl-gen-rst.py script. diff --git a/Documentation/networking/packet_mmap.rst b/Documentation/networking/packet_mmap.rst index 30a3be3c48f398..dca15d15feaf99 100644 --- a/Documentation/networking/packet_mmap.rst +++ b/Documentation/networking/packet_mmap.rst @@ -263,20 +263,20 @@ the name indicates, this function allocates pages of memory, and the second argument is "order" or a power of two number of pages, that is (for PAGE_SIZE == 4096) order=0 ==> 4096 bytes, order=1 ==> 8192 bytes, order=2 ==> 16384 bytes, etc. The maximum size of a -region allocated by __get_free_pages is determined by the MAX_ORDER macro. More -precisely the limit can be calculated as:: +region allocated by __get_free_pages is determined by the MAX_PAGE_ORDER macro. +More precisely the limit can be calculated as:: - PAGE_SIZE << MAX_ORDER + PAGE_SIZE << MAX_PAGE_ORDER In a i386 architecture PAGE_SIZE is 4096 bytes - In a 2.4/i386 kernel MAX_ORDER is 10 - In a 2.6/i386 kernel MAX_ORDER is 11 + In a 2.4/i386 kernel MAX_PAGE_ORDER is 10 + In a 2.6/i386 kernel MAX_PAGE_ORDER is 11 So get_free_pages can allocate as much as 4MB or 8MB in a 2.4/2.6 kernel respectively, with an i386 architecture. User space programs can include /usr/include/sys/user.h and -/usr/include/linux/mmzone.h to get PAGE_SIZE MAX_ORDER declarations. +/usr/include/linux/mmzone.h to get PAGE_SIZE MAX_PAGE_ORDER declarations. The pagesize can also be determined dynamically with the getpagesize (2) system call. @@ -324,7 +324,7 @@ Definitions: (see /proc/slabinfo) depends on the architecture -- ``sizeof(void *)`` depends on the architecture -- PAGE_SIZE or getpagesize (2) - is the value defined with MAX_ORDER + is the value defined with MAX_PAGE_ORDER it's an upper bound of frame's capture size (more on this later) ============== ================================================================ diff --git a/Documentation/networking/page_pool.rst b/Documentation/networking/page_pool.rst index 60993cb56b3254..9d958128a57cbc 100644 --- a/Documentation/networking/page_pool.rst +++ b/Documentation/networking/page_pool.rst @@ -41,6 +41,11 @@ Architecture overview | Fast cache | | ptr-ring cache | +-----------------+ +------------------+ +Monitoring +========== +Information about page pools on the system can be accessed via the netdev +genetlink family (see Documentation/netlink/specs/netdev.yaml). + API interface ============= The number of pools created **must** match the number of hardware queues @@ -107,8 +112,9 @@ page_pool_get_stats() and structures described below are available. It takes a pointer to a ``struct page_pool`` and a pointer to a struct page_pool_stats allocated by the caller. -The API will fill in the provided struct page_pool_stats with -statistics about the page_pool. +Older drivers expose page pool statistics via ethtool or debugfs. +The same statistics are accessible via the netlink netdev family +in a driver-independent fashion. .. kernel-doc:: include/net/page_pool/types.h :identifiers: struct page_pool_recycle_stats diff --git a/Documentation/networking/scaling.rst b/Documentation/networking/scaling.rst index 03ae19a689fc58..4eb50bcb9d429e 100644 --- a/Documentation/networking/scaling.rst +++ b/Documentation/networking/scaling.rst @@ -44,6 +44,21 @@ by masking out the low order seven bits of the computed hash for the packet (usually a Toeplitz hash), taking this number as a key into the indirection table and reading the corresponding value. +Some NICs support symmetric RSS hashing where, if the IP (source address, +destination address) and TCP/UDP (source port, destination port) tuples +are swapped, the computed hash is the same. This is beneficial in some +applications that monitor TCP/IP flows (IDS, firewalls, ...etc) and need +both directions of the flow to land on the same Rx queue (and CPU). The +"Symmetric-XOR" is a type of RSS algorithms that achieves this hash +symmetry by XORing the input source and destination fields of the IP +and/or L4 protocols. This, however, results in reduced input entropy and +could potentially be exploited. Specifically, the algorithm XORs the input +as follows:: + + # (SRC_IP ^ DST_IP, SRC_IP ^ DST_IP, SRC_PORT ^ DST_PORT, SRC_PORT ^ DST_PORT) + +The result is then fed to the underlying RSS algorithm. + Some advanced NICs allow steering packets to queues based on programmable filters. For example, webserver bound TCP port 80 packets can be directed to their own receive queue. Such “n-tuple” filters can diff --git a/Documentation/networking/smc-sysctl.rst b/Documentation/networking/smc-sysctl.rst index 769149d98773a2..a874d007f2db55 100644 --- a/Documentation/networking/smc-sysctl.rst +++ b/Documentation/networking/smc-sysctl.rst @@ -57,3 +57,17 @@ rmem - INTEGER only allowed 512KiB for SMC-R and 1MiB for SMC-D. Default: 64KiB + +smcr_max_links_per_lgr - INTEGER + Controls the max number of links can be added to a SMC-R link group. Notice that + the actual number of the links added to a SMC-R link group depends on the number + of RDMA devices exist in the system. The acceptable value ranges from 1 to 2. Only + for SMC-R v2.1 and later. + + Default: 2 + +smcr_max_conns_per_lgr - INTEGER + Controls the max number of connections can be added to a SMC-R link group. The + acceptable value ranges from 16 to 255. Only for SMC-R v2.1 and later. + + Default: 255 diff --git a/Documentation/networking/snmp_counter.rst b/Documentation/networking/snmp_counter.rst index 21363747447895..ff1e6a8ffe2164 100644 --- a/Documentation/networking/snmp_counter.rst +++ b/Documentation/networking/snmp_counter.rst @@ -313,7 +313,7 @@ https://lwn.net/Articles/576263/ * TcpExtTCPOrigDataSent -This counter is explained by `kernel commit f19c29e3e391`_, I pasted the +This counter is explained by kernel commit f19c29e3e391, I pasted the explanation below:: TCPOrigDataSent: number of outgoing packets with original data (excluding @@ -323,7 +323,7 @@ explanation below:: * TCPSynRetrans -This counter is explained by `kernel commit f19c29e3e391`_, I pasted the +This counter is explained by kernel commit f19c29e3e391, I pasted the explanation below:: TCPSynRetrans: number of SYN and SYN/ACK retransmits to break down @@ -331,14 +331,12 @@ explanation below:: * TCPFastOpenActiveFail -This counter is explained by `kernel commit f19c29e3e391`_, I pasted the +This counter is explained by kernel commit f19c29e3e391, I pasted the explanation below:: TCPFastOpenActiveFail: Fast Open attempts (SYN/data) failed because the remote does not accept it or the attempts timed out. -.. _kernel commit f19c29e3e391: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=f19c29e3e391a66a273e9afebaf01917245148cd - * TcpExtListenOverflows and TcpExtListenDrops When kernel receives a SYN from a client, and if the TCP accept queue @@ -698,11 +696,9 @@ number of the SACK block. For more details, please refer the comment of the function tcp_is_sackblock_valid in the kernel source code. A SACK option could have up to 4 blocks, they are checked individually. E.g., if 3 blocks of a SACk is invalid, the -corresponding counter would be updated 3 times. The comment of the -`Add counters for discarded SACK blocks`_ patch has additional -explanation: - -.. _Add counters for discarded SACK blocks: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=18f02545a9a16c9a89778b91a162ad16d510bb32 +corresponding counter would be updated 3 times. The comment of commit +18f02545a9a1 ("[TCP] MIB: Add counters for discarded SACK blocks") +has additional explanation: * TcpExtTCPSACKDiscard diff --git a/Documentation/networking/timestamping.rst b/Documentation/networking/timestamping.rst index f17c01834a1230..5e93cd71f99f1b 100644 --- a/Documentation/networking/timestamping.rst +++ b/Documentation/networking/timestamping.rst @@ -357,7 +357,8 @@ enabling SOF_TIMESTAMPING_OPT_ID and comparing the byte offset at send time with the value returned for each timestamp. It can prevent the situation by always flushing the TCP stack in between requests, for instance by enabling TCP_NODELAY and disabling TCP_CORK and -autocork. +autocork. After linux-4.7, a better way to prevent coalescing is +to use MSG_EOR flag at sendmsg() time. These precautions ensure that the timestamp is generated only when all bytes have passed a timestamp point, assuming that the network stack diff --git a/Documentation/networking/xdp-rx-metadata.rst b/Documentation/networking/xdp-rx-metadata.rst index 205696780b7897..a6e0ece18be54b 100644 --- a/Documentation/networking/xdp-rx-metadata.rst +++ b/Documentation/networking/xdp-rx-metadata.rst @@ -1,3 +1,5 @@ +.. SPDX-License-Identifier: GPL-2.0 + =============== XDP RX Metadata =============== @@ -18,7 +20,13 @@ Currently, the following kfuncs are supported. In the future, as more metadata is supported, this set will grow: .. kernel-doc:: net/core/xdp.c - :identifiers: bpf_xdp_metadata_rx_timestamp bpf_xdp_metadata_rx_hash + :identifiers: bpf_xdp_metadata_rx_timestamp + +.. kernel-doc:: net/core/xdp.c + :identifiers: bpf_xdp_metadata_rx_hash + +.. kernel-doc:: net/core/xdp.c + :identifiers: bpf_xdp_metadata_rx_vlan_tag An XDP program can use these kfuncs to read the metadata into stack variables for its own consumption. Or, to pass the metadata on to other diff --git a/Documentation/networking/xsk-tx-metadata.rst b/Documentation/networking/xsk-tx-metadata.rst new file mode 100644 index 00000000000000..bd033fe95cca5f --- /dev/null +++ b/Documentation/networking/xsk-tx-metadata.rst @@ -0,0 +1,81 @@ +.. SPDX-License-Identifier: GPL-2.0 + +================== +AF_XDP TX Metadata +================== + +This document describes how to enable offloads when transmitting packets +via :doc:`af_xdp`. Refer to :doc:`xdp-rx-metadata` on how to access similar +metadata on the receive side. + +General Design +============== + +The headroom for the metadata is reserved via ``tx_metadata_len`` in +``struct xdp_umem_reg``. The metadata length is therefore the same for +every socket that shares the same umem. The metadata layout is a fixed UAPI, +refer to ``union xsk_tx_metadata`` in ``include/uapi/linux/if_xdp.h``. +Thus, generally, the ``tx_metadata_len`` field above should contain +``sizeof(union xsk_tx_metadata)``. + +The headroom and the metadata itself should be located right before +``xdp_desc->addr`` in the umem frame. Within a frame, the metadata +layout is as follows:: + + tx_metadata_len + / \ + +-----------------+---------+----------------------------+ + | xsk_tx_metadata | padding | payload | + +-----------------+---------+----------------------------+ + ^ + | + xdp_desc->addr + +An AF_XDP application can request headrooms larger than ``sizeof(struct +xsk_tx_metadata)``. The kernel will ignore the padding (and will still +use ``xdp_desc->addr - tx_metadata_len`` to locate +the ``xsk_tx_metadata``). For the frames that shouldn't carry +any metadata (i.e., the ones that don't have ``XDP_TX_METADATA`` option), +the metadata area is ignored by the kernel as well. + +The flags field enables the particular offload: + +- ``XDP_TXMD_FLAGS_TIMESTAMP``: requests the device to put transmission + timestamp into ``tx_timestamp`` field of ``union xsk_tx_metadata``. +- ``XDP_TXMD_FLAGS_CHECKSUM``: requests the device to calculate L4 + checksum. ``csum_start`` specifies byte offset of where the checksumming + should start and ``csum_offset`` specifies byte offset where the + device should store the computed checksum. + +Besides the flags above, in order to trigger the offloads, the first +packet's ``struct xdp_desc`` descriptor should set ``XDP_TX_METADATA`` +bit in the ``options`` field. Also note that in a multi-buffer packet +only the first chunk should carry the metadata. + +Software TX Checksum +==================== + +For development and testing purposes its possible to pass +``XDP_UMEM_TX_SW_CSUM`` flag to ``XDP_UMEM_REG`` UMEM registration call. +In this case, when running in ``XDK_COPY`` mode, the TX checksum +is calculated on the CPU. Do not enable this option in production because +it will negatively affect performance. + +Querying Device Capabilities +============================ + +Every devices exports its offloads capabilities via netlink netdev family. +Refer to ``xsk-flags`` features bitmask in +``Documentation/netlink/specs/netdev.yaml``. + +- ``tx-timestamp``: device supports ``XDP_TXMD_FLAGS_TIMESTAMP`` +- ``tx-checksum``: device supports ``XDP_TXMD_FLAGS_CHECKSUM`` + +See ``tools/net/ynl/samples/netdev.c`` on how to query this information. + +Example +======= + +See ``tools/testing/selftests/bpf/xdp_hw_metadata.c`` for an example +program that handles TX metadata. Also see https://github.com/fomichev/xskgen +for a more bare-bones example. diff --git a/Documentation/power/freezing-of-tasks.rst b/Documentation/power/freezing-of-tasks.rst index 53b6a56c46354f..df9755bfbd9448 100644 --- a/Documentation/power/freezing-of-tasks.rst +++ b/Documentation/power/freezing-of-tasks.rst @@ -14,27 +14,28 @@ architectures). II. How does it work? ===================== -There are three per-task flags used for that, PF_NOFREEZE, PF_FROZEN -and PF_FREEZER_SKIP (the last one is auxiliary). The tasks that have -PF_NOFREEZE unset (all user space processes and some kernel threads) are -regarded as 'freezable' and treated in a special way before the system enters a -suspend state as well as before a hibernation image is created (in what follows -we only consider hibernation, but the description also applies to suspend). +There is one per-task flag (PF_NOFREEZE) and three per-task states +(TASK_FROZEN, TASK_FREEZABLE and __TASK_FREEZABLE_UNSAFE) used for that. +The tasks that have PF_NOFREEZE unset (all user space tasks and some kernel +threads) are regarded as 'freezable' and treated in a special way before the +system enters a sleep state as well as before a hibernation image is created +(hibernation is directly covered by what follows, but the description applies +to system-wide suspend too). Namely, as the first step of the hibernation procedure the function freeze_processes() (defined in kernel/power/process.c) is called. A system-wide -variable system_freezing_cnt (as opposed to a per-task flag) is used to indicate -whether the system is to undergo a freezing operation. And freeze_processes() -sets this variable. After this, it executes try_to_freeze_tasks() that sends a -fake signal to all user space processes, and wakes up all the kernel threads. -All freezable tasks must react to that by calling try_to_freeze(), which -results in a call to __refrigerator() (defined in kernel/freezer.c), which sets -the task's PF_FROZEN flag, changes its state to TASK_UNINTERRUPTIBLE and makes -it loop until PF_FROZEN is cleared for it. Then, we say that the task is -'frozen' and therefore the set of functions handling this mechanism is referred -to as 'the freezer' (these functions are defined in kernel/power/process.c, -kernel/freezer.c & include/linux/freezer.h). User space processes are generally -frozen before kernel threads. +static key freezer_active (as opposed to a per-task flag or state) is used to +indicate whether the system is to undergo a freezing operation. And +freeze_processes() sets this static key. After this, it executes +try_to_freeze_tasks() that sends a fake signal to all user space processes, and +wakes up all the kernel threads. All freezable tasks must react to that by +calling try_to_freeze(), which results in a call to __refrigerator() (defined +in kernel/freezer.c), which changes the task's state to TASK_FROZEN, and makes +it loop until it is woken by an explicit TASK_FROZEN wakeup. Then, that task +is regarded as 'frozen' and so the set of functions handling this mechanism is +referred to as 'the freezer' (these functions are defined in +kernel/power/process.c, kernel/freezer.c & include/linux/freezer.h). User space +tasks are generally frozen before kernel threads. __refrigerator() must not be called directly. Instead, use the try_to_freeze() function (defined in include/linux/freezer.h), that checks @@ -43,31 +44,40 @@ if the task is to be frozen and makes the task enter __refrigerator(). For user space processes try_to_freeze() is called automatically from the signal-handling code, but the freezable kernel threads need to call it explicitly in suitable places or use the wait_event_freezable() or -wait_event_freezable_timeout() macros (defined in include/linux/freezer.h) -that combine interruptible sleep with checking if the task is to be frozen and -calling try_to_freeze(). The main loop of a freezable kernel thread may look +wait_event_freezable_timeout() macros (defined in include/linux/wait.h) +that put the task to sleep (TASK_INTERRUPTIBLE) or freeze it (TASK_FROZEN) if +freezer_active is set. The main loop of a freezable kernel thread may look like the following one:: set_freezable(); - do { - hub_events(); - wait_event_freezable(khubd_wait, - !list_empty(&hub_event_list) || - kthread_should_stop()); - } while (!kthread_should_stop() || !list_empty(&hub_event_list)); - -(from drivers/usb/core/hub.c::hub_thread()). - -If a freezable kernel thread fails to call try_to_freeze() after the freezer has -initiated a freezing operation, the freezing of tasks will fail and the entire -hibernation operation will be cancelled. For this reason, freezable kernel -threads must call try_to_freeze() somewhere or use one of the + + while (true) { + struct task_struct *tsk = NULL; + + wait_event_freezable(oom_reaper_wait, oom_reaper_list != NULL); + spin_lock_irq(&oom_reaper_lock); + if (oom_reaper_list != NULL) { + tsk = oom_reaper_list; + oom_reaper_list = tsk->oom_reaper_list; + } + spin_unlock_irq(&oom_reaper_lock); + + if (tsk) + oom_reap_task(tsk); + } + +(from mm/oom_kill.c::oom_reaper()). + +If a freezable kernel thread is not put to the frozen state after the freezer +has initiated a freezing operation, the freezing of tasks will fail and the +entire system-wide transition will be cancelled. For this reason, freezable +kernel threads must call try_to_freeze() somewhere or use one of the wait_event_freezable() and wait_event_freezable_timeout() macros. After the system memory state has been restored from a hibernation image and devices have been reinitialized, the function thaw_processes() is called in -order to clear the PF_FROZEN flag for each frozen task. Then, the tasks that -have been frozen leave __refrigerator() and continue running. +order to wake up each frozen task. Then, the tasks that have been frozen leave +__refrigerator() and continue running. Rationale behind the functions dealing with freezing and thawing of tasks @@ -96,7 +106,8 @@ III. Which kernel threads are freezable? Kernel threads are not freezable by default. However, a kernel thread may clear PF_NOFREEZE for itself by calling set_freezable() (the resetting of PF_NOFREEZE directly is not allowed). From this point it is regarded as freezable -and must call try_to_freeze() in a suitable place. +and must call try_to_freeze() or variants of wait_event_freezable() in a +suitable place. IV. Why do we do that? ====================== diff --git a/Documentation/process/4.Coding.rst b/Documentation/process/4.Coding.rst index 1f0d81f44e14b2..c2046dec0c2f40 100644 --- a/Documentation/process/4.Coding.rst +++ b/Documentation/process/4.Coding.rst @@ -66,6 +66,10 @@ for aligning variables/macros, for reflowing text and other similar tasks. See the file :ref:`Documentation/process/clang-format.rst ` for more details. +Some basic editor settings, such as indentation and line endings, will be +set automatically if you are using an editor that is compatible with +EditorConfig. See the official EditorConfig website for more information: +https://editorconfig.org/ Abstraction layers ****************** diff --git a/Documentation/process/changes.rst b/Documentation/process/changes.rst index bb96ca0f774b9a..50b3d1cb11159b 100644 --- a/Documentation/process/changes.rst +++ b/Documentation/process/changes.rst @@ -31,7 +31,7 @@ you probably needn't concern yourself with pcmciautils. ====================== =============== ======================================== GNU C 5.1 gcc --version Clang/LLVM (optional) 11.0.0 clang --version -Rust (optional) 1.73.0 rustc --version +Rust (optional) 1.74.1 rustc --version bindgen (optional) 0.65.1 bindgen --version GNU make 3.82 make --version bash 4.2 bash --version @@ -39,7 +39,7 @@ binutils 2.25 ld -v flex 2.5.35 flex --version bison 2.0 bison --version pahole 1.16 pahole --version -util-linux 2.10o fdformat --version +util-linux 2.10o mount --version kmod 13 depmod -V e2fsprogs 1.41.4 e2fsck -V jfsutils 1.1.3 fsck.jfs -V @@ -58,7 +58,7 @@ mcelog 0.6 mcelog --version iptables 1.4.2 iptables -V openssl & libcrypto 1.0.0 openssl version bc 1.06.95 bc --version -Sphinx\ [#f1]_ 1.7 sphinx-build --version +Sphinx\ [#f1]_ 2.4.4 sphinx-build --version cpio any cpio --version GNU tar 1.28 tar --version gtags (optional) 6.6.5 gtags --version @@ -213,7 +213,7 @@ Util-linux New versions of util-linux provide ``fdisk`` support for larger disks, support new options to mount, recognize more supported partition -types, have a fdformat which works with 2.4 kernels, and similar goodies. +types, and similar goodies. You'll probably want to upgrade. Ksymoops diff --git a/Documentation/process/coding-style.rst b/Documentation/process/coding-style.rst index 6db37a46d3059e..c48382c6b47746 100644 --- a/Documentation/process/coding-style.rst +++ b/Documentation/process/coding-style.rst @@ -735,6 +735,10 @@ for aligning variables/macros, for reflowing text and other similar tasks. See the file :ref:`Documentation/process/clang-format.rst ` for more details. +Some basic editor settings, such as indentation and line endings, will be +set automatically if you are using an editor that is compatible with +EditorConfig. See the official EditorConfig website for more information: +https://editorconfig.org/ 10) Kconfig configuration files ------------------------------- diff --git a/Documentation/process/development-process.rst b/Documentation/process/development-process.rst index 61c627e41ba8c2..e34d7da58b7ffc 100644 --- a/Documentation/process/development-process.rst +++ b/Documentation/process/development-process.rst @@ -3,9 +3,17 @@ A guide to the Kernel Development Process ========================================= -Contents: +The purpose of this document is to help developers (and their managers) +work with the development community with a minimum of frustration. It is +an attempt to document how this community works in a way which is +accessible to those who are not intimately familiar with Linux kernel +development (or, indeed, free software development in general). While +there is some technical material here, this is very much a process-oriented +discussion which does not require a deep knowledge of kernel programming to +understand. .. toctree:: + :caption: Contents :numbered: :maxdepth: 2 @@ -17,12 +25,3 @@ Contents: 6.Followthrough 7.AdvancedTopics 8.Conclusion - -The purpose of this document is to help developers (and their managers) -work with the development community with a minimum of frustration. It is -an attempt to document how this community works in a way which is -accessible to those who are not intimately familiar with Linux kernel -development (or, indeed, free software development in general). While -there is some technical material here, this is very much a process-oriented -discussion which does not require a deep knowledge of kernel programming to -understand. diff --git a/Documentation/process/howto.rst b/Documentation/process/howto.rst index deb8235e20ff1d..6c73889c98fc3d 100644 --- a/Documentation/process/howto.rst +++ b/Documentation/process/howto.rst @@ -82,8 +82,7 @@ documentation files are also added which explain how to use the feature. When a kernel change causes the interface that the kernel exposes to userspace to change, it is recommended that you send the information or a patch to the manual pages explaining the change to the manual pages -maintainer at mtk.manpages@gmail.com, and CC the list -linux-api@vger.kernel.org. +maintainer at alx@kernel.org, and CC the list linux-api@vger.kernel.org. Here is a list of files that are in the kernel source tree that are required reading: diff --git a/Documentation/process/index.rst b/Documentation/process/index.rst index a1daa309b58d07..6cb732dfcc7224 100644 --- a/Documentation/process/index.rst +++ b/Documentation/process/index.rst @@ -15,49 +15,96 @@ to learn about how our community works. Reading these documents will make it much easier for you to get your changes merged with a minimum of trouble. -Below are the essential guides that every developer should read. +An introduction to how kernel development works +----------------------------------------------- + +Read these documents first: an understanding of the material here will ease +your entry into the kernel community. .. toctree:: :maxdepth: 1 - license-rules howto - code-of-conduct - code-of-conduct-interpretation development-process submitting-patches - handling-regressions + submit-checklist + +Tools and technical guides for kernel developers +------------------------------------------------ + +This is a collection of material that kernel developers should be familiar +with. + +.. toctree:: + :maxdepth: 1 + + changes programming-language coding-style - maintainer-handbooks maintainer-pgp-guide email-clients + applying-patches + backporting + adding-syscalls + volatile-considered-harmful + botching-up-ioctls + +Policy guides and developer statements +-------------------------------------- + +These are the rules that we try to live by in the kernel community (and +beyond). + +.. toctree:: + :maxdepth: 1 + + license-rules + code-of-conduct + code-of-conduct-interpretation + contribution-maturity-model kernel-enforcement-statement kernel-driver-statement + stable-api-nonsense + stable-kernel-rules + management-style + researcher-guidelines -For security issues, see: +Dealing with bugs +----------------- + +Bugs are a fact of life; it is important that we handle them properly. +The documents below describe our policies around the handling of a couple +of special classes of bugs: regressions and security problems. .. toctree:: :maxdepth: 1 + handling-regressions security-bugs embargoed-hardware-issues -Other guides to the community that are of interest to most developers are: +Maintainer information +---------------------- + +How to find the people who will accept your patches. + +.. toctree:: + :maxdepth: 1 + + maintainer-handbooks + maintainers + +Other material +-------------- + +Here are some other guides to the community that are of interest to most +developers: .. toctree:: :maxdepth: 1 - changes - stable-api-nonsense - management-style - stable-kernel-rules - submit-checklist kernel-docs deprecated - maintainers - researcher-guidelines - contribution-maturity-model These are some overall technical guides that have been put here for now for lack of a better place. @@ -65,12 +112,7 @@ lack of a better place. .. toctree:: :maxdepth: 1 - applying-patches - backporting - adding-syscalls magic-number - volatile-considered-harmful - botching-up-ioctls clang-format ../arch/riscv/patch-acceptance ../core-api/unaligned-memory-access diff --git a/Documentation/process/submitting-patches.rst b/Documentation/process/submitting-patches.rst index 86d346bcb8ef0f..66029999b58758 100644 --- a/Documentation/process/submitting-patches.rst +++ b/Documentation/process/submitting-patches.rst @@ -790,10 +790,14 @@ Providing base tree information ------------------------------- When other developers receive your patches and start the review process, -it is often useful for them to know where in the tree history they -should place your work. This is particularly useful for automated CI -processes that attempt to run a series of tests in order to establish -the quality of your submission before the maintainer starts the review. +it is absolutely necessary for them to know what is the base +commit/branch your work applies on, considering the sheer amount of +maintainer trees present nowadays. Note again the **T:** entry in the +MAINTAINERS file explained above. + +This is even more important for automated CI processes that attempt to +run a series of tests in order to establish the quality of your +submission before the maintainer starts the review. If you are using ``git format-patch`` to generate your patches, you can automatically include the base tree information in your submission by @@ -836,6 +840,9 @@ letter or in the first patch of the series and it should be placed either below the ``---`` line or at the very bottom of all other content, right before your email signature. +Make sure that base commit is in an official maintainer/mainline tree +and not in some internal, accessible only to you tree - otherwise it +would be worthless. References ---------- diff --git a/Documentation/rust/arch-support.rst b/Documentation/rust/arch-support.rst index b91e9ef4d0c21e..73203ba1e9011e 100644 --- a/Documentation/rust/arch-support.rst +++ b/Documentation/rust/arch-support.rst @@ -12,10 +12,11 @@ which uses ``libclang``. Below is a general summary of architectures that currently work. Level of support corresponds to ``S`` values in the ``MAINTAINERS`` file. -============ ================ ============================================== -Architecture Level of support Constraints -============ ================ ============================================== -``um`` Maintained ``x86_64`` only. -``x86`` Maintained ``x86_64`` only. -============ ================ ============================================== +============= ================ ============================================== +Architecture Level of support Constraints +============= ================ ============================================== +``loongarch`` Maintained - +``um`` Maintained ``x86_64`` only. +``x86`` Maintained ``x86_64`` only. +============= ================ ============================================== diff --git a/Documentation/rust/coding-guidelines.rst b/Documentation/rust/coding-guidelines.rst index aa8ed082613e12..05542840b16cca 100644 --- a/Documentation/rust/coding-guidelines.rst +++ b/Documentation/rust/coding-guidelines.rst @@ -177,6 +177,19 @@ please take a look at the ``rustdoc`` book at: https://doc.rust-lang.org/rustdoc/how-to-write-documentation.html +In addition, the kernel supports creating links relative to the source tree by +prefixing the link destination with ``srctree/``. For instance: + +.. code-block:: rust + + //! C header: [`include/linux/printk.h`](srctree/include/linux/printk.h) + +or: + +.. code-block:: rust + + /// [`struct mutex`]: srctree/include/linux/mutex.h + Naming ------ diff --git a/Documentation/rust/general-information.rst b/Documentation/rust/general-information.rst index 081397827a7eab..236c6dd3c647f8 100644 --- a/Documentation/rust/general-information.rst +++ b/Documentation/rust/general-information.rst @@ -77,3 +77,27 @@ configuration: #[cfg(CONFIG_X="y")] // Enabled as a built-in (`y`) #[cfg(CONFIG_X="m")] // Enabled as a module (`m`) #[cfg(not(CONFIG_X))] // Disabled + + +Testing +------- + +There are the tests that come from the examples in the Rust documentation +and get transformed into KUnit tests. These can be run via KUnit. For example +via ``kunit_tool`` (``kunit.py``) on the command line:: + + ./tools/testing/kunit/kunit.py run --make_options LLVM=1 --arch x86_64 --kconfig_add CONFIG_RUST=y + +Alternatively, KUnit can run them as kernel built-in at boot. Refer to +Documentation/dev-tools/kunit/index.rst for the general KUnit documentation +and Documentation/dev-tools/kunit/architecture.rst for the details of kernel +built-in vs. command line testing. + +Additionally, there are the ``#[test]`` tests. These can be run using +the ``rusttest`` Make target:: + + make LLVM=1 rusttest + +This requires the kernel ``.config`` and downloads external repositories. +It runs the ``#[test]`` tests on the host (currently) and thus is fairly +limited in what these tests can test. diff --git a/Documentation/rust/quick-start.rst b/Documentation/rust/quick-start.rst index f382914f41917a..cc3f11e0d441f8 100644 --- a/Documentation/rust/quick-start.rst +++ b/Documentation/rust/quick-start.rst @@ -33,14 +33,18 @@ A particular version of the Rust compiler is required. Newer versions may or may not work because, for the moment, the kernel depends on some unstable Rust features. -If ``rustup`` is being used, enter the checked out source code directory -and run:: +If ``rustup`` is being used, enter the kernel build directory (or use +``--path=`` argument to the ``set`` sub-command) and run:: rustup override set $(scripts/min-tool-version.sh rustc) This will configure your working directory to use the correct version of -``rustc`` without affecting your default toolchain. If you are not using -``rustup``, fetch a standalone installer from: +``rustc`` without affecting your default toolchain. + +Note that the override applies to the current working directory (and its +sub-directories). + +If you are not using ``rustup``, fetch a standalone installer from: https://forge.rust-lang.org/infra/other-installation-methods.html#standalone @@ -76,7 +80,7 @@ libclang ``libclang`` (part of LLVM) is used by ``bindgen`` to understand the C code in the kernel, which means LLVM needs to be installed; like when the kernel -is compiled with ``CC=clang`` or ``LLVM=1``. +is compiled with ``LLVM=1``. Linux distributions are likely to have a suitable one available, so it is best to check that first. @@ -229,10 +233,6 @@ at the moment. That is:: make LLVM=1 -For architectures that do not support a full LLVM toolchain, use:: - - make CC=clang - Using GCC also works for some configurations, but it is very experimental at the moment. diff --git a/Documentation/scheduler/sched-design-CFS.rst b/Documentation/scheduler/sched-design-CFS.rst index f68919800f0507..6cffffe265006e 100644 --- a/Documentation/scheduler/sched-design-CFS.rst +++ b/Documentation/scheduler/sched-design-CFS.rst @@ -180,7 +180,7 @@ This is the (partial) list of the hooks: compat_yield sysctl is turned on; in that case, it places the scheduling entity at the right-most end of the red-black tree. - - check_preempt_curr(...) + - wakeup_preempt(...) This function checks if a task that entered the runnable state should preempt the currently running task. @@ -189,10 +189,10 @@ This is the (partial) list of the hooks: This function chooses the most appropriate task eligible to run next. - - set_curr_task(...) + - set_next_task(...) - This function is called when a task changes its scheduling class or changes - its task group. + This function is called when a task changes its scheduling class, changes + its task group or is scheduled. - task_tick(...) diff --git a/Documentation/scheduler/schedutil.rst b/Documentation/scheduler/schedutil.rst index 32c7d69fc86c1f..803fba8fc71429 100644 --- a/Documentation/scheduler/schedutil.rst +++ b/Documentation/scheduler/schedutil.rst @@ -90,8 +90,8 @@ For more detail see: - Documentation/scheduler/sched-capacity.rst:"1. CPU Capacity + 2. Task utilization" -UTIL_EST / UTIL_EST_FASTUP -========================== +UTIL_EST +======== Because periodic tasks have their averages decayed while they sleep, even though when running their expected utilization will be the same, they suffer a @@ -99,8 +99,7 @@ though when running their expected utilization will be the same, they suffer a To alleviate this (a default enabled option) UTIL_EST drives an Infinite Impulse Response (IIR) EWMA with the 'running' value on dequeue -- when it is -highest. A further default enabled option UTIL_EST_FASTUP modifies the IIR -filter to instantly increase and only decay on decrease. +highest. UTIL_EST filters to instantly increase and only decay on decrease. A further runqueue wide sum (of runnable tasks) is maintained of: diff --git a/Documentation/security/keys/trusted-encrypted.rst b/Documentation/security/keys/trusted-encrypted.rst index 9bc9db8ec6517c..e989b9802f92ab 100644 --- a/Documentation/security/keys/trusted-encrypted.rst +++ b/Documentation/security/keys/trusted-encrypted.rst @@ -88,7 +88,7 @@ safe. (2) TEE TEEs have well-documented, standardized client interface and APIs. For - more details refer to ``Documentation/staging/tee.rst``. + more details refer to ``Documentation/driver-api/tee.rst``. (3) CAAM diff --git a/Documentation/sound/soc/dapm.rst b/Documentation/sound/soc/dapm.rst index 8e44107933abf5..c3154ce6e1b273 100644 --- a/Documentation/sound/soc/dapm.rst +++ b/Documentation/sound/soc/dapm.rst @@ -234,7 +234,7 @@ corresponding soft power control. In this case it is necessary to create a virtual widget - a widget with no control bits e.g. :: - SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_DAPM_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), This can be used to merge to signal paths together in software. diff --git a/Documentation/sphinx-static/custom.css b/Documentation/sphinx-static/custom.css index 084a884f6fb75e..f4285417c71aa9 100644 --- a/Documentation/sphinx-static/custom.css +++ b/Documentation/sphinx-static/custom.css @@ -7,6 +7,10 @@ div.body h1 { font-size: 180%; } div.body h2 { font-size: 150%; } div.body h3 { font-size: 130%; } +div.body h4 { font-size: 110%; } + +/* toctree captions are styled like h2 */ +div.toctree-wrapper p.caption[role=heading] { font-size: 150%; } /* Tighten up the layout slightly */ div.body { padding: 0 15px 0 10px; } @@ -20,6 +24,12 @@ div.document { width: auto; } +/* Size the logo appropriately */ +img.logo { + width: 104px; + margin-bottom: 20px; +} + /* * Parameters for the display of function prototypes and such included * from C source files. @@ -73,3 +83,56 @@ input.kernel-toc-toggle { display: none; } h3.kernel-toc-contents { display: inline; } div.kerneltoc a { color: black; } } + +/* Language selection menu */ + +div.admonition { + /* + * Make sure we don't overlap notes and warnings at the top of the + * document. + */ + clear: both; +} + +div.language-selection { + background: #eeeeee; + border: 1px solid #cccccc; + margin-bottom: 1em; + padding: .5em; + + position: relative; + float: right; +} + +div.language-selection a { + display: block; + padding: 0.5em; + color: #333333; + text-decoration: none; +} + +div.language-selection ul { + display: none; + position: absolute; + + /* Align with the parent div */ + top: 100%; + right: 0; + margin: 0; + + list-style: none; + + background: #fafafa; + border: 1px solid #cccccc; + + /* Never break menu item lines */ + white-space: nowrap; +} + +div.language-selection:hover ul { + display: block; +} + +div.language-selection ul li:hover { + background: #dddddd; +} diff --git a/Documentation/sphinx-static/theme_overrides.css b/Documentation/sphinx-static/theme_overrides.css index f6f2b941a5d61f..79000b26e64e55 100644 --- a/Documentation/sphinx-static/theme_overrides.css +++ b/Documentation/sphinx-static/theme_overrides.css @@ -81,11 +81,6 @@ div[class^="highlight"] pre { * - hide the permalink symbol as long as link is not hovered */ - .toc-title { - font-size: 150%; - font-weight: bold; - } - caption, .wy-table caption, .rst-content table.field-list caption { font-size: 100%; } diff --git a/Documentation/sphinx/automarkup.py b/Documentation/sphinx/automarkup.py index 06b34740bf90f1..a413f8dd511587 100644 --- a/Documentation/sphinx/automarkup.py +++ b/Documentation/sphinx/automarkup.py @@ -7,11 +7,7 @@ from docutils import nodes import sphinx from sphinx import addnodes -if sphinx.version_info[0] < 2 or \ - sphinx.version_info[0] == 2 and sphinx.version_info[1] < 1: - from sphinx.environment import NoUri -else: - from sphinx.errors import NoUri +from sphinx.errors import NoUri import re from itertools import chain @@ -74,6 +70,12 @@ Skipfuncs = [ 'open', 'close', 'read', 'write', 'fcntl', 'mmap', c_namespace = '' +# +# Detect references to commits. +# +RE_git = re.compile(r'commit\s+(?P[0-9a-f]{12,40})(?:\s+\(".*?"\))?', + flags=re.IGNORECASE | re.DOTALL) + def markup_refs(docname, app, node): t = node.astext() done = 0 @@ -90,7 +92,8 @@ def markup_refs(docname, app, node): RE_struct: markup_c_ref, RE_union: markup_c_ref, RE_enum: markup_c_ref, - RE_typedef: markup_c_ref} + RE_typedef: markup_c_ref, + RE_git: markup_git} if sphinx.version_info[0] >= 3: markup_func = markup_func_sphinx3 @@ -276,6 +279,17 @@ def get_c_namespace(app, docname): return match.group(1) return '' +def markup_git(docname, app, match): + # While we could probably assume that we are running in a git + # repository, we can't know for sure, so let's just mechanically + # turn them into git.kernel.org links without checking their + # validity. (Maybe we can do something in the future to warn about + # these references if this is explicitly requested.) + text = match.group(0) + rev = match.group('rev') + return nodes.reference('', nodes.Text(text), + refuri=f'https://git.kernel.org/torvalds/c/{rev}') + def auto_markup(app, doctree, name): global c_namespace c_namespace = get_c_namespace(app, name) diff --git a/Documentation/sphinx/cdomain.py b/Documentation/sphinx/cdomain.py index 4eb150bf509ca8..e6959af25402dd 100644 --- a/Documentation/sphinx/cdomain.py +++ b/Documentation/sphinx/cdomain.py @@ -127,11 +127,7 @@ def setup(app): # Handle easy Sphinx 3.1+ simple new tags: :c:expr and .. c:namespace:: app.connect('source-read', c_markups) - - if (major == 1 and minor < 8): - app.override_domain(CDomain) - else: - app.add_domain(CDomain, override=True) + app.add_domain(CDomain, override=True) return dict( version = __version__, diff --git a/Documentation/sphinx/kernel_abi.py b/Documentation/sphinx/kernel_abi.py index 49797c55479c44..5911bd0d796571 100644 --- a/Documentation/sphinx/kernel_abi.py +++ b/Documentation/sphinx/kernel_abi.py @@ -39,8 +39,6 @@ import sys import re import kernellog -from os import path - from docutils import nodes, statemachine from docutils.statemachine import ViewList from docutils.parsers.rst import directives, Directive @@ -73,60 +71,26 @@ class KernelCmd(Directive): } def run(self): - doc = self.state.document if not doc.settings.file_insertion_enabled: raise self.warning("docutils: file insertion disabled") - env = doc.settings.env - cwd = path.dirname(doc.current_source) - cmd = "get_abi.pl rest --enable-lineno --dir " - cmd += self.arguments[0] - - if 'rst' in self.options: - cmd += " --rst-source" + srctree = os.path.abspath(os.environ["srctree"]) - srctree = path.abspath(os.environ["srctree"]) + args = [ + os.path.join(srctree, 'scripts/get_abi.pl'), + 'rest', + '--enable-lineno', + '--dir', os.path.join(srctree, 'Documentation', self.arguments[0]), + ] - fname = cmd - - # extend PATH with $(srctree)/scripts - path_env = os.pathsep.join([ - srctree + os.sep + "scripts", - os.environ["PATH"] - ]) - shell_env = os.environ.copy() - shell_env["PATH"] = path_env - shell_env["srctree"] = srctree + if 'rst' in self.options: + args.append('--rst-source') - lines = self.runCmd(cmd, shell=True, cwd=cwd, env=shell_env) + lines = subprocess.check_output(args, cwd=os.path.dirname(doc.current_source)).decode('utf-8') nodeList = self.nestedParse(lines, self.arguments[0]) return nodeList - def runCmd(self, cmd, **kwargs): - u"""Run command ``cmd`` and return its stdout as unicode.""" - - try: - proc = subprocess.Popen( - cmd - , stdout = subprocess.PIPE - , stderr = subprocess.PIPE - , **kwargs - ) - out, err = proc.communicate() - - out, err = codecs.decode(out, 'utf-8'), codecs.decode(err, 'utf-8') - - if proc.returncode != 0: - raise self.severe( - u"command '%s' failed with return code %d" - % (cmd, proc.returncode) - ) - except OSError as exc: - raise self.severe(u"problems with '%s' directive: %s." - % (self.name, ErrorString(exc))) - return out - def nestedParse(self, lines, fname): env = self.state.document.settings.env content = ViewList() diff --git a/Documentation/sphinx/kernel_feat.py b/Documentation/sphinx/kernel_feat.py index b5fa2f0542a5d9..b9df61eb450138 100644 --- a/Documentation/sphinx/kernel_feat.py +++ b/Documentation/sphinx/kernel_feat.py @@ -37,8 +37,6 @@ import re import subprocess import sys -from os import path - from docutils import nodes, statemachine from docutils.statemachine import ViewList from docutils.parsers.rst import directives, Directive @@ -76,33 +74,26 @@ class KernelFeat(Directive): self.state.document.settings.env.app.warn(message, prefix="") def run(self): - doc = self.state.document if not doc.settings.file_insertion_enabled: raise self.warning("docutils: file insertion disabled") env = doc.settings.env - cwd = path.dirname(doc.current_source) - cmd = "get_feat.pl rest --enable-fname --dir " - cmd += self.arguments[0] - - if len(self.arguments) > 1: - cmd += " --arch " + self.arguments[1] - srctree = path.abspath(os.environ["srctree"]) + srctree = os.path.abspath(os.environ["srctree"]) - fname = cmd + args = [ + os.path.join(srctree, 'scripts/get_feat.pl'), + 'rest', + '--enable-fname', + '--dir', + os.path.join(srctree, 'Documentation', self.arguments[0]), + ] - # extend PATH with $(srctree)/scripts - path_env = os.pathsep.join([ - srctree + os.sep + "scripts", - os.environ["PATH"] - ]) - shell_env = os.environ.copy() - shell_env["PATH"] = path_env - shell_env["srctree"] = srctree + if len(self.arguments) > 1: + args.extend(['--arch', self.arguments[1]]) - lines = self.runCmd(cmd, shell=True, cwd=cwd, env=shell_env) + lines = subprocess.check_output(args, cwd=os.path.dirname(doc.current_source)).decode('utf-8') line_regex = re.compile(r"^\.\. FILE (\S+)$") @@ -121,30 +112,6 @@ class KernelFeat(Directive): nodeList = self.nestedParse(out_lines, fname) return nodeList - def runCmd(self, cmd, **kwargs): - u"""Run command ``cmd`` and return its stdout as unicode.""" - - try: - proc = subprocess.Popen( - cmd - , stdout = subprocess.PIPE - , stderr = subprocess.PIPE - , **kwargs - ) - out, err = proc.communicate() - - out, err = codecs.decode(out, 'utf-8'), codecs.decode(err, 'utf-8') - - if proc.returncode != 0: - raise self.severe( - u"command '%s' failed with return code %d" - % (cmd, proc.returncode) - ) - except OSError as exc: - raise self.severe(u"problems with '%s' directive: %s." - % (self.name, ErrorString(exc))) - return out - def nestedParse(self, lines, fname): content = ViewList() node = nodes.section() diff --git a/Documentation/sphinx/kfigure.py b/Documentation/sphinx/kfigure.py index 13e885bbd499c6..97166333b72703 100644 --- a/Documentation/sphinx/kfigure.py +++ b/Documentation/sphinx/kfigure.py @@ -61,13 +61,7 @@ import sphinx from sphinx.util.nodes import clean_astext import kernellog -# Get Sphinx version -major, minor, patch = sphinx.version_info[:3] -if major == 1 and minor > 3: - # patches.Figure only landed in Sphinx 1.4 - from sphinx.directives.patches import Figure # pylint: disable=C0413 -else: - Figure = images.Figure +Figure = images.Figure __version__ = '1.0.0' diff --git a/Documentation/sphinx/requirements.txt b/Documentation/sphinx/requirements.txt index 335b53df35e22f..5d47ed44394985 100644 --- a/Documentation/sphinx/requirements.txt +++ b/Documentation/sphinx/requirements.txt @@ -1,3 +1,6 @@ # jinja2>=3.1 is not compatible with Sphinx<4.0 jinja2<3.1 +# alabaster>=0.7.14 is not compatible with Sphinx<=3.3 +alabaster<0.7.14 Sphinx==2.4.4 +pyyaml diff --git a/Documentation/sphinx/templates/kernel-toc.html b/Documentation/sphinx/templates/kernel-toc.html index b58efa99df527d..41f1efbe64bb28 100644 --- a/Documentation/sphinx/templates/kernel-toc.html +++ b/Documentation/sphinx/templates/kernel-toc.html @@ -12,5 +12,7 @@ diff --git a/Documentation/sphinx/templates/translations.html b/Documentation/sphinx/templates/translations.html new file mode 100644 index 00000000000000..8df5d42d8dcd88 --- /dev/null +++ b/Documentation/sphinx/templates/translations.html @@ -0,0 +1,15 @@ + + + +{# Create a language menu for translations #} +{% if languages|length > 0: %} +
+{{ current_language }} + + +
+{% endif %} diff --git a/Documentation/sphinx/translations.py b/Documentation/sphinx/translations.py new file mode 100644 index 00000000000000..47161e6eba9976 --- /dev/null +++ b/Documentation/sphinx/translations.py @@ -0,0 +1,101 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright © 2023, Oracle and/or its affiliates. +# Author: Vegard Nossum +# +# Add translation links to the top of the document. +# + +import os + +from docutils import nodes +from docutils.transforms import Transform + +import sphinx +from sphinx import addnodes +from sphinx.errors import NoUri + +all_languages = { + # English is always first + None: 'English', + + # Keep the rest sorted alphabetically + 'zh_CN': 'Chinese (Simplified)', + 'zh_TW': 'Chinese (Traditional)', + 'it_IT': 'Italian', + 'ja_JP': 'Japanese', + 'ko_KR': 'Korean', + 'sp_SP': 'Spanish', +} + +class LanguagesNode(nodes.Element): + def __init__(self, current_language, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.current_language = current_language + +class TranslationsTransform(Transform): + default_priority = 900 + + def apply(self): + app = self.document.settings.env.app + docname = self.document.settings.env.docname + + this_lang_code = None + components = docname.split(os.sep) + if components[0] == 'translations' and len(components) > 2: + this_lang_code = components[1] + + # normalize docname to be the untranslated one + docname = os.path.join(*components[2:]) + + new_nodes = LanguagesNode(all_languages[this_lang_code]) + + for lang_code, lang_name in all_languages.items(): + if lang_code == this_lang_code: + continue + + if lang_code is None: + target_name = docname + else: + target_name = os.path.join('translations', lang_code, docname) + + pxref = addnodes.pending_xref('', refdomain='std', + reftype='doc', reftarget='/' + target_name, modname=None, + classname=None, refexplicit=True) + pxref += nodes.Text(lang_name) + new_nodes += pxref + + self.document.insert(0, new_nodes) + +def process_languages(app, doctree, docname): + for node in doctree.traverse(LanguagesNode): + if app.builder.format not in ['html']: + node.parent.remove(node) + continue + + languages = [] + + # Iterate over the child nodes; any resolved links will have + # the type 'nodes.reference', while unresolved links will be + # type 'nodes.Text'. + languages = list(filter(lambda xref: + isinstance(xref, nodes.reference), node.children)) + + html_content = app.builder.templates.render('translations.html', + context={ + 'current_language': node.current_language, + 'languages': languages, + }) + + node.replace_self(nodes.raw('', html_content, format='html')) + +def setup(app): + app.add_node(LanguagesNode) + app.add_transform(TranslationsTransform) + app.connect('doctree-resolved', process_languages) + + return { + 'parallel_read_safe': True, + 'parallel_write_safe': True, + } diff --git a/Documentation/spi/pxa2xx.rst b/Documentation/spi/pxa2xx.rst index 04f2a3856c406f..19479b801826cf 100644 --- a/Documentation/spi/pxa2xx.rst +++ b/Documentation/spi/pxa2xx.rst @@ -3,13 +3,13 @@ PXA2xx SPI on SSP driver HOWTO ============================== This a mini HOWTO on the pxa2xx_spi driver. The driver turns a PXA2xx -synchronous serial port into an SPI master controller +synchronous serial port into an SPI host controller (see Documentation/spi/spi-summary.rst). The driver has the following features - Support for any PXA2xx and compatible SSP. - SSP PIO and SSP DMA data transfers. - External and Internal (SSPFRM) chip selects. -- Per slave device (chip) configuration. +- Per peripheral device (chip) configuration. - Full suspend, freeze, resume support. The driver is built around a &struct spi_message FIFO serviced by kernel @@ -17,10 +17,10 @@ thread. The kernel thread, spi_pump_messages(), drives message FIFO and is responsible for queuing SPI transactions and setting up and launching the DMA or interrupt driven transfers. -Declaring PXA2xx Master Controllers ------------------------------------ -Typically, for a legacy platform, an SPI master is defined in the -arch/.../mach-*/board-*.c as a "platform device". The master configuration +Declaring PXA2xx host controllers +--------------------------------- +Typically, for a legacy platform, an SPI host controller is defined in the +arch/.../mach-*/board-*.c as a "platform device". The host controller configuration is passed to the driver via a table found in include/linux/spi/pxa2xx_spi.h:: struct pxa2xx_spi_controller { @@ -30,7 +30,7 @@ is passed to the driver via a table found in include/linux/spi/pxa2xx_spi.h:: }; The "pxa2xx_spi_controller.num_chipselect" field is used to determine the number of -slave device (chips) attached to this SPI master. +peripheral devices (chips) attached to this SPI host controller. The "pxa2xx_spi_controller.enable_dma" field informs the driver that SSP DMA should be used. This caused the driver to acquire two DMA channels: Rx channel and @@ -40,8 +40,8 @@ See the "PXA2xx Developer Manual" section "DMA Controller". For the new platforms the description of the controller and peripheral devices comes from Device Tree or ACPI. -NSSP MASTER SAMPLE ------------------- +NSSP HOST SAMPLE +---------------- Below is a sample configuration using the PXA255 NSSP for a legacy platform:: static struct resource pxa_spi_nssp_resources[] = { @@ -57,7 +57,7 @@ Below is a sample configuration using the PXA255 NSSP for a legacy platform:: }, }; - static struct pxa2xx_spi_controller pxa_nssp_master_info = { + static struct pxa2xx_spi_controller pxa_nssp_controller_info = { .num_chipselect = 1, /* Matches the number of chips attached to NSSP */ .enable_dma = 1, /* Enables NSSP DMA */ }; @@ -68,7 +68,7 @@ Below is a sample configuration using the PXA255 NSSP for a legacy platform:: .resource = pxa_spi_nssp_resources, .num_resources = ARRAY_SIZE(pxa_spi_nssp_resources), .dev = { - .platform_data = &pxa_nssp_master_info, /* Passed to driver */ + .platform_data = &pxa_nssp_controller_info, /* Passed to driver */ }, }; @@ -81,17 +81,17 @@ Below is a sample configuration using the PXA255 NSSP for a legacy platform:: (void)platform_add_device(devices, ARRAY_SIZE(devices)); } -Declaring Slave Devices ------------------------ -Typically, for a legacy platform, each SPI slave (chip) is defined in the +Declaring peripheral devices +---------------------------- +Typically, for a legacy platform, each SPI peripheral device (chip) is defined in the arch/.../mach-*/board-*.c using the "spi_board_info" structure found in "linux/spi/spi.h". See "Documentation/spi/spi-summary.rst" for additional information. -Each slave device attached to the PXA must provide slave specific configuration +Each peripheral device (chip) attached to the PXA2xx must provide specific chip configuration information via the structure "pxa2xx_spi_chip" found in -"include/linux/spi/pxa2xx_spi.h". The pxa2xx_spi master controller driver -will uses the configuration whenever the driver communicates with the slave +"include/linux/spi/pxa2xx_spi.h". The PXA2xx host controller driver will use +the configuration whenever the driver communicates with the peripheral device. All fields are optional. :: @@ -123,7 +123,7 @@ dma_burst_size == 0. The "pxa2xx_spi_chip.timeout" fields is used to efficiently handle trailing bytes in the SSP receiver FIFO. The correct value for this field is dependent on the SPI bus speed ("spi_board_info.max_speed_hz") and the specific -slave device. Please note that the PXA2xx SSP 1 does not support trailing byte +peripheral device. Please note that the PXA2xx SSP 1 does not support trailing byte timeouts and must busy-wait any trailing bytes. NOTE: the SPI driver cannot control the chip select if SSPFRM is used, so the @@ -132,8 +132,8 @@ asserted around the complete message. Use SSPFRM as a GPIO (through a descriptor to accommodate these chips. -NSSP SLAVE SAMPLE ------------------ +NSSP PERIPHERAL SAMPLE +---------------------- For a legacy platform or in some other cases, the pxa2xx_spi_chip structure is passed to the pxa2xx_spi driver in the "spi_board_info.controller_data" field. Below is a sample configuration using the PXA255 NSSP. @@ -161,16 +161,16 @@ field. Below is a sample configuration using the PXA255 NSSP. .bus_num = 2, /* Framework bus number */ .chip_select = 0, /* Framework chip select */ .platform_data = NULL; /* No spi_driver specific config */ - .controller_data = &cs8415a_chip_info, /* Master chip config */ - .irq = STREETRACER_APCI_IRQ, /* Slave device interrupt */ + .controller_data = &cs8415a_chip_info, /* Host controller config */ + .irq = STREETRACER_APCI_IRQ, /* Peripheral device interrupt */ }, { .modalias = "cs8405a", /* Name of spi_driver for this device */ .max_speed_hz = 3686400, /* Run SSP as fast a possible */ .bus_num = 2, /* Framework bus number */ .chip_select = 1, /* Framework chip select */ - .controller_data = &cs8405a_chip_info, /* Master chip config */ - .irq = STREETRACER_APCI_IRQ, /* Slave device interrupt */ + .controller_data = &cs8405a_chip_info, /* Host controller config */ + .irq = STREETRACER_APCI_IRQ, /* Peripheral device interrupt */ }, }; @@ -193,17 +193,14 @@ mode supports both coherent and stream based DMA mappings. The following logic is used to determine the type of I/O to be used on a per "spi_transfer" basis:: - if !enable_dma then - always use PIO transfers + if spi_message.len > 65536 then + if spi_message.is_dma_mapped or rx_dma_buf != 0 or tx_dma_buf != 0 then + reject premapped transfers - if spi_message.len > 8191 then print "rate limited" warning use PIO transfers - if spi_message.is_dma_mapped and rx_dma_buf != 0 and tx_dma_buf != 0 then - use coherent DMA mode - - if rx_buf and tx_buf are aligned on 8 byte boundary then + if enable_dma and the size is in the range [DMA burst size..65536] then use streaming DMA mode otherwise diff --git a/Documentation/staging/index.rst b/Documentation/staging/index.rst index ded8254bc0d750..71592f3ce89b76 100644 --- a/Documentation/staging/index.rst +++ b/Documentation/staging/index.rst @@ -12,5 +12,4 @@ Unsorted Documentation rpmsg speculation static-keys - tee xz diff --git a/Documentation/staging/rpmsg.rst b/Documentation/staging/rpmsg.rst index 1ce353cb232a3b..dba3e5f6561295 100644 --- a/Documentation/staging/rpmsg.rst +++ b/Documentation/staging/rpmsg.rst @@ -68,13 +68,14 @@ User API :: - int rpmsg_send(struct rpmsg_channel *rpdev, void *data, int len); + int rpmsg_send(struct rpmsg_endpoint *ept, void *data, int len); -sends a message across to the remote processor on a given channel. -The caller should specify the channel, the data it wants to send, +sends a message across to the remote processor from the given endpoint. +The caller should specify the endpoint, the data it wants to send, and its length (in bytes). The message will be sent on the specified -channel, i.e. its source and destination address fields will be -set to the channel's src and dst addresses. +endpoint's channel, i.e. its source and destination address fields will be +respectively set to the endpoint's src address and its parent channel +dst addresses. In case there are no TX buffers available, the function will block until one becomes available (i.e. until the remote processor consumes @@ -87,17 +88,18 @@ Returns 0 on success and an appropriate error value on failure. :: - int rpmsg_sendto(struct rpmsg_channel *rpdev, void *data, int len, u32 dst); + int rpmsg_sendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst); -sends a message across to the remote processor on a given channel, +sends a message across to the remote processor from a given endpoint, to a destination address provided by the caller. -The caller should specify the channel, the data it wants to send, +The caller should specify the endpoint, the data it wants to send, its length (in bytes), and an explicit destination address. The message will then be sent to the remote processor to which the -channel belongs, using the channel's src address, and the user-provided -dst address (thus the channel's dst address will be ignored). +endpoints's channel belongs, using the endpoints's src address, +and the user-provided dst address (thus the channel's dst address +will be ignored). In case there are no TX buffers available, the function will block until one becomes available (i.e. until the remote processor consumes @@ -110,18 +112,19 @@ Returns 0 on success and an appropriate error value on failure. :: - int rpmsg_send_offchannel(struct rpmsg_channel *rpdev, u32 src, u32 dst, + int rpmsg_send_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, void *data, int len); sends a message across to the remote processor, using the src and dst addresses provided by the user. -The caller should specify the channel, the data it wants to send, +The caller should specify the endpoint, the data it wants to send, its length (in bytes), and explicit source and destination addresses. The message will then be sent to the remote processor to which the -channel belongs, but the channel's src and dst addresses will be -ignored (and the user-provided addresses will be used instead). +endpoint's channel belongs, but the endpoint's src and channel dst +addresses will be ignored (and the user-provided addresses will +be used instead). In case there are no TX buffers available, the function will block until one becomes available (i.e. until the remote processor consumes @@ -134,13 +137,14 @@ Returns 0 on success and an appropriate error value on failure. :: - int rpmsg_trysend(struct rpmsg_channel *rpdev, void *data, int len); + int rpmsg_trysend(struct rpmsg_endpoint *ept, void *data, int len); -sends a message across to the remote processor on a given channel. -The caller should specify the channel, the data it wants to send, +sends a message across to the remote processor from a given endpoint. +The caller should specify the endpoint, the data it wants to send, and its length (in bytes). The message will be sent on the specified -channel, i.e. its source and destination address fields will be -set to the channel's src and dst addresses. +endpoint's channel, i.e. its source and destination address fields will be +respectively set to the endpoint's src address and its parent channel +dst addresses. In case there are no TX buffers available, the function will immediately return -ENOMEM without waiting until one becomes available. @@ -150,10 +154,10 @@ Returns 0 on success and an appropriate error value on failure. :: - int rpmsg_trysendto(struct rpmsg_channel *rpdev, void *data, int len, u32 dst) + int rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, int len, u32 dst) -sends a message across to the remote processor on a given channel, +sends a message across to the remote processor from a given endoint, to a destination address provided by the user. The user should specify the channel, the data it wants to send, @@ -171,7 +175,7 @@ Returns 0 on success and an appropriate error value on failure. :: - int rpmsg_trysend_offchannel(struct rpmsg_channel *rpdev, u32 src, u32 dst, + int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, void *data, int len); @@ -284,7 +288,7 @@ content to the console. dev_info(&rpdev->dev, "chnl: 0x%x -> 0x%x\n", rpdev->src, rpdev->dst); /* send a message on our channel */ - err = rpmsg_send(rpdev, "hello!", 6); + err = rpmsg_send(rpdev->ept, "hello!", 6); if (err) { pr_err("rpmsg_send failed: %d\n", err); return err; diff --git a/Documentation/staging/tee.rst b/Documentation/staging/tee.rst deleted file mode 100644 index 22baa077a3b908..00000000000000 --- a/Documentation/staging/tee.rst +++ /dev/null @@ -1,364 +0,0 @@ -============= -TEE subsystem -============= - -This document describes the TEE subsystem in Linux. - -A TEE (Trusted Execution Environment) is a trusted OS running in some -secure environment, for example, TrustZone on ARM CPUs, or a separate -secure co-processor etc. A TEE driver handles the details needed to -communicate with the TEE. - -This subsystem deals with: - -- Registration of TEE drivers - -- Managing shared memory between Linux and the TEE - -- Providing a generic API to the TEE - -The TEE interface -================= - -include/uapi/linux/tee.h defines the generic interface to a TEE. - -User space (the client) connects to the driver by opening /dev/tee[0-9]* or -/dev/teepriv[0-9]*. - -- TEE_IOC_SHM_ALLOC allocates shared memory and returns a file descriptor - which user space can mmap. When user space doesn't need the file - descriptor any more, it should be closed. When shared memory isn't needed - any longer it should be unmapped with munmap() to allow the reuse of - memory. - -- TEE_IOC_VERSION lets user space know which TEE this driver handles and - its capabilities. - -- TEE_IOC_OPEN_SESSION opens a new session to a Trusted Application. - -- TEE_IOC_INVOKE invokes a function in a Trusted Application. - -- TEE_IOC_CANCEL may cancel an ongoing TEE_IOC_OPEN_SESSION or TEE_IOC_INVOKE. - -- TEE_IOC_CLOSE_SESSION closes a session to a Trusted Application. - -There are two classes of clients, normal clients and supplicants. The latter is -a helper process for the TEE to access resources in Linux, for example file -system access. A normal client opens /dev/tee[0-9]* and a supplicant opens -/dev/teepriv[0-9]. - -Much of the communication between clients and the TEE is opaque to the -driver. The main job for the driver is to receive requests from the -clients, forward them to the TEE and send back the results. In the case of -supplicants the communication goes in the other direction, the TEE sends -requests to the supplicant which then sends back the result. - -The TEE kernel interface -======================== - -Kernel provides a TEE bus infrastructure where a Trusted Application is -represented as a device identified via Universally Unique Identifier (UUID) and -client drivers register a table of supported device UUIDs. - -TEE bus infrastructure registers following APIs: - -match(): - iterates over the client driver UUID table to find a corresponding - match for device UUID. If a match is found, then this particular device is - probed via corresponding probe API registered by the client driver. This - process happens whenever a device or a client driver is registered with TEE - bus. - -uevent(): - notifies user-space (udev) whenever a new device is registered on - TEE bus for auto-loading of modularized client drivers. - -TEE bus device enumeration is specific to underlying TEE implementation, so it -is left open for TEE drivers to provide corresponding implementation. - -Then TEE client driver can talk to a matched Trusted Application using APIs -listed in include/linux/tee_drv.h. - -TEE client driver example -------------------------- - -Suppose a TEE client driver needs to communicate with a Trusted Application -having UUID: ``ac6a4085-0e82-4c33-bf98-8eb8e118b6c2``, so driver registration -snippet would look like:: - - static const struct tee_client_device_id client_id_table[] = { - {UUID_INIT(0xac6a4085, 0x0e82, 0x4c33, - 0xbf, 0x98, 0x8e, 0xb8, 0xe1, 0x18, 0xb6, 0xc2)}, - {} - }; - - MODULE_DEVICE_TABLE(tee, client_id_table); - - static struct tee_client_driver client_driver = { - .id_table = client_id_table, - .driver = { - .name = DRIVER_NAME, - .bus = &tee_bus_type, - .probe = client_probe, - .remove = client_remove, - }, - }; - - static int __init client_init(void) - { - return driver_register(&client_driver.driver); - } - - static void __exit client_exit(void) - { - driver_unregister(&client_driver.driver); - } - - module_init(client_init); - module_exit(client_exit); - -OP-TEE driver -============= - -The OP-TEE driver handles OP-TEE [1] based TEEs. Currently it is only the ARM -TrustZone based OP-TEE solution that is supported. - -Lowest level of communication with OP-TEE builds on ARM SMC Calling -Convention (SMCCC) [2], which is the foundation for OP-TEE's SMC interface -[3] used internally by the driver. Stacked on top of that is OP-TEE Message -Protocol [4]. - -OP-TEE SMC interface provides the basic functions required by SMCCC and some -additional functions specific for OP-TEE. The most interesting functions are: - -- OPTEE_SMC_FUNCID_CALLS_UID (part of SMCCC) returns the version information - which is then returned by TEE_IOC_VERSION - -- OPTEE_SMC_CALL_GET_OS_UUID returns the particular OP-TEE implementation, used - to tell, for instance, a TrustZone OP-TEE apart from an OP-TEE running on a - separate secure co-processor. - -- OPTEE_SMC_CALL_WITH_ARG drives the OP-TEE message protocol - -- OPTEE_SMC_GET_SHM_CONFIG lets the driver and OP-TEE agree on which memory - range to used for shared memory between Linux and OP-TEE. - -The GlobalPlatform TEE Client API [5] is implemented on top of the generic -TEE API. - -Picture of the relationship between the different components in the -OP-TEE architecture:: - - User space Kernel Secure world - ~~~~~~~~~~ ~~~~~~ ~~~~~~~~~~~~ - +--------+ +-------------+ - | Client | | Trusted | - +--------+ | Application | - /\ +-------------+ - || +----------+ /\ - || |tee- | || - || |supplicant| \/ - || +----------+ +-------------+ - \/ /\ | TEE Internal| - +-------+ || | API | - + TEE | || +--------+--------+ +-------------+ - | Client| || | TEE | OP-TEE | | OP-TEE | - | API | \/ | subsys | driver | | Trusted OS | - +-------+----------------+----+-------+----+-----------+-------------+ - | Generic TEE API | | OP-TEE MSG | - | IOCTL (TEE_IOC_*) | | SMCCC (OPTEE_SMC_CALL_*) | - +-----------------------------+ +------------------------------+ - -RPC (Remote Procedure Call) are requests from secure world to kernel driver -or tee-supplicant. An RPC is identified by a special range of SMCCC return -values from OPTEE_SMC_CALL_WITH_ARG. RPC messages which are intended for the -kernel are handled by the kernel driver. Other RPC messages will be forwarded to -tee-supplicant without further involvement of the driver, except switching -shared memory buffer representation. - -OP-TEE device enumeration -------------------------- - -OP-TEE provides a pseudo Trusted Application: drivers/tee/optee/device.c in -order to support device enumeration. In other words, OP-TEE driver invokes this -application to retrieve a list of Trusted Applications which can be registered -as devices on the TEE bus. - -OP-TEE notifications --------------------- - -There are two kinds of notifications that secure world can use to make -normal world aware of some event. - -1. Synchronous notifications delivered with ``OPTEE_RPC_CMD_NOTIFICATION`` - using the ``OPTEE_RPC_NOTIFICATION_SEND`` parameter. -2. Asynchronous notifications delivered with a combination of a non-secure - edge-triggered interrupt and a fast call from the non-secure interrupt - handler. - -Synchronous notifications are limited by depending on RPC for delivery, -this is only usable when secure world is entered with a yielding call via -``OPTEE_SMC_CALL_WITH_ARG``. This excludes such notifications from secure -world interrupt handlers. - -An asynchronous notification is delivered via a non-secure edge-triggered -interrupt to an interrupt handler registered in the OP-TEE driver. The -actual notification value are retrieved with the fast call -``OPTEE_SMC_GET_ASYNC_NOTIF_VALUE``. Note that one interrupt can represent -multiple notifications. - -One notification value ``OPTEE_SMC_ASYNC_NOTIF_VALUE_DO_BOTTOM_HALF`` has a -special meaning. When this value is received it means that normal world is -supposed to make a yielding call ``OPTEE_MSG_CMD_DO_BOTTOM_HALF``. This -call is done from the thread assisting the interrupt handler. This is a -building block for OP-TEE OS in secure world to implement the top half and -bottom half style of device drivers. - -OPTEE_INSECURE_LOAD_IMAGE Kconfig option ----------------------------------------- - -The OPTEE_INSECURE_LOAD_IMAGE Kconfig option enables the ability to load the -BL32 OP-TEE image from the kernel after the kernel boots, rather than loading -it from the firmware before the kernel boots. This also requires enabling the -corresponding option in Trusted Firmware for Arm. The Trusted Firmware for Arm -documentation [8] explains the security threat associated with enabling this as -well as mitigations at the firmware and platform level. - -There are additional attack vectors/mitigations for the kernel that should be -addressed when using this option. - -1. Boot chain security. - - * Attack vector: Replace the OP-TEE OS image in the rootfs to gain control of - the system. - - * Mitigation: There must be boot chain security that verifies the kernel and - rootfs, otherwise an attacker can modify the loaded OP-TEE binary by - modifying it in the rootfs. - -2. Alternate boot modes. - - * Attack vector: Using an alternate boot mode (i.e. recovery mode), the - OP-TEE driver isn't loaded, leaving the SMC hole open. - - * Mitigation: If there are alternate methods of booting the device, such as a - recovery mode, it should be ensured that the same mitigations are applied - in that mode. - -3. Attacks prior to SMC invocation. - - * Attack vector: Code that is executed prior to issuing the SMC call to load - OP-TEE can be exploited to then load an alternate OS image. - - * Mitigation: The OP-TEE driver must be loaded before any potential attack - vectors are opened up. This should include mounting of any modifiable - filesystems, opening of network ports or communicating with external - devices (e.g. USB). - -4. Blocking SMC call to load OP-TEE. - - * Attack vector: Prevent the driver from being probed, so the SMC call to - load OP-TEE isn't executed when desired, leaving it open to being executed - later and loading a modified OS. - - * Mitigation: It is recommended to build the OP-TEE driver as builtin driver - rather than as a module to prevent exploits that may cause the module to - not be loaded. - -AMD-TEE driver -============== - -The AMD-TEE driver handles the communication with AMD's TEE environment. The -TEE environment is provided by AMD Secure Processor. - -The AMD Secure Processor (formerly called Platform Security Processor or PSP) -is a dedicated processor that features ARM TrustZone technology, along with a -software-based Trusted Execution Environment (TEE) designed to enable -third-party Trusted Applications. This feature is currently enabled only for -APUs. - -The following picture shows a high level overview of AMD-TEE:: - - | - x86 | - | - User space (Kernel space) | AMD Secure Processor (PSP) - ~~~~~~~~~~ ~~~~~~~~~~~~~~ | ~~~~~~~~~~~~~~~~~~~~~~~~~~ - | - +--------+ | +-------------+ - | Client | | | Trusted | - +--------+ | | Application | - /\ | +-------------+ - || | /\ - || | || - || | \/ - || | +----------+ - || | | TEE | - || | | Internal | - \/ | | API | - +---------+ +-----------+---------+ +----------+ - | TEE | | TEE | AMD-TEE | | AMD-TEE | - | Client | | subsystem | driver | | Trusted | - | API | | | | | OS | - +---------+-----------+----+------+---------+---------+----------+ - | Generic TEE API | | ASP | Mailbox | - | IOCTL (TEE_IOC_*) | | driver | Register Protocol | - +--------------------------+ +---------+--------------------+ - -At the lowest level (in x86), the AMD Secure Processor (ASP) driver uses the -CPU to PSP mailbox register to submit commands to the PSP. The format of the -command buffer is opaque to the ASP driver. It's role is to submit commands to -the secure processor and return results to AMD-TEE driver. The interface -between AMD-TEE driver and AMD Secure Processor driver can be found in [6]. - -The AMD-TEE driver packages the command buffer payload for processing in TEE. -The command buffer format for the different TEE commands can be found in [7]. - -The TEE commands supported by AMD-TEE Trusted OS are: - -* TEE_CMD_ID_LOAD_TA - loads a Trusted Application (TA) binary into - TEE environment. -* TEE_CMD_ID_UNLOAD_TA - unloads TA binary from TEE environment. -* TEE_CMD_ID_OPEN_SESSION - opens a session with a loaded TA. -* TEE_CMD_ID_CLOSE_SESSION - closes session with loaded TA -* TEE_CMD_ID_INVOKE_CMD - invokes a command with loaded TA -* TEE_CMD_ID_MAP_SHARED_MEM - maps shared memory -* TEE_CMD_ID_UNMAP_SHARED_MEM - unmaps shared memory - -AMD-TEE Trusted OS is the firmware running on AMD Secure Processor. - -The AMD-TEE driver registers itself with TEE subsystem and implements the -following driver function callbacks: - -* get_version - returns the driver implementation id and capability. -* open - sets up the driver context data structure. -* release - frees up driver resources. -* open_session - loads the TA binary and opens session with loaded TA. -* close_session - closes session with loaded TA and unloads it. -* invoke_func - invokes a command with loaded TA. - -cancel_req driver callback is not supported by AMD-TEE. - -The GlobalPlatform TEE Client API [5] can be used by the user space (client) to -talk to AMD's TEE. AMD's TEE provides a secure environment for loading, opening -a session, invoking commands and closing session with TA. - -References -========== - -[1] https://github.com/OP-TEE/optee_os - -[2] http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html - -[3] drivers/tee/optee/optee_smc.h - -[4] drivers/tee/optee/optee_msg.h - -[5] http://www.globalplatform.org/specificationsdevice.asp look for - "TEE Client API Specification v1.0" and click download. - -[6] include/linux/psp-tee.h - -[7] drivers/tee/amdtee/amdtee_if.h - -[8] https://trustedfirmware-a.readthedocs.io/en/latest/threat_model/threat_model.html diff --git a/Documentation/subsystem-apis.rst b/Documentation/subsystem-apis.rst index 930dc23998a032..2d353fb8ea26a4 100644 --- a/Documentation/subsystem-apis.rst +++ b/Documentation/subsystem-apis.rst @@ -86,3 +86,4 @@ Storage interfaces misc-devices/index peci/index wmi/index + tee/index diff --git a/Documentation/tee/amd-tee.rst b/Documentation/tee/amd-tee.rst new file mode 100644 index 00000000000000..51500fde703895 --- /dev/null +++ b/Documentation/tee/amd-tee.rst @@ -0,0 +1,90 @@ +.. SPDX-License-Identifier: GPL-2.0 + +============================================= +AMD-TEE (AMD's Trusted Execution Environment) +============================================= + +The AMD-TEE driver handles the communication with AMD's TEE environment. The +TEE environment is provided by AMD Secure Processor. + +The AMD Secure Processor (formerly called Platform Security Processor or PSP) +is a dedicated processor that features ARM TrustZone technology, along with a +software-based Trusted Execution Environment (TEE) designed to enable +third-party Trusted Applications. This feature is currently enabled only for +APUs. + +The following picture shows a high level overview of AMD-TEE:: + + | + x86 | + | + User space (Kernel space) | AMD Secure Processor (PSP) + ~~~~~~~~~~ ~~~~~~~~~~~~~~ | ~~~~~~~~~~~~~~~~~~~~~~~~~~ + | + +--------+ | +-------------+ + | Client | | | Trusted | + +--------+ | | Application | + /\ | +-------------+ + || | /\ + || | || + || | \/ + || | +----------+ + || | | TEE | + || | | Internal | + \/ | | API | + +---------+ +-----------+---------+ +----------+ + | TEE | | TEE | AMD-TEE | | AMD-TEE | + | Client | | subsystem | driver | | Trusted | + | API | | | | | OS | + +---------+-----------+----+------+---------+---------+----------+ + | Generic TEE API | | ASP | Mailbox | + | IOCTL (TEE_IOC_*) | | driver | Register Protocol | + +--------------------------+ +---------+--------------------+ + +At the lowest level (in x86), the AMD Secure Processor (ASP) driver uses the +CPU to PSP mailbox register to submit commands to the PSP. The format of the +command buffer is opaque to the ASP driver. It's role is to submit commands to +the secure processor and return results to AMD-TEE driver. The interface +between AMD-TEE driver and AMD Secure Processor driver can be found in [1]. + +The AMD-TEE driver packages the command buffer payload for processing in TEE. +The command buffer format for the different TEE commands can be found in [2]. + +The TEE commands supported by AMD-TEE Trusted OS are: + +* TEE_CMD_ID_LOAD_TA - loads a Trusted Application (TA) binary into + TEE environment. +* TEE_CMD_ID_UNLOAD_TA - unloads TA binary from TEE environment. +* TEE_CMD_ID_OPEN_SESSION - opens a session with a loaded TA. +* TEE_CMD_ID_CLOSE_SESSION - closes session with loaded TA +* TEE_CMD_ID_INVOKE_CMD - invokes a command with loaded TA +* TEE_CMD_ID_MAP_SHARED_MEM - maps shared memory +* TEE_CMD_ID_UNMAP_SHARED_MEM - unmaps shared memory + +AMD-TEE Trusted OS is the firmware running on AMD Secure Processor. + +The AMD-TEE driver registers itself with TEE subsystem and implements the +following driver function callbacks: + +* get_version - returns the driver implementation id and capability. +* open - sets up the driver context data structure. +* release - frees up driver resources. +* open_session - loads the TA binary and opens session with loaded TA. +* close_session - closes session with loaded TA and unloads it. +* invoke_func - invokes a command with loaded TA. + +cancel_req driver callback is not supported by AMD-TEE. + +The GlobalPlatform TEE Client API [3] can be used by the user space (client) to +talk to AMD's TEE. AMD's TEE provides a secure environment for loading, opening +a session, invoking commands and closing session with TA. + +References +========== + +[1] include/linux/psp-tee.h + +[2] drivers/tee/amdtee/amdtee_if.h + +[3] http://www.globalplatform.org/specificationsdevice.asp look for + "TEE Client API Specification v1.0" and click download. diff --git a/Documentation/tee/index.rst b/Documentation/tee/index.rst new file mode 100644 index 00000000000000..a23bd08847e5a2 --- /dev/null +++ b/Documentation/tee/index.rst @@ -0,0 +1,19 @@ +.. SPDX-License-Identifier: GPL-2.0 + +============= +TEE Subsystem +============= + +.. toctree:: + :maxdepth: 1 + + tee + op-tee + amd-tee + +.. only:: subproject and html + + Indices + ======= + + * :ref:`genindex` diff --git a/Documentation/tee/op-tee.rst b/Documentation/tee/op-tee.rst new file mode 100644 index 00000000000000..b0ac097d55476a --- /dev/null +++ b/Documentation/tee/op-tee.rst @@ -0,0 +1,166 @@ +.. SPDX-License-Identifier: GPL-2.0 + +==================================================== +OP-TEE (Open Portable Trusted Execution Environment) +==================================================== + +The OP-TEE driver handles OP-TEE [1] based TEEs. Currently it is only the ARM +TrustZone based OP-TEE solution that is supported. + +Lowest level of communication with OP-TEE builds on ARM SMC Calling +Convention (SMCCC) [2], which is the foundation for OP-TEE's SMC interface +[3] used internally by the driver. Stacked on top of that is OP-TEE Message +Protocol [4]. + +OP-TEE SMC interface provides the basic functions required by SMCCC and some +additional functions specific for OP-TEE. The most interesting functions are: + +- OPTEE_SMC_FUNCID_CALLS_UID (part of SMCCC) returns the version information + which is then returned by TEE_IOC_VERSION + +- OPTEE_SMC_CALL_GET_OS_UUID returns the particular OP-TEE implementation, used + to tell, for instance, a TrustZone OP-TEE apart from an OP-TEE running on a + separate secure co-processor. + +- OPTEE_SMC_CALL_WITH_ARG drives the OP-TEE message protocol + +- OPTEE_SMC_GET_SHM_CONFIG lets the driver and OP-TEE agree on which memory + range to used for shared memory between Linux and OP-TEE. + +The GlobalPlatform TEE Client API [5] is implemented on top of the generic +TEE API. + +Picture of the relationship between the different components in the +OP-TEE architecture:: + + User space Kernel Secure world + ~~~~~~~~~~ ~~~~~~ ~~~~~~~~~~~~ + +--------+ +-------------+ + | Client | | Trusted | + +--------+ | Application | + /\ +-------------+ + || +----------+ /\ + || |tee- | || + || |supplicant| \/ + || +----------+ +-------------+ + \/ /\ | TEE Internal| + +-------+ || | API | + + TEE | || +--------+--------+ +-------------+ + | Client| || | TEE | OP-TEE | | OP-TEE | + | API | \/ | subsys | driver | | Trusted OS | + +-------+----------------+----+-------+----+-----------+-------------+ + | Generic TEE API | | OP-TEE MSG | + | IOCTL (TEE_IOC_*) | | SMCCC (OPTEE_SMC_CALL_*) | + +-----------------------------+ +------------------------------+ + +RPC (Remote Procedure Call) are requests from secure world to kernel driver +or tee-supplicant. An RPC is identified by a special range of SMCCC return +values from OPTEE_SMC_CALL_WITH_ARG. RPC messages which are intended for the +kernel are handled by the kernel driver. Other RPC messages will be forwarded to +tee-supplicant without further involvement of the driver, except switching +shared memory buffer representation. + +OP-TEE device enumeration +------------------------- + +OP-TEE provides a pseudo Trusted Application: drivers/tee/optee/device.c in +order to support device enumeration. In other words, OP-TEE driver invokes this +application to retrieve a list of Trusted Applications which can be registered +as devices on the TEE bus. + +OP-TEE notifications +-------------------- + +There are two kinds of notifications that secure world can use to make +normal world aware of some event. + +1. Synchronous notifications delivered with ``OPTEE_RPC_CMD_NOTIFICATION`` + using the ``OPTEE_RPC_NOTIFICATION_SEND`` parameter. +2. Asynchronous notifications delivered with a combination of a non-secure + edge-triggered interrupt and a fast call from the non-secure interrupt + handler. + +Synchronous notifications are limited by depending on RPC for delivery, +this is only usable when secure world is entered with a yielding call via +``OPTEE_SMC_CALL_WITH_ARG``. This excludes such notifications from secure +world interrupt handlers. + +An asynchronous notification is delivered via a non-secure edge-triggered +interrupt to an interrupt handler registered in the OP-TEE driver. The +actual notification value are retrieved with the fast call +``OPTEE_SMC_GET_ASYNC_NOTIF_VALUE``. Note that one interrupt can represent +multiple notifications. + +One notification value ``OPTEE_SMC_ASYNC_NOTIF_VALUE_DO_BOTTOM_HALF`` has a +special meaning. When this value is received it means that normal world is +supposed to make a yielding call ``OPTEE_MSG_CMD_DO_BOTTOM_HALF``. This +call is done from the thread assisting the interrupt handler. This is a +building block for OP-TEE OS in secure world to implement the top half and +bottom half style of device drivers. + +OPTEE_INSECURE_LOAD_IMAGE Kconfig option +---------------------------------------- + +The OPTEE_INSECURE_LOAD_IMAGE Kconfig option enables the ability to load the +BL32 OP-TEE image from the kernel after the kernel boots, rather than loading +it from the firmware before the kernel boots. This also requires enabling the +corresponding option in Trusted Firmware for Arm. The Trusted Firmware for Arm +documentation [6] explains the security threat associated with enabling this as +well as mitigations at the firmware and platform level. + +There are additional attack vectors/mitigations for the kernel that should be +addressed when using this option. + +1. Boot chain security. + + * Attack vector: Replace the OP-TEE OS image in the rootfs to gain control of + the system. + + * Mitigation: There must be boot chain security that verifies the kernel and + rootfs, otherwise an attacker can modify the loaded OP-TEE binary by + modifying it in the rootfs. + +2. Alternate boot modes. + + * Attack vector: Using an alternate boot mode (i.e. recovery mode), the + OP-TEE driver isn't loaded, leaving the SMC hole open. + + * Mitigation: If there are alternate methods of booting the device, such as a + recovery mode, it should be ensured that the same mitigations are applied + in that mode. + +3. Attacks prior to SMC invocation. + + * Attack vector: Code that is executed prior to issuing the SMC call to load + OP-TEE can be exploited to then load an alternate OS image. + + * Mitigation: The OP-TEE driver must be loaded before any potential attack + vectors are opened up. This should include mounting of any modifiable + filesystems, opening of network ports or communicating with external + devices (e.g. USB). + +4. Blocking SMC call to load OP-TEE. + + * Attack vector: Prevent the driver from being probed, so the SMC call to + load OP-TEE isn't executed when desired, leaving it open to being executed + later and loading a modified OS. + + * Mitigation: It is recommended to build the OP-TEE driver as builtin driver + rather than as a module to prevent exploits that may cause the module to + not be loaded. + +References +========== + +[1] https://github.com/OP-TEE/optee_os + +[2] http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html + +[3] drivers/tee/optee/optee_smc.h + +[4] drivers/tee/optee/optee_msg.h + +[5] http://www.globalplatform.org/specificationsdevice.asp look for + "TEE Client API Specification v1.0" and click download. + +[6] https://trustedfirmware-a.readthedocs.io/en/latest/threat_model/threat_model.html diff --git a/Documentation/tee/tee.rst b/Documentation/tee/tee.rst new file mode 100644 index 00000000000000..fd9f8c4ff63d26 --- /dev/null +++ b/Documentation/tee/tee.rst @@ -0,0 +1,22 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=================================== +TEE (Trusted Execution Environment) +=================================== + +This document describes the TEE subsystem in Linux. + +Overview +======== + +A TEE is a trusted OS running in some secure environment, for example, +TrustZone on ARM CPUs, or a separate secure co-processor etc. A TEE driver +handles the details needed to communicate with the TEE. + +This subsystem deals with: + +- Registration of TEE drivers + +- Managing shared memory between Linux and the TEE + +- Providing a generic API to the TEE diff --git a/Documentation/trace/coresight/coresight.rst b/Documentation/trace/coresight/coresight.rst index 826e59a698da19..d4f93d6a2d6335 100644 --- a/Documentation/trace/coresight/coresight.rst +++ b/Documentation/trace/coresight/coresight.rst @@ -624,6 +624,10 @@ They are also listed in the folder /sys/bus/event_source/devices/cs_etm/format/ * - timestamp - Session local version of the system wide setting: :ref:`ETMv4_MODE_TIMESTAMP ` + * - cc_threshold + - Cycle count threshold value. If nothing is provided here or the provided value is 0, then the + default value i.e 0x100 will be used. If provided value is less than minimum cycles threshold + value, as indicated via TRCIDR3.CCITMIN, then the minimum value will be used instead. How to use the STM module ------------------------- diff --git a/Documentation/trace/ftrace-uses.rst b/Documentation/trace/ftrace-uses.rst index f7d98ae5b8853e..e198854ace7932 100644 --- a/Documentation/trace/ftrace-uses.rst +++ b/Documentation/trace/ftrace-uses.rst @@ -182,7 +182,7 @@ FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED FTRACE_OPS_FL_RECURSION By default, it is expected that the callback can handle recursion. - But if the callback is not that worried about overehead, then + But if the callback is not that worried about overhead, then setting this bit will add the recursion protection around the callback by calling a helper function that will do the recursion protection and only call the callback if it did not recurse. @@ -190,7 +190,7 @@ FTRACE_OPS_FL_RECURSION Note, if this flag is not set, and recursion does occur, it could cause the system to crash, and possibly reboot via a triple fault. - Not, if this flag is set, then the callback will always be called + Note, if this flag is set, then the callback will always be called with preemption disabled. If it is not set, then it is possible (but not guaranteed) that the callback will be called in preemptable context. diff --git a/Documentation/trace/ftrace.rst b/Documentation/trace/ftrace.rst index 23572f6697c0ab..7e7b8ec1793483 100644 --- a/Documentation/trace/ftrace.rst +++ b/Documentation/trace/ftrace.rst @@ -180,6 +180,21 @@ of ftrace. Here is a list of some of the key files: Only active when the file contains a number greater than 0. (in microseconds) + buffer_percent: + + This is the watermark for how much the ring buffer needs to be filled + before a waiter is woken up. That is, if an application calls a + blocking read syscall on one of the per_cpu trace_pipe_raw files, it + will block until the given amount of data specified by buffer_percent + is in the ring buffer before it wakes the reader up. This also + controls how the splice system calls are blocked on this file:: + + 0 - means to wake up as soon as there is any data in the ring buffer. + 50 - means to wake up when roughly half of the ring buffer sub-buffers + are full. + 100 - means to block until the ring buffer is totally full and is + about to start overwriting the older data. + buffer_size_kb: This sets or displays the number of kilobytes each CPU @@ -203,6 +218,27 @@ of ftrace. Here is a list of some of the key files: This displays the total combined size of all the trace buffers. + buffer_subbuf_size_kb: + + This sets or displays the sub buffer size. The ring buffer is broken up + into several same size "sub buffers". An event can not be bigger than + the size of the sub buffer. Normally, the sub buffer is the size of the + architecture's page (4K on x86). The sub buffer also contains meta data + at the start which also limits the size of an event. That means when + the sub buffer is a page size, no event can be larger than the page + size minus the sub buffer meta data. + + Note, the buffer_subbuf_size_kb is a way for the user to specify the + minimum size of the subbuffer. The kernel may make it bigger due to the + implementation details, or simply fail the operation if the kernel can + not handle the request. + + Changing the sub buffer size allows for events to be larger than the + page size. + + Note: When changing the sub-buffer size, tracing is stopped and any + data in the ring buffer and the snapshot buffer will be discarded. + free_buffer: If a process is performing tracing, and the ring buffer should be @@ -2574,7 +2610,7 @@ want, depending on your needs. - The cpu number on which the function executed is default enabled. It is sometimes better to only trace one cpu (see - tracing_cpu_mask file) or you might sometimes see unordered + tracing_cpumask file) or you might sometimes see unordered function calls while cpu tracing switch. - hide: echo nofuncgraph-cpu > trace_options diff --git a/Documentation/trace/kprobes.rst b/Documentation/trace/kprobes.rst index f825970a149573..e1636e579c9ccd 100644 --- a/Documentation/trace/kprobes.rst +++ b/Documentation/trace/kprobes.rst @@ -4,7 +4,7 @@ Kernel Probes (Kprobes) :Author: Jim Keniston :Author: Prasanna S Panchamukhi -:Author: Masami Hiramatsu +:Author: Masami Hiramatsu .. CONTENTS @@ -321,6 +321,7 @@ architectures: - mips - s390 - parisc +- loongarch Configuring Kprobes =================== diff --git a/Documentation/translations/it_IT/process/development-process.rst b/Documentation/translations/it_IT/process/development-process.rst index f1a6eca3082462..20e77c9816a148 100644 --- a/Documentation/translations/it_IT/process/development-process.rst +++ b/Documentation/translations/it_IT/process/development-process.rst @@ -8,9 +8,17 @@ Una guida al processo di sviluppo del Kernel ============================================ -Contenuti: +Lo scopo di questo documento è quello di aiutare gli sviluppatori (ed i loro +supervisori) a lavorare con la communità di sviluppo con il minimo sforzo. È +un tentativo di documentare il funzionamento di questa communità in modo che +sia accessibile anche a coloro che non hanno famigliarità con lo sviluppo del +Kernel Linux (o, anzi, con lo sviluppo di software libero in generale). Benchè +qui sia presente del materiale tecnico, questa è una discussione rivolta in +particolare al procedimento, e quindi per essere compreso non richiede una +conoscenza approfondità sullo sviluppo del kernel. .. toctree:: + :caption: Contenuti :numbered: :maxdepth: 2 @@ -22,12 +30,3 @@ Contenuti: 6.Followthrough 7.AdvancedTopics 8.Conclusion - -Lo scopo di questo documento è quello di aiutare gli sviluppatori (ed i loro -supervisori) a lavorare con la communità di sviluppo con il minimo sforzo. È -un tentativo di documentare il funzionamento di questa communità in modo che -sia accessibile anche a coloro che non hanno famigliarità con lo sviluppo del -Kernel Linux (o, anzi, con lo sviluppo di software libero in generale). Benchè -qui sia presente del materiale tecnico, questa è una discussione rivolta in -particolare al procedimento, e quindi per essere compreso non richiede una -conoscenza approfondità sullo sviluppo del kernel. diff --git a/Documentation/translations/ja_JP/SubmitChecklist b/Documentation/translations/ja_JP/SubmitChecklist index 4429447b096558..1759c6b452d60a 100644 --- a/Documentation/translations/ja_JP/SubmitChecklist +++ b/Documentation/translations/ja_JP/SubmitChecklist @@ -56,8 +56,8 @@ Linux カーネルパッチ投稿者向けチェックリスト 9: sparseを利用してちゃんとしたコードチェックをしてください。 -10: 'make checkstack' と 'make namespacecheck' を利用し、問題が発見されたら - 修正してください。'make checkstack' は明示的に問題を示しませんが、どれか +10: 'make checkstack' を利用し、問題が発見されたら修正してください。 + 'make checkstack' は明示的に問題を示しませんが、どれか 1つの関数が512バイトより大きいスタックを使っていれば、修正すべき候補と なります。 diff --git a/Documentation/translations/sp_SP/disclaimer-sp.rst b/Documentation/translations/sp_SP/disclaimer-sp.rst index a400034e95f962..841c2523e3dd02 100644 --- a/Documentation/translations/sp_SP/disclaimer-sp.rst +++ b/Documentation/translations/sp_SP/disclaimer-sp.rst @@ -4,3 +4,6 @@ Si tiene alguna duda sobre la exactitud del contenido de esta traducción, la única referencia válida es la documentación oficial en inglés. + Además, por defecto, los enlaces a documentos redirigen a la + documentación en inglés, incluso si existe una versión traducida. + Consulte el índice para más información. diff --git a/Documentation/translations/sp_SP/howto.rst b/Documentation/translations/sp_SP/howto.rst deleted file mode 100644 index f1629738b49d03..00000000000000 --- a/Documentation/translations/sp_SP/howto.rst +++ /dev/null @@ -1,617 +0,0 @@ -.. include:: ./disclaimer-sp.rst - -:Original: :ref:`Documentation/process/howto.rst ` -:Translator: Carlos Bilbao - -.. _sp_process_howto: - -Cómo participar en el desarrollo del kernel de Linux -==================================================== - -Este documento es el principal punto de partida. Contiene instrucciones -sobre cómo convertirse en desarrollador del kernel de Linux y explica cómo -trabajar con el y en su desarrollo. El documento no tratará ningún aspecto -técnico relacionado con la programación del kernel, pero le ayudará -guiándole por el camino correcto. - -Si algo en este documento quedara obsoleto, envíe parches al maintainer de -este archivo, que se encuentra en la parte superior del documento. - -Introducción ------------- -¿De modo que quiere descubrir como convertirse en un/a desarrollador/a del -kernel de Linux? Tal vez su jefe le haya dicho, "Escriba un driver de -Linux para este dispositivo." El objetivo de este documento en enseñarle -todo cuanto necesita para conseguir esto, describiendo el proceso por el -que debe pasar, y con indicaciones de como trabajar con la comunidad. -También trata de explicar las razones por las cuales la comunidad trabaja -de la forma en que lo hace. - -El kernel esta principalmente escrito en C, con algunas partes que son -dependientes de la arquitectura en ensamblador. Un buen conocimiento de C -es necesario para desarrollar en el kernel. Lenguaje ensamblador (en -cualquier arquitectura) no es necesario excepto que planee realizar -desarrollo de bajo nivel para dicha arquitectura. Aunque no es un perfecto -sustituto para una educación sólida en C y/o años de experiencia, los -siguientes libros sirven, como mínimo, como referencia: - -- "The C Programming Language" de Kernighan e Ritchie [Prentice Hall] -- "Practical C Programming" de Steve Oualline [O'Reilly] -- "C: A Reference Manual" de Harbison and Steele [Prentice Hall] - -El kernel está escrito usando GNU C y la cadena de herramientas GNU. Si -bien se adhiere al estándar ISO C89, utiliza una serie de extensiones que -no aparecen en dicho estándar. El kernel usa un C independiente de entorno, -sin depender de la biblioteca C estándar, por lo que algunas partes del -estándar C no son compatibles. Divisiones de long long arbitrarios o -de coma flotante no son permitidas. En ocasiones, puede ser difícil de -entender las suposiciones que el kernel hace respecto a la cadena de -herramientas y las extensiones que usa, y desafortunadamente no hay -referencia definitiva para estas. Consulte las páginas de información de -gcc (`info gcc`) para obtener información al respecto. - -Recuerde que está tratando de aprender a trabajar con una comunidad de -desarrollo existente. Es un grupo diverso de personas, con altos estándares -de código, estilo y procedimiento. Estas normas han sido creadas a lo -largo del tiempo en función de lo que se ha encontrado que funciona mejor -para un equipo tan grande y geográficamente disperso. Trate de aprender -tanto como le sea posible acerca de estos estándares antes de tiempo, ya -que están bien documentados; no espere que la gente se adapte a usted o a -la forma de hacer las cosas en su empresa. - -Cuestiones legales ------------------- -El código fuente del kernel de Linux se publica bajo licencia GPL. Por -favor, revise el archivo COPYING, presente en la carpeta principal del -código fuente, para detalles de la licencia. Si tiene alguna otra pregunta -sobre licencias, contacte a un abogado, no pregunte en listas de discusión -del kernel de Linux. La gente en estas listas no son abogadas, y no debe -confiar en sus opiniones en materia legal. - -Para preguntas y respuestas más frecuentes sobre la licencia GPL, consulte: - - https://www.gnu.org/licenses/gpl-faq.html - -Documentación --------------- -El código fuente del kernel de Linux tiene una gran variedad de documentos -que son increíblemente valiosos para aprender a interactuar con la -comunidad del kernel. Cuando se agregan nuevas funciones al kernel, se -recomienda que se incluyan nuevos archivos de documentación que expliquen -cómo usar la función. Cuando un cambio en el kernel hace que la interfaz -que el kernel expone espacio de usuario cambie, se recomienda que envíe la -información o un parche en las páginas del manual que expliquen el cambio -a mtk.manpages@gmail.com, y CC la lista linux-api@vger.kernel.org. - -Esta es la lista de archivos que están en el código fuente del kernel y son -de obligada lectura: - - :ref:`Documentation/admin-guide/README.rst ` - Este archivo ofrece una breve descripción del kernel de Linux y - describe lo que es necesario hacer para configurar y compilar el - kernel. Quienes sean nuevos en el kernel deben comenzar aquí. - - :ref:`Documentation/process/changes.rst ` - Este archivo proporciona una lista de los niveles mínimos de varios - paquetes que son necesarios para construir y ejecutar el kernel - exitosamente. - - :ref:`Documentation/process/coding-style.rst ` - Esto describe el estilo de código del kernel de Linux y algunas de los - razones detrás de esto. Se espera que todo el código nuevo siga las - directrices de este documento. La mayoría de los maintainers solo - aceptarán parches si se siguen estas reglas, y muchas personas solo - revisan el código si tiene el estilo adecuado. - - :ref:`Documentation/process/submitting-patches.rst ` - Este archivo describe en gran detalle cómo crear con éxito y enviar un - parche, que incluye (pero no se limita a): - - - Contenidos del correo electrónico (email) - - Formato del email - - A quien se debe enviar - - Seguir estas reglas no garantiza el éxito (ya que todos los parches son - sujetos a escrutinio de contenido y estilo), pero en caso de no seguir - dichas reglas, el fracaso es prácticamente garantizado. - Otras excelentes descripciones de cómo crear parches correctamente son: - - "The Perfect Patch" - https://www.ozlabs.org/~akpm/stuff/tpp.txt - - "Linux kernel patch submission format" - https://web.archive.org/web/20180829112450/http://linux.yyz.us/patch-format.html - - :ref:`Documentation/process/stable-api-nonsense.rst ` - Este archivo describe la lógica detrás de la decisión consciente de - no tener una API estable dentro del kernel, incluidas cosas como: - - - Capas intermedias del subsistema (por compatibilidad?) - - Portabilidad de drivers entre sistemas operativos - - Mitigar el cambio rápido dentro del árbol de fuentes del kernel (o - prevenir cambios rápidos) - - Este documento es crucial para comprender la filosofía del desarrollo - de Linux y es muy importante para las personas que se mudan a Linux - tras desarrollar otros sistemas operativos. - - :ref:`Documentation/process/security-bugs.rst ` - Si cree que ha encontrado un problema de seguridad en el kernel de - Linux, siga los pasos de este documento para ayudar a notificar a los - desarrolladores del kernel y ayudar a resolver el problema. - - :ref:`Documentation/process/management-style.rst ` - Este documento describe cómo operan los maintainers del kernel de Linux - y los valores compartidos detrás de sus metodologías. Esta es una - lectura importante para cualquier persona nueva en el desarrollo del - kernel (o cualquier persona que simplemente sienta curiosidad por - el campo IT), ya que clarifica muchos conceptos erróneos y confusiones - comunes sobre el comportamiento único de los maintainers del kernel. - - :ref:`Documentation/process/stable-kernel-rules.rst ` - Este archivo describe las reglas sobre cómo se suceden las versiones - del kernel estable, y qué hacer si desea obtener un cambio en una de - estas publicaciones. - - :ref:`Documentation/process/kernel-docs.rst ` - Una lista de documentación externa relativa al desarrollo del kernel. - Por favor consulte esta lista si no encuentra lo que están buscando - dentro de la documentación del kernel. - - :ref:`Documentation/process/applying-patches.rst ` - Una buena introducción que describe exactamente qué es un parche y cómo - aplicarlo a las diferentes ramas de desarrollo del kernel. - -El kernel también tiene una gran cantidad de documentos que pueden ser -generados automáticamente desde el propio código fuente o desde -ReStructuredText markups (ReST), como este. Esto incluye un descripción -completa de la API en el kernel y reglas sobre cómo manejar cerrojos -(locking) correctamente. - -Todos estos documentos se pueden generar como PDF o HTML ejecutando:: - - make pdfdocs - make htmldocs - -respectivamente desde el directorio fuente principal del kernel. - -Los documentos que utilizan el markup ReST se generarán en -Documentation/output. También se pueden generar en formatos LaTeX y ePub -con:: - - make latexdocs - make epubdocs - -Convertirse en un/a desarrollador/a de kernel ---------------------------------------------- - -Si no sabe nada sobre el desarrollo del kernel de Linux, debería consultar -el proyecto Linux KernelNewbies: - - https://kernelnewbies.org - -Consiste en una útil lista de correo donde puede preguntar casi cualquier -tipo de pregunta básica de desarrollo del kernel (asegúrese de buscar en -los archivos primero, antes de preguntar algo que ya ha sido respondido en -el pasado.) También tiene un canal IRC que puede usar para hacer preguntas -en tiempo real, y una gran cantidad de documentación útil para ir -aprendiendo sobre el desarrollo del kernel de Linux. - -El sitio web tiene información básica sobre la organización del código, -subsistemas, y proyectos actuales (tanto dentro como fuera del árbol). -También describe alguna información logística básica, como cómo compilar -un kernel y aplicar un parche. - -Si no sabe por dónde quiere empezar, pero quieres buscar alguna tarea que -comenzar a hacer para unirse a la comunidad de desarrollo del kernel, -acuda al proyecto Linux Kernel Janitor: - - https://kernelnewbies.org/KernelJanitors - -Es un gran lugar para comenzar. Describe una lista de problemas -relativamente simples que deben limpiarse y corregirse dentro del código -fuente del kernel de Linux árbol de fuentes. Trabajando con los -desarrolladores a cargo de este proyecto, aprenderá los conceptos básicos -para incluir su parche en el árbol del kernel de Linux, y posiblemente -descubrir en la dirección en que trabajar a continuación, si no tiene ya -una idea. - -Antes de realizar cualquier modificación real al código del kernel de -Linux, es imperativo entender cómo funciona el código en cuestión. Para -este propósito, nada es mejor que leerlo directamente (lo más complicado -está bien comentado), tal vez incluso con la ayuda de herramientas -especializadas. Una de esas herramientas que se recomienda especialmente -es el proyecto Linux Cross-Reference, que es capaz de presentar el código -fuente en un formato de página web indexada y autorreferencial. Una -excelente puesta al día del repositorio del código del kernel se puede -encontrar en: - - https://elixir.bootlin.com/ - -El proceso de desarrollo ------------------------- - -El proceso de desarrollo del kernel de Linux consiste actualmente de -diferentes "branches" (ramas) con muchos distintos subsistemas específicos -a cada una de ellas. Las diferentes ramas son: - - - El código principal de Linus (mainline tree) - - Varios árboles estables con múltiples major numbers - - Subsistemas específicos - - linux-next, para integración y testing - -Mainline tree (Árbol principal) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -El mainline tree es mantenido por Linus Torvalds, y puede encontrarse en -https://kernel.org o en su repo. El proceso de desarrollo es el siguiente: - - - Tan pronto como se lanza un nuevo kernel, se abre una ventana de dos - semanas, durante este período de tiempo, los maintainers pueden enviar - grandes modificaciones a Linus, por lo general los parches que ya se - han incluido en el linux-next durante unas semanas. La forma preferida - de enviar grandes cambios es usando git (la herramienta de - administración de código fuente del kernel, más información al respecto - en https://git-scm.com/), pero los parches simples también son validos. - - Después de dos semanas, se lanza un kernel -rc1 y la atención se centra - en hacer el kernel nuevo lo más estable ("solido") posible. La mayoría - de los parches en este punto deben arreglar una regresión. Los errores - que siempre han existido no son regresiones, por lo tanto, solo envíe - este tipo de correcciones si son importantes. Tenga en cuenta que se - podría aceptar un controlador (o sistema de archivos) completamente - nuevo después de -rc1 porque no hay riesgo de causar regresiones con - tal cambio, siempre y cuando el cambio sea autónomo y no afecte áreas - fuera del código que se está agregando. git se puede usar para enviar - parches a Linus después de que se lance -rc1, pero los parches también - deben ser enviado a una lista de correo pública para su revisión. - - Se lanza un nuevo -rc cada vez que Linus considera que el árbol git - actual esta en un estado razonablemente sano y adecuado para la prueba. - La meta es lanzar un nuevo kernel -rc cada semana. - - El proceso continúa hasta que el kernel se considera "listo", y esto - puede durar alrededor de 6 semanas. - -Vale la pena mencionar lo que Andrew Morton escribió en las listas de -correo del kernel de Linux, sobre lanzamientos del kernel (traducido): - - *"Nadie sabe cuándo se publicara un nuevo kernel, pues esto sucede - según el estado de los bugs, no de una cronología preconcebida."* - -Varios árboles estables con múltiples major numbers -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Los kernels con versiones de 3 partes son kernels estables. Estos contienen -correcciones relativamente pequeñas y críticas para problemas de seguridad -o importantes regresiones descubiertas para una publicación de código. -Cada lanzamiento en una gran serie estable incrementa la tercera parte de -la versión número, manteniendo las dos primeras partes iguales. - -Esta es la rama recomendada para los usuarios que quieren la versión -estable más reciente del kernel, y no están interesados en ayudar a probar -versiones en desarrollo/experimentales. - -Los árboles estables son mantenidos por el equipo "estable" -, y se liberan (publican) según lo dicten las -necesidades. El período de liberación normal es de aproximadamente dos -semanas, pero puede ser más largo si no hay problemas apremiantes. Un -problema relacionado con la seguridad, en cambio, puede causar un -lanzamiento casi instantáneamente. - -El archivo :ref:`Documentación/proceso/stable-kernel-rules.rst ` -en el árbol del kernel documenta qué tipos de cambios son aceptables para -el árbol estable y cómo funciona el proceso de lanzamiento. - -Subsistemas específicos -~~~~~~~~~~~~~~~~~~~~~~~~ -Los maintainers de los diversos subsistemas del kernel --- y también muchos -desarrolladores de subsistemas del kernel --- exponen su estado actual de -desarrollo en repositorios fuente. De esta manera, otros pueden ver lo que -está sucediendo en las diferentes áreas del kernel. En áreas donde el -desarrollo es rápido, se le puede pedir a un desarrollador que base sus -envíos en tal árbol del subsistema del kernel, para evitar conflictos entre -este y otros trabajos ya en curso. - -La mayoría de estos repositorios son árboles git, pero también hay otros -SCM en uso, o colas de parches que se publican como series quilt. Las -direcciones de estos repositorios de subsistemas se enumeran en el archivo -MAINTAINERS. Muchos de estos se pueden ver en https://git.kernel.org/. - -Antes de que un parche propuesto se incluya con dicho árbol de subsistemas, -es sujeto a revisión, que ocurre principalmente en las listas de correo -(ver la sección respectiva a continuación). Para varios subsistemas del -kernel, esta revisión se rastrea con la herramienta patchwork. Patchwork -ofrece una interfaz web que muestra publicaciones de parches, cualquier -comentario sobre un parche o revisiones a él, y los maintainers pueden -marcar los parches como en revisión, aceptado, o rechazado. La mayoría de -estos sitios de trabajo de parches se enumeran en - -https://patchwork.kernel.org/. - -linux-next, para integración y testing -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Antes de que las actualizaciones de los árboles de subsistemas se combinen -con el árbol principal, necesitan probar su integración. Para ello, existe -un repositorio especial de pruebas en el que se encuentran casi todos los -árboles de subsistema, actualizado casi a diario: - - https://git.kernel.org/?p=linux/kernel/git/next/linux-next.git - -De esta manera, linux-next ofrece una perspectiva resumida de lo que se -espera que entre en el kernel principal en el próximo período de "merge" -(fusión de código). Los testers aventureros son bienvenidos a probar -linux-next en ejecución. - -Reportar bugs -------------- - -El archivo 'Documentación/admin-guide/reporting-issues.rst' en el -directorio principal del kernel describe cómo informar un posible bug del -kernel y detalles sobre qué tipo de información necesitan los -desarrolladores del kernel para ayudar a rastrear la fuente del problema. - -Gestión de informes de bugs ------------------------------- - -Una de las mejores formas de poner en práctica sus habilidades de hacking -es arreglando errores reportados por otras personas. No solo ayudará a -hacer el kernel más estable, también aprenderá a solucionar problemas del -mundo real y mejora sus habilidades, y otros desarrolladores se darán -cuenta de tu presencia. La corrección de errores es una de las mejores -formas de ganar méritos entre desarrolladores, porque no a muchas personas -les gusta perder el tiempo arreglando los errores de otras personas. - -Para trabajar en informes de errores ya reportados, busque un subsistema -que le interese. Verifique el archivo MAINTAINERS donde se informan los -errores de ese subsistema; con frecuencia será una lista de correo, rara -vez un rastreador de errores (bugtracker). Busque en los archivos de dicho -lugar para informes recientes y ayude donde lo crea conveniente. También es -posible que desee revisar https://bugzilla.kernel.org para informes de -errores; solo un puñado de subsistemas del kernel lo emplean activamente -para informar o rastrear; sin embargo, todos los errores para todo el kernel -se archivan allí. - -Listas de correo ------------------ - -Como se explica en algunos de los documentos anteriores, la mayoría de -desarrolladores del kernel participan en la lista de correo del kernel de -Linux. Detalles sobre cómo para suscribirse y darse de baja de la lista se -pueden encontrar en: - - http://vger.kernel.org/vger-lists.html#linux-kernel - -Existen archivos de la lista de correo en la web en muchos lugares -distintos. Utilice un motor de búsqueda para encontrar estos archivos. Por -ejemplo: - - http://dir.gmane.org/gmane.linux.kernel - -Es muy recomendable que busque en los archivos sobre el tema que desea -tratar, antes de publicarlo en la lista. Un montón de cosas ya discutidas -en detalle solo se registran en los archivos de la lista de correo. - -La mayoría de los subsistemas individuales del kernel también tienen sus -propias lista de correo donde hacen sus esfuerzos de desarrollo. Revise el -archivo MAINTAINERS para obtener referencias de lo que estas listas para -los diferentes grupos. - -Muchas de las listas están alojadas en kernel.org. La información sobre -estas puede ser encontrada en: - - http://vger.kernel.org/vger-lists.html - -Recuerde mantener buenos hábitos de comportamiento al usar las listas. -Aunque un poco cursi, la siguiente URL tiene algunas pautas simples para -interactuar con la lista (o cualquier lista): - - http://www.albion.com/netiquette/ - -Si varias personas responden a su correo, el CC (lista de destinatarios) -puede hacerse bastante grande. No elimine a nadie de la lista CC: sin una -buena razón, o no responda solo a la dirección de la lista. Acostúmbrese -a recibir correos dos veces, una del remitente y otra de la lista, y no -intente ajustar esto agregando encabezados de correo astutos, a la gente no -le gustará. - -Recuerde mantener intacto el contexto y la atribución de sus respuestas, -mantenga las líneas "El hacker John Kernel escribió ...:" en la parte -superior de su respuesta, y agregue sus declaraciones entre las secciones -individuales citadas en lugar de escribiendo en la parte superior del -correo electrónico. - -Si incluye parches en su correo, asegúrese de que sean texto legible sin -formato como se indica en :ref:`Documentation/process/submitting-patches.rst `. -Los desarrolladores del kernel no quieren lidiar con archivos adjuntos o -parches comprimidos; y pueden querer comentar líneas individuales de su -parche, que funciona sólo de esa manera. Asegúrese de emplear un programa -de correo que no altere los espacios ni los tabuladores. Una buena primera -prueba es enviarse el correo a usted mismo, e intentar aplicar su -propio parche. Si eso no funciona, arregle su programa de correo o -reemplace hasta que funcione. - -Sobretodo, recuerde de ser respetuoso con otros subscriptores. - -Colaborando con la comunidad ----------------------------- - -El objetivo de la comunidad del kernel es proporcionar el mejor kernel -posible. Cuando envíe un parche para su aceptación, se revisará en sus -méritos técnicos solamente. Entonces, ¿qué deberías ser? - - - críticas - - comentarios - - peticiones de cambios - - peticiones de justificaciones - - silencio - -Recuerde, esto es parte de introducir su parche en el kernel. Tiene que ser -capaz de recibir críticas y comentarios sobre sus parches, evaluar -a nivel técnico y re-elaborar sus parches o proporcionar razonamiento claro -y conciso de por qué no se deben hacer tales cambios. Si no hay respuestas -a su publicación, espere unos días e intente de nuevo, a veces las cosas se -pierden dado el gran volumen. - -¿Qué no debería hacer? - - - esperar que su parche se acepte sin preguntas - - actuar de forma defensiva - - ignorar comentarios - - enviar el parche de nuevo, sin haber aplicados los cambios pertinentes - -En una comunidad que busca la mejor solución técnica posible, siempre habrá -diferentes opiniones sobre lo beneficioso que es un parche. Tiene que ser -cooperativo y estar dispuesto a adaptar su idea para que encaje dentro -del kernel, o al menos esté dispuesto a demostrar que su idea vale la pena. -Recuerde, estar equivocado es aceptable siempre y cuando estés dispuesto a -trabajar hacia una solución que sea correcta. - -Es normal que las respuestas a su primer parche sean simplemente una lista -de una docena de cosas que debe corregir. Esto **no** implica que su -parche no será aceptado, y **no** es personal. Simplemente corrija todos -los problemas planteados en su parche, y envié otra vez. - -Diferencias entre la comunidad kernel y las estructuras corporativas --------------------------------------------------------------------- - -La comunidad del kernel funciona de manera diferente a la mayoría de los -entornos de desarrollo tradicionales en empresas. Aquí hay una lista de -cosas que puede intentar hacer para evitar problemas: - - Cosas buenas que decir respecto a los cambios propuestos: - - - "Esto arregla múltiples problemas." - - "Esto elimina 2000 lineas de código." - - "Aquí hay un parche que explica lo que intento describir." - - "Lo he testeado en 5 arquitecturas distintas..." - - "Aquí hay una serie de parches menores que..." - - "Esto mejora el rendimiento en maquinas típicas..." - - Cosas negativas que debe evitar decir: - - - "Lo hicimos así en AIX/ptx/Solaris, de modo que debe ser bueno..." - - "Llevo haciendo esto 20 años, de modo que..." - - "Esto lo necesita mi empresa para ganar dinero" - - "Esto es para la linea de nuestros productos Enterprise" - - "Aquí esta el documento de 1000 paginas describiendo mi idea" - - "Llevo 6 meses trabajando en esto..." - - "Aquí esta un parche de 5000 lineas que..." - - "He rescrito todo el desastre actual, y aquí esta..." - - "Tengo un deadline, y este parche debe aplicarse ahora." - -Otra forma en que la comunidad del kernel es diferente a la mayoría de los -entornos de trabajo tradicionales en ingeniería de software, es la -naturaleza sin rostro de interacción. Una de las ventajas de utilizar el -correo electrónico y el IRC como formas principales de comunicación es la -no discriminación por motivos de género o raza. El entorno de trabajo del -kernel de Linux acepta a mujeres y minorías porque todo lo que eres es una -dirección de correo electrónico. El aspecto internacional también ayuda a -nivelar el campo de juego porque no puede adivinar el género basado en -el nombre de una persona. Un hombre puede llamarse Andrea y una mujer puede -llamarse Pat. La mayoría de las mujeres que han trabajado en el kernel de -Linux y han expresado una opinión han tenido experiencias positivas. - -La barrera del idioma puede causar problemas a algunas personas que no se -sientes cómodas con el inglés. Un buen dominio del idioma puede ser -necesario para transmitir ideas correctamente en las listas de correo, por -lo que le recomendamos que revise sus correos electrónicos para asegurarse -de que tengan sentido en inglés antes de enviarlos. - -Divida sus cambios ---------------------- - -La comunidad del kernel de Linux no acepta con gusto grandes fragmentos de -código, sobretodo a la vez. Los cambios deben introducirse correctamente, -discutidos y divididos en pequeñas porciones individuales. Esto es casi -exactamente lo contrario de lo que las empresas están acostumbradas a hacer. -Su propuesta también debe introducirse muy temprano en el proceso de -desarrollo, de modo que pueda recibir comentarios sobre lo que está -haciendo. También deje que la comunidad sienta que está trabajando con -ellos, y no simplemente usándolos como un vertedero para su función. Sin -embargo, no envíe 50 correos electrónicos a una vez a una lista de correo, -su serie de parches debe casi siempre ser más pequeña que eso. - -Las razones para dividir las cosas son las siguientes: - -1) Los cambios pequeños aumentan la probabilidad de que sus parches sean - aplicados, ya que no requieren mucho tiempo o esfuerzo para verificar su - exactitud. Un parche de 5 líneas puede ser aplicado por un maintainer - con apenas una segunda mirada. Sin embargo, un parche de 500 líneas - puede tardar horas en ser revisado en términos de corrección (el tiempo - que toma es exponencialmente proporcional al tamaño del parche, o algo - así). - - Los parches pequeños también facilitan la depuración cuando algo falla. - Es mucho más fácil retirar los parches uno por uno que diseccionar un - parche muy grande después de haber sido aplicado (y roto alguna cosa). - -2) Es importante no solo enviar pequeños parches, sino también reescribir - y simplificar (o simplemente reordenar) los parches antes de enviarlos. - -Esta es una analogía del desarrollador del kernel Al Viro (traducida): - - *"Piense en un maestro que califica la tarea de un estudiante de - matemáticas. El maestro no quiere ver los intentos y errores del - estudiante antes de que se les ocurriera la solución. Quiere ver la - respuesta más limpia y elegante. Un buen estudiante lo sabe, y nunca - presentaría su trabajo intermedio antes de tener la solución final.* - - *Lo mismo ocurre con el desarrollo del kernel. Los maintainers y - revisores no quieren ver el proceso de pensamiento detrás de la solución - al problema que se está resolviendo. Quieren ver un solución simple y - elegante."* - -Puede resultar un reto mantener el equilibrio entre presentar una solución -elegante y trabajar junto a la comunidad, discutiendo su trabajo inacabado. -Por lo tanto, es bueno comenzar temprano en el proceso para obtener -"feedback" y mejorar su trabajo, pero también mantenga sus cambios en -pequeños trozos que pueden ser aceptados, incluso cuando toda su labor no -está listo para inclusión en un momento dado. - -También tenga en cuenta que no es aceptable enviar parches para su -inclusión que están sin terminar y serán "arreglados más tarde". - -Justifique sus cambios ----------------------- - -Además de dividir sus parches, es muy importante que deje a la comunidad de -Linux sabe por qué deberían agregar este cambio. Nuevas características -debe justificarse como necesarias y útiles. - -Documente sus cambios ---------------------- - -Cuando envíe sus parches, preste especial atención a lo que dice en el -texto de su correo electrónico. Esta información se convertirá en el -ChangeLog del parche, y se conservará para que todos la vean, todo el -tiempo. Debe describir el parche por completo y contener: - - - por qué los cambios son necesarios - - el diseño general de su propuesta - - detalles de implementación - - resultados de sus experimentos - -Para obtener más detalles sobre cómo debería quedar todo esto, consulte la -sección ChangeLog del documento: - - "The Perfect Patch" - https://www.ozlabs.org/~akpm/stuff/tpp.txt - -Todas estas cuestiones son a veces son muy difíciles de conseguir. Puede -llevar años perfeccionar estas prácticas (si es que lo hace). Es un proceso -continuo de mejora que requiere mucha paciencia y determinación. Pero no se -rinda, es posible. Muchos lo han hecho antes, y cada uno tuvo que comenzar -exactamente donde está usted ahora. - ----------- - -Gracias a Paolo Ciarrocchi que permitió que la sección "Development Process" -se basara en el texto que había escrito (https://lwn.net/Articles/94386/), -y a Randy Dunlap y Gerrit Huizenga por algunas de la lista de cosas que -debes y no debes decir. También gracias a Pat Mochel, Hanna Linder, Randy -Dunlap, Kay Sievers, Vojtech Pavlik, Jan Kara, Josh Boyer, Kees Cook, -Andrew Morton, Andi Kleen, Vadim Lobanov, Jesper Juhl, Adrian Bunk, -Keri Harris, Frans Pop, David A. Wheeler, Junio Hamano, Michael Kerrisk y -Alex Shepard por su revisión, comentarios y contribuciones. Sin su ayuda, -este documento no hubiera sido posible. - -Maintainer: Greg Kroah-Hartman diff --git a/Documentation/translations/sp_SP/index.rst b/Documentation/translations/sp_SP/index.rst index 5c2a2131524b88..c543b495c04237 100644 --- a/Documentation/translations/sp_SP/index.rst +++ b/Documentation/translations/sp_SP/index.rst @@ -76,6 +76,5 @@ Traducciones al español .. toctree:: :maxdepth: 1 - howto process/index wrappers/memory-barriers diff --git a/Documentation/translations/sp_SP/process/handling-regressions.rst b/Documentation/translations/sp_SP/process/handling-regressions.rst new file mode 100644 index 00000000000000..aa0988985c55e2 --- /dev/null +++ b/Documentation/translations/sp_SP/process/handling-regressions.rst @@ -0,0 +1,797 @@ +.. include:: ../disclaimer-sp.rst + +:Translator: Sergio González Collado + +.. _sp_handling_regressions: + +Gestión de regresiones +++++++++++++++++++++++ + +*No causamos regresiones* -- este documento describe la que es la "primera +regla del desarrollo del kernel de Linux" y que implica en la práctica para +los desarrolladores. Y complementa la documentación: +Documentation/admin-guide/reporting-regressions.rst, que cubre el tema +desde el punto de vista de un usuario; si nunca ha leído ese texto, realice +al menos una lectura rápida del mismo antes de continuar. + +Las partes importantes (el "TL;DR") +=================================== + +#. Asegúrese de que los suscriptores a la lista `regression mailing list + `_ (regressions@lists.linux.dev) + son conocedores con rapidez de cualquier nuevo informe de regresión: + + * Cuando se reciba un correo que no incluyó a la lista, inclúyalo en la + conversación de los correos, mandando un breve "Reply-all" con la + lista en CCed. + + * Mande o redirija cualquier informe originado en los gestores de bugs + a la lista. + +#. Haga que el bot del kernel de Linux "regzbot" realice el seguimiento del + incidente (esto es opcional, pero recomendado). + + * Para reportes enviados por correo, verificar si contiene alguna línea + como ``#regzbot introduced v5.13..v5.14-rc1``. Si no, mandar una + respuesta (con la lista de regresiones en CC) que contenga un párrafo + como el siguiente, lo que le indica a regzbot cuando empezó a suceder + el incidente:: + + #regzbot ^introduced 1f2e3d4c5b6a + + * Cuando se mandan informes desde un gestor de incidentes a la lista de + regresiones(ver más arriba), incluir un párrafo como el siguiente:: + + #regzbot introduced: v5.13..v5.14-rc1 + #regzbot from: Some N. Ice Human + #regzbot monitor: http://some.bugtracker.example.com/ticket?id=123456789 + +#. Cuando se manden correcciones para las regresiones, añadir etiquetas + "Link:" a la descripción, apuntado a todos los sitios donde se informó + del incidente, como se indica en el documento: + Documentation/process/submitting-patches.rst y + :ref:`Documentation/process/5.Posting.rst `. + +#. Intente arreglar las regresiones rápidamente una vez la causa haya sido + identificada; las correcciones para la mayor parte de las regresiones + deberían ser integradas en menos de dos semanas, pero algunas pueden + resolverse en dos o tres días. + +Detalles importantes para desarrolladores en la regresiones de kernel de Linux +============================================================================== + +Puntos básicos importantes más en detalle +----------------------------------------- + +Qué hacer cuando se recibe un aviso de regresión. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Asegúrese de que el programa de gestión de regresiones del kernel de Linux +y los subscritos a la lista de correo `regression mailing list +`_ (regressions@lists.linux.dev) son +conocedores de cualquier nuevo informe de regresión: + + * Cuando se recibe un informe por email que no tiene en CC la lista, + inmediatamente meterla en el la cadena de emails mandado al menos un + breve "Reply-all" con la lista en CC; Intentar asegurar que la lista es + añadida en CC de nuevo en caso de que alguna respuesta la omita de la + lista. + + * Si un informe enviado a un gestor de defectos, llega a su correo, + reenvíelo o redirijalo a la lista. Considere verificar los archivos de + la lista de antemano, si la persona que lo ha informado, lo ha enviado + anteriormente, como se indica en: + Documentation/admin-guide/reporting-issues.rst. + +Cuando se realice cualquiera de las acciones anteriores, considere +inmediatamente iniciar el seguimiento de la regresión con "regzbot" el +gestor de regresiones del kernel de Linux. + + * Para los informes enviados por email, verificar si se ha incluido un + comando a "regzbot", como ``#regzbot introduced 1f2e3d4c5b6a``. Si no es + así, envíe una respuesta (con la lista de regresiones en CC) con un + párrafo como el siguiente:: + + #regzbot ^introduced: v5.13..v5.14-rc1 + + Esto indica a regzbot el rango de versiones en el cual es defecto + comenzó a suceder; Puede especificar un rango usando los identificadores + de los commits así como un único commit, en caso en el que el informante + haya identificado el commit causante con 'bisect'. + + Tenga en cuenta que el acento circunflejo (^) antes de "introduced": + Esto indica a regzbot, que debe tratar el email padre (el que ha sido + respondido) como el informeinicial para la regresión que quiere ser + seguida. Esto es importante, ya que regzbot buscará más tarde parches + con etiquetas "Link:" que apunten al al informe de losarchivos de + lore.kernel.org. + + * Cuando mande informes de regresiones a un gestor de defectos, incluya un + párrafo con los siguientes comandos a regzbot:: + + #regzbot introduced: 1f2e3d4c5b6a + #regzbot from: Some N. Ice Human + #regzbot monitor: http://some.bugtracker.example.com/ticket?id=123456789 + + Regzbot asociará automáticamente parches con el informe que contengan + las etiquetas "Link:" apuntando a su email o el ticket indicado. + +Qué es importante cuando se corrigen regresiones +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +No se necesita hacer nada especial cuando se mandan las correcciones para +las regresiones únicamente recordar lo que se explica en los documentos: +Documentation/process/submitting-patches.rst, +:ref:`Documentation/process/5.Posting.rst `, y +Documentation/process/stable-kernel-rules.rst + + * Apunte a todos los lugares donde el incidente se reportó usando la + etiqueta "Link:" :: + + Link: https://lore.kernel.org/r/30th.anniversary.repost@klaava.Helsinki.FI/ + Link: https://bugzilla.kernel.org/show_bug.cgi?id=1234567890 + + * Añada la etiqueta "Fixes:" para indicar el commit causante de la + regresión. + + * Si el culpable ha sido "mergeado" en un ciclo de desarrollo anterior, + marque explícitamente el fix para retro-importarlo usando la etiqueta + ``Cc: stable@vger.kernel.org`` tag. + +Todo esto se espera y es importante en una regresión, ya que estas +etiquetas son de gran valor para todos (incluido usted) que pueda estar +mirando en ese incidente semanas, meses o años después. Estas etiquetas son +también cruciales para las herramientas y scripts usados por otros +desarrolladores del kernel o distribuciones de Linux; una de esas +herramientas es regzbot, el cual depende mucho de las etiquetas "Link:" +para asociar los informes por regresiones con los cambios que las +resuelven. + + +Priorización del trabajo en arreglar regresiones +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Al final, los desarrolladores deberían hacer lo posible para evitar a los +usuarios situaciones donde una regresión les deje solo tres opciones: + + * Ejecutar el kernel con una regresión que afecta seriamente al uso. + + * Cambiar a un kernel nuevo o mas antiguo -- rebajarse a una versión + soportada del kernel que no tenga las funcionalidades requeridas. + + * Continuar ejecutando una versión desfasada y potencialmente insegura del + kernel por más de dos semanas después de que el causante de una regresión + fuese identificado. + +Cómo se ejecuta esto depende mucho de la situación. A continuación se +presentan unas reglas generales, en orden de importancia: + + * Priorice el trabajo en la gestión de los informes de la regresión y + arreglar la regresión por encima de cualquier otro trabajo en el kernel + de Linux, a menos que lo último afecte profundamente a efectos de + seguridad, o cause errores en los que haya pérdida o daño de datos. + + * Considere siempre revertir los commits responsables y re-aplicarlos + después, junto con las correcciones necesarias, ya que esto puede la + forma menos peligrosa y más rápida de arreglar la regresión. + + * Los desarrolladores deberían gestionar la regresión en todos los kernels + soportados de la serie, pero son libres de delegar el trabajo al equipo + permanente el incidente no hubiese ocurrido en la línea principal. + + * Intente resolver cualquier regresión que apareciera en el ciclo de + desarrollo antes de que este acabe. Si se teme que una corrección + pudiera ser demasiado arriesgada para aplicarla días antes de una + liberación de la línea principal de desarrollo, dejar decidir a Linus: + mande la corrección a él de forma separada, tan pronto como sea posible + con una explicación de la situación. El podrá decidir, y posponer la + liberación si fuese necesario, por ejemplo si aparecieran múltiples + cambios como ese. + + * Gestione las regresiones en la rama estable, de largo término, o la + propia rama principal de las versiones, con más urgencia que la + regresiones en las preliberaciones. Esto cambia después de la liberación + de la quinta pre-liberación, aka "-rc5": la rama principal entonces se + vuelve más importante, asegurar que todas las mejoras y correcciones son + idealmente testeados juntos por al menos una semana antes de que Linux + libere la nueva versión en la rama principal. + + * Intente arreglar regresiones en un intervalo de una semana después de + que se ha identificado el responsable, si el incidente fue introducido + en alguno de los siguientes casos: + + * una versión estable/largo-plazo reciente + + * en el último ciclo de desarrollo de la rama principal + + En el último caso (por ejemplo v5.14), intentar gestionar las + regresiones incluso más rápido, si la versión estable precedente (v5.13) + ha de ser abandonada pronto o ya se ha etiquetado como de final de vida + (EOL de las siglas en inglés End-of-Life) -- esto sucede usualmente + sobre tres o cuatro semanas después de una liberación de una versión en + la rama principal. + + * Intente arreglar cualquier otra regresión en un periodo de dos semanas + después de que el culpable haya sido identificado. Dos o tres semanas + adicionales son aceptables para regresiones de rendimiento y otros + incidentes que son molestos, pero no bloquean a nadie la ejecución de + Linux (a menos que se un incidente en el ciclo de desarrollo actual, en + ese caso se debería gestionar antes de la liberación de la versión). + Unas semanas son aceptables si la regresión únicamente puede ser + arreglada con un cambio arriesgado y al mismo tiempo únicamente afecta a + unos pocos usuarios; también está bien si se usa tanto tiempo como fuera + necesario si la regresión está presente en la segunda versión más nueva + de largo plazo del kernel. + +Nota: Los intervalos de tiempo mencionados anteriormente para la resolución +de las regresiones, incluyen la verificación de esta, revisión e inclusión +en la rama principal, idealmente con la corrección incluida en la rama +"linux-next" al menos brevemente. Esto conllevará retrasos que también se +tienen tener en cuenta. + +Se espera que los maintainers de los subsistemas, ayuden en conseguir esos +tiempos, haciendo revisiones con prontitud y gestionando con rapidez los +parches aceptados. Esto puede resultar en tener que mandar peticiones de +git-pull antes o de forma más frecuente que lo normal; dependiendo del +arreglo, podría incluso ser aceptable saltarse la verificación en +linux-next. Especialmente para las correcciones en las ramas de los kernels +estable y de largo plazo necesitan ser gestionadas rápidamente, y las +correcciones necesitan ser incluidas en la rama principal antes de que +puedan ser incluidas posteriormente a las series precedentes. + + +Más aspectos sobre regresiones que los desarrolladores deben saber +------------------------------------------------------------------ + +Cómo tratar con cambios donde se sabe que hay riesgo de regresión +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Evalué cómo de grande es el riesgo de una regresión, por ejemplo realizando +una búsqueda en las distribuciones de linux y en Git forges. Considere +también preguntar a otros desarrolladores o proyectos que pudieran ser +afectados para evaluar o incluso testear el cambio propuesto; si +apareciesen problemas, quizás se pudiera encontrar una solución aceptable +para todos. + +Si al final, el riesgo de la regresión parece ser relativamente pequeño, +entonces adelante con el cambio, pero siempre informe a todas las partes +involucradas del posible riesgo. Por tanto, asegúrese de que la descripción +del parche, se hace explícito este hecho. Una vez el cambio ha sido +integrado, informe al gestor de regresiones de Linux y a las listas de +correo de regresiones sobre el riesgo, de manera que cualquiera que tenga +el cambio en el radar, en el caso de que aparezcan reportes. Dependiendo +del riesgo, quizás se quiera preguntar al mantenedor del subsistema, que +mencione el hecho en su línea principal de desarrollo. + +¿Qué más hay que saber sobre regresiones? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Repase la documentación: Documentation/admin-guide/reporting-regressions.rst, +esta cubre otros aspectos a tener a en cuenta y conocer: + + * la finalidad de la "regla de no regresión" + + * qué incidencias no se califican como regresión + + * quién es el responsable de identificar la causa raíz de una regresión + + * cómo gestionar situaciones difíciles, como por ejemplo cuando una + regresión es causada por una corrección de seguridad o cuando una + regresión causa otra regresión + +A quién preguntar por consejo cuando se trata de regresiones +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Mande un email a la lista de correo de regresiones +(regressions@lists.linux.dev) y CC al seguidor de regresiones del kernel de +Linux (regressions@leemhuis.info); Si el incidente pudiera ser mejor +gestionarlo en privado, puede omitirse la lista. + + +Más sobre la gestión de regresiones con regzbot +----------------------------------------------- + +¿Por qué el kernel de Linux tiene un gestor de regresiones, y por qué se usa regzbot? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Reglas como "no regresiones" necesitan asegurar que se cumplen, de otro +modo se romperían accidentalmente o a propósito. La historia ha mostrado +que esto es verdad también para el kernel de Linux. Esto es por lo que +Thorsten Leemhuis se ofreció como voluntario para dar una solución a esto, +con el gestor de regresiones del kernel de Linux. A nadie se le paga por +hacer esto, y esa es la razón por la gestión de regresiones es un servicio +con el "mejor esfuerzo". + +Intentos iniciales de gestionar manualmente las regresiones han demostrado +que es una tarea extenuante y frustrante, y por esa razón se dejaron de +hacer después de un tiempo. Para evitar que volviese a suceder esto, +Thorsten desarrollo regbot para facilitar el trabajo, con el objetivo a +largo plazo de automatizar la gestión de regresiones tanto como fuese +posible para cualquiera que estuviese involucrado. + +¿Cómo funciona el seguimiento de regresiones con regzbot? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +El bot monitoriza las respuestas de los informes de las regresiones +identificadas. Adicionalmente mira si se han publicado o enviado parches +que hagan referencia a esos informes con la etiqueta: "Link:"; respuestas a +esos parches también se siguen. Combinando esta información, también +proporciona una buena imagen del estado actual del proceso de corrección. + +Regzbot intenta hacer todo este trabajo con tan poco retraso como sea +posible tanto para la gente que lo reporta, como para los desarrolladores. +De hecho, solo los informantes son requeridos para una tarea adicional: +necesitan informar a regzbot con el comando ``#regzbot introduced`` +indicado anteriormente; si no hacen esto, alguien más puede hacerlo usando +``#regzbot ^introduced``. + +Para los desarrolladores normalmente no hay un trabajo adicional que +realizar, únicamente necesitan asegurarse una cosa, que ya se hacía mucho +antes de que regzbot apareciera: añadir las etiquetas "Link:" a la +descripción del parche apuntando a todos los informes sobre el error +corregido. + +¿Tengo que usar regzbot? +~~~~~~~~~~~~~~~~~~~~~~~~ + +Hacerlo es por el bien de todo el mundo, tanto los mantenedores del kernel, +como Linus Torvalds dependen parcialmente en regzbot para seguir su trabajo +-- por ejemplo cuando deciden liberar una nueva versión o ampliar la fase de +desarrollo. Para esto necesitan conocer todas las regresiones que están sin +corregir; para esto, es conocido que Linux mira los informes semanales que +manda regzbot. + +¿He de informar a regzbot cada regresión que encuentre? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Idealmente, sí: todos somos humanos y olvidamos fácilmente los problemas +cuando algo más importante aparece inesperadamente -- por ejemplo un +problema mayor en el kernel de Linux o algo en la vida real que nos mantenga +alejados de los teclados por un tiempo. Por eso es mejor informar a regzbot +sobre cada regresión, excepto cuando inmediatamente escribimos un parche y +los mandamos al árbol de desarrollo en el que se integran habitualmente a +la serie del kernel. + +¿Cómo ver qué regresiones esta siguiendo regbot actualmente? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Verifique el `interfaz web de regzbot `_ +para ver la última información; o `busque el último informe de regresiones +`_, +el cual suele ser enviado por regzbot una vez a la semana el domingo por la +noche (UTC), lo cual es unas horas antes de que Linus normalmente anuncie +las "(pre-)releases". + +¿Qué sitios supervisa regzbot? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Regzbot supervisa las listas de correo más importantes de Linux, como +también las de los repositorios linux-next, mainline y stable/longterm. + + +¿Qué tipos de incidentes han de ser monitorizados por regzbot? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +El bot debe hacer seguimiento de las regresiones, y por tanto por favor, +no involucre a regzbot para incidencias normales. Pero es correcto para +el gestor de incidencias de kernel de Linux, monitorizar incidentes +graves, como informes sobre cuelgues, corrupción de datos o errores +internos (Panic, Oops, BUG(), warning, ...). + + +¿Puedo añadir una regresión detectada por un sistema de CI al seguimiento de regzbot? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Siéntase libre de hacerlo, si la regresión en concreto puede tener un +impacto en casos de uso prácticos y por tanto ser detectado por los usuarios; +Así, por favor no involucre a regzbot en regresiones teóricas que +difícilmente pudieran manifestarse en un uso real. + +¿Cómo interactuar con regzbot? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Usando el comando 'regzbot' en una respuesta directa o indirecta al correo +con el informe de regresión. Ese comando necesita estar en su propio +párrafo (debe estar separado del resto del texto usando líneas en blanco): + +Por ejemplo ``#regzbot introduced ``, que hace que regzbot +considere el correo como un informe de regressión que se ha de añadir al +seguimiento, como se ha descrito anteriormente; ``#regzbot ^introduced `` +es otro ejemplo del comando, el cual indica a regzbot que considere el email +anterior como el informe de una regresión que se ha de comenzar a monitorizar. + +Una vez uno de esos dos comandos se ha utilizado, se pueden usar otros +comandos regzbot en respuestas directas o indirectas al informe. Puede +escribirlos debajo de uno de los comandos anteriormente usados o en las +respuestas al correo en el que se uso como respuesta a ese correo: + + * Definir o actualizar el título:: + + #regzbot title: foo + + * Monitorizar una discusión o un tiquet de bugzilla.kernel.org donde + aspectos adicionales del incidente o de la corrección se están + comentando -- por ejemplo presentar un parche que corrige la regresión:: + + #regzbot monitor: https://lore.kernel.org/all/30th.anniversary.repost@klaava.Helsinki.FI/ + + Monitorizar solamente funciona para lore.kernel.org y bugzilla.kernel.org; + regzbot considerará todos los mensajes en ese hilo o el tiquet como + relacionados al proceso de corrección. + + * Indicar a un lugar donde más detalles de interés, como un mensaje en una + lista de correo o un tiquet en un gestor de incidencias que pueden estar + levemente relacionados, pero con un tema diferente:: + + #regzbot link: https://bugzilla.kernel.org/show_bug.cgi?id=123456789 + + * Identificar una regresión como corregida por un commit que se ha mandado + aguas arriba o se ha publicado:: + + #regzbot fixed-by: 1f2e3d4c5d + + + * Identificar una regresión como un duplicado de otra que ya es seguida + por regzbot:: + + #regzbot dup-of: https://lore.kernel.org/all/30th.anniversary.repost@klaava.Helsinki.FI/ + + * Identificar una regresión como inválida:: + + #regzbot invalid: wasn't a regression, problem has always existed + + +¿Algo más que decir sobre regzbot y sus comandos? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Hay información más detallada y actualizada sobre el bot de seguimiento de +regresiones del kernel de Linux en: `project page `_, +y entre otros contiene una `guia de inicio `_ +y `documentación de referencia `_ +Ambos contienen más detalles que las secciones anteriores. + + +Citas de Linus sobre regresiones +-------------------------------- + +A continuación se encuentran unos ejemplos reales (traducidos) de como +Linus Torvalds espera que se gestionen las regresiones: + + + * De 2017-10-26 (1/2) + `_:: + + Si rompes la configuración de los espacios de usuario ESO ES UNA REGRESIÓN. + + No está bien decir "pero nosotros arreglaremos la configuración del espacio + de usuario". + + Realmente. NO ESTÁ BIEN. + + [...] + + La primera regla es: + + - no causamos regresiones + + y el corolario es que cuando una regresión pasa, lo admitimos y lo + arreglamos, en vez de echar la culpa al espacio de usuario. + + El hecho de que aparentemente se haya negado la regresión durante + tres semanas, significa que lo revertiré y dejaré de integrar peticiones + de apparmor hasta que la gente involucrada entienda como se hace + el desarrollo del kernel. + + + * De `2017-10-26 (2/2) + `_:: + + La gente debería sentirse libre de actualizar su kernel y simplemente + no preocuparse por ello. + + Me niego a imponer una limitación del tipo "solo puede actualizar + el kernel si actualiza otro programa". Si el kernel trabaja para tí, + la regla es que continúe trabajando para tí. + + Ha habido algunas excepciones, pero son pocas y separadas entre sí, y + generalmente tienen una razón fundamental para haber sucedido, que era + básicamente inevitable, y la gente intentó evitarlas por todos los + medios. Quizás no podamos mantener el hardware más, después de que han + pasado décadas y nadie los usacon kernel modernos. Quizás haya un + problema de seguridad serio con cómo hicimos las cosas, y la gente + depende de un modelo fundamentalmente roto. Quizás haya algún otro roto + fundamental, que tenga que tener una _flag_ y por razones internas y + fundamentales. + + Y nótese que esto trata sobre *romper* los entornos de la gente. + + Cambios de comportamiento pasan, y quizás no se mantengan algunas + funcionalidades más. Hay un número de campos en /proc//stat que + se imprimen como ceros, simplemente porque ni siquiera existen ya en + kernel, o porque mostrarlos era un error (típica una fuga de + información). Pero los números se sustituyeron por ceros, así que + el código que se usaba para parsear esos campos todavía existe. El + usuario puede no ver todo lo que podía ver antes, y por eso el + omportamiento es claramente diferente, pero las cosas todavía + _funcionan_, incluso si no se puede mostrar información sensible + (o que no es ya importante). + + Pero si algo realmente se rompe, entonces el cambio debe de arreglarse + o revertirse. Y se arregla en el *kernel*. No diciendo "bueno, arreglaremos + tu espacio de usuario". Ha sido un cambio en el kernel el que creo + el problema, entonces ha de ser el kernel el que lo corrija, porque + tenemos un modelo de "actualización". Pero no tenemos una "actualización + con el nuevo espacio de usuario". + + Y yo seriamente me negaré a coger código de gente que no entiende y + honre esta sencilla regla. + + Y esta regla no va a cambiar. + + Y sí, me doy cuenta que el kernel es "especial" en este respecto. Y + estoy orgulloso de ello. + + Y he visto, y puedo señalar, muchos proyectos que dicen "Tenemos que + romper ese caso de uso para poder hacer progresos" o "estabas basandote + en comportamientos no documentados, debe ser duro ser tú" o "hay una + forma mejor de hacer lo que quieres hacer, y tienes que cambiar a esa + nueva forma", y yo simplemente no pienso que eso sea aceptable fuera + de una fase alfa muy temprana que tenga usuarios experimentales que + saben a lo que se han apuntado. El kernel no ha estado en esta + situación en las dos últimas décadas. + + Nosotros rompemos la API _dentro_ del kernel todo el tiempo. Y + arreglaremos los problemas internos diciendo "tú ahora necesitas + hacer XYZ", pero entonces es sobre la API interna del kernel y la + gente que hace esto entonces tendrá obviamente que arreglar todos + los usos de esa API del kernel. Nadie puede decir "ahora, yo he roto + la API que usas, y ahora tú necesitas arreglarlo". Quién rompa algo, + lo arregla también. + + Y nosotros, simplemente, no rompemos el espacio de usuario. + + * De `2020-05-21 + `_:: + + Las reglas sobre regresiones nunca han sido sobre ningún tipo de + comportamiento documentado, o dónde está situado el código. + + Las reglas sobre regresiones son siempre sobre "roturas en el + flujo de trabajo del usuario". + + Los usuarios son literalmente la _única_ cosa que importa. + + Argumentaciones como "no debería haber usado esto" o "ese + comportamiento es indefinido, es su culpa que su aplicación no + funcione" o "eso solía funcionar únicamente por un bug del kernel" son + irrelevantes. + + Ahora, la realidad nunca es blanca o negra. Así hemos tenido situaciones + como "un serio incidente de seguridad" etc que solamente nos fuerza + a hacer cambios que pueden romper el espacio de usuario. Pero incluso + entonces la regla es que realmente no hay otras opciones para que + las cosas sigan funcionando. + + Y obviamente, si los usuarios tardan años en darse cuenta que algo + se ha roto, o si hay formas adecuadas para sortear la rotura que + no causen muchos problemas para los usuarios (por ejemplo: "hay un + puñado de usuarios, y estos pueden usar la línea de comandos del + kernel para evitarlos"; ese tipo de casos), en esos casos se ha sido + un poco menos estricto. + + Pero no, "eso que está documentado que está roto" (si es dado a que + el código estaba en preparación o porque el manual dice otra cosa) eso + es irrelevante. Si preparar el código es tan útil que la gente, + acaba usando, esto implica que básicamente es código del kernel con + una señal diciendo "por favor limpiar esto". + + El otro lado de la moneda es que la gente que habla sobre "estabilidad + de las APIs" están totalmente equivocados. Las APIs tampoco importan. + Se puede hacer cualquier cambio que se quiera a una API ... siempre y + cuando nadie se de cuenta. + + De nuevo, la regla de las regresiones no trata sobre la documentación, + tampoco sobre las APIs y tampoco sobre las fases de la Luna. + + Únicamente trata sobre "hemos causado problemas al espacio de usuario que + antes funcionaba". + + * De `2017-11-05 + `_:: + + Y nuestra regla sobre las regresiones nunca ha sido "el comportamiento + no cambia". Eso podría significar que nunca podríamos hacer ningún + cambio. + + Por ejemplo, hacemos cosas como añadir una nueva gestión de + errores etc todo el tiempo, con lo cual a veces incluso añadimos + tests en el directorio de kselftest. + + Así que claramente cambia el comportamiento todo el tiempo y + nosotros no consideramos eso una regresión per se. + + La regla para regresiones para el kernel es para cuando se + rompe algo en el espacio de usuario. No en algún test. No en + "mira, antes podía hacer X, y ahora no puedo". + + * De `2018-08-03 + `_:: + + ESTÁS OLVIDANDO LA REGLA #1 DEL KERNEL. + + No hacemos regresiones, y no hacemos regresiones porque estás 100% + equivocado. + + Y la razón que apuntas en tú opinión es exactamente *PORQUÉ* estás + equivocado. + + Tus "buenas razones" son honradas y pura basura. + + El punto de "no hacemos regresiones" es para que la gente pueda + actualizar el kernel y nunca tengan que preocuparse por ello. + + > El kernel tiene un bug que ha de ser arreglado + + Eso es *TOTALMENTE* insustancial. + + Chicos, si algo estaba roto o no, NO IMPORTA. + + ¿Porqué? + + Los errores pasan. Eso es un hecho de la vida. Discutir que + "tenemos que romper algo porque estábamos arreglando un error" es + una locura. Arreglamos decenas de errores cada dia, pensando que + "arreglando un bug" significa que podemos romper otra cosa es algo + que simplemente NO ES VERDAD. + + Así que los bugs no son realmente relevantes para la discusión. Estos + suceden y se detectan, se arreglan, y no tienen nada que ver con + "rompemos a los usuarios". + + Porque la única cosa que importa ES EL USUARIO. + + ¿Cómo de complicado es eso de comprender? + + Cualquier persona que use "pero no funcionaba correctamente" es + un argumento no tiene la razón. Con respecto al USUARIO, no era + erróneo - funcionaba para él/ella. + + Quizás funcionaba *porque* el usuario había tenido el bug en cuenta, + y quizás funcionaba porque el usuario no lo había notado - de nuevo + no importa. Funcionaba para el usuario. + + Romper el flujo del trabajo de un usuario, debido a un "bug" es la + PEOR razón que se pueda usar. + + Es básicamente decir "He cogido algo que funcionaba, y lo he roto, + pero ahora es mejor". ¿No ves que un argumento como este es j*didamente + absurdo? + + y sin usuarios, tu programa no es un programa, es una pieza de + código sin finalidad que puedes perfectamente tirar a la basura. + + Seriamente. Esto es *porque* la regla #1 para el desarrollo del + kernel es "no rompemos el espacio de usuario". Porque "He arreglado + un error" PARA NADA ES UN ARGUMENTO si esa corrección del código + rompe el espacio de usuario. + + si actualizamos el kernel TODO EL TIEMPO, sin actualizar ningún otro + programa en absoluto. Y esto es absolutamente necesario, porque + las dependencias son terribles. + + Y esto es necesario simplemente porque yo como desarrollador del + kernel no actualizo al azar otras herramientas que ni siquiera me + importan como desarrollador del kernel, y yo quiero que mis usuarios + se sientan a salvo haciendo lo mismo. + + Así que no. Tu regla está COMPLETAMENTE equivocada. Si no puedes + actualizar el kernel sin actualizar otro binario al azar, entonces + tenemos un problema. + + * De `2021-06-05 + `_:: + + NO HAY ARGUMENTOS VÁLIDOS PARA UNA REGRESIÓN. + + Honestamente, la gente de seguridad necesita entender que "no funciona" + no es un caso de éxito sobre seguridad. Es un caso de fallo. + + Sí, "no funciona" puede ser seguro. Pero en este caso es totalmente + inutil. + + * De `2011-05-06 (1/3) + `_:: + + La compatibilidad de los binarios es más importante. + + Y si los binarios no usan el interfaz para parsear el formato + (o justamente lo parsea incorrectamente - como el reciente ejemplo + de añadir uuid al /proc/self/mountinfo), entonces es una regresión. + + Y las regresiones se revierten, a menos que haya problemas de + seguridad o similares que nos hagan decir "Dios mío, realmente + tenemos que romper las cosas". + + No entiendo porqué esta simple lógica es tan difícil para algunos + desarrolladores del kernel. La realidad importa. Sus deseos personales + NO IMPORTAN NADA. + + Si se crea un interface que puede usarse sin parsear la + descripción del interface, entonces estaḿos atascados en el interface. + La teoría simplemente no importa. + + Podrias alludar a arreglar las herramientas, e intentar evitar los + errores de compatibilidad de ese modo. No hay tampoco tantos de esos. + + De `2011-05-06 (2/3) + `_:: + + Esto claramente NO es un tracepoint interno. Por definición. Y está + siendo usado por powertop. + + De `2011-05-06 (3/3) + `_:: + + Tenemos programas que usan esa ABI y si eso se rompe eso es una + regresión. + + * De `2012-07-06 `_:: + + > Ahora esto me ha dejado preguntandome si Debian _inestable_ + realmente califica + > como espacio de usuario estándar. + + Oh, si el kernel rompe algún espacio de usuario estándar, eso cuenta. + Muchísima gente usa Debian inestable. + + * De `2019-09-15 + `_:: + + Una reversión _en particular_ en el último minuto en el último commit + (no teniendo en cuenta el propio cambio de versión) justo antes + de la liberación, y aunque es bastante incómodo, quizás también es + instructivo. + + Lo que es instructivo sobre esto es que he revertido un commit que no + tenía ningún error. De hecho, hacía exactamente lo que pretendía, y lo + hacía muy bien. De hecho lo hacía _tan_ bien que los muy mejorados + patrones de IO que causaba han acabado revelando una regresión observable + desde el espacio de usuario, debido a un error real en un componente + no relacionado en absoluto. + + De todas maneras, los detalles actuales de esta regresión no son la + razón por la que señalo esto como instructivo. Es más que es un ejemplo + ilustrativo sobre lo que cuenta como una regresión, y lo que conlleva + la regla del kernel de "no regresiones". El commit que ha sido revertido + no cambiaba ninguna API, y no introducía ningún error nuevo en el código. + Pero acabó exponiendo otro problema, y como eso causaba que la + actualización del kernel fallara para el usuario. Así que ha sido + revertido. + + El foco aquí, es que hemos hecho la reversión basándonos en el + comportamiento reportado en el espacio de usuario, no basado en + conceptos como "cambios de ABI" o "provocaba un error". Los mejores + patrones de IO que se han presentado debido al cambio únicamente han + expuesto un viejo error, y la gente ya dependía del benigno + comportamiento de ese viejo error. + + Y que no haya miedo, reintroduciremos el arreglo que mejoraba los + patrones de IO una vez hayamos decidido cómo gestionar el hecho de + que hay una interacción incorrecta con un interfaz en el que la + gente dependía de ese comportamiento previo. Es únicamente que + tenemos que ver cómo gestionamos y cómo lo hacemos (no hay menos de + tres parches diferentes de tres desarrolladores distintos que estamos + evaluando, ... puede haber más por llegar). Mientras tanto, he + revertido lo que exponía el problema a los usuarios de esta release, + incluso cuando espero que el fix será reintroducido (quizás insertado + a posteriormente como un parche estable) una vez lleguemos a un + acuerdo sobre cómo se ha de exponer el error. + + Lo que hay que recordar de todo el asunto no es sobre si el cambio + de kernel-espacio-de-usuario ABI, o la corrección de un error, o si + el código antiguo "en primer lugar nunca debería haber estado ahí". + Es sobre si algo rompe el actual flujo de trabajo del usuario. + + De todas formas, esto era mi pequeña aclaración en todo este + tema de la regresión. Ya que es la "primera regla de la programación + del kernel", me ha parecido que quizás es bueno mencionarlo de + vez en cuando. diff --git a/Documentation/translations/sp_SP/process/howto.rst b/Documentation/translations/sp_SP/process/howto.rst new file mode 100644 index 00000000000000..dd793c0f8574fe --- /dev/null +++ b/Documentation/translations/sp_SP/process/howto.rst @@ -0,0 +1,617 @@ +.. include:: ../disclaimer-sp.rst + +:Original: :ref:`Documentation/process/howto.rst ` +:Translator: Carlos Bilbao + +.. _sp_process_howto: + +Cómo participar en el desarrollo del kernel de Linux +==================================================== + +Este documento es el principal punto de partida. Contiene instrucciones +sobre cómo convertirse en desarrollador del kernel de Linux y explica cómo +trabajar con el y en su desarrollo. El documento no tratará ningún aspecto +técnico relacionado con la programación del kernel, pero le ayudará +guiándole por el camino correcto. + +Si algo en este documento quedara obsoleto, envíe parches al maintainer de +este archivo, que se encuentra en la parte superior del documento. + +Introducción +------------ +¿De modo que quiere descubrir como convertirse en un/a desarrollador/a del +kernel de Linux? Tal vez su jefe le haya dicho, "Escriba un driver de +Linux para este dispositivo." El objetivo de este documento en enseñarle +todo cuanto necesita para conseguir esto, describiendo el proceso por el +que debe pasar, y con indicaciones de como trabajar con la comunidad. +También trata de explicar las razones por las cuales la comunidad trabaja +de la forma en que lo hace. + +El kernel esta principalmente escrito en C, con algunas partes que son +dependientes de la arquitectura en ensamblador. Un buen conocimiento de C +es necesario para desarrollar en el kernel. Lenguaje ensamblador (en +cualquier arquitectura) no es necesario excepto que planee realizar +desarrollo de bajo nivel para dicha arquitectura. Aunque no es un perfecto +sustituto para una educación sólida en C y/o años de experiencia, los +siguientes libros sirven, como mínimo, como referencia: + +- "The C Programming Language" de Kernighan e Ritchie [Prentice Hall] +- "Practical C Programming" de Steve Oualline [O'Reilly] +- "C: A Reference Manual" de Harbison and Steele [Prentice Hall] + +El kernel está escrito usando GNU C y la cadena de herramientas GNU. Si +bien se adhiere al estándar ISO C89, utiliza una serie de extensiones que +no aparecen en dicho estándar. El kernel usa un C independiente de entorno, +sin depender de la biblioteca C estándar, por lo que algunas partes del +estándar C no son compatibles. Divisiones de long long arbitrarios o +de coma flotante no son permitidas. En ocasiones, puede ser difícil de +entender las suposiciones que el kernel hace respecto a la cadena de +herramientas y las extensiones que usa, y desafortunadamente no hay +referencia definitiva para estas. Consulte las páginas de información de +gcc (`info gcc`) para obtener información al respecto. + +Recuerde que está tratando de aprender a trabajar con una comunidad de +desarrollo existente. Es un grupo diverso de personas, con altos estándares +de código, estilo y procedimiento. Estas normas han sido creadas a lo +largo del tiempo en función de lo que se ha encontrado que funciona mejor +para un equipo tan grande y geográficamente disperso. Trate de aprender +tanto como le sea posible acerca de estos estándares antes de tiempo, ya +que están bien documentados; no espere que la gente se adapte a usted o a +la forma de hacer las cosas en su empresa. + +Cuestiones legales +------------------ +El código fuente del kernel de Linux se publica bajo licencia GPL. Por +favor, revise el archivo COPYING, presente en la carpeta principal del +código fuente, para detalles de la licencia. Si tiene alguna otra pregunta +sobre licencias, contacte a un abogado, no pregunte en listas de discusión +del kernel de Linux. La gente en estas listas no son abogadas, y no debe +confiar en sus opiniones en materia legal. + +Para preguntas y respuestas más frecuentes sobre la licencia GPL, consulte: + + https://www.gnu.org/licenses/gpl-faq.html + +Documentación +-------------- +El código fuente del kernel de Linux tiene una gran variedad de documentos +que son increíblemente valiosos para aprender a interactuar con la +comunidad del kernel. Cuando se agregan nuevas funciones al kernel, se +recomienda que se incluyan nuevos archivos de documentación que expliquen +cómo usar la función. Cuando un cambio en el kernel hace que la interfaz +que el kernel expone espacio de usuario cambie, se recomienda que envíe la +información o un parche en las páginas del manual que expliquen el cambio +a mtk.manpages@gmail.com, y CC la lista linux-api@vger.kernel.org. + +Esta es la lista de archivos que están en el código fuente del kernel y son +de obligada lectura: + + :ref:`Documentation/admin-guide/README.rst ` + Este archivo ofrece una breve descripción del kernel de Linux y + describe lo que es necesario hacer para configurar y compilar el + kernel. Quienes sean nuevos en el kernel deben comenzar aquí. + + :ref:`Documentation/process/changes.rst ` + Este archivo proporciona una lista de los niveles mínimos de varios + paquetes que son necesarios para construir y ejecutar el kernel + exitosamente. + + :ref:`Documentation/process/coding-style.rst ` + Esto describe el estilo de código del kernel de Linux y algunas de los + razones detrás de esto. Se espera que todo el código nuevo siga las + directrices de este documento. La mayoría de los maintainers solo + aceptarán parches si se siguen estas reglas, y muchas personas solo + revisan el código si tiene el estilo adecuado. + + :ref:`Documentation/process/submitting-patches.rst ` + Este archivo describe en gran detalle cómo crear con éxito y enviar un + parche, que incluye (pero no se limita a): + + - Contenidos del correo electrónico (email) + - Formato del email + - A quien se debe enviar + + Seguir estas reglas no garantiza el éxito (ya que todos los parches son + sujetos a escrutinio de contenido y estilo), pero en caso de no seguir + dichas reglas, el fracaso es prácticamente garantizado. + Otras excelentes descripciones de cómo crear parches correctamente son: + + "The Perfect Patch" + https://www.ozlabs.org/~akpm/stuff/tpp.txt + + "Linux kernel patch submission format" + https://web.archive.org/web/20180829112450/http://linux.yyz.us/patch-format.html + + :ref:`Documentation/process/stable-api-nonsense.rst ` + Este archivo describe la lógica detrás de la decisión consciente de + no tener una API estable dentro del kernel, incluidas cosas como: + + - Capas intermedias del subsistema (por compatibilidad?) + - Portabilidad de drivers entre sistemas operativos + - Mitigar el cambio rápido dentro del árbol de fuentes del kernel (o + prevenir cambios rápidos) + + Este documento es crucial para comprender la filosofía del desarrollo + de Linux y es muy importante para las personas que se mudan a Linux + tras desarrollar otros sistemas operativos. + + :ref:`Documentation/process/security-bugs.rst ` + Si cree que ha encontrado un problema de seguridad en el kernel de + Linux, siga los pasos de este documento para ayudar a notificar a los + desarrolladores del kernel y ayudar a resolver el problema. + + :ref:`Documentation/process/management-style.rst ` + Este documento describe cómo operan los maintainers del kernel de Linux + y los valores compartidos detrás de sus metodologías. Esta es una + lectura importante para cualquier persona nueva en el desarrollo del + kernel (o cualquier persona que simplemente sienta curiosidad por + el campo IT), ya que clarifica muchos conceptos erróneos y confusiones + comunes sobre el comportamiento único de los maintainers del kernel. + + :ref:`Documentation/process/stable-kernel-rules.rst ` + Este archivo describe las reglas sobre cómo se suceden las versiones + del kernel estable, y qué hacer si desea obtener un cambio en una de + estas publicaciones. + + :ref:`Documentation/process/kernel-docs.rst ` + Una lista de documentación externa relativa al desarrollo del kernel. + Por favor consulte esta lista si no encuentra lo que están buscando + dentro de la documentación del kernel. + + :ref:`Documentation/process/applying-patches.rst ` + Una buena introducción que describe exactamente qué es un parche y cómo + aplicarlo a las diferentes ramas de desarrollo del kernel. + +El kernel también tiene una gran cantidad de documentos que pueden ser +generados automáticamente desde el propio código fuente o desde +ReStructuredText markups (ReST), como este. Esto incluye un descripción +completa de la API en el kernel y reglas sobre cómo manejar cerrojos +(locking) correctamente. + +Todos estos documentos se pueden generar como PDF o HTML ejecutando:: + + make pdfdocs + make htmldocs + +respectivamente desde el directorio fuente principal del kernel. + +Los documentos que utilizan el markup ReST se generarán en +Documentation/output. También se pueden generar en formatos LaTeX y ePub +con:: + + make latexdocs + make epubdocs + +Convertirse en un/a desarrollador/a de kernel +--------------------------------------------- + +Si no sabe nada sobre el desarrollo del kernel de Linux, debería consultar +el proyecto Linux KernelNewbies: + + https://kernelnewbies.org + +Consiste en una útil lista de correo donde puede preguntar casi cualquier +tipo de pregunta básica de desarrollo del kernel (asegúrese de buscar en +los archivos primero, antes de preguntar algo que ya ha sido respondido en +el pasado.) También tiene un canal IRC que puede usar para hacer preguntas +en tiempo real, y una gran cantidad de documentación útil para ir +aprendiendo sobre el desarrollo del kernel de Linux. + +El sitio web tiene información básica sobre la organización del código, +subsistemas, y proyectos actuales (tanto dentro como fuera del árbol). +También describe alguna información logística básica, como cómo compilar +un kernel y aplicar un parche. + +Si no sabe por dónde quiere empezar, pero quieres buscar alguna tarea que +comenzar a hacer para unirse a la comunidad de desarrollo del kernel, +acuda al proyecto Linux Kernel Janitor: + + https://kernelnewbies.org/KernelJanitors + +Es un gran lugar para comenzar. Describe una lista de problemas +relativamente simples que deben limpiarse y corregirse dentro del código +fuente del kernel de Linux árbol de fuentes. Trabajando con los +desarrolladores a cargo de este proyecto, aprenderá los conceptos básicos +para incluir su parche en el árbol del kernel de Linux, y posiblemente +descubrir en la dirección en que trabajar a continuación, si no tiene ya +una idea. + +Antes de realizar cualquier modificación real al código del kernel de +Linux, es imperativo entender cómo funciona el código en cuestión. Para +este propósito, nada es mejor que leerlo directamente (lo más complicado +está bien comentado), tal vez incluso con la ayuda de herramientas +especializadas. Una de esas herramientas que se recomienda especialmente +es el proyecto Linux Cross-Reference, que es capaz de presentar el código +fuente en un formato de página web indexada y autorreferencial. Una +excelente puesta al día del repositorio del código del kernel se puede +encontrar en: + + https://elixir.bootlin.com/ + +El proceso de desarrollo +------------------------ + +El proceso de desarrollo del kernel de Linux consiste actualmente de +diferentes "branches" (ramas) con muchos distintos subsistemas específicos +a cada una de ellas. Las diferentes ramas son: + + - El código principal de Linus (mainline tree) + - Varios árboles estables con múltiples major numbers + - Subsistemas específicos + - linux-next, para integración y testing + +Mainline tree (Árbol principal) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +El mainline tree es mantenido por Linus Torvalds, y puede encontrarse en +https://kernel.org o en su repo. El proceso de desarrollo es el siguiente: + + - Tan pronto como se lanza un nuevo kernel, se abre una ventana de dos + semanas, durante este período de tiempo, los maintainers pueden enviar + grandes modificaciones a Linus, por lo general los parches que ya se + han incluido en el linux-next durante unas semanas. La forma preferida + de enviar grandes cambios es usando git (la herramienta de + administración de código fuente del kernel, más información al respecto + en https://git-scm.com/), pero los parches simples también son validos. + - Después de dos semanas, se lanza un kernel -rc1 y la atención se centra + en hacer el kernel nuevo lo más estable ("solido") posible. La mayoría + de los parches en este punto deben arreglar una regresión. Los errores + que siempre han existido no son regresiones, por lo tanto, solo envíe + este tipo de correcciones si son importantes. Tenga en cuenta que se + podría aceptar un controlador (o sistema de archivos) completamente + nuevo después de -rc1 porque no hay riesgo de causar regresiones con + tal cambio, siempre y cuando el cambio sea autónomo y no afecte áreas + fuera del código que se está agregando. git se puede usar para enviar + parches a Linus después de que se lance -rc1, pero los parches también + deben ser enviado a una lista de correo pública para su revisión. + - Se lanza un nuevo -rc cada vez que Linus considera que el árbol git + actual esta en un estado razonablemente sano y adecuado para la prueba. + La meta es lanzar un nuevo kernel -rc cada semana. + - El proceso continúa hasta que el kernel se considera "listo", y esto + puede durar alrededor de 6 semanas. + +Vale la pena mencionar lo que Andrew Morton escribió en las listas de +correo del kernel de Linux, sobre lanzamientos del kernel (traducido): + + *"Nadie sabe cuándo se publicara un nuevo kernel, pues esto sucede + según el estado de los bugs, no de una cronología preconcebida."* + +Varios árboles estables con múltiples major numbers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Los kernels con versiones de 3 partes son kernels estables. Estos contienen +correcciones relativamente pequeñas y críticas para problemas de seguridad +o importantes regresiones descubiertas para una publicación de código. +Cada lanzamiento en una gran serie estable incrementa la tercera parte de +la versión número, manteniendo las dos primeras partes iguales. + +Esta es la rama recomendada para los usuarios que quieren la versión +estable más reciente del kernel, y no están interesados en ayudar a probar +versiones en desarrollo/experimentales. + +Los árboles estables son mantenidos por el equipo "estable" +, y se liberan (publican) según lo dicten las +necesidades. El período de liberación normal es de aproximadamente dos +semanas, pero puede ser más largo si no hay problemas apremiantes. Un +problema relacionado con la seguridad, en cambio, puede causar un +lanzamiento casi instantáneamente. + +El archivo :ref:`Documentación/proceso/stable-kernel-rules.rst ` +en el árbol del kernel documenta qué tipos de cambios son aceptables para +el árbol estable y cómo funciona el proceso de lanzamiento. + +Subsistemas específicos +~~~~~~~~~~~~~~~~~~~~~~~~ +Los maintainers de los diversos subsistemas del kernel --- y también muchos +desarrolladores de subsistemas del kernel --- exponen su estado actual de +desarrollo en repositorios fuente. De esta manera, otros pueden ver lo que +está sucediendo en las diferentes áreas del kernel. En áreas donde el +desarrollo es rápido, se le puede pedir a un desarrollador que base sus +envíos en tal árbol del subsistema del kernel, para evitar conflictos entre +este y otros trabajos ya en curso. + +La mayoría de estos repositorios son árboles git, pero también hay otros +SCM en uso, o colas de parches que se publican como series quilt. Las +direcciones de estos repositorios de subsistemas se enumeran en el archivo +MAINTAINERS. Muchos de estos se pueden ver en https://git.kernel.org/. + +Antes de que un parche propuesto se incluya con dicho árbol de subsistemas, +es sujeto a revisión, que ocurre principalmente en las listas de correo +(ver la sección respectiva a continuación). Para varios subsistemas del +kernel, esta revisión se rastrea con la herramienta patchwork. Patchwork +ofrece una interfaz web que muestra publicaciones de parches, cualquier +comentario sobre un parche o revisiones a él, y los maintainers pueden +marcar los parches como en revisión, aceptado, o rechazado. La mayoría de +estos sitios de trabajo de parches se enumeran en + +https://patchwork.kernel.org/. + +linux-next, para integración y testing +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Antes de que las actualizaciones de los árboles de subsistemas se combinen +con el árbol principal, necesitan probar su integración. Para ello, existe +un repositorio especial de pruebas en el que se encuentran casi todos los +árboles de subsistema, actualizado casi a diario: + + https://git.kernel.org/?p=linux/kernel/git/next/linux-next.git + +De esta manera, linux-next ofrece una perspectiva resumida de lo que se +espera que entre en el kernel principal en el próximo período de "merge" +(fusión de código). Los testers aventureros son bienvenidos a probar +linux-next en ejecución. + +Reportar bugs +------------- + +El archivo 'Documentación/admin-guide/reporting-issues.rst' en el +directorio principal del kernel describe cómo informar un posible bug del +kernel y detalles sobre qué tipo de información necesitan los +desarrolladores del kernel para ayudar a rastrear la fuente del problema. + +Gestión de informes de bugs +------------------------------ + +Una de las mejores formas de poner en práctica sus habilidades de hacking +es arreglando errores reportados por otras personas. No solo ayudará a +hacer el kernel más estable, también aprenderá a solucionar problemas del +mundo real y mejora sus habilidades, y otros desarrolladores se darán +cuenta de tu presencia. La corrección de errores es una de las mejores +formas de ganar méritos entre desarrolladores, porque no a muchas personas +les gusta perder el tiempo arreglando los errores de otras personas. + +Para trabajar en informes de errores ya reportados, busque un subsistema +que le interese. Verifique el archivo MAINTAINERS donde se informan los +errores de ese subsistema; con frecuencia será una lista de correo, rara +vez un rastreador de errores (bugtracker). Busque en los archivos de dicho +lugar para informes recientes y ayude donde lo crea conveniente. También es +posible que desee revisar https://bugzilla.kernel.org para informes de +errores; solo un puñado de subsistemas del kernel lo emplean activamente +para informar o rastrear; sin embargo, todos los errores para todo el kernel +se archivan allí. + +Listas de correo +----------------- + +Como se explica en algunos de los documentos anteriores, la mayoría de +desarrolladores del kernel participan en la lista de correo del kernel de +Linux. Detalles sobre cómo para suscribirse y darse de baja de la lista se +pueden encontrar en: + + http://vger.kernel.org/vger-lists.html#linux-kernel + +Existen archivos de la lista de correo en la web en muchos lugares +distintos. Utilice un motor de búsqueda para encontrar estos archivos. Por +ejemplo: + + http://dir.gmane.org/gmane.linux.kernel + +Es muy recomendable que busque en los archivos sobre el tema que desea +tratar, antes de publicarlo en la lista. Un montón de cosas ya discutidas +en detalle solo se registran en los archivos de la lista de correo. + +La mayoría de los subsistemas individuales del kernel también tienen sus +propias lista de correo donde hacen sus esfuerzos de desarrollo. Revise el +archivo MAINTAINERS para obtener referencias de lo que estas listas para +los diferentes grupos. + +Muchas de las listas están alojadas en kernel.org. La información sobre +estas puede ser encontrada en: + + http://vger.kernel.org/vger-lists.html + +Recuerde mantener buenos hábitos de comportamiento al usar las listas. +Aunque un poco cursi, la siguiente URL tiene algunas pautas simples para +interactuar con la lista (o cualquier lista): + + http://www.albion.com/netiquette/ + +Si varias personas responden a su correo, el CC (lista de destinatarios) +puede hacerse bastante grande. No elimine a nadie de la lista CC: sin una +buena razón, o no responda solo a la dirección de la lista. Acostúmbrese +a recibir correos dos veces, una del remitente y otra de la lista, y no +intente ajustar esto agregando encabezados de correo astutos, a la gente no +le gustará. + +Recuerde mantener intacto el contexto y la atribución de sus respuestas, +mantenga las líneas "El hacker John Kernel escribió ...:" en la parte +superior de su respuesta, y agregue sus declaraciones entre las secciones +individuales citadas en lugar de escribiendo en la parte superior del +correo electrónico. + +Si incluye parches en su correo, asegúrese de que sean texto legible sin +formato como se indica en :ref:`Documentation/process/submitting-patches.rst `. +Los desarrolladores del kernel no quieren lidiar con archivos adjuntos o +parches comprimidos; y pueden querer comentar líneas individuales de su +parche, que funciona sólo de esa manera. Asegúrese de emplear un programa +de correo que no altere los espacios ni los tabuladores. Una buena primera +prueba es enviarse el correo a usted mismo, e intentar aplicar su +propio parche. Si eso no funciona, arregle su programa de correo o +reemplace hasta que funcione. + +Sobretodo, recuerde de ser respetuoso con otros subscriptores. + +Colaborando con la comunidad +---------------------------- + +El objetivo de la comunidad del kernel es proporcionar el mejor kernel +posible. Cuando envíe un parche para su aceptación, se revisará en sus +méritos técnicos solamente. Entonces, ¿qué deberías ser? + + - críticas + - comentarios + - peticiones de cambios + - peticiones de justificaciones + - silencio + +Recuerde, esto es parte de introducir su parche en el kernel. Tiene que ser +capaz de recibir críticas y comentarios sobre sus parches, evaluar +a nivel técnico y re-elaborar sus parches o proporcionar razonamiento claro +y conciso de por qué no se deben hacer tales cambios. Si no hay respuestas +a su publicación, espere unos días e intente de nuevo, a veces las cosas se +pierden dado el gran volumen. + +¿Qué no debería hacer? + + - esperar que su parche se acepte sin preguntas + - actuar de forma defensiva + - ignorar comentarios + - enviar el parche de nuevo, sin haber aplicados los cambios pertinentes + +En una comunidad que busca la mejor solución técnica posible, siempre habrá +diferentes opiniones sobre lo beneficioso que es un parche. Tiene que ser +cooperativo y estar dispuesto a adaptar su idea para que encaje dentro +del kernel, o al menos esté dispuesto a demostrar que su idea vale la pena. +Recuerde, estar equivocado es aceptable siempre y cuando estés dispuesto a +trabajar hacia una solución que sea correcta. + +Es normal que las respuestas a su primer parche sean simplemente una lista +de una docena de cosas que debe corregir. Esto **no** implica que su +parche no será aceptado, y **no** es personal. Simplemente corrija todos +los problemas planteados en su parche, y envié otra vez. + +Diferencias entre la comunidad kernel y las estructuras corporativas +-------------------------------------------------------------------- + +La comunidad del kernel funciona de manera diferente a la mayoría de los +entornos de desarrollo tradicionales en empresas. Aquí hay una lista de +cosas que puede intentar hacer para evitar problemas: + + Cosas buenas que decir respecto a los cambios propuestos: + + - "Esto arregla múltiples problemas." + - "Esto elimina 2000 lineas de código." + - "Aquí hay un parche que explica lo que intento describir." + - "Lo he testeado en 5 arquitecturas distintas..." + - "Aquí hay una serie de parches menores que..." + - "Esto mejora el rendimiento en maquinas típicas..." + + Cosas negativas que debe evitar decir: + + - "Lo hicimos así en AIX/ptx/Solaris, de modo que debe ser bueno..." + - "Llevo haciendo esto 20 años, de modo que..." + - "Esto lo necesita mi empresa para ganar dinero" + - "Esto es para la linea de nuestros productos Enterprise" + - "Aquí esta el documento de 1000 paginas describiendo mi idea" + - "Llevo 6 meses trabajando en esto..." + - "Aquí esta un parche de 5000 lineas que..." + - "He rescrito todo el desastre actual, y aquí esta..." + - "Tengo un deadline, y este parche debe aplicarse ahora." + +Otra forma en que la comunidad del kernel es diferente a la mayoría de los +entornos de trabajo tradicionales en ingeniería de software, es la +naturaleza sin rostro de interacción. Una de las ventajas de utilizar el +correo electrónico y el IRC como formas principales de comunicación es la +no discriminación por motivos de género o raza. El entorno de trabajo del +kernel de Linux acepta a mujeres y minorías porque todo lo que eres es una +dirección de correo electrónico. El aspecto internacional también ayuda a +nivelar el campo de juego porque no puede adivinar el género basado en +el nombre de una persona. Un hombre puede llamarse Andrea y una mujer puede +llamarse Pat. La mayoría de las mujeres que han trabajado en el kernel de +Linux y han expresado una opinión han tenido experiencias positivas. + +La barrera del idioma puede causar problemas a algunas personas que no se +sientes cómodas con el inglés. Un buen dominio del idioma puede ser +necesario para transmitir ideas correctamente en las listas de correo, por +lo que le recomendamos que revise sus correos electrónicos para asegurarse +de que tengan sentido en inglés antes de enviarlos. + +Divida sus cambios +--------------------- + +La comunidad del kernel de Linux no acepta con gusto grandes fragmentos de +código, sobretodo a la vez. Los cambios deben introducirse correctamente, +discutidos y divididos en pequeñas porciones individuales. Esto es casi +exactamente lo contrario de lo que las empresas están acostumbradas a hacer. +Su propuesta también debe introducirse muy temprano en el proceso de +desarrollo, de modo que pueda recibir comentarios sobre lo que está +haciendo. También deje que la comunidad sienta que está trabajando con +ellos, y no simplemente usándolos como un vertedero para su función. Sin +embargo, no envíe 50 correos electrónicos a una vez a una lista de correo, +su serie de parches debe casi siempre ser más pequeña que eso. + +Las razones para dividir las cosas son las siguientes: + +1) Los cambios pequeños aumentan la probabilidad de que sus parches sean + aplicados, ya que no requieren mucho tiempo o esfuerzo para verificar su + exactitud. Un parche de 5 líneas puede ser aplicado por un maintainer + con apenas una segunda mirada. Sin embargo, un parche de 500 líneas + puede tardar horas en ser revisado en términos de corrección (el tiempo + que toma es exponencialmente proporcional al tamaño del parche, o algo + así). + + Los parches pequeños también facilitan la depuración cuando algo falla. + Es mucho más fácil retirar los parches uno por uno que diseccionar un + parche muy grande después de haber sido aplicado (y roto alguna cosa). + +2) Es importante no solo enviar pequeños parches, sino también reescribir + y simplificar (o simplemente reordenar) los parches antes de enviarlos. + +Esta es una analogía del desarrollador del kernel Al Viro (traducida): + + *"Piense en un maestro que califica la tarea de un estudiante de + matemáticas. El maestro no quiere ver los intentos y errores del + estudiante antes de que se les ocurriera la solución. Quiere ver la + respuesta más limpia y elegante. Un buen estudiante lo sabe, y nunca + presentaría su trabajo intermedio antes de tener la solución final.* + + *Lo mismo ocurre con el desarrollo del kernel. Los maintainers y + revisores no quieren ver el proceso de pensamiento detrás de la solución + al problema que se está resolviendo. Quieren ver un solución simple y + elegante."* + +Puede resultar un reto mantener el equilibrio entre presentar una solución +elegante y trabajar junto a la comunidad, discutiendo su trabajo inacabado. +Por lo tanto, es bueno comenzar temprano en el proceso para obtener +"feedback" y mejorar su trabajo, pero también mantenga sus cambios en +pequeños trozos que pueden ser aceptados, incluso cuando toda su labor no +está listo para inclusión en un momento dado. + +También tenga en cuenta que no es aceptable enviar parches para su +inclusión que están sin terminar y serán "arreglados más tarde". + +Justifique sus cambios +---------------------- + +Además de dividir sus parches, es muy importante que deje a la comunidad de +Linux sabe por qué deberían agregar este cambio. Nuevas características +debe justificarse como necesarias y útiles. + +Documente sus cambios +--------------------- + +Cuando envíe sus parches, preste especial atención a lo que dice en el +texto de su correo electrónico. Esta información se convertirá en el +ChangeLog del parche, y se conservará para que todos la vean, todo el +tiempo. Debe describir el parche por completo y contener: + + - por qué los cambios son necesarios + - el diseño general de su propuesta + - detalles de implementación + - resultados de sus experimentos + +Para obtener más detalles sobre cómo debería quedar todo esto, consulte la +sección ChangeLog del documento: + + "The Perfect Patch" + https://www.ozlabs.org/~akpm/stuff/tpp.txt + +Todas estas cuestiones son a veces son muy difíciles de conseguir. Puede +llevar años perfeccionar estas prácticas (si es que lo hace). Es un proceso +continuo de mejora que requiere mucha paciencia y determinación. Pero no se +rinda, es posible. Muchos lo han hecho antes, y cada uno tuvo que comenzar +exactamente donde está usted ahora. + +---------- + +Gracias a Paolo Ciarrocchi que permitió que la sección "Development Process" +se basara en el texto que había escrito (https://lwn.net/Articles/94386/), +y a Randy Dunlap y Gerrit Huizenga por algunas de la lista de cosas que +debes y no debes decir. También gracias a Pat Mochel, Hanna Linder, Randy +Dunlap, Kay Sievers, Vojtech Pavlik, Jan Kara, Josh Boyer, Kees Cook, +Andrew Morton, Andi Kleen, Vadim Lobanov, Jesper Juhl, Adrian Bunk, +Keri Harris, Frans Pop, David A. Wheeler, Junio Hamano, Michael Kerrisk y +Alex Shepard por su revisión, comentarios y contribuciones. Sin su ayuda, +este documento no hubiera sido posible. + +Maintainer: Greg Kroah-Hartman diff --git a/Documentation/translations/sp_SP/process/index.rst b/Documentation/translations/sp_SP/process/index.rst index d6f3ccfb160e41..2239373b399940 100644 --- a/Documentation/translations/sp_SP/process/index.rst +++ b/Documentation/translations/sp_SP/process/index.rst @@ -24,3 +24,7 @@ contribution-maturity-model security-bugs embargoed-hardware-issues + handling-regressions + management-style + submit-checklist + howto diff --git a/Documentation/translations/sp_SP/process/management-style.rst b/Documentation/translations/sp_SP/process/management-style.rst new file mode 100644 index 00000000000000..4db33fbf894167 --- /dev/null +++ b/Documentation/translations/sp_SP/process/management-style.rst @@ -0,0 +1,299 @@ +.. include:: ../disclaimer-sp.rst + +:Original: Documentation/process/management-style.rst +:Translator: Avadhut Naik + +.. _sp_managementstyle: + + +Estilo de gestión del kernel de Linux +===================================== + +Este es un documento breve que describe el estilo de gestión preferido (o +inventado, dependiendo de a quién le preguntes) para el kernel de Linux. +Está destinado a reflejar el documento +:ref:`translations/sp_SP/process/coding-style.rst ` hasta +cierto punto y está escrito principalmente para evitar responder a [#f1]_ +las mismas preguntas (o similares) una y otra vez. + +El estilo de gestión es muy personal y mucho más difícil de cuantificar +que reglas simples de estilo de codificación, por lo que este documento +puede o no tener relación con la realidad. Comenzó como una broma, pero +eso no significa que no pueda ser realmente cierto. Tendrás que decidir +por ti mismo. + +Por cierto, cuando se hable de “gerente de kernel”, se refiere a las +personas lideres técnicas, no de las personas que hacen la gestión +tradicional dentro de las empresas. Si firmas pedidos de compra o tienes +alguna idea sobre el presupuesto de tu grupo, es casi seguro que no eres +un gerente de kernel. Estas sugerencias pueden o no aplicarse a usted. + +En primer lugar, sugeriría comprar “Seven Habits of Highly Effective +People” y NO leerlo. Quemarlo, es un gran gesto simbólico. + +.. [#f1] Este documento lo hace no tanto respondiendo a la pregunta, sino + haciendo dolorosamente obvio para el interrogador que no tenemos ni idea + de cuál es la respuesta. + +De todos modos, aquí va: + +.. _decisiones: + +1) Decisiones +------------- + +Todos piensan que los gerentes toman decisiones, y que la toma de +decisiones en importante. Cuanto más grande y dolorosa sea la decisión, +más grande debe ser el gerente para tomarla. Eso es muy profundo y obvio, +pero en realidad no es cierto. + +El nombre del partido es **evitar** tener que tomar una decisión. En +particular, si alguien te dice “elige (a) o (b), realmente necesitamos +que decidas sobre esto”, estas en problemas como gerente. Es mejor que +las personas a las que diriges conozcan los detalles mejor que tú, así +que, si acuden a ti para tomar una decisión técnica, estas jodido. +Claramente no eres competente para tomar una decisión por ellos. + +(Corolario: Si las personas a las que diriges no conocen los detalles +mejor que tú, también estas jodido, aunque por una razón totalmente +diferente. Es decir, que estas en el trabajo equivocado y que **ellos** +deberían gestionando tu brillantez en su lugar). + +Así que el nombre del partido es **evitar** las decisiones, al menos las +grandes y dolorosas. Tomar decisiones pequeñas y sin consecuencias está +bien, y te hace parecer que sabes lo que estás haciendo, así que lo que +un gerente de kernel necesita hacer es convertir las decisiones grandes +y dolorosas en cosas pequeñas a los que a nadie realmente le importa. + +Ayuda darse cuenta de que la diferencia clave entre una decisión grande +y una pequeña es si puede arreglar su decisión después. Cualquier +decisión se puede hacer pequeña simplemente asegurándose siempre de que +si te equivocaste (u **estarás** equivocado), siempre puede deshacer el +daño más tarde retrocediendo. De repente, llegas a ser doblemente +gerencial por tomar **dos** decisiones intrascendentes - la equivocada +**y** la correcta. + +Y las personas incluso verán eso como un verdadero liderazgo (*tos* +mierda *tos*). + +Por lo tanto, la llave para evitar las grandes decisiones se convierte en +simplemente evitar hacer cosas que no se pueden deshacer. No te dejes +llevar a una esquina del que no puedas escapar. Una rata acorralada puede +ser peligrosa – un gerente acorralado es directamente lamentable. + +Resulta que, dado que nadie sería tan estúpido como para dejar que un +gerente de kernel tenga una gran responsabilidad **de todos modos**, +generalmente es bastante fácil retroceder. Dado que no vas a poder +malgastar grandes cantidades de dinero que tal vez no puedas pagar, lo +único que puedes revertir es una decisión técnica, y ahí retroceder es +muy fácil: simplemente diles a todos que fuiste un bobo incompetente, +pide disculpas y deshaz todo el trabajo inútil que hiciste trabajar a la +gente durante el año pasado. De repente, la decisión que tomaste hace un +año no era una gran decisión después de todo, ya que se podía deshacer +fácilmente. + +Resulta que algunas personas tienen problemas con este enfoque, por dos +razones: + + - admitir que eras un idiota es más difícil de lo que parece. A todos + nos gusta mantener las apariencias, y salir en público a decir que te + equivocaste a veces es muy duro. + - que alguien te diga que lo que trabajaste durante el último año no + valió la pena después de todo también puede ser duro para los pobres + ingenieros humildes, y aunque el **trabajo** real fue bastante fácil + de deshacer simplemente eliminándolo, es posible que hayas perdido + irrevocablemente la confianza de ese ingeniero. Y recuerda: + “irrevocablemente” fue lo que tratamos de evitar en primer lugar, y + tu decisión terminó siendo muy grande después de todo. + +Afortunadamente, estas dos razones pueden mitigarse eficazmente +simplemente admitiendo inicialmente que no tienes ni idea, y diciéndole +a la gente que tu decisión es puramente preliminar, y podría ser la cosa +equivocada. Siempre te debes reservar el derecho de cambiar de opinión, y +hacer que la gente sea muy **consciente** de eso. Y es mucho más fácil +admitir que eres estúpido cuando **aun** no has hecho la cosa realmente +estúpida. + +Entonces, cuando realmente resulta ser estúpido, la gente simplemente +pone los ojos y dice “Ups, otra vez no”. + +Esta admisión preventiva de incompetencia también podría hacer que las +personas que realmente hacen el trabajo piensen dos veces sobre si vale la +pena hacerlo o no. Después de todo, si **ellos** no están seguros de si es +una buena idea, seguro que no deberías alentarlos prometiéndoles que lo +que trabajan será incluido. Haz que al menos lo piensen dos veces antes de +embarcarse en un gran esfuerzo. + +Recuerda: Es mejor que sepan más sobre los detalles que tú, y +generalmente ya piensan que tienen la respuesta a todo. Lo mejor que puede +hacer como gerente no es inculcar confianza, sino más bien una dosis +saludable de pensamiento crítico sobre lo que hacen. + +Por cierto, otra forma de evitar una decisión es quejarse lastimeramente +de “no podemos hacer ambas cosas?” y parecer lamentable. Créeme, funciona. +Si no está claro cuál enfoque es mejor, lo descubrirán. La respuesta puede +terminar siendo que ambos equipos se sientan tan frustrados por la +situación que simplemente se den por vencidos. + +Eso puede sonar como un fracaso, pero generalmente es una señal de que +había algo mal con ambos proyectos, y la razón por la que las personas +involucradas no pudieron decidir fue que ambos estaban equivocados. +Terminas oliendo a rosas y evitaste otra decisión que podrías haber +metido la pata. + +2) Gente +-------- + +La mayoría de las personas son idiotas, y ser gerente significa que +tendrás que lidiar con eso, y quizás lo más importante, que **ellos** +tienen que lidiar **contigo**. + +Resulta que, si bien es fácil deshacer los errores técnicos, no es tan +fácil deshacer los trastornos de personalidad. Solo tienes que vivir +con los suyos - y el tuyo. + +Sin embargo, para prepararse como gerente del kernel, es mejor recordar +no quemar ningún puente, bombardear a ningún aldeano inocente o alienar +a demasiados desarrolladores del kernel. Resulta que alienar a las +personas es bastante fácil, y desalienarlas es difícil. Por lo tanto, +“alienar” cae inmediatamente debajo del título “no reversible”, y se +convierte en un no-no según :ref:`decisiones`. + +Aquí solo hay algunas reglas simples: + + (1) No llames a la gente pen*ejos (al menos no en público) + (2) Aprende a disculparte cuando olvidaste la regla (1) + +El problema con #1 es que es muy fácil de hacer, ya que puedes decir +“eres un pen*ejo” de millones de manera diferentes [#f2]_, a veces sin +siquiera darte cuenta, y casi siempre con una convicción ardiente de que +tienes razón. + +Y cuanto más convencido estés de que tienes razón (y seamos sinceros, +puedes llamar a casi **cualquiera** un pen*ejo, y a menudo **tendrás** +razón), más difícil termina siendo disculparse después. + +Para resolver este problema, realmente solo tienes dos opciones: + + - Se muy buenos en las disculpas. + - Difunde el “amor” de manera tan uniforme que nadie termina sintiendo + que es atacado injustamente. Hazlo lo suficientemente ingenioso, e + incluso podría divertirse. + +La opción de ser infaliblemente educado realmente no existe. Nadie +confiará en alguien que está ocultando tan claramente su verdadero +carácter. + +.. [#f2] Paul Simon cantó “Cincuenta maneras de dejar a tu amante” porque, + francamente, “Un millón de maneras de decirle a un desarrollador que es + un pen*ejo” no escanea tan bien. Pero estoy seguro de que lo pensó. + +3) Gente II – el Buen Tipo +-------------------------- + +Aunque resulta que la mayoría de las personas son idiotas, el corolario +de eso es, tristemente, que tú también seas uno, y aunque todos podemos +disfrutar del conocimiento seguro de que somos mejores que la persona +promedio (somos realistas, nadie cree que nunca que son promedio o debajo +del promedio), también debemos admitir que no somos el cuchillo más +afilado alrededor, y habrá otras personas que son menos idiotas que tú. + +Algunas personas reaccionan mal a las personas inteligentes. Otras se +aprovechan de ellos. + +Asegúrate de que tú, como mantenedor del kernel, estás en el segundo +grupo. Aguanta con ellos, porque son las personas que te facilitarán el +trabajo. En particular, podrán tomar tus decisiones por ti, que es de lo +que se trata el juego. + +Así que cuando encuentras a alguien más inteligente que tú, simplemente +sigue adelante. Sus responsabilidades de gestión se convierten en gran +medida en las de decir “Suena como una buena idea, - hazlo sin +restricciones”, o “Eso suena bien, pero ¿qué pasa con xxx?". La segunda +versión en particular es una excelente manera de aprender algo nuevo +sobre “xxx” o parecer **extra** gerencial al señalar algo que la persona +más inteligente no había pensado. En cualquier caso, sales ganando. + +Una cosa para tener en cuenta es darse cuenta de que la grandeza en un +área no necesariamente se traduce en otras áreas. Así que puedes impulsar +a la gente en direcciones específicas, pero seamos realistas, pueden ser +buenos en lo que hacen, y ser malos en todo lo demás. La buena noticia es +que las personas tienden a gravitar naturalmente hacia lo que son buenos, +por lo que no es como si estuvieras haciendo algo irreversible cuando los +impulsas en alguna dirección, simplemente no presiones demasiado. + +4) Colocar la culpa +------------------- + +Las cosas saldrán mal, y la gente quiere culpar a alguien. Etiqueta, tú +lo eres. + +En realidad, no es tan difícil aceptar la culpa, especialmente si la gente +se da cuenta de que no fue **toda** tu culpa. Lo que nos lleva a la mejor +manera de asumir la culpa: hacerlo por otra persona. Te sentirás bien por +asumir la caída, ellos se sentirán bien por no ser culpados, y la persona +que perdió toda su colección de pornografía de 36 GB debido a tu +incompetencia admitirá a regañadientes que al menos intentaste escapar +de ella. + +Luego haz que el desarrollador que realmente metió la pata (si puedes +encontrarlo) sepa **en privado** que metió la pata. No solo para que +pueda evitarlo en futuro, sino para que sepan que te deben uno. Y, quizás +aún más importante, también es probable que sea la persona que puede +solucionarlo. Porque, seamos sinceros, seguro que no eres tú. + +Asumir la culpa también es la razón por la que llegas a ser un gerente +en primer lugar. Es parte de lo que hace que la gente confíe en ti y te +permita la gloria potencial porque eres tú quien puede decir “metí la +pata”. Y si has seguido las reglas anteriores, ya serás bastante bueno +para decir eso. + +5) Cosas que evitar +------------------- + +Hay una cosa que la gente odia incluso más que ser llamado “pen*ejo”, +y que es ser llamado “pen*ejo” en una voz mojigata. Por lo primero, +puedes disculparte, por lo segundo, realmente, no tendrás la oportunidad. +Es probable que ya no estén escuchando, incluso si de lo contrario haces +un buen trabajo. + +Todos pensamos que somos mejores que los demás, lo que significa que +cuando alguien más se da aires, **realmente** nos molesta. Puedes ser +moral e intelectualmente superior a todos los que te rodean, pero no +trates de hacerlo demasiado obvio a menos que tengas **la intención** +real de irritar a alguien [#f3]_. + +Del mismo modo, no seas demasiado educado o sutil acerca de las cosas. La +cortesía fácilmente termina yendo demasiado lejos y ocultado el problema, +y como dicen “En internet, nadie puede oírte ser sutil”. Usa un gran +objeto contundente para enfatizar el punto, porque realmente no puedes +depender de que las personas entiendan tu punto de otra manera. + +Un poco de humor puede ayudar a suavizar tanto la franqueza como la +moralización. Exagerar hasta el punto de ser ridículo puede reforzar un +punto sin hacer que sea doloroso para el destinatario, quien simplemente +piensa que estas siendo tonto. Por lo tanto, puede ayudarnos a superar el +bloqueo mental personal que todos tenemos sobre la crítica. + +.. [#f3] La pista: Los grupos de noticias de Internet que no están + directamente relacionados con tu trabajo son excelentes maneras de + desahogar tus frustraciones con otras personas. Escribe mensajes + insultantes con una mueca de desprecio solo para entrar en un humor de + vez en cuando, y te sentirás limpio. Eso sí, no te cagues demasiado + cerca de casa. + +6) ¿Por qué a mí? +----------------- + +Dado que tu principal responsabilidad parece ser asumir la culpa de los +errores de otras personas y hacer dolorosamente obvio para todos los +demás que eres incompetente, la pregunta obvia es: ¿por qué hacerlo en +primer lugar? + +Pase lo que pase, **tendrás** una sensación inmensa de logro personal por +estar “a cargo”. No importa el hecho de que realmente estés liderando al +tratar de mantenerte al día con todos los demás y correr detrás de ellos +lo más rápido que puedes. Todo el mundo seguirá pensando que eres la +persona a cargo. + +Es un gran trabajo si puedes descifrarlo. diff --git a/Documentation/translations/sp_SP/process/submit-checklist.rst b/Documentation/translations/sp_SP/process/submit-checklist.rst new file mode 100644 index 00000000000000..0d6651f9d87176 --- /dev/null +++ b/Documentation/translations/sp_SP/process/submit-checklist.rst @@ -0,0 +1,133 @@ +.. include:: ../disclaimer-sp.rst + +:Original: Documentation/process/submit-checklist.rst +:Translator: Avadhut Naik + +.. _sp_submitchecklist: + +Lista de comprobación para enviar parches del kernel de Linux +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Aquí hay algunas cosas básicas que los desarrolladores deben hacer si +quieren que sus envíos de parches del kernel sean aceptados más +rápidamente. + +Todo esto está más allá de la documentación que se proporciona en +:ref:`Documentation/translations/sp_SP/process/submitting-patches.rst ` +y en otros lugares con respecto al envío de parches del kernel de Linux. + +1) Si utiliza una funcionalidad, #include el archivo que define/declara + esa funcionalidad. No dependa de otros archivos de encabezado que + extraigan los que utiliza. + +2) Compile limpiamente: + + a) Con las opciones ``CONFIG`` aplicables o modificadas ``=y``, ``=m``, + y ``=n``. Sin advertencias/errores del compilador ``gcc``, ni + advertencias/errores del linker. + + b) Aprobar ``allnoconfig``, ``allmodconfig`` + + c) Compila correctamente cuando se usa ``O=builddir`` + + d) Cualquier documentación o cambios se compilan correctamente sin + nuevas advertencias/errores. Utilice ``make htmldocs`` o + ``make pdfdocs`` para comprobar la compilación y corregir cualquier + problema. + +3) Se compila en varias arquitecturas de CPU mediante herramientas de + compilación cruzada locales o alguna otra granja de compilación. + +4) ppc64 es una buena arquitectura para verificar la compilación cruzada + por que tiende a usar ``unsigned long`` para cantidades de 64-bits. + +5) Verifique su parche para el estilo general según se detalla en + :ref:`Documentation/translations/sp_SP/process/coding-style.rst `. + Verifique las infracciones triviales con el verificador de estilo de + parches antes de la entrega (``scripts/checkpatch.pl``). + Debería ser capaz de justificar todas las infracciones que permanezcan + en su parche. + +6) Cualquier opción ``CONFIG`` nueva o modificada no altera el menú de + configuración y se desactiva por defecto, a menos que cumpla con los + criterios de excepción documentados en + ``Documentation/kbuild/kconfig-language.rst`` Atributos del menú: valor por defecto. + +7) Todas las nuevas opciones de ``Kconfig`` tienen texto de ayuda. + +8) Ha sido revisado cuidadosamente con respecto a las combinaciones + relevantes de ``Kconfig``. Esto es muy difícil de hacer correctamente + con las pruebas -- la concentración mental da resultados aquí. + +9) Verifique limpiamente con sparse. + +10) Use ``make checkstack`` y solucione cualquier problema que encuentre. + + .. note:: + + ``checkstack`` no señala los problemas explícitamente, pero + cualquier función que use más de 512 bytes en la pila es + candidata para el cambio. + +11) Incluya :ref:`kernel-doc ` para documentar las API + globales del kernel. (No es necesario para funciones estáticas, pero + también está bien.) Utilice ``make htmldocs`` o ``make pdfdocs`` + para comprobar el :ref:`kernel-doc ` y solucionar + cualquier problema. + +12) Ha sido probado con ``CONFIG_PREEMPT``, ``CONFIG_DEBUG_PREEMPT``, + ``CONFIG_DEBUG_SLAB``, ``CONFIG_DEBUG_PAGEALLOC``, ``CONFIG_DEBUG_MUTEXES``, + ``CONFIG_DEBUG_SPINLOCK``, ``CONFIG_DEBUG_ATOMIC_SLEEP`` + ``CONFIG_PROVE_RCU`` y ``CONFIG_DEBUG_OBJECTS_RCU_HEAD`` todos + habilitados simultáneamente. + +13) Ha sido probado en tiempo de compilación y ejecución con y sin + ``CONFIG_SMP`` y ``CONFIG_PREEMPT``. + +14) Todas las rutas de código se han ejercido con todas las + características de lockdep habilitadas. + +15) Todas las nuevas entradas de ``/proc`` están documentadas en + ``Documentation/``. + +16) Todos los nuevos parámetros de arranque del kernel están documentados + en ``Documentation/admin-guide/kernel-parameters.rst``. + +17) Todos los nuevos parámetros del módulo están documentados con + ``MODULE_PARM_DESC()``. + +18) Todas las nuevas interfaces de espacio de usuario están documentadas + en ``Documentation/ABI/``. Consulte ``Documentation/ABI/README`` para + obtener más información. Los parches que cambian las interfaces del + espacio de usuario deben ser CCed a linux-api@vger.kernel.org. + +19) Se ha comprobado con la inyección de al menos errores de asignación + de slab y página. Consulte ``Documentation/fault-injection/``. + + Si el nuevo código es sustancial, la adición de la inyección de + errores específica del subsistema podría ser apropiada. + +20) El nuevo código añadido ha sido compilado con ``gcc -W`` (use + ``make KCFLAGS=-W``). Esto generara mucho ruido per es buena para + encontrar errores como "warning: comparison between signed and unsigned". + +21) Se prueba después de que se haya fusionado en el conjunto de + parches -mm para asegurarse de que siga funcionando con todos los + demás parches en cola y varios cambios en VM, VFS y otros subsistemas. + +22) Todas las barreras de memoria {p.ej., ``barrier()``, ``rmb()``, + ``wmb()``} necesitan un comentario en el código fuente que explique + la lógica de lo que están haciendo y por qué. + +23) Si se añaden algún ioctl en el parche, actualice también + ``Documentation/userspace-api/ioctl/ioctl-number.rst``. + +24) Si su código fuente modificado depende o utiliza cualquiera de las + API o características del kernel que están relacionadas con los + siguientes símbolos ``Kconfig`` entonces pruebe varias compilaciones + con los símbolos ``Kconfig`` relacionados deshabilitados y/o ``=m`` + (si esa opción esta disponible) [no todos estos al mismo tiempo, solo + varias/aleatorias combinaciones de ellos]: + + ``CONFIG_SMP``, ``CONFIG_SYSFS``, ``CONFIG_PROC_FS``, ``CONFIG_INPUT``, ``CONFIG_PCI``, ``CONFIG_BLOCK``, ``CONFIG_PM``, ``CONFIG_MAGIC_SYSRQ`` + ``CONFIG_NET``, ``CONFIG_INET=n`` (pero luego con ``CONFIG_NET=y``). diff --git a/Documentation/translations/zh_CN/arch/loongarch/features.rst b/Documentation/translations/zh_CN/arch/loongarch/features.rst index 82bfac180bdc04..cec38dda8298c1 100644 --- a/Documentation/translations/zh_CN/arch/loongarch/features.rst +++ b/Documentation/translations/zh_CN/arch/loongarch/features.rst @@ -5,4 +5,4 @@ :Original: Documentation/arch/loongarch/features.rst :Translator: Huacai Chen -.. kernel-feat:: $srctree/Documentation/features loongarch +.. kernel-feat:: features loongarch diff --git a/Documentation/translations/zh_CN/arch/mips/features.rst b/Documentation/translations/zh_CN/arch/mips/features.rst index da1b956e4a40f6..0d6df97db069bb 100644 --- a/Documentation/translations/zh_CN/arch/mips/features.rst +++ b/Documentation/translations/zh_CN/arch/mips/features.rst @@ -10,4 +10,4 @@ .. _cn_features: -.. kernel-feat:: $srctree/Documentation/features mips +.. kernel-feat:: features mips diff --git a/Documentation/translations/zh_CN/arch/riscv/boot.rst b/Documentation/translations/zh_CN/arch/riscv/boot.rst new file mode 100644 index 00000000000000..0c261909581962 --- /dev/null +++ b/Documentation/translations/zh_CN/arch/riscv/boot.rst @@ -0,0 +1,155 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. include:: ../../disclaimer-zh_CN.rst + +:Original: Documentation/arch/riscv/boot.rst + +:翻译: + + 龙进 Jin Long + +======================== +RISC-V内核启动要求和限制 +======================== + +:Author: Alexandre Ghiti +:Date: 23 May 2023 + +这份文档描述了RISC-V内核对引导加载程序和固件的期望,以及任何开发者在接触 +早期启动过程时必须牢记的约束。在这份文档中, ``早期启动过程`` 指的是在最 +终虚拟映射设置之前运行的任何代码。 + +内核预加载的要求和限制 +====================== + +RISC-V内核对引导加载程序和平台固件有以下要求: + +寄存器状态 +---------- + +RISC-V内核期望: + + * ``$a0`` 应包含当前核心的hartid。 + * ``$a1`` 应包含内存中设备树的地址。 + +CSR 寄存器状态 +-------------- + +RISC-V内核期望: + + * ``$satp = 0``: 如果存在MMU,必须将其禁用。 + +为常驻固件保留的内存 +-------------------- + +RISC-V内核在直接映射中不能映射任何常驻内存或用PMPs保护的内存, +因此固件必须根据设备树规范 和/或 UEFI规范正确标记这些区域。 + +内核的位置 +---------- + +RISC-V内核期望被放置在PMD边界(对于rv64为2MB对齐,对于rv32为4MB对齐)。 +请注意,如果不是这样,EFI stub 将重定位内核。 + +硬件描述 +-------- + +固件可以将设备树或ACPI表传递给RISC-V内核。 + +设备树可以直接从前一阶段通过$a1寄存器传递给内核,或者在使用UEFI启动时, +可以通过EFI配置表传递。 + +ACPI表通过EFI配置表传递给内核。在这种情况下,EFI stub 仍然会创建一个 +小的设备树。请参阅下面的"EFI stub 和设备树"部分,了解这个设备树的详细 +信息。 + +内核入口 +-------- + +在SMP系统中,有两种方法可以进入内核: + +- ``RISCV_BOOT_SPINWAIT``:固件在内核中释放所有的hart,一个hart赢 + 得抽奖并执行早期启动代码,而其他的hart则停在那里等待初始化完成。这种 + 方法主要用于支持没有SBI HSM扩展和M模式RISC-V内核的旧固件。 +- ``有序启动``:固件只释放一个将执行初始化阶段的hart,然后使用SBI HSM + 扩展启动所有其他的hart。有序启动方法是启动RISC-V内核的首选启动方法, + 因为它可以支持CPU热插拔和kexec。 + +UEFI +---- + +UEFI 内存映射 +~~~~~~~~~~~~~ + +使用UEFI启动时,RISC-V内核将只使用EFI内存映射来填充系统内存。 + +UEFI固件必须解析 ``/reserved-memory`` 设备树节点的子节点,并遵守设备 +树规范,将这些子节点的属性( ``no-map`` 和 ``reusable`` )转换为其正 +确的EFI等价物(参见设备树规范v0.4-rc1的"3.5.4/reserved-memory和 +UEFI"部分)。 + +RISCV_EFI_BOOT_PROTOCOL +~~~~~~~~~~~~~~~~~~~~~~~ + +使用UEFI启动时,EFI stub 需要引导hartid以便将其传递给 ``$a1`` 中的 +RISC-V内核。EFI stub使用以下方法之一获取引导hartid: + +- ``RISCV_EFI_BOOT_PROTOCOL`` (**首选**)。 +- ``boot-hartid`` 设备树子节点(**已弃用**)。 + +任何新的固件都必须实现 ``RISCV_EFI_BOOT_PROTOCOL``,因为基于设备树 +的方法现已被弃用。 + +早期启动的要求和约束 +==================== + +RISC-V内核的早期启动过程遵循以下约束: + +EFI stub 和设备树 +----------------- + +使用UEFI启动时,EFI stub 会用与arm64相同的参数补充(或创建)设备树, +这些参数在Documentation/arch/arm/uefi.rst中的 +"UEFI kernel supporton ARM"段落中有描述。 + +虚拟映射安装 +------------ + +在RISC-V内核中,虚拟映射的安装分为两步进行: + +1. ``setup_vm()`` 在 ``early_pg_dir`` 中安装一个临时的内核映射,这 + 允许发现系统内存。 此时只有内核文本/数据被映射。在建立这个映射时, + 不能进行分配(因为系统内存还未知),所以``early_pg_dir``页表是静 + 态分配的(每个级别只使用一个表)。 + +2. ``setup_vm_final()`` 在 ``swapper_pg_dir`` 中创建最终的内核映 + 射,并利用发现的系统内存 创建线性映射。在建立这个映射时,内核可以 + 分配内存,但不能直接访问它(因为直接映射还不存在),所以它使用fixmap + 区域的临时映射来访问新分配的页表级别。 + +为了让 ``virt_to_phys()`` 和 ``phys_to_virt()`` 能够正确地将直接 +映射地址转换为物理地址,它们需要知道DRAM的起始位置。这发生在步骤1之后, +就在步骤2安装直接映射之前(参见arch/riscv/mm/init.c中的 +``setup_bootmem()`` 函数)。在安装最终虚拟映射之前使用这些宏时必须 +仔细检查。 + +通过fixmap进行设备树映射 +------------------------ + +由于 ``reserved_mem`` 数组是用 ``setup_vm()`` 建立的虚拟地址初始化 +的,并且与``setup_vm_final()``建立的映射一起使用,RISC-V内核使用 +fixmap区域来映射设备树。这确保设备树可以通过两种虚拟映射访问。 + +Pre-MMU执行 +----------- + +在建立第一个虚拟映射之前,需要运行一些代码。这些包括第一个虚拟映射的安装本身, +早期替代方案的修补,以及内核命令行的早期解析。这些代码必须非常小心地编译,因为: + +- ``-fno-pie``:这对于使用``-fPIE``的可重定位内核是必需的,否则,任何对 + 全局符号的访问都将通过 GOT进行,而GOT只是虚拟地重新定位。 +- ``-mcmodel=medany``:任何对全局符号的访问都必须是PC相对的,以避免在设 + 置MMU之前发生任何重定位。 +- *所有* 的仪表化功能也必须被禁用(包括KASAN,ftrace和其他)。 + +由于使用来自不同编译单元的符号需要用这些标志编译该单元,我们建议尽可能不要使用 +外部符号。 diff --git a/Documentation/translations/zh_CN/arch/riscv/index.rst b/Documentation/translations/zh_CN/arch/riscv/index.rst index 3b041c1161698b..96573459105e76 100644 --- a/Documentation/translations/zh_CN/arch/riscv/index.rst +++ b/Documentation/translations/zh_CN/arch/riscv/index.rst @@ -17,6 +17,7 @@ RISC-V 体系结构 .. toctree:: :maxdepth: 1 + boot boot-image-header vm-layout patch-acceptance diff --git a/Documentation/translations/zh_CN/core-api/printk-basics.rst b/Documentation/translations/zh_CN/core-api/printk-basics.rst index 59c6efb3fc41b9..cafa01bccff290 100644 --- a/Documentation/translations/zh_CN/core-api/printk-basics.rst +++ b/Documentation/translations/zh_CN/core-api/printk-basics.rst @@ -100,7 +100,7 @@ printk()的用法通常是这样的:: 为了调试,还有两个有条件编译的宏: pr_debug()和pr_devel(),除非定义了 ``DEBUG`` (或者在pr_debug()的情况下定义了 -``CONFIG_DYNAMIC_DEBUG`` ),否则它们会被编译。 +``CONFIG_DYNAMIC_DEBUG`` ),否则它们不会被编译。 函数接口 diff --git a/Documentation/translations/zh_CN/dev-tools/index.rst b/Documentation/translations/zh_CN/dev-tools/index.rst index 02577c379007ce..c2db3e566b1be8 100644 --- a/Documentation/translations/zh_CN/dev-tools/index.rst +++ b/Documentation/translations/zh_CN/dev-tools/index.rst @@ -14,11 +14,8 @@ 有关测试专用工具的简要概述,参见 Documentation/translations/zh_CN/dev-tools/testing-overview.rst -.. class:: toc-title - - 目录 - .. toctree:: + :caption: 目录 :maxdepth: 2 testing-overview diff --git a/Documentation/translations/zh_CN/dev-tools/testing-overview.rst b/Documentation/translations/zh_CN/dev-tools/testing-overview.rst index 69e7e4cb2002b5..c91f9b60f9f13f 100644 --- a/Documentation/translations/zh_CN/dev-tools/testing-overview.rst +++ b/Documentation/translations/zh_CN/dev-tools/testing-overview.rst @@ -3,7 +3,7 @@ .. include:: ../disclaimer-zh_CN.rst :Original: Documentation/dev-tools/testing-overview.rst -:Translator: 胡皓文 Hu Haowen +:Translator: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> ============ 内核测试指南 diff --git a/Documentation/translations/zh_CN/driver-api/gpio/index.rst b/Documentation/translations/zh_CN/driver-api/gpio/index.rst index 9ab64e94aced4c..9a6a14162a6cef 100644 --- a/Documentation/translations/zh_CN/driver-api/gpio/index.rst +++ b/Documentation/translations/zh_CN/driver-api/gpio/index.rst @@ -14,9 +14,8 @@ 通用型输入/输出(GPIO) ======================= -目录: - .. toctree:: + :caption: 目录 :maxdepth: 2 legacy diff --git a/Documentation/translations/zh_CN/driver-api/index.rst b/Documentation/translations/zh_CN/driver-api/index.rst index ba354e1f4e6d4c..92ff1b7fc3d3d9 100644 --- a/Documentation/translations/zh_CN/driver-api/index.rst +++ b/Documentation/translations/zh_CN/driver-api/index.rst @@ -17,11 +17,8 @@ Linux驱动实现者的API指南 内核提供了各种各样的接口来支持设备驱动的开发。这份文档只是对其中一些接口进行了 一定程度的整理——希望随着时间的推移,它能变得更好!可用的小节可以在下面看到。 -.. class:: toc-title - - 目录列表: - .. toctree:: + :caption: 目录列表 :maxdepth: 2 gpio/index diff --git a/Documentation/translations/zh_CN/process/development-process.rst b/Documentation/translations/zh_CN/process/development-process.rst index 30cffe66c0758a..c10d8e2e21eb3d 100644 --- a/Documentation/translations/zh_CN/process/development-process.rst +++ b/Documentation/translations/zh_CN/process/development-process.rst @@ -8,9 +8,10 @@ 内核开发过程指南 ================ -内容: +本文档的目的是帮助开发人员(及其经理)以最小的挫折感与开发社区合作。它试图记录这个社区如何以一种不熟悉Linux内核开发(或者实际上是自由软件开发)的人可以访问的方式工作。虽然这里有一些技术资料,但这是一个面向过程的讨论,不需要深入了解内核编程就可以理解。 .. toctree:: + :caption: 内容 :numbered: :maxdepth: 2 @@ -22,5 +23,3 @@ 6.Followthrough 7.AdvancedTopics 8.Conclusion - -本文档的目的是帮助开发人员(及其经理)以最小的挫折感与开发社区合作。它试图记录这个社区如何以一种不熟悉Linux内核开发(或者实际上是自由软件开发)的人可以访问的方式工作。虽然这里有一些技术资料,但这是一个面向过程的讨论,不需要深入了解内核编程就可以理解。 diff --git a/Documentation/translations/zh_CN/process/index.rst b/Documentation/translations/zh_CN/process/index.rst index a1a35f88f4ae08..3ca02d281be04d 100644 --- a/Documentation/translations/zh_CN/process/index.rst +++ b/Documentation/translations/zh_CN/process/index.rst @@ -5,10 +5,11 @@ .. include:: ../disclaimer-zh_CN.rst -:Original: :ref:`Documentation/process/index.rst ` -:Translator: Alex Shi +:Original: Documentation/process/index.rst -.. _cn_process_index: +:翻译: + + Alex Shi ======================== 与Linux 内核社区一起工作 @@ -23,29 +24,55 @@ .. toctree:: :maxdepth: 1 + license-rules howto code-of-conduct code-of-conduct-interpretation + development-process submitting-patches programming-language coding-style - development-process + maintainer-pgp-guide email-clients - license-rules kernel-enforcement-statement kernel-driver-statement +TODOLIST: + +* handling-regressions +* maintainer-handbooks + +安全方面, 请阅读: + +.. toctree:: + :maxdepth: 1 + + embargoed-hardware-issues + +TODOLIST: + +* security-bugs + 其它大多数开发人员感兴趣的社区指南: .. toctree:: :maxdepth: 1 - submit-checklist stable-api-nonsense - stable-kernel-rules management-style - embargoed-hardware-issues + stable-kernel-rules + submit-checklist + +TODOLIST: + +* changes +* kernel-docs +* deprecated +* maintainers +* researcher-guidelines +* contribution-maturity-model + 这些是一些总体性技术指南,由于不大好分类而放在这里: @@ -54,6 +81,16 @@ magic-number volatile-considered-harmful + ../arch/riscv/patch-acceptance + ../core-api/unaligned-memory-access + +TODOLIST: + +* applying-patches +* backporting +* adding-syscalls +* botching-up-ioctls +* clang-format .. only:: subproject and html diff --git a/Documentation/translations/zh_CN/process/magic-number.rst b/Documentation/translations/zh_CN/process/magic-number.rst index 4a92ebb619ee41..4e4aeaca796c3a 100644 --- a/Documentation/translations/zh_CN/process/magic-number.rst +++ b/Documentation/translations/zh_CN/process/magic-number.rst @@ -1,58 +1,67 @@ -.. _cn_magicnumbers: - .. include:: ../disclaimer-zh_CN.rst -:Original: :ref:`Documentation/process/magic-number.rst ` +:Original: Documentation/process/magic-number.rst + +:翻译: -如果想评论或更新本文的内容,请直接发信到LKML。如果你使用英文交流有困难的话,也可 -以向中文版维护者求助。如果本翻译更新不及时或者翻译存在问题,请联系中文版维护者:: + 贾威威 Jia Wei Wei - 中文版维护者: 贾威威 Jia Wei Wei - 中文版翻译者: 贾威威 Jia Wei Wei - 中文版校译者: 贾威威 Jia Wei Wei +:校译: + + 司延腾 Yanteng Si Linux 魔术数 ============ -这个文件是有关当前使用的魔术值注册表。当你给一个结构添加了一个魔术值,你也应该把这个魔术值添加到这个文件,因为我们最好把用于各种结构的魔术值统一起来。 +这个文件是有关当前使用的魔术值注册表。当你给一个结构体添加了一个魔术值,你也 +应该把这个魔术值添加到这个文件,因为我们最好把用于各种结构体的魔术值统一起来。 -使用魔术值来保护内核数据结构是一个非常好的主意。这就允许你在运行期检查(a)一个结构是否已经被攻击,或者(b)你已经给一个例行程序通过了一个错误的结构。后一种情况特别地有用---特别是当你通过一个空指针指向结构体的时候。tty源码,例如,经常通过特定驱动使用这种方法并且反复地排列特定方面的结构。 +使用魔术值来保护内核数据结构是一个 **非常好的主意** 。这就允许你在运行时检 +查一个结构体(a)是否已经被攻击,或者(b)你已经给一个例程传递了一个错误的结构 +体。最后一种情况特别地有用---特别是当你通过一个空指针指向结构体的时候。例如, +tty源码经常通过特定驱动使用这种方法用来反复地排列特定方面的结构体。 -使用魔术值的方法是在结构的开始处声明的,如下:: +使用魔术值的方法是在结构体的开头声明它们,如下:: struct tty_ldisc { int magic; ... }; -当你以后给内核添加增强功能的时候,请遵守这条规则!这样就会节省数不清的调试时间,特别是一些古怪的情况,例如,数组超出范围并且重新写了超出部分。遵守这个规则,这些情况可以被快速地,安全地避免。 +当你以后给内核添加增强功能的时候,请遵守这条规则!这样就会节省数不清的调试 +时间,特别是一些古怪的情况,例如,数组超出范围并且覆盖写了超出部分。利用这 +个规则,这些情况可以被快速地,安全地检测到这些案例。 + +变更日志:: - Theodore Ts'o - 31 Mar 94 + Theodore Ts'o + 31 Mar 94 -给当前的Linux 2.1.55添加魔术表。 + 给当前的Linux 2.1.55添加魔术表。 - Michael Chastain - - 22 Sep 1997 + Michael Chastain + + 22 Sep 1997 -现在应该最新的Linux 2.1.112.因为在特性冻结期间,不能在2.2.x前改变任何东西。这些条目被数域所排序。 + 现在应该最新的Linux 2.1.112.因为在特性冻结期间,不能在2.2.x前改变任 + 何东西。这些条目被数域所排序。 - Krzysztof G.Baranowski - - 29 Jul 1998 + Krzysztof G.Baranowski + + 29 Jul 1998 -更新魔术表到Linux 2.5.45。刚好越过特性冻结,但是有可能还会有一些新的魔术值在2.6.x之前融入到内核中。 + 更新魔术表到Linux 2.5.45。刚好越过特性冻结,但是有可能还会有一些新的魔 + 术值在2.6.x之前融入到内核中。 - Petr Baudis - - 03 Nov 2002 + Petr Baudis + + 03 Nov 2002 -更新魔术表到Linux 2.5.74。 + 更新魔术表到Linux 2.5.74。 - Fabian Frederick - - 09 Jul 2003 + Fabian Frederick + + 09 Jul 2003 ===================== ================ ======================== ========================================== 魔术数名 数字 结构 文件 diff --git a/Documentation/translations/zh_CN/process/maintainer-pgp-guide.rst b/Documentation/translations/zh_CN/process/maintainer-pgp-guide.rst new file mode 100644 index 00000000000000..eb12694a4c5938 --- /dev/null +++ b/Documentation/translations/zh_CN/process/maintainer-pgp-guide.rst @@ -0,0 +1,789 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/process/maintainer-pgp-guide.rst + +:翻译: + + 司延腾 Yanteng Si + +:校译: + + +=================== +内核维护者 PGP 指南 +=================== + +:作者: Konstantin Ryabitsev + +本文档面向 Linux 内核开发者,特别是子系统维护人员。文档中含有Linux 基金 +会发布的更通用的 `保护代码完整性`_ 指南中讨论的内容子集。阅读该文档,以更 +深入地讨论本指南中提到的一些主题。 + +.. _`保护代码完整性`: https://github.com/lfit/itpol/blob/master/protecting-code-integrity.md + +PGP 在 Linux 内核开发中的作用 +============================= + +PGP 有助于确保 Linux 内核开发社区产出代码的完整性,并在较小程度上,通过 +PGP 签名的电子邮件交换,在开发者之间建立可信的交流渠道。 + +Linux 内核源代码主要有两种(维护)方式: + +- 分布式源仓库 (git) +- 定期发布快照 (tarballs) + +git 仓库和 tarball 都带有创建官方内核版本的内核开发者的 PGP 签名。这 +些签名提供了加密保证,即保证 kernel.org 或任何其他镜像提供的可下载版本 +与这些开发者在其工作站上的版本相同。为此: + +- git 仓库在所有标签上提供 PGP 签名 +- tarball 为所有下载提供独立的 PGP 签名 + +信任开发者,不要信基础设施 +-------------------------- + +自从 2011 年 kernel.org 核心系统遭到入侵以来,内核存档项目的主要运行原 +则就是假定基础设施的任何部分都可能随时受到入侵。因此,管理员特意采取措施, +强调必须始终信任开发者,不能信任代码托管基础设施,无论后者的安全实践有多好。 + +上述指导原则正是需要本指南的原因。希望确保通过对开发者的信任,我们不会简 +单地将未来潜在安全事件的责任归咎于其他人。目的是提供一套指导开发者可以用 +来创建安全的工作环境并保护用于建立 Linux 内核本身完整性的 PGP 密钥。 + +PGP 工具 +======== + +使用 GnuPG 2.2 或更高版本 +------------------------- + +默认情况下,你的发行版应该已经安装了 GnuPG,你只需要验证你使用的是相当新的 +版本即可。要检查,请运行:: + + $ gpg --version | head -n1 + +如果你有 2.2 或更高版本,那么你就可以开始了。如果你的版本早于 2.2,则本指 +南中的某些命令可能不起作用。 + +配置 gpg-agent 选项 +~~~~~~~~~~~~~~~~~~~ + +GnuPG agent是一个辅助工具,每当你使用该命令时,它都会自动启动gpg,并在 +后台运行,目的是缓存私钥密码。你应该知道两个选项,以便调整密码何时从缓存 +过期: + +- ``default-cache-ttl`` (秒): 如果在生命周期结束之前再次使用相同的 + 密钥,倒计时将重置为另一段时间。默认值为 600(10 分钟)。 +- ``max-cache-ttl`` (秒): 无论你自输入初始密码以来多久使用过密钥, + 如果最大生存时间倒计时结束,你都必须再次输入密码。默认值为 30 分钟。 + +如果你发现这些默认值太短(或太长),你可以编辑 ``~/.gnupg/gpg-agent.conf`` +文件以设置你自己的值:: + + # 常规ttl设置为30分钟,最大ttl设置为2小时 + default-cache-ttl 1800 + max-cache-ttl 7200 + +.. note:: + + 不需要在 shell 会话开始时手动启动 gpg-agent。你可能需要检查 + rc 文件来删除旧版本 GnuPG 中的所有内容,因为它可能不再做正确 + 的事情。 + +保护你的 PGP 密钥 +================= + +本指南假定你已经拥有用于 Linux 内核开发目的的 PGP 密钥。如果你还没 +有,请参阅前面提到的 "`保护代码完整性`_" 文档,以获取有关如何创建新 +密钥的指导。 + +如果你当前的密钥低于 2048 位 (RSA),你还应该创建一个新密钥。 + +了解 PGP 子密钥 +--------------- + +PGP 密钥很少由单个密钥对组成 - 通常它是独立子密钥的集合,这些子密钥 +可根据其功能用于不同的目的,并在创建时分配。PGP 定义了密钥可以具有的 +四种功能: + +- **[S]** 密钥可用于签名 +- **[E]** 密钥可用于加密 +- **[A]** 密钥可用于身份验证 +- **[C]** 密钥可用于验证其他密钥 + +具有 **[C]** 功能的密钥通常称为“主”密钥,但该术语具有误导性,因为 +它意味着可以使用Certify密钥来代替同一链上的任何其他子密钥(如物理 +“主密钥”可用于打开为其他钥匙制作的锁)。由于情况并非如此,本指南将 +其称为“认证密钥”以避免任何歧义。 + +充分理解以下内容至关重要: + +1. 所有子项彼此完全独立。如果你丢失了私有子密钥,则无法从链上的任何 + 其他私钥恢复或重新创建它。 +2. 除 Certify 密钥外,可以有多个具有相同功能的子密钥(例如,你可 + 以有 2 个有效的加密子密钥、3 个有效的签名子密钥,但只有 1 个有 + 效的认证子密钥)。所有子密钥都是完全独立的——加密到一个 **[E]** + 子密钥的信息(messages)无法使用你可能拥有的任何其他 **[E]** + 子密钥解密。 +3. 单个子密钥可能具有多种功能(例如,你的 **[C]** 密钥也可以是你 + 的 **[S]** 密钥)。 + +携带 **[C]** (证明)能力的密钥是唯一可以用来指示与其他密钥的关系 +的密钥。仅 **[C]** 密钥可用于: + +- 添加或撤销具有 S/E/A 功能的其他密钥(子密钥) +- 添加、更改或撤销与密钥关联的身份 (uid) +- 添加或更改其本身或任何子密钥的到期日期 +- 出于信任网络的目的签署其他人的密钥 + +默认情况下,GnuPG 在生成新密钥时创建以下内容: + +- 一个子密钥同时具有认证和签名功能 (**[SC]**) +- 具有加密功能的单独子密钥 (**[E]**) + +如果你在生成密钥时使用了默认参数,那么这就是你将得到的。你可以通过 +运行命令来验证,例如: ``gpg --list-secret-keys`` + +:: + + sec ed25519 2022-12-20 [SC] [expires: 2024-12-19] + 000000000000000000000000AAAABBBBCCCCDDDD + uid [ultimate] Alice Dev + ssb cv25519 2022-12-20 [E] [expires: 2024-12-19] + +在 ``sec`` 这行下面长长的一行就是你的密钥指纹-无论在下文任何地方 +看到 ``[fpr]`` 都指的是这40个字符。 + +确保你的密码强度高 +------------------ + +GnuPG 在将私钥存储到磁盘之前使用密码对其进行加密。这样,即使你的 +``.gnupg`` 目录全部泄露或被盗,攻击者在没有事先获取密码来解密的 +情况下也无法使用你的私钥。 + +你的私钥受到强密码保护是绝对必要的。要设置或更改它,请使用:: + + $ gpg --change-passphrase [fpr] + +创建一个单独的签名子密钥 +------------------------ + +我们的目的是通过将你的证书密钥移动到离线媒介来保护它,因此如果你只 +有组合的 **[SC]** 密钥,那么你应该创建一个单独的签名子密钥:: + + $ gpg --quick-addkey [fpr] ed25519 sign + +.. note:: GnuPG 中的 ECC 支持 + + 请注意,如果你打算使用不支持 ED25519 ECC 密钥的硬件密钥,则 + 应选择“nistp256”或“ed25519”。请参阅下面有关推荐硬件设备的 + 部分。 + + +备份你的证书密钥以进行灾难恢复 +------------------------------ + +你的 PGP 密钥上来自其他开发者的签名越多,出于灾难恢复的原因,你就越 +有理由创建一个位于数字媒体之外的备份版本。 + +创建私钥的可打印硬拷贝的最佳方法是使用 ``paperkey`` 为此目的编写 +的软件。有关输出格式及其相对于其他解决方案的优势的更多详细信息,请参 +阅 ``paperkey`` 参考资料。大多数发行版都应该已经打包了 Paperkey。 + +运行以下命令来创建私钥的硬拷贝备份:: + + $ gpg --export-secret-key [fpr] | paperkey -o /tmp/key-backup.txt + +打印出该文件(或将输出直接传输到 lpr),然后用笔在纸的边缘写下你的密 +码。 **强烈建议这样做**,因为密钥打印输出仍然使用该密码进行加密,并且 +如果你更改了它,你将不记得创建备份时它曾经是什么 - *保证*。 + +将生成的打印输出和手写密码放入信封中,并存放在安全且受到良好保护的地 +方,最好远离你的家,例如银行保险柜。 + +.. note:: + + 你的打印机可能不再是连接到并行端口的简单哑设备,但由于输出仍然使 + 用你的密码进行加密,因此即使“云端打印”的现代打印机也应该保持相 + 对安全的操作 + +备份整个 GnuPG 目录 +------------------- + +.. warning:: + + **!!!不要跳过这个步骤!!!** + +如果你需要恢复 PGP 密钥,拥有一个随时可用的备份非常重要。这与我们 +所做的灾难级准备不同 ``paperkey`` 。每当你需要使用你的证书密钥时, +例如在会议和峰会后更改你自己的密钥或签署其他人的密钥时,你还将依赖 +这些外部副本。 + +首先获取一个小型 USB “拇指” 驱动器(最好是两个!),用于备份目的。 +你需要使用 LUKS 对其进行加密——请参阅你的发行版文档以了解如何完成 +此操作。 + +对于加密密码,你可以使用与 PGP 密钥相同的密码。 + +加密过程完成后,重新插入 USB 驱动器并确保其正确安装。将整个 ``.gnupg`` +目录复制到加密存储:: + + $ cp -a ~/.gnupg /media/disk/foo/gnupg-backup + +你现在应该测试一下,确保一切依然能正常工作:: + + $ gpg --homedir=/media/disk/foo/gnupg-backup --list-key [fpr] + +如果没有出现任何错误,那么就可以开始了。卸下 USB 驱动器,给它贴上 +明显的标签,这样下次需要使用随机 USB 驱动器时就不会把它吹走,然后 +放在安全的地方 - 但不要太远,因为你每次都需要使用它时不时地用于诸 +如编辑身份、添加或撤销子密钥或签署其他人的密钥之类的事情。 + +从你的 homedir 中删除 Certify 密钥 +---------------------------------- + +我们的主目录中的文件并没有我们想象的那么受到保护。它们可以通过多种 +不同的方式泄露或被盗: + +- 在制作快速主目录备份以设置新工作站时意外发生 +- 系统管理员的疏忽或恶意 +- 通过不安全的备份 +- 通过桌面应用程序(浏览器、pdf 查看器等)中的恶意软件 +- 跨越国界时通过胁迫 + +使用良好的密码短语保护你的密钥极大地有助于降低上述任何风险,但密码 +短语可以通过键盘记录器、肩窥或任何其他方式发现。因此,建议的设置是 +从主目录中删除你的证书密钥并将其存储在离线存储中。 + +.. warning:: + + 请参阅上一节并确保你已完整备份 GnuPG 目录。如果你没有可用的 + 备份,我们要做的事情将使你的密钥毫无用处! + +首先,确定你的证书密钥的keygrip:: + + $ gpg --with-keygrip --list-key [fpr] + +输出将是这样的:: + + pub ed25519 2022-12-20 [SC] [expires: 2022-12-19] + 000000000000000000000000AAAABBBBCCCCDDDD + Keygrip = 1111000000000000000000000000000000000000 + uid [ultimate] Alice Dev + sub cv25519 2022-12-20 [E] [expires: 2022-12-19] + Keygrip = 2222000000000000000000000000000000000000 + sub ed25519 2022-12-20 [S] + Keygrip = 3333000000000000000000000000000000000000 + +找到该线 ``pub`` 下方的keygrip项 (位于“认证密钥指纹”的正下方)。 +这将直接对应于你``~/.gnupg`` 目录中的一个文件:: + + $ cd ~/.gnupg/private-keys-v1.d + $ ls + 1111000000000000000000000000000000000000.key + 2222000000000000000000000000000000000000.key + 3333000000000000000000000000000000000000.key + +你所要做的只是删除与证书密钥 keygrip 对应的 .key 文件:: + + $ cd ~/.gnupg/private-keys-v1.d + $ rm 1111000000000000000000000000000000000000.key + +现在,如果你发出命令 ``--list-secret-keys`` ,它将显示证书密钥丢 +失( 表示 ``#`` 它不可用):: + + $ gpg --list-secret-keys + sec# ed25519 2022-12-20 [SC] [expires: 2024-12-19] + 000000000000000000000000AAAABBBBCCCCDDDD + uid [ultimate] Alice Dev + ssb cv25519 2022-12-20 [E] [expires: 2024-12-19] + ssb ed25519 2022-12-20 [S] + +你还应该删除 ``~/.gnupg``目录中的所有 ``secring.gpg`` 文件 ,这些 +文件可能是以前版本的 GnuPG 留下的。 + +如果你没有“private-keys-v1.d”目录 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +如果你没有 ``~/.gnupg/private-keys-v1.d`` 目录,那么你的密钥仍存 +储在 GnuPG v1 使用的旧文件 ``secring.gpg`` 中。对密钥进行任何更改 +(例如更改密码或添加子密钥)应该会自动转换旧 ``secring.gpg`` 格式以 +供使用 ``private-keys-v1.d`` 。 + +完成此操作后,请确保删除过时的 ``secring.gpg`` 文件,其中仍然包含你 +的私钥。 + + +将子密钥移至专用加密设备 +======================== + +尽管 Certify 密钥现在不会被泄露或被盗,但子密钥仍然位于你的主目录中。 +任何设法获得这些内容的人都将能够解密你的通信或伪造你的签名(如果他们知 +道密码)。此外,每次执行 GnuPG 操作时,密钥都会加载到系统内存中,并 +可能被足够高级的恶意软件(例如 Meltdown 和 Spectre)从那里窃取。 + +完全保护密钥的最佳方法是将它们转移到能够进行智能卡操作的专用硬件设备上。 + +智能卡的好处 +------------ + +智能卡包含一个加密芯片,能够存储私钥并直接在卡本身上执行加密操作。由于 +密钥内容永远不会离开智能卡,因此插入硬件设备的计算机的操作系统无法自行 +检索私钥。这与我们之前用于备份目的的加密 USB 存储设备有很大不同——当 +USB 设备插入并安装时,操作系统能够访问私钥内容。 + +使用外部加密 USB 介质并不能替代具有智能卡功能的设备。 + +可用的智能卡设备 +---------------- + +除非你的所有笔记本电脑和工作站都有智能卡读卡器,否则最简单的方法是获 +取实现智能卡功能的专用 USB 设备。有多种选择:: + +- `Nitrokey Start`_: 开放硬件和免费软件,日本基于FSI的 `Gnuk` 。 + 少数支持 ED25519 ECC 密钥的商用设备之一,但提供的安全功能最少 + (例如防篡改或某些旁路攻击)。 +- `Nitrokey Pro 2`_: 与 Nitrokey Start 类似,但更防篡改并提供 + 更多安全功能。Pro 2 支持 ECC 加密 (NISTP)。 +- `Yubikey 5`_: 专有硬件和软件,但比 Nitrokey Pro 便宜,并且以 + USB-C 形式提供,对于较新的笔记本电脑更有用。提供额外的安全功能, + 例如 FIDO U2F 等,现在终于支持 NISTP 和 ED25519 ECC 密钥。 + +你的选择将取决于成本、你所在地理区域的货运便利性以及开放/专有硬件考虑 +因素。 + +.. note:: + + 如果你位列于 MAINTAINERS 中或在 kernel.org 上拥有帐户,则你有 + 资格获得Linux 基金会提供的_`qualify for a free Nitrokey Start` 。 + +.. _`Nitrokey Start`: https://shop.nitrokey.com/shop/product/nitrokey-start-6 +.. _`Nitrokey Pro 2`: https://shop.nitrokey.com/shop/product/nkpr2-nitrokey-pro-2-3 +.. _`Yubikey 5`: https://www.yubico.com/products/yubikey-5-overview/ +.. _Gnuk: https://www.fsij.org/doc-gnuk/ +.. _`qualify for a free Nitrokey Start`: https://www.kernel.org/nitrokey-digital-tokens-for-kernel-developers.html + +配置你的智能卡设备 +------------------ + +当你将智能卡设备插入任何现代 Linux 工作站时,它就应该可以正常工作 +(TM)。你可以通过运行来验证它:: + + $ gpg --card-status + +如果你看到完整的智能卡详细信息,那么你就可以开始了。不幸的是,对所有 +可能无法正常工作的原因进行故障排除超出了本指南的范围。如果你在使该卡 +与 GnuPG 配合使用时遇到问题,请通过常规支持渠道寻求帮助。 + +要配置你的智能卡,你需要使用 GnuPG 菜单系统,因为没有方便的命令行开 +关:: + + $ gpg --card-edit + [...omitted...] + gpg/card> admin + Admin commands are allowed + gpg/card> passwd + +你应该设置用户 PIN (1)、管理员 PIN (3) 和重置代码 (4)。请确保将 +这些信息记录并存储在安全的地方,尤其是管理员 PIN 码和重置代码(它允 +许你完全擦除智能卡)。你很少需要使用管理员 PIN 码,如果你不记录它, +你将不可避免地忘记它是什么。 + +回到主卡菜单,你还可以设置其他值(例如姓名、性别、登录数据等),但这 +不是必需的,并且如果你丢失智能卡,还会泄露有关智能卡的信息。 + +.. note:: + + 尽管名称为“PIN”,但卡上的用户 PIN 和管理员 PIN 都不需要是数字。 + +.. warning:: + + 某些设备可能要求你将子密钥移至设备上,然后才能更改密码。请检查设 + 备制造商提供的文档。 + +将子密钥移至你的智能卡 +---------------------- + +退出卡菜单(使用“q”)并保存所有更改。接下来,让我们将子密钥移至智能卡 +上。对于大多数操作,你将需要 PGP 密钥密码和卡的管理员 PIN:: + + $ gpg --edit-key [fpr] + + Secret subkeys are available. + + pub ed25519/AAAABBBBCCCCDDDD + created: 2022-12-20 expires: 2024-12-19 usage: SC + trust: ultimate validity: ultimate + ssb cv25519/1111222233334444 + created: 2022-12-20 expires: never usage: E + ssb ed25519/5555666677778888 + created: 2017-12-07 expires: never usage: S + [ultimate] (1). Alice Dev + + gpg> + +使用 ``--edit-key`` 使我们再次进入菜单模式,你会注意到按键列表有点 +不同。从现在开始,所有命令都在此菜单模式内完成,如 所示 ``gpg>``。 + +首先,让我们选择要放入卡上的密钥 - 你可以通过键入 ``key 1`` (它是 +列表中的第一个, **[E]** 子密钥)来完成此操作: + + gpg> key 1 + +在输出中,你现在在 **[E]** 子密钥应该看到 ``ssb*`` 。意味着这个子 +密钥当前被选中。它用作切换键,这意味着如果你再次输入 ``key 1`` , +``*`` 将会消失并且该键将不再被选择。 + +现在,让我们将该密钥移至智能卡上:: + + gpg> keytocard + Please select where to store the key: + (2) Encryption key + Your selection? 2 + +由于它是我们的 **[E]** 密钥,因此将其放入加密槽中是有意义的。当你提 +交选择时,系统将首先提示你输入 PGP 密钥密码,然后输入管理员 PIN 码。 +如果命令返回且没有错误,则你的密钥已被移动。 + +**重要提示**:现在再次键入 ``key 1`` 以取消选择第一个键,并 ``key 2`` +选择 **[S]** 密钥:: + + gpg> key 1 + gpg> key 2 + gpg> keytocard + Please select where to store the key: + (1) Signature key + (3) Authentication key + Your selection? 1 + +你可以使用 **[S]** 密钥进行签名和身份验证,但我们希望确保它位于签名槽中, +因此选择 (1)。跟之前一样,如果你的命令返回且没有错误,则操作成功:: + + gpg> q + Save changes? (y/N) y + +保存更改将删除你从主目录移动到卡上的密钥(但这没关系,因为我们还有备份, +让我们需要替换智能卡时再次执行此操作)。 + +验证密钥是否已移动 +~~~~~~~~~~~~~~~~~~ + +如果你现在执行 ``--list-secret-keys`` ,你将看到输出中存在细微的差异:: + + $ gpg --list-secret-keys + sec# ed25519 2022-12-20 [SC] [expires: 2024-12-19] + 000000000000000000000000AAAABBBBCCCCDDDD + uid [ultimate] Alice Dev + ssb> cv25519 2022-12-20 [E] [expires: 2024-12-19] + ssb> ed25519 2022-12-20 [S] + +在 ``ssb>``中的 ``>`` 输出意味着子密钥只能在智能卡上可用,如果你返回 +密钥目录并查看那里的内容,你会注意到 ``.key`` 那里的文件已被存根替换:: + + $ cd ~/.gnupg/private-keys-v1.d + $ strings *.key | grep 'private-key' + +输出应包含 ``shadowed-private-key`` 指示这些文件只是存根,实际内容 +位于智能卡上。 + +验证智能卡是否正常工作 +~~~~~~~~~~~~~~~~~~~~~~ + +要验证智能卡是否按预期工作,你可以创建签名:: + + $ echo "Hello world" | gpg --clearsign > /tmp/test.asc + $ gpg --verify /tmp/test.asc + +在你的第一条命令执行时,应该会询问你智能卡的PIN,然后在你运行 +``gpg --verify`` 后显示"Good signature"。 + +恭喜,你已成功使窃取你的数字开发者身份变得极其困难! + +其他常见的 GnuPG 操作 +--------------------- + +以下是你需要使用 PGP 密钥执行的一些常见操作的快速参考。 + +安装你的安全离线存储 +~~~~~~~~~~~~~~~~~~~~ + +你将需要你的证书密钥来执行以下任何操作,因此你首先需要安装备份离线存储 +并告诉 GnuPG 使用它:: + + $ export GNUPGHOME=/media/disk/foo/gnupg-backup + $ gpg --list-secret-keys + +你需要确保你看到 ``sec`` 而不是 ``sec#`` 在输出中( ``#`` 意味着 +密钥不可用并且你仍在使用常规主目录位置)。 + +延长密钥有效期 +~~~~~~~~~~~~~~ + +证书密钥的默认到期日期为自创建之日起 2 年。这样做既是出于安全原因,也 +是为了使过时的密钥最终从密钥服务器中消失。 + +要将密钥的有效期从当前日期延长一年,只需运行:: + + $ gpg --quick-set-expire [fpr] 1y + +如果更容易记住,你也可以使用特定日期(例如你的生日、1 月 1 日或加拿大 +国庆日):: + + $ gpg --quick-set-expire [fpr] 2025-07-01 + +请记住将更新后的密钥发送回密钥服务器:: + + $ gpg --send-key [fpr] + +进行任何更改后更新你的工作目录 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +使用离线存储对密钥进行任何更改后,你需要将这些更改导入回常规工作目录 +中:: + + $ gpg --export | gpg --homedir ~/.gnupg --import + $ unset GNUPGHOME + +通过 ssh 使用 gpg-agent +~~~~~~~~~~~~~~~~~~~~~~~ + +如果你需要在远程系统上签署标签或提交,你可以通过 ssh 转发你的 +gpg-agent。 + +请参考 GnuPG wiki 上提供的说明: + +- `Agent通过SSH转发`_ + +如果你可以修改远程端的 sshd 服务器设置,则工作会更顺利。 + +.. _`Agent通过SSH转发`: https://wiki.gnupg.org/AgentForwarding + +将 PGP 与 Git 结合使用 +====================== + +Git 的核心功能之一是它的分散性——一旦将仓库克隆到你的系统,你就拥有该 +项目的完整历史记录,包括其所有标签、提交和分支。然而,随着数百个克隆仓 +库的出现,人们如何验证他们的 linux.git 副本没有被恶意第三方篡改? + +或者,如果在代码中发现后门,并且提交中的“Author”行表示它是由你完成的, +而你非常确定 `自己与它无关`_ ,会发生什么? + +为了解决这两个问题,Git 引入了 PGP 集成。签名的标签通过确保其内容与创 +建标签的开发人员的工作站上的内容完全相同来证明仓库的完整性,而签名的提 +交使其他人几乎不可能在无法访问你的 PGP 密钥的情况下冒充你。 + +.. _`自己与它无关`: https://github.com/jayphelps/git-blame-someone-else + +配置 git 使用你的 PGP 密钥 +-------------------------- + +如果你的密钥环中只有一个密钥,那么你实际上不需要执行任何额外操作,因为 +它会成为你的默认密钥。但是,如果你碰巧有多个密钥,你可以告诉 git 应该 +使用哪个密钥(``[fpr]`` 是你密钥的指纹):: + + $ git config --global user.signingKey [fpr] + +如何使用签名标签 +---------------- + +要创建签名标签,只需将 ``-s`` 开关传递给 tag 命令:: + + $ git tag -s [tagname] + +我们的建议是始终签署 git 标签,因为这可以让其他开发人员确保他们从中提 +取的 git 仓库没有被恶意更改。 + +如何验证签名标签 +~~~~~~~~~~~~~~~~ + +要验证签名标签,只需使用以下 ``verify-tag`` 命令:: + + $ git verify-tag [tagname] + +如果你从项目仓库的另一个分支中拉取标签,git 应该自动验证你拉取的顶 +部的签名,并在合并操作期间向你显示结果:: + + $ git pull [url] tags/sometag + +合并消息将包含如下内容:: + + Merge tag 'sometag' of [url] + + [Tag message] + + # gpg: Signature made [...] + # gpg: Good signature from [...] + +如果你正在验证其他人的 git 标签,那么你将需要导入他们的 PGP 密钥。 +请参阅下面的":ref:`身份验证`"部分。 + +配置 git 始终对带注释的标签(annotated tags)进行签名annotated tags +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +如果你要创建带注释的标签,你很可能会想要对其进行签名。要强制 git 始终签 +署带注释的标签,你可以设置一个全局配置选项:: + + $ git config --global tag.forceSignAnnotated true + +如何使用签名的提交 +------------------ + +创建签名提交很容易,但在 Linux 内核开发中使用它们要困难得多,因为它依赖 +于发送到邮件列表的补丁,并且此工作流程不保留 PGP 提交签名。此外,当重新 +调整仓库以匹配上游时,甚至你自己的 PGP 提交签名最终也会被丢弃。因此,大 +多数内核开发人员不会费心签署他们的提交,并且会忽略他们在工作中依赖的任何 +外部仓库中的签名提交。 + +但是,如果你的工作 git 树在某些 git 托管服务(kernel.org、 +infradead.org、ozlabs.org 或其他)上公开可用,那么建议你签署所有 git +提交,即使上游开发人员不直接受益于这种做法。 + +我们推荐这样做的原因如下: + +1. 如果需要执行代码取证或跟踪代码来源,即使是外部维护的带有 PGP 提交签名 + 的树对于此类问题也很有价值。 +2. 如果你需要重新克隆本地仓库(例如,在磁盘故障后),这可以让你在恢复工 + 作之前轻松验证仓库的完整性。 +3. 如果有人需要挑选你的提交,这可以让他们在应用之前快速验证其完整性。 + +创建签名提交 +~~~~~~~~~~~~ + +要创建签名提交,你只需将 ``-S`` 标志传递给 ``git commit`` 命令(由于 +与另一个标志冲突,所以它是大写的 ``-S`` ):: + + $ git commit -S + +配置 git 始终对提交进行签名 +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +你可以告诉 git 总是签署提交:: + + git config --global commit.gpgSign true + +.. note:: + + 确保 ``gpg-agent`` 在打开此功能之前进行配置。 + +.. _身份验证: + + +如何使用签名补丁 +---------------- + +可以使用你的 PGP 密钥来签署发送到内核开发人员邮件列表的补丁。由于现有的 +电子邮件签名机制(PGP-Mime 或 PGP-inline)往往会导致常规代码审查任务 +出现问题,因此你应该使用为此创建的 kernel.org 工具,该工具将加密证明签 +名放入消息标头中(a-la DKIM): + +- `Patatt Patch Attestation`_ + +.. _`Patatt Patch Attestation`: https://pypi.org/project/patatt/ + +安装和配置 patatt +~~~~~~~~~~~~~~~~~ + +Patatt 已针对许多发行版进行了打包,因此请先检查那里。你还可以使用 +“ ``pip install patatt`` ”从 pypi 安装它。 + +如果你已经使用 git 配置了 PGP 密钥(通过``user.signingKey`` 配置参数), +则 patatt 不需要进一步配置。你可以通过在所需的仓库中安装 git-send-email +钩子来开始签署补丁:: + + patatt install-hook + +现在,你使用 ``git send-email`` 发送的任何补丁都将自动使用你的加密签 +名进行签名 + +检查 patatt 签名 +~~~~~~~~~~~~~~~~ + +如果你用于 ``b4`` 检索和应用补丁,那么它将自动尝试验证它遇到的所有 +DKIM 和 patatt 签名,例如:: + + $ b4 am 20220720205013.890942-1-broonie@kernel.org + [...] + Checking attestation on all messages, may take a moment... + --- + ✓ [PATCH v1 1/3] kselftest/arm64: Correct buffer allocation for SVE Z registers + ✓ [PATCH v1 2/3] arm64/sve: Document our actual ABI for clearing registers on syscall + ✓ [PATCH v1 3/3] kselftest/arm64: Enforce actual ABI for SVE syscalls + --- + ✓ Signed: openpgp/broonie@kernel.org + ✓ Signed: DKIM/kernel.org + +.. note:: + + Patatt 和 b4 仍在积极开发中,你应该检查这些项目的最新文档以了解任 + 何新功能或更新功能。 + +如何验证内核开发者身份 +====================== + +签署标签和提交很容易,但是如何验证用于签署某项内容的密钥是否属于实际的内 +核开发人员而不是恶意冒名顶替者? + +使用 WKD 和 DANE 配置auto-key-locate(自动密钥检索) +---------------------------------------------------- + +如果你还没有广泛收集其他开发人员的公钥,那么你可以依靠密钥自动发现和自动 +检索来快速启动你的密钥环。如果从头开始创建自己的信任 Web 的预期太令人畏 +惧, GnuPG 可以借助其他委托信任技术(即 DNSSEC 和 TLS)来帮助你继续前 +进。 + +将以下内容添加到你的 ``~/.gnupg/gpg.conf``:: + + auto-key-locate wkd,dane,local + auto-key-retrieve + +基于 DNS 的命名实体身份验证(“DANE”)是一种在 DNS 中发布公钥并使用 +DNSSEC 签名区域保护它们的方法。Web 密钥目录(“WKD”)是使用 https +查找来达到相同目的的替代方法。当使用 DANE 或 WKD 查找公钥时,GnuPG +将分别验证 DNSSEC 或 TLS 证书,然后将自动检索的公钥添加到本地密钥环。 + +Kernel.org 为所有拥有 kernel.org 帐户的开发人员发布 WKD。一旦你的 +``gpg.conf`` 中进行了上述更改,你就可以自动检索 Linus Torvalds 和 +Greg Kroah-Hartman 的密钥(如果你还没有它们):: + + $ gpg --locate-keys torvalds@kernel.org gregkh@kernel.org + +如果你有 kernel.org 帐户,那么你应该 `添加 kernel.org UID 到你的密钥中`_ +添加到你的密钥中,以使 WKD 对其他内核开发人员更有用。 + +.. _`添加 kernel.org UID 到你的密钥中`: https://korg.wiki.kernel.org/userdoc/mail#adding_a_kernelorg_uid_to_your_pgp_key + +信任网 (WOT) 与首次使用信任 (TOFU) +----------------------------------- + +PGP 结合了称为“信任网”的信任委托机制。从本质上讲,这是一次尝试取代 +HTTPS/TLS 世界对集中式证书颁发机构的需求。PGP 将这一责任留给每个 +用户,而不是由各种软件制造商规定谁应该是你值得信赖的认证实体。 + +不幸的是,很少有人了解信任网是如何运作的。虽然它仍然是 OpenPGP 规 +范的一个重要方面,但最新版本的 GnuPG(2.2 及更高版本)已经实现了 +一种称为“首次使用信任”(TOFU) 的替代机制。你可以将 TOFU 视为“类似 +SSH 的信任方法”。使用 SSH,第一次连接到远程系统时,其密钥指纹会被 +记录并记住。如果将来密钥发生变化,SSH 客户端将向你发出警报并拒绝连 +接,迫使你决定是否选择信任更改后的密钥。同样,第一次导入某人的 PGP +密钥时,它被认为是有效的。如果将来的任何时候 GnuPG 遇到具有相同标 +识的另一个密钥,则先前导入的密钥和新密钥都将被标记为无效,你将需要手 +动确定保留哪一个。 + +我们建议你使用 TOFU+PGP 组合信任模型(这是 GnuPG v2 中新默认的)。 +若要设置它,在 ``~/.gnupg/gpg.conf`` 中添加(或修改) +``trust-model`` 设置:: + + trust-model tofu+pgp + +使用 kernel.org 信任网仓库 +-------------------------- + +Kernel.org 维护着一个包含开发人员公钥的 git 仓库,作为复制密钥服 +务器网络的替代品,而在过去几年中,该网络几乎已经陷入黑暗。有关如何将 +该仓库设置为公钥来源的完整文档可以在此处找到: + +- `内核开发者密钥环`_ + +如果你是内核开发人员,请考虑提交你的密钥以将其包含到该密钥环中。 + +.. _`内核开发者密钥环`: https://korg.docs.kernel.org/pgpkeys.html diff --git a/Documentation/translations/zh_CN/process/submit-checklist.rst b/Documentation/translations/zh_CN/process/submit-checklist.rst index 3d6ee21c74ae07..10536b74aeeccb 100644 --- a/Documentation/translations/zh_CN/process/submit-checklist.rst +++ b/Documentation/translations/zh_CN/process/submit-checklist.rst @@ -53,8 +53,7 @@ Linux内核补丁提交检查单 9) 通过 sparse 清查。 (参见 Documentation/translations/zh_CN/dev-tools/sparse.rst ) -10) 使用 ``make checkstack`` 和 ``make namespacecheck`` 并修复他们发现的任何 - 问题。 +10) 使用 ``make checkstack`` 并修复他们发现的任何问题。 .. note:: diff --git a/Documentation/translations/zh_CN/scheduler/sched-design-CFS.rst b/Documentation/translations/zh_CN/scheduler/sched-design-CFS.rst index 3076402406c48e..abc6709ec3b26a 100644 --- a/Documentation/translations/zh_CN/scheduler/sched-design-CFS.rst +++ b/Documentation/translations/zh_CN/scheduler/sched-design-CFS.rst @@ -80,7 +80,7 @@ p->se.vruntime。一旦p->se.vruntime变得足够大,其它的任务将成为 CFS使用纳秒粒度的计时,不依赖于任何jiffies或HZ的细节。因此CFS并不像之前的调度器那样 有“时间片”的概念,也没有任何启发式的设计。唯一可调的参数(你需要打开CONFIG_SCHED_DEBUG)是: - /sys/kernel/debug/sched/min_granularity_ns + /sys/kernel/debug/sched/base_slice_ns 它可以用来将调度器从“桌面”模式(也就是低时延)调节为“服务器”(也就是高批处理)模式。 它的默认设置是适合桌面的工作负载。SCHED_BATCH也被CFS调度器模块处理。 @@ -147,7 +147,7 @@ array)。 这个函数的行为基本上是出队,紧接着入队,除非compat_yield sysctl被开启。在那种情况下, 它将调度实体放在红黑树的最右端。 - - check_preempt_curr(...) + - wakeup_preempt(...) 这个函数检查进入可运行状态的任务能否抢占当前正在运行的任务。 @@ -155,9 +155,9 @@ array)。 这个函数选择接下来最适合运行的任务。 - - set_curr_task(...) + - set_next_task(...) - 这个函数在任务改变调度类或改变任务组时被调用。 + 这个函数在任务改变调度类,改变任务组时,或者任务被调度时被调用。 - task_tick(...) diff --git a/Documentation/translations/zh_CN/scheduler/schedutil.rst b/Documentation/translations/zh_CN/scheduler/schedutil.rst index d1ea6800752012..7c8d87f21c4221 100644 --- a/Documentation/translations/zh_CN/scheduler/schedutil.rst +++ b/Documentation/translations/zh_CN/scheduler/schedutil.rst @@ -89,16 +89,15 @@ r_cpu被定义为当前CPU的最高性能水平与系统中任何其它CPU的最 - Documentation/translations/zh_CN/scheduler/sched-capacity.rst:"1. CPU Capacity + 2. Task utilization" -UTIL_EST / UTIL_EST_FASTUP -========================== +UTIL_EST +======== 由于周期性任务的平均数在睡眠时会衰减,而在运行时其预期利用率会和睡眠前相同, 因此它们在再次运行后会面临(DVFS)的上涨。 为了缓解这个问题,(一个默认使能的编译选项)UTIL_EST驱动一个无限脉冲响应 (Infinite Impulse Response,IIR)的EWMA,“运行”值在出队时是最高的。 -另一个默认使能的编译选项UTIL_EST_FASTUP修改了IIR滤波器,使其允许立即增加, -仅在利用率下降时衰减。 +UTIL_EST滤波使其在遇到更高值时立刻增加,而遇到低值时会缓慢衰减。 进一步,运行队列的(可运行任务的)利用率之和由下式计算: diff --git a/Documentation/translations/zh_CN/userspace-api/index.rst b/Documentation/translations/zh_CN/userspace-api/index.rst index 5dc0f2e69c176a..5b14721c82645b 100644 --- a/Documentation/translations/zh_CN/userspace-api/index.rst +++ b/Documentation/translations/zh_CN/userspace-api/index.rst @@ -17,11 +17,8 @@ Linux 内核用户空间API指南 在代码树中仍然可以找到有关用户空间的部分信息。这个手册意在成为这些信息 聚集的地方。 -.. class:: toc-title - - 目录 - .. toctree:: + :caption: 目录 :maxdepth: 2 no_new_privs diff --git a/Documentation/translations/zh_TW/IRQ.txt b/Documentation/translations/zh_TW/IRQ.txt index fd78ca72029808..8115a7618307f1 100644 --- a/Documentation/translations/zh_TW/IRQ.txt +++ b/Documentation/translations/zh_TW/IRQ.txt @@ -7,7 +7,7 @@ help. Contact the Chinese maintainer if this translation is outdated or if there is a problem with the translation. Maintainer: Eric W. Biederman -Traditional Chinese maintainer: Hu Haowen +Traditional Chinese maintainer: Hu Haowen <2023002089@link.tyut.edu.cn> --------------------------------------------------------------------- Documentation/core-api/irq/index.rst 的繁體中文翻譯 @@ -16,9 +16,9 @@ Documentation/core-api/irq/index.rst 的繁體中文翻譯 者翻譯存在問題,請聯繫繁體中文版維護者。 英文版維護者: Eric W. Biederman -繁體中文版維護者: 胡皓文 Hu Haowen -繁體中文版翻譯者: 胡皓文 Hu Haowen -繁體中文版校譯者: 胡皓文 Hu Haowen +繁體中文版維護者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> +繁體中文版翻譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> +繁體中文版校譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 以下爲正文 diff --git a/Documentation/translations/zh_TW/admin-guide/README.rst b/Documentation/translations/zh_TW/admin-guide/README.rst index 4cb581f5994ae9..a6e34c200ea32c 100644 --- a/Documentation/translations/zh_TW/admin-guide/README.rst +++ b/Documentation/translations/zh_TW/admin-guide/README.rst @@ -7,7 +7,7 @@ :譯者: 吳想成 Wu XiangCheng - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> Linux內核6.x版本 ========================================= diff --git a/Documentation/translations/zh_TW/admin-guide/bug-bisect.rst b/Documentation/translations/zh_TW/admin-guide/bug-bisect.rst index 3f10a9f8f2235b..1efe913b8da062 100644 --- a/Documentation/translations/zh_TW/admin-guide/bug-bisect.rst +++ b/Documentation/translations/zh_TW/admin-guide/bug-bisect.rst @@ -7,7 +7,7 @@ :譯者: 吳想成 Wu XiangCheng - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 二分(bisect)缺陷 +++++++++++++++++++ diff --git a/Documentation/translations/zh_TW/admin-guide/bug-hunting.rst b/Documentation/translations/zh_TW/admin-guide/bug-hunting.rst index 631fd2650929ab..c139ec99cab1a0 100644 --- a/Documentation/translations/zh_TW/admin-guide/bug-hunting.rst +++ b/Documentation/translations/zh_TW/admin-guide/bug-hunting.rst @@ -7,7 +7,7 @@ :譯者: 吳想成 Wu XiangCheng - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 追蹤缺陷 ========= diff --git a/Documentation/translations/zh_TW/admin-guide/clearing-warn-once.rst b/Documentation/translations/zh_TW/admin-guide/clearing-warn-once.rst index 6961006b4a2db6..a3e82ff9daac7f 100644 --- a/Documentation/translations/zh_TW/admin-guide/clearing-warn-once.rst +++ b/Documentation/translations/zh_TW/admin-guide/clearing-warn-once.rst @@ -2,7 +2,7 @@ .. include:: ../disclaimer-zh_TW.rst -:Translator: 胡皓文 Hu Haowen +:Translator: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 清除 WARN_ONCE -------------- diff --git a/Documentation/translations/zh_TW/admin-guide/cpu-load.rst b/Documentation/translations/zh_TW/admin-guide/cpu-load.rst index cc046f3b7ffa2d..4c25a2105b399d 100644 --- a/Documentation/translations/zh_TW/admin-guide/cpu-load.rst +++ b/Documentation/translations/zh_TW/admin-guide/cpu-load.rst @@ -2,7 +2,7 @@ .. include:: ../disclaimer-zh_TW.rst -:Translator: 胡皓文 Hu Haowen +:Translator: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> ======== CPU 負載 diff --git a/Documentation/translations/zh_TW/admin-guide/index.rst b/Documentation/translations/zh_TW/admin-guide/index.rst index aba8939351e07a..9335c0e9105d47 100644 --- a/Documentation/translations/zh_TW/admin-guide/index.rst +++ b/Documentation/translations/zh_TW/admin-guide/index.rst @@ -4,7 +4,7 @@ :Original: :doc:`../../../admin-guide/index` :Translator: Alex Shi - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> Linux 內核用戶和管理員指南 ========================== diff --git a/Documentation/translations/zh_TW/admin-guide/init.rst b/Documentation/translations/zh_TW/admin-guide/init.rst index be6e34f5f7fa21..4cef1994c65003 100644 --- a/Documentation/translations/zh_TW/admin-guide/init.rst +++ b/Documentation/translations/zh_TW/admin-guide/init.rst @@ -7,7 +7,7 @@ :譯者: 吳想成 Wu XiangCheng - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 解釋“No working init found.”啓動掛起消息 ========================================= diff --git a/Documentation/translations/zh_TW/admin-guide/reporting-issues.rst b/Documentation/translations/zh_TW/admin-guide/reporting-issues.rst index fe5a5a07d51a70..bc132b25f2aed8 100644 --- a/Documentation/translations/zh_TW/admin-guide/reporting-issues.rst +++ b/Documentation/translations/zh_TW/admin-guide/reporting-issues.rst @@ -9,7 +9,7 @@ :譯者: 吳想成 Wu XiangCheng - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 報告問題 diff --git a/Documentation/translations/zh_TW/admin-guide/security-bugs.rst b/Documentation/translations/zh_TW/admin-guide/security-bugs.rst index c0e9fc247695bb..cfe1e58e116be3 100644 --- a/Documentation/translations/zh_TW/admin-guide/security-bugs.rst +++ b/Documentation/translations/zh_TW/admin-guide/security-bugs.rst @@ -7,7 +7,7 @@ :譯者: 吳想成 Wu XiangCheng - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 安全缺陷 ========= diff --git a/Documentation/translations/zh_TW/admin-guide/tainted-kernels.rst b/Documentation/translations/zh_TW/admin-guide/tainted-kernels.rst index 47629f6b05de41..0d8046576d04a8 100644 --- a/Documentation/translations/zh_TW/admin-guide/tainted-kernels.rst +++ b/Documentation/translations/zh_TW/admin-guide/tainted-kernels.rst @@ -7,7 +7,7 @@ :譯者: 吳想成 Wu XiangCheng - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 受污染的內核 ------------- diff --git a/Documentation/translations/zh_TW/admin-guide/unicode.rst b/Documentation/translations/zh_TW/admin-guide/unicode.rst index a2b48b5d0a645d..f43edb2b5ed069 100644 --- a/Documentation/translations/zh_TW/admin-guide/unicode.rst +++ b/Documentation/translations/zh_TW/admin-guide/unicode.rst @@ -7,7 +7,7 @@ :譯者: 吳想成 Wu XiangCheng - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> Unicode(統一碼)支持 ====================== diff --git a/Documentation/translations/zh_TW/arch/arm64/amu.rst b/Documentation/translations/zh_TW/arch/arm64/amu.rst index 1b451eae2beeba..3726c1671ab6ec 100644 --- a/Documentation/translations/zh_TW/arch/arm64/amu.rst +++ b/Documentation/translations/zh_TW/arch/arm64/amu.rst @@ -5,7 +5,7 @@ :Original: :ref:`Documentation/arch/arm64/amu.rst ` Translator: Bailu Lin - Hu Haowen + Hu Haowen <2023002089@link.tyut.edu.cn> ================================== AArch64 Linux 中擴展的活動監控單元 diff --git a/Documentation/translations/zh_TW/arch/arm64/booting.txt b/Documentation/translations/zh_TW/arch/arm64/booting.txt index be0de91ecebd6b..f1ac96370ace7c 100644 --- a/Documentation/translations/zh_TW/arch/arm64/booting.txt +++ b/Documentation/translations/zh_TW/arch/arm64/booting.txt @@ -10,7 +10,7 @@ or if there is a problem with the translation. M: Will Deacon zh_CN: Fu Wei -zh_TW: Hu Haowen +zh_TW: Hu Haowen <2023002089@link.tyut.edu.cn> C: 55f058e7574c3615dea4615573a19bdb258696c6 --------------------------------------------------------------------- Documentation/arch/arm64/booting.rst 的中文翻譯 @@ -23,7 +23,7 @@ Documentation/arch/arm64/booting.rst 的中文翻譯 中文版維護者: 傅煒 Fu Wei 中文版翻譯者: 傅煒 Fu Wei 中文版校譯者: 傅煒 Fu Wei -繁體中文版校譯者: 胡皓文 Hu Haowen +繁體中文版校譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 本文翻譯提交時的 Git 檢出點爲: 55f058e7574c3615dea4615573a19bdb258696c6 以下爲正文 diff --git a/Documentation/translations/zh_TW/arch/arm64/elf_hwcaps.rst b/Documentation/translations/zh_TW/arch/arm64/elf_hwcaps.rst index d2c1c2f2381298..cada25303e8d46 100644 --- a/Documentation/translations/zh_TW/arch/arm64/elf_hwcaps.rst +++ b/Documentation/translations/zh_TW/arch/arm64/elf_hwcaps.rst @@ -5,7 +5,7 @@ :Original: :ref:`Documentation/arch/arm64/elf_hwcaps.rst ` Translator: Bailu Lin - Hu Haowen + Hu Haowen <2023002089@link.tyut.edu.cn> ================ ARM64 ELF hwcaps diff --git a/Documentation/translations/zh_TW/arch/arm64/hugetlbpage.rst b/Documentation/translations/zh_TW/arch/arm64/hugetlbpage.rst index a17858c978d622..b6849935e02858 100644 --- a/Documentation/translations/zh_TW/arch/arm64/hugetlbpage.rst +++ b/Documentation/translations/zh_TW/arch/arm64/hugetlbpage.rst @@ -5,7 +5,7 @@ :Original: :ref:`Documentation/arch/arm64/hugetlbpage.rst ` Translator: Bailu Lin - Hu Haowen + Hu Haowen <2023002089@link.tyut.edu.cn> ===================== ARM64中的 HugeTLBpage diff --git a/Documentation/translations/zh_TW/arch/arm64/index.rst b/Documentation/translations/zh_TW/arch/arm64/index.rst index a62b5f06b66c51..86014346792e52 100644 --- a/Documentation/translations/zh_TW/arch/arm64/index.rst +++ b/Documentation/translations/zh_TW/arch/arm64/index.rst @@ -4,7 +4,7 @@ :Original: :ref:`Documentation/arch/arm64/index.rst ` :Translator: Bailu Lin - Hu Haowen + Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_arm64_index: diff --git a/Documentation/translations/zh_TW/arch/arm64/legacy_instructions.txt b/Documentation/translations/zh_TW/arch/arm64/legacy_instructions.txt index 7d1f0593d7cae8..5c664555a71aae 100644 --- a/Documentation/translations/zh_TW/arch/arm64/legacy_instructions.txt +++ b/Documentation/translations/zh_TW/arch/arm64/legacy_instructions.txt @@ -11,7 +11,7 @@ or if there is a problem with the translation. Maintainer: Punit Agrawal Suzuki K. Poulose Chinese maintainer: Fu Wei -Traditional Chinese maintainer: Hu Haowen +Traditional Chinese maintainer: Hu Haowen <2023002089@link.tyut.edu.cn> --------------------------------------------------------------------- Documentation/arch/arm64/legacy_instructions.rst 的中文翻譯 @@ -26,7 +26,7 @@ Documentation/arch/arm64/legacy_instructions.rst 的中文翻譯 中文版維護者: 傅煒 Fu Wei 中文版翻譯者: 傅煒 Fu Wei 中文版校譯者: 傅煒 Fu Wei -繁體中文版校譯者:胡皓文 Hu Haowen +繁體中文版校譯者:胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 以下爲正文 --------------------------------------------------------------------- diff --git a/Documentation/translations/zh_TW/arch/arm64/memory.txt b/Documentation/translations/zh_TW/arch/arm64/memory.txt index e41c518e71c6b9..6ee2239c293fa6 100644 --- a/Documentation/translations/zh_TW/arch/arm64/memory.txt +++ b/Documentation/translations/zh_TW/arch/arm64/memory.txt @@ -10,7 +10,7 @@ or if there is a problem with the translation. Maintainer: Catalin Marinas Chinese maintainer: Fu Wei -Traditional Chinese maintainer: Hu Haowen +Traditional Chinese maintainer: Hu Haowen <2023002089@link.tyut.edu.cn> --------------------------------------------------------------------- Documentation/arch/arm64/memory.rst 的中文翻譯 @@ -24,7 +24,7 @@ Documentation/arch/arm64/memory.rst 的中文翻譯 中文版維護者: 傅煒 Fu Wei 中文版翻譯者: 傅煒 Fu Wei 中文版校譯者: 傅煒 Fu Wei -繁體中文版校譯者: 胡皓文 Hu Haowen +繁體中文版校譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 以下爲正文 --------------------------------------------------------------------- diff --git a/Documentation/translations/zh_TW/arch/arm64/perf.rst b/Documentation/translations/zh_TW/arch/arm64/perf.rst index 405d5f66964f2c..ce083ba6387227 100644 --- a/Documentation/translations/zh_TW/arch/arm64/perf.rst +++ b/Documentation/translations/zh_TW/arch/arm64/perf.rst @@ -5,7 +5,7 @@ :Original: :ref:`Documentation/arch/arm64/perf.rst ` Translator: Bailu Lin - Hu Haowen + Hu Haowen <2023002089@link.tyut.edu.cn> ============= Perf 事件屬性 diff --git a/Documentation/translations/zh_TW/arch/arm64/silicon-errata.txt b/Documentation/translations/zh_TW/arch/arm64/silicon-errata.txt index 70371807ca835d..16d73b6c309f6f 100644 --- a/Documentation/translations/zh_TW/arch/arm64/silicon-errata.txt +++ b/Documentation/translations/zh_TW/arch/arm64/silicon-errata.txt @@ -10,7 +10,7 @@ or if there is a problem with the translation. M: Will Deacon zh_CN: Fu Wei -zh_TW: Hu Haowen +zh_TW: Hu Haowen <2023002089@link.tyut.edu.cn> C: 1926e54f115725a9248d0c4c65c22acaf94de4c4 --------------------------------------------------------------------- Documentation/arch/arm64/silicon-errata.rst 的中文翻譯 @@ -23,7 +23,7 @@ Documentation/arch/arm64/silicon-errata.rst 的中文翻譯 中文版維護者: 傅煒 Fu Wei 中文版翻譯者: 傅煒 Fu Wei 中文版校譯者: 傅煒 Fu Wei -繁體中文版校譯者: 胡皓文 Hu Haowen +繁體中文版校譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 本文翻譯提交時的 Git 檢出點爲: 1926e54f115725a9248d0c4c65c22acaf94de4c4 以下爲正文 diff --git a/Documentation/translations/zh_TW/arch/arm64/tagged-pointers.txt b/Documentation/translations/zh_TW/arch/arm64/tagged-pointers.txt index 9812d99549ba6f..e86ffa893ef685 100644 --- a/Documentation/translations/zh_TW/arch/arm64/tagged-pointers.txt +++ b/Documentation/translations/zh_TW/arch/arm64/tagged-pointers.txt @@ -10,7 +10,7 @@ or if there is a problem with the translation. Maintainer: Will Deacon Chinese maintainer: Fu Wei -Traditional Chinese maintainer: Hu Haowen +Traditional Chinese maintainer: Hu Haowen <2023002089@link.tyut.edu.cn> --------------------------------------------------------------------- Documentation/arch/arm64/tagged-pointers.rst 的中文翻譯 @@ -22,7 +22,7 @@ Documentation/arch/arm64/tagged-pointers.rst 的中文翻譯 中文版維護者: 傅煒 Fu Wei 中文版翻譯者: 傅煒 Fu Wei 中文版校譯者: 傅煒 Fu Wei -繁體中文版校譯者: 胡皓文 Hu Haowen +繁體中文版校譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 以下爲正文 --------------------------------------------------------------------- diff --git a/Documentation/translations/zh_TW/arch/loongarch/features.rst b/Documentation/translations/zh_TW/arch/loongarch/features.rst index b64e430f55aef3..c2175fd32b54b9 100644 --- a/Documentation/translations/zh_TW/arch/loongarch/features.rst +++ b/Documentation/translations/zh_TW/arch/loongarch/features.rst @@ -5,5 +5,5 @@ :Original: Documentation/arch/loongarch/features.rst :Translator: Huacai Chen -.. kernel-feat:: $srctree/Documentation/features loongarch +.. kernel-feat:: features loongarch diff --git a/Documentation/translations/zh_TW/arch/mips/features.rst b/Documentation/translations/zh_TW/arch/mips/features.rst index f6941042003545..3d3906c4d08e29 100644 --- a/Documentation/translations/zh_TW/arch/mips/features.rst +++ b/Documentation/translations/zh_TW/arch/mips/features.rst @@ -10,5 +10,5 @@ .. _tw_features: -.. kernel-feat:: $srctree/Documentation/features mips +.. kernel-feat:: features mips diff --git a/Documentation/translations/zh_TW/dev-tools/sparse.rst b/Documentation/translations/zh_TW/dev-tools/sparse.rst index 11d64709d6a477..55f0ad2c0beb3f 100644 --- a/Documentation/translations/zh_TW/dev-tools/sparse.rst +++ b/Documentation/translations/zh_TW/dev-tools/sparse.rst @@ -6,19 +6,19 @@ communicating in English you can also ask the Chinese maintainer for help. Contact the Chinese maintainer if this translation is outdated or if there is a problem with the translation. -Traditional Chinese maintainer: Hu Haowen ---------------------------------------------------------------------- +Traditional Chinese maintainer: Hu Haowen <2023002089@link.tyut.edu.cn> +------------------------------------------------------------------------- Documentation/dev-tools/sparse.rst 的繁體中文翻譯 如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文 交流有困難的話,也可以向繁體中文版維護者求助。如果本翻譯更新不及時或 者翻譯存在問題,請聯繫繁體中文版維護者。 -繁體中文版維護者: 胡皓文 Hu Haowen -繁體中文版翻譯者: 胡皓文 Hu Haowen +繁體中文版維護者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> +繁體中文版翻譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 以下爲正文 ---------------------------------------------------------------------- +------------------------------------------------------------------------- Copyright 2004 Linus Torvalds Copyright 2004 Pavel Machek diff --git a/Documentation/translations/zh_TW/dev-tools/testing-overview.rst b/Documentation/translations/zh_TW/dev-tools/testing-overview.rst index fb3f691f46c3fd..3b08aad1da0018 100644 --- a/Documentation/translations/zh_TW/dev-tools/testing-overview.rst +++ b/Documentation/translations/zh_TW/dev-tools/testing-overview.rst @@ -3,7 +3,7 @@ .. include:: ../disclaimer-zh_TW.rst :Original: Documentation/dev-tools/testing-overview.rst -:Translator: 胡皓文 Hu Haowen +:Translator: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> ============ 內核測試指南 diff --git a/Documentation/translations/zh_TW/disclaimer-zh_TW.rst b/Documentation/translations/zh_TW/disclaimer-zh_TW.rst index 0d0ffb1ca4e8ea..28b734c223b6c5 100644 --- a/Documentation/translations/zh_TW/disclaimer-zh_TW.rst +++ b/Documentation/translations/zh_TW/disclaimer-zh_TW.rst @@ -7,5 +7,5 @@ .. note:: 如果您發現本文檔與原始文件有任何不同或者有翻譯問題,請聯繫該文件的譯者, - 或者發送電子郵件給胡皓文以獲取幫助:。 + 或者發送電子郵件給胡皓文以獲取幫助:<2023002089@link.tyut.edu.cn>。 diff --git a/Documentation/translations/zh_TW/filesystems/debugfs.rst b/Documentation/translations/zh_TW/filesystems/debugfs.rst index 78e2e08af95e38..cda7d0e18b9b52 100644 --- a/Documentation/translations/zh_TW/filesystems/debugfs.rst +++ b/Documentation/translations/zh_TW/filesystems/debugfs.rst @@ -14,7 +14,7 @@ Debugfs 中文版維護者: 羅楚成 Chucheng Luo 中文版翻譯者: 羅楚成 Chucheng Luo 中文版校譯者: 羅楚成 Chucheng Luo - 繁體中文版校譯者: 胡皓文 Hu Haowen + 繁體中文版校譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> diff --git a/Documentation/translations/zh_TW/filesystems/index.rst b/Documentation/translations/zh_TW/filesystems/index.rst index d7f9d61f654ce4..88f0e632bfe2e4 100644 --- a/Documentation/translations/zh_TW/filesystems/index.rst +++ b/Documentation/translations/zh_TW/filesystems/index.rst @@ -4,7 +4,7 @@ :Original: :ref:`Documentation/filesystems/index.rst ` :Translator: Wang Wenhu - Hu Haowen + Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_filesystems_index: diff --git a/Documentation/translations/zh_TW/filesystems/sysfs.txt b/Documentation/translations/zh_TW/filesystems/sysfs.txt index ebe90651fc3b91..978462d5fe14cf 100644 --- a/Documentation/translations/zh_TW/filesystems/sysfs.txt +++ b/Documentation/translations/zh_TW/filesystems/sysfs.txt @@ -22,7 +22,7 @@ Documentation/filesystems/sysfs.rst 的中文翻譯 中文版維護者: 傅煒 Fu Wei 中文版翻譯者: 傅煒 Fu Wei 中文版校譯者: 傅煒 Fu Wei -繁體中文版校譯者:胡皓文 Hu Haowen +繁體中文版校譯者:胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 以下爲正文 diff --git a/Documentation/translations/zh_TW/filesystems/virtiofs.rst b/Documentation/translations/zh_TW/filesystems/virtiofs.rst index 6150ad964e78a9..704a0ee44fd27c 100644 --- a/Documentation/translations/zh_TW/filesystems/virtiofs.rst +++ b/Documentation/translations/zh_TW/filesystems/virtiofs.rst @@ -10,7 +10,7 @@ 中文版維護者: 王文虎 Wang Wenhu 中文版翻譯者: 王文虎 Wang Wenhu 中文版校譯者: 王文虎 Wang Wenhu - 繁體中文版校譯者:胡皓文 Hu Haowen + 繁體中文版校譯者:胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> =========================================== virtiofs: virtio-fs 主機<->客機共享文件系統 diff --git a/Documentation/translations/zh_TW/gpio.txt b/Documentation/translations/zh_TW/gpio.txt index 555e4b11a5c7d7..b9b48012c62e59 100644 --- a/Documentation/translations/zh_TW/gpio.txt +++ b/Documentation/translations/zh_TW/gpio.txt @@ -8,7 +8,7 @@ or if there is a problem with the translation. Maintainer: Grant Likely Linus Walleij -Traditional Chinese maintainer: Hu Haowen +Traditional Chinese maintainer: Hu Haowen <2023002089@link.tyut.edu.cn> --------------------------------------------------------------------- Documentation/admin-guide/gpio 的繁體中文翻譯 @@ -18,9 +18,9 @@ Documentation/admin-guide/gpio 的繁體中文翻譯 英文版維護者: Grant Likely Linus Walleij -繁體中文版維護者: 胡皓文 Hu Haowen -繁體中文版翻譯者: 胡皓文 Hu Haowen -繁體中文版校譯者: 胡皓文 Hu Haowen +繁體中文版維護者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> +繁體中文版翻譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> +繁體中文版校譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 以下爲正文 --------------------------------------------------------------------- diff --git a/Documentation/translations/zh_TW/index.rst b/Documentation/translations/zh_TW/index.rst index 563ac9bfc66bda..660a74d2023cd0 100644 --- a/Documentation/translations/zh_TW/index.rst +++ b/Documentation/translations/zh_TW/index.rst @@ -15,7 +15,7 @@ .. note:: 內核文檔繁體中文版的翻譯工作正在進行中。如果您願意並且有時間參與這項工 - 作,歡迎提交補丁給胡皓文 。 + 作,歡迎提交補丁給胡皓文 <2023002089@link.tyut.edu.cn>。 與Linux 內核社區一起工作 ------------------------ diff --git a/Documentation/translations/zh_TW/io_ordering.txt b/Documentation/translations/zh_TW/io_ordering.txt index 03f86840c139ea..00b374092d7ea5 100644 --- a/Documentation/translations/zh_TW/io_ordering.txt +++ b/Documentation/translations/zh_TW/io_ordering.txt @@ -6,7 +6,7 @@ communicating in English you can also ask the Chinese maintainer for help. Contact the Chinese maintainer if this translation is outdated or if there is a problem with the translation. -Traditional Chinese maintainer: Hu Haowen +Traditional Chinese maintainer: Hu Haowen <2023002089@link.tyut.edu.cn> --------------------------------------------------------------------- Documentation/driver-api/io_ordering.rst 的繁體中文翻譯 @@ -14,9 +14,9 @@ Documentation/driver-api/io_ordering.rst 的繁體中文翻譯 交流有困難的話,也可以向繁體中文版維護者求助。如果本翻譯更新不及時或 者翻譯存在問題,請聯繫繁體中文版維護者。 -繁體中文版維護者: 胡皓文 Hu Haowen -繁體中文版翻譯者: 胡皓文 Hu Haowen -繁體中文版校譯者: 胡皓文 Hu Haowen +繁體中文版維護者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> +繁體中文版翻譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> +繁體中文版校譯者: 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 以下爲正文 diff --git a/Documentation/translations/zh_TW/process/1.Intro.rst b/Documentation/translations/zh_TW/process/1.Intro.rst index 6e754ac4896462..345c4cbe9b5555 100644 --- a/Documentation/translations/zh_TW/process/1.Intro.rst +++ b/Documentation/translations/zh_TW/process/1.Intro.rst @@ -11,7 +11,7 @@ :校譯: 吳想成 Wu XiangCheng - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_development_process_intro: diff --git a/Documentation/translations/zh_TW/process/2.Process.rst b/Documentation/translations/zh_TW/process/2.Process.rst index 49385d65c2161f..f45ddba6238ff3 100644 --- a/Documentation/translations/zh_TW/process/2.Process.rst +++ b/Documentation/translations/zh_TW/process/2.Process.rst @@ -11,7 +11,7 @@ :校譯: 吳想成 Wu XiangCheng - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_development_process: diff --git a/Documentation/translations/zh_TW/process/3.Early-stage.rst b/Documentation/translations/zh_TW/process/3.Early-stage.rst index a6959e6350f4fc..a58fc9e0ea9907 100644 --- a/Documentation/translations/zh_TW/process/3.Early-stage.rst +++ b/Documentation/translations/zh_TW/process/3.Early-stage.rst @@ -11,7 +11,7 @@ :校譯: 吳想成 Wu XiangCheng - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_development_early_stage: diff --git a/Documentation/translations/zh_TW/process/4.Coding.rst b/Documentation/translations/zh_TW/process/4.Coding.rst index 7a4e01eabd8172..bdd2abe4daf422 100644 --- a/Documentation/translations/zh_TW/process/4.Coding.rst +++ b/Documentation/translations/zh_TW/process/4.Coding.rst @@ -11,7 +11,7 @@ :校譯: 吳想成 Wu XiangCheng - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_development_coding: diff --git a/Documentation/translations/zh_TW/process/5.Posting.rst b/Documentation/translations/zh_TW/process/5.Posting.rst index d398dda427aa9a..7d66a1c638be1c 100644 --- a/Documentation/translations/zh_TW/process/5.Posting.rst +++ b/Documentation/translations/zh_TW/process/5.Posting.rst @@ -11,7 +11,7 @@ :校譯: 吳想成 Wu XiangCheng - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_development_posting: diff --git a/Documentation/translations/zh_TW/process/6.Followthrough.rst b/Documentation/translations/zh_TW/process/6.Followthrough.rst index bcc885ae1b8ed1..f3b195966632d8 100644 --- a/Documentation/translations/zh_TW/process/6.Followthrough.rst +++ b/Documentation/translations/zh_TW/process/6.Followthrough.rst @@ -11,7 +11,7 @@ :校譯: 吳想成 Wu XiangCheng - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_development_followthrough: diff --git a/Documentation/translations/zh_TW/process/7.AdvancedTopics.rst b/Documentation/translations/zh_TW/process/7.AdvancedTopics.rst index db74d8ca3f3bb8..b449d67e3ad92d 100644 --- a/Documentation/translations/zh_TW/process/7.AdvancedTopics.rst +++ b/Documentation/translations/zh_TW/process/7.AdvancedTopics.rst @@ -11,7 +11,7 @@ :校譯: 吳想成 Wu XiangCheng - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_development_advancedtopics: diff --git a/Documentation/translations/zh_TW/process/8.Conclusion.rst b/Documentation/translations/zh_TW/process/8.Conclusion.rst index a0c00741f9125f..d1634421b62ccd 100644 --- a/Documentation/translations/zh_TW/process/8.Conclusion.rst +++ b/Documentation/translations/zh_TW/process/8.Conclusion.rst @@ -10,7 +10,7 @@ :校譯: 吳想成 Wu XiangCheng - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_development_conclusion: diff --git a/Documentation/translations/zh_TW/process/code-of-conduct-interpretation.rst b/Documentation/translations/zh_TW/process/code-of-conduct-interpretation.rst index 48df918000e993..fbe66b00132227 100644 --- a/Documentation/translations/zh_TW/process/code-of-conduct-interpretation.rst +++ b/Documentation/translations/zh_TW/process/code-of-conduct-interpretation.rst @@ -4,7 +4,7 @@ :Original: :ref:`Documentation/process/code-of-conduct-interpretation.rst ` :Translator: Alex Shi - Hu Haowen + Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_code_of_conduct_interpretation: diff --git a/Documentation/translations/zh_TW/process/code-of-conduct.rst b/Documentation/translations/zh_TW/process/code-of-conduct.rst index a7a31de0352654..d24f1695bd0258 100644 --- a/Documentation/translations/zh_TW/process/code-of-conduct.rst +++ b/Documentation/translations/zh_TW/process/code-of-conduct.rst @@ -4,7 +4,7 @@ :Original: :ref:`Documentation/process/code-of-conduct.rst ` :Translator: Alex Shi - Hu Haowen + Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_code_of_conduct: diff --git a/Documentation/translations/zh_TW/process/coding-style.rst b/Documentation/translations/zh_TW/process/coding-style.rst index 5749363de421f0..f11dbb65ca2158 100644 --- a/Documentation/translations/zh_TW/process/coding-style.rst +++ b/Documentation/translations/zh_TW/process/coding-style.rst @@ -17,7 +17,7 @@ - 管旭東 Xudong Guan - Li Zefan - Wang Chen - - Hu Haowen + - Hu Haowen <2023002089@link.tyut.edu.cn> Linux 內核代碼風格 ================== diff --git a/Documentation/translations/zh_TW/process/development-process.rst b/Documentation/translations/zh_TW/process/development-process.rst index 7d803d3db89eff..305d9472b017ad 100644 --- a/Documentation/translations/zh_TW/process/development-process.rst +++ b/Documentation/translations/zh_TW/process/development-process.rst @@ -4,16 +4,17 @@ :Original: :ref:`Documentation/process/development-process.rst ` :Translator: Alex Shi - Hu Haowen + Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_development_process_main: 內核開發過程指南 ================ -內容: +本文檔的目的是幫助開發人員(及其經理)以最小的挫折感與開發社區合作。它試圖記錄這個社區如何以一種不熟悉Linux內核開發(或者實際上是自由軟體開發)的人可以訪問的方式工作。雖然這裡有一些技術資料,但這是一個面向過程的討論,不需要深入了解內核編程就可以理解。 .. toctree:: + :caption: 內容 :numbered: :maxdepth: 2 @@ -27,4 +28,3 @@ 8.Conclusion 本文檔的目的是幫助開發人員(及其經理)以最小的挫折感與開發社區合作。它試圖記錄這個社區如何以一種不熟悉Linux內核開發(或者實際上是自由軟件開發)的人可以訪問的方式工作。雖然這裏有一些技術資料,但這是一個面向過程的討論,不需要深入瞭解內核編程就可以理解。 - diff --git a/Documentation/translations/zh_TW/process/email-clients.rst b/Documentation/translations/zh_TW/process/email-clients.rst index 55e10d3fc28af9..a5ac9400a9f575 100644 --- a/Documentation/translations/zh_TW/process/email-clients.rst +++ b/Documentation/translations/zh_TW/process/email-clients.rst @@ -15,7 +15,7 @@ - Yinglin Luan - Xiaochen Wang - yaxinsn - - Hu Haowen + - Hu Haowen <2023002089@link.tyut.edu.cn> Linux郵件客戶端配置信息 ======================= diff --git a/Documentation/translations/zh_TW/process/embargoed-hardware-issues.rst b/Documentation/translations/zh_TW/process/embargoed-hardware-issues.rst index b9f6ab7b6666ff..3cce7db2ab7ede 100644 --- a/Documentation/translations/zh_TW/process/embargoed-hardware-issues.rst +++ b/Documentation/translations/zh_TW/process/embargoed-hardware-issues.rst @@ -4,7 +4,7 @@ :Original: :ref:`Documentation/process/embargoed-hardware-issues.rst ` :Translator: Alex Shi - Hu Haowen + Hu Haowen <2023002089@link.tyut.edu.cn> 被限制的硬件問題 ================ diff --git a/Documentation/translations/zh_TW/process/howto.rst b/Documentation/translations/zh_TW/process/howto.rst index 306f5b77b4b8df..80c416483e7386 100644 --- a/Documentation/translations/zh_TW/process/howto.rst +++ b/Documentation/translations/zh_TW/process/howto.rst @@ -16,7 +16,7 @@ 鍾宇 TripleX Chung 陳琦 Maggie Chen 王聰 Wang Cong - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 如何參與Linux內核開發 ===================== diff --git a/Documentation/translations/zh_TW/process/index.rst b/Documentation/translations/zh_TW/process/index.rst index 6a0d98b2f9eebc..65922d9faa2043 100644 --- a/Documentation/translations/zh_TW/process/index.rst +++ b/Documentation/translations/zh_TW/process/index.rst @@ -9,7 +9,7 @@ :Original: :ref:`Documentation/process/index.rst ` :Translator: Alex Shi - Hu Haowen + Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_process_index: diff --git a/Documentation/translations/zh_TW/process/kernel-driver-statement.rst b/Documentation/translations/zh_TW/process/kernel-driver-statement.rst index e967089d2e1f2e..23d5cae9685b47 100644 --- a/Documentation/translations/zh_TW/process/kernel-driver-statement.rst +++ b/Documentation/translations/zh_TW/process/kernel-driver-statement.rst @@ -6,7 +6,7 @@ :Original: :ref:`Documentation/process/kernel-driver-statement.rst ` :Translator: Alex Shi - Hu Haowen + Hu Haowen <2023002089@link.tyut.edu.cn> 內核驅動聲明 ------------ diff --git a/Documentation/translations/zh_TW/process/kernel-enforcement-statement.rst b/Documentation/translations/zh_TW/process/kernel-enforcement-statement.rst index 2861f4a15721e3..524eb4ac26cc8e 100644 --- a/Documentation/translations/zh_TW/process/kernel-enforcement-statement.rst +++ b/Documentation/translations/zh_TW/process/kernel-enforcement-statement.rst @@ -6,7 +6,7 @@ :Original: :ref:`Documentation/process/kernel-enforcement-statement.rst ` :Translator: Alex Shi - Hu Haowen + Hu Haowen <2023002089@link.tyut.edu.cn> Linux 內核執行聲明 ------------------ diff --git a/Documentation/translations/zh_TW/process/license-rules.rst b/Documentation/translations/zh_TW/process/license-rules.rst index 2c43bcf2ac7939..594255856b682b 100644 --- a/Documentation/translations/zh_TW/process/license-rules.rst +++ b/Documentation/translations/zh_TW/process/license-rules.rst @@ -4,7 +4,7 @@ :Original: :ref:`Documentation/process/license-rules.rst ` :Translator: Alex Shi - Hu Haowen + Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_kernel_licensing: diff --git a/Documentation/translations/zh_TW/process/magic-number.rst b/Documentation/translations/zh_TW/process/magic-number.rst index 5657d5cd18d4e6..199cd5d6397391 100644 --- a/Documentation/translations/zh_TW/process/magic-number.rst +++ b/Documentation/translations/zh_TW/process/magic-number.rst @@ -12,7 +12,7 @@ 中文版維護者: 賈威威 Jia Wei Wei 中文版翻譯者: 賈威威 Jia Wei Wei 中文版校譯者: 賈威威 Jia Wei Wei - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> Linux 魔術數 ============ diff --git a/Documentation/translations/zh_TW/process/management-style.rst b/Documentation/translations/zh_TW/process/management-style.rst index f3913e3c159d49..7cb912e8903231 100644 --- a/Documentation/translations/zh_TW/process/management-style.rst +++ b/Documentation/translations/zh_TW/process/management-style.rst @@ -4,7 +4,7 @@ :Original: :ref:`Documentation/process/management-style.rst ` :Translator: Alex Shi - Hu Haowen + Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_managementstyle: diff --git a/Documentation/translations/zh_TW/process/programming-language.rst b/Documentation/translations/zh_TW/process/programming-language.rst index e33389676eeda9..d2c64a5599e83b 100644 --- a/Documentation/translations/zh_TW/process/programming-language.rst +++ b/Documentation/translations/zh_TW/process/programming-language.rst @@ -4,7 +4,7 @@ :Original: :ref:`Documentation/process/programming-language.rst ` :Translator: Alex Shi - Hu Haowen + Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_programming_language: diff --git a/Documentation/translations/zh_TW/process/stable-api-nonsense.rst b/Documentation/translations/zh_TW/process/stable-api-nonsense.rst index 6839d25bb22aa3..4b8597fed5ae5f 100644 --- a/Documentation/translations/zh_TW/process/stable-api-nonsense.rst +++ b/Documentation/translations/zh_TW/process/stable-api-nonsense.rst @@ -12,7 +12,7 @@ 中文版維護者: 鍾宇 TripleX Chung 中文版翻譯者: 鍾宇 TripleX Chung 中文版校譯者: 李陽 Li Yang - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> Linux 內核驅動接口 ================== diff --git a/Documentation/translations/zh_TW/process/stable-kernel-rules.rst b/Documentation/translations/zh_TW/process/stable-kernel-rules.rst index bd82a8ff396946..2f8f064f86294b 100644 --- a/Documentation/translations/zh_TW/process/stable-kernel-rules.rst +++ b/Documentation/translations/zh_TW/process/stable-kernel-rules.rst @@ -15,7 +15,7 @@ 中文版校譯者: - 李陽 Li Yang - Kangkai Yin - - 胡皓文 Hu Haowen + - 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 所有你想知道的事情 - 關於linux穩定版發佈 ======================================== diff --git a/Documentation/translations/zh_TW/process/submit-checklist.rst b/Documentation/translations/zh_TW/process/submit-checklist.rst index 942962d1e2f4c0..43f2e3c5b51483 100644 --- a/Documentation/translations/zh_TW/process/submit-checklist.rst +++ b/Documentation/translations/zh_TW/process/submit-checklist.rst @@ -6,7 +6,7 @@ :Translator: - Alex Shi - Wu XiangCheng - - Hu Haowen + - Hu Haowen <2023002089@link.tyut.edu.cn> .. _tw_submitchecklist: @@ -56,8 +56,7 @@ Linux內核補丁提交檢查單 9) 通過 sparse 清查。 (參見 Documentation/translations/zh_CN/dev-tools/sparse.rst ) -10) 使用 ``make checkstack`` 和 ``make namespacecheck`` 並修復他們發現的任何 - 問題。 +10) 使用 ``make checkstack`` 並修復他們發現的任何問題。 .. note:: diff --git a/Documentation/translations/zh_TW/process/submitting-patches.rst b/Documentation/translations/zh_TW/process/submitting-patches.rst index 8272b3218b5472..99fa0f2fe6f414 100644 --- a/Documentation/translations/zh_TW/process/submitting-patches.rst +++ b/Documentation/translations/zh_TW/process/submitting-patches.rst @@ -14,7 +14,7 @@ :校譯: - 李陽 Li Yang - 王聰 Wang Cong - - 胡皓文 Hu Haowen + - 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 提交補丁:如何讓你的改動進入內核 diff --git a/Documentation/translations/zh_TW/process/volatile-considered-harmful.rst b/Documentation/translations/zh_TW/process/volatile-considered-harmful.rst index a609620affb09e..e2723f3cbbb0b3 100644 --- a/Documentation/translations/zh_TW/process/volatile-considered-harmful.rst +++ b/Documentation/translations/zh_TW/process/volatile-considered-harmful.rst @@ -17,7 +17,7 @@ 中文版校譯者: 張漢輝 Eugene Teo 楊瑞 Dave Young 時奎亮 Alex Shi - 胡皓文 Hu Haowen + 胡皓文 Hu Haowen <2023002089@link.tyut.edu.cn> 爲什麼不應該使用“volatile”類型 ============================== diff --git a/Documentation/usb/gadget-testing.rst b/Documentation/usb/gadget-testing.rst index 29072c166d236a..8cd62c466d20aa 100644 --- a/Documentation/usb/gadget-testing.rst +++ b/Documentation/usb/gadget-testing.rst @@ -448,15 +448,17 @@ Function-specific configfs interface The function name to use when creating the function directory is "ncm". The NCM function provides these attributes in its function directory: - =============== ================================================== - ifname network device interface name associated with this - function instance - qmult queue length multiplier for high and super speed - host_addr MAC address of host's end of this - Ethernet over USB link - dev_addr MAC address of device's end of this - Ethernet over USB link - =============== ================================================== + =============== ================================================== + ifname network device interface name associated with this + function instance + qmult queue length multiplier for high and super speed + host_addr MAC address of host's end of this + Ethernet over USB link + dev_addr MAC address of device's end of this + Ethernet over USB link + max_segment_size Segment size required for P2P connections. This + will set MTU to (max_segment_size - 14 bytes) + =============== ================================================== and after creating the functions/ncm. they contain default values: qmult is 5, dev_addr and host_addr are randomly selected. diff --git a/Documentation/usb/raw-gadget.rst b/Documentation/usb/raw-gadget.rst index 818a1648b38729..59b2132b584d70 100644 --- a/Documentation/usb/raw-gadget.rst +++ b/Documentation/usb/raw-gadget.rst @@ -81,9 +81,6 @@ feature must be kept in the implementation. Potential future improvements ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- Report more events (suspend, resume, etc.) through - ``USB_RAW_IOCTL_EVENT_FETCH``. - - Support ``O_NONBLOCK`` I/O. This would be another mode of operation, where Raw Gadget would not wait until the completion of each USB request. diff --git a/Documentation/userspace-api/dcdbas.rst b/Documentation/userspace-api/dcdbas.rst new file mode 100644 index 00000000000000..309cc57a7c1c8a --- /dev/null +++ b/Documentation/userspace-api/dcdbas.rst @@ -0,0 +1,99 @@ +=================================== +Dell Systems Management Base Driver +=================================== + +Overview +======== + +The Dell Systems Management Base Driver provides a sysfs interface for +systems management software such as Dell OpenManage to perform system +management interrupts and host control actions (system power cycle or +power off after OS shutdown) on certain Dell systems. + +Dell OpenManage requires this driver on the following Dell PowerEdge systems: +300, 1300, 1400, 400SC, 500SC, 1500SC, 1550, 600SC, 1600SC, 650, 1655MC, +700, and 750. Other Dell software such as the open source libsmbios project +is expected to make use of this driver, and it may include the use of this +driver on other Dell systems. + +The Dell libsmbios project aims towards providing access to as much BIOS +information as possible. See http://linux.dell.com/libsmbios/main/ for +more information about the libsmbios project. + + +System Management Interrupt +=========================== + +On some Dell systems, systems management software must access certain +management information via a system management interrupt (SMI). The SMI data +buffer must reside in 32-bit address space, and the physical address of the +buffer is required for the SMI. The driver maintains the memory required for +the SMI and provides a way for the application to generate the SMI. +The driver creates the following sysfs entries for systems management +software to perform these system management interrupts:: + + /sys/devices/platform/dcdbas/smi_data + /sys/devices/platform/dcdbas/smi_data_buf_phys_addr + /sys/devices/platform/dcdbas/smi_data_buf_size + /sys/devices/platform/dcdbas/smi_request + +Systems management software must perform the following steps to execute +a SMI using this driver: + +1) Lock smi_data. +2) Write system management command to smi_data. +3) Write "1" to smi_request to generate a calling interface SMI or + "2" to generate a raw SMI. +4) Read system management command response from smi_data. +5) Unlock smi_data. + + +Host Control Action +=================== + +Dell OpenManage supports a host control feature that allows the administrator +to perform a power cycle or power off of the system after the OS has finished +shutting down. On some Dell systems, this host control feature requires that +a driver perform a SMI after the OS has finished shutting down. + +The driver creates the following sysfs entries for systems management software +to schedule the driver to perform a power cycle or power off host control +action after the system has finished shutting down: + +/sys/devices/platform/dcdbas/host_control_action +/sys/devices/platform/dcdbas/host_control_smi_type +/sys/devices/platform/dcdbas/host_control_on_shutdown + +Dell OpenManage performs the following steps to execute a power cycle or +power off host control action using this driver: + +1) Write host control action to be performed to host_control_action. +2) Write type of SMI that driver needs to perform to host_control_smi_type. +3) Write "1" to host_control_on_shutdown to enable host control action. +4) Initiate OS shutdown. + (Driver will perform host control SMI when it is notified that the OS + has finished shutting down.) + + +Host Control SMI Type +===================== + +The following table shows the value to write to host_control_smi_type to +perform a power cycle or power off host control action: + +=================== ===================== +PowerEdge System Host Control SMI Type +=================== ===================== + 300 HC_SMITYPE_TYPE1 + 1300 HC_SMITYPE_TYPE1 + 1400 HC_SMITYPE_TYPE2 + 500SC HC_SMITYPE_TYPE2 + 1500SC HC_SMITYPE_TYPE2 + 1550 HC_SMITYPE_TYPE2 + 600SC HC_SMITYPE_TYPE2 + 1600SC HC_SMITYPE_TYPE2 + 650 HC_SMITYPE_TYPE2 + 1655MC HC_SMITYPE_TYPE2 + 700 HC_SMITYPE_TYPE3 + 750 HC_SMITYPE_TYPE3 +=================== ===================== diff --git a/Documentation/userspace-api/index.rst b/Documentation/userspace-api/index.rst index 031df47a7c1933..09f61bd2ac2ef5 100644 --- a/Documentation/userspace-api/index.rst +++ b/Documentation/userspace-api/index.rst @@ -9,11 +9,8 @@ While much of the kernel's user-space API is documented elsewhere also be found in the kernel tree itself. This manual is intended to be the place where this information is gathered. -.. class:: toc-title - - Table of contents - .. toctree:: + :caption: Table of contents :maxdepth: 2 no_new_privs @@ -33,6 +30,10 @@ place where this information is gathered. sysfs-platform_profile vduse futex2 + lsm + tee + isapnp + dcdbas .. only:: subproject and html diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst index 4ea5b837399ad1..457e16f06e04de 100644 --- a/Documentation/userspace-api/ioctl/ioctl-number.rst +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst @@ -128,7 +128,6 @@ Code Seq# Include File Comments 'F' all linux/fb.h conflict! 'F' 01-02 drivers/scsi/pmcraid.h conflict! 'F' 20 drivers/video/fsl-diu-fb.h conflict! -'F' 20 drivers/video/intelfb/intelfb.h conflict! 'F' 20 linux/ivtvfb.h conflict! 'F' 20 linux/matroxfb.h conflict! 'F' 20 drivers/video/aty/atyfb_base.c conflict! @@ -349,6 +348,10 @@ Code Seq# Include File Comments 0xB1 00-1F PPPoX +0xB2 00 arch/powerpc/include/uapi/asm/papr-vpd.h powerpc/pseries VPD API + +0xB2 01-02 arch/powerpc/include/uapi/asm/papr-sysparm.h powerpc/pseries system parameter API + 0xB3 00 linux/mmc/ioctl.h 0xB4 00-0F linux/gpio.h 0xB5 00-0F uapi/linux/rpmsg.h diff --git a/Documentation/userspace-api/isapnp.rst b/Documentation/userspace-api/isapnp.rst new file mode 100644 index 00000000000000..d6fceb19b8ae6a --- /dev/null +++ b/Documentation/userspace-api/isapnp.rst @@ -0,0 +1,15 @@ +======================= +ISA Plug & Play support +======================= + +Interface /proc/isapnp +====================== + +The interface was removed in kernel 2.5.53. See pnp.rst for more details. + +Interface /proc/bus/isapnp +========================== + +This directory allows access to ISA PnP cards and logical devices. +The regular files contain the contents of ISA PnP registers for +a logical device. diff --git a/Documentation/userspace-api/lsm.rst b/Documentation/userspace-api/lsm.rst new file mode 100644 index 00000000000000..a76da373841b26 --- /dev/null +++ b/Documentation/userspace-api/lsm.rst @@ -0,0 +1,73 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. Copyright (C) 2022 Casey Schaufler +.. Copyright (C) 2022 Intel Corporation + +===================================== +Linux Security Modules +===================================== + +:Author: Casey Schaufler +:Date: July 2023 + +Linux security modules (LSM) provide a mechanism to implement +additional access controls to the Linux security policies. + +The various security modules may support any of these attributes: + +``LSM_ATTR_CURRENT`` is the current, active security context of the +process. +The proc filesystem provides this value in ``/proc/self/attr/current``. +This is supported by the SELinux, Smack and AppArmor security modules. +Smack also provides this value in ``/proc/self/attr/smack/current``. +AppArmor also provides this value in ``/proc/self/attr/apparmor/current``. + +``LSM_ATTR_EXEC`` is the security context of the process at the time the +current image was executed. +The proc filesystem provides this value in ``/proc/self/attr/exec``. +This is supported by the SELinux and AppArmor security modules. +AppArmor also provides this value in ``/proc/self/attr/apparmor/exec``. + +``LSM_ATTR_FSCREATE`` is the security context of the process used when +creating file system objects. +The proc filesystem provides this value in ``/proc/self/attr/fscreate``. +This is supported by the SELinux security module. + +``LSM_ATTR_KEYCREATE`` is the security context of the process used when +creating key objects. +The proc filesystem provides this value in ``/proc/self/attr/keycreate``. +This is supported by the SELinux security module. + +``LSM_ATTR_PREV`` is the security context of the process at the time the +current security context was set. +The proc filesystem provides this value in ``/proc/self/attr/prev``. +This is supported by the SELinux and AppArmor security modules. +AppArmor also provides this value in ``/proc/self/attr/apparmor/prev``. + +``LSM_ATTR_SOCKCREATE`` is the security context of the process used when +creating socket objects. +The proc filesystem provides this value in ``/proc/self/attr/sockcreate``. +This is supported by the SELinux security module. + +Kernel interface +================ + +Set a security attribute of the current process +----------------------------------------------- + +.. kernel-doc:: security/lsm_syscalls.c + :identifiers: sys_lsm_set_self_attr + +Get the specified security attributes of the current process +------------------------------------------------------------ + +.. kernel-doc:: security/lsm_syscalls.c + :identifiers: sys_lsm_get_self_attr + +.. kernel-doc:: security/lsm_syscalls.c + :identifiers: sys_lsm_list_modules + +Additional documentation +======================== + +* Documentation/security/lsm.rst +* Documentation/security/lsm-development.rst diff --git a/Documentation/userspace-api/media/cec/cec-api.rst b/Documentation/userspace-api/media/cec/cec-api.rst index 4d229ed8a1d980..578303d484f325 100644 --- a/Documentation/userspace-api/media/cec/cec-api.rst +++ b/Documentation/userspace-api/media/cec/cec-api.rst @@ -10,13 +10,8 @@ Part V - Consumer Electronics Control API This part describes the CEC: Consumer Electronics Control -.. only:: html - - .. class:: toc-title - - Table of Contents - .. toctree:: + :caption: Table of Contents :maxdepth: 5 :numbered: diff --git a/Documentation/userspace-api/media/drivers/index.rst b/Documentation/userspace-api/media/drivers/index.rst index 1726f8ec86fa48..2252063593bf30 100644 --- a/Documentation/userspace-api/media/drivers/index.rst +++ b/Documentation/userspace-api/media/drivers/index.rst @@ -21,13 +21,8 @@ more details. For more details see the file COPYING in the source distribution of Linux. -.. only:: html - - .. class:: toc-title - - Table of Contents - .. toctree:: + :caption: Table of Contents :maxdepth: 5 :numbered: @@ -41,4 +36,5 @@ For more details see the file COPYING in the source distribution of Linux. npcm-video omap3isp-uapi st-vgxy61 + thp7312 uvcvideo diff --git a/Documentation/userspace-api/media/drivers/thp7312.rst b/Documentation/userspace-api/media/drivers/thp7312.rst new file mode 100644 index 00000000000000..7c777e6fb7d20a --- /dev/null +++ b/Documentation/userspace-api/media/drivers/thp7312.rst @@ -0,0 +1,39 @@ +.. SPDX-License-Identifier: GPL-2.0-only + +THine THP7312 ISP driver +======================== + +The THP7312 driver implements the following driver-specific controls: + +``V4L2_CID_THP7312_LOW_LIGHT_COMPENSATION`` + Enable/Disable auto-adjustment, based on lighting conditions, of the frame + rate when auto-exposure is enabled. + +``V4L2_CID_THP7312_AUTO_FOCUS_METHOD`` + Set method of auto-focus. Only takes effect when auto-focus is enabled. + + .. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 4 + + * - ``0`` + - Contrast-based auto-focus + * - ``1`` + - PDAF + * - ``2`` + - Hybrid of contrast-based and PDAF + + Supported values for the control depend on the camera sensor module + connected to the THP7312. If the module doesn't have a focus lens actuator, + this control will not be exposed by the THP7312 driver. If the module has a + controllable focus lens but the sensor doesn't support PDAF, only the + contrast-based auto-focus value will be valid. Otherwise all values for the + controls will be supported. + +``V4L2_CID_THP7312_NOISE_REDUCTION_AUTO`` + Enable/Disable auto noise reduction. + +``V4L2_CID_THP7312_NOISE_REDUCTION_ABSOLUTE`` + Set the noise reduction strength, where 0 is the weakest and 10 is the + strongest. diff --git a/Documentation/userspace-api/media/dvb/dvbapi.rst b/Documentation/userspace-api/media/dvb/dvbapi.rst index 1dda69343f3424..4ac0c1bc54ca6e 100644 --- a/Documentation/userspace-api/media/dvb/dvbapi.rst +++ b/Documentation/userspace-api/media/dvb/dvbapi.rst @@ -27,13 +27,8 @@ Part II - Digital TV API **Version 5.10** -.. only:: html - - .. class:: toc-title - - Table of Contents - .. toctree:: + :caption: Table of Contents :maxdepth: 5 :numbered: diff --git a/Documentation/userspace-api/media/index.rst b/Documentation/userspace-api/media/index.rst index d839904be08591..337ef6c7c47f54 100644 --- a/Documentation/userspace-api/media/index.rst +++ b/Documentation/userspace-api/media/index.rst @@ -21,13 +21,8 @@ Documentation/driver-api/media/index.rst media devices; -.. only:: html - - .. class:: toc-title - - Table of Contents - .. toctree:: + :caption: Table of Contents :maxdepth: 1 intro diff --git a/Documentation/userspace-api/media/mediactl/media-controller.rst b/Documentation/userspace-api/media/mediactl/media-controller.rst index 508dd693bf6c6a..73a87f82f92dbc 100644 --- a/Documentation/userspace-api/media/mediactl/media-controller.rst +++ b/Documentation/userspace-api/media/mediactl/media-controller.rst @@ -7,13 +7,8 @@ Part IV - Media Controller API ############################## -.. only:: html - - .. class:: toc-title - - Table of Contents - .. toctree:: + :caption: Table of Contents :maxdepth: 5 :numbered: diff --git a/Documentation/userspace-api/media/rc/remote_controllers.rst b/Documentation/userspace-api/media/rc/remote_controllers.rst index f89291838637ad..483f9ae92a906e 100644 --- a/Documentation/userspace-api/media/rc/remote_controllers.rst +++ b/Documentation/userspace-api/media/rc/remote_controllers.rst @@ -7,13 +7,8 @@ Part III - Remote Controller API ################################ -.. only:: html - - .. class:: toc-title - - Table of Contents - .. toctree:: + :caption: Table of Contents :maxdepth: 5 :numbered: diff --git a/Documentation/userspace-api/media/v4l/v4l2.rst b/Documentation/userspace-api/media/v4l/v4l2.rst index ad7a2bf0cf26c7..cf8ae56a008c1f 100644 --- a/Documentation/userspace-api/media/v4l/v4l2.rst +++ b/Documentation/userspace-api/media/v4l/v4l2.rst @@ -11,13 +11,8 @@ This part describes the Video for Linux API version 2 (V4L2 API) specification. **Revision 4.5** -.. only:: html - - .. class:: toc-title - - Table of Contents - .. toctree:: + :caption: Table of Contents :numbered: :maxdepth: 5 diff --git a/Documentation/userspace-api/media/v4l/vidioc-create-bufs.rst b/Documentation/userspace-api/media/v4l/vidioc-create-bufs.rst index a048a9f6b7b6a2..49232c9006c206 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-create-bufs.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-create-bufs.rst @@ -116,9 +116,13 @@ than the number requested. - ``flags`` - Specifies additional buffer management attributes. See :ref:`memory-flags`. - * - __u32 - - ``reserved``\ [6] + - ``max_num_buffers`` + - If the V4L2_BUF_CAP_SUPPORTS_MAX_NUM_BUFFERS capability flag is set + this field indicates the maximum possible number of buffers + for this queue. + * - __u32 + - ``reserved``\ [5] - A place holder for future extensions. Drivers and applications must set the array to zero. diff --git a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst index f9f73530a6be01..4d56c0528ad726 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst @@ -295,6 +295,14 @@ still cause this situation. - ``p_av1_film_grain`` - A pointer to a struct :c:type:`v4l2_ctrl_av1_film_grain`. Valid if this control is of type ``V4L2_CTRL_TYPE_AV1_FILM_GRAIN``. + * - struct :c:type:`v4l2_ctrl_hdr10_cll_info` * + - ``p_hdr10_cll_info`` + - A pointer to a struct :c:type:`v4l2_ctrl_hdr10_cll_info`. Valid if this control is + of type ``V4L2_CTRL_TYPE_HDR10_CLL_INFO``. + * - struct :c:type:`v4l2_ctrl_hdr10_mastering_display` * + - ``p_hdr10_mastering_display`` + - A pointer to a struct :c:type:`v4l2_ctrl_hdr10_mastering_display`. Valid if this control is + of type ``V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY``. * - void * - ``ptr`` - A pointer to a compound type which can be an N-dimensional array diff --git a/Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst b/Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst index 099fa6695167b4..0b3a41a45d05c7 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst @@ -120,6 +120,7 @@ aborting or finishing any DMA in progress, an implicit .. _V4L2-BUF-CAP-SUPPORTS-ORPHANED-BUFS: .. _V4L2-BUF-CAP-SUPPORTS-M2M-HOLD-CAPTURE-BUF: .. _V4L2-BUF-CAP-SUPPORTS-MMAP-CACHE-HINTS: +.. _V4L2-BUF-CAP-SUPPORTS-MAX-NUM-BUFFERS: .. raw:: latex diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-interval.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-interval.rst index 8def4c05d3da12..c935bacc3bc299 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-interval.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-interval.rst @@ -107,8 +107,7 @@ appropriately. The generic error codes are described at the :ref:`Generic Error Codes ` chapter. EINVAL - The struct - :c:type:`v4l2_subdev_frame_interval_enum` - ``pad`` references a non-existing pad, one of the ``code``, - ``width`` or ``height`` fields are invalid for the given pad or the - ``index`` field is out of bounds. + The struct :c:type:`v4l2_subdev_frame_interval_enum` ``pad`` references a + non-existing pad, the ``which`` field has an unsupported value, one of the + ``code``, ``width`` or ``height`` fields are invalid for the given pad, or + the ``index`` field is out of bounds. diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-size.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-size.rst index e3ae84df5486c0..65f0cfeca97337 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-size.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-size.rst @@ -126,7 +126,6 @@ appropriately. The generic error codes are described at the :ref:`Generic Error Codes ` chapter. EINVAL - The struct - :c:type:`v4l2_subdev_frame_size_enum` - ``pad`` references a non-existing pad, the ``code`` is invalid for - the given pad or the ``index`` field is out of bounds. + The struct :c:type:`v4l2_subdev_frame_size_enum` ``pad`` references a + non-existing pad, the ``which`` field has an unsupported value, the ``code`` + is invalid for the given pad, or the ``index`` field is out of bounds. diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-mbus-code.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-mbus-code.rst index 4ad7dec27e2598..3050966b199fbb 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-mbus-code.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-enum-mbus-code.rst @@ -158,7 +158,6 @@ appropriately. The generic error codes are described at the :ref:`Generic Error Codes ` chapter. EINVAL - The struct - :c:type:`v4l2_subdev_mbus_code_enum` - ``pad`` references a non-existing pad, or the ``index`` field is out - of bounds. + The struct :c:type:`v4l2_subdev_mbus_code_enum` ``pad`` references a + non-existing pad, the ``which`` field has an unsupported value, or the + ``index`` field is out of bounds. diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-client-cap.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-client-cap.rst index 20f12a1cc0f7dc..810b6a859dc8d7 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-client-cap.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-client-cap.rst @@ -71,6 +71,11 @@ is unknown to the kernel. of 'stream' fields (referring to the stream number) with various ioctls. If this is not set (which is the default), the 'stream' fields will be forced to 0 by the kernel. + * - ``V4L2_SUBDEV_CLIENT_CAP_INTERVAL_USES_WHICH`` + - The client is aware of the :c:type:`v4l2_subdev_frame_interval` + ``which`` field. If this is not set (which is the default), the + ``which`` field is forced to ``V4L2_SUBDEV_FORMAT_ACTIVE`` by the + kernel. Return Value ============ diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-crop.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-crop.rst index 1d267f7e799117..92d933631fda84 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-crop.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-crop.rst @@ -118,10 +118,9 @@ EBUSY ``VIDIOC_SUBDEV_S_CROP`` EINVAL - The struct :c:type:`v4l2_subdev_crop` ``pad`` - references a non-existing pad, the ``which`` field references a - non-existing format, or cropping is not supported on the given - subdev pad. + The struct :c:type:`v4l2_subdev_crop` ``pad`` references a non-existing pad, + the ``which`` field has an unsupported value, or cropping is not supported + on the given subdev pad. EPERM The ``VIDIOC_SUBDEV_S_CROP`` ioctl has been called on a read-only subdevice diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-fmt.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-fmt.rst index ed253a1e44b706..4a2b4e4f0152f5 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-fmt.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-fmt.rst @@ -140,9 +140,8 @@ EBUSY fix the problem first. Only returned by ``VIDIOC_SUBDEV_S_FMT`` EINVAL - The struct :c:type:`v4l2_subdev_format` - ``pad`` references a non-existing pad, or the ``which`` field - references a non-existing format. + The struct :c:type:`v4l2_subdev_format` ``pad`` references a non-existing + pad, or the ``which`` field has an unsupported value. EPERM The ``VIDIOC_SUBDEV_S_FMT`` ioctl has been called on a read-only subdevice diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-frame-interval.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-frame-interval.rst index 842f962d2aeaf1..c8022809ac35fa 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-frame-interval.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-frame-interval.rst @@ -58,8 +58,9 @@ struct contains the current frame interval as would be returned by a ``VIDIOC_SUBDEV_G_FRAME_INTERVAL`` call. -Calling ``VIDIOC_SUBDEV_S_FRAME_INTERVAL`` on a subdev device node that has been -registered in read-only mode is not allowed. An error is returned and the errno +If the subdev device node has been registered in read-only mode, calls to +``VIDIOC_SUBDEV_S_FRAME_INTERVAL`` are only valid if the ``which`` field is set +to ``V4L2_SUBDEV_FORMAT_TRY``, otherwise an error is returned and the errno variable is set to ``-EPERM``. Drivers must not return an error solely because the requested interval @@ -93,7 +94,11 @@ the same sub-device is not defined. - ``stream`` - Stream identifier. * - __u32 - - ``reserved``\ [8] + - ``which`` + - Active or try frame interval, from enum + :ref:`v4l2_subdev_format_whence `. + * - __u32 + - ``reserved``\ [7] - Reserved for future extensions. Applications and drivers must set the array to zero. @@ -112,11 +117,10 @@ EBUSY ``VIDIOC_SUBDEV_S_FRAME_INTERVAL`` EINVAL - The struct - :c:type:`v4l2_subdev_frame_interval` - ``pad`` references a non-existing pad, or the pad doesn't support - frame intervals. + The struct :c:type:`v4l2_subdev_frame_interval` ``pad`` references a + non-existing pad, the ``which`` field has an unsupported value, or the pad + doesn't support frame intervals. EPERM The ``VIDIOC_SUBDEV_S_FRAME_INTERVAL`` ioctl has been called on a read-only - subdevice. + subdevice and the ``which`` field is set to ``V4L2_SUBDEV_FORMAT_ACTIVE``. diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst index 72677a280cd647..26b5004bfe6dcb 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst @@ -72,7 +72,7 @@ On a successful ``VIDIOC_SUBDEV_G_ROUTING`` call the driver updates the * - __u32 - ``which`` - - Format to modified, from enum + - Routing table to be accessed, from enum :ref:`v4l2_subdev_format_whence `. * - struct :c:type:`v4l2_subdev_route` - ``routes[]`` @@ -140,8 +140,9 @@ ENOSPC all the available routes the subdevice exposes. EINVAL - The sink or source pad identifiers reference a non-existing pad, or reference - pads of different types (ie. the sink_pad identifiers refers to a source pad). + The sink or source pad identifiers reference a non-existing pad or reference + pads of different types (ie. the sink_pad identifiers refers to a source + pad), or the ``which`` field has an unsupported value. E2BIG The application provided ``num_routes`` for ``VIDIOC_SUBDEV_S_ROUTING`` is diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-selection.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-selection.rst index 6b629c19168c02..19e6c3e9c06da9 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-selection.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-selection.rst @@ -116,10 +116,9 @@ EBUSY ``VIDIOC_SUBDEV_S_SELECTION`` EINVAL - The struct :c:type:`v4l2_subdev_selection` - ``pad`` references a non-existing pad, the ``which`` field - references a non-existing format, or the selection target is not - supported on the given subdev pad. + The struct :c:type:`v4l2_subdev_selection` ``pad`` references a + non-existing pad, the ``which`` field has an unsupported value, or the + selection target is not supported on the given subdev pad. EPERM The ``VIDIOC_SUBDEV_S_SELECTION`` ioctl has been called on a read-only diff --git a/Documentation/userspace-api/netlink/index.rst b/Documentation/userspace-api/netlink/index.rst index 62725dafbbdb5d..c1b6765cc963e2 100644 --- a/Documentation/userspace-api/netlink/index.rst +++ b/Documentation/userspace-api/netlink/index.rst @@ -16,4 +16,6 @@ Netlink documentation for users. genetlink-legacy netlink-raw -See also :ref:`Documentation/core-api/netlink.rst `. +See also: + - :ref:`Documentation/core-api/netlink.rst ` + - :ref:`Documentation/networking/netlink_spec/index.rst ` diff --git a/Documentation/userspace-api/netlink/intro.rst b/Documentation/userspace-api/netlink/intro.rst index 7b1d401210efb4..aacffade8f84c3 100644 --- a/Documentation/userspace-api/netlink/intro.rst +++ b/Documentation/userspace-api/netlink/intro.rst @@ -234,6 +234,10 @@ ACK attributes may be present:: | ** optionally extended ACK | ---------------------------------------------- +Note that some implementations may issue custom ``NLMSG_DONE`` messages +in reply to ``do`` action requests. In that case the payload is +implementation-specific and may also be absent. + .. _res_fam: Resolving the Family ID diff --git a/Documentation/userspace-api/netlink/netlink-raw.rst b/Documentation/userspace-api/netlink/netlink-raw.rst index f07fb9b9c101ea..1e14f5f22b8e0f 100644 --- a/Documentation/userspace-api/netlink/netlink-raw.rst +++ b/Documentation/userspace-api/netlink/netlink-raw.rst @@ -14,7 +14,8 @@ Specification The netlink-raw schema extends the :doc:`genetlink-legacy ` schema with properties that are needed to specify the protocol numbers and multicast IDs used by raw netlink families. See :ref:`classic_netlink` for more -information. +information. The raw netlink families also make use of type-specific +sub-messages. Globals ------- @@ -56,3 +57,96 @@ group registration. - name: rtnlgrp-mctp-ifaddr value: 34 + +Sub-messages +------------ + +Several raw netlink families such as +:doc:`rt_link<../../networking/netlink_spec/rt_link>` and +:doc:`tc<../../networking/netlink_spec/tc>` use attribute nesting as an +abstraction to carry module specific information. + +Conceptually it looks as follows:: + + [OUTER NEST OR MESSAGE LEVEL] + [GENERIC ATTR 1] + [GENERIC ATTR 2] + [GENERIC ATTR 3] + [GENERIC ATTR - wrapper] + [MODULE SPECIFIC ATTR 1] + [MODULE SPECIFIC ATTR 2] + +The ``GENERIC ATTRs`` at the outer level are defined in the core (or rt_link or +core TC), while specific drivers, TC classifiers, qdiscs etc. can carry their +own information wrapped in the ``GENERIC ATTR - wrapper``. Even though the +example above shows attributes nesting inside the wrapper, the modules generally +have full freedom to define the format of the nest. In practice the payload of +the wrapper attr has very similar characteristics to a netlink message. It may +contain a fixed header / structure, netlink attributes, or both. Because of +those shared characteristics we refer to the payload of the wrapper attribute as +a sub-message. + +A sub-message attribute uses the value of another attribute as a selector key to +choose the right sub-message format. For example if the following attribute has +already been decoded: + +.. code-block:: json + + { "kind": "gre" } + +and we encounter the following attribute spec: + +.. code-block:: yaml + + - + name: data + type: sub-message + sub-message: linkinfo-data-msg + selector: kind + +Then we look for a sub-message definition called ``linkinfo-data-msg`` and use +the value of the ``kind`` attribute i.e. ``gre`` as the key to choose the +correct format for the sub-message: + +.. code-block:: yaml + + sub-messages: + name: linkinfo-data-msg + formats: + - + value: bridge + attribute-set: linkinfo-bridge-attrs + - + value: gre + attribute-set: linkinfo-gre-attrs + - + value: geneve + attribute-set: linkinfo-geneve-attrs + +This would decode the attribute value as a sub-message with the attribute-set +called ``linkinfo-gre-attrs`` as the attribute space. + +A sub-message can have an optional ``fixed-header`` followed by zero or more +attributes from an ``attribute-set``. For example the following +``tc-options-msg`` sub-message defines message formats that use a mixture of +``fixed-header``, ``attribute-set`` or both together: + +.. code-block:: yaml + + sub-messages: + - + name: tc-options-msg + formats: + - + value: bfifo + fixed-header: tc-fifo-qopt + - + value: cake + attribute-set: tc-cake-attrs + - + value: netem + fixed-header: tc-netem-qopt + attribute-set: tc-netem-attrs + +Note that a selector attribute must appear in a netlink message before any +sub-message attributes that depend on it. diff --git a/Documentation/userspace-api/netlink/specs.rst b/Documentation/userspace-api/netlink/specs.rst index c1b95164911324..1b50d97d8d7c3f 100644 --- a/Documentation/userspace-api/netlink/specs.rst +++ b/Documentation/userspace-api/netlink/specs.rst @@ -15,7 +15,7 @@ kernel headers directly. Internally kernel uses the YAML specs to generate: - the C uAPI header - - documentation of the protocol as a ReST file + - documentation of the protocol as a ReST file - see :ref:`Documentation/networking/netlink_spec/index.rst ` - policy tables for input attribute validation - operation tables diff --git a/Documentation/userspace-api/tee.rst b/Documentation/userspace-api/tee.rst new file mode 100644 index 00000000000000..e2368dbc345112 --- /dev/null +++ b/Documentation/userspace-api/tee.rst @@ -0,0 +1,39 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. tee: + +================================================== +TEE (Trusted Execution Environment) Userspace API +================================================== + +include/uapi/linux/tee.h defines the generic interface to a TEE. + +User space (the client) connects to the driver by opening /dev/tee[0-9]* or +/dev/teepriv[0-9]*. + +- TEE_IOC_SHM_ALLOC allocates shared memory and returns a file descriptor + which user space can mmap. When user space doesn't need the file + descriptor any more, it should be closed. When shared memory isn't needed + any longer it should be unmapped with munmap() to allow the reuse of + memory. + +- TEE_IOC_VERSION lets user space know which TEE this driver handles and + its capabilities. + +- TEE_IOC_OPEN_SESSION opens a new session to a Trusted Application. + +- TEE_IOC_INVOKE invokes a function in a Trusted Application. + +- TEE_IOC_CANCEL may cancel an ongoing TEE_IOC_OPEN_SESSION or TEE_IOC_INVOKE. + +- TEE_IOC_CLOSE_SESSION closes a session to a Trusted Application. + +There are two classes of clients, normal clients and supplicants. The latter is +a helper process for the TEE to access resources in Linux, for example file +system access. A normal client opens /dev/tee[0-9]* and a supplicant opens +/dev/teepriv[0-9]. + +Much of the communication between clients and the TEE is opaque to the +driver. The main job for the driver is to receive requests from the +clients, forward them to the TEE and send back the results. In the case of +supplicants the communication goes in the other direction, the TEE sends +requests to the supplicant which then sends back the result. diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 7025b375102795..3ec0b7a455a0cf 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -147,10 +147,29 @@ described as 'basic' will be available. The new VM has no virtual cpus and no memory. You probably want to use 0 as machine type. +X86: +^^^^ + +Supported X86 VM types can be queried via KVM_CAP_VM_TYPES. + +S390: +^^^^^ + In order to create user controlled virtual machines on S390, check KVM_CAP_S390_UCONTROL and use the flag KVM_VM_S390_UCONTROL as privileged user (CAP_SYS_ADMIN). +MIPS: +^^^^^ + +To use hardware assisted virtualization on MIPS (VZ ASE) rather than +the default trap & emulate implementation (which changes the virtual +memory layout to fit in user mode), check KVM_CAP_MIPS_VZ and use the +flag KVM_VM_MIPS_VZ. + +ARM64: +^^^^^^ + On arm64, the physical address size for a VM (IPA Size limit) is limited to 40bits by default. The limit can be configured if the host supports the extension KVM_CAP_ARM_VM_IPA_SIZE. When supported, use @@ -608,18 +627,6 @@ interrupt number dequeues the interrupt. This is an asynchronous vcpu ioctl and can be invoked from any thread. -4.17 KVM_DEBUG_GUEST --------------------- - -:Capability: basic -:Architectures: none -:Type: vcpu ioctl -:Parameters: none) -:Returns: -1 on error - -Support for this has been removed. Use KVM_SET_GUEST_DEBUG instead. - - 4.18 KVM_GET_MSRS ----------------- @@ -6192,6 +6199,130 @@ to know what fields can be changed for the system register described by ``op0, op1, crn, crm, op2``. KVM rejects ID register values that describe a superset of the features supported by the system. +4.140 KVM_SET_USER_MEMORY_REGION2 +--------------------------------- + +:Capability: KVM_CAP_USER_MEMORY2 +:Architectures: all +:Type: vm ioctl +:Parameters: struct kvm_userspace_memory_region2 (in) +:Returns: 0 on success, -1 on error + +KVM_SET_USER_MEMORY_REGION2 is an extension to KVM_SET_USER_MEMORY_REGION that +allows mapping guest_memfd memory into a guest. All fields shared with +KVM_SET_USER_MEMORY_REGION identically. Userspace can set KVM_MEM_GUEST_MEMFD +in flags to have KVM bind the memory region to a given guest_memfd range of +[guest_memfd_offset, guest_memfd_offset + memory_size]. The target guest_memfd +must point at a file created via KVM_CREATE_GUEST_MEMFD on the current VM, and +the target range must not be bound to any other memory region. All standard +bounds checks apply (use common sense). + +:: + + struct kvm_userspace_memory_region2 { + __u32 slot; + __u32 flags; + __u64 guest_phys_addr; + __u64 memory_size; /* bytes */ + __u64 userspace_addr; /* start of the userspace allocated memory */ + __u64 guest_memfd_offset; + __u32 guest_memfd; + __u32 pad1; + __u64 pad2[14]; + }; + +A KVM_MEM_GUEST_MEMFD region _must_ have a valid guest_memfd (private memory) and +userspace_addr (shared memory). However, "valid" for userspace_addr simply +means that the address itself must be a legal userspace address. The backing +mapping for userspace_addr is not required to be valid/populated at the time of +KVM_SET_USER_MEMORY_REGION2, e.g. shared memory can be lazily mapped/allocated +on-demand. + +When mapping a gfn into the guest, KVM selects shared vs. private, i.e consumes +userspace_addr vs. guest_memfd, based on the gfn's KVM_MEMORY_ATTRIBUTE_PRIVATE +state. At VM creation time, all memory is shared, i.e. the PRIVATE attribute +is '0' for all gfns. Userspace can control whether memory is shared/private by +toggling KVM_MEMORY_ATTRIBUTE_PRIVATE via KVM_SET_MEMORY_ATTRIBUTES as needed. + +4.141 KVM_SET_MEMORY_ATTRIBUTES +------------------------------- + +:Capability: KVM_CAP_MEMORY_ATTRIBUTES +:Architectures: x86 +:Type: vm ioctl +:Parameters: struct kvm_memory_attributes (in) +:Returns: 0 on success, <0 on error + +KVM_SET_MEMORY_ATTRIBUTES allows userspace to set memory attributes for a range +of guest physical memory. + +:: + + struct kvm_memory_attributes { + __u64 address; + __u64 size; + __u64 attributes; + __u64 flags; + }; + + #define KVM_MEMORY_ATTRIBUTE_PRIVATE (1ULL << 3) + +The address and size must be page aligned. The supported attributes can be +retrieved via ioctl(KVM_CHECK_EXTENSION) on KVM_CAP_MEMORY_ATTRIBUTES. If +executed on a VM, KVM_CAP_MEMORY_ATTRIBUTES precisely returns the attributes +supported by that VM. If executed at system scope, KVM_CAP_MEMORY_ATTRIBUTES +returns all attributes supported by KVM. The only attribute defined at this +time is KVM_MEMORY_ATTRIBUTE_PRIVATE, which marks the associated gfn as being +guest private memory. + +Note, there is no "get" API. Userspace is responsible for explicitly tracking +the state of a gfn/page as needed. + +The "flags" field is reserved for future extensions and must be '0'. + +4.142 KVM_CREATE_GUEST_MEMFD +---------------------------- + +:Capability: KVM_CAP_GUEST_MEMFD +:Architectures: none +:Type: vm ioctl +:Parameters: struct kvm_create_guest_memfd(in) +:Returns: 0 on success, <0 on error + +KVM_CREATE_GUEST_MEMFD creates an anonymous file and returns a file descriptor +that refers to it. guest_memfd files are roughly analogous to files created +via memfd_create(), e.g. guest_memfd files live in RAM, have volatile storage, +and are automatically released when the last reference is dropped. Unlike +"regular" memfd_create() files, guest_memfd files are bound to their owning +virtual machine (see below), cannot be mapped, read, or written by userspace, +and cannot be resized (guest_memfd files do however support PUNCH_HOLE). + +:: + + struct kvm_create_guest_memfd { + __u64 size; + __u64 flags; + __u64 reserved[6]; + }; + +Conceptually, the inode backing a guest_memfd file represents physical memory, +i.e. is coupled to the virtual machine as a thing, not to a "struct kvm". The +file itself, which is bound to a "struct kvm", is that instance's view of the +underlying memory, e.g. effectively provides the translation of guest addresses +to host memory. This allows for use cases where multiple KVM structures are +used to manage a single virtual machine, e.g. when performing intrahost +migration of a virtual machine. + +KVM currently only supports mapping guest_memfd via KVM_SET_USER_MEMORY_REGION2, +and more specifically via the guest_memfd and guest_memfd_offset fields in +"struct kvm_userspace_memory_region2", where guest_memfd_offset is the offset +into the guest_memfd instance. For a given guest_memfd file, there can be at +most one mapping per page, i.e. binding multiple memory regions to a single +guest_memfd range is not allowed (any number of memory regions can be bound to +a single guest_memfd file, but the bound ranges must not overlap). + +See KVM_SET_USER_MEMORY_REGION2 for additional details. + 5. The kvm_run structure ======================== @@ -6824,6 +6955,30 @@ array field represents return values. The userspace should update the return values of SBI call before resuming the VCPU. For more details on RISC-V SBI spec refer, https://github.com/riscv/riscv-sbi-doc. +:: + + /* KVM_EXIT_MEMORY_FAULT */ + struct { + #define KVM_MEMORY_EXIT_FLAG_PRIVATE (1ULL << 3) + __u64 flags; + __u64 gpa; + __u64 size; + } memory_fault; + +KVM_EXIT_MEMORY_FAULT indicates the vCPU has encountered a memory fault that +could not be resolved by KVM. The 'gpa' and 'size' (in bytes) describe the +guest physical address range [gpa, gpa + size) of the fault. The 'flags' field +describes properties of the faulting access that are likely pertinent: + + - KVM_MEMORY_EXIT_FLAG_PRIVATE - When set, indicates the memory fault occurred + on a private memory access. When clear, indicates the fault occurred on a + shared access. + +Note! KVM_EXIT_MEMORY_FAULT is unique among all KVM exit reasons in that it +accompanies a return code of '-1', not '0'! errno will always be set to EFAULT +or EHWPOISON when KVM exits with KVM_EXIT_MEMORY_FAULT, userspace should assume +kvm_run.exit_reason is stale/undefined for all other error numbers. + :: /* KVM_EXIT_NOTIFY */ @@ -7858,6 +8013,27 @@ This capability is aimed to mitigate the threat that malicious VMs can cause CPU stuck (due to event windows don't open up) and make the CPU unavailable to host or other VMs. +7.34 KVM_CAP_MEMORY_FAULT_INFO +------------------------------ + +:Architectures: x86 +:Returns: Informational only, -EINVAL on direct KVM_ENABLE_CAP. + +The presence of this capability indicates that KVM_RUN will fill +kvm_run.memory_fault if KVM cannot resolve a guest page fault VM-Exit, e.g. if +there is a valid memslot but no backing VMA for the corresponding host virtual +address. + +The information in kvm_run.memory_fault is valid if and only if KVM_RUN returns +an error with errno=EFAULT or errno=EHWPOISON *and* kvm_run.exit_reason is set +to KVM_EXIT_MEMORY_FAULT. + +Note: Userspaces which attempt to resolve memory faults so that they can retry +KVM_RUN are encouraged to guard against repeatedly receiving the same +error/annotated fault. + +See KVM_EXIT_MEMORY_FAULT for more information. + 8. Other capabilities. ====================== @@ -8374,6 +8550,7 @@ PVHVM guests. Valid flags are:: #define KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL (1 << 4) #define KVM_XEN_HVM_CONFIG_EVTCHN_SEND (1 << 5) #define KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG (1 << 6) + #define KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE (1 << 7) The KVM_XEN_HVM_CONFIG_HYPERCALL_MSR flag indicates that the KVM_XEN_HVM_CONFIG ioctl is available, for the guest to set its hypercall page. @@ -8417,6 +8594,11 @@ behave more correctly, not using the XEN_RUNSTATE_UPDATE flag until/unless specifically enabled (by the guest making the hypercall, causing the VMM to enable the KVM_XEN_ATTR_TYPE_RUNSTATE_UPDATE_FLAG attribute). +The KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE flag indicates that KVM supports +clearing the PVCLOCK_TSC_STABLE_BIT flag in Xen pvclock sources. This will be +done when the KVM_CAP_XEN_HVM ioctl sets the +KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE flag. + 8.31 KVM_CAP_PPC_MULTITCE ------------------------- @@ -8596,6 +8778,19 @@ block sizes is exposed in KVM_CAP_ARM_SUPPORTED_BLOCK_SIZES as a 64-bit bitmap (each bit describing a block size). The default value is 0, to disable the eager page splitting. +8.41 KVM_CAP_VM_TYPES +--------------------- + +:Capability: KVM_CAP_MEMORY_ATTRIBUTES +:Architectures: x86 +:Type: system ioctl + +This capability returns a bitmap of support VM types. The 1-setting of bit @n +means the VM type with value @n is supported. Possible values of @n are:: + + #define KVM_X86_DEFAULT_VM 0 + #define KVM_X86_SW_PROTECTED_VM 1 + 9. Known KVM API problems ========================= diff --git a/Documentation/virt/kvm/locking.rst b/Documentation/virt/kvm/locking.rst index 3a034db5e55f89..02880d5552d5fa 100644 --- a/Documentation/virt/kvm/locking.rst +++ b/Documentation/virt/kvm/locking.rst @@ -43,10 +43,9 @@ On x86: - vcpu->mutex is taken outside kvm->arch.hyperv.hv_lock and kvm->arch.xen.xen_lock -- kvm->arch.mmu_lock is an rwlock. kvm->arch.tdp_mmu_pages_lock and - kvm->arch.mmu_unsync_pages_lock are taken inside kvm->arch.mmu_lock, and - cannot be taken without already holding kvm->arch.mmu_lock (typically with - ``read_lock`` for the TDP MMU, thus the need for additional spinlocks). +- kvm->arch.mmu_lock is an rwlock; critical sections for + kvm->arch.tdp_mmu_pages_lock and kvm->arch.mmu_unsync_pages_lock must + also take kvm->arch.mmu_lock Everything else is a leaf: no other lock is taken inside the critical sections. diff --git a/MAINTAINERS b/MAINTAINERS index a7c4cf8201e012..8999497011a263 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -441,6 +441,13 @@ W: http://wiki.analog.com/AD7879 W: https://ez.analog.com/linux-software-drivers F: drivers/input/touchscreen/ad7879.c +ADAFRUIT MINI I2C GAMEPAD +M: Anshul Dalal +L: linux-input@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/input/adafruit,seesaw-gamepad.yaml +F: drivers/input/joystick/adafruit-seesaw.c + ADDRESS SPACE LAYOUT RANDOMIZATION (ASLR) M: Jiri Kosina S: Maintained @@ -699,6 +706,15 @@ S: Maintained F: Documentation/devicetree/bindings/media/allegro,al5e.yaml F: drivers/media/platform/allegro-dvt/ +ALLIED VISION ALVIUM CAMERA DRIVER +M: Tommaso Merciai +M: Martin Hecht +L: linux-media@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/media/i2c/alliedvision,alvium-csi2.yaml +F: drivers/media/i2c/alvium-csi2.c +F: drivers/media/i2c/alvium-csi2.h + ALLWINNER A10 CSI DRIVER M: Maxime Ripard L: linux-media@vger.kernel.org @@ -881,6 +897,14 @@ Q: https://patchwork.kernel.org/project/linux-rdma/list/ F: drivers/infiniband/hw/efa/ F: include/uapi/rdma/efa-abi.h +AMD AXI W1 DRIVER +M: Kris Chaplin +R: Thomas Delev +R: Michal Simek +S: Maintained +F: Documentation/devicetree/bindings/w1/amd,axi-1wire-host.yaml +F: drivers/w1/masters/amd_axi_w1.c + AMD CDX BUS DRIVER M: Nipun Gupta M: Nikhil Agarwal @@ -1114,6 +1138,14 @@ F: Documentation/ABI/testing/sysfs-bus-iio-adc-ad4130 F: Documentation/devicetree/bindings/iio/adc/adi,ad4130.yaml F: drivers/iio/adc/ad4130.c +ANALOG DEVICES INC AD7091R DRIVER +M: Marcelo Schmitt +L: linux-iio@vger.kernel.org +S: Supported +W: http://ez.analog.com/community/linux-device-drivers +F: Documentation/devicetree/bindings/iio/adc/adi,ad7091r* +F: drivers/iio/adc/drivers/iio/adc/ad7091r* + ANALOG DEVICES INC AD7192 DRIVER M: Alexandru Tachici L: linux-iio@vger.kernel.org @@ -1684,11 +1716,6 @@ S: Odd Fixes F: drivers/amba/ F: include/linux/amba/bus.h -ARM PRIMECELL CLCD PL110 DRIVER -M: Russell King -S: Odd Fixes -F: drivers/video/fbdev/amba-clcd.* - ARM PRIMECELL KMI PL050 DRIVER M: Russell King S: Odd Fixes @@ -1931,7 +1958,6 @@ F: drivers/i2c/busses/i2c-pasemi-platform.c F: drivers/iommu/apple-dart.c F: drivers/iommu/io-pgtable-dart.c F: drivers/irqchip/irq-apple-aic.c -F: drivers/mailbox/apple-mailbox.c F: drivers/nvme/host/apple.c F: drivers/nvmem/apple-efuses.c F: drivers/pinctrl/pinctrl-apple-gpio.c @@ -1940,7 +1966,6 @@ F: drivers/soc/apple/* F: drivers/watchdog/apple_wdt.c F: include/dt-bindings/interrupt-controller/apple-aic.h F: include/dt-bindings/pinctrl/apple.h -F: include/linux/apple-mailbox.h F: include/linux/soc/apple/* ARM/ARTPEC MACHINE SUPPORT @@ -2017,11 +2042,6 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Odd Fixes N: clps711x -ARM/CIRRUS LOGIC EDB9315A MACHINE SUPPORT -M: Lennert Buytenhek -L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -S: Maintained - ARM/CIRRUS LOGIC EP93XX ARM ARCHITECTURE M: Hartley Sweeten M: Alexander Sverdlin @@ -2051,7 +2071,6 @@ ARM/CORESIGHT FRAMEWORK AND DRIVERS M: Suzuki K Poulose R: Mike Leach R: James Clark -R: Leo Yan L: coresight@lists.linaro.org (moderated for non-subscribers) L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained @@ -2307,6 +2326,7 @@ F: arch/arm/mach-dove/ F: arch/arm/mach-mv78xx0/ F: arch/arm/mach-orion5x/ F: arch/arm/plat-orion/ +F: drivers/bus/mvebu-mbus.c F: drivers/soc/dove/ ARM/Marvell Kirkwood and Armada 370, 375, 38x, 39x, XP, 3700, 7K/8K, CN9130 SOC support @@ -2321,8 +2341,7 @@ F: arch/arm/boot/dts/marvell/armada* F: arch/arm/boot/dts/marvell/kirkwood* F: arch/arm/configs/mvebu_*_defconfig F: arch/arm/mach-mvebu/ -F: arch/arm64/boot/dts/marvell/armada* -F: arch/arm64/boot/dts/marvell/cn913* +F: arch/arm64/boot/dts/marvell/ F: drivers/clk/mvebu/ F: drivers/cpufreq/armada-37xx-cpufreq.c F: drivers/cpufreq/armada-8k-cpufreq.c @@ -2394,7 +2413,6 @@ F: drivers/memory/atmel* F: drivers/watchdog/sama5d4_wdt.c F: include/soc/at91/ X: drivers/input/touchscreen/atmel_mxt_ts.c -X: drivers/net/wireless/atmel/ N: at91 N: atmel @@ -2546,7 +2564,6 @@ F: arch/arm64/boot/dts/qcom/sc7280* F: arch/arm64/boot/dts/qcom/sdm845-cheza* ARM/QUALCOMM SUPPORT -M: Andy Gross M: Bjorn Andersson M: Konrad Dybcio L: linux-arm-msm@vger.kernel.org @@ -2826,7 +2843,6 @@ F: Documentation/devicetree/bindings/interrupt-controller/sunplus,sp7021-intc.ya F: Documentation/devicetree/bindings/reset/sunplus,reset.yaml F: arch/arm/boot/dts/sunplus/ F: arch/arm/configs/sp7021_*defconfig -F: arch/arm/mach-sunplus/ F: drivers/clk/clk-sp7021.c F: drivers/irqchip/irq-sp7021-intc.c F: drivers/reset/reset-sunplus.c @@ -2842,11 +2858,6 @@ F: arch/arm/boot/dts/synaptics/ F: arch/arm/mach-berlin/ F: arch/arm64/boot/dts/synaptics/ -ARM/TECHNOLOGIC SYSTEMS TS7250 MACHINE SUPPORT -M: Lennert Buytenhek -L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -S: Maintained - ARM/TEGRA HDMI CEC SUBSYSTEM SUPPORT M: Hans Verkuil L: linux-tegra@vger.kernel.org @@ -2863,11 +2874,6 @@ L: linux-samsung-soc@vger.kernel.org S: Maintained F: arch/arm64/boot/dts/tesla/ -ARM/TETON BGA MACHINE SUPPORT -M: "Mark F. Brown" -L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -S: Maintained - ARM/TEXAS INSTRUMENT AEMIF/EMIF DRIVERS M: Santosh Shilimkar L: linux-kernel@vger.kernel.org @@ -2946,7 +2952,6 @@ F: Documentation/devicetree/bindings/pinctrl/socionext,uniphier-pinctrl.yaml F: Documentation/devicetree/bindings/soc/socionext/socionext,uniphier*.yaml F: arch/arm/boot/dts/socionext/uniphier* F: arch/arm/include/asm/hardware/cache-uniphier.h -F: arch/arm/mach-uniphier/ F: arch/arm/mm/cache-uniphier.c F: arch/arm64/boot/dts/socionext/uniphier* F: drivers/bus/uniphier-system-bus.c @@ -3009,6 +3014,7 @@ F: Documentation/devicetree/bindings/i2c/cdns,i2c-r1p10.yaml F: Documentation/devicetree/bindings/i2c/xlnx,xps-iic-2.00.a.yaml F: Documentation/devicetree/bindings/memory-controllers/snps,dw-umctl2-ddrc.yaml F: Documentation/devicetree/bindings/memory-controllers/xlnx,zynq-ddrc-a05.yaml +F: Documentation/devicetree/bindings/soc/xilinx/xilinx.yaml F: Documentation/devicetree/bindings/spi/xlnx,zynq-qspi.yaml F: arch/arm/mach-zynq/ F: drivers/clocksource/timer-cadence-ttc.c @@ -3060,6 +3066,13 @@ S: Supported W: http://www.akm.com/ F: drivers/iio/magnetometer/ak8974.c +AOSONG AGS02MA TVOC SENSOR DRIVER +M: Anshul Dalal +L: linux-iio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/iio/chemical/aosong,ags02ma.yaml +F: drivers/iio/chemical/ags02ma.c + ASC7621 HARDWARE MONITOR DRIVER M: George Joseph L: linux-hwmon@vger.kernel.org @@ -3073,6 +3086,14 @@ S: Maintained F: Documentation/devicetree/bindings/net/asix,ax88796c.yaml F: drivers/net/ethernet/asix/ax88796c_* +ASIX PHY DRIVER [RUST] +M: FUJITA Tomonori +R: Trevor Gross +L: netdev@vger.kernel.org +L: rust-for-linux@vger.kernel.org +S: Maintained +F: drivers/net/phy/ax88796b_rust.rs + ASPEED CRYPTO DRIVER M: Neal Liu L: linux-aspeed@lists.ozlabs.org (moderated for non-subscribers) @@ -3147,10 +3168,10 @@ F: drivers/hwmon/asus-ec-sensors.c ASUS NOTEBOOKS AND EEEPC ACPI/WMI EXTRAS DRIVERS M: Corentin Chary -L: acpi4asus-user@lists.sourceforge.net +M: Luke D. Jones L: platform-driver-x86@vger.kernel.org S: Maintained -W: http://acpi4asus.sf.net +W: https://asus-linux.org/ F: drivers/platform/x86/asus*.c F: drivers/platform/x86/eeepc*.c @@ -3298,13 +3319,6 @@ T: git git://github.com/ndyer/linux.git F: Documentation/devicetree/bindings/input/atmel,maxtouch.yaml F: drivers/input/touchscreen/atmel_mxt_ts.c -ATMEL WIRELESS DRIVER -L: linux-wireless@vger.kernel.org -S: Orphan -W: http://www.thekelleys.org.uk/atmel -W: http://atmelwlandriver.sourceforge.net/ -F: drivers/net/wireless/atmel/atmel* - ATOMIC INFRASTRUCTURE M: Will Deacon M: Peter Zijlstra @@ -3339,13 +3353,17 @@ M: Eric Paris L: audit@vger.kernel.org S: Supported W: https://github.com/linux-audit -T: git git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/audit.git +Q: https://patchwork.kernel.org/project/audit/list +B: mailto:audit@vger.kernel.org +P: https://github.com/linux-audit/audit-kernel/blob/main/README.md +T: git https://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/audit.git F: include/asm-generic/audit_*.h F: include/linux/audit.h F: include/linux/audit_arch.h F: include/uapi/linux/audit.h F: kernel/audit* F: lib/*audit.c +K: \baudit_[a-z_0-9]\+\b AUXILIARY BUS DRIVER M: Greg Kroah-Hartman @@ -3372,9 +3390,8 @@ F: Documentation/devicetree/bindings/iio/adc/avia-hx711.yaml F: drivers/iio/adc/hx711.c AX.25 NETWORK LAYER -M: Ralf Baechle L: linux-hams@vger.kernel.org -S: Maintained +S: Orphan W: https://linux-ax25.in-berlin.de F: include/net/ax25.h F: include/uapi/linux/ax25.h @@ -3404,6 +3421,16 @@ W: https://ez.analog.com/linux-software-drivers F: Documentation/devicetree/bindings/hwmon/adi,axi-fan-control.yaml F: drivers/hwmon/axi-fan-control.c +AXI SPI ENGINE +M: Michael Hennerich +M: Nuno Sá +R: David Lechner +L: linux-spi@vger.kernel.org +S: Supported +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/spi/adi,axi-spi-engine.yaml +F: drivers/spi/spi-axi-spi-engine.c + AXXIA I2C CONTROLLER M: Krzysztof Adamski L: linux-i2c@vger.kernel.org @@ -3456,6 +3483,14 @@ F: drivers/video/backlight/ F: include/linux/backlight.h F: include/linux/pwm_backlight.h +BAIKAL-T1 PVT HARDWARE MONITOR DRIVER +M: Serge Semin +L: linux-hwmon@vger.kernel.org +S: Supported +F: Documentation/devicetree/bindings/hwmon/baikal,bt1-pvt.yaml +F: Documentation/hwmon/bt1-pvt.rst +F: drivers/hwmon/bt1-pvt.[ch] + BARCO P50 GPIO DRIVER M: Santosh Kumar Yadav M: Peter Korsgaard @@ -3488,7 +3523,7 @@ F: drivers/net/hamradio/baycom* BCACHE (BLOCK LAYER CACHE) M: Coly Li -M: Kent Overstreet +M: Kent Overstreet L: linux-bcache@vger.kernel.org S: Maintained W: http://bcache.evilpiepirate.org @@ -3595,7 +3630,6 @@ F: drivers/mtd/devices/block2mtd.c BLUETOOTH DRIVERS M: Marcel Holtmann -M: Johan Hedberg M: Luiz Augusto von Dentz L: linux-bluetooth@vger.kernel.org S: Supported @@ -3636,6 +3670,13 @@ S: Maintained F: Documentation/devicetree/bindings/iio/accel/bosch,bma400.yaml F: drivers/iio/accel/bma400* +BOSCH SENSORTEC BMI323 IMU IIO DRIVER +M: Jagath Jog J +L: linux-iio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/iio/imu/bosch,bmi323.yaml +F: drivers/iio/imu/bmi323/ + BPF JIT for ARM M: Russell King M: Puranjay Mohan @@ -3651,6 +3692,13 @@ L: bpf@vger.kernel.org S: Supported F: arch/arm64/net/ +BPF JIT for LOONGARCH +M: Tiezhu Yang +R: Hengqi Chen +L: bpf@vger.kernel.org +S: Maintained +F: arch/loongarch/net/ + BPF JIT for MIPS (32-BIT AND 64-BIT) M: Johan Almbladh M: Paul Burton @@ -4499,7 +4547,7 @@ F: drivers/net/ieee802154/ca8210.c CACHEFILES: FS-CACHE BACKEND FOR CACHING ON MOUNTED FILESYSTEMS M: David Howells -L: linux-cachefs@redhat.com (moderated for non-subscribers) +L: netfs@lists.linux.dev S: Supported F: Documentation/filesystems/caching/cachefiles.rst F: fs/cachefiles/ @@ -4683,11 +4731,8 @@ F: drivers/i2c/busses/i2c-octeon* F: drivers/i2c/busses/i2c-thunderx* CAVIUM LIQUIDIO NETWORK DRIVER -M: Derek Chickles -M: Satanand Burla -M: Felix Manlunas L: netdev@vger.kernel.org -S: Supported +S: Orphan W: http://www.marvell.com F: drivers/net/ethernet/cavium/liquidio/ @@ -5157,7 +5202,7 @@ M: Philipp Zabel L: linux-media@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/media/coda.yaml -F: drivers/media/platform/chips-media/ +F: drivers/media/platform/chips-media/coda CODE OF CONDUCT M: Greg Kroah-Hartman @@ -5191,7 +5236,7 @@ X: drivers/clk/clkdev.c COMMON INTERNET FILE SYSTEM CLIENT (CIFS and SMB3) M: Steve French R: Paulo Alcantara (DFS, global name space) -R: Ronnie Sahlberg (directory leases, sparse files) +R: Ronnie Sahlberg (directory leases, sparse files) R: Shyam Prasad N (multichannel) R: Tom Talpey (RDMA, smbdirect) L: linux-cifs@vger.kernel.org @@ -5244,6 +5289,7 @@ M: Dan Williams L: linux-cxl@vger.kernel.org S: Maintained F: drivers/cxl/ +F: include/linux/cxl-event.h F: include/uapi/linux/cxl_mem.h F: tools/testing/cxl/ @@ -5261,10 +5307,10 @@ W: http://accessrunner.sourceforge.net/ F: drivers/usb/atm/cxacru.c CONFIDENTIAL COMPUTING THREAT MODEL FOR X86 VIRTUALIZATION (SNP/TDX) -M: Elena Reshetova -M: Carlos Bilbao -S: Maintained -F: Documentation/security/snp-tdx-threat-model.rst +M: Elena Reshetova +M: Carlos Bilbao +S: Maintained +F: Documentation/security/snp-tdx-threat-model.rst CONFIGFS M: Joel Becker @@ -5339,6 +5385,7 @@ L: linux-mm@kvack.org S: Maintained F: mm/memcontrol.c F: mm/swap_cgroup.c +F: samples/cgroup/* F: tools/testing/selftests/cgroup/memcg_protection.m F: tools/testing/selftests/cgroup/test_hugetlb_memcg.c F: tools/testing/selftests/cgroup/test_kmem.c @@ -5376,6 +5423,12 @@ F: include/linux/counter.h F: include/uapi/linux/counter.h F: tools/counter/ +COUNTER WATCH EVENTS TOOL +M: Fabrice Gasnier +L: linux-iio@vger.kernel.org +S: Maintained +F: tools/counter/counter_watch_events.c + CP2615 I2C DRIVER M: Bence Csókás S: Maintained @@ -5523,6 +5576,12 @@ F: include/crypto/ F: include/linux/crypto* F: lib/crypto/ +CRYPTO SPEED TEST COMPARE +M: Wang Jinchao +L: linux-crypto@vger.kernel.org +S: Maintained +F: tools/crypto/tcrypt/tcrypt_speed_compare.py + CRYPTOGRAPHIC RANDOM NUMBER GENERATOR M: Neil Horman L: linux-crypto@vger.kernel.org @@ -5882,7 +5941,7 @@ DELL SYSTEMS MANAGEMENT BASE DRIVER (dcdbas) M: Stuart Hayes L: platform-driver-x86@vger.kernel.org S: Maintained -F: Documentation/driver-api/dcdbas.rst +F: Documentation/userspace-api/dcdbas.rst F: drivers/platform/x86/dell/dcdbas.* DELL WMI DDV DRIVER @@ -5899,7 +5958,6 @@ S: Maintained F: drivers/platform/x86/dell/dell-wmi-descriptor.c DELL WMI HARDWARE PRIVACY SUPPORT -M: Perry Yuan L: Dell.Client.Kernel@dell.com L: platform-driver-x86@vger.kernel.org S: Maintained @@ -6096,7 +6154,7 @@ F: Documentation/devicetree/bindings/regulator/dlg,da9*.yaml F: Documentation/devicetree/bindings/regulator/dlg,slg51000.yaml F: Documentation/devicetree/bindings/sound/da[79]*.txt F: Documentation/devicetree/bindings/thermal/da90??-thermal.txt -F: Documentation/devicetree/bindings/watchdog/da90??-wdt.txt +F: Documentation/devicetree/bindings/watchdog/dlg,da90??-watchdog.yaml F: Documentation/hwmon/da90??.rst F: drivers/gpio/gpio-da90??.c F: drivers/hwmon/da90??-hwmon.c @@ -6482,8 +6540,7 @@ T: git git://anongit.freedesktop.org/drm/drm-misc F: drivers/gpu/drm/sun4i/sun8i* DRM DRIVER FOR ARM PL111 CLCD -M: Emma Anholt -S: Supported +S: Orphan T: git git://anongit.freedesktop.org/drm/drm-misc F: drivers/gpu/drm/pl111/ @@ -6598,8 +6655,7 @@ F: Documentation/devicetree/bindings/display/panel/himax,hx8394.yaml F: drivers/gpu/drm/panel/panel-himax-hx8394.c DRM DRIVER FOR HX8357D PANELS -M: Emma Anholt -S: Maintained +S: Orphan T: git git://anongit.freedesktop.org/drm/drm-misc F: Documentation/devicetree/bindings/display/himax,hx8357d.txt F: drivers/gpu/drm/tiny/hx8357d.c @@ -6626,6 +6682,12 @@ T: git git://anongit.freedesktop.org/drm/drm-misc F: Documentation/devicetree/bindings/display/ilitek,ili9486.yaml F: drivers/gpu/drm/tiny/ili9486.c +DRM DRIVER FOR ILITEK ILI9805 PANELS +M: Michael Trimarchi +S: Maintained +F: Documentation/devicetree/bindings/display/panel/ilitek,ili9805.yaml +F: drivers/gpu/drm/panel/panel-ilitek-ili9805.c + DRM DRIVER FOR JADARD JD9365DA-H3 MIPI-DSI LCD PANELS M: Jagan Teki S: Maintained @@ -6854,6 +6916,12 @@ T: git git://anongit.freedesktop.org/drm/drm-misc F: Documentation/devicetree/bindings/display/ste,mcde.yaml F: drivers/gpu/drm/mcde/ +DRM DRIVER FOR SYNAPTICS R63353 PANELS +M: Michael Trimarchi +S: Maintained +F: Documentation/devicetree/bindings/display/panel/synaptics,r63353.yaml +F: drivers/gpu/drm/panel/panel-synaptics-r63353.c + DRM DRIVER FOR TI DLPC3433 MIPI DSI TO DMD BRIDGE M: Jagan Teki S: Maintained @@ -7138,6 +7206,7 @@ F: include/linux/platform_data/shmob_drm.h DRM DRIVERS FOR ROCKCHIP M: Sandy Huang M: Heiko Stübner +M: Andy Yan L: dri-devel@lists.freedesktop.org S: Maintained T: git git://anongit.freedesktop.org/drm/drm-misc @@ -7192,8 +7261,8 @@ F: Documentation/devicetree/bindings/display/ti/ F: drivers/gpu/drm/omapdrm/ DRM DRIVERS FOR V3D -M: Emma Anholt M: Melissa Wen +M: Maíra Canal S: Supported T: git git://anongit.freedesktop.org/drm/drm-misc F: Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml @@ -7201,7 +7270,6 @@ F: drivers/gpu/drm/v3d/ F: include/uapi/drm/v3d_drm.h DRM DRIVERS FOR VC4 -M: Emma Anholt M: Maxime Ripard S: Supported T: git git://github.com/anholt/linux @@ -7878,12 +7946,21 @@ F: include/uapi/linux/mdio.h F: include/uapi/linux/mii.h F: net/core/of_net.c -EXEC & BINFMT API +ETHERNET PHY LIBRARY [RUST] +M: FUJITA Tomonori +R: Trevor Gross +L: netdev@vger.kernel.org +L: rust-for-linux@vger.kernel.org +S: Maintained +F: rust/kernel/net/phy.rs + +EXEC & BINFMT API, ELF R: Eric Biederman R: Kees Cook L: linux-mm@kvack.org S: Supported T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/execve +F: Documentation/userspace-api/ELF.rst F: fs/*binfmt_*.c F: fs/exec.c F: include/linux/binfmts.h @@ -7925,6 +8002,7 @@ F: include/uapi/linux/ext4.h Extended Verification Module (EVM) M: Mimi Zohar +M: Roberto Sassu L: linux-integrity@vger.kernel.org S: Supported T: git git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git @@ -8103,6 +8181,7 @@ F: include/trace/events/fs_dax.h FILESYSTEMS (VFS and infrastructure) M: Alexander Viro M: Christian Brauner +R: Jan Kara L: linux-fsdevel@vger.kernel.org S: Maintained F: fs/* @@ -8123,6 +8202,16 @@ F: fs/exportfs/ F: fs/fhandle.c F: include/linux/exportfs.h +FILESYSTEMS [IDMAPPED MOUNTS] +M: Christian Brauner +M: Seth Forshee +L: linux-fsdevel@vger.kernel.org +S: Maintained +F: Documentation/filesystems/idmappings.rst +F: fs/mnt_idmapping.c +F: include/linux/mnt_idmapping.* +F: tools/testing/selftests/mount_setattr/ + FILESYSTEMS [IOMAP] M: Christian Brauner R: Darrick J. Wong @@ -8132,6 +8221,29 @@ S: Supported F: fs/iomap/ F: include/linux/iomap.h +FILESYSTEMS [NETFS LIBRARY] +M: David Howells +R: Jeff Layton +L: netfs@lists.linux.dev +L: linux-fsdevel@vger.kernel.org +S: Supported +F: Documentation/filesystems/caching/ +F: Documentation/filesystems/netfs_library.rst +F: fs/netfs/ +F: include/linux/fscache*.h +F: include/linux/netfs.h +F: include/trace/events/fscache.h +F: include/trace/events/netfs.h + +FILESYSTEMS [STACKABLE] +M: Miklos Szeredi +M: Amir Goldstein +L: linux-fsdevel@vger.kernel.org +L: linux-unionfs@vger.kernel.org +S: Maintained +F: fs/backing-file.c +F: include/linux/backing-file.h + FINTEK F75375S HARDWARE MONITOR AND FAN CONTROLLER DRIVER M: Riku Voipio L: linux-hwmon@vger.kernel.org @@ -8218,11 +8330,14 @@ L: linux-input@vger.kernel.org S: Maintained F: drivers/input/joystick/fsia6b.c -FOCUSRITE SCARLETT GEN 2/3 MIXER DRIVER +FOCUSRITE SCARLETT2 MIXER DRIVER (Scarlett Gen 2+ and Clarett) M: Geoffrey D. Bennett L: alsa-devel@alsa-project.org (moderated for non-subscribers) S: Maintained -T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git +W: https://github.com/geoffreybennett/scarlett-gen2 +B: https://github.com/geoffreybennett/scarlett-gen2/issues +T: git https://github.com/geoffreybennett/scarlett-gen2.git +F: include/uapi/sound/scarlett2.h F: sound/usb/mixer_scarlett2.c FORCEDETH GIGABIT ETHERNET DRIVER @@ -8527,7 +8642,6 @@ L: linuxppc-dev@lists.ozlabs.org S: Maintained F: sound/soc/fsl/fsl* F: sound/soc/fsl/imx* -F: sound/soc/fsl/mpc8610_hpcd.c FREESCALE SOC SOUND QMC DRIVER M: Herve Codina @@ -8566,14 +8680,6 @@ F: Documentation/power/freezing-of-tasks.rst F: include/linux/freezer.h F: kernel/freezer.c -FS-CACHE: LOCAL CACHING FOR NETWORK FILESYSTEMS -M: David Howells -L: linux-cachefs@redhat.com (moderated for non-subscribers) -S: Supported -F: Documentation/filesystems/caching/ -F: fs/fscache/ -F: include/linux/fscache*.h - FSCRYPT: FILE SYSTEM LEVEL ENCRYPTION SUPPORT M: Eric Biggers M: Theodore Y. Ts'o @@ -8706,6 +8812,21 @@ F: kernel/futex/* F: tools/perf/bench/futex* F: tools/testing/selftests/futex/ +GALAXYCORE GC0308 CAMERA SENSOR DRIVER +M: Sebastian Reichel +L: linux-media@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/media/i2c/galaxycore,gc0308.yaml +F: drivers/media/i2c/gc0308.c + +GALAXYCORE GC2145 SENSOR DRIVER +M: Alain Volmat +L: linux-media@vger.kernel.org +S: Maintained +T: git git://linuxtv.org/media_tree.git +F: Documentation/devicetree/bindings/media/i2c/galaxycore,gc2145.yaml +F: drivers/media/i2c/gc2145.c + GATEWORKS SYSTEM CONTROLLER (GSC) DRIVER M: Tim Harvey S: Maintained @@ -8824,21 +8945,13 @@ F: Documentation/devicetree/bindings/i2c/i2c-demux-pinctrl.yaml F: drivers/i2c/muxes/i2c-demux-pinctrl.c GENERIC PM DOMAINS -M: "Rafael J. Wysocki" -M: Kevin Hilman M: Ulf Hansson L: linux-pm@vger.kernel.org S: Supported F: Documentation/devicetree/bindings/power/power?domain* -F: drivers/base/power/domain*.c -F: include/linux/pm_domain.h - -GENERIC PM DOMAIN PROVIDERS -M: Ulf Hansson -L: linux-pm@vger.kernel.org -S: Supported T: git git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm.git F: drivers/pmdomain/ +F: include/linux/pm_domain.h GENERIC RADIX TREE M: Kent Overstreet @@ -8905,6 +9018,13 @@ F: Documentation/filesystems/gfs2* F: fs/gfs2/ F: include/uapi/linux/gfs2_ondisk.h +GIGABYTE WATERFORCE SENSOR DRIVER +M: Aleksa Savic +L: linux-hwmon@vger.kernel.org +S: Maintained +F: Documentation/hwmon/gigabyte_waterforce.rst +F: drivers/hwmon/gigabyte_waterforce.c + GIGABYTE WMI DRIVER M: Thomas Weißschuh L: platform-driver-x86@vger.kernel.org @@ -8951,6 +9071,16 @@ S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/chrome-platform/linux.git F: drivers/firmware/google/ +GOOGLE TENSOR SoC SUPPORT +M: Peter Griffin +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) +L: linux-samsung-soc@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/clock/google,gs101-clock.yaml +F: arch/arm64/boot/dts/exynos/google/ +F: drivers/clk/samsung/clk-gs101.c +F: include/dt-bindings/clock/google,gs101.h + GPD POCKET FAN DRIVER M: Hans de Goede L: platform-driver-x86@vger.kernel.org @@ -8990,7 +9120,7 @@ F: drivers/gpio/gpio-mockup.c F: tools/testing/selftests/gpio/ GPIO REGMAP -M: Michael Walle +M: Michael Walle S: Maintained F: drivers/gpio/gpio-regmap.c F: include/linux/gpio/regmap.h @@ -9262,7 +9392,6 @@ F: drivers/char/hw_random/ F: include/linux/hw_random.h HARDWARE SPINLOCK CORE -M: Ohad Ben-Cohen M: Bjorn Andersson R: Baolin Wang L: linux-remoteproc@vger.kernel.org @@ -9491,6 +9620,7 @@ F: Documentation/devicetree/bindings/gpio/hisilicon,ascend910-gpio.yaml F: drivers/gpio/gpio-hisi.c HISILICON HIGH PERFORMANCE RSA ENGINE DRIVER (HPRE) +M: Zhiqi Song M: Longfang Liu L: linux-crypto@vger.kernel.org S: Maintained @@ -9593,7 +9723,6 @@ F: Documentation/devicetree/bindings/scsi/hisilicon-sas.txt F: drivers/scsi/hisi_sas/ HISILICON SECURITY ENGINE V2 DRIVER (SEC2) -M: Kai Ye M: Longfang Liu L: linux-crypto@vger.kernel.org S: Maintained @@ -9653,6 +9782,13 @@ F: lib/test_hmm* F: mm/hmm* F: tools/testing/selftests/mm/*hmm* +HONEYWELL HSC030PA PRESSURE SENSOR SERIES IIO DRIVER +M: Petre Rodan +L: linux-iio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/iio/pressure/honeywell,hsc030pa.yaml +F: drivers/iio/pressure/hsc030pa* + HONEYWELL MPRLS0025PA PRESSURE SENSOR SERIES IIO DRIVER M: Andreas Klinger L: linux-iio@vger.kernel.org @@ -9660,11 +9796,6 @@ S: Maintained F: Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml F: drivers/iio/pressure/mprls0025pa.c -HOST AP DRIVER -L: linux-wireless@vger.kernel.org -S: Obsolete -F: drivers/net/wireless/intersil/hostap/ - HP BIOSCFG DRIVER M: Jorge Lopez L: platform-driver-x86@vger.kernel.org @@ -9938,7 +10069,7 @@ F: Documentation/i2c/busses/i2c-parport.rst F: drivers/i2c/busses/i2c-parport.c I2C SUBSYSTEM -M: Wolfram Sang +M: Wolfram Sang L: linux-i2c@vger.kernel.org S: Maintained W: https://i2c.wiki.kernel.org/ @@ -10116,7 +10247,6 @@ IBM Power SRIOV Virtual NIC Device Driver M: Haren Myneni M: Rick Lindsley R: Nick Child -R: Dany Madden R: Thomas Falcon L: netdev@vger.kernel.org S: Supported @@ -10202,16 +10332,6 @@ S: Maintained W: https://github.com/o2genum/ideapad-slidebar F: drivers/input/misc/ideapad_slidebar.c -IDMAPPED MOUNTS -M: Christian Brauner -M: Seth Forshee -L: linux-fsdevel@vger.kernel.org -S: Maintained -T: git git://git.kernel.org/pub/scm/linux/kernel/git/vfs/idmapping.git -F: Documentation/filesystems/idmappings.rst -F: include/linux/mnt_idmapping.* -F: tools/testing/selftests/mount_setattr/ - IDT VersaClock 5 CLOCK DRIVER M: Luca Ceresoli S: Maintained @@ -10283,8 +10403,8 @@ IIO LIGHT SENSOR GAIN-TIME-SCALE HELPERS M: Matti Vaittinen L: linux-iio@vger.kernel.org S: Maintained -F: drivers/iio/light/gain-time-scale-helper.c -F: drivers/iio/light/gain-time-scale-helper.h +F: drivers/iio/industrialio-gts-helper.c +F: include/linux/iio/iio-gts-helper.h IIO MULTIPLEXER M: Peter Rosin @@ -10345,6 +10465,17 @@ IMGTEC IR DECODER DRIVER S: Orphan F: drivers/media/rc/img-ir/ +IMGTEC POWERVR DRM DRIVER +M: Frank Binns +M: Donald Robson +M: Matt Coster +S: Supported +T: git git://anongit.freedesktop.org/drm/drm-misc +F: Documentation/devicetree/bindings/gpu/img,powervr.yaml +F: Documentation/gpu/imagination/ +F: drivers/gpu/drm/imagination/ +F: include/uapi/drm/pvr_drm.h + IMON SOUNDGRAPH USB IR RECEIVER M: Sean Young L: linux-media@vger.kernel.org @@ -10504,7 +10635,9 @@ F: drivers/crypto/inside-secure/ INTEGRITY MEASUREMENT ARCHITECTURE (IMA) M: Mimi Zohar +M: Roberto Sassu M: Dmitry Kasatkin +R: Eric Snowberg L: linux-integrity@vger.kernel.org S: Supported T: git git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git @@ -10582,16 +10715,26 @@ L: linux-kernel@vger.kernel.org S: Supported F: arch/x86/include/asm/intel-family.h -INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets) +INTEL DRM DISPLAY FOR XE AND I915 DRIVERS +M: Jani Nikula +M: Rodrigo Vivi +L: intel-gfx@lists.freedesktop.org +L: intel-xe@lists.freedesktop.org +S: Supported +F: drivers/gpu/drm/i915/display/ +F: drivers/gpu/drm/xe/display/ +F: drivers/gpu/drm/xe/compat-i915-headers + +INTEL DRM I915 DRIVER (Meteor Lake, DG2 and older excluding Poulsbo, Moorestown and derivative) M: Jani Nikula M: Joonas Lahtinen M: Rodrigo Vivi M: Tvrtko Ursulin L: intel-gfx@lists.freedesktop.org S: Supported -W: https://01.org/linuxgraphics/ +W: https://drm.pages.freedesktop.org/intel-docs/ Q: http://patchwork.freedesktop.org/project/intel-gfx/ -B: https://gitlab.freedesktop.org/drm/intel/-/wikis/How-to-file-i915-bugs +B: https://drm.pages.freedesktop.org/intel-docs/how-to-file-i915-bugs.html C: irc://irc.oftc.net/intel-gfx T: git git://anongit.freedesktop.org/drm-intel F: Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon @@ -10601,6 +10744,23 @@ F: drivers/gpu/drm/i915/ F: include/drm/i915* F: include/uapi/drm/i915_drm.h +INTEL DRM XE DRIVER (Lunar Lake and newer) +M: Lucas De Marchi +M: Oded Gabbay +M: Thomas Hellström +L: intel-xe@lists.freedesktop.org +S: Supported +W: https://drm.pages.freedesktop.org/intel-docs/ +Q: http://patchwork.freedesktop.org/project/intel-xe/ +B: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues +C: irc://irc.oftc.net/xe +T: git https://gitlab.freedesktop.org/drm/xe/kernel.git +F: Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon +F: Documentation/gpu/xe/ +F: drivers/gpu/drm/xe/ +F: include/drm/xe* +F: include/uapi/drm/xe_drm.h + INTEL ETHERNET DRIVERS M: Jesse Brandeburg M: Tony Nguyen @@ -10624,13 +10784,6 @@ S: Supported F: drivers/infiniband/hw/irdma/ F: include/uapi/rdma/irdma-abi.h -INTEL FRAMEBUFFER DRIVER (excluding 810 and 815) -M: Maik Broemme -L: linux-fbdev@vger.kernel.org -S: Maintained -F: Documentation/fb/intelfb.rst -F: drivers/video/fbdev/intelfb/ - INTEL GPIO DRIVERS M: Andy Shevchenko L: linux-gpio@vger.kernel.org @@ -10670,6 +10823,13 @@ S: Supported Q: https://patchwork.kernel.org/project/linux-dmaengine/list/ F: drivers/dma/ioat* +INTEL IAA CRYPTO DRIVER +M: Tom Zanussi +L: linux-crypto@vger.kernel.org +S: Supported +F: Documentation/driver-api/crypto/iaa/iaa-crypto.rst +F: drivers/crypto/intel/iaa/* + INTEL IDLE DRIVER M: Jacob Pan M: Len Brown @@ -10968,6 +11128,7 @@ F: drivers/net/wireless/intel/iwlegacy/ INTEL WIRELESS WIFI LINK (iwlwifi) M: Gregory Greenman +M: Miri Korenblit L: linux-wireless@vger.kernel.org S: Supported W: https://wireless.wiki.kernel.org/en/users/drivers/iwlwifi @@ -11107,6 +11268,7 @@ L: io-uring@vger.kernel.org S: Maintained T: git git://git.kernel.dk/linux-block T: git git://git.kernel.dk/liburing +F: include/linux/io_uring/ F: include/linux/io_uring.h F: include/linux/io_uring_types.h F: include/trace/events/io_uring.h @@ -11202,7 +11364,7 @@ F: drivers/media/radio/radio-isa* ISAPNP M: Jaroslav Kysela S: Maintained -F: Documentation/driver-api/isapnp.rst +F: Documentation/userspace-api/isapnp.rst F: drivers/pnp/isapnp/ F: include/linux/isapnp.h @@ -11975,6 +12137,14 @@ S: Maintained F: arch/mips/lantiq F: drivers/soc/lantiq +LANTIQ PEF2256 DRIVER +M: Herve Codina +S: Maintained +F: Documentation/devicetree/bindings/net/lantiq,pef2256.yaml +F: drivers/net/wan/framer/pef2256/ +F: drivers/pinctrl/pinctrl-pef2256.c +F: include/linux/framer/pef2256.h + LASI 53c700 driver for PARISC M: "James E.J. Bottomley" L: linux-scsi@vger.kernel.org @@ -12102,9 +12272,10 @@ F: drivers/ata/sata_promise.* LIBATA SUBSYSTEM (Serial and Parallel ATA drivers) M: Damien Le Moal +M: Niklas Cassel L: linux-ide@vger.kernel.org S: Maintained -T: git git://git.kernel.org/pub/scm/linux/kernel/git/dlemoal/libata.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/libata/linux.git F: Documentation/ABI/testing/sysfs-ata F: Documentation/devicetree/bindings/ata/ F: drivers/ata/ @@ -12242,21 +12413,21 @@ S: Orphan F: arch/powerpc/platforms/40x/ F: arch/powerpc/platforms/44x/ -LINUX FOR POWERPC EMBEDDED PPC83XX AND PPC85XX +LINUX FOR POWERPC EMBEDDED PPC85XX M: Scott Wood L: linuxppc-dev@lists.ozlabs.org S: Odd fixes T: git git://git.kernel.org/pub/scm/linux/kernel/git/scottwood/linux.git F: Documentation/devicetree/bindings/cache/freescale-l2cache.txt F: Documentation/devicetree/bindings/powerpc/fsl/ -F: arch/powerpc/platforms/83xx/ F: arch/powerpc/platforms/85xx/ -LINUX FOR POWERPC EMBEDDED PPC8XX +LINUX FOR POWERPC EMBEDDED PPC8XX AND PPC83XX M: Christophe Leroy L: linuxppc-dev@lists.ozlabs.org S: Maintained F: arch/powerpc/platforms/8xx/ +F: arch/powerpc/platforms/83xx/ LINUX KERNEL DUMP TEST MODULE (LKDTM) M: Kees Cook @@ -12403,6 +12574,12 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/har F: Documentation/admin-guide/LSM/LoadPin.rst F: security/loadpin/ +LOCKDOWN SECURITY MODULE +L: linux-security-module@vger.kernel.org +S: Odd Fixes +T: git https://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm.git +F: security/lockdown/ + LOCKING PRIMITIVES M: Peter Zijlstra M: Ingo Molnar @@ -12414,7 +12591,7 @@ S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git locking/core F: Documentation/locking/ F: arch/*/include/asm/spinlock*.h -F: include/linux/lockdep.h +F: include/linux/lockdep*.h F: include/linux/mutex*.h F: include/linux/rwlock*.h F: include/linux/rwsem*.h @@ -12463,6 +12640,13 @@ S: Maintained F: Documentation/devicetree/bindings/gpio/loongson,ls-gpio.yaml F: drivers/gpio/gpio-loongson-64bit.c +LOONGSON LS2X APB DMA DRIVER +M: Binbin Zhou +L: dmaengine@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/dma/loongson,ls2x-apbdma.yaml +F: drivers/dma/ls2x-apb-dma.c + LOONGSON LS2X I2C DRIVER M: Binbin Zhou L: linux-i2c@vger.kernel.org @@ -12585,6 +12769,16 @@ S: Maintained F: Documentation/hwmon/ltc4261.rst F: drivers/hwmon/ltc4261.c +LTC4286 HARDWARE MONITOR DRIVER +M: Delphine CC Chiu +L: linux-i2c@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/hwmon/lltc,ltc4286.yaml +F: Documentation/hwmon/ltc4286.rst +F: drivers/hwmon/pmbus/Kconfig +F: drivers/hwmon/pmbus/Makefile +F: drivers/hwmon/pmbus/ltc4286.c + LTC4306 I2C MULTIPLEXER DRIVER M: Michael Hennerich L: linux-i2c@vger.kernel.org @@ -12594,17 +12788,23 @@ F: Documentation/devicetree/bindings/i2c/i2c-mux-ltc4306.txt F: drivers/i2c/muxes/i2c-mux-ltc4306.c LTP (Linux Test Project) -M: Mike Frysinger M: Cyril Hrubis -M: Wanlong Gao M: Jan Stancek -M: Stanislav Kholmanskikh -M: Alexey Kodanev +M: Petr Vorel +M: Li Wang +M: Yang Xu L: ltp@lists.linux.it (subscribers-only) S: Maintained W: http://linux-test-project.github.io/ T: git https://github.com/linux-test-project/ltp.git +LTR390 AMBIENT/UV LIGHT SENSOR DRIVER +M: Anshul Dalal +L: linux-iio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/iio/light/liteon,ltr390.yaml +F: drivers/iio/light/ltr390.c + LYNX 28G SERDES PHY DRIVER M: Ioana Ciornei L: netdev@vger.kernel.org @@ -12699,7 +12899,7 @@ F: drivers/mailbox/arm_mhuv2.c F: include/linux/mailbox/arm_mhuv2_message.h MAN-PAGES: MANUAL PAGES FOR LINUX -- Sections 2, 3, 4, 5, and 7 -M: Michael Kerrisk +M: Alejandro Colomar L: linux-man@vger.kernel.org S: Maintained W: http://www.kernel.org/doc/man-pages @@ -12739,7 +12939,8 @@ MARVELL 88E6XXX ETHERNET SWITCH FABRIC DRIVER M: Andrew Lunn L: netdev@vger.kernel.org S: Maintained -F: Documentation/devicetree/bindings/net/dsa/marvell.txt +F: Documentation/devicetree/bindings/net/dsa/marvell,mv88e6060.yaml +F: Documentation/devicetree/bindings/net/dsa/marvell,mv88e6xxx.yaml F: Documentation/networking/devlink/mv88e6xxx.rst F: drivers/net/dsa/mv88e6xxx/ F: include/linux/dsa/mv88e6xxx.h @@ -12816,10 +13017,10 @@ S: Maintained F: drivers/thermal/armada_thermal.c MARVELL MVNETA ETHERNET DRIVER -M: Thomas Petazzoni +M: Marcin Wojtas L: netdev@vger.kernel.org S: Maintained -F: drivers/net/ethernet/marvell/mvneta.* +F: drivers/net/ethernet/marvell/mvneta* MARVELL MVPP2 ETHERNET DRIVER M: Marcin Wojtas @@ -12939,6 +13140,14 @@ F: Documentation/devicetree/bindings/hwmon/adi,max31827.yaml F: Documentation/hwmon/max31827.rst F: drivers/hwmon/max31827.c +MAX31335 RTC DRIVER +M: Antoniu Miclaus +L: linux-rtc@vger.kernel.org +S: Supported +W: https://ez.analog.com/linux-software-drivers +F: Documentation/devicetree/bindings/rtc/adi,max31335.yaml +F: drivers/rtc/rtc-max31335.c + MAX6650 HARDWARE MONITOR AND FAN CONTROLLER DRIVER L: linux-hwmon@vger.kernel.org S: Orphan @@ -12968,6 +13177,7 @@ MAX96712 QUAD GMSL2 DESERIALIZER DRIVER M: Niklas Söderlund L: linux-media@vger.kernel.org S: Maintained +F: Documentation/devicetree/bindings/media/i2c/maxim,max96712.yaml F: drivers/staging/media/max96712/max96712.c MAX9860 MONO AUDIO VOICE CODEC DRIVER @@ -13147,6 +13357,13 @@ F: Documentation/ABI/testing/sysfs-bus-iio-potentiometer-mcp4531 F: drivers/iio/potentiometer/mcp4018.c F: drivers/iio/potentiometer/mcp4531.c +MCP4821 DAC DRIVER +M: Anshul Dalal +L: linux-iio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/iio/dac/microchip,mcp4821.yaml +F: drivers/iio/dac/mcp4821.c + MCR20A IEEE-802.15.4 RADIO DRIVER M: Stefan Schmidt L: linux-wpan@vger.kernel.org @@ -13388,13 +13605,16 @@ W: https://linuxtv.org T: git git://linuxtv.org/media_tree.git F: drivers/media/dvb-frontends/stv6111* -MEDIA DRIVERS FOR STM32 - DCMI +MEDIA DRIVERS FOR STM32 - DCMI / DCMIPP M: Hugues Fruchet +M: Alain Volmat L: linux-media@vger.kernel.org S: Supported T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml +F: Documentation/devicetree/bindings/media/st,stm32-dcmipp.yaml F: drivers/media/platform/st/stm32/stm32-dcmi.c +F: drivers/media/platform/st/stm32/stm32-dcmipp/* MEDIA INPUT INFRASTRUCTURE (V4L/DVB) M: Mauro Carvalho Chehab @@ -13450,7 +13670,6 @@ F: drivers/dma/mediatek/ MEDIATEK ETHERNET DRIVER M: Felix Fietkau -M: John Crispin M: Sean Wang M: Mark Lee M: Lorenzo Bianconi @@ -13606,7 +13825,6 @@ F: include/soc/mediatek/smi.h MEDIATEK SWITCH DRIVER M: Arınç ÜNAL M: Daniel Golle -M: Landen Chao M: DENG Qingfang M: Sean Wang L: netdev@vger.kernel.org @@ -13671,6 +13889,13 @@ S: Supported W: http://www.melexis.com F: drivers/iio/temperature/mlx90632.c +MELEXIS MLX90635 DRIVER +M: Crt Mori +L: linux-iio@vger.kernel.org +S: Supported +W: http://www.melexis.com +F: drivers/iio/temperature/mlx90635.c + MELFAS MIP4 TOUCHSCREEN DRIVER M: Sangwon Jee S: Supported @@ -14141,11 +14366,12 @@ F: Documentation/devicetree/bindings/regulator/mcp16502-regulator.txt F: drivers/regulator/mcp16502.c MICROCHIP MCP3564 ADC DRIVER -M: Marius Cristea -L: linux-iio@vger.kernel.org -S: Supported -F: Documentation/devicetree/bindings/iio/adc/microchip,mcp3564.yaml -F: drivers/iio/adc/mcp3564.c +M: Marius Cristea +L: linux-iio@vger.kernel.org +S: Supported +F: Documentation/ABI/testing/sysfs-bus-iio-adc-mcp3564 +F: Documentation/devicetree/bindings/iio/adc/microchip,mcp3564.yaml +F: drivers/iio/adc/mcp3564.c MICROCHIP MCP3911 ADC DRIVER M: Marcus Folkesson @@ -14605,6 +14831,13 @@ S: Maintained F: Documentation/driver-api/tty/moxa-smartio.rst F: drivers/tty/mxser.* +MP3309C BACKLIGHT DRIVER +M: Flavio Suligoi +L: dri-devel@lists.freedesktop.org +S: Maintained +F: Documentation/devicetree/bindings/leds/backlight/mps,mp3309c.yaml +F: drivers/video/backlight/mp3309c.c + MR800 AVERMEDIA USB FM RADIO DRIVER M: Alexey Klimov L: linux-media@vger.kernel.org @@ -14941,6 +15174,7 @@ Q: https://patchwork.kernel.org/project/netdevbpf/list/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git F: Documentation/devicetree/bindings/net/ +F: Documentation/networking/net_cachelines/net_device.rst F: drivers/connector/ F: drivers/net/ F: include/dt-bindings/net/ @@ -14996,6 +15230,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git F: Documentation/core-api/netlink.rst F: Documentation/netlink/ F: Documentation/networking/ +F: Documentation/networking/net_cachelines/ F: Documentation/process/maintainer-netdev.rst F: Documentation/userspace-api/netlink/ F: include/linux/in.h @@ -15093,7 +15328,7 @@ W: https://github.com/multipath-tcp/mptcp_net-next/wiki B: https://github.com/multipath-tcp/mptcp_net-next/issues T: git https://github.com/multipath-tcp/mptcp_net-next.git export-net T: git https://github.com/multipath-tcp/mptcp_net-next.git export -F: Documentation/netlink/specs/mptcp.yaml +F: Documentation/netlink/specs/mptcp_pm.yaml F: Documentation/networking/mptcp-sysctl.rst F: include/net/mptcp.h F: include/trace/events/mptcp.h @@ -15106,6 +15341,7 @@ NETWORKING [TCP] M: Eric Dumazet L: netdev@vger.kernel.org S: Maintained +F: Documentation/networking/net_cachelines/tcp_sock.rst F: include/linux/tcp.h F: include/net/tcp.h F: include/trace/events/tcp.h @@ -15237,6 +15473,15 @@ F: include/linux/nitro_enclaves.h F: include/uapi/linux/nitro_enclaves.h F: samples/nitro_enclaves/ +NITRO SECURE MODULE (NSM) +M: Alexander Graf +L: linux-kernel@vger.kernel.org +L: The AWS Nitro Enclaves Team +S: Supported +W: https://aws.amazon.com/ec2/nitro/nitro-enclaves/ +F: drivers/misc/nsm.c +F: include/uapi/linux/nsm.h + NOHZ, DYNTICKS SUPPORT M: Frederic Weisbecker M: Thomas Gleixner @@ -15436,7 +15681,7 @@ NXP C45 TJA11XX PHY DRIVER M: Andrei Botila L: netdev@vger.kernel.org S: Maintained -F: drivers/net/phy/nxp-c45-tja11xx.c +F: drivers/net/phy/nxp-c45-tja11xx* NXP FSPI DRIVER M: Han Xu @@ -15704,9 +15949,8 @@ F: Documentation/devicetree/bindings/gpio/ti,omap-gpio.yaml F: drivers/gpio/gpio-omap.c OMAP HARDWARE SPINLOCK SUPPORT -M: Ohad Ben-Cohen L: linux-omap@vger.kernel.org -S: Maintained +S: Orphan F: drivers/hwspinlock/omap_hwspinlock.c OMAP HS MMC SUPPORT @@ -15806,6 +16050,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap.git F: Documentation/devicetree/bindings/arm/ti/omap.yaml F: arch/arm/configs/omap2plus_defconfig F: arch/arm/mach-omap2/ +F: drivers/bus/omap*.[ch] F: drivers/bus/ti-sysc.c F: drivers/gpio/gpio-tps65219.c F: drivers/i2c/busses/i2c-omap.c @@ -15968,6 +16213,14 @@ S: Maintained T: git git://linuxtv.org/media_tree.git F: drivers/media/i2c/ov5695.c +OMNIVISION OV64A40 SENSOR DRIVER +M: Jacopo Mondi +L: linux-media@vger.kernel.org +S: Maintained +T: git git://linuxtv.org/media_tree.git +F: Documentation/devicetree/bindings/media/i2c/ovti,ov64a40.yaml +F: drivers/media/i2c/ov64a40.c + OMNIVISION OV7670 SENSOR DRIVER L: linux-media@vger.kernel.org S: Orphan @@ -16137,7 +16390,7 @@ F: include/dt-bindings/ OPENCOMPUTE PTP CLOCK DRIVER M: Jonathan Lemon -M: Vadim Fedorenko +M: Vadim Fedorenko L: netdev@vger.kernel.org S: Maintained F: drivers/ptp/ptp_ocp.c @@ -16215,13 +16468,6 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/hubcap/linux.git F: Documentation/filesystems/orangefs.rst F: fs/orangefs/ -ORINOCO DRIVER -L: linux-wireless@vger.kernel.org -S: Orphan -W: https://wireless.wiki.kernel.org/en/users/Drivers/orinoco -W: http://www.nongnu.org/orinoco/ -F: drivers/net/wireless/intersil/orinoco/ - OV2659 OMNIVISION SENSOR DRIVER M: "Lad, Prabhakar" L: linux-media@vger.kernel.org @@ -16902,10 +17148,10 @@ PERFORMANCE EVENTS SUBSYSTEM M: Peter Zijlstra M: Ingo Molnar M: Arnaldo Carvalho de Melo +M: Namhyung Kim R: Mark Rutland R: Alexander Shishkin R: Jiri Olsa -R: Namhyung Kim R: Ian Rogers R: Adrian Hunter L: linux-perf-users@vger.kernel.org @@ -17367,7 +17613,7 @@ F: tools/testing/selftests/proc/ PROC SYSCTL M: Luis Chamberlain M: Kees Cook -M: Iurii Zaikin +M: Joel Granados L: linux-kernel@vger.kernel.org L: linux-fsdevel@vger.kernel.org S: Maintained @@ -17506,12 +17752,11 @@ F: Documentation/devicetree/bindings/leds/irled/pwm-ir-tx.yaml F: drivers/media/rc/pwm-ir-tx.c PWM SUBSYSTEM -M: Thierry Reding -R: Uwe Kleine-König +M: Uwe Kleine-König L: linux-pwm@vger.kernel.org S: Maintained Q: https://patchwork.ozlabs.org/project/linux-pwm/list/ -T: git git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm.git +T: git https://git.kernel.org/pub/scm/linux/kernel/git/ukleinek/linux.git F: Documentation/devicetree/bindings/gpio/gpio-mvebu.yaml F: Documentation/devicetree/bindings/pwm/ F: Documentation/driver-api/pwm.rst @@ -17521,7 +17766,7 @@ F: drivers/video/backlight/pwm_bl.c F: include/dt-bindings/pwm/ F: include/linux/pwm.h F: include/linux/pwm_backlight.h -K: pwm_(config|apply_state|ops) +K: pwm_(config|apply_might_sleep|apply_atomic|ops) PXA GPIO DRIVER M: Robert Jarzmik @@ -18059,6 +18304,7 @@ F: drivers/media/cec/usb/rainshadow/ RALINK MIPS ARCHITECTURE M: John Crispin +M: Sergio Paracuellos L: linux-mips@vger.kernel.org S: Maintained F: arch/mips/ralink @@ -18113,11 +18359,6 @@ F: drivers/ras/ F: include/linux/ras.h F: include/ras/ras_event.h -RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER -L: linux-wireless@vger.kernel.org -S: Orphan -F: drivers/net/wireless/legacy/ray* - RC-CORE / LIRC FRAMEWORK M: Sean Young L: linux-media@vger.kernel.org @@ -18230,7 +18471,6 @@ X: include/linux/srcu*.h X: kernel/rcu/srcu*.c REAL TIME CLOCK (RTC) SUBSYSTEM -M: Alessandro Zummo M: Alexandre Belloni L: linux-rtc@vger.kernel.org S: Maintained @@ -18585,6 +18825,7 @@ F: Documentation/devicetree/bindings/usb/microchip,mpfs-musb.yaml F: arch/riscv/boot/dts/microchip/ F: drivers/char/hw_random/mpfs-rng.c F: drivers/clk/microchip/clk-mpfs*.c +F: drivers/firmware/microchip/mpfs-auto-update.c F: drivers/i2c/busses/i2c-microchip-corei2c.c F: drivers/mailbox/mailbox-mpfs.c F: drivers/pci/controller/pcie-microchip-host.c @@ -18917,7 +19158,7 @@ F: drivers/iommu/s390-iommu.c S390 IUCV NETWORK LAYER M: Alexandra Winter -M: Wenjia Zhang +M: Thorsten Winkler L: linux-s390@vger.kernel.org L: netdev@vger.kernel.org S: Supported @@ -18936,7 +19177,7 @@ F: arch/s390/mm S390 NETWORK DRIVERS M: Alexandra Winter -M: Wenjia Zhang +M: Thorsten Winkler L: linux-s390@vger.kernel.org L: netdev@vger.kernel.org S: Supported @@ -19154,7 +19395,6 @@ R: Alim Akhtar L: linux-samsung-soc@vger.kernel.org S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux.git -T: git git://git.kernel.org/pub/scm/linux/kernel/git/snawrocki/clk.git F: Documentation/devicetree/bindings/clock/samsung,*.yaml F: Documentation/devicetree/bindings/clock/samsung,s3c* F: drivers/clk/samsung/ @@ -19442,22 +19682,29 @@ SECURITY SUBSYSTEM M: Paul Moore M: James Morris M: "Serge E. Hallyn" -L: linux-security-module@vger.kernel.org (suggested Cc:) +L: linux-security-module@vger.kernel.org S: Supported -W: http://kernsec.org/ -T: git git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm.git +Q: https://patchwork.kernel.org/project/linux-security-module/list +B: mailto:linux-security-module@vger.kernel.org +P: https://github.com/LinuxSecurityModule/kernel/blob/main/README.md +T: git https://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm.git +F: include/uapi/linux/lsm.h F: security/ +F: tools/testing/selftests/lsm/ X: security/selinux/ +K: \bsecurity_[a-z_0-9]\+\b SELINUX SECURITY MODULE M: Paul Moore M: Stephen Smalley -M: Eric Paris +R: Ondrej Mosnacek L: selinux@vger.kernel.org S: Supported -W: https://selinuxproject.org W: https://github.com/SELinuxProject -T: git git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux.git +Q: https://patchwork.kernel.org/project/selinux/list +B: mailto:selinux@vger.kernel.org +P: https://github.com/SELinuxProject/selinux-kernel/blob/main/README.md +T: git https://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux.git F: Documentation/ABI/removed/sysfs-selinux-checkreqprot F: Documentation/ABI/removed/sysfs-selinux-disable F: Documentation/admin-guide/LSM/SELinux.rst @@ -19597,6 +19844,19 @@ T: git git://linuxtv.org/media_tree.git F: drivers/media/i2c/rj54n1cb0c.c F: include/media/i2c/rj54n1cb0c.h +SHRINKER +M: Andrew Morton +M: Dave Chinner +R: Qi Zheng +R: Roman Gushchin +R: Muchun Song +L: linux-mm@kvack.org +S: Maintained +F: Documentation/admin-guide/mm/shrinker_debugfs.rst +F: include/linux/shrinker.h +F: mm/shrinker.c +F: mm/shrinker_debug.c + SH_VOU V4L2 OUTPUT DRIVER L: linux-media@vger.kernel.org S: Orphan @@ -19713,6 +19973,13 @@ S: Supported N: sifive K: [^@]sifive +SIFIVE CACHE DRIVER +M: Conor Dooley +L: linux-riscv@lists.infradead.org +S: Maintained +F: Documentation/devicetree/bindings/cache/sifive,ccache0.yaml +F: drivers/cache/sifive_ccache.c + SIFIVE FU540 SYSTEM-ON-CHIP M: Paul Walmsley M: Palmer Dabbelt @@ -19728,13 +19995,6 @@ S: Maintained F: Documentation/devicetree/bindings/dma/sifive,fu540-c000-pdma.yaml F: drivers/dma/sf-pdma/ -SIFIVE SOC DRIVERS -M: Conor Dooley -L: linux-riscv@lists.infradead.org -S: Maintained -T: git https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux.git/ -F: Documentation/devicetree/bindings/cache/sifive,ccache0.yaml -F: drivers/soc/sifive/ SILEAD TOUCHSCREEN DRIVER M: Hans de Goede @@ -19775,11 +20035,6 @@ F: Documentation/devicetree/bindings/display/simple-framebuffer.yaml F: drivers/video/fbdev/simplefb.c F: include/linux/platform_data/simplefb.h -SIMTEC EB110ATX (Chalice CATS) -M: Simtec Linux Team -S: Supported -W: http://www.simtec.co.uk/products/EB110ATX/ - SIOX M: Thorsten Scherer M: Uwe Kleine-König @@ -19829,7 +20084,7 @@ W: http://www.winischhofer.at/linuxsisusbvga.shtml F: drivers/usb/misc/sisusbvga/ SL28 CPLD MFD DRIVER -M: Michael Walle +M: Michael Walle S: Maintained F: Documentation/devicetree/bindings/gpio/kontron,sl28cpld-gpio.yaml F: Documentation/devicetree/bindings/hwmon/kontron,sl28cpld-hwmon.yaml @@ -19844,7 +20099,7 @@ F: drivers/pwm/pwm-sl28cpld.c F: drivers/watchdog/sl28cpld_wdt.c SL28 VPD NVMEM LAYOUT DRIVER -M: Michael Walle +M: Michael Walle S: Maintained F: Documentation/devicetree/bindings/nvmem/layouts/kontron,sl28-vpd.yaml F: drivers/nvmem/layouts/sl28vpd.c @@ -20034,6 +20289,7 @@ F: include/linux/property.h SOFTWARE RAID (Multiple Disks) SUPPORT M: Song Liu +R: Yu Kuai L: linux-raid@vger.kernel.org S: Supported Q: https://patchwork.kernel.org/project/linux-raid/list/ @@ -20288,11 +20544,13 @@ F: drivers/media/dvb-frontends/sp2* SPANISH DOCUMENTATION M: Carlos Bilbao +R: Avadhut Naik S: Maintained F: Documentation/translations/sp_SP/ SPARC + UltraSPARC (sparc/sparc64) M: "David S. Miller" +M: Andreas Larsson L: sparclinux@vger.kernel.org S: Maintained Q: http://patchwork.ozlabs.org/project/sparclinux/list/ @@ -20354,7 +20612,7 @@ F: drivers/pinctrl/spear/ SPI NOR SUBSYSTEM M: Tudor Ambarus M: Pratyush Yadav -R: Michael Walle +M: Michael Walle L: linux-mtd@lists.infradead.org S: Maintained W: http://www.linux-mtd.infradead.org/ @@ -20566,6 +20824,15 @@ M: Ion Badulescu S: Odd Fixes F: drivers/net/ethernet/adaptec/starfire* +STARFIVE CAMERA SUBSYSTEM DRIVER +M: Jack Zhu +M: Changhuang Liang +L: linux-media@vger.kernel.org +S: Maintained +F: Documentation/admin-guide/media/starfive_camss.rst +F: Documentation/devicetree/bindings/media/starfive,jh7110-camss.yaml +F: drivers/staging/media/starfive/camss + STARFIVE CRYPTO DRIVER M: Jia Jie Ho M: William Qiu @@ -21018,6 +21285,13 @@ L: linux-mmc@vger.kernel.org S: Maintained F: drivers/mmc/host/dw_mmc* +SYNOPSYS DESIGNWARE PCIE PMU DRIVER +M: Shuai Xue +M: Jing Zhang +S: Supported +F: Documentation/admin-guide/perf/dwc_pcie_pmu.rst +F: drivers/perf/dwc_pcie_pmu.c + SYNOPSYS HSDK RESET CONTROLLER DRIVER M: Eugeniy Paltsev S: Supported @@ -21259,6 +21533,12 @@ L: linux-media@vger.kernel.org S: Maintained F: drivers/media/rc/ttusbir.c +TECHWELL TW9900 VIDEO DECODER +M: Mehdi Djait +L: linux-media@vger.kernel.org +S: Maintained +F: drivers/media/i2c/tw9900.c + TECHWELL TW9910 VIDEO DECODER L: linux-media@vger.kernel.org S: Orphan @@ -21270,7 +21550,9 @@ M: Jens Wiklander R: Sumit Garg L: op-tee@lists.trustedfirmware.org S: Maintained -F: Documentation/staging/tee.rst +F: Documentation/driver-api/tee.rst +F: Documentation/tee/ +F: Documentation/userspace-api/tee.rst F: drivers/tee/ F: include/linux/tee_drv.h F: include/uapi/linux/tee.h @@ -21565,6 +21847,17 @@ S: Maintained F: Documentation/ABI/testing/sysfs-class-firmware-attributes F: drivers/platform/x86/think-lmi.? +THP7312 ISP DRIVER +M: Laurent Pinchart +M: Paul Elder +L: linux-media@vger.kernel.org +S: Maintained +T: git git://linuxtv.org/media_tree.git +F: Documentation/devicetree/bindings/media/i2c/thine,thp7312.yaml +F: Documentation/userspace-api/media/drivers/thp7312.rst +F: drivers/media/i2c/thp7312.c +F: include/uapi/linux/thp7312.h + THUNDERBOLT DMA TRAFFIC TEST DRIVER M: Isaac Hazan L: linux-usb@vger.kernel.org @@ -22041,7 +22334,7 @@ F: kernel/trace/trace_osnoise.c F: kernel/trace/trace_sched_wakeup.c TRADITIONAL CHINESE DOCUMENTATION -M: Hu Haowen +M: Hu Haowen <2023002089@link.tyut.edu.cn> S: Maintained W: https://github.com/srcres258/linux-doc T: git git://github.com/srcres258/linux-doc.git doc-zh-tw @@ -22224,7 +22517,7 @@ F: drivers/usb/common/ulpi.c F: include/linux/ulpi/ UNICODE SUBSYSTEM -M: Gabriel Krisman Bertazi +M: Gabriel Krisman Bertazi L: linux-fsdevel@vger.kernel.org S: Supported F: fs/unicode/ @@ -22266,7 +22559,8 @@ S: Maintained F: drivers/ufs/host/ufs-exynos* UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER MEDIATEK HOOKS -M: Stanley Chu +M: Peter Wang +R: Stanley Jhu L: linux-scsi@vger.kernel.org L: linux-mediatek@lists.infradead.org (moderated for non-subscribers) S: Maintained @@ -22597,11 +22891,6 @@ F: drivers/usb/gadget/function/*uvc* F: drivers/usb/gadget/legacy/webcam.c F: include/uapi/linux/usb/g_uvc.h -USB WIRELESS RNDIS DRIVER (rndis_wlan) -L: linux-wireless@vger.kernel.org -S: Orphan -F: drivers/net/wireless/legacy/rndis_wlan.c - USB XHCI DRIVER M: Mathias Nyman L: linux-usb@vger.kernel.org @@ -22609,12 +22898,6 @@ S: Supported F: drivers/usb/host/pci-quirks* F: drivers/usb/host/xhci* -USB ZD1201 DRIVER -L: linux-wireless@vger.kernel.org -S: Orphan -W: http://linux-lc100020.sourceforge.net -F: drivers/net/wireless/zydas/zd1201.* - USER DATAGRAM PROTOCOL (UDP) M: Willem de Bruijn S: Maintained @@ -22720,6 +23003,7 @@ S: Maintained F: Documentation/driver-api/media/camera-sensor.rst F: Documentation/driver-api/media/tx-rx.rst F: drivers/media/i2c/ar* +F: drivers/media/i2c/gc* F: drivers/media/i2c/hi* F: drivers/media/i2c/imx* F: drivers/media/i2c/mt* @@ -22753,6 +23037,7 @@ M: Alex Williamson L: kvm@vger.kernel.org S: Maintained T: git https://github.com/awilliam/linux-vfio.git +F: Documentation/ABI/testing/debugfs-vfio F: Documentation/ABI/testing/sysfs-devices-vfio-dev F: Documentation/driver-api/vfio.rst F: drivers/vfio/ @@ -22788,6 +23073,13 @@ L: kvm@vger.kernel.org S: Maintained F: drivers/vfio/pci/mlx5/ +VFIO VIRTIO PCI DRIVER +M: Yishai Hadas +L: kvm@vger.kernel.org +L: virtualization@lists.linux-foundation.org +S: Maintained +F: drivers/vfio/pci/virtio + VFIO PCI DEVICE SPECIFIC DRIVERS R: Jason Gunthorpe R: Yishai Hadas @@ -22936,7 +23228,6 @@ M: Amit Shah L: virtualization@lists.linux.dev S: Maintained F: drivers/char/virtio_console.c -F: include/linux/virtio_console.h F: include/uapi/linux/virtio_console.h VIRTIO CORE AND NET DRIVERS @@ -23112,6 +23403,12 @@ S: Maintained F: drivers/input/serio/userio.c F: include/uapi/linux/userio.h +VISHAY VEML6075 UVA AND UVB LIGHT SENSOR DRIVER +M: Javier Carrasco +S: Maintained +F: Documentation/devicetree/bindings/iio/light/vishay,veml6075.yaml +F: drivers/iio/light/veml6075.c + VISL VIRTUAL STATELESS DECODER DRIVER M: Daniel Almeida L: linux-media@vger.kernel.org @@ -23152,11 +23449,8 @@ F: include/linux/vmalloc.h F: mm/vmalloc.c VME SUBSYSTEM -M: Martyn Welch -M: Manohar Vanga -M: Greg Kroah-Hartman L: linux-kernel@vger.kernel.org -S: Odd fixes +S: Orphan T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git F: Documentation/driver-api/vme.rst F: drivers/staging/vme_user/ @@ -23362,6 +23656,14 @@ F: include/linux/watchdog.h F: include/trace/events/watchdog.h F: include/uapi/linux/watchdog.h +WAVE5 VPU CODEC DRIVER +M: Nas Chung +M: Jackson Lee +L: linux-media@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/media/cnm,wave521c.yaml +F: drivers/media/platform/chips-media/wave5/ + WHISKEYCOVE PMIC GPIO DRIVER M: Kuppuswamy Sathyanarayanan L: linux-gpio@vger.kernel.org @@ -23415,11 +23717,6 @@ M: Miloslav Trmac S: Maintained F: drivers/input/misc/wistron_btns.c -WL3501 WIRELESS PCMCIA CARD DRIVER -L: linux-wireless@vger.kernel.org -S: Orphan -F: drivers/net/wireless/legacy/wl3501* - WMI BINARY MOF DRIVER M: Armin Wolf R: Thomas Weißschuh @@ -23589,15 +23886,6 @@ F: drivers/platform/olpc/ F: drivers/platform/x86/ F: include/linux/platform_data/x86/ -X86 PLATFORM DRIVERS - ARCH -R: Darren Hart -R: Andy Shevchenko -L: platform-driver-x86@vger.kernel.org -L: x86@kernel.org -S: Maintained -T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/core -F: arch/x86/platform - X86 PLATFORM UV HPE SUPERDOME FLEX M: Steve Wahl R: Justin Ernst @@ -23809,10 +24097,10 @@ S: Supported W: http://xfs.org/ C: irc://irc.oftc.net/xfs T: git git://git.kernel.org/pub/scm/fs/xfs/xfs-linux.git -P: Documentation/filesystems/xfs-maintainer-entry-profile.rst +P: Documentation/filesystems/xfs/xfs-maintainer-entry-profile.rst F: Documentation/ABI/testing/sysfs-fs-xfs F: Documentation/admin-guide/xfs.rst -F: Documentation/filesystems/xfs-* +F: Documentation/filesystems/xfs/* F: fs/xfs/ F: include/uapi/linux/dqblk_xfs.h F: include/uapi/linux/fsmap.h @@ -24105,11 +24393,13 @@ N: zstd K: zstd ZSWAP COMPRESSED SWAP CACHING -M: Seth Jennings -M: Dan Streetman -M: Vitaly Wool +M: Johannes Weiner +M: Yosry Ahmed +M: Nhat Pham L: linux-mm@kvack.org S: Maintained +F: Documentation/admin-guide/mm/zswap.rst +F: include/linux/zswap.h F: mm/zswap.c THE REST diff --git a/Makefile b/Makefile index c6f549f6a4aeb9..6c0a4d294444cb 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 6 -PATCHLEVEL = 7 +PATCHLEVEL = 8 SUBLEVEL = 0 -EXTRAVERSION = +EXTRAVERSION = -rc2 NAME = Hurr durr I'ma ninja sloth # *DOCUMENTATION* @@ -155,6 +155,15 @@ endif export KBUILD_EXTMOD +# backward compatibility +KBUILD_EXTRA_WARN ?= $(KBUILD_ENABLE_EXTRA_GCC_CHECKS) + +ifeq ("$(origin W)", "command line") + KBUILD_EXTRA_WARN := $(W) +endif + +export KBUILD_EXTRA_WARN + # Kbuild will save output files in the current working directory. # This does not need to match to the root of the kernel source tree. # @@ -181,14 +190,11 @@ ifeq ("$(origin O)", "command line") endif ifneq ($(KBUILD_OUTPUT),) -# Make's built-in functions such as $(abspath ...), $(realpath ...) cannot -# expand a shell special character '~'. We use a somewhat tedious way here. -abs_objtree := $(shell mkdir -p $(KBUILD_OUTPUT) && cd $(KBUILD_OUTPUT) && pwd) -$(if $(abs_objtree),, \ - $(error failed to create output directory "$(KBUILD_OUTPUT)")) - +# $(realpath ...) gets empty if the path does not exist. Run 'mkdir -p' first. +$(shell mkdir -p "$(KBUILD_OUTPUT)") # $(realpath ...) resolves symlinks -abs_objtree := $(realpath $(abs_objtree)) +abs_objtree := $(realpath $(KBUILD_OUTPUT)) +$(if $(abs_objtree),,$(error failed to create output directory "$(KBUILD_OUTPUT)")) endif # ifneq ($(KBUILD_OUTPUT),) ifneq ($(words $(subst :, ,$(abs_srctree))), 1) @@ -609,8 +615,6 @@ export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL KBUILD_RUSTFLAGS_KERNEL export RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o \ -name CVS -o -name .pc -o -name .hg -o -name .git \) \ -prune -o -export RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn \ - --exclude CVS --exclude .pc --exclude .hg --exclude .git # =========================================================================== # Rules shared between *config targets and build targets @@ -982,6 +986,10 @@ NOSTDINC_FLAGS += -nostdinc # perform bounds checking. KBUILD_CFLAGS += $(call cc-option, -fstrict-flex-arrays=3) +#Currently, disable -Wstringop-overflow for GCC 11, globally. +KBUILD_CFLAGS-$(CONFIG_CC_NO_STRINGOP_OVERFLOW) += $(call cc-option, -Wno-stringop-overflow) +KBUILD_CFLAGS-$(CONFIG_CC_STRINGOP_OVERFLOW) += $(call cc-option, -Wstringop-overflow) + # disable invalid "can't wrap" optimizations for signed / pointers KBUILD_CFLAGS += -fno-strict-overflow @@ -1576,7 +1584,8 @@ help: echo ' (default: $(INSTALL_HDR_PATH))'; \ echo '' @echo 'Static analysers:' - @echo ' checkstack - Generate a list of stack hogs' + @echo ' checkstack - Generate a list of stack hogs and consider all functions' + @echo ' with a stack size larger than MINSTACKSIZE (default: 100)' @echo ' versioncheck - Sanity check on version.h usage' @echo ' includecheck - Check for duplicate included header files' @echo ' export_report - List the usages of all exported symbols' @@ -1661,6 +1670,7 @@ help: @echo ' 1: warnings which may be relevant and do not occur too often' @echo ' 2: warnings which occur quite often but may still be relevant' @echo ' 3: more obscure warnings, can most likely be ignored' + @echo ' c: extra checks in the configuration stage (Kconfig)' @echo ' e: warnings are being treated as errors' @echo ' Multiple levels can be combined with W=12 or W=123' @$(if $(dtstree), \ @@ -2016,9 +2026,10 @@ CHECKSTACK_ARCH := $(SUBARCH) else CHECKSTACK_ARCH := $(ARCH) endif +MINSTACKSIZE ?= 100 checkstack: $(OBJDUMP) -d vmlinux $$(find . -name '*.ko') | \ - $(PERL) $(srctree)/scripts/checkstack.pl $(CHECKSTACK_ARCH) + $(PERL) $(srctree)/scripts/checkstack.pl $(CHECKSTACK_ARCH) $(MINSTACKSIZE) kernelrelease: @$(filechk_kernel.release) diff --git a/arch/Kconfig b/arch/Kconfig index f4b210ab061291..c91917b508736d 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -301,17 +301,13 @@ config ARCH_HAS_DMA_CLEAR_UNCACHED config ARCH_HAS_CPU_FINALIZE_INIT bool -# Select if arch init_task must go in the __init_task_data section -config ARCH_TASK_STRUCT_ON_STACK - bool - -# Select if arch has its private alloc_task_struct() function -config ARCH_TASK_STRUCT_ALLOCATOR +# The architecture has a per-task state that includes the mm's PASID +config ARCH_HAS_CPU_PASID bool + select IOMMU_MM_DATA config HAVE_ARCH_THREAD_STRUCT_WHITELIST bool - depends on !ARCH_TASK_STRUCT_ALLOCATOR help An architecture should select this to provide hardened usercopy knowledge about what region of the thread_struct should be @@ -320,10 +316,6 @@ config HAVE_ARCH_THREAD_STRUCT_WHITELIST should be implemented. Without this, the entire thread_struct field in task_struct will be left whitelisted. -# Select if arch has its private alloc_thread_stack() function -config ARCH_THREAD_STACK_ALLOCATOR - bool - # Select if arch wants to size task_struct dynamically via arch_task_struct_size: config ARCH_WANTS_DYNAMIC_TASK_STRUCT bool @@ -1470,6 +1462,14 @@ config DYNAMIC_SIGFRAME config HAVE_ARCH_NODE_DEV_GROUP bool +config ARCH_HAS_HW_PTE_YOUNG + bool + help + Architectures that select this option are capable of setting the + accessed bit in PTE entries when using them as part of linear address + translations. Architectures that require runtime check should select + this option and override arch_has_hw_pte_young(). + config ARCH_HAS_NONLEAF_PMD_YOUNG bool help diff --git a/arch/alpha/include/asm/io.h b/arch/alpha/include/asm/io.h index 7aeaf7c30a6f64..4f47a5003fe88a 100644 --- a/arch/alpha/include/asm/io.h +++ b/arch/alpha/include/asm/io.h @@ -308,7 +308,6 @@ static inline void __iomem *ioremap(unsigned long port, unsigned long size) } #define ioremap_wc ioremap -#define ioremap_uc ioremap static inline void iounmap(volatile void __iomem *addr) { @@ -651,12 +650,6 @@ extern void outsl (unsigned long port, const void *src, unsigned long count); #endif #define RTC_ALWAYS_BCD 0 -/* - * Convert a physical pointer to a virtual kernel pointer for /dev/mem - * access - */ -#define xlate_dev_mem_ptr(p) __va(p) - /* * These get provided from since alpha does not * select GENERIC_IOMAP. diff --git a/arch/alpha/include/asm/mmu_context.h b/arch/alpha/include/asm/mmu_context.h index 4eea7c61699253..29a3e3a1f02bec 100644 --- a/arch/alpha/include/asm/mmu_context.h +++ b/arch/alpha/include/asm/mmu_context.h @@ -183,6 +183,8 @@ ev4_switch_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm, } extern void __load_new_mm_context(struct mm_struct *); +asmlinkage void do_page_fault(unsigned long address, unsigned long mmcsr, + long cause, struct pt_regs *regs); #ifdef CONFIG_SMP #define check_mmu_context() \ diff --git a/arch/alpha/kernel/asm-offsets.c b/arch/alpha/kernel/asm-offsets.c index b121294bee2663..bf1eedd27cf751 100644 --- a/arch/alpha/kernel/asm-offsets.c +++ b/arch/alpha/kernel/asm-offsets.c @@ -12,7 +12,7 @@ #include #include -void foo(void) +static void __used foo(void) { DEFINE(TI_TASK, offsetof(struct thread_info, task)); DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); diff --git a/arch/alpha/kernel/rtc.c b/arch/alpha/kernel/rtc.c index fb3025396ac964..cfdf90bc8b3f86 100644 --- a/arch/alpha/kernel/rtc.c +++ b/arch/alpha/kernel/rtc.c @@ -80,7 +80,7 @@ init_rtc_epoch(void) static int alpha_rtc_read_time(struct device *dev, struct rtc_time *tm) { - int ret = mc146818_get_time(tm); + int ret = mc146818_get_time(tm, 10); if (ret < 0) { dev_err_ratelimited(dev, "unable to read current time\n"); diff --git a/arch/alpha/kernel/srmcons.c b/arch/alpha/kernel/srmcons.c index d6139dbae4ac9f..feaf89f6936bcd 100644 --- a/arch/alpha/kernel/srmcons.c +++ b/arch/alpha/kernel/srmcons.c @@ -53,7 +53,7 @@ srmcons_do_receive_chars(struct tty_port *port) do { result.as_long = callback_getc(0); if (result.bits.status < 2) { - tty_insert_flip_char(port, (char)result.bits.c, 0); + tty_insert_flip_char(port, (u8)result.bits.c, 0); count++; } } while((result.bits.status & 1) && (++loops < 10)); @@ -88,30 +88,27 @@ srmcons_receive_chars(struct timer_list *t) } /* called with callback_lock held */ -static int -srmcons_do_write(struct tty_port *port, const char *buf, int count) +static void +srmcons_do_write(struct tty_port *port, const u8 *buf, size_t count) { - static char str_cr[1] = "\r"; - long c, remaining = count; + size_t c; srmcons_result result; - char *cur; - int need_cr; - for (cur = (char *)buf; remaining > 0; ) { - need_cr = 0; + while (count > 0) { + bool need_cr = false; /* * Break it up into reasonable size chunks to allow a chance * for input to get in */ - for (c = 0; c < min_t(long, 128L, remaining) && !need_cr; c++) - if (cur[c] == '\n') - need_cr = 1; + for (c = 0; c < min_t(size_t, 128U, count) && !need_cr; c++) + if (buf[c] == '\n') + need_cr = true; while (c > 0) { - result.as_long = callback_puts(0, cur, c); + result.as_long = callback_puts(0, buf, c); c -= result.bits.c; - remaining -= result.bits.c; - cur += result.bits.c; + count -= result.bits.c; + buf += result.bits.c; /* * Check for pending input iff a tty port was provided @@ -121,12 +118,11 @@ srmcons_do_write(struct tty_port *port, const char *buf, int count) } while (need_cr) { - result.as_long = callback_puts(0, str_cr, 1); + result.as_long = callback_puts(0, "\r", 1); if (result.bits.c > 0) - need_cr = 0; + need_cr = false; } } - return count; } static ssize_t @@ -135,7 +131,7 @@ srmcons_write(struct tty_struct *tty, const u8 *buf, size_t count) unsigned long flags; spin_lock_irqsave(&srmcons_callback_lock, flags); - srmcons_do_write(tty->port, (const char *) buf, count); + srmcons_do_write(tty->port, buf, count); spin_unlock_irqrestore(&srmcons_callback_lock, flags); return count; diff --git a/arch/alpha/kernel/syscalls/syscall.tbl b/arch/alpha/kernel/syscalls/syscall.tbl index 18c842ca6c32c1..8ff110826ce21d 100644 --- a/arch/alpha/kernel/syscalls/syscall.tbl +++ b/arch/alpha/kernel/syscalls/syscall.tbl @@ -496,3 +496,8 @@ 564 common futex_wake sys_futex_wake 565 common futex_wait sys_futex_wait 566 common futex_requeue sys_futex_requeue +567 common statmount sys_statmount +568 common listmount sys_listmount +569 common lsm_get_self_attr sys_lsm_get_self_attr +570 common lsm_set_self_attr sys_lsm_set_self_attr +571 common lsm_list_modules sys_lsm_list_modules diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c index d9a67b370e0476..7fc72aeb7398c7 100644 --- a/arch/alpha/kernel/traps.c +++ b/arch/alpha/kernel/traps.c @@ -9,6 +9,7 @@ * This file initializes the trap entry points */ +#include #include #include #include diff --git a/arch/alpha/lib/Makefile b/arch/alpha/lib/Makefile index 1cc74f7b50efbe..6a779b9018fd15 100644 --- a/arch/alpha/lib/Makefile +++ b/arch/alpha/lib/Makefile @@ -4,7 +4,6 @@ # asflags-y := $(KBUILD_CFLAGS) -ccflags-y := -Werror # Many of these routines have implementations tuned for ev6. # Choose them iff we're targeting ev6 specifically. diff --git a/arch/alpha/mm/Makefile b/arch/alpha/mm/Makefile index bd770302eb8243..101dbd06b4ceb6 100644 --- a/arch/alpha/mm/Makefile +++ b/arch/alpha/mm/Makefile @@ -3,6 +3,4 @@ # Makefile for the linux alpha-specific parts of the memory manager. # -ccflags-y := -Werror - obj-y := init.o fault.o diff --git a/arch/arc/include/asm/cacheflush.h b/arch/arc/include/asm/cacheflush.h index 563af3e75f01f2..329c94cd45d8f6 100644 --- a/arch/arc/include/asm/cacheflush.h +++ b/arch/arc/include/asm/cacheflush.h @@ -40,6 +40,7 @@ void dma_cache_wback(phys_addr_t start, unsigned long sz); /* TBD: optimize this */ #define flush_cache_vmap(start, end) flush_cache_all() +#define flush_cache_vmap_early(start, end) do { } while (0) #define flush_cache_vunmap(start, end) flush_cache_all() #define flush_cache_dup_mm(mm) /* called on fork (VIVT only) */ diff --git a/arch/arc/include/asm/page.h b/arch/arc/include/asm/page.h index 02b53ad811fb60..def0dfb95b4369 100644 --- a/arch/arc/include/asm/page.h +++ b/arch/arc/include/asm/page.h @@ -84,15 +84,6 @@ typedef struct { typedef struct page *pgtable_t; -/* - * Use virt_to_pfn with caution: - * If used in pte or paddr related macros, it could cause truncation - * in PAE40 builds - * As a rule of thumb, only use it in helpers starting with virt_ - * You have been warned ! - */ -#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT) - /* * When HIGHMEM is enabled we have holes in the memory map so we need * pfn_valid() that takes into account the actual extents of the physical @@ -122,6 +113,18 @@ extern int pfn_valid(unsigned long pfn); #define __pa(vaddr) ((unsigned long)(vaddr)) #define __va(paddr) ((void *)((unsigned long)(paddr))) +/* + * Use virt_to_pfn with caution: + * If used in pte or paddr related macros, it could cause truncation + * in PAE40 builds + * As a rule of thumb, only use it in helpers starting with virt_ + * You have been warned ! + */ +static inline unsigned long virt_to_pfn(const void *kaddr) +{ + return __pa(kaddr) >> PAGE_SHIFT; +} + #define virt_to_page(kaddr) pfn_to_page(virt_to_pfn(kaddr)) #define virt_addr_valid(kaddr) pfn_valid(virt_to_pfn(kaddr)) diff --git a/arch/arc/include/asm/pgtable-levels.h b/arch/arc/include/asm/pgtable-levels.h index fc417c75c24db3..86e14822646301 100644 --- a/arch/arc/include/asm/pgtable-levels.h +++ b/arch/arc/include/asm/pgtable-levels.h @@ -159,7 +159,7 @@ #define pmd_clear(xp) do { pmd_val(*(xp)) = 0; } while (0) #define pmd_page_vaddr(pmd) (pmd_val(pmd) & PAGE_MASK) #define pmd_pfn(pmd) ((pmd_val(pmd) & PAGE_MASK) >> PAGE_SHIFT) -#define pmd_page(pmd) virt_to_page(pmd_page_vaddr(pmd)) +#define pmd_page(pmd) virt_to_page((void *)pmd_page_vaddr(pmd)) #define set_pmd(pmdp, pmd) (*(pmdp) = pmd) #define pmd_pgtable(pmd) ((pgtable_t) pmd_page(pmd)) diff --git a/arch/arc/mm/dma.c b/arch/arc/mm/dma.c index 2a7fbbb83b7056..197707bc765889 100644 --- a/arch/arc/mm/dma.c +++ b/arch/arc/mm/dma.c @@ -91,7 +91,7 @@ void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size, * Plug in direct dma map ops. */ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, - const struct iommu_ops *iommu, bool coherent) + bool coherent) { /* * IOC hardware snoops all DMA traffic keeping the caches consistent diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index f8567e95f98bef..0af6709570d147 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -35,6 +35,7 @@ config ARM select ARCH_OPTIONAL_KERNEL_RWX_DEFAULT if CPU_V7 select ARCH_SUPPORTS_ATOMIC_RMW select ARCH_SUPPORTS_HUGETLBFS if ARM_LPAE + select ARCH_SUPPORTS_PER_VMA_LOCK select ARCH_USE_BUILTIN_BSWAP select ARCH_USE_CMPXCHG_LOCKREF select ARCH_USE_MEMTEST @@ -340,83 +341,7 @@ config ARCH_MULTIPLATFORM Selecting N here allows using those options, including DEBUG_UNCOMPRESS, XIP_KERNEL and ZBOOT_ROM. If unsure, say Y. -menu "Platform selection" - depends on MMU - -comment "CPU Core family selection" - -config ARCH_MULTI_V4 - bool "ARMv4 based platforms (FA526, StrongARM)" - depends on !ARCH_MULTI_V6_V7 - # https://github.com/llvm/llvm-project/issues/50764 - depends on !LD_IS_LLD || LLD_VERSION >= 160000 - select ARCH_MULTI_V4_V5 - select CPU_FA526 if !(CPU_SA110 || CPU_SA1100) - -config ARCH_MULTI_V4T - bool "ARMv4T based platforms (ARM720T, ARM920T, ...)" - depends on !ARCH_MULTI_V6_V7 - # https://github.com/llvm/llvm-project/issues/50764 - depends on !LD_IS_LLD || LLD_VERSION >= 160000 - select ARCH_MULTI_V4_V5 - select CPU_ARM920T if !(CPU_ARM7TDMI || CPU_ARM720T || \ - CPU_ARM740T || CPU_ARM9TDMI || CPU_ARM922T || \ - CPU_ARM925T || CPU_ARM940T) - -config ARCH_MULTI_V5 - bool "ARMv5 based platforms (ARM926T, XSCALE, PJ1, ...)" - depends on !ARCH_MULTI_V6_V7 - select ARCH_MULTI_V4_V5 - select CPU_ARM926T if !(CPU_ARM946E || CPU_ARM1020 || \ - CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || \ - CPU_XSCALE || CPU_XSC3 || CPU_MOHAWK || CPU_FEROCEON) - -config ARCH_MULTI_V4_V5 - bool - -config ARCH_MULTI_V6 - bool "ARMv6 based platforms (ARM11)" - select ARCH_MULTI_V6_V7 - select CPU_V6K - -config ARCH_MULTI_V7 - bool "ARMv7 based platforms (Cortex-A, PJ4, Scorpion, Krait)" - default y - select ARCH_MULTI_V6_V7 - select CPU_V7 - select HAVE_SMP - -config ARCH_MULTI_V6_V7 - bool - select MIGHT_HAVE_CACHE_L2X0 - -config ARCH_MULTI_CPU_AUTO - def_bool !(ARCH_MULTI_V4 || ARCH_MULTI_V4T || ARCH_MULTI_V6_V7) - select ARCH_MULTI_V5 - -endmenu - -config ARCH_VIRT - bool "Dummy Virtual Machine" - depends on ARCH_MULTI_V7 - select ARM_AMBA - select ARM_GIC - select ARM_GIC_V2M if PCI - select ARM_GIC_V3 - select ARM_GIC_V3_ITS if PCI - select ARM_PSCI - select HAVE_ARM_ARCH_TIMER - -config ARCH_AIROHA - bool "Airoha SoC Support" - depends on ARCH_MULTI_V7 - select ARM_AMBA - select ARM_GIC - select ARM_GIC_V3 - select ARM_PSCI - select HAVE_ARM_ARCH_TIMER - help - Support for Airoha EN7523 SoCs +source "arch/arm/Kconfig.platforms" # # This is sorted alphabetically by mach-* pathname. However, plat-* @@ -429,8 +354,6 @@ source "arch/arm/mach-alpine/Kconfig" source "arch/arm/mach-artpec/Kconfig" -source "arch/arm/mach-asm9260/Kconfig" - source "arch/arm/mach-aspeed/Kconfig" source "arch/arm/mach-at91/Kconfig" @@ -479,8 +402,6 @@ source "arch/arm/mach-milbeaut/Kconfig" source "arch/arm/mach-mmp/Kconfig" -source "arch/arm/mach-moxart/Kconfig" - source "arch/arm/mach-mstar/Kconfig" source "arch/arm/mach-mv78xx0/Kconfig" @@ -493,8 +414,6 @@ source "arch/arm/mach-nomadik/Kconfig" source "arch/arm/mach-npcm/Kconfig" -source "arch/arm/mach-nspire/Kconfig" - source "arch/arm/mach-omap1/Kconfig" source "arch/arm/mach-omap2/Kconfig" @@ -505,8 +424,6 @@ source "arch/arm/mach-pxa/Kconfig" source "arch/arm/mach-qcom/Kconfig" -source "arch/arm/mach-rda/Kconfig" - source "arch/arm/mach-realtek/Kconfig" source "arch/arm/mach-rpc/Kconfig" @@ -529,14 +446,10 @@ source "arch/arm/mach-sti/Kconfig" source "arch/arm/mach-stm32/Kconfig" -source "arch/arm/mach-sunplus/Kconfig" - source "arch/arm/mach-sunxi/Kconfig" source "arch/arm/mach-tegra/Kconfig" -source "arch/arm/mach-uniphier/Kconfig" - source "arch/arm/mach-ux500/Kconfig" source "arch/arm/mach-versatile/Kconfig" @@ -1362,7 +1275,7 @@ config ARCH_FORCE_MAX_ORDER default "10" help The kernel page allocator limits the size of maximal physically - contiguous allocations. The limit is called MAX_ORDER and it + contiguous allocations. The limit is called MAX_PAGE_ORDER and it defines the maximal power of two of number of pages that can be allocated as a single contiguous block. This option allows overriding the default setting when ability to allocate very diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index fc2b41d414470e..5fbbac1b708b0a 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -1809,15 +1809,8 @@ config DEBUG_UNCOMPRESS (!DEBUG_TEGRA_UART || !ZBOOT_ROM) && \ !DEBUG_BRCMSTB_UART && !DEBUG_SEMIHOSTING help - This option influences the normal decompressor output for - multiplatform kernels. Normally, multiplatform kernels disable - decompressor output because it is not possible to know where to - send the decompressor output. - - When this option is set, the selected DEBUG_LL output method - will be re-used for normal decompressor output on multiplatform - kernels. - + Say Y here to enable debug output in the decompressor code, using + the selected DEBUG_LL output method. config UNCOMPRESS_INCLUDE string diff --git a/arch/arm/Kconfig.platforms b/arch/arm/Kconfig.platforms new file mode 100644 index 00000000000000..845ab08e20a4b5 --- /dev/null +++ b/arch/arm/Kconfig.platforms @@ -0,0 +1,183 @@ +# SPDX-License-Identifier: GPL-2.0-only + +menu "Platform selection" + depends on MMU + +comment "CPU Core family selection" + +config ARCH_MULTI_V4 + bool "ARMv4 based platforms (FA526, StrongARM)" + depends on !ARCH_MULTI_V6_V7 + # https://github.com/llvm/llvm-project/issues/50764 + depends on !LD_IS_LLD || LLD_VERSION >= 160000 + select ARCH_MULTI_V4_V5 + select CPU_FA526 if !(CPU_SA110 || CPU_SA1100) + +config ARCH_MULTI_V4T + bool "ARMv4T based platforms (ARM720T, ARM920T, ...)" + depends on !ARCH_MULTI_V6_V7 + # https://github.com/llvm/llvm-project/issues/50764 + depends on !LD_IS_LLD || LLD_VERSION >= 160000 + select ARCH_MULTI_V4_V5 + select CPU_ARM920T if !(CPU_ARM7TDMI || CPU_ARM720T || \ + CPU_ARM740T || CPU_ARM9TDMI || CPU_ARM922T || \ + CPU_ARM925T || CPU_ARM940T) + +config ARCH_MULTI_V5 + bool "ARMv5 based platforms (ARM926T, XSCALE, PJ1, ...)" + depends on !ARCH_MULTI_V6_V7 + select ARCH_MULTI_V4_V5 + select CPU_ARM926T if !(CPU_ARM946E || CPU_ARM1020 || \ + CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || \ + CPU_XSCALE || CPU_XSC3 || CPU_MOHAWK || CPU_FEROCEON) + +config ARCH_MULTI_V4_V5 + bool + +config ARCH_MULTI_V6 + bool "ARMv6 based platforms (ARM11)" + select ARCH_MULTI_V6_V7 + select CPU_V6K + +config ARCH_MULTI_V7 + bool "ARMv7 based platforms (Cortex-A, PJ4, Scorpion, Krait)" + default y + select ARCH_MULTI_V6_V7 + select CPU_V7 + select HAVE_SMP + +config ARCH_MULTI_V6_V7 + bool + select MIGHT_HAVE_CACHE_L2X0 + +config ARCH_MULTI_CPU_AUTO + def_bool !(ARCH_MULTI_V4 || ARCH_MULTI_V4T || ARCH_MULTI_V6_V7) + select ARCH_MULTI_V5 + +endmenu + +config ARCH_VIRT + bool "Dummy Virtual Machine" + depends on ARCH_MULTI_V7 + select ARM_AMBA + select ARM_GIC + select ARM_GIC_V2M if PCI + select ARM_GIC_V3 + select ARM_GIC_V3_ITS if PCI + select ARM_PSCI + select HAVE_ARM_ARCH_TIMER + +config ARCH_AIROHA + bool "Airoha SoC Support" + depends on ARCH_MULTI_V7 + select ARM_AMBA + select ARM_GIC + select ARM_GIC_V3 + select ARM_PSCI + select HAVE_ARM_ARCH_TIMER + help + Support for Airoha EN7523 SoCs + +config MACH_ASM9260 + bool "Alphascale ASM9260" + depends on ARCH_MULTI_V5 + depends on CPU_LITTLE_ENDIAN + select CPU_ARM926T + select ASM9260_TIMER + help + Support for Alphascale ASM9260 based platform. + +menuconfig ARCH_MOXART + bool "MOXA ART SoC" + depends on ARCH_MULTI_V4 + depends on CPU_LITTLE_ENDIAN + select CPU_FA526 + select ARM_DMA_MEM_BUFFERABLE + select FARADAY_FTINTC010 + select FTTMR010_TIMER + select GPIOLIB + select PHYLIB if NETDEVICES + help + Say Y here if you want to run your kernel on hardware with a + MOXA ART SoC. + The MOXA ART SoC is based on a Faraday FA526 ARMv4 32-bit + 192 MHz CPU with MMU and 16KB/8KB D/I-cache (UC-7112-LX). + Used on models UC-7101, UC-7112/UC-7110, IA240/IA241, IA3341. + +if ARCH_MOXART + +config MACH_UC7112LX + bool "MOXA UC-7112-LX" + depends on ARCH_MOXART + help + Say Y here if you intend to run this kernel on a MOXA + UC-7112-LX embedded computer. + +endif + +config ARCH_NSPIRE + bool "TI-NSPIRE based" + depends on ARCH_MULTI_V4T + depends on CPU_LITTLE_ENDIAN + select CPU_ARM926T + select GENERIC_IRQ_CHIP + select ARM_AMBA + select ARM_VIC + select ARM_TIMER_SP804 + select NSPIRE_TIMER + select POWER_RESET + select POWER_RESET_SYSCON + help + This enables support for systems using the TI-NSPIRE CPU + +config ARCH_RDA + bool "RDA Micro SoCs" + depends on ARCH_MULTI_V7 + select RDA_INTC + select RDA_TIMER + help + This enables support for the RDA Micro 8810PL SoC family. + +menuconfig ARCH_SUNPLUS + bool "Sunplus SoCs" + depends on ARCH_MULTI_V7 + help + Support for Sunplus SoC family: SP7021 and succeeding SoC-based systems, + such as the Banana Pi BPI-F2S development board (and derivatives). + () + () + +if ARCH_SUNPLUS + +config SOC_SP7021 + bool "Sunplus SP7021 SoC support" + default ARCH_SUNPLUS + select HAVE_ARM_ARCH_TIMER + select ARM_GIC + select ARM_PSCI + select PINCTRL + select PINCTRL_SPPCTL + select SERIAL_SUNPLUS if TTY + select SERIAL_SUNPLUS_CONSOLE if TTY + help + Support for Sunplus SP7021 SoC. It is based on ARM 4-core + Cortex-A7 with various peripherals (e.g.: I2C, SPI, SDIO, + Ethernet, etc.), FPGA interface, chip-to-chip bus. + It is designed for industrial control. + +endif + +config ARCH_UNIPHIER + bool "Socionext UniPhier SoCs" + depends on ARCH_MULTI_V7 + select ARCH_HAS_RESET_CONTROLLER + select ARM_AMBA + select ARM_GLOBAL_TIMER + select ARM_GIC + select HAVE_ARM_SCU + select HAVE_ARM_TWD if SMP + select PINCTRL + select RESET_CONTROLLER + help + Support for UniPhier SoC family developed by Socionext Inc. + (formerly, System LSI Business Division of Panasonic Corporation) diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 5ba42f69f8ce0c..473280d5adce34 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -167,7 +167,6 @@ textofs-$(CONFIG_ARCH_AXXIA) := 0x00308000 # Machine directory name. This list is sorted alphanumerically # by CONFIG_* macro name. machine-$(CONFIG_ARCH_ACTIONS) += actions -machine-$(CONFIG_ARCH_AIROHA) += airoha machine-$(CONFIG_ARCH_ALPINE) += alpine machine-$(CONFIG_ARCH_ARTPEC) += artpec machine-$(CONFIG_ARCH_ASPEED) += aspeed @@ -192,7 +191,6 @@ machine-$(CONFIG_ARCH_LPC18XX) += lpc18xx machine-$(CONFIG_ARCH_LPC32XX) += lpc32xx machine-$(CONFIG_ARCH_MESON) += meson machine-$(CONFIG_ARCH_MMP) += mmp -machine-$(CONFIG_ARCH_MOXART) += moxart machine-$(CONFIG_ARCH_MV78XX0) += mv78xx0 machine-$(CONFIG_ARCH_MVEBU) += mvebu machine-$(CONFIG_ARCH_MXC) += imx @@ -202,7 +200,6 @@ machine-$(CONFIG_ARCH_MXS) += mxs machine-$(CONFIG_ARCH_MSTARV7) += mstar machine-$(CONFIG_ARCH_NOMADIK) += nomadik machine-$(CONFIG_ARCH_NPCM) += npcm -machine-$(CONFIG_ARCH_NSPIRE) += nspire machine-$(CONFIG_ARCH_OMAP1) += omap1 machine-$(CONFIG_ARCH_OMAP2PLUS) += omap2 machine-$(CONFIG_ARCH_ORION5X) += orion5x @@ -218,7 +215,6 @@ machine-$(CONFIG_ARCH_RENESAS) += shmobile machine-$(CONFIG_ARCH_INTEL_SOCFPGA) += socfpga machine-$(CONFIG_ARCH_STI) += sti machine-$(CONFIG_ARCH_STM32) += stm32 -machine-$(CONFIG_ARCH_SUNPLUS) += sunplus machine-$(CONFIG_ARCH_SUNXI) += sunxi machine-$(CONFIG_ARCH_TEGRA) += tegra machine-$(CONFIG_ARCH_U8500) += ux500 diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts index e899de681f4752..5be0e8fd2633c2 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-bletchley.dts @@ -45,8 +45,8 @@ num-chipselects = <1>; cs-gpios = <&gpio0 ASPEED_GPIO(Z, 0) GPIO_ACTIVE_LOW>; - tpmdev@0 { - compatible = "tcg,tpm_tis-spi"; + tpm@0 { + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; spi-max-frequency = <33000000>; reg = <0>; }; diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-wedge400.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-wedge400.dts index a677c827e758fe..5a8169bbda8792 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-wedge400.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-facebook-wedge400.dts @@ -80,8 +80,8 @@ gpio-miso = <&gpio ASPEED_GPIO(R, 5) GPIO_ACTIVE_HIGH>; num-chipselects = <1>; - tpmdev@0 { - compatible = "tcg,tpm_tis-spi"; + tpm@0 { + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; spi-max-frequency = <33000000>; reg = <0>; }; diff --git a/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-tacoma.dts b/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-tacoma.dts index 3f6010ef2b86f2..213023bc5aec41 100644 --- a/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-tacoma.dts +++ b/arch/arm/boot/dts/aspeed/aspeed-bmc-opp-tacoma.dts @@ -456,7 +456,7 @@ status = "okay"; tpm: tpm@2e { - compatible = "tcg,tpm-tis-i2c"; + compatible = "nuvoton,npct75x", "tcg,tpm-tis-i2c"; reg = <0x2e>; }; }; diff --git a/arch/arm/boot/dts/aspeed/ast2600-facebook-netbmc-common.dtsi b/arch/arm/boot/dts/aspeed/ast2600-facebook-netbmc-common.dtsi index 31590d3186a2e0..00e5887c926f18 100644 --- a/arch/arm/boot/dts/aspeed/ast2600-facebook-netbmc-common.dtsi +++ b/arch/arm/boot/dts/aspeed/ast2600-facebook-netbmc-common.dtsi @@ -35,8 +35,8 @@ gpio-mosi = <&gpio0 ASPEED_GPIO(X, 4) GPIO_ACTIVE_HIGH>; gpio-miso = <&gpio0 ASPEED_GPIO(X, 5) GPIO_ACTIVE_HIGH>; - tpmdev@0 { - compatible = "tcg,tpm_tis-spi"; + tpm@0 { + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; spi-max-frequency = <33000000>; reg = <0>; }; diff --git a/arch/arm/boot/dts/broadcom/bcm2711-rpi.dtsi b/arch/arm/boot/dts/broadcom/bcm2711-rpi.dtsi index 98817a6675b9dd..d233a191c13936 100644 --- a/arch/arm/boot/dts/broadcom/bcm2711-rpi.dtsi +++ b/arch/arm/boot/dts/broadcom/bcm2711-rpi.dtsi @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "bcm2835-rpi.dtsi" +#include #include / { @@ -76,3 +77,7 @@ &vchiq { interrupts = ; }; + +&xhci { + power-domains = <&power RPI_POWER_DOMAIN_USB>; +}; diff --git a/arch/arm/boot/dts/broadcom/bcm2711.dtsi b/arch/arm/boot/dts/broadcom/bcm2711.dtsi index 4a379a14966d8d..22c7f1561344ed 100644 --- a/arch/arm/boot/dts/broadcom/bcm2711.dtsi +++ b/arch/arm/boot/dts/broadcom/bcm2711.dtsi @@ -604,6 +604,20 @@ }; }; + xhci: usb@7e9c0000 { + compatible = "brcm,bcm2711-xhci", "brcm,xhci-brcm-v2"; + reg = <0x0 0x7e9c0000 0x100000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = ; + /* DWC2 and this IP block share the same USB PHY, + * enabling both at the same time results in lockups. + * So keep this node disabled and let the bootloader + * decide which interface should be enabled. + */ + status = "disabled"; + }; + v3d: gpu@7ec00000 { compatible = "brcm,2711-v3d"; reg = <0x0 0x7ec00000 0x4000>, diff --git a/arch/arm/boot/dts/broadcom/bcm63138.dtsi b/arch/arm/boot/dts/broadcom/bcm63138.dtsi index 93281c47c9ba9f..4ef02283612bb4 100644 --- a/arch/arm/boot/dts/broadcom/bcm63138.dtsi +++ b/arch/arm/boot/dts/broadcom/bcm63138.dtsi @@ -232,6 +232,12 @@ interrupt-names = "nand"; }; + serial@4400 { + compatible = "brcm,bcm63138-hs-uart", "brcm,bcmbca-hs-uart"; + reg = <0x4400 0x1e0>; + interrupts = ; + }; + bootlut: bootlut@8000 { compatible = "brcm,bcm63138-bootlut"; reg = <0x8000 0x50>; diff --git a/arch/arm/boot/dts/intel/ixp/intel-ixp42x-usrobotics-usr8200.dts b/arch/arm/boot/dts/intel/ixp/intel-ixp42x-usrobotics-usr8200.dts index 90fd51b36e7da2..2c89db34c8d889 100644 --- a/arch/arm/boot/dts/intel/ixp/intel-ixp42x-usrobotics-usr8200.dts +++ b/arch/arm/boot/dts/intel/ixp/intel-ixp42x-usrobotics-usr8200.dts @@ -165,6 +165,24 @@ #address-cells = <1>; #size-cells = <0>; + /* + * PHY 0..4 are internal to the MV88E6060 switch but appear + * as independent devices. + */ + phy0: ethernet-phy@0 { + reg = <0>; + }; + phy1: ethernet-phy@1 { + reg = <1>; + }; + phy2: ethernet-phy@2 { + reg = <2>; + }; + phy3: ethernet-phy@3 { + reg = <3>; + }; + + /* Altima AMI101L used by the WAN port */ phy9: ethernet-phy@9 { reg = <9>; }; @@ -181,21 +199,25 @@ port@0 { reg = <0>; label = "lan1"; + phy-handle = <&phy0>; }; port@1 { reg = <1>; label = "lan2"; + phy-handle = <&phy1>; }; port@2 { reg = <2>; label = "lan3"; + phy-handle = <&phy2>; }; port@3 { reg = <3>; label = "lan4"; + phy-handle = <&phy3>; }; port@5 { diff --git a/arch/arm/boot/dts/intel/socfpga/socfpga.dtsi b/arch/arm/boot/dts/intel/socfpga/socfpga.dtsi index 4c1d140f40f870..35be14150f4167 100644 --- a/arch/arm/boot/dts/intel/socfpga/socfpga.dtsi +++ b/arch/arm/boot/dts/intel/socfpga/socfpga.dtsi @@ -768,7 +768,7 @@ status = "disabled"; }; - nand0: nand@ff900000 { + nand0: nand-controller@ff900000 { #address-cells = <0x1>; #size-cells = <0x0>; compatible = "altr,socfpga-denali-nand"; diff --git a/arch/arm/boot/dts/intel/socfpga/socfpga_arria10.dtsi b/arch/arm/boot/dts/intel/socfpga/socfpga_arria10.dtsi index f36063c57c7f28..6b6e77596ffa86 100644 --- a/arch/arm/boot/dts/intel/socfpga/socfpga_arria10.dtsi +++ b/arch/arm/boot/dts/intel/socfpga/socfpga_arria10.dtsi @@ -669,7 +669,7 @@ status = "disabled"; }; - nand: nand@ffb90000 { + nand: nand-controller@ffb90000 { #address-cells = <1>; #size-cells = <0>; compatible = "altr,socfpga-denali-nand"; diff --git a/arch/arm/boot/dts/intel/socfpga/socfpga_arria10_socdk_qspi.dts b/arch/arm/boot/dts/intel/socfpga/socfpga_arria10_socdk_qspi.dts index 11ccdc6c2dc646..0434f1c7b66529 100644 --- a/arch/arm/boot/dts/intel/socfpga/socfpga_arria10_socdk_qspi.dts +++ b/arch/arm/boot/dts/intel/socfpga/socfpga_arria10_socdk_qspi.dts @@ -17,8 +17,6 @@ spi-max-frequency = <100000000>; m25p,fast-read; - cdns,page-size = <256>; - cdns,block-size = <16>; cdns,read-delay = <3>; cdns,tshsl-ns = <50>; cdns,tsd2d-ns = <50>; diff --git a/arch/arm/boot/dts/intel/socfpga/socfpga_arria5_socdk.dts b/arch/arm/boot/dts/intel/socfpga/socfpga_arria5_socdk.dts index c48385702a854d..7342f5942b0d09 100644 --- a/arch/arm/boot/dts/intel/socfpga/socfpga_arria5_socdk.dts +++ b/arch/arm/boot/dts/intel/socfpga/socfpga_arria5_socdk.dts @@ -124,8 +124,6 @@ spi-max-frequency = <100000000>; m25p,fast-read; - cdns,page-size = <256>; - cdns,block-size = <16>; cdns,read-delay = <4>; cdns,tshsl-ns = <50>; cdns,tsd2d-ns = <50>; diff --git a/arch/arm/boot/dts/intel/socfpga/socfpga_cyclone5_socdk.dts b/arch/arm/boot/dts/intel/socfpga/socfpga_cyclone5_socdk.dts index c7f5fa0ba0f28a..d37a982e857192 100644 --- a/arch/arm/boot/dts/intel/socfpga/socfpga_cyclone5_socdk.dts +++ b/arch/arm/boot/dts/intel/socfpga/socfpga_cyclone5_socdk.dts @@ -129,8 +129,6 @@ spi-max-frequency = <100000000>; m25p,fast-read; - cdns,page-size = <256>; - cdns,block-size = <16>; cdns,read-delay = <4>; cdns,tshsl-ns = <50>; cdns,tsd2d-ns = <50>; diff --git a/arch/arm/boot/dts/intel/socfpga/socfpga_cyclone5_sockit.dts b/arch/arm/boot/dts/intel/socfpga/socfpga_cyclone5_sockit.dts index 3dd99c7c95e0ce..9e4db7407f1a3e 100644 --- a/arch/arm/boot/dts/intel/socfpga/socfpga_cyclone5_sockit.dts +++ b/arch/arm/boot/dts/intel/socfpga/socfpga_cyclone5_sockit.dts @@ -174,8 +174,6 @@ spi-max-frequency = <100000000>; m25p,fast-read; - cdns,page-size = <256>; - cdns,block-size = <16>; cdns,read-delay = <4>; cdns,tshsl-ns = <50>; cdns,tsd2d-ns = <50>; diff --git a/arch/arm/boot/dts/intel/socfpga/socfpga_cyclone5_sodia.dts b/arch/arm/boot/dts/intel/socfpga/socfpga_cyclone5_sodia.dts index 2564671fc1c67f..ce0d6514eeb571 100644 --- a/arch/arm/boot/dts/intel/socfpga/socfpga_cyclone5_sodia.dts +++ b/arch/arm/boot/dts/intel/socfpga/socfpga_cyclone5_sodia.dts @@ -121,8 +121,6 @@ spi-max-frequency = <100000000>; m25p,fast-read; - cdns,page-size = <256>; - cdns,block-size = <16>; cdns,read-delay = <4>; cdns,tshsl-ns = <50>; cdns,tsd2d-ns = <50>; diff --git a/arch/arm/boot/dts/intel/socfpga/socfpga_cyclone5_vining_fpga.dts b/arch/arm/boot/dts/intel/socfpga/socfpga_cyclone5_vining_fpga.dts index e0630b0eed036d..65f390bf897534 100644 --- a/arch/arm/boot/dts/intel/socfpga/socfpga_cyclone5_vining_fpga.dts +++ b/arch/arm/boot/dts/intel/socfpga/socfpga_cyclone5_vining_fpga.dts @@ -229,8 +229,6 @@ spi-max-frequency = <100000000>; m25p,fast-read; - cdns,page-size = <256>; - cdns,block-size = <16>; cdns,read-delay = <4>; cdns,tshsl-ns = <50>; cdns,tsd2d-ns = <50>; @@ -246,8 +244,6 @@ spi-max-frequency = <100000000>; m25p,fast-read; - cdns,page-size = <256>; - cdns,block-size = <16>; cdns,read-delay = <4>; cdns,tshsl-ns = <50>; cdns,tsd2d-ns = <50>; diff --git a/arch/arm/boot/dts/marvell/armada-370-rd.dts b/arch/arm/boot/dts/marvell/armada-370-rd.dts index b459a670f6158c..f23f6b3fc8f3ba 100644 --- a/arch/arm/boot/dts/marvell/armada-370-rd.dts +++ b/arch/arm/boot/dts/marvell/armada-370-rd.dts @@ -95,7 +95,7 @@ gpio-fan { compatible = "gpio-fan"; gpios = <&gpio0 8 GPIO_ACTIVE_HIGH>; - gpio-fan,speed-map = <0 0 3000 1>; + gpio-fan,speed-map = <0 0>, <3000 1>; pinctrl-0 = <&fan_pins>; pinctrl-names = "default"; }; @@ -149,39 +149,37 @@ }; }; - switch: switch@10 { + switch: ethernet-switch@10 { compatible = "marvell,mv88e6085"; - #address-cells = <1>; - #size-cells = <0>; reg = <0x10>; interrupt-controller; #interrupt-cells = <2>; - ports { + ethernet-ports { #address-cells = <1>; #size-cells = <0>; - port@0 { + ethernet-port@0 { reg = <0>; label = "lan0"; }; - port@1 { + ethernet-port@1 { reg = <1>; label = "lan1"; }; - port@2 { + ethernet-port@2 { reg = <2>; label = "lan2"; }; - port@3 { + ethernet-port@3 { reg = <3>; label = "lan3"; }; - port@5 { + ethernet-port@5 { reg = <5>; ethernet = <ð1>; phy-mode = "rgmii-id"; @@ -196,25 +194,25 @@ #address-cells = <1>; #size-cells = <0>; - switchphy0: switchphy@0 { + switchphy0: ethernet-phy@0 { reg = <0>; interrupt-parent = <&switch>; interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; }; - switchphy1: switchphy@1 { + switchphy1: ethernet-phy@1 { reg = <1>; interrupt-parent = <&switch>; interrupts = <1 IRQ_TYPE_LEVEL_HIGH>; }; - switchphy2: switchphy@2 { + switchphy2: ethernet-phy@2 { reg = <2>; interrupt-parent = <&switch>; interrupts = <2 IRQ_TYPE_LEVEL_HIGH>; }; - switchphy3: switchphy@3 { + switchphy3: ethernet-phy@3 { reg = <3>; interrupt-parent = <&switch>; interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; diff --git a/arch/arm/boot/dts/marvell/armada-370-seagate-nas-2bay.dts b/arch/arm/boot/dts/marvell/armada-370-seagate-nas-2bay.dts index 8dd242e668e652..6ec3dd3337f423 100644 --- a/arch/arm/boot/dts/marvell/armada-370-seagate-nas-2bay.dts +++ b/arch/arm/boot/dts/marvell/armada-370-seagate-nas-2bay.dts @@ -25,9 +25,9 @@ gpio-fan { gpio-fan,speed-map = - < 0 3 - 950 2 - 1400 1 - 1800 0>; + < 0 3>, + < 950 2>, + <1400 1>, + <1800 0>; }; }; diff --git a/arch/arm/boot/dts/marvell/armada-370-seagate-nas-4bay.dts b/arch/arm/boot/dts/marvell/armada-370-seagate-nas-4bay.dts index 370ca9c432479f..3011578a31244e 100644 --- a/arch/arm/boot/dts/marvell/armada-370-seagate-nas-4bay.dts +++ b/arch/arm/boot/dts/marvell/armada-370-seagate-nas-4bay.dts @@ -106,10 +106,10 @@ gpio-fan { gpio-fan,speed-map = - < 0 3 - 800 2 - 1050 1 - 1300 0>; + < 0 3>, + < 800 2>, + <1050 1>, + <1300 0>; }; }; diff --git a/arch/arm/boot/dts/marvell/armada-370-synology-ds213j.dts b/arch/arm/boot/dts/marvell/armada-370-synology-ds213j.dts index b07d11d1f12495..02599a3e9816a3 100644 --- a/arch/arm/boot/dts/marvell/armada-370-synology-ds213j.dts +++ b/arch/arm/boot/dts/marvell/armada-370-synology-ds213j.dts @@ -113,14 +113,14 @@ &gpio2 0 GPIO_ACTIVE_HIGH &gpio2 1 GPIO_ACTIVE_HIGH>; alarm-gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>; - gpio-fan,speed-map = < 0 0 - 1000 1 - 1150 2 - 1350 4 - 1500 3 - 1650 5 - 1750 6 - 1900 7 >; + gpio-fan,speed-map = < 0 0>, + <1000 1>, + <1150 2>, + <1350 4>, + <1500 3>, + <1650 5>, + <1750 6>, + <1900 7>; }; gpio-leds { diff --git a/arch/arm/boot/dts/marvell/armada-381-netgear-gs110emx.dts b/arch/arm/boot/dts/marvell/armada-381-netgear-gs110emx.dts index f4c4b213ef4ed6..5baf83e5253d8c 100644 --- a/arch/arm/boot/dts/marvell/armada-381-netgear-gs110emx.dts +++ b/arch/arm/boot/dts/marvell/armada-381-netgear-gs110emx.dts @@ -77,51 +77,49 @@ pinctrl-0 = <&mdio_pins>; status = "okay"; - switch@0 { + ethernet-switch@0 { compatible = "marvell,mv88e6190"; - #address-cells = <1>; #interrupt-cells = <2>; interrupt-controller; interrupt-parent = <&gpio1>; interrupts = <7 IRQ_TYPE_LEVEL_LOW>; pinctrl-0 = <&switch_interrupt_pins>; pinctrl-names = "default"; - #size-cells = <0>; reg = <0>; mdio { #address-cells = <1>; #size-cells = <0>; - switch0phy1: switch0phy1@1 { + switch0phy1: ethernet-phy@1 { reg = <0x1>; }; - switch0phy2: switch0phy2@2 { + switch0phy2: ethernet-phy@2 { reg = <0x2>; }; - switch0phy3: switch0phy3@3 { + switch0phy3: ethernet-phy@3 { reg = <0x3>; }; - switch0phy4: switch0phy4@4 { + switch0phy4: ethernet-phy@4 { reg = <0x4>; }; - switch0phy5: switch0phy5@5 { + switch0phy5: ethernet-phy@5 { reg = <0x5>; }; - switch0phy6: switch0phy6@6 { + switch0phy6: ethernet-phy@6 { reg = <0x6>; }; - switch0phy7: switch0phy7@7 { + switch0phy7: ethernet-phy@7 { reg = <0x7>; }; - switch0phy8: switch0phy8@8 { + switch0phy8: ethernet-phy@8 { reg = <0x8>; }; }; @@ -142,11 +140,11 @@ }; }; - ports { + ethernet-ports { #address-cells = <1>; #size-cells = <0>; - port@0 { + ethernet-port@0 { ethernet = <ð0>; phy-mode = "rgmii"; reg = <0>; @@ -158,55 +156,55 @@ }; }; - port@1 { + ethernet-port@1 { label = "lan1"; phy-handle = <&switch0phy1>; reg = <1>; }; - port@2 { + ethernet-port@2 { label = "lan2"; phy-handle = <&switch0phy2>; reg = <2>; }; - port@3 { + ethernet-port@3 { label = "lan3"; phy-handle = <&switch0phy3>; reg = <3>; }; - port@4 { + ethernet-port@4 { label = "lan4"; phy-handle = <&switch0phy4>; reg = <4>; }; - port@5 { + ethernet-port@5 { label = "lan5"; phy-handle = <&switch0phy5>; reg = <5>; }; - port@6 { + ethernet-port@6 { label = "lan6"; phy-handle = <&switch0phy6>; reg = <6>; }; - port@7 { + ethernet-port@7 { label = "lan7"; phy-handle = <&switch0phy7>; reg = <7>; }; - port@8 { + ethernet-port@8 { label = "lan8"; phy-handle = <&switch0phy8>; reg = <8>; }; - port@9 { + ethernet-port@9 { /* 88X3310P external phy */ label = "lan9"; phy-handle = <&phy1>; @@ -214,7 +212,7 @@ reg = <9>; }; - port@a { + ethernet-port@a { /* 88X3310P external phy */ label = "lan10"; phy-handle = <&phy2>; diff --git a/arch/arm/boot/dts/marvell/armada-385-clearfog-gtr-l8.dts b/arch/arm/boot/dts/marvell/armada-385-clearfog-gtr-l8.dts index 1990f7d0cc79a7..1707d1b015452d 100644 --- a/arch/arm/boot/dts/marvell/armada-385-clearfog-gtr-l8.dts +++ b/arch/arm/boot/dts/marvell/armada-385-clearfog-gtr-l8.dts @@ -7,66 +7,66 @@ }; &mdio { - switch0: switch0@4 { + switch0: ethernet-switch@4 { compatible = "marvell,mv88e6190"; reg = <4>; pinctrl-names = "default"; pinctrl-0 = <&cf_gtr_switch_reset_pins>; reset-gpios = <&gpio0 18 GPIO_ACTIVE_LOW>; - ports { + ethernet-ports { #address-cells = <1>; #size-cells = <0>; - port@1 { + ethernet-port@1 { reg = <1>; label = "lan8"; phy-handle = <&switch0phy0>; }; - port@2 { + ethernet-port@2 { reg = <2>; label = "lan7"; phy-handle = <&switch0phy1>; }; - port@3 { + ethernet-port@3 { reg = <3>; label = "lan6"; phy-handle = <&switch0phy2>; }; - port@4 { + ethernet-port@4 { reg = <4>; label = "lan5"; phy-handle = <&switch0phy3>; }; - port@5 { + ethernet-port@5 { reg = <5>; label = "lan4"; phy-handle = <&switch0phy4>; }; - port@6 { + ethernet-port@6 { reg = <6>; label = "lan3"; phy-handle = <&switch0phy5>; }; - port@7 { + ethernet-port@7 { reg = <7>; label = "lan2"; phy-handle = <&switch0phy6>; }; - port@8 { + ethernet-port@8 { reg = <8>; label = "lan1"; phy-handle = <&switch0phy7>; }; - port@10 { + ethernet-port@10 { reg = <10>; phy-mode = "2500base-x"; @@ -83,35 +83,35 @@ #address-cells = <1>; #size-cells = <0>; - switch0phy0: switch0phy0@1 { + switch0phy0: ethernet-phy@1 { reg = <0x1>; }; - switch0phy1: switch0phy1@2 { + switch0phy1: ethernet-phy@2 { reg = <0x2>; }; - switch0phy2: switch0phy2@3 { + switch0phy2: ethernet-phy@3 { reg = <0x3>; }; - switch0phy3: switch0phy3@4 { + switch0phy3: ethernet-phy@4 { reg = <0x4>; }; - switch0phy4: switch0phy4@5 { + switch0phy4: ethernet-phy@5 { reg = <0x5>; }; - switch0phy5: switch0phy5@6 { + switch0phy5: ethernet-phy@6 { reg = <0x6>; }; - switch0phy6: switch0phy6@7 { + switch0phy6: ethernet-phy@7 { reg = <0x7>; }; - switch0phy7: switch0phy7@8 { + switch0phy7: ethernet-phy@8 { reg = <0x8>; }; }; diff --git a/arch/arm/boot/dts/marvell/armada-385-clearfog-gtr-s4.dts b/arch/arm/boot/dts/marvell/armada-385-clearfog-gtr-s4.dts index b795ad573891ea..a7678a784c1801 100644 --- a/arch/arm/boot/dts/marvell/armada-385-clearfog-gtr-s4.dts +++ b/arch/arm/boot/dts/marvell/armada-385-clearfog-gtr-s4.dts @@ -11,42 +11,42 @@ }; &mdio { - switch0: switch0@4 { + switch0: ethernet-switch@4 { compatible = "marvell,mv88e6085"; reg = <4>; pinctrl-names = "default"; pinctrl-0 = <&cf_gtr_switch_reset_pins>; reset-gpios = <&gpio0 18 GPIO_ACTIVE_LOW>; - ports { + ethernet-ports { #address-cells = <1>; #size-cells = <0>; - port@1 { + ethernet-port@1 { reg = <1>; label = "lan2"; phy-handle = <&switch0phy0>; }; - port@2 { + ethernet-port@2 { reg = <2>; label = "lan1"; phy-handle = <&switch0phy1>; }; - port@3 { + ethernet-port@3 { reg = <3>; label = "lan4"; phy-handle = <&switch0phy2>; }; - port@4 { + ethernet-port@4 { reg = <4>; label = "lan3"; phy-handle = <&switch0phy3>; }; - port@5 { + ethernet-port@5 { reg = <5>; phy-mode = "2500base-x"; ethernet = <ð1>; @@ -63,19 +63,19 @@ #address-cells = <1>; #size-cells = <0>; - switch0phy0: switch0phy0@11 { + switch0phy0: ethernet-phy@11 { reg = <0x11>; }; - switch0phy1: switch0phy1@12 { + switch0phy1: ethernet-phy@12 { reg = <0x12>; }; - switch0phy2: switch0phy2@13 { + switch0phy2: ethernet-phy@13 { reg = <0x13>; }; - switch0phy3: switch0phy3@14 { + switch0phy3: ethernet-phy@14 { reg = <0x14>; }; }; diff --git a/arch/arm/boot/dts/marvell/armada-385-linksys.dtsi b/arch/arm/boot/dts/marvell/armada-385-linksys.dtsi index fc8216fd9f6009..4116ed60f70923 100644 --- a/arch/arm/boot/dts/marvell/armada-385-linksys.dtsi +++ b/arch/arm/boot/dts/marvell/armada-385-linksys.dtsi @@ -158,42 +158,40 @@ &mdio { status = "okay"; - switch@0 { + ethernet-switch@0 { compatible = "marvell,mv88e6085"; - #address-cells = <1>; - #size-cells = <0>; reg = <0>; - ports { + ethernet-ports { #address-cells = <1>; #size-cells = <0>; - port@0 { + ethernet-port@0 { reg = <0>; label = "lan4"; }; - port@1 { + ethernet-port@1 { reg = <1>; label = "lan3"; }; - port@2 { + ethernet-port@2 { reg = <2>; label = "lan2"; }; - port@3 { + ethernet-port@3 { reg = <3>; label = "lan1"; }; - port@4 { + ethernet-port@4 { reg = <4>; label = "wan"; }; - port@5 { + ethernet-port@5 { reg = <5>; phy-mode = "sgmii"; ethernet = <ð2>; diff --git a/arch/arm/boot/dts/marvell/armada-385-synology-ds116.dts b/arch/arm/boot/dts/marvell/armada-385-synology-ds116.dts index ea91ff964d94ec..6caa5c50175a22 100644 --- a/arch/arm/boot/dts/marvell/armada-385-synology-ds116.dts +++ b/arch/arm/boot/dts/marvell/armada-385-synology-ds116.dts @@ -131,14 +131,14 @@ gpios = <&gpio1 18 GPIO_ACTIVE_HIGH>, <&gpio1 17 GPIO_ACTIVE_HIGH>, <&gpio1 16 GPIO_ACTIVE_HIGH>; - gpio-fan,speed-map = < 0 0 - 1500 1 - 2500 2 - 3000 3 - 3400 4 - 3700 5 - 3900 6 - 4000 7>; + gpio-fan,speed-map = < 0 0>, + <1500 1>, + <2500 2>, + <3000 3>, + <3400 4>, + <3700 5>, + <3900 6>, + <4000 7>; #cooling-cells = <2>; }; diff --git a/arch/arm/boot/dts/marvell/armada-385-turris-omnia.dts b/arch/arm/boot/dts/marvell/armada-385-turris-omnia.dts index 2d8d319bec8300..7b755bb4e4e751 100644 --- a/arch/arm/boot/dts/marvell/armada-385-turris-omnia.dts +++ b/arch/arm/boot/dts/marvell/armada-385-turris-omnia.dts @@ -435,12 +435,10 @@ }; /* Switch MV88E6176 at address 0x10 */ - switch@10 { + ethernet-switch@10 { pinctrl-names = "default"; pinctrl-0 = <&swint_pins>; compatible = "marvell,mv88e6085"; - #address-cells = <1>; - #size-cells = <0>; dsa,member = <0 0>; reg = <0x10>; @@ -448,36 +446,36 @@ interrupt-parent = <&gpio1>; interrupts = <13 IRQ_TYPE_LEVEL_LOW>; - ports { + ethernet-ports { #address-cells = <1>; #size-cells = <0>; - ports@0 { + ethernet-port@0 { reg = <0>; label = "lan0"; }; - ports@1 { + ethernet-port@1 { reg = <1>; label = "lan1"; }; - ports@2 { + ethernet-port@2 { reg = <2>; label = "lan2"; }; - ports@3 { + ethernet-port@3 { reg = <3>; label = "lan3"; }; - ports@4 { + ethernet-port@4 { reg = <4>; label = "lan4"; }; - ports@5 { + ethernet-port@5 { reg = <5>; ethernet = <ð1>; phy-mode = "rgmii-id"; @@ -488,7 +486,7 @@ }; }; - ports@6 { + ethernet-port@6 { reg = <6>; ethernet = <ð0>; phy-mode = "rgmii-id"; diff --git a/arch/arm/boot/dts/marvell/armada-388-clearfog.dts b/arch/arm/boot/dts/marvell/armada-388-clearfog.dts index 32c569df142ffc..3290ccad237457 100644 --- a/arch/arm/boot/dts/marvell/armada-388-clearfog.dts +++ b/arch/arm/boot/dts/marvell/armada-388-clearfog.dts @@ -92,44 +92,42 @@ &mdio { status = "okay"; - switch@4 { + ethernet-switch@4 { compatible = "marvell,mv88e6085"; - #address-cells = <1>; - #size-cells = <0>; reg = <4>; pinctrl-0 = <&clearfog_dsa0_clk_pins &clearfog_dsa0_pins>; pinctrl-names = "default"; - ports { + ethernet-ports { #address-cells = <1>; #size-cells = <0>; - port@0 { + ethernet-port@0 { reg = <0>; label = "lan5"; }; - port@1 { + ethernet-port@1 { reg = <1>; label = "lan4"; }; - port@2 { + ethernet-port@2 { reg = <2>; label = "lan3"; }; - port@3 { + ethernet-port@3 { reg = <3>; label = "lan2"; }; - port@4 { + ethernet-port@4 { reg = <4>; label = "lan1"; }; - port@5 { + ethernet-port@5 { reg = <5>; ethernet = <ð1>; phy-mode = "1000base-x"; @@ -140,7 +138,7 @@ }; }; - port@6 { + ethernet-port@6 { /* 88E1512 external phy */ reg = <6>; label = "lan6"; diff --git a/arch/arm/boot/dts/marvell/armada-388-gp.dts b/arch/arm/boot/dts/marvell/armada-388-gp.dts index e2ba50520b6b0b..1de0a172aa5f18 100644 --- a/arch/arm/boot/dts/marvell/armada-388-gp.dts +++ b/arch/arm/boot/dts/marvell/armada-388-gp.dts @@ -237,8 +237,8 @@ gpio-fan { compatible = "gpio-fan"; gpios = <&expander1 3 GPIO_ACTIVE_HIGH>; - gpio-fan,speed-map = < 0 0 - 3000 1>; + gpio-fan,speed-map = < 0 0>, + <3000 1>; }; }; diff --git a/arch/arm/boot/dts/marvell/armada-xp-linksys-mamba.dts b/arch/arm/boot/dts/marvell/armada-xp-linksys-mamba.dts index 7a0614fd0c93ad..ea859f7ea04221 100644 --- a/arch/arm/boot/dts/marvell/armada-xp-linksys-mamba.dts +++ b/arch/arm/boot/dts/marvell/armada-xp-linksys-mamba.dts @@ -265,42 +265,40 @@ &mdio { status = "okay"; - switch@0 { + ethernet-switch@0 { compatible = "marvell,mv88e6085"; - #address-cells = <1>; - #size-cells = <0>; reg = <0>; - ports { + ethernet-ports { #address-cells = <1>; #size-cells = <0>; - port@0 { + ethernet-port@0 { reg = <0>; label = "lan4"; }; - port@1 { + ethernet-port@1 { reg = <1>; label = "lan3"; }; - port@2 { + ethernet-port@2 { reg = <2>; label = "lan2"; }; - port@3 { + ethernet-port@3 { reg = <3>; label = "lan1"; }; - port@4 { + ethernet-port@4 { reg = <4>; label = "internet"; }; - port@5 { + ethernet-port@5 { reg = <5>; phy-mode = "rgmii-id"; ethernet = <ð0>; diff --git a/arch/arm/boot/dts/marvell/kirkwood-dnskw.dtsi b/arch/arm/boot/dts/marvell/kirkwood-dnskw.dtsi index eb917462b219b9..0738eb679fcd7a 100644 --- a/arch/arm/boot/dts/marvell/kirkwood-dnskw.dtsi +++ b/arch/arm/boot/dts/marvell/kirkwood-dnskw.dtsi @@ -38,9 +38,9 @@ pinctrl-names = "default"; gpios = <&gpio1 14 GPIO_ACTIVE_HIGH &gpio1 13 GPIO_ACTIVE_HIGH>; - gpio-fan,speed-map = <0 0 - 3000 1 - 6000 2>; + gpio-fan,speed-map = <0 0>, + <3000 1>, + <6000 2>; }; gpio_poweroff { diff --git a/arch/arm/boot/dts/marvell/kirkwood-linkstation-6282.dtsi b/arch/arm/boot/dts/marvell/kirkwood-linkstation-6282.dtsi index 377b6e970259fd..dfac2045a1ebbb 100644 --- a/arch/arm/boot/dts/marvell/kirkwood-linkstation-6282.dtsi +++ b/arch/arm/boot/dts/marvell/kirkwood-linkstation-6282.dtsi @@ -118,10 +118,11 @@ gpios = <&gpio0 17 GPIO_ACTIVE_LOW &gpio0 16 GPIO_ACTIVE_LOW>; - gpio-fan,speed-map = <0 3 - 1500 2 - 3250 1 - 5000 0>; + gpio-fan,speed-map = + < 0 3>, + <1500 2>, + <3250 1>, + <5000 0>; alarm-gpios = <&gpio1 11 GPIO_ACTIVE_HIGH>; }; diff --git a/arch/arm/boot/dts/marvell/kirkwood-linkstation-lswxl.dts b/arch/arm/boot/dts/marvell/kirkwood-linkstation-lswxl.dts index c6024b569423ab..0425df8cb91cc1 100644 --- a/arch/arm/boot/dts/marvell/kirkwood-linkstation-lswxl.dts +++ b/arch/arm/boot/dts/marvell/kirkwood-linkstation-lswxl.dts @@ -69,10 +69,11 @@ gpios = <&gpio1 16 GPIO_ACTIVE_LOW &gpio1 15 GPIO_ACTIVE_LOW>; - gpio-fan,speed-map = <0 3 - 1500 2 - 3250 1 - 5000 0>; + gpio-fan,speed-map = + < 0 3>, + <1500 2>, + <3250 1>, + <5000 0>; alarm-gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>; }; diff --git a/arch/arm/boot/dts/marvell/kirkwood-lsxl.dtsi b/arch/arm/boot/dts/marvell/kirkwood-lsxl.dtsi index 88b70ba1c8feec..f80af24b9e9008 100644 --- a/arch/arm/boot/dts/marvell/kirkwood-lsxl.dtsi +++ b/arch/arm/boot/dts/marvell/kirkwood-lsxl.dtsi @@ -172,10 +172,11 @@ pinctrl-names = "default"; gpios = <&gpio0 19 GPIO_ACTIVE_LOW &gpio0 18 GPIO_ACTIVE_LOW>; - gpio-fan,speed-map = <0 3 - 1500 2 - 3250 1 - 5000 0>; + gpio-fan,speed-map = + <0 3>, + <1500 2>, + <3250 1>, + <5000 0>; alarm-gpios = <&gpio1 8 GPIO_ACTIVE_HIGH>; }; diff --git a/arch/arm/boot/dts/marvell/kirkwood-ns2max.dts b/arch/arm/boot/dts/marvell/kirkwood-ns2max.dts index c0a087e7740848..044958bc55da16 100644 --- a/arch/arm/boot/dts/marvell/kirkwood-ns2max.dts +++ b/arch/arm/boot/dts/marvell/kirkwood-ns2max.dts @@ -29,15 +29,15 @@ &gpio1 1 GPIO_ACTIVE_LOW &gpio0 23 GPIO_ACTIVE_LOW>; gpio-fan,speed-map = - < 0 0 - 1500 15 - 1700 14 - 1800 13 - 2100 12 - 3100 11 - 3300 10 - 4300 9 - 5500 8>; + < 0 0>, + <1500 15>, + <1700 14>, + <1800 13>, + <2100 12>, + <3100 11>, + <3300 10>, + <4300 9>, + <5500 8>; alarm-gpios = <&gpio0 25 GPIO_ACTIVE_LOW>; }; diff --git a/arch/arm/boot/dts/marvell/kirkwood-ns2mini.dts b/arch/arm/boot/dts/marvell/kirkwood-ns2mini.dts index 5b9fa14b642861..3fbe008f914117 100644 --- a/arch/arm/boot/dts/marvell/kirkwood-ns2mini.dts +++ b/arch/arm/boot/dts/marvell/kirkwood-ns2mini.dts @@ -30,15 +30,15 @@ &gpio1 1 GPIO_ACTIVE_LOW &gpio0 23 GPIO_ACTIVE_LOW>; gpio-fan,speed-map = - < 0 0 - 3000 15 - 3180 14 - 4140 13 - 4570 12 - 6760 11 - 7140 10 - 7980 9 - 9200 8>; + < 0 0>, + <3000 15>, + <3180 14>, + <4140 13>, + <4570 12>, + <6760 11>, + <7140 10>, + <7980 9>, + <9200 8>; alarm-gpios = <&gpio0 25 GPIO_ACTIVE_LOW>; }; diff --git a/arch/arm/boot/dts/marvell/kirkwood-synology.dtsi b/arch/arm/boot/dts/marvell/kirkwood-synology.dtsi index 9b6666020cddfe..20964eb48fd75a 100644 --- a/arch/arm/boot/dts/marvell/kirkwood-synology.dtsi +++ b/arch/arm/boot/dts/marvell/kirkwood-synology.dtsi @@ -286,14 +286,15 @@ gpios = <&gpio1 0 GPIO_ACTIVE_HIGH &gpio1 1 GPIO_ACTIVE_HIGH &gpio1 2 GPIO_ACTIVE_HIGH>; - gpio-fan,speed-map = < 0 0 - 2200 1 - 2500 2 - 3000 4 - 3300 3 - 3700 5 - 3800 6 - 4200 7 >; + gpio-fan,speed-map = + < 0 0>, + <2200 1>, + <2500 2>, + <3000 4>, + <3300 3>, + <3700 5>, + <3800 6>, + <4200 7>; }; gpio-fan-150-15-18 { @@ -306,14 +307,15 @@ &gpio0 16 GPIO_ACTIVE_HIGH &gpio0 17 GPIO_ACTIVE_HIGH>; alarm-gpios = <&gpio0 18 GPIO_ACTIVE_HIGH>; - gpio-fan,speed-map = < 0 0 - 2200 1 - 2500 2 - 3000 4 - 3300 3 - 3700 5 - 3800 6 - 4200 7 >; + gpio-fan,speed-map = + < 0 0>, + <2200 1>, + <2500 2>, + <3000 4>, + <3300 3>, + <3700 5>, + <3800 6>, + <4200 7>; }; gpio-fan-100-32-35 { @@ -326,14 +328,15 @@ &gpio1 1 GPIO_ACTIVE_HIGH &gpio1 2 GPIO_ACTIVE_HIGH>; alarm-gpios = <&gpio1 3 GPIO_ACTIVE_HIGH>; - gpio-fan,speed-map = < 0 0 - 2500 1 - 3100 2 - 3800 3 - 4600 4 - 4800 5 - 4900 6 - 5000 7 >; + gpio-fan,speed-map = + < 0 0>, + <2500 1>, + <3100 2>, + <3800 3>, + <4600 4>, + <4800 5>, + <4900 6>, + <5000 7>; }; gpio-fan-100-15-18 { @@ -346,14 +349,15 @@ &gpio0 16 GPIO_ACTIVE_HIGH &gpio0 17 GPIO_ACTIVE_HIGH>; alarm-gpios = <&gpio0 18 GPIO_ACTIVE_HIGH>; - gpio-fan,speed-map = < 0 0 - 2500 1 - 3100 2 - 3800 3 - 4600 4 - 4800 5 - 4900 6 - 5000 7 >; + gpio-fan,speed-map = + < 0 0>, + <2500 1>, + <3100 2>, + <3800 3>, + <4600 4>, + <4800 5>, + <4900 6>, + <5000 7>; }; gpio-fan-100-15-35-1 { @@ -366,14 +370,15 @@ &gpio0 16 GPIO_ACTIVE_HIGH &gpio0 17 GPIO_ACTIVE_HIGH>; alarm-gpios = <&gpio1 3 GPIO_ACTIVE_HIGH>; - gpio-fan,speed-map = < 0 0 - 2500 1 - 3100 2 - 3800 3 - 4600 4 - 4800 5 - 4900 6 - 5000 7 >; + gpio-fan,speed-map = + < 0 0>, + <2500 1>, + <3100 2>, + <3800 3>, + <4600 4>, + <4800 5>, + <4900 6>, + <5000 7>; }; gpio-fan-100-15-35-3 { @@ -388,14 +393,15 @@ alarm-gpios = <&gpio1 3 GPIO_ACTIVE_HIGH &gpio1 12 GPIO_ACTIVE_HIGH &gpio1 13 GPIO_ACTIVE_HIGH>; - gpio-fan,speed-map = < 0 0 - 2500 1 - 3100 2 - 3800 3 - 4600 4 - 4800 5 - 4900 6 - 5000 7 >; + gpio-fan,speed-map = + < 0 0>, + <2500 1>, + <3100 2>, + <3800 3>, + <4600 4>, + <4800 5>, + <4900 6>, + <5000 7>; }; gpio-leds-alarm-12 { diff --git a/arch/arm/boot/dts/marvell/mvebu-linkstation-fan.dtsi b/arch/arm/boot/dts/marvell/mvebu-linkstation-fan.dtsi index e172029a0c4de6..a260c42dbda33b 100644 --- a/arch/arm/boot/dts/marvell/mvebu-linkstation-fan.dtsi +++ b/arch/arm/boot/dts/marvell/mvebu-linkstation-fan.dtsi @@ -50,10 +50,10 @@ pinctrl-names = "default"; gpio-fan,speed-map = - <0 3 - 1500 2 - 3250 1 - 5000 0>; + < 0 3>, + <1500 2>, + <3250 1>, + <5000 0>; }; }; diff --git a/arch/arm/boot/dts/microchip/at91-sam9x60_curiosity.dts b/arch/arm/boot/dts/microchip/at91-sam9x60_curiosity.dts index 83372c1f291bb2..c6fbdd29019f39 100644 --- a/arch/arm/boot/dts/microchip/at91-sam9x60_curiosity.dts +++ b/arch/arm/boot/dts/microchip/at91-sam9x60_curiosity.dts @@ -249,6 +249,8 @@ ethernet-phy@0 { reg = <0x0>; + interrupt-parent = <&pioB>; + interrupts = <8 IRQ_TYPE_LEVEL_LOW>; }; }; @@ -353,6 +355,7 @@ AT91_PIOB 5 AT91_PERIPH_A AT91_PINCTRL_NONE /* PB5 periph A */ AT91_PIOB 6 AT91_PERIPH_A AT91_PINCTRL_NONE /* PB6 periph A */ AT91_PIOB 7 AT91_PERIPH_A AT91_PINCTRL_NONE /* PB7 periph A */ + AT91_PIOB 8 AT91_PERIPH_GPIO AT91_PINCTRL_NONE /* PB8 IRQ GPIO */ AT91_PIOB 9 AT91_PERIPH_A AT91_PINCTRL_NONE /* PB9 periph A */ AT91_PIOB 10 AT91_PERIPH_A AT91_PINCTRL_NONE>; /* PB10 periph A */ }; diff --git a/arch/arm/boot/dts/microchip/at91-sam9x60ek.dts b/arch/arm/boot/dts/microchip/at91-sam9x60ek.dts index 5cd593028aff7c..f3cbb675cea4ae 100644 --- a/arch/arm/boot/dts/microchip/at91-sam9x60ek.dts +++ b/arch/arm/boot/dts/microchip/at91-sam9x60ek.dts @@ -292,6 +292,8 @@ ethernet-phy@0 { reg = <0x0>; + interrupt-parent = <&pioB>; + interrupts = <8 IRQ_TYPE_LEVEL_LOW>; }; }; @@ -465,6 +467,7 @@ AT91_PIOB 5 AT91_PERIPH_A AT91_PINCTRL_NONE /* PB5 periph A */ AT91_PIOB 6 AT91_PERIPH_A AT91_PINCTRL_NONE /* PB6 periph A */ AT91_PIOB 7 AT91_PERIPH_A AT91_PINCTRL_NONE /* PB7 periph A */ + AT91_PIOB 8 AT91_PERIPH_GPIO AT91_PINCTRL_NONE /* PB8 IRQ GPIO */ AT91_PIOB 9 AT91_PERIPH_A AT91_PINCTRL_NONE /* PB9 periph A */ AT91_PIOB 10 AT91_PERIPH_A AT91_PINCTRL_NONE>; /* PB10 periph A */ }; diff --git a/arch/arm/boot/dts/microchip/at91-sama5d27_som1_ek.dts b/arch/arm/boot/dts/microchip/at91-sama5d27_som1_ek.dts index d0a6dbd377dfa1..f3ffb8f01d8ac3 100644 --- a/arch/arm/boot/dts/microchip/at91-sama5d27_som1_ek.dts +++ b/arch/arm/boot/dts/microchip/at91-sama5d27_som1_ek.dts @@ -54,7 +54,6 @@ sdmmc0: sdio-host@a0000000 { bus-width = <8>; - mmc-ddr-3_3v; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_sdmmc0_default>; status = "okay"; diff --git a/arch/arm/boot/dts/microchip/at91-sama5d27_wlsom1_ek.dts b/arch/arm/boot/dts/microchip/at91-sama5d27_wlsom1_ek.dts index e055b9e2fe3446..15239834d886ed 100644 --- a/arch/arm/boot/dts/microchip/at91-sama5d27_wlsom1_ek.dts +++ b/arch/arm/boot/dts/microchip/at91-sama5d27_wlsom1_ek.dts @@ -197,7 +197,6 @@ &sdmmc0 { bus-width = <4>; - mmc-ddr-3_3v; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_sdmmc0_default>; status = "okay"; diff --git a/arch/arm/boot/dts/nvidia/tegra20-colibri.dtsi b/arch/arm/boot/dts/nvidia/tegra20-colibri.dtsi index 16b374e6482f51..8c1d5c9fa4831d 100644 --- a/arch/arm/boot/dts/nvidia/tegra20-colibri.dtsi +++ b/arch/arm/boot/dts/nvidia/tegra20-colibri.dtsi @@ -446,7 +446,7 @@ tegra_ac97: ac97@70002000 { status = "okay"; nvidia,codec-reset-gpio = - <&gpio TEGRA_GPIO(V, 0) GPIO_ACTIVE_HIGH>; + <&gpio TEGRA_GPIO(V, 0) GPIO_ACTIVE_LOW>; nvidia,codec-sync-gpio = <&gpio TEGRA_GPIO(P, 0) GPIO_ACTIVE_HIGH>; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx1-ads.dts b/arch/arm/boot/dts/nxp/imx/imx1-ads.dts index 5833fb6f15d88a..2c817c4a4c68f8 100644 --- a/arch/arm/boot/dts/nxp/imx/imx1-ads.dts +++ b/arch/arm/boot/dts/nxp/imx/imx1-ads.dts @@ -65,7 +65,7 @@ pinctrl-0 = <&pinctrl_weim>; status = "okay"; - nor: nor@0,0 { + nor: flash@0,0 { compatible = "cfi-flash"; reg = <0 0x00000000 0x02000000>; bank-width = <4>; diff --git a/arch/arm/boot/dts/nxp/imx/imx1-apf9328.dts b/arch/arm/boot/dts/nxp/imx/imx1-apf9328.dts index 1f11e9542a72de..e66eef87a7a4fd 100644 --- a/arch/arm/boot/dts/nxp/imx/imx1-apf9328.dts +++ b/arch/arm/boot/dts/nxp/imx/imx1-apf9328.dts @@ -45,7 +45,7 @@ pinctrl-0 = <&pinctrl_weim>; status = "okay"; - nor: nor@0,0 { + nor: flash@0,0 { compatible = "cfi-flash"; reg = <0 0x00000000 0x02000000>; bank-width = <2>; diff --git a/arch/arm/boot/dts/nxp/imx/imx1.dtsi b/arch/arm/boot/dts/nxp/imx/imx1.dtsi index e312f1e74e2fe6..1ac10965fdfdd5 100644 --- a/arch/arm/boot/dts/nxp/imx/imx1.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx1.dtsi @@ -68,7 +68,7 @@ interrupt-parent = <&aitc>; ranges; - aipi@200000 { + bus@200000 { compatible = "fsl,aipi-bus", "simple-bus"; #address-cells = <1>; #size-cells = <1>; @@ -155,7 +155,7 @@ }; }; - aipi@210000 { + bus@210000 { compatible = "fsl,aipi-bus", "simple-bus"; #address-cells = <1>; #size-cells = <1>; @@ -268,9 +268,12 @@ status = "disabled"; }; - esram: esram@300000 { + esram: sram@300000 { compatible = "mmio-sram"; reg = <0x00300000 0x20000>; + ranges = <0 0x00300000 0x20000>; + #address-cells = <1>; + #size-cells = <1>; }; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx25-eukrea-cpuimx25.dtsi b/arch/arm/boot/dts/nxp/imx/imx25-eukrea-cpuimx25.dtsi index 0703f62d10d1cb..93a6e4e680b451 100644 --- a/arch/arm/boot/dts/nxp/imx/imx25-eukrea-cpuimx25.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx25-eukrea-cpuimx25.dtsi @@ -27,7 +27,7 @@ pinctrl-0 = <&pinctrl_i2c1>; status = "okay"; - pcf8563@51 { + rtc@51 { compatible = "nxp,pcf8563"; reg = <0x51>; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx25-eukrea-mbimxsd25-baseboard-cmo-qvga.dts b/arch/arm/boot/dts/nxp/imx/imx25-eukrea-mbimxsd25-baseboard-cmo-qvga.dts index fc8a502fc957f0..6cddb2cc36fe2a 100644 --- a/arch/arm/boot/dts/nxp/imx/imx25-eukrea-mbimxsd25-baseboard-cmo-qvga.dts +++ b/arch/arm/boot/dts/nxp/imx/imx25-eukrea-mbimxsd25-baseboard-cmo-qvga.dts @@ -16,7 +16,7 @@ bus-width = <18>; display-timings { native-mode = <&qvga_timings>; - qvga_timings: 320x240 { + qvga_timings: timing0 { clock-frequency = <6500000>; hactive = <320>; vactive = <240>; diff --git a/arch/arm/boot/dts/nxp/imx/imx25-eukrea-mbimxsd25-baseboard-dvi-svga.dts b/arch/arm/boot/dts/nxp/imx/imx25-eukrea-mbimxsd25-baseboard-dvi-svga.dts index 80a7f96de4c6ac..64b2ffac463b2a 100644 --- a/arch/arm/boot/dts/nxp/imx/imx25-eukrea-mbimxsd25-baseboard-dvi-svga.dts +++ b/arch/arm/boot/dts/nxp/imx/imx25-eukrea-mbimxsd25-baseboard-dvi-svga.dts @@ -16,7 +16,7 @@ bus-width = <18>; display-timings { native-mode = <&dvi_svga_timings>; - dvi_svga_timings: 800x600 { + dvi_svga_timings: timing0 { clock-frequency = <40000000>; hactive = <800>; vactive = <600>; diff --git a/arch/arm/boot/dts/nxp/imx/imx25-eukrea-mbimxsd25-baseboard-dvi-vga.dts b/arch/arm/boot/dts/nxp/imx/imx25-eukrea-mbimxsd25-baseboard-dvi-vga.dts index 24027a1fb46d11..fb074bfdaa8dc2 100644 --- a/arch/arm/boot/dts/nxp/imx/imx25-eukrea-mbimxsd25-baseboard-dvi-vga.dts +++ b/arch/arm/boot/dts/nxp/imx/imx25-eukrea-mbimxsd25-baseboard-dvi-vga.dts @@ -16,7 +16,7 @@ bus-width = <18>; display-timings { native-mode = <&dvi_vga_timings>; - dvi_vga_timings: 640x480 { + dvi_vga_timings: timing0 { clock-frequency = <31250000>; hactive = <640>; vactive = <480>; diff --git a/arch/arm/boot/dts/nxp/imx/imx25-pdk.dts b/arch/arm/boot/dts/nxp/imx/imx25-pdk.dts index 04f4b127a17257..dd176fb54e5859 100644 --- a/arch/arm/boot/dts/nxp/imx/imx25-pdk.dts +++ b/arch/arm/boot/dts/nxp/imx/imx25-pdk.dts @@ -68,7 +68,7 @@ bus-width = <18>; display-timings { native-mode = <&wvga_timings>; - wvga_timings: 640x480 { + wvga_timings: timing0 { hactive = <640>; vactive = <480>; hback-porch = <45>; @@ -122,6 +122,7 @@ codec: sgtl5000@a { compatible = "fsl,sgtl5000"; reg = <0x0a>; + #sound-dai-cells = <0>; clocks = <&clks 129>; VDDA-supply = <®_2p5v>; VDDIO-supply = <®_3p3v>; diff --git a/arch/arm/boot/dts/nxp/imx/imx25.dtsi b/arch/arm/boot/dts/nxp/imx/imx25.dtsi index 534c70b8d79df5..9cfff2151b7edc 100644 --- a/arch/arm/boot/dts/nxp/imx/imx25.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx25.dtsi @@ -68,6 +68,16 @@ }; }; + usbphy0: usb-phy0 { + compatible = "usb-nop-xceiv"; + #phy-cells = <0>; + }; + + usbphy1: usb-phy1 { + compatible = "usb-nop-xceiv"; + #phy-cells = <0>; + }; + soc: soc { #address-cells = <1>; #size-cells = <1>; @@ -93,7 +103,7 @@ compatible = "fsl,imx25-i2c", "fsl,imx21-i2c"; reg = <0x43f80000 0x4000>; clocks = <&clks 48>; - clock-names = ""; + clock-names = "ipg"; interrupts = <3>; status = "disabled"; }; @@ -104,7 +114,7 @@ compatible = "fsl,imx25-i2c", "fsl,imx21-i2c"; reg = <0x43f84000 0x4000>; clocks = <&clks 48>; - clock-names = ""; + clock-names = "ipg"; interrupts = <10>; status = "disabled"; }; @@ -151,7 +161,7 @@ compatible = "fsl,imx25-i2c", "fsl,imx21-i2c"; reg = <0x43f98000 0x4000>; clocks = <&clks 48>; - clock-names = ""; + clock-names = "ipg"; interrupts = <4>; status = "disabled"; }; @@ -178,12 +188,9 @@ }; kpp: kpp@43fa8000 { - #address-cells = <1>; - #size-cells = <0>; compatible = "fsl,imx25-kpp", "fsl,imx21-kpp"; reg = <0x43fa8000 0x4000>; clocks = <&clks 102>; - clock-names = ""; interrupts = <24>; status = "disabled"; }; @@ -542,7 +549,7 @@ }; iim: efuse@53ff0000 { - compatible = "fsl,imx25-iim", "fsl,imx27-iim"; + compatible = "fsl,imx25-iim"; reg = <0x53ff0000 0x4000>; interrupts = <19>; clocks = <&clks 99>; @@ -597,7 +604,7 @@ #size-cells = <1>; }; - emi@80000000 { + bus@80000000 { compatible = "fsl,emi-bus", "simple-bus"; #address-cells = <1>; #size-cells = <1>; @@ -617,22 +624,4 @@ }; }; }; - - usbphy { - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <0>; - - usbphy0: usb-phy@0 { - reg = <0>; - compatible = "usb-nop-xceiv"; - #phy-cells = <0>; - }; - - usbphy1: usb-phy@1 { - reg = <1>; - compatible = "usb-nop-xceiv"; - #phy-cells = <0>; - }; - }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx27-apf27dev.dts b/arch/arm/boot/dts/nxp/imx/imx27-apf27dev.dts index a21f1f7c24b88d..849306cb4532db 100644 --- a/arch/arm/boot/dts/nxp/imx/imx27-apf27dev.dts +++ b/arch/arm/boot/dts/nxp/imx/imx27-apf27dev.dts @@ -16,7 +16,7 @@ fsl,pcr = <0xfae80083>; /* non-standard but required */ display-timings { native-mode = <&timing0>; - timing0: 800x480 { + timing0: timing0 { clock-frequency = <33000033>; hactive = <800>; vactive = <480>; @@ -47,7 +47,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_gpio_leds>; - user { + led-user { label = "Heartbeat"; gpios = <&gpio6 14 GPIO_ACTIVE_HIGH>; linux,default-trigger = "heartbeat"; diff --git a/arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi b/arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi index 74110bbcd9d4f2..c7e92358487826 100644 --- a/arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx27-eukrea-cpuimx27.dtsi @@ -33,7 +33,7 @@ pinctrl-0 = <&pinctrl_i2c1>; status = "okay"; - pcf8563@51 { + rtc@51 { compatible = "nxp,pcf8563"; reg = <0x51>; }; @@ -90,7 +90,7 @@ &weim { status = "okay"; - nor: nor@0,0 { + nor: flash@0,0 { #address-cells = <1>; #size-cells = <1>; compatible = "cfi-flash"; diff --git a/arch/arm/boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts b/arch/arm/boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts index 145e459625b32d..d78793601306cf 100644 --- a/arch/arm/boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts +++ b/arch/arm/boot/dts/nxp/imx/imx27-eukrea-mbimxsd27-baseboard.dts @@ -16,7 +16,7 @@ display-timings { native-mode = <&timing0>; - timing0: 320x240 { + timing0: timing0 { clock-frequency = <6500000>; hactive = <320>; vactive = <240>; diff --git a/arch/arm/boot/dts/nxp/imx/imx27-pdk.dts b/arch/arm/boot/dts/nxp/imx/imx27-pdk.dts index 35123b7cb6b3ed..21d436972aa47c 100644 --- a/arch/arm/boot/dts/nxp/imx/imx27-pdk.dts +++ b/arch/arm/boot/dts/nxp/imx/imx27-pdk.dts @@ -14,18 +14,12 @@ reg = <0xa0000000 0x08000000>; }; - usbphy { - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <0>; - - usbphy0: usbphy@0 { - compatible = "usb-nop-xceiv"; - reg = <0>; - clocks = <&clks IMX27_CLK_DUMMY>; - clock-names = "main_clk"; - #phy-cells = <0>; - }; + + usbphy0: usbphy { + compatible = "usb-nop-xceiv"; + clocks = <&clks IMX27_CLK_DUMMY>; + clock-names = "main_clk"; + #phy-cells = <0>; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx27-phytec-phycard-s-rdk.dts b/arch/arm/boot/dts/nxp/imx/imx27-phytec-phycard-s-rdk.dts index 25442eba21c1e0..27c93b9fe0499f 100644 --- a/arch/arm/boot/dts/nxp/imx/imx27-phytec-phycard-s-rdk.dts +++ b/arch/arm/boot/dts/nxp/imx/imx27-phytec-phycard-s-rdk.dts @@ -19,7 +19,7 @@ fsl,pcr = <0xf0c88080>; /* non-standard but required */ display-timings { native-mode = <&timing0>; - timing0: 640x480 { + timing0: timing0 { hactive = <640>; vactive = <480>; hback-porch = <112>; diff --git a/arch/arm/boot/dts/nxp/imx/imx27-phytec-phycore-rdk.dts b/arch/arm/boot/dts/nxp/imx/imx27-phytec-phycore-rdk.dts index 7f0cd4d3ec2de4..b8048e12e3d9ab 100644 --- a/arch/arm/boot/dts/nxp/imx/imx27-phytec-phycore-rdk.dts +++ b/arch/arm/boot/dts/nxp/imx/imx27-phytec-phycore-rdk.dts @@ -19,7 +19,7 @@ display-timings { native-mode = <&timing0>; - timing0: 240x320 { + timing0: timing0 { clock-frequency = <5500000>; hactive = <240>; vactive = <320>; @@ -48,15 +48,12 @@ regulator-always-on; }; - usbphy { - usbphy2: usbphy@2 { - compatible = "usb-nop-xceiv"; - reg = <2>; - vcc-supply = <®_5v0>; - clocks = <&clks IMX27_CLK_DUMMY>; - clock-names = "main_clk"; - #phy-cells = <0>; - }; + usbphy2: usbphy { + compatible = "usb-nop-xceiv"; + vcc-supply = <®_5v0>; + clocks = <&clks IMX27_CLK_DUMMY>; + clock-names = "main_clk"; + #phy-cells = <0>; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx27-phytec-phycore-som.dtsi b/arch/arm/boot/dts/nxp/imx/imx27-phytec-phycore-som.dtsi index 7b2ea4cdae58c9..e958d7286ae9d3 100644 --- a/arch/arm/boot/dts/nxp/imx/imx27-phytec-phycore-som.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx27-phytec-phycore-som.dtsi @@ -29,19 +29,13 @@ regulator-max-microvolt = <5000000>; }; - usbphy { - compatible = "simple-bus"; - #address-cells = <1>; - #size-cells = <0>; - - usbphy0: usbphy@0 { - compatible = "usb-nop-xceiv"; - reg = <0>; - vcc-supply = <&sw3_reg>; - clocks = <&clks IMX27_CLK_DUMMY>; - clock-names = "main_clk"; - #phy-cells = <0>; - }; + + usbphy0: usbphy { + compatible = "usb-nop-xceiv"; + vcc-supply = <&sw3_reg>; + clocks = <&clks IMX27_CLK_DUMMY>; + clock-names = "main_clk"; + #phy-cells = <0>; }; }; @@ -49,12 +43,12 @@ status = "okay"; /* SSI0 <=> PINS_4 (MC13783 Audio) */ - ssi0 { + mux-ssi0 { fsl,audmux-port = <0>; fsl,port-config = <0xcb205000>; }; - pins4 { + mux-pins4 { fsl,audmux-port = <2>; fsl,port-config = <0x00001000>; }; @@ -186,7 +180,7 @@ reg = <0x52>; }; - pcf8563@51 { + rtc@51 { compatible = "nxp,pcf8563"; reg = <0x51>; }; @@ -314,7 +308,7 @@ &weim { status = "okay"; - nor: nor@0,0 { + nor: flash@0,0 { compatible = "cfi-flash"; reg = <0 0x00000000 0x02000000>; bank-width = <2>; diff --git a/arch/arm/boot/dts/nxp/imx/imx27.dtsi b/arch/arm/boot/dts/nxp/imx/imx27.dtsi index faba12ee7465eb..ec472695c71ea9 100644 --- a/arch/arm/boot/dts/nxp/imx/imx27.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx27.dtsi @@ -81,7 +81,7 @@ interrupt-parent = <&aitc>; ranges; - aipi1: aipi@10000000 { /* AIPI1 */ + aipi1: bus@10000000 { /* AIPI1 */ compatible = "fsl,aipi-bus", "simple-bus"; #address-cells = <1>; #size-cells = <1>; @@ -453,7 +453,7 @@ }; }; - aipi2: aipi@10020000 { /* AIPI2 */ + aipi2: bus@10020000 { /* AIPI2 */ compatible = "fsl,aipi-bus", "simple-bus"; #address-cells = <1>; #size-cells = <1>; @@ -588,6 +588,9 @@ iram: sram@ffff4c00 { compatible = "mmio-sram"; reg = <0xffff4c00 0xb400>; + ranges = <0 0xffff4c00 0xb400>; + #address-cells = <1>; + #size-cells = <1>; }; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx53-cx9020.dts b/arch/arm/boot/dts/nxp/imx/imx53-cx9020.dts index 055d23a9aee7c0..0814f5665a59c3 100644 --- a/arch/arm/boot/dts/nxp/imx/imx53-cx9020.dts +++ b/arch/arm/boot/dts/nxp/imx/imx53-cx9020.dts @@ -22,7 +22,7 @@ }; display-0 { - #address-cells =<1>; + #address-cells = <1>; #size-cells = <0>; compatible = "fsl,imx-parallel-display"; interface-pix-fmt = "rgb24"; diff --git a/arch/arm/boot/dts/nxp/imx/imx6dl-b105pv2.dts b/arch/arm/boot/dts/nxp/imx/imx6dl-b105pv2.dts index 7d4ae113c381d2..63cdf24eb397ed 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6dl-b105pv2.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6dl-b105pv2.dts @@ -22,7 +22,7 @@ compatible = "ilitek,ili251x"; reg = <0x41>; pinctrl-names = "default"; - pinctrl-0 =<&pinctrl_q7_gpio0>; + pinctrl-0 = <&pinctrl_q7_gpio0>; interrupt-parent = <&gpio5>; interrupts = <2 IRQ_TYPE_EDGE_FALLING>; reset-gpios = <&tca6424a 21 GPIO_ACTIVE_LOW>; diff --git a/arch/arm/boot/dts/nxp/imx/imx6dl-b105v2.dts b/arch/arm/boot/dts/nxp/imx/imx6dl-b105v2.dts index 9c5938e16d99aa..2e75d700efdb32 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6dl-b105v2.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6dl-b105v2.dts @@ -22,7 +22,7 @@ compatible = "ilitek,ili251x"; reg = <0x41>; pinctrl-names = "default"; - pinctrl-0 =<&pinctrl_q7_gpio0>; + pinctrl-0 = <&pinctrl_q7_gpio0>; interrupt-parent = <&gpio5>; interrupts = <2 IRQ_TYPE_EDGE_FALLING>; reset-gpios = <&tca6424a 21 GPIO_ACTIVE_LOW>; diff --git a/arch/arm/boot/dts/nxp/imx/imx6dl-b125pv2.dts b/arch/arm/boot/dts/nxp/imx/imx6dl-b125pv2.dts index 01df7cffcef2ea..94625d5d5918e8 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6dl-b125pv2.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6dl-b125pv2.dts @@ -22,7 +22,7 @@ compatible = "eeti,exc80h60"; reg = <0x2a>; pinctrl-names = "default"; - pinctrl-0 =<&pinctrl_q7_gpio0>; + pinctrl-0 = <&pinctrl_q7_gpio0>; interrupt-parent = <&gpio5>; interrupts = <2 IRQ_TYPE_LEVEL_LOW>; reset-gpios = <&tca6424a 21 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm/boot/dts/nxp/imx/imx6dl-b125v2.dts b/arch/arm/boot/dts/nxp/imx/imx6dl-b125v2.dts index a015453daf10ef..b3cfa8110ade45 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6dl-b125v2.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6dl-b125v2.dts @@ -22,7 +22,7 @@ compatible = "eeti,exc80h60"; reg = <0x2a>; pinctrl-names = "default"; - pinctrl-0 =<&pinctrl_q7_gpio0>; + pinctrl-0 = <&pinctrl_q7_gpio0>; interrupt-parent = <&gpio5>; interrupts = <2 IRQ_TYPE_LEVEL_LOW>; reset-gpios = <&tca6424a 21 GPIO_ACTIVE_HIGH>; diff --git a/arch/arm/boot/dts/nxp/imx/imx6dl-b155v2.dts b/arch/arm/boot/dts/nxp/imx/imx6dl-b155v2.dts index b71ee6b792088d..7edc788bcb8f3a 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6dl-b155v2.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6dl-b155v2.dts @@ -22,7 +22,7 @@ compatible = "eeti,exc80h84"; reg = <0x2a>; pinctrl-names = "default"; - pinctrl-0 =<&pinctrl_q7_gpio0>; + pinctrl-0 = <&pinctrl_q7_gpio0>; interrupt-parent = <&gpio5>; interrupts = <2 IRQ_TYPE_LEVEL_LOW>; touchscreen-inverted-x; diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-apalis-ixora-v1.2.dts b/arch/arm/boot/dts/nxp/imx/imx6q-apalis-ixora-v1.2.dts index 717decda0cebd5..3ac7a45016205a 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6q-apalis-ixora-v1.2.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6q-apalis-ixora-v1.2.dts @@ -76,6 +76,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_enable_can1_power>; regulator-name = "can1_supply"; + startup-delay-us = <1000>; }; reg_can2_supply: regulator-can2-supply { @@ -85,6 +86,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_enable_can2_power>; regulator-name = "can2_supply"; + startup-delay-us = <1000>; }; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6q-var-mx6customboard.dts b/arch/arm/boot/dts/nxp/imx/imx6q-var-mx6customboard.dts index 6f9d094dd6d015..18a620832a2ad3 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6q-var-mx6customboard.dts +++ b/arch/arm/boot/dts/nxp/imx/imx6q-var-mx6customboard.dts @@ -16,7 +16,7 @@ compatible = "variscite,mx6customboard", "variscite,var-som-imx6q", "fsl,imx6q"; panel0: lvds-panel0 { - compatible = "panel-lvds"; + compatible = "panel-lvds"; backlight = <&backlight_lvds>; width-mm = <152>; height-mm = <91>; @@ -43,7 +43,7 @@ }; panel1: lvds-panel1 { - compatible = "panel-lvds"; + compatible = "panel-lvds"; width-mm = <152>; height-mm = <91>; data-mapping = "jeida-18"; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-apalis.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-apalis.dtsi index 4cc965277c5219..2ae93f57fe5aca 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-apalis.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-apalis.dtsi @@ -12,6 +12,13 @@ model = "Toradex Apalis iMX6Q/D Module"; compatible = "toradex,apalis_imx6q", "fsl,imx6q"; + aliases { + mmc0 = &usdhc3; /* eMMC */ + mmc1 = &usdhc1; /* MMC1 slot */ + mmc2 = &usdhc2; /* SD1 slot */ + /delete-property/ mmc3; + }; + /* Will be filled by the bootloader */ memory@10000000 { device_type = "memory"; @@ -166,7 +173,7 @@ reg_usb_host_vbus: regulator-usb-host-vbus { compatible = "regulator-fixed"; enable-active-high; - gpio = <&gpio1 0 GPIO_ACTIVE_HIGH>; + gpio = <&gpio1 0 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_regulator_usbh_pwr>; regulator-max-microvolt = <5000000>; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-colibri.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-colibri.dtsi index 11d9c7a2dacb14..55c90f6393ad5e 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-colibri.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-colibri.dtsi @@ -12,6 +12,13 @@ model = "Toradex Colibri iMX6DL/S Module"; compatible = "toradex,colibri_imx6dl", "fsl,imx6dl"; + aliases { + mmc0 = &usdhc3; /* eMMC */ + mmc1 = &usdhc1; /* MMC/SD Slot */ + /delete-property/ mmc2; + /delete-property/ mmc3; + }; + backlight: backlight { compatible = "pwm-backlight"; brightness-levels = <0 45 63 88 119 158 203 255>; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-emcon-avari.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-emcon-avari.dtsi index f1a41c76729cb5..5587069b605217 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-emcon-avari.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-emcon-avari.dtsi @@ -54,7 +54,7 @@ clk_codec: clock-codec { compatible = "fixed-clock"; #clock-cells = <0>; - clock-frequency = <12000000>; + clock-frequency = <12000000>; }; sound { diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-mba6.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-mba6.dtsi index da0f8dae1ea827..4d2abcd44eff24 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-mba6.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-mba6.dtsi @@ -500,21 +500,21 @@ pinctrl_pwm1: pwm1grp { fsl,pins = < - /* 100 k PD, DSE 120 OHM, SPPEED LO */ + /* 100 k PD, DSE 120 OHM, SPEED LO */ MX6QDL_PAD_GPIO_9__PWM1_OUT 0x00003050 >; }; pinctrl_pwm3: pwm3grp { fsl,pins = < - /* 100 k PD, DSE 120 OHM, SPPEED LO */ + /* 100 k PD, DSE 120 OHM, SPEED LO */ MX6QDL_PAD_SD4_DAT1__PWM3_OUT 0x00003050 >; }; pinctrl_pwm4: pwm4grp { fsl,pins = < - /* 100 k PD, DSE 120 OHM, SPPEED LO */ + /* 100 k PD, DSE 120 OHM, SPEED LO */ MX6QDL_PAD_SD4_DAT2__PWM4_OUT 0x00003050 >; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl-skov-cpu-revc.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl-skov-cpu-revc.dtsi index b81799d7076aa7..596b3bb3ddd1b8 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl-skov-cpu-revc.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl-skov-cpu-revc.dtsi @@ -25,7 +25,7 @@ compatible = "ti,tsc2046e-adc"; reg = <0>; pinctrl-0 = <&pinctrl_touch>; - pinctrl-names ="default"; + pinctrl-names = "default"; spi-max-frequency = <1000000>; interrupts-extended = <&gpio3 19 IRQ_TYPE_LEVEL_LOW>; #io-channel-cells = <1>; diff --git a/arch/arm/boot/dts/nxp/imx/imx6qdl.dtsi b/arch/arm/boot/dts/nxp/imx/imx6qdl.dtsi index bda182edc58915..81142c523fa8c3 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6qdl.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6qdl.dtsi @@ -475,7 +475,7 @@ <&sdma 20 23 1>, <&sdma 21 23 1>, <&sdma 22 23 1>; dma-names = "rxa", "rxb", "rxc", "txa", "txb", "txc"; - fsl,asrc-rate = <48000>; + fsl,asrc-rate = <48000>; fsl,asrc-width = <16>; status = "okay"; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6sx.dtsi b/arch/arm/boot/dts/nxp/imx/imx6sx.dtsi index f6b35923ad83ec..df3a375f0a3e85 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6sx.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6sx.dtsi @@ -418,7 +418,7 @@ <&sdma 21 23 1>, <&sdma 22 23 1>; dma-names = "rxa", "rxb", "rxc", "txa", "txb", "txc"; - fsl,asrc-rate = <48000>; + fsl,asrc-rate = <48000>; fsl,asrc-width = <16>; status = "okay"; }; @@ -1010,7 +1010,7 @@ clock-names = "ipg", "ahb", "per"; bus-width = <4>; fsl,tuning-start-tap = <20>; - fsl,tuning-step= <2>; + fsl,tuning-step = <2>; status = "disabled"; }; @@ -1024,7 +1024,7 @@ clock-names = "ipg", "ahb", "per"; bus-width = <4>; fsl,tuning-start-tap = <20>; - fsl,tuning-step= <2>; + fsl,tuning-step = <2>; status = "disabled"; }; @@ -1038,7 +1038,7 @@ clock-names = "ipg", "ahb", "per"; bus-width = <4>; fsl,tuning-start-tap = <20>; - fsl,tuning-step= <2>; + fsl,tuning-step = <2>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6ul.dtsi b/arch/arm/boot/dts/nxp/imx/imx6ul.dtsi index 3b87d980e9f465..a27a7554c2e7fd 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6ul.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6ul.dtsi @@ -364,7 +364,7 @@ <&sdma 20 23 1>, <&sdma 21 23 1>, <&sdma 22 23 1>; dma-names = "rxa", "rxb", "rxc", "txa", "txb", "txc"; - fsl,asrc-rate = <48000>; + fsl,asrc-rate = <48000>; fsl,asrc-width = <16>; status = "okay"; }; diff --git a/arch/arm/boot/dts/nxp/imx/imx6ull-phytec-tauri.dtsi b/arch/arm/boot/dts/nxp/imx/imx6ull-phytec-tauri.dtsi index 44cc4ff1d0df35..d12fb44aeb140c 100644 --- a/arch/arm/boot/dts/nxp/imx/imx6ull-phytec-tauri.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx6ull-phytec-tauri.dtsi @@ -116,7 +116,7 @@ tpm_tis: tpm@1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_tpm>; - compatible = "tcg,tpm_tis-spi"; + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; reg = <1>; spi-max-frequency = <20000000>; interrupt-parent = <&gpio5>; diff --git a/arch/arm/boot/dts/nxp/imx/imx7-tqma7.dtsi b/arch/arm/boot/dts/nxp/imx/imx7-tqma7.dtsi index fe42b0a4683108..3fc3130f9defe4 100644 --- a/arch/arm/boot/dts/nxp/imx/imx7-tqma7.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx7-tqma7.dtsi @@ -128,11 +128,16 @@ }; }; - /* NXP SE97BTP with temperature sensor + eeprom */ + /* LM75A temperature sensor, TQMa7x 01xx */ + lm75a: temperature-sensor@48 { + compatible = "national,lm75a"; + reg = <0x48>; + }; + + /* NXP SE97BTP with temperature sensor + eeprom, TQMa7x 02xx */ se97b: temperature-sensor-eeprom@1e { compatible = "nxp,se97b", "jedec,jc-42.4-temp"; reg = <0x1e>; - status = "okay"; }; /* ST M24C64 */ diff --git a/arch/arm/boot/dts/nxp/imx/imx7d-colibri-emmc.dtsi b/arch/arm/boot/dts/nxp/imx/imx7d-colibri-emmc.dtsi index 3740e34ef99f1b..9670f45eab3bad 100644 --- a/arch/arm/boot/dts/nxp/imx/imx7d-colibri-emmc.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx7d-colibri-emmc.dtsi @@ -11,6 +11,10 @@ /* Required to properly pass MAC addresses from bootloader. */ ethernet0 = &fec1; ethernet1 = &fec2; + mmc0 = &usdhc3; /* eMMC */ + mmc1 = &usdhc1; /* MMC/SD slot */ + /delete-property/ mmc2; + /delete-property/ mmc3; }; memory@80000000 { diff --git a/arch/arm/boot/dts/nxp/imx/imx7d-flex-concentrator.dts b/arch/arm/boot/dts/nxp/imx/imx7d-flex-concentrator.dts index 3a723843d5626f..9984b343cdf0ca 100644 --- a/arch/arm/boot/dts/nxp/imx/imx7d-flex-concentrator.dts +++ b/arch/arm/boot/dts/nxp/imx/imx7d-flex-concentrator.dts @@ -130,7 +130,7 @@ * TCG specification - Section 6.4.1 Clocking: * TPM shall support a SPI clock frequency range of 10-24 MHz. */ - st33htph: tpm-tis@0 { + st33htph: tpm@0 { compatible = "st,st33htpm-spi", "tcg,tpm_tis-spi"; reg = <0>; spi-max-frequency = <24000000>; diff --git a/arch/arm/boot/dts/nxp/imx/imx7d-meerkat96.dts b/arch/arm/boot/dts/nxp/imx/imx7d-meerkat96.dts index dd8003bd1fc09c..f0fda15f30204a 100644 --- a/arch/arm/boot/dts/nxp/imx/imx7d-meerkat96.dts +++ b/arch/arm/boot/dts/nxp/imx/imx7d-meerkat96.dts @@ -212,7 +212,7 @@ keep-power-in-suspend; wakeup-source; vmmc-supply = <®_wlreg_on>; - vqmmc-supply =<®_3p3v>; + vqmmc-supply = <®_3p3v>; status = "okay"; brcmf: wifi@1 { diff --git a/arch/arm/boot/dts/nxp/imx/imx7d-pico.dtsi b/arch/arm/boot/dts/nxp/imx/imx7d-pico.dtsi index c5eefe89cd9964..8d5037ac03c7d1 100644 --- a/arch/arm/boot/dts/nxp/imx/imx7d-pico.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx7d-pico.dtsi @@ -108,6 +108,14 @@ assigned-clock-rates = <0>, <32768>; }; +&cpu0 { + cpu-supply = <&sw1a_reg>; +}; + +&cpu1 { + cpu-supply = <&sw1a_reg>; +}; + &ecspi3 { cs-gpios = <&gpio4 11 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/nxp/imx/imx7d-smegw01.dts b/arch/arm/boot/dts/nxp/imx/imx7d-smegw01.dts index 85b97b5f64e728..7ed27c7ad726fa 100644 --- a/arch/arm/boot/dts/nxp/imx/imx7d-smegw01.dts +++ b/arch/arm/boot/dts/nxp/imx/imx7d-smegw01.dts @@ -149,7 +149,7 @@ &i2c2 { pinctrl-names = "default"; - pinctrl-0 =<&pinctrl_i2c2>; + pinctrl-0 = <&pinctrl_i2c2>; clock-frequency = <100000>; status = "okay"; diff --git a/arch/arm/boot/dts/nxp/imx/imx7d.dtsi b/arch/arm/boot/dts/nxp/imx/imx7d.dtsi index 4b94b8afb55d91..0484e349e064e4 100644 --- a/arch/arm/boot/dts/nxp/imx/imx7d.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx7d.dtsi @@ -217,9 +217,6 @@ }; &ca_funnel_in_ports { - #address-cells = <1>; - #size-cells = <0>; - port@1 { reg = <1>; ca_funnel_in_port1: endpoint { diff --git a/arch/arm/boot/dts/nxp/imx/imx7s.dtsi b/arch/arm/boot/dts/nxp/imx/imx7s.dtsi index 5387da8a2a0a37..ebf7befcc11e3e 100644 --- a/arch/arm/boot/dts/nxp/imx/imx7s.dtsi +++ b/arch/arm/boot/dts/nxp/imx/imx7s.dtsi @@ -183,6 +183,15 @@ interrupt-parent = <&gpc>; ranges; + ocram: sram@900000 { + compatible = "mmio-sram"; + reg = <0x00900000 0x20000>; + ranges = <0 0x00900000 0x20000>; + #address-cells = <1>; + #size-cells = <1>; + clocks = <&clks IMX7D_OCRAM_CLK>; + }; + funnel@30041000 { compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; reg = <0x30041000 0x1000>; @@ -190,7 +199,11 @@ clock-names = "apb_pclk"; ca_funnel_in_ports: in-ports { - port { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; ca_funnel_in_port0: endpoint { remote-endpoint = <&etm0_out_port>; }; @@ -605,6 +618,7 @@ nvmem-cells = <&tempmon_calib>, <&fuse_grade>; nvmem-cell-names = "calib", "temp_grade"; clocks = <&clks IMX7D_PLL_SYS_MAIN_CLK>; + #thermal-sensor-cells = <0>; }; }; @@ -720,6 +734,8 @@ clocks = <&clks IMX7D_ECSPI4_ROOT_CLK>, <&clks IMX7D_ECSPI4_ROOT_CLK>; clock-names = "ipg", "per"; + dma-names = "rx", "tx"; + dmas = <&sdma 6 7 1>, <&sdma 7 7 2>; status = "disabled"; }; @@ -811,13 +827,23 @@ }; lcdif: lcdif@30730000 { - compatible = "fsl,imx7d-lcdif", "fsl,imx28-lcdif"; + compatible = "fsl,imx7d-lcdif", "fsl,imx6sx-lcdif"; reg = <0x30730000 0x10000>; interrupts = ; clocks = <&clks IMX7D_LCDIF_PIXEL_ROOT_CLK>, <&clks IMX7D_LCDIF_PIXEL_ROOT_CLK>; clock-names = "pix", "axi"; status = "disabled"; + + port { + #address-cells = <1>; + #size-cells = <0>; + + lcdif_out_mipi_dsi: endpoint@0 { + reg = <0>; + remote-endpoint = <&mipi_dsi_in_lcdif>; + }; + }; }; mipi_csi: mipi-csi@30750000 { @@ -850,6 +876,42 @@ }; }; }; + + mipi_dsi: dsi@30760000 { + compatible = "fsl,imx7d-mipi-dsim", "fsl,imx8mm-mipi-dsim"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x30760000 0x400>; + clocks = <&clks IMX7D_MIPI_DSI_ROOT_CLK>, + <&clks IMX7D_MIPI_DPHY_ROOT_CLK>; + clock-names = "bus_clk", "sclk_mipi"; + assigned-clocks = <&clks IMX7D_MIPI_DSI_ROOT_SRC>, + <&clks IMX7D_PLL_SYS_PFD5_CLK>; + assigned-clock-parents = <&clks IMX7D_PLL_SYS_PFD5_CLK>; + assigned-clock-rates = <0>, <333000000>; + power-domains = <&pgc_mipi_phy>; + interrupts = ; + samsung,burst-clock-frequency = <891000000>; + samsung,esc-clock-frequency = <20000000>; + samsung,pll-clock-frequency = <24000000>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + mipi_dsi_in_lcdif: endpoint@0 { + reg = <0>; + remote-endpoint = <&lcdif_out_mipi_dsi>; + }; + }; + }; + }; }; aips3: bus@30800000 { @@ -875,6 +937,8 @@ clocks = <&clks IMX7D_ECSPI1_ROOT_CLK>, <&clks IMX7D_ECSPI1_ROOT_CLK>; clock-names = "ipg", "per"; + dma-names = "rx", "tx"; + dmas = <&sdma 0 7 1>, <&sdma 1 7 2>; status = "disabled"; }; @@ -887,6 +951,8 @@ clocks = <&clks IMX7D_ECSPI2_ROOT_CLK>, <&clks IMX7D_ECSPI2_ROOT_CLK>; clock-names = "ipg", "per"; + dma-names = "rx", "tx"; + dmas = <&sdma 2 7 1>, <&sdma 3 7 2>; status = "disabled"; }; @@ -899,6 +965,8 @@ clocks = <&clks IMX7D_ECSPI3_ROOT_CLK>, <&clks IMX7D_ECSPI3_ROOT_CLK>; clock-names = "ipg", "per"; + dma-names = "rx", "tx"; + dmas = <&sdma 4 7 1>, <&sdma 5 7 2>; status = "disabled"; }; @@ -1275,7 +1343,7 @@ gpmi: nand-controller@33002000 { compatible = "fsl,imx7d-gpmi-nand"; #address-cells = <1>; - #size-cells = <1>; + #size-cells = <0>; reg = <0x33002000 0x2000>, <0x33004000 0x4000>; reg-names = "gpmi-nand", "bch"; interrupts = ; diff --git a/arch/arm/boot/dts/nxp/imx/mba6ulx.dtsi b/arch/arm/boot/dts/nxp/imx/mba6ulx.dtsi index 5a8b867d7d7931..e78d0a7d8cd28c 100644 --- a/arch/arm/boot/dts/nxp/imx/mba6ulx.dtsi +++ b/arch/arm/boot/dts/nxp/imx/mba6ulx.dtsi @@ -467,7 +467,7 @@ pinctrl_pwm2: pwm2grp { fsl,pins = < - /* 100 k PD, DSE 120 OHM, SPPEED LO */ + /* 100 k PD, DSE 120 OHM, SPEED LO */ MX6UL_PAD_GPIO1_IO09__PWM2_OUT 0x00003050 >; }; diff --git a/arch/arm/boot/dts/nxp/lpc/lpc18xx.dtsi b/arch/arm/boot/dts/nxp/lpc/lpc18xx.dtsi index 9cf09c183b85e8..6dd73290f0c639 100644 --- a/arch/arm/boot/dts/nxp/lpc/lpc18xx.dtsi +++ b/arch/arm/boot/dts/nxp/lpc/lpc18xx.dtsi @@ -74,7 +74,7 @@ sct_pwm: pwm@40000000 { compatible = "nxp,lpc1850-sct-pwm"; reg = <0x40000000 0x1000>; - clocks =<&ccu1 CLK_CPU_SCT>; + clocks = <&ccu1 CLK_CPU_SCT>; clock-names = "pwm"; resets = <&rgu 37>; #pwm-cells = <3>; diff --git a/arch/arm/boot/dts/nxp/ls/ls1021a.dtsi b/arch/arm/boot/dts/nxp/ls/ls1021a.dtsi index 49c78c84cd5dfd..d471cc5efa949b 100644 --- a/arch/arm/boot/dts/nxp/ls/ls1021a.dtsi +++ b/arch/arm/boot/dts/nxp/ls/ls1021a.dtsi @@ -112,7 +112,7 @@ compatible = "fsl,ls1021a-msi"; reg = <0x0 0x1570e00 0x0 0x8>; msi-controller; - interrupts = ; + interrupts = ; }; msi2: msi-controller@1570e08 { diff --git a/arch/arm/boot/dts/nxp/mxs/imx23-sansa.dts b/arch/arm/boot/dts/nxp/mxs/imx23-sansa.dts index 636cf09a2b375f..b23e7ada9c804f 100644 --- a/arch/arm/boot/dts/nxp/mxs/imx23-sansa.dts +++ b/arch/arm/boot/dts/nxp/mxs/imx23-sansa.dts @@ -175,10 +175,8 @@ #address-cells = <1>; #size-cells = <0>; compatible = "i2c-gpio"; - gpios = < - &gpio1 24 0 /* SDA */ - &gpio1 22 0 /* SCL */ - >; + sda-gpios = <&gpio1 24 0>; + scl-gpios = <&gpio1 22 0>; i2c-gpio,delay-us = <2>; /* ~100 kHz */ }; @@ -186,10 +184,8 @@ #address-cells = <1>; #size-cells = <0>; compatible = "i2c-gpio"; - gpios = < - &gpio0 31 0 /* SDA */ - &gpio0 30 0 /* SCL */ - >; + sda-gpios = <&gpio0 31 0>; + scl-gpios = <&gpio0 30 0>; i2c-gpio,delay-us = <2>; /* ~100 kHz */ touch: touch@20 { diff --git a/arch/arm/boot/dts/nxp/mxs/imx23.dtsi b/arch/arm/boot/dts/nxp/mxs/imx23.dtsi index fdf18b7cb2f6a2..0309592af1e1eb 100644 --- a/arch/arm/boot/dts/nxp/mxs/imx23.dtsi +++ b/arch/arm/boot/dts/nxp/mxs/imx23.dtsi @@ -110,7 +110,7 @@ reg = <0x80018000 0x2000>; gpio0: gpio@0 { - compatible = "fsl,imx23-gpio", "fsl,mxs-gpio"; + compatible = "fsl,imx23-gpio"; reg = <0>; interrupts = <16>; gpio-controller; @@ -120,7 +120,7 @@ }; gpio1: gpio@1 { - compatible = "fsl,imx23-gpio", "fsl,mxs-gpio"; + compatible = "fsl,imx23-gpio"; reg = <1>; interrupts = <17>; gpio-controller; @@ -130,7 +130,7 @@ }; gpio2: gpio@2 { - compatible = "fsl,imx23-gpio", "fsl,mxs-gpio"; + compatible = "fsl,imx23-gpio"; reg = <2>; interrupts = <18>; gpio-controller; @@ -412,7 +412,7 @@ status = "disabled"; }; - dma_apbx: dma-apbx@80024000 { + dma_apbx: dma-controller@80024000 { compatible = "fsl,imx23-dma-apbx"; reg = <0x80024000 0x2000>; interrupts = <7>, <5>, <9>, <26>, @@ -484,7 +484,7 @@ ranges; clks: clkctrl@80040000 { - compatible = "fsl,imx23-clkctrl", "fsl,clkctrl"; + compatible = "fsl,imx23-clkctrl"; reg = <0x80040000 0x2000>; #clock-cells = <1>; }; diff --git a/arch/arm/boot/dts/nxp/mxs/imx28-lwe.dtsi b/arch/arm/boot/dts/nxp/mxs/imx28-lwe.dtsi index bb971e660db8e3..69fcb0dde94026 100644 --- a/arch/arm/boot/dts/nxp/mxs/imx28-lwe.dtsi +++ b/arch/arm/boot/dts/nxp/mxs/imx28-lwe.dtsi @@ -18,6 +18,7 @@ memory@40000000 { reg = <0x40000000 0x08000000>; + device_type = "memory"; }; reg_3v3: regulator-reg-3v3 { diff --git a/arch/arm/boot/dts/nxp/mxs/imx28-tx28.dts b/arch/arm/boot/dts/nxp/mxs/imx28-tx28.dts index 153e4017951d88..5485fe118dc48b 100644 --- a/arch/arm/boot/dts/nxp/mxs/imx28-tx28.dts +++ b/arch/arm/boot/dts/nxp/mxs/imx28-tx28.dts @@ -260,6 +260,7 @@ sgtl5000: sgtl5000@a { compatible = "fsl,sgtl5000"; reg = <0x0a>; + #sound-dai-cells = <0>; VDDA-supply = <®_2p5v>; VDDIO-supply = <®_3p3v>; clocks = <&mclk>; diff --git a/arch/arm/boot/dts/nxp/mxs/imx28.dtsi b/arch/arm/boot/dts/nxp/mxs/imx28.dtsi index 6932d23fb29dec..4817fba2d938b9 100644 --- a/arch/arm/boot/dts/nxp/mxs/imx28.dtsi +++ b/arch/arm/boot/dts/nxp/mxs/imx28.dtsi @@ -164,7 +164,7 @@ reg = <0x80018000 0x2000>; gpio0: gpio@0 { - compatible = "fsl,imx28-gpio", "fsl,mxs-gpio"; + compatible = "fsl,imx28-gpio"; reg = <0>; interrupts = <127>; gpio-controller; @@ -174,7 +174,7 @@ }; gpio1: gpio@1 { - compatible = "fsl,imx28-gpio", "fsl,mxs-gpio"; + compatible = "fsl,imx28-gpio"; reg = <1>; interrupts = <126>; gpio-controller; @@ -184,7 +184,7 @@ }; gpio2: gpio@2 { - compatible = "fsl,imx28-gpio", "fsl,mxs-gpio"; + compatible = "fsl,imx28-gpio"; reg = <2>; interrupts = <125>; gpio-controller; @@ -194,7 +194,7 @@ }; gpio3: gpio@3 { - compatible = "fsl,imx28-gpio", "fsl,mxs-gpio"; + compatible = "fsl,imx28-gpio"; reg = <3>; interrupts = <124>; gpio-controller; @@ -204,7 +204,7 @@ }; gpio4: gpio@4 { - compatible = "fsl,imx28-gpio", "fsl,mxs-gpio"; + compatible = "fsl,imx28-gpio"; reg = <4>; interrupts = <123>; gpio-controller; @@ -990,7 +990,7 @@ status = "disabled"; }; - dma_apbx: dma-apbx@80024000 { + dma_apbx: dma-controller@80024000 { compatible = "fsl,imx28-dma-apbx"; reg = <0x80024000 0x2000>; interrupts = <78>, <79>, <66>, <0>, @@ -1100,7 +1100,7 @@ ranges; clks: clkctrl@80040000 { - compatible = "fsl,imx28-clkctrl", "fsl,clkctrl"; + compatible = "fsl,imx28-clkctrl"; reg = <0x80040000 0x2000>; #clock-cells = <1>; }; diff --git a/arch/arm/boot/dts/nxp/vf/vf-colibri-eval-v3.dtsi b/arch/arm/boot/dts/nxp/vf/vf-colibri-eval-v3.dtsi index 14c411f146f50f..5a19da9313ae6c 100644 --- a/arch/arm/boot/dts/nxp/vf/vf-colibri-eval-v3.dtsi +++ b/arch/arm/boot/dts/nxp/vf/vf-colibri-eval-v3.dtsi @@ -55,7 +55,7 @@ brightness-levels = <0 4 8 16 32 64 128 255>; default-brightness-level = <6>; power-supply = <®_3v3>; - status = "okay"; + status = "okay"; }; &dcu0 { diff --git a/arch/arm/boot/dts/nxp/vf/vf610-bk4.dts b/arch/arm/boot/dts/nxp/vf/vf610-bk4.dts index e4f691d601cc2e..722182f5fd1722 100644 --- a/arch/arm/boot/dts/nxp/vf/vf610-bk4.dts +++ b/arch/arm/boot/dts/nxp/vf/vf610-bk4.dts @@ -68,7 +68,7 @@ #address-cells = <1>; #size-cells = <0>; /* PTD12 ->RPIO[91] */ - sck-gpios = <&gpio2 27 GPIO_ACTIVE_LOW>; + sck-gpios = <&gpio2 27 GPIO_ACTIVE_LOW>; /* PTD10 ->RPIO[89] */ miso-gpios = <&gpio2 25 GPIO_ACTIVE_HIGH>; num-chipselects = <0>; @@ -79,7 +79,7 @@ gpio-controller; #gpio-cells = <2>; /* PTB18 -> RGPIO[40] */ - load-gpios = <&gpio1 8 GPIO_ACTIVE_LOW>; + load-gpios = <&gpio1 8 GPIO_ACTIVE_LOW>; spi-max-frequency = <100000>; }; }; diff --git a/arch/arm/boot/dts/nxp/vf/vf610-zii-cfu1.dts b/arch/arm/boot/dts/nxp/vf/vf610-zii-cfu1.dts index 1a19aec8957b74..7e72f860c3c516 100644 --- a/arch/arm/boot/dts/nxp/vf/vf610-zii-cfu1.dts +++ b/arch/arm/boot/dts/nxp/vf/vf610-zii-cfu1.dts @@ -162,7 +162,7 @@ suppress-preamble; status = "okay"; - switch0: switch0@0 { + switch0: ethernet-switch@0 { compatible = "marvell,mv88e6085"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_switch>; @@ -173,26 +173,26 @@ interrupt-controller; #interrupt-cells = <2>; - ports { + ethernet-ports { #address-cells = <1>; #size-cells = <0>; - port@0 { + ethernet-port@0 { reg = <0>; label = "eth_cu_1000_1"; }; - port@1 { + ethernet-port@1 { reg = <1>; label = "eth_cu_1000_2"; }; - port@2 { + ethernet-port@2 { reg = <2>; label = "eth_cu_1000_3"; }; - port@5 { + ethernet-port@5 { reg = <5>; label = "eth_fc_1000_1"; phy-mode = "1000base-x"; @@ -200,7 +200,7 @@ sfp = <&sff>; }; - port@6 { + ethernet-port@6 { reg = <6>; phy-mode = "rmii"; ethernet = <&fec1>; diff --git a/arch/arm/boot/dts/nxp/vf/vf610-zii-dev-rev-b.dts b/arch/arm/boot/dts/nxp/vf/vf610-zii-dev-rev-b.dts index 16b4e06c4efad3..b0ed68af054670 100644 --- a/arch/arm/boot/dts/nxp/vf/vf610-zii-dev-rev-b.dts +++ b/arch/arm/boot/dts/nxp/vf/vf610-zii-dev-rev-b.dts @@ -294,11 +294,11 @@ pinctrl-names = "default"; #address-cells = <1>; #size-cells = <0>; - sck-gpios = <&gpio1 12 GPIO_ACTIVE_HIGH>; + sck-gpios = <&gpio1 12 GPIO_ACTIVE_HIGH>; mosi-gpios = <&gpio1 11 GPIO_ACTIVE_HIGH>; miso-gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; - cs-gpios = <&gpio1 9 GPIO_ACTIVE_LOW - &gpio1 8 GPIO_ACTIVE_HIGH>; + cs-gpios = <&gpio1 9 GPIO_ACTIVE_LOW + &gpio1 8 GPIO_ACTIVE_HIGH>; num-chipselects = <2>; flash@0 { diff --git a/arch/arm/boot/dts/nxp/vf/vf610-zii-scu4-aib.dts b/arch/arm/boot/dts/nxp/vf/vf610-zii-scu4-aib.dts index df1335492a1998..77492eeea4509b 100644 --- a/arch/arm/boot/dts/nxp/vf/vf610-zii-scu4-aib.dts +++ b/arch/arm/boot/dts/nxp/vf/vf610-zii-scu4-aib.dts @@ -47,17 +47,17 @@ #address-cells = <1>; #size-cells = <0>; - switch0: switch0@0 { + switch0: ethernet-switch@0 { compatible = "marvell,mv88e6190"; reg = <0>; dsa,member = <0 0>; eeprom-length = <65536>; - ports { + ethernet-ports { #address-cells = <1>; #size-cells = <0>; - port@0 { + ethernet-port@0 { reg = <0>; phy-mode = "rmii"; ethernet = <&fec1>; @@ -68,37 +68,37 @@ }; }; - port@1 { + ethernet-port@1 { reg = <1>; label = "aib2main_1"; }; - port@2 { + ethernet-port@2 { reg = <2>; label = "aib2main_2"; }; - port@3 { + ethernet-port@3 { reg = <3>; label = "eth_cu_1000_5"; }; - port@4 { + ethernet-port@4 { reg = <4>; label = "eth_cu_1000_6"; }; - port@5 { + ethernet-port@5 { reg = <5>; label = "eth_cu_1000_4"; }; - port@6 { + ethernet-port@6 { reg = <6>; label = "eth_cu_1000_7"; }; - port@7 { + ethernet-port@7 { reg = <7>; label = "modem_pic"; @@ -108,7 +108,7 @@ }; }; - switch0port10: port@10 { + switch0port10: ethernet-port@10 { reg = <10>; label = "dsa"; phy-mode = "xgmii"; @@ -130,32 +130,32 @@ #address-cells = <1>; #size-cells = <0>; - switch1: switch1@0 { + switch1: ethernet-switch@0 { compatible = "marvell,mv88e6190"; reg = <0>; dsa,member = <0 1>; eeprom-length = <65536>; - ports { + ethernet-ports { #address-cells = <1>; #size-cells = <0>; - port@1 { + ethernet-port@1 { reg = <1>; label = "eth_cu_1000_3"; }; - port@2 { + ethernet-port@2 { reg = <2>; label = "eth_cu_100_2"; }; - port@3 { + ethernet-port@3 { reg = <3>; label = "eth_cu_100_3"; }; - switch1port9: port@9 { + switch1port9: ethernet-port@9 { reg = <9>; label = "dsa"; phy-mode = "xgmii"; @@ -168,7 +168,7 @@ }; }; - switch1port10: port@10 { + switch1port10: ethernet-port@10 { reg = <10>; label = "dsa"; phy-mode = "xgmii"; @@ -188,17 +188,17 @@ #address-cells = <1>; #size-cells = <0>; - switch2: switch2@0 { + switch2: ethernet-switch@0 { compatible = "marvell,mv88e6190"; reg = <0>; dsa,member = <0 2>; eeprom-length = <65536>; - ports { + ethernet-ports { #address-cells = <1>; #size-cells = <0>; - port@2 { + ethernet-port@2 { reg = <2>; label = "eth_fc_1000_2"; phy-mode = "1000base-x"; @@ -206,7 +206,7 @@ sfp = <&sff1>; }; - port@3 { + ethernet-port@3 { reg = <3>; label = "eth_fc_1000_3"; phy-mode = "1000base-x"; @@ -214,7 +214,7 @@ sfp = <&sff2>; }; - port@4 { + ethernet-port@4 { reg = <4>; label = "eth_fc_1000_4"; phy-mode = "1000base-x"; @@ -222,7 +222,7 @@ sfp = <&sff3>; }; - port@5 { + ethernet-port@5 { reg = <5>; label = "eth_fc_1000_5"; phy-mode = "1000base-x"; @@ -230,7 +230,7 @@ sfp = <&sff4>; }; - port@6 { + ethernet-port@6 { reg = <6>; label = "eth_fc_1000_6"; phy-mode = "1000base-x"; @@ -238,7 +238,7 @@ sfp = <&sff5>; }; - port@7 { + ethernet-port@7 { reg = <7>; label = "eth_fc_1000_7"; phy-mode = "1000base-x"; @@ -246,7 +246,7 @@ sfp = <&sff6>; }; - port@9 { + ethernet-port@9 { reg = <9>; label = "eth_fc_1000_1"; phy-mode = "1000base-x"; @@ -254,7 +254,7 @@ sfp = <&sff0>; }; - switch2port10: port@10 { + switch2port10: ethernet-port@10 { reg = <10>; label = "dsa"; phy-mode = "2500base-x"; @@ -276,17 +276,17 @@ #address-cells = <1>; #size-cells = <0>; - switch3: switch3@0 { + switch3: ethernet-switch@0 { compatible = "marvell,mv88e6190"; reg = <0>; dsa,member = <0 3>; eeprom-length = <65536>; - ports { + ethernet-ports { #address-cells = <1>; #size-cells = <0>; - port@2 { + ethernet-port@2 { reg = <2>; label = "eth_fc_1000_8"; phy-mode = "1000base-x"; @@ -294,7 +294,7 @@ sfp = <&sff7>; }; - port@3 { + ethernet-port@3 { reg = <3>; label = "eth_fc_1000_9"; phy-mode = "1000base-x"; @@ -302,7 +302,7 @@ sfp = <&sff8>; }; - port@4 { + ethernet-port@4 { reg = <4>; label = "eth_fc_1000_10"; phy-mode = "1000base-x"; @@ -310,7 +310,7 @@ sfp = <&sff9>; }; - switch3port9: port@9 { + switch3port9: ethernet-port@9 { reg = <9>; label = "dsa"; phy-mode = "2500base-x"; @@ -322,7 +322,7 @@ }; }; - switch3port10: port@10 { + switch3port10: ethernet-port@10 { reg = <10>; label = "dsa"; phy-mode = "xgmii"; diff --git a/arch/arm/boot/dts/nxp/vf/vf610-zii-spb4.dts b/arch/arm/boot/dts/nxp/vf/vf610-zii-spb4.dts index 1461804ecaea3b..2a490464660c08 100644 --- a/arch/arm/boot/dts/nxp/vf/vf610-zii-spb4.dts +++ b/arch/arm/boot/dts/nxp/vf/vf610-zii-spb4.dts @@ -123,7 +123,7 @@ suppress-preamble; status = "okay"; - switch0: switch0@0 { + switch0: ethernet-switch@0 { compatible = "marvell,mv88e6190"; pinctrl-0 = <&pinctrl_gpio_switch0>; pinctrl-names = "default"; @@ -134,11 +134,11 @@ interrupt-controller; #interrupt-cells = <2>; - ports { + ethernet-ports { #address-cells = <1>; #size-cells = <0>; - port@0 { + ethernet-port@0 { reg = <0>; phy-mode = "rmii"; ethernet = <&fec1>; @@ -149,32 +149,32 @@ }; }; - port@1 { + ethernet-port@1 { reg = <1>; label = "eth_cu_1000_1"; }; - port@2 { + ethernet-port@2 { reg = <2>; label = "eth_cu_1000_2"; }; - port@3 { + ethernet-port@3 { reg = <3>; label = "eth_cu_1000_3"; }; - port@4 { + ethernet-port@4 { reg = <4>; label = "eth_cu_1000_4"; }; - port@5 { + ethernet-port@5 { reg = <5>; label = "eth_cu_1000_5"; }; - port@6 { + ethernet-port@6 { reg = <6>; label = "eth_cu_1000_6"; }; diff --git a/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-dtu.dts b/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-dtu.dts index 463c2452b9b7f9..078d8699e16d70 100644 --- a/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-dtu.dts +++ b/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-dtu.dts @@ -112,7 +112,7 @@ suppress-preamble; status = "okay"; - switch0: switch0@0 { + switch0: ethernet-switch@0 { compatible = "marvell,mv88e6190"; pinctrl-0 = <&pinctrl_gpio_switch0>; pinctrl-names = "default"; @@ -123,11 +123,11 @@ interrupt-controller; #interrupt-cells = <2>; - ports { + ethernet-ports { #address-cells = <1>; #size-cells = <0>; - port@0 { + ethernet-port@0 { reg = <0>; phy-mode = "rmii"; ethernet = <&fec1>; @@ -138,27 +138,27 @@ }; }; - port@1 { + ethernet-port@1 { reg = <1>; label = "eth_cu_100_3"; }; - port@5 { + ethernet-port@5 { reg = <5>; label = "eth_cu_1000_4"; }; - port@6 { + ethernet-port@6 { reg = <6>; label = "eth_cu_1000_5"; }; - port@8 { + ethernet-port@8 { reg = <8>; label = "eth_cu_1000_1"; }; - port@9 { + ethernet-port@9 { reg = <9>; label = "eth_cu_1000_2"; phy-handle = <&phy9>; @@ -167,12 +167,12 @@ }; }; - mdio1 { + mdio-external { compatible = "marvell,mv88e6xxx-mdio-external"; #address-cells = <1>; #size-cells = <0>; - phy9: phy9@0 { + phy9: ethernet-phy@0 { compatible = "ethernet-phy-ieee802.3-c45"; pinctrl-0 = <&pinctrl_gpio_phy9>; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-spu3.dts b/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-spu3.dts index f5ae0d5de31517..22c8f44390a96d 100644 --- a/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-spu3.dts +++ b/arch/arm/boot/dts/nxp/vf/vf610-zii-ssmb-spu3.dts @@ -137,7 +137,7 @@ suppress-preamble; status = "okay"; - switch0: switch0@0 { + switch0: ethernet-switch@0 { compatible = "marvell,mv88e6190"; pinctrl-0 = <&pinctrl_gpio_switch0>; pinctrl-names = "default"; @@ -148,11 +148,11 @@ interrupt-controller; #interrupt-cells = <2>; - ports { + ethernet-ports { #address-cells = <1>; #size-cells = <0>; - port@0 { + ethernet-port@0 { reg = <0>; phy-mode = "rmii"; ethernet = <&fec1>; @@ -163,32 +163,32 @@ }; }; - port@1 { + ethernet-port@1 { reg = <1>; label = "eth_cu_1000_1"; }; - port@2 { + ethernet-port@2 { reg = <2>; label = "eth_cu_1000_2"; }; - port@3 { + ethernet-port@3 { reg = <3>; label = "eth_cu_1000_3"; }; - port@4 { + ethernet-port@4 { reg = <4>; label = "eth_cu_1000_4"; }; - port@5 { + ethernet-port@5 { reg = <5>; label = "eth_cu_1000_5"; }; - port@6 { + ethernet-port@6 { reg = <6>; label = "eth_cu_1000_6"; }; diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile index 3dfb1c8cefb86e..9cc1e14e6cd09c 100644 --- a/arch/arm/boot/dts/qcom/Makefile +++ b/arch/arm/boot/dts/qcom/Makefile @@ -23,12 +23,19 @@ dtb-$(CONFIG_ARCH_QCOM) += \ qcom-ipq4019-ap.dk07.1-c2.dtb \ qcom-ipq8064-ap148.dtb \ qcom-ipq8064-rb3011.dtb \ + qcom-msm8226-microsoft-dempsey.dtb \ + qcom-msm8226-microsoft-makepeace.dtb \ + qcom-msm8226-microsoft-moneypenny.dtb \ qcom-msm8226-samsung-s3ve3g.dtb \ qcom-msm8660-surf.dtb \ qcom-msm8916-samsung-e5.dtb \ qcom-msm8916-samsung-e7.dtb \ qcom-msm8916-samsung-grandmax.dtb \ qcom-msm8916-samsung-serranove.dtb \ + qcom-msm8926-htc-memul.dtb \ + qcom-msm8926-microsoft-superman-lte.dtb \ + qcom-msm8926-microsoft-tesla.dtb \ + qcom-msm8926-motorola-peregrine.dtb \ qcom-msm8960-cdp.dtb \ qcom-msm8960-samsung-expressatt.dtb \ qcom-msm8974-lge-nexus5-hammerhead.dtb \ diff --git a/arch/arm/boot/dts/qcom/pm8018.dtsi b/arch/arm/boot/dts/qcom/pm8018.dtsi new file mode 100644 index 00000000000000..22f3c7bac52236 --- /dev/null +++ b/arch/arm/boot/dts/qcom/pm8018.dtsi @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Device Tree Source for Qualcomm PM8018 + * + * Copyright (C) 2016 BayLibre, SAS. + * Author : Neil Armstrong + */ + +&ssbi { + pm8018: pmic { + compatible = "qcom,pm8018", "qcom,pm8921"; + #interrupt-cells = <2>; + interrupt-controller; + #address-cells = <1>; + #size-cells = <0>; + + pwrkey@1c { + compatible = "qcom,pm8018-pwrkey", + "qcom,pm8921-pwrkey"; + reg = <0x1c>; + interrupts-extended = <&pm8018 50 IRQ_TYPE_EDGE_RISING>, + <&pm8018 51 IRQ_TYPE_EDGE_RISING>; + debounce = <15625>; + pull-up; + }; + + pm8018_mpps: mpps@50 { + compatible = "qcom,pm8018-mpp", "qcom,ssbi-mpp"; + reg = <0x50>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pm8018_mpps 0 0 6>; + }; + + rtc@11d { + compatible = "qcom,pm8018-rtc", "qcom,pm8921-rtc"; + reg = <0x11d>; + interrupts-extended = <&pm8018 39 IRQ_TYPE_EDGE_RISING>; + allow-set-time; + }; + + pm8018_gpio: gpio@150 { + compatible = "qcom,pm8058-gpio", + "qcom,ssbi-gpio"; + reg = <0x150>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + gpio-ranges = <&pm8018_gpio 0 0 6>; + #gpio-cells = <2>; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/pm8058.dtsi b/arch/arm/boot/dts/qcom/pm8058.dtsi new file mode 100644 index 00000000000000..984b7977798460 --- /dev/null +++ b/arch/arm/boot/dts/qcom/pm8058.dtsi @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: GPL-2.0 + +&ssbi { + pm8058: pmic { + compatible = "qcom,pm8058"; + #interrupt-cells = <2>; + interrupt-controller; + #address-cells = <1>; + #size-cells = <0>; + + pwrkey@1c { + compatible = "qcom,pm8058-pwrkey"; + reg = <0x1c>; + interrupts-extended = <&pm8058 50 IRQ_TYPE_EDGE_RISING>, + <&pm8058 51 IRQ_TYPE_EDGE_RISING>; + debounce = <15625>; + pull-up; + }; + + pm8058_led48: led@48 { + compatible = "qcom,pm8058-keypad-led"; + reg = <0x48>; + status = "disabled"; + }; + + vibrator@4a { + compatible = "qcom,pm8058-vib"; + reg = <0x4a>; + }; + + pm8058_mpps: mpps@50 { + compatible = "qcom,pm8058-mpp", + "qcom,ssbi-mpp"; + reg = <0x50>; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pm8058_mpps 0 0 12>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + pm8058_led131: led@131 { + compatible = "qcom,pm8058-led"; + reg = <0x131>; + status = "disabled"; + }; + + pm8058_led132: led@132 { + compatible = "qcom,pm8058-led"; + reg = <0x132>; + status = "disabled"; + }; + + pm8058_led133: led@133 { + compatible = "qcom,pm8058-led"; + reg = <0x133>; + status = "disabled"; + }; + + pm8058_keypad: keypad@148 { + compatible = "qcom,pm8058-keypad"; + reg = <0x148>; + interrupts-extended = <&pm8058 74 IRQ_TYPE_EDGE_RISING>, + <&pm8058 75 IRQ_TYPE_EDGE_RISING>; + debounce = <15>; + scan-delay = <32>; + row-hold = <91500>; + }; + + pm8058_gpio: gpio@150 { + compatible = "qcom,pm8058-gpio", + "qcom,ssbi-gpio"; + reg = <0x150>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + gpio-ranges = <&pm8058_gpio 0 0 44>; + #gpio-cells = <2>; + }; + + pm8058_xoadc: xoadc@197 { + compatible = "qcom,pm8058-adc"; + reg = <0x197>; + interrupts-extended = <&pm8058 76 IRQ_TYPE_EDGE_RISING>; + #address-cells = <2>; + #size-cells = <0>; + #io-channel-cells = <2>; + + vcoin: adc-channel@0 { + reg = <0x00 0x00>; + }; + + vbat: adc-channel@1 { + reg = <0x00 0x01>; + }; + + dcin: adc-channel@2 { + reg = <0x00 0x02>; + }; + + ichg: adc-channel@3 { + reg = <0x00 0x03>; + }; + + vph_pwr: adc-channel@4 { + reg = <0x00 0x04>; + }; + + usb_vbus: adc-channel@a { + reg = <0x00 0x0a>; + }; + + die_temp: adc-channel@b { + reg = <0x00 0x0b>; + }; + + ref_625mv: adc-channel@c { + reg = <0x00 0x0c>; + }; + + ref_1250mv: adc-channel@d { + reg = <0x00 0x0d>; + }; + + ref_325mv: adc-channel@e { + reg = <0x00 0x0e>; + }; + + ref_muxoff: adc-channel@f { + reg = <0x00 0x0f>; + }; + }; + + rtc@1e8 { + compatible = "qcom,pm8058-rtc"; + reg = <0x1e8>; + interrupts-extended = <&pm8058 39 IRQ_TYPE_EDGE_RISING>; + allow-set-time; + }; + }; +}; + +/ { + /* + * These channels from the ADC are simply hardware monitors. + * That is why the ADC is referred to as "HKADC" - HouseKeeping + * ADC. + */ + iio-hwmon { + compatible = "iio-hwmon"; + io-channels = <&pm8058_xoadc 0x00 0x01>, /* Battery */ + <&pm8058_xoadc 0x00 0x02>, /* DC in (charger) */ + <&pm8058_xoadc 0x00 0x04>, /* VPH the main system voltage */ + <&pm8058_xoadc 0x00 0x0b>, /* Die temperature */ + <&pm8058_xoadc 0x00 0x0c>, /* Reference voltage 1.25V */ + <&pm8058_xoadc 0x00 0x0d>, /* Reference voltage 0.625V */ + <&pm8058_xoadc 0x00 0x0e>; /* Reference voltage 0.325V */ + }; +}; diff --git a/arch/arm/boot/dts/qcom/pm8226.dtsi b/arch/arm/boot/dts/qcom/pm8226.dtsi new file mode 100644 index 00000000000000..2fd4f135ed84c8 --- /dev/null +++ b/arch/arm/boot/dts/qcom/pm8226.dtsi @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: BSD-3-Clause +#include +#include +#include +#include + +/ { + thermal-zones { + pm8226-thermal { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-sensors = <&pm8226_temp>; + + trips { + trip0 { + temperature = <105000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip1 { + temperature = <125000>; + hysteresis = <2000>; + type = "hot"; + }; + + crit { + temperature = <145000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + }; + }; +}; + +&spmi_bus { + pm8226_0: pm8226@0 { + compatible = "qcom,pm8226", "qcom,spmi-pmic"; + reg = <0x0 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + pon@800 { + compatible = "qcom,pm8916-pon"; + reg = <0x800>; + + pwrkey { + compatible = "qcom,pm8941-pwrkey"; + interrupts = <0x0 0x8 0 IRQ_TYPE_EDGE_BOTH>; + debounce = <15625>; + bias-pull-up; + linux,code = ; + }; + + pm8226_resin: resin { + compatible = "qcom,pm8941-resin"; + interrupts = <0x0 0x8 1 IRQ_TYPE_EDGE_BOTH>; + debounce = <15625>; + bias-pull-up; + status = "disabled"; + }; + }; + + smbb: charger@1000 { + compatible = "qcom,pm8226-charger"; + reg = <0x1000>; + interrupts = <0x0 0x10 7 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x10 5 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x10 4 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x12 1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x12 0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 2 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x14 1 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "chg-done", + "chg-fast", + "chg-trkl", + "bat-temp-ok", + "bat-present", + "chg-gone", + "usb-valid", + "dc-valid"; + + status = "disabled"; + + chg_otg: otg-vbus { }; + }; + + pm8226_temp: temp-alarm@2400 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0x2400>; + interrupts = <0 0x24 0 IRQ_TYPE_EDGE_RISING>; + io-channels = <&pm8226_vadc VADC_DIE_TEMP>; + io-channel-names = "thermal"; + #thermal-sensor-cells = <0>; + }; + + pm8226_vadc: adc@3100 { + compatible = "qcom,spmi-vadc"; + reg = <0x3100>; + interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>; + #address-cells = <1>; + #size-cells = <0>; + #io-channel-cells = <1>; + + channel@7 { + reg = ; + qcom,pre-scaling = <1 3>; + label = "vph_pwr"; + }; + channel@8 { + reg = ; + label = "die_temp"; + }; + channel@9 { + reg = ; + label = "ref_625mv"; + }; + channel@a { + reg = ; + label = "ref_1250mv"; + }; + channel@e { + reg = ; + }; + channel@f { + reg = ; + }; + }; + + pm8226_iadc: adc@3600 { + compatible = "qcom,pm8226-iadc", "qcom,spmi-iadc"; + reg = <0x3600>; + interrupts = <0x0 0x36 0x0 IRQ_TYPE_EDGE_RISING>; + }; + + rtc@6000 { + compatible = "qcom,pm8941-rtc"; + reg = <0x6000>, <0x6100>; + reg-names = "rtc", "alarm"; + interrupts = <0x0 0x61 0x1 IRQ_TYPE_EDGE_RISING>; + }; + + pm8226_mpps: mpps@a000 { + compatible = "qcom,pm8226-mpp", "qcom,spmi-mpp"; + reg = <0xa000>; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pm8226_mpps 0 0 8>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + pm8226_gpios: gpio@c000 { + compatible = "qcom,pm8226-gpio", "qcom,spmi-gpio"; + reg = <0xc000>; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pm8226_gpios 0 0 8>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + pm8226_1: pm8226@1 { + compatible = "qcom,pm8226", "qcom,spmi-pmic"; + reg = <0x1 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + pm8226_spmi_regulators: regulators { + compatible = "qcom,pm8226-regulators"; + }; + + pm8226_vib: vibrator@c000 { + compatible = "qcom,pm8916-vib"; + reg = <0xc000>; + status = "disabled"; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/pm8821.dtsi b/arch/arm/boot/dts/qcom/pm8821.dtsi new file mode 100644 index 00000000000000..064e3ba54e1807 --- /dev/null +++ b/arch/arm/boot/dts/qcom/pm8821.dtsi @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* This PMIC is used on a secondary SSBI bus */ +&ssbi2 { + pm8821: pmic { + compatible = "qcom,pm8821"; + interrupt-controller; + #interrupt-cells = <2>; + #address-cells = <1>; + #size-cells = <0>; + + pm8821_mpps: mpps@50 { + compatible = "qcom,pm8821-mpp", "qcom,ssbi-mpp"; + reg = <0x50>; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pm8821_mpps 0 0 4>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/pm8841.dtsi b/arch/arm/boot/dts/qcom/pm8841.dtsi new file mode 100644 index 00000000000000..3bf2ce5c86a641 --- /dev/null +++ b/arch/arm/boot/dts/qcom/pm8841.dtsi @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include + + +/ { + thermal-zones { + pm8841-thermal { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-sensors = <&pm8841_temp>; + + trips { + trip0 { + temperature = <105000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip1 { + temperature = <125000>; + hysteresis = <2000>; + type = "hot"; + }; + + crit { + temperature = <140000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + }; + }; +}; + +&spmi_bus { + + pm8841_0: pm8841@4 { + compatible = "qcom,pm8841", "qcom,spmi-pmic"; + reg = <0x4 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + pm8841_mpps: mpps@a000 { + compatible = "qcom,pm8841-mpp", "qcom,spmi-mpp"; + reg = <0xa000>; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pm8841_mpps 0 0 4>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + pm8841_temp: temp-alarm@2400 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0x2400>; + interrupts = <4 0x24 0 IRQ_TYPE_EDGE_RISING>; + #thermal-sensor-cells = <0>; + }; + }; + + pm8841_1: pm8841@5 { + compatible = "qcom,pm8841", "qcom,spmi-pmic"; + reg = <0x5 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/pm8921.dtsi b/arch/arm/boot/dts/qcom/pm8921.dtsi new file mode 100644 index 00000000000000..058962af30051d --- /dev/null +++ b/arch/arm/boot/dts/qcom/pm8921.dtsi @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: GPL-2.0 + +&ssbi { + pm8921: pmic { + compatible = "qcom,pm8921"; + #interrupt-cells = <2>; + interrupt-controller; + #address-cells = <1>; + #size-cells = <0>; + + pwrkey@1c { + compatible = "qcom,pm8921-pwrkey"; + reg = <0x1c>; + interrupts-extended = <&pm8921 50 IRQ_TYPE_EDGE_RISING>, + <&pm8921 51 IRQ_TYPE_EDGE_RISING>; + debounce = <15625>; + pull-up; + }; + + pm8921_mpps: mpps@50 { + compatible = "qcom,pm8921-mpp", + "qcom,ssbi-mpp"; + reg = <0x50>; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pm8921_mpps 0 0 12>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + rtc@11d { + compatible = "qcom,pm8921-rtc"; + reg = <0x11d>; + interrupts-extended = <&pm8921 39 IRQ_TYPE_EDGE_RISING>; + allow-set-time; + }; + + pm8921_keypad: keypad@148 { + compatible = "qcom,pm8921-keypad"; + reg = <0x148>; + interrupts-extended = <&pm8921 74 IRQ_TYPE_EDGE_RISING>, + <&pm8921 75 IRQ_TYPE_EDGE_RISING>; + debounce = <15>; + scan-delay = <32>; + row-hold = <91500>; + status = "disabled"; + }; + + pm8921_gpio: gpio@150 { + + compatible = "qcom,pm8921-gpio", + "qcom,ssbi-gpio"; + reg = <0x150>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + gpio-ranges = <&pm8921_gpio 0 0 44>; + #gpio-cells = <2>; + + }; + + pm8921_xoadc: xoadc@197 { + compatible = "qcom,pm8921-adc"; + reg = <0x197>; + interrupts-extended = <&pm8921 78 IRQ_TYPE_EDGE_RISING>; + #address-cells = <2>; + #size-cells = <0>; + #io-channel-cells = <2>; + + vcoin: adc-channel@0 { + reg = <0x00 0x00>; + }; + + vbat: adc-channel@1 { + reg = <0x00 0x01>; + }; + + dcin: adc-channel@2 { + reg = <0x00 0x02>; + }; + + vph_pwr: adc-channel@4 { + reg = <0x00 0x04>; + }; + + batt_therm: adc-channel@8 { + reg = <0x00 0x08>; + }; + + batt_id: adc-channel@9 { + reg = <0x00 0x09>; + }; + + usb_vbus: adc-channel@a { + reg = <0x00 0x0a>; + }; + + die_temp: adc-channel@b { + reg = <0x00 0x0b>; + }; + + ref_625mv: adc-channel@c { + reg = <0x00 0x0c>; + }; + + ref_1250mv: adc-channel@d { + reg = <0x00 0x0d>; + }; + + chg_temp: adc-channel@e { + reg = <0x00 0x0e>; + }; + + ref_muxoff: adc-channel@f { + reg = <0x00 0x0f>; + }; + }; + }; +}; + +/ { + /* + * These channels from the ADC are simply hardware monitors. + * That is why the ADC is referred to as "HKADC" - HouseKeeping + * ADC. + */ + iio-hwmon { + compatible = "iio-hwmon"; + io-channels = <&pm8921_xoadc 0x00 0x01>, /* Battery */ + <&pm8921_xoadc 0x00 0x02>, /* DC in (charger) */ + <&pm8921_xoadc 0x00 0x04>, /* VPH the main system voltage */ + <&pm8921_xoadc 0x00 0x0b>, /* Die temperature */ + <&pm8921_xoadc 0x00 0x0c>, /* Reference voltage 1.25V */ + <&pm8921_xoadc 0x00 0x0d>, /* Reference voltage 0.625V */ + <&pm8921_xoadc 0x00 0x0e>; /* Charger temperature */ + }; +}; diff --git a/arch/arm/boot/dts/qcom/pm8941.dtsi b/arch/arm/boot/dts/qcom/pm8941.dtsi new file mode 100644 index 00000000000000..aca0052a02b75d --- /dev/null +++ b/arch/arm/boot/dts/qcom/pm8941.dtsi @@ -0,0 +1,256 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include + + +/ { + thermal-zones { + pm8941-thermal { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-sensors = <&pm8941_temp>; + + trips { + trip0 { + temperature = <105000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip1 { + temperature = <125000>; + hysteresis = <2000>; + type = "hot"; + }; + + crit { + temperature = <145000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + }; + }; +}; + +&spmi_bus { + + pm8941_0: pm8941@0 { + compatible = "qcom,pm8941", "qcom,spmi-pmic"; + reg = <0x0 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + rtc@6000 { + compatible = "qcom,pm8941-rtc"; + reg = <0x6000>, + <0x6100>; + reg-names = "rtc", "alarm"; + interrupts = <0x0 0x61 0x1 IRQ_TYPE_EDGE_RISING>; + }; + + pon@800 { + compatible = "qcom,pm8941-pon"; + reg = <0x800>; + + pwrkey { + compatible = "qcom,pm8941-pwrkey"; + interrupts = <0x0 0x8 0 IRQ_TYPE_EDGE_BOTH>; + debounce = <15625>; + bias-pull-up; + }; + + pm8941_resin: resin { + compatible = "qcom,pm8941-resin"; + interrupts = <0x0 0x8 1 IRQ_TYPE_EDGE_BOTH>; + debounce = <15625>; + bias-pull-up; + status = "disabled"; + }; + }; + + usb_id: usb-detect@900 { + compatible = "qcom,pm8941-misc"; + reg = <0x900>; + interrupts = <0x0 0x9 0 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "usb_id"; + }; + + smbb: charger@1000 { + compatible = "qcom,pm8941-charger"; + reg = <0x1000>; + interrupts = <0x0 0x10 7 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x10 5 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x10 4 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x12 1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x12 0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 2 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x14 1 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "chg-done", + "chg-fast", + "chg-trkl", + "bat-temp-ok", + "bat-present", + "chg-gone", + "usb-valid", + "dc-valid"; + + usb-otg-in-supply = <&pm8941_5vs1>; + + status = "disabled"; + + chg_otg: otg-vbus { }; + }; + + pm8941_gpios: gpio@c000 { + compatible = "qcom,pm8941-gpio", "qcom,spmi-gpio"; + reg = <0xc000>; + gpio-controller; + gpio-ranges = <&pm8941_gpios 0 0 36>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + + boost_bypass_n_pin: boost-bypass-state { + pins = "gpio21"; + function = "normal"; + }; + }; + + pm8941_mpps: mpps@a000 { + compatible = "qcom,pm8941-mpp", "qcom,spmi-mpp"; + reg = <0xa000>; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pm8941_mpps 0 0 8>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + pm8941_temp: temp-alarm@2400 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0x2400>; + interrupts = <0 0x24 0 IRQ_TYPE_EDGE_RISING>; + io-channels = <&pm8941_vadc VADC_DIE_TEMP>; + io-channel-names = "thermal"; + #thermal-sensor-cells = <0>; + }; + + pm8941_vadc: adc@3100 { + compatible = "qcom,spmi-vadc"; + reg = <0x3100>; + interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>; + #address-cells = <1>; + #size-cells = <0>; + #io-channel-cells = <1>; + + + channel@6 { + reg = ; + }; + + channel@8 { + reg = ; + }; + + channel@9 { + reg = ; + }; + + channel@a { + reg = ; + }; + + channel@e { + reg = ; + }; + + channel@f { + reg = ; + }; + + channel@30 { + reg = ; + }; + }; + + pm8941_iadc: adc@3600 { + compatible = "qcom,pm8941-iadc", "qcom,spmi-iadc"; + reg = <0x3600>; + interrupts = <0x0 0x36 0x0 IRQ_TYPE_EDGE_RISING>; + qcom,external-resistor-micro-ohms = <10000>; + }; + + pm8941_coincell: charger@2800 { + compatible = "qcom,pm8941-coincell"; + reg = <0x2800>; + status = "disabled"; + }; + }; + + pm8941_1: pm8941@1 { + compatible = "qcom,pm8941", "qcom,spmi-pmic"; + reg = <0x1 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + pm8941_lpg: pwm { + compatible = "qcom,pm8941-lpg"; + + #address-cells = <1>; + #size-cells = <0>; + #pwm-cells = <2>; + + status = "disabled"; + }; + + pm8941_vib: vibrator@c000 { + compatible = "qcom,pm8916-vib"; + reg = <0xc000>; + status = "disabled"; + }; + + pm8941_wled: wled@d800 { + compatible = "qcom,pm8941-wled"; + reg = <0xd800>; + label = "backlight"; + + status = "disabled"; + }; + + regulators { + compatible = "qcom,pm8941-regulators"; + interrupts = <0x1 0x83 0x2 0>, <0x1 0x84 0x2 0>; + interrupt-names = "ocp-5vs1", "ocp-5vs2"; + vin_5vs-supply = <&pm8941_5v>; + + pm8941_5v: s4 { + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-enable-ramp-delay = <500>; + }; + + pm8941_5vs1: 5vs1 { + regulator-enable-ramp-delay = <1000>; + regulator-pull-down; + regulator-over-current-protection; + qcom,ocp-max-retries = <10>; + qcom,ocp-retry-delay = <30>; + qcom,vs-soft-start-strength = <0>; + regulator-initial-mode = <1>; + }; + + pm8941_5vs2: 5vs2 { + regulator-enable-ramp-delay = <1000>; + regulator-pull-down; + regulator-over-current-protection; + qcom,ocp-max-retries = <10>; + qcom,ocp-retry-delay = <30>; + qcom,vs-soft-start-strength = <0>; + regulator-initial-mode = <1>; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/pma8084.dtsi b/arch/arm/boot/dts/qcom/pma8084.dtsi new file mode 100644 index 00000000000000..2985f4805b93ee --- /dev/null +++ b/arch/arm/boot/dts/qcom/pma8084.dtsi @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include + +&spmi_bus { + + pma8084_0: pma8084@0 { + compatible = "qcom,pma8084", "qcom,spmi-pmic"; + reg = <0x0 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + rtc@6000 { + compatible = "qcom,pm8941-rtc"; + reg = <0x6000>, + <0x6100>; + reg-names = "rtc", "alarm"; + interrupts = <0x0 0x61 0x1 IRQ_TYPE_EDGE_RISING>; + }; + + pwrkey@800 { + compatible = "qcom,pm8941-pwrkey"; + reg = <0x800>; + interrupts = <0x0 0x8 0 IRQ_TYPE_EDGE_BOTH>; + debounce = <15625>; + bias-pull-up; + }; + + pma8084_gpios: gpio@c000 { + compatible = "qcom,pma8084-gpio", "qcom,spmi-gpio"; + reg = <0xc000>; + gpio-controller; + gpio-ranges = <&pma8084_gpios 0 0 22>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + pma8084_mpps: mpps@a000 { + compatible = "qcom,pma8084-mpp", "qcom,spmi-mpp"; + reg = <0xa000>; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pma8084_mpps 0 0 8>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + pma8084_temp: temp-alarm@2400 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0x2400>; + interrupts = <0 0x24 0 IRQ_TYPE_EDGE_RISING>; + #thermal-sensor-cells = <0>; + io-channels = <&pma8084_vadc VADC_DIE_TEMP>; + io-channel-names = "thermal"; + }; + + pma8084_vadc: adc@3100 { + compatible = "qcom,spmi-vadc"; + reg = <0x3100>; + interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>; + #address-cells = <1>; + #size-cells = <0>; + #io-channel-cells = <1>; + + channel@8 { + reg = ; + }; + + channel@9 { + reg = ; + }; + + channel@a { + reg = ; + }; + + channel@c { + reg = ; + }; + + channel@e { + reg = ; + }; + + channel@f { + reg = ; + }; + }; + }; + + pma8084_1: pma8084@1 { + compatible = "qcom,pma8084", "qcom,spmi-pmic"; + reg = <0x1 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/pmx55.dtsi b/arch/arm/boot/dts/qcom/pmx55.dtsi new file mode 100644 index 00000000000000..da0851173c6997 --- /dev/null +++ b/arch/arm/boot/dts/qcom/pmx55.dtsi @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: BSD-3-Clause + +/* + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2020, Linaro Limited + */ + +#include +#include +#include + +&spmi_bus { + pmic@8 { + compatible = "qcom,pmx55", "qcom,spmi-pmic"; + reg = <0x8 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + pon@800 { + compatible = "qcom,pm8916-pon"; + reg = <0x0800>; + + status = "disabled"; + }; + + pmx55_temp: temp-alarm@2400 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0x2400>; + interrupts = <0x8 0x24 0x0 IRQ_TYPE_EDGE_BOTH>; + io-channels = <&pmx55_adc ADC5_DIE_TEMP>; + io-channel-names = "thermal"; + #thermal-sensor-cells = <0>; + }; + + pmx55_adc: adc@3100 { + compatible = "qcom,spmi-adc5"; + reg = <0x3100>; + #address-cells = <1>; + #size-cells = <0>; + #io-channel-cells = <1>; + interrupts = <0x8 0x31 0x0 IRQ_TYPE_EDGE_RISING>; + + channel@0 { + reg = ; + qcom,pre-scaling = <1 1>; + label = "ref_gnd"; + }; + + channel@1 { + reg = ; + qcom,pre-scaling = <1 1>; + label = "vref_1p25"; + }; + + channel@6 { + reg = ; + qcom,pre-scaling = <1 1>; + label = "die_temp"; + }; + + channel@9 { + reg = ; + qcom,pre-scaling = <1 1>; + label = "chg_temp"; + }; + }; + + pmx55_gpios: gpio@c000 { + compatible = "qcom,pmx55-gpio", "qcom,spmi-gpio"; + reg = <0xc000>; + gpio-controller; + gpio-ranges = <&pmx55_gpios 0 0 11>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + pmic@9 { + compatible = "qcom,pmx55", "qcom,spmi-pmic"; + reg = <0x9 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/pmx65.dtsi b/arch/arm/boot/dts/qcom/pmx65.dtsi new file mode 100644 index 00000000000000..1c7fdf59c1f56a --- /dev/null +++ b/arch/arm/boot/dts/qcom/pmx65.dtsi @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include + +&spmi_bus { + pmic@1 { + compatible = "qcom,pmx65", "qcom,spmi-pmic"; + reg = <1 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + pmx65_temp: temp-alarm@a00 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0xa00>; + interrupts = <0x1 0xa 0x0 IRQ_TYPE_EDGE_BOTH>; + #thermal-sensor-cells = <0>; + }; + + pmx65_gpios: gpio@8800 { + compatible = "qcom,pmx65-gpio", "qcom,spmi-gpio"; + reg = <0x8800>; + gpio-controller; + gpio-ranges = <&pmx65_gpios 0 0 16>; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/qcom-apq8026-asus-sparrow.dts b/arch/arm/boot/dts/qcom/qcom-apq8026-asus-sparrow.dts index aa0e0e8d2a973e..a2ca456012f1a0 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8026-asus-sparrow.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8026-asus-sparrow.dts @@ -6,7 +6,7 @@ /dts-v1/; #include "qcom-msm8226.dtsi" -#include "qcom-pm8226.dtsi" +#include "pm8226.dtsi" /delete-node/ &adsp_region; @@ -253,6 +253,8 @@ qcom,fast-charge-high-threshold-voltage = <4400000>; qcom,auto-recharge-threshold-voltage = <4300000>; qcom,minimum-input-voltage = <4400000>; + + status = "okay"; }; &tlmm { diff --git a/arch/arm/boot/dts/qcom/qcom-apq8026-huawei-sturgeon.dts b/arch/arm/boot/dts/qcom/qcom-apq8026-huawei-sturgeon.dts index de19640efe5538..ac228965a48559 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8026-huawei-sturgeon.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8026-huawei-sturgeon.dts @@ -6,7 +6,7 @@ /dts-v1/; #include "qcom-msm8226.dtsi" -#include "qcom-pm8226.dtsi" +#include "pm8226.dtsi" #include /delete-node/ &adsp_region; @@ -335,6 +335,8 @@ qcom,fast-charge-current-limit = <300000>; qcom,fast-charge-safe-current = <600000>; qcom,auto-recharge-threshold-voltage = <4240000>; + + status = "okay"; }; &tlmm { diff --git a/arch/arm/boot/dts/qcom/qcom-apq8026-lg-lenok.dts b/arch/arm/boot/dts/qcom/qcom-apq8026-lg-lenok.dts index b887e5361ec3a2..0a1fd5eb3c6d26 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8026-lg-lenok.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8026-lg-lenok.dts @@ -6,7 +6,7 @@ /dts-v1/; #include "qcom-msm8226.dtsi" -#include "qcom-pm8226.dtsi" +#include "pm8226.dtsi" /delete-node/ &adsp_region; @@ -292,6 +292,8 @@ qcom,fast-charge-high-threshold-voltage = <4350000>; qcom,auto-recharge-threshold-voltage = <4240000>; qcom,minimum-input-voltage = <4450000>; + + status = "okay"; }; &tlmm { diff --git a/arch/arm/boot/dts/qcom/qcom-apq8026-samsung-matisse-wifi.dts b/arch/arm/boot/dts/qcom/qcom-apq8026-samsung-matisse-wifi.dts index f516e0426bb9e8..cffc069712b2f1 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8026-samsung-matisse-wifi.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8026-samsung-matisse-wifi.dts @@ -7,7 +7,7 @@ #include #include "qcom-msm8226.dtsi" -#include "qcom-pm8226.dtsi" +#include "pm8226.dtsi" /delete-node/ &adsp_region; /delete-node/ &smem_region; diff --git a/arch/arm/boot/dts/qcom/qcom-apq8060-dragonboard.dts b/arch/arm/boot/dts/qcom/qcom-apq8060-dragonboard.dts index 569cbf0d8df87b..009afd8212c223 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8060-dragonboard.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8060-dragonboard.dts @@ -5,6 +5,7 @@ #include #include #include "qcom-msm8660.dtsi" +#include "pm8058.dtsi" / { model = "Qualcomm APQ8060 Dragonboard"; @@ -71,7 +72,7 @@ /* Trig on both edges - getting close or far away */ interrupts-extended = <&pm8058_gpio 34 IRQ_TYPE_EDGE_BOTH>; /* MPP05 analog input to the XOADC */ - io-channels = <&xoadc 0x00 0x05>; + io-channels = <&pm8058_xoadc 0x00 0x05>; io-channel-names = "aout"; pinctrl-names = "default"; pinctrl-0 = <&dragon_cm3605_gpios>, <&dragon_cm3605_mpps>; @@ -272,6 +273,10 @@ }; }; +&pm8058 { + interrupts-extended = <&tlmm 88 IRQ_TYPE_LEVEL_LOW>; +}; + &pm8058_gpio { dragon_ethernet_gpios: ethernet-state { pinconf { @@ -447,6 +452,8 @@ * that means */ regulators-0 { + compatible = "qcom,rpm-pm8901-regulators"; + vdd_l0-supply = <&pm8901_s4>; vdd_l1-supply = <&vph>; vdd_l2-supply = <&vph>; @@ -464,57 +471,63 @@ lvs3_in-supply = <&pm8058_s2>; mvs_in-supply = <&pm8058_s3>; - l0 { + pm8901_l0: l0 { regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; bias-pull-down; }; - l1 { + + pm8901_l1: l1 { regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; bias-pull-down; }; - l2 { + + pm8901_l2: l2 { /* TMA340 requires strictly 3.3V */ regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; bias-pull-down; }; - l3 { + + pm8901_l3: l3 { regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; bias-pull-down; }; - l4 { + + pm8901_l4: l4 { regulator-min-microvolt = <2600000>; regulator-max-microvolt = <2600000>; bias-pull-down; }; - l5 { + + pm8901_l5: l5 { regulator-min-microvolt = <2850000>; regulator-max-microvolt = <2850000>; bias-pull-down; }; - l6 { + + pm8901_l6: l6 { regulator-min-microvolt = <2200000>; regulator-max-microvolt = <2200000>; bias-pull-down; }; /* s0 and s1 are SAW regulators controlled over SPM */ - s2 { + pm8901_s2: s2 { regulator-min-microvolt = <1300000>; regulator-max-microvolt = <1300000>; qcom,switch-mode-frequency = <1600000>; bias-pull-down; }; - s3 { + pm8901_s3: s3 { regulator-min-microvolt = <1100000>; regulator-max-microvolt = <1100000>; qcom,switch-mode-frequency = <1600000>; bias-pull-down; }; - s4 { + pm8901_s4: s4 { regulator-min-microvolt = <1225000>; regulator-max-microvolt = <1225000>; qcom,switch-mode-frequency = <1600000>; @@ -522,17 +535,22 @@ }; /* LVS0 thru 3 and mvs are just switches */ - lvs0 { + pm8901_lvs0: lvs0 { regulator-always-on; }; - lvs1 { }; - lvs2 { }; - lvs3 { }; - mvs { }; + pm8901_lvs1: lvs1 { }; + + pm8901_lvs2: lvs2 { }; + + pm8901_lvs3: lvs3 { }; + + pm8901_mvs: mvs { }; }; regulators-1 { + compatible = "qcom,rpm-pm8058-regulators"; + vdd_l0_l1_lvs-supply = <&pm8058_s3>; vdd_l2_l11_l12-supply = <&vph>; vdd_l3_l4_l5-supply = <&vph>; @@ -554,144 +572,169 @@ vdd_s4-supply = <&vph>; vdd_ncp-supply = <&vph>; - l0 { + pm8058_l0: l0 { regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; bias-pull-down; }; - l1 { + + pm8058_l1: l1 { regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; bias-pull-down; }; - l2 { + + pm8058_l2: l2 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <2600000>; bias-pull-down; }; - l3 { + + pm8058_l3: l3 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; bias-pull-down; }; - l4 { + + pm8058_l4: l4 { regulator-min-microvolt = <2850000>; regulator-max-microvolt = <2850000>; bias-pull-down; }; - l5 { + + pm8058_l5: l5 { regulator-min-microvolt = <2850000>; regulator-max-microvolt = <2850000>; bias-pull-down; }; - l6 { + + pm8058_l6: l6 { regulator-min-microvolt = <3000000>; regulator-max-microvolt = <3600000>; bias-pull-down; }; - l7 { + + pm8058_l7: l7 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; bias-pull-down; }; - l8 { + + pm8058_l8: l8 { regulator-min-microvolt = <2900000>; regulator-max-microvolt = <3050000>; bias-pull-down; }; - l9 { + + pm8058_l9: l9 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; bias-pull-down; }; - l10 { + + pm8058_l10: l10 { regulator-min-microvolt = <2600000>; regulator-max-microvolt = <2600000>; bias-pull-down; }; - l11 { + + pm8058_l11: l11 { regulator-min-microvolt = <1500000>; regulator-max-microvolt = <1500000>; bias-pull-down; }; - l12 { + + pm8058_l12: l12 { regulator-min-microvolt = <2900000>; regulator-max-microvolt = <2900000>; bias-pull-down; }; - l13 { + + pm8058_l13: l13 { regulator-min-microvolt = <2050000>; regulator-max-microvolt = <2050000>; bias-pull-down; }; - l14 { + + pm8058_l14: l14 { regulator-min-microvolt = <2850000>; regulator-max-microvolt = <2850000>; }; - l15 { + + pm8058_l15: l15 { regulator-min-microvolt = <2850000>; regulator-max-microvolt = <2850000>; bias-pull-down; }; - l16 { + + pm8058_l16: l16 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; bias-pull-down; regulator-always-on; }; - l17 { + + pm8058_l17: l17 { // 1.5V according to schematic regulator-min-microvolt = <2600000>; regulator-max-microvolt = <2600000>; bias-pull-down; }; - l18 { + + pm8058_l18: l18 { regulator-min-microvolt = <2200000>; regulator-max-microvolt = <2200000>; bias-pull-down; }; - l19 { + + pm8058_l19: l19 { regulator-min-microvolt = <2500000>; regulator-max-microvolt = <2500000>; bias-pull-down; }; - l20 { + + pm8058_l20: l20 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; bias-pull-down; }; - l21 { + + pm8058_l21: l21 { // 1.1 V according to schematic regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; bias-pull-down; regulator-always-on; }; - l22 { + + pm8058_l22: l22 { // 1.2 V according to schematic regulator-min-microvolt = <1150000>; regulator-max-microvolt = <1150000>; bias-pull-down; }; - l23 { + + pm8058_l23: l23 { // Unused regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; bias-pull-down; }; - l24 { + + pm8058_l24: l24 { // Unused regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; bias-pull-down; }; - l25 { + + pm8058_l25: l25 { regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; bias-pull-down; }; - s0 { + pm8058_s0: s0 { // regulator-min-microvolt = <500000>; // regulator-max-microvolt = <1325000>; regulator-min-microvolt = <1100000>; @@ -699,7 +742,8 @@ qcom,switch-mode-frequency = <1600000>; bias-pull-down; }; - s1 { + + pm8058_s1: s1 { // regulator-min-microvolt = <500000>; // regulator-max-microvolt = <1250000>; regulator-min-microvolt = <1100000>; @@ -707,21 +751,24 @@ qcom,switch-mode-frequency = <1600000>; bias-pull-down; }; - s2 { + + pm8058_s2: s2 { // 1.3 V according to schematic regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1400000>; qcom,switch-mode-frequency = <1600000>; bias-pull-down; }; - s3 { + + pm8058_s3: s3 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; qcom,switch-mode-frequency = <1600000>; regulator-always-on; bias-pull-down; }; - s4 { + + pm8058_s4: s4 { regulator-min-microvolt = <2200000>; regulator-max-microvolt = <2200000>; qcom,switch-mode-frequency = <1600000>; @@ -730,14 +777,15 @@ }; /* LVS0 and LVS1 are just switches */ - lvs0 { + pm8058_lvs0: lvs0 { bias-pull-down; }; - lvs1 { + + pm8058_lvs1: lvs1 { bias-pull-down; }; - ncp { + pm8058_ncp: ncp { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; qcom,switch-mode-frequency = <1600000>; @@ -944,28 +992,32 @@ }; }; -&xoadc { +&pm8058_xoadc { /* Reference voltage 2.2 V */ xoadc-ref-supply = <&pm8058_l18>; /* Board-specific channels */ - mpp5@5 { + adc-channel@5 { /* Connected to AOUT of ALS sensor */ reg = <0x00 0x05>; }; - mpp6@6 { + + adc-channel@6 { /* Connected to test point TP43 */ reg = <0x00 0x06>; }; - mpp7@7 { + + adc-channel@7 { /* Connected to battery thermistor */ reg = <0x00 0x07>; }; - mpp8@8 { + + adc-channel@8 { /* Connected to battery ID detector */ reg = <0x00 0x08>; }; - mpp9@9 { + + adc-channel@9 { /* Connected to XO thermistor */ reg = <0x00 0x09>; }; diff --git a/arch/arm/boot/dts/qcom/qcom-apq8064-asus-nexus7-flo.dts b/arch/arm/boot/dts/qcom/qcom-apq8064-asus-nexus7-flo.dts index c0dd6399f597a7..d460743fbb9401 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8064-asus-nexus7-flo.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8064-asus-nexus7-flo.dts @@ -1,8 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 -#include "qcom-apq8064-v2.0.dtsi" #include #include #include + +#include "qcom-apq8064-v2.0.dtsi" +#include "pm8821.dtsi" +#include "pm8921.dtsi" + / { model = "Asus Nexus7(flo)"; compatible = "asus,nexus7-flo", "qcom,apq8064"; @@ -180,24 +184,26 @@ status = "okay"; }; -/* eMMC */ -&sdcc1 { - vmmc-supply = <&pm8921_l5>; - vqmmc-supply = <&pm8921_s4>; - status = "okay"; -}; - &mdp_dsi1_out { remote-endpoint = <&dsi0_in>; }; +&pm8821 { + interrupts-extended = <&tlmm_pinmux 76 IRQ_TYPE_LEVEL_LOW>; +}; + +&pm8921 { + interrupts-extended = <&tlmm_pinmux 74 IRQ_TYPE_LEVEL_LOW>; +}; + &rpm { regulators { + compatible = "qcom,rpm-pm8921-regulators"; + vdd_l1_l2_l12_l18-supply = <&pm8921_s4>; vin_lvs1_3_6-supply = <&pm8921_s4>; vin_lvs4_5_7-supply = <&pm8921_s4>; - vdd_l24-supply = <&pm8921_s1>; vdd_l25-supply = <&pm8921_s1>; vin_lvs2-supply = <&pm8921_s1>; @@ -209,7 +215,7 @@ vdd_ncp-supply = <&pm8921_l6>; /* Buck SMPS */ - s1 { + pm8921_s1: s1 { regulator-always-on; regulator-min-microvolt = <1225000>; regulator-max-microvolt = <1225000>; @@ -218,7 +224,7 @@ }; /* msm otg HSUSB_VDDCX */ - s3 { + pm8921_s3: s3 { regulator-min-microvolt = <500000>; regulator-max-microvolt = <1150000>; qcom,switch-mode-frequency = <4800000>; @@ -231,55 +237,58 @@ * tabla2x-slim-CDC_VDD_CP * tabla2x-slim-VDDIO_CDC */ - s4 { + pm8921_s4: s4 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; qcom,switch-mode-frequency = <3200000>; regulator-always-on; }; - s7 { + pm8921_s7: s7 { regulator-min-microvolt = <1300000>; regulator-max-microvolt = <1300000>; qcom,switch-mode-frequency = <3200000>; }; /* mipi_dsi.1-dsi1_pll_vdda */ - l2 { + pm8921_l2: l2 { regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; regulator-always-on; }; /* msm_otg-HSUSB_3p3 */ - l3 { + pm8921_l3: l3 { regulator-min-microvolt = <3075000>; regulator-max-microvolt = <3075000>; bias-pull-down; }; /* msm_otg-HSUSB_1p8 */ - l4 { + pm8921_l4: l4 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; bias-pull-down; }; /* msm_sdcc.1-sdc_vdd */ - l5 { + pm8921_l5: l5 { regulator-min-microvolt = <2950000>; regulator-max-microvolt = <2950000>; regulator-always-on; bias-pull-down; }; - l6 { + pm8921_l6: l6 { regulator-min-microvolt = <2950000>; regulator-max-microvolt = <2950000>; }; + pm8921_l8: l8 { + }; + /* mipi_dsi.1-dsi1_avdd */ - l11 { + pm8921_l11: l11 { regulator-min-microvolt = <3000000>; regulator-max-microvolt = <3000000>; bias-pull-down; @@ -287,14 +296,14 @@ }; /* pwm_power for backlight */ - l17 { + pm8921_l17: l17 { regulator-min-microvolt = <3000000>; regulator-max-microvolt = <3000000>; regulator-always-on; }; /* camera, qdsp6 */ - l23 { + pm8921_l23: l23 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; bias-pull-down; @@ -304,37 +313,44 @@ * tabla2x-slim-CDC_VDDA_A_1P2V * tabla2x-slim-VDDD_CDC_D */ - l25 { + pm8921_l25: l25 { regulator-min-microvolt = <1250000>; regulator-max-microvolt = <1250000>; bias-pull-down; }; - lvs1 { + pm8921_lvs1: lvs1 { bias-pull-down; }; - lvs4 { + pm8921_lvs4: lvs4 { bias-pull-down; }; - lvs5 { + pm8921_lvs5: lvs5 { bias-pull-down; }; - lvs6 { + pm8921_lvs6: lvs6 { bias-pull-down; }; /* * mipi_dsi.1-dsi1_vddio * pil_riva-pll_vdd */ - lvs7 { + pm8921_lvs7: lvs7 { bias-pull-down; }; }; }; +/* eMMC */ +&sdcc1 { + vmmc-supply = <&pm8921_l5>; + vqmmc-supply = <&pm8921_s4>; + status = "okay"; +}; + &usb_hs1_phy { v3p3-supply = <&pm8921_l3>; v1p8-supply = <&pm8921_l4>; diff --git a/arch/arm/boot/dts/qcom/qcom-apq8064-cm-qs600.dts b/arch/arm/boot/dts/qcom/qcom-apq8064-cm-qs600.dts index d6ecfd8addb7ae..671d58cc2741b0 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8064-cm-qs600.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8064-cm-qs600.dts @@ -1,8 +1,11 @@ // SPDX-License-Identifier: GPL-2.0 -#include "qcom-apq8064-v2.0.dtsi" #include #include +#include "qcom-apq8064-v2.0.dtsi" +#include "pm8821.dtsi" +#include "pm8921.dtsi" + / { model = "CompuLab CM-QS600"; compatible = "qcom,apq8064-cm-qs600", "qcom,apq8064"; @@ -69,6 +72,14 @@ status = "okay"; }; +&pm8821 { + interrupts-extended = <&tlmm_pinmux 76 IRQ_TYPE_LEVEL_LOW>; +}; + +&pm8921 { + interrupts-extended = <&tlmm_pinmux 74 IRQ_TYPE_LEVEL_LOW>; +}; + &pm8921_gpio { wlan_default_gpios: wlan-gpios-state { pinconf { @@ -82,6 +93,8 @@ &rpm { regulators { + compatible = "qcom,rpm-pm8921-regulators"; + vin_lvs1_3_6-supply = <&pm8921_s4>; vin_lvs2-supply = <&pm8921_s1>; vin_lvs4_5_7-supply = <&pm8921_s4>; @@ -93,9 +106,8 @@ vdd_l27-supply = <&pm8921_s7>; vdd_l28-supply = <&pm8921_s7>; - /* Buck SMPS */ - s1 { + pm8921_s1: s1 { regulator-always-on; regulator-min-microvolt = <1225000>; regulator-max-microvolt = <1225000>; @@ -103,52 +115,51 @@ bias-pull-down; }; - s3 { + pm8921_s3: s3 { regulator-min-microvolt = <1000000>; regulator-max-microvolt = <1400000>; qcom,switch-mode-frequency = <4800000>; }; - s4 { + pm8921_s4: s4 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; qcom,switch-mode-frequency = <3200000>; }; - s7 { + pm8921_s7: s7 { regulator-min-microvolt = <1300000>; regulator-max-microvolt = <1300000>; qcom,switch-mode-frequency = <3200000>; }; - l3 { + pm8921_l3: l3 { regulator-min-microvolt = <3050000>; regulator-max-microvolt = <3300000>; bias-pull-down; }; - l4 { + pm8921_l4: l4 { regulator-min-microvolt = <1000000>; regulator-max-microvolt = <1800000>; bias-pull-down; }; - l5 { + pm8921_l5: l5 { regulator-min-microvolt = <2750000>; regulator-max-microvolt = <3000000>; bias-pull-down; }; - l23 { + pm8921_l23: l23 { regulator-min-microvolt = <1700000>; regulator-max-microvolt = <1900000>; bias-pull-down; }; - lvs6 { + pm8921_lvs6: lvs6 { bias-pull-down; }; - }; }; diff --git a/arch/arm/boot/dts/qcom/qcom-apq8064-ifc6410.dts b/arch/arm/boot/dts/qcom/qcom-apq8064-ifc6410.dts index b0c5e7bd5e74e1..ed86b24119c97f 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8064-ifc6410.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8064-ifc6410.dts @@ -1,9 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 -#include "qcom-apq8064-v2.0.dtsi" #include #include #include +#include "qcom-apq8064-v2.0.dtsi" +#include "pm8821.dtsi" +#include "pm8921.dtsi" + / { model = "Qualcomm APQ8064/IFC6410"; compatible = "qcom,apq8064-ifc6410", "qcom,apq8064"; @@ -170,6 +173,14 @@ perst-gpios = <&tlmm_pinmux 27 GPIO_ACTIVE_LOW>; }; +&pm8821 { + interrupts-extended = <&tlmm_pinmux 76 IRQ_TYPE_LEVEL_LOW>; +}; + +&pm8921 { + interrupts-extended = <&tlmm_pinmux 74 IRQ_TYPE_LEVEL_LOW>; +}; + &pm8921_gpio { wlan_default_gpios: wlan-gpios-state { pinconf { @@ -192,6 +203,8 @@ &rpm { regulators { + compatible = "qcom,rpm-pm8921-regulators"; + vin_lvs1_3_6-supply = <&pm8921_s4>; vin_lvs2-supply = <&pm8921_s1>; vin_lvs4_5_7-supply = <&pm8921_s4>; @@ -203,9 +216,8 @@ vdd_l27-supply = <&pm8921_s7>; vdd_l28-supply = <&pm8921_s7>; - /* Buck SMPS */ - s1 { + pm8921_s1: s1 { regulator-always-on; regulator-min-microvolt = <1225000>; regulator-max-microvolt = <1225000>; @@ -213,59 +225,63 @@ bias-pull-down; }; - s3 { + pm8921_s3: s3 { regulator-min-microvolt = <1000000>; regulator-max-microvolt = <1400000>; qcom,switch-mode-frequency = <4800000>; }; - s4 { + pm8921_s4: s4 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; qcom,switch-mode-frequency = <3200000>; }; - s7 { + pm8921_s7: s7 { regulator-min-microvolt = <1300000>; regulator-max-microvolt = <1300000>; qcom,switch-mode-frequency = <3200000>; }; - l3 { + pm8921_l3: l3 { regulator-min-microvolt = <3050000>; regulator-max-microvolt = <3300000>; bias-pull-down; }; - l4 { + pm8921_l4: l4 { regulator-min-microvolt = <1000000>; regulator-max-microvolt = <1800000>; bias-pull-down; }; - l5 { + pm8921_l5: l5 { regulator-min-microvolt = <2750000>; regulator-max-microvolt = <3000000>; bias-pull-down; }; - l6 { + pm8921_l6: l6 { regulator-min-microvolt = <2950000>; regulator-max-microvolt = <2950000>; bias-pull-down; }; - l23 { + pm8921_l23: l23 { regulator-min-microvolt = <1700000>; regulator-max-microvolt = <1900000>; bias-pull-down; }; - lvs1 { + pm8921_lvs1: lvs1 { + bias-pull-down; + }; + + pm8921_lvs6: lvs6 { bias-pull-down; }; - lvs6 { + pm8921_hdmi_switch: hdmi-switch { bias-pull-down; }; }; diff --git a/arch/arm/boot/dts/qcom/qcom-apq8064-sony-xperia-lagan-yuga.dts b/arch/arm/boot/dts/qcom/qcom-apq8064-sony-xperia-lagan-yuga.dts index 9244512b74d1e1..2412aa3e3e8dba 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8064-sony-xperia-lagan-yuga.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8064-sony-xperia-lagan-yuga.dts @@ -1,10 +1,13 @@ // SPDX-License-Identifier: GPL-2.0 -#include "qcom-apq8064-v2.0.dtsi" #include #include #include #include +#include "qcom-apq8064-v2.0.dtsi" +#include "pm8821.dtsi" +#include "pm8921.dtsi" + / { model = "Sony Xperia Z"; compatible = "sony,xperia-yuga", "qcom,apq8064"; @@ -65,6 +68,14 @@ status = "okay"; }; +&pm8821 { + interrupts-extended = <&tlmm_pinmux 76 IRQ_TYPE_LEVEL_LOW>; +}; + +&pm8921 { + interrupts-extended = <&tlmm_pinmux 74 IRQ_TYPE_LEVEL_LOW>; +}; + &pm8921_gpio { gpio_keys_pin_a: gpio-keys-active-state { pins = "gpio3", "gpio4", "gpio29", "gpio35"; @@ -82,11 +93,25 @@ &riva { pinctrl-names = "default"; pinctrl-0 = <&riva_wlan_pin_a>, <&riva_bt_pin_a>, <&riva_fm_pin_a>; + + vddcx-supply = <&pm8921_s3>; + vddmx-supply = <&pm8921_l24>; + vddpx-supply = <&pm8921_s4>; + status = "okay"; + + iris { + vddxo-supply = <&pm8921_l4>; + vddrfa-supply = <&pm8921_s2>; + vddpa-supply = <&pm8921_l10>; + vdddig-supply = <&pm8921_lvs2>; + }; }; &rpm { regulators { + compatible = "qcom,rpm-pm8921-regulators"; + vin_l1_l2_l12_l18-supply = <&pm8921_s4>; vin_lvs_1_3_6-supply = <&pm8921_s4>; vin_lvs_4_5_7-supply = <&pm8921_s4>; @@ -98,7 +123,7 @@ vin_l28-supply = <&pm8921_s7>; /* Buck SMPS */ - s1 { + pm8921_s1: s1 { regulator-always-on; regulator-min-microvolt = <1225000>; regulator-max-microvolt = <1225000>; @@ -106,21 +131,21 @@ bias-pull-down; }; - s2 { + pm8921_s2: s2 { regulator-min-microvolt = <1300000>; regulator-max-microvolt = <1300000>; qcom,switch-mode-frequency = <1600000>; bias-pull-down; }; - s3 { + pm8921_s3: s3 { regulator-min-microvolt = <500000>; regulator-max-microvolt = <1150000>; qcom,switch-mode-frequency = <4800000>; bias-pull-down; }; - s4 { + pm8921_s4: s4 { regulator-always-on; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; @@ -129,205 +154,207 @@ qcom,force-mode = ; }; - s7 { + pm8921_s7: s7 { regulator-min-microvolt = <1300000>; regulator-max-microvolt = <1300000>; qcom,switch-mode-frequency = <3200000>; }; - s8 { + pm8921_s8: s8 { regulator-min-microvolt = <2200000>; regulator-max-microvolt = <2200000>; qcom,switch-mode-frequency = <1600000>; }; /* PMOS LDO */ - l1 { + pm8921_l1: l1 { regulator-always-on; regulator-min-microvolt = <1100000>; regulator-max-microvolt = <1100000>; bias-pull-down; }; - l2 { + pm8921_l2: l2 { regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; bias-pull-down; }; - l3 { + pm8921_l3: l3 { regulator-min-microvolt = <3075000>; regulator-max-microvolt = <3075000>; bias-pull-down; }; - l4 { + pm8921_l4: l4 { regulator-always-on; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; bias-pull-down; }; - l5 { + pm8921_l5: l5 { regulator-min-microvolt = <2950000>; regulator-max-microvolt = <2950000>; bias-pull-down; }; - l6 { + pm8921_l6: l6 { regulator-min-microvolt = <2950000>; regulator-max-microvolt = <2950000>; bias-pull-down; }; - l7 { + pm8921_l7: l7 { regulator-min-microvolt = <1850000>; regulator-max-microvolt = <2950000>; bias-pull-down; }; - l8 { + pm8921_l8: l8 { regulator-min-microvolt = <2800000>; regulator-max-microvolt = <2800000>; bias-pull-down; }; - l9 { + pm8921_l9: l9 { regulator-min-microvolt = <3000000>; regulator-max-microvolt = <3000000>; bias-pull-down; }; - l10 { + pm8921_l10: l10 { regulator-min-microvolt = <2900000>; regulator-max-microvolt = <2900000>; bias-pull-down; }; - l11 { + pm8921_l11: l11 { regulator-min-microvolt = <3000000>; regulator-max-microvolt = <3000000>; bias-pull-down; }; - l12 { + pm8921_l12: l12 { regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; bias-pull-down; }; - l14 { + pm8921_l14: l14 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; bias-pull-down; }; - l15 { + pm8921_l15: l15 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <2950000>; bias-pull-down; }; - l16 { + pm8921_l16: l16 { regulator-min-microvolt = <2800000>; regulator-max-microvolt = <2800000>; bias-pull-down; }; - l17 { + pm8921_l17: l17 { regulator-min-microvolt = <2000000>; regulator-max-microvolt = <2000000>; bias-pull-down; }; - l18 { + pm8921_l18: l18 { regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; bias-pull-down; }; - l21 { + pm8921_l21: l21 { regulator-min-microvolt = <1050000>; regulator-max-microvolt = <1050000>; bias-pull-down; }; - l22 { + pm8921_l22: l22 { regulator-min-microvolt = <2600000>; regulator-max-microvolt = <2600000>; bias-pull-down; }; - l23 { + pm8921_l23: l23 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; bias-pull-down; }; - l24 { + pm8921_l24: l24 { regulator-min-microvolt = <750000>; regulator-max-microvolt = <1150000>; bias-pull-down; }; - l25 { + pm8921_l25: l25 { regulator-always-on; regulator-min-microvolt = <1250000>; regulator-max-microvolt = <1250000>; bias-pull-down; }; - l27 { + pm8921_l27: l27 { regulator-min-microvolt = <1100000>; regulator-max-microvolt = <1100000>; }; - l28 { + pm8921_l28: l28 { regulator-min-microvolt = <1050000>; regulator-max-microvolt = <1050000>; bias-pull-down; }; - l29 { + pm8921_l29: l29 { regulator-min-microvolt = <2000000>; regulator-max-microvolt = <2000000>; bias-pull-down; }; /* Low Voltage Switch */ - lvs1 { + pm8921_lvs1: lvs1 { bias-pull-down; }; - lvs2 { + pm8921_lvs2: lvs2 { bias-pull-down; }; - lvs3 { + pm8921_lvs3: lvs3 { bias-pull-down; }; - lvs4 { + pm8921_lvs4: lvs4 { bias-pull-down; }; - lvs5 { + pm8921_lvs5: lvs5 { bias-pull-down; }; - lvs6 { + pm8921_lvs6: lvs6 { bias-pull-down; }; - lvs7 { + pm8921_lvs7: lvs7 { bias-pull-down; }; - usb-switch {}; + pm8921_usb_switch: usb-switch {}; - hdmi-switch {}; + pm8921_hdmi_switch: hdmi-switch { + bias-pull-down; + }; - ncp { + pm8921_ncp: ncp { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; qcom,switch-mode-frequency = <1600000>; diff --git a/arch/arm/boot/dts/qcom/qcom-apq8064.dtsi b/arch/arm/boot/dts/qcom/qcom-apq8064.dtsi index 59fd86b9fb4718..3faf57035d544d 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8064.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-apq8064.dtsi @@ -284,23 +284,6 @@ }; }; - - /* - * These channels from the ADC are simply hardware monitors. - * That is why the ADC is referred to as "HKADC" - HouseKeeping - * ADC. - */ - iio-hwmon { - compatible = "iio-hwmon"; - io-channels = <&xoadc 0x00 0x01>, /* Battery */ - <&xoadc 0x00 0x02>, /* DC in (charger) */ - <&xoadc 0x00 0x04>, /* VPH the main system voltage */ - <&xoadc 0x00 0x0b>, /* Die temperature */ - <&xoadc 0x00 0x0c>, /* Reference voltage 1.25V */ - <&xoadc 0x00 0x0d>, /* Reference voltage 0.625V */ - <&xoadc 0x00 0x0e>; /* Charger temperature */ - }; - soc: soc { #address-cells = <1>; #size-cells = <1>; @@ -655,133 +638,16 @@ clock-names = "core"; }; - ssbi@c00000 { + ssbi2: ssbi@c00000 { compatible = "qcom,ssbi"; reg = <0x00c00000 0x1000>; qcom,controller-type = "pmic-arbiter"; - - pm8821: pmic { - compatible = "qcom,pm8821"; - interrupt-parent = <&tlmm_pinmux>; - interrupts = <76 IRQ_TYPE_LEVEL_LOW>; - #interrupt-cells = <2>; - interrupt-controller; - #address-cells = <1>; - #size-cells = <0>; - - pm8821_mpps: mpps@50 { - compatible = "qcom,pm8821-mpp", "qcom,ssbi-mpp"; - reg = <0x50>; - interrupt-controller; - #interrupt-cells = <2>; - gpio-controller; - #gpio-cells = <2>; - gpio-ranges = <&pm8821_mpps 0 0 4>; - }; - }; }; - ssbi@500000 { + ssbi: ssbi@500000 { compatible = "qcom,ssbi"; reg = <0x00500000 0x1000>; qcom,controller-type = "pmic-arbiter"; - - pmicintc: pmic { - compatible = "qcom,pm8921"; - interrupt-parent = <&tlmm_pinmux>; - interrupts = <74 8>; - #interrupt-cells = <2>; - interrupt-controller; - #address-cells = <1>; - #size-cells = <0>; - - pm8921_gpio: gpio@150 { - - compatible = "qcom,pm8921-gpio", - "qcom,ssbi-gpio"; - reg = <0x150>; - interrupt-controller; - #interrupt-cells = <2>; - gpio-controller; - gpio-ranges = <&pm8921_gpio 0 0 44>; - #gpio-cells = <2>; - - }; - - pm8921_mpps: mpps@50 { - compatible = "qcom,pm8921-mpp", - "qcom,ssbi-mpp"; - reg = <0x50>; - gpio-controller; - #gpio-cells = <2>; - gpio-ranges = <&pm8921_mpps 0 0 12>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - rtc@11d { - compatible = "qcom,pm8921-rtc"; - interrupt-parent = <&pmicintc>; - interrupts = <39 1>; - reg = <0x11d>; - allow-set-time; - }; - - pwrkey@1c { - compatible = "qcom,pm8921-pwrkey"; - reg = <0x1c>; - interrupt-parent = <&pmicintc>; - interrupts = <50 1>, <51 1>; - debounce = <15625>; - pull-up; - }; - - xoadc: xoadc@197 { - compatible = "qcom,pm8921-adc"; - reg = <197>; - interrupts-extended = <&pmicintc 78 IRQ_TYPE_EDGE_RISING>; - #address-cells = <2>; - #size-cells = <0>; - #io-channel-cells = <2>; - - vcoin: adc-channel@0 { - reg = <0x00 0x00>; - }; - vbat: adc-channel@1 { - reg = <0x00 0x01>; - }; - dcin: adc-channel@2 { - reg = <0x00 0x02>; - }; - vph_pwr: adc-channel@4 { - reg = <0x00 0x04>; - }; - batt_therm: adc-channel@8 { - reg = <0x00 0x08>; - }; - batt_id: adc-channel@9 { - reg = <0x00 0x09>; - }; - usb_vbus: adc-channel@a { - reg = <0x00 0x0a>; - }; - die_temp: adc-channel@b { - reg = <0x00 0x0b>; - }; - ref_625mv: adc-channel@c { - reg = <0x00 0x0c>; - }; - ref_1250mv: adc-channel@d { - reg = <0x00 0x0d>; - }; - chg_temp: adc-channel@e { - reg = <0x00 0x0e>; - }; - ref_muxoff: adc-channel@f { - reg = <0x00 0x0f>; - }; - }; - }; }; qfprom: qfprom@700000 { @@ -891,60 +757,6 @@ clocks = <&pxo_board>, <&cxo_board>; clock-names = "pxo", "cxo"; }; - - regulators { - compatible = "qcom,rpm-pm8921-regulators"; - - pm8921_s1: s1 {}; - pm8921_s2: s2 {}; - pm8921_s3: s3 {}; - pm8921_s4: s4 {}; - pm8921_s7: s7 {}; - pm8921_s8: s8 {}; - - pm8921_l1: l1 {}; - pm8921_l2: l2 {}; - pm8921_l3: l3 {}; - pm8921_l4: l4 {}; - pm8921_l5: l5 {}; - pm8921_l6: l6 {}; - pm8921_l7: l7 {}; - pm8921_l8: l8 {}; - pm8921_l9: l9 {}; - pm8921_l10: l10 {}; - pm8921_l11: l11 {}; - pm8921_l12: l12 {}; - pm8921_l14: l14 {}; - pm8921_l15: l15 {}; - pm8921_l16: l16 {}; - pm8921_l17: l17 {}; - pm8921_l18: l18 {}; - pm8921_l21: l21 {}; - pm8921_l22: l22 {}; - pm8921_l23: l23 {}; - pm8921_l24: l24 {}; - pm8921_l25: l25 {}; - pm8921_l26: l26 {}; - pm8921_l27: l27 {}; - pm8921_l28: l28 {}; - pm8921_l29: l29 {}; - - pm8921_lvs1: lvs1 {}; - pm8921_lvs2: lvs2 {}; - pm8921_lvs3: lvs3 {}; - pm8921_lvs4: lvs4 {}; - pm8921_lvs5: lvs5 {}; - pm8921_lvs6: lvs6 {}; - pm8921_lvs7: lvs7 {}; - - pm8921_usb_switch: usb-switch {}; - - pm8921_hdmi_switch: hdmi-switch { - bias-pull-down; - }; - - pm8921_ncp: ncp {}; - }; }; usb1: usb@12500000 { @@ -1472,7 +1284,7 @@ qcom,ncb = <3>; }; - pcie: pci@1b500000 { + pcie: pcie@1b500000 { compatible = "qcom,pcie-apq8064"; reg = <0x1b500000 0x1000>, <0x1b502000 0x80>, @@ -1623,10 +1435,6 @@ memory-region = <&wcnss_mem>; - vddcx-supply = <&pm8921_s3>; - vddmx-supply = <&pm8921_l24>; - vddpx-supply = <&pm8921_s4>; - status = "disabled"; iris { @@ -1634,11 +1442,6 @@ clocks = <&cxo_board>; clock-names = "xo"; - - vddxo-supply = <&pm8921_l4>; - vddrfa-supply = <&pm8921_s2>; - vddpa-supply = <&pm8921_l10>; - vdddig-supply = <&pm8921_lvs2>; }; smd-edge { diff --git a/arch/arm/boot/dts/qcom/qcom-apq8074-dragonboard.dts b/arch/arm/boot/dts/qcom/qcom-apq8074-dragonboard.dts index 6d1b2439ae3ace..6fce0112361f89 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8074-dragonboard.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8074-dragonboard.dts @@ -4,8 +4,8 @@ #include #include #include "qcom-msm8974.dtsi" -#include "qcom-pm8841.dtsi" -#include "qcom-pm8941.dtsi" +#include "pm8841.dtsi" +#include "pm8941.dtsi" /delete-node/ &mpss_region; @@ -49,6 +49,33 @@ no-map; }; }; + + vreg_boost: vreg-boost { + compatible = "regulator-fixed"; + + regulator-name = "vreg-boost"; + regulator-min-microvolt = <3150000>; + regulator-max-microvolt = <3150000>; + + regulator-always-on; + regulator-boot-on; + + gpio = <&pm8941_gpios 21 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-names = "default"; + pinctrl-0 = <&boost_bypass_n_pin>; + }; + + vreg_vph_pwr: vreg-vph-pwr { + compatible = "regulator-fixed"; + regulator-name = "vph-pwr"; + + regulator-min-microvolt = <3600000>; + regulator-max-microvolt = <3600000>; + + regulator-always-on; + }; }; &blsp1_uart2 { @@ -403,6 +430,10 @@ pinctrl-1 = <&sdc2_off>; }; +&smbb { + status = "okay"; +}; + &tlmm { sdc1_on: sdc1-on-state { clk-pins { diff --git a/arch/arm/boot/dts/qcom/qcom-apq8084-ifc6540.dts b/arch/arm/boot/dts/qcom/qcom-apq8084-ifc6540.dts index 116e59a3b76d01..1df24c922be9f3 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8084-ifc6540.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8084-ifc6540.dts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 #include "qcom-apq8084.dtsi" -#include "qcom-pma8084.dtsi" +#include "pma8084.dtsi" / { model = "Qualcomm APQ8084/IFC6540"; diff --git a/arch/arm/boot/dts/qcom/qcom-apq8084-mtp.dts b/arch/arm/boot/dts/qcom/qcom-apq8084-mtp.dts index c6b6680248a69e..d4e6aee034afd1 100644 --- a/arch/arm/boot/dts/qcom/qcom-apq8084-mtp.dts +++ b/arch/arm/boot/dts/qcom/qcom-apq8084-mtp.dts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 #include "qcom-apq8084.dtsi" -#include "qcom-pma8084.dtsi" +#include "pma8084.dtsi" / { model = "Qualcomm APQ 8084-MTP"; diff --git a/arch/arm/boot/dts/qcom/qcom-ipq4019-ap.dk04.1.dtsi b/arch/arm/boot/dts/qcom/qcom-ipq4019-ap.dk04.1.dtsi index 468ebc40d2ad38..374af6dd360a72 100644 --- a/arch/arm/boot/dts/qcom/qcom-ipq4019-ap.dk04.1.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-ipq4019-ap.dk04.1.dtsi @@ -98,7 +98,7 @@ }; }; - pci@40000000 { + pcie@40000000 { status = "okay"; perst-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>; }; diff --git a/arch/arm/boot/dts/qcom/qcom-ipq4019.dtsi b/arch/arm/boot/dts/qcom/qcom-ipq4019.dtsi index 9844e0b7cff99f..f989bd741cd185 100644 --- a/arch/arm/boot/dts/qcom/qcom-ipq4019.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-ipq4019.dtsi @@ -224,7 +224,7 @@ }; sdhci: mmc@7824900 { - compatible = "qcom,sdhci-msm-v4"; + compatible = "qcom,ipq4019-sdhci", "qcom,sdhci-msm-v4"; reg = <0x7824900 0x11c>, <0x7824000 0x800>; reg-names = "hc", "core"; interrupts = , ; @@ -417,7 +417,7 @@ reg = <0x4ab000 0x4>; }; - pcie0: pci@40000000 { + pcie0: pcie@40000000 { compatible = "qcom,pcie-ipq4019"; reg = <0x40000000 0xf1d>, <0x40000f20 0xa8>, diff --git a/arch/arm/boot/dts/qcom/qcom-ipq8064.dtsi b/arch/arm/boot/dts/qcom/qcom-ipq8064.dtsi index 6198f42f6a9c7f..6a7f4dd0f775be 100644 --- a/arch/arm/boot/dts/qcom/qcom-ipq8064.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-ipq8064.dtsi @@ -366,7 +366,7 @@ }; }; - qcom,ssbi@500000 { + ssbi@500000 { compatible = "qcom,ssbi"; reg = <0x00500000 0x1000>; qcom,controller-type = "pmic-arbiter"; @@ -1076,7 +1076,7 @@ status = "disabled"; }; - pcie0: pci@1b500000 { + pcie0: pcie@1b500000 { compatible = "qcom,pcie-ipq8064"; reg = <0x1b500000 0x1000 0x1b502000 0x80 @@ -1127,7 +1127,7 @@ perst-gpios = <&qcom_pinmux 3 GPIO_ACTIVE_LOW>; }; - pcie1: pci@1b700000 { + pcie1: pcie@1b700000 { compatible = "qcom,pcie-ipq8064"; reg = <0x1b700000 0x1000 0x1b702000 0x80 @@ -1178,7 +1178,7 @@ perst-gpios = <&qcom_pinmux 48 GPIO_ACTIVE_LOW>; }; - pcie2: pci@1b900000 { + pcie2: pcie@1b900000 { compatible = "qcom,pcie-ipq8064"; reg = <0x1b900000 0x1000 0x1b902000 0x80 diff --git a/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548-mangoh-green.dts b/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548-mangoh-green.dts index b269fdca1460c8..e3b4b93c3d3861 100644 --- a/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548-mangoh-green.dts +++ b/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548-mangoh-green.dts @@ -6,11 +6,11 @@ * Author : Neil Armstrong */ +#include #include +#include #include "qcom-mdm9615-wp8548.dtsi" -#include -#include / { model = "MangOH Green with WP8548 Module"; diff --git a/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548.dtsi b/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548.dtsi index 92c8003dac252d..0dd52cac0e2e27 100644 --- a/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-mdm9615-wp8548.dtsi @@ -7,6 +7,7 @@ */ #include "qcom-mdm9615.dtsi" +#include "pm8018.dtsi" / { model = "Sierra Wireless WP8548 Module"; @@ -76,7 +77,11 @@ }; }; -&pmicgpio { +&pm8018 { + interrupts-extended = <&intc GIC_PPI 226 IRQ_TYPE_LEVEL_HIGH>; +}; + +&pm8018_gpio { usb_vbus_5v_pins: usb-vbus-5v-state { pins = "gpio4"; function = "normal"; @@ -129,6 +134,142 @@ pinctrl-names = "default"; }; +&rpm { + regulators { + compatible = "qcom,rpm-pm8018-regulators"; + + vin_lvs1-supply = <&pm8018_s3>; + + vdd_l7-supply = <&pm8018_s4>; + vdd_l8-supply = <&pm8018_s3>; + vdd_l9_l10_l11_l12-supply = <&pm8018_s5>; + + /* Buck SMPS */ + pm8018_s1: s1 { + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1150000>; + qcom,switch-mode-frequency = <1600000>; + bias-pull-down; + }; + + pm8018_s2: s2 { + regulator-min-microvolt = <1225000>; + regulator-max-microvolt = <1300000>; + qcom,switch-mode-frequency = <1600000>; + bias-pull-down; + }; + + pm8018_s3: s3 { + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,switch-mode-frequency = <1600000>; + bias-pull-down; + }; + + pm8018_s4: s4 { + regulator-min-microvolt = <2100000>; + regulator-max-microvolt = <2200000>; + qcom,switch-mode-frequency = <1600000>; + bias-pull-down; + }; + + pm8018_s5: s5 { + regulator-always-on; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + qcom,switch-mode-frequency = <1600000>; + bias-pull-down; + }; + + /* PMOS LDO */ + pm8018_l2: l2 { + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + bias-pull-down; + }; + + pm8018_l3: l3 { + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + bias-pull-down; + }; + + pm8018_l4: l4 { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + bias-pull-down; + }; + + pm8018_l5: l5 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + bias-pull-down; + }; + + pm8018_l6: l6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2850000>; + bias-pull-down; + }; + + pm8018_l7: l7 { + regulator-min-microvolt = <1850000>; + regulator-max-microvolt = <1900000>; + bias-pull-down; + }; + + pm8018_l8: l8 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + bias-pull-down; + }; + + pm8018_l9: l9 { + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <1150000>; + bias-pull-down; + }; + + pm8018_l10: l10 { + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + bias-pull-down; + }; + + pm8018_l11: l11 { + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + bias-pull-down; + }; + + pm8018_l12: l12 { + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + bias-pull-down; + }; + + pm8018_l13: l13 { + regulator-min-microvolt = <1850000>; + regulator-max-microvolt = <2950000>; + bias-pull-down; + }; + + pm8018_l14: l14 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + bias-pull-down; + }; + + /* Low Voltage Switch */ + pm8018_lvs1: lvs1 { + bias-pull-down; + }; + }; +}; + &sdcc1 { status = "okay"; }; diff --git a/arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi b/arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi index 63e21aa2364292..34c60994d02634 100644 --- a/arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-mdm9615.dtsi @@ -256,57 +256,10 @@ }; }; - qcom,ssbi@500000 { + ssbi: ssbi@500000 { compatible = "qcom,ssbi"; reg = <0x500000 0x1000>; qcom,controller-type = "pmic-arbiter"; - - pmicintc: pmic { - compatible = "qcom,pm8018", "qcom,pm8921"; - interrupts = ; - #interrupt-cells = <2>; - interrupt-controller; - #address-cells = <1>; - #size-cells = <0>; - - pwrkey@1c { - compatible = "qcom,pm8018-pwrkey", "qcom,pm8921-pwrkey"; - reg = <0x1c>; - interrupt-parent = <&pmicintc>; - interrupts = <50 IRQ_TYPE_EDGE_RISING>, - <51 IRQ_TYPE_EDGE_RISING>; - debounce = <15625>; - pull-up; - }; - - pmicmpp: mpps@50 { - compatible = "qcom,pm8018-mpp", "qcom,ssbi-mpp"; - interrupt-controller; - #interrupt-cells = <2>; - reg = <0x50>; - gpio-controller; - #gpio-cells = <2>; - gpio-ranges = <&pmicmpp 0 0 6>; - }; - - rtc@11d { - compatible = "qcom,pm8018-rtc", "qcom,pm8921-rtc"; - interrupt-parent = <&pmicintc>; - interrupts = <39 IRQ_TYPE_EDGE_RISING>; - reg = <0x11d>; - allow-set-time; - }; - - pmicgpio: gpio@150 { - compatible = "qcom,pm8018-gpio", "qcom,ssbi-gpio"; - reg = <0x150>; - interrupt-controller; - #interrupt-cells = <2>; - gpio-controller; - gpio-ranges = <&pmicgpio 0 0 6>; - #gpio-cells = <2>; - }; - }; }; sdcc1bam: dma-controller@12182000 { @@ -383,140 +336,6 @@ , ; interrupt-names = "ack", "err", "wakeup"; - - regulators { - compatible = "qcom,rpm-pm8018-regulators"; - - vin_lvs1-supply = <&pm8018_s3>; - - vdd_l7-supply = <&pm8018_s4>; - vdd_l8-supply = <&pm8018_s3>; - vdd_l9_l10_l11_l12-supply = <&pm8018_s5>; - - /* Buck SMPS */ - pm8018_s1: s1 { - regulator-min-microvolt = <500000>; - regulator-max-microvolt = <1150000>; - qcom,switch-mode-frequency = <1600000>; - bias-pull-down; - }; - - pm8018_s2: s2 { - regulator-min-microvolt = <1225000>; - regulator-max-microvolt = <1300000>; - qcom,switch-mode-frequency = <1600000>; - bias-pull-down; - }; - - pm8018_s3: s3 { - regulator-always-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - qcom,switch-mode-frequency = <1600000>; - bias-pull-down; - }; - - pm8018_s4: s4 { - regulator-min-microvolt = <2100000>; - regulator-max-microvolt = <2200000>; - qcom,switch-mode-frequency = <1600000>; - bias-pull-down; - }; - - pm8018_s5: s5 { - regulator-always-on; - regulator-min-microvolt = <1350000>; - regulator-max-microvolt = <1350000>; - qcom,switch-mode-frequency = <1600000>; - bias-pull-down; - }; - - /* PMOS LDO */ - pm8018_l2: l2 { - regulator-always-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - bias-pull-down; - }; - - pm8018_l3: l3 { - regulator-always-on; - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - bias-pull-down; - }; - - pm8018_l4: l4 { - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - bias-pull-down; - }; - - pm8018_l5: l5 { - regulator-min-microvolt = <2850000>; - regulator-max-microvolt = <2850000>; - bias-pull-down; - }; - - pm8018_l6: l6 { - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <2850000>; - bias-pull-down; - }; - - pm8018_l7: l7 { - regulator-min-microvolt = <1850000>; - regulator-max-microvolt = <1900000>; - bias-pull-down; - }; - - pm8018_l8: l8 { - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1200000>; - bias-pull-down; - }; - - pm8018_l9: l9 { - regulator-min-microvolt = <750000>; - regulator-max-microvolt = <1150000>; - bias-pull-down; - }; - - pm8018_l10: l10 { - regulator-min-microvolt = <1050000>; - regulator-max-microvolt = <1050000>; - bias-pull-down; - }; - - pm8018_l11: l11 { - regulator-min-microvolt = <1050000>; - regulator-max-microvolt = <1050000>; - bias-pull-down; - }; - - pm8018_l12: l12 { - regulator-min-microvolt = <1050000>; - regulator-max-microvolt = <1050000>; - bias-pull-down; - }; - - pm8018_l13: l13 { - regulator-min-microvolt = <1850000>; - regulator-max-microvolt = <2950000>; - bias-pull-down; - }; - - pm8018_l14: l14 { - regulator-min-microvolt = <2850000>; - regulator-max-microvolt = <2850000>; - bias-pull-down; - }; - - /* Low Voltage Switch */ - pm8018_lvs1: lvs1 { - bias-pull-down; - }; - }; }; }; }; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8226-microsoft-common.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8226-microsoft-common.dtsi new file mode 100644 index 00000000000000..525d8c608b06fb --- /dev/null +++ b/arch/arm/boot/dts/qcom/qcom-msm8226-microsoft-common.dtsi @@ -0,0 +1,327 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Common Board Device Tree for Microsoft MSM8x26-based Lumias + * + * Copyright (c) 2023, Jack Matthews + * Copyright (c) 2023, Ivaylo Ivanov + * Copyright (c) 2023, Dominik Kobinski + * Copyright (c) 2023, Rayyan Ansari + */ + +#include "qcom-msm8226.dtsi" +#include "pm8226.dtsi" +#include + +/* + * Delete all generic (msm8226.dtsi) reserved + * memory mappings which are different on these devices. + */ +/delete-node/ &smem_region; + +/ { + aliases { + mmc0 = &sdhc_1; /* eMMC */ + mmc1 = &sdhc_2; /* microSD */ + display0 = &framebuffer; + }; + + chosen { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + stdout-path = "display0"; + + framebuffer: framebuffer@3200000 { + compatible = "simple-framebuffer"; + reg = <0x3200000 0x800000>; + format = "a8r8g8b8"; + width = <720>; + height = <1280>; + stride = <(720 * 4)>; + + clocks = <&mmcc MDSS_AHB_CLK>, + <&mmcc MDSS_AXI_CLK>, + <&mmcc MDSS_BYTE0_CLK>, + <&mmcc MDSS_MDP_CLK>, + <&mmcc MDSS_PCLK0_CLK>, + <&mmcc MDSS_VSYNC_CLK>; + power-domains = <&mmcc MDSS_GDSC>; + }; + }; + + gpio_keys: gpio-keys { + compatible = "gpio-keys"; + + pinctrl-0 = <&gpio_keys_default>; + pinctrl-names = "default"; + + label = "GPIO Buttons"; + + key-volume-up { + label = "Volume Up"; + gpios = <&tlmm 106 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + /* + * This device being a WP platform has a different + * memory layout than other Android based devices. + * This smem memory region is directly copied from + * the original UEFI firmware. + */ + reserved-memory { + display_reserved: framebuffer@3200000 { + reg = <0x03200000 0x800000>; + no-map; + }; + + smem_region: smem@fa00000 { + reg = <0x0fa00000 0x100000>; + no-map; + }; + }; +}; + +&blsp1_i2c5 { + status = "okay"; + + touchscreen: touchscreen@4b { + compatible = "syna,rmi4-i2c"; + reg = <0x4b>; + + interrupts-extended = <&tlmm 17 IRQ_TYPE_EDGE_FALLING>; + vdd-supply = <&pm8226_l15>; + vio-supply = <&pm8226_l6>; + + pinctrl-0 = <&touchscreen_default>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + rmi4-f01@1 { + reg = <0x01>; + syna,nosleep-mode = <1>; + }; + + rmi4-f11@11 { + reg = <0x11>; + syna,sensor-type = <1>; + }; + }; +}; + +&blsp1_uart3 { + status = "okay"; +}; + +&pm8226_resin { + linux,code = ; + status = "okay"; +}; + +&pm8226_vib { + status = "okay"; +}; + +&rpm_requests { + regulators { + compatible = "qcom,rpm-pm8226-regulators"; + + /* These values were taken from the original firmware DSDT */ + pm8226_s1: s1 { + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + }; + + pm8226_s3: s3 { + regulator-min-microvolt = <1300000>; + regulator-max-microvolt = <1300000>; + }; + + pm8226_s4: s4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2100000>; + }; + + pm8226_s5: s5 { + regulator-min-microvolt = <1150000>; + regulator-max-microvolt = <1150000>; + }; + + pm8226_l3: l3 { + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <1150000>; + }; + + pm8226_l4: l4 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + pm8226_l5: l5 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + pm8226_l6: l6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm8226_l7: l7 { + regulator-min-microvolt = <1850000>; + regulator-max-microvolt = <1850000>; + }; + + pm8226_l8: l8 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + pm8226_l9: l9 { + regulator-min-microvolt = <2050000>; + regulator-max-microvolt = <2050000>; + }; + + pm8226_l10: l10 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm8226_l12: l12 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm8226_l14: l14 { + regulator-min-microvolt = <2750000>; + regulator-max-microvolt = <2750000>; + }; + + pm8226_l15: l15 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + }; + + pm8226_l16: l16 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + }; + + pm8226_l17: l17 { + regulator-min-microvolt = <2950000>; + regulator-max-microvolt = <2950000>; + regulator-system-load = <200000>; + regulator-allow-set-load; + }; + + pm8226_l18: l18 { + regulator-min-microvolt = <2950000>; + regulator-max-microvolt = <2950000>; + regulator-system-load = <200000>; + regulator-allow-set-load; + }; + + pm8226_l19: l19 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + }; + + pm8226_l20: l20 { + regulator-min-microvolt = <3075000>; + regulator-max-microvolt = <3075000>; + }; + + pm8226_l21: l21 { + regulator-min-microvolt = <1850000>; + regulator-max-microvolt = <2950000>; + }; + + pm8226_l22: l22 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm8226_l23: l23 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm8226_l24: l24 { + regulator-min-microvolt = <1300000>; + regulator-max-microvolt = <1300000>; + }; + + pm8226_l25: l25 { + regulator-min-microvolt = <1775000>; + regulator-max-microvolt = <2075000>; + }; + + pm8226_l27: l27 { + regulator-min-microvolt = <2050000>; + regulator-max-microvolt = <2050000>; + }; + + pm8226_l28: l28 { + regulator-min-microvolt = <2000000>; + regulator-max-microvolt = <3000000>; + }; + }; +}; + +&sdhc_1 { + vmmc-supply = <&pm8226_l17>; + vqmmc-supply = <&pm8226_l6>; + + status = "okay"; +}; + +&sdhc_2 { + vmmc-supply = <&pm8226_l18>; + vqmmc-supply = <&pm8226_l21>; + + status = "okay"; +}; + +&usb { + extcon = <&smbb>; + dr_mode = "peripheral"; + + status = "okay"; +}; + +&usb_hs_phy { + extcon = <&smbb>; + v1p8-supply = <&pm8226_l10>; + v3p3-supply = <&pm8226_l20>; +}; + +&tlmm { + gpio_keys_default: gpio-keys-default-state { + pins = "gpio106", "gpio107", "gpio108"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + + touchscreen_default: touchscreen-default-state { + irq-pins { + pins = "gpio17"; + function = "gpio"; + drive-strength = <8>; + bias-pull-up; + }; + + reset-pins { + pins = "gpio16"; + function = "gpio"; + drive-strength = <8>; + bias-disable; + output-high; + }; + }; +}; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8226-microsoft-dempsey.dts b/arch/arm/boot/dts/qcom/qcom-msm8226-microsoft-dempsey.dts new file mode 100644 index 00000000000000..2c664b5934ec54 --- /dev/null +++ b/arch/arm/boot/dts/qcom/qcom-msm8226-microsoft-dempsey.dts @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2023, Jack Matthews + * Copyright (c) 2023, Ivaylo Ivanov + * Copyright (c) 2023, Dominik Kobinski + * Copyright (c) 2023, Rayyan Ansari + */ + +/dts-v1/; + +#include "qcom-msm8226-microsoft-common.dtsi" + +/ { + model = "Microsoft Lumia 640"; + compatible = "microsoft,dempsey", "qcom,msm8226"; + chassis-type = "handset"; +}; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8226-microsoft-makepeace.dts b/arch/arm/boot/dts/qcom/qcom-msm8226-microsoft-makepeace.dts new file mode 100644 index 00000000000000..731c5c37567846 --- /dev/null +++ b/arch/arm/boot/dts/qcom/qcom-msm8226-microsoft-makepeace.dts @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2023, Jack Matthews + * Copyright (c) 2023, Ivaylo Ivanov + * Copyright (c) 2023, Dominik Kobinski + * Copyright (c) 2023, Rayyan Ansari + */ + +/dts-v1/; + +#include "qcom-msm8226-microsoft-common.dtsi" + +/ { + model = "Microsoft Lumia 640 XL"; + compatible = "microsoft,makepeace", "qcom,msm8226"; + chassis-type = "handset"; +}; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8226-microsoft-moneypenny.dts b/arch/arm/boot/dts/qcom/qcom-msm8226-microsoft-moneypenny.dts new file mode 100644 index 00000000000000..992b7115b5f8f5 --- /dev/null +++ b/arch/arm/boot/dts/qcom/qcom-msm8226-microsoft-moneypenny.dts @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2023, Jack Matthews + * Copyright (c) 2023, Ivaylo Ivanov + * Copyright (c) 2023, Dominik Kobinski + * Copyright (c) 2023, Rayyan Ansari + */ + +/dts-v1/; + +#include "qcom-msm8226-microsoft-common.dtsi" + +/ { + model = "Nokia Lumia 630"; + compatible = "microsoft,moneypenny", "qcom,msm8226"; + chassis-type = "handset"; +}; + +&framebuffer { + width = <480>; + height = <854>; + stride = <(480 * 4)>; +}; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8226.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8226.dtsi index 97a377b5a0ecaf..b492c95e5d301d 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8226.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-msm8226.dtsi @@ -442,8 +442,8 @@ <&gcc GPLL0_VOTE>, <&gcc GPLL1_VOTE>, <&rpmcc RPM_SMD_GFX3D_CLK_SRC>, - <0>, - <0>; + <&mdss_dsi0_phy 1>, + <&mdss_dsi0_phy 0>; clock-names = "xo", "mmss_gpll0_vote", "gpll0_vote", @@ -875,8 +875,8 @@ offset = <0x65c>; mode-bootloader = <0x77665500>; - mode-normal = <0x77665501>; - mode-recovery = <0x77665502>; + mode-normal = <0x77665501>; + mode-recovery = <0x77665502>; }; }; @@ -1006,6 +1006,46 @@ "ref"; }; }; + + gpu: adreno@fdb00000 { + compatible = "qcom,adreno-305.18", "qcom,adreno"; + reg = <0xfdb00000 0x10000>; + reg-names = "kgsl_3d0_reg_memory"; + + interrupts = ; + interrupt-names = "kgsl_3d0_irq"; + + clocks = <&mmcc OXILI_GFX3D_CLK>, + <&mmcc OXILICX_AHB_CLK>, + <&mmcc OXILICX_AXI_CLK>; + clock-names = "core", "iface", "mem_iface"; + + sram = <&gmu_sram>; + power-domains = <&mmcc OXILICX_GDSC>; + operating-points-v2 = <&gpu_opp_table>; + + status = "disabled"; + + gpu_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-450000000 { + opp-hz = /bits/ 64 <450000000>; + }; + + opp-320000000 { + opp-hz = /bits/ 64 <320000000>; + }; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + }; + + opp-19000000 { + opp-hz = /bits/ 64 <19000000>; + }; + }; + }; }; thermal-zones { diff --git a/arch/arm/boot/dts/qcom/qcom-msm8660-surf.dts b/arch/arm/boot/dts/qcom/qcom-msm8660-surf.dts index be18f1be29a17c..69fe651f564d25 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8660-surf.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8660-surf.dts @@ -2,6 +2,7 @@ #include #include "qcom-msm8660.dtsi" +#include "pm8058.dtsi" / { model = "Qualcomm MSM8660 SURF"; @@ -35,30 +36,42 @@ }; &pm8058 { - keypad@148 { - linux,keymap = < - MATRIX_KEY(0, 0, KEY_FN_F1) - MATRIX_KEY(0, 1, KEY_UP) - MATRIX_KEY(0, 2, KEY_LEFT) - MATRIX_KEY(0, 3, KEY_VOLUMEUP) - MATRIX_KEY(1, 0, KEY_FN_F2) - MATRIX_KEY(1, 1, KEY_RIGHT) - MATRIX_KEY(1, 2, KEY_DOWN) - MATRIX_KEY(1, 3, KEY_VOLUMEDOWN) - MATRIX_KEY(2, 3, KEY_ENTER) - MATRIX_KEY(4, 0, KEY_CAMERA_FOCUS) - MATRIX_KEY(4, 1, KEY_UP) - MATRIX_KEY(4, 2, KEY_LEFT) - MATRIX_KEY(4, 3, KEY_HOME) - MATRIX_KEY(4, 4, KEY_FN_F3) - MATRIX_KEY(5, 0, KEY_CAMERA) - MATRIX_KEY(5, 1, KEY_RIGHT) - MATRIX_KEY(5, 2, KEY_DOWN) - MATRIX_KEY(5, 3, KEY_BACK) - MATRIX_KEY(5, 4, KEY_MENU) - >; - keypad,num-rows = <6>; - keypad,num-columns = <5>; + interrupts-extended = <&tlmm 88 IRQ_TYPE_LEVEL_LOW>; +}; + +&pm8058_keypad { + linux,keymap = < + MATRIX_KEY(0, 0, KEY_FN_F1) + MATRIX_KEY(0, 1, KEY_UP) + MATRIX_KEY(0, 2, KEY_LEFT) + MATRIX_KEY(0, 3, KEY_VOLUMEUP) + MATRIX_KEY(1, 0, KEY_FN_F2) + MATRIX_KEY(1, 1, KEY_RIGHT) + MATRIX_KEY(1, 2, KEY_DOWN) + MATRIX_KEY(1, 3, KEY_VOLUMEDOWN) + MATRIX_KEY(2, 3, KEY_ENTER) + MATRIX_KEY(4, 0, KEY_CAMERA_FOCUS) + MATRIX_KEY(4, 1, KEY_UP) + MATRIX_KEY(4, 2, KEY_LEFT) + MATRIX_KEY(4, 3, KEY_HOME) + MATRIX_KEY(4, 4, KEY_FN_F3) + MATRIX_KEY(5, 0, KEY_CAMERA) + MATRIX_KEY(5, 1, KEY_RIGHT) + MATRIX_KEY(5, 2, KEY_DOWN) + MATRIX_KEY(5, 3, KEY_BACK) + MATRIX_KEY(5, 4, KEY_MENU) + >; + keypad,num-rows = <6>; + keypad,num-columns = <5>; +}; + +&rpm { + regulators-0 { + compatible = "qcom,rpm-pm8901-regulators"; + }; + + regulators-1 { + compatible = "qcom,rpm-pm8058-regulators"; }; }; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8660.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8660.dtsi index 78023ed2fdf71f..a7c245b9c8f973 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8660.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-msm8660.dtsi @@ -73,22 +73,6 @@ }; }; - /* - * These channels from the ADC are simply hardware monitors. - * That is why the ADC is referred to as "HKADC" - HouseKeeping - * ADC. - */ - iio-hwmon { - compatible = "iio-hwmon"; - io-channels = <&xoadc 0x00 0x01>, /* Battery */ - <&xoadc 0x00 0x02>, /* DC in (charger) */ - <&xoadc 0x00 0x04>, /* VPH the main system voltage */ - <&xoadc 0x00 0x0b>, /* Die temperature */ - <&xoadc 0x00 0x0c>, /* Reference voltage 1.25V */ - <&xoadc 0x00 0x0d>, /* Reference voltage 0.625V */ - <&xoadc 0x00 0x0e>; /* Reference voltage 0.325V */ - }; - soc: soc { #address-cells = <1>; #size-cells = <1>; @@ -334,143 +318,10 @@ status = "disabled"; }; - ssbi@500000 { + ssbi: ssbi@500000 { compatible = "qcom,ssbi"; reg = <0x500000 0x1000>; qcom,controller-type = "pmic-arbiter"; - - pm8058: pmic { - compatible = "qcom,pm8058"; - interrupt-parent = <&tlmm>; - interrupts = <88 8>; - #interrupt-cells = <2>; - interrupt-controller; - #address-cells = <1>; - #size-cells = <0>; - - pm8058_gpio: gpio@150 { - compatible = "qcom,pm8058-gpio", - "qcom,ssbi-gpio"; - reg = <0x150>; - interrupt-controller; - #interrupt-cells = <2>; - gpio-controller; - gpio-ranges = <&pm8058_gpio 0 0 44>; - #gpio-cells = <2>; - - }; - - pm8058_mpps: mpps@50 { - compatible = "qcom,pm8058-mpp", - "qcom,ssbi-mpp"; - reg = <0x50>; - gpio-controller; - #gpio-cells = <2>; - gpio-ranges = <&pm8058_mpps 0 0 12>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - pwrkey@1c { - compatible = "qcom,pm8058-pwrkey"; - reg = <0x1c>; - interrupt-parent = <&pm8058>; - interrupts = <50 1>, <51 1>; - debounce = <15625>; - pull-up; - }; - - pm8058_keypad: keypad@148 { - compatible = "qcom,pm8058-keypad"; - reg = <0x148>; - interrupt-parent = <&pm8058>; - interrupts = <74 1>, <75 1>; - debounce = <15>; - scan-delay = <32>; - row-hold = <91500>; - }; - - xoadc: xoadc@197 { - compatible = "qcom,pm8058-adc"; - reg = <0x197>; - interrupts-extended = <&pm8058 76 IRQ_TYPE_EDGE_RISING>; - #address-cells = <2>; - #size-cells = <0>; - #io-channel-cells = <2>; - - vcoin: adc-channel@0 { - reg = <0x00 0x00>; - }; - vbat: adc-channel@1 { - reg = <0x00 0x01>; - }; - dcin: adc-channel@2 { - reg = <0x00 0x02>; - }; - ichg: adc-channel@3 { - reg = <0x00 0x03>; - }; - vph_pwr: adc-channel@4 { - reg = <0x00 0x04>; - }; - usb_vbus: adc-channel@a { - reg = <0x00 0x0a>; - }; - die_temp: adc-channel@b { - reg = <0x00 0x0b>; - }; - ref_625mv: adc-channel@c { - reg = <0x00 0x0c>; - }; - ref_1250mv: adc-channel@d { - reg = <0x00 0x0d>; - }; - ref_325mv: adc-channel@e { - reg = <0x00 0x0e>; - }; - ref_muxoff: adc-channel@f { - reg = <0x00 0x0f>; - }; - }; - - rtc@1e8 { - compatible = "qcom,pm8058-rtc"; - reg = <0x1e8>; - interrupt-parent = <&pm8058>; - interrupts = <39 1>; - allow-set-time; - }; - - vibrator@4a { - compatible = "qcom,pm8058-vib"; - reg = <0x4a>; - }; - - pm8058_led48: led@48 { - compatible = "qcom,pm8058-keypad-led"; - reg = <0x48>; - status = "disabled"; - }; - - pm8058_led131: led@131 { - compatible = "qcom,pm8058-led"; - reg = <0x131>; - status = "disabled"; - }; - - pm8058_led132: led@132 { - compatible = "qcom,pm8058-led"; - reg = <0x132>; - status = "disabled"; - }; - - pm8058_led133: led@133 { - compatible = "qcom,pm8058-led"; - reg = <0x133>; - status = "disabled"; - }; - - }; }; l2cc: clock-controller@2082000 { @@ -496,72 +347,6 @@ clocks = <&pxo_board>; clock-names = "pxo"; }; - - regulators-0 { - compatible = "qcom,rpm-pm8901-regulators"; - - pm8901_l0: l0 {}; - pm8901_l1: l1 {}; - pm8901_l2: l2 {}; - pm8901_l3: l3 {}; - pm8901_l4: l4 {}; - pm8901_l5: l5 {}; - pm8901_l6: l6 {}; - - /* S0 and S1 Handled as SAW regulators by SPM */ - pm8901_s2: s2 {}; - pm8901_s3: s3 {}; - pm8901_s4: s4 {}; - - pm8901_lvs0: lvs0 {}; - pm8901_lvs1: lvs1 {}; - pm8901_lvs2: lvs2 {}; - pm8901_lvs3: lvs3 {}; - - pm8901_mvs: mvs {}; - }; - - regulators-1 { - compatible = "qcom,rpm-pm8058-regulators"; - - pm8058_l0: l0 {}; - pm8058_l1: l1 {}; - pm8058_l2: l2 {}; - pm8058_l3: l3 {}; - pm8058_l4: l4 {}; - pm8058_l5: l5 {}; - pm8058_l6: l6 {}; - pm8058_l7: l7 {}; - pm8058_l8: l8 {}; - pm8058_l9: l9 {}; - pm8058_l10: l10 {}; - pm8058_l11: l11 {}; - pm8058_l12: l12 {}; - pm8058_l13: l13 {}; - pm8058_l14: l14 {}; - pm8058_l15: l15 {}; - pm8058_l16: l16 {}; - pm8058_l17: l17 {}; - pm8058_l18: l18 {}; - pm8058_l19: l19 {}; - pm8058_l20: l20 {}; - pm8058_l21: l21 {}; - pm8058_l22: l22 {}; - pm8058_l23: l23 {}; - pm8058_l24: l24 {}; - pm8058_l25: l25 {}; - - pm8058_s0: s0 {}; - pm8058_s1: s1 {}; - pm8058_s2: s2 {}; - pm8058_s3: s3 {}; - pm8058_s4: s4 {}; - - pm8058_lvs0: lvs0 {}; - pm8058_lvs1: lvs1 {}; - - pm8058_ncp: ncp {}; - }; }; amba { diff --git a/arch/arm/boot/dts/qcom/qcom-msm8926-htc-memul.dts b/arch/arm/boot/dts/qcom/qcom-msm8926-htc-memul.dts new file mode 100644 index 00000000000000..ed328b24335f4b --- /dev/null +++ b/arch/arm/boot/dts/qcom/qcom-msm8926-htc-memul.dts @@ -0,0 +1,372 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2023, Luca Weiss + */ + +/dts-v1/; + +#include "qcom-msm8226.dtsi" +#include "pm8226.dtsi" + +/delete-node/ &adsp_region; +/delete-node/ &smem_region; + +/ { + model = "HTC One Mini 2"; + compatible = "htc,memul", "qcom,msm8926", "qcom,msm8226"; + chassis-type = "handset"; + + aliases { + mmc1 = &sdhc_2; /* SDC2 SD card slot */ + }; + + gpio-keys { + compatible = "gpio-keys"; + + key-power { + label = "Power"; + gpios = <&tlmm 106 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <15>; + }; + + key-volume-down { + label = "Volume Down"; + gpios = <&tlmm 107 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <15>; + }; + + key-volume-up { + label = "Volume Up"; + gpios = <&tlmm 108 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <15>; + }; + }; + + reserved-memory { + unknown@5b00000 { + reg = <0x05b00000 0x200000>; + no-map; + }; + + unknown@7500000 { + reg = <0x07500000 0xb00000>; + no-map; + }; + + mpss_region: mpss@8000000 { + reg = <0x08000000 0x4f00000>; + no-map; + }; + + unknown@cf00000 { + reg = <0x0cf00000 0x200000>; + no-map; + }; + + mba_region: mba@d100000 { + reg = <0x0d100000 0x3a000>; + no-map; + }; + + unknown@d13a000 { + reg = <0x0d13a000 0xc6000>; + no-map; + }; + + wcnss_region: wcnss@d200000 { + reg = <0x0d200000 0x650000>; + no-map; + }; + + unknown@d850000 { + reg = <0x0d850000 0x3b0000>; + no-map; + }; + + adsp_region: adsp@dc00000 { + reg = <0x0dc00000 0x1400000>; + no-map; + }; + + unknown@f000000 { + reg = <0x0f000000 0x500000>; + no-map; + }; + + venus_region: venus@f500000 { + reg = <0x0f500000 0x500000>; + no-map; + }; + + smem_region: smem@fa00000 { + reg = <0x0fa00000 0x100000>; + no-map; + }; + + unknown@fb00000 { + reg = <0x0fb00000 0x1b00000>; + no-map; + }; + }; +}; + +&adsp { + firmware-name = "qcom/msm8926/memul/adsp.mbn"; + status = "okay"; +}; + +&blsp1_i2c2 { + status = "okay"; + + magnetometer@d { + compatible = "asahi-kasei,ak8963"; + reg = <0x0d>; + interrupts-extended = <&tlmm 66 IRQ_TYPE_EDGE_RISING>; + vdd-supply = <&pm8226_l19>; + vid-supply = <&pm8226_l28>; + }; + + accelerometer@18 { + compatible = "bosch,bma250e"; + reg = <0x18>; + interrupts-extended = <&tlmm 63 IRQ_TYPE_EDGE_RISING>; + vdd-supply = <&pm8226_l19>; + vddio-supply = <&pm8226_l28>; + }; +}; + +&blsp1_i2c4 { + status = "okay"; + + /* TFA9887 @ 34 */ + /* TFA9887 @ 35 */ +}; + +&blsp1_i2c5 { + status = "okay"; + + touchscreen@20 { + compatible = "syna,rmi4-i2c"; + reg = <0x20>; + + interrupts-extended = <&tlmm 17 IRQ_TYPE_EDGE_FALLING>; + vdd-supply = <&pm8226_l19>; + + syna,startup-delay-ms = <160>; + + #address-cells = <1>; + #size-cells = <0>; + + rmi4-f01@1 { + reg = <0x1>; + syna,nosleep-mode = <1>; + }; + + rmi4-f12@12 { + reg = <0x12>; + syna,sensor-type = <1>; + }; + }; +}; + +&blsp1_i2c6 { + status = "okay"; + + /* NCP6924 Camera Regulators @ 10 */ + /* PN544 NFC @ 28 */ + /* TPS61310 Flash/Torch @ 33 */ +}; + +&pm8226_vib { + status = "okay"; +}; + +&rpm_requests { + regulators { + compatible = "qcom,rpm-pm8226-regulators"; + + pm8226_s3: s3 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1350000>; + }; + + pm8226_s4: s4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2200000>; + }; + + pm8226_s5: s5 { + regulator-min-microvolt = <1150000>; + regulator-max-microvolt = <1150000>; + }; + + pm8226_l1: l1 { + regulator-min-microvolt = <1225000>; + regulator-max-microvolt = <1225000>; + }; + + pm8226_l2: l2 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + pm8226_l3: l3 { + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <1337500>; + }; + + pm8226_l4: l4 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + pm8226_l5: l5 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + pm8226_l6: l6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm8226_l7: l7 { + regulator-min-microvolt = <1850000>; + regulator-max-microvolt = <1850000>; + }; + + pm8226_l8: l8 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm8226_l9: l9 { + regulator-min-microvolt = <2050000>; + regulator-max-microvolt = <2050000>; + }; + + pm8226_l10: l10 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm8226_l12: l12 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm8226_l14: l14 { + regulator-min-microvolt = <2750000>; + regulator-max-microvolt = <2750000>; + }; + + pm8226_l15: l15 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + }; + + pm8226_l16: l16 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3350000>; + }; + + pm8226_l17: l17 { + regulator-min-microvolt = <2950000>; + regulator-max-microvolt = <2950000>; + }; + + pm8226_l18: l18 { + regulator-min-microvolt = <2950000>; + regulator-max-microvolt = <2950000>; + }; + + pm8226_l19: l19 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + }; + + pm8226_l20: l20 { + regulator-min-microvolt = <3075000>; + regulator-max-microvolt = <3075000>; + }; + + pm8226_l21: l21 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2950000>; + regulator-allow-set-load; + }; + + pm8226_l22: l22 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2950000>; + }; + + pm8226_l23: l23 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3000000>; + }; + + pm8226_l24: l24 { + regulator-min-microvolt = <1300000>; + regulator-max-microvolt = <1350000>; + }; + + pm8226_l25: l25 { + regulator-min-microvolt = <1775000>; + regulator-max-microvolt = <2125000>; + }; + + pm8226_l26: l26 { + regulator-min-microvolt = <1225000>; + regulator-max-microvolt = <1225000>; + }; + + pm8226_l27: l27 { + regulator-min-microvolt = <2050000>; + regulator-max-microvolt = <2050000>; + }; + + pm8226_l28: l28 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm8226_lvs1: lvs1 {}; + }; +}; + +&sdhc_2 { + vmmc-supply = <&pm8226_l18>; + vqmmc-supply = <&pm8226_l21>; + + bus-width = <4>; + cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>; + + status = "okay"; +}; + +&smbb { + qcom,fast-charge-safe-current = <1750000>; + qcom,fast-charge-current-limit = <1750000>; + qcom,fast-charge-safe-voltage = <4360000>; + qcom,fast-charge-high-threshold-voltage = <4350000>; + qcom,auto-recharge-threshold-voltage = <4300000>; + qcom,minimum-input-voltage = <4300000>; + + status = "okay"; +}; + +&usb { + extcon = <&smbb>; + dr_mode = "peripheral"; + status = "okay"; +}; + +&usb_hs_phy { + extcon = <&smbb>; + v1p8-supply = <&pm8226_l10>; + v3p3-supply = <&pm8226_l20>; +}; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8926-microsoft-superman-lte.dts b/arch/arm/boot/dts/qcom/qcom-msm8926-microsoft-superman-lte.dts new file mode 100644 index 00000000000000..9b48661d69c538 --- /dev/null +++ b/arch/arm/boot/dts/qcom/qcom-msm8926-microsoft-superman-lte.dts @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2023, Jack Matthews + * Copyright (c) 2023, Ivaylo Ivanov + * Copyright (c) 2023, Dominik Kobinski + * Copyright (c) 2023, Rayyan Ansari + */ + +/dts-v1/; + +#include "qcom-msm8226-microsoft-common.dtsi" + +/* This device has touchscreen on i2c3 instead */ +/delete-node/ &touchscreen; + +/ { + model = "Nokia Lumia 735"; + compatible = "microsoft,superman-lte", "qcom,msm8926", "qcom,msm8226"; + chassis-type = "handset"; +}; + +&blsp1_i2c3 { + status = "okay"; + + touchscreen: touchscreen@4b { + compatible = "syna,rmi4-i2c"; + reg = <0x4b>; + + interrupts-extended = <&tlmm 17 IRQ_TYPE_EDGE_FALLING>; + vdd-supply = <&pm8226_l15>; + vio-supply = <&pm8226_l6>; + + pinctrl-0 = <&touchscreen_default>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + rmi4-f01@1 { + reg = <0x01>; + syna,nosleep-mode = <1>; + }; + + rmi4-f11@11 { + reg = <0x11>; + syna,sensor-type = <1>; + }; + }; +}; + +&blsp1_i2c5 { + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8926-microsoft-tesla.dts b/arch/arm/boot/dts/qcom/qcom-msm8926-microsoft-tesla.dts new file mode 100644 index 00000000000000..53a6d4e85959fb --- /dev/null +++ b/arch/arm/boot/dts/qcom/qcom-msm8926-microsoft-tesla.dts @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2023, Jack Matthews + * Copyright (c) 2023, Ivaylo Ivanov + * Copyright (c) 2023, Dominik Kobinski + * Copyright (c) 2023, Rayyan Ansari + */ + +/dts-v1/; + +#include "qcom-msm8226-microsoft-common.dtsi" + +/* This device has touchscreen on i2c1 instead */ +/delete-node/ &touchscreen; + +/ { + model = "Nokia Lumia 830"; + compatible = "microsoft,tesla", "qcom,msm8926", "qcom,msm8226"; + chassis-type = "handset"; +}; + +&blsp1_i2c1 { + status = "okay"; + + touchscreen: touchscreen@4b { + compatible = "syna,rmi4-i2c"; + reg = <0x4b>; + + interrupts-extended = <&tlmm 17 IRQ_TYPE_EDGE_FALLING>; + vdd-supply = <&pm8226_l15>; + vio-supply = <&pm8226_l6>; + + pinctrl-0 = <&touchscreen_default>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + rmi4-f01@1 { + reg = <0x01>; + syna,nosleep-mode = <1>; + }; + + rmi4-f12@12 { + reg = <0x12>; + syna,sensor-type = <1>; + }; + }; +}; + +&blsp1_i2c5 { + status = "disabled"; +}; + +&gpio_keys { + key-camera-snapshot { + label = "Camera Snapshot"; + gpios = <&tlmm 107 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + key-camera-focus { + label = "Camera Focus"; + gpios = <&tlmm 108 GPIO_ACTIVE_LOW>; + linux,code = ; + }; +}; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8926-motorola-peregrine.dts b/arch/arm/boot/dts/qcom/qcom-msm8926-motorola-peregrine.dts new file mode 100644 index 00000000000000..0cbe2d2fbbb18b --- /dev/null +++ b/arch/arm/boot/dts/qcom/qcom-msm8926-motorola-peregrine.dts @@ -0,0 +1,291 @@ +// SPDX-License-Identifier: BSD-3-Clause + +/dts-v1/; + +#include "qcom-msm8226.dtsi" +#include "pm8226.dtsi" + +/delete-node/ &smem_region; + +/ { + model = "Motorola Moto G 4G (2013)"; + compatible = "motorola,peregrine", "qcom,msm8926", "qcom,msm8226"; + chassis-type = "handset"; + + aliases { + mmc0 = &sdhc_1; /* SDC1 eMMC slot */ + mmc1 = &sdhc_2; /* SDC2 SD card slot */ + }; + + chosen { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + framebuffer0: framebuffer@3200000 { + compatible = "simple-framebuffer"; + reg = <0x03200000 0x800000>; + width = <720>; + height = <1280>; + stride = <(720 * 3)>; + format = "r8g8b8"; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + + event-hall-sensor { + label = "Hall Effect Sensor"; + gpios = <&tlmm 51 GPIO_ACTIVE_LOW>; + linux,input-type = ; + linux,code = ; + linux,can-disable; + }; + + key-volume-up { + label = "Volume Up"; + gpios = <&tlmm 106 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <15>; + }; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + framebuffer@3200000 { + reg = <0x03200000 0x800000>; + no-map; + }; + + smem_region: smem@fa00000 { + reg = <0x0fa00000 0x100000>; + no-map; + }; + }; +}; + +&blsp1_i2c3 { + status = "okay"; + + sensor@48 { + compatible = "ti,tmp108"; + reg = <0x48>; + }; +}; + +&blsp1_uart3 { + status = "okay"; +}; + +&pm8226_resin { + linux,code = ; + status = "okay"; +}; + +&pm8226_vib { + status = "okay"; +}; + +&rpm_requests { + regulators { + compatible = "qcom,rpm-pm8226-regulators"; + + pm8226_s3: s3 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1300000>; + }; + + pm8226_s4: s4 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2200000>; + }; + + pm8226_s5: s5 { + regulator-min-microvolt = <1150000>; + regulator-max-microvolt = <1150000>; + }; + + pm8226_l1: l1 { + regulator-min-microvolt = <1225000>; + regulator-max-microvolt = <1225000>; + }; + + pm8226_l2: l2 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + pm8226_l3: l3 { + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <1337500>; + }; + + pm8226_l4: l4 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + pm8226_l5: l5 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + pm8226_l6: l6 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-allow-set-load; + }; + + pm8226_l7: l7 { + regulator-min-microvolt = <1850000>; + regulator-max-microvolt = <1850000>; + }; + + pm8226_l8: l8 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm8226_l9: l9 { + regulator-min-microvolt = <2050000>; + regulator-max-microvolt = <2050000>; + }; + + pm8226_l10: l10 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm8226_l12: l12 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm8226_l14: l14 { + regulator-min-microvolt = <2750000>; + regulator-max-microvolt = <2750000>; + }; + + pm8226_l15: l15 { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + }; + + pm8226_l16: l16 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3350000>; + }; + + pm8226_l17: l17 { + regulator-min-microvolt = <2950000>; + regulator-max-microvolt = <2950000>; + }; + + pm8226_l18: l18 { + regulator-min-microvolt = <2950000>; + regulator-max-microvolt = <2950000>; + }; + + pm8226_l19: l19 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + }; + + pm8226_l20: l20 { + regulator-min-microvolt = <3075000>; + regulator-max-microvolt = <3075000>; + }; + + pm8226_l21: l21 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2950000>; + regulator-allow-set-load; + }; + + pm8226_l22: l22 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2950000>; + }; + + pm8226_l23: l23 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2950000>; + }; + + pm8226_l24: l24 { + regulator-min-microvolt = <1300000>; + regulator-max-microvolt = <1350000>; + }; + + pm8226_l25: l25 { + regulator-min-microvolt = <1775000>; + regulator-max-microvolt = <2125000>; + }; + + pm8226_l26: l26 { + regulator-min-microvolt = <1225000>; + regulator-max-microvolt = <1225000>; + }; + + pm8226_l27: l27 { + regulator-min-microvolt = <2050000>; + regulator-max-microvolt = <2050000>; + }; + + pm8226_l28: l28 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3400000>; + regulator-boot-on; + }; + + pm8226_lvs1: lvs1 { + /* Pull-up for I2C lines */ + regulator-always-on; + }; + }; +}; + +&sdhc_1 { + vmmc-supply = <&pm8226_l17>; + vqmmc-supply = <&pm8226_l6>; + + bus-width = <8>; + non-removable; + + status = "okay"; +}; + +&sdhc_2 { + vmmc-supply = <&pm8226_l18>; + vqmmc-supply = <&pm8226_l21>; + + bus-width = <4>; + cd-gpios = <&tlmm 115 GPIO_ACTIVE_HIGH>; + + status = "okay"; +}; + +&smbb { + qcom,fast-charge-safe-current = <2000000>; + qcom,fast-charge-current-limit = <1900000>; + qcom,fast-charge-safe-voltage = <4400000>; + qcom,minimum-input-voltage = <4300000>; + + status = "okay"; +}; + +&usb { + extcon = <&smbb>; + dr_mode = "peripheral"; + status = "okay"; +}; + +&usb_hs_phy { + extcon = <&smbb>; + v1p8-supply = <&pm8226_l10>; + v3p3-supply = <&pm8226_l20>; +}; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8960-cdp.dts b/arch/arm/boot/dts/qcom/qcom-msm8960-cdp.dts index 6c1bc3818883ca..36f4c997b0b3aa 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8960-cdp.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8960-cdp.dts @@ -2,6 +2,7 @@ #include #include "qcom-msm8960.dtsi" +#include "pm8921.dtsi" / { model = "Qualcomm MSM8960 CDP"; @@ -88,17 +89,21 @@ }; }; -&pmicintc { - keypad@148 { - linux,keymap = < - MATRIX_KEY(0, 0, KEY_VOLUMEUP) - MATRIX_KEY(0, 1, KEY_VOLUMEDOWN) - MATRIX_KEY(0, 2, KEY_CAMERA_FOCUS) - MATRIX_KEY(0, 3, KEY_CAMERA) - >; - keypad,num-rows = <1>; - keypad,num-columns = <5>; - }; +&pm8921 { + interrupts-extended = <&msmgpio 104 IRQ_TYPE_LEVEL_LOW>; +}; + +&pm8921_keypad { + linux,keymap = < + MATRIX_KEY(0, 0, KEY_VOLUMEUP) + MATRIX_KEY(0, 1, KEY_VOLUMEDOWN) + MATRIX_KEY(0, 2, KEY_CAMERA_FOCUS) + MATRIX_KEY(0, 3, KEY_CAMERA) + >; + keypad,num-rows = <1>; + keypad,num-columns = <5>; + + status = "okay"; }; &rpm { diff --git a/arch/arm/boot/dts/qcom/qcom-msm8960-samsung-expressatt.dts b/arch/arm/boot/dts/qcom/qcom-msm8960-samsung-expressatt.dts index 13e85c28749871..1a5116336ff029 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8960-samsung-expressatt.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8960-samsung-expressatt.dts @@ -1,8 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 #include +#include #include "qcom-msm8960.dtsi" -#include +#include "pm8921.dtsi" / { model = "Samsung Galaxy Express SGH-I437"; @@ -84,6 +85,10 @@ }; }; +&pm8921 { + interrupts-extended = <&msmgpio 104 IRQ_TYPE_LEVEL_LOW>; +}; + &rpm { regulators { compatible = "qcom,rpm-pm8921-regulators"; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi index d13080fcbeea22..f420740e068e82 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-msm8960.dtsi @@ -200,10 +200,6 @@ , ; interrupt-names = "ack", "err", "wakeup"; - - regulators { - compatible = "qcom,rpm-pm8921-regulators"; - }; }; acc0: clock-controller@2088000 { @@ -259,49 +255,10 @@ }; }; - ssbi@500000 { + ssbi: ssbi@500000 { compatible = "qcom,ssbi"; reg = <0x500000 0x1000>; qcom,controller-type = "pmic-arbiter"; - - pmicintc: pmic { - compatible = "qcom,pm8921"; - interrupt-parent = <&msmgpio>; - interrupts = <104 IRQ_TYPE_LEVEL_LOW>; - #interrupt-cells = <2>; - interrupt-controller; - #address-cells = <1>; - #size-cells = <0>; - - pwrkey@1c { - compatible = "qcom,pm8921-pwrkey"; - reg = <0x1c>; - interrupt-parent = <&pmicintc>; - interrupts = <50 IRQ_TYPE_EDGE_RISING>, - <51 IRQ_TYPE_EDGE_RISING>; - debounce = <15625>; - pull-up; - }; - - keypad@148 { - compatible = "qcom,pm8921-keypad"; - reg = <0x148>; - interrupt-parent = <&pmicintc>; - interrupts = <74 IRQ_TYPE_EDGE_RISING>, - <75 IRQ_TYPE_EDGE_RISING>; - debounce = <15>; - scan-delay = <32>; - row-hold = <91500>; - }; - - rtc@11d { - compatible = "qcom,pm8921-rtc"; - interrupt-parent = <&pmicintc>; - interrupts = <39 IRQ_TYPE_EDGE_RISING>; - reg = <0x11d>; - allow-set-time; - }; - }; }; rng@1a500000 { diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974-lge-nexus5-hammerhead.dts b/arch/arm/boot/dts/qcom/qcom-msm8974-lge-nexus5-hammerhead.dts index 60bdfddeae69eb..4aaae8537a3fd9 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8974-lge-nexus5-hammerhead.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8974-lge-nexus5-hammerhead.dts @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "qcom-msm8974.dtsi" -#include "qcom-pm8841.dtsi" -#include "qcom-pm8941.dtsi" +#include "pm8841.dtsi" +#include "pm8941.dtsi" #include #include #include @@ -60,6 +60,33 @@ enable-gpios = <&tlmm 60 GPIO_ACTIVE_HIGH>; }; + vreg_boost: vreg-boost { + compatible = "regulator-fixed"; + + regulator-name = "vreg-boost"; + regulator-min-microvolt = <3150000>; + regulator-max-microvolt = <3150000>; + + regulator-always-on; + regulator-boot-on; + + gpio = <&pm8941_gpios 21 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-names = "default"; + pinctrl-0 = <&boost_bypass_n_pin>; + }; + + vreg_vph_pwr: vreg-vph-pwr { + compatible = "regulator-fixed"; + regulator-name = "vph-pwr"; + + regulator-min-microvolt = <3600000>; + regulator-max-microvolt = <3600000>; + + regulator-always-on; + }; + vreg_wlan: wlan-regulator { compatible = "regulator-fixed"; @@ -340,6 +367,7 @@ &remoteproc_adsp { cx-supply = <&pm8841_s2>; + status = "okay"; }; &remoteproc_mss { @@ -347,6 +375,7 @@ mss-supply = <&pm8841_s3>; mx-supply = <&pm8841_s1>; pll-supply = <&pm8941_l12>; + status = "okay"; }; &rpm_requests { diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974-sony-xperia-rhine.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8974-sony-xperia-rhine.dtsi index 68a2f9094e536f..d34659ebac22e6 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8974-sony-xperia-rhine.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-msm8974-sony-xperia-rhine.dtsi @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "qcom-msm8974.dtsi" -#include "qcom-pm8841.dtsi" -#include "qcom-pm8941.dtsi" +#include "pm8841.dtsi" +#include "pm8941.dtsi" #include #include #include @@ -65,6 +65,33 @@ pmsg-size = <0x80000>; }; }; + + vreg_boost: vreg-boost { + compatible = "regulator-fixed"; + + regulator-name = "vreg-boost"; + regulator-min-microvolt = <3150000>; + regulator-max-microvolt = <3150000>; + + regulator-always-on; + regulator-boot-on; + + gpio = <&pm8941_gpios 21 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-names = "default"; + pinctrl-0 = <&boost_bypass_n_pin>; + }; + + vreg_vph_pwr: vreg-vph-pwr { + compatible = "regulator-fixed"; + regulator-name = "vph-pwr"; + + regulator-min-microvolt = <3600000>; + regulator-max-microvolt = <3600000>; + + regulator-always-on; + }; }; &blsp1_i2c2 { @@ -190,6 +217,7 @@ &remoteproc_adsp { cx-supply = <&pm8841_s2>; + status = "okay"; }; &remoteproc_mss { @@ -197,6 +225,7 @@ mss-supply = <&pm8841_s3>; mx-supply = <&pm8841_s1>; pll-supply = <&pm8941_l12>; + status = "okay"; }; &rpm_requests { @@ -425,6 +454,8 @@ qcom,fast-charge-low-threshold-voltage = <3400000>; qcom,auto-recharge-threshold-voltage = <4200000>; qcom,minimum-input-voltage = <4300000>; + + status = "okay"; }; &tlmm { diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi index 0bc2e66d15b156..b1413983787c2e 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-msm8974.dtsi @@ -346,6 +346,20 @@ reg = <0xf9011000 0x1000>; }; + saw_l2: power-controller@f9012000 { + compatible = "qcom,saw2"; + reg = <0xf9012000 0x1000>; + regulator; + }; + + watchdog@f9017000 { + compatible = "qcom,apss-wdt-msm8974", "qcom,kpss-wdt"; + reg = <0xf9017000 0x1000>; + interrupts = , + ; + clocks = <&sleep_clk>; + }; + timer@f9020000 { #address-cells = <1>; #size-cells = <1>; @@ -405,52 +419,46 @@ }; }; - saw0: power-controller@f9089000 { - compatible = "qcom,msm8974-saw2-v2.1-cpu", "qcom,saw2"; - reg = <0xf9089000 0x1000>, <0xf9009000 0x1000>; - }; - - saw1: power-controller@f9099000 { - compatible = "qcom,msm8974-saw2-v2.1-cpu", "qcom,saw2"; - reg = <0xf9099000 0x1000>, <0xf9009000 0x1000>; - }; - - saw2: power-controller@f90a9000 { - compatible = "qcom,msm8974-saw2-v2.1-cpu", "qcom,saw2"; - reg = <0xf90a9000 0x1000>, <0xf9009000 0x1000>; - }; - - saw3: power-controller@f90b9000 { - compatible = "qcom,msm8974-saw2-v2.1-cpu", "qcom,saw2"; - reg = <0xf90b9000 0x1000>, <0xf9009000 0x1000>; - }; - - saw_l2: power-controller@f9012000 { - compatible = "qcom,saw2"; - reg = <0xf9012000 0x1000>; - regulator; - }; - acc0: power-manager@f9088000 { compatible = "qcom,kpss-acc-v2"; reg = <0xf9088000 0x1000>, <0xf9008000 0x1000>; }; + saw0: power-controller@f9089000 { + compatible = "qcom,msm8974-saw2-v2.1-cpu", "qcom,saw2"; + reg = <0xf9089000 0x1000>, <0xf9009000 0x1000>; + }; + acc1: power-manager@f9098000 { compatible = "qcom,kpss-acc-v2"; reg = <0xf9098000 0x1000>, <0xf9008000 0x1000>; }; + saw1: power-controller@f9099000 { + compatible = "qcom,msm8974-saw2-v2.1-cpu", "qcom,saw2"; + reg = <0xf9099000 0x1000>, <0xf9009000 0x1000>; + }; + acc2: power-manager@f90a8000 { compatible = "qcom,kpss-acc-v2"; reg = <0xf90a8000 0x1000>, <0xf9008000 0x1000>; }; + saw2: power-controller@f90a9000 { + compatible = "qcom,msm8974-saw2-v2.1-cpu", "qcom,saw2"; + reg = <0xf90a9000 0x1000>, <0xf9009000 0x1000>; + }; + acc3: power-manager@f90b8000 { compatible = "qcom,kpss-acc-v2"; reg = <0xf90b8000 0x1000>, <0xf9008000 0x1000>; }; + saw3: power-controller@f90b9000 { + compatible = "qcom,msm8974-saw2-v2.1-cpu", "qcom,saw2"; + reg = <0xf90b9000 0x1000>, <0xf9009000 0x1000>; + }; + sdhc_1: mmc@f9824900 { compatible = "qcom,msm8974-sdhci", "qcom,sdhci-msm-v4"; reg = <0xf9824900 0x11c>, <0xf9824000 0x800>; @@ -1063,6 +1071,15 @@ }; }; + bimc: interconnect@fc380000 { + reg = <0xfc380000 0x6a000>; + compatible = "qcom,msm8974-bimc"; + #interconnect-cells = <1>; + clock-names = "bus", "bus_a"; + clocks = <&rpmcc RPM_SMD_BIMC_CLK>, + <&rpmcc RPM_SMD_BIMC_A_CLK>; + }; + gcc: clock-controller@fc400000 { compatible = "qcom,gcc-msm8974"; #clock-cells = <1>; @@ -1101,22 +1118,13 @@ }; }; - bimc: interconnect@fc380000 { - reg = <0xfc380000 0x6a000>; - compatible = "qcom,msm8974-bimc"; - #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_BIMC_CLK>, - <&rpmcc RPM_SMD_BIMC_A_CLK>; - }; - snoc: interconnect@fc460000 { reg = <0xfc460000 0x4000>; compatible = "qcom,msm8974-snoc"; #interconnect-cells = <1>; clock-names = "bus", "bus_a"; clocks = <&rpmcc RPM_SMD_SNOC_CLK>, - <&rpmcc RPM_SMD_SNOC_A_CLK>; + <&rpmcc RPM_SMD_SNOC_A_CLK>; }; pnoc: interconnect@fc468000 { @@ -1125,7 +1133,7 @@ #interconnect-cells = <1>; clock-names = "bus", "bus_a"; clocks = <&rpmcc RPM_SMD_PNOC_CLK>, - <&rpmcc RPM_SMD_PNOC_A_CLK>; + <&rpmcc RPM_SMD_PNOC_A_CLK>; }; ocmemnoc: interconnect@fc470000 { @@ -1134,7 +1142,7 @@ #interconnect-cells = <1>; clock-names = "bus", "bus_a"; clocks = <&rpmcc RPM_SMD_OCMEMGX_CLK>, - <&rpmcc RPM_SMD_OCMEMGX_A_CLK>; + <&rpmcc RPM_SMD_OCMEMGX_A_CLK>; }; mmssnoc: interconnect@fc478000 { @@ -1143,7 +1151,7 @@ #interconnect-cells = <1>; clock-names = "bus", "bus_a"; clocks = <&mmcc MMSS_S0_AXI_CLK>, - <&mmcc MMSS_S0_AXI_CLK>; + <&mmcc MMSS_S0_AXI_CLK>; }; cnoc: interconnect@fc480000 { @@ -1152,7 +1160,7 @@ #interconnect-cells = <1>; clock-names = "bus", "bus_a"; clocks = <&rpmcc RPM_SMD_CNOC_CLK>, - <&rpmcc RPM_SMD_CNOC_A_CLK>; + <&rpmcc RPM_SMD_CNOC_A_CLK>; }; tsens: thermal-sensor@fc4a9000 { @@ -1633,13 +1641,6 @@ bias-pull-up; drive-strength = <2>; }; - - cd-pins { - pins = "gpio54"; - function = "gpio"; - bias-disable; - drive-strength = <2>; - }; }; blsp1_uart2_default: blsp1-uart2-default-state { @@ -2408,31 +2409,4 @@ ; clock-frequency = <19200000>; }; - - vreg_boost: vreg-boost { - compatible = "regulator-fixed"; - - regulator-name = "vreg-boost"; - regulator-min-microvolt = <3150000>; - regulator-max-microvolt = <3150000>; - - regulator-always-on; - regulator-boot-on; - - gpio = <&pm8941_gpios 21 GPIO_ACTIVE_HIGH>; - enable-active-high; - - pinctrl-names = "default"; - pinctrl-0 = <&boost_bypass_n_pin>; - }; - - vreg_vph_pwr: vreg-vph-pwr { - compatible = "regulator-fixed"; - regulator-name = "vph-pwr"; - - regulator-min-microvolt = <3600000>; - regulator-max-microvolt = <3600000>; - - regulator-always-on; - }; }; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974pro-fairphone-fp2.dts b/arch/arm/boot/dts/qcom/qcom-msm8974pro-fairphone-fp2.dts index 42d253b75dad02..fe227fd3f908e2 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8974pro-fairphone-fp2.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8974pro-fairphone-fp2.dts @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "qcom-msm8974pro.dtsi" -#include "qcom-pm8841.dtsi" -#include "qcom-pm8941.dtsi" +#include "pm8841.dtsi" +#include "pm8941.dtsi" #include #include #include @@ -57,6 +57,33 @@ enable-gpios = <&tlmm 86 GPIO_ACTIVE_HIGH>; vcc-supply = <&pm8941_l18>; }; + + vreg_boost: vreg-boost { + compatible = "regulator-fixed"; + + regulator-name = "vreg-boost"; + regulator-min-microvolt = <3150000>; + regulator-max-microvolt = <3150000>; + + regulator-always-on; + regulator-boot-on; + + gpio = <&pm8941_gpios 21 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-names = "default"; + pinctrl-0 = <&boost_bypass_n_pin>; + }; + + vreg_vph_pwr: vreg-vph-pwr { + compatible = "regulator-fixed"; + regulator-name = "vph-pwr"; + + regulator-min-microvolt = <3600000>; + regulator-max-microvolt = <3600000>; + + regulator-always-on; + }; }; &blsp1_i2c2 { @@ -381,6 +408,8 @@ qcom,fast-charge-high-threshold-voltage = <4350000>; qcom,auto-recharge-threshold-voltage = <4240000>; qcom,minimum-input-voltage = <4450000>; + + status = "okay"; }; &tlmm { diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974pro-oneplus-bacon.dts b/arch/arm/boot/dts/qcom/qcom-msm8974pro-oneplus-bacon.dts index 8230d0e1d95d1d..4c8edadea0ac63 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8974pro-oneplus-bacon.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8974pro-oneplus-bacon.dts @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "qcom-msm8974pro.dtsi" -#include "qcom-pm8841.dtsi" -#include "qcom-pm8941.dtsi" +#include "pm8841.dtsi" +#include "pm8941.dtsi" #include #include @@ -51,6 +51,33 @@ debounce-interval = <150>; }; }; + + vreg_boost: vreg-boost { + compatible = "regulator-fixed"; + + regulator-name = "vreg-boost"; + regulator-min-microvolt = <3150000>; + regulator-max-microvolt = <3150000>; + + regulator-always-on; + regulator-boot-on; + + gpio = <&pm8941_gpios 21 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-names = "default"; + pinctrl-0 = <&boost_bypass_n_pin>; + }; + + vreg_vph_pwr: vreg-vph-pwr { + compatible = "regulator-fixed"; + regulator-name = "vph-pwr"; + + regulator-min-microvolt = <3600000>; + regulator-max-microvolt = <3600000>; + + regulator-always-on; + }; }; &blsp1_i2c1 { @@ -433,6 +460,10 @@ status = "okay"; }; +&smbb { + status = "okay"; +}; + &tlmm { gpio_hall_sensor_default: gpio-hall-sensor-default-state { pins = "gpio68"; diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974pro-samsung-klte.dts b/arch/arm/boot/dts/qcom/qcom-msm8974pro-samsung-klte.dts index 3e2c86591ee2f7..b93539e2b87e91 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8974pro-samsung-klte.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8974pro-samsung-klte.dts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 #include "qcom-msm8974pro.dtsi" -#include "qcom-pma8084.dtsi" +#include "pma8084.dtsi" #include #include #include @@ -155,7 +155,15 @@ enable-active-high; }; - /delete-node/ vreg-boost; + vreg_vph_pwr: vreg-vph-pwr { + compatible = "regulator-fixed"; + regulator-name = "vph-pwr"; + + regulator-min-microvolt = <3600000>; + regulator-max-microvolt = <3600000>; + + regulator-always-on; + }; }; &blsp1_i2c2 { @@ -355,7 +363,6 @@ vddr-supply = <&vreg_panel>; reset-gpios = <&pma8084_gpios 17 GPIO_ACTIVE_LOW>; - te-gpios = <&tlmm 12 GPIO_ACTIVE_HIGH>; port { panel_in: endpoint { diff --git a/arch/arm/boot/dts/qcom/qcom-msm8974pro-sony-xperia-shinano-castor.dts b/arch/arm/boot/dts/qcom/qcom-msm8974pro-sony-xperia-shinano-castor.dts index 11468d1409f722..ee94741a26ed6d 100644 --- a/arch/arm/boot/dts/qcom/qcom-msm8974pro-sony-xperia-shinano-castor.dts +++ b/arch/arm/boot/dts/qcom/qcom-msm8974pro-sony-xperia-shinano-castor.dts @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "qcom-msm8974pro.dtsi" -#include "qcom-pm8841.dtsi" -#include "qcom-pm8941.dtsi" +#include "pm8841.dtsi" +#include "pm8941.dtsi" #include #include #include @@ -84,6 +84,33 @@ pinctrl-0 = <&lcd_dcdc_en_pin_a>; }; + vreg_boost: vreg-boost { + compatible = "regulator-fixed"; + + regulator-name = "vreg-boost"; + regulator-min-microvolt = <3150000>; + regulator-max-microvolt = <3150000>; + + regulator-always-on; + regulator-boot-on; + + gpio = <&pm8941_gpios 21 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-names = "default"; + pinctrl-0 = <&boost_bypass_n_pin>; + }; + + vreg_vph_pwr: vreg-vph-pwr { + compatible = "regulator-fixed"; + regulator-name = "vph-pwr"; + + regulator-min-microvolt = <3600000>; + regulator-max-microvolt = <3600000>; + + regulator-always-on; + }; + vreg_wlan: wlan-regulator { compatible = "regulator-fixed"; @@ -297,6 +324,7 @@ &remoteproc_adsp { cx-supply = <&pm8841_s2>; + status = "okay"; }; &remoteproc_mss { @@ -304,6 +332,7 @@ mss-supply = <&pm8841_s3>; mx-supply = <&pm8841_s1>; pll-supply = <&pm8941_l12>; + status = "okay"; }; &rpm_requests { @@ -558,6 +587,8 @@ qcom,fast-charge-low-threshold-voltage = <3400000>; qcom,auto-recharge-threshold-voltage = <4200000>; qcom,minimum-input-voltage = <4300000>; + + status = "okay"; }; &tlmm { diff --git a/arch/arm/boot/dts/qcom/qcom-pm8226.dtsi b/arch/arm/boot/dts/qcom/qcom-pm8226.dtsi deleted file mode 100644 index 2413778f371507..00000000000000 --- a/arch/arm/boot/dts/qcom/qcom-pm8226.dtsi +++ /dev/null @@ -1,180 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -#include -#include -#include -#include - -/ { - thermal-zones { - pm8226-thermal { - polling-delay-passive = <100>; - polling-delay = <0>; - thermal-sensors = <&pm8226_temp>; - - trips { - trip0 { - temperature = <105000>; - hysteresis = <2000>; - type = "passive"; - }; - - trip1 { - temperature = <125000>; - hysteresis = <2000>; - type = "hot"; - }; - - crit { - temperature = <145000>; - hysteresis = <2000>; - type = "critical"; - }; - }; - }; - }; -}; - -&spmi_bus { - pm8226_0: pm8226@0 { - compatible = "qcom,pm8226", "qcom,spmi-pmic"; - reg = <0x0 SPMI_USID>; - #address-cells = <1>; - #size-cells = <0>; - - pon@800 { - compatible = "qcom,pm8916-pon"; - reg = <0x800>; - - pwrkey { - compatible = "qcom,pm8941-pwrkey"; - interrupts = <0x0 0x8 0 IRQ_TYPE_EDGE_BOTH>; - debounce = <15625>; - bias-pull-up; - linux,code = ; - }; - - pm8226_resin: resin { - compatible = "qcom,pm8941-resin"; - interrupts = <0x0 0x8 1 IRQ_TYPE_EDGE_BOTH>; - debounce = <15625>; - bias-pull-up; - status = "disabled"; - }; - }; - - smbb: charger@1000 { - compatible = "qcom,pm8226-charger"; - reg = <0x1000>; - interrupts = <0x0 0x10 7 IRQ_TYPE_EDGE_BOTH>, - <0x0 0x10 5 IRQ_TYPE_EDGE_BOTH>, - <0x0 0x10 4 IRQ_TYPE_EDGE_BOTH>, - <0x0 0x12 1 IRQ_TYPE_EDGE_BOTH>, - <0x0 0x12 0 IRQ_TYPE_EDGE_BOTH>, - <0x0 0x13 2 IRQ_TYPE_EDGE_BOTH>, - <0x0 0x13 1 IRQ_TYPE_EDGE_BOTH>, - <0x0 0x14 1 IRQ_TYPE_EDGE_BOTH>; - interrupt-names = "chg-done", - "chg-fast", - "chg-trkl", - "bat-temp-ok", - "bat-present", - "chg-gone", - "usb-valid", - "dc-valid"; - - chg_otg: otg-vbus { }; - }; - - pm8226_temp: temp-alarm@2400 { - compatible = "qcom,spmi-temp-alarm"; - reg = <0x2400>; - interrupts = <0 0x24 0 IRQ_TYPE_EDGE_RISING>; - io-channels = <&pm8226_vadc VADC_DIE_TEMP>; - io-channel-names = "thermal"; - #thermal-sensor-cells = <0>; - }; - - pm8226_vadc: adc@3100 { - compatible = "qcom,spmi-vadc"; - reg = <0x3100>; - interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>; - #address-cells = <1>; - #size-cells = <0>; - #io-channel-cells = <1>; - - channel@7 { - reg = ; - qcom,pre-scaling = <1 3>; - label = "vph_pwr"; - }; - channel@8 { - reg = ; - label = "die_temp"; - }; - channel@9 { - reg = ; - label = "ref_625mv"; - }; - channel@a { - reg = ; - label = "ref_1250mv"; - }; - channel@e { - reg = ; - }; - channel@f { - reg = ; - }; - }; - - pm8226_iadc: adc@3600 { - compatible = "qcom,pm8226-iadc", "qcom,spmi-iadc"; - reg = <0x3600>; - interrupts = <0x0 0x36 0x0 IRQ_TYPE_EDGE_RISING>; - }; - - rtc@6000 { - compatible = "qcom,pm8941-rtc"; - reg = <0x6000>, <0x6100>; - reg-names = "rtc", "alarm"; - interrupts = <0x0 0x61 0x1 IRQ_TYPE_EDGE_RISING>; - }; - - pm8226_mpps: mpps@a000 { - compatible = "qcom,pm8226-mpp", "qcom,spmi-mpp"; - reg = <0xa000>; - gpio-controller; - #gpio-cells = <2>; - gpio-ranges = <&pm8226_mpps 0 0 8>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - pm8226_gpios: gpio@c000 { - compatible = "qcom,pm8226-gpio", "qcom,spmi-gpio"; - reg = <0xc000>; - gpio-controller; - #gpio-cells = <2>; - gpio-ranges = <&pm8226_gpios 0 0 8>; - interrupt-controller; - #interrupt-cells = <2>; - }; - }; - - pm8226_1: pm8226@1 { - compatible = "qcom,pm8226", "qcom,spmi-pmic"; - reg = <0x1 SPMI_USID>; - #address-cells = <1>; - #size-cells = <0>; - - pm8226_spmi_regulators: regulators { - compatible = "qcom,pm8226-regulators"; - }; - - pm8226_vib: vibrator@c000 { - compatible = "qcom,pm8916-vib"; - reg = <0xc000>; - status = "disabled"; - }; - }; -}; diff --git a/arch/arm/boot/dts/qcom/qcom-pm8841.dtsi b/arch/arm/boot/dts/qcom/qcom-pm8841.dtsi deleted file mode 100644 index 3bf2ce5c86a641..00000000000000 --- a/arch/arm/boot/dts/qcom/qcom-pm8841.dtsi +++ /dev/null @@ -1,68 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include - - -/ { - thermal-zones { - pm8841-thermal { - polling-delay-passive = <100>; - polling-delay = <0>; - thermal-sensors = <&pm8841_temp>; - - trips { - trip0 { - temperature = <105000>; - hysteresis = <2000>; - type = "passive"; - }; - - trip1 { - temperature = <125000>; - hysteresis = <2000>; - type = "hot"; - }; - - crit { - temperature = <140000>; - hysteresis = <2000>; - type = "critical"; - }; - }; - }; - }; -}; - -&spmi_bus { - - pm8841_0: pm8841@4 { - compatible = "qcom,pm8841", "qcom,spmi-pmic"; - reg = <0x4 SPMI_USID>; - #address-cells = <1>; - #size-cells = <0>; - - pm8841_mpps: mpps@a000 { - compatible = "qcom,pm8841-mpp", "qcom,spmi-mpp"; - reg = <0xa000>; - gpio-controller; - #gpio-cells = <2>; - gpio-ranges = <&pm8841_mpps 0 0 4>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - pm8841_temp: temp-alarm@2400 { - compatible = "qcom,spmi-temp-alarm"; - reg = <0x2400>; - interrupts = <4 0x24 0 IRQ_TYPE_EDGE_RISING>; - #thermal-sensor-cells = <0>; - }; - }; - - pm8841_1: pm8841@5 { - compatible = "qcom,pm8841", "qcom,spmi-pmic"; - reg = <0x5 SPMI_USID>; - #address-cells = <1>; - #size-cells = <0>; - }; -}; diff --git a/arch/arm/boot/dts/qcom/qcom-pm8941.dtsi b/arch/arm/boot/dts/qcom/qcom-pm8941.dtsi deleted file mode 100644 index ed0ba591c75581..00000000000000 --- a/arch/arm/boot/dts/qcom/qcom-pm8941.dtsi +++ /dev/null @@ -1,254 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include -#include - - -/ { - thermal-zones { - pm8941-thermal { - polling-delay-passive = <100>; - polling-delay = <0>; - thermal-sensors = <&pm8941_temp>; - - trips { - trip0 { - temperature = <105000>; - hysteresis = <2000>; - type = "passive"; - }; - - trip1 { - temperature = <125000>; - hysteresis = <2000>; - type = "hot"; - }; - - crit { - temperature = <145000>; - hysteresis = <2000>; - type = "critical"; - }; - }; - }; - }; -}; - -&spmi_bus { - - pm8941_0: pm8941@0 { - compatible = "qcom,pm8941", "qcom,spmi-pmic"; - reg = <0x0 SPMI_USID>; - #address-cells = <1>; - #size-cells = <0>; - - rtc@6000 { - compatible = "qcom,pm8941-rtc"; - reg = <0x6000>, - <0x6100>; - reg-names = "rtc", "alarm"; - interrupts = <0x0 0x61 0x1 IRQ_TYPE_EDGE_RISING>; - }; - - pon@800 { - compatible = "qcom,pm8941-pon"; - reg = <0x800>; - - pwrkey { - compatible = "qcom,pm8941-pwrkey"; - interrupts = <0x0 0x8 0 IRQ_TYPE_EDGE_BOTH>; - debounce = <15625>; - bias-pull-up; - }; - - pm8941_resin: resin { - compatible = "qcom,pm8941-resin"; - interrupts = <0x0 0x8 1 IRQ_TYPE_EDGE_BOTH>; - debounce = <15625>; - bias-pull-up; - status = "disabled"; - }; - }; - - usb_id: usb-detect@900 { - compatible = "qcom,pm8941-misc"; - reg = <0x900>; - interrupts = <0x0 0x9 0 IRQ_TYPE_EDGE_BOTH>; - interrupt-names = "usb_id"; - }; - - smbb: charger@1000 { - compatible = "qcom,pm8941-charger"; - reg = <0x1000>; - interrupts = <0x0 0x10 7 IRQ_TYPE_EDGE_BOTH>, - <0x0 0x10 5 IRQ_TYPE_EDGE_BOTH>, - <0x0 0x10 4 IRQ_TYPE_EDGE_BOTH>, - <0x0 0x12 1 IRQ_TYPE_EDGE_BOTH>, - <0x0 0x12 0 IRQ_TYPE_EDGE_BOTH>, - <0x0 0x13 2 IRQ_TYPE_EDGE_BOTH>, - <0x0 0x13 1 IRQ_TYPE_EDGE_BOTH>, - <0x0 0x14 1 IRQ_TYPE_EDGE_BOTH>; - interrupt-names = "chg-done", - "chg-fast", - "chg-trkl", - "bat-temp-ok", - "bat-present", - "chg-gone", - "usb-valid", - "dc-valid"; - - usb-otg-in-supply = <&pm8941_5vs1>; - - chg_otg: otg-vbus { }; - }; - - pm8941_gpios: gpio@c000 { - compatible = "qcom,pm8941-gpio", "qcom,spmi-gpio"; - reg = <0xc000>; - gpio-controller; - gpio-ranges = <&pm8941_gpios 0 0 36>; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - - boost_bypass_n_pin: boost-bypass-state { - pins = "gpio21"; - function = "normal"; - }; - }; - - pm8941_mpps: mpps@a000 { - compatible = "qcom,pm8941-mpp", "qcom,spmi-mpp"; - reg = <0xa000>; - gpio-controller; - #gpio-cells = <2>; - gpio-ranges = <&pm8941_mpps 0 0 8>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - pm8941_temp: temp-alarm@2400 { - compatible = "qcom,spmi-temp-alarm"; - reg = <0x2400>; - interrupts = <0 0x24 0 IRQ_TYPE_EDGE_RISING>; - io-channels = <&pm8941_vadc VADC_DIE_TEMP>; - io-channel-names = "thermal"; - #thermal-sensor-cells = <0>; - }; - - pm8941_vadc: adc@3100 { - compatible = "qcom,spmi-vadc"; - reg = <0x3100>; - interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>; - #address-cells = <1>; - #size-cells = <0>; - #io-channel-cells = <1>; - - - channel@6 { - reg = ; - }; - - channel@8 { - reg = ; - }; - - channel@9 { - reg = ; - }; - - channel@a { - reg = ; - }; - - channel@e { - reg = ; - }; - - channel@f { - reg = ; - }; - - channel@30 { - reg = ; - }; - }; - - pm8941_iadc: adc@3600 { - compatible = "qcom,pm8941-iadc", "qcom,spmi-iadc"; - reg = <0x3600>; - interrupts = <0x0 0x36 0x0 IRQ_TYPE_EDGE_RISING>; - qcom,external-resistor-micro-ohms = <10000>; - }; - - pm8941_coincell: charger@2800 { - compatible = "qcom,pm8941-coincell"; - reg = <0x2800>; - status = "disabled"; - }; - }; - - pm8941_1: pm8941@1 { - compatible = "qcom,pm8941", "qcom,spmi-pmic"; - reg = <0x1 SPMI_USID>; - #address-cells = <1>; - #size-cells = <0>; - - pm8941_lpg: pwm { - compatible = "qcom,pm8941-lpg"; - - #address-cells = <1>; - #size-cells = <0>; - #pwm-cells = <2>; - - status = "disabled"; - }; - - pm8941_vib: vibrator@c000 { - compatible = "qcom,pm8916-vib"; - reg = <0xc000>; - status = "disabled"; - }; - - pm8941_wled: wled@d800 { - compatible = "qcom,pm8941-wled"; - reg = <0xd800>; - label = "backlight"; - - status = "disabled"; - }; - - regulators { - compatible = "qcom,pm8941-regulators"; - interrupts = <0x1 0x83 0x2 0>, <0x1 0x84 0x2 0>; - interrupt-names = "ocp-5vs1", "ocp-5vs2"; - vin_5vs-supply = <&pm8941_5v>; - - pm8941_5v: s4 { - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - regulator-enable-ramp-delay = <500>; - }; - - pm8941_5vs1: 5vs1 { - regulator-enable-ramp-delay = <1000>; - regulator-pull-down; - regulator-over-current-protection; - qcom,ocp-max-retries = <10>; - qcom,ocp-retry-delay = <30>; - qcom,vs-soft-start-strength = <0>; - regulator-initial-mode = <1>; - }; - - pm8941_5vs2: 5vs2 { - regulator-enable-ramp-delay = <1000>; - regulator-pull-down; - regulator-over-current-protection; - qcom,ocp-max-retries = <10>; - qcom,ocp-retry-delay = <30>; - qcom,vs-soft-start-strength = <0>; - regulator-initial-mode = <1>; - }; - }; - }; -}; diff --git a/arch/arm/boot/dts/qcom/qcom-pma8084.dtsi b/arch/arm/boot/dts/qcom/qcom-pma8084.dtsi deleted file mode 100644 index 2985f4805b93ee..00000000000000 --- a/arch/arm/boot/dts/qcom/qcom-pma8084.dtsi +++ /dev/null @@ -1,99 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include -#include - -&spmi_bus { - - pma8084_0: pma8084@0 { - compatible = "qcom,pma8084", "qcom,spmi-pmic"; - reg = <0x0 SPMI_USID>; - #address-cells = <1>; - #size-cells = <0>; - - rtc@6000 { - compatible = "qcom,pm8941-rtc"; - reg = <0x6000>, - <0x6100>; - reg-names = "rtc", "alarm"; - interrupts = <0x0 0x61 0x1 IRQ_TYPE_EDGE_RISING>; - }; - - pwrkey@800 { - compatible = "qcom,pm8941-pwrkey"; - reg = <0x800>; - interrupts = <0x0 0x8 0 IRQ_TYPE_EDGE_BOTH>; - debounce = <15625>; - bias-pull-up; - }; - - pma8084_gpios: gpio@c000 { - compatible = "qcom,pma8084-gpio", "qcom,spmi-gpio"; - reg = <0xc000>; - gpio-controller; - gpio-ranges = <&pma8084_gpios 0 0 22>; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - pma8084_mpps: mpps@a000 { - compatible = "qcom,pma8084-mpp", "qcom,spmi-mpp"; - reg = <0xa000>; - gpio-controller; - #gpio-cells = <2>; - gpio-ranges = <&pma8084_mpps 0 0 8>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - pma8084_temp: temp-alarm@2400 { - compatible = "qcom,spmi-temp-alarm"; - reg = <0x2400>; - interrupts = <0 0x24 0 IRQ_TYPE_EDGE_RISING>; - #thermal-sensor-cells = <0>; - io-channels = <&pma8084_vadc VADC_DIE_TEMP>; - io-channel-names = "thermal"; - }; - - pma8084_vadc: adc@3100 { - compatible = "qcom,spmi-vadc"; - reg = <0x3100>; - interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>; - #address-cells = <1>; - #size-cells = <0>; - #io-channel-cells = <1>; - - channel@8 { - reg = ; - }; - - channel@9 { - reg = ; - }; - - channel@a { - reg = ; - }; - - channel@c { - reg = ; - }; - - channel@e { - reg = ; - }; - - channel@f { - reg = ; - }; - }; - }; - - pma8084_1: pma8084@1 { - compatible = "qcom,pma8084", "qcom,spmi-pmic"; - reg = <0x1 SPMI_USID>; - #address-cells = <1>; - #size-cells = <0>; - }; -}; diff --git a/arch/arm/boot/dts/qcom/qcom-pmx55.dtsi b/arch/arm/boot/dts/qcom/qcom-pmx55.dtsi deleted file mode 100644 index da0851173c6997..00000000000000 --- a/arch/arm/boot/dts/qcom/qcom-pmx55.dtsi +++ /dev/null @@ -1,85 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause - -/* - * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. - * Copyright (c) 2020, Linaro Limited - */ - -#include -#include -#include - -&spmi_bus { - pmic@8 { - compatible = "qcom,pmx55", "qcom,spmi-pmic"; - reg = <0x8 SPMI_USID>; - #address-cells = <1>; - #size-cells = <0>; - - pon@800 { - compatible = "qcom,pm8916-pon"; - reg = <0x0800>; - - status = "disabled"; - }; - - pmx55_temp: temp-alarm@2400 { - compatible = "qcom,spmi-temp-alarm"; - reg = <0x2400>; - interrupts = <0x8 0x24 0x0 IRQ_TYPE_EDGE_BOTH>; - io-channels = <&pmx55_adc ADC5_DIE_TEMP>; - io-channel-names = "thermal"; - #thermal-sensor-cells = <0>; - }; - - pmx55_adc: adc@3100 { - compatible = "qcom,spmi-adc5"; - reg = <0x3100>; - #address-cells = <1>; - #size-cells = <0>; - #io-channel-cells = <1>; - interrupts = <0x8 0x31 0x0 IRQ_TYPE_EDGE_RISING>; - - channel@0 { - reg = ; - qcom,pre-scaling = <1 1>; - label = "ref_gnd"; - }; - - channel@1 { - reg = ; - qcom,pre-scaling = <1 1>; - label = "vref_1p25"; - }; - - channel@6 { - reg = ; - qcom,pre-scaling = <1 1>; - label = "die_temp"; - }; - - channel@9 { - reg = ; - qcom,pre-scaling = <1 1>; - label = "chg_temp"; - }; - }; - - pmx55_gpios: gpio@c000 { - compatible = "qcom,pmx55-gpio", "qcom,spmi-gpio"; - reg = <0xc000>; - gpio-controller; - gpio-ranges = <&pmx55_gpios 0 0 11>; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - }; - - pmic@9 { - compatible = "qcom,pmx55", "qcom,spmi-pmic"; - reg = <0x9 SPMI_USID>; - #address-cells = <1>; - #size-cells = <0>; - }; -}; diff --git a/arch/arm/boot/dts/qcom/qcom-pmx65.dtsi b/arch/arm/boot/dts/qcom/qcom-pmx65.dtsi deleted file mode 100644 index 1c7fdf59c1f56a..00000000000000 --- a/arch/arm/boot/dts/qcom/qcom-pmx65.dtsi +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. - */ - -#include -#include - -&spmi_bus { - pmic@1 { - compatible = "qcom,pmx65", "qcom,spmi-pmic"; - reg = <1 SPMI_USID>; - #address-cells = <1>; - #size-cells = <0>; - - pmx65_temp: temp-alarm@a00 { - compatible = "qcom,spmi-temp-alarm"; - reg = <0xa00>; - interrupts = <0x1 0xa 0x0 IRQ_TYPE_EDGE_BOTH>; - #thermal-sensor-cells = <0>; - }; - - pmx65_gpios: gpio@8800 { - compatible = "qcom,pmx65-gpio", "qcom,spmi-gpio"; - reg = <0x8800>; - gpio-controller; - gpio-ranges = <&pmx65_gpios 0 0 16>; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - }; -}; diff --git a/arch/arm/boot/dts/qcom/qcom-sdx55-mtp.dts b/arch/arm/boot/dts/qcom/qcom-sdx55-mtp.dts index 7e97ad5803d87b..2470693619090b 100644 --- a/arch/arm/boot/dts/qcom/qcom-sdx55-mtp.dts +++ b/arch/arm/boot/dts/qcom/qcom-sdx55-mtp.dts @@ -9,7 +9,7 @@ #include "qcom-sdx55.dtsi" #include #include -#include "qcom-pmx55.dtsi" +#include "pmx55.dtsi" / { model = "Qualcomm Technologies, Inc. SDX55 MTP"; diff --git a/arch/arm/boot/dts/qcom/qcom-sdx55-t55.dts b/arch/arm/boot/dts/qcom/qcom-sdx55-t55.dts index 51058b06527979..082f7ed1a01fb8 100644 --- a/arch/arm/boot/dts/qcom/qcom-sdx55-t55.dts +++ b/arch/arm/boot/dts/qcom/qcom-sdx55-t55.dts @@ -8,7 +8,7 @@ #include #include #include "qcom-sdx55.dtsi" -#include "qcom-pmx55.dtsi" +#include "pmx55.dtsi" / { model = "Thundercomm T55 Development Kit"; diff --git a/arch/arm/boot/dts/qcom/qcom-sdx55-telit-fn980-tlb.dts b/arch/arm/boot/dts/qcom/qcom-sdx55-telit-fn980-tlb.dts index 8fadc6e70692a5..e336a15b45c4c6 100644 --- a/arch/arm/boot/dts/qcom/qcom-sdx55-telit-fn980-tlb.dts +++ b/arch/arm/boot/dts/qcom/qcom-sdx55-telit-fn980-tlb.dts @@ -8,7 +8,7 @@ #include #include #include "qcom-sdx55.dtsi" -#include "qcom-pmx55.dtsi" +#include "pmx55.dtsi" / { model = "Telit FN980 TLB"; diff --git a/arch/arm/boot/dts/qcom/qcom-sdx55.dtsi b/arch/arm/boot/dts/qcom/qcom-sdx55.dtsi index 2aa5089a8513d1..2045fc779f8870 100644 --- a/arch/arm/boot/dts/qcom/qcom-sdx55.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-sdx55.dtsi @@ -228,31 +228,26 @@ usb_qmpphy: phy@ff6000 { compatible = "qcom,sdx55-qmp-usb3-uni-phy"; - reg = <0x00ff6000 0x1c0>; - status = "disabled"; - #address-cells = <1>; - #size-cells = <1>; - ranges; + reg = <0x00ff6000 0x1000>; clocks = <&gcc GCC_USB3_PHY_AUX_CLK>, + <&gcc GCC_USB3_PRIM_CLKREF_CLK>, <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, - <&gcc GCC_USB3_PRIM_CLKREF_CLK>; - clock-names = "aux", "cfg_ahb", "ref"; - - resets = <&gcc GCC_USB3PHY_PHY_BCR>, - <&gcc GCC_USB3_PHY_BCR>; - reset-names = "phy", "common"; - - usb_ssphy: phy@ff6200 { - reg = <0x00ff6200 0x170>, - <0x00ff6400 0x200>, - <0x00ff6800 0x800>; - #phy-cells = <0>; - #clock-cells = <0>; - clocks = <&gcc GCC_USB3_PHY_PIPE_CLK>; - clock-names = "pipe0"; - clock-output-names = "usb3_uni_phy_pipe_clk_src"; - }; + <&gcc GCC_USB3_PHY_PIPE_CLK>; + clock-names = "aux", + "ref", + "cfg_ahb", + "pipe"; + clock-output-names = "usb3_uni_phy_pipe_clk_src"; + #clock-cells = <0>; + #phy-cells = <0>; + + resets = <&gcc GCC_USB3_PHY_BCR>, + <&gcc GCC_USB3PHY_PHY_BCR>; + reset-names = "phy", + "phy_phy"; + + status = "disabled"; }; mc_virt: interconnect@1100000 { @@ -436,9 +431,9 @@ status = "disabled"; }; - pcie_phy: phy@1c07000 { + pcie_phy: phy@1c06000 { compatible = "qcom,sdx55-qmp-pcie-phy"; - reg = <0x01c07000 0x2000>; + reg = <0x01c06000 0x2000>; #address-cells = <1>; #size-cells = <1>; ranges; @@ -585,10 +580,10 @@ <&gcc GCC_USB30_MASTER_CLK>; assigned-clock-rates = <19200000>, <200000000>; - interrupts = , - , - , - ; + interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 51 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 11 IRQ_TYPE_EDGE_BOTH>, + <&pdc 10 IRQ_TYPE_EDGE_BOTH>; interrupt-names = "hs_phy_irq", "ss_phy_irq", "dm_hs_phy_irq", "dp_hs_phy_irq"; @@ -603,7 +598,7 @@ iommus = <&apps_smmu 0x1a0 0x0>; snps,dis_u2_susphy_quirk; snps,dis_enblslpm_quirk; - phys = <&usb_hsphy>, <&usb_ssphy>; + phys = <&usb_hsphy>, <&usb_qmpphy>; phy-names = "usb2-phy", "usb3-phy"; }; }; @@ -612,7 +607,7 @@ compatible = "qcom,sdx55-pdc", "qcom,pdc"; reg = <0x0b210000 0x30000>; qcom,pdc-ranges = <0 179 52>; - #interrupt-cells = <3>; + #interrupt-cells = <2>; interrupt-parent = <&intc>; interrupt-controller; }; diff --git a/arch/arm/boot/dts/qcom/qcom-sdx65-mtp.dts b/arch/arm/boot/dts/qcom/qcom-sdx65-mtp.dts index 9649c859a2c363..07c10c84eefa1b 100644 --- a/arch/arm/boot/dts/qcom/qcom-sdx65-mtp.dts +++ b/arch/arm/boot/dts/qcom/qcom-sdx65-mtp.dts @@ -12,7 +12,7 @@ #include #include #include -#include "qcom-pmx65.dtsi" +#include "pmx65.dtsi" / { model = "Qualcomm Technologies, Inc. SDX65 MTP"; diff --git a/arch/arm/boot/dts/qcom/qcom-sdx65.dtsi b/arch/arm/boot/dts/qcom/qcom-sdx65.dtsi index e559adaaeee7a4..40591a4da6a42f 100644 --- a/arch/arm/boot/dts/qcom/qcom-sdx65.dtsi +++ b/arch/arm/boot/dts/qcom/qcom-sdx65.dtsi @@ -204,8 +204,16 @@ gcc: clock-controller@100000 { compatible = "qcom,gcc-sdx65"; reg = <0x00100000 0x001f7400>; - clocks = <&rpmhcc RPMH_CXO_CLK>, <&rpmhcc RPMH_CXO_CLK_A>, <&sleep_clk>; - clock-names = "bi_tcxo", "bi_tcxo_ao", "sleep_clk"; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&rpmhcc RPMH_CXO_CLK_A>, + <&sleep_clk>, + <&pcie_phy>, + <0>; + clock-names = "bi_tcxo", + "bi_tcxo_ao", + "sleep_clk", + "pcie_pipe_clk", + "usb3_phy_wrapper_gcc_usb30_pipe_clk"; #power-domain-cells = <1>; #clock-cells = <1>; #reset-cells = <1>; @@ -233,32 +241,27 @@ usb_qmpphy: phy@ff6000 { compatible = "qcom,sdx65-qmp-usb3-uni-phy"; - reg = <0x00ff6000 0x1c8>; - #address-cells = <1>; - #size-cells = <1>; - ranges; + reg = <0x00ff6000 0x2000>; clocks = <&gcc GCC_USB3_PHY_AUX_CLK>, + <&gcc GCC_USB3_PRIM_CLKREF_EN>, <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, - <&gcc GCC_USB3_PRIM_CLKREF_EN>; - clock-names = "aux", "cfg_ahb", "ref"; + <&gcc GCC_USB3_PHY_PIPE_CLK>; + clock-names = "aux", + "ref", + "cfg_ahb", + "pipe"; + clock-output-names = "usb3_uni_phy_pipe_clk_src"; + #clock-cells = <0>; + #phy-cells = <0>; - resets = <&gcc GCC_USB3PHY_PHY_BCR>, - <&gcc GCC_USB3_PHY_BCR>; - reset-names = "phy", "common"; + resets = <&gcc GCC_USB3_PHY_BCR>, + <&gcc GCC_USB3PHY_PHY_BCR>; + reset-names = "phy", + "phy_phy"; status = "disabled"; - usb_ssphy: phy@ff6200 { - reg = <0x00ff6e00 0x160>, - <0x00ff7000 0x1ec>, - <0x00ff6200 0x1e00>; - #phy-cells = <0>; - #clock-cells = <0>; - clocks = <&gcc GCC_USB3_PHY_PIPE_CLK>; - clock-names = "pipe0"; - clock-output-names = "usb3_uni_phy_pipe_clk_src"; - }; }; system_noc: interconnect@1620000 { @@ -338,7 +341,7 @@ power-domains = <&gcc PCIE_GDSC>; phys = <&pcie_phy>; - phy-names = "pcie-phy"; + phy-names = "pciephy"; max-link-speed = <3>; num-lanes = <2>; @@ -520,7 +523,7 @@ iommus = <&apps_smmu 0x1a0 0x0>; snps,dis_u2_susphy_quirk; snps,dis_enblslpm_quirk; - phys = <&usb_hsphy>, <&usb_ssphy>; + phys = <&usb_hsphy>, <&usb_qmpphy>; phy-names = "usb2-phy", "usb3-phy"; }; }; @@ -530,7 +533,7 @@ reg = <0x0c264000 0x1000>; }; - spmi_bus: qcom,spmi@c440000 { + spmi_bus: spmi@c440000 { compatible = "qcom,spmi-pmic-arb"; reg = <0xc440000 0xd00>, <0xc600000 0x2000000>, diff --git a/arch/arm/boot/dts/renesas/iwg20d-q7-dbcm-ca.dtsi b/arch/arm/boot/dts/renesas/iwg20d-q7-dbcm-ca.dtsi index e10f99278c77aa..de52218ceaa4c0 100644 --- a/arch/arm/boot/dts/renesas/iwg20d-q7-dbcm-ca.dtsi +++ b/arch/arm/boot/dts/renesas/iwg20d-q7-dbcm-ca.dtsi @@ -27,6 +27,15 @@ }; }; }; + + reg_1p8v: regulator-1p8v { + compatible = "regulator-fixed"; + regulator-name = "1P8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; }; &can1 { @@ -69,6 +78,12 @@ clocks = <&cec_clock>; clock-names = "cec"; + avdd-supply = <®_1p8v>; + dvdd-supply = <®_1p8v>; + pvdd-supply = <®_1p8v>; + dvdd-3v-supply = <®_3p3v>; + bgvdd-supply = <®_1p8v>; + adi,input-depth = <8>; adi,input-colorspace = "rgb"; adi,input-clock = "1x"; diff --git a/arch/arm/boot/dts/renesas/r8a7740-armadillo800eva.dts b/arch/arm/boot/dts/renesas/r8a7740-armadillo800eva.dts index d21e00e1f40152..e1ac2c161e7303 100644 --- a/arch/arm/boot/dts/renesas/r8a7740-armadillo800eva.dts +++ b/arch/arm/boot/dts/renesas/r8a7740-armadillo800eva.dts @@ -132,7 +132,7 @@ i2c-gpio,delay-us = <5>; }; - backlight { + backlight: backlight { compatible = "pwm-backlight"; pwms = <&tpu 2 33333 PWM_POLARITY_INVERTED>; brightness-levels = <0 1 2 4 8 16 32 64 128 255>; @@ -143,6 +143,18 @@ enable-gpios = <&pfc 61 GPIO_ACTIVE_HIGH>; }; + panel { + compatible = "ampire,am-800480l1tmqw-t00h"; + backlight = <&backlight>; + power-supply = <®_5p0v>; + + port { + panel_in: endpoint { + remote-endpoint = <&lcdc0_rgb>; + }; + }; + }; + sound { compatible = "simple-audio-card"; @@ -228,10 +240,22 @@ }; }; -&pfc { +&lcdc0 { pinctrl-0 = <&lcd0_pins>; pinctrl-names = "default"; + status = "okay"; + + ports { + port@0 { + endpoint { + remote-endpoint = <&panel_in>; + }; + }; + }; +}; + +&pfc { ether_pins: ether { groups = "gether_mii", "gether_int"; function = "gether"; diff --git a/arch/arm/boot/dts/renesas/r8a7740.dtsi b/arch/arm/boot/dts/renesas/r8a7740.dtsi index 1b2cf5fa322b29..55884ec701f8da 100644 --- a/arch/arm/boot/dts/renesas/r8a7740.dtsi +++ b/arch/arm/boot/dts/renesas/r8a7740.dtsi @@ -398,6 +398,61 @@ status = "disabled"; }; + lcdc0: lcd-controller@fe940000 { + compatible = "renesas,r8a7740-lcdc"; + reg = <0xfe940000 0x4000>; + interrupts = ; + clocks = <&mstp1_clks R8A7740_CLK_LCDC0>, + <&cpg_clocks R8A7740_CLK_M3>, <&lcdlclk0_clk>, + <&vou_clk>; + clock-names = "fck", "media", "lclk", "video"; + power-domains = <&pd_a4lc>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + lcdc0_rgb: endpoint { + }; + }; + }; + }; + + lcdc1: lcd-controller@fe944000 { + compatible = "renesas,r8a7740-lcdc"; + reg = <0xfe944000 0x4000>; + interrupts = ; + clocks = <&mstp1_clks R8A7740_CLK_LCDC1>, + <&cpg_clocks R8A7740_CLK_M3>, <&lcdlclk1_clk>, + <&vou_clk>; + clock-names = "fck", "media", "lclk", "video"; + power-domains = <&pd_a4lc>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + lcdc1_rgb: endpoint { + }; + }; + + port@1 { + reg = <1>; + + lcdc1_hdmi: endpoint { + }; + }; + }; + }; + tmu0: timer@fff80000 { compatible = "renesas,tmu-r8a7740", "renesas,tmu"; reg = <0xfff80000 0x2c>; @@ -474,6 +529,16 @@ #clock-cells = <0>; clock-frequency = <0>; }; + lcdlclk0_clk: lcdlclk0 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + }; + lcdlclk1_clk: lcdlclk1 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + }; /* Special CPG clocks */ cpg_clocks: cpg_clocks@e6150000 { diff --git a/arch/arm/boot/dts/renesas/r8a7745-iwg22d-sodimm-dbhd-ca.dts b/arch/arm/boot/dts/renesas/r8a7745-iwg22d-sodimm-dbhd-ca.dts index b1f679da36b2ed..a0b574398055ad 100644 --- a/arch/arm/boot/dts/renesas/r8a7745-iwg22d-sodimm-dbhd-ca.dts +++ b/arch/arm/boot/dts/renesas/r8a7745-iwg22d-sodimm-dbhd-ca.dts @@ -34,6 +34,15 @@ }; }; }; + + reg_1p8v: regulator-1p8v { + compatible = "regulator-fixed"; + regulator-name = "1P8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; }; &du { @@ -81,6 +90,12 @@ clock-names = "cec"; pd-gpios = <&gpio2 24 GPIO_ACTIVE_HIGH>; + avdd-supply = <®_1p8v>; + dvdd-supply = <®_1p8v>; + pvdd-supply = <®_1p8v>; + dvdd-3v-supply = <®_3p3v>; + bgvdd-supply = <®_1p8v>; + adi,input-depth = <8>; adi,input-colorspace = "rgb"; adi,input-clock = "1x"; diff --git a/arch/arm/boot/dts/renesas/r8a7745-iwg22d-sodimm.dts b/arch/arm/boot/dts/renesas/r8a7745-iwg22d-sodimm.dts index c105932f642ea5..24411044ef6c4f 100644 --- a/arch/arm/boot/dts/renesas/r8a7745-iwg22d-sodimm.dts +++ b/arch/arm/boot/dts/renesas/r8a7745-iwg22d-sodimm.dts @@ -182,7 +182,7 @@ VDDIO-supply = <®_3p3v>; }; - stmpe811@44 { + port-expander@44 { compatible = "st,stmpe811"; reg = <0x44>; interrupt-parent = <&gpio4>; @@ -197,7 +197,7 @@ /* internal ADC reference */ st,ref-sel = <0>; - stmpe_touchscreen { + touchscreen { compatible = "st,stmpe-ts"; /* 8 sample average control */ st,ave-ctrl = <3>; diff --git a/arch/arm/boot/dts/renesas/r8a7779-marzen.dts b/arch/arm/boot/dts/renesas/r8a7779-marzen.dts index 08ea149b1ee6f9..9b13e8d1538b00 100644 --- a/arch/arm/boot/dts/renesas/r8a7779-marzen.dts +++ b/arch/arm/boot/dts/renesas/r8a7779-marzen.dts @@ -52,10 +52,10 @@ states = <3300000 1>, <1800000 0>; }; - keyboard-irq { + keypad-0 { compatible = "gpio-keys"; - pinctrl-0 = <&keyboard_irq_pins>; + pinctrl-0 = <&keypad0_pins>; pinctrl-names = "default"; interrupt-parent = <&gpio0>; @@ -76,11 +76,11 @@ }; }; - keyboard-gpio { + keypad-1 { compatible = "gpio-keys-polled"; poll-interval = <50>; - pinctrl-0 = <&keyboard_gpio_pins>; + pinctrl-0 = <&keypad1_pins>; pinctrl-names = "default"; key-3 { @@ -193,7 +193,7 @@ }; &gpio0 { - keyboard-irq-hog { + keypad0-hog { gpio-hog; gpios = <17 GPIO_ACTIVE_LOW>, <18 GPIO_ACTIVE_LOW>; input; @@ -215,6 +215,35 @@ }; &lbsc { + flash@0 { + compatible = "cfi-flash"; + reg = <0x0 0x04000000>; + pinctrl-0 = <&flash_pins>; + pinctrl-names = "default"; + bank-width = <2>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "uboot"; + reg = <0x00000000 0x00040000>; + read-only; + }; + partition@40000 { + label = "uboot-env"; + reg = <0x00040000 0x00040000>; + read-only; + }; + partition@80000 { + label = "flash"; + reg = <0x00080000 0x03f80000>; + }; + }; + }; + ethernet@18000000 { compatible = "smsc,lan89218", "smsc,lan9115"; reg = <0x18000000 0x100>; @@ -266,6 +295,11 @@ }; }; + flash_pins: flash { + groups = "lbsc_cs0"; + function = "lbsc"; + }; + scif2_pins: scif2 { groups = "scif2_data_c"; function = "scif2"; @@ -286,11 +320,11 @@ function = "hspi0"; }; - keyboard_irq_pins: keyboard-irq { + keypad0_pins: keypad-0 { pins = "GP_0_17", "GP_0_18"; bias-pull-up; }; - keyboard_gpio_pins: keyboard-gpio { + keypad1_pins: keypad-1 { pins = "GP_0_19", "GP_0_20"; bias-pull-up; }; diff --git a/arch/arm/boot/dts/renesas/r8a7790-lager.dts b/arch/arm/boot/dts/renesas/r8a7790-lager.dts index 4d666ad8b114b3..2fba4d084001b9 100644 --- a/arch/arm/boot/dts/renesas/r8a7790-lager.dts +++ b/arch/arm/boot/dts/renesas/r8a7790-lager.dts @@ -122,6 +122,15 @@ }; }; + fixedregulator1v8: regulator-1v8 { + compatible = "regulator-fixed"; + regulator-name = "fixed-1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + fixedregulator3v3: regulator-3v3 { compatible = "regulator-fixed"; regulator-name = "fixed-3.3V"; @@ -303,7 +312,7 @@ * * IIC0/I2C0 does not appear to support fallback to GPIO. */ - i2cexio0: i2c-10 { + i2cexio0: i2c-mux1 { compatible = "i2c-demux-pinctrl"; i2c-parent = <&iic0>, <&i2c0>; i2c-bus-name = "i2c-exio0"; @@ -316,7 +325,7 @@ * This is similar to the arangement described for i2cexio0 (above) * with a fallback to GPIO also provided. */ - i2cexio1: i2c-11 { + i2cexio1: i2c-mux2 { compatible = "i2c-demux-pinctrl"; i2c-parent = <&iic1>, <&i2c1>, <&gpioi2c1>; i2c-bus-name = "i2c-exio1"; @@ -328,7 +337,7 @@ * IIC2 and I2C2 may be switched using pinmux. * A fallback to GPIO is also provided. */ - i2chdmi: i2c-12 { + i2chdmi: i2c-mux3 { compatible = "i2c-demux-pinctrl"; i2c-parent = <&iic2>, <&i2c2>, <&gpioi2c2>; i2c-bus-name = "i2c-hdmi"; @@ -361,6 +370,12 @@ clocks = <&cec_clock>; clock-names = "cec"; + avdd-supply = <&fixedregulator1v8>; + dvdd-supply = <&fixedregulator1v8>; + pvdd-supply = <&fixedregulator1v8>; + dvdd-3v-supply = <&fixedregulator3v3>; + bgvdd-supply = <&fixedregulator1v8>; + adi,input-depth = <8>; adi,input-colorspace = "rgb"; adi,input-clock = "1x"; @@ -417,7 +432,7 @@ * IIC3 and I2C3 may be switched using pinmux. * IIC3/I2C3 does not appear to support fallback to GPIO. */ - i2cpwr: i2c-13 { + i2cpwr: i2c-mux4 { compatible = "i2c-demux-pinctrl"; pinctrl-names = "default"; pinctrl-0 = <&pmic_irq_pins>; diff --git a/arch/arm/boot/dts/renesas/r8a7790-stout.dts b/arch/arm/boot/dts/renesas/r8a7790-stout.dts index fe14727eefe1ec..f9bc5b4f019d02 100644 --- a/arch/arm/boot/dts/renesas/r8a7790-stout.dts +++ b/arch/arm/boot/dts/renesas/r8a7790-stout.dts @@ -44,6 +44,15 @@ }; }; + fixedregulator1v8: regulator-1v8 { + compatible = "regulator-fixed"; + regulator-name = "fixed-1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + fixedregulator3v3: regulator-3v3 { compatible = "regulator-fixed"; regulator-name = "fixed-3.3V"; @@ -296,6 +305,12 @@ clocks = <&osc4_clk>; clock-names = "cec"; + avdd-supply = <&fixedregulator1v8>; + dvdd-supply = <&fixedregulator1v8>; + pvdd-supply = <&fixedregulator1v8>; + dvdd-3v-supply = <&fixedregulator3v3>; + bgvdd-supply = <&fixedregulator1v8>; + adi,input-depth = <8>; adi,input-colorspace = "rgb"; adi,input-clock = "1x"; diff --git a/arch/arm/boot/dts/renesas/r8a7791-koelsch.dts b/arch/arm/boot/dts/renesas/r8a7791-koelsch.dts index 545515b41ea3fa..e9c13bb03772af 100644 --- a/arch/arm/boot/dts/renesas/r8a7791-koelsch.dts +++ b/arch/arm/boot/dts/renesas/r8a7791-koelsch.dts @@ -174,6 +174,24 @@ }; }; + reg_1p8v: regulator-1v8 { + compatible = "regulator-fixed"; + regulator-name = "fixed-1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + reg_3p3v: regulator-3v3 { + compatible = "regulator-fixed"; + regulator-name = "fixed-3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + vcc_sdhi0: regulator-vcc-sdhi0 { compatible = "regulator-fixed"; @@ -340,7 +358,7 @@ * I2C1 is routed to EXIO connector B, pins 64 (SCL) + 66 (SDA). * A fallback to GPIO is provided. */ - i2cexio1: i2c-12 { + i2cexio1: i2c-mux1 { compatible = "i2c-demux-pinctrl"; i2c-parent = <&i2c1>, <&gpioi2c1>; i2c-bus-name = "i2c-exio1"; @@ -351,7 +369,7 @@ /* * A fallback to GPIO is provided for I2C2. */ - i2chdmi: i2c-13 { + i2chdmi: i2c-mux2 { compatible = "i2c-demux-pinctrl"; i2c-parent = <&i2c2>, <&gpioi2c2>; i2c-bus-name = "i2c-hdmi"; @@ -384,6 +402,12 @@ clocks = <&cec_clock>; clock-names = "cec"; + avdd-supply = <®_1p8v>; + dvdd-supply = <®_1p8v>; + pvdd-supply = <®_1p8v>; + dvdd-3v-supply = <®_3p3v>; + bgvdd-supply = <®_1p8v>; + adi,input-depth = <8>; adi,input-colorspace = "rgb"; adi,input-clock = "1x"; @@ -446,7 +470,7 @@ * I2C4 is routed to EXIO connector E, pins 37 (SCL) + 39 (SDA). * A fallback to GPIO is provided. */ - i2cexio4: i2c-14 { + i2cexio4: i2c-mux3 { compatible = "i2c-demux-pinctrl"; i2c-parent = <&i2c4>, <&gpioi2c4>; i2c-bus-name = "i2c-exio4"; diff --git a/arch/arm/boot/dts/renesas/r8a7791-porter.dts b/arch/arm/boot/dts/renesas/r8a7791-porter.dts index ec0a20d5130d6f..7e8bc06715f656 100644 --- a/arch/arm/boot/dts/renesas/r8a7791-porter.dts +++ b/arch/arm/boot/dts/renesas/r8a7791-porter.dts @@ -47,6 +47,24 @@ reg = <2 0x00000000 0 0x40000000>; }; + reg_1p8v: regulator-1v8 { + compatible = "regulator-fixed"; + regulator-name = "fixed-1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + reg_3p3v: regulator-3v3 { + compatible = "regulator-fixed"; + regulator-name = "fixed-3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + vcc_sdhi0: regulator-vcc-sdhi0 { compatible = "regulator-fixed"; @@ -148,7 +166,7 @@ /* * A fallback to GPIO is provided for I2C2. */ - i2chdmi: i2c-10 { + i2chdmi: i2c-mux1 { compatible = "i2c-demux-pinctrl"; i2c-parent = <&i2c2>, <&gpioi2c2>; i2c-bus-name = "i2c-hdmi"; @@ -179,6 +197,12 @@ interrupt-parent = <&gpio3>; interrupts = <29 IRQ_TYPE_LEVEL_LOW>; + avdd-supply = <®_1p8v>; + dvdd-supply = <®_1p8v>; + pvdd-supply = <®_1p8v>; + dvdd-3v-supply = <®_3p3v>; + bgvdd-supply = <®_1p8v>; + adi,input-depth = <8>; adi,input-colorspace = "rgb"; adi,input-clock = "1x"; diff --git a/arch/arm/boot/dts/renesas/r8a7792-blanche.dts b/arch/arm/boot/dts/renesas/r8a7792-blanche.dts index e793134f32a302..4f9838cf97ee4f 100644 --- a/arch/arm/boot/dts/renesas/r8a7792-blanche.dts +++ b/arch/arm/boot/dts/renesas/r8a7792-blanche.dts @@ -30,6 +30,15 @@ reg = <0 0x40000000 0 0x40000000>; }; + d1_8v: regulator-1v8 { + compatible = "regulator-fixed"; + regulator-name = "D1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + d3_3v: regulator-3v3 { compatible = "regulator-fixed"; regulator-name = "D3.3V"; @@ -182,6 +191,35 @@ }; &lbsc { + flash@0 { + compatible = "cfi-flash"; + reg = <0x00000000 0x04000000>; + pinctrl-0 = <&flash_pins>; + pinctrl-names = "default"; + bank-width = <2>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "uboot"; + reg = <0x00000000 0x00040000>; + read-only; + }; + partition@40000 { + label = "uboot-env"; + reg = <0x00040000 0x00040000>; + read-only; + }; + partition@80000 { + label = "flash"; + reg = <0x00080000 0x03f80000>; + }; + }; + }; + ethernet@18000000 { compatible = "smsc,lan89218", "smsc,lan9115"; reg = <0x18000000 0x100>; @@ -240,6 +278,11 @@ function = "du1"; }; + flash_pins: flash { + groups = "lbsc_cs0"; + function = "lbsc"; + }; + keyboard_pins: keyboard { pins = "GP_3_10", "GP_3_11", "GP_3_12", "GP_3_15", "GP_11_2"; bias-pull-up; @@ -296,6 +339,12 @@ interrupt-parent = <&irqc>; interrupts = <3 IRQ_TYPE_EDGE_FALLING>; + avdd-supply = <&d1_8v>; + dvdd-supply = <&d1_8v>; + pvdd-supply = <&d1_8v>; + dvdd-3v-supply = <&d3_3v>; + bgvdd-supply = <&d1_8v>; + adi,input-depth = <8>; adi,input-colorspace = "rgb"; adi,input-clock = "1x"; diff --git a/arch/arm/boot/dts/renesas/r8a7792-wheat.dts b/arch/arm/boot/dts/renesas/r8a7792-wheat.dts index f87e78fe3f6e6a..000f21a2a8630a 100644 --- a/arch/arm/boot/dts/renesas/r8a7792-wheat.dts +++ b/arch/arm/boot/dts/renesas/r8a7792-wheat.dts @@ -29,6 +29,15 @@ reg = <0 0x40000000 0 0x40000000>; }; + d1_8v: regulator-1v8 { + compatible = "regulator-fixed"; + regulator-name = "D1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + d3_3v: regulator-3v3 { compatible = "regulator-fixed"; regulator-name = "D3.3V"; @@ -254,6 +263,12 @@ reg = <0x3d>, <0x4d>, <0x2d>, <0x5d>; reg-names = "main", "edid", "cec", "packet"; + avdd-supply = <&d1_8v>; + dvdd-supply = <&d1_8v>; + pvdd-supply = <&d1_8v>; + dvdd-3v-supply = <&d3_3v>; + bgvdd-supply = <&d1_8v>; + adi,input-depth = <8>; adi,input-colorspace = "rgb"; adi,input-clock = "1x"; @@ -283,6 +298,12 @@ reg = <0x39>, <0x49>, <0x29>, <0x59>; reg-names = "main", "edid", "cec", "packet"; + avdd-supply = <&d1_8v>; + dvdd-supply = <&d1_8v>; + pvdd-supply = <&d1_8v>; + dvdd-3v-supply = <&d3_3v>; + bgvdd-supply = <&d1_8v>; + adi,input-depth = <8>; adi,input-colorspace = "rgb"; adi,input-clock = "1x"; diff --git a/arch/arm/boot/dts/renesas/r8a7793-gose.dts b/arch/arm/boot/dts/renesas/r8a7793-gose.dts index 79b537b2464266..1744fdbf9e0ce0 100644 --- a/arch/arm/boot/dts/renesas/r8a7793-gose.dts +++ b/arch/arm/boot/dts/renesas/r8a7793-gose.dts @@ -165,6 +165,24 @@ }; }; + reg_1p8v: regulator-1v8 { + compatible = "regulator-fixed"; + regulator-name = "fixed-1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + reg_3p3v: regulator-3v3 { + compatible = "regulator-fixed"; + regulator-name = "fixed-3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + vcc_sdhi0: regulator-vcc-sdhi0 { compatible = "regulator-fixed"; @@ -324,7 +342,7 @@ /* * A fallback to GPIO is provided for I2C2. */ - i2chdmi: i2c-11 { + i2chdmi: i2c-mux1 { compatible = "i2c-demux-pinctrl"; i2c-parent = <&i2c2>, <&gpioi2c2>; i2c-bus-name = "i2c-hdmi"; @@ -368,6 +386,12 @@ interrupt-parent = <&gpio3>; interrupts = <29 IRQ_TYPE_LEVEL_LOW>; + avdd-supply = <®_1p8v>; + dvdd-supply = <®_1p8v>; + pvdd-supply = <®_1p8v>; + dvdd-3v-supply = <®_3p3v>; + bgvdd-supply = <®_1p8v>; + adi,input-depth = <8>; adi,input-colorspace = "rgb"; adi,input-clock = "1x"; @@ -430,7 +454,7 @@ * I2C4 is routed to EXIO connector E, pins 37 (SCL) + 39 (SDA). * A fallback to GPIO is provided. */ - i2cexio4: i2c-12 { + i2cexio4: i2c-mux2 { compatible = "i2c-demux-pinctrl"; i2c-parent = <&i2c4>, <&gpioi2c4>; i2c-bus-name = "i2c-exio4"; diff --git a/arch/arm/boot/dts/renesas/r8a7794-alt.dts b/arch/arm/boot/dts/renesas/r8a7794-alt.dts index 08df031bc27c9e..c0d067df22a03d 100644 --- a/arch/arm/boot/dts/renesas/r8a7794-alt.dts +++ b/arch/arm/boot/dts/renesas/r8a7794-alt.dts @@ -192,7 +192,7 @@ /* * A fallback to GPIO is provided for I2C1. */ - i2chdmi: i2c-11 { + i2chdmi: i2c-mux1 { compatible = "i2c-demux-pinctrl"; i2c-parent = <&i2c1>, <&gpioi2c1>; i2c-bus-name = "i2c-hdmi"; @@ -222,7 +222,7 @@ * I2C4 is routed to EXIO connector B, pins 73 (SCL) + 74 (SDA). * A fallback to GPIO is provided. */ - i2cexio4: i2c-14 { + i2cexio4: i2c-mux2 { compatible = "i2c-demux-pinctrl"; i2c-parent = <&i2c4>, <&gpioi2c4>; i2c-bus-name = "i2c-exio4"; diff --git a/arch/arm/boot/dts/renesas/r8a7794-silk.dts b/arch/arm/boot/dts/renesas/r8a7794-silk.dts index b7af1befa126ba..43d480a7f3eacc 100644 --- a/arch/arm/boot/dts/renesas/r8a7794-silk.dts +++ b/arch/arm/boot/dts/renesas/r8a7794-silk.dts @@ -102,6 +102,15 @@ }; }; + d1_8v: regulator-d1-8v { + compatible = "regulator-fixed"; + regulator-name = "D1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + d3_3v: regulator-d3-3v { compatible = "regulator-fixed"; regulator-name = "D3.3V"; @@ -225,7 +234,7 @@ /* * A fallback to GPIO is provided for I2C1. */ - i2chdmi: i2c-10 { + i2chdmi: i2c-mux1 { compatible = "i2c-demux-pinctrl"; i2c-parent = <&i2c1>, <&gpioi2c1>; i2c-bus-name = "i2c-hdmi"; @@ -256,6 +265,12 @@ interrupt-parent = <&gpio5>; interrupts = <23 IRQ_TYPE_LEVEL_LOW>; + avdd-supply = <&d1_8v>; + dvdd-supply = <&d1_8v>; + pvdd-supply = <&d1_8v>; + dvdd-3v-supply = <&d3_3v>; + bgvdd-supply = <&d1_8v>; + adi,input-depth = <8>; adi,input-colorspace = "rgb"; adi,input-clock = "1x"; diff --git a/arch/arm/boot/dts/renesas/r9a06g032.dtsi b/arch/arm/boot/dts/renesas/r9a06g032.dtsi index 0fa565a1c3ad39..fa63e1afc4ef4c 100644 --- a/arch/arm/boot/dts/renesas/r9a06g032.dtsi +++ b/arch/arm/boot/dts/renesas/r9a06g032.dtsi @@ -437,7 +437,7 @@ }; can0: can@52104000 { - compatible = "renesas,r9a06g032-sja1000","renesas,rzn1-sja1000"; + compatible = "renesas,r9a06g032-sja1000", "renesas,rzn1-sja1000"; reg = <0x52104000 0x800>; reg-io-width = <4>; interrupts = ; diff --git a/arch/arm/boot/dts/rockchip/Makefile b/arch/arm/boot/dts/rockchip/Makefile index 0f46e18fe2754b..ab4cd9aab7227c 100644 --- a/arch/arm/boot/dts/rockchip/Makefile +++ b/arch/arm/boot/dts/rockchip/Makefile @@ -2,7 +2,9 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \ rv1108-elgin-r1.dtb \ rv1108-evb.dtb \ + rv1109-sonoff-ihost.dtb \ rv1126-edgeble-neu2-io.dtb \ + rv1126-sonoff-ihost.dtb \ rk3036-evb.dtb \ rk3036-kylin.dtb \ rk3066a-bqcurie2.dtb \ @@ -10,6 +12,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \ rk3066a-mk808.dtb \ rk3066a-rayeager.dtb \ rk3128-evb.dtb \ + rk3128-xpi-3128.dtb \ rk3188-bqedison2qc.dtb \ rk3188-px3-evb.dtb \ rk3188-radxarock.dtb \ diff --git a/arch/arm/boot/dts/rockchip/rk3036-kylin.dts b/arch/arm/boot/dts/rockchip/rk3036-kylin.dts index 67e1e04139e732..e32c73d32f0aaf 100644 --- a/arch/arm/boot/dts/rockchip/rk3036-kylin.dts +++ b/arch/arm/boot/dts/rockchip/rk3036-kylin.dts @@ -8,11 +8,26 @@ model = "Rockchip RK3036 KylinBoard"; compatible = "rockchip,rk3036-kylin", "rockchip,rk3036"; + chosen { + stdout-path = "serial2:115200n8"; + }; + memory@60000000 { device_type = "memory"; reg = <0x60000000 0x20000000>; }; + hdmi_con: hdmi-con { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_con_in: endpoint { + remote-endpoint = <&hdmi_out_con>; + }; + }; + }; + leds: gpio-leds { compatible = "gpio-leds"; @@ -110,6 +125,12 @@ status = "okay"; }; +&hdmi_out { + hdmi_out_con: endpoint { + remote-endpoint = <&hdmi_con_in>; + }; +}; + &i2c1 { clock-frequency = <400000>; diff --git a/arch/arm/boot/dts/rockchip/rk3036.dtsi b/arch/arm/boot/dts/rockchip/rk3036.dtsi index 78686fc72ce69a..04af224005f8c2 100644 --- a/arch/arm/boot/dts/rockchip/rk3036.dtsi +++ b/arch/arm/boot/dts/rockchip/rk3036.dtsi @@ -17,6 +17,9 @@ interrupt-parent = <&gic>; aliases { + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; i2c0 = &i2c0; i2c1 = &i2c1; i2c2 = &i2c2; @@ -282,7 +285,6 @@ clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>, <&cru SCLK_EMMC_DRV>, <&cru SCLK_EMMC_SAMPLE>; clock-names = "biu", "ciu", "ciu-drive", "ciu-sample"; - rockchip,default-sample-phase = <158>; disable-wp; dmas = <&pdma 12>; dma-names = "rx-tx"; @@ -402,12 +404,20 @@ pinctrl-0 = <&hdmi_ctl>; status = "disabled"; - hdmi_in: port { + ports { #address-cells = <1>; #size-cells = <0>; - hdmi_in_vop: endpoint@0 { + + hdmi_in: port@0 { reg = <0>; - remote-endpoint = <&vop_out_hdmi>; + + hdmi_in_vop: endpoint { + remote-endpoint = <&vop_out_hdmi>; + }; + }; + + hdmi_out: port@1 { + reg = <1>; }; }; }; diff --git a/arch/arm/boot/dts/rockchip/rk3066a.dtsi b/arch/arm/boot/dts/rockchip/rk3066a.dtsi index de9915d946f74f..30139f21de64d0 100644 --- a/arch/arm/boot/dts/rockchip/rk3066a.dtsi +++ b/arch/arm/boot/dts/rockchip/rk3066a.dtsi @@ -13,6 +13,11 @@ / { compatible = "rockchip,rk3066a"; + aliases { + gpio4 = &gpio4; + gpio6 = &gpio6; + }; + cpus { #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm/boot/dts/rockchip/rk3128-evb.dts b/arch/arm/boot/dts/rockchip/rk3128-evb.dts index c38f42497cbd9e..c7ab7fcdb43615 100644 --- a/arch/arm/boot/dts/rockchip/rk3128-evb.dts +++ b/arch/arm/boot/dts/rockchip/rk3128-evb.dts @@ -12,11 +12,6 @@ compatible = "rockchip,rk3128-evb", "rockchip,rk3128"; aliases { - gpio0 = &gpio0; - gpio1 = &gpio1; - gpio2 = &gpio2; - gpio3 = &gpio3; - i2c1 = &i2c1; mmc0 = &emmc; }; diff --git a/arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts b/arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts new file mode 100644 index 00000000000000..03a97881519a6a --- /dev/null +++ b/arch/arm/boot/dts/rockchip/rk3128-xpi-3128.dts @@ -0,0 +1,425 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +/dts-v1/; + +#include +#include +#include "rk3128.dtsi" + +/ { + model = "Geniatech XPI-3128"; + compatible = "geniatech,xpi-3128", "rockchip,rk3128"; + + aliases { + ethernet0 = &gmac; + mmc0 = &emmc; + mmc1 = &sdmmc; + }; + + memory@60000000 { + device_type = "memory"; + reg = <0x60000000 0x40000000>; + }; + + chosen { + stdout-path = &uart1; + }; + + adc-keys { + compatible = "adc-keys"; + io-channels = <&saradc 1>; + io-channel-names = "buttons"; + keyup-threshold-microvolt = <3300000>; + + button-recovery { + label = "Recovery"; + linux,code = ; + press-threshold-microvolt = <0>; + }; + }; + + dc_5v: dc-5v-regulator { + compatible = "regulator-fixed"; + regulator-name = "DC_5V"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + regulator-boot-on; + }; + + /* + * This is a vbus-supply, which also supplies the GL852G usb hub, + * thus has to be always-on + */ + host_pwr_5v: host-pwr-5v-regulator { + compatible = "regulator-fixed"; + gpio = <&gpio3 RK_PC4 GPIO_ACTIVE_HIGH>; + startup-delay-us = <1500>; + regulator-name = "HOST_PWR_5V"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&dc_5v>; + pinctrl-names = "default"; + pinctrl-0 = <&host_drv>; + enable-active-high; + regulator-always-on; + }; + + ir-receiver { + compatible = "gpio-ir-receiver"; + gpios = <&gpio3 RK_PD2 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&ir_int>; + }; + + leds { + compatible = "gpio-leds"; + + led-power { + gpios = <&gpio0 RK_PD2 GPIO_ACTIVE_HIGH>; + function = LED_FUNCTION_POWER; + color = ; + default-state = "on"; + pinctrl-names = "default"; + pinctrl-0 = <&power_led>; + }; + + led-spd { + gpios = <&gpio3 RK_PB3 GPIO_ACTIVE_LOW>; + function = LED_FUNCTION_LAN; + color = ; + /* + * currently not allowed to be set as per + * https://www.kernel.org/doc/Documentation/devicetree/bindings/leds/common.yaml + * and needs to set in userspace: + * + * linux,default-trigger = "netdev"; + */ + pinctrl-names = "default"; + pinctrl-0 = <&spd_led>; + }; + }; + + mcu3v3: mcu3v3-regulator { + compatible = "regulator-fixed"; + regulator-name = "MCU3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_io>; + regulator-always-on; + regulator-boot-on; + }; + + vcc_ddr: vcc-ddr-regulator { + compatible = "regulator-fixed"; + regulator-name = "VCC_DDR"; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; + vin-supply = <&vcc_sys>; + regulator-always-on; + regulator-boot-on; + }; + + vcc_io: vcc-io-regulator { + compatible = "regulator-fixed"; + regulator-name = "VCC_IO"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_sys>; + regulator-always-on; + regulator-boot-on; + }; + + vcc_lan: vcc-lan-regulator { + compatible = "regulator-fixed"; + regulator-name = "VCC_LAN"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_io>; + regulator-always-on; + regulator-boot-on; + }; + + vcc_sd: vcc-sd-regulator { + compatible = "regulator-fixed"; + gpio = <&gpio1 RK_PB6 GPIO_ACTIVE_LOW>; + startup-delay-us = <500>; + regulator-name = "VCC_SD"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_io>; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc_pwren>; + }; + + vcc_sys: vcc-sys-regulator { + compatible = "regulator-fixed"; + regulator-name = "VCC_SYS"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&dc_5v>; + regulator-always-on; + regulator-boot-on; + }; + + vcc33_hdmi: vcc33-hdmi-regulator { + compatible = "regulator-fixed"; + regulator-name = "VCC33_HDMI"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcca_33>; + regulator-always-on; + regulator-boot-on; + }; + + vcca_33: vcca-33-regulator { + compatible = "regulator-fixed"; + regulator-name = "VCCA_33"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_sys>; + regulator-always-on; + regulator-boot-on; + }; + + vdd_11: vdd-11-regulator { + compatible = "regulator-fixed"; + regulator-name = "VDD_11"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + vin-supply = <&vcc_sys>; + regulator-always-on; + regulator-boot-on; + }; + + vdd11_hdmi: vdd11-hdmi-regulator { + compatible = "regulator-fixed"; + regulator-name = "VDD11_HDMI"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + vin-supply = <&vdd_11>; + regulator-always-on; + regulator-boot-on; + }; + + vdd_arm: vdd-arm-regulator { + compatible = "pwm-regulator"; + regulator-name = "VDD_ARM"; + pwms = <&pwm1 0 25000 1>; + pwm-supply = <&vcc_sys>; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1400000>; + regulator-always-on; + regulator-boot-on; + }; + + /* + * As per schematics vdd_log is minimum 900 mV, maximum 1400 mV. + * Since there are HW blocks in PD_LOGIC (which are all driven by + * this supply), that either do not have a driver at all or the + * driver does not implement regulator support we have to make + * sure here that the voltage never drops below 1050 mV. + */ + vdd_log: vdd-log-regulator { + compatible = "pwm-regulator"; + regulator-name = "VDD_LOG"; + pwms = <&pwm2 0 25000 1>; + pwm-dutycycle-range = <30 100>; + pwm-supply = <&vcc_sys>; + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1400000>; + regulator-ramp-delay = <4000>; + regulator-always-on; + regulator-boot-on; + }; + +}; + +&cpu0 { + cpu-supply = <&vdd_arm>; +}; + +&emmc { + bus-width = <8>; + vmmc-supply = <&vcc_io>; + pinctrl-names = "default"; + pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8>; + cap-mmc-highspeed; + mmc-ddr-3_3v; + no-sd; + no-sdio; + status = "okay"; +}; + +&gmac { + clock_in_out = "output"; + phy-supply = <&vcc_lan>; + phy-mode = "rmii"; + phy-handle = <&phy0>; + assigned-clocks = <&cru SCLK_MAC_SRC>; + assigned-clock-rates= <50000000>; + pinctrl-names = "default"; + pinctrl-0 = <&rmii_pins>; + status = "okay"; +}; + +&gpio0 { + gpio-line-names = /* GPIO0 A0-A7 */ + "", "", "HEADER_5", "HEADER_3", + "", "", "", "", + /* GPIO0 B0-B7 */ + "HEADER_22", "HEADER_23", "", "HEADER_19", + "HEADER_26", "HEADER_21", "HEADER_24", "", + /* GPIO0 C0-C7 */ + "", "HEADER_18", "", "", + "", "", "", "", + /* GPIO0 D0-D7 */ + "HEADER_36", "", "", "", + "", "", "HEADER_13", ""; +}; + +&gpio1 { + gpio-line-names = /* GPIO1 A0-A7 */ + "HEADER_7", "HEADER_35", "HEADER_33", "HEADER_37", + "HEADER_40", "HEADER_38", "", "", + /* GPIO1 B0-B7 */ + "HEADER_11", "", "", "HEADER_29", + "HEADER_31", "", "", "", + /* GPIO1 C0-C7 */ + "", "", "", "", + "", "", "", "", + /* GPIO1 D0-D7 */ + "", "", "", "", + "", "", "", ""; +}; + +&gpio2 { + gpio-line-names = /* GPIO2 A0-A7 */ + "", "", "", "", + "", "", "", "", + /* GPIO2 B0-B7 */ + "", "", "", "", + "", "", "", "", + /* GPIO2 C0-C7 */ + "", "", "", "", + "HEADER_27", "", "", "", + /* GPIO2 D0-D7 */ + "", "", "HEADER_8", "HEADER_10", + "", "", "", ""; +}; + +&gpio3 { + gpio-line-names = /* GPIO3 A0-A7 */ + "", "", "", "", + "", "", "", "", + /* GPIO3 B0-B7 */ + "", "", "", "", + "", "", "", "", + /* GPIO3 C0-C7 */ + "", "HEADER_32", "", "", + "", "", "", "HEADER_12", + /* GPIO3 D0-D7 */ + "", "", "", "HEADER_15", + "", "", "", ""; +}; + +&gpu { + mali-supply = <&vdd_log>; + status = "okay"; +}; + +&mdio { + phy0: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + max-speed = <100>; + /* T2.2.4 min. 1 us */ + reset-assert-us = <10>; + /* T2.2.1 + T2.2.2 + T2.2.3 min. 6.05 us */ + reset-deassert-us = <20>; + reset-gpios = <&gpio2 RK_PD0 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&dp83848c_rst>; + }; +}; + +&pinctrl { + dp83848c { + dp83848c_rst: dp83848c-rst { + rockchip,pins = <2 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + ir-receiver { + ir_int: ir-int { + rockchip,pins = <3 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + leds { + power_led: power-led { + rockchip,pins = <0 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + spd_led: spd-led { + rockchip,pins = <3 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + usb2 { + host_drv: host-drv { + rockchip,pins = <3 RK_PC4 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; + +&pwm1 { + status = "okay"; +}; + +&pwm2 { + status = "okay"; +}; + +&saradc { + vref-supply = <&vcc_io>; + status = "okay"; +}; + +&sdmmc { + bus-width = <4>; + vmmc-supply = <&vcc_sd>; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc_bus4 &sdmmc_clk &sdmmc_cmd &sdmmc_det>; + disable-wp; + cap-sd-highspeed; + no-mmc; + no-sdio; + status = "okay"; +}; + +&uart1 { + status = "okay"; +}; + +&usb_host_ehci { + status = "okay"; +}; + +&usb_otg { + vusb_a-supply = <&vcc_io>; + vusb_d-supply = <&vdd_11>; + status = "okay"; +}; + +&usb2phy { + status = "okay"; +}; + +&usb2phy_host { + status = "okay"; +}; + +&usb2phy_otg { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/rockchip/rk3128.dtsi b/arch/arm/boot/dts/rockchip/rk3128.dtsi index 01edf244ddeef6..e2264c40b924c6 100644 --- a/arch/arm/boot/dts/rockchip/rk3128.dtsi +++ b/arch/arm/boot/dts/rockchip/rk3128.dtsi @@ -8,6 +8,7 @@ #include #include #include +#include / { compatible = "rockchip,rk3128"; @@ -15,6 +16,20 @@ #address-cells = <1>; #size-cells = <1>; + aliases { + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; + i2c0 = &i2c0; + i2c1 = &i2c1; + i2c2 = &i2c2; + i2c3 = &i2c3; + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + }; + arm-pmu { compatible = "arm,cortex-a7-pmu"; interrupts = , @@ -100,6 +115,27 @@ }; }; + gpu_opp_table: opp-table-1 { + compatible = "operating-points-v2"; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + opp-microvolt = <975000 975000 1250000>; + }; + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + opp-microvolt = <1050000 1050000 1250000>; + }; + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + opp-microvolt = <1150000 1150000 1250000>; + }; + opp-480000000 { + opp-hz = /bits/ 64 <480000000>; + opp-microvolt = <1250000 1250000 1250000>; + }; + }; + timer { compatible = "arm,armv7-timer"; interrupts = , @@ -130,9 +166,119 @@ }; }; + gpu: gpu@10090000 { + compatible = "rockchip,rk3128-mali", "arm,mali-400"; + reg = <0x10090000 0x10000>; + interrupts = , + , + , + , + , + ; + interrupt-names = "gp", + "gpmmu", + "pp0", + "ppmmu0", + "pp1", + "ppmmu1"; + clocks = <&cru ACLK_GPU>, <&cru ACLK_GPU>; + clock-names = "bus", "core"; + operating-points-v2 = <&gpu_opp_table>; + resets = <&cru SRST_GPU>; + power-domains = <&power RK3128_PD_GPU>; + status = "disabled"; + }; + pmu: syscon@100a0000 { compatible = "rockchip,rk3128-pmu", "syscon", "simple-mfd"; reg = <0x100a0000 0x1000>; + + power: power-controller { + compatible = "rockchip,rk3128-power-controller"; + #power-domain-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + + power-domain@RK3128_PD_VIO { + reg = ; + clocks = <&cru ACLK_CIF>, + <&cru HCLK_CIF>, + <&cru DCLK_EBC>, + <&cru HCLK_EBC>, + <&cru ACLK_IEP>, + <&cru HCLK_IEP>, + <&cru ACLK_LCDC0>, + <&cru HCLK_LCDC0>, + <&cru PCLK_MIPI>, + <&cru ACLK_RGA>, + <&cru HCLK_RGA>, + <&cru ACLK_VIO0>, + <&cru ACLK_VIO1>, + <&cru HCLK_VIO>, + <&cru HCLK_VIO_H2P>, + <&cru DCLK_VOP>, + <&cru SCLK_VOP>; + pm_qos = <&qos_ebc>, + <&qos_iep>, + <&qos_lcdc>, + <&qos_rga>, + <&qos_vip>; + #power-domain-cells = <0>; + }; + + power-domain@RK3128_PD_VIDEO { + reg = ; + clocks = <&cru ACLK_VDPU>, + <&cru HCLK_VDPU>, + <&cru ACLK_VEPU>, + <&cru HCLK_VEPU>, + <&cru SCLK_HEVC_CORE>; + pm_qos = <&qos_vpu>; + #power-domain-cells = <0>; + }; + + power-domain@RK3128_PD_GPU { + reg = ; + clocks = <&cru ACLK_GPU>; + pm_qos = <&qos_gpu>; + #power-domain-cells = <0>; + }; + }; + }; + + qos_gpu: qos@1012d000 { + compatible = "rockchip,rk3128-qos", "syscon"; + reg = <0x1012d000 0x20>; + }; + + qos_vpu: qos@1012e000 { + compatible = "rockchip,rk3128-qos", "syscon"; + reg = <0x1012e000 0x20>; + }; + + qos_rga: qos@1012f000 { + compatible = "rockchip,rk3128-qos", "syscon"; + reg = <0x1012f000 0x20>; + }; + + qos_ebc: qos@1012f080 { + compatible = "rockchip,rk3128-qos", "syscon"; + reg = <0x1012f080 0x20>; + }; + + qos_iep: qos@1012f100 { + compatible = "rockchip,rk3128-qos", "syscon"; + reg = <0x1012f100 0x20>; + }; + + qos_lcdc: qos@1012f180 { + compatible = "rockchip,rk3128-qos", "syscon"; + reg = <0x1012f180 0x20>; + }; + + qos_vip: qos@1012f200 { + compatible = "rockchip,rk3128-qos", "syscon"; + reg = <0x1012f200 0x20>; }; gic: interrupt-controller@10139000 { @@ -154,6 +300,9 @@ clocks = <&cru HCLK_OTG>; clock-names = "otg"; dr_mode = "otg"; + g-np-tx-fifo-size = <16>; + g-rx-fifo-size = <280>; + g-tx-fifo-size = <256 128 128 64 32 16>; phys = <&usb2phy_otg>; phy-names = "usb2-phy"; status = "disabled"; @@ -163,6 +312,7 @@ compatible = "generic-ehci"; reg = <0x101c0000 0x20000>; interrupts = ; + clocks = <&cru HCLK_HOST2>; phys = <&usb2phy_host>; phy-names = "usb"; status = "disabled"; @@ -172,6 +322,7 @@ compatible = "generic-ohci"; reg = <0x101e0000 0x20000>; interrupts = ; + clocks = <&cru HCLK_HOST2>; phys = <&usb2phy_host>; phy-names = "usb"; status = "disabled"; @@ -261,6 +412,8 @@ clocks = <&cru SCLK_OTGPHY0>; clock-names = "phyclk"; clock-output-names = "usb480m_phy"; + assigned-clocks = <&cru SCLK_USB480M>; + assigned-clock-parents = <&usb2phy>; #clock-cells = <0>; status = "disabled"; @@ -518,6 +671,34 @@ #dma-cells = <1>; }; + gmac: ethernet@2008c000 { + compatible = "rockchip,rk3128-gmac"; + reg = <0x2008c000 0x4000>; + interrupts = , + ; + interrupt-names = "macirq", "eth_wake_irq"; + clocks = <&cru SCLK_MAC>, + <&cru SCLK_MAC_RX>, <&cru SCLK_MAC_TX>, + <&cru SCLK_MAC_REF>, <&cru SCLK_MAC_REFOUT>, + <&cru ACLK_GMAC>, <&cru PCLK_GMAC>; + clock-names = "stmmaceth", + "mac_clk_rx", "mac_clk_tx", + "clk_mac_ref", "clk_mac_refout", + "aclk_mac", "pclk_mac"; + resets = <&cru SRST_GMAC>; + reset-names = "stmmaceth"; + rockchip,grf = <&grf>; + rx-fifo-depth = <4096>; + tx-fifo-depth = <2048>; + status = "disabled"; + + mdio: mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <0x1>; + #size-cells = <0x0>; + }; + }; + pinctrl: pinctrl { compatible = "rockchip,rk3128-pinctrl"; rockchip,grf = <&grf>; @@ -843,6 +1024,10 @@ rockchip,pins = <1 RK_PB7 1 &pcfg_pull_default>; }; + sdmmc_det: sdmmc-det { + rockchip,pins = <1 RK_PC1 1 &pcfg_pull_default>; + }; + sdmmc_wp: sdmmc-wp { rockchip,pins = <1 RK_PA7 1 &pcfg_pull_default>; }; diff --git a/arch/arm/boot/dts/rockchip/rk322x.dtsi b/arch/arm/boot/dts/rockchip/rk322x.dtsi index a721744cbfd17f..831561fc181460 100644 --- a/arch/arm/boot/dts/rockchip/rk322x.dtsi +++ b/arch/arm/boot/dts/rockchip/rk322x.dtsi @@ -15,6 +15,10 @@ interrupt-parent = <&gic>; aliases { + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; serial0 = &uart0; serial1 = &uart1; serial2 = &uart2; diff --git a/arch/arm/boot/dts/rockchip/rk3288.dtsi b/arch/arm/boot/dts/rockchip/rk3288.dtsi index cb9cdaddffd429..ead343dc3df101 100644 --- a/arch/arm/boot/dts/rockchip/rk3288.dtsi +++ b/arch/arm/boot/dts/rockchip/rk3288.dtsi @@ -19,6 +19,15 @@ aliases { ethernet0 = &gmac; + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; + gpio4 = &gpio4; + gpio5 = &gpio5; + gpio6 = &gpio6; + gpio7 = &gpio7; + gpio8 = &gpio8; i2c0 = &i2c0; i2c1 = &i2c1; i2c2 = &i2c2; diff --git a/arch/arm/boot/dts/rockchip/rk3xxx.dtsi b/arch/arm/boot/dts/rockchip/rk3xxx.dtsi index cb4e42ede56a9a..f37137f298d5f1 100644 --- a/arch/arm/boot/dts/rockchip/rk3xxx.dtsi +++ b/arch/arm/boot/dts/rockchip/rk3xxx.dtsi @@ -16,6 +16,10 @@ aliases { ethernet0 = &emac; + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; i2c0 = &i2c0; i2c1 = &i2c1; i2c2 = &i2c2; diff --git a/arch/arm/boot/dts/rockchip/rv1109-sonoff-ihost.dts b/arch/arm/boot/dts/rockchip/rv1109-sonoff-ihost.dts new file mode 100644 index 00000000000000..45dced8087a3c0 --- /dev/null +++ b/arch/arm/boot/dts/rockchip/rv1109-sonoff-ihost.dts @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2020 Rockchip Electronics Co., Ltd. + */ + +/dts-v1/; +#include "rv1109.dtsi" +#include "rv1126-sonoff-ihost.dtsi" + +/ { + model = "Sonoff iHost 2G"; + compatible = "itead,sonoff-ihost", "rockchip,rv1109"; +}; + +&cpu0 { + cpu-supply = <&vdd_arm>; +}; + +&cpu1 { + cpu-supply = <&vdd_arm>; +}; diff --git a/arch/arm/boot/dts/rockchip/rv1109.dtsi b/arch/arm/boot/dts/rockchip/rv1109.dtsi new file mode 100644 index 00000000000000..9cbaa08ab1b8c9 --- /dev/null +++ b/arch/arm/boot/dts/rockchip/rv1109.dtsi @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd. + */ + +/dts-v1/; + +#include "rv1126.dtsi" + +/ { + compatible = "rockchip,rv1109"; + + cpus { + /delete-node/ cpu@f02; + /delete-node/ cpu@f03; + }; + + arm-pmu { + interrupts = , + ; + interrupt-affinity = <&cpu0>, <&cpu1>; + }; +}; diff --git a/arch/arm/boot/dts/rockchip/rv1126-edgeble-neu2-io.dts b/arch/arm/boot/dts/rockchip/rv1126-edgeble-neu2-io.dts index f09be840596454..0c2396b8f8db6d 100644 --- a/arch/arm/boot/dts/rockchip/rv1126-edgeble-neu2-io.dts +++ b/arch/arm/boot/dts/rockchip/rv1126-edgeble-neu2-io.dts @@ -61,7 +61,7 @@ phy-mode = "rgmii"; phy-supply = <&vcc_3v3>; pinctrl-names = "default"; - pinctrl-0 = <&rgmiim1_pins &clk_out_ethernetm1_pins>; + pinctrl-0 = <&rgmiim1_miim &rgmiim1_bus2 &rgmiim1_bus4 &clk_out_ethernetm1_pins>; tx_delay = <0x2a>; rx_delay = <0x1a>; status = "okay"; diff --git a/arch/arm/boot/dts/rockchip/rv1126-pinctrl.dtsi b/arch/arm/boot/dts/rockchip/rv1126-pinctrl.dtsi index bb34b0c9cb4a88..06b1d7f2d8585a 100644 --- a/arch/arm/boot/dts/rockchip/rv1126-pinctrl.dtsi +++ b/arch/arm/boot/dts/rockchip/rv1126-pinctrl.dtsi @@ -87,6 +87,16 @@ <0 RK_PB5 1 &pcfg_pull_none_drv_level_0_smt>; }; }; + i2c2 { + /omit-if-no-ref/ + i2c2_xfer: i2c2-xfer { + rockchip,pins = + /* i2c2_scl */ + <0 RK_PC2 1 &pcfg_pull_none_drv_level_0_smt>, + /* i2c2_sda */ + <0 RK_PC3 1 &pcfg_pull_none_drv_level_0_smt>; + }; + }; pwm2 { /omit-if-no-ref/ pwm2m0_pins: pwm2m0-pins { @@ -105,36 +115,56 @@ }; rgmii { /omit-if-no-ref/ - rgmiim1_pins: rgmiim1-pins { + rgmiim1_miim: rgmiim1-miim { rockchip,pins = /* rgmii_mdc_m1 */ <2 RK_PC2 2 &pcfg_pull_none>, /* rgmii_mdio_m1 */ - <2 RK_PC1 2 &pcfg_pull_none>, - /* rgmii_rxclk_m1 */ - <2 RK_PD3 2 &pcfg_pull_none>, + <2 RK_PC1 2 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + rgmiim1_rxer: rgmiim1-rxer { + rockchip,pins = + /* rgmii_rxer_m1 */ + <2 RK_PC0 2 &pcfg_pull_none>; + }; + /omit-if-no-ref/ + rgmiim1_bus2: rgmiim1-bus2 { + rockchip,pins = /* rgmii_rxd0_m1 */ <2 RK_PB5 2 &pcfg_pull_none>, /* rgmii_rxd1_m1 */ <2 RK_PB6 2 &pcfg_pull_none>, - /* rgmii_rxd2_m1 */ - <2 RK_PC7 2 &pcfg_pull_none>, - /* rgmii_rxd3_m1 */ - <2 RK_PD0 2 &pcfg_pull_none>, /* rgmii_rxdv_m1 */ <2 RK_PB4 2 &pcfg_pull_none>, - /* rgmii_txclk_m1 */ - <2 RK_PD2 2 &pcfg_pull_none_drv_level_3>, /* rgmii_txd0_m1 */ <2 RK_PC3 2 &pcfg_pull_none_drv_level_3>, /* rgmii_txd1_m1 */ <2 RK_PC4 2 &pcfg_pull_none_drv_level_3>, + /* rgmii_txen_m1 */ + <2 RK_PC6 2 &pcfg_pull_none_drv_level_3>; + }; + /omit-if-no-ref/ + rgmiim1_bus4: rgmiim1-bus4 { + rockchip,pins = + /* rgmii_rxclk_m1 */ + <2 RK_PD3 2 &pcfg_pull_none>, + /* rgmii_rxd2_m1 */ + <2 RK_PC7 2 &pcfg_pull_none>, + /* rgmii_rxd3_m1 */ + <2 RK_PD0 2 &pcfg_pull_none>, + /* rgmii_txclk_m1 */ + <2 RK_PD2 2 &pcfg_pull_none_drv_level_3>, /* rgmii_txd2_m1 */ <2 RK_PD1 2 &pcfg_pull_none_drv_level_3>, /* rgmii_txd3_m1 */ - <2 RK_PA4 2 &pcfg_pull_none_drv_level_3>, - /* rgmii_txen_m1 */ - <2 RK_PC6 2 &pcfg_pull_none_drv_level_3>; + <2 RK_PA4 2 &pcfg_pull_none_drv_level_3>; + }; + /omit-if-no-ref/ + rgmiim1_mclkinout: rgmiim1-mclkinout { + rockchip,pins = + /* rgmii_clk_m1 */ + <2 RK_PB7 2 &pcfg_pull_none>; }; }; sdmmc0 { @@ -263,6 +293,14 @@ /* uart3_tx_m0 */ <3 RK_PC6 4 &pcfg_pull_up>; }; + /omit-if-no-ref/ + uart3m2_xfer: uart3m2-xfer { + rockchip,pins = + /* uart3_rx_m2 */ + <3 RK_PA1 4 &pcfg_pull_up>, + /* uart3_tx_m2 */ + <3 RK_PA0 4 &pcfg_pull_up>; + }; }; uart4 { /omit-if-no-ref/ @@ -273,6 +311,14 @@ /* uart4_tx_m0 */ <3 RK_PA4 4 &pcfg_pull_up>; }; + /omit-if-no-ref/ + uart4m2_xfer: uart4m2-xfer { + rockchip,pins = + /* uart4_rx_m2 */ + <1 RK_PD4 3 &pcfg_pull_up>, + /* uart4_tx_m2 */ + <1 RK_PD5 3 &pcfg_pull_up>; + }; }; uart5 { /omit-if-no-ref/ diff --git a/arch/arm/boot/dts/rockchip/rv1126-sonoff-ihost.dts b/arch/arm/boot/dts/rockchip/rv1126-sonoff-ihost.dts new file mode 100644 index 00000000000000..77386a48d81ef6 --- /dev/null +++ b/arch/arm/boot/dts/rockchip/rv1126-sonoff-ihost.dts @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2020 Rockchip Electronics Co., Ltd. + */ + +/dts-v1/; +#include "rv1126.dtsi" +#include "rv1126-sonoff-ihost.dtsi" + +/ { + model = "Sonoff iHost 4G"; + compatible = "itead,sonoff-ihost", "rockchip,rv1126"; +}; + +&cpu0 { + cpu-supply = <&vdd_arm>; +}; + +&cpu1 { + cpu-supply = <&vdd_arm>; +}; + +&cpu2 { + cpu-supply = <&vdd_arm>; +}; + +&cpu3 { + cpu-supply = <&vdd_arm>; +}; diff --git a/arch/arm/boot/dts/rockchip/rv1126-sonoff-ihost.dtsi b/arch/arm/boot/dts/rockchip/rv1126-sonoff-ihost.dtsi new file mode 100644 index 00000000000000..32b329e87a0cd3 --- /dev/null +++ b/arch/arm/boot/dts/rockchip/rv1126-sonoff-ihost.dtsi @@ -0,0 +1,404 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2020 Rockchip Electronics Co., Ltd. + * Copyright (c) 2022 Edgeble AI Technologies Pvt. Ltd. + */ + +/ { + aliases { + ethernet0 = &gmac; + mmc0 = &emmc; + }; + + chosen { + stdout-path = "serial2:1500000n8"; + }; + + vcc5v0_sys: regulator-vcc5v0-sys { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_sys"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + + sdio_pwrseq: pwrseq-sdio { + compatible = "mmc-pwrseq-simple"; + clocks = <&rk809 1>; + clock-names = "ext_clock"; + pinctrl-names = "default"; + pinctrl-0 = <&wifi_enable_h>; + reset-gpios = <&gpio1 RK_PD0 GPIO_ACTIVE_LOW>; + }; +}; + +&emmc { + bus-width = <8>; + cap-mmc-highspeed; + mmc-hs200-1_8v; + non-removable; + pinctrl-names = "default"; + pinctrl-0 = <&emmc_bus8 &emmc_cmd &emmc_clk &emmc_rstnout>; + rockchip,default-sample-phase = <90>; + vmmc-supply = <&vcc_3v3>; + vqmmc-supply = <&vcc_1v8>; + status = "okay"; +}; + +&i2c0 { + clock-frequency = <400000>; + status = "okay"; + + rk809: pmic@20 { + compatible = "rockchip,rk809"; + reg = <0x20>; + interrupt-parent = <&gpio0>; + interrupts = ; + #clock-cells = <1>; + clock-output-names = "rk808-clkout1", "rk808-clkout2"; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_int_l>; + rockchip,system-power-controller; + wakeup-source; + + vcc1-supply = <&vcc5v0_sys>; + vcc2-supply = <&vcc5v0_sys>; + vcc3-supply = <&vcc5v0_sys>; + vcc4-supply = <&vcc5v0_sys>; + vcc5-supply = <&vcc_buck5>; + vcc6-supply = <&vcc_buck5>; + vcc7-supply = <&vcc5v0_sys>; + vcc8-supply = <&vcc3v3_sys>; + vcc9-supply = <&vcc5v0_sys>; + + regulators { + vdd_npu_vepu: DCDC_REG1 { + regulator-name = "vdd_npu_vepu"; + regulator-always-on; + regulator-boot-on; + regulator-initial-mode = <0x2>; + regulator-min-microvolt = <650000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <6001>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_arm: DCDC_REG2 { + regulator-name = "vdd_arm"; + regulator-always-on; + regulator-boot-on; + regulator-initial-mode = <0x2>; + regulator-min-microvolt = <725000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <6001>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_ddr: DCDC_REG3 { + regulator-name = "vcc_ddr"; + regulator-always-on; + regulator-boot-on; + regulator-initial-mode = <0x2>; + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vcc3v3_sys: DCDC_REG4 { + regulator-name = "vcc3v3_sys"; + regulator-always-on; + regulator-boot-on; + regulator-initial-mode = <0x2>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vcc_buck5: DCDC_REG5 { + regulator-name = "vcc_buck5"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <2200000>; + regulator-max-microvolt = <2200000>; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <2200000>; + }; + }; + + vcc_0v8: LDO_REG1 { + regulator-name = "vcc_0v8"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc1v8_pmu: LDO_REG2 { + regulator-name = "vcc1v8_pmu"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vdd0v8_pmu: LDO_REG3 { + regulator-name = "vcc0v8_pmu"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <800000>; + }; + }; + + vcc_1v8: LDO_REG4 { + regulator-name = "vcc_1v8"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vcc_dovdd: LDO_REG5 { + regulator-name = "vcc_dovdd"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_dvdd: LDO_REG6 { + regulator-name = "vcc_dvdd"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_avdd: LDO_REG7 { + regulator-name = "vcc_avdd"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vccio_sd: LDO_REG8 { + regulator-name = "vccio_sd"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc3v3_sd: LDO_REG9 { + regulator-name = "vcc3v3_sd"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_5v0: SWITCH_REG1 { + regulator-name = "vcc_5v0"; + }; + + vcc_3v3: SWITCH_REG2 { + regulator-name = "vcc_3v3"; + regulator-always-on; + regulator-boot-on; + }; + }; + }; +}; + +&i2c2 { + status = "okay"; + clock-frequency = <400000>; + + pcf8563: rtc@51 { + compatible = "nxp,pcf8563"; + reg = <0x51>; + #clock-cells = <0>; + interrupt-parent = <&gpio0>; + interrupts = ; + clock-output-names = "xin32k"; + }; +}; + +&gmac { + assigned-clocks = <&cru CLK_GMAC_SRC_M1>, <&cru CLK_GMAC_SRC>, + <&cru CLK_GMAC_TX_RX>; + assigned-clock-parents = <&cru CLK_GMAC_RGMII_M1>, <&cru CLK_GMAC_SRC_M1>, + <&cru RMII_MODE_CLK>; + assigned-clock-rates = <0>, <50000000>; + clock_in_out = "output"; + phy-handle = <&phy>; + phy-mode = "rmii"; + phy-supply = <&vcc_3v3>; + pinctrl-names = "default"; + pinctrl-0 = <&rgmiim1_miim &rgmiim1_rxer &rgmiim1_bus2 &rgmiim1_mclkinout>; + status = "okay"; +}; + +&mdio { + phy: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0x0>; + pinctrl-names = "default"; + pinctrl-0 = <ð_phy_rst>; + reset-active-low; + reset-assert-us = <50000>; + reset-deassert-us = <10000>; + reset-gpios = <&gpio2 RK_PA6 GPIO_ACTIVE_LOW>; + }; +}; + +&pinctrl { + ethernet { + eth_phy_rst: eth-phy-rst { + rockchip,pins = <2 RK_PA6 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; + bt { + bt_enable: bt-enable { + rockchip,pins = <1 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + bt_wake_dev: bt-wake-dev { + rockchip,pins = <1 RK_PC7 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + bt_wake_host: bt-wake-host { + rockchip,pins = <1 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + pmic { + pmic_int_l: pmic-int-l { + rockchip,pins = <0 RK_PB1 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + wifi { + wifi_enable_h: wifi-enable-h { + rockchip,pins = <1 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; + +&pmu_io_domains { + pmuio0-supply = <&vcc1v8_pmu>; + pmuio1-supply = <&vcc3v3_sys>; + vccio1-supply = <&vcc_1v8>; + vccio2-supply = <&vccio_sd>; + vccio3-supply = <&vcc_1v8>; + vccio4-supply = <&vcc_dovdd>; + vccio5-supply = <&vcc_1v8>; + vccio6-supply = <&vcc_1v8>; + vccio7-supply = <&vcc_dovdd>; + status = "okay"; +}; + +&saradc { + vref-supply = <&vcc_1v8>; + status = "okay"; +}; + +&sdio { + bus-width = <4>; + cap-sd-highspeed; + cap-sdio-irq; + keep-power-in-suspend; + max-frequency = <100000000>; + mmc-pwrseq = <&sdio_pwrseq>; + non-removable; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc1_clk &sdmmc1_cmd &sdmmc1_bus4>; + rockchip,default-sample-phase = <90>; + sd-uhs-sdr104; + vmmc-supply = <&vcc3v3_sys>; + vqmmc-supply = <&vcc_1v8>; + status = "okay"; +}; + +&sdmmc { + bus-width = <4>; + cap-mmc-highspeed; + cap-sd-highspeed; + card-detect-delay = <200>; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_bus4 &sdmmc0_det>; + rockchip,default-sample-phase = <90>; + sd-uhs-sdr12; + sd-uhs-sdr25; + sd-uhs-sdr104; + vqmmc-supply = <&vccio_sd>; + status = "okay"; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_xfer &uart0_ctsn &uart0_rtsn>; + uart-has-rtscts; + status = "okay"; + + bluetooth { + compatible = "realtek,rtl8723ds-bt"; + device-wake-gpios = <&gpio1 RK_PC7 GPIO_ACTIVE_HIGH>; /* BT_WAKE */ + enable-gpios = <&gpio1 RK_PC6 GPIO_ACTIVE_HIGH>; /* BT_RST */ + host-wake-gpios = <&gpio1 RK_PC5 GPIO_ACTIVE_HIGH>; /* BT_WAKE_HOST */ + max-speed = <2000000>; + pinctrl-names = "default"; + pinctrl-0 = <&bt_enable>, <&bt_wake_dev>, <&bt_wake_host>; + }; +}; + +&uart2 { + status = "okay"; +}; + +&uart3 { + pinctrl-names = "default"; + pinctrl-0 = <&uart3m2_xfer>; + status = "okay"; +}; + +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&uart4m2_xfer>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/rockchip/rv1126.dtsi b/arch/arm/boot/dts/rockchip/rv1126.dtsi index 9ccd1bad622944..bb603cae13dfc7 100644 --- a/arch/arm/boot/dts/rockchip/rv1126.dtsi +++ b/arch/arm/boot/dts/rockchip/rv1126.dtsi @@ -21,6 +21,13 @@ aliases { i2c0 = &i2c0; + i2c2 = &i2c2; + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + serial3 = &uart3; + serial4 = &uart4; + serial5 = &uart5; }; cpus { @@ -231,6 +238,20 @@ status = "disabled"; }; + i2c2: i2c@ff400000 { + compatible = "rockchip,rv1126-i2c", "rockchip,rk3399-i2c"; + reg = <0xff400000 0x1000>; + interrupts = ; + rockchip,grf = <&pmugrf>; + clocks = <&pmucru CLK_I2C2>, <&pmucru PCLK_I2C2>; + clock-names = "i2c", "pclk"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c2_xfer>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + uart1: serial@ff410000 { compatible = "rockchip,rv1126-uart", "snps,dw-apb-uart"; reg = <0xff410000 0x100>; diff --git a/arch/arm/boot/dts/samsung/exynos4.dtsi b/arch/arm/boot/dts/samsung/exynos4.dtsi index f775b9377a38b5..7f981b5c0d64b5 100644 --- a/arch/arm/boot/dts/samsung/exynos4.dtsi +++ b/arch/arm/boot/dts/samsung/exynos4.dtsi @@ -203,16 +203,16 @@ camera: camera@11800000 { compatible = "samsung,fimc"; + ranges = <0x0 0x11800000 0xa0000>; status = "disabled"; #address-cells = <1>; #size-cells = <1>; #clock-cells = <1>; clock-output-names = "cam_a_clkout", "cam_b_clkout"; - ranges; - fimc_0: fimc@11800000 { + fimc_0: fimc@0 { compatible = "samsung,exynos4210-fimc"; - reg = <0x11800000 0x1000>; + reg = <0x0 0x1000>; interrupts = ; clocks = <&clock CLK_FIMC0>, <&clock CLK_SCLK_FIMC0>; @@ -223,9 +223,9 @@ status = "disabled"; }; - fimc_1: fimc@11810000 { + fimc_1: fimc@10000 { compatible = "samsung,exynos4210-fimc"; - reg = <0x11810000 0x1000>; + reg = <0x00010000 0x1000>; interrupts = ; clocks = <&clock CLK_FIMC1>, <&clock CLK_SCLK_FIMC1>; @@ -236,9 +236,9 @@ status = "disabled"; }; - fimc_2: fimc@11820000 { + fimc_2: fimc@20000 { compatible = "samsung,exynos4210-fimc"; - reg = <0x11820000 0x1000>; + reg = <0x00020000 0x1000>; interrupts = ; clocks = <&clock CLK_FIMC2>, <&clock CLK_SCLK_FIMC2>; @@ -249,9 +249,9 @@ status = "disabled"; }; - fimc_3: fimc@11830000 { + fimc_3: fimc@30000 { compatible = "samsung,exynos4210-fimc"; - reg = <0x11830000 0x1000>; + reg = <0x00030000 0x1000>; interrupts = ; clocks = <&clock CLK_FIMC3>, <&clock CLK_SCLK_FIMC3>; @@ -262,9 +262,9 @@ status = "disabled"; }; - csis_0: csis@11880000 { + csis_0: csis@80000 { compatible = "samsung,exynos4210-csis"; - reg = <0x11880000 0x4000>; + reg = <0x00080000 0x4000>; interrupts = ; clocks = <&clock CLK_CSIS0>, <&clock CLK_SCLK_CSIS0>; @@ -278,9 +278,9 @@ #size-cells = <0>; }; - csis_1: csis@11890000 { + csis_1: csis@90000 { compatible = "samsung,exynos4210-csis"; - reg = <0x11890000 0x4000>; + reg = <0x00090000 0x4000>; interrupts = ; clocks = <&clock CLK_CSIS1>, <&clock CLK_SCLK_CSIS1>; diff --git a/arch/arm/boot/dts/samsung/exynos4210-i9100.dts b/arch/arm/boot/dts/samsung/exynos4210-i9100.dts index a9ec1f6c1dea15..0d8495792a7021 100644 --- a/arch/arm/boot/dts/samsung/exynos4210-i9100.dts +++ b/arch/arm/boot/dts/samsung/exynos4210-i9100.dts @@ -184,6 +184,28 @@ }; }; + i2c-gpio-2 { + compatible = "i2c-gpio"; + #address-cells = <1>; + #size-cells = <0>; + + sda-gpios = <&gpk1 2 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + scl-gpios = <&gpk1 0 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + i2c-gpio,delay-us = <2>; + + touchscreen@20 { + compatible = "cypress,aries-touchkey"; + reg = <0x20>; + + interrupt-parent = <&gpl0>; + interrupts = <5 IRQ_TYPE_EDGE_FALLING>; + + vdd-supply = <&vtouchled_reg>; + vcc-supply = <&vtouch_reg>; + linux,keycodes = , ; + }; + }; + spi-3 { compatible = "spi-gpio"; #address-cells = <1>; @@ -380,6 +402,23 @@ vusb_a-supply = <&vusbdac_reg>; }; +&i2c_1 { + status = "okay"; + + samsung,i2c-sda-delay = <100>; + samsung,i2c-slave-addr = <0x10>; + samsung,i2c-max-bus-freq = <100000>; + + lis3dh: accelerometer@19 { + compatible = "st,lis3dh-accel"; + reg = <0x19>; + + mount-matrix = "0", "-1", "0", + "1", "0", "0", + "0", "0", "1"; + }; +}; + &i2c_3 { status = "okay"; @@ -513,7 +552,6 @@ regulator-name = "TOUCH_2.8V"; regulator-min-microvolt = <2800000>; regulator-max-microvolt = <2800000>; - regulator-always-on; }; vpll_reg: LDO10 { @@ -527,6 +565,14 @@ regulator-name = "VT_CAM_1.8V"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; + + /* + * Force-enable this regulator; otherwise the + * kernel hangs very early in the boot process + * for about 12 seconds, without apparent + * reason. + */ + regulator-always-on; }; vcclcd_reg: LDO13 { diff --git a/arch/arm/boot/dts/samsung/exynos4212-tab3.dtsi b/arch/arm/boot/dts/samsung/exynos4212-tab3.dtsi index d7954ff466b491..e5254e32aa8fc3 100644 --- a/arch/arm/boot/dts/samsung/exynos4212-tab3.dtsi +++ b/arch/arm/boot/dts/samsung/exynos4212-tab3.dtsi @@ -434,6 +434,7 @@ }; &fimd { + samsung,invert-vclk; status = "okay"; }; diff --git a/arch/arm/boot/dts/samsung/exynos4x12.dtsi b/arch/arm/boot/dts/samsung/exynos4x12.dtsi index 84c1db221c984b..b4b5e769145b85 100644 --- a/arch/arm/boot/dts/samsung/exynos4x12.dtsi +++ b/arch/arm/boot/dts/samsung/exynos4x12.dtsi @@ -451,14 +451,15 @@ }; &camera { + ranges = <0x0 0x11800000 0xba1000>; clocks = <&clock CLK_SCLK_CAM0>, <&clock CLK_SCLK_CAM1>, <&clock CLK_PIXELASYNCM0>, <&clock CLK_PIXELASYNCM1>; clock-names = "sclk_cam0", "sclk_cam1", "pxl_async0", "pxl_async1"; /* fimc_[0-3] are configured outside, under phandles */ - fimc_lite_0: fimc-lite@12390000 { + fimc_lite_0: fimc-lite@b90000 { compatible = "samsung,exynos4212-fimc-lite"; - reg = <0x12390000 0x1000>; + reg = <0x00b90000 0x1000>; interrupts = ; power-domains = <&pd_isp>; clocks = <&isp_clock CLK_ISP_FIMC_LITE0>; @@ -467,9 +468,9 @@ status = "disabled"; }; - fimc_lite_1: fimc-lite@123a0000 { + fimc_lite_1: fimc-lite@ba0000 { compatible = "samsung,exynos4212-fimc-lite"; - reg = <0x123a0000 0x1000>; + reg = <0x00ba0000 0x1000>; interrupts = ; power-domains = <&pd_isp>; clocks = <&isp_clock CLK_ISP_FIMC_LITE1>; @@ -478,9 +479,9 @@ status = "disabled"; }; - fimc_is: fimc-is@12000000 { + fimc_is: fimc-is@800000 { compatible = "samsung,exynos4212-fimc-is"; - reg = <0x12000000 0x260000>; + reg = <0x00800000 0x260000>; interrupts = , ; power-domains = <&pd_isp>; @@ -516,18 +517,15 @@ iommus = <&sysmmu_fimc_isp>, <&sysmmu_fimc_drc>, <&sysmmu_fimc_fd>, <&sysmmu_fimc_mcuctl>; iommu-names = "isp", "drc", "fd", "mcuctl"; + samsung,pmu-syscon = <&pmu_system_controller>; #address-cells = <1>; #size-cells = <1>; ranges; status = "disabled"; - pmu@10020000 { - reg = <0x10020000 0x3000>; - }; - - i2c1_isp: i2c-isp@12140000 { + i2c1_isp: i2c-isp@940000 { compatible = "samsung,exynos4212-i2c-isp"; - reg = <0x12140000 0x100>; + reg = <0x00940000 0x100>; clocks = <&isp_clock CLK_ISP_I2C1_ISP>; clock-names = "i2c_isp"; #address-cells = <1>; diff --git a/arch/arm/boot/dts/samsung/s5pv210.dtsi b/arch/arm/boot/dts/samsung/s5pv210.dtsi index f7de5b5f2f3837..ed560c9a3aa1ef 100644 --- a/arch/arm/boot/dts/samsung/s5pv210.dtsi +++ b/arch/arm/boot/dts/samsung/s5pv210.dtsi @@ -549,17 +549,17 @@ camera: camera@fa600000 { compatible = "samsung,fimc"; + ranges = <0x0 0xfa600000 0xe01000>; clocks = <&clocks SCLK_CAM0>, <&clocks SCLK_CAM1>; clock-names = "sclk_cam0", "sclk_cam1"; #address-cells = <1>; #size-cells = <1>; #clock-cells = <1>; clock-output-names = "cam_a_clkout", "cam_b_clkout"; - ranges; - csis0: csis@fa600000 { + csis0: csis@0 { compatible = "samsung,s5pv210-csis"; - reg = <0xfa600000 0x4000>; + reg = <0x00000000 0x4000>; interrupt-parent = <&vic2>; interrupts = <29>; clocks = <&clocks CLK_CSIS>, @@ -572,9 +572,9 @@ #size-cells = <0>; }; - fimc0: fimc@fb200000 { + fimc0: fimc@c00000 { compatible = "samsung,s5pv210-fimc"; - reg = <0xfb200000 0x1000>; + reg = <0x00c00000 0x1000>; interrupts = <5>; interrupt-parent = <&vic2>; clocks = <&clocks CLK_FIMC0>, @@ -586,9 +586,9 @@ samsung,cam-if; }; - fimc1: fimc@fb300000 { + fimc1: fimc@d00000 { compatible = "samsung,s5pv210-fimc"; - reg = <0xfb300000 0x1000>; + reg = <0x00d00000 0x1000>; interrupt-parent = <&vic2>; interrupts = <6>; clocks = <&clocks CLK_FIMC1>, @@ -602,9 +602,9 @@ samsung,lcd-wb; }; - fimc2: fimc@fb400000 { + fimc2: fimc@e00000 { compatible = "samsung,s5pv210-fimc"; - reg = <0xfb400000 0x1000>; + reg = <0x00e00000 0x1000>; interrupt-parent = <&vic2>; interrupts = <7>; clocks = <&clocks CLK_FIMC2>, diff --git a/arch/arm/boot/dts/st/ste-dbx5x0.dtsi b/arch/arm/boot/dts/st/ste-dbx5x0.dtsi index d5d88771ef976f..0f87abeddc335a 100644 --- a/arch/arm/boot/dts/st/ste-dbx5x0.dtsi +++ b/arch/arm/boot/dts/st/ste-dbx5x0.dtsi @@ -425,7 +425,7 @@ gpio0: gpio@8012e000 { compatible = "stericsson,db8500-gpio", "st,nomadik-gpio"; - reg = <0x8012e000 0x80>; + reg = <0x8012e000 0x80>; interrupts = ; interrupt-controller; #interrupt-cells = <2>; @@ -440,7 +440,7 @@ gpio1: gpio@8012e080 { compatible = "stericsson,db8500-gpio", "st,nomadik-gpio"; - reg = <0x8012e080 0x80>; + reg = <0x8012e080 0x80>; interrupts = ; interrupt-controller; #interrupt-cells = <2>; @@ -455,7 +455,7 @@ gpio2: gpio@8000e000 { compatible = "stericsson,db8500-gpio", "st,nomadik-gpio"; - reg = <0x8000e000 0x80>; + reg = <0x8000e000 0x80>; interrupts = ; interrupt-controller; #interrupt-cells = <2>; @@ -470,7 +470,7 @@ gpio3: gpio@8000e080 { compatible = "stericsson,db8500-gpio", "st,nomadik-gpio"; - reg = <0x8000e080 0x80>; + reg = <0x8000e080 0x80>; interrupts = ; interrupt-controller; #interrupt-cells = <2>; @@ -485,7 +485,7 @@ gpio4: gpio@8000e100 { compatible = "stericsson,db8500-gpio", "st,nomadik-gpio"; - reg = <0x8000e100 0x80>; + reg = <0x8000e100 0x80>; interrupts = ; interrupt-controller; #interrupt-cells = <2>; @@ -500,7 +500,7 @@ gpio5: gpio@8000e180 { compatible = "stericsson,db8500-gpio", "st,nomadik-gpio"; - reg = <0x8000e180 0x80>; + reg = <0x8000e180 0x80>; interrupts = ; interrupt-controller; #interrupt-cells = <2>; @@ -515,7 +515,7 @@ gpio6: gpio@8011e000 { compatible = "stericsson,db8500-gpio", "st,nomadik-gpio"; - reg = <0x8011e000 0x80>; + reg = <0x8011e000 0x80>; interrupts = ; interrupt-controller; #interrupt-cells = <2>; @@ -530,7 +530,7 @@ gpio7: gpio@8011e080 { compatible = "stericsson,db8500-gpio", "st,nomadik-gpio"; - reg = <0x8011e080 0x80>; + reg = <0x8011e080 0x80>; interrupts = ; interrupt-controller; #interrupt-cells = <2>; @@ -545,7 +545,7 @@ gpio8: gpio@a03fe000 { compatible = "stericsson,db8500-gpio", "st,nomadik-gpio"; - reg = <0xa03fe000 0x80>; + reg = <0xa03fe000 0x80>; interrupts = ; interrupt-controller; #interrupt-cells = <2>; diff --git a/arch/arm/boot/dts/st/ste-href-ab8500.dtsi b/arch/arm/boot/dts/st/ste-href-ab8500.dtsi index e1de9d389a01bf..5eeb44c5e93234 100644 --- a/arch/arm/boot/dts/st/ste-href-ab8500.dtsi +++ b/arch/arm/boot/dts/st/ste-href-ab8500.dtsi @@ -9,6 +9,54 @@ soc { prcmu@80157000 { ab8500 { + phy { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&usb_a_1_default>; + pinctrl-1 = <&usb_a_1_sleep>; + }; + + regulator { + ab8500_ldo_aux1_reg: ab8500_ldo_aux1 { + regulator-name = "V-DISPLAY"; + }; + + ab8500_ldo_aux2_reg: ab8500_ldo_aux2 { + regulator-name = "V-eMMC1"; + }; + + ab8500_ldo_aux3_reg: ab8500_ldo_aux3 { + regulator-name = "V-MMC-SD"; + }; + + ab8500_ldo_intcore_reg: ab8500_ldo_intcore { + regulator-name = "V-INTCORE"; + }; + + ab8500_ldo_tvout_reg: ab8500_ldo_tvout { + regulator-name = "V-TVOUT"; + }; + + ab8500_ldo_audio_reg: ab8500_ldo_audio { + regulator-name = "V-AUD"; + }; + + ab8500_ldo_anamic1_reg: ab8500_ldo_anamic1 { + regulator-name = "V-AMIC1"; + }; + + ab8500_ldo_anamic2_reg: ab8500_ldo_anamic2 { + regulator-name = "V-AMIC2"; + }; + + ab8500_ldo_dmic_reg: ab8500_ldo_dmic { + regulator-name = "V-DMIC"; + }; + + ab8500_ldo_ana_reg: ab8500_ldo_ana { + regulator-name = "V-CSI/DSI"; + }; + }; + gpio { /* Hog a few default settings */ pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/st/ste-href-ab8505.dtsi b/arch/arm/boot/dts/st/ste-href-ab8505.dtsi new file mode 100644 index 00000000000000..268db68ccf87b6 --- /dev/null +++ b/arch/arm/boot/dts/st/ste-href-ab8505.dtsi @@ -0,0 +1,490 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright 2023 Linus Walleij + */ + +#include "ste-ab8505.dtsi" + +/ { + soc { + prcmu@80157000 { + ab8505 { + phy { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&usb_a_1_default>; + pinctrl-1 = <&usb_a_1_sleep>; + }; + + regulator { + ab8500_ldo_aux1_reg: ab8500_ldo_aux1 { + regulator-name = "V-DISPLAY"; + }; + + ab8500_ldo_aux2_reg: ab8500_ldo_aux2 { + regulator-name = "V-eMMC1"; + }; + + ab8500_ldo_aux3_reg: ab8500_ldo_aux3 { + regulator-name = "V-MMC-SD"; + }; + + ab8500_ldo_intcore_reg: ab8500_ldo_intcore { + regulator-name = "V-INTCORE"; + }; + + ab8500_ldo_tvout_reg: ab8500_ldo_tvout { + regulator-name = "V-TVOUT"; + }; + + ab8500_ldo_audio_reg: ab8500_ldo_audio { + regulator-name = "V-AUD"; + }; + + ab8500_ldo_anamic1_reg: ab8500_ldo_anamic1 { + regulator-name = "V-AMIC1"; + }; + + ab8500_ldo_anamic2_reg: ab8500_ldo_anamic2 { + regulator-name = "V-AMIC2"; + }; + + ab8500_ldo_dmic_reg: ab8500_ldo_dmic { + regulator-name = "V-DMIC"; + }; + + ab8500_ldo_ana_reg: ab8500_ldo_ana { + regulator-name = "V-CSI/DSI"; + }; + }; + + gpio { + /* Hog a few default settings */ + pinctrl-names = "default"; + pinctrl-0 = <&gpio2_default_mode>, + <&gpio4_default_mode>, + <&gpio10_default_mode>, + <&gpio11_default_mode>, + <&gpio12_default_mode>, + <&gpio13_default_mode>, + <&gpio16_default_mode>, + <&gpio24_default_mode>, + <&gpio25_default_mode>, + <&gpio36_default_mode>, + <&gpio37_default_mode>, + <&gpio38_default_mode>, + <&gpio39_default_mode>, + <&gpio42_default_mode>, + <&gpio26_default_mode>, + <&gpio35_default_mode>, + <&ycbcr_default_mode>, + <&pwm_default_mode>, + <&adi1_default_mode>, + <&usbuicc_default_mode>, + <&dmic_default_mode>, + <&extcpena_default_mode>, + <&modsclsda_default_mode>; + + /* + * Pins 2, 4, 10, 11, 12, 13, 16, 24, 25, 36, 37, 38, 39 and 42 + * are muxed in as GPIO, and configured as INPUT PULL DOWN + */ + gpio2 { + gpio2_default_mode: gpio2_default { + default_mux { + function = "gpio"; + groups = "gpio2_a_1"; + }; + default_cfg { + pins = "GPIO2_T9"; + input-enable; + bias-pull-down; + }; + }; + }; + gpio4 { + gpio4_default_mode: gpio4_default { + default_mux { + function = "gpio"; + groups = "gpio4_a_1"; + }; + default_cfg { + pins = "GPIO4_W2"; + input-enable; + bias-pull-down; + }; + }; + }; + gpio10 { + gpio10_default_mode: gpio10_default { + default_mux { + function = "gpio"; + groups = "gpio10_d_1"; + }; + default_cfg { + pins = "GPIO10_U17"; + input-enable; + bias-pull-down; + }; + }; + }; + gpio11 { + gpio11_default_mode: gpio11_default { + default_mux { + function = "gpio"; + groups = "gpio11_d_1"; + }; + default_cfg { + pins = "GPIO11_AA18"; + input-enable; + bias-pull-down; + }; + }; + }; + gpio12 { + gpio12_default_mode: gpio12_default { + default_mux { + function = "gpio"; + groups = "gpio12_d_1"; + }; + default_cfg { + pins = "GPIO12_U16"; + input-enable; + bias-pull-down; + }; + }; + }; + gpio13 { + gpio13_default_mode: gpio13_default { + default_mux { + function = "gpio"; + groups = "gpio13_d_1"; + }; + default_cfg { + pins = "GPIO13_W17"; + input-enable; + bias-pull-down; + }; + }; + }; + gpio16 { + gpio16_default_mode: gpio16_default { + default_mux { + function = "gpio"; + groups = "gpio16_a_1"; + }; + default_cfg { + pins = "GPIO16_F15"; + input-enable; + bias-pull-down; + }; + }; + }; + gpio24 { + gpio24_default_mode: gpio24_default { + default_mux { + function = "gpio"; + groups = "gpio24_a_1"; + }; + default_cfg { + pins = "GPIO24_T14"; + input-enable; + bias-pull-down; + }; + }; + }; + gpio25 { + gpio25_default_mode: gpio25_default { + default_mux { + function = "gpio"; + groups = "gpio25_a_1"; + }; + default_cfg { + pins = "GPIO25_R16"; + input-enable; + bias-pull-down; + }; + }; + }; + gpio36 { + gpio36_default_mode: gpio36_default { + default_mux { + function = "gpio"; + groups = "gpio36_a_1"; + }; + default_cfg { + pins = "GPIO36_A17"; + input-enable; + bias-pull-down; + }; + }; + }; + gpio37 { + gpio37_default_mode: gpio37_default { + default_mux { + function = "gpio"; + groups = "gpio37_a_1"; + }; + default_cfg { + pins = "GPIO37_E15"; + input-enable; + bias-pull-down; + }; + }; + }; + gpio38 { + gpio38_default_mode: gpio38_default { + default_mux { + function = "gpio"; + groups = "gpio38_a_1"; + }; + default_cfg { + pins = "GPIO38_C17"; + input-enable; + bias-pull-down; + }; + }; + }; + gpio39 { + gpio39_default_mode: gpio39_default { + default_mux { + function = "gpio"; + groups = "gpio39_a_1"; + }; + default_cfg { + pins = "GPIO39_E16"; + input-enable; + bias-pull-down; + }; + }; + }; + gpio42 { + gpio42_default_mode: gpio42_default { + default_mux { + function = "gpio"; + groups = "gpio42_a_1"; + }; + default_cfg { + pins = "GPIO42_U2"; + input-enable; + bias-pull-down; + }; + }; + }; + /* + * Pins 26 and 35 muxed in as GPIO, and configured as OUTPUT LOW + */ + gpio26 { + gpio26_default_mode: gpio26_default { + default_mux { + function = "gpio"; + groups = "gpio26_d_1"; + }; + default_cfg { + pins = "GPIO26_M16"; + output-low; + }; + }; + }; + gpio35 { + gpio35_default_mode: gpio35_default { + default_mux { + function = "gpio"; + groups = "gpio35_d_1"; + }; + default_cfg { + pins = "GPIO35_W15"; + output-low; + }; + }; + }; + /* + * This sets up the YCBCR connector pins, i.e. analog video out. + * Set as input with no bias. + */ + ycbcr { + ycbcr_default_mode: ycbcr_default { + default_mux { + function = "ycbcr"; + groups = "ycbcr0123_d_1"; + }; + default_cfg { + pins = "GPIO6_Y18", + "GPIO7_AA20", + "GPIO8_W18", + "GPIO9_AA19"; + input-enable; + bias-disable; + }; + }; + }; + /* This sets up the PWM pins 14 and 15 */ + pwm { + pwm_default_mode: pwm_default { + default_mux { + function = "pwmout"; + groups = "pwmout1_d_1", "pwmout2_d_1"; + }; + default_cfg { + pins = "GPIO14_F14", + "GPIO15_B17"; + input-enable; + bias-pull-down; + }; + }; + }; + /* This sets up audio interface 1 */ + adi1 { + adi1_default_mode: adi1_default { + default_mux { + function = "adi1"; + groups = "adi1_d_1"; + }; + default_cfg { + pins = "GPIO17_P5", + "GPIO18_R5", + "GPIO19_U5", + "GPIO20_T5"; + input-enable; + bias-pull-down; + }; + }; + }; + /* This sets up the USB UICC pins */ + usbuicc { + usbuicc_default_mode: usbuicc_default { + default_mux { + function = "usbuicc"; + groups = "usbuicc_d_1"; + }; + default_cfg { + pins = "GPIO21_H19", + "GPIO22_G20", + "GPIO23_G19"; + input-enable; + bias-pull-down; + }; + }; + }; + /* This sets up the microphone pins */ + dmic { + dmic_default_mode: dmic_default { + default_mux { + function = "dmic"; + groups = "dmic12_d_1", + "dmic34_d_1", + "dmic56_d_1"; + }; + default_cfg { + pins = "GPIO27_J6", + "GPIO28_K6", + "GPIO29_G6", + "GPIO30_H6", + "GPIO31_F5", + "GPIO32_G5"; + input-enable; + bias-pull-down; + }; + }; + }; + extcpena { + extcpena_default_mode: extcpena_default { + default_mux { + function = "extcpena"; + groups = "extcpena_d_1"; + }; + default_cfg { + pins = "GPIO34_R17"; + input-enable; + bias-pull-down; + }; + }; + }; + /* Modem I2C setup (SCL and SDA pins) */ + modsclsda { + modsclsda_default_mode: modsclsda_default { + default_mux { + function = "modsclsda"; + groups = "modsclsda_d_1"; + }; + default_cfg { + pins = "GPIO40_T19", + "GPIO41_U19"; + input-enable; + bias-pull-down; + }; + }; + }; + /* + * Clock output pins associated with regulators. + */ + sysclkreq2 { + sysclkreq2_default_mode: sysclkreq2_default { + default_mux { + function = "sysclkreq"; + groups = "sysclkreq2_d_1"; + }; + default_cfg { + pins = "GPIO1_T10"; + input-enable; + bias-disable; + }; + }; + sysclkreq2_sleep_mode: sysclkreq2_sleep { + default_mux { + function = "gpio"; + groups = "gpio1_a_1"; + }; + default_cfg { + pins = "GPIO1_T10"; + input-enable; + bias-pull-down; + }; + }; + }; + sysclkreq4 { + sysclkreq4_default_mode: sysclkreq4_default { + default_mux { + function = "sysclkreq"; + groups = "sysclkreq4_d_1"; + }; + default_cfg { + pins = "GPIO3_U9"; + input-enable; + bias-disable; + }; + }; + sysclkreq4_sleep_mode: sysclkreq4_sleep { + default_mux { + function = "gpio"; + groups = "gpio3_a_1"; + }; + default_cfg { + pins = "GPIO3_U9"; + input-enable; + bias-pull-down; + }; + }; + }; + }; + /* + * Charging is not working on the HREF unless an actual battery is + * mounted, most HREFs have a DC cable in to the "battery power" + * which means this will only be cofusing. So do not enable charging + * of the HREFs. + */ + ab8500_fg { + status = "disabled"; + }; + ab8500_btemp { + status = "disabled"; + }; + ab8500_charger { + status = "disabled"; + }; + ab8500_chargalg { + status = "disabled"; + }; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/st/ste-href.dtsi b/arch/arm/boot/dts/st/ste-href.dtsi index 13b11dbeba1c1f..fbf0309e108f05 100644 --- a/arch/arm/boot/dts/st/ste-href.dtsi +++ b/arch/arm/boot/dts/st/ste-href.dtsi @@ -242,61 +242,6 @@ status = "okay"; }; - prcmu@80157000 { - ab8500 { - gpio { - }; - - phy { - pinctrl-names = "default", "sleep"; - pinctrl-0 = <&usb_a_1_default>; - pinctrl-1 = <&usb_a_1_sleep>; - }; - - regulator { - ab8500_ldo_aux1_reg: ab8500_ldo_aux1 { - regulator-name = "V-DISPLAY"; - }; - - ab8500_ldo_aux2_reg: ab8500_ldo_aux2 { - regulator-name = "V-eMMC1"; - }; - - ab8500_ldo_aux3_reg: ab8500_ldo_aux3 { - regulator-name = "V-MMC-SD"; - }; - - ab8500_ldo_intcore_reg: ab8500_ldo_intcore { - regulator-name = "V-INTCORE"; - }; - - ab8500_ldo_tvout_reg: ab8500_ldo_tvout { - regulator-name = "V-TVOUT"; - }; - - ab8500_ldo_audio_reg: ab8500_ldo_audio { - regulator-name = "V-AUD"; - }; - - ab8500_ldo_anamic1_reg: ab8500_ldo_anamic1 { - regulator-name = "V-AMIC1"; - }; - - ab8500_ldo_anamic2_reg: ab8500_ldo_anamic2 { - regulator-name = "V-AMIC2"; - }; - - ab8500_ldo_dmic_reg: ab8500_ldo_dmic { - regulator-name = "V-DMIC"; - }; - - ab8500_ldo_ana_reg: ab8500_ldo_ana { - regulator-name = "V-CSI/DSI"; - }; - }; - }; - }; - pinctrl { sdi0 { sdi0_default_mode: sdi0_default { diff --git a/arch/arm/boot/dts/st/ste-href520-tvk.dts b/arch/arm/boot/dts/st/ste-href520-tvk.dts index 7f661f8f13addb..5677df43c3acb1 100644 --- a/arch/arm/boot/dts/st/ste-href520-tvk.dts +++ b/arch/arm/boot/dts/st/ste-href520-tvk.dts @@ -5,6 +5,7 @@ /dts-v1/; #include "ste-db8520.dtsi" +#include "ste-href-ab8505.dtsi" #include "ste-hrefv60plus.dtsi" #include "ste-href-tvk1281618-r3.dtsi" diff --git a/arch/arm/boot/dts/st/ste-hrefprev60-stuib.dts b/arch/arm/boot/dts/st/ste-hrefprev60-stuib.dts index a29e345a43d33e..b142bb2d38d8bb 100644 --- a/arch/arm/boot/dts/st/ste-hrefprev60-stuib.dts +++ b/arch/arm/boot/dts/st/ste-hrefprev60-stuib.dts @@ -5,6 +5,7 @@ /dts-v1/; #include "ste-db8500.dtsi" +#include "ste-href-ab8500.dtsi" #include "ste-hrefprev60.dtsi" #include "ste-href-stuib.dtsi" diff --git a/arch/arm/boot/dts/st/ste-hrefprev60-tvk.dts b/arch/arm/boot/dts/st/ste-hrefprev60-tvk.dts index 1968bd143114dc..5da1ff41b00e5d 100644 --- a/arch/arm/boot/dts/st/ste-hrefprev60-tvk.dts +++ b/arch/arm/boot/dts/st/ste-hrefprev60-tvk.dts @@ -5,6 +5,7 @@ /dts-v1/; #include "ste-db8500.dtsi" +#include "ste-href-ab8500.dtsi" #include "ste-hrefprev60.dtsi" #include "ste-href-tvk1281618-r2.dtsi" diff --git a/arch/arm/boot/dts/st/ste-hrefprev60.dtsi b/arch/arm/boot/dts/st/ste-hrefprev60.dtsi index 9859ee91a15ece..c87fd27b443456 100644 --- a/arch/arm/boot/dts/st/ste-hrefprev60.dtsi +++ b/arch/arm/boot/dts/st/ste-hrefprev60.dtsi @@ -62,7 +62,7 @@ // External Micro SD slot mmc@80126000 { - cd-gpios = <&tc3589x_gpio 3 GPIO_ACTIVE_HIGH>; + cd-gpios = <&tc3589x_gpio 3 GPIO_ACTIVE_HIGH>; }; pinctrl { diff --git a/arch/arm/boot/dts/st/ste-hrefv60plus-stuib.dts b/arch/arm/boot/dts/st/ste-hrefv60plus-stuib.dts index 7a5b6aa1db5bf0..c4abe24a7cd0dd 100644 --- a/arch/arm/boot/dts/st/ste-hrefv60plus-stuib.dts +++ b/arch/arm/boot/dts/st/ste-hrefv60plus-stuib.dts @@ -7,6 +7,7 @@ /dts-v1/; #include "ste-db8500.dtsi" +#include "ste-href-ab8500.dtsi" #include "ste-hrefv60plus.dtsi" #include "ste-href-stuib.dtsi" diff --git a/arch/arm/boot/dts/st/ste-hrefv60plus-tvk.dts b/arch/arm/boot/dts/st/ste-hrefv60plus-tvk.dts index d5af3f375161b6..f55e8de2b51614 100644 --- a/arch/arm/boot/dts/st/ste-hrefv60plus-tvk.dts +++ b/arch/arm/boot/dts/st/ste-hrefv60plus-tvk.dts @@ -7,6 +7,7 @@ /dts-v1/; #include "ste-db8500.dtsi" +#include "ste-href-ab8500.dtsi" #include "ste-hrefv60plus.dtsi" #include "ste-href-tvk1281618-r2.dtsi" diff --git a/arch/arm/boot/dts/st/ste-hrefv60plus.dtsi b/arch/arm/boot/dts/st/ste-hrefv60plus.dtsi index e66fa59c2de64e..b23966c16a32b9 100644 --- a/arch/arm/boot/dts/st/ste-hrefv60plus.dtsi +++ b/arch/arm/boot/dts/st/ste-hrefv60plus.dtsi @@ -3,7 +3,6 @@ * Copyright 2012 ST-Ericsson AB */ -#include "ste-href-ab8500.dtsi" #include "ste-href.dtsi" / { @@ -191,7 +190,7 @@ // External Micro SD slot mmc@80126000 { - cd-gpios = <&gpio2 31 GPIO_ACTIVE_HIGH>; // 95 + cd-gpios = <&gpio2 31 GPIO_ACTIVE_HIGH>; // 95 }; pinctrl { diff --git a/arch/arm/boot/dts/st/ste-nomadik-stn8815.dtsi b/arch/arm/boot/dts/st/ste-nomadik-stn8815.dtsi index 6816eef39d4504..4d37c5fb553c8a 100644 --- a/arch/arm/boot/dts/st/ste-nomadik-stn8815.dtsi +++ b/arch/arm/boot/dts/st/ste-nomadik-stn8815.dtsi @@ -52,7 +52,7 @@ gpio0: gpio@101e4000 { compatible = "st,nomadik-gpio"; - reg = <0x101e4000 0x80>; + reg = <0x101e4000 0x80>; interrupt-parent = <&vica>; interrupts = <6>; interrupt-controller; @@ -66,7 +66,7 @@ gpio1: gpio@101e5000 { compatible = "st,nomadik-gpio"; - reg = <0x101e5000 0x80>; + reg = <0x101e5000 0x80>; interrupt-parent = <&vica>; interrupts = <7>; interrupt-controller; @@ -80,7 +80,7 @@ gpio2: gpio@101e6000 { compatible = "st,nomadik-gpio"; - reg = <0x101e6000 0x80>; + reg = <0x101e6000 0x80>; interrupt-parent = <&vica>; interrupts = <8>; interrupt-controller; @@ -94,7 +94,7 @@ gpio3: gpio@101e7000 { compatible = "st,nomadik-gpio"; - reg = <0x101e7000 0x80>; + reg = <0x101e7000 0x80>; ngpio = <28>; interrupt-parent = <&vica>; interrupts = <9>; diff --git a/arch/arm/boot/dts/st/ste-snowball.dts b/arch/arm/boot/dts/st/ste-snowball.dts index 27c2ec51e7325b..1322abfc7acfba 100644 --- a/arch/arm/boot/dts/st/ste-snowball.dts +++ b/arch/arm/boot/dts/st/ste-snowball.dts @@ -266,7 +266,7 @@ pinctrl-1 = <&mc0_a_1_sleep>; /* GPIO218 MMC_CD */ - cd-gpios = <&gpio6 26 GPIO_ACTIVE_LOW>; + cd-gpios = <&gpio6 26 GPIO_ACTIVE_LOW>; status = "okay"; }; diff --git a/arch/arm/boot/dts/st/ste-ux500-samsung-codina-tmo.dts b/arch/arm/boot/dts/st/ste-ux500-samsung-codina-tmo.dts index 463942ae755ecb..c623cc35c5ea23 100644 --- a/arch/arm/boot/dts/st/ste-ux500-samsung-codina-tmo.dts +++ b/arch/arm/boot/dts/st/ste-ux500-samsung-codina-tmo.dts @@ -310,7 +310,7 @@ pinctrl-names = "default", "sleep"; pinctrl-0 = <&mc0_a_2_default>; pinctrl-1 = <&mc0_a_2_sleep>; - cd-gpios = <&gpio6 25 GPIO_ACTIVE_LOW>; // GPIO217 + cd-gpios = <&gpio6 25 GPIO_ACTIVE_LOW>; // GPIO217 status = "okay"; }; diff --git a/arch/arm/boot/dts/st/ste-ux500-samsung-codina.dts b/arch/arm/boot/dts/st/ste-ux500-samsung-codina.dts index c1ae0e23fe4596..2355ca6e9ad6c6 100644 --- a/arch/arm/boot/dts/st/ste-ux500-samsung-codina.dts +++ b/arch/arm/boot/dts/st/ste-ux500-samsung-codina.dts @@ -402,7 +402,7 @@ pinctrl-names = "default", "sleep"; pinctrl-0 = <&mc0_a_2_default>; pinctrl-1 = <&mc0_a_2_sleep>; - cd-gpios = <&gpio6 25 GPIO_ACTIVE_LOW>; // GPIO217 + cd-gpios = <&gpio6 25 GPIO_ACTIVE_LOW>; // GPIO217 status = "okay"; }; diff --git a/arch/arm/boot/dts/st/ste-ux500-samsung-gavini.dts b/arch/arm/boot/dts/st/ste-ux500-samsung-gavini.dts index b21e40da3dfdb4..ad9a20ccaaebec 100644 --- a/arch/arm/boot/dts/st/ste-ux500-samsung-gavini.dts +++ b/arch/arm/boot/dts/st/ste-ux500-samsung-gavini.dts @@ -362,7 +362,7 @@ pinctrl-0 = <&mc0_a_2_default>; pinctrl-1 = <&mc0_a_2_sleep>; /* "flash detect" actually card detect */ - cd-gpios = <&gpio6 25 GPIO_ACTIVE_LOW>; + cd-gpios = <&gpio6 25 GPIO_ACTIVE_LOW>; status = "okay"; }; diff --git a/arch/arm/boot/dts/st/ste-ux500-samsung-janice.dts b/arch/arm/boot/dts/st/ste-ux500-samsung-janice.dts index 6e586e875565a4..229f7c32103c5c 100644 --- a/arch/arm/boot/dts/st/ste-ux500-samsung-janice.dts +++ b/arch/arm/boot/dts/st/ste-ux500-samsung-janice.dts @@ -412,7 +412,7 @@ pinctrl-names = "default", "sleep"; pinctrl-0 = <&mc0_a_2_default>; pinctrl-1 = <&mc0_a_2_sleep>; - cd-gpios = <&gpio6 25 GPIO_ACTIVE_LOW>; // GPIO217 + cd-gpios = <&gpio6 25 GPIO_ACTIVE_LOW>; // GPIO217 status = "okay"; }; diff --git a/arch/arm/boot/dts/st/ste-ux500-samsung-kyle.dts b/arch/arm/boot/dts/st/ste-ux500-samsung-kyle.dts index ba4421080b2a55..cdb147dcc1dbc1 100644 --- a/arch/arm/boot/dts/st/ste-ux500-samsung-kyle.dts +++ b/arch/arm/boot/dts/st/ste-ux500-samsung-kyle.dts @@ -238,7 +238,7 @@ pinctrl-names = "default", "sleep"; pinctrl-0 = <&mc0_a_1_default>; pinctrl-1 = <&mc0_a_1_sleep>; - cd-gpios = <&gpio6 25 GPIO_ACTIVE_LOW>; // GPIO217 + cd-gpios = <&gpio6 25 GPIO_ACTIVE_LOW>; // GPIO217 status = "okay"; }; diff --git a/arch/arm/boot/dts/st/stm32f469-disco.dts b/arch/arm/boot/dts/st/stm32f469-disco.dts index cbbd521bf01084..8a4f8ddd083d40 100644 --- a/arch/arm/boot/dts/st/stm32f469-disco.dts +++ b/arch/arm/boot/dts/st/stm32f469-disco.dts @@ -69,16 +69,9 @@ serial0 = &usart3; }; - mmc_vcard: mmc_vcard { + vcc_3v3: vcc-3v3 { compatible = "regulator-fixed"; - regulator-name = "mmc_vcard"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - }; - - vdd_dsi: vdd-dsi { - compatible = "regulator-fixed"; - regulator-name = "vdd_dsi"; + regulator-name = "vcc_3v3"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; }; @@ -164,7 +157,7 @@ compatible = "orisetech,otm8009a"; reg = <0>; /* dsi virtual channel (0..3) */ reset-gpios = <&gpioh 7 GPIO_ACTIVE_LOW>; - power-supply = <&vdd_dsi>; + power-supply = <&vcc_3v3>; status = "okay"; port { @@ -219,7 +212,7 @@ &sdio { status = "okay"; - vmmc-supply = <&mmc_vcard>; + vmmc-supply = <&vcc_3v3>; cd-gpios = <&gpiog 2 GPIO_ACTIVE_LOW>; broken-cd; pinctrl-names = "default", "opendrain"; diff --git a/arch/arm/boot/dts/st/stm32f746.dtsi b/arch/arm/boot/dts/st/stm32f746.dtsi index 53a8e2dec9a4a1..65c72b6fcc8311 100644 --- a/arch/arm/boot/dts/st/stm32f746.dtsi +++ b/arch/arm/boot/dts/st/stm32f746.dtsi @@ -274,6 +274,26 @@ clocks = <&rcc 0 STM32F7_APB1_CLOCK(CAN3)>; }; + spi2: spi@40003800 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "st,stm32f7-spi"; + reg = <0x40003800 0x400>; + interrupts = <36>; + clocks = <&rcc 0 STM32F7_APB1_CLOCK(SPI2)>; + status = "disabled"; + }; + + spi3: spi@40003c00 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "st,stm32f7-spi"; + reg = <0x40003c00 0x400>; + interrupts = <51>; + clocks = <&rcc 0 STM32F7_APB1_CLOCK(SPI3)>; + status = "disabled"; + }; + usart2: serial@40004400 { compatible = "st,stm32f7-uart"; reg = <0x40004400 0x400>; @@ -491,9 +511,30 @@ status = "disabled"; }; + spi1: spi@40013000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "st,stm32f7-spi"; + reg = <0x40013000 0x400>; + interrupts = <35>; + clocks = <&rcc 0 STM32F7_APB2_CLOCK(SPI1)>; + status = "disabled"; + }; + + spi4: spi@40013400 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "st,stm32f7-spi"; + reg = <0x40013400 0x400>; + interrupts = <84>; + clocks = <&rcc 0 STM32F7_APB2_CLOCK(SPI4)>; + status = "disabled"; + }; + syscfg: syscon@40013800 { compatible = "st,stm32-syscfg", "syscon"; reg = <0x40013800 0x400>; + clocks = <&rcc 0 STM32F7_APB2_CLOCK(SYSCFG)>; }; exti: interrupt-controller@40013c00 { @@ -554,6 +595,26 @@ }; }; + spi5: spi@40015000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "st,stm32f7-spi"; + reg = <0x40015000 0x400>; + interrupts = <85>; + clocks = <&rcc 0 STM32F7_APB2_CLOCK(SPI5)>; + status = "disabled"; + }; + + spi6: spi@40015400 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "st,stm32f7-spi"; + reg = <0x40015400 0x400>; + interrupts = <86>; + clocks = <&rcc 0 STM32F7_APB2_CLOCK(SPI6)>; + status = "disabled"; + }; + ltdc: display-controller@40016800 { compatible = "st,stm32-ltdc"; reg = <0x40016800 0x200>; diff --git a/arch/arm/boot/dts/st/stm32mp135.dtsi b/arch/arm/boot/dts/st/stm32mp135.dtsi index abf2acd37b4ea0..68d32f9f5314a6 100644 --- a/arch/arm/boot/dts/st/stm32mp135.dtsi +++ b/arch/arm/boot/dts/st/stm32mp135.dtsi @@ -8,5 +8,16 @@ / { soc { + dcmipp: dcmipp@5a000000 { + compatible = "st,stm32mp13-dcmipp"; + reg = <0x5a000000 0x400>; + interrupts = ; + resets = <&rcc DCMIPP_R>; + clocks = <&rcc DCMIPP_K>; + status = "disabled"; + + port { + }; + }; }; }; diff --git a/arch/arm/boot/dts/st/stm32mp151.dtsi b/arch/arm/boot/dts/st/stm32mp151.dtsi index 61508917521c36..fa4cbd312e5a11 100644 --- a/arch/arm/boot/dts/st/stm32mp151.dtsi +++ b/arch/arm/boot/dts/st/stm32mp151.dtsi @@ -1521,6 +1521,8 @@ clocks = <&usbphyc>, <&rcc USBH>; resets = <&rcc USBH_R>; interrupts = ; + phys = <&usbphyc_port0>; + phy-names = "usb"; status = "disabled"; }; @@ -1531,6 +1533,8 @@ resets = <&rcc USBH_R>; interrupts = ; companion = <&usbh_ohci>; + phys = <&usbphyc_port0>; + phy-names = "usb"; status = "disabled"; }; diff --git a/arch/arm/boot/dts/st/stm32mp151a-prtt1l.dtsi b/arch/arm/boot/dts/st/stm32mp151a-prtt1l.dtsi index dd23de85100c48..3938d357e198f4 100644 --- a/arch/arm/boot/dts/st/stm32mp151a-prtt1l.dtsi +++ b/arch/arm/boot/dts/st/stm32mp151a-prtt1l.dtsi @@ -206,8 +206,6 @@ }; &usbh_ehci { - phys = <&usbphyc_port0>; - phy-names = "usb"; status = "okay"; }; diff --git a/arch/arm/boot/dts/st/stm32mp157a-dk1-scmi.dts b/arch/arm/boot/dts/st/stm32mp157a-dk1-scmi.dts index afcd6285890cc0..ce5937270aa1df 100644 --- a/arch/arm/boot/dts/st/stm32mp157a-dk1-scmi.dts +++ b/arch/arm/boot/dts/st/stm32mp157a-dk1-scmi.dts @@ -11,7 +11,7 @@ / { model = "STMicroelectronics STM32MP157A-DK1 SCMI Discovery Board"; - compatible = "st,stm32mp157a-dk1-scmi", "st,stm32mp157a-dk1", "st,stm32mp157"; + compatible = "st,stm32mp157a-dk1-scmi", "st,stm32mp157"; reserved-memory { optee@de000000 { @@ -59,7 +59,7 @@ /delete-property/ st,syscfg-holdboot; resets = <&scmi_reset RST_SCMI_MCU>, <&scmi_reset RST_SCMI_MCU_HOLD_BOOT>; - reset-names = "mcu_rst", "hold_boot"; + reset-names = "mcu_rst", "hold_boot"; }; &rcc { diff --git a/arch/arm/boot/dts/st/stm32mp157a-stinger96.dtsi b/arch/arm/boot/dts/st/stm32mp157a-stinger96.dtsi index 5f85598cc7c6bc..5c1cc48e5199f0 100644 --- a/arch/arm/boot/dts/st/stm32mp157a-stinger96.dtsi +++ b/arch/arm/boot/dts/st/stm32mp157a-stinger96.dtsi @@ -313,8 +313,6 @@ }; &usbh_ehci { - phys = <&usbphyc_port0>; - phy-names = "usb"; status = "okay"; }; diff --git a/arch/arm/boot/dts/st/stm32mp157c-dk2-scmi.dts b/arch/arm/boot/dts/st/stm32mp157c-dk2-scmi.dts index 39358d90200031..c20a73841c1f67 100644 --- a/arch/arm/boot/dts/st/stm32mp157c-dk2-scmi.dts +++ b/arch/arm/boot/dts/st/stm32mp157c-dk2-scmi.dts @@ -11,7 +11,7 @@ / { model = "STMicroelectronics STM32MP157C-DK2 SCMI Discovery Board"; - compatible = "st,stm32mp157c-dk2-scmi", "st,stm32mp157c-dk2", "st,stm32mp157"; + compatible = "st,stm32mp157c-dk2-scmi", "st,stm32mp157"; reserved-memory { optee@de000000 { @@ -65,7 +65,7 @@ /delete-property/ st,syscfg-holdboot; resets = <&scmi_reset RST_SCMI_MCU>, <&scmi_reset RST_SCMI_MCU_HOLD_BOOT>; - reset-names = "mcu_rst", "hold_boot"; + reset-names = "mcu_rst", "hold_boot"; }; &rcc { diff --git a/arch/arm/boot/dts/st/stm32mp157c-ed1-scmi.dts b/arch/arm/boot/dts/st/stm32mp157c-ed1-scmi.dts index 07ea765a4553a5..5e2eaf57ce22f1 100644 --- a/arch/arm/boot/dts/st/stm32mp157c-ed1-scmi.dts +++ b/arch/arm/boot/dts/st/stm32mp157c-ed1-scmi.dts @@ -11,7 +11,7 @@ / { model = "STMicroelectronics STM32MP157C-ED1 SCMI eval daughter"; - compatible = "st,stm32mp157c-ed1-scmi", "st,stm32mp157c-ed1", "st,stm32mp157"; + compatible = "st,stm32mp157c-ed1-scmi", "st,stm32mp157"; reserved-memory { optee@fe000000 { @@ -64,7 +64,7 @@ /delete-property/ st,syscfg-holdboot; resets = <&scmi_reset RST_SCMI_MCU>, <&scmi_reset RST_SCMI_MCU_HOLD_BOOT>; - reset-names = "mcu_rst", "hold_boot"; + reset-names = "mcu_rst", "hold_boot"; }; &rcc { diff --git a/arch/arm/boot/dts/st/stm32mp157c-emstamp-argon.dtsi b/arch/arm/boot/dts/st/stm32mp157c-emstamp-argon.dtsi index f928cfb80b87cf..4792004cab0cc7 100644 --- a/arch/arm/boot/dts/st/stm32mp157c-emstamp-argon.dtsi +++ b/arch/arm/boot/dts/st/stm32mp157c-emstamp-argon.dtsi @@ -500,14 +500,10 @@ }; &usbh_ehci { - phys = <&usbphyc_port0>; - phy-names = "usb"; status = "okay"; }; &usbh_ohci { - phys = <&usbphyc_port0>; - phy-names = "usb"; status = "okay"; }; diff --git a/arch/arm/boot/dts/st/stm32mp157c-ev1-scmi.dts b/arch/arm/boot/dts/st/stm32mp157c-ev1-scmi.dts index 813086ec248959..3226fb945a8ec7 100644 --- a/arch/arm/boot/dts/st/stm32mp157c-ev1-scmi.dts +++ b/arch/arm/boot/dts/st/stm32mp157c-ev1-scmi.dts @@ -11,8 +11,7 @@ / { model = "STMicroelectronics STM32MP157C-EV1 SCMI eval daughter on eval mother"; - compatible = "st,stm32mp157c-ev1-scmi", "st,stm32mp157c-ev1", "st,stm32mp157c-ed1", - "st,stm32mp157"; + compatible = "st,stm32mp157c-ev1-scmi", "st,stm32mp157c-ed1", "st,stm32mp157"; reserved-memory { optee@fe000000 { @@ -70,7 +69,7 @@ /delete-property/ st,syscfg-holdboot; resets = <&scmi_reset RST_SCMI_MCU>, <&scmi_reset RST_SCMI_MCU_HOLD_BOOT>; - reset-names = "mcu_rst", "hold_boot"; + reset-names = "mcu_rst", "hold_boot"; }; &rcc { diff --git a/arch/arm/boot/dts/st/stm32mp157c-ev1.dts b/arch/arm/boot/dts/st/stm32mp157c-ev1.dts index cd9c3ff5378bd6..9eb9a1bf4f2c14 100644 --- a/arch/arm/boot/dts/st/stm32mp157c-ev1.dts +++ b/arch/arm/boot/dts/st/stm32mp157c-ev1.dts @@ -362,7 +362,6 @@ }; &usbh_ehci { - phys = <&usbphyc_port0>; status = "okay"; #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm/boot/dts/st/stm32mp157c-osd32mp1-red.dts b/arch/arm/boot/dts/st/stm32mp157c-osd32mp1-red.dts index bd67a1db912208..527c33be66cc00 100644 --- a/arch/arm/boot/dts/st/stm32mp157c-osd32mp1-red.dts +++ b/arch/arm/boot/dts/st/stm32mp157c-osd32mp1-red.dts @@ -197,14 +197,10 @@ }; &usbh_ehci { - phys = <&usbphyc_port0>; - phy-names = "usb"; status = "okay"; }; &usbh_ohci { - phys = <&usbphyc_port0>; - phy-names = "usb"; status = "okay"; }; diff --git a/arch/arm/boot/dts/st/stm32mp157c-phycore-stm32mp15-som.dtsi b/arch/arm/boot/dts/st/stm32mp157c-phycore-stm32mp15-som.dtsi index 4e8b2d2b30c7ab..bf0c32027baf76 100644 --- a/arch/arm/boot/dts/st/stm32mp157c-phycore-stm32mp15-som.dtsi +++ b/arch/arm/boot/dts/st/stm32mp157c-phycore-stm32mp15-som.dtsi @@ -547,14 +547,10 @@ }; &usbh_ehci { - phys = <&usbphyc_port0>; - phy-names = "usb"; status = "okay"; }; &usbh_ohci { - phys = <&usbphyc_port0>; - phy-names = "usb"; status = "okay"; }; diff --git a/arch/arm/boot/dts/st/stm32mp15xc-lxa-tac.dtsi b/arch/arm/boot/dts/st/stm32mp15xc-lxa-tac.dtsi index f09b7c384bd931..fc3a2386dbb90d 100644 --- a/arch/arm/boot/dts/st/stm32mp15xc-lxa-tac.dtsi +++ b/arch/arm/boot/dts/st/stm32mp15xc-lxa-tac.dtsi @@ -567,9 +567,6 @@ baseboard_eeprom: &sip_eeprom { }; &usbh_ehci { - phys = <&usbphyc_port0>; - phy-names = "usb"; - status = "okay"; }; diff --git a/arch/arm/boot/dts/st/stm32mp15xx-dhcom-drc02.dtsi b/arch/arm/boot/dts/st/stm32mp15xx-dhcom-drc02.dtsi index 35b1034aa3cf63..bb4f8a0b937f37 100644 --- a/arch/arm/boot/dts/st/stm32mp15xx-dhcom-drc02.dtsi +++ b/arch/arm/boot/dts/st/stm32mp15xx-dhcom-drc02.dtsi @@ -152,7 +152,6 @@ }; &usbh_ehci { - phys = <&usbphyc_port0>; status = "okay"; }; diff --git a/arch/arm/boot/dts/st/stm32mp15xx-dhcom-pdk2.dtsi b/arch/arm/boot/dts/st/stm32mp15xx-dhcom-pdk2.dtsi index 46b87a27d8b378..466d9701add0f6 100644 --- a/arch/arm/boot/dts/st/stm32mp15xx-dhcom-pdk2.dtsi +++ b/arch/arm/boot/dts/st/stm32mp15xx-dhcom-pdk2.dtsi @@ -305,7 +305,6 @@ }; &usbh_ehci { - phys = <&usbphyc_port0>; status = "okay"; }; diff --git a/arch/arm/boot/dts/st/stm32mp15xx-dhcom-picoitx.dtsi b/arch/arm/boot/dts/st/stm32mp15xx-dhcom-picoitx.dtsi index abc595350e71a0..b5bc53accd6b2f 100644 --- a/arch/arm/boot/dts/st/stm32mp15xx-dhcom-picoitx.dtsi +++ b/arch/arm/boot/dts/st/stm32mp15xx-dhcom-picoitx.dtsi @@ -119,12 +119,10 @@ }; &usbh_ehci { - phys = <&usbphyc_port0>; status = "okay"; }; &usbh_ohci { - phys = <&usbphyc_port0>; status = "okay"; }; diff --git a/arch/arm/boot/dts/st/stm32mp15xx-dhcor-avenger96.dtsi b/arch/arm/boot/dts/st/stm32mp15xx-dhcor-avenger96.dtsi index 0069ad75d55e5e..343a4613dfca7c 100644 --- a/arch/arm/boot/dts/st/stm32mp15xx-dhcor-avenger96.dtsi +++ b/arch/arm/boot/dts/st/stm32mp15xx-dhcor-avenger96.dtsi @@ -489,8 +489,6 @@ }; &usbh_ehci { - phys = <&usbphyc_port0>; - phy-names = "usb"; status = "okay"; }; diff --git a/arch/arm/boot/dts/st/stm32mp15xx-dhcor-drc-compact.dtsi b/arch/arm/boot/dts/st/stm32mp15xx-dhcor-drc-compact.dtsi index 92d906bfd5d7d6..bc4ddcbdd5cf6b 100644 --- a/arch/arm/boot/dts/st/stm32mp15xx-dhcor-drc-compact.dtsi +++ b/arch/arm/boot/dts/st/stm32mp15xx-dhcor-drc-compact.dtsi @@ -312,12 +312,10 @@ }; &usbh_ehci { - phys = <&usbphyc_port0>; status = "okay"; }; &usbh_ohci { - phys = <&usbphyc_port0>; status = "okay"; }; diff --git a/arch/arm/boot/dts/st/stm32mp15xx-dhcor-testbench.dtsi b/arch/arm/boot/dts/st/stm32mp15xx-dhcor-testbench.dtsi index ab7f0ba4963968..6e79c4b6fe325f 100644 --- a/arch/arm/boot/dts/st/stm32mp15xx-dhcor-testbench.dtsi +++ b/arch/arm/boot/dts/st/stm32mp15xx-dhcor-testbench.dtsi @@ -168,12 +168,10 @@ }; &usbh_ehci { - phys = <&usbphyc_port0>; status = "okay"; }; &usbh_ohci { - phys = <&usbphyc_port0>; status = "okay"; }; diff --git a/arch/arm/boot/dts/st/stm32mp15xx-dkx.dtsi b/arch/arm/boot/dts/st/stm32mp15xx-dkx.dtsi index 511113f2e39928..f7634c51efb26f 100644 --- a/arch/arm/boot/dts/st/stm32mp15xx-dkx.dtsi +++ b/arch/arm/boot/dts/st/stm32mp15xx-dkx.dtsi @@ -680,7 +680,6 @@ }; &usbh_ehci { - phys = <&usbphyc_port0>; status = "okay"; #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm/boot/dts/ti/keystone/keystone-k2e-netcp.dtsi b/arch/arm/boot/dts/ti/keystone/keystone-k2e-netcp.dtsi index bff73a0ed10bfb..5c88a90903b845 100644 --- a/arch/arm/boot/dts/ti/keystone/keystone-k2e-netcp.dtsi +++ b/arch/arm/boot/dts/ti/keystone/keystone-k2e-netcp.dtsi @@ -36,9 +36,9 @@ qmss: qmss@2a40000 { qpend { qpend-0 { qrange = <658 8>; - interrupts =<0 40 0xf04 0 41 0xf04 0 42 0xf04 - 0 43 0xf04 0 44 0xf04 0 45 0xf04 - 0 46 0xf04 0 47 0xf04>; + interrupts = <0 40 0xf04 0 41 0xf04 0 42 0xf04 + 0 43 0xf04 0 44 0xf04 0 45 0xf04 + 0 46 0xf04 0 47 0xf04>; }; qpend-1 { qrange = <528 16>; diff --git a/arch/arm/boot/dts/ti/keystone/keystone-k2g-evm.dts b/arch/arm/boot/dts/ti/keystone/keystone-k2g-evm.dts index 7bfc80f1af26bb..f0ddbbcdc97215 100644 --- a/arch/arm/boot/dts/ti/keystone/keystone-k2g-evm.dts +++ b/arch/arm/boot/dts/ti/keystone/keystone-k2g-evm.dts @@ -9,7 +9,7 @@ #include "keystone-k2g.dtsi" / { - compatible = "ti,k2g-evm", "ti,k2g", "ti,keystone"; + compatible = "ti,k2g-evm", "ti,k2g", "ti,keystone"; model = "Texas Instruments K2G General Purpose EVM"; memory@800000000 { diff --git a/arch/arm/boot/dts/ti/keystone/keystone-k2g-netcp.dtsi b/arch/arm/boot/dts/ti/keystone/keystone-k2g-netcp.dtsi index f6306933ff426b..7109ca0316175d 100644 --- a/arch/arm/boot/dts/ti/keystone/keystone-k2g-netcp.dtsi +++ b/arch/arm/boot/dts/ti/keystone/keystone-k2g-netcp.dtsi @@ -37,9 +37,9 @@ qmss: qmss@4020000 { qpend { qpend-0 { qrange = <77 8>; - interrupts =<0 308 0xf04 0 309 0xf04 0 310 0xf04 - 0 311 0xf04 0 312 0xf04 0 313 0xf04 - 0 314 0xf04 0 315 0xf04>; + interrupts = <0 308 0xf04 0 309 0xf04 0 310 0xf04 + 0 311 0xf04 0 312 0xf04 0 313 0xf04 + 0 314 0xf04 0 315 0xf04>; qalloc-by-id; }; }; diff --git a/arch/arm/boot/dts/ti/keystone/keystone-k2hk-evm.dts b/arch/arm/boot/dts/ti/keystone/keystone-k2hk-evm.dts index 206df8a8d9dd7d..8dfb54295027e8 100644 --- a/arch/arm/boot/dts/ti/keystone/keystone-k2hk-evm.dts +++ b/arch/arm/boot/dts/ti/keystone/keystone-k2hk-evm.dts @@ -10,7 +10,7 @@ #include "keystone-k2hk.dtsi" / { - compatible = "ti,k2hk-evm", "ti,k2hk", "ti,keystone"; + compatible = "ti,k2hk-evm", "ti,k2hk", "ti,keystone"; model = "Texas Instruments Keystone 2 Kepler/Hawking EVM"; reserved-memory { diff --git a/arch/arm/boot/dts/ti/keystone/keystone-k2hk-netcp.dtsi b/arch/arm/boot/dts/ti/keystone/keystone-k2hk-netcp.dtsi index 8a421c65f9209e..c2ee775eab6aed 100644 --- a/arch/arm/boot/dts/ti/keystone/keystone-k2hk-netcp.dtsi +++ b/arch/arm/boot/dts/ti/keystone/keystone-k2hk-netcp.dtsi @@ -49,9 +49,9 @@ qmss: qmss@2a40000 { qpend { qpend-0 { qrange = <658 8>; - interrupts =<0 40 0xf04 0 41 0xf04 0 42 0xf04 - 0 43 0xf04 0 44 0xf04 0 45 0xf04 - 0 46 0xf04 0 47 0xf04>; + interrupts = <0 40 0xf04 0 41 0xf04 0 42 0xf04 + 0 43 0xf04 0 44 0xf04 0 45 0xf04 + 0 46 0xf04 0 47 0xf04>; }; qpend-1 { qrange = <8704 16>; diff --git a/arch/arm/boot/dts/ti/keystone/keystone-k2l-netcp.dtsi b/arch/arm/boot/dts/ti/keystone/keystone-k2l-netcp.dtsi index 5ec6680a533da8..1afebd7458c113 100644 --- a/arch/arm/boot/dts/ti/keystone/keystone-k2l-netcp.dtsi +++ b/arch/arm/boot/dts/ti/keystone/keystone-k2l-netcp.dtsi @@ -36,9 +36,9 @@ qmss: qmss@2a40000 { qpend { qpend-0 { qrange = <658 8>; - interrupts =<0 40 0xf04 0 41 0xf04 0 42 0xf04 - 0 43 0xf04 0 44 0xf04 0 45 0xf04 - 0 46 0xf04 0 47 0xf04>; + interrupts = <0 40 0xf04 0 41 0xf04 0 42 0xf04 + 0 43 0xf04 0 44 0xf04 0 45 0xf04 + 0 46 0xf04 0 47 0xf04>; }; qpend-1 { qrange = <528 16>; diff --git a/arch/arm/boot/dts/ti/omap/Makefile b/arch/arm/boot/dts/ti/omap/Makefile index d2b590004fedfe..95c68135dd0c52 100644 --- a/arch/arm/boot/dts/ti/omap/Makefile +++ b/arch/arm/boot/dts/ti/omap/Makefile @@ -79,7 +79,9 @@ dtb-$(CONFIG_ARCH_OMAP4) += \ omap4-sdp.dtb \ omap4-sdp-es23plus.dtb \ omap4-var-dvk-om44.dtb \ - omap4-var-stk-om44.dtb + omap4-var-stk-om44.dtb \ + omap4-xyboard-mz609.dtb \ + omap4-xyboard-mz617.dtb dtb-$(CONFIG_SOC_AM33XX) += \ am335x-baltos-ir2110.dtb \ am335x-baltos-ir3220.dtb \ @@ -129,6 +131,16 @@ dtb-$(CONFIG_SOC_AM43XX) += \ am57xx-evm-dtbs := am57xx-beagle-x15.dtb am57xx-evm.dtbo am57xx-evm-reva3-dtbs := am57xx-beagle-x15-revc.dtb am57xx-evm.dtbo +am571x-idk-overlays-dtbs := am571x-idk.dtb \ + am571x-idk-touchscreen.dtbo am57xx-idk-lcd-osd101t2587.dtbo +am572x-idk-overlays-dtbs := am572x-idk.dtb \ + am572x-idk-touchscreen.dtbo am57xx-idk-lcd-osd101t2045.dtbo + +# Build time test only, enabled by CONFIG_OF_ALL_DTBS +dtb- += \ + am571x-idk-overlays.dtb \ + am572x-idk-overlays.dtb + dtb-$(CONFIG_SOC_DRA7XX) += \ am57xx-beagle-x15.dtb \ am57xx-beagle-x15-revb1.dtb \ diff --git a/arch/arm/boot/dts/ti/omap/am335x-moxa-uc-2100-common.dtsi b/arch/arm/boot/dts/ti/omap/am335x-moxa-uc-2100-common.dtsi index b8730aa52ce6fe..a59331aa58e55e 100644 --- a/arch/arm/boot/dts/ti/omap/am335x-moxa-uc-2100-common.dtsi +++ b/arch/arm/boot/dts/ti/omap/am335x-moxa-uc-2100-common.dtsi @@ -217,7 +217,7 @@ pinctrl-names = "default"; pinctrl-0 = <&spi1_pins>; - tpm_spi_tis@0 { + tpm@0 { compatible = "tcg,tpm_tis-spi"; reg = <0>; spi-max-frequency = <500000>; diff --git a/arch/arm/boot/dts/ti/omap/am571x-idk.dts b/arch/arm/boot/dts/ti/omap/am571x-idk.dts index 48425020281a9a..322cf79d22e996 100644 --- a/arch/arm/boot/dts/ti/omap/am571x-idk.dts +++ b/arch/arm/boot/dts/ti/omap/am571x-idk.dts @@ -168,8 +168,8 @@ }; &extcon_usb2 { - id-gpio = <&gpio5 7 GPIO_ACTIVE_HIGH>; - vbus-gpio = <&gpio7 22 GPIO_ACTIVE_HIGH>; + id-gpios = <&gpio5 7 GPIO_ACTIVE_HIGH>; + vbus-gpios = <&gpio7 22 GPIO_ACTIVE_HIGH>; }; &sn65hvs882 { diff --git a/arch/arm/boot/dts/ti/omap/am5729-beagleboneai.dts b/arch/arm/boot/dts/ti/omap/am5729-beagleboneai.dts index 9a234dc1431d12..c8e55642f9c6e5 100644 --- a/arch/arm/boot/dts/ti/omap/am5729-beagleboneai.dts +++ b/arch/arm/boot/dts/ti/omap/am5729-beagleboneai.dts @@ -197,7 +197,7 @@ extcon_usb1: extcon_usb1 { compatible = "linux,extcon-usb-gpio"; ti,enable-id-detection; - id-gpio = <&gpio3 13 GPIO_ACTIVE_HIGH>; + id-gpios = <&gpio3 13 GPIO_ACTIVE_HIGH>; }; }; diff --git a/arch/arm/boot/dts/ti/omap/am572x-idk-common.dtsi b/arch/arm/boot/dts/ti/omap/am572x-idk-common.dtsi index 1d66278c3a7220..3fca84819dc0ce 100644 --- a/arch/arm/boot/dts/ti/omap/am572x-idk-common.dtsi +++ b/arch/arm/boot/dts/ti/omap/am572x-idk-common.dtsi @@ -169,8 +169,8 @@ }; &extcon_usb2 { - id-gpio = <&gpio3 16 GPIO_ACTIVE_HIGH>; - vbus-gpio = <&gpio3 26 GPIO_ACTIVE_HIGH>; + id-gpios = <&gpio3 16 GPIO_ACTIVE_HIGH>; + vbus-gpios = <&gpio3 26 GPIO_ACTIVE_HIGH>; }; &sn65hvs882 { diff --git a/arch/arm/boot/dts/ti/omap/dra7-evm-common.dtsi b/arch/arm/boot/dts/ti/omap/dra7-evm-common.dtsi index 4cdffd6db74073..ed5199d7acd843 100644 --- a/arch/arm/boot/dts/ti/omap/dra7-evm-common.dtsi +++ b/arch/arm/boot/dts/ti/omap/dra7-evm-common.dtsi @@ -15,12 +15,12 @@ extcon_usb1: extcon_usb1 { compatible = "linux,extcon-usb-gpio"; - id-gpio = <&pcf_gpio_21 1 GPIO_ACTIVE_HIGH>; + id-gpios = <&pcf_gpio_21 1 GPIO_ACTIVE_HIGH>; }; extcon_usb2: extcon_usb2 { compatible = "linux,extcon-usb-gpio"; - id-gpio = <&pcf_gpio_21 2 GPIO_ACTIVE_HIGH>; + id-gpios = <&pcf_gpio_21 2 GPIO_ACTIVE_HIGH>; }; sound0: sound0 { diff --git a/arch/arm/boot/dts/ti/omap/dra71-evm.dts b/arch/arm/boot/dts/ti/omap/dra71-evm.dts index a6436444303152..f747ac56eb9278 100644 --- a/arch/arm/boot/dts/ti/omap/dra71-evm.dts +++ b/arch/arm/boot/dts/ti/omap/dra71-evm.dts @@ -293,11 +293,11 @@ }; &extcon_usb1 { - vbus-gpio = <&pcf_lcd 14 GPIO_ACTIVE_HIGH>; + vbus-gpios = <&pcf_lcd 14 GPIO_ACTIVE_HIGH>; }; &extcon_usb2 { - vbus-gpio = <&pcf_lcd 15 GPIO_ACTIVE_HIGH>; + vbus-gpios = <&pcf_lcd 15 GPIO_ACTIVE_HIGH>; }; &ipu2 { diff --git a/arch/arm/boot/dts/ti/omap/dra72-evm-common.dtsi b/arch/arm/boot/dts/ti/omap/dra72-evm-common.dtsi index 31ab0c60ca75e0..f8151c61488e14 100644 --- a/arch/arm/boot/dts/ti/omap/dra72-evm-common.dtsi +++ b/arch/arm/boot/dts/ti/omap/dra72-evm-common.dtsi @@ -96,12 +96,12 @@ extcon_usb1: extcon_usb1 { compatible = "linux,extcon-usb-gpio"; - id-gpio = <&pcf_gpio_21 1 GPIO_ACTIVE_HIGH>; + id-gpios = <&pcf_gpio_21 1 GPIO_ACTIVE_HIGH>; }; extcon_usb2: extcon_usb2 { compatible = "linux,extcon-usb-gpio"; - id-gpio = <&pcf_gpio_21 2 GPIO_ACTIVE_HIGH>; + id-gpios = <&pcf_gpio_21 2 GPIO_ACTIVE_HIGH>; }; hdmi0: connector { diff --git a/arch/arm/boot/dts/ti/omap/dra76-evm.dts b/arch/arm/boot/dts/ti/omap/dra76-evm.dts index 57868ac60d2985..cf9c3d35b04992 100644 --- a/arch/arm/boot/dts/ti/omap/dra76-evm.dts +++ b/arch/arm/boot/dts/ti/omap/dra76-evm.dts @@ -533,11 +533,11 @@ }; &extcon_usb1 { - vbus-gpio = <&pcf_lcd 14 GPIO_ACTIVE_HIGH>; + vbus-gpios = <&pcf_lcd 14 GPIO_ACTIVE_HIGH>; }; &extcon_usb2 { - vbus-gpio = <&pcf_lcd 15 GPIO_ACTIVE_HIGH>; + vbus-gpios = <&pcf_lcd 15 GPIO_ACTIVE_HIGH>; }; &m_can0 { diff --git a/arch/arm/boot/dts/ti/omap/logicpd-torpedo-37xx-devkit.dts b/arch/arm/boot/dts/ti/omap/logicpd-torpedo-37xx-devkit.dts index 533ce7ce387a54..fbff15a0a0fe9e 100644 --- a/arch/arm/boot/dts/ti/omap/logicpd-torpedo-37xx-devkit.dts +++ b/arch/arm/boot/dts/ti/omap/logicpd-torpedo-37xx-devkit.dts @@ -52,7 +52,7 @@ &uart2 { /delete-property/dma-names; - bluetooth { + bluetooth-gnss { compatible = "ti,wl1283-st"; enable-gpios = <&gpio6 2 GPIO_ACTIVE_HIGH>; /* gpio 162 */ max-speed = <3000000>; diff --git a/arch/arm/boot/dts/ti/omap/motorola-mapphone-common.dtsi b/arch/arm/boot/dts/ti/omap/motorola-mapphone-common.dtsi index a2bb3609c94feb..a0c53d9c26255a 100644 --- a/arch/arm/boot/dts/ti/omap/motorola-mapphone-common.dtsi +++ b/arch/arm/boot/dts/ti/omap/motorola-mapphone-common.dtsi @@ -6,15 +6,6 @@ #include "motorola-cpcap-mapphone.dtsi" / { - chosen { - stdout-path = &uart3; - }; - - aliases { - display0 = &lcd0; - display1 = &hdmi0; - }; - /* * We seem to have only 1021 MB accessible, 1021 - 1022 is locked, * then 1023 - 1024 seems to contain mbm. @@ -63,46 +54,6 @@ regulator-always-on; }; - /* FS USB Host PHY on port 1 for mdm6600 */ - fsusb1_phy: usb-phy@1 { - compatible = "motorola,mapphone-mdm6600"; - pinctrl-0 = <&usb_mdm6600_pins>; - pinctrl-1 = <&usb_mdm6600_sleep_pins>; - pinctrl-names = "default", "sleep"; - enable-gpios = <&gpio3 31 GPIO_ACTIVE_LOW>; /* gpio_95 */ - power-gpios = <&gpio2 22 GPIO_ACTIVE_HIGH>; /* gpio_54 */ - reset-gpios = <&gpio2 17 GPIO_ACTIVE_HIGH>; /* gpio_49 */ - /* mode: gpio_148 gpio_149 */ - motorola,mode-gpios = <&gpio5 20 GPIO_ACTIVE_HIGH>, - <&gpio5 21 GPIO_ACTIVE_HIGH>; - /* cmd: gpio_103 gpio_104 gpio_142 */ - motorola,cmd-gpios = <&gpio4 7 GPIO_ACTIVE_HIGH>, - <&gpio4 8 GPIO_ACTIVE_HIGH>, - <&gpio5 14 GPIO_ACTIVE_HIGH>; - /* status: gpio_52 gpio_53 gpio_55 */ - motorola,status-gpios = <&gpio2 20 GPIO_ACTIVE_HIGH>, - <&gpio2 21 GPIO_ACTIVE_HIGH>, - <&gpio2 23 GPIO_ACTIVE_HIGH>; - #phy-cells = <0>; - }; - - /* HS USB host TLL nop-phy on port 2 for w3glte */ - hsusb2_phy: usb-phy@2 { - compatible = "usb-nop-xceiv"; - #phy-cells = <0>; - }; - - /* LCD regulator from sw5 source */ - lcd_regulator: regulator-lcd { - compatible = "regulator-fixed"; - regulator-name = "lcd"; - regulator-min-microvolt = <5050000>; - regulator-max-microvolt = <5050000>; - gpio = <&gpio4 0 GPIO_ACTIVE_HIGH>; /* gpio96 */ - enable-active-high; - vin-supply = <&sw5>; - }; - /* This is probably coming straight from the battery.. */ wl12xx_vmmc: regulator-wl12xx { compatible = "regulator-fixed"; @@ -133,41 +84,6 @@ dais = <&mcbsp2_port>, <&mcbsp3_port>; }; - - pwm8: pwm-8 { - pinctrl-names = "default"; - pinctrl-0 = <&vibrator_direction_pin>; - - compatible = "ti,omap-dmtimer-pwm"; - #pwm-cells = <3>; - ti,timers = <&timer8>; - ti,clock-source = <0x01>; - }; - - pwm9: pwm-9 { - pinctrl-names = "default"; - pinctrl-0 = <&vibrator_enable_pin>; - - compatible = "ti,omap-dmtimer-pwm"; - #pwm-cells = <3>; - ti,timers = <&timer9>; - ti,clock-source = <0x01>; - }; - - vibrator { - compatible = "pwm-vibrator"; - pwms = <&pwm9 0 10000000 0>, <&pwm8 0 10000000 0>; - pwm-names = "enable", "direction"; - direction-duty-cycle-ns = <10000000>; - }; - - backlight: backlight { - compatible = "led-backlight"; - - leds = <&backlight_led>; - brightness-levels = <31 63 95 127 159 191 223 255>; - default-brightness-level = <6>; - }; }; &cpu_thermal { @@ -197,57 +113,6 @@ status = "okay"; }; -&dsi1 { - status = "okay"; - vdd-supply = <&vcsi>; - - port { - dsi1_out_ep: endpoint { - remote-endpoint = <&lcd0_in>; - lanes = <0 1 2 3 4 5>; - }; - }; - - lcd0: panel@0 { - compatible = "motorola,droid4-panel", "panel-dsi-cm"; - reg = <0>; - label = "lcd0"; - vddi-supply = <&lcd_regulator>; - reset-gpios = <&gpio4 5 GPIO_ACTIVE_HIGH>; /* gpio101 */ - - backlight = <&backlight>; - - width-mm = <50>; - height-mm = <89>; - rotation = <90>; - - panel-timing { - clock-frequency = <0>; /* Calculated by dsi */ - - hback-porch = <2>; - hactive = <540>; - hfront-porch = <0>; - hsync-len = <2>; - - vback-porch = <1>; - vactive = <960>; - vfront-porch = <0>; - vsync-len = <1>; - - hsync-active = <0>; - vsync-active = <0>; - de-active = <1>; - pixelclk-active = <1>; - }; - - port { - lcd0_in: endpoint { - remote-endpoint = <&dsi1_out_ep>; - }; - }; - }; -}; - &hdmi { status = "okay"; pinctrl-0 = <&dss_hdmi_pins>; @@ -262,13 +127,6 @@ }; }; -/* Battery NVRAM on 1-wire handled by w1_ds250x driver */ -&hdqw1w { - pinctrl-0 = <&hdq_pins>; - pinctrl-names = "default"; - ti,mode = "1w"; -}; - &i2c1 { tmp105@48 { compatible = "ti,tmp105"; @@ -322,34 +180,6 @@ }; }; -&i2c2 { - touchscreen@4a { - compatible = "atmel,maxtouch"; - reg = <0x4a>; - pinctrl-names = "default"; - pinctrl-0 = <&touchscreen_pins>; - - reset-gpios = <&gpio6 13 GPIO_ACTIVE_LOW>; /* gpio173 */ - - /* gpio_183 with sys_nirq2 pad as wakeup */ - interrupts-extended = <&gpio6 23 IRQ_TYPE_LEVEL_LOW>, - <&omap4_pmx_core 0x160>; - interrupt-names = "irq", "wakeup"; - wakeup-source; - }; - - isl29030@44 { - compatible = "isil,isl29030"; - reg = <0x44>; - - pinctrl-names = "default"; - pinctrl-0 = <&als_proximity_pins>; - - interrupt-parent = <&gpio6>; - interrupts = <17 IRQ_TYPE_LEVEL_LOW>; /* gpio177 */ - }; -}; - &omap4_pmx_core { /* hdmi_hpd.gpio_63 */ @@ -359,13 +189,6 @@ >; }; - hdq_pins: hdq-pins { - pinctrl-single,pins = < - /* 0x4a100120 hdq_sio.hdq_sio aa27 */ - OMAP4_IOPAD(0x120, PIN_INPUT | MUX_MODE0) - >; - }; - /* hdmi_cec.hdmi_cec, hdmi_scl.hdmi_scl, hdmi_sda.hdmi_sda */ dss_hdmi_pins: dss-hdmi-pins { pinctrl-single,pins = < @@ -427,73 +250,6 @@ >; }; - touchscreen_pins: touchscreen-pins { - pinctrl-single,pins = < - OMAP4_IOPAD(0x180, PIN_OUTPUT | MUX_MODE3) - OMAP4_IOPAD(0x1a0, PIN_INPUT_PULLUP | MUX_MODE3) - >; - }; - - als_proximity_pins: als-proximity-pins { - pinctrl-single,pins = < - OMAP4_IOPAD(0x18c, PIN_INPUT_PULLUP | MUX_MODE3) - >; - }; - - usb_mdm6600_pins: usb-mdm6600-pins { - pinctrl-single,pins = < - /* enable 0x4a1000d8 usbb1_ulpitll_dat7.gpio_95 ag16 */ - OMAP4_IOPAD(0x0d8, PIN_INPUT | MUX_MODE3) - - /* power 0x4a10007c gpmc_nwp.gpio_54 c25 */ - OMAP4_IOPAD(0x07c, PIN_OUTPUT | MUX_MODE3) - - /* reset 0x4a100072 gpmc_a25.gpio_49 d20 */ - OMAP4_IOPAD(0x072, PIN_OUTPUT | MUX_MODE3) - - /* mode0/bpwake 0x4a10014e sdmmc5_dat1.gpio_148 af4 */ - OMAP4_IOPAD(0x14e, PIN_OUTPUT | MUX_MODE3) - - /* mode1/apwake 0x4a100150 sdmmc5_dat2.gpio_149 ag3 */ - OMAP4_IOPAD(0x150, PIN_OFF_OUTPUT_LOW | PIN_INPUT | MUX_MODE3) - - /* status0 0x4a10007e gpmc_clk.gpio_55 b22 */ - OMAP4_IOPAD(0x07e, PIN_INPUT | MUX_MODE3) - - /* status1 0x4a10007a gpmc_ncs3.gpio_53 c22 */ - OMAP4_IOPAD(0x07a, PIN_INPUT | MUX_MODE3) - - /* status2 0x4a100078 gpmc_ncs2.gpio_52 d21 */ - OMAP4_IOPAD(0x078, PIN_INPUT | MUX_MODE3) - - /* cmd0 0x4a100094 gpmc_ncs6.gpio_103 c24 */ - OMAP4_IOPAD(0x094, PIN_OUTPUT | MUX_MODE3) - - /* cmd1 0x4a100096 gpmc_ncs7.gpio_104 d24 */ - OMAP4_IOPAD(0x096, PIN_OUTPUT | MUX_MODE3) - - /* cmd2 0x4a100142 uart3_rts_sd.gpio_142 f28 */ - OMAP4_IOPAD(0x142, PIN_OUTPUT | MUX_MODE3) - >; - }; - - /* Modem sleep pins to keep gpio_49 high with internal pull */ - usb_mdm6600_sleep_pins: usb-mdm6600-sleep-pins { - pinctrl-single,pins = < - OMAP4_IOPAD(0x0d8, PIN_INPUT | MUX_MODE3) - OMAP4_IOPAD(0x07c, PIN_OUTPUT | MUX_MODE3) - OMAP4_IOPAD(0x072, PIN_INPUT_PULLUP | MUX_MODE7) /* Keep gpio_49 reset high */ - OMAP4_IOPAD(0x14e, PIN_OUTPUT | MUX_MODE3) - OMAP4_IOPAD(0x150, PIN_OFF_OUTPUT_LOW | PIN_INPUT | MUX_MODE3) - OMAP4_IOPAD(0x07e, PIN_INPUT | MUX_MODE3) - OMAP4_IOPAD(0x07a, PIN_INPUT | MUX_MODE3) - OMAP4_IOPAD(0x078, PIN_INPUT | MUX_MODE3) - OMAP4_IOPAD(0x094, PIN_OUTPUT | MUX_MODE3) - OMAP4_IOPAD(0x096, PIN_OUTPUT | MUX_MODE3) - OMAP4_IOPAD(0x142, PIN_OUTPUT | MUX_MODE3) - >; - }; - usb_ulpi_pins: usb-ulpi-pins { pinctrl-single,pins = < OMAP4_IOPAD(0x196, MUX_MODE7) @@ -601,18 +357,6 @@ OMAP4_IOPAD(0x10c, PIN_INPUT | MUX_MODE1) /* abe_mcbsp3_fsx */ >; }; - - vibrator_direction_pin: vibrator-direction-pins { - pinctrl-single,pins = < - OMAP4_IOPAD(0x1ce, PIN_OUTPUT | MUX_MODE1) /* dmtimer8_pwm_evt (gpio_27) */ - >; - }; - - vibrator_enable_pin: vibrator-enable-pins { - pinctrl-single,pins = < - OMAP4_IOPAD(0X1d0, PIN_OUTPUT | MUX_MODE1) /* dmtimer9_pwm_evt (gpio_28) */ - >; - }; }; &omap4_pmx_wkup { @@ -629,17 +373,6 @@ status = "disabled"; }; -/* Configure pwm clock source for timers 8 & 9 */ -&timer8 { - assigned-clocks = <&abe_clkctrl OMAP4_TIMER8_CLKCTRL 24>; - assigned-clock-parents = <&sys_32k_ck>; -}; - -&timer9 { - assigned-clocks = <&l4_per_clkctrl OMAP4_TIMER9_CLKCTRL 24>; - assigned-clock-parents = <&sys_32k_ck>; -}; - /* * The uart1 port is wired to mdm6600 with rts and cts. The modem uses gpio_149 * for wake-up events for both the USB PHY and the UART. We can use gpio_149 @@ -672,20 +405,6 @@ }; }; -&usbhsohci { - phys = <&fsusb1_phy>; - phy-names = "usb"; -}; - -&usbhsehci { - phys = <&hsusb2_phy>; -}; - -&usbhshost { - port1-mode = "ohci-phy-4pin-dpdm"; - port2-mode = "ehci-tll"; -}; - /* Internal UTMI+ PHY used for OTG, CPCAP ULPI PHY for detection and charger */ &usb_otg_hs { interface-type = <1>; @@ -698,23 +417,6 @@ power = <150>; }; -&i2c4 { - ak8975: magnetometer@c { - compatible = "asahi-kasei,ak8975"; - reg = <0x0c>; - - vdd-supply = <&vhvio>; - - interrupt-parent = <&gpio6>; - interrupts = <15 IRQ_TYPE_EDGE_RISING>; /* gpio175 */ - - rotation-matrix = "-1", "0", "0", - "0", "1", "0", - "0", "0", "-1"; - - }; -}; - &mcbsp2 { #sound-dai-cells = <0>; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/ti/omap/motorola-mapphone-handset.dtsi b/arch/arm/boot/dts/ti/omap/motorola-mapphone-handset.dtsi new file mode 100644 index 00000000000000..f3f9ff02b35f07 --- /dev/null +++ b/arch/arm/boot/dts/ti/omap/motorola-mapphone-handset.dtsi @@ -0,0 +1,234 @@ +// SPDX-License-Identifier: GPL-2.0-only +/dts-v1/; + +#include "motorola-mapphone-common.dtsi" + +/ { + /* FS USB Host PHY on port 1 for mdm6600 */ + fsusb1_phy: usb-phy@1 { + compatible = "motorola,mapphone-mdm6600"; + pinctrl-0 = <&usb_mdm6600_pins>; + pinctrl-1 = <&usb_mdm6600_sleep_pins>; + pinctrl-names = "default", "sleep"; + enable-gpios = <&gpio3 31 GPIO_ACTIVE_LOW>; /* gpio_95 */ + power-gpios = <&gpio2 22 GPIO_ACTIVE_HIGH>; /* gpio_54 */ + reset-gpios = <&gpio2 17 GPIO_ACTIVE_HIGH>; /* gpio_49 */ + /* mode: gpio_148 gpio_149 */ + motorola,mode-gpios = <&gpio5 20 GPIO_ACTIVE_HIGH>, + <&gpio5 21 GPIO_ACTIVE_HIGH>; + /* cmd: gpio_103 gpio_104 gpio_142 */ + motorola,cmd-gpios = <&gpio4 7 GPIO_ACTIVE_HIGH>, + <&gpio4 8 GPIO_ACTIVE_HIGH>, + <&gpio5 14 GPIO_ACTIVE_HIGH>; + /* status: gpio_52 gpio_53 gpio_55 */ + motorola,status-gpios = <&gpio2 20 GPIO_ACTIVE_HIGH>, + <&gpio2 21 GPIO_ACTIVE_HIGH>, + <&gpio2 23 GPIO_ACTIVE_HIGH>; + #phy-cells = <0>; + }; + + /* HS USB host TLL nop-phy on port 2 for w3glte */ + hsusb2_phy: usb-phy@2 { + compatible = "usb-nop-xceiv"; + #phy-cells = <0>; + }; + + pwm8: pwm-8 { + pinctrl-names = "default"; + pinctrl-0 = <&vibrator_direction_pin>; + + compatible = "ti,omap-dmtimer-pwm"; + #pwm-cells = <3>; + ti,timers = <&timer8>; + ti,clock-source = <0x01>; + }; + + pwm9: pwm-9 { + pinctrl-names = "default"; + pinctrl-0 = <&vibrator_enable_pin>; + + compatible = "ti,omap-dmtimer-pwm"; + #pwm-cells = <3>; + ti,timers = <&timer9>; + ti,clock-source = <0x01>; + }; + + vibrator { + compatible = "pwm-vibrator"; + pwms = <&pwm9 0 10000000 0>, <&pwm8 0 10000000 0>; + pwm-names = "enable", "direction"; + direction-duty-cycle-ns = <10000000>; + }; +}; + +/* Battery NVRAM on 1-wire handled by w1_ds250x driver */ +&hdqw1w { + pinctrl-0 = <&hdq_pins>; + pinctrl-names = "default"; + ti,mode = "1w"; +}; + +&i2c2 { + touchscreen@4a { + compatible = "atmel,maxtouch"; + reg = <0x4a>; + pinctrl-names = "default"; + pinctrl-0 = <&touchscreen_pins>; + + reset-gpios = <&gpio6 13 GPIO_ACTIVE_LOW>; /* gpio173 */ + + /* gpio_183 with sys_nirq2 pad as wakeup */ + interrupts-extended = <&gpio6 23 IRQ_TYPE_LEVEL_LOW>, + <&omap4_pmx_core 0x160>; + interrupt-names = "irq", "wakeup"; + wakeup-source; + }; + + isl29030@44 { + compatible = "isil,isl29030"; + reg = <0x44>; + + pinctrl-names = "default"; + pinctrl-0 = <&als_proximity_pins>; + + interrupt-parent = <&gpio6>; + interrupts = <17 IRQ_TYPE_LEVEL_LOW>; /* gpio177 */ + }; +}; + +&omap4_pmx_core { + hdq_pins: hdq-pins { + pinctrl-single,pins = < + /* 0x4a100120 hdq_sio.hdq_sio aa27 */ + OMAP4_IOPAD(0x120, PIN_INPUT | MUX_MODE0) + >; + }; + + /* kpd_row0.gpio_178 */ + tmp105_irq: tmp105-irq-pins { + pinctrl-single,pins = < + OMAP4_IOPAD(0x18e, PIN_INPUT_PULLUP | MUX_MODE3) + >; + }; + + touchscreen_pins: touchscreen-pins { + pinctrl-single,pins = < + OMAP4_IOPAD(0x180, PIN_OUTPUT | MUX_MODE3) + OMAP4_IOPAD(0x1a0, PIN_INPUT_PULLUP | MUX_MODE3) + >; + }; + + usb_mdm6600_pins: usb-mdm6600-pins { + pinctrl-single,pins = < + /* enable 0x4a1000d8 usbb1_ulpitll_dat7.gpio_95 ag16 */ + OMAP4_IOPAD(0x0d8, PIN_INPUT | MUX_MODE3) + + /* power 0x4a10007c gpmc_nwp.gpio_54 c25 */ + OMAP4_IOPAD(0x07c, PIN_OUTPUT | MUX_MODE3) + + /* reset 0x4a100072 gpmc_a25.gpio_49 d20 */ + OMAP4_IOPAD(0x072, PIN_OUTPUT | MUX_MODE3) + + /* mode0/bpwake 0x4a10014e sdmmc5_dat1.gpio_148 af4 */ + OMAP4_IOPAD(0x14e, PIN_OUTPUT | MUX_MODE3) + + /* mode1/apwake 0x4a100150 sdmmc5_dat2.gpio_149 ag3 */ + OMAP4_IOPAD(0x150, PIN_OFF_OUTPUT_LOW | PIN_INPUT | MUX_MODE3) + + /* status0 0x4a10007e gpmc_clk.gpio_55 b22 */ + OMAP4_IOPAD(0x07e, PIN_INPUT | MUX_MODE3) + + /* status1 0x4a10007a gpmc_ncs3.gpio_53 c22 */ + OMAP4_IOPAD(0x07a, PIN_INPUT | MUX_MODE3) + + /* status2 0x4a100078 gpmc_ncs2.gpio_52 d21 */ + OMAP4_IOPAD(0x078, PIN_INPUT | MUX_MODE3) + + /* cmd0 0x4a100094 gpmc_ncs6.gpio_103 c24 */ + OMAP4_IOPAD(0x094, PIN_OUTPUT | MUX_MODE3) + + /* cmd1 0x4a100096 gpmc_ncs7.gpio_104 d24 */ + OMAP4_IOPAD(0x096, PIN_OUTPUT | MUX_MODE3) + + /* cmd2 0x4a100142 uart3_rts_sd.gpio_142 f28 */ + OMAP4_IOPAD(0x142, PIN_OUTPUT | MUX_MODE3) + >; + }; + + /* Modem sleep pins to keep gpio_49 high with internal pull */ + usb_mdm6600_sleep_pins: usb-mdm6600-sleep-pins { + pinctrl-single,pins = < + OMAP4_IOPAD(0x0d8, PIN_INPUT | MUX_MODE3) + OMAP4_IOPAD(0x07c, PIN_OUTPUT | MUX_MODE3) + OMAP4_IOPAD(0x072, PIN_INPUT_PULLUP | MUX_MODE7) /* Keep gpio_49 reset high */ + OMAP4_IOPAD(0x14e, PIN_OUTPUT | MUX_MODE3) + OMAP4_IOPAD(0x150, PIN_OFF_OUTPUT_LOW | PIN_INPUT | MUX_MODE3) + OMAP4_IOPAD(0x07e, PIN_INPUT | MUX_MODE3) + OMAP4_IOPAD(0x07a, PIN_INPUT | MUX_MODE3) + OMAP4_IOPAD(0x078, PIN_INPUT | MUX_MODE3) + OMAP4_IOPAD(0x094, PIN_OUTPUT | MUX_MODE3) + OMAP4_IOPAD(0x096, PIN_OUTPUT | MUX_MODE3) + OMAP4_IOPAD(0x142, PIN_OUTPUT | MUX_MODE3) + >; + }; + + als_proximity_pins: als-proximity-pins { + pinctrl-single,pins = < + OMAP4_IOPAD(0x18c, PIN_INPUT_PULLUP | MUX_MODE3) + >; + }; + + vibrator_direction_pin: vibrator-direction-pins { + pinctrl-single,pins = < + OMAP4_IOPAD(0x1ce, PIN_OUTPUT | MUX_MODE1) /* dmtimer8_pwm_evt (gpio_27) */ + >; + }; + + vibrator_enable_pin: vibrator-enable-pins { + pinctrl-single,pins = < + OMAP4_IOPAD(0X1d0, PIN_OUTPUT | MUX_MODE1) /* dmtimer9_pwm_evt (gpio_28) */ + >; + }; +}; + +/* Configure pwm clock source for timers 8 & 9 */ +&timer8 { + assigned-clocks = <&abe_clkctrl OMAP4_TIMER8_CLKCTRL 24>; + assigned-clock-parents = <&sys_32k_ck>; +}; + +&timer9 { + assigned-clocks = <&l4_per_clkctrl OMAP4_TIMER9_CLKCTRL 24>; + assigned-clock-parents = <&sys_32k_ck>; +}; + +&usbhsohci { + phys = <&fsusb1_phy>; + phy-names = "usb"; +}; + +&usbhsehci { + phys = <&hsusb2_phy>; +}; + +&usbhshost { + port1-mode = "ohci-phy-4pin-dpdm"; + port2-mode = "ehci-tll"; +}; + +&i2c4 { + ak8975: magnetometer@c { + compatible = "asahi-kasei,ak8975"; + reg = <0x0c>; + + vdd-supply = <&vhvio>; + + interrupt-parent = <&gpio6>; + interrupts = <15 IRQ_TYPE_EDGE_RISING>; /* gpio175 */ + + rotation-matrix = "-1", "0", "0", + "0", "1", "0", + "0", "0", "-1"; + + }; +}; diff --git a/arch/arm/boot/dts/ti/omap/motorola-mapphone-mz607-mz617.dtsi b/arch/arm/boot/dts/ti/omap/motorola-mapphone-mz607-mz617.dtsi new file mode 100644 index 00000000000000..a356b3a2f24e94 --- /dev/null +++ b/arch/arm/boot/dts/ti/omap/motorola-mapphone-mz607-mz617.dtsi @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0-only +/dts-v1/; + +#include "motorola-mapphone-common.dtsi" + +&keypad { + keypad,num-rows = <8>; + keypad,num-columns = <8>; + linux,keymap = , + ; +}; + +/* + * On tablets, mmc1 regulator is vsimcard instead of vwlan2 in the stock kernel + * dtb. The regulator may not be wired even if a MMC cage is added though. + */ +&mmc1 { + vmmc-supply = <&vsimcard>; + bus-width = <4>; + cd-gpios = <&gpio6 16 GPIO_ACTIVE_LOW>; /* gpio_176 */ +}; diff --git a/arch/arm/boot/dts/ti/omap/motorola-mapphone-xt8xx.dtsi b/arch/arm/boot/dts/ti/omap/motorola-mapphone-xt8xx.dtsi new file mode 100644 index 00000000000000..8b8de92b5424d7 --- /dev/null +++ b/arch/arm/boot/dts/ti/omap/motorola-mapphone-xt8xx.dtsi @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0-only +/dts-v1/; + +#include "motorola-mapphone-handset.dtsi" + +/ { + backlight: backlight { + compatible = "led-backlight"; + + leds = <&backlight_led>; + brightness-levels = <31 63 95 127 159 191 223 255>; + default-brightness-level = <6>; + }; + + /* LCD regulator from sw5 source */ + lcd_regulator: regulator-lcd { + compatible = "regulator-fixed"; + regulator-name = "lcd"; + regulator-min-microvolt = <5050000>; + regulator-max-microvolt = <5050000>; + gpio = <&gpio4 0 GPIO_ACTIVE_HIGH>; /* gpio96 */ + enable-active-high; + vin-supply = <&sw5>; + }; +}; + +&dsi1 { + status = "okay"; + vdd-supply = <&vcsi>; + + port { + dsi1_out_ep: endpoint { + remote-endpoint = <&lcd0_in>; + lanes = <0 1 2 3 4 5>; + }; + }; + + lcd0: panel@0 { + compatible = "motorola,droid4-panel", "panel-dsi-cm"; + reg = <0>; + label = "lcd0"; + vddi-supply = <&lcd_regulator>; + reset-gpios = <&gpio4 5 GPIO_ACTIVE_HIGH>; /* gpio101 */ + backlight = <&backlight>; + + width-mm = <50>; + height-mm = <89>; + rotation = <90>; + + panel-timing { + clock-frequency = <0>; /* Calculated by dsi */ + + hback-porch = <2>; + hactive = <540>; + hfront-porch = <0>; + hsync-len = <2>; + + vback-porch = <1>; + vactive = <960>; + vfront-porch = <0>; + vsync-len = <1>; + + hsync-active = <0>; + vsync-active = <0>; + de-active = <1>; + pixelclk-active = <1>; + }; + + port { + lcd0_in: endpoint { + remote-endpoint = <&dsi1_out_ep>; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/ti/omap/omap4-droid-bionic-xt875.dts b/arch/arm/boot/dts/ti/omap/omap4-droid-bionic-xt875.dts index ccf03a743678f6..1d9000f84f1b41 100644 --- a/arch/arm/boot/dts/ti/omap/omap4-droid-bionic-xt875.dts +++ b/arch/arm/boot/dts/ti/omap/omap4-droid-bionic-xt875.dts @@ -1,11 +1,20 @@ // SPDX-License-Identifier: GPL-2.0-only /dts-v1/; -#include "motorola-mapphone-common.dtsi" +#include "motorola-mapphone-xt8xx.dtsi" / { model = "Motorola Droid Bionic XT875"; compatible = "motorola,droid-bionic", "ti,omap4430", "ti,omap4"; + + chosen { + stdout-path = &uart3; + }; + + aliases { + display0 = &lcd0; + display1 = &hdmi0; + }; }; &keypad { diff --git a/arch/arm/boot/dts/ti/omap/omap4-droid4-xt894.dts b/arch/arm/boot/dts/ti/omap/omap4-droid4-xt894.dts index e833c21f1c0149..cc3f3e1b65ea98 100644 --- a/arch/arm/boot/dts/ti/omap/omap4-droid4-xt894.dts +++ b/arch/arm/boot/dts/ti/omap/omap4-droid4-xt894.dts @@ -1,9 +1,21 @@ // SPDX-License-Identifier: GPL-2.0-only /dts-v1/; -#include "motorola-mapphone-common.dtsi" +#include "motorola-mapphone-xt8xx.dtsi" / { + model = "Motorola Droid 4 XT894"; + compatible = "motorola,droid4", "ti,omap4430", "ti,omap4"; + + chosen { + stdout-path = &uart3; + }; + + aliases { + display0 = &lcd0; + display1 = &hdmi0; + }; + gpio_keys { compatible = "gpio-keys"; @@ -33,11 +45,6 @@ }; }; -/ { - model = "Motorola Droid 4 XT894"; - compatible = "motorola,droid4", "ti,omap4430", "ti,omap4"; -}; - &keypad { keypad,num-rows = <8>; keypad,num-columns = <8>; diff --git a/arch/arm/boot/dts/ti/omap/omap4-epson-embt2ws.dts b/arch/arm/boot/dts/ti/omap/omap4-epson-embt2ws.dts index 01d783826d5fca..24f7d0285f7995 100644 --- a/arch/arm/boot/dts/ti/omap/omap4-epson-embt2ws.dts +++ b/arch/arm/boot/dts/ti/omap/omap4-epson-embt2ws.dts @@ -51,6 +51,12 @@ regulator-name = "unknown"; }; + wl12xx_pwrseq: wl12xx-pwrseq { + compatible = "mmc-pwrseq-simple"; + clocks = <&twl 1>; + clock-names = "ext_clock"; + }; + /* regulator for wl12xx on sdio2 */ wl12xx_vmmc: wl12xx-vmmc { pinctrl-names = "default"; @@ -74,6 +80,7 @@ twl: pmic@48 { compatible = "ti,twl6032"; reg = <0x48>; + #clock-cells = <1>; /* IRQ# = 7 */ interrupts = ; /* IRQ_SYS_1N cascaded to gic */ interrupt-controller; @@ -294,6 +301,7 @@ pinctrl-names = "default"; pinctrl-0 = <&wl12xx_pins>; vmmc-supply = <&wl12xx_vmmc>; + mmc-pwrseq = <&wl12xx_pwrseq>; interrupts-extended = <&wakeupgen GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH &omap4_pmx_core 0x12e>; non-removable; @@ -454,10 +462,12 @@ interrupts-extended = <&wakeupgen GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH &omap4_pmx_core OMAP4_UART2_RX>; - /* - * BT + GPS in WL1283 in WG7500 requiring CLK32KAUDIO of pmic - * which does not have a driver - */ + bluetooth-gnss { + compatible = "ti,wl1283-st"; + enable-gpios = <&gpio1 25 GPIO_ACTIVE_HIGH>; /* GPIO_25 */ + clocks = <&twl 1>; + clock-names = "ext_clock"; + }; }; &uart3 { diff --git a/arch/arm/boot/dts/ti/omap/omap4-xyboard-mz609.dts b/arch/arm/boot/dts/ti/omap/omap4-xyboard-mz609.dts new file mode 100644 index 00000000000000..762934e2d0752e --- /dev/null +++ b/arch/arm/boot/dts/ti/omap/omap4-xyboard-mz609.dts @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0-only +/dts-v1/; + +#include "motorola-mapphone-mz607-mz617.dtsi" + +/ { + model = "Motorola Xyboard MZ609"; + compatible = "motorola,xyboard-mz609", "ti,omap4430", "ti,omap4"; + + chosen { + stdout-path = &uart3; + }; + + aliases { + display1 = &hdmi0; + }; + + backlight: backlight { + compatible = "led-backlight"; + + leds = <&backlight_led>; + brightness-levels = <31 63 95 127 159 191 223 255>; + default-brightness-level = <6>; + }; +}; + +&i2c1 { + led-controller@38 { + compatible = "ti,lm3532"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x38>; + + enable-gpios = <&gpio6 12 GPIO_ACTIVE_HIGH>; + + ramp-up-us = <1024>; + ramp-down-us = <8193>; + + backlight_led: led@0 { + reg = <0>; + led-sources = <2>; + ti,led-mode = <0>; + label = ":backlight"; + }; + }; +}; diff --git a/arch/arm/boot/dts/ti/omap/omap4-xyboard-mz617.dts b/arch/arm/boot/dts/ti/omap/omap4-xyboard-mz617.dts new file mode 100644 index 00000000000000..b9caea3b7f9d15 --- /dev/null +++ b/arch/arm/boot/dts/ti/omap/omap4-xyboard-mz617.dts @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0-only +/dts-v1/; + +#include "motorola-mapphone-mz607-mz617.dtsi" + +/ { + model = "Motorola Xyboard MZ617"; + compatible = "motorola,xyboard-mz617", "ti,omap4430", "ti,omap4"; + + chosen { + stdout-path = &uart3; + }; + + aliases { + display1 = &hdmi0; + }; +}; diff --git a/arch/arm/common/locomo.c b/arch/arm/common/locomo.c index 70480dd9e96db2..6d0c9f7268bad2 100644 --- a/arch/arm/common/locomo.c +++ b/arch/arm/common/locomo.c @@ -68,6 +68,8 @@ struct locomo { #endif }; +static const struct bus_type locomo_bus_type; + struct locomo_dev_info { unsigned long offset; unsigned long length; @@ -842,7 +844,7 @@ static void locomo_bus_remove(struct device *dev) drv->remove(ldev); } -struct bus_type locomo_bus_type = { +static const struct bus_type locomo_bus_type = { .name = "locomo-bus", .match = locomo_match, .probe = locomo_bus_probe, diff --git a/arch/arm/configs/am200epdkit_defconfig b/arch/arm/configs/am200epdkit_defconfig index a25834e4c90155..134a559aba3dd5 100644 --- a/arch/arm/configs/am200epdkit_defconfig +++ b/arch/arm/configs/am200epdkit_defconfig @@ -1,6 +1,5 @@ CONFIG_LOCALVERSION="gum" CONFIG_SYSVIPC=y -CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_PREEMPT=y CONFIG_EXPERT=y # CONFIG_EPOLL is not set @@ -49,7 +48,6 @@ CONFIG_BLK_DEV_SD=m CONFIG_ATA=m CONFIG_PATA_PCMCIA=m CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y CONFIG_SMC91X=m # CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_PXA=y diff --git a/arch/arm/configs/aspeed_g4_defconfig b/arch/arm/configs/aspeed_g4_defconfig index 9d1b297c432eec..b3dc0465796f9a 100644 --- a/arch/arm/configs/aspeed_g4_defconfig +++ b/arch/arm/configs/aspeed_g4_defconfig @@ -12,11 +12,12 @@ CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_BZIP2 is not set # CONFIG_RD_LZO is not set # CONFIG_RD_LZ4 is not set +CONFIG_EXPERT=y # CONFIG_UID16 is not set # CONFIG_SYSFS_SYSCALL is not set # CONFIG_AIO is not set -CONFIG_EXPERT=y CONFIG_PERF_EVENTS=y +CONFIG_KEXEC=y # CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_ASPEED=y CONFIG_MACH_ASPEED_G4=y @@ -24,7 +25,6 @@ CONFIG_VMSPLIT_2G=y CONFIG_AEABI=y CONFIG_UACCESS_WITH_MEMCPY=y # CONFIG_ATAGS is not set -CONFIG_KEXEC=y CONFIG_JUMP_LABEL=y CONFIG_STRICT_KERNEL_RWX=y # CONFIG_BLK_DEBUG_FS is not set diff --git a/arch/arm/configs/aspeed_g5_defconfig b/arch/arm/configs/aspeed_g5_defconfig index b55f8f539c5fc6..3fdf4dbfdea5db 100644 --- a/arch/arm/configs/aspeed_g5_defconfig +++ b/arch/arm/configs/aspeed_g5_defconfig @@ -12,11 +12,12 @@ CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_BZIP2 is not set # CONFIG_RD_LZO is not set # CONFIG_RD_LZ4 is not set +CONFIG_EXPERT=y # CONFIG_UID16 is not set # CONFIG_SYSFS_SYSCALL is not set # CONFIG_AIO is not set -CONFIG_EXPERT=y CONFIG_PERF_EVENTS=y +CONFIG_KEXEC=y CONFIG_ARCH_MULTI_V6=y CONFIG_ARCH_ASPEED=y CONFIG_MACH_ASPEED_G5=y @@ -29,7 +30,6 @@ CONFIG_NR_CPUS=2 CONFIG_HIGHMEM=y CONFIG_UACCESS_WITH_MEMCPY=y # CONFIG_ATAGS is not set -CONFIG_KEXEC=y CONFIG_VFP=y CONFIG_NEON=y CONFIG_KERNEL_MODE_NEON=y diff --git a/arch/arm/configs/assabet_defconfig b/arch/arm/configs/assabet_defconfig index 8ba8eb7a4adf21..07ab9eaac4af1c 100644 --- a/arch/arm/configs/assabet_defconfig +++ b/arch/arm/configs/assabet_defconfig @@ -28,7 +28,6 @@ CONFIG_MTD_SA1100=y CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_RAM=y CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y CONFIG_NET_PCMCIA=y CONFIG_PCMCIA_PCNET=y CONFIG_INPUT_EVDEV=y diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig index 71b5acc7818792..1d53aec4c8361b 100644 --- a/arch/arm/configs/at91_dt_defconfig +++ b/arch/arm/configs/at91_dt_defconfig @@ -6,8 +6,9 @@ CONFIG_LOG_BUF_SHIFT=14 CONFIG_CGROUPS=y CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y -CONFIG_KALLSYMS_ALL=y CONFIG_EXPERT=y +CONFIG_KALLSYMS_ALL=y +CONFIG_KEXEC=y CONFIG_ARCH_MULTI_V4T=y CONFIG_ARCH_MULTI_V5=y # CONFIG_ARCH_MULTI_V7 is not set @@ -22,7 +23,6 @@ CONFIG_UACCESS_WITH_MEMCPY=y CONFIG_ARM_APPENDED_DTB=y CONFIG_ARM_ATAG_DTB_COMPAT=y CONFIG_CMDLINE="console=ttyS0,115200 initrd=0x21100000,25165824 root=/dev/ram0 rw" -CONFIG_KEXEC=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set diff --git a/arch/arm/configs/bcm2835_defconfig b/arch/arm/configs/bcm2835_defconfig index 225a16c0323c8c..b5f0bd8dd53699 100644 --- a/arch/arm/configs/bcm2835_defconfig +++ b/arch/arm/configs/bcm2835_defconfig @@ -18,17 +18,17 @@ CONFIG_SCHED_AUTOGROUP=y CONFIG_RELAY=y CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y -CONFIG_KALLSYMS_ALL=y CONFIG_EXPERT=y +CONFIG_KALLSYMS_ALL=y CONFIG_PROFILING=y CONFIG_CC_STACKPROTECTOR_REGULAR=y +CONFIG_CRASH_DUMP=y CONFIG_ARCH_MULTI_V6=y CONFIG_ARCH_BCM=y CONFIG_ARCH_BCM2835=y CONFIG_AEABI=y CONFIG_SECCOMP=y CONFIG_KEXEC=y -CONFIG_CRASH_DUMP=y CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_STAT=y CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE=y diff --git a/arch/arm/configs/clps711x_defconfig b/arch/arm/configs/clps711x_defconfig index d7ed1e7c6a90c7..6fa3477e6b026d 100644 --- a/arch/arm/configs/clps711x_defconfig +++ b/arch/arm/configs/clps711x_defconfig @@ -6,15 +6,8 @@ CONFIG_RD_LZMA=y CONFIG_EXPERT=y CONFIG_JUMP_LABEL=y CONFIG_PARTITION_ADVANCED=y -CONFIG_ARCH_CLPS711X=y -CONFIG_ARCH_AUTCPU12=y -CONFIG_ARCH_CDB89712=y -CONFIG_ARCH_CLEP7312=y -CONFIG_ARCH_EDB7211=y -CONFIG_ARCH_P720T=y CONFIG_AEABI=y # CONFIG_COREDUMP is not set -CONFIG_SLUB=y CONFIG_SLUB_TINY=y CONFIG_NET=y CONFIG_PACKET=y diff --git a/arch/arm/configs/collie_defconfig b/arch/arm/configs/collie_defconfig index 69341c33e0cc67..01b5a5a73f0371 100644 --- a/arch/arm/configs/collie_defconfig +++ b/arch/arm/configs/collie_defconfig @@ -13,7 +13,6 @@ CONFIG_CMDLINE="noinitrd root=/dev/mtdblock2 rootfstype=jffs2 fbcon=rotate:1" CONFIG_FPE_NWFPE=y CONFIG_PM=y # CONFIG_SWAP is not set -CONFIG_SLUB=y CONFIG_SLUB_TINY=y CONFIG_NET=y CONFIG_PACKET=y @@ -60,9 +59,9 @@ CONFIG_MCP_SA11X0=y CONFIG_MCP_UCB1200=y CONFIG_MCP_UCB1200_TS=y CONFIG_FB=y -CONFIG_FB_MODE_HELPERS=y CONFIG_FB_SA1100=y # CONFIG_VGA_CONSOLE is not set +CONFIG_FB_MODE_HELPERS=y CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y CONFIG_NEW_LEDS=y diff --git a/arch/arm/configs/davinci_all_defconfig b/arch/arm/configs/davinci_all_defconfig index 05ea71778ef876..3474e475373ae8 100644 --- a/arch/arm/configs/davinci_all_defconfig +++ b/arch/arm/configs/davinci_all_defconfig @@ -148,8 +148,8 @@ CONFIG_DRM_SIMPLE_BRIDGE=m CONFIG_DRM_TINYDRM=m CONFIG_TINYDRM_ST7586=m CONFIG_FB=y -CONFIG_FIRMWARE_EDID=y CONFIG_FB_DA8XX=y +CONFIG_FIRMWARE_EDID=y CONFIG_BACKLIGHT_PWM=m CONFIG_BACKLIGHT_GPIO=m CONFIG_FRAMEBUFFER_CONSOLE=y diff --git a/arch/arm/configs/dove_defconfig b/arch/arm/configs/dove_defconfig index 46859e6fee5ba8..2849d17f585660 100644 --- a/arch/arm/configs/dove_defconfig +++ b/arch/arm/configs/dove_defconfig @@ -6,9 +6,7 @@ CONFIG_EXPERT=y # CONFIG_ARCH_MULTI_V6 is not set CONFIG_ARCH_MULTI_V7=y CONFIG_ARCH_DOVE=y -CONFIG_MACH_DOVE_DB=y CONFIG_MACH_CM_A510=y -CONFIG_MACH_DOVE_DT=y CONFIG_AEABI=y CONFIG_HIGHMEM=y CONFIG_ARM_APPENDED_DTB=y diff --git a/arch/arm/configs/ep93xx_defconfig b/arch/arm/configs/ep93xx_defconfig index 44e89a980d29d1..7dece9d9882880 100644 --- a/arch/arm/configs/ep93xx_defconfig +++ b/arch/arm/configs/ep93xx_defconfig @@ -78,8 +78,8 @@ CONFIG_SPI_EP93XX=y CONFIG_WATCHDOG=y CONFIG_EP93XX_WATCHDOG=y CONFIG_FB=y -CONFIG_FB_MODE_HELPERS=y CONFIG_FB_EP93XX=y +CONFIG_FB_MODE_HELPERS=y CONFIG_LOGO=y CONFIG_USB=y CONFIG_USB_DYNAMIC_MINORS=y diff --git a/arch/arm/configs/footbridge_defconfig b/arch/arm/configs/footbridge_defconfig index c9f4594b7ca97a..5f6963687ee4f0 100644 --- a/arch/arm/configs/footbridge_defconfig +++ b/arch/arm/configs/footbridge_defconfig @@ -55,7 +55,6 @@ CONFIG_BLK_DEV_LOOP=m CONFIG_BLK_DEV_NBD=m CONFIG_BLK_DEV_RAM=y CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y CONFIG_NET_VENDOR_3COM=y CONFIG_VORTEX=y CONFIG_NET_PCI=y diff --git a/arch/arm/configs/gemini_defconfig b/arch/arm/configs/gemini_defconfig index 592a6e6024d484..7b1daec630cbe0 100644 --- a/arch/arm/configs/gemini_defconfig +++ b/arch/arm/configs/gemini_defconfig @@ -7,13 +7,13 @@ CONFIG_BSD_PROCESS_ACCT=y CONFIG_USER_NS=y CONFIG_RELAY=y CONFIG_BLK_DEV_INITRD=y +CONFIG_KEXEC=y CONFIG_ARCH_MULTI_V4=y # CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_GEMINI=y CONFIG_AEABI=y CONFIG_HIGHMEM=y CONFIG_CMDLINE="console=ttyS0,115200n8" -CONFIG_KEXEC=y CONFIG_PM=y CONFIG_PARTITION_ADVANCED=y CONFIG_BINFMT_MISC=y diff --git a/arch/arm/configs/imx_v4_v5_defconfig b/arch/arm/configs/imx_v4_v5_defconfig index ec45e622522545..875c8cdbada7d6 100644 --- a/arch/arm/configs/imx_v4_v5_defconfig +++ b/arch/arm/configs/imx_v4_v5_defconfig @@ -12,11 +12,6 @@ CONFIG_ARCH_MULTI_V4T=y CONFIG_ARCH_MULTI_V5=y # CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_MXC=y -CONFIG_MACH_MX21ADS=y -CONFIG_MACH_MX27ADS=y -CONFIG_MACH_MX27_3DS=y -CONFIG_MACH_IMX27_VISSTRIM_M10=y -CONFIG_MACH_PCA100=y CONFIG_SOC_IMX1=y CONFIG_SOC_IMX25=y CONFIG_SOC_IMX27=y diff --git a/arch/arm/configs/jornada720_defconfig b/arch/arm/configs/jornada720_defconfig index 91bdcc095884e1..e6ec768f42e2cd 100644 --- a/arch/arm/configs/jornada720_defconfig +++ b/arch/arm/configs/jornada720_defconfig @@ -1,6 +1,5 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_ARCH_MULTI_V4=y # CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_SA1100=y @@ -26,7 +25,6 @@ CONFIG_ATA=y CONFIG_PATA_PCMCIA=y CONFIG_NETDEVICES=y CONFIG_DUMMY=y -CONFIG_NET_ETHERNET=y CONFIG_NET_PCMCIA=y CONFIG_INPUT_MOUSEDEV_SCREEN_X=640 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=240 diff --git a/arch/arm/configs/lpc32xx_defconfig b/arch/arm/configs/lpc32xx_defconfig index 42053e45f73047..98e267213b214f 100644 --- a/arch/arm/configs/lpc32xx_defconfig +++ b/arch/arm/configs/lpc32xx_defconfig @@ -5,8 +5,6 @@ CONFIG_PREEMPT=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=16 -CONFIG_SYSFS_DEPRECATED=y -CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_EXPERT=y diff --git a/arch/arm/configs/mmp2_defconfig b/arch/arm/configs/mmp2_defconfig index 3d1d6f3b592a45..f6f9e135353ed4 100644 --- a/arch/arm/configs/mmp2_defconfig +++ b/arch/arm/configs/mmp2_defconfig @@ -2,7 +2,6 @@ CONFIG_SYSVIPC=y CONFIG_HIGH_RES_TIMERS=y CONFIG_PREEMPT=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_SYSFS_DEPRECATED_V2=y # CONFIG_BLK_DEV_BSG is not set CONFIG_ARCH_MMP=y CONFIG_AEABI=y @@ -28,7 +27,6 @@ CONFIG_MTD_ONENAND_GENERIC=y CONFIG_MTD_RAW_NAND=y # CONFIG_BLK_DEV is not set CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y CONFIG_SMC91X=y # CONFIG_INPUT_MOUSEDEV_PSAUX is not set # CONFIG_INPUT_KEYBOARD is not set diff --git a/arch/arm/configs/moxart_defconfig b/arch/arm/configs/moxart_defconfig index bb6a5222e42faf..1d41e73f4903cb 100644 --- a/arch/arm/configs/moxart_defconfig +++ b/arch/arm/configs/moxart_defconfig @@ -4,13 +4,13 @@ CONFIG_NO_HZ_IDLE=y CONFIG_PREEMPT=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y +CONFIG_EXPERT=y # CONFIG_ELF_CORE is not set # CONFIG_BASE_FULL is not set # CONFIG_SIGNALFD is not set # CONFIG_TIMERFD is not set # CONFIG_EVENTFD is not set # CONFIG_AIO is not set -CONFIG_EXPERT=y # CONFIG_BLK_DEV_BSG is not set CONFIG_ARCH_MULTI_V4=y # CONFIG_ARCH_MULTI_V7 is not set @@ -126,8 +126,8 @@ CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y CONFIG_KGDB=y CONFIG_DEBUG_PAGEALLOC=y # CONFIG_SLUB_DEBUG is not set -CONFIG_DEBUG_OBJECTS=y CONFIG_DEBUG_KMEMLEAK=y +CONFIG_DEBUG_OBJECTS=y CONFIG_DEBUG_STACK_USAGE=y CONFIG_DEBUG_MEMORY_INIT=y CONFIG_DEBUG_SHIRQ=y diff --git a/arch/arm/configs/multi_v4t_defconfig b/arch/arm/configs/multi_v4t_defconfig index a7fabf1d88ff7e..27d650635d9b83 100644 --- a/arch/arm/configs/multi_v4t_defconfig +++ b/arch/arm/configs/multi_v4t_defconfig @@ -5,12 +5,12 @@ CONFIG_BLK_DEV_INITRD=y CONFIG_EXPERT=y CONFIG_ARCH_MULTI_V4T=y # CONFIG_ARCH_MULTI_V7 is not set +CONFIG_ARCH_NSPIRE=y CONFIG_ARCH_AT91=y CONFIG_SOC_AT91RM9200=y CONFIG_ARCH_CLPS711X=y CONFIG_ARCH_MXC=y CONFIG_SOC_IMX1=y -CONFIG_ARCH_NSPIRE=y CONFIG_ARCH_INTEGRATOR=y CONFIG_ARCH_INTEGRATOR_AP=y CONFIG_INTEGRATOR_IMPD1=y @@ -25,7 +25,6 @@ CONFIG_ARM_CLPS711X_CPUIDLE=y CONFIG_JUMP_LABEL=y CONFIG_PARTITION_ADVANCED=y # CONFIG_COREDUMP is not set -CONFIG_SLUB=y CONFIG_SLUB_TINY=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y diff --git a/arch/arm/configs/multi_v5_defconfig b/arch/arm/configs/multi_v5_defconfig index 52bb1a5e25fc49..3f4ddcf49ec752 100644 --- a/arch/arm/configs/multi_v5_defconfig +++ b/arch/arm/configs/multi_v5_defconfig @@ -62,8 +62,8 @@ CONFIG_NET_DSA=y CONFIG_NET_PKTGEN=m CONFIG_CFG80211=y CONFIG_MAC80211=y -CONFIG_PCI_MVEBU=y CONFIG_PCI_VERSATILE=y +CONFIG_PCI_MVEBU=y CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y CONFIG_IMX_WEIM=y diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index 10fd74bf85f9b4..ecb3e286107a4c 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -5,8 +5,11 @@ CONFIG_CGROUPS=y CONFIG_BLK_DEV_INITRD=y CONFIG_EXPERT=y CONFIG_PERF_EVENTS=y +CONFIG_KEXEC=y CONFIG_ARCH_VIRT=y CONFIG_ARCH_AIROHA=y +CONFIG_ARCH_SUNPLUS=y +CONFIG_ARCH_UNIPHIER=y CONFIG_ARCH_ACTIONS=y CONFIG_ARCH_ALPINE=y CONFIG_ARCH_ARTPEC=y @@ -96,10 +99,8 @@ CONFIG_MACH_SPEAR1310=y CONFIG_MACH_SPEAR1340=y CONFIG_ARCH_STI=y CONFIG_ARCH_STM32=y -CONFIG_ARCH_SUNPLUS=y CONFIG_ARCH_SUNXI=y CONFIG_ARCH_TEGRA=y -CONFIG_ARCH_UNIPHIER=y CONFIG_ARCH_U8500=y CONFIG_ARCH_VEXPRESS=y CONFIG_ARCH_VEXPRESS_TC2_PM=y @@ -109,7 +110,6 @@ CONFIG_SMP=y CONFIG_NR_CPUS=16 CONFIG_ARM_APPENDED_DTB=y CONFIG_ARM_ATAG_DTB_COMPAT=y -CONFIG_KEXEC=y CONFIG_EFI=y CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_STAT=y @@ -179,10 +179,10 @@ CONFIG_NFC_S3FWRN5_I2C=m CONFIG_PCIEPORTBUS=y CONFIG_PCI_MVEBU=y CONFIG_PCI_TEGRA=y -CONFIG_PCI_RCAR_GEN2=y CONFIG_PCIE_RCAR_HOST=y -CONFIG_PCI_DRA7XX_EP=y +CONFIG_PCI_RCAR_GEN2=y CONFIG_PCI_LAYERSCAPE=y +CONFIG_PCI_DRA7XX_EP=y CONFIG_PCI_ENDPOINT=y CONFIG_PCI_ENDPOINT_CONFIGFS=y CONFIG_PCI_EPF_TEST=m @@ -272,6 +272,7 @@ CONFIG_KS8851=y CONFIG_LAN966X_SWITCH=m CONFIG_R8169=y CONFIG_SH_ETH=y +CONFIG_RAVB=y CONFIG_SMSC911X=y CONFIG_SNI_AVE=y CONFIG_STMMAC_ETH=y @@ -523,6 +524,7 @@ CONFIG_CHARGER_TPS65090=y CONFIG_BATTERY_ACER_A500=m CONFIG_SENSORS_ARM_SCMI=y CONFIG_SENSORS_ASPEED=m +CONFIG_SENSORS_GXP_FAN_CTRL=m CONFIG_SENSORS_IIO_HWMON=y CONFIG_SENSORS_LAN966X=m CONFIG_SENSORS_LM90=y @@ -531,7 +533,6 @@ CONFIG_SENSORS_NTC_THERMISTOR=m CONFIG_SENSORS_PWM_FAN=m CONFIG_SENSORS_RASPBERRYPI_HWMON=m CONFIG_SENSORS_INA2XX=m -CONFIG_SENSORS_GXP_FAN_CTRL=m CONFIG_CPU_THERMAL=y CONFIG_DEVFREQ_THERMAL=y CONFIG_IMX_THERMAL=y @@ -691,6 +692,7 @@ CONFIG_VIDEO_STI_BDISP=m CONFIG_VIDEO_STI_DELTA=m CONFIG_VIDEO_STI_HVA=m CONFIG_VIDEO_STM32_DCMI=m +CONFIG_VIDEO_STM32_DCMIPP=m CONFIG_V4L_TEST_DRIVERS=y CONFIG_VIDEO_VIVID=m CONFIG_VIDEO_S5C73M3=m @@ -1072,6 +1074,7 @@ CONFIG_HWSPINLOCK_QCOM=y CONFIG_OMAP2PLUS_MBOX=y CONFIG_BCM2835_MBOX=y CONFIG_QCOM_APCS_IPC=y +CONFIG_STM32_IPCC=m CONFIG_QCOM_IPCC=y CONFIG_OMAP_IOMMU=y CONFIG_OMAP_IOMMU_DEBUG=y @@ -1087,20 +1090,18 @@ CONFIG_QCOM_Q6V5_MSS=m CONFIG_QCOM_SYSMON=m CONFIG_QCOM_WCNSS_PIL=m CONFIG_ST_REMOTEPROC=m +CONFIG_RPMSG_CHAR=m +CONFIG_RPMSG_CTRL=m CONFIG_RPMSG_QCOM_SMD=y CONFIG_RPMSG_VIRTIO=m CONFIG_ASPEED_LPC_CTRL=m CONFIG_ASPEED_LPC_SNOOP=m CONFIG_ASPEED_P2A_CTRL=m -CONFIG_RASPBERRYPI_POWER=y CONFIG_QCOM_COMMAND_DB=m -CONFIG_QCOM_CPR=y CONFIG_QCOM_GSBI=y CONFIG_QCOM_OCMEM=m CONFIG_QCOM_RMTFS_MEM=m CONFIG_QCOM_RPMH=y -CONFIG_QCOM_RPMHPD=y -CONFIG_QCOM_RPMPD=y CONFIG_QCOM_SMEM=y CONFIG_QCOM_SMD_RPM=y CONFIG_QCOM_SMP2P=y @@ -1128,11 +1129,15 @@ CONFIG_ARCH_R8A7744=y CONFIG_ARCH_R9A06G032=y CONFIG_ARCH_SH73A0=y CONFIG_ROCKCHIP_IODOMAIN=y -CONFIG_ROCKCHIP_PM_DOMAINS=y CONFIG_ARCH_TEGRA_2x_SOC=y CONFIG_ARCH_TEGRA_3x_SOC=y CONFIG_ARCH_TEGRA_114_SOC=y CONFIG_ARCH_TEGRA_124_SOC=y +CONFIG_RASPBERRYPI_POWER=y +CONFIG_QCOM_CPR=y +CONFIG_QCOM_RPMHPD=y +CONFIG_QCOM_RPMPD=y +CONFIG_ROCKCHIP_PM_DOMAINS=y CONFIG_ARM_EXYNOS_BUS_DEVFREQ=m CONFIG_ARM_TEGRA_DEVFREQ=m CONFIG_DEVFREQ_EVENT_EXYNOS_NOCP=m @@ -1191,6 +1196,7 @@ CONFIG_PWM_TEGRA=y CONFIG_PWM_VT8500=y CONFIG_KEYSTONE_IRQ=y CONFIG_RESET_MCHP_SPARX5=y +CONFIG_RESET_SCMI=y CONFIG_PHY_SUN4I_USB=y CONFIG_PHY_SUN9I_USB=y CONFIG_PHY_BRCM_USB=m @@ -1240,8 +1246,8 @@ CONFIG_OPTEE=y CONFIG_INTERCONNECT_QCOM=y CONFIG_INTERCONNECT_QCOM_MSM8916=y CONFIG_COUNTER=m -CONFIG_STM32_TIMER_CNT=m CONFIG_STM32_LPTIMER_CNT=m +CONFIG_STM32_TIMER_CNT=m CONFIG_EXT4_FS=y CONFIG_AUTOFS_FS=y CONFIG_MSDOS_FS=y diff --git a/arch/arm/configs/mv78xx0_defconfig b/arch/arm/configs/mv78xx0_defconfig index 4ed6e8c8e164d0..3343f72de7ea89 100644 --- a/arch/arm/configs/mv78xx0_defconfig +++ b/arch/arm/configs/mv78xx0_defconfig @@ -3,7 +3,6 @@ CONFIG_NO_HZ_IDLE=y CONFIG_HIGH_RES_TIMERS=y CONFIG_PREEMPT=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y CONFIG_PROFILING=y @@ -52,7 +51,6 @@ CONFIG_CHR_DEV_SG=m CONFIG_ATA=y CONFIG_SATA_MV=y CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y CONFIG_MII=y CONFIG_NET_PCI=y CONFIG_MV643XX_ETH=y diff --git a/arch/arm/configs/mxs_defconfig b/arch/arm/configs/mxs_defconfig index feb38a94c1a70a..43bc1255a5db9f 100644 --- a/arch/arm/configs/mxs_defconfig +++ b/arch/arm/configs/mxs_defconfig @@ -138,7 +138,8 @@ CONFIG_PWM_MXS=y CONFIG_NVMEM_MXS_OCOTP=y CONFIG_EXT4_FS=y # CONFIG_DNOTIFY is not set -CONFIG_FSCACHE=m +CONFIG_NETFS_SUPPORT=m +CONFIG_FSCACHE=y CONFIG_FSCACHE_STATS=y CONFIG_CACHEFILES=m CONFIG_VFAT_FS=y diff --git a/arch/arm/configs/neponset_defconfig b/arch/arm/configs/neponset_defconfig index c333406ce5e3ff..2227f86100ad25 100644 --- a/arch/arm/configs/neponset_defconfig +++ b/arch/arm/configs/neponset_defconfig @@ -38,7 +38,6 @@ CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_SCSI=m CONFIG_BLK_DEV_SD=m CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y CONFIG_NET_VENDOR_SMC=y CONFIG_PCMCIA_PCNET=y CONFIG_SMC9194=y diff --git a/arch/arm/configs/netwinder_defconfig b/arch/arm/configs/netwinder_defconfig index 30ff6fbce5a348..e639e6ad02cb89 100644 --- a/arch/arm/configs/netwinder_defconfig +++ b/arch/arm/configs/netwinder_defconfig @@ -27,7 +27,6 @@ CONFIG_BLK_DEV_SD=y CONFIG_ATA=y CONFIG_PATA_WINBOND=y CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y CONFIG_MII=y CONFIG_NET_TULIP=y CONFIG_TULIP=y diff --git a/arch/arm/configs/omap1_defconfig b/arch/arm/configs/omap1_defconfig index 7c2cc7a89511a6..729ea8157e2a57 100644 --- a/arch/arm/configs/omap1_defconfig +++ b/arch/arm/configs/omap1_defconfig @@ -28,7 +28,6 @@ CONFIG_MACH_OMAP_PALMTE=y CONFIG_MACH_SX1=y CONFIG_MACH_NOKIA770=y CONFIG_MACH_AMS_DELTA=y -CONFIG_MACH_OMAP_GENERIC=y CONFIG_AEABI=y CONFIG_CMDLINE="root=1f03 rootfstype=jffs2" CONFIG_FPE_NWFPE=y @@ -40,7 +39,6 @@ CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_PARTITION_ADVANCED=y CONFIG_BINFMT_MISC=y # CONFIG_SWAP is not set -CONFIG_SLUB=y CONFIG_SLUB_TINY=y # CONFIG_VM_EVENT_COUNTERS is not set CONFIG_NET=y @@ -132,14 +130,14 @@ CONFIG_WATCHDOG=y CONFIG_WATCHDOG_NOWAYOUT=y CONFIG_OMAP_WATCHDOG=y CONFIG_FB=y -CONFIG_FIRMWARE_EDID=y -CONFIG_FB_MODE_HELPERS=y CONFIG_FB_VIRTUAL=y CONFIG_FB_OMAP=y CONFIG_FB_OMAP_LCDC_EXTERNAL=y CONFIG_FB_OMAP_LCDC_HWA742=y CONFIG_FB_OMAP_MANUAL_UPDATE=y CONFIG_FB_OMAP_LCD_MIPID=y +CONFIG_FIRMWARE_EDID=y +CONFIG_FB_MODE_HELPERS=y CONFIG_LCD_CLASS_DEVICE=y CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig index 7b1b41b4b16093..3a166c2f02bd80 100644 --- a/arch/arm/configs/omap2plus_defconfig +++ b/arch/arm/configs/omap2plus_defconfig @@ -607,6 +607,7 @@ CONFIG_LEDS_LP55XX_COMMON=m CONFIG_LEDS_LP5523=m CONFIG_LEDS_PCA963X=m CONFIG_LEDS_PWM=m +CONFIG_LEDS_BD2606MVV=m CONFIG_LEDS_TRIGGERS=y CONFIG_LEDS_TRIGGER_TIMER=m CONFIG_LEDS_TRIGGER_ONESHOT=m @@ -624,6 +625,7 @@ CONFIG_RTC_DRV_PALMAS=m CONFIG_RTC_DRV_OMAP=m CONFIG_RTC_DRV_CPCAP=m CONFIG_DMADEVICES=y +CONFIG_CLK_TWL=m CONFIG_CLK_TWL6040=m CONFIG_COMMON_CLK_PALMAS=m CONFIG_OMAP_IOMMU=y @@ -646,6 +648,9 @@ CONFIG_CPCAP_ADC=m CONFIG_INA2XX_ADC=m CONFIG_TI_AM335X_ADC=m CONFIG_TWL4030_MADC=m +CONFIG_TWL6030_GPADC=m +CONFIG_MPU3050_I2C=m +CONFIG_INV_MPU6050_I2C=m CONFIG_SENSORS_ISL29028=m CONFIG_AK8975=m CONFIG_BMP280=m diff --git a/arch/arm/configs/pxa168_defconfig b/arch/arm/configs/pxa168_defconfig index ec3a43f9c85ea8..ce10fe2104bf1e 100644 --- a/arch/arm/configs/pxa168_defconfig +++ b/arch/arm/configs/pxa168_defconfig @@ -1,5 +1,4 @@ CONFIG_SYSVIPC=y -CONFIG_SYSFS_DEPRECATED_V2=y # CONFIG_BLK_DEV_BSG is not set CONFIG_NO_HZ_IDLE=y CONFIG_HIGH_RES_TIMERS=y @@ -22,7 +21,6 @@ CONFIG_IP_PNP=y # CONFIG_PREVENT_FIRMWARE_BUILD is not set # CONFIG_BLK_DEV is not set CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y CONFIG_SMC91X=y # CONFIG_INPUT_MOUSEDEV_PSAUX is not set # CONFIG_INPUT_KEYBOARD is not set diff --git a/arch/arm/configs/pxa3xx_defconfig b/arch/arm/configs/pxa3xx_defconfig index 7f95fa273a7d7f..381356faf38251 100644 --- a/arch/arm/configs/pxa3xx_defconfig +++ b/arch/arm/configs/pxa3xx_defconfig @@ -1,7 +1,6 @@ CONFIG_SYSVIPC=y CONFIG_PREEMPT=y CONFIG_LOG_BUF_SHIFT=18 -CONFIG_SYSFS_DEPRECATED_V2=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_KALLSYMS_ALL=y # CONFIG_BLK_DEV_BSG is not set @@ -34,7 +33,6 @@ CONFIG_MTD_NAND_MARVELL=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y CONFIG_SMC91X=y # CONFIG_INPUT_MOUSEDEV_PSAUX is not set # CONFIG_KEYBOARD_ATKBD is not set diff --git a/arch/arm/configs/pxa910_defconfig b/arch/arm/configs/pxa910_defconfig index 958d958377dca5..1f28aea860146f 100644 --- a/arch/arm/configs/pxa910_defconfig +++ b/arch/arm/configs/pxa910_defconfig @@ -3,7 +3,6 @@ CONFIG_NO_HZ_IDLE=y CONFIG_HIGH_RES_TIMERS=y CONFIG_PREEMPT=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_BLK_DEV_INITRD=y CONFIG_ARCH_MMP=y CONFIG_CMDLINE="root=/dev/nfs rootfstype=nfs nfsroot=192.168.2.100:/nfsroot/ ip=192.168.2.101:192.168.2.100::255.255.255.0::eth0:on console=ttyS0,115200 mem=128M earlyprintk" @@ -23,7 +22,6 @@ CONFIG_IP_PNP=y # CONFIG_PREVENT_FIRMWARE_BUILD is not set # CONFIG_BLK_DEV is not set CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y CONFIG_SMC91X=y # CONFIG_INPUT_MOUSEDEV_PSAUX is not set # CONFIG_INPUT_KEYBOARD is not set diff --git a/arch/arm/configs/pxa_defconfig b/arch/arm/configs/pxa_defconfig index 9e81b1849e4c3a..f2ca5c9131b52f 100644 --- a/arch/arm/configs/pxa_defconfig +++ b/arch/arm/configs/pxa_defconfig @@ -10,9 +10,10 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=13 CONFIG_BLK_DEV_INITRD=y -CONFIG_KALLSYMS_ALL=y CONFIG_EXPERT=y +CONFIG_KALLSYMS_ALL=y CONFIG_PROFILING=y +CONFIG_KEXEC=y # CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_PXA=y CONFIG_ARCH_GUMSTIX=y @@ -22,7 +23,6 @@ CONFIG_MACH_BORZOI=y CONFIG_AEABI=y CONFIG_ARCH_FORCE_MAX_ORDER=8 CONFIG_CMDLINE="root=/dev/ram0 ro" -CONFIG_KEXEC=y CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_STAT=y CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y @@ -44,7 +44,6 @@ CONFIG_PARTITION_ADVANCED=y CONFIG_LDM_PARTITION=y CONFIG_CMDLINE_PARTITION=y CONFIG_BINFMT_MISC=y -CONFIG_SLUB=y CONFIG_SLUB_TINY=y # CONFIG_COMPACTION is not set CONFIG_NET=y @@ -380,8 +379,6 @@ CONFIG_V4L_MEM2MEM_DRIVERS=y CONFIG_VIDEO_PXA27x=m CONFIG_DRM=m CONFIG_FB=y -CONFIG_FIRMWARE_EDID=y -CONFIG_FB_TILEBLITTING=y CONFIG_FB_PXA=y CONFIG_FB_PXA_OVERLAY=y CONFIG_FB_PXA_PARAMETERS=y @@ -393,6 +390,8 @@ CONFIG_LCD_CORGI=m CONFIG_LCD_PLATFORM=m CONFIG_BACKLIGHT_PWM=m CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FIRMWARE_EDID=y +CONFIG_FB_TILEBLITTING=y CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y CONFIG_LOGO=y CONFIG_SOUND=m diff --git a/arch/arm/configs/qcom_defconfig b/arch/arm/configs/qcom_defconfig index 737d51412eb24b..ec52ccece0ca7d 100644 --- a/arch/arm/configs/qcom_defconfig +++ b/arch/arm/configs/qcom_defconfig @@ -6,8 +6,8 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_CGROUPS=y CONFIG_BLK_DEV_INITRD=y -CONFIG_KALLSYMS_ALL=y CONFIG_EXPERT=y +CONFIG_KALLSYMS_ALL=y CONFIG_PROFILING=y CONFIG_ARCH_QCOM=y CONFIG_ARCH_MSM8X60=y @@ -139,11 +139,11 @@ CONFIG_PINCTRL_MDM9615=y CONFIG_PINCTRL_MSM8X74=y CONFIG_PINCTRL_MSM8909=y CONFIG_PINCTRL_MSM8916=y -CONFIG_PINCTRL_QCOM_SPMI_PMIC=y -CONFIG_PINCTRL_QCOM_SSBI_PMIC=y CONFIG_GPIOLIB=y CONFIG_PINCTRL_SDX55=y CONFIG_PINCTRL_SDX65=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y +CONFIG_PINCTRL_QCOM_SSBI_PMIC=y CONFIG_GPIO_SYSFS=y CONFIG_POWER_RESET=y CONFIG_POWER_RESET_MSM=y @@ -259,8 +259,6 @@ CONFIG_QCOM_OCMEM=y CONFIG_QCOM_PM=y CONFIG_QCOM_RMTFS_MEM=y CONFIG_QCOM_RPMH=y -CONFIG_QCOM_RPMHPD=y -CONFIG_QCOM_RPMPD=y CONFIG_QCOM_SMEM=y CONFIG_QCOM_SMD_RPM=y CONFIG_QCOM_SMP2P=y @@ -268,6 +266,8 @@ CONFIG_QCOM_SMSM=y CONFIG_QCOM_SOCINFO=y CONFIG_QCOM_STATS=y CONFIG_QCOM_WCNSS_CTRL=y +CONFIG_QCOM_RPMHPD=y +CONFIG_QCOM_RPMPD=y CONFIG_EXTCON_QCOM_SPMI_MISC=y CONFIG_IIO=y CONFIG_IIO_BUFFER_CB=y diff --git a/arch/arm/configs/realview_defconfig b/arch/arm/configs/realview_defconfig index a221a99f647205..febea5cf7aaa9e 100644 --- a/arch/arm/configs/realview_defconfig +++ b/arch/arm/configs/realview_defconfig @@ -9,8 +9,6 @@ CONFIG_MACH_REALVIEW_EB=y CONFIG_REALVIEW_EB_ARM1136=y CONFIG_REALVIEW_EB_ARM1176=y CONFIG_REALVIEW_EB_A9MP=y -CONFIG_REALVIEW_EB_ARM11MP=y -CONFIG_MACH_REALVIEW_PB11MP=y CONFIG_MACH_REALVIEW_PB1176=y CONFIG_MACH_REALVIEW_PBA8=y CONFIG_MACH_REALVIEW_PBX=y @@ -58,6 +56,8 @@ CONFIG_GPIOLIB=y # CONFIG_HWMON is not set CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_AUXDISPLAY=y +CONFIG_ARM_CHARLCD=y CONFIG_DRM=y CONFIG_DRM_PANEL_SIMPLE=y CONFIG_DRM_PANEL_EDP=y @@ -85,8 +85,6 @@ CONFIG_LEDS_TRIGGER_CPU=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_DS1307=y CONFIG_RTC_DRV_PL031=y -CONFIG_AUXDISPLAY=y -CONFIG_ARM_CHARLCD=y CONFIG_VFAT_FS=y CONFIG_TMPFS=y CONFIG_CRAMFS=y diff --git a/arch/arm/configs/rpc_defconfig b/arch/arm/configs/rpc_defconfig index b1d12a2c2ef8e1..24f1fa86823080 100644 --- a/arch/arm/configs/rpc_defconfig +++ b/arch/arm/configs/rpc_defconfig @@ -2,13 +2,13 @@ CONFIG_SYSVIPC=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y CONFIG_ARCH_MULTI_V4=y # CONFIG_ARCH_MULTI_V7 is not set CONFIG_ARCH_RPC=y CONFIG_CPU_SA110=y CONFIG_FPE_NWFPE=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y CONFIG_PARTITION_ADVANCED=y CONFIG_BSD_DISKLABEL=y CONFIG_NET=y @@ -45,7 +45,6 @@ CONFIG_ATA=y CONFIG_PATA_ICSIDE=y CONFIG_PATA_PLATFORM=y CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y CONFIG_ARM_ETHER1=y CONFIG_ARM_ETHER3=y CONFIG_ARM_ETHERH=y diff --git a/arch/arm/configs/s3c6400_defconfig b/arch/arm/configs/s3c6400_defconfig index 93258d5b57ff41..a37e6ac4082519 100644 --- a/arch/arm/configs/s3c6400_defconfig +++ b/arch/arm/configs/s3c6400_defconfig @@ -1,5 +1,3 @@ -CONFIG_SYSFS_DEPRECATED=y -CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_BLK_DEV_INITRD=y CONFIG_KALLSYMS_ALL=y CONFIG_ARCH_MULTI_V6=y diff --git a/arch/arm/configs/s5pv210_defconfig b/arch/arm/configs/s5pv210_defconfig index d280169081bd9a..5dbe85c263de3c 100644 --- a/arch/arm/configs/s5pv210_defconfig +++ b/arch/arm/configs/s5pv210_defconfig @@ -3,8 +3,6 @@ CONFIG_NO_HZ_IDLE=y CONFIG_HIGH_RES_TIMERS=y CONFIG_PREEMPT=y CONFIG_CGROUPS=y -CONFIG_SYSFS_DEPRECATED=y -CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_BLK_DEV_INITRD=y CONFIG_KALLSYMS_ALL=y CONFIG_ARCH_S5PV210=y diff --git a/arch/arm/configs/sama5_defconfig b/arch/arm/configs/sama5_defconfig index 0e030063130fae..9096a99b5abdc8 100644 --- a/arch/arm/configs/sama5_defconfig +++ b/arch/arm/configs/sama5_defconfig @@ -6,6 +6,7 @@ CONFIG_LOG_BUF_SHIFT=14 CONFIG_CGROUPS=y CONFIG_BLK_DEV_INITRD=y CONFIG_EXPERT=y +CONFIG_KEXEC=y CONFIG_ARCH_AT91=y CONFIG_SOC_SAMA5D2=y CONFIG_SOC_SAMA5D3=y @@ -14,7 +15,6 @@ CONFIG_SOC_SAMA5D4=y CONFIG_UACCESS_WITH_MEMCPY=y # CONFIG_ATAGS is not set CONFIG_CMDLINE="console=ttyS0,115200 initrd=0x21100000,25165824 root=/dev/ram0 rw" -CONFIG_KEXEC=y CONFIG_VFP=y CONFIG_NEON=y CONFIG_KERNEL_MODE_NEON=y diff --git a/arch/arm/configs/sama7_defconfig b/arch/arm/configs/sama7_defconfig index be0cfed4ecf153..7fa5d251ced282 100644 --- a/arch/arm/configs/sama7_defconfig +++ b/arch/arm/configs/sama7_defconfig @@ -6,13 +6,11 @@ CONFIG_LOG_BUF_SHIFT=16 CONFIG_CGROUPS=y CONFIG_CGROUP_DEBUG=y CONFIG_NAMESPACES=y -CONFIG_SYSFS_DEPRECATED=y -CONFIG_SYSFS_DEPRECATED_V2=y CONFIG_BLK_DEV_INITRD=y +CONFIG_EXPERT=y # CONFIG_FHANDLE is not set # CONFIG_IO_URING is not set CONFIG_KALLSYMS_ALL=y -CONFIG_EXPERT=y CONFIG_ARCH_AT91=y CONFIG_SOC_SAMA7G5=y CONFIG_ATMEL_CLOCKSOURCE_TCB=y diff --git a/arch/arm/configs/shmobile_defconfig b/arch/arm/configs/shmobile_defconfig index dfdea295c4affc..c47a638172a89b 100644 --- a/arch/arm/configs/shmobile_defconfig +++ b/arch/arm/configs/shmobile_defconfig @@ -75,6 +75,7 @@ CONFIG_SERIAL_8250=y # CONFIG_SERIAL_8250_16550A_VARIANTS is not set CONFIG_SERIAL_8250_CONSOLE=y # CONFIG_SERIAL_8250_PCI is not set +# CONFIG_SERIAL_8250_EXAR is not set CONFIG_SERIAL_8250_DW=y CONFIG_SERIAL_8250_EM=y # CONFIG_SERIAL_8250_PERICOM is not set @@ -134,8 +135,10 @@ CONFIG_VIDEO_ADV7604=y CONFIG_VIDEO_ADV7604_CEC=y CONFIG_VIDEO_ML86V7667=y CONFIG_DRM=y +CONFIG_DRM_FBDEV_EMULATION=y CONFIG_DRM_RCAR_DU=y # CONFIG_DRM_RCAR_USE_MIPI_DSI is not set +CONFIG_DRM_SHMOBILE=y CONFIG_DRM_PANEL_SIMPLE=y CONFIG_DRM_PANEL_EDP=y CONFIG_DRM_DISPLAY_CONNECTOR=y @@ -144,8 +147,7 @@ CONFIG_DRM_SII902X=y CONFIG_DRM_SIMPLE_BRIDGE=y CONFIG_DRM_I2C_ADV7511=y CONFIG_DRM_I2C_ADV7511_AUDIO=y -CONFIG_FB=y -CONFIG_FB_SH_MOBILE_LCDC=y +CONFIG_FB_DEVICE=y CONFIG_BACKLIGHT_PWM=y CONFIG_BACKLIGHT_AS3711=y CONFIG_SOUND=y diff --git a/arch/arm/configs/spitz_defconfig b/arch/arm/configs/spitz_defconfig index 10108b4a978e9c..294d16ddeb18ad 100644 --- a/arch/arm/configs/spitz_defconfig +++ b/arch/arm/configs/spitz_defconfig @@ -2,7 +2,6 @@ CONFIG_SYSVIPC=y CONFIG_PREEMPT=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_LOG_BUF_SHIFT=14 -CONFIG_SYSFS_DEPRECATED_V2=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_EXPERT=y CONFIG_PROFILING=y @@ -87,7 +86,6 @@ CONFIG_CHR_DEV_SG=m CONFIG_ATA=y CONFIG_PATA_PCMCIA=y CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y CONFIG_PCMCIA_PCNET=m CONFIG_PPP=m CONFIG_PPP_BSDCOMP=m diff --git a/arch/arm/configs/stm32_defconfig b/arch/arm/configs/stm32_defconfig index e95aba916547b6..b9fe3fbed5aeca 100644 --- a/arch/arm/configs/stm32_defconfig +++ b/arch/arm/configs/stm32_defconfig @@ -4,6 +4,7 @@ CONFIG_PREEMPT=y CONFIG_LOG_BUF_SHIFT=16 CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_EXPERT=y # CONFIG_UID16 is not set # CONFIG_BASE_FULL is not set # CONFIG_FUTEX is not set @@ -11,7 +12,6 @@ CONFIG_CC_OPTIMIZE_FOR_SIZE=y # CONFIG_SIGNALFD is not set # CONFIG_EVENTFD is not set # CONFIG_AIO is not set -CONFIG_EXPERT=y # CONFIG_BLK_DEV_BSG is not set # CONFIG_MMU is not set CONFIG_ARCH_STM32=y diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig index 8635b7216bfc5a..d2a094ad360cef 100644 --- a/arch/arm/configs/tegra_defconfig +++ b/arch/arm/configs/tegra_defconfig @@ -13,13 +13,13 @@ CONFIG_CGROUP_DEBUG=y CONFIG_NAMESPACES=y CONFIG_USER_NS=y CONFIG_BLK_DEV_INITRD=y -# CONFIG_ELF_CORE is not set CONFIG_EXPERT=y +# CONFIG_ELF_CORE is not set CONFIG_PERF_EVENTS=y +CONFIG_KEXEC=y CONFIG_ARCH_TEGRA=y CONFIG_SMP=y CONFIG_HIGHMEM=y -CONFIG_KEXEC=y CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_USERSPACE=y diff --git a/arch/arm/configs/vf610m4_defconfig b/arch/arm/configs/vf610m4_defconfig index 963ff0a033110c..a5609cbfdfb323 100644 --- a/arch/arm/configs/vf610m4_defconfig +++ b/arch/arm/configs/vf610m4_defconfig @@ -4,8 +4,8 @@ CONFIG_BLK_DEV_INITRD=y # CONFIG_RD_LZMA is not set # CONFIG_RD_XZ is not set # CONFIG_RD_LZ4 is not set -CONFIG_KALLSYMS_ALL=y CONFIG_EXPERT=y +CONFIG_KALLSYMS_ALL=y # CONFIG_MMU is not set CONFIG_ARCH_MXC=y CONFIG_SOC_VF610=y diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index f6181f69577fe5..1075534b0a2eeb 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h @@ -340,6 +340,8 @@ static inline void flush_cache_vmap(unsigned long start, unsigned long end) dsb(ishst); } +#define flush_cache_vmap_early(start, end) do { } while (0) + static inline void flush_cache_vunmap(unsigned long start, unsigned long end) { if (!cache_is_vipt_nonaliasing()) diff --git a/arch/arm/include/asm/hardware/locomo.h b/arch/arm/include/asm/hardware/locomo.h index aaaedafef7cce6..9fd9ad5d920207 100644 --- a/arch/arm/include/asm/hardware/locomo.h +++ b/arch/arm/include/asm/hardware/locomo.h @@ -158,8 +158,6 @@ #define LOCOMO_LPT_TOH(TOH) ((TOH & 0x7) << 4) #define LOCOMO_LPT_TOL(TOL) ((TOL & 0x7)) -extern struct bus_type locomo_bus_type; - #define LOCOMO_DEVID_KEYBOARD 0 #define LOCOMO_DEVID_FRONTLIGHT 1 #define LOCOMO_DEVID_BACKLIGHT 2 diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h index 56b08ed6cc3bcb..1815748f5d2acc 100644 --- a/arch/arm/include/asm/io.h +++ b/arch/arm/include/asm/io.h @@ -407,12 +407,6 @@ struct pci_dev; #define pci_iounmap pci_iounmap extern void pci_iounmap(struct pci_dev *dev, void __iomem *addr); -/* - * Convert a physical pointer to a virtual kernel pointer for /dev/mem - * access - */ -#define xlate_dev_mem_ptr(p) __va(p) - #include #ifdef CONFIG_MMU diff --git a/arch/arm/include/asm/irq_work.h b/arch/arm/include/asm/irq_work.h index 3149e4dc1b5405..8895999834cc0b 100644 --- a/arch/arm/include/asm/irq_work.h +++ b/arch/arm/include/asm/irq_work.h @@ -9,6 +9,4 @@ static inline bool arch_irq_work_has_interrupt(void) return is_smp(); } -extern void arch_irq_work_raise(void); - #endif /* _ASM_ARM_IRQ_WORK_H */ diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h index 16b02f44c7d312..d657b84b6bf706 100644 --- a/arch/arm/include/asm/pgtable.h +++ b/arch/arm/include/asm/pgtable.h @@ -151,6 +151,8 @@ extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; +#define pgdp_get(pgpd) READ_ONCE(*pgdp) + #define pud_page(pud) pmd_page(__pmd(pud_val(pud))) #define pud_write(pud) pmd_write(__pmd(pud_val(pud))) diff --git a/arch/arm/include/asm/topology.h b/arch/arm/include/asm/topology.h index c7d2510e5a786f..853c4f81ba4a57 100644 --- a/arch/arm/include/asm/topology.h +++ b/arch/arm/include/asm/topology.h @@ -13,6 +13,7 @@ #define arch_set_freq_scale topology_set_freq_scale #define arch_scale_freq_capacity topology_get_freq_scale #define arch_scale_freq_invariant topology_scale_freq_invariant +#define arch_scale_freq_ref topology_get_freq_ref #endif /* Replace task scheduler's default cpu-invariant accounting */ diff --git a/arch/arm/include/asm/vdso.h b/arch/arm/include/asm/vdso.h index 422c3afa806a91..5b85889f82eeb4 100644 --- a/arch/arm/include/asm/vdso.h +++ b/arch/arm/include/asm/vdso.h @@ -24,11 +24,6 @@ static inline void arm_install_vdso(struct mm_struct *mm, unsigned long addr) #endif /* CONFIG_VDSO */ -int __vdso_clock_gettime(clockid_t clock, struct old_timespec32 *ts); -int __vdso_clock_gettime64(clockid_t clock, struct __kernel_timespec *ts); -int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz); -int __vdso_clock_getres(clockid_t clock_id, struct old_timespec32 *res); - #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ diff --git a/arch/arm/kernel/atags_proc.c b/arch/arm/kernel/atags_proc.c index 3ec2afe7842327..cd09f8ab93e36c 100644 --- a/arch/arm/kernel/atags_proc.c +++ b/arch/arm/kernel/atags_proc.c @@ -7,7 +7,7 @@ struct buffer { size_t size; - char data[]; + char data[] __counted_by(size); }; static ssize_t atags_read(struct file *file, char __user *buf, @@ -54,7 +54,7 @@ static int __init init_atags_procfs(void) WARN_ON(tag->hdr.tag != ATAG_NONE); - b = kmalloc(sizeof(*b) + size, GFP_KERNEL); + b = kmalloc(struct_size(b, data, size), GFP_KERNEL); if (!b) goto nomem; diff --git a/arch/arm/kernel/perf_event_v6.c b/arch/arm/kernel/perf_event_v6.c index 1ae99deeec5491..d9fd538415918f 100644 --- a/arch/arm/kernel/perf_event_v6.c +++ b/arch/arm/kernel/perf_event_v6.c @@ -113,69 +113,6 @@ static const unsigned armv6_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] [C(ITLB)][C(OP_WRITE)][C(RESULT_MISS)] = ARMV6_PERFCTR_ITLB_MISS, }; -enum armv6mpcore_perf_types { - ARMV6MPCORE_PERFCTR_ICACHE_MISS = 0x0, - ARMV6MPCORE_PERFCTR_IBUF_STALL = 0x1, - ARMV6MPCORE_PERFCTR_DDEP_STALL = 0x2, - ARMV6MPCORE_PERFCTR_ITLB_MISS = 0x3, - ARMV6MPCORE_PERFCTR_DTLB_MISS = 0x4, - ARMV6MPCORE_PERFCTR_BR_EXEC = 0x5, - ARMV6MPCORE_PERFCTR_BR_NOTPREDICT = 0x6, - ARMV6MPCORE_PERFCTR_BR_MISPREDICT = 0x7, - ARMV6MPCORE_PERFCTR_INSTR_EXEC = 0x8, - ARMV6MPCORE_PERFCTR_DCACHE_RDACCESS = 0xA, - ARMV6MPCORE_PERFCTR_DCACHE_RDMISS = 0xB, - ARMV6MPCORE_PERFCTR_DCACHE_WRACCESS = 0xC, - ARMV6MPCORE_PERFCTR_DCACHE_WRMISS = 0xD, - ARMV6MPCORE_PERFCTR_DCACHE_EVICTION = 0xE, - ARMV6MPCORE_PERFCTR_SW_PC_CHANGE = 0xF, - ARMV6MPCORE_PERFCTR_MAIN_TLB_MISS = 0x10, - ARMV6MPCORE_PERFCTR_EXPL_MEM_ACCESS = 0x11, - ARMV6MPCORE_PERFCTR_LSU_FULL_STALL = 0x12, - ARMV6MPCORE_PERFCTR_WBUF_DRAINED = 0x13, - ARMV6MPCORE_PERFCTR_CPU_CYCLES = 0xFF, -}; - -/* - * The hardware events that we support. We do support cache operations but - * we have harvard caches and no way to combine instruction and data - * accesses/misses in hardware. - */ -static const unsigned armv6mpcore_perf_map[PERF_COUNT_HW_MAX] = { - PERF_MAP_ALL_UNSUPPORTED, - [PERF_COUNT_HW_CPU_CYCLES] = ARMV6MPCORE_PERFCTR_CPU_CYCLES, - [PERF_COUNT_HW_INSTRUCTIONS] = ARMV6MPCORE_PERFCTR_INSTR_EXEC, - [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV6MPCORE_PERFCTR_BR_EXEC, - [PERF_COUNT_HW_BRANCH_MISSES] = ARMV6MPCORE_PERFCTR_BR_MISPREDICT, - [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = ARMV6MPCORE_PERFCTR_IBUF_STALL, - [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = ARMV6MPCORE_PERFCTR_LSU_FULL_STALL, -}; - -static const unsigned armv6mpcore_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] - [PERF_COUNT_HW_CACHE_OP_MAX] - [PERF_COUNT_HW_CACHE_RESULT_MAX] = { - PERF_CACHE_MAP_ALL_UNSUPPORTED, - - [C(L1D)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV6MPCORE_PERFCTR_DCACHE_RDACCESS, - [C(L1D)][C(OP_READ)][C(RESULT_MISS)] = ARMV6MPCORE_PERFCTR_DCACHE_RDMISS, - [C(L1D)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV6MPCORE_PERFCTR_DCACHE_WRACCESS, - [C(L1D)][C(OP_WRITE)][C(RESULT_MISS)] = ARMV6MPCORE_PERFCTR_DCACHE_WRMISS, - - [C(L1I)][C(OP_READ)][C(RESULT_MISS)] = ARMV6MPCORE_PERFCTR_ICACHE_MISS, - - /* - * The ARM performance counters can count micro DTLB misses, micro ITLB - * misses and main TLB misses. There isn't an event for TLB misses, so - * use the micro misses here and if users want the main TLB misses they - * can use a raw counter. - */ - [C(DTLB)][C(OP_READ)][C(RESULT_MISS)] = ARMV6MPCORE_PERFCTR_DTLB_MISS, - [C(DTLB)][C(OP_WRITE)][C(RESULT_MISS)] = ARMV6MPCORE_PERFCTR_DTLB_MISS, - - [C(ITLB)][C(OP_READ)][C(RESULT_MISS)] = ARMV6MPCORE_PERFCTR_ITLB_MISS, - [C(ITLB)][C(OP_WRITE)][C(RESULT_MISS)] = ARMV6MPCORE_PERFCTR_ITLB_MISS, -}; - static inline unsigned long armv6_pmcr_read(void) { @@ -268,10 +205,8 @@ static inline void armv6pmu_write_counter(struct perf_event *event, u64 value) static void armv6pmu_enable_event(struct perf_event *event) { - unsigned long val, mask, evt, flags; - struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu); + unsigned long val, mask, evt; struct hw_perf_event *hwc = &event->hw; - struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); int idx = hwc->idx; if (ARMV6_CYCLE_COUNTER == idx) { @@ -294,12 +229,10 @@ static void armv6pmu_enable_event(struct perf_event *event) * Mask out the current event and set the counter to count the event * that we're interested in. */ - raw_spin_lock_irqsave(&events->pmu_lock, flags); val = armv6_pmcr_read(); val &= ~mask; val |= evt; armv6_pmcr_write(val); - raw_spin_unlock_irqrestore(&events->pmu_lock, flags); } static irqreturn_t @@ -362,26 +295,20 @@ armv6pmu_handle_irq(struct arm_pmu *cpu_pmu) static void armv6pmu_start(struct arm_pmu *cpu_pmu) { - unsigned long flags, val; - struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); + unsigned long val; - raw_spin_lock_irqsave(&events->pmu_lock, flags); val = armv6_pmcr_read(); val |= ARMV6_PMCR_ENABLE; armv6_pmcr_write(val); - raw_spin_unlock_irqrestore(&events->pmu_lock, flags); } static void armv6pmu_stop(struct arm_pmu *cpu_pmu) { - unsigned long flags, val; - struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); + unsigned long val; - raw_spin_lock_irqsave(&events->pmu_lock, flags); val = armv6_pmcr_read(); val &= ~ARMV6_PMCR_ENABLE; armv6_pmcr_write(val); - raw_spin_unlock_irqrestore(&events->pmu_lock, flags); } static int @@ -419,10 +346,8 @@ static void armv6pmu_clear_event_idx(struct pmu_hw_events *cpuc, static void armv6pmu_disable_event(struct perf_event *event) { - unsigned long val, mask, evt, flags; - struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu); + unsigned long val, mask, evt; struct hw_perf_event *hwc = &event->hw; - struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); int idx = hwc->idx; if (ARMV6_CYCLE_COUNTER == idx) { @@ -444,43 +369,10 @@ static void armv6pmu_disable_event(struct perf_event *event) * of ETM bus signal assertion cycles. The external reporting should * be disabled and so this should never increment. */ - raw_spin_lock_irqsave(&events->pmu_lock, flags); - val = armv6_pmcr_read(); - val &= ~mask; - val |= evt; - armv6_pmcr_write(val); - raw_spin_unlock_irqrestore(&events->pmu_lock, flags); -} - -static void armv6mpcore_pmu_disable_event(struct perf_event *event) -{ - unsigned long val, mask, flags, evt = 0; - struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu); - struct hw_perf_event *hwc = &event->hw; - struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); - int idx = hwc->idx; - - if (ARMV6_CYCLE_COUNTER == idx) { - mask = ARMV6_PMCR_CCOUNT_IEN; - } else if (ARMV6_COUNTER0 == idx) { - mask = ARMV6_PMCR_COUNT0_IEN; - } else if (ARMV6_COUNTER1 == idx) { - mask = ARMV6_PMCR_COUNT1_IEN; - } else { - WARN_ONCE(1, "invalid counter number (%d)\n", idx); - return; - } - - /* - * Unlike UP ARMv6, we don't have a way of stopping the counters. We - * simply disable the interrupt reporting. - */ - raw_spin_lock_irqsave(&events->pmu_lock, flags); val = armv6_pmcr_read(); val &= ~mask; val |= evt; armv6_pmcr_write(val); - raw_spin_unlock_irqrestore(&events->pmu_lock, flags); } static int armv6_map_event(struct perf_event *event) @@ -525,40 +417,7 @@ static int armv6_1176_pmu_init(struct arm_pmu *cpu_pmu) return 0; } -/* - * ARMv6mpcore is almost identical to single core ARMv6 with the exception - * that some of the events have different enumerations and that there is no - * *hack* to stop the programmable counters. To stop the counters we simply - * disable the interrupt reporting and update the event. When unthrottling we - * reset the period and enable the interrupt reporting. - */ - -static int armv6mpcore_map_event(struct perf_event *event) -{ - return armpmu_map_event(event, &armv6mpcore_perf_map, - &armv6mpcore_perf_cache_map, 0xFF); -} - -static int armv6mpcore_pmu_init(struct arm_pmu *cpu_pmu) -{ - cpu_pmu->name = "armv6_11mpcore"; - cpu_pmu->handle_irq = armv6pmu_handle_irq; - cpu_pmu->enable = armv6pmu_enable_event; - cpu_pmu->disable = armv6mpcore_pmu_disable_event; - cpu_pmu->read_counter = armv6pmu_read_counter; - cpu_pmu->write_counter = armv6pmu_write_counter; - cpu_pmu->get_event_idx = armv6pmu_get_event_idx; - cpu_pmu->clear_event_idx = armv6pmu_clear_event_idx; - cpu_pmu->start = armv6pmu_start; - cpu_pmu->stop = armv6pmu_stop; - cpu_pmu->map_event = armv6mpcore_map_event; - cpu_pmu->num_events = 3; - - return 0; -} - static const struct of_device_id armv6_pmu_of_device_ids[] = { - {.compatible = "arm,arm11mpcore-pmu", .data = armv6mpcore_pmu_init}, {.compatible = "arm,arm1176-pmu", .data = armv6_1176_pmu_init}, {.compatible = "arm,arm1136-pmu", .data = armv6_1136_pmu_init}, { /* sentinel value */ } @@ -568,7 +427,6 @@ static const struct pmu_probe_info armv6_pmu_probe_table[] = { ARM_PMU_PROBE(ARM_CPU_PART_ARM1136, armv6_1136_pmu_init), ARM_PMU_PROBE(ARM_CPU_PART_ARM1156, armv6_1156_pmu_init), ARM_PMU_PROBE(ARM_CPU_PART_ARM1176, armv6_1176_pmu_init), - ARM_PMU_PROBE(ARM_CPU_PART_ARM11MPCORE, armv6mpcore_pmu_init), { /* sentinel value */ } }; diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c index eb2190477da10a..a3322e2b3ea44d 100644 --- a/arch/arm/kernel/perf_event_v7.c +++ b/arch/arm/kernel/perf_event_v7.c @@ -870,10 +870,8 @@ static void armv7_pmnc_dump_regs(struct arm_pmu *cpu_pmu) static void armv7pmu_enable_event(struct perf_event *event) { - unsigned long flags; struct hw_perf_event *hwc = &event->hw; struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu); - struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); int idx = hwc->idx; if (!armv7_pmnc_counter_valid(cpu_pmu, idx)) { @@ -886,7 +884,6 @@ static void armv7pmu_enable_event(struct perf_event *event) * Enable counter and interrupt, and set the counter to count * the event that we're interested in. */ - raw_spin_lock_irqsave(&events->pmu_lock, flags); /* * Disable counter @@ -910,16 +907,12 @@ static void armv7pmu_enable_event(struct perf_event *event) * Enable counter */ armv7_pmnc_enable_counter(idx); - - raw_spin_unlock_irqrestore(&events->pmu_lock, flags); } static void armv7pmu_disable_event(struct perf_event *event) { - unsigned long flags; struct hw_perf_event *hwc = &event->hw; struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu); - struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); int idx = hwc->idx; if (!armv7_pmnc_counter_valid(cpu_pmu, idx)) { @@ -931,7 +924,6 @@ static void armv7pmu_disable_event(struct perf_event *event) /* * Disable counter and interrupt */ - raw_spin_lock_irqsave(&events->pmu_lock, flags); /* * Disable counter @@ -942,8 +934,6 @@ static void armv7pmu_disable_event(struct perf_event *event) * Disable interrupt for this counter */ armv7_pmnc_disable_intens(idx); - - raw_spin_unlock_irqrestore(&events->pmu_lock, flags); } static irqreturn_t armv7pmu_handle_irq(struct arm_pmu *cpu_pmu) @@ -1009,24 +999,14 @@ static irqreturn_t armv7pmu_handle_irq(struct arm_pmu *cpu_pmu) static void armv7pmu_start(struct arm_pmu *cpu_pmu) { - unsigned long flags; - struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); - - raw_spin_lock_irqsave(&events->pmu_lock, flags); /* Enable all counters */ armv7_pmnc_write(armv7_pmnc_read() | ARMV7_PMNC_E); - raw_spin_unlock_irqrestore(&events->pmu_lock, flags); } static void armv7pmu_stop(struct arm_pmu *cpu_pmu) { - unsigned long flags; - struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); - - raw_spin_lock_irqsave(&events->pmu_lock, flags); /* Disable all counters */ armv7_pmnc_write(armv7_pmnc_read() & ~ARMV7_PMNC_E); - raw_spin_unlock_irqrestore(&events->pmu_lock, flags); } static int armv7pmu_get_event_idx(struct pmu_hw_events *cpuc, @@ -1072,8 +1052,10 @@ static int armv7pmu_set_event_filter(struct hw_perf_event *event, { unsigned long config_base = 0; - if (attr->exclude_idle) - return -EPERM; + if (attr->exclude_idle) { + pr_debug("ARM performance counters do not support mode exclusion\n"); + return -EOPNOTSUPP; + } if (attr->exclude_user) config_base |= ARMV7_EXCLUDE_USER; if (attr->exclude_kernel) @@ -1492,14 +1474,10 @@ static void krait_clearpmu(u32 config_base) static void krait_pmu_disable_event(struct perf_event *event) { - unsigned long flags; struct hw_perf_event *hwc = &event->hw; int idx = hwc->idx; - struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu); - struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); /* Disable counter and interrupt */ - raw_spin_lock_irqsave(&events->pmu_lock, flags); /* Disable counter */ armv7_pmnc_disable_counter(idx); @@ -1512,23 +1490,17 @@ static void krait_pmu_disable_event(struct perf_event *event) /* Disable interrupt for this counter */ armv7_pmnc_disable_intens(idx); - - raw_spin_unlock_irqrestore(&events->pmu_lock, flags); } static void krait_pmu_enable_event(struct perf_event *event) { - unsigned long flags; struct hw_perf_event *hwc = &event->hw; int idx = hwc->idx; - struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu); - struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); /* * Enable counter and interrupt, and set the counter to count * the event that we're interested in. */ - raw_spin_lock_irqsave(&events->pmu_lock, flags); /* Disable counter */ armv7_pmnc_disable_counter(idx); @@ -1548,8 +1520,6 @@ static void krait_pmu_enable_event(struct perf_event *event) /* Enable counter */ armv7_pmnc_enable_counter(idx); - - raw_spin_unlock_irqrestore(&events->pmu_lock, flags); } static void krait_pmu_reset(void *info) @@ -1825,14 +1795,10 @@ static void scorpion_clearpmu(u32 config_base) static void scorpion_pmu_disable_event(struct perf_event *event) { - unsigned long flags; struct hw_perf_event *hwc = &event->hw; int idx = hwc->idx; - struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu); - struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); /* Disable counter and interrupt */ - raw_spin_lock_irqsave(&events->pmu_lock, flags); /* Disable counter */ armv7_pmnc_disable_counter(idx); @@ -1845,23 +1811,17 @@ static void scorpion_pmu_disable_event(struct perf_event *event) /* Disable interrupt for this counter */ armv7_pmnc_disable_intens(idx); - - raw_spin_unlock_irqrestore(&events->pmu_lock, flags); } static void scorpion_pmu_enable_event(struct perf_event *event) { - unsigned long flags; struct hw_perf_event *hwc = &event->hw; int idx = hwc->idx; - struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu); - struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); /* * Enable counter and interrupt, and set the counter to count * the event that we're interested in. */ - raw_spin_lock_irqsave(&events->pmu_lock, flags); /* Disable counter */ armv7_pmnc_disable_counter(idx); @@ -1881,8 +1841,6 @@ static void scorpion_pmu_enable_event(struct perf_event *event) /* Enable counter */ armv7_pmnc_enable_counter(idx); - - raw_spin_unlock_irqrestore(&events->pmu_lock, flags); } static void scorpion_pmu_reset(void *info) diff --git a/arch/arm/kernel/perf_event_xscale.c b/arch/arm/kernel/perf_event_xscale.c index f6cdcacfb96dbc..7a2ba1c689a7f5 100644 --- a/arch/arm/kernel/perf_event_xscale.c +++ b/arch/arm/kernel/perf_event_xscale.c @@ -203,10 +203,8 @@ xscale1pmu_handle_irq(struct arm_pmu *cpu_pmu) static void xscale1pmu_enable_event(struct perf_event *event) { - unsigned long val, mask, evt, flags; - struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu); + unsigned long val, mask, evt; struct hw_perf_event *hwc = &event->hw; - struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); int idx = hwc->idx; switch (idx) { @@ -229,20 +227,16 @@ static void xscale1pmu_enable_event(struct perf_event *event) return; } - raw_spin_lock_irqsave(&events->pmu_lock, flags); val = xscale1pmu_read_pmnc(); val &= ~mask; val |= evt; xscale1pmu_write_pmnc(val); - raw_spin_unlock_irqrestore(&events->pmu_lock, flags); } static void xscale1pmu_disable_event(struct perf_event *event) { - unsigned long val, mask, evt, flags; - struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu); + unsigned long val, mask, evt; struct hw_perf_event *hwc = &event->hw; - struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); int idx = hwc->idx; switch (idx) { @@ -263,12 +257,10 @@ static void xscale1pmu_disable_event(struct perf_event *event) return; } - raw_spin_lock_irqsave(&events->pmu_lock, flags); val = xscale1pmu_read_pmnc(); val &= ~mask; val |= evt; xscale1pmu_write_pmnc(val); - raw_spin_unlock_irqrestore(&events->pmu_lock, flags); } static int @@ -300,26 +292,20 @@ static void xscalepmu_clear_event_idx(struct pmu_hw_events *cpuc, static void xscale1pmu_start(struct arm_pmu *cpu_pmu) { - unsigned long flags, val; - struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); + unsigned long val; - raw_spin_lock_irqsave(&events->pmu_lock, flags); val = xscale1pmu_read_pmnc(); val |= XSCALE_PMU_ENABLE; xscale1pmu_write_pmnc(val); - raw_spin_unlock_irqrestore(&events->pmu_lock, flags); } static void xscale1pmu_stop(struct arm_pmu *cpu_pmu) { - unsigned long flags, val; - struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); + unsigned long val; - raw_spin_lock_irqsave(&events->pmu_lock, flags); val = xscale1pmu_read_pmnc(); val &= ~XSCALE_PMU_ENABLE; xscale1pmu_write_pmnc(val); - raw_spin_unlock_irqrestore(&events->pmu_lock, flags); } static inline u64 xscale1pmu_read_counter(struct perf_event *event) @@ -549,10 +535,8 @@ xscale2pmu_handle_irq(struct arm_pmu *cpu_pmu) static void xscale2pmu_enable_event(struct perf_event *event) { - unsigned long flags, ien, evtsel; - struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu); + unsigned long ien, evtsel; struct hw_perf_event *hwc = &event->hw; - struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); int idx = hwc->idx; ien = xscale2pmu_read_int_enable(); @@ -587,18 +571,14 @@ static void xscale2pmu_enable_event(struct perf_event *event) return; } - raw_spin_lock_irqsave(&events->pmu_lock, flags); xscale2pmu_write_event_select(evtsel); xscale2pmu_write_int_enable(ien); - raw_spin_unlock_irqrestore(&events->pmu_lock, flags); } static void xscale2pmu_disable_event(struct perf_event *event) { - unsigned long flags, ien, evtsel, of_flags; - struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu); + unsigned long ien, evtsel, of_flags; struct hw_perf_event *hwc = &event->hw; - struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); int idx = hwc->idx; ien = xscale2pmu_read_int_enable(); @@ -638,11 +618,9 @@ static void xscale2pmu_disable_event(struct perf_event *event) return; } - raw_spin_lock_irqsave(&events->pmu_lock, flags); xscale2pmu_write_event_select(evtsel); xscale2pmu_write_int_enable(ien); xscale2pmu_write_overflow_flags(of_flags); - raw_spin_unlock_irqrestore(&events->pmu_lock, flags); } static int @@ -663,26 +641,20 @@ out: static void xscale2pmu_start(struct arm_pmu *cpu_pmu) { - unsigned long flags, val; - struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); + unsigned long val; - raw_spin_lock_irqsave(&events->pmu_lock, flags); val = xscale2pmu_read_pmnc() & ~XSCALE_PMU_CNT64; val |= XSCALE_PMU_ENABLE; xscale2pmu_write_pmnc(val); - raw_spin_unlock_irqrestore(&events->pmu_lock, flags); } static void xscale2pmu_stop(struct arm_pmu *cpu_pmu) { - unsigned long flags, val; - struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events); + unsigned long val; - raw_spin_lock_irqsave(&events->pmu_lock, flags); val = xscale2pmu_read_pmnc(); val &= ~XSCALE_PMU_ENABLE; xscale2pmu_write_pmnc(val); - raw_spin_unlock_irqrestore(&events->pmu_lock, flags); } static inline u64 xscale2pmu_read_counter(struct perf_event *event) diff --git a/arch/arm/mach-airoha/Makefile b/arch/arm/mach-airoha/Makefile deleted file mode 100644 index a5857d0d02ebf9..00000000000000 --- a/arch/arm/mach-airoha/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -obj-y += airoha.o diff --git a/arch/arm/mach-airoha/airoha.c b/arch/arm/mach-airoha/airoha.c deleted file mode 100644 index ea23b5abb478e3..00000000000000 --- a/arch/arm/mach-airoha/airoha.c +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Device Tree support for Airoha SoCs - * - * Copyright (c) 2022 Felix Fietkau - */ -#include - -static const char * const airoha_board_dt_compat[] = { - "airoha,en7523", - NULL, -}; - -DT_MACHINE_START(MEDIATEK_DT, "Airoha Cortex-A53 (Device Tree)") - .dt_compat = airoha_board_dt_compat, -MACHINE_END diff --git a/arch/arm/mach-asm9260/Kconfig b/arch/arm/mach-asm9260/Kconfig deleted file mode 100644 index 74e0f61c74c88f..00000000000000 --- a/arch/arm/mach-asm9260/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config MACH_ASM9260 - bool "Alphascale ASM9260" - depends on ARCH_MULTI_V5 - depends on CPU_LITTLE_ENDIAN - select CPU_ARM926T - select ASM9260_TIMER - help - Support for Alphascale ASM9260 based platform. diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index 1a26af0fabc710..345b91dc6627b4 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -1103,6 +1103,7 @@ static void __init at91_pm_secure_init(void) if (res.a0 == 0) { pr_info("AT91: Secure PM: suspend mode set to %s\n", pm_modes[suspend_mode].pattern); + soc_pm.data.mode = suspend_mode; return; } @@ -1112,6 +1113,7 @@ static void __init at91_pm_secure_init(void) res = sam_smccc_call(SAMA5_SMC_SIP_GET_SUSPEND_MODE, 0, 0); if (res.a0 == 0) { pr_warn("AT91: Secure PM: failed to get default mode\n"); + soc_pm.data.mode = -1; return; } @@ -1119,6 +1121,7 @@ static void __init at91_pm_secure_init(void) pm_modes[suspend_mode].pattern); soc_pm.data.suspend_mode = res.a1; + soc_pm.data.mode = soc_pm.data.suspend_mode; } static const struct of_device_id atmel_shdwc_ids[] = { { .compatible = "atmel,sama5d2-shdwc" }, diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig index 4316e1370627cf..2a8a9fe46586d2 100644 --- a/arch/arm/mach-davinci/Kconfig +++ b/arch/arm/mach-davinci/Kconfig @@ -4,12 +4,14 @@ menuconfig ARCH_DAVINCI bool "TI DaVinci" depends on ARCH_MULTI_V5 depends on CPU_LITTLE_ENDIAN + select CPU_ARM926T select DAVINCI_TIMER select ZONE_DMA select PM_GENERIC_DOMAINS if PM select PM_GENERIC_DOMAINS_OF if PM && OF select REGMAP_MMIO select RESET_CONTROLLER + select PINCTRL select PINCTRL_SINGLE if ARCH_DAVINCI diff --git a/arch/arm/mach-ep93xx/edb93xx.c b/arch/arm/mach-ep93xx/edb93xx.c index 4b90899a66e92f..dbdb822a0100df 100644 --- a/arch/arm/mach-ep93xx/edb93xx.c +++ b/arch/arm/mach-ep93xx/edb93xx.c @@ -88,7 +88,7 @@ static void __init edb93xx_register_i2c(void) * EDB93xx SPI peripheral handling *************************************************************************/ static struct cs4271_platform_data edb93xx_cs4271_data = { - .gpio_nreset = -EINVAL, /* filled in later */ + /* Intentionally left blank */ }; static struct spi_board_info edb93xx_spi_board_info[] __initdata = { @@ -114,14 +114,38 @@ static struct ep93xx_spi_info edb93xx_spi_info __initdata = { /* Intentionally left blank */ }; +static struct gpiod_lookup_table edb93xx_cs4272_edb9301_gpio_table = { + .dev_id = "spi0.0", /* CS0 on SPI0 */ + .table = { + GPIO_LOOKUP("A", 1, "reset", GPIO_ACTIVE_LOW), + { }, + }, +}; + +static struct gpiod_lookup_table edb93xx_cs4272_edb9302_gpio_table = { + .dev_id = "spi0.0", /* CS0 on SPI0 */ + .table = { + GPIO_LOOKUP("H", 2, "reset", GPIO_ACTIVE_LOW), + { }, + }, +}; + +static struct gpiod_lookup_table edb93xx_cs4272_edb9315_gpio_table = { + .dev_id = "spi0.0", /* CS0 on SPI0 */ + .table = { + GPIO_LOOKUP("B", 6, "reset", GPIO_ACTIVE_LOW), + { }, + }, +}; + static void __init edb93xx_register_spi(void) { if (machine_is_edb9301() || machine_is_edb9302()) - edb93xx_cs4271_data.gpio_nreset = EP93XX_GPIO_LINE_EGPIO1; + gpiod_add_lookup_table(&edb93xx_cs4272_edb9301_gpio_table); else if (machine_is_edb9302a() || machine_is_edb9307a()) - edb93xx_cs4271_data.gpio_nreset = EP93XX_GPIO_LINE_H(2); + gpiod_add_lookup_table(&edb93xx_cs4272_edb9302_gpio_table); else if (machine_is_edb9315a()) - edb93xx_cs4271_data.gpio_nreset = EP93XX_GPIO_LINE_EGPIO14; + gpiod_add_lookup_table(&edb93xx_cs4272_edb9315_gpio_table); gpiod_add_lookup_table(&edb93xx_spi_cs_gpio_table); ep93xx_register_spi(&edb93xx_spi_info, edb93xx_spi_board_info, diff --git a/arch/arm/mach-ep93xx/vision_ep9307.c b/arch/arm/mach-ep93xx/vision_ep9307.c index 30d9cf3791ebb3..9471938df64c86 100644 --- a/arch/arm/mach-ep93xx/vision_ep9307.c +++ b/arch/arm/mach-ep93xx/vision_ep9307.c @@ -164,7 +164,7 @@ static struct i2c_board_info vision_i2c_info[] __initdata = { * SPI CS4271 Audio Codec *************************************************************************/ static struct cs4271_platform_data vision_cs4271_data = { - .gpio_nreset = EP93XX_GPIO_LINE_H(2), + /* Intentionally left blank */ }; /************************************************************************* @@ -241,6 +241,15 @@ static struct spi_board_info vision_spi_board_info[] __initdata = { }, }; +static struct gpiod_lookup_table vision_spi_cs4271_gpio_table = { + .dev_id = "spi0.0", /* cs4271 @ CS0 */ + .table = { + /* RESET */ + GPIO_LOOKUP_IDX("H", 2, NULL, 0, GPIO_ACTIVE_LOW), + { }, + }, +}; + static struct gpiod_lookup_table vision_spi_cs_gpio_table = { .dev_id = "spi0", .table = { @@ -292,6 +301,7 @@ static void __init vision_init_machine(void) ep93xx_register_i2c(vision_i2c_info, ARRAY_SIZE(vision_i2c_info)); + gpiod_add_lookup_table(&vision_spi_cs4271_gpio_table); gpiod_add_lookup_table(&vision_spi_mmc_gpio_table); gpiod_add_lookup_table(&vision_spi_cs_gpio_table); ep93xx_register_spi(&vision_spi_master, vision_spi_board_info, diff --git a/arch/arm/mach-imx/mmdc.c b/arch/arm/mach-imx/mmdc.c index df69af9323754f..444a7eaa320ca7 100644 --- a/arch/arm/mach-imx/mmdc.c +++ b/arch/arm/mach-imx/mmdc.c @@ -13,7 +13,8 @@ #include #include #include -#include +#include +#include #include #include @@ -103,7 +104,7 @@ struct mmdc_pmu { struct device *dev; struct perf_event *mmdc_events[MMDC_NUM_COUNTERS]; struct hlist_node node; - struct fsl_mmdc_devtype_data *devtype_data; + const struct fsl_mmdc_devtype_data *devtype_data; struct clk *mmdc_ipg_clk; }; @@ -474,8 +475,6 @@ static int imx_mmdc_perf_init(struct platform_device *pdev, void __iomem *mmdc_b struct mmdc_pmu *pmu_mmdc; char *name; int ret; - const struct of_device_id *of_id = - of_match_device(imx_mmdc_dt_ids, &pdev->dev); pmu_mmdc = kzalloc(sizeof(*pmu_mmdc), GFP_KERNEL); if (!pmu_mmdc) { @@ -507,7 +506,7 @@ static int imx_mmdc_perf_init(struct platform_device *pdev, void __iomem *mmdc_b } pmu_mmdc->mmdc_ipg_clk = mmdc_ipg_clk; - pmu_mmdc->devtype_data = (struct fsl_mmdc_devtype_data *)of_id->data; + pmu_mmdc->devtype_data = device_get_match_data(&pdev->dev); hrtimer_init(&pmu_mmdc->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); diff --git a/arch/arm/mach-moxart/Kconfig b/arch/arm/mach-moxart/Kconfig deleted file mode 100644 index 909c6573ba8b19..00000000000000 --- a/arch/arm/mach-moxart/Kconfig +++ /dev/null @@ -1,28 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -menuconfig ARCH_MOXART - bool "MOXA ART SoC" - depends on ARCH_MULTI_V4 - depends on CPU_LITTLE_ENDIAN - select CPU_FA526 - select ARM_DMA_MEM_BUFFERABLE - select FARADAY_FTINTC010 - select FTTMR010_TIMER - select GPIOLIB - select PHYLIB if NETDEVICES - help - Say Y here if you want to run your kernel on hardware with a - MOXA ART SoC. - The MOXA ART SoC is based on a Faraday FA526 ARMv4 32-bit - 192 MHz CPU with MMU and 16KB/8KB D/I-cache (UC-7112-LX). - Used on models UC-7101, UC-7112/UC-7110, IA240/IA241, IA3341. - -if ARCH_MOXART - -config MACH_UC7112LX - bool "MOXA UC-7112-LX" - depends on ARCH_MOXART - help - Say Y here if you intend to run this kernel on a MOXA - UC-7112-LX embedded computer. - -endif diff --git a/arch/arm/mach-moxart/Makefile b/arch/arm/mach-moxart/Makefile deleted file mode 100644 index ded3e38fb98d33..00000000000000 --- a/arch/arm/mach-moxart/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# Object file lists. - -obj-$(CONFIG_MACH_UC7112LX) += moxart.o diff --git a/arch/arm/mach-moxart/moxart.c b/arch/arm/mach-moxart/moxart.c deleted file mode 100644 index f1f58c0c0fa1ca..00000000000000 --- a/arch/arm/mach-moxart/moxart.c +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * arch/arm/mach-moxart/moxart.c - * - * (C) Copyright 2013, Jonas Jensen - */ diff --git a/arch/arm/mach-mxs/mach-mxs.c b/arch/arm/mach-mxs/mach-mxs.c index 3faf9a1e3e36aa..6e017fa306c828 100644 --- a/arch/arm/mach-mxs/mach-mxs.c +++ b/arch/arm/mach-mxs/mach-mxs.c @@ -356,7 +356,9 @@ static int __init mxs_restart_init(void) { struct device_node *np; - np = of_find_compatible_node(NULL, NULL, "fsl,clkctrl"); + np = of_find_compatible_node(NULL, NULL, "fsl,imx23-clkctrl"); + if (!np) + np = of_find_compatible_node(NULL, NULL, "fsl,imx28-clkctrl"); reset_addr = of_iomap(np, 0); if (!reset_addr) return -ENODEV; diff --git a/arch/arm/mach-nspire/Kconfig b/arch/arm/mach-nspire/Kconfig deleted file mode 100644 index 0ffdcaca1e6b42..00000000000000 --- a/arch/arm/mach-nspire/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config ARCH_NSPIRE - bool "TI-NSPIRE based" - depends on ARCH_MULTI_V4T - depends on CPU_LITTLE_ENDIAN - select CPU_ARM926T - select GENERIC_IRQ_CHIP - select ARM_AMBA - select ARM_VIC - select ARM_TIMER_SP804 - select NSPIRE_TIMER - select POWER_RESET - select POWER_RESET_SYSCON - help - This enables support for systems using the TI-NSPIRE CPU diff --git a/arch/arm/mach-nspire/Makefile b/arch/arm/mach-nspire/Makefile deleted file mode 100644 index 4716b9b9aa7bba..00000000000000 --- a/arch/arm/mach-nspire/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -obj-y += nspire.o diff --git a/arch/arm/mach-nspire/nspire.c b/arch/arm/mach-nspire/nspire.c deleted file mode 100644 index 2fbfc23237ffe8..00000000000000 --- a/arch/arm/mach-nspire/nspire.c +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2013 Daniel Tang - */ - -#include - -static const char *const nspire_dt_match[] __initconst = { - "ti,nspire", - "ti,nspire-cx", - "ti,nspire-tp", - "ti,nspire-clp", - NULL, -}; - -DT_MACHINE_START(NSPIRE, "TI-NSPIRE") - .dt_compat = nspire_dt_match, -MACHINE_END diff --git a/arch/arm/mach-rda/Kconfig b/arch/arm/mach-rda/Kconfig deleted file mode 100644 index 4d2e4e046cb358..00000000000000 --- a/arch/arm/mach-rda/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -menuconfig ARCH_RDA - bool "RDA Micro SoCs" - depends on ARCH_MULTI_V7 - select RDA_INTC - select RDA_TIMER - help - This enables support for the RDA Micro 8810PL SoC family. diff --git a/arch/arm/mach-s3c/mach-crag6410-module.c b/arch/arm/mach-s3c/mach-crag6410-module.c index 8fce1e815ee83a..2de1a89f6e9976 100644 --- a/arch/arm/mach-s3c/mach-crag6410-module.c +++ b/arch/arm/mach-s3c/mach-crag6410-module.c @@ -32,9 +32,18 @@ #include "crag6410.h" +static struct gpiod_lookup_table wm0010_gpiod_table = { + .dev_id = "spi0.0", /* SPI device name */ + .table = { + /* Active high for Glenfarclas Rev 2 */ + GPIO_LOOKUP("GPION", 6, + "reset", GPIO_ACTIVE_HIGH), + { }, + }, +}; + static struct wm0010_pdata wm0010_pdata = { - .gpio_reset = S3C64XX_GPN(6), - .reset_active_high = 1, /* Active high for Glenfarclas Rev 2 */ + /* Intentionally left blank */ }; static struct spi_board_info wm1253_devs[] = { @@ -61,10 +70,19 @@ static struct spi_board_info balblair_devs[] = { }, }; +static struct gpiod_lookup_table wm5100_gpiod_table = { + .dev_id = "1-001a", /* Device 001a on I2C bus 1 */ + .table = { + GPIO_LOOKUP("GPION", 7, + "wlf,ldo1ena", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("wm5100", 3, + "hp-pol", GPIO_ACTIVE_HIGH), + { }, + }, +}; + static struct wm5100_pdata wm5100_pdata = { - .ldo_ena = S3C64XX_GPN(7), .irq_flags = IRQF_TRIGGER_HIGH, - .gpio_base = CODEC_GPIO_BASE, .in_mode = { WM5100_IN_DIFF, @@ -73,7 +91,6 @@ static struct wm5100_pdata wm5100_pdata = { WM5100_IN_SE, }, - .hp_pol = CODEC_GPIO_BASE + 3, .jack_modes = { { WM5100_MICDET_MICBIAS3, 0, 0 }, { WM5100_MICDET_MICBIAS2, 1, 1 }, @@ -110,9 +127,16 @@ static struct wm8996_retune_mobile_config wm8996_retune[] = { }, }; +static struct gpiod_lookup_table wm8996_gpiod_table = { + .dev_id = "1-001a", /* Device 001a on I2C bus 1 */ + .table = { + GPIO_LOOKUP("GPION", 7, + "wlf,ldo1ena", GPIO_ACTIVE_HIGH), + { }, + }, +}; + static struct wm8996_pdata wm8996_pdata __initdata = { - .ldo_ena = S3C64XX_GPN(7), - .gpio_base = CODEC_GPIO_BASE, .micdet_def = 1, .inl_mode = WM8996_DIFFERRENTIAL_1, .inr_mode = WM8996_DIFFERRENTIAL_1, @@ -296,12 +320,20 @@ static const struct i2c_board_info wm6230_i2c_devs[] = { }; static struct wm2200_pdata wm2200_pdata = { - .ldo_ena = S3C64XX_GPN(7), .gpio_defaults = { [2] = 0x0005, /* GPIO3 24.576MHz output clock */ }, }; +static struct gpiod_lookup_table wm2200_gpiod_table = { + .dev_id = "1-003a", /* Device 003a on I2C bus 1 */ + .table = { + GPIO_LOOKUP("GPION", 7, + "wlf,ldo1ena", GPIO_ACTIVE_HIGH), + { }, + }, +}; + static const struct i2c_board_info wm2200_i2c[] = { { I2C_BOARD_INFO("wm2200", 0x3a), .platform_data = &wm2200_pdata, }, @@ -337,18 +369,21 @@ static const struct { { .id = 0x21, .rev = 0xff, .name = "1275-EV1 Mortlach" }, { .id = 0x25, .rev = 0xff, .name = "1274-EV1 Glencadam" }, { .id = 0x31, .rev = 0xff, .name = "1253-EV1 Tomatin", - .spi_devs = wm1253_devs, .num_spi_devs = ARRAY_SIZE(wm1253_devs) }, + .spi_devs = wm1253_devs, .num_spi_devs = ARRAY_SIZE(wm1253_devs), + .gpiod_table = &wm0010_gpiod_table }, { .id = 0x32, .rev = 0xff, .name = "XXXX-EV1 Caol Illa" }, { .id = 0x33, .rev = 0xff, .name = "XXXX-EV1 Oban" }, { .id = 0x34, .rev = 0xff, .name = "WM0010-6320-CS42 Balblair", .spi_devs = balblair_devs, .num_spi_devs = ARRAY_SIZE(balblair_devs) }, { .id = 0x39, .rev = 0xff, .name = "1254-EV1 Dallas Dhu", - .i2c_devs = wm1254_devs, .num_i2c_devs = ARRAY_SIZE(wm1254_devs) }, + .i2c_devs = wm1254_devs, .num_i2c_devs = ARRAY_SIZE(wm1254_devs), + .gpiod_table = &wm8996_gpiod_table }, { .id = 0x3a, .rev = 0xff, .name = "1259-EV1 Tobermory", .i2c_devs = wm1259_devs, .num_i2c_devs = ARRAY_SIZE(wm1259_devs) }, { .id = 0x3b, .rev = 0xff, .name = "1255-EV1 Kilchoman", - .i2c_devs = wm1255_devs, .num_i2c_devs = ARRAY_SIZE(wm1255_devs) }, + .i2c_devs = wm1255_devs, .num_i2c_devs = ARRAY_SIZE(wm1255_devs), + .gpiod_table = &wm5100_gpiod_table }, { .id = 0x3c, .rev = 0xff, .name = "1273-EV1 Longmorn" }, { .id = 0x3d, .rev = 0xff, .name = "1277-EV1 Littlemill", .i2c_devs = wm1277_devs, .num_i2c_devs = ARRAY_SIZE(wm1277_devs), @@ -362,7 +397,8 @@ static const struct { .num_spi_devs = ARRAY_SIZE(wm5102_spi_devs), .gpiod_table = &wm5102_gpiod_table }, { .id = 0x3f, .rev = -1, .name = "WM2200-6271-CS90-M-REV1", - .i2c_devs = wm2200_i2c, .num_i2c_devs = ARRAY_SIZE(wm2200_i2c) }, + .i2c_devs = wm2200_i2c, .num_i2c_devs = ARRAY_SIZE(wm2200_i2c), + .gpiod_table = &wm2200_gpiod_table }, }; static int wlf_gf_module_probe(struct i2c_client *i2c) diff --git a/arch/arm/mach-s3c/mach-crag6410.c b/arch/arm/mach-s3c/mach-crag6410.c index 7c4bed4370a137..e5df2cb51ab278 100644 --- a/arch/arm/mach-s3c/mach-crag6410.c +++ b/arch/arm/mach-s3c/mach-crag6410.c @@ -39,8 +39,6 @@ #include #include -#include - #include #include @@ -713,13 +711,16 @@ static struct wm831x_pdata glenfarclas_pmic_pdata = { .disable_touch = true, }; -static struct wm1250_ev1_pdata wm1250_ev1_pdata = { - .gpios = { - [WM1250_EV1_GPIO_CLK_ENA] = S3C64XX_GPN(12), - [WM1250_EV1_GPIO_CLK_SEL0] = S3C64XX_GPL(12), - [WM1250_EV1_GPIO_CLK_SEL1] = S3C64XX_GPL(13), - [WM1250_EV1_GPIO_OSR] = S3C64XX_GPL(14), - [WM1250_EV1_GPIO_MASTER] = S3C64XX_GPL(8), +static struct gpiod_lookup_table crag_wm1250_ev1_gpiod_table = { + /* The WM1250-EV1 is device 0027 on I2C bus 1 */ + .dev_id = "1-0027", + .table = { + GPIO_LOOKUP("GPION", 12, "clk-ena", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOL", 12, "clk-sel0", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOL", 13, "clk-sel1", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOL", 14, "osr", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOL", 8, "master", GPIO_ACTIVE_HIGH), + { }, }, }; @@ -733,9 +734,7 @@ static struct i2c_board_info i2c_devs1[] = { { I2C_BOARD_INFO("wlf-gf-module", 0x24) }, { I2C_BOARD_INFO("wlf-gf-module", 0x25) }, { I2C_BOARD_INFO("wlf-gf-module", 0x26) }, - - { I2C_BOARD_INFO("wm1250-ev1", 0x27), - .platform_data = &wm1250_ev1_pdata }, + { I2C_BOARD_INFO("wm1250-ev1", 0x27), }, }; static struct s3c2410_platform_i2c i2c1_pdata = { @@ -862,6 +861,7 @@ static void __init crag6410_machine_init(void) gpiod_add_lookup_table(&crag_pmic_gpiod_table); i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0)); + gpiod_add_lookup_table(&crag_wm1250_ev1_gpiod_table); i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1)); samsung_keypad_set_platdata(&crag6410_keypad_data); diff --git a/arch/arm/mach-sunplus/Kconfig b/arch/arm/mach-sunplus/Kconfig deleted file mode 100644 index d0c2416e6f241b..00000000000000 --- a/arch/arm/mach-sunplus/Kconfig +++ /dev/null @@ -1,27 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) - -menuconfig ARCH_SUNPLUS - bool "Sunplus SoCs" - depends on ARCH_MULTI_V7 - help - Support for Sunplus SoC family: SP7021 and succeeding SoC-based systems, - such as the Banana Pi BPI-F2S development board (and derivatives). - () - () - -config SOC_SP7021 - bool "Sunplus SP7021 SoC support" - depends on ARCH_SUNPLUS - default ARCH_SUNPLUS - select HAVE_ARM_ARCH_TIMER - select ARM_GIC - select ARM_PSCI - select PINCTRL - select PINCTRL_SPPCTL - select SERIAL_SUNPLUS if TTY - select SERIAL_SUNPLUS_CONSOLE if TTY - help - Support for Sunplus SP7021 SoC. It is based on ARM 4-core - Cortex-A7 with various peripherals (e.g.: I2C, SPI, SDIO, - Ethernet, etc.), FPGA interface, chip-to-chip bus. - It is designed for industrial control. diff --git a/arch/arm/mach-sunplus/Makefile b/arch/arm/mach-sunplus/Makefile deleted file mode 100644 index d211de6af2db99..00000000000000 --- a/arch/arm/mach-sunplus/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for the linux kernel. -# - -# Object file lists. - -obj-$(CONFIG_SOC_SP7021) += sp7021.o diff --git a/arch/arm/mach-sunplus/sp7021.c b/arch/arm/mach-sunplus/sp7021.c deleted file mode 100644 index 774d0a5bd4eb00..00000000000000 --- a/arch/arm/mach-sunplus/sp7021.c +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -/* - * Copyright (C) Sunplus Technology Co., Ltd. - * All rights reserved. - */ -#include -#include - -static const char *sp7021_compat[] __initconst = { - "sunplus,sp7021", - NULL -}; - -DT_MACHINE_START(SP7021_DT, "SP7021") - .dt_compat = sp7021_compat, -MACHINE_END diff --git a/arch/arm/mach-uniphier/Kconfig b/arch/arm/mach-uniphier/Kconfig deleted file mode 100644 index e661d262667512..00000000000000 --- a/arch/arm/mach-uniphier/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -config ARCH_UNIPHIER - bool "Socionext UniPhier SoCs" - depends on ARCH_MULTI_V7 - select ARCH_HAS_RESET_CONTROLLER - select ARM_AMBA - select ARM_GLOBAL_TIMER - select ARM_GIC - select HAVE_ARM_SCU - select HAVE_ARM_TWD if SMP - select PINCTRL - select RESET_CONTROLLER - help - Support for UniPhier SoC family developed by Socionext Inc. - (formerly, System LSI Business Division of Panasonic Corporation) diff --git a/arch/arm/mach-versatile/Kconfig b/arch/arm/mach-versatile/Kconfig index b1519b4dc03a0f..e029270c2687d9 100644 --- a/arch/arm/mach-versatile/Kconfig +++ b/arch/arm/mach-versatile/Kconfig @@ -201,23 +201,6 @@ config REALVIEW_EB_A9MP Enable support for the Cortex-A9MPCore tile fitted to the Realview(R) Emulation Baseboard platform. -config REALVIEW_EB_ARM11MP - bool "Support ARM11MPCore Tile" - depends on MACH_REALVIEW_EB && ARCH_MULTI_V6 - select HAVE_SMP - help - Enable support for the ARM11MPCore tile fitted to the Realview(R) - Emulation Baseboard platform. - -config MACH_REALVIEW_PB11MP - bool "Support RealView(R) Platform Baseboard for ARM11MPCore" - depends on ARCH_MULTI_V6 - select HAVE_SMP - help - Include support for the ARM(R) RealView(R) Platform Baseboard for - the ARM11MPCore. This platform has an on-board ARM11MPCore and has - support for PCI-E and Compact Flash. - # ARMv6 CPU without K extensions, but does have the new exclusive ops config MACH_REALVIEW_PB1176 bool "Support RealView(R) Platform Baseboard for ARM1176JZF-S" diff --git a/arch/arm/mach-versatile/platsmp-realview.c b/arch/arm/mach-versatile/platsmp-realview.c index 5d363385c80192..6965a1de727b07 100644 --- a/arch/arm/mach-versatile/platsmp-realview.c +++ b/arch/arm/mach-versatile/platsmp-realview.c @@ -18,6 +18,11 @@ #define REALVIEW_SYS_FLAGSSET_OFFSET 0x30 static const struct of_device_id realview_scu_match[] = { + /* + * The ARM11MP SCU compatible is only provided as fallback for + * old RealView EB Cortex-A9 device trees that were using this + * compatible by mistake. + */ { .compatible = "arm,arm11mp-scu", }, { .compatible = "arm,cortex-a9-scu", }, { .compatible = "arm,cortex-a5-scu", }, @@ -27,7 +32,6 @@ static const struct of_device_id realview_scu_match[] = { static const struct of_device_id realview_syscon_match[] = { { .compatible = "arm,core-module-integrator", }, { .compatible = "arm,realview-eb-syscon", }, - { .compatible = "arm,realview-pb11mp-syscon", }, { .compatible = "arm,realview-pbx-syscon", }, { }, }; diff --git a/arch/arm/mach-versatile/realview.c b/arch/arm/mach-versatile/realview.c index a3933e2373d543..36a6f6bc4fdd53 100644 --- a/arch/arm/mach-versatile/realview.c +++ b/arch/arm/mach-versatile/realview.c @@ -9,7 +9,6 @@ static const char *const realview_dt_platform_compat[] __initconst = { "arm,realview-eb", "arm,realview-pb1176", - "arm,realview-pb11mp", "arm,realview-pba8", "arm,realview-pbx", NULL, diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index c164cde5024344..2b6f50dd547840 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -937,24 +937,6 @@ config VDSO You must have glibc 2.22 or later for programs to seamlessly take advantage of this. -config DMA_CACHE_RWFO - bool "Enable read/write for ownership DMA cache maintenance" - depends on CPU_V6K && SMP - default y - help - The Snoop Control Unit on ARM11MPCore does not detect the - cache maintenance operations and the dma_{map,unmap}_area() - functions may leave stale cache entries on other CPUs. By - enabling this option, Read or Write For Ownership in the ARMv6 - DMA cache maintenance functions is performed. These LDR/STR - instructions change the cache line state to shared or modified - so that the cache operation has the desired effect. - - Note that the workaround is only valid on processors that do - not perform speculative loads into the D-cache. For such - processors, if cache maintenance operations are not broadcast - in hardware, other workarounds are needed (e.g. cache - maintenance broadcasting in software via FIQ). config OUTER_CACHE bool diff --git a/arch/arm/mm/cache-v6.S b/arch/arm/mm/cache-v6.S index 250c83bf715874..44211d8a296fc1 100644 --- a/arch/arm/mm/cache-v6.S +++ b/arch/arm/mm/cache-v6.S @@ -201,10 +201,6 @@ ENTRY(v6_flush_kern_dcache_area) * - end - virtual end address of region */ v6_dma_inv_range: -#ifdef CONFIG_DMA_CACHE_RWFO - ldrb r2, [r0] @ read for ownership - strb r2, [r0] @ write for ownership -#endif tst r0, #D_CACHE_LINE_SIZE - 1 bic r0, r0, #D_CACHE_LINE_SIZE - 1 #ifdef HARVARD_CACHE @@ -213,10 +209,6 @@ v6_dma_inv_range: mcrne p15, 0, r0, c7, c11, 1 @ clean unified line #endif tst r1, #D_CACHE_LINE_SIZE - 1 -#ifdef CONFIG_DMA_CACHE_RWFO - ldrbne r2, [r1, #-1] @ read for ownership - strbne r2, [r1, #-1] @ write for ownership -#endif bic r1, r1, #D_CACHE_LINE_SIZE - 1 #ifdef HARVARD_CACHE mcrne p15, 0, r1, c7, c14, 1 @ clean & invalidate D line @@ -231,10 +223,6 @@ v6_dma_inv_range: #endif add r0, r0, #D_CACHE_LINE_SIZE cmp r0, r1 -#ifdef CONFIG_DMA_CACHE_RWFO - ldrlo r2, [r0] @ read for ownership - strlo r2, [r0] @ write for ownership -#endif blo 1b mov r0, #0 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer @@ -248,9 +236,6 @@ v6_dma_inv_range: v6_dma_clean_range: bic r0, r0, #D_CACHE_LINE_SIZE - 1 1: -#ifdef CONFIG_DMA_CACHE_RWFO - ldr r2, [r0] @ read for ownership -#endif #ifdef HARVARD_CACHE mcr p15, 0, r0, c7, c10, 1 @ clean D line #else @@ -269,10 +254,6 @@ v6_dma_clean_range: * - end - virtual end address of region */ ENTRY(v6_dma_flush_range) -#ifdef CONFIG_DMA_CACHE_RWFO - ldrb r2, [r0] @ read for ownership - strb r2, [r0] @ write for ownership -#endif bic r0, r0, #D_CACHE_LINE_SIZE - 1 1: #ifdef HARVARD_CACHE @@ -282,10 +263,6 @@ ENTRY(v6_dma_flush_range) #endif add r0, r0, #D_CACHE_LINE_SIZE cmp r0, r1 -#ifdef CONFIG_DMA_CACHE_RWFO - ldrblo r2, [r0] @ read for ownership - strblo r2, [r0] @ write for ownership -#endif blo 1b mov r0, #0 mcr p15, 0, r0, c7, c10, 4 @ drain write buffer @@ -301,13 +278,7 @@ ENTRY(v6_dma_map_area) add r1, r1, r0 teq r2, #DMA_FROM_DEVICE beq v6_dma_inv_range -#ifndef CONFIG_DMA_CACHE_RWFO b v6_dma_clean_range -#else - teq r2, #DMA_TO_DEVICE - beq v6_dma_clean_range - b v6_dma_flush_range -#endif ENDPROC(v6_dma_map_area) /* @@ -317,11 +288,9 @@ ENDPROC(v6_dma_map_area) * - dir - DMA direction */ ENTRY(v6_dma_unmap_area) -#ifndef CONFIG_DMA_CACHE_RWFO add r1, r1, r0 teq r2, #DMA_TO_DEVICE bne v6_dma_inv_range -#endif ret lr ENDPROC(v6_dma_unmap_area) diff --git a/arch/arm/mm/dma-mapping-nommu.c b/arch/arm/mm/dma-mapping-nommu.c index cfd9c933d2f09c..b94850b579952a 100644 --- a/arch/arm/mm/dma-mapping-nommu.c +++ b/arch/arm/mm/dma-mapping-nommu.c @@ -34,7 +34,7 @@ void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size, } void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, - const struct iommu_ops *iommu, bool coherent) + bool coherent) { if (IS_ENABLED(CONFIG_CPU_V7M)) { /* diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 5409225b4abc06..f68db05eba29fd 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -859,10 +859,7 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size, int i = 0; int order_idx = 0; - if (array_size <= PAGE_SIZE) - pages = kzalloc(array_size, GFP_KERNEL); - else - pages = vzalloc(array_size); + pages = kvzalloc(array_size, GFP_KERNEL); if (!pages) return NULL; @@ -1713,7 +1710,7 @@ void arm_iommu_detach_device(struct device *dev) EXPORT_SYMBOL_GPL(arm_iommu_detach_device); static void arm_setup_iommu_dma_ops(struct device *dev, u64 dma_base, u64 size, - const struct iommu_ops *iommu, bool coherent) + bool coherent) { struct dma_iommu_mapping *mapping; @@ -1748,7 +1745,7 @@ static void arm_teardown_iommu_dma_ops(struct device *dev) #else static void arm_setup_iommu_dma_ops(struct device *dev, u64 dma_base, u64 size, - const struct iommu_ops *iommu, bool coherent) + bool coherent) { } @@ -1757,7 +1754,7 @@ static void arm_teardown_iommu_dma_ops(struct device *dev) { } #endif /* CONFIG_ARM_DMA_USE_IOMMU */ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, - const struct iommu_ops *iommu, bool coherent) + bool coherent) { /* * Due to legacy code that sets the ->dma_coherent flag from a bus @@ -1776,8 +1773,8 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, if (dev->dma_ops) return; - if (iommu) - arm_setup_iommu_dma_ops(dev, dma_base, size, iommu, coherent); + if (device_iommu_mapped(dev)) + arm_setup_iommu_dma_ops(dev, dma_base, size, coherent); xen_setup_dma_ops(dev); dev->archdata.dma_ops_setup = true; diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index fef62e4a9edde6..e96fb40b9cc32a 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -278,6 +278,35 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, addr); + if (!(flags & FAULT_FLAG_USER)) + goto lock_mmap; + + vma = lock_vma_under_rcu(mm, addr); + if (!vma) + goto lock_mmap; + + if (!(vma->vm_flags & vm_flags)) { + vma_end_read(vma); + goto lock_mmap; + } + fault = handle_mm_fault(vma, addr, flags | FAULT_FLAG_VMA_LOCK, regs); + if (!(fault & (VM_FAULT_RETRY | VM_FAULT_COMPLETED))) + vma_end_read(vma); + + if (!(fault & VM_FAULT_RETRY)) { + count_vm_vma_lock_event(VMA_LOCK_SUCCESS); + goto done; + } + count_vm_vma_lock_event(VMA_LOCK_RETRY); + + /* Quick path to respond to signals */ + if (fault_signal_pending(fault, regs)) { + if (!user_mode(regs)) + goto no_context; + return 0; + } +lock_mmap: + retry: vma = lock_mm_and_find_vma(mm, addr, regs); if (unlikely(!vma)) { @@ -316,6 +345,7 @@ retry: } mmap_read_unlock(mm); +done: /* * Handle the "normal" case first - VM_FAULT_MAJOR diff --git a/arch/arm/mm/kasan_init.c b/arch/arm/mm/kasan_init.c index 24d71b5db62de4..111d4f703136e4 100644 --- a/arch/arm/mm/kasan_init.c +++ b/arch/arm/mm/kasan_init.c @@ -28,6 +28,12 @@ static pgd_t tmp_pgd_table[PTRS_PER_PGD] __initdata __aligned(PGD_SIZE); pmd_t tmp_pmd_table[PTRS_PER_PMD] __page_aligned_bss; +static __init void *kasan_alloc_block_raw(size_t size) +{ + return memblock_alloc_try_nid_raw(size, size, __pa(MAX_DMA_ADDRESS), + MEMBLOCK_ALLOC_NOLEAKTRACE, NUMA_NO_NODE); +} + static __init void *kasan_alloc_block(size_t size) { return memblock_alloc_try_nid(size, size, __pa(MAX_DMA_ADDRESS), @@ -50,7 +56,7 @@ static void __init kasan_pte_populate(pmd_t *pmdp, unsigned long addr, if (!pte_none(READ_ONCE(*ptep))) continue; - p = kasan_alloc_block(PAGE_SIZE); + p = kasan_alloc_block_raw(PAGE_SIZE); if (!p) { panic("%s failed to allocate shadow page for address 0x%lx\n", __func__, addr); diff --git a/arch/arm/tools/syscall.tbl b/arch/arm/tools/syscall.tbl index 584f9528c99644..b6c9e01e14f559 100644 --- a/arch/arm/tools/syscall.tbl +++ b/arch/arm/tools/syscall.tbl @@ -470,3 +470,8 @@ 454 common futex_wake sys_futex_wake 455 common futex_wait sys_futex_wait 456 common futex_requeue sys_futex_requeue +457 common statmount sys_statmount +458 common listmount sys_listmount +459 common lsm_get_self_attr sys_lsm_get_self_attr +460 common lsm_set_self_attr sys_lsm_set_self_attr +461 common lsm_list_modules sys_lsm_list_modules diff --git a/arch/arm/vdso/vgettimeofday.c b/arch/arm/vdso/vgettimeofday.c index a003beacac761c..3554aa35f1ba13 100644 --- a/arch/arm/vdso/vgettimeofday.c +++ b/arch/arm/vdso/vgettimeofday.c @@ -8,6 +8,7 @@ #include #include #include +#include int __vdso_clock_gettime(clockid_t clock, struct old_timespec32 *ts) diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index 7e8773a2d99d08..b68efe643a12ca 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -800,6 +800,24 @@ static struct undef_hook neon_support_hook[] = {{ .cpsr_mask = PSR_T_BIT, .cpsr_val = PSR_T_BIT, .fn = vfp_support_entry, +}, { + .instr_mask = 0xff000800, + .instr_val = 0xfc000800, + .cpsr_mask = 0, + .cpsr_val = 0, + .fn = vfp_support_entry, +}, { + .instr_mask = 0xff000800, + .instr_val = 0xfd000800, + .cpsr_mask = 0, + .cpsr_val = 0, + .fn = vfp_support_entry, +}, { + .instr_mask = 0xff000800, + .instr_val = 0xfe000800, + .cpsr_mask = 0, + .cpsr_val = 0, + .fn = vfp_support_entry, }}; static struct undef_hook vfp_support_hook = { diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 7b071a00425d2b..aa7c1d43513968 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -36,6 +36,7 @@ config ARM64 select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE select ARCH_HAS_PTE_DEVMAP select ARCH_HAS_PTE_SPECIAL + select ARCH_HAS_HW_PTE_YOUNG select ARCH_HAS_SETUP_DMA_OPS select ARCH_HAS_SET_DIRECT_MAP select ARCH_HAS_SET_MEMORY @@ -132,6 +133,7 @@ config ARM64 select GENERIC_ARCH_TOPOLOGY select GENERIC_CLOCKEVENTS_BROADCAST select GENERIC_CPU_AUTOPROBE + select GENERIC_CPU_DEVICES select GENERIC_CPU_VULNERABILITIES select GENERIC_EARLY_IOREMAP select GENERIC_IDLE_POLL_SETUP @@ -154,7 +156,7 @@ config ARM64 select HAVE_MOVE_PUD select HAVE_PCI select HAVE_ACPI_APEI if (ACPI && EFI) - select HAVE_ALIGNED_STRUCT_PAGE if SLUB + select HAVE_ALIGNED_STRUCT_PAGE select HAVE_ARCH_AUDITSYSCALL select HAVE_ARCH_BITREVERSE select HAVE_ARCH_COMPILER_H @@ -1037,8 +1039,12 @@ config ARM64_ERRATUM_2645198 If unsure, say Y. +config ARM64_WORKAROUND_SPECULATIVE_UNPRIV_LOAD + bool + config ARM64_ERRATUM_2966298 bool "Cortex-A520: 2966298: workaround for speculatively executed unprivileged load" + select ARM64_WORKAROUND_SPECULATIVE_UNPRIV_LOAD default y help This option adds the workaround for ARM Cortex-A520 erratum 2966298. @@ -1050,6 +1056,20 @@ config ARM64_ERRATUM_2966298 If unsure, say Y. +config ARM64_ERRATUM_3117295 + bool "Cortex-A510: 3117295: workaround for speculatively executed unprivileged load" + select ARM64_WORKAROUND_SPECULATIVE_UNPRIV_LOAD + default y + help + This option adds the workaround for ARM Cortex-A510 erratum 3117295. + + On an affected Cortex-A510 core, a speculatively executed unprivileged + load might leak data from a privileged level via a cache side channel. + + Work around this problem by executing a TLBI before returning to EL0. + + If unsure, say Y. + config CAVIUM_ERRATUM_22375 bool "Cavium erratum 22375, 24313" default y @@ -1519,15 +1539,15 @@ config XEN # include/linux/mmzone.h requires the following to be true: # -# MAX_ORDER + PAGE_SHIFT <= SECTION_SIZE_BITS +# MAX_PAGE_ORDER + PAGE_SHIFT <= SECTION_SIZE_BITS # -# so the maximum value of MAX_ORDER is SECTION_SIZE_BITS - PAGE_SHIFT: +# so the maximum value of MAX_PAGE_ORDER is SECTION_SIZE_BITS - PAGE_SHIFT: # -# | SECTION_SIZE_BITS | PAGE_SHIFT | max MAX_ORDER | default MAX_ORDER | -# ----+-------------------+--------------+-----------------+--------------------+ -# 4K | 27 | 12 | 15 | 10 | -# 16K | 27 | 14 | 13 | 11 | -# 64K | 29 | 16 | 13 | 13 | +# | SECTION_SIZE_BITS | PAGE_SHIFT | max MAX_PAGE_ORDER | default MAX_PAGE_ORDER | +# ----+-------------------+--------------+----------------------+-------------------------+ +# 4K | 27 | 12 | 15 | 10 | +# 16K | 27 | 14 | 13 | 11 | +# 64K | 29 | 16 | 13 | 13 | config ARCH_FORCE_MAX_ORDER int default "13" if ARM64_64K_PAGES @@ -1535,21 +1555,21 @@ config ARCH_FORCE_MAX_ORDER default "10" help The kernel page allocator limits the size of maximal physically - contiguous allocations. The limit is called MAX_ORDER and it + contiguous allocations. The limit is called MAX_PAGE_ORDER and it defines the maximal power of two of number of pages that can be allocated as a single contiguous block. This option allows overriding the default setting when ability to allocate very large blocks of physically contiguous memory is required. The maximal size of allocation cannot exceed the size of the - section, so the value of MAX_ORDER should satisfy + section, so the value of MAX_PAGE_ORDER should satisfy - MAX_ORDER + PAGE_SHIFT <= SECTION_SIZE_BITS + MAX_PAGE_ORDER + PAGE_SHIFT <= SECTION_SIZE_BITS Don't change if unsure. config UNMAP_KERNEL_AT_EL0 - bool "Unmap kernel when running in userspace (aka \"KAISER\")" if EXPERT + bool "Unmap kernel when running in userspace (KPTI)" if EXPERT default y help Speculation attacks against some high-performance processors can diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index 9a2d3723cd0fa9..47ecc4cff9d25b 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -200,7 +200,7 @@ endif endif vdso-install-y += arch/arm64/kernel/vdso/vdso.so.dbg -vdso-install-$(CONFIG_COMPAT_VDSO) += arch/arm64/kernel/vdso32/vdso.so.dbg:vdso32.so +vdso-install-$(CONFIG_COMPAT_VDSO) += arch/arm64/kernel/vdso32/vdso32.so.dbg include $(srctree)/scripts/Makefile.defconf diff --git a/arch/arm64/boot/Makefile b/arch/arm64/boot/Makefile index 1761f5972443fc..a5a7873711173b 100644 --- a/arch/arm64/boot/Makefile +++ b/arch/arm64/boot/Makefile @@ -44,7 +44,7 @@ EFI_ZBOOT_BFD_TARGET := elf64-littleaarch64 EFI_ZBOOT_MACH_TYPE := ARM64 EFI_ZBOOT_FORWARD_CFI := $(CONFIG_ARM64_BTI_KERNEL) -EFI_ZBOOT_OBJCOPY_FLAGS = --add-symbol zboot_code_size=0x$(shell \ +EFI_ZBOOT_OBJCOPY_FLAGS = --add-symbol zboot_code_size=0x$$( \ $(NM) vmlinux|grep _kernel_codesize|cut -d' ' -f1) include $(srctree)/drivers/firmware/efi/libstub/Makefile.zboot diff --git a/arch/arm64/boot/dts/allwinner/Makefile b/arch/arm64/boot/dts/allwinner/Makefile index 3aca6787a16798..91d505b385de5a 100644 --- a/arch/arm64/boot/dts/allwinner/Makefile +++ b/arch/arm64/boot/dts/allwinner/Makefile @@ -43,3 +43,4 @@ dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h616-bigtreetech-pi.dtb dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h616-orangepi-zero2.dtb dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h616-x96-mate.dtb dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h618-orangepi-zero3.dtb +dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h618-transpeed-8k618-t.dtb diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h618-orangepi-zero2w.dts b/arch/arm64/boot/dts/allwinner/sun50i-h618-orangepi-zero2w.dts new file mode 100644 index 00000000000000..21ca1977055d95 --- /dev/null +++ b/arch/arm64/boot/dts/allwinner/sun50i-h618-orangepi-zero2w.dts @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) 2023 Arm Ltd. + */ + +/dts-v1/; + +#include "sun50i-h616.dtsi" + +#include +#include +#include + +/ { + model = "OrangePi Zero 2W"; + compatible = "xunlong,orangepi-zero2w", "allwinner,sun50i-h618"; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + leds { + compatible = "gpio-leds"; + + led-0 { + function = LED_FUNCTION_STATUS; + color = ; + gpios = <&pio 2 13 GPIO_ACTIVE_HIGH>; /* PC13 */ + }; + }; + + reg_vcc5v: vcc5v { + /* board wide 5V supply directly from the USB-C socket */ + compatible = "regulator-fixed"; + regulator-name = "vcc-5v"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + }; + + reg_vcc3v3: vcc3v3 { + /* SY8089 DC/DC converter */ + compatible = "regulator-fixed"; + regulator-name = "vcc-3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <®_vcc5v>; + regulator-always-on; + }; +}; + +&ehci1 { + status = "okay"; +}; + +/* USB 2 & 3 are on the FPC connector (or the exansion board) */ + +&mmc0 { + cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */ + bus-width = <4>; + vmmc-supply = <®_vcc3v3>; + status = "okay"; +}; + +&ohci1 { + status = "okay"; +}; + +&pio { + vcc-pc-supply = <®_dldo1>; + vcc-pf-supply = <®_dldo1>; /* internally via VCC-IO */ + vcc-pg-supply = <®_aldo1>; + vcc-ph-supply = <®_dldo1>; /* internally via VCC-IO */ + vcc-pi-supply = <®_dldo1>; +}; + +&r_i2c { + status = "okay"; + + axp313: pmic@36 { + compatible = "x-powers,axp313a"; + reg = <0x36>; + #interrupt-cells = <1>; + interrupt-controller; + interrupt-parent = <&pio>; + interrupts = <2 9 IRQ_TYPE_LEVEL_LOW>; /* PC9 */ + + vin1-supply = <®_vcc5v>; + vin2-supply = <®_vcc5v>; + vin3-supply = <®_vcc5v>; + + regulators { + /* Supplies VCC-PLL and DRAM */ + reg_aldo1: aldo1 { + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc1v8"; + }; + + /* Supplies VCC-IO, so needs to be always on. */ + reg_dldo1: dldo1 { + regulator-always-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc3v3"; + }; + + reg_dcdc1: dcdc1 { + regulator-always-on; + regulator-min-microvolt = <810000>; + regulator-max-microvolt = <990000>; + regulator-name = "vdd-gpu-sys"; + }; + + reg_dcdc2: dcdc2 { + regulator-always-on; + regulator-min-microvolt = <810000>; + regulator-max-microvolt = <1100000>; + regulator-name = "vdd-cpu"; + }; + + reg_dcdc3: dcdc3 { + regulator-always-on; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-name = "vdd-dram"; + }; + }; + }; +}; + +&spi0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&spi0_pins>, <&spi0_cs0_pin>; + + flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <40000000>; + }; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_ph_pins>; + status = "okay"; +}; + +&usbotg { + /* + * PHY0 pins are connected to a USB-C socket, but a role switch + * is not implemented: both CC pins are pulled to GND. + * The VBUS pins power the device, so a fixed peripheral mode + * is the best choice. + * The board can be powered via GPIOs, in this case port0 *can* + * act as a host (with a cable/adapter ignoring CC), as VBUS is + * then provided by the GPIOs. Any user of this setup would + * need to adjust the DT accordingly: dr_mode set to "host", + * enabling OHCI0 and EHCI0. + */ + dr_mode = "peripheral"; + status = "okay"; +}; + +&usbphy { + usb1_vbus-supply = <®_vcc5v>; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h618-transpeed-8k618-t.dts b/arch/arm64/boot/dts/allwinner/sun50i-h618-transpeed-8k618-t.dts new file mode 100644 index 00000000000000..8ea1fd41aebaa0 --- /dev/null +++ b/arch/arm64/boot/dts/allwinner/sun50i-h618-transpeed-8k618-t.dts @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) 2023 Arm Ltd. + */ + +/dts-v1/; + +#include "sun50i-h616.dtsi" + +#include +#include + +/ { + model = "Transpeed 8K618-T"; + compatible = "transpeed,8k618-t", "allwinner,sun50i-h618"; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + reg_vcc5v: vcc5v { + /* board wide 5V supply directly from the DC input */ + compatible = "regulator-fixed"; + regulator-name = "vcc-5v"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + regulator-always-on; + }; + + reg_vcc3v3: vcc3v3 { + /* discrete 3.3V regulator */ + compatible = "regulator-fixed"; + regulator-name = "vcc-3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; +}; + +&ehci0 { + status = "okay"; +}; + +&ehci1 { + status = "okay"; +}; + +&ir { + status = "okay"; +}; + +&mmc0 { + vmmc-supply = <®_dldo1>; + cd-gpios = <&pio 8 16 GPIO_ACTIVE_LOW>; /* PI16 */ + bus-width = <4>; + status = "okay"; +}; + +&mmc2 { + vmmc-supply = <®_dldo1>; + vqmmc-supply = <®_aldo1>; + bus-width = <8>; + non-removable; + cap-mmc-hw-reset; + mmc-ddr-1_8v; + mmc-hs200-1_8v; + status = "okay"; +}; + +&ohci0 { + status = "okay"; +}; + +&ohci1 { + status = "okay"; +}; + +&r_i2c { + status = "okay"; + + axp313: pmic@36 { + compatible = "x-powers,axp313a"; + reg = <0x36>; + #interrupt-cells = <1>; + interrupt-controller; + + vin1-supply = <®_vcc5v>; + vin2-supply = <®_vcc5v>; + vin3-supply = <®_vcc5v>; + + regulators { + reg_aldo1: aldo1 { + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc-1v8-pll"; + }; + + reg_dldo1: dldo1 { + regulator-always-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc-3v3-io-mmc"; + }; + + reg_dcdc1: dcdc1 { + regulator-always-on; + regulator-min-microvolt = <810000>; + regulator-max-microvolt = <990000>; + regulator-name = "vdd-gpu-sys"; + }; + + reg_dcdc2: dcdc2 { + regulator-always-on; + regulator-min-microvolt = <810000>; + regulator-max-microvolt = <1100000>; + regulator-name = "vdd-cpu"; + }; + + reg_dcdc3: dcdc3 { + regulator-always-on; + regulator-min-microvolt = <1360000>; + regulator-max-microvolt = <1360000>; + regulator-name = "vdd-dram"; + }; + }; + }; +}; + +&pio { + vcc-pc-supply = <®_aldo1>; + vcc-pg-supply = <®_dldo1>; + vcc-ph-supply = <®_dldo1>; + vcc-pi-supply = <®_dldo1>; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_ph_pins>; + status = "okay"; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>; + uart-has-rtscts; + status = "okay"; +}; + +&usbotg { + dr_mode = "host"; /* USB A type receptable */ + status = "okay"; +}; + +&usbphy { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi b/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi index 439497ab967d9f..072fe20cfca087 100644 --- a/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi +++ b/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi @@ -59,6 +59,25 @@ }; }; + firmware { + svc { + compatible = "intel,stratix10-svc"; + method = "smc"; + memory-region = <&service_reserved>; + + fpga_mgr: fpga-mgr { + compatible = "intel,stratix10-soc-fpga-mgr"; + }; + }; + }; + + fpga-region { + compatible = "fpga-region"; + #address-cells = <0x2>; + #size-cells = <0x2>; + fpga-mgr = <&fpga_mgr>; + }; + pmu { compatible = "arm,armv8-pmuv3"; interrupts = <0 170 4>, @@ -125,7 +144,7 @@ }; }; - soc { + soc@0 { #address-cells = <1>; #size-cells = <1>; compatible = "simple-bus"; @@ -133,13 +152,6 @@ interrupt-parent = <&intc>; ranges = <0 0 0 0xffffffff>; - base_fpga_region { - #address-cells = <0x2>; - #size-cells = <0x2>; - compatible = "fpga-region"; - fpga-mgr = <&fpga_mgr>; - }; - clkmgr: clock-controller@ffd10000 { compatible = "intel,stratix10-clkmgr"; reg = <0xffd10000 0x1000>; @@ -510,6 +522,7 @@ resets = <&rst USB1_RESET>, <&rst USB1_OCP_RESET>; reset-names = "dwc2", "dwc2-ecc"; clocks = <&clkmgr STRATIX10_USB_CLK>; + clock-names = "otg"; iommus = <&smmu 7>; status = "disabled"; }; @@ -620,18 +633,6 @@ status = "disabled"; }; - - firmware { - svc { - compatible = "intel,stratix10-svc"; - method = "smc"; - memory-region = <&service_reserved>; - - fpga_mgr: fpga-mgr { - compatible = "intel,stratix10-soc-fpga-mgr"; - }; - }; - }; }; usbphy0: usbphy0 { diff --git a/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts b/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts index 468fcc7da0668a..26173f0b0051b6 100644 --- a/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts +++ b/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts @@ -51,7 +51,7 @@ regulator-max-microvolt = <330000>; }; - soc { + soc@0 { eccmgr { sdmmca-ecc@ff8c8c00 { compatible = "altr,socfpga-s10-sdmmc-ecc", @@ -66,14 +66,14 @@ }; &pinctrl0 { - i2c1_pmx_func: i2c1-pmx-func { + i2c1_pmx_func: i2c1-pmx-func-pins { pinctrl-single,pins = < 0x78 0x4 /* I2C1_SDA (IO6-B) PIN30SEL) */ 0x7c 0x4 /* I2C1_SCL (IO7-B) PIN31SEL */ >; }; - i2c1_pmx_func_gpio: i2c1-pmx-func-gpio { + i2c1_pmx_func_gpio: i2c1-pmx-func-gpio-pins { pinctrl-single,pins = < 0x78 0x8 /* I2C1_SDA (IO6-B) PIN30SEL) */ 0x7c 0x8 /* I2C1_SCL (IO7-B) PIN31SEL */ @@ -187,8 +187,6 @@ spi-max-frequency = <100000000>; m25p,fast-read; - cdns,page-size = <256>; - cdns,block-size = <16>; cdns,read-delay = <1>; cdns,tshsl-ns = <50>; cdns,tsd2d-ns = <50>; diff --git a/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk_nand.dts b/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk_nand.dts index 532164a6354c6a..81d0e914a77c43 100644 --- a/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk_nand.dts +++ b/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk_nand.dts @@ -51,7 +51,7 @@ regulator-max-microvolt = <330000>; }; - soc { + soc@0 { eccmgr { sdmmca-ecc@ff8c8c00 { compatible = "altr,socfpga-s10-sdmmc-ecc", @@ -102,7 +102,7 @@ &nand { status = "okay"; - flash@0 { + nand@0 { reg = <0>; #address-cells = <1>; #size-cells = <1>; @@ -176,8 +176,6 @@ spi-max-frequency = <100000000>; m25p,fast-read; - cdns,page-size = <256>; - cdns,block-size = <16>; cdns,read-delay = <1>; cdns,tshsl-ns = <50>; cdns,tsd2d-ns = <50>; diff --git a/arch/arm64/boot/dts/altera/socfpga_stratix10_swvp.dts b/arch/arm64/boot/dts/altera/socfpga_stratix10_swvp.dts index ff413f8e3b079d..0d837d3e65a563 100644 --- a/arch/arm64/boot/dts/altera/socfpga_stratix10_swvp.dts +++ b/arch/arm64/boot/dts/altera/socfpga_stratix10_swvp.dts @@ -80,8 +80,6 @@ &mmc { status = "okay"; - altr,dw-mshc-ciu-div = <0x3>; - altr,dw-mshc-sdr-timing = <0x0 0x3>; cap-sd-highspeed; cap-mmc-highspeed; broken-cd; diff --git a/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi b/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi index 998f5050795c6d..2ad1f8eef1996f 100644 --- a/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi +++ b/arch/arm64/boot/dts/amlogic/amlogic-c3.dtsi @@ -81,6 +81,12 @@ #size-cells = <2>; ranges = <0x0 0x0 0x0 0xfe000000 0x0 0x480000>; + watchdog@2100 { + compatible = "amlogic,c3-wdt", "amlogic,t7-wdt"; + reg = <0x0 0x2100 0x0 0x10>; + clocks = <&xtal>; + }; + periphs_pinctrl: pinctrl@4000 { compatible = "amlogic,c3-periphs-pinctrl"; #address-cells = <2>; diff --git a/arch/arm64/boot/dts/amlogic/meson-axg-jethome-jethub-j110-rev-2.dts b/arch/arm64/boot/dts/amlogic/meson-axg-jethome-jethub-j110-rev-2.dts index 0062667c4f65f9..8a18ce94845013 100644 --- a/arch/arm64/boot/dts/amlogic/meson-axg-jethome-jethub-j110-rev-2.dts +++ b/arch/arm64/boot/dts/amlogic/meson-axg-jethome-jethub-j110-rev-2.dts @@ -30,8 +30,20 @@ &uart_B { bluetooth { compatible = "realtek,rtl8822cs-bt"; - enable-gpios = <&gpio GPIOZ_7 GPIO_ACTIVE_HIGH>; + enable-gpios = <&gpio GPIOZ_7 GPIO_ACTIVE_HIGH>; host-wake-gpios = <&gpio GPIOZ_8 GPIO_ACTIVE_HIGH>; device-wake-gpios = <&gpio GPIOZ_6 GPIO_ACTIVE_HIGH>; }; }; + +&i2c_AO { + /* EEPROM on base board */ + eeprompd: eeprom@56 { + compatible = "atmel,24c64"; + reg = <0x56>; + pagesize = <0x20>; + label = "eeprompd"; + address-width = <0x10>; + vcc-supply = <&vddao_3v3>; + }; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-axg-jethome-jethub-j110-rev-3.dts b/arch/arm64/boot/dts/amlogic/meson-axg-jethome-jethub-j110-rev-3.dts index c2d22b00c1cd77..c356bd2cc63aaf 100644 --- a/arch/arm64/boot/dts/amlogic/meson-axg-jethome-jethub-j110-rev-3.dts +++ b/arch/arm64/boot/dts/amlogic/meson-axg-jethome-jethub-j110-rev-3.dts @@ -25,3 +25,15 @@ &sd_emmc_b { broken-cd;/* cd-gpios = <&gpio_ao GPIOAO_3 GPIO_ACTIVE_LOW>;*/ }; + +&i2c_AO { + /* EEPROM on base board */ + eeprompd: eeprom@56 { + compatible = "atmel,24c64"; + reg = <0x56>; + pagesize = <0x20>; + label = "eeprompd"; + address-width = <0x10>; + vcc-supply = <&vddao_3v3>; + }; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-axg-s400.dts b/arch/arm64/boot/dts/amlogic/meson-axg-s400.dts index df16eead2c8030..c8905663bc7541 100644 --- a/arch/arm64/boot/dts/amlogic/meson-axg-s400.dts +++ b/arch/arm64/boot/dts/amlogic/meson-axg-s400.dts @@ -66,7 +66,6 @@ VDDA-supply = <&vcc_3v3>; VDDP-supply = <&vcc_3v3>; VDDD-supply = <&vcc_3v3>; - status = "okay"; sound-name-prefix = "Linein"; }; @@ -75,14 +74,12 @@ compatible = "everest,es7154"; VDD-supply = <&vcc_3v3>; PVDD-supply = <&vcc_5v>; - status = "okay"; sound-name-prefix = "Lineout"; }; spdif_dit: audio-codec-2 { #sound-dai-cells = <0>; compatible = "linux,spdif-dit"; - status = "okay"; sound-name-prefix = "DIT"; }; @@ -91,14 +88,12 @@ compatible = "dmic-codec"; num-channels = <7>; wakeup-delay-ms = <50>; - status = "okay"; sound-name-prefix = "MIC"; }; spdif_dir: audio-codec-4 { #sound-dai-cells = <0>; compatible = "linux,spdif-dir"; - status = "okay"; sound-name-prefix = "DIR"; }; diff --git a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi index a49aa62e3f9fb7..7e5ac9db93f8a7 100644 --- a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi @@ -432,6 +432,27 @@ }; }; + nand_all_pins: nand-all-pins { + mux { + groups = "emmc_nand_d0", + "emmc_nand_d1", + "emmc_nand_d2", + "emmc_nand_d3", + "emmc_nand_d4", + "emmc_nand_d5", + "emmc_nand_d6", + "emmc_nand_d7", + "nand_ce0", + "nand_ale", + "nand_cle", + "nand_wen_clk", + "nand_ren_wr"; + function = "nand"; + input-enable; + bias-pull-up; + }; + }; + emmc_ds_pins: emmc_ds { mux { groups = "emmc_ds"; @@ -1913,6 +1934,8 @@ reg = <0x0 0x7800 0x0 0x100>, <0x0 0x7000 0x0 0x800>; reg-names = "nfc", "emmc"; + pinctrl-0 = <&nand_all_pins>; + pinctrl-names = "default"; #address-cells = <1>; #size-cells = <0>; interrupts = ; diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts index 0ad0c2b7dfefcb..4c4550dd471127 100644 --- a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts @@ -45,7 +45,6 @@ compatible = "dmic-codec"; num-channels = <2>; wakeup-delay-ms = <50>; - status = "okay"; sound-name-prefix = "MIC"; }; diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts index 4969a76460fa63..9b55982b6a6bbd 100644 --- a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts +++ b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts @@ -22,7 +22,6 @@ spdif_dit: audio-codec-1 { #sound-dai-cells = <0>; compatible = "linux,spdif-dit"; - status = "okay"; sound-name-prefix = "DIT"; }; diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi-cm4.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi-cm4.dtsi index 995ce10d5c8171..08c33ec7e9f1de 100644 --- a/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi-cm4.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi-cm4.dtsi @@ -369,7 +369,7 @@ bluetooth { compatible = "realtek,rtl8822cs-bt"; - enable-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>; + enable-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>; host-wake-gpios = <&gpio GPIOX_19 GPIO_ACTIVE_HIGH>; device-wake-gpios = <&gpio GPIOX_18 GPIO_ACTIVE_HIGH>; }; diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi.dtsi index 0a6a12808568fc..4b8db872bbf315 100644 --- a/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-g12b-bananapi.dtsi @@ -487,7 +487,7 @@ bluetooth { compatible = "realtek,rtl8822cs-bt"; - enable-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>; + enable-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>; host-wake-gpios = <&gpio GPIOX_19 GPIO_ACTIVE_HIGH>; device-wake-gpios = <&gpio GPIOX_18 GPIO_ACTIVE_HIGH>; }; diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-gtking.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-gtking.dts index 8fc2e143cb5407..0da386cabe1a5a 100644 --- a/arch/arm64/boot/dts/amlogic/meson-g12b-gtking.dts +++ b/arch/arm64/boot/dts/amlogic/meson-g12b-gtking.dts @@ -22,7 +22,6 @@ spdif_dit: audio-codec-1 { #sound-dai-cells = <0>; compatible = "linux,spdif-dit"; - status = "okay"; sound-name-prefix = "DIT"; }; diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-ugoos-am6.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-ugoos-am6.dts index ce548b37329601..6396f190d703ed 100644 --- a/arch/arm64/boot/dts/amlogic/meson-g12b-ugoos-am6.dts +++ b/arch/arm64/boot/dts/amlogic/meson-g12b-ugoos-am6.dts @@ -17,7 +17,6 @@ spdif_dit: audio-codec-1 { #sound-dai-cells = <0>; compatible = "linux,spdif-dit"; - status = "okay"; sound-name-prefix = "DIT"; }; diff --git a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi index 18f7b730289e4a..e59c3c92b1e7c6 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi @@ -26,7 +26,6 @@ spdif_dit: audio-codec-0 { #sound-dai-cells = <0>; compatible = "linux,spdif-dit"; - status = "okay"; sound-name-prefix = "DIT"; }; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-kii-pro.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-kii-pro.dts index e238f1f1012419..f28452b9f00fdb 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxbb-kii-pro.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-kii-pro.dts @@ -18,7 +18,6 @@ spdif_dit: audio-codec-0 { #sound-dai-cells = <0>; compatible = "linux,spdif-dit"; - status = "okay"; sound-name-prefix = "DIT"; }; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-p200.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-p200.dts index 292c718ee19c58..591455c50e8866 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxbb-p200.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-p200.dts @@ -18,7 +18,6 @@ spdif_dit: audio-codec-0 { #sound-dai-cells = <0>; compatible = "linux,spdif-dit"; - status = "okay"; sound-name-prefix = "DIT"; }; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi index e8303089bff69d..74df3253423189 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi @@ -21,7 +21,6 @@ spdif_dit: audio-codec-0 { #sound-dai-cells = <0>; compatible = "linux,spdif-dit"; - status = "okay"; sound-name-prefix = "DIT"; }; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-play2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-play2.dts index e1b74b17491523..376760d8676615 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-play2.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-play2.dts @@ -17,7 +17,6 @@ spdif_dit: audio-codec-0 { #sound-dai-cells = <0>; compatible = "linux,spdif-dit"; - status = "okay"; sound-name-prefix = "DIT"; }; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts index 7d525bdb0e062e..ad2dd4ad0a313f 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts @@ -28,7 +28,6 @@ spdif_dit: audio-codec-0 { #sound-dai-cells = <0>; compatible = "linux,spdif-dit"; - status = "okay"; sound-name-prefix = "DIT"; }; diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-rbox-pro.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-rbox-pro.dts index 50d49aec41bdb5..d05dde8da5c566 100644 --- a/arch/arm64/boot/dts/amlogic/meson-gxm-rbox-pro.dts +++ b/arch/arm64/boot/dts/amlogic/meson-gxm-rbox-pro.dts @@ -37,7 +37,6 @@ spdif_dit: audio-codec-0 { #sound-dai-cells = <0>; compatible = "linux,spdif-dit"; - status = "okay"; sound-name-prefix = "DIT"; }; diff --git a/arch/arm64/boot/dts/amlogic/meson-s4-s805x2-aq222.dts b/arch/arm64/boot/dts/amlogic/meson-s4-s805x2-aq222.dts index c1f322c7398261..983caddc409c35 100644 --- a/arch/arm64/boot/dts/amlogic/meson-s4-s805x2-aq222.dts +++ b/arch/arm64/boot/dts/amlogic/meson-s4-s805x2-aq222.dts @@ -15,7 +15,7 @@ #size-cells = <2>; aliases { - serial0 = &uart_B; + serial0 = &uart_b; }; memory@0 { @@ -23,9 +23,20 @@ reg = <0x0 0x0 0x0 0x40000000>; }; + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + /* 52 MiB reserved for ARM Trusted Firmware */ + secmon_reserved: secmon@5000000 { + reg = <0x0 0x05000000 0x0 0x3400000>; + no-map; + }; + }; }; -&uart_B { +&uart_b { status = "okay"; }; @@ -34,3 +45,48 @@ pinctrl-0 = <&remote_pins>; pinctrl-names = "default"; }; + +&nand { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + pinctrl-0 = <&nand_pins>; + pinctrl-names = "default"; + + nand@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + + nand-on-flash-bbt; + + partition@0 { + label = "boot"; + reg = <0x0 0x00200000>; + }; + partition@200000 { + label = "env"; + reg = <0x00200000 0x00400000>; + }; + partition@600000 { + label = "system"; + reg = <0x00600000 0x00a00000>; + }; + partition@1000000 { + label = "rootfs"; + reg = <0x01000000 0x03000000>; + }; + partition@4000000 { + label = "media"; + reg = <0x04000000 0x8000000>; + }; + }; +}; + +&spicc0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&spicc0_pins_x>; + cs-gpios = <&gpio GPIOX_10 GPIO_ACTIVE_LOW>; +}; diff --git a/arch/arm64/boot/dts/amlogic/meson-s4.dtsi b/arch/arm64/boot/dts/amlogic/meson-s4.dtsi index e0cfc54ebccb1f..ce90b35686a212 100644 --- a/arch/arm64/boot/dts/amlogic/meson-s4.dtsi +++ b/arch/arm64/boot/dts/amlogic/meson-s4.dtsi @@ -6,6 +6,10 @@ #include #include #include +#include +#include +#include +#include / { cpus { @@ -92,6 +96,44 @@ #size-cells = <2>; ranges = <0x0 0x0 0x0 0xfe000000 0x0 0x480000>; + clkc_periphs: clock-controller@0 { + compatible = "amlogic,s4-peripherals-clkc"; + reg = <0x0 0x0 0x0 0x49c>; + clocks = <&clkc_pll CLKID_FCLK_DIV2>, + <&clkc_pll CLKID_FCLK_DIV2P5>, + <&clkc_pll CLKID_FCLK_DIV3>, + <&clkc_pll CLKID_FCLK_DIV4>, + <&clkc_pll CLKID_FCLK_DIV5>, + <&clkc_pll CLKID_FCLK_DIV7>, + <&clkc_pll CLKID_HIFI_PLL>, + <&clkc_pll CLKID_GP0_PLL>, + <&clkc_pll CLKID_MPLL0>, + <&clkc_pll CLKID_MPLL1>, + <&clkc_pll CLKID_MPLL2>, + <&clkc_pll CLKID_MPLL3>, + <&clkc_pll CLKID_HDMI_PLL>, + <&xtal>; + clock-names = "fclk_div2", "fclk_div2p5", "fclk_div3", + "fclk_div4", "fclk_div5", "fclk_div7", + "hifi_pll", "gp0_pll", "mpll0", "mpll1", + "mpll2", "mpll3", "hdmi_pll", "xtal"; + #clock-cells = <1>; + }; + + clkc_pll: clock-controller@8000 { + compatible = "amlogic,s4-pll-clkc"; + reg = <0x0 0x8000 0x0 0x1e8>; + clocks = <&xtal>; + clock-names = "xtal"; + #clock-cells = <1>; + }; + + watchdog@2100 { + compatible = "amlogic,s4-wdt", "amlogic,t7-wdt"; + reg = <0x0 0x2100 0x0 0x10>; + clocks = <&xtal>; + }; + periphs_pinctrl: pinctrl@4000 { compatible = "amlogic,meson-s4-periphs-pinctrl"; #address-cells = <2>; @@ -114,6 +156,187 @@ bias-disable; }; }; + + i2c0_pins1: i2c0-pins1 { + mux { + groups = "i2c0_sda", + "i2c0_scl"; + function = "i2c0"; + drive-strength-microamp = <3000>; + bias-disable; + }; + }; + + i2c1_pins1: i2c1-pins1 { + mux { + groups = "i2c1_sda_c", + "i2c1_scl_c"; + function = "i2c1"; + drive-strength-microamp = <3000>; + bias-disable; + }; + }; + + i2c1_pins2: i2c1-pins2 { + mux { + groups = "i2c1_sda_d", + "i2c1_scl_d"; + function = "i2c1"; + drive-strength-microamp = <3000>; + bias-disable; + }; + }; + + i2c1_pins3: i2c1-pins3 { + mux { + groups = "i2c1_sda_h", + "i2c1_scl_h"; + function = "i2c1"; + drive-strength-microamp = <3000>; + bias-disable; + }; + }; + + i2c1_pins4: i2c1-pins4 { + mux { + groups = "i2c1_sda_x", + "i2c1_scl_x"; + function = "i2c1"; + drive-strength-microamp = <3000>; + bias-disable; + }; + }; + + i2c2_pins1: i2c2-pins1 { + mux { + groups = "i2c2_sda_d", + "i2c2_scl_d"; + function = "i2c2"; + drive-strength-microamp = <3000>; + bias-disable; + }; + }; + + i2c2_pins2: i2c2-pins2 { + mux { + groups = "i2c2_sda_h8", + "i2c2_scl_h9"; + function = "i2c2"; + drive-strength-microamp = <3000>; + bias-disable; + }; + }; + + i2c2_pins3: i2c2-pins3 { + mux { + groups = "i2c2_sda_h0", + "i2c2_scl_h1"; + function = "i2c2"; + drive-strength-microamp = <3000>; + bias-disable; + }; + }; + + i2c3_pins1: i2c3-pins1 { + mux { + groups = "i2c3_sda_x", + "i2c3_scl_x"; + function = "i2c3"; + drive-strength-microamp = <3000>; + bias-disable; + }; + }; + + i2c3_pins2: i2c3-pins2 { + mux { + groups = "i2c3_sda_z", + "i2c3_scl_z"; + function = "i2c3"; + drive-strength-microamp = <3000>; + bias-disable; + }; + }; + + i2c4_pins1: i2c4-pins1 { + mux { + groups = "i2c4_sda_c", + "i2c4_scl_c"; + function = "i2c4"; + drive-strength-microamp = <3000>; + bias-disable; + }; + }; + + i2c4_pins2: i2c4-pins2 { + mux { + groups = "i2c4_sda_d", + "i2c4_scl_d"; + function = "i2c4"; + drive-strength-microamp = <3000>; + bias-disable; + }; + }; + + i2c4_pins3: i2c4-pins3 { + mux { + groups = "i2c4_sda_z", + "i2c4_scl_z"; + function = "i2c4"; + drive-strength-microamp = <3000>; + bias-disable; + }; + }; + + nand_pins: nand-pins { + mux { + groups = "emmc_nand_d0", + "emmc_nand_d1", + "emmc_nand_d2", + "emmc_nand_d3", + "emmc_nand_d4", + "emmc_nand_d5", + "emmc_nand_d6", + "emmc_nand_d7", + "nand_ce0", + "nand_ale", + "nand_cle", + "nand_wen_clk", + "nand_ren_wr"; + function = "nand"; + input-enable; + }; + }; + + spicc0_pins_x: spicc0-pins_x { + mux { + groups = "spi_a_mosi_x", + "spi_a_miso_x", + "spi_a_clk_x"; + function = "spi_a"; + drive-strength-microamp = <3000>; + }; + }; + + spicc0_pins_h: spicc0-pins-h { + mux { + groups = "spi_a_mosi_h", + "spi_a_miso_h", + "spi_a_clk_h"; + function = "spi_a"; + drive-strength-microamp = <3000>; + }; + }; + + spicc0_pins_z: spicc0-pins-z { + mux { + groups = "spi_a_mosi_z", + "spi_a_miso_z", + "spi_a_clk_z"; + function = "spi_a"; + drive-strength-microamp = <3000>; + }; + }; + }; gpio_intc: interrupt-controller@4080 { @@ -126,14 +349,120 @@ <10 11 12 13 14 15 16 17 18 19 20 21>; }; - uart_B: serial@7a000 { + eth_phy: mdio-multiplexer@28000 { + compatible = "amlogic,g12a-mdio-mux"; + reg = <0x0 0x28000 0x0 0xa4>; + + #address-cells = <1>; + #size-cells = <0>; + clocks = <&clkc_periphs CLKID_ETHPHY>, + <&xtal>, + <&clkc_pll CLKID_MPLL_50M>; + clock-names = "pclk", "clkin0", "clkin1"; + mdio-parent-bus = <&mdio0>; + + ext_mdio: mdio@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + }; + + int_mdio: mdio@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + internal_ephy: ethernet-phy@8 { + compatible = "ethernet-phy-id0180.3301", + "ethernet-phy-ieee802.3-c22"; + interrupts = ; + reg = <8>; + max-speed = <100>; + }; + }; + }; + + spicc0: spi@50000 { + compatible = "amlogic,meson-g12a-spicc"; + reg = <0x0 0x50000 0x0 0x44>; + interrupts = ; + clocks = <&clkc_periphs CLKID_SPICC0>, + <&clkc_periphs CLKID_SPICC0_EN>; + clock-names = "core", "pclk"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c0: i2c@66000 { + compatible = "amlogic,meson-axg-i2c"; + reg = <0x0 0x66000 0x0 0x20>; + interrupts = ; + clocks = <&clkc_periphs CLKID_I2C_M_A>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c1: i2c@68000 { + compatible = "amlogic,meson-axg-i2c"; + reg = <0x0 0x68000 0x0 0x20>; + interrupts = ; + clocks = <&clkc_periphs CLKID_I2C_M_B>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c2: i2c@6a000 { + compatible = "amlogic,meson-axg-i2c"; + reg = <0x0 0x6a000 0x0 0x20>; + interrupts = ; + clocks = <&clkc_periphs CLKID_I2C_M_C>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c3: i2c@6c000 { + compatible = "amlogic,meson-axg-i2c"; + reg = <0x0 0x6c000 0x0 0x20>; + interrupts = ; + clocks = <&clkc_periphs CLKID_I2C_M_D>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c4: i2c@6e000 { + compatible = "amlogic,meson-axg-i2c"; + reg = <0x0 0x6e000 0x0 0x20>; + interrupts = ; + clocks = <&clkc_periphs CLKID_I2C_M_E>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + nand: nand-controller@8c800 { + compatible = "amlogic,meson-axg-nfc"; + reg = <0x0 0x8c800 0x0 0x100>, <0x0 0x8c000 0x0 0x4>; + reg-names = "nfc", "emmc"; + interrupts = ; + clocks = <&clkc_periphs CLKID_SD_EMMC_C>, + <&clkc_pll CLKID_FCLK_DIV2>; + clock-names = "core", "device"; + status = "disabled"; + }; + + uart_b: serial@7a000 { compatible = "amlogic,meson-s4-uart", "amlogic,meson-ao-uart"; reg = <0x0 0x7a000 0x0 0x18>; interrupts = ; - status = "disabled"; - clocks = <&xtal>, <&xtal>, <&xtal>; + clocks = <&xtal>, <&clkc_periphs CLKID_UART_B>, <&xtal>; clock-names = "xtal", "pclk", "baud"; + status = "disabled"; }; reset: reset-controller@2000 { @@ -154,5 +483,30 @@ reg = <0x0 0x440788 0x0 0x0c>; }; }; + + ethmac: ethernet@fdc00000 { + compatible = "amlogic,meson-axg-dwmac", + "snps,dwmac-3.70a", + "snps,dwmac"; + reg = <0x0 0xfdc00000 0x0 0x10000>, + <0x0 0xfe024000 0x0 0x8>; + + interrupts = ; + interrupt-names = "macirq"; + power-domains = <&pwrc PWRC_S4_ETH_ID>; + clocks = <&clkc_periphs CLKID_ETH>, + <&clkc_pll CLKID_FCLK_DIV2>, + <&clkc_pll CLKID_MPLL2>; + clock-names = "stmmaceth", "clkin0", "clkin1"; + rx-fifo-depth = <4096>; + tx-fifo-depth = <2048>; + status = "disabled"; + + mdio0: mdio { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,dwmac-mdio"; + }; + }; }; }; diff --git a/arch/arm64/boot/dts/amlogic/meson-sm1-sei610.dts b/arch/arm64/boot/dts/amlogic/meson-sm1-sei610.dts index 095579c55f18e3..109932068dbe6c 100644 --- a/arch/arm64/boot/dts/amlogic/meson-sm1-sei610.dts +++ b/arch/arm64/boot/dts/amlogic/meson-sm1-sei610.dts @@ -32,7 +32,6 @@ compatible = "dmic-codec"; num-channels = <2>; wakeup-delay-ms = <50>; - status = "okay"; sound-name-prefix = "MIC"; }; diff --git a/arch/arm64/boot/dts/arm/juno-base.dtsi b/arch/arm64/boot/dts/arm/juno-base.dtsi index 8b4d280b1e7e78..b897f5542c0a1c 100644 --- a/arch/arm64/boot/dts/arm/juno-base.dtsi +++ b/arch/arm64/boot/dts/arm/juno-base.dtsi @@ -747,7 +747,7 @@ }; thermal-zones { - pmic { + pmic-thermal { polling-delay = <1000>; polling-delay-passive = <100>; thermal-sensors = <&scpi_sensors0 0>; @@ -760,7 +760,7 @@ }; }; - soc { + soc-thermal { polling-delay = <1000>; polling-delay-passive = <100>; thermal-sensors = <&scpi_sensors0 3>; @@ -773,28 +773,28 @@ }; }; - big_cluster_thermal_zone: big-cluster { + big_cluster_thermal_zone: big-cluster-thermal { polling-delay = <1000>; polling-delay-passive = <100>; thermal-sensors = <&scpi_sensors0 21>; status = "disabled"; }; - little_cluster_thermal_zone: little-cluster { + little_cluster_thermal_zone: little-cluster-thermal { polling-delay = <1000>; polling-delay-passive = <100>; thermal-sensors = <&scpi_sensors0 22>; status = "disabled"; }; - gpu0_thermal_zone: gpu0 { + gpu0_thermal_zone: gpu0-thermal { polling-delay = <1000>; polling-delay-passive = <100>; thermal-sensors = <&scpi_sensors0 23>; status = "disabled"; }; - gpu1_thermal_zone: gpu1 { + gpu1_thermal_zone: gpu1-thermal { polling-delay = <1000>; polling-delay-passive = <100>; thermal-sensors = <&scpi_sensors0 24>; diff --git a/arch/arm64/boot/dts/arm/juno-scmi.dtsi b/arch/arm64/boot/dts/arm/juno-scmi.dtsi index ec85cd2c733cec..31929e2377d8a4 100644 --- a/arch/arm64/boot/dts/arm/juno-scmi.dtsi +++ b/arch/arm64/boot/dts/arm/juno-scmi.dtsi @@ -76,27 +76,27 @@ }; thermal-zones { - pmic { + pmic-thermal { thermal-sensors = <&scmi_sensors0 0>; }; - soc { + soc-thermal { thermal-sensors = <&scmi_sensors0 3>; }; - big-cluster { + big-cluster-thermal { thermal-sensors = <&scmi_sensors0 21>; }; - little-cluster { + little-cluster-thermal { thermal-sensors = <&scmi_sensors0 22>; }; - gpu0 { + gpu0-thermal { thermal-sensors = <&scmi_sensors0 23>; }; - gpu1 { + gpu1-thermal { thermal-sensors = <&scmi_sensors0 24>; }; }; diff --git a/arch/arm64/boot/dts/exynos/Makefile b/arch/arm64/boot/dts/exynos/Makefile index 6e4ba69268e50e..d7f2191c2cdbe9 100644 --- a/arch/arm64/boot/dts/exynos/Makefile +++ b/arch/arm64/boot/dts/exynos/Makefile @@ -1,8 +1,11 @@ # SPDX-License-Identifier: GPL-2.0 +subdir-y += google + dtb-$(CONFIG_ARCH_EXYNOS) += \ exynos5433-tm2.dtb \ exynos5433-tm2e.dtb \ exynos7-espresso.dtb \ exynos7885-jackpotlte.dtb \ exynos850-e850-96.dtb \ - exynosautov9-sadk.dtb + exynosautov9-sadk.dtb \ + exynosautov920-sadk.dtb diff --git a/arch/arm64/boot/dts/exynos/exynos5433.dtsi b/arch/arm64/boot/dts/exynos/exynos5433.dtsi index 91ae0462a706a6..7fbbec04bff037 100644 --- a/arch/arm64/boot/dts/exynos/exynos5433.dtsi +++ b/arch/arm64/boot/dts/exynos/exynos5433.dtsi @@ -361,7 +361,8 @@ ranges = <0x0 0x0 0x0 0x18000000>; chipid@10000000 { - compatible = "samsung,exynos4210-chipid"; + compatible = "samsung,exynos5433-chipid", + "samsung,exynos4210-chipid"; reg = <0x10000000 0x100>; }; @@ -850,7 +851,8 @@ reg = <0x10580000 0x1a20>, <0x11090000 0x100>; wakeup-interrupt-controller { - compatible = "samsung,exynos7-wakeup-eint"; + compatible = "samsung,exynos5433-wakeup-eint", + "samsung,exynos7-wakeup-eint"; interrupts = ; }; }; @@ -1546,7 +1548,7 @@ }; adc: adc@14d10000 { - compatible = "samsung,exynos7-adc"; + compatible = "samsung,exynos5433-adc", "samsung,exynos7-adc"; reg = <0x14d10000 0x100>; interrupts = ; clock-names = "adc"; @@ -1556,7 +1558,7 @@ }; i2s1: i2s@14d60000 { - compatible = "samsung,exynos7-i2s"; + compatible = "samsung,exynos5433-i2s", "samsung,exynos7-i2s"; reg = <0x14d60000 0x100>; dmas = <&pdma0 31>, <&pdma0 30>; dma-names = "tx", "rx"; @@ -1571,7 +1573,7 @@ }; pwm: pwm@14dd0000 { - compatible = "samsung,exynos4210-pwm"; + compatible = "samsung,exynos5433-pwm", "samsung,exynos4210-pwm"; reg = <0x14dd0000 0x100>; interrupts = , , @@ -1586,7 +1588,8 @@ }; hsi2c_0: i2c@14e40000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "samsung,exynos5433-hsi2c", + "samsung,exynos7-hsi2c"; reg = <0x14e40000 0x1000>; interrupts = ; #address-cells = <1>; @@ -1599,7 +1602,8 @@ }; hsi2c_1: i2c@14e50000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "samsung,exynos5433-hsi2c", + "samsung,exynos7-hsi2c"; reg = <0x14e50000 0x1000>; interrupts = ; #address-cells = <1>; @@ -1612,7 +1616,8 @@ }; hsi2c_2: i2c@14e60000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "samsung,exynos5433-hsi2c", + "samsung,exynos7-hsi2c"; reg = <0x14e60000 0x1000>; interrupts = ; #address-cells = <1>; @@ -1625,7 +1630,8 @@ }; hsi2c_3: i2c@14e70000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "samsung,exynos5433-hsi2c", + "samsung,exynos7-hsi2c"; reg = <0x14e70000 0x1000>; interrupts = ; #address-cells = <1>; @@ -1638,7 +1644,8 @@ }; hsi2c_4: i2c@14ec0000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "samsung,exynos5433-hsi2c", + "samsung,exynos7-hsi2c"; reg = <0x14ec0000 0x1000>; interrupts = ; #address-cells = <1>; @@ -1651,7 +1658,8 @@ }; hsi2c_5: i2c@14ed0000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "samsung,exynos5433-hsi2c", + "samsung,exynos7-hsi2c"; reg = <0x14ed0000 0x1000>; interrupts = ; #address-cells = <1>; @@ -1664,7 +1672,8 @@ }; hsi2c_6: i2c@14ee0000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "samsung,exynos5433-hsi2c", + "samsung,exynos7-hsi2c"; reg = <0x14ee0000 0x1000>; interrupts = ; #address-cells = <1>; @@ -1677,7 +1686,8 @@ }; hsi2c_7: i2c@14ef0000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "samsung,exynos5433-hsi2c", + "samsung,exynos7-hsi2c"; reg = <0x14ef0000 0x1000>; interrupts = ; #address-cells = <1>; @@ -1690,7 +1700,8 @@ }; hsi2c_8: i2c@14d90000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "samsung,exynos5433-hsi2c", + "samsung,exynos7-hsi2c"; reg = <0x14d90000 0x1000>; interrupts = ; #address-cells = <1>; @@ -1703,7 +1714,8 @@ }; hsi2c_9: i2c@14da0000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "samsung,exynos5433-hsi2c", + "samsung,exynos7-hsi2c"; reg = <0x14da0000 0x1000>; interrupts = ; #address-cells = <1>; @@ -1716,7 +1728,8 @@ }; hsi2c_10: i2c@14de0000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "samsung,exynos5433-hsi2c", + "samsung,exynos7-hsi2c"; reg = <0x14de0000 0x1000>; interrupts = ; #address-cells = <1>; @@ -1729,7 +1742,8 @@ }; hsi2c_11: i2c@14df0000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "samsung,exynos5433-hsi2c", + "samsung,exynos7-hsi2c"; reg = <0x14df0000 0x1000>; interrupts = ; #address-cells = <1>; @@ -1820,7 +1834,8 @@ }; mshc_0: mmc@15540000 { - compatible = "samsung,exynos7-dw-mshc-smu"; + compatible = "samsung,exynos5433-dw-mshc-smu", + "samsung,exynos7-dw-mshc-smu"; interrupts = ; #address-cells = <1>; #size-cells = <0>; @@ -1833,7 +1848,8 @@ }; mshc_1: mmc@15550000 { - compatible = "samsung,exynos7-dw-mshc-smu"; + compatible = "samsung,exynos5433-dw-mshc-smu", + "samsung,exynos7-dw-mshc-smu"; interrupts = ; #address-cells = <1>; #size-cells = <0>; @@ -1846,7 +1862,8 @@ }; mshc_2: mmc@15560000 { - compatible = "samsung,exynos7-dw-mshc-smu"; + compatible = "samsung,exynos5433-dw-mshc-smu", + "samsung,exynos7-dw-mshc-smu"; interrupts = ; #address-cells = <1>; #size-cells = <0>; @@ -1897,7 +1914,8 @@ }; i2s0: i2s@11440000 { - compatible = "samsung,exynos7-i2s"; + compatible = "samsung,exynos5433-i2s", + "samsung,exynos7-i2s"; reg = <0x11440000 0x100>; dmas = <&adma 0>, <&adma 2>; dma-names = "tx", "rx"; diff --git a/arch/arm64/boot/dts/exynos/exynos7.dtsi b/arch/arm64/boot/dts/exynos/exynos7.dtsi index 6ed80ddf336956..9cb6bd61262e15 100644 --- a/arch/arm64/boot/dts/exynos/exynos7.dtsi +++ b/arch/arm64/boot/dts/exynos/exynos7.dtsi @@ -128,7 +128,8 @@ ranges = <0 0 0 0x18000000>; chipid@10000000 { - compatible = "samsung,exynos4210-chipid"; + compatible = "samsung,exynos7-chipid", + "samsung,exynos4210-chipid"; reg = <0x10000000 0x100>; }; @@ -279,7 +280,7 @@ }; serial_0: serial@13630000 { - compatible = "samsung,exynos4210-uart"; + compatible = "samsung,exynos7-uart", "samsung,exynos4210-uart"; reg = <0x13630000 0x100>; interrupts = ; clocks = <&clock_peric0 PCLK_UART0>, @@ -289,7 +290,7 @@ }; serial_1: serial@14c20000 { - compatible = "samsung,exynos4210-uart"; + compatible = "samsung,exynos7-uart", "samsung,exynos4210-uart"; reg = <0x14c20000 0x100>; interrupts = ; clocks = <&clock_peric1 PCLK_UART1>, @@ -299,7 +300,7 @@ }; serial_2: serial@14c30000 { - compatible = "samsung,exynos4210-uart"; + compatible = "samsung,exynos7-uart", "samsung,exynos4210-uart"; reg = <0x14c30000 0x100>; interrupts = ; clocks = <&clock_peric1 PCLK_UART2>, @@ -309,7 +310,7 @@ }; serial_3: serial@14c40000 { - compatible = "samsung,exynos4210-uart"; + compatible = "samsung,exynos7-uart", "samsung,exynos4210-uart"; reg = <0x14c40000 0x100>; interrupts = ; clocks = <&clock_peric1 PCLK_UART3>, @@ -539,7 +540,7 @@ }; rtc: rtc@10590000 { - compatible = "samsung,s3c6410-rtc"; + compatible = "samsung,exynos7-rtc", "samsung,s3c6410-rtc"; reg = <0x10590000 0x100>; interrupts = , ; @@ -559,7 +560,8 @@ }; gpu: gpu@14ac0000 { - compatible = "samsung,exynos5433-mali", "arm,mali-t760"; + compatible = "samsung,exynos7-mali", + "samsung,exynos5433-mali", "arm,mali-t760"; reg = <0x14ac0000 0x5000>; interrupts = , , @@ -619,7 +621,7 @@ }; pwm: pwm@136c0000 { - compatible = "samsung,exynos4210-pwm"; + compatible = "samsung,exynos7-pwm", "samsung,exynos4210-pwm"; reg = <0x136c0000 0x100>; interrupts = , , diff --git a/arch/arm64/boot/dts/exynos/exynos7885.dtsi b/arch/arm64/boot/dts/exynos/exynos7885.dtsi index d69fc2392bd0e3..008228fb319a90 100644 --- a/arch/arm64/boot/dts/exynos/exynos7885.dtsi +++ b/arch/arm64/boot/dts/exynos/exynos7885.dtsi @@ -172,7 +172,8 @@ ranges = <0x0 0x0 0x0 0x20000000>; chipid@10000000 { - compatible = "samsung,exynos850-chipid"; + compatible = "samsung,exynos7885-chipid", + "samsung,exynos850-chipid"; reg = <0x10000000 0x24>; }; @@ -264,7 +265,8 @@ reg = <0x11cb0000 0x1000>; wakeup-interrupt-controller { - compatible = "samsung,exynos7-wakeup-eint"; + compatible = "samsung,exynos7885-wakeup-eint", + "samsung,exynos7-wakeup-eint"; interrupt-parent = <&gic>; interrupts = ; }; @@ -289,12 +291,14 @@ }; pmu_system_controller: system-controller@11c80000 { - compatible = "samsung,exynos7-pmu", "syscon"; + compatible = "samsung,exynos7885-pmu", + "samsung,exynos7-pmu", "syscon"; reg = <0x11c80000 0x10000>; }; mmc_0: mmc@13500000 { - compatible = "samsung,exynos7-dw-mshc-smu"; + compatible = "samsung,exynos7885-dw-mshc-smu", + "samsung,exynos7-dw-mshc-smu"; reg = <0x13500000 0x2000>; interrupts = ; #address-cells = <1>; @@ -307,7 +311,8 @@ }; serial_0: serial@13800000 { - compatible = "samsung,exynos5433-uart"; + compatible = "samsung,exynos7885-uart", + "samsung,exynos5433-uart"; reg = <0x13800000 0x100>; interrupts = ; pinctrl-names = "default"; @@ -320,7 +325,8 @@ }; serial_1: serial@13810000 { - compatible = "samsung,exynos5433-uart"; + compatible = "samsung,exynos7885-uart", + "samsung,exynos5433-uart"; reg = <0x13810000 0x100>; interrupts = ; pinctrl-names = "default"; @@ -333,7 +339,8 @@ }; serial_2: serial@13820000 { - compatible = "samsung,exynos5433-uart"; + compatible = "samsung,exynos7885-uart", + "samsung,exynos5433-uart"; reg = <0x13820000 0x100>; interrupts = ; pinctrl-names = "default"; @@ -346,7 +353,8 @@ }; i2c_0: i2c@13830000 { - compatible = "samsung,s3c2440-i2c"; + compatible = "samsung,exynos7885-i2c", + "samsung,s3c2440-i2c"; reg = <0x13830000 0x100>; interrupts = ; #address-cells = <1>; @@ -359,7 +367,8 @@ }; i2c_1: i2c@13840000 { - compatible = "samsung,s3c2440-i2c"; + compatible = "samsung,exynos7885-i2c", + "samsung,s3c2440-i2c"; reg = <0x13840000 0x100>; interrupts = ; #address-cells = <1>; @@ -372,7 +381,8 @@ }; i2c_2: i2c@13850000 { - compatible = "samsung,s3c2440-i2c"; + compatible = "samsung,exynos7885-i2c", + "samsung,s3c2440-i2c"; reg = <0x13850000 0x100>; interrupts = ; #address-cells = <1>; @@ -385,7 +395,8 @@ }; i2c_3: i2c@13860000 { - compatible = "samsung,s3c2440-i2c"; + compatible = "samsung,exynos7885-i2c", + "samsung,s3c2440-i2c"; reg = <0x13860000 0x100>; interrupts = ; #address-cells = <1>; @@ -398,7 +409,8 @@ }; i2c_4: i2c@13870000 { - compatible = "samsung,s3c2440-i2c"; + compatible = "samsung,exynos7885-i2c", + "samsung,s3c2440-i2c"; reg = <0x13870000 0x100>; interrupts = ; #address-cells = <1>; @@ -411,7 +423,8 @@ }; i2c_5: i2c@13880000 { - compatible = "samsung,s3c2440-i2c"; + compatible = "samsung,exynos7885-i2c", + "samsung,s3c2440-i2c"; reg = <0x13880000 0x100>; interrupts = ; #address-cells = <1>; @@ -424,7 +437,8 @@ }; i2c_6: i2c@13890000 { - compatible = "samsung,s3c2440-i2c"; + compatible = "samsung,exynos7885-i2c", + "samsung,s3c2440-i2c"; reg = <0x13890000 0x100>; interrupts = ; #address-cells = <1>; @@ -437,7 +451,8 @@ }; i2c_7: i2c@11cd0000 { - compatible = "samsung,s3c2440-i2c"; + compatible = "samsung,exynos7885-i2c", + "samsung,s3c2440-i2c"; reg = <0x11cd0000 0x100>; interrupts = ; #address-cells = <1>; diff --git a/arch/arm64/boot/dts/exynos/exynos850.dtsi b/arch/arm64/boot/dts/exynos/exynos850.dtsi index 53104e65b9c670..da3f4a791e686c 100644 --- a/arch/arm64/boot/dts/exynos/exynos850.dtsi +++ b/arch/arm64/boot/dts/exynos/exynos850.dtsi @@ -359,7 +359,8 @@ reg = <0x11850000 0x1000>; wakeup-interrupt-controller { - compatible = "samsung,exynos850-wakeup-eint"; + compatible = "samsung,exynos850-wakeup-eint", + "samsung,exynos7-wakeup-eint"; }; }; @@ -368,7 +369,8 @@ reg = <0x11c30000 0x1000>; wakeup-interrupt-controller { - compatible = "samsung,exynos850-wakeup-eint"; + compatible = "samsung,exynos850-wakeup-eint", + "samsung,exynos7-wakeup-eint"; }; }; @@ -396,7 +398,7 @@ }; rtc: rtc@11a30000 { - compatible = "samsung,s3c6410-rtc"; + compatible = "samsung,exynos850-rtc", "samsung,s3c6410-rtc"; reg = <0x11a30000 0x100>; interrupts = , ; @@ -406,7 +408,8 @@ }; mmc_0: mmc@12100000 { - compatible = "samsung,exynos7-dw-mshc-smu"; + compatible = "samsung,exynos850-dw-mshc-smu", + "samsung,exynos7-dw-mshc-smu"; reg = <0x12100000 0x2000>; interrupts = ; #address-cells = <1>; @@ -419,7 +422,7 @@ }; i2c_0: i2c@13830000 { - compatible = "samsung,s3c2440-i2c"; + compatible = "samsung,exynos850-i2c", "samsung,s3c2440-i2c"; reg = <0x13830000 0x100>; interrupts = ; #address-cells = <1>; @@ -432,7 +435,7 @@ }; i2c_1: i2c@13840000 { - compatible = "samsung,s3c2440-i2c"; + compatible = "samsung,exynos850-i2c", "samsung,s3c2440-i2c"; reg = <0x13840000 0x100>; interrupts = ; #address-cells = <1>; @@ -445,7 +448,7 @@ }; i2c_2: i2c@13850000 { - compatible = "samsung,s3c2440-i2c"; + compatible = "samsung,exynos850-i2c", "samsung,s3c2440-i2c"; reg = <0x13850000 0x100>; interrupts = ; #address-cells = <1>; @@ -458,7 +461,7 @@ }; i2c_3: i2c@13860000 { - compatible = "samsung,s3c2440-i2c"; + compatible = "samsung,exynos850-i2c", "samsung,s3c2440-i2c"; reg = <0x13860000 0x100>; interrupts = ; #address-cells = <1>; @@ -471,7 +474,7 @@ }; i2c_4: i2c@13870000 { - compatible = "samsung,s3c2440-i2c"; + compatible = "samsung,exynos850-i2c", "samsung,s3c2440-i2c"; reg = <0x13870000 0x100>; interrupts = ; #address-cells = <1>; @@ -485,7 +488,7 @@ /* I2C_5 (also called CAM_PMIC_I2C in TRM) */ i2c_5: i2c@13880000 { - compatible = "samsung,s3c2440-i2c"; + compatible = "samsung,exynos850-i2c", "samsung,s3c2440-i2c"; reg = <0x13880000 0x100>; interrupts = ; #address-cells = <1>; @@ -499,7 +502,7 @@ /* I2C_6 (also called MOTOR_I2C in TRM) */ i2c_6: i2c@13890000 { - compatible = "samsung,s3c2440-i2c"; + compatible = "samsung,exynos850-i2c", "samsung,s3c2440-i2c"; reg = <0x13890000 0x100>; interrupts = ; #address-cells = <1>; @@ -640,7 +643,8 @@ status = "disabled"; hsi2c_0: i2c@138a0000 { - compatible = "samsung,exynosautov9-hsi2c"; + compatible = "samsung,exynos850-hsi2c", + "samsung,exynosautov9-hsi2c"; reg = <0x138a0000 0xc0>; interrupts = ; #address-cells = <1>; @@ -668,7 +672,8 @@ status = "disabled"; hsi2c_1: i2c@138b0000 { - compatible = "samsung,exynosautov9-hsi2c"; + compatible = "samsung,exynos850-hsi2c", + "samsung,exynosautov9-hsi2c"; reg = <0x138b0000 0xc0>; interrupts = ; #address-cells = <1>; @@ -696,7 +701,8 @@ status = "disabled"; hsi2c_2: i2c@138c0000 { - compatible = "samsung,exynosautov9-hsi2c"; + compatible = "samsung,exynos850-hsi2c", + "samsung,exynosautov9-hsi2c"; reg = <0x138c0000 0xc0>; interrupts = ; #address-cells = <1>; @@ -738,7 +744,8 @@ status = "disabled"; hsi2c_3: i2c@11d00000 { - compatible = "samsung,exynosautov9-hsi2c"; + compatible = "samsung,exynos850-hsi2c", + "samsung,exynosautov9-hsi2c"; reg = <0x11d00000 0xc0>; interrupts = ; #address-cells = <1>; @@ -778,7 +785,8 @@ status = "disabled"; hsi2c_4: i2c@11d20000 { - compatible = "samsung,exynosautov9-hsi2c"; + compatible = "samsung,exynos850-hsi2c", + "samsung,exynosautov9-hsi2c"; reg = <0x11d20000 0xc0>; interrupts = ; #address-cells = <1>; diff --git a/arch/arm64/boot/dts/exynos/exynosautov9-sadk.dts b/arch/arm64/boot/dts/exynos/exynosautov9-sadk.dts index bc1815f6ada26f..de2c1de51a76ec 100644 --- a/arch/arm64/boot/dts/exynos/exynosautov9-sadk.dts +++ b/arch/arm64/boot/dts/exynos/exynosautov9-sadk.dts @@ -9,6 +9,7 @@ /dts-v1/; #include "exynosautov9.dtsi" #include +#include / { model = "Samsung ExynosAuto v9 SADK board"; @@ -32,6 +33,31 @@ <0xa 0x00000000 0x2 0x00000000>; }; + gpio-keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&key_wakeup &key_volup &key_voldown>; + + key-wakeup { + label = "Wakeup"; + linux,code = ; + gpios = <&gpa0 0 GPIO_ACTIVE_LOW>; + wakeup-source; + }; + + key-volume-down { + label = "Volume Down"; + linux,code = ; + gpios = <&gpg2 0 GPIO_ACTIVE_LOW>; + }; + + key-volume-up { + label = "Volume Up"; + linux,code = ; + gpios = <&gpg1 5 GPIO_ACTIVE_LOW>; + }; + }; + ufs_0_fixed_vcc_reg: regulator-0 { compatible = "regulator-fixed"; regulator-name = "ufs-vcc"; @@ -49,6 +75,31 @@ }; }; +&pinctrl_alive { + key_wakeup: key-wakeup-pins { + samsung,pins = "gpa0-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; +}; + +&pinctrl_peric1 { + key_voldown: key-voldown-pins { + samsung,pins = "gpg2-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + key_volup: key-volup-pins { + samsung,pins = "gpg1-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; +}; + &pwm { pinctrl-names = "default"; pinctrl-0 = <&pwm_tout3>; diff --git a/arch/arm64/boot/dts/exynos/exynosautov9.dtsi b/arch/arm64/boot/dts/exynos/exynosautov9.dtsi index b228cd7e351e99..c871a2f49fda86 100644 --- a/arch/arm64/boot/dts/exynos/exynosautov9.dtsi +++ b/arch/arm64/boot/dts/exynos/exynosautov9.dtsi @@ -166,7 +166,8 @@ ranges = <0x0 0x0 0x0 0x20000000>; chipid@10000000 { - compatible = "samsung,exynos850-chipid"; + compatible = "samsung,exynosautov9-chipid", + "samsung,exynos850-chipid"; reg = <0x10000000 0x24>; }; @@ -309,7 +310,9 @@ reg = <0x10450000 0x1000>; wakeup-interrupt-controller { - compatible = "samsung,exynosautov9-wakeup-eint"; + compatible = "samsung,exynosautov9-wakeup-eint", + "samsung,exynos850-wakeup-eint", + "samsung,exynos7-wakeup-eint"; }; }; @@ -349,7 +352,8 @@ }; pmu_system_controller: system-controller@10460000 { - compatible = "samsung,exynos7-pmu", "syscon"; + compatible = "samsung,exynosautov9-pmu", + "samsung,exynos7-pmu", "syscon"; reg = <0x10460000 0x10000>; reboot: syscon-reboot { diff --git a/arch/arm64/boot/dts/exynos/exynosautov920-pinctrl.dtsi b/arch/arm64/boot/dts/exynos/exynosautov920-pinctrl.dtsi new file mode 100644 index 00000000000000..663e8265cbf508 --- /dev/null +++ b/arch/arm64/boot/dts/exynos/exynosautov920-pinctrl.dtsi @@ -0,0 +1,1266 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Samsung's ExynosAutov920 SoC pin-mux and pin-config device tree source + * + * Copyright (c) 2023 Samsung Electronics Co., Ltd. + * + * Samsung's ExynosAutov920 SoC pin-mux and pin-config options are listed as + * device tree nodes in this file. + */ + +#include + +#include "exynos-pinctrl.h" + +&pinctrl_alive { + gpa0: gpa0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gic>; + interrupts = , + , + , + , + , + , + , + ; + }; + + gpa1: gpa1-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gic>; + interrupts = , + ; + }; + + gpq0: gpq0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; +}; + +&pinctrl_aud { + gpb0: gpb0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpb1: gpb1-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpb2: gpb2-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpb3: gpb3-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpb4: gpb4-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpb5: gpb5-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpb6: gpb6-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; +}; + +&pinctrl_hsi0 { + gph0: gph0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gph1: gph1-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; +}; + +&pinctrl_hsi1 { + gph8: gph8-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; +}; + +&pinctrl_hsi2 { + gph3: gph3-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gph4: gph4-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gph5: gph5-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gph6: gph6-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; +}; + +&pinctrl_hsi2ufs { + gph2: gph2-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + ufs_refclk_out: ufs-refclk-out-pins { + samsung,pins = "gph2-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-con-pdn = ; + }; + + ufs_rst_n: ufs-rst-n-pins { + samsung,pins = "gph2-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-con-pdn = ; + }; + + ufs_refclk_out_1: ufs-refclk-out-1-pins { + samsung,pins = "gph2-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-con-pdn = ; + }; + + ufs_rst_n_1: ufs-rst-n-1-pins { + samsung,pins = "gph2-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-con-pdn = ; + }; +}; + +&pinctrl_peric0 { + gpg0: gpg0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpg2: gpg2-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpg3: gpg3-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpg4: gpg4-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpg5: gpg5-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp0: gpp0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp1: gpp1-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp2: gpp2-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp3: gpp3-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp4: gpp4-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + /* PWM PERIC0 */ + pwm_tout0: pwm-tout0-pins { + samsung,pins = "gpg0-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + pwm_tout1: pwm-tout1-pins { + samsung,pins = "gpg0-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + pwm_tout2: pwm-tout2-pins { + samsung,pins = "gpg0-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + pwm_tout3: pwm-tout3-pins { + samsung,pins = "gpg0-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC0_USI00 */ + uart0_bus: uart0-bus-pins { + samsung,pins = "gpp0-0", "gpp0-1", "gpp0-2", "gpp0-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart0_bus_dual: uart0-bus-dual-pins { + samsung,pins = "gpp0-0", "gpp0-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC0_USI01 */ + uart1_bus: uart1-bus-pins { + samsung,pins = "gpp0-4", "gpp0-5", "gpp0-6", "gpp0-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart1_bus_dual: uart1-bus-dual-pins { + samsung,pins = "gpp0-4", "gpp0-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC0_USI02 */ + uart2_bus: uart2-bus-pins { + samsung,pins = "gpp1-0", "gpp1-1", "gpp1-2", "gpp1-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart2_bus_dual: uart2-bus-dual-pins { + samsung,pins = "gpp1-0", "gpp1-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC0_USI03 */ + uart3_bus: uart3-bus-pins { + samsung,pins = "gpp1-4", "gpp1-5", "gpp1-6", "gpp1-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart3_bus_dual: uart3-bus-dual-pins { + samsung,pins = "gpp1-4", "gpp1-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC0_USI04 */ + uart4_bus: uart4-bus-pins { + samsung,pins = "gpp2-0", "gpp2-1", "gpp2-2", "gpp2-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart4_bus_dual: uart4-bus-dual-pins { + samsung,pins = "gpp2-0", "gpp2-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC0_USI05 */ + uart5_bus: uart5-bus-pins { + samsung,pins = "gpp2-4", "gpp2-5", "gpp2-6", "gpp2-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart5_bus_dual: uart5-bus-dual-pins { + samsung,pins = "gpp2-4", "gpp2-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC0_USI06 */ + uart6_bus: uart6-bus-pins { + samsung,pins = "gpp3-0", "gpp3-1", "gpp3-2", "gpp3-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart6_bus_dual: uart6-bus-dual-pins { + samsung,pins = "gpp3-0", "gpp3-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC0_USI07 */ + uart7_bus: uart7-bus-pins { + samsung,pins = "gpp3-4", "gpp3-5", "gpp3-6", "gpp3-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart7_bus_dual: uart7-bus-dual-pins { + samsung,pins = "gpp3-4", "gpp3-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC0_USI08 */ + uart8_bus: uart8-bus-pins { + samsung,pins = "gpp4-0", "gpp4-1", "gpp4-2", "gpp4-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart8_bus_dual: uart8-bus-dual-pins { + samsung,pins = "gpp4-0", "gpp4-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI00 */ + hsi2c0_bus: hsi2c0-bus-pins { + samsung,pins = "gpp0-0", "gpp0-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI00_I2C */ + hsi2c1_bus: hsi2c1-bus-pins { + samsung,pins = "gpp0-2", "gpp0-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI01 */ + hsi2c2_bus: hsi2c2-bus-pins { + samsung,pins = "gpp0-4", "gpp0-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI01_I2C */ + hsi2c3_bus: hsi2c3-bus-pins { + samsung,pins = "gpp0-6", "gpp0-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI02 */ + hsi2c4_bus: hsi2c4-bus-pins { + samsung,pins = "gpp1-0", "gpp1-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI02_I2C */ + hsi2c5_bus: hsi2c5-bus-pins { + samsung,pins = "gpp1-2", "gpp1-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI03 */ + hsi2c6_bus: hsi2c6-bus-pins { + samsung,pins = "gpp1-4", "gpp1-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI03_I2C */ + hsi2c7_bus: hsi2c7-bus-pins { + samsung,pins = "gpp1-6", "gpp1-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI04 */ + hsi2c8_bus: hsi2c8-bus-pins { + samsung,pins = "gpp2-0", "gpp2-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI04_I2C */ + hsi2c9_bus: hsi2c9-bus-pins { + samsung,pins = "gpp2-2", "gpp2-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI05 */ + hsi2c10_bus: hsi2c10-bus-pins { + samsung,pins = "gpp2-4", "gpp2-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI05_I2C */ + hsi2c11_bus: hsi2c11-bus-pins { + samsung,pins = "gpp2-6", "gpp2-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI06 */ + hsi2c12_bus: hsi2c12-bus-pins { + samsung,pins = "gpp3-0", "gpp3-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI06_I2C */ + hsi2c13_bus: hsi2c13-bus-pins { + samsung,pins = "gpp3-2", "gpp3-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI07 */ + hsi2c14_bus: hsi2c14-bus-pins { + samsung,pins = "gpp3-4", "gpp3-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI07_I2C */ + hsi2c15_bus: hsi2c15-bus-pins { + samsung,pins = "gpp3-6", "gpp3-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI08 */ + hsi2c16_bus: hsi2c16-bus-pins { + samsung,pins = "gpp4-0", "gpp4-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC0 USI08_I2C */ + hsi2c17_bus: hsi2c17-bus-pins { + samsung,pins = "gpp4-2", "gpp4-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC0 USI00 */ + spi0_bus: spi0-bus-pins { + samsung,pins = "gpp0-0", "gpp0-1", "gpp0-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi0_cs: spi0-cs-pins { + samsung,pins = "gpp0-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi0_cs_func: spi0-cs-func-pins { + samsung,pins = "gpp0-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC0 USI01 */ + spi1_bus: spi1-bus-pins { + samsung,pins = "gpp0-4", "gpp0-5", "gpp0-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi1_cs: spi1-cs-pins { + samsung,pins = "gpp0-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi1_cs_func: spi1-cs-func-pins { + samsung,pins = "gpp0-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC0 USI02 */ + spi2_bus: spi2-bus-pins { + samsung,pins = "gpp1-0", "gpp1-1", "gpp1-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi2_cs: spi2-cs-pins { + samsung,pins = "gpp1-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi2_cs_func: spi2-cs-func-pins { + samsung,pins = "gpp1-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC0 USI03 */ + spi3_bus: spi3-bus-pins { + samsung,pins = "gpp1-4", "gpp1-5", "gpp1-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi3_cs: spi3-cs-pins { + samsung,pins = "gpp1-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi3_cs_func: spi3-cs-func-pins { + samsung,pins = "gpp1-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC0 USI04 */ + spi4_bus: spi4-bus-pins { + samsung,pins = "gpp2-0", "gpp2-1", "gpp2-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi4_cs: spi4-cs-pins { + samsung,pins = "gpp2-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi4_cs_func: spi4-cs-func-pins { + samsung,pins = "gpp2-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC0 USI05 */ + spi5_bus: spi5-bus-pins { + samsung,pins = "gpp2-4", "gpp2-5", "gpp2-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi5_cs: spi5-cs-pins { + samsung,pins = "gpp2-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi5_cs_func: spi5-cs-func-pins { + samsung,pins = "gpp2-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC0 USI06 */ + spi6_bus: spi6-bus-pins { + samsung,pins = "gpp3-0", "gpp3-1", "gpp3-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi6_cs: spi6-cs-pins { + samsung,pins = "gpp3-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi6_cs_func: spi6-cs-func-pins { + samsung,pins = "gpp3-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC0 USI07 */ + spi7_bus: spi7-bus-pins { + samsung,pins = "gpp3-4", "gpp3-5", "gpp3-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi7_cs: spi7-cs-pins { + samsung,pins = "gpp3-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi7_cs_func: spi7-cs-func-pins { + samsung,pins = "gpp3-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC0 USI08 */ + spi8_bus: spi8-bus-pins { + samsung,pins = "gpp4-0", "gpp4-1", "gpp4-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi8_cs: spi8-cs-pins { + samsung,pins = "gpp4-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi8_cs_func: spi8-cs-func-pins { + samsung,pins = "gpp4-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I3C PERIC0 */ + i3c0_bus: i3c0-bus-pins { + samsung,pins = "gpp2-6", "gpp2-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + i3c1_bus: i3c1-bus-pins { + samsung,pins = "gpp3-2", "gpp3-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + i3c2_bus: i3c2-bus-pins { + samsung,pins = "gpp3-6", "gpp3-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + i3c3_bus: i3c3-bus-pins { + samsung,pins = "gpp4-2", "gpp4-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; +}; + +&pinctrl_peric1 { + gpg1: gpg1-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp5: gpp5-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp6: gpp6-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp7: gpp7-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp8: gpp8-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp9: gpp9-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp10: gpp10-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp11: gpp11-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp12: gpp12-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + + /* UART PERIC1 USI09 */ + uart9_bus: uart9-bus-pins { + samsung,pins = "gpp5-0", "gpp5-1", "gpp5-2", "gpp5-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart9_bus_dual: uart9-bus-dual-pins { + samsung,pins = "gpp5-0", "gpp5-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC1 USI10 */ + uart10_bus: uart10-bus-pins { + samsung,pins = "gpp5-4", "gpp5-5", "gpp5-6", "gpp5-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart10_bus_dual: uart10-bus-dual-pins { + samsung,pins = "gpp5-4", "gpp5-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC1 USI11 */ + uart11_bus: uart11-bus-pins { + samsung,pins = "gpp10-0", "gpp10-1", "gpp10-2", "gpp10-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart11_bus_dual: uart11-bus-dual-pins { + samsung,pins = "gpp10-0", "gpp10-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC1_USI12 */ + uart12_bus: uart12-bus-pins { + samsung,pins = "gpp7-0", "gpp7-1", "gpp7-2", "gpp7-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart12_bus_dual: uart12-bus-dual-pins { + samsung,pins = "gpp7-0", "gpp7-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC1_USI13 */ + uart13_bus: uart13-bus-pins { + samsung,pins = "gpp7-4", "gpp7-5", "gpp7-6", "gpp7-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart13_bus_dual: uart13-bus-dual-pins { + samsung,pins = "gpp7-4", "gpp7-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC1 USI14 */ + uart14_bus: uart14-bus-pins { + samsung,pins = "gpp8-0", "gpp8-1", "gpp8-2", "gpp8-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart14_bus_dual: uart14-bus-dual-pins { + samsung,pins = "gpp8-0", "gpp8-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC1 USI15 */ + uart15_bus: uart15-bus-pins { + samsung,pins = "gpp11-0", "gpp11-1", "gpp11-2", "gpp11-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart15_bus_dual: uart15-bus-dual-pins { + samsung,pins = "gpp11-0", "gpp11-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC1 USI16 */ + uart16_bus: uart16-bus-pins { + samsung,pins = "gpp9-0", "gpp9-1", "gpp9-2", "gpp9-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart16_bus_dual: uart16-bus-dual-pins { + samsung,pins = "gpp9-0", "gpp9-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* UART PERIC1 USI17 */ + uart17_bus: uart17-bus-pins { + samsung,pins = "gpp12-0", "gpp12-1", "gpp12-2", "gpp12-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart17_bus_dual: uart17-bus-dual-pins { + samsung,pins = "gpp12-0", "gpp12-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI09 */ + hsi2c18_bus: hsi2c18-bus-pins { + samsung,pins = "gpp5-0", "gpp5-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI09_I2C */ + hsi2c19_bus: hsi2c19-bus-pins { + samsung,pins = "gpp5-2", "gpp5-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI10 */ + hsi2c20_bus: hsi2c20-bus-pins { + samsung,pins = "gpp5-4", "gpp5-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI10_I2C */ + hsi2c21_bus: hsi2c21-bus-pins { + samsung,pins = "gpp5-6", "gpp5-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI11 */ + hsi2c22_bus: hsi2c22-bus-pins { + samsung,pins = "gpp10-0", "gpp10-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI11_I2C */ + hsi2c23_bus: hsi2c23-bus-pins { + samsung,pins = "gpp10-2", "gpp10-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI12 */ + hsi2c24_bus: hsi2c24-bus-pins { + samsung,pins = "gpp7-0", "gpp7-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI12_I2C */ + hsi2c25_bus: hsi2c25-bus-pins { + samsung,pins = "gpp7-2", "gpp7-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI13 */ + hsi2c26_bus: hsi2c26-bus-pins { + samsung,pins = "gpp7-4", "gpp7-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI13_I2C */ + hsi2c27_bus: hsi2c27-bus-pins { + samsung,pins = "gpp7-6", "gpp7-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI14 */ + hsi2c28_bus: hsi2c28-bus-pins { + samsung,pins = "gpp8-0", "gpp8-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI14_I2C */ + hsi2c29_bus: hsi2c29-bus-pins { + samsung,pins = "gpp8-2", "gpp8-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI15 */ + hsi2c30_bus: hsi2c30-bus-pins { + samsung,pins = "gpp11-0", "gpp11-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI15_I2C */ + hsi2c31_bus: hsi2c31-bus-pins { + samsung,pins = "gpp11-2", "gpp11-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI16 */ + hsi2c32_bus: hsi2c32-bus-pins { + samsung,pins = "gpp9-0", "gpp9-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI16_I2C */ + hsi2c33_bus: hsi2c33-bus-pins { + samsung,pins = "gpp9-2", "gpp9-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI17 */ + hsi2c34_bus: hsi2c34-bus-pins { + samsung,pins = "gpp12-0", "gpp12-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I2C PERIC1 USI17_I2C */ + hsi2c35_bus: hsi2c35-bus-pins { + samsung,pins = "gpp12-2", "gpp12-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC1 USI09 */ + spi9_bus: spi9-bus-pins { + samsung,pins = "gpp5-0", "gpp5-1", "gpp5-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi9_cs: spi9-cs-pins { + samsung,pins = "gpp5-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi9_cs_func: spi9-cs-func-pins { + samsung,pins = "gpp5-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC1 USI10 */ + spi10_bus: spi10-bus-pins { + samsung,pins = "gpp5-4", "gpp5-5", "gpp5-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi10_cs: spi10-cs-pins { + samsung,pins = "gpp5-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi10_cs_func: spi10-cs-func-pins { + samsung,pins = "gpp5-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC1 USI11 */ + spi11_bus: spi11-bus-pins { + samsung,pins = "gpp10-0", "gpp10-1", "gpp10-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi11_cs: spi11-cs-pins { + samsung,pins = "gpp10-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi11_cs_func: spi11-cs-func-pins { + samsung,pins = "gpp10-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC1 USI12 */ + spi12_bus: spi12-bus-pins { + samsung,pins = "gpp7-0", "gpp7-1", "gpp7-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi12_cs: spi12-cs-pins { + samsung,pins = "gpp7-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi12_cs_func: spi12-cs-func-pins { + samsung,pins = "gpp7-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC1 USI13 */ + spi13_bus: spi13-bus-pins { + samsung,pins = "gpp7-4", "gpp7-5", "gpp7-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi13_cs: spi13-cs-pins { + samsung,pins = "gpp7-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi13_cs_func: spi13-cs-func-pins { + samsung,pins = "gpp7-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC1 USI14 */ + spi14_bus: spi14-bus-pins { + samsung,pins = "gpp8-0", "gpp8-1", "gpp8-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi14_cs: spi14-cs-pins { + samsung,pins = "gpp8-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi14_cs_func: spi14-cs-func-pins { + samsung,pins = "gpp8-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC1 USI15 */ + spi15_bus: spi15-bus-pins { + samsung,pins = "gpp11-0", "gpp11-1", "gpp11-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi15_cs: spi15-cs-pins { + samsung,pins = "gpp11-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi15_cs_func: spi15-cs-func-pins { + samsung,pins = "gpp11-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC1 USI16 */ + spi16_bus: spi16-bus-pins { + samsung,pins = "gpp9-0", "gpp9-1", "gpp9-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi16_cs: spi16-cs-pins { + samsung,pins = "gpp9-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi16_cs_func: spi16-cs-func-pins { + samsung,pins = "gpp9-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* SPI PERIC1 USI17 */ + spi17_bus: spi17-bus-pins { + samsung,pins = "gpp12-0", "gpp12-1", "gpp12-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi17_cs: spi17-cs-pins { + samsung,pins = "gpp12-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi17_cs_func: spi17-cs-func-pins { + samsung,pins = "gpp12-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + /* I3C PERIC1 */ + i3c4_bus: i3c4-bus-pins { + samsung,pins = "gpp7-2", "gpp7-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + i3c5_bus: i3c5-bus-pins { + samsung,pins = "gpp7-6", "gpp7-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + i3c6_bus: i3c6-bus-pins { + samsung,pins = "gpp8-2", "gpp8-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + i3c7_bus: i3c7-bus-pins { + samsung,pins = "gpp11-2", "gpp11-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; +}; diff --git a/arch/arm64/boot/dts/exynos/exynosautov920-sadk.dts b/arch/arm64/boot/dts/exynos/exynosautov920-sadk.dts new file mode 100644 index 00000000000000..a397f068ed5352 --- /dev/null +++ b/arch/arm64/boot/dts/exynos/exynosautov920-sadk.dts @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Samsung's ExynosAutov920 SADK board device tree source + * + * Copyright (c) 2023 Samsung Electronics Co., Ltd. + * + */ + +/dts-v1/; +#include "exynosautov920.dtsi" +#include "exynos-pinctrl.h" +#include +#include + +/ { + model = "Samsung ExynosAutov920 SADK board"; + compatible = "samsung,exynosautov920-sadk", "samsung,exynosautov920"; + + #address-cells = <2>; + #size-cells = <2>; + + aliases { + serial0 = &serial_0; + }; + + chosen { + stdout-path = &serial_0; + }; + + gpio-keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&key_wakeup &key_back>; + + key-wakeup { + label = "KEY_WAKEUP"; + linux,code = ; + gpios = <&gpa0 0 GPIO_ACTIVE_LOW>; + wakeup-source; + }; + + key-back { + label = "KEY_BACK"; + linux,code = ; + gpios = <&gpp6 3 GPIO_ACTIVE_LOW>; + }; + }; + + memory@80000000 { + device_type = "memory"; + reg = <0x0 0x80000000 0x0 0x70000000>, + <0x8 0x80000000 0x1 0xfba00000>, + <0xa 0x00000000 0x2 0x00000000>; + }; +}; + +&pinctrl_alive { + key_wakeup: key-wakeup-pins { + samsung,pins = "gpa0-0"; + samsung,pin-function = ; + }; +}; + +&pinctrl_peric1 { + key_back: key-back-pins { + samsung,pins = "gpp6-3"; + samsung,pin-function = ; + }; +}; + +&pwm { + pinctrl-names = "default"; + pinctrl-0 = <&pwm_tout0>; + status = "okay"; +}; + +&serial_0 { + status = "okay"; +}; + +&usi_0 { + samsung,clkreq-on; /* needed for UART mode */ + status = "okay"; +}; + +&xtcxo { + clock-frequency = <38400000>; +}; diff --git a/arch/arm64/boot/dts/exynos/exynosautov920.dtsi b/arch/arm64/boot/dts/exynos/exynosautov920.dtsi new file mode 100644 index 00000000000000..c1c8566d74f597 --- /dev/null +++ b/arch/arm64/boot/dts/exynos/exynosautov920.dtsi @@ -0,0 +1,312 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Samsung's ExynosAutov920 SoC device tree source + * + * Copyright (c) 2023 Samsung Electronics Co., Ltd. + * + */ + +#include +#include + +/ { + compatible = "samsung,exynosautov920"; + #address-cells = <2>; + #size-cells = <1>; + + interrupt-parent = <&gic>; + + aliases { + pinctrl0 = &pinctrl_alive; + pinctrl1 = &pinctrl_aud; + pinctrl2 = &pinctrl_hsi0; + pinctrl3 = &pinctrl_hsi1; + pinctrl4 = &pinctrl_hsi2; + pinctrl5 = &pinctrl_hsi2ufs; + pinctrl6 = &pinctrl_peric0; + pinctrl7 = &pinctrl_peric1; + }; + + arm-pmu { + compatible = "arm,cortex-a78-pmu"; + interrupts = ; + }; + + xtcxo: clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-output-names = "oscclk"; + }; + + /* + * FIXME: Keep the stub clock for serial driver, until proper clock + * driver is implemented. + */ + clock_usi: clock-usi { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <200000000>; + clock-output-names = "usi"; + }; + + cpus: cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu-map { + cluster0 { + core0 { + cpu = <&cpu0>; + }; + core1 { + cpu = <&cpu1>; + }; + core2 { + cpu = <&cpu2>; + }; + core3 { + cpu = <&cpu3>; + }; + }; + + cluster1 { + core0 { + cpu = <&cpu4>; + }; + core1 { + cpu = <&cpu5>; + }; + core2 { + cpu = <&cpu6>; + }; + core3 { + cpu = <&cpu7>; + }; + }; + + cluster2 { + core0 { + cpu = <&cpu8>; + }; + core1 { + cpu = <&cpu9>; + }; + }; + }; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a78ae"; + reg = <0x0 0x0>; + enable-method = "psci"; + }; + + cpu1: cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a78ae"; + reg = <0x0 0x100>; + enable-method = "psci"; + }; + + cpu2: cpu@200 { + device_type = "cpu"; + compatible = "arm,cortex-a78ae"; + reg = <0x0 0x200>; + enable-method = "psci"; + }; + + cpu3: cpu@300 { + device_type = "cpu"; + compatible = "arm,cortex-a78ae"; + reg = <0x0 0x300>; + enable-method = "psci"; + }; + + cpu4: cpu@10000 { + device_type = "cpu"; + compatible = "arm,cortex-a78ae"; + reg = <0x0 0x10000>; + enable-method = "psci"; + }; + + cpu5: cpu@10100 { + device_type = "cpu"; + compatible = "arm,cortex-a78ae"; + reg = <0x0 0x10100>; + enable-method = "psci"; + }; + + cpu6: cpu@10200 { + device_type = "cpu"; + compatible = "arm,cortex-a78ae"; + reg = <0x0 0x10200>; + enable-method = "psci"; + }; + + cpu7: cpu@10300 { + device_type = "cpu"; + compatible = "arm,cortex-a78ae"; + reg = <0x0 0x10300>; + enable-method = "psci"; + }; + + cpu8: cpu@20000 { + device_type = "cpu"; + compatible = "arm,cortex-a78ae"; + reg = <0x0 0x20000>; + enable-method = "psci"; + }; + + cpu9: cpu@20100 { + device_type = "cpu"; + compatible = "arm,cortex-a78ae"; + reg = <0x0 0x20100>; + enable-method = "psci"; + }; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + + soc: soc@0 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x0 0x0 0x20000000>; + + chipid@10000000 { + compatible = "samsung,exynosautov920-chipid", + "samsung,exynos850-chipid"; + reg = <0x10000000 0x24>; + }; + + gic: interrupt-controller@10400000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <3>; + #address-cells = <0>; + interrupt-controller; + reg = <0x10400000 0x10000>, + <0x10460000 0x140000>; + interrupts = ; + }; + + syscon_peric0: syscon@10820000 { + compatible = "samsung,exynosautov920-peric0-sysreg", + "syscon"; + reg = <0x10820000 0x2000>; + }; + + pinctrl_peric0: pinctrl@10830000 { + compatible = "samsung,exynosautov920-pinctrl"; + reg = <0x10830000 0x10000>; + interrupts = ; + }; + + usi_0: usi@108800c0 { + compatible = "samsung,exynosautov920-usi", + "samsung,exynos850-usi"; + reg = <0x108800c0 0x20>; + samsung,sysreg = <&syscon_peric0 0x1000>; + samsung,mode = ; + #address-cells = <1>; + #size-cells = <1>; + ranges; + clocks = <&clock_usi>, <&clock_usi>; + clock-names = "pclk", "ipclk"; + status = "disabled"; + + serial_0: serial@10880000 { + compatible = "samsung,exynosautov920-uart", + "samsung,exynos850-uart"; + reg = <0x10880000 0xc0>; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&uart0_bus>; + clocks = <&clock_usi>, <&clock_usi>; + clock-names = "uart", "clk_uart_baud0"; + samsung,uart-fifosize = <256>; + status = "disabled"; + }; + }; + + pwm: pwm@109b0000 { + compatible = "samsung,exynosautov920-pwm", + "samsung,exynos4210-pwm"; + reg = <0x109b0000 0x100>; + samsung,pwm-outputs = <0>, <1>, <2>, <3>; + #pwm-cells = <3>; + clocks = <&xtcxo>; + clock-names = "timers"; + status = "disabled"; + }; + + syscon_peric1: syscon@10c20000 { + compatible = "samsung,exynosautov920-peric1-sysreg", + "syscon"; + reg = <0x10c20000 0x2000>; + }; + + pinctrl_peric1: pinctrl@10c30000 { + compatible = "samsung,exynosautov920-pinctrl"; + reg = <0x10c30000 0x10000>; + interrupts = ; + }; + + pinctrl_alive: pinctrl@11850000 { + compatible = "samsung,exynosautov920-pinctrl"; + reg = <0x11850000 0x10000>; + + wakeup-interrupt-controller { + compatible = "samsung,exynosautov920-wakeup-eint"; + }; + }; + + pmu_system_controller: system-controller@11860000 { + compatible = "samsung,exynosautov920-pmu", + "samsung,exynos7-pmu","syscon"; + reg = <0x11860000 0x10000>; + }; + + pinctrl_hsi0: pinctrl@16040000 { + compatible = "samsung,exynosautov920-pinctrl"; + reg = <0x16040000 0x10000>; + interrupts = ; + }; + + pinctrl_hsi1: pinctrl@16450000 { + compatible = "samsung,exynosautov920-pinctrl"; + reg = <0x16450000 0x10000>; + interrupts = ; + }; + + pinctrl_hsi2: pinctrl@16c10000 { + compatible = "samsung,exynosautov920-pinctrl"; + reg = <0x16c10000 0x10000>; + interrupts = ; + }; + + pinctrl_hsi2ufs: pinctrl@16d20000 { + compatible = "samsung,exynosautov920-pinctrl"; + reg = <0x16d20000 0x10000>; + interrupts = ; + }; + + pinctrl_aud: pinctrl@1a460000 { + compatible = "samsung,exynosautov920-pinctrl"; + reg = <0x1a460000 0x10000>; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + , + ; + }; +}; + +#include "exynosautov920-pinctrl.dtsi" diff --git a/arch/arm64/boot/dts/exynos/google/Makefile b/arch/arm64/boot/dts/exynos/google/Makefile new file mode 100644 index 00000000000000..0a6d5e1fe4eea1 --- /dev/null +++ b/arch/arm64/boot/dts/exynos/google/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 + +dtb-$(CONFIG_ARCH_EXYNOS) += \ + gs101-oriole.dtb \ diff --git a/arch/arm64/boot/dts/exynos/google/gs101-oriole.dts b/arch/arm64/boot/dts/exynos/google/gs101-oriole.dts new file mode 100644 index 00000000000000..4a71f752200df1 --- /dev/null +++ b/arch/arm64/boot/dts/exynos/google/gs101-oriole.dts @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Oriole Device Tree + * + * Copyright 2021-2023 Google LLC + * Copyright 2023 Linaro Ltd - + */ + +/dts-v1/; + +#include +#include +#include "gs101-pinctrl.h" +#include "gs101.dtsi" + +/ { + model = "Oriole"; + compatible = "google,gs101-oriole", "google,gs101"; + + aliases { + serial0 = &serial_0; + }; + + chosen { + /* Bootloader expects bootargs specified otherwise it crashes */ + bootargs = ""; + stdout-path = &serial_0; + }; + + gpio-keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&key_voldown>, <&key_volup>, <&key_power>; + + button-vol-down { + label = "KEY_VOLUMEDOWN"; + linux,code = ; + gpios = <&gpa7 3 GPIO_ACTIVE_LOW>; + wakeup-source; + }; + + button-vol-up { + label = "KEY_VOLUMEUP"; + linux,code = ; + gpios = <&gpa8 1 GPIO_ACTIVE_LOW>; + wakeup-source; + }; + + button-power { + label = "KEY_POWER"; + linux,code = ; + gpios = <&gpa10 1 GPIO_ACTIVE_LOW>; + wakeup-source; + }; + }; +}; + +&ext_24_5m { + clock-frequency = <24576000>; +}; + +&ext_200m { + clock-frequency = <200000000>; +}; + +&pinctrl_far_alive { + key_voldown: key-voldown-pins { + samsung,pins = "gpa7-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + key_volup: key-volup-pins { + samsung,pins = "gpa8-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; +}; + +&pinctrl_gpio_alive { + key_power: key-power-pins { + samsung,pins = "gpa10-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; +}; + +&serial_0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_bus>; + status = "okay"; +}; + +&usi_uart { + samsung,clkreq-on; /* needed for UART mode */ + status = "okay"; +}; + +&watchdog_cl0 { + timeout-sec = <30>; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/exynos/google/gs101-pinctrl.dtsi b/arch/arm64/boot/dts/exynos/google/gs101-pinctrl.dtsi new file mode 100644 index 00000000000000..e6a9776d4d62ed --- /dev/null +++ b/arch/arm64/boot/dts/exynos/google/gs101-pinctrl.dtsi @@ -0,0 +1,1249 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * GS101 SoC pin-mux and pin-config device tree source + * + * Copyright 2019-2023 Google LLC + * Copyright 2023 Linaro Ltd - + */ + +#include "gs101-pinctrl.h" + +&pinctrl_gpio_alive { + gpa0: gpa0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gic>; + interrupts = , + , + , + , + , + , + , + ; + }; + + gpa1: gpa1-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gic>; + interrupts = , + , + , + , + , + , + ; + }; + + gpa2: gpa2-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gic>; + interrupts = , + , + , + , + ; + }; + + gpa3: gpa3-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gic>; + interrupts = , + , + , + ; + }; + + gpa4: gpa4-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gic>; + interrupts = , + , + , + ; + }; + + gpa5: gpa5-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = , + , + , + , + , + , + ; + }; + + gpa9: gpa9-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = , + , + , + , + , + , + , + ; + }; + + gpa10: gpa10-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = , + ; + }; + + uart15_bus: uart15-bus-pins { + samsung,pins = "gpa2-3", "gpa2-4"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart16_bus: uart16-bus-pins { + samsung,pins = "gpa3-0", "gpa3-1", "gpa3-2", "gpa3-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + uart17_bus: uart17-bus-pins { + samsung,pins = "gpa4-0", "gpa4-1", "gpa4-2", "gpa4-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi15_bus: spi15-bus-pins { + samsung,pins = "gpa4-0", "gpa4-1", "gpa4-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi15_cs: spi15-cs-pins { + samsung,pins = "gpa4-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; +}; + +&pinctrl_far_alive { + gpa6: gpa6-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gic>; + interrupts = , + , + , + , + , + , + , + ; + }; + + gpa7: gpa7-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gic>; + interrupts = , + , + , + ; + }; + + gpa8: gpa8-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gic>; + interrupts = , + , + , + , + , + , + , + ; + }; + + gpa11: gpa11-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gic>; + interrupts = , + ; + }; +}; + +&pinctrl_gsacore { + gps0: gps0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gps1: gps1-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gps2: gps2-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; +}; + +&pinctrl_gsactrl { + gps3: gps3-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; +}; + +&pinctrl_hsi1 { + gph0: gph0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gph1: gph1-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + pcie0_clkreq: pcie0-clkreq-pins{ + samsung,pins = "gph0-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + samsung,pin-con-pdn = ; + samsung,pin-pud-pdn = ; + }; + + pcie0_perst: pcie0-perst-pins { + samsung,pins = "gph0-0"; + samsung,pin-function = ; + samsung,pin-drv = ; + samsung,pin-con-pdn = ; + }; +}; + +&pinctrl_hsi2 { + gph2: gph2-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gph3: gph3-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gph4: gph4-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + sd2_clk: sd2-clk-pins { + samsung,pins = "gph4-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sd2_cmd: sd2-cmd-pins { + samsung,pins = "gph4-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sd2_bus1: sd2-bus-width1-pins { + samsung,pins = "gph4-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sd2_bus4: sd2-bus-width4-pins { + samsung,pins = "gph4-3", "gph4-4", "gph4-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sd2_clk_fast_slew_rate_1x: sd2-clk-fast-slew-rate-1x-pins { + samsung,pins = "gph4-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sd2_clk_fast_slew_rate_2x: sd2-clk-fast-slew-rate-2x-pins { + samsung,pins = "gph4-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sd2_clk_fast_slew_rate_3x: sd2-clk-fast-slew-rate-3x-pins { + samsung,pins = "gph4-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sd2_clk_fast_slew_rate_4x: sd2-clk-fast-slew-rate-4x-pins { + samsung,pins = "gph4-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + ufs_rst_n: ufs-rst-n-pins { + samsung,pins = "gph3-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-con-pdn = ; + samsung,pin-pud-pdn = ; + }; + + ufs_refclk_out: ufs-refclk-out-pins { + samsung,pins = "gph3-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-con-pdn = ; + samsung,pin-pud-pdn = ; + }; + + pcie1_clkreq: pcie1-clkreq-pins { + samsung,pins = "gph2-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + samsung,pin-con-pdn = ; + samsung,pin-pud-pdn = ; + }; + + pcie1_perst: pcie1-perst-pins { + samsung,pins = "gph2-0"; + samsung,pin-function = ; + samsung,pin-drv = ; + samsung,pin-con-pdn = ; + }; +}; + +&pinctrl_peric0 { + gpp0: gpp0-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp1: gpp1-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp2: gpp2-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp3: gpp3-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp4: gpp4-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp5: gpp5-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp6: gpp6-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp7: gpp7-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp8: gpp8-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp9: gpp9-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp10: gpp10-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp11: gpp11-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp12: gpp12-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp13: gpp13-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp14: gpp14-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp15: gpp15-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp16: gpp16-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp17: gpp17-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp18: gpp18-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp19: gpp19-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + /* USI_PERIC0_UART_DBG */ + uart0_bus: uart0-bus-pins { + samsung,pins = "gpp1-2", "gpp1-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + disp_te_pri_on: disp-te-pri-on-pins { + samsung,pins = "gpp0-3"; + samsung,pin-function = ; + }; + + disp_te_pri_off: disp-te-pri-off-pins { + samsung,pins = "gpp0-3"; + samsung,pin-function = ; + }; + + disp_te_sec_on: disp-te-sec-on-pins { + samsung,pins = "gpp0-4"; + samsung,pin-function = ; + }; + + disp_te_sec_off: disp-te-sec-off-pins { + samsung,pins = "gpp0-4"; + samsung,pin-function = ; + }; + + sensor_mclk1_out: sensor-mclk1-out-pins { + samsung,pins = "gpp3-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sensor_mclk1_fn: sensor-mclk1-fn-pins { + samsung,pins = "gpp3-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sensor_mclk2_out: sensor-mclk2-out-pins { + samsung,pins = "gpp5-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sensor_mclk2_fn: sensor-mclk2-fn-pins { + samsung,pins = "gpp5-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sensor_mclk3_out: sensor-mclk3-out-pins { + samsung,pins = "gpp7-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sensor_mclk3_fn: sensor-mclk3-fn-pins { + samsung,pins = "gpp7-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sensor_mclk4_out: sensor-mclk4-out-pins { + samsung,pins = "gpp9-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sensor_mclk4_fn: sensor-mclk4-fn-pins { + samsung,pins = "gpp9-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sensor_mclk5_out: sensor-mclk5-out-pins { + samsung,pins = "gpp11-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sensor_mclk5_fn: sensor-mclk5-fn-pins { + samsung,pins = "gpp11-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sensor_mclk6_out: sensor-mclk6-out-pins { + samsung,pins = "gpp13-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sensor_mclk6_fn: sensor-mclk6-fn-pins { + samsung,pins = "gpp13-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sensor_mclk7_out: sensor-mclk7-out-pins { + samsung,pins = "gpp15-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sensor_mclk7_fn: sensor-mclk7-fn-pins { + samsung,pins = "gpp15-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sensor_mclk8_out: sensor-mclk8-out-pins { + samsung,pins = "gpp17-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + sensor_mclk8_fn: sensor-mclk8-fn-pins { + samsung,pins = "gpp17-0"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c14_bus: hsi2c14-bus-pins { + samsung,pins = "gpp18-0", "gpp18-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + uart14_bus_single: uart14-bus-pins { + samsung,pins = "gpp18-0", "gpp18-1", + "gpp18-2", "gpp18-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi14_bus: spi14-bus-pins { + samsung,pins = "gpp18-0", "gpp18-1", "gpp18-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi14_cs: spi14-cs-pins { + samsung,pins = "gpp18-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi14_cs_func: spi14-cs-func-pins { + samsung,pins = "gpp18-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c8_bus: hsi2c8-bus-pins { + samsung,pins = "gpp16-0", "gpp16-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + samsung,pin-pud-pdn = ; + }; + + uart8_bus_single: uart8-bus-pins { + samsung,pins = "gpp16-0", "gpp16-1", "gpp16-2", + "gpp16-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi8_bus: spi8-bus-pins { + samsung,pins = "gpp16-0", "gpp16-1", "gpp16-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi8_cs: spi8-cs-pins { + samsung,pins = "gpp16-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi8_cs_func: spi8-cs-func-pins { + samsung,pins = "gpp16-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c7_bus: hsi2c7-bus-pins { + samsung,pins = "gpp14-0", "gpp14-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + uart7_bus_single: uart7-bus-pins { + samsung,pins = "gpp14-0", "gpp14-1", + "gpp14-2", "gpp14-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi7_bus: spi7-bus-pins { + samsung,pins = "gpp14-0", "gpp14-1", "gpp14-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi7_cs: spi7-cs-pins { + samsung,pins = "gpp14-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi7_cs_func: spi7-cs-func-pins { + samsung,pins = "gpp14-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c6_bus: hsi2c6-bus-pins { + samsung,pins = "gpp12-0", "gpp12-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + uart6_bus_single: uart6-bus-pins { + samsung,pins = "gpp12-0", "gpp12-1", + "gpp12-2", "gpp12-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi6_bus: spi6-bus-pins { + samsung,pins = "gpp12-0", "gpp12-1", "gpp12-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi6_cs: spi6-cs-pins { + samsung,pins = "gpp12-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi6_cs_func: spi6-cs-func-pins { + samsung,pins = "gpp12-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c5_bus: hsi2c5-bus-pins { + samsung,pins = "gpp10-0", "gpp10-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + uart5_bus_single: uart5-bus-pins { + samsung,pins = "gpp10-0", "gpp10-1", + "gpp10-2", "gpp10-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi5_bus: spi5-bus-pins { + samsung,pins = "gpp10-0", "gpp10-1", "gpp10-2"; + samsung,pin-drv = ; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-con-pdn = ; + samsung,pin-pud-pdn = ; + }; + + spi5_cs_func: spi5-cs-func-pins { + samsung,pins = "gpp10-3"; + samsung,pin-drv = ; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-con-pdn = ; + samsung,pin-pud-pdn = ; + }; + + hsi2c4_bus: hsi2c4-bus-pins { + samsung,pins = "gpp8-0", "gpp8-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + uart4_bus_single: uart4-bus-pins { + samsung,pins = "gpp8-0", "gpp8-1", + "gpp8-2", "gpp8-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi4_bus: spi4-bus-pins { + samsung,pins = "gpp8-0", "gpp8-1", "gpp8-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi4_cs: spi4-cs-pins { + samsung,pins = "gpp8-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi4_cs_func: spi4-cs-func-pins { + samsung,pins = "gpp8-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c3_bus: hsi2c3-bus-pins { + samsung,pins = "gpp6-0", "gpp6-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + uart3_bus_single: uart3-bus-pins { + samsung,pins = "gpp6-0", "gpp6-1", + "gpp6-2", "gpp6-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi3_bus: spi3-bus-pins { + samsung,pins = "gpp6-0", "gpp6-1", "gpp6-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi3_cs: spi3-cs-pins { + samsung,pins = "gpp6-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi3_cs_func: spi3-cs-func-pins { + samsung,pins = "gpp6-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c2_bus: hsi2c2-bus-pins { + samsung,pins = "gpp4-0", "gpp4-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + uart2_bus_single: uart2-bus-pins { + samsung,pins = "gpp4-0", "gpp4-1", + "gpp4-2", "gpp4-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi2_bus: spi2-bus-pins { + samsung,pins = "gpp4-0", "gpp4-1", "gpp4-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi2_cs: spi2-cs-pins { + samsung,pins = "gpp4-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi2_cs_func: spi2-cs-func-pins { + samsung,pins = "gpp4-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c1_bus: hsi2c1-bus-pins { + samsung,pins = "gpp2-0", "gpp2-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + uart1_bus_single: uart1-bus-pins { + samsung,pins = "gpp2-0", "gpp2-1", + "gpp2-2", "gpp2-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi1_bus: spi1-bus-pins { + samsung,pins = "gpp2-0", "gpp2-1", "gpp2-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi1_cs: spi1-cs-pins { + samsung,pins = "gpp2-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi1_cs_func: spi1-cs-func-pins { + samsung,pins = "gpp2-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; +}; + +&pinctrl_peric1 { + gpp20: gpp20-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp21: gpp21-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp22: gpp22-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp23: gpp23-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp24: gpp24-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp25: gpp25-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp26: gpp26-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + gpp27: gpp27-gpio-bank { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + hsi2c13_bus: hsi2c13-bus-pins { + samsung,pins = "gpp25-0", "gpp25-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + uart13_bus_single: uart13-bus-pins { + samsung,pins = "gpp25-0", "gpp25-1", + "gpp25-2", "gpp25-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi13_bus: spi13-bus-pins { + samsung,pins = "gpp25-0", "gpp25-1", "gpp25-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi13_cs: spi13-cs-pins { + samsung,pins = "gpp25-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi13_cs_func: spi13-cs-func-pins { + samsung,pins = "gpp25-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c12_bus: hsi2c12-bus-pins { + samsung,pins = "gpp23-4", "gpp23-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + uart12_bus_single: uart12-bus-pins { + samsung,pins = "gpp23-4", "gpp23-5", + "gpp23-6", "gpp23-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi12_bus: spi12-bus-pins { + samsung,pins = "gpp23-4", "gpp23-5", "gpp23-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi14_cs2: spi14-cs2-pins { + samsung,pins = "gpp23-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi12_cs: spi12-cs-pins { + samsung,pins = "gpp23-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi12_cs_func: spi12-cs-func-pins { + samsung,pins = "gpp23-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c11_bus: hsi2c11-bus-pins { + samsung,pins = "gpp23-0", "gpp23-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + uart11_bus_single: uart11-bus-pins { + samsung,pins = "gpp23-0", "gpp23-1", + "gpp23-2", "gpp23-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi11_bus: spi11-bus-pins { + samsung,pins = "gpp23-0", "gpp23-1", "gpp23-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi11_cs: spi11-cs-pins { + samsung,pins = "gpp23-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi11_cs_func: spi11-cs-func-pins { + samsung,pins = "gpp23-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c10_bus: hsi2c10-bus-pins { + samsung,pins = "gpp21-0", "gpp21-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + uart10_bus_single: uart10-bus-pins { + samsung,pins = "gpp21-0", "gpp21-1", + "gpp21-2", "gpp21-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi10_bus: spi10-bus-pins { + samsung,pins = "gpp21-0", "gpp21-1", "gpp21-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi10_cs: spi10-cs-pins { + samsung,pins = "gpp21-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi10_cs_func: spi10-cs-func-pins { + samsung,pins = "gpp21-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c9_bus: hsi2c9-bus-pins { + samsung,pins = "gpp20-4", "gpp20-5"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + uart9_bus_single: uart9-bus-pins { + samsung,pins = "gpp20-4", "gpp20-5", + "gpp20-6", "gpp20-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi9_bus: spi9-bus-pins { + samsung,pins = "gpp20-4", "gpp20-5", "gpp20-6"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi9_cs: spi9-cs-pins { + samsung,pins = "gpp20-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi9_cs_func: spi9-cs-func-pins { + samsung,pins = "gpp20-7"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + hsi2c0_bus: hsi2c0-bus-pins { + samsung,pins = "gpp20-0", "gpp20-1"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + uart0_bus_single: uart0-bus-pins { + samsung,pins = "gpp20-0", "gpp20-1", + "gpp20-2", "gpp20-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + }; + + spi0_bus: spi0-bus-pins { + samsung,pins = "gpp20-0", "gpp20-1", "gpp20-2"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi0_cs: spi0-cs-pins { + samsung,pins = "gpp20-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; + + spi0_cs_func: spi0-cs-func-pins { + samsung,pins = "gpp20-3"; + samsung,pin-function = ; + samsung,pin-pud = ; + samsung,pin-drv = ; + }; +}; diff --git a/arch/arm64/boot/dts/exynos/google/gs101-pinctrl.h b/arch/arm64/boot/dts/exynos/google/gs101-pinctrl.h new file mode 100644 index 00000000000000..b7d276b1e25a8d --- /dev/null +++ b/arch/arm64/boot/dts/exynos/google/gs101-pinctrl.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Pinctrl binding constants for GS101 + * + * Copyright 2020-2023 Google LLC + */ + +#ifndef __DTS_ARM64_SAMSUNG_EXYNOS_GOOGLE_PINCTRL_GS101_H__ +#define __DTS_ARM64_SAMSUNG_EXYNOS_GOOGLE_PINCTRL_GS101_H__ + +#define GS101_PIN_PULL_NONE 0 +#define GS101_PIN_PULL_DOWN 1 +#define GS101_PIN_PULL_UP 3 + +/* Pin function in power down mode */ +#define GS101_PIN_PDN_OUT0 0 +#define GS101_PIN_PDN_OUT1 1 +#define GS101_PIN_PDN_INPUT 2 +#define GS101_PIN_PDN_PREV 3 + +/* GS101 drive strengths */ +#define GS101_PIN_DRV_2_5_MA 0 +#define GS101_PIN_DRV_5_MA 1 +#define GS101_PIN_DRV_7_5_MA 2 +#define GS101_PIN_DRV_10_MA 3 + +#define GS101_PIN_FUNC_INPUT 0 +#define GS101_PIN_FUNC_OUTPUT 1 +#define GS101_PIN_FUNC_2 2 +#define GS101_PIN_FUNC_3 3 +#define GS101_PIN_FUNC_EINT 0xf + +#endif /* __DTS_ARM64_SAMSUNG_EXYNOS_GOOGLE_PINCTRL_GS101_H__ */ diff --git a/arch/arm64/boot/dts/exynos/google/gs101.dtsi b/arch/arm64/boot/dts/exynos/google/gs101.dtsi new file mode 100644 index 00000000000000..d838e3a7af6e5d --- /dev/null +++ b/arch/arm64/boot/dts/exynos/google/gs101.dtsi @@ -0,0 +1,473 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * GS101 SoC + * + * Copyright 2019-2023 Google LLC + * Copyright 2023 Linaro Ltd - + */ + +#include +#include +#include +#include + +/ { + compatible = "google,gs101"; + #address-cells = <2>; + #size-cells = <1>; + + interrupt-parent = <&gic>; + + aliases { + pinctrl0 = &pinctrl_gpio_alive; + pinctrl1 = &pinctrl_far_alive; + pinctrl2 = &pinctrl_gsacore; + pinctrl3 = &pinctrl_gsactrl; + pinctrl4 = &pinctrl_peric0; + pinctrl5 = &pinctrl_peric1; + pinctrl6 = &pinctrl_hsi1; + pinctrl7 = &pinctrl_hsi2; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu-map { + cluster0 { + core0 { + cpu = <&cpu0>; + }; + core1 { + cpu = <&cpu1>; + }; + core2 { + cpu = <&cpu2>; + }; + core3 { + cpu = <&cpu3>; + }; + }; + + cluster1 { + core0 { + cpu = <&cpu4>; + }; + core1 { + cpu = <&cpu5>; + }; + }; + + cluster2 { + core0 { + cpu = <&cpu6>; + }; + core1 { + cpu = <&cpu7>; + }; + }; + }; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0000>; + enable-method = "psci"; + cpu-idle-states = <&ANANKE_CPU_SLEEP>; + capacity-dmips-mhz = <250>; + dynamic-power-coefficient = <70>; + }; + + cpu1: cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0100>; + enable-method = "psci"; + cpu-idle-states = <&ANANKE_CPU_SLEEP>; + capacity-dmips-mhz = <250>; + dynamic-power-coefficient = <70>; + }; + + cpu2: cpu@200 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0200>; + enable-method = "psci"; + cpu-idle-states = <&ANANKE_CPU_SLEEP>; + capacity-dmips-mhz = <250>; + dynamic-power-coefficient = <70>; + }; + + cpu3: cpu@300 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0300>; + enable-method = "psci"; + cpu-idle-states = <&ANANKE_CPU_SLEEP>; + capacity-dmips-mhz = <250>; + dynamic-power-coefficient = <70>; + }; + + cpu4: cpu@400 { + device_type = "cpu"; + compatible = "arm,cortex-a76"; + reg = <0x0400>; + enable-method = "psci"; + cpu-idle-states = <&ENYO_CPU_SLEEP>; + capacity-dmips-mhz = <620>; + dynamic-power-coefficient = <284>; + }; + + cpu5: cpu@500 { + device_type = "cpu"; + compatible = "arm,cortex-a76"; + reg = <0x0500>; + enable-method = "psci"; + cpu-idle-states = <&ENYO_CPU_SLEEP>; + capacity-dmips-mhz = <620>; + dynamic-power-coefficient = <284>; + }; + + cpu6: cpu@600 { + device_type = "cpu"; + compatible = "arm,cortex-x1"; + reg = <0x0600>; + enable-method = "psci"; + cpu-idle-states = <&HERA_CPU_SLEEP>; + capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <650>; + }; + + cpu7: cpu@700 { + device_type = "cpu"; + compatible = "arm,cortex-x1"; + reg = <0x0700>; + enable-method = "psci"; + cpu-idle-states = <&HERA_CPU_SLEEP>; + capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <650>; + }; + + idle-states { + entry-method = "psci"; + + ANANKE_CPU_SLEEP: cpu-ananke-sleep { + idle-state-name = "c2"; + compatible = "arm,idle-state"; + arm,psci-suspend-param = <0x0010000>; + entry-latency-us = <70>; + exit-latency-us = <160>; + min-residency-us = <2000>; + }; + + ENYO_CPU_SLEEP: cpu-enyo-sleep { + idle-state-name = "c2"; + compatible = "arm,idle-state"; + arm,psci-suspend-param = <0x0010000>; + entry-latency-us = <150>; + exit-latency-us = <190>; + min-residency-us = <2500>; + }; + + HERA_CPU_SLEEP: cpu-hera-sleep { + idle-state-name = "c2"; + compatible = "arm,idle-state"; + arm,psci-suspend-param = <0x0010000>; + entry-latency-us = <235>; + exit-latency-us = <220>; + min-residency-us = <3500>; + }; + }; + }; + + /* TODO replace with CCF clock */ + dummy_clk: clock-3 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <12345>; + clock-output-names = "pclk"; + }; + + /* ect node is required to be present by bootloader */ + ect { + }; + + ext_24_5m: clock-1 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-output-names = "oscclk"; + }; + + ext_200m: clock-2 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-output-names = "ext-200m"; + }; + + pmu-0 { + compatible = "arm,cortex-a55-pmu"; + interrupts = ; + }; + + pmu-1 { + compatible = "arm,cortex-a76-pmu"; + interrupts = ; + }; + + pmu-2 { + compatible = "arm,cortex-x1-pmu"; + interrupts = ; + }; + + pmu-3 { + compatible = "arm,dsu-pmu"; + interrupts = ; + cpus = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>, + <&cpu4>, <&cpu5>, <&cpu6>, <&cpu7>; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + + reserved_memory: reserved-memory { + #address-cells = <2>; + #size-cells = <1>; + ranges; + + gsa_reserved_protected: gsa@90200000 { + reg = <0x0 0x90200000 0x400000>; + no-map; + }; + + tpu_fw_reserved: tpu-fw@93000000 { + reg = <0x0 0x93000000 0x1000000>; + no-map; + }; + + aoc_reserve: aoc@94000000 { + reg = <0x0 0x94000000 0x03000000>; + no-map; + }; + + abl_reserved: abl@f8800000 { + reg = <0x0 0xf8800000 0x02000000>; + no-map; + }; + + dss_log_reserved: dss-log-reserved@fd3f0000 { + reg = <0x0 0xfd3f0000 0x0000e000>; + no-map; + }; + + debug_kinfo_reserved: debug-kinfo-reserved@fd3fe000 { + reg = <0x0 0xfd3fe000 0x00001000>; + no-map; + }; + + bldr_log_reserved: bldr-log-reserved@fd800000 { + reg = <0x0 0xfd800000 0x00100000>; + no-map; + }; + + bldr_log_hist_reserved: bldr-log-hist-reserved@fd900000 { + reg = <0x0 0xfd900000 0x00002000>; + no-map; + }; + }; + + soc: soc@0 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x0 0x0 0x40000000>; + + cmu_misc: clock-controller@10010000 { + compatible = "google,gs101-cmu-misc"; + reg = <0x10010000 0x8000>; + #clock-cells = <1>; + clocks = <&cmu_top CLK_DOUT_CMU_MISC_BUS>, + <&cmu_top CLK_DOUT_CMU_MISC_SSS>; + clock-names = "bus", "sss"; + }; + + watchdog_cl0: watchdog@10060000 { + compatible = "google,gs101-wdt"; + reg = <0x10060000 0x100>; + interrupts = ; + clocks = <&cmu_misc CLK_GOUT_MISC_WDT_CLUSTER0_PCLK>, + <&ext_24_5m>; + clock-names = "watchdog", "watchdog_src"; + samsung,syscon-phandle = <&pmu_system_controller>; + samsung,cluster-index = <0>; + status = "disabled"; + }; + + watchdog_cl1: watchdog@10070000 { + compatible = "google,gs101-wdt"; + reg = <0x10070000 0x100>; + interrupts = ; + clocks = <&cmu_misc CLK_GOUT_MISC_WDT_CLUSTER1_PCLK>, + <&ext_24_5m>; + clock-names = "watchdog", "watchdog_src"; + samsung,syscon-phandle = <&pmu_system_controller>; + samsung,cluster-index = <1>; + status = "disabled"; + }; + + gic: interrupt-controller@10400000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <4>; + interrupt-controller; + reg = <0x10400000 0x10000>, /* GICD */ + <0x10440000 0x100000>;/* GICR * 8 */ + interrupts = ; + + ppi-partitions { + ppi_cluster0: interrupt-partition-0 { + affinity = <&cpu0 &cpu1 &cpu2 &cpu3>; + }; + + ppi_cluster1: interrupt-partition-1 { + affinity = <&cpu4 &cpu5>; + }; + + ppi_cluster2: interrupt-partition-2 { + affinity = <&cpu6 &cpu7>; + }; + }; + }; + + sysreg_peric0: syscon@10820000 { + compatible = "google,gs101-peric0-sysreg", "syscon"; + reg = <0x10820000 0x10000>; + }; + + pinctrl_peric0: pinctrl@10840000 { + compatible = "google,gs101-pinctrl"; + reg = <0x10840000 0x00001000>; + interrupts = ; + }; + + usi_uart: usi@10a000c0 { + compatible = "google,gs101-usi", + "samsung,exynos850-usi"; + reg = <0x10a000c0 0x20>; + ranges; + #address-cells = <1>; + #size-cells = <1>; + clocks = <&dummy_clk>, <&dummy_clk>; + clock-names = "pclk", "ipclk"; + samsung,sysreg = <&sysreg_peric0 0x1020>; + samsung,mode = ; + status = "disabled"; + + serial_0: serial@10a00000 { + compatible = "google,gs101-uart"; + reg = <0x10a00000 0xc0>; + reg-io-width = <4>; + interrupts = ; + clocks = <&dummy_clk 0>, <&dummy_clk 0>; + clock-names = "uart", "clk_uart_baud0"; + samsung,uart-fifosize = <256>; + status = "disabled"; + }; + }; + + sysreg_peric1: syscon@10c20000 { + compatible = "google,gs101-peric1-sysreg", "syscon"; + reg = <0x10c20000 0x10000>; + }; + + pinctrl_peric1: pinctrl@10c40000 { + compatible = "google,gs101-pinctrl"; + reg = <0x10c40000 0x00001000>; + interrupts = ; + }; + + pinctrl_hsi1: pinctrl@11840000 { + compatible = "google,gs101-pinctrl"; + reg = <0x11840000 0x00001000>; + interrupts = ; + }; + + pinctrl_hsi2: pinctrl@14440000 { + compatible = "google,gs101-pinctrl"; + reg = <0x14440000 0x00001000>; + interrupts = ; + }; + + cmu_apm: clock-controller@17400000 { + compatible = "google,gs101-cmu-apm"; + reg = <0x17400000 0x8000>; + #clock-cells = <1>; + + clocks = <&ext_24_5m>; + clock-names = "oscclk"; + }; + + sysreg_apm: syscon@174204e0 { + compatible = "google,gs101-apm-sysreg", "syscon"; + reg = <0x174204e0 0x1000>; + }; + + pmu_system_controller: system-controller@17460000 { + compatible = "google,gs101-pmu", "syscon"; + reg = <0x17460000 0x10000>; + }; + + pinctrl_gpio_alive: pinctrl@174d0000 { + compatible = "google,gs101-pinctrl"; + reg = <0x174d0000 0x00001000>; + + wakeup-interrupt-controller { + compatible = "google,gs101-wakeup-eint", + "samsung,exynos850-wakeup-eint", + "samsung,exynos7-wakeup-eint"; + }; + }; + + pinctrl_far_alive: pinctrl@174e0000 { + compatible = "google,gs101-pinctrl"; + reg = <0x174e0000 0x00001000>; + + wakeup-interrupt-controller { + compatible = "google,gs101-wakeup-eint", + "samsung,exynos850-wakeup-eint", + "samsung,exynos7-wakeup-eint"; + }; + }; + + pinctrl_gsactrl: pinctrl@17940000 { + compatible = "google,gs101-pinctrl"; + reg = <0x17940000 0x00001000>; + }; + + pinctrl_gsacore: pinctrl@17a80000 { + compatible = "google,gs101-pinctrl"; + reg = <0x17a80000 0x00001000>; + }; + + cmu_top: clock-controller@1e080000 { + compatible = "google,gs101-cmu-top"; + reg = <0x1e080000 0x8000>; + #clock-cells = <1>; + + clocks = <&ext_24_5m>; + clock-names = "oscclk"; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = + , + , + , + ; + }; +}; + +#include "gs101-pinctrl.dtsi" diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile index 300049037eb0bd..2e027675d7bbe1 100644 --- a/arch/arm64/boot/dts/freescale/Makefile +++ b/arch/arm64/boot/dts/freescale/Makefile @@ -53,6 +53,32 @@ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-qds-85bb.dtb dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-qds-899b.dtb dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-qds-9999.dtb +fsl-lx2160a-tqmlx2160a-mblx2160a-12-11-x-dtbs := fsl-lx2160a-tqmlx2160a-mblx2160a.dtb \ + fsl-lx2160a-tqmlx2160a-mblx2160a_12_x_x.dtbo \ + fsl-lx2160a-tqmlx2160a-mblx2160a_x_11_x.dtbo +fsl-lx2160a-tqmlx2160a-mblx2160a-12-7-x-dtbs := fsl-lx2160a-tqmlx2160a-mblx2160a.dtb \ + fsl-lx2160a-tqmlx2160a-mblx2160a_12_x_x.dtbo \ + fsl-lx2160a-tqmlx2160a-mblx2160a_x_7_x.dtbo +fsl-lx2160a-tqmlx2160a-mblx2160a-12-8-x-dtbs := fsl-lx2160a-tqmlx2160a-mblx2160a.dtb \ + fsl-lx2160a-tqmlx2160a-mblx2160a_12_x_x.dtbo \ + fsl-lx2160a-tqmlx2160a-mblx2160a_x_8_x.dtbo +fsl-lx2160a-tqmlx2160a-mblx2160a-14-7-x-dtbs := fsl-lx2160a-tqmlx2160a-mblx2160a.dtb \ + fsl-lx2160a-tqmlx2160a-mblx2160a_14_x_x.dtbo \ + fsl-lx2160a-tqmlx2160a-mblx2160a_x_7_x.dtbo +fsl-lx2160a-tqmlx2160a-mblx2160a-14-8-x-dtbs := fsl-lx2160a-tqmlx2160a-mblx2160a.dtb \ + fsl-lx2160a-tqmlx2160a-mblx2160a_14_x_x.dtbo \ + fsl-lx2160a-tqmlx2160a-mblx2160a_x_8_x.dtbo +fsl-lx2160a-tqmlx2160a-mblx2160a-14-11-x-dtbs := fsl-lx2160a-tqmlx2160a-mblx2160a.dtb \ + fsl-lx2160a-tqmlx2160a-mblx2160a_14_x_x.dtbo \ + fsl-lx2160a-tqmlx2160a-mblx2160a_x_11_x.dtbo + +dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2160a-tqmlx2160a-mblx2160a-12-11-x.dtb +dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2160a-tqmlx2160a-mblx2160a-12-8-x.dtb +dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2160a-tqmlx2160a-mblx2160a-12-7-x.dtb +dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2160a-tqmlx2160a-mblx2160a-14-11-x.dtb +dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2160a-tqmlx2160a-mblx2160a-14-8-x.dtb +dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2160a-tqmlx2160a-mblx2160a-14-7-x.dtb + dtb-$(CONFIG_ARCH_MXC) += imx8dxl-evk.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-beacon-kit.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-data-modul-edm-sbc.dtb @@ -84,9 +110,11 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mm-venice-gw7904.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-venice-gw7905-0x.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-dahlia.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-dev.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-mallow.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-nonwifi-yavia.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dahlia.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-dev.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-mallow.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mm-verdin-wifi-yavia.dtb imx8mm-tqma8mqml-mba8mx-lvds-tm070jvhg33-dtbs += imx8mm-tqma8mqml-mba8mx.dtb imx8mm-tqma8mqml-mba8mx-lvds-tm070jvhg33.dtbo @@ -95,9 +123,11 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mm-tqma8mqml-mba8mx-lvds-tm070jvhg33.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mn-beacon-kit.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mn-bsh-smm-s2.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mn-bsh-smm-s2pro.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mn-dimonoff-gateway-evk.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mn-evk.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mn-ddr3l-evk.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mn-ddr4-evk.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mn-rve-gateway.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mn-tqma8mqnl-mba8mx.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mn-var-som-symphony.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mn-venice-gw7902.dtb @@ -115,6 +145,9 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-icore-mx8mp-edimm2.2.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-msc-sm2s-ep1.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-phyboard-pollux-rdk.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mp-skov-revb-hdmi.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mp-skov-revb-lt6.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mp-skov-revb-mi1010ait-1cp1.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-tqma8mpql-mba8mpxl.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-venice-gw71xx-2x.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-venice-gw72xx-2x.dtb @@ -123,13 +156,17 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mp-venice-gw74xx.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-venice-gw7905-2x.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-verdin-nonwifi-dahlia.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-verdin-nonwifi-dev.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mp-verdin-nonwifi-mallow.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-verdin-nonwifi-yavia.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-verdin-wifi-dahlia.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-verdin-wifi-dev.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mp-verdin-wifi-mallow.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mp-verdin-wifi-yavia.dtb imx8mp-tqma8mpql-mba8mpxl-lvds-dtbs += imx8mp-tqma8mpql-mba8mpxl.dtb imx8mp-tqma8mpql-mba8mpxl-lvds.dtbo +imx8mp-tqma8mpql-mba8mpxl-lvds-g133han01-dtbs += imx8mp-tqma8mpql-mba8mpxl.dtb imx8mp-tqma8mpql-mba8mpxl-lvds-g133han01.dtbo dtb-$(CONFIG_ARCH_MXC) += imx8mp-tqma8mpql-mba8mpxl-lvds.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mp-tqma8mpql-mba8mpxl-lvds-g133han01.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mq-evk.dtb dtb-$(CONFIG_ARCH_MXC) += imx8mq-hummingboard-pulse.dtb @@ -164,6 +201,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx8qxp-colibri-iris-v2.dtb dtb-$(CONFIG_ARCH_MXC) += imx8qxp-mek.dtb dtb-$(CONFIG_ARCH_MXC) += imx8ulp-evk.dtb dtb-$(CONFIG_ARCH_MXC) += imx93-11x11-evk.dtb +dtb-$(CONFIG_ARCH_MXC) += imx93-tqma9352-mba93xxca.dtb dtb-$(CONFIG_ARCH_MXC) += imx93-tqma9352-mba93xxla.dtb imx8mm-venice-gw72xx-0x-imx219-dtbs := imx8mm-venice-gw72xx-0x.dtb imx8mm-venice-gw72xx-0x-imx219.dtbo diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi index a863022529ac5d..1e3fe3897b52ce 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi @@ -307,46 +307,46 @@ reg = <0x0 0x1f00000 0x0 0x10000>; interrupts = <0 33 0x4>; fsl,tmu-range = <0xb0000 0x9002a 0x6004c 0x60062>; - fsl,tmu-calibration = <0x00000000 0x00000025 - 0x00000001 0x0000002c - 0x00000002 0x00000032 - 0x00000003 0x00000039 - 0x00000004 0x0000003f - 0x00000005 0x00000046 - 0x00000006 0x0000004c - 0x00000007 0x00000053 - 0x00000008 0x00000059 - 0x00000009 0x0000005f - 0x0000000a 0x00000066 - 0x0000000b 0x0000006c - - 0x00010000 0x00000026 - 0x00010001 0x0000002d - 0x00010002 0x00000035 - 0x00010003 0x0000003d - 0x00010004 0x00000045 - 0x00010005 0x0000004d - 0x00010006 0x00000055 - 0x00010007 0x0000005d - 0x00010008 0x00000065 - 0x00010009 0x0000006d - - 0x00020000 0x00000026 - 0x00020001 0x00000030 - 0x00020002 0x0000003a - 0x00020003 0x00000044 - 0x00020004 0x0000004e - 0x00020005 0x00000059 - 0x00020006 0x00000063 - - 0x00030000 0x00000014 - 0x00030001 0x00000021 - 0x00030002 0x0000002e - 0x00030003 0x0000003a - 0x00030004 0x00000047 - 0x00030005 0x00000053 - 0x00030006 0x00000060>; - big-endian; + fsl,tmu-calibration = + <0x00000000 0x00000025>, + <0x00000001 0x0000002c>, + <0x00000002 0x00000032>, + <0x00000003 0x00000039>, + <0x00000004 0x0000003f>, + <0x00000005 0x00000046>, + <0x00000006 0x0000004c>, + <0x00000007 0x00000053>, + <0x00000008 0x00000059>, + <0x00000009 0x0000005f>, + <0x0000000a 0x00000066>, + <0x0000000b 0x0000006c>, + + <0x00010000 0x00000026>, + <0x00010001 0x0000002d>, + <0x00010002 0x00000035>, + <0x00010003 0x0000003d>, + <0x00010004 0x00000045>, + <0x00010005 0x0000004d>, + <0x00010006 0x00000055>, + <0x00010007 0x0000005d>, + <0x00010008 0x00000065>, + <0x00010009 0x0000006d>, + + <0x00020000 0x00000026>, + <0x00020001 0x00000030>, + <0x00020002 0x0000003a>, + <0x00020003 0x00000044>, + <0x00020004 0x0000004e>, + <0x00020005 0x00000059>, + <0x00020006 0x00000063>, + + <0x00030000 0x00000014>, + <0x00030001 0x00000021>, + <0x00030002 0x0000002e>, + <0x00030003 0x0000003a>, + <0x00030004 0x00000047>, + <0x00030005 0x00000053>, + <0x00030006 0x00000060>; #thermal-sensor-cells = <1>; }; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi index eefe3577d94e04..ae534c23b970a2 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi @@ -1026,49 +1026,50 @@ reg = <0x0 0x1f80000 0x0 0x10000>; interrupts = <0 23 0x4>; fsl,tmu-range = <0xb0000 0xa0026 0x80048 0x70061>; - fsl,tmu-calibration = <0x00000000 0x00000024 - 0x00000001 0x0000002b - 0x00000002 0x00000031 - 0x00000003 0x00000038 - 0x00000004 0x0000003f - 0x00000005 0x00000045 - 0x00000006 0x0000004c - 0x00000007 0x00000053 - 0x00000008 0x00000059 - 0x00000009 0x00000060 - 0x0000000a 0x00000066 - 0x0000000b 0x0000006d - - 0x00010000 0x0000001c - 0x00010001 0x00000024 - 0x00010002 0x0000002c - 0x00010003 0x00000035 - 0x00010004 0x0000003d - 0x00010005 0x00000045 - 0x00010006 0x0000004d - 0x00010007 0x00000055 - 0x00010008 0x0000005e - 0x00010009 0x00000066 - 0x0001000a 0x0000006e - - 0x00020000 0x00000018 - 0x00020001 0x00000022 - 0x00020002 0x0000002d - 0x00020003 0x00000038 - 0x00020004 0x00000043 - 0x00020005 0x0000004d - 0x00020006 0x00000058 - 0x00020007 0x00000063 - 0x00020008 0x0000006e - - 0x00030000 0x00000010 - 0x00030001 0x0000001c - 0x00030002 0x00000029 - 0x00030003 0x00000036 - 0x00030004 0x00000042 - 0x00030005 0x0000004f - 0x00030006 0x0000005b - 0x00030007 0x00000068>; + fsl,tmu-calibration = + <0x00000000 0x00000024>, + <0x00000001 0x0000002b>, + <0x00000002 0x00000031>, + <0x00000003 0x00000038>, + <0x00000004 0x0000003f>, + <0x00000005 0x00000045>, + <0x00000006 0x0000004c>, + <0x00000007 0x00000053>, + <0x00000008 0x00000059>, + <0x00000009 0x00000060>, + <0x0000000a 0x00000066>, + <0x0000000b 0x0000006d>, + + <0x00010000 0x0000001c>, + <0x00010001 0x00000024>, + <0x00010002 0x0000002c>, + <0x00010003 0x00000035>, + <0x00010004 0x0000003d>, + <0x00010005 0x00000045>, + <0x00010006 0x0000004d>, + <0x00010007 0x00000055>, + <0x00010008 0x0000005e>, + <0x00010009 0x00000066>, + <0x0001000a 0x0000006e>, + + <0x00020000 0x00000018>, + <0x00020001 0x00000022>, + <0x00020002 0x0000002d>, + <0x00020003 0x00000038>, + <0x00020004 0x00000043>, + <0x00020005 0x0000004d>, + <0x00020006 0x00000058>, + <0x00020007 0x00000063>, + <0x00020008 0x0000006e>, + + <0x00030000 0x00000010>, + <0x00030001 0x0000001c>, + <0x00030002 0x00000029>, + <0x00030003 0x00000036>, + <0x00030004 0x00000042>, + <0x00030005 0x0000004f>, + <0x00030006 0x0000005b>, + <0x00030007 0x00000068>; little-endian; #thermal-sensor-cells = <1>; }; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi index 229bb4bebe4267..d333b773bc455e 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi @@ -447,46 +447,47 @@ reg = <0x0 0x1f00000 0x0 0x10000>; interrupts = <0 33 0x4>; fsl,tmu-range = <0xb0000 0x9002a 0x6004c 0x70062>; - fsl,tmu-calibration = <0x00000000 0x00000023 - 0x00000001 0x0000002a - 0x00000002 0x00000031 - 0x00000003 0x00000037 - 0x00000004 0x0000003e - 0x00000005 0x00000044 - 0x00000006 0x0000004b - 0x00000007 0x00000051 - 0x00000008 0x00000058 - 0x00000009 0x0000005e - 0x0000000a 0x00000065 - 0x0000000b 0x0000006b - - 0x00010000 0x00000023 - 0x00010001 0x0000002b - 0x00010002 0x00000033 - 0x00010003 0x0000003b - 0x00010004 0x00000043 - 0x00010005 0x0000004b - 0x00010006 0x00000054 - 0x00010007 0x0000005c - 0x00010008 0x00000064 - 0x00010009 0x0000006c - - 0x00020000 0x00000021 - 0x00020001 0x0000002c - 0x00020002 0x00000036 - 0x00020003 0x00000040 - 0x00020004 0x0000004b - 0x00020005 0x00000055 - 0x00020006 0x0000005f - - 0x00030000 0x00000013 - 0x00030001 0x0000001d - 0x00030002 0x00000028 - 0x00030003 0x00000032 - 0x00030004 0x0000003d - 0x00030005 0x00000047 - 0x00030006 0x00000052 - 0x00030007 0x0000005c>; + fsl,tmu-calibration = + <0x00000000 0x00000023>, + <0x00000001 0x0000002a>, + <0x00000002 0x00000031>, + <0x00000003 0x00000037>, + <0x00000004 0x0000003e>, + <0x00000005 0x00000044>, + <0x00000006 0x0000004b>, + <0x00000007 0x00000051>, + <0x00000008 0x00000058>, + <0x00000009 0x0000005e>, + <0x0000000a 0x00000065>, + <0x0000000b 0x0000006b>, + + <0x00010000 0x00000023>, + <0x00010001 0x0000002b>, + <0x00010002 0x00000033>, + <0x00010003 0x0000003b>, + <0x00010004 0x00000043>, + <0x00010005 0x0000004b>, + <0x00010006 0x00000054>, + <0x00010007 0x0000005c>, + <0x00010008 0x00000064>, + <0x00010009 0x0000006c>, + + <0x00020000 0x00000021>, + <0x00020001 0x0000002c>, + <0x00020002 0x00000036>, + <0x00020003 0x00000040>, + <0x00020004 0x0000004b>, + <0x00020005 0x00000055>, + <0x00020006 0x0000005f>, + + <0x00030000 0x00000013>, + <0x00030001 0x0000001d>, + <0x00030002 0x00000028>, + <0x00030003 0x00000032>, + <0x00030004 0x0000003d>, + <0x00030005 0x00000047>, + <0x00030006 0x00000052>, + <0x00030007 0x0000005c>; #thermal-sensor-cells = <1>; }; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi index 50f68ca5a9af71..1515cec231470c 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi @@ -445,46 +445,46 @@ fsl,tmu-range = <0xb0000 0x9002a 0x6004c 0x70062>; fsl,tmu-calibration = /* Calibration data group 1 */ - <0x00000000 0x00000023 - 0x00000001 0x00000029 - 0x00000002 0x0000002f - 0x00000003 0x00000036 - 0x00000004 0x0000003c - 0x00000005 0x00000042 - 0x00000006 0x00000049 - 0x00000007 0x0000004f - 0x00000008 0x00000055 - 0x00000009 0x0000005c - 0x0000000a 0x00000062 - 0x0000000b 0x00000068 + <0x00000000 0x00000023>, + <0x00000001 0x00000029>, + <0x00000002 0x0000002f>, + <0x00000003 0x00000036>, + <0x00000004 0x0000003c>, + <0x00000005 0x00000042>, + <0x00000006 0x00000049>, + <0x00000007 0x0000004f>, + <0x00000008 0x00000055>, + <0x00000009 0x0000005c>, + <0x0000000a 0x00000062>, + <0x0000000b 0x00000068>, /* Calibration data group 2 */ - 0x00010000 0x00000022 - 0x00010001 0x0000002a - 0x00010002 0x00000032 - 0x00010003 0x0000003a - 0x00010004 0x00000042 - 0x00010005 0x0000004a - 0x00010006 0x00000052 - 0x00010007 0x0000005a - 0x00010008 0x00000062 - 0x00010009 0x0000006a + <0x00010000 0x00000022>, + <0x00010001 0x0000002a>, + <0x00010002 0x00000032>, + <0x00010003 0x0000003a>, + <0x00010004 0x00000042>, + <0x00010005 0x0000004a>, + <0x00010006 0x00000052>, + <0x00010007 0x0000005a>, + <0x00010008 0x00000062>, + <0x00010009 0x0000006a>, /* Calibration data group 3 */ - 0x00020000 0x00000021 - 0x00020001 0x0000002b - 0x00020002 0x00000035 - 0x00020003 0x0000003e - 0x00020004 0x00000048 - 0x00020005 0x00000052 - 0x00020006 0x0000005c + <0x00020000 0x00000021>, + <0x00020001 0x0000002b>, + <0x00020002 0x00000035>, + <0x00020003 0x0000003e>, + <0x00020004 0x00000048>, + <0x00020005 0x00000052>, + <0x00020006 0x0000005c>, /* Calibration data group 4 */ - 0x00030000 0x00000011 - 0x00030001 0x0000001a - 0x00030002 0x00000024 - 0x00030003 0x0000002e - 0x00030004 0x00000038 - 0x00030005 0x00000042 - 0x00030006 0x0000004c - 0x00030007 0x00000056>; + <0x00030000 0x00000011>, + <0x00030001 0x0000001a>, + <0x00030002 0x00000024>, + <0x00030003 0x0000002e>, + <0x00030004 0x00000038>, + <0x00030005 0x00000042>, + <0x00030006 0x0000004c>, + <0x00030007 0x00000056>; big-endian; #thermal-sensor-cells = <1>; }; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi index 8f6090a9aef2b3..8616d5e0c38845 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls1088a.dtsi @@ -284,46 +284,46 @@ fsl,tmu-range = <0xb0000 0x9002a 0x6004c 0x70062>; fsl,tmu-calibration = /* Calibration data group 1 */ - <0x00000000 0x00000023 - 0x00000001 0x0000002a - 0x00000002 0x00000030 - 0x00000003 0x00000037 - 0x00000004 0x0000003d - 0x00000005 0x00000044 - 0x00000006 0x0000004a - 0x00000007 0x00000051 - 0x00000008 0x00000057 - 0x00000009 0x0000005e - 0x0000000a 0x00000064 - 0x0000000b 0x0000006b + <0x00000000 0x00000023>, + <0x00000001 0x0000002a>, + <0x00000002 0x00000030>, + <0x00000003 0x00000037>, + <0x00000004 0x0000003d>, + <0x00000005 0x00000044>, + <0x00000006 0x0000004a>, + <0x00000007 0x00000051>, + <0x00000008 0x00000057>, + <0x00000009 0x0000005e>, + <0x0000000a 0x00000064>, + <0x0000000b 0x0000006b>, /* Calibration data group 2 */ - 0x00010000 0x00000022 - 0x00010001 0x0000002a - 0x00010002 0x00000032 - 0x00010003 0x0000003a - 0x00010004 0x00000042 - 0x00010005 0x0000004a - 0x00010006 0x00000052 - 0x00010007 0x0000005a - 0x00010008 0x00000062 - 0x00010009 0x0000006a + <0x00010000 0x00000022>, + <0x00010001 0x0000002a>, + <0x00010002 0x00000032>, + <0x00010003 0x0000003a>, + <0x00010004 0x00000042>, + <0x00010005 0x0000004a>, + <0x00010006 0x00000052>, + <0x00010007 0x0000005a>, + <0x00010008 0x00000062>, + <0x00010009 0x0000006a>, /* Calibration data group 3 */ - 0x00020000 0x00000021 - 0x00020001 0x0000002b - 0x00020002 0x00000035 - 0x00020003 0x00000040 - 0x00020004 0x0000004a - 0x00020005 0x00000054 - 0x00020006 0x0000005e + <0x00020000 0x00000021>, + <0x00020001 0x0000002b>, + <0x00020002 0x00000035>, + <0x00020003 0x00000040>, + <0x00020004 0x0000004a>, + <0x00020005 0x00000054>, + <0x00020006 0x0000005e>, /* Calibration data group 4 */ - 0x00030000 0x00000010 - 0x00030001 0x0000001c - 0x00030002 0x00000027 - 0x00030003 0x00000032 - 0x00030004 0x0000003e - 0x00030005 0x00000049 - 0x00030006 0x00000054 - 0x00030007 0x00000060>; + <0x00030000 0x00000010>, + <0x00030001 0x0000001c>, + <0x00030002 0x00000027>, + <0x00030003 0x00000032>, + <0x00030004 0x0000003e>, + <0x00030005 0x00000049>, + <0x00030006 0x00000054>, + <0x00030007 0x00000060>; little-endian; #thermal-sensor-cells = <1>; }; diff --git a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi index 717288bbdb8b63..0b729283590680 100644 --- a/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi @@ -321,42 +321,43 @@ reg = <0x0 0x1f80000 0x0 0x10000>; interrupts = <0 23 0x4>; fsl,tmu-range = <0xb0000 0x9002a 0x6004c 0x30062>; - fsl,tmu-calibration = <0x00000000 0x00000026 - 0x00000001 0x0000002d - 0x00000002 0x00000032 - 0x00000003 0x00000039 - 0x00000004 0x0000003f - 0x00000005 0x00000046 - 0x00000006 0x0000004d - 0x00000007 0x00000054 - 0x00000008 0x0000005a - 0x00000009 0x00000061 - 0x0000000a 0x0000006a - 0x0000000b 0x00000071 - - 0x00010000 0x00000025 - 0x00010001 0x0000002c - 0x00010002 0x00000035 - 0x00010003 0x0000003d - 0x00010004 0x00000045 - 0x00010005 0x0000004e - 0x00010006 0x00000057 - 0x00010007 0x00000061 - 0x00010008 0x0000006b - 0x00010009 0x00000076 - - 0x00020000 0x00000029 - 0x00020001 0x00000033 - 0x00020002 0x0000003d - 0x00020003 0x00000049 - 0x00020004 0x00000056 - 0x00020005 0x00000061 - 0x00020006 0x0000006d - - 0x00030000 0x00000021 - 0x00030001 0x0000002a - 0x00030002 0x0000003c - 0x00030003 0x0000004e>; + fsl,tmu-calibration = + <0x00000000 0x00000026>, + <0x00000001 0x0000002d>, + <0x00000002 0x00000032>, + <0x00000003 0x00000039>, + <0x00000004 0x0000003f>, + <0x00000005 0x00000046>, + <0x00000006 0x0000004d>, + <0x00000007 0x00000054>, + <0x00000008 0x0000005a>, + <0x00000009 0x00000061>, + <0x0000000a 0x0000006a>, + <0x0000000b 0x00000071>, + + <0x00010000 0x00000025>, + <0x00010001 0x0000002c>, + <0x00010002 0x00000035>, + <0x00010003 0x0000003d>, + <0x00010004 0x00000045>, + <0x00010005 0x0000004e>, + <0x00010006 0x00000057>, + <0x00010007 0x00000061>, + <0x00010008 0x0000006b>, + <0x00010009 0x00000076>, + + <0x00020000 0x00000029>, + <0x00020001 0x00000033>, + <0x00020002 0x0000003d>, + <0x00020003 0x00000049>, + <0x00020004 0x00000056>, + <0x00020005 0x00000061>, + <0x00020006 0x0000006d>, + + <0x00030000 0x00000021>, + <0x00030001 0x0000002a>, + <0x00030002 0x0000003c>, + <0x00030003 0x0000004e>; little-endian; #thermal-sensor-cells = <1>; }; diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a-tqmlx2160a-mblx2160a.dts b/arch/arm64/boot/dts/freescale/fsl-lx2160a-tqmlx2160a-mblx2160a.dts new file mode 100644 index 00000000000000..da0f58e26b9aae --- /dev/null +++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a-tqmlx2160a-mblx2160a.dts @@ -0,0 +1,338 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright (c) 2020-2023 TQ-Systems GmbH , + * D-82229 Seefeld, Germany. + * Author: Gregor Herburger + */ + +/dts-v1/; + +#include +#include +#include + +#include "fsl-lx2160a-tqmlx2160a.dtsi" + +/ { + model = "TQ Systems GmbH MBLX2160A Starterkit"; + compatible = "tq,lx2160a-tqmlx2160a-mblx2160a", "tq,lx2160a-tqmlx2160a", + "fsl,lx2160a"; + + aliases { + mmc0 = &esdhc0; + mmc1 = &esdhc1; + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + serial3 = &uart3; + }; + + chosen { + stdout-path = &uart0; + }; + + gpio-keys { + compatible = "gpio-keys"; + + button-user1 { + label = "button:user1"; + gpios = <&gpio2 9 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + button-user2 { + label = "button:user2"; + gpios = <&gpio2 10 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + leds { + compatible = "gpio-leds"; + + led-user1 { + gpios = <&gpioex1 15 GPIO_ACTIVE_LOW>; + color = ; + function = LED_FUNCTION_HEARTBEAT; + function-enumerator = <0>; + linux,default-trigger = "heartbeat"; + }; + + led-user2 { + gpios = <&gpio2 8 GPIO_ACTIVE_LOW>; + color = ; + function = LED_FUNCTION_HEARTBEAT; + function-enumerator = <1>; + linux,default-trigger = "heartbeat"; + }; + }; + + sfp_xfi1: sfp-xfi1 { + compatible = "sff,sfp"; + i2c-bus = <&xfi1_i2c>; + mod-def0-gpios = <&gpioex2 2 GPIO_ACTIVE_LOW>; + los-gpios = <&gpioex2 3 GPIO_ACTIVE_HIGH>; + tx-fault-gpios = <&gpioex2 0 GPIO_ACTIVE_HIGH>; + tx-disable-gpios = <&gpioex2 1 GPIO_ACTIVE_HIGH>; + status = "disabled"; + }; + + sfp_xfi2: sfp-xfi2 { + compatible = "sff,sfp"; + i2c-bus = <&xfi2_i2c>; + mod-def0-gpios = <&gpioex2 6 GPIO_ACTIVE_LOW>; + los-gpios = <&gpioex2 7 GPIO_ACTIVE_HIGH>; + tx-fault-gpios = <&gpioex2 4 GPIO_ACTIVE_HIGH>; + tx-disable-gpios = <&gpioex2 5 GPIO_ACTIVE_HIGH>; + status = "disabled"; + }; +}; + +&can0 { + status = "okay"; +}; + +&can1 { + status = "okay"; +}; + +&dpmac17 { + phy-handle = <&dp83867_2_3>; + phy-connection-type = "rgmii-id"; +}; + +&dpmac18 { + phy-handle = <&dp83867_2_4>; + phy-connection-type = "rgmii-id"; +}; + +&emdio1 { + status = "okay"; + + dp83867_1_1: ethernet-phy@1 { + reg = <1>; + ti,clk-output-sel = ; + }; + + dp83867_1_2: ethernet-phy@2 { + reg = <2>; + ti,clk-output-sel = ; + }; + + dp83867_1_3: ethernet-phy@3 { + reg = <3>; + ti,clk-output-sel = ; + }; + + dp83867_1_4: ethernet-phy@4 { + reg = <4>; + ti,clk-output-sel = ; + }; + + dp83867_1_5: ethernet-phy@5 { + reg = <5>; + ti,clk-output-sel = ; + }; + + dp83867_1_6: ethernet-phy@6 { + reg = <6>; + ti,clk-output-sel = ; + }; +}; + +&emdio2 { + status = "okay"; + + dp83867_2_1: ethernet-phy@1 { + reg = <1>; + ti,clk-output-sel = ; + }; + + dp83867_2_2: ethernet-phy@2 { + reg = <2>; + ti,clk-output-sel = ; + }; + + dp83867_2_3: ethernet-phy@3 { + reg = <3>; + ti,rx-internal-delay = ; + ti,tx-internal-delay = ; + ti,clk-output-sel = ; + }; + + dp83867_2_4: ethernet-phy@4 { + reg = <4>; + ti,rx-internal-delay = ; + ti,tx-internal-delay = ; + ti,clk-output-sel = ; + }; +}; + +&esdhc0 { + sd-uhs-sdr104; + sd-uhs-sdr50; + sd-uhs-sdr25; + sd-uhs-sdr12; + no-mmc; + no-sdio; + wp-gpios = <&gpio0 30 GPIO_ACTIVE_LOW>; + cd-gpios = <&gpio0 31 GPIO_ACTIVE_LOW>; + status = "okay"; +}; + +&i2c0 { + gpioex3: gpio@20 { + compatible = "nxp,pca9555"; + reg = <0x20>; + #gpio-cells = <2>; + gpio-controller; + vcc-supply = <®_vcc3v3>; + }; +}; + +&i2c4 { + status = "okay"; + + mux@70 { + compatible = "nxp,pca9544"; + reg = <0x70>; + #address-cells = <1>; + #size-cells = <0>; + vdd-supply = <®_vcc3v3>; + + i2c@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c@2 { + reg = <2>; + #address-cells = <1>; + #size-cells = <0>; + + gpioex0: gpio@20 { + compatible = "nxp,pca9555"; + reg = <0x20>; + #gpio-cells = <2>; + gpio-controller; + vcc-supply = <®_vcc3v3>; + }; + + gpioex1: gpio@21 { + compatible = "nxp,pca9555"; + reg = <0x21>; + #gpio-cells = <2>; + gpio-controller; + vcc-supply = <®_vcc3v3>; + }; + + gpioex2: gpio@22 { + compatible = "nxp,pca9555"; + reg = <0x22>; + #gpio-cells = <2>; + gpio-controller; + vcc-supply = <®_vcc3v3>; + }; + }; + + i2c@3 { + reg = <3>; + #address-cells = <1>; + #size-cells = <0>; + }; + }; +}; + +&i2c5 { + status = "okay"; + + mux@70 { + compatible = "nxp,pca9544"; + reg = <0x70>; + #address-cells = <1>; + #size-cells = <0>; + vdd-supply = <®_vcc3v3>; + + i2c@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + }; + + xfi1_i2c: i2c@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + }; + + xfi2_i2c: i2c@2 { + reg = <2>; + #address-cells = <1>; + #size-cells = <0>; + }; + + i2c@3 { + reg = <3>; + #address-cells = <1>; + #size-cells = <0>; + }; + }; +}; + +&pcs_mdio17 { + status = "okay"; +}; + +&pcs_mdio18 { + status = "okay"; +}; + +&uart0 { + status = "okay"; +}; + +&uart1 { + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; + +&uart3 { + status = "okay"; +}; + +&usb0 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + hub_2_0: hub@1 { + compatible = "usb451,8142"; + reg = <1>; + peer-hub = <&hub_3_0>; + reset-gpios = <&gpioex1 0 GPIO_ACTIVE_LOW>; + vcc-supply = <®_vcc3v3>; + }; + + hub_3_0: hub@2 { + compatible = "usb451,8140"; + reg = <2>; + peer-hub = <&hub_2_0>; + reset-gpios = <&gpioex1 0 GPIO_ACTIVE_LOW>; + vcc-supply = <®_vcc3v3>; + }; +}; + +&usb1 { + dr_mode = "otg"; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a-tqmlx2160a-mblx2160a_12_x_x.dtso b/arch/arm64/boot/dts/freescale/fsl-lx2160a-tqmlx2160a-mblx2160a_12_x_x.dtso new file mode 100644 index 00000000000000..8284a564e20ddc --- /dev/null +++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a-tqmlx2160a-mblx2160a_12_x_x.dtso @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright (c) 2020-2023 TQ-Systems GmbH , + * D-82229 Seefeld, Germany. + * Author: Gregor Herburger + */ + +/dts-v1/; +/plugin/; + +&dpmac9 { + phy-handle = <&dp83867_2_1>; + phy-connection-type = "sgmii"; + managed = "in-band-status"; +}; + +&dpmac10 { + phy-handle = <&dp83867_2_2>; + phy-connection-type = "sgmii"; + managed = "in-band-status"; +}; + +&pcs_mdio9 { + status = "okay"; +}; + +&pcs_mdio10 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a-tqmlx2160a-mblx2160a_14_x_x.dtso b/arch/arm64/boot/dts/freescale/fsl-lx2160a-tqmlx2160a-mblx2160a_14_x_x.dtso new file mode 100644 index 00000000000000..636b17a383edbd --- /dev/null +++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a-tqmlx2160a-mblx2160a_14_x_x.dtso @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright (c) 2020-2023 TQ-Systems GmbH , + * D-82229 Seefeld, Germany. + * Author: Gregor Herburger + */ + +/dts-v1/; +/plugin/; + +&dpmac1 { + managed = "in-band-status"; +}; + +&pcs_mdio1 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a-tqmlx2160a-mblx2160a_x_11_x.dtso b/arch/arm64/boot/dts/freescale/fsl-lx2160a-tqmlx2160a-mblx2160a_x_11_x.dtso new file mode 100644 index 00000000000000..6d0c808cd840fd --- /dev/null +++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a-tqmlx2160a-mblx2160a_x_11_x.dtso @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright (c) 2020-2023 TQ-Systems GmbH , + * D-82229 Seefeld, Germany. + * Author: Gregor Herburger + */ + +/dts-v1/; +/plugin/; + +&dpmac12 { + phy-handle = <&dp83867_1_1>; + phy-connection-type = "sgmii"; + managed = "in-band-status"; +}; + +&dpmac13 { + phy-handle = <&dp83867_1_5>; + phy-connection-type = "sgmii"; + managed = "in-band-status"; +}; + +&dpmac14 { + phy-handle = <&dp83867_1_6>; + phy-connection-type = "sgmii"; + managed = "in-band-status"; +}; + +&dpmac16 { + phy-handle = <&dp83867_1_4>; + phy-connection-type = "sgmii"; + managed = "in-band-status"; +}; + +&pcs_mdio12 { + status = "okay"; +}; + +&pcs_mdio13 { + status = "okay"; +}; + +&pcs_mdio14 { + status = "okay"; +}; + +&pcs_mdio16 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a-tqmlx2160a-mblx2160a_x_7_x.dtso b/arch/arm64/boot/dts/freescale/fsl-lx2160a-tqmlx2160a-mblx2160a_x_7_x.dtso new file mode 100644 index 00000000000000..db88a86ff69cd8 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a-tqmlx2160a-mblx2160a_x_7_x.dtso @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright (c) 2020-2023 TQ-Systems GmbH , + * D-82229 Seefeld, Germany. + * Author: Gregor Herburger + */ + +/dts-v1/; +/plugin/; + +&dpmac12 { + phy-handle = <&dp83867_1_1>; + phy-connection-type = "sgmii"; + managed = "in-band-status"; +}; + +&dpmac13 { + sfp = <&sfp_xfi1>; + managed = "in-band-status"; +}; + +&dpmac14 { + sfp = <&sfp_xfi2>; + managed = "in-band-status"; +}; + +&dpmac16 { + phy-handle = <&dp83867_1_4>; + phy-connection-type = "sgmii"; + managed = "in-band-status"; +}; + +&pcs_mdio12 { + status = "okay"; +}; + +&pcs_mdio13 { + status = "okay"; +}; + +&pcs_mdio14 { + status = "okay"; +}; + +&pcs_mdio16 { + status = "okay"; +}; + +&sfp_xfi1 { + status = "okay"; +}; + +&sfp_xfi2 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a-tqmlx2160a-mblx2160a_x_8_x.dtso b/arch/arm64/boot/dts/freescale/fsl-lx2160a-tqmlx2160a-mblx2160a_x_8_x.dtso new file mode 100644 index 00000000000000..f6dfa76aa0e767 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a-tqmlx2160a-mblx2160a_x_8_x.dtso @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright (c) 2020-2023 TQ-Systems GmbH , + * D-82229 Seefeld, Germany. + * Author: Gregor Herburger + */ + +/dts-v1/; +/plugin/; + +&dpmac13 { + sfp = <&sfp_xfi1>; + managed = "in-band-status"; +}; + +&dpmac14 { + sfp = <&sfp_xfi2>; + managed = "in-band-status"; +}; + +&pcs_mdio13 { + status = "okay"; +}; + +&pcs_mdio14 { + status = "okay"; +}; + +&sata0 { + status = "okay"; +}; + +&sata1 { + status = "okay"; +}; + +&sata2 { + status = "okay"; +}; + +&sfp_xfi1 { + status = "okay"; +}; + +&sfp_xfi2 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a-tqmlx2160a.dtsi b/arch/arm64/boot/dts/freescale/fsl-lx2160a-tqmlx2160a.dtsi new file mode 100644 index 00000000000000..89a4765737b4f4 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a-tqmlx2160a.dtsi @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright (c) 2020-2023 TQ-Systems GmbH , + * D-82229 Seefeld, Germany. + * Author: Gregor Herburger + */ + +#include "fsl-lx2160a.dtsi" + +/ { + reg_vcc3v3: regulator-vcc3v3 { + compatible = "regulator-fixed"; + regulator-name = "VCC3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; +}; + + +&emdio1 { + status = "okay"; +}; + +&emdio2 { + status = "okay"; +}; + +&esdhc1 { + bus-width = <8>; + no-sd; + no-sdio; + non-removable; + mmc-hs200-1_8v; + status = "okay"; +}; + +&fspi { + status = "okay"; + + flash0: flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <10000000>; + spi-rx-bus-width = <1>; + spi-tx-bus-width = <1>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + }; + }; + + flash1: flash@1 { + compatible = "jedec,spi-nor"; + reg = <1>; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <10000000>; + spi-rx-bus-width = <1>; + spi-tx-bus-width = <1>; + }; +}; + +&i2c0 { + scl-gpios = <&gpio2 11 GPIO_ACTIVE_HIGH>; + status = "okay"; + + sensor0: temperature-sensor@1f { + compatible = "nxp,se97", "jedec,jc-42.4-temp"; + reg = <0x1f>; + }; + + eeprom1: eeprom@57 { + compatible = "atmel,24c02"; + reg = <0x57>; + pagesize = <16>; + read-only; + vcc-supply = <®_vcc3v3>; + }; + + rtc: rtc@51 { + compatible = "nxp,pcf85063a"; + reg = <0x51>; + quartz-load-femtofarads = <12500>; + }; + + eeprom2: eeprom@50 { + compatible = "atmel,24c64"; + reg = <0x50>; + pagesize = <32>; + vcc-supply = <®_vcc3v3>; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi index f176ca2e244e75..6640b49670ae51 100644 --- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi +++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi @@ -732,9 +732,9 @@ fsl,tmu-range = <0x800000e6 0x8001017d>; fsl,tmu-calibration = /* Calibration data group 1 */ - <0x00000000 0x00000035 + <0x00000000 0x00000035>, /* Calibration data group 2 */ - 0x00000001 0x00000154>; + <0x00000001 0x00000154>; little-endian; #thermal-sensor-cells = <1>; }; diff --git a/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi b/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi index 72136c436a70c3..f6654fdcb14780 100644 --- a/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8-apalis-ixora-v1.2.dtsi @@ -68,6 +68,7 @@ gpio = <&lsio_gpio5 22 GPIO_ACTIVE_HIGH>; enable-active-high; regulator-name = "can1_supply"; + startup-delay-us = <1000>; }; reg_can2_supply: regulator-can2-supply { @@ -77,6 +78,7 @@ gpio = <&lsio_gpio2 8 GPIO_ACTIVE_HIGH>; enable-active-high; regulator-name = "can2_supply"; + startup-delay-us = <1000>; }; reg_usb_host_vbus: regulator-usb-host-vbus { diff --git a/arch/arm64/boot/dts/freescale/imx8-ss-audio.dtsi b/arch/arm64/boot/dts/freescale/imx8-ss-audio.dtsi index 9d75ce4675691e..f057c6b21b3012 100644 --- a/arch/arm64/boot/dts/freescale/imx8-ss-audio.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8-ss-audio.dtsi @@ -24,7 +24,6 @@ audio_subsys: bus@59000000 { compatible = "fsl,imx8qm-edma"; reg = <0x591f0000 0x190000>; #dma-cells = <3>; - shared-interrupt; dma-channels = <24>; dma-channel-mask = <0x5c0c00>; interrupts = , /* 0 asrc 0 */ @@ -127,7 +126,6 @@ audio_subsys: bus@59000000 { compatible = "fsl,imx8qm-edma"; reg = <0x599f0000 0xc0000>; #dma-cells = <3>; - shared-interrupt; dma-channels = <11>; dma-channel-mask = <0xc0>; interrupts = , /* 0 asrc 1 */ diff --git a/arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi b/arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi index a414df64535111..6d13e4fafb761c 100644 --- a/arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8dxl-ss-conn.dtsi @@ -13,6 +13,13 @@ clock-frequency = <250000000>; clock-output-names = "conn_enet0_root_clk"; }; + + clk_dummy: clock-dummy { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + clock-output-names = "clk_dummy"; + }; }; &conn_subsys { @@ -22,7 +29,7 @@ interrupt-parent = <&gic>; interrupts = , ; - interrupt-names = "eth_wake_irq", "macirq"; + interrupt-names = "macirq", "eth_wake_irq"; clocks = <&eqos_lpcg IMX_LPCG_CLK_4>, <&eqos_lpcg IMX_LPCG_CLK_6>, <&eqos_lpcg IMX_LPCG_CLK_0>, @@ -53,13 +60,6 @@ rx-burst-size-dword = <0x10>; power-domains = <&pd IMX_SC_R_USB_1>; status = "disabled"; - - clk_dummy: clock-dummy { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <0>; - clock-output-names = "clk_dummy"; - }; }; usbmisc2: usbmisc@5b0e0200 { diff --git a/arch/arm64/boot/dts/freescale/imx8dxl-ss-ddr.dtsi b/arch/arm64/boot/dts/freescale/imx8dxl-ss-ddr.dtsi index 550f513708d854..3569abb5bb9bef 100644 --- a/arch/arm64/boot/dts/freescale/imx8dxl-ss-ddr.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8dxl-ss-ddr.dtsi @@ -4,6 +4,6 @@ */ &ddr_pmu0 { - compatible = "fsl,imx8-ddr-pmu"; + compatible = "fsl,imx8dxl-ddr-pmu", "fsl,imx8-ddr-pmu"; interrupts = ; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-beacon-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-beacon-som.dtsi index f264102bdb2748..62ed64663f4952 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-beacon-som.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm-beacon-som.dtsi @@ -3,6 +3,8 @@ * Copyright 2020 Compass Electronics Group, LLC */ +#include "imx8mm-overdrive.dtsi" + / { aliases { rtc0 = &rtc; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-emcon-avari.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-emcon-avari.dtsi index d897a852733531..44c2cba41a1f04 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-emcon-avari.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm-emcon-avari.dtsi @@ -104,7 +104,7 @@ compatible = "nxp,pca8574"; reg = <0x3a>; gpio-controller; - #gpio-cells = <1>; + #gpio-cells = <2>; }; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-evk.dtsi index a882c86ec3132b..b53104ed891993 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-evk.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm-evk.dtsi @@ -367,12 +367,6 @@ interrupts = <11 8>; status = "okay"; - port { - typec1_dr_sw: endpoint { - remote-endpoint = <&usb1_drd_sw>; - }; - }; - typec1_con: connector { compatible = "usb-c-connector"; label = "USB-C"; @@ -384,6 +378,12 @@ PDO_VAR(5000, 20000, 3000)>; op-sink-microwatt = <15000000>; self-powered; + + port { + typec1_dr_sw: endpoint { + remote-endpoint = <&usb1_drd_sw>; + }; + }; }; }; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-nitrogen-r2.dts b/arch/arm64/boot/dts/freescale/imx8mm-nitrogen-r2.dts index 0e8f0d7161ad0f..12fb79d20b29e2 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-nitrogen-r2.dts +++ b/arch/arm64/boot/dts/freescale/imx8mm-nitrogen-r2.dts @@ -220,7 +220,7 @@ #address-cells = <1>; #size-cells = <0>; - i2c3@0 { + i2c@0 { reg = <0>; #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-overdrive.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-overdrive.dtsi new file mode 100644 index 00000000000000..b31436b5e9b703 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mm-overdrive.dtsi @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +&gpu_2d { + assigned-clocks = <&clk IMX8MM_CLK_GPU2D_CORE>, + <&clk IMX8MM_GPU_PLL_OUT>; + assigned-clock-parents = <&clk IMX8MM_GPU_PLL_OUT>; + assigned-clock-rates = <0>, <1000000000>; +}; + +&gpu_3d { + assigned-clocks = <&clk IMX8MM_CLK_GPU3D_CORE>, + <&clk IMX8MM_GPU_PLL_OUT>; + assigned-clock-parents = <&clk IMX8MM_GPU_PLL_OUT>; + assigned-clock-rates = <0>, <1000000000>; +}; + +&vpu_blk_ctrl { + assigned-clocks = <&clk IMX8MM_CLK_VPU_G1>, + <&clk IMX8MM_CLK_VPU_G2>, + <&clk IMX8MM_CLK_VPU_H1>, + <&clk IMX8MM_VPU_PLL_OUT>; + assigned-clock-parents = <&clk IMX8MM_SYS_PLL3_OUT>, + <&clk IMX8MM_VPU_PLL_OUT>, + <&clk IMX8MM_SYS_PLL3_OUT>; + assigned-clock-rates = <750000000>, + <700000000>, + <750000000>, + <700000000>; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-phygate-tauri-l.dts b/arch/arm64/boot/dts/freescale/imx8mm-phygate-tauri-l.dts index 968f475b9a96c3..27a902569e2a28 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-phygate-tauri-l.dts +++ b/arch/arm64/boot/dts/freescale/imx8mm-phygate-tauri-l.dts @@ -120,7 +120,7 @@ }; tpm: tpm@1 { - compatible = "tcg,tpm_tis-spi"; + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; interrupts = <11 IRQ_TYPE_LEVEL_LOW>; interrupt-parent = <&gpio2>; pinctrl-names = "default"; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml-mba8mx.dts b/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml-mba8mx.dts index 156d793a0c9723..ea6e8b85169f75 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml-mba8mx.dts +++ b/arch/arm64/boot/dts/freescale/imx8mm-tqma8mqml-mba8mx.dts @@ -11,6 +11,7 @@ / { model = "TQ-Systems GmbH i.MX8MM TQMa8MxML on MBa8Mx"; compatible = "tq,imx8mm-tqma8mqml-mba8mx", "tq,imx8mm-tqma8mqml", "fsl,imx8mm"; + chassis-type = "embedded"; aliases { eeprom0 = &eeprom3; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi index 3a0a10e835a277..752caa38eb03bf 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx.dtsi @@ -84,8 +84,15 @@ &ecspi2 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_spi2>; - cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>; + cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>, + <&gpio1 10 GPIO_ACTIVE_LOW>; status = "okay"; + + tpm@1 { + compatible = "atmel,attpm20p", "tcg,tpm_tis-spi"; + reg = <0x1>; + spi-max-frequency = <36000000>; + }; }; &gpio1 { @@ -152,23 +159,30 @@ pcie@0,0 { reg = <0x0000 0 0 0 0>; - #address-cells = <1>; - #size-cells = <0>; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + ranges; - pcie@1,0 { + pcie@0,0 { reg = <0x0000 0 0 0 0>; - #address-cells = <1>; - #size-cells = <0>; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + ranges; - pcie@2,3 { + pcie@3,0 { reg = <0x1800 0 0 0 0>; - #address-cells = <1>; - #size-cells = <0>; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + ranges; - eth1: pcie@5,0 { + eth1: ethernet@0,0 { reg = <0x0000 0 0 0 0>; - #address-cells = <1>; - #size-cells = <0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; local-mac-address = [00 00 00 00 00 00]; }; @@ -312,6 +326,7 @@ MX8MM_IOMUXC_ECSPI2_MOSI_ECSPI2_MOSI 0xd6 MX8MM_IOMUXC_ECSPI2_MISO_ECSPI2_MISO 0xd6 MX8MM_IOMUXC_ECSPI2_SS0_GPIO5_IO13 0xd6 + MX8MM_IOMUXC_GPIO1_IO10_GPIO1_IO10 0xd6 >; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx.dtsi index d79fe9f62b9559..2aa6c1090fc7d7 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw73xx.dtsi @@ -109,7 +109,7 @@ status = "okay"; tpm@1 { - compatible = "tcg,tpm_tis-spi"; + compatible = "atmel,attpm20p", "tcg,tpm_tis-spi"; reg = <0x1>; spi-max-frequency = <36000000>; }; @@ -179,23 +179,30 @@ pcie@0,0 { reg = <0x0000 0 0 0 0>; - #address-cells = <1>; - #size-cells = <0>; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + ranges; - pcie@1,0 { + pcie@0,0 { reg = <0x0000 0 0 0 0>; - #address-cells = <1>; - #size-cells = <0>; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + ranges; - pcie@2,4 { + pcie@4,0 { reg = <0x2000 0 0 0 0>; - #address-cells = <1>; - #size-cells = <0>; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + ranges; - eth1: pcie@6,0 { + eth1: ethernet@0,0 { reg = <0x0000 0 0 0 0>; - #address-cells = <1>; - #size-cells = <0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; local-mac-address = [00 00 00 00 00 00]; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts index 06a394a41d7c43..c11260c26d0b43 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts +++ b/arch/arm64/boot/dts/freescale/imx8mm-venice-gw7902.dts @@ -635,13 +635,16 @@ pcie@0,0 { reg = <0x0000 0 0 0 0>; - #address-cells = <1>; - #size-cells = <0>; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + ranges; - eth1: pcie@1,0 { + eth1: ethernet@0,0 { reg = <0x0000 0 0 0 0>; - #address-cells = <1>; - #size-cells = <0>; + #address-cells = <3>; + #size-cells = <2>; + ranges; local-mac-address = [00 00 00 00 00 00]; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-verdin-mallow.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-verdin-mallow.dtsi new file mode 100644 index 00000000000000..4a0799d63446cd --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mm-verdin-mallow.dtsi @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright 2023 Toradex + * + * Common dtsi for Verdin IMX8MM SoM on Mallow carrier board + * + * https://www.toradex.com/computer-on-modules/verdin-arm-family/nxp-imx-8m-mini-nano + * https://www.toradex.com/products/carrier-board/mallow-carrier-board + */ + +#include + +/ { + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_leds>; + + /* SODIMM 52 - USER_LED_1_RED */ + led-0 { + color = ; + function = LED_FUNCTION_DEBUG; + function-enumerator = <1>; + gpios = <&gpio3 0 GPIO_ACTIVE_HIGH>; + }; + + /* SODIMM 54 - USER_LED_1_GREEN */ + led-1 { + color = ; + function = LED_FUNCTION_DEBUG; + function-enumerator = <1>; + gpios = <&gpio3 1 GPIO_ACTIVE_HIGH>; + }; + + /* SODIMM 56 - USER_LED_2_RED */ + led-2 { + color = ; + function = LED_FUNCTION_DEBUG; + function-enumerator = <2>; + gpios = <&gpio3 6 GPIO_ACTIVE_HIGH>; + }; + + /* SODIMM 58 - USER_LED_2_GREEN */ + led-3 { + color = ; + function = LED_FUNCTION_DEBUG; + function-enumerator = <2>; + gpios = <&gpio3 7 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +/* Verdin SPI_1 */ +&ecspi2 { + pinctrl-0 = <&pinctrl_ecspi2>, <&pinctrl_tpm_cs>; + cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>, <&gpio3 2 GPIO_ACTIVE_LOW>; + status = "okay"; + + tpm@1 { + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; + reg = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_tpm_irq>; + interrupt-parent = <&gpio3>; + interrupts = <14 IRQ_TYPE_LEVEL_LOW>; + spi-max-frequency = <18500000>; + }; +}; + +/* EEPROM on Mallow */ +&eeprom_carrier_board { + status = "okay"; +}; + +/* Verdin ETH_1 */ +&fec1 { + status = "okay"; +}; + +/* Temperature sensor on Mallow */ +&hwmon_temp { + compatible = "ti,tmp1075"; + status = "okay"; +}; + +/* Verdin I2C_2_DSI */ +&i2c2 { + status = "okay"; +}; + +/* Verdin I2C_4_CSI */ +&i2c3 { + status = "okay"; +}; + +/* Verdin I2C_1 */ +&i2c4 { + status = "okay"; +}; + +/* Verdin PCIE_1 */ +&pcie0 { + status = "okay"; +}; + +&pcie_phy { + status = "okay"; +}; + +/* Verdin PWM_3_DSI */ +&pwm1 { + status = "okay"; +}; + +/* Verdin PWM_1 */ +&pwm2 { + status = "okay"; +}; + +/* Verdin PWM_2 */ +&pwm3 { + status = "okay"; +}; + +/* Verdin UART_3 */ +&uart1 { + status = "okay"; +}; + +/* Verdin UART_1 */ +&uart2 { + status = "okay"; +}; + +/* Verdin UART_2 */ +&uart3 { + status = "okay"; +}; + +/* Verdin USB_1 */ +&usbotg1 { + status = "okay"; +}; + +/* Verdin USB_2 */ +&usbotg2 { + status = "okay"; +}; + +/* Verdin SD_1 */ +&usdhc2 { + status = "okay"; +}; + +&iomuxc { + pinctrl_leds: ledsgrp { + fsl,pins = + , /* SODIMM 52 */ + , /* SODIMM 54 */ + , /* SODIMM 56 */ + ; /* SODIMM 58 */ + }; + + pinctrl_tpm_cs: tpmcsgrp { + fsl,pins = + ; /* SODIMM 64 */ + }; + + pinctrl_tpm_irq: tpmirqgrp { + fsl,pins = + ; /* SODIMM 66 */ + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-verdin-nonwifi-mallow.dts b/arch/arm64/boot/dts/freescale/imx8mm-verdin-nonwifi-mallow.dts new file mode 100644 index 00000000000000..1b1999f3a80e8d --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mm-verdin-nonwifi-mallow.dts @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright 2023 Toradex + */ + +/dts-v1/; + +#include "imx8mm-verdin.dtsi" +#include "imx8mm-verdin-nonwifi.dtsi" +#include "imx8mm-verdin-mallow.dtsi" + +/ { + model = "Toradex Verdin iMX8M Mini on Mallow"; + compatible = "toradex,verdin-imx8mm-nonwifi-mallow", + "toradex,verdin-imx8mm-nonwifi", + "toradex,verdin-imx8mm", + "fsl,imx8mm"; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mm-verdin-wifi-mallow.dts b/arch/arm64/boot/dts/freescale/imx8mm-verdin-wifi-mallow.dts new file mode 100644 index 00000000000000..2916145f31bbe9 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mm-verdin-wifi-mallow.dts @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright 2023 Toradex + */ + +/dts-v1/; + +#include "imx8mm-verdin.dtsi" +#include "imx8mm-verdin-wifi.dtsi" +#include "imx8mm-verdin-mallow.dtsi" + +/ { + model = "Toradex Verdin iMX8M Mini WB on Mallow"; + compatible = "toradex,verdin-imx8mm-wifi-mallow", + "toradex,verdin-imx8mm-wifi", + "toradex,verdin-imx8mm", + "fsl,imx8mm"; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mm.dtsi b/arch/arm64/boot/dts/freescale/imx8mm.dtsi index 738024baaa5789..8a1b42b94dce69 100644 --- a/arch/arm64/boot/dts/freescale/imx8mm.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mm.dtsi @@ -636,6 +636,8 @@ clk: clock-controller@30380000 { compatible = "fsl,imx8mm-ccm"; reg = <0x30380000 0x10000>; + interrupts = , + ; #clock-cells = <1>; clocks = <&osc_32k>, <&osc_24m>, <&clk_ext1>, <&clk_ext2>, <&clk_ext3>, <&clk_ext4>; @@ -647,7 +649,6 @@ <&clk IMX8MM_CLK_AUDIO_AHB>, <&clk IMX8MM_CLK_IPG_AUDIO_ROOT>, <&clk IMX8MM_SYS_PLL3>, - <&clk IMX8MM_VIDEO_PLL1>, <&clk IMX8MM_AUDIO_PLL1>; assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_800M>, <&clk IMX8MM_ARM_PLL_OUT>, @@ -657,7 +658,6 @@ <400000000>, <400000000>, <750000000>, - <594000000>, <393216000>; }; @@ -1133,7 +1133,7 @@ assigned-clock-parents = <&clk IMX8MM_VIDEO_PLL1_OUT>, <&clk IMX8MM_SYS_PLL2_1000M>, <&clk IMX8MM_SYS_PLL1_800M>; - assigned-clock-rates = <594000000>, <500000000>, <200000000>; + assigned-clock-rates = <24000000>, <500000000>, <200000000>; interrupts = ; power-domains = <&disp_blk_ctrl IMX8MM_DISPBLK_PD_LCDIF>; status = "disabled"; @@ -1151,12 +1151,8 @@ clocks = <&clk IMX8MM_CLK_DSI_CORE>, <&clk IMX8MM_CLK_DSI_PHY_REF>; clock-names = "bus_clk", "sclk_mipi"; - assigned-clocks = <&clk IMX8MM_CLK_DSI_CORE>, - <&clk IMX8MM_CLK_DSI_PHY_REF>; - assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_266M>, - <&clk IMX8MM_CLK_24M>; - assigned-clock-rates = <266000000>, <24000000>; - samsung,pll-clock-frequency = <24000000>; + assigned-clocks = <&clk IMX8MM_CLK_DSI_CORE>; + assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_266M>; interrupts = ; power-domains = <&disp_blk_ctrl IMX8MM_DISPBLK_PD_MIPI_DSI>; status = "disabled"; @@ -1408,7 +1404,7 @@ assigned-clocks = <&clk IMX8MM_CLK_GPU3D_CORE>, <&clk IMX8MM_GPU_PLL_OUT>; assigned-clock-parents = <&clk IMX8MM_GPU_PLL_OUT>; - assigned-clock-rates = <0>, <1000000000>; + assigned-clock-rates = <0>, <800000000>; power-domains = <&pgc_gpu>; }; @@ -1423,7 +1419,7 @@ assigned-clocks = <&clk IMX8MM_CLK_GPU2D_CORE>, <&clk IMX8MM_GPU_PLL_OUT>; assigned-clock-parents = <&clk IMX8MM_GPU_PLL_OUT>; - assigned-clock-rates = <0>, <1000000000>; + assigned-clock-rates = <0>, <800000000>; power-domains = <&pgc_gpu>; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mn-beacon-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-beacon-som.dtsi index 90073b16536f40..2a64115eebf1c6 100644 --- a/arch/arm64/boot/dts/freescale/imx8mn-beacon-som.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mn-beacon-som.dtsi @@ -3,6 +3,8 @@ * Copyright 2020 Compass Electronics Group, LLC */ +#include "imx8mn-overdrive.dtsi" + / { aliases { rtc0 = &rtc; diff --git a/arch/arm64/boot/dts/freescale/imx8mn-bsh-smm-s2-common.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-bsh-smm-s2-common.dtsi index 22a754d438f19f..bbb07c650da9c2 100644 --- a/arch/arm64/boot/dts/freescale/imx8mn-bsh-smm-s2-common.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mn-bsh-smm-s2-common.dtsi @@ -7,6 +7,7 @@ /dts-v1/; #include "imx8mn.dtsi" +#include "imx8mn-bsh-smm-s2-display.dtsi" / { chosen { diff --git a/arch/arm64/boot/dts/freescale/imx8mn-bsh-smm-s2-display.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-bsh-smm-s2-display.dtsi new file mode 100644 index 00000000000000..7675583a6b6794 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mn-bsh-smm-s2-display.dtsi @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright 2021 BSH + */ + +/ { + backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&pwm1 0 700000 0>; /* 700000 ns = 1337Hz */ + brightness-levels = <0 100>; + num-interpolated-steps = <100>; + default-brightness-level = <50>; + status = "okay"; + }; + + reg_3v3_dvdd: regulator-3v3-O3 { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_dvdd>; + regulator-name = "3v3-dvdd-supply"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio1 7 GPIO_ACTIVE_LOW>; + }; + + reg_v3v3_avdd: regulator-3v3-O2 { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_avdd>; + regulator-name = "3v3-avdd-supply"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio1 5 GPIO_ACTIVE_LOW>; + }; +}; + +&pwm1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_bl>; + status = "okay"; +}; + +&lcdif { + assigned-clocks = <&clk IMX8MN_VIDEO_PLL1>; + assigned-clock-rates = <594000000>; + status = "okay"; +}; + +&pgc_dispmix { + assigned-clocks = <&clk IMX8MN_CLK_DISP_AXI>, <&clk IMX8MN_CLK_DISP_APB>; + assigned-clock-parents = <&clk IMX8MN_SYS_PLL2_1000M>, <&clk IMX8MN_SYS_PLL1_800M>; + assigned-clock-rates = <500000000>, <200000000>; +}; + +&mipi_dsi { + #address-cells = <1>; + #size-cells = <0>; + samsung,esc-clock-frequency = <20000000>; + samsung,pll-clock-frequency = <12000000>; + status = "okay"; + + panel@0 { + compatible = "sharp,ls068b3sx02", "syna,r63353"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_panel>; + reg = <0>; + + backlight = <&backlight>; + dvdd-supply = <®_3v3_dvdd>; + avdd-supply = <®_v3v3_avdd>; + reset-gpios = <&gpio4 29 GPIO_ACTIVE_HIGH>; + + port { + panel_in: endpoint { + remote-endpoint = <&mipi_dsi_out>; + }; + }; + + }; + + ports { + port@1 { + reg = <1>; + + mipi_dsi_out: endpoint { + remote-endpoint = <&panel_in>; + }; + }; + }; +}; + +&gpu { + status = "okay"; +}; + +&iomuxc { + pinctrl_avdd: avddgrp { + fsl,pins = < + MX8MN_IOMUXC_GPIO1_IO05_GPIO1_IO5 0x16 /* VDD 3V3_VO2 */ + >; + }; + + /* This is for both PWM and voltage regulators for display */ + pinctrl_bl: blgrp { + fsl,pins = < + MX8MN_IOMUXC_GPIO1_IO01_PWM1_OUT 0x16 + >; + }; + + pinctrl_dvdd: dvddgrp { + fsl,pins = < + MX8MN_IOMUXC_GPIO1_IO07_GPIO1_IO7 0x16 /* VDD 3V3_VO3 */ + >; + }; + + pinctrl_panel: panelgrp { + fsl,pins = < + MX8MN_IOMUXC_SAI3_RXC_GPIO4_IO29 0x16 /* panel reset */ + >; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mn-dimonoff-gateway-evk.dts b/arch/arm64/boot/dts/freescale/imx8mn-dimonoff-gateway-evk.dts new file mode 100644 index 00000000000000..6f9b82958b96a5 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mn-dimonoff-gateway-evk.dts @@ -0,0 +1,160 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright 2022 DimOnOff + */ + +/dts-v1/; + +#include +#include "imx8mn-var-som-symphony.dts" + +/ { + model = "DimOnOff Gateway EVK board"; + compatible = "dimonoff,gateway-evk", "variscite,var-som-mx8mn", + "fsl,imx8mn"; + + /* + * U30 FPF2193 regulator. + * Source = BASE_PER_3V3 = SOM_3V3 (COM pin 49). + */ + reg_disp_3v3: regulator-disp-3v3 { + compatible = "regulator-fixed"; + regulator-name = "Display 3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-boot-on; + }; + + gpio-keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio_keys>; + + key-enter { + label = "enter"; + gpios = <&gpio1 8 GPIO_ACTIVE_LOW>; + linux,code = ; + wakeup-source; + }; + }; + + /* Bourns PEC12R rotary encoder, 24 steps. */ + rotary: rotary-encoder { + compatible = "rotary-encoder"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rotary>; + gpios = <&gpio5 12 GPIO_ACTIVE_LOW>, /* A */ + <&gpio5 13 GPIO_ACTIVE_LOW>; /* B */ + linux,axis = <0>; /* REL_X */ + rotary-encoder,encoding = "gray"; + rotary-encoder,relative-axis; + }; +}; + +/* Disable Asynchronous Sample Rate Converter (audio) */ +&easrc { + status = "disabled"; +}; + +&ecspi1 { + /* Resistive touch controller */ + /delete-node/ touchscreen@0; +}; + +&gpu { + status = "disabled"; +}; + +&i2c2 { + adc@48 { + compatible = "ti,ads7924"; + reg = <0x48>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_adc>; + vref-supply = <®_disp_3v3>; + reset-gpios = <&gpio5 5 GPIO_ACTIVE_LOW>; + #address-cells = <1>; + #size-cells = <0>; + + channel@0 { + reg = <0>; + label = "Pot0"; + }; + channel@1 { + reg = <1>; + label = "Pot1"; + }; + channel@2 { + reg = <2>; + label = "Pot2"; + }; + channel@3 { + reg = <3>; + label = "Pot3"; + }; + }; + + rtc@51 { + compatible = "nxp,pcf2129"; + reg = <0x51>; + reset-source; /* For watchdog. */ + }; + + rtc@53 { + compatible = "nxp,pcf2131"; + reg = <0x53>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rtc>; + reset-source; /* For watchdog. */ + interrupt-parent = <&gpio5>; + interrupts = <10 IRQ_TYPE_EDGE_FALLING>; /* J17.6 on EVK */ + }; +}; + +&i2c3 { + touchscreen@38 { + status = "disabled"; + }; + + codec@1a { + status = "disabled"; + }; + + /* DS1337 RTC module */ + rtc@68 { + status = "disabled"; + }; +}; + +&sai5 { + status = "disabled"; +}; + +&iomuxc { + pinctrl_gpio_keys: gpiokeysgrp { + fsl,pins = < + MX8MN_IOMUXC_GPIO1_IO08_GPIO1_IO8 0xc6 + >; + }; + + pinctrl_rotary: rotarygrp { + fsl,pins = < + MX8MN_IOMUXC_ECSPI2_MISO_GPIO5_IO12 0x00000156 + MX8MN_IOMUXC_ECSPI2_SS0_GPIO5_IO13 0x00000156 + >; + }; + + pinctrl_adc: adcgrp { + fsl,pins = < + MX8MN_IOMUXC_SPDIF_EXT_CLK_GPIO5_IO5 0x00000156 + >; + }; + + pinctrl_rtc: rtcgrp { + fsl,pins = < + MX8MN_IOMUXC_ECSPI2_SCLK_GPIO5_IO10 0x00000156 + MX8MN_IOMUXC_ECSPI2_MOSI_GPIO5_IO11 0x00000156 + >; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mn-evk.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-evk.dtsi index 3f6a19839c9e8e..a0e13d3324ed12 100644 --- a/arch/arm64/boot/dts/freescale/imx8mn-evk.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mn-evk.dtsi @@ -221,12 +221,6 @@ interrupts = <11 IRQ_TYPE_LEVEL_LOW>; status = "okay"; - port { - typec1_dr_sw: endpoint { - remote-endpoint = <&usb1_drd_sw>; - }; - }; - typec1_con: connector { compatible = "usb-c-connector"; label = "USB-C"; @@ -238,6 +232,12 @@ PDO_VAR(5000, 20000, 3000)>; op-sink-microwatt = <15000000>; self-powered; + + port { + typec1_dr_sw: endpoint { + remote-endpoint = <&usb1_drd_sw>; + }; + }; }; }; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mn-overdrive.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-overdrive.dtsi new file mode 100644 index 00000000000000..5d03fb893e90f8 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mn-overdrive.dtsi @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +&gpu { + assigned-clocks = <&clk IMX8MN_CLK_GPU_CORE>, + <&clk IMX8MN_CLK_GPU_SHADER>, + <&clk IMX8MN_CLK_GPU_AXI>, + <&clk IMX8MN_CLK_GPU_AHB>, + <&clk IMX8MN_GPU_PLL>; + assigned-clock-parents = <&clk IMX8MN_GPU_PLL_OUT>, + <&clk IMX8MN_GPU_PLL_OUT>, + <&clk IMX8MN_SYS_PLL1_800M>, + <&clk IMX8MN_SYS_PLL1_800M>; + assigned-clock-rates = <600000000>, + <600000000>, + <800000000>, + <400000000>, + <1200000000>; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mn-rve-gateway.dts b/arch/arm64/boot/dts/freescale/imx8mn-rve-gateway.dts new file mode 100644 index 00000000000000..1b633bd1ebb669 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mn-rve-gateway.dts @@ -0,0 +1,285 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright 2023 DimOnOff + */ + +/dts-v1/; + +#include +#include "imx8mn-var-som.dtsi" + +/ { + model = "RVE gateway"; + compatible = "rve,rve-gateway", "variscite,var-som-mx8mn", "fsl,imx8mn"; + + crystal_duart_24m: crystal-duart-24m { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + }; + + gpio-keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio_keys>; + + key-enter { + label = "enter"; + gpios = <&gpio1 1 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + + key-exit { + label = "exit"; + gpios = <&gpio3 23 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + lcd { + compatible = "hit,hd44780"; + display-height-chars = <2>; + display-width-chars = <20>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcd>; + data-gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>, + <&gpio1 6 GPIO_ACTIVE_HIGH>, + <&gpio1 14 GPIO_ACTIVE_HIGH>, + <&gpio4 28 GPIO_ACTIVE_HIGH>, + <&gpio5 24 GPIO_ACTIVE_HIGH>, + <&gpio5 2 GPIO_ACTIVE_HIGH>, + <&gpio1 12 GPIO_ACTIVE_HIGH>, + <&gpio5 25 GPIO_ACTIVE_HIGH>; + enable-gpios = <&gpio5 23 GPIO_ACTIVE_HIGH>; + rs-gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>; + rw-gpios = <&gpio4 27 GPIO_ACTIVE_HIGH>; + }; + + reg_3p3v: regulator-3p3v { + compatible = "regulator-fixed"; + regulator-name = "3P3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + /* Bourns PEC12R rotary encoder, 24 steps. */ + rotary: rotary-encoder { + compatible = "rotary-encoder"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rotary>; + gpios = <&gpio1 5 GPIO_ACTIVE_LOW>, /* A */ + <&gpio3 21 GPIO_ACTIVE_LOW>; /* B */ + linux,axis = <0>; /* REL_X */ + rotary-encoder,encoding = "gray"; + rotary-encoder,relative-axis; + }; +}; + +&ecspi1 { + cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>; + + duart1: serial@0 { + compatible = "nxp,sc16is752"; + reg = <0>; + spi-rx-bus-width = <1>; + spi-tx-bus-width = <1>; + spi-max-frequency = <4000000>; + clocks = <&crystal_duart_24m>; + interrupt-parent = <&gpio3>; + interrupts = <22 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "RADIO0", "RADIO1", "RADIO2", "RADIO3", + "RADIO4", "RADIO_RESET", "TP12", "TP11"; + linux,rs485-enabled-at-boot-time; + rs485-rts-active-low; + }; + + /delete-node/ touchscreen@0; +}; + +&ecspi2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi2>; + cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>; + /delete-property/ dmas; + /delete-property/ dma-names; + status = "okay"; + + duart2: serial@0 { + compatible = "nxp,sc16is752"; + reg = <0>; + spi-rx-bus-width = <1>; + spi-tx-bus-width = <1>; + spi-max-frequency = <4000000>; + clocks = <&crystal_duart_24m>; + interrupt-parent = <&gpio3>; + interrupts = <20 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "LED_B_USER", "LED_R_USER", "LED_G_USER", + "GPIO_EXT3", "GPIO_EXT2", "GPIO_EXT1", + "GPIO_EXT0", "TP13"; + linux,rs485-enabled-at-boot-time; + rs485-rts-active-low; + }; +}; + +/* Configure PWM pins in GPIO mode: */ +&gpio5 { + gpio-line-names = "", "", "", "PWM3", "PWM2", "PWM1"; +}; + +&gpu { + status = "disabled"; +}; + +&i2c2 { + clock-frequency = <400000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + status = "okay"; + + /* Carrier board EEPROM */ + eeprom_cb: eeprom@56 { + compatible = "atmel,24c04"; + reg = <0x56>; + pagesize = <16>; + vcc-supply = <®_3p3v>; + }; + + lm75: sensor@48 { + compatible = "st,stlm75"; + reg = <0x48>; + vs-supply = <®_3p3v>; + }; + + mcp7940: rtc@6f { + compatible = "microchip,mcp7940x"; + reg = <0x6f>; + }; +}; + +&i2c3 { + codec@1a { + status = "disabled"; + }; +}; + +&i2c4 { + clock-frequency = <400000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c4>; + status = "okay"; + + pcf8574_1: gpio@38 { + compatible = "nxp,pcf8574"; + reg = <0x38>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "LED_B_COMM3", "LED_R_COMM3", "LED_G_COMM3", + "TP14", "TP15", "LED_G_COMM4", "LED_R_COMM4", + "LED_B_COMM4"; + }; + + pcf8574_2: gpio@39 { + compatible = "nxp,pcf8574"; + reg = <0x39>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "LED_B_COMM2", "LED_G_COMM2", "LED_B_COMM1", + "LED_R_COMM2", "LED_R_COMM1", "LED_G_COMM1", + "TP16", "TP17"; + }; +}; + +/* Bluetooth */ +&uart2 { + status = "disabled"; +}; + +&usbotg1 { + dr_mode = "host"; + disable-over-current; + status = "okay"; +}; + +/* SD interface on expansion connector. */ +&usdhc2 { + vmmc-supply = <®_3p3v>; + cd-gpios = <&gpio1 13 GPIO_ACTIVE_LOW>; +}; + +&iomuxc { + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX8MN_IOMUXC_ECSPI1_SCLK_ECSPI1_SCLK 0x13 + MX8MN_IOMUXC_ECSPI1_MOSI_ECSPI1_MOSI 0x13 + MX8MN_IOMUXC_ECSPI1_MISO_ECSPI1_MISO 0x13 + MX8MN_IOMUXC_ECSPI1_SS0_GPIO5_IO9 0x13 /* SS0 */ + MX8MN_IOMUXC_SAI5_RXD1_GPIO3_IO22 0x13 /* SC16 IRQ */ + >; + }; + + pinctrl_ecspi2: ecspi2grp { + fsl,pins = < + MX8MN_IOMUXC_ECSPI2_SCLK_ECSPI2_SCLK 0x13 + MX8MN_IOMUXC_ECSPI2_MOSI_ECSPI2_MOSI 0x13 + MX8MN_IOMUXC_ECSPI2_MISO_ECSPI2_MISO 0x13 + MX8MN_IOMUXC_ECSPI2_SS0_GPIO5_IO13 0x13 /* SS0 */ + MX8MN_IOMUXC_SAI5_RXC_GPIO3_IO20 0x13 /* SC16 IRQ */ + >; + }; + + pinctrl_gpio_keys: gpiokeysgrp { + fsl,pins = < + MX8MN_IOMUXC_GPIO1_IO01_GPIO1_IO1 0xc6 /* Enter */ + MX8MN_IOMUXC_SAI5_RXD2_GPIO3_IO23 0xc6 /* Exit */ + >; + }; + + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX8MN_IOMUXC_I2C2_SCL_I2C2_SCL 0x400001c3 + MX8MN_IOMUXC_I2C2_SDA_I2C2_SDA 0x400001c3 + >; + }; + + pinctrl_i2c4: i2c4grp { + fsl,pins = < + MX8MN_IOMUXC_I2C4_SCL_I2C4_SCL 0x400001c3 + MX8MN_IOMUXC_I2C4_SDA_I2C4_SDA 0x400001c3 + >; + }; + + pinctrl_lcd: lcdgrp { + fsl,pins = < + MX8MN_IOMUXC_SAI3_TXD_GPIO5_IO1 0x00000156 /* D0 */ + MX8MN_IOMUXC_GPIO1_IO06_GPIO1_IO6 0x00000156 /* D1 */ + MX8MN_IOMUXC_GPIO1_IO14_GPIO1_IO14 0x00000156 /* D2 */ + MX8MN_IOMUXC_SAI3_RXFS_GPIO4_IO28 0x00000156 /* D3 */ + MX8MN_IOMUXC_UART2_RXD_GPIO5_IO24 0x00000156 /* D4 */ + MX8MN_IOMUXC_SAI3_MCLK_GPIO5_IO2 0x00000156 /* D5 */ + MX8MN_IOMUXC_GPIO1_IO12_GPIO1_IO12 0x00000156 /* D6 */ + MX8MN_IOMUXC_UART2_TXD_GPIO5_IO25 0x00000156 /* D7 */ + MX8MN_IOMUXC_UART1_TXD_GPIO5_IO23 0x00000156 /* E */ + MX8MN_IOMUXC_GPIO1_IO07_GPIO1_IO7 0x00000156 /* RS */ + MX8MN_IOMUXC_SAI2_MCLK_GPIO4_IO27 0x00000156 /* R/W */ + >; + }; + + pinctrl_rotary: rotarygrp { + fsl,pins = < + MX8MN_IOMUXC_GPIO1_IO05_GPIO1_IO5 0x00000156 /* A */ + MX8MN_IOMUXC_SAI5_RXD0_GPIO3_IO21 0x00000156 /* B */ + >; + }; + + /* Override Card Detect function GPIO value (GPIO1_IO10) from SOM: */ + pinctrl_usdhc2_gpio: usdhc2gpiogrp { + fsl,pins = < + MX8MN_IOMUXC_GPIO1_IO13_GPIO1_IO13 0x41 + >; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl-mba8mx.dts b/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl-mba8mx.dts index 3f1e49bfe38f73..c07d59147ab559 100644 --- a/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl-mba8mx.dts +++ b/arch/arm64/boot/dts/freescale/imx8mn-tqma8mqnl-mba8mx.dts @@ -11,6 +11,7 @@ / { model = "TQ-Systems GmbH i.MX8MN TQMa8MxNL on MBa8Mx"; compatible = "tq,imx8mn-tqma8mqnl-mba8mx", "tq,imx8mn-tqma8mqnl", "fsl,imx8mn"; + chassis-type = "embedded"; aliases { eeprom0 = &eeprom3; diff --git a/arch/arm64/boot/dts/freescale/imx8mn-var-som-symphony.dts b/arch/arm64/boot/dts/freescale/imx8mn-var-som-symphony.dts index a7a57442cb81ff..f38ee2266b25dd 100644 --- a/arch/arm64/boot/dts/freescale/imx8mn-var-som-symphony.dts +++ b/arch/arm64/boot/dts/freescale/imx8mn-var-som-symphony.dts @@ -57,6 +57,15 @@ linux,default-trigger = "heartbeat"; }; }; + + /* Peripherals supply, enabled by Q2 after SOM_3V3 rises. */ + reg_per_3v3: regulator-peripheral-3v3 { + compatible = "regulator-fixed"; + regulator-name = "per_3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; }; ðphy { @@ -79,6 +88,7 @@ interrupts = <7 IRQ_TYPE_EDGE_FALLING>; #gpio-cells = <2>; wakeup-source; + vcc-supply = <®_per_3v3>; /* USB 3.0 OTG (usbotg1) / SATA port switch, set to USB 3.0 */ usb3-sata-sel-hog { @@ -118,9 +128,14 @@ pinctrl-0 = <&pinctrl_ptn5150>; status = "okay"; - port { - typec1_dr_sw: endpoint { - remote-endpoint = <&usb1_drd_sw>; + connector { + compatible = "usb-c-connector"; + label = "USB-C"; + + port { + typec1_dr_sw: endpoint { + remote-endpoint = <&usb1_drd_sw>; + }; }; }; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mn-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mn-var-som.dtsi index b8946edf317bd1..b364307868f25e 100644 --- a/arch/arm64/boot/dts/freescale/imx8mn-var-som.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mn-var-som.dtsi @@ -31,6 +31,14 @@ gpio = <&gpio2 9 GPIO_ACTIVE_HIGH>; enable-active-high; }; + + reg_3v3_fixed: regulator-3v3-fixed { + compatible = "regulator-fixed"; + regulator-name = "fixed_3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; }; &A53_0 { @@ -234,6 +242,7 @@ compatible = "atmel,24c04"; reg = <0x52>; pagesize = <16>; + vcc-supply = <®_3v3_fixed>; }; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mn.dtsi b/arch/arm64/boot/dts/freescale/imx8mn.dtsi index 1bb1d0c1bae4de..136e75c51251a6 100644 --- a/arch/arm64/boot/dts/freescale/imx8mn.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mn.dtsi @@ -637,6 +637,8 @@ clk: clock-controller@30380000 { compatible = "fsl,imx8mn-ccm"; reg = <0x30380000 0x10000>; + interrupts = , + ; #clock-cells = <1>; clocks = <&osc_32k>, <&osc_24m>, <&clk_ext1>, <&clk_ext2>, <&clk_ext3>, <&clk_ext4>; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-beacon-kit.dts b/arch/arm64/boot/dts/freescale/imx8mp-beacon-kit.dts index 0bea0798d2db25..a08057410bdef5 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-beacon-kit.dts +++ b/arch/arm64/boot/dts/freescale/imx8mp-beacon-kit.dts @@ -94,6 +94,17 @@ }; }; + bridge-connector { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_con: endpoint { + remote-endpoint = <&adv7535_out>; + }; + }; + }; + leds { compatible = "gpio-leds"; pinctrl-names = "default"; @@ -153,6 +164,21 @@ enable-active-high; }; + sound-adv7535 { + compatible = "simple-audio-card"; + simple-audio-card,name = "sound-adv7535"; + simple-audio-card,format = "i2s"; + + simple-audio-card,cpu { + sound-dai = <&sai5>; + system-clock-direction-out; + }; + + simple-audio-card,codec { + sound-dai = <&adv_bridge>; + }; + }; + sound-dmic { compatible = "simple-audio-card"; simple-audio-card,name = "sound-pdm"; @@ -208,7 +234,7 @@ status = "okay"; tpm: tpm@0 { - compatible = "infineon,slb9670"; + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; reg = <0>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_tpm>; @@ -274,6 +300,35 @@ #interrupt-cells = <2>; }; + adv_bridge: hdmi@3d { + compatible = "adi,adv7535"; + reg = <0x3d>, <0x3c>, <0x3e>, <0x3f>; + reg-names = "main", "cec", "edid", "packet"; + adi,dsi-lanes = <4>; + #sound-dai-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + adv7535_in: endpoint { + remote-endpoint = <&dsi_out>; + }; + }; + + port@1 { + reg = <1>; + + adv7535_out: endpoint { + remote-endpoint = <&hdmi_con>; + }; + }; + }; + }; + pcieclk: clock-generator@68 { compatible = "renesas,9fgv0241"; reg = <0x68>; @@ -398,6 +453,10 @@ }; }; +&lcdif1 { + status = "okay"; +}; + &micfil { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_pdm>; @@ -407,6 +466,21 @@ status = "okay"; }; +&mipi_dsi { + samsung,esc-clock-frequency = <10000000>; + status = "okay"; + + ports { + port@1 { + reg = <1>; + + dsi_out: endpoint { + remote-endpoint = <&adv7535_in>; + }; + }; + }; +}; + &pcie { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_pcie>; @@ -433,6 +507,16 @@ status = "okay"; }; +&sai5 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sai5>; + assigned-clocks = <&clk IMX8MP_CLK_SAI5>; + assigned-clock-parents = <&clk IMX8MP_AUDIO_PLL1_OUT>; + assigned-clock-rates = <12288000>; + fsl,sai-mclk-direction-output; + status = "okay"; +}; + &snvs_pwrkey { status = "okay"; }; @@ -612,6 +696,14 @@ >; }; + pinctrl_sai5: sai5grp { + fsl,pins = < + MX8MP_IOMUXC_SAI5_RXD3__AUDIOMIX_SAI5_TX_DATA00 0xd6 + MX8MP_IOMUXC_SAI5_RXD2__AUDIOMIX_SAI5_TX_BCLK 0xd6 + MX8MP_IOMUXC_SAI5_RXD1__AUDIOMIX_SAI5_TX_SYNC 0xd6 + >; + }; + pinctrl_tpm: tpmgrp { fsl,pins = < MX8MP_IOMUXC_SAI1_RXFS__GPIO4_IO00 0x19 /* Reset */ diff --git a/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts b/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts index 267ceffc02d840..2c19766ebf093f 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts +++ b/arch/arm64/boot/dts/freescale/imx8mp-debix-model-a.dts @@ -75,7 +75,7 @@ &eqos { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_eqos>; - phy-connection-type = "rgmii-id"; + phy-mode = "rgmii-id"; phy-handle = <ðphy0>; status = "okay"; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a-bmb-08.dts b/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a-bmb-08.dts index 0afd90224a59a5..b11d694b98e1bc 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a-bmb-08.dts +++ b/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a-bmb-08.dts @@ -63,6 +63,50 @@ regulator-always-on; }; + reg_csi1_1v8: regulator-csi1-vdd1v8 { + compatible = "regulator-fixed"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "CSI1_VDD1V8"; + gpio = <&expander0 13 GPIO_ACTIVE_HIGH>; + enable-active-high; + vin-supply = <®_baseboard_vdd3v3>; + }; + + reg_csi1_3v3: regulator-csi1-vdd3v3 { + compatible = "regulator-fixed"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "CSI1_VDD3V3"; + gpio = <&expander0 14 GPIO_ACTIVE_HIGH>; + enable-active-high; + vin-supply = <®_vdd5v0>; + }; + + reg_csi2_1v8: regulator-csi2-vdd1v8 { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_reg_csi2_1v8>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "CSI2_VDD1V8"; + gpio = <&gpio3 21 GPIO_ACTIVE_HIGH>; + enable-active-high; + vin-supply = <®_baseboard_vdd3v3>; + }; + + reg_csi2_3v3: regulator-csi2-vdd3v3 { + compatible = "regulator-fixed"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_reg_csi2_3v3>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "CSI2_VDD3V3"; + gpio = <&gpio4 25 GPIO_ACTIVE_HIGH>; + enable-active-high; + vin-supply = <®_vdd5v0>; + }; + regulator-vbus-usb20 { compatible = "regulator-fixed"; regulator-min-microvolt = <5000000>; @@ -413,6 +457,18 @@ >; }; + pinctrl_reg_csi2_1v8: regcsi21v8grp { + fsl,pins = < + MX8MP_IOMUXC_SAI5_RXD0__GPIO3_IO21 0x19 + >; + }; + + pinctrl_reg_csi2_3v3: regcsi23v3grp { + fsl,pins = < + MX8MP_IOMUXC_SAI2_TXC__GPIO4_IO25 0x19 + >; + }; + pinctrl_uart2: uart2grp { fsl,pins = < MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX 0x14f diff --git a/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi index bc312aa1bfc8b4..91094c2277443c 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp-debix-som-a.dtsi @@ -6,6 +6,8 @@ #include "imx8mp.dtsi" +#include + / { model = "Polyhex i.MX8MPlus Debix SOM A"; compatible = "polyhex,imx8mp-debix-som-a", "fsl,imx8mp"; @@ -20,6 +22,20 @@ gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>; enable-active-high; }; + + gpio-leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio_led>; + + led-0 { + gpios = <&gpio3 16 GPIO_ACTIVE_HIGH>; + default-state = "on"; + linux,default-trigger = "heartbeat"; + function = LED_FUNCTION_STATUS; + color = ; + }; + }; }; &A53_0 { @@ -203,6 +219,12 @@ }; &iomuxc { + pinctrl_gpio_led: gpioledgrp { + fsl,pins = < + MX8MP_IOMUXC_NAND_READY_B__GPIO3_IO16 0x19 + >; + }; + pinctrl_i2c1: i2c1grp { fsl,pins = < MX8MP_IOMUXC_I2C1_SCL__I2C1_SCL 0x400001c2 diff --git a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-pdk3.dts b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-pdk3.dts index b749e28e5ede5c..fea67a9282f033 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-pdk3.dts +++ b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-pdk3.dts @@ -175,10 +175,14 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_ptn5150>; - port { - - ptn5150_out_ep: endpoint { - remote-endpoint = <&dwc3_0_ep>; + connector { + compatible = "usb-c-connector"; + label = "USB-C"; + + port { + ptn5150_out_ep: endpoint { + remote-endpoint = <&dwc3_0_ep>; + }; }; }; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi index d8963f32ec84ca..4ae4fdab461e00 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp-dhcom-som.dtsi @@ -420,6 +420,18 @@ reg = <0x53>; }; + eeprom0wl: eeprom@58 { + compatible = "atmel,24c32d-wl"; /* M24C32-D WL page of 0x50 */ + pagesize = <32>; + reg = <0x58>; + }; + + eeprom1wl: eeprom@5b { + compatible = "atmel,24c32d-wl"; /* M24C32-D WL page of 0x53 */ + pagesize = <32>; + reg = <0x5b>; + }; + ioexp: gpio@74 { compatible = "nxp,pca9539"; reg = <0x74>; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts index cc9d468b43ab8d..f87fa5a948ccc3 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-evk.dts +++ b/arch/arm64/boot/dts/freescale/imx8mp-evk.dts @@ -137,6 +137,28 @@ }; }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + dsp_vdev0vring0: vdev0vring0@942f0000 { + reg = <0 0x942f0000 0 0x8000>; + no-map; + }; + + dsp_vdev0vring1: vdev0vring1@942f8000 { + reg = <0 0x942f8000 0 0x8000>; + no-map; + }; + + dsp_vdev0buffer: vdev0buffer@94300000 { + compatible = "shared-dma-pool"; + reg = <0 0x94300000 0 0x100000>; + no-map; + }; + }; }; &flexspi { diff --git a/arch/arm64/boot/dts/freescale/imx8mp-msc-sm2s-ep1.dts b/arch/arm64/boot/dts/freescale/imx8mp-msc-sm2s-ep1.dts index e4215c83ee0f59..da4b1807c2753c 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-msc-sm2s-ep1.dts +++ b/arch/arm64/boot/dts/freescale/imx8mp-msc-sm2s-ep1.dts @@ -57,8 +57,8 @@ clocks = <&clk IMX8MP_CLK_CLKOUT1>; #sound-dai-cells = <0>; - VDDA-supply = <®_vcc_3v3_audio>; - VDDD-supply = <®_vcc_1v8_audio>; + VDDA-supply = <®_vcc_3v3_audio>; + VDDD-supply = <®_vcc_1v8_audio>; VDDIO-supply = <®_vcc_1v8_audio>; }; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-skov-reva.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-skov-reva.dtsi new file mode 100644 index 00000000000000..59813ef8e2bb3a --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mp-skov-reva.dtsi @@ -0,0 +1,711 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) + +#include "imx8mp.dtsi" + +#include + +/ { + aliases { + /* some of this aliases like backlight0, ethernetX and switch0 + * are needed for the bootloader. + */ + backlight0 = &backlight; + ethernet0 = &eqos; + ethernet1 = &lan1; + ethernet2 = &lan2; + rtc0 = &i2c_rtc; + rtc1 = &snvs_rtc; + switch0 = &switch; + }; + + /* + * Backlight is present only on some of boards, so it is disabled by + * default. + */ + backlight: backlight { + compatible = "pwm-backlight"; + pinctrl-0 = <&pinctrl_backlight>; + pwms = <&pwm1 0 20000 0>; + power-supply = <®_24v>; + enable-gpios = <&gpio4 24 GPIO_ACTIVE_HIGH>; + brightness-levels = <0 255>; + num-interpolated-steps = <17>; + default-brightness-level = <8>; + status = "disabled"; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio_led>; + + led-0 { + label = "D1"; + color = ; + gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>; + function = LED_FUNCTION_STATUS; + default-state = "on"; + linux,default-trigger = "heartbeat"; + }; + + led-1 { + label = "D2"; + color = ; + gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>; + default-state = "off"; + }; + + led-2 { + label = "D3"; + color = ; + gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>; + default-state = "on"; + }; + }; + + reg_1v2: regulator-1v2 { + compatible = "regulator-fixed"; + vin-supply = <®_5v_p>; + regulator-name = "1V2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + reg_2v5: regulator-2v5 { + compatible = "regulator-fixed"; + vin-supply = <®_5v_s>; + regulator-name = "2V5"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + }; + + reg_3v3: regulator-3v3 { + compatible = "regulator-fixed"; + vin-supply = <®_5v_s>; + regulator-name = "3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + /* + * This regulator will provide power as long as possible even if + * undervoltage is detected. + */ + reg_5v_p: regulator-5v-p { + compatible = "regulator-fixed"; + regulator-name = "5V_P"; + vin-supply = <®_24v>; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + + /* + * This regulator will be automatically shutdown if undervoltage is + * detected. + */ + reg_5v_s: regulator-5v-s { + compatible = "regulator-fixed"; + regulator-name = "5V_S"; + vin-supply = <®_24v>; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + + reg_24v: regulator-24v { + compatible = "regulator-fixed"; + regulator-name = "24V"; + regulator-min-microvolt = <24000000>; + regulator-max-microvolt = <24000000>; + }; + + reg_can2rs: regulator-can2rs { + compatible = "regulator-fixed"; + regulator-name = "CAN2RS"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_can2rs>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio4 22 GPIO_ACTIVE_LOW>; + }; + + reg_canrs: regulator-canrs { + compatible = "regulator-fixed"; + regulator-name = "CANRS"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_canrs>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio4 21 GPIO_ACTIVE_LOW>; + }; + + reg_tft_vcom: regulator-tft-vcom { + compatible = "pwm-regulator"; + pwms = <&pwm4 0 20000 0>; + regulator-name = "VCOM"; + vin-supply = <®_5v_s>; + regulator-min-microvolt = <3600000>; + regulator-max-microvolt = <3600000>; + regulator-always-on; + voltage-table = <3600000 26>; + status = "disabled"; + }; + + reg_vsd_3v3: regulator-vsd-3v3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_reg_vsd_3v3>; + vin-supply = <®_vdd_3v3>; + compatible = "regulator-fixed"; + regulator-name = "VSD_3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; +}; + +&A53_0 { + cpu-supply = <®_vdd_arm>; +}; + +&A53_1 { + cpu-supply = <®_vdd_arm>; +}; + +&A53_2 { + cpu-supply = <®_vdd_arm>; +}; + +&A53_3 { + cpu-supply = <®_vdd_arm>; +}; + +&ecspi2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi2>; + cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>; + status = "okay"; + + adc: adc@0 { + compatible = "microchip,mcp3002"; + reg = <0>; + vref-supply = <®_vdd_3v3>; + spi-max-frequency = <1000000>; + #io-channel-cells = <1>; + }; +}; + +&eqos { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_eqos>; + phy-mode = "rgmii-txid"; + status = "okay"; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&flexcan1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flexcan1>; + xceiver-supply = <®_canrs>; + status = "okay"; +}; + +&flexcan2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flexcan2>; + xceiver-supply = <®_can2rs>; + status = "okay"; +}; + +&i2c1 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + pmic@25 { + compatible = "nxp,pca9450c"; + reg = <0x25>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pmic>; + interrupts-extended = <&gpio1 3 IRQ_TYPE_EDGE_RISING>; + sd-vsel-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>; + + regulators { + reg_vdd_soc: BUCK1 { + regulator-name = "VDD_SOC"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <2187500>; + vin-supply = <®_5v_p>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <3125>; + }; + + reg_vdd_arm: BUCK2 { + regulator-name = "VDD_ARM"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <2187500>; + vin-supply = <®_5v_p>; + regulator-boot-on; + regulator-always-on; + regulator-ramp-delay = <3125>; + nxp,dvs-run-voltage = <950000>; + nxp,dvs-standby-voltage = <850000>; + }; + + reg_vdd_3v3: BUCK4 { + regulator-name = "VDD_3V3"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <3400000>; + vin-supply = <®_5v_p>; + regulator-boot-on; + regulator-always-on; + }; + + reg_vdd_1v8: BUCK5 { + regulator-name = "VDD_1V8"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <3400000>; + vin-supply = <®_5v_p>; + regulator-boot-on; + regulator-always-on; + }; + + reg_nvcc_dram_1v1: BUCK6 { + regulator-name = "NVCC_DRAM_1V1"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <3400000>; + vin-supply = <®_5v_p>; + regulator-boot-on; + regulator-always-on; + }; + + reg_nvcc_snvs_1v8: LDO1 { + regulator-name = "NVCC_SNVS_1V8"; + regulator-min-microvolt = <1600000>; + regulator-max-microvolt = <3300000>; + vin-supply = <®_5v_p>; + regulator-boot-on; + regulator-always-on; + }; + + reg_vdda_1v8: LDO3 { + regulator-name = "VDDA_1V8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <3300000>; + vin-supply = <®_5v_p>; + regulator-boot-on; + regulator-always-on; + }; + + reg_nvcc_sd2: LDO5 { + regulator-name = "NVCC_SD2"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + vin-supply = <®_5v_p>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; +}; + +&i2c3 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c3>; + status = "okay"; + + i2c_rtc: rtc@51 { + compatible = "nxp,pcf85063tp"; + reg = <0x51>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_rtc>; + interrupts-extended = <&gpio4 31 IRQ_TYPE_EDGE_FALLING>; + quartz-load-femtofarads = <12500>; + }; +}; + +&i2c4 { + clock-frequency = <380000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c4>; + status = "okay"; + + switch: switch@5f { + compatible = "microchip,ksz9893"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_switch>; + reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>; + reg = <0x5f>; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + + lan1: port@0 { + reg = <0>; + phy-mode = "internal"; + label = "lan1"; + }; + + lan2: port@1 { + reg = <1>; + phy-mode = "internal"; + label = "lan2"; + }; + + port@2 { + reg = <2>; + label = "cpu"; + ethernet = <&eqos>; + phy-mode = "rgmii"; + /* 2ns RX delay is implemented on PCB */ + tx-internal-delay-ps = <2000>; + rx-internal-delay-ps = <0>; + + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + }; + }; +}; + +&pwm1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm1>; +}; + +&pwm4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm4>; +}; + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + status = "okay"; +}; + +&uart2 { + /* console */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + status = "okay"; +}; + +&usb3_0 { + status = "okay"; +}; + +&usb3_1 { + status = "okay"; +}; + +&usb3_phy0 { + vbus-supply = <®_3v3>; + status = "okay"; +}; + +&usb3_phy1 { + vbus-supply = <®_3v3>; + status = "okay"; +}; + +&usb_dwc3_0 { + dr_mode = "host"; +}; + +&usb_dwc3_1 { + dr_mode = "host"; +}; + +/* SD Card */ +&usdhc2 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>; + pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>; + pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>; + vmmc-supply = <®_vsd_3v3>; + vqmmc-supply = <®_nvcc_sd2>; + cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>; + wp-gpios = <&gpio2 20 GPIO_ACTIVE_HIGH>; + bus-width = <4>; + status = "okay"; +}; + +/* eMMC */ +&usdhc3 { + assigned-clocks = <&clk IMX8MP_CLK_USDHC3>; + assigned-clock-rates = <400000000>; + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc3>; + pinctrl-1 = <&pinctrl_usdhc3_100mhz>; + pinctrl-2 = <&pinctrl_usdhc3_200mhz>; + vmmc-supply = <®_vdd_3v3>; + vqmmc-supply = <®_vdd_1v8>; + bus-width = <8>; + no-sd; + no-sdio; + non-removable; + status = "okay"; +}; + +&wdog1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wdog>; + fsl,ext-reset-output; + status = "okay"; +}; + +&iomuxc { + pinctrl_backlight: backlightgrp { + fsl,pins = < + MX8MP_IOMUXC_SAI2_TXFS__GPIO4_IO24 0x0100 + >; + }; + + pinctrl_can2rs: can2rsgrp { + fsl,pins = < + MX8MP_IOMUXC_SAI2_RXC__GPIO4_IO22 0x154 + >; + }; + + pinctrl_canrs: canrsgrp { + fsl,pins = < + MX8MP_IOMUXC_SAI2_RXFS__GPIO4_IO21 0x154 + >; + }; + + pinctrl_ecspi2: ecspi2grp { + fsl,pins = < + MX8MP_IOMUXC_ECSPI2_SCLK__ECSPI2_SCLK 0x44 + MX8MP_IOMUXC_ECSPI2_MOSI__ECSPI2_MOSI 0x44 + MX8MP_IOMUXC_ECSPI2_MISO__ECSPI2_MISO 0x44 + MX8MP_IOMUXC_ECSPI2_SS0__GPIO5_IO13 0x40 + >; + }; + + pinctrl_eqos: eqosgrp { + fsl,pins = < + MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0 0x91 + MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1 0x91 + MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2 0x91 + MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3 0x91 + MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK 0x91 + MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL 0x91 + MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0 0x1f + MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1 0x1f + MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2 0x1f + MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3 0x1f + MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL 0x1f + MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK 0x1f + >; + }; + + pinctrl_flexcan1: flexcan1grp { + fsl,pins = < + MX8MP_IOMUXC_SPDIF_RX__CAN1_RX 0x154 + MX8MP_IOMUXC_SPDIF_TX__CAN1_TX 0x154 + >; + }; + + pinctrl_flexcan2: flexcan2grp { + fsl,pins = < + MX8MP_IOMUXC_SAI2_MCLK__CAN2_RX 0x154 + MX8MP_IOMUXC_SAI2_TXD0__CAN2_TX 0x154 + >; + }; + + pinctrl_gpio_led: gpioledgrp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO05__GPIO1_IO05 0x19 + MX8MP_IOMUXC_GPIO1_IO06__GPIO1_IO06 0x19 + MX8MP_IOMUXC_GPIO1_IO07__GPIO1_IO07 0x19 + >; + }; + + pinctrl_i2c1: i2c1grp { + fsl,pins = < + MX8MP_IOMUXC_I2C1_SCL__I2C1_SCL 0x400001c2 + MX8MP_IOMUXC_I2C1_SDA__I2C1_SDA 0x400001c2 + >; + }; + + pinctrl_i2c3: i2c3grp { + fsl,pins = < + MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL 0x400001c2 + MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA 0x400001c2 + >; + }; + + pinctrl_i2c4: i2c4grp { + fsl,pins = < + MX8MP_IOMUXC_I2C4_SCL__I2C4_SCL 0x400001c3 + MX8MP_IOMUXC_I2C4_SDA__I2C4_SDA 0x400001c3 + >; + }; + + pinctrl_pmic: pmicirqgrp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO03__GPIO1_IO03 0x41 + MX8MP_IOMUXC_GPIO1_IO04__GPIO1_IO04 0x41 + >; + }; + + pinctrl_pwm1: pwm1grp { + fsl,pins = < + MX8MP_IOMUXC_SPDIF_EXT_CLK__PWM1_OUT 0x116 + >; + }; + + pinctrl_pwm4: pwm4grp { + fsl,pins = < + MX8MP_IOMUXC_SAI3_MCLK__PWM4_OUT 0x116 + >; + }; + + pinctrl_reg_vsd_3v3: regvsd3v3grp { + fsl,pins = < + MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19 0x40 + >; + }; + + pinctrl_rtc: rtcgrp { + fsl,pins = < + MX8MP_IOMUXC_SAI3_TXFS__GPIO4_IO31 0x41 + >; + }; + + pinctrl_switch: switchgrp { + fsl,pins = < + MX8MP_IOMUXC_SAI3_TXC__GPIO5_IO00 0x41 + MX8MP_IOMUXC_SAI3_TXD__GPIO5_IO01 0x41 + >; + }; + + pinctrl_touchscreen: touchscreengrp { + fsl,pins = < + /* external 10 k pull up */ + /* CTP_INT */ + MX8MP_IOMUXC_SAI3_RXFS__GPIO4_IO28 0x41 + /* CTP_RST */ + MX8MP_IOMUXC_SAI3_RXC__GPIO4_IO29 0x41 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX8MP_IOMUXC_UART1_RXD__UART1_DCE_RX 0x140 + MX8MP_IOMUXC_UART1_TXD__UART1_DCE_TX 0x140 + MX8MP_IOMUXC_UART3_RXD__UART1_DTE_RTS 0x140 + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX 0x14f + MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX 0x14f + >; + }; + + pinctrl_usdhc2: usdhc2grp { + fsl,pins = < + MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK 0x190 + MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD 0x1d0 + MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0 0x1d0 + MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1 0x1d0 + MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2 0x1d0 + MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3 0x1d0 + >; + }; + + pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp { + fsl,pins = < + MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK 0x194 + MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD 0x1d4 + MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0 0x1d4 + MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1 0x1d4 + MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2 0x1d4 + MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3 0x1d4 + >; + }; + + pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp { + fsl,pins = < + MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK 0x196 + MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD 0x1d6 + MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0 0x1d6 + MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1 0x1d6 + MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2 0x1d6 + MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3 0x1d6 + >; + }; + + pinctrl_usdhc2_gpio: usdhc2gpiogrp { + fsl,pins = < + MX8MP_IOMUXC_SD2_CD_B__GPIO2_IO12 0x1c4 + MX8MP_IOMUXC_SD2_WP__GPIO2_IO20 0x1c4 + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK 0x190 + MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD 0x1d0 + MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0 0x1d0 + MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1 0x1d0 + MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2 0x1d0 + MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3 0x1d0 + MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4 0x1d0 + MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5 0x1d0 + MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6 0x1d0 + MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7 0x1d0 + MX8MP_IOMUXC_NAND_CE1_B__USDHC3_STROBE 0x190 + >; + }; + + pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp { + fsl,pins = < + MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK 0x194 + MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD 0x1d4 + MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0 0x1d4 + MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1 0x1d4 + MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2 0x1d4 + MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3 0x1d4 + MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4 0x1d4 + MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5 0x1d4 + MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6 0x1d4 + MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7 0x1d4 + MX8MP_IOMUXC_NAND_CE1_B__USDHC3_STROBE 0x194 + >; + }; + + pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp { + fsl,pins = < + MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK 0x196 + MX8MP_IOMUXC_NAND_WP_B__USDHC3_CMD 0x1d6 + MX8MP_IOMUXC_NAND_DATA04__USDHC3_DATA0 0x1d6 + MX8MP_IOMUXC_NAND_DATA05__USDHC3_DATA1 0x1d6 + MX8MP_IOMUXC_NAND_DATA06__USDHC3_DATA2 0x1d6 + MX8MP_IOMUXC_NAND_DATA07__USDHC3_DATA3 0x1d6 + MX8MP_IOMUXC_NAND_RE_B__USDHC3_DATA4 0x1d6 + MX8MP_IOMUXC_NAND_CE2_B__USDHC3_DATA5 0x1d6 + MX8MP_IOMUXC_NAND_CE3_B__USDHC3_DATA6 0x1d6 + MX8MP_IOMUXC_NAND_CLE__USDHC3_DATA7 0x1d6 + MX8MP_IOMUXC_NAND_CE1_B__USDHC3_STROBE 0x196 + >; + }; + + pinctrl_wdog: wdoggrp { + fsl,pins = < + MX8MP_IOMUXC_GPIO1_IO02__WDOG1_WDOG_B 0xc6 + >; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-skov-revb-hdmi.dts b/arch/arm64/boot/dts/freescale/imx8mp-skov-revb-hdmi.dts new file mode 100644 index 00000000000000..c1ca69da3cb8ed --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mp-skov-revb-hdmi.dts @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) + +/dts-v1/; + +#include "imx8mp-skov-reva.dtsi" + +/ { + model = "SKOV IMX8MP CPU revB - HDMI"; + compatible = "skov,imx8mp-skov-revb-hdmi", "fsl,imx8mp"; +}; + +&iomuxc { + pinctrl_hdmi: hdmigrp { + fsl,pins = < + MX8MP_IOMUXC_HDMI_DDC_SCL__HDMIMIX_HDMI_SCL 0x1c3 + MX8MP_IOMUXC_HDMI_DDC_SDA__HDMIMIX_HDMI_SDA 0x1c3 + MX8MP_IOMUXC_HDMI_HPD__HDMIMIX_HDMI_HPD 0x19 + >; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-skov-revb-lt6.dts b/arch/arm64/boot/dts/freescale/imx8mp-skov-revb-lt6.dts new file mode 100644 index 00000000000000..ccbd3abedd6941 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mp-skov-revb-lt6.dts @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) + +/dts-v1/; + +#include "imx8mp-skov-reva.dtsi" + +/ { + model = "SKOV IMX8MP CPU revB - LT6"; + compatible = "skov,imx8mp-skov-revb-lt6", "fsl,imx8mp"; + + touchscreen { + compatible = "resistive-adc-touch"; + io-channels = <&adc_ts 1>, <&adc_ts 3>, <&adc_ts 4>, <&adc_ts 5>; + io-channel-names = "y", "z1", "z2", "x"; + touchscreen-min-pressure = <65000>; + touchscreen-inverted-y; + touchscreen-swapped-x-y; + touchscreen-x-plate-ohms = <300>; + }; +}; + +®_tft_vcom { + regulator-min-microvolt = <3600000>; + regulator-max-microvolt = <3600000>; + voltage-table = <3600000 26>; + status = "okay"; +}; + +&pwm4 { + status = "okay"; +}; + +&backlight { + status = "okay"; +}; + +&ecspi1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ecspi1>; + cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>; + status = "okay"; + + adc_ts: adc@0 { + compatible = "ti,tsc2046e-adc"; + reg = <0>; + pinctrl-0 = <&pinctrl_touch>; + pinctrl-names ="default"; + spi-max-frequency = <1000000>; + interrupts-extended = <&gpio4 25 IRQ_TYPE_LEVEL_LOW>; + #io-channel-cells = <1>; + + #address-cells = <1>; + #size-cells = <0>; + + channel@1 { + reg = <1>; + settling-time-us = <700>; + oversampling-ratio = <5>; + }; + + channel@3 { + reg = <3>; + settling-time-us = <700>; + oversampling-ratio = <5>; + }; + + channel@4 { + reg = <4>; + settling-time-us = <700>; + oversampling-ratio = <5>; + }; + + channel@5 { + reg = <5>; + settling-time-us = <700>; + oversampling-ratio = <5>; + }; + }; +}; + +&pwm1 { + status = "okay"; +}; + +&iomuxc { + pinctrl_ecspi1: ecspi1grp { + fsl,pins = < + MX8MP_IOMUXC_ECSPI1_SCLK__ECSPI1_SCLK 0x44 + MX8MP_IOMUXC_ECSPI1_MOSI__ECSPI1_MOSI 0x44 + MX8MP_IOMUXC_ECSPI1_MISO__ECSPI1_MISO 0x44 + MX8MP_IOMUXC_ECSPI1_SS0__GPIO5_IO09 0x40 + >; + }; + + pinctrl_touch: touchgrp { + fsl,pins = < + /* external pull up */ + MX8MP_IOMUXC_SAI2_TXC__GPIO4_IO25 0x40 + >; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-skov-revb-mi1010ait-1cp1.dts b/arch/arm64/boot/dts/freescale/imx8mp-skov-revb-mi1010ait-1cp1.dts new file mode 100644 index 00000000000000..3c2efdc59bfad3 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mp-skov-revb-mi1010ait-1cp1.dts @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) + +/dts-v1/; + +#include "imx8mp-skov-reva.dtsi" + +/ { + model = "SKOV IMX8MP CPU revB - MI1010AIT-1CP1"; + compatible = "skov,imx8mp-skov-revb-mi1010ait-1cp1", "fsl,imx8mp"; + + panel { + compatible = "multi-inno,mi1010ait-1cp"; + backlight = <&backlight>; + power-supply = <®_tft_vcom>; + + port { + in_lvds0: endpoint { + remote-endpoint = <&ldb_lvds_ch0>; + }; + }; + }; +}; + +&backlight { + status = "okay"; +}; + +&i2c2 { + clock-frequency = <100000>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c2>; + status = "okay"; + + touchscreen@38 { + compatible = "edt,edt-ft5406"; + reg = <0x38>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_touchscreen>; + interrupts-extended = <&gpio4 28 IRQ_TYPE_EDGE_FALLING>; + reset-gpios = <&gpio4 29 GPIO_ACTIVE_LOW>; + touchscreen-size-x = <1280>; + touchscreen-size-y = <800>; + vcc-supply = <®_vdd_3v3>; + iovcc-supply = <®_vdd_3v3>; + wakeup-source; + }; +}; + +&lcdif2 { + status = "okay"; +}; + +&lvds_bridge { + /* IMX8MP_CLK_MEDIA_LDB = IMX8MP_CLK_MEDIA_DISP2_PIX * 7 */ + assigned-clock-rates = <482300000>; + status = "okay"; + + ports { + port@1 { + ldb_lvds_ch0: endpoint { + remote-endpoint = <&in_lvds0>; + }; + }; + }; +}; + +&media_blk_ctrl { + /* currently it is not possible to let display clocks confugure + * automatically, so we need to set them manually + */ + assigned-clock-rates = <500000000>, <200000000>, <0>, + /* IMX8MP_CLK_MEDIA_DISP2_PIX = pixelclk of lvds panel */ + <68900000>, + /* IMX8MP_VIDEO_PLL1 = IMX8MP_CLK_MEDIA_LDB * 2 */ + <964600000>; +}; + +&pwm4 { + status = "okay"; +}; + +&pwm1 { + status = "okay"; +}; + +®_tft_vcom { + regulator-min-microvolt = <3160000>; + regulator-max-microvolt = <3160000>; + voltage-table = <3160000 73>; + status = "okay"; +}; + +&iomuxc { + pinctrl_i2c2: i2c2grp { + fsl,pins = < + MX8MP_IOMUXC_I2C2_SCL__I2C2_SCL 0x400001c2 + MX8MP_IOMUXC_I2C2_SDA__I2C2_SDA 0x400001c2 + >; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl-lvds-g133han01.dtso b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl-lvds-g133han01.dtso new file mode 100644 index 00000000000000..5058cd9409c755 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl-lvds-g133han01.dtso @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR MIT) +/* + * Copyright (c) 2023 TQ-Systems GmbH , + * D-82229 Seefeld, Germany. + * Author: Alexander Stein + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + compatible = "tq,imx8mp-tqma8mpql-mba8mpxl", "tq,imx8mp-tqma8mpql", "fsl,imx8mp"; +}; + +&backlight_lvds { + status = "okay"; +}; + +&display { + compatible = "auo,g133han01"; + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dual-lvds-odd-pixels; + + panel_in_lvds0: endpoint { + remote-endpoint = <&ldb_lvds_ch0>; + }; + }; + + port@1 { + reg = <1>; + dual-lvds-even-pixels; + + panel_in_lvds1: endpoint { + remote-endpoint = <&ldb_lvds_ch1>; + }; + }; + }; +}; + +&lcdif2 { + status = "okay"; +}; + +&lvds_bridge { + assigned-clocks = <&clk IMX8MP_CLK_MEDIA_LDB>, + <&clk IMX8MP_VIDEO_PLL1>; + assigned-clock-parents = <&clk IMX8MP_VIDEO_PLL1_OUT>; + assigned-clock-rates = <0>, <988400000>; + status = "okay"; + + ports { + port@1 { + ldb_lvds_ch0: endpoint { + remote-endpoint = <&panel_in_lvds0>; + }; + }; + + port@2 { + ldb_lvds_ch1: endpoint { + remote-endpoint = <&panel_in_lvds1>; + }; + }; + }; +}; + +&pwm2 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts index 4240e20d38ac32..a2d5d19b2de0cb 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts +++ b/arch/arm64/boot/dts/freescale/imx8mp-tqma8mpql-mba8mpxl.dts @@ -15,6 +15,7 @@ / { model = "TQ-Systems i.MX8MPlus TQMa8MPxL on MBa8MPxL"; compatible = "tq,imx8mp-tqma8mpql-mba8mpxl", "tq,imx8mp-tqma8mpql", "fsl,imx8mp"; + chassis-type = "embedded"; chosen { stdout-path = &uart4; @@ -55,6 +56,21 @@ clock-frequency = <25000000>; }; + connector { + compatible = "gpio-usb-b-connector", "usb-b-connector"; + type = "micro"; + label = "X29"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbcon0>; + id-gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; + + port { + usb_dr_connector: endpoint { + remote-endpoint = <&usb3_dwc>; + }; + }; + }; + fan0: pwm-fan { compatible = "pwm-fan"; pinctrl-names = "default"; @@ -602,7 +618,6 @@ &usb3_1 { fsl,disable-port-power-control; fsl,permanently-attached; - dr_mode = "host"; status = "okay"; }; @@ -626,13 +641,10 @@ role-switch-default-mode = "peripheral"; status = "okay"; - connector { - compatible = "gpio-usb-b-connector", "usb-b-connector"; - type = "micro"; - label = "X29"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usbcon0>; - id-gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; + port { + usb3_dwc: endpoint { + remote-endpoint = <&usb_dr_connector>; + }; }; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw71xx.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw71xx.dtsi index bf47b5e9dd8cc0..0e8d0f3c7ea871 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw71xx.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw71xx.dtsi @@ -8,6 +8,21 @@ #include / { + connector { + compatible = "gpio-usb-b-connector", "usb-b-connector"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbcon1>; + type = "micro"; + label = "Type-C"; + id-gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>; + + port { + usb_dr_connector: endpoint { + remote-endpoint = <&usb3_dwc>; + }; + }; + }; + led-controller { compatible = "gpio-leds"; pinctrl-names = "default"; @@ -132,13 +147,10 @@ role-switch-default-mode = "peripheral"; status = "okay"; - connector { - compatible = "gpio-usb-b-connector", "usb-b-connector"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usbcon1>; - type = "micro"; - label = "Type-C"; - id-gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>; + port { + usb3_dwc: endpoint { + remote-endpoint = <&usb_dr_connector>; + }; }; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw72xx.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw72xx.dtsi index f942e949084bdd..41c79d2ebdd620 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw72xx.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw72xx.dtsi @@ -8,6 +8,21 @@ #include / { + connector { + compatible = "gpio-usb-b-connector", "usb-b-connector"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbcon1>; + type = "micro"; + label = "otg"; + id-gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>; + + port { + usb_dr_connector: endpoint { + remote-endpoint = <&usb3_dwc>; + }; + }; + }; + led-controller { compatible = "gpio-leds"; pinctrl-names = "default"; @@ -83,8 +98,15 @@ &ecspi2 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_spi2>; - cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>; + cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>, + <&gpio1 10 GPIO_ACTIVE_LOW>; status = "okay"; + + tpm@1 { + compatible = "atmel,attpm20p", "tcg,tpm_tis-spi"; + reg = <0x1>; + spi-max-frequency = <36000000>; + }; }; &gpio4 { @@ -175,13 +197,10 @@ role-switch-default-mode = "peripheral"; status = "okay"; - connector { - compatible = "gpio-usb-b-connector", "usb-b-connector"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usbcon1>; - type = "micro"; - label = "otg"; - id-gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>; + port { + usb3_dwc: endpoint { + remote-endpoint = <&usb_dr_connector>; + }; }; }; @@ -285,6 +304,7 @@ MX8MP_IOMUXC_ECSPI2_MOSI__ECSPI2_MOSI 0x140 MX8MP_IOMUXC_ECSPI2_MISO__ECSPI2_MISO 0x140 MX8MP_IOMUXC_ECSPI2_SS0__GPIO5_IO13 0x140 + MX8MP_IOMUXC_GPIO1_IO10__GPIO1_IO10 0x140 >; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw73xx.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw73xx.dtsi index b0d42b18c5ced7..d5c400b355af56 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw73xx.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw73xx.dtsi @@ -8,6 +8,21 @@ #include / { + connector { + compatible = "gpio-usb-b-connector", "usb-b-connector"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbcon1>; + type = "micro"; + label = "otg"; + id-gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>; + + port { + usb_dr_connector: endpoint { + remote-endpoint = <&usb3_dwc>; + }; + }; + }; + led-controller { compatible = "gpio-leds"; pinctrl-names = "default"; @@ -100,7 +115,7 @@ status = "okay"; tpm@1 { - compatible = "tcg,tpm_tis-spi"; + compatible = "atmel,attpm20p", "tcg,tpm_tis-spi"; reg = <0x1>; spi-max-frequency = <36000000>; }; @@ -201,13 +216,10 @@ role-switch-default-mode = "peripheral"; status = "okay"; - connector { - compatible = "gpio-usb-b-connector", "usb-b-connector"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usbcon1>; - type = "micro"; - label = "otg"; - id-gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>; + port { + usb3_dwc: endpoint { + remote-endpoint = <&usb_dr_connector>; + }; }; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw74xx.dts b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw74xx.dts index 2ab9f4cc12cc9d..cae586cd45bdd5 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-venice-gw74xx.dts +++ b/arch/arm64/boot/dts/freescale/imx8mp-venice-gw74xx.dts @@ -35,6 +35,21 @@ reg = <0x0 0x40000000 0 0x80000000>; }; + connector { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usbcon1>; + compatible = "gpio-usb-b-connector", "usb-b-connector"; + type = "micro"; + label = "Type-C"; + id-gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; + + port { + usb_dr_connector: endpoint { + remote-endpoint = <&usb3_dwc>; + }; + }; + }; + gpio-keys { compatible = "gpio-keys"; @@ -181,9 +196,7 @@ status = "okay"; tpm@0 { - compatible = "tcg,tpm_tis-spi"; - #address-cells = <0x1>; - #size-cells = <0x1>; + compatible = "atmel,attpm20p", "tcg,tpm_tis-spi"; reg = <0x0>; spi-max-frequency = <36000000>; }; @@ -694,13 +707,10 @@ role-switch-default-mode = "peripheral"; status = "okay"; - connector { - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usbcon1>; - compatible = "gpio-usb-b-connector", "usb-b-connector"; - type = "micro"; - label = "Type-C"; - id-gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; + port { + usb3_dwc: endpoint { + remote-endpoint = <&usb_dr_connector>; + }; }; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-verdin-mallow.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-verdin-mallow.dtsi new file mode 100644 index 00000000000000..8482393f3cac5e --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mp-verdin-mallow.dtsi @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright 2023 Toradex + * + * Common dtsi for Verdin IMX8MP SoM on Mallow carrier board + * + * https://www.toradex.com/computer-on-modules/verdin-arm-family/nxp-imx-8m-plus + * https://www.toradex.com/products/carrier-board/mallow-carrier-board + */ + +#include + +/ { + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_leds>; + + /* SODIMM 52 - USER_LED_1_RED */ + led-0 { + color = ; + function = LED_FUNCTION_DEBUG; + function-enumerator = <1>; + gpios = <&gpio3 0 GPIO_ACTIVE_HIGH>; + }; + + /* SODIMM 54 - USER_LED_1_GREEN */ + led-1 { + color = ; + function = LED_FUNCTION_DEBUG; + function-enumerator = <1>; + gpios = <&gpio3 1 GPIO_ACTIVE_HIGH>; + }; + + /* SODIMM 56 - USER_LED_2_RED */ + led-2 { + color = ; + function = LED_FUNCTION_DEBUG; + function-enumerator = <2>; + gpios = <&gpio3 6 GPIO_ACTIVE_HIGH>; + }; + + /* SODIMM 58 - USER_LED_2_GREEN */ + led-3 { + color = ; + function = LED_FUNCTION_DEBUG; + function-enumerator = <2>; + gpios = <&gpio3 7 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +&backlight { + power-supply = <®_3p3v>; +}; + +/* Verdin SPI_1 */ +&ecspi1 { + pinctrl-0 = <&pinctrl_ecspi1>, <&pinctrl_tpm_cs>; + cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>, <&gpio3 16 GPIO_ACTIVE_LOW>; + status = "okay"; + + tpm@1 { + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; + reg = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_tpm_irq>; + interrupt-parent = <&gpio3>; + interrupts = <14 IRQ_TYPE_LEVEL_LOW>; + spi-max-frequency = <18500000>; + }; +}; + +/* EEPROM on Mallow */ +&eeprom_carrier_board { + status = "okay"; +}; + +/* Verdin ETH_1 */ +&eqos { + status = "okay"; +}; + +/* Verdin CAN_1 */ +&flexcan1 { + status = "okay"; +}; + +/* Verdin CAN_2 */ +&flexcan2 { + status = "okay"; +}; + +/* Temperature sensor on Mallow */ +&hwmon_temp { + compatible = "ti,tmp1075"; + status = "okay"; +}; + +/* Verdin I2C_2_DSI */ +&i2c2 { + status = "okay"; +}; + +/* Verdin I2C_4_CSI */ +&i2c3 { + status = "okay"; +}; + +/* Verdin I2C_1 */ +&i2c4 { + status = "okay"; +}; + +/* Verdin PCIE_1 */ +&pcie { + status = "okay"; +}; + +&pcie_phy { + status = "okay"; +}; + +/* Verdin PWM_1 */ +&pwm1 { + status = "okay"; +}; + +/* Verdin PWM_2 */ +&pwm2 { + status = "okay"; +}; + +/* Verdin PWM_3_DSI */ +&pwm3 { + status = "okay"; +}; + +®_usdhc2_vmmc { + vin-supply = <®_3p3v>; +}; + +/* Verdin UART_1 */ +&uart1 { + status = "okay"; +}; + +/* Verdin UART_2 */ +&uart2 { + status = "okay"; +}; + +/* Verdin UART_3 */ +&uart3 { + status = "okay"; +}; + +/* Verdin USB_1 */ +&usb3_0 { + status = "okay"; +}; + +&usb3_phy0 { + status = "okay"; +}; + +/* Verdin USB_2 */ +&usb3_1 { + status = "okay"; +}; + +&usb3_phy1 { + status = "okay"; +}; + +/* Verdin SD_1 */ +&usdhc2 { + status = "okay"; +}; + +&iomuxc { + pinctrl_leds: ledsgrp { + fsl,pins = + , /* SODIMM 52 */ + , /* SODIMM 54 */ + , /* SODIMM 56 */ + ; /* SODIMM 58 */ + }; + + pinctrl_tpm_cs: tpmcsgrp { + fsl,pins = + ; /* SODIMM 64 */ + }; + + pinctrl_tpm_irq: tpmirqgrp { + fsl,pins = + ; /* SODIMM 66 */ + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-verdin-nonwifi-mallow.dts b/arch/arm64/boot/dts/freescale/imx8mp-verdin-nonwifi-mallow.dts new file mode 100644 index 00000000000000..6a536a4964bbb1 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mp-verdin-nonwifi-mallow.dts @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright 2023 Toradex + */ + +/dts-v1/; + +#include "imx8mp-verdin.dtsi" +#include "imx8mp-verdin-nonwifi.dtsi" +#include "imx8mp-verdin-mallow.dtsi" + +/ { + model = "Toradex Verdin iMX8M Plus on Mallow Board"; + compatible = "toradex,verdin-imx8mp-nonwifi-mallow", + "toradex,verdin-imx8mp-nonwifi", + "toradex,verdin-imx8mp", + "fsl,imx8mp"; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-verdin-wifi-mallow.dts b/arch/arm64/boot/dts/freescale/imx8mp-verdin-wifi-mallow.dts new file mode 100644 index 00000000000000..08b7aef3fddefc --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mp-verdin-wifi-mallow.dts @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright 2023 Toradex + */ + +/dts-v1/; + +#include "imx8mp-verdin.dtsi" +#include "imx8mp-verdin-wifi.dtsi" +#include "imx8mp-verdin-mallow.dtsi" + +/ { + model = "Toradex Verdin iMX8M Plus WB on Mallow Board"; + compatible = "toradex,verdin-imx8mp-wifi-mallow", + "toradex,verdin-imx8mp-wifi", + "toradex,verdin-imx8mp", + "fsl,imx8mp"; +}; diff --git a/arch/arm64/boot/dts/freescale/imx8mp-verdin.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-verdin.dtsi index 04f2083c4ab2e3..c3305f0d400100 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp-verdin.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp-verdin.dtsi @@ -45,6 +45,23 @@ status = "disabled"; }; + connector { + compatible = "gpio-usb-b-connector", "usb-b-connector"; + id-gpios = <&gpio2 10 GPIO_ACTIVE_HIGH>; + label = "Type-C"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb_1_id>; + self-powered; + type = "micro"; + vbus-supply = <®_usb1_vbus>; + + port { + usb_dr_connector: endpoint { + remote-endpoint = <&usb3_dwc>; + }; + }; + }; + gpio-keys { compatible = "gpio-keys"; pinctrl-names = "default"; @@ -835,15 +852,10 @@ srp-disable; usb-role-switch; - connector { - compatible = "gpio-usb-b-connector", "usb-b-connector"; - id-gpios = <&gpio2 10 GPIO_ACTIVE_HIGH>; - label = "Type-C"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usb_1_id>; - self-powered; - type = "micro"; - vbus-supply = <®_usb1_vbus>; + port { + usb3_dwc: endpoint { + remote-endpoint = <&usb_dr_connector>; + }; }; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mp.dtsi b/arch/arm64/boot/dts/freescale/imx8mp.dtsi index 1264da6012f929..76c73daf546bd0 100644 --- a/arch/arm64/boot/dts/freescale/imx8mp.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mp.dtsi @@ -264,6 +264,7 @@ dsp_reserved: dsp@92400000 { reg = <0 0x92400000 0 0x2000000>; no-map; + status = "disabled"; }; }; @@ -726,6 +727,8 @@ clk: clock-controller@30380000 { compatible = "fsl,imx8mp-ccm"; reg = <0x30380000 0x10000>; + interrupts = , + ; #clock-cells = <1>; clocks = <&osc_32k>, <&osc_24m>, <&clk_ext1>, <&clk_ext2>, <&clk_ext3>, <&clk_ext4>; @@ -793,8 +796,8 @@ <&clk IMX8MP_CLK_AUDIO_AXI>; assigned-clocks = <&clk IMX8MP_CLK_AUDIO_AHB>, <&clk IMX8MP_CLK_AUDIO_AXI_SRC>; - assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_800M>, - <&clk IMX8MP_SYS_PLL1_800M>; + assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_800M>, + <&clk IMX8MP_SYS_PLL1_800M>; assigned-clock-rates = <400000000>, <600000000>; }; @@ -887,6 +890,15 @@ clocks = <&clk IMX8MP_CLK_ML_AXI>, <&clk IMX8MP_CLK_ML_AHB>, <&clk IMX8MP_CLK_NPU_ROOT>; + assigned-clocks = <&clk IMX8MP_CLK_ML_CORE>, + <&clk IMX8MP_CLK_ML_AXI>, + <&clk IMX8MP_CLK_ML_AHB>; + assigned-clock-parents = <&clk IMX8MP_SYS_PLL1_800M>, + <&clk IMX8MP_SYS_PLL1_800M>, + <&clk IMX8MP_SYS_PLL1_800M>; + assigned-clock-rates = <800000000>, + <800000000>, + <300000000>; }; }; }; @@ -2012,6 +2024,18 @@ interconnect-names = "g1", "g2", "vc8000e"; }; + npu: npu@38500000 { + compatible = "vivante,gc"; + reg = <0x38500000 0x200000>; + interrupts = ; + clocks = <&clk IMX8MP_CLK_NPU_ROOT>, + <&clk IMX8MP_CLK_NPU_ROOT>, + <&clk IMX8MP_CLK_ML_AXI>, + <&clk IMX8MP_CLK_ML_AHB>; + clock-names = "core", "shader", "bus", "reg"; + power-domains = <&pgc_mlmix>; + }; + gic: interrupt-controller@38800000 { compatible = "arm,gic-v3"; reg = <0x38800000 0x10000>, diff --git a/arch/arm64/boot/dts/freescale/imx8mq-kontron-pitx-imx8m.dts b/arch/arm64/boot/dts/freescale/imx8mq-kontron-pitx-imx8m.dts index 6376417e918c20..d8cf1f27c3ec8a 100644 --- a/arch/arm64/boot/dts/freescale/imx8mq-kontron-pitx-imx8m.dts +++ b/arch/arm64/boot/dts/freescale/imx8mq-kontron-pitx-imx8m.dts @@ -65,7 +65,7 @@ status = "okay"; tpm@0 { - compatible = "infineon,slb9670"; + compatible = "infineon,slb9670", "tcg,tpm_tis-spi"; reg = <0>; spi-max-frequency = <43000000>; }; diff --git a/arch/arm64/boot/dts/freescale/imx8mq-phanbell.dts b/arch/arm64/boot/dts/freescale/imx8mq-phanbell.dts index a3b9d615a3b407..e34045d10a12fd 100644 --- a/arch/arm64/boot/dts/freescale/imx8mq-phanbell.dts +++ b/arch/arm64/boot/dts/freescale/imx8mq-phanbell.dts @@ -39,7 +39,7 @@ fan: gpio-fan { compatible = "gpio-fan"; - gpio-fan,speed-map = <0 0 8600 1>; + gpio-fan,speed-map = <0 0>, <8600 1>; gpios = <&gpio3 5 GPIO_ACTIVE_HIGH>; #cooling-cells = <2>; pinctrl-names = "default"; diff --git a/arch/arm64/boot/dts/freescale/imx8mq-tqma8mq-mba8mx.dts b/arch/arm64/boot/dts/freescale/imx8mq-tqma8mq-mba8mx.dts index 0d8def2766f50e..b302daca4ce64e 100644 --- a/arch/arm64/boot/dts/freescale/imx8mq-tqma8mq-mba8mx.dts +++ b/arch/arm64/boot/dts/freescale/imx8mq-tqma8mq-mba8mx.dts @@ -11,6 +11,7 @@ / { model = "TQ-Systems GmbH i.MX8MQ TQMa8MQ on MBa8Mx"; compatible = "tq,imx8mq-tqma8mq-mba8mx", "tq,imx8mq-tqma8mq", "fsl,imx8mq"; + chassis-type = "embedded"; aliases { eeprom0 = &eeprom3; diff --git a/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi b/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi index 8439dd6b393534..69cb8676732ea5 100644 --- a/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8qm-ss-dma.dtsi @@ -128,21 +128,25 @@ &lpuart0 { compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart"; dmas = <&edma2 13 0 0>, <&edma2 12 0 1>; + dma-names = "rx","tx"; }; &lpuart1 { compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart"; dmas = <&edma2 15 0 0>, <&edma2 14 0 1>; + dma-names = "rx","tx"; }; &lpuart2 { compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart"; dmas = <&edma2 17 0 0>, <&edma2 16 0 1>; + dma-names = "rx","tx"; }; &lpuart3 { compatible = "fsl,imx8qm-lpuart", "fsl,imx8qxp-lpuart"; dmas = <&edma2 19 0 0>, <&edma2 18 0 1>; + dma-names = "rx","tx"; }; &i2c0 { diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts b/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts index 99611729943cee..8360bb851ac03f 100644 --- a/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts +++ b/arch/arm64/boot/dts/freescale/imx8qxp-mek.dts @@ -31,7 +31,7 @@ }; gpio-sbu-mux { - compatible = "gpio-sbu-mux"; + compatible = "nxp,cbdtu02043", "gpio-sbu-mux"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_typec_mux>; select-gpios = <&lsio_gpio5 9 GPIO_ACTIVE_HIGH>; @@ -50,6 +50,10 @@ status = "okay"; }; +&dsp_reserved { + status = "okay"; +}; + &fec1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_fec1>; @@ -152,12 +156,6 @@ interrupt-parent = <&lsio_gpio1>; interrupts = <3 IRQ_TYPE_LEVEL_LOW>; - port { - typec_dr_sw: endpoint { - remote-endpoint = <&usb3_drd_sw>; - }; - }; - usb_con1: connector { compatible = "usb-c-connector"; label = "USB-C"; @@ -169,8 +167,17 @@ #address-cells = <1>; #size-cells = <0>; + port@0 { + reg = <0>; + + typec_dr_sw: endpoint { + remote-endpoint = <&usb3_drd_sw>; + }; + }; + port@1 { reg = <1>; + typec_con_ss: endpoint { remote-endpoint = <&usb3_data_ss>; }; diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-ss-vpu.dtsi b/arch/arm64/boot/dts/freescale/imx8qxp-ss-vpu.dtsi new file mode 100644 index 00000000000000..7894a3ab26d6bc --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8qxp-ss-vpu.dtsi @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR X11) +/* + * Copyright 2023 TQ-Systems GmbH , + * D-82229 Seefeld, Germany. + * Author: Alexander Stein + */ + +&vpu_core0 { + reg = <0x2d040000 0x10000>; +}; + +&vpu_core1 { + reg = <0x2d050000 0x10000>; +}; + +/delete-node/ &mu2_m0; +/delete-node/ &vpu_core2; diff --git a/arch/arm64/boot/dts/freescale/imx8qxp.dtsi b/arch/arm64/boot/dts/freescale/imx8qxp.dtsi index c80c85a4b40591..958267b3334031 100644 --- a/arch/arm64/boot/dts/freescale/imx8qxp.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8qxp.dtsi @@ -48,7 +48,6 @@ serial3 = &lpuart3; vpu-core0 = &vpu_core0; vpu-core1 = &vpu_core1; - vpu-core2 = &vpu_core2; }; cpus { @@ -184,6 +183,7 @@ dsp_reserved: dsp@92400000 { reg = <0 0x92400000 0 0x2000000>; no-map; + status = "disabled"; }; encoder_rpc: encoder-rpc@94400000 { @@ -317,6 +317,7 @@ }; #include "imx8qxp-ss-img.dtsi" +#include "imx8qxp-ss-vpu.dtsi" #include "imx8qxp-ss-adma.dtsi" #include "imx8qxp-ss-conn.dtsi" #include "imx8qxp-ss-lsio.dtsi" diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts index 2b9d47716f750c..9921ea13ab4892 100644 --- a/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts +++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts @@ -76,6 +76,7 @@ regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; gpio = <&gpio3 7 GPIO_ACTIVE_HIGH>; + off-on-delay-us = <12000>; enable-active-high; }; }; @@ -237,18 +238,19 @@ >; }; + /* need to config the SION for data and cmd pad, refer to ERR052021 */ pinctrl_usdhc1: usdhc1grp { fsl,pins = < MX93_PAD_SD1_CLK__USDHC1_CLK 0x15fe - MX93_PAD_SD1_CMD__USDHC1_CMD 0x13fe - MX93_PAD_SD1_DATA0__USDHC1_DATA0 0x13fe - MX93_PAD_SD1_DATA1__USDHC1_DATA1 0x13fe - MX93_PAD_SD1_DATA2__USDHC1_DATA2 0x13fe - MX93_PAD_SD1_DATA3__USDHC1_DATA3 0x13fe - MX93_PAD_SD1_DATA4__USDHC1_DATA4 0x13fe - MX93_PAD_SD1_DATA5__USDHC1_DATA5 0x13fe - MX93_PAD_SD1_DATA6__USDHC1_DATA6 0x13fe - MX93_PAD_SD1_DATA7__USDHC1_DATA7 0x13fe + MX93_PAD_SD1_CMD__USDHC1_CMD 0x400013fe + MX93_PAD_SD1_DATA0__USDHC1_DATA0 0x400013fe + MX93_PAD_SD1_DATA1__USDHC1_DATA1 0x400013fe + MX93_PAD_SD1_DATA2__USDHC1_DATA2 0x400013fe + MX93_PAD_SD1_DATA3__USDHC1_DATA3 0x400013fe + MX93_PAD_SD1_DATA4__USDHC1_DATA4 0x400013fe + MX93_PAD_SD1_DATA5__USDHC1_DATA5 0x400013fe + MX93_PAD_SD1_DATA6__USDHC1_DATA6 0x400013fe + MX93_PAD_SD1_DATA7__USDHC1_DATA7 0x400013fe MX93_PAD_SD1_STROBE__USDHC1_STROBE 0x15fe >; }; @@ -265,14 +267,15 @@ >; }; + /* need to config the SION for data and cmd pad, refer to ERR052021 */ pinctrl_usdhc2: usdhc2grp { fsl,pins = < MX93_PAD_SD2_CLK__USDHC2_CLK 0x15fe - MX93_PAD_SD2_CMD__USDHC2_CMD 0x13fe - MX93_PAD_SD2_DATA0__USDHC2_DATA0 0x13fe - MX93_PAD_SD2_DATA1__USDHC2_DATA1 0x13fe - MX93_PAD_SD2_DATA2__USDHC2_DATA2 0x13fe - MX93_PAD_SD2_DATA3__USDHC2_DATA3 0x13fe + MX93_PAD_SD2_CMD__USDHC2_CMD 0x400013fe + MX93_PAD_SD2_DATA0__USDHC2_DATA0 0x400013fe + MX93_PAD_SD2_DATA1__USDHC2_DATA1 0x400013fe + MX93_PAD_SD2_DATA2__USDHC2_DATA2 0x400013fe + MX93_PAD_SD2_DATA3__USDHC2_DATA3 0x400013fe MX93_PAD_SD2_VSELECT__USDHC2_VSELECT 0x51e >; }; diff --git a/arch/arm64/boot/dts/freescale/imx93-tqma9352-mba93xxca.dts b/arch/arm64/boot/dts/freescale/imx93-tqma9352-mba93xxca.dts new file mode 100644 index 00000000000000..af795ecf678b78 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx93-tqma9352-mba93xxca.dts @@ -0,0 +1,709 @@ +// SPDX-License-Identifier: (GPL-2.0-or-later OR MIT) +/* + * Copyright (c) 2022-2023 TQ-Systems GmbH , + * D-82229 Seefeld, Germany. + * Author: Markus Niebel + * Author: Alexander Stein + */ +/dts-v1/; + +#include +#include +#include +#include + +#include "imx93-tqma9352.dtsi" + +/{ + model = "TQ-Systems i.MX93 TQMa93xxLA/TQMa93xxCA on MBa93xxCA starter kit"; + compatible = "tq,imx93-tqma9352-mba93xxca", + "tq,imx93-tqma9352", "fsl,imx93"; + chassis-type = "embedded"; + + chosen { + stdout-path = &lpuart1; + }; + + aliases { + eeprom0 = &eeprom0; + rtc0 = &pcf85063; + rtc1 = &bbnsm_rtc; + }; + + backlight_lvds: backlight { + compatible = "pwm-backlight"; + pwms = <&tpm5 0 5000000 0>; + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <7>; + power-supply = <®_12v0>; + enable-gpios = <&expander2 2 GPIO_ACTIVE_HIGH>; + status = "disabled"; + }; + + fan0: pwm-fan { + compatible = "pwm-fan"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwmfan>; + fan-supply = <®_pwm_fan>; + #cooling-cells = <2>; + /* typical 25 kHz -> 40.000 nsec */ + pwms = <&tpm6 0 40000 PWM_POLARITY_INVERTED>; + cooling-levels = <0 32 64 128 196 240>; + pulses-per-revolution = <2>; + interrupt-parent = <&gpio2>; + interrupts = <9 IRQ_TYPE_EDGE_FALLING>; + status = "disabled"; + }; + + gpio-keys { + compatible = "gpio-keys"; + autorepeat; + + switch-a { + label = "switcha"; + linux,code = ; + gpios = <&expander0 6 GPIO_ACTIVE_LOW>; + wakeup-source; + }; + + switch-b { + label = "switchb"; + linux,code = ; + gpios = <&expander0 7 GPIO_ACTIVE_LOW>; + wakeup-source; + }; + }; + + gpio-leds { + compatible = "gpio-leds"; + + led-1 { + color = ; + function = LED_FUNCTION_STATUS; + gpios = <&expander2 6 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "default-on"; + }; + + led-2 { + color = ; + function = LED_FUNCTION_HEARTBEAT; + gpios = <&expander2 7 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + }; + }; + + iio-hwmon { + compatible = "iio-hwmon"; + io-channels = <&adc1 0>, <&adc1 1>, <&adc1 2>, <&adc1 3>; + }; + + reg_3v3: regulator-3v3 { + compatible = "regulator-fixed"; + regulator-name = "V_3V3_MB"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + reg_5v0: regulator-5v0 { + compatible = "regulator-fixed"; + regulator-name = "V_5V0_MB"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + + reg_12v0: regulator-12v0 { + compatible = "regulator-fixed"; + regulator-name = "V_12V"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + gpio = <&expander1 7 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_mpcie_1v5: regulator-mpcie-1v5 { + compatible = "regulator-fixed"; + regulator-name = "V_1V5_MPCIE"; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <1500000>; + gpio = <&expander0 2 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_mpcie_3v3: regulator-mpcie-3v3 { + compatible = "regulator-fixed"; + regulator-name = "V_3V3_MPCIE"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpio = <&expander0 3 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + reg_pwm_fan: regulator-pwm-fan { + compatible = "regulator-fixed"; + regulator-name = "FAN_PWR"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + gpio = <&expander0 0 GPIO_ACTIVE_HIGH>; + enable-active-high; + vin-supply = <®_12v0>; + }; + + thermal-zones { + cpu-thermal { + trips { + cpu_active0: trip-active0 { + temperature = <40000>; + hysteresis = <5000>; + type = "active"; + }; + + cpu_active1: trip-active1 { + temperature = <48000>; + hysteresis = <3000>; + type = "active"; + }; + + cpu_active2: trip-active2 { + temperature = <60000>; + hysteresis = <10000>; + type = "active"; + }; + }; + + cooling-maps { + map1 { + trip = <&cpu_active0>; + cooling-device = <&fan0 1 1>; + }; + + map2 { + trip = <&cpu_active1>; + cooling-device = <&fan0 2 2>; + }; + + map3 { + trip = <&cpu_active2>; + cooling-device = <&fan0 3 3>; + }; + }; + }; + }; +}; + +&adc1 { + status = "okay"; +}; + +&eqos { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_eqos>; + phy-mode = "rgmii-id"; + phy-handle = <ðphy_eqos>; + status = "okay"; + + mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + + ethphy_eqos: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_eqos_phy>; + reset-gpios = <&expander1 0 GPIO_ACTIVE_LOW>; + reset-assert-us = <500000>; + reset-deassert-us = <50000>; + interrupt-parent = <&gpio3>; + interrupts = <26 IRQ_TYPE_EDGE_FALLING>; + enet-phy-lane-no-swap; + ti,rx-internal-delay = ; + ti,tx-internal-delay = ; + ti,fifo-depth = ; + ti,dp83867-rxctrl-strap-quirk; + ti,clk-output-sel = ; + }; + }; +}; + +&fec { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fec>; + phy-mode = "rgmii-id"; + phy-handle = <ðphy_fec>; + fsl,magic-packet; + status = "okay"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = <5000000>; + + ethphy_fec: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fec_phy>; + reset-gpios = <&expander1 1 GPIO_ACTIVE_LOW>; + reset-assert-us = <500000>; + reset-deassert-us = <50000>; + interrupt-parent = <&gpio3>; + interrupts = <27 IRQ_TYPE_EDGE_FALLING>; + enet-phy-lane-no-swap; + ti,rx-internal-delay = ; + ti,tx-internal-delay = ; + ti,fifo-depth = ; + ti,dp83867-rxctrl-strap-quirk; + ti,clk-output-sel = ; + }; + }; +}; + +&flexcan1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flexcan1>; + xceiver-supply = <®_3v3>; + status = "okay"; +}; + +&flexcan2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flexcan2>; + xceiver-supply = <®_3v3>; + status = "okay"; +}; + +&gpio1 { + expander-irq-hog { + gpio-hog; + gpios = <12 GPIO_ACTIVE_LOW>; + input; + line-name = "PEX_INT#"; + }; + + tcpc-irq-hog { + gpio-hog; + gpios = <2 GPIO_ACTIVE_LOW>; + input; + line-name = "USB_C_ALERT#"; + }; +}; + +&lpi2c3 { + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = <400000>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_lpi2c3>; + pinctrl-1 = <&pinctrl_lpi2c3>; + status = "okay"; + + temperature-sensor@1c { + compatible = "nxp,se97b", "jedec,jc-42.4-temp"; + reg = <0x1c>; + }; + + eeprom2: eeprom@54 { + compatible = "nxp,se97b", "atmel,24c02"; + reg = <0x54>; + pagesize = <16>; + vcc-supply = <®_3v3>; + }; + + expander0: gpio@70 { + compatible = "nxp,pca9538"; + reg = <0x70>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pexp_irq>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gpio1>; + interrupts = <12 IRQ_TYPE_LEVEL_LOW>; + vcc-supply = <®_3v3>; + gpio-line-names = "FAN_PWR_EN", "MPCIE_WAKE#", + "MPCIE_1V5_EN", "MPCIE_3V3_EN", + "MPCIE_PERST#", "MPCIE_WDISABLE#", + "BUTTON_A#", "BUTTON_B#"; + + mpcie-wake-hog { + gpio-hog; + gpios = <1 GPIO_ACTIVE_LOW>; + input; + line-name = "MPCIE_WAKE#"; + }; + + /* + * Controls the mPCIE slot reset which is low active as + * reset signal. The output-low states, the signal is + * inactive, e.g. not in reset + */ + mpcie_rst_hog: mpcie-rst-hog { + gpio-hog; + gpios = <4 GPIO_ACTIVE_LOW>; + output-low; + line-name = "MPCIE_PERST#"; + }; + + /* + * Controls the mPCIE slot WDISABLE pin which is low active + * as disable signal. The output-low states, the signal is + * inactive, e.g. not disabled + */ + mpcie_wdisable_hog: mpcie-wdisable-hog { + gpio-hog; + gpios = <5 GPIO_ACTIVE_LOW>; + output-low; + line-name = "MPCIE_WDISABLE#"; + }; + }; + + expander1: gpio@71 { + compatible = "nxp,pca9538"; + reg = <0x71>; + gpio-controller; + #gpio-cells = <2>; + vcc-supply = <®_3v3>; + gpio-line-names = "ENET1_RESET#", "ENET2_RESET#", + "USB_RESET#", "", + "WLAN_PD#", "WLAN_W_DISABLE#", + "WLAN_PERST#", "12V_EN"; + + /* + * Controls the on board USB Hub reset which is low + * active as reset signal. The output-low states, the + * signal is inactive, e.g. no reset + */ + usb-reset-hog { + gpio-hog; + gpios = <2 GPIO_ACTIVE_LOW>; + output-low; + line-name = "USB_RESET#"; + }; + + /* + * Controls the WiFi card PD pin which is low active + * as power down signal. The output-high states, the signal + * is active, e.g. card is powered down + */ + wlan-pd-hog { + gpio-hog; + gpios = <4 GPIO_ACTIVE_LOW>; + output-high; + line-name = "WLAN_PD#"; + }; + + /* + * Controls the WiFi card disable pin which is low active + * as disable signal. The output-high states, the signal + * is active, e.g. card is disabled + */ + wlan-wdisable-hog { + gpio-hog; + gpios = <5 GPIO_ACTIVE_LOW>; + output-high; + line-name = "WLAN_W_DISABLE#"; + }; + + /* + * Controls the WiFi card reset pin which is low active + * as reset signal. The output-high states, the signal + * is active, e.g. card in reset + */ + wlan-perst-hog { + gpio-hog; + gpios = <6 GPIO_ACTIVE_LOW>; + output-high; + line-name = "WLAN_PERST#"; + }; + }; + + expander2: gpio@72 { + compatible = "nxp,pca9538"; + reg = <0x72>; + gpio-controller; + #gpio-cells = <2>; + vcc-supply = <®_3v3>; + gpio-line-names = "LCD_RESET#", "LCD_PWR_EN", + "LCD_BLT_EN", "DP_EN", + "MIPI_CSI_EN", "MIPI_CSI_RST#", + "USER_LED1", "USER_LED2"; + }; +}; + +&lpi2c5 { + #address-cells = <1>; + #size-cells = <0>; + clock-frequency = <400000>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_lpi2c5>; + pinctrl-1 = <&pinctrl_lpi2c5>; + status = "okay"; +}; + +&lpspi6 { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&pinctrl_lpspi6>; + pinctrl-1 = <&pinctrl_lpspi6>; + status = "okay"; +}; + +&lpuart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; + status = "okay"; +}; + +&lpuart2 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart2>; + linux,rs485-enabled-at-boot-time; + status = "okay"; +}; + +/* disabled per default, console for M33 */ +&lpuart3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart3>; + status = "disabled"; +}; + +&lpuart6 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart6>; + status = "okay"; +}; + +&lpuart8 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart8>; + status = "okay"; +}; + +&tpm5 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_tpm5>; +}; + +&tpm6 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_tpm6>; + status = "okay"; +}; + +&usdhc2 { + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc2_hs>, <&pinctrl_usdhc2_gpio>; + pinctrl-1 = <&pinctrl_usdhc2_uhs>, <&pinctrl_usdhc2_gpio>; + pinctrl-2 = <&pinctrl_usdhc2_uhs>, <&pinctrl_usdhc2_gpio>; + cd-gpios = <&gpio3 0 GPIO_ACTIVE_LOW>; + vmmc-supply = <®_usdhc2_vmmc>; + bus-width = <4>; + no-sdio; + no-mmc; + disable-wp; + status = "okay"; +}; + +&iomuxc { + pinctrl_eqos: eqosgrp { + fsl,pins = < + /* PD | FSEL_2 | DSE X4 */ + MX93_PAD_ENET1_MDC__ENET_QOS_MDC 0x51e + MX93_PAD_ENET1_MDIO__ENET_QOS_MDIO 0x4000051e + /* PD | FSEL_2 | DSE X6 */ + MX93_PAD_ENET1_RD0__ENET_QOS_RGMII_RD0 0x57e + MX93_PAD_ENET1_RD1__ENET_QOS_RGMII_RD1 0x57e + MX93_PAD_ENET1_RD2__ENET_QOS_RGMII_RD2 0x57e + MX93_PAD_ENET1_RD3__ENET_QOS_RGMII_RD3 0x57e + /* PD | FSEL_3 | DSE X6 */ + MX93_PAD_ENET1_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK 0x5fe + MX93_PAD_ENET1_RX_CTL__ENET_QOS_RGMII_RX_CTL 0x57e + /* PD | FSEL_2 | DSE X4 */ + MX93_PAD_ENET1_TD0__ENET_QOS_RGMII_TD0 0x51e + MX93_PAD_ENET1_TD1__ENET_QOS_RGMII_TD1 0x51e + MX93_PAD_ENET1_TD2__ENET_QOS_RGMII_TD2 0x51e + MX93_PAD_ENET1_TD3__ENET_QOS_RGMII_TD3 0x51e + MX93_PAD_ENET1_TX_CTL__ENET_QOS_RGMII_TX_CTL 0x51e + /* PD | FSEL_3 | DSE X3 */ + MX93_PAD_ENET1_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK 0x58e + >; + }; + + pinctrl_eqos_phy: eqosphygrp { + fsl,pins = < + MX93_PAD_CCM_CLKO1__GPIO3_IO26 0x1306 + >; + }; + + pinctrl_fec: fecgrp { + fsl,pins = < + /* PD | FSEL_2 | DSE X4 */ + MX93_PAD_ENET2_MDC__ENET1_MDC 0x51e + MX93_PAD_ENET2_MDIO__ENET1_MDIO 0x4000051e + /* PD | FSEL_2 | DSE X6 */ + MX93_PAD_ENET2_RD0__ENET1_RGMII_RD0 0x57e + MX93_PAD_ENET2_RD1__ENET1_RGMII_RD1 0x57e + MX93_PAD_ENET2_RD2__ENET1_RGMII_RD2 0x57e + MX93_PAD_ENET2_RD3__ENET1_RGMII_RD3 0x57e + /* PD | FSEL_3 | DSE X6 */ + MX93_PAD_ENET2_RXC__ENET1_RGMII_RXC 0x5fe + MX93_PAD_ENET2_RX_CTL__ENET1_RGMII_RX_CTL 0x57e + /* PD | FSEL_2 | DSE X4 */ + MX93_PAD_ENET2_TD0__ENET1_RGMII_TD0 0x51e + MX93_PAD_ENET2_TD1__ENET1_RGMII_TD1 0x51e + MX93_PAD_ENET2_TD2__ENET1_RGMII_TD2 0x51e + MX93_PAD_ENET2_TD3__ENET1_RGMII_TD3 0x51e + MX93_PAD_ENET2_TX_CTL__ENET1_RGMII_TX_CTL 0x51e + /* PD | FSEL_3 | DSE X3 */ + MX93_PAD_ENET2_TXC__ENET1_RGMII_TXC 0x58e + >; + }; + + pinctrl_fec_phy: fecphygrp { + fsl,pins = < + MX93_PAD_CCM_CLKO2__GPIO3_IO27 0x1306 + >; + }; + + pinctrl_flexcan1: flexcan1grp { + fsl,pins = < + MX93_PAD_PDM_BIT_STREAM0__CAN1_RX 0x139e + MX93_PAD_PDM_CLK__CAN1_TX 0x139e + >; + }; + + pinctrl_flexcan2: flexcan2grp { + fsl,pins = < + MX93_PAD_GPIO_IO25__CAN2_TX 0x139e + MX93_PAD_GPIO_IO27__CAN2_RX 0x139e + >; + }; + + pinctrl_lpi2c3: lpi2c3grp { + fsl,pins = < + MX93_PAD_GPIO_IO28__LPI2C3_SDA 0x40000b9e + MX93_PAD_GPIO_IO29__LPI2C3_SCL 0x40000b9e + >; + }; + + pinctrl_lpi2c5: lpi2c5grp { + fsl,pins = < + MX93_PAD_GPIO_IO22__LPI2C5_SDA 0x40000b9e + MX93_PAD_GPIO_IO23__LPI2C5_SCL 0x40000b9e + >; + }; + + pinctrl_lpspi6: lpspi6grp { + fsl,pins = < + MX93_PAD_GPIO_IO00__LPSPI6_PCS0 0x3fe + MX93_PAD_GPIO_IO01__LPSPI6_SIN 0x3fe + MX93_PAD_GPIO_IO02__LPSPI6_SOUT 0x3fe + MX93_PAD_GPIO_IO03__LPSPI6_SCK 0x3fe + >; + }; + + pinctrl_pexp_irq: pexpirqgrp { + fsl,pins = < + MX93_PAD_SAI1_TXC__GPIO1_IO12 0x1306 + >; + }; + + pinctrl_pwmfan: pwmfangrp { + fsl,pins = < + MX93_PAD_GPIO_IO09__GPIO2_IO09 0x1306 + >; + }; + + pinctrl_tpm5: tpm5grp { + fsl,pins = < + MX93_PAD_GPIO_IO06__TPM5_CH0 0x57e + >; + }; + + pinctrl_tpm6: tpm6grp { + fsl,pins = < + MX93_PAD_GPIO_IO08__TPM6_CH0 0x57e + >; + }; + + pinctrl_typec: typecgrp { + fsl,pins = < + MX93_PAD_I2C2_SCL__GPIO1_IO02 0x1306 + >; + }; + + pinctrl_uart1: uart1grp { + fsl,pins = < + MX93_PAD_UART1_RXD__LPUART1_RX 0x31e + MX93_PAD_UART1_TXD__LPUART1_TX 0x31e + >; + }; + + pinctrl_uart2: uart2grp { + fsl,pins = < + MX93_PAD_UART2_TXD__LPUART2_TX 0x31e + MX93_PAD_UART2_RXD__LPUART2_RX 0x31e + MX93_PAD_SAI1_TXD0__LPUART2_RTS_B 0x51e + >; + }; + + pinctrl_uart3: uart3grp { + fsl,pins = < + MX93_PAD_GPIO_IO14__LPUART3_TX 0x31e + MX93_PAD_GPIO_IO15__LPUART3_RX 0x31e + >; + }; + + pinctrl_uart6: uart6grp { + fsl,pins = < + MX93_PAD_GPIO_IO04__LPUART6_TX 0x31e + MX93_PAD_GPIO_IO05__LPUART6_RX 0x31e + >; + }; + + pinctrl_uart8: uart8grp { + fsl,pins = < + MX93_PAD_GPIO_IO12__LPUART8_TX 0x31e + MX93_PAD_GPIO_IO13__LPUART8_RX 0x31e + >; + }; + + pinctrl_usdhc2_gpio: usdhc2gpiogrp { + fsl,pins = < + MX93_PAD_SD2_CD_B__GPIO3_IO00 0x31e + >; + }; + + pinctrl_usdhc2_hs: usdhc2hsgrp { + fsl,pins = < + /* HYS | PD | PU | FSEL_3 | DSE X5 */ + MX93_PAD_SD2_CLK__USDHC2_CLK 0x17be + /* HYS | PD | PU | FSEL_3 | DSE X4 */ + MX93_PAD_SD2_CMD__USDHC2_CMD 0x139e + /* HYS | PD | PU | FSEL_3 | DSE X3 */ + MX93_PAD_SD2_DATA0__USDHC2_DATA0 0x138e + MX93_PAD_SD2_DATA1__USDHC2_DATA1 0x138e + MX93_PAD_SD2_DATA2__USDHC2_DATA2 0x138e + MX93_PAD_SD2_DATA3__USDHC2_DATA3 0x138e + /* PD | PU | FSEL_2 | DSE X3 */ + MX93_PAD_SD2_VSELECT__USDHC2_VSELECT 0x50e + >; + }; + + pinctrl_usdhc2_uhs: usdhc2uhsgrp { + fsl,pins = < + /* HYS | PD | PU | FSEL_3 | DSE X6 */ + MX93_PAD_SD2_CLK__USDHC2_CLK 0x17fe + /* HYS | PD | PU | FSEL_3 | DSE X4 */ + MX93_PAD_SD2_CMD__USDHC2_CMD 0x139e + MX93_PAD_SD2_DATA0__USDHC2_DATA0 0x139e + MX93_PAD_SD2_DATA1__USDHC2_DATA1 0x139e + MX93_PAD_SD2_DATA2__USDHC2_DATA2 0x139e + MX93_PAD_SD2_DATA3__USDHC2_DATA3 0x139e + /* PD | PU | FSEL_2 | DSE X3 */ + MX93_PAD_SD2_VSELECT__USDHC2_VSELECT 0x50e + >; + }; +}; diff --git a/arch/arm64/boot/dts/freescale/imx93-tqma9352-mba93xxla.dts b/arch/arm64/boot/dts/freescale/imx93-tqma9352-mba93xxla.dts index 3c5c67ebee5d30..eb3f4cfb69863e 100644 --- a/arch/arm64/boot/dts/freescale/imx93-tqma9352-mba93xxla.dts +++ b/arch/arm64/boot/dts/freescale/imx93-tqma9352-mba93xxla.dts @@ -18,6 +18,7 @@ model = "TQ-Systems i.MX93 TQMa93xxLA on MBa93xxLA SBC"; compatible = "tq,imx93-tqma9352-mba93xxla", "tq,imx93-tqma9352", "fsl,imx93"; + chassis-type = "embedded"; chosen { stdout-path = &lpuart1; diff --git a/arch/arm64/boot/dts/freescale/imx93.dtsi b/arch/arm64/boot/dts/freescale/imx93.dtsi index 34c0540276d166..8f2e7c42ad6e83 100644 --- a/arch/arm64/boot/dts/freescale/imx93.dtsi +++ b/arch/arm64/boot/dts/freescale/imx93.dtsi @@ -171,6 +171,18 @@ status = "disabled"; }; + mqs1: mqs1 { + compatible = "fsl,imx93-mqs"; + gpr = <&aonmix_ns_gpr>; + status = "disabled"; + }; + + mqs2: mqs2 { + compatible = "fsl,imx93-mqs"; + gpr = <&wakeupmix_gpr>; + status = "disabled"; + }; + soc@0 { compatible = "simple-bus"; #address-cells = <1>; @@ -282,6 +294,19 @@ status = "disabled"; }; + i3c1: i3c-master@44330000 { + compatible = "silvaco,i3c-master-v1"; + reg = <0x44330000 0x10000>; + interrupts = ; + #address-cells = <3>; + #size-cells = <0>; + clocks = <&clk IMX93_CLK_BUS_AON>, + <&clk IMX93_CLK_I3C1_GATE>, + <&clk IMX93_CLK_I3C1_SLOW>; + clock-names = "pclk", "fast_clk", "slow_clk"; + status = "disabled"; + }; + lpi2c1: i2c@44340000 { compatible = "fsl,imx93-lpi2c", "fsl,imx7ulp-lpi2c"; reg = <0x44340000 0x10000>; @@ -367,6 +392,19 @@ status = "disabled"; }; + sai1: sai@443b0000 { + compatible = "fsl,imx93-sai"; + reg = <0x443b0000 0x10000>; + interrupts = ; + clocks = <&clk IMX93_CLK_SAI1_IPG>, <&clk IMX93_CLK_DUMMY>, + <&clk IMX93_CLK_SAI1_GATE>, <&clk IMX93_CLK_DUMMY>, + <&clk IMX93_CLK_DUMMY>; + clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3"; + dmas = <&edma1 22 0 1>, <&edma1 21 0 0>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + iomuxc: pinctrl@443c0000 { compatible = "fsl,imx93-iomuxc"; reg = <0x443c0000 0x10000>; @@ -395,6 +433,8 @@ #clock-cells = <1>; clocks = <&osc_32k>, <&osc_24m>, <&clk_ext1>; clock-names = "osc_32k", "osc_24m", "clk_ext1"; + assigned-clocks = <&clk IMX93_CLK_AUDIO_PLL>; + assigned-clock-rates = <393216000>; status = "okay"; }; @@ -422,9 +462,10 @@ }; }; - anatop: anatop@44480000 { - compatible = "fsl,imx93-anatop", "syscon"; + clock-controller@44480000 { + compatible = "fsl,imx93-anatop"; reg = <0x44480000 0x2000>; + #clock-cells = <1>; }; tmu: tmu@44482000 { @@ -447,6 +488,21 @@ #thermal-sensor-cells = <1>; }; + micfil: micfil@44520000 { + compatible = "fsl,imx93-micfil"; + reg = <0x44520000 0x10000>; + interrupts = , + , + , + ; + clocks = <&clk IMX93_CLK_PDM_IPG>, + <&clk IMX93_CLK_PDM_GATE>, + <&clk IMX93_CLK_AUDIO_PLL>; + clock-names = "ipg_clk", "ipg_clk_app", "pll8k"; + dmas = <&edma1 29 0 5>; + dma-names = "rx"; + status = "disabled"; + }; adc1: adc@44530000 { compatible = "nxp,imx93-adc"; @@ -473,7 +529,6 @@ compatible = "fsl,imx93-edma4"; reg = <0x42000000 0x210000>; #dma-cells = <3>; - shared-interrupt; dma-channels = <64>; interrupts = , , @@ -616,6 +671,19 @@ status = "disabled"; }; + i3c2: i3c-master@42520000 { + compatible = "silvaco,i3c-master-v1"; + reg = <0x42520000 0x10000>; + interrupts = ; + #address-cells = <3>; + #size-cells = <0>; + clocks = <&clk IMX93_CLK_BUS_WAKEUP>, + <&clk IMX93_CLK_I3C2_GATE>, + <&clk IMX93_CLK_I3C2_SLOW>; + clock-names = "pclk", "fast_clk", "slow_clk"; + status = "disabled"; + }; + lpi2c3: i2c@42530000 { compatible = "fsl,imx93-lpi2c", "fsl,imx7ulp-lpi2c"; reg = <0x42530000 0x10000>; @@ -738,6 +806,51 @@ status = "disabled"; }; + sai2: sai@42650000 { + compatible = "fsl,imx93-sai"; + reg = <0x42650000 0x10000>; + interrupts = ; + clocks = <&clk IMX93_CLK_SAI2_IPG>, <&clk IMX93_CLK_DUMMY>, + <&clk IMX93_CLK_SAI2_GATE>, <&clk IMX93_CLK_DUMMY>, + <&clk IMX93_CLK_DUMMY>; + clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3"; + dmas = <&edma2 59 0 1>, <&edma2 58 0 0>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + + sai3: sai@42660000 { + compatible = "fsl,imx93-sai"; + reg = <0x42660000 0x10000>; + interrupts = ; + clocks = <&clk IMX93_CLK_SAI3_IPG>, <&clk IMX93_CLK_DUMMY>, + <&clk IMX93_CLK_SAI3_GATE>, <&clk IMX93_CLK_DUMMY>, + <&clk IMX93_CLK_DUMMY>; + clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3"; + dmas = <&edma2 61 0 1>, <&edma2 60 0 0>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + + xcvr: xcvr@42680000 { + compatible = "fsl,imx93-xcvr"; + reg = <0x42680000 0x800>, + <0x42680800 0x400>, + <0x42680c00 0x080>, + <0x42680e00 0x080>; + reg-names = "ram", "regs", "rxfifo", "txfifo"; + interrupts = , + ; + clocks = <&clk IMX93_CLK_BUS_WAKEUP>, + <&clk IMX93_CLK_SPDIF_GATE>, + <&clk IMX93_CLK_DUMMY>, + <&clk IMX93_CLK_AUD_XCVR_GATE>; + clock-names = "ipg", "phy", "spba", "pll_ipg"; + dmas = <&edma2 65 0 1>, <&edma2 66 0 0>; + dma-names = "rx", "tx"; + status = "disabled"; + }; + lpuart7: serial@42690000 { compatible = "fsl,imx93-lpuart", "fsl,imx8ulp-lpuart", "fsl,imx7ulp-lpuart"; reg = <0x42690000 0x1000>; @@ -755,7 +868,7 @@ interrupts = ; clocks = <&clk IMX93_CLK_LPUART8_GATE>; clock-names = "ipg"; - dmas = <&edma2 90 0 1>, <&edma2 89 0 0>; + dmas = <&edma2 90 0 1>, <&edma2 89 0 0>; dma-names = "rx", "tx"; status = "disabled"; }; @@ -874,7 +987,7 @@ <&clk IMX93_CLK_USDHC1_GATE>; clock-names = "ipg", "ahb", "per"; bus-width = <8>; - fsl,tuning-start-tap = <20>; + fsl,tuning-start-tap = <1>; fsl,tuning-step = <2>; status = "disabled"; }; @@ -888,7 +1001,7 @@ <&clk IMX93_CLK_USDHC2_GATE>; clock-names = "ipg", "ahb", "per"; bus-width = <4>; - fsl,tuning-start-tap = <20>; + fsl,tuning-start-tap = <1>; fsl,tuning-step = <2>; status = "disabled"; }; @@ -951,7 +1064,7 @@ <&clk IMX93_CLK_USDHC3_GATE>; clock-names = "ipg", "ahb", "per"; bus-width = <4>; - fsl,tuning-start-tap = <20>; + fsl,tuning-start-tap = <1>; fsl,tuning-step = <2>; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/hisilicon/hikey970-pmic.dtsi b/arch/arm64/boot/dts/hisilicon/hikey970-pmic.dtsi index 970047f2dabd51..299c4ab630e850 100644 --- a/arch/arm64/boot/dts/hisilicon/hikey970-pmic.dtsi +++ b/arch/arm64/boot/dts/hisilicon/hikey970-pmic.dtsi @@ -10,10 +10,9 @@ / { spmi: spmi@fff24000 { compatible = "hisilicon,kirin970-spmi-controller"; + reg = <0x0 0xfff24000 0x0 0x1000>; #address-cells = <2>; #size-cells = <0>; - status = "okay"; - reg = <0x0 0xfff24000 0x0 0x1000>; hisilicon,spmi-channel = <2>; pmic: pmic@0 { @@ -25,9 +24,6 @@ gpios = <&gpio28 0 0>; regulators { - #address-cells = <1>; - #size-cells = <0>; - ldo3: ldo3 { /* HDMI */ regulator-name = "ldo3"; regulator-min-microvolt = <1500000>; diff --git a/arch/arm64/boot/dts/intel/socfpga_agilex.dtsi b/arch/arm64/boot/dts/intel/socfpga_agilex.dtsi index d3adb6a130aef4..76aafa172eb013 100644 --- a/arch/arm64/boot/dts/intel/socfpga_agilex.dtsi +++ b/arch/arm64/boot/dts/intel/socfpga_agilex.dtsi @@ -60,6 +60,25 @@ }; }; + firmware { + svc { + compatible = "intel,agilex-svc"; + method = "smc"; + memory-region = <&service_reserved>; + + fpga_mgr: fpga-mgr { + compatible = "intel,agilex-soc-fpga-mgr"; + }; + }; + }; + + fpga-region { + compatible = "fpga-region"; + #address-cells = <0x2>; + #size-cells = <0x2>; + fpga-mgr = <&fpga_mgr>; + }; + pmu { compatible = "arm,armv8-pmuv3"; interrupts = , @@ -130,7 +149,7 @@ compatible = "usb-nop-xceiv"; }; - soc { + soc@0 { #address-cells = <1>; #size-cells = <1>; compatible = "simple-bus"; @@ -138,13 +157,6 @@ interrupt-parent = <&intc>; ranges = <0 0 0 0xffffffff>; - base_fpga_region { - #address-cells = <0x2>; - #size-cells = <0x2>; - compatible = "fpga-region"; - fpga-mgr = <&fpga_mgr>; - }; - clkmgr: clock-controller@ffd10000 { compatible = "intel,agilex-clkmgr"; reg = <0xffd10000 0x1000>; @@ -368,7 +380,7 @@ pinctrl-single,function-mask = <0x0000000f>; }; - pinctrl1: pinconf@ffd13100 { + pinctrl1: pinctrl@ffd13100 { compatible = "pinctrl-single"; #pinctrl-cells = <1>; reg = <0xffd13100 0x20>; @@ -659,17 +671,5 @@ status = "disabled"; }; - - firmware { - svc { - compatible = "intel,agilex-svc"; - method = "smc"; - memory-region = <&service_reserved>; - - fpga_mgr: fpga-mgr { - compatible = "intel,agilex-soc-fpga-mgr"; - }; - }; - }; }; }; diff --git a/arch/arm64/boot/dts/intel/socfpga_agilex5.dtsi b/arch/arm64/boot/dts/intel/socfpga_agilex5.dtsi index dcdaf706495336..d66d425e45b7d9 100644 --- a/arch/arm64/boot/dts/intel/socfpga_agilex5.dtsi +++ b/arch/arm64/boot/dts/intel/socfpga_agilex5.dtsi @@ -73,7 +73,7 @@ ranges; #interrupt-cells = <3>; #address-cells = <2>; - #size-cells =<2>; + #size-cells = <2>; interrupt-controller; #redistributor-regions = <1>; redistributor-stride = <0x0 0x20000>; @@ -315,7 +315,7 @@ num-cs = <4>; clocks = <&clkmgr AGILEX5_L4_MAIN_CLK>; dmas = <&dmac0 2>, <&dmac0 3>; - dma-names ="tx", "rx"; + dma-names = "tx", "rx"; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/intel/socfpga_agilex_n6000.dts b/arch/arm64/boot/dts/intel/socfpga_agilex_n6000.dts index 1a32840c74e094..d22de06e983961 100644 --- a/arch/arm64/boot/dts/intel/socfpga_agilex_n6000.dts +++ b/arch/arm64/boot/dts/intel/socfpga_agilex_n6000.dts @@ -26,7 +26,7 @@ reg = <0 0x80000000 0 0>; }; - soc { + soc@0 { bus@80000000 { compatible = "simple-bus"; reg = <0x80000000 0x60000000>, diff --git a/arch/arm64/boot/dts/intel/socfpga_agilex_socdk.dts b/arch/arm64/boot/dts/intel/socfpga_agilex_socdk.dts index 053690657675b6..ad99aefeb185a1 100644 --- a/arch/arm64/boot/dts/intel/socfpga_agilex_socdk.dts +++ b/arch/arm64/boot/dts/intel/socfpga_agilex_socdk.dts @@ -113,8 +113,6 @@ spi-max-frequency = <100000000>; m25p,fast-read; - cdns,page-size = <256>; - cdns,block-size = <16>; cdns,read-delay = <2>; cdns,tshsl-ns = <50>; cdns,tsd2d-ns = <50>; diff --git a/arch/arm64/boot/dts/intel/socfpga_n5x_socdk.dts b/arch/arm64/boot/dts/intel/socfpga_n5x_socdk.dts index 5ddfdff37c25c0..2d70a92c20900e 100644 --- a/arch/arm64/boot/dts/intel/socfpga_n5x_socdk.dts +++ b/arch/arm64/boot/dts/intel/socfpga_n5x_socdk.dts @@ -25,12 +25,11 @@ reg = <0 0x80000000 0 0>; }; - soc { + soc@0 { sdram_edac: memory-controller@f87f8000 { compatible = "snps,ddrc-3.80a"; reg = <0xf87f8000 0x400>; interrupts = <0 175 4>; - status = "okay"; }; }; }; @@ -91,8 +90,6 @@ spi-max-frequency = <100000000>; m25p,fast-read; - cdns,page-size = <256>; - cdns,block-size = <16>; cdns,read-delay = <2>; cdns,tshsl-ns = <50>; cdns,tsd2d-ns = <50>; diff --git a/arch/arm64/boot/dts/marvell/Makefile b/arch/arm64/boot/dts/marvell/Makefile index 79ac09b58a8995..99b8cb3c49e11c 100644 --- a/arch/arm64/boot/dts/marvell/Makefile +++ b/arch/arm64/boot/dts/marvell/Makefile @@ -26,4 +26,5 @@ dtb-$(CONFIG_ARCH_MVEBU) += cn9132-db.dtb dtb-$(CONFIG_ARCH_MVEBU) += cn9132-db-B.dtb dtb-$(CONFIG_ARCH_MVEBU) += cn9130-crb-A.dtb dtb-$(CONFIG_ARCH_MVEBU) += cn9130-crb-B.dtb +dtb-$(CONFIG_ARCH_MVEBU) += ac5x-rd-carrier-cn9131.dtb dtb-$(CONFIG_ARCH_MVEBU) += ac5-98dx35xx-rd.dtb diff --git a/arch/arm64/boot/dts/marvell/ac5x-rd-carrier-cn9131.dts b/arch/arm64/boot/dts/marvell/ac5x-rd-carrier-cn9131.dts new file mode 100644 index 00000000000000..2a0b070000894e --- /dev/null +++ b/arch/arm64/boot/dts/marvell/ac5x-rd-carrier-cn9131.dts @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) 2023 Marvell International Ltd. + * + * Device tree for the AC5X RD Type 7 Com Express carrier board, + * Utilizing the CN913x COM Express CPU module board. + * This specific carrier board in this mode of operation (external) + * only maintains a PCIe link with the CPU module, + * which does not require any special DTS definitions. + * + * AC5X RD works here in external mode (switch selectable at the back of the + * board), and connect via an external cable a kit + * which would allow it to use an external CN9131 CPU COM Express module, + * mounted on top of an interposer kit. + * + * So in this case, once the switch is set to external mode as explained above, + * the AC5X RD becomes part of the carrier solution. + * + * When the board boots in the external CPU mode, the internal CPU is disabled, + * and only the switch portion of the SOC acts as a PCIe end-point, Hence there + * is no need to describe this internal (disabled CPU) in the device tree. + * + * There is no CPU booting in this mode on the carrier, only on the + * CN9131 COM Express CPU module. + * What runs the Linux is the CN9131 on the COM Express CPU module, + * And it accesses the switch end-point on the AC5X RD portion of the carrier + * via PCIe. + */ + +#include "cn9131-db-comexpress.dtsi" +#include "ac5x-rd-carrier.dtsi" + +/ { + model = "Marvell Armada AC5X RD COM EXPRESS type 7 carrier board with CN9131 CPU module"; + compatible = "marvell,cn9131-ac5x-carrier", "marvell,rd-ac5x-carrier", + "marvell,cn9131-cpu-module", "marvell,cn9131", + "marvell,armada-ap807-quad", "marvell,armada-ap807"; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x0 0x2 0x00000000>; + }; + +}; diff --git a/arch/arm64/boot/dts/marvell/ac5x-rd-carrier.dtsi b/arch/arm64/boot/dts/marvell/ac5x-rd-carrier.dtsi new file mode 100644 index 00000000000000..f98629abb58b1e --- /dev/null +++ b/arch/arm64/boot/dts/marvell/ac5x-rd-carrier.dtsi @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) 2023 Marvell International Ltd. + * + * Device tree for the AC5X RD Type 7 Com Express carrier board, + * This specific board in external mode (see below) only maintains + * a PCIe link with the COM Express CPU module, which does not + * require any special DTS definitions. + * + * AC5X RD can either work as you would expect, as a complete standalone + * box using the internal CPU, or you can move the switch on the back of + * the box to "external" mode, and connect via an external cable a kit + * which would allow it to use an external CPU COM Express module, + * mounted on top of an interposer kit. + * + * So in this case, once the switch is set to external mode as explained above, + * the AC5X RD becomes part of the carrier solution. + * This is a development/reference solution, not a full commercial solution, + * hence it was designed with the flexibility to be configured in different + * modes of operation. + * + * When the board boots in the external CPU mode, the internal CPU is disabled, + * and only the switch portion of the SOC acts as a PCIe end-point, Hence there + * is no need to describe this internal (disabled CPU) in the device tree. + * + * There is no CPU booting in this mode on the carrier, + * only on the COM Express CPU module. + */ + +/ { + model = "Marvell Armada AC5X RD COM EXPRESS type 7 carrier board"; + compatible = "marvell,rd-ac5x-carrier"; + +}; diff --git a/arch/arm64/boot/dts/marvell/armada-3720-espressobin-ultra.dts b/arch/arm64/boot/dts/marvell/armada-3720-espressobin-ultra.dts index f9abef8dcc9489..870bb380a40a67 100644 --- a/arch/arm64/boot/dts/marvell/armada-3720-espressobin-ultra.dts +++ b/arch/arm64/boot/dts/marvell/armada-3720-espressobin-ultra.dts @@ -126,32 +126,32 @@ reset-gpios = <&gpiosb 23 GPIO_ACTIVE_LOW>; - ports { - switch0port1: port@1 { + ethernet-ports { + switch0port1: ethernet-port@1 { reg = <1>; label = "lan0"; phy-handle = <&switch0phy0>; }; - switch0port2: port@2 { + switch0port2: ethernet-port@2 { reg = <2>; label = "lan1"; phy-handle = <&switch0phy1>; }; - switch0port3: port@3 { + switch0port3: ethernet-port@3 { reg = <3>; label = "lan2"; phy-handle = <&switch0phy2>; }; - switch0port4: port@4 { + switch0port4: ethernet-port@4 { reg = <4>; label = "lan3"; phy-handle = <&switch0phy3>; }; - switch0port5: port@5 { + switch0port5: ethernet-port@5 { reg = <5>; label = "wan"; phy-handle = <&extphy>; @@ -160,7 +160,7 @@ }; mdio { - switch0phy3: switch0phy3@14 { + switch0phy3: ethernet-phy@14 { reg = <0x14>; }; }; diff --git a/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi b/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi index 49cbdb55b4b366..fed2dcecb323f0 100644 --- a/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi +++ b/arch/arm64/boot/dts/marvell/armada-3720-espressobin.dtsi @@ -145,19 +145,17 @@ }; &mdio { - switch0: switch0@1 { + switch0: ethernet-switch@1 { compatible = "marvell,mv88e6085"; - #address-cells = <1>; - #size-cells = <0>; reg = <1>; dsa,member = <0 0>; - ports { + ethernet-ports { #address-cells = <1>; #size-cells = <0>; - switch0port0: port@0 { + switch0port0: ethernet-port@0 { reg = <0>; label = "cpu"; ethernet = <ð0>; @@ -168,19 +166,19 @@ }; }; - switch0port1: port@1 { + switch0port1: ethernet-port@1 { reg = <1>; label = "wan"; phy-handle = <&switch0phy0>; }; - switch0port2: port@2 { + switch0port2: ethernet-port@2 { reg = <2>; label = "lan0"; phy-handle = <&switch0phy1>; }; - switch0port3: port@3 { + switch0port3: ethernet-port@3 { reg = <3>; label = "lan1"; phy-handle = <&switch0phy2>; @@ -192,13 +190,13 @@ #address-cells = <1>; #size-cells = <0>; - switch0phy0: switch0phy0@11 { + switch0phy0: ethernet-phy@11 { reg = <0x11>; }; - switch0phy1: switch0phy1@12 { + switch0phy1: ethernet-phy@12 { reg = <0x12>; }; - switch0phy2: switch0phy2@13 { + switch0phy2: ethernet-phy@13 { reg = <0x13>; }; }; diff --git a/arch/arm64/boot/dts/marvell/armada-3720-gl-mv1000.dts b/arch/arm64/boot/dts/marvell/armada-3720-gl-mv1000.dts index b1b45b4fa9d4a3..63fbc83521616a 100644 --- a/arch/arm64/boot/dts/marvell/armada-3720-gl-mv1000.dts +++ b/arch/arm64/boot/dts/marvell/armada-3720-gl-mv1000.dts @@ -152,31 +152,29 @@ }; &mdio { - switch0: switch0@1 { + switch0: ethernet-switch@1 { compatible = "marvell,mv88e6085"; - #address-cells = <1>; - #size-cells = <0>; reg = <1>; dsa,member = <0 0>; - ports: ports { + ports: ethernet-ports { #address-cells = <1>; #size-cells = <0>; - port@0 { + ethernet-port@0 { reg = <0>; label = "cpu"; ethernet = <ð0>; }; - port@1 { + ethernet-port@1 { reg = <1>; label = "wan"; phy-handle = <&switch0phy0>; }; - port@2 { + ethernet-port@2 { reg = <2>; label = "lan0"; phy-handle = <&switch0phy1>; @@ -185,7 +183,7 @@ nvmem-cell-names = "mac-address"; }; - port@3 { + ethernet-port@3 { reg = <3>; label = "lan1"; phy-handle = <&switch0phy2>; @@ -199,13 +197,13 @@ #address-cells = <1>; #size-cells = <0>; - switch0phy0: switch0phy0@11 { + switch0phy0: ethernet-phy@11 { reg = <0x11>; }; - switch0phy1: switch0phy1@12 { + switch0phy1: ethernet-phy@12 { reg = <0x12>; }; - switch0phy2: switch0phy2@13 { + switch0phy2: ethernet-phy@13 { reg = <0x13>; }; }; diff --git a/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts b/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts index 9eab2bb221348a..f1a9f223435919 100644 --- a/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts +++ b/arch/arm64/boot/dts/marvell/armada-3720-turris-mox.dts @@ -130,7 +130,7 @@ compatible = "microchip,mcp7940x"; reg = <0x6f>; interrupt-parent = <&gpiosb>; - interrupts = <5 0>; /* GPIO2_5 */ + interrupts = <5 IRQ_TYPE_EDGE_FALLING>; /* GPIO2_5 */ }; }; @@ -304,9 +304,15 @@ reg = <1>; }; - /* switch nodes are enabled by U-Boot if modules are present */ + /* + * NOTE: switch nodes are enabled by U-Boot if modules are present + * DO NOT change this node name (switch0@10) even if it is not following + * conventions! Deployed U-Boot binaries are explicitly looking for + * this node in order to augment the device tree! + * Also do not touch the "ports" or "port@n" nodes. These are also ABI. + */ switch0@10 { - compatible = "marvell,mv88e6190"; + compatible = "marvell,turris-mox-mv88e6190", "marvell,mv88e6190"; reg = <0x10>; dsa,member = <0 0>; interrupt-parent = <&moxtet>; @@ -317,35 +323,35 @@ #address-cells = <1>; #size-cells = <0>; - switch0phy1: switch0phy1@1 { + switch0phy1: ethernet-phy@1 { reg = <0x1>; }; - switch0phy2: switch0phy2@2 { + switch0phy2: ethernet-phy@2 { reg = <0x2>; }; - switch0phy3: switch0phy3@3 { + switch0phy3: ethernet-phy@3 { reg = <0x3>; }; - switch0phy4: switch0phy4@4 { + switch0phy4: ethernet-phy@4 { reg = <0x4>; }; - switch0phy5: switch0phy5@5 { + switch0phy5: ethernet-phy@5 { reg = <0x5>; }; - switch0phy6: switch0phy6@6 { + switch0phy6: ethernet-phy@6 { reg = <0x6>; }; - switch0phy7: switch0phy7@7 { + switch0phy7: ethernet-phy@7 { reg = <0x7>; }; - switch0phy8: switch0phy8@8 { + switch0phy8: ethernet-phy@8 { reg = <0x8>; }; }; @@ -430,8 +436,9 @@ }; }; + /* NOTE: this node name is ABI, don't change it! */ switch0@2 { - compatible = "marvell,mv88e6085"; + compatible = "marvell,turris-mox-mv88e6085", "marvell,mv88e6085"; reg = <0x2>; dsa,member = <0 0>; interrupt-parent = <&moxtet>; @@ -442,19 +449,19 @@ #address-cells = <1>; #size-cells = <0>; - switch0phy1_topaz: switch0phy1@11 { + switch0phy1_topaz: ethernet-phy@11 { reg = <0x11>; }; - switch0phy2_topaz: switch0phy2@12 { + switch0phy2_topaz: ethernet-phy@12 { reg = <0x12>; }; - switch0phy3_topaz: switch0phy3@13 { + switch0phy3_topaz: ethernet-phy@13 { reg = <0x13>; }; - switch0phy4_topaz: switch0phy4@14 { + switch0phy4_topaz: ethernet-phy@14 { reg = <0x14>; }; }; @@ -497,8 +504,9 @@ }; }; + /* NOTE: this node name is ABI, don't change it! */ switch1@11 { - compatible = "marvell,mv88e6190"; + compatible = "marvell,turris-mox-mv88e6190", "marvell,mv88e6190"; reg = <0x11>; dsa,member = <0 1>; interrupt-parent = <&moxtet>; @@ -509,35 +517,35 @@ #address-cells = <1>; #size-cells = <0>; - switch1phy1: switch1phy1@1 { + switch1phy1: ethernet-phy@1 { reg = <0x1>; }; - switch1phy2: switch1phy2@2 { + switch1phy2: ethernet-phy@2 { reg = <0x2>; }; - switch1phy3: switch1phy3@3 { + switch1phy3: ethernet-phy@3 { reg = <0x3>; }; - switch1phy4: switch1phy4@4 { + switch1phy4: ethernet-phy@4 { reg = <0x4>; }; - switch1phy5: switch1phy5@5 { + switch1phy5: ethernet-phy@5 { reg = <0x5>; }; - switch1phy6: switch1phy6@6 { + switch1phy6: ethernet-phy@6 { reg = <0x6>; }; - switch1phy7: switch1phy7@7 { + switch1phy7: ethernet-phy@7 { reg = <0x7>; }; - switch1phy8: switch1phy8@8 { + switch1phy8: ethernet-phy@8 { reg = <0x8>; }; }; @@ -622,8 +630,9 @@ }; }; + /* NOTE: this node name is ABI, don't change it! */ switch1@2 { - compatible = "marvell,mv88e6085"; + compatible = "marvell,turris-mox-mv88e6085", "marvell,mv88e6085"; reg = <0x2>; dsa,member = <0 1>; interrupt-parent = <&moxtet>; @@ -634,19 +643,19 @@ #address-cells = <1>; #size-cells = <0>; - switch1phy1_topaz: switch1phy1@11 { + switch1phy1_topaz: ethernet-phy@11 { reg = <0x11>; }; - switch1phy2_topaz: switch1phy2@12 { + switch1phy2_topaz: ethernet-phy@12 { reg = <0x12>; }; - switch1phy3_topaz: switch1phy3@13 { + switch1phy3_topaz: ethernet-phy@13 { reg = <0x13>; }; - switch1phy4_topaz: switch1phy4@14 { + switch1phy4_topaz: ethernet-phy@14 { reg = <0x14>; }; }; @@ -689,8 +698,9 @@ }; }; + /* NOTE: this node name is ABI, don't change it! */ switch2@12 { - compatible = "marvell,mv88e6190"; + compatible = "marvell,turris-mox-mv88e6190", "marvell,mv88e6190"; reg = <0x12>; dsa,member = <0 2>; interrupt-parent = <&moxtet>; @@ -701,35 +711,35 @@ #address-cells = <1>; #size-cells = <0>; - switch2phy1: switch2phy1@1 { + switch2phy1: ethernet-phy@1 { reg = <0x1>; }; - switch2phy2: switch2phy2@2 { + switch2phy2: ethernet-phy@2 { reg = <0x2>; }; - switch2phy3: switch2phy3@3 { + switch2phy3: ethernet-phy@3 { reg = <0x3>; }; - switch2phy4: switch2phy4@4 { + switch2phy4: ethernet-phy@4 { reg = <0x4>; }; - switch2phy5: switch2phy5@5 { + switch2phy5: ethernet-phy@5 { reg = <0x5>; }; - switch2phy6: switch2phy6@6 { + switch2phy6: ethernet-phy@6 { reg = <0x6>; }; - switch2phy7: switch2phy7@7 { + switch2phy7: ethernet-phy@7 { reg = <0x7>; }; - switch2phy8: switch2phy8@8 { + switch2phy8: ethernet-phy@8 { reg = <0x8>; }; }; @@ -805,8 +815,9 @@ }; }; + /* NOTE: this node name is ABI, don't change it! */ switch2@2 { - compatible = "marvell,mv88e6085"; + compatible = "marvell,turris-mox-mv88e6085", "marvell,mv88e6085"; reg = <0x2>; dsa,member = <0 2>; interrupt-parent = <&moxtet>; @@ -817,19 +828,19 @@ #address-cells = <1>; #size-cells = <0>; - switch2phy1_topaz: switch2phy1@11 { + switch2phy1_topaz: ethernet-phy@11 { reg = <0x11>; }; - switch2phy2_topaz: switch2phy2@12 { + switch2phy2_topaz: ethernet-phy@12 { reg = <0x12>; }; - switch2phy3_topaz: switch2phy3@13 { + switch2phy3_topaz: ethernet-phy@13 { reg = <0x13>; }; - switch2phy4_topaz: switch2phy4@14 { + switch2phy4_topaz: ethernet-phy@14 { reg = <0x14>; }; }; diff --git a/arch/arm64/boot/dts/marvell/armada-7040-mochabin.dts b/arch/arm64/boot/dts/marvell/armada-7040-mochabin.dts index 48202810bf7862..40b7ee7ead72e2 100644 --- a/arch/arm64/boot/dts/marvell/armada-7040-mochabin.dts +++ b/arch/arm64/boot/dts/marvell/armada-7040-mochabin.dts @@ -301,10 +301,8 @@ }; /* 88E6141 Topaz switch */ - switch: switch@3 { + switch: ethernet-switch@3 { compatible = "marvell,mv88e6085"; - #address-cells = <1>; - #size-cells = <0>; reg = <3>; pinctrl-names = "default"; @@ -314,35 +312,35 @@ interrupt-parent = <&cp0_gpio1>; interrupts = <1 IRQ_TYPE_LEVEL_LOW>; - ports { + ethernet-ports { #address-cells = <1>; #size-cells = <0>; - swport1: port@1 { + swport1: ethernet-port@1 { reg = <1>; label = "lan0"; phy-handle = <&swphy1>; }; - swport2: port@2 { + swport2: ethernet-port@2 { reg = <2>; label = "lan1"; phy-handle = <&swphy2>; }; - swport3: port@3 { + swport3: ethernet-port@3 { reg = <3>; label = "lan2"; phy-handle = <&swphy3>; }; - swport4: port@4 { + swport4: ethernet-port@4 { reg = <4>; label = "lan3"; phy-handle = <&swphy4>; }; - port@5 { + ethernet-port@5 { reg = <5>; label = "cpu"; ethernet = <&cp0_eth1>; @@ -355,19 +353,19 @@ #address-cells = <1>; #size-cells = <0>; - swphy1: swphy1@17 { + swphy1: ethernet-phy@17 { reg = <17>; }; - swphy2: swphy2@18 { + swphy2: ethernet-phy@18 { reg = <18>; }; - swphy3: swphy3@19 { + swphy3: ethernet-phy@19 { reg = <19>; }; - swphy4: swphy4@20 { + swphy4: ethernet-phy@20 { reg = <20>; }; }; diff --git a/arch/arm64/boot/dts/marvell/armada-8040-clearfog-gt-8k.dts b/arch/arm64/boot/dts/marvell/armada-8040-clearfog-gt-8k.dts index 4125202028c856..67892f0d28633e 100644 --- a/arch/arm64/boot/dts/marvell/armada-8040-clearfog-gt-8k.dts +++ b/arch/arm64/boot/dts/marvell/armada-8040-clearfog-gt-8k.dts @@ -497,42 +497,42 @@ reset-deassert-us = <10000>; }; - switch0: switch0@4 { + switch0: ethernet-switch@4 { compatible = "marvell,mv88e6085"; reg = <4>; pinctrl-names = "default"; pinctrl-0 = <&cp1_switch_reset_pins>; reset-gpios = <&cp1_gpio1 24 GPIO_ACTIVE_LOW>; - ports { + ethernet-ports { #address-cells = <1>; #size-cells = <0>; - port@1 { + ethernet-port@1 { reg = <1>; label = "lan2"; phy-handle = <&switch0phy0>; }; - port@2 { + ethernet-port@2 { reg = <2>; label = "lan1"; phy-handle = <&switch0phy1>; }; - port@3 { + ethernet-port@3 { reg = <3>; label = "lan4"; phy-handle = <&switch0phy2>; }; - port@4 { + ethernet-port@4 { reg = <4>; label = "lan3"; phy-handle = <&switch0phy3>; }; - port@5 { + ethernet-port@5 { reg = <5>; label = "cpu"; ethernet = <&cp1_eth2>; @@ -545,19 +545,19 @@ #address-cells = <1>; #size-cells = <0>; - switch0phy0: switch0phy0@11 { + switch0phy0: ethernet-phy@11 { reg = <0x11>; }; - switch0phy1: switch0phy1@12 { + switch0phy1: ethernet-phy@12 { reg = <0x12>; }; - switch0phy2: switch0phy2@13 { + switch0phy2: ethernet-phy@13 { reg = <0x13>; }; - switch0phy3: switch0phy3@14 { + switch0phy3: ethernet-phy@14 { reg = <0x14>; }; }; diff --git a/arch/arm64/boot/dts/marvell/cn9130-crb.dtsi b/arch/arm64/boot/dts/marvell/cn9130-crb.dtsi index 47d45ff3d6f578..6fcc34f7b46474 100644 --- a/arch/arm64/boot/dts/marvell/cn9130-crb.dtsi +++ b/arch/arm64/boot/dts/marvell/cn9130-crb.dtsi @@ -207,11 +207,9 @@ reg = <0>; }; - switch6: switch0@6 { + switch6: ethernet-switch@6 { /* Actual device is MV88E6393X */ compatible = "marvell,mv88e6190"; - #address-cells = <1>; - #size-cells = <0>; reg = <6>; interrupt-parent = <&cp0_gpio1>; interrupts = <28 IRQ_TYPE_LEVEL_LOW>; @@ -220,59 +218,59 @@ dsa,member = <0 0>; - ports { + ethernet-ports { #address-cells = <1>; #size-cells = <0>; - port@1 { + ethernet-port@1 { reg = <1>; label = "p1"; phy-handle = <&switch0phy1>; }; - port@2 { + ethernet-port@2 { reg = <2>; label = "p2"; phy-handle = <&switch0phy2>; }; - port@3 { + ethernet-port@3 { reg = <3>; label = "p3"; phy-handle = <&switch0phy3>; }; - port@4 { + ethernet-port@4 { reg = <4>; label = "p4"; phy-handle = <&switch0phy4>; }; - port@5 { + ethernet-port@5 { reg = <5>; label = "p5"; phy-handle = <&switch0phy5>; }; - port@6 { + ethernet-port@6 { reg = <6>; label = "p6"; phy-handle = <&switch0phy6>; }; - port@7 { + ethernet-port@7 { reg = <7>; label = "p7"; phy-handle = <&switch0phy7>; }; - port@8 { + ethernet-port@8 { reg = <8>; label = "p8"; phy-handle = <&switch0phy8>; }; - port@9 { + ethernet-port@9 { reg = <9>; label = "p9"; phy-mode = "10gbase-r"; @@ -280,7 +278,7 @@ managed = "in-band-status"; }; - port@a { + ethernet-port@a { reg = <10>; ethernet = <&cp0_eth0>; phy-mode = "10gbase-r"; @@ -293,35 +291,35 @@ #address-cells = <1>; #size-cells = <0>; - switch0phy1: switch0phy1@1 { + switch0phy1: ethernet-phy@1 { reg = <0x1>; }; - switch0phy2: switch0phy2@2 { + switch0phy2: ethernet-phy@2 { reg = <0x2>; }; - switch0phy3: switch0phy3@3 { + switch0phy3: ethernet-phy@3 { reg = <0x3>; }; - switch0phy4: switch0phy4@4 { + switch0phy4: ethernet-phy@4 { reg = <0x4>; }; - switch0phy5: switch0phy5@5 { + switch0phy5: ethernet-phy@5 { reg = <0x5>; }; - switch0phy6: switch0phy6@6 { + switch0phy6: ethernet-phy@6 { reg = <0x6>; }; - switch0phy7: switch0phy7@7 { + switch0phy7: ethernet-phy@7 { reg = <0x7>; }; - switch0phy8: switch0phy8@8 { + switch0phy8: ethernet-phy@8 { reg = <0x8>; }; }; diff --git a/arch/arm64/boot/dts/marvell/cn9130-db-comexpress.dtsi b/arch/arm64/boot/dts/marvell/cn9130-db-comexpress.dtsi new file mode 100644 index 00000000000000..028496ebc4736b --- /dev/null +++ b/arch/arm64/boot/dts/marvell/cn9130-db-comexpress.dtsi @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) 2023 Marvell International Ltd. + * + * Device tree for the CN9130-DB Com Express CPU module board. + */ + +#include "cn9130-db.dtsi" + +/ { + model = "Marvell Armada CN9130-DB COM EXPRESS type 7 CPU module board"; + compatible = "marvell,cn9130-cpu-module", "marvell,cn9130", + "marvell,armada-ap807-quad", "marvell,armada-ap807"; + +}; + +&ap0_reg_sd_vccq { + regulator-max-microvolt = <1800000>; + states = <1800000 0x1 1800000 0x0>; + /delete-property/ gpios; +}; + +&cp0_reg_usb3_vbus0 { + /delete-property/ gpio; +}; + +&cp0_reg_usb3_vbus1 { + /delete-property/ gpio; +}; + +&cp0_reg_sd_vcc { + status = "disabled"; +}; + +&cp0_reg_sd_vccq { + status = "disabled"; +}; + +&cp0_sdhci0 { + status = "disabled"; +}; + +&cp0_eth0 { + status = "disabled"; +}; + +&cp0_eth1 { + status = "okay"; + phy = <&phy0>; + phy-mode = "rgmii-id"; +}; + +&cp0_eth2 { + status = "disabled"; +}; + +&cp0_mdio { + status = "okay"; + pinctrl-0 = <&cp0_ge_mdio_pins>; + phy0: ethernet-phy@0 { + status = "okay"; + }; +}; + +&cp0_syscon0 { + cp0_pinctrl: pinctrl { + compatible = "marvell,cp115-standalone-pinctrl"; + + cp0_ge_mdio_pins: ge-mdio-pins { + marvell,pins = "mpp40", "mpp41"; + marvell,function = "ge"; + }; + }; +}; + +&cp0_sdhci0 { + status = "disabled"; +}; + +&cp0_spi1 { + status = "okay"; +}; + +&cp0_usb3_0 { + status = "okay"; + usb-phy = <&cp0_usb3_0_phy0>; + phy-names = "usb"; + /delete-property/ phys; +}; + +&cp0_usb3_1 { + status = "okay"; + usb-phy = <&cp0_usb3_0_phy1>; + phy-names = "usb"; + /delete-property/ phys; +}; diff --git a/arch/arm64/boot/dts/marvell/cn9131-db-comexpress.dtsi b/arch/arm64/boot/dts/marvell/cn9131-db-comexpress.dtsi new file mode 100644 index 00000000000000..6f3914bcfd01e3 --- /dev/null +++ b/arch/arm64/boot/dts/marvell/cn9131-db-comexpress.dtsi @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) 2023 Marvell International Ltd. + * + * Device tree for the CN9131-DB Com Express CPU module board. + */ + +#include "cn9131-db.dtsi" + +/ { + model = "Marvell Armada CN9131-DB COM EXPRESS type 7 CPU module board"; + compatible = "marvell,cn9131-cpu-module", "marvell,cn9131", "marvell,cn9130", + "marvell,armada-ap807-quad", "marvell,armada-ap807"; + +}; + +&ap0_reg_sd_vccq { + regulator-max-microvolt = <1800000>; + states = <1800000 0x1 1800000 0x0>; + /delete-property/ gpios; +}; + +&cp0_reg_usb3_vbus0 { + /delete-property/ gpio; +}; + +&cp0_reg_usb3_vbus1 { + /delete-property/ gpio; +}; + +&cp1_reg_usb3_vbus0 { + /delete-property/ gpio; +}; + +&cp0_reg_sd_vcc { + status = "disabled"; +}; + +&cp0_reg_sd_vccq { + status = "disabled"; +}; + +&cp0_sdhci0 { + status = "disabled"; +}; + +&cp0_eth0 { + status = "disabled"; +}; + +&cp0_eth1 { + status = "okay"; + phy = <&phy0>; + phy-mode = "rgmii-id"; +}; + +&cp0_eth2 { + status = "disabled"; +}; + +&cp0_mdio { + status = "okay"; + pinctrl-0 = <&cp0_ge_mdio_pins>; + phy0: ethernet-phy@0 { + status = "okay"; + }; +}; + +&cp0_syscon0 { + cp0_pinctrl: pinctrl { + compatible = "marvell,cp115-standalone-pinctrl"; + + cp0_ge_mdio_pins: ge-mdio-pins { + marvell,pins = "mpp40", "mpp41"; + marvell,function = "ge"; + }; + }; +}; + +&cp0_sdhci0 { + status = "disabled"; +}; + +&cp0_spi1 { + status = "okay"; +}; + +&cp0_usb3_0 { + status = "okay"; + usb-phy = <&cp0_usb3_0_phy0>; + phy-names = "usb"; + /delete-property/ phys; +}; + +&cp0_usb3_1 { + status = "okay"; + usb-phy = <&cp0_usb3_0_phy1>; + phy-names = "usb"; + /delete-property/ phys; +}; + +&cp1_usb3_1 { + status = "okay"; + usb-phy = <&cp1_usb3_0_phy0>; + /* Generic PHY, providing serdes lanes */ + phys = <&cp1_comphy3 1>; + phy-names = "usb"; +}; diff --git a/arch/arm64/boot/dts/mediatek/Makefile b/arch/arm64/boot/dts/mediatek/Makefile index e6e7592a364581..1e6f91731e9279 100644 --- a/arch/arm64/boot/dts/mediatek/Makefile +++ b/arch/arm64/boot/dts/mediatek/Makefile @@ -32,10 +32,16 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-jacuzzi-fennel14-sku2.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-jacuzzi-juniper-sku16.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-jacuzzi-kappa.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-jacuzzi-kenzo.dtb +dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-jacuzzi-makomo-sku0.dtb +dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-jacuzzi-makomo-sku1.dtb +dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-jacuzzi-pico.dtb +dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-jacuzzi-pico6.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-jacuzzi-willow-sku0.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-jacuzzi-willow-sku1.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-kakadu.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-kakadu-sku22.dtb +dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-katsu-sku32.dtb +dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-katsu-sku38.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-kodama-sku16.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-kodama-sku272.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-kodama-sku288.dtb @@ -44,6 +50,7 @@ dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-krane-sku0.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-kukui-krane-sku176.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8183-pumpkin.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8186-evb.dtb +dtb-$(CONFIG_ARCH_MEDIATEK) += mt8188-evb.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8192-asurada-hayato-r1.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8192-asurada-hayato-r5-sku2.dtb dtb-$(CONFIG_ARCH_MEDIATEK) += mt8192-asurada-spherion-r0.dtb diff --git a/arch/arm64/boot/dts/mediatek/mt6358.dtsi b/arch/arm64/boot/dts/mediatek/mt6358.dtsi index b605313bed99d1..a1b96013f8141a 100644 --- a/arch/arm64/boot/dts/mediatek/mt6358.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt6358.dtsi @@ -8,8 +8,6 @@ pmic: pmic { compatible = "mediatek,mt6358"; interrupt-controller; - interrupt-parent = <&pio>; - interrupts = <182 IRQ_TYPE_LEVEL_HIGH>; #interrupt-cells = <2>; mt6358codec: mt6358codec { @@ -128,7 +126,6 @@ }; mt6358_vrf12_reg: ldo_vrf12 { - compatible = "regulator-fixed"; regulator-name = "vrf12"; regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; @@ -136,7 +133,6 @@ }; mt6358_vio18_reg: ldo_vio18 { - compatible = "regulator-fixed"; regulator-name = "vio18"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; @@ -153,7 +149,6 @@ }; mt6358_vcamio_reg: ldo_vcamio { - compatible = "regulator-fixed"; regulator-name = "vcamio"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; @@ -168,7 +163,6 @@ }; mt6358_vcn18_reg: ldo_vcn18 { - compatible = "regulator-fixed"; regulator-name = "vcn18"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; @@ -176,7 +170,6 @@ }; mt6358_vfe28_reg: ldo_vfe28 { - compatible = "regulator-fixed"; regulator-name = "vfe28"; regulator-min-microvolt = <2800000>; regulator-max-microvolt = <2800000>; @@ -193,7 +186,6 @@ }; mt6358_vcn28_reg: ldo_vcn28 { - compatible = "regulator-fixed"; regulator-name = "vcn28"; regulator-min-microvolt = <2800000>; regulator-max-microvolt = <2800000>; @@ -218,7 +210,6 @@ }; mt6358_vxo22_reg: ldo_vxo22 { - compatible = "regulator-fixed"; regulator-name = "vxo22"; regulator-min-microvolt = <2200000>; regulator-max-microvolt = <2200000>; @@ -234,7 +225,6 @@ }; mt6358_vaux18_reg: ldo_vaux18 { - compatible = "regulator-fixed"; regulator-name = "vaux18"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; @@ -249,7 +239,6 @@ }; mt6358_vbif28_reg: ldo_vbif28 { - compatible = "regulator-fixed"; regulator-name = "vbif28"; regulator-min-microvolt = <2800000>; regulator-max-microvolt = <2800000>; @@ -280,7 +269,6 @@ }; mt6358_vio28_reg: ldo_vio28 { - compatible = "regulator-fixed"; regulator-name = "vio28"; regulator-min-microvolt = <2800000>; regulator-max-microvolt = <2800000>; @@ -288,7 +276,6 @@ }; mt6358_va12_reg: ldo_va12 { - compatible = "regulator-fixed"; regulator-name = "va12"; regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; @@ -297,22 +284,14 @@ }; mt6358_vrf18_reg: ldo_vrf18 { - compatible = "regulator-fixed"; regulator-name = "vrf18"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; regulator-enable-ramp-delay = <120>; }; - mt6358_vcn33_bt_reg: ldo_vcn33_bt { - regulator-name = "vcn33_bt"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3500000>; - regulator-enable-ramp-delay = <270>; - }; - - mt6358_vcn33_wifi_reg: ldo_vcn33_wifi { - regulator-name = "vcn33_wifi"; + mt6358_vcn33_reg: ldo_vcn33 { + regulator-name = "vcn33"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3500000>; regulator-enable-ramp-delay = <270>; @@ -340,7 +319,6 @@ }; mt6358_vaud28_reg: ldo_vaud28 { - compatible = "regulator-fixed"; regulator-name = "vaud28"; regulator-min-microvolt = <2800000>; regulator-max-microvolt = <2800000>; diff --git a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts index c46682150e502a..a1f42048dcc703 100644 --- a/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts +++ b/arch/arm64/boot/dts/mediatek/mt7622-bananapi-bpi-r64.dts @@ -153,8 +153,7 @@ reg = <0>; interrupt-controller; #interrupt-cells = <1>; - interrupt-parent = <&pio>; - interrupts = <53 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&pio 53 IRQ_TYPE_LEVEL_HIGH>; reset-gpios = <&pio 54 0>; ports { diff --git a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts index b876e501216be8..d06d4af43cbffb 100644 --- a/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts +++ b/arch/arm64/boot/dts/mediatek/mt7986a-bananapi-bpi-r3.dts @@ -205,8 +205,7 @@ reg = <31>; interrupt-controller; #interrupt-cells = <1>; - interrupt-parent = <&pio>; - interrupts = <66 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&pio 66 IRQ_TYPE_LEVEL_HIGH>; reset-gpios = <&pio 5 GPIO_ACTIVE_HIGH>; }; }; diff --git a/arch/arm64/boot/dts/mediatek/mt8173-elm-hana.dtsi b/arch/arm64/boot/dts/mediatek/mt8173-elm-hana.dtsi index bdcd35cecad908..90cbbc18a4834e 100644 --- a/arch/arm64/boot/dts/mediatek/mt8173-elm-hana.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8173-elm-hana.dtsi @@ -13,8 +13,7 @@ touchscreen2: touchscreen@34 { compatible = "melfas,mip4_ts"; reg = <0x34>; - interrupt-parent = <&pio>; - interrupts = <88 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&pio 88 IRQ_TYPE_LEVEL_LOW>; }; /* @@ -26,8 +25,7 @@ compatible = "hid-over-i2c"; reg = <0x20>; hid-descr-addr = <0x0020>; - interrupt-parent = <&pio>; - interrupts = <88 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&pio 88 IRQ_TYPE_LEVEL_LOW>; }; }; @@ -39,8 +37,7 @@ */ trackpad2: trackpad@2c { compatible = "hid-over-i2c"; - interrupt-parent = <&pio>; - interrupts = <117 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&pio 117 IRQ_TYPE_LEVEL_LOW>; reg = <0x2c>; hid-descr-addr = <0x0020>; wakeup-source; diff --git a/arch/arm64/boot/dts/mediatek/mt8173-elm.dtsi b/arch/arm64/boot/dts/mediatek/mt8173-elm.dtsi index 111495622cacdc..8d614ac2c58ed8 100644 --- a/arch/arm64/boot/dts/mediatek/mt8173-elm.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8173-elm.dtsi @@ -245,8 +245,7 @@ reg = <0x1a>; avdd-supply = <&mt6397_vgp1_reg>; cpvdd-supply = <&mt6397_vcama_reg>; - interrupt-parent = <&pio>; - interrupts = <3 IRQ_TYPE_EDGE_BOTH>; + interrupts-extended = <&pio 3 IRQ_TYPE_EDGE_BOTH>; pinctrl-names = "default"; pinctrl-0 = <&rt5650_irq>; #sound-dai-cells = <1>; @@ -308,8 +307,7 @@ da9211: da9211@68 { compatible = "dlg,da9211"; reg = <0x68>; - interrupt-parent = <&pio>; - interrupts = <15 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&pio 15 IRQ_TYPE_LEVEL_LOW>; regulators { da9211_vcpu_reg: BUCKA { @@ -353,8 +351,7 @@ touchscreen: touchscreen@10 { compatible = "elan,ekth3500"; reg = <0x10>; - interrupt-parent = <&pio>; - interrupts = <88 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&pio 88 IRQ_TYPE_LEVEL_LOW>; }; }; @@ -366,8 +363,7 @@ trackpad: trackpad@15 { compatible = "elan,ekth3000"; - interrupt-parent = <&pio>; - interrupts = <117 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&pio 117 IRQ_TYPE_LEVEL_LOW>; reg = <0x15>; vcc-supply = <&mt6397_vgp6_reg>; wakeup-source; @@ -439,8 +435,7 @@ btmrvl: btmrvl@2 { compatible = "marvell,sd8897-bt"; reg = <2>; - interrupt-parent = <&pio>; - interrupts = <119 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&pio 119 IRQ_TYPE_LEVEL_LOW>; marvell,wakeup-pin = /bits/ 16 <0x0d>; marvell,wakeup-gap-ms = /bits/ 16 <0x64>; }; @@ -448,8 +443,7 @@ mwifiex: mwifiex@1 { compatible = "marvell,sd8897"; reg = <1>; - interrupt-parent = <&pio>; - interrupts = <38 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&pio 38 IRQ_TYPE_LEVEL_LOW>; marvell,wakeup-pin = <3>; }; }; @@ -933,8 +927,7 @@ compatible = "mediatek,mt6397"; #address-cells = <1>; #size-cells = <1>; - interrupt-parent = <&pio>; - interrupts = <11 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&pio 11 IRQ_TYPE_LEVEL_HIGH>; interrupt-controller; #interrupt-cells = <2>; @@ -1160,8 +1153,7 @@ compatible = "google,cros-ec-spi"; reg = <0x0>; spi-max-frequency = <12000000>; - interrupt-parent = <&pio>; - interrupts = <0 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&pio 0 IRQ_TYPE_LEVEL_LOW>; google,cros-ec-spi-msg-delay = <500>; i2c_tunnel: i2c-tunnel0 { diff --git a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts index d258c80213b264..0e5c628d1ec3e0 100644 --- a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts +++ b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts @@ -303,8 +303,7 @@ pmic: pmic { compatible = "mediatek,mt6397"; - interrupt-parent = <&pio>; - interrupts = <11 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&pio 11 IRQ_TYPE_LEVEL_HIGH>; interrupt-controller; #interrupt-cells = <2>; diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi index c47d7d900f2836..cac4cd0a032012 100644 --- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi @@ -1368,10 +1368,9 @@ #clock-cells = <1>; }; - vcodec_dec: vcodec@16000000 { + vcodec_dec: vcodec@16020000 { compatible = "mediatek,mt8173-vcodec-dec"; - reg = <0 0x16000000 0 0x100>, /* VDEC_SYS */ - <0 0x16020000 0 0x1000>, /* VDEC_MISC */ + reg = <0 0x16020000 0 0x1000>, /* VDEC_MISC */ <0 0x16021000 0 0x800>, /* VDEC_LD */ <0 0x16021800 0 0x800>, /* VDEC_TOP */ <0 0x16022000 0 0x1000>, /* VDEC_CM */ @@ -1382,6 +1381,8 @@ <0 0x16027000 0 0x800>, /* VDEC_HWQ */ <0 0x16027800 0 0x800>, /* VDEC_HWB */ <0 0x16028400 0 0x400>; /* VDEC_HWG */ + reg-names = "misc", "ld", "top", "cm", "ad", "av", "pp", + "hwd", "hwq", "hwb", "hwg"; interrupts = ; iommus = <&iommu M4U_PORT_HW_VDEC_MC_EXT>, <&iommu M4U_PORT_HW_VDEC_PP_EXT>, @@ -1392,6 +1393,7 @@ <&iommu M4U_PORT_HW_VDEC_VLD_EXT>, <&iommu M4U_PORT_HW_VDEC_VLD2_EXT>; mediatek,vpu = <&vpu>; + mediatek,vdecsys = <&vdecsys>; power-domains = <&spm MT8173_POWER_DOMAIN_VDEC>; clocks = <&apmixedsys CLK_APMIXED_VCODECPLL>, <&topckgen CLK_TOP_UNIVPLL_D2>, diff --git a/arch/arm64/boot/dts/mediatek/mt8183-evb.dts b/arch/arm64/boot/dts/mediatek/mt8183-evb.dts index 77f9ab94c00bd9..681deddffc2ad0 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-evb.dts +++ b/arch/arm64/boot/dts/mediatek/mt8183-evb.dts @@ -381,6 +381,10 @@ }; }; +&pmic { + interrupts-extended = <&pio 182 IRQ_TYPE_LEVEL_HIGH>; +}; + &mfg { domain-supply = <&mt6358_vgpu_reg>; }; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-audio-da7219.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui-audio-da7219.dtsi index 2c69e7658dba6d..8b57706ac8140b 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-audio-da7219.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-audio-da7219.dtsi @@ -11,8 +11,7 @@ pinctrl-0 = <&da7219_pins>; compatible = "dlg,da7219"; reg = <0x1a>; - interrupt-parent = <&pio>; - interrupts = <165 IRQ_TYPE_LEVEL_LOW 165 0>; + interrupts-extended = <&pio 165 IRQ_TYPE_LEVEL_LOW>; dlg,micbias-lvl = <2600>; dlg,mic-amp-in-sel = "diff"; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-audio-ts3a227e.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui-audio-ts3a227e.dtsi index 0799c48ade19e3..548e22c194a21c 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-audio-ts3a227e.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-audio-ts3a227e.dtsi @@ -11,8 +11,7 @@ pinctrl-0 = <&ts3a227e_pins>; compatible = "ti,ts3a227e"; reg = <0x3b>; - interrupt-parent = <&pio>; - interrupts = <157 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&pio 157 IRQ_TYPE_LEVEL_LOW>; status = "okay"; }; }; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-damu.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-damu.dts index 552bfc72699945..0b45aee2e29953 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-damu.dts +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-damu.dts @@ -18,8 +18,7 @@ compatible = "hid-over-i2c"; reg = <0x10>; - interrupt-parent = <&pio>; - interrupts = <155 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&pio 155 IRQ_TYPE_LEVEL_LOW>; pinctrl-names = "default"; pinctrl-0 = <&touchscreen_pins>; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-fennel-sku1.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-fennel-sku1.dts index 77b96ddf648ebe..b595622e7beea3 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-fennel-sku1.dts +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-fennel-sku1.dts @@ -30,8 +30,7 @@ compatible = "hid-over-i2c"; reg = <0x10>; - interrupt-parent = <&pio>; - interrupts = <155 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&pio 155 IRQ_TYPE_LEVEL_LOW>; pinctrl-names = "default"; pinctrl-0 = <&touchscreen_pins>; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-fennel-sku6.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-fennel-sku6.dts index 37e6e58f63b7e3..5a1c39318a6caa 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-fennel-sku6.dts +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-fennel-sku6.dts @@ -17,8 +17,7 @@ compatible = "hid-over-i2c"; reg = <0x10>; - interrupt-parent = <&pio>; - interrupts = <155 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&pio 155 IRQ_TYPE_LEVEL_LOW>; pinctrl-names = "default"; pinctrl-0 = <&touchscreen_pins>; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-fennel-sku7.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-fennel-sku7.dts index 0e09604004d5e7..3ea4fdb401184f 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-fennel-sku7.dts +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-fennel-sku7.dts @@ -17,8 +17,7 @@ compatible = "hid-over-i2c"; reg = <0x10>; - interrupt-parent = <&pio>; - interrupts = <155 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&pio 155 IRQ_TYPE_LEVEL_LOW>; pinctrl-names = "default"; pinctrl-0 = <&touchscreen_pins>; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-makomo-sku0.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-makomo-sku0.dts new file mode 100644 index 00000000000000..4eb2a0d571af45 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-makomo-sku0.dts @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2023 Google LLC + */ + +/dts-v1/; +#include "mt8183-kukui-jacuzzi-fennel.dtsi" +#include "mt8183-kukui-audio-da7219-rt1015p.dtsi" + +/ { + model = "Google makomo sku0 board"; + chassis-type = "laptop"; + compatible = "google,makomo-sku0", "google,makomo", "mediatek,mt8183"; +}; + +&qca_wifi { + qcom,ath10k-calibration-variant = "GO_FENNEL14"; +}; + +&mmc1_pins_uhs { + pins-clk { + drive-strength = ; + }; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-makomo-sku1.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-makomo-sku1.dts new file mode 100644 index 00000000000000..6a733361e8ae26 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-makomo-sku1.dts @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2023 Google LLC + */ + +/dts-v1/; +#include "mt8183-kukui-jacuzzi-fennel.dtsi" +#include "mt8183-kukui-audio-ts3a227e-rt1015p.dtsi" + +/ { + model = "Google makomo sku1 board"; + chassis-type = "laptop"; + compatible = "google,makomo-sku1", "google,makomo", "mediatek,mt8183"; +}; + +&qca_wifi { + qcom,ath10k-calibration-variant = "GO_FENNEL14"; +}; + +&mmc1_pins_uhs { + pins-clk { + drive-strength = ; + }; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-pico.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-pico.dts new file mode 100644 index 00000000000000..8ce9568fee95a6 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-pico.dts @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2023 Google LLC + */ + +/dts-v1/; +#include "mt8183-kukui-jacuzzi.dtsi" +#include "mt8183-kukui-audio-ts3a227e-max98357a.dtsi" + +/ { + model = "Google pico board"; + chassis-type = "convertible"; + compatible = "google,pico-sku1", "google,pico", "mediatek,mt8183"; +}; + +&i2c_tunnel { + google,remote-bus = <0>; +}; + +&i2c2 { + i2c-scl-internal-delay-ns = <25000>; + + trackpad@2c { + compatible = "hid-over-i2c"; + reg = <0x2c>; + hid-descr-addr = <0x20>; + + pinctrl-names = "default"; + pinctrl-0 = <&trackpad_pins>; + + interrupts-extended = <&pio 7 IRQ_TYPE_LEVEL_LOW>; + + wakeup-source; + }; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-pico6.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-pico6.dts new file mode 100644 index 00000000000000..a2e74b82932064 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi-pico6.dts @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2023 Google LLC + */ + +/dts-v1/; +#include "mt8183-kukui-jacuzzi.dtsi" +#include "mt8183-kukui-audio-ts3a227e-max98357a.dtsi" + +/ { + model = "Google pico6 board"; + chassis-type = "convertible"; + compatible = "google,pico-sku2", "google,pico", "mediatek,mt8183"; + + bt_wakeup: bt-wakeup { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&bt_pins_wakeup>; + + wobt { + label = "Wake on BT"; + gpios = <&pio 42 GPIO_ACTIVE_HIGH>; + linux,code = ; + wakeup-source; + }; + }; +}; + +&i2c_tunnel { + google,remote-bus = <0>; +}; + +&i2c2 { + i2c-scl-internal-delay-ns = <25000>; + + trackpad@2c { + compatible = "hid-over-i2c"; + reg = <0x2c>; + hid-descr-addr = <0x20>; + + pinctrl-names = "default"; + pinctrl-0 = <&trackpad_pins>; + + interrupts-extended = <&pio 7 IRQ_TYPE_LEVEL_LOW>; + + wakeup-source; + }; +}; + +&wifi_wakeup { + wowlan { + gpios = <&pio 113 GPIO_ACTIVE_LOW>; + }; +}; + +&wifi_pwrseq { + post-power-on-delay-ms = <50>; + + /* Toggle WIFI_ENABLE to reset the chip. */ + reset-gpios = <&pio 8 GPIO_ACTIVE_LOW>; +}; + +&wifi_pins_pwrseq { + pins-wifi-enable { + pinmux = ; + }; +}; + +&mmc1_pins_default { + pins-cmd-dat { + drive-strength = ; + }; + pins-clk { + drive-strength = ; + }; +}; + +&mmc1_pins_uhs { + pins-clk { + drive-strength = ; + }; +}; + +&mmc1 { + bt_reset: bt-reset { + compatible = "mediatek,mt7921s-bluetooth"; + pinctrl-names = "default"; + pinctrl-0 = <&bt_pins_reset>; + reset-gpios = <&pio 120 GPIO_ACTIVE_LOW>; + }; +}; + +&pio { + bt_pins_wakeup: bt-pins-wakeup { + piins-bt-wakeup { + pinmux = ; + input-enable; + }; + }; + + bt_pins_reset: bt-pins-reset { + pins-bt-reset { + pinmux = ; + output-high; + }; + }; +}; + +/delete-node/ &bluetooth; +/delete-node/ &bt_pins; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi.dtsi index 820260348de9b6..7592e3b860377e 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-jacuzzi.dtsi @@ -149,7 +149,6 @@ reg = <0x58>; pinctrl-names = "default"; pinctrl-0 = <&anx7625_pins>; - panel_flags = <1>; enable-gpios = <&pio 45 GPIO_ACTIVE_HIGH>; reset-gpios = <&pio 73 GPIO_ACTIVE_HIGH>; vdd10-supply = <&pp1200_mipibrdg>; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu-sku22.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu-sku22.dts index fcce8ea1232e64..1ecf39458d9308 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu-sku22.dts +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu-sku22.dts @@ -14,6 +14,24 @@ "google,kakadu", "mediatek,mt8183"; }; +&i2c0 { + touchscreen: touchscreen@10 { + compatible = "hid-over-i2c"; + reg = <0x10>; + pinctrl-names = "default"; + pinctrl-0 = <&open_touch>; + + interrupts-extended = <&pio 155 IRQ_TYPE_EDGE_FALLING>; + + post-power-on-delay-ms = <10>; + hid-descr-addr = <0x0001>; + }; +}; + +&panel { + compatible = "boe,tv105wum-nw0"; +}; + &sound { compatible = "mediatek,mt8183_mt6358_ts3a227_rt1015p"; }; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dts index ebfabba7250758..ba74109a49094e 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dts +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dts @@ -13,3 +13,21 @@ compatible = "google,kakadu-rev3", "google,kakadu-rev2", "google,kakadu", "mediatek,mt8183"; }; + +&i2c0 { + touchscreen: touchscreen@10 { + compatible = "hid-over-i2c"; + reg = <0x10>; + pinctrl-names = "default"; + pinctrl-0 = <&open_touch>; + + interrupts-extended = <&pio 155 IRQ_TYPE_EDGE_FALLING>; + + post-power-on-delay-ms = <10>; + hid-descr-addr = <0x0001>; + }; +}; + +&panel { + compatible = "boe,tv105wum-nw0"; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dtsi index a11adeb29b1f2e..b6a9830af2696f 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kakadu.dtsi @@ -63,19 +63,6 @@ &i2c0 { status = "okay"; - - touchscreen: touchscreen@10 { - compatible = "hid-over-i2c"; - reg = <0x10>; - pinctrl-names = "default"; - pinctrl-0 = <&open_touch>; - - interrupt-parent = <&pio>; - interrupts = <155 IRQ_TYPE_EDGE_FALLING>; - - post-power-on-delay-ms = <10>; - hid-descr-addr = <0x0001>; - }; }; &mt6358_vcama2_reg { @@ -384,5 +371,5 @@ &panel { status = "okay"; - compatible = "boe,tv105wum-nw0"; + /* compatible will be set in board dts */ }; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-katsu-sku32.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-katsu-sku32.dts new file mode 100644 index 00000000000000..05361008e8ac02 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-katsu-sku32.dts @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2023 Google LLC + */ + +/dts-v1/; +#include "mt8183-kukui-kakadu.dtsi" +#include "mt8183-kukui-audio-da7219-rt1015p.dtsi" + +/ { + model = "Google katsu board"; + chassis-type = "tablet"; + compatible = "google,katsu-sku32", "google,katsu", "mediatek,mt8183"; +}; + +&i2c0 { + touchscreen1: touchscreen@5d { + compatible = "goodix,gt7375p"; + reg = <0x5d>; + pinctrl-names = "default"; + pinctrl-0 = <&open_touch>; + + interrupts-extended = <&pio 155 IRQ_TYPE_LEVEL_LOW>; + + reset-gpios = <&pio 156 GPIO_ACTIVE_LOW>; + vdd-supply = <&lcd_pp3300>; + }; +}; + +&panel { + compatible = "starry,2081101qfh032011-53g"; +}; + +&qca_wifi { + qcom,ath10k-calibration-variant = "GO_KATSU"; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-katsu-sku38.dts b/arch/arm64/boot/dts/mediatek/mt8183-kukui-katsu-sku38.dts new file mode 100644 index 00000000000000..cf008ed828783a --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-katsu-sku38.dts @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2023 Google LLC + */ + +/dts-v1/; +#include "mt8183-kukui-kakadu.dtsi" +#include "mt8183-kukui-audio-rt1015p.dtsi" + +/ { + model = "Google katsu sku38 board"; + chassis-type = "tablet"; + compatible = "google,katsu-sku38", "google,katsu", "mediatek,mt8183"; +}; + +&i2c0 { + touchscreen1: touchscreen@5d { + compatible = "goodix,gt7375p"; + reg = <0x5d>; + pinctrl-names = "default"; + pinctrl-0 = <&open_touch>; + + interrupts-extended = <&pio 155 IRQ_TYPE_LEVEL_LOW>; + + reset-gpios = <&pio 156 GPIO_ACTIVE_LOW>; + vdd-supply = <&lcd_pp3300>; + }; +}; + +&panel { + compatible = "starry,2081101qfh032011-53g"; +}; + +&qca_wifi { + qcom,ath10k-calibration-variant = "GO_KATSU"; +}; + +&sound { + compatible = "mediatek,mt8183_mt6358_ts3a227_rt1015p"; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama.dtsi index 4864c39e53a4fd..306c95166f3fec 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-kodama.dtsi @@ -48,8 +48,7 @@ touchscreen: touchscreen@10 { compatible = "hid-over-i2c"; reg = <0x10>; - interrupt-parent = <&pio>; - interrupts = <155 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&pio 155 IRQ_TYPE_LEVEL_LOW>; pinctrl-names = "default"; pinctrl-0 = <&touch_default>; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui-krane.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui-krane.dtsi index d5f41c6c98814a..382e4c6d7191c0 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui-krane.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui-krane.dtsi @@ -54,8 +54,7 @@ pinctrl-names = "default"; pinctrl-0 = <&open_touch>; - interrupt-parent = <&pio>; - interrupts = <155 IRQ_TYPE_EDGE_FALLING>; + interrupts-extended = <&pio 155 IRQ_TYPE_EDGE_FALLING>; post-power-on-delay-ms = <10>; hid-descr-addr = <0x0001>; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi b/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi index 7881a27be02970..1b3396b1cee394 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8183-kukui.dtsi @@ -846,6 +846,10 @@ }; }; +&pmic { + interrupts-extended = <&pio 182 IRQ_TYPE_LEVEL_HIGH>; +}; + &pwm0 { status = "okay"; pinctrl-names = "default"; @@ -884,14 +888,13 @@ status = "okay"; cs-gpios = <&pio 86 GPIO_ACTIVE_LOW>; - cr50@0 { + tpm@0 { compatible = "google,cr50"; reg = <0>; spi-max-frequency = <1000000>; pinctrl-names = "default"; pinctrl-0 = <&h1_int_od_l>; - interrupt-parent = <&pio>; - interrupts = <153 IRQ_TYPE_EDGE_RISING>; + interrupts-extended = <&pio 153 IRQ_TYPE_EDGE_RISING>; }; }; @@ -918,8 +921,7 @@ compatible = "google,cros-ec-spi"; reg = <0>; spi-max-frequency = <3000000>; - interrupt-parent = <&pio>; - interrupts = <151 IRQ_TYPE_LEVEL_LOW>; + interrupts-extended = <&pio 151 IRQ_TYPE_LEVEL_LOW>; pinctrl-names = "default"; pinctrl-0 = <&ec_ap_int_odl>; diff --git a/arch/arm64/boot/dts/mediatek/mt8183-pumpkin.dts b/arch/arm64/boot/dts/mediatek/mt8183-pumpkin.dts index b5784a60c315d3..76449b4cf23606 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183-pumpkin.dts +++ b/arch/arm64/boot/dts/mediatek/mt8183-pumpkin.dts @@ -370,6 +370,10 @@ }; }; +&pmic { + interrupts-extended = <&pio 182 IRQ_TYPE_LEVEL_HIGH>; +}; + &mfg { domain-supply = <&mt6358_vgpu_reg>; }; diff --git a/arch/arm64/boot/dts/mediatek/mt8183.dtsi b/arch/arm64/boot/dts/mediatek/mt8183.dtsi index 976dc968b3ca14..920ee415ef5fbd 100644 --- a/arch/arm64/boot/dts/mediatek/mt8183.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8183.dtsi @@ -1183,22 +1183,10 @@ status = "disabled"; }; - svs: svs@1100b000 { - compatible = "mediatek,mt8183-svs"; - reg = <0 0x1100b000 0 0x1000>; - interrupts = ; - clocks = <&infracfg CLK_INFRA_THERM>; - clock-names = "main"; - nvmem-cells = <&svs_calibration>, - <&thermal_calibration>; - nvmem-cell-names = "svs-calibration-data", - "t-calibration-data"; - }; - thermal: thermal@1100b000 { #thermal-sensor-cells = <1>; compatible = "mediatek,mt8183-thermal"; - reg = <0 0x1100b000 0 0x1000>; + reg = <0 0x1100b000 0 0xc00>; clocks = <&infracfg CLK_INFRA_THERM>, <&infracfg CLK_INFRA_AUXADC>; clock-names = "therm", "auxadc"; @@ -1210,6 +1198,18 @@ nvmem-cell-names = "calibration-data"; }; + svs: svs@1100bc00 { + compatible = "mediatek,mt8183-svs"; + reg = <0 0x1100bc00 0 0x400>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_THERM>; + clock-names = "main"; + nvmem-cells = <&svs_calibration>, + <&thermal_calibration>; + nvmem-cell-names = "svs-calibration-data", + "t-calibration-data"; + }; + pwm0: pwm@1100e000 { compatible = "mediatek,mt8183-disp-pwm"; reg = <0 0x1100e000 0 0x1000>; @@ -1660,7 +1660,7 @@ mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0 0x1000>; }; - mdp3-rdma0@14001000 { + dma-controller0@14001000 { compatible = "mediatek,mt8183-mdp3-rdma"; reg = <0 0x14001000 0 0x1000>; mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0x1000 0x1000>; @@ -1672,6 +1672,7 @@ iommus = <&iommu M4U_PORT_MDP_RDMA0>; mboxes = <&gce 20 CMDQ_THR_PRIO_LOWEST 0>, <&gce 21 CMDQ_THR_PRIO_LOWEST 0>; + #dma-cells = <1>; }; mdp3-rsz0@14003000 { @@ -1692,7 +1693,7 @@ clocks = <&mmsys CLK_MM_MDP_RSZ1>; }; - mdp3-wrot0@14005000 { + dma-controller@14005000 { compatible = "mediatek,mt8183-mdp3-wrot"; reg = <0 0x14005000 0 0x1000>; mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0x5000 0x1000>; @@ -1701,6 +1702,7 @@ power-domains = <&spm MT8183_POWER_DOMAIN_DISP>; clocks = <&mmsys CLK_MM_MDP_WROT0>; iommus = <&iommu M4U_PORT_MDP_WROT0>; + #dma-cells = <1>; }; mdp3-wdma@14006000 { @@ -1898,6 +1900,36 @@ #clock-cells = <1>; }; + vcodec_dec: video-codec@16020000 { + compatible = "mediatek,mt8183-vcodec-dec"; + reg = <0 0x16020000 0 0x1000>, /* VDEC_MISC */ + <0 0x16021000 0 0x800>, /* VDEC_VLD */ + <0 0x16021800 0 0x800>, /* VDEC_TOP */ + <0 0x16022000 0 0x1000>, /* VDEC_MC */ + <0 0x16023000 0 0x1000>, /* VDEC_AVCVLD */ + <0 0x16024000 0 0x1000>, /* VDEC_AVCMV */ + <0 0x16025000 0 0x1000>, /* VDEC_PP */ + <0 0x16026800 0 0x800>, /* VP8_VD */ + <0 0x16027000 0 0x800>, /* VP6_VD */ + <0 0x16027800 0 0x800>, /* VP8_VL */ + <0 0x16028400 0 0x400>; /* VP9_VD */ + reg-names = "misc", "ld", "top", "cm", "ad", "av", "pp", + "hwd", "hwq", "hwb", "hwg"; + interrupts = ; + iommus = <&iommu M4U_PORT_HW_VDEC_MC_EXT>, + <&iommu M4U_PORT_HW_VDEC_PP_EXT>, + <&iommu M4U_PORT_HW_VDEC_VLD_EXT>, + <&iommu M4U_PORT_HW_VDEC_AVC_MV_EXT>, + <&iommu M4U_PORT_HW_VDEC_PRED_RD_EXT>, + <&iommu M4U_PORT_HW_VDEC_PRED_WR_EXT>, + <&iommu M4U_PORT_HW_VDEC_PPWRAP_EXT>; + mediatek,scp = <&scp>; + mediatek,vdecsys = <&vdecsys>; + power-domains = <&spm MT8183_POWER_DOMAIN_VDEC>; + clocks = <&vdecsys CLK_VDEC_VDEC>; + clock-names = "vdec"; + }; + larb1: larb@16010000 { compatible = "mediatek,mt8183-smi-larb"; reg = <0 0x16010000 0 0x1000>; diff --git a/arch/arm64/boot/dts/mediatek/mt8186.dtsi b/arch/arm64/boot/dts/mediatek/mt8186.dtsi index df0c04f2ba1da9..2fec6fd1c1a71d 100644 --- a/arch/arm64/boot/dts/mediatek/mt8186.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8186.dtsi @@ -22,7 +22,7 @@ aliases { ovl0 = &ovl0; - ovl_2l0 = &ovl_2l0; + ovl-2l0 = &ovl_2l0; rdma0 = &rdma0; rdma1 = &rdma1; }; @@ -1160,14 +1160,14 @@ status = "disabled"; }; - adsp_mailbox0: mailbox@10686000 { + adsp_mailbox0: mailbox@10686100 { compatible = "mediatek,mt8186-adsp-mbox"; #mbox-cells = <0>; reg = <0 0x10686100 0 0x1000>; interrupts = ; }; - adsp_mailbox1: mailbox@10687000 { + adsp_mailbox1: mailbox@10687100 { compatible = "mediatek,mt8186-adsp-mbox"; #mbox-cells = <0>; reg = <0 0x10687100 0 0x1000>; diff --git a/arch/arm64/boot/dts/mediatek/mt8188-evb.dts b/arch/arm64/boot/dts/mediatek/mt8188-evb.dts new file mode 100644 index 00000000000000..68a82b49f7a3af --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt8188-evb.dts @@ -0,0 +1,387 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2023 MediaTek Inc. + */ +/dts-v1/; +#include "mt8188.dtsi" +#include "mt6359.dtsi" + +/ { + model = "MediaTek MT8188 evaluation board"; + compatible = "mediatek,mt8188-evb", "mediatek,mt8188"; + + aliases { + serial0 = &uart0; + i2c0 = &i2c0; + i2c1 = &i2c1; + i2c2 = &i2c2; + i2c3 = &i2c3; + i2c4 = &i2c4; + i2c5 = &i2c5; + i2c6 = &i2c6; + mmc0 = &mmc0; + }; + + chosen: chosen { + stdout-path = "serial0:115200n8"; + }; + + memory@40000000 { + device_type = "memory"; + reg = <0 0x40000000 0 0x80000000>; + }; + + reserved_memory: reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + scp_mem_reserved: memory@50000000 { + compatible = "shared-dma-pool"; + reg = <0 0x50000000 0 0x2900000>; + no-map; + }; + }; +}; + +&auxadc { + status = "okay"; +}; + +&i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins>; + clock-frequency = <400000>; + status = "okay"; +}; + +&i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pins>; + clock-frequency = <400000>; + status = "okay"; +}; + +&i2c2 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c2_pins>; + clock-frequency = <400000>; + status = "okay"; +}; + +&i2c3 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c3_pins>; + clock-frequency = <400000>; + status = "okay"; +}; + +&i2c4 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c4_pins>; + clock-frequency = <400000>; + status = "okay"; +}; + +&i2c5 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c5_pins>; + clock-frequency = <400000>; + status = "okay"; +}; + +&i2c6 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c6_pins>; + clock-frequency = <400000>; + status = "okay"; +}; + +&mmc0 { + bus-width = <8>; + hs400-ds-delay = <0x1481b>; + max-frequency = <200000000>; + + cap-mmc-highspeed; + mmc-hs200-1_8v; + mmc-hs400-1_8v; + supports-cqe; + cap-mmc-hw-reset; + no-sdio; + no-sd; + non-removable; + + vmmc-supply = <&mt6359_vemc_1_ldo_reg>; + vqmmc-supply = <&mt6359_vufs_ldo_reg>; + + pinctrl-names = "default", "state_uhs"; + pinctrl-0 = <&mmc0_default_pins>; + pinctrl-1 = <&mmc0_uhs_pins>; + + status = "okay"; +}; + +&mt6359_vcore_buck_reg { + regulator-always-on; +}; + +&mt6359_vgpu11_buck_reg { + regulator-always-on; +}; + +&mt6359_vpu_buck_reg { + regulator-always-on; +}; + +&mt6359_vrf12_ldo_reg { + regulator-always-on; +}; + +&nor_flash { + pinctrl-names = "default"; + pinctrl-0 = <&nor_pins_default>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <52000000>; + }; +}; + +&pio { + adsp_uart_pins: adsp-uart-pins { + pins-tx-rx { + pinmux = , + ; + }; + }; + + i2c0_pins: i2c0-pins { + pins-bus { + pinmux = , + ; + bias-pull-up = ; + }; + }; + + i2c1_pins: i2c1-pins { + pins-bus { + pinmux = , + ; + bias-pull-up = ; + }; + }; + + i2c2_pins: i2c2-pins { + pins-bus { + pinmux = , + ; + bias-pull-up = ; + }; + }; + + i2c3_pins: i2c3-pins { + pins-bus { + pinmux = , + ; + bias-pull-up = ; + }; + }; + + i2c4_pins: i2c4-pins { + pins-bus { + pinmux = , + ; + bias-pull-up = ; + }; + }; + + i2c5_pins: i2c5-pins { + pins-bus { + pinmux = , + ; + bias-pull-up = ; + }; + }; + + i2c6_pins: i2c6-pins { + pins-bus { + pinmux = , + ; + bias-pull-up = ; + }; + }; + + mmc0_default_pins: mmc0-default-pins { + pins-cmd-dat { + pinmux = , + , + , + , + , + , + , + , + ; + input-enable; + drive-strength = <6>; + bias-pull-up = ; + }; + + pins-clk { + pinmux = ; + drive-strength = <6>; + bias-pull-down = ; + }; + + pins-rst { + pinmux = ; + drive-strength = <6>; + bias-pull-up = ; + }; + }; + + mmc0_uhs_pins: mmc0-uhs-pins { + pins-cmd-dat { + pinmux = , + , + , + , + , + , + , + , + ; + input-enable; + drive-strength = <8>; + bias-pull-up = ; + }; + + pins-clk-ds { + pinmux = , + ; + drive-strength = <8>; + bias-pull-down = ; + }; + + pins-rst { + pinmux = ; + drive-strength = <8>; + bias-pull-up = ; + }; + }; + + nor_pins_default: nor-pins { + pins-io-ck { + pinmux = , + , + ; + bias-pull-down; + }; + + pins-io-cs { + pinmux = , + , + ; + bias-pull-up; + }; + }; + + spi0_pins: spi0-pins { + pins-spi { + pinmux = , + , + , + ; + bias-disable; + }; + }; + + spi1_pins: spi1-pins { + pins-spi { + pinmux = , + , + , + ; + bias-disable; + }; + }; + + spi2_pins: spi2-pins { + pins-spi { + pinmux = , + , + , + ; + bias-disable; + }; + }; + + uart0_pins: uart0-pins { + pins-rx-tx { + pinmux = , + ; + bias-pull-up; + }; + }; +}; + +&pmic { + interrupts-extended = <&pio 222 IRQ_TYPE_LEVEL_HIGH>; +}; + +&scp { + memory-region = <&scp_mem_reserved>; + status = "okay"; +}; + +&spi0 { + pinctrl-names = "default"; + pinctrl-0 = <&spi0_pins>; + status = "okay"; +}; + +&spi1 { + pinctrl-names = "default"; + pinctrl-0 = <&spi1_pins>; + status = "okay"; +}; + +&spi2 { + pinctrl-names = "default"; + pinctrl-0 = <&spi2_pins>; + status = "okay"; +}; + +&u3phy0 { + status = "okay"; +}; + +&u3phy1 { + status = "okay"; +}; + +&u3phy2 { + status = "okay"; +}; + +&uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins>; + status = "okay"; +}; + +&xhci0 { + status = "okay"; +}; + +&xhci1 { + status = "okay"; +}; + +&xhci2 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt8188.dtsi b/arch/arm64/boot/dts/mediatek/mt8188.dtsi new file mode 100644 index 00000000000000..b4315c9214dc51 --- /dev/null +++ b/arch/arm64/boot/dts/mediatek/mt8188.dtsi @@ -0,0 +1,956 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023 MediaTek Inc. + * + */ + +/dts-v1/; +#include +#include +#include +#include +#include +#include + +/ { + compatible = "mediatek,mt8188"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x000>; + enable-method = "psci"; + clock-frequency = <2000000000>; + capacity-dmips-mhz = <282>; + cpu-idle-states = <&cpu_off_l &cluster_off_l>; + i-cache-size = <32768>; + i-cache-line-size = <64>; + i-cache-sets = <128>; + d-cache-size = <32768>; + d-cache-line-size = <64>; + d-cache-sets = <128>; + next-level-cache = <&l2_0>; + #cooling-cells = <2>; + }; + + cpu1: cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x100>; + enable-method = "psci"; + clock-frequency = <2000000000>; + capacity-dmips-mhz = <282>; + cpu-idle-states = <&cpu_off_l &cluster_off_l>; + i-cache-size = <32768>; + i-cache-line-size = <64>; + i-cache-sets = <128>; + d-cache-size = <32768>; + d-cache-line-size = <64>; + d-cache-sets = <128>; + next-level-cache = <&l2_0>; + #cooling-cells = <2>; + }; + + cpu2: cpu@200 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x200>; + enable-method = "psci"; + clock-frequency = <2000000000>; + capacity-dmips-mhz = <282>; + cpu-idle-states = <&cpu_off_l &cluster_off_l>; + i-cache-size = <32768>; + i-cache-line-size = <64>; + i-cache-sets = <128>; + d-cache-size = <32768>; + d-cache-line-size = <64>; + d-cache-sets = <128>; + next-level-cache = <&l2_0>; + #cooling-cells = <2>; + }; + + cpu3: cpu@300 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x300>; + enable-method = "psci"; + clock-frequency = <2000000000>; + capacity-dmips-mhz = <282>; + cpu-idle-states = <&cpu_off_l &cluster_off_l>; + i-cache-size = <32768>; + i-cache-line-size = <64>; + i-cache-sets = <128>; + d-cache-size = <32768>; + d-cache-line-size = <64>; + d-cache-sets = <128>; + next-level-cache = <&l2_0>; + #cooling-cells = <2>; + }; + + cpu4: cpu@400 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x400>; + enable-method = "psci"; + clock-frequency = <2000000000>; + capacity-dmips-mhz = <282>; + cpu-idle-states = <&cpu_off_l &cluster_off_l>; + i-cache-size = <32768>; + i-cache-line-size = <64>; + i-cache-sets = <128>; + d-cache-size = <32768>; + d-cache-line-size = <64>; + d-cache-sets = <128>; + next-level-cache = <&l2_0>; + #cooling-cells = <2>; + }; + + cpu5: cpu@500 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x500>; + enable-method = "psci"; + clock-frequency = <2000000000>; + capacity-dmips-mhz = <282>; + cpu-idle-states = <&cpu_off_l &cluster_off_l>; + i-cache-size = <32768>; + i-cache-line-size = <64>; + i-cache-sets = <128>; + d-cache-size = <32768>; + d-cache-line-size = <64>; + d-cache-sets = <128>; + next-level-cache = <&l2_0>; + #cooling-cells = <2>; + }; + + cpu6: cpu@600 { + device_type = "cpu"; + compatible = "arm,cortex-a78"; + reg = <0x600>; + enable-method = "psci"; + clock-frequency = <2600000000>; + capacity-dmips-mhz = <1024>; + cpu-idle-states = <&cpu_off_b &cluster_off_b>; + i-cache-size = <65536>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <65536>; + d-cache-line-size = <64>; + d-cache-sets = <256>; + next-level-cache = <&l2_1>; + #cooling-cells = <2>; + }; + + cpu7: cpu@700 { + device_type = "cpu"; + compatible = "arm,cortex-a78"; + reg = <0x700>; + enable-method = "psci"; + clock-frequency = <2600000000>; + capacity-dmips-mhz = <1024>; + cpu-idle-states = <&cpu_off_b &cluster_off_b>; + i-cache-size = <65536>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <65536>; + d-cache-line-size = <64>; + d-cache-sets = <256>; + next-level-cache = <&l2_1>; + #cooling-cells = <2>; + }; + + cpu-map { + cluster0 { + core0 { + cpu = <&cpu0>; + }; + + core1 { + cpu = <&cpu1>; + }; + + core2 { + cpu = <&cpu2>; + }; + + core3 { + cpu = <&cpu3>; + }; + + core4 { + cpu = <&cpu4>; + }; + + core5 { + cpu = <&cpu5>; + }; + + core6 { + cpu = <&cpu6>; + }; + + core7 { + cpu = <&cpu7>; + }; + }; + }; + + idle-states { + entry-method = "psci"; + + cpu_off_l: cpu-off-l { + compatible = "arm,idle-state"; + arm,psci-suspend-param = <0x00010000>; + local-timer-stop; + entry-latency-us = <50>; + exit-latency-us = <95>; + min-residency-us = <580>; + }; + + cpu_off_b: cpu-off-b { + compatible = "arm,idle-state"; + arm,psci-suspend-param = <0x00010000>; + local-timer-stop; + entry-latency-us = <45>; + exit-latency-us = <140>; + min-residency-us = <740>; + }; + + cluster_off_l: cluster-off-l { + compatible = "arm,idle-state"; + arm,psci-suspend-param = <0x01010010>; + local-timer-stop; + entry-latency-us = <55>; + exit-latency-us = <155>; + min-residency-us = <840>; + }; + + cluster_off_b: cluster-off-b { + compatible = "arm,idle-state"; + arm,psci-suspend-param = <0x01010010>; + local-timer-stop; + entry-latency-us = <50>; + exit-latency-us = <200>; + min-residency-us = <1000>; + }; + }; + + l2_0: l2-cache0 { + compatible = "cache"; + cache-level = <2>; + cache-size = <131072>; + cache-line-size = <64>; + cache-sets = <512>; + next-level-cache = <&l3_0>; + cache-unified; + }; + + l2_1: l2-cache1 { + compatible = "cache"; + cache-level = <2>; + cache-size = <262144>; + cache-line-size = <64>; + cache-sets = <512>; + next-level-cache = <&l3_0>; + cache-unified; + }; + + l3_0: l3-cache { + compatible = "cache"; + cache-level = <3>; + cache-size = <2097152>; + cache-line-size = <64>; + cache-sets = <2048>; + cache-unified; + }; + }; + + clk13m: oscillator-13m { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <13000000>; + clock-output-names = "clk13m"; + }; + + clk26m: oscillator-26m { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <26000000>; + clock-output-names = "clk26m"; + }; + + clk32k: oscillator-32k { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <32768>; + clock-output-names = "clk32k"; + }; + + pmu-a55 { + compatible = "arm,cortex-a55-pmu"; + interrupt-parent = <&gic>; + interrupts = ; + }; + + pmu-a78 { + compatible = "arm,cortex-a78-pmu"; + interrupt-parent = <&gic>; + interrupts = ; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + }; + + timer: timer { + compatible = "arm,armv8-timer"; + interrupt-parent = <&gic>; + interrupts = , + , + , + ; + clock-frequency = <13000000>; + }; + + soc { + #address-cells = <2>; + #size-cells = <2>; + compatible = "simple-bus"; + ranges; + + gic: interrupt-controller@c000000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <4>; + #redistributor-regions = <1>; + interrupt-parent = <&gic>; + interrupt-controller; + reg = <0 0x0c000000 0 0x40000>, + <0 0x0c040000 0 0x200000>; + interrupts = ; + + ppi-partitions { + ppi_cluster0: interrupt-partition-0 { + affinity = <&cpu0 &cpu1 &cpu2 &cpu3 &cpu4 &cpu5>; + }; + + ppi_cluster1: interrupt-partition-1 { + affinity = <&cpu6 &cpu7>; + }; + }; + }; + + topckgen: syscon@10000000 { + compatible = "mediatek,mt8188-topckgen", "syscon"; + reg = <0 0x10000000 0 0x1000>; + #clock-cells = <1>; + }; + + infracfg_ao: syscon@10001000 { + compatible = "mediatek,mt8188-infracfg-ao", "syscon"; + reg = <0 0x10001000 0 0x1000>; + #clock-cells = <1>; + }; + + pericfg: syscon@10003000 { + compatible = "mediatek,mt8188-pericfg", "syscon"; + reg = <0 0x10003000 0 0x1000>; + #clock-cells = <1>; + }; + + pio: pinctrl@10005000 { + compatible = "mediatek,mt8188-pinctrl"; + reg = <0 0x10005000 0 0x1000>, + <0 0x11c00000 0 0x1000>, + <0 0x11e10000 0 0x1000>, + <0 0x11e20000 0 0x1000>, + <0 0x11ea0000 0 0x1000>, + <0 0x1000b000 0 0x1000>; + reg-names = "iocfg0", "iocfg_rm", "iocfg_lt", + "iocfg_lm", "iocfg_rt", "eint"; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pio 0 0 176>; + interrupt-controller; + interrupts = ; + #interrupt-cells = <2>; + }; + + watchdog: watchdog@10007000 { + compatible = "mediatek,mt8188-wdt"; + reg = <0 0x10007000 0 0x100>; + mediatek,disable-extrst; + #reset-cells = <1>; + }; + + apmixedsys: syscon@1000c000 { + compatible = "mediatek,mt8188-apmixedsys", "syscon"; + reg = <0 0x1000c000 0 0x1000>; + #clock-cells = <1>; + }; + + systimer: timer@10017000 { + compatible = "mediatek,mt8188-timer", "mediatek,mt6765-timer"; + reg = <0 0x10017000 0 0x1000>; + interrupts = ; + clocks = <&clk13m>; + }; + + pwrap: pwrap@10024000 { + compatible = "mediatek,mt8188-pwrap", "mediatek,mt8195-pwrap", "syscon"; + reg = <0 0x10024000 0 0x1000>; + reg-names = "pwrap"; + interrupts = ; + clocks = <&infracfg_ao CLK_INFRA_AO_PMIC_AP>, + <&infracfg_ao CLK_INFRA_AO_PMIC_TMR>; + clock-names = "spi", "wrap"; + }; + + scp: scp@10500000 { + compatible = "mediatek,mt8188-scp"; + reg = <0 0x10500000 0 0x100000>, + <0 0x10720000 0 0xe0000>; + reg-names = "sram", "cfg"; + interrupts = ; + }; + + adsp_audio26m: clock-controller@10b91100 { + compatible = "mediatek,mt8188-adsp-audio26m"; + reg = <0 0x10b91100 0 0x100>; + #clock-cells = <1>; + }; + + uart0: serial@11001100 { + compatible = "mediatek,mt8188-uart", "mediatek,mt6577-uart"; + reg = <0 0x11001100 0 0x100>; + interrupts = ; + clocks = <&clk26m>, <&infracfg_ao CLK_INFRA_AO_UART0>; + clock-names = "baud", "bus"; + status = "disabled"; + }; + + uart1: serial@11001200 { + compatible = "mediatek,mt8188-uart", "mediatek,mt6577-uart"; + reg = <0 0x11001200 0 0x100>; + interrupts = ; + clocks = <&clk26m>, <&infracfg_ao CLK_INFRA_AO_UART1>; + clock-names = "baud", "bus"; + status = "disabled"; + }; + + uart2: serial@11001300 { + compatible = "mediatek,mt8188-uart", "mediatek,mt6577-uart"; + reg = <0 0x11001300 0 0x100>; + interrupts = ; + clocks = <&clk26m>, <&infracfg_ao CLK_INFRA_AO_UART2>; + clock-names = "baud", "bus"; + status = "disabled"; + }; + + uart3: serial@11001400 { + compatible = "mediatek,mt8188-uart", "mediatek,mt6577-uart"; + reg = <0 0x11001400 0 0x100>; + interrupts = ; + clocks = <&clk26m>, <&infracfg_ao CLK_INFRA_AO_UART3>; + clock-names = "baud", "bus"; + status = "disabled"; + }; + + auxadc: adc@11002000 { + compatible = "mediatek,mt8188-auxadc", "mediatek,mt8173-auxadc"; + reg = <0 0x11002000 0 0x1000>; + clocks = <&infracfg_ao CLK_INFRA_AO_AUXADC>; + clock-names = "main"; + #io-channel-cells = <1>; + status = "disabled"; + }; + + pericfg_ao: syscon@11003000 { + compatible = "mediatek,mt8188-pericfg-ao", "syscon"; + reg = <0 0x11003000 0 0x1000>; + #clock-cells = <1>; + }; + + spi0: spi@1100a000 { + compatible = "mediatek,mt8188-spi-ipm", "mediatek,spi-ipm"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0 0x1100a000 0 0x1000>; + interrupts = ; + clocks = <&topckgen CLK_TOP_UNIVPLL_D6_D2>, + <&topckgen CLK_TOP_SPI>, + <&infracfg_ao CLK_INFRA_AO_SPI0>; + clock-names = "parent-clk", "sel-clk", "spi-clk"; + status = "disabled"; + }; + + spi1: spi@11010000 { + compatible = "mediatek,mt8188-spi-ipm", "mediatek,spi-ipm"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0 0x11010000 0 0x1000>; + interrupts = ; + clocks = <&topckgen CLK_TOP_UNIVPLL_D6_D2>, + <&topckgen CLK_TOP_SPI>, + <&infracfg_ao CLK_INFRA_AO_SPI1>; + clock-names = "parent-clk", "sel-clk", "spi-clk"; + status = "disabled"; + }; + + spi2: spi@11012000 { + compatible = "mediatek,mt8188-spi-ipm", "mediatek,spi-ipm"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0 0x11012000 0 0x1000>; + interrupts = ; + clocks = <&topckgen CLK_TOP_UNIVPLL_D6_D2>, + <&topckgen CLK_TOP_SPI>, + <&infracfg_ao CLK_INFRA_AO_SPI2>; + clock-names = "parent-clk", "sel-clk", "spi-clk"; + status = "disabled"; + }; + + spi3: spi@11013000 { + compatible = "mediatek,mt8188-spi-ipm", "mediatek,spi-ipm"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0 0x11013000 0 0x1000>; + interrupts = ; + clocks = <&topckgen CLK_TOP_UNIVPLL_D6_D2>, + <&topckgen CLK_TOP_SPI>, + <&infracfg_ao CLK_INFRA_AO_SPI3>; + clock-names = "parent-clk", "sel-clk", "spi-clk"; + status = "disabled"; + }; + + spi4: spi@11018000 { + compatible = "mediatek,mt8188-spi-ipm", "mediatek,spi-ipm"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0 0x11018000 0 0x1000>; + interrupts = ; + clocks = <&topckgen CLK_TOP_UNIVPLL_D6_D2>, + <&topckgen CLK_TOP_SPI>, + <&infracfg_ao CLK_INFRA_AO_SPI4>; + clock-names = "parent-clk", "sel-clk", "spi-clk"; + status = "disabled"; + }; + + spi5: spi@11019000 { + compatible = "mediatek,mt8188-spi-ipm", "mediatek,spi-ipm"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0 0x11019000 0 0x1000>; + interrupts = ; + clocks = <&topckgen CLK_TOP_UNIVPLL_D6_D2>, + <&topckgen CLK_TOP_SPI>, + <&infracfg_ao CLK_INFRA_AO_SPI5>; + clock-names = "parent-clk", "sel-clk", "spi-clk"; + status = "disabled"; + }; + + xhci1: usb@11200000 { + compatible = "mediatek,mt8188-xhci", "mediatek,mtk-xhci"; + reg = <0 0x11200000 0 0x1000>, + <0 0x11203e00 0 0x0100>; + reg-names = "mac", "ippc"; + interrupts = ; + phys = <&u2port1 PHY_TYPE_USB2>, + <&u3port1 PHY_TYPE_USB3>; + assigned-clocks = <&topckgen CLK_TOP_USB_TOP>, + <&topckgen CLK_TOP_SSUSB_XHCI>; + assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL_D5_D4>, + <&topckgen CLK_TOP_UNIVPLL_D5_D4>; + clocks = <&pericfg_ao CLK_PERI_AO_SSUSB_BUS>, + <&topckgen CLK_TOP_SSUSB_TOP_REF>, + <&pericfg_ao CLK_PERI_AO_SSUSB_XHCI>; + clock-names = "sys_ck", "ref_ck", "mcu_ck"; + mediatek,syscon-wakeup = <&pericfg 0x468 2>; + wakeup-source; + status = "disabled"; + }; + + mmc0: mmc@11230000 { + compatible = "mediatek,mt8188-mmc", "mediatek,mt8183-mmc"; + reg = <0 0x11230000 0 0x10000>, + <0 0x11f50000 0 0x1000>; + interrupts = ; + clocks = <&topckgen CLK_TOP_MSDC50_0>, + <&infracfg_ao CLK_INFRA_AO_MSDC0>, + <&infracfg_ao CLK_INFRA_AO_MSDC0_SRC>, + <&infracfg_ao CLK_INFRA_AO_RG_AES_MSDCFDE_CK_0P>; + clock-names = "source", "hclk", "source_cg", "crypto_clk"; + status = "disabled"; + }; + + mmc1: mmc@11240000 { + compatible = "mediatek,mt8188-mmc", "mediatek,mt8183-mmc"; + reg = <0 0x11240000 0 0x1000>, + <0 0x11eb0000 0 0x1000>; + interrupts = ; + clocks = <&topckgen CLK_TOP_MSDC30_1>, + <&infracfg_ao CLK_INFRA_AO_MSDC1>, + <&infracfg_ao CLK_INFRA_AO_MSDC1_SRC>; + clock-names = "source", "hclk", "source_cg"; + assigned-clocks = <&topckgen CLK_TOP_MSDC30_1>; + assigned-clock-parents = <&topckgen CLK_TOP_MSDCPLL_D2>; + status = "disabled"; + }; + + i2c0: i2c@11280000 { + compatible = "mediatek,mt8188-i2c"; + reg = <0 0x11280000 0 0x1000>, + <0 0x10220080 0 0x80>; + interrupts = ; + clock-div = <1>; + clocks = <&imp_iic_wrap_c CLK_IMP_IIC_WRAP_C_AP_CLOCK_I2C0>, + <&infracfg_ao CLK_INFRA_AO_APDMA_BCLK>; + clock-names = "main", "dma"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c2: i2c@11281000 { + compatible = "mediatek,mt8188-i2c"; + reg = <0 0x11281000 0 0x1000>, + <0 0x10220180 0 0x80>; + interrupts = ; + clock-div = <1>; + clocks = <&imp_iic_wrap_c CLK_IMP_IIC_WRAP_C_AP_CLOCK_I2C2>, + <&infracfg_ao CLK_INFRA_AO_APDMA_BCLK>; + clock-names = "main", "dma"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c3: i2c@11282000 { + compatible = "mediatek,mt8188-i2c"; + reg = <0 0x11282000 0 0x1000>, + <0 0x10220280 0 0x80>; + interrupts = ; + clock-div = <1>; + clocks = <&imp_iic_wrap_c CLK_IMP_IIC_WRAP_C_AP_CLOCK_I2C3>, + <&infracfg_ao CLK_INFRA_AO_APDMA_BCLK>; + clock-names = "main", "dma"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + imp_iic_wrap_c: clock-controller@11283000 { + compatible = "mediatek,mt8188-imp-iic-wrap-c"; + reg = <0 0x11283000 0 0x1000>; + #clock-cells = <1>; + }; + + xhci2: usb@112a0000 { + compatible = "mediatek,mt8188-xhci", "mediatek,mtk-xhci"; + reg = <0 0x112a0000 0 0x1000>, + <0 0x112a3e00 0 0x0100>; + reg-names = "mac", "ippc"; + interrupts = ; + phys = <&u2port2 PHY_TYPE_USB2>; + assigned-clocks = <&topckgen CLK_TOP_SSUSB_XHCI_3P>, + <&topckgen CLK_TOP_USB_TOP_3P>; + assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL_D5_D4>, + <&topckgen CLK_TOP_UNIVPLL_D5_D4>; + clocks = <&pericfg_ao CLK_PERI_AO_SSUSB_3P_BUS>, + <&topckgen CLK_TOP_SSUSB_TOP_P3_REF>, + <&pericfg_ao CLK_PERI_AO_SSUSB_3P_XHCI>; + clock-names = "sys_ck", "ref_ck", "mcu_ck"; + status = "disabled"; + }; + + xhci0: usb@112b0000 { + compatible = "mediatek,mt8188-xhci", "mediatek,mtk-xhci"; + reg = <0 0x112b0000 0 0x1000>, + <0 0x112b3e00 0 0x0100>; + reg-names = "mac", "ippc"; + interrupts = ; + phys = <&u2port0 PHY_TYPE_USB2>; + assigned-clocks = <&topckgen CLK_TOP_SSUSB_XHCI_2P>, + <&topckgen CLK_TOP_USB_TOP_2P>; + assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL_D5_D4>, + <&topckgen CLK_TOP_UNIVPLL_D5_D4>; + clocks = <&pericfg_ao CLK_PERI_AO_SSUSB_2P_BUS>, + <&topckgen CLK_TOP_SSUSB_TOP_P2_REF>, + <&pericfg_ao CLK_PERI_AO_SSUSB_2P_XHCI>; + clock-names = "sys_ck", "ref_ck", "mcu_ck"; + mediatek,syscon-wakeup = <&pericfg 0x460 2>; + wakeup-source; + status = "disabled"; + }; + + nor_flash: spi@1132c000 { + compatible = "mediatek,mt8188-nor", "mediatek,mt8186-nor"; + reg = <0 0x1132c000 0 0x1000>; + clocks = <&topckgen CLK_TOP_SPINOR>, + <&pericfg_ao CLK_PERI_AO_FLASHIFLASHCK>, + <&pericfg_ao CLK_PERI_AO_FLASHIF_BUS>; + clock-names = "spi", "sf", "axi"; + assigned-clocks = <&topckgen CLK_TOP_SPINOR>; + interrupts = ; + status = "disabled"; + }; + + i2c1: i2c@11e00000 { + compatible = "mediatek,mt8188-i2c"; + reg = <0 0x11e00000 0 0x1000>, + <0 0x10220100 0 0x80>; + interrupts = ; + clock-div = <1>; + clocks = <&imp_iic_wrap_w CLK_IMP_IIC_WRAP_W_AP_CLOCK_I2C1>, + <&infracfg_ao CLK_INFRA_AO_APDMA_BCLK>; + clock-names = "main", "dma"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c4: i2c@11e01000 { + compatible = "mediatek,mt8188-i2c"; + reg = <0 0x11e01000 0 0x1000>, + <0 0x10220380 0 0x80>; + interrupts = ; + clock-div = <1>; + clocks = <&imp_iic_wrap_w CLK_IMP_IIC_WRAP_W_AP_CLOCK_I2C4>, + <&infracfg_ao CLK_INFRA_AO_APDMA_BCLK>; + clock-names = "main", "dma"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + imp_iic_wrap_w: clock-controller@11e02000 { + compatible = "mediatek,mt8188-imp-iic-wrap-w"; + reg = <0 0x11e02000 0 0x1000>; + #clock-cells = <1>; + }; + + u3phy0: t-phy@11e30000 { + compatible = "mediatek,mt8188-tphy", "mediatek,generic-tphy-v3"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x0 0x11e30000 0x1000>; + status = "disabled"; + + u2port0: usb-phy@0 { + reg = <0x0 0x700>; + clocks = <&topckgen CLK_TOP_SSUSB_PHY_P2_REF>, + <&apmixedsys CLK_APMIXED_PLL_SSUSB26M_EN>; + clock-names = "ref", "da_ref"; + #phy-cells = <1>; + }; + }; + + u3phy1: t-phy@11e40000 { + compatible = "mediatek,mt8188-tphy", "mediatek,generic-tphy-v3"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x0 0x11e40000 0x1000>; + status = "disabled"; + + u2port1: usb-phy@0 { + reg = <0x0 0x700>; + clocks = <&topckgen CLK_TOP_SSUSB_PHY_REF>, + <&apmixedsys CLK_APMIXED_PLL_SSUSB26M_EN>; + clock-names = "ref", "da_ref"; + #phy-cells = <1>; + }; + + u3port1: usb-phy@700 { + reg = <0x700 0x700>; + clocks = <&apmixedsys CLK_APMIXED_PLL_SSUSB26M_EN>, + <&clk26m>; + clock-names = "ref", "da_ref"; + #phy-cells = <1>; + status = "disabled"; + }; + }; + + u3phy2: t-phy@11e80000 { + compatible = "mediatek,mt8188-tphy", "mediatek,generic-tphy-v3"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x0 0x11e80000 0x1000>; + status = "disabled"; + + u2port2: usb-phy@0 { + reg = <0x0 0x700>; + clocks = <&topckgen CLK_TOP_SSUSB_PHY_P3_REF>, + <&apmixedsys CLK_APMIXED_PLL_SSUSB26M_EN>; + clock-names = "ref", "da_ref"; + #phy-cells = <1>; + }; + }; + + i2c5: i2c@11ec0000 { + compatible = "mediatek,mt8188-i2c"; + reg = <0 0x11ec0000 0 0x1000>, + <0 0x10220480 0 0x80>; + interrupts = ; + clock-div = <1>; + clocks = <&imp_iic_wrap_en CLK_IMP_IIC_WRAP_EN_AP_CLOCK_I2C5>, + <&infracfg_ao CLK_INFRA_AO_APDMA_BCLK>; + clock-names = "main", "dma"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c6: i2c@11ec1000 { + compatible = "mediatek,mt8188-i2c"; + reg = <0 0x11ec1000 0 0x1000>, + <0 0x10220600 0 0x80>; + interrupts = ; + clock-div = <1>; + clocks = <&imp_iic_wrap_en CLK_IMP_IIC_WRAP_EN_AP_CLOCK_I2C6>, + <&infracfg_ao CLK_INFRA_AO_APDMA_BCLK>; + clock-names = "main", "dma"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + imp_iic_wrap_en: clock-controller@11ec2000 { + compatible = "mediatek,mt8188-imp-iic-wrap-en"; + reg = <0 0x11ec2000 0 0x1000>; + #clock-cells = <1>; + }; + + mfgcfg: clock-controller@13fbf000 { + compatible = "mediatek,mt8188-mfgcfg"; + reg = <0 0x13fbf000 0 0x1000>; + #clock-cells = <1>; + }; + + vppsys0: clock-controller@14000000 { + compatible = "mediatek,mt8188-vppsys0"; + reg = <0 0x14000000 0 0x1000>; + #clock-cells = <1>; + }; + + wpesys: clock-controller@14e00000 { + compatible = "mediatek,mt8188-wpesys"; + reg = <0 0x14e00000 0 0x1000>; + #clock-cells = <1>; + }; + + wpesys_vpp0: clock-controller@14e02000 { + compatible = "mediatek,mt8188-wpesys-vpp0"; + reg = <0 0x14e02000 0 0x1000>; + #clock-cells = <1>; + }; + + vppsys1: clock-controller@14f00000 { + compatible = "mediatek,mt8188-vppsys1"; + reg = <0 0x14f00000 0 0x1000>; + #clock-cells = <1>; + }; + + imgsys: clock-controller@15000000 { + compatible = "mediatek,mt8188-imgsys"; + reg = <0 0x15000000 0 0x1000>; + #clock-cells = <1>; + }; + + imgsys1_dip_top: clock-controller@15110000 { + compatible = "mediatek,mt8188-imgsys1-dip-top"; + reg = <0 0x15110000 0 0x1000>; + #clock-cells = <1>; + }; + + imgsys1_dip_nr: clock-controller@15130000 { + compatible = "mediatek,mt8188-imgsys1-dip-nr"; + reg = <0 0x15130000 0 0x1000>; + #clock-cells = <1>; + }; + + imgsys_wpe1: clock-controller@15220000 { + compatible = "mediatek,mt8188-imgsys-wpe1"; + reg = <0 0x15220000 0 0x1000>; + #clock-cells = <1>; + }; + + ipesys: clock-controller@15330000 { + compatible = "mediatek,mt8188-ipesys"; + reg = <0 0x15330000 0 0x1000>; + #clock-cells = <1>; + }; + + imgsys_wpe2: clock-controller@15520000 { + compatible = "mediatek,mt8188-imgsys-wpe2"; + reg = <0 0x15520000 0 0x1000>; + #clock-cells = <1>; + }; + + imgsys_wpe3: clock-controller@15620000 { + compatible = "mediatek,mt8188-imgsys-wpe3"; + reg = <0 0x15620000 0 0x1000>; + #clock-cells = <1>; + }; + + camsys: clock-controller@16000000 { + compatible = "mediatek,mt8188-camsys"; + reg = <0 0x16000000 0 0x1000>; + #clock-cells = <1>; + }; + + camsys_rawa: clock-controller@1604f000 { + compatible = "mediatek,mt8188-camsys-rawa"; + reg = <0 0x1604f000 0 0x1000>; + #clock-cells = <1>; + }; + + camsys_yuva: clock-controller@1606f000 { + compatible = "mediatek,mt8188-camsys-yuva"; + reg = <0 0x1606f000 0 0x1000>; + #clock-cells = <1>; + }; + + camsys_rawb: clock-controller@1608f000 { + compatible = "mediatek,mt8188-camsys-rawb"; + reg = <0 0x1608f000 0 0x1000>; + #clock-cells = <1>; + }; + + camsys_yuvb: clock-controller@160af000 { + compatible = "mediatek,mt8188-camsys-yuvb"; + reg = <0 0x160af000 0 0x1000>; + #clock-cells = <1>; + }; + + ccusys: clock-controller@17200000 { + compatible = "mediatek,mt8188-ccusys"; + reg = <0 0x17200000 0 0x1000>; + #clock-cells = <1>; + }; + + vdecsys_soc: clock-controller@1800f000 { + compatible = "mediatek,mt8188-vdecsys-soc"; + reg = <0 0x1800f000 0 0x1000>; + #clock-cells = <1>; + }; + + vdecsys: clock-controller@1802f000 { + compatible = "mediatek,mt8188-vdecsys"; + reg = <0 0x1802f000 0 0x1000>; + #clock-cells = <1>; + }; + + vencsys: clock-controller@1a000000 { + compatible = "mediatek,mt8188-vencsys"; + reg = <0 0x1a000000 0 0x1000>; + #clock-cells = <1>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/mediatek/mt8192-asurada.dtsi b/arch/arm64/boot/dts/mediatek/mt8192-asurada.dtsi index f2281250ac35da..d87aab8d7a79ed 100644 --- a/arch/arm64/boot/dts/mediatek/mt8192-asurada.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8192-asurada.dtsi @@ -1402,7 +1402,7 @@ pinctrl-names = "default"; pinctrl-0 = <&spi5_pins>; - cr50@0 { + tpm@0 { compatible = "google,cr50"; reg = <0>; interrupts-extended = <&pio 171 IRQ_TYPE_EDGE_RISING>; diff --git a/arch/arm64/boot/dts/mediatek/mt8192.dtsi b/arch/arm64/boot/dts/mediatek/mt8192.dtsi index 69f4cded5dbbf2..6dd32dbfb832e7 100644 --- a/arch/arm64/boot/dts/mediatek/mt8192.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8192.dtsi @@ -14,6 +14,8 @@ #include #include #include +#include +#include / { compatible = "mediatek,mt8192"; @@ -72,6 +74,7 @@ next-level-cache = <&l2_0>; performance-domains = <&performance 0>; capacity-dmips-mhz = <427>; + #cooling-cells = <2>; }; cpu1: cpu@100 { @@ -90,6 +93,7 @@ next-level-cache = <&l2_0>; performance-domains = <&performance 0>; capacity-dmips-mhz = <427>; + #cooling-cells = <2>; }; cpu2: cpu@200 { @@ -108,6 +112,7 @@ next-level-cache = <&l2_0>; performance-domains = <&performance 0>; capacity-dmips-mhz = <427>; + #cooling-cells = <2>; }; cpu3: cpu@300 { @@ -126,6 +131,7 @@ next-level-cache = <&l2_0>; performance-domains = <&performance 0>; capacity-dmips-mhz = <427>; + #cooling-cells = <2>; }; cpu4: cpu@400 { @@ -144,6 +150,7 @@ next-level-cache = <&l2_1>; performance-domains = <&performance 1>; capacity-dmips-mhz = <1024>; + #cooling-cells = <2>; }; cpu5: cpu@500 { @@ -162,6 +169,7 @@ next-level-cache = <&l2_1>; performance-domains = <&performance 1>; capacity-dmips-mhz = <1024>; + #cooling-cells = <2>; }; cpu6: cpu@600 { @@ -180,6 +188,7 @@ next-level-cache = <&l2_1>; performance-domains = <&performance 1>; capacity-dmips-mhz = <1024>; + #cooling-cells = <2>; }; cpu7: cpu@700 { @@ -198,6 +207,7 @@ next-level-cache = <&l2_1>; performance-domains = <&performance 1>; capacity-dmips-mhz = <1024>; + #cooling-cells = <2>; }; cpu-map { @@ -788,6 +798,29 @@ status = "disabled"; }; + lvts_ap: thermal-sensor@1100b000 { + compatible = "mediatek,mt8192-lvts-ap"; + reg = <0 0x1100b000 0 0xc00>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_THERM>; + resets = <&infracfg MT8192_INFRA_RST0_THERM_CTRL_SWRST>; + nvmem-cells = <&lvts_e_data1>; + nvmem-cell-names = "lvts-calib-data-1"; + #thermal-sensor-cells = <1>; + }; + + svs: svs@1100bc00 { + compatible = "mediatek,mt8192-svs"; + reg = <0 0x1100bc00 0 0x400>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_THERM>; + clock-names = "main"; + nvmem-cells = <&svs_calibration>, <&lvts_e_data1>; + nvmem-cell-names = "svs-calibration-data", "t-calibration-data"; + resets = <&infracfg MT8192_INFRA_RST3_THERM_CTRL_PTP_SWRST>; + reset-names = "svs_rst"; + }; + pwm0: pwm@1100e000 { compatible = "mediatek,mt8183-disp-pwm"; reg = <0 0x1100e000 0 0x1000>; @@ -1114,6 +1147,17 @@ status = "disabled"; }; + lvts_mcu: thermal-sensor@11278000 { + compatible = "mediatek,mt8192-lvts-mcu"; + reg = <0 0x11278000 0 0x1000>; + interrupts = ; + clocks = <&infracfg CLK_INFRA_THERM>; + resets = <&infracfg MT8192_INFRA_RST4_THERM_CTRL_MCU_SWRST>; + nvmem-cells = <&lvts_e_data1>; + nvmem-cell-names = "lvts-calib-data-1"; + #thermal-sensor-cells = <1>; + }; + efuse: efuse@11c10000 { compatible = "mediatek,mt8192-efuse", "mediatek,efuse"; reg = <0 0x11c10000 0 0x1000>; @@ -1899,4 +1943,426 @@ power-domains = <&spm MT8192_POWER_DOMAIN_MDP>; }; }; + + thermal_zones: thermal-zones { + cpu0-thermal { + polling-delay = <1000>; + polling-delay-passive = <250>; + thermal-sensors = <&lvts_mcu MT8192_MCU_LITTLE_CPU0>; + + trips { + cpu0_alert: trip-alert { + temperature = <85000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu0_crit: trip-crit { + temperature = <100000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu0_alert>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + + cpu1-thermal { + polling-delay = <1000>; + polling-delay-passive = <250>; + thermal-sensors = <&lvts_mcu MT8192_MCU_LITTLE_CPU1>; + + trips { + cpu1_alert: trip-alert { + temperature = <85000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu1_crit: trip-crit { + temperature = <100000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu1_alert>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + + cpu2-thermal { + polling-delay = <1000>; + polling-delay-passive = <250>; + thermal-sensors = <&lvts_mcu MT8192_MCU_LITTLE_CPU2>; + + trips { + cpu2_alert: trip-alert { + temperature = <85000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu2_crit: trip-crit { + temperature = <100000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu2_alert>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + + cpu3-thermal { + polling-delay = <1000>; + polling-delay-passive = <250>; + thermal-sensors = <&lvts_mcu MT8192_MCU_LITTLE_CPU3>; + + trips { + cpu3_alert: trip-alert { + temperature = <85000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu3_crit: trip-crit { + temperature = <100000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu3_alert>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + + cpu4-thermal { + polling-delay = <1000>; + polling-delay-passive = <250>; + thermal-sensors = <&lvts_mcu MT8192_MCU_BIG_CPU0>; + + trips { + cpu4_alert: trip-alert { + temperature = <85000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu4_crit: trip-crit { + temperature = <100000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu4_alert>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + + cpu5-thermal { + polling-delay = <1000>; + polling-delay-passive = <250>; + thermal-sensors = <&lvts_mcu MT8192_MCU_BIG_CPU1>; + + trips { + cpu5_alert: trip-alert { + temperature = <85000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu5_crit: trip-crit { + temperature = <100000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu5_alert>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + + cpu6-thermal { + polling-delay = <1000>; + polling-delay-passive = <250>; + thermal-sensors = <&lvts_mcu MT8192_MCU_BIG_CPU2>; + + trips { + cpu6_alert: trip-alert { + temperature = <85000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu6_crit: trip-crit { + temperature = <100000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu6_alert>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + + cpu7-thermal { + polling-delay = <1000>; + polling-delay-passive = <250>; + thermal-sensors = <&lvts_mcu MT8192_MCU_BIG_CPU3>; + + trips { + cpu7_alert: trip-alert { + temperature = <85000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu7_crit: trip-crit { + temperature = <100000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu7_alert>; + cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>, + <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; + }; + }; + }; + + vpu0-thermal { + polling-delay = <1000>; + polling-delay-passive = <250>; + thermal-sensors = <&lvts_ap MT8192_AP_VPU0>; + + trips { + vpu0_alert: trip-alert { + temperature = <85000>; + hysteresis = <2000>; + type = "passive"; + }; + + vpu0_crit: trip-crit { + temperature = <100000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + }; + + vpu1-thermal { + polling-delay = <1000>; + polling-delay-passive = <250>; + thermal-sensors = <&lvts_ap MT8192_AP_VPU1>; + + trips { + vpu1_alert: trip-alert { + temperature = <85000>; + hysteresis = <2000>; + type = "passive"; + }; + + vpu1_crit: trip-crit { + temperature = <100000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + }; + + gpu0-thermal { + polling-delay = <1000>; + polling-delay-passive = <250>; + thermal-sensors = <&lvts_ap MT8192_AP_GPU0>; + + trips { + gpu0_alert: trip-alert { + temperature = <85000>; + hysteresis = <2000>; + type = "passive"; + }; + + gpu0_crit: trip-crit { + temperature = <100000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + }; + + gpu1-thermal { + polling-delay = <1000>; + polling-delay-passive = <250>; + thermal-sensors = <&lvts_ap MT8192_AP_GPU1>; + + trips { + gpu1_alert: trip-alert { + temperature = <85000>; + hysteresis = <2000>; + type = "passive"; + }; + + gpu1_crit: trip-crit { + temperature = <100000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + }; + + infra-thermal { + polling-delay = <1000>; + polling-delay-passive = <250>; + thermal-sensors = <&lvts_ap MT8192_AP_INFRA>; + + trips { + infra_alert: trip-alert { + temperature = <85000>; + hysteresis = <2000>; + type = "passive"; + }; + + infra_crit: trip-crit { + temperature = <100000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + }; + + cam-thermal { + polling-delay = <1000>; + polling-delay-passive = <250>; + thermal-sensors = <&lvts_ap MT8192_AP_CAM>; + + trips { + cam_alert: trip-alert { + temperature = <85000>; + hysteresis = <2000>; + type = "passive"; + }; + + cam_crit: trip-crit { + temperature = <100000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + }; + + md0-thermal { + polling-delay = <1000>; + polling-delay-passive = <250>; + thermal-sensors = <&lvts_ap MT8192_AP_MD0>; + + trips { + md0_alert: trip-alert { + temperature = <85000>; + hysteresis = <2000>; + type = "passive"; + }; + + md0_crit: trip-crit { + temperature = <100000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + }; + + md1-thermal { + polling-delay = <1000>; + polling-delay-passive = <250>; + thermal-sensors = <&lvts_ap MT8192_AP_MD1>; + + trips { + md1_alert: trip-alert { + temperature = <85000>; + hysteresis = <2000>; + type = "passive"; + }; + + md1_crit: trip-crit { + temperature = <100000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + }; + + md2-thermal { + polling-delay = <1000>; + polling-delay-passive = <250>; + thermal-sensors = <&lvts_ap MT8192_AP_MD2>; + + trips { + md2_alert: trip-alert { + temperature = <85000>; + hysteresis = <2000>; + type = "passive"; + }; + + md2_crit: trip-crit { + temperature = <100000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + }; + }; }; diff --git a/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi b/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi index 5a7cab489ff3ac..3c6079edda190d 100644 --- a/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8195-cherry.dtsi @@ -127,6 +127,77 @@ regulator-boot-on; }; + /* Murata NCP03WF104F05RL */ + tboard_thermistor1: thermal-sensor-t1 { + compatible = "generic-adc-thermal"; + #thermal-sensor-cells = <0>; + io-channels = <&auxadc 0>; + io-channel-names = "sensor-channel"; + temperature-lookup-table = < (-10000) 1553 + (-5000) 1485 + 0 1406 + 5000 1317 + 10000 1219 + 15000 1115 + 20000 1007 + 25000 900 + 30000 796 + 35000 697 + 40000 605 + 45000 523 + 50000 449 + 55000 384 + 60000 327 + 65000 279 + 70000 237 + 75000 202 + 80000 172 + 85000 147 + 90000 125 + 95000 107 + 100000 92 + 105000 79 + 110000 68 + 115000 59 + 120000 51 + 125000 44>; + }; + + tboard_thermistor2: thermal-sensor-t2 { + compatible = "generic-adc-thermal"; + #thermal-sensor-cells = <0>; + io-channels = <&auxadc 1>; + io-channel-names = "sensor-channel"; + temperature-lookup-table = < (-10000) 1553 + (-5000) 1485 + 0 1406 + 5000 1317 + 10000 1219 + 15000 1115 + 20000 1007 + 25000 900 + 30000 796 + 35000 697 + 40000 605 + 45000 523 + 50000 449 + 55000 384 + 60000 327 + 65000 279 + 70000 237 + 75000 202 + 80000 172 + 85000 147 + 90000 125 + 95000 107 + 100000 92 + 105000 79 + 110000 68 + 115000 59 + 120000 51 + 125000 44>; + }; + usb_vbus: regulator-5v0-usb-vbus { compatible = "regulator-fixed"; regulator-name = "usb-vbus"; @@ -189,6 +260,10 @@ memory-region = <&afe_mem>; }; +&auxadc { + status = "okay"; +}; + &dp_intf0 { status = "okay"; @@ -401,6 +476,14 @@ }; }; +&mfg0 { + domain-supply = <&mt6315_7_vbuck1>; +}; + +&mfg1 { + domain-supply = <&mt6359_vsram_others_ldo_reg>; +}; + &mmc0 { status = "okay"; @@ -471,7 +554,6 @@ /* for GPU SRAM */ &mt6359_vsram_others_ldo_reg { - regulator-always-on; regulator-min-microvolt = <750000>; regulator-max-microvolt = <750000>; }; @@ -1154,7 +1236,36 @@ regulator-enable-ramp-delay = <256>; regulator-ramp-delay = <6250>; regulator-allowed-modes = <0 1 2>; - regulator-always-on; + }; + }; + }; +}; + +&thermal_zones { + soc-area-thermal { + polling-delay = <1000>; + polling-delay-passive = <250>; + thermal-sensors = <&tboard_thermistor1>; + + trips { + trip-crit { + temperature = <84000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + pmic-area-thermal { + polling-delay = <1000>; + polling-delay-passive = <0>; + thermal-sensors = <&tboard_thermistor2>; + + trips { + trip-crit { + temperature = <84000>; + hysteresis = <1000>; + type = "critical"; }; }; }; @@ -1183,6 +1294,7 @@ &xhci0 { status = "okay"; + rx-fifo-depth = <3072>; vusb33-supply = <&mt6359_vusb_ldo_reg>; vbus-supply = <&usb_vbus>; }; @@ -1190,6 +1302,7 @@ &xhci1 { status = "okay"; + rx-fifo-depth = <3072>; vusb33-supply = <&mt6359_vusb_ldo_reg>; vbus-supply = <&usb_vbus>; }; diff --git a/arch/arm64/boot/dts/mediatek/mt8195.dtsi b/arch/arm64/boot/dts/mediatek/mt8195.dtsi index e0ac2e9f5b7204..b9101662ce40d0 100644 --- a/arch/arm64/boot/dts/mediatek/mt8195.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8195.dtsi @@ -538,7 +538,7 @@ #size-cells = <0>; #power-domain-cells = <1>; - power-domain@MT8195_POWER_DOMAIN_MFG1 { + mfg1: power-domain@MT8195_POWER_DOMAIN_MFG1 { reg = ; clocks = <&apmixedsys CLK_APMIXED_MFGPLL>, <&topckgen CLK_TOP_MFG_CORE_TMP>; @@ -1119,7 +1119,7 @@ lvts_ap: thermal-sensor@1100b000 { compatible = "mediatek,mt8195-lvts-ap"; - reg = <0 0x1100b000 0 0x1000>; + reg = <0 0x1100b000 0 0xc00>; interrupts = ; clocks = <&infracfg_ao CLK_INFRA_AO_THERM>; resets = <&infracfg_ao MT8195_INFRA_RST0_THERM_CTRL_SWRST>; @@ -1128,6 +1128,18 @@ #thermal-sensor-cells = <1>; }; + svs: svs@1100bc00 { + compatible = "mediatek,mt8195-svs"; + reg = <0 0x1100bc00 0 0x400>; + interrupts = ; + clocks = <&infracfg_ao CLK_INFRA_AO_THERM>; + clock-names = "main"; + nvmem-cells = <&svs_calib_data &lvts_efuse_data1>; + nvmem-cell-names = "svs-calibration-data", "t-calibration-data"; + resets = <&infracfg_ao MT8195_INFRA_RST3_THERM_CTRL_PTP_SWRST>; + reset-names = "svs_rst"; + }; + disp_pwm0: pwm@1100e000 { compatible = "mediatek,mt8195-disp-pwm", "mediatek,mt8183-disp-pwm"; reg = <0 0x1100e000 0 0x1000>; @@ -1686,6 +1698,9 @@ lvts_efuse_data2: lvts2-calib@1d0 { reg = <0x1d0 0x38>; }; + svs_calib_data: svs-calib@580 { + reg = <0x580 0x64>; + }; }; u3phy2: t-phy@11c40000 { @@ -1718,6 +1733,26 @@ }; }; + mipi_tx0: dsi-phy@11c80000 { + compatible = "mediatek,mt8195-mipi-tx", "mediatek,mt8183-mipi-tx"; + reg = <0 0x11c80000 0 0x1000>; + clocks = <&clk26m>; + clock-output-names = "mipi_tx0_pll"; + #clock-cells = <0>; + #phy-cells = <0>; + status = "disabled"; + }; + + mipi_tx1: dsi-phy@11c90000 { + compatible = "mediatek,mt8195-mipi-tx", "mediatek,mt8183-mipi-tx"; + reg = <0 0x11c90000 0 0x1000>; + clocks = <&clk26m>; + clock-output-names = "mipi_tx1_pll"; + #clock-cells = <0>; + #phy-cells = <0>; + status = "disabled"; + }; + i2c5: i2c@11d00000 { compatible = "mediatek,mt8195-i2c", "mediatek,mt8192-i2c"; @@ -1965,6 +2000,115 @@ #clock-cells = <1>; }; + dma-controller@14001000 { + compatible = "mediatek,mt8195-mdp3-rdma"; + reg = <0 0x14001000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_1400XXXX 0x1000 0x1000>; + mediatek,gce-events = , + ; + power-domains = <&spm MT8195_POWER_DOMAIN_VPPSYS0>; + iommus = <&iommu_vpp M4U_PORT_L4_MDP_RDMA>; + clocks = <&vppsys0 CLK_VPP0_MDP_RDMA>; + mboxes = <&gce1 12 CMDQ_THR_PRIO_1>, + <&gce1 13 CMDQ_THR_PRIO_1>, + <&gce1 14 CMDQ_THR_PRIO_1>, + <&gce1 21 CMDQ_THR_PRIO_1>, + <&gce1 22 CMDQ_THR_PRIO_1>; + #dma-cells = <1>; + }; + + display@14002000 { + compatible = "mediatek,mt8195-mdp3-fg"; + reg = <0 0x14002000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_1400XXXX 0x2000 0x1000>; + clocks = <&vppsys0 CLK_VPP0_MDP_FG>; + }; + + display@14003000 { + compatible = "mediatek,mt8195-mdp3-stitch"; + reg = <0 0x14003000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_1400XXXX 0x3000 0x1000>; + clocks = <&vppsys0 CLK_VPP0_STITCH>; + }; + + display@14004000 { + compatible = "mediatek,mt8195-mdp3-hdr"; + reg = <0 0x14004000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_1400XXXX 0x4000 0x1000>; + clocks = <&vppsys0 CLK_VPP0_MDP_HDR>; + }; + + display@14005000 { + compatible = "mediatek,mt8195-mdp3-aal"; + reg = <0 0x14005000 0 0x1000>; + interrupts = ; + mediatek,gce-client-reg = <&gce1 SUBSYS_1400XXXX 0x5000 0x1000>; + clocks = <&vppsys0 CLK_VPP0_MDP_AAL>; + power-domains = <&spm MT8195_POWER_DOMAIN_VPPSYS0>; + }; + + display@14006000 { + compatible = "mediatek,mt8195-mdp3-rsz", "mediatek,mt8183-mdp3-rsz"; + reg = <0 0x14006000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_1400XXXX 0x6000 0x1000>; + mediatek,gce-events = , + ; + clocks = <&vppsys0 CLK_VPP0_MDP_RSZ>; + }; + + display@14007000 { + compatible = "mediatek,mt8195-mdp3-tdshp"; + reg = <0 0x14007000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_1400XXXX 0x7000 0x1000>; + clocks = <&vppsys0 CLK_VPP0_MDP_TDSHP>; + }; + + display@14008000 { + compatible = "mediatek,mt8195-mdp3-color"; + reg = <0 0x14008000 0 0x1000>; + interrupts = ; + mediatek,gce-client-reg = <&gce1 SUBSYS_1400XXXX 0x8000 0x1000>; + clocks = <&vppsys0 CLK_VPP0_MDP_COLOR>; + power-domains = <&spm MT8195_POWER_DOMAIN_VPPSYS0>; + }; + + display@14009000 { + compatible = "mediatek,mt8195-mdp3-ovl"; + reg = <0 0x14009000 0 0x1000>; + interrupts = ; + mediatek,gce-client-reg = <&gce1 SUBSYS_1400XXXX 0x9000 0x1000>; + clocks = <&vppsys0 CLK_VPP0_MDP_OVL>; + power-domains = <&spm MT8195_POWER_DOMAIN_VPPSYS0>; + iommus = <&iommu_vpp M4U_PORT_L4_MDP_OVL>; + }; + + display@1400a000 { + compatible = "mediatek,mt8195-mdp3-padding"; + reg = <0 0x1400a000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_1400XXXX 0xa000 0x1000>; + clocks = <&vppsys0 CLK_VPP0_PADDING>; + power-domains = <&spm MT8195_POWER_DOMAIN_VPPSYS0>; + }; + + display@1400b000 { + compatible = "mediatek,mt8195-mdp3-tcc"; + reg = <0 0x1400b000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_1400XXXX 0xb000 0x1000>; + clocks = <&vppsys0 CLK_VPP0_MDP_TCC>; + }; + + dma-controller@1400c000 { + compatible = "mediatek,mt8195-mdp3-wrot", "mediatek,mt8183-mdp3-wrot"; + reg = <0 0x1400c000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_1400XXXX 0xc000 0x1000>; + mediatek,gce-events = , + ; + clocks = <&vppsys0 CLK_VPP0_MDP_WROT>; + iommus = <&iommu_vpp M4U_PORT_L4_MDP_WROT>; + power-domains = <&spm MT8195_POWER_DOMAIN_VPPSYS0>; + #dma-cells = <1>; + }; + mutex@1400f000 { compatible = "mediatek,mt8195-vpp-mutex"; reg = <0 0x1400f000 0 0x1000>; @@ -2112,6 +2256,289 @@ power-domains = <&spm MT8195_POWER_DOMAIN_VPPSYS1>; }; + display@14f06000 { + compatible = "mediatek,mt8195-mdp3-split"; + reg = <0 0x14f06000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_14f0XXXX 0x6000 0x1000>; + clocks = <&vppsys1 CLK_VPP1_VPP_SPLIT>, + <&vppsys1 CLK_VPP1_HDMI_META>, + <&vppsys1 CLK_VPP1_VPP_SPLIT_HDMI>; + power-domains = <&spm MT8195_POWER_DOMAIN_VPPSYS1>; + }; + + display@14f07000 { + compatible = "mediatek,mt8195-mdp3-tcc"; + reg = <0 0x14f07000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_14f0XXXX 0x7000 0x1000>; + clocks = <&vppsys1 CLK_VPP1_SVPP1_MDP_TCC>; + }; + + dma-controller@14f08000 { + compatible = "mediatek,mt8195-mdp3-rdma"; + reg = <0 0x14f08000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_14f0XXXX 0x8000 0x1000>; + mediatek,gce-events = , + ; + clocks = <&vppsys1 CLK_VPP1_SVPP1_MDP_RDMA>; + iommus = <&iommu_vdo M4U_PORT_L5_SVPP1_MDP_RDMA>; + power-domains = <&spm MT8195_POWER_DOMAIN_VPPSYS1>; + #dma-cells = <1>; + }; + + dma-controller@14f09000 { + compatible = "mediatek,mt8195-mdp3-rdma"; + reg = <0 0x14f09000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_14f0XXXX 0x9000 0x1000>; + mediatek,gce-events = , + ; + clocks = <&vppsys1 CLK_VPP1_SVPP2_MDP_RDMA>; + iommus = <&iommu_vdo M4U_PORT_L5_SVPP2_MDP_RDMA>; + power-domains = <&spm MT8195_POWER_DOMAIN_VPPSYS1>; + #dma-cells = <1>; + }; + + dma-controller@14f0a000 { + compatible = "mediatek,mt8195-mdp3-rdma"; + reg = <0 0x14f0a000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_14f0XXXX 0xa000 0x1000>; + mediatek,gce-events = , + ; + clocks = <&vppsys1 CLK_VPP1_SVPP3_MDP_RDMA>; + iommus = <&iommu_vpp M4U_PORT_L6_SVPP3_MDP_RDMA>; + power-domains = <&spm MT8195_POWER_DOMAIN_VPPSYS1>; + #dma-cells = <1>; + }; + + display@14f0b000 { + compatible = "mediatek,mt8195-mdp3-fg"; + reg = <0 0x14f0b000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_14f0XXXX 0xb000 0x1000>; + clocks = <&vppsys1 CLK_VPP1_SVPP1_MDP_FG>; + }; + + display@14f0c000 { + compatible = "mediatek,mt8195-mdp3-fg"; + reg = <0 0x14f0c000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_14f0XXXX 0xc000 0x1000>; + clocks = <&vppsys1 CLK_VPP1_SVPP2_MDP_FG>; + }; + + display@14f0d000 { + compatible = "mediatek,mt8195-mdp3-fg"; + reg = <0 0x14f0d000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_14f0XXXX 0xd000 0x1000>; + clocks = <&vppsys1 CLK_VPP1_SVPP3_MDP_FG>; + }; + + display@14f0e000 { + compatible = "mediatek,mt8195-mdp3-hdr"; + reg = <0 0x14f0e000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_14f0XXXX 0xe000 0x1000>; + clocks = <&vppsys1 CLK_VPP1_SVPP1_MDP_HDR>; + }; + + display@14f0f000 { + compatible = "mediatek,mt8195-mdp3-hdr"; + reg = <0 0x14f0f000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_14f0XXXX 0xf000 0x1000>; + clocks = <&vppsys1 CLK_VPP1_SVPP2_MDP_HDR>; + }; + + display@14f10000 { + compatible = "mediatek,mt8195-mdp3-hdr"; + reg = <0 0x14f10000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_14f1XXXX 0 0x1000>; + clocks = <&vppsys1 CLK_VPP1_SVPP3_MDP_HDR>; + }; + + display@14f11000 { + compatible = "mediatek,mt8195-mdp3-aal"; + reg = <0 0x14f11000 0 0x1000>; + interrupts = ; + mediatek,gce-client-reg = <&gce1 SUBSYS_14f1XXXX 0x1000 0x1000>; + clocks = <&vppsys1 CLK_VPP1_SVPP1_MDP_AAL>; + power-domains = <&spm MT8195_POWER_DOMAIN_VPPSYS1>; + }; + + display@14f12000 { + compatible = "mediatek,mt8195-mdp3-aal"; + reg = <0 0x14f12000 0 0x1000>; + interrupts = ; + mediatek,gce-client-reg = <&gce1 SUBSYS_14f1XXXX 0x2000 0x1000>; + clocks = <&vppsys1 CLK_VPP1_SVPP2_MDP_AAL>; + power-domains = <&spm MT8195_POWER_DOMAIN_VPPSYS1>; + }; + + display@14f13000 { + compatible = "mediatek,mt8195-mdp3-aal"; + reg = <0 0x14f13000 0 0x1000>; + interrupts = ; + mediatek,gce-client-reg = <&gce1 SUBSYS_14f1XXXX 0x3000 0x1000>; + clocks = <&vppsys1 CLK_VPP1_SVPP3_MDP_AAL>; + power-domains = <&spm MT8195_POWER_DOMAIN_VPPSYS1>; + }; + + display@14f14000 { + compatible = "mediatek,mt8195-mdp3-rsz", "mediatek,mt8183-mdp3-rsz"; + reg = <0 0x14f14000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_14f1XXXX 0x4000 0x1000>; + mediatek,gce-events = , + ; + clocks = <&vppsys1 CLK_VPP1_SVPP1_MDP_RSZ>; + }; + + display@14f15000 { + compatible = "mediatek,mt8195-mdp3-rsz", "mediatek,mt8183-mdp3-rsz"; + reg = <0 0x14f15000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_14f1XXXX 0x5000 0x1000>; + mediatek,gce-events = , + ; + clocks = <&vppsys1 CLK_VPP1_SVPP2_MDP_RSZ>; + }; + + display@14f16000 { + compatible = "mediatek,mt8195-mdp3-rsz", "mediatek,mt8183-mdp3-rsz"; + reg = <0 0x14f16000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_14f1XXXX 0x6000 0x1000>; + mediatek,gce-events = , + ; + clocks = <&vppsys1 CLK_VPP1_SVPP3_MDP_RSZ>; + }; + + display@14f17000 { + compatible = "mediatek,mt8195-mdp3-tdshp"; + reg = <0 0x14f17000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_14f1XXXX 0x7000 0x1000>; + clocks = <&vppsys1 CLK_VPP1_SVPP1_MDP_TDSHP>; + }; + + display@14f18000 { + compatible = "mediatek,mt8195-mdp3-tdshp"; + reg = <0 0x14f18000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_14f1XXXX 0x8000 0x1000>; + clocks = <&vppsys1 CLK_VPP1_SVPP2_MDP_TDSHP>; + }; + + display@14f19000 { + compatible = "mediatek,mt8195-mdp3-tdshp"; + reg = <0 0x14f19000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_14f1XXXX 0x9000 0x1000>; + clocks = <&vppsys1 CLK_VPP1_SVPP3_MDP_TDSHP>; + }; + + display@14f1a000 { + compatible = "mediatek,mt8195-mdp3-merge"; + reg = <0 0x14f1a000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_14f1XXXX 0xa000 0x1000>; + clocks = <&vppsys1 CLK_VPP1_SVPP2_VPP_MERGE>; + power-domains = <&spm MT8195_POWER_DOMAIN_VPPSYS1>; + }; + + display@14f1b000 { + compatible = "mediatek,mt8195-mdp3-merge"; + reg = <0 0x14f1b000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_14f1XXXX 0xb000 0x1000>; + clocks = <&vppsys1 CLK_VPP1_SVPP3_VPP_MERGE>; + power-domains = <&spm MT8195_POWER_DOMAIN_VPPSYS1>; + }; + + display@14f1c000 { + compatible = "mediatek,mt8195-mdp3-color"; + reg = <0 0x14f1c000 0 0x1000>; + interrupts = ; + mediatek,gce-client-reg = <&gce1 SUBSYS_14f1XXXX 0xc000 0x1000>; + clocks = <&vppsys1 CLK_VPP1_SVPP1_MDP_COLOR>; + power-domains = <&spm MT8195_POWER_DOMAIN_VPPSYS1>; + }; + + display@14f1d000 { + compatible = "mediatek,mt8195-mdp3-color"; + reg = <0 0x14f1d000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_14f1XXXX 0xd000 0x1000>; + interrupts = ; + clocks = <&vppsys1 CLK_VPP1_SVPP2_MDP_COLOR>; + power-domains = <&spm MT8195_POWER_DOMAIN_VPPSYS1>; + }; + + display@14f1e000 { + compatible = "mediatek,mt8195-mdp3-color"; + reg = <0 0x14f1e000 0 0x1000>; + interrupts = ; + mediatek,gce-client-reg = <&gce1 SUBSYS_14f1XXXX 0xe000 0x1000>; + clocks = <&vppsys1 CLK_VPP1_SVPP3_MDP_COLOR>; + power-domains = <&spm MT8195_POWER_DOMAIN_VPPSYS1>; + }; + + display@14f1f000 { + compatible = "mediatek,mt8195-mdp3-ovl"; + reg = <0 0x14f1f000 0 0x1000>; + interrupts = ; + mediatek,gce-client-reg = <&gce1 SUBSYS_14f1XXXX 0xf000 0x1000>; + clocks = <&vppsys1 CLK_VPP1_SVPP1_MDP_OVL>; + power-domains = <&spm MT8195_POWER_DOMAIN_VPPSYS1>; + iommus = <&iommu_vdo M4U_PORT_L5_SVPP1_MDP_OVL>; + }; + + display@14f20000 { + compatible = "mediatek,mt8195-mdp3-padding"; + reg = <0 0x14f20000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_14f2XXXX 0 0x1000>; + clocks = <&vppsys1 CLK_VPP1_SVPP1_VPP_PAD>; + power-domains = <&spm MT8195_POWER_DOMAIN_VPPSYS1>; + }; + + display@14f21000 { + compatible = "mediatek,mt8195-mdp3-padding"; + reg = <0 0x14f21000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_14f2XXXX 0x1000 0x1000>; + clocks = <&vppsys1 CLK_VPP1_SVPP2_VPP_PAD>; + power-domains = <&spm MT8195_POWER_DOMAIN_VPPSYS1>; + }; + + display@14f22000 { + compatible = "mediatek,mt8195-mdp3-padding"; + reg = <0 0x14f22000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_14f2XXXX 0x2000 0x1000>; + clocks = <&vppsys1 CLK_VPP1_SVPP3_VPP_PAD>; + power-domains = <&spm MT8195_POWER_DOMAIN_VPPSYS1>; + }; + + dma-controller@14f23000 { + compatible = "mediatek,mt8195-mdp3-wrot", "mediatek,mt8183-mdp3-wrot"; + reg = <0 0x14f23000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_14f2XXXX 0x3000 0x1000>; + mediatek,gce-events = , + ; + clocks = <&vppsys1 CLK_VPP1_SVPP1_MDP_WROT>; + iommus = <&iommu_vdo M4U_PORT_L5_SVPP1_MDP_WROT>; + power-domains = <&spm MT8195_POWER_DOMAIN_VPPSYS1>; + #dma-cells = <1>; + }; + + dma-controller@14f24000 { + compatible = "mediatek,mt8195-mdp3-wrot", "mediatek,mt8183-mdp3-wrot"; + reg = <0 0x14f24000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_14f2XXXX 0x4000 0x1000>; + mediatek,gce-events = , + ; + clocks = <&vppsys1 CLK_VPP1_SVPP2_MDP_WROT>; + iommus = <&iommu_vdo M4U_PORT_L5_SVPP2_MDP_WROT>; + power-domains = <&spm MT8195_POWER_DOMAIN_VPPSYS1>; + #dma-cells = <1>; + }; + + dma-controller@14f25000 { + compatible = "mediatek,mt8195-mdp3-wrot", "mediatek,mt8183-mdp3-wrot"; + reg = <0 0x14f25000 0 0x1000>; + mediatek,gce-client-reg = <&gce1 SUBSYS_14f2XXXX 0x5000 0x1000>; + mediatek,gce-events = , + ; + clocks = <&vppsys1 CLK_VPP1_SVPP3_MDP_WROT>; + iommus = <&iommu_vpp M4U_PORT_L6_SVPP3_MDP_WROT>; + power-domains = <&spm MT8195_POWER_DOMAIN_VPPSYS1>; + #dma-cells = <1>; + }; + imgsys: clock-controller@15000000 { compatible = "mediatek,mt8195-imgsys"; reg = <0 0x15000000 0 0x1000>; @@ -2741,6 +3168,20 @@ mediatek,gce-client-reg = <&gce0 SUBSYS_1c00XXXX 0x7000 0x1000>; }; + dsi0: dsi@1c008000 { + compatible = "mediatek,mt8195-dsi", "mediatek,mt8183-dsi"; + reg = <0 0x1c008000 0 0x1000>; + interrupts = ; + power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS0>; + clocks = <&vdosys0 CLK_VDO0_DSI0>, + <&vdosys0 CLK_VDO0_DSI0_DSI>, + <&mipi_tx0>; + clock-names = "engine", "digital", "hs"; + phys = <&mipi_tx0>; + phy-names = "dphy"; + status = "disabled"; + }; + dsc0: dsc@1c009000 { compatible = "mediatek,mt8195-disp-dsc"; reg = <0 0x1c009000 0 0x1000>; @@ -2750,6 +3191,20 @@ mediatek,gce-client-reg = <&gce0 SUBSYS_1c00XXXX 0x9000 0x1000>; }; + dsi1: dsi@1c012000 { + compatible = "mediatek,mt8195-dsi", "mediatek,mt8183-dsi"; + reg = <0 0x1c012000 0 0x1000>; + interrupts = ; + power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS0>; + clocks = <&vdosys0 CLK_VDO0_DSI1>, + <&vdosys0 CLK_VDO0_DSI1_DSI>, + <&mipi_tx1>; + clock-names = "engine", "digital", "hs"; + phys = <&mipi_tx1>; + phy-names = "dphy"; + status = "disabled"; + }; + merge0: merge@1c014000 { compatible = "mediatek,mt8195-disp-merge"; reg = <0 0x1c014000 0 0x1000>; @@ -2873,7 +3328,7 @@ power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>; }; - vdo1_rdma0: rdma@1c104000 { + vdo1_rdma0: dma-controller@1c104000 { compatible = "mediatek,mt8195-vdo1-rdma"; reg = <0 0x1c104000 0 0x1000>; interrupts = ; @@ -2881,9 +3336,10 @@ power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>; iommus = <&iommu_vdo M4U_PORT_L2_MDP_RDMA0>; mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0x4000 0x1000>; + #dma-cells = <1>; }; - vdo1_rdma1: rdma@1c105000 { + vdo1_rdma1: dma-controller@1c105000 { compatible = "mediatek,mt8195-vdo1-rdma"; reg = <0 0x1c105000 0 0x1000>; interrupts = ; @@ -2891,9 +3347,10 @@ power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>; iommus = <&iommu_vpp M4U_PORT_L3_MDP_RDMA1>; mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0x5000 0x1000>; + #dma-cells = <1>; }; - vdo1_rdma2: rdma@1c106000 { + vdo1_rdma2: dma-controller@1c106000 { compatible = "mediatek,mt8195-vdo1-rdma"; reg = <0 0x1c106000 0 0x1000>; interrupts = ; @@ -2901,9 +3358,10 @@ power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>; iommus = <&iommu_vdo M4U_PORT_L2_MDP_RDMA2>; mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0x6000 0x1000>; + #dma-cells = <1>; }; - vdo1_rdma3: rdma@1c107000 { + vdo1_rdma3: dma-controller@1c107000 { compatible = "mediatek,mt8195-vdo1-rdma"; reg = <0 0x1c107000 0 0x1000>; interrupts = ; @@ -2911,9 +3369,10 @@ power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>; iommus = <&iommu_vpp M4U_PORT_L3_MDP_RDMA3>; mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0x7000 0x1000>; + #dma-cells = <1>; }; - vdo1_rdma4: rdma@1c108000 { + vdo1_rdma4: dma-controller@1c108000 { compatible = "mediatek,mt8195-vdo1-rdma"; reg = <0 0x1c108000 0 0x1000>; interrupts = ; @@ -2921,9 +3380,10 @@ power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>; iommus = <&iommu_vdo M4U_PORT_L2_MDP_RDMA4>; mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0x8000 0x1000>; + #dma-cells = <1>; }; - vdo1_rdma5: rdma@1c109000 { + vdo1_rdma5: dma-controller@1c109000 { compatible = "mediatek,mt8195-vdo1-rdma"; reg = <0 0x1c109000 0 0x1000>; interrupts = ; @@ -2931,9 +3391,10 @@ power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>; iommus = <&iommu_vpp M4U_PORT_L3_MDP_RDMA5>; mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0x9000 0x1000>; + #dma-cells = <1>; }; - vdo1_rdma6: rdma@1c10a000 { + vdo1_rdma6: dma-controller@1c10a000 { compatible = "mediatek,mt8195-vdo1-rdma"; reg = <0 0x1c10a000 0 0x1000>; interrupts = ; @@ -2941,9 +3402,10 @@ power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>; iommus = <&iommu_vdo M4U_PORT_L2_MDP_RDMA6>; mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0xa000 0x1000>; + #dma-cells = <1>; }; - vdo1_rdma7: rdma@1c10b000 { + vdo1_rdma7: dma-controller@1c10b000 { compatible = "mediatek,mt8195-vdo1-rdma"; reg = <0 0x1c10b000 0 0x1000>; interrupts = ; @@ -2951,6 +3413,7 @@ power-domains = <&spm MT8195_POWER_DOMAIN_VDOSYS1>; iommus = <&iommu_vpp M4U_PORT_L3_MDP_RDMA7>; mediatek,gce-client-reg = <&gce0 SUBSYS_1c10XXXX 0xb000 0x1000>; + #dma-cells = <1>; }; merge1: vpp-merge@1c10c000 { diff --git a/arch/arm64/boot/dts/mediatek/mt8395-genio-1200-evk.dts b/arch/arm64/boot/dts/mediatek/mt8395-genio-1200-evk.dts index 00ac59a873e8dd..7fc515a07c65d1 100644 --- a/arch/arm64/boot/dts/mediatek/mt8395-genio-1200-evk.dts +++ b/arch/arm64/boot/dts/mediatek/mt8395-genio-1200-evk.dts @@ -210,8 +210,7 @@ touchscreen@5d { compatible = "goodix,gt9271"; reg = <0x5d>; - interrupt-parent = <&pio>; - interrupts = <132 IRQ_TYPE_EDGE_RISING>; + interrupts-extended = <&pio 132 IRQ_TYPE_EDGE_RISING>; irq-gpios = <&pio 132 GPIO_ACTIVE_HIGH>; reset-gpios = <&pio 133 GPIO_ACTIVE_HIGH>; AVDD28-supply = <&mt6360_ldo1>; @@ -774,8 +773,7 @@ }; &pmic { - interrupt-parent = <&pio>; - interrupts = <222 IRQ_TYPE_LEVEL_HIGH>; + interrupts-extended = <&pio 222 IRQ_TYPE_LEVEL_HIGH>; }; &scp { diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index d6cb840b705047..39889d5f8e1238 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -45,6 +45,7 @@ dtb-$(CONFIG_ARCH_QCOM) += msm8916-thwc-uf896.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8916-thwc-ufi001c.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8916-wingtech-wt88047.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8916-yiming-uz801v3.dtb +dtb-$(CONFIG_ARCH_QCOM) += msm8939-huawei-kiwi.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8939-longcheer-l9100.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8939-samsung-a7.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8939-sony-xperia-kanuti-tulip.dtb @@ -87,8 +88,10 @@ dtb-$(CONFIG_ARCH_QCOM) += msm8998-sony-xperia-yoshino-maple.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8998-sony-xperia-yoshino-poplar.dtb dtb-$(CONFIG_ARCH_QCOM) += msm8998-xiaomi-sagit.dtb dtb-$(CONFIG_ARCH_QCOM) += qcm6490-fairphone-fp5.dtb +dtb-$(CONFIG_ARCH_QCOM) += qcm6490-idp.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs404-evb-1000.dtb dtb-$(CONFIG_ARCH_QCOM) += qcs404-evb-4000.dtb +dtb-$(CONFIG_ARCH_QCOM) += qcs6490-rb3gen2.dtb dtb-$(CONFIG_ARCH_QCOM) += qdu1000-idp.dtb dtb-$(CONFIG_ARCH_QCOM) += qrb2210-rb1.dtb dtb-$(CONFIG_ARCH_QCOM) += qrb4210-rb2.dtb @@ -220,6 +223,7 @@ dtb-$(CONFIG_ARCH_QCOM) += sm8250-sony-xperia-edo-pdx203.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8250-sony-xperia-edo-pdx206.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8250-xiaomi-elish-boe.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8250-xiaomi-elish-csot.dtb +dtb-$(CONFIG_ARCH_QCOM) += sm8250-xiaomi-pipa.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8350-hdk.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8350-microsoft-surface-duo2.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8350-mtp.dtb @@ -231,3 +235,7 @@ dtb-$(CONFIG_ARCH_QCOM) += sm8450-sony-xperia-nagara-pdx223.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8450-sony-xperia-nagara-pdx224.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8550-mtp.dtb dtb-$(CONFIG_ARCH_QCOM) += sm8550-qrd.dtb +dtb-$(CONFIG_ARCH_QCOM) += sm8650-mtp.dtb +dtb-$(CONFIG_ARCH_QCOM) += sm8650-qrd.dtb +dtb-$(CONFIG_ARCH_QCOM) += x1e80100-crd.dtb +dtb-$(CONFIG_ARCH_QCOM) += x1e80100-qcp.dtb diff --git a/arch/arm64/boot/dts/qcom/ipq5018-rdp432-c2.dts b/arch/arm64/boot/dts/qcom/ipq5018-rdp432-c2.dts index e636a1cb9b7766..8460b538eb6a3e 100644 --- a/arch/arm64/boot/dts/qcom/ipq5018-rdp432-c2.dts +++ b/arch/arm64/boot/dts/qcom/ipq5018-rdp432-c2.dts @@ -67,6 +67,18 @@ }; }; +&usb { + status = "okay"; +}; + +&usb_dwc { + dr_mode = "host"; +}; + +&usbphy0 { + status = "okay"; +}; + &xo_board_clk { clock-frequency = <24000000>; }; diff --git a/arch/arm64/boot/dts/qcom/ipq5018.dtsi b/arch/arm64/boot/dts/qcom/ipq5018.dtsi index 38ffdc3cbdcd7c..32b178b639f0cc 100644 --- a/arch/arm64/boot/dts/qcom/ipq5018.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq5018.dtsi @@ -5,6 +5,7 @@ * Copyright (c) 2023 The Linux Foundation. All rights reserved. */ +#include #include #include #include @@ -36,6 +37,8 @@ reg = <0x0>; enable-method = "psci"; next-level-cache = <&L2_0>; + clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>; + operating-points-v2 = <&cpu_opp_table>; }; CPU1: cpu@1 { @@ -44,6 +47,8 @@ reg = <0x1>; enable-method = "psci"; next-level-cache = <&L2_0>; + clocks = <&apcs_glb APCS_ALIAS0_CORE_CLK>; + operating-points-v2 = <&cpu_opp_table>; }; L2_0: l2-cache { @@ -54,6 +59,23 @@ }; }; + cpu_opp_table: opp-table-cpu { + compatible = "operating-points-v2"; + opp-shared; + + opp-800000000 { + opp-hz = /bits/ 64 <800000000>; + opp-microvolt = <1100000>; + clock-latency-ns = <200000>; + }; + + opp-1008000000 { + opp-hz = /bits/ 64 <1008000000>; + opp-microvolt = <1100000>; + clock-latency-ns = <200000>; + }; + }; + firmware { scm { compatible = "qcom,scm-ipq5018", "qcom,scm"; @@ -82,6 +104,24 @@ #size-cells = <2>; ranges; + bootloader@4a800000 { + reg = <0x0 0x4a800000 0x0 0x200000>; + no-map; + }; + + sbl@4aa00000 { + reg = <0x0 0x4aa00000 0x0 0x100000>; + no-map; + }; + + smem@4ab00000 { + compatible = "qcom,smem"; + reg = <0x0 0x4ab00000 0x0 0x100000>; + no-map; + + hwlocks = <&tcsr_mutex 3>; + }; + tz_region: tz@4ac00000 { reg = <0x0 0x4ac00000 0x0 0x200000>; no-map; @@ -94,6 +134,19 @@ #size-cells = <1>; ranges = <0 0 0 0xffffffff>; + usbphy0: phy@5b000 { + compatible = "qcom,ipq5018-usb-hsphy"; + reg = <0x0005b000 0x120>; + + clocks = <&gcc GCC_USB0_PHY_CFG_AHB_CLK>; + + resets = <&gcc GCC_QUSB2_0_PHY_BCR>; + + #phy-cells = <0>; + + status = "disabled"; + }; + tlmm: pinctrl@1000000 { compatible = "qcom,ipq5018-tlmm"; reg = <0x01000000 0x300000>; @@ -129,6 +182,12 @@ #power-domain-cells = <1>; }; + tcsr_mutex: hwlock@1905000 { + compatible = "qcom,tcsr-mutex"; + reg = <0x01905000 0x20000>; + #hwlock-cells = <1>; + }; + sdhc_1: mmc@7804000 { compatible = "qcom,ipq5018-sdhci", "qcom,sdhci-msm-v5"; reg = <0x7804000 0x1000>; @@ -146,6 +205,16 @@ status = "disabled"; }; + blsp_dma: dma-controller@7884000 { + compatible = "qcom,bam-v1.7.0"; + reg = <0x07884000 0x1d000>; + interrupts = ; + clocks = <&gcc GCC_BLSP1_AHB_CLK>; + clock-names = "bam_clk"; + #dma-cells = <1>; + qcom,ee = <0>; + }; + blsp1_uart1: serial@78af000 { compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; reg = <0x078af000 0x200>; @@ -156,6 +225,61 @@ status = "disabled"; }; + blsp1_spi1: spi@78b5000 { + compatible = "qcom,spi-qup-v2.2.1"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x078b5000 0x600>; + interrupts = ; + clocks = <&gcc GCC_BLSP1_QUP1_SPI_APPS_CLK>, + <&gcc GCC_BLSP1_AHB_CLK>; + clock-names = "core", "iface"; + dmas = <&blsp_dma 4>, <&blsp_dma 5>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + usb: usb@8af8800 { + compatible = "qcom,ipq5018-dwc3", "qcom,dwc3"; + reg = <0x08af8800 0x400>; + + interrupts = ; + interrupt-names = "hs_phy_irq"; + + clocks = <&gcc GCC_USB0_MASTER_CLK>, + <&gcc GCC_SYS_NOC_USB0_AXI_CLK>, + <&gcc GCC_USB0_SLEEP_CLK>, + <&gcc GCC_USB0_MOCK_UTMI_CLK>; + clock-names = "core", + "iface", + "sleep", + "mock_utmi"; + + resets = <&gcc GCC_USB0_BCR>; + + qcom,select-utmi-as-pipe-clk; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + status = "disabled"; + + usb_dwc: usb@8a00000 { + compatible = "snps,dwc3"; + reg = <0x08a00000 0xe000>; + clocks = <&gcc GCC_USB0_MOCK_UTMI_CLK>; + clock-names = "ref"; + interrupts = ; + phy-names = "usb2-phy"; + phys = <&usbphy0>; + tx-fifo-resize; + snps,is-utmi-l1-suspend; + snps,hird-threshold = /bits/ 8 <0x0>; + snps,dis_u2_susphy_quirk; + snps,dis_u3_susphy_quirk; + }; + }; + intc: interrupt-controller@b000000 { compatible = "qcom,msm-qgic2"; reg = <0x0b000000 0x1000>, /* GICD */ @@ -189,6 +313,24 @@ clocks = <&sleep_clk>; }; + apcs_glb: mailbox@b111000 { + compatible = "qcom,ipq5018-apcs-apps-global", + "qcom,ipq6018-apcs-apps-global"; + reg = <0x0b111000 0x1000>; + #clock-cells = <1>; + clocks = <&a53pll>, <&xo_board_clk>, <&gcc GPLL0>; + clock-names = "pll", "xo", "gpll0"; + #mbox-cells = <1>; + }; + + a53pll: clock@b116000 { + compatible = "qcom,ipq5018-a53pll"; + reg = <0x0b116000 0x40>; + #clock-cells = <0>; + clocks = <&xo_board_clk>; + clock-names = "xo"; + }; + timer@b120000 { compatible = "arm,armv7-timer-mem"; reg = <0x0b120000 0x1000>; diff --git a/arch/arm64/boot/dts/qcom/ipq5332-rdp-common.dtsi b/arch/arm64/boot/dts/qcom/ipq5332-rdp-common.dtsi index 4870cdb764d003..b37ae7749083f4 100644 --- a/arch/arm64/boot/dts/qcom/ipq5332-rdp-common.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq5332-rdp-common.dtsi @@ -9,6 +9,7 @@ #include #include +#include #include "ipq5332.dtsi" / { @@ -39,6 +40,8 @@ pinctrl-names = "default"; led-0 { + color = ; + function = LED_FUNCTION_WLAN; gpios = <&tlmm 36 GPIO_ACTIVE_HIGH>; linux,default-trigger = "phy0tx"; default-state = "off"; diff --git a/arch/arm64/boot/dts/qcom/ipq5332-rdp441.dts b/arch/arm64/boot/dts/qcom/ipq5332-rdp441.dts index e89e2e948603d6..846413817e9ad0 100644 --- a/arch/arm64/boot/dts/qcom/ipq5332-rdp441.dts +++ b/arch/arm64/boot/dts/qcom/ipq5332-rdp441.dts @@ -15,7 +15,7 @@ }; &blsp1_i2c1 { - clock-frequency = <400000>; + clock-frequency = <400000>; pinctrl-0 = <&i2c_1_pins>; pinctrl-names = "default"; status = "okay"; diff --git a/arch/arm64/boot/dts/qcom/ipq5332-rdp442.dts b/arch/arm64/boot/dts/qcom/ipq5332-rdp442.dts index efd480a7afdf19..ed8a54eb95c02b 100644 --- a/arch/arm64/boot/dts/qcom/ipq5332-rdp442.dts +++ b/arch/arm64/boot/dts/qcom/ipq5332-rdp442.dts @@ -15,7 +15,7 @@ }; &blsp1_i2c1 { - clock-frequency = <400000>; + clock-frequency = <400000>; pinctrl-0 = <&i2c_1_pins>; pinctrl-names = "default"; status = "okay"; diff --git a/arch/arm64/boot/dts/qcom/ipq5332-rdp474.dts b/arch/arm64/boot/dts/qcom/ipq5332-rdp474.dts index eb1fa33d6fe45c..d5f99e741ae57a 100644 --- a/arch/arm64/boot/dts/qcom/ipq5332-rdp474.dts +++ b/arch/arm64/boot/dts/qcom/ipq5332-rdp474.dts @@ -15,7 +15,7 @@ }; &blsp1_i2c1 { - clock-frequency = <400000>; + clock-frequency = <400000>; pinctrl-0 = <&i2c_1_pins>; pinctrl-names = "default"; status = "okay"; diff --git a/arch/arm64/boot/dts/qcom/ipq5332.dtsi b/arch/arm64/boot/dts/qcom/ipq5332.dtsi index d3fef2f80a81f4..42e2e48b2bc3d1 100644 --- a/arch/arm64/boot/dts/qcom/ipq5332.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq5332.dtsi @@ -91,11 +91,19 @@ }; cpu_opp_table: opp-table-cpu { - compatible = "operating-points-v2"; + compatible = "operating-points-v2-kryo-cpu"; opp-shared; + nvmem-cells = <&cpu_speed_bin>; - opp-1488000000 { - opp-hz = /bits/ 64 <1488000000>; + opp-1100000000 { + opp-hz = /bits/ 64 <1100000000>; + opp-supported-hw = <0x7>; + clock-latency-ns = <200000>; + }; + + opp-1500000000 { + opp-hz = /bits/ 64 <1500000000>; + opp-supported-hw = <0x3>; clock-latency-ns = <200000>; }; }; @@ -163,6 +171,11 @@ reg = <0x000a4000 0x721>; #address-cells = <1>; #size-cells = <1>; + + cpu_speed_bin: cpu-speed-bin@1d { + reg = <0x1d 0x2>; + bits = <7 2>; + }; }; rng: rng@e3000 { @@ -390,8 +403,8 @@ "qcom,ipq6018-apcs-apps-global"; reg = <0x0b111000 0x1000>; #clock-cells = <1>; - clocks = <&a53pll>, <&xo_board>; - clock-names = "pll", "xo"; + clocks = <&a53pll>, <&xo_board>, <&gcc GPLL0>; + clock-names = "pll", "xo", "gpll0"; #mbox-cells = <1>; }; diff --git a/arch/arm64/boot/dts/qcom/ipq6018.dtsi b/arch/arm64/boot/dts/qcom/ipq6018.dtsi index e59b9df96c7e6c..5e1277fea7250b 100644 --- a/arch/arm64/boot/dts/qcom/ipq6018.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq6018.dtsi @@ -96,42 +96,49 @@ }; cpu_opp_table: opp-table-cpu { - compatible = "operating-points-v2"; + compatible = "operating-points-v2-kryo-cpu"; + nvmem-cells = <&cpu_speed_bin>; opp-shared; opp-864000000 { opp-hz = /bits/ 64 <864000000>; opp-microvolt = <725000>; + opp-supported-hw = <0xf>; clock-latency-ns = <200000>; }; opp-1056000000 { opp-hz = /bits/ 64 <1056000000>; opp-microvolt = <787500>; + opp-supported-hw = <0xf>; clock-latency-ns = <200000>; }; opp-1320000000 { opp-hz = /bits/ 64 <1320000000>; opp-microvolt = <862500>; + opp-supported-hw = <0x3>; clock-latency-ns = <200000>; }; opp-1440000000 { opp-hz = /bits/ 64 <1440000000>; opp-microvolt = <925000>; + opp-supported-hw = <0x3>; clock-latency-ns = <200000>; }; opp-1608000000 { opp-hz = /bits/ 64 <1608000000>; opp-microvolt = <987500>; + opp-supported-hw = <0x1>; clock-latency-ns = <200000>; }; opp-1800000000 { opp-hz = /bits/ 64 <1800000000>; opp-microvolt = <1062500>; + opp-supported-hw = <0x1>; clock-latency-ns = <200000>; }; }; @@ -236,31 +243,26 @@ ssphy_0: ssphy@78000 { compatible = "qcom,ipq6018-qmp-usb3-phy"; - reg = <0x0 0x00078000 0x0 0x1c4>; - #address-cells = <2>; - #size-cells = <2>; - ranges; + reg = <0x0 0x00078000 0x0 0x1000>; clocks = <&gcc GCC_USB0_AUX_CLK>, - <&gcc GCC_USB0_PHY_CFG_AHB_CLK>, <&xo>; - clock-names = "aux", "cfg_ahb", "ref"; + <&xo>, + <&gcc GCC_USB0_PHY_CFG_AHB_CLK>, + <&gcc GCC_USB0_PIPE_CLK>; + clock-names = "aux", + "ref", + "cfg_ahb", + "pipe"; + clock-output-names = "gcc_usb0_pipe_clk_src"; + #clock-cells = <0>; + #phy-cells = <0>; resets = <&gcc GCC_USB0_PHY_BCR>, <&gcc GCC_USB3PHY_0_PHY_BCR>; - reset-names = "phy","common"; - status = "disabled"; + reset-names = "phy", + "phy_phy"; - usb0_ssphy: phy@78200 { - reg = <0x0 0x00078200 0x0 0x130>, /* Tx */ - <0x0 0x00078400 0x0 0x200>, /* Rx */ - <0x0 0x00078800 0x0 0x1f8>, /* PCS */ - <0x0 0x00078600 0x0 0x044>; /* PCS misc */ - #phy-cells = <0>; - #clock-cells = <0>; - clocks = <&gcc GCC_USB0_PIPE_CLK>; - clock-names = "pipe0"; - clock-output-names = "gcc_usb0_pipe_clk_src"; - }; + status = "disabled"; }; qusb_phy_0: qusb@79000 { @@ -314,6 +316,11 @@ reg = <0x0 0x000a4000 0x0 0x2000>; #address-cells = <1>; #size-cells = <1>; + + cpu_speed_bin: cpu-speed-bin@135 { + reg = <0x135 0x1>; + bits = <7 1>; + }; }; prng: qrng@e3000 { @@ -439,6 +446,26 @@ qcom,ee = <0>; }; + blsp1_uart1: serial@78af000 { + compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; + reg = <0x0 0x78af000 0x0 0x200>; + interrupts = ; + clocks = <&gcc GCC_BLSP1_UART1_APPS_CLK>, + <&gcc GCC_BLSP1_AHB_CLK>; + clock-names = "core", "iface"; + status = "disabled"; + }; + + blsp1_uart2: serial@78b0000 { + compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; + reg = <0x0 0x78b0000 0x0 0x200>; + interrupts = ; + clocks = <&gcc GCC_BLSP1_UART2_APPS_CLK>, + <&gcc GCC_BLSP1_AHB_CLK>; + clock-names = "core", "iface"; + status = "disabled"; + }; + blsp1_uart3: serial@78b1000 { compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; reg = <0x0 0x078b1000 0x0 0x200>; @@ -449,6 +476,36 @@ status = "disabled"; }; + blsp1_uart4: serial@78b2000 { + compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; + reg = <0x0 0x078b2000 0x0 0x200>; + interrupts = ; + clocks = <&gcc GCC_BLSP1_UART4_APPS_CLK>, + <&gcc GCC_BLSP1_AHB_CLK>; + clock-names = "core", "iface"; + status = "disabled"; + }; + + blsp1_uart5: serial@78b3000 { + compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; + reg = <0x0 0x78b3000 0x0 0x200>; + interrupts = ; + clocks = <&gcc GCC_BLSP1_UART5_APPS_CLK>, + <&gcc GCC_BLSP1_AHB_CLK>; + clock-names = "core", "iface"; + status = "disabled"; + }; + + blsp1_uart6: serial@78b4000 { + compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; + reg = <0x0 0x078b4000 0x0 0x200>; + interrupts = ; + clocks = <&gcc GCC_BLSP1_UART6_APPS_CLK>, + <&gcc GCC_BLSP1_AHB_CLK>; + clock-names = "core", "iface"; + status = "disabled"; + }; + blsp1_spi1: spi@78b5000 { compatible = "qcom,spi-qup-v2.2.1"; #address-cells = <1>; @@ -477,6 +534,20 @@ status = "disabled"; }; + blsp1_spi5: spi@78b9000 { + compatible = "qcom,spi-qup-v2.2.1"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0 0x078b9000 0x0 0x600>; + interrupts = ; + clocks = <&gcc GCC_BLSP1_QUP5_SPI_APPS_CLK>, + <&gcc GCC_BLSP1_AHB_CLK>; + clock-names = "core", "iface"; + dmas = <&blsp_dma 20>, <&blsp_dma 21>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + blsp1_i2c2: i2c@78b6000 { compatible = "qcom,i2c-qup-v2.2.1"; #address-cells = <1>; @@ -557,7 +628,7 @@ <&gcc GCC_USB0_MOCK_UTMI_CLK>; assigned-clock-rates = <133330000>, <133330000>, - <20000000>; + <24000000>; resets = <&gcc GCC_USB0_BCR>; status = "disabled"; @@ -566,7 +637,7 @@ compatible = "snps,dwc3"; reg = <0x0 0x08a00000 0x0 0xcd00>; interrupts = ; - phys = <&qusb_phy_0>, <&usb0_ssphy>; + phys = <&qusb_phy_0>, <&ssphy_0>; phy-names = "usb2-phy", "usb3-phy"; clocks = <&xo>; clock-names = "ref"; @@ -611,8 +682,8 @@ compatible = "qcom,ipq6018-apcs-apps-global"; reg = <0x0 0x0b111000 0x0 0x1000>; #clock-cells = <1>; - clocks = <&a53pll>, <&xo>; - clock-names = "pll", "xo"; + clocks = <&a53pll>, <&xo>, <&gcc GPLL0>; + clock-names = "pll", "xo", "gpll0"; #mbox-cells = <1>; }; @@ -731,7 +802,7 @@ }; }; - pcie0: pci@20000000 { + pcie0: pcie@20000000 { compatible = "qcom,pcie-ipq6018"; reg = <0x0 0x20000000 0x0 0xf1d>, <0x0 0x20000f20 0x0 0xa8>, diff --git a/arch/arm64/boot/dts/qcom/ipq8074.dtsi b/arch/arm64/boot/dts/qcom/ipq8074.dtsi index 2f275c84e56650..cf295bed329980 100644 --- a/arch/arm64/boot/dts/qcom/ipq8074.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq8074.dtsi @@ -125,32 +125,26 @@ ssphy_1: phy@58000 { compatible = "qcom,ipq8074-qmp-usb3-phy"; - reg = <0x00058000 0x1c4>; - #address-cells = <1>; - #size-cells = <1>; - ranges; + reg = <0x00058000 0x1000>; clocks = <&gcc GCC_USB1_AUX_CLK>, - <&gcc GCC_USB1_PHY_CFG_AHB_CLK>, - <&xo>; - clock-names = "aux", "cfg_ahb", "ref"; + <&xo>, + <&gcc GCC_USB1_PHY_CFG_AHB_CLK>, + <&gcc GCC_USB1_PIPE_CLK>; + clock-names = "aux", + "ref", + "cfg_ahb", + "pipe"; + clock-output-names = "usb3phy_1_cc_pipe_clk"; + #clock-cells = <0>; + #phy-cells = <0>; resets = <&gcc GCC_USB1_PHY_BCR>, - <&gcc GCC_USB3PHY_1_PHY_BCR>; - reset-names = "phy","common"; - status = "disabled"; + <&gcc GCC_USB3PHY_1_PHY_BCR>; + reset-names = "phy", + "phy_phy"; - usb1_ssphy: phy@58200 { - reg = <0x00058200 0x130>, /* Tx */ - <0x00058400 0x200>, /* Rx */ - <0x00058800 0x1f8>, /* PCS */ - <0x00058600 0x044>; /* PCS misc */ - #phy-cells = <0>; - #clock-cells = <0>; - clocks = <&gcc GCC_USB1_PIPE_CLK>; - clock-names = "pipe0"; - clock-output-names = "usb3phy_1_cc_pipe_clk"; - }; + status = "disabled"; }; qusb_phy_1: phy@59000 { @@ -168,32 +162,26 @@ ssphy_0: phy@78000 { compatible = "qcom,ipq8074-qmp-usb3-phy"; - reg = <0x00078000 0x1c4>; - #address-cells = <1>; - #size-cells = <1>; - ranges; + reg = <0x00078000 0x1000>; clocks = <&gcc GCC_USB0_AUX_CLK>, - <&gcc GCC_USB0_PHY_CFG_AHB_CLK>, - <&xo>; - clock-names = "aux", "cfg_ahb", "ref"; + <&xo>, + <&gcc GCC_USB0_PHY_CFG_AHB_CLK>, + <&gcc GCC_USB0_PIPE_CLK>; + clock-names = "aux", + "ref", + "cfg_ahb", + "pipe"; + clock-output-names = "usb3phy_0_cc_pipe_clk"; + #clock-cells = <0>; + #phy-cells = <0>; resets = <&gcc GCC_USB0_PHY_BCR>, - <&gcc GCC_USB3PHY_0_PHY_BCR>; - reset-names = "phy","common"; - status = "disabled"; + <&gcc GCC_USB3PHY_0_PHY_BCR>; + reset-names = "phy", + "phy_phy"; - usb0_ssphy: phy@78200 { - reg = <0x00078200 0x130>, /* Tx */ - <0x00078400 0x200>, /* Rx */ - <0x00078800 0x1f8>, /* PCS */ - <0x00078600 0x044>; /* PCS misc */ - #phy-cells = <0>; - #clock-cells = <0>; - clocks = <&gcc GCC_USB0_PIPE_CLK>; - clock-names = "pipe0"; - clock-output-names = "usb3phy_0_cc_pipe_clk"; - }; + status = "disabled"; }; qusb_phy_0: phy@79000 { @@ -369,8 +357,14 @@ gcc: gcc@1800000 { compatible = "qcom,gcc-ipq8074"; reg = <0x01800000 0x80000>; - clocks = <&xo>, <&sleep_clk>; - clock-names = "xo", "sleep_clk"; + clocks = <&xo>, + <&sleep_clk>, + <&pcie_qmp0>, + <&pcie_qmp1>; + clock-names = "xo", + "sleep_clk", + "pcie0_pipe", + "pcie1_pipe"; #clock-cells = <1>; #power-domain-cells = <1>; #reset-cells = <1>; @@ -406,7 +400,7 @@ }; sdhc_1: mmc@7824900 { - compatible = "qcom,sdhci-msm-v4"; + compatible = "qcom,ipq8074-sdhci", "qcom,sdhci-msm-v4"; reg = <0x7824900 0x500>, <0x7824000 0x800>; reg-names = "hc", "core"; @@ -523,6 +517,20 @@ status = "disabled"; }; + blsp1_spi4: spi@78b8000 { + compatible = "qcom,spi-qup-v2.2.1"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x78b8000 0x600>; + interrupts = ; + clocks = <&gcc GCC_BLSP1_QUP4_SPI_APPS_CLK>, + <&gcc GCC_BLSP1_AHB_CLK>; + clock-names = "core", "iface"; + dmas = <&blsp_dma 18>, <&blsp_dma 19>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + blsp1_i2c5: i2c@78b9000 { compatible = "qcom,i2c-qup-v2.2.1"; #address-cells = <1>; @@ -628,7 +636,7 @@ compatible = "snps,dwc3"; reg = <0x8a00000 0xcd00>; interrupts = ; - phys = <&qusb_phy_0>, <&usb0_ssphy>; + phys = <&qusb_phy_0>, <&ssphy_0>; phy-names = "usb2-phy", "usb3-phy"; snps,is-utmi-l1-suspend; snps,hird-threshold = /bits/ 8 <0x0>; @@ -670,7 +678,7 @@ compatible = "snps,dwc3"; reg = <0x8c00000 0xcd00>; interrupts = ; - phys = <&qusb_phy_1>, <&usb1_ssphy>; + phys = <&qusb_phy_1>, <&ssphy_1>; phy-names = "usb2-phy", "usb3-phy"; snps,is-utmi-l1-suspend; snps,hird-threshold = /bits/ 8 <0x0>; @@ -708,8 +716,8 @@ compatible = "qcom,ipq8074-apcs-apps-global", "qcom,ipq6018-apcs-apps-global"; reg = <0x0b111000 0x1000>; - clocks = <&a53pll>, <&xo>; - clock-names = "pll", "xo"; + clocks = <&a53pll>, <&xo>, <&gcc GPLL0>; + clock-names = "pll", "xo", "gpll0"; #clock-cells = <1>; #mbox-cells = <1>; @@ -781,7 +789,7 @@ }; }; - pcie1: pci@10000000 { + pcie1: pcie@10000000 { compatible = "qcom,pcie-ipq8074"; reg = <0x10000000 0xf1d>, <0x10000f20 0xa8>, @@ -842,7 +850,7 @@ status = "disabled"; }; - pcie0: pci@20000000 { + pcie0: pcie@20000000 { compatible = "qcom,pcie-ipq8074-gen3"; reg = <0x20000000 0xf1d>, <0x20000f20 0xa8>, diff --git a/arch/arm64/boot/dts/qcom/ipq9574-rdp-common.dtsi b/arch/arm64/boot/dts/qcom/ipq9574-rdp-common.dtsi new file mode 100644 index 00000000000000..91e104b0f86534 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/ipq9574-rdp-common.dtsi @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * IPQ9574 RDP board common device tree source + * + * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +/dts-v1/; + +#include +#include +#include +#include "ipq9574.dtsi" + +/ { + aliases { + serial0 = &blsp1_uart2; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + regulator_fixed_3p3: s3300 { + compatible = "regulator-fixed"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + regulator-name = "fixed_3p3"; + }; + + regulator_fixed_0p925: s0925 { + compatible = "regulator-fixed"; + regulator-min-microvolt = <925000>; + regulator-max-microvolt = <925000>; + regulator-boot-on; + regulator-always-on; + regulator-name = "fixed_0p925"; + }; + + gpio-keys { + compatible = "gpio-keys"; + pinctrl-0 = <&gpio_keys_default>; + pinctrl-names = "default"; + + button-wps { + label = "wps"; + linux,code = ; + gpios = <&tlmm 37 GPIO_ACTIVE_LOW>; + debounce-interval = <60>; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-0 = <&gpio_leds_default>; + pinctrl-names = "default"; + + led-0 { + color = ; + function = LED_FUNCTION_WLAN; + gpios = <&tlmm 64 GPIO_ACTIVE_LOW>; + linux,default-trigger = "phy0tx"; + default-state = "off"; + }; + }; +}; + +&blsp1_spi0 { + pinctrl-0 = <&spi_0_pins>; + pinctrl-names = "default"; + status = "okay"; + + flash@0 { + compatible = "micron,n25q128a11", "jedec,spi-nor"; + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <50000000>; + }; +}; + +&blsp1_uart2 { + pinctrl-0 = <&uart2_pins>; + pinctrl-names = "default"; + status = "okay"; +}; + +&rpm_requests { + regulators { + compatible = "qcom,rpm-mp5496-regulators"; + + ipq9574_s1: s1 { + /* + * During kernel bootup, the SoC runs at 800MHz with 875mV set by the bootloaders. + * During regulator registration, kernel not knowing the initial voltage, + * considers it as zero and brings up the regulators with minimum supported voltage. + * Update the regulator-min-microvolt with SVS voltage of 725mV so that + * the regulators are brought up with 725mV which is sufficient for all the + * corner parts to operate at 800MHz + */ + regulator-min-microvolt = <725000>; + regulator-max-microvolt = <1075000>; + }; + + mp5496_l2: l2 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + }; +}; + +&sleep_clk { + clock-frequency = <32000>; +}; + +&tlmm { + spi_0_pins: spi-0-state { + pins = "gpio11", "gpio12", "gpio13", "gpio14"; + function = "blsp0_spi"; + drive-strength = <8>; + bias-disable; + }; + + gpio_keys_default: gpio-keys-default-state { + pins = "gpio37"; + function = "gpio"; + drive-strength = <8>; + bias-pull-up; + }; + + gpio_leds_default: gpio-leds-default-state { + pins = "gpio64"; + function = "gpio"; + drive-strength = <8>; + bias-pull-up; + }; +}; + +&usb_0_dwc3 { + dr_mode = "host"; +}; + +&usb_0_qmpphy { + vdda-pll-supply = <&mp5496_l2>; + vdda-phy-supply = <®ulator_fixed_0p925>; + + status = "okay"; +}; + +&usb_0_qusbphy { + vdd-supply = <®ulator_fixed_0p925>; + vdda-pll-supply = <&mp5496_l2>; + vdda-phy-dpdm-supply = <®ulator_fixed_3p3>; + + status = "okay"; +}; + +&usb3 { + status = "okay"; +}; + +&xo_board_clk { + clock-frequency = <24000000>; +}; diff --git a/arch/arm64/boot/dts/qcom/ipq9574-rdp418.dts b/arch/arm64/boot/dts/qcom/ipq9574-rdp418.dts index 2b093e02637ba5..f4f9199d4ab1e5 100644 --- a/arch/arm64/boot/dts/qcom/ipq9574-rdp418.dts +++ b/arch/arm64/boot/dts/qcom/ipq9574-rdp418.dts @@ -8,58 +8,12 @@ /dts-v1/; -#include "ipq9574.dtsi" +#include "ipq9574-rdp-common.dtsi" / { model = "Qualcomm Technologies, Inc. IPQ9574/AP-AL02-C2"; compatible = "qcom,ipq9574-ap-al02-c2", "qcom,ipq9574"; - aliases { - serial0 = &blsp1_uart2; - }; - - chosen { - stdout-path = "serial0:115200n8"; - }; -}; - -&blsp1_spi0 { - pinctrl-0 = <&spi_0_pins>; - pinctrl-names = "default"; - status = "okay"; - - flash@0 { - compatible = "micron,n25q128a11", "jedec,spi-nor"; - reg = <0>; - #address-cells = <1>; - #size-cells = <1>; - spi-max-frequency = <50000000>; - }; -}; - -&blsp1_uart2 { - pinctrl-0 = <&uart2_pins>; - pinctrl-names = "default"; - status = "okay"; -}; - -&rpm_requests { - regulators { - compatible = "qcom,rpm-mp5496-regulators"; - - ipq9574_s1: s1 { - /* - * During kernel bootup, the SoC runs at 800MHz with 875mV set by the bootloaders. - * During regulator registration, kernel not knowing the initial voltage, - * considers it as zero and brings up the regulators with minimum supported voltage. - * Update the regulator-min-microvolt with SVS voltage of 725mV so that - * the regulators are brought up with 725mV which is sufficient for all the - * corner parts to operate at 800MHz - */ - regulator-min-microvolt = <725000>; - regulator-max-microvolt = <1075000>; - }; - }; }; &sdhc_1 { @@ -74,10 +28,6 @@ status = "okay"; }; -&sleep_clk { - clock-frequency = <32000>; -}; - &tlmm { sdc_default_state: sdc-default-state { clk-pins { @@ -110,15 +60,4 @@ bias-pull-down; }; }; - - spi_0_pins: spi-0-state { - pins = "gpio11", "gpio12", "gpio13", "gpio14"; - function = "blsp0_spi"; - drive-strength = <8>; - bias-disable; - }; -}; - -&xo_board_clk { - clock-frequency = <24000000>; }; diff --git a/arch/arm64/boot/dts/qcom/ipq9574-rdp433.dts b/arch/arm64/boot/dts/qcom/ipq9574-rdp433.dts index 877026ccc6e257..1bb8d96c9a8270 100644 --- a/arch/arm64/boot/dts/qcom/ipq9574-rdp433.dts +++ b/arch/arm64/boot/dts/qcom/ipq9574-rdp433.dts @@ -8,69 +8,11 @@ /dts-v1/; -#include "ipq9574.dtsi" +#include "ipq9574-rdp-common.dtsi" / { model = "Qualcomm Technologies, Inc. IPQ9574/AP-AL02-C7"; compatible = "qcom,ipq9574-ap-al02-c7", "qcom,ipq9574"; - - aliases { - serial0 = &blsp1_uart2; - }; - - chosen { - stdout-path = "serial0:115200n8"; - }; - - regulator_fixed_3p3: s3300 { - compatible = "regulator-fixed"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - regulator-boot-on; - regulator-always-on; - regulator-name = "fixed_3p3"; - }; - - regulator_fixed_0p925: s0925 { - compatible = "regulator-fixed"; - regulator-min-microvolt = <925000>; - regulator-max-microvolt = <925000>; - regulator-boot-on; - regulator-always-on; - regulator-name = "fixed_0p925"; - }; -}; - -&blsp1_uart2 { - pinctrl-0 = <&uart2_pins>; - pinctrl-names = "default"; - status = "okay"; -}; - -&rpm_requests { - regulators { - compatible = "qcom,rpm-mp5496-regulators"; - - ipq9574_s1: s1 { - /* - * During kernel bootup, the SoC runs at 800MHz with 875mV set by the bootloaders. - * During regulator registration, kernel not knowing the initial voltage, - * considers it as zero and brings up the regulators with minimum supported voltage. - * Update the regulator-min-microvolt with SVS voltage of 725mV so that - * the regulators are brought up with 725mV which is sufficient for all the - * corner parts to operate at 800MHz - */ - regulator-min-microvolt = <725000>; - regulator-max-microvolt = <1075000>; - }; - - mp5496_l2: l2 { - regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <1800000>; - regulator-always-on; - regulator-boot-on; - }; - }; }; &sdhc_1 { @@ -85,10 +27,6 @@ status = "okay"; }; -&sleep_clk { - clock-frequency = <32000>; -}; - &tlmm { sdc_default_state: sdc-default-state { clk-pins { @@ -122,30 +60,3 @@ }; }; }; - -&usb_0_dwc3 { - dr_mode = "host"; -}; - -&usb_0_qmpphy { - vdda-pll-supply = <&mp5496_l2>; - vdda-phy-supply = <®ulator_fixed_0p925>; - - status = "okay"; -}; - -&usb_0_qusbphy { - vdd-supply = <®ulator_fixed_0p925>; - vdda-pll-supply = <&mp5496_l2>; - vdda-phy-dpdm-supply = <®ulator_fixed_3p3>; - - status = "okay"; -}; - -&usb3 { - status = "okay"; -}; - -&xo_board_clk { - clock-frequency = <24000000>; -}; diff --git a/arch/arm64/boot/dts/qcom/ipq9574-rdp449.dts b/arch/arm64/boot/dts/qcom/ipq9574-rdp449.dts index c8fa54e1a62cc0..d36d1078763ec3 100644 --- a/arch/arm64/boot/dts/qcom/ipq9574-rdp449.dts +++ b/arch/arm64/boot/dts/qcom/ipq9574-rdp449.dts @@ -8,73 +8,10 @@ /dts-v1/; -#include "ipq9574.dtsi" +#include "ipq9574-rdp-common.dtsi" / { model = "Qualcomm Technologies, Inc. IPQ9574/AP-AL02-C6"; compatible = "qcom,ipq9574-ap-al02-c6", "qcom,ipq9574"; - aliases { - serial0 = &blsp1_uart2; - }; - - chosen { - stdout-path = "serial0:115200n8"; - }; -}; - -&blsp1_spi0 { - pinctrl-0 = <&spi_0_pins>; - pinctrl-names = "default"; - status = "okay"; - - flash@0 { - compatible = "micron,n25q128a11", "jedec,spi-nor"; - reg = <0>; - #address-cells = <1>; - #size-cells = <1>; - spi-max-frequency = <50000000>; - }; -}; - -&blsp1_uart2 { - pinctrl-0 = <&uart2_pins>; - pinctrl-names = "default"; - status = "okay"; -}; - -&rpm_requests { - regulators { - compatible = "qcom,rpm-mp5496-regulators"; - - ipq9574_s1: s1 { - /* - * During kernel bootup, the SoC runs at 800MHz with 875mV set by the bootloaders. - * During regulator registration, kernel not knowing the initial voltage, - * considers it as zero and brings up the regulators with minimum supported voltage. - * Update the regulator-min-microvolt with SVS voltage of 725mV so that - * the regulators are brought up with 725mV which is sufficient for all the - * corner parts to operate at 800MHz - */ - regulator-min-microvolt = <725000>; - regulator-max-microvolt = <1075000>; - }; - }; -}; - -&sleep_clk { - clock-frequency = <32000>; -}; - -&tlmm { - spi_0_pins: spi-0-state { - pins = "gpio11", "gpio12", "gpio13", "gpio14"; - function = "blsp0_spi"; - drive-strength = <8>; - bias-disable; - }; -}; - -&xo_board_clk { - clock-frequency = <24000000>; }; diff --git a/arch/arm64/boot/dts/qcom/ipq9574-rdp453.dts b/arch/arm64/boot/dts/qcom/ipq9574-rdp453.dts index f01de6628c3b11..c30c9fbedf26bf 100644 --- a/arch/arm64/boot/dts/qcom/ipq9574-rdp453.dts +++ b/arch/arm64/boot/dts/qcom/ipq9574-rdp453.dts @@ -8,73 +8,10 @@ /dts-v1/; -#include "ipq9574.dtsi" +#include "ipq9574-rdp-common.dtsi" / { model = "Qualcomm Technologies, Inc. IPQ9574/AP-AL02-C8"; compatible = "qcom,ipq9574-ap-al02-c8", "qcom,ipq9574"; - aliases { - serial0 = &blsp1_uart2; - }; - - chosen { - stdout-path = "serial0:115200n8"; - }; -}; - -&blsp1_spi0 { - pinctrl-0 = <&spi_0_pins>; - pinctrl-names = "default"; - status = "okay"; - - flash@0 { - compatible = "micron,n25q128a11", "jedec,spi-nor"; - reg = <0>; - #address-cells = <1>; - #size-cells = <1>; - spi-max-frequency = <50000000>; - }; -}; - -&blsp1_uart2 { - pinctrl-0 = <&uart2_pins>; - pinctrl-names = "default"; - status = "okay"; -}; - -&rpm_requests { - regulators { - compatible = "qcom,rpm-mp5496-regulators"; - - ipq9574_s1: s1 { - /* - * During kernel bootup, the SoC runs at 800MHz with 875mV set by the bootloaders. - * During regulator registration, kernel not knowing the initial voltage, - * considers it as zero and brings up the regulators with minimum supported voltage. - * Update the regulator-min-microvolt with SVS voltage of 725mV so that - * the regulators are brought up with 725mV which is sufficient for all the - * corner parts to operate at 800MHz - */ - regulator-min-microvolt = <725000>; - regulator-max-microvolt = <1075000>; - }; - }; -}; - -&sleep_clk { - clock-frequency = <32000>; -}; - -&tlmm { - spi_0_pins: spi-0-state { - pins = "gpio11", "gpio12", "gpio13", "gpio14"; - function = "blsp0_spi"; - drive-strength = <8>; - bias-disable; - }; -}; - -&xo_board_clk { - clock-frequency = <24000000>; }; diff --git a/arch/arm64/boot/dts/qcom/ipq9574-rdp454.dts b/arch/arm64/boot/dts/qcom/ipq9574-rdp454.dts index 6efae3426cb840..0dc382f5d5ecdf 100644 --- a/arch/arm64/boot/dts/qcom/ipq9574-rdp454.dts +++ b/arch/arm64/boot/dts/qcom/ipq9574-rdp454.dts @@ -8,73 +8,9 @@ /dts-v1/; -#include "ipq9574.dtsi" +#include "ipq9574-rdp-common.dtsi" / { model = "Qualcomm Technologies, Inc. IPQ9574/AP-AL02-C9"; compatible = "qcom,ipq9574-ap-al02-c9", "qcom,ipq9574"; - - aliases { - serial0 = &blsp1_uart2; - }; - - chosen { - stdout-path = "serial0:115200n8"; - }; -}; - -&blsp1_spi0 { - pinctrl-0 = <&spi_0_pins>; - pinctrl-names = "default"; - status = "okay"; - - flash@0 { - compatible = "micron,n25q128a11", "jedec,spi-nor"; - reg = <0>; - #address-cells = <1>; - #size-cells = <1>; - spi-max-frequency = <50000000>; - }; -}; - -&blsp1_uart2 { - pinctrl-0 = <&uart2_pins>; - pinctrl-names = "default"; - status = "okay"; -}; - -&rpm_requests { - regulators { - compatible = "qcom,rpm-mp5496-regulators"; - - ipq9574_s1: s1 { - /* - * During kernel bootup, the SoC runs at 800MHz with 875mV set by the bootloaders. - * During regulator registration, kernel not knowing the initial voltage, - * considers it as zero and brings up the regulators with minimum supported voltage. - * Update the regulator-min-microvolt with SVS voltage of 725mV so that - * the regulators are brought up with 725mV which is sufficient for all the - * corner parts to operate at 800MHz - */ - regulator-min-microvolt = <725000>; - regulator-max-microvolt = <1075000>; - }; - }; -}; - -&sleep_clk { - clock-frequency = <32000>; -}; - -&tlmm { - spi_0_pins: spi-0-state { - pins = "gpio11", "gpio12", "gpio13", "gpio14"; - function = "blsp0_spi"; - drive-strength = <8>; - bias-disable; - }; -}; - -&xo_board_clk { - clock-frequency = <24000000>; }; diff --git a/arch/arm64/boot/dts/qcom/ipq9574.dtsi b/arch/arm64/boot/dts/qcom/ipq9574.dtsi index 8a72ad4afd0320..5f83ee42a71942 100644 --- a/arch/arm64/boot/dts/qcom/ipq9574.dtsi +++ b/arch/arm64/boot/dts/qcom/ipq9574.dtsi @@ -106,42 +106,56 @@ }; cpu_opp_table: opp-table-cpu { - compatible = "operating-points-v2"; + compatible = "operating-points-v2-kryo-cpu"; opp-shared; + nvmem-cells = <&cpu_speed_bin>; opp-936000000 { opp-hz = /bits/ 64 <936000000>; opp-microvolt = <725000>; + opp-supported-hw = <0xf>; clock-latency-ns = <200000>; }; opp-1104000000 { opp-hz = /bits/ 64 <1104000000>; opp-microvolt = <787500>; + opp-supported-hw = <0xf>; + clock-latency-ns = <200000>; + }; + + opp-1200000000 { + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt = <862500>; + opp-supported-hw = <0xf>; clock-latency-ns = <200000>; }; opp-1416000000 { opp-hz = /bits/ 64 <1416000000>; opp-microvolt = <862500>; + opp-supported-hw = <0x7>; clock-latency-ns = <200000>; }; opp-1488000000 { opp-hz = /bits/ 64 <1488000000>; opp-microvolt = <925000>; + opp-supported-hw = <0x7>; clock-latency-ns = <200000>; }; opp-1800000000 { opp-hz = /bits/ 64 <1800000000>; opp-microvolt = <987500>; + opp-supported-hw = <0x5>; clock-latency-ns = <200000>; }; opp-2208000000 { opp-hz = /bits/ 64 <2208000000>; opp-microvolt = <1062500>; + opp-supported-hw = <0x1>; clock-latency-ns = <200000>; }; }; @@ -223,6 +237,11 @@ reg = <0x000a4000 0x5a1>; #address-cells = <1>; #size-cells = <1>; + + cpu_speed_bin: cpu-speed-bin@15 { + reg = <0x15 0x2>; + bits = <7 2>; + }; }; cryptobam: dma-controller@704000 { @@ -652,8 +671,8 @@ "qcom,ipq6018-apcs-apps-global"; reg = <0x0b111000 0x1000>; #clock-cells = <1>; - clocks = <&a73pll>, <&xo_board_clk>; - clock-names = "pll", "xo"; + clocks = <&a73pll>, <&xo_board_clk>, <&gcc GPLL0>; + clock-names = "pll", "xo", "gpll0"; #mbox-cells = <1>; }; diff --git a/arch/arm64/boot/dts/qcom/msm8916-acer-a1-724.dts b/arch/arm64/boot/dts/qcom/msm8916-acer-a1-724.dts index 57a74eea1005a3..b32c7a97394d8d 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-acer-a1-724.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-acer-a1-724.dts @@ -7,6 +7,7 @@ #include #include #include +#include /* * NOTE: The original firmware from Acer can only boot 32-bit kernels. @@ -83,6 +84,29 @@ }; }; +&blsp_i2c4 { + status = "okay"; + + led-controller@30 { + compatible = "kinetic,ktd2026"; + reg = <0x30>; + #address-cells = <1>; + #size-cells = <0>; + + led@0 { + reg = <0>; + function = LED_FUNCTION_STATUS; + color = ; + }; + + led@1 { + reg = <1>; + function = LED_FUNCTION_STATUS; + color = ; + }; + }; +}; + &blsp_i2c5 { status = "okay"; diff --git a/arch/arm64/boot/dts/qcom/msm8916-alcatel-idol347.dts b/arch/arm64/boot/dts/qcom/msm8916-alcatel-idol347.dts index aa4c1ab1e6737f..3459145516a12a 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-alcatel-idol347.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-alcatel-idol347.dts @@ -3,6 +3,8 @@ /dts-v1/; #include "msm8916-pm8916.dtsi" +#include "msm8916-modem-qdsp6.dtsi" + #include #include #include @@ -22,6 +24,19 @@ stdout-path = "serial0"; }; + reserved-memory { + /delete-node/ reserved@86680000; + /delete-node/ rmtfs@86700000; + + rmtfs: rmtfs@86680000 { + compatible = "qcom,rmtfs-mem"; + reg = <0x0 0x86680000 0x0 0x160000>; + no-map; + + qcom,client-id = <1>; + }; + }; + gpio-keys { compatible = "gpio-keys"; @@ -50,6 +65,17 @@ }; }; + reg_headphones_avdd: regulator-headphones-avdd { + compatible = "regulator-fixed"; + regulator-name = "headphones_avdd"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + gpio = <&tlmm 121 GPIO_ACTIVE_HIGH>; + enable-active-high; + pinctrl-0 = <&headphones_avdd_default>; + pinctrl-names = "default"; + }; + usb_id: usb-id { compatible = "linux,extcon-usb-gpio"; id-gpios = <&tlmm 69 GPIO_ACTIVE_HIGH>; @@ -58,8 +84,41 @@ }; }; -&blsp_uart2 { +&blsp_i2c3 { status = "okay"; + + headphones: audio-codec@10 { + compatible = "asahi-kasei,ak4375"; + reg = <0x10>; + avdd-supply = <®_headphones_avdd>; + tvdd-supply = <&pm8916_l6>; + pdn-gpios = <&tlmm 114 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&headphones_pdn_default>; + pinctrl-names = "default"; + #sound-dai-cells = <0>; + }; + + speaker_codec_top: audio-codec@34 { + compatible = "nxp,tfa9897"; + reg = <0x34>; + vddd-supply = <&pm8916_l6>; + rcv-gpios = <&tlmm 50 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&speaker_top_default>; + pinctrl-names = "default"; + sound-name-prefix = "Speaker Top"; + #sound-dai-cells = <0>; + }; + + speaker_codec_bottom: audio-codec@36 { + compatible = "nxp,tfa9897"; + reg = <0x36>; + vddd-supply = <&pm8916_l6>; + rcv-gpios = <&tlmm 111 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&speaker_bottom_default>; + pinctrl-names = "default"; + sound-name-prefix = "Speaker Bottom"; + #sound-dai-cells = <0>; + }; }; &blsp_i2c4 { @@ -153,6 +212,22 @@ }; }; +&blsp_uart2 { + status = "okay"; +}; + +&mpss_mem { + reg = <0x0 0x86800000 0x0 0x5000000>; +}; + +&pm8916_codec { + qcom,micbias1-ext-cap; + qcom,micbias-lvl = <2800>; + qcom,mbhc-vthreshold-low = <75 100 120 180 500>; + qcom,mbhc-vthreshold-high = <75 100 120 180 500>; + qcom,hphl-jack-type-normally-open; +}; + &pm8916_resin { status = "okay"; linux,code = ; @@ -169,6 +244,17 @@ status = "okay"; }; +&q6afedai { + dai@18 { + reg = ; + qcom,sd-lines = <0>; + }; + dai@22 { + reg = ; + qcom,sd-lines = <0>; + }; +}; + &sdhc_1 { status = "okay"; }; @@ -183,6 +269,54 @@ cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>; }; +&sound { + /* Add pin switches for speakers to allow disabling them individually */ + model = "alcatel-idol3"; + widgets = + "Speaker", "Speaker Top", + "Speaker", "Speaker Bottom"; + pin-switches = "Speaker Top", "Speaker Bottom"; + audio-routing = + "Speaker Top", "Speaker Top OUT", + "Speaker Bottom", "Speaker Bottom OUT", + "AMIC1", "MIC BIAS External1", + "AMIC2", "MIC BIAS Internal2", + "AMIC3", "MIC BIAS External1"; + + pinctrl-0 = <&cdc_pdm_default &pri_mi2s_default &pri_mi2s_ws_default &sec_mi2s_default>; + pinctrl-1 = <&cdc_pdm_sleep &pri_mi2s_sleep &pri_mi2s_ws_sleep &sec_mi2s_sleep>; + pinctrl-names = "default", "sleep"; + + sound_link_backend2: backend2-dai-link { + link-name = "Quaternary MI2S"; + + cpu { + sound-dai = <&q6afedai QUATERNARY_MI2S_RX>; + }; + platform { + sound-dai = <&q6routing>; + }; + codec { + sound-dai = <&speaker_codec_top>, <&speaker_codec_bottom>; + }; + }; +}; + +&sound_link_backend0 { + /* Primary MI2S is not used, replace with Secondary MI2S for headphones */ + link-name = "Secondary MI2S"; + + cpu { + sound-dai = <&q6afedai SECONDARY_MI2S_RX>; + }; + platform { + sound-dai = <&q6routing>; + }; + codec { + sound-dai = <&headphones>; + }; +}; + &usb { status = "okay"; extcon = <&usb_id>, <&usb_id>; @@ -212,6 +346,15 @@ status = "okay"; }; +/* Only some of the pins are used */ +&pri_mi2s_default { + pins = "gpio113", "gpio115"; +}; + +&pri_mi2s_sleep { + pins = "gpio113", "gpio115"; +}; + &tlmm { accel_int_default: accel-int-default-state { pins = "gpio31"; @@ -245,6 +388,20 @@ bias-disable; }; + headphones_avdd_default: headphones-avdd-default-state { + pins = "gpio121"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + headphones_pdn_default: headphones-pdn-default-state { + pins = "gpio114"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + /* * The OEM wired an additional GPIO to be asserted so that * the si-en,sn3190 LED IC works. Since this GPIO is not @@ -291,6 +448,20 @@ bias-disable; }; + speaker_bottom_default: speaker-bottom-default-state { + pins = "gpio111"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + speaker_top_default: speaker-top-default-state { + pins = "gpio50"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + ts_int_reset_default: ts-int-reset-default-state { pins = "gpio13", "gpio100"; function = "gpio"; diff --git a/arch/arm64/boot/dts/qcom/msm8916-asus-z00l.dts b/arch/arm64/boot/dts/qcom/msm8916-asus-z00l.dts index a8be6ff66893f3..77618c7374dfe2 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-asus-z00l.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-asus-z00l.dts @@ -3,6 +3,8 @@ /dts-v1/; #include "msm8916-pm8916.dtsi" +#include "msm8916-modem-qdsp6.dtsi" + #include #include #include @@ -130,6 +132,18 @@ status = "okay"; }; +&mpss_mem { + reg = <0x0 0x86800000 0x0 0x5500000>; +}; + +&pm8916_codec { + qcom,micbias-lvl = <2800>; + qcom,mbhc-vthreshold-low = <75 150 237 450 500>; + qcom,mbhc-vthreshold-high = <75 150 237 450 500>; + qcom,micbias1-ext-cap; + qcom,hphl-jack-type-normally-open; +}; + &pm8916_rpm_regulators { pm8916_l17: l17 { regulator-min-microvolt = <2850000>; @@ -151,6 +165,13 @@ cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>; }; +&sound { + audio-routing = + "AMIC1", "MIC BIAS External1", + "AMIC2", "MIC BIAS Internal2", + "AMIC3", "MIC BIAS External1"; +}; + &usb { status = "okay"; extcon = <&usb_id>, <&usb_id>; diff --git a/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts b/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts index 47d1c5cb13f4ee..3a3e794c022f91 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8150.dts @@ -3,6 +3,8 @@ /dts-v1/; #include "msm8916-pm8916.dtsi" +#include "msm8916-modem-qdsp6.dtsi" + #include #include #include @@ -25,17 +27,45 @@ /* * For some reason, the signed wcnss firmware is not relocatable. - * It must be loaded at 0x8b600000. All other firmware is relocatable, - * so place wcnss at the fixed address and then all other firmware - * regions will be automatically allocated at a fitting place. + * It must be loaded at 0x8b600000. Unfortunately, this also means that + * mpss_mem does not fit when loaded to the typical address at 0x86800000. + * + * Load wcnss_mem to the fixed address and relocate mpss_mem to the next + * working higher address. For some reason the modem firmware does not + * boot when placed at 0x8a800000 to 0x8e800000. */ reserved-memory { + /delete-node/ mpss@86800000; /delete-node/ wcnss; wcnss_mem: wcnss@8b600000 { reg = <0x0 0x8b600000 0x0 0x600000>; no-map; }; + + mpss_mem: mpss@8e800000 { + reg = <0x0 0x8e800000 0x0 0x5000000>; + no-map; + }; + }; + + battery: battery { + compatible = "simple-battery"; + voltage-min-design-microvolt = <3400000>; + voltage-max-design-microvolt = <4350000>; + energy-full-design-microwatt-hours = <9500000>; + charge-full-design-microamp-hours = <2500000>; + + ocv-capacity-celsius = <25>; + ocv-capacity-table-0 = <4330000 100>, <4265000 95>, + <4208000 90>, <4153000 85>, <4100000 80>, <4049000 75>, + <4001000 70>, <3962000 65>, <3919000 60>, <3872000 55>, + <3839000 50>, <3817000 45>, <3798000 40>, <3783000 35>, + <3767000 30>, <3747000 25>, <3729000 20>, <3709000 16>, + <3688000 13>, <3681000 11>, <3680000 10>, <3679000 9>, + <3677000 8>, <3674000 7>, <3666000 6>, <3641000 5>, + <3597000 4>, <3537000 3>, <3457000 2>, <3336000 1>, + <3000000 0>; }; gpio-keys { @@ -93,6 +123,7 @@ #size-cells = <0>; vcc-supply = <&pm8916_l17>; + vio-supply = <&pm8916_l6>; led@0 { reg = <0>; @@ -225,6 +256,29 @@ status = "okay"; }; +&pm8916_bms { + status = "okay"; + + monitored-battery = <&battery>; + power-supplies = <&pm8916_charger>; +}; + +&pm8916_charger { + status = "okay"; + + monitored-battery = <&battery>; + + qcom,fast-charge-safe-current = <900000>; + qcom,fast-charge-safe-voltage = <4300000>; +}; + +&pm8916_codec { + qcom,micbias-lvl = <2800>; + qcom,mbhc-vthreshold-low = <75 150 237 450 500>; + qcom,mbhc-vthreshold-high = <75 150 237 450 500>; + qcom,hphl-jack-type-normally-open; +}; + &pm8916_resin { status = "okay"; linux,code = ; @@ -237,10 +291,6 @@ }; }; -&pm8916_usbin { - status = "okay"; -}; - &pm8916_vib { status = "okay"; }; @@ -254,14 +304,21 @@ non-removable; }; +&sound { + audio-routing = + "AMIC1", "MIC BIAS Internal1", + "AMIC2", "MIC BIAS Internal2", + "AMIC3", "MIC BIAS Internal3"; +}; + &usb { status = "okay"; dr_mode = "peripheral"; - extcon = <&pm8916_usbin>; + extcon = <&pm8916_charger>; }; &usb_hs_phy { - extcon = <&pm8916_usbin>; + extcon = <&pm8916_charger>; }; &venus { diff --git a/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8910.dts b/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8910.dts index 41cadb906b98cc..3b7fdb6797a942 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8910.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-longcheer-l8910.dts @@ -3,9 +3,12 @@ /dts-v1/; #include "msm8916-pm8916.dtsi" +#include "msm8916-modem-qdsp6.dtsi" + #include #include #include +#include / { model = "BQ Aquaris X5 (Longcheer L8910)"; @@ -22,6 +25,16 @@ stdout-path = "serial0"; }; + speaker_amp: audio-amplifier { + compatible = "awinic,aw8738"; + mode-gpios = <&tlmm 114 GPIO_ACTIVE_HIGH>; + awinic,mode = <5>; + sound-name-prefix = "Speaker Amp"; + + pinctrl-0 = <&spk_ext_pa_default>; + pinctrl-names = "default"; + }; + flash-led-controller { compatible = "ocs,ocp8110"; enable-gpios = <&tlmm 49 GPIO_ACTIVE_HIGH>; @@ -74,6 +87,46 @@ }; }; +&blsp_i2c2 { + status = "okay"; + + led-controller@30 { + compatible = "kinetic,ktd2026"; + reg = <0x30>; + #address-cells = <1>; + #size-cells = <0>; + + vin-supply = <&pm8916_l17>; + vio-supply = <&pm8916_l6>; + + pinctrl-0 = <&status_led_default>; + pinctrl-names = "default"; + + multi-led { + color = ; + function = LED_FUNCTION_STATUS; + + #address-cells = <1>; + #size-cells = <0>; + + led@0 { + reg = <0>; + color = ; + }; + + led@1 { + reg = <1>; + color = ; + }; + + led@2 { + reg = <2>; + color = ; + }; + }; + }; +}; + &blsp_i2c3 { status = "okay"; @@ -107,6 +160,27 @@ status = "okay"; }; +&mpss_mem { + reg = <0x0 0x86800000 0x0 0x5000000>; +}; + +&pm8916_codec { + qcom,micbias-lvl = <2800>; + qcom,mbhc-vthreshold-low = <75 100 120 180 500>; + qcom,mbhc-vthreshold-high = <75 100 120 180 500>; + qcom,hphl-jack-type-normally-open; +}; + +&pm8916_gpios { + status_led_default: status-led-default-state { + pins = "gpio3"; + function = PMIC_GPIO_FUNC_NORMAL; + power-source = ; + bias-disable; + output-high; + }; +}; + &pm8916_resin { status = "okay"; linux,code = ; @@ -137,6 +211,28 @@ cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>; }; +&sound { + /* + * Provide widgets/pin-switches to allow enabling speaker separately. + * The hardware does not provide a way to disable the output via the + * headphone jack when the speaker is enabled. + */ + model = "bq-paella"; + widgets = + "Speaker", "Speaker", + "Headphone", "Headphones"; + pin-switches = "Speaker"; + audio-routing = + "Speaker", "Speaker Amp OUT", + "Speaker Amp IN", "HPH_R", + "Headphones", "HPH_L", + "Headphones", "HPH_R", + "AMIC1", "MIC BIAS External1", + "AMIC2", "MIC BIAS Internal2", + "AMIC3", "MIC BIAS External1"; + aux-devs = <&speaker_amp>; +}; + &usb { status = "okay"; extcon = <&usb_id>, <&usb_id>; @@ -205,6 +301,13 @@ bias-disable; }; + spk_ext_pa_default: spk-ext-pa-default-state { + pins = "gpio114"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + usb_id_default: usb-id-default-state { pins = "gpio110"; function = "gpio"; diff --git a/arch/arm64/boot/dts/qcom/msm8916-modem-qdsp6.dtsi b/arch/arm64/boot/dts/qcom/msm8916-modem-qdsp6.dtsi new file mode 100644 index 00000000000000..0399616226330b --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8916-modem-qdsp6.dtsi @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +/* + * msm8916-modem-qdsp6.dtsi describes the typical modem setup on MSM8916 devices + * (or similar SoCs) with audio routed via the QDSP6 services provided by the + * modem firmware. The digital/analog codec in the SoC/PMIC is used by default, + * but boards can define additional codecs by adding additional backend DAI links. + */ + +#include +#include + +&apr { + status = "okay"; +}; + +&bam_dmux { + status = "okay"; +}; + +&bam_dmux_dma { + status = "okay"; +}; + +&lpass { + status = "reserved"; /* Controlled by QDSP6 */ +}; + +&lpass_codec { + status = "okay"; +}; + +&mba_mem { + status = "okay"; +}; + +&mpss { + status = "okay"; +}; + +&mpss_mem { + status = "okay"; +}; + +&pm8916_codec { + status = "okay"; +}; + +&q6afedai { + dai@16 { + reg = ; + qcom,sd-lines = <0 1>; + }; + dai@20 { + reg = ; + qcom,sd-lines = <0 1>; + }; +}; + +&q6asmdai { + dai@0 { + reg = <0>; + direction = ; + }; + dai@1 { + reg = <1>; + direction = ; + }; + dai@2 { + reg = <2>; + direction = ; + }; + dai@3 { + reg = <3>; + direction = ; + is-compress-dai; + }; +}; + +&sound { + compatible = "qcom,msm8916-qdsp6-sndcard"; + model = "msm8916"; + + pinctrl-0 = <&cdc_pdm_default>; + pinctrl-1 = <&cdc_pdm_sleep>; + pinctrl-names = "default", "sleep"; + + status = "okay"; + + frontend0-dai-link { + link-name = "MultiMedia1"; + + cpu { + sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA1>; + }; + }; + + frontend1-dai-link { + link-name = "MultiMedia2"; + + cpu { + sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA2>; + }; + }; + + frontend2-dai-link { + link-name = "MultiMedia3"; + + cpu { + sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA3>; + }; + }; + + frontend3-dai-link { + link-name = "MultiMedia4"; + + cpu { + sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA4>; + }; + }; + + sound_link_backend0: backend0-dai-link { + link-name = "Primary MI2S"; + + cpu { + sound-dai = <&q6afedai PRIMARY_MI2S_RX>; + }; + platform { + sound-dai = <&q6routing>; + }; + codec { + sound-dai = <&lpass_codec 0>, <&pm8916_codec 0>; + }; + }; + + sound_link_backend1: backend1-dai-link { + link-name = "Tertiary MI2S"; + + cpu { + sound-dai = <&q6afedai TERTIARY_MI2S_TX>; + }; + platform { + sound-dai = <&q6routing>; + }; + codec { + sound-dai = <&lpass_codec 1>, <&pm8916_codec 1>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-a2015-common.dtsi b/arch/arm64/boot/dts/qcom/msm8916-samsung-a2015-common.dtsi index 0b29132b74e1da..2937495940ea02 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-samsung-a2015-common.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-a2015-common.dtsi @@ -1,10 +1,13 @@ // SPDX-License-Identifier: GPL-2.0-only #include "msm8916-pm8916.dtsi" +#include "msm8916-modem-qdsp6.dtsi" + #include #include #include #include +#include / { aliases { @@ -196,6 +199,18 @@ }; }; +&blsp_i2c1 { + status = "okay"; + + speaker_codec: audio-codec@34 { + compatible = "nxp,tfa9895"; + reg = <0x34>; + vddd-supply = <&pm8916_l5>; + sound-name-prefix = "Speaker"; + #sound-dai-cells = <0>; + }; +}; + &blsp_i2c2 { status = "okay"; @@ -243,6 +258,25 @@ status = "okay"; }; +/* + * For some reason the speaker amplifier is connected to the second SD line + * (MI2S_2_D1) instead of the first (MI2S_2_D0). This must be configured in the + * device tree, otherwise audio will seemingly play fine on the wrong SD line + * but the speaker stays silent. + * + * When routing audio via QDSP6 (the default) the &lpass node is reserved and + * the definitions from &q6afedai are used. When the modem is disabled audio can + * be alternatively routed directly to the LPASS hardware with reduced latency. + * The definitions for &lpass are here for completeness to simplify changing the + * setup with minor changes to the DT (either manually or with DT overlays). + */ +&lpass { + dai-link@3 { + reg = ; + qcom,playback-sd-lines = <1>; + }; +}; + &mdss { status = "okay"; }; @@ -253,6 +287,10 @@ pinctrl-1 = <&mdss_sleep>; }; +&mpss_mem { + reg = <0x0 0x86800000 0x0 0x5400000>; +}; + &pm8916_resin { status = "okay"; linux,code = ; @@ -265,6 +303,13 @@ }; }; +&q6afedai { + dai@22 { + reg = ; + qcom,sd-lines = <1>; + }; +}; + &sdhc_1 { status = "okay"; }; @@ -279,6 +324,32 @@ cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>; }; +&sound { + model = "samsung-a2015"; + audio-routing = + "AMIC1", "MIC BIAS External1", + "AMIC2", "MIC BIAS Internal2", + "AMIC3", "MIC BIAS External1"; + + pinctrl-0 = <&cdc_pdm_default &sec_mi2s_default>; + pinctrl-1 = <&cdc_pdm_sleep &sec_mi2s_sleep>; + pinctrl-names = "default", "sleep"; + + sound_link_backend2: backend2-dai-link { + link-name = "Quaternary MI2S"; + + cpu { + sound-dai = <&q6afedai QUATERNARY_MI2S_RX>; + }; + platform { + sound-dai = <&q6routing>; + }; + codec { + sound-dai = <&speaker_codec>; + }; + }; +}; + &usb { status = "okay"; extcon = <&muic>, <&muic>; diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-a3u-eur.dts b/arch/arm64/boot/dts/qcom/msm8916-samsung-a3u-eur.dts index f5a8083695182a..3b934f5eba4732 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-samsung-a3u-eur.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-a3u-eur.dts @@ -49,11 +49,6 @@ }; }; -&touchkey { - vcc-supply = <®_touch_key>; - vdd-supply = <®_key_led>; -}; - &accelerometer { mount-matrix = "0", "1", "0", "1", "0", "0", @@ -108,6 +103,11 @@ remote-endpoint = <&panel_in>; }; +&touchkey { + vcc-supply = <®_touch_key>; + vdd-supply = <®_key_led>; +}; + &vibrator { status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-e2015-common.dtsi b/arch/arm64/boot/dts/qcom/msm8916-samsung-e2015-common.dtsi index 0824ab041d805d..3c49dac92d2d4a 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-samsung-e2015-common.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-e2015-common.dtsi @@ -65,6 +65,10 @@ }; }; +&mpss_mem { + reg = <0x0 0x86800000 0x0 0x5a00000>; +}; + ®_motor_vdd { regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-grandmax.dts b/arch/arm64/boot/dts/qcom/msm8916-samsung-grandmax.dts index 3f145dde4059f8..5882b3a593b8c9 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-samsung-grandmax.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-grandmax.dts @@ -49,6 +49,10 @@ status = "disabled"; }; +&sound { + model = "samsung-gmax"; /* No secondary microphone */ +}; + &tlmm { gpio_leds_default: gpio-led-default-state { pins = "gpio60"; diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-gt5-common.dtsi b/arch/arm64/boot/dts/qcom/msm8916-samsung-gt5-common.dtsi index c19cf20d74272c..fbd2caf405d5f6 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-samsung-gt5-common.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-gt5-common.dtsi @@ -3,9 +3,12 @@ /dts-v1/; #include "msm8916-pm8916.dtsi" +#include "msm8916-modem-qdsp6.dtsi" + #include #include #include +#include / { aliases { @@ -65,25 +68,6 @@ }; }; -&blsp_i2c4 { - status = "okay"; - - fuelgauge@36 { - compatible = "maxim,max77849-battery"; - reg = <0x36>; - - maxim,rsns-microohm = <10000>; - maxim,over-heat-temp = <600>; - maxim,over-volt = <4400>; - - interrupt-parent = <&tlmm>; - interrupts = <121 IRQ_TYPE_EDGE_FALLING>; - - pinctrl-0 = <&fuelgauge_int_default>; - pinctrl-names = "default"; - }; -}; - &blsp_i2c2 { status = "okay"; @@ -112,10 +96,52 @@ }; }; +&blsp_i2c4 { + status = "okay"; + + fuelgauge@36 { + compatible = "maxim,max77849-battery"; + reg = <0x36>; + + maxim,rsns-microohm = <10000>; + maxim,over-heat-temp = <600>; + maxim,over-volt = <4400>; + + interrupt-parent = <&tlmm>; + interrupts = <121 IRQ_TYPE_EDGE_FALLING>; + + pinctrl-0 = <&fuelgauge_int_default>; + pinctrl-names = "default"; + }; +}; + &blsp_uart2 { status = "okay"; }; +/* + * For some reason the speaker amplifier is connected to the second SD line + * (MI2S_2_D1) instead of the first (MI2S_2_D0). This must be configured in the + * device tree, otherwise audio will seemingly play fine on the wrong SD line + * but the speaker stays silent. + * + * When routing audio via QDSP6 (the default) the &lpass node is reserved and + * the definitions from &q6afedai are used. When the modem is disabled audio can + * be alternatively routed directly to the LPASS hardware with reduced latency. + * The definitions for &lpass are here for completeness to simplify changing the + * setup with minor changes to the DT (either manually or with DT overlays). + */ +&lpass { + dai-link@3 { + reg = ; + qcom,playback-sd-lines = <1>; + }; +}; + +&mpss_mem { + reg = <0x0 0x86800000 0x0 0x5400000>; +}; + &pm8916_resin { linux,code = ; status = "okay"; @@ -133,6 +159,13 @@ status = "okay"; }; +&q6afedai { + dai@22 { + reg = ; + qcom,sd-lines = <1>; + }; +}; + &sdhc_1 { status = "okay"; }; @@ -147,6 +180,27 @@ status = "okay"; }; +&sound { + audio-routing = + "AMIC1", "MIC BIAS External1", + "AMIC2", "MIC BIAS Internal2", + "AMIC3", "MIC BIAS External1"; + + sound_link_backend2: backend2-dai-link { + link-name = "Quaternary MI2S"; + + cpu { + sound-dai = <&q6afedai QUATERNARY_MI2S_RX>; + }; + platform { + sound-dai = <&q6routing>; + }; + codec { + sound-dai = <&speaker_codec>; + }; + }; +}; + &usb { dr_mode = "peripheral"; extcon = <&pm8916_usbin>; diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-gt510.dts b/arch/arm64/boot/dts/qcom/msm8916-samsung-gt510.dts index 75c4854ecd6482..5b34529b816c84 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-samsung-gt510.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-gt510.dts @@ -9,6 +9,14 @@ compatible = "samsung,gt510", "qcom,msm8916"; chassis-type = "tablet"; + speaker_codec: audio-codec { + compatible = "maxim,max98357a"; + sdmode-gpios = <&tlmm 55 GPIO_ACTIVE_HIGH>; + #sound-dai-cells = <0>; + pinctrl-0 = <&audio_sdmode_default>; + pinctrl-names = "default"; + }; + clk_pwm: pwm { compatible = "clk-pwm"; #pwm-cells = <2>; @@ -112,6 +120,10 @@ }; }; +&gpu { + status = "okay"; +}; + &mdss { status = "okay"; }; @@ -142,7 +154,21 @@ remote-endpoint = <&panel_in>; }; +&sound { + model = "samsung-gt510"; + pinctrl-0 = <&cdc_pdm_default &sec_mi2s_default>; + pinctrl-1 = <&cdc_pdm_sleep &sec_mi2s_sleep>; + pinctrl-names = "default", "sleep"; +}; + &tlmm { + audio_sdmode_default: audio-sdmode-default-state { + pins = "gpio55"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + buckbooster_en_default: buckbooster-en-default-state { pins = "gpio51"; function = "gpio"; diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-gt58.dts b/arch/arm64/boot/dts/qcom/msm8916-samsung-gt58.dts index 11359bcc27b3d9..579312ed53ce1a 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-samsung-gt58.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-gt58.dts @@ -35,6 +35,26 @@ pinctrl-names = "default"; }; + i2c-amplifier { + compatible = "i2c-gpio"; + sda-gpios = <&tlmm 55 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + scl-gpios = <&tlmm 56 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + + pinctrl-0 = <&_i2c_default>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + speaker_codec: audio-codec@34 { + compatible = "nxp,tfa9895"; + reg = <0x34>; + vddd-supply = <&pm8916_l5>; + sound-name-prefix = "Speaker"; + #sound-dai-cells = <0>; + }; + }; + vibrator { compatible = "gpio-vibrator"; enable-gpios = <&tlmm 76 GPIO_ACTIVE_HIGH>; @@ -64,6 +84,10 @@ }; }; +&gpu { + status = "okay"; +}; + &mdss { status = "okay"; }; @@ -94,7 +118,21 @@ remote-endpoint = <&panel_in>; }; +&sound { + model = "samsung-a2015"; + pinctrl-0 = <&cdc_pdm_default &sec_mi2s_default &secondary_mic_default>; + pinctrl-1 = <&cdc_pdm_sleep &sec_mi2s_sleep &secondary_mic_default>; + pinctrl-names = "default", "sleep"; +}; + &tlmm { + amp_i2c_default: amp-i2c-default-state { + pins = "gpio55", "gpio56"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + buckbooster_en_default: buckbooster-en-default-state { pins = "gpio8"; function = "gpio"; @@ -123,6 +161,14 @@ bias-disable; }; + secondary_mic_default: secondary-mic-default-state { + pins = "gpio98"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + output-high; + }; + tsp_int_default: tsp-int-default-state { pins = "gpio13"; function = "gpio"; diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-j5-common.dtsi b/arch/arm64/boot/dts/qcom/msm8916-samsung-j5-common.dtsi index fe59be3505fe1b..5ca2ada266f495 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-samsung-j5-common.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-j5-common.dtsi @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only #include "msm8916-pm8916.dtsi" +#include "msm8916-modem-qdsp6.dtsi" + #include #include #include @@ -135,6 +137,10 @@ status = "okay"; }; +&mpss_mem { + reg = <0x0 0x86800000 0x0 0x5800000>; +}; + &pm8916_resin { status = "okay"; linux,code = ; @@ -154,6 +160,14 @@ cd-gpios = <&tlmm 38 GPIO_ACTIVE_LOW>; }; +&sound { + model = "msm8916-1mic"; + audio-routing = + "AMIC1", "MIC BIAS External1", + "AMIC2", "MIC BIAS Internal2", + "AMIC3", "MIC BIAS External1"; +}; + &usb { extcon = <&muic>, <&muic>; status = "okay"; diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-j5.dts b/arch/arm64/boot/dts/qcom/msm8916-samsung-j5.dts index 58c2f5a70e785a..ba8650971d6a95 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-samsung-j5.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-j5.dts @@ -19,6 +19,10 @@ status = "disabled"; }; +&pm8916_codec { + qcom,micbias1-ext-cap; +}; + &touchscreen { /* FIXME: Missing sm5703-mfd driver to power up vdd-supply */ }; diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-serranove.dts b/arch/arm64/boot/dts/qcom/msm8916-samsung-serranove.dts index 68da2a2d30774d..5ce8f1350abcfa 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-samsung-serranove.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-serranove.dts @@ -6,6 +6,8 @@ /dts-v1/; #include "msm8916-pm8916.dtsi" +#include "msm8916-modem-qdsp6.dtsi" + #include #include #include @@ -319,6 +321,10 @@ status = "okay"; }; +&mpss_mem { + reg = <0x0 0x86800000 0x0 0x5a00000>; +}; + &pm8916_resin { status = "okay"; linux,code = ; @@ -350,6 +356,13 @@ no-1-8-v; }; +&sound { + audio-routing = + "AMIC1", "MIC BIAS External1", + "AMIC2", "MIC BIAS Internal2", + "AMIC3", "MIC BIAS External1"; +}; + &usb { status = "okay"; extcon = <&muic>, <&muic>; diff --git a/arch/arm64/boot/dts/qcom/msm8916-thwc-uf896.dts b/arch/arm64/boot/dts/qcom/msm8916-thwc-uf896.dts index 6fe1850ba20e9e..f3499750089115 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-thwc-uf896.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-thwc-uf896.dts @@ -13,16 +13,16 @@ gpios = <&tlmm 35 GPIO_ACTIVE_LOW>; }; -&led_r { - gpios = <&tlmm 82 GPIO_ACTIVE_HIGH>; +&led_b { + gpios = <&tlmm 81 GPIO_ACTIVE_HIGH>; }; &led_g { gpios = <&tlmm 83 GPIO_ACTIVE_HIGH>; }; -&led_b { - gpios = <&tlmm 81 GPIO_ACTIVE_HIGH>; +&led_r { + gpios = <&tlmm 82 GPIO_ACTIVE_HIGH>; }; &button_default { diff --git a/arch/arm64/boot/dts/qcom/msm8916-thwc-ufi001c.dts b/arch/arm64/boot/dts/qcom/msm8916-thwc-ufi001c.dts index 16d4a91022be6f..6cb3911ba1c9ef 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-thwc-ufi001c.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-thwc-ufi001c.dts @@ -13,16 +13,16 @@ gpios = <&tlmm 37 GPIO_ACTIVE_HIGH>; }; -&led_r { - gpios = <&tlmm 22 GPIO_ACTIVE_HIGH>; +&led_b { + gpios = <&tlmm 20 GPIO_ACTIVE_HIGH>; }; &led_g { gpios = <&tlmm 21 GPIO_ACTIVE_HIGH>; }; -&led_b { - gpios = <&tlmm 20 GPIO_ACTIVE_HIGH>; +&led_r { + gpios = <&tlmm 22 GPIO_ACTIVE_HIGH>; }; &mpss { diff --git a/arch/arm64/boot/dts/qcom/msm8916-wingtech-wt88047.dts b/arch/arm64/boot/dts/qcom/msm8916-wingtech-wt88047.dts index 419f35c1fc92ed..510b3b3c4e3c42 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-wingtech-wt88047.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-wingtech-wt88047.dts @@ -6,6 +6,8 @@ /dts-v1/; #include "msm8916-pm8916.dtsi" +#include "msm8916-modem-qdsp6.dtsi" + #include #include #include @@ -25,6 +27,28 @@ stdout-path = "serial0"; }; + speaker_amp: audio-amplifier { + compatible = "simple-audio-amplifier"; + enable-gpios = <&tlmm 117 GPIO_ACTIVE_HIGH>; + sound-name-prefix = "Speaker Amp"; + pinctrl-0 = <&speaker_amp_default>; + pinctrl-names = "default"; + }; + + /* + * This seems to be actually an analog switch that either routes audio + * to the headphone jack or nowhere. Given that we need to enable a GPIO + * to get sound on headphones, modelling it as simple-audio-amplifier + * works just fine. + */ + headphones_switch: audio-switch { + compatible = "simple-audio-amplifier"; + enable-gpios = <&tlmm 8 GPIO_ACTIVE_HIGH>; + sound-name-prefix = "Headphones Switch"; + pinctrl-0 = <&headphones_switch_default>; + pinctrl-names = "default"; + }; + flash-led-controller { compatible = "ocs,ocp8110"; enable-gpios = <&tlmm 31 GPIO_ACTIVE_HIGH>; @@ -118,6 +142,7 @@ #size-cells = <0>; vcc-supply = <&pm8916_l16>; + vio-supply = <&pm8916_l5>; led@0 { reg = <0>; @@ -146,6 +171,18 @@ status = "okay"; }; +&mpss_mem { + reg = <0x0 0x86800000 0x0 0x5100000>; +}; + +&pm8916_codec { + qcom,micbias1-ext-cap; + qcom,micbias-lvl = <2800>; + qcom,mbhc-vthreshold-low = <75 100 120 180 500>; + qcom,mbhc-vthreshold-high = <75 100 120 180 500>; + qcom,hphl-jack-type-normally-open; +}; + &pm8916_resin { status = "okay"; linux,code = ; @@ -180,6 +217,30 @@ non-removable; }; +&sound { + /* + * Provide widgets/pin-switches to allow enabling speaker and headphones + * separately. Both are routed via the HPH_L/HPH_R pins of the codec. + */ + model = "wt88047"; + widgets = + "Speaker", "Speaker", + "Headphone", "Headphones"; + pin-switches = "Speaker", "Headphones"; + audio-routing = + "Speaker", "Speaker Amp OUTL", + "Speaker", "Speaker Amp OUTR", + "Speaker Amp INL", "HPH_R", + "Speaker Amp INR", "HPH_R", + "Headphones", "Headphones Switch OUTL", + "Headphones", "Headphones Switch OUTR", + "Headphones Switch INL", "HPH_L", + "Headphones Switch INR", "HPH_R", + "AMIC1", "MIC BIAS External1", + "AMIC2", "MIC BIAS Internal2"; + aux-devs = <&speaker_amp>, <&headphones_switch>; +}; + &usb { status = "okay"; extcon = <&usb_id>, <&usb_id>; @@ -226,6 +287,13 @@ bias-pull-up; }; + headphones_switch_default: headphones-switch-default-state { + pins = "gpio8"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + imu_default: imu-default-state { pins = "gpio115"; function = "gpio"; @@ -234,6 +302,13 @@ bias-disable; }; + speaker_amp_default: speaker-amp-default-state { + pins = "gpio117"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + touchscreen_default: touchscreen-default-state { touchscreen-pins { pins = "gpio13"; diff --git a/arch/arm64/boot/dts/qcom/msm8916-yiming-uz801v3.dts b/arch/arm64/boot/dts/qcom/msm8916-yiming-uz801v3.dts index 5e6ba8c58bb577..a98efcfe78b709 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-yiming-uz801v3.dts +++ b/arch/arm64/boot/dts/qcom/msm8916-yiming-uz801v3.dts @@ -13,16 +13,16 @@ gpios = <&tlmm 23 GPIO_ACTIVE_LOW>; }; -&led_r { - gpios = <&tlmm 7 GPIO_ACTIVE_HIGH>; +&led_b { + gpios = <&tlmm 6 GPIO_ACTIVE_HIGH>; }; &led_g { gpios = <&tlmm 8 GPIO_ACTIVE_HIGH>; }; -&led_b { - gpios = <&tlmm 6 GPIO_ACTIVE_HIGH>; +&led_r { + gpios = <&tlmm 7 GPIO_ACTIVE_HIGH>; }; &button_default { diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi index 4f799b536a92ad..e423c57ddd41ec 100644 --- a/arch/arm64/boot/dts/qcom/msm8916.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi @@ -10,6 +10,7 @@ #include #include #include +#include #include / { @@ -539,9 +540,6 @@ compatible = "qcom,msm8916-bimc"; reg = <0x00400000 0x62000>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_BIMC_CLK>, - <&rpmcc RPM_SMD_BIMC_A_CLK>; }; tsens: thermal-sensor@4a9000 { @@ -574,18 +572,12 @@ compatible = "qcom,msm8916-pcnoc"; reg = <0x00500000 0x11000>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_PCNOC_CLK>, - <&rpmcc RPM_SMD_PCNOC_A_CLK>; }; snoc: interconnect@580000 { compatible = "qcom,msm8916-snoc"; reg = <0x00580000 0x14000>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_SNOC_CLK>, - <&rpmcc RPM_SMD_SNOC_A_CLK>; }; stm: stm@802000 { @@ -1989,6 +1981,54 @@ label = "hexagon"; + apr: apr { + compatible = "qcom,apr-v2"; + qcom,smd-channels = "apr_audio_svc"; + qcom,domain = ; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + q6core: service@3 { + compatible = "qcom,q6core"; + reg = ; + }; + + q6afe: service@4 { + compatible = "qcom,q6afe"; + reg = ; + + q6afedai: dais { + compatible = "qcom,q6afe-dais"; + #address-cells = <1>; + #size-cells = <0>; + #sound-dai-cells = <1>; + }; + }; + + q6asm: service@7 { + compatible = "qcom,q6asm"; + reg = ; + + q6asmdai: dais { + compatible = "qcom,q6asm-dais"; + #address-cells = <1>; + #size-cells = <0>; + #sound-dai-cells = <1>; + }; + }; + + q6adm: service@8 { + compatible = "qcom,q6adm"; + reg = ; + + q6routing: routing { + compatible = "qcom,q6adm-routing"; + #sound-dai-cells = <0>; + }; + }; + }; + fastrpc { compatible = "qcom,fastrpc"; qcom,smd-channels = "fastrpcsmd-apps-dsp"; @@ -2106,6 +2146,7 @@ clock-names = "bam_clk"; #dma-cells = <1>; qcom,ee = <0>; + qcom,controlled-remotely; }; blsp_uart1: serial@78af000 { diff --git a/arch/arm64/boot/dts/qcom/msm8939-huawei-kiwi.dts b/arch/arm64/boot/dts/qcom/msm8939-huawei-kiwi.dts new file mode 100644 index 00000000000000..3cec51891aed95 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8939-huawei-kiwi.dts @@ -0,0 +1,242 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/dts-v1/; + +#include "msm8939-pm8916.dtsi" +#include + +/ { + model = "Huawei Honor 5X / GR5 (2016)"; + compatible = "huawei,kiwi", "qcom,msm8939"; + chassis-type = "handset"; + + aliases { + mmc0 = &sdhc_1; /* SDC1 eMMC slot */ + mmc1 = &sdhc_2; /* SDC2 SD card slot */ + serial0 = &blsp_uart2; + }; + + chosen { + stdout-path = "serial0"; + }; + + reserved-memory { + qseecom_mem: qseecom@84a00000 { + reg = <0x0 0x84a00000 0x0 0x1600000>; + no-map; + }; + }; + + gpio-hall-sensor { + compatible = "gpio-keys"; + + pinctrl-0 = <&gpio_hall_sensor_default>; + pinctrl-names = "default"; + + label = "GPIO Hall Effect Sensor"; + + event-hall-sensor { + label = "Hall Effect Sensor"; + gpios = <&tlmm 69 GPIO_ACTIVE_LOW>; + linux,input-type = ; + linux,code = ; + linux,can-disable; + }; + }; + + gpio-keys { + compatible = "gpio-keys"; + + pinctrl-0 = <&gpio_keys_default>; + pinctrl-names = "default"; + + label = "GPIO Buttons"; + + button-volume-up { + label = "Volume Up"; + gpios = <&tlmm 107 GPIO_ACTIVE_LOW>; + linux,code = ; + }; + }; + + usb_id: usb-id { + compatible = "linux,extcon-usb-gpio"; + id-gpios = <&tlmm 110 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&usb_id_default>; + pinctrl-names = "default"; + }; +}; + +&blsp_i2c2 { + status = "okay"; + + accelerometer@1e { + compatible = "kionix,kx023-1025"; + reg = <0x1e>; + + vdd-supply = <&pm8916_l17>; + vddio-supply = <&pm8916_l6>; + pinctrl-0 = <&accel_int_default>; + pinctrl-names = "default"; + mount-matrix = "-1", "0", "0", + "0", "1", "0", + "0", "0", "1"; + }; + + proximity@39 { + compatible = "avago,apds9930"; + reg = <0x39>; + + interrupt-parent = <&tlmm>; + interrupts = <113 IRQ_TYPE_EDGE_FALLING>; + + vdd-supply = <&pm8916_l17>; + vddio-supply = <&pm8916_l6>; + + led-max-microamp = <25000>; + amstaos,proximity-diodes = <0>; + + pinctrl-0 = <&prox_irq_default>; + pinctrl-names = "default"; + }; +}; + +&blsp_i2c5 { + status = "okay"; + + touchscreen@1c { + compatible = "cypress,tt21000"; + + reg = <0x1c>; + interrupt-parent = <&tlmm>; + interrupts = <13 IRQ_TYPE_EDGE_FALLING>; + + reset-gpios = <&tlmm 12 GPIO_ACTIVE_LOW>; + + /* + * NOTE: vdd is not directly supplied by pm8916_l16, it seems to be a + * fixed regulator that is automatically enabled by pm8916_l16. + */ + vdd-supply = <&pm8916_l16>; + vddio-supply = <&pm8916_l16>; + + pinctrl-0 = <&touchscreen_default>; + pinctrl-names = "default"; + }; +}; + +&blsp_uart2 { + status = "okay"; +}; + +&pm8916_l8 { + regulator-min-microvolt = <2950000>; + regulator-max-microvolt = <2950000>; +}; + +&pm8916_resin { + linux,code = ; + status = "okay"; +}; + +&pm8916_rpm_regulators { + pm8916_l16: l16 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + pm8916_l17: l17 { + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + }; +}; + +&pm8916_vib { + status = "okay"; +}; + +&sdhc_1 { + status = "okay"; +}; + +&sdhc_2 { + pinctrl-0 = <&sdc2_default &sdc2_cd_default>; + pinctrl-1 = <&sdc2_sleep &sdc2_cd_default>; + pinctrl-names = "default", "sleep"; + + cd-gpios = <&tlmm 38 GPIO_ACTIVE_HIGH>; + + status = "okay"; +}; + +&usb { + extcon = <&usb_id>, <&usb_id>; + status = "okay"; +}; + +&usb_hs_phy { + extcon = <&usb_id>; +}; + +&wcnss { + status = "okay"; +}; + +&wcnss_iris { + compatible = "qcom,wcn3620"; +}; + +&wcnss_mem { + status = "okay"; +}; + +&tlmm { + accel_int_default: accel-int-default-state { + pins = "gpio115"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + gpio_hall_sensor_default: gpio-hall-sensor-default-state { + pins = "gpio69"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + gpio_keys_default: gpio-keys-default-state { + pins = "gpio107"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + + prox_irq_default: prox-irq-default-state { + pins = "gpio113"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + sdc2_cd_default: sdc2-cd-default-state { + pins = "gpio38"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + touchscreen_default: touchscreen-default-state { + pins = "gpio12", "gpio13"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + usb_id_default: usb-id-default-state { + pins = "gpio110"; + function = "gpio"; + drive-strength = <8>; + bias-pull-up; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8939-longcheer-l9100.dts b/arch/arm64/boot/dts/qcom/msm8939-longcheer-l9100.dts index 6802714fda3f57..e3404c4455cf8d 100644 --- a/arch/arm64/boot/dts/qcom/msm8939-longcheer-l9100.dts +++ b/arch/arm64/boot/dts/qcom/msm8939-longcheer-l9100.dts @@ -8,6 +8,7 @@ #include #include #include +#include #include / { @@ -120,6 +121,46 @@ }; +&blsp_i2c2 { + status = "okay"; + + led-controller@30 { + compatible = "kinetic,ktd2026"; + reg = <0x30>; + #address-cells = <1>; + #size-cells = <0>; + + vin-supply = <&pm8916_l17>; + vio-supply = <&pm8916_l6>; + + pinctrl-0 = <&status_led_default>; + pinctrl-names = "default"; + + multi-led { + color = ; + function = LED_FUNCTION_STATUS; + + #address-cells = <1>; + #size-cells = <0>; + + led@0 { + reg = <0>; + color = ; + }; + + led@1 { + reg = <1>; + color = ; + }; + + led@2 { + reg = <2>; + color = ; + }; + }; + }; +}; + &blsp_i2c3 { status = "okay"; @@ -139,6 +180,7 @@ light-sensor@23 { compatible = "liteon,ltr559"; reg = <0x23>; + proximity-near-level = <75>; vdd-supply = <&pm8916_l17>; vddio-supply = <&pm8916_l5>; @@ -184,6 +226,16 @@ status = "okay"; }; +&pm8916_gpios { + status_led_default: status-led-default-state { + pins = "gpio3"; + function = PMIC_GPIO_FUNC_NORMAL; + power-source = ; + bias-disable; + output-high; + }; +}; + &pm8916_mpps { pwm_out: mpp4-state { pins = "mpp4"; @@ -247,6 +299,10 @@ compatible = "qcom,wcn3620"; }; +&wcnss_mem { + status = "okay"; +}; + &tlmm { button_backlight_default: button-backlight-default-state { pins = "gpio17"; diff --git a/arch/arm64/boot/dts/qcom/msm8939-samsung-a7.dts b/arch/arm64/boot/dts/qcom/msm8939-samsung-a7.dts index fccd8fec8b8f7c..aa6c39482a2f13 100644 --- a/arch/arm64/boot/dts/qcom/msm8939-samsung-a7.dts +++ b/arch/arm64/boot/dts/qcom/msm8939-samsung-a7.dts @@ -3,10 +3,12 @@ /dts-v1/; #include "msm8939-pm8916.dtsi" +#include "msm8916-modem-qdsp6.dtsi" #include #include #include +#include / { model = "Samsung Galaxy A7 (2015)"; @@ -287,6 +289,18 @@ }; }; +&blsp_i2c2 { + status = "okay"; + + speaker_codec: audio-codec@34 { + compatible = "nxp,tfa9895"; + reg = <0x34>; + vddd-supply = <&pm8916_l5>; + sound-name-prefix = "Speaker"; + #sound-dai-cells = <0>; + }; +}; + &blsp_i2c5 { status = "okay"; @@ -309,6 +323,29 @@ status = "okay"; }; +/* + * For some reason the speaker amplifier is connected to the second SD line + * (MI2S_2_D1) instead of the first (MI2S_2_D0). This must be configured in the + * device tree, otherwise audio will seemingly play fine on the wrong SD line + * but the speaker stays silent. + * + * When routing audio via QDSP6 (the default) the &lpass node is reserved and + * the definitions from &q6afedai are used. When the modem is disabled audio can + * be alternatively routed directly to the LPASS hardware with reduced latency. + * The definitions for &lpass are here for completeness to simplify changing the + * setup with minor changes to the DT (either manually or with DT overlays). + */ +&lpass { + dai-link@3 { + reg = ; + qcom,playback-sd-lines = <1>; + }; +}; + +&mpss_mem { + reg = <0x0 0x86800000 0x0 0x5800000>; +}; + &pm8916_resin { linux,code = ; status = "okay"; @@ -321,6 +358,13 @@ }; }; +&q6afedai { + dai@22 { + reg = ; + qcom,sd-lines = <1>; + }; +}; + &sdhc_1 { status = "okay"; }; @@ -335,6 +379,32 @@ status = "okay"; }; +&sound { + model = "samsung-a2015"; + audio-routing = + "AMIC1", "MIC BIAS External1", + "AMIC2", "MIC BIAS Internal2", + "AMIC3", "MIC BIAS External1"; + + pinctrl-0 = <&cdc_pdm_default &sec_mi2s_default>; + pinctrl-1 = <&cdc_pdm_sleep &sec_mi2s_sleep>; + pinctrl-names = "default", "sleep"; + + sound_link_backend2: backend2-dai-link { + link-name = "Quaternary MI2S"; + + cpu { + sound-dai = <&q6afedai QUATERNARY_MI2S_RX>; + }; + platform { + sound-dai = <&q6routing>; + }; + codec { + sound-dai = <&speaker_codec>; + }; + }; +}; + &usb { extcon = <&muic>, <&muic>; status = "okay"; diff --git a/arch/arm64/boot/dts/qcom/msm8939.dtsi b/arch/arm64/boot/dts/qcom/msm8939.dtsi index 324b5d26db4005..82d85ff61045d3 100644 --- a/arch/arm64/boot/dts/qcom/msm8939.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8939.dtsi @@ -10,6 +10,7 @@ #include #include #include +#include #include / { @@ -601,9 +602,6 @@ bimc: interconnect@400000 { compatible = "qcom,msm8939-bimc"; reg = <0x00400000 0x62000>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_BIMC_CLK>, - <&rpmcc RPM_SMD_BIMC_A_CLK>; #interconnect-cells = <1>; }; @@ -647,25 +645,16 @@ pcnoc: interconnect@500000 { compatible = "qcom,msm8939-pcnoc"; reg = <0x00500000 0x11000>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_PCNOC_CLK>, - <&rpmcc RPM_SMD_PCNOC_A_CLK>; #interconnect-cells = <1>; }; snoc: interconnect@580000 { compatible = "qcom,msm8939-snoc"; reg = <0x00580000 0x14080>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_SNOC_CLK>, - <&rpmcc RPM_SMD_SNOC_A_CLK>; #interconnect-cells = <1>; snoc_mm: interconnect-snoc { compatible = "qcom,msm8939-snoc-mm"; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_SYSMMNOC_CLK>, - <&rpmcc RPM_SMD_SYSMMNOC_A_CLK>; #interconnect-cells = <1>; }; }; @@ -1537,6 +1526,20 @@ #interrupt-cells = <4>; }; + bam_dmux_dma: dma-controller@4044000 { + compatible = "qcom,bam-v1.7.0"; + reg = <0x04044000 0x19000>; + interrupts = ; + #dma-cells = <1>; + qcom,ee = <0>; + + num-channels = <6>; + qcom,num-ees = <1>; + qcom,powered-remotely; + + status = "disabled"; + }; + mpss: remoteproc@4080000 { compatible = "qcom,msm8916-mss-pil"; reg = <0x04080000 0x100>, <0x04020000 0x040>; @@ -1569,6 +1572,22 @@ qcom,halt-regs = <&tcsr 0x18000 0x19000 0x1a000>; status = "disabled"; + bam_dmux: bam-dmux { + compatible = "qcom,bam-dmux"; + + interrupt-parent = <&hexagon_smsm>; + interrupts = <1 IRQ_TYPE_EDGE_BOTH>, <11 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "pc", "pc-ack"; + + qcom,smem-states = <&apps_smsm 1>, <&apps_smsm 11>; + qcom,smem-state-names = "pc", "pc-ack"; + + dmas = <&bam_dmux_dma 4>, <&bam_dmux_dma 5>; + dma-names = "tx", "rx"; + + status = "disabled"; + }; + mba { memory-region = <&mba_mem>; }; @@ -1585,6 +1604,54 @@ qcom,remote-pid = <1>; label = "hexagon"; + + apr: apr { + compatible = "qcom,apr-v2"; + qcom,smd-channels = "apr_audio_svc"; + qcom,domain = ; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + q6core: service@3 { + compatible = "qcom,q6core"; + reg = ; + }; + + q6afe: service@4 { + compatible = "qcom,q6afe"; + reg = ; + + q6afedai: dais { + compatible = "qcom,q6afe-dais"; + #address-cells = <1>; + #size-cells = <0>; + #sound-dai-cells = <1>; + }; + }; + + q6asm: service@7 { + compatible = "qcom,q6asm"; + reg = ; + + q6asmdai: dais { + compatible = "qcom,q6asm-dais"; + #address-cells = <1>; + #size-cells = <0>; + #sound-dai-cells = <1>; + }; + }; + + q6adm: service@8 { + compatible = "qcom,q6adm"; + reg = ; + + q6routing: routing { + compatible = "qcom,q6adm-routing"; + #sound-dai-cells = <0>; + }; + }; + }; }; }; @@ -1682,6 +1749,7 @@ clock-names = "bam_clk"; #dma-cells = <1>; qcom,ee = <0>; + qcom,controlled-remotely; }; blsp_uart1: serial@78af000 { @@ -2116,6 +2184,8 @@ #address-cells = <1>; #size-cells = <1>; ranges; + /* Necessary because firmware does not configure this correctly */ + clock-frequency = <19200000>; frame@b121000 { reg = <0x0b121000 0x1000>, diff --git a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-mido.dts b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-mido.dts index ed95d09cedb1e3..6b9245cd8b0c3f 100644 --- a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-mido.dts +++ b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-mido.dts @@ -111,6 +111,7 @@ reg = <0x45>; vcc-supply = <&pm8953_l10>; + vio-supply = <&pm8953_l5>; #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-tissot.dts b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-tissot.dts index 61ff629c9bf345..9ac4f507e321a6 100644 --- a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-tissot.dts +++ b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-tissot.dts @@ -104,6 +104,7 @@ reg = <0x45>; vcc-supply = <&pm8953_l10>; + vio-supply = <&pm8953_l5>; #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts index 1a1d3f92a51168..b0588f30f8f1a7 100644 --- a/arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts +++ b/arch/arm64/boot/dts/qcom/msm8953-xiaomi-vince.dts @@ -113,6 +113,7 @@ reg = <0x45>; vcc-supply = <&pm8953_l10>; + vio-supply = <&pm8953_l5>; #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi index e7de7632669a29..ad2f8cf9c966c5 100644 --- a/arch/arm64/boot/dts/qcom/msm8953.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi @@ -174,10 +174,10 @@ }; }; - memory { + memory@10000000 { device_type = "memory"; /* We expect the bootloader to fill in the reg */ - reg = <0 0 0 0>; + reg = <0 0x10000000 0 0>; }; pmu { @@ -726,6 +726,48 @@ bias-disable; }; + spi_3_default: spi-3-default-state { + pins = "gpio10", "gpio11"; + function = "blsp_spi3"; + drive-strength = <2>; + bias-disable; + }; + + spi_3_sleep: spi-3-sleep-state { + pins = "gpio10", "gpio11"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + spi_5_default: spi-5-default-state { + pins = "gpio18", "gpio19"; + function = "blsp_spi5"; + drive-strength = <2>; + bias-disable; + }; + + spi_5_sleep: spi-5-sleep-state { + pins = "gpio18", "gpio19"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + + spi_6_default: spi-6-default-state { + pins = "gpio22", "gpio23"; + function = "blsp_spi6"; + drive-strength = <2>; + bias-disable; + }; + + spi_6_sleep: spi-6-sleep-state { + pins = "gpio22", "gpio23"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + wcnss_pin_a: wcnss-active-state { wcss-wlan2-pins { @@ -1004,7 +1046,7 @@ apps_iommu: iommu@1e20000 { compatible = "qcom,msm8953-iommu", "qcom,msm-iommu-v1"; - ranges = <0 0x01e20000 0x20000>; + ranges = <0 0x01e20000 0x20000>; clocks = <&gcc GCC_SMMU_CFG_CLK>, <&gcc GCC_APSS_TCU_ASYNC_CLK>; @@ -1360,6 +1402,26 @@ status = "disabled"; }; + spi_3: spi@78b7000 { + compatible = "qcom,spi-qup-v2.2.1"; + reg = <0x078b7000 0x600>; + interrupts = ; + clock-names = "core", "iface"; + clocks = <&gcc GCC_BLSP1_QUP3_I2C_APPS_CLK>, + <&gcc GCC_BLSP1_AHB_CLK>; + dmas = <&blsp1_dma 8>, <&blsp1_dma 9>; + dma-names = "tx", "rx"; + + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&spi_3_default>; + pinctrl-1 = <&spi_3_sleep>; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + i2c_4: i2c@78b8000 { compatible = "qcom,i2c-qup-v2.2.1"; reg = <0x078b8000 0x600>; @@ -1413,6 +1475,26 @@ status = "disabled"; }; + spi_5: spi@7af5000 { + compatible = "qcom,spi-qup-v2.2.1"; + reg = <0x07af5000 0x600>; + interrupts = ; + clock-names = "core", "iface"; + clocks = <&gcc GCC_BLSP2_QUP1_I2C_APPS_CLK>, + <&gcc GCC_BLSP2_AHB_CLK>; + dmas = <&blsp2_dma 4>, <&blsp2_dma 5>; + dma-names = "tx", "rx"; + + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&spi_5_default>; + pinctrl-1 = <&spi_5_sleep>; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + i2c_6: i2c@7af6000 { compatible = "qcom,i2c-qup-v2.2.1"; reg = <0x07af6000 0x600>; @@ -1433,6 +1515,26 @@ status = "disabled"; }; + spi_6: spi@7af6000 { + compatible = "qcom,spi-qup-v2.2.1"; + reg = <0x07af6000 0x600>; + interrupts = ; + clock-names = "core", "iface"; + clocks = <&gcc GCC_BLSP2_QUP2_I2C_APPS_CLK>, + <&gcc GCC_BLSP2_AHB_CLK>; + dmas = <&blsp2_dma 6>, <&blsp2_dma 7>; + dma-names = "tx", "rx"; + + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&spi_6_default>; + pinctrl-1 = <&spi_6_sleep>; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + i2c_7: i2c@7af7000 { compatible = "qcom,i2c-qup-v2.2.1"; reg = <0x07af7000 0x600>; @@ -1645,7 +1747,7 @@ apr { compatible = "qcom,apr-v2"; qcom,smd-channels = "apr_audio_svc"; - qcom,apr-domain = ; + qcom,domain = ; #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi index 6ba9da9e6a8b99..8d41ed261adfbf 100644 --- a/arch/arm64/boot/dts/qcom/msm8996.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi @@ -444,6 +444,38 @@ reg = <0x0 0x80000000 0x0 0x0>; }; + etm { + compatible = "qcom,coresight-remote-etm"; + + out-ports { + port { + modem_etm_out_funnel_in2: endpoint { + remote-endpoint = + <&funnel_in2_in_modem_etm>; + }; + }; + }; + }; + + mpm: interrupt-controller { + compatible = "qcom,mpm"; + qcom,rpm-msg-ram = <&apss_mpm>; + interrupts = ; + mboxes = <&apcs_glb 1>; + interrupt-controller; + #interrupt-cells = <2>; + #power-domain-cells = <0>; + interrupt-parent = <&intc>; + qcom,mpm-pin-count = <96>; + qcom,mpm-pin-map = <2 184>, /* TSENS1 upper_lower_int */ + <52 243>, /* DWC3_PRI ss_phy_irq */ + <79 347>, /* DWC3_PRI hs_phy_irq */ + <80 352>, /* DWC3_SEC hs_phy_irq */ + <81 347>, /* QUSB2_PHY_PRI DP+DM */ + <82 352>, /* QUSB2_PHY_SEC DP+DM */ + <87 326>; /* SPMI */ + }; + psci { compatible = "arm,psci-1.0"; method = "smc"; @@ -733,8 +765,15 @@ }; rpm_msg_ram: sram@68000 { - compatible = "qcom,rpm-msg-ram"; + compatible = "qcom,rpm-msg-ram", "mmio-sram"; reg = <0x00068000 0x6000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x00068000 0x7000>; + + apss_mpm: sram@1b8 { + reg = <0x1b8 0x48>; + }; }; qfprom@74000 { @@ -779,10 +818,10 @@ <&pciephy_0>, <&pciephy_1>, <&pciephy_2>, - <&ssusb_phy_0>, - <&ufsphy_lane 0>, - <&ufsphy_lane 1>, - <&ufsphy_lane 2>; + <&usb3phy>, + <&ufsphy 0>, + <&ufsphy 1>, + <&ufsphy 2>; clock-names = "cxo", "cxo2", "sleep_clk", @@ -799,9 +838,6 @@ compatible = "qcom,msm8996-bimc"; reg = <0x00408000 0x5a000>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_BIMC_CLK>, - <&rpmcc RPM_SMD_BIMC_A_CLK>; }; tsens0: thermal-sensor@4a9000 { @@ -820,8 +856,8 @@ reg = <0x004ad000 0x1000>, /* TM */ <0x004ac000 0x1000>; /* SROT */ #qcom,sensors = <8>; - interrupts = , - ; + interrupts-extended = <&mpm 2 IRQ_TYPE_LEVEL_HIGH>, + <&intc GIC_SPI 430 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "uplow", "critical"; #thermal-sensor-cells = <1>; }; @@ -852,18 +888,12 @@ compatible = "qcom,msm8996-cnoc"; reg = <0x00500000 0x1000>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_CNOC_CLK>, - <&rpmcc RPM_SMD_CNOC_A_CLK>; }; snoc: interconnect@524000 { compatible = "qcom,msm8996-snoc"; reg = <0x00524000 0x1c000>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_SNOC_CLK>, - <&rpmcc RPM_SMD_SNOC_A_CLK>; }; a0noc: interconnect@543000 { @@ -883,19 +913,14 @@ compatible = "qcom,msm8996-a1noc"; reg = <0x00562000 0x5000>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_AGGR1_NOC_CLK>, - <&rpmcc RPM_SMD_AGGR1_NOC_A_CLK>; }; a2noc: interconnect@583000 { compatible = "qcom,msm8996-a2noc"; reg = <0x00583000 0x7000>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a", "aggre2_ufs_axi", "ufs_axi"; - clocks = <&rpmcc RPM_SMD_AGGR2_NOC_CLK>, - <&rpmcc RPM_SMD_AGGR2_NOC_A_CLK>, - <&gcc GCC_AGGRE2_UFS_AXI_CLK>, + clock-names = "aggre2_ufs_axi", "ufs_axi"; + clocks = <&gcc GCC_AGGRE2_UFS_AXI_CLK>, <&gcc GCC_UFS_AXI_CLK>; }; @@ -903,19 +928,14 @@ compatible = "qcom,msm8996-mnoc"; reg = <0x005a4000 0x1c000>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a", "iface"; - clocks = <&rpmcc RPM_SMD_MMAXI_CLK>, - <&rpmcc RPM_SMD_MMAXI_A_CLK>, - <&mmcc AHB_CLK_SRC>; + clock-names = "iface"; + clocks = <&mmcc AHB_CLK_SRC>; }; pnoc: interconnect@5c0000 { compatible = "qcom,msm8996-pnoc"; reg = <0x005c0000 0x3000>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_PCNOC_CLK>, - <&rpmcc RPM_SMD_PCNOC_A_CLK>; }; tcsr_mutex: hwlock@740000 { @@ -1343,6 +1363,7 @@ interrupts = ; gpio-controller; gpio-ranges = <&tlmm 0 0 150>; + wakeup-parent = <&mpm>; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; @@ -1870,7 +1891,7 @@ <0x0400a000 0x002100>; reg-names = "core", "chnls", "obsrvr", "intr", "cnfg"; interrupt-names = "periph_irq"; - interrupts = ; + interrupts-extended = <&mpm 87 IRQ_TYPE_LEVEL_HIGH>; qcom,ee = <0>; qcom,channel = <0>; #address-cells = <2>; @@ -2047,7 +2068,7 @@ reg = <0x00624000 0x2500>; interrupts = ; - phys = <&ufsphy_lane>; + phys = <&ufsphy>; phy-names = "ufsphy"; power-domains = <&gcc UFS_GDSC>; @@ -2100,25 +2121,18 @@ ufsphy: phy@627000 { compatible = "qcom,msm8996-qmp-ufs-phy"; - reg = <0x00627000 0x1c4>; - #address-cells = <1>; - #size-cells = <1>; - ranges; + reg = <0x00627000 0x1000>; clocks = <&gcc GCC_UFS_CLKREF_CLK>; clock-names = "ref"; resets = <&ufshc 0>; reset-names = "ufsphy"; - status = "disabled"; - ufsphy_lane: phy@627400 { - reg = <0x627400 0x12c>, - <0x627600 0x200>, - <0x627c00 0x1b4>; - #clock-cells = <1>; - #phy-cells = <0>; - }; + #clock-cells = <1>; + #phy-cells = <0>; + + status = "disabled"; }; camss: camss@a34000 { @@ -2453,9 +2467,8 @@ "handover", "stop-ack"; - clocks = <&xo_board>, - <&rpmcc RPM_SMD_AGGR2_NOC_CLK>; - clock-names = "xo", "aggre2"; + clocks = <&xo_board>; + clock-names = "xo"; memory-region = <&slpi_mem>; @@ -2500,10 +2513,15 @@ <&gcc GCC_MSS_GPLL0_DIV_CLK>, <&gcc GCC_MSS_SNOC_AXI_CLK>, <&gcc GCC_MSS_MNOC_BIMC_AXI_CLK>, - <&rpmcc RPM_SMD_PCNOC_CLK>, <&rpmcc RPM_SMD_QDSS_CLK>; - clock-names = "iface", "bus", "mem", "xo", "gpll0_mss", - "snoc_axi", "mnoc_axi", "pnoc", "qdss"; + clock-names = "iface", + "bus", + "mem", + "xo", + "gpll0_mss", + "snoc_axi", + "mnoc_axi", + "qdss"; resets = <&gcc GCC_MSS_RESTART>; reset-names = "mss_restart"; @@ -2644,6 +2662,14 @@ clocks = <&rpmcc RPM_QDSS_CLK>, <&rpmcc RPM_QDSS_A_CLK>; clock-names = "apb_pclk", "atclk"; + in-ports { + port { + funnel_in2_in_modem_etm: endpoint { + remote-endpoint = + <&modem_etm_out_funnel_in2>; + }; + }; + }; out-ports { port { @@ -3026,8 +3052,8 @@ #size-cells = <1>; ranges; - interrupts = , - ; + interrupts-extended = <&mpm 79 IRQ_TYPE_LEVEL_HIGH>, + <&mpm 52 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "hs_phy_irq", "ss_phy_irq"; clocks = <&gcc GCC_SYS_NOC_USB3_AXI_CLK>, @@ -3056,7 +3082,7 @@ compatible = "snps,dwc3"; reg = <0x06a00000 0xcc00>; interrupts = ; - phys = <&hsusb_phy1>, <&ssusb_phy_0>; + phys = <&hsusb_phy1>, <&usb3phy>; phy-names = "usb2-phy", "usb3-phy"; snps,hird-threshold = /bits/ 8 <0>; snps,dis_u2_susphy_quirk; @@ -3068,32 +3094,26 @@ usb3phy: phy@7410000 { compatible = "qcom,msm8996-qmp-usb3-phy"; - reg = <0x07410000 0x1c4>; - #address-cells = <1>; - #size-cells = <1>; - ranges; + reg = <0x07410000 0x1000>; clocks = <&gcc GCC_USB3_PHY_AUX_CLK>, - <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, - <&gcc GCC_USB3_CLKREF_CLK>; - clock-names = "aux", "cfg_ahb", "ref"; + <&gcc GCC_USB3_CLKREF_CLK>, + <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, + <&gcc GCC_USB3_PHY_PIPE_CLK>; + clock-names = "aux", + "ref", + "cfg_ahb", + "pipe"; + clock-output-names = "usb3_phy_pipe_clk_src"; + #clock-cells = <0>; + #phy-cells = <0>; resets = <&gcc GCC_USB3_PHY_BCR>, - <&gcc GCC_USB3PHY_PHY_BCR>; - reset-names = "phy", "common"; - status = "disabled"; + <&gcc GCC_USB3PHY_PHY_BCR>; + reset-names = "phy", + "phy_phy"; - ssusb_phy_0: phy@7410200 { - reg = <0x07410200 0x200>, - <0x07410400 0x130>, - <0x07410600 0x1a8>; - #phy-cells = <0>; - - #clock-cells = <0>; - clock-output-names = "usb3_phy_pipe_clk_src"; - clocks = <&gcc GCC_USB3_PHY_PIPE_CLK>; - clock-names = "pipe0"; - }; + status = "disabled"; }; hsusb_phy1: phy@7411000 { diff --git a/arch/arm64/boot/dts/qcom/msm8998.dtsi b/arch/arm64/boot/dts/qcom/msm8998.dtsi index b485bf925ce613..2793cc22d381af 100644 --- a/arch/arm64/boot/dts/qcom/msm8998.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8998.dtsi @@ -933,7 +933,7 @@ ; }; - pcie0: pci@1c00000 { + pcie0: pcie@1c00000 { compatible = "qcom,pcie-msm8998", "qcom,pcie-msm8996"; reg = <0x01c00000 0x2000>, <0x1b000000 0xf1d>, @@ -1004,7 +1004,7 @@ compatible = "qcom,msm8998-ufshc", "qcom,ufshc", "jedec,ufs-2.0"; reg = <0x01da4000 0x2500>; interrupts = ; - phys = <&ufsphy_lanes>; + phys = <&ufsphy>; phy-names = "ufsphy"; lanes-per-direction = <2>; power-domains = <&gcc UFS_GDSC>; @@ -1045,11 +1045,7 @@ ufsphy: phy@1da7000 { compatible = "qcom,msm8998-qmp-ufs-phy"; - reg = <0x01da7000 0x18c>; - #address-cells = <1>; - #size-cells = <1>; - status = "disabled"; - ranges; + reg = <0x01da7000 0x1000>; clock-names = "ref", @@ -1061,14 +1057,8 @@ reset-names = "ufsphy"; resets = <&ufshc 0>; - ufsphy_lanes: phy@1da7400 { - reg = <0x01da7400 0x128>, - <0x01da7600 0x1fc>, - <0x01da7c00 0x1dc>, - <0x01da7800 0x128>, - <0x01da7a00 0x1fc>; - #phy-cells = <0>; - }; + #phy-cells = <0>; + status = "disabled"; }; tcsr_mutex: hwlock@1f40000 { @@ -1615,9 +1605,8 @@ px-supply = <&vreg_lvs2a_1p8>; - clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>, - <&rpmcc RPM_SMD_AGGR2_NOC_CLK>; - clock-names = "xo", "aggre2"; + clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>; + clock-names = "xo"; memory-region = <&slpi_mem>; @@ -2031,9 +2020,11 @@ cpu = <&CPU4>; - port { - etm4_out: endpoint { - remote-endpoint = <&apss_funnel_in4>; + out-ports { + port { + etm4_out: endpoint { + remote-endpoint = <&apss_funnel_in4>; + }; }; }; }; @@ -2048,9 +2039,11 @@ cpu = <&CPU5>; - port { - etm5_out: endpoint { - remote-endpoint = <&apss_funnel_in5>; + out-ports { + port { + etm5_out: endpoint { + remote-endpoint = <&apss_funnel_in5>; + }; }; }; }; @@ -2065,9 +2058,11 @@ cpu = <&CPU6>; - port { - etm6_out: endpoint { - remote-endpoint = <&apss_funnel_in6>; + out-ports { + port { + etm6_out: endpoint { + remote-endpoint = <&apss_funnel_in6>; + }; }; }; }; @@ -2082,9 +2077,11 @@ cpu = <&CPU7>; - port { - etm7_out: endpoint { - remote-endpoint = <&apss_funnel_in7>; + out-ports { + port { + etm7_out: endpoint { + remote-endpoint = <&apss_funnel_in7>; + }; }; }; }; @@ -2149,7 +2146,7 @@ interrupts = ; snps,dis_u2_susphy_quirk; snps,dis_enblslpm_quirk; - phys = <&qusb2phy>, <&usb1_ssphy>; + phys = <&qusb2phy>, <&usb3phy>; phy-names = "usb2-phy", "usb3-phy"; snps,has-lpm-erratum; snps,hird-threshold = /bits/ 8 <0x10>; @@ -2158,33 +2155,26 @@ usb3phy: phy@c010000 { compatible = "qcom,msm8998-qmp-usb3-phy"; - reg = <0x0c010000 0x18c>; - status = "disabled"; - #address-cells = <1>; - #size-cells = <1>; - ranges; + reg = <0x0c010000 0x1000>; clocks = <&gcc GCC_USB3_PHY_AUX_CLK>, + <&gcc GCC_USB3_CLKREF_CLK>, <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, - <&gcc GCC_USB3_CLKREF_CLK>; - clock-names = "aux", "cfg_ahb", "ref"; + <&gcc GCC_USB3_PHY_PIPE_CLK>; + clock-names = "aux", + "ref", + "cfg_ahb", + "pipe"; + clock-output-names = "usb3_phy_pipe_clk_src"; + #clock-cells = <0>; + #phy-cells = <0>; resets = <&gcc GCC_USB3_PHY_BCR>, <&gcc GCC_USB3PHY_PHY_BCR>; - reset-names = "phy", "common"; + reset-names = "phy", + "phy_phy"; - usb1_ssphy: phy@c010200 { - reg = <0xc010200 0x128>, - <0xc010400 0x200>, - <0xc010c00 0x20c>, - <0xc010600 0x128>, - <0xc010800 0x200>; - #phy-cells = <0>; - #clock-cells = <0>; - clocks = <&gcc GCC_USB3_PHY_PIPE_CLK>; - clock-names = "pipe0"; - clock-output-names = "usb3_phy_pipe_clk_src"; - }; + status = "disabled"; }; qusb2phy: phy@c012000 { diff --git a/arch/arm64/boot/dts/qcom/pm7250b.dtsi b/arch/arm64/boot/dts/qcom/pm7250b.dtsi index df0afe82f250e5..3bf7cf5d170082 100644 --- a/arch/arm64/boot/dts/qcom/pm7250b.dtsi +++ b/arch/arm64/boot/dts/qcom/pm7250b.dtsi @@ -148,7 +148,7 @@ status = "disabled"; }; - pm7250b_gpios: pinctrl@c000 { + pm7250b_gpios: gpio@c000 { compatible = "qcom,pm7250b-gpio", "qcom,spmi-gpio"; reg = <0xc000>; gpio-controller; diff --git a/arch/arm64/boot/dts/qcom/pm8550.dtsi b/arch/arm64/boot/dts/qcom/pm8550.dtsi index db3d5c17a77dfb..797a18c249a4a4 100644 --- a/arch/arm64/boot/dts/qcom/pm8550.dtsi +++ b/arch/arm64/boot/dts/qcom/pm8550.dtsi @@ -64,9 +64,6 @@ pm8550_pwm: pwm { compatible = "qcom,pm8550-pwm", "qcom,pm8350c-pwm"; - - #address-cells = <1>; - #size-cells = <0>; #pwm-cells = <2>; status = "disabled"; diff --git a/arch/arm64/boot/dts/qcom/pm8550ve.dtsi b/arch/arm64/boot/dts/qcom/pm8550ve.dtsi index c47646a467bed3..4dc1f03ab2c746 100644 --- a/arch/arm64/boot/dts/qcom/pm8550ve.dtsi +++ b/arch/arm64/boot/dts/qcom/pm8550ve.dtsi @@ -33,16 +33,16 @@ &spmi_bus { - pm8550ve: pmic@5 { + pm8550ve: pmic@PMK8550VE_SID { compatible = "qcom,pm8550", "qcom,spmi-pmic"; - reg = <0x5 SPMI_USID>; + reg = ; #address-cells = <1>; #size-cells = <0>; pm8550ve_temp_alarm: temp-alarm@a00 { compatible = "qcom,spmi-temp-alarm"; reg = <0xa00>; - interrupts = <0x5 0xa 0x0 IRQ_TYPE_EDGE_BOTH>; + interrupts = ; #thermal-sensor-cells = <0>; }; diff --git a/arch/arm64/boot/dts/qcom/pm8916.dtsi b/arch/arm64/boot/dts/qcom/pm8916.dtsi index f4de86787743b0..4b2e8fb47d2da1 100644 --- a/arch/arm64/boot/dts/qcom/pm8916.dtsi +++ b/arch/arm64/boot/dts/qcom/pm8916.dtsi @@ -41,6 +41,35 @@ }; }; + pm8916_charger: charger@1000 { + compatible = "qcom,pm8916-lbc"; + reg = <0x1000>, <0x1200>, <0x1300>, <0x1600>; + reg-names = "chgr", "bat_if", "usb", "misc"; + + interrupts = <0x0 0x10 0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x10 5 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x10 6 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x10 7 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x12 0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x12 1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 0 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 2 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x13 4 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "vbat_det", + "fast_chg", + "chg_fail", + "chg_done", + "bat_pres", + "temp_ok", + "coarse_det", + "usb_vbus", + "chg_gone", + "overtemp"; + + status = "disabled"; + }; + pm8916_usbin: usb-detect@1300 { compatible = "qcom,pm8941-misc"; reg = <0x1300>; @@ -91,6 +120,25 @@ }; }; + pm8916_bms: battery@4000 { + compatible = "qcom,pm8916-bms-vm"; + reg = <0x4000>; + interrupts = <0x0 0x40 0 IRQ_TYPE_EDGE_RISING>, + <0x0 0x40 1 IRQ_TYPE_EDGE_RISING>, + <0x0 0x40 2 IRQ_TYPE_EDGE_RISING>, + <0x0 0x40 3 IRQ_TYPE_EDGE_RISING>, + <0x0 0x40 4 IRQ_TYPE_EDGE_RISING>, + <0x0 0x40 5 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "cv_leave", + "cv_enter", + "ocv_good", + "ocv_thr", + "fifo", + "state_chg"; + + status = "disabled"; + }; + rtc@6000 { compatible = "qcom,pm8941-rtc"; reg = <0x6000>, <0x6100>; diff --git a/arch/arm64/boot/dts/qcom/pmk8350.dtsi b/arch/arm64/boot/dts/qcom/pmk8350.dtsi index 1eb74017062d63..f0ed15458dd7bb 100644 --- a/arch/arm64/boot/dts/qcom/pmk8350.dtsi +++ b/arch/arm64/boot/dts/qcom/pmk8350.dtsi @@ -22,7 +22,7 @@ mode-bootloader = <0x02>; }; }; - + &spmi_bus { pmk8350: pmic@PMK8350_SID { compatible = "qcom,pmk8350", "qcom,spmi-pmic"; diff --git a/arch/arm64/boot/dts/qcom/qcm2290.dtsi b/arch/arm64/boot/dts/qcom/qcm2290.dtsi index d46e591e72b5c9..0911fb08ed6327 100644 --- a/arch/arm64/boot/dts/qcom/qcm2290.dtsi +++ b/arch/arm64/boot/dts/qcom/qcm2290.dtsi @@ -5,12 +5,15 @@ * Based on sm6115.dtsi and previous efforts by Shawn Guo & Loic Poulain. */ +#include #include #include #include #include #include #include +#include +#include #include / { @@ -150,6 +153,8 @@ clocks = <&rpmcc RPM_SMD_CE1_CLK>; clock-names = "core"; #reset-cells = <1>; + interconnects = <&system_noc MASTER_CRYPTO_CORE0 RPM_ALWAYS_TAG + &bimc SLAVE_EBI1 RPM_ALWAYS_TAG>; }; }; @@ -194,6 +199,7 @@ CLUSTER_PD: power-domain-cpu-cluster { #power-domain-cells = <0>; + power-domains = <&mpm>; domain-idle-states = <&CLUSTER_SLEEP>; }; }; @@ -261,6 +267,24 @@ }; }; }; + + mpm: interrupt-controller { + compatible = "qcom,mpm"; + qcom,rpm-msg-ram = <&apss_mpm>; + interrupts = ; + mboxes = <&apcs_glb 1>; + interrupt-controller; + #interrupt-cells = <2>; + #power-domain-cells = <0>; + interrupt-parent = <&intc>; + qcom,mpm-pin-count = <96>; + qcom,mpm-pin-map = <2 275>, /* TSENS0 uplow */ + <5 296>, /* Soundwire master_irq */ + <12 422>, /* DWC3 ss_phy_irq */ + <24 79>, /* Soundwire wake_irq */ + <86 183>, /* MPM wake, SPMI */ + <90 260>; /* QUSB2_PHY DP+DM */ + }; }; reserved_memory: reserved-memory { @@ -424,6 +448,7 @@ interrupts = ; gpio-controller; gpio-ranges = <&tlmm 0 0 127>; + wakeup-parent = <&mpm>; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; @@ -668,6 +693,33 @@ status = "disabled"; }; + system_noc: interconnect@1880000 { + compatible = "qcom,qcm2290-snoc"; + reg = <0x0 0x01880000 0x0 0x60200>; + #interconnect-cells = <2>; + + qup_virt: interconnect-qup { + compatible = "qcom,qcm2290-qup-virt"; + #interconnect-cells = <2>; + }; + + mmnrt_virt: interconnect-mmnrt { + compatible = "qcom,qcm2290-mmnrt-virt"; + #interconnect-cells = <2>; + }; + + mmrt_virt: interconnect-mmrt { + compatible = "qcom,qcm2290-mmrt-virt"; + #interconnect-cells = <2>; + }; + }; + + config_noc: interconnect@1900000 { + compatible = "qcom,qcm2290-cnoc"; + reg = <0x0 0x01900000 0x0 0x8200>; + #interconnect-cells = <2>; + }; + qfprom@1b44000 { compatible = "qcom,qcm2290-qfprom", "qcom,qfprom"; reg = <0x0 0x01b44000 0x0 0x3000>; @@ -680,6 +732,60 @@ }; }; + pmu@1b8e300 { + compatible = "qcom,qcm2290-cpu-bwmon", "qcom,sdm845-bwmon"; + reg = <0x0 0x01b8e300 0x0 0x600>; + interrupts = ; + + operating-points-v2 = <&cpu_bwmon_opp_table>; + interconnects = <&bimc MASTER_APPSS_PROC RPM_ACTIVE_TAG + &bimc SLAVE_EBI1 RPM_ACTIVE_TAG>; + + cpu_bwmon_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-0 { + opp-peak-kBps = <(200 * 4 * 1000)>; + }; + + opp-1 { + opp-peak-kBps = <(300 * 4 * 1000)>; + }; + + opp-2 { + opp-peak-kBps = <(451 * 4 * 1000)>; + }; + + opp-3 { + opp-peak-kBps = <(547 * 4 * 1000)>; + }; + + opp-4 { + opp-peak-kBps = <(681 * 4 * 1000)>; + }; + + opp-5 { + opp-peak-kBps = <(768 * 4 * 1000)>; + }; + + opp-6 { + opp-peak-kBps = <(1017 * 4 * 1000)>; + }; + + opp-7 { + opp-peak-kBps = <(1353 * 4 * 1000)>; + }; + + opp-8 { + opp-peak-kBps = <(1555 * 4 * 1000)>; + }; + + opp-9 { + opp-peak-kBps = <(1804 * 4 * 1000)>; + }; + }; + }; + spmi_bus: spmi@1c40000 { compatible = "qcom,spmi-pmic-arb"; reg = <0x0 0x01c40000 0x0 0x1100>, @@ -692,7 +798,7 @@ "obsrvr", "intr", "cnfg"; - interrupts = ; + interrupts-extended = <&mpm 86 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "periph_irq"; qcom,ee = <0>; qcom,channel = <0>; @@ -707,8 +813,8 @@ reg = <0x0 0x04411000 0x0 0x1ff>, <0x0 0x04410000 0x0 0x8>; #qcom,sensors = <10>; - interrupts = , - ; + interrupts-extended = <&mpm 2 IRQ_TYPE_LEVEL_HIGH>, + <&intc GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "uplow", "critical"; #thermal-sensor-cells = <1>; }; @@ -720,9 +826,22 @@ clock-names = "core"; }; + bimc: interconnect@4480000 { + compatible = "qcom,qcm2290-bimc"; + reg = <0x0 0x04480000 0x0 0x80000>; + #interconnect-cells = <2>; + }; + rpm_msg_ram: sram@45f0000 { - compatible = "qcom,rpm-msg-ram"; + compatible = "qcom,rpm-msg-ram", "mmio-sram"; reg = <0x0 0x045f0000 0x0 0x7000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x0 0x045f0000 0x7000>; + + apss_mpm: sram@1b8 { + reg = <0x1b8 0x48>; + }; }; sram@4690000 { @@ -755,13 +874,45 @@ resets = <&gcc GCC_SDCC1_BCR>; power-domains = <&rpmpd QCM2290_VDDCX>; + operating-points-v2 = <&sdhc1_opp_table>; iommus = <&apps_smmu 0xc0 0x0>; + interconnects = <&system_noc MASTER_SDCC_1 RPM_ALWAYS_TAG + &bimc SLAVE_EBI1 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc SLAVE_SDCC_1 RPM_ALWAYS_TAG>; + interconnect-names = "sdhc-ddr", + "cpu-sdhc"; qcom,dll-config = <0x000f642c>; qcom,ddr-config = <0x80040868>; bus-width = <8>; status = "disabled"; + + sdhc1_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-100000000 { + opp-hz = /bits/ 64 <100000000>; + required-opps = <&rpmpd_opp_low_svs>; + opp-peak-kBps = <250000 133320>; + opp-avg-kBps = <102400 65000>; + }; + + opp-192000000 { + opp-hz = /bits/ 64 <192000000>; + required-opps = <&rpmpd_opp_low_svs>; + opp-peak-kBps = <800000 300000>; + opp-avg-kBps = <204800 200000>; + }; + + opp-384000000 { + opp-hz = /bits/ 64 <384000000>; + required-opps = <&rpmpd_opp_svs_plus>; + opp-peak-kBps = <800000 300000>; + opp-avg-kBps = <204800 200000>; + }; + }; }; sdhc_2: mmc@4784000 { @@ -785,6 +936,12 @@ power-domains = <&rpmpd QCM2290_VDDCX>; operating-points-v2 = <&sdhc2_opp_table>; iommus = <&apps_smmu 0xa0 0x0>; + interconnects = <&system_noc MASTER_SDCC_2 RPM_ALWAYS_TAG + &bimc SLAVE_EBI1 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc SLAVE_SDCC_2 RPM_ALWAYS_TAG>; + interconnect-names = "sdhc-ddr", + "cpu-sdhc"; qcom,dll-config = <0x0007642c>; qcom,ddr-config = <0x80040868>; @@ -798,11 +955,15 @@ opp-100000000 { opp-hz = /bits/ 64 <100000000>; required-opps = <&rpmpd_opp_low_svs>; + opp-peak-kBps = <250000 133320>; + opp-avg-kBps = <261438 150000>; }; opp-202000000 { opp-hz = /bits/ 64 <202000000>; required-opps = <&rpmpd_opp_svs_plus>; + opp-peak-kBps = <800000 300000>; + opp-avg-kBps = <261438 300000>; }; }; }; @@ -850,6 +1011,15 @@ dmas = <&gpi_dma0 0 0 QCOM_GPI_I2C>, <&gpi_dma0 1 0 QCOM_GPI_I2C>; dma-names = "tx", "rx"; + interconnects = <&qup_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &qup_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc SLAVE_QUP_0 RPM_ALWAYS_TAG>, + <&system_noc MASTER_QUP_0 RPM_ALWAYS_TAG + &bimc SLAVE_EBI1 RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -866,6 +1036,12 @@ dmas = <&gpi_dma0 0 0 QCOM_GPI_SPI>, <&gpi_dma0 1 0 QCOM_GPI_SPI>; dma-names = "tx", "rx"; + interconnects = <&qup_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &qup_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc MASTER_APPSS_PROC RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -879,6 +1055,12 @@ clock-names = "se"; pinctrl-0 = <&qup_uart0_default>; pinctrl-names = "default"; + interconnects = <&qup_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &qup_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc MASTER_APPSS_PROC RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config"; status = "disabled"; }; @@ -893,6 +1075,15 @@ dmas = <&gpi_dma0 0 1 QCOM_GPI_I2C>, <&gpi_dma0 1 1 QCOM_GPI_I2C>; dma-names = "tx", "rx"; + interconnects = <&qup_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &qup_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc SLAVE_QUP_0 RPM_ALWAYS_TAG>, + <&system_noc MASTER_QUP_0 RPM_ALWAYS_TAG + &bimc SLAVE_EBI1 RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -909,6 +1100,12 @@ dmas = <&gpi_dma0 0 1 QCOM_GPI_SPI>, <&gpi_dma0 1 1 QCOM_GPI_SPI>; dma-names = "tx", "rx"; + interconnects = <&qup_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &qup_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc MASTER_APPSS_PROC RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -925,6 +1122,15 @@ dmas = <&gpi_dma0 0 2 QCOM_GPI_I2C>, <&gpi_dma0 1 2 QCOM_GPI_I2C>; dma-names = "tx", "rx"; + interconnects = <&qup_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &qup_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc SLAVE_QUP_0 RPM_ALWAYS_TAG>, + <&system_noc MASTER_QUP_0 RPM_ALWAYS_TAG + &bimc SLAVE_EBI1 RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -941,6 +1147,12 @@ dmas = <&gpi_dma0 0 2 QCOM_GPI_SPI>, <&gpi_dma0 1 2 QCOM_GPI_SPI>; dma-names = "tx", "rx"; + interconnects = <&qup_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &qup_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc MASTER_APPSS_PROC RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -957,6 +1169,15 @@ dmas = <&gpi_dma0 0 3 QCOM_GPI_I2C>, <&gpi_dma0 1 3 QCOM_GPI_I2C>; dma-names = "tx", "rx"; + interconnects = <&qup_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &qup_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc SLAVE_QUP_0 RPM_ALWAYS_TAG>, + <&system_noc MASTER_QUP_0 RPM_ALWAYS_TAG + &bimc SLAVE_EBI1 RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -973,6 +1194,12 @@ dmas = <&gpi_dma0 0 3 QCOM_GPI_SPI>, <&gpi_dma0 1 3 QCOM_GPI_SPI>; dma-names = "tx", "rx"; + interconnects = <&qup_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &qup_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc MASTER_APPSS_PROC RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -989,6 +1216,15 @@ dmas = <&gpi_dma0 0 4 QCOM_GPI_I2C>, <&gpi_dma0 1 4 QCOM_GPI_I2C>; dma-names = "tx", "rx"; + interconnects = <&qup_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &qup_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc SLAVE_QUP_0 RPM_ALWAYS_TAG>, + <&system_noc MASTER_QUP_0 RPM_ALWAYS_TAG + &bimc SLAVE_EBI1 RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -1005,6 +1241,12 @@ dmas = <&gpi_dma0 0 4 QCOM_GPI_SPI>, <&gpi_dma0 1 4 QCOM_GPI_SPI>; dma-names = "tx", "rx"; + interconnects = <&qup_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &qup_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc MASTER_APPSS_PROC RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -1018,6 +1260,12 @@ clock-names = "se"; pinctrl-0 = <&qup_uart4_default>; pinctrl-names = "default"; + interconnects = <&qup_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &qup_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc MASTER_APPSS_PROC RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config"; status = "disabled"; }; @@ -1032,6 +1280,15 @@ dmas = <&gpi_dma0 0 5 QCOM_GPI_I2C>, <&gpi_dma0 1 5 QCOM_GPI_I2C>; dma-names = "tx", "rx"; + interconnects = <&qup_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &qup_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc SLAVE_QUP_0 RPM_ALWAYS_TAG>, + <&system_noc MASTER_QUP_0 RPM_ALWAYS_TAG + &bimc SLAVE_EBI1 RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -1048,6 +1305,12 @@ dmas = <&gpi_dma0 0 5 QCOM_GPI_SPI>, <&gpi_dma0 1 5 QCOM_GPI_SPI>; dma-names = "tx", "rx"; + interconnects = <&qup_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &qup_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc MASTER_APPSS_PROC RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -1057,9 +1320,10 @@ usb: usb@4ef8800 { compatible = "qcom,qcm2290-dwc3", "qcom,dwc3"; reg = <0x0 0x04ef8800 0x0 0x400>; - interrupts = , - ; - interrupt-names = "hs_phy_irq", "ss_phy_irq"; + interrupts-extended = <&intc GIC_SPI 260 IRQ_TYPE_LEVEL_HIGH>, + <&mpm 12 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "hs_phy_irq", + "ss_phy_irq"; clocks = <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>, <&gcc GCC_USB30_PRIM_MASTER_CLK>, @@ -1080,6 +1344,13 @@ resets = <&gcc GCC_USB30_PRIM_BCR>; power-domains = <&gcc GCC_USB30_PRIM_GDSC>; + /* TODO: USB<->IPA path */ + interconnects = <&system_noc MASTER_USB3_0 RPM_ALWAYS_TAG + &bimc SLAVE_EBI1 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc SLAVE_USB3 RPM_ALWAYS_TAG>; + interconnect-names = "usb-ddr", + "apps-usb"; wakeup-source; #address-cells = <2>; @@ -1105,6 +1376,225 @@ }; }; + mdss: display-subsystem@5e00000 { + compatible = "qcom,qcm2290-mdss"; + reg = <0x0 0x05e00000 0x0 0x1000>; + reg-names = "mdss"; + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + + clocks = <&gcc GCC_DISP_AHB_CLK>, + <&gcc GCC_DISP_HF_AXI_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>; + clock-names = "iface", + "bus", + "core"; + + resets = <&dispcc DISP_CC_MDSS_CORE_BCR>; + + power-domains = <&dispcc MDSS_GDSC>; + + iommus = <&apps_smmu 0x420 0x2>, + <&apps_smmu 0x421 0x0>; + interconnects = <&mmrt_virt MASTER_MDP0 RPM_ALWAYS_TAG + &bimc SLAVE_EBI1 RPM_ALWAYS_TAG>, + <&bimc MASTER_APPSS_PROC RPM_ALWAYS_TAG + &config_noc SLAVE_DISPLAY_CFG RPM_ALWAYS_TAG>; + interconnect-names = "mdp0-mem", + "cpu-cfg"; + + #address-cells = <2>; + #size-cells = <2>; + ranges; + + status = "disabled"; + + mdp: display-controller@5e01000 { + compatible = "qcom,qcm2290-dpu"; + reg = <0x0 0x05e01000 0x0 0x8f000>, + <0x0 0x05eb0000 0x0 0x2008>; + reg-names = "mdp", + "vbif"; + + interrupt-parent = <&mdss>; + interrupts = <0>; + + clocks = <&gcc GCC_DISP_HF_AXI_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>, + <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>, + <&dispcc DISP_CC_MDSS_VSYNC_CLK>; + clock-names = "bus", + "iface", + "core", + "lut", + "vsync"; + + operating-points-v2 = <&mdp_opp_table>; + power-domains = <&rpmpd QCM2290_VDDCX>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dpu_intf1_out: endpoint { + remote-endpoint = <&mdss_dsi0_in>; + }; + }; + }; + + mdp_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-19200000 { + opp-hz = /bits/ 64 <19200000>; + required-opps = <&rpmpd_opp_min_svs>; + }; + + opp-192000000 { + opp-hz = /bits/ 64 <192000000>; + required-opps = <&rpmpd_opp_low_svs>; + }; + + opp-256000000 { + opp-hz = /bits/ 64 <256000000>; + required-opps = <&rpmpd_opp_svs>; + }; + + opp-307200000 { + opp-hz = /bits/ 64 <307200000>; + required-opps = <&rpmpd_opp_svs_plus>; + }; + + opp-384000000 { + opp-hz = /bits/ 64 <384000000>; + required-opps = <&rpmpd_opp_nom>; + }; + }; + }; + + mdss_dsi0: dsi@5e94000 { + compatible = "qcom,qcm2290-dsi-ctrl", "qcom,mdss-dsi-ctrl"; + reg = <0x0 0x05e94000 0x0 0x400>; + reg-names = "dsi_ctrl"; + + interrupt-parent = <&mdss>; + interrupts = <4>; + + clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK>, + <&dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>, + <&dispcc DISP_CC_MDSS_PCLK0_CLK>, + <&dispcc DISP_CC_MDSS_ESC0_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&gcc GCC_DISP_HF_AXI_CLK>; + clock-names = "byte", + "byte_intf", + "pixel", + "core", + "iface", + "bus"; + + assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>, + <&dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>; + assigned-clock-parents = <&mdss_dsi0_phy 0>, + <&mdss_dsi0_phy 1>; + + operating-points-v2 = <&dsi_opp_table>; + power-domains = <&rpmpd QCM2290_VDDCX>; + phys = <&mdss_dsi0_phy>; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + + dsi_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-19200000 { + opp-hz = /bits/ 64 <19200000>; + required-opps = <&rpmpd_opp_min_svs>; + }; + + opp-164000000 { + opp-hz = /bits/ 64 <164000000>; + required-opps = <&rpmpd_opp_low_svs>; + }; + + opp-187500000 { + opp-hz = /bits/ 64 <187500000>; + required-opps = <&rpmpd_opp_svs>; + }; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + mdss_dsi0_in: endpoint { + remote-endpoint = <&dpu_intf1_out>; + }; + }; + + port@1 { + reg = <1>; + + mdss_dsi0_out: endpoint { + }; + }; + }; + }; + + mdss_dsi0_phy: phy@5e94400 { + compatible = "qcom,dsi-phy-14nm-2290"; + reg = <0x0 0x05e94400 0x0 0x100>, + <0x0 0x05e94500 0x0 0x300>, + <0x0 0x05e94800 0x0 0x188>; + reg-names = "dsi_phy", + "dsi_phy_lane", + "dsi_pll"; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&rpmcc RPM_SMD_XO_CLK_SRC>; + clock-names = "iface", + "ref"; + + power-domains = <&rpmpd QCM2290_VDDMX>; + required-opps = <&rpmpd_opp_nom>; + + #clock-cells = <1>; + #phy-cells = <0>; + + status = "disabled"; + }; + }; + + dispcc: clock-controller@5f00000 { + compatible = "qcom,qcm2290-dispcc"; + reg = <0x0 0x05f00000 0x0 0x20000>; + clocks = <&rpmcc RPM_SMD_XO_CLK_SRC>, + <&rpmcc RPM_SMD_XO_A_CLK_SRC>, + <&gcc GCC_DISP_GPLL0_CLK_SRC>, + <&gcc GCC_DISP_GPLL0_DIV_CLK_SRC>, + <&mdss_dsi0_phy 0>, + <&mdss_dsi0_phy 1>; + clock-names = "bi_tcxo", + "bi_tcxo_ao", + "gcc_disp_gpll0_clk_src", + "gcc_disp_gpll0_div_clk_src", + "dsi0_phy_pll_out_byteclk", + "dsi0_phy_pll_out_dsiclk"; + #power-domain-cells = <1>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + remoteproc_mpss: remoteproc@6080000 { compatible = "qcom,qcm2290-mpss-pas", "qcom,sm6115-mpss-pas"; reg = <0x0 0x06080000 0x0 0x100>; diff --git a/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts b/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts index 2de0b8c26c3542..176898c9dbbd72 100644 --- a/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts +++ b/arch/arm64/boot/dts/qcom/qcm6490-fairphone-fp5.dts @@ -9,6 +9,8 @@ #define PM7250B_SID 8 #define PM7250B_SID1 9 +#include +#include #include #include #include @@ -75,26 +77,11 @@ no-map; }; - adsp_mem: adsp@86700000 { - reg = <0x0 0x86700000 0x0 0x2800000>; - no-map; - }; - cdsp_mem: cdsp@88f00000 { reg = <0x0 0x88f00000 0x0 0x1e00000>; no-map; }; - mpss_mem: mpss@8b800000 { - reg = <0x0 0x8b800000 0x0 0xf600000>; - no-map; - }; - - wpss_mem: wpss@9ae00000 { - reg = <0x0 0x9ae00000 0x0 0x1900000>; - no-map; - }; - rmtfs_mem: memory@f8500000 { compatible = "qcom,rmtfs-mem"; reg = <0x0 0xf8500000 0x0 0x600000>; @@ -134,6 +121,106 @@ enable-active-high; vin-supply = <&vreg_bob>; }; + + thermal-zones { + camera-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pmk8350_adc_tm 2>; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + chg-skin-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pm7250b_adc_tm 0>; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + conn-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pm7250b_adc_tm 1>; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + quiet-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pmk8350_adc_tm 1>; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + rear-cam-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pmk8350_adc_tm 4>; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + sdm-skin-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pmk8350_adc_tm 3>; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + xo-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pmk8350_adc_tm 0>; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + }; }; &apps_rsc { @@ -182,8 +269,9 @@ }; vreg_l7b: ldo7 { - regulator-min-microvolt = <2400000>; - regulator-max-microvolt = <3544000>; + /* Constrained for UFS VCC, at least until UFS driver scales voltage */ + regulator-min-microvolt = <2952000>; + regulator-max-microvolt = <2952000>; regulator-initial-mode = ; }; @@ -425,6 +513,42 @@ status = "okay"; }; +&pm7250b_adc { + channel@4d { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + label = "charger_skin_therm"; + }; + + channel@4f { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + label = "conn_therm"; + }; +}; + +&pm7250b_adc_tm { + status = "okay"; + + charger-skin-therm@0 { + reg = <0>; + io-channels = <&pm7250b_adc ADC5_AMUX_THM1_100K_PU>; + qcom,ratiometric; + qcom,hw-settle-time-us = <200>; + }; + + conn-therm@1 { + reg = <1>; + io-channels = <&pm7250b_adc ADC5_AMUX_THM3_100K_PU>; + qcom,ratiometric; + qcom,hw-settle-time-us = <200>; + }; +}; + &pm7325_gpios { volume_down_default: volume-down-default-state { pins = "gpio6"; @@ -448,10 +572,93 @@ }; }; +&pmk8350_adc_tm { + status = "okay"; + + xo-therm@0 { + reg = <0>; + io-channels = <&pmk8350_vadc PMK8350_ADC7_AMUX_THM1_100K_PU>; + qcom,ratiometric; + qcom,hw-settle-time-us = <200>; + }; + + quiet-therm@1 { + reg = <1>; + io-channels = <&pmk8350_vadc PM7325_ADC7_AMUX_THM1_100K_PU>; + qcom,ratiometric; + qcom,hw-settle-time-us = <200>; + }; + + cam-flash-therm@2 { + reg = <2>; + io-channels = <&pmk8350_vadc PM7325_ADC7_AMUX_THM2_100K_PU>; + qcom,ratiometric; + qcom,hw-settle-time-us = <200>; + }; + + sdm-skin-therm@3 { + reg = <3>; + io-channels = <&pmk8350_vadc PM7325_ADC7_AMUX_THM3_100K_PU>; + qcom,ratiometric; + qcom,hw-settle-time-us = <200>; + }; + + wide-rfc-therm@4 { + reg = <4>; + io-channels = <&pmk8350_vadc PM7325_ADC7_AMUX_THM4_100K_PU>; + qcom,ratiometric; + qcom,hw-settle-time-us = <200>; + }; +}; + &pmk8350_rtc { status = "okay"; }; +&pmk8350_vadc { + status = "okay"; + + channel@44 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + label = "pmk8350_xo_therm"; + }; + + channel@144 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + label = "pm7325_quiet_therm"; + }; + + channel@145 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + label = "pm7325_cam_flash_therm"; + }; + + channel@146 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + label = "pm7325_sdm_skin_therm"; + }; + + channel@147 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + label = "pm7325_wide_rfc_therm"; + }; +}; + &pon_pwrkey { status = "okay"; }; @@ -489,6 +696,26 @@ status = "okay"; }; +&remoteproc_adsp { + firmware-name = "qcom/qcm6490/fairphone5/adsp.mbn"; + status = "okay"; +}; + +&remoteproc_cdsp { + firmware-name = "qcom/qcm6490/fairphone5/cdsp.mbn"; + status = "okay"; +}; + +&remoteproc_mpss { + firmware-name = "qcom/qcm6490/fairphone5/modem.mbn"; + status = "okay"; +}; + +&remoteproc_wpss { + firmware-name = "qcom/qcm6490/fairphone5/wpss.mbn"; + status = "okay"; +}; + &sdc2_clk { drive-strength = <16>; bias-disable; @@ -632,6 +859,28 @@ }; }; +&ufs_mem_hc { + reset-gpios = <&tlmm 175 GPIO_ACTIVE_LOW>; + + vcc-supply = <&vreg_l7b>; + vcc-max-microamp = <800000>; + /* + * Technically l9b enables an eLDO (supplied by s1b) which then powers + * VCCQ2 of the UFS. + */ + vccq-supply = <&vreg_l9b>; + vccq-max-microamp = <900000>; + + status = "okay"; +}; + +&ufs_mem_phy { + vdda-phy-supply = <&vreg_l10c>; + vdda-pll-supply = <&vreg_l6b>; + + status = "okay"; +}; + &usb_1 { status = "okay"; }; @@ -665,3 +914,8 @@ status = "okay"; }; + +&wifi { + qcom,ath11k-calibration-variant = "Fairphone_5"; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/qcm6490-idp.dts b/arch/arm64/boot/dts/qcom/qcm6490-idp.dts new file mode 100644 index 00000000000000..03e97e27d16d4a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcm6490-idp.dts @@ -0,0 +1,468 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +/dts-v1/; + +#include +#include "sc7280.dtsi" +#include "pm7325.dtsi" +#include "pm8350c.dtsi" +#include "pmk8350.dtsi" + +/delete-node/ &ipa_fw_mem; +/delete-node/ &rmtfs_mem; +/delete-node/ &adsp_mem; +/delete-node/ &cdsp_mem; +/delete-node/ &video_mem; +/delete-node/ &wlan_ce_mem; +/delete-node/ &wpss_mem; +/delete-node/ &xbl_mem; + +/ { + model = "Qualcomm Technologies, Inc. QCM6490 IDP"; + compatible = "qcom,qcm6490-idp", "qcom,qcm6490"; + chassis-type = "embedded"; + + aliases { + serial0 = &uart5; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + reserved-memory { + xbl_mem: xbl@80700000 { + reg = <0x0 0x80700000 0x0 0x100000>; + no-map; + }; + + cdsp_secure_heap_mem: cdsp-secure-heap@81800000 { + reg = <0x0 0x81800000 0x0 0x1e00000>; + no-map; + }; + + camera_mem: camera@84300000 { + reg = <0x0 0x84300000 0x0 0x500000>; + no-map; + }; + + wpss_mem: wpss@84800000 { + reg = <0x0 0x84800000 0x0 0x1900000>; + no-map; + }; + + adsp_mem: adsp@86100000 { + reg = <0x0 0x86100000 0x0 0x2800000>; + no-map; + }; + + cdsp_mem: cdsp@88900000 { + reg = <0x0 0x88900000 0x0 0x1e00000>; + no-map; + }; + + video_mem: video@8a700000 { + reg = <0x0 0x8a700000 0x0 0x700000>; + no-map; + }; + + cvp_mem: cvp@8ae00000 { + reg = <0x0 0x8ae00000 0x0 0x500000>; + no-map; + }; + + ipa_fw_mem: ipa-fw@8b300000 { + reg = <0x0 0x8b300000 0x0 0x10000>; + no-map; + }; + + ipa_gsi_mem: ipa-gsi@8b310000 { + reg = <0x0 0x8b310000 0x0 0xa000>; + no-map; + }; + + gpu_microcode_mem: gpu-microcode@8b31a000 { + reg = <0x0 0x8b31a000 0x0 0x2000>; + no-map; + }; + + mpss_mem: mpss@8b800000 { + reg = <0x0 0x8b800000 0x0 0xf600000>; + no-map; + }; + + tz_stat_mem: tz-stat@c0000000 { + reg = <0x0 0xc0000000 0x0 0x100000>; + no-map; + }; + + tags_mem: tags@c0100000 { + reg = <0x0 0xc0100000 0x0 0x1200000>; + no-map; + }; + + qtee_mem: qtee@c1300000 { + reg = <0x0 0xc1300000 0x0 0x500000>; + no-map; + }; + + trusted_apps_mem: trusted_apps@c1800000 { + reg = <0x0 0xc1800000 0x0 0x1c00000>; + no-map; + }; + + debug_vm_mem: debug-vm@d0600000 { + reg = <0x0 0xd0600000 0x0 0x100000>; + no-map; + }; + }; + + vph_pwr: vph-pwr-regulator { + compatible = "regulator-fixed"; + regulator-name = "vph_pwr"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <4350000>; + }; +}; + +&apps_rsc { + regulators-0 { + compatible = "qcom,pm7325-rpmh-regulators"; + qcom,pmic-id = "b"; + + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vph_pwr>; + vdd-s3-supply = <&vph_pwr>; + vdd-s4-supply = <&vph_pwr>; + vdd-s5-supply = <&vph_pwr>; + vdd-s6-supply = <&vph_pwr>; + vdd-s7-supply = <&vph_pwr>; + vdd-s8-supply = <&vph_pwr>; + vdd-l1-l4-l12-l15-supply = <&vreg_s7b_0p972>; + vdd-l2-l7-supply = <&vreg_bob_3p296>; + vdd-l3-supply = <&vreg_s2b_0p876>; + vdd-l5-supply = <&vreg_s2b_0p876>; + vdd-l6-l9-l10-supply = <&vreg_s8b_1p272>; + vdd-l8-supply = <&vreg_s7b_0p972>; + vdd-l11-l17-l18-l19-supply = <&vreg_s1b_1p872>; + vdd-l13-supply = <&vreg_s7b_0p972>; + vdd-l14-l16-supply = <&vreg_s8b_1p272>; + + vreg_s1b_1p872: smps1 { + regulator-min-microvolt = <1840000>; + regulator-max-microvolt = <2040000>; + }; + + vreg_s2b_0p876: smps2 { + regulator-min-microvolt = <570070>; + regulator-max-microvolt = <1050000>; + }; + + vreg_s7b_0p972: smps7 { + regulator-min-microvolt = <535000>; + regulator-max-microvolt = <1120000>; + }; + + vreg_s8b_1p272: smps8 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1500000>; + regulator-initial-mode = ; + }; + + vreg_l1b_0p912: ldo1 { + regulator-min-microvolt = <825000>; + regulator-max-microvolt = <925000>; + regulator-initial-mode = ; + }; + + vreg_l2b_3p072: ldo2 { + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_l3b_0p504: ldo3 { + regulator-min-microvolt = <312000>; + regulator-max-microvolt = <910000>; + regulator-initial-mode = ; + }; + + vreg_l4b_0p752: ldo4 { + regulator-min-microvolt = <752000>; + regulator-max-microvolt = <820000>; + regulator-initial-mode = ; + }; + + reg_l5b_0p752: ldo5 { + regulator-min-microvolt = <552000>; + regulator-max-microvolt = <832000>; + regulator-initial-mode = ; + }; + + vreg_l6b_1p2: ldo6 { + regulator-min-microvolt = <1140000>; + regulator-max-microvolt = <1260000>; + regulator-initial-mode = ; + }; + + vreg_l7b_2p952: ldo7 { + regulator-min-microvolt = <2400000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_l8b_0p904: ldo8 { + regulator-min-microvolt = <870000>; + regulator-max-microvolt = <970000>; + regulator-initial-mode = ; + }; + + vreg_l9b_1p2: ldo9 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1304000>; + regulator-initial-mode = ; + }; + + vreg_l11b_1p504: ldo11 { + regulator-min-microvolt = <1504000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l12b_0p751: ldo12 { + regulator-min-microvolt = <751000>; + regulator-max-microvolt = <824000>; + regulator-initial-mode = ; + }; + + vreg_l13b_0p53: ldo13 { + regulator-min-microvolt = <530000>; + regulator-max-microvolt = <824000>; + regulator-initial-mode = ; + }; + + vreg_l14b_1p08: ldo14 { + regulator-min-microvolt = <1080000>; + regulator-max-microvolt = <1304000>; + regulator-initial-mode = ; + }; + + vreg_l15b_0p765: ldo15 { + regulator-min-microvolt = <765000>; + regulator-max-microvolt = <1020000>; + regulator-initial-mode = ; + }; + + vreg_l16b_1p1: ldo16 { + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1300000>; + regulator-initial-mode = ; + }; + + vreg_l17b_1p7: ldo17 { + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <1900000>; + regulator-initial-mode = ; + }; + + vreg_l18b_1p8: ldo18 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l19b_1p8: ldo19 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; + + regulators-1 { + compatible = "qcom,pm8350c-rpmh-regulators"; + qcom,pmic-id = "c"; + + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vph_pwr>; + vdd-s3-supply = <&vph_pwr>; + vdd-s4-supply = <&vph_pwr>; + vdd-s5-supply = <&vph_pwr>; + vdd-s6-supply = <&vph_pwr>; + vdd-s7-supply = <&vph_pwr>; + vdd-s8-supply = <&vph_pwr>; + vdd-s9-supply = <&vph_pwr>; + vdd-s10-supply = <&vph_pwr>; + vdd-l1-l12-supply = <&vreg_s1b_1p872>; + vdd-l2-l8-supply = <&vreg_s1b_1p872>; + vdd-l3-l4-l5-l7-l13-supply = <&vreg_bob_3p296>; + vdd-l6-l9-l11-supply = <&vreg_bob_3p296>; + vdd-l10-supply = <&vreg_s7b_0p972>; + vdd-bob-supply = <&vph_pwr>; + + vreg_s1c_2p19: smps1 { + regulator-min-microvolt = <2190000>; + regulator-max-microvolt = <2210000>; + }; + + vreg_s2c_0p752: smps2 { + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <800000>; + }; + + vreg_s5c_0p752: smps5 { + regulator-min-microvolt = <465000>; + regulator-max-microvolt = <1050000>; + }; + + vreg_s7c_0p752: smps7 { + regulator-min-microvolt = <465000>; + regulator-max-microvolt = <800000>; + }; + + vreg_s9c_1p084: smps9 { + regulator-min-microvolt = <1010000>; + regulator-max-microvolt = <1170000>; + }; + + vreg_l1c_1p8: ldo1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1980000>; + regulator-initial-mode = ; + }; + + vreg_l2c_1p62: ldo2 { + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <1980000>; + regulator-initial-mode = ; + }; + + vreg_l3c_2p8: ldo3 { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3540000>; + regulator-initial-mode = ; + }; + + vreg_l4c_1p62: ldo4 { + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <3300000>; + regulator-initial-mode = ; + }; + + vreg_l5c_1p62: ldo5 { + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <3300000>; + regulator-initial-mode = ; + }; + + vreg_l6c_2p96: ldo6 { + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_l7c_3p0: ldo7 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_l8c_1p62: ldo8 { + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l9c_2p96: ldo9 { + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <35440000>; + regulator-initial-mode = ; + }; + + vreg_l10c_0p88: ldo10 { + regulator-min-microvolt = <720000>; + regulator-max-microvolt = <1050000>; + regulator-initial-mode = ; + }; + + vreg_l11c_2p8: ldo11 { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_l12c_1p65: ldo12 { + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l13c_2p7: ldo13 { + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_bob_3p296: bob { + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3960000>; + }; + }; +}; + +&qupv3_id_0 { + status = "okay"; +}; + +&sdhc_1 { + non-removable; + no-sd; + no-sdio; + + vmmc-supply = <&vreg_l7b_2p952>; + vqmmc-supply = <&vreg_l19b_1p8>; + + status = "okay"; +}; + +&tlmm { + gpio-reserved-ranges = <32 2>, /* ADSP */ + <48 4>; /* NFC */ +}; + +&uart5 { + compatible = "qcom,geni-debug-uart"; + status = "okay"; +}; + +&usb_1 { + status = "okay"; +}; + +&usb_1_dwc3 { + dr_mode = "peripheral"; +}; + +&usb_1_hsphy { + vdda-pll-supply = <&vreg_l10c_0p88>; + vdda33-supply = <&vreg_l2b_3p072>; + vdda18-supply = <&vreg_l1c_1p8>; + + status = "okay"; +}; + +&usb_1_qmpphy { + vdda-phy-supply = <&vreg_l6b_1p2>; + vdda-pll-supply = <&vreg_l1b_0p912>; + + status = "okay"; +}; + +&wifi { + memory-region = <&wlan_fw_mem>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs404.dtsi b/arch/arm64/boot/dts/qcom/qcs404.dtsi index 2721f32dfb7104..2f2eeaf2e94578 100644 --- a/arch/arm64/boot/dts/qcom/qcs404.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs404.dtsi @@ -558,9 +558,6 @@ reg = <0x00400000 0x80000>; compatible = "qcom,qcs404-bimc"; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_BIMC_CLK>, - <&rpmcc RPM_SMD_BIMC_A_CLK>; }; tsens: thermal-sensor@4a9000 { @@ -601,18 +598,12 @@ reg = <0x00500000 0x15080>; compatible = "qcom,qcs404-pcnoc"; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_PNOC_CLK>, - <&rpmcc RPM_SMD_PNOC_A_CLK>; }; snoc: interconnect@580000 { reg = <0x00580000 0x23080>; compatible = "qcom,qcs404-snoc"; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_SNOC_CLK>, - <&rpmcc RPM_SMD_SNOC_A_CLK>; }; remoteproc_cdsp: remoteproc@b00000 { @@ -1461,7 +1452,7 @@ }; }; - pcie: pci@10000000 { + pcie: pcie@10000000 { compatible = "qcom,pcie-qcs404"; reg = <0x10000000 0xf1d>, <0x10000f20 0xa8>, diff --git a/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts new file mode 100644 index 00000000000000..8bb7d13d85f663 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs6490-rb3gen2.dts @@ -0,0 +1,455 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +/dts-v1/; + +/* PM7250B is configured to use SID8/9 */ +#define PM7250B_SID 8 +#define PM7250B_SID1 9 + +#include +#include "sc7280.dtsi" +#include "pm7250b.dtsi" +#include "pm7325.dtsi" +#include "pm8350c.dtsi" +#include "pmk8350.dtsi" + +/delete-node/ &ipa_fw_mem; +/delete-node/ &remoteproc_mpss; +/delete-node/ &rmtfs_mem; +/delete-node/ &adsp_mem; +/delete-node/ &cdsp_mem; +/delete-node/ &video_mem; +/delete-node/ &wlan_ce_mem; +/delete-node/ &wpss_mem; +/delete-node/ &xbl_mem; + +/ { + model = "Qualcomm Technologies, Inc. Robotics RB3gen2"; + compatible = "qcom,qcs6490-rb3gen2", "qcom,qcm6490"; + chassis-type = "embedded"; + + aliases { + serial0 = &uart5; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + reserved-memory { + xbl_mem: xbl@80700000 { + reg = <0x0 0x80700000 0x0 0x100000>; + no-map; + }; + + cdsp_secure_heap_mem: cdsp-secure-heap@81800000 { + reg = <0x0 0x81800000 0x0 0x1e00000>; + no-map; + }; + + camera_mem: camera@84300000 { + reg = <0x0 0x84300000 0x0 0x500000>; + no-map; + }; + + wpss_mem: wpss@84800000 { + reg = <0x0 0x84800000 0x0 0x1900000>; + no-map; + }; + + adsp_mem: adsp@86100000 { + reg = <0x0 0x86100000 0x0 0x2800000>; + no-map; + }; + + cdsp_mem: cdsp@88900000 { + reg = <0x0 0x88900000 0x0 0x1e00000>; + no-map; + }; + + video_mem: video@8a700000 { + reg = <0x0 0x8a700000 0x0 0x700000>; + no-map; + }; + + cvp_mem: cvp@8ae00000 { + reg = <0x0 0x8ae00000 0x0 0x500000>; + no-map; + }; + + ipa_fw_mem: ipa-fw@8b300000 { + reg = <0x0 0x8b300000 0x0 0x10000>; + no-map; + }; + + ipa_gsi_mem: ipa-gsi@8b310000 { + reg = <0x0 0x8b310000 0x0 0xa000>; + no-map; + }; + + gpu_microcode_mem: gpu-microcode@8b31a000 { + reg = <0x0 0x8b31a000 0x0 0x2000>; + no-map; + }; + + tz_stat_mem: tz-stat@c0000000 { + reg = <0x0 0xc0000000 0x0 0x100000>; + no-map; + }; + + tags_mem: tags@c0100000 { + reg = <0x0 0xc0100000 0x0 0x1200000>; + no-map; + }; + + qtee_mem: qtee@c1300000 { + reg = <0x0 0xc1300000 0x0 0x500000>; + no-map; + }; + + trusted_apps_mem: trusted_apps@c1800000 { + reg = <0x0 0xc1800000 0x0 0x1c00000>; + no-map; + }; + + debug_vm_mem: debug-vm@d0600000 { + reg = <0x0 0xd0600000 0x0 0x100000>; + no-map; + }; + }; + + vph_pwr: vph-pwr-regulator { + compatible = "regulator-fixed"; + regulator-name = "vph_pwr"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <4350000>; + }; +}; + +&apps_rsc { + regulators-0 { + compatible = "qcom,pm7325-rpmh-regulators"; + qcom,pmic-id = "b"; + + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vph_pwr>; + vdd-s3-supply = <&vph_pwr>; + vdd-s4-supply = <&vph_pwr>; + vdd-s5-supply = <&vph_pwr>; + vdd-s6-supply = <&vph_pwr>; + vdd-s7-supply = <&vph_pwr>; + vdd-s8-supply = <&vph_pwr>; + vdd-l1-l4-l12-l15-supply = <&vreg_s7b_0p972>; + vdd-l2-l7-supply = <&vreg_bob_3p296>; + vdd-l3-supply = <&vreg_s2b_0p876>; + vdd-l5-supply = <&vreg_s2b_0p876>; + vdd-l6-l9-l10-supply = <&vreg_s8b_1p272>; + vdd-l8-supply = <&vreg_s7b_0p972>; + vdd-l11-l17-l18-l19-supply = <&vreg_s1b_1p872>; + vdd-l13-supply = <&vreg_s7b_0p972>; + vdd-l14-l16-supply = <&vreg_s8b_1p272>; + + vreg_s1b_1p872: smps1 { + regulator-min-microvolt = <1840000>; + regulator-max-microvolt = <2040000>; + }; + + vreg_s2b_0p876: smps2 { + regulator-min-microvolt = <570070>; + regulator-max-microvolt = <1050000>; + }; + + vreg_s7b_0p972: smps7 { + regulator-min-microvolt = <535000>; + regulator-max-microvolt = <1120000>; + }; + + vreg_s8b_1p272: smps8 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1500000>; + regulator-initial-mode = ; + }; + + vreg_l1b_0p912: ldo1 { + regulator-min-microvolt = <825000>; + regulator-max-microvolt = <925000>; + regulator-initial-mode = ; + }; + + vreg_l2b_3p072: ldo2 { + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_l3b_0p504: ldo3 { + regulator-min-microvolt = <312000>; + regulator-max-microvolt = <910000>; + regulator-initial-mode = ; + }; + + vreg_l4b_0p752: ldo4 { + regulator-min-microvolt = <752000>; + regulator-max-microvolt = <820000>; + regulator-initial-mode = ; + }; + + reg_l5b_0p752: ldo5 { + regulator-min-microvolt = <552000>; + regulator-max-microvolt = <832000>; + regulator-initial-mode = ; + }; + + vreg_l6b_1p2: ldo6 { + regulator-min-microvolt = <1140000>; + regulator-max-microvolt = <1260000>; + regulator-initial-mode = ; + }; + + vreg_l7b_2p952: ldo7 { + regulator-min-microvolt = <2400000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_l8b_0p904: ldo8 { + regulator-min-microvolt = <870000>; + regulator-max-microvolt = <970000>; + regulator-initial-mode = ; + }; + + vreg_l9b_1p2: ldo9 { + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1304000>; + regulator-initial-mode = ; + }; + + vreg_l11b_1p504: ldo11 { + regulator-min-microvolt = <1504000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l12b_0p751: ldo12 { + regulator-min-microvolt = <751000>; + regulator-max-microvolt = <824000>; + regulator-initial-mode = ; + }; + + vreg_l13b_0p53: ldo13 { + regulator-min-microvolt = <530000>; + regulator-max-microvolt = <824000>; + regulator-initial-mode = ; + }; + + vreg_l14b_1p08: ldo14 { + regulator-min-microvolt = <1080000>; + regulator-max-microvolt = <1304000>; + regulator-initial-mode = ; + }; + + vreg_l15b_0p765: ldo15 { + regulator-min-microvolt = <765000>; + regulator-max-microvolt = <1020000>; + regulator-initial-mode = ; + }; + + vreg_l16b_1p1: ldo16 { + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1300000>; + regulator-initial-mode = ; + }; + + vreg_l17b_1p7: ldo17 { + regulator-min-microvolt = <1700000>; + regulator-max-microvolt = <1900000>; + regulator-initial-mode = ; + }; + + vreg_l18b_1p8: ldo18 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l19b_1p8: ldo19 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + }; + + regulators-1 { + compatible = "qcom,pm8350c-rpmh-regulators"; + qcom,pmic-id = "c"; + + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vph_pwr>; + vdd-s3-supply = <&vph_pwr>; + vdd-s4-supply = <&vph_pwr>; + vdd-s5-supply = <&vph_pwr>; + vdd-s6-supply = <&vph_pwr>; + vdd-s7-supply = <&vph_pwr>; + vdd-s8-supply = <&vph_pwr>; + vdd-s9-supply = <&vph_pwr>; + vdd-s10-supply = <&vph_pwr>; + vdd-l1-l12-supply = <&vreg_s1b_1p872>; + vdd-l2-l8-supply = <&vreg_s1b_1p872>; + vdd-l3-l4-l5-l7-l13-supply = <&vreg_bob_3p296>; + vdd-l6-l9-l11-supply = <&vreg_bob_3p296>; + vdd-l10-supply = <&vreg_s7b_0p972>; + vdd-bob-supply = <&vph_pwr>; + + vreg_s1c_2p19: smps1 { + regulator-min-microvolt = <2190000>; + regulator-max-microvolt = <2210000>; + }; + + vreg_s2c_0p752: smps2 { + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <800000>; + }; + + vreg_s5c_0p752: smps5 { + regulator-min-microvolt = <465000>; + regulator-max-microvolt = <1050000>; + }; + + vreg_s7c_0p752: smps7 { + regulator-min-microvolt = <465000>; + regulator-max-microvolt = <800000>; + }; + + vreg_s9c_1p084: smps9 { + regulator-min-microvolt = <1010000>; + regulator-max-microvolt = <1170000>; + }; + + vreg_l1c_1p8: ldo1 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1980000>; + regulator-initial-mode = ; + }; + + vreg_l2c_1p62: ldo2 { + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <1980000>; + regulator-initial-mode = ; + }; + + vreg_l3c_2p8: ldo3 { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3540000>; + regulator-initial-mode = ; + }; + + vreg_l4c_1p62: ldo4 { + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <3300000>; + regulator-initial-mode = ; + }; + + vreg_l5c_1p62: ldo5 { + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <3300000>; + regulator-initial-mode = ; + }; + + vreg_l6c_2p96: ldo6 { + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_l7c_3p0: ldo7 { + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_l8c_1p62: ldo8 { + regulator-min-microvolt = <1620000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l9c_2p96: ldo9 { + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <35440000>; + regulator-initial-mode = ; + }; + + vreg_l10c_0p88: ldo10 { + regulator-min-microvolt = <720000>; + regulator-max-microvolt = <1050000>; + regulator-initial-mode = ; + }; + + vreg_l11c_2p8: ldo11 { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_l12c_1p65: ldo12 { + regulator-min-microvolt = <1650000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l13c_2p7: ldo13 { + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3544000>; + regulator-initial-mode = ; + }; + + vreg_bob_3p296: bob { + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3960000>; + }; + }; +}; + +&qupv3_id_0 { + status = "okay"; +}; + +&tlmm { + gpio-reserved-ranges = <32 2>, /* ADSP */ + <48 4>; /* NFC */ +}; + +&uart5 { + compatible = "qcom,geni-debug-uart"; + status = "okay"; +}; + +&usb_1 { + status = "okay"; +}; + +&usb_1_dwc3 { + dr_mode = "peripheral"; +}; + +&usb_1_hsphy { + vdda-pll-supply = <&vreg_l10c_0p88>; + vdda33-supply = <&vreg_l2b_3p072>; + vdda18-supply = <&vreg_l1c_1p8>; + + status = "okay"; +}; + +&usb_1_qmpphy { + vdda-phy-supply = <&vreg_l6b_1p2>; + vdda-pll-supply = <&vreg_l1b_0p912>; + + status = "okay"; +}; + +&wifi { + memory-region = <&wlan_fw_mem>; +}; diff --git a/arch/arm64/boot/dts/qcom/qdu1000.dtsi b/arch/arm64/boot/dts/qcom/qdu1000.dtsi index 1c0e5d271e91bb..832f472c4b7a5e 100644 --- a/arch/arm64/boot/dts/qcom/qdu1000.dtsi +++ b/arch/arm64/boot/dts/qcom/qdu1000.dtsi @@ -381,6 +381,20 @@ #power-domain-cells = <1>; }; + ecpricc: clock-controller@280000 { + compatible = "qcom,qdu1000-ecpricc"; + reg = <0x0 0x00280000 0x0 0x31c00>; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&gcc GCC_ECPRI_CC_GPLL0_CLK_SRC>, + <&gcc GCC_ECPRI_CC_GPLL1_EVEN_CLK_SRC>, + <&gcc GCC_ECPRI_CC_GPLL2_EVEN_CLK_SRC>, + <&gcc GCC_ECPRI_CC_GPLL3_CLK_SRC>, + <&gcc GCC_ECPRI_CC_GPLL4_CLK_SRC>, + <&gcc GCC_ECPRI_CC_GPLL5_EVEN_CLK_SRC>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + gpi_dma0: dma-controller@900000 { compatible = "qcom,qdu1000-gpi-dma", "qcom,sm6350-gpi-dma"; reg = <0x0 0x900000 0x0 0x60000>; @@ -1446,13 +1460,10 @@ system-cache-controller@19200000 { compatible = "qcom,qdu1000-llcc"; reg = <0 0x19200000 0 0xd80000>, - <0 0x1a200000 0 0x80000>, - <0 0x221c8128 0 0x4>; - reg-names = "llcc_base", - "llcc_broadcast_base", - "multi_channel_register"; + <0 0x1a200000 0 0x80000>; + reg-names = "llcc0_base", + "llcc_broadcast_base"; interrupts = ; - multi-ch-bit-off = <24 2>; }; }; diff --git a/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts b/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts index 94885b9c21c89d..aa53b6af6d9cbd 100644 --- a/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts +++ b/arch/arm64/boot/dts/qcom/qrb2210-rb1.dts @@ -23,6 +23,14 @@ stdout-path = "serial0:115200n8"; }; + clocks { + clk40M: can-clk { + compatible = "fixed-clock"; + clock-frequency = <40000000>; + #clock-cells = <0>; + }; + }; + gpio-keys { compatible = "gpio-keys"; label = "gpio-keys"; @@ -40,6 +48,17 @@ }; }; + hdmi-connector { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_con: endpoint { + remote-endpoint = <<9611_out>; + }; + }; + }; + leds { compatible = "gpio-leds"; @@ -158,6 +177,68 @@ }; }; +&gpi_dma0 { + status = "okay"; +}; + +&i2c2 { + clock-frequency = <400000>; + status = "okay"; + + lt9611_codec: hdmi-bridge@2b { + compatible = "lontium,lt9611uxc"; + reg = <0x2b>; + interrupts-extended = <&tlmm 46 IRQ_TYPE_EDGE_FALLING>; + reset-gpios = <&tlmm 41 GPIO_ACTIVE_HIGH>; + + vdd-supply = <&vreg_hdmi_out_1p2>; + vcc-supply = <<9611_3v3>; + + pinctrl-0 = <<9611_irq_pin <9611_rst_pin>; + pinctrl-names = "default"; + #sound-dai-cells = <1>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + lt9611_a: endpoint { + remote-endpoint = <&mdss_dsi0_out>; + }; + }; + + port@2 { + reg = <2>; + + lt9611_out: endpoint { + remote-endpoint = <&hdmi_con>; + }; + }; + }; + }; +}; + +&mdss { + status = "okay"; +}; + +&mdss_dsi0 { + vdda-supply = <&pm2250_l5>; + status = "okay"; +}; + +&mdss_dsi0_out { + remote-endpoint = <<9611_a>; + data-lanes = <0 1 2 3>; +}; + +&mdss_dsi0_phy { + status = "okay"; +}; + &pm2250_resin { linux,code = ; status = "okay"; @@ -376,7 +457,34 @@ status = "okay"; }; +&spi5 { + status = "okay"; + + can@0 { + compatible = "microchip,mcp2518fd"; + reg = <0>; + interrupts-extended = <&tlmm 39 IRQ_TYPE_LEVEL_LOW>; + clocks = <&clk40M>; + spi-max-frequency = <10000000>; + vdd-supply = <&vdc_5v>; + xceiver-supply = <&vdc_5v>; + }; +}; + &tlmm { + lt9611_rst_pin: lt9611-rst-state { + pins = "gpio41"; + function = "gpio"; + input-disable; + output-high; + }; + + lt9611_irq_pin: lt9611-irq-state { + pins = "gpio46"; + function = "gpio"; + bias-disable; + }; + sd_det_in_on: sd-det-in-on-state { pins = "gpio88"; function = "gpio"; @@ -415,6 +523,10 @@ status = "okay"; }; +&usb_dwc3 { + dr_mode = "host"; +}; + &usb_hsphy { vdd-supply = <&pm2250_l12>; vdda-pll-supply = <&pm2250_l13>; @@ -427,6 +539,7 @@ vdd-1.8-xo-supply = <&pm2250_l13>; vdd-1.3-rfa-supply = <&pm2250_l10>; vdd-3.3-ch0-supply = <&pm2250_l22>; + qcom,ath10k-calibration-variant = "Thundercomm_RB1"; status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts b/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts index a7278a9472ed9b..7c19f874fa716d 100644 --- a/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts +++ b/arch/arm64/boot/dts/qcom/qrb4210-rb2.dts @@ -15,6 +15,7 @@ aliases { serial0 = &uart4; + serial1 = &uart3; }; chosen { @@ -280,6 +281,12 @@ status = "okay"; }; +&remoteproc_mpss { + firmware-name = "qcom/qrb4210/modem.mbn"; + + status = "okay"; +}; + &rpm_requests { regulators { compatible = "qcom,rpm-pm6125-regulators"; @@ -346,13 +353,14 @@ }; vreg_l8a_0p664: l8 { - regulator-min-microvolt = <400000>; - regulator-max-microvolt = <728000>; + regulator-min-microvolt = <640000>; + regulator-max-microvolt = <640000>; }; vreg_l9a_1p8: l9 { regulator-min-microvolt = <1800000>; - regulator-max-microvolt = <2000000>; + regulator-max-microvolt = <1800000>; + regulator-allow-set-load; }; vreg_l10a_1p8: l10 { @@ -389,11 +397,13 @@ vreg_l16a_1p3: l16 { regulator-min-microvolt = <1704000>; regulator-max-microvolt = <1904000>; + regulator-allow-set-load; }; vreg_l17a_1p3: l17 { regulator-min-microvolt = <1152000>; regulator-max-microvolt = <1384000>; + regulator-allow-set-load; }; vreg_l18a_1p232: l18 { @@ -424,8 +434,9 @@ }; vreg_l23a_3p3: l23 { - regulator-min-microvolt = <3200000>; - regulator-max-microvolt = <3400000>; + regulator-min-microvolt = <3312000>; + regulator-max-microvolt = <3312000>; + regulator-allow-set-load; }; vreg_l24a_2p96: l24 { @@ -487,6 +498,66 @@ <56 3>, <61 2>, <64 1>, <68 1>, <72 8>, <96 1>; + uart3_default: uart3-default-state { + cts-pins { + pins = "gpio8"; + function = "qup3"; + drive-strength = <2>; + bias-bus-hold; + }; + + rts-pins { + pins = "gpio9"; + function = "qup3"; + drive-strength = <2>; + bias-disable; + }; + + tx-pins { + pins = "gpio10"; + function = "qup3"; + drive-strength = <2>; + bias-disable; + }; + + rx-pins { + pins = "gpio11"; + function = "qup3"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + uart3_sleep: uart3-sleep-state { + cts-pins { + pins = "gpio8"; + function = "gpio"; + drive-strength = <2>; + bias-bus-hold; + }; + + rts-pins { + pins = "gpio9"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + + tx-pins { + pins = "gpio10"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + + rx-pins { + pins = "gpio11"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + lt9611_rst_pin: lt9611-rst-state { pins = "gpio41"; function = "gpio"; @@ -508,6 +579,26 @@ }; }; +&uart3 { + interrupts-extended = <&intc GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH>, + <&tlmm 11 IRQ_TYPE_LEVEL_HIGH>; + pinctrl-0 = <&uart3_default>; + pinctrl-1 = <&uart3_sleep>; + pinctrl-names = "default", "sleep"; + status = "okay"; + + bluetooth { + compatible = "qcom,wcn3988-bt"; + + vddio-supply = <&vreg_l9a_1p8>; + vddxo-supply = <&vreg_l16a_1p3>; + vddrf-supply = <&vreg_l17a_1p3>; + vddch0-supply = <&vreg_l23a_3p3>; + enable-gpios = <&tlmm 87 GPIO_ACTIVE_HIGH>; + max-speed = <3200000>; + }; +}; + &uart4 { status = "okay"; }; @@ -518,7 +609,6 @@ &usb_dwc3 { maximum-speed = "super-speed"; - dr_mode = "peripheral"; }; &usb_hsphy { @@ -536,6 +626,16 @@ status = "okay"; }; +&wifi { + vdd-0.8-cx-mx-supply = <&vreg_l8a_0p664>; + vdd-1.8-xo-supply = <&vreg_l16a_1p3>; + vdd-1.3-rfa-supply = <&vreg_l17a_1p3>; + vdd-3.3-ch0-supply = <&vreg_l23a_3p3>; + qcom,ath10k-calibration-variant = "Thundercomm_RB2"; + + status = "okay"; +}; + &xo_board { clock-frequency = <19200000>; }; diff --git a/arch/arm64/boot/dts/qcom/qrb5165-rb5-vision-mezzanine.dts b/arch/arm64/boot/dts/qcom/qrb5165-rb5-vision-mezzanine.dts index bb149e577914ed..edc0e42ee01735 100644 --- a/arch/arm64/boot/dts/qcom/qrb5165-rb5-vision-mezzanine.dts +++ b/arch/arm64/boot/dts/qcom/qrb5165-rb5-vision-mezzanine.dts @@ -46,7 +46,7 @@ assigned-clocks = <&camcc CAM_CC_MCLK2_CLK>; assigned-clock-rates = <24000000>; - dovdd-supply = <&vreg_l7f_1p8>; + dovdd-supply = <&vreg_l7f_1p8>; avdd-supply = <&vdc_5v>; dvdd-supply = <&vdc_5v>; diff --git a/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts b/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts index c8cd40a462a3f5..cd0db4f31d4af9 100644 --- a/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts +++ b/arch/arm64/boot/dts/qcom/qrb5165-rb5.dts @@ -23,6 +23,7 @@ aliases { serial0 = &uart12; + serial1 = &uart6; sdhc2 = &sdhc_2; }; @@ -64,8 +65,8 @@ function = LED_FUNCTION_INDICATOR; color = ; gpios = <&pm8150_gpios 10 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "panic-indicator"; default-state = "off"; + panic-indicator; }; led-wlan { @@ -1263,6 +1264,14 @@ "HST_WLAN_UART_TX", "HST_WLAN_UART_RX"; + bt_en_state: bt-default-state { + pins = "gpio21"; + function = "gpio"; + drive-strength = <16>; + output-low; + bias-pull-up; + }; + lt9611_irq_pin: lt9611-irq-state { pins = "gpio63"; function = "gpio"; @@ -1296,6 +1305,26 @@ }; }; +&uart6 { + status = "okay"; + + bluetooth { + compatible = "qcom,qca6390-bt"; + + pinctrl-names = "default"; + pinctrl-0 = <&bt_en_state>; + + enable-gpios = <&tlmm 21 GPIO_ACTIVE_HIGH>; + + vddio-supply = <&vreg_s4a_1p8>; + vddpmu-supply = <&vreg_s2f_0p95>; + vddaon-supply = <&vreg_s6a_0p95>; + vddrfa0p9-supply = <&vreg_s2f_0p95>; + vddrfa1p3-supply = <&vreg_s8c_1p3>; + vddrfa1p9-supply = <&vreg_s5a_1p9>; + }; +}; + &uart12 { status = "okay"; }; @@ -1425,7 +1454,7 @@ altmodes { displayport { - svid = <0xff01>; + svid = /bits/ 16 <0xff01>; vdo = <0x00001c46>; }; }; diff --git a/arch/arm64/boot/dts/qcom/sa8775p-ride.dts b/arch/arm64/boot/dts/qcom/sa8775p-ride.dts index 9760bb4b468c4e..26ad05bd3b3ff0 100644 --- a/arch/arm64/boot/dts/qcom/sa8775p-ride.dts +++ b/arch/arm64/boot/dts/qcom/sa8775p-ride.dts @@ -461,6 +461,11 @@ "ANALOG_PON_OPT"; }; +&pmm8654au_0_pon_resin { + linux,code = ; + status = "okay"; +}; + &pmm8654au_1_gpios { gpio-line-names = "PMIC_C_ID0", "PMIC_C_ID1", diff --git a/arch/arm64/boot/dts/qcom/sa8775p.dtsi b/arch/arm64/boot/dts/qcom/sa8775p.dtsi index b6a93b11cbbd4e..a7eaca33d32644 100644 --- a/arch/arm64/boot/dts/qcom/sa8775p.dtsi +++ b/arch/arm64/boot/dts/qcom/sa8775p.dtsi @@ -1487,6 +1487,11 @@ }; }; + rng: rng@10d2000 { + compatible = "qcom,sa8775p-trng", "qcom,trng"; + reg = <0 0x010d2000 0 0x1000>; + }; + ufs_mem_hc: ufs@1d84000 { compatible = "qcom,sa8775p-ufshc", "qcom,ufshc", "jedec,ufs-2.0"; reg = <0x0 0x01d84000 0x0 0x3000>; @@ -1610,8 +1615,8 @@ assigned-clock-rates = <19200000>, <200000000>; interrupts-extended = <&intc GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>, - <&pdc 14 IRQ_TYPE_EDGE_RISING>, - <&pdc 15 IRQ_TYPE_EDGE_RISING>, + <&pdc 14 IRQ_TYPE_EDGE_BOTH>, + <&pdc 15 IRQ_TYPE_EDGE_BOTH>, <&pdc 12 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "pwr_event", "dp_hs_phy_irq", @@ -1697,8 +1702,8 @@ assigned-clock-rates = <19200000>, <200000000>; interrupts-extended = <&intc GIC_SPI 352 IRQ_TYPE_LEVEL_HIGH>, - <&pdc 8 IRQ_TYPE_EDGE_RISING>, - <&pdc 7 IRQ_TYPE_EDGE_RISING>, + <&pdc 8 IRQ_TYPE_EDGE_BOTH>, + <&pdc 7 IRQ_TYPE_EDGE_BOTH>, <&pdc 13 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "pwr_event", "dp_hs_phy_irq", @@ -1760,8 +1765,8 @@ assigned-clock-rates = <19200000>, <200000000>; interrupts-extended = <&intc GIC_SPI 444 IRQ_TYPE_LEVEL_HIGH>, - <&pdc 10 IRQ_TYPE_EDGE_RISING>, - <&pdc 9 IRQ_TYPE_EDGE_RISING>; + <&pdc 10 IRQ_TYPE_EDGE_BOTH>, + <&pdc 9 IRQ_TYPE_EDGE_BOTH>; interrupt-names = "pwr_event", "dp_hs_phy_irq", "dm_hs_phy_irq"; @@ -1910,6 +1915,50 @@ interrupt-controller; }; + tsens2: thermal-sensor@c251000 { + compatible = "qcom,sa8775p-tsens", "qcom,tsens-v2"; + reg = <0x0 0x0c251000 0x0 0x1ff>, + <0x0 0x0c224000 0x0 0x8>; + interrupts = , + ; + #qcom,sensors = <13>; + interrupt-names = "uplow", "critical"; + #thermal-sensor-cells = <1>; + }; + + tsens3: thermal-sensor@c252000 { + compatible = "qcom,sa8775p-tsens", "qcom,tsens-v2"; + reg = <0x0 0x0c252000 0x0 0x1ff>, + <0x0 0x0c225000 0x0 0x8>; + interrupts = , + ; + #qcom,sensors = <13>; + interrupt-names = "uplow", "critical"; + #thermal-sensor-cells = <1>; + }; + + tsens0: thermal-sensor@c263000 { + compatible = "qcom,sa8775p-tsens", "qcom,tsens-v2"; + reg = <0x0 0x0c263000 0x0 0x1ff>, + <0x0 0x0c222000 0x0 0x8>; + interrupts = , + ; + #qcom,sensors = <12>; + interrupt-names = "uplow", "critical"; + #thermal-sensor-cells = <1>; + }; + + tsens1: thermal-sensor@c265000 { + compatible = "qcom,sa8775p-tsens", "qcom,tsens-v2"; + reg = <0x0 0x0c265000 0x0 0x1ff>, + <0x0 0x0c223000 0x0 0x8>; + interrupts = , + ; + #qcom,sensors = <12>; + interrupt-names = "uplow", "critical"; + #thermal-sensor-cells = <1>; + }; + aoss_qmp: power-management@c300000 { compatible = "qcom,sa8775p-aoss-qmp", "qcom,aoss-qmp"; reg = <0x0 0x0c300000 0x0 0x400>; @@ -1920,6 +1969,11 @@ #clock-cells = <0>; }; + sram@c3f0000 { + compatible = "qcom,rpmh-stats"; + reg = <0x0 0x0c3f0000 0x0 0x400>; + }; + spmi_bus: spmi@c440000 { compatible = "qcom,spmi-pmic-arb"; reg = <0x0 0x0c440000 0x0 0x1100>, @@ -2181,7 +2235,7 @@ compatible = "qcom,apss-wdt-sa8775p", "qcom,kpss-wdt"; reg = <0x0 0x17c10000 0x0 0x1000>; clocks = <&sleep_clk>; - interrupts = ; + interrupts = ; }; memtimer: timer@17c20000 { @@ -2401,6 +2455,1058 @@ }; }; + thermal-zones { + aoss-0-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 0>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-0-0-0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 1>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-0-1-0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 2>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-0-2-0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 3>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-0-3-0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 4>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + gpuss-0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 5>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + gpuss-1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 6>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + gpuss-2-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 7>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + audio-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 8>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + camss-0-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 9>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + pcie-0-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 10>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpuss-0-0-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens0 11>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + aoss-1-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 0>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-0-0-1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 1>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-0-1-1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 2>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-0-2-1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 3>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-0-3-1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 4>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + gpuss-3-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 5>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + gpuss-4-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 6>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + gpuss-5-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 7>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + video-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 8>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + camss-1-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 9>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + pcie-1-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 10>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpuss-0-1-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens1 11>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + aoss-2-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens2 0>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-1-0-0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens2 1>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-1-1-0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens2 2>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-1-2-0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens2 3>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-1-3-0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens2 4>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + nsp-0-0-0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens2 5>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + nsp-0-1-0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens2 6>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + nsp-0-2-0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens2 7>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + nsp-1-0-0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens2 8>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + nsp-1-1-0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens2 9>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + nsp-1-2-0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens2 10>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + ddrss-0-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens2 11>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpuss-1-0-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens2 12>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + aoss-3-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens3 0>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-1-0-1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens3 1>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-1-1-1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens3 2>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-1-2-1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens3 3>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu-1-3-1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens3 4>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + nsp-0-0-1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens3 5>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + nsp-0-1-1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens3 6>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + nsp-0-2-1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens3 7>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + nsp-1-0-1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens3 8>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + nsp-1-1-1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens3 9>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + nsp-1-2-1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + + thermal-sensors = <&tsens3 10>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + ddrss-1-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens3 11>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpuss-1-1-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&tsens3 12>; + + trips { + trip-point0 { + temperature = <105000>; + hysteresis = <5000>; + type = "passive"; + }; + + trip-point1 { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + }; + arch_timer: timer { compatible = "arm,armv8-timer"; interrupts = , @@ -2409,7 +3515,7 @@ ; }; - pcie0: pci@1c00000{ + pcie0: pcie@1c00000 { compatible = "qcom,pcie-sa8775p"; reg = <0x0 0x01c00000 0x0 0x3000>, <0x0 0x40000000 0x0 0xf20>, @@ -2509,7 +3615,7 @@ status = "disabled"; }; - pcie1: pci@1c10000{ + pcie1: pcie@1c10000 { compatible = "qcom,pcie-sa8775p"; reg = <0x0 0x01c10000 0x0 0x3000>, <0x0 0x60000000 0x0 0xf20>, diff --git a/arch/arm64/boot/dts/qcom/sc7180-acer-aspire1.dts b/arch/arm64/boot/dts/qcom/sc7180-acer-aspire1.dts index dbb48934d49950..5afcb8212f4900 100644 --- a/arch/arm64/boot/dts/qcom/sc7180-acer-aspire1.dts +++ b/arch/arm64/boot/dts/qcom/sc7180-acer-aspire1.dts @@ -3,6 +3,7 @@ /dts-v1/; #include +#include #include #include "sc7180.dtsi" @@ -129,6 +130,113 @@ pinctrl-names = "default"; }; + sound: sound { + compatible = "qcom,sc7180-qdsp6-sndcard"; + pinctrl-0 = <&pri_mi2s_active>, <&pri_mi2s_mclk_active>, <&ter_mi2s_active>; + pinctrl-names = "default"; + model = "Acer-Aspire-1"; + + audio-routing = + "Headphone Jack", "HPOL", + "Headphone Jack", "HPOR"; + + multimedia1-dai-link { + link-name = "MultiMedia1"; + + cpu { + sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA1>; + }; + }; + + multimedia2-dai-link { + link-name = "MultiMedia2"; + + cpu { + sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA2>; + }; + }; + + multimedia3-dai-link { + link-name = "MultiMedia3"; + + cpu { + sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA3>; + }; + }; + + multimedia4-dai-link { + link-name = "MultiMedia4"; + + cpu { + sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA4>; + }; + }; + + primary-rx-dai-link { + link-name = "Primary MI2S Playback"; + + cpu { + sound-dai = <&q6afedai PRIMARY_MI2S_RX>; + }; + + platform { + sound-dai = <&q6routing>; + }; + + codec { + sound-dai = <&alc5682 0>; + }; + }; + + primary-tx-dai-link { + link-name = "Primary MI2S Capture"; + + cpu { + sound-dai = <&q6afedai PRIMARY_MI2S_TX>; + }; + + platform { + sound-dai = <&q6routing>; + }; + + codec { + sound-dai = <&alc5682 0>; + }; + }; + + tertiary-rx-dai-link { + link-name = "Tertiary MI2S Playback"; + + cpu { + sound-dai = <&q6afedai TERTIARY_MI2S_RX>; + }; + + platform { + sound-dai = <&q6routing>; + }; + + codec { + sound-dai = <&max98357a>; + }; + }; + + displayport-rx-dai-link { + link-name = "DisplayPort Playback"; + + cpu { + sound-dai = <&q6afedai DISPLAY_PORT_RX>; + }; + + platform { + sound-dai = <&q6routing>; + }; + + codec { + sound-dai = <&mdss_dp>; + }; + }; + }; + reg_tp_3p3: touchpad-regulator { compatible = "regulator-fixed"; regulator-name = "tp_3p3"; @@ -209,9 +317,22 @@ AVDD-supply = <&vreg_l15a_1p8>; MICVDD-supply = <®_codec_3p3>; VBAT-supply = <®_codec_3p3>; + DBVDD-supply = <&vreg_l15a_1p8>; + LDO1-IN-supply = <&vreg_l15a_1p8>; + + /* + * NOTE: The board has a path from this codec to the + * DMIC microphones in the lid, however some of the option + * resistors are absent and the microphones are connected + * to the SoC instead. + * + * If the resistors were to be changed by the user to + * connect the codec, the following could be used: + * + * realtek,dmic1-data-pin = <1>; + * realtek,dmic1-clk-pin = <1>; + */ - realtek,dmic1-data-pin = <1>; - realtek,dmic1-clk-pin = <1>; realtek,jd-src = <1>; }; }; @@ -351,6 +472,49 @@ status = "disabled"; }; +&pm6150_rtc { + status = "okay"; +}; + +&q6afedai { + dai@16 { + reg = ; + qcom,sd-lines = <1>; + }; + + dai@17 { + reg = ; + qcom,sd-lines = <0>; + }; + + dai@20 { + reg = ; + qcom,sd-lines = <0>; + }; + + dai@104 { + reg = ; + }; +}; + +&q6asmdai { + dai@0 { + reg = <0>; + }; + + dai@1 { + reg = <1>; + }; + + dai@2 { + reg = <2>; + }; + + dai@3 { + reg = <3>; + }; +}; + &qupv3_id_0 { status = "okay"; }; @@ -359,6 +523,12 @@ status = "okay"; }; +&remoteproc_adsp { + memory-region = <&adsp_mem>; + firmware-name = "qcom/sc7180/acer/aspire1/qcadsp7180.mbn"; + status = "okay"; +}; + &remoteproc_mpss { firmware-name = "qcom/sc7180/acer/aspire1/qcmpss7180_nm.mbn"; status = "okay"; diff --git a/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom.dtsi b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom.dtsi index 0be62331f9825c..067813f5f437e6 100644 --- a/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7180-trogdor-pompom.dtsi @@ -141,7 +141,7 @@ ap_ts_pen_1v8: &i2c4 { }; &panel { - compatible = "kingdisplay,kd116n21-30nv-a010"; + compatible = "edp-panel"; }; &pen_insert { diff --git a/arch/arm64/boot/dts/qcom/sc7180.dtsi b/arch/arm64/boot/dts/qcom/sc7180.dtsi index 11f353d416b4d5..4dcaa15caef263 100644 --- a/arch/arm64/boot/dts/qcom/sc7180.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7180.dtsi @@ -2966,8 +2966,8 @@ interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, <&pdc 6 IRQ_TYPE_LEVEL_HIGH>, - <&pdc 8 IRQ_TYPE_LEVEL_HIGH>, - <&pdc 9 IRQ_TYPE_LEVEL_HIGH>; + <&pdc 8 IRQ_TYPE_EDGE_BOTH>, + <&pdc 9 IRQ_TYPE_EDGE_BOTH>; interrupt-names = "hs_phy_irq", "ss_phy_irq", "dm_hs_phy_irq", "dp_hs_phy_irq"; @@ -3100,8 +3100,12 @@ interrupt-controller; #interrupt-cells = <1>; - interconnects = <&mmss_noc MASTER_MDP0 0 &mc_virt SLAVE_EBI1 0>; - interconnect-names = "mdp0-mem"; + interconnects = <&mmss_noc MASTER_MDP0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_DISPLAY_CFG QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "mdp0-mem", + "cpu-cfg"; iommus = <&apps_smmu 0x800 0x2>; @@ -3576,7 +3580,7 @@ compatible = "qcom,apss-wdt-sc7180", "qcom,kpss-wdt"; reg = <0 0x17c10000 0 0x1000>; clocks = <&sleep_clk>; - interrupts = ; + interrupts = ; }; timer@17c20000 { diff --git a/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi b/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi index 5d462ae14ba122..c4d00a81da394e 100644 --- a/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280-chrome-common.dtsi @@ -17,6 +17,9 @@ * required by the setup for Chrome boards. */ +/delete-node/ &cdsp_mem; +/delete-node/ &gpu_zap_mem; +/delete-node/ &gpu_zap_shader; /delete-node/ &hyp_mem; /delete-node/ &xbl_mem; /delete-node/ &reserved_xbl_uefi_log; @@ -24,11 +27,6 @@ / { reserved-memory { - adsp_mem: memory@86700000 { - reg = <0x0 0x86700000 0x0 0x2800000>; - no-map; - }; - camera_mem: memory@8ad00000 { reg = <0x0 0x8ad00000 0x0 0x500000>; no-map; @@ -38,11 +36,6 @@ reg = <0x0 0x8b200000 0x0 0x500000>; no-map; }; - - wpss_mem: memory@9ae00000 { - reg = <0x0 0x9ae00000 0x0 0x1900000>; - no-map; - }; }; }; @@ -94,9 +87,31 @@ }; }; +/* Currently not used */ +&remoteproc_cdsp { + /delete-property/ memory-region; +}; + &remoteproc_wpss { - status = "okay"; + compatible = "qcom,sc7280-wpss-pil"; + clocks = <&gcc GCC_WPSS_AHB_BDG_MST_CLK>, + <&gcc GCC_WPSS_AHB_CLK>, + <&gcc GCC_WPSS_RSCP_CLK>, + <&rpmhcc RPMH_CXO_CLK>; + clock-names = "ahb_bdg", + "ahb", + "rscp", + "xo"; + + resets = <&aoss_reset AOSS_CC_WCSS_RESTART>, + <&pdc_reset PDC_WPSS_SYNC_RESET>; + reset-names = "restart", "pdc_sync"; + + qcom,halt-regs = <&tcsr_1 0x17000>; + firmware-name = "ath11k/WCN6750/hw1.0/wpss.mdt"; + + status = "okay"; }; &scm { diff --git a/arch/arm64/boot/dts/qcom/sc7280-herobrine-lte-sku.dtsi b/arch/arm64/boot/dts/qcom/sc7280-herobrine-lte-sku.dtsi index 95505549adccd5..b721a8546800cc 100644 --- a/arch/arm64/boot/dts/qcom/sc7280-herobrine-lte-sku.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280-herobrine-lte-sku.dtsi @@ -8,11 +8,6 @@ / { reserved-memory { - mpss_mem: memory@8b800000 { - reg = <0x0 0x8b800000 0x0 0xf600000>; - no-map; - }; - mba_mem: memory@9c700000 { reg = <0x0 0x9c700000 0x0 0x200000>; no-map; @@ -33,6 +28,8 @@ &remoteproc_mpss { compatible = "qcom,sc7280-mss-pil"; + reg = <0 0x04080000 0 0x10000>, <0 0x04180000 0 0x48>; + reg-names = "qdsp6", "rmb"; clocks = <&gcc GCC_MSS_CFG_AHB_CLK>, <&gcc GCC_MSS_OFFLINE_AXI_CLK>, diff --git a/arch/arm64/boot/dts/qcom/sc7280-herobrine-wifi-sku.dtsi b/arch/arm64/boot/dts/qcom/sc7280-herobrine-wifi-sku.dtsi index 2febd6126d4c84..3ebc915f0dc2f6 100644 --- a/arch/arm64/boot/dts/qcom/sc7280-herobrine-wifi-sku.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280-herobrine-wifi-sku.dtsi @@ -7,5 +7,6 @@ /* WIFI SKUs save 256M by not having modem/mba/rmtfs memory regions defined. */ +/delete-node/ &mpss_mem; /delete-node/ &remoteproc_mpss; /delete-node/ &rmtfs_mem; diff --git a/arch/arm64/boot/dts/qcom/sc7280-idp.dtsi b/arch/arm64/boot/dts/qcom/sc7280-idp.dtsi index 2ff549f4dc7a99..a0059527d9e48a 100644 --- a/arch/arm64/boot/dts/qcom/sc7280-idp.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280-idp.dtsi @@ -499,6 +499,25 @@ status = "okay"; }; +&ufs_mem_hc { + reset-gpios = <&tlmm 175 GPIO_ACTIVE_LOW>; + vcc-supply = <&vreg_l7b_2p9>; + vcc-max-microamp = <800000>; + vccq-supply = <&vreg_l9b_1p2>; + vccq-max-microamp = <900000>; + vccq2-supply = <&vreg_l9b_1p2>; + vccq2-max-microamp = <900000>; + + status = "okay"; +}; + +&ufs_mem_phy { + vdda-phy-supply = <&vreg_l10c_0p8>; + vdda-pll-supply = <&vreg_l6b_1p2>; + + status = "okay"; +}; + &usb_1 { status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/sc7280.dtsi b/arch/arm64/boot/dts/qcom/sc7280.dtsi index 66f1eb83cca7e7..83b5b76ba17940 100644 --- a/arch/arm64/boot/dts/qcom/sc7280.dtsi +++ b/arch/arm64/boot/dts/qcom/sc7280.dtsi @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -91,68 +92,93 @@ #size-cells = <2>; ranges; - wlan_ce_mem: memory@4cd000 { + wlan_ce_mem: wlan-ce@4cd000 { no-map; reg = <0x0 0x004cd000 0x0 0x1000>; }; - hyp_mem: memory@80000000 { + hyp_mem: hyp@80000000 { reg = <0x0 0x80000000 0x0 0x600000>; no-map; }; - xbl_mem: memory@80600000 { + xbl_mem: xbl@80600000 { reg = <0x0 0x80600000 0x0 0x200000>; no-map; }; - aop_mem: memory@80800000 { + aop_mem: aop@80800000 { reg = <0x0 0x80800000 0x0 0x60000>; no-map; }; - aop_cmd_db_mem: memory@80860000 { + aop_cmd_db_mem: aop-cmd-db@80860000 { reg = <0x0 0x80860000 0x0 0x20000>; compatible = "qcom,cmd-db"; no-map; }; - reserved_xbl_uefi_log: memory@80880000 { + reserved_xbl_uefi_log: xbl-uefi-res@80880000 { reg = <0x0 0x80884000 0x0 0x10000>; no-map; }; - sec_apps_mem: memory@808ff000 { + sec_apps_mem: sec-apps@808ff000 { reg = <0x0 0x808ff000 0x0 0x1000>; no-map; }; - smem_mem: memory@80900000 { + smem_mem: smem@80900000 { reg = <0x0 0x80900000 0x0 0x200000>; no-map; }; - cpucp_mem: memory@80b00000 { + cpucp_mem: cpucp@80b00000 { no-map; reg = <0x0 0x80b00000 0x0 0x100000>; }; - wlan_fw_mem: memory@80c00000 { + wlan_fw_mem: wlan-fw@80c00000 { reg = <0x0 0x80c00000 0x0 0xc00000>; no-map; }; - video_mem: memory@8b200000 { + adsp_mem: adsp@86700000 { + reg = <0x0 0x86700000 0x0 0x2800000>; + no-map; + }; + + video_mem: video@8b200000 { reg = <0x0 0x8b200000 0x0 0x500000>; no-map; }; - ipa_fw_mem: memory@8b700000 { + cdsp_mem: cdsp@88f00000 { + reg = <0x0 0x88f00000 0x0 0x1e00000>; + no-map; + }; + + ipa_fw_mem: ipa-fw@8b700000 { reg = <0 0x8b700000 0 0x10000>; no-map; }; - rmtfs_mem: memory@9c900000 { + gpu_zap_mem: zap@8b71a000 { + reg = <0 0x8b71a000 0 0x2000>; + no-map; + }; + + mpss_mem: mpss@8b800000 { + reg = <0x0 0x8b800000 0x0 0xf600000>; + no-map; + }; + + wpss_mem: wpss@9ae00000 { + reg = <0x0 0x9ae00000 0x0 0x1900000>; + no-map; + }; + + rmtfs_mem: rmtfs@9c900000 { compatible = "qcom,rmtfs-mem"; reg = <0x0 0x9c900000 0x0 0x280000>; no-map; @@ -906,7 +932,7 @@ clocks = <&rpmhcc RPMH_CXO_CLK>, <&rpmhcc RPMH_CXO_CLK_A>, <&sleep_clk>, <0>, <&pcie1_phy>, - <0>, <0>, <0>, + <&ufs_mem_phy 0>, <&ufs_mem_phy 1>, <&ufs_mem_phy 2>, <&usb_1_qmpphy QMP_USB43DP_USB3_PIPE_CLK>; clock-names = "bi_tcxo", "bi_tcxo_ao", "sleep_clk", "pcie_0_pipe_clk", "pcie_1_pipe_clk", @@ -974,6 +1000,7 @@ bus-width = <8>; supports-cqe; + dma-coherent; qcom,dll-config = <0x0007642c>; qcom,ddr-config = <0x80040868>; @@ -2034,6 +2061,11 @@ }; }; + rng: rng@10d3000 { + compatible = "qcom,sc7280-trng", "qcom,trng"; + reg = <0 0x010d3000 0 0x1000>; + }; + cnoc2: interconnect@1500000 { reg = <0 0x01500000 0 0x1000>; compatible = "qcom,sc7280-cnoc2"; @@ -2126,7 +2158,7 @@ qcom,smem-state-names = "wlan-smp2p-out"; }; - pcie1: pci@1c08000 { + pcie1: pcie@1c08000 { compatible = "qcom,pcie-sc7280"; reg = <0 0x01c08000 0 0x3000>, <0 0x40000000 0 0xf1d>, @@ -2233,6 +2265,99 @@ status = "disabled"; }; + ufs_mem_hc: ufs@1d84000 { + compatible = "qcom,sc7280-ufshc", "qcom,ufshc", + "jedec,ufs-2.0"; + reg = <0x0 0x01d84000 0x0 0x3000>; + interrupts = ; + phys = <&ufs_mem_phy>; + phy-names = "ufsphy"; + lanes-per-direction = <2>; + #reset-cells = <1>; + resets = <&gcc GCC_UFS_PHY_BCR>; + reset-names = "rst"; + + power-domains = <&gcc GCC_UFS_PHY_GDSC>; + required-opps = <&rpmhpd_opp_nom>; + + iommus = <&apps_smmu 0x80 0x0>; + dma-coherent; + + interconnects = <&aggre1_noc MASTER_UFS_MEM QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &cnoc2 SLAVE_UFS_MEM_CFG QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "ufs-ddr", "cpu-ufs"; + + clocks = <&gcc GCC_UFS_PHY_AXI_CLK>, + <&gcc GCC_AGGRE_UFS_PHY_AXI_CLK>, + <&gcc GCC_UFS_PHY_AHB_CLK>, + <&gcc GCC_UFS_PHY_UNIPRO_CORE_CLK>, + <&rpmhcc RPMH_CXO_CLK>, + <&gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>, + <&gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>, + <&gcc GCC_UFS_PHY_RX_SYMBOL_1_CLK>; + clock-names = "core_clk", + "bus_aggr_clk", + "iface_clk", + "core_clk_unipro", + "ref_clk", + "tx_lane0_sync_clk", + "rx_lane0_sync_clk", + "rx_lane1_sync_clk"; + freq-table-hz = + <75000000 300000000>, + <0 0>, + <0 0>, + <75000000 300000000>, + <0 0>, + <0 0>, + <0 0>, + <0 0>; + status = "disabled"; + }; + + ufs_mem_phy: phy@1d87000 { + compatible = "qcom,sc7280-qmp-ufs-phy"; + reg = <0x0 0x01d87000 0x0 0xe00>; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&gcc GCC_UFS_PHY_PHY_AUX_CLK>, + <&gcc GCC_UFS_1_CLKREF_EN>; + clock-names = "ref", "ref_aux", "qref"; + + power-domains = <&rpmhpd SC7280_MX>; + + resets = <&ufs_mem_hc 0>; + reset-names = "ufsphy"; + + #clock-cells = <1>; + #phy-cells = <0>; + + status = "disabled"; + }; + + cryptobam: dma-controller@1dc4000 { + compatible = "qcom,bam-v1.7.4", "qcom,bam-v1.7.0"; + reg = <0x0 0x01dc4000 0x0 0x28000>; + interrupts = ; + #dma-cells = <1>; + iommus = <&apps_smmu 0x4e4 0x0011>, + <&apps_smmu 0x4e6 0x0011>; + qcom,ee = <0>; + qcom,controlled-remotely; + }; + + crypto: crypto@1dfa000 { + compatible = "qcom,sc7280-qce", "qcom,sm8150-qce", "qcom,qce"; + reg = <0x0 0x01dfa000 0x0 0x6000>; + dmas = <&cryptobam 4>, <&cryptobam 5>; + dma-names = "rx", "tx"; + iommus = <&apps_smmu 0x4e4 0x0011>, + <&apps_smmu 0x4e4 0x0011>; + interconnects = <&aggre2_noc MASTER_CRYPTO 0 &mc_virt SLAVE_EBI1 0>; + interconnect-names = "memory"; + }; + ipa: ipa@1e40000 { compatible = "qcom,sc7280-ipa"; @@ -2598,7 +2723,8 @@ "cx_mem", "cx_dbgc"; interrupts = ; - iommus = <&adreno_smmu 0 0x401>; + iommus = <&adreno_smmu 0 0x400>, + <&adreno_smmu 1 0x400>; operating-points-v2 = <&gpu_opp_table>; qcom,gmu = <&gmu>; interconnects = <&gem_noc MASTER_GFX3D 0 &mc_virt SLAVE_EBI1 0>; @@ -2608,6 +2734,10 @@ nvmem-cells = <&gpu_speed_bin>; nvmem-cell-names = "speed_bin"; + gpu_zap_shader: zap-shader { + memory-region = <&gpu_zap_mem>; + }; + gpu_opp_table: opp-table { compatible = "operating-points-v2"; @@ -2615,14 +2745,14 @@ opp-hz = /bits/ 64 <315000000>; opp-level = ; opp-peak-kBps = <1804000>; - opp-supported-hw = <0x03>; + opp-supported-hw = <0x07>; }; opp-450000000 { opp-hz = /bits/ 64 <450000000>; opp-level = ; opp-peak-kBps = <4068000>; - opp-supported-hw = <0x03>; + opp-supported-hw = <0x07>; }; /* Only applicable for SKUs which has 550Mhz as Fmax */ @@ -2637,28 +2767,28 @@ opp-hz = /bits/ 64 <550000000>; opp-level = ; opp-peak-kBps = <6832000>; - opp-supported-hw = <0x02>; + opp-supported-hw = <0x06>; }; opp-608000000 { opp-hz = /bits/ 64 <608000000>; opp-level = ; opp-peak-kBps = <8368000>; - opp-supported-hw = <0x02>; + opp-supported-hw = <0x06>; }; opp-700000000 { opp-hz = /bits/ 64 <700000000>; opp-level = ; opp-peak-kBps = <8532000>; - opp-supported-hw = <0x02>; + opp-supported-hw = <0x06>; }; opp-812000000 { opp-hz = /bits/ 64 <812000000>; opp-level = ; opp-peak-kBps = <8532000>; - opp-supported-hw = <0x02>; + opp-supported-hw = <0x06>; }; opp-840000000 { @@ -2772,12 +2902,12 @@ "gpu_cc_hub_aon_clk"; power-domains = <&gpucc GPU_CC_CX_GDSC>; + dma-coherent; }; remoteproc_mpss: remoteproc@4080000 { compatible = "qcom,sc7280-mpss-pas"; - reg = <0 0x04080000 0 0x10000>, <0 0x04180000 0 0x48>; - reg-names = "qdsp6", "rmb"; + reg = <0 0x04080000 0 0x10000>; interrupts-extended = <&intc GIC_SPI 264 IRQ_TYPE_EDGE_RISING>, <&modem_smp2p_in 0 IRQ_TYPE_EDGE_RISING>, @@ -3329,6 +3459,7 @@ operating-points-v2 = <&sdhc2_opp_table>; bus-width = <4>; + dma-coherent; qcom,dll-config = <0x0007642c>; @@ -3399,6 +3530,32 @@ #clock-cells = <1>; #phy-cells = <1>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + usb_dp_qmpphy_out: endpoint { + }; + }; + + port@1 { + reg = <1>; + + usb_dp_qmpphy_usb_ss_in: endpoint { + }; + }; + + port@2 { + reg = <2>; + + usb_dp_qmpphy_dp_in: endpoint { + }; + }; + }; }; usb_2: usb@8cf8800 { @@ -3426,8 +3583,8 @@ assigned-clock-rates = <19200000>, <200000000>; interrupts-extended = <&intc GIC_SPI 240 IRQ_TYPE_LEVEL_HIGH>, - <&pdc 12 IRQ_TYPE_EDGE_RISING>, - <&pdc 13 IRQ_TYPE_EDGE_RISING>; + <&pdc 12 IRQ_TYPE_EDGE_BOTH>, + <&pdc 13 IRQ_TYPE_EDGE_BOTH>; interrupt-names = "hs_phy_irq", "dp_hs_phy_irq", "dm_hs_phy_irq"; @@ -3479,8 +3636,77 @@ status = "disabled"; }; + remoteproc_adsp: remoteproc@3700000 { + compatible = "qcom,sc7280-adsp-pas"; + reg = <0 0x03700000 0 0x100>; + + interrupts-extended = <&pdc 6 IRQ_TYPE_LEVEL_HIGH>, + <&adsp_smp2p_in 0 IRQ_TYPE_EDGE_RISING>, + <&adsp_smp2p_in 1 IRQ_TYPE_EDGE_RISING>, + <&adsp_smp2p_in 2 IRQ_TYPE_EDGE_RISING>, + <&adsp_smp2p_in 3 IRQ_TYPE_EDGE_RISING>, + <&adsp_smp2p_in 7 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog", "fatal", "ready", "handover", + "stop-ack", "shutdown-ack"; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "xo"; + + power-domains = <&rpmhpd SC7280_LCX>, + <&rpmhpd SC7280_LMX>; + power-domain-names = "lcx", "lmx"; + + memory-region = <&adsp_mem>; + + qcom,qmp = <&aoss_qmp>; + + qcom,smem-states = <&adsp_smp2p_out 0>; + qcom,smem-state-names = "stop"; + + status = "disabled"; + + glink-edge { + interrupts-extended = <&ipcc IPCC_CLIENT_LPASS + IPCC_MPROC_SIGNAL_GLINK_QMP + IRQ_TYPE_EDGE_RISING>; + + mboxes = <&ipcc IPCC_CLIENT_LPASS + IPCC_MPROC_SIGNAL_GLINK_QMP>; + + label = "lpass"; + qcom,remote-pid = <2>; + + fastrpc { + compatible = "qcom,fastrpc"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + label = "adsp"; + qcom,non-secure-domain; + #address-cells = <1>; + #size-cells = <0>; + + compute-cb@3 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <3>; + iommus = <&apps_smmu 0x1803 0x0>; + }; + + compute-cb@4 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <4>; + iommus = <&apps_smmu 0x1804 0x0>; + }; + + compute-cb@5 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <5>; + iommus = <&apps_smmu 0x1805 0x0>; + }; + }; + }; + }; + remoteproc_wpss: remoteproc@8a00000 { - compatible = "qcom,sc7280-wpss-pil"; + compatible = "qcom,sc7280-wpss-pas"; reg = <0 0x08a00000 0 0x10000>; interrupts-extended = <&intc GIC_SPI 587 IRQ_TYPE_EDGE_RISING>, @@ -3492,12 +3718,8 @@ interrupt-names = "wdog", "fatal", "ready", "handover", "stop-ack", "shutdown-ack"; - clocks = <&gcc GCC_WPSS_AHB_BDG_MST_CLK>, - <&gcc GCC_WPSS_AHB_CLK>, - <&gcc GCC_WPSS_RSCP_CLK>, - <&rpmhcc RPMH_CXO_CLK>; - clock-names = "ahb_bdg", "ahb", - "rscp", "xo"; + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "xo"; power-domains = <&rpmhpd SC7280_CX>, <&rpmhpd SC7280_MX>; @@ -3510,11 +3732,6 @@ qcom,smem-states = <&wpss_smp2p_out 0>; qcom,smem-state-names = "stop"; - resets = <&aoss_reset AOSS_CC_WCSS_RESTART>, - <&pdc_reset PDC_WPSS_SYNC_RESET>; - reset-names = "restart", "pdc_sync"; - - qcom,halt-regs = <&tcsr_1 0x17000>; status = "disabled"; @@ -3656,6 +3873,144 @@ qcom,bcm-voters = <&apps_bcm_voter>; }; + remoteproc_cdsp: remoteproc@a300000 { + compatible = "qcom,sc7280-cdsp-pas"; + reg = <0 0x0a300000 0 0x10000>; + + interrupts-extended = <&intc GIC_SPI 578 IRQ_TYPE_LEVEL_HIGH>, + <&cdsp_smp2p_in 0 IRQ_TYPE_EDGE_RISING>, + <&cdsp_smp2p_in 1 IRQ_TYPE_EDGE_RISING>, + <&cdsp_smp2p_in 2 IRQ_TYPE_EDGE_RISING>, + <&cdsp_smp2p_in 3 IRQ_TYPE_EDGE_RISING>, + <&cdsp_smp2p_in 7 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog", "fatal", "ready", "handover", + "stop-ack", "shutdown-ack"; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "xo"; + + power-domains = <&rpmhpd SC7280_CX>, + <&rpmhpd SC7280_MX>; + power-domain-names = "cx", "mx"; + + interconnects = <&nsp_noc MASTER_CDSP_PROC 0 &mc_virt SLAVE_EBI1 0>; + + memory-region = <&cdsp_mem>; + + qcom,qmp = <&aoss_qmp>; + + qcom,smem-states = <&cdsp_smp2p_out 0>; + qcom,smem-state-names = "stop"; + + status = "disabled"; + + glink-edge { + interrupts-extended = <&ipcc IPCC_CLIENT_CDSP + IPCC_MPROC_SIGNAL_GLINK_QMP + IRQ_TYPE_EDGE_RISING>; + mboxes = <&ipcc IPCC_CLIENT_CDSP + IPCC_MPROC_SIGNAL_GLINK_QMP>; + + label = "cdsp"; + qcom,remote-pid = <5>; + + fastrpc { + compatible = "qcom,fastrpc"; + qcom,glink-channels = "fastrpcglink-apps-dsp"; + label = "cdsp"; + qcom,non-secure-domain; + #address-cells = <1>; + #size-cells = <0>; + + compute-cb@1 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <1>; + iommus = <&apps_smmu 0x11a1 0x0420>, + <&apps_smmu 0x1181 0x0420>; + }; + + compute-cb@2 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <2>; + iommus = <&apps_smmu 0x11a2 0x0420>, + <&apps_smmu 0x1182 0x0420>; + }; + + compute-cb@3 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <3>; + iommus = <&apps_smmu 0x11a3 0x0420>, + <&apps_smmu 0x1183 0x0420>; + }; + + compute-cb@4 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <4>; + iommus = <&apps_smmu 0x11a4 0x0420>, + <&apps_smmu 0x1184 0x0420>; + }; + + compute-cb@5 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <5>; + iommus = <&apps_smmu 0x11a5 0x0420>, + <&apps_smmu 0x1185 0x0420>; + }; + + compute-cb@6 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <6>; + iommus = <&apps_smmu 0x11a6 0x0420>, + <&apps_smmu 0x1186 0x0420>; + }; + + compute-cb@7 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <7>; + iommus = <&apps_smmu 0x11a7 0x0420>, + <&apps_smmu 0x1187 0x0420>; + }; + + compute-cb@8 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <8>; + iommus = <&apps_smmu 0x11a8 0x0420>, + <&apps_smmu 0x1188 0x0420>; + }; + + /* note: secure cb9 in downstream */ + + compute-cb@11 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <11>; + iommus = <&apps_smmu 0x11ab 0x0420>, + <&apps_smmu 0x118b 0x0420>; + }; + + compute-cb@12 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <12>; + iommus = <&apps_smmu 0x11ac 0x0420>, + <&apps_smmu 0x118c 0x0420>; + }; + + compute-cb@13 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <13>; + iommus = <&apps_smmu 0x11ad 0x0420>, + <&apps_smmu 0x118d 0x0420>; + }; + + compute-cb@14 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <14>; + iommus = <&apps_smmu 0x11ae 0x0420>, + <&apps_smmu 0x118e 0x0420>; + }; + }; + }; + }; + usb_1: usb@a6f8800 { compatible = "qcom,sc7280-dwc3", "qcom,dwc3"; reg = <0 0x0a6f8800 0 0x400>; @@ -3681,9 +4036,9 @@ assigned-clock-rates = <19200000>, <200000000>; interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, - <&pdc 14 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 14 IRQ_TYPE_EDGE_BOTH>, <&pdc 15 IRQ_TYPE_EDGE_BOTH>, - <&pdc 17 IRQ_TYPE_EDGE_BOTH>; + <&pdc 17 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "hs_phy_irq", "dp_hs_phy_irq", "dm_hs_phy_irq", @@ -3793,6 +4148,86 @@ #power-domain-cells = <1>; }; + cci0: cci@ac4a000 { + compatible = "qcom,sc7280-cci", "qcom,msm8996-cci"; + reg = <0 0x0ac4a000 0 0x1000>; + interrupts = ; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + + clocks = <&camcc CAM_CC_CAMNOC_AXI_CLK>, + <&camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&camcc CAM_CC_CPAS_AHB_CLK>, + <&camcc CAM_CC_CCI_0_CLK>, + <&camcc CAM_CC_CCI_0_CLK_SRC>; + clock-names = "camnoc_axi", + "slow_ahb_src", + "cpas_ahb", + "cci", + "cci_src"; + pinctrl-0 = <&cci0_default &cci1_default>; + pinctrl-1 = <&cci0_sleep &cci1_sleep>; + pinctrl-names = "default", "sleep"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + + cci0_i2c0: i2c-bus@0 { + reg = <0>; + clock-frequency = <1000000>; + #address-cells = <1>; + #size-cells = <0>; + }; + + cci0_i2c1: i2c-bus@1 { + reg = <1>; + clock-frequency = <1000000>; + #address-cells = <1>; + #size-cells = <0>; + }; + }; + + cci1: cci@ac4b000 { + compatible = "qcom,sc7280-cci", "qcom,msm8996-cci"; + reg = <0 0x0ac4b000 0 0x1000>; + interrupts = ; + power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>; + + clocks = <&camcc CAM_CC_CAMNOC_AXI_CLK>, + <&camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&camcc CAM_CC_CPAS_AHB_CLK>, + <&camcc CAM_CC_CCI_1_CLK>, + <&camcc CAM_CC_CCI_1_CLK_SRC>; + clock-names = "camnoc_axi", + "slow_ahb_src", + "cpas_ahb", + "cci", + "cci_src"; + pinctrl-0 = <&cci2_default &cci3_default>; + pinctrl-1 = <&cci2_sleep &cci3_sleep>; + pinctrl-names = "default", "sleep"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + + cci1_i2c0: i2c-bus@0 { + reg = <0>; + clock-frequency = <1000000>; + #address-cells = <1>; + #size-cells = <0>; + }; + + cci1_i2c1: i2c-bus@1 { + reg = <1>; + clock-frequency = <1000000>; + #address-cells = <1>; + #size-cells = <0>; + }; + }; + camcc: clock-controller@ad00000 { compatible = "qcom,sc7280-camcc"; reg = <0 0x0ad00000 0 0x10000>; @@ -3847,8 +4282,12 @@ interrupt-controller; #interrupt-cells = <1>; - interconnects = <&mmss_noc MASTER_MDP0 0 &mc_virt SLAVE_EBI1 0>; - interconnect-names = "mdp0-mem"; + interconnects = <&mmss_noc MASTER_MDP0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &cnoc2 SLAVE_DISPLAY_CFG QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "mdp0-mem", + "cpu-cfg"; iommus = <&apps_smmu 0x900 0x402>; @@ -4298,6 +4737,62 @@ gpio-ranges = <&tlmm 0 0 175>; wakeup-parent = <&pdc>; + cci0_default: cci0-default-state { + pins = "gpio69", "gpio70"; + function = "cci_i2c"; + drive-strength = <2>; + bias-pull-up; + }; + + cci0_sleep: cci0-sleep-state { + pins = "gpio69", "gpio70"; + function = "cci_i2c"; + drive-strength = <2>; + bias-pull-down; + }; + + cci1_default: cci1-default-state { + pins = "gpio71", "gpio72"; + function = "cci_i2c"; + drive-strength = <2>; + bias-pull-up; + }; + + cci1_sleep: cci1-sleep-state { + pins = "gpio71", "gpio72"; + function = "cci_i2c"; + drive-strength = <2>; + bias-pull-down; + }; + + cci2_default: cci2-default-state { + pins = "gpio73", "gpio74"; + function = "cci_i2c"; + drive-strength = <2>; + bias-pull-up; + }; + + cci2_sleep: cci2-sleep-state { + pins = "gpio73", "gpio74"; + function = "cci_i2c"; + drive-strength = <2>; + bias-pull-down; + }; + + cci3_default: cci3-default-state { + pins = "gpio75", "gpio76"; + function = "cci_i2c"; + drive-strength = <2>; + bias-pull-up; + }; + + cci3_sleep: cci3-sleep-state { + pins = "gpio75", "gpio76"; + function = "cci_i2c"; + drive-strength = <2>; + bias-pull-down; + }; + dp_hot_plug_det: dp-hot-plug-det-state { pins = "gpio47"; function = "dp_hot"; @@ -5222,7 +5717,7 @@ compatible = "qcom,apss-wdt-sc7280", "qcom,kpss-wdt"; reg = <0 0x17c10000 0 0x1000>; clocks = <&sleep_clk>; - interrupts = ; + interrupts = ; status = "reserved"; /* Owned by Gunyah hyp */ }; diff --git a/arch/arm64/boot/dts/qcom/sc8180x-lenovo-flex-5g.dts b/arch/arm64/boot/dts/qcom/sc8180x-lenovo-flex-5g.dts index 3ea07d094b607f..0c22f3efec20c8 100644 --- a/arch/arm64/boot/dts/qcom/sc8180x-lenovo-flex-5g.dts +++ b/arch/arm64/boot/dts/qcom/sc8180x-lenovo-flex-5g.dts @@ -452,8 +452,8 @@ }; &pcie3 { - perst-gpio = <&tlmm 178 GPIO_ACTIVE_LOW>; - wake-gpio = <&tlmm 180 GPIO_ACTIVE_HIGH>; + perst-gpios = <&tlmm 178 GPIO_ACTIVE_LOW>; + wake-gpios = <&tlmm 180 GPIO_ACTIVE_HIGH>; pinctrl-0 = <&pcie3_default_state>; pinctrl-names = "default"; diff --git a/arch/arm64/boot/dts/qcom/sc8180x-primus.dts b/arch/arm64/boot/dts/qcom/sc8180x-primus.dts index fd2fab4895b390..bfee60c93ccce8 100644 --- a/arch/arm64/boot/dts/qcom/sc8180x-primus.dts +++ b/arch/arm64/boot/dts/qcom/sc8180x-primus.dts @@ -43,7 +43,7 @@ pinctrl-0 = <&hall_int_active_state>; lid-switch { - gpios = <&tlmm 121 GPIO_ACTIVE_HIGH>; + gpios = <&tlmm 121 GPIO_ACTIVE_LOW>; linux,input-type = ; linux,code = ; wakeup-source; @@ -386,12 +386,18 @@ regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; regulator-initial-mode = ; + regulator-allowed-modes = ; + regulator-allow-set-load; }; vreg_l10e_2p9: ldo10 { regulator-min-microvolt = <2904000>; regulator-max-microvolt = <2904000>; regulator-initial-mode = ; + regulator-allowed-modes = ; + regulator-allow-set-load; }; vreg_l12e: ldo12 { @@ -531,8 +537,8 @@ }; &pcie1 { - perst-gpio = <&tlmm 175 GPIO_ACTIVE_LOW>; - wake-gpio = <&tlmm 177 GPIO_ACTIVE_HIGH>; + perst-gpios = <&tlmm 175 GPIO_ACTIVE_LOW>; + wake-gpios = <&tlmm 177 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; pinctrl-0 = <&pcie2_default_state>; diff --git a/arch/arm64/boot/dts/qcom/sc8180x.dtsi b/arch/arm64/boot/dts/qcom/sc8180x.dtsi index a34f438ef2d9a4..0430d99091e30a 100644 --- a/arch/arm64/boot/dts/qcom/sc8180x.dtsi +++ b/arch/arm64/boot/dts/qcom/sc8180x.dtsi @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -1684,7 +1685,7 @@ qcom,bcm-voters = <&apps_bcm_voter>; }; - pcie0: pci@1c00000 { + pcie0: pcie@1c00000 { compatible = "qcom,pcie-sc8180x"; reg = <0 0x01c00000 0 0x3000>, <0 0x60000000 0 0xf1d>, @@ -1736,7 +1737,6 @@ assigned-clocks = <&gcc GCC_PCIE_0_AUX_CLK>; assigned-clock-rates = <19200000>; - iommus = <&apps_smmu 0x1d80 0x7f>; iommu-map = <0x0 &apps_smmu 0x1d80 0x1>, <0x100 &apps_smmu 0x1d81 0x1>; @@ -1751,6 +1751,7 @@ phys = <&pcie0_phy>; phy-names = "pciephy"; + dma-coherent; status = "disabled"; }; @@ -1761,7 +1762,7 @@ clocks = <&gcc GCC_PCIE_PHY_AUX_CLK>, <&gcc GCC_PCIE_0_CFG_AHB_CLK>, <&gcc GCC_PCIE_0_CLKREF_CLK>, - <&gcc GCC_PCIE1_PHY_REFGEN_CLK>, + <&gcc GCC_PCIE0_PHY_REFGEN_CLK>, <&gcc GCC_PCIE_0_PIPE_CLK>; clock-names = "aux", "cfg_ahb", @@ -1781,7 +1782,7 @@ status = "disabled"; }; - pcie3: pci@1c08000 { + pcie3: pcie@1c08000 { compatible = "qcom,pcie-sc8180x"; reg = <0 0x01c08000 0 0x3000>, <0 0x40000000 0 0xf1d>, @@ -1833,7 +1834,6 @@ assigned-clocks = <&gcc GCC_PCIE_3_AUX_CLK>; assigned-clock-rates = <19200000>; - iommus = <&apps_smmu 0x1e00 0x7f>; iommu-map = <0x0 &apps_smmu 0x1e00 0x1>, <0x100 &apps_smmu 0x1e01 0x1>; @@ -1848,6 +1848,7 @@ phys = <&pcie3_phy>; phy-names = "pciephy"; + dma-coherent; status = "disabled"; }; @@ -1858,7 +1859,7 @@ clocks = <&gcc GCC_PCIE_PHY_AUX_CLK>, <&gcc GCC_PCIE_3_CFG_AHB_CLK>, <&gcc GCC_PCIE_3_CLKREF_CLK>, - <&gcc GCC_PCIE2_PHY_REFGEN_CLK>, + <&gcc GCC_PCIE3_PHY_REFGEN_CLK>, <&gcc GCC_PCIE_3_PIPE_CLK>; clock-names = "aux", "cfg_ahb", @@ -1879,7 +1880,7 @@ status = "disabled"; }; - pcie1: pci@1c10000 { + pcie1: pcie@1c10000 { compatible = "qcom,pcie-sc8180x"; reg = <0 0x01c10000 0 0x3000>, <0 0x68000000 0 0xf1d>, @@ -1931,7 +1932,6 @@ assigned-clocks = <&gcc GCC_PCIE_1_AUX_CLK>; assigned-clock-rates = <19200000>; - iommus = <&apps_smmu 0x1c80 0x7f>; iommu-map = <0x0 &apps_smmu 0x1c80 0x1>, <0x100 &apps_smmu 0x1c81 0x1>; @@ -1946,6 +1946,7 @@ phys = <&pcie1_phy>; phy-names = "pciephy"; + dma-coherent; status = "disabled"; }; @@ -1977,7 +1978,7 @@ status = "disabled"; }; - pcie2: pci@1c18000 { + pcie2: pcie@1c18000 { compatible = "qcom,pcie-sc8180x"; reg = <0 0x01c18000 0 0x3000>, <0 0x70000000 0 0xf1d>, @@ -2029,7 +2030,6 @@ assigned-clocks = <&gcc GCC_PCIE_2_AUX_CLK>; assigned-clock-rates = <19200000>; - iommus = <&apps_smmu 0x1d00 0x7f>; iommu-map = <0x0 &apps_smmu 0x1d00 0x1>, <0x100 &apps_smmu 0x1d01 0x1>; @@ -2044,6 +2044,7 @@ phys = <&pcie2_phy>; phy-names = "pciephy"; + dma-coherent; status = "disabled"; }; @@ -2062,7 +2063,7 @@ "refgen", "pipe"; #clock-cells = <0>; - clock-output-names = "pcie_3_pipe_clk"; + clock-output-names = "pcie_2_pipe_clk"; #phy-cells = <0>; @@ -2114,6 +2115,14 @@ <0 0>, <0 0>; + power-domains = <&gcc UFS_PHY_GDSC>; + + interconnects = <&aggre1_noc MASTER_UFS_MEM QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI_CH0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_AMPSS_M0 QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_UFS_MEM_0_CFG QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "ufs-ddr", "cpu-ufs"; + status = "disabled"; }; @@ -2548,10 +2557,10 @@ usb_prim: usb@a6f8800 { compatible = "qcom,sc8180x-dwc3", "qcom,dwc3"; reg = <0 0x0a6f8800 0 0x400>; - interrupts = , - , - , - ; + interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 6 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 8 IRQ_TYPE_EDGE_BOTH>, + <&pdc 9 IRQ_TYPE_EDGE_BOTH>; interrupt-names = "hs_phy_irq", "ss_phy_irq", "dm_hs_phy_irq", @@ -2622,10 +2631,10 @@ "xo"; resets = <&gcc GCC_USB30_SEC_BCR>; power-domains = <&gcc USB30_SEC_GDSC>; - interrupts = , - , - , - ; + interrupts-extended = <&intc GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 7 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 10 IRQ_TYPE_EDGE_BOTH>, + <&pdc 11 IRQ_TYPE_EDGE_BOTH>; interrupt-names = "hs_phy_irq", "ss_phy_irq", "dm_hs_phy_irq", "dp_hs_phy_irq"; @@ -2704,11 +2713,15 @@ clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, <&gcc GCC_DISP_HF_AXI_CLK>, <&dispcc DISP_CC_MDSS_MDP_CLK>, - <&dispcc DISP_CC_MDSS_VSYNC_CLK>; + <&dispcc DISP_CC_MDSS_VSYNC_CLK>, + <&dispcc DISP_CC_MDSS_ROT_CLK>, + <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>; clock-names = "iface", "bus", "core", - "vsync"; + "vsync", + "rot", + "lut"; assigned-clocks = <&dispcc DISP_CC_MDSS_MDP_CLK>, <&dispcc DISP_CC_MDSS_VSYNC_CLK>; @@ -3117,8 +3130,6 @@ phys = <&edp_phy>; phy-names = "dp"; - #sound-dai-cells = <0>; - operating-points-v2 = <&edp_opp_table>; power-domains = <&rpmhpd SC8180X_MMCX>; @@ -3418,10 +3429,12 @@ reg = <0x0 0x17a00000 0x0 0x10000>, /* GICD */ <0x0 0x17a60000 0x0 0x100000>; /* GICR * 8 */ interrupts = ; + #redistributor-regions = <1>; + redistributor-stride = <0 0x20000>; }; apss_shared: mailbox@17c00000 { - compatible = "qcom,sc8180x-apss-shared"; + compatible = "qcom,sc8180x-apss-shared", "qcom,sdm845-apss-shared"; reg = <0x0 0x17c00000 0x0 0x1000>; #mbox-cells = <1>; }; diff --git a/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts b/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts index e4861c61a65bdc..ffc4406422ae2f 100644 --- a/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts +++ b/arch/arm64/boot/dts/qcom/sc8280xp-crd.dts @@ -458,6 +458,8 @@ }; &mdss0_dp3_phy { + compatible = "qcom,sc8280xp-edp-phy"; + vdda-phy-supply = <&vreg_l6b>; vdda-pll-supply = <&vreg_l3b>; diff --git a/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts b/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts index 38edaf51aa3457..def3976bd5bb15 100644 --- a/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts +++ b/arch/arm64/boot/dts/qcom/sc8280xp-lenovo-thinkpad-x13s.dts @@ -82,6 +82,9 @@ leds { compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&cam_indicator_en>; + led-camera-indicator { label = "white:camera-indicator"; function = LED_FUNCTION_INDICATOR; @@ -570,6 +573,7 @@ &mdss0_dp3 { compatible = "qcom,sc8280xp-edp"; + /delete-property/ #sound-dai-cells; data-lanes = <0 1 2 3>; @@ -601,6 +605,7 @@ }; &mdss0_dp3_phy { + compatible = "qcom,sc8280xp-edp-phy"; vdda-phy-supply = <&vreg_l6b>; vdda-pll-supply = <&vreg_l3b>; @@ -1277,6 +1282,13 @@ }; }; + cam_indicator_en: cam-indicator-en-state { + pins = "gpio28"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + edp_reg_en: edp-reg-en-state { pins = "gpio25"; function = "gpio"; diff --git a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi index cad59af7ccef1b..febf28356ff8b0 100644 --- a/arch/arm64/boot/dts/qcom/sc8280xp.dtsi +++ b/arch/arm64/boot/dts/qcom/sc8280xp.dtsi @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -2731,7 +2732,7 @@ status = "disabled"; }; - swr1: soundwire-controller@3210000 { + swr1: soundwire@3210000 { compatible = "qcom,soundwire-v1.6.0"; reg = <0 0x03210000 0 0x2000>; interrupts = ; @@ -2807,7 +2808,7 @@ status = "disabled"; }; - swr0: soundwire-controller@3250000 { + swr0: soundwire@3250000 { reg = <0 0x03250000 0 0x2000>; compatible = "qcom,soundwire-v1.6.0"; interrupts = ; @@ -2844,7 +2845,7 @@ #reset-cells = <1>; }; - swr2: soundwire-controller@3330000 { + swr2: soundwire@3330000 { compatible = "qcom,soundwire-v1.6.0"; reg = <0 0x03330000 0 0x2000>; interrupts = , @@ -3450,6 +3451,20 @@ }; }; + camcc: clock-controller@ad00000 { + compatible = "qcom,sc8280xp-camcc"; + reg = <0 0x0ad00000 0 0x20000>; + clocks = <&gcc GCC_CAMERA_AHB_CLK>, + <&rpmhcc RPMH_CXO_CLK>, + <&rpmhcc RPMH_CXO_CLK_A>, + <&sleep_clk>; + power-domains = <&rpmhpd SC8280XP_MMCX>; + required-opps = <&rpmhpd_opp_low_svs>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; + mdss0: display-subsystem@ae00000 { compatible = "qcom,sc8280xp-mdss"; reg = <0 0x0ae00000 0 0x1000>; @@ -4030,6 +4045,7 @@ sram@c3f0000 { compatible = "qcom,rpmh-stats"; reg = <0 0x0c3f0000 0 0x400>; + qcom,qmp = <&aoss_qmp>; }; spmi_bus: spmi@c440000 { @@ -4225,7 +4241,7 @@ compatible = "qcom,apss-wdt-sc8280xp", "qcom,kpss-wdt"; reg = <0 0x17c10000 0 0x1000>; clocks = <&sleep_clk>; - interrupts = ; + interrupts = ; }; timer@17c20000 { diff --git a/arch/arm64/boot/dts/qcom/sdm630.dtsi b/arch/arm64/boot/dts/qcom/sdm630.dtsi index 775700f78e0feb..513fe5e76b688e 100644 --- a/arch/arm64/boot/dts/qcom/sdm630.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm630.dtsi @@ -606,9 +606,6 @@ compatible = "qcom,sdm660-bimc"; reg = <0x01008000 0x78000>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_BIMC_CLK>, - <&rpmcc RPM_SMD_BIMC_A_CLK>; }; restart@10ac000 { @@ -620,28 +617,17 @@ compatible = "qcom,sdm660-cnoc"; reg = <0x01500000 0x10000>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_CNOC_CLK>, - <&rpmcc RPM_SMD_CNOC_A_CLK>; }; snoc: interconnect@1626000 { compatible = "qcom,sdm660-snoc"; reg = <0x01626000 0x7090>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a"; - clocks = <&rpmcc RPM_SMD_SNOC_CLK>, - <&rpmcc RPM_SMD_SNOC_A_CLK>; }; anoc2_smmu: iommu@16c0000 { compatible = "qcom,sdm630-smmu-v2", "qcom,smmu-v2"; reg = <0x016c0000 0x40000>; - - assigned-clocks = <&rpmcc RPM_SMD_AGGR2_NOC_CLK>; - assigned-clock-rates = <1000>; - clocks = <&rpmcc RPM_SMD_AGGR2_NOC_CLK>; - clock-names = "bus"; #global-interrupts = <2>; #iommu-cells = <1>; @@ -686,16 +672,12 @@ compatible = "qcom,sdm660-a2noc"; reg = <0x01704000 0xc100>; #interconnect-cells = <1>; - clock-names = "bus", - "bus_a", - "ipa", + clock-names = "ipa", "ufs_axi", "aggre2_ufs_axi", "aggre2_usb3_axi", "cfg_noc_usb2_axi"; - clocks = <&rpmcc RPM_SMD_AGGR2_NOC_CLK>, - <&rpmcc RPM_SMD_AGGR2_NOC_A_CLK>, - <&rpmcc RPM_SMD_IPA_CLK>, + clocks = <&rpmcc RPM_SMD_IPA_CLK>, <&gcc GCC_UFS_AXI_CLK>, <&gcc GCC_AGGRE2_UFS_AXI_CLK>, <&gcc GCC_AGGRE2_USB3_AXI_CLK>, @@ -706,10 +688,8 @@ compatible = "qcom,sdm660-mnoc"; reg = <0x01745000 0xa010>; #interconnect-cells = <1>; - clock-names = "bus", "bus_a", "iface"; - clocks = <&rpmcc RPM_SMD_MMSSNOC_AXI_CLK>, - <&rpmcc RPM_SMD_MMSSNOC_AXI_CLK_A>, - <&mmcc AHB_CLK_SRC>; + clock-names = "iface"; + clocks = <&mmcc AHB_CLK_SRC>; }; tsens: thermal-sensor@10ae000 { @@ -1186,7 +1166,9 @@ clocks = <&gcc GCC_GPU_CFG_AHB_CLK>, <&gcc GCC_BIMC_GFX_CLK>, <&gcc GCC_GPU_BIMC_GFX_CLK>; - clock-names = "iface", "mem", "mem_iface"; + clock-names = "iface", + "mem", + "mem_iface"; #global-interrupts = <2>; #iommu-cells = <1>; @@ -1288,20 +1270,16 @@ <&gcc GCC_USB30_MASTER_CLK>, <&gcc GCC_AGGRE2_USB3_AXI_CLK>, <&gcc GCC_USB30_SLEEP_CLK>, - <&gcc GCC_USB30_MOCK_UTMI_CLK>, - <&rpmcc RPM_SMD_AGGR2_NOC_CLK>; + <&gcc GCC_USB30_MOCK_UTMI_CLK>; clock-names = "cfg_noc", "core", "iface", "sleep", - "mock_utmi", - "bus"; + "mock_utmi"; assigned-clocks = <&gcc GCC_USB30_MOCK_UTMI_CLK>, - <&gcc GCC_USB30_MASTER_CLK>, - <&rpmcc RPM_SMD_AGGR2_NOC_CLK>; - assigned-clock-rates = <19200000>, <120000000>, - <19200000>; + <&gcc GCC_USB30_MASTER_CLK>; + assigned-clock-rates = <19200000>, <120000000>; interrupts = , ; @@ -2204,10 +2182,9 @@ clocks = <&mmcc MNOC_AHB_CLK>, <&mmcc BIMC_SMMU_AHB_CLK>, - <&rpmcc RPM_SMD_MMSSNOC_AXI_CLK>, <&mmcc BIMC_SMMU_AXI_CLK>; clock-names = "iface-mm", "iface-smmu", - "bus-mm", "bus-smmu"; + "bus-smmu"; #global-interrupts = <2>; #iommu-cells = <1>; @@ -2324,12 +2301,6 @@ compatible = "qcom,sdm660-gnoc"; reg = <0x17900000 0xe000>; #interconnect-cells = <1>; - /* - * This one apparently features no clocks, - * so let's not mess with the driver needlessly - */ - clock-names = "bus", "bus_a"; - clocks = <&xo_board>, <&xo_board>; }; apcs_glb: mailbox@17911000 { diff --git a/arch/arm64/boot/dts/qcom/sdm632-fairphone-fp3.dts b/arch/arm64/boot/dts/qcom/sdm632-fairphone-fp3.dts index 301eca9a4f313c..057579ae30138d 100644 --- a/arch/arm64/boot/dts/qcom/sdm632-fairphone-fp3.dts +++ b/arch/arm64/boot/dts/qcom/sdm632-fairphone-fp3.dts @@ -80,6 +80,10 @@ }; }; +&lpass { + status = "okay"; +}; + &pm8953_resin { status = "okay"; linux,code = ; @@ -239,3 +243,18 @@ &usb3_dwc3 { dr_mode = "peripheral"; }; + +&wcnss { + status = "okay"; + + vddpx-supply = <&pm8953_l5>; +}; + +&wcnss_iris { + compatible = "qcom,wcn3680"; + + vddxo-supply = <&pm8953_l7>; + vddrfa-supply = <&pm8953_l19>; + vddpa-supply = <&pm8953_l9>; + vdddig-supply = <&pm8953_l5>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi index ba2043d67370ad..4d7b77a231598e 100644 --- a/arch/arm64/boot/dts/qcom/sdm670.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi @@ -6,6 +6,7 @@ * Copyright (c) 2022, Richard Acayan. All rights reserved. */ +#include #include #include #include @@ -400,6 +401,30 @@ }; }; + dsi_opp_table: opp-table-dsi { + compatible = "operating-points-v2"; + + opp-19200000 { + opp-hz = /bits/ 64 <19200000>; + required-opps = <&rpmhpd_opp_min_svs>; + }; + + opp-180000000 { + opp-hz = /bits/ 64 <180000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-275000000 { + opp-hz = /bits/ 64 <275000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-358000000 { + opp-hz = /bits/ 64 <358000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + }; + psci { compatible = "arm,psci-1.0"; method = "smc"; @@ -1295,10 +1320,10 @@ <&gcc GCC_USB30_PRIM_MASTER_CLK>; assigned-clock-rates = <19200000>, <150000000>; - interrupts = , - , - , - ; + interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 6 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 8 IRQ_TYPE_EDGE_BOTH>, + <&pdc 9 IRQ_TYPE_EDGE_BOTH>; interrupt-names = "hs_phy_irq", "ss_phy_irq", "dm_hs_phy_irq", "dp_hs_phy_irq"; @@ -1353,6 +1378,273 @@ #interrupt-cells = <4>; }; + mdss: display-subsystem@ae00000 { + compatible = "qcom,sdm670-mdss"; + reg = <0 0x0ae00000 0 0x1000>; + reg-names = "mdss"; + + power-domains = <&dispcc MDSS_GDSC>; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>; + clock-names = "iface", "core"; + + interrupts = ; + interrupt-controller; + #interrupt-cells = <1>; + + interconnects = <&mmss_noc MASTER_MDP_PORT0 0 &mem_noc SLAVE_EBI_CH0 0>, + <&mmss_noc MASTER_MDP_PORT1 0 &mem_noc SLAVE_EBI_CH0 0>; + interconnect-names = "mdp0-mem", "mdp1-mem"; + + iommus = <&apps_smmu 0x880 0x8>, + <&apps_smmu 0xc80 0x8>; + + #address-cells = <2>; + #size-cells = <2>; + ranges; + + status = "disabled"; + + mdss_mdp: display-controller@ae01000 { + compatible = "qcom,sdm670-dpu"; + reg = <0 0x0ae01000 0 0x8f000>, + <0 0x0aeb0000 0 0x2008>; + reg-names = "mdp", "vbif"; + + clocks = <&gcc GCC_DISP_AXI_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_AXI_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>, + <&dispcc DISP_CC_MDSS_VSYNC_CLK>; + clock-names = "gcc-bus", "iface", "bus", "core", "vsync"; + + assigned-clocks = <&dispcc DISP_CC_MDSS_VSYNC_CLK>; + assigned-clock-rates = <19200000>; + operating-points-v2 = <&mdp_opp_table>; + power-domains = <&rpmhpd SDM670_CX>; + + interrupt-parent = <&mdss>; + interrupts = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + dpu_intf0_out: endpoint { + remote-endpoint = <&mdss_dsi0_in>; + }; + }; + + port@1 { + reg = <1>; + dpu_intf1_out: endpoint { + remote-endpoint = <&mdss_dsi1_in>; + }; + }; + }; + + mdp_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-19200000 { + opp-hz = /bits/ 64 <19200000>; + required-opps = <&rpmhpd_opp_min_svs>; + }; + + opp-171428571 { + opp-hz = /bits/ 64 <171428571>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-358000000 { + opp-hz = /bits/ 64 <358000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-430000000 { + opp-hz = /bits/ 64 <430000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + mdss_dsi0: dsi@ae94000 { + compatible = "qcom,sdm670-dsi-ctrl", + "qcom,mdss-dsi-ctrl"; + reg = <0 0x0ae94000 0 0x400>; + reg-names = "dsi_ctrl"; + + interrupt-parent = <&mdss>; + interrupts = <4>; + + clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK>, + <&dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>, + <&dispcc DISP_CC_MDSS_PCLK0_CLK>, + <&dispcc DISP_CC_MDSS_ESC0_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_AXI_CLK>; + clock-names = "byte", + "byte_intf", + "pixel", + "core", + "iface", + "bus"; + assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>, + <&dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>; + assigned-clock-parents = <&mdss_dsi0_phy 0>, + <&mdss_dsi0_phy 1>; + + operating-points-v2 = <&dsi_opp_table>; + power-domains = <&rpmhpd SDM670_CX>; + + phys = <&mdss_dsi0_phy>; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + mdss_dsi0_in: endpoint { + remote-endpoint = <&dpu_intf0_out>; + }; + }; + + port@1 { + reg = <1>; + mdss_dsi0_out: endpoint { + }; + }; + }; + }; + + mdss_dsi0_phy: phy@ae94400 { + compatible = "qcom,dsi-phy-10nm"; + reg = <0 0x0ae94400 0 0x200>, + <0 0x0ae94600 0 0x280>, + <0 0x0ae94a00 0 0x1e0>; + reg-names = "dsi_phy", + "dsi_phy_lane", + "dsi_pll"; + + #clock-cells = <1>; + #phy-cells = <0>; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&rpmhcc RPMH_CXO_CLK>; + clock-names = "iface", "ref"; + + status = "disabled"; + }; + + mdss_dsi1: dsi@ae96000 { + compatible = "qcom,sdm670-dsi-ctrl", + "qcom,mdss-dsi-ctrl"; + reg = <0 0x0ae96000 0 0x400>; + reg-names = "dsi_ctrl"; + + interrupt-parent = <&mdss>; + interrupts = <5>; + + clocks = <&dispcc DISP_CC_MDSS_BYTE1_CLK>, + <&dispcc DISP_CC_MDSS_BYTE1_INTF_CLK>, + <&dispcc DISP_CC_MDSS_PCLK1_CLK>, + <&dispcc DISP_CC_MDSS_ESC1_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_AXI_CLK>; + clock-names = "byte", + "byte_intf", + "pixel", + "core", + "iface", + "bus"; + assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE1_CLK_SRC>, + <&dispcc DISP_CC_MDSS_PCLK1_CLK_SRC>; + assigned-clock-parents = <&mdss_dsi1_phy 0>, <&mdss_dsi1_phy 1>; + + operating-points-v2 = <&dsi_opp_table>; + power-domains = <&rpmhpd SDM670_CX>; + + phys = <&mdss_dsi1_phy>; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + mdss_dsi1_in: endpoint { + remote-endpoint = <&dpu_intf1_out>; + }; + }; + + port@1 { + reg = <1>; + mdss_dsi1_out: endpoint { + }; + }; + }; + }; + + mdss_dsi1_phy: phy@ae96400 { + compatible = "qcom,dsi-phy-10nm"; + reg = <0 0x0ae96400 0 0x200>, + <0 0x0ae96600 0 0x280>, + <0 0x0ae96a00 0 0x10e>; + reg-names = "dsi_phy", + "dsi_phy_lane", + "dsi_pll"; + + #clock-cells = <1>; + #phy-cells = <0>; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&rpmhcc RPMH_CXO_CLK>; + clock-names = "iface", "ref"; + + status = "disabled"; + }; + }; + + dispcc: clock-controller@af00000 { + compatible = "qcom,sdm845-dispcc"; + reg = <0 0x0af00000 0 0x10000>; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&gcc GCC_DISP_GPLL0_CLK_SRC>, + <&gcc GCC_DISP_GPLL0_DIV_CLK_SRC>, + <&mdss_dsi0_phy 0>, + <&mdss_dsi0_phy 1>, + <&mdss_dsi1_phy 0>, + <&mdss_dsi1_phy 1>, + <0>, + <0>; + clock-names = "bi_tcxo", + "gcc_disp_gpll0_clk_src", + "gcc_disp_gpll0_div_clk_src", + "dsi0_phy_pll_out_byteclk", + "dsi0_phy_pll_out_dsiclk", + "dsi1_phy_pll_out_byteclk", + "dsi1_phy_pll_out_dsiclk", + "dp_link_clk_divsel_ten", + "dp_vco_divided_clk_src_mux"; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; + apps_smmu: iommu@15000000 { compatible = "qcom,sdm670-smmu-500", "qcom,smmu-500", "arm,mmu-500"; reg = <0 0x15000000 0 0x80000>; @@ -1532,7 +1824,7 @@ }; cpufreq_hw: cpufreq@17d43000 { - compatible = "qcom,cpufreq-hw"; + compatible = "qcom,sdm670-cpufreq-hw", "qcom,cpufreq-hw"; reg = <0 0x17d43000 0 0x1400>, <0 0x17d45800 0 0x1400>; reg-names = "freq-domain0", "freq-domain1"; diff --git a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts index c7eba6c491be2b..ab6220456513cf 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-db845c.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-db845c.dts @@ -67,8 +67,8 @@ function = LED_FUNCTION_INDICATOR; color = ; gpios = <&pm8998_gpios 13 GPIO_ACTIVE_HIGH>; - linux,default-trigger = "panic-indicator"; default-state = "off"; + panic-indicator; }; led-1 { @@ -1130,7 +1130,7 @@ vdd-rx-supply = <&vreg_s4a_1p8>; vdd-io-supply = <&vreg_s4a_1p8>; - swm: swm@c85 { + swm: soundwire@c85 { left_spkr: speaker@0,1 { compatible = "sdw10217201000"; reg = <0 1>; diff --git a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi index b523b5fff70228..e821103d49c0ad 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-oneplus-common.dtsi @@ -8,6 +8,7 @@ /dts-v1/; #include +#include #include #include #include @@ -484,6 +485,28 @@ status = "okay"; }; +&pmi8998_flash { + status = "okay"; + + led-0 { + function = LED_FUNCTION_FLASH; + color = ; + led-sources = <1>; + led-max-microamp = <500000>; + flash-max-microamp = <1500000>; + flash-max-timeout-us = <1280000>; + }; + + led-1 { + function = LED_FUNCTION_FLASH; + color = ; + led-sources = <2>; + led-max-microamp = <500000>; + flash-max-microamp = <1500000>; + flash-max-timeout-us = <1280000>; + }; +}; + &q6afedai { qi2s@22 { reg = <22>; diff --git a/arch/arm64/boot/dts/qcom/sdm845-wcd9340.dtsi b/arch/arm64/boot/dts/qcom/sdm845-wcd9340.dtsi index c15d488606468b..6172cd1539e6bb 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-wcd9340.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-wcd9340.dtsi @@ -54,7 +54,7 @@ reg = <0x42 0x2>; }; - swm: swm@c85 { + swm: soundwire@c85 { compatible = "qcom,soundwire-v1.3.0"; reg = <0xc85 0x40>; interrupts-extended = <&wcd9340 20>; diff --git a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi index 93b1582e807dd8..617b17b2d7d9df 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-xiaomi-beryllium-common.dtsi @@ -355,6 +355,28 @@ status = "okay"; }; +&pmi8998_flash { + status = "okay"; + + led-0 { + function = LED_FUNCTION_FLASH; + color = ; + led-sources = <1>; + led-max-microamp = <500000>; + flash-max-microamp = <1500000>; + flash-max-timeout-us = <1280000>; + }; + + led-1 { + function = LED_FUNCTION_FLASH; + color = ; + led-sources = <2>; + led-max-microamp = <500000>; + flash-max-microamp = <1500000>; + flash-max-timeout-us = <1280000>; + }; +}; + &pm8998_resin { linux,code = ; status = "okay"; diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index bf5e6eb9d3138f..c2244824355a20 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -2306,7 +2306,7 @@ }; }; - pcie0: pci@1c00000 { + pcie0: pcie@1c00000 { compatible = "qcom,pcie-sdm845"; reg = <0 0x01c00000 0 0x2000>, <0 0x60000000 0 0xf1d>, @@ -2405,7 +2405,7 @@ status = "disabled"; }; - pcie1: pci@1c08000 { + pcie1: pcie@1c08000 { compatible = "qcom,pcie-sdm845"; reg = <0 0x01c08000 0 0x2000>, <0 0x40000000 0 0xf1d>, @@ -2565,7 +2565,7 @@ <0 0x01d90000 0 0x8000>; reg-names = "std", "ice"; interrupts = ; - phys = <&ufs_mem_phy_lanes>; + phys = <&ufs_mem_phy>; phy-names = "ufsphy"; lanes-per-direction = <2>; power-domains = <&gcc UFS_PHY_GDSC>; @@ -2595,30 +2595,50 @@ <&gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>, <&gcc GCC_UFS_PHY_RX_SYMBOL_1_CLK>, <&gcc GCC_UFS_PHY_ICE_CORE_CLK>; - freq-table-hz = - <50000000 200000000>, - <0 0>, - <0 0>, - <37500000 150000000>, - <0 0>, - <0 0>, - <0 0>, - <0 0>, - <75000000 300000000>; + + operating-points-v2 = <&ufs_opp_table>; interconnects = <&aggre1_noc MASTER_UFS_MEM 0 &mem_noc SLAVE_EBI1 0>, <&gladiator_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_UFS_MEM_CFG 0>; interconnect-names = "ufs-ddr", "cpu-ufs"; status = "disabled"; + + ufs_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-50000000 { + opp-hz = /bits/ 64 <50000000>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <37500000>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <75000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <150000000>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <300000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; }; ufs_mem_phy: phy@1d87000 { compatible = "qcom,sdm845-qmp-ufs-phy"; - reg = <0 0x01d87000 0 0x18c>; - #address-cells = <2>; - #size-cells = <2>; - ranges; + reg = <0 0x01d87000 0 0x1000>; + clock-names = "ref", "ref_aux"; clocks = <&gcc GCC_UFS_MEM_CLKREF_CLK>, @@ -2626,16 +2646,9 @@ resets = <&ufs_mem_hc 0>; reset-names = "ufsphy"; - status = "disabled"; - ufs_mem_phy_lanes: phy@1d87400 { - reg = <0 0x01d87400 0 0x108>, - <0 0x01d87600 0 0x1e0>, - <0 0x01d87c00 0 0x1dc>, - <0 0x01d87800 0 0x108>, - <0 0x01d87a00 0 0x1e0>; - #phy-cells = <0>; - }; + #phy-cells = <0>; + status = "disabled"; }; cryptobam: dma-controller@1dc4000 { @@ -3545,11 +3558,8 @@ }; in-ports { - #address-cells = <1>; - #size-cells = <0>; - port@1 { - reg = <1>; + port { etf_in: endpoint { remote-endpoint = <&merge_funnel_out>; @@ -4000,33 +4010,28 @@ usb_2_qmpphy: phy@88eb000 { compatible = "qcom,sdm845-qmp-usb3-uni-phy"; - reg = <0 0x088eb000 0 0x18c>; - status = "disabled"; - #address-cells = <2>; - #size-cells = <2>; - ranges; + reg = <0 0x088eb000 0 0x1000>; clocks = <&gcc GCC_USB3_SEC_PHY_AUX_CLK>, <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, <&gcc GCC_USB3_SEC_CLKREF_CLK>, - <&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>; - clock-names = "aux", "cfg_ahb", "ref", "com_aux"; + <&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>, + <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>; + clock-names = "aux", + "cfg_ahb", + "ref", + "com_aux", + "pipe"; + clock-output-names = "usb3_uni_phy_pipe_clk_src"; + #clock-cells = <0>; + #phy-cells = <0>; - resets = <&gcc GCC_USB3PHY_PHY_SEC_BCR>, - <&gcc GCC_USB3_PHY_SEC_BCR>; - reset-names = "phy", "common"; + resets = <&gcc GCC_USB3_PHY_SEC_BCR>, + <&gcc GCC_USB3PHY_PHY_SEC_BCR>; + reset-names = "phy", + "phy_phy"; - usb_2_ssphy: phy@88eb200 { - reg = <0 0x088eb200 0 0x128>, - <0 0x088eb400 0 0x1fc>, - <0 0x088eb800 0 0x218>, - <0 0x088eb600 0 0x70>; - #clock-cells = <0>; - #phy-cells = <0>; - clocks = <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>; - clock-names = "pipe0"; - clock-output-names = "usb3_uni_phy_pipe_clk_src"; - }; + status = "disabled"; }; usb_1: usb@a6f8800 { @@ -4053,10 +4058,10 @@ <&gcc GCC_USB30_PRIM_MASTER_CLK>; assigned-clock-rates = <19200000>, <150000000>; - interrupts = , - , - , - ; + interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, + <&pdc_intc 6 IRQ_TYPE_LEVEL_HIGH>, + <&pdc_intc 8 IRQ_TYPE_EDGE_BOTH>, + <&pdc_intc 9 IRQ_TYPE_EDGE_BOTH>; interrupt-names = "hs_phy_irq", "ss_phy_irq", "dm_hs_phy_irq", "dp_hs_phy_irq"; @@ -4104,10 +4109,10 @@ <&gcc GCC_USB30_SEC_MASTER_CLK>; assigned-clock-rates = <19200000>, <150000000>; - interrupts = , - , - , - ; + interrupts-extended = <&intc GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>, + <&pdc_intc 7 IRQ_TYPE_LEVEL_HIGH>, + <&pdc_intc 10 IRQ_TYPE_EDGE_BOTH>, + <&pdc_intc 11 IRQ_TYPE_EDGE_BOTH>; interrupt-names = "hs_phy_irq", "ss_phy_irq", "dm_hs_phy_irq", "dp_hs_phy_irq"; @@ -4126,7 +4131,7 @@ iommus = <&apps_smmu 0x760 0>; snps,dis_u2_susphy_quirk; snps,dis_enblslpm_quirk; - phys = <&usb_2_hsphy>, <&usb_2_ssphy>; + phys = <&usb_2_hsphy>, <&usb_2_qmpphy>; phy-names = "usb2-phy", "usb3-phy"; }; }; @@ -5088,7 +5093,7 @@ compatible = "qcom,apss-wdt-sdm845", "qcom,kpss-wdt"; reg = <0 0x17980000 0 0x1000>; clocks = <&sleep_clk>; - interrupts = ; + interrupts = ; }; apss_shared: mailbox@17990000 { diff --git a/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts b/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts index 92a812b5f4238e..47dc42f6e936cd 100644 --- a/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts +++ b/arch/arm64/boot/dts/qcom/sdm850-lenovo-yoga-c630.dts @@ -392,6 +392,8 @@ hid-descr-addr = <0x20>; interrupts-extended = <&tlmm 37 IRQ_TYPE_LEVEL_HIGH>; + + wakeup-source; }; }; @@ -408,6 +410,8 @@ pinctrl-names = "default"; pinctrl-0 = <&i2c5_hid_active>; + + wakeup-source; }; }; @@ -482,6 +486,8 @@ pinctrl-names = "default"; pinctrl-0 = <&i2c11_hid_active>; + + wakeup-source; }; }; @@ -797,7 +803,7 @@ qcom,mbhc-headset-vthreshold-microvolt = <1700000>; qcom,mbhc-headphone-vthreshold-microvolt = <50000>; - swm: swm@c85 { + swm: soundwire@c85 { left_spkr: speaker@0,3 { compatible = "sdw10217211000"; reg = <0 3>; diff --git a/arch/arm64/boot/dts/qcom/sdm850-samsung-w737.dts b/arch/arm64/boot/dts/qcom/sdm850-samsung-w737.dts index 543837316001b3..26217836c2707b 100644 --- a/arch/arm64/boot/dts/qcom/sdm850-samsung-w737.dts +++ b/arch/arm64/boot/dts/qcom/sdm850-samsung-w737.dts @@ -658,7 +658,7 @@ qcom,mbhc-headset-vthreshold-microvolt = <1700000>; qcom,mbhc-headphone-vthreshold-microvolt = <50000>; - swm: swm@c85 { + swm: soundwire@c85 { left_spkr: speaker@0,3 { compatible = "sdw10217211000"; reg = <0 3>; diff --git a/arch/arm64/boot/dts/qcom/sdx75-idp.dts b/arch/arm64/boot/dts/qcom/sdx75-idp.dts index a14e0650c4a8aa..f76e72fb2072ff 100644 --- a/arch/arm64/boot/dts/qcom/sdx75-idp.dts +++ b/arch/arm64/boot/dts/qcom/sdx75-idp.dts @@ -250,6 +250,11 @@ stdout-path = "serial0:115200n8"; }; +&pm7550ba_eusb2_repeater { + vdd18-supply = <&vreg_l5b_1p776>; + vdd3-supply = <&vreg_l10b_3p08>; +}; + &qupv3_id_0 { status = "okay"; }; @@ -261,3 +266,27 @@ &uart1 { status = "okay"; }; + +&usb { + status = "okay"; +}; + +&usb_dwc3 { + dr_mode = "peripheral"; +}; + +&usb_hsphy { + vdd-supply = <&vreg_l4b_0p88>; + vdda12-supply = <&vreg_l1b_1p2>; + + phys = <&pm7550ba_eusb2_repeater>; + + status = "okay"; +}; + +&usb_qmpphy { + vdda-phy-supply = <&vreg_l4b_0p88>; + vdda-pll-supply = <&vreg_l1b_1p2>; + + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/sdx75.dtsi b/arch/arm64/boot/dts/qcom/sdx75.dtsi index e180aa4023eca4..7dbdf8ca6de685 100644 --- a/arch/arm64/boot/dts/qcom/sdx75.dtsi +++ b/arch/arm64/boot/dts/qcom/sdx75.dtsi @@ -8,6 +8,8 @@ #include #include +#include +#include #include #include #include @@ -203,6 +205,19 @@ }; }; + clk_virt: interconnect-0 { + compatible = "qcom,sdx75-clk-virt"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + clocks = <&rpmhcc RPMH_QPIC_CLK>; + }; + + mc_virt: interconnect-1 { + compatible = "qcom,sdx75-mc-virt"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + memory@80000000 { device_type = "memory"; reg = <0x0 0x80000000 0x0 0x0>; @@ -434,6 +449,9 @@ clock-names = "m-ahb", "s-ahb"; iommus = <&apps_smmu 0xe3 0x0>; + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core"; #address-cells = <2>; #size-cells = <2>; ranges; @@ -444,6 +462,12 @@ reg = <0x0 0x00984000 0x0 0x4000>; clocks = <&gcc GCC_QUPV3_WRAP0_S1_CLK>; clock-names = "se"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &system_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config"; interrupts = ; pinctrl-0 = <&qupv3_se1_2uart_active>; pinctrl-1 = <&qupv3_se1_2uart_sleep>; @@ -453,12 +477,144 @@ }; }; + usb_hsphy: phy@ff4000 { + compatible = "qcom,sdx75-snps-eusb2-phy", "qcom,sm8550-snps-eusb2-phy"; + reg = <0x0 0x00ff4000 0x0 0x154>; + #phy-cells = <0>; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "ref"; + + resets = <&gcc GCC_QUSB2PHY_BCR>; + + status = "disabled"; + }; + + usb_qmpphy: phy@ff6000 { + compatible = "qcom,sdx75-qmp-usb3-uni-phy"; + reg = <0x0 0x00ff6000 0x0 0x2000>; + + clocks = <&gcc GCC_USB3_PHY_AUX_CLK>, + <&gcc GCC_USB2_CLKREF_EN>, + <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, + <&gcc GCC_USB3_PHY_PIPE_CLK>; + clock-names = "aux", + "ref", + "cfg_ahb", + "pipe"; + + power-domains = <&gcc GCC_USB3_PHY_GDSC>; + + resets = <&gcc GCC_USB3_PHY_BCR>, + <&gcc GCC_USB3PHY_PHY_BCR>; + reset-names = "phy", + "phy_phy"; + + #clock-cells = <0>; + clock-output-names = "usb3_uni_phy_pipe_clk_src"; + + #phy-cells = <0>; + + status = "disabled"; + }; + + system_noc: interconnect@1640000 { + compatible = "qcom,sdx75-system-noc"; + reg = <0x0 0x01640000 0x0 0x4b400>; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + pcie_anoc: interconnect@16c0000 { + compatible = "qcom,sdx75-pcie-anoc"; + reg = <0x0 0x016c0000 0x0 0x14200>; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + tcsr_mutex: hwlock@1f40000 { compatible = "qcom,tcsr-mutex"; reg = <0x0 0x01f40000 0x0 0x40000>; #hwlock-cells = <1>; }; + usb: usb@a6f8800 { + compatible = "qcom,sdx75-dwc3", "qcom,dwc3"; + reg = <0x0 0x0a6f8800 0x0 0x400>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + clocks = <&gcc GCC_USB30_SLV_AHB_CLK>, + <&gcc GCC_USB30_MASTER_CLK>, + <&gcc GCC_USB30_MSTR_AXI_CLK>, + <&gcc GCC_USB30_SLEEP_CLK>, + <&gcc GCC_USB30_MOCK_UTMI_CLK>; + clock-names = "cfg_noc", + "core", + "iface", + "sleep", + "mock_utmi"; + + assigned-clocks = <&gcc GCC_USB30_MOCK_UTMI_CLK>, + <&gcc GCC_USB30_MASTER_CLK>; + assigned-clock-rates = <19200000>, <200000000>; + + interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 17 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 9 IRQ_TYPE_EDGE_RISING>, + <&pdc 10 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "hs_phy_irq", + "ss_phy_irq", + "dm_hs_phy_irq", + "dp_hs_phy_irq"; + + power-domains = <&gcc GCC_USB30_GDSC>; + + resets = <&gcc GCC_USB30_BCR>; + + interconnects = <&system_noc MASTER_USB3_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &system_noc SLAVE_USB3 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "usb-ddr", + "apps-usb"; + + status = "disabled"; + + usb_dwc3: usb@a600000 { + compatible = "snps,dwc3"; + reg = <0x0 0x0a600000 0x0 0xcd00>; + interrupts = ; + iommus = <&apps_smmu 0x80 0x0>; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; + phys = <&usb_hsphy>, + <&usb_qmpphy>; + phy-names = "usb2-phy", + "usb3-phy"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + usb_1_dwc3_hs: endpoint { + }; + }; + + port@1 { + reg = <1>; + + usb_1_dwc3_ss: endpoint { + }; + }; + }; + }; + }; + pdc: interrupt-controller@b220000 { compatible = "qcom,sdx75-pdc", "qcom,pdc"; reg = <0x0 0xb220000 0x0 0x30000>, @@ -733,6 +889,20 @@ #freq-domain-cells = <1>; #clock-cells = <1>; }; + + dc_noc: interconnect@190e0000 { + compatible = "qcom,sdx75-dc-noc"; + reg = <0x0 0x190e0000 0x0 0x8200>; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + gem_noc: interconnect@19100000 { + compatible = "qcom,sdx75-gem-noc"; + reg = <0x0 0x19100000 0x0 0x34080>; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; }; timer { diff --git a/arch/arm64/boot/dts/qcom/sm4450-qrd.dts b/arch/arm64/boot/dts/qcom/sm4450-qrd.dts index 00a1c81ca3977e..866e9378359020 100644 --- a/arch/arm64/boot/dts/qcom/sm4450-qrd.dts +++ b/arch/arm64/boot/dts/qcom/sm4450-qrd.dts @@ -10,9 +10,23 @@ model = "Qualcomm Technologies, Inc. SM4450 QRD"; compatible = "qcom,sm4450-qrd", "qcom,sm4450"; - aliases { }; + aliases { + serial0 = &uart7; + }; chosen { - bootargs = "console=hvc0"; + stdout-path = "serial0:115200n8"; }; }; + +&qupv3_id_0 { + status = "okay"; +}; + +&tlmm { + gpio-reserved-ranges = <0 4>; /* NFC eSE SPI */ +}; + +&uart7 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/sm4450.dtsi b/arch/arm64/boot/dts/qcom/sm4450.dtsi index c4e5b33f5169c8..3e7ae3bebbe081 100644 --- a/arch/arm64/boot/dts/qcom/sm4450.dtsi +++ b/arch/arm64/boot/dts/qcom/sm4450.dtsi @@ -3,8 +3,11 @@ * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. */ +#include +#include #include #include +#include / { interrupt-parent = <&intc>; @@ -328,6 +331,18 @@ }; }; + reserved_memory: reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + aop_cmd_db_mem: cmd-db@80860000 { + compatible = "qcom,cmd-db"; + reg = <0x0 0x80860000 0x0 0x20000>; + no-map; + }; + }; + soc: soc@0 { #address-cells = <2>; #size-cells = <2>; @@ -335,6 +350,43 @@ dma-ranges = <0 0 0 0 0x10 0>; compatible = "simple-bus"; + gcc: clock-controller@100000 { + compatible = "qcom,sm4450-gcc"; + reg = <0x0 0x00100000 0x0 0x1f4200>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&sleep_clk>, + <0>, + <0>, + <0>, + <0>; + }; + + qupv3_id_0: geniqup@ac0000 { + compatible = "qcom,geni-se-qup"; + reg = <0x0 0x00ac0000 0x0 0x2000>; + ranges; + clocks = <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + clock-names = "m-ahb", "s-ahb"; + #address-cells = <2>; + #size-cells = <2>; + status = "disabled"; + + uart7: serial@a88000 { + compatible = "qcom,geni-debug-uart"; + reg = <0x0 0x00a88000 0x0 0x4000>; + clocks = <&gcc GCC_QUPV3_WRAP1_S2_CLK>; + clock-names = "se"; + interrupts = ; + pinctrl-0 = <&qup_uart7_tx>, <&qup_uart7_rx>; + pinctrl-names = "default"; + status = "disabled"; + }; + }; + tcsr_mutex: hwlock@1f40000 { compatible = "qcom,tcsr-mutex"; reg = <0x0 0x01f40000 0x0 0x40000>; @@ -351,6 +403,32 @@ interrupt-controller; }; + tlmm: pinctrl@f100000 { + compatible = "qcom,sm4450-tlmm"; + reg = <0x0 0x0f100000 0x0 0x300000>; + interrupts = ; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-ranges = <&tlmm 0 0 137>; + wakeup-parent = <&pdc>; + + qup_uart7_rx: qup-uart7-rx-state { + pins = "gpio23"; + function = "qup1_se2_l2"; + drive-strength = <2>; + bias-disable; + }; + + qup_uart7_tx: qup-uart7-tx-state { + pins = "gpio22"; + function = "qup1_se2_l2"; + drive-strength = <2>; + bias-disable; + }; + }; + intc: interrupt-controller@17200000 { compatible = "arm,gic-v3"; reg = <0x0 0x17200000 0x0 0x10000>, /* GICD */ @@ -419,6 +497,35 @@ status = "disabled"; }; }; + + apps_rsc: rsc@17a00000 { + compatible = "qcom,rpmh-rsc"; + reg = <0x0 0x17a00000 0x0 0x10000>, + <0x0 0x17a10000 0x0 0x10000>, + <0x0 0x17a20000 0x0 0x10000>; + reg-names = "drv-0", "drv-1", "drv-2"; + interrupts = , + , + ; + label = "apps_rsc"; + qcom,tcs-offset = <0xd00>; + qcom,drv-id = <2>; + qcom,tcs-config = , , + , ; + power-domains = <&CLUSTER_PD>; + + apps_bcm_voter: bcm-voter { + compatible = "qcom,bcm-voter"; + }; + + rpmhcc: clock-controller { + compatible = "qcom,sm4450-rpmh-clk"; + #clock-cells = <1>; + clocks = <&xo_board>; + clock-names = "xo"; + }; + }; + }; timer { diff --git a/arch/arm64/boot/dts/qcom/sm6115.dtsi b/arch/arm64/boot/dts/qcom/sm6115.dtsi index 839c6035124034..160e098f10757e 100644 --- a/arch/arm64/boot/dts/qcom/sm6115.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6115.dtsi @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include @@ -264,6 +266,8 @@ scm: scm { compatible = "qcom,scm-sm6115", "qcom,scm"; #reset-cells = <1>; + interconnects = <&system_noc MASTER_CRYPTO_CORE0 RPM_ALWAYS_TAG + &bimc SLAVE_EBI_CH0 RPM_ALWAYS_TAG>; }; }; @@ -273,6 +277,25 @@ reg = <0 0x80000000 0 0>; }; + qup_opp_table: opp-table-qup { + compatible = "operating-points-v2"; + + opp-75000000 { + opp-hz = /bits/ 64 <75000000>; + required-opps = <&rpmpd_opp_low_svs>; + }; + + opp-100000000 { + opp-hz = /bits/ 64 <100000000>; + required-opps = <&rpmpd_opp_svs>; + }; + + opp-128000000 { + opp-hz = /bits/ 64 <128000000>; + required-opps = <&rpmpd_opp_nom>; + }; + }; + pmu { compatible = "arm,armv8-pmuv3"; interrupts = ; @@ -859,6 +882,43 @@ status = "disabled"; }; + system_noc: interconnect@1880000 { + compatible = "qcom,sm6115-snoc"; + reg = <0x0 0x01880000 0x0 0x5f080>; + clocks = <&gcc GCC_SYS_NOC_CPUSS_AHB_CLK>, + <&gcc GCC_SYS_NOC_UFS_PHY_AXI_CLK>, + <&gcc GCC_SYS_NOC_USB3_PRIM_AXI_CLK>, + <&rpmcc RPM_SMD_IPA_CLK>; + clock-names = "cpu_axi", + "ufs_axi", + "usb_axi", + "ipa"; + #interconnect-cells = <2>; + + clk_virt: interconnect-clk { + compatible = "qcom,sm6115-clk-virt"; + #interconnect-cells = <2>; + }; + + mmrt_virt: interconnect-mmrt { + compatible = "qcom,sm6115-mmrt-virt"; + #interconnect-cells = <2>; + }; + + mmnrt_virt: interconnect-mmnrt { + compatible = "qcom,sm6115-mmnrt-virt"; + #interconnect-cells = <2>; + }; + }; + + config_noc: interconnect@1900000 { + compatible = "qcom,sm6115-cnoc"; + reg = <0x0 0x01900000 0x0 0x6200>; + clocks = <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>; + clock-names = "usb_axi"; + #interconnect-cells = <2>; + }; + qfprom@1b40000 { compatible = "qcom,sm6115-qfprom", "qcom,qfprom"; reg = <0x0 0x01b40000 0x0 0x7000>; @@ -883,6 +943,60 @@ clock-names = "core"; }; + pmu@1b8e300 { + compatible = "qcom,sm6115-cpu-bwmon", "qcom,sdm845-bwmon"; + reg = <0x0 0x01b8e300 0x0 0x600>; + interrupts = ; + + operating-points-v2 = <&cpu_bwmon_opp_table>; + interconnects = <&bimc MASTER_AMPSS_M0 RPM_ACTIVE_TAG + &bimc SLAVE_EBI_CH0 RPM_ACTIVE_TAG>; + + cpu_bwmon_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-0 { + opp-peak-kBps = <(200 * 4 * 1000)>; + }; + + opp-1 { + opp-peak-kBps = <(300 * 4 * 1000)>; + }; + + opp-2 { + opp-peak-kBps = <(451 * 4 * 1000)>; + }; + + opp-3 { + opp-peak-kBps = <(547 * 4 * 1000)>; + }; + + opp-4 { + opp-peak-kBps = <(681 * 4 * 1000)>; + }; + + opp-5 { + opp-peak-kBps = <(768 * 4 * 1000)>; + }; + + opp-6 { + opp-peak-kBps = <(1017 * 4 * 1000)>; + }; + + opp-7 { + opp-peak-kBps = <(1353 * 4 * 1000)>; + }; + + opp-8 { + opp-peak-kBps = <(1555 * 4 * 1000)>; + }; + + opp-9 { + opp-peak-kBps = <(1804 * 4 * 1000)>; + }; + }; + }; + spmi_bus: spmi@1c40000 { compatible = "qcom,spmi-pmic-arb"; reg = <0x0 0x01c40000 0x0 0x1100>, @@ -912,6 +1026,12 @@ #thermal-sensor-cells = <1>; }; + bimc: interconnect@4480000 { + compatible = "qcom,sm6115-bimc"; + reg = <0x0 0x04480000 0x0 0x80000>; + #interconnect-cells = <2>; + }; + rpm_msg_ram: sram@45f0000 { compatible = "qcom,rpm-msg-ram"; reg = <0x0 0x045f0000 0x0 0x7000>; @@ -939,8 +1059,42 @@ <&gcc GCC_SDCC1_ICE_CORE_CLK>; clock-names = "iface", "core", "xo", "ice"; + power-domains = <&rpmpd SM6115_VDDCX>; + operating-points-v2 = <&sdhc1_opp_table>; + interconnects = <&system_noc MASTER_SDCC_1 RPM_ALWAYS_TAG + &bimc SLAVE_EBI_CH0 RPM_ALWAYS_TAG>, + <&bimc MASTER_AMPSS_M0 RPM_ALWAYS_TAG + &config_noc SLAVE_SDCC_1 RPM_ALWAYS_TAG>; + interconnect-names = "sdhc-ddr", + "cpu-sdhc"; + bus-width = <8>; status = "disabled"; + + sdhc1_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-100000000 { + opp-hz = /bits/ 64 <100000000>; + required-opps = <&rpmpd_opp_low_svs>; + opp-peak-kBps = <250000 133320>; + opp-avg-kBps = <102400 65000>; + }; + + opp-192000000 { + opp-hz = /bits/ 64 <192000000>; + required-opps = <&rpmpd_opp_low_svs>; + opp-peak-kBps = <800000 300000>; + opp-avg-kBps = <204800 200000>; + }; + + opp-384000000 { + opp-hz = /bits/ 64 <384000000>; + required-opps = <&rpmpd_opp_svs_plus>; + opp-peak-kBps = <800000 300000>; + opp-avg-kBps = <204800 200000>; + }; + }; }; sdhc_2: mmc@4784000 { @@ -961,6 +1115,12 @@ operating-points-v2 = <&sdhc2_opp_table>; iommus = <&apps_smmu 0x00a0 0x0>; resets = <&gcc GCC_SDCC2_BCR>; + interconnects = <&system_noc MASTER_SDCC_2 RPM_ALWAYS_TAG + &bimc SLAVE_EBI_CH0 RPM_ALWAYS_TAG>, + <&bimc MASTER_AMPSS_M0 RPM_ALWAYS_TAG + &config_noc SLAVE_SDCC_2 RPM_ALWAYS_TAG>; + interconnect-names = "sdhc-ddr", + "cpu-sdhc"; bus-width = <4>; qcom,dll-config = <0x0007642c>; @@ -973,11 +1133,15 @@ opp-100000000 { opp-hz = /bits/ 64 <100000000>; required-opps = <&rpmpd_opp_low_svs>; + opp-peak-kBps = <250000 133320>; + opp-avg-kBps = <261438 150000>; }; opp-202000000 { opp-hz = /bits/ 64 <202000000>; required-opps = <&rpmpd_opp_nom>; + opp-peak-kBps = <800000 300000>; + opp-avg-kBps = <261438 300000>; }; }; }; @@ -987,7 +1151,7 @@ reg = <0x0 0x04804000 0x0 0x3000>, <0x0 0x04810000 0x0 0x8000>; reg-names = "std", "ice"; interrupts = ; - phys = <&ufs_mem_phy_lanes>; + phys = <&ufs_mem_phy>; phy-names = "ufsphy"; lanes-per-direction = <1>; #reset-cells = <1>; @@ -1028,24 +1192,17 @@ ufs_mem_phy: phy@4807000 { compatible = "qcom,sm6115-qmp-ufs-phy"; - reg = <0x0 0x04807000 0x0 0x1c4>; - #address-cells = <2>; - #size-cells = <2>; - ranges; + reg = <0x0 0x04807000 0x0 0x1000>; clocks = <&gcc GCC_UFS_CLKREF_CLK>, <&gcc GCC_UFS_PHY_PHY_AUX_CLK>; clock-names = "ref", "ref_aux"; resets = <&ufs_mem_hc 0>; reset-names = "ufsphy"; - status = "disabled"; - ufs_mem_phy_lanes: phy@4807400 { - reg = <0x0 0x04807400 0x0 0x098>, - <0x0 0x04807600 0x0 0x130>, - <0x0 0x04807c00 0x0 0x16c>; - #phy-cells = <0>; - }; + #phy-cells = <0>; + + status = "disabled"; }; gpi_dma0: dma-controller@4a00000 { @@ -1091,6 +1248,15 @@ dmas = <&gpi_dma0 0 0 QCOM_GPI_I2C>, <&gpi_dma0 1 0 QCOM_GPI_I2C>; dma-names = "tx", "rx"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &clk_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_AMPSS_M0 RPM_ALWAYS_TAG + &config_noc SLAVE_QUP_0 RPM_ALWAYS_TAG>, + <&system_noc MASTER_QUP_0 RPM_ALWAYS_TAG + &bimc SLAVE_EBI_CH0 RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -1107,6 +1273,15 @@ dmas = <&gpi_dma0 0 0 QCOM_GPI_SPI>, <&gpi_dma0 1 0 QCOM_GPI_SPI>; dma-names = "tx", "rx"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &clk_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_AMPSS_M0 RPM_ALWAYS_TAG + &config_noc SLAVE_QUP_0 RPM_ALWAYS_TAG>, + <&system_noc MASTER_QUP_0 RPM_ALWAYS_TAG + &bimc SLAVE_EBI_CH0 RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -1123,6 +1298,12 @@ dmas = <&gpi_dma0 0 1 QCOM_GPI_I2C>, <&gpi_dma0 1 1 QCOM_GPI_I2C>; dma-names = "tx", "rx"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &clk_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_AMPSS_M0 RPM_ALWAYS_TAG + &config_noc SLAVE_QUP_0 RPM_ALWAYS_TAG>, + <&system_noc MASTER_QUP_0 RPM_ALWAYS_TAG + &bimc SLAVE_EBI_CH0 RPM_ALWAYS_TAG>; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -1139,6 +1320,15 @@ dmas = <&gpi_dma0 0 1 QCOM_GPI_SPI>, <&gpi_dma0 1 1 QCOM_GPI_SPI>; dma-names = "tx", "rx"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &clk_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_AMPSS_M0 RPM_ALWAYS_TAG + &config_noc SLAVE_QUP_0 RPM_ALWAYS_TAG>, + <&system_noc MASTER_QUP_0 RPM_ALWAYS_TAG + &bimc SLAVE_EBI_CH0 RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -1155,6 +1345,15 @@ dmas = <&gpi_dma0 0 2 QCOM_GPI_I2C>, <&gpi_dma0 1 2 QCOM_GPI_I2C>; dma-names = "tx", "rx"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &clk_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_AMPSS_M0 RPM_ALWAYS_TAG + &config_noc SLAVE_QUP_0 RPM_ALWAYS_TAG>, + <&system_noc MASTER_QUP_0 RPM_ALWAYS_TAG + &bimc SLAVE_EBI_CH0 RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -1171,6 +1370,15 @@ dmas = <&gpi_dma0 0 2 QCOM_GPI_SPI>, <&gpi_dma0 1 2 QCOM_GPI_SPI>; dma-names = "tx", "rx"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &clk_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_AMPSS_M0 RPM_ALWAYS_TAG + &config_noc SLAVE_QUP_0 RPM_ALWAYS_TAG>, + <&system_noc MASTER_QUP_0 RPM_ALWAYS_TAG + &bimc SLAVE_EBI_CH0 RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -1187,6 +1395,15 @@ dmas = <&gpi_dma0 0 3 QCOM_GPI_I2C>, <&gpi_dma0 1 3 QCOM_GPI_I2C>; dma-names = "tx", "rx"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &clk_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_AMPSS_M0 RPM_ALWAYS_TAG + &config_noc SLAVE_QUP_0 RPM_ALWAYS_TAG>, + <&system_noc MASTER_QUP_0 RPM_ALWAYS_TAG + &bimc SLAVE_EBI_CH0 RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -1203,11 +1420,37 @@ dmas = <&gpi_dma0 0 3 QCOM_GPI_SPI>, <&gpi_dma0 1 3 QCOM_GPI_SPI>; dma-names = "tx", "rx"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &clk_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_AMPSS_M0 RPM_ALWAYS_TAG + &config_noc SLAVE_QUP_0 RPM_ALWAYS_TAG>, + <&system_noc MASTER_QUP_0 RPM_ALWAYS_TAG + &bimc SLAVE_EBI_CH0 RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; }; + uart3: serial@4a8c000 { + compatible = "qcom,geni-uart"; + reg = <0x0 0x04a8c000 0x0 0x4000>; + interrupts-extended = <&intc GIC_SPI 330 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&gcc GCC_QUPV3_WRAP0_S3_CLK>; + clock-names = "se"; + power-domains = <&rpmpd SM6115_VDDCX>; + operating-points-v2 = <&qup_opp_table>; + interconnects = <&clk_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &clk_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_AMPSS_M0 RPM_ALWAYS_TAG + &config_noc SLAVE_QUP_0 RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config"; + status = "disabled"; + }; + i2c4: i2c@4a90000 { compatible = "qcom,geni-i2c"; reg = <0x0 0x04a90000 0x0 0x4000>; @@ -1219,6 +1462,15 @@ dmas = <&gpi_dma0 0 4 QCOM_GPI_I2C>, <&gpi_dma0 1 4 QCOM_GPI_I2C>; dma-names = "tx", "rx"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &clk_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_AMPSS_M0 RPM_ALWAYS_TAG + &config_noc SLAVE_QUP_0 RPM_ALWAYS_TAG>, + <&system_noc MASTER_QUP_0 RPM_ALWAYS_TAG + &bimc SLAVE_EBI_CH0 RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -1235,6 +1487,15 @@ dmas = <&gpi_dma0 0 4 QCOM_GPI_SPI>, <&gpi_dma0 1 4 QCOM_GPI_SPI>; dma-names = "tx", "rx"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &clk_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_AMPSS_M0 RPM_ALWAYS_TAG + &config_noc SLAVE_QUP_0 RPM_ALWAYS_TAG>, + <&system_noc MASTER_QUP_0 RPM_ALWAYS_TAG + &bimc SLAVE_EBI_CH0 RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -1246,6 +1507,12 @@ clock-names = "se"; clocks = <&gcc GCC_QUPV3_WRAP0_S4_CLK>; interrupts = ; + interconnects = <&clk_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &clk_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_AMPSS_M0 RPM_ALWAYS_TAG + &config_noc SLAVE_QUP_0 RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config"; status = "disabled"; }; @@ -1260,6 +1527,15 @@ dmas = <&gpi_dma0 0 5 QCOM_GPI_I2C>, <&gpi_dma0 1 5 QCOM_GPI_I2C>; dma-names = "tx", "rx"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &clk_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_AMPSS_M0 RPM_ALWAYS_TAG + &config_noc SLAVE_QUP_0 RPM_ALWAYS_TAG>, + <&system_noc MASTER_QUP_0 RPM_ALWAYS_TAG + &bimc SLAVE_EBI_CH0 RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -1276,6 +1552,15 @@ dmas = <&gpi_dma0 0 5 QCOM_GPI_SPI>, <&gpi_dma0 1 5 QCOM_GPI_SPI>; dma-names = "tx", "rx"; + interconnects = <&clk_virt MASTER_QUP_CORE_0 RPM_ALWAYS_TAG + &clk_virt SLAVE_QUP_CORE_0 RPM_ALWAYS_TAG>, + <&bimc MASTER_AMPSS_M0 RPM_ALWAYS_TAG + &config_noc SLAVE_QUP_0 RPM_ALWAYS_TAG>, + <&system_noc MASTER_QUP_0 RPM_ALWAYS_TAG + &bimc SLAVE_EBI_CH0 RPM_ALWAYS_TAG>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; #address-cells = <1>; #size-cells = <0>; status = "disabled"; @@ -1307,6 +1592,14 @@ resets = <&gcc GCC_USB30_PRIM_BCR>; power-domains = <&gcc GCC_USB30_PRIM_GDSC>; + /* TODO: USB<->IPA path */ + interconnects = <&system_noc MASTER_USB3 RPM_ALWAYS_TAG + &bimc SLAVE_EBI_CH0 RPM_ALWAYS_TAG>, + <&bimc MASTER_AMPSS_M0 RPM_ALWAYS_TAG + &config_noc SLAVE_USB3 RPM_ALWAYS_TAG>; + interconnect-names = "usb-ddr", + "apps-usb"; + qcom,select-utmi-as-pipe-clk; status = "disabled"; @@ -1478,6 +1771,13 @@ iommus = <&apps_smmu 0x420 0x2>, <&apps_smmu 0x421 0x0>; + interconnects = <&mmrt_virt MASTER_MDP_PORT0 RPM_ALWAYS_TAG + &bimc SLAVE_EBI_CH0 RPM_ALWAYS_TAG>, + <&bimc MASTER_AMPSS_M0 RPM_ALWAYS_TAG + &config_noc SLAVE_DISPLAY_CFG RPM_ALWAYS_TAG>; + interconnect-names = "mdp0-mem", + "cpu-cfg"; + #address-cells = <2>; #size-cells = <2>; ranges; @@ -2566,54 +2866,54 @@ compatible = "arm,armv7-timer-mem"; reg = <0x0 0x0f120000 0x0 0x1000>; #address-cells = <2>; - #size-cells = <2>; - ranges; + #size-cells = <1>; + ranges = <0x0 0x0 0x0 0x0 0x20000000>; clock-frequency = <19200000>; frame@f121000 { - reg = <0x0 0x0f121000 0x0 0x1000>, <0x0 0x0f122000 0x0 0x1000>; + reg = <0x0 0x0f121000 0x1000>, <0x0 0x0f122000 0x1000>; frame-number = <0>; interrupts = , ; }; frame@f123000 { - reg = <0x0 0x0f123000 0x0 0x1000>; + reg = <0x0 0x0f123000 0x1000>; frame-number = <1>; interrupts = ; status = "disabled"; }; frame@f124000 { - reg = <0x0 0x0f124000 0x0 0x1000>; + reg = <0x0 0x0f124000 0x1000>; frame-number = <2>; interrupts = ; status = "disabled"; }; frame@f125000 { - reg = <0x0 0x0f125000 0x0 0x1000>; + reg = <0x0 0x0f125000 0x1000>; frame-number = <3>; interrupts = ; status = "disabled"; }; frame@f126000 { - reg = <0x0 0x0f126000 0x0 0x1000>; + reg = <0x0 0x0f126000 0x1000>; frame-number = <4>; interrupts = ; status = "disabled"; }; frame@f127000 { - reg = <0x0 0x0f127000 0x0 0x1000>; + reg = <0x0 0x0f127000 0x1000>; frame-number = <5>; interrupts = ; status = "disabled"; }; frame@f128000 { - reg = <0x0 0x0f128000 0x0 0x1000>; + reg = <0x0 0x0f128000 0x1000>; frame-number = <6>; interrupts = ; status = "disabled"; diff --git a/arch/arm64/boot/dts/qcom/sm6125.dtsi b/arch/arm64/boot/dts/qcom/sm6125.dtsi index eb07eca3a48df6..1dd3a4056e26f3 100644 --- a/arch/arm64/boot/dts/qcom/sm6125.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6125.dtsi @@ -1185,6 +1185,10 @@ <&gcc GCC_USB30_PRIM_MASTER_CLK>; assigned-clock-rates = <19200000>, <66666667>; + interrupts = , + ; + interrupt-names = "hs_phy_irq", "ss_phy_irq"; + power-domains = <&gcc USB30_PRIM_GDSC>; qcom,select-utmi-as-pipe-clk; status = "disabled"; diff --git a/arch/arm64/boot/dts/qcom/sm6350.dtsi b/arch/arm64/boot/dts/qcom/sm6350.dtsi index 8fd6f4d0349001..43cffe8e1247e3 100644 --- a/arch/arm64/boot/dts/qcom/sm6350.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6350.dtsi @@ -1142,7 +1142,7 @@ <0 0x01d90000 0 0x8000>; reg-names = "std", "ice"; interrupts = ; - phys = <&ufs_mem_phy_lanes>; + phys = <&ufs_mem_phy>; phy-names = "ufsphy"; lanes-per-direction = <2>; #reset-cells = <1>; @@ -1187,10 +1187,7 @@ ufs_mem_phy: phy@1d87000 { compatible = "qcom,sm6350-qmp-ufs-phy"; - reg = <0 0x01d87000 0 0x18c>; - #address-cells = <2>; - #size-cells = <2>; - ranges; + reg = <0 0x01d87000 0 0x1000>; clock-names = "ref", "ref_aux"; @@ -1200,16 +1197,9 @@ resets = <&ufs_mem_hc 0>; reset-names = "ufsphy"; - status = "disabled"; + #phy-cells = <0>; - ufs_mem_phy_lanes: phy@1d87400 { - reg = <0 0x01d87400 0 0x128>, - <0 0x01d87600 0 0x1fc>, - <0 0x01d87c00 0 0x1dc>, - <0 0x01d87800 0 0x128>, - <0 0x01d87a00 0 0x1fc>; - #phy-cells = <0>; - }; + status = "disabled"; }; ipa: ipa@1e40000 { @@ -2524,7 +2514,7 @@ compatible = "qcom,apss-wdt-sm6350", "qcom,kpss-wdt"; reg = <0 0x17c10000 0 0x1000>; clocks = <&sleep_clk>; - interrupts = ; + interrupts = ; }; timer@17c20000 { diff --git a/arch/arm64/boot/dts/qcom/sm6375-sony-xperia-murray-pdx225.dts b/arch/arm64/boot/dts/qcom/sm6375-sony-xperia-murray-pdx225.dts index b2f1bb1d58e974..cca2c2eb88ade7 100644 --- a/arch/arm64/boot/dts/qcom/sm6375-sony-xperia-murray-pdx225.dts +++ b/arch/arm64/boot/dts/qcom/sm6375-sony-xperia-murray-pdx225.dts @@ -80,6 +80,15 @@ }; }; + touch_avdd: touch-avdd-regulator { + compatible = "regulator-fixed"; + regulator-name = "touch_avdd"; + gpio = <&tlmm 59 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&ts_avdd_default>; + enable-active-high; + }; + vph_pwr: vph-pwr-regulator { compatible = "regulator-fixed"; regulator-name = "vph_pwr"; @@ -136,9 +145,10 @@ interrupts = <22 0x2008>; vdd-supply = <&pm6125_l13>; + avdd-supply = <&touch_avdd>; pinctrl-names = "default"; - pinctrl-0 = <&ts_int_default &ts_avdd_default>; + pinctrl-0 = <&ts_int_default>; }; }; @@ -187,6 +197,11 @@ status = "okay"; }; +&remoteproc_mss { + firmware-name = "qcom/sm6375/Sony/murray/modem.mbn"; + status = "okay"; +}; + &rpm_requests { regulators-0 { compatible = "qcom,rpm-pm6125-regulators"; @@ -238,8 +253,8 @@ }; pm6125_l7: l7 { - regulator-min-microvolt = <720000>; - regulator-max-microvolt = <1050000>; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; }; pm6125_l8: l8 { @@ -306,7 +321,7 @@ pm6125_l21: l21 { regulator-min-microvolt = <3000000>; - regulator-max-microvolt = <3400000>; + regulator-max-microvolt = <3312000>; }; pm6125_l22: l22 { @@ -317,7 +332,7 @@ pm6125_l23: l23 { regulator-min-microvolt = <3000000>; - regulator-max-microvolt = <3400000>; + regulator-max-microvolt = <3312000>; }; pm6125_l24: l24 { @@ -340,8 +355,8 @@ }; pmr735a_l2: l2 { - regulator-min-microvolt = <352000>; - regulator-max-microvolt = <796000>; + regulator-min-microvolt = <640000>; + regulator-max-microvolt = <640000>; }; pmr735a_l3: l3 { @@ -412,7 +427,7 @@ pins = "gpio59"; function = "gpio"; drive-strength = <8>; - output-high; + output-low; }; }; @@ -425,6 +440,18 @@ }; &usb_1_hsphy { + vdda-pll-supply = <&pm6125_l7>; + vdda18-supply = <&pm6125_l10>; + vdda33-supply = <&pmr735a_l7>; + status = "okay"; +}; + +&wifi { + vdd-0.8-cx-mx-supply = <&pmr735a_l2>; + vdd-1.8-xo-supply = <&pm6125_l16>; + vdd-1.3-rfa-supply = <&pm6125_l2>; + vdd-3.3-ch0-supply = <&pm6125_l23>; + vdd-3.3-ch1-supply = <&pm6125_l21>; status = "okay"; }; diff --git a/arch/arm64/boot/dts/qcom/sm6375.dtsi b/arch/arm64/boot/dts/qcom/sm6375.dtsi index e7ff55443da702..7ac8bf26dda3a2 100644 --- a/arch/arm64/boot/dts/qcom/sm6375.dtsi +++ b/arch/arm64/boot/dts/qcom/sm6375.dtsi @@ -311,6 +311,25 @@ }; }; + mpm: interrupt-controller { + compatible = "qcom,mpm"; + qcom,rpm-msg-ram = <&apss_mpm>; + interrupts = ; + mboxes = <&ipcc IPCC_CLIENT_AOP IPCC_MPROC_SIGNAL_SMP2P>; + interrupt-controller; + #interrupt-cells = <2>; + #power-domain-cells = <0>; + interrupt-parent = <&intc>; + qcom,mpm-pin-count = <96>; + qcom,mpm-pin-map = <5 296>, /* Soundwire wake_irq */ + <12 422>, /* DWC3 ss_phy_irq */ + <86 183>, /* MPM wake, SPMI */ + <89 314>, /* TSENS0 0C */ + <90 315>, /* TSENS1 0C */ + <93 164>, /* DWC3 dm_hs_phy_irq */ + <94 165>; /* DWC3 dp_hs_phy_irq */ + }; + memory@80000000 { device_type = "memory"; /* We expect the bootloader to fill in the size */ @@ -486,6 +505,7 @@ CLUSTER_PD: power-domain-cpu-cluster0 { #power-domain-cells = <0>; + power-domains = <&mpm>; domain-idle-states = <&CLUSTER_SLEEP_0>; }; }; @@ -808,7 +828,7 @@ reg = <0 0x00500000 0 0x800000>; interrupts = ; gpio-ranges = <&tlmm 0 0 157>; - /* TODO: Hook up MPM as wakeup-parent when it's there */ + wakeup-parent = <&mpm>; interrupt-controller; gpio-controller; #interrupt-cells = <2>; @@ -896,6 +916,36 @@ drive-strength = <6>; bias-disable; }; + + qup_uart1_default: qup-uart1-default-state { + cts-pins { + pins = "gpio61"; + function = "qup01"; + drive-strength = <2>; + bias-pull-down; + }; + + rts-pins { + pins = "gpio62"; + function = "qup01"; + drive-strength = <2>; + bias-disable; + }; + + tx-pins { + pins = "gpio63"; + function = "qup01"; + drive-strength = <2>; + bias-disable; + }; + + rx-pins { + pins = "gpio64"; + function = "qup01"; + drive-strength = <2>; + bias-pull-up; + }; + }; }; gcc: clock-controller@1400000 { @@ -930,7 +980,7 @@ <0 0x01c0a000 0 0x26000>; reg-names = "core", "chnls", "obsrvr", "intr", "cnfg"; interrupt-names = "periph_irq"; - interrupts = ; + interrupts-extended = <&mpm 86 IRQ_TYPE_LEVEL_HIGH>; qcom,ee = <0>; qcom,channel = <0>; #address-cells = <2>; @@ -962,8 +1012,15 @@ }; rpm_msg_ram: sram@45f0000 { - compatible = "qcom,rpm-msg-ram"; + compatible = "qcom,rpm-msg-ram", "mmio-sram"; reg = <0 0x045f0000 0 0x7000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x0 0x045f0000 0x7000>; + + apss_mpm: sram@1b8 { + reg = <0x1b8 0x48>; + }; }; sram@4690000 { @@ -1111,6 +1168,19 @@ status = "disabled"; }; + uart1: serial@4a84000 { + compatible = "qcom,geni-uart"; + reg = <0x0 0x04a84000 0x0 0x4000>; + interrupts = ; + clocks = <&gcc GCC_QUPV3_WRAP0_S1_CLK>; + clock-names = "se"; + power-domains = <&rpmpd SM6375_VDDCX>; + operating-points-v2 = <&qup_opp_table>; + pinctrl-0 = <&qup_uart1_default>; + pinctrl-names = "default"; + status = "disabled"; + }; + i2c2: i2c@4a88000 { compatible = "qcom,geni-i2c"; reg = <0x0 0x04a88000 0x0 0x4000>; @@ -1360,10 +1430,10 @@ <&gcc GCC_USB30_PRIM_MASTER_CLK>; assigned-clock-rates = <19200000>, <133333333>; - interrupts = , - , - , - ; + interrupts-extended = <&intc GIC_SPI 302 IRQ_TYPE_LEVEL_HIGH>, + <&mpm 12 IRQ_TYPE_LEVEL_HIGH>, + <&mpm 93 IRQ_TYPE_EDGE_BOTH>, + <&mpm 94 IRQ_TYPE_EDGE_BOTH>; interrupt-names = "hs_phy_irq", "ss_phy_irq", "dm_hs_phy_irq", diff --git a/arch/arm64/boot/dts/qcom/sm8150-hdk.dts b/arch/arm64/boot/dts/qcom/sm8150-hdk.dts index bb161b536da466..de670b407ef142 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-hdk.dts +++ b/arch/arm64/boot/dts/qcom/sm8150-hdk.dts @@ -7,6 +7,7 @@ #include #include +#include #include "sm8150.dtsi" #include "pm8150.dtsi" #include "pm8150b.dtsi" @@ -54,6 +55,17 @@ gpios = <&pm8150_gpios 6 GPIO_ACTIVE_LOW>; }; }; + + hdmi-out { + compatible = "hdmi-connector"; + type = "a"; + + port { + hdmi_con: endpoint { + remote-endpoint = <<9611_out>; + }; + }; + }; }; &apps_rsc { @@ -127,8 +139,6 @@ vdda_sp_sensor: vdda_ufs_2ln_core_1: vdda_ufs_2ln_core_2: - vdda_usb_ss_dp_core_1: - vdda_usb_ss_dp_core_2: vdda_qlink_lv: vdda_qlink_lv_ck: vreg_l5a_0p875: ldo5 { @@ -210,6 +220,12 @@ regulator-max-microvolt = <3008000>; regulator-initial-mode = ; }; + + vreg_l18a_0p8: ldo18 { + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + regulator-initial-mode = ; + }; }; regulators-1 { @@ -359,15 +375,210 @@ status = "okay"; }; +&gpi_dma0 { + status = "okay"; +}; + +&gpi_dma1 { + status = "okay"; +}; + &gpu { - /* - * NOTE: "amd,imageon" makes Adreno start in headless mode, remove it - * after display support is added on this board. - */ - compatible = "qcom,adreno-640.1", "qcom,adreno", "amd,imageon"; status = "okay"; }; +&i2c4 { + clock-frequency = <100000>; + + status = "okay"; + + typec-mux@42 { + compatible = "fcs,fsa4480"; + reg = <0x42>; + + interrupts-extended = <&tlmm 152 IRQ_TYPE_LEVEL_LOW>; + + vcc-supply = <&vreg_bob>; + mode-switch; + orientation-switch; + + port { + fsa4480_sbu_mux: endpoint { + remote-endpoint = <&pm8150b_typec_sbu_out>; + }; + }; + }; +}; + +&i2c9 { + status = "okay"; + clock-frequency = <400000>; + + lt9611_codec: hdmi-bridge@3b { + compatible = "lontium,lt9611"; + reg = <0x3b>; + #sound-dai-cells = <1>; + + interrupts-extended = <&tlmm 9 IRQ_TYPE_EDGE_FALLING>; + + reset-gpios = <&tlmm 7 GPIO_ACTIVE_HIGH>; + + vdd-supply = <&vreg_s4a_1p8>; + vcc-supply = <&vreg_bob>; + + pinctrl-names = "default"; + pinctrl-0 = <<9611_irq_pin>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + lt9611_a: endpoint { + remote-endpoint = <&mdss_dsi0_out>; + }; + }; + + port@1 { + reg = <1>; + + lt9611_b: endpoint { + remote-endpoint = <&mdss_dsi1_out>; + }; + }; + + port@2 { + reg = <2>; + + lt9611_out: endpoint { + remote-endpoint = <&hdmi_con>; + }; + }; + }; + }; +}; + +&mdss { + status = "okay"; +}; + +&mdss_dp { + status = "okay"; +}; + +&mdss_dp_out { + data-lanes = <0 1>; + remote-endpoint = <&usb_1_qmpphy_dp_in>; +}; + +&mdss_dsi0 { + status = "okay"; + vdda-supply = <&vreg_l3c_1p2>; + + qcom,dual-dsi-mode; + qcom,master-dsi; + + ports { + port@1 { + endpoint { + remote-endpoint = <<9611_a>; + data-lanes = <0 1 2 3>; + }; + }; + }; +}; + +&mdss_dsi0_phy { + status = "okay"; + vdds-supply = <&vreg_l5a_0p875>; +}; + +&mdss_dsi1 { + vdda-supply = <&vreg_l3c_1p2>; + + qcom,dual-dsi-mode; + + /* DSI1 is slave, so use DSI0 clocks */ + assigned-clock-parents = <&mdss_dsi0_phy 0>, <&mdss_dsi0_phy 1>; + + status = "okay"; + + ports { + port@1 { + endpoint { + remote-endpoint = <<9611_b>; + data-lanes = <0 1 2 3>; + }; + }; + }; +}; + +&mdss_dsi1_phy { + vdds-supply = <&vreg_l5a_0p875>; + status = "okay"; +}; + +&pm8150b_vbus { + regulator-min-microamp = <500000>; + regulator-max-microamp = <3000000>; + status = "okay"; +}; + +&pm8150b_typec { + status = "okay"; + + vdd-pdphy-supply = <&vreg_l2a_3p1>; + + connector { + compatible = "usb-c-connector"; + + power-role = "source"; + data-role = "dual"; + self-powered; + + source-pdos = ; + + altmodes { + displayport { + svid = /bits/ 16 <0xff01>; + vdo = <0x00001c46>; + }; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + pm8150b_role_switch_in: endpoint { + remote-endpoint = <&usb_1_dwc3_hs>; + }; + }; + + port@1 { + reg = <1>; + pm8150b_typec_mux_in: endpoint { + remote-endpoint = <&usb_1_qmpphy_out>; + }; + }; + + port@2 { + reg = <2>; + + pm8150b_typec_sbu_out: endpoint { + remote-endpoint = <&fsa4480_sbu_mux>; + }; + }; + }; + }; +}; + &pon_pwrkey { status = "okay"; }; @@ -378,6 +589,10 @@ linux,code = ; }; +&qupv3_id_0 { + status = "okay"; +}; + &qupv3_id_1 { status = "okay"; }; @@ -402,6 +617,13 @@ &tlmm { gpio-reserved-ranges = <0 4>, <126 4>; + + lt9611_irq_pin: lt9611-irq-state { + pins = "gpio9"; + function = "gpio"; + bias-disable; + }; + }; &uart2 { @@ -445,13 +667,26 @@ &usb_1_qmpphy { status = "okay"; vdda-phy-supply = <&vreg_l3c_1p2>; - vdda-pll-supply = <&vdda_usb_ss_dp_core_1>; + vdda-pll-supply = <&vreg_l18a_0p8>; + orientation-switch; +}; + +&usb_1_qmpphy_dp_in { + remote-endpoint = <&mdss_dp_out>; +}; + +&usb_1_qmpphy_out { + remote-endpoint = <&pm8150b_typec_mux_in>; +}; + +&usb_1_qmpphy_usb_ss_in { + remote-endpoint = <&usb_1_dwc3_ss>; }; &usb_2_qmpphy { status = "okay"; vdda-phy-supply = <&vreg_l3c_1p2>; - vdda-pll-supply = <&vdda_usb_ss_dp_core_1>; + vdda-pll-supply = <&vreg_l5a_0p875>; }; &usb_1 { @@ -463,7 +698,16 @@ }; &usb_1_dwc3 { - dr_mode = "peripheral"; + dr_mode = "otg"; + usb-role-switch; +}; + +&usb_1_dwc3_hs { + remote-endpoint = <&pm8150b_role_switch_in>; +}; + +&usb_1_dwc3_ss { + remote-endpoint = <&usb_1_qmpphy_usb_ss_in>; }; &usb_2_dwc3 { diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index 97623af13464c2..761a6757dc26f0 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -1824,7 +1824,7 @@ <0x0 0x010ad000 0x0 0x3000>; }; - pcie0: pci@1c00000 { + pcie0: pcie@1c00000 { compatible = "qcom,pcie-sm8150"; reg = <0 0x01c00000 0 0x3000>, <0 0x60000000 0 0xf1d>, @@ -1878,7 +1878,7 @@ phys = <&pcie0_phy>; phy-names = "pciephy"; - perst-gpio = <&tlmm 35 GPIO_ACTIVE_HIGH>; + perst-gpios = <&tlmm 35 GPIO_ACTIVE_HIGH>; enable-gpio = <&tlmm 37 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; @@ -1915,7 +1915,7 @@ status = "disabled"; }; - pcie1: pci@1c08000 { + pcie1: pcie@1c08000 { compatible = "qcom,pcie-sm8150"; reg = <0 0x01c08000 0 0x3000>, <0 0x40000000 0 0xf1d>, @@ -1972,7 +1972,7 @@ phys = <&pcie1_phy>; phy-names = "pciephy"; - perst-gpio = <&tlmm 102 GPIO_ACTIVE_HIGH>; + perst-gpios = <&tlmm 102 GPIO_ACTIVE_HIGH>; enable-gpio = <&tlmm 104 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; @@ -2016,7 +2016,7 @@ <0 0x01d90000 0 0x8000>; reg-names = "std", "ice"; interrupts = ; - phys = <&ufs_mem_phy_lanes>; + phys = <&ufs_mem_phy>; phy-names = "ufsphy"; lanes-per-direction = <2>; #reset-cells = <1>; @@ -2061,10 +2061,8 @@ ufs_mem_phy: phy@1d87000 { compatible = "qcom,sm8150-qmp-ufs-phy"; - reg = <0 0x01d87000 0 0x1c0>; - #address-cells = <2>; - #size-cells = <2>; - ranges; + reg = <0 0x01d87000 0 0x1000>; + clock-names = "ref", "ref_aux"; clocks = <&gcc GCC_UFS_MEM_CLKREF_CLK>, @@ -2074,16 +2072,10 @@ resets = <&ufs_mem_hc 0>; reset-names = "ufsphy"; - status = "disabled"; - ufs_mem_phy_lanes: phy@1d87400 { - reg = <0 0x01d87400 0 0x16c>, - <0 0x01d87600 0 0x200>, - <0 0x01d87c00 0 0x200>, - <0 0x01d87800 0 0x16c>, - <0 0x01d87a00 0 0x200>; - #phy-cells = <0>; - }; + #phy-cells = <0>; + + status = "disabled"; }; cryptobam: dma-controller@1dc4000 { @@ -2957,11 +2949,8 @@ }; in-ports { - #address-cells = <1>; - #size-cells = <0>; - port@1 { - reg = <1>; + port { replicator1_in: endpoint { remote-endpoint = <&replicator_out1>; }; @@ -3447,37 +3436,56 @@ #phy-cells = <1>; status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + usb_1_qmpphy_out: endpoint { + }; + }; + + port@1 { + reg = <1>; + + usb_1_qmpphy_usb_ss_in: endpoint { + }; + }; + + port@2 { + reg = <2>; + + usb_1_qmpphy_dp_in: endpoint { + }; + }; + }; }; usb_2_qmpphy: phy@88eb000 { compatible = "qcom,sm8150-qmp-usb3-uni-phy"; - reg = <0 0x088eb000 0 0x200>; - status = "disabled"; - #address-cells = <2>; - #size-cells = <2>; - ranges; + reg = <0 0x088eb000 0 0x1000>; clocks = <&gcc GCC_USB3_SEC_PHY_AUX_CLK>, - <&rpmhcc RPMH_CXO_CLK>, <&gcc GCC_USB3_SEC_CLKREF_CLK>, - <&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>; - clock-names = "aux", "ref_clk_src", "ref", "com_aux"; + <&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>, + <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>; + clock-names = "aux", + "ref", + "com_aux", + "pipe"; + clock-output-names = "usb3_uni_phy_pipe_clk_src"; + #clock-cells = <0>; + #phy-cells = <0>; - resets = <&gcc GCC_USB3PHY_PHY_SEC_BCR>, - <&gcc GCC_USB3_PHY_SEC_BCR>; - reset-names = "phy", "common"; + resets = <&gcc GCC_USB3_PHY_SEC_BCR>, + <&gcc GCC_USB3PHY_PHY_SEC_BCR>; + reset-names = "phy", + "phy_phy"; - usb_2_ssphy: phy@88eb200 { - reg = <0 0x088eb200 0 0x200>, - <0 0x088eb400 0 0x200>, - <0 0x088eb800 0 0x800>, - <0 0x088eb600 0 0x200>; - #clock-cells = <0>; - #phy-cells = <0>; - clocks = <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>; - clock-names = "pipe0"; - clock-output-names = "usb3_uni_phy_pipe_clk_src"; - }; + status = "disabled"; }; sdhc_2: mmc@8804000 { @@ -3565,10 +3573,10 @@ <&gcc GCC_USB30_PRIM_MASTER_CLK>; assigned-clock-rates = <19200000>, <200000000>; - interrupts = , - , - , - ; + interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 6 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 8 IRQ_TYPE_EDGE_BOTH>, + <&pdc 9 IRQ_TYPE_EDGE_BOTH>; interrupt-names = "hs_phy_irq", "ss_phy_irq", "dm_hs_phy_irq", "dp_hs_phy_irq"; @@ -3589,6 +3597,25 @@ snps,dis_enblslpm_quirk; phys = <&usb_1_hsphy>, <&usb_1_qmpphy QMP_USB43DP_USB3_PHY>; phy-names = "usb2-phy", "usb3-phy"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + usb_1_dwc3_hs: endpoint { + }; + }; + + port@1 { + reg = <1>; + + usb_1_dwc3_ss: endpoint { + }; + }; + }; }; }; @@ -3618,10 +3645,10 @@ <&gcc GCC_USB30_SEC_MASTER_CLK>; assigned-clock-rates = <19200000>, <200000000>; - interrupts = , - , - , - ; + interrupts-extended = <&intc GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 7 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 10 IRQ_TYPE_EDGE_BOTH>, + <&pdc 11 IRQ_TYPE_EDGE_BOTH>; interrupt-names = "hs_phy_irq", "ss_phy_irq", "dm_hs_phy_irq", "dp_hs_phy_irq"; @@ -3640,7 +3667,7 @@ iommus = <&apps_smmu 0x160 0>; snps,dis_u2_susphy_quirk; snps,dis_enblslpm_quirk; - phys = <&usb_2_hsphy>, <&usb_2_ssphy>; + phys = <&usb_2_hsphy>, <&usb_2_qmpphy>; phy-names = "usb2-phy", "usb3-phy"; }; }; @@ -3719,6 +3746,13 @@ remote-endpoint = <&mdss_dsi1_in>; }; }; + + port@2 { + reg = <2>; + dpu_intf0_out: endpoint { + remote-endpoint = <&mdss_dp_in>; + }; + }; }; mdp_opp_table: opp-table { @@ -3746,6 +3780,86 @@ }; }; + mdss_dp: displayport-controller@ae90000 { + compatible = "qcom,sm8150-dp", "qcom,sm8350-dp"; + reg = <0 0xae90000 0 0x200>, + <0 0xae90200 0 0x200>, + <0 0xae90400 0 0x600>, + <0 0x0ae90a00 0 0x600>, + <0 0x0ae91000 0 0x600>; + + interrupt-parent = <&mdss>; + interrupts = <12>; + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_DP_AUX_CLK>, + <&dispcc DISP_CC_MDSS_DP_LINK_CLK>, + <&dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>, + <&dispcc DISP_CC_MDSS_DP_PIXEL_CLK>; + clock-names = "core_iface", + "core_aux", + "ctrl_link", + "ctrl_link_iface", + "stream_pixel"; + + assigned-clocks = <&dispcc DISP_CC_MDSS_DP_LINK_CLK_SRC>, + <&dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>; + assigned-clock-parents = <&usb_1_qmpphy QMP_USB43DP_DP_LINK_CLK>, + <&usb_1_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>; + + phys = <&usb_1_qmpphy QMP_USB43DP_DP_PHY>; + phy-names = "dp"; + + #sound-dai-cells = <0>; + + operating-points-v2 = <&dp_opp_table>; + power-domains = <&rpmhpd SM8250_MMCX>; + + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + mdss_dp_in: endpoint { + remote-endpoint = <&dpu_intf0_out>; + }; + }; + + port@1 { + reg = <1>; + + mdss_dp_out: endpoint { + }; + }; + }; + + dp_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-160000000 { + opp-hz = /bits/ 64 <160000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-270000000 { + opp-hz = /bits/ 64 <270000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-540000000 { + opp-hz = /bits/ 64 <540000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-810000000 { + opp-hz = /bits/ 64 <810000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + mdss_dsi0: dsi@ae94000 { compatible = "qcom,sm8150-dsi-ctrl", "qcom,mdss-dsi-ctrl"; reg = <0 0x0ae94000 0 0x400>; @@ -3932,6 +4046,7 @@ "dp_phy_pll_link_clk", "dp_phy_pll_vco_div_clk"; power-domains = <&rpmhpd SM8150_MMCX>; + required-opps = <&rpmhpd_opp_low_svs>; #clock-cells = <1>; #reset-cells = <1>; #power-domain-cells = <1>; @@ -4170,7 +4285,7 @@ compatible = "qcom,apss-wdt-sm8150", "qcom,kpss-wdt"; reg = <0 0x17c10000 0 0x1000>; clocks = <&sleep_clk>; - interrupts = ; + interrupts = ; }; timer@17c20000 { diff --git a/arch/arm64/boot/dts/qcom/sm8250-xiaomi-elish-common.dtsi b/arch/arm64/boot/dts/qcom/sm8250-xiaomi-elish-common.dtsi index 85e5cf3dc91e1d..946365f15a5985 100644 --- a/arch/arm64/boot/dts/qcom/sm8250-xiaomi-elish-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8250-xiaomi-elish-common.dtsi @@ -6,6 +6,7 @@ #include #include #include +#include #include "sm8250.dtsi" #include "pm8150.dtsi" #include "pm8150b.dtsi" @@ -23,7 +24,7 @@ /delete-node/ &xbl_aop_mem; / { - classis-type = "tablet"; + chassis-type = "tablet"; /* required for bootloader to select correct board */ qcom,msm-id = ; /* SM8250 v2.1 */ @@ -114,7 +115,7 @@ }; reserved-memory { - xbl_aop_mem: xbl-aop@80700000 { + xbl_aop_mem: xbl-aop@80600000 { reg = <0x0 0x80600000 0x0 0x260000>; no-map; }; @@ -627,6 +628,41 @@ }; }; +&pm8150b_typec { + vdd-pdphy-supply = <&vreg_l2a_3p1>; + status = "okay"; + + connector { + compatible = "usb-c-connector"; + + power-role = "source"; + data-role = "dual"; + self-powered; + + source-pdos = ; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + pm8150b_role_switch_in: endpoint { + remote-endpoint = <&usb_1_role_switch_out>; + }; + }; + }; + }; +}; + +&pm8150b_vbus { + status = "okay"; +}; + &pon_pwrkey { status = "okay"; }; @@ -664,11 +700,12 @@ }; &usb_1_dwc3 { - dr_mode = "peripheral"; + dr_mode = "otg"; maximum-speed = "high-speed"; /* Remove USB3 phy */ phys = <&usb_1_hsphy>; phy-names = "usb2-phy"; + usb-role-switch; }; &usb_1_hsphy { @@ -678,6 +715,10 @@ status = "okay"; }; +&usb_1_role_switch_out { + remote-endpoint = <&pm8150b_role_switch_in>; +}; + &ufs_mem_hc { vcc-supply = <&vreg_l17a_3p0>; vcc-max-microamp = <800000>; diff --git a/arch/arm64/boot/dts/qcom/sm8250-xiaomi-pipa.dts b/arch/arm64/boot/dts/qcom/sm8250-xiaomi-pipa.dts new file mode 100644 index 00000000000000..86e1f7fd1c2058 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8250-xiaomi-pipa.dts @@ -0,0 +1,623 @@ +// SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +/* + * Copyright (c) 2023 Luka Panio + */ + +/dts-v1/; + +#include +#include +#include +#include "sm8250.dtsi" +#include "pm8150.dtsi" +#include "pm8150b.dtsi" +#include "pm8150l.dtsi" +#include "pm8009.dtsi" + +/* + * Delete following upstream (sm8250.dtsi) reserved + * memory mappings which are different on this device. + */ +/delete-node/ &adsp_mem; +/delete-node/ &cdsp_secure_heap; +/delete-node/ &slpi_mem; +/delete-node/ &spss_mem; +/delete-node/ &xbl_aop_mem; + +/ { + + model = "Xiaomi Pad 6"; + compatible = "xiaomi,pipa", "qcom,sm8250"; + + chassis-type = "tablet"; + + /* required for bootloader to select correct board */ + qcom,msm-id = ; /* SM8250 v2.1 */ + qcom,board-id = <0x34 0>; + + chosen { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + framebuffer: framebuffer@9c000000 { + compatible = "simple-framebuffer"; + reg = <0x0 0x9c000000 0x0 0x2300000>; + width = <1800>; + height = <2880>; + stride = <(1800 * 4)>; + format = "a8r8g8b8"; + }; + }; + + battery_l: battery-l { + compatible = "simple-battery"; + voltage-min-design-microvolt = <3870000>; + energy-full-design-microwatt-hours = <16700000>; + charge-full-design-microamp-hours = <4420000>; + }; + + battery_r: battery-r { + compatible = "simple-battery"; + voltage-min-design-microvolt = <3870000>; + energy-full-design-microwatt-hours = <16700000>; + charge-full-design-microamp-hours = <4420000>; + }; + + bl_vddpos_5p5: bl-vddpos-regulator { + compatible = "regulator-fixed"; + regulator-name = "bl_vddpos_5p5"; + regulator-min-microvolt = <5500000>; + regulator-max-microvolt = <5500000>; + regulator-enable-ramp-delay = <233>; + gpio = <&tlmm 130 GPIO_ACTIVE_HIGH>; + enable-active-high; + regulator-boot-on; + }; + + bl_vddneg_5p5: bl-vddneg-regulator { + compatible = "regulator-fixed"; + regulator-name = "bl_vddneg_5p5"; + regulator-min-microvolt = <5500000>; + regulator-max-microvolt = <5500000>; + regulator-enable-ramp-delay = <233>; + gpio = <&tlmm 131 GPIO_ACTIVE_HIGH>; + enable-active-high; + regulator-boot-on; + }; + + gpio_keys: gpio-keys { + compatible = "gpio-keys"; + + pinctrl-0 = <&vol_up_n>; + pinctrl-names = "default"; + + key-vol-up { + label = "Volume Up"; + gpios = <&pm8150_gpios 6 GPIO_ACTIVE_LOW>; + linux,code = ; + debounce-interval = <15>; + linux,can-disable; + wakeup-source; + }; + }; + + vph_pwr: vph-pwr-regulator { + compatible = "regulator-fixed"; + regulator-name = "vph_pwr"; + regulator-min-microvolt = <3700000>; + regulator-max-microvolt = <3700000>; + }; + + /* S6c is really ebi.lvl but it's there for supply map completeness sake. */ + vreg_s6c_0p88: smpc6-regulator { + compatible = "regulator-fixed"; + regulator-name = "vreg_s6c_0p88"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + regulator-always-on; + vin-supply = <&vph_pwr>; + }; + + reserved-memory { + xbl_aop_mem: xbl-aop@80700000 { + reg = <0x0 0x80600000 0x0 0x260000>; + no-map; + }; + + slpi_mem: slpi@88c00000 { + reg = <0x0 0x88c00000 0x0 0x2f00000>; + no-map; + }; + + adsp_mem: adsp@8bb00000 { + reg = <0x0 0x8bb00000 0x0 0x2500000>; + no-map; + }; + + spss_mem: spss@8e000000 { + reg = <0x0 0x8e000000 0x0 0x100000>; + no-map; + }; + + cdsp_secure_heap: cdsp-secure-heap@8e100000 { + reg = <0x0 0x8e100000 0x0 0x4600000>; + no-map; + }; + + cont_splash_mem: cont-splash@9c000000 { + reg = <0x0 0x9c000000 0x0 0x2300000>; + no-map; + }; + + ramoops@b0000000 { + compatible = "ramoops"; + reg = <0x0 0xb0000000 0x0 0x400000>; + record-size = <0x1000>; + console-size = <0x200000>; + ecc-size = <16>; + no-map; + }; + }; +}; + +&adsp { + firmware-name = "qcom/sm8250/xiaomi/pipa/adsp.mbn"; + status = "okay"; +}; + +&apps_rsc { + regulators-0 { + compatible = "qcom,pm8150-rpmh-regulators"; + qcom,pmic-id = "a"; + + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vph_pwr>; + vdd-s3-supply = <&vph_pwr>; + vdd-s4-supply = <&vph_pwr>; + vdd-s5-supply = <&vph_pwr>; + vdd-s6-supply = <&vph_pwr>; + vdd-s7-supply = <&vph_pwr>; + vdd-s8-supply = <&vph_pwr>; + vdd-s9-supply = <&vph_pwr>; + vdd-s10-supply = <&vph_pwr>; + vdd-l1-l8-l11-supply = <&vreg_s6c_0p88>; + vdd-l2-l10-supply = <&vreg_bob>; + vdd-l3-l4-l5-l18-supply = <&vreg_s6a_0p95>; + vdd-l6-l9-supply = <&vreg_s8c_1p35>; + vdd-l7-l12-l14-l15-supply = <&vreg_s5a_1p9>; + vdd-l13-l16-l17-supply = <&vreg_bob>; + + /* (S1+S2+S3) - cx.lvl (ARC) */ + + vreg_s4a_1p8: smps4 { + regulator-name = "vreg_s4a_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1920000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_s5a_1p9: smps5 { + regulator-name = "vreg_s5a_1p9"; + regulator-min-microvolt = <1900000>; + regulator-max-microvolt = <2040000>; + regulator-initial-mode = ; + }; + + vreg_s6a_0p95: smps6 { + regulator-name = "vreg_s6a_0p95"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1128000>; + regulator-initial-mode = ; + }; + + vreg_l2a_3p1: ldo2 { + regulator-name = "vreg_l2a_3p1"; + regulator-min-microvolt = <3072000>; + regulator-max-microvolt = <3072000>; + regulator-initial-mode = ; + }; + + vreg_l3a_0p9: ldo3 { + regulator-name = "vreg_l3a_0p9"; + regulator-min-microvolt = <928000>; + regulator-max-microvolt = <932000>; + regulator-initial-mode = ; + }; + + /* L4 - lmx.lvl (ARC) */ + + vreg_l5a_0p88: ldo5 { + regulator-name = "vreg_l5a_0p88"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + regulator-initial-mode = ; + }; + + vreg_l6a_1p2: ldo6 { + regulator-name = "vreg_l6a_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + /* L7 is unused. */ + + vreg_l9a_1p2: ldo9 { + regulator-name = "vreg_l9a_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + /* L10 is unused, L11 - lcx.lvl (ARC) */ + + vreg_l12a_1p8: ldo12 { + regulator-name = "vreg_l12a_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + /* L13 is unused. */ + + vreg_l14a_1p88: ldo14 { + regulator-name = "vreg_l14a_1p88"; + regulator-min-microvolt = <1880000>; + regulator-max-microvolt = <1880000>; + regulator-initial-mode = ; + }; + + /* L15 & L16 are unused. */ + + vreg_l17a_3p0: ldo17 { + regulator-name = "vreg_l17a_3p0"; + regulator-min-microvolt = <2496000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l18a_0p9: ldo18 { + regulator-name = "vreg_l18a_0p9"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + }; + + regulators-1 { + compatible = "qcom,pm8150l-rpmh-regulators"; + qcom,pmic-id = "c"; + + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vph_pwr>; + vdd-s3-supply = <&vph_pwr>; + vdd-s4-supply = <&vph_pwr>; + vdd-s5-supply = <&vph_pwr>; + vdd-s6-supply = <&vph_pwr>; + vdd-s7-supply = <&vph_pwr>; + vdd-s8-supply = <&vph_pwr>; + vdd-l1-l8-supply = <&vreg_s4a_1p8>; + vdd-l2-l3-supply = <&vreg_s8c_1p35>; + vdd-l4-l5-l6-supply = <&vreg_bob>; + vdd-l7-l11-supply = <&vreg_bob>; + vdd-l9-l10-supply = <&vreg_bob>; + vdd-bob-supply = <&vph_pwr>; + + vreg_bob: bob { + regulator-name = "vreg_bob"; + regulator-min-microvolt = <3350000>; + regulator-max-microvolt = <3960000>; + regulator-initial-mode = ; + }; + + /* + * S1-S6 are ARCs: + * (S1+S2) - gfx.lvl, + * S3 - mx.lvl, + * (S4+S5) - mmcx.lvl, + * S6 - ebi.lvl + */ + + vreg_s7c_0p35: smps7 { + regulator-name = "vreg_s7c_0p35"; + regulator-min-microvolt = <348000>; + regulator-max-microvolt = <1000000>; + regulator-initial-mode = ; + }; + + vreg_s8c_1p35: smps8 { + regulator-name = "vreg_s8c_1p35"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1400000>; + regulator-initial-mode = ; + }; + + vreg_l1c_1p8: ldo1 { + regulator-name = "vreg_l1c_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + /* L2-4 are unused. */ + + vreg_l5c_1p8: ldo5 { + regulator-name = "vreg_l5c_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2800000>; + regulator-initial-mode = ; + }; + + vreg_l6c_2p9: ldo6 { + regulator-name = "vreg_l6c_2p9"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l7c_2p85: ldo7 { + regulator-name = "vreg_l7c_2p85"; + regulator-min-microvolt = <2856000>; + regulator-max-microvolt = <3104000>; + regulator-initial-mode = ; + }; + + vreg_l8c_1p8: ldo8 { + regulator-name = "vreg_l8c_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l9c_2p9: ldo9 { + regulator-name = "vreg_l9c_2p9"; + regulator-min-microvolt = <2704000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l10c_3p3: ldo10 { + regulator-name = "vreg_l10c_3p3"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3312000>; + regulator-initial-mode = ; + }; + + vreg_l11c_3p0: ldo11 { + regulator-name = "vreg_l11c_3p0"; + regulator-min-microvolt = <3104000>; + regulator-max-microvolt = <3304000>; + regulator-initial-mode = ; + }; + }; + + regulators-2 { + compatible = "qcom,pm8009-rpmh-regulators"; + qcom,pmic-id = "f"; + + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vreg_bob>; + vdd-l2-supply = <&vreg_s8c_1p35>; + vdd-l5-l6-supply = <&vreg_bob>; + vdd-l7-supply = <&vreg_s4a_1p8>; + + vreg_s1f_1p2: smps1 { + regulator-name = "vreg_s1f_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1300000>; + regulator-initial-mode = ; + }; + + vreg_s2f_0p5: smps2 { + regulator-name = "vreg_s2f_0p5"; + regulator-min-microvolt = <512000>; + regulator-max-microvolt = <1100000>; + regulator-initial-mode = ; + }; + + /* L1 is unused. */ + + vreg_l2f_1p3: ldo2 { + regulator-name = "vreg_l2f_1p3"; + regulator-min-microvolt = <1056000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + /* L3 & L4 are unused. */ + + vreg_l5f_2p8: ldo5 { + regulator-name = "vreg_l5f_2p85"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3000000>; + regulator-initial-mode = ; + }; + + vreg_l6f_2p8: ldo6 { + regulator-name = "vreg_l6f_2p8"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3000000>; + regulator-initial-mode = ; + }; + + vreg_l7f_1p8: ldo7 { + regulator-name = "vreg_l7f_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + }; +}; + +&cdsp { + firmware-name = "qcom/sm8250/xiaomi/pipa/cdsp.mbn"; + status = "okay"; +}; + +&gmu { + status = "okay"; +}; + +&gpi_dma0 { + status = "okay"; +}; + +&gpi_dma1 { + status = "okay"; +}; + +&gpi_dma2 { + status = "okay"; +}; + +&gpu { + status = "okay"; + + zap-shader { + memory-region = <&gpu_mem>; + firmware-name = "qcom/sm8250/xiaomi/pipa/a650_zap.mbn"; + }; +}; + +&i2c0 { + clock-frequency = <400000>; + status = "okay"; + + fuel-gauge@55 { + compatible = "ti,bq27z561"; + reg = <0x55>; + monitored-battery = <&battery_r>; + }; +}; + +&i2c11 { + clock-frequency = <400000>; + status = "okay"; + + backlight: backlight@11 { + compatible = "kinetic,ktz8866"; + reg = <0x11>; + vddpos-supply = <&bl_vddpos_5p5>; + vddneg-supply = <&bl_vddneg_5p5>; + enable-gpios = <&tlmm 139 GPIO_ACTIVE_HIGH>; + current-num-sinks = <5>; + kinetic,current-ramp-delay-ms = <128>; + kinetic,led-enable-ramp-delay-ms = <1>; + kinetic,enable-lcd-bias; + }; +}; + +&i2c13 { + clock-frequency = <400000>; + status = "okay"; + + fuel-gauge@55 { + compatible = "ti,bq27z561"; + reg = <0x55>; + monitored-battery = <&battery_l>; + }; +}; + +&pcie0 { + status = "okay"; +}; + +&pcie0_phy { + vdda-phy-supply = <&vreg_l5a_0p88>; + vdda-pll-supply = <&vreg_l9a_1p2>; + status = "okay"; +}; + +&pm8150_gpios { + vol_up_n: vol-up-n-state { + pins = "gpio6"; + function = "normal"; + power-source = <1>; + input-enable; + bias-pull-up; + }; +}; + +&pon_pwrkey { + status = "okay"; +}; + +&pon_resin { + linux,code = ; + status = "okay"; +}; + +&qupv3_id_0 { + status = "okay"; +}; + +&qupv3_id_1 { + status = "okay"; +}; + +&qupv3_id_2 { + status = "okay"; +}; + +&slpi { + firmware-name = "qcom/sm8250/xiaomi/pipa/slpi.mbn"; + status = "okay"; +}; + +&usb_1 { + status = "okay"; +}; + +&usb_1_dwc3 { + dr_mode = "peripheral"; +}; + +&usb_1_hsphy { + vdda-pll-supply = <&vreg_l5a_0p88>; + vdda18-supply = <&vreg_l12a_1p8>; + vdda33-supply = <&vreg_l2a_3p1>; + status = "okay"; +}; + +&usb_1_qmpphy { + status = "okay"; + vdda-phy-supply = <&vreg_l9a_1p2>; + vdda-pll-supply = <&vreg_l18a_0p9>; +}; + +&ufs_mem_hc { + vcc-supply = <&vreg_l17a_3p0>; + vcc-max-microamp = <800000>; + vccq-supply = <&vreg_l6a_1p2>; + vccq-max-microamp = <800000>; + vccq2-supply = <&vreg_s4a_1p8>; + vccq2-max-microamp = <800000>; + status = "okay"; +}; + +&ufs_mem_phy { + vdda-phy-supply = <&vreg_l5a_0p88>; + vdda-pll-supply = <&vreg_l9a_1p2>; + status = "okay"; +}; + +&venus { + firmware-name = "qcom/sm8250/xiaomi/pipa/venus.mbn"; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8250.dtsi b/arch/arm64/boot/dts/qcom/sm8250.dtsi index be970472f6c4e7..760501c1301a62 100644 --- a/arch/arm64/boot/dts/qcom/sm8250.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8250.dtsi @@ -671,6 +671,7 @@ firmware { scm: scm { compatible = "qcom,scm-sm8250", "qcom,scm"; + qcom,dload-mode = <&tcsr 0x13000>; #reset-cells = <1>; }; }; @@ -2123,7 +2124,7 @@ qcom,bcm-voters = <&apps_bcm_voter>; }; - pcie0: pci@1c00000 { + pcie0: pcie@1c00000 { compatible = "qcom,pcie-sm8250"; reg = <0 0x01c00000 0 0x3000>, <0 0x60000000 0 0xf1d>, @@ -2227,7 +2228,7 @@ status = "disabled"; }; - pcie1: pci@1c08000 { + pcie1: pcie@1c08000 { compatible = "qcom,pcie-sm8250"; reg = <0 0x01c08000 0 0x3000>, <0 0x40000000 0 0xf1d>, @@ -2328,7 +2329,7 @@ status = "disabled"; }; - pcie2: pci@1c10000 { + pcie2: pcie@1c10000 { compatible = "qcom,pcie-sm8250"; reg = <0 0x01c10000 0 0x3000>, <0 0x64000000 0 0xf1d>, @@ -2434,7 +2435,7 @@ "jedec,ufs-2.0"; reg = <0 0x01d84000 0 0x3000>; interrupts = ; - phys = <&ufs_mem_phy_lanes>; + phys = <&ufs_mem_phy>; phy-names = "ufsphy"; lanes-per-direction = <2>; #reset-cells = <1>; @@ -2463,29 +2464,48 @@ <&gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>, <&gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>, <&gcc GCC_UFS_PHY_RX_SYMBOL_1_CLK>; - freq-table-hz = - <37500000 300000000>, - <0 0>, - <0 0>, - <37500000 300000000>, - <0 0>, - <0 0>, - <0 0>, - <0 0>; + + operating-points-v2 = <&ufs_opp_table>; interconnects = <&aggre1_noc MASTER_UFS_MEM 0 &mc_virt SLAVE_EBI_CH0 0>, <&gem_noc MASTER_AMPSS_M0 0 &config_noc SLAVE_UFS_MEM_CFG 0>; interconnect-names = "ufs-ddr", "cpu-ufs"; status = "disabled"; + + ufs_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-37500000 { + opp-hz = /bits/ 64 <37500000>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <37500000>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <0>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <300000000>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <0>, + /bits/ 64 <0>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; }; ufs_mem_phy: phy@1d87000 { compatible = "qcom,sm8250-qmp-ufs-phy"; - reg = <0 0x01d87000 0 0x1c0>; - #address-cells = <2>; - #size-cells = <2>; - ranges; + reg = <0 0x01d87000 0 0x1000>; + clock-names = "ref", "ref_aux"; clocks = <&rpmhcc RPMH_CXO_CLK>, @@ -2493,16 +2513,10 @@ resets = <&ufs_mem_hc 0>; reset-names = "ufsphy"; - status = "disabled"; - ufs_mem_phy_lanes: phy@1d87400 { - reg = <0 0x01d87400 0 0x16c>, - <0 0x01d87600 0 0x200>, - <0 0x01d87c00 0 0x200>, - <0 0x01d87800 0 0x16c>, - <0 0x01d87a00 0 0x200>; - #phy-cells = <0>; - }; + #phy-cells = <0>; + + status = "disabled"; }; cryptobam: dma-controller@1dc4000 { @@ -2543,6 +2557,11 @@ #hwlock-cells = <1>; }; + tcsr: syscon@1fc0000 { + compatible = "qcom,sm8250-tcsr", "syscon"; + reg = <0x0 0x1fc0000 0x0 0x30000>; + }; + wsamacro: codec@3240000 { compatible = "qcom,sm8250-lpass-wsa-macro"; reg = <0 0x03240000 0 0x1000>; @@ -2565,7 +2584,7 @@ status = "disabled"; }; - swr0: soundwire-controller@3250000 { + swr0: soundwire@3250000 { reg = <0 0x03250000 0 0x2000>; compatible = "qcom,soundwire-v1.5.1"; interrupts = ; @@ -2631,7 +2650,7 @@ #sound-dai-cells = <1>; }; - swr1: soundwire-controller@3210000 { + swr1: soundwire@3210000 { reg = <0 0x03210000 0 0x2000>; compatible = "qcom,soundwire-v1.5.1"; status = "disabled"; @@ -2678,7 +2697,7 @@ }; /* tx macro */ - swr2: soundwire-controller@3230000 { + swr2: soundwire@3230000 { reg = <0 0x03230000 0 0x2000>; compatible = "qcom,soundwire-v1.5.1"; interrupts = ; @@ -3095,11 +3114,8 @@ clock-names = "apb_pclk"; out-ports { - #address-cells = <1>; - #size-cells = <0>; - port@0 { - reg = <0>; + port { tpda_out_funnel_qatb: endpoint { remote-endpoint = <&funnel_qatb_in_tpda>; }; @@ -3142,11 +3158,7 @@ }; in-ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; + port { funnel_qatb_in_tpda: endpoint { remote-endpoint = <&tpda_out_funnel_qatb>; }; @@ -3355,11 +3367,8 @@ }; in-ports { - #address-cells = <1>; - #size-cells = <0>; - port@0 { - reg = <0>; + port { etf_in_funnel_swao_out: endpoint { remote-endpoint = <&funnel_swao_out_etf>; }; @@ -3443,8 +3452,6 @@ clock-names = "apb_pclk"; out-ports { - #address-cells = <1>; - #size-cells = <0>; port { tpdm_mm_out_tpda9: endpoint { remote-endpoint = <&tpda_9_in_tpdm_mm>; @@ -3710,11 +3717,7 @@ }; in-ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; + port { funnel_apss_merg_in_funnel_apss: endpoint { remote-endpoint = <&funnel_apss_out_funnel_apss_merg>; }; @@ -3889,32 +3892,26 @@ usb_2_qmpphy: phy@88eb000 { compatible = "qcom,sm8250-qmp-usb3-uni-phy"; - reg = <0 0x088eb000 0 0x200>; - status = "disabled"; - #address-cells = <2>; - #size-cells = <2>; - ranges; + reg = <0 0x088eb000 0 0x1000>; clocks = <&gcc GCC_USB3_SEC_PHY_AUX_CLK>, - <&rpmhcc RPMH_CXO_CLK>, <&gcc GCC_USB3_SEC_CLKREF_EN>, - <&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>; - clock-names = "aux", "ref_clk_src", "ref", "com_aux"; + <&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>, + <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>; + clock-names = "aux", + "ref", + "com_aux", + "pipe"; + clock-output-names = "usb3_uni_phy_pipe_clk_src"; + #clock-cells = <0>; + #phy-cells = <0>; - resets = <&gcc GCC_USB3PHY_PHY_SEC_BCR>, - <&gcc GCC_USB3_PHY_SEC_BCR>; - reset-names = "phy", "common"; + resets = <&gcc GCC_USB3_PHY_SEC_BCR>, + <&gcc GCC_USB3PHY_PHY_SEC_BCR>; + reset-names = "phy", + "phy_phy"; - usb_2_ssphy: phy@88eb200 { - reg = <0 0x088eb200 0 0x200>, - <0 0x088eb400 0 0x200>, - <0 0x088eb800 0 0x800>; - #clock-cells = <0>; - #phy-cells = <0>; - clocks = <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>; - clock-names = "pipe0"; - clock-output-names = "usb3_uni_phy_pipe_clk_src"; - }; + status = "disabled"; }; sdhc_2: mmc@8804000 { @@ -4141,6 +4138,7 @@ "dp_hs_phy_irq"; power-domains = <&gcc USB30_PRIM_GDSC>; + wakeup-source; resets = <&gcc GCC_USB30_PRIM_BCR>; @@ -4209,6 +4207,7 @@ "dp_hs_phy_irq"; power-domains = <&gcc USB30_SEC_GDSC>; + wakeup-source; resets = <&gcc GCC_USB30_SEC_BCR>; @@ -4223,7 +4222,7 @@ iommus = <&apps_smmu 0x20 0>; snps,dis_u2_susphy_quirk; snps,dis_enblslpm_quirk; - phys = <&usb_2_hsphy>, <&usb_2_ssphy>; + phys = <&usb_2_hsphy>, <&usb_2_qmpphy>; phy-names = "usb2-phy", "usb3-phy"; }; }; @@ -6018,7 +6017,7 @@ compatible = "qcom,apss-wdt-sm8250", "qcom,kpss-wdt"; reg = <0 0x17c10000 0 0x1000>; clocks = <&sleep_clk>; - interrupts = ; + interrupts = ; }; timer@17c20000 { diff --git a/arch/arm64/boot/dts/qcom/sm8350.dtsi b/arch/arm64/boot/dts/qcom/sm8350.dtsi index b46236235b7f4b..e78c83a897c283 100644 --- a/arch/arm64/boot/dts/qcom/sm8350.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8350.dtsi @@ -289,6 +289,7 @@ firmware { scm: scm { compatible = "qcom,scm-sm8350", "qcom,scm"; + qcom,dload-mode = <&tcsr 0x13000>; #reset-cells = <1>; }; }; @@ -677,9 +678,9 @@ <0>, <0>, <0>, - <&ufs_mem_phy_lanes 0>, - <&ufs_mem_phy_lanes 1>, - <&ufs_mem_phy_lanes 2>, + <&ufs_mem_phy 0>, + <&ufs_mem_phy 1>, + <&ufs_mem_phy 2>, <&usb_1_qmpphy QMP_USB43DP_USB3_PIPE_CLK>, <0>; }; @@ -919,9 +920,9 @@ }; }; - gpi_dma0: dma-controller@9800000 { + gpi_dma0: dma-controller@900000 { compatible = "qcom,sm8350-gpi-dma", "qcom,sm6350-gpi-dma"; - reg = <0 0x09800000 0 0x60000>; + reg = <0 0x00900000 0 0x60000>; interrupts = , , , @@ -1498,7 +1499,7 @@ qcom,bcm-voters = <&apps_bcm_voter>; }; - pcie0: pci@1c00000 { + pcie0: pcie@1c00000 { compatible = "qcom,pcie-sm8350"; reg = <0 0x01c00000 0 0x3000>, <0 0x60000000 0 0xf1d>, @@ -1591,7 +1592,7 @@ status = "disabled"; }; - pcie1: pci@1c08000 { + pcie1: pcie@1c08000 { compatible = "qcom,pcie-sm8350"; reg = <0 0x01c08000 0 0x3000>, <0 0x40000000 0 0xf1d>, @@ -1679,7 +1680,7 @@ "jedec,ufs-2.0"; reg = <0 0x01d84000 0 0x3000>; interrupts = ; - phys = <&ufs_mem_phy_lanes>; + phys = <&ufs_mem_phy>; phy-names = "ufsphy"; lanes-per-direction = <2>; #reset-cells = <1>; @@ -1723,10 +1724,8 @@ ufs_mem_phy: phy@1d87000 { compatible = "qcom,sm8350-qmp-ufs-phy"; - reg = <0 0x01d87000 0 0x1c4>; - #address-cells = <2>; - #size-cells = <2>; - ranges; + reg = <0 0x01d87000 0 0x1000>; + clock-names = "ref", "ref_aux"; clocks = <&rpmhcc RPMH_CXO_CLK>, @@ -1734,17 +1733,11 @@ resets = <&ufs_mem_hc 0>; reset-names = "ufsphy"; - status = "disabled"; - ufs_mem_phy_lanes: phy@1d87400 { - reg = <0 0x01d87400 0 0x188>, - <0 0x01d87600 0 0x200>, - <0 0x01d87c00 0 0x200>, - <0 0x01d87800 0 0x188>, - <0 0x01d87a00 0 0x200>; - #clock-cells = <1>; - #phy-cells = <0>; - }; + #clock-cells = <1>; + #phy-cells = <0>; + + status = "disabled"; }; cryptobam: dma-controller@1dc4000 { @@ -1818,6 +1811,11 @@ #hwlock-cells = <1>; }; + tcsr: syscon@1fc0000 { + compatible = "qcom,sm8350-tcsr", "syscon"; + reg = <0x0 0x1fc0000 0x0 0x30000>; + }; + lpass_tlmm: pinctrl@33c0000 { compatible = "qcom,sm8350-lpass-lpi-pinctrl"; reg = <0 0x033c0000 0 0x20000>, @@ -2021,7 +2019,7 @@ compatible = "qcom,sm8350-mpss-pas"; reg = <0x0 0x04080000 0x0 0x4040>; - interrupts-extended = <&intc GIC_SPI 264 IRQ_TYPE_LEVEL_HIGH>, + interrupts-extended = <&intc GIC_SPI 264 IRQ_TYPE_EDGE_RISING>, <&smp2p_modem_in 0 IRQ_TYPE_EDGE_RISING>, <&smp2p_modem_in 1 IRQ_TYPE_EDGE_RISING>, <&smp2p_modem_in 2 IRQ_TYPE_EDGE_RISING>, @@ -2063,7 +2061,7 @@ compatible = "qcom,sm8350-slpi-pas"; reg = <0 0x05c00000 0 0x4000>; - interrupts-extended = <&pdc 9 IRQ_TYPE_LEVEL_HIGH>, + interrupts-extended = <&pdc 9 IRQ_TYPE_EDGE_RISING>, <&smp2p_slpi_in 0 IRQ_TYPE_EDGE_RISING>, <&smp2p_slpi_in 1 IRQ_TYPE_EDGE_RISING>, <&smp2p_slpi_in 2 IRQ_TYPE_EDGE_RISING>, @@ -2238,34 +2236,27 @@ }; }; - usb_2_qmpphy: phy-wrapper@88eb000 { + usb_2_qmpphy: phy@88eb000 { compatible = "qcom,sm8350-qmp-usb3-uni-phy"; - reg = <0 0x088eb000 0 0x200>; + reg = <0 0x088eb000 0 0x2000>; status = "disabled"; - #address-cells = <2>; - #size-cells = <2>; - ranges; clocks = <&gcc GCC_USB3_SEC_PHY_AUX_CLK>, - <&rpmhcc RPMH_CXO_CLK>, <&gcc GCC_USB3_SEC_CLKREF_EN>, - <&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>; - clock-names = "aux", "ref_clk_src", "ref", "com_aux"; - - resets = <&gcc GCC_USB3PHY_PHY_SEC_BCR>, - <&gcc GCC_USB3_PHY_SEC_BCR>; - reset-names = "phy", "common"; + <&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>, + <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>; + clock-names = "aux", + "ref", + "com_aux", + "pipe"; + clock-output-names = "usb3_uni_phy_pipe_clk_src"; + #clock-cells = <0>; + #phy-cells = <0>; - usb_2_ssphy: phy@88ebe00 { - reg = <0 0x088ebe00 0 0x200>, - <0 0x088ec000 0 0x200>, - <0 0x088eb200 0 0x1100>; - #phy-cells = <0>; - #clock-cells = <0>; - clocks = <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>; - clock-names = "pipe0"; - clock-output-names = "usb3_uni_phy_pipe_clk_src"; - }; + resets = <&gcc GCC_USB3_PHY_SEC_BCR>, + <&gcc GCC_USB3PHY_PHY_SEC_BCR>; + reset-names = "phy", + "phy_phy"; }; dc_noc: interconnect@90c0000 { @@ -2418,7 +2409,7 @@ iommus = <&apps_smmu 0x20 0x0>; snps,dis_u2_susphy_quirk; snps,dis_enblslpm_quirk; - phys = <&usb_2_hsphy>, <&usb_2_ssphy>; + phys = <&usb_2_hsphy>, <&usb_2_qmpphy>; phy-names = "usb2-phy", "usb3-phy"; }; }; @@ -2453,35 +2444,6 @@ #size-cells = <2>; ranges; - dpu_opp_table: opp-table { - compatible = "operating-points-v2"; - - /* TODO: opp-200000000 should work with - * &rpmhpd_opp_low_svs, but one some of - * sm8350_hdk boards reboot using this - * opp. - */ - opp-200000000 { - opp-hz = /bits/ 64 <200000000>; - required-opps = <&rpmhpd_opp_svs>; - }; - - opp-300000000 { - opp-hz = /bits/ 64 <300000000>; - required-opps = <&rpmhpd_opp_svs>; - }; - - opp-345000000 { - opp-hz = /bits/ 64 <345000000>; - required-opps = <&rpmhpd_opp_svs_l1>; - }; - - opp-460000000 { - opp-hz = /bits/ 64 <460000000>; - required-opps = <&rpmhpd_opp_nom>; - }; - }; - mdss_mdp: display-controller@ae01000 { compatible = "qcom,sm8350-dpu"; reg = <0 0x0ae01000 0 0x8f000>, @@ -2510,6 +2472,35 @@ interrupt-parent = <&mdss>; interrupts = <0>; + dpu_opp_table: opp-table { + compatible = "operating-points-v2"; + + /* TODO: opp-200000000 should work with + * &rpmhpd_opp_low_svs, but one some of + * sm8350_hdk boards reboot using this + * opp. + */ + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-345000000 { + opp-hz = /bits/ 64 <345000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-460000000 { + opp-hz = /bits/ 64 <460000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + ports { #address-cells = <1>; #size-cells = <0>; @@ -3207,7 +3198,7 @@ compatible = "qcom,sm8350-adsp-pas"; reg = <0 0x17300000 0 0x100>; - interrupts-extended = <&pdc 6 IRQ_TYPE_LEVEL_HIGH>, + interrupts-extended = <&pdc 6 IRQ_TYPE_EDGE_RISING>, <&smp2p_adsp_in 0 IRQ_TYPE_EDGE_RISING>, <&smp2p_adsp_in 1 IRQ_TYPE_EDGE_RISING>, <&smp2p_adsp_in 2 IRQ_TYPE_EDGE_RISING>, @@ -3512,7 +3503,7 @@ compatible = "qcom,sm8350-cdsp-pas"; reg = <0 0x98900000 0 0x1400000>; - interrupts-extended = <&intc GIC_SPI 578 IRQ_TYPE_LEVEL_HIGH>, + interrupts-extended = <&intc GIC_SPI 578 IRQ_TYPE_EDGE_RISING>, <&smp2p_cdsp_in 0 IRQ_TYPE_EDGE_RISING>, <&smp2p_cdsp_in 1 IRQ_TYPE_EDGE_RISING>, <&smp2p_cdsp_in 2 IRQ_TYPE_EDGE_RISING>, diff --git a/arch/arm64/boot/dts/qcom/sm8450-hdk.dts b/arch/arm64/boot/dts/qcom/sm8450-hdk.dts index 20153d08eddec8..a20d5d76af352c 100644 --- a/arch/arm64/boot/dts/qcom/sm8450-hdk.dts +++ b/arch/arm64/boot/dts/qcom/sm8450-hdk.dts @@ -580,6 +580,14 @@ status = "okay"; }; +&gpu { + status = "okay"; + + zap-shader { + firmware-name = "qcom/sm8450/a730_zap.mbn"; + }; +}; + &i2c9 { clock-frequency = <400000>; status = "okay"; diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi index 1783fa78bdbcb5..01e4dfc4babd29 100644 --- a/arch/arm64/boot/dts/qcom/sm8450.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -18,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -754,9 +756,9 @@ <&pcie0_phy>, <&pcie1_phy>, <0>, - <&ufs_mem_phy_lanes 0>, - <&ufs_mem_phy_lanes 1>, - <&ufs_mem_phy_lanes 2>, + <&ufs_mem_phy 0>, + <&ufs_mem_phy 1>, + <&ufs_mem_phy 2>, <&usb_1_qmpphy QMP_USB43DP_USB3_PIPE_CLK>; clock-names = "bi_tcxo", "sleep_clk", @@ -1739,7 +1741,12 @@ }; }; - pcie0: pci@1c00000 { + rng: rng@10c3000 { + compatible = "qcom,sm8450-trng", "qcom,trng"; + reg = <0 0x010c3000 0 0x1000>; + }; + + pcie0: pcie@1c00000 { compatible = "qcom,pcie-sm8450-pcie0"; reg = <0 0x01c00000 0 0x3000>, <0 0x60000000 0 0xf1d>, @@ -1848,7 +1855,7 @@ status = "disabled"; }; - pcie1: pci@1c08000 { + pcie1: pcie@1c08000 { compatible = "qcom,pcie-sm8450-pcie1"; reg = <0 0x01c08000 0 0x3000>, <0 0x40000000 0 0xf1d>, @@ -2014,6 +2021,206 @@ reg = <0x0 0x1fc0000 0x0 0x30000>; }; + gpu: gpu@3d00000 { + compatible = "qcom,adreno-730.1", "qcom,adreno"; + reg = <0x0 0x03d00000 0x0 0x40000>, + <0x0 0x03d9e000 0x0 0x1000>, + <0x0 0x03d61000 0x0 0x800>; + reg-names = "kgsl_3d0_reg_memory", + "cx_mem", + "cx_dbgc"; + + interrupts = ; + + iommus = <&adreno_smmu 0 0x400>, + <&adreno_smmu 1 0x400>; + + operating-points-v2 = <&gpu_opp_table>; + + qcom,gmu = <&gmu>; + + status = "disabled"; + + zap-shader { + memory-region = <&gpu_micro_code_mem>; + }; + + gpu_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-818000000 { + opp-hz = /bits/ 64 <818000000>; + opp-level = ; + }; + + opp-791000000 { + opp-hz = /bits/ 64 <791000000>; + opp-level = ; + }; + + opp-734000000 { + opp-hz = /bits/ 64 <734000000>; + opp-level = ; + }; + + opp-640000000 { + opp-hz = /bits/ 64 <640000000>; + opp-level = ; + }; + + opp-599000000 { + opp-hz = /bits/ 64 <599000000>; + opp-level = ; + }; + + opp-545000000 { + opp-hz = /bits/ 64 <545000000>; + opp-level = ; + }; + + opp-492000000 { + opp-hz = /bits/ 64 <492000000>; + opp-level = ; + }; + + opp-421000000 { + opp-hz = /bits/ 64 <421000000>; + opp-level = ; + }; + + opp-350000000 { + opp-hz = /bits/ 64 <350000000>; + opp-level = ; + }; + + opp-317000000 { + opp-hz = /bits/ 64 <317000000>; + opp-level = ; + }; + + opp-285000000 { + opp-hz = /bits/ 64 <285000000>; + opp-level = ; + }; + + opp-220000000 { + opp-hz = /bits/ 64 <220000000>; + opp-level = ; + }; + }; + }; + + gmu: gmu@3d6a000 { + compatible = "qcom,adreno-gmu-730.1", "qcom,adreno-gmu"; + reg = <0x0 0x03d6a000 0x0 0x35000>, + <0x0 0x03d50000 0x0 0x10000>, + <0x0 0x0b290000 0x0 0x10000>; + reg-names = "gmu", "rscc", "gmu_pdc"; + + interrupts = , + ; + interrupt-names = "hfi", "gmu"; + + clocks = <&gpucc GPU_CC_AHB_CLK>, + <&gpucc GPU_CC_CX_GMU_CLK>, + <&gpucc GPU_CC_CXO_CLK>, + <&gcc GCC_DDRSS_GPU_AXI_CLK>, + <&gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&gpucc GPU_CC_HUB_CX_INT_CLK>, + <&gpucc GPU_CC_DEMET_CLK>; + clock-names = "ahb", + "gmu", + "cxo", + "axi", + "memnoc", + "hub", + "demet"; + + power-domains = <&gpucc GPU_CX_GDSC>, + <&gpucc GPU_GX_GDSC>; + power-domain-names = "cx", + "gx"; + + iommus = <&adreno_smmu 5 0x400>; + + qcom,qmp = <&aoss_qmp>; + + operating-points-v2 = <&gmu_opp_table>; + + gmu_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-500000000 { + opp-hz = /bits/ 64 <500000000>; + opp-level = ; + }; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + opp-level = ; + }; + }; + }; + + gpucc: clock-controller@3d90000 { + compatible = "qcom,sm8450-gpucc"; + reg = <0x0 0x03d90000 0x0 0xa000>; + clocks = <&rpmhcc RPMH_CXO_CLK>, + <&gcc GCC_GPU_GPLL0_CLK_SRC>, + <&gcc GCC_GPU_GPLL0_DIV_CLK_SRC>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; + + adreno_smmu: iommu@3da0000 { + compatible = "qcom,sm8450-smmu-500", "qcom,adreno-smmu", + "qcom,smmu-500", "arm,mmu-500"; + reg = <0x0 0x03da0000 0x0 0x40000>; + #iommu-cells = <2>; + #global-interrupts = <1>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + clocks = <&gpucc GPU_CC_CX_GMU_CLK>, + <&gpucc GPU_CC_HUB_CX_INT_CLK>, + <&gpucc GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK>, + <&gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&gcc GCC_GPU_SNOC_DVM_GFX_CLK>, + <&gpucc GPU_CC_AHB_CLK>; + clock-names = "gmu", + "hub", + "hlos", + "bus", + "iface", + "ahb"; + power-domains = <&gpucc GPU_CX_GDSC>; + dma-coherent; + }; + usb_1_hsphy: phy@88e3000 { compatible = "qcom,sm8450-usb-hs-phy", "qcom,usb-snps-hs-7nm-phy"; @@ -2149,18 +2356,13 @@ <&q6prmcc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, <&vamacro>; clock-names = "mclk", "npl", "macro", "dcodec", "fsgen"; - assigned-clocks = <&q6prmcc LPASS_CLK_ID_WSA2_CORE_TX_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>, - <&q6prmcc LPASS_CLK_ID_WSA2_CORE_TX_2X_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>; - assigned-clock-rates = <19200000>, <19200000>; #clock-cells = <0>; clock-output-names = "wsa2-mclk"; - pinctrl-names = "default"; - pinctrl-0 = <&wsa2_swr_active>; #sound-dai-cells = <1>; }; - swr4: soundwire-controller@31f0000 { + swr4: soundwire@31f0000 { compatible = "qcom,soundwire-v1.7.0"; reg = <0 0x031f0000 0 0x2000>; interrupts = ; @@ -2168,6 +2370,9 @@ clock-names = "iface"; label = "WSA2"; + pinctrl-0 = <&wsa2_swr_active>; + pinctrl-names = "default"; + qcom,din-ports = <2>; qcom,dout-ports = <6>; @@ -2197,18 +2402,12 @@ <&vamacro>; clock-names = "mclk", "npl", "macro", "dcodec", "fsgen"; - assigned-clocks = <&q6prmcc LPASS_CLK_ID_RX_CORE_TX_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>, - <&q6prmcc LPASS_CLK_ID_RX_CORE_MCLK2_2X_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>; - assigned-clock-rates = <19200000>, <19200000>; - #clock-cells = <0>; clock-output-names = "mclk"; - pinctrl-names = "default"; - pinctrl-0 = <&rx_swr_active>; #sound-dai-cells = <1>; }; - swr1: soundwire-controller@3210000 { + swr1: soundwire@3210000 { compatible = "qcom,soundwire-v1.7.0"; reg = <0 0x03210000 0 0x2000>; interrupts = ; @@ -2218,6 +2417,9 @@ qcom,din-ports = <0>; qcom,dout-ports = <5>; + pinctrl-0 = <&rx_swr_active>; + pinctrl-names = "default"; + qcom,ports-sinterval-low = /bits/ 8 <0x03 0x1f 0x1f 0x07 0x00>; qcom,ports-offset1 = /bits/ 8 <0x00 0x00 0x0b 0x01 0x00>; qcom,ports-offset2 = /bits/ 8 <0x00 0x00 0x0b 0x00 0x00>; @@ -2243,14 +2445,9 @@ <&q6prmcc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, <&vamacro>; clock-names = "mclk", "npl", "macro", "dcodec", "fsgen"; - assigned-clocks = <&q6prmcc LPASS_CLK_ID_RX_CORE_TX_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>, - <&q6prmcc LPASS_CLK_ID_RX_CORE_MCLK2_2X_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>; - assigned-clock-rates = <19200000>, <19200000>; #clock-cells = <0>; clock-output-names = "mclk"; - pinctrl-names = "default"; - pinctrl-0 = <&tx_swr_active>; #sound-dai-cells = <1>; }; @@ -2264,18 +2461,12 @@ <&vamacro>; clock-names = "mclk", "npl", "macro", "dcodec", "fsgen"; - assigned-clocks = <&q6prmcc LPASS_CLK_ID_WSA_CORE_TX_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>, - <&q6prmcc LPASS_CLK_ID_WSA_CORE_TX_2X_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>; - assigned-clock-rates = <19200000>, <19200000>; - #clock-cells = <0>; clock-output-names = "mclk"; - pinctrl-names = "default"; - pinctrl-0 = <&wsa_swr_active>; #sound-dai-cells = <1>; }; - swr0: soundwire-controller@3250000 { + swr0: soundwire@3250000 { compatible = "qcom,soundwire-v1.7.0"; reg = <0 0x03250000 0 0x2000>; interrupts = ; @@ -2283,6 +2474,9 @@ clock-names = "iface"; label = "WSA"; + pinctrl-0 = <&wsa_swr_active>; + pinctrl-names = "default"; + qcom,din-ports = <2>; qcom,dout-ports = <6>; @@ -2302,17 +2496,20 @@ status = "disabled"; }; - swr2: soundwire-controller@33b0000 { + swr2: soundwire@33b0000 { compatible = "qcom,soundwire-v1.7.0"; reg = <0 0x033b0000 0 0x2000>; interrupts = , ; interrupt-names = "core", "wakeup"; - clocks = <&vamacro>; + clocks = <&txmacro>; clock-names = "iface"; label = "TX"; + pinctrl-0 = <&tx_swr_active>; + pinctrl-names = "default"; + qcom,din-ports = <4>; qcom,dout-ports = <0>; qcom,ports-sinterval-low = /bits/ 8 <0x01 0x01 0x03 0x03>; @@ -2339,8 +2536,6 @@ <&q6prmcc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, <&q6prmcc LPASS_CLK_ID_RX_CORE_MCLK2_2X_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>; clock-names = "mclk", "macro", "dcodec", "npl"; - assigned-clocks = <&q6prmcc LPASS_CLK_ID_TX_CORE_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>; - assigned-clock-rates = <19200000>; #clock-cells = <0>; clock-output-names = "fsgen"; @@ -4122,7 +4317,7 @@ "jedec,ufs-2.0"; reg = <0 0x01d84000 0 0x3000>; interrupts = ; - phys = <&ufs_mem_phy_lanes>; + phys = <&ufs_mem_phy>; phy-names = "ufsphy"; lanes-per-direction = <2>; #reset-cells = <1>; @@ -4171,10 +4366,8 @@ ufs_mem_phy: phy@1d87000 { compatible = "qcom,sm8450-qmp-ufs-phy"; - reg = <0 0x01d87000 0 0x1c4>; - #address-cells = <2>; - #size-cells = <2>; - ranges; + reg = <0 0x01d87000 0 0x1000>; + clock-names = "ref", "ref_aux", "qref"; clocks = <&rpmhcc RPMH_CXO_CLK>, <&gcc GCC_UFS_PHY_PHY_AUX_CLK>, @@ -4182,17 +4375,11 @@ resets = <&ufs_mem_hc 0>; reset-names = "ufsphy"; - status = "disabled"; - ufs_mem_phy_lanes: phy@1d87400 { - reg = <0 0x01d87400 0 0x188>, - <0 0x01d87600 0 0x200>, - <0 0x01d87c00 0 0x200>, - <0 0x01d87800 0 0x188>, - <0 0x01d87a00 0 0x200>; - #clock-cells = <1>; - #phy-cells = <0>; - }; + #clock-cells = <1>; + #phy-cells = <0>; + + status = "disabled"; }; ice: crypto@1d88000 { diff --git a/arch/arm64/boot/dts/qcom/sm8550-mtp.dts b/arch/arm64/boot/dts/qcom/sm8550-mtp.dts index 9a70875028b7ec..c1135ad5fa696f 100644 --- a/arch/arm64/boot/dts/qcom/sm8550-mtp.dts +++ b/arch/arm64/boot/dts/qcom/sm8550-mtp.dts @@ -10,6 +10,7 @@ #include "pm8010.dtsi" #include "pm8550.dtsi" #include "pm8550b.dtsi" +#define PMK8550VE_SID 5 #include "pm8550ve.dtsi" #include "pm8550vs.dtsi" #include "pmk8550.dtsi" @@ -510,6 +511,134 @@ regulator-initial-mode = ; }; }; + + regulators-6 { + compatible = "qcom,pm8010-rpmh-regulators"; + qcom,pmic-id = "m"; + + vdd-l1-l2-supply = <&vreg_s4g_1p3>; + vdd-l3-l4-supply = <&vreg_bob2>; + vdd-l5-supply = <&vreg_s6g_1p8>; + vdd-l6-supply = <&vreg_s6g_1p8>; + vdd-l7-supply = <&vreg_bob1>; + + vreg_l1m_1p056: ldo1 { + regulator-name = "vreg_l1m_1p056"; + regulator-min-microvolt = <1056000>; + regulator-max-microvolt = <1056000>; + regulator-initial-mode = ; + }; + + vreg_l2m_1p056: ldo2 { + regulator-name = "vreg_l2m_1p056"; + regulator-min-microvolt = <1056000>; + regulator-max-microvolt = <1056000>; + regulator-initial-mode = ; + }; + + vreg_l3m_2p8: ldo3 { + regulator-name = "vreg_l3m_2p8"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-initial-mode = ; + }; + + vreg_l4m_2p8: ldo4 { + regulator-name = "vreg_l4m_2p8"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-initial-mode = ; + }; + + vreg_l5m_1p8: ldo5 { + regulator-name = "vreg_l5m_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l6m_1p8: ldo6 { + regulator-name = "vreg_l6m_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l7m_2p9: ldo7 { + regulator-name = "vreg_l7m_2p9"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2904000>; + regulator-initial-mode = ; + }; + }; + + regulators-7 { + compatible = "qcom,pm8010-rpmh-regulators"; + qcom,pmic-id = "n"; + + vdd-l1-l2-supply = <&vreg_s4g_1p3>; + vdd-l3-l4-supply = <&vreg_bob2>; + vdd-l5-supply = <&vreg_s6g_1p8>; + vdd-l6-supply = <&vreg_bob1>; + vdd-l7-supply = <&vreg_bob1>; + + vreg_l1n_1p1: ldo1 { + regulator-name = "vreg_l1n_1p1"; + regulator-min-microvolt = <1104000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l2n_1p1: ldo2 { + regulator-name = "vreg_l2n_1p1"; + regulator-min-microvolt = <1104000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l3n_2p8: ldo3 { + regulator-name = "vreg_l3n_2p8"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3000000>; + regulator-initial-mode = ; + }; + + vreg_l4n_2p8: ldo4 { + regulator-name = "vreg_l4n_2p8"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3300000>; + regulator-initial-mode = ; + }; + + vreg_l5n_1p8: ldo5 { + regulator-name = "vreg_l5n_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l6n_3p3: ldo6 { + regulator-name = "vreg_l6n_3p3"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3304000>; + regulator-initial-mode = ; + }; + + vreg_l7n_2p96: ldo7 { + regulator-name = "vreg_l7n_2p96"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = ; + }; + }; +}; + +&gpu { + status = "okay"; + + zap-shader { + firmware-name = "qcom/sm8550/a740_zap.mbn"; + }; }; &i2c_master_hub_0 { diff --git a/arch/arm64/boot/dts/qcom/sm8550-qrd.dts b/arch/arm64/boot/dts/qcom/sm8550-qrd.dts index eef811def39bcf..d401d63e5c4d2a 100644 --- a/arch/arm64/boot/dts/qcom/sm8550-qrd.dts +++ b/arch/arm64/boot/dts/qcom/sm8550-qrd.dts @@ -11,6 +11,7 @@ #include "pm8010.dtsi" #include "pm8550.dtsi" #include "pm8550b.dtsi" +#define PMK8550VE_SID 5 #include "pm8550ve.dtsi" #include "pm8550vs.dtsi" #include "pmk8550.dtsi" @@ -527,6 +528,126 @@ regulator-initial-mode = ; }; }; + + regulators-6 { + compatible = "qcom,pm8010-rpmh-regulators"; + qcom,pmic-id = "m"; + + vdd-l1-l2-supply = <&vreg_s4g_1p25>; + vdd-l3-l4-supply = <&vreg_bob2>; + vdd-l5-supply = <&vreg_s6g_1p86>; + vdd-l6-supply = <&vreg_s6g_1p86>; + vdd-l7-supply = <&vreg_bob1>; + + vreg_l1m_1p056: ldo1 { + regulator-name = "vreg_l1m_1p056"; + regulator-min-microvolt = <1056000>; + regulator-max-microvolt = <1056000>; + regulator-initial-mode = ; + }; + + vreg_l2m_1p056: ldo2 { + regulator-name = "vreg_l2m_1p056"; + regulator-min-microvolt = <1056000>; + regulator-max-microvolt = <1056000>; + regulator-initial-mode = ; + }; + + vreg_l3m_2p8: ldo3 { + regulator-name = "vreg_l3m_2p8"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-initial-mode = ; + }; + + vreg_l4m_2p8: ldo4 { + regulator-name = "vreg_l4m_2p8"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-initial-mode = ; + }; + + vreg_l5m_1p8: ldo5 { + regulator-name = "vreg_l5m_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l6m_1p8: ldo6 { + regulator-name = "vreg_l6m_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l7m_2p9: ldo7 { + regulator-name = "vreg_l7m_2p9"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2904000>; + regulator-initial-mode = ; + }; + }; + + regulators-7 { + compatible = "qcom,pm8010-rpmh-regulators"; + qcom,pmic-id = "n"; + + vdd-l1-l2-supply = <&vreg_s4g_1p25>; + vdd-l3-l4-supply = <&vreg_bob2>; + vdd-l5-supply = <&vreg_s6g_1p86>; + vdd-l6-supply = <&vreg_bob1>; + vdd-l7-supply = <&vreg_bob1>; + + vreg_l1n_1p1: ldo1 { + regulator-name = "vreg_l1n_1p1"; + regulator-min-microvolt = <1104000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l2n_1p1: ldo2 { + regulator-name = "vreg_l2n_1p1"; + regulator-min-microvolt = <1104000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l3n_2p8: ldo3 { + regulator-name = "vreg_l3n_2p8"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3000000>; + regulator-initial-mode = ; + }; + + vreg_l4n_2p8: ldo4 { + regulator-name = "vreg_l4n_2p8"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3300000>; + regulator-initial-mode = ; + }; + + vreg_l5n_1p8: ldo5 { + regulator-name = "vreg_l5n_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l6n_3p3: ldo6 { + regulator-name = "vreg_l6n_3p3"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <3304000>; + regulator-initial-mode = ; + }; + + vreg_l7n_2p96: ldo7 { + regulator-name = "vreg_l7n_2p96"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = ; + }; + }; }; &i2c_master_hub_0 { @@ -585,6 +706,13 @@ }; }; +&ipa { + qcom,gsi-loader = "self"; + memory-region = <&ipa_fw_mem>; + firmware-name = "qcom/sm8550/ipa_fws.mbn"; + status = "okay"; +}; + &gcc { clocks = <&bi_tcxo_div2>, <&sleep_clk>, <&pcie0_phy>, @@ -596,6 +724,14 @@ <&usb_dp_qmpphy QMP_USB43DP_USB3_PIPE_CLK>; }; +&gpu { + status = "okay"; + + zap-shader { + firmware-name = "qcom/sm8550/a740_zap.mbn"; + }; +}; + &lpass_tlmm { spkr_1_sd_n_active: spkr-1-sd-n-active-state { pins = "gpio17"; diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi index 7b9ddde0b2c9a1..ee1ba5a8c8fc2f 100644 --- a/arch/arm64/boot/dts/qcom/sm8550.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi @@ -285,9 +285,9 @@ compatible = "arm,idle-state"; idle-state-name = "silver-rail-power-collapse"; arm,psci-suspend-param = <0x40000004>; - entry-latency-us = <800>; + entry-latency-us = <550>; exit-latency-us = <750>; - min-residency-us = <4090>; + min-residency-us = <6700>; local-timer-stop; }; @@ -296,8 +296,18 @@ idle-state-name = "gold-rail-power-collapse"; arm,psci-suspend-param = <0x40000004>; entry-latency-us = <600>; - exit-latency-us = <1550>; - min-residency-us = <4791>; + exit-latency-us = <1300>; + min-residency-us = <8136>; + local-timer-stop; + }; + + PRIME_CPU_SLEEP_0: cpu-sleep-2-0 { + compatible = "arm,idle-state"; + idle-state-name = "goldplus-rail-power-collapse"; + arm,psci-suspend-param = <0x40000004>; + entry-latency-us = <500>; + exit-latency-us = <1350>; + min-residency-us = <7480>; local-timer-stop; }; }; @@ -306,17 +316,17 @@ CLUSTER_SLEEP_0: cluster-sleep-0 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x41000044>; - entry-latency-us = <1050>; - exit-latency-us = <2500>; - min-residency-us = <5309>; + entry-latency-us = <750>; + exit-latency-us = <2350>; + min-residency-us = <9144>; }; CLUSTER_SLEEP_1: cluster-sleep-1 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x4100c344>; - entry-latency-us = <2700>; - exit-latency-us = <3500>; - min-residency-us = <13959>; + entry-latency-us = <2800>; + exit-latency-us = <4400>; + min-residency-us = <10150>; }; }; }; @@ -324,6 +334,7 @@ firmware { scm: scm { compatible = "qcom,scm-sm8550", "qcom,scm"; + qcom,dload-mode = <&tcsr 0x19000>; interconnects = <&aggre2_noc MASTER_CRYPTO 0 &mc_virt SLAVE_EBI1 0>; }; }; @@ -400,7 +411,7 @@ CPU_PD7: power-domain-cpu7 { #power-domain-cells = <0>; power-domains = <&CLUSTER_PD>; - domain-idle-states = <&BIG_CPU_SLEEP_0>; + domain-idle-states = <&PRIME_CPU_SLEEP_0>; }; CLUSTER_PD: power-domain-cluster { @@ -1677,7 +1688,12 @@ qcom,bcm-voters = <&apps_bcm_voter>; }; - pcie0: pci@1c00000 { + rng: rng@10c3000 { + compatible = "qcom,sm8550-trng", "qcom,trng"; + reg = <0 0x010c3000 0 0x1000>; + }; + + pcie0: pcie@1c00000 { device_type = "pci"; compatible = "qcom,pcie-sm8550"; reg = <0 0x01c00000 0 0x3000>, @@ -1768,7 +1784,7 @@ status = "disabled"; }; - pcie1: pci@1c08000 { + pcie1: pcie@1c08000 { device_type = "pci"; compatible = "qcom,pcie-sm8550"; reg = <0x0 0x01c08000 0x0 0x3000>, @@ -1979,6 +1995,128 @@ #reset-cells = <1>; }; + gpu: gpu@3d00000 { + compatible = "qcom,adreno-43050a01", "qcom,adreno"; + reg = <0x0 0x03d00000 0x0 0x40000>, + <0x0 0x03d9e000 0x0 0x1000>, + <0x0 0x03d61000 0x0 0x800>; + reg-names = "kgsl_3d0_reg_memory", + "cx_mem", + "cx_dbgc"; + + interrupts = ; + + iommus = <&adreno_smmu 0 0x0>, + <&adreno_smmu 1 0x0>; + + operating-points-v2 = <&gpu_opp_table>; + + qcom,gmu = <&gmu>; + + status = "disabled"; + + zap-shader { + memory-region = <&gpu_micro_code_mem>; + }; + + /* Speedbin needs more work on A740+, keep only lower freqs */ + gpu_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-680000000 { + opp-hz = /bits/ 64 <680000000>; + opp-level = ; + }; + + opp-615000000 { + opp-hz = /bits/ 64 <615000000>; + opp-level = ; + }; + + opp-550000000 { + opp-hz = /bits/ 64 <550000000>; + opp-level = ; + }; + + opp-475000000 { + opp-hz = /bits/ 64 <475000000>; + opp-level = ; + }; + + opp-401000000 { + opp-hz = /bits/ 64 <401000000>; + opp-level = ; + }; + + opp-348000000 { + opp-hz = /bits/ 64 <348000000>; + opp-level = ; + }; + + opp-295000000 { + opp-hz = /bits/ 64 <295000000>; + opp-level = ; + }; + + opp-220000000 { + opp-hz = /bits/ 64 <220000000>; + opp-level = ; + }; + }; + }; + + gmu: gmu@3d6a000 { + compatible = "qcom,adreno-gmu-740.1", "qcom,adreno-gmu"; + reg = <0x0 0x03d6a000 0x0 0x35000>, + <0x0 0x03d50000 0x0 0x10000>, + <0x0 0x0b280000 0x0 0x10000>; + reg-names = "gmu", "rscc", "gmu_pdc"; + + interrupts = , + ; + interrupt-names = "hfi", "gmu"; + + clocks = <&gpucc GPU_CC_AHB_CLK>, + <&gpucc GPU_CC_CX_GMU_CLK>, + <&gpucc GPU_CC_CXO_CLK>, + <&gcc GCC_DDRSS_GPU_AXI_CLK>, + <&gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&gpucc GPU_CC_HUB_CX_INT_CLK>, + <&gpucc GPU_CC_DEMET_CLK>; + clock-names = "ahb", + "gmu", + "cxo", + "axi", + "memnoc", + "hub", + "demet"; + + power-domains = <&gpucc GPU_CC_CX_GDSC>, + <&gpucc GPU_CC_GX_GDSC>; + power-domain-names = "cx", + "gx"; + + iommus = <&adreno_smmu 5 0x0>; + + qcom,qmp = <&aoss_qmp>; + + operating-points-v2 = <&gmu_opp_table>; + + gmu_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-500000000 { + opp-hz = /bits/ 64 <500000000>; + opp-level = ; + }; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + opp-level = ; + }; + }; + }; + gpucc: clock-controller@3d90000 { compatible = "qcom,sm8550-gpucc"; reg = <0 0x03d90000 0 0xa000>; @@ -1990,6 +2128,89 @@ #power-domain-cells = <1>; }; + adreno_smmu: iommu@3da0000 { + compatible = "qcom,sm8550-smmu-500", "qcom,adreno-smmu", + "qcom,smmu-500", "arm,mmu-500"; + reg = <0x0 0x03da0000 0x0 0x40000>; + #iommu-cells = <2>; + #global-interrupts = <1>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + clocks = <&gpucc GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK>, + <&gcc GCC_GPU_MEMNOC_GFX_CLK>, + <&gcc GCC_GPU_SNOC_DVM_GFX_CLK>, + <&gpucc GPU_CC_AHB_CLK>; + clock-names = "hlos", + "bus", + "iface", + "ahb"; + power-domains = <&gpucc GPU_CC_CX_GDSC>; + dma-coherent; + }; + + ipa: ipa@3f40000 { + compatible = "qcom,sm8550-ipa"; + + iommus = <&apps_smmu 0x4a0 0x0>, + <&apps_smmu 0x4a2 0x0>; + reg = <0 0x3f40000 0 0x10000>, + <0 0x3f50000 0 0x5000>, + <0 0x3e04000 0 0xfc000>; + reg-names = "ipa-reg", + "ipa-shared", + "gsi"; + + interrupts-extended = <&intc GIC_SPI 654 IRQ_TYPE_EDGE_RISING>, + <&intc GIC_SPI 432 IRQ_TYPE_LEVEL_HIGH>, + <&ipa_smp2p_in 0 IRQ_TYPE_EDGE_RISING>, + <&ipa_smp2p_in 1 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "ipa", + "gsi", + "ipa-clock-query", + "ipa-setup-ready"; + + clocks = <&rpmhcc RPMH_IPA_CLK>; + clock-names = "core"; + + interconnects = <&aggre2_noc MASTER_IPA 0 &mc_virt SLAVE_EBI1 0>, + <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_IPA_CFG 0>; + interconnect-names = "memory", + "config"; + + qcom,qmp = <&aoss_qmp>; + + qcom,smem-states = <&ipa_smp2p_out 0>, + <&ipa_smp2p_out 1>; + qcom,smem-state-names = "ipa-clock-enabled-valid", + "ipa-clock-enabled"; + + status = "disabled"; + }; + remoteproc_mpss: remoteproc@4080000 { compatible = "qcom,sm8550-mpss-pas"; reg = <0x0 0x04080000 0x0 0x4040>; @@ -2040,17 +2261,13 @@ <&q6prmcc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, <&lpass_vamacro>; clock-names = "mclk", "macro", "dcodec", "fsgen"; - assigned-clocks = <&q6prmcc LPASS_CLK_ID_WSA2_CORE_TX_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>; - assigned-clock-rates = <19200000>; #clock-cells = <0>; clock-output-names = "wsa2-mclk"; - pinctrl-names = "default"; - pinctrl-0 = <&wsa2_swr_active>; #sound-dai-cells = <1>; }; - swr3: soundwire-controller@6ab0000 { + swr3: soundwire@6ab0000 { compatible = "qcom,soundwire-v2.0.0"; reg = <0 0x06ab0000 0 0x10000>; interrupts = ; @@ -2058,6 +2275,9 @@ clock-names = "iface"; label = "WSA2"; + pinctrl-0 = <&wsa2_swr_active>; + pinctrl-names = "default"; + qcom,din-ports = <4>; qcom,dout-ports = <9>; @@ -2086,17 +2306,12 @@ <&lpass_vamacro>; clock-names = "mclk", "macro", "dcodec", "fsgen"; - assigned-clocks = <&q6prmcc LPASS_CLK_ID_RX_CORE_TX_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>; - assigned-clock-rates = <19200000>; - #clock-cells = <0>; clock-output-names = "mclk"; - pinctrl-names = "default"; - pinctrl-0 = <&rx_swr_active>; #sound-dai-cells = <1>; }; - swr1: soundwire-controller@6ad0000 { + swr1: soundwire@6ad0000 { compatible = "qcom,soundwire-v2.0.0"; reg = <0 0x06ad0000 0 0x10000>; interrupts = ; @@ -2104,18 +2319,21 @@ clock-names = "iface"; label = "RX"; - qcom,din-ports = <0>; - qcom,dout-ports = <10>; + pinctrl-0 = <&rx_swr_active>; + pinctrl-names = "default"; + + qcom,din-ports = <1>; + qcom,dout-ports = <11>; - qcom,ports-sinterval = /bits/ 16 <0x03 0x3f 0x1f 0x07 0x00 0x18f 0xff 0xff 0xff 0xff>; - qcom,ports-offset1 = /bits/ 8 <0x00 0x00 0x0b 0x01 0x00 0x00 0xff 0xff 0xff 0xff>; - qcom,ports-offset2 = /bits/ 8 <0x00 0x00 0x0b 0x00 0x00 0x00 0xff 0xff 0xff 0xff>; - qcom,ports-hstart = /bits/ 8 <0xff 0x03 0xff 0xff 0xff 0x08 0xff 0xff 0xff 0xff>; - qcom,ports-hstop = /bits/ 8 <0xff 0x06 0xff 0xff 0xff 0x08 0xff 0xff 0xff 0xff>; - qcom,ports-word-length = /bits/ 8 <0x01 0x07 0x04 0xff 0xff 0x0f 0xff 0xff 0xff 0xff>; - qcom,ports-block-pack-mode = /bits/ 8 <0xff 0x00 0x01 0xff 0xff 0x00 0xff 0xff 0xff 0xff>; - qcom,ports-block-group-count = /bits/ 8 <0xff 0xff 0xff 0xff 0x00 0x00 0xff 0xff 0xff 0xff>; - qcom,ports-lane-control = /bits/ 8 <0x01 0x00 0x00 0x00 0x00 0x00 0xff 0xff 0xff 0xff>; + qcom,ports-sinterval = /bits/ 16 <0x03 0x3f 0x1f 0x07 0x00 0x18f 0xff 0xff 0xff 0xff 0xff 0xff>; + qcom,ports-offset1 = /bits/ 8 <0x00 0x00 0x0b 0x01 0x00 0x00 0xff 0xff 0xff 0xff 0xff 0xff>; + qcom,ports-offset2 = /bits/ 8 <0x00 0x00 0x0b 0x00 0x00 0x00 0xff 0xff 0xff 0xff 0xff 0xff>; + qcom,ports-hstart = /bits/ 8 <0xff 0x03 0xff 0xff 0xff 0x08 0xff 0xff 0xff 0xff 0xff 0xff>; + qcom,ports-hstop = /bits/ 8 <0xff 0x06 0xff 0xff 0xff 0x08 0xff 0xff 0xff 0xff 0xff 0xff>; + qcom,ports-word-length = /bits/ 8 <0x01 0x07 0x04 0xff 0xff 0x0f 0xff 0xff 0xff 0xff 0xff 0xff>; + qcom,ports-block-pack-mode = /bits/ 8 <0xff 0x00 0x01 0xff 0xff 0x00 0xff 0xff 0xff 0xff 0xff 0xff>; + qcom,ports-block-group-count = /bits/ 8 <0xff 0xff 0xff 0xff 0x00 0x00 0xff 0xff 0xff 0xff 0xff 0xff>; + qcom,ports-lane-control = /bits/ 8 <0x01 0x00 0x00 0x00 0x00 0x00 0xff 0xff 0xff 0xff 0xff 0xff>; #address-cells = <2>; #size-cells = <0>; @@ -2131,14 +2349,9 @@ <&q6prmcc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, <&lpass_vamacro>; clock-names = "mclk", "macro", "dcodec", "fsgen"; - assigned-clocks = <&q6prmcc LPASS_CLK_ID_TX_CORE_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>; - - assigned-clock-rates = <19200000>; #clock-cells = <0>; clock-output-names = "mclk"; - pinctrl-names = "default"; - pinctrl-0 = <&tx_swr_active>; #sound-dai-cells = <1>; }; @@ -2151,17 +2364,12 @@ <&lpass_vamacro>; clock-names = "mclk", "macro", "dcodec", "fsgen"; - assigned-clocks = <&q6prmcc LPASS_CLK_ID_WSA_CORE_TX_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>; - assigned-clock-rates = <19200000>; - #clock-cells = <0>; clock-output-names = "mclk"; - pinctrl-names = "default"; - pinctrl-0 = <&wsa_swr_active>; #sound-dai-cells = <1>; }; - swr0: soundwire-controller@6b10000 { + swr0: soundwire@6b10000 { compatible = "qcom,soundwire-v2.0.0"; reg = <0 0x06b10000 0 0x10000>; interrupts = ; @@ -2169,6 +2377,9 @@ clock-names = "iface"; label = "WSA"; + pinctrl-0 = <&wsa_swr_active>; + pinctrl-names = "default"; + qcom,din-ports = <4>; qcom,dout-ports = <9>; @@ -2188,16 +2399,19 @@ status = "disabled"; }; - swr2: soundwire-controller@6d30000 { + swr2: soundwire@6d30000 { compatible = "qcom,soundwire-v2.0.0"; reg = <0 0x06d30000 0 0x10000>; interrupts = , ; interrupt-names = "core", "wakeup"; - clocks = <&lpass_vamacro>; + clocks = <&lpass_txmacro>; clock-names = "iface"; label = "TX"; + pinctrl-0 = <&tx_swr_active>; + pinctrl-names = "default"; + qcom,din-ports = <4>; qcom,dout-ports = <0>; qcom,ports-sinterval-low = /bits/ 8 <0x01 0x01 0x03 0x03>; @@ -2224,9 +2438,6 @@ <&q6prmcc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>; clock-names = "mclk", "macro", "dcodec"; - assigned-clocks = <&q6prmcc LPASS_CLK_ID_TX_CORE_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>; - assigned-clock-rates = <19200000>; - #clock-cells = <0>; clock-output-names = "fsgen"; #sound-dai-cells = <1>; @@ -2923,8 +3134,8 @@ interrupts-extended = <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>, <&pdc 17 IRQ_TYPE_LEVEL_HIGH>, - <&pdc 15 IRQ_TYPE_EDGE_RISING>, - <&pdc 14 IRQ_TYPE_EDGE_RISING>; + <&pdc 15 IRQ_TYPE_EDGE_BOTH>, + <&pdc 14 IRQ_TYPE_EDGE_BOTH>; interrupt-names = "hs_phy_irq", "ss_phy_irq", "dm_hs_phy_irq", diff --git a/arch/arm64/boot/dts/qcom/sm8650-mtp.dts b/arch/arm64/boot/dts/qcom/sm8650-mtp.dts new file mode 100644 index 00000000000000..9d916edb1c73c1 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8650-mtp.dts @@ -0,0 +1,727 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2023, Linaro Limited + */ + +/dts-v1/; + +#include +#include "sm8650.dtsi" +#include "pm8010.dtsi" +#include "pm8550.dtsi" +#include "pm8550b.dtsi" +#define PMK8550VE_SID 8 +#include "pm8550ve.dtsi" +#include "pm8550vs.dtsi" +#include "pmk8550.dtsi" +#include "pmr735d_a.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SM8650 MTP"; + compatible = "qcom,sm8650-mtp", "qcom,sm8650"; + + aliases { + serial0 = &uart15; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + pmic-glink { + compatible = "qcom,sm8650-pmic-glink", + "qcom,sm8550-pmic-glink", + "qcom,pmic-glink"; + #address-cells = <1>; + #size-cells = <0>; + orientation-gpios = <&tlmm 29 GPIO_ACTIVE_HIGH>; + + connector@0 { + compatible = "usb-c-connector"; + reg = <0>; + + power-role = "dual"; + data-role = "dual"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + pmic_glink_hs_in: endpoint { + remote-endpoint = <&usb_1_dwc3_hs>; + }; + }; + + port@1 { + reg = <1>; + + pmic_glink_ss_in: endpoint { + remote-endpoint = <&usb_1_dwc3_ss>; + }; + }; + }; + }; + }; + + vph_pwr: vph-pwr-regulator { + compatible = "regulator-fixed"; + + regulator-name = "vph_pwr"; + regulator-min-microvolt = <3700000>; + regulator-max-microvolt = <3700000>; + + regulator-always-on; + regulator-boot-on; + }; +}; + +&apps_rsc { + regulators-0 { + compatible = "qcom,pm8550-rpmh-regulators"; + + vdd-bob1-supply = <&vph_pwr>; + vdd-bob2-supply = <&vph_pwr>; + vdd-l2-l13-l14-supply = <&vreg_bob1>; + vdd-l3-supply = <&vreg_s1c_1p2>; + vdd-l5-l16-supply = <&vreg_bob1>; + vdd-l6-l7-supply = <&vreg_bob1>; + vdd-l8-l9-supply = <&vreg_bob1>; + vdd-l11-supply = <&vreg_s1c_1p2>; + vdd-l12-supply = <&vreg_s6c_1p8>; + vdd-l15-supply = <&vreg_s6c_1p8>; + vdd-l17-supply = <&vreg_bob2>; + + qcom,pmic-id = "b"; + + vreg_bob1: bob1 { + regulator-name = "vreg_bob1"; + regulator-min-microvolt = <3296000>; + regulator-max-microvolt = <3960000>; + regulator-initial-mode = ; + }; + + vreg_bob2: bob2 { + regulator-name = "vreg_bob2"; + regulator-min-microvolt = <2720000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + }; + + vreg_l2b_3p0: ldo2 { + regulator-name = "vreg_l2b_3p0"; + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l5b_3p1: ldo5 { + regulator-name = "vreg_l5b_3p1"; + regulator-min-microvolt = <3104000>; + regulator-max-microvolt = <3104000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l6b_1p8: ldo6 { + regulator-name = "vreg_l6b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l7b_1p8: ldo7 { + regulator-name = "vreg_l7b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + }; + + vreg_l8b_1p8: ldo8 { + regulator-name = "vreg_l8b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l9b_2p9: ldo9 { + regulator-name = "vreg_l9b_2p9"; + regulator-min-microvolt = <2960000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l11b_1p2: ldo11 { + regulator-name = "vreg_l11b_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1504000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l12b_1p8: ldo12 { + regulator-name = "vreg_l12b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l13b_3p0: ldo13 { + regulator-name = "vreg_l13b_3p0"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l14b_3p2: ldo14 { + regulator-name = "vreg_l14b_3p2"; + regulator-min-microvolt = <3200000>; + regulator-max-microvolt = <3200000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l15b_1p8: ldo15 { + regulator-name = "vreg_l15b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l16b_2p8: ldo16 { + regulator-name = "vreg_l16b_2p8"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l17b_2p5: ldo17 { + regulator-name = "vreg_l17b_2p5"; + regulator-min-microvolt = <2504000>; + regulator-max-microvolt = <2504000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; + + regulators-1 { + compatible = "qcom,pm8550vs-rpmh-regulators"; + + vdd-l1-supply = <&vreg_s1c_1p2>; + vdd-l2-supply = <&vreg_s1c_1p2>; + vdd-l3-supply = <&vreg_s1c_1p2>; + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vph_pwr>; + vdd-s3-supply = <&vph_pwr>; + vdd-s4-supply = <&vph_pwr>; + vdd-s5-supply = <&vph_pwr>; + vdd-s6-supply = <&vph_pwr>; + + qcom,pmic-id = "c"; + + vreg_s1c_1p2: smps1 { + regulator-name = "vreg_s1c_1p2"; + regulator-min-microvolt = <1256000>; + regulator-max-microvolt = <1348000>; + regulator-initial-mode = ; + }; + + vreg_s2c_0p8: smps2 { + regulator-name = "vreg_s2c_0p8"; + regulator-min-microvolt = <852000>; + regulator-max-microvolt = <1036000>; + regulator-initial-mode = ; + }; + + vreg_s3c_0p9: smps3 { + regulator-name = "vreg_s3c_0p9"; + regulator-min-microvolt = <976000>; + regulator-max-microvolt = <1064000>; + regulator-initial-mode = ; + }; + + vreg_s4c_1p2: smps4 { + regulator-name = "vreg_s4c_1p2"; + regulator-min-microvolt = <1224000>; + regulator-max-microvolt = <1280000>; + regulator-initial-mode = ; + }; + + vreg_s5c_0p7: smps5 { + regulator-name = "vreg_s5c_0p7"; + regulator-min-microvolt = <752000>; + regulator-max-microvolt = <900000>; + regulator-initial-mode = ; + }; + + vreg_s6c_1p8: smps6 { + regulator-name = "vreg_s6c_1p8"; + regulator-min-microvolt = <1856000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l1c_1p2: ldo1 { + regulator-name = "vreg_l1c_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l3c_1p2: ldo3 { + regulator-name = "vreg_l3c_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; + + regulators-2 { + compatible = "qcom,pm8550vs-rpmh-regulators"; + + vdd-l1-supply = <&vreg_s3c_0p9>; + + qcom,pmic-id = "d"; + + vreg_l1d_0p88: ldo1 { + regulator-name = "vreg_l1d_0p88"; + regulator-min-microvolt = <912000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; + + regulators-3 { + compatible = "qcom,pm8550vs-rpmh-regulators"; + + vdd-l3-supply = <&vreg_s3c_0p9>; + + qcom,pmic-id = "e"; + + vreg_l3e_0p9: ldo3 { + regulator-name = "vreg_l3e_0p9"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; + + regulators-4 { + compatible = "qcom,pm8550vs-rpmh-regulators"; + + vdd-l1-supply = <&vreg_s3c_0p9>; + vdd-l3-supply = <&vreg_s3c_0p9>; + + qcom,pmic-id = "g"; + + vreg_l1g_0p91: ldo1 { + regulator-name = "vreg_l1g_0p91"; + regulator-min-microvolt = <912000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l3g_0p91: ldo3 { + regulator-name = "vreg_l3g_0p91"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <912000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; + + regulators-5 { + compatible = "qcom,pm8550ve-rpmh-regulators"; + + vdd-l1-supply = <&vreg_s3c_0p9>; + vdd-l2-supply = <&vreg_s3c_0p9>; + vdd-l3-supply = <&vreg_s1c_1p2>; + vdd-s4-supply = <&vph_pwr>; + + qcom,pmic-id = "i"; + + vreg_s4i_0p85: smps4 { + regulator-name = "vreg_s4i_0p85"; + regulator-min-microvolt = <852000>; + regulator-max-microvolt = <1004000>; + regulator-initial-mode = ; + }; + + vreg_l1i_0p88: ldo1 { + regulator-name = "vreg_l1i_0p88"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <912000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l2i_0p88: ldo2 { + regulator-name = "vreg_l2i_0p88"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <912000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l3i_1p2: ldo3 { + regulator-name = "vreg_l3i_0p91"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; +}; + +&dispcc { + status = "okay"; +}; + +&lpass_tlmm { + spkr_1_sd_n_active: spkr-1-sd-n-active-state { + pins = "gpio21"; + function = "gpio"; + drive-strength = <16>; + bias-disable; + output-low; + }; +}; + +&mdss { + status = "okay"; +}; + +&mdss_dsi0 { + vdda-supply = <&vreg_l3i_1p2>; + + status = "okay"; + + panel@0 { + compatible = "visionox,vtdr6130"; + reg = <0>; + + reset-gpios = <&tlmm 133 GPIO_ACTIVE_LOW>; + + vddio-supply = <&vreg_l12b_1p8>; + vci-supply = <&vreg_l13b_3p0>; + vdd-supply = <&vreg_l11b_1p2>; + + pinctrl-0 = <&disp0_reset_n_active>, <&mdp_vsync_active>; + pinctrl-1 = <&disp0_reset_n_suspend>, <&mdp_vsync_suspend>; + pinctrl-names = "default", "sleep"; + + port { + panel0_in: endpoint { + remote-endpoint = <&mdss_dsi0_out>; + }; + }; + }; +}; + +&mdss_dsi0_out { + remote-endpoint = <&panel0_in>; + data-lanes = <0 1 2 3>; +}; + +&mdss_dsi0_phy { + vdds-supply = <&vreg_l1i_0p88>; + + status = "okay"; +}; + +&mdss_mdp { + status = "okay"; +}; + +&pcie_1_phy_aux_clk { + clock-frequency = <1000>; +}; + +&pcie0 { + wake-gpios = <&tlmm 96 GPIO_ACTIVE_HIGH>; + perst-gpios = <&tlmm 94 GPIO_ACTIVE_LOW>; + + pinctrl-0 = <&pcie0_default_state>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&pcie0_phy { + vdda-phy-supply = <&vreg_l1i_0p88>; + vdda-pll-supply = <&vreg_l3i_1p2>; + + status = "okay"; +}; + +&pcie1 { + wake-gpios = <&tlmm 99 GPIO_ACTIVE_HIGH>; + perst-gpios = <&tlmm 97 GPIO_ACTIVE_LOW>; + + pinctrl-0 = <&pcie1_default_state>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&pcie1_phy { + vdda-phy-supply = <&vreg_l3e_0p9>; + vdda-pll-supply = <&vreg_l3i_1p2>; + vdda-qref-supply = <&vreg_l1i_0p88>; + + status = "okay"; +}; + +&pm8550_gpios { + sdc2_card_det_n: sdc2-card-det-state { + pins = "gpio12"; + function = "normal"; + bias-pull-up; + input-enable; + output-disable; + power-source = <1>; /* 1.8 V */ + }; +}; + +&pm8550b_eusb2_repeater { + vdd18-supply = <&vreg_l15b_1p8>; + vdd3-supply = <&vreg_l5b_3p1>; +}; + +&qupv3_id_1 { + status = "okay"; +}; + +&remoteproc_adsp { + firmware-name = "qcom/sm8650/adsp.mbn", + "qcom/sm8650/adsp_dtb.mbn"; + + status = "okay"; +}; + +&remoteproc_cdsp { + firmware-name = "qcom/sm8650/cdsp.mbn", + "qcom/sm8650/cdsp_dtb.mbn"; + + status = "okay"; +}; + +&remoteproc_mpss { + firmware-name = "qcom/sm8650/modem.mbn", + "qcom/sm8650/modem_dtb.mbn"; + + status = "okay"; +}; + +&sdhc_2 { + cd-gpios = <&pm8550_gpios 12 GPIO_ACTIVE_LOW>; + + vmmc-supply = <&vreg_l9b_2p9>; + vqmmc-supply = <&vreg_l8b_1p8>; + bus-width = <4>; + no-sdio; + no-mmc; + + pinctrl-0 = <&sdc2_default>, <&sdc2_card_det_n>; + pinctrl-1 = <&sdc2_sleep>, <&sdc2_card_det_n>; + pinctrl-names = "default", "sleep"; + + status = "okay"; +}; + +&sleep_clk { + clock-frequency = <32000>; +}; + +&swr0 { + status = "okay"; + + /* WSA8845, Speaker Left */ + left_spkr: speaker@0,0 { + compatible = "sdw20217020400"; + reg = <0 0>; + pinctrl-0 = <&spkr_1_sd_n_active>; + pinctrl-names = "default"; + powerdown-gpios = <&lpass_tlmm 21 GPIO_ACTIVE_LOW>; + #sound-dai-cells = <0>; + sound-name-prefix = "SpkrLeft"; + vdd-1p8-supply = <&vreg_l15b_1p8>; + vdd-io-supply = <&vreg_l3c_1p2>; + }; + + /* WSA8845, Speaker Right */ + right_spkr: speaker@0,1 { + compatible = "sdw20217020400"; + reg = <0 1>; + pinctrl-0 = <&spkr_2_sd_n_active>; + pinctrl-names = "default"; + powerdown-gpios = <&tlmm 77 GPIO_ACTIVE_LOW>; + #sound-dai-cells = <0>; + sound-name-prefix = "SpkrRight"; + vdd-1p8-supply = <&vreg_l15b_1p8>; + vdd-io-supply = <&vreg_l3c_1p2>; + }; +}; + +&tlmm { + /* Reserved I/Os for NFC */ + gpio-reserved-ranges = <32 8>; + + disp0_reset_n_active: disp0-reset-n-active-state { + pins = "gpio133"; + function = "gpio"; + drive-strength = <8>; + bias-disable; + }; + + disp0_reset_n_suspend: disp0-reset-n-suspend-state { + pins = "gpio133"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + + mdp_vsync_active: mdp-vsync-active-state { + pins = "gpio86"; + function = "mdp_vsync"; + drive-strength = <2>; + bias-pull-down; + }; + + mdp_vsync_suspend: mdp-vsync-suspend-state { + pins = "gpio86"; + function = "mdp_vsync"; + drive-strength = <2>; + bias-pull-down; + }; + + spkr_2_sd_n_active: spkr-2-sd-n-active-state { + pins = "gpio77"; + function = "gpio"; + drive-strength = <16>; + bias-disable; + output-low; + }; +}; + +&uart15 { + status = "okay"; +}; + +&ufs_mem_hc { + reset-gpios = <&tlmm 210 GPIO_ACTIVE_LOW>; + + vcc-supply = <&vreg_l17b_2p5>; + vcc-max-microamp = <1300000>; + vccq-supply = <&vreg_l1c_1p2>; + vccq-max-microamp = <1200000>; + + status = "okay"; +}; + +&ufs_mem_phy { + vdda-phy-supply = <&vreg_l1d_0p88>; + vdda-pll-supply = <&vreg_l3i_1p2>; + + status = "okay"; +}; + +/* + * DPAUX -> WCD9395 -> USB_SBU -> USB-C + * eUSB2 DP/DM -> PM85550HS -> eUSB2 DP/DM -> USB-C + * USB SS -> USB-C + */ + +&usb_1 { + status = "okay"; +}; + +&usb_1_dwc3 { + dr_mode = "otg"; + usb-role-switch; +}; + +&usb_1_dwc3_hs { + remote-endpoint = <&pmic_glink_hs_in>; +}; + +&usb_1_dwc3_ss { + remote-endpoint = <&pmic_glink_ss_in>; +}; + +&usb_1_hsphy { + vdd-supply = <&vreg_l1i_0p88>; + vdda12-supply = <&vreg_l3i_1p2>; + + phys = <&pm8550b_eusb2_repeater>; + + status = "okay"; +}; + +&usb_dp_qmpphy { + vdda-phy-supply = <&vreg_l3i_1p2>; + vdda-pll-supply = <&vreg_l3g_0p91>; + + status = "okay"; +}; + +&xo_board { + clock-frequency = <76800000>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8650-qrd.dts b/arch/arm64/boot/dts/qcom/sm8650-qrd.dts new file mode 100644 index 00000000000000..592a67a47c782f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8650-qrd.dts @@ -0,0 +1,811 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2023, Linaro Limited + */ + +/dts-v1/; + +#include +#include +#include "sm8650.dtsi" +#include "pm8010.dtsi" +#include "pm8550.dtsi" +#include "pm8550b.dtsi" +#define PMK8550VE_SID 8 +#include "pm8550ve.dtsi" +#include "pm8550vs.dtsi" +#include "pmk8550.dtsi" +#include "pmr735d_a.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SM8650 QRD"; + compatible = "qcom,sm8650-qrd", "qcom,sm8650"; + + aliases { + serial0 = &uart15; + serial1 = &uart14; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + gpio-keys { + compatible = "gpio-keys"; + + pinctrl-0 = <&volume_up_n>; + pinctrl-names = "default"; + + key-volume-up { + label = "Volume Up"; + linux,code = ; + gpios = <&pm8550_gpios 6 GPIO_ACTIVE_LOW>; + debounce-interval = <15>; + linux,can-disable; + wakeup-source; + }; + }; + + pmic-glink { + compatible = "qcom,sm8650-pmic-glink", + "qcom,sm8550-pmic-glink", + "qcom,pmic-glink"; + #address-cells = <1>; + #size-cells = <0>; + orientation-gpios = <&tlmm 29 GPIO_ACTIVE_HIGH>; + + connector@0 { + compatible = "usb-c-connector"; + reg = <0>; + + power-role = "dual"; + data-role = "dual"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + pmic_glink_hs_in: endpoint { + remote-endpoint = <&usb_1_dwc3_hs>; + }; + }; + + port@1 { + reg = <1>; + + pmic_glink_ss_in: endpoint { + remote-endpoint = <&usb_1_dwc3_ss>; + }; + }; + }; + }; + }; + + vph_pwr: vph-pwr-regulator { + compatible = "regulator-fixed"; + + regulator-name = "vph_pwr"; + regulator-min-microvolt = <3700000>; + regulator-max-microvolt = <3700000>; + + regulator-always-on; + regulator-boot-on; + }; +}; + +&apps_rsc { + regulators-0 { + compatible = "qcom,pm8550-rpmh-regulators"; + + vdd-bob1-supply = <&vph_pwr>; + vdd-bob2-supply = <&vph_pwr>; + vdd-l2-l13-l14-supply = <&vreg_bob1>; + vdd-l3-supply = <&vreg_s1c_1p2>; + vdd-l5-l16-supply = <&vreg_bob1>; + vdd-l6-l7-supply = <&vreg_bob1>; + vdd-l8-l9-supply = <&vreg_bob1>; + vdd-l11-supply = <&vreg_s1c_1p2>; + vdd-l12-supply = <&vreg_s6c_1p8>; + vdd-l15-supply = <&vreg_s6c_1p8>; + vdd-l17-supply = <&vreg_bob2>; + + qcom,pmic-id = "b"; + + vreg_bob1: bob1 { + regulator-name = "vreg_bob1"; + regulator-min-microvolt = <3296000>; + regulator-max-microvolt = <3960000>; + regulator-initial-mode = ; + }; + + vreg_bob2: bob2 { + regulator-name = "vreg_bob2"; + regulator-min-microvolt = <2720000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + }; + + vreg_l2b_3p0: ldo2 { + regulator-name = "vreg_l2b_3p0"; + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l5b_3p1: ldo5 { + regulator-name = "vreg_l5b_3p1"; + regulator-min-microvolt = <3104000>; + regulator-max-microvolt = <3104000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l6b_1p8: ldo6 { + regulator-name = "vreg_l6b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l7b_1p8: ldo7 { + regulator-name = "vreg_l7b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + }; + + vreg_l8b_1p8: ldo8 { + regulator-name = "vreg_l8b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l11b_1p2: ldo11 { + regulator-name = "vreg_l11b_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1504000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l12b_1p8: ldo12 { + regulator-name = "vreg_l12b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l13b_3p0: ldo13 { + regulator-name = "vreg_l13b_3p0"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l14b_3p2: ldo14 { + regulator-name = "vreg_l14b_3p2"; + regulator-min-microvolt = <3200000>; + regulator-max-microvolt = <3200000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l15b_1p8: ldo15 { + regulator-name = "vreg_l15b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l16b_2p8: ldo16 { + regulator-name = "vreg_l16b_2p8"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l17b_2p5: ldo17 { + regulator-name = "vreg_l17b_2p5"; + regulator-min-microvolt = <2504000>; + regulator-max-microvolt = <2504000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; + + regulators-1 { + compatible = "qcom,pm8550vs-rpmh-regulators"; + + vdd-l1-supply = <&vreg_s1c_1p2>; + vdd-l2-supply = <&vreg_s1c_1p2>; + vdd-l3-supply = <&vreg_s1c_1p2>; + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vph_pwr>; + vdd-s3-supply = <&vph_pwr>; + vdd-s4-supply = <&vph_pwr>; + vdd-s5-supply = <&vph_pwr>; + vdd-s6-supply = <&vph_pwr>; + + qcom,pmic-id = "c"; + + vreg_s1c_1p2: smps1 { + regulator-name = "vreg_s1c_1p2"; + regulator-min-microvolt = <1256000>; + regulator-max-microvolt = <1348000>; + regulator-initial-mode = ; + }; + + vreg_s2c_0p8: smps2 { + regulator-name = "vreg_s2c_0p8"; + regulator-min-microvolt = <852000>; + regulator-max-microvolt = <1036000>; + regulator-initial-mode = ; + }; + + vreg_s3c_0p9: smps3 { + regulator-name = "vreg_s3c_0p9"; + regulator-min-microvolt = <976000>; + regulator-max-microvolt = <1064000>; + regulator-initial-mode = ; + }; + + vreg_s4c_1p2: smps4 { + regulator-name = "vreg_s4c_1p2"; + regulator-min-microvolt = <1224000>; + regulator-max-microvolt = <1280000>; + regulator-initial-mode = ; + }; + + vreg_s5c_0p7: smps5 { + regulator-name = "vreg_s5c_0p7"; + regulator-min-microvolt = <752000>; + regulator-max-microvolt = <900000>; + regulator-initial-mode = ; + }; + + vreg_s6c_1p8: smps6 { + regulator-name = "vreg_s6c_1p8"; + regulator-min-microvolt = <1856000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l1c_1p2: ldo1 { + regulator-name = "vreg_l1c_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l3c_1p2: ldo3 { + regulator-name = "vreg_l3c_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; + + regulators-2 { + compatible = "qcom,pm8550vs-rpmh-regulators"; + + vdd-l1-supply = <&vreg_s3c_0p9>; + + qcom,pmic-id = "d"; + + vreg_l1d_0p88: ldo1 { + regulator-name = "vreg_l1d_0p88"; + regulator-min-microvolt = <912000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; + + regulators-3 { + compatible = "qcom,pm8550vs-rpmh-regulators"; + + vdd-l3-supply = <&vreg_s3c_0p9>; + + qcom,pmic-id = "e"; + + vreg_l3e_0p9: ldo3 { + regulator-name = "vreg_l3e_0p9"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; + + regulators-4 { + compatible = "qcom,pm8550vs-rpmh-regulators"; + + vdd-l1-supply = <&vreg_s3c_0p9>; + vdd-l3-supply = <&vreg_s3c_0p9>; + + qcom,pmic-id = "g"; + + vreg_l1g_0p91: ldo1 { + regulator-name = "vreg_l1g_0p91"; + regulator-min-microvolt = <912000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l3g_0p91: ldo3 { + regulator-name = "vreg_l3g_0p91"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <912000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; + + regulators-5 { + compatible = "qcom,pm8550ve-rpmh-regulators"; + + vdd-l1-supply = <&vreg_s3c_0p9>; + vdd-l2-supply = <&vreg_s3c_0p9>; + vdd-l3-supply = <&vreg_s1c_1p2>; + vdd-s4-supply = <&vph_pwr>; + + qcom,pmic-id = "i"; + + vreg_s4i_0p85: smps4 { + regulator-name = "vreg_s4i_0p85"; + regulator-min-microvolt = <852000>; + regulator-max-microvolt = <1004000>; + regulator-initial-mode = ; + }; + + vreg_l1i_0p88: ldo1 { + regulator-name = "vreg_l1i_0p88"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <912000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l2i_0p88: ldo2 { + regulator-name = "vreg_l2i_0p88"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <912000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + + vreg_l3i_1p2: ldo3 { + regulator-name = "vreg_l3i_0p91"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + regulator-allow-set-load; + regulator-allowed-modes = ; + }; + }; +}; + +&dispcc { + status = "okay"; +}; + +&gpi_dma1 { + status = "okay"; +}; + +&ipa { + qcom,gsi-loader = "self"; + memory-region = <&ipa_fw_mem>; + firmware-name = "qcom/sm8650/ipa_fws.mbn"; + status = "okay"; +}; + +&mdss { + status = "okay"; +}; + +&mdss_dsi0 { + vdda-supply = <&vreg_l3i_1p2>; + + status = "okay"; + + panel@0 { + compatible = "visionox,vtdr6130"; + reg = <0>; + + reset-gpios = <&tlmm 133 GPIO_ACTIVE_LOW>; + + vddio-supply = <&vreg_l12b_1p8>; + vci-supply = <&vreg_l13b_3p0>; + vdd-supply = <&vreg_l11b_1p2>; + + pinctrl-0 = <&disp0_reset_n_active>, <&mdp_vsync_active>; + pinctrl-1 = <&disp0_reset_n_suspend>, <&mdp_vsync_suspend>; + pinctrl-names = "default", "sleep"; + + port { + panel0_in: endpoint { + remote-endpoint = <&mdss_dsi0_out>; + }; + }; + }; +}; + +&mdss_dsi0_out { + remote-endpoint = <&panel0_in>; + data-lanes = <0 1 2 3>; +}; + +&mdss_dsi0_phy { + vdds-supply = <&vreg_l1i_0p88>; + + status = "okay"; +}; + +&mdss_mdp { + status = "okay"; +}; + +&pcie_1_phy_aux_clk { + clock-frequency = <1000>; +}; + +&pcie0 { + wake-gpios = <&tlmm 96 GPIO_ACTIVE_HIGH>; + perst-gpios = <&tlmm 94 GPIO_ACTIVE_LOW>; + + pinctrl-0 = <&pcie0_default_state>; + pinctrl-names = "default"; + + status = "okay"; +}; + +&pcie0_phy { + vdda-phy-supply = <&vreg_l1i_0p88>; + vdda-pll-supply = <&vreg_l3i_1p2>; + + status = "okay"; +}; + +&pon_pwrkey { + status = "okay"; +}; + +&pon_resin { + linux,code = ; + + status = "okay"; +}; + +&pm8550_flash { + status = "okay"; + + led-0 { + function = LED_FUNCTION_FLASH; + color = ; + led-sources = <1>, <4>; + led-max-microamp = <500000>; + flash-max-microamp = <2000000>; + flash-max-timeout-us = <1280000>; + function-enumerator = <0>; + }; + + led-1 { + function = LED_FUNCTION_FLASH; + color = ; + led-sources = <2>, <3>; + led-max-microamp = <500000>; + flash-max-microamp = <2000000>; + flash-max-timeout-us = <1280000>; + function-enumerator = <1>; + }; +}; + +&pm8550_gpios { + volume_up_n: volume-up-n-state { + pins = "gpio6"; + function = "normal"; + bias-pull-up; + input-enable; + power-source = <1>; + }; +}; + +&pm8550_pwm { + status = "okay"; + + multi-led { + color = ; + function = LED_FUNCTION_STATUS; + + #address-cells = <1>; + #size-cells = <0>; + + led@1 { + reg = <1>; + color = ; + }; + + led@2 { + reg = <2>; + color = ; + }; + + led@3 { + reg = <3>; + color = ; + }; + }; +}; + +&pm8550b_eusb2_repeater { + vdd18-supply = <&vreg_l15b_1p8>; + vdd3-supply = <&vreg_l5b_3p1>; +}; + +&pmk8550_rtc { + status = "okay"; +}; + +&qupv3_id_0 { + status = "okay"; +}; + +&qupv3_id_1 { + status = "okay"; +}; + +&remoteproc_adsp { + firmware-name = "qcom/sm8650/adsp.mbn", + "qcom/sm8650/adsp_dtb.mbn"; + + status = "okay"; +}; + +&remoteproc_cdsp { + firmware-name = "qcom/sm8650/cdsp.mbn", + "qcom/sm8650/cdsp_dtb.mbn"; + + status = "okay"; +}; + +&remoteproc_mpss { + firmware-name = "qcom/sm8650/modem.mbn", + "qcom/sm8650/modem_dtb.mbn"; + + status = "okay"; +}; + +&sleep_clk { + clock-frequency = <32000>; +}; + +&spi4 { + status = "okay"; + + touchscreen@0 { + compatible = "goodix,gt9916"; + reg = <0>; + + interrupt-parent = <&tlmm>; + interrupts = <162 IRQ_TYPE_LEVEL_LOW>; + + reset-gpios = <&tlmm 161 GPIO_ACTIVE_LOW>; + + avdd-supply = <&vreg_l14b_3p2>; + + spi-max-frequency = <1000000>; + + touchscreen-size-x = <1080>; + touchscreen-size-y = <2400>; + + pinctrl-0 = <&ts_irq>, <&ts_reset>; + pinctrl-names = "default"; + }; +}; + +&tlmm { + /* Reserved I/Os for NFC */ + gpio-reserved-ranges = <32 8>; + + bt_default: bt-default-state { + bt-en-pins { + pins = "gpio17"; + function = "gpio"; + drive-strength = <16>; + bias-disable; + }; + + sw-ctrl-pins { + pins = "gpio18"; + function = "gpio"; + bias-pull-down; + }; + }; + + disp0_reset_n_active: disp0-reset-n-active-state { + pins = "gpio133"; + function = "gpio"; + drive-strength = <8>; + bias-disable; + }; + + disp0_reset_n_suspend: disp0-reset-n-suspend-state { + pins = "gpio133"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + + mdp_vsync_active: mdp-vsync-active-state { + pins = "gpio86"; + function = "mdp_vsync"; + drive-strength = <2>; + bias-pull-down; + }; + + mdp_vsync_suspend: mdp-vsync-suspend-state { + pins = "gpio86"; + function = "mdp_vsync"; + drive-strength = <2>; + bias-pull-down; + }; + + ts_irq: ts-irq-state { + pins = "gpio161"; + function = "gpio"; + drive-strength = <8>; + bias-pull-up; + output-disable; + }; + + ts_reset: ts-reset-state { + pins = "gpio162"; + function = "gpio"; + drive-strength = <8>; + bias-pull-up; + }; +}; + +&uart14 { + status = "okay"; + + bluetooth { + compatible = "qcom,wcn7850-bt"; + + clocks = <&rpmhcc RPMH_RF_CLK1>; + + vddio-supply = <&vreg_l3c_1p2>; + vddaon-supply = <&vreg_l15b_1p8>; + vdddig-supply = <&vreg_s3c_0p9>; + vddrfa0p8-supply = <&vreg_s3c_0p9>; + vddrfa1p2-supply = <&vreg_s1c_1p2>; + vddrfa1p9-supply = <&vreg_s6c_1p8>; + + max-speed = <3200000>; + + enable-gpios = <&tlmm 17 GPIO_ACTIVE_HIGH>; + swctrl-gpios = <&tlmm 18 GPIO_ACTIVE_HIGH>; + + pinctrl-0 = <&bt_default>; + pinctrl-names = "default"; + }; +}; + +&uart15 { + status = "okay"; +}; + +&ufs_mem_hc { + reset-gpios = <&tlmm 210 GPIO_ACTIVE_LOW>; + + vcc-supply = <&vreg_l17b_2p5>; + vcc-max-microamp = <1300000>; + vccq-supply = <&vreg_l1c_1p2>; + vccq-max-microamp = <1200000>; + + status = "okay"; +}; + +&ufs_mem_phy { + vdda-phy-supply = <&vreg_l1d_0p88>; + vdda-pll-supply = <&vreg_l3i_1p2>; + + status = "okay"; +}; + +/* + * DPAUX -> WCD9395 -> USB_SBU -> USB-C + * eUSB2 DP/DM -> PM85550HS -> eUSB2 DP/DM -> WCD9395 -> USB-C + * USB SS -> NB7VPQ904MMUTWG -> USB-C + */ + +&usb_1 { + status = "okay"; +}; + +&usb_1_dwc3 { + dr_mode = "otg"; + usb-role-switch; +}; + +&usb_1_dwc3_hs { + remote-endpoint = <&pmic_glink_hs_in>; +}; + +&usb_1_dwc3_ss { + remote-endpoint = <&pmic_glink_ss_in>; +}; + +&usb_1_hsphy { + vdd-supply = <&vreg_l1i_0p88>; + vdda12-supply = <&vreg_l3i_1p2>; + + phys = <&pm8550b_eusb2_repeater>; + + status = "okay"; +}; + +&usb_dp_qmpphy { + vdda-phy-supply = <&vreg_l3i_1p2>; + vdda-pll-supply = <&vreg_l3g_0p91>; + + status = "okay"; +}; + +&xo_board { + clock-frequency = <76800000>; +}; diff --git a/arch/arm64/boot/dts/qcom/sm8650.dtsi b/arch/arm64/boot/dts/qcom/sm8650.dtsi new file mode 100644 index 00000000000000..2df77123a8c7bb --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sm8650.dtsi @@ -0,0 +1,6013 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2023, Linaro Limited + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/ { + interrupt-parent = <&intc>; + + #address-cells = <2>; + #size-cells = <2>; + + chosen { }; + + clocks { + xo_board: xo-board { + compatible = "fixed-clock"; + #clock-cells = <0>; + }; + + sleep_clk: sleep-clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + }; + + bi_tcxo_div2: bi-tcxo-div2-clk { + compatible = "fixed-factor-clock"; + #clock-cells = <0>; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-mult = <1>; + clock-div = <2>; + }; + + bi_tcxo_ao_div2: bi-tcxo-ao-div2-clk { + compatible = "fixed-factor-clock"; + #clock-cells = <0>; + + clocks = <&rpmhcc RPMH_CXO_CLK_A>; + clock-mult = <1>; + clock-div = <2>; + }; + + pcie_1_phy_aux_clk: pcie-1-phy-aux-clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + }; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a520"; + reg = <0 0>; + + clocks = <&cpufreq_hw 0>; + + power-domains = <&CPU_PD0>; + power-domain-names = "psci"; + + enable-method = "psci"; + next-level-cache = <&L2_0>; + capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <100>; + + qcom,freq-domain = <&cpufreq_hw 0>; + + #cooling-cells = <2>; + + L2_0: l2-cache { + compatible = "cache"; + cache-level = <2>; + cache-unified; + next-level-cache = <&L3_0>; + + L3_0: l3-cache { + compatible = "cache"; + cache-level = <3>; + cache-unified; + }; + }; + }; + + CPU1: cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a520"; + reg = <0 0x100>; + + clocks = <&cpufreq_hw 0>; + + power-domains = <&CPU_PD1>; + power-domain-names = "psci"; + + enable-method = "psci"; + next-level-cache = <&L2_0>; + capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <100>; + + qcom,freq-domain = <&cpufreq_hw 0>; + + #cooling-cells = <2>; + }; + + CPU2: cpu@200 { + device_type = "cpu"; + compatible = "arm,cortex-a720"; + reg = <0 0x200>; + + clocks = <&cpufreq_hw 3>; + + power-domains = <&CPU_PD2>; + power-domain-names = "psci"; + + enable-method = "psci"; + next-level-cache = <&L2_200>; + capacity-dmips-mhz = <1792>; + dynamic-power-coefficient = <238>; + + qcom,freq-domain = <&cpufreq_hw 3>; + + #cooling-cells = <2>; + + L2_200: l2-cache { + compatible = "cache"; + cache-level = <2>; + cache-unified; + next-level-cache = <&L3_0>; + }; + }; + + CPU3: cpu@300 { + device_type = "cpu"; + compatible = "arm,cortex-a720"; + reg = <0 0x300>; + + clocks = <&cpufreq_hw 3>; + + power-domains = <&CPU_PD3>; + power-domain-names = "psci"; + + enable-method = "psci"; + next-level-cache = <&L2_200>; + capacity-dmips-mhz = <1792>; + dynamic-power-coefficient = <238>; + + qcom,freq-domain = <&cpufreq_hw 3>; + + #cooling-cells = <2>; + }; + + CPU4: cpu@400 { + device_type = "cpu"; + compatible = "arm,cortex-a720"; + reg = <0 0x400>; + + clocks = <&cpufreq_hw 3>; + + power-domains = <&CPU_PD4>; + power-domain-names = "psci"; + + enable-method = "psci"; + next-level-cache = <&L2_400>; + capacity-dmips-mhz = <1792>; + dynamic-power-coefficient = <238>; + + qcom,freq-domain = <&cpufreq_hw 3>; + + #cooling-cells = <2>; + + L2_400: l2-cache { + compatible = "cache"; + cache-level = <2>; + cache-unified; + next-level-cache = <&L3_0>; + }; + }; + + CPU5: cpu@500 { + device_type = "cpu"; + compatible = "arm,cortex-a720"; + reg = <0 0x500>; + + clocks = <&cpufreq_hw 1>; + + power-domains = <&CPU_PD5>; + power-domain-names = "psci"; + + enable-method = "psci"; + next-level-cache = <&L2_500>; + capacity-dmips-mhz = <1792>; + dynamic-power-coefficient = <238>; + + qcom,freq-domain = <&cpufreq_hw 1>; + + #cooling-cells = <2>; + + L2_500: l2-cache { + compatible = "cache"; + cache-level = <2>; + cache-unified; + next-level-cache = <&L3_0>; + }; + }; + + CPU6: cpu@600 { + device_type = "cpu"; + compatible = "arm,cortex-a720"; + reg = <0 0x600>; + + clocks = <&cpufreq_hw 1>; + + power-domains = <&CPU_PD6>; + power-domain-names = "psci"; + + enable-method = "psci"; + next-level-cache = <&L2_600>; + capacity-dmips-mhz = <1792>; + dynamic-power-coefficient = <238>; + + qcom,freq-domain = <&cpufreq_hw 1>; + + #cooling-cells = <2>; + + L2_600: l2-cache { + compatible = "cache"; + cache-level = <2>; + cache-unified; + next-level-cache = <&L3_0>; + }; + }; + + CPU7: cpu@700 { + device_type = "cpu"; + compatible = "arm,cortex-x4"; + reg = <0 0x700>; + + clocks = <&cpufreq_hw 2>; + + power-domains = <&CPU_PD7>; + power-domain-names = "psci"; + + enable-method = "psci"; + next-level-cache = <&L2_700>; + capacity-dmips-mhz = <1894>; + dynamic-power-coefficient = <588>; + + qcom,freq-domain = <&cpufreq_hw 2>; + + #cooling-cells = <2>; + + L2_700: l2-cache { + compatible = "cache"; + cache-level = <2>; + cache-unified; + next-level-cache = <&L3_0>; + }; + }; + + cpu-map { + cluster0 { + core0 { + cpu = <&CPU0>; + }; + + core1 { + cpu = <&CPU1>; + }; + + core2 { + cpu = <&CPU2>; + }; + + core3 { + cpu = <&CPU3>; + }; + + core4 { + cpu = <&CPU4>; + }; + + core5 { + cpu = <&CPU5>; + }; + + core6 { + cpu = <&CPU6>; + }; + + core7 { + cpu = <&CPU7>; + }; + }; + }; + + idle-states { + entry-method = "psci"; + + SILVER_CPU_SLEEP_0: cpu-sleep-0-0 { + compatible = "arm,idle-state"; + idle-state-name = "silver-rail-power-collapse"; + arm,psci-suspend-param = <0x40000004>; + entry-latency-us = <550>; + exit-latency-us = <750>; + min-residency-us = <6700>; + local-timer-stop; + }; + + GOLD_CPU_SLEEP_0: cpu-sleep-1-0 { + compatible = "arm,idle-state"; + idle-state-name = "gold-rail-power-collapse"; + arm,psci-suspend-param = <0x40000004>; + entry-latency-us = <600>; + exit-latency-us = <1300>; + min-residency-us = <8136>; + local-timer-stop; + }; + + GOLD_PLUS_CPU_SLEEP_0: cpu-sleep-2-0 { + compatible = "arm,idle-state"; + idle-state-name = "gold-plus-rail-power-collapse"; + arm,psci-suspend-param = <0x40000004>; + entry-latency-us = <500>; + exit-latency-us = <1350>; + min-residency-us = <7480>; + local-timer-stop; + }; + }; + + domain-idle-states { + CLUSTER_SLEEP_0: cluster-sleep-0 { + compatible = "domain-idle-state"; + arm,psci-suspend-param = <0x41000044>; + entry-latency-us = <750>; + exit-latency-us = <2350>; + min-residency-us = <9144>; + }; + + CLUSTER_SLEEP_1: cluster-sleep-1 { + compatible = "domain-idle-state"; + arm,psci-suspend-param = <0x4100c344>; + entry-latency-us = <2800>; + exit-latency-us = <4400>; + min-residency-us = <10150>; + }; + }; + }; + + firmware { + scm: scm { + compatible = "qcom,scm-sm8650", "qcom,scm"; + interconnects = <&aggre2_noc MASTER_CRYPTO QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + }; + }; + + clk_virt: interconnect-0 { + compatible = "qcom,sm8650-clk-virt"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + mc_virt: interconnect-1 { + compatible = "qcom,sm8650-mc-virt"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + memory@a0000000 { + device_type = "memory"; + /* We expect the bootloader to fill in the size */ + reg = <0 0xa0000000 0 0>; + }; + + pmu { + compatible = "arm,armv8-pmuv3"; + interrupts = ; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + + CPU_PD0: power-domain-cpu0 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD>; + domain-idle-states = <&SILVER_CPU_SLEEP_0>; + }; + + CPU_PD1: power-domain-cpu1 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD>; + domain-idle-states = <&SILVER_CPU_SLEEP_0>; + }; + + CPU_PD2: power-domain-cpu2 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD>; + domain-idle-states = <&SILVER_CPU_SLEEP_0>; + }; + + CPU_PD3: power-domain-cpu3 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD>; + domain-idle-states = <&GOLD_CPU_SLEEP_0>; + }; + + CPU_PD4: power-domain-cpu4 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD>; + domain-idle-states = <&GOLD_CPU_SLEEP_0>; + }; + + CPU_PD5: power-domain-cpu5 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD>; + domain-idle-states = <&GOLD_CPU_SLEEP_0>; + }; + + CPU_PD6: power-domain-cpu6 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD>; + domain-idle-states = <&GOLD_CPU_SLEEP_0>; + }; + + CPU_PD7: power-domain-cpu7 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD>; + domain-idle-states = <&GOLD_PLUS_CPU_SLEEP_0>; + }; + + CLUSTER_PD: power-domain-cluster { + #power-domain-cells = <0>; + domain-idle-states = <&CLUSTER_SLEEP_0>, + <&CLUSTER_SLEEP_1>; + }; + }; + + reserved_memory: reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + hyp_mem: hyp@80000000 { + reg = <0 0x80000000 0 0xe00000>; + no-map; + }; + + cpusys_vm_mem: cpusys-vm@80e00000 { + reg = <0 0x80e00000 0 0x400000>; + no-map; + }; + + /* Merged xbl_dtlog, xbl_ramdump and aop_image regions */ + xbl_dt_log_merged_mem: xbl-dt-log-merged@81a00000 { + reg = <0 0x81a00000 0 0x260000>; + no-map; + }; + + aop_cmd_db_mem: aop-cmd-db@81c60000 { + compatible = "qcom,cmd-db"; + reg = <0 0x81c60000 0 0x20000>; + no-map; + }; + + /* Merged aop_config, tme_crash_dump, tme_log and uefi_log regions */ + aop_tme_uefi_merged_mem: aop-tme-uefi-merged@81c80000 { + reg = <0 0x81c80000 0 0x74000>; + no-map; + }; + + /* Secdata region can be reused by apps */ + + smem: smem@81d00000 { + compatible = "qcom,smem"; + reg = <0 0x81d00000 0 0x200000>; + hwlocks = <&tcsr_mutex 3>; + no-map; + }; + + adsp_mhi_mem: adsp-mhi@81f00000 { + reg = <0 0x81f00000 0 0x20000>; + no-map; + }; + + pvmfw_mem: pvmfw@824a0000 { + reg = <0 0x824a0000 0 0x100000>; + no-map; + }; + + global_sync_mem: global-sync@82600000 { + reg = <0 0x82600000 0 0x100000>; + no-map; + }; + + tz_stat_mem: tz-stat@82700000 { + reg = <0 0x82700000 0 0x100000>; + no-map; + }; + + qdss_mem: qdss@82800000 { + reg = <0 0x82800000 0 0x2000000>; + no-map; + }; + + mpss_dsm_mem: mpss-dsm@86b00000 { + reg = <0 0x86b00000 0 0x4900000>; + no-map; + }; + + mpss_dsm_mem_2: mpss-dsm-2@8b400000 { + reg = <0 0x8b400000 0 0x800000>; + no-map; + }; + + mpss_mem: mpss@8bc00000 { + reg = <0 0x8bc00000 0 0xf400000>; + no-map; + }; + + q6_mpss_dtb_mem: q6-mpss-dtb@9b000000 { + reg = <0 0x9b000000 0 0x80000>; + no-map; + }; + + ipa_fw_mem: ipa-fw@9b080000 { + reg = <0 0x9b080000 0 0x10000>; + no-map; + }; + + ipa_gsi_mem: ipa-gsi@9b090000 { + reg = <0 0x9b090000 0 0xa000>; + no-map; + }; + + gpu_micro_code_mem: gpu-micro-code@9b09a000 { + reg = <0 0x9b09a000 0 0x2000>; + no-map; + }; + + spss_region_mem: spss@9b0a0000 { + reg = <0 0x9b0a0000 0 0x1e0000>; + no-map; + }; + + /* First part of the "SPU secure shared memory" region */ + spu_tz_shared_mem: spu-tz-shared@9b280000 { + reg = <0 0x9b280000 0 0x60000>; + no-map; + }; + + /* Second part of the "SPU secure shared memory" region */ + spu_modem_shared_mem: spu-modem-shared@9b2e0000 { + reg = <0 0x9b2e0000 0 0x20000>; + no-map; + }; + + camera_mem: camera@9b300000 { + reg = <0 0x9b300000 0 0x800000>; + no-map; + }; + + video_mem: video@9bb00000 { + reg = <0 0x9bb00000 0 0x800000>; + no-map; + }; + + cvp_mem: cvp@9c300000 { + reg = <0 0x9c300000 0 0x700000>; + no-map; + }; + + cdsp_mem: cdsp@9ca00000 { + reg = <0 0x9ca00000 0 0x1400000>; + no-map; + }; + + q6_cdsp_dtb_mem: q6-cdsp-dtb@9de00000 { + reg = <0 0x9de00000 0 0x80000>; + no-map; + }; + + q6_adsp_dtb_mem: q6-adsp-dtb@9de80000 { + reg = <0 0x9de80000 0 0x80000>; + no-map; + }; + + adspslpi_mem: adspslpi@9df00000 { + reg = <0 0x9df00000 0 0x4080000>; + no-map; + }; + + rmtfs_mem: rmtfs@d7c00000 { + compatible = "qcom,rmtfs-mem"; + reg = <0 0xd7c00000 0 0x400000>; + no-map; + + qcom,client-id = <1>; + qcom,vmid = ; + }; + + /* Merged tz_reserved, xbl_sc, cpucp_fw and qtee regions */ + tz_merged_mem: tz-merged@d8000000 { + reg = <0 0xd8000000 0 0x800000>; + no-map; + }; + + hwfence_shbuf: hwfence-shbuf@e6440000 { + reg = <0 0xe6440000 0 0x2dd000>; + no-map; + }; + + trust_ui_vm_mem: trust-ui-vm@f3800000 { + reg = <0 0xf3800000 0 0x4400000>; + no-map; + }; + + oem_vm_mem: oem-vm@f7c00000 { + reg = <0 0xf7c00000 0 0x4c00000>; + no-map; + }; + + llcc_lpi_mem: llcc-lpi@ff800000 { + reg = <0 0xff800000 0 0x600000>; + no-map; + }; + }; + + smp2p-adsp { + compatible = "qcom,smp2p"; + + interrupts-extended = <&ipcc IPCC_CLIENT_LPASS + IPCC_MPROC_SIGNAL_SMP2P + IRQ_TYPE_EDGE_RISING>; + + mboxes = <&ipcc IPCC_CLIENT_LPASS + IPCC_MPROC_SIGNAL_SMP2P>; + + qcom,smem = <443>, <429>; + qcom,local-pid = <0>; + qcom,remote-pid = <2>; + + smp2p_adsp_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + smp2p_adsp_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + smp2p-cdsp { + compatible = "qcom,smp2p"; + + interrupts-extended = <&ipcc IPCC_CLIENT_CDSP + IPCC_MPROC_SIGNAL_SMP2P + IRQ_TYPE_EDGE_RISING>; + + mboxes = <&ipcc IPCC_CLIENT_CDSP + IPCC_MPROC_SIGNAL_SMP2P>; + + qcom,smem = <94>, <432>; + qcom,local-pid = <0>; + qcom,remote-pid = <5>; + + smp2p_cdsp_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + smp2p_cdsp_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + smp2p-modem { + compatible = "qcom,smp2p"; + + interrupts-extended = <&ipcc IPCC_CLIENT_MPSS + IPCC_MPROC_SIGNAL_SMP2P + IRQ_TYPE_EDGE_RISING>; + + mboxes = <&ipcc IPCC_CLIENT_MPSS + IPCC_MPROC_SIGNAL_SMP2P>; + + qcom,smem = <435>, <428>; + qcom,local-pid = <0>; + qcom,remote-pid = <1>; + + smp2p_modem_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + smp2p_modem_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + ipa_smp2p_out: ipa-ap-to-modem { + qcom,entry-name = "ipa"; + #qcom,smem-state-cells = <1>; + }; + + ipa_smp2p_in: ipa-modem-to-ap { + qcom,entry-name = "ipa"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + soc: soc@0 { + compatible = "simple-bus"; + + #address-cells = <2>; + #size-cells = <2>; + dma-ranges = <0 0 0 0 0x10 0>; + ranges = <0 0 0 0 0x10 0>; + + gcc: clock-controller@100000 { + compatible = "qcom,sm8650-gcc"; + reg = <0 0x00100000 0 0x1f4200>; + + clocks = <&bi_tcxo_div2>, + <&bi_tcxo_ao_div2>, + <&sleep_clk>, + <&pcie0_phy>, + <&pcie1_phy>, + <&pcie_1_phy_aux_clk>, + <&ufs_mem_phy 0>, + <&ufs_mem_phy 1>, + <&ufs_mem_phy 2>, + <&usb_dp_qmpphy QMP_USB43DP_USB3_PIPE_CLK>; + + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; + + ipcc: mailbox@406000 { + compatible = "qcom,sm8650-ipcc", "qcom,ipcc"; + reg = <0 0x00406000 0 0x1000>; + + interrupts = ; + interrupt-controller; + #interrupt-cells = <3>; + + #mbox-cells = <2>; + }; + + gpi_dma2: dma-controller@800000 { + compatible = "qcom,sm8650-gpi-dma", "qcom,sm6350-gpi-dma"; + reg = <0 0x00800000 0 0x60000>; + + interrupts = , + , + , + , + , + , + , + , + , + , + , + ; + + dma-channels = <12>; + dma-channel-mask = <0x3f>; + #dma-cells = <3>; + + iommus = <&apps_smmu 0x436 0>; + + dma-coherent; + + status = "disabled"; + }; + + qupv3_id_1: geniqup@8c0000 { + compatible = "qcom,geni-se-qup"; + reg = <0 0x008c0000 0 0x2000>; + + clocks = <&gcc GCC_QUPV3_WRAP_2_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_2_S_AHB_CLK>; + clock-names = "m-ahb", + "s-ahb"; + + iommus = <&apps_smmu 0x423 0>; + + dma-coherent; + + #address-cells = <2>; + #size-cells = <2>; + ranges; + + status = "disabled"; + + i2c8: i2c@880000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00880000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S0_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 0 QCOM_GPI_I2C>, + <&gpi_dma2 1 0 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c8_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi8: spi@880000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00880000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S0_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 0 QCOM_GPI_SPI>, + <&gpi_dma2 1 0 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi8_data_clk>, <&qup_spi8_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c9: i2c@884000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00884000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S1_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 1 QCOM_GPI_I2C>, + <&gpi_dma2 1 1 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c9_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi9: spi@884000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00884000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S1_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 1 QCOM_GPI_SPI>, + <&gpi_dma2 1 1 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi9_data_clk>, <&qup_spi9_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c10: i2c@888000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00888000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S2_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 2 QCOM_GPI_I2C>, + <&gpi_dma2 1 2 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c10_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi10: spi@888000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00888000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S2_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 2 QCOM_GPI_SPI>, + <&gpi_dma2 1 2 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi10_data_clk>, <&qup_spi10_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c11: i2c@88c000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x0088c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S3_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 3 QCOM_GPI_I2C>, + <&gpi_dma2 1 3 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c11_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi11: spi@88c000 { + compatible = "qcom,geni-spi"; + reg = <0 0x0088c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S3_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 3 QCOM_GPI_SPI>, + <&gpi_dma2 1 3 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi11_data_clk>, <&qup_spi11_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c12: i2c@890000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00890000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S4_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 4 QCOM_GPI_I2C>, + <&gpi_dma2 1 4 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c12_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi12: spi@890000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00890000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S4_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 4 QCOM_GPI_SPI>, + <&gpi_dma2 1 4 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi12_data_clk>, <&qup_spi12_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c13: i2c@894000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00894000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S5_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 5 QCOM_GPI_I2C>, + <&gpi_dma2 1 5 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c13_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi13: spi@894000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00894000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S5_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 5 QCOM_GPI_SPI>, + <&gpi_dma2 1 5 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi13_data_clk>, <&qup_spi13_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + uart14: serial@898000 { + compatible = "qcom,geni-uart"; + reg = <0 0x00898000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S6_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config"; + + pinctrl-0 = <&qup_uart14_default>, <&qup_uart14_cts_rts>; + pinctrl-names = "default"; + + status = "disabled"; + }; + + uart15: serial@89c000 { + compatible = "qcom,geni-debug-uart"; + reg = <0 0x0089c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S7_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config"; + + pinctrl-0 = <&qup_uart15_default>; + pinctrl-names = "default"; + + status = "disabled"; + }; + }; + + i2c_master_hub_0: geniqup@9c0000 { + compatible = "qcom,geni-se-i2c-master-hub"; + reg = <0 0x009c0000 0 0x2000>; + + clocks = <&gcc GCC_QUPV3_I2C_S_AHB_CLK>; + clock-names = "s-ahb"; + + #address-cells = <2>; + #size-cells = <2>; + ranges; + + status = "disabled"; + + i2c_hub_0: i2c@980000 { + compatible = "qcom,geni-i2c-master-hub"; + reg = <0 0x00980000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_I2C_S0_CLK>, + <&gcc GCC_QUPV3_I2C_CORE_CLK>; + clock-names = "se", + "core"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_I2C QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config"; + + pinctrl-0 = <&hub_i2c0_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c_hub_1: i2c@984000 { + compatible = "qcom,geni-i2c-master-hub"; + reg = <0 0x00984000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_I2C_S1_CLK>, + <&gcc GCC_QUPV3_I2C_CORE_CLK>; + clock-names = "se", + "core"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_I2C QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config"; + + pinctrl-0 = <&hub_i2c1_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c_hub_2: i2c@988000 { + compatible = "qcom,geni-i2c-master-hub"; + reg = <0 0x00988000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_I2C_S2_CLK>, + <&gcc GCC_QUPV3_I2C_CORE_CLK>; + clock-names = "se", + "core"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_I2C QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config"; + + pinctrl-0 = <&hub_i2c2_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c_hub_3: i2c@98c000 { + compatible = "qcom,geni-i2c-master-hub"; + reg = <0 0x0098c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_I2C_S3_CLK>, + <&gcc GCC_QUPV3_I2C_CORE_CLK>; + clock-names = "se", + "core"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_I2C QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config"; + + pinctrl-0 = <&hub_i2c3_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c_hub_4: i2c@990000 { + compatible = "qcom,geni-i2c-master-hub"; + reg = <0 0x00990000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_I2C_S4_CLK>, + <&gcc GCC_QUPV3_I2C_CORE_CLK>; + clock-names = "se", + "core"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_I2C QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config"; + + pinctrl-0 = <&hub_i2c4_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c_hub_5: i2c@994000 { + compatible = "qcom,geni-i2c-master-hub"; + reg = <0 0x00994000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_I2C_S5_CLK>, + <&gcc GCC_QUPV3_I2C_CORE_CLK>; + clock-names = "se", + "core"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_I2C QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config"; + + pinctrl-0 = <&hub_i2c5_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c_hub_6: i2c@998000 { + compatible = "qcom,geni-i2c-master-hub"; + reg = <0 0x00998000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_I2C_S6_CLK>, + <&gcc GCC_QUPV3_I2C_CORE_CLK>; + clock-names = "se", + "core"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_I2C QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config"; + + pinctrl-0 = <&hub_i2c6_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c_hub_7: i2c@99c000 { + compatible = "qcom,geni-i2c-master-hub"; + reg = <0 0x0099c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_I2C_S7_CLK>, + <&gcc GCC_QUPV3_I2C_CORE_CLK>; + clock-names = "se", + "core"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_I2C QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config"; + + pinctrl-0 = <&hub_i2c7_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c_hub_8: i2c@9a0000 { + compatible = "qcom,geni-i2c-master-hub"; + reg = <0 0x009a0000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_I2C_S8_CLK>, + <&gcc GCC_QUPV3_I2C_CORE_CLK>; + clock-names = "se", + "core"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_I2C QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config"; + + pinctrl-0 = <&hub_i2c8_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c_hub_9: i2c@9a4000 { + compatible = "qcom,geni-i2c-master-hub"; + reg = <0 0x009a4000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_I2C_S9_CLK>, + <&gcc GCC_QUPV3_I2C_CORE_CLK>; + clock-names = "se", + "core"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_I2C QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config"; + + pinctrl-0 = <&hub_i2c9_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + }; + + gpi_dma1: dma-controller@a00000 { + compatible = "qcom,sm8650-gpi-dma", "qcom,sm6350-gpi-dma"; + reg = <0 0x00a00000 0 0x60000>; + + interrupts = , + , + , + , + , + , + , + , + , + , + , + ; + + dma-channels = <12>; + dma-channel-mask = <0xc>; + #dma-cells = <3>; + + iommus = <&apps_smmu 0xb6 0>; + dma-coherent; + + status = "disabled"; + }; + + qupv3_id_0: geniqup@ac0000 { + compatible = "qcom,geni-se-qup"; + reg = <0 0x00ac0000 0 0x2000>; + + clocks = <&gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + clock-names = "m-ahb", + "s-ahb"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core"; + + iommus = <&apps_smmu 0xa3 0>; + + dma-coherent; + + #address-cells = <2>; + #size-cells = <2>; + ranges; + + status = "disabled"; + + i2c0: i2c@a80000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a80000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S0_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 0 QCOM_GPI_I2C>, + <&gpi_dma1 1 0 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c0_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi0: spi@a80000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a80000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S0_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 0 QCOM_GPI_SPI>, + <&gpi_dma1 1 0 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi0_data_clk>, <&qup_spi0_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c1: i2c@a84000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a84000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S1_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 1 QCOM_GPI_I2C>, + <&gpi_dma1 1 1 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c1_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi1: spi@a84000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a84000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S1_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 1 QCOM_GPI_SPI>, + <&gpi_dma1 1 1 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi1_data_clk>, <&qup_spi1_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c2: i2c@a88000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a88000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S2_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 2 QCOM_GPI_I2C>, + <&gpi_dma1 1 2 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c2_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi2: spi@a88000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a88000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S2_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 2 QCOM_GPI_SPI>, + <&gpi_dma1 1 2 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi2_data_clk>, <&qup_spi2_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c3: i2c@a8c000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a8c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S3_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 3 QCOM_GPI_I2C>, + <&gpi_dma1 1 3 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c3_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi3: spi@a8c000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a8c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S3_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 3 QCOM_GPI_SPI>, + <&gpi_dma1 1 3 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi3_data_clk>, <&qup_spi3_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c4: i2c@a90000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a90000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S4_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 4 QCOM_GPI_I2C>, + <&gpi_dma1 1 4 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c4_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi4: spi@a90000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a90000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S4_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 4 QCOM_GPI_SPI>, + <&gpi_dma1 1 4 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi4_data_clk>, <&qup_spi4_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c5: i2c@a94000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a94000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S5_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 5 QCOM_GPI_I2C>, + <&gpi_dma1 1 5 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c5_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi5: spi@a94000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a94000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S5_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 5 QCOM_GPI_SPI>, + <&gpi_dma1 1 5 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi5_data_clk>, <&qup_spi5_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c6: i2c@a98000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a98000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S6_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 6 QCOM_GPI_I2C>, + <&gpi_dma1 1 6 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c6_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi6: spi@a98000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a98000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S6_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 6 QCOM_GPI_SPI>, + <&gpi_dma1 1 6 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi6_data_clk>, <&qup_spi6_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c7: i2c@a9c000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a9c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S7_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 7 QCOM_GPI_I2C>, + <&gpi_dma1 1 7 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c7_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi7: spi@a9c000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a9c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S7_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 7 QCOM_GPI_SPI>, + <&gpi_dma1 1 7 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi7_data_clk>, <&qup_spi7_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + }; + + cnoc_main: interconnect@1500000 { + compatible = "qcom,sm8650-cnoc-main"; + reg = <0 0x01500000 0 0x14080>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + config_noc: interconnect@1600000 { + compatible = "qcom,sm8650-config-noc"; + reg = <0 0x01600000 0 0x6200>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + system_noc: interconnect@1680000 { + compatible = "qcom,sm8650-system-noc"; + reg = <0 0x01680000 0 0x1d080>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + pcie_noc: interconnect@16c0000 { + compatible = "qcom,sm8650-pcie-anoc"; + reg = <0 0x016c0000 0 0x12200>; + + clocks = <&gcc GCC_AGGRE_NOC_PCIE_AXI_CLK>, + <&gcc GCC_CFG_NOC_PCIE_ANOC_AHB_CLK>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + aggre1_noc: interconnect@16e0000 { + compatible = "qcom,sm8650-aggre1-noc"; + reg = <0 0x016e0000 0 0x16400>; + + clocks = <&gcc GCC_AGGRE_UFS_PHY_AXI_CLK>, + <&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + aggre2_noc: interconnect@1700000 { + compatible = "qcom,sm8650-aggre2-noc"; + reg = <0 0x01700000 0 0x1e400>; + + clocks = <&rpmhcc RPMH_IPA_CLK>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + mmss_noc: interconnect@1780000 { + compatible = "qcom,sm8650-mmss-noc"; + reg = <0 0x01780000 0 0x5b800>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + rng: rng@10c3000 { + compatible = "qcom,sm8650-trng", "qcom,trng"; + reg = <0 0x010c3000 0 0x1000>; + }; + + pcie0: pci@1c00000 { + device_type = "pci"; + compatible = "qcom,pcie-sm8650", "qcom,pcie-sm8550"; + reg = <0 0x01c00000 0 0x3000>, + <0 0x60000000 0 0xf1d>, + <0 0x60000f20 0 0xa8>, + <0 0x60001000 0 0x1000>, + <0 0x60100000 0 0x100000>; + reg-names = "parf", "dbi", "elbi", "atu", "config"; + + interrupts = ; + interrupt-names = "msi"; + + clocks = <&gcc GCC_PCIE_0_AUX_CLK>, + <&gcc GCC_PCIE_0_CFG_AHB_CLK>, + <&gcc GCC_PCIE_0_MSTR_AXI_CLK>, + <&gcc GCC_PCIE_0_SLV_AXI_CLK>, + <&gcc GCC_PCIE_0_SLV_Q2A_AXI_CLK>, + <&gcc GCC_DDRSS_PCIE_SF_QTB_CLK>, + <&gcc GCC_AGGRE_NOC_PCIE_AXI_CLK>, + <&gcc GCC_CNOC_PCIE_SF_AXI_CLK>; + clock-names = "aux", + "cfg", + "bus_master", + "bus_slave", + "slave_q2a", + "ddrss_sf_tbu", + "noc_aggr", + "cnoc_sf_axi"; + + resets = <&gcc GCC_PCIE_0_BCR>; + reset-names = "pci"; + + interconnects = <&pcie_noc MASTER_PCIE_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &cnoc_main SLAVE_PCIE_0 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "pcie-mem", + "cpu-pcie"; + + power-domains = <&gcc PCIE_0_GDSC>; + + iommu-map = <0 &apps_smmu 0x1400 0x1>, + <0x100 &apps_smmu 0x1401 0x1>; + + interrupt-map = <0 0 0 1 &intc 0 0 0 149 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 2 &intc 0 0 0 150 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 3 &intc 0 0 0 151 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 4 &intc 0 0 0 152 IRQ_TYPE_LEVEL_HIGH>; + interrupt-map-mask = <0 0 0 0x7>; + #interrupt-cells = <1>; + + linux,pci-domain = <0>; + num-lanes = <2>; + bus-range = <0 0xff>; + + phys = <&pcie0_phy>; + phy-names = "pciephy"; + + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x01000000 0 0x00000000 0 0x60200000 0 0x100000>, + <0x02000000 0 0x60300000 0 0x60300000 0 0x3d00000>; + + dma-coherent; + + status = "disabled"; + }; + + pcie0_phy: phy@1c06000 { + compatible = "qcom,sm8650-qmp-gen3x2-pcie-phy"; + reg = <0 0x01c06000 0 0x2000>; + + clocks = <&gcc GCC_PCIE_0_AUX_CLK>, + <&gcc GCC_PCIE_0_CFG_AHB_CLK>, + <&tcsr TCSR_PCIE_0_CLKREF_EN>, + <&gcc GCC_PCIE_0_PHY_RCHNG_CLK>, + <&gcc GCC_PCIE_0_PIPE_CLK>; + clock-names = "aux", + "cfg_ahb", + "ref", + "rchng", + "pipe"; + + assigned-clocks = <&gcc GCC_PCIE_0_PHY_RCHNG_CLK>; + assigned-clock-rates = <100000000>; + + resets = <&gcc GCC_PCIE_0_PHY_BCR>; + reset-names = "phy"; + + power-domains = <&gcc PCIE_0_PHY_GDSC>; + + #clock-cells = <0>; + clock-output-names = "pcie0_pipe_clk"; + + #phy-cells = <0>; + + status = "disabled"; + }; + + pcie1: pci@1c08000 { + device_type = "pci"; + compatible = "qcom,pcie-sm8650", "qcom,pcie-sm8550"; + reg = <0 0x01c08000 0 0x3000>, + <0 0x40000000 0 0xf1d>, + <0 0x40000f20 0 0xa8>, + <0 0x40001000 0 0x1000>, + <0 0x40100000 0 0x100000>; + reg-names = "parf", + "dbi", + "elbi", + "atu", + "config"; + + interrupts = ; + interrupt-names = "msi"; + + clocks = <&gcc GCC_PCIE_1_AUX_CLK>, + <&gcc GCC_PCIE_1_CFG_AHB_CLK>, + <&gcc GCC_PCIE_1_MSTR_AXI_CLK>, + <&gcc GCC_PCIE_1_SLV_AXI_CLK>, + <&gcc GCC_PCIE_1_SLV_Q2A_AXI_CLK>, + <&gcc GCC_DDRSS_PCIE_SF_QTB_CLK>, + <&gcc GCC_AGGRE_NOC_PCIE_AXI_CLK>, + <&gcc GCC_CNOC_PCIE_SF_AXI_CLK>; + clock-names = "aux", + "cfg", + "bus_master", + "bus_slave", + "slave_q2a", + "ddrss_sf_tbu", + "noc_aggr", + "cnoc_sf_axi"; + + assigned-clocks = <&gcc GCC_PCIE_1_AUX_CLK>; + assigned-clock-rates = <19200000>; + + resets = <&gcc GCC_PCIE_1_BCR>, + <&gcc GCC_PCIE_1_LINK_DOWN_BCR>; + reset-names = "pci", + "link_down"; + + interconnects = <&pcie_noc MASTER_PCIE_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &cnoc_main SLAVE_PCIE_1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "pcie-mem", + "cpu-pcie"; + + power-domains = <&gcc PCIE_1_GDSC>; + + iommu-map = <0 &apps_smmu 0x1480 0x1>, + <0x100 &apps_smmu 0x1481 0x1>; + + interrupt-map = <0 0 0 1 &intc 0 0 0 434 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 2 &intc 0 0 0 435 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 3 &intc 0 0 0 438 IRQ_TYPE_LEVEL_HIGH>, + <0 0 0 4 &intc 0 0 0 439 IRQ_TYPE_LEVEL_HIGH>; + interrupt-map-mask = <0 0 0 0x7>; + #interrupt-cells = <1>; + + linux,pci-domain = <1>; + num-lanes = <2>; + bus-range = <0 0xff>; + + phys = <&pcie1_phy>; + phy-names = "pciephy"; + + dma-coherent; + + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x01000000 0 0x00000000 0 0x40200000 0 0x100000>, + <0x02000000 0 0x40300000 0 0x40300000 0 0x1fd00000>; + + status = "disabled"; + }; + + pcie1_phy: phy@1c0e000 { + compatible = "qcom,sm8650-qmp-gen4x2-pcie-phy"; + reg = <0 0x01c0e000 0 0x2000>; + + clocks = <&gcc GCC_PCIE_1_PHY_AUX_CLK>, + <&gcc GCC_PCIE_1_CFG_AHB_CLK>, + <&tcsr TCSR_PCIE_1_CLKREF_EN>, + <&gcc GCC_PCIE_1_PHY_RCHNG_CLK>, + <&gcc GCC_PCIE_1_PIPE_CLK>; + clock-names = "aux", + "cfg_ahb", + "ref", + "rchng", + "pipe"; + + assigned-clocks = <&gcc GCC_PCIE_1_PHY_RCHNG_CLK>; + assigned-clock-rates = <100000000>; + + resets = <&gcc GCC_PCIE_1_PHY_BCR>, + <&gcc GCC_PCIE_1_NOCSR_COM_PHY_BCR>; + reset-names = "phy", + "phy_nocsr"; + + power-domains = <&gcc PCIE_1_PHY_GDSC>; + + #clock-cells = <0>; + clock-output-names = "pcie1_pipe_clk"; + + #phy-cells = <0>; + + status = "disabled"; + }; + + cryptobam: dma-controller@1dc4000 { + compatible = "qcom,bam-v1.7.0"; + reg = <0 0x01dc4000 0 0x28000>; + + interrupts = ; + + #dma-cells = <1>; + + iommus = <&apps_smmu 0x480 0>, + <&apps_smmu 0x481 0>; + + qcom,ee = <0>; + qcom,controlled-remotely; + }; + + crypto: crypto@1dfa000 { + compatible = "qcom,sm8650-qce", "qcom,sm8150-qce", "qcom,qce"; + reg = <0 0x01dfa000 0 0x6000>; + + interconnects = <&aggre2_noc MASTER_CRYPTO QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "memory"; + + dmas = <&cryptobam 4>, <&cryptobam 5>; + dma-names = "rx", "tx"; + + iommus = <&apps_smmu 0x480 0>, + <&apps_smmu 0x481 0>; + }; + + ufs_mem_phy: phy@1d80000 { + compatible = "qcom,sm8650-qmp-ufs-phy"; + reg = <0 0x01d80000 0 0x2000>; + + clocks = <&tcsr TCSR_UFS_CLKREF_EN>, + <&gcc GCC_UFS_PHY_PHY_AUX_CLK>; + clock-names = "ref", + "ref_aux"; + + resets = <&ufs_mem_hc 0>; + reset-names = "ufsphy"; + + power-domains = <&gcc UFS_MEM_PHY_GDSC>; + + #clock-cells = <1>; + #phy-cells = <0>; + + status = "disabled"; + }; + + ufs_mem_hc: ufs@1d84000 { + compatible = "qcom,sm8650-ufshc", "qcom,ufshc", "jedec,ufs-2.0"; + reg = <0 0x01d84000 0 0x3000>; + + interrupts = ; + + clocks = <&gcc GCC_UFS_PHY_AXI_CLK>, + <&gcc GCC_AGGRE_UFS_PHY_AXI_CLK>, + <&gcc GCC_UFS_PHY_AHB_CLK>, + <&gcc GCC_UFS_PHY_UNIPRO_CORE_CLK>, + <&tcsr TCSR_UFS_PAD_CLKREF_EN>, + <&gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>, + <&gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>, + <&gcc GCC_UFS_PHY_RX_SYMBOL_1_CLK>; + clock-names = "core_clk", + "bus_aggr_clk", + "iface_clk", + "core_clk_unipro", + "ref_clk", + "tx_lane0_sync_clk", + "rx_lane0_sync_clk", + "rx_lane1_sync_clk"; + freq-table-hz = <100000000 403000000>, + <0 0>, + <0 0>, + <100000000 403000000>, + <100000000 403000000>, + <0 0>, + <0 0>, + <0 0>; + + resets = <&gcc GCC_UFS_PHY_BCR>; + reset-names = "rst"; + + interconnects = <&aggre1_noc MASTER_UFS_MEM QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_UFS_MEM_CFG QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "ufs-ddr", + "cpu-ufs"; + + power-domains = <&gcc UFS_PHY_GDSC>; + required-opps = <&rpmhpd_opp_nom>; + + iommus = <&apps_smmu 0x60 0>; + + lanes-per-direction = <2>; + qcom,ice = <&ice>; + + phys = <&ufs_mem_phy>; + phy-names = "ufsphy"; + + #reset-cells = <1>; + + status = "disabled"; + }; + + ice: crypto@1d88000 { + compatible = "qcom,sm8650-inline-crypto-engine", + "qcom,inline-crypto-engine"; + reg = <0 0x01d88000 0 0x8000>; + + clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>; + }; + + tcsr_mutex: hwlock@1f40000 { + compatible = "qcom,tcsr-mutex"; + reg = <0 0x01f40000 0 0x20000>; + + #hwlock-cells = <1>; + }; + + tcsr: clock-controller@1fc0000 { + compatible = "qcom,sm8650-tcsr", "syscon"; + reg = <0 0x01fc0000 0 0xa0000>; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + + #clock-cells = <1>; + #reset-cells = <1>; + }; + + gpucc: clock-controller@3d90000 { + compatible = "qcom,sm8650-gpucc"; + reg = <0 0x03d90000 0 0xa000>; + + clocks = <&bi_tcxo_div2>, + <&gcc GCC_GPU_GPLL0_CLK_SRC>, + <&gcc GCC_GPU_GPLL0_DIV_CLK_SRC>; + + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; + + ipa: ipa@3f40000 { + compatible = "qcom,sm8650-ipa", "qcom,sm8550-ipa"; + + iommus = <&apps_smmu 0x4a0 0x0>, + <&apps_smmu 0x4a2 0x0>; + reg = <0 0x3f40000 0 0x10000>, + <0 0x3f50000 0 0x5000>, + <0 0x3e04000 0 0xfc000>; + reg-names = "ipa-reg", + "ipa-shared", + "gsi"; + + interrupts-extended = <&intc GIC_SPI 654 IRQ_TYPE_EDGE_RISING>, + <&intc GIC_SPI 432 IRQ_TYPE_LEVEL_HIGH>, + <&ipa_smp2p_in 0 IRQ_TYPE_EDGE_RISING>, + <&ipa_smp2p_in 1 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "ipa", + "gsi", + "ipa-clock-query", + "ipa-setup-ready"; + + clocks = <&rpmhcc RPMH_IPA_CLK>; + clock-names = "core"; + + interconnects = <&aggre2_noc MASTER_IPA 0 &mc_virt SLAVE_EBI1 0>, + <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_IPA_CFG 0>; + interconnect-names = "memory", + "config"; + + qcom,qmp = <&aoss_qmp>; + + qcom,smem-states = <&ipa_smp2p_out 0>, + <&ipa_smp2p_out 1>; + qcom,smem-state-names = "ipa-clock-enabled-valid", + "ipa-clock-enabled"; + + status = "disabled"; + }; + + remoteproc_mpss: remoteproc@4080000 { + compatible = "qcom,sm8650-mpss-pas"; + reg = <0 0x04080000 0 0x4040>; + + interrupts-extended = <&intc GIC_SPI 264 IRQ_TYPE_EDGE_RISING>, + <&smp2p_modem_in 0 IRQ_TYPE_EDGE_RISING>, + <&smp2p_modem_in 1 IRQ_TYPE_EDGE_RISING>, + <&smp2p_modem_in 2 IRQ_TYPE_EDGE_RISING>, + <&smp2p_modem_in 3 IRQ_TYPE_EDGE_RISING>, + <&smp2p_modem_in 7 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog", + "fatal", + "ready", + "handover", + "stop-ack", + "shutdown-ack"; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "xo"; + + interconnects = <&mc_virt MASTER_LLCC QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + + power-domains = <&rpmhpd RPMHPD_CX>, + <&rpmhpd RPMHPD_MSS>; + power-domain-names = "cx", + "mss"; + + memory-region = <&mpss_mem>, <&q6_mpss_dtb_mem>, + <&mpss_dsm_mem>, <&mpss_dsm_mem_2>; + + qcom,qmp = <&aoss_qmp>; + + qcom,smem-states = <&smp2p_modem_out 0>; + qcom,smem-state-names = "stop"; + + status = "disabled"; + + glink-edge { + interrupts-extended = <&ipcc IPCC_CLIENT_MPSS + IPCC_MPROC_SIGNAL_GLINK_QMP + IRQ_TYPE_EDGE_RISING>; + + mboxes = <&ipcc IPCC_CLIENT_MPSS + IPCC_MPROC_SIGNAL_GLINK_QMP>; + + qcom,remote-pid = <1>; + + label = "mpss"; + }; + }; + + lpass_wsa2macro: codec@6aa0000 { + compatible = "qcom,sm8650-lpass-wsa-macro", "qcom,sm8550-lpass-wsa-macro"; + reg = <0 0x06aa0000 0 0x1000>; + clocks = <&q6prmcc LPASS_CLK_ID_WSA2_CORE_TX_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&q6prmcc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&q6prmcc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&lpass_vamacro>; + clock-names = "mclk", + "macro", + "dcodec", + "fsgen"; + + #clock-cells = <0>; + clock-output-names = "wsa2-mclk"; + #sound-dai-cells = <1>; + }; + + swr3: soundwire@6ab0000 { + compatible = "qcom,soundwire-v2.0.0"; + reg = <0 0x06ab0000 0 0x10000>; + interrupts = ; + clocks = <&lpass_wsa2macro>; + clock-names = "iface"; + label = "WSA2"; + + pinctrl-0 = <&wsa2_swr_active>; + pinctrl-names = "default"; + + qcom,din-ports = <4>; + qcom,dout-ports = <9>; + + qcom,ports-sinterval = /bits/ 16 <0x07 0x1f 0x3f 0x07 0x1f 0x3f 0x18f 0xff 0xff 0x0f 0x0f 0xff 0x31f>; + qcom,ports-offset1 = /bits/ 8 <0x01 0x03 0x05 0x02 0x04 0x15 0x00 0xff 0xff 0x06 0x0d 0xff 0x00>; + qcom,ports-offset2 = /bits/ 8 <0xff 0x07 0x1f 0xff 0x07 0x1f 0xff 0xff 0xff 0xff 0xff 0xff 0xff>; + qcom,ports-hstart = /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0x08 0xff 0xff 0xff 0xff 0xff 0x0f>; + qcom,ports-hstop = /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0x08 0xff 0xff 0xff 0xff 0xff 0x0f>; + qcom,ports-word-length = /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0x08 0xff 0xff 0xff 0xff 0xff 0x18>; + qcom,ports-block-pack-mode = /bits/ 8 <0x00 0x01 0x01 0x00 0x01 0x01 0x00 0x00 0x00 0x01 0x01 0x00 0x00>; + qcom,ports-block-group-count = /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff>; + qcom,ports-lane-control = /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff>; + + #address-cells = <2>; + #size-cells = <0>; + #sound-dai-cells = <1>; + status = "disabled"; + }; + + lpass_rxmacro: codec@6ac0000 { + compatible = "qcom,sm8650-lpass-rx-macro", "qcom,sm8550-lpass-rx-macro"; + reg = <0 0x06ac0000 0 0x1000>; + clocks = <&q6prmcc LPASS_CLK_ID_RX_CORE_TX_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&q6prmcc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&q6prmcc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&lpass_vamacro>; + clock-names = "mclk", + "macro", + "dcodec", + "fsgen"; + + #clock-cells = <0>; + clock-output-names = "mclk"; + #sound-dai-cells = <1>; + }; + + swr1: soundwire@6ad0000 { + compatible = "qcom,soundwire-v2.0.0"; + reg = <0 0x06ad0000 0 0x10000>; + interrupts = ; + clocks = <&lpass_rxmacro>; + clock-names = "iface"; + label = "RX"; + + pinctrl-0 = <&rx_swr_active>; + pinctrl-names = "default"; + + qcom,din-ports = <0>; + qcom,dout-ports = <11>; + + qcom,ports-sinterval = /bits/ 16 <0x03 0x1f 0x1f 0x07 0x03 0xff 0xff 0x31 0xff 0xff 0xff>; + qcom,ports-offset1 = /bits/ 8 <0x00 0x00 0x0b 0x09 0x01 0xff 0xff 0x00 0xff 0xff 0xff>; + qcom,ports-offset2 = /bits/ 8 <0x00 0x00 0x0b 0x00 0x00 0xff 0xff 0x00 0xff 0xff 0xff>; + qcom,ports-hstart = /bits/ 8 <0xff 0x03 0xff 0xff 0xff 0xff 0xff 0x00 0xff 0xff 0xff>; + qcom,ports-hstop = /bits/ 8 <0xff 0x06 0xff 0xff 0xff 0xff 0xff 0x0f 0xff 0xff 0xff>; + qcom,ports-word-length = /bits/ 8 <0x01 0x07 0x04 0xff 0xff 0xff 0xff 0x18 0xff 0xff 0xff>; + qcom,ports-block-pack-mode = /bits/ 8 <0xff 0x00 0x01 0xff 0xff 0xff 0xff 0x01 0xff 0xff 0xff>; + qcom,ports-block-group-count = /bits/ 8 <0xff 0xff 0xff 0x01 0x03 0xff 0xff 0x00 0xff 0xff 0xff>; + qcom,ports-lane-control = /bits/ 8 <0x01 0x00 0x00 0x00 0x00 0xff 0xff 0x01 0xff 0xff 0xff>; + + #address-cells = <2>; + #size-cells = <0>; + #sound-dai-cells = <1>; + status = "disabled"; + }; + + lpass_txmacro: codec@6ae0000 { + compatible = "qcom,sm8650-lpass-tx-macro", "qcom,sm8550-lpass-tx-macro"; + reg = <0 0x06ae0000 0 0x1000>; + clocks = <&q6prmcc LPASS_CLK_ID_TX_CORE_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&q6prmcc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&q6prmcc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&lpass_vamacro>; + clock-names = "mclk", + "macro", + "dcodec", + "fsgen"; + + #clock-cells = <0>; + clock-output-names = "mclk"; + #sound-dai-cells = <1>; + }; + + lpass_wsamacro: codec@6b00000 { + compatible = "qcom,sm8650-lpass-wsa-macro", "qcom,sm8550-lpass-wsa-macro"; + reg = <0 0x06b00000 0 0x1000>; + clocks = <&q6prmcc LPASS_CLK_ID_WSA_CORE_TX_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&q6prmcc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&q6prmcc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&lpass_vamacro>; + clock-names = "mclk", + "macro", + "dcodec", + "fsgen"; + + #clock-cells = <0>; + clock-output-names = "mclk"; + #sound-dai-cells = <1>; + }; + + swr0: soundwire@6b10000 { + compatible = "qcom,soundwire-v2.0.0"; + reg = <0 0x06b10000 0 0x10000>; + interrupts = ; + clocks = <&lpass_wsamacro>; + clock-names = "iface"; + label = "WSA"; + + pinctrl-0 = <&wsa_swr_active>; + pinctrl-names = "default"; + + qcom,din-ports = <4>; + qcom,dout-ports = <9>; + + qcom,ports-sinterval = /bits/ 16 <0x07 0x1f 0x3f 0x07 0x1f 0x3f 0x18f 0xff 0xff 0x0f 0x0f 0xff 0x31f>; + qcom,ports-offset1 = /bits/ 8 <0x01 0x03 0x05 0x02 0x04 0x15 0x00 0xff 0xff 0x06 0x0d 0xff 0x00>; + qcom,ports-offset2 = /bits/ 8 <0xff 0x07 0x1f 0xff 0x07 0x1f 0xff 0xff 0xff 0xff 0xff 0xff 0xff>; + qcom,ports-hstart = /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0x08 0xff 0xff 0xff 0xff 0xff 0x0f>; + qcom,ports-hstop = /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0x08 0xff 0xff 0xff 0xff 0xff 0x0f>; + qcom,ports-word-length = /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0x08 0xff 0xff 0xff 0xff 0xff 0x18>; + qcom,ports-block-pack-mode = /bits/ 8 <0x00 0x01 0x01 0x00 0x01 0x01 0x00 0x00 0x00 0x01 0x01 0x00 0x00>; + qcom,ports-block-group-count = /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff>; + qcom,ports-lane-control = /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff>; + + #address-cells = <2>; + #size-cells = <0>; + #sound-dai-cells = <1>; + status = "disabled"; + }; + + swr2: soundwire@6d30000 { + compatible = "qcom,soundwire-v2.0.0"; + reg = <0 0x06d30000 0 0x10000>; + interrupts = , + ; + interrupt-names = "core", "wakeup"; + clocks = <&lpass_txmacro>; + clock-names = "iface"; + label = "TX"; + + pinctrl-0 = <&tx_swr_active>; + pinctrl-names = "default"; + + qcom,din-ports = <4>; + qcom,dout-ports = <0>; + + qcom,ports-sinterval-low = /bits/ 8 <0x01 0x01 0x03 0x03>; + qcom,ports-offset1 = /bits/ 8 <0x00 0x00 0x01 0x01>; + qcom,ports-offset2 = /bits/ 8 <0x00 0x00 0x00 0x00>; + qcom,ports-hstart = /bits/ 8 <0xff 0xff 0xff 0xff>; + qcom,ports-hstop = /bits/ 8 <0xff 0xff 0xff 0xff>; + qcom,ports-word-length = /bits/ 8 <0xff 0xff 0xff 0xff>; + qcom,ports-block-pack-mode = /bits/ 8 <0xff 0xff 0xff 0xff>; + qcom,ports-block-group-count = /bits/ 8 <0xff 0xff 0xff 0xff>; + qcom,ports-lane-control = /bits/ 8 <0x01 0x02 0x00 0x00>; + + #address-cells = <2>; + #size-cells = <0>; + #sound-dai-cells = <1>; + status = "disabled"; + }; + + lpass_vamacro: codec@6d44000 { + compatible = "qcom,sm8650-lpass-va-macro", "qcom,sm8550-lpass-va-macro"; + reg = <0 0x06d44000 0 0x1000>; + clocks = <&q6prmcc LPASS_CLK_ID_TX_CORE_MCLK LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&q6prmcc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&q6prmcc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>; + clock-names = "mclk", + "macro", + "dcodec"; + + #clock-cells = <0>; + clock-output-names = "fsgen"; + #sound-dai-cells = <1>; + }; + + lpass_tlmm: pinctrl@6e80000 { + compatible = "qcom,sm8650-lpass-lpi-pinctrl"; + reg = <0 0x06e80000 0 0x20000>; + + clocks = <&q6prmcc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, + <&q6prmcc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>; + clock-names = "core", "audio"; + + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&lpass_tlmm 0 0 23>; + + tx_swr_active: tx-swr-active-state { + clk-pins { + pins = "gpio0"; + function = "swr_tx_clk"; + drive-strength = <2>; + slew-rate = <1>; + bias-disable; + }; + + data-pins { + pins = "gpio1", "gpio2", "gpio14"; + function = "swr_tx_data"; + drive-strength = <2>; + slew-rate = <1>; + bias-bus-hold; + }; + }; + + rx_swr_active: rx-swr-active-state { + clk-pins { + pins = "gpio3"; + function = "swr_rx_clk"; + drive-strength = <2>; + slew-rate = <1>; + bias-disable; + }; + + data-pins { + pins = "gpio4", "gpio5"; + function = "swr_rx_data"; + drive-strength = <2>; + slew-rate = <1>; + bias-bus-hold; + }; + }; + + dmic01_default: dmic01-default-state { + clk-pins { + pins = "gpio6"; + function = "dmic1_clk"; + drive-strength = <8>; + output-high; + }; + + data-pins { + pins = "gpio7"; + function = "dmic1_data"; + drive-strength = <8>; + input-enable; + }; + }; + + dmic02_default: dmic02-default-state { + clk-pins { + pins = "gpio8"; + function = "dmic2_clk"; + drive-strength = <8>; + output-high; + }; + + data-pins { + pins = "gpio9"; + function = "dmic2_data"; + drive-strength = <8>; + input-enable; + }; + }; + + wsa_swr_active: wsa-swr-active-state { + clk-pins { + pins = "gpio10"; + function = "wsa_swr_clk"; + drive-strength = <2>; + slew-rate = <1>; + bias-disable; + }; + + data-pins { + pins = "gpio11"; + function = "wsa_swr_data"; + drive-strength = <2>; + slew-rate = <1>; + bias-bus-hold; + }; + }; + + wsa2_swr_active: wsa2-swr-active-state { + clk-pins { + pins = "gpio15"; + function = "wsa2_swr_clk"; + drive-strength = <2>; + slew-rate = <1>; + bias-disable; + }; + + data-pins { + pins = "gpio16"; + function = "wsa2_swr_data"; + drive-strength = <2>; + slew-rate = <1>; + bias-bus-hold; + }; + }; + }; + + lpass_lpiaon_noc: interconnect@7400000 { + compatible = "qcom,sm8650-lpass-lpiaon-noc"; + reg = <0 0x07400000 0 0x19080>; + + #interconnect-cells = <2>; + + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + lpass_lpicx_noc: interconnect@7430000 { + compatible = "qcom,sm8650-lpass-lpicx-noc"; + reg = <0 0x07430000 0 0x3a200>; + + #interconnect-cells = <2>; + + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + lpass_ag_noc: interconnect@7e40000 { + compatible = "qcom,sm8650-lpass-ag-noc"; + reg = <0 0x07e40000 0 0xe080>; + + #interconnect-cells = <2>; + + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + sdhc_2: mmc@8804000 { + compatible = "qcom,sm8650-sdhci", "qcom,sdhci-msm-v5"; + reg = <0 0x08804000 0 0x1000>; + + interrupts = , + ; + interrupt-names = "hc_irq", + "pwr_irq"; + + clocks = <&gcc GCC_SDCC2_AHB_CLK>, + <&gcc GCC_SDCC2_APPS_CLK>, + <&rpmhcc RPMH_CXO_CLK>; + clock-names = "iface", + "core", + "xo"; + + interconnects = <&aggre2_noc MASTER_SDCC_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_SDCC_2 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "sdhc-ddr", + "cpu-sdhc"; + + power-domains = <&rpmhpd RPMHPD_CX>; + operating-points-v2 = <&sdhc2_opp_table>; + + iommus = <&apps_smmu 0x540 0>; + + bus-width = <4>; + + /* Forbid SDR104/SDR50 - broken hw! */ + sdhci-caps-mask = <0x3 0>; + + qcom,dll-config = <0x0007642c>; + qcom,ddr-config = <0x80040868>; + + dma-coherent; + + status = "disabled"; + + sdhc2_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-19200000 { + opp-hz = /bits/ 64 <19200000>; + required-opps = <&rpmhpd_opp_min_svs>; + }; + + opp-50000000 { + opp-hz = /bits/ 64 <50000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-100000000 { + opp-hz = /bits/ 64 <100000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-202000000 { + opp-hz = /bits/ 64 <202000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + }; + }; + + mdss: display-subsystem@ae00000 { + compatible = "qcom,sm8650-mdss"; + reg = <0 0x0ae00000 0 0x1000>; + reg-names = "mdss"; + + interrupts = ; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&gcc GCC_DISP_HF_AXI_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>; + + resets = <&dispcc DISP_CC_MDSS_CORE_BCR>; + + interconnects = <&mmss_noc MASTER_MDP QCOM_ICC_TAG_ALWAYS + &gem_noc SLAVE_LLCC QCOM_ICC_TAG_ALWAYS>, + <&mc_virt MASTER_LLCC QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "mdp0-mem", + "mdp1-mem"; + + power-domains = <&dispcc MDSS_GDSC>; + + iommus = <&apps_smmu 0x1c00 0x2>; + + interrupt-controller; + #interrupt-cells = <1>; + + #address-cells = <2>; + #size-cells = <2>; + ranges; + + status = "disabled"; + + mdss_mdp: display-controller@ae01000 { + compatible = "qcom,sm8650-dpu"; + reg = <0 0x0ae01000 0 0x8f000>, + <0 0x0aeb0000 0 0x2008>; + reg-names = "mdp", + "vbif"; + + interrupts-extended = <&mdss 0>; + + clocks = <&gcc GCC_DISP_HF_AXI_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_MDP_LUT_CLK>, + <&dispcc DISP_CC_MDSS_MDP_CLK>, + <&dispcc DISP_CC_MDSS_VSYNC_CLK>; + clock-names = "nrt_bus", + "iface", + "lut", + "core", + "vsync"; + + assigned-clocks = <&dispcc DISP_CC_MDSS_VSYNC_CLK>; + assigned-clock-rates = <19200000>; + + operating-points-v2 = <&mdp_opp_table>; + + power-domains = <&rpmhpd RPMHPD_MMCX>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + dpu_intf1_out: endpoint { + remote-endpoint = <&mdss_dsi0_in>; + }; + }; + + port@1 { + reg = <1>; + + dpu_intf2_out: endpoint { + remote-endpoint = <&mdss_dsi1_in>; + }; + }; + + port@2 { + reg = <2>; + + dpu_intf0_out: endpoint { + remote-endpoint = <&mdss_dp0_in>; + }; + }; + }; + + mdp_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-200000000 { + opp-hz = /bits/ 64 <200000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-325000000 { + opp-hz = /bits/ 64 <325000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-375000000 { + opp-hz = /bits/ 64 <375000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-514000000 { + opp-hz = /bits/ 64 <514000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + }; + + mdss_dsi0: dsi@ae94000 { + compatible = "qcom,sm8650-dsi-ctrl", "qcom,mdss-dsi-ctrl"; + reg = <0 0x0ae94000 0 0x400>; + reg-names = "dsi_ctrl"; + + interrupts-extended = <&mdss 4>; + + clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK>, + <&dispcc DISP_CC_MDSS_BYTE0_INTF_CLK>, + <&dispcc DISP_CC_MDSS_PCLK0_CLK>, + <&dispcc DISP_CC_MDSS_ESC0_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&gcc GCC_DISP_HF_AXI_CLK>; + clock-names = "byte", + "byte_intf", + "pixel", + "core", + "iface", + "bus"; + + assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>, + <&dispcc DISP_CC_MDSS_PCLK0_CLK_SRC>; + assigned-clock-parents = <&mdss_dsi0_phy 0>, + <&mdss_dsi0_phy 1>; + + operating-points-v2 = <&mdss_dsi_opp_table>; + + power-domains = <&rpmhpd RPMHPD_MMCX>; + + phys = <&mdss_dsi0_phy>; + phy-names = "dsi"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + mdss_dsi0_in: endpoint { + remote-endpoint = <&dpu_intf1_out>; + }; + }; + + port@1 { + reg = <1>; + + mdss_dsi0_out: endpoint { + }; + }; + }; + + mdss_dsi_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-187500000 { + opp-hz = /bits/ 64 <187500000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-300000000 { + opp-hz = /bits/ 64 <300000000>; + required-opps = <&rpmhpd_opp_svs>; + }; + + opp-358000000 { + opp-hz = /bits/ 64 <358000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + }; + }; + + mdss_dsi0_phy: phy@ae95000 { + compatible = "qcom,sm8650-dsi-phy-4nm"; + reg = <0 0x0ae95000 0 0x200>, + <0 0x0ae95200 0 0x280>, + <0 0x0ae95500 0 0x400>; + reg-names = "dsi_phy", + "dsi_phy_lane", + "dsi_pll"; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&rpmhcc RPMH_CXO_CLK>; + clock-names = "iface", + "ref"; + + #clock-cells = <1>; + #phy-cells = <0>; + + status = "disabled"; + }; + + mdss_dsi1: dsi@ae96000 { + compatible = "qcom,sm8650-dsi-ctrl", "qcom,mdss-dsi-ctrl"; + reg = <0 0x0ae96000 0 0x400>; + reg-names = "dsi_ctrl"; + + interrupts-extended = <&mdss 5>; + + clocks = <&dispcc DISP_CC_MDSS_BYTE1_CLK>, + <&dispcc DISP_CC_MDSS_BYTE1_INTF_CLK>, + <&dispcc DISP_CC_MDSS_PCLK1_CLK>, + <&dispcc DISP_CC_MDSS_ESC1_CLK>, + <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&gcc GCC_DISP_HF_AXI_CLK>; + clock-names = "byte", + "byte_intf", + "pixel", + "core", + "iface", + "bus"; + + assigned-clocks = <&dispcc DISP_CC_MDSS_BYTE1_CLK_SRC>, + <&dispcc DISP_CC_MDSS_PCLK1_CLK_SRC>; + assigned-clock-parents = <&mdss_dsi1_phy 0>, + <&mdss_dsi1_phy 1>; + + operating-points-v2 = <&mdss_dsi_opp_table>; + + power-domains = <&rpmhpd RPMHPD_MMCX>; + + phys = <&mdss_dsi1_phy>; + phy-names = "dsi"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + mdss_dsi1_in: endpoint { + remote-endpoint = <&dpu_intf2_out>; + }; + }; + + port@1 { + reg = <1>; + + mdss_dsi1_out: endpoint { + }; + }; + }; + }; + + mdss_dsi1_phy: phy@ae97000 { + compatible = "qcom,sm8650-dsi-phy-4nm"; + reg = <0 0x0ae97000 0 0x200>, + <0 0x0ae97200 0 0x280>, + <0 0x0ae97500 0 0x400>; + reg-names = "dsi_phy", + "dsi_phy_lane", + "dsi_pll"; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&rpmhcc RPMH_CXO_CLK>; + clock-names = "iface", + "ref"; + + #clock-cells = <1>; + #phy-cells = <0>; + + status = "disabled"; + }; + + mdss_dp0: displayport-controller@af54000 { + compatible = "qcom,sm8650-dp"; + reg = <0 0xaf54000 0 0x104>, + <0 0xaf54200 0 0xc0>, + <0 0xaf55000 0 0x770>, + <0 0xaf56000 0 0x9c>, + <0 0xaf57000 0 0x9c>; + + interrupts-extended = <&mdss 12>; + + clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>, + <&dispcc DISP_CC_MDSS_DPTX0_AUX_CLK>, + <&dispcc DISP_CC_MDSS_DPTX0_LINK_CLK>, + <&dispcc DISP_CC_MDSS_DPTX0_LINK_INTF_CLK>, + <&dispcc DISP_CC_MDSS_DPTX0_PIXEL0_CLK>; + clock-names = "core_iface", + "core_aux", + "ctrl_link", + "ctrl_link_iface", + "stream_pixel"; + + assigned-clocks = <&dispcc DISP_CC_MDSS_DPTX0_LINK_CLK_SRC>, + <&dispcc DISP_CC_MDSS_DPTX0_PIXEL0_CLK_SRC>; + assigned-clock-parents = <&usb_dp_qmpphy QMP_USB43DP_DP_LINK_CLK>, + <&usb_dp_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>; + + operating-points-v2 = <&dp_opp_table>; + + power-domains = <&rpmhpd RPMHPD_MMCX>; + + phys = <&usb_dp_qmpphy QMP_USB43DP_DP_PHY>; + phy-names = "dp"; + + #sound-dai-cells = <0>; + + status = "disabled"; + + dp_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-162000000 { + opp-hz = /bits/ 64 <162000000>; + required-opps = <&rpmhpd_opp_low_svs_d1>; + }; + + opp-270000000 { + opp-hz = /bits/ 64 <270000000>; + required-opps = <&rpmhpd_opp_low_svs>; + }; + + opp-540000000 { + opp-hz = /bits/ 64 <540000000>; + required-opps = <&rpmhpd_opp_svs_l1>; + }; + + opp-810000000 { + opp-hz = /bits/ 64 <810000000>; + required-opps = <&rpmhpd_opp_nom>; + }; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + mdss_dp0_in: endpoint { + remote-endpoint = <&dpu_intf0_out>; + }; + }; + + port@1 { + reg = <1>; + + mdss_dp0_out: endpoint { + }; + }; + }; + }; + }; + + dispcc: clock-controller@af00000 { + compatible = "qcom,sm8650-dispcc"; + reg = <0 0x0af00000 0 0x20000>; + + clocks = <&bi_tcxo_div2>, + <&bi_tcxo_ao_div2>, + <&gcc GCC_DISP_AHB_CLK>, + <&sleep_clk>, + <&mdss_dsi0_phy 0>, + <&mdss_dsi0_phy 1>, + <&mdss_dsi1_phy 0>, + <&mdss_dsi1_phy 1>, + <&usb_dp_qmpphy QMP_USB43DP_DP_LINK_CLK>, + <&usb_dp_qmpphy QMP_USB43DP_DP_VCO_DIV_CLK>, + <0>, /* dp1 */ + <0>, + <0>, /* dp2 */ + <0>, + <0>, /* dp3 */ + <0>; + + power-domains = <&rpmhpd RPMHPD_MMCX>; + required-opps = <&rpmhpd_opp_low_svs>; + + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + + status = "disabled"; + }; + + usb_1_hsphy: phy@88e3000 { + compatible = "qcom,sm8650-snps-eusb2-phy", + "qcom,sm8550-snps-eusb2-phy"; + reg = <0 0x088e3000 0 0x154>; + + clocks = <&tcsr TCSR_USB2_CLKREF_EN>; + clock-names = "ref"; + + resets = <&gcc GCC_QUSB2PHY_PRIM_BCR>; + + #phy-cells = <0>; + + status = "disabled"; + }; + + usb_dp_qmpphy: phy@88e8000 { + compatible = "qcom,sm8650-qmp-usb3-dp-phy"; + reg = <0 0x088e8000 0 0x3000>; + + clocks = <&gcc GCC_USB3_PRIM_PHY_AUX_CLK>, + <&rpmhcc RPMH_CXO_CLK>, + <&gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>, + <&gcc GCC_USB3_PRIM_PHY_PIPE_CLK>; + clock-names = "aux", + "ref", + "com_aux", + "usb3_pipe"; + + resets = <&gcc GCC_USB3_PHY_PRIM_BCR>, + <&gcc GCC_USB3_DP_PHY_PRIM_BCR>; + reset-names = "phy", + "common"; + + power-domains = <&gcc USB3_PHY_GDSC>; + + #clock-cells = <1>; + #phy-cells = <1>; + + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + usb_dp_qmpphy_out: endpoint { + }; + }; + + port@1 { + reg = <1>; + + usb_dp_qmpphy_usb_ss_in: endpoint { + }; + }; + + port@2 { + reg = <2>; + + usb_dp_qmpphy_dp_in: endpoint { + }; + }; + }; + }; + + usb_1: usb@a6f8800 { + compatible = "qcom,sm8650-dwc3", "qcom,dwc3"; + reg = <0 0x0a6f8800 0 0x400>; + + interrupts-extended = <&intc GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 17 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 15 IRQ_TYPE_EDGE_RISING>, + <&pdc 14 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "hs_phy_irq", + "ss_phy_irq", + "dm_hs_phy_irq", + "dp_hs_phy_irq"; + + clocks = <&gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>, + <&gcc GCC_USB30_PRIM_MASTER_CLK>, + <&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>, + <&gcc GCC_USB30_PRIM_SLEEP_CLK>, + <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, + <&tcsr TCSR_USB3_CLKREF_EN>; + clock-names = "cfg_noc", + "core", + "iface", + "sleep", + "mock_utmi", + "xo"; + + assigned-clocks = <&gcc GCC_USB30_PRIM_MOCK_UTMI_CLK>, + <&gcc GCC_USB30_PRIM_MASTER_CLK>; + assigned-clock-rates = <19200000>, <200000000>; + + resets = <&gcc GCC_USB30_PRIM_BCR>; + + power-domains = <&gcc USB30_PRIM_GDSC>; + required-opps = <&rpmhpd_opp_nom>; + + #address-cells = <2>; + #size-cells = <2>; + ranges; + + status = "disabled"; + + usb_1_dwc3: usb@a600000 { + compatible = "snps,dwc3"; + reg = <0 0x0a600000 0 0xcd00>; + + interrupts = ; + + iommus = <&apps_smmu 0x40 0>; + + phys = <&usb_1_hsphy>, + <&usb_dp_qmpphy QMP_USB43DP_USB3_PHY>; + phy-names = "usb2-phy", + "usb3-phy"; + + snps,hird-threshold = /bits/ 8 <0x0>; + snps,usb2-gadget-lpm-disable; + snps,dis_u2_susphy_quirk; + snps,dis_enblslpm_quirk; + snps,dis-u1-entry-quirk; + snps,dis-u2-entry-quirk; + snps,is-utmi-l1-suspend; + snps,usb3_lpm_capable; + snps,usb2-lpm-disable; + snps,has-lpm-erratum; + tx-fifo-resize; + + dma-coherent; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + usb_1_dwc3_hs: endpoint { + }; + }; + + port@1 { + reg = <1>; + + usb_1_dwc3_ss: endpoint { + }; + }; + }; + }; + }; + + pdc: interrupt-controller@b220000 { + compatible = "qcom,sm8650-pdc", "qcom,pdc"; + reg = <0 0x0b220000 0 0x30000>, <0 0x174000f0 0 0x64>; + + interrupt-parent = <&intc>; + + qcom,pdc-ranges = <0 480 94>, <94 609 31>, + <125 63 1>, <126 716 12>, + <138 251 5>, <143 244 4>; + + #interrupt-cells = <2>; + interrupt-controller; + }; + + tsens0: thermal-sensor@c228000 { + compatible = "qcom,sm8650-tsens", "qcom,tsens-v2"; + reg = <0 0x0c228000 0 0x1000>, /* TM */ + <0 0x0c222000 0 0x1000>; /* SROT */ + + interrupts = , + ; + interrupt-names = "uplow", + "critical"; + + #qcom,sensors = <15>; + + #thermal-sensor-cells = <1>; + }; + + tsens1: thermal-sensor@c229000 { + compatible = "qcom,sm8650-tsens", "qcom,tsens-v2"; + reg = <0 0x0c229000 0 0x1000>, /* TM */ + <0 0x0c223000 0 0x1000>; /* SROT */ + + interrupts = , + ; + interrupt-names = "uplow", + "critical"; + + #qcom,sensors = <16>; + + #thermal-sensor-cells = <1>; + }; + + tsens2: thermal-sensor@c22a000 { + compatible = "qcom,sm8650-tsens", "qcom,tsens-v2"; + reg = <0 0x0c22a000 0 0x1000>, /* TM */ + <0 0x0c224000 0 0x1000>; /* SROT */ + + interrupts = , + ; + interrupt-names = "uplow", + "critical"; + + #qcom,sensors = <13>; + + #thermal-sensor-cells = <1>; + }; + + aoss_qmp: power-management@c300000 { + compatible = "qcom,sm8650-aoss-qmp", "qcom,aoss-qmp"; + reg = <0 0x0c300000 0 0x400>; + + interrupt-parent = <&ipcc>; + interrupts-extended = <&ipcc IPCC_CLIENT_AOP IPCC_MPROC_SIGNAL_GLINK_QMP + IRQ_TYPE_EDGE_RISING>; + + mboxes = <&ipcc IPCC_CLIENT_AOP IPCC_MPROC_SIGNAL_GLINK_QMP>; + + #clock-cells = <0>; + }; + + sram@c3f0000 { + compatible = "qcom,rpmh-stats"; + reg = <0 0x0c3f0000 0 0x400>; + }; + + spmi_bus: spmi@c400000 { + compatible = "qcom,spmi-pmic-arb"; + reg = <0 0x0c400000 0 0x3000>, + <0 0x0c500000 0 0x4000000>, + <0 0x0c440000 0 0x80000>, + <0 0x0c4c0000 0 0x20000>, + <0 0x0c42d000 0 0x4000>; + reg-names = "core", + "chnls", + "obsrvr", + "intr", + "cnfg"; + + interrupts-extended = <&pdc 1 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "periph_irq"; + + qcom,ee = <0>; + qcom,channel = <0>; + qcom,bus-id = <0>; + + interrupt-controller; + #interrupt-cells = <4>; + + #address-cells = <2>; + #size-cells = <0>; + }; + + tlmm: pinctrl@f100000 { + compatible = "qcom,sm8650-tlmm"; + reg = <0 0x0f100000 0 0x300000>; + + interrupts = ; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + + gpio-ranges = <&tlmm 0 0 211>; + + wakeup-parent = <&pdc>; + + hub_i2c0_data_clk: hub-i2c0-data-clk-state { + /* SDA, SCL */ + pins = "gpio64", "gpio65"; + function = "i2chub0_se0"; + drive-strength = <2>; + bias-pull-up; + }; + + hub_i2c1_data_clk: hub-i2c1-data-clk-state { + /* SDA, SCL */ + pins = "gpio66", "gpio67"; + function = "i2chub0_se1"; + drive-strength = <2>; + bias-pull-up; + }; + + hub_i2c2_data_clk: hub-i2c2-data-clk-state { + /* SDA, SCL */ + pins = "gpio68", "gpio69"; + function = "i2chub0_se2"; + drive-strength = <2>; + bias-pull-up; + }; + + hub_i2c3_data_clk: hub-i2c3-data-clk-state { + /* SDA, SCL */ + pins = "gpio70", "gpio71"; + function = "i2chub0_se3"; + drive-strength = <2>; + bias-pull-up; + }; + + hub_i2c4_data_clk: hub-i2c4-data-clk-state { + /* SDA, SCL */ + pins = "gpio72", "gpio73"; + function = "i2chub0_se4"; + drive-strength = <2>; + bias-pull-up; + }; + + hub_i2c5_data_clk: hub-i2c5-data-clk-state { + /* SDA, SCL */ + pins = "gpio74", "gpio75"; + function = "i2chub0_se5"; + drive-strength = <2>; + bias-pull-up; + }; + + hub_i2c6_data_clk: hub-i2c6-data-clk-state { + /* SDA, SCL */ + pins = "gpio76", "gpio77"; + function = "i2chub0_se6"; + drive-strength = <2>; + bias-pull-up; + }; + + hub_i2c7_data_clk: hub-i2c7-data-clk-state { + /* SDA, SCL */ + pins = "gpio78", "gpio79"; + function = "i2chub0_se7"; + drive-strength = <2>; + bias-pull-up; + }; + + hub_i2c8_data_clk: hub-i2c8-data-clk-state { + /* SDA, SCL */ + pins = "gpio206", "gpio207"; + function = "i2chub0_se8"; + drive-strength = <2>; + bias-pull-up; + }; + + hub_i2c9_data_clk: hub-i2c9-data-clk-state { + /* SDA, SCL */ + pins = "gpio80", "gpio81"; + function = "i2chub0_se9"; + drive-strength = <2>; + bias-pull-up; + }; + + pcie0_default_state: pcie0-default-state { + perst-pins { + pins = "gpio94"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + + clkreq-pins { + pins = "gpio95"; + function = "pcie0_clk_req_n"; + drive-strength = <2>; + bias-pull-up; + }; + + wake-pins { + pins = "gpio96"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + pcie1_default_state: pcie1-default-state { + perst-pins { + pins = "gpio97"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; + + clkreq-pins { + pins = "gpio98"; + function = "pcie1_clk_req_n"; + drive-strength = <2>; + bias-pull-up; + }; + + wake-pins { + pins = "gpio99"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + qup_i2c0_data_clk: qup-i2c0-data-clk-state { + /* SDA, SCL */ + pins = "gpio32", "gpio33"; + function = "qup1_se0"; + drive-strength = <2>; + bias-pull-up; + }; + + qup_i2c1_data_clk: qup-i2c1-data-clk-state { + /* SDA, SCL */ + pins = "gpio36", "gpio37"; + function = "qup1_se1"; + drive-strength = <2>; + bias-pull-up; + }; + + qup_i2c2_data_clk: qup-i2c2-data-clk-state { + /* SDA, SCL */ + pins = "gpio40", "gpio41"; + function = "qup1_se2"; + drive-strength = <2>; + bias-pull-up; + }; + + qup_i2c3_data_clk: qup-i2c3-data-clk-state { + /* SDA, SCL */ + pins = "gpio44", "gpio45"; + function = "qup1_se3"; + drive-strength = <2>; + bias-pull-up; + }; + + qup_i2c4_data_clk: qup-i2c4-data-clk-state { + /* SDA, SCL */ + pins = "gpio48", "gpio49"; + function = "qup1_se4"; + drive-strength = <2>; + bias-pull-up; + }; + + qup_i2c5_data_clk: qup-i2c5-data-clk-state { + /* SDA, SCL */ + pins = "gpio52", "gpio53"; + function = "qup1_se5"; + drive-strength = <2>; + bias-pull-up; + }; + + qup_i2c6_data_clk: qup-i2c6-data-clk-state { + /* SDA, SCL */ + pins = "gpio56", "gpio57"; + function = "qup1_se6"; + drive-strength = <2>; + bias-pull-up; + }; + + qup_i2c7_data_clk: qup-i2c7-data-clk-state { + /* SDA, SCL */ + pins = "gpio60", "gpio61"; + function = "qup1_se7"; + drive-strength = <2>; + bias-pull-up; + }; + + qup_i2c8_data_clk: qup-i2c8-data-clk-state { + /* SDA, SCL */ + pins = "gpio0", "gpio1"; + function = "qup2_se0"; + drive-strength = <2>; + bias-pull-up; + }; + + qup_i2c9_data_clk: qup-i2c9-data-clk-state { + /* SDA, SCL */ + pins = "gpio4", "gpio5"; + function = "qup2_se1"; + drive-strength = <2>; + bias-pull-up; + }; + + qup_i2c10_data_clk: qup-i2c10-data-clk-state { + /* SDA, SCL */ + pins = "gpio8", "gpio9"; + function = "qup2_se2"; + drive-strength = <2>; + bias-pull-up; + }; + + qup_i2c11_data_clk: qup-i2c11-data-clk-state { + /* SDA, SCL */ + pins = "gpio12", "gpio13"; + function = "qup2_se3"; + drive-strength = <2>; + bias-pull-up; + }; + + qup_i2c12_data_clk: qup-i2c12-data-clk-state { + /* SDA, SCL */ + pins = "gpio16", "gpio17"; + function = "qup2_se4"; + drive-strength = <2>; + bias-pull-up; + }; + + qup_i2c13_data_clk: qup-i2c13-data-clk-state { + /* SDA, SCL */ + pins = "gpio20", "gpio21"; + function = "qup2_se5"; + drive-strength = <2>; + bias-pull-up; + }; + + qup_i2c14_data_clk: qup-i2c14-data-clk-state { + /* SDA, SCL */ + pins = "gpio24", "gpio25"; + function = "qup2_se6"; + drive-strength = <2>; + bias-pull-up; + }; + + qup_spi0_cs: qup-spi0-cs-state { + pins = "gpio35"; + function = "qup1_se0"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi0_data_clk: qup-spi0-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio32", "gpio33", "gpio34"; + function = "qup1_se0"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi1_cs: qup-spi1-cs-state { + pins = "gpio39"; + function = "qup1_se1"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi1_data_clk: qup-spi1-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio36", "gpio37", "gpio38"; + function = "qup1_se1"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi2_cs: qup-spi2-cs-state { + pins = "gpio43"; + function = "qup1_se2"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi2_data_clk: qup-spi2-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio40", "gpio41", "gpio42"; + function = "qup1_se2"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi3_cs: qup-spi3-cs-state { + pins = "gpio47"; + function = "qup1_se3"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi3_data_clk: qup-spi3-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio44", "gpio45", "gpio46"; + function = "qup1_se3"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi4_cs: qup-spi4-cs-state { + pins = "gpio51"; + function = "qup1_se4"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi4_data_clk: qup-spi4-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio48", "gpio49", "gpio50"; + function = "qup1_se4"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi5_cs: qup-spi5-cs-state { + pins = "gpio55"; + function = "qup1_se5"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi5_data_clk: qup-spi5-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio52", "gpio53", "gpio54"; + function = "qup1_se5"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi6_cs: qup-spi6-cs-state { + pins = "gpio59"; + function = "qup1_se6"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi6_data_clk: qup-spi6-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio56", "gpio57", "gpio58"; + function = "qup1_se6"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi7_cs: qup-spi7-cs-state { + pins = "gpio63"; + function = "qup1_se7"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi7_data_clk: qup-spi7-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio60", "gpio61", "gpio62"; + function = "qup1_se7"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi8_cs: qup-spi8-cs-state { + pins = "gpio3"; + function = "qup2_se0"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi8_data_clk: qup-spi8-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio0", "gpio1", "gpio2"; + function = "qup2_se0"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi9_cs: qup-spi9-cs-state { + pins = "gpio7"; + function = "qup2_se1"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi9_data_clk: qup-spi9-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio4", "gpio5", "gpio6"; + function = "qup2_se1"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi10_cs: qup-spi10-cs-state { + pins = "gpio11"; + function = "qup2_se2"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi10_data_clk: qup-spi10-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio8", "gpio9", "gpio10"; + function = "qup2_se2"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi11_cs: qup-spi11-cs-state { + pins = "gpio15"; + function = "qup2_se3"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi11_data_clk: qup-spi11-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio12", "gpio13", "gpio14"; + function = "qup2_se3"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi12_cs: qup-spi12-cs-state { + pins = "gpio19"; + function = "qup2_se4"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi12_data_clk: qup-spi12-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio16", "gpio17", "gpio18"; + function = "qup2_se4"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi13_cs: qup-spi13-cs-state { + pins = "gpio23"; + function = "qup2_se5"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi13_data_clk: qup-spi13-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio20", "gpio21", "gpio22"; + function = "qup2_se5"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi14_cs: qup-spi14-cs-state { + pins = "gpio27"; + function = "qup2_se6"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi14_data_clk: qup-spi14-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio24", "gpio25", "gpio26"; + function = "qup2_se6"; + drive-strength = <6>; + bias-disable; + }; + + qup_uart14_default: qup-uart14-default-state { + /* TX, RX */ + pins = "gpio26", "gpio27"; + function = "qup2_se6"; + drive-strength = <2>; + bias-pull-up; + }; + + qup_uart14_cts_rts: qup-uart14-cts-rts-state { + /* CTS, RTS */ + pins = "gpio24", "gpio25"; + function = "qup2_se6"; + drive-strength = <2>; + bias-pull-down; + }; + + qup_uart15_default: qup-uart15-default-state { + /* TX, RX */ + pins = "gpio30", "gpio31"; + function = "qup2_se7"; + drive-strength = <2>; + bias-disable; + }; + + sdc2_sleep: sdc2-sleep-state { + clk-pins { + pins = "sdc2_clk"; + drive-strength = <2>; + bias-disable; + }; + + cmd-pins { + pins = "sdc2_cmd"; + drive-strength = <2>; + bias-pull-up; + }; + + data-pins { + pins = "sdc2_data"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + sdc2_default: sdc2-default-state { + clk-pins { + pins = "sdc2_clk"; + drive-strength = <16>; + bias-disable; + }; + + cmd-pins { + pins = "sdc2_cmd"; + drive-strength = <10>; + bias-pull-up; + }; + + data-pins { + pins = "sdc2_data"; + drive-strength = <10>; + bias-pull-up; + }; + }; + }; + + apps_smmu: iommu@15000000 { + compatible = "qcom,sm8650-smmu-500", "qcom,smmu-500", "arm,mmu-500"; + reg = <0 0x15000000 0 0x100000>; + + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + + #iommu-cells = <2>; + #global-interrupts = <1>; + + dma-coherent; + }; + + intc: interrupt-controller@17100000 { + compatible = "arm,gic-v3"; + reg = <0 0x17100000 0 0x10000>, /* GICD */ + <0 0x17180000 0 0x200000>; /* GICR * 8 */ + + interrupts = ; + + #interrupt-cells = <3>; + interrupt-controller; + + #redistributor-regions = <1>; + redistributor-stride = <0 0x40000>; + + #address-cells = <2>; + #size-cells = <2>; + ranges; + + gic_its: msi-controller@17140000 { + compatible = "arm,gic-v3-its"; + reg = <0 0x17140000 0 0x20000>; + + msi-controller; + #msi-cells = <1>; + }; + }; + + timer@17420000 { + compatible = "arm,armv7-timer-mem"; + reg = <0 0x17420000 0 0x1000>; + + ranges = <0 0 0 0x20000000>; + #address-cells = <1>; + #size-cells = <1>; + + frame@17421000 { + reg = <0x17421000 0x1000>, + <0x17422000 0x1000>; + + interrupts = , + ; + + frame-number = <0>; + }; + + frame@17423000 { + reg = <0x17423000 0x1000>; + + interrupts = ; + + frame-number = <1>; + + status = "disabled"; + }; + + frame@17425000 { + reg = <0x17425000 0x1000>; + + interrupts = ; + + frame-number = <2>; + + status = "disabled"; + }; + + frame@17427000 { + reg = <0x17427000 0x1000>; + + interrupts = ; + + frame-number = <3>; + + status = "disabled"; + }; + + frame@17429000 { + reg = <0x17429000 0x1000>; + + interrupts = ; + + frame-number = <4>; + + status = "disabled"; + }; + + frame@1742b000 { + reg = <0x1742b000 0x1000>; + + interrupts = ; + + frame-number = <5>; + + status = "disabled"; + }; + + frame@1742d000 { + reg = <0x1742d000 0x1000>; + + interrupts = ; + + frame-number = <6>; + + status = "disabled"; + }; + }; + + apps_rsc: rsc@17a00000 { + compatible = "qcom,rpmh-rsc"; + reg = <0 0x17a00000 0 0x10000>, + <0 0x17a10000 0 0x10000>, + <0 0x17a20000 0 0x10000>, + <0 0x17a30000 0 0x10000>; + reg-names = "drv-0", + "drv-1", + "drv-2"; + + interrupts = , + , + ; + + power-domains = <&CLUSTER_PD>; + + qcom,tcs-offset = <0xd00>; + qcom,drv-id = <2>; + qcom,tcs-config = , , + , ; + + label = "apps_rsc"; + + apps_bcm_voter: bcm-voter { + compatible = "qcom,bcm-voter"; + }; + + rpmhcc: clock-controller { + compatible = "qcom,sm8650-rpmh-clk"; + + clocks = <&xo_board>; + clock-names = "xo"; + + #clock-cells = <1>; + }; + + rpmhpd: power-controller { + compatible = "qcom,sm8650-rpmhpd"; + + operating-points-v2 = <&rpmhpd_opp_table>; + + #power-domain-cells = <1>; + + rpmhpd_opp_table: opp-table { + compatible = "operating-points-v2"; + + rpmhpd_opp_ret: opp-16 { + opp-level = ; + }; + + rpmhpd_opp_min_svs: opp-48 { + opp-level = ; + }; + + rpmhpd_opp_low_svs_d2: opp-52 { + opp-level = ; + }; + + rpmhpd_opp_low_svs_d1: opp-56 { + opp-level = ; + }; + + rpmhpd_opp_low_svs_d0: opp-60 { + opp-level = ; + }; + + rpmhpd_opp_low_svs: opp-64 { + opp-level = ; + }; + + rpmhpd_opp_low_svs_l1: opp-80 { + opp-level = ; + }; + + rpmhpd_opp_svs: opp-128 { + opp-level = ; + }; + + rpmhpd_opp_svs_l0: opp-144 { + opp-level = ; + }; + + rpmhpd_opp_svs_l1: opp-192 { + opp-level = ; + }; + + rpmhpd_opp_nom: opp-256 { + opp-level = ; + }; + + rpmhpd_opp_nom_l1: opp-320 { + opp-level = ; + }; + + rpmhpd_opp_nom_l2: opp-336 { + opp-level = ; + }; + + rpmhpd_opp_turbo: opp-384 { + opp-level = ; + }; + + rpmhpd_opp_turbo_l1: opp-416 { + opp-level = ; + }; + }; + }; + }; + + cpufreq_hw: cpufreq@17d91000 { + compatible = "qcom,sm8650-cpufreq-epss", "qcom,cpufreq-epss"; + reg = <0 0x17d91000 0 0x1000>, + <0 0x17d92000 0 0x1000>, + <0 0x17d93000 0 0x1000>, + <0 0x17d94000 0 0x1000>; + reg-names = "freq-domain0", + "freq-domain1", + "freq-domain2", + "freq-domain3"; + + interrupts = , + , + , + ; + interrupt-names = "dcvsh-irq-0", + "dcvsh-irq-1", + "dcvsh-irq-2", + "dcvsh-irq-3"; + + clocks = <&bi_tcxo_div2>, <&gcc GCC_GPLL0>; + clock-names = "xo", "alternate"; + + #freq-domain-cells = <1>; + #clock-cells = <1>; + }; + + pmu@24091000 { + compatible = "qcom,sm8650-llcc-bwmon", "qcom,sc7280-llcc-bwmon"; + reg = <0 0x24091000 0 0x1000>; + + interrupts = ; + + interconnects = <&mc_virt MASTER_LLCC QCOM_ICC_TAG_ACTIVE_ONLY + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ACTIVE_ONLY>; + + operating-points-v2 = <&llcc_bwmon_opp_table>; + + llcc_bwmon_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-0 { + opp-peak-kBps = <2086000>; + }; + + opp-1 { + opp-peak-kBps = <2929000>; + }; + + opp-2 { + opp-peak-kBps = <5931000>; + }; + + opp-3 { + opp-peak-kBps = <6515000>; + }; + + opp-4 { + opp-peak-kBps = <7980000>; + }; + + opp-5 { + opp-peak-kBps = <10437000>; + }; + + opp-6 { + opp-peak-kBps = <12157000>; + }; + + opp-7 { + opp-peak-kBps = <14060000>; + }; + + opp-8 { + opp-peak-kBps = <16113000>; + }; + }; + }; + + pmu@240b7400 { + compatible = "qcom,sm8650-cpu-bwmon", "qcom,sdm845-bwmon"; + reg = <0 0x240b7400 0 0x600>; + + interrupts = ; + + interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &gem_noc SLAVE_LLCC QCOM_ICC_TAG_ACTIVE_ONLY>; + + operating-points-v2 = <&cpu_bwmon_opp_table>; + + cpu_bwmon_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-0 { + opp-peak-kBps = <4577000>; + }; + + opp-1 { + opp-peak-kBps = <7110000>; + }; + + opp-2 { + opp-peak-kBps = <9155000>; + }; + + opp-3 { + opp-peak-kBps = <12298000>; + }; + + opp-4 { + opp-peak-kBps = <14236000>; + }; + + opp-5 { + opp-peak-kBps = <16265000>; + }; + }; + }; + + gem_noc: interconnect@24100000 { + compatible = "qcom,sm8650-gem-noc"; + reg = <0 0x24100000 0 0xc5080>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + system-cache-controller@25000000 { + compatible = "qcom,sm8650-llcc"; + reg = <0 0x25000000 0 0x200000>, + <0 0x25400000 0 0x200000>, + <0 0x25200000 0 0x200000>, + <0 0x25600000 0 0x200000>, + <0 0x25800000 0 0x200000>; + reg-names = "llcc0_base", + "llcc1_base", + "llcc2_base", + "llcc3_base", + "llcc_broadcast_base"; + + interrupts = ; + }; + + remoteproc_adsp: remoteproc@30000000 { + compatible = "qcom,sm8650-adsp-pas"; + reg = <0 0x30000000 0 0x100>; + + interrupts-extended = <&pdc 6 IRQ_TYPE_EDGE_RISING>, + <&smp2p_adsp_in 0 IRQ_TYPE_EDGE_RISING>, + <&smp2p_adsp_in 1 IRQ_TYPE_EDGE_RISING>, + <&smp2p_adsp_in 2 IRQ_TYPE_EDGE_RISING>, + <&smp2p_adsp_in 3 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog", + "fatal", + "ready", + "handover", + "stop-ack"; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "xo"; + + interconnects = <&lpass_lpicx_noc MASTER_LPASS_PROC QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + + power-domains = <&rpmhpd RPMHPD_LCX>, + <&rpmhpd RPMHPD_LMX>; + power-domain-names = "lcx", + "lmx"; + + memory-region = <&adspslpi_mem>, <&q6_adsp_dtb_mem>; + + qcom,qmp = <&aoss_qmp>; + + qcom,smem-states = <&smp2p_adsp_out 0>; + qcom,smem-state-names = "stop"; + + status = "disabled"; + + remoteproc_adsp_glink: glink-edge { + interrupts-extended = <&ipcc IPCC_CLIENT_LPASS + IPCC_MPROC_SIGNAL_GLINK_QMP + IRQ_TYPE_EDGE_RISING>; + + mboxes = <&ipcc IPCC_CLIENT_LPASS + IPCC_MPROC_SIGNAL_GLINK_QMP>; + + qcom,remote-pid = <2>; + + label = "lpass"; + + fastrpc { + compatible = "qcom,fastrpc"; + + qcom,glink-channels = "fastrpcglink-apps-dsp"; + + label = "adsp"; + + #address-cells = <1>; + #size-cells = <0>; + + compute-cb@3 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <3>; + + iommus = <&apps_smmu 0x1003 0x80>, + <&apps_smmu 0x1043 0x20>; + }; + + compute-cb@4 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <4>; + + iommus = <&apps_smmu 0x1004 0x80>, + <&apps_smmu 0x1044 0x20>; + }; + + compute-cb@5 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <5>; + + iommus = <&apps_smmu 0x1005 0x80>, + <&apps_smmu 0x1045 0x20>; + }; + + compute-cb@6 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <6>; + + iommus = <&apps_smmu 0x1006 0x80>, + <&apps_smmu 0x1046 0x20>; + }; + + compute-cb@7 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <7>; + + iommus = <&apps_smmu 0x1007 0x40>, + <&apps_smmu 0x1067 0x0>, + <&apps_smmu 0x1087 0x0>; + }; + }; + + gpr { + compatible = "qcom,gpr"; + qcom,glink-channels = "adsp_apps"; + qcom,domain = ; + qcom,intents = <512 20>; + #address-cells = <1>; + #size-cells = <0>; + + q6apm: service@1 { + compatible = "qcom,q6apm"; + reg = ; + #sound-dai-cells = <0>; + qcom,protection-domain = "avs/audio", + "msm/adsp/audio_pd"; + + q6apmbedai: bedais { + compatible = "qcom,q6apm-lpass-dais"; + #sound-dai-cells = <1>; + }; + + q6apmdai: dais { + compatible = "qcom,q6apm-dais"; + iommus = <&apps_smmu 0x1001 0x80>, + <&apps_smmu 0x1061 0x0>; + }; + }; + + q6prm: service@2 { + compatible = "qcom,q6prm"; + reg = ; + qcom,protection-domain = "avs/audio", + "msm/adsp/audio_pd"; + + q6prmcc: clock-controller { + compatible = "qcom,q6prm-lpass-clocks"; + #clock-cells = <2>; + }; + }; + }; + }; + }; + + nsp_noc: interconnect@320c0000 { + compatible = "qcom,sm8650-nsp-noc"; + reg = <0 0x320c0000 0 0xf080>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + remoteproc_cdsp: remoteproc@32300000 { + compatible = "qcom,sm8650-cdsp-pas"; + reg = <0 0x32300000 0 0x1400000>; + + interrupts-extended = <&intc GIC_SPI 578 IRQ_TYPE_EDGE_RISING>, + <&smp2p_cdsp_in 0 IRQ_TYPE_EDGE_RISING>, + <&smp2p_cdsp_in 1 IRQ_TYPE_EDGE_RISING>, + <&smp2p_cdsp_in 2 IRQ_TYPE_EDGE_RISING>, + <&smp2p_cdsp_in 3 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog", + "fatal", + "ready", + "handover", + "stop-ack"; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-names = "xo"; + + interconnects = <&nsp_noc MASTER_CDSP_PROC QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + + power-domains = <&rpmhpd RPMHPD_CX>, + <&rpmhpd RPMHPD_MXC>, + <&rpmhpd RPMHPD_NSP>; + power-domain-names = "cx", + "mxc", + "nsp"; + + memory-region = <&cdsp_mem>, <&q6_cdsp_dtb_mem>, <&global_sync_mem>; + + qcom,qmp = <&aoss_qmp>; + + qcom,smem-states = <&smp2p_cdsp_out 0>; + qcom,smem-state-names = "stop"; + + status = "disabled"; + + glink-edge { + interrupts-extended = <&ipcc IPCC_CLIENT_CDSP + IPCC_MPROC_SIGNAL_GLINK_QMP + IRQ_TYPE_EDGE_RISING>; + + mboxes = <&ipcc IPCC_CLIENT_CDSP + IPCC_MPROC_SIGNAL_GLINK_QMP>; + + qcom,remote-pid = <5>; + + label = "cdsp"; + + fastrpc { + compatible = "qcom,fastrpc"; + + qcom,glink-channels = "fastrpcglink-apps-dsp"; + + label = "cdsp"; + + #address-cells = <1>; + #size-cells = <0>; + + compute-cb@1 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <1>; + + iommus = <&apps_smmu 0x1961 0x0>, + <&apps_smmu 0x0c01 0x20>, + <&apps_smmu 0x19c1 0x0>; + }; + + compute-cb@2 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <2>; + + iommus = <&apps_smmu 0x1962 0x0>, + <&apps_smmu 0x0c02 0x20>, + <&apps_smmu 0x19c2 0x0>; + }; + + compute-cb@3 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <3>; + + iommus = <&apps_smmu 0x1963 0x0>, + <&apps_smmu 0x0c03 0x20>, + <&apps_smmu 0x19c3 0x0>; + }; + + compute-cb@4 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <4>; + + iommus = <&apps_smmu 0x1964 0x0>, + <&apps_smmu 0x0c04 0x20>, + <&apps_smmu 0x19c4 0x0>; + }; + + compute-cb@5 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <5>; + + iommus = <&apps_smmu 0x1965 0x0>, + <&apps_smmu 0x0c05 0x20>, + <&apps_smmu 0x19c5 0x0>; + }; + + compute-cb@6 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <6>; + + iommus = <&apps_smmu 0x1966 0x0>, + <&apps_smmu 0x0c06 0x20>, + <&apps_smmu 0x19c6 0x0>; + }; + + compute-cb@7 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <7>; + + iommus = <&apps_smmu 0x1967 0x0>, + <&apps_smmu 0x0c07 0x20>, + <&apps_smmu 0x19c7 0x0>; + }; + + compute-cb@8 { + compatible = "qcom,fastrpc-compute-cb"; + reg = <8>; + + iommus = <&apps_smmu 0x1968 0x0>, + <&apps_smmu 0x0c08 0x20>, + <&apps_smmu 0x19c8 0x0>; + }; + }; + }; + }; + }; + + thermal-zones { + aoss0-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 0>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + aoss0-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + cpuss0-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 1>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + cpuss0-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + cpuss1-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 2>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + cpuss1-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + cpuss2-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 3>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + cpuss2-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + cpuss3-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 4>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + cpuss3-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + cpu2-top-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 5>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu2-critical { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu2-bottom-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 6>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu2-critical { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu3-top-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 7>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu3-critical { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu3-bottom-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 8>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu3-critical { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu4-top-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 9>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu4-critical { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu4-bottom-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 10>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu4-critical { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu5-top-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 11>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu5-critical { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu5-bottom-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 12>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu5-critical { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu6-top-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 13>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu6-critical { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu6-bottom-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 14>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu6-critical { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + aoss1-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 0>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + aoss1-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + cpu7-top-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 1>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu7-critical { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu7-middle-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 2>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu7-critical { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu7-bottom-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 3>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu7-critical { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu0-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 4>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu0-critical { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + cpu1-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 5>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + trip-point1 { + temperature = <95000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu1-critical { + temperature = <110000>; + hysteresis = <1000>; + type = "critical"; + }; + }; + }; + + nsphvx0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens2 6>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + nsphvx1-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + nsphvx1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens2 7>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + nsphvx1-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + nsphmx0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens2 8>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + nsphmx0-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + nsphmx1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens2 9>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + nsphmx1-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + nsphmx2-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens2 10>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + nsphmx2-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + nsphmx3-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens2 11>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + nsphmx3-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + video-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens1 12>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + video-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + ddr-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens1 13>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + ddr-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + camera0-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 14>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + camera0-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + camera1-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 15>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + camera1-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + aoss2-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens2 0>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + aoss2-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + gpuss0-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens2 1>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + gpuss0-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + gpuss1-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens2 2>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + gpuss1-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + gpuss2-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens2 3>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + gpuss2-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + gpuss3-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens2 4>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + gpuss3-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + gpuss4-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens2 5>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + gpuss4-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + gpuss5-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens2 6>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + gpuss5-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + gpuss6-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens2 7>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + gpuss6-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + gpuss7-thermal { + polling-delay-passive = <10>; + polling-delay = <0>; + thermal-sensors = <&tsens2 8>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + gpuss7-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + modem0-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens2 9>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + modem0-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + modem1-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens2 10>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + modem1-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + modem2-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens2 11>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + modem2-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + + modem3-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens2 12>; + + trips { + trip-point0 { + temperature = <90000>; + hysteresis = <2000>; + type = "hot"; + }; + + modem3-critical { + temperature = <110000>; + hysteresis = <0>; + type = "critical"; + }; + }; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + + interrupts = , + , + , + ; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/x1e80100-crd.dts b/arch/arm64/boot/dts/qcom/x1e80100-crd.dts new file mode 100644 index 00000000000000..7532d8eca2de33 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/x1e80100-crd.dts @@ -0,0 +1,424 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +/dts-v1/; + +#include +#include + +#include "x1e80100.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. X1E80100 CRD"; + compatible = "qcom,x1e80100-crd", "qcom,x1e80100"; + + aliases { + serial0 = &uart21; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + vph_pwr: vph-pwr-regulator { + compatible = "regulator-fixed"; + + regulator-name = "vph_pwr"; + regulator-min-microvolt = <3700000>; + regulator-max-microvolt = <3700000>; + + regulator-always-on; + regulator-boot-on; + }; + + vreg_edp_3p3: regulator-edp-3p3 { + compatible = "regulator-fixed"; + + regulator-name = "VREG_EDP_3P3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + gpio = <&tlmm 70 GPIO_ACTIVE_HIGH>; + enable-active-high; + + pinctrl-0 = <&edp_reg_en>; + pinctrl-names = "default"; + + regulator-always-on; + regulator-boot-on; + }; +}; + +&apps_rsc { + regulators-0 { + compatible = "qcom,pm8550-rpmh-regulators"; + qcom,pmic-id = "b"; + + vdd-bob1-supply = <&vph_pwr>; + vdd-bob2-supply = <&vph_pwr>; + vdd-l1-l4-l10-supply = <&vreg_s4c_1p8>; + vdd-l2-l13-l14-supply = <&vreg_bob1>; + vdd-l5-l16-supply = <&vreg_bob1>; + vdd-l6-l7-supply = <&vreg_bob2>; + vdd-l8-l9-supply = <&vreg_bob1>; + vdd-l12-supply = <&vreg_s5j_1p2>; + vdd-l15-supply = <&vreg_s4c_1p8>; + vdd-l17-supply = <&vreg_bob2>; + + vreg_bob1: bob1 { + regulator-name = "vreg_bob1"; + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3960000>; + regulator-initial-mode = ; + }; + + vreg_bob2: bob2 { + regulator-name = "vreg_bob2"; + regulator-min-microvolt = <2504000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + }; + + vreg_l1b_1p8: ldo1 { + regulator-name = "vreg_l1b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l2b_3p0: ldo2 { + regulator-name = "vreg_l2b_3p0"; + regulator-min-microvolt = <3072000>; + regulator-max-microvolt = <3100000>; + regulator-initial-mode = ; + }; + + vreg_l4b_1p8: ldo4 { + regulator-name = "vreg_l4b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l5b_3p0: ldo5 { + regulator-name = "vreg_l5b_3p0"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-initial-mode = ; + }; + + vreg_l6b_1p8: ldo6 { + regulator-name = "vreg_l6b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = ; + }; + + vreg_l7b_2p8: ldo7 { + regulator-name = "vreg_l7b_2p8"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-initial-mode = ; + }; + + vreg_l8b_3p0: ldo8 { + regulator-name = "vreg_l8b_3p0"; + regulator-min-microvolt = <3072000>; + regulator-max-microvolt = <3072000>; + regulator-initial-mode = ; + }; + + vreg_l9b_2p9: ldo9 { + regulator-name = "vreg_l9b_2p9"; + regulator-min-microvolt = <2960000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = ; + }; + + vreg_l10b_1p8: ldo10 { + regulator-name = "vreg_l10b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l12b_1p2: ldo12 { + regulator-name = "vreg_l12b_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l13b_3p0: ldo13 { + regulator-name = "vreg_l13b_3p0"; + regulator-min-microvolt = <3072000>; + regulator-max-microvolt = <3100000>; + regulator-initial-mode = ; + }; + + vreg_l14b_3p0: ldo14 { + regulator-name = "vreg_l14b_3p0"; + regulator-min-microvolt = <3072000>; + regulator-max-microvolt = <3072000>; + regulator-initial-mode = ; + }; + + vreg_l15b_1p8: ldo15 { + regulator-name = "vreg_l15b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l16b_2p9: ldo16 { + regulator-name = "vreg_l16b_2p9"; + regulator-min-microvolt = <2912000>; + regulator-max-microvolt = <2912000>; + regulator-initial-mode = ; + }; + + vreg_l17b_2p5: ldo17 { + regulator-name = "vreg_l17b_2p5"; + regulator-min-microvolt = <2504000>; + regulator-max-microvolt = <2504000>; + regulator-initial-mode = ; + }; + }; + + regulators-1 { + compatible = "qcom,pm8550ve-rpmh-regulators"; + qcom,pmic-id = "c"; + + vdd-l1-supply = <&vreg_s5j_1p2>; + vdd-l2-supply = <&vreg_s1f_0p7>; + vdd-l3-supply = <&vreg_s1f_0p7>; + vdd-s4-supply = <&vph_pwr>; + + vreg_s4c_1p8: smps4 { + regulator-name = "vreg_s4c_1p8"; + regulator-min-microvolt = <1856000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l1c_1p2: ldo1 { + regulator-name = "vreg_l1c_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l2c_0p8: ldo2 { + regulator-name = "vreg_l2c_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + + vreg_l3c_0p8: ldo3 { + regulator-name = "vreg_l3c_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + }; + + regulators-2 { + compatible = "qcom,pmc8380-rpmh-regulators"; + qcom,pmic-id = "d"; + + vdd-l1-supply = <&vreg_s1f_0p7>; + vdd-l2-supply = <&vreg_s1f_0p7>; + vdd-l3-supply = <&vreg_s4c_1p8>; + vdd-s1-supply = <&vph_pwr>; + + vreg_l1d_0p8: ldo1 { + regulator-name = "vreg_l1d_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + + vreg_l2d_0p9: ldo2 { + regulator-name = "vreg_l2d_0p9"; + regulator-min-microvolt = <912000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + + vreg_l3d_1p8: ldo3 { + regulator-name = "vreg_l3d_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + }; + + regulators-3 { + compatible = "qcom,pmc8380-rpmh-regulators"; + qcom,pmic-id = "e"; + + vdd-l2-supply = <&vreg_s1f_0p7>; + vdd-l3-supply = <&vreg_s5j_1p2>; + + vreg_l2e_0p8: ldo2 { + regulator-name = "vreg_l2e_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + + vreg_l3e_1p2: ldo3 { + regulator-name = "vreg_l3e_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + }; + + regulators-4 { + compatible = "qcom,pmc8380-rpmh-regulators"; + qcom,pmic-id = "f"; + + vdd-l1-supply = <&vreg_s5j_1p2>; + vdd-l2-supply = <&vreg_s5j_1p2>; + vdd-l3-supply = <&vreg_s5j_1p2>; + vdd-s1-supply = <&vph_pwr>; + + vreg_s1f_0p7: smps1 { + regulator-name = "vreg_s1f_0p7"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1100000>; + regulator-initial-mode = ; + }; + + vreg_l1f_1p0: ldo1 { + regulator-name = "vreg_l1f_1p0"; + regulator-min-microvolt = <1024000>; + regulator-max-microvolt = <1024000>; + regulator-initial-mode = ; + }; + + vreg_l2f_1p0: ldo2 { + regulator-name = "vreg_l2f_1p0"; + regulator-min-microvolt = <1024000>; + regulator-max-microvolt = <1024000>; + regulator-initial-mode = ; + }; + + vreg_l3f_1p0: ldo3 { + regulator-name = "vreg_l3f_1p0"; + regulator-min-microvolt = <1024000>; + regulator-max-microvolt = <1024000>; + regulator-initial-mode = ; + }; + }; + + regulators-6 { + compatible = "qcom,pm8550ve-rpmh-regulators"; + qcom,pmic-id = "i"; + + vdd-l1-supply = <&vreg_s4c_1p8>; + vdd-l2-supply = <&vreg_s5j_1p2>; + vdd-l3-supply = <&vreg_s1f_0p7>; + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vph_pwr>; + + vreg_s1i_0p9: smps1 { + regulator-name = "vreg_s1i_0p9"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + + vreg_s2i_1p0: smps2 { + regulator-name = "vreg_s2i_1p0"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1100000>; + regulator-initial-mode = ; + }; + + vreg_l1i_1p8: ldo1 { + regulator-name = "vreg_l1i_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l2i_1p2: ldo2 { + regulator-name = "vreg_l2i_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l3i_0p8: ldo3 { + regulator-name = "vreg_l3i_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + }; + + regulators-7 { + compatible = "qcom,pm8550ve-rpmh-regulators"; + qcom,pmic-id = "j"; + + vdd-l1-supply = <&vreg_s1f_0p7>; + vdd-l2-supply = <&vreg_s5j_1p2>; + vdd-l3-supply = <&vreg_s1f_0p7>; + vdd-s5-supply = <&vph_pwr>; + + vreg_s5j_1p2: smps5 { + regulator-name = "vreg_s5j_1p2"; + regulator-min-microvolt = <1256000>; + regulator-max-microvolt = <1304000>; + regulator-initial-mode = ; + }; + + vreg_l1j_0p8: ldo1 { + regulator-name = "vreg_l1j_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + + vreg_l2j_1p2: ldo2 { + regulator-name = "vreg_l2j_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l3j_0p8: ldo3 { + regulator-name = "vreg_l3j_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + }; +}; + +&qupv3_2 { + status = "okay"; +}; + +&tlmm { + gpio-reserved-ranges = <34 2>, /* Unused */ + <44 4>, /* SPI (TPM) */ + <238 1>; /* UFS Reset */ + + edp_reg_en: edp-reg-en-state { + pins = "gpio70"; + function = "gpio"; + drive-strength = <16>; + bias-disable; + }; +}; + +&uart21 { + compatible = "qcom,geni-debug-uart"; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/x1e80100-qcp.dts b/arch/arm64/boot/dts/qcom/x1e80100-qcp.dts new file mode 100644 index 00000000000000..a37ad9475c90d8 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/x1e80100-qcp.dts @@ -0,0 +1,399 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +/dts-v1/; + +#include + +#include "x1e80100.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. X1E80100 QCP"; + compatible = "qcom,x1e80100-qcp", "qcom,x1e80100"; + + aliases { + serial0 = &uart21; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + vph_pwr: vph-pwr-regulator { + compatible = "regulator-fixed"; + + regulator-name = "vph_pwr"; + regulator-min-microvolt = <3700000>; + regulator-max-microvolt = <3700000>; + + regulator-always-on; + regulator-boot-on; + }; +}; + +&apps_rsc { + regulators-0 { + compatible = "qcom,pm8550-rpmh-regulators"; + qcom,pmic-id = "b"; + + vdd-bob1-supply = <&vph_pwr>; + vdd-bob2-supply = <&vph_pwr>; + vdd-l1-l4-l10-supply = <&vreg_s4c_1p8>; + vdd-l2-l13-l14-supply = <&vreg_bob1>; + vdd-l5-l16-supply = <&vreg_bob1>; + vdd-l6-l7-supply = <&vreg_bob2>; + vdd-l8-l9-supply = <&vreg_bob1>; + vdd-l12-supply = <&vreg_s5j_1p2>; + vdd-l15-supply = <&vreg_s4c_1p8>; + vdd-l17-supply = <&vreg_bob2>; + + vreg_bob1: bob1 { + regulator-name = "vreg_bob1"; + regulator-min-microvolt = <3008000>; + regulator-max-microvolt = <3960000>; + regulator-initial-mode = ; + }; + + vreg_bob2: bob2 { + regulator-name = "vreg_bob2"; + regulator-min-microvolt = <2504000>; + regulator-max-microvolt = <3008000>; + regulator-initial-mode = ; + }; + + vreg_l1b_1p8: ldo1 { + regulator-name = "vreg_l1b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l2b_3p0: ldo2 { + regulator-name = "vreg_l2b_3p0"; + regulator-min-microvolt = <3072000>; + regulator-max-microvolt = <3100000>; + regulator-initial-mode = ; + }; + + vreg_l4b_1p8: ldo4 { + regulator-name = "vreg_l4b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l5b_3p0: ldo5 { + regulator-name = "vreg_l5b_3p0"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + regulator-initial-mode = ; + }; + + vreg_l6b_1p8: ldo6 { + regulator-name = "vreg_l6b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = ; + }; + + vreg_l7b_2p8: ldo7 { + regulator-name = "vreg_l7b_2p8"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-initial-mode = ; + }; + + vreg_l8b_3p0: ldo8 { + regulator-name = "vreg_l8b_3p0"; + regulator-min-microvolt = <3072000>; + regulator-max-microvolt = <3072000>; + regulator-initial-mode = ; + }; + + vreg_l9b_2p9: ldo9 { + regulator-name = "vreg_l9b_2p9"; + regulator-min-microvolt = <2960000>; + regulator-max-microvolt = <2960000>; + regulator-initial-mode = ; + }; + + vreg_l10b_1p8: ldo10 { + regulator-name = "vreg_l10b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l12b_1p2: ldo12 { + regulator-name = "vreg_l12b_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l13b_3p0: ldo13 { + regulator-name = "vreg_l13b_3p0"; + regulator-min-microvolt = <3072000>; + regulator-max-microvolt = <3100000>; + regulator-initial-mode = ; + }; + + vreg_l14b_3p0: ldo14 { + regulator-name = "vreg_l14b_3p0"; + regulator-min-microvolt = <3072000>; + regulator-max-microvolt = <3072000>; + regulator-initial-mode = ; + }; + + vreg_l15b_1p8: ldo15 { + regulator-name = "vreg_l15b_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l16b_2p9: ldo16 { + regulator-name = "vreg_l16b_2p9"; + regulator-min-microvolt = <2912000>; + regulator-max-microvolt = <2912000>; + regulator-initial-mode = ; + }; + + vreg_l17b_2p5: ldo17 { + regulator-name = "vreg_l17b_2p5"; + regulator-min-microvolt = <2504000>; + regulator-max-microvolt = <2504000>; + regulator-initial-mode = ; + }; + }; + + regulators-1 { + compatible = "qcom,pm8550ve-rpmh-regulators"; + qcom,pmic-id = "c"; + + vdd-l1-supply = <&vreg_s5j_1p2>; + vdd-l2-supply = <&vreg_s1f_0p7>; + vdd-l3-supply = <&vreg_s1f_0p7>; + vdd-s4-supply = <&vph_pwr>; + + vreg_s4c_1p8: smps4 { + regulator-name = "vreg_s4c_1p8"; + regulator-min-microvolt = <1856000>; + regulator-max-microvolt = <2000000>; + regulator-initial-mode = ; + }; + + vreg_l1c_1p2: ldo1 { + regulator-name = "vreg_l1c_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l2c_0p8: ldo2 { + regulator-name = "vreg_l2c_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + + vreg_l3c_0p8: ldo3 { + regulator-name = "vreg_l3c_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + }; + + regulators-2 { + compatible = "qcom,pmc8380-rpmh-regulators"; + qcom,pmic-id = "d"; + + vdd-l1-supply = <&vreg_s1f_0p7>; + vdd-l2-supply = <&vreg_s1f_0p7>; + vdd-l3-supply = <&vreg_s4c_1p8>; + vdd-s1-supply = <&vph_pwr>; + + vreg_l1d_0p8: ldo1 { + regulator-name = "vreg_l1d_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + + vreg_l2d_0p9: ldo2 { + regulator-name = "vreg_l2d_0p9"; + regulator-min-microvolt = <912000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + + vreg_l3d_1p8: ldo3 { + regulator-name = "vreg_l3d_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + }; + + regulators-3 { + compatible = "qcom,pmc8380-rpmh-regulators"; + qcom,pmic-id = "e"; + + vdd-l2-supply = <&vreg_s1f_0p7>; + vdd-l3-supply = <&vph_pwr>; + + vreg_l2e_0p8: ldo2 { + regulator-name = "vreg_l2e_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + + vreg_l3e_1p2: ldo3 { + regulator-name = "vreg_l3e_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + }; + + regulators-4 { + compatible = "qcom,pmc8380-rpmh-regulators"; + qcom,pmic-id = "f"; + + vdd-l1-supply = <&vreg_s5j_1p2>; + vdd-l2-supply = <&vreg_s5j_1p2>; + vdd-l3-supply = <&vreg_s5j_1p2>; + vdd-s1-supply = <&vph_pwr>; + + vreg_s1f_0p7: smps1 { + regulator-name = "vreg_s1f_0p7"; + regulator-min-microvolt = <700000>; + regulator-max-microvolt = <1100000>; + regulator-initial-mode = ; + }; + + vreg_l1f_1p0: ldo1 { + regulator-name = "vreg_l1f_1p0"; + regulator-min-microvolt = <1024000>; + regulator-max-microvolt = <1024000>; + regulator-initial-mode = ; + }; + + vreg_l2f_1p0: ldo2 { + regulator-name = "vreg_l2f_1p0"; + regulator-min-microvolt = <1024000>; + regulator-max-microvolt = <1024000>; + regulator-initial-mode = ; + }; + + vreg_l3f_1p0: ldo3 { + regulator-name = "vreg_l3f_1p0"; + regulator-min-microvolt = <1024000>; + regulator-max-microvolt = <1024000>; + regulator-initial-mode = ; + }; + }; + + regulators-6 { + compatible = "qcom,pm8550ve-rpmh-regulators"; + qcom,pmic-id = "i"; + + vdd-l1-supply = <&vreg_s4c_1p8>; + vdd-l2-supply = <&vreg_s5j_1p2>; + vdd-l3-supply = <&vreg_s1f_0p7>; + vdd-s1-supply = <&vph_pwr>; + vdd-s2-supply = <&vph_pwr>; + + vreg_s1i_0p9: smps1 { + regulator-name = "vreg_s1i_0p9"; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + + vreg_s2i_1p0: smps2 { + regulator-name = "vreg_s2i_1p0"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1100000>; + regulator-initial-mode = ; + }; + + vreg_l1i_1p8: ldo1 { + regulator-name = "vreg_l1i_1p8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-initial-mode = ; + }; + + vreg_l2i_1p2: ldo2 { + regulator-name = "vreg_l2i_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l3i_0p8: ldo3 { + regulator-name = "vreg_l3i_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + }; + + regulators-7 { + compatible = "qcom,pm8550ve-rpmh-regulators"; + qcom,pmic-id = "j"; + + vdd-l1-supply = <&vreg_s1f_0p7>; + vdd-l2-supply = <&vph_pwr>; + vdd-l3-supply = <&vreg_s1f_0p7>; + vdd-s5-supply = <&vph_pwr>; + + vreg_s5j_1p2: smps5 { + regulator-name = "vreg_s5j_1p2"; + regulator-min-microvolt = <1256000>; + regulator-max-microvolt = <1304000>; + regulator-initial-mode = ; + }; + + vreg_l1j_0p8: ldo1 { + regulator-name = "vreg_l1j_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + + vreg_l2j_1p2: ldo2 { + regulator-name = "vreg_l2j_1p2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-initial-mode = ; + }; + + vreg_l3j_0p8: ldo3 { + regulator-name = "vreg_l3j_0p8"; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <920000>; + regulator-initial-mode = ; + }; + }; +}; + +&qupv3_2 { + status = "okay"; +}; + +&tlmm { + gpio-reserved-ranges = <33 3>, /* Unused */ + <44 4>, /* SPI (TPM) */ + <238 1>; /* UFS Reset */ +}; + +&uart21 { + compatible = "qcom,geni-debug-uart"; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/x1e80100.dtsi b/arch/arm64/boot/dts/qcom/x1e80100.dtsi new file mode 100644 index 00000000000000..6f75fc342ceb38 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/x1e80100.dtsi @@ -0,0 +1,3527 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/ { + interrupt-parent = <&intc>; + + #address-cells = <2>; + #size-cells = <2>; + + chosen { }; + + clocks { + xo_board: xo-board { + compatible = "fixed-clock"; + clock-frequency = <76800000>; + #clock-cells = <0>; + }; + + sleep_clk: sleep-clk { + compatible = "fixed-clock"; + clock-frequency = <32000>; + #clock-cells = <0>; + }; + + bi_tcxo_div2: bi-tcxo-div2-clk { + compatible = "fixed-factor-clock"; + #clock-cells = <0>; + + clocks = <&rpmhcc RPMH_CXO_CLK>; + clock-mult = <1>; + clock-div = <2>; + }; + + bi_tcxo_ao_div2: bi-tcxo-ao-div2-clk { + compatible = "fixed-factor-clock"; + #clock-cells = <0>; + + clocks = <&rpmhcc RPMH_CXO_CLK_A>; + clock-mult = <1>; + clock-div = <2>; + }; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x0>; + enable-method = "psci"; + next-level-cache = <&L2_0>; + power-domains = <&CPU_PD0>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER_C4>; + + L2_0: l2-cache { + compatible = "cache"; + cache-level = <2>; + cache-unified; + }; + }; + + CPU1: cpu@100 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x100>; + enable-method = "psci"; + next-level-cache = <&L2_0>; + power-domains = <&CPU_PD1>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER_C4>; + }; + + CPU2: cpu@200 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x200>; + enable-method = "psci"; + next-level-cache = <&L2_0>; + power-domains = <&CPU_PD2>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER_C4>; + }; + + CPU3: cpu@300 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x300>; + enable-method = "psci"; + next-level-cache = <&L2_0>; + power-domains = <&CPU_PD3>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER_C4>; + }; + + CPU4: cpu@10000 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x10000>; + enable-method = "psci"; + next-level-cache = <&L2_1>; + power-domains = <&CPU_PD4>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER_C4>; + + L2_1: l2-cache { + compatible = "cache"; + cache-level = <2>; + cache-unified; + }; + }; + + CPU5: cpu@10100 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x10100>; + enable-method = "psci"; + next-level-cache = <&L2_1>; + power-domains = <&CPU_PD5>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER_C4>; + }; + + CPU6: cpu@10200 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x10200>; + enable-method = "psci"; + next-level-cache = <&L2_1>; + power-domains = <&CPU_PD6>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER_C4>; + }; + + CPU7: cpu@10300 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x10300>; + enable-method = "psci"; + next-level-cache = <&L2_1>; + power-domains = <&CPU_PD7>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER_C4>; + }; + + CPU8: cpu@20000 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x20000>; + enable-method = "psci"; + next-level-cache = <&L2_2>; + power-domains = <&CPU_PD8>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER_C4>; + + L2_2: l2-cache { + compatible = "cache"; + cache-level = <2>; + cache-unified; + }; + }; + + CPU9: cpu@20100 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x20100>; + enable-method = "psci"; + next-level-cache = <&L2_2>; + power-domains = <&CPU_PD9>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER_C4>; + }; + + CPU10: cpu@20200 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x20200>; + enable-method = "psci"; + next-level-cache = <&L2_2>; + power-domains = <&CPU_PD10>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER_C4>; + }; + + CPU11: cpu@20300 { + device_type = "cpu"; + compatible = "qcom,oryon"; + reg = <0x0 0x20300>; + enable-method = "psci"; + next-level-cache = <&L2_2>; + power-domains = <&CPU_PD11>; + power-domain-names = "psci"; + cpu-idle-states = <&CLUSTER_C4>; + }; + + cpu-map { + cluster0 { + core0 { + cpu = <&CPU0>; + }; + + core1 { + cpu = <&CPU1>; + }; + + core2 { + cpu = <&CPU2>; + }; + + core3 { + cpu = <&CPU3>; + }; + }; + + cluster1 { + core0 { + cpu = <&CPU4>; + }; + + core1 { + cpu = <&CPU5>; + }; + + core2 { + cpu = <&CPU6>; + }; + + core3 { + cpu = <&CPU7>; + }; + }; + + cluster2 { + core0 { + cpu = <&CPU8>; + }; + + core1 { + cpu = <&CPU9>; + }; + + core2 { + cpu = <&CPU10>; + }; + + core3 { + cpu = <&CPU11>; + }; + }; + }; + + idle-states { + entry-method = "psci"; + + CLUSTER_C4: cpu-sleep-0 { + compatible = "arm,idle-state"; + idle-state-name = "ret"; + arm,psci-suspend-param = <0x00000004>; + entry-latency-us = <180>; + exit-latency-us = <320>; + min-residency-us = <1000>; + }; + }; + + domain-idle-states { + CLUSTER_CL4: cluster-sleep-0 { + compatible = "arm,idle-state"; + idle-state-name = "l2-ret"; + arm,psci-suspend-param = <0x01000044>; + entry-latency-us = <350>; + exit-latency-us = <500>; + min-residency-us = <2500>; + }; + + CLUSTER_CL5: cluster-sleep-1 { + compatible = "arm,idle-state"; + idle-state-name = "ret-pll-off"; + arm,psci-suspend-param = <0x01000054>; + entry-latency-us = <2200>; + exit-latency-us = <2500>; + min-residency-us = <7000>; + }; + }; + }; + + firmware { + scm: scm { + compatible = "qcom,scm-x1e80100", "qcom,scm"; + interconnects = <&aggre2_noc MASTER_CRYPTO QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + }; + }; + + clk_virt: interconnect-0 { + compatible = "qcom,x1e80100-clk-virt"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + mc_virt: interconnect-1 { + compatible = "qcom,x1e80100-mc-virt"; + #interconnect-cells = <2>; + qcom,bcm-voters = <&apps_bcm_voter>; + }; + + memory@80000000 { + device_type = "memory"; + /* We expect the bootloader to fill in the size */ + reg = <0 0x80000000 0 0>; + }; + + pmu { + compatible = "arm,armv8-pmuv3"; + interrupts = ; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + + CPU_PD0: power-domain-cpu0 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD0>; + }; + + CPU_PD1: power-domain-cpu1 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD0>; + }; + + CPU_PD2: power-domain-cpu2 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD0>; + }; + + CPU_PD3: power-domain-cpu3 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD0>; + }; + + CPU_PD4: power-domain-cpu4 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD1>; + }; + + CPU_PD5: power-domain-cpu5 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD1>; + }; + + CPU_PD6: power-domain-cpu6 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD1>; + }; + + CPU_PD7: power-domain-cpu7 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD1>; + }; + + CPU_PD8: power-domain-cpu8 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD2>; + }; + + CPU_PD9: power-domain-cpu9 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD2>; + }; + + CPU_PD10: power-domain-cpu10 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD2>; + }; + + CPU_PD11: power-domain-cpu11 { + #power-domain-cells = <0>; + power-domains = <&CLUSTER_PD2>; + }; + + CLUSTER_PD0: power-domain-cpu-cluster0 { + #power-domain-cells = <0>; + domain-idle-states = <&CLUSTER_CL4>, <&CLUSTER_CL5>; + }; + + CLUSTER_PD1: power-domain-cpu-cluster1 { + #power-domain-cells = <0>; + domain-idle-states = <&CLUSTER_CL4>, <&CLUSTER_CL5>; + }; + + CLUSTER_PD2: power-domain-cpu-cluster2 { + #power-domain-cells = <0>; + domain-idle-states = <&CLUSTER_CL4>, <&CLUSTER_CL5>; + }; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + gunyah_hyp_mem: gunyah-hyp@80000000 { + reg = <0x0 0x80000000 0x0 0x800000>; + no-map; + }; + + hyp_elf_package_mem: hyp-elf-package@80800000 { + reg = <0x0 0x80800000 0x0 0x200000>; + no-map; + }; + + ncc_mem: ncc@80a00000 { + reg = <0x0 0x80a00000 0x0 0x400000>; + no-map; + }; + + cpucp_log_mem: cpucp-log@80e00000 { + reg = <0x0 0x80e00000 0x0 0x40000>; + no-map; + }; + + cpucp_mem: cpucp@80e40000 { + reg = <0x0 0x80e40000 0x0 0x540000>; + no-map; + }; + + reserved-region@81380000 { + reg = <0x0 0x81380000 0x0 0x80000>; + no-map; + }; + + tags_mem: tags-region@81400000 { + reg = <0x0 0x81400000 0x0 0x1a0000>; + no-map; + }; + + xbl_dtlog_mem: xbl-dtlog@81a00000 { + reg = <0x0 0x81a00000 0x0 0x40000>; + no-map; + }; + + xbl_ramdump_mem: xbl-ramdump@81a40000 { + reg = <0x0 0x81a40000 0x0 0x1c0000>; + no-map; + }; + + aop_image_mem: aop-image@81c00000 { + reg = <0x0 0x81c00000 0x0 0x60000>; + no-map; + }; + + aop_cmd_db_mem: aop-cmd-db@81c60000 { + compatible = "qcom,cmd-db"; + reg = <0x0 0x81c60000 0x0 0x20000>; + no-map; + }; + + aop_config_mem: aop-config@81c80000 { + reg = <0x0 0x81c80000 0x0 0x20000>; + no-map; + }; + + tme_crash_dump_mem: tme-crash-dump@81ca0000 { + reg = <0x0 0x81ca0000 0x0 0x40000>; + no-map; + }; + + tme_log_mem: tme-log@81ce0000 { + reg = <0x0 0x81ce0000 0x0 0x4000>; + no-map; + }; + + uefi_log_mem: uefi-log@81ce4000 { + reg = <0x0 0x81ce4000 0x0 0x10000>; + no-map; + }; + + secdata_apss_mem: secdata-apss@81cff000 { + reg = <0x0 0x81cff000 0x0 0x1000>; + no-map; + }; + + pdp_ns_shared_mem: pdp-ns-shared@81e00000 { + reg = <0x0 0x81e00000 0x0 0x100000>; + no-map; + }; + + gpu_prr_mem: gpu-prr@81f00000 { + reg = <0x0 0x81f00000 0x0 0x10000>; + no-map; + }; + + tpm_control_mem: tpm-control@81f10000 { + reg = <0x0 0x81f10000 0x0 0x10000>; + no-map; + }; + + usb_ucsi_shared_mem: usb-ucsi-shared@81f20000 { + reg = <0x0 0x81f20000 0x0 0x10000>; + no-map; + }; + + pld_pep_mem: pld-pep@81f30000 { + reg = <0x0 0x81f30000 0x0 0x6000>; + no-map; + }; + + pld_gmu_mem: pld-gmu@81f36000 { + reg = <0x0 0x81f36000 0x0 0x1000>; + no-map; + }; + + pld_pdp_mem: pld-pdp@81f37000 { + reg = <0x0 0x81f37000 0x0 0x1000>; + no-map; + }; + + tz_stat_mem: tz-stat@82700000 { + reg = <0x0 0x82700000 0x0 0x100000>; + no-map; + }; + + xbl_tmp_buffer_mem: xbl-tmp-buffer@82800000 { + reg = <0x0 0x82800000 0x0 0xc00000>; + no-map; + }; + + adsp_rpc_remote_heap_mem: adsp-rpc-remote-heap@84b00000 { + reg = <0x0 0x84b00000 0x0 0x800000>; + no-map; + }; + + spu_secure_shared_memory_mem: spu-secure-shared-memory@85300000 { + reg = <0x0 0x85300000 0x0 0x80000>; + no-map; + }; + + adsp_boot_dtb_mem: adsp-boot-dtb@866c0000 { + reg = <0x0 0x866c0000 0x0 0x40000>; + no-map; + }; + + spss_region_mem: spss-region@86700000 { + reg = <0x0 0x86700000 0x0 0x400000>; + no-map; + }; + + adsp_boot_mem: adsp-boot@86b00000 { + reg = <0x0 0x86b00000 0x0 0xc00000>; + no-map; + }; + + video_mem: video@87700000 { + reg = <0x0 0x87700000 0x0 0x700000>; + no-map; + }; + + adspslpi_mem: adspslpi@87e00000 { + reg = <0x0 0x87e00000 0x0 0x3a00000>; + no-map; + }; + + q6_adsp_dtb_mem: q6-adsp-dtb@8b800000 { + reg = <0x0 0x8b800000 0x0 0x80000>; + no-map; + }; + + cdsp_mem: cdsp@8b900000 { + reg = <0x0 0x8b900000 0x0 0x2000000>; + no-map; + }; + + q6_cdsp_dtb_mem: q6-cdsp-dtb@8d900000 { + reg = <0x0 0x8d900000 0x0 0x80000>; + no-map; + }; + + gpu_microcode_mem: gpu-microcode@8d9fe000 { + reg = <0x0 0x8d9fe000 0x0 0x2000>; + no-map; + }; + + cvp_mem: cvp@8da00000 { + reg = <0x0 0x8da00000 0x0 0x700000>; + no-map; + }; + + camera_mem: camera@8e100000 { + reg = <0x0 0x8e100000 0x0 0x800000>; + no-map; + }; + + av1_encoder_mem: av1-encoder@8e900000 { + reg = <0x0 0x8e900000 0x0 0x700000>; + no-map; + }; + + reserved-region@8f000000 { + reg = <0x0 0x8f000000 0x0 0xa00000>; + no-map; + }; + + wpss_mem: wpss@8fa00000 { + reg = <0x0 0x8fa00000 0x0 0x1900000>; + no-map; + }; + + q6_wpss_dtb_mem: q6-wpss-dtb@91300000 { + reg = <0x0 0x91300000 0x0 0x80000>; + no-map; + }; + + xbl_sc_mem: xbl-sc@d8000000 { + reg = <0x0 0xd8000000 0x0 0x40000>; + no-map; + }; + + reserved-region@d8040000 { + reg = <0x0 0xd8040000 0x0 0xa0000>; + no-map; + }; + + qtee_mem: qtee@d80e0000 { + reg = <0x0 0xd80e0000 0x0 0x520000>; + no-map; + }; + + ta_mem: ta@d8600000 { + reg = <0x0 0xd8600000 0x0 0x8a00000>; + no-map; + }; + + tags_mem1: tags@e1000000 { + reg = <0x0 0xe1000000 0x0 0x26a0000>; + no-map; + }; + + llcc_lpi_mem: llcc-lpi@ff800000 { + reg = <0x0 0xff800000 0x0 0x600000>; + no-map; + }; + + smem_mem: smem@ffe00000 { + compatible = "qcom,smem"; + reg = <0x0 0xffe00000 0x0 0x200000>; + hwlocks = <&tcsr_mutex 3>; + no-map; + }; + }; + + soc: soc@0 { + compatible = "simple-bus"; + + #address-cells = <2>; + #size-cells = <2>; + dma-ranges = <0 0 0 0 0x10 0>; + ranges = <0 0 0 0 0x10 0>; + + gcc: clock-controller@100000 { + compatible = "qcom,x1e80100-gcc"; + reg = <0 0x00100000 0 0x200000>; + + clocks = <&bi_tcxo_div2>, + <&sleep_clk>, + <0>, + <0>, + <0>, + <0>, + <0>, + <0>, + <0>, + <0>; + + power-domains = <&rpmhpd RPMHPD_CX>; + #clock-cells = <1>; + #reset-cells = <1>; + #power-domain-cells = <1>; + }; + + gpi_dma2: dma-controller@800000 { + compatible = "qcom,x1e80100-gpi-dma", "qcom,sm6350-gpi-dma"; + reg = <0 0x00800000 0 0x60000>; + + interrupts = , + , + , + , + , + , + , + , + , + , + , + ; + + dma-channels = <12>; + dma-channel-mask = <0x3e>; + #dma-cells = <3>; + + iommus = <&apps_smmu 0x436 0x0>; + + status = "disabled"; + }; + + qupv3_2: geniqup@8c0000 { + compatible = "qcom,geni-se-qup"; + reg = <0 0x008c0000 0 0x2000>; + + clocks = <&gcc GCC_QUPV3_WRAP_2_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_2_S_AHB_CLK>; + clock-names = "m-ahb", + "s-ahb"; + + iommus = <&apps_smmu 0x423 0x0>; + + #address-cells = <2>; + #size-cells = <2>; + ranges; + + status = "disabled"; + + i2c16: i2c@880000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00880000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S0_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 0 QCOM_GPI_I2C>, + <&gpi_dma2 1 0 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c16_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi16: spi@880000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00880000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S0_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 0 QCOM_GPI_SPI>, + <&gpi_dma2 1 0 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi16_data_clk>, <&qup_spi16_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c17: i2c@884000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00884000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S1_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 1 QCOM_GPI_I2C>, + <&gpi_dma2 1 1 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c17_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi17: spi@884000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00884000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S1_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 1 QCOM_GPI_SPI>, + <&gpi_dma2 1 1 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi17_data_clk>, <&qup_spi17_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c18: i2c@888000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00888000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S2_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 2 QCOM_GPI_I2C>, + <&gpi_dma2 1 2 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c18_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi18: spi@888000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00888000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S2_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 2 QCOM_GPI_SPI>, + <&gpi_dma2 1 2 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi18_data_clk>, <&qup_spi18_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c19: i2c@88c000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x0088c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S3_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 3 QCOM_GPI_I2C>, + <&gpi_dma2 1 3 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c19_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi19: spi@88c000 { + compatible = "qcom,geni-spi"; + reg = <0 0x0088c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S3_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 3 QCOM_GPI_SPI>, + <&gpi_dma2 1 3 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi19_data_clk>, <&qup_spi19_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c20: i2c@890000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00890000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S4_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 4 QCOM_GPI_I2C>, + <&gpi_dma2 1 4 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c20_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi20: spi@890000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00890000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S4_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 4 QCOM_GPI_SPI>, + <&gpi_dma2 1 4 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi20_data_clk>, <&qup_spi20_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c21: i2c@894000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00894000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S5_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 5 QCOM_GPI_I2C>, + <&gpi_dma2 1 5 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c21_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi21: spi@894000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00894000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S5_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 5 QCOM_GPI_SPI>, + <&gpi_dma2 1 5 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi21_data_clk>, <&qup_spi21_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + uart21: serial@894000 { + compatible = "qcom,geni-uart"; + reg = <0 0x00894000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S5_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config"; + + pinctrl-0 = <&qup_uart21_default>; + pinctrl-names = "default"; + + status = "disabled"; + }; + + i2c22: i2c@898000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00898000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S6_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 6 QCOM_GPI_I2C>, + <&gpi_dma2 1 6 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c22_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi22: spi@898000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00898000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S6_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 6 QCOM_GPI_SPI>, + <&gpi_dma2 1 6 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi22_data_clk>, <&qup_spi22_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c23: i2c@89c000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x0089c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S7_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 7 QCOM_GPI_I2C>, + <&gpi_dma2 1 7 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c23_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi23: spi@89c000 { + compatible = "qcom,geni-spi"; + reg = <0 0x0089c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP2_S7_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_2 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_2 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_2 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma2 0 7 QCOM_GPI_SPI>, + <&gpi_dma2 1 7 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi23_data_clk>, <&qup_spi23_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + }; + + gpi_dma1: dma-controller@a00000 { + compatible = "qcom,x1e80100-gpi-dma", "qcom,sm6350-gpi-dma"; + reg = <0 0x00a00000 0 0x60000>; + + interrupts = , + , + , + , + , + , + , + , + , + , + , + ; + + dma-channels = <12>; + dma-channel-mask = <0x3e>; + #dma-cells = <3>; + + iommus = <&apps_smmu 0x136 0x0>; + + status = "disabled"; + }; + + qupv3_1: geniqup@ac0000 { + compatible = "qcom,geni-se-qup"; + reg = <0 0x00ac0000 0 0x2000>; + + clocks = <&gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + clock-names = "m-ahb", + "s-ahb"; + + iommus = <&apps_smmu 0x123 0x0>; + + #address-cells = <2>; + #size-cells = <2>; + ranges; + + status = "disabled"; + + i2c8: i2c@a80000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a80000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S0_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 0 QCOM_GPI_I2C>, + <&gpi_dma1 1 0 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c8_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi8: spi@a80000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a80000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S0_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 0 QCOM_GPI_SPI>, + <&gpi_dma1 1 0 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi8_data_clk>, <&qup_spi8_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c9: i2c@a84000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a84000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S1_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 1 QCOM_GPI_I2C>, + <&gpi_dma1 1 1 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c9_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi9: spi@a84000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a84000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S1_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 1 QCOM_GPI_SPI>, + <&gpi_dma1 1 1 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi9_data_clk>, <&qup_spi9_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c10: i2c@a88000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a88000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S2_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 2 QCOM_GPI_I2C>, + <&gpi_dma1 1 2 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c10_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi10: spi@a88000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a88000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S2_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 2 QCOM_GPI_SPI>, + <&gpi_dma1 1 2 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi10_data_clk>, <&qup_spi10_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c11: i2c@a8c000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a8c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S3_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 3 QCOM_GPI_I2C>, + <&gpi_dma1 1 3 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c11_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi11: spi@a8c000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a8c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S3_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 3 QCOM_GPI_SPI>, + <&gpi_dma1 1 3 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi11_data_clk>, <&qup_spi11_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c12: i2c@a90000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a90000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S4_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 4 QCOM_GPI_I2C>, + <&gpi_dma1 1 4 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c12_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi12: spi@a90000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a90000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S4_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 4 QCOM_GPI_SPI>, + <&gpi_dma1 1 4 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi12_data_clk>, <&qup_spi12_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c13: i2c@a94000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a94000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S5_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 5 QCOM_GPI_I2C>, + <&gpi_dma1 1 5 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c13_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi13: spi@a94000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a94000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S5_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 5 QCOM_GPI_SPI>, + <&gpi_dma1 1 5 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi13_data_clk>, <&qup_spi13_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c14: i2c@a98000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a98000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S6_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 6 QCOM_GPI_I2C>, + <&gpi_dma1 1 6 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c14_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi14: spi@a98000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a98000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S6_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 6 QCOM_GPI_SPI>, + <&gpi_dma1 1 6 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi14_data_clk>, <&qup_spi14_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c15: i2c@a9c000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00a9c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S7_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 7 QCOM_GPI_I2C>, + <&gpi_dma1 1 7 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c15_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi15: spi@a9c000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00a9c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP1_S7_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_1 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_1 QCOM_ICC_TAG_ALWAYS>, + <&aggre1_noc MASTER_QUP_1 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma1 0 7 QCOM_GPI_SPI>, + <&gpi_dma1 1 7 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi15_data_clk>, <&qup_spi15_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + }; + + gpi_dma0: dma-controller@b00000 { + compatible = "qcom,x1e80100-gpi-dma", "qcom,sm6350-gpi-dma"; + reg = <0 0x00b00000 0 0x60000>; + + interrupts = , + , + , + , + , + , + , + , + , + , + , + ; + + dma-channels = <12>; + dma-channel-mask = <0x3e>; + #dma-cells = <3>; + + iommus = <&apps_smmu 0x456 0x0>; + + status = "disabled"; + }; + + qupv3_0: geniqup@bc0000 { + compatible = "qcom,geni-se-qup"; + reg = <0 0x00bc0000 0 0x2000>; + + clocks = <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, + <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; + clock-names = "m-ahb", + "s-ahb"; + + iommus = <&apps_smmu 0x443 0x0>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + status = "disabled"; + + i2c0: i2c@b80000 { + compatible = "qcom,geni-i2c"; + reg = <0 0xb80000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP0_S0_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma0 0 0 QCOM_GPI_I2C>, + <&gpi_dma0 1 0 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c0_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi0: spi@b80000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00b80000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP0_S0_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma0 0 0 QCOM_GPI_SPI>, + <&gpi_dma0 1 0 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi0_data_clk>, <&qup_spi0_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c1: i2c@b84000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00b84000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP0_S1_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma0 0 1 QCOM_GPI_I2C>, + <&gpi_dma0 1 1 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c1_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi1: spi@b84000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00b84000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP0_S1_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma0 0 1 QCOM_GPI_SPI>, + <&gpi_dma0 1 1 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi1_data_clk>, <&qup_spi1_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c2: i2c@b88000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00b88000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP0_S2_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma0 0 2 QCOM_GPI_I2C>, + <&gpi_dma0 1 2 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c2_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi2: spi@b88000 { + compatible = "qcom,geni-spi"; + reg = <0 0xb88000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP0_S2_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma0 0 2 QCOM_GPI_SPI>, + <&gpi_dma0 1 2 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi2_data_clk>, <&qup_spi2_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c3: i2c@b8c000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00b8c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP0_S3_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma0 0 3 QCOM_GPI_I2C>, + <&gpi_dma0 1 3 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c3_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi3: spi@b8c000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00b8c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP0_S3_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma0 0 3 QCOM_GPI_SPI>, + <&gpi_dma0 1 3 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi3_data_clk>, <&qup_spi3_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c4: i2c@b90000 { + compatible = "qcom,geni-i2c"; + reg = <0 0xb90000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP0_S4_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma0 0 4 QCOM_GPI_I2C>, + <&gpi_dma0 1 4 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c4_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi4: spi@b90000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00b90000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP0_S4_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma0 0 4 QCOM_GPI_SPI>, + <&gpi_dma0 1 4 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi4_data_clk>, <&qup_spi4_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c5: i2c@b94000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00b94000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP0_S5_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma0 0 5 QCOM_GPI_I2C>, + <&gpi_dma0 1 5 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c5_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi5: spi@b94000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00b94000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP0_S5_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma0 0 5 QCOM_GPI_SPI>, + <&gpi_dma0 1 5 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi5_data_clk>, <&qup_spi5_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c6: i2c@b98000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00b98000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP0_S6_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma0 0 6 QCOM_GPI_I2C>, + <&gpi_dma0 1 6 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c6_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi6: spi@b98000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00b98000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP0_S6_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma0 0 6 QCOM_GPI_SPI>, + <&gpi_dma0 1 6 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi6_data_clk>, <&qup_spi6_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + i2c7: i2c@b9c000 { + compatible = "qcom,geni-i2c"; + reg = <0 0x00b9c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP0_S7_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma0 0 7 QCOM_GPI_I2C>, + <&gpi_dma0 1 7 QCOM_GPI_I2C>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_i2c7_data_clk>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + spi7: spi@b9c000 { + compatible = "qcom,geni-spi"; + reg = <0 0x00b9c000 0 0x4000>; + + interrupts = ; + + clocks = <&gcc GCC_QUPV3_WRAP0_S7_CLK>; + clock-names = "se"; + + interconnects = <&clk_virt MASTER_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS + &clk_virt SLAVE_QUP_CORE_0 QCOM_ICC_TAG_ALWAYS>, + <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ALWAYS + &config_noc SLAVE_QUP_0 QCOM_ICC_TAG_ALWAYS>, + <&aggre2_noc MASTER_QUP_0 QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "qup-core", + "qup-config", + "qup-memory"; + + dmas = <&gpi_dma0 0 7 QCOM_GPI_SPI>, + <&gpi_dma0 1 7 QCOM_GPI_SPI>; + dma-names = "tx", + "rx"; + + pinctrl-0 = <&qup_spi7_data_clk>, <&qup_spi7_cs>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + }; + + cnoc_main: interconnect@1500000 { + compatible = "qcom,x1e80100-cnoc-main"; + reg = <0 0x1500000 0 0x14400>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + config_noc: interconnect@1600000 { + compatible = "qcom,x1e80100-cnoc-cfg"; + reg = <0 0x1600000 0 0x6600>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + system_noc: interconnect@1680000 { + compatible = "qcom,x1e80100-system-noc"; + reg = <0 0x1680000 0 0x1c080>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + pcie_south_anoc: interconnect@16c0000 { + compatible = "qcom,x1e80100-pcie-south-anoc"; + reg = <0 0x16c0000 0 0xd080>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + pcie_center_anoc: interconnect@16d0000 { + compatible = "qcom,x1e80100-pcie-center-anoc"; + reg = <0 0x16d0000 0 0x7000>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + aggre1_noc: interconnect@16e0000 { + compatible = "qcom,x1e80100-aggre1-noc"; + reg = <0 0x16E0000 0 0x14400>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + aggre2_noc: interconnect@1700000 { + compatible = "qcom,x1e80100-aggre2-noc"; + reg = <0 0x1700000 0 0x1c400>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + pcie_north_anoc: interconnect@1740000 { + compatible = "qcom,x1e80100-pcie-north-anoc"; + reg = <0 0x1740000 0 0x9080>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + usb_center_anoc: interconnect@1750000 { + compatible = "qcom,x1e80100-usb-center-anoc"; + reg = <0 0x1750000 0 0x8800>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + usb_north_anoc: interconnect@1760000 { + compatible = "qcom,x1e80100-usb-north-anoc"; + reg = <0 0x1760000 0 0x7080>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + usb_south_anoc: interconnect@1770000 { + compatible = "qcom,x1e80100-usb-south-anoc"; + reg = <0 0x1770000 0 0xf080>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + mmss_noc: interconnect@1780000 { + compatible = "qcom,x1e80100-mmss-noc"; + reg = <0 0x1780000 0 0x5B800>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + tcsr_mutex: hwlock@1f40000 { + compatible = "qcom,tcsr-mutex"; + reg = <0 0x01f40000 0 0x20000>; + #hwlock-cells = <1>; + }; + + gem_noc: interconnect@26400000 { + compatible = "qcom,x1e80100-gem-noc"; + reg = <0 0x26400000 0 0x311200>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + nsp_noc: interconnect@320c0000 { + compatible = "qcom,x1e80100-nsp-noc"; + reg = <0 0x320C0000 0 0xE080>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + lpass_ag_noc: interconnect@7e40000 { + compatible = "qcom,x1e80100-lpass-ag-noc"; + reg = <0 0x7e40000 0 0xE080>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + lpass_lpiaon_noc: interconnect@7400000 { + compatible = "qcom,x1e80100-lpass-lpiaon-noc"; + reg = <0 0x7400000 0 0x19080>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + lpass_lpicx_noc: interconnect@7430000 { + compatible = "qcom,x1e80100-lpass-lpicx-noc"; + reg = <0 0x7430000 0 0x3A200>; + + qcom,bcm-voters = <&apps_bcm_voter>; + + #interconnect-cells = <2>; + }; + + pdc: interrupt-controller@b220000 { + compatible = "qcom,x1e80100-pdc", "qcom,pdc"; + reg = <0 0x0b220000 0 0x30000>, <0 0x174000f0 0 0x64>; + + qcom,pdc-ranges = <0 480 42>, <42 251 5>, + <47 522 52>, <99 609 32>, + <131 717 12>, <143 816 19>; + #interrupt-cells = <2>; + interrupt-parent = <&intc>; + interrupt-controller; + }; + + tlmm: pinctrl@f100000 { + compatible = "qcom,x1e80100-tlmm"; + reg = <0 0x0f100000 0 0xf00000>; + + interrupts = ; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + + gpio-ranges = <&tlmm 0 0 239>; + wakeup-parent = <&pdc>; + + qup_i2c0_data_clk: qup-i2c0-data-clk-state { + /* SDA, SCL */ + pins = "gpio0", "gpio1"; + function = "qup0_se0"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c1_data_clk: qup-i2c1-data-clk-state { + /* SDA, SCL */ + pins = "gpio4", "gpio5"; + function = "qup0_se1"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c2_data_clk: qup-i2c2-data-clk-state { + /* SDA, SCL */ + pins = "gpio8", "gpio9"; + function = "qup0_se2"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c3_data_clk: qup-i2c3-data-clk-state { + /* SDA, SCL */ + pins = "gpio12", "gpio13"; + function = "qup0_se3"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c4_data_clk: qup-i2c4-data-clk-state { + /* SDA, SCL */ + pins = "gpio16", "gpio17"; + function = "qup0_se4"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c5_data_clk: qup-i2c5-data-clk-state { + /* SDA, SCL */ + pins = "gpio20", "gpio21"; + function = "qup0_se5"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c6_data_clk: qup-i2c6-data-clk-state { + /* SDA, SCL */ + pins = "gpio24", "gpio25"; + function = "qup0_se6"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c7_data_clk: qup-i2c7-data-clk-state { + /* SDA, SCL */ + pins = "gpio14", "gpio15"; + function = "qup0_se7"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c8_data_clk: qup-i2c8-data-clk-state { + /* SDA, SCL */ + pins = "gpio32", "gpio33"; + function = "qup1_se0"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c9_data_clk: qup-i2c9-data-clk-state { + /* SDA, SCL */ + pins = "gpio36", "gpio37"; + function = "qup1_se1"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c10_data_clk: qup-i2c10-data-clk-state { + /* SDA, SCL */ + pins = "gpio40", "gpio41"; + function = "qup1_se2"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c11_data_clk: qup-i2c11-data-clk-state { + /* SDA, SCL */ + pins = "gpio44", "gpio45"; + function = "qup1_se3"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c12_data_clk: qup-i2c12-data-clk-state { + /* SDA, SCL */ + pins = "gpio48", "gpio49"; + function = "qup1_se4"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c13_data_clk: qup-i2c13-data-clk-state { + /* SDA, SCL */ + pins = "gpio52", "gpio53"; + function = "qup1_se5"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c14_data_clk: qup-i2c14-data-clk-state { + /* SDA, SCL */ + pins = "gpio56", "gpio57"; + function = "qup1_se6"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c15_data_clk: qup-i2c15-data-clk-state { + /* SDA, SCL */ + pins = "gpio54", "gpio55"; + function = "qup1_se7"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c16_data_clk: qup-i2c16-data-clk-state { + /* SDA, SCL */ + pins = "gpio64", "gpio65"; + function = "qup2_se0"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c17_data_clk: qup-i2c17-data-clk-state { + /* SDA, SCL */ + pins = "gpio68", "gpio69"; + function = "qup2_se1"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c18_data_clk: qup-i2c18-data-clk-state { + /* SDA, SCL */ + pins = "gpio72", "gpio73"; + function = "qup2_se2"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c19_data_clk: qup-i2c19-data-clk-state { + /* SDA, SCL */ + pins = "gpio76", "gpio77"; + function = "qup2_se3"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c20_data_clk: qup-i2c20-data-clk-state { + /* SDA, SCL */ + pins = "gpio80", "gpio81"; + function = "qup2_se4"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c21_data_clk: qup-i2c21-data-clk-state { + /* SDA, SCL */ + pins = "gpio84", "gpio85"; + function = "qup2_se5"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c22_data_clk: qup-i2c22-data-clk-state { + /* SDA, SCL */ + pins = "gpio88", "gpio89"; + function = "qup2_se6"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_i2c23_data_clk: qup-i2c23-data-clk-state { + /* SDA, SCL */ + pins = "gpio86", "gpio87"; + function = "qup2_se7"; + drive-strength = <2>; + bias-pull-up = <2200>; + }; + + qup_spi0_cs: qup-spi0-cs-state { + pins = "gpio3"; + function = "qup0_se0"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi0_data_clk: qup-spi0-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio0", "gpio1", "gpio2"; + function = "qup0_se0"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi1_cs: qup-spi1-cs-state { + pins = "gpio7"; + function = "qup0_se1"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi1_data_clk: qup-spi1-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio4", "gpio5", "gpio6"; + function = "qup0_se1"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi2_cs: qup-spi2-cs-state { + pins = "gpio11"; + function = "qup0_se2"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi2_data_clk: qup-spi2-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio8", "gpio9", "gpio10"; + function = "qup0_se2"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi3_cs: qup-spi3-cs-state { + pins = "gpio15"; + function = "qup0_se3"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi3_data_clk: qup-spi3-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio12", "gpio13", "gpio14"; + function = "qup0_se3"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi4_cs: qup-spi4-cs-state { + pins = "gpio19"; + function = "qup0_se4"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi4_data_clk: qup-spi4-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio16", "gpio17", "gpio18"; + function = "qup0_se4"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi5_cs: qup-spi5-cs-state { + pins = "gpio23"; + function = "qup0_se5"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi5_data_clk: qup-spi5-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio20", "gpio21", "gpio22"; + function = "qup0_se5"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi6_cs: qup-spi6-cs-state { + pins = "gpio27"; + function = "qup0_se6"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi6_data_clk: qup-spi6-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio24", "gpio25", "gpio26"; + function = "qup0_se6"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi7_cs: qup-spi7-cs-state { + pins = "gpio13"; + function = "qup0_se7"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi7_data_clk: qup-spi7-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio14", "gpio15", "gpio12"; + function = "qup0_se7"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi8_cs: qup-spi8-cs-state { + pins = "gpio35"; + function = "qup1_se0"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi8_data_clk: qup-spi8-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio32", "gpio33", "gpio34"; + function = "qup1_se0"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi9_cs: qup-spi9-cs-state { + pins = "gpio39"; + function = "qup1_se1"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi9_data_clk: qup-spi9-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio36", "gpio37", "gpio38"; + function = "qup1_se1"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi10_cs: qup-spi10-cs-state { + pins = "gpio43"; + function = "qup1_se2"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi10_data_clk: qup-spi10-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio40", "gpio41", "gpio42"; + function = "qup1_se2"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi11_cs: qup-spi11-cs-state { + pins = "gpio47"; + function = "qup1_se3"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi11_data_clk: qup-spi11-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio44", "gpio45", "gpio46"; + function = "qup1_se3"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi12_cs: qup-spi12-cs-state { + pins = "gpio51"; + function = "qup1_se4"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi12_data_clk: qup-spi12-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio48", "gpio49", "gpio50"; + function = "qup1_se4"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi13_cs: qup-spi13-cs-state { + pins = "gpio55"; + function = "qup1_se5"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi13_data_clk: qup-spi13-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio52", "gpio53", "gpio54"; + function = "qup1_se5"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi14_cs: qup-spi14-cs-state { + pins = "gpio59"; + function = "qup1_se6"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi14_data_clk: qup-spi14-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio56", "gpio57", "gpio58"; + function = "qup1_se6"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi15_cs: qup-spi15-cs-state { + pins = "gpio53"; + function = "qup1_se7"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi15_data_clk: qup-spi15-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio54", "gpio55", "gpio52"; + function = "qup1_se7"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi16_cs: qup-spi16-cs-state { + pins = "gpio67"; + function = "qup2_se0"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi16_data_clk: qup-spi16-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio64", "gpio65", "gpio66"; + function = "qup2_se0"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi17_cs: qup-spi17-cs-state { + pins = "gpio71"; + function = "qup2_se1"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi17_data_clk: qup-spi17-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio68", "gpio69", "gpio70"; + function = "qup2_se1"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi18_cs: qup-spi18-cs-state { + pins = "gpio75"; + function = "qup2_se2"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi18_data_clk: qup-spi18-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio72", "gpio73", "gpio74"; + function = "qup2_se2"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi19_cs: qup-spi19-cs-state { + pins = "gpio79"; + function = "qup2_se3"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi19_data_clk: qup-spi19-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio76", "gpio77", "gpio78"; + function = "qup2_se3"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi20_cs: qup-spi20-cs-state { + pins = "gpio83"; + function = "qup2_se4"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi20_data_clk: qup-spi20-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio80", "gpio81", "gpio82"; + function = "qup2_se4"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi21_cs: qup-spi21-cs-state { + pins = "gpio87"; + function = "qup2_se5"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi21_data_clk: qup-spi21-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio84", "gpio85", "gpio86"; + function = "qup2_se5"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi22_cs: qup-spi22-cs-state { + pins = "gpio91"; + function = "qup2_se6"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi22_data_clk: qup-spi22-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio88", "gpio89", "gpio90"; + function = "qup2_se6"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi23_cs: qup-spi23-cs-state { + pins = "gpio85"; + function = "qup2_se7"; + drive-strength = <6>; + bias-disable; + }; + + qup_spi23_data_clk: qup-spi23-data-clk-state { + /* MISO, MOSI, CLK */ + pins = "gpio86", "gpio87", "gpio84"; + function = "qup2_se7"; + drive-strength = <6>; + bias-disable; + }; + + qup_uart21_default: qup-uart21-default-state { + /* TX, RX */ + pins = "gpio86", "gpio87"; + function = "qup2_se5"; + drive-strength= <2>; + bias-disable; + }; + }; + + apps_smmu: iommu@15000000 { + compatible = "qcom,x1e80100-smmu-500", "qcom,smmu-500", "arm,mmu-500"; + reg = <0 0x15000000 0 0x100000>; + + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + + #iommu-cells = <2>; + #global-interrupts = <1>; + }; + + intc: interrupt-controller@17000000 { + compatible = "arm,gic-v3"; + reg = <0 0x17000000 0 0x10000>, /* GICD */ + <0 0x17080000 0 0x480000>; /* GICR * 12 */ + + interrupts = ; + + #interrupt-cells = <3>; + interrupt-controller; + + #redistributor-regions = <1>; + redistributor-stride = <0x0 0x40000>; + + #address-cells = <2>; + #size-cells = <2>; + ranges; + + gic_its: msi-controller@17040000 { + compatible = "arm,gic-v3-its"; + reg = <0 0x17040000 0 0x40000>; + + msi-controller; + #msi-cells = <1>; + + status = "disabled"; + }; + }; + + apps_rsc: rsc@17500000 { + compatible = "qcom,rpmh-rsc"; + reg = <0 0x17500000 0 0x10000>, + <0 0x17510000 0 0x10000>, + <0 0x17520000 0 0x10000>; + reg-names = "drv-0", "drv-1", "drv-2"; + qcom,drv-count = <3>; + + interrupts = , + , + ; + qcom,tcs-offset = <0xd00>; + qcom,drv-id = <2>; + qcom,tcs-config = , , + , ; + + label = "apps_rsc"; + + apps_bcm_voter: bcm-voter { + compatible = "qcom,bcm-voter"; + }; + + rpmhcc: clock-controller { + compatible = "qcom,x1e80100-rpmh-clk"; + + clocks = <&xo_board>; + clock-names = "xo"; + + #clock-cells = <1>; + }; + + rpmhpd: power-controller { + compatible = "qcom,x1e80100-rpmhpd"; + + operating-points-v2 = <&rpmhpd_opp_table>; + + #power-domain-cells = <1>; + + rpmhpd_opp_table: opp-table { + compatible = "operating-points-v2"; + + rpmhpd_opp_ret: opp-16 { + opp-level = ; + }; + + rpmhpd_opp_min_svs: opp-48 { + opp-level = ; + }; + + rpmhpd_opp_low_svs_d2: opp-52 { + opp-level = ; + }; + + rpmhpd_opp_low_svs_d1: opp-56 { + opp-level = ; + }; + + rpmhpd_opp_low_svs_d0: opp-60 { + opp-level = ; + }; + + rpmhpd_opp_low_svs: opp-64 { + opp-level = ; + }; + + rpmhpd_opp_low_svs_l1: opp-80 { + opp-level = ; + }; + + rpmhpd_opp_svs: opp-128 { + opp-level = ; + }; + + rpmhpd_opp_svs_l0: opp-144 { + opp-level = ; + }; + + rpmhpd_opp_svs_l1: opp-192 { + opp-level = ; + }; + + rpmhpd_opp_nom: opp-256 { + opp-level = ; + }; + + rpmhpd_opp_nom_l1: opp-320 { + opp-level = ; + }; + + rpmhpd_opp_nom_l2: opp-336 { + opp-level = ; + }; + + rpmhpd_opp_turbo: opp-384 { + opp-level = ; + }; + + rpmhpd_opp_turbo_l1: opp-416 { + opp-level = ; + }; + }; + }; + }; + + timer@17800000 { + compatible = "arm,armv7-timer-mem"; + reg = <0 0x17800000 0 0x1000>; + + #address-cells = <2>; + #size-cells = <1>; + ranges = <0 0 0 0 0x20000000>; + + frame@17801000 { + reg = <0 0x17801000 0x1000>, + <0 0x17802000 0x1000>; + + interrupts = , + ; + + frame-number = <0>; + }; + + frame@17803000 { + reg = <0 0x17803000 0x1000>; + + interrupts = ; + + frame-number = <1>; + + status = "disabled"; + }; + + frame@17805000 { + reg = <0 0x17805000 0x1000>; + + interrupts = ; + + frame-number = <2>; + + status = "disabled"; + }; + + frame@17807000 { + reg = <0 0x17807000 0x1000>; + + interrupts = ; + + frame-number = <3>; + + status = "disabled"; + }; + + frame@17809000 { + reg = <0 0x17809000 0x1000>; + + interrupts = ; + + frame-number = <4>; + + status = "disabled"; + }; + + frame@1780b000 { + reg = <0 0x1780b000 0x1000>; + + interrupts = ; + + frame-number = <5>; + + status = "disabled"; + }; + + frame@1780d000 { + reg = <0 0x1780d000 0x1000>; + + interrupts = ; + + frame-number = <6>; + + status = "disabled"; + }; + }; + + system-cache-controller@25000000 { + compatible = "qcom,x1e80100-llcc"; + reg = <0 0x25000000 0 0x200000>, + <0 0x25200000 0 0x200000>, + <0 0x25400000 0 0x200000>, + <0 0x25600000 0 0x200000>, + <0 0x25800000 0 0x200000>, + <0 0x25a00000 0 0x200000>, + <0 0x25c00000 0 0x200000>, + <0 0x25e00000 0 0x200000>, + <0 0x26000000 0 0x200000>; + reg-names = "llcc0_base", + "llcc1_base", + "llcc2_base", + "llcc3_base", + "llcc4_base", + "llcc5_base", + "llcc6_base", + "llcc7_base", + "llcc_broadcast_base"; + interrupts = ; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + + interrupts = , + , + , + ; + }; +}; diff --git a/arch/arm64/boot/dts/renesas/draak.dtsi b/arch/arm64/boot/dts/renesas/draak.dtsi index ef3bb835d5c051..6f133f54ded54e 100644 --- a/arch/arm64/boot/dts/renesas/draak.dtsi +++ b/arch/arm64/boot/dts/renesas/draak.dtsi @@ -356,12 +356,9 @@ * CVBS and HDMI inputs through SW[49-53] * switches. * - * CVBS is the default selection, link it to - * VIN4 here. + * HDMI is the default selection, leave CVBS + * not connected here. */ - adv7180_out: endpoint { - remote-endpoint = <&vin4_in>; - }; }; }; @@ -374,6 +371,12 @@ interrupt-parent = <&gpio1>; interrupts = <28 IRQ_TYPE_LEVEL_LOW>; + avdd-supply = <®_1p8v>; + dvdd-supply = <®_1p8v>; + pvdd-supply = <®_1p8v>; + dvdd-3v-supply = <®_3p3v>; + bgvdd-supply = <®_1p8v>; + adi,input-depth = <8>; adi,input-colorspace = "rgb"; adi,input-clock = "1x"; @@ -423,13 +426,11 @@ * CVBS and HDMI inputs through SW[49-53] * switches. * - * CVBS is the default selection, leave HDMI - * not connected here. + * HDMI is the default selection, link it to + * VIN4 here. */ adv7612_out: endpoint { - pclk-sample = <0>; - hsync-active = <0>; - vsync-active = <0>; + remote-endpoint = <&vin4_in>; }; }; }; @@ -580,8 +581,8 @@ function = "usb0"; }; - vin4_pins_cvbs: vin4 { - groups = "vin4_data8", "vin4_sync", "vin4_clk"; + vin4_pins: vin4 { + groups = "vin4_data24", "vin4_sync", "vin4_clk"; function = "vin4"; }; }; @@ -729,7 +730,7 @@ }; &vin4 { - pinctrl-0 = <&vin4_pins_cvbs>; + pinctrl-0 = <&vin4_pins>; pinctrl-names = "default"; status = "okay"; @@ -737,7 +738,10 @@ ports { port { vin4_in: endpoint { - remote-endpoint = <&adv7180_out>; + pclk-sample = <0>; + hsync-active = <0>; + vsync-active = <0>; + remote-endpoint = <&adv7612_out>; }; }; }; diff --git a/arch/arm64/boot/dts/renesas/ebisu.dtsi b/arch/arm64/boot/dts/renesas/ebisu.dtsi index f1a5778ef11583..cba2fde9dd3688 100644 --- a/arch/arm64/boot/dts/renesas/ebisu.dtsi +++ b/arch/arm64/boot/dts/renesas/ebisu.dtsi @@ -403,6 +403,12 @@ interrupt-parent = <&gpio1>; interrupts = <1 IRQ_TYPE_LEVEL_LOW>; + avdd-supply = <®_1p8v>; + dvdd-supply = <®_1p8v>; + pvdd-supply = <®_1p8v>; + dvdd-3v-supply = <®_3p3v>; + bgvdd-supply = <®_1p8v>; + adi,input-depth = <8>; adi,input-colorspace = "rgb"; adi,input-clock = "1x"; diff --git a/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts b/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts index 405404c0843d97..0608dce92e4059 100644 --- a/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts +++ b/arch/arm64/boot/dts/renesas/r8a77970-eagle.dts @@ -29,6 +29,15 @@ stdout-path = "serial0:115200n8"; }; + d1p8: regulator-fixed { + compatible = "regulator-fixed"; + regulator-name = "fixed-1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + d3p3: regulator-fixed { compatible = "regulator-fixed"; regulator-name = "fixed-3.3V"; @@ -166,6 +175,12 @@ interrupt-parent = <&gpio1>; interrupts = <20 IRQ_TYPE_LEVEL_LOW>; + avdd-supply = <&d1p8>; + dvdd-supply = <&d1p8>; + pvdd-supply = <&d1p8>; + dvdd-3v-supply = <&d3p3>; + bgvdd-supply = <&d1p8>; + adi,input-depth = <8>; adi,input-colorspace = "rgb"; adi,input-clock = "1x"; diff --git a/arch/arm64/boot/dts/renesas/r8a779g0-white-hawk-cpu.dtsi b/arch/arm64/boot/dts/renesas/r8a779g0-white-hawk-cpu.dtsi index bb4a5270f71b6a..913f70fe6c5cd2 100644 --- a/arch/arm64/boot/dts/renesas/r8a779g0-white-hawk-cpu.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a779g0-white-hawk-cpu.dtsi @@ -187,6 +187,9 @@ }; &hscif0 { + pinctrl-0 = <&hscif0_pins>; + pinctrl-names = "default"; + status = "okay"; }; diff --git a/arch/arm64/boot/dts/renesas/r9a08g045.dtsi b/arch/arm64/boot/dts/renesas/r9a08g045.dtsi index 6c7b29b69d0e10..5facfad9615838 100644 --- a/arch/arm64/boot/dts/renesas/r9a08g045.dtsi +++ b/arch/arm64/boot/dts/renesas/r9a08g045.dtsi @@ -96,6 +96,7 @@ #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; + interrupt-parent = <&irqc>; gpio-ranges = <&pinctrl 0 0 152>; clocks = <&cpg CPG_MOD R9A08G045_GPIO_HCLK>; power-domains = <&cpg>; @@ -104,6 +105,73 @@ <&cpg R9A08G045_GPIO_SPARE_RESETN>; }; + irqc: interrupt-controller@11050000 { + compatible = "renesas,r9a08g045-irqc", "renesas,rzg2l-irqc"; + #interrupt-cells = <2>; + #address-cells = <0>; + interrupt-controller; + reg = <0 0x11050000 0 0x10000>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + interrupt-names = "nmi", + "irq0", "irq1", "irq2", "irq3", + "irq4", "irq5", "irq6", "irq7", + "tint0", "tint1", "tint2", "tint3", + "tint4", "tint5", "tint6", "tint7", + "tint8", "tint9", "tint10", "tint11", + "tint12", "tint13", "tint14", "tint15", + "tint16", "tint17", "tint18", "tint19", + "tint20", "tint21", "tint22", "tint23", + "tint24", "tint25", "tint26", "tint27", + "tint28", "tint29", "tint30", "tint31", + "bus-err"; + clocks = <&cpg CPG_MOD R9A08G045_IA55_CLK>, + <&cpg CPG_MOD R9A08G045_IA55_PCLK>; + clock-names = "clk", "pclk"; + power-domains = <&cpg>; + resets = <&cpg R9A08G045_IA55_RESETN>; + }; + sdhi0: mmc@11c00000 { compatible = "renesas,sdhi-r9a08g045", "renesas,rcar-gen3-sdhi"; reg = <0x0 0x11c00000 0 0x10000>; @@ -149,6 +217,44 @@ status = "disabled"; }; + eth0: ethernet@11c30000 { + compatible = "renesas,r9a08g045-gbeth", "renesas,rzg2l-gbeth"; + reg = <0 0x11c30000 0 0x10000>; + interrupts = , + , + ; + interrupt-names = "mux", "fil", "arp_ns"; + phy-mode = "rgmii"; + clocks = <&cpg CPG_MOD R9A08G045_ETH0_CLK_AXI>, + <&cpg CPG_MOD R9A08G045_ETH0_CLK_CHI>, + <&cpg CPG_MOD R9A08G045_ETH0_REFCLK>; + clock-names = "axi", "chi", "refclk"; + resets = <&cpg R9A08G045_ETH0_RST_HW_N>; + power-domains = <&cpg>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + eth1: ethernet@11c40000 { + compatible = "renesas,r9a08g045-gbeth", "renesas,rzg2l-gbeth"; + reg = <0 0x11c40000 0 0x10000>; + interrupts = , + , + ; + interrupt-names = "mux", "fil", "arp_ns"; + phy-mode = "rgmii"; + clocks = <&cpg CPG_MOD R9A08G045_ETH1_CLK_AXI>, + <&cpg CPG_MOD R9A08G045_ETH1_CLK_CHI>, + <&cpg CPG_MOD R9A08G045_ETH1_REFCLK>; + clock-names = "axi", "chi", "refclk"; + resets = <&cpg R9A08G045_ETH1_RST_HW_N>; + power-domains = <&cpg>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + gic: interrupt-controller@12400000 { compatible = "arm,gic-v3"; #interrupt-cells = <3>; diff --git a/arch/arm64/boot/dts/renesas/r9a09g011.dtsi b/arch/arm64/boot/dts/renesas/r9a09g011.dtsi index 33f2ecf424412f..50ed66d42a2453 100644 --- a/arch/arm64/boot/dts/renesas/r9a09g011.dtsi +++ b/arch/arm64/boot/dts/renesas/r9a09g011.dtsi @@ -163,7 +163,7 @@ }; avb: ethernet@a3300000 { - compatible = "renesas,etheravb-r9a09g011","renesas,etheravb-rzv2m"; + compatible = "renesas,etheravb-r9a09g011", "renesas,etheravb-rzv2m"; reg = <0 0xa3300000 0 0x800>; interrupts = , /* ch0: Rx0 BE */ , /* ch1: Rx1 NC */ diff --git a/arch/arm64/boot/dts/renesas/rzg2l-smarc-som.dtsi b/arch/arm64/boot/dts/renesas/rzg2l-smarc-som.dtsi index 547859c388ce4b..4409c47239b982 100644 --- a/arch/arm64/boot/dts/renesas/rzg2l-smarc-som.dtsi +++ b/arch/arm64/boot/dts/renesas/rzg2l-smarc-som.dtsi @@ -312,6 +312,7 @@ m25p,fast-read; spi-max-frequency = <50000000>; spi-rx-bus-width = <4>; + spi-tx-bus-width = <4>; partitions { compatible = "fixed-partitions"; diff --git a/arch/arm64/boot/dts/renesas/rzg2lc-smarc-som.dtsi b/arch/arm64/boot/dts/renesas/rzg2lc-smarc-som.dtsi index 56ff92453976fd..5e4209d6fb42f3 100644 --- a/arch/arm64/boot/dts/renesas/rzg2lc-smarc-som.dtsi +++ b/arch/arm64/boot/dts/renesas/rzg2lc-smarc-som.dtsi @@ -241,6 +241,7 @@ m25p,fast-read; spi-max-frequency = <50000000>; spi-rx-bus-width = <4>; + spi-tx-bus-width = <4>; partitions { compatible = "fixed-partitions"; diff --git a/arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi b/arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi index a199de8f8b0251..f062d4ad78b79d 100644 --- a/arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi +++ b/arch/arm64/boot/dts/renesas/rzg3s-smarc-som.dtsi @@ -9,18 +9,36 @@ #include /* - * Signals of SW_CONFIG switches: - * @SW_SD0_DEV_SEL: - * 0 - SD0 is connected to eMMC - * 1 - SD0 is connected to uSD0 card + * On-board switches' states: + * @SW_OFF: switch's state is OFF + * @SW_ON: switch's state is ON */ -#define SW_SD0_DEV_SEL 1 +#define SW_OFF 0 +#define SW_ON 1 + +/* + * SW_CONFIG[x] switches' states: + * @SW_CONFIG2: + * SW_OFF - SD0 is connected to eMMC + * SW_ON - SD0 is connected to uSD0 card + * @SW_CONFIG3: + * SW_OFF - SD2 is connected to SoC + * SW_ON - SCIF1, SSI0, IRQ0, IRQ1 connected to SoC + */ +#define SW_CONFIG2 SW_ON +#define SW_CONFIG3 SW_ON / { compatible = "renesas,rzg3s-smarcm", "renesas,r9a08g045s33", "renesas,r9a08g045"; aliases { mmc0 = &sdhi0; +#if SW_CONFIG3 == SW_OFF + mmc2 = &sdhi2; +#else + eth0 = ð0; + eth1 = ð1; +#endif }; chosen { @@ -43,7 +61,7 @@ enable-active-high; }; -#if SW_SD0_DEV_SEL +#if SW_CONFIG2 == SW_ON vccq_sdhi0: regulator1 { compatible = "regulator-gpio"; regulator-name = "SDHI0 VccQ"; @@ -63,13 +81,76 @@ regulator-always-on; }; #endif + + vcc_sdhi2: regulator2 { + compatible = "regulator-fixed"; + regulator-name = "SDHI2 Vcc"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpios = <&pinctrl RZG2L_GPIO(8, 1) GPIO_ACTIVE_HIGH>; + enable-active-high; + }; +}; + +#if SW_CONFIG3 == SW_ON +ð0 { + pinctrl-0 = <ð0_pins>; + pinctrl-names = "default"; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + status = "okay"; + + phy0: ethernet-phy@7 { + reg = <7>; + interrupt-parent = <&pinctrl>; + interrupts = ; + rxc-skew-psec = <0>; + txc-skew-psec = <0>; + rxdv-skew-psec = <0>; + txen-skew-psec = <0>; + rxd0-skew-psec = <0>; + rxd1-skew-psec = <0>; + rxd2-skew-psec = <0>; + rxd3-skew-psec = <0>; + txd0-skew-psec = <0>; + txd1-skew-psec = <0>; + txd2-skew-psec = <0>; + txd3-skew-psec = <0>; + }; +}; + +ð1 { + pinctrl-0 = <ð1_pins>; + pinctrl-names = "default"; + phy-handle = <&phy1>; + phy-mode = "rgmii-id"; + status = "okay"; + + phy1: ethernet-phy@7 { + reg = <7>; + interrupt-parent = <&pinctrl>; + interrupts = ; + rxc-skew-psec = <0>; + txc-skew-psec = <0>; + rxdv-skew-psec = <0>; + txen-skew-psec = <0>; + rxd0-skew-psec = <0>; + rxd1-skew-psec = <0>; + rxd2-skew-psec = <0>; + rxd3-skew-psec = <0>; + txd0-skew-psec = <0>; + txd1-skew-psec = <0>; + txd2-skew-psec = <0>; + txd3-skew-psec = <0>; + }; }; +#endif &extal_clk { clock-frequency = <24000000>; }; -#if SW_SD0_DEV_SEL +#if SW_CONFIG2 == SW_ON /* SD0 slot */ &sdhi0 { pinctrl-0 = <&sdhi0_pins>; @@ -100,7 +181,100 @@ }; #endif +#if SW_CONFIG3 == SW_OFF +&sdhi2 { + pinctrl-0 = <&sdhi2_pins>; + pinctrl-names = "default"; + vmmc-supply = <&vcc_sdhi2>; + bus-width = <4>; + max-frequency = <50000000>; + status = "okay"; +}; +#endif + &pinctrl { + eth0-phy-irq-hog { + gpio-hog; + gpios = ; + input; + line-name = "eth0-phy-irq"; + }; + + eth0_pins: eth0 { + txc { + pinmux = ; /* ET0_TXC */ + power-source = <1800>; + output-enable; + input-enable; + drive-strength-microamp = <5200>; + }; + + tx_ctl { + pinmux = ; /* ET0_TX_CTL */ + power-source = <1800>; + output-enable; + drive-strength-microamp = <5200>; + }; + + mux { + pinmux = , /* ET0_TXD0 */ + , /* ET0_TXD1 */ + , /* ET0_TXD2 */ + , /* ET0_TXD3 */ + , /* ET0_RXC */ + , /* ET0_RX_CTL */ + , /* ET0_RXD0 */ + , /* ET0_RXD1 */ + , /* ET0_RXD2 */ + , /* ET0_RXD3 */ + , /* ET0_MDC */ + , /* ET0_MDIO */ + ; /* ET0_LINKSTA */ + power-source = <1800>; + }; + }; + + eth1-phy-irq-hog { + gpio-hog; + gpios = ; + input; + line-name = "eth1-phy-irq"; + }; + + eth1_pins: eth1 { + txc { + pinmux = ; /* ET1_TXC */ + power-source = <1800>; + output-enable; + input-enable; + drive-strength-microamp = <5200>; + }; + + tx_ctl { + pinmux = ; /* ET1_TX_CTL */ + power-source = <1800>; + output-enable; + drive-strength-microamp = <5200>; + }; + + mux { + pinmux = , /* ET1_TXD0 */ + , /* ET1_TXD1 */ + , /* ET1_TXD2 */ + , /* ET1_TXD3 */ + , /* ET1_RXC */ + , /* ET1_RX_CTL */ + , /* ET1_RXD0 */ + , /* ET1_RXD1 */ + , /* ET1_RXD2 */ + , /* ET1_RXD3 */ + , /* ET1_MDC */ + , /* ET1_MDIO */ + ; /* ET1_LINKSTA */ + power-source = <1800>; + }; + }; + sdhi0_pins: sd0 { data { pins = "SD0_DATA0", "SD0_DATA1", "SD0_DATA2", "SD0_DATA3"; @@ -139,4 +313,26 @@ "SD0_CLK", "SD0_CMD", "SD0_RST#"; power-source = <1800>; }; + + sdhi2_pins: sd2 { + data { + pins = "P11_2", "P11_3", "P12_0", "P12_1"; + input-enable; + }; + + ctrl { + pins = "P11_1"; + input-enable; + }; + + mux { + pinmux = , /* SD2_CLK */ + , /* SD2_CMD */ + , /* SD2_DATA0 */ + , /* SD2_DATA1 */ + , /* SD2_DATA2 */ + , /* SD2_DATA3 */ + ; /* SD2_CD# */ + }; + }; }; diff --git a/arch/arm64/boot/dts/renesas/rzg3s-smarc.dtsi b/arch/arm64/boot/dts/renesas/rzg3s-smarc.dtsi index e7073a09ed2e25..21452013723084 100644 --- a/arch/arm64/boot/dts/renesas/rzg3s-smarc.dtsi +++ b/arch/arm64/boot/dts/renesas/rzg3s-smarc.dtsi @@ -11,6 +11,26 @@ / { aliases { serial0 = &scif0; + mmc1 = &sdhi1; + }; + + vcc_sdhi1: regulator-vcc-sdhi1 { + compatible = "regulator-fixed"; + regulator-name = "SDHI1 Vcc"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + gpios = <&pinctrl RZG2L_GPIO(2, 3) GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + vccq_sdhi1: regulator-vccq-sdhi1 { + compatible = "regulator-gpio"; + regulator-name = "SDHI1 VccQ"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + gpios = <&pinctrl RZG2L_GPIO(4, 2) GPIO_ACTIVE_HIGH>; + gpios-states = <1>; + states = <3300000 1>, <1800000 0>; }; }; @@ -19,6 +39,38 @@ pinmux = , /* RXD */ ; /* TXD */ }; + + sdhi1_pins: sd1 { + data { + pins = "SD1_DATA0", "SD1_DATA1", "SD1_DATA2", "SD1_DATA3"; + power-source = <3300>; + }; + + ctrl { + pins = "SD1_CLK", "SD1_CMD"; + power-source = <3300>; + }; + + cd { + pinmux = ; /* SD1_CD */ + }; + }; + + sdhi1_pins_uhs: sd1-uhs { + data { + pins = "SD1_DATA0", "SD1_DATA1", "SD1_DATA2", "SD1_DATA3"; + power-source = <1800>; + }; + + ctrl { + pins = "SD1_CLK", "SD1_CMD"; + power-source = <1800>; + }; + + cd { + pinmux = ; /* SD1_CD */ + }; + }; }; &scif0 { @@ -26,3 +78,16 @@ pinctrl-0 = <&scif0_pins>; status = "okay"; }; + +&sdhi1 { + pinctrl-0 = <&sdhi1_pins>; + pinctrl-1 = <&sdhi1_pins_uhs>; + pinctrl-names = "default", "state_uhs"; + vmmc-supply = <&vcc_sdhi1>; + vqmmc-supply = <&vccq_sdhi1>; + bus-width = <4>; + sd-uhs-sdr50; + sd-uhs-sdr104; + max-frequency = <125000000>; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile index a18f33bf0c0e99..a7b30e11beaf41 100644 --- a/arch/arm64/boot/dts/rockchip/Makefile +++ b/arch/arm64/boot/dts/rockchip/Makefile @@ -9,6 +9,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3308-roc-cc.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3308-rock-pi-s.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3318-a95x-z2.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3326-anbernic-rg351m.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3326-anbernic-rg351v.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3326-odroid-go2.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3326-odroid-go2-v11.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3326-odroid-go3.dtb @@ -78,6 +79,8 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-anbernic-rg503.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-pinenote-v1.1.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-pinenote-v1.2.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-powkiddy-rgb30.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-powkiddy-rk2023.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-powkiddy-x55.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-quartz64-a.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-quartz64-b.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3566-radxa-cm3-io.dtb @@ -98,14 +101,17 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-odroid-m1.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-radxa-e25.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-roc-pc.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-rock-3a.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-coolpi-cm5-evb.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-edgeble-neu6a-io.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-edgeble-neu6b-io.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-evb1-v10.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-jaguar.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-nanopc-t6.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-orangepi-5-plus.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-quartzpro64.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-rock-5b.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-turing-rk1.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-coolpi-4b.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-indiedroid-nova.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-khadas-edge2.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588s-rock-5a.dtb diff --git a/arch/arm64/boot/dts/rockchip/px30-engicam-common.dtsi b/arch/arm64/boot/dts/rockchip/px30-engicam-common.dtsi index 3429e124d95a21..5b4e223851659f 100644 --- a/arch/arm64/boot/dts/rockchip/px30-engicam-common.dtsi +++ b/arch/arm64/boot/dts/rockchip/px30-engicam-common.dtsi @@ -7,6 +7,7 @@ / { aliases { + ethernet0 = &gmac; mmc1 = &sdmmc; mmc2 = &sdio; }; diff --git a/arch/arm64/boot/dts/rockchip/px30-evb.dts b/arch/arm64/boot/dts/rockchip/px30-evb.dts index c1bbd555f5f5b2..0a90a88fc66497 100644 --- a/arch/arm64/boot/dts/rockchip/px30-evb.dts +++ b/arch/arm64/boot/dts/rockchip/px30-evb.dts @@ -14,6 +14,7 @@ compatible = "rockchip,px30-evb", "rockchip,px30"; aliases { + ethernet0 = &gmac; mmc0 = &sdmmc; mmc1 = &sdio; mmc2 = &emmc; diff --git a/arch/arm64/boot/dts/rockchip/px30-ringneck-haikou.dts b/arch/arm64/boot/dts/rockchip/px30-ringneck-haikou.dts index 7d4c5324c61bce..16798eb7707704 100644 --- a/arch/arm64/boot/dts/rockchip/px30-ringneck-haikou.dts +++ b/arch/arm64/boot/dts/rockchip/px30-ringneck-haikou.dts @@ -13,6 +13,7 @@ compatible = "tsd,px30-ringneck-haikou", "rockchip,px30"; aliases { + ethernet0 = &gmac; mmc2 = &sdmmc; }; diff --git a/arch/arm64/boot/dts/rockchip/px30.dtsi b/arch/arm64/boot/dts/rockchip/px30.dtsi index 42ce78beb4134d..d0905515399bb0 100644 --- a/arch/arm64/boot/dts/rockchip/px30.dtsi +++ b/arch/arm64/boot/dts/rockchip/px30.dtsi @@ -20,7 +20,6 @@ #size-cells = <2>; aliases { - ethernet0 = &gmac; i2c0 = &i2c0; i2c1 = &i2c1; i2c2 = &i2c2; diff --git a/arch/arm64/boot/dts/rockchip/rk3308-rock-pi-s.dts b/arch/arm64/boot/dts/rockchip/rk3308-rock-pi-s.dts index e9810d2f04071c..b47fe02c33fbdc 100644 --- a/arch/arm64/boot/dts/rockchip/rk3308-rock-pi-s.dts +++ b/arch/arm64/boot/dts/rockchip/rk3308-rock-pi-s.dts @@ -143,6 +143,68 @@ status = "okay"; }; +&gpio0 { + gpio-line-names = + /* GPIO0_A0 - A7 */ + "", "", "", "", "", "", "", "", + /* GPIO0_B0 - B7 */ + "", "", "", "header1-pin3 [GPIO0_B3]", + "header1-pin5 [GPIO0_B4]", "", "", + "header1-pin11 [GPIO0_B7]", + /* GPIO0_C0 - C7 */ + "header1-pin13 [GPIO0_C0]", + "header1-pin15 [GPIO0_C1]", "", "", "", + "", "", "", + /* GPIO0_D0 - D7 */ + "", "", "", "", "", "", "", ""; +}; + +&gpio1 { + gpio-line-names = + /* GPIO1_A0 - A7 */ + "", "", "", "", "", "", "", "", + /* GPIO1_B0 - B7 */ + "", "", "", "", "", "", "", "", + /* GPIO1_C0 - C7 */ + "", "", "", "", "", "", "header1-pin21 [GPIO1_C6]", + "header1-pin19 [GPIO1_C7]", + /* GPIO1_D0 - D7 */ + "header1-pin23 [GPIO1_D0]", "header1-pin24 [GPIO1_D1]", + "", "", "", "", "", ""; +}; + +&gpio2 { + gpio-line-names = + /* GPIO2_A0 - A7 */ + "header1-pin10 [GPIO2_A0]", "header1-pin8 [GPIO2_A1]", + "", "", + "header1-pin7 [GPIO2_A4]", "header1-pin12 [GPIO2_A5]", + "header2-pin46 [GPIO2_A6]", "header1-pin22 [GPIO1_A7]", + /* GPIO2_B0 - B7 */ + "header2-pin45 [GPIO2_B0]", "header1-pin18 [GPIO2_B1]", + "header1-pin16 [GPIO2_B2]", "header2-pin44 [GPIO2_B3]", + "header2-pin43 [GPIO2_B4]", "header2-pin28 [GPIO2_B5]", + "header2-pin30 [GPIO2_B6]", "header2-pin32 [GPIO2_B7]", + /* GPIO2_C0 - C7 */ + "header2-pin34 [GPIO2_C0]", "", "", "", "", "", "", "", + /* GPIO2_D0 - D7 */ + "", "", "", "", "", "", "", ""; +}; + +&gpio3 { + gpio-line-names = + /* GPIO3_A0 - A7 */ + "", "", "", "", "", "", "", "", + /* GPIO3_B0 - B7 */ + "", "", "header2-pin42 [GPIO3_B2]", + "header2-pin41 [GPIO3_B3]", "header2-pin40 [GPIO3_B4]", + "header2-pin39 [GPIO3_B5]", "", "", + /* GPIO3_C0 - C7 */ + "", "", "", "", "", "", "", "", + /* GPIO3_D0 - D7 */ + "", "", "", "", "", "", "", ""; +}; + &i2c1 { status = "okay"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3308.dtsi b/arch/arm64/boot/dts/rockchip/rk3308.dtsi index 2ae4bb7d5e62a3..cfc0a87b519593 100644 --- a/arch/arm64/boot/dts/rockchip/rk3308.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3308.dtsi @@ -20,6 +20,11 @@ #size-cells = <2>; aliases { + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; + gpio4 = &gpio4; i2c0 = &i2c0; i2c1 = &i2c1; i2c2 = &i2c2; diff --git a/arch/arm64/boot/dts/rockchip/rk3318-a95x-z2.dts b/arch/arm64/boot/dts/rockchip/rk3318-a95x-z2.dts index 1deef53a4c9407..c7b1862fca6a0f 100644 --- a/arch/arm64/boot/dts/rockchip/rk3318-a95x-z2.dts +++ b/arch/arm64/boot/dts/rockchip/rk3318-a95x-z2.dts @@ -9,6 +9,7 @@ compatible = "zkmagic,a95x-z2", "rockchip,rk3318"; aliases { + ethernet0 = &gmac2phy; mmc0 = &sdmmc; mmc1 = &sdio; mmc2 = &emmc; diff --git a/arch/arm64/boot/dts/rockchip/rk3326-anbernic-rg351m.dts b/arch/arm64/boot/dts/rockchip/rk3326-anbernic-rg351m.dts index ce318e05f0a60a..f4d20f29c1b47b 100644 --- a/arch/arm64/boot/dts/rockchip/rk3326-anbernic-rg351m.dts +++ b/arch/arm64/boot/dts/rockchip/rk3326-anbernic-rg351m.dts @@ -6,30 +6,16 @@ */ /dts-v1/; -#include "rk3326-odroid-go.dtsi" +#include "rk3326-anbernic-rg351m.dtsi" / { model = "Anbernic RG351M"; compatible = "anbernic,rg351m", "rockchip,rk3326"; - - vibrator { - compatible = "pwm-vibrator"; - pwms = <&pwm0 0 1000000 0>; - pwm-names = "enable"; - }; }; -/delete-node/ &builtin_gamepad; -/delete-node/ &vcc_host; /* conflicts with pwm vibration motor */ - &internal_display { compatible = "elida,kd35t133"; iovcc-supply = <&vcc_lcd>; + rotation = <270>; vdd-supply = <&vcc_lcd>; }; - -&pwm0 { - status = "okay"; -}; - -/delete-node/ &rk817_charger; diff --git a/arch/arm64/boot/dts/rockchip/rk3326-anbernic-rg351m.dtsi b/arch/arm64/boot/dts/rockchip/rk3326-anbernic-rg351m.dtsi new file mode 100644 index 00000000000000..b6d041dbed94af --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3326-anbernic-rg351m.dtsi @@ -0,0 +1,478 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2019 Hardkernel Co., Ltd + * Copyright (c) 2020 Theobroma Systems Design und Consulting GmbH + * Copyright (c) 2022 Maya Matuszczyk + */ + +/dts-v1/; +#include +#include +#include +#include +#include "rk3326.dtsi" + +/ { + aliases { + mmc0 = &sdmmc; + }; + + chosen { + stdout-path = "serial2:115200n8"; + }; + + backlight: backlight { + compatible = "pwm-backlight"; + power-supply = <&vcc_bl>; + pwms = <&pwm1 0 25000 0>; + }; + + /* + * LED is a tri-state. Driven high it is red, driven low it is + * green, and not driven at all (pin set to input) it is amber. + * Additionally, there is a 2nd LED that is not controllable + * that is on (red) when plugged in to power. + */ + gpio_led: gpio-leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&led_pin>; + + red_green_led: led-0 { + color = ; + gpios = <&gpio2 RK_PB5 GPIO_ACTIVE_HIGH>; + function = LED_FUNCTION_CHARGING; + }; + }; + + rk817-sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "rk817_int"; + simple-audio-card,format = "i2s"; + simple-audio-card,hp-det-gpio = <&gpio2 RK_PC6 GPIO_ACTIVE_HIGH>; + simple-audio-card,mclk-fs = <256>; + simple-audio-card,widgets = + "Microphone", "Mic Jack", + "Headphone", "Headphones", + "Speaker", "Speaker"; + simple-audio-card,routing = + "MICL", "Mic Jack", + "Headphones", "HPOL", + "Headphones", "HPOR", + "Speaker", "SPKO"; + + simple-audio-card,codec { + sound-dai = <&rk817>; + }; + + simple-audio-card,cpu { + sound-dai = <&i2s1_2ch>; + }; + }; + + vccsys: vccsys { + compatible = "regulator-fixed"; + regulator-name = "vcc3v8_sys"; + regulator-always-on; + regulator-min-microvolt = <3800000>; + regulator-max-microvolt = <3800000>; + }; + + vibrator { + compatible = "pwm-vibrator"; + pwms = <&pwm0 0 1000000 0>; + pwm-names = "enable"; + }; +}; + +&cpu0 { + cpu-supply = <&vdd_arm>; +}; + +&cpu1 { + cpu-supply = <&vdd_arm>; +}; + +&cpu2 { + cpu-supply = <&vdd_arm>; +}; + +&cpu3 { + cpu-supply = <&vdd_arm>; +}; + +&cru { + assigned-clocks = <&cru PLL_NPLL>, + <&cru ACLK_BUS_PRE>, <&cru ACLK_PERI_PRE>, + <&cru HCLK_BUS_PRE>, <&cru HCLK_PERI_PRE>, + <&cru PCLK_BUS_PRE>, <&cru SCLK_GPU>; + + assigned-clock-rates = <1188000000>, + <200000000>, <200000000>, + <150000000>, <150000000>, + <100000000>, <200000000>; +}; + +&display_subsystem { + status = "okay"; +}; + +&dsi { + status = "okay"; + + ports { + mipi_out: port@1 { + reg = <1>; + + mipi_out_panel: endpoint { + remote-endpoint = <&mipi_in_panel>; + }; + }; + }; + + internal_display: panel@0 { + reg = <0>; + backlight = <&backlight>; + reset-gpios = <&gpio3 RK_PC0 GPIO_ACTIVE_LOW>; + + port { + mipi_in_panel: endpoint { + remote-endpoint = <&mipi_out_panel>; + }; + }; + }; +}; + +&dsi_dphy { + status = "okay"; +}; + +&gpu { + mali-supply = <&vdd_logic>; + status = "okay"; +}; + +&i2c0 { + clock-frequency = <400000>; + i2c-scl-falling-time-ns = <16>; + i2c-scl-rising-time-ns = <280>; + status = "okay"; + + rk817: pmic@20 { + compatible = "rockchip,rk817"; + reg = <0x20>; + #clock-cells = <1>; + clock-names = "mclk"; + clock-output-names = "rk808-clkout1", "xin32k"; + clocks = <&cru SCLK_I2S1_OUT>; + interrupt-parent = <&gpio0>; + interrupts = ; + pinctrl-0 = <&pmic_int>, <&i2s1_2ch_mclk>; + pinctrl-names = "default"; + #sound-dai-cells = <0>; + wakeup-source; + + vcc1-supply = <&vccsys>; + vcc2-supply = <&vccsys>; + vcc3-supply = <&vccsys>; + vcc4-supply = <&vccsys>; + vcc5-supply = <&vccsys>; + vcc6-supply = <&vccsys>; + vcc7-supply = <&vccsys>; + vcc8-supply = <&vccsys>; + + regulators { + vdd_logic: DCDC_REG1 { + regulator-always-on; + regulator-boot-on; + regulator-max-microvolt = <1150000>; + regulator-min-microvolt = <950000>; + regulator-name = "vdd_logic"; + regulator-ramp-delay = <6001>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <950000>; + }; + }; + + vdd_arm: DCDC_REG2 { + regulator-always-on; + regulator-boot-on; + regulator-max-microvolt = <1350000>; + regulator-min-microvolt = <950000>; + regulator-name = "vdd_arm"; + regulator-ramp-delay = <6001>; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <950000>; + }; + }; + + vcc_ddr: DCDC_REG3 { + regulator-always-on; + regulator-boot-on; + regulator-name = "vcc_ddr"; + + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vcc_3v3: DCDC_REG4 { + regulator-always-on; + regulator-boot-on; + regulator-max-microvolt = <3300000>; + regulator-min-microvolt = <3300000>; + regulator-name = "vcc_3v3"; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vcc_1v8: LDO_REG2 { + regulator-always-on; + regulator-boot-on; + regulator-max-microvolt = <1800000>; + regulator-min-microvolt = <1800000>; + regulator-name = "vcc_1v8"; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vdd_1v0: LDO_REG3 { + regulator-always-on; + regulator-boot-on; + regulator-max-microvolt = <1000000>; + regulator-min-microvolt = <1000000>; + regulator-name = "vdd_1v0"; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1000000>; + }; + }; + + vcc3v3_pmu: LDO_REG4 { + regulator-always-on; + regulator-boot-on; + regulator-max-microvolt = <3300000>; + regulator-min-microvolt = <3300000>; + regulator-name = "vcc3v3_pmu"; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vccio_sd: LDO_REG5 { + regulator-always-on; + regulator-boot-on; + regulator-max-microvolt = <3300000>; + regulator-min-microvolt = <1800000>; + regulator-name = "vccio_sd"; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vcc_sd: LDO_REG6 { + regulator-boot-on; + regulator-max-microvolt = <3300000>; + regulator-min-microvolt = <3300000>; + regulator-name = "vcc_sd"; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vcc_bl: LDO_REG7 { + regulator-max-microvolt = <3300000>; + regulator-min-microvolt = <3300000>; + regulator-name = "vcc_bl"; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vcc_lcd: LDO_REG8 { + regulator-max-microvolt = <2800000>; + regulator-min-microvolt = <2800000>; + regulator-name = "vcc_lcd"; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <2800000>; + }; + }; + + vcc_wifi: LDO_REG9 { + regulator-max-microvolt = <3300000>; + regulator-min-microvolt = <3300000>; + regulator-name = "vcc_wifi"; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + usb_midu: BOOST { + regulator-always-on; + regulator-boot-on; + regulator-max-microvolt = <5400000>; + regulator-min-microvolt = <5000000>; + regulator-name = "usb_midu"; + }; + }; + + rk817_codec: codec { + rockchip,mic-in-differential; + }; + }; +}; + +&i2s1_2ch { + status = "okay"; +}; + +&io_domains { + vccio1-supply = <&vcc_3v3>; + vccio2-supply = <&vccio_sd>; + vccio3-supply = <&vcc_3v3>; + vccio4-supply = <&vcc_3v3>; + vccio5-supply = <&vcc_3v3>; + vccio6-supply = <&vcc_3v3>; + status = "okay"; +}; + +&pmu_io_domains { + pmuio1-supply = <&vcc3v3_pmu>; + pmuio2-supply = <&vcc3v3_pmu>; + status = "okay"; +}; + +&pwm0 { + status = "okay"; +}; + +&pwm1 { + status = "okay"; +}; + +&saradc { + vref-supply = <&vcc_1v8>; + status = "okay"; +}; + +&sdmmc { + cap-sd-highspeed; + card-detect-delay = <200>; + cd-gpios = <&gpio0 RK_PA3 GPIO_ACTIVE_LOW>; + sd-uhs-sdr12; + sd-uhs-sdr25; + sd-uhs-sdr50; + sd-uhs-sdr104; + vmmc-supply = <&vcc_sd>; + vqmmc-supply = <&vccio_sd>; + status = "okay"; +}; + +&sfc { + #address-cells = <1>; + pinctrl-0 = <&sfc_clk &sfc_cs0 &sfc_bus2>; + pinctrl-names = "default"; + #size-cells = <0>; + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + spi-max-frequency = <108000000>; + spi-rx-bus-width = <2>; + spi-tx-bus-width = <1>; + }; +}; + +&tsadc { + status = "okay"; +}; + +&u2phy { + status = "okay"; + + u2phy_host: host-port { + status = "okay"; + }; + + u2phy_otg: otg-port { + status = "disabled"; + }; +}; + +&usb20_otg { + status = "okay"; +}; + +&uart2 { + pinctrl-0 = <&uart2m1_xfer>; + pinctrl-names = "default"; + status = "okay"; +}; + +&vopb { + status = "okay"; +}; + +&vopb_mmu { + status = "okay"; +}; + +&pinctrl { + headphone { + hp_det: hp-det { + rockchip,pins = <2 RK_PC6 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; + + leds { + led_pin: led-pin { + rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + pmic { + dc_det: dc-det { + rockchip,pins = <0 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + pmic_int: pmic-int { + rockchip,pins = <0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + soc_slppin_gpio: soc_slppin_gpio { + rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_output_low>; + }; + + soc_slppin_rst: soc_slppin_rst { + rockchip,pins = <0 RK_PA4 2 &pcfg_pull_none>; + }; + + soc_slppin_slp: soc_slppin_slp { + rockchip,pins = <0 RK_PA4 1 &pcfg_pull_none>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3326-anbernic-rg351v.dts b/arch/arm64/boot/dts/rockchip/rk3326-anbernic-rg351v.dts new file mode 100644 index 00000000000000..c79f7a7b38cb45 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3326-anbernic-rg351v.dts @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +/dts-v1/; +#include "rk3326-anbernic-rg351m.dtsi" + +/ { + model = "Anbernic RG351V"; + compatible = "anbernic,rg351v", "rockchip,rk3326"; + + gpio_keys_vol: gpio-keys-vol { + compatible = "gpio-keys"; + autorepeat; + + button-vol-down { + gpios = <&gpio2 RK_PA1 GPIO_ACTIVE_LOW>; + label = "VOLUMEDOWN"; + linux,code = ; + }; + + button-vol-up { + gpios = <&gpio2 RK_PA0 GPIO_ACTIVE_LOW>; + label = "VOLUMEUP"; + linux,code = ; + }; + }; +}; + +&internal_display { + compatible = "anbernic,rg351v-panel", "newvision,nv3051d"; + vdd-supply = <&vcc_lcd>; +}; + +&io_domains { + vccio1-supply = <&vccio_sd>; +}; + +&vcc_sd { + regulator-max-microvolt = <3000000>; + regulator-min-microvolt = <1800000>; +}; + +&vccio_sd { + regulator-max-microvolt = <1800000>; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-a1.dts b/arch/arm64/boot/dts/rockchip/rk3328-a1.dts index 40bf808642b91f..824183e515da64 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-a1.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-a1.dts @@ -9,6 +9,7 @@ compatible = "azw,beelink-a1", "rockchip,rk3328"; aliases { + ethernet0 = &gmac2io; mmc0 = &sdmmc; mmc1 = &emmc; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-evb.dts b/arch/arm64/boot/dts/rockchip/rk3328-evb.dts index ff6b466e0e0744..1eef5504445fa9 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-evb.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-evb.dts @@ -11,6 +11,7 @@ compatible = "rockchip,rk3328-evb", "rockchip,rk3328"; aliases { + ethernet0 = &gmac2phy; mmc0 = &sdmmc; mmc1 = &sdio; mmc2 = &emmc; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s.dts b/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s.dts index 1445b879ac7abd..a4399da7d8b1ad 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-nanopi-r2s.dts @@ -14,6 +14,7 @@ compatible = "friendlyarm,nanopi-r2s", "rockchip,rk3328"; aliases { + ethernet0 = &gmac2io; ethernet1 = &rtl8153; mmc0 = &sdmmc; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-orangepi-r1-plus-lts.dts b/arch/arm64/boot/dts/rockchip/rk3328-orangepi-r1-plus-lts.dts index 5d7d567283e525..4237f2ee8fee33 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-orangepi-r1-plus-lts.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-orangepi-r1-plus-lts.dts @@ -26,9 +26,11 @@ compatible = "ethernet-phy-ieee802.3-c22"; reg = <0>; + motorcomm,auto-sleep-disabled; motorcomm,clk-out-frequency-hz = <125000000>; motorcomm,keep-pll-enabled; - motorcomm,auto-sleep-disabled; + motorcomm,rx-clk-drv-microamp = <5020>; + motorcomm,rx-data-drv-microamp = <5020>; pinctrl-0 = <ð_phy_reset_pin>; pinctrl-names = "default"; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-orangepi-r1-plus.dts b/arch/arm64/boot/dts/rockchip/rk3328-orangepi-r1-plus.dts index dc83d74045a3c1..f20662929c7713 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-orangepi-r1-plus.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-orangepi-r1-plus.dts @@ -15,6 +15,7 @@ compatible = "xunlong,orangepi-r1-plus", "rockchip,rk3328"; aliases { + ethernet0 = &gmac2io; ethernet1 = &rtl8153; mmc0 = &sdmmc; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts index 5d5d9574088cab..414897a57e7570 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-roc-cc.dts @@ -11,6 +11,7 @@ compatible = "firefly,roc-rk3328-cc", "rockchip,rk3328"; aliases { + ethernet0 = &gmac2io; mmc0 = &sdmmc; mmc1 = &emmc; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts b/arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts index 018a3a5075c72e..3cda6c627b681e 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-rock-pi-e.dts @@ -21,6 +21,8 @@ compatible = "radxa,rockpi-e", "rockchip,rk3328"; aliases { + ethernet0 = &gmac2io; + ethernet1 = &gmac2phy; mmc0 = &sdmmc; mmc1 = &emmc; }; @@ -180,6 +182,59 @@ status = "okay"; }; +&gpio0 { + gpio-line-names = + /* GPIO0_A0 - A7 */ + "", "", "", "", "", "", "", "", + /* GPIO0_B0 - B7 */ + "", "", "", "", "", "", "", "", + /* GPIO0_C0 - C7 */ + "", "", "", "", "", "", "", "", + /* GPIO0_D0 - D7 */ + "", "", "", "pin-15 [GPIO0_D3]", "", "", "", ""; +}; + +&gpio1 { + gpio-line-names = + /* GPIO1_A0 - A7 */ + "", "", "", "", "", "", "", "", + /* GPIO1_B0 - B7 */ + "", "", "", "", "", "", "", "", + /* GPIO1_C0 - C7 */ + "", "", "", "", "", "", "", "", + /* GPIO1_D0 - D7 */ + "", "", "", "", "pin-07 [GPIO1_D4]", "", "", ""; +}; + +&gpio2 { + gpio-line-names = + /* GPIO2_A0 - A7 */ + "pin-08 [GPIO2_A0]", "pin-10 [GPIO2_A1]", "pin-11 [GPIO2_A2]", + "pin-13 [GPIO2-A3]", "pin-27 [GPIO2_A4]", "pin-28 [GPIO2_A5]", + "pin-33 [GPIO2_A6]", "", + /* GPIO2_B0 - B7 */ + "", "", "", "", "pin-26 [GPIO2_B4]", "", "", "pin-36 [GPIO2_B7]", + /* GPIO2_C0 - C7 */ + "pin-32 [GPIO2_C0]", "pin-35 [GPIO2_C1]", "pin-12 [GPIO2_C2]", + "pin-38 [GPIO2_C3]", "pin-29 [GPIO2_C4]", "pin-31 [GPIO2_C5]", + "pin-37 [GPIO2_C6]", "pin-40 [GPIO2_C7]", + /* GPIO2_D0 - D7 */ + "", "", "", "", "", "", "", ""; +}; + +&gpio3 { + gpio-line-names = + /* GPIO3_A0 - A7 */ + "pin-23 [GPIO3_A0]", "pin-19 [GPIO3_A1]", "pin-21 [GPIO3_A2]", + "", "pin-03 [GPIO3_A4]", "", "pin-05 [GPIO3_A6]", "", + /* GPIO3_B0 - B7 */ + "pin-24 [GPIO3_B0]", "", "", "", "", "", "", "", + /* GPIO3_C0 - C7 */ + "", "", "", "", "", "", "", "", + /* GPIO3_D0 - D7 */ + "", "", "", "", "", "", "", ""; +}; + &i2c1 { status = "okay"; diff --git a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts index 0a27fa5271f576..229fe9da9c2ddc 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts +++ b/arch/arm64/boot/dts/rockchip/rk3328-rock64.dts @@ -11,6 +11,7 @@ compatible = "pine64,rock64", "rockchip,rk3328"; aliases { + ethernet0 = &gmac2io; mmc0 = &sdmmc; mmc1 = &emmc; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi index cc8209795c3e53..fb5dcf6e932721 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi @@ -20,6 +20,10 @@ #size-cells = <2>; aliases { + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; serial0 = &uart0; serial1 = &uart1; serial2 = &uart2; @@ -27,8 +31,6 @@ i2c1 = &i2c1; i2c2 = &i2c2; i2c3 = &i2c3; - ethernet0 = &gmac2io; - ethernet1 = &gmac2phy; }; cpus { @@ -916,6 +918,8 @@ resets = <&cru SRST_GMAC2IO_A>; reset-names = "stmmaceth"; rockchip,grf = <&grf>; + tx-fifo-depth = <2048>; + rx-fifo-depth = <4096>; snps,txpbl = <0x4>; status = "disabled"; }; @@ -938,6 +942,8 @@ reset-names = "stmmaceth"; phy-mode = "rmii"; phy-handle = <&phy>; + tx-fifo-depth = <2048>; + rx-fifo-depth = <4096>; snps,txpbl = <0x4>; clock_in_out = "output"; status = "disabled"; diff --git a/arch/arm64/boot/dts/rockchip/rk3368-evb.dtsi b/arch/arm64/boot/dts/rockchip/rk3368-evb.dtsi index e47d1398aecac7..b48b98c13705c3 100644 --- a/arch/arm64/boot/dts/rockchip/rk3368-evb.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3368-evb.dtsi @@ -9,6 +9,7 @@ / { aliases { + ethernet0 = &gmac; mmc0 = &emmc; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3368-geekbox.dts b/arch/arm64/boot/dts/rockchip/rk3368-geekbox.dts index be06e6e64d1831..029b8e22e709ff 100644 --- a/arch/arm64/boot/dts/rockchip/rk3368-geekbox.dts +++ b/arch/arm64/boot/dts/rockchip/rk3368-geekbox.dts @@ -12,6 +12,7 @@ compatible = "geekbuying,geekbox", "rockchip,rk3368"; aliases { + ethernet0 = &gmac; mmc0 = &emmc; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi b/arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi index 5753e57fd7161f..8ac8acf4082df4 100644 --- a/arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3368-lion.dtsi @@ -8,6 +8,7 @@ / { aliases { + ethernet0 = &gmac; mmc0 = &emmc; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3368-orion-r68-meta.dts b/arch/arm64/boot/dts/rockchip/rk3368-orion-r68-meta.dts index 81d1064fdb2154..dcee2e28916f71 100644 --- a/arch/arm64/boot/dts/rockchip/rk3368-orion-r68-meta.dts +++ b/arch/arm64/boot/dts/rockchip/rk3368-orion-r68-meta.dts @@ -12,6 +12,7 @@ compatible = "tronsmart,orion-r68-meta", "rockchip,rk3368"; aliases { + ethernet0 = &gmac; mmc0 = &sdmmc; mmc1 = &emmc; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3368-r88.dts b/arch/arm64/boot/dts/rockchip/rk3368-r88.dts index 5589f3db6b36b4..b16b7ca02379a8 100644 --- a/arch/arm64/boot/dts/rockchip/rk3368-r88.dts +++ b/arch/arm64/boot/dts/rockchip/rk3368-r88.dts @@ -12,6 +12,7 @@ compatible = "rockchip,r88", "rockchip,rk3368"; aliases { + ethernet0 = &gmac; mmc0 = &sdio0; mmc1 = &emmc; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3368.dtsi b/arch/arm64/boot/dts/rockchip/rk3368.dtsi index a4c5aaf1f45794..62af0cb94839bb 100644 --- a/arch/arm64/boot/dts/rockchip/rk3368.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3368.dtsi @@ -19,7 +19,10 @@ #size-cells = <2>; aliases { - ethernet0 = &gmac; + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; i2c0 = &i2c0; i2c1 = &i2c1; i2c2 = &i2c2; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-eaidk-610.dts b/arch/arm64/boot/dts/rockchip/rk3399-eaidk-610.dts index 6464ef4d113ddd..173da81fc23117 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-eaidk-610.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-eaidk-610.dts @@ -15,6 +15,7 @@ compatible = "openailab,eaidk-610", "rockchip,rk3399"; aliases { + ethernet0 = &gmac; mmc0 = &sdio0; mmc1 = &sdmmc; mmc2 = &sdhci; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts index 3d1e126b553f93..55eca7a50a1f54 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts @@ -12,6 +12,7 @@ compatible = "rockchip,rk3399-evb", "rockchip,rk3399"; aliases { + ethernet0 = &gmac; mmc0 = &sdhci; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-ficus.dts b/arch/arm64/boot/dts/rockchip/rk3399-ficus.dts index 1ce85a5816e451..30e4879f322c5d 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-ficus.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-ficus.dts @@ -13,6 +13,10 @@ model = "96boards RK3399 Ficus"; compatible = "vamrs,ficus", "rockchip,rk3399"; + aliases { + ethernet0 = &gmac; + }; + chosen { stdout-path = "serial2:1500000n8"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts b/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts index c5db64f3e12413..260415d99aebf8 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts @@ -16,6 +16,7 @@ compatible = "firefly,firefly-rk3399", "rockchip,rk3399"; aliases { + ethernet0 = &gmac; mmc0 = &sdio0; mmc1 = &sdmmc; mmc2 = &sdhci; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-bob.dts b/arch/arm64/boot/dts/rockchip/rk3399-gru-bob.dts index 0f9cc042d9bf06..1cba1d857c96ba 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-gru-bob.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-bob.dts @@ -70,7 +70,7 @@ &spi0 { status = "okay"; - cr50@0 { + tpm@0 { compatible = "google,cr50"; reg = <0>; interrupt-parent = <&gpio0>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi index c5e7de60c12140..5846a11f0e848f 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi @@ -706,7 +706,7 @@ camera: &i2c7 { &spi2 { status = "okay"; - cr50@0 { + tpm@0 { compatible = "google,cr50"; reg = <0>; interrupt-parent = <&gpio1>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-hugsun-x99.dts b/arch/arm64/boot/dts/rockchip/rk3399-hugsun-x99.dts index 7af27e8216f1b3..4a6ab6c2e24cff 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-hugsun-x99.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-hugsun-x99.dts @@ -11,6 +11,7 @@ compatible = "hugsun,x99", "rockchip,rk3399"; aliases { + ethernet0 = &gmac; mmc0 = &sdio0; mmc1 = &sdmmc; mmc2 = &sdhci; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge-captain.dts b/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge-captain.dts index 8302e51def52a3..99ac4ed0f13f6f 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge-captain.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge-captain.dts @@ -10,6 +10,10 @@ / { model = "Khadas Edge-Captain"; compatible = "khadas,edge-captain", "rockchip,rk3399"; + + aliases { + ethernet0 = &gmac; + }; }; &gmac { diff --git a/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge-v.dts b/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge-v.dts index f5dcb99dc3495a..e12e7b4d64ca17 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge-v.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-khadas-edge-v.dts @@ -10,6 +10,10 @@ / { model = "Khadas Edge-V"; compatible = "khadas,edge-v", "rockchip,rk3399"; + + aliases { + ethernet0 = &gmac; + }; }; &gmac { diff --git a/arch/arm64/boot/dts/rockchip/rk3399-kobol-helios64.dts b/arch/arm64/boot/dts/rockchip/rk3399-kobol-helios64.dts index 1eb287a3f8c03e..9e3aec4440bd65 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-kobol-helios64.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-kobol-helios64.dts @@ -19,6 +19,7 @@ compatible = "kobol,helios64", "rockchip,rk3399"; aliases { + ethernet0 = &gmac; mmc0 = &sdmmc; mmc1 = &sdhci; spi1 = &spi1; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts b/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts index a21ac319f809fe..cb69e2145fa940 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-leez-p710.dts @@ -15,6 +15,7 @@ compatible = "leez,p710", "rockchip,rk3399"; aliases { + ethernet0 = &gmac; mmc0 = &sdio0; mmc1 = &sdmmc; mmc2 = &sdhci; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi index 7c5f441a2219ee..b7f1e47978a69e 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-nanopi4.dtsi @@ -18,6 +18,7 @@ / { aliases { + ethernet0 = &gmac; mmc0 = &sdio0; mmc1 = &sdmmc; mmc2 = &sdhci; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts b/arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts index dba4d03bfc2b84..e7551449e718ca 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-orangepi.dts @@ -17,6 +17,7 @@ compatible = "rockchip,rk3399-orangepi", "rockchip,rk3399"; aliases { + ethernet0 = &gmac; mmc0 = &sdio0; mmc1 = &sdmmc; mmc2 = &sdhci; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts b/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts index 115c14c0a3c68c..18a98c4648eae7 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts @@ -5,6 +5,7 @@ /dts-v1/; #include "rk3399-puma.dtsi" +#include / { model = "Theobroma Systems RK3399-Q7 SoM"; @@ -18,6 +19,38 @@ stdout-path = "serial0:115200n8"; }; + gpio-keys { + compatible = "gpio-keys"; + pinctrl-0 = <&haikou_keys_pin>; + pinctrl-names = "default"; + + button-batlow-n { + gpios = <&gpio0 RK_PB2 GPIO_ACTIVE_LOW>; + label = "BATLOW#"; + linux,code = ; + }; + + button-slp-btn-n { + gpios = <&gpio0 RK_PB3 GPIO_ACTIVE_LOW>; + label = "SLP_BTN#"; + linux,code = ; + }; + + button-wake-n { + gpios = <&gpio0 RK_PB1 GPIO_ACTIVE_LOW>; + label = "WAKE#"; + linux,code = ; + wakeup-source; + }; + + switch-lid-btn-n { + gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>; + label = "LID_BTN#"; + linux,code = ; + linux,input-type = ; + }; + }; + leds { pinctrl-0 = <&module_led_pin>, <&sd_card_led_pin>; @@ -165,11 +198,8 @@ }; &pinctrl { - pinctrl-names = "default"; - pinctrl-0 = <&haikou_pin_hog>; - - hog { - haikou_pin_hog: haikou-pin-hog { + buttons { + haikou_keys_pin: haikou-keys-pin { rockchip,pins = /* LID_BTN */ <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>, @@ -177,7 +207,7 @@ <0 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>, /* SLP_BTN# */ <0 RK_PB3 RK_FUNC_GPIO &pcfg_pull_up>, - /* BIOS_DISABLE# */ + /* WAKE# */ <0 RK_PB1 RK_FUNC_GPIO &pcfg_pull_up>; }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi index 20e3f41efe97fa..c08e69391c0154 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi @@ -9,6 +9,7 @@ / { aliases { + ethernet0 = &gmac; mmc0 = &sdhci; }; @@ -119,6 +120,20 @@ drive-impedance-ohm = <33>; }; +&gpio0 { + /* + * The BIOS_DISABLE hog is a feedback pin for the actual status of the + * signal. This usually represents the state of a switch on the baseboard. + * The pin has a 10k pull-up resistor connected, so no pull-up setting is needed. + */ + bios-disable-hog { + gpios = ; + gpio-hog; + input; + line-name = "bios_disable"; + }; +}; + &gmac { assigned-clocks = <&cru SCLK_RMII_SRC>; assigned-clock-parents = <&clkin_gmac>; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi index c32913df93c327..ca7a446b656895 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-roc-pc.dtsi @@ -14,6 +14,7 @@ compatible = "firefly,roc-rk3399-pc", "rockchip,rk3399"; aliases { + ethernet0 = &gmac; mmc0 = &sdmmc; mmc1 = &sdhci; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rock-4c-plus.dts b/arch/arm64/boot/dts/rockchip/rk3399-rock-4c-plus.dts index 8bfd5f88d1ef61..7baf9d1b22fd5f 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-rock-4c-plus.dts +++ b/arch/arm64/boot/dts/rockchip/rk3399-rock-4c-plus.dts @@ -15,6 +15,7 @@ compatible = "radxa,rock-4c-plus", "rockchip,rk3399"; aliases { + ethernet0 = &gmac; mmc0 = &sdhci; mmc1 = &sdmmc; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dtsi index f2279aa6ca9e12..281a1218070343 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-rock-pi-4.dtsi @@ -12,6 +12,7 @@ / { aliases { + ethernet0 = &gmac; mmc0 = &sdhci; mmc1 = &sdmmc; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi index bca2b50e0a9347..f30b82a10ca385 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-rockpro64.dtsi @@ -11,6 +11,7 @@ / { aliases { + ethernet0 = &gmac; mmc0 = &sdio0; mmc1 = &sdmmc; mmc2 = &sdhci; diff --git a/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi index e6ac292ce6458b..b3ef1c85e7549e 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi @@ -12,6 +12,7 @@ compatible = "rockchip,rk3399-sapphire", "rockchip,rk3399"; aliases { + ethernet0 = &gmac; mmc0 = &sdmmc; mmc1 = &sdhci; }; @@ -44,7 +45,7 @@ fan0: gpio-fan { #cooling-cells = <2>; compatible = "gpio-fan"; - gpio-fan,speed-map = <0 0 3000 1>; + gpio-fan,speed-map = <0 0>, <3000 1>; gpios = <&gpio1 RK_PC2 GPIO_ACTIVE_HIGH>; status = "okay"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi index da0dfb237f853f..6e12c5a920caba 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi @@ -19,7 +19,11 @@ #size-cells = <2>; aliases { - ethernet0 = &gmac; + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; + gpio4 = &gpio4; i2c0 = &i2c0; i2c1 = &i2c1; i2c2 = &i2c2; @@ -2114,6 +2118,7 @@ interrupt-names = "job", "mmu", "gpu"; clocks = <&cru ACLK_GPU>; #cooling-cells = <2>; + dynamic-power-coefficient = <2640>; power-domains = <&power RK3399_PD_GPU>; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi index 8b8992a8e9c0d8..8823c924dc1d64 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399pro-vmarc-som.dtsi @@ -13,6 +13,7 @@ compatible = "vamrs,rk3399pro-vmarc-som", "rockchip,rk3399pro"; aliases { + ethernet0 = &gmac; mmc0 = &sdhci; mmc1 = &sdmmc; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-lubancat-1.dts b/arch/arm64/boot/dts/rockchip/rk3566-lubancat-1.dts index 1c6d83b47cd217..6ecdf5d283390a 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-lubancat-1.dts +++ b/arch/arm64/boot/dts/rockchip/rk3566-lubancat-1.dts @@ -455,7 +455,7 @@ &pinctrl { leds { sys_led_pin: sys-status-led-pin { - rockchip,pins = <0 RK_PC7 RK_FUNC_GPIO &pcfg_pull_none>; + rockchip,pins = <0 RK_PC5 RK_FUNC_GPIO &pcfg_pull_none>; }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rgb30.dts b/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rgb30.dts index 1ead3c5c24b375..0ac64f043b807f 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rgb30.dts +++ b/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rgb30.dts @@ -5,67 +5,11 @@ #include #include #include -#include "rk3566-anbernic-rg353x.dtsi" +#include "rk3566-powkiddy-rk2023.dtsi" / { model = "RGB30"; compatible = "powkiddy,rgb30", "rockchip,rk3566"; - - aliases { - mmc1 = &sdmmc0; - mmc2 = &sdmmc1; - mmc3 = &sdmmc2; - }; - - battery: battery { - compatible = "simple-battery"; - charge-full-design-microamp-hours = <3151000>; - charge-term-current-microamp = <300000>; - constant-charge-current-max-microamp = <2000000>; - constant-charge-voltage-max-microvolt = <4250000>; - factory-internal-resistance-micro-ohms = <117000>; - voltage-max-design-microvolt = <4172000>; - voltage-min-design-microvolt = <3400000>; - - ocv-capacity-celsius = <20>; - ocv-capacity-table-0 = <4172000 100>, <4092000 95>, <4035000 90>, <3990000 85>, - <3939000 80>, <3895000 75>, <3852000 70>, <3807000 65>, - <3762000 60>, <3713000 55>, <3672000 50>, <3647000 45>, - <3629000 40>, <3613000 35>, <3598000 30>, <3578000 25>, - <3550000 20>, <3519000 15>, <3479000 10>, <3438000 5>, - <3400000 0>; - }; - - /* - * Channels reversed for speakers. Headphones automatically switch via hardware when - * detected with no ability to control output in software. Headphones appear to be mono - * (each output channel receives all audio). No microphone support on 3.5mm jack. - */ - sound { - compatible = "simple-audio-card"; - simple-audio-card,name = "rk817_ext"; - simple-audio-card,format = "i2s"; - simple-audio-card,mclk-fs = <256>; - simple-audio-card,widgets = - "Headphone", "Headphones"; - simple-audio-card,routing = - "Headphones", "HPOL", - "Headphones", "HPOR"; - - simple-audio-card,codec { - sound-dai = <&rk817>; - }; - - simple-audio-card,cpu { - sound-dai = <&i2s1_8ch>; - }; - }; -}; - -/delete-node/ &adc_keys; - -&chosen { - /delete-property/ stdout-path; }; &cru { @@ -75,87 +19,21 @@ <200000000>, <292500000>; }; -&gpio_keys_control { - button-r1 { - gpios = <&gpio3 RK_PB3 GPIO_ACTIVE_LOW>; - label = "TR"; - linux,code = ; - }; - - button-r2 { - gpios = <&gpio3 RK_PB4 GPIO_ACTIVE_LOW>; - label = "TR2"; - linux,code = ; - }; -}; - -/delete-node/ &{/i2c@fdd40000/regulator@40}; - -&i2c0 { - vdd_cpu: regulator@1c { - compatible = "tcs,tcs4525"; - reg = <0x1c>; - fcs,suspend-voltage-selector = <1>; - regulator-always-on; - regulator-boot-on; - regulator-min-microvolt = <712500>; - regulator-max-microvolt = <1390000>; - regulator-name = "vdd_cpu"; - regulator-ramp-delay = <2300>; - vin-supply = <&vcc_sys>; - regulator-state-mem { - regulator-off-in-suspend; +&dsi0 { + panel: panel@0 { + compatible = "powkiddy,rgb30-panel"; + reg = <0>; + backlight = <&backlight>; + pinctrl-names = "default"; + pinctrl-0 = <&lcd_rst>; + reset-gpios = <&gpio4 RK_PA0 GPIO_ACTIVE_LOW>; + vcc-supply = <&vcc3v3_lcd0_n>; + iovcc-supply = <&vcc3v3_lcd0_n>; + + port { + mipi_in_panel: endpoint { + remote-endpoint = <&mipi_out_panel>; + }; }; }; }; - -/* - * Device has 2 red LEDs instead of an amber and a red. Relabel LEDs as - * red_led0 and red_led1. - */ -/delete-node/ &{/pwm-leds/led-1}; -/delete-node/ &{/pwm-leds/led-2}; - -&leds { - red_led0: led-1 { - color = ; - function = LED_FUNCTION_CHARGING; - max-brightness = <255>; - pwms = <&pwm7 0 25000 0>; - }; - - red_led1: led-2 { - color = ; - default-state = "off"; - function = LED_FUNCTION_STATUS; - max-brightness = <255>; - pwms = <&pwm0 0 25000 0>; - }; -}; - -&panel { - compatible = "powkiddy,rgb30-panel"; - vcc-supply = <&vcc3v3_lcd0_n>; - iovcc-supply = <&vcc3v3_lcd0_n>; - /delete-property/ vdd-supply; -}; - -&pwm5 { - status = "disabled"; -}; - -&rk817 { - rk817_charger: charger { - monitored-battery = <&battery>; - rockchip,resistor-sense-micro-ohms = <10000>; - rockchip,sleep-enter-current-microamp = <300000>; - rockchip,sleep-filter-current-microamp = <100000>; - }; -}; - -/* There is no UART header visible on the board for this device. */ -&uart2 { - status = "disabled"; -}; - -/delete-node/ &vibrator; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rk2023.dts b/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rk2023.dts new file mode 100644 index 00000000000000..ba32d0793dca22 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rk2023.dts @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +/dts-v1/; + +#include +#include +#include +#include "rk3566-powkiddy-rk2023.dtsi" + +/ { + model = "RK2023"; + compatible = "powkiddy,rk2023", "rockchip,rk3566"; +}; + +&cru { + assigned-clocks = <&pmucru CLK_RTC_32K>, <&cru PLL_GPLL>, + <&pmucru PLL_PPLL>, <&cru PLL_VPLL>; + assigned-clock-rates = <32768>, <1200000000>, + <200000000>, <115200000>; +}; + +&dsi0 { + panel: panel@0 { + compatible = "powkiddy,rk2023-panel", "newvision,nv3051d"; + reg = <0>; + backlight = <&backlight>; + pinctrl-names = "default"; + pinctrl-0 = <&lcd_rst>; + reset-gpios = <&gpio4 RK_PA0 GPIO_ACTIVE_LOW>; + vdd-supply = <&vcc3v3_lcd0_n>; + + port { + mipi_in_panel: endpoint { + remote-endpoint = <&mipi_out_panel>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rk2023.dtsi b/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rk2023.dtsi new file mode 100644 index 00000000000000..0fa8f06f94cd90 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-rk2023.dtsi @@ -0,0 +1,875 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +/dts-v1/; + +#include +#include +#include +#include +#include +#include "rk3566.dtsi" + +/ { + aliases { + mmc1 = &sdmmc0; + mmc2 = &sdmmc1; + mmc3 = &sdmmc2; + }; + + adc-joystick { + compatible = "adc-joystick"; + io-channels = <&adc_mux 0>, + <&adc_mux 1>, + <&adc_mux 2>, + <&adc_mux 3>; + pinctrl-0 = <&joy_mux_en>; + pinctrl-names = "default"; + poll-interval = <60>; + #address-cells = <1>; + #size-cells = <0>; + + axis@0 { + reg = <0>; + abs-flat = <32>; + abs-fuzz = <32>; + abs-range = <1023 15>; + linux,code = ; + }; + + axis@1 { + reg = <1>; + abs-flat = <32>; + abs-fuzz = <32>; + abs-range = <15 1023>; + linux,code = ; + }; + + axis@2 { + reg = <2>; + abs-flat = <32>; + abs-fuzz = <32>; + abs-range = <15 1023>; + linux,code = ; + }; + + axis@3 { + reg = <3>; + abs-flat = <32>; + abs-fuzz = <32>; + abs-range = <1023 15>; + linux,code = ; + }; + }; + + adc_mux: adc-mux { + compatible = "io-channel-mux"; + channels = "left_x", "right_x", "left_y", "right_y"; + #io-channel-cells = <1>; + io-channels = <&saradc 3>; + io-channel-names = "parent"; + mux-controls = <&gpio_mux>; + settle-time-us = <100>; + }; + + backlight: backlight { + compatible = "pwm-backlight"; + power-supply = <&vcc_sys>; + pwms = <&pwm4 0 25000 0>; + }; + + battery: battery { + compatible = "simple-battery"; + charge-full-design-microamp-hours = <3151000>; + charge-term-current-microamp = <300000>; + constant-charge-current-max-microamp = <2000000>; + constant-charge-voltage-max-microvolt = <4250000>; + factory-internal-resistance-micro-ohms = <117000>; + voltage-max-design-microvolt = <4172000>; + voltage-min-design-microvolt = <3400000>; + + ocv-capacity-celsius = <20>; + ocv-capacity-table-0 = <4172000 100>, <4092000 95>, <4035000 90>, <3990000 85>, + <3939000 80>, <3895000 75>, <3852000 70>, <3807000 65>, + <3762000 60>, <3713000 55>, <3672000 50>, <3647000 45>, + <3629000 40>, <3613000 35>, <3598000 30>, <3578000 25>, + <3550000 20>, <3519000 15>, <3479000 10>, <3438000 5>, + <3400000 0>; + }; + + gpio_keys_control: gpio-keys-control { + compatible = "gpio-keys"; + pinctrl-0 = <&btn_pins_ctrl>; + pinctrl-names = "default"; + + button-a { + gpios = <&gpio3 RK_PC2 GPIO_ACTIVE_LOW>; + label = "EAST"; + linux,code = ; + }; + + button-b { + gpios = <&gpio3 RK_PC3 GPIO_ACTIVE_LOW>; + label = "SOUTH"; + linux,code = ; + }; + + button-down { + gpios = <&gpio3 RK_PA4 GPIO_ACTIVE_LOW>; + label = "DPAD-DOWN"; + linux,code = ; + }; + + button-l1 { + gpios = <&gpio3 RK_PB1 GPIO_ACTIVE_LOW>; + label = "TL"; + linux,code = ; + }; + + button-l2 { + gpios = <&gpio3 RK_PB2 GPIO_ACTIVE_LOW>; + label = "TL2"; + linux,code = ; + }; + + button-left { + gpios = <&gpio3 RK_PA6 GPIO_ACTIVE_LOW>; + label = "DPAD-LEFT"; + linux,code = ; + }; + + button-r1 { + gpios = <&gpio3 RK_PB3 GPIO_ACTIVE_LOW>; + label = "TR"; + linux,code = ; + }; + + button-r2 { + gpios = <&gpio3 RK_PB4 GPIO_ACTIVE_LOW>; + label = "TR2"; + linux,code = ; + }; + + button-right { + gpios = <&gpio3 RK_PA5 GPIO_ACTIVE_LOW>; + label = "DPAD-RIGHT"; + linux,code = ; + }; + + button-select { + gpios = <&gpio3 RK_PB6 GPIO_ACTIVE_LOW>; + label = "SELECT"; + linux,code = ; + }; + + button-start { + gpios = <&gpio3 RK_PB5 GPIO_ACTIVE_LOW>; + label = "START"; + linux,code = ; + }; + + button-thumbl { + gpios = <&gpio3 RK_PA1 GPIO_ACTIVE_LOW>; + label = "THUMBL"; + linux,code = ; + }; + + button-thumbr { + gpios = <&gpio3 RK_PA2 GPIO_ACTIVE_LOW>; + label = "THUMBR"; + linux,code = ; + }; + + button-up { + gpios = <&gpio3 RK_PA3 GPIO_ACTIVE_LOW>; + label = "DPAD-UP"; + linux,code = ; + }; + + button-x { + gpios = <&gpio3 RK_PC0 GPIO_ACTIVE_LOW>; + label = "NORTH"; + linux,code = ; + }; + + button-y { + gpios = <&gpio3 RK_PC1 GPIO_ACTIVE_LOW>; + label = "WEST"; + linux,code = ; + }; + }; + + gpio_keys_vol: gpio-keys-vol { + compatible = "gpio-keys"; + autorepeat; + pinctrl-0 = <&btn_pins_vol>; + pinctrl-names = "default"; + + button-vol-down { + gpios = <&gpio3 RK_PB0 GPIO_ACTIVE_LOW>; + label = "VOLUMEDOWN"; + linux,code = ; + }; + + button-vol-up { + gpios = <&gpio3 RK_PA7 GPIO_ACTIVE_LOW>; + label = "VOLUMEUP"; + linux,code = ; + }; + }; + + gpio_mux: mux-controller { + compatible = "gpio-mux"; + mux-gpios = <&gpio0 RK_PB6 GPIO_ACTIVE_LOW>, + <&gpio0 RK_PB7 GPIO_ACTIVE_LOW>; + #mux-control-cells = <0>; + }; + + hdmi-con { + compatible = "hdmi-connector"; + ddc-i2c-bus = <&i2c5>; + type = "c"; + + port { + hdmi_con_in: endpoint { + remote-endpoint = <&hdmi_out_con>; + }; + }; + }; + + /* + * Device also includes an always on LED that is wired to the 5V input + * voltage and is on when the device is plugged in. + */ + leds: pwm-leds { + compatible = "pwm-leds"; + + green_led: led-0 { + color = ; + function = LED_FUNCTION_STATUS; + max-brightness = <255>; + pwms = <&pwm6 0 25000 0>; + }; + + red_led: led-1 { + color = ; + function = LED_FUNCTION_CHARGING; + max-brightness = <255>; + pwms = <&pwm7 0 25000 0>; + }; + }; + + sdio_pwrseq: sdio-pwrseq { + compatible = "mmc-pwrseq-simple"; + clocks = <&rk817 1>; + clock-names = "ext_clock"; + pinctrl-0 = <&wifi_enable_h>; + pinctrl-names = "default"; + post-power-on-delay-ms = <200>; + reset-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_LOW>; + }; + + /* + * Channels reversed for speakers. Headphones automatically switch via hardware when + * detected with no ability to control output in software. Headphones appear to be mono + * (each output channel receives all audio). No microphone support on 3.5mm jack. + */ + sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "rk817_ext"; + simple-audio-card,format = "i2s"; + simple-audio-card,mclk-fs = <256>; + simple-audio-card,widgets = + "Headphone", "Headphones"; + simple-audio-card,routing = + "Headphones", "HPOL", + "Headphones", "HPOR"; + + simple-audio-card,codec { + sound-dai = <&rk817>; + }; + + simple-audio-card,cpu { + sound-dai = <&i2s1_8ch>; + }; + }; + + vcc3v3_lcd0_n: regulator-vcc3v3-lcd0 { + compatible = "regulator-fixed"; + gpio = <&gpio0 RK_PC2 GPIO_ACTIVE_HIGH>; + enable-active-high; + pinctrl-0 = <&vcc_lcd_h>; + pinctrl-names = "default"; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc3v3_lcd0_n"; + vin-supply = <&vcc_3v3>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_sys: regulator-vcc-sys { + compatible = "regulator-fixed"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3800000>; + regulator-max-microvolt = <3800000>; + regulator-name = "vcc_sys"; + }; + + vcc_wifi: regulator-vcc-wifi { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio0 RK_PA0 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&vcc_wifi_h>; + pinctrl-names = "default"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc_wifi"; + }; +}; + +&combphy1 { + status = "okay"; +}; + +&cpu0 { + cpu-supply = <&vdd_cpu>; +}; + +&cpu1 { + cpu-supply = <&vdd_cpu>; +}; + +&cpu2 { + cpu-supply = <&vdd_cpu>; +}; + +&cpu3 { + cpu-supply = <&vdd_cpu>; +}; + +&dsi0 { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + ports { + dsi0_in: port@0 { + reg = <0>; + dsi0_in_vp1: endpoint { + remote-endpoint = <&vp1_out_dsi0>; + }; + }; + + dsi0_out: port@1 { + reg = <1>; + mipi_out_panel: endpoint { + remote-endpoint = <&mipi_in_panel>; + }; + }; + }; +}; + +&dsi_dphy0 { + status = "okay"; +}; + +&gpu { + mali-supply = <&vdd_gpu>; + status = "okay"; +}; + +&hdmi { + ddc-i2c-bus = <&i2c5>; + pinctrl-0 = <&hdmitxm0_cec>; + pinctrl-names = "default"; + status = "okay"; +}; + +&hdmi_in { + hdmi_in_vp0: endpoint { + remote-endpoint = <&vp0_out_hdmi>; + }; +}; + +&hdmi_out { + hdmi_out_con: endpoint { + remote-endpoint = <&hdmi_con_in>; + }; +}; + +&hdmi_sound { + status = "okay"; +}; + +&i2c0 { + status = "okay"; + + rk817: pmic@20 { + compatible = "rockchip,rk817"; + reg = <0x20>; + interrupt-parent = <&gpio0>; + interrupts = ; + clock-output-names = "rk808-clkout1", "rk808-clkout2"; + clock-names = "mclk"; + clocks = <&cru I2S1_MCLKOUT_TX>; + assigned-clocks = <&cru I2S1_MCLKOUT_TX>; + assigned-clock-parents = <&cru CLK_I2S1_8CH_TX>; + #clock-cells = <1>; + #sound-dai-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&i2s1m0_mclk>, <&pmic_int_l>; + wakeup-source; + + vcc1-supply = <&vcc_sys>; + vcc2-supply = <&vcc_sys>; + vcc3-supply = <&vcc_sys>; + vcc4-supply = <&vcc_sys>; + vcc5-supply = <&vcc_sys>; + vcc6-supply = <&vcc_sys>; + vcc7-supply = <&vcc_sys>; + vcc8-supply = <&vcc_sys>; + vcc9-supply = <&dcdc_boost>; + + regulators { + vdd_logic: DCDC_REG1 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <6001>; + regulator-initial-mode = <0x2>; + regulator-name = "vdd_logic"; + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <900000>; + }; + }; + + vdd_gpu: DCDC_REG2 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <6001>; + regulator-initial-mode = <0x2>; + regulator-name = "vdd_gpu"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_ddr: DCDC_REG3 { + regulator-always-on; + regulator-boot-on; + regulator-initial-mode = <0x2>; + regulator-name = "vcc_ddr"; + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vcc_3v3: DCDC_REG4 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-initial-mode = <0x2>; + regulator-name = "vcc_3v3"; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vcca1v8_pmu: LDO_REG1 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcca1v8_pmu"; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vdda_0v9: LDO_REG2 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + regulator-name = "vdda_0v9"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdda0v9_pmu: LDO_REG3 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + regulator-name = "vdda0v9_pmu"; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <900000>; + }; + }; + + vccio_acodec: LDO_REG4 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vccio_acodec"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vccio_sd: LDO_REG5 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vccio_sd"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc3v3_pmu: LDO_REG6 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc3v3_pmu"; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vcc_1v8: LDO_REG7 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc_1v8"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc1v8_dvp: LDO_REG8 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc1v8_dvp"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc2v8_dvp: LDO_REG9 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-name = "vcc2v8_dvp"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + dcdc_boost: BOOST { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <4700000>; + regulator-max-microvolt = <5400000>; + regulator-name = "boost"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + otg_switch: OTG_SWITCH { + regulator-name = "otg_switch"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + }; + + rk817_charger: charger { + monitored-battery = <&battery>; + rockchip,resistor-sense-micro-ohms = <10000>; + rockchip,sleep-enter-current-microamp = <300000>; + rockchip,sleep-filter-current-microamp = <100000>; + }; + }; + + vdd_cpu: regulator@1c { + compatible = "tcs,tcs4525"; + reg = <0x1c>; + fcs,suspend-voltage-selector = <1>; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1390000>; + regulator-name = "vdd_cpu"; + regulator-ramp-delay = <2300>; + vin-supply = <&vcc_sys>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; +}; + +&i2c5 { + pinctrl-0 = <&i2c5m1_xfer>; + pinctrl-names = "default"; + status = "okay"; +}; + +&i2s0_8ch { + status = "okay"; +}; + +&i2s1_8ch { + pinctrl-0 = <&i2s1m0_sclktx + &i2s1m0_lrcktx + &i2s1m0_sdi0 + &i2s1m0_sdo0>; + pinctrl-names = "default"; + rockchip,trcm-sync-tx-only; + status = "okay"; +}; + +&pinctrl { + gpio-btns { + btn_pins_ctrl: btn-pins-ctrl { + rockchip,pins = + <3 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PB1 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PB3 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PB5 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PB6 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PC0 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PC1 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PC2 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PC3 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + btn_pins_vol: btn-pins-vol { + rockchip,pins = + <3 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + joy-mux { + joy_mux_en: joy-mux-en { + rockchip,pins = + <0 RK_PB5 RK_FUNC_GPIO &pcfg_output_low>; + }; + }; + + gpio-lcd { + lcd_rst: lcd-rst { + rockchip,pins = + <4 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + pmic { + pmic_int_l: pmic-int-l { + rockchip,pins = + <0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + sdio-pwrseq { + wifi_enable_h: wifi-enable-h { + rockchip,pins = + <4 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + vcc3v3-lcd { + vcc_lcd_h: vcc-lcd-h { + rockchip,pins = + <0 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + vcc-wifi { + vcc_wifi_h: vcc-wifi-h { + rockchip,pins = + <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; + +&pmu_io_domains { + status = "okay"; + pmuio1-supply = <&vcc3v3_pmu>; + pmuio2-supply = <&vcc3v3_pmu>; + vccio1-supply = <&vccio_acodec>; + vccio3-supply = <&vccio_sd>; + vccio4-supply = <&vcc_1v8>; + vccio5-supply = <&vcc_3v3>; + vccio6-supply = <&vcc1v8_dvp>; + vccio7-supply = <&vcc_3v3>; +}; + +&pwm4 { + status = "okay"; +}; + +&pwm6 { + status = "okay"; +}; + +&pwm7 { + status = "okay"; +}; + +&saradc { + vref-supply = <&vcc_1v8>; + status = "okay"; +}; + +&sdmmc0 { + bus-width = <4>; + cap-sd-highspeed; + cd-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>; + disable-wp; + pinctrl-0 = <&sdmmc0_bus4 &sdmmc0_clk &sdmmc0_cmd &sdmmc0_det>; + pinctrl-names = "default"; + sd-uhs-sdr104; + vmmc-supply = <&vcc_3v3>; + vqmmc-supply = <&vccio_sd>; + status = "okay"; +}; + +&sdmmc1 { + bus-width = <4>; + cap-sd-highspeed; + cd-gpios = <&gpio2 RK_PB2 GPIO_ACTIVE_LOW>; + disable-wp; + pinctrl-0 = <&sdmmc1_bus4 &sdmmc1_cmd &sdmmc1_clk &sdmmc1_det>; + pinctrl-names = "default"; + sd-uhs-sdr104; + vmmc-supply = <&vcc_3v3>; + vqmmc-supply = <&vcc1v8_dvp>; + status = "okay"; +}; + +&sdmmc2 { + bus-width = <4>; + cap-sd-highspeed; + cap-sdio-irq; + keep-power-in-suspend; + mmc-pwrseq = <&sdio_pwrseq>; + non-removable; + pinctrl-0 = <&sdmmc2m0_bus4 &sdmmc2m0_cmd &sdmmc2m0_clk>; + pinctrl-names = "default"; + vmmc-supply = <&vcc_wifi>; + vqmmc-supply = <&vcca1v8_pmu>; + status = "okay"; +}; + +&tsadc { + rockchip,hw-tshut-mode = <1>; + rockchip,hw-tshut-polarity = <0>; + status = "okay"; +}; + +&uart1 { + pinctrl-0 = <&uart1m1_xfer &uart1m1_ctsn &uart1m1_rtsn>; + pinctrl-names = "default"; + uart-has-rtscts; + status = "okay"; + + bluetooth { + compatible = "realtek,rtl8821cs-bt", "realtek,rtl8723bs-bt"; + device-wake-gpios = <&gpio4 4 GPIO_ACTIVE_HIGH>; + enable-gpios = <&gpio4 3 GPIO_ACTIVE_HIGH>; + host-wake-gpios = <&gpio4 5 GPIO_ACTIVE_HIGH>; + }; +}; + +&usb_host0_xhci { + dr_mode = "peripheral"; + phys = <&usb2phy0_otg>; + phy-names = "usb2-phy"; + status = "okay"; +}; + +&usb_host1_ehci { + status = "okay"; +}; + +&usb_host1_ohci { + status = "okay"; +}; + +&usb_host1_xhci { + phy-names = "usb2-phy", "usb3-phy"; + phys = <&usb2phy1_host>, <&combphy1 PHY_TYPE_USB3>; + status = "okay"; +}; + +&usb2phy0 { + status = "okay"; +}; + +&usb2phy0_otg { + status = "okay"; +}; + +&usb2phy1 { + status = "okay"; +}; + +&usb2phy1_host { + status = "okay"; +}; + +&vop { + assigned-clocks = <&cru DCLK_VOP0>, <&cru DCLK_VOP1>; + assigned-clock-parents = <&pmucru PLL_HPLL>, <&cru PLL_VPLL>; + status = "okay"; +}; + +&vop_mmu { + status = "okay"; +}; + +&vp0 { + vp0_out_hdmi: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { + reg = ; + remote-endpoint = <&hdmi_in_vp0>; + }; +}; + +&vp1 { + vp1_out_dsi0: endpoint@ROCKCHIP_VOP2_EP_MIPI0 { + reg = ; + remote-endpoint = <&dsi0_in_vp1>; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-x55.dts b/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-x55.dts new file mode 100644 index 00000000000000..4786b19fd01786 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3566-powkiddy-x55.dts @@ -0,0 +1,926 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) + +/dts-v1/; + +#include +#include +#include +#include +#include +#include "rk3566.dtsi" + +/ { + model = "Powkiddy x55"; + compatible = "powkiddy,x55", "rockchip,rk3566"; + + aliases { + mmc0 = &sdhci; + mmc1 = &sdmmc0; + mmc2 = &sdmmc2; + mmc3 = &sdmmc1; + }; + + chosen: chosen { + stdout-path = "serial2:1500000n8"; + }; + + adc_joystick: adc-joystick { + compatible = "adc-joystick"; + io-channels = <&saradc 0>, <&saradc 1>, + <&saradc 2>, <&saradc 3>; + poll-interval = <60>; + #address-cells = <1>; + #size-cells = <0>; + + axis@0 { + reg = <0>; + abs-flat = <30>; + abs-fuzz = <20>; + abs-range = <15 1023>; + linux,code = ; + }; + + axis@1 { + reg = <1>; + abs-flat = <30>; + abs-fuzz = <20>; + abs-range = <1023 15>; + linux,code = ; + }; + + axis@2 { + reg = <2>; + abs-flat = <30>; + abs-fuzz = <20>; + abs-range = <15 1023>; + linux,code = ; + }; + + axis@3 { + reg = <3>; + abs-flat = <30>; + abs-fuzz = <20>; + abs-range = <1023 15>; + linux,code = ; + }; + }; + + backlight: backlight { + compatible = "pwm-backlight"; + power-supply = <&vcc_sys>; + pwms = <&pwm4 0 25000 0>; + }; + + battery: battery { + compatible = "simple-battery"; + charge-full-design-microamp-hours = <4000000>; + charge-term-current-microamp = <300000>; + constant-charge-current-max-microamp = <2000000>; + constant-charge-voltage-max-microvolt = <4300000>; + factory-internal-resistance-micro-ohms = <91000>; + voltage-max-design-microvolt = <4138000>; + voltage-min-design-microvolt = <3400000>; + + ocv-capacity-celsius = <20>; + ocv-capacity-table-0 = <4138000 100>, <4083000 95>, <4059000 90>, <4044000 85>, + <4030000 80>, <4020000 75>, <4006000 70>, <3972000 65>, + <3934000 60>, <3904000 55>, <3878000 50>, <3857000 45>, + <3843000 40>, <3826000 35>, <3801000 30>, <3768000 25>, + <3735000 20>, <3688000 15>, <3621000 10>, <3553000 5>, + <3400000 0>; + }; + + gpio_keys_control: gpio-keys-control { + compatible = "gpio-keys"; + pinctrl-0 = <&btn_pins_ctrl>; + pinctrl-names = "default"; + + button-a { + gpios = <&gpio3 RK_PD3 GPIO_ACTIVE_LOW>; + label = "EAST"; + linux,code = ; + }; + + button-b { + gpios = <&gpio3 RK_PD2 GPIO_ACTIVE_LOW>; + label = "SOUTH"; + linux,code = ; + }; + + button-down { + gpios = <&gpio4 RK_PA1 GPIO_ACTIVE_LOW>; + label = "DPAD-DOWN"; + linux,code = ; + }; + + button-l1 { + gpios = <&gpio3 RK_PD0 GPIO_ACTIVE_LOW>; + label = "TL"; + linux,code = ; + }; + + button-l2 { + gpios = <&gpio3 RK_PD1 GPIO_ACTIVE_LOW>; + label = "TL2"; + linux,code = ; + }; + + button-left { + gpios = <&gpio3 RK_PD6 GPIO_ACTIVE_LOW>; + label = "DPAD-LEFT"; + linux,code = ; + }; + + button-right { + gpios = <&gpio3 RK_PD7 GPIO_ACTIVE_LOW>; + label = "DPAD-RIGHT"; + linux,code = ; + }; + + button-select { + gpios = <&gpio4 RK_PA4 GPIO_ACTIVE_LOW>; + label = "SELECT"; + linux,code = ; + }; + + button-start { + gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_LOW>; + label = "START"; + linux,code = ; + }; + + button-thumbl { + gpios = <&gpio4 RK_PA7 GPIO_ACTIVE_LOW>; + label = "THUMBL"; + linux,code = ; + }; + + button-thumbr { + gpios = <&gpio4 RK_PB0 GPIO_ACTIVE_LOW>; + label = "THUMBR"; + linux,code = ; + }; + + button-r1 { + gpios = <&gpio3 RK_PC6 GPIO_ACTIVE_LOW>; + label = "TR"; + linux,code = ; + }; + + button-r2 { + gpios = <&gpio3 RK_PC7 GPIO_ACTIVE_LOW>; + label = "TR2"; + linux,code = ; + }; + + button-up { + gpios = <&gpio4 RK_PA0 GPIO_ACTIVE_LOW>; + label = "DPAD-UP"; + linux,code = ; + }; + + button-x { + gpios = <&gpio3 RK_PD5 GPIO_ACTIVE_LOW>; + label = "NORTH"; + linux,code = ; + }; + + button-y { + gpios = <&gpio3 RK_PD4 GPIO_ACTIVE_LOW>; + label = "WEST"; + linux,code = ; + }; + }; + + gpio_keys_vol: gpio-keys-vol { + compatible = "gpio-keys"; + autorepeat; + pinctrl-0 = <&btn_pins_vol>; + pinctrl-names = "default"; + + button-voldown { + gpios = <&gpio4 RK_PA3 GPIO_ACTIVE_LOW>; + label = "VOLUMEDOWN"; + linux,code = ; + }; + + button-volup { + gpios = <&gpio4 RK_PA5 GPIO_ACTIVE_LOW>; + label = "VOLUMEUP"; + linux,code = ; + }; + }; + + gpio_leds: gpio-leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&led_pins>; + + red_led: led-0 { + color = ; + default-state = "off"; + gpios = <&gpio4 RK_PB4 GPIO_ACTIVE_HIGH>; + function = LED_FUNCTION_STATUS; + }; + + green_led: led-1 { + color = ; + default-state = "on"; + gpios = <&gpio4 RK_PB5 GPIO_ACTIVE_HIGH>; + function = LED_FUNCTION_POWER; + }; + + amber_led: led-2 { + color = ; + gpios = <&gpio4 RK_PB6 GPIO_ACTIVE_HIGH>; + function = LED_FUNCTION_CHARGING; + }; + + }; + + hdmi-con { + compatible = "hdmi-connector"; + ddc-i2c-bus = <&i2c5>; + type = "c"; + + port { + hdmi_con_in: endpoint { + remote-endpoint = <&hdmi_out_con>; + }; + }; + }; + + sdio_pwrseq: sdio-pwrseq { + compatible = "mmc-pwrseq-simple"; + clocks = <&rk817 1>; + clock-names = "ext_clock"; + pinctrl-0 = <&wifi_enable_h>; + pinctrl-names = "default"; + post-power-on-delay-ms = <200>; + reset-gpios = <&gpio0 RK_PC0 GPIO_ACTIVE_LOW>; + }; + + /* Channels reversed for both headphones and speakers. */ + sound { + compatible = "simple-audio-card"; + pinctrl-0 = <&hp_det>; + pinctrl-names = "default"; + simple-audio-card,name = "rk817_ext"; + simple-audio-card,aux-devs = <&spk_amp>; + simple-audio-card,format = "i2s"; + simple-audio-card,hp-det-gpio = <&gpio4 RK_PC6 GPIO_ACTIVE_HIGH>; + simple-audio-card,mclk-fs = <256>; + simple-audio-card,widgets = + "Microphone", "Mic Jack", + "Headphone", "Headphones", + "Speaker", "Internal Speakers"; + simple-audio-card,routing = + "MICL", "Mic Jack", + "Headphones", "HPOL", + "Headphones", "HPOR", + "Internal Speakers", "Speaker Amp OUTL", + "Internal Speakers", "Speaker Amp OUTR", + "Speaker Amp INL", "HPOL", + "Speaker Amp INR", "HPOR"; + simple-audio-card,pin-switches = "Internal Speakers"; + + simple-audio-card,codec { + sound-dai = <&rk817>; + }; + + simple-audio-card,cpu { + sound-dai = <&i2s1_8ch>; + }; + }; + + spk_amp: audio-amplifier { + compatible = "simple-audio-amplifier"; + enable-gpios = <&gpio4 RK_PC2 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&spk_amp_enable_h>; + pinctrl-names = "default"; + sound-name-prefix = "Speaker Amp"; + }; + + vcc5v0_host: regulator-vcc5v0-host { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio4 RK_PC4 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&vcc5v0_host_en>; + pinctrl-names = "default"; + regulator-name = "vcc5v0_host"; + vin-supply = <&dcdc_boost>; + }; + + vcc_lcd: regulator-vcc-lcd { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio0 RK_PC7 GPIO_ACTIVE_HIGH>; + pinctrl-0 = <&vcc_lcd_en>; + pinctrl-names = "default"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc_lcd"; + }; + + vcc_sys: regulator-vcc-sys { + compatible = "regulator-fixed"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3800000>; + regulator-max-microvolt = <3800000>; + regulator-name = "vcc_sys"; + }; + + vcc_wifi: regulator-vcc-wifi { + compatible = "regulator-fixed"; + gpio = <&gpio0 RK_PA0 GPIO_ACTIVE_LOW>; + pinctrl-0 = <&vcc_wifi_h>; + pinctrl-names = "default"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc_wifi"; + }; +}; + +&combphy1 { + status = "okay"; +}; + +&cru { + assigned-clocks = <&pmucru CLK_RTC_32K>, <&cru PLL_GPLL>, + <&pmucru PLL_PPLL>, <&cru PLL_VPLL>; + assigned-clock-rates = <32768>, <1200000000>, + <200000000>, <126400000>; +}; + +&cpu0 { + cpu-supply = <&vdd_cpu>; +}; + +&cpu1 { + cpu-supply = <&vdd_cpu>; +}; + +&cpu2 { + cpu-supply = <&vdd_cpu>; +}; + +&cpu3 { + cpu-supply = <&vdd_cpu>; +}; + +&dsi_dphy0 { + status = "okay"; +}; + +&dsi0 { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + ports { + dsi0_in: port@0 { + reg = <0>; + dsi0_in_vp1: endpoint { + remote-endpoint = <&vp1_out_dsi0>; + }; + }; + + dsi0_out: port@1 { + reg = <1>; + mipi_out_panel: endpoint { + remote-endpoint = <&mipi_in_panel>; + }; + }; + }; + + panel: panel@0 { + compatible = "powkiddy,x55-panel", "himax,hx8394"; + reg = <0>; + backlight = <&backlight>; + iovcc-supply = <&vcc_lcd>; + pinctrl-names = "default"; + pinctrl-0 = <&lcd_rst>; + reset-gpios = <&gpio0 RK_PD5 GPIO_ACTIVE_LOW>; + rotation = <270>; + vcc-supply = <&vcc_lcd>; + + port { + mipi_in_panel: endpoint { + remote-endpoint = <&mipi_out_panel>; + }; + }; + }; +}; + +&gpu { + mali-supply = <&vdd_gpu>; + status = "okay"; +}; + +&hdmi { + ddc-i2c-bus = <&i2c5>; + pinctrl-0 = <&hdmitxm0_cec>; + pinctrl-names = "default"; + status = "okay"; +}; + +&hdmi_in { + hdmi_in_vp0: endpoint { + remote-endpoint = <&vp0_out_hdmi>; + }; +}; + +&hdmi_out { + hdmi_out_con: endpoint { + remote-endpoint = <&hdmi_con_in>; + }; +}; + +&hdmi_sound { + status = "okay"; +}; + +&i2c0 { + status = "okay"; + + rk817: pmic@20 { + compatible = "rockchip,rk817"; + reg = <0x20>; + assigned-clocks = <&cru I2S1_MCLKOUT_TX>; + assigned-clock-parents = <&cru CLK_I2S1_8CH_TX>; + clock-names = "mclk"; + clock-output-names = "rk808-clkout1", "rk808-clkout2"; + clocks = <&cru I2S1_MCLKOUT_TX>; + interrupt-parent = <&gpio0>; + interrupts = ; + pinctrl-names = "default"; + pinctrl-0 = <&i2s1m0_mclk>, <&pmic_int_l>; + wakeup-source; + #clock-cells = <1>; + #sound-dai-cells = <0>; + + vcc1-supply = <&vcc_sys>; + vcc2-supply = <&vcc_sys>; + vcc3-supply = <&vcc_sys>; + vcc4-supply = <&vcc_sys>; + vcc5-supply = <&vcc_sys>; + vcc6-supply = <&vcc_sys>; + vcc7-supply = <&vcc_sys>; + vcc8-supply = <&vcc_sys>; + vcc9-supply = <&dcdc_boost>; + + regulators { + vdd_logic: DCDC_REG1 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <6001>; + regulator-initial-mode = <0x2>; + regulator-name = "vdd_logic"; + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <900000>; + }; + }; + + vdd_gpu: DCDC_REG2 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1350000>; + regulator-ramp-delay = <6001>; + regulator-initial-mode = <0x2>; + regulator-name = "vdd_gpu"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_ddr: DCDC_REG3 { + regulator-always-on; + regulator-boot-on; + regulator-initial-mode = <0x2>; + regulator-name = "vcc_ddr"; + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vcc_3v3: DCDC_REG4 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-initial-mode = <0x2>; + regulator-name = "vcc_3v3"; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vcca1v8_pmu: LDO_REG1 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcca1v8_pmu"; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vdda_0v9: LDO_REG2 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + regulator-name = "vdda_0v9"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdda0v9_pmu: LDO_REG3 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + regulator-name = "vdda0v9_pmu"; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <900000>; + }; + }; + + vccio_acodec: LDO_REG4 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vccio_acodec"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vccio_sd: LDO_REG5 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vccio_sd"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc3v3_pmu: LDO_REG6 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc3v3_pmu"; + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vcc_1v8: LDO_REG7 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc_1v8"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc1v8_dvp: LDO_REG8 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc1v8_dvp"; + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vcc2v8_dvp: LDO_REG9 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc2v8_dvp"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + dcdc_boost: BOOST { + regulator-min-microvolt = <4700000>; + regulator-max-microvolt = <5400000>; + regulator-name = "boost"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + otg_switch: OTG_SWITCH { + regulator-name = "otg_switch"; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + }; + + rk817_charger: charger { + monitored-battery = <&battery>; + rockchip,resistor-sense-micro-ohms = <10000>; + rockchip,sleep-enter-current-microamp = <150000>; + rockchip,sleep-filter-current-microamp = <100000>; + }; + + }; + + vdd_cpu: regulator@1c { + compatible = "tcs,tcs4525"; + reg = <0x1c>; + fcs,suspend-voltage-selector = <1>; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <712500>; + regulator-max-microvolt = <1390000>; + regulator-name = "vdd_cpu"; + regulator-ramp-delay = <2300>; + vin-supply = <&vcc_sys>; + regulator-state-mem { + regulator-off-in-suspend; + }; + }; +}; + +&i2c5 { + pinctrl-0 = <&i2c5m1_xfer>; + pinctrl-names = "default"; + status = "okay"; +}; + +&i2s0_8ch { + status = "okay"; +}; + +&i2s1_8ch { + pinctrl-0 = <&i2s1m0_sclktx>, <&i2s1m0_lrcktx>, <&i2s1m0_sdi0>, + <&i2s1m0_sdo0>; + pinctrl-names = "default"; + rockchip,trcm-sync-tx-only; + status = "okay"; +}; + +&pinctrl { + audio-amplifier { + spk_amp_enable_h: spk-amp-enable-h { + rockchip,pins = + <4 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + gpio-control { + btn_pins_ctrl: btn-pins-ctrl { + rockchip,pins = + <3 RK_PC6 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PC7 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PD0 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PD1 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PD2 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PD3 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PD4 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PD5 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PD6 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PD7 RK_FUNC_GPIO &pcfg_pull_up>, + <4 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>, + <4 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up>, + <4 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>, + <4 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>, + <4 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up>, + <4 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + btn_pins_vol: btn-pins-vol { + rockchip,pins = + <4 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>, + <4 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + gpio-lcd { + lcd_rst: lcd-rst { + rockchip,pins = + <0 RK_PD5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + gpio-leds { + led_pins: led-pins { + rockchip,pins = + <4 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>, + <4 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>, + <4 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + hp-detect { + hp_det: hp-det { + rockchip,pins = + <4 RK_PC6 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + pmic { + pmic_int_l: pmic-int-l { + rockchip,pins = + <0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + sdio-pwrseq { + wifi_enable_h: wifi-enable-h { + rockchip,pins = + <0 RK_PC0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + usb { + vcc5v0_host_en: vcc5v0-host-en { + rockchip,pins = + <4 RK_PC4 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + vcc5v0_otg_en: vcc5v0-otg-en { + rockchip,pins = + <4 RK_PC5 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + vcc-lcd { + vcc_lcd_en: vcc-lcd-en { + rockchip,pins = + <0 RK_PC7 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + vcc-wifi { + vcc_wifi_h: vcc-wifi-h { + rockchip,pins = + <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; + +&pmu_io_domains { + status = "okay"; + pmuio1-supply = <&vcc3v3_pmu>; + pmuio2-supply = <&vcca1v8_pmu>; + vccio1-supply = <&vccio_acodec>; + vccio3-supply = <&vccio_sd>; + vccio4-supply = <&vcca1v8_pmu>; + vccio5-supply = <&vcc2v8_dvp>; + vccio6-supply = <&vcc1v8_dvp>; + vccio7-supply = <&vcc_3v3>; +}; + +&pwm4 { + status = "okay"; +}; + +&saradc { + vref-supply = <&vcc_1v8>; + status = "okay"; +}; + +&sdhci { + bus-width = <8>; + mmc-hs200-1_8v; + non-removable; + pinctrl-0 = <&emmc_bus8>, <&emmc_clk>, <&emmc_cmd>, + <&emmc_datastrobe>, <&emmc_rstnout>; + pinctrl-names = "default"; + status = "okay"; +}; + +&sdmmc0 { + bus-width = <4>; + cap-mmc-highspeed; + cap-sd-highspeed; + disable-wp; + pinctrl-0 = <&sdmmc0_bus4>, <&sdmmc0_clk>, <&sdmmc0_cmd>, + <&sdmmc0_det>; + pinctrl-names = "default"; + sd-uhs-sdr104; + vqmmc-supply = <&vccio_sd>; + status = "okay"; +}; + +&sdmmc1 { + bus-width = <4>; + cap-sd-highspeed; + cap-sdio-irq; + keep-power-in-suspend; + mmc-pwrseq = <&sdio_pwrseq>; + non-removable; + pinctrl-0 = <&sdmmc1_bus4>, <&sdmmc1_cmd>, <&sdmmc1_clk>; + pinctrl-names = "default"; + vmmc-supply = <&vcc_wifi>; + status = "okay"; +}; + +&sdmmc2 { + bus-width = <4>; + cap-mmc-highspeed; + cap-sd-highspeed; + disable-wp; + pinctrl-0 = <&sdmmc2m1_bus4>, <&sdmmc2m1_cmd>, <&sdmmc2m1_clk>, + <&sdmmc2m1_det>; + pinctrl-names = "default"; + sd-uhs-sdr104; + vqmmc-supply = <&vcc2v8_dvp>; + status = "okay"; +}; + +&tsadc { + rockchip,hw-tshut-mode = <1>; + rockchip,hw-tshut-polarity = <0>; + status = "okay"; +}; + +&uart1 { + pinctrl-0 = <&uart1m0_xfer>, <&uart1m0_ctsn>, <&uart1m0_rtsn>; + pinctrl-names = "default"; + uart-has-rtscts; + status = "okay"; + + bluetooth { + compatible = "realtek,rtl8821cs-bt", "realtek,rtl8723bs-bt"; + device-wake-gpios = <&gpio0 RK_PB6 GPIO_ACTIVE_HIGH>; + enable-gpios = <&gpio0 RK_PC1 GPIO_ACTIVE_HIGH>; + host-wake-gpios = <&gpio0 RK_PB5 GPIO_ACTIVE_HIGH>; + }; +}; + +&uart2 { + status = "okay"; +}; + +&usb_host0_xhci { + phys = <&usb2phy0_otg>; + phy-names = "usb2-phy"; + status = "okay"; +}; + +&usb_host1_xhci { + status = "okay"; +}; + +&usb2phy0 { + status = "okay"; +}; + +&usb2phy0_otg { + status = "okay"; +}; + +&usb2phy0_host { + phy-supply = <&vcc5v0_host>; + status = "okay"; +}; + +&vop { + assigned-clocks = <&cru DCLK_VOP0>, <&cru DCLK_VOP1>; + assigned-clock-parents = <&pmucru PLL_HPLL>, <&cru PLL_VPLL>; + status = "okay"; +}; + +&vop_mmu { + status = "okay"; +}; + +&vp0 { + vp0_out_hdmi: endpoint@ROCKCHIP_VOP2_EP_HDMI0 { + reg = ; + remote-endpoint = <&hdmi_in_vp0>; + }; +}; + +&vp1 { + vp1_out_dsi0: endpoint@ROCKCHIP_VOP2_EP_MIPI0 { + reg = ; + remote-endpoint = <&dsi0_in_vp1>; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts index 854d02b46e6fcd..59843a7a199c24 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts +++ b/arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts @@ -31,8 +31,9 @@ fan: gpio_fan { compatible = "gpio-fan"; gpios = <&gpio0 RK_PD5 GPIO_ACTIVE_HIGH>; - gpio-fan,speed-map = <0 0 - 4500 1>; + gpio-fan,speed-map = + < 0 0>, + <4500 1>; pinctrl-names = "default"; pinctrl-0 = <&fan_en_h>; #cooling-cells = <2>; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-radxa-cm3-io.dts b/arch/arm64/boot/dts/rockchip/rk3566-radxa-cm3-io.dts index 1b1c67d5b1ef33..3ae24e39450a2d 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-radxa-cm3-io.dts +++ b/arch/arm64/boot/dts/rockchip/rk3566-radxa-cm3-io.dts @@ -14,6 +14,7 @@ compatible = "radxa,cm3-io", "radxa,cm3", "rockchip,rk3566"; aliases { + ethernet0 = &gmac1; mmc1 = &sdmmc0; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-roc-pc.dts b/arch/arm64/boot/dts/rockchip/rk3566-roc-pc.dts index 938092fce18661..63eea27293fe93 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-roc-pc.dts +++ b/arch/arm64/boot/dts/rockchip/rk3566-roc-pc.dts @@ -12,6 +12,7 @@ compatible = "firefly,rk3566-roc-pc", "rockchip,rk3566"; aliases { + ethernet0 = &gmac1; mmc0 = &sdmmc0; mmc1 = &sdhci; mmc2 = &sdmmc1; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-soquartz-blade.dts b/arch/arm64/boot/dts/rockchip/rk3566-soquartz-blade.dts index 4e49bebf548b48..fdbf1c78324229 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-soquartz-blade.dts +++ b/arch/arm64/boot/dts/rockchip/rk3566-soquartz-blade.dts @@ -13,6 +13,10 @@ model = "PINE64 RK3566 SOQuartz on Blade carrier board"; compatible = "pine64,soquartz-blade", "pine64,soquartz", "rockchip,rk3566"; + aliases { + ethernet0 = &gmac1; + }; + /* labeled VCC3V0_SD in schematic to not conflict with PMIC regulator */ vcc3v0_sd: vcc3v0-sd-regulator { compatible = "regulator-fixed"; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-soquartz-cm4.dts b/arch/arm64/boot/dts/rockchip/rk3566-soquartz-cm4.dts index cddf6cd2fecb1b..6ed3fa4aee34f2 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-soquartz-cm4.dts +++ b/arch/arm64/boot/dts/rockchip/rk3566-soquartz-cm4.dts @@ -8,6 +8,10 @@ model = "Pine64 RK3566 SoQuartz with CM4-IO Carrier Board"; compatible = "pine64,soquartz-cm4io", "pine64,soquartz", "rockchip,rk3566"; + aliases { + ethernet0 = &gmac1; + }; + /* labeled +12v in schematic */ vcc12v_dcin: vcc12v-dcin-regulator { compatible = "regulator-fixed"; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-soquartz-model-a.dts b/arch/arm64/boot/dts/rockchip/rk3566-soquartz-model-a.dts index 2208dbfb7f0a3c..f2095dfa4eaf6e 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-soquartz-model-a.dts +++ b/arch/arm64/boot/dts/rockchip/rk3566-soquartz-model-a.dts @@ -8,6 +8,10 @@ model = "PINE64 RK3566 SOQuartz on Model A carrier board"; compatible = "pine64,soquartz-model-a", "pine64,soquartz", "rockchip,rk3566"; + aliases { + ethernet0 = &gmac1; + }; + /* labeled DCIN_12V in schematic */ vcc12v_dcin: vcc12v-dcin-regulator { compatible = "regulator-fixed"; diff --git a/arch/arm64/boot/dts/rockchip/rk3566-soquartz.dtsi b/arch/arm64/boot/dts/rockchip/rk3566-soquartz.dtsi index 63bae36b8f7e7d..bfb7b952f4c5e8 100644 --- a/arch/arm64/boot/dts/rockchip/rk3566-soquartz.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3566-soquartz.dtsi @@ -12,7 +12,6 @@ compatible = "pine64,soquartz", "rockchip,rk3566"; aliases { - ethernet0 = &gmac1; mmc0 = &sdmmc0; mmc1 = &sdhci; mmc2 = &sdmmc1; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-evb.dts b/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-evb.dts new file mode 100644 index 00000000000000..d4c70835e0fe28 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5-evb.dts @@ -0,0 +1,214 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2023 Rockchip Electronics Co., Ltd. + * + */ + +/dts-v1/; + +#include +#include "rk3588-coolpi-cm5.dtsi" + +/ { + model = "RK3588 CoolPi CM5 EVB"; + compatible = "coolpi,pi-cm5-evb", "coolpi,pi-cm5", "rockchip,rk3588"; + + backlight: backlight { + compatible = "pwm-backlight"; + enable-gpios = <&gpio4 RK_PA3 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&bl_en>; + power-supply = <&vcc12v_dcin>; + pwms = <&pwm2 0 25000 0>; + }; + + leds: leds { + compatible = "gpio-leds"; + + green_led: led-0 { + color = ; + function = LED_FUNCTION_STATUS; + gpios = <&gpio3 RK_PB7 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + }; + }; + + vcc12v_dcin: vcc12v-dcin-regulator { + compatible = "regulator-fixed"; + regulator-name = "vcc12v_dcin"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + }; + + vcc5v0_sys: vcc5v0-sys-regulator { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_sys"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc12v_dcin>; + }; + + vcc3v3_sys: vcc3v3-sys-regulator { + compatible = "regulator-fixed"; + regulator-name = "vcc3v3_sys"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc12v_dcin>; + }; + + vcc3v3_lcd: vcc3v3-lcd-regulator { + compatible = "regulator-fixed"; + regulator-name = "vcc3v3_lcd"; + enable-active-high; + gpio = <&gpio1 RK_PC4 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&lcdpwr_en>; + vin-supply = <&vcc3v3_sys>; + }; + + vcc5v0_usb30_host: vcc5v0-usb30-host-regulator { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_host"; + regulator-boot-on; + regulator-always-on; + enable-active-high; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&gpio1 RK_PD5 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&usb_host_pwren>; + vin-supply = <&vcc5v0_sys>; + }; + + vcc5v0_usb30_otg: vcc5v0-usb30-otg-regulator { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_otg"; + regulator-boot-on; + regulator-always-on; + enable-active-high; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpios = <&gpio0 RK_PA0 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&usb_otg_pwren>; + vin-supply = <&vcc5v0_sys>; + }; +}; + +/* M.2 E-Key */ +&pcie2x1l1 { + reset-gpios = <&gpio4 RK_PA2 GPIO_ACTIVE_HIGH>; + vpcie3v3-supply = <&vcc3v3_sys>; + pinctrl-names = "default"; + pinctrl-0 = <&pcie_clkreq &pcie_wake &pcie_rst &wifi_pwron &bt_pwron>; + status = "okay"; +}; + +&pcie30phy { + status = "okay"; +}; + +&pcie3x2 { + reset-gpios = <&gpio3 RK_PB0 GPIO_ACTIVE_HIGH>; + vpcie3v3-supply = <&vcc3v3_sys>; + status = "okay"; +}; + +/* M.2 M-Key ssd */ +&pcie3x4 { + reset-gpios = <&gpio4 RK_PB6 GPIO_ACTIVE_HIGH>; + vpcie3v3-supply = <&vcc3v3_sys>; + status = "okay"; +}; + +&pinctrl { + lcd { + lcdpwr_en: lcdpwr-en { + rockchip,pins = <1 RK_PC4 RK_FUNC_GPIO &pcfg_pull_down>; + }; + + bl_en: bl-en { + rockchip,pins = <4 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + usb { + usb_host_pwren: usb-host-pwren { + rockchip,pins = <1 RK_PD5 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + usb_otg_pwren: usb-otg-pwren { + rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + wifi { + bt_pwron: bt-pwron { + rockchip,pins = <3 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + pcie_clkreq: pcie-clkreq { + rockchip,pins = <4 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + pcie_rst: pcie-rst { + rockchip,pins = <4 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + wifi_pwron: wifi-pwron { + rockchip,pins = <3 RK_PB1 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + pcie_wake: pcie-wake { + rockchip,pins = <4 RK_PA1 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; +}; + +&pwm2 { + status = "okay"; +}; + +&sata1 { + status = "okay"; +}; + +&u2phy2 { + status = "okay"; +}; + +&u2phy3 { + status = "okay"; +}; + +&u2phy2_host { + phy-supply = <&vcc5v0_usb30_host>; + status = "okay"; +}; + +&u2phy3_host { + phy-supply = <&vcc5v0_usb30_host>; + status = "okay"; +}; + +&usb_host0_ehci { + status = "okay"; +}; + +&usb_host0_ohci { + status = "okay"; +}; + +&usb_host1_ehci { + status = "okay"; +}; + +&usb_host1_ohci { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5.dtsi new file mode 100644 index 00000000000000..0b02f4d6e00331 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3588-coolpi-cm5.dtsi @@ -0,0 +1,650 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2023 Rockchip Electronics Co., Ltd. + * + */ + +/dts-v1/; + +#include +#include +#include +#include "rk3588.dtsi" + +/ { + compatible = "coolpi,pi-cm5", "rockchip,rk3588"; + + aliases { + mmc0 = &sdhci; + mmc1 = &sdio; + mmc2 = &sdmmc; + serial2 = &uart2; + }; + + analog-sound { + compatible = "audio-graph-card"; + dais = <&i2s0_8ch_p0>; + label = "rk3588-es8316"; + routing = "MIC2", "Mic Jack", + "Headphones", "HPOL", + "Headphones", "HPOR"; + widgets = "Microphone", "Mic Jack", + "Headphone", "Headphones"; + }; + + chosen { + stdout-path = "serial2:1500000n8"; + }; + + avdd0v85_pcie20: avdd0v85-pcie20-regulator { + compatible = "regulator-fixed"; + regulator-name = "avdd0v85_pcie20"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + vin-supply = <&vdd_0v85_s0>; + }; + + avdd1v8_pcie20: avdd1v8-pcie20-regulator { + compatible = "regulator-fixed"; + regulator-name = "avdd1v8_pcie20"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&avcc_1v8_s0>; + }; + + avdd0v75_pcie30: avdd0v75-pcie30-regulator { + compatible = "regulator-fixed"; + regulator-name = "avdd0v75_pcie30"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + vin-supply = <&avdd_0v75_s0>; + }; + + pcie30_avdd1v8: avdd1v8-pcie30-regulator { + compatible = "regulator-fixed"; + regulator-name = "pcie30_avdd1v8"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&avcc_1v8_s0>; + }; +}; + +&combphy0_ps { + status = "okay"; +}; + +&combphy1_ps { + status = "okay"; +}; + +&combphy2_psu { + status = "okay"; +}; + +&cpu_b0 { + cpu-supply = <&vdd_cpu_big0_s0>; +}; + +&cpu_b1 { + cpu-supply = <&vdd_cpu_big0_s0>; +}; + +&cpu_b2 { + cpu-supply = <&vdd_cpu_big1_s0>; +}; + +&cpu_b3 { + cpu-supply = <&vdd_cpu_big1_s0>; +}; + +&cpu_l0 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&cpu_l1 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&cpu_l2 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&cpu_l3 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&gmac0 { + clock_in_out = "output"; + phy-handle = <&rgmii_phy>; + phy-mode = "rgmii-rxid"; + pinctrl-0 = <&gmac0_miim + &gmac0_tx_bus2 + &gmac0_rx_bus2 + &gmac0_rgmii_clk + &gmac0_rgmii_bus>; + pinctrl-names = "default"; + rx_delay = <0x00>; + tx_delay = <0x43>; + status = "okay"; +}; + +&i2c0 { + pinctrl-0 = <&i2c0m2_xfer>; + status = "okay"; + + vdd_cpu_big0_s0: regulator@42 { + compatible = "rockchip,rk8602"; + reg = <0x42>; + fcs,suspend-voltage-selector = <1>; + regulator-name = "vdd_cpu_big0_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <1050000>; + regulator-ramp-delay = <2300>; + vin-supply = <&vcc5v0_sys>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_cpu_big1_s0: regulator@43 { + compatible = "rockchip,rk8603", "rockchip,rk8602"; + reg = <0x43>; + fcs,suspend-voltage-selector = <1>; + regulator-name = "vdd_cpu_big1_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <1050000>; + regulator-ramp-delay = <2300>; + vin-supply = <&vcc5v0_sys>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; +}; + +&i2c2 { + status = "okay"; + + vdd_npu_s0: regulator@42 { + compatible = "rockchip,rk8602"; + reg = <0x42>; + fcs,suspend-voltage-selector = <1>; + regulator-name = "vdd_npu_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <2300>; + vin-supply = <&vcc5v0_sys>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; +}; + +&i2c6 { + status = "okay"; + + hym8563: rtc@51 { + compatible = "haoyu,hym8563"; + reg = <0x51>; + interrupt-parent = <&gpio0>; + interrupts = ; + #clock-cells = <0>; + clock-output-names = "hym8563"; + pinctrl-names = "default"; + pinctrl-0 = <&hym8563_int>; + wakeup-source; + }; +}; + +&i2c7 { + pinctrl-0 = <&i2c7m0_xfer>; + status = "okay"; + + es8316: audio-codec@11 { + compatible = "everest,es8316"; + reg = <0x11>; + assigned-clocks = <&cru I2S0_8CH_MCLKOUT>; + assigned-clock-rates = <12288000>; + clocks = <&cru I2S0_8CH_MCLKOUT>; + clock-names = "mclk"; + #sound-dai-cells = <0>; + + port { + es8316_p0_0: endpoint { + remote-endpoint = <&i2s0_8ch_p0_0>; + }; + }; + }; +}; + +&i2s0_8ch { + pinctrl-0 = <&i2s0_lrck + &i2s0_mclk + &i2s0_sclk + &i2s0_sdi0 + &i2s0_sdo0>; + status = "okay"; + + i2s0_8ch_p0: port { + i2s0_8ch_p0_0: endpoint { + dai-format = "i2s"; + mclk-fs = <256>; + remote-endpoint = <&es8316_p0_0>; + }; + }; +}; + +&mdio0 { + rgmii_phy: ethernet-phy@1 { + /* YT8531C/H */ + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0x1>; + pinctrl-names = "default"; + pinctrl-0 = <&yt8531_rst>; + reset-assert-us = <20000>; + reset-deassert-us = <100000>; + reset-gpios = <&gpio4 RK_PB3 GPIO_ACTIVE_LOW>; + }; +}; + +/* ethernet */ +&pcie2x1l2 { + reset-gpios = <&gpio3 RK_PD1 GPIO_ACTIVE_HIGH>; + vpcie3v3-supply = <&vcc3v3_sys>; + pinctrl-names = "default"; + pinctrl-0 = <&yt6801_isolate>; + status = "okay"; +}; + +&pinctrl { + hym8563 { + hym8563_int: hym8563-int { + rockchip,pins = <0 RK_PD4 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + yt6801 { + yt6801_isolate: yt6801-isolate { + rockchip,pins = <1 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + yt8531 { + yt8531_rst: yt8531-rst { + rockchip,pins = <4 RK_PB3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; + +&saradc { + vref-supply = <&vcc_1v8_s0>; + status = "okay"; +}; + +&sdhci { + bus-width = <8>; + max-frequency = <200000000>; + mmc-hs400-1_8v; + mmc-hs400-enhanced-strobe; + no-sdio; + no-sd; + non-removable; + status = "okay"; +}; + +&sdmmc { + bus-width = <4>; + cap-mmc-highspeed; + cap-sd-highspeed; + disable-wp; + max-frequency = <150000000>; + no-sdio; + no-mmc; + sd-uhs-sdr104; + vqmmc-supply = <&vccio_sd_s0>; + status = "okay"; +}; + +&spi2 { + assigned-clocks = <&cru CLK_SPI2>; + assigned-clock-rates = <200000000>; + num-cs = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&spi2m2_cs0 &spi2m2_pins>; + status = "okay"; + + pmic@0 { + compatible = "rockchip,rk806"; + reg = <0x0>; + interrupt-parent = <&gpio0>; + interrupts = <7 IRQ_TYPE_LEVEL_LOW>; + gpio-controller; + #gpio-cells = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>, + <&rk806_dvs2_null>, <&rk806_dvs3_null>; + spi-max-frequency = <1000000>; + vcc1-supply = <&vcc5v0_sys>; + vcc2-supply = <&vcc5v0_sys>; + vcc3-supply = <&vcc5v0_sys>; + vcc4-supply = <&vcc5v0_sys>; + vcc5-supply = <&vcc5v0_sys>; + vcc6-supply = <&vcc5v0_sys>; + vcc7-supply = <&vcc5v0_sys>; + vcc8-supply = <&vcc5v0_sys>; + vcc9-supply = <&vcc5v0_sys>; + vcc10-supply = <&vcc5v0_sys>; + vcc11-supply = <&vcc_2v0_pldo_s3>; + vcc12-supply = <&vcc5v0_sys>; + vcc13-supply = <&vcc_2v0_pldo_s3>; + vcc14-supply = <&vcc_2v0_pldo_s3>; + vcca-supply = <&vcc5v0_sys>; + + rk806_dvs1_null: dvs1-null-pins { + pins = "gpio_pwrctrl2"; + function = "pin_fun0"; + }; + + rk806_dvs2_null: dvs2-null-pins { + pins = "gpio_pwrctrl2"; + function = "pin_fun0"; + }; + + rk806_dvs3_null: dvs3-null-pins { + pins = "gpio_pwrctrl3"; + function = "pin_fun0"; + }; + + regulators { + vdd_gpu_s0: vdd_gpu_mem_s0: dcdc-reg1 { + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + regulator-name = "vdd_gpu_s0"; + regulator-enable-ramp-delay = <400>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_cpu_lit_s0: vdd_cpu_lit_mem_s0: dcdc-reg2 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + regulator-name = "vdd_cpu_lit_s0"; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_log_s0: dcdc-reg3 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <675000>; + regulator-max-microvolt = <750000>; + regulator-ramp-delay = <12500>; + regulator-name = "vdd_log_s0"; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <750000>; + }; + }; + + vdd_vdenc_s0: vdd_vdenc_mem_s0: dcdc-reg4 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + regulator-name = "vdd_vdenc_s0"; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_ddr_s0: dcdc-reg5 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <675000>; + regulator-max-microvolt = <900000>; + regulator-ramp-delay = <12500>; + regulator-name = "vdd_ddr_s0"; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <850000>; + }; + }; + + vdd2_ddr_s3: dcdc-reg6 { + regulator-always-on; + regulator-boot-on; + regulator-name = "vdd2_ddr_s3"; + + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vcc_2v0_pldo_s3: dcdc-reg7 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <2000000>; + regulator-max-microvolt = <2000000>; + regulator-ramp-delay = <12500>; + regulator-name = "vdd_2v0_pldo_s3"; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <2000000>; + }; + }; + + vcc_3v3_s3: dcdc-reg8 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc_3v3_s3"; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vddq_ddr_s0: dcdc-reg9 { + regulator-always-on; + regulator-boot-on; + regulator-name = "vddq_ddr_s0"; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_1v8_s3: dcdc-reg10 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc_1v8_s3"; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + avcc_1v8_s0: pldo-reg1 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "avcc_1v8_s0"; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_1v8_s0: pldo-reg2 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc_1v8_s0"; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + avdd_1v2_s0: pldo-reg3 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-name = "avdd_1v2_s0"; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_3v3_s0: pldo-reg4 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-ramp-delay = <12500>; + regulator-name = "vcc_3v3_s0"; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vccio_sd_s0: pldo-reg5 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-ramp-delay = <12500>; + regulator-name = "vccio_sd_s0"; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + pldo6_s3: pldo-reg6 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "pldo6_s3"; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vdd_0v75_s3: nldo-reg1 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + regulator-name = "vdd_0v75_s3"; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <750000>; + }; + }; + + vdd_ddr_pll_s0: nldo-reg2 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-name = "vdd_ddr_pll_s0"; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <850000>; + }; + }; + + avdd_0v75_s0: nldo-reg3 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + regulator-name = "avdd_0v75_s0"; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_0v85_s0: nldo-reg4 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-name = "vdd_0v85_s0"; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_0v75_s0: nldo-reg5 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + regulator-name = "vdd_0v75_s0"; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + }; + }; +}; + +&tsadc { + status = "okay"; +}; + +&uart2 { + pinctrl-0 = <&uart2m0_xfer>; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6a-io.dts b/arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6a-io.dts index b5154389207873..be6a4f4f90f68b 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6a-io.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6a-io.dts @@ -12,10 +12,6 @@ compatible = "edgeble,neural-compute-module-6a-io", "edgeble,neural-compute-module-6a", "rockchip,rk3588"; - aliases { - serial2 = &uart2; - }; - chosen { stdout-path = "serial2:1500000n8"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6b-io.dts b/arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6b-io.dts index 9933765e409790..070baeb63431f9 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6b-io.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-edgeble-neu6b-io.dts @@ -9,13 +9,9 @@ / { model = "Edgeble Neu6B IO Board"; - compatible = "edgeble,neural-compute-module-6b-io", + compatible = "edgeble,neural-compute-module-6a-io", "edgeble,neural-compute-module-6b", "rockchip,rk3588"; - aliases { - serial2 = &uart2; - }; - chosen { stdout-path = "serial2:1500000n8"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts b/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts index b9d789d57862c2..ac7c677b0fb9c3 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-evb1-v10.dts @@ -16,8 +16,8 @@ compatible = "rockchip,rk3588-evb1-v10", "rockchip,rk3588"; aliases { + ethernet0 = &gmac0; mmc0 = &sdhci; - serial2 = &uart2; }; chosen { @@ -56,6 +56,63 @@ }; }; + analog-sound { + compatible = "simple-audio-card"; + pinctrl-names = "default"; + pinctrl-0 = <&hp_detect>; + simple-audio-card,name = "RK3588 EVB1 Audio"; + simple-audio-card,aux-devs = <&_headphone>, <&_speaker>; + simple-audio-card,bitclock-master = <&masterdai>; + simple-audio-card,format = "i2s"; + simple-audio-card,frame-master = <&masterdai>; + simple-audio-card,hp-det-gpio = <&gpio1 RK_PD5 GPIO_ACTIVE_LOW>; + simple-audio-card,mclk-fs = <256>; + simple-audio-card,pin-switches = "Headphones", "Speaker"; + simple-audio-card,routing = + "Speaker Amplifier INL", "LOUT2", + "Speaker Amplifier INR", "ROUT2", + "Speaker", "Speaker Amplifier OUTL", + "Speaker", "Speaker Amplifier OUTR", + "Headphones Amplifier INL", "LOUT1", + "Headphones Amplifier INR", "ROUT1", + "Headphones", "Headphones Amplifier OUTL", + "Headphones", "Headphones Amplifier OUTR", + "LINPUT1", "Onboard Microphone", + "RINPUT1", "Onboard Microphone", + "LINPUT2", "Microphone Jack", + "RINPUT2", "Microphone Jack"; + simple-audio-card,widgets = + "Microphone", "Microphone Jack", + "Microphone", "Onboard Microphone", + "Headphone", "Headphones", + "Speaker", "Speaker"; + + simple-audio-card,cpu { + sound-dai = <&i2s0_8ch>; + }; + + masterdai: simple-audio-card,codec { + sound-dai = <&es8388>; + system-clock-frequency = <12288000>; + }; + }; + + amp_headphone: headphone-amplifier { + compatible = "simple-audio-amplifier"; + enable-gpios = <&gpio1 RK_PD2 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&headphone_amplifier_en>; + sound-name-prefix = "Headphones Amplifier"; + }; + + amp_speaker: speaker-amplifier { + compatible = "simple-audio-amplifier"; + enable-gpios = <&gpio1 RK_PD3 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&speaker_amplifier_en>; + sound-name-prefix = "Speaker Amplifier"; + }; + backlight: backlight { compatible = "pwm-backlight"; power-supply = <&vcc12v_dcin>; @@ -240,6 +297,32 @@ }; }; +&i2c7 { + status = "okay"; + + es8388: audio-codec@11 { + compatible = "everest,es8388"; + reg = <0x11>; + clocks = <&cru I2S0_8CH_MCLKOUT>; + assigned-clocks = <&cru I2S0_8CH_MCLKOUT>; + assigned-clock-rates = <12288000>; + AVDD-supply = <&avcc_1v8_codec_s0>; + DVDD-supply = <&avcc_1v8_codec_s0>; + HPVDD-supply = <&vcc_3v3_s0>; + PVDD-supply = <&vcc_3v3_s0>; + #sound-dai-cells = <0>; + }; +}; + +&i2s0_8ch { + pinctrl-0 = <&i2s0_lrck + &i2s0_mclk + &i2s0_sclk + &i2s0_sdi0 + &i2s0_sdo0>; + status = "okay"; +}; + &mdio0 { rgmii_phy: ethernet-phy@1 { /* RTL8211F */ @@ -273,6 +356,20 @@ }; &pinctrl { + audio { + hp_detect: headphone-detect { + rockchip,pins = <1 RK_PD5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + headphone_amplifier_en: headphone-amplifier-en { + rockchip,pins = <1 RK_PD2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + speaker_amplifier_en: speaker-amplifier-en { + rockchip,pins = <1 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + rtl8111 { rtl8111_isolate: rtl8111-isolate { rockchip,pins = <1 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts b/arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts new file mode 100644 index 00000000000000..4ce70fb75a307b --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts @@ -0,0 +1,803 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2023 Theobroma Systems Design und Consulting GmbH + */ + +/dts-v1/; +#include +#include +#include +#include +#include +#include "rk3588.dtsi" + +/ { + model = "Theobroma Systems RK3588-SBC Jaguar"; + compatible = "tsd,rk3588-jaguar", "rockchip,rk3588"; + + adc-keys { + compatible = "adc-keys"; + io-channels = <&saradc 0>; + io-channel-names = "buttons"; + keyup-threshold-microvolt = <1800000>; + poll-interval = <100>; + + /* Can be controlled through SW2 but also GPIO1 on CP2102 on P20 */ + button-bios-disable { + label = "BIOS_DISABLE"; + linux,code = ; + press-threshold-microvolt = <0>; + }; + }; + + aliases { + ethernet0 = &gmac0; + mmc0 = &sdhci; + mmc1 = &sdmmc; + rtc0 = &rtc_twi; + }; + + chosen { + stdout-path = "serial2:115200n8"; + }; + + /* DCIN is 12-24V but standard is 12V */ + dc_12v: dc-12v-regulator { + compatible = "regulator-fixed"; + regulator-name = "dc_12v"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + }; + + emmc_pwrseq: emmc-pwrseq { + compatible = "mmc-pwrseq-emmc"; + pinctrl-0 = <&emmc_reset>; + pinctrl-names = "default"; + reset-gpios = <&gpio2 RK_PA3 GPIO_ACTIVE_HIGH>; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&led1_pin>; + status = "okay"; + + /* LED1 on PCB */ + led-1 { + gpios = <&gpio1 RK_PD4 GPIO_ACTIVE_HIGH>; + function = LED_FUNCTION_HEARTBEAT; + linux,default-trigger = "heartbeat"; + color = ; + }; + }; + + pps { + compatible = "pps-gpio"; + gpios = <&gpio0 RK_PD5 GPIO_ACTIVE_HIGH>; + }; + + vcc_1v1_nldo_s3: vcc-1v1-nldo-s3-regulator { + compatible = "regulator-fixed"; + regulator-name = "vcc_1v1_nldo_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + vin-supply = <&vcc5v0_sys>; + }; + + vcc_1v2_s3: vcc-1v2-s3-regulator { + compatible = "regulator-fixed"; + regulator-name = "vcc_1v2_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + vin-supply = <&vcc5v0_sys>; + }; + + /* Exposed on P14 and P15 */ + vcc_2v8_s3: vcc-2v8-s3-regulator { + compatible = "regulator-fixed"; + regulator-name = "vcc_2v8_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + vin-supply = <&vcc_3v3_s3>; + }; + + vcc_5v0_usb_a: vcc-5v0-usb-a-regulator { + compatible = "regulator-fixed"; + regulator-name = "usb_a_vcc"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc5v0_sys>; + gpio = <&gpio1 RK_PB4 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + vcc_5v0_usb_c1: vcc-5v0-usb-c1-regulator { + compatible = "regulator-fixed"; + regulator-name = "5v_usbc1"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc5v0_usb>; + gpio = <&gpio4 RK_PB5 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + vcc_5v0_usb_c2: vcc-5v0-usb-c2-regulator { + compatible = "regulator-fixed"; + regulator-name = "5v_usbc2"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc5v0_usb>; + gpio = <&gpio4 RK_PB6 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + vcc3v3_mdot2: vcc3v3-mdot2-regulator { + compatible = "regulator-fixed"; + regulator-name = "vcc3v3_mdot2"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&dc_12v>; + }; + + vcc5v0_sys: vcc5v0-sys-regulator { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_sys"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&dc_12v>; + }; + + vcc5v0_usb: vcc5v0-usb-regulator { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_usb"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc5v0_sys>; + }; +}; + +&combphy1_ps { + status = "okay"; +}; + +&cpu_b0 { + cpu-supply = <&vdd_cpu_big0_s0>; +}; + +&cpu_b1 { + cpu-supply = <&vdd_cpu_big0_s0>; +}; + +&cpu_b2 { + cpu-supply = <&vdd_cpu_big1_s0>; +}; + +&cpu_b3 { + cpu-supply = <&vdd_cpu_big1_s0>; +}; + +&cpu_l0 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&cpu_l1 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&cpu_l2 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&cpu_l3 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&gmac0 { + clock_in_out = "output"; + phy-handle = <&rgmii_phy>; + phy-mode = "rgmii"; + phy-supply = <&vcc_1v2_s3>; + pinctrl-names = "default"; + pinctrl-0 = <&gmac0_miim + &gmac0_rx_bus2 + &gmac0_tx_bus2 + &gmac0_rgmii_clk + &gmac0_rgmii_bus + ð0_pins + ð_reset>; + tx_delay = <0x10>; + rx_delay = <0x10>; + snps,reset-gpio = <&gpio4 RK_PC3 GPIO_ACTIVE_LOW>; + snps,reset-active-low; + snps,reset-delays-us = <0 10000 100000>; + + status = "okay"; +}; + +&gpio1 { + mdot2e-w-disable1-n-hog { + gpios = ; + output-low; + line-name = "m.2 E-key W_DISABLE1#"; + gpio-hog; + }; +}; + +&gpio4 { + mdot2e-w-disable2-n-hog { + gpios = ; + output-low; + line-name = "m.2 E-key W_DISABLE2#"; + gpio-hog; + }; +}; + +&i2c0 { + pinctrl-0 = <&i2c0m2_xfer>; + status = "okay"; + + fan@18 { + compatible = "ti,amc6821"; + reg = <0x18>; + }; + + vdd_npu_s0: regulator@42 { + compatible = "rockchip,rk8602"; + reg = <0x42>; + fcs,suspend-voltage-selector = <1>; + regulator-name = "vdd_npu_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <2300>; + vin-supply = <&vcc5v0_sys>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_cpu_big1_s0: regulator@43 { + compatible = "rockchip,rk8603", "rockchip,rk8602"; + reg = <0x43>; + fcs,suspend-voltage-selector = <1>; + regulator-name = "vdd_cpu_big1_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <1050000>; + regulator-ramp-delay = <2300>; + vin-supply = <&vcc5v0_sys>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + rtc_twi: rtc@6f { + compatible = "isil,isl1208"; + reg = <0x6f>; + }; +}; + +&i2c1 { + pinctrl-0 = <&i2c1m4_xfer>; +}; + +&i2c6 { + pinctrl-0 = <&i2c6m4_xfer>; +}; + +&i2c7 { + status = "okay"; + + /* SE050 Secure Element at 0x48; GPIO1_A4 for enable pin */ + + /* Also on 0x55 */ + eeprom@54 { + compatible = "st,24c04", "atmel,24c04"; + reg = <0x54>; + pagesize = <16>; + vcc-supply = <&vcc_3v3_s3>; + }; +}; + +&i2c8 { + pinctrl-0 = <&i2c8m2_xfer>; + status = "okay"; + + vdd_cpu_big0_s0: regulator@42 { + compatible = "rockchip,rk8602"; + reg = <0x42>; + fcs,suspend-voltage-selector = <1>; + regulator-name = "vdd_cpu_big0_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <1050000>; + regulator-ramp-delay = <2300>; + vin-supply = <&vcc5v0_sys>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; +}; + +&mdio0 { + rgmii_phy: ethernet-phy@6 { + /* KSZ9031 or KSZ9131 */ + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0x6>; + clocks = <&cru REFCLKO25M_ETH0_OUT>; + }; +}; + +&pcie2x1l0 { + reset-gpios = <&gpio4 RK_PB3 GPIO_ACTIVE_HIGH>; /* WIFI_PERST0# */ + vpcie3v3-supply = <&vcc3v3_mdot2>; + status = "okay"; +}; + +&pinctrl { + emmc { + emmc_reset: emmc-reset { + rockchip,pins = <2 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + ethernet { + eth_reset: eth-reset { + rockchip,pins = <4 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + leds { + led1_pin: led1-pin { + rockchip,pins = <1 RK_PD4 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; + +&saradc { + vref-supply = <&vcc_1v8_s0>; + status = "okay"; +}; + +&sdhci { + bus-width = <8>; + cap-mmc-highspeed; + mmc-ddr-1_8v; + mmc-hs200-1_8v; + mmc-hs400-1_8v; + mmc-hs400-enhanced-strobe; + mmc-pwrseq = <&emmc_pwrseq>; + no-sdio; + no-sd; + non-removable; + pinctrl-names = "default"; + pinctrl-0 = <&emmc_bus8 &emmc_cmd &emmc_clk &emmc_data_strobe>; + supports-cqe; + vmmc-supply = <&vcc_3v3_s3>; + vqmmc-supply = <&vcc_1v8_s3>; + status = "okay"; +}; + +&sdmmc { + broken-cd; + bus-width = <4>; + cap-sd-highspeed; + disable-wp; + max-frequency = <150000000>; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc_bus4 &sdmmc_cmd &sdmmc_clk>; + sd-uhs-sdr12; + sd-uhs-sdr25; + sd-uhs-sdr50; + sd-uhs-ddr50; + sd-uhs-sdr104; + vmmc-supply = <&vcc_3v3_s3>; + vqmmc-supply = <&vccio_sd_s0>; + status = "okay"; +}; + +&spi2 { + assigned-clocks = <&cru CLK_SPI2>; + assigned-clock-rates = <200000000>; + num-cs = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&spi2m2_cs0 &spi2m2_pins>; + status = "okay"; + + pmic@0 { + compatible = "rockchip,rk806"; + reg = <0x0>; + interrupt-parent = <&gpio0>; + interrupts = <7 IRQ_TYPE_LEVEL_LOW>; + gpio-controller; + #gpio-cells = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>, + <&rk806_dvs2_null>, <&rk806_dvs3_null>; + spi-max-frequency = <1000000>; + system-power-controller; + vcc1-supply = <&vcc5v0_sys>; + vcc2-supply = <&vcc5v0_sys>; + vcc3-supply = <&vcc5v0_sys>; + vcc4-supply = <&vcc5v0_sys>; + vcc5-supply = <&vcc5v0_sys>; + vcc6-supply = <&vcc5v0_sys>; + vcc7-supply = <&vcc5v0_sys>; + vcc8-supply = <&vcc5v0_sys>; + vcc9-supply = <&vcc5v0_sys>; + vcc10-supply = <&vcc5v0_sys>; + vcc11-supply = <&vcc_2v0_pldo_s3>; + vcc12-supply = <&vcc5v0_sys>; + vcc13-supply = <&vcc_1v1_nldo_s3>; + vcc14-supply = <&vcc_1v1_nldo_s3>; + vcca-supply = <&vcc5v0_sys>; + + rk806_dvs1_null: dvs1-null-pins { + pins = "gpio_pwrctrl2"; + function = "pin_fun0"; + }; + + rk806_dvs2_null: dvs2-null-pins { + pins = "gpio_pwrctrl2"; + function = "pin_fun0"; + }; + + rk806_dvs3_null: dvs3-null-pins { + pins = "gpio_pwrctrl3"; + function = "pin_fun0"; + }; + + regulators { + vdd_gpu_s0: dcdc-reg1 { + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + regulator-name = "vdd_gpu_s0"; + regulator-enable-ramp-delay = <400>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_cpu_lit_s0: dcdc-reg2 { + regulator-name = "vdd_cpu_lit_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_log_s0: dcdc-reg3 { + regulator-name = "vdd_log_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <675000>; + regulator-max-microvolt = <750000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <750000>; + }; + }; + + vdd_vdenc_s0: dcdc-reg4 { + regulator-name = "vdd_vdenc_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_ddr_s0: dcdc-reg5 { + regulator-name = "vdd_ddr_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <675000>; + regulator-max-microvolt = <900000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <850000>; + }; + }; + + vdd2_ddr_s3: dcdc-reg6 { + regulator-name = "vdd2_ddr_s3"; + regulator-always-on; + regulator-boot-on; + + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vcc_2v0_pldo_s3: dcdc-reg7 { + regulator-name = "vdd_2v0_pldo_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <2000000>; + regulator-max-microvolt = <2000000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <2000000>; + }; + }; + + vcc_3v3_s3: dcdc-reg8 { + regulator-name = "vcc_3v3_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vddq_ddr_s0: dcdc-reg9 { + regulator-name = "vddq_ddr_s0"; + regulator-always-on; + regulator-boot-on; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_1v8_s3: dcdc-reg10 { + regulator-name = "vcc_1v8_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vcca_1v8_s0: pldo-reg1 { + regulator-name = "vcca_1v8_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_1v8_s0: pldo-reg2 { + regulator-name = "vcc_1v8_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vdda_1v2_s0: pldo-reg3 { + regulator-name = "vdda_1v2_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcca_3v3_s0: pldo-reg4 { + regulator-name = "vcca_3v3_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vccio_sd_s0: pldo-reg5 { + regulator-name = "vccio_sd_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + pldo6_s3: pldo-reg6 { + regulator-name = "pldo6_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vdd_0v75_s3: nldo-reg1 { + regulator-name = "vdd_0v75_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <750000>; + }; + }; + + vdda_ddr_pll_s0: nldo-reg2 { + regulator-name = "vdda_ddr_pll_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <850000>; + }; + }; + + vdda_0v75_s0: nldo-reg3 { + regulator-name = "vdda_0v75_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdda_0v85_s0: nldo-reg4 { + regulator-name = "vdda_0v85_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_0v75_s0: nldo-reg5 { + regulator-name = "vdd_0v75_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + }; + }; +}; + +&tsadc { + status = "okay"; +}; + +&u2phy2 { + status = "okay"; +}; + +&u2phy2_host { + phy-supply = <&vcc_5v0_usb_a>; + status = "okay"; +}; + +&u2phy3 { + status = "okay"; +}; + +&u2phy3_host { + status = "okay"; +}; + +/* Mule-ATtiny debug UART; typically baudrate 9600 */ +&uart0 { + pinctrl-0 = <&uart0m0_xfer>; + status = "okay"; +}; + +/* Main debug interface on P20 micro-USB B port and P21 header */ +&uart2 { + pinctrl-0 = <&uart2m0_xfer>; + status = "okay"; +}; + +/* RS485 on P19 */ +&uart3 { + pinctrl-0 = <&uart3m2_xfer &uart3_rtsn>; + linux,rs485-enabled-at-boot-time; + status = "okay"; +}; + +/* Mule-ATtiny UPDI flashing UART */ +&uart7 { + pinctrl-0 = <&uart7m0_xfer>; + status = "okay"; +}; + +/* host0 on P10 USB-A */ +&usb_host0_ehci { + status = "okay"; +}; + +/* host0 on P10 USB-A */ +&usb_host0_ohci { + status = "okay"; +}; + +/* host1 on M.2 E-key */ +&usb_host1_ehci { + status = "okay"; +}; + +/* host1 on M.2 E-key */ +&usb_host1_ohci { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dts b/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dts index 97af4f91282854..d7722772ecd8a0 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-nanopc-t6.dts @@ -19,7 +19,6 @@ aliases { mmc0 = &sdhci; mmc1 = &sdmmc; - serial2 = &uart2; }; chosen { @@ -537,13 +536,12 @@ }; &sdmmc { - max-frequency = <200000000>; - no-sdio; - no-mmc; bus-width = <4>; cap-mmc-highspeed; cap-sd-highspeed; disable-wp; + no-mmc; + no-sdio; sd-uhs-sdr104; vmmc-supply = <&vcc_3v3_s3>; vqmmc-supply = <&vccio_sd_s0>; @@ -570,6 +568,8 @@ pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>, <&rk806_dvs2_null>, <&rk806_dvs3_null>; + system-power-controller; + vcc1-supply = <&vcc4v0_sys>; vcc2-supply = <&vcc4v0_sys>; vcc3-supply = <&vcc4v0_sys>; @@ -590,7 +590,7 @@ #gpio-cells = <2>; rk806_dvs1_null: dvs1-null-pins { - pins = "gpio_pwrctrl2"; + pins = "gpio_pwrctrl1"; function = "pin_fun0"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts index 298c183d6f4fc9..3e660ff6cd5ff3 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-orangepi-5-plus.dts @@ -19,7 +19,6 @@ aliases { mmc0 = &sdhci; mmc1 = &sdmmc; - serial2 = &uart2; }; chosen { diff --git a/arch/arm64/boot/dts/rockchip/rk3588-quartzpro64.dts b/arch/arm64/boot/dts/rockchip/rk3588-quartzpro64.dts index 5c59f9571dce6e..87a0abf95f7d4f 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-quartzpro64.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-quartzpro64.dts @@ -17,9 +17,9 @@ compatible = "pine64,quartzpro64", "rockchip,rk3588"; aliases { + ethernet0 = &gmac0; mmc0 = &sdhci; mmc1 = &sdmmc; - serial2 = &uart2; }; chosen { diff --git a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts index 741f631db345f0..a0e303c3a1dc6d 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588-rock-5b.dts @@ -14,7 +14,6 @@ mmc0 = &sdhci; mmc1 = &sdmmc; mmc2 = &sdio; - serial2 = &uart2; }; chosen { @@ -138,6 +137,10 @@ status = "okay"; }; +&combphy2_psu { + status = "okay"; +}; + &cpu_b0 { cpu-supply = <&vdd_cpu_big0_s0>; }; @@ -423,6 +426,8 @@ pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>, <&rk806_dvs2_null>, <&rk806_dvs3_null>; + system-power-controller; + vcc1-supply = <&vcc5v0_sys>; vcc2-supply = <&vcc5v0_sys>; vcc3-supply = <&vcc5v0_sys>; @@ -443,7 +448,7 @@ #gpio-cells = <2>; rk806_dvs1_null: dvs1-null-pins { - pins = "gpio_pwrctrl2"; + pins = "gpio_pwrctrl1"; function = "pin_fun0"; }; @@ -765,3 +770,7 @@ &usb_host1_ohci { status = "okay"; }; + +&usb_host2_xhci { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-turing-rk1.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-turing-rk1.dtsi index d88c0e85235651..dc08da518a76d1 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-turing-rk1.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-turing-rk1.dtsi @@ -19,8 +19,6 @@ aliases { ethernet0 = &gmac1; mmc0 = &sdhci; - serial2 = &uart2; - serial9 = &uart9; }; fan: pwm-fan { diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-coolpi-4b.dts b/arch/arm64/boot/dts/rockchip/rk3588s-coolpi-4b.dts new file mode 100644 index 00000000000000..ef4f058c20ff15 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3588s-coolpi-4b.dts @@ -0,0 +1,812 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2023 Rockchip Electronics Co., Ltd. + * + * https://cool-pi.com/topic/130/coolpi-4b-product-spec-introduction + * + */ + +/dts-v1/; + +#include +#include +#include +#include "rk3588s.dtsi" + +/ { + model = "RK3588S CoolPi 4 Model B"; + compatible = "coolpi,pi-4b", "rockchip,rk3588s"; + + aliases { + mmc0 = &sdhci; + mmc1 = &sdio; + mmc2 = &sdmmc; + }; + + analog-sound { + compatible = "audio-graph-card"; + dais = <&i2s0_8ch_p0>; + label = "rk3588-es8316"; + routing = "MIC2", "Mic Jack", + "Headphones", "HPOL", + "Headphones", "HPOR"; + widgets = "Microphone", "Mic Jack", + "Headphone", "Headphones"; + }; + + chosen { + stdout-path = "serial2:1500000n8"; + }; + + leds: leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&gpio_leds>; + + led0: led-green { + color = ; + function = LED_FUNCTION_STATUS; + gpios = <&gpio0 RK_PD0 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "heartbeat"; + }; + + led1: led-red { + color = ; + default-state = "off"; + function = LED_FUNCTION_WLAN; + gpios = <&gpio0 RK_PC4 GPIO_ACTIVE_HIGH>; + linux,default-trigger = "phy0tx"; + }; + }; + + sdio_pwrseq: sdio-pwrseq { + compatible = "mmc-pwrseq-simple"; + clocks = <&hym8563>; + clock-names = "ext_clock"; + pinctrl-names = "default"; + pinctrl-0 = <&wifi_enable_h>; + /* + * On the module itself this is one of these (depending + * on the actual card populated): + * - SDIO_RESET_L_WL_REG_ON + * - PDN (power down when low) + */ + post-power-on-delay-ms = <200>; + reset-gpios = <&gpio0 RK_PC7 GPIO_ACTIVE_LOW>; + }; + + vcc12v_dcin: vcc12v-dcin-regulator { + compatible = "regulator-fixed"; + regulator-name = "vcc12v_dcin"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + }; + + vcc5v0_sys: vcc5v0-sys-regulator { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_sys"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc12v_dcin>; + }; + + vcc5v0_usbdcin: vcc5v0-usbdcin-regulator { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_usbdcin"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc12v_dcin>; + }; + + vcc5v0_usb: vcc5v0-usb-regulator { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_usb"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc5v0_usbdcin>; + }; + + avdd0v85_pcie20: avdd0v85-pcie20-regulator { + compatible = "regulator-fixed"; + regulator-name = "avdd0v85_pcie20"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + vin-supply = <&vdd_0v85_s0>; + }; + + avdd1v8_pcie20: avdd1v8-pcie20-regulator { + compatible = "regulator-fixed"; + regulator-name = "avdd1v8_pcie20"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&avcc_1v8_s0>; + }; + + vcc3v3_mipi: vcc3v3-mipi-regulator { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio3 RK_PC2 GPIO_ACTIVE_HIGH>; + regulator-name = "vcc3v3_mipi"; + regulator-boot-on; + regulator-always-on; + vin-supply = <&vcc_3v3_s3>; + }; + + vcc5v0_host: vcc5v0-host-regulator { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio3 RK_PC0 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&vcc5v0_host_en>; + regulator-name = "vcc5v0_host"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc5v0_sys>; + }; + + vcc5v0_otg: vcc5v0-otg-regulator { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio3 RK_PC1 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&vcc5v0_u3host_en>; + regulator-name = "vcc5v0_otg"; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc5v0_sys>; + }; + + vcc_1v1_nldo_s3: vcc-1v1-nldo-s3-regulator { + compatible = "regulator-fixed"; + regulator-name = "vcc_1v1_nldo_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + vin-supply = <&vcc5v0_sys>; + }; +}; + +&combphy0_ps { + status = "okay"; +}; + +&combphy2_psu { + status = "okay"; +}; + +&cpu_l0 { + cpu-supply = <&vdd_cpu_lit_s0>; +}; + +&cpu_b0 { + cpu-supply = <&vdd_cpu_big0_s0>; +}; + +&cpu_b2 { + cpu-supply = <&vdd_cpu_big1_s0>; +}; + +&i2c0 { + pinctrl-0 = <&i2c0m2_xfer>; + status = "okay"; + + vdd_cpu_big0_s0: regulator@42 { + compatible = "rockchip,rk8602"; + reg = <0x42>; + fcs,suspend-voltage-selector = <1>; + regulator-name = "vdd_cpu_big0_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <1050000>; + regulator-ramp-delay = <2300>; + vin-supply = <&vcc5v0_sys>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_cpu_big1_s0: regulator@43 { + compatible = "rockchip,rk8603", "rockchip,rk8602"; + reg = <0x43>; + fcs,suspend-voltage-selector = <1>; + regulator-name = "vdd_cpu_big1_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <1050000>; + regulator-ramp-delay = <2300>; + vin-supply = <&vcc5v0_sys>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; +}; + +&i2c2 { + status = "okay"; + + vdd_npu_s0: regulator@42 { + compatible = "rockchip,rk8602"; + reg = <0x42>; + fcs,suspend-voltage-selector = <1>; + regulator-name = "vdd_npu_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <2300>; + vin-supply = <&vcc5v0_sys>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; +}; + +&i2c6 { + pinctrl-0 = <&i2c6m3_xfer>; + status = "okay"; + + hym8563: rtc@51 { + compatible = "haoyu,hym8563"; + reg = <0x51>; + interrupt-parent = <&gpio0>; + interrupts = ; + #clock-cells = <0>; + clock-output-names = "hym8563"; + pinctrl-names = "default"; + pinctrl-0 = <&hym8563_int>; + }; +}; + +&i2c7 { + pinctrl-0 = <&i2c7m0_xfer>; + status = "okay"; + + es8316: audio-codec@11 { + compatible = "everest,es8316"; + reg = <0x11>; + assigned-clocks = <&cru I2S0_8CH_MCLKOUT>; + assigned-clock-rates = <12288000>; + clocks = <&cru I2S0_8CH_MCLKOUT>; + clock-names = "mclk"; + #sound-dai-cells = <0>; + + port { + es8316_p0_0: endpoint { + remote-endpoint = <&i2s0_8ch_p0_0>; + }; + }; + }; +}; + +&i2s0_8ch { + pinctrl-0 = <&i2s0_lrck + &i2s0_mclk + &i2s0_sclk + &i2s0_sdi0 + &i2s0_sdo0>; + status = "okay"; + + i2s0_8ch_p0: port { + i2s0_8ch_p0_0: endpoint { + dai-format = "i2s"; + mclk-fs = <256>; + remote-endpoint = <&es8316_p0_0>; + }; + }; +}; + +&pcie2x1l2 { + pinctrl-names = "default"; + pinctrl-0 = <&rtl8111_isolate>; + reset-gpios = <&gpio3 RK_PD1 GPIO_ACTIVE_HIGH>; + status = "okay"; +}; + +&pinctrl { + hym8563 { + hym8563_int: hym8563-int { + rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + led { + gpio_leds: gpio-leds { + rockchip,pins = <0 RK_PC4 RK_FUNC_GPIO &pcfg_pull_down>, + <0 RK_PD0 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; + + rtl8111 { + rtl8111_isolate: rtl8111-isolate { + rockchip,pins = <1 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + sdio-pwrseq { + wifi_enable_h: wifi-enable-h { + rockchip,pins = <0 RK_PC7 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; + + usb { + vcc5v0_host_en: vcc5v0-host-en { + rockchip,pins = <3 RK_PC0 RK_FUNC_GPIO &pcfg_pull_none>, + <4 RK_PB5 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + vcc5v0_u3host_en: vcc5v0-u3host-en { + rockchip,pins = <3 RK_PC1 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + wireless-bluetooth { + bt_reset_gpio: bt-reset-pin { + rockchip,pins = <0 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + bt_wake_gpio: bt-wake-pin { + rockchip,pins = <0 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + bt_wake_host_irq: bt-wake-host-irq { + rockchip,pins = <0 RK_PC5 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; + + wireless-wlan { + wifi_host_wake_irq: wifi-host-wake-irq { + rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_down>; + }; + + wifi_poweren_pin: wifi-poweren-pin { + rockchip,pins = <1 RK_PD3 RK_FUNC_GPIO &pcfg_pull_up>; + }; + }; +}; + +&pwm2 { + pinctrl-0 = <&pwm2m1_pins>; + status = "okay"; +}; + +&pwm13 { + pinctrl-names = "active"; + pinctrl-0 = <&pwm13m2_pins>; + status = "okay"; +}; + +&saradc { + vref-supply = <&vcc_1v8_s0>; + status = "okay"; +}; + +&sdhci { + bus-width = <8>; + max-frequency = <200000000>; + mmc-hs400-1_8v; + mmc-hs400-enhanced-strobe; + no-sdio; + no-sd; + non-removable; + status = "okay"; +}; + +&sdio { + bus-width = <4>; + cap-sd-highspeed; + cap-sdio-irq; + disable-wp; + keep-power-in-suspend; + max-frequency = <150000000>; + mmc-pwrseq = <&sdio_pwrseq>; + no-sd; + no-mmc; + non-removable; + pinctrl-names = "default"; + pinctrl-0 = <&sdiom1_pins>,<&wifi_poweren_pin>; + status = "okay"; +}; + +&sdmmc { + bus-width = <4>; + cap-mmc-highspeed; + cap-sd-highspeed; + disable-wp; + max-frequency = <150000000>; + no-sdio; + no-mmc; + sd-uhs-sdr104; + vmmc-supply = <&vcc_3v3_s3>; + vqmmc-supply = <&vccio_sd_s0>; + status = "okay"; +}; + +&spi2 { + assigned-clocks = <&cru CLK_SPI2>; + assigned-clock-rates = <200000000>; + num-cs = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&spi2m2_cs0 &spi2m2_pins>; + status = "okay"; + + pmic@0 { + compatible = "rockchip,rk806"; + reg = <0x0>; + interrupt-parent = <&gpio0>; + interrupts = <7 IRQ_TYPE_LEVEL_LOW>; + gpio-controller; + #gpio-cells = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>, + <&rk806_dvs2_null>, <&rk806_dvs3_null>; + spi-max-frequency = <1000000>; + vcc1-supply = <&vcc5v0_sys>; + vcc2-supply = <&vcc5v0_sys>; + vcc3-supply = <&vcc5v0_sys>; + vcc4-supply = <&vcc5v0_sys>; + vcc5-supply = <&vcc5v0_sys>; + vcc6-supply = <&vcc5v0_sys>; + vcc7-supply = <&vcc5v0_sys>; + vcc8-supply = <&vcc5v0_sys>; + vcc9-supply = <&vcc5v0_sys>; + vcc10-supply = <&vcc5v0_sys>; + vcc11-supply = <&vcc_2v0_pldo_s3>; + vcc12-supply = <&vcc5v0_sys>; + vcc13-supply = <&vcc_1v1_nldo_s3>; + vcc14-supply = <&vcc_1v1_nldo_s3>; + vcca-supply = <&vcc5v0_sys>; + + rk806_dvs1_null: dvs1-null-pins { + pins = "gpio_pwrctrl2"; + function = "pin_fun0"; + }; + + rk806_dvs2_null: dvs2-null-pins { + pins = "gpio_pwrctrl2"; + function = "pin_fun0"; + }; + + rk806_dvs3_null: dvs3-null-pins { + pins = "gpio_pwrctrl3"; + function = "pin_fun0"; + }; + + regulators { + vdd_gpu_s0: vdd_gpu_mem_s0: dcdc-reg1 { + regulator-name = "vdd_gpu_s0"; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + regulator-enable-ramp-delay = <400>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_cpu_lit_s0: vdd_cpu_lit_mem_s0: dcdc-reg2 { + regulator-name = "vdd_cpu_lit_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_log_s0: dcdc-reg3 { + regulator-name = "vdd_log_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <675000>; + regulator-max-microvolt = <750000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <750000>; + }; + }; + + vdd_vdenc_s0: vdd_vdenc_mem_s0: dcdc-reg4 { + regulator-name = "vdd_vdenc_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <550000>; + regulator-max-microvolt = <950000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_ddr_s0: dcdc-reg5 { + regulator-name = "vdd_ddr_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <675000>; + regulator-max-microvolt = <900000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <850000>; + }; + }; + + vdd2_ddr_s3: dcdc-reg6 { + regulator-name = "vdd2_ddr_s3"; + regulator-always-on; + regulator-boot-on; + + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vcc_2v0_pldo_s3: dcdc-reg7 { + regulator-name = "vdd_2v0_pldo_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <2000000>; + regulator-max-microvolt = <2000000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <2000000>; + }; + }; + + vcc_3v3_s3: dcdc-reg8 { + regulator-name = "vcc_3v3_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vddq_ddr_s0: dcdc-reg9 { + regulator-name = "vddq_ddr_s0"; + regulator-always-on; + regulator-boot-on; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_1v8_s3: dcdc-reg10 { + regulator-name = "vcc_1v8_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + avcc_1v8_s0: pldo-reg1 { + regulator-name = "avcc_1v8_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_1v8_s0: pldo-reg2 { + regulator-name = "vcc_1v8_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + avdd_1v2_s0: pldo-reg3 { + regulator-name = "avdd_1v2_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_3v3_s0: pldo-reg4 { + regulator-name = "vcc_3v3_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vccio_sd_s0: pldo-reg5 { + regulator-name = "vccio_sd_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-ramp-delay = <12500>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + pldo6_s3: pldo-reg6 { + regulator-name = "pldo6_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vdd_0v75_s3: nldo-reg1 { + regulator-name = "vdd_0v75_s3"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <750000>; + }; + }; + + vdd_ddr_pll_s0: nldo-reg2 { + regulator-name = "vdd_ddr_pll_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <850000>; + }; + }; + + avdd_0v75_s0: nldo-reg3 { + regulator-name = "avdd_0v75_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_0v85_s0: nldo-reg4 { + regulator-name = "vdd_0v85_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdd_0v75_s0: nldo-reg5 { + regulator-name = "vdd_0v75_s0"; + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <750000>; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + }; + }; +}; + +&tsadc { + status = "okay"; +}; + +&u2phy2 { + status = "okay"; +}; + +&u2phy3 { + status = "okay"; +}; + +&u2phy2_host { + phy-supply = <&vcc5v0_host>; + status = "okay"; +}; + +&u2phy3_host { + status = "okay"; +}; + +&uart2 { + pinctrl-0 = <&uart2m0_xfer>; + status = "okay"; +}; + +/* bt */ +&uart9 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&uart9m2_xfer &uart9m2_ctsn>; +}; + +&usb_host0_ehci { + status = "okay"; +}; + +&usb_host0_ohci { + status = "okay"; +}; + +&usb_host1_ehci { + status = "okay"; +}; + +&usb_host1_ohci { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-indiedroid-nova.dts b/arch/arm64/boot/dts/rockchip/rk3588s-indiedroid-nova.dts index 60f00ceb630e14..dc677f29a9c7fc 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-indiedroid-nova.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588s-indiedroid-nova.dts @@ -44,7 +44,6 @@ mmc0 = &sdhci; mmc1 = &sdmmc; mmc2 = &sdio; - serial2 = &uart2; }; chosen { diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-khadas-edge2.dts b/arch/arm64/boot/dts/rockchip/rk3588s-khadas-edge2.dts index 82478a45253371..f53e993c785edb 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-khadas-edge2.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588s-khadas-edge2.dts @@ -12,7 +12,6 @@ aliases { mmc0 = &sdhci; - serial2 = &uart2; }; chosen { diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dts b/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dts index e3a839a12dc6f0..25de4362af3867 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588s-orangepi-5.dts @@ -13,8 +13,8 @@ compatible = "xunlong,orangepi-5", "rockchip,rk3588s"; aliases { + ethernet0 = &gmac1; mmc0 = &sdmmc; - serial2 = &uart2; }; chosen { @@ -314,6 +314,7 @@ pinctrl-0 = <&pmic_pins>, <&rk806_dvs1_null>, <&rk806_dvs2_null>, <&rk806_dvs3_null>; spi-max-frequency = <1000000>; + system-power-controller; vcc1-supply = <&vcc5v0_sys>; vcc2-supply = <&vcc5v0_sys>; @@ -660,3 +661,7 @@ &usb_host1_ohci { status = "okay"; }; + +&usb_host2_xhci { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts b/arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts index 8347adcbd00301..2002fd0221fa30 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts +++ b/arch/arm64/boot/dts/rockchip/rk3588s-rock-5a.dts @@ -12,9 +12,9 @@ compatible = "radxa,rock-5a", "rockchip,rk3588s"; aliases { + ethernet0 = &gmac1; mmc0 = &sdhci; mmc1 = &sdmmc; - serial2 = &uart2; }; analog-sound { @@ -114,6 +114,10 @@ }; }; +&combphy2_psu { + status = "okay"; +}; + &cpu_b0 { cpu-supply = <&vdd_cpu_big0_s0>; }; @@ -734,3 +738,7 @@ &usb_host1_ohci { status = "okay"; }; + +&usb_host2_xhci { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi index 8aa0499f9b032d..36b1b7acfe6a15 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588s.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588s.dtsi @@ -18,6 +18,38 @@ #address-cells = <2>; #size-cells = <2>; + aliases { + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; + gpio4 = &gpio4; + i2c0 = &i2c0; + i2c1 = &i2c1; + i2c2 = &i2c2; + i2c3 = &i2c3; + i2c4 = &i2c4; + i2c5 = &i2c5; + i2c6 = &i2c6; + i2c7 = &i2c7; + i2c8 = &i2c8; + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + serial3 = &uart3; + serial4 = &uart4; + serial5 = &uart5; + serial6 = &uart6; + serial7 = &uart7; + serial8 = &uart8; + serial9 = &uart9; + spi0 = &spi0; + spi1 = &spi1; + spi2 = &spi2; + spi3 = &spi3; + spi4 = &spi4; + }; + cpus { #address-cells = <1>; #size-cells = <0>; @@ -362,6 +394,11 @@ #clock-cells = <0>; }; + display_subsystem: display-subsystem { + compatible = "rockchip,display-subsystem"; + ports = <&vop_out>; + }; + timer { compatible = "arm,armv8-timer"; interrupts = , @@ -474,6 +511,16 @@ reg = <0x0 0xfd58c000 0x0 0x1000>; }; + vop_grf: syscon@fd5a4000 { + compatible = "rockchip,rk3588-vop-grf", "syscon"; + reg = <0x0 0xfd5a4000 0x0 0x2000>; + }; + + vo1_grf: syscon@fd5a8000 { + compatible = "rockchip,rk3588-vo-grf", "syscon"; + reg = <0x0 0xfd5a8000 0x0 0x100>; + }; + php_grf: syscon@fd5b0000 { compatible = "rockchip,rk3588-php-grf", "syscon"; reg = <0x0 0xfd5b0000 0x0 0x1000>; @@ -593,6 +640,74 @@ status = "disabled"; }; + vop: vop@fdd90000 { + compatible = "rockchip,rk3588-vop"; + reg = <0x0 0xfdd90000 0x0 0x4200>, <0x0 0xfdd95000 0x0 0x1000>; + reg-names = "vop", "gamma-lut"; + interrupts = ; + clocks = <&cru ACLK_VOP>, + <&cru HCLK_VOP>, + <&cru DCLK_VOP0>, + <&cru DCLK_VOP1>, + <&cru DCLK_VOP2>, + <&cru DCLK_VOP3>, + <&cru PCLK_VOP_ROOT>; + clock-names = "aclk", + "hclk", + "dclk_vp0", + "dclk_vp1", + "dclk_vp2", + "dclk_vp3", + "pclk_vop"; + iommus = <&vop_mmu>; + power-domains = <&power RK3588_PD_VOP>; + rockchip,grf = <&sys_grf>; + rockchip,vop-grf = <&vop_grf>; + rockchip,vo1-grf = <&vo1_grf>; + rockchip,pmu = <&pmu>; + status = "disabled"; + + vop_out: ports { + #address-cells = <1>; + #size-cells = <0>; + + vp0: port@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + + vp1: port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + + vp2: port@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + }; + + vp3: port@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + }; + }; + }; + + vop_mmu: iommu@fdd97e00 { + compatible = "rockchip,rk3588-iommu", "rockchip,rk3568-iommu"; + reg = <0x0 0xfdd97e00 0x0 0x100>, <0x0 0xfdd97f00 0x0 0x100>; + interrupts = ; + clocks = <&cru ACLK_VOP>, <&cru HCLK_VOP>; + clock-names = "aclk", "iface"; + #iommu-cells = <0>; + power-domains = <&power RK3588_PD_VOP>; + status = "disabled"; + }; + uart0: serial@fd890000 { compatible = "rockchip,rk3588-uart", "snps,dw-apb-uart"; reg = <0x0 0xfd890000 0x0 0x100>; @@ -916,6 +1031,7 @@ reg = ; clocks = <&cru PCLK_PHP_ROOT>, <&cru ACLK_USB_ROOT>, + <&cru ACLK_USB>, <&cru HCLK_USB_ROOT>, <&cru HCLK_HOST0>, <&cru HCLK_HOST_ARB0>, diff --git a/arch/arm64/boot/dts/sprd/Makefile b/arch/arm64/boot/dts/sprd/Makefile index 97522fb0bf6682..3ce81ad7116f13 100644 --- a/arch/arm64/boot/dts/sprd/Makefile +++ b/arch/arm64/boot/dts/sprd/Makefile @@ -2,4 +2,5 @@ dtb-$(CONFIG_ARCH_SPRD) += sc9836-openphone.dtb \ sp9860g-1h10.dtb \ sp9863a-1h10.dtb \ - ums512-1h10.dtb + ums512-1h10.dtb \ + ums9620-2h10.dtb diff --git a/arch/arm64/boot/dts/sprd/ums512.dtsi b/arch/arm64/boot/dts/sprd/ums512.dtsi index 024be594c47d17..dbdb79f8e959be 100644 --- a/arch/arm64/boot/dts/sprd/ums512.dtsi +++ b/arch/arm64/boot/dts/sprd/ums512.dtsi @@ -96,7 +96,7 @@ CPU6: cpu@600 { device_type = "cpu"; - compatible = "arm,cortex-a55"; + compatible = "arm,cortex-a75"; reg = <0x0 0x600>; enable-method = "psci"; cpu-idle-states = <&CORE_PD>; @@ -104,7 +104,7 @@ CPU7: cpu@700 { device_type = "cpu"; - compatible = "arm,cortex-a55"; + compatible = "arm,cortex-a75"; reg = <0x0 0x700>; enable-method = "psci"; cpu-idle-states = <&CORE_PD>; @@ -113,7 +113,7 @@ idle-states { entry-method = "psci"; - CORE_PD: core-pd { + CORE_PD: cpu-pd { compatible = "arm,idle-state"; entry-latency-us = <4000>; exit-latency-us = <4000>; @@ -291,6 +291,7 @@ pll2: clock-controller@0 { compatible = "sprd,ums512-gc-pll"; reg = <0x0 0x100>; + clocks = <&ext_26m>; clock-names = "ext-26m"; #clock-cells = <1>; }; @@ -682,8 +683,8 @@ compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x3f040000 0 0x1000>; cpu = <&CPU0>; - clocks = <&ext_26m>, <&aon_clk CLK_CSSYS>, <&pll2 CLK_TWPLL_512M>; - clock-names = "apb_pclk", "clk_cs", "cs_src"; + clocks = <&ext_26m>; + clock-names = "apb_pclk"; out-ports { port { @@ -699,8 +700,8 @@ compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x3f140000 0 0x1000>; cpu = <&CPU1>; - clocks = <&ext_26m>, <&aon_clk CLK_CSSYS>, <&pll2 CLK_TWPLL_512M>; - clock-names = "apb_pclk", "clk_cs", "cs_src"; + clocks = <&ext_26m>; + clock-names = "apb_pclk"; out-ports { port { @@ -716,8 +717,8 @@ compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x3f240000 0 0x1000>; cpu = <&CPU2>; - clocks = <&ext_26m>, <&aon_clk CLK_CSSYS>, <&pll2 CLK_TWPLL_512M>; - clock-names = "apb_pclk", "clk_cs", "cs_src"; + clocks = <&ext_26m>; + clock-names = "apb_pclk"; out-ports { port { @@ -733,8 +734,8 @@ compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x3f340000 0 0x1000>; cpu = <&CPU3>; - clocks = <&ext_26m>, <&aon_clk CLK_CSSYS>, <&pll2 CLK_TWPLL_512M>; - clock-names = "apb_pclk", "clk_cs", "cs_src"; + clocks = <&ext_26m>; + clock-names = "apb_pclk"; out-ports { port { @@ -750,8 +751,8 @@ compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x3f440000 0 0x1000>; cpu = <&CPU4>; - clocks = <&ext_26m>, <&aon_clk CLK_CSSYS>, <&pll2 CLK_TWPLL_512M>; - clock-names = "apb_pclk", "clk_cs", "cs_src"; + clocks = <&ext_26m>; + clock-names = "apb_pclk"; out-ports { port { @@ -767,8 +768,8 @@ compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x3f540000 0 0x1000>; cpu = <&CPU5>; - clocks = <&ext_26m>, <&aon_clk CLK_CSSYS>, <&pll2 CLK_TWPLL_512M>; - clock-names = "apb_pclk", "clk_cs", "cs_src"; + clocks = <&ext_26m>; + clock-names = "apb_pclk"; out-ports { port { @@ -784,8 +785,8 @@ compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x3f640000 0 0x1000>; cpu = <&CPU6>; - clocks = <&ext_26m>, <&aon_clk CLK_CSSYS>, <&pll2 CLK_TWPLL_512M>; - clock-names = "apb_pclk", "clk_cs", "cs_src"; + clocks = <&ext_26m>; + clock-names = "apb_pclk"; out-ports { port { @@ -801,8 +802,8 @@ compatible = "arm,coresight-etm4x", "arm,primecell"; reg = <0 0x3f740000 0 0x1000>; cpu = <&CPU7>; - clocks = <&ext_26m>, <&aon_clk CLK_CSSYS>, <&pll2 CLK_TWPLL_512M>; - clock-names = "apb_pclk", "clk_cs", "cs_src"; + clocks = <&ext_26m>; + clock-names = "apb_pclk"; out-ports { port { diff --git a/arch/arm64/boot/dts/sprd/ums9620-2h10.dts b/arch/arm64/boot/dts/sprd/ums9620-2h10.dts new file mode 100644 index 00000000000000..b35671192a726c --- /dev/null +++ b/arch/arm64/boot/dts/sprd/ums9620-2h10.dts @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Unisoc UMS9620-2h10 board DTS file + * + * Copyright (C) 2023, Unisoc Inc. + */ + +/dts-v1/; + +#include "ums9620.dtsi" + +/ { + model = "Unisoc UMS9620-2H10 Board"; + + compatible = "sprd,ums9620-2h10", "sprd,ums9620"; + + aliases { + serial0 = &uart0; + serial1 = &uart1; + }; + + memory@80000000 { + device_type = "memory"; + reg = <0x0 0x80000000 0x2 0x00000000>; + }; + + chosen { + stdout-path = "serial1:921600n8"; + }; +}; + +&uart0 { + status = "okay"; +}; + +&uart1 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/sprd/ums9620.dtsi b/arch/arm64/boot/dts/sprd/ums9620.dtsi new file mode 100644 index 00000000000000..2191f0a4811b1e --- /dev/null +++ b/arch/arm64/boot/dts/sprd/ums9620.dtsi @@ -0,0 +1,245 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Unisoc UMS9620 DTS file + * + * Copyright (C) 2023, Unisoc Inc. + */ + +#include + +/ { + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu-map { + cluster0 { + core0 { + cpu = <&CPU0>; + }; + core1 { + cpu = <&CPU1>; + }; + core2 { + cpu = <&CPU2>; + }; + core3 { + cpu = <&CPU3>; + }; + core4 { + cpu = <&CPU4>; + }; + core5 { + cpu = <&CPU5>; + }; + core6 { + cpu = <&CPU6>; + }; + core7 { + cpu = <&CPU7>; + }; + }; + }; + + CPU0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x0>; + enable-method = "psci"; + cpu-idle-states = <&LIT_CORE_PD>; + }; + + CPU1: cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x100>; + enable-method = "psci"; + cpu-idle-states = <&LIT_CORE_PD>; + }; + + CPU2: cpu@200 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x200>; + enable-method = "psci"; + cpu-idle-states = <&LIT_CORE_PD>; + }; + + CPU3: cpu@300 { + device_type = "cpu"; + compatible = "arm,cortex-a55"; + reg = <0x0 0x300>; + enable-method = "psci"; + cpu-idle-states = <&LIT_CORE_PD>; + }; + + CPU4: cpu@400 { + device_type = "cpu"; + compatible = "arm,cortex-a76"; + reg = <0x0 0x400>; + enable-method = "psci"; + cpu-idle-states = <&BIG_CORE_PD>; + }; + + CPU5: cpu@500 { + device_type = "cpu"; + compatible = "arm,cortex-a76"; + reg = <0x0 0x500>; + enable-method = "psci"; + cpu-idle-states = <&BIG_CORE_PD>; + }; + + CPU6: cpu@600 { + device_type = "cpu"; + compatible = "arm,cortex-a76"; + reg = <0x0 0x600>; + enable-method = "psci"; + cpu-idle-states = <&BIG_CORE_PD>; + }; + + CPU7: cpu@700 { + device_type = "cpu"; + compatible = "arm,cortex-a76"; + reg = <0x0 0x700>; + enable-method = "psci"; + cpu-idle-states = <&BIG_CORE_PD>; + }; + }; + + idle-states { + entry-method = "psci"; + LIT_CORE_PD: cpu-pd-lit { + compatible = "arm,idle-state"; + entry-latency-us = <1000>; + exit-latency-us = <500>; + min-residency-us = <2500>; + local-timer-stop; + arm,psci-suspend-param = <0x00010000>; + }; + + BIG_CORE_PD: cpu-pd-big { + compatible = "arm,idle-state"; + entry-latency-us = <4000>; + exit-latency-us = <4000>; + min-residency-us = <10000>; + local-timer-stop; + arm,psci-suspend-param = <0x00010000>; + }; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , /* Physical Secure PPI */ + , /* Physical Non-Secure PPI */ + , /* Virtual PPI */ + ; /* Hipervisor PPI */ + }; + + pmu { + compatible = "arm,armv8-pmuv3"; + interrupts = , + , + , + , + , + , + , + ; + }; + + soc: soc { + compatible = "simple-bus"; + ranges; + #address-cells = <2>; + #size-cells = <2>; + + gic: interrupt-controller@12000000 { + compatible = "arm,gic-v3"; + reg = <0x0 0x12000000 0 0x20000>, /* GICD */ + <0x0 0x12040000 0 0x100000>; /* GICR */ + #interrupt-cells = <3>; + #address-cells = <2>; + #size-cells = <2>; + redistributor-stride = <0x0 0x20000>; /* 128KB stride */ + #redistributor-regions = <1>; + interrupt-controller; + interrupts = ; + }; + + apb@20200000 { + compatible = "simple-bus"; + ranges = <0 0 0x20200000 0x100000>; + #address-cells = <1>; + #size-cells = <1>; + + uart0: serial@0 { + compatible = "sprd,ums9620-uart", + "sprd,sc9836-uart"; + reg = <0 0x100>; + interrupts = ; + clocks = <&ext_26m>; + status = "disabled"; + }; + + uart1: serial@10000 { + compatible = "sprd,ums9620-uart", + "sprd,sc9836-uart"; + reg = <0x10000 0x100>; + interrupts = ; + clocks = <&ext_26m>; + status = "disabled"; + }; + }; + }; + + ext_26m: clk-26m { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <26000000>; + clock-output-names = "ext-26m"; + }; + + ext_4m: clk-4m { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <4000000>; + clock-output-names = "ext-4m"; + }; + + ext_32k: clk-32k { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <32768>; + clock-output-names = "ext-32k"; + }; + + rco_100m: clk-100m { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + clock-output-names = "rco-100m"; + }; + + dphy_312m5: dphy-312m5 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <312500000>; + clock-output-names = "dphy-312m5"; + }; + + dphy_416m7: dphy-416m7 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <416700000>; + clock-output-names = "dphy-416m7"; + }; +}; diff --git a/arch/arm64/boot/dts/st/stm32mp251.dtsi b/arch/arm64/boot/dts/st/stm32mp251.dtsi index 124403f5f1f497..96859d098ef8f6 100644 --- a/arch/arm64/boot/dts/st/stm32mp251.dtsi +++ b/arch/arm64/boot/dts/st/stm32mp251.dtsi @@ -140,6 +140,22 @@ }; }; + bsec: efuse@44000000 { + compatible = "st,stm32mp25-bsec"; + reg = <0x44000000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + + part_number_otp@24 { + reg = <0x24 0x4>; + }; + + package_otp@1e8 { + reg = <0x1e8 0x1>; + bits = <0 3>; + }; + }; + syscfg: syscon@44230000 { compatible = "st,stm32mp25-syscfg", "syscon"; reg = <0x44230000 0x10000>; diff --git a/arch/arm64/boot/dts/tesla/fsd.dtsi b/arch/arm64/boot/dts/tesla/fsd.dtsi index bb50a9f7db4aa0..aaffb50b8b60df 100644 --- a/arch/arm64/boot/dts/tesla/fsd.dtsi +++ b/arch/arm64/boot/dts/tesla/fsd.dtsi @@ -342,6 +342,18 @@ #clock-cells = <0>; }; + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + mfc_left: region@84000000 { + compatible = "shared-dma-pool"; + no-map; + reg = <0 0x84000000 0 0x8000000>; + }; + }; + soc: soc@0 { compatible = "simple-bus"; #address-cells = <2>; @@ -581,7 +593,7 @@ }; serial_0: serial@14180000 { - compatible = "samsung,exynos4210-uart"; + compatible = "tesla,fsd-uart", "samsung,exynos4210-uart"; reg = <0x0 0x14180000 0x0 0x100>; interrupts = ; dmas = <&pdma1 1>, <&pdma1 0>; @@ -593,7 +605,7 @@ }; serial_1: serial@14190000 { - compatible = "samsung,exynos4210-uart"; + compatible = "tesla,fsd-uart", "samsung,exynos4210-uart"; reg = <0x0 0x14190000 0x0 0x100>; interrupts = ; dmas = <&pdma1 3>, <&pdma1 2>; @@ -605,12 +617,12 @@ }; pmu_system_controller: system-controller@11400000 { - compatible = "samsung,exynos7-pmu", "syscon"; + compatible = "tesla,fsd-pmu", "samsung,exynos7-pmu", "syscon"; reg = <0x0 0x11400000 0x0 0x5000>; }; watchdog_0: watchdog@100a0000 { - compatible = "samsung,exynos7-wdt"; + compatible = "tesla,fsd-wdt", "samsung,exynos7-wdt"; reg = <0x0 0x100a0000 0x0 0x100>; interrupts = ; samsung,syscon-phandle = <&pmu_system_controller>; @@ -619,7 +631,7 @@ }; watchdog_1: watchdog@100b0000 { - compatible = "samsung,exynos7-wdt"; + compatible = "tesla,fsd-wdt", "samsung,exynos7-wdt"; reg = <0x0 0x100b0000 0x0 0x100>; interrupts = ; samsung,syscon-phandle = <&pmu_system_controller>; @@ -628,7 +640,7 @@ }; watchdog_2: watchdog@100c0000 { - compatible = "samsung,exynos7-wdt"; + compatible = "tesla,fsd-wdt", "samsung,exynos7-wdt"; reg = <0x0 0x100c0000 0x0 0x100>; interrupts = ; samsung,syscon-phandle = <&pmu_system_controller>; @@ -637,7 +649,7 @@ }; pwm_0: pwm@14100000 { - compatible = "samsung,exynos4210-pwm"; + compatible = "tesla,fsd-pwm", "samsung,exynos4210-pwm"; reg = <0x0 0x14100000 0x0 0x100>; samsung,pwm-outputs = <0>, <1>, <2>, <3>; #pwm-cells = <3>; @@ -647,7 +659,7 @@ }; pwm_1: pwm@14110000 { - compatible = "samsung,exynos4210-pwm"; + compatible = "tesla,fsd-pwm", "samsung,exynos4210-pwm"; reg = <0x0 0x14110000 0x0 0x100>; samsung,pwm-outputs = <0>, <1>, <2>, <3>; #pwm-cells = <3>; @@ -657,7 +669,7 @@ }; hsi2c_0: i2c@14200000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "tesla,fsd-hsi2c", "samsung,exynos7-hsi2c"; reg = <0x0 0x14200000 0x0 0x1000>; interrupts = ; #address-cells = <1>; @@ -670,7 +682,7 @@ }; hsi2c_1: i2c@14210000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "tesla,fsd-hsi2c", "samsung,exynos7-hsi2c"; reg = <0x0 0x14210000 0x0 0x1000>; interrupts = ; #address-cells = <1>; @@ -683,7 +695,7 @@ }; hsi2c_2: i2c@14220000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "tesla,fsd-hsi2c", "samsung,exynos7-hsi2c"; reg = <0x0 0x14220000 0x0 0x1000>; interrupts = ; #address-cells = <1>; @@ -696,7 +708,7 @@ }; hsi2c_3: i2c@14230000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "tesla,fsd-hsi2c", "samsung,exynos7-hsi2c"; reg = <0x0 0x14230000 0x0 0x1000>; interrupts = ; #address-cells = <1>; @@ -709,7 +721,7 @@ }; hsi2c_4: i2c@14240000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "tesla,fsd-hsi2c", "samsung,exynos7-hsi2c"; reg = <0x0 0x14240000 0x0 0x1000>; interrupts = ; #address-cells = <1>; @@ -722,7 +734,7 @@ }; hsi2c_5: i2c@14250000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "tesla,fsd-hsi2c", "samsung,exynos7-hsi2c"; reg = <0x0 0x14250000 0x0 0x1000>; interrupts = ; #address-cells = <1>; @@ -735,7 +747,7 @@ }; hsi2c_6: i2c@14260000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "tesla,fsd-hsi2c", "samsung,exynos7-hsi2c"; reg = <0x0 0x14260000 0x0 0x1000>; interrupts = ; #address-cells = <1>; @@ -748,7 +760,7 @@ }; hsi2c_7: i2c@14270000 { - compatible = "samsung,exynos7-hsi2c"; + compatible = "tesla,fsd-hsi2c", "samsung,exynos7-hsi2c"; reg = <0x0 0x14270000 0x0 0x1000>; interrupts = ; #address-cells = <1>; @@ -956,6 +968,15 @@ clock-names = "fin_pll", "mct"; }; + mfc: mfc@12880000 { + compatible = "tesla,fsd-mfc"; + reg = <0x0 0x12880000 0x0 0x10000>; + interrupts = ; + clock-names = "mfc"; + clocks = <&clock_mfc MFC_MFC_IPCLKPORT_ACLK>; + memory-region = <&mfc_left>; + }; + ufs: ufs@15120000 { compatible = "tesla,fsd-ufs"; reg = <0x0 0x15120000 0x0 0x200>, /* 0: HCI standard */ diff --git a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile index 77a347f9f47d57..52c1dc9103087e 100644 --- a/arch/arm64/boot/dts/ti/Makefile +++ b/arch/arm64/boot/dts/ti/Makefile @@ -9,20 +9,20 @@ # alphabetically. # Boards with AM62x SoC -k3-am625-sk-hdmi-audio-dtbs := k3-am625-sk.dtb k3-am62x-sk-hdmi-audio.dtbo -k3-am62-lp-sk-hdmi-audio-dtbs := k3-am62-lp-sk.dtb k3-am62x-sk-hdmi-audio.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am625-beagleplay.dtb +dtb-$(CONFIG_ARCH_K3) += k3-am625-beagleplay-csi2-ov5640.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am625-beagleplay-csi2-tevi-ov5640.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am625-phyboard-lyra-rdk.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-sk.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-nonwifi-dahlia.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-nonwifi-dev.dtb +dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-nonwifi-mallow.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-nonwifi-yavia.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-dahlia.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-dev.dtb +dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-mallow.dtb dtb-$(CONFIG_ARCH_K3) += k3-am625-verdin-wifi-yavia.dtb dtb-$(CONFIG_ARCH_K3) += k3-am62-lp-sk.dtb -dtb-$(CONFIG_ARCH_K3) += k3-am625-sk-hdmi-audio.dtb -dtb-$(CONFIG_ARCH_K3) += k3-am62-lp-sk-hdmi-audio.dtb # Boards with AM62Ax SoC dtb-$(CONFIG_ARCH_K3) += k3-am62a7-sk.dtb @@ -30,19 +30,19 @@ dtb-$(CONFIG_ARCH_K3) += k3-am62a7-sk.dtb # Boards with AM62Px SoC dtb-$(CONFIG_ARCH_K3) += k3-am62p5-sk.dtb +# Common overlays for SK-AM62* family of boards +dtb-$(CONFIG_ARCH_K3) += k3-am62x-sk-csi2-ov5640.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am62x-sk-csi2-tevi-ov5640.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am62x-sk-csi2-imx219.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am62x-sk-hdmi-audio.dtbo + # Boards with AM64x SoC dtb-$(CONFIG_ARCH_K3) += k3-am642-evm.dtb dtb-$(CONFIG_ARCH_K3) += k3-am642-phyboard-electra-rdk.dtb dtb-$(CONFIG_ARCH_K3) += k3-am642-sk.dtb dtb-$(CONFIG_ARCH_K3) += k3-am642-tqma64xxl-mbax4xxl.dtb - -k3-am642-tqma64xxl-mbax4xxl-sdcard-dtbs := \ - k3-am642-tqma64xxl-mbax4xxl.dtb k3-am64-tqma64xxl-mbax4xxl-sdcard.dtbo -k3-am642-tqma64xxl-mbax4xxl-wlan-dtbs := \ - k3-am642-tqma64xxl-mbax4xxl.dtb k3-am64-tqma64xxl-mbax4xxl-wlan.dtbo - -dtb-$(CONFIG_ARCH_K3) += k3-am642-tqma64xxl-mbax4xxl-sdcard.dtb -dtb-$(CONFIG_ARCH_K3) += k3-am642-tqma64xxl-mbax4xxl-wlan.dtb +dtb-$(CONFIG_ARCH_K3) += k3-am64-tqma64xxl-mbax4xxl-sdcard.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am64-tqma64xxl-mbax4xxl-wlan.dtbo # Boards with AM65x SoC k3-am654-gp-evm-dtbs := k3-am654-base-board.dtb k3-am654-base-board-rocktech-rk101-panel.dtbo @@ -67,6 +67,7 @@ k3-j721e-evm-dtbs := k3-j721e-common-proc-board.dtb k3-j721e-evm-quad-port-eth-e dtb-$(CONFIG_ARCH_K3) += k3-j721e-beagleboneai64.dtb dtb-$(CONFIG_ARCH_K3) += k3-j721e-evm.dtb dtb-$(CONFIG_ARCH_K3) += k3-j721e-evm-gesi-exp-board.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-j721e-evm-pcie0-ep.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j721e-sk.dtb # Boards with J721s2 SoC @@ -75,14 +76,59 @@ dtb-$(CONFIG_ARCH_K3) += k3-j721s2-common-proc-board.dtb dtb-$(CONFIG_ARCH_K3) += k3-j721s2-evm-gesi-exp-board.dtbo k3-j721s2-evm-dtbs := k3-j721s2-common-proc-board.dtb k3-j721s2-evm-gesi-exp-board.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j721s2-evm.dtb +dtb-$(CONFIG_ARCH_K3) += k3-j721s2-evm-pcie1-ep.dtbo # Boards with J784s4 SoC dtb-$(CONFIG_ARCH_K3) += k3-am69-sk.dtb dtb-$(CONFIG_ARCH_K3) += k3-j784s4-evm.dtb +# Build time test only, enabled by CONFIG_OF_ALL_DTBS +k3-am625-beagleplay-csi2-ov5640-dtbs := k3-am625-beagleplay.dtb \ + k3-am625-beagleplay-csi2-ov5640.dtbo +k3-am625-beagleplay-csi2-tevi-ov5640-dtbs := k3-am625-beagleplay.dtb \ + k3-am625-beagleplay-csi2-tevi-ov5640.dtbo +k3-am625-sk-csi2-imx219-dtbs := k3-am625-sk.dtb \ + k3-am62x-sk-csi2-imx219.dtbo +k3-am625-sk-csi2-ov5640-dtbs := k3-am625-sk.dtb \ + k3-am62x-sk-csi2-ov5640.dtbo +k3-am625-sk-csi2-tevi-ov5640-dtbs := k3-am625-sk.dtb \ + k3-am62x-sk-csi2-tevi-ov5640.dtbo +k3-am625-sk-hdmi-audio-dtbs := k3-am625-sk.dtb k3-am62x-sk-hdmi-audio.dtbo +k3-am62-lp-sk-hdmi-audio-dtbs := k3-am62-lp-sk.dtb k3-am62x-sk-hdmi-audio.dtbo +k3-am62a7-sk-csi2-imx219-dtbs := k3-am62a7-sk.dtb \ + k3-am62x-sk-csi2-imx219.dtbo +k3-am62a7-sk-csi2-ov5640-dtbs := k3-am62a7-sk.dtb \ + k3-am62x-sk-csi2-ov5640.dtbo +k3-am62a7-sk-csi2-tevi-ov5640-dtbs := k3-am62a7-sk.dtb \ + k3-am62x-sk-csi2-tevi-ov5640.dtbo +k3-am642-tqma64xxl-mbax4xxl-sdcard-dtbs := \ + k3-am642-tqma64xxl-mbax4xxl.dtb k3-am64-tqma64xxl-mbax4xxl-sdcard.dtbo +k3-am642-tqma64xxl-mbax4xxl-wlan-dtbs := \ + k3-am642-tqma64xxl-mbax4xxl.dtb k3-am64-tqma64xxl-mbax4xxl-wlan.dtbo +k3-j721e-evm-pcie0-ep-dtbs := k3-j721e-common-proc-board.dtb \ + k3-j721e-evm-pcie0-ep.dtbo +k3-j721s2-evm-pcie1-ep-dtbs := k3-j721s2-common-proc-board.dtb \ + k3-j721s2-evm-pcie1-ep.dtbo +dtb- += k3-am625-beagleplay-csi2-ov5640.dtb \ + k3-am625-beagleplay-csi2-tevi-ov5640.dtb \ + k3-am625-sk-csi2-imx219.dtb \ + k3-am625-sk-csi2-ov5640.dtb \ + k3-am625-sk-csi2-tevi-ov5640.dtb \ + k3-am625-sk-hdmi-audio.dtb \ + k3-am62-lp-sk-hdmi-audio.dtb \ + k3-am62a7-sk-csi2-imx219.dtb \ + k3-am62a7-sk-csi2-ov5640.dtb \ + k3-am642-tqma64xxl-mbax4xxl-sdcard.dtb \ + k3-am642-tqma64xxl-mbax4xxl-wlan.dtb \ + k3-j721e-evm-pcie0-ep.dtb \ + k3-j721s2-evm-pcie1-ep.dtb + # Enable support for device-tree overlays +DTC_FLAGS_k3-am625-beagleplay += -@ DTC_FLAGS_k3-am625-sk += -@ DTC_FLAGS_k3-am62-lp-sk += -@ +DTC_FLAGS_k3-am62a7-sk += -@ +DTC_FLAGS_k3-am642-tqma64xxl-mbax4xxl += -@ DTC_FLAGS_k3-am6548-iot2050-advanced-m2 += -@ DTC_FLAGS_k3-j721e-common-proc-board += -@ DTC_FLAGS_k3-j721s2-common-proc-board += -@ diff --git a/arch/arm64/boot/dts/ti/k3-am62-main.dtsi b/arch/arm64/boot/dts/ti/k3-am62-main.dtsi index e5c64c86d1d5ae..464b7565d085d7 100644 --- a/arch/arm64/boot/dts/ti/k3-am62-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62-main.dtsi @@ -121,8 +121,13 @@ <0x00 0x4c000000 0x00 0x20000>, <0x00 0x4a820000 0x00 0x20000>, <0x00 0x4aa40000 0x00 0x20000>, - <0x00 0x4bc00000 0x00 0x100000>; - reg-names = "gcfg", "bchanrt", "rchanrt", "tchanrt", "ringrt"; + <0x00 0x4bc00000 0x00 0x100000>, + <0x00 0x48600000 0x00 0x8000>, + <0x00 0x484a4000 0x00 0x2000>, + <0x00 0x484c2000 0x00 0x2000>, + <0x00 0x48420000 0x00 0x2000>; + reg-names = "gcfg", "bchanrt", "rchanrt", "tchanrt", "ringrt", + "ring", "tchan", "rchan", "bchan"; msi-parent = <&inta_main_dmss>; #dma-cells = <3>; @@ -138,8 +143,13 @@ reg = <0x00 0x485c0000 0x00 0x100>, <0x00 0x4a800000 0x00 0x20000>, <0x00 0x4aa00000 0x00 0x40000>, - <0x00 0x4b800000 0x00 0x400000>; - reg-names = "gcfg", "rchanrt", "tchanrt", "ringrt"; + <0x00 0x4b800000 0x00 0x400000>, + <0x00 0x485e0000 0x00 0x10000>, + <0x00 0x484a0000 0x00 0x2000>, + <0x00 0x484c0000 0x00 0x2000>, + <0x00 0x48430000 0x00 0x1000>; + reg-names = "gcfg", "rchanrt", "tchanrt", "ringrt", + "ring", "tchan", "rchan", "rflow"; msi-parent = <&inta_main_dmss>; #dma-cells = <2>; @@ -502,6 +512,9 @@ main_gpio0: gpio@600000 { compatible = "ti,am64-gpio", "ti,keystone-gpio"; reg = <0x0 0x00600000 0x0 0x100>; + gpio-ranges = <&main_pmx0 0 0 32>, + <&main_pmx0 32 33 38>, + <&main_pmx0 70 72 22>; gpio-controller; #gpio-cells = <2>; interrupt-parent = <&main_gpio_intr>; @@ -520,6 +533,10 @@ compatible = "ti,am64-gpio", "ti,keystone-gpio"; reg = <0x0 0x00601000 0x0 0x100>; gpio-controller; + gpio-ranges = <&main_pmx0 0 94 41>, + <&main_pmx0 41 136 6>, + <&main_pmx0 47 143 3>, + <&main_pmx0 50 149 2>; #gpio-cells = <2>; interrupt-parent = <&main_gpio_intr>; interrupts = <180>, <181>, <182>, @@ -675,6 +692,15 @@ }; }; + gpu: gpu@fd00000 { + compatible = "ti,am62-gpu", "img,img-axe"; + reg = <0x00 0x0fd00000 0x00 0x20000>; + clocks = <&k3_clks 187 0>; + clock-names = "core"; + interrupts = ; + power-domains = <&k3_pds 187 TI_SCI_PD_EXCLUSIVE>; + }; + cpsw3g: ethernet@8000000 { compatible = "ti,am642-cpsw-nuss"; #address-cells = <2>; @@ -965,4 +991,66 @@ power-domains = <&k3_pds 192 TI_SCI_PD_EXCLUSIVE>; status = "disabled"; }; + + ti_csi2rx0: ticsi2rx@30102000 { + compatible = "ti,j721e-csi2rx-shim"; + dmas = <&main_bcdma 0 0x4700 0>; + dma-names = "rx0"; + reg = <0x00 0x30102000 0x00 0x1000>; + power-domains = <&k3_pds 182 TI_SCI_PD_EXCLUSIVE>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + status = "disabled"; + + cdns_csi2rx0: csi-bridge@30101000 { + compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; + reg = <0x00 0x30101000 0x00 0x1000>; + clocks = <&k3_clks 182 0>, <&k3_clks 182 3>, <&k3_clks 182 0>, + <&k3_clks 182 0>, <&k3_clks 182 4>, <&k3_clks 182 4>; + clock-names = "sys_clk", "p_clk", "pixel_if0_clk", + "pixel_if1_clk", "pixel_if2_clk", "pixel_if3_clk"; + phys = <&dphy0>; + phy-names = "dphy"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "disabled"; + }; + + csi0_port1: port@1 { + reg = <1>; + status = "disabled"; + }; + + csi0_port2: port@2 { + reg = <2>; + status = "disabled"; + }; + + csi0_port3: port@3 { + reg = <3>; + status = "disabled"; + }; + + csi0_port4: port@4 { + reg = <4>; + status = "disabled"; + }; + }; + }; + }; + + dphy0: phy@30110000 { + compatible = "cdns,dphy-rx"; + reg = <0x00 0x30110000 0x00 0x1100>; + #phy-cells = <0>; + power-domains = <&k3_pds 185 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; + }; diff --git a/arch/arm64/boot/dts/ti/k3-am62-verdin-dahlia.dtsi b/arch/arm64/boot/dts/ti/k3-am62-verdin-dahlia.dtsi index 013357d17d4826..bf6d27e70bc484 100644 --- a/arch/arm64/boot/dts/ti/k3-am62-verdin-dahlia.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62-verdin-dahlia.dtsi @@ -214,6 +214,5 @@ /* Verdin UART_2 */ &wkup_uart0 { - /* FIXME: WKUP UART0 is used by DM firmware */ - status = "reserved"; + status = "okay"; }; diff --git a/arch/arm64/boot/dts/ti/k3-am62-verdin-dev.dtsi b/arch/arm64/boot/dts/ti/k3-am62-verdin-dev.dtsi index 6701cb8974bbd7..680071688dcb63 100644 --- a/arch/arm64/boot/dts/ti/k3-am62-verdin-dev.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62-verdin-dev.dtsi @@ -235,6 +235,5 @@ /* Verdin UART_2 */ &wkup_uart0 { - /* FIXME: WKUP UART0 is used by DM firmware */ - status = "reserved"; + status = "okay"; }; diff --git a/arch/arm64/boot/dts/ti/k3-am62-verdin-mallow.dtsi b/arch/arm64/boot/dts/ti/k3-am62-verdin-mallow.dtsi new file mode 100644 index 00000000000000..17b93534f6588b --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am62-verdin-mallow.dtsi @@ -0,0 +1,188 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright 2023 Toradex + * + * Common dtsi for Verdin AM62 SoM on Mallow carrier board + * + * https://www.toradex.com/computer-on-modules/verdin-arm-family/ti-am62 + * https://www.toradex.com/products/carrier-board/mallow-carrier-board + */ + +#include + +/ { + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_qspi1_clk_gpio>, + <&pinctrl_qspi1_cs_gpio>, + <&pinctrl_qspi1_io0_gpio>, + <&pinctrl_qspi1_io1_gpio>; + + /* SODIMM 52 - USER_LED_1_RED */ + led-0 { + color = ; + function = LED_FUNCTION_DEBUG; + function-enumerator = <1>; + gpios = <&main_gpio0 0 GPIO_ACTIVE_HIGH>; + }; + + /* SODIMM 54 - USER_LED_1_GREEN */ + led-1 { + color = ; + function = LED_FUNCTION_DEBUG; + function-enumerator = <1>; + gpios = <&main_gpio0 11 GPIO_ACTIVE_HIGH>; + }; + + /* SODIMM 56 - USER_LED_2_RED */ + led-2 { + color = ; + function = LED_FUNCTION_DEBUG; + function-enumerator = <2>; + gpios = <&main_gpio0 3 GPIO_ACTIVE_HIGH>; + }; + + /* SODIMM 58 - USER_LED_2_GREEN */ + led-3 { + color = ; + function = LED_FUNCTION_DEBUG; + function-enumerator = <2>; + gpios = <&main_gpio0 4 GPIO_ACTIVE_HIGH>; + }; + }; +}; + +/* Verdin ETH */ +&cpsw3g { + status = "okay"; +}; + +/* Verdin MDIO */ +&cpsw3g_mdio { + status = "okay"; +}; + +/* Verdin ETH_1*/ +&cpsw_port1 { + status = "okay"; +}; + +/* Verdin PWM_1 and PWM_2*/ +&epwm0 { + status = "okay"; +}; + +/* Verdin PWM_3 DSI */ +&epwm1 { + status = "okay"; +}; + +&main_gpio0 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_ctrl_sleep_moci>, + <&pinctrl_gpio_1>, + <&pinctrl_gpio_2>, + <&pinctrl_gpio_3>, + <&pinctrl_gpio_4>; +}; + +/* Verdin I2C_1 */ +&main_i2c1 { + status = "okay"; + + /* Temperature sensor */ + sensor@4f { + compatible = "ti,tmp1075"; + reg = <0x4f>; + }; + + /* EEPROM */ + eeprom@57 { + compatible = "st,24c02", "atmel,24c02"; + reg = <0x57>; + pagesize = <16>; + }; +}; + +/* Verdin I2C_2 DSI */ +&main_i2c2 { + status = "okay"; +}; + +/* Verdin I2C_4 CSI */ +&main_i2c3 { + status = "okay"; +}; + +/* Verdin CAN_1 */ +&main_mcan0 { + status = "okay"; +}; + +/* Verdin SPI_1 */ +&main_spi1 { + pinctrl-0 = <&pinctrl_spi1>, + <&pinctrl_spi1_cs0>, + <&pinctrl_qspi1_cs2_gpio>; + cs-gpios = <0>, <&main_gpio0 12 GPIO_ACTIVE_LOW>; + status = "okay"; +}; + +/* Verdin UART_3 */ +&main_uart0 { + status = "okay"; +}; + +/* Verdin UART_1 */ +&main_uart1 { + status = "okay"; +}; + +/* Verdin I2C_3_HDMI */ +&mcu_i2c0 { + status = "okay"; +}; + +/* Verdin CAN_2 */ +&mcu_mcan0 { + status = "okay"; +}; + +/* Verdin UART_4 */ +&mcu_uart0 { + status = "okay"; +}; + +/* Verdin SD_1 */ +&sdhci1 { + status = "okay"; +}; + +/* Verdin USB_1 */ +&usbss0 { + status = "okay"; +}; + +&usb0 { + status = "okay"; +}; + +/* Verdin USB_2 */ +&usbss1 { + status = "okay"; +}; + +&usb1 { + status = "okay"; +}; + +/* Verdin CTRL_WAKE1_MICO# */ +&verdin_gpio_keys { + status = "okay"; +}; + +/* Verdin UART_2 */ +&wkup_uart0 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am62-verdin-yavia.dtsi b/arch/arm64/boot/dts/ti/k3-am62-verdin-yavia.dtsi index c685df7deaeed9..997dfafd27eb46 100644 --- a/arch/arm64/boot/dts/ti/k3-am62-verdin-yavia.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62-verdin-yavia.dtsi @@ -207,6 +207,5 @@ /* Verdin UART_2 */ &wkup_uart0 { - /* FIXME: WKUP UART0 is used by DM firmware */ - status = "reserved"; + status = "okay"; }; diff --git a/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi b/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi index 5db52f2372534b..6a06724b6d168b 100644 --- a/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62-verdin.dtsi @@ -233,6 +233,13 @@ >; }; + /* Verdin SPI_1 CS as GPIO */ + pinctrl_qspi1_io4_gpio: main-gpio0-7-default-pins { + pinctrl-single,pins = < + AM62X_IOPAD(0x001c, PIN_INPUT, 7) /* (J23) OSPI0_D4.GPIO0_7 */ /* SODIMM 202 */ + >; + }; + /* Verdin QSPI_1_CS# as GPIO (conflict with Verdin QSPI_1 interface) */ pinctrl_qspi1_cs_gpio: main-gpio0-11-default-pins { pinctrl-single,pins = < @@ -599,12 +606,18 @@ pinctrl_spi1: main-spi1-default-pins { pinctrl-single,pins = < AM62X_IOPAD(0x0020, PIN_INPUT, 1) /* (J25) OSPI0_D5.SPI1_CLK */ /* SODIMM 196 */ - AM62X_IOPAD(0x001c, PIN_INPUT, 1) /* (J23) OSPI0_D4.SPI1_CS0 */ /* SODIMM 202 */ AM62X_IOPAD(0x0024, PIN_INPUT, 1) /* (H25) OSPI0_D6.SPI1_D0 */ /* SODIMM 200 */ AM62X_IOPAD(0x0028, PIN_INPUT, 1) /* (J22) OSPI0_D7.SPI1_D1 */ /* SODIMM 198 */ >; }; + /* Verdin SPI_1 CS */ + pinctrl_spi1_cs0: main-spi1-cs0-default-pins { + pinctrl-single,pins = < + AM62X_IOPAD(0x001c, PIN_INPUT, 1) /* (J23) OSPI0_D4.SPI1_CS0 */ /* SODIMM 202 */ + >; + }; + /* ETH_25MHz_CLK */ pinctrl_eth_clock: main-system-clkout0-default-pins { pinctrl-single,pins = < @@ -1278,7 +1291,7 @@ /* Verdin SPI_1 */ &main_spi1 { pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_spi1>; + pinctrl-0 = <&pinctrl_spi1>, <&pinctrl_spi1_cs0>; ti,pindir-d0-out-d1-in; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/ti/k3-am625-beagleplay-csi2-ov5640.dtso b/arch/arm64/boot/dts/ti/k3-am625-beagleplay-csi2-ov5640.dtso new file mode 100644 index 00000000000000..5e80ca7033ba7e --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am625-beagleplay-csi2-ov5640.dtso @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ALINX AN5641 & Digilent PCam 5C - OV5640 camera module + * Copyright (C) 2022-2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_ov5640_fixed: ov5640-xclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <12000000>; + }; +}; + +&main_gpio0 { + p11-hog { + /* P11 - CSI2_CAMERA_GPIO1 */ + gpio-hog; + gpios = <11 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "CSI2_CAMERA_GPIO1"; + }; +}; + +&wkup_i2c0 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + ov5640: camera@3c { + compatible = "ovti,ov5640"; + reg = <0x3c>; + + clocks = <&clk_ov5640_fixed>; + clock-names = "xclk"; + + port { + csi2_cam0: endpoint { + remote-endpoint = <&csi2rx0_in_sensor>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2rx0_in_sensor: endpoint { + remote-endpoint = <&csi2_cam0>; + bus-type = <4>; /* CSI2 DPHY. */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&dphy0 { + status = "okay"; +}; + +&ti_csi2rx0 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am625-beagleplay-csi2-tevi-ov5640.dtso b/arch/arm64/boot/dts/ti/k3-am625-beagleplay-csi2-tevi-ov5640.dtso new file mode 100644 index 00000000000000..5e1cbbc27c8f2e --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am625-beagleplay-csi2-tevi-ov5640.dtso @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Technexion TEVI-OV5640-*-RPI - OV5640 camera module + * Copyright (C) 2022-2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_ov5640_fixed: ov5640-xclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + }; +}; + +&main_gpio0 { + p11-hog { + /* P11 - CSI2_CAMERA_GPIO1 */ + gpio-hog; + gpios = <11 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "CSI2_CAMERA_GPIO1"; + }; +}; + +&wkup_i2c0 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + ov5640: camera@3c { + compatible = "ovti,ov5640"; + reg = <0x3c>; + + clocks = <&clk_ov5640_fixed>; + clock-names = "xclk"; + + port { + csi2_cam0: endpoint { + remote-endpoint = <&csi2rx0_in_sensor>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2rx0_in_sensor: endpoint { + remote-endpoint = <&csi2_cam0>; + bus-type = <4>; /* CSI2 DPHY. */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&dphy0 { + status = "okay"; +}; + +&ti_csi2rx0 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am625-beagleplay.dts b/arch/arm64/boot/dts/ti/k3-am625-beagleplay.dts index 9a6bd0a3c94f72..eadbdd9ffe3770 100644 --- a/arch/arm64/boot/dts/ti/k3-am625-beagleplay.dts +++ b/arch/arm64/boot/dts/ti/k3-am625-beagleplay.dts @@ -443,7 +443,7 @@ >; }; - console_pins_default: console-default-pins { + main_uart0_pins_default: main-uart0-default-pins { bootph-all; pinctrl-single,pins = < AM62X_IOPAD(0x01c8, PIN_INPUT, 0) /* (D14) UART0_RXD */ @@ -877,7 +877,7 @@ &main_uart0 { bootph-all; pinctrl-names = "default"; - pinctrl-0 = <&console_pins_default>; + pinctrl-0 = <&main_uart0_pins_default>; status = "okay"; }; diff --git a/arch/arm64/boot/dts/ti/k3-am625-phyboard-lyra-rdk.dts b/arch/arm64/boot/dts/ti/k3-am625-phyboard-lyra-rdk.dts index a438baf542c225..4bc0134c987d48 100644 --- a/arch/arm64/boot/dts/ti/k3-am625-phyboard-lyra-rdk.dts +++ b/arch/arm64/boot/dts/ti/k3-am625-phyboard-lyra-rdk.dts @@ -35,6 +35,18 @@ standby-gpios = <&gpio_exp 1 GPIO_ACTIVE_HIGH>; }; + hdmi0: connector-hdmi { + compatible = "hdmi-connector"; + label = "hdmi"; + type = "a"; + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&sii9022_out>; + }; + }; + }; + keys { compatible = "gpio-keys"; autorepeat; @@ -93,6 +105,37 @@ >; }; + hdmi_int_pins_default: hdmi-int-default-pins { + pinctrl-single,pins = < + AM62X_IOPAD(0x040, PIN_INPUT, 7) /* (N23) GPMC0_AD1.GPIO0_16 */ + >; + }; + + main_dss0_pins_default: main-dss0-default-pins { + pinctrl-single,pins = < + AM62X_IOPAD(0x0b8, PIN_OUTPUT, 0) /* (U22) VOUT0_DATA0 */ + AM62X_IOPAD(0x0bc, PIN_OUTPUT, 0) /* (V24) VOUT0_DATA1 */ + AM62X_IOPAD(0x0e0, PIN_OUTPUT, 0) /* (V20) VOUT0_DATA10 */ + AM62X_IOPAD(0x0e4, PIN_OUTPUT, 0) /* (AA23) VOUT0_DATA11 */ + AM62X_IOPAD(0x0e8, PIN_OUTPUT, 0) /* (AB25) VOUT0_DATA12 */ + AM62X_IOPAD(0x0ec, PIN_OUTPUT, 0) /* (AA24) VOUT0_DATA13 */ + AM62X_IOPAD(0x0f0, PIN_OUTPUT, 0) /* (Y22) VOUT0_DATA14 */ + AM62X_IOPAD(0x0f4, PIN_OUTPUT, 0) /* (AA21) VOUT0_DATA15 */ + AM62X_IOPAD(0x0c0, PIN_OUTPUT, 0) /* (W25) VOUT0_DATA2 */ + AM62X_IOPAD(0x0c4, PIN_OUTPUT, 0) /* (W24) VOUT0_DATA3 */ + AM62X_IOPAD(0x0c8, PIN_OUTPUT, 0) /* (Y25) VOUT0_DATA4 */ + AM62X_IOPAD(0x0cc, PIN_OUTPUT, 0) /* (Y24) VOUT0_DATA5 */ + AM62X_IOPAD(0x0d0, PIN_OUTPUT, 0) /* (Y23) VOUT0_DATA6 */ + AM62X_IOPAD(0x0d4, PIN_OUTPUT, 0) /* (AA25) VOUT0_DATA7 */ + AM62X_IOPAD(0x0d8, PIN_OUTPUT, 0) /* (V21) VOUT0_DATA8 */ + AM62X_IOPAD(0x0dc, PIN_OUTPUT, 0) /* (W21) VOUT0_DATA9 */ + AM62X_IOPAD(0x0fc, PIN_OUTPUT, 0) /* (Y20) VOUT0_DE */ + AM62X_IOPAD(0x0f8, PIN_OUTPUT, 0) /* (AB24) VOUT0_HSYNC */ + AM62X_IOPAD(0x104, PIN_OUTPUT, 0) /* (AC24) VOUT0_PCLK */ + AM62X_IOPAD(0x100, PIN_OUTPUT, 0) /* (AC25) VOUT0_VSYNC */ + >; + }; + main_i2c1_pins_default: main-i2c1-default-pins { pinctrl-single,pins = < AM62X_IOPAD(0x1e8, PIN_INPUT_PULLUP, 0) /* (B17) I2C1_SCL */ @@ -184,10 +227,30 @@ }; }; +&dss { + pinctrl-names = "default"; + pinctrl-0 = <&main_dss0_pins_default>; + status = "okay"; +}; + +&dss_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* VP2: DPI/HDMI Output */ + port@1 { + reg = <1>; + + dpi1_out: endpoint { + remote-endpoint = <&sii9022_in>; + }; + }; +}; + &main_i2c1 { pinctrl-names = "default"; pinctrl-0 = <&main_i2c1_pins_default>; - clock-frequency = <400000>; + clock-frequency = <100000>; status = "okay"; gpio_exp: gpio-expander@21 { @@ -201,12 +264,43 @@ gpio-controller; interrupt-controller; #interrupt-cells = <2>; - gpio-line-names = "GPIO0_HDMI_RST", "GPIO1_CAN0_nEN", + gpio-line-names = "", "GPIO1_CAN0_nEN", "GPIO2_LED2", "GPIO3_LVDS_GPIO", "GPIO4_BUT2", "GPIO5_LVDS_BKLT_EN", "GPIO6_ETH1_USER_RESET", "GPIO7_AUDIO_USER_RESET"; }; + sii9022: bridge-hdmi@39 { + compatible = "sil,sii9022"; + reg = <0x39>; + + interrupt-parent = <&main_gpio0>; + interrupts = <16 IRQ_TYPE_EDGE_FALLING>; + pinctrl-names = "default"; + pinctrl-0 = <&hdmi_int_pins_default>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + sii9022_in: endpoint { + remote-endpoint = <&dpi1_out>; + }; + }; + + port@1 { + reg = <1>; + + sii9022_out: endpoint { + remote-endpoint = <&hdmi_connector_in>; + }; + }; + }; + }; + eeprom@51 { compatible = "atmel,24c02"; pagesize = <16>; diff --git a/arch/arm64/boot/dts/ti/k3-am625-verdin-nonwifi-mallow.dts b/arch/arm64/boot/dts/ti/k3-am625-verdin-nonwifi-mallow.dts new file mode 100644 index 00000000000000..9cae12106e0e60 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am625-verdin-nonwifi-mallow.dts @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright 2023 Toradex + * + * https://www.toradex.com/computer-on-modules/verdin-arm-family/ti-am62 + * https://www.toradex.com/products/carrier-board/mallow-carrier-board + */ + +/dts-v1/; + +#include "k3-am625.dtsi" +#include "k3-am62-verdin.dtsi" +#include "k3-am62-verdin-nonwifi.dtsi" +#include "k3-am62-verdin-mallow.dtsi" + +/ { + model = "Toradex Verdin AM62 on Mallow Board"; + compatible = "toradex,verdin-am62-nonwifi-mallow", + "toradex,verdin-am62-nonwifi", + "toradex,verdin-am62", + "ti,am625"; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am625-verdin-wifi-mallow.dts b/arch/arm64/boot/dts/ti/k3-am625-verdin-wifi-mallow.dts new file mode 100644 index 00000000000000..81d834b2264975 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am625-verdin-wifi-mallow.dts @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT +/* + * Copyright 2023 Toradex + * + * https://www.toradex.com/computer-on-modules/verdin-arm-family/ti-am62 + * https://www.toradex.com/products/carrier-board/mallow-carrier-board + */ + +/dts-v1/; + +#include "k3-am625.dtsi" +#include "k3-am62-verdin.dtsi" +#include "k3-am62-verdin-wifi.dtsi" +#include "k3-am62-verdin-mallow.dtsi" + +/ { + model = "Toradex Verdin AM62 WB on Mallow Board"; + compatible = "toradex,verdin-am62-wifi-mallow", + "toradex,verdin-am62-wifi", + "toradex,verdin-am62", + "ti,am625"; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am62a-main.dtsi b/arch/arm64/boot/dts/ti/k3-am62a-main.dtsi index 4ae7fdc5221b23..f0b8c9ab14593f 100644 --- a/arch/arm64/boot/dts/ti/k3-am62a-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62a-main.dtsi @@ -101,8 +101,13 @@ <0x00 0x4c000000 0x00 0x20000>, <0x00 0x4a820000 0x00 0x20000>, <0x00 0x4aa40000 0x00 0x20000>, - <0x00 0x4bc00000 0x00 0x100000>; - reg-names = "gcfg", "bchanrt", "rchanrt", "tchanrt", "ringrt"; + <0x00 0x4bc00000 0x00 0x100000>, + <0x00 0x48600000 0x00 0x8000>, + <0x00 0x484a4000 0x00 0x2000>, + <0x00 0x484c2000 0x00 0x2000>, + <0x00 0x48420000 0x00 0x2000>; + reg-names = "gcfg", "bchanrt", "rchanrt", "tchanrt", "ringrt", + "ring", "tchan", "rchan", "bchan"; msi-parent = <&inta_main_dmss>; #dma-cells = <3>; ti,sci = <&dmsc>; @@ -117,8 +122,13 @@ reg = <0x00 0x485c0000 0x00 0x100>, <0x00 0x4a800000 0x00 0x20000>, <0x00 0x4aa00000 0x00 0x40000>, - <0x00 0x4b800000 0x00 0x400000>; - reg-names = "gcfg", "rchanrt", "tchanrt", "ringrt"; + <0x00 0x4b800000 0x00 0x400000>, + <0x00 0x485e0000 0x00 0x10000>, + <0x00 0x484a0000 0x00 0x2000>, + <0x00 0x484c0000 0x00 0x2000>, + <0x00 0x48430000 0x00 0x1000>; + reg-names = "gcfg", "rchanrt", "tchanrt", "ringrt", + "ring", "tchan", "rchan", "rflow"; msi-parent = <&inta_main_dmss>; #dma-cells = <2>; ti,sci = <&dmsc>; @@ -144,6 +154,44 @@ }; }; + dmss_csi: bus@4e000000 { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + dma-ranges; + ranges = <0x00 0x4e000000 0x00 0x4e000000 0x00 0x300000>; + + ti,sci-dev-id = <198>; + + inta_main_dmss_csi: interrupt-controller@4e0a0000 { + compatible = "ti,sci-inta"; + reg = <0x00 0x4e0a0000 0x00 0x8000>; + #interrupt-cells = <0>; + interrupt-controller; + interrupt-parent = <&gic500>; + msi-controller; + ti,sci = <&dmsc>; + ti,sci-dev-id = <200>; + ti,interrupt-ranges = <0 237 8>; + ti,unmapped-event-sources = <&main_bcdma_csi>; + power-domains = <&k3_pds 182 TI_SCI_PD_EXCLUSIVE>; + }; + + main_bcdma_csi: dma-controller@4e230000 { + compatible = "ti,am62a-dmss-bcdma-csirx"; + reg = <0x00 0x4e230000 0x00 0x100>, + <0x00 0x4e180000 0x00 0x8000>, + <0x00 0x4e100000 0x00 0x10000>; + reg-names = "gcfg", "rchanrt", "ringrt"; + msi-parent = <&inta_main_dmss_csi>; + #dma-cells = <3>; + ti,sci = <&dmsc>; + ti,sci-dev-id = <199>; + ti,sci-rm-range-rchan = <0x21>; + power-domains = <&k3_pds 182 TI_SCI_PD_EXCLUSIVE>; + }; + }; + dmsc: system-controller@44043000 { compatible = "ti,k2g-sci"; reg = <0x00 0x44043000 0x00 0xfe0>; @@ -462,7 +510,7 @@ <193>, <194>, <195>; interrupt-controller; #interrupt-cells = <2>; - ti,ngpio = <87>; + ti,ngpio = <92>; ti,davinci-gpio-unbanked = <0>; power-domains = <&k3_pds 77 TI_SCI_PD_EXCLUSIVE>; clocks = <&k3_clks 77 0>; @@ -480,7 +528,7 @@ <183>, <184>, <185>; interrupt-controller; #interrupt-cells = <2>; - ti,ngpio = <88>; + ti,ngpio = <52>; ti,davinci-gpio-unbanked = <0>; power-domains = <&k3_pds 78 TI_SCI_PD_EXCLUSIVE>; clocks = <&k3_clks 78 0>; @@ -876,4 +924,65 @@ power-domains = <&k3_pds 192 TI_SCI_PD_EXCLUSIVE>; status = "disabled"; }; + + ti_csi2rx0: ticsi2rx@30102000 { + compatible = "ti,j721e-csi2rx-shim"; + dmas = <&main_bcdma_csi 0 0x5000 0>; + dma-names = "rx0"; + reg = <0x00 0x30102000 0x00 0x1000>; + power-domains = <&k3_pds 182 TI_SCI_PD_EXCLUSIVE>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + status = "disabled"; + + cdns_csi2rx0: csi-bridge@30101000 { + compatible = "ti,j721e-csi2rx", "cdns,csi2rx"; + reg = <0x00 0x30101000 0x00 0x1000>; + clocks = <&k3_clks 182 0>, <&k3_clks 182 3>, <&k3_clks 182 0>, + <&k3_clks 182 0>, <&k3_clks 182 4>, <&k3_clks 182 4>; + clock-names = "sys_clk", "p_clk", "pixel_if0_clk", + "pixel_if1_clk", "pixel_if2_clk", "pixel_if3_clk"; + phys = <&dphy0>; + phy-names = "dphy"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "disabled"; + }; + + csi0_port1: port@1 { + reg = <1>; + status = "disabled"; + }; + + csi0_port2: port@2 { + reg = <2>; + status = "disabled"; + }; + + csi0_port3: port@3 { + reg = <3>; + status = "disabled"; + }; + + csi0_port4: port@4 { + reg = <4>; + status = "disabled"; + }; + }; + }; + }; + + dphy0: phy@30110000 { + compatible = "cdns,dphy-rx"; + reg = <0x00 0x30110000 0x00 0x1100>; + #phy-cells = <0>; + power-domains = <&k3_pds 185 TI_SCI_PD_EXCLUSIVE>; + status = "disabled"; + }; }; diff --git a/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts b/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts index 8f64ac2c7568cb..7b71425862958b 100644 --- a/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts +++ b/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts @@ -274,6 +274,12 @@ AM62AX_IOPAD(0x084, PIN_INPUT, 2) /* (L18) GPMC0_ADVn_ALE.MCASP1_AXR2 */ >; }; + + main_gpio1_ioexp_intr_pins_default: main-gpio1-ioexp-intr-default-pins { + pinctrl-single,pins = < + AM62AX_IOPAD(0x01d4, PIN_INPUT, 7) /* (C15) UART0_RTSn.GPIO1_23 */ + >; + }; }; &mcu_pmx0 { @@ -407,6 +413,12 @@ reg = <0x22>; gpio-controller; #gpio-cells = <2>; + interrupt-parent = <&main_gpio1>; + interrupts = <23 IRQ_TYPE_EDGE_FALLING>; + interrupt-controller; + #interrupt-cells = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&main_gpio1_ioexp_intr_pins_default>; gpio-line-names = "GPIO_CPSW2_RST", "GPIO_CPSW1_RST", "BT_EN_SOC", "MMC1_SD_EN", @@ -434,6 +446,33 @@ DRVDD-supply = <&vcc_3v3_sys>; DVDD-supply = <&buck5>; }; + + exp2: gpio@23 { + compatible = "ti,tca6424"; + reg = <0x23>; + gpio-controller; + #gpio-cells = <2>; + + gpio-line-names = "", "", + "", "", + "", "", + "", "", + "WL_LT_EN", "CSI_RSTz", + "", "", + "", "", + "", "", + "SPI0_FET_SEL", "SPI0_FET_OE", + "RGMII2_BRD_CONN_DET", "CSI_SEL2", + "CSI_EN", "AUTO_100M_1000M_CONFIG", + "CSI_VLDO_SEL", "SoC_WLAN_SDIO_RST"; + }; +}; + +&main_i2c2 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c2_pins_default>; + clock-frequency = <400000>; }; &sdhci1 { diff --git a/arch/arm64/boot/dts/ti/k3-am62p-main.dtsi b/arch/arm64/boot/dts/ti/k3-am62p-main.dtsi index 963758c7d377aa..4c51bae06b57eb 100644 --- a/arch/arm64/boot/dts/ti/k3-am62p-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62p-main.dtsi @@ -101,8 +101,13 @@ <0x00 0x4c000000 0x00 0x20000>, <0x00 0x4a820000 0x00 0x20000>, <0x00 0x4aa40000 0x00 0x20000>, - <0x00 0x4bc00000 0x00 0x100000>; - reg-names = "gcfg", "bchanrt", "rchanrt", "tchanrt", "ringrt"; + <0x00 0x4bc00000 0x00 0x100000>, + <0x00 0x48600000 0x00 0x8000>, + <0x00 0x484a4000 0x00 0x2000>, + <0x00 0x484c2000 0x00 0x2000>, + <0x00 0x48420000 0x00 0x2000>; + reg-names = "gcfg", "bchanrt", "rchanrt", "tchanrt", "ringrt", + "ring", "tchan", "rchan", "bchan"; msi-parent = <&inta_main_dmss>; #dma-cells = <3>; @@ -119,8 +124,13 @@ reg = <0x00 0x485c0000 0x00 0x100>, <0x00 0x4a800000 0x00 0x20000>, <0x00 0x4aa00000 0x00 0x40000>, - <0x00 0x4b800000 0x00 0x400000>; - reg-names = "gcfg", "rchanrt", "tchanrt", "ringrt"; + <0x00 0x4b800000 0x00 0x400000>, + <0x00 0x485e0000 0x00 0x10000>, + <0x00 0x484a0000 0x00 0x2000>, + <0x00 0x484c0000 0x00 0x2000>, + <0x00 0x48430000 0x00 0x1000>; + reg-names = "gcfg", "rchanrt", "tchanrt", "ringrt", + "ring", "tchan", "rchan", "rflow"; msi-parent = <&inta_main_dmss>; #dma-cells = <2>; bootph-all; diff --git a/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts b/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts index f377eadef0c128..1773c05f752cdf 100644 --- a/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts +++ b/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts @@ -598,3 +598,12 @@ status = "reserved"; bootph-all; }; + +/* mcu_gpio0 and mcu_gpio_intr are reserved for mcu firmware usage */ +&mcu_gpio0 { + status = "reserved"; +}; + +&mcu_gpio_intr { + status = "reserved"; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi b/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi index 19f57ead4ebd17..33768c02d8eb16 100644 --- a/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am62x-sk-common.dtsi @@ -399,6 +399,13 @@ }; }; +&main_i2c2 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c2_pins_default>; + clock-frequency = <400000>; +}; + &sdhci0 { bootph-all; status = "okay"; @@ -517,3 +524,12 @@ }; }; }; + +/* mcu_gpio0 and mcu_gpio_intr are reserved for mcu firmware usage */ +&mcu_gpio0 { + status = "reserved"; +}; + +&mcu_gpio_intr { + status = "reserved"; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-imx219.dtso b/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-imx219.dtso new file mode 100644 index 00000000000000..6f4cd73c2f4333 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-imx219.dtso @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX219 (RPi v2) Camera Module + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_imx219_fixed: imx219-xclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + }; +}; + +&main_i2c2 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + i2c-switch@71 { + compatible = "nxp,pca9543"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x71>; + + /* CAM port */ + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + ov5640: camera@10 { + compatible = "sony,imx219"; + reg = <0x10>; + + clocks = <&clk_imx219_fixed>; + clock-names = "xclk"; + + reset-gpios = <&exp1 13 GPIO_ACTIVE_HIGH>; + + port { + csi2_cam0: endpoint { + remote-endpoint = <&csi2rx0_in_sensor>; + link-frequencies = /bits/ 64 <456000000>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2rx0_in_sensor: endpoint { + remote-endpoint = <&csi2_cam0>; + bus-type = <4>; /* CSI2 DPHY. */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&ti_csi2rx0 { + status = "okay"; +}; + +&dphy0 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-ov5640.dtso b/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-ov5640.dtso new file mode 100644 index 00000000000000..9323a4b38389e0 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-ov5640.dtso @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ALINX AN5641 & Digilent PCam 5C - OV5640 camera module + * Copyright (C) 2022-2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_ov5640_fixed: ov5640-xclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <12000000>; + }; +}; + +&main_i2c2 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + i2c-switch@71 { + compatible = "nxp,pca9543"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x71>; + + /* CAM port */ + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + ov5640: camera@3c { + compatible = "ovti,ov5640"; + reg = <0x3c>; + + clocks = <&clk_ov5640_fixed>; + clock-names = "xclk"; + powerdown-gpios = <&exp1 13 GPIO_ACTIVE_LOW>; + + port { + csi2_cam0: endpoint { + remote-endpoint = <&csi2rx0_in_sensor>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2rx0_in_sensor: endpoint { + remote-endpoint = <&csi2_cam0>; + bus-type = <4>; /* CSI2 DPHY. */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&ti_csi2rx0 { + status = "okay"; +}; + +&dphy0 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-tevi-ov5640.dtso b/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-tevi-ov5640.dtso new file mode 100644 index 00000000000000..dcaa33a4c8d354 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am62x-sk-csi2-tevi-ov5640.dtso @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Technexion TEVI-OV5640-*-RPI - OV5640 camera module + * Copyright (C) 2022-2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_ov5640_fixed: ov5640-xclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + }; +}; + +&main_i2c2 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + i2c-switch@71 { + compatible = "nxp,pca9543"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x71>; + + /* CAM port */ + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + ov5640: camera@3c { + compatible = "ovti,ov5640"; + reg = <0x3c>; + + clocks = <&clk_ov5640_fixed>; + clock-names = "xclk"; + powerdown-gpios = <&exp1 13 GPIO_ACTIVE_LOW>; + + port { + csi2_cam0: endpoint { + remote-endpoint = <&csi2rx0_in_sensor>; + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2rx0_in_sensor: endpoint { + remote-endpoint = <&csi2_cam0>; + bus-type = <4>; /* CSI2 DPHY. */ + clock-lanes = <0>; + data-lanes = <1 2>; + }; + }; + }; +}; + +&ti_csi2rx0 { + status = "okay"; +}; + +&dphy0 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am64-main.dtsi b/arch/arm64/boot/dts/ti/k3-am64-main.dtsi index 0be642bc1b86d7..e348114f42e017 100644 --- a/arch/arm64/boot/dts/ti/k3-am64-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am64-main.dtsi @@ -63,7 +63,7 @@ #phy-cells = <1>; }; - epwm_tbclk: clock-controller@4140 { + epwm_tbclk: clock-controller@4130 { compatible = "ti,am64-epwm-tbclk"; reg = <0x4130 0x4>; #clock-cells = <1>; @@ -138,8 +138,13 @@ <0x00 0x4c000000 0x00 0x20000>, <0x00 0x4a820000 0x00 0x20000>, <0x00 0x4aa40000 0x00 0x20000>, - <0x00 0x4bc00000 0x00 0x100000>; - reg-names = "gcfg", "bchanrt", "rchanrt", "tchanrt", "ringrt"; + <0x00 0x4bc00000 0x00 0x100000>, + <0x00 0x48600000 0x00 0x8000>, + <0x00 0x484a4000 0x00 0x2000>, + <0x00 0x484c2000 0x00 0x2000>, + <0x00 0x48420000 0x00 0x2000>; + reg-names = "gcfg", "bchanrt", "rchanrt", "tchanrt", "ringrt", + "ring", "tchan", "rchan", "bchan"; msi-parent = <&inta_main_dmss>; #dma-cells = <3>; @@ -155,8 +160,13 @@ reg = <0x00 0x485c0000 0x00 0x100>, <0x00 0x4a800000 0x00 0x20000>, <0x00 0x4aa00000 0x00 0x40000>, - <0x00 0x4b800000 0x00 0x400000>; - reg-names = "gcfg", "rchanrt", "tchanrt", "ringrt"; + <0x00 0x4b800000 0x00 0x400000>, + <0x00 0x485e0000 0x00 0x20000>, + <0x00 0x484a0000 0x00 0x4000>, + <0x00 0x484c0000 0x00 0x2000>, + <0x00 0x48430000 0x00 0x4000>; + reg-names = "gcfg", "rchanrt", "tchanrt", "ringrt", + "ring", "tchan", "rchan", "rflow"; msi-parent = <&inta_main_dmss>; #dma-cells = <2>; @@ -623,6 +633,7 @@ ti,otap-del-sel-mmc-hs = <0x0>; ti,otap-del-sel-ddr52 = <0x6>; ti,otap-del-sel-hs200 = <0x7>; + status = "disabled"; }; sdhci1: mmc@fa00000 { @@ -641,6 +652,7 @@ ti,otap-del-sel-sdr104 = <0x6>; ti,otap-del-sel-ddr50 = <0x9>; ti,clkbuf-sel = <0x7>; + status = "disabled"; }; cpsw3g: ethernet@8000000 { diff --git a/arch/arm64/boot/dts/ti/k3-am64-phycore-som.dtsi b/arch/arm64/boot/dts/ti/k3-am64-phycore-som.dtsi index f87f09d83c956a..1678e74cb750e8 100644 --- a/arch/arm64/boot/dts/ti/k3-am64-phycore-som.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am64-phycore-som.dtsi @@ -29,7 +29,7 @@ reg = <0x00000000 0x80000000 0x00000000 0x80000000>; }; - reserved-memory { + reserved_memory: reserved-memory { #address-cells = <2>; #size-cells = <2>; ranges; @@ -39,6 +39,54 @@ alignment = <0x1000>; no-map; }; + + main_r5fss0_core0_dma_memory_region: r5f-dma-memory@a0000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa0000000 0x00 0x100000>; + no-map; + }; + + main_r5fss0_core0_memory_region: r5f-memory@a0100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa0100000 0x00 0xf00000>; + no-map; + }; + + main_r5fss0_core1_dma_memory_region: r5f-dma-memory@a1000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa1000000 0x00 0x100000>; + no-map; + }; + + main_r5fss0_core1_memory_region: r5f-memory@a1100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa1100000 0x00 0xf00000>; + no-map; + }; + + main_r5fss1_core0_dma_memory_region: r5f-dma-memory@a2000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa2000000 0x00 0x100000>; + no-map; + }; + + main_r5fss1_core0_memory_region: r5f-memory@a2100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa2100000 0x00 0xf00000>; + no-map; + }; + + main_r5fss1_core1_dma_memory_region: r5f-dma-memory@a3000000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa3000000 0x00 0x100000>; + no-map; + }; + + main_r5fss1_core1_memory_region: r5f-memory@a3100000 { + compatible = "shared-dma-pool"; + reg = <0x00 0xa3100000 0x00 0xf00000>; + no-map; + }; }; leds { @@ -166,6 +214,34 @@ status = "disabled"; }; +&mailbox0_cluster2 { + status = "okay"; + + mbox_main_r5fss0_core0: mbox-main-r5fss0-core0 { + ti,mbox-rx = <0 0 2>; + ti,mbox-tx = <1 0 2>; + }; + + mbox_main_r5fss0_core1: mbox-main-r5fss0-core1 { + ti,mbox-rx = <2 0 2>; + ti,mbox-tx = <3 0 2>; + }; +}; + +&mailbox0_cluster4 { + status = "okay"; + + mbox_main_r5fss1_core0: mbox-main-r5fss1-core0 { + ti,mbox-rx = <0 0 2>; + ti,mbox-tx = <1 0 2>; + }; + + mbox_main_r5fss1_core1: mbox-main-r5fss1-core1 { + ti,mbox-rx = <2 0 2>; + ti,mbox-tx = <3 0 2>; + }; +}; + &main_i2c0 { status = "okay"; pinctrl-names = "default"; @@ -191,6 +267,30 @@ }; }; +&main_r5fss0_core0 { + mboxes = <&mailbox0_cluster2 &mbox_main_r5fss0_core0>; + memory-region = <&main_r5fss0_core0_dma_memory_region>, + <&main_r5fss0_core0_memory_region>; +}; + +&main_r5fss0_core1 { + mboxes = <&mailbox0_cluster2 &mbox_main_r5fss0_core1>; + memory-region = <&main_r5fss0_core1_dma_memory_region>, + <&main_r5fss0_core1_memory_region>; +}; + +&main_r5fss1_core0 { + mboxes = <&mailbox0_cluster4 &mbox_main_r5fss1_core0>; + memory-region = <&main_r5fss1_core0_dma_memory_region>, + <&main_r5fss1_core0_memory_region>; +}; + +&main_r5fss1_core1 { + mboxes = <&mailbox0_cluster4 &mbox_main_r5fss1_core1>; + memory-region = <&main_r5fss1_core1_dma_memory_region>, + <&main_r5fss1_core1_memory_region>; +}; + &ospi0 { status = "okay"; pinctrl-names = "default"; @@ -211,6 +311,7 @@ }; &sdhci0 { + status = "okay"; bus-width = <8>; non-removable; ti,driver-strength-ohm = <50>; diff --git a/arch/arm64/boot/dts/ti/k3-am642-evm.dts b/arch/arm64/boot/dts/ti/k3-am642-evm.dts index 4dba18941015dd..8c5651d2cf5ddc 100644 --- a/arch/arm64/boot/dts/ti/k3-am642-evm.dts +++ b/arch/arm64/boot/dts/ti/k3-am642-evm.dts @@ -468,11 +468,15 @@ bootph-all; }; -/* mcu_gpio0 is reserved for mcu firmware usage */ +/* mcu_gpio0 and mcu_gpio_intr are reserved for mcu firmware usage */ &mcu_gpio0 { status = "reserved"; }; +&mcu_gpio_intr { + status = "reserved"; +}; + &main_spi0 { status = "okay"; pinctrl-names = "default"; @@ -487,17 +491,19 @@ }; }; +/* eMMC */ &sdhci0 { - /* emmc */ + status = "okay"; bus-width = <8>; non-removable; ti,driver-strength-ohm = <50>; disable-wp; }; +/* SD/MMC */ &sdhci1 { - /* SD/MMC */ bootph-all; + status = "okay"; vmmc-supply = <&vdd_mmc1>; pinctrl-names = "default"; bus-width = <4>; diff --git a/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-rdk.dts b/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-rdk.dts index 9175e96842d821..53b64e55413f99 100644 --- a/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-rdk.dts +++ b/arch/arm64/boot/dts/ti/k3-am642-phyboard-electra-rdk.dts @@ -264,6 +264,7 @@ }; &sdhci1 { + status = "okay"; vmmc-supply = <&vcc_3v3_mmc>; pinctrl-names = "default"; pinctrl-0 = <&main_mmc1_pins_default>; diff --git a/arch/arm64/boot/dts/ti/k3-am642-sk.dts b/arch/arm64/boot/dts/ti/k3-am642-sk.dts index f29c8a9b59ba7d..1dddd6fc1a0d2d 100644 --- a/arch/arm64/boot/dts/ti/k3-am642-sk.dts +++ b/arch/arm64/boot/dts/ti/k3-am642-sk.dts @@ -433,12 +433,17 @@ }; }; -/* mcu_gpio0 is reserved for mcu firmware usage */ +/* mcu_gpio0 and mcu_gpio_intr are reserved for mcu firmware usage */ &mcu_gpio0 { status = "reserved"; }; +&mcu_gpio_intr { + status = "reserved"; +}; + &sdhci0 { + status = "okay"; vmmc-supply = <&wlan_en>; bus-width = <4>; non-removable; @@ -458,9 +463,10 @@ }; }; +/* SD/MMC */ &sdhci1 { - /* SD/MMC */ bootph-all; + status = "okay"; vmmc-supply = <&vdd_mmc1>; pinctrl-names = "default"; bus-width = <4>; diff --git a/arch/arm64/boot/dts/ti/k3-am642-tqma64xxl-mbax4xxl.dts b/arch/arm64/boot/dts/ti/k3-am642-tqma64xxl-mbax4xxl.dts index d95d80076a4270..55102d35cecc1e 100644 --- a/arch/arm64/boot/dts/ti/k3-am642-tqma64xxl-mbax4xxl.dts +++ b/arch/arm64/boot/dts/ti/k3-am642-tqma64xxl-mbax4xxl.dts @@ -425,7 +425,6 @@ ti,driver-strength-ohm = <50>; ti,fails-without-test-cd; /* Enabled by overlay */ - status = "disabled"; }; &tscadc0 { diff --git a/arch/arm64/boot/dts/ti/k3-am642-tqma64xxl.dtsi b/arch/arm64/boot/dts/ti/k3-am642-tqma64xxl.dtsi index d82d4a98306a7d..6c785eff7d2ffa 100644 --- a/arch/arm64/boot/dts/ti/k3-am642-tqma64xxl.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am642-tqma64xxl.dtsi @@ -219,6 +219,7 @@ }; &sdhci0 { + status = "okay"; non-removable; disable-wp; no-sdio; diff --git a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg1.dtsi b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg1.dtsi index 51f902fa35a737..1d197985958369 100644 --- a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg1.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg1.dtsi @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) Siemens AG, 2021 + * Copyright (c) Siemens AG, 2021-2023 * * Authors: * Jan Kiszka @@ -44,3 +44,11 @@ &tx_pru2_1 { status = "disabled"; }; + +&icssg0_eth { + status = "disabled"; +}; + +&icssg0_mdio { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg2.dtsi b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg2.dtsi index e9419c4fe605c5..e9b57b87e42e07 100644 --- a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg2.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common-pg2.dtsi @@ -20,7 +20,9 @@ &main_gpio1 { pinctrl-names = "default"; - pinctrl-0 = <&cp2102n_reset_pin_default>; + pinctrl-0 = + <&main_pcie_enable_pins_default>, + <&cp2102n_reset_pin_default>; gpio-line-names = "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", diff --git a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi index ba1c14a54acf48..61a634afaa4fec 100644 --- a/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am65-iot2050-common.dtsi @@ -9,14 +9,26 @@ * Common bits of the IOT2050 Basic and Advanced variants, PG1 and PG2 */ -#include "k3-am654.dtsi" #include +#include / { aliases { + serial0 = &wkup_uart0; + serial1 = &mcu_uart0; + serial2 = &main_uart0; + serial3 = &main_uart1; + i2c0 = &wkup_i2c0; + i2c1 = &mcu_i2c0; + i2c2 = &main_i2c0; + i2c3 = &main_i2c1; + i2c4 = &main_i2c2; + i2c5 = &main_i2c3; spi0 = &mcu_spi0; mmc0 = &sdhci1; mmc1 = &sdhci0; + ethernet1 = &icssg0_emac0; + ethernet2 = &icssg0_emac1; }; chosen { @@ -101,9 +113,498 @@ #clock-cells = <0>; clock-frequency = <19200000>; }; + + /* Dual Ethernet application node on PRU-ICSSG0 */ + icssg0_eth: icssg0-eth { + compatible = "ti,am654-icssg-prueth"; + pinctrl-names = "default"; + pinctrl-0 = <&icssg0_rgmii_pins_default>; + sram = <&msmc_ram>; + + ti,prus = <&pru0_0>, <&rtu0_0>, <&tx_pru0_0>, + <&pru0_1>, <&rtu0_1>, <&tx_pru0_1>; + firmware-name = "ti-pruss/am65x-sr2-pru0-prueth-fw.elf", + "ti-pruss/am65x-sr2-rtu0-prueth-fw.elf", + "ti-pruss/am65x-sr2-txpru0-prueth-fw.elf", + "ti-pruss/am65x-sr2-pru1-prueth-fw.elf", + "ti-pruss/am65x-sr2-rtu1-prueth-fw.elf", + "ti-pruss/am65x-sr2-txpru1-prueth-fw.elf"; + + ti,pruss-gp-mux-sel = <2>, /* MII mode */ + <2>, + <2>, + <2>, /* MII mode */ + <2>, + <2>; + + ti,mii-g-rt = <&icssg0_mii_g_rt>; + ti,mii-rt = <&icssg0_mii_rt>; + ti,iep = <&icssg0_iep0>, <&icssg0_iep1>; + + interrupt-parent = <&icssg0_intc>; + interrupts = <24 0 2>, <25 1 3>; + interrupt-names = "tx_ts0", "tx_ts1"; + + dmas = <&main_udmap 0xc100>, /* egress slice 0 */ + <&main_udmap 0xc101>, /* egress slice 0 */ + <&main_udmap 0xc102>, /* egress slice 0 */ + <&main_udmap 0xc103>, /* egress slice 0 */ + <&main_udmap 0xc104>, /* egress slice 1 */ + <&main_udmap 0xc105>, /* egress slice 1 */ + <&main_udmap 0xc106>, /* egress slice 1 */ + <&main_udmap 0xc107>, /* egress slice 1 */ + <&main_udmap 0x4100>, /* ingress slice 0 */ + <&main_udmap 0x4101>; /* ingress slice 1 */ + dma-names = "tx0-0", "tx0-1", "tx0-2", "tx0-3", + "tx1-0", "tx1-1", "tx1-2", "tx1-3", + "rx0", "rx1"; + + ethernet-ports { + #address-cells = <1>; + #size-cells = <0>; + icssg0_emac0: port@0 { + reg = <0>; + phy-handle = <&icssg0_eth0_phy>; + phy-mode = "rgmii-id"; + ti,syscon-rgmii-delay = <&scm_conf 0x4100>; + ti,half-duplex-capable; + /* Filled in by bootloader */ + local-mac-address = [00 00 00 00 00 00]; + }; + + icssg0_emac1: port@1 { + reg = <1>; + phy-handle = <&icssg0_eth1_phy>; + phy-mode = "rgmii-id"; + ti,syscon-rgmii-delay = <&scm_conf 0x4104>; + ti,half-duplex-capable; + /* Filled in by bootloader */ + local-mac-address = [00 00 00 00 00 00]; + }; + }; + }; }; &wkup_pmx0 { + pinctrl-names = + "default", + "d0-uart0-rxd", "d0-gpio", "d0-gpio-pullup", "d0-gpio-pulldown", + "d1-uart0-txd", "d1-gpio", "d1-gpio-pullup", "d1-gpio-pulldown", + "d2-uart0-ctsn", "d2-gpio", "d2-gpio-pullup", "d2-gpio-pulldown", + "d3-uart0-rtsn", "d3-gpio", "d3-gpio-pullup", "d3-gpio-pulldown", + "d10-spi0-cs0", "d10-gpio", "d10-gpio-pullup", "d10-gpio-pulldown", + "d11-spi0-d0", "d11-gpio", "d11-gpio-pullup", "d11-gpio-pulldown", + "d12-spi0-d1", "d12-gpio", "d12-gpio-pullup", "d12-gpio-pulldown", + "d13-spi0-clk", "d13-gpio", "d13-gpio-pullup", "d13-gpio-pulldown", + "a0-gpio", "a0-gpio-pullup", "a0-gpio-pulldown", + "a1-gpio", "a1-gpio-pullup", "a1-gpio-pulldown", + "a2-gpio", "a2-gpio-pullup", "a2-gpio-pulldown", + "a3-gpio", "a3-gpio-pullup", "a3-gpio-pulldown", + "a4-gpio", "a4-gpio-pullup", "a4-gpio-pulldown", + "a5-gpio", "a5-gpio-pullup", "a5-gpio-pulldown"; + + pinctrl-0 = <&d0_uart0_rxd>; + pinctrl-1 = <&d0_uart0_rxd>; + pinctrl-2 = <&d0_gpio>; + pinctrl-3 = <&d0_gpio_pullup>; + pinctrl-4 = <&d0_gpio_pulldown>; + pinctrl-5 = <&d1_uart0_txd>; + pinctrl-6 = <&d1_gpio>; + pinctrl-7 = <&d1_gpio_pullup>; + pinctrl-8 = <&d1_gpio_pulldown>; + pinctrl-9 = <&d2_uart0_ctsn>; + pinctrl-10 = <&d2_gpio>; + pinctrl-11 = <&d2_gpio_pullup>; + pinctrl-12 = <&d2_gpio_pulldown>; + pinctrl-13 = <&d3_uart0_rtsn>; + pinctrl-14 = <&d3_gpio>; + pinctrl-15 = <&d3_gpio_pullup>; + pinctrl-16 = <&d3_gpio_pulldown>; + pinctrl-17 = <&d10_spi0_cs0>; + pinctrl-18 = <&d10_gpio>; + pinctrl-19 = <&d10_gpio_pullup>; + pinctrl-20 = <&d10_gpio_pulldown>; + pinctrl-21 = <&d11_spi0_d0>; + pinctrl-22 = <&d11_gpio>; + pinctrl-23 = <&d11_gpio_pullup>; + pinctrl-24 = <&d11_gpio_pulldown>; + pinctrl-25 = <&d12_spi0_d1>; + pinctrl-26 = <&d12_gpio>; + pinctrl-27 = <&d12_gpio_pullup>; + pinctrl-28 = <&d12_gpio_pulldown>; + pinctrl-29 = <&d13_spi0_clk>; + pinctrl-30 = <&d13_gpio>; + pinctrl-31 = <&d13_gpio_pullup>; + pinctrl-32 = <&d13_gpio_pulldown>; + pinctrl-33 = <&a0_gpio>; + pinctrl-34 = <&a0_gpio_pullup>; + pinctrl-35 = <&a0_gpio_pulldown>; + pinctrl-36 = <&a1_gpio>; + pinctrl-37 = <&a1_gpio_pullup>; + pinctrl-38 = <&a1_gpio_pulldown>; + pinctrl-39 = <&a2_gpio>; + pinctrl-40 = <&a2_gpio_pullup>; + pinctrl-41 = <&a2_gpio_pulldown>; + pinctrl-42 = <&a3_gpio>; + pinctrl-43 = <&a3_gpio_pullup>; + pinctrl-44 = <&a3_gpio_pulldown>; + pinctrl-45 = <&a4_gpio>; + pinctrl-46 = <&a4_gpio_pullup>; + pinctrl-47 = <&a4_gpio_pulldown>; + pinctrl-48 = <&a5_gpio>; + pinctrl-49 = <&a5_gpio_pullup>; + pinctrl-50 = <&a5_gpio_pulldown>; + + d0_uart0_rxd: d0-uart0-rxd-pins { + pinctrl-single,pins = < + /* (P4) MCU_UART0_RXD */ + AM65X_WKUP_IOPAD(0x0044, PIN_INPUT, 4) + >; + }; + + d0_gpio: d0-gpio-pins { + pinctrl-single,pins = < + /* (P4) WKUP_GPIO0_29 */ + AM65X_WKUP_IOPAD(0x0044, PIN_INPUT, 7) + >; + }; + + d0_gpio_pullup: d0-gpio-pullup-pins { + pinctrl-single,pins = < + /* (P4) WKUP_GPIO0_29 */ + AM65X_WKUP_IOPAD(0x0044, PIN_INPUT_PULLUP, 7) + >; + }; + + d0_gpio_pulldown: d0-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (P4) WKUP_GPIO0_29 */ + AM65X_WKUP_IOPAD(0x0044, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d1_uart0_txd: d1-uart0-txd-pins { + pinctrl-single,pins = < + /* (P5) MCU_UART0_TXD */ + AM65X_WKUP_IOPAD(0x0048, PIN_OUTPUT, 4) + >; + }; + + d1_gpio: d1-gpio-pins { + pinctrl-single,pins = < + /* (P5) WKUP_GPIO0_30 */ + AM65X_WKUP_IOPAD(0x0048, PIN_INPUT, 7) + >; + }; + + d1_gpio_pullup: d1-gpio-pullup-pins { + pinctrl-single,pins = < + /* (P5) WKUP_GPIO0_30 */ + AM65X_WKUP_IOPAD(0x0048, PIN_INPUT, 7) + >; + }; + + d1_gpio_pulldown: d1-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (P5) WKUP_GPIO0_30 */ + AM65X_WKUP_IOPAD(0x0048, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d2_uart0_ctsn: d2-uart0-ctsn-pins { + pinctrl-single,pins = < + /* (P1) MCU_UART0_CTSn */ + AM65X_WKUP_IOPAD(0x004C, PIN_INPUT, 4) + >; + }; + + d2_gpio: d2-gpio-pins { + pinctrl-single,pins = < + /* (P5) WKUP_GPIO0_31 */ + AM65X_WKUP_IOPAD(0x004C, PIN_INPUT, 7) + >; + }; + + d2_gpio_pullup: d2-gpio-pullup-pins { + pinctrl-single,pins = < + /* (P5) WKUP_GPIO0_31 */ + AM65X_WKUP_IOPAD(0x004C, PIN_INPUT, 7) + >; + }; + + d2_gpio_pulldown: d2-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (P5) WKUP_GPIO0_31 */ + AM65X_WKUP_IOPAD(0x004C, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d3_uart0_rtsn: d3-uart0-rtsn-pins { + pinctrl-single,pins = < + /* (N3) MCU_UART0_RTSn */ + AM65X_WKUP_IOPAD(0x0054, PIN_OUTPUT, 4) + >; + }; + + d3_gpio: d3-gpio-pins { + pinctrl-single,pins = < + /* (N3) WKUP_GPIO0_33 */ + AM65X_WKUP_IOPAD(0x0054, PIN_INPUT, 7) + >; + }; + + d3_gpio_pullup: d3-gpio-pullup-pins { + pinctrl-single,pins = < + /* (N3) WKUP_GPIO0_33 */ + AM65X_WKUP_IOPAD(0x0054, PIN_INPUT, 7) + >; + }; + + d3_gpio_pulldown: d3-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (N3) WKUP_GPIO0_33 */ + AM65X_WKUP_IOPAD(0x0054, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d10_spi0_cs0: d10-spi0-cs0-pins { + pinctrl-single,pins = < + /* (Y4) MCU_SPI0_CS0 */ + AM65X_WKUP_IOPAD(0x009c, PIN_OUTPUT, 0) + >; + }; + + d10_gpio: d10-gpio-pins { + pinctrl-single,pins = < + /* (Y4) WKUP_GPIO0_51 */ + AM65X_WKUP_IOPAD(0x009c, PIN_INPUT, 7) + >; + }; + + d10_gpio_pullup: d10-gpio-pullup-pins { + pinctrl-single,pins = < + /* (Y4) WKUP_GPIO0_51 */ + AM65X_WKUP_IOPAD(0x009c, PIN_INPUT, 7) + >; + }; + + d10_gpio_pulldown: d10-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (Y4) WKUP_GPIO0_51 */ + AM65X_WKUP_IOPAD(0x009c, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d11_spi0_d0: d11-spi0-d0-pins { + pinctrl-single,pins = < + /* (Y3) MCU_SPI0_D0 */ + AM65X_WKUP_IOPAD(0x0094, PIN_INPUT, 0) + >; + }; + + d11_gpio: d11-gpio-pins { + pinctrl-single,pins = < + /* (Y3) WKUP_GPIO0_49 */ + AM65X_WKUP_IOPAD(0x0094, PIN_INPUT, 7) + >; + }; + + d11_gpio_pullup: d11-gpio-pullup-pins { + pinctrl-single,pins = < + /* (Y3) WKUP_GPIO0_49 */ + AM65X_WKUP_IOPAD(0x0094, PIN_INPUT, 7) + >; + }; + + d11_gpio_pulldown: d11-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (Y3) WKUP_GPIO0_49 */ + AM65X_WKUP_IOPAD(0x0094, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d12_spi0_d1: d12-spi0-d1-pins { + pinctrl-single,pins = < + /* (Y2) MCU_SPI0_D1 */ + AM65X_WKUP_IOPAD(0x0098, PIN_INPUT, 0) + >; + }; + + d12_gpio: d12-gpio-pins { + pinctrl-single,pins = < + /* (Y2) WKUP_GPIO0_50 */ + AM65X_WKUP_IOPAD(0x0098, PIN_INPUT, 7) + >; + }; + + d12_gpio_pullup: d12-gpio-pullup-pins { + pinctrl-single,pins = < + /* (Y2) WKUP_GPIO0_50 */ + AM65X_WKUP_IOPAD(0x0098, PIN_INPUT, 7) + >; + }; + + d12_gpio_pulldown: d12-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (Y2) WKUP_GPIO0_50 */ + AM65X_WKUP_IOPAD(0x0098, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d13_spi0_clk: d13-spi0-clk-pins { + pinctrl-single,pins = < + /* (Y1) MCU_SPI0_CLK */ + AM65X_WKUP_IOPAD(0x0090, PIN_INPUT, 0) + >; + }; + + d13_gpio: d13-gpio-pins { + pinctrl-single,pins = < + /* (Y1) WKUP_GPIO0_48 */ + AM65X_WKUP_IOPAD(0x0090, PIN_INPUT, 7) + >; + }; + + d13_gpio_pullup: d13-gpio-pullup-pins { + pinctrl-single,pins = < + /* (Y1) WKUP_GPIO0_48 */ + AM65X_WKUP_IOPAD(0x0090, PIN_INPUT, 7) + >; + }; + + d13_gpio_pulldown: d13-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (Y1) WKUP_GPIO0_48 */ + AM65X_WKUP_IOPAD(0x0090, PIN_INPUT_PULLDOWN, 7) + >; + }; + + a0_gpio: a0-gpio-pins { + pinctrl-single,pins = < + /* (L6) WKUP_GPIO0_45 */ + AM65X_WKUP_IOPAD(0x0084, PIN_INPUT, 7) + >; + }; + + a0_gpio_pullup: a0-gpio-pullup-pins { + pinctrl-single,pins = < + /* (L6) WKUP_GPIO0_45 */ + AM65X_WKUP_IOPAD(0x0084, PIN_INPUT, 7) + >; + }; + + a0_gpio_pulldown: a0-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (L6) WKUP_GPIO0_45 */ + AM65X_WKUP_IOPAD(0x0084, PIN_INPUT_PULLDOWN, 7) + >; + }; + + a1_gpio: a1-gpio-pins { + pinctrl-single,pins = < + /* (M6) WKUP_GPIO0_44 */ + AM65X_WKUP_IOPAD(0x0080, PIN_INPUT, 7) + >; + }; + + a1_gpio_pullup: a1-gpio-pullup-pins { + pinctrl-single,pins = < + /* (M6) WKUP_GPIO0_44 */ + AM65X_WKUP_IOPAD(0x0080, PIN_INPUT, 7) + >; + }; + + a1_gpio_pulldown: a1-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (M6) WKUP_GPIO0_44 */ + AM65X_WKUP_IOPAD(0x0080, PIN_INPUT_PULLDOWN, 7) + >; + }; + + a2_gpio: a2-gpio-pins { + pinctrl-single,pins = < + /* (L5) WKUP_GPIO0_43 */ + AM65X_WKUP_IOPAD(0x007C, PIN_INPUT, 7) + >; + }; + + a2_gpio_pullup: a2-gpio-pullup-pins { + pinctrl-single,pins = < + /* (L5) WKUP_GPIO0_43 */ + AM65X_WKUP_IOPAD(0x007C, PIN_INPUT, 7) + >; + }; + + a2_gpio_pulldown: a2-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (L5) WKUP_GPIO0_43 */ + AM65X_WKUP_IOPAD(0x007C, PIN_INPUT_PULLDOWN, 7) + >; + }; + + a3_gpio: a3-gpio-pins { + pinctrl-single,pins = < + /* (M5) WKUP_GPIO0_39 */ + AM65X_WKUP_IOPAD(0x006C, PIN_INPUT, 7) + >; + }; + + a3_gpio_pullup: a3-gpio-pullup-pins { + pinctrl-single,pins = < + /* (M5) WKUP_GPIO0_39 */ + AM65X_WKUP_IOPAD(0x006C, PIN_INPUT, 7) + >; + }; + + a3_gpio_pulldown: a3-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (M5) WKUP_GPIO0_39 */ + AM65X_WKUP_IOPAD(0x006C, PIN_INPUT_PULLDOWN, 7) + >; + }; + + a4_gpio: a4-gpio-pins { + pinctrl-single,pins = < + /* (L2) WKUP_GPIO0_42 */ + AM65X_WKUP_IOPAD(0x0078, PIN_INPUT, 7) + >; + }; + + a4_gpio_pullup: a4-gpio-pullup-pins { + pinctrl-single,pins = < + /* (L2) WKUP_GPIO0_42 */ + AM65X_WKUP_IOPAD(0x0078, PIN_INPUT, 7) + >; + }; + + a4_gpio_pulldown: a4-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (L2) WKUP_GPIO0_42 */ + AM65X_WKUP_IOPAD(0x0078, PIN_INPUT_PULLDOWN, 7) + >; + }; + + a5_gpio: a5-gpio-pins { + pinctrl-single,pins = < + /* (N5) WKUP_GPIO0_35 */ + AM65X_WKUP_IOPAD(0x005C, PIN_INPUT, 7) + >; + }; + + a5_gpio_pullup: a5-gpio-pullup-pins { + pinctrl-single,pins = < + /* (N5) WKUP_GPIO0_35 */ + AM65X_WKUP_IOPAD(0x005C, PIN_INPUT_PULLUP, 7) + >; + }; + + a5_gpio_pulldown: a5-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (N5) WKUP_GPIO0_35 */ + AM65X_WKUP_IOPAD(0x005C, PIN_INPUT_PULLDOWN, 7) + >; + }; + wkup_i2c0_pins_default: wkup-i2c0-default-pins { pinctrl-single,pins = < /* (AC7) WKUP_I2C0_SCL */ @@ -136,23 +637,6 @@ >; }; - arduino_uart_pins_default: arduino-uart-default-pins { - pinctrl-single,pins = < - /* (P4) MCU_UART0_RXD */ - AM65X_WKUP_IOPAD(0x0044, PIN_INPUT, 4) - /* (P5) MCU_UART0_TXD */ - AM65X_WKUP_IOPAD(0x0048, PIN_OUTPUT, 4) - >; - }; - - arduino_io_d2_to_d3_pins_default: arduino-io-d2-to-d3-default-pins { - pinctrl-single,pins = < - /* (P1) WKUP_GPIO0_31 */ - AM65X_WKUP_IOPAD(0x004C, PIN_OUTPUT, 7) - /* (N3) WKUP_GPIO0_33 */ - AM65X_WKUP_IOPAD(0x0054, PIN_OUTPUT, 7) - >; - }; arduino_io_oe_pins_default: arduino-io-oe-default-pins { pinctrl-single,pins = < @@ -232,6 +716,220 @@ }; &main_pmx0 { + pinctrl-names = + "default", + "d4-ehrpwm0-a", "d4-gpio", "d4-gpio-pullup", "d4-gpio-pulldown", + "d5-ehrpwm1-a", "d5-gpio", "d5-gpio-pullup", "d5-gpio-pulldown", + "d6-ehrpwm2-a", "d6-gpio", "d6-gpio-pullup", "d6-gpio-pulldown", + "d7-ehrpwm3-a", "d7-gpio", "d7-gpio-pullup", "d7-gpio-pulldown", + "d8-ehrpwm4-a", "d8-gpio", "d8-gpio-pullup", "d8-gpio-pulldown", + "d9-ehrpwm5-a", "d9-gpio", "d9-gpio-pullup", "d9-gpio-pulldown"; + + pinctrl-0 = <&d4_ehrpwm0_a>; + pinctrl-1 = <&d4_ehrpwm0_a>; + pinctrl-2 = <&d4_gpio>; + pinctrl-3 = <&d4_gpio_pullup>; + pinctrl-4 = <&d4_gpio_pulldown>; + + pinctrl-5 = <&d5_ehrpwm1_a>; + pinctrl-6 = <&d5_gpio>; + pinctrl-7 = <&d5_gpio_pullup>; + pinctrl-8 = <&d5_gpio_pulldown>; + + pinctrl-9 = <&d6_ehrpwm2_a>; + pinctrl-10 = <&d6_gpio>; + pinctrl-11 = <&d6_gpio_pullup>; + pinctrl-12 = <&d6_gpio_pulldown>; + + pinctrl-13 = <&d7_ehrpwm3_a>; + pinctrl-14 = <&d7_gpio>; + pinctrl-15 = <&d7_gpio_pullup>; + pinctrl-16 = <&d7_gpio_pulldown>; + + pinctrl-17 = <&d8_ehrpwm4_a>; + pinctrl-18 = <&d8_gpio>; + pinctrl-19 = <&d8_gpio_pullup>; + pinctrl-20 = <&d8_gpio_pulldown>; + + pinctrl-21 = <&d9_ehrpwm5_a>; + pinctrl-22 = <&d9_gpio>; + pinctrl-23 = <&d9_gpio_pullup>; + pinctrl-24 = <&d9_gpio_pulldown>; + + d4_ehrpwm0_a: d4-ehrpwm0-a-pins { + pinctrl-single,pins = < + /* (AG18) EHRPWM0_A */ + AM65X_IOPAD(0x0084, PIN_OUTPUT, 5) + >; + }; + + d4_gpio: d4-gpio-pins { + pinctrl-single,pins = < + /* (AG18) GPIO0_33 */ + AM65X_IOPAD(0x0084, PIN_INPUT, 7) + >; + }; + + d4_gpio_pullup: d4-gpio-pullup-pins { + pinctrl-single,pins = < + /* (AG18) GPIO0_33 */ + AM65X_IOPAD(0x0084, PIN_INPUT_PULLUP, 7) + >; + }; + + d4_gpio_pulldown: d4-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (AG18) GPIO0_33 */ + AM65X_IOPAD(0x0084, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d5_ehrpwm1_a: d5-ehrpwm1-a-pins { + pinctrl-single,pins = < + /* (AF17) EHRPWM1_A */ + AM65X_IOPAD(0x008C, PIN_OUTPUT, 5) + >; + }; + + d5_gpio: d5-gpio-pins { + pinctrl-single,pins = < + /* (AF17) GPIO0_35 */ + AM65X_IOPAD(0x008C, PIN_INPUT, 7) + >; + }; + + d5_gpio_pullup: d5-gpio-pullup-pins { + pinctrl-single,pins = < + /* (AF17) GPIO0_35 */ + AM65X_IOPAD(0x008C, PIN_INPUT_PULLUP, 7) + >; + }; + + d5_gpio_pulldown: d5-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (AF17) GPIO0_35 */ + AM65X_IOPAD(0x008C, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d6_ehrpwm2_a: d6-ehrpwm2-a-pins { + pinctrl-single,pins = < + /* (AH16) EHRPWM2_A */ + AM65X_IOPAD(0x0098, PIN_OUTPUT, 5) + >; + }; + + d6_gpio: d6-gpio-pins { + pinctrl-single,pins = < + /* (AH16) GPIO0_38 */ + AM65X_IOPAD(0x0098, PIN_INPUT, 7) + >; + }; + + d6_gpio_pullup: d6-gpio-pullup-pins { + pinctrl-single,pins = < + /* (AH16) GPIO0_38 */ + AM65X_IOPAD(0x0098, PIN_INPUT_PULLUP, 7) + >; + }; + + d6_gpio_pulldown: d6-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (AH16) GPIO0_38 */ + AM65X_IOPAD(0x0098, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d7_ehrpwm3_a: d7-ehrpwm3-a-pins { + pinctrl-single,pins = < + /* (AH15) EHRPWM3_A */ + AM65X_IOPAD(0x00AC, PIN_OUTPUT, 5) + >; + }; + + d7_gpio: d7-gpio-pins { + pinctrl-single,pins = < + /* (AH15) GPIO0_43 */ + AM65X_IOPAD(0x00AC, PIN_INPUT, 7) + >; + }; + + d7_gpio_pullup: d7-gpio-pullup-pins { + pinctrl-single,pins = < + /* (AH15) GPIO0_43 */ + AM65X_IOPAD(0x00AC, PIN_INPUT_PULLUP, 7) + >; + }; + + d7_gpio_pulldown: d7-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (AH15) GPIO0_43 */ + AM65X_IOPAD(0x00AC, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d8_ehrpwm4_a: d8-ehrpwm4-a-pins { + pinctrl-single,pins = < + /* (AG15) EHRPWM4_A */ + AM65X_IOPAD(0x00C0, PIN_OUTPUT, 5) + >; + }; + + d8_gpio: d8-gpio-pins { + pinctrl-single,pins = < + /* (AG15) GPIO0_48 */ + AM65X_IOPAD(0x00C0, PIN_INPUT, 7) + >; + }; + + d8_gpio_pullup: d8-gpio-pullup-pins { + pinctrl-single,pins = < + /* (AG15) GPIO0_48 */ + AM65X_IOPAD(0x00C0, PIN_INPUT_PULLUP, 7) + >; + }; + + d8_gpio_pulldown: d8-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (AG15) GPIO0_48 */ + AM65X_IOPAD(0x00C0, PIN_INPUT_PULLDOWN, 7) + >; + }; + + d9_ehrpwm5_a: d9-ehrpwm5-a-pins { + pinctrl-single,pins = < + /* (AD15) EHRPWM5_A */ + AM65X_IOPAD(0x00CC, PIN_OUTPUT, 5) + >; + }; + + d9_gpio: d9-gpio-pins { + pinctrl-single,pins = < + /* (AD15) GPIO0_51 */ + AM65X_IOPAD(0x00CC, PIN_INPUT, 7) + >; + }; + + d9_gpio_pullup: d9-gpio-pullup-pins { + pinctrl-single,pins = < + /* (AD15) GPIO0_51 */ + AM65X_IOPAD(0x00CC, PIN_INPUT_PULLUP, 7) + >; + }; + + d9_gpio_pulldown: d9-gpio-pulldown-pins { + pinctrl-single,pins = < + /* (AD15) GPIO0_51 */ + AM65X_IOPAD(0x00CC, PIN_INPUT_PULLDOWN, 7) + >; + }; + + main_pcie_enable_pins_default: main-pcie-enable-default-pins { + pinctrl-single,pins = < + AM65X_IOPAD(0x01c4, PIN_INPUT_PULLUP, 7) /* (AH13) GPIO1_17 */ + >; + }; + main_uart1_pins_default: main-uart1-default-pins { pinctrl-single,pins = < AM65X_IOPAD(0x0174, PIN_INPUT, 6) /* (AE23) UART1_RXD */ @@ -273,17 +971,6 @@ >; }; - arduino_io_d4_to_d9_pins_default: arduino-io-d4-to-d9-default-pins { - pinctrl-single,pins = < - AM65X_IOPAD(0x0084, PIN_OUTPUT, 7) /* (AG18) GPIO0_33 */ - AM65X_IOPAD(0x008C, PIN_OUTPUT, 7) /* (AF17) GPIO0_35 */ - AM65X_IOPAD(0x0098, PIN_OUTPUT, 7) /* (AH16) GPIO0_38 */ - AM65X_IOPAD(0x00AC, PIN_OUTPUT, 7) /* (AH15) GPIO0_43 */ - AM65X_IOPAD(0x00C0, PIN_OUTPUT, 7) /* (AG15) GPIO0_48 */ - AM65X_IOPAD(0x00CC, PIN_OUTPUT, 7) /* (AD15) GPIO0_51 */ - >; - }; - dss_vout1_pins_default: dss-vout1-default-pins { pinctrl-single,pins = < AM65X_IOPAD(0x0000, PIN_OUTPUT, 1) /* VOUT1_DATA0 */ @@ -329,6 +1016,43 @@ AM65X_IOPAD(0x0070, PIN_INPUT, 5) /* (R25) I2C2_SDA */ >; }; + + icssg0_mdio_pins_default: icssg0-mdio-default-pins { + pinctrl-single,pins = < + AM65X_IOPAD(0x0294, PIN_INPUT, 0) /* (AE26) PRG0_MDIO0_MDIO */ + AM65X_IOPAD(0x0298, PIN_OUTPUT, 0) /* (AE28) PRG0_MDIO0_MDC */ + >; + }; + + icssg0_rgmii_pins_default: icssg0-rgmii-default-pins { + pinctrl-single,pins = < + AM65X_IOPAD(0x0244, PIN_INPUT, 2) /* (AB28) PRG0_PRU1_GPO0.PRG0_RGMII2_RD0 */ + AM65X_IOPAD(0x0248, PIN_INPUT, 2) /* (AC28) PRG0_PRU1_GPO1.PRG0_RGMII2_RD1 */ + AM65X_IOPAD(0x024c, PIN_INPUT, 2) /* (AC27) PRG0_PRU1_GPO2.PRG0_RGMII2_RD2 */ + AM65X_IOPAD(0x0250, PIN_INPUT, 2) /* (AB26) PRG0_PRU1_GPO3.PRG0_RGMII2_RD3 */ + AM65X_IOPAD(0x0274, PIN_OUTPUT, 2) /* (AC25) PRG0_PRU1_GPO12.PRG0_RGMII2_TD0 */ + AM65X_IOPAD(0x0278, PIN_OUTPUT, 2) /* (AD25) PRG0_PRU1_GPO13.PRG0_RGMII2_TD1 */ + AM65X_IOPAD(0x027c, PIN_OUTPUT, 2) /* (AD24) PRG0_PRU1_GPO14.PRG0_RGMII2_TD2 */ + AM65X_IOPAD(0x0280, PIN_OUTPUT, 2) /* (AE27) PRG0_PRU1_GPO15.PRG0_RGMII2_TD3 */ + AM65X_IOPAD(0x0284, PIN_INPUT, 2) /* (AC24) PRG0_PRU1_GPO16.PRG0_RGMII2_TXC */ + AM65X_IOPAD(0x0270, PIN_OUTPUT, 2) /* (AB24) PRG0_PRU1_GPO11.PRG0_RGMII2_TX_CTL */ + AM65X_IOPAD(0x025c, PIN_INPUT, 2) /* (AB27) PRG0_PRU1_GPO6.PRG0_RGMII2_RXC */ + AM65X_IOPAD(0x0254, PIN_INPUT, 2) /* (AA25) PRG0_PRU1_GPO4.PRG0_RGMII2_RX_CTL */ + + AM65X_IOPAD(0x01f4, PIN_INPUT, 2) /* (V24) PRG0_PRU0_GPO0.PRG0_RGMII1_RD0 */ + AM65X_IOPAD(0x01f8, PIN_INPUT, 2) /* (W25) PRG0_PRU0_GPO1.PRG0_RGMII1_RD1 */ + AM65X_IOPAD(0x01fc, PIN_INPUT, 2) /* (W24) PRG0_PRU0_GPO2.PRG0_RGMII1_RD2 */ + AM65X_IOPAD(0x0200, PIN_INPUT, 2) /* (AA27) PRG0_PRU0_GPO3.PRG0_RGMII1_RD3 */ + AM65X_IOPAD(0x0224, PIN_OUTPUT, 2) /* (AD27) PRG0_PRU0_GPO12.PRG0_RGMII1_TD0 */ + AM65X_IOPAD(0x0228, PIN_OUTPUT, 2) /* (AC26) PRG0_PRU0_GPO13.PRG0_RGMII1_TD1 */ + AM65X_IOPAD(0x022c, PIN_OUTPUT, 2) /* (AD26) PRG0_PRU0_GPO14.PRG0_RGMII1_TD2 */ + AM65X_IOPAD(0x0230, PIN_OUTPUT, 2) /* (AA24) PRG0_PRU0_GPO15.PRG0_RGMII1_TD3 */ + AM65X_IOPAD(0x0234, PIN_INPUT, 2) /* (AD28) PRG0_PRU0_GPO16.PRG0_RGMII1_TXC */ + AM65X_IOPAD(0x0220, PIN_OUTPUT, 2) /* (AB25) PRG0_PRU0_GPO11.PRG0_RGMII1_TX_CTL */ + AM65X_IOPAD(0x020c, PIN_INPUT, 2) /* (Y25) PRG0_PRU0_GPO6.PRG0_RGMII1_RXC */ + AM65X_IOPAD(0x0204, PIN_INPUT, 2) /* (Y24) PRG0_PRU0_GPO4.PRG0_RGMII1_RX_CTL */ + >; + }; }; &main_pmx1 { @@ -345,12 +1069,6 @@ AM65X_IOPAD(0x000c, PIN_INPUT, 0) /* (E21) I2C1_SDA */ >; }; - - ecap0_pins_default: ecap0-default-pins { - pinctrl-single,pins = < - AM65X_IOPAD(0x0010, PIN_INPUT, 0) /* (D21) ECAP0_IN_APWM_OUT */ - >; - }; }; &wkup_uart0 { @@ -366,13 +1084,9 @@ &mcu_uart0 { status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&arduino_uart_pins_default>; }; &main_gpio0 { - pinctrl-names = "default"; - pinctrl-0 = <&arduino_io_d4_to_d9_pins_default>; gpio-line-names = "main_gpio0-base", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", @@ -382,10 +1096,14 @@ "", "IO9"; }; +&main_gpio1 { + pinctrl-names = "default"; + pinctrl-0 = <&main_pcie_enable_pins_default>; +}; + &wkup_gpio0 { pinctrl-names = "default"; pinctrl-0 = - <&arduino_io_d2_to_d3_pins_default>, <&arduino_i2c_aio_switch_pins_default>, <&arduino_io_oe_pins_default>, <&push_button_pins_default>, @@ -547,13 +1265,8 @@ status = "disabled"; }; -&ecap0 { - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&ecap0_pins_default>; -}; - &sdhci1 { + status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&main_mmc1_pins_default>; ti,driver-strength-ohm = <50>; @@ -574,9 +1287,6 @@ &mcu_spi0 { status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <&mcu_spi0_pins_default>; - #address-cells = <1>; #size-cells = <0>; ti,pindir-d0-out-d1-in; @@ -716,3 +1426,21 @@ <&mcu_r5fss0_core1_memory_region>; mboxes = <&mailbox0_cluster1>, <&mbox_mcu_r5fss0_core1>; }; + +&icssg0_mdio { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&icssg0_mdio_pins_default>; + + icssg0_eth0_phy: ethernet-phy@0 { + reg = <0>; + ti,rx-internal-delay = ; + ti,fifo-depth = ; + }; + + icssg0_eth1_phy: ethernet-phy@1 { + reg = <1>; + ti,rx-internal-delay = ; + ti,fifo-depth = ; + }; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi index 5ebb87f467de5e..fcea544656360c 100644 --- a/arch/arm64/boot/dts/ti/k3-am65-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am65-main.dtsi @@ -449,6 +449,7 @@ ti,otap-del-sel-hs400 = <0x0>; ti,trm-icp = <0x8>; dma-coherent; + status = "disabled"; }; sdhci1: mmc@4fa0000 { @@ -471,6 +472,7 @@ ti,clkbuf-sel = <0x7>; ti,trm-icp = <0x8>; dma-coherent; + status = "disabled"; }; scm_conf: scm-conf@100000 { @@ -498,8 +500,8 @@ }; dss_oldi_io_ctrl: dss-oldi-io-ctrl@41e0 { - compatible = "syscon"; - reg = <0x000041e0 0x14>; + compatible = "ti,am654-dss-oldi-io-ctrl", "syscon"; + reg = <0x41e0 0x14>; }; ehrpwm_tbclk: clock-controller@4140 { @@ -790,8 +792,12 @@ compatible = "ti,am654-navss-main-udmap"; reg = <0x0 0x31150000 0x0 0x100>, <0x0 0x34000000 0x0 0x100000>, - <0x0 0x35000000 0x0 0x100000>; - reg-names = "gcfg", "rchanrt", "tchanrt"; + <0x0 0x35000000 0x0 0x100000>, + <0x0 0x30b00000 0x0 0x10000>, + <0x0 0x30c00000 0x0 0x10000>, + <0x0 0x30d00000 0x0 0x8000>; + reg-names = "gcfg", "rchanrt", "tchanrt", + "tchan", "rchan", "rflow"; msi-parent = <&inta_main_udmass>; #dma-cells = <1>; @@ -1034,7 +1040,7 @@ assigned-clocks = <&k3_clks 67 2>; assigned-clock-parents = <&k3_clks 67 5>; - interrupts = ; + interrupts = ; dma-coherent; diff --git a/arch/arm64/boot/dts/ti/k3-am65-mcu.dtsi b/arch/arm64/boot/dts/ti/k3-am65-mcu.dtsi index edd5cfbec40e66..ecd7356f3315d1 100644 --- a/arch/arm64/boot/dts/ti/k3-am65-mcu.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am65-mcu.dtsi @@ -214,8 +214,12 @@ compatible = "ti,am654-navss-mcu-udmap"; reg = <0x0 0x285c0000 0x0 0x100>, <0x0 0x2a800000 0x0 0x40000>, - <0x0 0x2aa00000 0x0 0x40000>; - reg-names = "gcfg", "rchanrt", "tchanrt"; + <0x0 0x2aa00000 0x0 0x40000>, + <0x0 0x284a0000 0x0 0x4000>, + <0x0 0x284c0000 0x0 0x4000>, + <0x0 0x28400000 0x0 0x2000>; + reg-names = "gcfg", "rchanrt", "tchanrt", + "tchan", "rchan", "rflow"; msi-parent = <&inta_main_udmass>; #dma-cells = <1>; diff --git a/arch/arm64/boot/dts/ti/k3-am65-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-am65-wakeup.dtsi index fd2b998ebddc4c..f037b36243ceda 100644 --- a/arch/arm64/boot/dts/ti/k3-am65-wakeup.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am65-wakeup.dtsi @@ -34,9 +34,16 @@ }; }; - chipid@43000014 { - compatible = "ti,am654-chipid"; - reg = <0x43000014 0x4>; + wkup_conf: bus@43000000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x43000000 0x20000>; + + chipid: chipid@14 { + compatible = "ti,am654-chipid"; + reg = <0x14 0x4>; + }; }; wkup_pmx0: pinctrl@4301c000 { diff --git a/arch/arm64/boot/dts/ti/k3-am652.dtsi b/arch/arm64/boot/dts/ti/k3-am652.dtsi new file mode 100644 index 00000000000000..0f22e00faa9032 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am652.dtsi @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device Tree Source for AM65 SoC family in Dual core configuration + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include "k3-am65.dtsi" + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + cpu-map { + cluster0: cluster0 { + core0 { + cpu = <&cpu0>; + }; + + core1 { + cpu = <&cpu1>; + }; + }; + }; + + cpu0: cpu@0 { + compatible = "arm,cortex-a53"; + reg = <0x000>; + device_type = "cpu"; + enable-method = "psci"; + i-cache-size = <0x8000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; + next-level-cache = <&L2_0>; + }; + + cpu1: cpu@1 { + compatible = "arm,cortex-a53"; + reg = <0x001>; + device_type = "cpu"; + enable-method = "psci"; + i-cache-size = <0x8000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <128>; + next-level-cache = <&L2_0>; + }; + }; + + L2_0: l2-cache0 { + compatible = "cache"; + cache-level = <2>; + cache-unified; + cache-size = <0x80000>; + cache-line-size = <64>; + cache-sets = <512>; + next-level-cache = <&msmc_l3>; + }; + + msmc_l3: l3-cache0 { + compatible = "cache"; + cache-level = <3>; + cache-unified; + }; + + thermal_zones: thermal-zones { + #include "k3-am654-industrial-thermal.dtsi" + }; +}; diff --git a/arch/arm64/boot/dts/ti/k3-am6528-iot2050-basic-common.dtsi b/arch/arm64/boot/dts/ti/k3-am6528-iot2050-basic-common.dtsi index 5ab434c02ab6b4..1d6cddb1199149 100644 --- a/arch/arm64/boot/dts/ti/k3-am6528-iot2050-basic-common.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am6528-iot2050-basic-common.dtsi @@ -9,6 +9,7 @@ * Common bits of the IOT2050 Basic variant, PG1 and PG2 */ +#include "k3-am652.dtsi" #include "k3-am65-iot2050-common.dtsi" / { @@ -17,21 +18,6 @@ /* 1G RAM */ reg = <0x00000000 0x80000000 0x00000000 0x40000000>; }; - - cpus { - cpu-map { - /delete-node/ cluster1; - }; - /delete-node/ cpu@100; - /delete-node/ cpu@101; - }; - - /delete-node/ l2-cache1; -}; - -/* eMMC */ -&sdhci0 { - status = "disabled"; }; &main_pmx0 { diff --git a/arch/arm64/boot/dts/ti/k3-am654-base-board.dts b/arch/arm64/boot/dts/ti/k3-am654-base-board.dts index 1637ec5ab5eda5..822c288d279763 100644 --- a/arch/arm64/boot/dts/ti/k3-am654-base-board.dts +++ b/arch/arm64/boot/dts/ti/k3-am654-base-board.dts @@ -449,6 +449,7 @@ }; &sdhci0 { + status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&main_mmc0_pins_default>; bus-width = <8>; @@ -463,6 +464,7 @@ * disable sdhci1 */ &sdhci1 { + status = "okay"; vmmc-supply = <&vdd_mmc1_sd>; pinctrl-names = "default"; pinctrl-0 = <&main_mmc1_pins_default>; diff --git a/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-common.dtsi b/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-common.dtsi index be55494b1f3fca..3864ec54e3716d 100644 --- a/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-common.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-common.dtsi @@ -11,6 +11,7 @@ /dts-v1/; +#include "k3-am654.dtsi" #include "k3-am65-iot2050-common.dtsi" / { @@ -43,6 +44,7 @@ /* eMMC */ &sdhci0 { + status = "okay"; pinctrl-names = "default"; pinctrl-0 = <&main_mmc0_pins_default>; bus-width = <8>; diff --git a/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-m2.dts b/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-m2.dts index 774eb14ac907d2..bd6f2e696e94c7 100644 --- a/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-m2.dts +++ b/arch/arm64/boot/dts/ti/k3-am6548-iot2050-advanced-m2.dts @@ -27,12 +27,6 @@ }; &main_pmx0 { - main_m2_enable_pins_default: main-m2-enable-default-pins { - pinctrl-single,pins = < - AM65X_IOPAD(0x01c4, PIN_INPUT_PULLUP, 7) /* (AH13) GPIO1_17 */ - >; - }; - main_bkey_pcie_reset: main-bkey-pcie-reset-default-pins { pinctrl-single,pins = < AM65X_IOPAD(0x01bc, PIN_OUTPUT_PULLUP, 7) /* (AG13) GPIO1_15 */ @@ -66,15 +60,13 @@ &main_gpio0 { pinctrl-names = "default"; - pinctrl-0 = - <&main_m2_pcie_mux_control>, - <&arduino_io_d4_to_d9_pins_default>; + pinctrl-0 = <&main_m2_pcie_mux_control>; }; &main_gpio1 { pinctrl-names = "default"; pinctrl-0 = - <&main_m2_enable_pins_default>, + <&main_pcie_enable_pins_default>, <&main_pmx0_m2_config_pins_default>, <&main_pmx1_m2_config_pins_default>, <&cp2102n_reset_pin_default>; diff --git a/arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts b/arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts index 1e1a82f9d2b813..d0cfdeac21fbe1 100644 --- a/arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts +++ b/arch/arm64/boot/dts/ti/k3-am68-sk-base-board.dts @@ -31,6 +31,7 @@ can1 = &mcu_mcan1; can2 = &main_mcan6; can3 = &main_mcan7; + ethernet0 = &cpsw_port1; }; vusb_main: regulator-vusb-main5v0 { diff --git a/arch/arm64/boot/dts/ti/k3-am69-sk.dts b/arch/arm64/boot/dts/ti/k3-am69-sk.dts index 9868c7049bfb9f..8da5915798688a 100644 --- a/arch/arm64/boot/dts/ti/k3-am69-sk.dts +++ b/arch/arm64/boot/dts/ti/k3-am69-sk.dts @@ -433,6 +433,13 @@ &wkup_pmx2 { bootph-all; + pmic_irq_pins_default: pmic-irq-default-pins { + pinctrl-single,pins = < + /* (AA37) MCU_ADC1_AIN4.WKUP_GPIO0_83 */ + J784S4_WKUP_IOPAD(0x0fc, PIN_INPUT, 7) + >; + }; + wkup_uart0_pins_default: wkup-uart0-default-pins { bootph-all; pinctrl-single,pins = < @@ -631,6 +638,93 @@ compatible = "atmel,24c512"; reg = <0x51>; }; + + tps659413: pmic@48 { + compatible = "ti,tps6594-q1"; + reg = <0x48>; + system-power-controller; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_irq_pins_default>; + interrupt-parent = <&wkup_gpio0>; + interrupts = <39 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + ti,primary-pmic; + buck12-supply = <&vsys_3v3>; + buck3-supply = <&vsys_3v3>; + buck4-supply = <&vsys_3v3>; + buck5-supply = <&vsys_3v3>; + ldo1-supply = <&vsys_3v3>; + ldo2-supply = <&vsys_3v3>; + ldo3-supply = <&vsys_3v3>; + ldo4-supply = <&vsys_3v3>; + + regulators { + bucka12: buck12 { + regulator-name = "vdd_ddr_1v1"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-boot-on; + regulator-always-on; + }; + + bucka3: buck3 { + regulator-name = "vdd_ram_0v85"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-boot-on; + regulator-always-on; + }; + + bucka4: buck4 { + regulator-name = "vdd_io_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + bucka5: buck5 { + regulator-name = "vdd_mcu_0v85"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa1: ldo1 { + regulator-name = "vdd_mcuio_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa2: ldo2 { + regulator-name = "vdd_mcuio_3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa3: ldo3 { + regulator-name = "vds_dll_0v8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa4: ldo4 { + regulator-name = "vda_mcu_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; }; &wkup_gpio0 { @@ -671,7 +765,7 @@ reg = <0x21>; gpio-controller; #gpio-cells = <2>; - gpio-line-names = "BOARDID_EEPROM_WP", "CAN_STB", "GPIO_uSD_PWR_EN", + gpio-line-names = "BOARDID_EEPROM_WP", "CAN_STB", "GPIO_uSD_PWR_EN", "IO_EXP_MCU_RGMII_RST#", "IO_EXP_PCIe0_4L_PERST#", "IO_EXP_PCIe1_M.2_RTSz", "IO_EXP_PCIe3_M.2_RTSz", "PM_INA_BUS_EN", "ENET1_EXP_PWRDN", "EXP1_ENET_RSTz", diff --git a/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi b/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi index 264913f8328767..da67bf8fe703eb 100644 --- a/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j7200-main.dtsi @@ -281,8 +281,12 @@ compatible = "ti,j721e-navss-main-udmap"; reg = <0x00 0x31150000 0x00 0x100>, <0x00 0x34000000 0x00 0x100000>, - <0x00 0x35000000 0x00 0x100000>; - reg-names = "gcfg", "rchanrt", "tchanrt"; + <0x00 0x35000000 0x00 0x100000>, + <0x00 0x30b00000 0x00 0x4000>, + <0x00 0x30c00000 0x00 0x4000>, + <0x00 0x30d00000 0x00 0x4000>; + reg-names = "gcfg", "rchanrt", "tchanrt", + "tchan", "rchan", "rflow"; msi-parent = <&main_udmass_inta>; #dma-cells = <1>; @@ -647,6 +651,7 @@ ti,otap-del-sel-hs400 = <0x5>; ti,itap-del-sel-legacy = <0x10>; ti,itap-del-sel-mmc-hs = <0xa>; + ti,itap-del-sel-ddr52 = <0x3>; ti,strobe-sel = <0x77>; ti,clkbuf-sel = <0x7>; ti,trm-icp = <0x8>; diff --git a/arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi index 3fc588b848c612..60b26374ae0ccf 100644 --- a/arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j7200-mcu-wakeup.dtsi @@ -178,9 +178,16 @@ }; }; - chipid@43000014 { - compatible = "ti,am654-chipid"; - reg = <0x00 0x43000014 0x00 0x4>; + wkup_conf: bus@43000000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x00 0x43000000 0x20000>; + + chipid: chipid@14 { + compatible = "ti,am654-chipid"; + reg = <0x14 0x4>; + }; }; /* MCU_TIMERIO pad input CTRLMMR_MCU_TIMER*_CTRL registers */ @@ -346,8 +353,12 @@ compatible = "ti,j721e-navss-mcu-udmap"; reg = <0x00 0x285c0000 0x00 0x100>, <0x00 0x2a800000 0x00 0x40000>, - <0x00 0x2aa00000 0x00 0x40000>; - reg-names = "gcfg", "rchanrt", "tchanrt"; + <0x00 0x2aa00000 0x00 0x40000>, + <0x00 0x284a0000 0x00 0x4000>, + <0x00 0x284c0000 0x00 0x4000>, + <0x00 0x28400000 0x00 0x2000>; + reg-names = "gcfg", "rchanrt", "tchanrt", + "tchan", "rchan", "rflow"; msi-parent = <&main_udmass_inta>; #dma-cells = <1>; diff --git a/arch/arm64/boot/dts/ti/k3-j7200-som-p0.dtsi b/arch/arm64/boot/dts/ti/k3-j7200-som-p0.dtsi index 5a300d4c8ba031..ea47f10d393afc 100644 --- a/arch/arm64/boot/dts/ti/k3-j7200-som-p0.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j7200-som-p0.dtsi @@ -127,6 +127,14 @@ }; }; +&wkup_pmx3 { + pmic_irq_pins_default: pmic-irq-default-pins { + pinctrl-single,pins = < + J721E_WKUP_IOPAD(0x01c, PIN_INPUT, 7) /* (E18) WKUP_GPIO0_84 */ + >; + }; +}; + &main_pmx0 { main_i2c0_pins_default: main-i2c0-default-pins { pinctrl-single,pins = < @@ -264,6 +272,151 @@ compatible = "atmel,24c256"; reg = <0x50>; }; + + tps659414: pmic@48 { + compatible = "ti,tps6594-q1"; + reg = <0x48>; + system-power-controller; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_irq_pins_default>; + interrupt-parent = <&wkup_gpio0>; + interrupts = <84 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + ti,primary-pmic; + buck1-supply = <&vsys_3v3>; + buck2-supply = <&vsys_3v3>; + buck3-supply = <&vsys_3v3>; + buck4-supply = <&vsys_3v3>; + buck5-supply = <&vsys_3v3>; + ldo1-supply = <&vsys_3v3>; + ldo2-supply = <&vsys_3v3>; + ldo3-supply = <&vsys_3v3>; + ldo4-supply = <&vsys_3v3>; + + regulators { + bucka1: buck1 { + regulator-name = "vda_mcu_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + bucka2: buck2 { + regulator-name = "vdd_mcuio_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + bucka3: buck3 { + regulator-name = "vdd_mcu_0v85"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-boot-on; + regulator-always-on; + }; + + bucka4: buck4 { + regulator-name = "vdd_ddr_1v1"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-boot-on; + regulator-always-on; + }; + + bucka5: buck5 { + regulator-name = "vdd_phyio_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa1: ldo1 { + regulator-name = "vdd1_lpddr4_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa2: ldo2 { + regulator-name = "vda_dll_0v8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa3: ldo3 { + regulator-name = "vdd_wk_0v8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa4: ldo4 { + regulator-name = "vda_pll_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; + + lp876441: pmic@4c { + compatible = "ti,lp8764-q1"; + reg = <0x4c>; + system-power-controller; + interrupt-parent = <&wkup_gpio0>; + interrupts = <84 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + buck1-supply = <&vsys_3v3>; + buck2-supply = <&vsys_3v3>; + buck3-supply = <&vsys_3v3>; + buck4-supply = <&vsys_3v3>; + + regulators: regulators { + buckb1: buck1 { + regulator-name = "vdd_cpu_avs"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <900000>; + regulator-always-on; + regulator-boot-on; + bootph-pre-ram; + }; + + buckb2: buck2 { + regulator-name = "vdd_ram_0v85"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-boot-on; + regulator-always-on; + }; + + buckb3: buck3 { + regulator-name = "vdd_core_0v85"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-boot-on; + regulator-always-on; + }; + + buckb4: buck4 { + regulator-name = "vdd_io_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; }; &ospi0 { diff --git a/arch/arm64/boot/dts/ti/k3-j721e-evm-pcie0-ep.dtso b/arch/arm64/boot/dts/ti/k3-j721e-evm-pcie0-ep.dtso new file mode 100644 index 00000000000000..0c82a13b65a47f --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-j721e-evm-pcie0-ep.dtso @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 +/** + * DT Overlay for enabling PCIE0 instance in Endpoint Configuration with the + * J7 common processor board. + * + * J7 Common Processor Board Product Link: https://www.ti.com/tool/J721EXCPXEVM + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include + +#include "k3-pinctrl.h" + +/* + * Since Root Complex and Endpoint modes are mutually exclusive + * disable Root Complex mode. + */ +&pcie0_rc { + status = "disabled"; +}; + +&cbass_main { + #address-cells = <2>; + #size-cells = <2>; + interrupt-parent = <&gic500>; + + pcie0_ep: pcie-ep@2900000 { + compatible = "ti,j721e-pcie-ep"; + reg = <0x00 0x02900000 0x00 0x1000>, + <0x00 0x02907000 0x00 0x400>, + <0x00 0x0d000000 0x00 0x00800000>, + <0x00 0x10000000 0x00 0x08000000>; + reg-names = "intd_cfg", "user_cfg", "reg", "mem"; + interrupt-names = "link_state"; + interrupts = ; + ti,syscon-pcie-ctrl = <&scm_conf 0x4070>; + max-link-speed = <3>; + num-lanes = <1>; + power-domains = <&k3_pds 239 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 239 1>; + clock-names = "fck"; + max-functions = /bits/ 8 <6>; + max-virtual-functions = /bits/ 8 <4 4 4 4 0 0>; + dma-coherent; + phys = <&serdes0_pcie_link>; + phy-names = "pcie-phy"; + }; +}; diff --git a/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi b/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi index 746b9f8b1c6401..2569b4c08ffb85 100644 --- a/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi @@ -382,8 +382,12 @@ compatible = "ti,j721e-navss-main-udmap"; reg = <0x0 0x31150000 0x0 0x100>, <0x0 0x34000000 0x0 0x100000>, - <0x0 0x35000000 0x0 0x100000>; - reg-names = "gcfg", "rchanrt", "tchanrt"; + <0x0 0x35000000 0x0 0x100000>, + <0x0 0x30b00000 0x0 0x20000>, + <0x0 0x30c00000 0x0 0x10000>, + <0x0 0x30d00000 0x0 0x8000>; + reg-names = "gcfg", "rchanrt", "tchanrt", + "tchan", "rchan", "rflow"; msi-parent = <&main_udmass_inta>; #dma-cells = <1>; diff --git a/arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi index f7ab7719fc077a..a74912d9e4dafd 100644 --- a/arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j721e-mcu-wakeup.dtsi @@ -48,9 +48,16 @@ }; }; - chipid@43000014 { - compatible = "ti,am654-chipid"; - reg = <0x0 0x43000014 0x0 0x4>; + wkup_conf: bus@43000000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x00 0x43000000 0x20000>; + + chipid: chipid@14 { + compatible = "ti,am654-chipid"; + reg = <0x14 0x4>; + }; }; wkup_pmx0: pinctrl@4301c000 { @@ -468,8 +475,12 @@ compatible = "ti,j721e-navss-mcu-udmap"; reg = <0x0 0x285c0000 0x0 0x100>, <0x0 0x2a800000 0x0 0x40000>, - <0x0 0x2aa00000 0x0 0x40000>; - reg-names = "gcfg", "rchanrt", "tchanrt"; + <0x0 0x2aa00000 0x0 0x40000>, + <0x0 0x284a0000 0x0 0x4000>, + <0x0 0x284c0000 0x0 0x4000>, + <0x0 0x28400000 0x0 0x2000>; + reg-names = "gcfg", "rchanrt", "tchanrt", + "tchan", "rchan", "rflow"; msi-parent = <&main_udmass_inta>; #dma-cells = <1>; diff --git a/arch/arm64/boot/dts/ti/k3-j721e-sk.dts b/arch/arm64/boot/dts/ti/k3-j721e-sk.dts index 42fe8eee9ec8c7..188dfe291a32b4 100644 --- a/arch/arm64/boot/dts/ti/k3-j721e-sk.dts +++ b/arch/arm64/boot/dts/ti/k3-j721e-sk.dts @@ -459,6 +459,12 @@ }; &wkup_pmx0 { + pmic_irq_pins_default: pmic-irq-default-pins { + pinctrl-single,pins = < + J721E_WKUP_IOPAD(0x0cc, PIN_INPUT, 7) /* (G28) WKUP_GPIO0_7 */ + >; + }; + mcu_cpsw_pins_default: mcu-cpsw-default-pins { pinctrl-single,pins = < J721E_WKUP_IOPAD(0x84, PIN_INPUT, 0) /* (B24) MCU_RGMII1_RD0 */ @@ -560,6 +566,151 @@ compatible = "atmel,24c512"; reg = <0x51>; }; + + tps659413: pmic@48 { + compatible = "ti,tps6594-q1"; + reg = <0x48>; + system-power-controller; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_irq_pins_default>; + interrupt-parent = <&wkup_gpio0>; + interrupts = <9 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + ti,primary-pmic; + buck123-supply = <&vsys_3v3>; + buck4-supply = <&vsys_3v3>; + buck5-supply = <&vsys_3v3>; + ldo1-supply = <&vsys_3v3>; + ldo2-supply = <&vsys_3v3>; + ldo3-supply = <&vsys_3v3>; + ldo4-supply = <&vsys_3v3>; + + regulators { + bucka123: buck123 { + regulator-name = "vdd_cpu_avs"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <900000>; + regulator-boot-on; + regulator-always-on; + bootph-pre-ram; + }; + + bucka4: buck4 { + regulator-name = "vdd_mcu_0v85"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-boot-on; + regulator-always-on; + }; + + bucka5: buck5 { + regulator-name = "vdd_phyio_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa1: ldo1 { + regulator-name = "vdd1_lpddr4_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa2: ldo2 { + regulator-name = "vdd_mcuio_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa3: ldo3 { + regulator-name = "vdda_dll_0v8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa4: ldo4 { + regulator-name = "vda_mcu_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; + + tps659411: pmic@4c { + compatible = "ti,tps6594-q1"; + reg = <0x4c>; + system-power-controller; + interrupt-parent = <&wkup_gpio0>; + interrupts = <9 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + buck1234-supply = <&vsys_3v3>; + buck5-supply = <&vsys_3v3>; + ldo1-supply = <&vsys_3v3>; + ldo2-supply = <&vsys_3v3>; + ldo3-supply = <&vsys_3v3>; + ldo4-supply = <&vsys_3v3>; + + regulators { + buckb1234: buck1234 { + regulator-name = "vdd_core_0v8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-boot-on; + regulator-always-on; + }; + + buckb5: buck5 { + regulator-name = "vdd_ram_0v85"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-boot-on; + regulator-always-on; + }; + + ldob1: ldo1 { + regulator-name = "vdd_sd_dv"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + ldob2: ldo2 { + regulator-name = "vdd_usb_3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + ldob3: ldo3 { + regulator-name = "vdd_io_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldob4: ldo4 { + regulator-name = "vda_pll_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; }; &mcu_uart0 { diff --git a/arch/arm64/boot/dts/ti/k3-j721e-som-p0.dtsi b/arch/arm64/boot/dts/ti/k3-j721e-som-p0.dtsi index 7f0686c2ce371d..a75611eec79142 100644 --- a/arch/arm64/boot/dts/ti/k3-j721e-som-p0.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j721e-som-p0.dtsi @@ -152,6 +152,12 @@ >; }; + pmic_irq_pins_default: pmic-irq-default-pins { + pinctrl-single,pins = < + J721E_WKUP_IOPAD(0x0d4, PIN_INPUT, 7) /* (G26) WKUP_GPIO0_9 */ + >; + }; + mcu_fss0_ospi0_pins_default: mcu-fss0-ospi0-default-pins { pinctrl-single,pins = < J721E_WKUP_IOPAD(0x0000, PIN_OUTPUT, 0) /* MCU_OSPI0_CLK */ @@ -199,6 +205,160 @@ compatible = "atmel,24c256"; reg = <0x50>; }; + + tps659413: pmic@48 { + compatible = "ti,tps6594-q1"; + reg = <0x48>; + system-power-controller; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_irq_pins_default>; + interrupt-parent = <&wkup_gpio0>; + interrupts = <9 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + ti,primary-pmic; + buck12-supply = <&vsys_3v3>; + buck3-supply = <&vsys_3v3>; + buck4-supply = <&vsys_3v3>; + buck5-supply = <&vsys_3v3>; + ldo1-supply = <&vsys_3v3>; + ldo2-supply = <&vsys_3v3>; + ldo3-supply = <&vsys_3v3>; + ldo4-supply = <&vsys_3v3>; + + regulators { + bucka12: buck12 { + regulator-name = "vdd_cpu_avs"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <900000>; + regulator-boot-on; + regulator-always-on; + bootph-pre-ram; + }; + + bucka3: buck3 { + regulator-name = "vdd_mcu_0v85"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-boot-on; + regulator-always-on; + }; + + bucka4: buck4 { + regulator-name = "vdd_ddr_1v1"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-boot-on; + regulator-always-on; + }; + + bucka5: buck5 { + regulator-name = "vdd_phyio_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa1: ldo1 { + regulator-name = "vdd1_lpddr4_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa2: ldo2 { + regulator-name = "vdd_mcuio_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa3: ldo3 { + regulator-name = "vdda_dll_0v8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa4: ldo4 { + regulator-name = "vda_mcu_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; + + tps659411: pmic@4c { + compatible = "ti,tps6594-q1"; + reg = <0x4c>; + system-power-controller; + interrupt-parent = <&wkup_gpio0>; + interrupts = <9 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + buck1234-supply = <&vsys_3v3>; + buck5-supply = <&vsys_3v3>; + ldo1-supply = <&vsys_3v3>; + ldo2-supply = <&vsys_3v3>; + ldo3-supply = <&vsys_3v3>; + ldo4-supply = <&vsys_3v3>; + + regulators { + buckb1234: buck1234 { + regulator-name = "vdd_core_0v8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-boot-on; + regulator-always-on; + }; + + buckb5: buck5 { + regulator-name = "vdd_ram_0v85"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-boot-on; + regulator-always-on; + }; + + ldob1: ldo1 { + regulator-name = "vdd_sd_dv"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + ldob2: ldo2 { + regulator-name = "vdd_usb_3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + ldob3: ldo3 { + regulator-name = "vdd_io_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldob4: ldo4 { + regulator-name = "vda_pll_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; }; &ospi0 { diff --git a/arch/arm64/boot/dts/ti/k3-j721s2-evm-pcie1-ep.dtso b/arch/arm64/boot/dts/ti/k3-j721s2-evm-pcie1-ep.dtso new file mode 100644 index 00000000000000..43568eb67d93f5 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-j721s2-evm-pcie1-ep.dtso @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 +/** + * DT Overlay for enabling PCIE1 instance in Endpoint Configuration with the + * J7 common processor board. + * + * J7 Common Processor Board Product Link: https://www.ti.com/tool/J721EXCPXEVM + * + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include + +#include "k3-pinctrl.h" + +/* + * Since Root Complex and Endpoint modes are mutually exclusive + * disable Root Complex mode. + */ +&pcie1_rc { + status = "disabled"; +}; + +&cbass_main { + #address-cells = <2>; + #size-cells = <2>; + interrupt-parent = <&gic500>; + + pcie1_ep: pcie-ep@2910000 { + compatible = "ti,j7200-pcie-ep", "ti,j721e-pcie-ep"; + reg = <0x00 0x02910000 0x00 0x1000>, + <0x00 0x02917000 0x00 0x400>, + <0x00 0x0d800000 0x00 0x00800000>, + <0x00 0x18000000 0x00 0x08000000>; + reg-names = "intd_cfg", "user_cfg", "reg", "mem"; + interrupt-names = "link_state"; + interrupts = ; + ti,syscon-pcie-ctrl = <&scm_conf 0x074>; + max-link-speed = <3>; + num-lanes = <1>; + power-domains = <&k3_pds 276 TI_SCI_PD_EXCLUSIVE>; + clocks = <&k3_clks 276 41>; + clock-names = "fck"; + max-functions = /bits/ 8 <6>; + max-virtual-functions = /bits/ 8 <4 4 4 4 0 0>; + dma-coherent; + phys = <&serdes0_pcie_link>; + phy-names = "pcie-phy"; + }; +}; diff --git a/arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi b/arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi index b03731b53a2631..ea7f2b2ab165d3 100644 --- a/arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi @@ -766,6 +766,7 @@ ti,itap-del-sel-sd-hs = <0x0>; ti,itap-del-sel-sdr12 = <0x0>; ti,itap-del-sel-sdr25 = <0x0>; + ti,itap-del-sel-ddr50 = <0x2>; ti,clkbuf-sel = <0x7>; ti,trm-icp = <0x8>; dma-coherent; @@ -1086,8 +1087,12 @@ compatible = "ti,j721e-navss-main-udmap"; reg = <0x0 0x31150000 0x0 0x100>, <0x0 0x34000000 0x0 0x80000>, - <0x0 0x35000000 0x0 0x200000>; - reg-names = "gcfg", "rchanrt", "tchanrt"; + <0x0 0x35000000 0x0 0x200000>, + <0x0 0x30b00000 0x0 0x20000>, + <0x0 0x30c00000 0x0 0x8000>, + <0x0 0x30d00000 0x0 0x4000>; + reg-names = "gcfg", "rchanrt", "tchanrt", + "tchan", "rchan", "rflow"; msi-parent = <&main_udmass_inta>; #dma-cells = <1>; diff --git a/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi index 7254f3bd3634da..80aa33c58a452b 100644 --- a/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j721s2-mcu-wakeup.dtsi @@ -34,9 +34,16 @@ }; }; - chipid@43000014 { - compatible = "ti,am654-chipid"; - reg = <0x00 0x43000014 0x00 0x4>; + wkup_conf: bus@43000000 { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x00 0x43000000 0x20000>; + + chipid: chipid@14 { + compatible = "ti,am654-chipid"; + reg = <0x14 0x4>; + }; }; secure_proxy_sa3: mailbox@43600000 { @@ -471,8 +478,12 @@ compatible = "ti,j721e-navss-mcu-udmap"; reg = <0x0 0x285c0000 0x0 0x100>, <0x0 0x2a800000 0x0 0x40000>, - <0x0 0x2aa00000 0x0 0x40000>; - reg-names = "gcfg", "rchanrt", "tchanrt"; + <0x0 0x2aa00000 0x0 0x40000>, + <0x0 0x284a0000 0x0 0x4000>, + <0x0 0x284c0000 0x0 0x4000>, + <0x0 0x28400000 0x0 0x2000>; + reg-names = "gcfg", "rchanrt", "tchanrt", + "tchan", "rchan", "rflow"; msi-parent = <&main_udmass_inta>; #dma-cells = <1>; diff --git a/arch/arm64/boot/dts/ti/k3-j721s2-som-p0.dtsi b/arch/arm64/boot/dts/ti/k3-j721s2-som-p0.dtsi index dcad372620b1d0..da3237b23b63ac 100644 --- a/arch/arm64/boot/dts/ti/k3-j721s2-som-p0.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j721s2-som-p0.dtsi @@ -172,6 +172,15 @@ }; }; +&wkup_pmx1 { + pmic_irq_pins_default: pmic-irq-default-pins { + pinctrl-single,pins = < + /* (C21) MCU_OSPI1_CSn1.WKUP_GPIO0_39 */ + J721S2_WKUP_IOPAD(0x028, PIN_INPUT, 7) + >; + }; +}; + &wkup_pmx2 { wkup_i2c0_pins_default: wkup-i2c0-default-pins { pinctrl-single,pins = < @@ -208,6 +217,190 @@ compatible = "atmel,24c256"; reg = <0x50>; }; + + tps659411: pmic@48 { + compatible = "ti,tps6594-q1"; + reg = <0x48>; + system-power-controller; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_irq_pins_default>; + interrupt-parent = <&wkup_gpio0>; + interrupts = <39 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + ti,primary-pmic; + buck1234-supply = <&vsys_3v3>; + buck5-supply = <&vsys_3v3>; + ldo1-supply = <&vsys_3v3>; + ldo2-supply = <&vsys_3v3>; + ldo3-supply = <&vsys_3v3>; + ldo4-supply = <&vsys_3v3>; + + regulators { + bucka1234: buck1234 { + regulator-name = "vdd_cpu_avs"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <900000>; + regulator-boot-on; + regulator-always-on; + bootph-pre-ram; + }; + + bucka5: buck5 { + regulator-name = "vdd_mcu_0v85"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa1: ldo1 { + regulator-name = "vdd_mcuwk_0v8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa2: ldo2 { + regulator-name = "vdd_mcu_gpioret_3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa3: ldo3 { + regulator-name = "vdd_mcuio_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa4: ldo4 { + regulator-name = "vda_mcu_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; + + tps659414: pmic@4c { + compatible = "ti,tps6594-q1"; + reg = <0x4c>; + system-power-controller; + interrupt-parent = <&wkup_gpio0>; + interrupts = <39 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + buck1-supply = <&vsys_3v3>; + buck2-supply = <&vsys_3v3>; + buck3-supply = <&vsys_3v3>; + buck4-supply = <&vsys_3v3>; + buck5-supply = <&vsys_3v3>; + ldo1-supply = <&vsys_3v3>; + ldo2-supply = <&vsys_3v3>; + ldo3-supply = <&vsys_3v3>; + ldo4-supply = <&vsys_3v3>; + + regulators { + buckb1: buck1 { + regulator-name = "vdd_io_1v8_reg"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + regulator-boot-on; + }; + + buckb2: buck2 { + regulator-name = "vdd_fpd_1v1"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-boot-on; + regulator-always-on; + }; + + buckb3: buck3 { + regulator-name = "vdd_phy_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + buckb4: buck4 { + regulator-name = "vdd_ddr_1v1"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-boot-on; + regulator-always-on; + }; + + buckb5: buck5 { + regulator-name = "vdd_ram_0v85"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-boot-on; + regulator-always-on; + }; + + ldob1: ldo1 { + regulator-name = "vdd_wk_0v8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldob2: ldo2 { + regulator-name = "vdd_gpioret_3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + ldob3: ldo3 { + regulator-name = "vda_dll_0v8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldob4: ldo4 { + regulator-name = "vda_pll_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; + + lp876411: pmic@58 { + compatible = "ti,lp8764-q1"; + reg = <0x58>; + system-power-controller; + interrupt-parent = <&wkup_gpio0>; + interrupts = <39 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + buck1234-supply = <&vsys_3v3>; + + regulators { + buckc1234: buck1234 { + regulator-name = "vdd_core_0v8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; }; &main_i2c0 { diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-evm.dts b/arch/arm64/boot/dts/ti/k3-j784s4-evm.dts index f1f4c8634ab690..f34b92acc56d87 100644 --- a/arch/arm64/boot/dts/ti/k3-j784s4-evm.dts +++ b/arch/arm64/boot/dts/ti/k3-j784s4-evm.dts @@ -273,6 +273,10 @@ }; }; +&wkup_gpio0 { + status = "okay"; +}; + &main_pmx0 { bootph-all; main_uart8_pins_default: main-uart8-default-pins { @@ -407,6 +411,17 @@ }; }; +&wkup_pmx1 { + status = "okay"; + + pmic_irq_pins_default: pmic-irq-default-pins { + pinctrl-single,pins = < + /* (G33) MCU_OSPI1_CSn1.WKUP_GPIO0_39 */ + J784S4_WKUP_IOPAD(0x028, PIN_INPUT, 7) + >; + }; +}; + &wkup_pmx0 { bootph-all; mcu_fss0_ospi0_pins_default: mcu-fss0-ospi0-default-pins { @@ -471,6 +486,93 @@ compatible = "atmel,24c256"; reg = <0x50>; }; + + tps659413: pmic@48 { + compatible = "ti,tps6594-q1"; + reg = <0x48>; + system-power-controller; + pinctrl-names = "default"; + pinctrl-0 = <&pmic_irq_pins_default>; + interrupt-parent = <&wkup_gpio0>; + interrupts = <39 IRQ_TYPE_EDGE_FALLING>; + gpio-controller; + #gpio-cells = <2>; + ti,primary-pmic; + buck12-supply = <&vsys_3v3>; + buck3-supply = <&vsys_3v3>; + buck4-supply = <&vsys_3v3>; + buck5-supply = <&vsys_3v3>; + ldo1-supply = <&vsys_3v3>; + ldo2-supply = <&vsys_3v3>; + ldo3-supply = <&vsys_3v3>; + ldo4-supply = <&vsys_3v3>; + + regulators { + bucka12: buck12 { + regulator-name = "vdd_ddr_1v1"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-boot-on; + regulator-always-on; + }; + + bucka3: buck3 { + regulator-name = "vdd_ram_0v85"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-boot-on; + regulator-always-on; + }; + + bucka4: buck4 { + regulator-name = "vdd_io_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + bucka5: buck5 { + regulator-name = "vdd_mcu_0v85"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa1: ldo1 { + regulator-name = "vdd_mcuio_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa2: ldo2 { + regulator-name = "vdd_mcuio_3v3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa3: ldo3 { + regulator-name = "vds_dll_0v8"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + regulator-boot-on; + regulator-always-on; + }; + + ldoa4: ldo4 { + regulator-name = "vda_mcu_1v8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; }; &mcu_uart0 { diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi index d89bcddcfe3d45..f2b720ed1e4f23 100644 --- a/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j784s4-main.dtsi @@ -712,6 +712,7 @@ ti,itap-del-sel-sd-hs = <0x0>; ti,itap-del-sel-sdr12 = <0x0>; ti,itap-del-sel-sdr25 = <0x0>; + ti,itap-del-sel-ddr50 = <0x2>; ti,clkbuf-sel = <0x7>; ti,trm-icp = <0x8>; dma-coherent; @@ -1188,8 +1189,12 @@ compatible = "ti,j721e-navss-main-udmap"; reg = <0x00 0x31150000 0x00 0x100>, <0x00 0x34000000 0x00 0x80000>, - <0x00 0x35000000 0x00 0x200000>; - reg-names = "gcfg", "rchanrt", "tchanrt"; + <0x00 0x35000000 0x00 0x200000>, + <0x00 0x30b00000 0x00 0x20000>, + <0x00 0x30c00000 0x00 0x8000>, + <0x00 0x30d00000 0x00 0x4000>; + reg-names = "gcfg", "rchanrt", "tchanrt", + "tchan", "rchan", "rflow"; msi-parent = <&main_udmass_inta>; #dma-cells = <1>; diff --git a/arch/arm64/boot/dts/ti/k3-j784s4-mcu-wakeup.dtsi b/arch/arm64/boot/dts/ti/k3-j784s4-mcu-wakeup.dtsi index adb5ea6b973214..3902a921d7e585 100644 --- a/arch/arm64/boot/dts/ti/k3-j784s4-mcu-wakeup.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j784s4-mcu-wakeup.dtsi @@ -38,10 +38,18 @@ }; }; - chipid@43000014 { + wkup_conf: bus@43000000 { bootph-all; - compatible = "ti,am654-chipid"; - reg = <0x00 0x43000014 0x00 0x4>; + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x00 0x43000000 0x20000>; + + chipid: chipid@14 { + bootph-all; + compatible = "ti,am654-chipid"; + reg = <0x14 0x4>; + }; }; secure_proxy_sa3: mailbox@43600000 { @@ -478,8 +486,12 @@ compatible = "ti,j721e-navss-mcu-udmap"; reg = <0x00 0x285c0000 0x00 0x100>, <0x00 0x2a800000 0x00 0x40000>, - <0x00 0x2aa00000 0x00 0x40000>; - reg-names = "gcfg", "rchanrt", "tchanrt"; + <0x00 0x2aa00000 0x00 0x40000>, + <0x00 0x284a0000 0x00 0x4000>, + <0x00 0x284c0000 0x00 0x4000>, + <0x00 0x28400000 0x00 0x2000>; + reg-names = "gcfg", "rchanrt", "tchanrt", + "tchan", "rchan", "rflow"; msi-parent = <&main_udmass_inta>; #dma-cells = <1>; diff --git a/arch/arm64/boot/dts/xilinx/Makefile b/arch/arm64/boot/dts/xilinx/Makefile index 5e40c0b4fa0a90..1068b0fa8e9847 100644 --- a/arch/arm64/boot/dts/xilinx/Makefile +++ b/arch/arm64/boot/dts/xilinx/Makefile @@ -22,11 +22,10 @@ dtb-$(CONFIG_ARCH_ZYNQMP) += zynqmp-sm-k26-revA.dtb dtb-$(CONFIG_ARCH_ZYNQMP) += zynqmp-smk-k26-revA.dtb zynqmp-sm-k26-revA-sck-kv-g-revA-dtbs := zynqmp-sm-k26-revA.dtb zynqmp-sck-kv-g-revA.dtbo +dtb-$(CONFIG_ARCH_ZYNQMP) += zynqmp-sm-k26-revA-sck-kv-g-revA.dtb zynqmp-sm-k26-revA-sck-kv-g-revB-dtbs := zynqmp-sm-k26-revA.dtb zynqmp-sck-kv-g-revB.dtbo +dtb-$(CONFIG_ARCH_ZYNQMP) += zynqmp-sm-k26-revA-sck-kv-g-revB.dtb zynqmp-smk-k26-revA-sck-kv-g-revA-dtbs := zynqmp-smk-k26-revA.dtb zynqmp-sck-kv-g-revA.dtbo +dtb-$(CONFIG_ARCH_ZYNQMP) += zynqmp-smk-k26-revA-sck-kv-g-revA.dtb zynqmp-smk-k26-revA-sck-kv-g-revB-dtbs := zynqmp-smk-k26-revA.dtb zynqmp-sck-kv-g-revB.dtbo - -zynqmp-sm-k26-revA-sck-kr-g-revA-dtbs := zynqmp-sm-k26-revA.dtb zynqmp-sck-kr-g-revA.dtbo -zynqmp-sm-k26-revA-sck-kr-g-revB-dtbs := zynqmp-sm-k26-revA.dtb zynqmp-sck-kr-g-revB.dtbo -zynqmp-smk-k26-revA-sck-kr-g-revA-dtbs := zynqmp-smk-k26-revA.dtb zynqmp-sck-kr-g-revA.dtbo -zynqmp-smk-k26-revA-sck-kr-g-revB-dtbs := zynqmp-smk-k26-revA.dtb zynqmp-sck-kr-g-revB.dtbo +dtb-$(CONFIG_ARCH_ZYNQMP) += zynqmp-smk-k26-revA-sck-kv-g-revB.dtb diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revA.dtso b/arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revA.dtso index ae1b9b2bdbee27..92f4190d564db1 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revA.dtso +++ b/arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revA.dtso @@ -21,57 +21,57 @@ /dts-v1/; /plugin/; -&i2c1 { /* I2C_SCK C23/C24 - MIO from SOM */ - #address-cells = <1>; - #size-cells = <0>; - pinctrl-names = "default", "gpio"; - pinctrl-0 = <&pinctrl_i2c1_default>; - pinctrl-1 = <&pinctrl_i2c1_gpio>; - scl-gpios = <&gpio 24 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; - sda-gpios = <&gpio 25 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; - - /* u14 - 0x40 - ina260 */ - /* u27 - 0xe0 - STDP4320 DP/HDMI splitter */ -}; - -&amba { - si5332_0: si5332_0 { /* u17 */ +&{/} { + si5332_0: si5332-0 { /* u17 */ compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <125000000>; }; - si5332_1: si5332_1 { /* u17 */ + si5332_1: si5332-1 { /* u17 */ compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <25000000>; }; - si5332_2: si5332_2 { /* u17 */ + si5332_2: si5332-2 { /* u17 */ compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <48000000>; }; - si5332_3: si5332_3 { /* u17 */ + si5332_3: si5332-3 { /* u17 */ compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <24000000>; }; - si5332_4: si5332_4 { /* u17 */ + si5332_4: si5332-4 { /* u17 */ compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <26000000>; }; - si5332_5: si5332_5 { /* u17 */ + si5332_5: si5332-5 { /* u17 */ compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <27000000>; }; }; +&i2c1 { /* I2C_SCK C23/C24 - MIO from SOM */ + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default", "gpio"; + pinctrl-0 = <&pinctrl_i2c1_default>; + pinctrl-1 = <&pinctrl_i2c1_gpio>; + scl-gpios = <&gpio 24 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + sda-gpios = <&gpio 25 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + + /* u14 - 0x40 - ina260 */ + /* u27 - 0xe0 - STDP4320 DP/HDMI splitter */ +}; + /* DP/USB 3.0 and SATA */ &psgtr { status = "okay"; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revB.dtso b/arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revB.dtso index b59e48be6465a5..f88b71f5b07a63 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revB.dtso +++ b/arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revB.dtso @@ -16,58 +16,58 @@ /dts-v1/; /plugin/; -&i2c1 { /* I2C_SCK C23/C24 - MIO from SOM */ - #address-cells = <1>; - #size-cells = <0>; - pinctrl-names = "default", "gpio"; - pinctrl-0 = <&pinctrl_i2c1_default>; - pinctrl-1 = <&pinctrl_i2c1_gpio>; - scl-gpios = <&gpio 24 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; - sda-gpios = <&gpio 25 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; - - /* u14 - 0x40 - ina260 */ - /* u43 - 0x2d - usb5744 */ - /* u27 - 0xe0 - STDP4320 DP/HDMI splitter */ -}; - -&amba { - si5332_0: si5332_0 { /* u17 */ +&{/} { + si5332_0: si5332-0 { /* u17 */ compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <125000000>; }; - si5332_1: si5332_1 { /* u17 */ + si5332_1: si5332-1 { /* u17 */ compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <25000000>; }; - si5332_2: si5332_2 { /* u17 */ + si5332_2: si5332-2 { /* u17 */ compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <48000000>; }; - si5332_3: si5332_3 { /* u17 */ + si5332_3: si5332-3 { /* u17 */ compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <24000000>; }; - si5332_4: si5332_4 { /* u17 */ + si5332_4: si5332-4 { /* u17 */ compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <26000000>; }; - si5332_5: si5332_5 { /* u17 */ + si5332_5: si5332-5 { /* u17 */ compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <27000000>; }; }; +&i2c1 { /* I2C_SCK C23/C24 - MIO from SOM */ + #address-cells = <1>; + #size-cells = <0>; + pinctrl-names = "default", "gpio"; + pinctrl-0 = <&pinctrl_i2c1_default>; + pinctrl-1 = <&pinctrl_i2c1_gpio>; + scl-gpios = <&gpio 24 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + sda-gpios = <&gpio 25 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + + /* u14 - 0x40 - ina260 */ + /* u43 - 0x2d - usb5744 */ + /* u27 - 0xe0 - STDP4320 DP/HDMI splitter */ +}; + /* DP/USB 3.0 */ &psgtr { status = "okay"; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-sm-k26-revA.dts b/arch/arm64/boot/dts/xilinx/zynqmp-sm-k26-revA.dts index c4774a42d5fcd4..51622896b1b1c3 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-sm-k26-revA.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-sm-k26-revA.dts @@ -131,9 +131,7 @@ &qspi { /* MIO 0-5 - U143 */ status = "okay"; spi_flash: flash@0 { /* MT25QU512A */ - compatible = "mt25qu512a", "jedec,spi-nor"; /* 64MB */ - #address-cells = <1>; - #size-cells = <1>; + compatible = "jedec,spi-nor"; /* 64MB */ reg = <0>; spi-tx-bus-width = <4>; spi-rx-bus-width = <4>; @@ -222,9 +220,9 @@ label = "Secure OS Storage"; reg = <0x2280000 0x20000>; /* 128KB */ }; - partition@22A0000 { + partition@22a0000 { label = "User"; - reg = <0x22A0000 0x1d60000>; /* 29.375 MB */ + reg = <0x22a0000 0x1d60000>; /* 29.375 MB */ }; }; }; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm015-dc1.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm015-dc1.dts index e821d55d8d5a89..73491626e01e65 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm015-dc1.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm015-dc1.dts @@ -98,8 +98,12 @@ phy-mode = "rgmii-id"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_gem3_default>; - phy0: ethernet-phy@0 { - reg = <0>; + mdio: mdio { + #address-cells = <1>; + #size-cells = <0>; + phy0: ethernet-phy@0 { + reg = <0>; + }; }; }; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm016-dc2.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm016-dc2.dts index b59e11316b4be0..f767708fb50d92 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm016-dc2.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm016-dc2.dts @@ -91,12 +91,16 @@ phy-mode = "rgmii-id"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_gem2_default>; - phy0: ethernet-phy@5 { - reg = <5>; - ti,rx-internal-delay = <0x8>; - ti,tx-internal-delay = <0xa>; - ti,fifo-depth = <0x1>; - ti,dp83867-rxctrl-strap-quirk; + mdio: mdio { + #address-cells = <1>; + #size-cells = <0>; + phy0: ethernet-phy@5 { + reg = <5>; + ti,rx-internal-delay = <0x8>; + ti,tx-internal-delay = <0xa>; + ti,fifo-depth = <0x1>; + ti,dp83867-rxctrl-strap-quirk; + }; }; }; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm017-dc3.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm017-dc3.dts index 38b0a312171b70..f553b317e6b2a5 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm017-dc3.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm017-dc3.dts @@ -88,8 +88,12 @@ status = "okay"; phy-handle = <&phy0>; phy-mode = "rgmii-id"; - phy0: ethernet-phy@0 { /* VSC8211 */ - reg = <0>; + mdio: mdio { + #address-cells = <1>; + #size-cells = <0>; + phy0: ethernet-phy@0 { /* VSC8211 */ + reg = <0>; + }; }; }; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm018-dc4.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm018-dc4.dts index 6636e76545a5d9..6ec1d9813973c4 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm018-dc4.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm018-dc4.dts @@ -116,17 +116,21 @@ status = "okay"; phy-mode = "rgmii-id"; phy-handle = <ðernet_phy0>; - ethernet_phy0: ethernet-phy@0 { /* Marvell 88e1512 */ - reg = <0>; - }; - ethernet_phy7: ethernet-phy@7 { /* Vitesse VSC8211 */ - reg = <7>; - }; - ethernet_phy3: ethernet-phy@3 { /* Realtek RTL8211DN */ - reg = <3>; - }; - ethernet_phy8: ethernet-phy@8 { /* Vitesse VSC8211 */ - reg = <8>; + mdio: mdio { + #address-cells = <1>; + #size-cells = <0>; + ethernet_phy0: ethernet-phy@0 { /* Marvell 88e1512 */ + reg = <0>; + }; + ethernet_phy7: ethernet-phy@7 { /* Vitesse VSC8211 */ + reg = <7>; + }; + ethernet_phy3: ethernet-phy@3 { /* Realtek RTL8211DN */ + reg = <3>; + }; + ethernet_phy8: ethernet-phy@8 { /* Vitesse VSC8211 */ + reg = <8>; + }; }; }; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm019-dc5.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm019-dc5.dts index 0d2ea9c09a0a01..b1857e17ab7e8b 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm019-dc5.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm019-dc5.dts @@ -77,8 +77,12 @@ phy-mode = "rgmii-id"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_gem1_default>; - phy0: ethernet-phy@0 { - reg = <0>; + mdio: mdio { + #address-cells = <1>; + #size-cells = <0>; + phy0: ethernet-phy@0 { + reg = <0>; + }; }; }; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu100-revC.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu100-revC.dts index d0091d3cb7643d..52f998c2253817 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu100-revC.dts +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu100-revC.dts @@ -123,13 +123,13 @@ io-channels = <&u35 0>, <&u35 1>, <&u35 2>, <&u35 3>; }; - si5335_0: si5335_0 { /* clk0_usb - u23 */ + si5335_0: si5335-0 { /* clk0_usb - u23 */ compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <26000000>; }; - si5335_1: si5335_1 { /* clk1_dp - u23 */ + si5335_1: si5335-1 { /* clk1_dp - u23 */ compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <27000000>; diff --git a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi index b61fc99cd911e8..eaba466804bc30 100644 --- a/arch/arm64/boot/dts/xilinx/zynqmp.dtsi +++ b/arch/arm64/boot/dts/xilinx/zynqmp.dtsi @@ -129,7 +129,7 @@ }; }; - zynqmp_ipi: zynqmp_ipi { + zynqmp_ipi: zynqmp-ipi { bootph-all; compatible = "xlnx,zynqmp-ipi-mailbox"; interrupt-parent = <&gic>; @@ -141,6 +141,7 @@ ipi_mailbox_pmu1: mailbox@ff9905c0 { bootph-all; + compatible = "xlnx,zynqmp-ipi-dest-mailbox"; reg = <0x0 0xff9905c0 0x0 0x20>, <0x0 0xff9905e0 0x0 0x20>, <0x0 0xff990e80 0x0 0x20>, @@ -194,12 +195,12 @@ mbox-names = "tx", "rx"; }; - nvmem_firmware { + nvmem-firmware { compatible = "xlnx,zynqmp-nvmem-fw"; #address-cells = <1>; #size-cells = <1>; - soc_revision: soc_revision@0 { + soc_revision: soc-revision@0 { reg = <0x0 0x4>; }; }; @@ -584,8 +585,6 @@ ; reg = <0x0 0xff0b0000 0x0 0x1000>; clock-names = "pclk", "hclk", "tx_clk", "rx_clk", "tsu_clk"; - #address-cells = <1>; - #size-cells = <0>; iommus = <&smmu 0x874>; power-domains = <&zynqmp_firmware PD_ETH_0>; resets = <&zynqmp_reset ZYNQMP_RESET_GEM0>; @@ -600,8 +599,6 @@ ; reg = <0x0 0xff0c0000 0x0 0x1000>; clock-names = "pclk", "hclk", "tx_clk", "rx_clk", "tsu_clk"; - #address-cells = <1>; - #size-cells = <0>; iommus = <&smmu 0x875>; power-domains = <&zynqmp_firmware PD_ETH_1>; resets = <&zynqmp_reset ZYNQMP_RESET_GEM1>; @@ -616,8 +613,6 @@ ; reg = <0x0 0xff0d0000 0x0 0x1000>; clock-names = "pclk", "hclk", "tx_clk", "rx_clk", "tsu_clk"; - #address-cells = <1>; - #size-cells = <0>; iommus = <&smmu 0x876>; power-domains = <&zynqmp_firmware PD_ETH_2>; resets = <&zynqmp_reset ZYNQMP_RESET_GEM2>; @@ -632,8 +627,6 @@ ; reg = <0x0 0xff0e0000 0x0 0x1000>; clock-names = "pclk", "hclk", "tx_clk", "rx_clk", "tsu_clk"; - #address-cells = <1>; - #size-cells = <0>; iommus = <&smmu 0x877>; power-domains = <&zynqmp_firmware PD_ETH_3>; resets = <&zynqmp_reset ZYNQMP_RESET_GEM3>; diff --git a/arch/arm64/boot/install.sh b/arch/arm64/boot/install.sh index 7399d706967a4f..9b7a09808a3dda 100755 --- a/arch/arm64/boot/install.sh +++ b/arch/arm64/boot/install.sh @@ -17,7 +17,8 @@ # $3 - kernel map file # $4 - default install path (blank if root directory) -if [ "$(basename $2)" = "Image.gz" ]; then +if [ "$(basename $2)" = "Image.gz" ] || [ "$(basename $2)" = "vmlinuz.efi" ] +then # Compressed install echo "Installing compressed kernel" base=vmlinuz diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index b60aa1f8934369..e6cf3e5d63c301 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -30,6 +30,9 @@ CONFIG_SCHED_AUTOGROUP=y CONFIG_BLK_DEV_INITRD=y CONFIG_KALLSYMS_ALL=y CONFIG_PROFILING=y +CONFIG_KEXEC=y +CONFIG_KEXEC_FILE=y +CONFIG_CRASH_DUMP=y CONFIG_ARCH_ACTIONS=y CONFIG_ARCH_SUNXI=y CONFIG_ARCH_ALPINE=y @@ -77,9 +80,6 @@ CONFIG_ARM64_VA_BITS_48=y CONFIG_SCHED_MC=y CONFIG_SCHED_SMT=y CONFIG_NUMA=y -CONFIG_KEXEC=y -CONFIG_KEXEC_FILE=y -CONFIG_CRASH_DUMP=y CONFIG_XEN=y CONFIG_COMPAT=y CONFIG_RANDOMIZE_BASE=y @@ -180,8 +180,6 @@ CONFIG_NET_ACT_GATE=m CONFIG_QRTR_SMD=m CONFIG_QRTR_TUN=m CONFIG_CAN=m -CONFIG_CAN_M_CAN=m -CONFIG_CAN_M_CAN_PLATFORM=m CONFIG_BT=m CONFIG_BT_HIDP=m # CONFIG_BT_LE is not set @@ -215,27 +213,27 @@ CONFIG_PCI_PASID=y CONFIG_HOTPLUG_PCI=y CONFIG_HOTPLUG_PCI_ACPI=y CONFIG_PCI_AARDVARK=y -CONFIG_PCI_TEGRA=y -CONFIG_PCIE_RCAR_HOST=y -CONFIG_PCIE_RCAR_EP=y -CONFIG_PCI_HOST_GENERIC=y -CONFIG_PCI_XGENE=y CONFIG_PCIE_ALTERA=y CONFIG_PCIE_ALTERA_MSI=y +CONFIG_PCIE_BRCMSTB=m CONFIG_PCI_HOST_THUNDER_PEM=y CONFIG_PCI_HOST_THUNDER_ECAM=y -CONFIG_PCIE_ROCKCHIP_HOST=m +CONFIG_PCI_HOST_GENERIC=y CONFIG_PCIE_MEDIATEK_GEN3=m -CONFIG_PCIE_BRCMSTB=m +CONFIG_PCI_TEGRA=y +CONFIG_PCIE_RCAR_HOST=y +CONFIG_PCIE_RCAR_EP=y +CONFIG_PCIE_ROCKCHIP_HOST=m +CONFIG_PCI_XGENE=y CONFIG_PCI_IMX6_HOST=y CONFIG_PCI_LAYERSCAPE=y CONFIG_PCI_HISI=y -CONFIG_PCIE_QCOM=y -CONFIG_PCIE_ARMADA_8K=y -CONFIG_PCIE_ROCKCHIP_DW_HOST=y CONFIG_PCIE_KIRIN=y CONFIG_PCIE_HISI_STB=y +CONFIG_PCIE_ARMADA_8K=y CONFIG_PCIE_TEGRA194_HOST=m +CONFIG_PCIE_QCOM=y +CONFIG_PCIE_ROCKCHIP_DW_HOST=y CONFIG_PCIE_VISCONTI_HOST=y CONFIG_PCIE_LAYERSCAPE_GEN4=y CONFIG_PCI_ENDPOINT=y @@ -252,9 +250,11 @@ CONFIG_ARM_SCPI_PROTOCOL=y CONFIG_RASPBERRYPI_FIRMWARE=y CONFIG_INTEL_STRATIX10_SERVICE=y CONFIG_INTEL_STRATIX10_RSU=m +CONFIG_MTK_ADSP_IPC=m CONFIG_EFI_CAPSULE_LOADER=y CONFIG_IMX_SCU=y -CONFIG_IMX_SCU_PD=y +CONFIG_QCOM_QSEECOM=y +CONFIG_QCOM_QSEECOM_UEFISECAPP=y CONFIG_GNSS=m CONFIG_GNSS_MTK_SERIAL=m CONFIG_MTD=y @@ -276,15 +276,12 @@ CONFIG_MTD_NAND_FSL_IFC=y CONFIG_MTD_NAND_QCOM=y CONFIG_MTD_SPI_NOR=y CONFIG_MTD_UBI=m -CONFIG_UBIFS_FS=m CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_NBD=m CONFIG_VIRTIO_BLK=y CONFIG_BLK_DEV_NVME=m CONFIG_QCOM_COINCELL=m CONFIG_QCOM_FASTRPC=m -CONFIG_BATTERY_QCOM_BATTMGR=m -CONFIG_UCSI_PMIC_GLINK=m CONFIG_SRAM=y CONFIG_PCI_ENDPOINT_TEST=m CONFIG_EEPROM_AT24=m @@ -368,6 +365,7 @@ CONFIG_SNI_NETSEC=y CONFIG_STMMAC_ETH=m CONFIG_DWMAC_TEGRA=m CONFIG_TI_K3_AM65_CPSW_NUSS=y +CONFIG_TI_ICSSG_PRUETH=m CONFIG_QCOM_IPA=m CONFIG_MESON_GXL_PHY=m CONFIG_AQUANTIA_PHY=y @@ -384,6 +382,8 @@ CONFIG_DP83869_PHY=m CONFIG_DP83TD510_PHY=y CONFIG_VITESSE_PHY=y CONFIG_CAN_FLEXCAN=m +CONFIG_CAN_M_CAN=m +CONFIG_CAN_M_CAN_PLATFORM=m CONFIG_CAN_RCAR=m CONFIG_CAN_RCAR_CANFD=m CONFIG_CAN_MCP251XFD=m @@ -448,6 +448,7 @@ CONFIG_SERIO_AMBAKMI=y CONFIG_LEGACY_PTY_COUNT=16 CONFIG_SERIAL_8250=y CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=8 CONFIG_SERIAL_8250_EXTENDED=y CONFIG_SERIAL_8250_SHARE_IRQ=y CONFIG_SERIAL_8250_BCM2835AUX=y @@ -574,9 +575,9 @@ CONFIG_PINCTRL_IMX8DXL=y CONFIG_PINCTRL_IMX8ULP=y CONFIG_PINCTRL_IMX93=y CONFIG_PINCTRL_MSM=y -CONFIG_PINCTRL_IPQ8074=y CONFIG_PINCTRL_IPQ5018=y CONFIG_PINCTRL_IPQ5332=y +CONFIG_PINCTRL_IPQ8074=y CONFIG_PINCTRL_IPQ6018=y CONFIG_PINCTRL_IPQ9574=y CONFIG_PINCTRL_MSM8916=y @@ -588,34 +589,37 @@ CONFIG_PINCTRL_MSM8998=y CONFIG_PINCTRL_QCM2290=y CONFIG_PINCTRL_QCS404=y CONFIG_PINCTRL_QDF2XXX=y -CONFIG_PINCTRL_QCOM_SPMI_PMIC=y CONFIG_PINCTRL_QDU1000=y CONFIG_PINCTRL_SA8775P=y CONFIG_PINCTRL_SC7180=y CONFIG_PINCTRL_SC7280=y -CONFIG_PINCTRL_SC7280_LPASS_LPI=m CONFIG_PINCTRL_SC8180X=y CONFIG_PINCTRL_SC8280XP=y CONFIG_PINCTRL_SDM660=y CONFIG_PINCTRL_SDM670=y CONFIG_PINCTRL_SDM845=y +CONFIG_PINCTRL_SDX75=y +CONFIG_PINCTRL_SM4450=y CONFIG_PINCTRL_SM6115=y -CONFIG_PINCTRL_SM6115_LPASS_LPI=m CONFIG_PINCTRL_SM6125=y CONFIG_PINCTRL_SM6350=y CONFIG_PINCTRL_SM6375=y CONFIG_PINCTRL_SM8150=y CONFIG_PINCTRL_SM8250=y -CONFIG_PINCTRL_SM8250_LPASS_LPI=m CONFIG_PINCTRL_SM8350=y -CONFIG_PINCTRL_SM8350_LPASS_LPI=m CONFIG_PINCTRL_SM8450=y +CONFIG_PINCTRL_SM8550=y +CONFIG_PINCTRL_SM8650=y +CONFIG_PINCTRL_X1E80100=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y +CONFIG_PINCTRL_LPASS_LPI=m +CONFIG_PINCTRL_SC7280_LPASS_LPI=m +CONFIG_PINCTRL_SM6115_LPASS_LPI=m +CONFIG_PINCTRL_SM8250_LPASS_LPI=m +CONFIG_PINCTRL_SM8350_LPASS_LPI=m CONFIG_PINCTRL_SM8450_LPASS_LPI=m CONFIG_PINCTRL_SC8280XP_LPASS_LPI=m -CONFIG_PINCTRL_SM8550=y CONFIG_PINCTRL_SM8550_LPASS_LPI=m -CONFIG_PINCTRL_LPASS_LPI=m -CONFIG_GPIO_AGGREGATOR=m CONFIG_GPIO_ALTERA=m CONFIG_GPIO_DAVINCI=y CONFIG_GPIO_DWAPB=y @@ -624,6 +628,7 @@ CONFIG_GPIO_MPC8XXX=y CONFIG_GPIO_MXC=y CONFIG_GPIO_PL061=y CONFIG_GPIO_RCAR=y +CONFIG_GPIO_SYSCON=y CONFIG_GPIO_UNIPHIER=y CONFIG_GPIO_VISCONTI=y CONFIG_GPIO_WCD934X=m @@ -635,7 +640,7 @@ CONFIG_GPIO_PCA953X_IRQ=y CONFIG_GPIO_BD9571MWV=m CONFIG_GPIO_MAX77620=y CONFIG_GPIO_SL28CPLD=m -CONFIG_GPIO_SYSCON=y +CONFIG_GPIO_AGGREGATOR=m CONFIG_POWER_RESET_MSM=y CONFIG_POWER_RESET_QCOM_PON=m CONFIG_POWER_RESET_XGENE=y @@ -643,6 +648,7 @@ CONFIG_POWER_RESET_SYSCON=y CONFIG_POWER_RESET_SYSCON_POWEROFF=y CONFIG_SYSCON_REBOOT_MODE=y CONFIG_NVMEM_REBOOT_MODE=m +CONFIG_BATTERY_QCOM_BATTMGR=m CONFIG_BATTERY_SBS=m CONFIG_BATTERY_BQ27XXX=y CONFIG_BATTERY_MAX17042=m @@ -667,14 +673,16 @@ CONFIG_DEVFREQ_THERMAL=y CONFIG_THERMAL_EMULATION=y CONFIG_IMX_SC_THERMAL=m CONFIG_IMX8MM_THERMAL=m -CONFIG_QORIQ_THERMAL=m CONFIG_K3_THERMAL=m +CONFIG_QORIQ_THERMAL=m CONFIG_SUN8I_THERMAL=y CONFIG_ROCKCHIP_THERMAL=m CONFIG_RCAR_THERMAL=y CONFIG_RCAR_GEN3_THERMAL=y CONFIG_RZG2L_THERMAL=y CONFIG_ARMADA_THERMAL=y +CONFIG_MTK_THERMAL=m +CONFIG_MTK_LVTS_THERMAL=m CONFIG_BCM2711_THERMAL=m CONFIG_BCM2835_THERMAL=m CONFIG_BRCMSTB_THERMAL=m @@ -694,6 +702,7 @@ CONFIG_ARM_SP805_WATCHDOG=y CONFIG_ARM_SBSA_WATCHDOG=y CONFIG_S3C2410_WATCHDOG=y CONFIG_DW_WATCHDOG=y +CONFIG_K3_RTI_WATCHDOG=m CONFIG_SUNXI_WATCHDOG=m CONFIG_NPCM7XX_WATCHDOG=y CONFIG_IMX2_WDT=y @@ -709,7 +718,6 @@ CONFIG_UNIPHIER_WATCHDOG=y CONFIG_PM8916_WATCHDOG=m CONFIG_BCM2835_WDT=y CONFIG_BCM7038_WDT=m -CONFIG_K3_RTI_WATCHDOG=m CONFIG_MFD_ALTERA_SYSMGR=y CONFIG_MFD_BD9571MWV=y CONFIG_MFD_AXP20X_I2C=y @@ -726,9 +734,9 @@ CONFIG_MFD_RK8XX_SPI=y CONFIG_MFD_SEC_CORE=y CONFIG_MFD_SL28CPLD=y CONFIG_RZ_MTU3=y +CONFIG_MFD_TI_AM335X_TSCADC=m CONFIG_MFD_TPS65219=y CONFIG_MFD_TPS6594_I2C=m -CONFIG_MFD_TI_AM335X_TSCADC=m CONFIG_MFD_ROHM_BD718XX=y CONFIG_MFD_WCD934X=m CONFIG_MFD_KHADAS_MCU=m @@ -737,6 +745,7 @@ CONFIG_REGULATOR_AXP20X=y CONFIG_REGULATOR_BD718XX=y CONFIG_REGULATOR_BD9571MWV=y CONFIG_REGULATOR_CROS_EC=y +CONFIG_REGULATOR_DA9211=m CONFIG_REGULATOR_FAN53555=y CONFIG_REGULATOR_GPIO=y CONFIG_REGULATOR_HI6421V530=y @@ -783,6 +792,7 @@ CONFIG_USB_VIDEO_CLASS=m CONFIG_V4L_PLATFORM_DRIVERS=y CONFIG_SDR_PLATFORM_DRIVERS=y CONFIG_V4L_MEM2MEM_DRIVERS=y +CONFIG_VIDEO_CADENCE_CSI2RX=m CONFIG_VIDEO_MEDIATEK_JPEG=m CONFIG_VIDEO_MEDIATEK_VCODEC=m CONFIG_VIDEO_IMX7_CSI=m @@ -804,6 +814,7 @@ CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC=m CONFIG_VIDEO_SAMSUNG_S5P_JPEG=m CONFIG_VIDEO_SAMSUNG_S5P_MFC=m CONFIG_VIDEO_SUN6I_CSI=m +CONFIG_VIDEO_TI_J721E_CSI2RX=m CONFIG_VIDEO_HANTRO=m CONFIG_VIDEO_IMX219=m CONFIG_VIDEO_IMX412=m @@ -860,6 +871,7 @@ CONFIG_DRM_SAMSUNG_DSIM=m CONFIG_DRM_SII902X=m CONFIG_DRM_SIMPLE_BRIDGE=m CONFIG_DRM_THINE_THC63LVD1024=m +CONFIG_DRM_TOSHIBA_TC358767=m CONFIG_DRM_TOSHIBA_TC358768=m CONFIG_DRM_TI_TFP410=m CONFIG_DRM_TI_SN65DSI83=m @@ -877,17 +889,19 @@ CONFIG_DRM_ETNAVIV=m CONFIG_DRM_HISI_HIBMC=m CONFIG_DRM_HISI_KIRIN=m CONFIG_DRM_MEDIATEK=m +CONFIG_DRM_MEDIATEK_DP=m CONFIG_DRM_MEDIATEK_HDMI=m CONFIG_DRM_MXSFB=m -CONFIG_DRM_MESON=m CONFIG_DRM_IMX_LCDIF=m +CONFIG_DRM_MESON=m CONFIG_DRM_PL111=m CONFIG_DRM_LIMA=m CONFIG_DRM_PANFROST=m CONFIG_DRM_TIDSS=m +CONFIG_DRM_POWERVR=m CONFIG_FB=y -CONFIG_FB_MODE_HELPERS=y CONFIG_FB_EFI=y +CONFIG_FB_MODE_HELPERS=y CONFIG_BACKLIGHT_PWM=m CONFIG_BACKLIGHT_LP855X=m CONFIG_LOGO=y @@ -913,6 +927,8 @@ CONFIG_SND_SOC_MT8183_MT6358_TS3A227E_MAX98357A=m CONFIG_SND_SOC_MT8183_DA7219_MAX98357A=m CONFIG_SND_SOC_MT8192=m CONFIG_SND_SOC_MT8192_MT6359_RT1015_RT5682=m +CONFIG_SND_SOC_MT8195=m +CONFIG_SND_SOC_MT8195_MT6359=m CONFIG_SND_MESON_AXG_SOUND_CARD=m CONFIG_SND_MESON_GX_SOUND_CARD=m CONFIG_SND_SOC_QCOM=m @@ -920,6 +936,7 @@ CONFIG_SND_SOC_APQ8016_SBC=m CONFIG_SND_SOC_MSM8996=m CONFIG_SND_SOC_SDM845=m CONFIG_SND_SOC_SM8250=m +CONFIG_SND_SOC_SC8280XP=m CONFIG_SND_SOC_SC7180=m CONFIG_SND_SOC_SC7280=m CONFIG_SND_SOC_ROCKCHIP=m @@ -930,6 +947,10 @@ CONFIG_SND_SOC_RK3399_GRU_SOUND=m CONFIG_SND_SOC_SAMSUNG=y CONFIG_SND_SOC_RCAR=m CONFIG_SND_SOC_RZ=m +CONFIG_SND_SOC_SOF_TOPLEVEL=y +CONFIG_SND_SOC_SOF_OF=y +CONFIG_SND_SOC_SOF_MTK_TOPLEVEL=y +CONFIG_SND_SOC_SOF_MT8195=m CONFIG_SND_SUN8I_CODEC=m CONFIG_SND_SUN8I_CODEC_ANALOG=m CONFIG_SND_SUN50I_CODEC_ANALOG=m @@ -950,6 +971,7 @@ CONFIG_SND_SOC_TEGRA210_ADX=m CONFIG_SND_SOC_TEGRA210_MIXER=m CONFIG_SND_SOC_TEGRA_AUDIO_GRAPH_CARD=m CONFIG_SND_SOC_DAVINCI_MCASP=m +CONFIG_SND_SOC_J721E_EVM=m CONFIG_SND_SOC_AK4613=m CONFIG_SND_SOC_DA7213=m CONFIG_SND_SOC_ES7134=m @@ -961,7 +983,6 @@ CONFIG_SND_SOC_MSM8916_WCD_DIGITAL=m CONFIG_SND_SOC_PCM3168A_I2C=m CONFIG_SND_SOC_RK817=m CONFIG_SND_SOC_RT5640=m -CONFIG_SND_SOC_J721E_EVM=m CONFIG_SND_SOC_RT5659=m CONFIG_SND_SOC_SIMPLE_AMPLIFIER=m CONFIG_SND_SOC_SIMPLE_MUX=m @@ -977,6 +998,8 @@ CONFIG_SND_SOC_WM8960=m CONFIG_SND_SOC_WM8962=m CONFIG_SND_SOC_WM8978=m CONFIG_SND_SOC_WSA881X=m +CONFIG_SND_SOC_WSA883X=m +CONFIG_SND_SOC_WSA884X=m CONFIG_SND_SOC_NAU8822=m CONFIG_SND_SOC_LPASS_WSA_MACRO=m CONFIG_SND_SOC_LPASS_VA_MACRO=m @@ -1047,14 +1070,15 @@ CONFIG_TYPEC=m CONFIG_TYPEC_TCPM=m CONFIG_TYPEC_TCPCI=m CONFIG_TYPEC_FUSB302=m -CONFIG_TYPEC_TPS6598X=m -CONFIG_TYPEC_HD3SS3220=m CONFIG_TYPEC_QCOM_PMIC=m CONFIG_TYPEC_UCSI=m -CONFIG_TYPEC_MUX_FSA4480=m -CONFIG_TYPEC_MUX_NB7VPQ904M=m CONFIG_UCSI_CCG=m +CONFIG_UCSI_PMIC_GLINK=m +CONFIG_TYPEC_TPS6598X=m +CONFIG_TYPEC_HD3SS3220=m +CONFIG_TYPEC_MUX_FSA4480=m CONFIG_TYPEC_MUX_GPIO_SBU=m +CONFIG_TYPEC_MUX_NB7VPQ904M=m CONFIG_TYPEC_DP_ALTMODE=m CONFIG_MMC=y CONFIG_MMC_BLOCK_MINORS=32 @@ -1183,6 +1207,7 @@ CONFIG_CROS_EC=y CONFIG_CROS_EC_I2C=y CONFIG_CROS_EC_RPMSG=m CONFIG_CROS_EC_SPI=y +CONFIG_CROS_KBD_LED_BACKLIGHT=m CONFIG_CROS_EC_CHARDEV=m CONFIG_COMMON_CLK_RK808=y CONFIG_COMMON_CLK_SCMI=y @@ -1192,6 +1217,7 @@ CONFIG_COMMON_CLK_FSL_SAI=y CONFIG_COMMON_CLK_S2MPS11=y CONFIG_COMMON_CLK_PWM=y CONFIG_COMMON_CLK_RS9_PCIE=y +CONFIG_COMMON_CLK_VC3=y CONFIG_COMMON_CLK_VC5=y CONFIG_COMMON_CLK_BD718XX=m CONFIG_CLK_RASPBERRYPI=m @@ -1216,30 +1242,32 @@ CONFIG_COMMON_CLK_MT8192_SCP_ADSP=y CONFIG_COMMON_CLK_MT8192_VDECSYS=y CONFIG_COMMON_CLK_MT8192_VENCSYS=y CONFIG_COMMON_CLK_QCOM=y +CONFIG_CLK_X1E80100_GCC=y CONFIG_QCOM_A53PLL=y CONFIG_QCOM_CLK_APCS_MSM8916=y CONFIG_QCOM_CLK_APCC_MSM8996=y CONFIG_QCOM_CLK_SMD_RPM=y CONFIG_QCOM_CLK_RPMH=y CONFIG_IPQ_APSS_6018=y -CONFIG_IPQ_GCC_5332=y CONFIG_IPQ_APSS_5018=y CONFIG_IPQ_GCC_5018=y +CONFIG_IPQ_GCC_5332=y CONFIG_IPQ_GCC_6018=y CONFIG_IPQ_GCC_8074=y CONFIG_IPQ_GCC_9574=y CONFIG_MSM_GCC_8916=y +CONFIG_MSM_MMCC_8994=m CONFIG_MSM_GCC_8994=y CONFIG_MSM_GCC_8996=y -CONFIG_MSM_MMCC_8994=m CONFIG_MSM_MMCC_8996=m -CONFIG_MSM_MMCC_8998=m CONFIG_MSM_GCC_8998=y +CONFIG_MSM_MMCC_8998=m CONFIG_QCM_GCC_2290=y CONFIG_QCM_DISPCC_2290=m CONFIG_QCS_GCC_404=y -CONFIG_SA_GCC_8775P=y +CONFIG_SC_CAMCC_8280XP=m CONFIG_SC_DISPCC_8280XP=m +CONFIG_SA_GCC_8775P=y CONFIG_SA_GPUCC_8775P=m CONFIG_SC_GCC_7180=y CONFIG_SC_GCC_7280=y @@ -1252,19 +1280,27 @@ CONFIG_SDM_GPUCC_845=y CONFIG_SDM_VIDEOCC_845=y CONFIG_SDM_DISPCC_845=y CONFIG_SDM_LPASSCC_845=m +CONFIG_SDX_GCC_75=y CONFIG_SM_CAMCC_8250=m CONFIG_SM_DISPCC_6115=m CONFIG_SM_DISPCC_8250=y CONFIG_SM_DISPCC_8450=m CONFIG_SM_DISPCC_8550=m +CONFIG_SM_DISPCC_8650=m +CONFIG_SM_GCC_4450=y CONFIG_SM_GCC_6115=y CONFIG_SM_GCC_8350=y CONFIG_SM_GCC_8450=y CONFIG_SM_GCC_8550=y -CONFIG_SM_TCSRCC_8550=y +CONFIG_SM_GCC_8650=y CONFIG_SM_GPUCC_6115=m CONFIG_SM_GPUCC_8150=y CONFIG_SM_GPUCC_8250=y +CONFIG_SM_GPUCC_8450=m +CONFIG_SM_GPUCC_8550=m +CONFIG_SM_GPUCC_8650=m +CONFIG_SM_TCSRCC_8550=y +CONFIG_SM_TCSRCC_8650=y CONFIG_SM_VIDEOCC_8250=y CONFIG_QCOM_HFPLL=y CONFIG_CLK_GFM_LPASS_SM8250=m @@ -1279,6 +1315,7 @@ CONFIG_OMAP2PLUS_MBOX=m CONFIG_PLATFORM_MHU=y CONFIG_BCM2835_MBOX=y CONFIG_QCOM_APCS_IPC=y +CONFIG_MTK_ADSP_MBOX=m CONFIG_QCOM_IPCC=y CONFIG_ROCKCHIP_IOMMU=y CONFIG_TEGRA_IOMMU_SMMU=y @@ -1288,14 +1325,14 @@ CONFIG_MTK_IOMMU=y CONFIG_QCOM_IOMMU=y CONFIG_REMOTEPROC=y CONFIG_IMX_REMOTEPROC=y -CONFIG_TI_K3_R5_REMOTEPROC=m -CONFIG_TI_K3_DSP_REMOTEPROC=m CONFIG_MTK_SCP=m CONFIG_QCOM_Q6V5_ADSP=m CONFIG_QCOM_Q6V5_MSS=m CONFIG_QCOM_Q6V5_PAS=m CONFIG_QCOM_SYSMON=m CONFIG_QCOM_WCNSS_PIL=m +CONFIG_TI_K3_DSP_REMOTEPROC=m +CONFIG_TI_K3_R5_REMOTEPROC=m CONFIG_RPMSG_CHAR=m CONFIG_RPMSG_CTRL=m CONFIG_RPMSG_QCOM_GLINK_RPM=y @@ -1304,8 +1341,6 @@ CONFIG_RPMSG_QCOM_SMD=y CONFIG_RPMSG_VIRTIO=y CONFIG_SOUNDWIRE=m CONFIG_SOUNDWIRE_QCOM=m -CONFIG_OWL_PM_DOMAINS=y -CONFIG_RASPBERRYPI_POWER=y CONFIG_FSL_DPAA=y CONFIG_FSL_MC_DPIO=y CONFIG_FSL_RCPM=y @@ -1315,15 +1350,12 @@ CONFIG_MTK_PMIC_WRAP=y CONFIG_MTK_SVS=m CONFIG_QCOM_AOSS_QMP=y CONFIG_QCOM_COMMAND_DB=y -CONFIG_QCOM_CPR=y CONFIG_QCOM_GENI_SE=y CONFIG_QCOM_LLCC=m CONFIG_QCOM_OCMEM=m CONFIG_QCOM_PMIC_GLINK=m CONFIG_QCOM_RMTFS_MEM=m CONFIG_QCOM_RPMH=y -CONFIG_QCOM_RPMHPD=y -CONFIG_QCOM_RPMPD=y CONFIG_QCOM_SMEM=y CONFIG_QCOM_SMD_RPM=y CONFIG_QCOM_SMP2P=y @@ -1355,14 +1387,20 @@ CONFIG_ARCH_R9A07G054=y CONFIG_ARCH_R9A08G045=y CONFIG_ARCH_R9A09G011=y CONFIG_ROCKCHIP_IODOMAIN=y -CONFIG_ROCKCHIP_PM_DOMAINS=y CONFIG_ARCH_TEGRA_132_SOC=y CONFIG_ARCH_TEGRA_210_SOC=y CONFIG_ARCH_TEGRA_186_SOC=y CONFIG_ARCH_TEGRA_194_SOC=y CONFIG_ARCH_TEGRA_234_SOC=y -CONFIG_TI_SCI_PM_DOMAINS=y CONFIG_TI_PRUSS=m +CONFIG_OWL_PM_DOMAINS=y +CONFIG_RASPBERRYPI_POWER=y +CONFIG_IMX_SCU_PD=y +CONFIG_QCOM_CPR=y +CONFIG_QCOM_RPMHPD=y +CONFIG_QCOM_RPMPD=y +CONFIG_ROCKCHIP_PM_DOMAINS=y +CONFIG_TI_SCI_PM_DOMAINS=y CONFIG_ARM_IMX_BUS_DEVFREQ=y CONFIG_ARM_IMX8M_DDRC_DEVFREQ=m CONFIG_ARM_MEDIATEK_CCI_DEVFREQ=m @@ -1421,6 +1459,7 @@ CONFIG_PHY_XGENE=y CONFIG_PHY_CAN_TRANSCEIVER=m CONFIG_PHY_SUN4I_USB=y CONFIG_PHY_CADENCE_TORRENT=m +CONFIG_PHY_CADENCE_DPHY_RX=m CONFIG_PHY_CADENCE_SIERRA=m CONFIG_PHY_MIXEL_MIPI_DPHY=m CONFIG_PHY_FSL_IMX8M_PCIE=y @@ -1430,17 +1469,17 @@ CONFIG_PHY_HISI_INNO_USB2=y CONFIG_PHY_MVEBU_CP110_COMPHY=y CONFIG_PHY_MTK_TPHY=y CONFIG_PHY_QCOM_EDP=m -CONFIG_PHY_QCOM_EUSB2_REPEATER=m CONFIG_PHY_QCOM_PCIE2=m CONFIG_PHY_QCOM_QMP=m CONFIG_PHY_QCOM_QUSB2=m CONFIG_PHY_QCOM_SNPS_EUSB2=m +CONFIG_PHY_QCOM_EUSB2_REPEATER=m +CONFIG_PHY_QCOM_M31_USB=m CONFIG_PHY_QCOM_USB_HS=m CONFIG_PHY_QCOM_USB_SNPS_FEMTO_V2=m CONFIG_PHY_QCOM_USB_HS_28NM=m CONFIG_PHY_QCOM_USB_SS=m CONFIG_PHY_QCOM_SGMII_ETH=m -CONFIG_PHY_QCOM_M31_USB=m CONFIG_PHY_R8A779F0_ETHERNET_SERDES=y CONFIG_PHY_RCAR_GEN3_PCIE=y CONFIG_PHY_RCAR_GEN3_USB2=y @@ -1462,7 +1501,6 @@ CONFIG_PHY_J721E_WIZ=m CONFIG_ARM_CCI_PMU=m CONFIG_ARM_CCN=m CONFIG_ARM_CMN=m -CONFIG_ARM_CORESIGHT_PMU_ARCH_SYSTEM_PMU=m CONFIG_ARM_SMMU_V3_PMU=m CONFIG_ARM_DSU_PMU=m CONFIG_FSL_IMX8_DDR_PMU=m @@ -1471,6 +1509,7 @@ CONFIG_QCOM_L3_PMU=y CONFIG_ARM_SPE_PMU=m CONFIG_ARM_DMC620_PMU=m CONFIG_HISI_PMU=y +CONFIG_ARM_CORESIGHT_PMU_ARCH_SYSTEM_PMU=m CONFIG_MESON_DDR_PMU=m CONFIG_NVMEM_LAYOUT_SL28_VPD=m CONFIG_NVMEM_IMX_OCOTP=y @@ -1519,11 +1558,14 @@ CONFIG_INTERCONNECT_QCOM_SC7280=y CONFIG_INTERCONNECT_QCOM_SC8180X=y CONFIG_INTERCONNECT_QCOM_SC8280XP=y CONFIG_INTERCONNECT_QCOM_SDM845=y +CONFIG_INTERCONNECT_QCOM_SDX75=y CONFIG_INTERCONNECT_QCOM_SM8150=m CONFIG_INTERCONNECT_QCOM_SM8250=m CONFIG_INTERCONNECT_QCOM_SM8350=m CONFIG_INTERCONNECT_QCOM_SM8450=y CONFIG_INTERCONNECT_QCOM_SM8550=y +CONFIG_INTERCONNECT_QCOM_SM8650=y +CONFIG_INTERCONNECT_QCOM_X1E80100=y CONFIG_COUNTER=m CONFIG_RZ_MTU3_CNT=m CONFIG_HTE=y @@ -1546,6 +1588,7 @@ CONFIG_TMPFS_POSIX_ACL=y CONFIG_HUGETLBFS=y CONFIG_CONFIGFS_FS=y CONFIG_EFIVAR_FS=y +CONFIG_UBIFS_FS=m CONFIG_SQUASHFS=y CONFIG_NFS_FS=y CONFIG_NFS_V4=y diff --git a/arch/arm64/crypto/Kconfig b/arch/arm64/crypto/Kconfig index 6d06b448a66e0c..eb7b423ba46350 100644 --- a/arch/arm64/crypto/Kconfig +++ b/arch/arm64/crypto/Kconfig @@ -231,7 +231,7 @@ config CRYPTO_SM4_ARM64_CE - NEON (Advanced SIMD) extensions config CRYPTO_SM4_ARM64_CE_BLK - tristate "Ciphers: SM4, modes: ECB/CBC/CFB/CTR/XTS (ARMv8 Crypto Extensions)" + tristate "Ciphers: SM4, modes: ECB/CBC/CTR/XTS (ARMv8 Crypto Extensions)" depends on KERNEL_MODE_NEON select CRYPTO_SKCIPHER select CRYPTO_SM4 @@ -240,7 +240,6 @@ config CRYPTO_SM4_ARM64_CE_BLK with block cipher modes: - ECB (Electronic Codebook) mode (NIST SP800-38A) - CBC (Cipher Block Chaining) mode (NIST SP800-38A) - - CFB (Cipher Feedback) mode (NIST SP800-38A) - CTR (Counter) mode (NIST SP800-38A) - XTS (XOR Encrypt XOR with ciphertext stealing) mode (NIST SP800-38E and IEEE 1619) @@ -250,7 +249,7 @@ config CRYPTO_SM4_ARM64_CE_BLK - NEON (Advanced SIMD) extensions config CRYPTO_SM4_ARM64_NEON_BLK - tristate "Ciphers: SM4, modes: ECB/CBC/CFB/CTR (NEON)" + tristate "Ciphers: SM4, modes: ECB/CBC/CTR (NEON)" depends on KERNEL_MODE_NEON select CRYPTO_SKCIPHER select CRYPTO_SM4 @@ -259,7 +258,6 @@ config CRYPTO_SM4_ARM64_NEON_BLK with block cipher modes: - ECB (Electronic Codebook) mode (NIST SP800-38A) - CBC (Cipher Block Chaining) mode (NIST SP800-38A) - - CFB (Cipher Feedback) mode (NIST SP800-38A) - CTR (Counter) mode (NIST SP800-38A) Architecture: arm64 using: diff --git a/arch/arm64/crypto/sm4-ce-core.S b/arch/arm64/crypto/sm4-ce-core.S index 877b80c54a0d3a..1f3625c2c67e4b 100644 --- a/arch/arm64/crypto/sm4-ce-core.S +++ b/arch/arm64/crypto/sm4-ce-core.S @@ -402,164 +402,6 @@ SYM_FUNC_START(sm4_ce_cbc_cts_dec) ret SYM_FUNC_END(sm4_ce_cbc_cts_dec) -.align 3 -SYM_FUNC_START(sm4_ce_cfb_enc) - /* input: - * x0: round key array, CTX - * x1: dst - * x2: src - * x3: iv (big endian, 128 bit) - * w4: nblocks - */ - SM4_PREPARE(x0) - - ld1 {RIV.16b}, [x3] - -.Lcfb_enc_loop_4x: - cmp w4, #4 - blt .Lcfb_enc_loop_1x - - sub w4, w4, #4 - - ld1 {v0.16b-v3.16b}, [x2], #64 - - rev32 v8.16b, RIV.16b - SM4_CRYPT_BLK_BE(v8) - eor v0.16b, v0.16b, v8.16b - - rev32 v8.16b, v0.16b - SM4_CRYPT_BLK_BE(v8) - eor v1.16b, v1.16b, v8.16b - - rev32 v8.16b, v1.16b - SM4_CRYPT_BLK_BE(v8) - eor v2.16b, v2.16b, v8.16b - - rev32 v8.16b, v2.16b - SM4_CRYPT_BLK_BE(v8) - eor v3.16b, v3.16b, v8.16b - - st1 {v0.16b-v3.16b}, [x1], #64 - mov RIV.16b, v3.16b - - cbz w4, .Lcfb_enc_end - b .Lcfb_enc_loop_4x - -.Lcfb_enc_loop_1x: - sub w4, w4, #1 - - ld1 {v0.16b}, [x2], #16 - - SM4_CRYPT_BLK(RIV) - eor RIV.16b, RIV.16b, v0.16b - - st1 {RIV.16b}, [x1], #16 - - cbnz w4, .Lcfb_enc_loop_1x - -.Lcfb_enc_end: - /* store new IV */ - st1 {RIV.16b}, [x3] - - ret -SYM_FUNC_END(sm4_ce_cfb_enc) - -.align 3 -SYM_FUNC_START(sm4_ce_cfb_dec) - /* input: - * x0: round key array, CTX - * x1: dst - * x2: src - * x3: iv (big endian, 128 bit) - * w4: nblocks - */ - SM4_PREPARE(x0) - - ld1 {RIV.16b}, [x3] - -.Lcfb_dec_loop_8x: - sub w4, w4, #8 - tbnz w4, #31, .Lcfb_dec_4x - - ld1 {v0.16b-v3.16b}, [x2], #64 - ld1 {v4.16b-v7.16b}, [x2], #64 - - rev32 v8.16b, RIV.16b - rev32 v9.16b, v0.16b - rev32 v10.16b, v1.16b - rev32 v11.16b, v2.16b - rev32 v12.16b, v3.16b - rev32 v13.16b, v4.16b - rev32 v14.16b, v5.16b - rev32 v15.16b, v6.16b - - SM4_CRYPT_BLK8_BE(v8, v9, v10, v11, v12, v13, v14, v15) - - mov RIV.16b, v7.16b - - eor v0.16b, v0.16b, v8.16b - eor v1.16b, v1.16b, v9.16b - eor v2.16b, v2.16b, v10.16b - eor v3.16b, v3.16b, v11.16b - eor v4.16b, v4.16b, v12.16b - eor v5.16b, v5.16b, v13.16b - eor v6.16b, v6.16b, v14.16b - eor v7.16b, v7.16b, v15.16b - - st1 {v0.16b-v3.16b}, [x1], #64 - st1 {v4.16b-v7.16b}, [x1], #64 - - cbz w4, .Lcfb_dec_end - b .Lcfb_dec_loop_8x - -.Lcfb_dec_4x: - add w4, w4, #8 - cmp w4, #4 - blt .Lcfb_dec_loop_1x - - sub w4, w4, #4 - - ld1 {v0.16b-v3.16b}, [x2], #64 - - rev32 v8.16b, RIV.16b - rev32 v9.16b, v0.16b - rev32 v10.16b, v1.16b - rev32 v11.16b, v2.16b - - SM4_CRYPT_BLK4_BE(v8, v9, v10, v11) - - mov RIV.16b, v3.16b - - eor v0.16b, v0.16b, v8.16b - eor v1.16b, v1.16b, v9.16b - eor v2.16b, v2.16b, v10.16b - eor v3.16b, v3.16b, v11.16b - - st1 {v0.16b-v3.16b}, [x1], #64 - - cbz w4, .Lcfb_dec_end - -.Lcfb_dec_loop_1x: - sub w4, w4, #1 - - ld1 {v0.16b}, [x2], #16 - - SM4_CRYPT_BLK(RIV) - - eor RIV.16b, RIV.16b, v0.16b - st1 {RIV.16b}, [x1], #16 - - mov RIV.16b, v0.16b - - cbnz w4, .Lcfb_dec_loop_1x - -.Lcfb_dec_end: - /* store new IV */ - st1 {RIV.16b}, [x3] - - ret -SYM_FUNC_END(sm4_ce_cfb_dec) - .align 3 SYM_FUNC_START(sm4_ce_ctr_enc) /* input: diff --git a/arch/arm64/crypto/sm4-ce-glue.c b/arch/arm64/crypto/sm4-ce-glue.c index 0a2d32ed3bdec4..43741bed874e27 100644 --- a/arch/arm64/crypto/sm4-ce-glue.c +++ b/arch/arm64/crypto/sm4-ce-glue.c @@ -37,10 +37,6 @@ asmlinkage void sm4_ce_cbc_cts_enc(const u32 *rkey, u8 *dst, const u8 *src, u8 *iv, unsigned int nbytes); asmlinkage void sm4_ce_cbc_cts_dec(const u32 *rkey, u8 *dst, const u8 *src, u8 *iv, unsigned int nbytes); -asmlinkage void sm4_ce_cfb_enc(const u32 *rkey, u8 *dst, const u8 *src, - u8 *iv, unsigned int nblks); -asmlinkage void sm4_ce_cfb_dec(const u32 *rkey, u8 *dst, const u8 *src, - u8 *iv, unsigned int nblks); asmlinkage void sm4_ce_ctr_enc(const u32 *rkey, u8 *dst, const u8 *src, u8 *iv, unsigned int nblks); asmlinkage void sm4_ce_xts_enc(const u32 *rkey1, u8 *dst, const u8 *src, @@ -56,7 +52,6 @@ asmlinkage void sm4_ce_mac_update(const u32 *rkey_enc, u8 *digest, EXPORT_SYMBOL(sm4_ce_expand_key); EXPORT_SYMBOL(sm4_ce_crypt_block); EXPORT_SYMBOL(sm4_ce_cbc_enc); -EXPORT_SYMBOL(sm4_ce_cfb_enc); struct sm4_xts_ctx { struct sm4_ctx key1; @@ -280,90 +275,6 @@ static int sm4_cbc_cts_decrypt(struct skcipher_request *req) return sm4_cbc_cts_crypt(req, false); } -static int sm4_cfb_encrypt(struct skcipher_request *req) -{ - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); - struct sm4_ctx *ctx = crypto_skcipher_ctx(tfm); - struct skcipher_walk walk; - unsigned int nbytes; - int err; - - err = skcipher_walk_virt(&walk, req, false); - - while ((nbytes = walk.nbytes) > 0) { - const u8 *src = walk.src.virt.addr; - u8 *dst = walk.dst.virt.addr; - unsigned int nblks; - - kernel_neon_begin(); - - nblks = BYTES2BLKS(nbytes); - if (nblks) { - sm4_ce_cfb_enc(ctx->rkey_enc, dst, src, walk.iv, nblks); - dst += nblks * SM4_BLOCK_SIZE; - src += nblks * SM4_BLOCK_SIZE; - nbytes -= nblks * SM4_BLOCK_SIZE; - } - - /* tail */ - if (walk.nbytes == walk.total && nbytes > 0) { - u8 keystream[SM4_BLOCK_SIZE]; - - sm4_ce_crypt_block(ctx->rkey_enc, keystream, walk.iv); - crypto_xor_cpy(dst, src, keystream, nbytes); - nbytes = 0; - } - - kernel_neon_end(); - - err = skcipher_walk_done(&walk, nbytes); - } - - return err; -} - -static int sm4_cfb_decrypt(struct skcipher_request *req) -{ - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); - struct sm4_ctx *ctx = crypto_skcipher_ctx(tfm); - struct skcipher_walk walk; - unsigned int nbytes; - int err; - - err = skcipher_walk_virt(&walk, req, false); - - while ((nbytes = walk.nbytes) > 0) { - const u8 *src = walk.src.virt.addr; - u8 *dst = walk.dst.virt.addr; - unsigned int nblks; - - kernel_neon_begin(); - - nblks = BYTES2BLKS(nbytes); - if (nblks) { - sm4_ce_cfb_dec(ctx->rkey_enc, dst, src, walk.iv, nblks); - dst += nblks * SM4_BLOCK_SIZE; - src += nblks * SM4_BLOCK_SIZE; - nbytes -= nblks * SM4_BLOCK_SIZE; - } - - /* tail */ - if (walk.nbytes == walk.total && nbytes > 0) { - u8 keystream[SM4_BLOCK_SIZE]; - - sm4_ce_crypt_block(ctx->rkey_enc, keystream, walk.iv); - crypto_xor_cpy(dst, src, keystream, nbytes); - nbytes = 0; - } - - kernel_neon_end(); - - err = skcipher_walk_done(&walk, nbytes); - } - - return err; -} - static int sm4_ctr_crypt(struct skcipher_request *req) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); @@ -542,22 +453,6 @@ static struct skcipher_alg sm4_algs[] = { .setkey = sm4_setkey, .encrypt = sm4_cbc_encrypt, .decrypt = sm4_cbc_decrypt, - }, { - .base = { - .cra_name = "cfb(sm4)", - .cra_driver_name = "cfb-sm4-ce", - .cra_priority = 400, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct sm4_ctx), - .cra_module = THIS_MODULE, - }, - .min_keysize = SM4_KEY_SIZE, - .max_keysize = SM4_KEY_SIZE, - .ivsize = SM4_BLOCK_SIZE, - .chunksize = SM4_BLOCK_SIZE, - .setkey = sm4_setkey, - .encrypt = sm4_cfb_encrypt, - .decrypt = sm4_cfb_decrypt, }, { .base = { .cra_name = "ctr(sm4)", @@ -869,12 +764,11 @@ static void __exit sm4_exit(void) module_cpu_feature_match(SM4, sm4_init); module_exit(sm4_exit); -MODULE_DESCRIPTION("SM4 ECB/CBC/CFB/CTR/XTS using ARMv8 Crypto Extensions"); +MODULE_DESCRIPTION("SM4 ECB/CBC/CTR/XTS using ARMv8 Crypto Extensions"); MODULE_ALIAS_CRYPTO("sm4-ce"); MODULE_ALIAS_CRYPTO("sm4"); MODULE_ALIAS_CRYPTO("ecb(sm4)"); MODULE_ALIAS_CRYPTO("cbc(sm4)"); -MODULE_ALIAS_CRYPTO("cfb(sm4)"); MODULE_ALIAS_CRYPTO("ctr(sm4)"); MODULE_ALIAS_CRYPTO("cts(cbc(sm4))"); MODULE_ALIAS_CRYPTO("xts(sm4)"); diff --git a/arch/arm64/crypto/sm4-ce.h b/arch/arm64/crypto/sm4-ce.h index 109c21b37590d3..1e235c4371eb0b 100644 --- a/arch/arm64/crypto/sm4-ce.h +++ b/arch/arm64/crypto/sm4-ce.h @@ -11,6 +11,3 @@ void sm4_ce_crypt_block(const u32 *rkey, u8 *dst, const u8 *src); void sm4_ce_cbc_enc(const u32 *rkey_enc, u8 *dst, const u8 *src, u8 *iv, unsigned int nblocks); - -void sm4_ce_cfb_enc(const u32 *rkey_enc, u8 *dst, const u8 *src, - u8 *iv, unsigned int nblocks); diff --git a/arch/arm64/crypto/sm4-neon-core.S b/arch/arm64/crypto/sm4-neon-core.S index f295b4b7d70a3e..734dc7193610c2 100644 --- a/arch/arm64/crypto/sm4-neon-core.S +++ b/arch/arm64/crypto/sm4-neon-core.S @@ -437,119 +437,6 @@ SYM_FUNC_START(sm4_neon_cbc_dec) ret SYM_FUNC_END(sm4_neon_cbc_dec) -.align 3 -SYM_FUNC_START(sm4_neon_cfb_dec) - /* input: - * x0: round key array, CTX - * x1: dst - * x2: src - * x3: iv (big endian, 128 bit) - * w4: nblocks - */ - SM4_PREPARE() - - ld1 {v0.16b}, [x3] - -.Lcfb_dec_loop_8x: - sub w4, w4, #8 - tbnz w4, #31, .Lcfb_dec_4x - - ld1 {v1.16b-v3.16b}, [x2], #48 - ld4 {v4.4s-v7.4s}, [x2] - - transpose_4x4(v0, v1, v2, v3) - - SM4_CRYPT_BLK8(v0, v1, v2, v3, v4, v5, v6, v7) - - sub x2, x2, #48 - ld1 {RTMP0.16b-RTMP3.16b}, [x2], #64 - ld1 {RTMP4.16b-RTMP7.16b}, [x2], #64 - - eor v0.16b, v0.16b, RTMP0.16b - eor v1.16b, v1.16b, RTMP1.16b - eor v2.16b, v2.16b, RTMP2.16b - eor v3.16b, v3.16b, RTMP3.16b - eor v4.16b, v4.16b, RTMP4.16b - eor v5.16b, v5.16b, RTMP5.16b - eor v6.16b, v6.16b, RTMP6.16b - eor v7.16b, v7.16b, RTMP7.16b - - st1 {v0.16b-v3.16b}, [x1], #64 - st1 {v4.16b-v7.16b}, [x1], #64 - - mov v0.16b, RTMP7.16b - - cbz w4, .Lcfb_dec_end - b .Lcfb_dec_loop_8x - -.Lcfb_dec_4x: - add w4, w4, #8 - cmp w4, #4 - blt .Lcfb_dec_tail - - sub w4, w4, #4 - - ld1 {v4.16b-v7.16b}, [x2], #64 - - rev32 v0.16b, v0.16b /* v0 is IV register */ - rev32 v1.16b, v4.16b - rev32 v2.16b, v5.16b - rev32 v3.16b, v6.16b - - transpose_4x4(v0, v1, v2, v3) - - SM4_CRYPT_BLK4_BE(v0, v1, v2, v3) - - eor v0.16b, v0.16b, v4.16b - eor v1.16b, v1.16b, v5.16b - eor v2.16b, v2.16b, v6.16b - eor v3.16b, v3.16b, v7.16b - - st1 {v0.16b-v3.16b}, [x1], #64 - - mov v0.16b, v7.16b - - cbz w4, .Lcfb_dec_end - -.Lcfb_dec_tail: - cmp w4, #2 - ld1 {v4.16b}, [x2], #16 - blt .Lcfb_dec_tail_load_done - ld1 {v5.16b}, [x2], #16 - beq .Lcfb_dec_tail_load_done - ld1 {v6.16b}, [x2], #16 - -.Lcfb_dec_tail_load_done: - rev32 v0.16b, v0.16b /* v0 is IV register */ - rev32 v1.16b, v4.16b - rev32 v2.16b, v5.16b - - transpose_4x4(v0, v1, v2, v3) - - SM4_CRYPT_BLK4_BE(v0, v1, v2, v3) - - cmp w4, #2 - eor v0.16b, v0.16b, v4.16b - st1 {v0.16b}, [x1], #16 - mov v0.16b, v4.16b - blt .Lcfb_dec_end - - eor v1.16b, v1.16b, v5.16b - st1 {v1.16b}, [x1], #16 - mov v0.16b, v5.16b - beq .Lcfb_dec_end - - eor v2.16b, v2.16b, v6.16b - st1 {v2.16b}, [x1], #16 - mov v0.16b, v6.16b - -.Lcfb_dec_end: - /* store new IV */ - st1 {v0.16b}, [x3] - - ret -SYM_FUNC_END(sm4_neon_cfb_dec) - .align 3 SYM_FUNC_START(sm4_neon_ctr_crypt) /* input: diff --git a/arch/arm64/crypto/sm4-neon-glue.c b/arch/arm64/crypto/sm4-neon-glue.c index 7b19accf5c0374..e3500aca2d18bd 100644 --- a/arch/arm64/crypto/sm4-neon-glue.c +++ b/arch/arm64/crypto/sm4-neon-glue.c @@ -22,8 +22,6 @@ asmlinkage void sm4_neon_crypt(const u32 *rkey, u8 *dst, const u8 *src, unsigned int nblocks); asmlinkage void sm4_neon_cbc_dec(const u32 *rkey_dec, u8 *dst, const u8 *src, u8 *iv, unsigned int nblocks); -asmlinkage void sm4_neon_cfb_dec(const u32 *rkey_enc, u8 *dst, const u8 *src, - u8 *iv, unsigned int nblocks); asmlinkage void sm4_neon_ctr_crypt(const u32 *rkey_enc, u8 *dst, const u8 *src, u8 *iv, unsigned int nblocks); @@ -142,90 +140,6 @@ static int sm4_cbc_decrypt(struct skcipher_request *req) return err; } -static int sm4_cfb_encrypt(struct skcipher_request *req) -{ - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); - struct sm4_ctx *ctx = crypto_skcipher_ctx(tfm); - struct skcipher_walk walk; - unsigned int nbytes; - int err; - - err = skcipher_walk_virt(&walk, req, false); - - while ((nbytes = walk.nbytes) > 0) { - u8 keystream[SM4_BLOCK_SIZE]; - const u8 *iv = walk.iv; - const u8 *src = walk.src.virt.addr; - u8 *dst = walk.dst.virt.addr; - - while (nbytes >= SM4_BLOCK_SIZE) { - sm4_crypt_block(ctx->rkey_enc, keystream, iv); - crypto_xor_cpy(dst, src, keystream, SM4_BLOCK_SIZE); - iv = dst; - src += SM4_BLOCK_SIZE; - dst += SM4_BLOCK_SIZE; - nbytes -= SM4_BLOCK_SIZE; - } - if (iv != walk.iv) - memcpy(walk.iv, iv, SM4_BLOCK_SIZE); - - /* tail */ - if (walk.nbytes == walk.total && nbytes > 0) { - sm4_crypt_block(ctx->rkey_enc, keystream, walk.iv); - crypto_xor_cpy(dst, src, keystream, nbytes); - nbytes = 0; - } - - err = skcipher_walk_done(&walk, nbytes); - } - - return err; -} - -static int sm4_cfb_decrypt(struct skcipher_request *req) -{ - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); - struct sm4_ctx *ctx = crypto_skcipher_ctx(tfm); - struct skcipher_walk walk; - unsigned int nbytes; - int err; - - err = skcipher_walk_virt(&walk, req, false); - - while ((nbytes = walk.nbytes) > 0) { - const u8 *src = walk.src.virt.addr; - u8 *dst = walk.dst.virt.addr; - unsigned int nblocks; - - nblocks = nbytes / SM4_BLOCK_SIZE; - if (nblocks) { - kernel_neon_begin(); - - sm4_neon_cfb_dec(ctx->rkey_enc, dst, src, - walk.iv, nblocks); - - kernel_neon_end(); - - dst += nblocks * SM4_BLOCK_SIZE; - src += nblocks * SM4_BLOCK_SIZE; - nbytes -= nblocks * SM4_BLOCK_SIZE; - } - - /* tail */ - if (walk.nbytes == walk.total && nbytes > 0) { - u8 keystream[SM4_BLOCK_SIZE]; - - sm4_crypt_block(ctx->rkey_enc, keystream, walk.iv); - crypto_xor_cpy(dst, src, keystream, nbytes); - nbytes = 0; - } - - err = skcipher_walk_done(&walk, nbytes); - } - - return err; -} - static int sm4_ctr_crypt(struct skcipher_request *req) { struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); @@ -301,22 +215,6 @@ static struct skcipher_alg sm4_algs[] = { .setkey = sm4_setkey, .encrypt = sm4_cbc_encrypt, .decrypt = sm4_cbc_decrypt, - }, { - .base = { - .cra_name = "cfb(sm4)", - .cra_driver_name = "cfb-sm4-neon", - .cra_priority = 200, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct sm4_ctx), - .cra_module = THIS_MODULE, - }, - .min_keysize = SM4_KEY_SIZE, - .max_keysize = SM4_KEY_SIZE, - .ivsize = SM4_BLOCK_SIZE, - .chunksize = SM4_BLOCK_SIZE, - .setkey = sm4_setkey, - .encrypt = sm4_cfb_encrypt, - .decrypt = sm4_cfb_decrypt, }, { .base = { .cra_name = "ctr(sm4)", @@ -349,12 +247,11 @@ static void __exit sm4_exit(void) module_init(sm4_init); module_exit(sm4_exit); -MODULE_DESCRIPTION("SM4 ECB/CBC/CFB/CTR using ARMv8 NEON"); +MODULE_DESCRIPTION("SM4 ECB/CBC/CTR using ARMv8 NEON"); MODULE_ALIAS_CRYPTO("sm4-neon"); MODULE_ALIAS_CRYPTO("sm4"); MODULE_ALIAS_CRYPTO("ecb(sm4)"); MODULE_ALIAS_CRYPTO("cbc(sm4)"); -MODULE_ALIAS_CRYPTO("cfb(sm4)"); MODULE_ALIAS_CRYPTO("ctr(sm4)"); MODULE_AUTHOR("Tianjia Zhang "); MODULE_LICENSE("GPL v2"); diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h index 376a980f2bad08..513787e4332993 100644 --- a/arch/arm64/include/asm/assembler.h +++ b/arch/arm64/include/asm/assembler.h @@ -12,7 +12,7 @@ #ifndef __ASM_ASSEMBLER_H #define __ASM_ASSEMBLER_H -#include +#include #include #include @@ -760,32 +760,25 @@ alternative_endif .endm /* - * Check whether preempt/bh-disabled asm code should yield as soon as - * it is able. This is the case if we are currently running in task - * context, and either a softirq is pending, or the TIF_NEED_RESCHED - * flag is set and re-enabling preemption a single time would result in - * a preempt count of zero. (Note that the TIF_NEED_RESCHED flag is - * stored negated in the top word of the thread_info::preempt_count + * Check whether asm code should yield as soon as it is able. This is + * the case if we are currently running in task context, and the + * TIF_NEED_RESCHED flag is set. (Note that the TIF_NEED_RESCHED flag + * is stored negated in the top word of the thread_info::preempt_count * field) */ - .macro cond_yield, lbl:req, tmp:req, tmp2:req + .macro cond_yield, lbl:req, tmp:req, tmp2 +#ifdef CONFIG_PREEMPT_VOLUNTARY get_current_task \tmp ldr \tmp, [\tmp, #TSK_TI_PREEMPT] /* * If we are serving a softirq, there is no point in yielding: the * softirq will not be preempted no matter what we do, so we should - * run to completion as quickly as we can. + * run to completion as quickly as we can. The preempt_count field will + * have BIT(SOFTIRQ_SHIFT) set in this case, so the zero check will + * catch this case too. */ - tbnz \tmp, #SOFTIRQ_SHIFT, .Lnoyield_\@ -#ifdef CONFIG_PREEMPTION - sub \tmp, \tmp, #PREEMPT_DISABLE_OFFSET cbz \tmp, \lbl #endif - adr_l \tmp, irq_stat + IRQ_CPUSTAT_SOFTIRQ_PENDING - get_this_cpu_offset \tmp2 - ldr w\tmp, [\tmp, \tmp2] - cbnz w\tmp, \lbl // yield on pending softirq in task context -.Lnoyield_\@: .endm /* diff --git a/arch/arm64/include/asm/cache.h b/arch/arm64/include/asm/cache.h index ceb368d33bf4ea..06a4670bdb0b9b 100644 --- a/arch/arm64/include/asm/cache.h +++ b/arch/arm64/include/asm/cache.h @@ -58,7 +58,6 @@ static inline unsigned int arch_slab_minalign(void) #define CTR_L1IP(ctr) SYS_FIELD_GET(CTR_EL0, L1Ip, ctr) #define ICACHEF_ALIASING 0 -#define ICACHEF_VPIPT 1 extern unsigned long __icache_flags; /* @@ -70,11 +69,6 @@ static inline int icache_is_aliasing(void) return test_bit(ICACHEF_ALIASING, &__icache_flags); } -static __always_inline int icache_is_vpipt(void) -{ - return test_bit(ICACHEF_VPIPT, &__icache_flags); -} - static inline u32 cache_type_cwg(void) { return SYS_FIELD_GET(CTR_EL0, CWG, read_cpuid_cachetype()); diff --git a/arch/arm64/include/asm/cpu.h b/arch/arm64/include/asm/cpu.h index f3034099fd952b..b1e43f56ee461e 100644 --- a/arch/arm64/include/asm/cpu.h +++ b/arch/arm64/include/asm/cpu.h @@ -38,7 +38,6 @@ struct cpuinfo_32bit { }; struct cpuinfo_arm64 { - struct cpu cpu; struct kobject kobj; u64 reg_ctr; u64 reg_cntfrq; diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index f6d416fe49b097..21c824edf8ce4a 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -617,6 +617,7 @@ static inline bool id_aa64pfr1_mte(u64 pfr1) return val >= ID_AA64PFR1_EL1_MTE_MTE2; } +void __init setup_boot_cpu_features(void); void __init setup_system_features(void); void __init setup_user_features(void); @@ -819,6 +820,11 @@ static inline bool system_supports_tlb_range(void) return alternative_has_cap_unlikely(ARM64_HAS_TLB_RANGE); } +static inline bool system_supports_lpa2(void) +{ + return cpus_have_final_cap(ARM64_HAS_LPA2); +} + int do_emulate_mrs(struct pt_regs *regs, u32 sys_reg, u32 rt); bool try_emulate_mrs(struct pt_regs *regs, u32 isn); diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h index ae35939f395bb1..353fe08546cf90 100644 --- a/arch/arm64/include/asm/esr.h +++ b/arch/arm64/include/asm/esr.h @@ -392,6 +392,21 @@ static inline bool esr_is_data_abort(unsigned long esr) return ec == ESR_ELx_EC_DABT_LOW || ec == ESR_ELx_EC_DABT_CUR; } +static inline bool esr_fsc_is_translation_fault(unsigned long esr) +{ + return (esr & ESR_ELx_FSC_TYPE) == ESR_ELx_FSC_FAULT; +} + +static inline bool esr_fsc_is_permission_fault(unsigned long esr) +{ + return (esr & ESR_ELx_FSC_TYPE) == ESR_ELx_FSC_PERM; +} + +static inline bool esr_fsc_is_access_flag_fault(unsigned long esr) +{ + return (esr & ESR_ELx_FSC_TYPE) == ESR_ELx_FSC_ACCESS; +} + const char *esr_get_class_string(unsigned long esr); #endif /* __ASSEMBLY */ diff --git a/arch/arm64/include/asm/fpsimdmacros.h b/arch/arm64/include/asm/fpsimdmacros.h index cdf6a35e399440..cda81d009c9bd7 100644 --- a/arch/arm64/include/asm/fpsimdmacros.h +++ b/arch/arm64/include/asm/fpsimdmacros.h @@ -242,14 +242,6 @@ | (\nx << 5) .endm -/* - * Zero the entire ZA array - * ZERO ZA - */ -.macro zero_za - .inst 0xc00800ff -.endm - .macro __for from:req, to:req .if (\from) == (\to) _for__body %\from diff --git a/arch/arm64/include/asm/irq.h b/arch/arm64/include/asm/irq.h index 50ce8b697ff361..e93548914c366f 100644 --- a/arch/arm64/include/asm/irq.h +++ b/arch/arm64/include/asm/irq.h @@ -4,6 +4,8 @@ #ifndef __ASSEMBLER__ +#include + #include void arch_trigger_cpumask_backtrace(const cpumask_t *mask, int exclude_cpu); diff --git a/arch/arm64/include/asm/irq_work.h b/arch/arm64/include/asm/irq_work.h index 81bbfa3a035bd2..a1020285ea7504 100644 --- a/arch/arm64/include/asm/irq_work.h +++ b/arch/arm64/include/asm/irq_work.h @@ -2,8 +2,6 @@ #ifndef __ASM_IRQ_WORK_H #define __ASM_IRQ_WORK_H -extern void arch_irq_work_raise(void); - static inline bool arch_irq_work_has_interrupt(void) { return true; diff --git a/arch/arm64/include/asm/kasan.h b/arch/arm64/include/asm/kasan.h index 12d5f47f7dbec6..7eefc525a9dfb8 100644 --- a/arch/arm64/include/asm/kasan.h +++ b/arch/arm64/include/asm/kasan.h @@ -15,29 +15,9 @@ #if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS) +asmlinkage void kasan_early_init(void); void kasan_init(void); - -/* - * KASAN_SHADOW_START: beginning of the kernel virtual addresses. - * KASAN_SHADOW_END: KASAN_SHADOW_START + 1/N of kernel virtual addresses, - * where N = (1 << KASAN_SHADOW_SCALE_SHIFT). - * - * KASAN_SHADOW_OFFSET: - * This value is used to map an address to the corresponding shadow - * address by the following formula: - * shadow_addr = (address >> KASAN_SHADOW_SCALE_SHIFT) + KASAN_SHADOW_OFFSET - * - * (1 << (64 - KASAN_SHADOW_SCALE_SHIFT)) shadow addresses that lie in range - * [KASAN_SHADOW_OFFSET, KASAN_SHADOW_END) cover all 64-bits of virtual - * addresses. So KASAN_SHADOW_OFFSET should satisfy the following equation: - * KASAN_SHADOW_OFFSET = KASAN_SHADOW_END - - * (1ULL << (64 - KASAN_SHADOW_SCALE_SHIFT)) - */ -#define _KASAN_SHADOW_START(va) (KASAN_SHADOW_END - (1UL << ((va) - KASAN_SHADOW_SCALE_SHIFT))) -#define KASAN_SHADOW_START _KASAN_SHADOW_START(vabits_actual) - void kasan_copy_shadow(pgd_t *pgdir); -asmlinkage void kasan_early_init(void); #else static inline void kasan_init(void) { } diff --git a/arch/arm64/include/asm/kernel-pgtable.h b/arch/arm64/include/asm/kernel-pgtable.h index 85d26143faa598..83ddb14b95a5e3 100644 --- a/arch/arm64/include/asm/kernel-pgtable.h +++ b/arch/arm64/include/asm/kernel-pgtable.h @@ -37,27 +37,12 @@ /* - * If KASLR is enabled, then an offset K is added to the kernel address - * space. The bottom 21 bits of this offset are zero to guarantee 2MB - * alignment for PA and VA. - * - * For each pagetable level of the swapper, we know that the shift will - * be larger than 21 (for the 4KB granule case we use section maps thus - * the smallest shift is actually 30) thus there is the possibility that - * KASLR can increase the number of pagetable entries by 1, so we make - * room for this extra entry. - * - * Note KASLR cannot increase the number of required entries for a level - * by more than one because it increments both the virtual start and end - * addresses equally (the extra entry comes from the case where the end - * address is just pushed over a boundary and the start address isn't). + * A relocatable kernel may execute from an address that differs from the one at + * which it was linked. In the worst case, its runtime placement may intersect + * with two adjacent PGDIR entries, which means that an additional page table + * may be needed at each subordinate level. */ - -#ifdef CONFIG_RANDOMIZE_BASE -#define EARLY_KASLR (1) -#else -#define EARLY_KASLR (0) -#endif +#define EXTRA_PAGE __is_defined(CONFIG_RELOCATABLE) #define SPAN_NR_ENTRIES(vstart, vend, shift) \ ((((vend) - 1) >> (shift)) - ((vstart) >> (shift)) + 1) @@ -83,7 +68,7 @@ + EARLY_PGDS((vstart), (vend), add) /* each PGDIR needs a next level page table */ \ + EARLY_PUDS((vstart), (vend), add) /* each PUD needs a next level page table */ \ + EARLY_PMDS((vstart), (vend), add)) /* each PMD needs a next level page table */ -#define INIT_DIR_SIZE (PAGE_SIZE * EARLY_PAGES(KIMAGE_VADDR, _end, EARLY_KASLR)) +#define INIT_DIR_SIZE (PAGE_SIZE * EARLY_PAGES(KIMAGE_VADDR, _end, EXTRA_PAGE)) /* the initial ID map may need two extra pages if it needs to be extended */ #if VA_BITS < 48 diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h index b85f46a73e21bb..3c6f8ba1e47927 100644 --- a/arch/arm64/include/asm/kvm_arm.h +++ b/arch/arm64/include/asm/kvm_arm.h @@ -108,6 +108,7 @@ #define HCRX_HOST_FLAGS (HCRX_EL2_MSCEn | HCRX_EL2_TCR2En) /* TCR_EL2 Registers bits */ +#define TCR_EL2_DS (1UL << 32) #define TCR_EL2_RES1 ((1U << 31) | (1 << 23)) #define TCR_EL2_TBI (1 << 20) #define TCR_EL2_PS_SHIFT 16 @@ -122,6 +123,7 @@ TCR_EL2_ORGN0_MASK | TCR_EL2_IRGN0_MASK | TCR_EL2_T0SZ_MASK) /* VTCR_EL2 Registers bits */ +#define VTCR_EL2_DS TCR_EL2_DS #define VTCR_EL2_RES1 (1U << 31) #define VTCR_EL2_HD (1 << 22) #define VTCR_EL2_HA (1 << 21) @@ -344,36 +346,47 @@ * Once we get to a point where the two describe the same thing, we'll * merge the definitions. One day. */ -#define __HFGRTR_EL2_RES0 (GENMASK(63, 56) | GENMASK(53, 51)) +#define __HFGRTR_EL2_RES0 HFGxTR_EL2_RES0 #define __HFGRTR_EL2_MASK GENMASK(49, 0) -#define __HFGRTR_EL2_nMASK (GENMASK(58, 57) | GENMASK(55, 54) | BIT(50)) +#define __HFGRTR_EL2_nMASK ~(__HFGRTR_EL2_RES0 | __HFGRTR_EL2_MASK) -#define __HFGWTR_EL2_RES0 (GENMASK(63, 56) | GENMASK(53, 51) | \ - BIT(46) | BIT(42) | BIT(40) | BIT(28) | \ - GENMASK(26, 25) | BIT(21) | BIT(18) | \ +/* + * The HFGWTR bits are a subset of HFGRTR bits. To ensure we don't miss any + * future additions, define __HFGWTR* macros relative to __HFGRTR* ones. + */ +#define __HFGRTR_ONLY_MASK (BIT(46) | BIT(42) | BIT(40) | BIT(28) | \ + GENMASK(26, 25) | BIT(21) | BIT(18) | \ GENMASK(15, 14) | GENMASK(10, 9) | BIT(2)) -#define __HFGWTR_EL2_MASK GENMASK(49, 0) -#define __HFGWTR_EL2_nMASK (GENMASK(58, 57) | GENMASK(55, 54) | BIT(50)) - -#define __HFGITR_EL2_RES0 GENMASK(63, 57) -#define __HFGITR_EL2_MASK GENMASK(54, 0) -#define __HFGITR_EL2_nMASK GENMASK(56, 55) - -#define __HDFGRTR_EL2_RES0 (BIT(49) | BIT(42) | GENMASK(39, 38) | \ - GENMASK(21, 20) | BIT(8)) -#define __HDFGRTR_EL2_MASK ~__HDFGRTR_EL2_nMASK -#define __HDFGRTR_EL2_nMASK GENMASK(62, 59) - -#define __HDFGWTR_EL2_RES0 (BIT(63) | GENMASK(59, 58) | BIT(51) | BIT(47) | \ - BIT(43) | GENMASK(40, 38) | BIT(34) | BIT(30) | \ - BIT(22) | BIT(9) | BIT(6)) -#define __HDFGWTR_EL2_MASK ~__HDFGWTR_EL2_nMASK -#define __HDFGWTR_EL2_nMASK GENMASK(62, 60) +#define __HFGWTR_EL2_RES0 (__HFGRTR_EL2_RES0 | __HFGRTR_ONLY_MASK) +#define __HFGWTR_EL2_MASK (__HFGRTR_EL2_MASK & ~__HFGRTR_ONLY_MASK) +#define __HFGWTR_EL2_nMASK ~(__HFGWTR_EL2_RES0 | __HFGWTR_EL2_MASK) + +#define __HFGITR_EL2_RES0 HFGITR_EL2_RES0 +#define __HFGITR_EL2_MASK (BIT(62) | BIT(60) | GENMASK(54, 0)) +#define __HFGITR_EL2_nMASK ~(__HFGITR_EL2_RES0 | __HFGITR_EL2_MASK) + +#define __HDFGRTR_EL2_RES0 HDFGRTR_EL2_RES0 +#define __HDFGRTR_EL2_MASK (BIT(63) | GENMASK(58, 50) | GENMASK(48, 43) | \ + GENMASK(41, 40) | GENMASK(37, 22) | \ + GENMASK(19, 9) | GENMASK(7, 0)) +#define __HDFGRTR_EL2_nMASK ~(__HDFGRTR_EL2_RES0 | __HDFGRTR_EL2_MASK) + +#define __HDFGWTR_EL2_RES0 HDFGWTR_EL2_RES0 +#define __HDFGWTR_EL2_MASK (GENMASK(57, 52) | GENMASK(50, 48) | \ + GENMASK(46, 44) | GENMASK(42, 41) | \ + GENMASK(37, 35) | GENMASK(33, 31) | \ + GENMASK(29, 23) | GENMASK(21, 10) | \ + GENMASK(8, 7) | GENMASK(5, 0)) +#define __HDFGWTR_EL2_nMASK ~(__HDFGWTR_EL2_RES0 | __HDFGWTR_EL2_MASK) + +#define __HAFGRTR_EL2_RES0 HAFGRTR_EL2_RES0 +#define __HAFGRTR_EL2_MASK (GENMASK(49, 17) | GENMASK(4, 0)) +#define __HAFGRTR_EL2_nMASK ~(__HAFGRTR_EL2_RES0 | __HAFGRTR_EL2_MASK) /* Similar definitions for HCRX_EL2 */ -#define __HCRX_EL2_RES0 (GENMASK(63, 16) | GENMASK(13, 12)) -#define __HCRX_EL2_MASK (0) -#define __HCRX_EL2_nMASK (GENMASK(15, 14) | GENMASK(4, 0)) +#define __HCRX_EL2_RES0 HCRX_EL2_RES0 +#define __HCRX_EL2_MASK (BIT(6)) +#define __HCRX_EL2_nMASK ~(__HCRX_EL2_RES0 | __HCRX_EL2_MASK) /* Hyp Prefetch Fault Address Register (HPFAR/HDFAR) */ #define HPFAR_MASK (~UL(0xf)) diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h index 78a550537b673f..b804fe83218446 100644 --- a/arch/arm64/include/asm/kvm_emulate.h +++ b/arch/arm64/include/asm/kvm_emulate.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -54,11 +55,6 @@ void kvm_emulate_nested_eret(struct kvm_vcpu *vcpu); int kvm_inject_nested_sync(struct kvm_vcpu *vcpu, u64 esr_el2); int kvm_inject_nested_irq(struct kvm_vcpu *vcpu); -static inline bool vcpu_has_feature(const struct kvm_vcpu *vcpu, int feature) -{ - return test_bit(feature, vcpu->kvm->arch.vcpu_features); -} - #if defined(__KVM_VHE_HYPERVISOR__) || defined(__KVM_NVHE_HYPERVISOR__) static __always_inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu) { @@ -248,7 +244,7 @@ static inline bool __is_hyp_ctxt(const struct kvm_cpu_context *ctxt) static inline bool is_hyp_ctxt(const struct kvm_vcpu *vcpu) { - return __is_hyp_ctxt(&vcpu->arch.ctxt); + return vcpu_has_nv(vcpu) && __is_hyp_ctxt(&vcpu->arch.ctxt); } /* @@ -404,14 +400,25 @@ static __always_inline u8 kvm_vcpu_trap_get_fault(const struct kvm_vcpu *vcpu) return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC; } -static __always_inline u8 kvm_vcpu_trap_get_fault_type(const struct kvm_vcpu *vcpu) +static inline +bool kvm_vcpu_trap_is_permission_fault(const struct kvm_vcpu *vcpu) { - return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC_TYPE; + return esr_fsc_is_permission_fault(kvm_vcpu_get_esr(vcpu)); } -static __always_inline u8 kvm_vcpu_trap_get_fault_level(const struct kvm_vcpu *vcpu) +static inline +bool kvm_vcpu_trap_is_translation_fault(const struct kvm_vcpu *vcpu) { - return kvm_vcpu_get_esr(vcpu) & ESR_ELx_FSC_LEVEL; + return esr_fsc_is_translation_fault(kvm_vcpu_get_esr(vcpu)); +} + +static inline +u64 kvm_vcpu_trap_get_perm_fault_granule(const struct kvm_vcpu *vcpu) +{ + unsigned long esr = kvm_vcpu_get_esr(vcpu); + + BUG_ON(!esr_fsc_is_permission_fault(esr)); + return BIT(ARM64_HW_PGTABLE_LEVEL_SHIFT(esr & ESR_ELx_FSC_LEVEL)); } static __always_inline bool kvm_vcpu_abt_issea(const struct kvm_vcpu *vcpu) @@ -454,12 +461,7 @@ static inline bool kvm_is_write_fault(struct kvm_vcpu *vcpu) * first), then a permission fault to allow the flags * to be set. */ - switch (kvm_vcpu_trap_get_fault_type(vcpu)) { - case ESR_ELx_FSC_PERM: - return true; - default: - return false; - } + return kvm_vcpu_trap_is_permission_fault(vcpu); } if (kvm_vcpu_trap_is_iabt(vcpu)) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 824f29f04916af..21c57b812569f2 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -27,6 +27,7 @@ #include #include #include +#include #define __KVM_HAVE_ARCH_INTC_INITIALIZED @@ -306,6 +307,7 @@ struct kvm_arch { * Atomic access to multiple idregs are guarded by kvm_arch.config_lock. */ #define IDREG_IDX(id) (((sys_reg_CRm(id) - 1) << 3) | sys_reg_Op2(id)) +#define IDX_IDREG(idx) sys_reg(3, 0, 0, ((idx) >> 3) + 1, (idx) & Op2_mask) #define IDREG(kvm, id) ((kvm)->arch.id_regs[IDREG_IDX(id)]) #define KVM_ARM_ID_REG_NUM (IDREG_IDX(sys_reg(3, 0, 0, 7, 7)) + 1) u64 id_regs[KVM_ARM_ID_REG_NUM]; @@ -324,33 +326,33 @@ struct kvm_vcpu_fault_info { u64 disr_el1; /* Deferred [SError] Status Register */ }; +/* + * VNCR() just places the VNCR_capable registers in the enum after + * __VNCR_START__, and the value (after correction) to be an 8-byte offset + * from the VNCR base. As we don't require the enum to be otherwise ordered, + * we need the terrible hack below to ensure that we correctly size the + * sys_regs array, no matter what. + * + * The __MAX__ macro has been lifted from Sean Eron Anderson's wonderful + * treasure trove of bit hacks: + * https://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax + */ +#define __MAX__(x,y) ((x) ^ (((x) ^ (y)) & -((x) < (y)))) +#define VNCR(r) \ + __before_##r, \ + r = __VNCR_START__ + ((VNCR_ ## r) / 8), \ + __after_##r = __MAX__(__before_##r - 1, r) + enum vcpu_sysreg { __INVALID_SYSREG__, /* 0 is reserved as an invalid value */ MPIDR_EL1, /* MultiProcessor Affinity Register */ CLIDR_EL1, /* Cache Level ID Register */ CSSELR_EL1, /* Cache Size Selection Register */ - SCTLR_EL1, /* System Control Register */ - ACTLR_EL1, /* Auxiliary Control Register */ - CPACR_EL1, /* Coprocessor Access Control */ - ZCR_EL1, /* SVE Control */ - TTBR0_EL1, /* Translation Table Base Register 0 */ - TTBR1_EL1, /* Translation Table Base Register 1 */ - TCR_EL1, /* Translation Control Register */ - TCR2_EL1, /* Extended Translation Control Register */ - ESR_EL1, /* Exception Syndrome Register */ - AFSR0_EL1, /* Auxiliary Fault Status Register 0 */ - AFSR1_EL1, /* Auxiliary Fault Status Register 1 */ - FAR_EL1, /* Fault Address Register */ - MAIR_EL1, /* Memory Attribute Indirection Register */ - VBAR_EL1, /* Vector Base Address Register */ - CONTEXTIDR_EL1, /* Context ID Register */ TPIDR_EL0, /* Thread ID, User R/W */ TPIDRRO_EL0, /* Thread ID, User R/O */ TPIDR_EL1, /* Thread ID, Privileged */ - AMAIR_EL1, /* Aux Memory Attribute Indirection Register */ CNTKCTL_EL1, /* Timer Control Register (EL1) */ PAR_EL1, /* Physical Address Register */ - MDSCR_EL1, /* Monitor Debug System Control Register */ MDCCINT_EL1, /* Monitor Debug Comms Channel Interrupt Enable Reg */ OSLSR_EL1, /* OS Lock Status Register */ DISR_EL1, /* Deferred Interrupt Status Register */ @@ -381,26 +383,11 @@ enum vcpu_sysreg { APGAKEYLO_EL1, APGAKEYHI_EL1, - ELR_EL1, - SP_EL1, - SPSR_EL1, - - CNTVOFF_EL2, - CNTV_CVAL_EL0, - CNTV_CTL_EL0, - CNTP_CVAL_EL0, - CNTP_CTL_EL0, - /* Memory Tagging Extension registers */ RGSR_EL1, /* Random Allocation Tag Seed Register */ GCR_EL1, /* Tag Control Register */ - TFSR_EL1, /* Tag Fault Status Register (EL1) */ TFSRE0_EL1, /* Tag Fault Status Register (EL0) */ - /* Permission Indirection Extension registers */ - PIR_EL1, /* Permission Indirection Register 1 (EL1) */ - PIRE0_EL1, /* Permission Indirection Register 0 (EL1) */ - /* 32bit specific registers. */ DACR32_EL2, /* Domain Access Control Register */ IFSR32_EL2, /* Instruction Fault Status Register */ @@ -408,21 +395,14 @@ enum vcpu_sysreg { DBGVCR32_EL2, /* Debug Vector Catch Register */ /* EL2 registers */ - VPIDR_EL2, /* Virtualization Processor ID Register */ - VMPIDR_EL2, /* Virtualization Multiprocessor ID Register */ SCTLR_EL2, /* System Control Register (EL2) */ ACTLR_EL2, /* Auxiliary Control Register (EL2) */ - HCR_EL2, /* Hypervisor Configuration Register */ MDCR_EL2, /* Monitor Debug Configuration Register (EL2) */ CPTR_EL2, /* Architectural Feature Trap Register (EL2) */ - HSTR_EL2, /* Hypervisor System Trap Register */ HACR_EL2, /* Hypervisor Auxiliary Control Register */ - HCRX_EL2, /* Extended Hypervisor Configuration Register */ TTBR0_EL2, /* Translation Table Base Register 0 (EL2) */ TTBR1_EL2, /* Translation Table Base Register 1 (EL2) */ TCR_EL2, /* Translation Control Register (EL2) */ - VTTBR_EL2, /* Virtualization Translation Table Base Register */ - VTCR_EL2, /* Virtualization Translation Control Register */ SPSR_EL2, /* EL2 saved program status register */ ELR_EL2, /* EL2 exception link register */ AFSR0_EL2, /* Auxiliary Fault Status Register 0 (EL2) */ @@ -435,19 +415,62 @@ enum vcpu_sysreg { VBAR_EL2, /* Vector Base Address Register (EL2) */ RVBAR_EL2, /* Reset Vector Base Address Register */ CONTEXTIDR_EL2, /* Context ID Register (EL2) */ - TPIDR_EL2, /* EL2 Software Thread ID Register */ CNTHCTL_EL2, /* Counter-timer Hypervisor Control register */ SP_EL2, /* EL2 Stack Pointer */ - HFGRTR_EL2, - HFGWTR_EL2, - HFGITR_EL2, - HDFGRTR_EL2, - HDFGWTR_EL2, CNTHP_CTL_EL2, CNTHP_CVAL_EL2, CNTHV_CTL_EL2, CNTHV_CVAL_EL2, + __VNCR_START__, /* Any VNCR-capable reg goes after this point */ + + VNCR(SCTLR_EL1),/* System Control Register */ + VNCR(ACTLR_EL1),/* Auxiliary Control Register */ + VNCR(CPACR_EL1),/* Coprocessor Access Control */ + VNCR(ZCR_EL1), /* SVE Control */ + VNCR(TTBR0_EL1),/* Translation Table Base Register 0 */ + VNCR(TTBR1_EL1),/* Translation Table Base Register 1 */ + VNCR(TCR_EL1), /* Translation Control Register */ + VNCR(TCR2_EL1), /* Extended Translation Control Register */ + VNCR(ESR_EL1), /* Exception Syndrome Register */ + VNCR(AFSR0_EL1),/* Auxiliary Fault Status Register 0 */ + VNCR(AFSR1_EL1),/* Auxiliary Fault Status Register 1 */ + VNCR(FAR_EL1), /* Fault Address Register */ + VNCR(MAIR_EL1), /* Memory Attribute Indirection Register */ + VNCR(VBAR_EL1), /* Vector Base Address Register */ + VNCR(CONTEXTIDR_EL1), /* Context ID Register */ + VNCR(AMAIR_EL1),/* Aux Memory Attribute Indirection Register */ + VNCR(MDSCR_EL1),/* Monitor Debug System Control Register */ + VNCR(ELR_EL1), + VNCR(SP_EL1), + VNCR(SPSR_EL1), + VNCR(TFSR_EL1), /* Tag Fault Status Register (EL1) */ + VNCR(VPIDR_EL2),/* Virtualization Processor ID Register */ + VNCR(VMPIDR_EL2),/* Virtualization Multiprocessor ID Register */ + VNCR(HCR_EL2), /* Hypervisor Configuration Register */ + VNCR(HSTR_EL2), /* Hypervisor System Trap Register */ + VNCR(VTTBR_EL2),/* Virtualization Translation Table Base Register */ + VNCR(VTCR_EL2), /* Virtualization Translation Control Register */ + VNCR(TPIDR_EL2),/* EL2 Software Thread ID Register */ + VNCR(HCRX_EL2), /* Extended Hypervisor Configuration Register */ + + /* Permission Indirection Extension registers */ + VNCR(PIR_EL1), /* Permission Indirection Register 1 (EL1) */ + VNCR(PIRE0_EL1), /* Permission Indirection Register 0 (EL1) */ + + VNCR(HFGRTR_EL2), + VNCR(HFGWTR_EL2), + VNCR(HFGITR_EL2), + VNCR(HDFGRTR_EL2), + VNCR(HDFGWTR_EL2), + VNCR(HAFGRTR_EL2), + + VNCR(CNTVOFF_EL2), + VNCR(CNTV_CVAL_EL0), + VNCR(CNTV_CTL_EL0), + VNCR(CNTP_CVAL_EL0), + VNCR(CNTP_CTL_EL0), + NR_SYS_REGS /* Nothing after this line! */ }; @@ -464,6 +487,9 @@ struct kvm_cpu_context { u64 sys_regs[NR_SYS_REGS]; struct kvm_vcpu *__hyp_running_vcpu; + + /* This pointer has to be 4kB aligned. */ + u64 *vncr_array; }; struct kvm_host_data { @@ -826,8 +852,19 @@ struct kvm_vcpu_arch { * accessed by a running VCPU. For example, for userspace access or * for system registers that are never context switched, but only * emulated. + * + * Don't bother with VNCR-based accesses in the nVHE code, it has no + * business dealing with NV. */ -#define __ctxt_sys_reg(c,r) (&(c)->sys_regs[(r)]) +static inline u64 *__ctxt_sys_reg(const struct kvm_cpu_context *ctxt, int r) +{ +#if !defined (__KVM_NVHE_HYPERVISOR__) + if (unlikely(cpus_have_final_cap(ARM64_HAS_NESTED_VIRT) && + r >= __VNCR_START__ && ctxt->vncr_array)) + return &ctxt->vncr_array[r - __VNCR_START__]; +#endif + return (u64 *)&ctxt->sys_regs[r]; +} #define ctxt_sys_reg(c,r) (*__ctxt_sys_reg(c,r)) @@ -871,6 +908,7 @@ static inline bool __vcpu_read_sys_reg_from_cpu(int reg, u64 *val) case AMAIR_EL1: *val = read_sysreg_s(SYS_AMAIR_EL12); break; case CNTKCTL_EL1: *val = read_sysreg_s(SYS_CNTKCTL_EL12); break; case ELR_EL1: *val = read_sysreg_s(SYS_ELR_EL12); break; + case SPSR_EL1: *val = read_sysreg_s(SYS_SPSR_EL12); break; case PAR_EL1: *val = read_sysreg_par(); break; case DACR32_EL2: *val = read_sysreg_s(SYS_DACR32_EL2); break; case IFSR32_EL2: *val = read_sysreg_s(SYS_IFSR32_EL2); break; @@ -915,6 +953,7 @@ static inline bool __vcpu_write_sys_reg_to_cpu(u64 val, int reg) case AMAIR_EL1: write_sysreg_s(val, SYS_AMAIR_EL12); break; case CNTKCTL_EL1: write_sysreg_s(val, SYS_CNTKCTL_EL12); break; case ELR_EL1: write_sysreg_s(val, SYS_ELR_EL12); break; + case SPSR_EL1: write_sysreg_s(val, SYS_SPSR_EL12); break; case PAR_EL1: write_sysreg_s(val, SYS_PAR_EL1); break; case DACR32_EL2: write_sysreg_s(val, SYS_DACR32_EL2); break; case IFSR32_EL2: write_sysreg_s(val, SYS_IFSR32_EL2); break; @@ -954,8 +993,6 @@ int __kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu, int __kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu, struct kvm_vcpu_events *events); -#define KVM_ARCH_WANT_MMU_NOTIFIER - void kvm_arm_halt_guest(struct kvm *kvm); void kvm_arm_resume_guest(struct kvm *kvm); @@ -1177,6 +1214,13 @@ bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu); #define kvm_vm_has_ran_once(kvm) \ (test_bit(KVM_ARCH_FLAG_HAS_RAN_ONCE, &(kvm)->arch.flags)) +static inline bool __vcpu_has_feature(const struct kvm_arch *ka, int feature) +{ + return test_bit(feature, ka->vcpu_features); +} + +#define vcpu_has_feature(v, f) __vcpu_has_feature(&(v)->kvm->arch, (f)) + int kvm_trng_call(struct kvm_vcpu *vcpu); #ifdef CONFIG_KVM extern phys_addr_t hyp_mem_base; diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h index 49e0d4b36bd009..e3e793d0ec3041 100644 --- a/arch/arm64/include/asm/kvm_mmu.h +++ b/arch/arm64/include/asm/kvm_mmu.h @@ -243,13 +243,6 @@ static inline size_t __invalidate_icache_max_range(void) static inline void __invalidate_icache_guest_page(void *va, size_t size) { - /* - * VPIPT I-cache maintenance must be done from EL2. See comment in the - * nVHE flavor of __kvm_tlb_flush_vmid_ipa(). - */ - if (icache_is_vpipt() && read_sysreg(CurrentEL) != CurrentEL_EL2) - return; - /* * Blow the whole I-cache if it is aliasing (i.e. VIPT) or the * invalidation range exceeds our arbitrary limit on invadations by diff --git a/arch/arm64/include/asm/kvm_nested.h b/arch/arm64/include/asm/kvm_nested.h index 6cec8e9c6c9126..4882905357f43b 100644 --- a/arch/arm64/include/asm/kvm_nested.h +++ b/arch/arm64/include/asm/kvm_nested.h @@ -2,8 +2,9 @@ #ifndef __ARM64_KVM_NESTED_H #define __ARM64_KVM_NESTED_H -#include +#include #include +#include static inline bool vcpu_has_nv(const struct kvm_vcpu *vcpu) { @@ -12,12 +13,55 @@ static inline bool vcpu_has_nv(const struct kvm_vcpu *vcpu) vcpu_has_feature(vcpu, KVM_ARM_VCPU_HAS_EL2)); } -extern bool __check_nv_sr_forward(struct kvm_vcpu *vcpu); +/* Translation helpers from non-VHE EL2 to EL1 */ +static inline u64 tcr_el2_ps_to_tcr_el1_ips(u64 tcr_el2) +{ + return (u64)FIELD_GET(TCR_EL2_PS_MASK, tcr_el2) << TCR_IPS_SHIFT; +} + +static inline u64 translate_tcr_el2_to_tcr_el1(u64 tcr) +{ + return TCR_EPD1_MASK | /* disable TTBR1_EL1 */ + ((tcr & TCR_EL2_TBI) ? TCR_TBI0 : 0) | + tcr_el2_ps_to_tcr_el1_ips(tcr) | + (tcr & TCR_EL2_TG0_MASK) | + (tcr & TCR_EL2_ORGN0_MASK) | + (tcr & TCR_EL2_IRGN0_MASK) | + (tcr & TCR_EL2_T0SZ_MASK); +} + +static inline u64 translate_cptr_el2_to_cpacr_el1(u64 cptr_el2) +{ + u64 cpacr_el1 = 0; + + if (cptr_el2 & CPTR_EL2_TTA) + cpacr_el1 |= CPACR_ELx_TTA; + if (!(cptr_el2 & CPTR_EL2_TFP)) + cpacr_el1 |= CPACR_ELx_FPEN; + if (!(cptr_el2 & CPTR_EL2_TZ)) + cpacr_el1 |= CPACR_ELx_ZEN; -struct sys_reg_params; -struct sys_reg_desc; + return cpacr_el1; +} + +static inline u64 translate_sctlr_el2_to_sctlr_el1(u64 val) +{ + /* Only preserve the minimal set of bits we support */ + val &= (SCTLR_ELx_M | SCTLR_ELx_A | SCTLR_ELx_C | SCTLR_ELx_SA | + SCTLR_ELx_I | SCTLR_ELx_IESB | SCTLR_ELx_WXN | SCTLR_ELx_EE); + val |= SCTLR_EL1_RES1; + + return val; +} + +static inline u64 translate_ttbr0_el2_to_ttbr0_el1(u64 ttbr0) +{ + /* Clear the ASID field */ + return ttbr0 & ~GENMASK_ULL(63, 48); +} + +extern bool __check_nv_sr_forward(struct kvm_vcpu *vcpu); -void access_nested_id_reg(struct kvm_vcpu *v, struct sys_reg_params *p, - const struct sys_reg_desc *r); +int kvm_init_nv_sysregs(struct kvm *kvm); #endif /* __ARM64_KVM_NESTED_H */ diff --git a/arch/arm64/include/asm/kvm_pgtable.h b/arch/arm64/include/asm/kvm_pgtable.h index d3e354bb8351d7..cfdf40f734b122 100644 --- a/arch/arm64/include/asm/kvm_pgtable.h +++ b/arch/arm64/include/asm/kvm_pgtable.h @@ -11,7 +11,8 @@ #include #include -#define KVM_PGTABLE_MAX_LEVELS 4U +#define KVM_PGTABLE_FIRST_LEVEL -1 +#define KVM_PGTABLE_LAST_LEVEL 3 /* * The largest supported block sizes for KVM (no 52-bit PA support): @@ -20,17 +21,29 @@ * - 64K (level 2): 512MB */ #ifdef CONFIG_ARM64_4K_PAGES -#define KVM_PGTABLE_MIN_BLOCK_LEVEL 1U +#define KVM_PGTABLE_MIN_BLOCK_LEVEL 1 #else -#define KVM_PGTABLE_MIN_BLOCK_LEVEL 2U +#define KVM_PGTABLE_MIN_BLOCK_LEVEL 2 #endif +#define kvm_lpa2_is_enabled() system_supports_lpa2() + +static inline u64 kvm_get_parange_max(void) +{ + if (kvm_lpa2_is_enabled() || + (IS_ENABLED(CONFIG_ARM64_PA_BITS_52) && PAGE_SHIFT == 16)) + return ID_AA64MMFR0_EL1_PARANGE_52; + else + return ID_AA64MMFR0_EL1_PARANGE_48; +} + static inline u64 kvm_get_parange(u64 mmfr0) { + u64 parange_max = kvm_get_parange_max(); u64 parange = cpuid_feature_extract_unsigned_field(mmfr0, ID_AA64MMFR0_EL1_PARANGE_SHIFT); - if (parange > ID_AA64MMFR0_EL1_PARANGE_MAX) - parange = ID_AA64MMFR0_EL1_PARANGE_MAX; + if (parange > parange_max) + parange = parange_max; return parange; } @@ -41,6 +54,8 @@ typedef u64 kvm_pte_t; #define KVM_PTE_ADDR_MASK GENMASK(47, PAGE_SHIFT) #define KVM_PTE_ADDR_51_48 GENMASK(15, 12) +#define KVM_PTE_ADDR_MASK_LPA2 GENMASK(49, PAGE_SHIFT) +#define KVM_PTE_ADDR_51_50_LPA2 GENMASK(9, 8) #define KVM_PHYS_INVALID (-1ULL) @@ -51,21 +66,34 @@ static inline bool kvm_pte_valid(kvm_pte_t pte) static inline u64 kvm_pte_to_phys(kvm_pte_t pte) { - u64 pa = pte & KVM_PTE_ADDR_MASK; - - if (PAGE_SHIFT == 16) - pa |= FIELD_GET(KVM_PTE_ADDR_51_48, pte) << 48; + u64 pa; + + if (kvm_lpa2_is_enabled()) { + pa = pte & KVM_PTE_ADDR_MASK_LPA2; + pa |= FIELD_GET(KVM_PTE_ADDR_51_50_LPA2, pte) << 50; + } else { + pa = pte & KVM_PTE_ADDR_MASK; + if (PAGE_SHIFT == 16) + pa |= FIELD_GET(KVM_PTE_ADDR_51_48, pte) << 48; + } return pa; } static inline kvm_pte_t kvm_phys_to_pte(u64 pa) { - kvm_pte_t pte = pa & KVM_PTE_ADDR_MASK; - - if (PAGE_SHIFT == 16) { - pa &= GENMASK(51, 48); - pte |= FIELD_PREP(KVM_PTE_ADDR_51_48, pa >> 48); + kvm_pte_t pte; + + if (kvm_lpa2_is_enabled()) { + pte = pa & KVM_PTE_ADDR_MASK_LPA2; + pa &= GENMASK(51, 50); + pte |= FIELD_PREP(KVM_PTE_ADDR_51_50_LPA2, pa >> 50); + } else { + pte = pa & KVM_PTE_ADDR_MASK; + if (PAGE_SHIFT == 16) { + pa &= GENMASK(51, 48); + pte |= FIELD_PREP(KVM_PTE_ADDR_51_48, pa >> 48); + } } return pte; @@ -76,28 +104,28 @@ static inline kvm_pfn_t kvm_pte_to_pfn(kvm_pte_t pte) return __phys_to_pfn(kvm_pte_to_phys(pte)); } -static inline u64 kvm_granule_shift(u32 level) +static inline u64 kvm_granule_shift(s8 level) { - /* Assumes KVM_PGTABLE_MAX_LEVELS is 4 */ + /* Assumes KVM_PGTABLE_LAST_LEVEL is 3 */ return ARM64_HW_PGTABLE_LEVEL_SHIFT(level); } -static inline u64 kvm_granule_size(u32 level) +static inline u64 kvm_granule_size(s8 level) { return BIT(kvm_granule_shift(level)); } -static inline bool kvm_level_supports_block_mapping(u32 level) +static inline bool kvm_level_supports_block_mapping(s8 level) { return level >= KVM_PGTABLE_MIN_BLOCK_LEVEL; } static inline u32 kvm_supported_block_sizes(void) { - u32 level = KVM_PGTABLE_MIN_BLOCK_LEVEL; + s8 level = KVM_PGTABLE_MIN_BLOCK_LEVEL; u32 r = 0; - for (; level < KVM_PGTABLE_MAX_LEVELS; level++) + for (; level <= KVM_PGTABLE_LAST_LEVEL; level++) r |= BIT(kvm_granule_shift(level)); return r; @@ -142,7 +170,7 @@ struct kvm_pgtable_mm_ops { void* (*zalloc_page)(void *arg); void* (*zalloc_pages_exact)(size_t size); void (*free_pages_exact)(void *addr, size_t size); - void (*free_unlinked_table)(void *addr, u32 level); + void (*free_unlinked_table)(void *addr, s8 level); void (*get_page)(void *addr); void (*put_page)(void *addr); int (*page_count)(void *addr); @@ -238,7 +266,7 @@ struct kvm_pgtable_visit_ctx { u64 start; u64 addr; u64 end; - u32 level; + s8 level; enum kvm_pgtable_walk_flags flags; }; @@ -341,7 +369,7 @@ static inline bool kvm_pgtable_walk_lock_held(void) */ struct kvm_pgtable { u32 ia_bits; - u32 start_level; + s8 start_level; kvm_pteref_t pgd; struct kvm_pgtable_mm_ops *mm_ops; @@ -475,7 +503,7 @@ void kvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt); * The page-table is assumed to be unreachable by any hardware walkers prior to * freeing and therefore no TLB invalidation is performed. */ -void kvm_pgtable_stage2_free_unlinked(struct kvm_pgtable_mm_ops *mm_ops, void *pgtable, u32 level); +void kvm_pgtable_stage2_free_unlinked(struct kvm_pgtable_mm_ops *mm_ops, void *pgtable, s8 level); /** * kvm_pgtable_stage2_create_unlinked() - Create an unlinked stage-2 paging structure. @@ -499,7 +527,7 @@ void kvm_pgtable_stage2_free_unlinked(struct kvm_pgtable_mm_ops *mm_ops, void *p * an ERR_PTR(error) on failure. */ kvm_pte_t *kvm_pgtable_stage2_create_unlinked(struct kvm_pgtable *pgt, - u64 phys, u32 level, + u64 phys, s8 level, enum kvm_pgtable_prot prot, void *mc, bool force_pte); @@ -725,7 +753,7 @@ int kvm_pgtable_walk(struct kvm_pgtable *pgt, u64 addr, u64 size, * Return: 0 on success, negative error code on failure. */ int kvm_pgtable_get_leaf(struct kvm_pgtable *pgt, u64 addr, - kvm_pte_t *ptep, u32 *level); + kvm_pte_t *ptep, s8 *level); /** * kvm_pgtable_stage2_pte_prot() - Retrieve the protection attributes of a diff --git a/arch/arm64/include/asm/kvm_pkvm.h b/arch/arm64/include/asm/kvm_pkvm.h index e46250a0201721..ad9cfb5c1ff4e6 100644 --- a/arch/arm64/include/asm/kvm_pkvm.h +++ b/arch/arm64/include/asm/kvm_pkvm.h @@ -56,10 +56,11 @@ static inline unsigned long hyp_vm_table_pages(void) static inline unsigned long __hyp_pgtable_max_pages(unsigned long nr_pages) { - unsigned long total = 0, i; + unsigned long total = 0; + int i; /* Provision the worst case scenario */ - for (i = 0; i < KVM_PGTABLE_MAX_LEVELS; i++) { + for (i = KVM_PGTABLE_FIRST_LEVEL; i <= KVM_PGTABLE_LAST_LEVEL; i++) { nr_pages = DIV_ROUND_UP(nr_pages, PTRS_PER_PTE); total += nr_pages; } diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h index fde4186cc38708..d82305ab420f74 100644 --- a/arch/arm64/include/asm/memory.h +++ b/arch/arm64/include/asm/memory.h @@ -65,15 +65,41 @@ #define KERNEL_END _end /* - * Generic and tag-based KASAN require 1/8th and 1/16th of the kernel virtual - * address space for the shadow region respectively. They can bloat the stack - * significantly, so double the (minimum) stack size when they are in use. + * Generic and Software Tag-Based KASAN modes require 1/8th and 1/16th of the + * kernel virtual address space for storing the shadow memory respectively. + * + * The mapping between a virtual memory address and its corresponding shadow + * memory address is defined based on the formula: + * + * shadow_addr = (addr >> KASAN_SHADOW_SCALE_SHIFT) + KASAN_SHADOW_OFFSET + * + * where KASAN_SHADOW_SCALE_SHIFT is the order of the number of bits that map + * to a single shadow byte and KASAN_SHADOW_OFFSET is a constant that offsets + * the mapping. Note that KASAN_SHADOW_OFFSET does not point to the start of + * the shadow memory region. + * + * Based on this mapping, we define two constants: + * + * KASAN_SHADOW_START: the start of the shadow memory region; + * KASAN_SHADOW_END: the end of the shadow memory region. + * + * KASAN_SHADOW_END is defined first as the shadow address that corresponds to + * the upper bound of possible virtual kernel memory addresses UL(1) << 64 + * according to the mapping formula. + * + * KASAN_SHADOW_START is defined second based on KASAN_SHADOW_END. The shadow + * memory start must map to the lowest possible kernel virtual memory address + * and thus it depends on the actual bitness of the address space. + * + * As KASAN inserts redzones between stack variables, this increases the stack + * memory usage significantly. Thus, we double the (minimum) stack size. */ #if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS) #define KASAN_SHADOW_OFFSET _AC(CONFIG_KASAN_SHADOW_OFFSET, UL) -#define KASAN_SHADOW_END ((UL(1) << (64 - KASAN_SHADOW_SCALE_SHIFT)) \ - + KASAN_SHADOW_OFFSET) -#define PAGE_END (KASAN_SHADOW_END - (1UL << (vabits_actual - KASAN_SHADOW_SCALE_SHIFT))) +#define KASAN_SHADOW_END ((UL(1) << (64 - KASAN_SHADOW_SCALE_SHIFT)) + KASAN_SHADOW_OFFSET) +#define _KASAN_SHADOW_START(va) (KASAN_SHADOW_END - (UL(1) << ((va) - KASAN_SHADOW_SCALE_SHIFT))) +#define KASAN_SHADOW_START _KASAN_SHADOW_START(vabits_actual) +#define PAGE_END KASAN_SHADOW_START #define KASAN_THREAD_SHIFT 1 #else #define KASAN_THREAD_SHIFT 0 @@ -182,6 +208,7 @@ #include #include #include +#include #if VA_BITS > 48 extern u64 vabits_actual; @@ -193,15 +220,12 @@ extern s64 memstart_addr; /* PHYS_OFFSET - the physical address of the start of memory. */ #define PHYS_OFFSET ({ VM_BUG_ON(memstart_addr & 1); memstart_addr; }) -/* the virtual base of the kernel image */ -extern u64 kimage_vaddr; - /* the offset between the kernel virtual and physical mappings */ extern u64 kimage_voffset; static inline unsigned long kaslr_offset(void) { - return kimage_vaddr - KIMAGE_VADDR; + return (u64)&_text - KIMAGE_VADDR; } #ifdef CONFIG_RANDOMIZE_BASE @@ -407,6 +431,5 @@ void dump_mem_limit(void); #define INIT_MEMBLOCK_MEMORY_REGIONS (INIT_MEMBLOCK_REGIONS * 8) #endif -#include #endif /* __ASM_MEMORY_H */ diff --git a/arch/arm64/include/asm/pgtable-prot.h b/arch/arm64/include/asm/pgtable-prot.h index e9624f6326dde8..483dbfa39c4c9c 100644 --- a/arch/arm64/include/asm/pgtable-prot.h +++ b/arch/arm64/include/asm/pgtable-prot.h @@ -71,6 +71,8 @@ extern bool arm64_use_ng_mappings; #define PTE_MAYBE_NG (arm64_use_ng_mappings ? PTE_NG : 0) #define PMD_MAYBE_NG (arm64_use_ng_mappings ? PMD_SECT_NG : 0) +#define lpa2_is_enabled() false + /* * If we have userspace only BTI we don't want to mark kernel pages * guarded even if the system does support BTI. diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h index e5bc54522e7112..5b0a04810b236b 100644 --- a/arch/arm64/include/asm/processor.h +++ b/arch/arm64/include/asm/processor.h @@ -167,6 +167,9 @@ struct thread_struct { unsigned long fault_address; /* fault info */ unsigned long fault_code; /* ESR_EL1 value */ struct debug_info debug; /* debugging */ + + struct user_fpsimd_state kernel_fpsimd_state; + unsigned int kernel_fpsimd_cpu; #ifdef CONFIG_ARM64_PTR_AUTH struct ptrauth_keys_user keys_user; #ifdef CONFIG_ARM64_PTR_AUTH_KERNEL diff --git a/arch/arm64/include/asm/simd.h b/arch/arm64/include/asm/simd.h index 6a75d7ecdcaa2d..8e86c9e70e4831 100644 --- a/arch/arm64/include/asm/simd.h +++ b/arch/arm64/include/asm/simd.h @@ -12,8 +12,6 @@ #include #include -DECLARE_PER_CPU(bool, fpsimd_context_busy); - #ifdef CONFIG_KERNEL_MODE_NEON /* @@ -28,17 +26,10 @@ static __must_check inline bool may_use_simd(void) /* * We must make sure that the SVE has been initialized properly * before using the SIMD in kernel. - * fpsimd_context_busy is only set while preemption is disabled, - * and is clear whenever preemption is enabled. Since - * this_cpu_read() is atomic w.r.t. preemption, fpsimd_context_busy - * cannot change under our feet -- if it's set we cannot be - * migrated, and if it's clear we cannot be migrated to a CPU - * where it is set. */ return !WARN_ON(!system_capabilities_finalized()) && system_supports_fpsimd() && - !in_hardirq() && !irqs_disabled() && !in_nmi() && - !this_cpu_read(fpsimd_context_busy); + !in_hardirq() && !irqs_disabled() && !in_nmi(); } #else /* ! CONFIG_KERNEL_MODE_NEON */ diff --git a/arch/arm64/include/asm/sparsemem.h b/arch/arm64/include/asm/sparsemem.h index 5f54376210293e..8a8acc220371cb 100644 --- a/arch/arm64/include/asm/sparsemem.h +++ b/arch/arm64/include/asm/sparsemem.h @@ -10,7 +10,7 @@ /* * Section size must be at least 512MB for 64K base * page size config. Otherwise it will be less than - * MAX_ORDER and the build process will fail. + * MAX_PAGE_ORDER and the build process will fail. */ #ifdef CONFIG_ARM64_64K_PAGES #define SECTION_SIZE_BITS 29 diff --git a/arch/arm64/include/asm/spectre.h b/arch/arm64/include/asm/spectre.h index 06c357d83b1382..0c4d9045c31f47 100644 --- a/arch/arm64/include/asm/spectre.h +++ b/arch/arm64/include/asm/spectre.h @@ -13,8 +13,8 @@ #define __BP_HARDEN_HYP_VECS_SZ ((BP_HARDEN_EL2_SLOTS - 1) * SZ_2K) #ifndef __ASSEMBLY__ - -#include +#include +#include #include #include diff --git a/arch/arm64/include/asm/stacktrace/common.h b/arch/arm64/include/asm/stacktrace/common.h index 508f734de46ee2..f63dc654e545f4 100644 --- a/arch/arm64/include/asm/stacktrace/common.h +++ b/arch/arm64/include/asm/stacktrace/common.h @@ -9,7 +9,6 @@ #ifndef __ASM_STACKTRACE_COMMON_H #define __ASM_STACKTRACE_COMMON_H -#include #include struct stack_info { @@ -23,12 +22,6 @@ struct stack_info { * @fp: The fp value in the frame record (or the real fp) * @pc: The lr value in the frame record (or the real lr) * - * @kr_cur: When KRETPROBES is selected, holds the kretprobe instance - * associated with the most recently encountered replacement lr - * value. - * - * @task: The task being unwound. - * * @stack: The stack currently being unwound. * @stacks: An array of stacks which can be unwound. * @nr_stacks: The number of stacks in @stacks. @@ -36,10 +29,6 @@ struct stack_info { struct unwind_state { unsigned long fp; unsigned long pc; -#ifdef CONFIG_KRETPROBES - struct llist_node *kr_cur; -#endif - struct task_struct *task; struct stack_info stack; struct stack_info *stacks; @@ -66,14 +55,8 @@ static inline bool stackinfo_on_stack(const struct stack_info *info, return true; } -static inline void unwind_init_common(struct unwind_state *state, - struct task_struct *task) +static inline void unwind_init_common(struct unwind_state *state) { - state->task = task; -#ifdef CONFIG_KRETPROBES - state->kr_cur = NULL; -#endif - state->stack = stackinfo_get_unknown(); } diff --git a/arch/arm64/include/asm/stacktrace/nvhe.h b/arch/arm64/include/asm/stacktrace/nvhe.h index 25ab83a315a76d..44759281d0d437 100644 --- a/arch/arm64/include/asm/stacktrace/nvhe.h +++ b/arch/arm64/include/asm/stacktrace/nvhe.h @@ -31,7 +31,7 @@ static inline void kvm_nvhe_unwind_init(struct unwind_state *state, unsigned long fp, unsigned long pc) { - unwind_init_common(state, NULL); + unwind_init_common(state); state->fp = fp; state->pc = pc; diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index 5e65f51c10d244..c3b19b376c8672 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -645,6 +645,7 @@ #define OP_AT_S1E0W sys_insn(AT_Op0, 0, AT_CRn, 8, 3) #define OP_AT_S1E1RP sys_insn(AT_Op0, 0, AT_CRn, 9, 0) #define OP_AT_S1E1WP sys_insn(AT_Op0, 0, AT_CRn, 9, 1) +#define OP_AT_S1E1A sys_insn(AT_Op0, 0, AT_CRn, 9, 2) #define OP_AT_S1E2R sys_insn(AT_Op0, 4, AT_CRn, 8, 0) #define OP_AT_S1E2W sys_insn(AT_Op0, 4, AT_CRn, 8, 1) #define OP_AT_S12E1R sys_insn(AT_Op0, 4, AT_CRn, 8, 4) @@ -781,10 +782,16 @@ #define OP_TLBI_VMALLS12E1NXS sys_insn(1, 4, 9, 7, 6) /* Misc instructions */ +#define OP_GCSPUSHX sys_insn(1, 0, 7, 7, 4) +#define OP_GCSPOPCX sys_insn(1, 0, 7, 7, 5) +#define OP_GCSPOPX sys_insn(1, 0, 7, 7, 6) +#define OP_GCSPUSHM sys_insn(1, 3, 7, 7, 0) + #define OP_BRB_IALL sys_insn(1, 1, 7, 2, 4) #define OP_BRB_INJ sys_insn(1, 1, 7, 2, 5) #define OP_CFP_RCTX sys_insn(1, 3, 7, 3, 4) #define OP_DVP_RCTX sys_insn(1, 3, 7, 3, 5) +#define OP_COSP_RCTX sys_insn(1, 3, 7, 3, 6) #define OP_CPP_RCTX sys_insn(1, 3, 7, 3, 7) /* Common SCTLR_ELx flags. */ @@ -871,10 +878,12 @@ /* id_aa64mmfr0 */ #define ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED_MIN 0x0 +#define ID_AA64MMFR0_EL1_TGRAN4_LPA2 ID_AA64MMFR0_EL1_TGRAN4_52_BIT #define ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED_MAX 0x7 #define ID_AA64MMFR0_EL1_TGRAN64_SUPPORTED_MIN 0x0 #define ID_AA64MMFR0_EL1_TGRAN64_SUPPORTED_MAX 0x7 #define ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED_MIN 0x1 +#define ID_AA64MMFR0_EL1_TGRAN16_LPA2 ID_AA64MMFR0_EL1_TGRAN16_52_BIT #define ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED_MAX 0xf #define ARM64_MIN_PARANGE_BITS 32 @@ -882,6 +891,7 @@ #define ID_AA64MMFR0_EL1_TGRAN_2_SUPPORTED_DEFAULT 0x0 #define ID_AA64MMFR0_EL1_TGRAN_2_SUPPORTED_NONE 0x1 #define ID_AA64MMFR0_EL1_TGRAN_2_SUPPORTED_MIN 0x2 +#define ID_AA64MMFR0_EL1_TGRAN_2_SUPPORTED_LPA2 0x3 #define ID_AA64MMFR0_EL1_TGRAN_2_SUPPORTED_MAX 0x7 #ifdef CONFIG_ARM64_PA_BITS_52 @@ -892,11 +902,13 @@ #if defined(CONFIG_ARM64_4K_PAGES) #define ID_AA64MMFR0_EL1_TGRAN_SHIFT ID_AA64MMFR0_EL1_TGRAN4_SHIFT +#define ID_AA64MMFR0_EL1_TGRAN_LPA2 ID_AA64MMFR0_EL1_TGRAN4_52_BIT #define ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MIN ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED_MIN #define ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MAX ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED_MAX #define ID_AA64MMFR0_EL1_TGRAN_2_SHIFT ID_AA64MMFR0_EL1_TGRAN4_2_SHIFT #elif defined(CONFIG_ARM64_16K_PAGES) #define ID_AA64MMFR0_EL1_TGRAN_SHIFT ID_AA64MMFR0_EL1_TGRAN16_SHIFT +#define ID_AA64MMFR0_EL1_TGRAN_LPA2 ID_AA64MMFR0_EL1_TGRAN16_52_BIT #define ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MIN ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED_MIN #define ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MAX ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED_MAX #define ID_AA64MMFR0_EL1_TGRAN_2_SHIFT ID_AA64MMFR0_EL1_TGRAN16_2_SHIFT @@ -1039,6 +1051,19 @@ #define PIRx_ELx_PERM(idx, perm) ((perm) << ((idx) * 4)) +/* + * Permission Overlay Extension (POE) permission encodings. + */ +#define POE_NONE UL(0x0) +#define POE_R UL(0x1) +#define POE_X UL(0x2) +#define POE_RX UL(0x3) +#define POE_W UL(0x4) +#define POE_RW UL(0x5) +#define POE_XW UL(0x6) +#define POE_RXW UL(0x7) +#define POE_MASK UL(0xf) + #define ARM64_FEATURE_FIELD_BITS 4 /* Defined for compatibility only, do not add new users. */ diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h index 553d1bc559c603..e72a3bf9e56348 100644 --- a/arch/arm64/include/asm/thread_info.h +++ b/arch/arm64/include/asm/thread_info.h @@ -80,6 +80,7 @@ void arch_setup_new_exec(void); #define TIF_TAGGED_ADDR 26 /* Allow tagged user addresses */ #define TIF_SME 27 /* SME in use */ #define TIF_SME_VL_INHERIT 28 /* Inherit SME vl_onexec across exec */ +#define TIF_KERNEL_FPSTATE 29 /* Task is in a kernel mode FPSIMD section */ #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) diff --git a/arch/arm64/include/asm/tlb.h b/arch/arm64/include/asm/tlb.h index 846c563689a818..0150deb332afd7 100644 --- a/arch/arm64/include/asm/tlb.h +++ b/arch/arm64/include/asm/tlb.h @@ -22,15 +22,15 @@ static void tlb_flush(struct mmu_gather *tlb); #include /* - * get the tlbi levels in arm64. Default value is 0 if more than one - * of cleared_* is set or neither is set. - * Arm64 doesn't support p4ds now. + * get the tlbi levels in arm64. Default value is TLBI_TTL_UNKNOWN if more than + * one of cleared_* is set or neither is set - this elides the level hinting to + * the hardware. */ static inline int tlb_get_level(struct mmu_gather *tlb) { /* The TTL field is only valid for the leaf entry. */ if (tlb->freed_tables) - return 0; + return TLBI_TTL_UNKNOWN; if (tlb->cleared_ptes && !(tlb->cleared_pmds || tlb->cleared_puds || @@ -47,7 +47,12 @@ static inline int tlb_get_level(struct mmu_gather *tlb) tlb->cleared_p4ds)) return 1; - return 0; + if (tlb->cleared_p4ds && !(tlb->cleared_ptes || + tlb->cleared_pmds || + tlb->cleared_puds)) + return 0; + + return TLBI_TTL_UNKNOWN; } static inline void tlb_flush(struct mmu_gather *tlb) diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h index bb2c2833a98722..1deb5d789c2e23 100644 --- a/arch/arm64/include/asm/tlbflush.h +++ b/arch/arm64/include/asm/tlbflush.h @@ -94,19 +94,22 @@ static inline unsigned long get_trans_granule(void) * When ARMv8.4-TTL exists, TLBI operations take an additional hint for * the level at which the invalidation must take place. If the level is * wrong, no invalidation may take place. In the case where the level - * cannot be easily determined, a 0 value for the level parameter will - * perform a non-hinted invalidation. + * cannot be easily determined, the value TLBI_TTL_UNKNOWN will perform + * a non-hinted invalidation. Any provided level outside the hint range + * will also cause fall-back to non-hinted invalidation. * * For Stage-2 invalidation, use the level values provided to that effect * in asm/stage2_pgtable.h. */ #define TLBI_TTL_MASK GENMASK_ULL(47, 44) +#define TLBI_TTL_UNKNOWN INT_MAX + #define __tlbi_level(op, addr, level) do { \ u64 arg = addr; \ \ if (alternative_has_cap_unlikely(ARM64_HAS_ARMv8_4_TTL) && \ - level) { \ + level >= 0 && level <= 3) { \ u64 ttl = level & 3; \ ttl |= get_trans_granule() << 2; \ arg &= ~TLBI_TTL_MASK; \ @@ -122,28 +125,34 @@ static inline unsigned long get_trans_granule(void) } while (0) /* - * This macro creates a properly formatted VA operand for the TLB RANGE. - * The value bit assignments are: + * This macro creates a properly formatted VA operand for the TLB RANGE. The + * value bit assignments are: * * +----------+------+-------+-------+-------+----------------------+ * | ASID | TG | SCALE | NUM | TTL | BADDR | * +-----------------+-------+-------+-------+----------------------+ * |63 48|47 46|45 44|43 39|38 37|36 0| * - * The address range is determined by below formula: - * [BADDR, BADDR + (NUM + 1) * 2^(5*SCALE + 1) * PAGESIZE) + * The address range is determined by below formula: [BADDR, BADDR + (NUM + 1) * + * 2^(5*SCALE + 1) * PAGESIZE) + * + * Note that the first argument, baddr, is pre-shifted; If LPA2 is in use, BADDR + * holds addr[52:16]. Else BADDR holds page number. See for example ARM DDI + * 0487J.a section C5.5.60 "TLBI VAE1IS, TLBI VAE1ISNXS, TLB Invalidate by VA, + * EL1, Inner Shareable". * */ -#define __TLBI_VADDR_RANGE(addr, asid, scale, num, ttl) \ - ({ \ - unsigned long __ta = (addr) >> PAGE_SHIFT; \ - __ta &= GENMASK_ULL(36, 0); \ - __ta |= (unsigned long)(ttl) << 37; \ - __ta |= (unsigned long)(num) << 39; \ - __ta |= (unsigned long)(scale) << 44; \ - __ta |= get_trans_granule() << 46; \ - __ta |= (unsigned long)(asid) << 48; \ - __ta; \ +#define __TLBI_VADDR_RANGE(baddr, asid, scale, num, ttl) \ + ({ \ + unsigned long __ta = (baddr); \ + unsigned long __ttl = (ttl >= 1 && ttl <= 3) ? ttl : 0; \ + __ta &= GENMASK_ULL(36, 0); \ + __ta |= __ttl << 37; \ + __ta |= (unsigned long)(num) << 39; \ + __ta |= (unsigned long)(scale) << 44; \ + __ta |= get_trans_granule() << 46; \ + __ta |= (unsigned long)(asid) << 48; \ + __ta; \ }) /* These macros are used by the TLBI RANGE feature. */ @@ -216,12 +225,16 @@ static inline unsigned long get_trans_granule(void) * CPUs, ensuring that any walk-cache entries associated with the * translation are also invalidated. * - * __flush_tlb_range(vma, start, end, stride, last_level) + * __flush_tlb_range(vma, start, end, stride, last_level, tlb_level) * Invalidate the virtual-address range '[start, end)' on all * CPUs for the user address space corresponding to 'vma->mm'. * The invalidation operations are issued at a granularity * determined by 'stride' and only affect any walk-cache entries - * if 'last_level' is equal to false. + * if 'last_level' is equal to false. tlb_level is the level at + * which the invalidation must take place. If the level is wrong, + * no invalidation may take place. In the case where the level + * cannot be easily determined, the value TLBI_TTL_UNKNOWN will + * perform a non-hinted invalidation. * * * Finally, take a look at asm/tlb.h to see how tlb_flush() is implemented @@ -345,34 +358,44 @@ static inline void arch_tlbbatch_flush(struct arch_tlbflush_unmap_batch *batch) * @tlb_level: Translation Table level hint, if known * @tlbi_user: If 'true', call an additional __tlbi_user() * (typically for user ASIDs). 'flase' for IPA instructions + * @lpa2: If 'true', the lpa2 scheme is used as set out below * * When the CPU does not support TLB range operations, flush the TLB * entries one by one at the granularity of 'stride'. If the TLB * range ops are supported, then: * - * 1. If 'pages' is odd, flush the first page through non-range - * operations; + * 1. If FEAT_LPA2 is in use, the start address of a range operation must be + * 64KB aligned, so flush pages one by one until the alignment is reached + * using the non-range operations. This step is skipped if LPA2 is not in + * use. + * + * 2. The minimum range granularity is decided by 'scale', so multiple range + * TLBI operations may be required. Start from scale = 3, flush the largest + * possible number of pages ((num+1)*2^(5*scale+1)) that fit into the + * requested range, then decrement scale and continue until one or zero pages + * are left. We must start from highest scale to ensure 64KB start alignment + * is maintained in the LPA2 case. * - * 2. For remaining pages: the minimum range granularity is decided - * by 'scale', so multiple range TLBI operations may be required. - * Start from scale = 0, flush the corresponding number of pages - * ((num+1)*2^(5*scale+1) starting from 'addr'), then increase it - * until no pages left. + * 3. If there is 1 page remaining, flush it through non-range operations. Range + * operations can only span an even number of pages. We save this for last to + * ensure 64KB start alignment is maintained for the LPA2 case. * * Note that certain ranges can be represented by either num = 31 and * scale or num = 0 and scale + 1. The loop below favours the latter * since num is limited to 30 by the __TLBI_RANGE_NUM() macro. */ #define __flush_tlb_range_op(op, start, pages, stride, \ - asid, tlb_level, tlbi_user) \ + asid, tlb_level, tlbi_user, lpa2) \ do { \ int num = 0; \ - int scale = 0; \ + int scale = 3; \ + int shift = lpa2 ? 16 : PAGE_SHIFT; \ unsigned long addr; \ \ while (pages > 0) { \ if (!system_supports_tlb_range() || \ - pages % 2 == 1) { \ + pages == 1 || \ + (lpa2 && start != ALIGN(start, SZ_64K))) { \ addr = __TLBI_VADDR(start, asid); \ __tlbi_level(op, addr, tlb_level); \ if (tlbi_user) \ @@ -384,20 +407,20 @@ do { \ \ num = __TLBI_RANGE_NUM(pages, scale); \ if (num >= 0) { \ - addr = __TLBI_VADDR_RANGE(start, asid, scale, \ - num, tlb_level); \ + addr = __TLBI_VADDR_RANGE(start >> shift, asid, \ + scale, num, tlb_level); \ __tlbi(r##op, addr); \ if (tlbi_user) \ __tlbi_user(r##op, addr); \ start += __TLBI_RANGE_PAGES(num, scale) << PAGE_SHIFT; \ pages -= __TLBI_RANGE_PAGES(num, scale); \ } \ - scale++; \ + scale--; \ } \ } while (0) #define __flush_s2_tlb_range_op(op, start, pages, stride, tlb_level) \ - __flush_tlb_range_op(op, start, pages, stride, 0, tlb_level, false) + __flush_tlb_range_op(op, start, pages, stride, 0, tlb_level, false, kvm_lpa2_is_enabled()); static inline void __flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end, @@ -427,9 +450,11 @@ static inline void __flush_tlb_range(struct vm_area_struct *vma, asid = ASID(vma->vm_mm); if (last_level) - __flush_tlb_range_op(vale1is, start, pages, stride, asid, tlb_level, true); + __flush_tlb_range_op(vale1is, start, pages, stride, asid, + tlb_level, true, lpa2_is_enabled()); else - __flush_tlb_range_op(vae1is, start, pages, stride, asid, tlb_level, true); + __flush_tlb_range_op(vae1is, start, pages, stride, asid, + tlb_level, true, lpa2_is_enabled()); dsb(ish); mmu_notifier_arch_invalidate_secondary_tlbs(vma->vm_mm, start, end); @@ -441,9 +466,10 @@ static inline void flush_tlb_range(struct vm_area_struct *vma, /* * We cannot use leaf-only invalidation here, since we may be invalidating * table entries as part of collapsing hugepages or moving page tables. - * Set the tlb_level to 0 because we can not get enough information here. + * Set the tlb_level to TLBI_TTL_UNKNOWN because we can not get enough + * information here. */ - __flush_tlb_range(vma, start, end, PAGE_SIZE, false, 0); + __flush_tlb_range(vma, start, end, PAGE_SIZE, false, TLBI_TTL_UNKNOWN); } static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end) diff --git a/arch/arm64/include/asm/topology.h b/arch/arm64/include/asm/topology.h index 9fab663dd2de96..a323b109b9c44b 100644 --- a/arch/arm64/include/asm/topology.h +++ b/arch/arm64/include/asm/topology.h @@ -23,6 +23,7 @@ void update_freq_counters_refs(void); #define arch_set_freq_scale topology_set_freq_scale #define arch_scale_freq_capacity topology_get_freq_scale #define arch_scale_freq_invariant topology_scale_freq_invariant +#define arch_scale_freq_ref topology_get_freq_ref #ifdef CONFIG_ACPI_CPPC_LIB #define arch_init_invariance_cppc topology_init_cpu_capacity_cppc diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h index 531effca5f1fc0..491b2b9bd5536f 100644 --- a/arch/arm64/include/asm/unistd.h +++ b/arch/arm64/include/asm/unistd.h @@ -39,7 +39,7 @@ #define __ARM_NR_compat_set_tls (__ARM_NR_COMPAT_BASE + 5) #define __ARM_NR_COMPAT_END (__ARM_NR_COMPAT_BASE + 0x800) -#define __NR_compat_syscalls 457 +#define __NR_compat_syscalls 462 #endif #define __ARCH_WANT_SYS_CLONE diff --git a/arch/arm64/include/asm/unistd32.h b/arch/arm64/include/asm/unistd32.h index 9f7c1bf9952679..7118282d1c7976 100644 --- a/arch/arm64/include/asm/unistd32.h +++ b/arch/arm64/include/asm/unistd32.h @@ -919,6 +919,16 @@ __SYSCALL(__NR_futex_wake, sys_futex_wake) __SYSCALL(__NR_futex_wait, sys_futex_wait) #define __NR_futex_requeue 456 __SYSCALL(__NR_futex_requeue, sys_futex_requeue) +#define __NR_statmount 457 +__SYSCALL(__NR_statmount, sys_statmount) +#define __NR_listmount 458 +__SYSCALL(__NR_listmount, sys_listmount) +#define __NR_lsm_get_self_attr 459 +__SYSCALL(__NR_lsm_get_self_attr, sys_lsm_get_self_attr) +#define __NR_lsm_set_self_attr 460 +__SYSCALL(__NR_lsm_set_self_attr, sys_lsm_set_self_attr) +#define __NR_lsm_list_modules 461 +__SYSCALL(__NR_lsm_list_modules, sys_lsm_list_modules) /* * Please add new compat syscalls above this comment and update diff --git a/arch/arm64/include/asm/vncr_mapping.h b/arch/arm64/include/asm/vncr_mapping.h new file mode 100644 index 00000000000000..df2c47c559728b --- /dev/null +++ b/arch/arm64/include/asm/vncr_mapping.h @@ -0,0 +1,103 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * System register offsets in the VNCR page + * All offsets are *byte* displacements! + */ + +#ifndef __ARM64_VNCR_MAPPING_H__ +#define __ARM64_VNCR_MAPPING_H__ + +#define VNCR_VTTBR_EL2 0x020 +#define VNCR_VTCR_EL2 0x040 +#define VNCR_VMPIDR_EL2 0x050 +#define VNCR_CNTVOFF_EL2 0x060 +#define VNCR_HCR_EL2 0x078 +#define VNCR_HSTR_EL2 0x080 +#define VNCR_VPIDR_EL2 0x088 +#define VNCR_TPIDR_EL2 0x090 +#define VNCR_HCRX_EL2 0x0A0 +#define VNCR_VNCR_EL2 0x0B0 +#define VNCR_CPACR_EL1 0x100 +#define VNCR_CONTEXTIDR_EL1 0x108 +#define VNCR_SCTLR_EL1 0x110 +#define VNCR_ACTLR_EL1 0x118 +#define VNCR_TCR_EL1 0x120 +#define VNCR_AFSR0_EL1 0x128 +#define VNCR_AFSR1_EL1 0x130 +#define VNCR_ESR_EL1 0x138 +#define VNCR_MAIR_EL1 0x140 +#define VNCR_AMAIR_EL1 0x148 +#define VNCR_MDSCR_EL1 0x158 +#define VNCR_SPSR_EL1 0x160 +#define VNCR_CNTV_CVAL_EL0 0x168 +#define VNCR_CNTV_CTL_EL0 0x170 +#define VNCR_CNTP_CVAL_EL0 0x178 +#define VNCR_CNTP_CTL_EL0 0x180 +#define VNCR_SCXTNUM_EL1 0x188 +#define VNCR_TFSR_EL1 0x190 +#define VNCR_HFGRTR_EL2 0x1B8 +#define VNCR_HFGWTR_EL2 0x1C0 +#define VNCR_HFGITR_EL2 0x1C8 +#define VNCR_HDFGRTR_EL2 0x1D0 +#define VNCR_HDFGWTR_EL2 0x1D8 +#define VNCR_ZCR_EL1 0x1E0 +#define VNCR_HAFGRTR_EL2 0x1E8 +#define VNCR_TTBR0_EL1 0x200 +#define VNCR_TTBR1_EL1 0x210 +#define VNCR_FAR_EL1 0x220 +#define VNCR_ELR_EL1 0x230 +#define VNCR_SP_EL1 0x240 +#define VNCR_VBAR_EL1 0x250 +#define VNCR_TCR2_EL1 0x270 +#define VNCR_PIRE0_EL1 0x290 +#define VNCR_PIRE0_EL2 0x298 +#define VNCR_PIR_EL1 0x2A0 +#define VNCR_ICH_LR0_EL2 0x400 +#define VNCR_ICH_LR1_EL2 0x408 +#define VNCR_ICH_LR2_EL2 0x410 +#define VNCR_ICH_LR3_EL2 0x418 +#define VNCR_ICH_LR4_EL2 0x420 +#define VNCR_ICH_LR5_EL2 0x428 +#define VNCR_ICH_LR6_EL2 0x430 +#define VNCR_ICH_LR7_EL2 0x438 +#define VNCR_ICH_LR8_EL2 0x440 +#define VNCR_ICH_LR9_EL2 0x448 +#define VNCR_ICH_LR10_EL2 0x450 +#define VNCR_ICH_LR11_EL2 0x458 +#define VNCR_ICH_LR12_EL2 0x460 +#define VNCR_ICH_LR13_EL2 0x468 +#define VNCR_ICH_LR14_EL2 0x470 +#define VNCR_ICH_LR15_EL2 0x478 +#define VNCR_ICH_AP0R0_EL2 0x480 +#define VNCR_ICH_AP0R1_EL2 0x488 +#define VNCR_ICH_AP0R2_EL2 0x490 +#define VNCR_ICH_AP0R3_EL2 0x498 +#define VNCR_ICH_AP1R0_EL2 0x4A0 +#define VNCR_ICH_AP1R1_EL2 0x4A8 +#define VNCR_ICH_AP1R2_EL2 0x4B0 +#define VNCR_ICH_AP1R3_EL2 0x4B8 +#define VNCR_ICH_HCR_EL2 0x4C0 +#define VNCR_ICH_VMCR_EL2 0x4C8 +#define VNCR_VDISR_EL2 0x500 +#define VNCR_PMBLIMITR_EL1 0x800 +#define VNCR_PMBPTR_EL1 0x810 +#define VNCR_PMBSR_EL1 0x820 +#define VNCR_PMSCR_EL1 0x828 +#define VNCR_PMSEVFR_EL1 0x830 +#define VNCR_PMSICR_EL1 0x838 +#define VNCR_PMSIRR_EL1 0x840 +#define VNCR_PMSLATFR_EL1 0x848 +#define VNCR_TRFCR_EL1 0x880 +#define VNCR_MPAM1_EL1 0x900 +#define VNCR_MPAMHCR_EL2 0x930 +#define VNCR_MPAMVPMV_EL2 0x938 +#define VNCR_MPAMVPM0_EL2 0x940 +#define VNCR_MPAMVPM1_EL2 0x948 +#define VNCR_MPAMVPM2_EL2 0x950 +#define VNCR_MPAMVPM3_EL2 0x958 +#define VNCR_MPAMVPM4_EL2 0x960 +#define VNCR_MPAMVPM5_EL2 0x968 +#define VNCR_MPAMVPM6_EL2 0x970 +#define VNCR_MPAMVPM7_EL2 0x978 + +#endif /* __ARM64_VNCR_MAPPING_H__ */ diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index d95b3d6b471a7d..e5d03a7039b4bf 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -73,7 +73,13 @@ obj-$(CONFIG_ARM64_MTE) += mte.o obj-y += vdso-wrap.o obj-$(CONFIG_COMPAT_VDSO) += vdso32-wrap.o obj-$(CONFIG_UNWIND_PATCH_PAC_INTO_SCS) += patch-scs.o -CFLAGS_patch-scs.o += -mbranch-protection=none + +# We need to prevent the SCS patching code from patching itself. Using +# -mbranch-protection=none here to avoid the patchable PAC opcodes from being +# generated triggers an issue with full LTO on Clang, which stops emitting PAC +# instructions altogether. So instead, omit the unwind tables used by the +# patching code, so it will not be able to locate its own PAC instructions. +CFLAGS_patch-scs.o += -fno-asynchronous-unwind-tables -fno-unwind-tables # Force dependency (vdso*-wrap.S includes vdso.so through incbin) $(obj)/vdso-wrap.o: $(obj)/vdso/vdso.so diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index 5ff1942b04fcfd..5a7dbbe0ce639a 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -117,8 +117,6 @@ int main(void) DEFINE(DMA_FROM_DEVICE, DMA_FROM_DEVICE); BLANK(); DEFINE(PREEMPT_DISABLE_OFFSET, PREEMPT_DISABLE_OFFSET); - DEFINE(SOFTIRQ_SHIFT, SOFTIRQ_SHIFT); - DEFINE(IRQ_CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending)); BLANK(); DEFINE(CPU_BOOT_TASK, offsetof(struct secondary_data, task)); BLANK(); diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index e29e0fea63fb62..967c7c7a4e7db3 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -416,6 +416,19 @@ static struct midr_range broken_aarch32_aes[] = { }; #endif /* CONFIG_ARM64_WORKAROUND_TRBE_WRITE_OUT_OF_RANGE */ +#ifdef CONFIG_ARM64_WORKAROUND_SPECULATIVE_UNPRIV_LOAD +static const struct midr_range erratum_spec_unpriv_load_list[] = { +#ifdef CONFIG_ARM64_ERRATUM_3117295 + MIDR_ALL_VERSIONS(MIDR_CORTEX_A510), +#endif +#ifdef CONFIG_ARM64_ERRATUM_2966298 + /* Cortex-A520 r0p0 to r0p1 */ + MIDR_REV_RANGE(MIDR_CORTEX_A520, 0, 0, 1), +#endif + {}, +}; +#endif + const struct arm64_cpu_capabilities arm64_errata[] = { #ifdef CONFIG_ARM64_WORKAROUND_CLEAN_CACHE { @@ -713,12 +726,12 @@ const struct arm64_cpu_capabilities arm64_errata[] = { MIDR_FIXED(MIDR_CPU_VAR_REV(1,1), BIT(25)), }, #endif -#ifdef CONFIG_ARM64_ERRATUM_2966298 +#ifdef CONFIG_ARM64_WORKAROUND_SPECULATIVE_UNPRIV_LOAD { - .desc = "ARM erratum 2966298", - .capability = ARM64_WORKAROUND_2966298, + .desc = "ARM errata 2966298, 3117295", + .capability = ARM64_WORKAROUND_SPECULATIVE_UNPRIV_LOAD, /* Cortex-A520 r0p0 - r0p1 */ - ERRATA_MIDR_REV_RANGE(MIDR_CORTEX_A520, 0, 0, 1), + ERRATA_MIDR_RANGE_LIST(erratum_spec_unpriv_load_list), }, #endif #ifdef CONFIG_AMPERE_ERRATUM_AC03_CPU_38 diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 91d2d671496911..8d1a634a403eed 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -1081,25 +1081,6 @@ void __init init_cpu_features(struct cpuinfo_arm64 *info) if (id_aa64pfr1_mte(info->reg_id_aa64pfr1)) init_cpu_ftr_reg(SYS_GMID_EL1, info->reg_gmid); - - /* - * Initialize the indirect array of CPU capabilities pointers before we - * handle the boot CPU below. - */ - init_cpucap_indirect_list(); - - /* - * Detect broken pseudo-NMI. Must be called _before_ the call to - * setup_boot_cpu_capabilities() since it interacts with - * can_use_gic_priorities(). - */ - detect_system_supports_pseudo_nmi(); - - /* - * Detect and enable early CPU capabilities based on the boot CPU, - * after we have initialised the CPU feature infrastructure. - */ - setup_boot_cpu_capabilities(); } static void update_cpu_ftr_reg(struct arm64_ftr_reg *reg, u64 new) @@ -1584,16 +1565,6 @@ static bool has_useable_gicv3_cpuif(const struct arm64_cpu_capabilities *entry, return has_sre; } -static bool has_no_hw_prefetch(const struct arm64_cpu_capabilities *entry, int __unused) -{ - u32 midr = read_cpuid_id(); - - /* Cavium ThunderX pass 1.x and 2.x */ - return midr_is_cpu_model_range(midr, MIDR_THUNDERX, - MIDR_CPU_VAR_REV(0, 0), - MIDR_CPU_VAR_REV(1, MIDR_REVISION_MASK)); -} - static bool has_cache_idc(const struct arm64_cpu_capabilities *entry, int scope) { @@ -1768,6 +1739,39 @@ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry, return !meltdown_safe; } +#if defined(ID_AA64MMFR0_EL1_TGRAN_LPA2) && defined(ID_AA64MMFR0_EL1_TGRAN_2_SUPPORTED_LPA2) +static bool has_lpa2_at_stage1(u64 mmfr0) +{ + unsigned int tgran; + + tgran = cpuid_feature_extract_unsigned_field(mmfr0, + ID_AA64MMFR0_EL1_TGRAN_SHIFT); + return tgran == ID_AA64MMFR0_EL1_TGRAN_LPA2; +} + +static bool has_lpa2_at_stage2(u64 mmfr0) +{ + unsigned int tgran; + + tgran = cpuid_feature_extract_unsigned_field(mmfr0, + ID_AA64MMFR0_EL1_TGRAN_2_SHIFT); + return tgran == ID_AA64MMFR0_EL1_TGRAN_2_SUPPORTED_LPA2; +} + +static bool has_lpa2(const struct arm64_cpu_capabilities *entry, int scope) +{ + u64 mmfr0; + + mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1); + return has_lpa2_at_stage1(mmfr0) && has_lpa2_at_stage2(mmfr0); +} +#else +static bool has_lpa2(const struct arm64_cpu_capabilities *entry, int scope) +{ + return false; +} +#endif + #ifdef CONFIG_UNMAP_KERNEL_AT_EL0 #define KPTI_NG_TEMP_VA (-(1UL << PMD_SHIFT)) @@ -1840,7 +1844,7 @@ static int __init __kpti_install_ng_mappings(void *__unused) static void __init kpti_install_ng_mappings(void) { /* Check whether KPTI is going to be used */ - if (!cpus_have_cap(ARM64_UNMAP_KERNEL_AT_EL0)) + if (!arm64_kernel_unmapped_at_el0()) return; /* @@ -2325,12 +2329,6 @@ static const struct arm64_cpu_capabilities arm64_features[] = { ARM64_CPUID_FIELDS(ID_AA64ISAR0_EL1, ATOMIC, IMP) }, #endif /* CONFIG_ARM64_LSE_ATOMICS */ - { - .desc = "Software prefetching using PRFM", - .capability = ARM64_HAS_NO_HW_PREFETCH, - .type = ARM64_CPUCAP_WEAK_LOCAL_CPU_FEATURE, - .matches = has_no_hw_prefetch, - }, { .desc = "Virtualization Host Extensions", .capability = ARM64_HAS_VIRT_HOST_EXTN, @@ -2343,7 +2341,7 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .capability = ARM64_HAS_NESTED_VIRT, .type = ARM64_CPUCAP_SYSTEM_FEATURE, .matches = has_nested_virt_support, - ARM64_CPUID_FIELDS(ID_AA64MMFR2_EL1, NV, IMP) + ARM64_CPUID_FIELDS(ID_AA64MMFR2_EL1, NV, NV2) }, { .capability = ARM64_HAS_32BIT_EL0_DO_NOT_USE, @@ -2735,6 +2733,12 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .matches = has_cpuid_feature, ARM64_CPUID_FIELDS(ID_AA64MMFR2_EL1, EVT, IMP) }, + { + .desc = "52-bit Virtual Addressing for KVM (LPA2)", + .capability = ARM64_HAS_LPA2, + .type = ARM64_CPUCAP_SYSTEM_FEATURE, + .matches = has_lpa2, + }, {}, }; @@ -3275,14 +3279,6 @@ void check_local_cpu_capabilities(void) verify_local_cpu_capabilities(); } -static void __init setup_boot_cpu_capabilities(void) -{ - /* Detect capabilities with either SCOPE_BOOT_CPU or SCOPE_LOCAL_CPU */ - update_cpu_capabilities(SCOPE_BOOT_CPU | SCOPE_LOCAL_CPU); - /* Enable the SCOPE_BOOT_CPU capabilities alone right away */ - enable_cpu_capabilities(SCOPE_BOOT_CPU); -} - bool this_cpu_has_cap(unsigned int n) { if (!WARN_ON(preemptible()) && n < ARM64_NCAPS) { @@ -3338,37 +3334,52 @@ unsigned long cpu_get_elf_hwcap2(void) return elf_hwcap[1]; } -void __init setup_system_features(void) +static void __init setup_boot_cpu_capabilities(void) { - int i; /* - * The system-wide safe feature feature register values have been - * finalized. Finalize and log the available system capabilities. + * The boot CPU's feature register values have been recorded. Detect + * boot cpucaps and local cpucaps for the boot CPU, then enable and + * patch alternatives for the available boot cpucaps. */ - update_cpu_capabilities(SCOPE_SYSTEM); - if (IS_ENABLED(CONFIG_ARM64_SW_TTBR0_PAN) && - !cpus_have_cap(ARM64_HAS_PAN)) - pr_info("emulated: Privileged Access Never (PAN) using TTBR0_EL1 switching\n"); + update_cpu_capabilities(SCOPE_BOOT_CPU | SCOPE_LOCAL_CPU); + enable_cpu_capabilities(SCOPE_BOOT_CPU); + apply_boot_alternatives(); +} +void __init setup_boot_cpu_features(void) +{ /* - * Enable all the available capabilities which have not been enabled - * already. + * Initialize the indirect array of CPU capabilities pointers before we + * handle the boot CPU. */ - enable_cpu_capabilities(SCOPE_ALL & ~SCOPE_BOOT_CPU); + init_cpucap_indirect_list(); - kpti_install_ng_mappings(); + /* + * Detect broken pseudo-NMI. Must be called _before_ the call to + * setup_boot_cpu_capabilities() since it interacts with + * can_use_gic_priorities(). + */ + detect_system_supports_pseudo_nmi(); - sve_setup(); - sme_setup(); + setup_boot_cpu_capabilities(); +} +static void __init setup_system_capabilities(void) +{ /* - * Check for sane CTR_EL0.CWG value. + * The system-wide safe feature register values have been finalized. + * Detect, enable, and patch alternatives for the available system + * cpucaps. */ - if (!cache_type_cwg()) - pr_warn("No Cache Writeback Granule information, assuming %d\n", - ARCH_DMA_MINALIGN); + update_cpu_capabilities(SCOPE_SYSTEM); + enable_cpu_capabilities(SCOPE_ALL & ~SCOPE_BOOT_CPU); + apply_alternatives_all(); - for (i = 0; i < ARM64_NCAPS; i++) { + /* + * Log any cpucaps with a cpumask as these aren't logged by + * update_cpu_capabilities(). + */ + for (int i = 0; i < ARM64_NCAPS; i++) { const struct arm64_cpu_capabilities *caps = cpucap_ptrs[i]; if (caps && caps->cpus && caps->desc && @@ -3376,6 +3387,29 @@ void __init setup_system_features(void) pr_info("detected: %s on CPU%*pbl\n", caps->desc, cpumask_pr_args(caps->cpus)); } + + /* + * TTBR0 PAN doesn't have its own cpucap, so log it manually. + */ + if (system_uses_ttbr0_pan()) + pr_info("emulated: Privileged Access Never (PAN) using TTBR0_EL1 switching\n"); +} + +void __init setup_system_features(void) +{ + setup_system_capabilities(); + + kpti_install_ng_mappings(); + + sve_setup(); + sme_setup(); + + /* + * Check for sane CTR_EL0.CWG value. + */ + if (!cache_type_cwg()) + pr_warn("No Cache Writeback Granule information, assuming %d\n", + ARCH_DMA_MINALIGN); } void __init setup_user_features(void) diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c index a257da7b56fe6a..47043c0d95ec3d 100644 --- a/arch/arm64/kernel/cpuinfo.c +++ b/arch/arm64/kernel/cpuinfo.c @@ -36,8 +36,6 @@ static struct cpuinfo_arm64 boot_cpu_data; static inline const char *icache_policy_str(int l1ip) { switch (l1ip) { - case CTR_EL0_L1Ip_VPIPT: - return "VPIPT"; case CTR_EL0_L1Ip_VIPT: return "VIPT"; case CTR_EL0_L1Ip_PIPT: @@ -388,9 +386,6 @@ static void cpuinfo_detect_icache_policy(struct cpuinfo_arm64 *info) switch (l1ip) { case CTR_EL0_L1Ip_PIPT: break; - case CTR_EL0_L1Ip_VPIPT: - set_bit(ICACHEF_VPIPT, &__icache_flags); - break; case CTR_EL0_L1Ip_VIPT: default: /* Assume aliasing */ diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index a6030913cd58c4..7ef0e127b149fc 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -428,16 +428,9 @@ alternative_else_nop_endif ldp x28, x29, [sp, #16 * 14] .if \el == 0 -alternative_if ARM64_WORKAROUND_2966298 - tlbi vale1, xzr - dsb nsh -alternative_else_nop_endif -alternative_if_not ARM64_UNMAP_KERNEL_AT_EL0 - ldr lr, [sp, #S_LR] - add sp, sp, #PT_REGS_SIZE // restore sp - eret -alternative_else_nop_endif #ifdef CONFIG_UNMAP_KERNEL_AT_EL0 + alternative_insn "b .L_skip_tramp_exit_\@", nop, ARM64_UNMAP_KERNEL_AT_EL0 + msr far_el1, x29 ldr_this_cpu x30, this_cpu_vector, x29 @@ -446,16 +439,26 @@ alternative_else_nop_endif ldr lr, [sp, #S_LR] // restore x30 add sp, sp, #PT_REGS_SIZE // restore sp br x29 + +.L_skip_tramp_exit_\@: #endif - .else + .endif + ldr lr, [sp, #S_LR] add sp, sp, #PT_REGS_SIZE // restore sp + .if \el == 0 + /* This must be after the last explicit memory access */ +alternative_if ARM64_WORKAROUND_SPECULATIVE_UNPRIV_LOAD + tlbi vale1, xzr + dsb nsh +alternative_else_nop_endif + .else /* Ensure any device/NC reads complete */ alternative_insn nop, "dmb sy", ARM64_WORKAROUND_1508412 + .endif eret - .endif sb .endm diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c index 1559c706d32d1d..a5dc6f76419584 100644 --- a/arch/arm64/kernel/fpsimd.c +++ b/arch/arm64/kernel/fpsimd.c @@ -85,13 +85,13 @@ * softirq kicks in. Upon vcpu_put(), KVM will save the vcpu FP state and * flag the register state as invalid. * - * In order to allow softirq handlers to use FPSIMD, kernel_neon_begin() may - * save the task's FPSIMD context back to task_struct from softirq context. - * To prevent this from racing with the manipulation of the task's FPSIMD state - * from task context and thereby corrupting the state, it is necessary to - * protect any manipulation of a task's fpsimd_state or TIF_FOREIGN_FPSTATE - * flag with {, __}get_cpu_fpsimd_context(). This will still allow softirqs to - * run but prevent them to use FPSIMD. + * In order to allow softirq handlers to use FPSIMD, kernel_neon_begin() may be + * called from softirq context, which will save the task's FPSIMD context back + * to task_struct. To prevent this from racing with the manipulation of the + * task's FPSIMD state from task context and thereby corrupting the state, it + * is necessary to protect any manipulation of a task's fpsimd_state or + * TIF_FOREIGN_FPSTATE flag with get_cpu_fpsimd_context(), which will suspend + * softirq servicing entirely until put_cpu_fpsimd_context() is called. * * For a certain task, the sequence may look something like this: * - the task gets scheduled in; if both the task's fpsimd_cpu field @@ -209,27 +209,14 @@ static inline void sme_free(struct task_struct *t) { } #endif -DEFINE_PER_CPU(bool, fpsimd_context_busy); -EXPORT_PER_CPU_SYMBOL(fpsimd_context_busy); - static void fpsimd_bind_task_to_cpu(void); -static void __get_cpu_fpsimd_context(void) -{ - bool busy = __this_cpu_xchg(fpsimd_context_busy, true); - - WARN_ON(busy); -} - /* * Claim ownership of the CPU FPSIMD context for use by the calling context. * * The caller may freely manipulate the FPSIMD context metadata until * put_cpu_fpsimd_context() is called. * - * The double-underscore version must only be called if you know the task - * can't be preempted. - * * On RT kernels local_bh_disable() is not sufficient because it only * serializes soft interrupt related sections via a local lock, but stays * preemptible. Disabling preemption is the right choice here as bottom @@ -242,14 +229,6 @@ static void get_cpu_fpsimd_context(void) local_bh_disable(); else preempt_disable(); - __get_cpu_fpsimd_context(); -} - -static void __put_cpu_fpsimd_context(void) -{ - bool busy = __this_cpu_xchg(fpsimd_context_busy, false); - - WARN_ON(!busy); /* No matching get_cpu_fpsimd_context()? */ } /* @@ -261,18 +240,12 @@ static void __put_cpu_fpsimd_context(void) */ static void put_cpu_fpsimd_context(void) { - __put_cpu_fpsimd_context(); if (!IS_ENABLED(CONFIG_PREEMPT_RT)) local_bh_enable(); else preempt_enable(); } -static bool have_cpu_fpsimd_context(void) -{ - return !preemptible() && __this_cpu_read(fpsimd_context_busy); -} - unsigned int task_get_vl(const struct task_struct *task, enum vec_type type) { return task->thread.vl[type]; @@ -383,7 +356,8 @@ static void task_fpsimd_load(void) bool restore_ffr; WARN_ON(!system_supports_fpsimd()); - WARN_ON(!have_cpu_fpsimd_context()); + WARN_ON(preemptible()); + WARN_ON(test_thread_flag(TIF_KERNEL_FPSTATE)); if (system_supports_sve() || system_supports_sme()) { switch (current->thread.fp_type) { @@ -406,7 +380,7 @@ static void task_fpsimd_load(void) default: /* * This indicates either a bug in - * fpsimd_save() or memory corruption, we + * fpsimd_save_user_state() or memory corruption, we * should always record an explicit format * when we save. We always at least have the * memory allocated for FPSMID registers so @@ -457,7 +431,7 @@ static void task_fpsimd_load(void) * than via current, if we are saving KVM state then it will have * ensured that the type of registers to save is set in last->to_save. */ -static void fpsimd_save(void) +static void fpsimd_save_user_state(void) { struct cpu_fp_state const *last = this_cpu_ptr(&fpsimd_last_state); @@ -467,7 +441,7 @@ static void fpsimd_save(void) unsigned int vl; WARN_ON(!system_supports_fpsimd()); - WARN_ON(!have_cpu_fpsimd_context()); + WARN_ON(preemptible()); if (test_thread_flag(TIF_FOREIGN_FPSTATE)) return; @@ -888,7 +862,7 @@ int vec_set_vector_length(struct task_struct *task, enum vec_type type, if (task == current) { get_cpu_fpsimd_context(); - fpsimd_save(); + fpsimd_save_user_state(); } fpsimd_flush_task_state(task); @@ -924,10 +898,8 @@ int vec_set_vector_length(struct task_struct *task, enum vec_type type, * allocate SVE now in case it is needed for use in streaming * mode. */ - if (system_supports_sve()) { - sve_free(task); - sve_alloc(task, true); - } + sve_free(task); + sve_alloc(task, true); if (free_sme) sme_free(task); @@ -1171,7 +1143,7 @@ void __init sve_setup(void) unsigned long b; int max_bit; - if (!cpus_have_cap(ARM64_SVE)) + if (!system_supports_sve()) return; /* @@ -1245,8 +1217,10 @@ void fpsimd_release_task(struct task_struct *dead_task) */ void sme_alloc(struct task_struct *task, bool flush) { - if (task->thread.sme_state && flush) { - memset(task->thread.sme_state, 0, sme_state_size(task)); + if (task->thread.sme_state) { + if (flush) + memset(task->thread.sme_state, 0, + sme_state_size(task)); return; } @@ -1301,7 +1275,7 @@ void __init sme_setup(void) struct vl_info *info = &vl_info[ARM64_VEC_SME]; int min_bit, max_bit; - if (!cpus_have_cap(ARM64_SME)) + if (!system_supports_sme()) return; /* @@ -1500,6 +1474,34 @@ void do_fpsimd_exc(unsigned long esr, struct pt_regs *regs) current); } +static void fpsimd_load_kernel_state(struct task_struct *task) +{ + struct cpu_fp_state *last = this_cpu_ptr(&fpsimd_last_state); + + /* + * Elide the load if this CPU holds the most recent kernel mode + * FPSIMD context of the current task. + */ + if (last->st == &task->thread.kernel_fpsimd_state && + task->thread.kernel_fpsimd_cpu == smp_processor_id()) + return; + + fpsimd_load_state(&task->thread.kernel_fpsimd_state); +} + +static void fpsimd_save_kernel_state(struct task_struct *task) +{ + struct cpu_fp_state cpu_fp_state = { + .st = &task->thread.kernel_fpsimd_state, + .to_save = FP_STATE_FPSIMD, + }; + + fpsimd_save_state(&task->thread.kernel_fpsimd_state); + fpsimd_bind_state_to_cpu(&cpu_fp_state); + + task->thread.kernel_fpsimd_cpu = smp_processor_id(); +} + void fpsimd_thread_switch(struct task_struct *next) { bool wrong_task, wrong_cpu; @@ -1507,24 +1509,31 @@ void fpsimd_thread_switch(struct task_struct *next) if (!system_supports_fpsimd()) return; - __get_cpu_fpsimd_context(); + WARN_ON_ONCE(!irqs_disabled()); /* Save unsaved fpsimd state, if any: */ - fpsimd_save(); - - /* - * Fix up TIF_FOREIGN_FPSTATE to correctly describe next's - * state. For kernel threads, FPSIMD registers are never loaded - * and wrong_task and wrong_cpu will always be true. - */ - wrong_task = __this_cpu_read(fpsimd_last_state.st) != - &next->thread.uw.fpsimd_state; - wrong_cpu = next->thread.fpsimd_cpu != smp_processor_id(); + if (test_thread_flag(TIF_KERNEL_FPSTATE)) + fpsimd_save_kernel_state(current); + else + fpsimd_save_user_state(); - update_tsk_thread_flag(next, TIF_FOREIGN_FPSTATE, - wrong_task || wrong_cpu); + if (test_tsk_thread_flag(next, TIF_KERNEL_FPSTATE)) { + fpsimd_load_kernel_state(next); + set_tsk_thread_flag(next, TIF_FOREIGN_FPSTATE); + } else { + /* + * Fix up TIF_FOREIGN_FPSTATE to correctly describe next's + * state. For kernel threads, FPSIMD registers are never + * loaded with user mode FPSIMD state and so wrong_task and + * wrong_cpu will always be true. + */ + wrong_task = __this_cpu_read(fpsimd_last_state.st) != + &next->thread.uw.fpsimd_state; + wrong_cpu = next->thread.fpsimd_cpu != smp_processor_id(); - __put_cpu_fpsimd_context(); + update_tsk_thread_flag(next, TIF_FOREIGN_FPSTATE, + wrong_task || wrong_cpu); + } } static void fpsimd_flush_thread_vl(enum vec_type type) @@ -1614,7 +1623,7 @@ void fpsimd_preserve_current_state(void) return; get_cpu_fpsimd_context(); - fpsimd_save(); + fpsimd_save_user_state(); put_cpu_fpsimd_context(); } @@ -1826,13 +1835,15 @@ static void fpsimd_flush_cpu_state(void) */ void fpsimd_save_and_flush_cpu_state(void) { + unsigned long flags; + if (!system_supports_fpsimd()) return; WARN_ON(preemptible()); - __get_cpu_fpsimd_context(); - fpsimd_save(); + local_irq_save(flags); + fpsimd_save_user_state(); fpsimd_flush_cpu_state(); - __put_cpu_fpsimd_context(); + local_irq_restore(flags); } #ifdef CONFIG_KERNEL_MODE_NEON @@ -1864,10 +1875,37 @@ void kernel_neon_begin(void) get_cpu_fpsimd_context(); /* Save unsaved fpsimd state, if any: */ - fpsimd_save(); + if (test_thread_flag(TIF_KERNEL_FPSTATE)) { + BUG_ON(IS_ENABLED(CONFIG_PREEMPT_RT) || !in_serving_softirq()); + fpsimd_save_kernel_state(current); + } else { + fpsimd_save_user_state(); + + /* + * Set the thread flag so that the kernel mode FPSIMD state + * will be context switched along with the rest of the task + * state. + * + * On non-PREEMPT_RT, softirqs may interrupt task level kernel + * mode FPSIMD, but the task will not be preemptible so setting + * TIF_KERNEL_FPSTATE for those would be both wrong (as it + * would mark the task context FPSIMD state as requiring a + * context switch) and unnecessary. + * + * On PREEMPT_RT, softirqs are serviced from a separate thread, + * which is scheduled as usual, and this guarantees that these + * softirqs are not interrupting use of the FPSIMD in kernel + * mode in task context. So in this case, setting the flag here + * is always appropriate. + */ + if (IS_ENABLED(CONFIG_PREEMPT_RT) || !in_serving_softirq()) + set_thread_flag(TIF_KERNEL_FPSTATE); + } /* Invalidate any task state remaining in the fpsimd regs: */ fpsimd_flush_cpu_state(); + + put_cpu_fpsimd_context(); } EXPORT_SYMBOL_GPL(kernel_neon_begin); @@ -1885,7 +1923,16 @@ void kernel_neon_end(void) if (!system_supports_fpsimd()) return; - put_cpu_fpsimd_context(); + /* + * If we are returning from a nested use of kernel mode FPSIMD, restore + * the task context kernel mode FPSIMD state. This can only happen when + * running in softirq context on non-PREEMPT_RT. + */ + if (!IS_ENABLED(CONFIG_PREEMPT_RT) && in_serving_softirq() && + test_thread_flag(TIF_KERNEL_FPSTATE)) + fpsimd_load_kernel_state(current); + else + clear_thread_flag(TIF_KERNEL_FPSTATE); } EXPORT_SYMBOL_GPL(kernel_neon_end); diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S index 7b236994f0e150..cab7f91949d8f5 100644 --- a/arch/arm64/kernel/head.S +++ b/arch/arm64/kernel/head.S @@ -482,7 +482,7 @@ SYM_FUNC_START_LOCAL(__primary_switched) str_l x21, __fdt_pointer, x5 // Save FDT pointer - ldr_l x4, kimage_vaddr // Save the offset between + adrp x4, _text // Save the offset between sub x4, x4, x0 // the kernel virtual and str_l x4, kimage_voffset, x5 // physical mappings diff --git a/arch/arm64/kernel/idreg-override.c b/arch/arm64/kernel/idreg-override.c index 3addc09f874615..e30fd9e32ef3a1 100644 --- a/arch/arm64/kernel/idreg-override.c +++ b/arch/arm64/kernel/idreg-override.c @@ -21,14 +21,25 @@ static u64 __boot_status __initdata; +// temporary __prel64 related definitions +// to be removed when this code is moved under pi/ + +#define __prel64_initconst __initconst + +#define PREL64(type, name) union { type *name; } + +#define prel64_pointer(__d) (__d) + +typedef bool filter_t(u64 val); + struct ftr_set_desc { char name[FTR_DESC_NAME_LEN]; - struct arm64_ftr_override *override; + PREL64(struct arm64_ftr_override, override); struct { char name[FTR_DESC_FIELD_LEN]; u8 shift; u8 width; - bool (*filter)(u64 val); + PREL64(filter_t, filter); } fields[]; }; @@ -46,7 +57,7 @@ static bool __init mmfr1_vh_filter(u64 val) val == 0); } -static const struct ftr_set_desc mmfr1 __initconst = { +static const struct ftr_set_desc mmfr1 __prel64_initconst = { .name = "id_aa64mmfr1", .override = &id_aa64mmfr1_override, .fields = { @@ -70,7 +81,7 @@ static bool __init pfr0_sve_filter(u64 val) return true; } -static const struct ftr_set_desc pfr0 __initconst = { +static const struct ftr_set_desc pfr0 __prel64_initconst = { .name = "id_aa64pfr0", .override = &id_aa64pfr0_override, .fields = { @@ -94,7 +105,7 @@ static bool __init pfr1_sme_filter(u64 val) return true; } -static const struct ftr_set_desc pfr1 __initconst = { +static const struct ftr_set_desc pfr1 __prel64_initconst = { .name = "id_aa64pfr1", .override = &id_aa64pfr1_override, .fields = { @@ -105,7 +116,7 @@ static const struct ftr_set_desc pfr1 __initconst = { }, }; -static const struct ftr_set_desc isar1 __initconst = { +static const struct ftr_set_desc isar1 __prel64_initconst = { .name = "id_aa64isar1", .override = &id_aa64isar1_override, .fields = { @@ -117,7 +128,7 @@ static const struct ftr_set_desc isar1 __initconst = { }, }; -static const struct ftr_set_desc isar2 __initconst = { +static const struct ftr_set_desc isar2 __prel64_initconst = { .name = "id_aa64isar2", .override = &id_aa64isar2_override, .fields = { @@ -128,7 +139,7 @@ static const struct ftr_set_desc isar2 __initconst = { }, }; -static const struct ftr_set_desc smfr0 __initconst = { +static const struct ftr_set_desc smfr0 __prel64_initconst = { .name = "id_aa64smfr0", .override = &id_aa64smfr0_override, .fields = { @@ -149,7 +160,7 @@ static bool __init hvhe_filter(u64 val) ID_AA64MMFR1_EL1_VH_SHIFT)); } -static const struct ftr_set_desc sw_features __initconst = { +static const struct ftr_set_desc sw_features __prel64_initconst = { .name = "arm64_sw", .override = &arm64_sw_feature_override, .fields = { @@ -159,22 +170,23 @@ static const struct ftr_set_desc sw_features __initconst = { }, }; -static const struct ftr_set_desc * const regs[] __initconst = { - &mmfr1, - &pfr0, - &pfr1, - &isar1, - &isar2, - &smfr0, - &sw_features, +static const +PREL64(const struct ftr_set_desc, reg) regs[] __prel64_initconst = { + { &mmfr1 }, + { &pfr0 }, + { &pfr1 }, + { &isar1 }, + { &isar2 }, + { &smfr0 }, + { &sw_features }, }; static const struct { char alias[FTR_ALIAS_NAME_LEN]; char feature[FTR_ALIAS_OPTION_LEN]; } aliases[] __initconst = { - { "kvm-arm.mode=nvhe", "id_aa64mmfr1.vh=0" }, - { "kvm-arm.mode=protected", "id_aa64mmfr1.vh=0" }, + { "kvm_arm.mode=nvhe", "id_aa64mmfr1.vh=0" }, + { "kvm_arm.mode=protected", "id_aa64mmfr1.vh=0" }, { "arm64.nosve", "id_aa64pfr0.sve=0" }, { "arm64.nosme", "id_aa64pfr1.sme=0" }, { "arm64.nobti", "id_aa64pfr1.bt=0" }, @@ -187,45 +199,61 @@ static const struct { { "nokaslr", "arm64_sw.nokaslr=1" }, }; -static int __init parse_nokaslr(char *unused) +static int __init parse_hexdigit(const char *p, u64 *v) { - /* nokaslr param handling is done by early cpufeature code */ + // skip "0x" if it comes next + if (p[0] == '0' && tolower(p[1]) == 'x') + p += 2; + + // check whether the RHS is a single hex digit + if (!isxdigit(p[0]) || (p[1] && !isspace(p[1]))) + return -EINVAL; + + *v = tolower(*p) - (isdigit(*p) ? '0' : 'a' - 10); return 0; } -early_param("nokaslr", parse_nokaslr); -static int __init find_field(const char *cmdline, +static int __init find_field(const char *cmdline, char *opt, int len, const struct ftr_set_desc *reg, int f, u64 *v) { - char opt[FTR_DESC_NAME_LEN + FTR_DESC_FIELD_LEN + 2]; - int len; + int flen = strlen(reg->fields[f].name); - len = snprintf(opt, ARRAY_SIZE(opt), "%s.%s=", - reg->name, reg->fields[f].name); + // append '=' to obtain '.=' + memcpy(opt + len, reg->fields[f].name, flen); + len += flen; + opt[len++] = '='; - if (!parameqn(cmdline, opt, len)) + if (memcmp(cmdline, opt, len)) return -1; - return kstrtou64(cmdline + len, 0, v); + return parse_hexdigit(cmdline + len, v); } static void __init match_options(const char *cmdline) { + char opt[FTR_DESC_NAME_LEN + FTR_DESC_FIELD_LEN + 2]; int i; for (i = 0; i < ARRAY_SIZE(regs); i++) { + const struct ftr_set_desc *reg = prel64_pointer(regs[i].reg); + struct arm64_ftr_override *override; + int len = strlen(reg->name); int f; - if (!regs[i]->override) - continue; + override = prel64_pointer(reg->override); - for (f = 0; strlen(regs[i]->fields[f].name); f++) { - u64 shift = regs[i]->fields[f].shift; - u64 width = regs[i]->fields[f].width ?: 4; + // set opt[] to '.' + memcpy(opt, reg->name, len); + opt[len++] = '.'; + + for (f = 0; reg->fields[f].name[0] != '\0'; f++) { + u64 shift = reg->fields[f].shift; + u64 width = reg->fields[f].width ?: 4; u64 mask = GENMASK_ULL(shift + width - 1, shift); + bool (*filter)(u64 val); u64 v; - if (find_field(cmdline, regs[i], f, &v)) + if (find_field(cmdline, opt, len, reg, f, &v)) continue; /* @@ -233,16 +261,16 @@ static void __init match_options(const char *cmdline) * it by setting the value to the all-ones while * clearing the mask... Yes, this is fragile. */ - if (regs[i]->fields[f].filter && - !regs[i]->fields[f].filter(v)) { - regs[i]->override->val |= mask; - regs[i]->override->mask &= ~mask; + filter = prel64_pointer(reg->fields[f].filter); + if (filter && !filter(v)) { + override->val |= mask; + override->mask &= ~mask; continue; } - regs[i]->override->val &= ~mask; - regs[i]->override->val |= (v << shift) & mask; - regs[i]->override->mask |= mask; + override->val &= ~mask; + override->val |= (v << shift) & mask; + override->mask |= mask; return; } @@ -258,23 +286,29 @@ static __init void __parse_cmdline(const char *cmdline, bool parse_aliases) cmdline = skip_spaces(cmdline); - for (len = 0; cmdline[len] && !isspace(cmdline[len]); len++); - if (!len) + /* terminate on "--" appearing on the command line by itself */ + if (cmdline[0] == '-' && cmdline[1] == '-' && isspace(cmdline[2])) return; - len = min(len, ARRAY_SIZE(buf) - 1); - memcpy(buf, cmdline, len); - buf[len] = '\0'; - - if (strcmp(buf, "--") == 0) + for (len = 0; cmdline[len] && !isspace(cmdline[len]); len++) { + if (len >= sizeof(buf) - 1) + break; + if (cmdline[len] == '-') + buf[len] = '_'; + else + buf[len] = cmdline[len]; + } + if (!len) return; + buf[len] = 0; + cmdline += len; match_options(buf); for (i = 0; parse_aliases && i < ARRAY_SIZE(aliases); i++) - if (parameq(buf, aliases[i].alias)) + if (!memcmp(buf, aliases[i].alias, len + 1)) __parse_cmdline(aliases[i].feature, false); } while (1); } @@ -316,13 +350,16 @@ void init_feature_override(u64 boot_status); asmlinkage void __init init_feature_override(u64 boot_status) { + struct arm64_ftr_override *override; + const struct ftr_set_desc *reg; int i; for (i = 0; i < ARRAY_SIZE(regs); i++) { - if (regs[i]->override) { - regs[i]->override->val = 0; - regs[i]->override->mask = 0; - } + reg = prel64_pointer(regs[i].reg); + override = prel64_pointer(reg->override); + + override->val = 0; + override->mask = 0; } __boot_status = boot_status; @@ -330,9 +367,9 @@ asmlinkage void __init init_feature_override(u64 boot_status) parse_cmdline(); for (i = 0; i < ARRAY_SIZE(regs); i++) { - if (regs[i]->override) - dcache_clean_inval_poc((unsigned long)regs[i]->override, - (unsigned long)regs[i]->override + - sizeof(*regs[i]->override)); + reg = prel64_pointer(regs[i].reg); + override = prel64_pointer(reg->override); + dcache_clean_inval_poc((unsigned long)override, + (unsigned long)(override + 1)); } } diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c index 6ad5c6ef532962..85087e2df56498 100644 --- a/arch/arm64/kernel/irq.c +++ b/arch/arm64/kernel/irq.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -47,17 +48,17 @@ static void init_irq_scs(void) for_each_possible_cpu(cpu) per_cpu(irq_shadow_call_stack_ptr, cpu) = - scs_alloc(cpu_to_node(cpu)); + scs_alloc(early_cpu_to_node(cpu)); } #ifdef CONFIG_VMAP_STACK -static void init_irq_stacks(void) +static void __init init_irq_stacks(void) { int cpu; unsigned long *p; for_each_possible_cpu(cpu) { - p = arch_alloc_vmap_stack(IRQ_STACK_SIZE, cpu_to_node(cpu)); + p = arch_alloc_vmap_stack(IRQ_STACK_SIZE, early_cpu_to_node(cpu)); per_cpu(irq_stack_ptr, cpu) = p; } } diff --git a/arch/arm64/kernel/kaslr.c b/arch/arm64/kernel/kaslr.c index 94a269cd1f07a0..12c7f3c8ba764f 100644 --- a/arch/arm64/kernel/kaslr.c +++ b/arch/arm64/kernel/kaslr.c @@ -36,3 +36,10 @@ void __init kaslr_init(void) pr_info("KASLR enabled\n"); __kaslr_is_enabled = true; } + +static int __init parse_nokaslr(char *unused) +{ + /* nokaslr param handling is done by early cpufeature code */ + return 0; +} +early_param("nokaslr", parse_nokaslr); diff --git a/arch/arm64/kernel/kexec_image.c b/arch/arm64/kernel/kexec_image.c index 636be671515575..532d72ea42ee8e 100644 --- a/arch/arm64/kernel/kexec_image.c +++ b/arch/arm64/kernel/kexec_image.c @@ -122,9 +122,9 @@ static void *image_load(struct kimage *image, kernel_segment->memsz -= text_offset; image->start = kernel_segment->mem; - pr_debug("Loaded kernel at 0x%lx bufsz=0x%lx memsz=0x%lx\n", - kernel_segment->mem, kbuf.bufsz, - kernel_segment->memsz); + kexec_dprintk("Loaded kernel at 0x%lx bufsz=0x%lx memsz=0x%lx\n", + kernel_segment->mem, kbuf.bufsz, + kernel_segment->memsz); return NULL; } diff --git a/arch/arm64/kernel/machine_kexec.c b/arch/arm64/kernel/machine_kexec.c index 078910db77a41b..b38aae5b488d07 100644 --- a/arch/arm64/kernel/machine_kexec.c +++ b/arch/arm64/kernel/machine_kexec.c @@ -32,26 +32,12 @@ static void _kexec_image_info(const char *func, int line, const struct kimage *kimage) { - unsigned long i; - - pr_debug("%s:%d:\n", func, line); - pr_debug(" kexec kimage info:\n"); - pr_debug(" type: %d\n", kimage->type); - pr_debug(" start: %lx\n", kimage->start); - pr_debug(" head: %lx\n", kimage->head); - pr_debug(" nr_segments: %lu\n", kimage->nr_segments); - pr_debug(" dtb_mem: %pa\n", &kimage->arch.dtb_mem); - pr_debug(" kern_reloc: %pa\n", &kimage->arch.kern_reloc); - pr_debug(" el2_vectors: %pa\n", &kimage->arch.el2_vectors); - - for (i = 0; i < kimage->nr_segments; i++) { - pr_debug(" segment[%lu]: %016lx - %016lx, 0x%lx bytes, %lu pages\n", - i, - kimage->segment[i].mem, - kimage->segment[i].mem + kimage->segment[i].memsz, - kimage->segment[i].memsz, - kimage->segment[i].memsz / PAGE_SIZE); - } + kexec_dprintk("%s:%d:\n", func, line); + kexec_dprintk(" kexec kimage info:\n"); + kexec_dprintk(" type: %d\n", kimage->type); + kexec_dprintk(" head: %lx\n", kimage->head); + kexec_dprintk(" kern_reloc: %pa\n", &kimage->arch.kern_reloc); + kexec_dprintk(" el2_vectors: %pa\n", &kimage->arch.el2_vectors); } void machine_kexec_cleanup(struct kimage *kimage) diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c index a11a6e14ba89f6..0e017358f4ba64 100644 --- a/arch/arm64/kernel/machine_kexec_file.c +++ b/arch/arm64/kernel/machine_kexec_file.c @@ -127,8 +127,8 @@ int load_other_segments(struct kimage *image, image->elf_load_addr = kbuf.mem; image->elf_headers_sz = headers_sz; - pr_debug("Loaded elf core header at 0x%lx bufsz=0x%lx memsz=0x%lx\n", - image->elf_load_addr, kbuf.bufsz, kbuf.memsz); + kexec_dprintk("Loaded elf core header at 0x%lx bufsz=0x%lx memsz=0x%lx\n", + image->elf_load_addr, kbuf.bufsz, kbuf.memsz); } /* load initrd */ @@ -148,8 +148,8 @@ int load_other_segments(struct kimage *image, goto out_err; initrd_load_addr = kbuf.mem; - pr_debug("Loaded initrd at 0x%lx bufsz=0x%lx memsz=0x%lx\n", - initrd_load_addr, kbuf.bufsz, kbuf.memsz); + kexec_dprintk("Loaded initrd at 0x%lx bufsz=0x%lx memsz=0x%lx\n", + initrd_load_addr, kbuf.bufsz, kbuf.memsz); } /* load dtb */ @@ -179,8 +179,8 @@ int load_other_segments(struct kimage *image, image->arch.dtb = dtb; image->arch.dtb_mem = kbuf.mem; - pr_debug("Loaded dtb at 0x%lx bufsz=0x%lx memsz=0x%lx\n", - kbuf.mem, kbuf.bufsz, kbuf.memsz); + kexec_dprintk("Loaded dtb at 0x%lx bufsz=0x%lx memsz=0x%lx\n", + kbuf.mem, kbuf.bufsz, kbuf.memsz); return 0; diff --git a/arch/arm64/kernel/pi/Makefile b/arch/arm64/kernel/pi/Makefile index 4c0ea3cd4ea406..c844a0546d7f0e 100644 --- a/arch/arm64/kernel/pi/Makefile +++ b/arch/arm64/kernel/pi/Makefile @@ -3,6 +3,7 @@ KBUILD_CFLAGS := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) -fpie \ -Os -DDISABLE_BRANCH_PROFILING $(DISABLE_STACKLEAK_PLUGIN) \ + $(DISABLE_LATENT_ENTROPY_PLUGIN) \ $(call cc-option,-mbranch-protection=none) \ -I$(srctree)/scripts/dtc/libfdt -fno-stack-protector \ -include $(srctree)/include/linux/hidden.h \ diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index 20d7ef82de90aa..dc6cf0e37194e4 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -1107,12 +1108,13 @@ static int za_set(struct task_struct *target, } } - /* Allocate/reinit ZA storage */ - sme_alloc(target, true); - if (!target->thread.sme_state) { - ret = -ENOMEM; - goto out; - } + /* + * Only flush the storage if PSTATE.ZA was not already set, + * otherwise preserve any existing data. + */ + sme_alloc(target, !thread_za_enabled(&target->thread)); + if (!target->thread.sme_state) + return -ENOMEM; /* If there is no data then disable ZA */ if (!count) { diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 417a8a86b2db59..42c690bb2d608c 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -402,19 +402,10 @@ static inline bool cpu_can_disable(unsigned int cpu) return false; } -static int __init topology_init(void) +bool arch_cpu_is_hotpluggable(int num) { - int i; - - for_each_possible_cpu(i) { - struct cpu *cpu = &per_cpu(cpu_data.cpu, i); - cpu->hotpluggable = cpu_can_disable(i); - register_cpu(cpu, i); - } - - return 0; + return cpu_can_disable(num); } -subsys_initcall(topology_init); static void dump_kernel_offset(void) { diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index defbab84e9e5c7..4ced34f62dab59 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -439,9 +439,8 @@ static void __init hyp_mode_check(void) void __init smp_cpus_done(unsigned int max_cpus) { pr_info("SMP: Total of %d processors activated.\n", num_online_cpus()); - setup_system_features(); hyp_mode_check(); - apply_alternatives_all(); + setup_system_features(); setup_user_features(); mark_linear_text_alias_ro(); } @@ -454,14 +453,9 @@ void __init smp_prepare_boot_cpu(void) * freed shortly, so we must move over to the runtime per-cpu area. */ set_my_cpu_offset(per_cpu_offset(smp_processor_id())); - cpuinfo_store_boot_cpu(); - /* - * We now know enough about the boot CPU to apply the - * alternatives that cannot wait until interrupt handling - * and/or scheduling is enabled. - */ - apply_boot_alternatives(); + cpuinfo_store_boot_cpu(); + setup_boot_cpu_features(); /* Conditionally switch to GIC PMR for interrupt masking */ if (system_uses_irq_prio_masking()) diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index 17f66a74c745c8..7f88028a00c02c 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -18,6 +19,31 @@ #include #include +/* + * Kernel unwind state + * + * @common: Common unwind state. + * @task: The task being unwound. + * @kr_cur: When KRETPROBES is selected, holds the kretprobe instance + * associated with the most recently encountered replacement lr + * value. + */ +struct kunwind_state { + struct unwind_state common; + struct task_struct *task; +#ifdef CONFIG_KRETPROBES + struct llist_node *kr_cur; +#endif +}; + +static __always_inline void +kunwind_init(struct kunwind_state *state, + struct task_struct *task) +{ + unwind_init_common(&state->common); + state->task = task; +} + /* * Start an unwind from a pt_regs. * @@ -26,13 +52,13 @@ * The regs must be on a stack currently owned by the calling task. */ static __always_inline void -unwind_init_from_regs(struct unwind_state *state, - struct pt_regs *regs) +kunwind_init_from_regs(struct kunwind_state *state, + struct pt_regs *regs) { - unwind_init_common(state, current); + kunwind_init(state, current); - state->fp = regs->regs[29]; - state->pc = regs->pc; + state->common.fp = regs->regs[29]; + state->common.pc = regs->pc; } /* @@ -44,12 +70,12 @@ unwind_init_from_regs(struct unwind_state *state, * The function which invokes this must be noinline. */ static __always_inline void -unwind_init_from_caller(struct unwind_state *state) +kunwind_init_from_caller(struct kunwind_state *state) { - unwind_init_common(state, current); + kunwind_init(state, current); - state->fp = (unsigned long)__builtin_frame_address(1); - state->pc = (unsigned long)__builtin_return_address(0); + state->common.fp = (unsigned long)__builtin_frame_address(1); + state->common.pc = (unsigned long)__builtin_return_address(0); } /* @@ -63,35 +89,38 @@ unwind_init_from_caller(struct unwind_state *state) * call this for the current task. */ static __always_inline void -unwind_init_from_task(struct unwind_state *state, - struct task_struct *task) +kunwind_init_from_task(struct kunwind_state *state, + struct task_struct *task) { - unwind_init_common(state, task); + kunwind_init(state, task); - state->fp = thread_saved_fp(task); - state->pc = thread_saved_pc(task); + state->common.fp = thread_saved_fp(task); + state->common.pc = thread_saved_pc(task); } static __always_inline int -unwind_recover_return_address(struct unwind_state *state) +kunwind_recover_return_address(struct kunwind_state *state) { #ifdef CONFIG_FUNCTION_GRAPH_TRACER if (state->task->ret_stack && - (state->pc == (unsigned long)return_to_handler)) { + (state->common.pc == (unsigned long)return_to_handler)) { unsigned long orig_pc; - orig_pc = ftrace_graph_ret_addr(state->task, NULL, state->pc, - (void *)state->fp); - if (WARN_ON_ONCE(state->pc == orig_pc)) + orig_pc = ftrace_graph_ret_addr(state->task, NULL, + state->common.pc, + (void *)state->common.fp); + if (WARN_ON_ONCE(state->common.pc == orig_pc)) return -EINVAL; - state->pc = orig_pc; + state->common.pc = orig_pc; } #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ #ifdef CONFIG_KRETPROBES - if (is_kretprobe_trampoline(state->pc)) { - state->pc = kretprobe_find_ret_addr(state->task, - (void *)state->fp, - &state->kr_cur); + if (is_kretprobe_trampoline(state->common.pc)) { + unsigned long orig_pc; + orig_pc = kretprobe_find_ret_addr(state->task, + (void *)state->common.fp, + &state->kr_cur); + state->common.pc = orig_pc; } #endif /* CONFIG_KRETPROBES */ @@ -106,38 +135,40 @@ unwind_recover_return_address(struct unwind_state *state) * and the location (but not the fp value) of B. */ static __always_inline int -unwind_next(struct unwind_state *state) +kunwind_next(struct kunwind_state *state) { struct task_struct *tsk = state->task; - unsigned long fp = state->fp; + unsigned long fp = state->common.fp; int err; /* Final frame; nothing to unwind */ if (fp == (unsigned long)task_pt_regs(tsk)->stackframe) return -ENOENT; - err = unwind_next_frame_record(state); + err = unwind_next_frame_record(&state->common); if (err) return err; - state->pc = ptrauth_strip_kernel_insn_pac(state->pc); + state->common.pc = ptrauth_strip_kernel_insn_pac(state->common.pc); - return unwind_recover_return_address(state); + return kunwind_recover_return_address(state); } +typedef bool (*kunwind_consume_fn)(const struct kunwind_state *state, void *cookie); + static __always_inline void -unwind(struct unwind_state *state, stack_trace_consume_fn consume_entry, - void *cookie) +do_kunwind(struct kunwind_state *state, kunwind_consume_fn consume_state, + void *cookie) { - if (unwind_recover_return_address(state)) + if (kunwind_recover_return_address(state)) return; while (1) { int ret; - if (!consume_entry(cookie, state->pc)) + if (!consume_state(state, cookie)) break; - ret = unwind_next(state); + ret = kunwind_next(state); if (ret < 0) break; } @@ -172,9 +203,10 @@ unwind(struct unwind_state *state, stack_trace_consume_fn consume_entry, : stackinfo_get_unknown(); \ }) -noinline noinstr void arch_stack_walk(stack_trace_consume_fn consume_entry, - void *cookie, struct task_struct *task, - struct pt_regs *regs) +static __always_inline void +kunwind_stack_walk(kunwind_consume_fn consume_state, + void *cookie, struct task_struct *task, + struct pt_regs *regs) { struct stack_info stacks[] = { stackinfo_get_task(task), @@ -190,22 +222,48 @@ noinline noinstr void arch_stack_walk(stack_trace_consume_fn consume_entry, STACKINFO_EFI, #endif }; - struct unwind_state state = { - .stacks = stacks, - .nr_stacks = ARRAY_SIZE(stacks), + struct kunwind_state state = { + .common = { + .stacks = stacks, + .nr_stacks = ARRAY_SIZE(stacks), + }, }; if (regs) { if (task != current) return; - unwind_init_from_regs(&state, regs); + kunwind_init_from_regs(&state, regs); } else if (task == current) { - unwind_init_from_caller(&state); + kunwind_init_from_caller(&state); } else { - unwind_init_from_task(&state, task); + kunwind_init_from_task(&state, task); } - unwind(&state, consume_entry, cookie); + do_kunwind(&state, consume_state, cookie); +} + +struct kunwind_consume_entry_data { + stack_trace_consume_fn consume_entry; + void *cookie; +}; + +static bool +arch_kunwind_consume_entry(const struct kunwind_state *state, void *cookie) +{ + struct kunwind_consume_entry_data *data = cookie; + return data->consume_entry(data->cookie, state->common.pc); +} + +noinline noinstr void arch_stack_walk(stack_trace_consume_fn consume_entry, + void *cookie, struct task_struct *task, + struct pt_regs *regs) +{ + struct kunwind_consume_entry_data data = { + .consume_entry = consume_entry, + .cookie = cookie, + }; + + kunwind_stack_walk(arch_kunwind_consume_entry, &data, task, regs); } static bool dump_backtrace_entry(void *arg, unsigned long where) diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c index 817d788cd86669..1a2c72f3e7f80e 100644 --- a/arch/arm64/kernel/topology.c +++ b/arch/arm64/kernel/topology.c @@ -82,7 +82,12 @@ int __init parse_acpi_topology(void) #undef pr_fmt #define pr_fmt(fmt) "AMU: " fmt -static DEFINE_PER_CPU_READ_MOSTLY(unsigned long, arch_max_freq_scale); +/* + * Ensure that amu_scale_freq_tick() will return SCHED_CAPACITY_SCALE until + * the CPU capacity and its associated frequency have been correctly + * initialized. + */ +static DEFINE_PER_CPU_READ_MOSTLY(unsigned long, arch_max_freq_scale) = 1UL << (2 * SCHED_CAPACITY_SHIFT); static DEFINE_PER_CPU(u64, arch_const_cycles_prev); static DEFINE_PER_CPU(u64, arch_core_cycles_prev); static cpumask_var_t amu_fie_cpus; @@ -112,14 +117,14 @@ static inline bool freq_counters_valid(int cpu) return true; } -static int freq_inv_set_max_ratio(int cpu, u64 max_rate, u64 ref_rate) +void freq_inv_set_max_ratio(int cpu, u64 max_rate) { - u64 ratio; + u64 ratio, ref_rate = arch_timer_get_rate(); if (unlikely(!max_rate || !ref_rate)) { - pr_debug("CPU%d: invalid maximum or reference frequency.\n", + WARN_ONCE(1, "CPU%d: invalid maximum or reference frequency.\n", cpu); - return -EINVAL; + return; } /* @@ -139,12 +144,10 @@ static int freq_inv_set_max_ratio(int cpu, u64 max_rate, u64 ref_rate) ratio = div64_u64(ratio, max_rate); if (!ratio) { WARN_ONCE(1, "Reference frequency too low.\n"); - return -EINVAL; + return; } - per_cpu(arch_max_freq_scale, cpu) = (unsigned long)ratio; - - return 0; + WRITE_ONCE(per_cpu(arch_max_freq_scale, cpu), (unsigned long)ratio); } static void amu_scale_freq_tick(void) @@ -195,10 +198,7 @@ static void amu_fie_setup(const struct cpumask *cpus) return; for_each_cpu(cpu, cpus) { - if (!freq_counters_valid(cpu) || - freq_inv_set_max_ratio(cpu, - cpufreq_get_hw_max_freq(cpu) * 1000ULL, - arch_timer_get_rate())) + if (!freq_counters_valid(cpu)) return; } diff --git a/arch/arm64/kernel/vdso32/Makefile b/arch/arm64/kernel/vdso32/Makefile index 1f911a76c5af39..2266fcdff78a07 100644 --- a/arch/arm64/kernel/vdso32/Makefile +++ b/arch/arm64/kernel/vdso32/Makefile @@ -118,7 +118,7 @@ endif VDSO_CFLAGS_REMOVE_vgettimeofday.o = $(CC_FLAGS_FTRACE) -Os # Build rules -targets := $(c-obj-vdso) $(c-obj-vdso-gettimeofday) $(asm-obj-vdso) vdso.so vdso.so.dbg vdso.so.raw +targets := $(c-obj-vdso) $(c-obj-vdso-gettimeofday) $(asm-obj-vdso) vdso.so vdso32.so.dbg vdso.so.raw c-obj-vdso := $(addprefix $(obj)/, $(c-obj-vdso)) c-obj-vdso-gettimeofday := $(addprefix $(obj)/, $(c-obj-vdso-gettimeofday)) asm-obj-vdso := $(addprefix $(obj)/, $(asm-obj-vdso)) @@ -127,15 +127,15 @@ obj-vdso := $(c-obj-vdso) $(c-obj-vdso-gettimeofday) $(asm-obj-vdso) targets += vdso.lds CPPFLAGS_vdso.lds += -P -C -U$(ARCH) -include/generated/vdso32-offsets.h: $(obj)/vdso.so.dbg FORCE +include/generated/vdso32-offsets.h: $(obj)/vdso32.so.dbg FORCE $(call if_changed,vdsosym) # Strip rule for vdso.so $(obj)/vdso.so: OBJCOPYFLAGS := -S -$(obj)/vdso.so: $(obj)/vdso.so.dbg FORCE +$(obj)/vdso.so: $(obj)/vdso32.so.dbg FORCE $(call if_changed,objcopy) -$(obj)/vdso.so.dbg: $(obj)/vdso.so.raw $(obj)/$(munge) FORCE +$(obj)/vdso32.so.dbg: $(obj)/vdso.so.raw $(obj)/$(munge) FORCE $(call if_changed,vdsomunge) # Link rule for the .so file, .lds has to be first diff --git a/arch/arm64/kernel/vdso32/vgettimeofday.c b/arch/arm64/kernel/vdso32/vgettimeofday.c index 5acff29c599154..29b4d8f61e39c9 100644 --- a/arch/arm64/kernel/vdso32/vgettimeofday.c +++ b/arch/arm64/kernel/vdso32/vgettimeofday.c @@ -5,6 +5,8 @@ * Copyright (C) 2018 ARM Limited * */ +#define BUILD_VDSO32_64 +#include int __vdso_clock_gettime(clockid_t clock, struct old_timespec32 *ts) diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig index 83c1e09be42e5b..6c3c8ca73e7fda 100644 --- a/arch/arm64/kvm/Kconfig +++ b/arch/arm64/kvm/Kconfig @@ -21,16 +21,14 @@ if VIRTUALIZATION menuconfig KVM bool "Kernel-based Virtual Machine (KVM) support" depends on HAVE_KVM + select KVM_COMMON select KVM_GENERIC_HARDWARE_ENABLING - select MMU_NOTIFIER - select PREEMPT_NOTIFIERS + select KVM_GENERIC_MMU_NOTIFIER select HAVE_KVM_CPU_RELAX_INTERCEPT select KVM_MMIO select KVM_GENERIC_DIRTYLOG_READ_PROTECT select KVM_XFER_TO_GUEST_WORK select KVM_VFIO - select HAVE_KVM_EVENTFD - select HAVE_KVM_IRQFD select HAVE_KVM_DIRTY_RING_ACQ_REL select NEED_KVM_DIRTY_RING_WITH_BITMAP select HAVE_KVM_MSI @@ -41,7 +39,6 @@ menuconfig KVM select HAVE_KVM_VCPU_RUN_PID_CHANGE select SCHED_INFO select GUEST_PERF_EVENTS if PERF_EVENTS - select INTERVAL_TREE select XARRAY_MULTI help Support hosting virtualized guest machines. diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c index 13ba691b848f7a..9dec8c419bf402 100644 --- a/arch/arm64/kvm/arch_timer.c +++ b/arch/arm64/kvm/arch_timer.c @@ -295,8 +295,7 @@ static u64 wfit_delay_ns(struct kvm_vcpu *vcpu) u64 val = vcpu_get_reg(vcpu, kvm_vcpu_sys_get_rt(vcpu)); struct arch_timer_context *ctx; - ctx = (vcpu_has_nv(vcpu) && is_hyp_ctxt(vcpu)) ? vcpu_hvtimer(vcpu) - : vcpu_vtimer(vcpu); + ctx = is_hyp_ctxt(vcpu) ? vcpu_hvtimer(vcpu) : vcpu_vtimer(vcpu); return kvm_counter_compute_delta(ctx, val); } diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 4796104c447181..a25265aca4324e 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -221,7 +221,6 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) r = vgic_present; break; case KVM_CAP_IOEVENTFD: - case KVM_CAP_DEVICE_CTRL: case KVM_CAP_USER_MEMORY: case KVM_CAP_SYNC_MMU: case KVM_CAP_DESTROY_MEMORY_REGION_WORKS: @@ -669,6 +668,12 @@ int kvm_arch_vcpu_run_pid_change(struct kvm_vcpu *vcpu) return ret; } + if (vcpu_has_nv(vcpu)) { + ret = kvm_init_nv_sysregs(vcpu->kvm); + if (ret) + return ret; + } + ret = kvm_timer_enable(vcpu); if (ret) return ret; @@ -1837,6 +1842,7 @@ static int kvm_init_vector_slots(void) static void __init cpu_prepare_hyp_mode(int cpu, u32 hyp_va_bits) { struct kvm_nvhe_init_params *params = per_cpu_ptr_nvhe_sym(kvm_init_params, cpu); + u64 mmfr0 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1); unsigned long tcr; /* @@ -1859,6 +1865,10 @@ static void __init cpu_prepare_hyp_mode(int cpu, u32 hyp_va_bits) } tcr &= ~TCR_T0SZ_MASK; tcr |= TCR_T0SZ(hyp_va_bits); + tcr &= ~TCR_EL2_PS_MASK; + tcr |= FIELD_PREP(TCR_EL2_PS_MASK, kvm_get_parange(mmfr0)); + if (kvm_lpa2_is_enabled()) + tcr |= TCR_EL2_DS; params->tcr_el2 = tcr; params->pgd_pa = kvm_mmu_get_httbr(); diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c index 06185216a297dd..431fd429932dfa 100644 --- a/arch/arm64/kvm/emulate-nested.c +++ b/arch/arm64/kvm/emulate-nested.c @@ -1012,6 +1012,7 @@ enum fgt_group_id { HDFGRTR_GROUP, HDFGWTR_GROUP, HFGITR_GROUP, + HAFGRTR_GROUP, /* Must be last */ __NR_FGT_GROUP_IDS__ @@ -1042,10 +1043,20 @@ enum fg_filter_id { static const struct encoding_to_trap_config encoding_to_fgt[] __initconst = { /* HFGRTR_EL2, HFGWTR_EL2 */ + SR_FGT(SYS_AMAIR2_EL1, HFGxTR, nAMAIR2_EL1, 0), + SR_FGT(SYS_MAIR2_EL1, HFGxTR, nMAIR2_EL1, 0), + SR_FGT(SYS_S2POR_EL1, HFGxTR, nS2POR_EL1, 0), + SR_FGT(SYS_POR_EL1, HFGxTR, nPOR_EL1, 0), + SR_FGT(SYS_POR_EL0, HFGxTR, nPOR_EL0, 0), SR_FGT(SYS_PIR_EL1, HFGxTR, nPIR_EL1, 0), SR_FGT(SYS_PIRE0_EL1, HFGxTR, nPIRE0_EL1, 0), + SR_FGT(SYS_RCWMASK_EL1, HFGxTR, nRCWMASK_EL1, 0), SR_FGT(SYS_TPIDR2_EL0, HFGxTR, nTPIDR2_EL0, 0), SR_FGT(SYS_SMPRI_EL1, HFGxTR, nSMPRI_EL1, 0), + SR_FGT(SYS_GCSCR_EL1, HFGxTR, nGCS_EL1, 0), + SR_FGT(SYS_GCSPR_EL1, HFGxTR, nGCS_EL1, 0), + SR_FGT(SYS_GCSCRE0_EL1, HFGxTR, nGCS_EL0, 0), + SR_FGT(SYS_GCSPR_EL0, HFGxTR, nGCS_EL0, 0), SR_FGT(SYS_ACCDATA_EL1, HFGxTR, nACCDATA_EL1, 0), SR_FGT(SYS_ERXADDR_EL1, HFGxTR, ERXADDR_EL1, 1), SR_FGT(SYS_ERXPFGCDN_EL1, HFGxTR, ERXPFGCDN_EL1, 1), @@ -1107,6 +1118,11 @@ static const struct encoding_to_trap_config encoding_to_fgt[] __initconst = { SR_FGT(SYS_AFSR1_EL1, HFGxTR, AFSR1_EL1, 1), SR_FGT(SYS_AFSR0_EL1, HFGxTR, AFSR0_EL1, 1), /* HFGITR_EL2 */ + SR_FGT(OP_AT_S1E1A, HFGITR, ATS1E1A, 1), + SR_FGT(OP_COSP_RCTX, HFGITR, COSPRCTX, 1), + SR_FGT(OP_GCSPUSHX, HFGITR, nGCSEPP, 0), + SR_FGT(OP_GCSPOPX, HFGITR, nGCSEPP, 0), + SR_FGT(OP_GCSPUSHM, HFGITR, nGCSPUSHM_EL1, 0), SR_FGT(OP_BRB_IALL, HFGITR, nBRBIALL, 0), SR_FGT(OP_BRB_INJ, HFGITR, nBRBINJ, 0), SR_FGT(SYS_DC_CVAC, HFGITR, DCCVAC, 1), @@ -1674,6 +1690,49 @@ static const struct encoding_to_trap_config encoding_to_fgt[] __initconst = { SR_FGT(SYS_PMCR_EL0, HDFGWTR, PMCR_EL0, 1), SR_FGT(SYS_PMSWINC_EL0, HDFGWTR, PMSWINC_EL0, 1), SR_FGT(SYS_OSLAR_EL1, HDFGWTR, OSLAR_EL1, 1), + /* + * HAFGRTR_EL2 + */ + SR_FGT(SYS_AMEVTYPER1_EL0(15), HAFGRTR, AMEVTYPER115_EL0, 1), + SR_FGT(SYS_AMEVTYPER1_EL0(14), HAFGRTR, AMEVTYPER114_EL0, 1), + SR_FGT(SYS_AMEVTYPER1_EL0(13), HAFGRTR, AMEVTYPER113_EL0, 1), + SR_FGT(SYS_AMEVTYPER1_EL0(12), HAFGRTR, AMEVTYPER112_EL0, 1), + SR_FGT(SYS_AMEVTYPER1_EL0(11), HAFGRTR, AMEVTYPER111_EL0, 1), + SR_FGT(SYS_AMEVTYPER1_EL0(10), HAFGRTR, AMEVTYPER110_EL0, 1), + SR_FGT(SYS_AMEVTYPER1_EL0(9), HAFGRTR, AMEVTYPER19_EL0, 1), + SR_FGT(SYS_AMEVTYPER1_EL0(8), HAFGRTR, AMEVTYPER18_EL0, 1), + SR_FGT(SYS_AMEVTYPER1_EL0(7), HAFGRTR, AMEVTYPER17_EL0, 1), + SR_FGT(SYS_AMEVTYPER1_EL0(6), HAFGRTR, AMEVTYPER16_EL0, 1), + SR_FGT(SYS_AMEVTYPER1_EL0(5), HAFGRTR, AMEVTYPER15_EL0, 1), + SR_FGT(SYS_AMEVTYPER1_EL0(4), HAFGRTR, AMEVTYPER14_EL0, 1), + SR_FGT(SYS_AMEVTYPER1_EL0(3), HAFGRTR, AMEVTYPER13_EL0, 1), + SR_FGT(SYS_AMEVTYPER1_EL0(2), HAFGRTR, AMEVTYPER12_EL0, 1), + SR_FGT(SYS_AMEVTYPER1_EL0(1), HAFGRTR, AMEVTYPER11_EL0, 1), + SR_FGT(SYS_AMEVTYPER1_EL0(0), HAFGRTR, AMEVTYPER10_EL0, 1), + SR_FGT(SYS_AMEVCNTR1_EL0(15), HAFGRTR, AMEVCNTR115_EL0, 1), + SR_FGT(SYS_AMEVCNTR1_EL0(14), HAFGRTR, AMEVCNTR114_EL0, 1), + SR_FGT(SYS_AMEVCNTR1_EL0(13), HAFGRTR, AMEVCNTR113_EL0, 1), + SR_FGT(SYS_AMEVCNTR1_EL0(12), HAFGRTR, AMEVCNTR112_EL0, 1), + SR_FGT(SYS_AMEVCNTR1_EL0(11), HAFGRTR, AMEVCNTR111_EL0, 1), + SR_FGT(SYS_AMEVCNTR1_EL0(10), HAFGRTR, AMEVCNTR110_EL0, 1), + SR_FGT(SYS_AMEVCNTR1_EL0(9), HAFGRTR, AMEVCNTR19_EL0, 1), + SR_FGT(SYS_AMEVCNTR1_EL0(8), HAFGRTR, AMEVCNTR18_EL0, 1), + SR_FGT(SYS_AMEVCNTR1_EL0(7), HAFGRTR, AMEVCNTR17_EL0, 1), + SR_FGT(SYS_AMEVCNTR1_EL0(6), HAFGRTR, AMEVCNTR16_EL0, 1), + SR_FGT(SYS_AMEVCNTR1_EL0(5), HAFGRTR, AMEVCNTR15_EL0, 1), + SR_FGT(SYS_AMEVCNTR1_EL0(4), HAFGRTR, AMEVCNTR14_EL0, 1), + SR_FGT(SYS_AMEVCNTR1_EL0(3), HAFGRTR, AMEVCNTR13_EL0, 1), + SR_FGT(SYS_AMEVCNTR1_EL0(2), HAFGRTR, AMEVCNTR12_EL0, 1), + SR_FGT(SYS_AMEVCNTR1_EL0(1), HAFGRTR, AMEVCNTR11_EL0, 1), + SR_FGT(SYS_AMEVCNTR1_EL0(0), HAFGRTR, AMEVCNTR10_EL0, 1), + SR_FGT(SYS_AMCNTENCLR1_EL0, HAFGRTR, AMCNTEN1, 1), + SR_FGT(SYS_AMCNTENSET1_EL0, HAFGRTR, AMCNTEN1, 1), + SR_FGT(SYS_AMCNTENCLR0_EL0, HAFGRTR, AMCNTEN0, 1), + SR_FGT(SYS_AMCNTENSET0_EL0, HAFGRTR, AMCNTEN0, 1), + SR_FGT(SYS_AMEVCNTR0_EL0(3), HAFGRTR, AMEVCNTR03_EL0, 1), + SR_FGT(SYS_AMEVCNTR0_EL0(2), HAFGRTR, AMEVCNTR02_EL0, 1), + SR_FGT(SYS_AMEVCNTR0_EL0(1), HAFGRTR, AMEVCNTR01_EL0, 1), + SR_FGT(SYS_AMEVCNTR0_EL0(0), HAFGRTR, AMEVCNTR00_EL0, 1), }; static union trap_config get_trap_config(u32 sysreg) @@ -1894,6 +1953,10 @@ bool __check_nv_sr_forward(struct kvm_vcpu *vcpu) val = sanitised_sys_reg(vcpu, HDFGWTR_EL2); break; + case HAFGRTR_GROUP: + val = sanitised_sys_reg(vcpu, HAFGRTR_EL2); + break; + case HFGITR_GROUP: val = sanitised_sys_reg(vcpu, HFGITR_EL2); switch (tc.fgf) { diff --git a/arch/arm64/kvm/hyp/include/hyp/fault.h b/arch/arm64/kvm/hyp/include/hyp/fault.h index 9ddcfe2c3e574f..9e13c1bc2ad541 100644 --- a/arch/arm64/kvm/hyp/include/hyp/fault.h +++ b/arch/arm64/kvm/hyp/include/hyp/fault.h @@ -60,7 +60,7 @@ static inline bool __get_fault_info(u64 esr, struct kvm_vcpu_fault_info *fault) */ if (!(esr & ESR_ELx_S1PTW) && (cpus_have_final_cap(ARM64_WORKAROUND_834220) || - (esr & ESR_ELx_FSC_TYPE) == ESR_ELx_FSC_PERM)) { + esr_fsc_is_permission_fault(esr))) { if (!__translate_far_to_hpfar(far, &hpfar)) return false; } else { diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h index f99d8af0b9afb0..a038320cdb0890 100644 --- a/arch/arm64/kvm/hyp/include/hyp/switch.h +++ b/arch/arm64/kvm/hyp/include/hyp/switch.h @@ -79,6 +79,45 @@ static inline void __activate_traps_fpsimd32(struct kvm_vcpu *vcpu) clr |= ~hfg & __ ## reg ## _nMASK; \ } while(0) +#define update_fgt_traps_cs(vcpu, reg, clr, set) \ + do { \ + struct kvm_cpu_context *hctxt = \ + &this_cpu_ptr(&kvm_host_data)->host_ctxt; \ + u64 c = 0, s = 0; \ + \ + ctxt_sys_reg(hctxt, reg) = read_sysreg_s(SYS_ ## reg); \ + compute_clr_set(vcpu, reg, c, s); \ + s |= set; \ + c |= clr; \ + if (c || s) { \ + u64 val = __ ## reg ## _nMASK; \ + val |= s; \ + val &= ~c; \ + write_sysreg_s(val, SYS_ ## reg); \ + } \ + } while(0) + +#define update_fgt_traps(vcpu, reg) \ + update_fgt_traps_cs(vcpu, reg, 0, 0) + +/* + * Validate the fine grain trap masks. + * Check that the masks do not overlap and that all bits are accounted for. + */ +#define CHECK_FGT_MASKS(reg) \ + do { \ + BUILD_BUG_ON((__ ## reg ## _MASK) & (__ ## reg ## _nMASK)); \ + BUILD_BUG_ON(~((__ ## reg ## _RES0) ^ (__ ## reg ## _MASK) ^ \ + (__ ## reg ## _nMASK))); \ + } while(0) + +static inline bool cpu_has_amu(void) +{ + u64 pfr0 = read_sysreg_s(SYS_ID_AA64PFR0_EL1); + + return cpuid_feature_extract_unsigned_field(pfr0, + ID_AA64PFR0_EL1_AMU_SHIFT); +} static inline void __activate_traps_hfgxtr(struct kvm_vcpu *vcpu) { @@ -86,6 +125,14 @@ static inline void __activate_traps_hfgxtr(struct kvm_vcpu *vcpu) u64 r_clr = 0, w_clr = 0, r_set = 0, w_set = 0, tmp; u64 r_val, w_val; + CHECK_FGT_MASKS(HFGRTR_EL2); + CHECK_FGT_MASKS(HFGWTR_EL2); + CHECK_FGT_MASKS(HFGITR_EL2); + CHECK_FGT_MASKS(HDFGRTR_EL2); + CHECK_FGT_MASKS(HDFGWTR_EL2); + CHECK_FGT_MASKS(HAFGRTR_EL2); + CHECK_FGT_MASKS(HCRX_EL2); + if (!cpus_have_final_cap(ARM64_HAS_FGT)) return; @@ -110,12 +157,15 @@ static inline void __activate_traps_hfgxtr(struct kvm_vcpu *vcpu) compute_clr_set(vcpu, HFGWTR_EL2, w_clr, w_set); } - /* The default is not to trap anything but ACCDATA_EL1 */ - r_val = __HFGRTR_EL2_nMASK & ~HFGxTR_EL2_nACCDATA_EL1; + /* The default to trap everything not handled or supported in KVM. */ + tmp = HFGxTR_EL2_nAMAIR2_EL1 | HFGxTR_EL2_nMAIR2_EL1 | HFGxTR_EL2_nS2POR_EL1 | + HFGxTR_EL2_nPOR_EL1 | HFGxTR_EL2_nPOR_EL0 | HFGxTR_EL2_nACCDATA_EL1; + + r_val = __HFGRTR_EL2_nMASK & ~tmp; r_val |= r_set; r_val &= ~r_clr; - w_val = __HFGWTR_EL2_nMASK & ~HFGxTR_EL2_nACCDATA_EL1; + w_val = __HFGWTR_EL2_nMASK & ~tmp; w_val |= w_set; w_val &= ~w_clr; @@ -125,34 +175,12 @@ static inline void __activate_traps_hfgxtr(struct kvm_vcpu *vcpu) if (!vcpu_has_nv(vcpu) || is_hyp_ctxt(vcpu)) return; - ctxt_sys_reg(hctxt, HFGITR_EL2) = read_sysreg_s(SYS_HFGITR_EL2); + update_fgt_traps(vcpu, HFGITR_EL2); + update_fgt_traps(vcpu, HDFGRTR_EL2); + update_fgt_traps(vcpu, HDFGWTR_EL2); - r_set = r_clr = 0; - compute_clr_set(vcpu, HFGITR_EL2, r_clr, r_set); - r_val = __HFGITR_EL2_nMASK; - r_val |= r_set; - r_val &= ~r_clr; - - write_sysreg_s(r_val, SYS_HFGITR_EL2); - - ctxt_sys_reg(hctxt, HDFGRTR_EL2) = read_sysreg_s(SYS_HDFGRTR_EL2); - ctxt_sys_reg(hctxt, HDFGWTR_EL2) = read_sysreg_s(SYS_HDFGWTR_EL2); - - r_clr = r_set = w_clr = w_set = 0; - - compute_clr_set(vcpu, HDFGRTR_EL2, r_clr, r_set); - compute_clr_set(vcpu, HDFGWTR_EL2, w_clr, w_set); - - r_val = __HDFGRTR_EL2_nMASK; - r_val |= r_set; - r_val &= ~r_clr; - - w_val = __HDFGWTR_EL2_nMASK; - w_val |= w_set; - w_val &= ~w_clr; - - write_sysreg_s(r_val, SYS_HDFGRTR_EL2); - write_sysreg_s(w_val, SYS_HDFGWTR_EL2); + if (cpu_has_amu()) + update_fgt_traps(vcpu, HAFGRTR_EL2); } static inline void __deactivate_traps_hfgxtr(struct kvm_vcpu *vcpu) @@ -171,6 +199,9 @@ static inline void __deactivate_traps_hfgxtr(struct kvm_vcpu *vcpu) write_sysreg_s(ctxt_sys_reg(hctxt, HFGITR_EL2), SYS_HFGITR_EL2); write_sysreg_s(ctxt_sys_reg(hctxt, HDFGRTR_EL2), SYS_HDFGRTR_EL2); write_sysreg_s(ctxt_sys_reg(hctxt, HDFGWTR_EL2), SYS_HDFGWTR_EL2); + + if (cpu_has_amu()) + write_sysreg_s(ctxt_sys_reg(hctxt, HAFGRTR_EL2), SYS_HAFGRTR_EL2); } static inline void __activate_traps_common(struct kvm_vcpu *vcpu) @@ -591,7 +622,7 @@ static bool kvm_hyp_handle_dabt_low(struct kvm_vcpu *vcpu, u64 *exit_code) if (static_branch_unlikely(&vgic_v2_cpuif_trap)) { bool valid; - valid = kvm_vcpu_trap_get_fault_type(vcpu) == ESR_ELx_FSC_FAULT && + valid = kvm_vcpu_trap_is_translation_fault(vcpu) && kvm_vcpu_dabt_isvalid(vcpu) && !kvm_vcpu_abt_issea(vcpu) && !kvm_vcpu_abt_iss1tw(vcpu); diff --git a/arch/arm64/kvm/hyp/include/nvhe/fixed_config.h b/arch/arm64/kvm/hyp/include/nvhe/fixed_config.h index e91922daa8ca8e..51f043649146aa 100644 --- a/arch/arm64/kvm/hyp/include/nvhe/fixed_config.h +++ b/arch/arm64/kvm/hyp/include/nvhe/fixed_config.h @@ -69,6 +69,8 @@ ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_SSBS) \ ) +#define PVM_ID_AA64PFR2_ALLOW 0ULL + /* * Allow for protected VMs: * - Mixed-endian @@ -101,6 +103,7 @@ * - Privileged Access Never * - SError interrupt exceptions from speculative reads * - Enhanced Translation Synchronization + * - Control for cache maintenance permission */ #define PVM_ID_AA64MMFR1_ALLOW (\ ARM64_FEATURE_MASK(ID_AA64MMFR1_EL1_HAFDBS) | \ @@ -108,7 +111,8 @@ ARM64_FEATURE_MASK(ID_AA64MMFR1_EL1_HPDS) | \ ARM64_FEATURE_MASK(ID_AA64MMFR1_EL1_PAN) | \ ARM64_FEATURE_MASK(ID_AA64MMFR1_EL1_SpecSEI) | \ - ARM64_FEATURE_MASK(ID_AA64MMFR1_EL1_ETS) \ + ARM64_FEATURE_MASK(ID_AA64MMFR1_EL1_ETS) | \ + ARM64_FEATURE_MASK(ID_AA64MMFR1_EL1_CMOW) \ ) /* @@ -133,6 +137,8 @@ ARM64_FEATURE_MASK(ID_AA64MMFR2_EL1_E0PD) \ ) +#define PVM_ID_AA64MMFR3_ALLOW (0ULL) + /* * No support for Scalable Vectors for protected VMs: * Requires additional support from KVM, e.g., context-switching and @@ -178,10 +184,18 @@ ARM64_FEATURE_MASK(ID_AA64ISAR0_EL1_RNDR) \ ) +/* Restrict pointer authentication to the basic version. */ +#define PVM_ID_AA64ISAR1_RESTRICT_UNSIGNED (\ + FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_APA), ID_AA64ISAR1_EL1_APA_PAuth) | \ + FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_API), ID_AA64ISAR1_EL1_API_PAuth) \ + ) + +#define PVM_ID_AA64ISAR2_RESTRICT_UNSIGNED (\ + FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_APA3), ID_AA64ISAR2_EL1_APA3_PAuth) \ + ) + #define PVM_ID_AA64ISAR1_ALLOW (\ ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_DPB) | \ - ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_APA) | \ - ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_API) | \ ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_JSCVT) | \ ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_FCMA) | \ ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_LRCPC) | \ @@ -196,8 +210,8 @@ ) #define PVM_ID_AA64ISAR2_ALLOW (\ + ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_ATS1A)| \ ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_GPA3) | \ - ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_APA3) | \ ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_MOPS) \ ) diff --git a/arch/arm64/kvm/hyp/include/nvhe/gfp.h b/arch/arm64/kvm/hyp/include/nvhe/gfp.h index fe5472a184a37d..97c527ef53c2ad 100644 --- a/arch/arm64/kvm/hyp/include/nvhe/gfp.h +++ b/arch/arm64/kvm/hyp/include/nvhe/gfp.h @@ -16,7 +16,7 @@ struct hyp_pool { * API at EL2. */ hyp_spinlock_t lock; - struct list_head free_area[MAX_ORDER + 1]; + struct list_head free_area[NR_PAGE_ORDERS]; phys_addr_t range_start; phys_addr_t range_end; unsigned short max_order; diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-init.S b/arch/arm64/kvm/hyp/nvhe/hyp-init.S index 1cc06e6797bda3..2994878d68ea7e 100644 --- a/arch/arm64/kvm/hyp/nvhe/hyp-init.S +++ b/arch/arm64/kvm/hyp/nvhe/hyp-init.S @@ -122,11 +122,7 @@ alternative_if ARM64_HAS_CNP alternative_else_nop_endif msr ttbr0_el2, x2 - /* - * Set the PS bits in TCR_EL2. - */ ldr x0, [x0, #NVHE_INIT_TCR_EL2] - tcr_compute_pa_size x0, #TCR_EL2_PS_SHIFT, x1, x2 msr tcr_el2, x0 isb @@ -292,6 +288,8 @@ alternative_else_nop_endif mov sp, x0 /* And turn the MMU back on! */ + dsb nsh + isb set_sctlr_el2 x2 ret x1 SYM_FUNC_END(__pkvm_init_switch_pgd) diff --git a/arch/arm64/kvm/hyp/nvhe/mem_protect.c b/arch/arm64/kvm/hyp/nvhe/mem_protect.c index 8d0a5834e88300..861c76021a250c 100644 --- a/arch/arm64/kvm/hyp/nvhe/mem_protect.c +++ b/arch/arm64/kvm/hyp/nvhe/mem_protect.c @@ -91,7 +91,7 @@ static void host_s2_put_page(void *addr) hyp_put_page(&host_s2_pool, addr); } -static void host_s2_free_unlinked_table(void *addr, u32 level) +static void host_s2_free_unlinked_table(void *addr, s8 level) { kvm_pgtable_stage2_free_unlinked(&host_mmu.mm_ops, addr, level); } @@ -443,7 +443,7 @@ static int host_stage2_adjust_range(u64 addr, struct kvm_mem_range *range) { struct kvm_mem_range cur; kvm_pte_t pte; - u32 level; + s8 level; int ret; hyp_assert_lock_held(&host_mmu.lock); @@ -462,7 +462,7 @@ static int host_stage2_adjust_range(u64 addr, struct kvm_mem_range *range) cur.start = ALIGN_DOWN(addr, granule); cur.end = cur.start + granule; level++; - } while ((level < KVM_PGTABLE_MAX_LEVELS) && + } while ((level <= KVM_PGTABLE_LAST_LEVEL) && !(kvm_level_supports_block_mapping(level) && range_included(&cur, range))); diff --git a/arch/arm64/kvm/hyp/nvhe/mm.c b/arch/arm64/kvm/hyp/nvhe/mm.c index 65a7a186d7b217..b01a3d1078a880 100644 --- a/arch/arm64/kvm/hyp/nvhe/mm.c +++ b/arch/arm64/kvm/hyp/nvhe/mm.c @@ -260,7 +260,7 @@ static void fixmap_clear_slot(struct hyp_fixmap_slot *slot) * https://lore.kernel.org/kvm/20221017115209.2099-1-will@kernel.org/T/#mf10dfbaf1eaef9274c581b81c53758918c1d0f03 */ dsb(ishst); - __tlbi_level(vale2is, __TLBI_VADDR(addr, 0), (KVM_PGTABLE_MAX_LEVELS - 1)); + __tlbi_level(vale2is, __TLBI_VADDR(addr, 0), KVM_PGTABLE_LAST_LEVEL); dsb(ish); isb(); } @@ -275,7 +275,7 @@ static int __create_fixmap_slot_cb(const struct kvm_pgtable_visit_ctx *ctx, { struct hyp_fixmap_slot *slot = per_cpu_ptr(&fixmap_slots, (u64)ctx->arg); - if (!kvm_pte_valid(ctx->old) || ctx->level != KVM_PGTABLE_MAX_LEVELS - 1) + if (!kvm_pte_valid(ctx->old) || ctx->level != KVM_PGTABLE_LAST_LEVEL) return -EINVAL; slot->addr = ctx->addr; diff --git a/arch/arm64/kvm/hyp/nvhe/page_alloc.c b/arch/arm64/kvm/hyp/nvhe/page_alloc.c index b1e392186a0f6b..e691290d3765d3 100644 --- a/arch/arm64/kvm/hyp/nvhe/page_alloc.c +++ b/arch/arm64/kvm/hyp/nvhe/page_alloc.c @@ -228,7 +228,8 @@ int hyp_pool_init(struct hyp_pool *pool, u64 pfn, unsigned int nr_pages, int i; hyp_spin_lock_init(&pool->lock); - pool->max_order = min(MAX_ORDER, get_order(nr_pages << PAGE_SHIFT)); + pool->max_order = min(MAX_PAGE_ORDER, + get_order(nr_pages << PAGE_SHIFT)); for (i = 0; i <= pool->max_order; i++) INIT_LIST_HEAD(&pool->free_area[i]); pool->range_start = phys; diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c index 9d23a51d7f7525..26dd9a20ad6e6d 100644 --- a/arch/arm64/kvm/hyp/nvhe/pkvm.c +++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c @@ -12,7 +12,7 @@ #include #include -/* Used by icache_is_vpipt(). */ +/* Used by icache_is_aliasing(). */ unsigned long __icache_flags; /* Used by kvm_get_vttbr(). */ @@ -136,6 +136,10 @@ static void pvm_init_traps_aa64dfr0(struct kvm_vcpu *vcpu) cptr_set |= CPTR_EL2_TTA; } + /* Trap External Trace */ + if (!FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_EL1_ExtTrcBuff), feature_ids)) + mdcr_clear |= MDCR_EL2_E2TB_MASK << MDCR_EL2_E2TB_SHIFT; + vcpu->arch.mdcr_el2 |= mdcr_set; vcpu->arch.mdcr_el2 &= ~mdcr_clear; vcpu->arch.cptr_el2 |= cptr_set; diff --git a/arch/arm64/kvm/hyp/nvhe/setup.c b/arch/arm64/kvm/hyp/nvhe/setup.c index 0d5e0a89ddce5d..bc58d1b515af19 100644 --- a/arch/arm64/kvm/hyp/nvhe/setup.c +++ b/arch/arm64/kvm/hyp/nvhe/setup.c @@ -181,7 +181,7 @@ static int fix_host_ownership_walker(const struct kvm_pgtable_visit_ctx *ctx, if (!kvm_pte_valid(ctx->old)) return 0; - if (ctx->level != (KVM_PGTABLE_MAX_LEVELS - 1)) + if (ctx->level != KVM_PGTABLE_LAST_LEVEL) return -EINVAL; phys = kvm_pte_to_phys(ctx->old); diff --git a/arch/arm64/kvm/hyp/nvhe/tlb.c b/arch/arm64/kvm/hyp/nvhe/tlb.c index 1b265713d6bede..a60fb13e21924f 100644 --- a/arch/arm64/kvm/hyp/nvhe/tlb.c +++ b/arch/arm64/kvm/hyp/nvhe/tlb.c @@ -105,28 +105,6 @@ void __kvm_tlb_flush_vmid_ipa(struct kvm_s2_mmu *mmu, dsb(ish); isb(); - /* - * If the host is running at EL1 and we have a VPIPT I-cache, - * then we must perform I-cache maintenance at EL2 in order for - * it to have an effect on the guest. Since the guest cannot hit - * I-cache lines allocated with a different VMID, we don't need - * to worry about junk out of guest reset (we nuke the I-cache on - * VMID rollover), but we do need to be careful when remapping - * executable pages for the same guest. This can happen when KSM - * takes a CoW fault on an executable page, copies the page into - * a page that was previously mapped in the guest and then needs - * to invalidate the guest view of the I-cache for that page - * from EL1. To solve this, we invalidate the entire I-cache when - * unmapping a page from a guest if we have a VPIPT I-cache but - * the host is running at EL1. As above, we could do better if - * we had the VA. - * - * The moral of this story is: if you have a VPIPT I-cache, then - * you should be running with VHE enabled. - */ - if (icache_is_vpipt()) - icache_inval_all_pou(); - __tlb_switch_to_host(&cxt); } @@ -157,28 +135,6 @@ void __kvm_tlb_flush_vmid_ipa_nsh(struct kvm_s2_mmu *mmu, dsb(nsh); isb(); - /* - * If the host is running at EL1 and we have a VPIPT I-cache, - * then we must perform I-cache maintenance at EL2 in order for - * it to have an effect on the guest. Since the guest cannot hit - * I-cache lines allocated with a different VMID, we don't need - * to worry about junk out of guest reset (we nuke the I-cache on - * VMID rollover), but we do need to be careful when remapping - * executable pages for the same guest. This can happen when KSM - * takes a CoW fault on an executable page, copies the page into - * a page that was previously mapped in the guest and then needs - * to invalidate the guest view of the I-cache for that page - * from EL1. To solve this, we invalidate the entire I-cache when - * unmapping a page from a guest if we have a VPIPT I-cache but - * the host is running at EL1. As above, we could do better if - * we had the VA. - * - * The moral of this story is: if you have a VPIPT I-cache, then - * you should be running with VHE enabled. - */ - if (icache_is_vpipt()) - icache_inval_all_pou(); - __tlb_switch_to_host(&cxt); } @@ -205,10 +161,6 @@ void __kvm_tlb_flush_vmid_range(struct kvm_s2_mmu *mmu, dsb(ish); isb(); - /* See the comment in __kvm_tlb_flush_vmid_ipa() */ - if (icache_is_vpipt()) - icache_inval_all_pou(); - __tlb_switch_to_host(&cxt); } @@ -246,18 +198,5 @@ void __kvm_flush_vm_context(void) /* Same remark as in __tlb_switch_to_guest() */ dsb(ish); __tlbi(alle1is); - - /* - * VIPT and PIPT caches are not affected by VMID, so no maintenance - * is necessary across a VMID rollover. - * - * VPIPT caches constrain lookup and maintenance to the active VMID, - * so we need to invalidate lines with a stale VMID to avoid an ABA - * race after multiple rollovers. - * - */ - if (icache_is_vpipt()) - asm volatile("ic ialluis"); - dsb(ish); } diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c index 1966fdee740ebf..c651df904fe3eb 100644 --- a/arch/arm64/kvm/hyp/pgtable.c +++ b/arch/arm64/kvm/hyp/pgtable.c @@ -79,7 +79,10 @@ static bool kvm_pgtable_walk_skip_cmo(const struct kvm_pgtable_visit_ctx *ctx) static bool kvm_phys_is_valid(u64 phys) { - return phys < BIT(id_aa64mmfr0_parange_to_phys_shift(ID_AA64MMFR0_EL1_PARANGE_MAX)); + u64 parange_max = kvm_get_parange_max(); + u8 shift = id_aa64mmfr0_parange_to_phys_shift(parange_max); + + return phys < BIT(shift); } static bool kvm_block_mapping_supported(const struct kvm_pgtable_visit_ctx *ctx, u64 phys) @@ -98,7 +101,7 @@ static bool kvm_block_mapping_supported(const struct kvm_pgtable_visit_ctx *ctx, return IS_ALIGNED(ctx->addr, granule); } -static u32 kvm_pgtable_idx(struct kvm_pgtable_walk_data *data, u32 level) +static u32 kvm_pgtable_idx(struct kvm_pgtable_walk_data *data, s8 level) { u64 shift = kvm_granule_shift(level); u64 mask = BIT(PAGE_SHIFT - 3) - 1; @@ -114,7 +117,7 @@ static u32 kvm_pgd_page_idx(struct kvm_pgtable *pgt, u64 addr) return (addr & mask) >> shift; } -static u32 kvm_pgd_pages(u32 ia_bits, u32 start_level) +static u32 kvm_pgd_pages(u32 ia_bits, s8 start_level) { struct kvm_pgtable pgt = { .ia_bits = ia_bits, @@ -124,9 +127,9 @@ static u32 kvm_pgd_pages(u32 ia_bits, u32 start_level) return kvm_pgd_page_idx(&pgt, -1ULL) + 1; } -static bool kvm_pte_table(kvm_pte_t pte, u32 level) +static bool kvm_pte_table(kvm_pte_t pte, s8 level) { - if (level == KVM_PGTABLE_MAX_LEVELS - 1) + if (level == KVM_PGTABLE_LAST_LEVEL) return false; if (!kvm_pte_valid(pte)) @@ -154,11 +157,11 @@ static kvm_pte_t kvm_init_table_pte(kvm_pte_t *childp, struct kvm_pgtable_mm_ops return pte; } -static kvm_pte_t kvm_init_valid_leaf_pte(u64 pa, kvm_pte_t attr, u32 level) +static kvm_pte_t kvm_init_valid_leaf_pte(u64 pa, kvm_pte_t attr, s8 level) { kvm_pte_t pte = kvm_phys_to_pte(pa); - u64 type = (level == KVM_PGTABLE_MAX_LEVELS - 1) ? KVM_PTE_TYPE_PAGE : - KVM_PTE_TYPE_BLOCK; + u64 type = (level == KVM_PGTABLE_LAST_LEVEL) ? KVM_PTE_TYPE_PAGE : + KVM_PTE_TYPE_BLOCK; pte |= attr & (KVM_PTE_LEAF_ATTR_LO | KVM_PTE_LEAF_ATTR_HI); pte |= FIELD_PREP(KVM_PTE_TYPE, type); @@ -203,11 +206,11 @@ static bool kvm_pgtable_walk_continue(const struct kvm_pgtable_walker *walker, } static int __kvm_pgtable_walk(struct kvm_pgtable_walk_data *data, - struct kvm_pgtable_mm_ops *mm_ops, kvm_pteref_t pgtable, u32 level); + struct kvm_pgtable_mm_ops *mm_ops, kvm_pteref_t pgtable, s8 level); static inline int __kvm_pgtable_visit(struct kvm_pgtable_walk_data *data, struct kvm_pgtable_mm_ops *mm_ops, - kvm_pteref_t pteref, u32 level) + kvm_pteref_t pteref, s8 level) { enum kvm_pgtable_walk_flags flags = data->walker->flags; kvm_pte_t *ptep = kvm_dereference_pteref(data->walker, pteref); @@ -272,12 +275,13 @@ out: } static int __kvm_pgtable_walk(struct kvm_pgtable_walk_data *data, - struct kvm_pgtable_mm_ops *mm_ops, kvm_pteref_t pgtable, u32 level) + struct kvm_pgtable_mm_ops *mm_ops, kvm_pteref_t pgtable, s8 level) { u32 idx; int ret = 0; - if (WARN_ON_ONCE(level >= KVM_PGTABLE_MAX_LEVELS)) + if (WARN_ON_ONCE(level < KVM_PGTABLE_FIRST_LEVEL || + level > KVM_PGTABLE_LAST_LEVEL)) return -EINVAL; for (idx = kvm_pgtable_idx(data, level); idx < PTRS_PER_PTE; ++idx) { @@ -340,7 +344,7 @@ int kvm_pgtable_walk(struct kvm_pgtable *pgt, u64 addr, u64 size, struct leaf_walk_data { kvm_pte_t pte; - u32 level; + s8 level; }; static int leaf_walker(const struct kvm_pgtable_visit_ctx *ctx, @@ -355,7 +359,7 @@ static int leaf_walker(const struct kvm_pgtable_visit_ctx *ctx, } int kvm_pgtable_get_leaf(struct kvm_pgtable *pgt, u64 addr, - kvm_pte_t *ptep, u32 *level) + kvm_pte_t *ptep, s8 *level) { struct leaf_walk_data data; struct kvm_pgtable_walker walker = { @@ -408,7 +412,8 @@ static int hyp_set_prot_attr(enum kvm_pgtable_prot prot, kvm_pte_t *ptep) } attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S1_AP, ap); - attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S1_SH, sh); + if (!kvm_lpa2_is_enabled()) + attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S1_SH, sh); attr |= KVM_PTE_LEAF_ATTR_LO_S1_AF; attr |= prot & KVM_PTE_LEAF_ATTR_HI_SW; *ptep = attr; @@ -467,7 +472,7 @@ static int hyp_map_walker(const struct kvm_pgtable_visit_ctx *ctx, if (hyp_map_walker_try_leaf(ctx, data)) return 0; - if (WARN_ON(ctx->level == KVM_PGTABLE_MAX_LEVELS - 1)) + if (WARN_ON(ctx->level == KVM_PGTABLE_LAST_LEVEL)) return -EINVAL; childp = (kvm_pte_t *)mm_ops->zalloc_page(NULL); @@ -563,14 +568,19 @@ u64 kvm_pgtable_hyp_unmap(struct kvm_pgtable *pgt, u64 addr, u64 size) int kvm_pgtable_hyp_init(struct kvm_pgtable *pgt, u32 va_bits, struct kvm_pgtable_mm_ops *mm_ops) { - u64 levels = ARM64_HW_PGTABLE_LEVELS(va_bits); + s8 start_level = KVM_PGTABLE_LAST_LEVEL + 1 - + ARM64_HW_PGTABLE_LEVELS(va_bits); + + if (start_level < KVM_PGTABLE_FIRST_LEVEL || + start_level > KVM_PGTABLE_LAST_LEVEL) + return -EINVAL; pgt->pgd = (kvm_pteref_t)mm_ops->zalloc_page(NULL); if (!pgt->pgd) return -ENOMEM; pgt->ia_bits = va_bits; - pgt->start_level = KVM_PGTABLE_MAX_LEVELS - levels; + pgt->start_level = start_level; pgt->mm_ops = mm_ops; pgt->mmu = NULL; pgt->force_pte_cb = NULL; @@ -624,7 +634,7 @@ struct stage2_map_data { u64 kvm_get_vtcr(u64 mmfr0, u64 mmfr1, u32 phys_shift) { u64 vtcr = VTCR_EL2_FLAGS; - u8 lvls; + s8 lvls; vtcr |= kvm_get_parange(mmfr0) << VTCR_EL2_PS_SHIFT; vtcr |= VTCR_EL2_T0SZ(phys_shift); @@ -635,6 +645,15 @@ u64 kvm_get_vtcr(u64 mmfr0, u64 mmfr1, u32 phys_shift) lvls = stage2_pgtable_levels(phys_shift); if (lvls < 2) lvls = 2; + + /* + * When LPA2 is enabled, the HW supports an extra level of translation + * (for 5 in total) when using 4K pages. It also introduces VTCR_EL2.SL2 + * to as an addition to SL0 to enable encoding this extra start level. + * However, since we always use concatenated pages for the first level + * lookup, we will never need this extra level and therefore do not need + * to touch SL2. + */ vtcr |= VTCR_EL2_LVLS_TO_SL0(lvls); #ifdef CONFIG_ARM64_HW_AFDBM @@ -654,6 +673,9 @@ u64 kvm_get_vtcr(u64 mmfr0, u64 mmfr1, u32 phys_shift) vtcr |= VTCR_EL2_HA; #endif /* CONFIG_ARM64_HW_AFDBM */ + if (kvm_lpa2_is_enabled()) + vtcr |= VTCR_EL2_DS; + /* Set the vmid bits */ vtcr |= (get_vmid_bits(mmfr1) == 16) ? VTCR_EL2_VS_16BIT : @@ -711,7 +733,9 @@ static int stage2_set_prot_attr(struct kvm_pgtable *pgt, enum kvm_pgtable_prot p if (prot & KVM_PGTABLE_PROT_W) attr |= KVM_PTE_LEAF_ATTR_LO_S2_S2AP_W; - attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S2_SH, sh); + if (!kvm_lpa2_is_enabled()) + attr |= FIELD_PREP(KVM_PTE_LEAF_ATTR_LO_S2_SH, sh); + attr |= KVM_PTE_LEAF_ATTR_LO_S2_AF; attr |= prot & KVM_PTE_LEAF_ATTR_HI_SW; *ptep = attr; @@ -902,7 +926,7 @@ static bool stage2_leaf_mapping_allowed(const struct kvm_pgtable_visit_ctx *ctx, { u64 phys = stage2_map_walker_phys_addr(ctx, data); - if (data->force_pte && (ctx->level < (KVM_PGTABLE_MAX_LEVELS - 1))) + if (data->force_pte && ctx->level < KVM_PGTABLE_LAST_LEVEL) return false; return kvm_block_mapping_supported(ctx, phys); @@ -981,7 +1005,7 @@ static int stage2_map_walk_leaf(const struct kvm_pgtable_visit_ctx *ctx, if (ret != -E2BIG) return ret; - if (WARN_ON(ctx->level == KVM_PGTABLE_MAX_LEVELS - 1)) + if (WARN_ON(ctx->level == KVM_PGTABLE_LAST_LEVEL)) return -EINVAL; if (!data->memcache) @@ -1151,7 +1175,7 @@ struct stage2_attr_data { kvm_pte_t attr_set; kvm_pte_t attr_clr; kvm_pte_t pte; - u32 level; + s8 level; }; static int stage2_attr_walker(const struct kvm_pgtable_visit_ctx *ctx, @@ -1194,7 +1218,7 @@ static int stage2_attr_walker(const struct kvm_pgtable_visit_ctx *ctx, static int stage2_update_leaf_attrs(struct kvm_pgtable *pgt, u64 addr, u64 size, kvm_pte_t attr_set, kvm_pte_t attr_clr, kvm_pte_t *orig_pte, - u32 *level, enum kvm_pgtable_walk_flags flags) + s8 *level, enum kvm_pgtable_walk_flags flags) { int ret; kvm_pte_t attr_mask = KVM_PTE_LEAF_ATTR_LO | KVM_PTE_LEAF_ATTR_HI; @@ -1296,7 +1320,7 @@ int kvm_pgtable_stage2_relax_perms(struct kvm_pgtable *pgt, u64 addr, enum kvm_pgtable_prot prot) { int ret; - u32 level; + s8 level; kvm_pte_t set = 0, clr = 0; if (prot & KVM_PTE_LEAF_ATTR_HI_SW) @@ -1349,7 +1373,7 @@ int kvm_pgtable_stage2_flush(struct kvm_pgtable *pgt, u64 addr, u64 size) } kvm_pte_t *kvm_pgtable_stage2_create_unlinked(struct kvm_pgtable *pgt, - u64 phys, u32 level, + u64 phys, s8 level, enum kvm_pgtable_prot prot, void *mc, bool force_pte) { @@ -1407,7 +1431,7 @@ kvm_pte_t *kvm_pgtable_stage2_create_unlinked(struct kvm_pgtable *pgt, * fully populated tree up to the PTE entries. Note that @level is * interpreted as in "level @level entry". */ -static int stage2_block_get_nr_page_tables(u32 level) +static int stage2_block_get_nr_page_tables(s8 level) { switch (level) { case 1: @@ -1418,7 +1442,7 @@ static int stage2_block_get_nr_page_tables(u32 level) return 0; default: WARN_ON_ONCE(level < KVM_PGTABLE_MIN_BLOCK_LEVEL || - level >= KVM_PGTABLE_MAX_LEVELS); + level > KVM_PGTABLE_LAST_LEVEL); return -EINVAL; }; } @@ -1431,13 +1455,13 @@ static int stage2_split_walker(const struct kvm_pgtable_visit_ctx *ctx, struct kvm_s2_mmu *mmu; kvm_pte_t pte = ctx->old, new, *childp; enum kvm_pgtable_prot prot; - u32 level = ctx->level; + s8 level = ctx->level; bool force_pte; int nr_pages; u64 phys; /* No huge-pages exist at the last level */ - if (level == KVM_PGTABLE_MAX_LEVELS - 1) + if (level == KVM_PGTABLE_LAST_LEVEL) return 0; /* We only split valid block mappings */ @@ -1514,7 +1538,7 @@ int __kvm_pgtable_stage2_init(struct kvm_pgtable *pgt, struct kvm_s2_mmu *mmu, u64 vtcr = mmu->vtcr; u32 ia_bits = VTCR_EL2_IPA(vtcr); u32 sl0 = FIELD_GET(VTCR_EL2_SL0_MASK, vtcr); - u32 start_level = VTCR_EL2_TGRAN_SL0_BASE - sl0; + s8 start_level = VTCR_EL2_TGRAN_SL0_BASE - sl0; pgd_sz = kvm_pgd_pages(ia_bits, start_level) * PAGE_SIZE; pgt->pgd = (kvm_pteref_t)mm_ops->zalloc_pages_exact(pgd_sz); @@ -1537,7 +1561,7 @@ size_t kvm_pgtable_stage2_pgd_size(u64 vtcr) { u32 ia_bits = VTCR_EL2_IPA(vtcr); u32 sl0 = FIELD_GET(VTCR_EL2_SL0_MASK, vtcr); - u32 start_level = VTCR_EL2_TGRAN_SL0_BASE - sl0; + s8 start_level = VTCR_EL2_TGRAN_SL0_BASE - sl0; return kvm_pgd_pages(ia_bits, start_level) * PAGE_SIZE; } @@ -1573,7 +1597,7 @@ void kvm_pgtable_stage2_destroy(struct kvm_pgtable *pgt) pgt->pgd = NULL; } -void kvm_pgtable_stage2_free_unlinked(struct kvm_pgtable_mm_ops *mm_ops, void *pgtable, u32 level) +void kvm_pgtable_stage2_free_unlinked(struct kvm_pgtable_mm_ops *mm_ops, void *pgtable, s8 level) { kvm_pteref_t ptep = (kvm_pteref_t)pgtable; struct kvm_pgtable_walker walker = { diff --git a/arch/arm64/kvm/hyp/vhe/tlb.c b/arch/arm64/kvm/hyp/vhe/tlb.c index b636b4111dbf50..b32e2940df7dc8 100644 --- a/arch/arm64/kvm/hyp/vhe/tlb.c +++ b/arch/arm64/kvm/hyp/vhe/tlb.c @@ -216,18 +216,5 @@ void __kvm_flush_vm_context(void) { dsb(ishst); __tlbi(alle1is); - - /* - * VIPT and PIPT caches are not affected by VMID, so no maintenance - * is necessary across a VMID rollover. - * - * VPIPT caches constrain lookup and maintenance to the active VMID, - * so we need to invalidate lines with a stale VMID to avoid an ABA - * race after multiple rollovers. - * - */ - if (icache_is_vpipt()) - asm volatile("ic ialluis"); - dsb(ish); } diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index d87c8fcc4c24f6..d14504821b794e 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -223,12 +223,12 @@ static void stage2_free_unlinked_table_rcu_cb(struct rcu_head *head) { struct page *page = container_of(head, struct page, rcu_head); void *pgtable = page_to_virt(page); - u32 level = page_private(page); + s8 level = page_private(page); kvm_pgtable_stage2_free_unlinked(&kvm_s2_mm_ops, pgtable, level); } -static void stage2_free_unlinked_table(void *addr, u32 level) +static void stage2_free_unlinked_table(void *addr, s8 level) { struct page *page = virt_to_page(addr); @@ -804,13 +804,13 @@ static int get_user_mapping_size(struct kvm *kvm, u64 addr) struct kvm_pgtable pgt = { .pgd = (kvm_pteref_t)kvm->mm->pgd, .ia_bits = vabits_actual, - .start_level = (KVM_PGTABLE_MAX_LEVELS - - CONFIG_PGTABLE_LEVELS), + .start_level = (KVM_PGTABLE_LAST_LEVEL - + CONFIG_PGTABLE_LEVELS + 1), .mm_ops = &kvm_user_mm_ops, }; unsigned long flags; kvm_pte_t pte = 0; /* Keep GCC quiet... */ - u32 level = ~0; + s8 level = S8_MAX; int ret; /* @@ -829,7 +829,9 @@ static int get_user_mapping_size(struct kvm *kvm, u64 addr) * Not seeing an error, but not updating level? Something went * deeply wrong... */ - if (WARN_ON(level >= KVM_PGTABLE_MAX_LEVELS)) + if (WARN_ON(level > KVM_PGTABLE_LAST_LEVEL)) + return -EFAULT; + if (WARN_ON(level < KVM_PGTABLE_FIRST_LEVEL)) return -EFAULT; /* Oops, the userspace PTs are gone... Replay the fault */ @@ -1374,7 +1376,7 @@ static bool kvm_vma_mte_allowed(struct vm_area_struct *vma) static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, struct kvm_memory_slot *memslot, unsigned long hva, - unsigned long fault_status) + bool fault_is_perm) { int ret = 0; bool write_fault, writable, force_pte = false; @@ -1388,17 +1390,17 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, gfn_t gfn; kvm_pfn_t pfn; bool logging_active = memslot_is_logging(memslot); - unsigned long fault_level = kvm_vcpu_trap_get_fault_level(vcpu); long vma_pagesize, fault_granule; enum kvm_pgtable_prot prot = KVM_PGTABLE_PROT_R; struct kvm_pgtable *pgt; - fault_granule = 1UL << ARM64_HW_PGTABLE_LEVEL_SHIFT(fault_level); + if (fault_is_perm) + fault_granule = kvm_vcpu_trap_get_perm_fault_granule(vcpu); write_fault = kvm_is_write_fault(vcpu); exec_fault = kvm_vcpu_trap_is_exec_fault(vcpu); VM_BUG_ON(write_fault && exec_fault); - if (fault_status == ESR_ELx_FSC_PERM && !write_fault && !exec_fault) { + if (fault_is_perm && !write_fault && !exec_fault) { kvm_err("Unexpected L2 read permission error\n"); return -EFAULT; } @@ -1409,8 +1411,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, * only exception to this is when dirty logging is enabled at runtime * and a write fault needs to collapse a block entry into a table. */ - if (fault_status != ESR_ELx_FSC_PERM || - (logging_active && write_fault)) { + if (!fault_is_perm || (logging_active && write_fault)) { ret = kvm_mmu_topup_memory_cache(memcache, kvm_mmu_cache_min_pages(vcpu->arch.hw_mmu)); if (ret) @@ -1527,8 +1528,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, * backed by a THP and thus use block mapping if possible. */ if (vma_pagesize == PAGE_SIZE && !(force_pte || device)) { - if (fault_status == ESR_ELx_FSC_PERM && - fault_granule > PAGE_SIZE) + if (fault_is_perm && fault_granule > PAGE_SIZE) vma_pagesize = fault_granule; else vma_pagesize = transparent_hugepage_adjust(kvm, memslot, @@ -1541,7 +1541,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, } } - if (fault_status != ESR_ELx_FSC_PERM && !device && kvm_has_mte(kvm)) { + if (!fault_is_perm && !device && kvm_has_mte(kvm)) { /* Check the VMM hasn't introduced a new disallowed VMA */ if (mte_allowed) { sanitise_mte_tags(kvm, pfn, vma_pagesize); @@ -1567,7 +1567,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, * permissions only if vma_pagesize equals fault_granule. Otherwise, * kvm_pgtable_stage2_map() should be called to change block size. */ - if (fault_status == ESR_ELx_FSC_PERM && vma_pagesize == fault_granule) + if (fault_is_perm && vma_pagesize == fault_granule) ret = kvm_pgtable_stage2_relax_perms(pgt, fault_ipa, prot); else ret = kvm_pgtable_stage2_map(pgt, fault_ipa, vma_pagesize, @@ -1618,7 +1618,7 @@ static void handle_access_fault(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa) */ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu) { - unsigned long fault_status; + unsigned long esr; phys_addr_t fault_ipa; struct kvm_memory_slot *memslot; unsigned long hva; @@ -1626,12 +1626,12 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu) gfn_t gfn; int ret, idx; - fault_status = kvm_vcpu_trap_get_fault_type(vcpu); + esr = kvm_vcpu_get_esr(vcpu); fault_ipa = kvm_vcpu_get_fault_ipa(vcpu); is_iabt = kvm_vcpu_trap_is_iabt(vcpu); - if (fault_status == ESR_ELx_FSC_FAULT) { + if (esr_fsc_is_permission_fault(esr)) { /* Beyond sanitised PARange (which is the IPA limit) */ if (fault_ipa >= BIT_ULL(get_kvm_ipa_limit())) { kvm_inject_size_fault(vcpu); @@ -1666,9 +1666,9 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu) kvm_vcpu_get_hfar(vcpu), fault_ipa); /* Check the stage-2 fault is trans. fault or write fault */ - if (fault_status != ESR_ELx_FSC_FAULT && - fault_status != ESR_ELx_FSC_PERM && - fault_status != ESR_ELx_FSC_ACCESS) { + if (!esr_fsc_is_translation_fault(esr) && + !esr_fsc_is_permission_fault(esr) && + !esr_fsc_is_access_flag_fault(esr)) { kvm_err("Unsupported FSC: EC=%#x xFSC=%#lx ESR_EL2=%#lx\n", kvm_vcpu_trap_get_class(vcpu), (unsigned long)kvm_vcpu_trap_get_fault(vcpu), @@ -1730,13 +1730,14 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu) /* Userspace should not be able to register out-of-bounds IPAs */ VM_BUG_ON(fault_ipa >= kvm_phys_size(vcpu->arch.hw_mmu)); - if (fault_status == ESR_ELx_FSC_ACCESS) { + if (esr_fsc_is_access_flag_fault(esr)) { handle_access_fault(vcpu, fault_ipa); ret = 1; goto out_unlock; } - ret = user_mem_abort(vcpu, fault_ipa, memslot, hva, fault_status); + ret = user_mem_abort(vcpu, fault_ipa, memslot, hva, + esr_fsc_is_permission_fault(esr)); if (ret == 0) ret = 1; out: diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c index 042695a210cebd..ba95d044bc98fd 100644 --- a/arch/arm64/kvm/nested.c +++ b/arch/arm64/kvm/nested.c @@ -23,13 +23,9 @@ * This list should get updated as new features get added to the NV * support, and new extension to the architecture. */ -void access_nested_id_reg(struct kvm_vcpu *v, struct sys_reg_params *p, - const struct sys_reg_desc *r) +static u64 limit_nv_id_reg(u32 id, u64 val) { - u32 id = reg_to_encoding(r); - u64 val, tmp; - - val = p->regval; + u64 tmp; switch (id) { case SYS_ID_AA64ISAR0_EL1: @@ -158,5 +154,17 @@ void access_nested_id_reg(struct kvm_vcpu *v, struct sys_reg_params *p, break; } - p->regval = val; + return val; +} +int kvm_init_nv_sysregs(struct kvm *kvm) +{ + mutex_lock(&kvm->arch.config_lock); + + for (int i = 0; i < KVM_ARM_ID_REG_NUM; i++) + kvm->arch.id_regs[i] = limit_nv_id_reg(IDX_IDREG(i), + kvm->arch.id_regs[i]); + + mutex_unlock(&kvm->arch.config_lock); + + return 0; } diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c index fe99b3dab6ce5d..3d9467ff73bcbf 100644 --- a/arch/arm64/kvm/pmu-emul.c +++ b/arch/arm64/kvm/pmu-emul.c @@ -267,9 +267,8 @@ void kvm_pmu_vcpu_destroy(struct kvm_vcpu *vcpu) u64 kvm_pmu_valid_counter_mask(struct kvm_vcpu *vcpu) { - u64 val = kvm_vcpu_read_pmcr(vcpu) >> ARMV8_PMU_PMCR_N_SHIFT; + u64 val = FIELD_GET(ARMV8_PMU_PMCR_N, kvm_vcpu_read_pmcr(vcpu)); - val &= ARMV8_PMU_PMCR_N_MASK; if (val == 0) return BIT(ARMV8_PMU_CYCLE_IDX); else @@ -1136,8 +1135,7 @@ u8 kvm_arm_pmu_get_pmuver_limit(void) */ u64 kvm_vcpu_read_pmcr(struct kvm_vcpu *vcpu) { - u64 pmcr = __vcpu_sys_reg(vcpu, PMCR_EL0) & - ~(ARMV8_PMU_PMCR_N_MASK << ARMV8_PMU_PMCR_N_SHIFT); + u64 pmcr = __vcpu_sys_reg(vcpu, PMCR_EL0); - return pmcr | ((u64)vcpu->kvm->arch.pmcr_n << ARMV8_PMU_PMCR_N_SHIFT); + return u64_replace_bits(pmcr, vcpu->kvm->arch.pmcr_n, ARMV8_PMU_PMCR_N); } diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c index 5bb4de162cab5d..68d1d05672bd4f 100644 --- a/arch/arm64/kvm/reset.c +++ b/arch/arm64/kvm/reset.c @@ -280,12 +280,11 @@ int __init kvm_set_ipa_limit(void) parange = cpuid_feature_extract_unsigned_field(mmfr0, ID_AA64MMFR0_EL1_PARANGE_SHIFT); /* - * IPA size beyond 48 bits could not be supported - * on either 4K or 16K page size. Hence let's cap - * it to 48 bits, in case it's reported as larger - * on the system. + * IPA size beyond 48 bits for 4K and 16K page size is only supported + * when LPA2 is available. So if we have LPA2, enable it, else cap to 48 + * bits, in case it's reported as larger on the system. */ - if (PAGE_SIZE != SZ_64K) + if (!kvm_lpa2_is_enabled() && PAGE_SIZE != SZ_64K) parange = min(parange, (unsigned int)ID_AA64MMFR0_EL1_PARANGE_48); /* diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 4735e1b37fb3e0..30253bd19917f4 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -45,44 +45,170 @@ static u64 sys_reg_to_index(const struct sys_reg_desc *reg); static int set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, u64 val); -static bool read_from_write_only(struct kvm_vcpu *vcpu, - struct sys_reg_params *params, - const struct sys_reg_desc *r) +static bool bad_trap(struct kvm_vcpu *vcpu, + struct sys_reg_params *params, + const struct sys_reg_desc *r, + const char *msg) { - WARN_ONCE(1, "Unexpected sys_reg read to write-only register\n"); + WARN_ONCE(1, "Unexpected %s\n", msg); print_sys_reg_instr(params); kvm_inject_undefined(vcpu); return false; } +static bool read_from_write_only(struct kvm_vcpu *vcpu, + struct sys_reg_params *params, + const struct sys_reg_desc *r) +{ + return bad_trap(vcpu, params, r, + "sys_reg read to write-only register"); +} + static bool write_to_read_only(struct kvm_vcpu *vcpu, struct sys_reg_params *params, const struct sys_reg_desc *r) { - WARN_ONCE(1, "Unexpected sys_reg write to read-only register\n"); - print_sys_reg_instr(params); - kvm_inject_undefined(vcpu); - return false; + return bad_trap(vcpu, params, r, + "sys_reg write to read-only register"); +} + +#define PURE_EL2_SYSREG(el2) \ + case el2: { \ + *el1r = el2; \ + return true; \ + } + +#define MAPPED_EL2_SYSREG(el2, el1, fn) \ + case el2: { \ + *xlate = fn; \ + *el1r = el1; \ + return true; \ + } + +static bool get_el2_to_el1_mapping(unsigned int reg, + unsigned int *el1r, u64 (**xlate)(u64)) +{ + switch (reg) { + PURE_EL2_SYSREG( VPIDR_EL2 ); + PURE_EL2_SYSREG( VMPIDR_EL2 ); + PURE_EL2_SYSREG( ACTLR_EL2 ); + PURE_EL2_SYSREG( HCR_EL2 ); + PURE_EL2_SYSREG( MDCR_EL2 ); + PURE_EL2_SYSREG( HSTR_EL2 ); + PURE_EL2_SYSREG( HACR_EL2 ); + PURE_EL2_SYSREG( VTTBR_EL2 ); + PURE_EL2_SYSREG( VTCR_EL2 ); + PURE_EL2_SYSREG( RVBAR_EL2 ); + PURE_EL2_SYSREG( TPIDR_EL2 ); + PURE_EL2_SYSREG( HPFAR_EL2 ); + PURE_EL2_SYSREG( CNTHCTL_EL2 ); + MAPPED_EL2_SYSREG(SCTLR_EL2, SCTLR_EL1, + translate_sctlr_el2_to_sctlr_el1 ); + MAPPED_EL2_SYSREG(CPTR_EL2, CPACR_EL1, + translate_cptr_el2_to_cpacr_el1 ); + MAPPED_EL2_SYSREG(TTBR0_EL2, TTBR0_EL1, + translate_ttbr0_el2_to_ttbr0_el1 ); + MAPPED_EL2_SYSREG(TTBR1_EL2, TTBR1_EL1, NULL ); + MAPPED_EL2_SYSREG(TCR_EL2, TCR_EL1, + translate_tcr_el2_to_tcr_el1 ); + MAPPED_EL2_SYSREG(VBAR_EL2, VBAR_EL1, NULL ); + MAPPED_EL2_SYSREG(AFSR0_EL2, AFSR0_EL1, NULL ); + MAPPED_EL2_SYSREG(AFSR1_EL2, AFSR1_EL1, NULL ); + MAPPED_EL2_SYSREG(ESR_EL2, ESR_EL1, NULL ); + MAPPED_EL2_SYSREG(FAR_EL2, FAR_EL1, NULL ); + MAPPED_EL2_SYSREG(MAIR_EL2, MAIR_EL1, NULL ); + MAPPED_EL2_SYSREG(AMAIR_EL2, AMAIR_EL1, NULL ); + MAPPED_EL2_SYSREG(ELR_EL2, ELR_EL1, NULL ); + MAPPED_EL2_SYSREG(SPSR_EL2, SPSR_EL1, NULL ); + default: + return false; + } } u64 vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, int reg) { u64 val = 0x8badf00d8badf00d; + u64 (*xlate)(u64) = NULL; + unsigned int el1r; + + if (!vcpu_get_flag(vcpu, SYSREGS_ON_CPU)) + goto memory_read; - if (vcpu_get_flag(vcpu, SYSREGS_ON_CPU) && - __vcpu_read_sys_reg_from_cpu(reg, &val)) + if (unlikely(get_el2_to_el1_mapping(reg, &el1r, &xlate))) { + if (!is_hyp_ctxt(vcpu)) + goto memory_read; + + /* + * If this register does not have an EL1 counterpart, + * then read the stored EL2 version. + */ + if (reg == el1r) + goto memory_read; + + /* + * If we have a non-VHE guest and that the sysreg + * requires translation to be used at EL1, use the + * in-memory copy instead. + */ + if (!vcpu_el2_e2h_is_set(vcpu) && xlate) + goto memory_read; + + /* Get the current version of the EL1 counterpart. */ + WARN_ON(!__vcpu_read_sys_reg_from_cpu(el1r, &val)); return val; + } + /* EL1 register can't be on the CPU if the guest is in vEL2. */ + if (unlikely(is_hyp_ctxt(vcpu))) + goto memory_read; + + if (__vcpu_read_sys_reg_from_cpu(reg, &val)) + return val; + +memory_read: return __vcpu_sys_reg(vcpu, reg); } void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, int reg) { - if (vcpu_get_flag(vcpu, SYSREGS_ON_CPU) && - __vcpu_write_sys_reg_to_cpu(val, reg)) + u64 (*xlate)(u64) = NULL; + unsigned int el1r; + + if (!vcpu_get_flag(vcpu, SYSREGS_ON_CPU)) + goto memory_write; + + if (unlikely(get_el2_to_el1_mapping(reg, &el1r, &xlate))) { + if (!is_hyp_ctxt(vcpu)) + goto memory_write; + + /* + * Always store a copy of the write to memory to avoid having + * to reverse-translate virtual EL2 system registers for a + * non-VHE guest hypervisor. + */ + __vcpu_sys_reg(vcpu, reg) = val; + + /* No EL1 counterpart? We're done here.? */ + if (reg == el1r) + return; + + if (!vcpu_el2_e2h_is_set(vcpu) && xlate) + val = xlate(val); + + /* Redirect this to the EL1 version of the register. */ + WARN_ON(!__vcpu_write_sys_reg_to_cpu(val, el1r)); + return; + } + + /* EL1 register can't be on the CPU if the guest is in vEL2. */ + if (unlikely(is_hyp_ctxt(vcpu))) + goto memory_write; + + if (__vcpu_write_sys_reg_to_cpu(val, reg)) return; - __vcpu_sys_reg(vcpu, reg) = val; +memory_write: + __vcpu_sys_reg(vcpu, reg) = val; } /* CSSELR values; used to index KVM_REG_ARM_DEMUX_ID_CCSIDR */ @@ -877,7 +1003,7 @@ static bool pmu_counter_idx_valid(struct kvm_vcpu *vcpu, u64 idx) u64 pmcr, val; pmcr = kvm_vcpu_read_pmcr(vcpu); - val = (pmcr >> ARMV8_PMU_PMCR_N_SHIFT) & ARMV8_PMU_PMCR_N_MASK; + val = FIELD_GET(ARMV8_PMU_PMCR_N, pmcr); if (idx >= val && idx != ARMV8_PMU_CYCLE_IDX) { kvm_inject_undefined(vcpu); return false; @@ -1143,7 +1269,7 @@ static int get_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, static int set_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, u64 val) { - u8 new_n = (val >> ARMV8_PMU_PMCR_N_SHIFT) & ARMV8_PMU_PMCR_N_MASK; + u8 new_n = FIELD_GET(ARMV8_PMU_PMCR_N, val); struct kvm *kvm = vcpu->kvm; mutex_lock(&kvm->arch.config_lock); @@ -1505,8 +1631,6 @@ static bool access_id_reg(struct kvm_vcpu *vcpu, return write_to_read_only(vcpu, p, r); p->regval = read_id_reg(vcpu, r); - if (vcpu_has_nv(vcpu)) - access_nested_id_reg(vcpu, p, r); return true; } @@ -1885,6 +2009,32 @@ static unsigned int el2_visibility(const struct kvm_vcpu *vcpu, return REG_HIDDEN; } +static bool bad_vncr_trap(struct kvm_vcpu *vcpu, + struct sys_reg_params *p, + const struct sys_reg_desc *r) +{ + /* + * We really shouldn't be here, and this is likely the result + * of a misconfigured trap, as this register should target the + * VNCR page, and nothing else. + */ + return bad_trap(vcpu, p, r, + "trap of VNCR-backed register"); +} + +static bool bad_redir_trap(struct kvm_vcpu *vcpu, + struct sys_reg_params *p, + const struct sys_reg_desc *r) +{ + /* + * We really shouldn't be here, and this is likely the result + * of a misconfigured trap, as this register should target the + * corresponding EL1, and nothing else. + */ + return bad_trap(vcpu, p, r, + "trap of EL2 register redirected to EL1"); +} + #define EL2_REG(name, acc, rst, v) { \ SYS_DESC(SYS_##name), \ .access = acc, \ @@ -1894,6 +2044,9 @@ static unsigned int el2_visibility(const struct kvm_vcpu *vcpu, .val = v, \ } +#define EL2_REG_VNCR(name, rst, v) EL2_REG(name, bad_vncr_trap, rst, v) +#define EL2_REG_REDIR(name, rst, v) EL2_REG(name, bad_redir_trap, rst, v) + /* * EL{0,1}2 registers are the EL2 view on an EL0 or EL1 register when * HCR_EL2.E2H==1, and only in the sysreg table for convenience of @@ -2508,32 +2661,33 @@ static const struct sys_reg_desc sys_reg_descs[] = { { PMU_SYS_REG(PMCCFILTR_EL0), .access = access_pmu_evtyper, .reset = reset_val, .reg = PMCCFILTR_EL0, .val = 0 }, - EL2_REG(VPIDR_EL2, access_rw, reset_unknown, 0), - EL2_REG(VMPIDR_EL2, access_rw, reset_unknown, 0), + EL2_REG_VNCR(VPIDR_EL2, reset_unknown, 0), + EL2_REG_VNCR(VMPIDR_EL2, reset_unknown, 0), EL2_REG(SCTLR_EL2, access_rw, reset_val, SCTLR_EL2_RES1), EL2_REG(ACTLR_EL2, access_rw, reset_val, 0), - EL2_REG(HCR_EL2, access_rw, reset_val, 0), + EL2_REG_VNCR(HCR_EL2, reset_val, 0), EL2_REG(MDCR_EL2, access_rw, reset_val, 0), EL2_REG(CPTR_EL2, access_rw, reset_val, CPTR_NVHE_EL2_RES1), - EL2_REG(HSTR_EL2, access_rw, reset_val, 0), - EL2_REG(HFGRTR_EL2, access_rw, reset_val, 0), - EL2_REG(HFGWTR_EL2, access_rw, reset_val, 0), - EL2_REG(HFGITR_EL2, access_rw, reset_val, 0), - EL2_REG(HACR_EL2, access_rw, reset_val, 0), + EL2_REG_VNCR(HSTR_EL2, reset_val, 0), + EL2_REG_VNCR(HFGRTR_EL2, reset_val, 0), + EL2_REG_VNCR(HFGWTR_EL2, reset_val, 0), + EL2_REG_VNCR(HFGITR_EL2, reset_val, 0), + EL2_REG_VNCR(HACR_EL2, reset_val, 0), - EL2_REG(HCRX_EL2, access_rw, reset_val, 0), + EL2_REG_VNCR(HCRX_EL2, reset_val, 0), EL2_REG(TTBR0_EL2, access_rw, reset_val, 0), EL2_REG(TTBR1_EL2, access_rw, reset_val, 0), EL2_REG(TCR_EL2, access_rw, reset_val, TCR_EL2_RES1), - EL2_REG(VTTBR_EL2, access_rw, reset_val, 0), - EL2_REG(VTCR_EL2, access_rw, reset_val, 0), + EL2_REG_VNCR(VTTBR_EL2, reset_val, 0), + EL2_REG_VNCR(VTCR_EL2, reset_val, 0), { SYS_DESC(SYS_DACR32_EL2), trap_undef, reset_unknown, DACR32_EL2 }, - EL2_REG(HDFGRTR_EL2, access_rw, reset_val, 0), - EL2_REG(HDFGWTR_EL2, access_rw, reset_val, 0), - EL2_REG(SPSR_EL2, access_rw, reset_val, 0), - EL2_REG(ELR_EL2, access_rw, reset_val, 0), + EL2_REG_VNCR(HDFGRTR_EL2, reset_val, 0), + EL2_REG_VNCR(HDFGWTR_EL2, reset_val, 0), + EL2_REG_VNCR(HAFGRTR_EL2, reset_val, 0), + EL2_REG_REDIR(SPSR_EL2, reset_val, 0), + EL2_REG_REDIR(ELR_EL2, reset_val, 0), { SYS_DESC(SYS_SP_EL1), access_sp_el1}, /* AArch32 SPSR_* are RES0 if trapped from a NV guest */ @@ -2549,10 +2703,10 @@ static const struct sys_reg_desc sys_reg_descs[] = { { SYS_DESC(SYS_IFSR32_EL2), trap_undef, reset_unknown, IFSR32_EL2 }, EL2_REG(AFSR0_EL2, access_rw, reset_val, 0), EL2_REG(AFSR1_EL2, access_rw, reset_val, 0), - EL2_REG(ESR_EL2, access_rw, reset_val, 0), + EL2_REG_REDIR(ESR_EL2, reset_val, 0), { SYS_DESC(SYS_FPEXC32_EL2), trap_undef, reset_val, FPEXC32_EL2, 0x700 }, - EL2_REG(FAR_EL2, access_rw, reset_val, 0), + EL2_REG_REDIR(FAR_EL2, reset_val, 0), EL2_REG(HPFAR_EL2, access_rw, reset_val, 0), EL2_REG(MAIR_EL2, access_rw, reset_val, 0), @@ -2565,24 +2719,9 @@ static const struct sys_reg_desc sys_reg_descs[] = { EL2_REG(CONTEXTIDR_EL2, access_rw, reset_val, 0), EL2_REG(TPIDR_EL2, access_rw, reset_val, 0), - EL2_REG(CNTVOFF_EL2, access_rw, reset_val, 0), + EL2_REG_VNCR(CNTVOFF_EL2, reset_val, 0), EL2_REG(CNTHCTL_EL2, access_rw, reset_val, 0), - EL12_REG(SCTLR, access_vm_reg, reset_val, 0x00C50078), - EL12_REG(CPACR, access_rw, reset_val, 0), - EL12_REG(TTBR0, access_vm_reg, reset_unknown, 0), - EL12_REG(TTBR1, access_vm_reg, reset_unknown, 0), - EL12_REG(TCR, access_vm_reg, reset_val, 0), - { SYS_DESC(SYS_SPSR_EL12), access_spsr}, - { SYS_DESC(SYS_ELR_EL12), access_elr}, - EL12_REG(AFSR0, access_vm_reg, reset_unknown, 0), - EL12_REG(AFSR1, access_vm_reg, reset_unknown, 0), - EL12_REG(ESR, access_vm_reg, reset_unknown, 0), - EL12_REG(FAR, access_vm_reg, reset_unknown, 0), - EL12_REG(MAIR, access_vm_reg, reset_unknown, 0), - EL12_REG(AMAIR, access_vm_reg, reset_amair_el1, 0), - EL12_REG(VBAR, access_rw, reset_val, 0), - EL12_REG(CONTEXTIDR, access_vm_reg, reset_val, 0), EL12_REG(CNTKCTL, access_rw, reset_val, 0), EL2_REG(SP_EL2, NULL, reset_unknown, 0), diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c index 2dad2d095160d8..e2764d0ffa9f32 100644 --- a/arch/arm64/kvm/vgic/vgic-its.c +++ b/arch/arm64/kvm/vgic/vgic-its.c @@ -590,7 +590,11 @@ static struct vgic_irq *vgic_its_check_cache(struct kvm *kvm, phys_addr_t db, unsigned long flags; raw_spin_lock_irqsave(&dist->lpi_list_lock, flags); + irq = __vgic_its_check_cache(dist, db, devid, eventid); + if (irq) + vgic_get_irq_kref(irq); + raw_spin_unlock_irqrestore(&dist->lpi_list_lock, flags); return irq; @@ -769,6 +773,7 @@ int vgic_its_inject_cached_translation(struct kvm *kvm, struct kvm_msi *msi) raw_spin_lock_irqsave(&irq->irq_lock, flags); irq->pending_latch = true; vgic_queue_irq_unlock(kvm, irq, flags); + vgic_put_irq(kvm, irq); return 0; } diff --git a/arch/arm64/kvm/vgic/vgic-mmio-v3.c b/arch/arm64/kvm/vgic/vgic-mmio-v3.c index a764b0ab8bf913..c15ee1df036a22 100644 --- a/arch/arm64/kvm/vgic/vgic-mmio-v3.c +++ b/arch/arm64/kvm/vgic/vgic-mmio-v3.c @@ -357,31 +357,13 @@ static int vgic_v3_uaccess_write_pending(struct kvm_vcpu *vcpu, gpa_t addr, unsigned int len, unsigned long val) { - u32 intid = VGIC_ADDR_TO_INTID(addr, 1); - int i; - unsigned long flags; - - for (i = 0; i < len * 8; i++) { - struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); - - raw_spin_lock_irqsave(&irq->irq_lock, flags); - if (test_bit(i, &val)) { - /* - * pending_latch is set irrespective of irq type - * (level or edge) to avoid dependency that VM should - * restore irq config before pending info. - */ - irq->pending_latch = true; - vgic_queue_irq_unlock(vcpu->kvm, irq, flags); - } else { - irq->pending_latch = false; - raw_spin_unlock_irqrestore(&irq->irq_lock, flags); - } + int ret; - vgic_put_irq(vcpu->kvm, irq); - } + ret = vgic_uaccess_write_spending(vcpu, addr, len, val); + if (ret) + return ret; - return 0; + return vgic_uaccess_write_cpending(vcpu, addr, len, ~val); } /* We want to avoid outer shareable. */ diff --git a/arch/arm64/kvm/vgic/vgic-mmio.c b/arch/arm64/kvm/vgic/vgic-mmio.c index ff558c05e990c7..cf76523a219456 100644 --- a/arch/arm64/kvm/vgic/vgic-mmio.c +++ b/arch/arm64/kvm/vgic/vgic-mmio.c @@ -301,9 +301,8 @@ static bool is_vgic_v2_sgi(struct kvm_vcpu *vcpu, struct vgic_irq *irq) vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2); } -void vgic_mmio_write_spending(struct kvm_vcpu *vcpu, - gpa_t addr, unsigned int len, - unsigned long val) +static void __set_pending(struct kvm_vcpu *vcpu, gpa_t addr, unsigned int len, + unsigned long val, bool is_user) { u32 intid = VGIC_ADDR_TO_INTID(addr, 1); int i; @@ -312,14 +311,22 @@ void vgic_mmio_write_spending(struct kvm_vcpu *vcpu, for_each_set_bit(i, &val, len * 8) { struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); - /* GICD_ISPENDR0 SGI bits are WI */ - if (is_vgic_v2_sgi(vcpu, irq)) { + /* GICD_ISPENDR0 SGI bits are WI when written from the guest. */ + if (is_vgic_v2_sgi(vcpu, irq) && !is_user) { vgic_put_irq(vcpu->kvm, irq); continue; } raw_spin_lock_irqsave(&irq->irq_lock, flags); + /* + * GICv2 SGIs are terribly broken. We can't restore + * the source of the interrupt, so just pick the vcpu + * itself as the source... + */ + if (is_vgic_v2_sgi(vcpu, irq)) + irq->source |= BIT(vcpu->vcpu_id); + if (irq->hw && vgic_irq_is_sgi(irq->intid)) { /* HW SGI? Ask the GIC to inject it */ int err; @@ -335,7 +342,7 @@ void vgic_mmio_write_spending(struct kvm_vcpu *vcpu, } irq->pending_latch = true; - if (irq->hw) + if (irq->hw && !is_user) vgic_irq_set_phys_active(irq, true); vgic_queue_irq_unlock(vcpu->kvm, irq, flags); @@ -343,33 +350,18 @@ void vgic_mmio_write_spending(struct kvm_vcpu *vcpu, } } +void vgic_mmio_write_spending(struct kvm_vcpu *vcpu, + gpa_t addr, unsigned int len, + unsigned long val) +{ + __set_pending(vcpu, addr, len, val, false); +} + int vgic_uaccess_write_spending(struct kvm_vcpu *vcpu, gpa_t addr, unsigned int len, unsigned long val) { - u32 intid = VGIC_ADDR_TO_INTID(addr, 1); - int i; - unsigned long flags; - - for_each_set_bit(i, &val, len * 8) { - struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); - - raw_spin_lock_irqsave(&irq->irq_lock, flags); - irq->pending_latch = true; - - /* - * GICv2 SGIs are terribly broken. We can't restore - * the source of the interrupt, so just pick the vcpu - * itself as the source... - */ - if (is_vgic_v2_sgi(vcpu, irq)) - irq->source |= BIT(vcpu->vcpu_id); - - vgic_queue_irq_unlock(vcpu->kvm, irq, flags); - - vgic_put_irq(vcpu->kvm, irq); - } - + __set_pending(vcpu, addr, len, val, true); return 0; } @@ -394,9 +386,9 @@ static void vgic_hw_irq_cpending(struct kvm_vcpu *vcpu, struct vgic_irq *irq) vgic_irq_set_phys_active(irq, false); } -void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu, - gpa_t addr, unsigned int len, - unsigned long val) +static void __clear_pending(struct kvm_vcpu *vcpu, + gpa_t addr, unsigned int len, + unsigned long val, bool is_user) { u32 intid = VGIC_ADDR_TO_INTID(addr, 1); int i; @@ -405,14 +397,22 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu, for_each_set_bit(i, &val, len * 8) { struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); - /* GICD_ICPENDR0 SGI bits are WI */ - if (is_vgic_v2_sgi(vcpu, irq)) { + /* GICD_ICPENDR0 SGI bits are WI when written from the guest. */ + if (is_vgic_v2_sgi(vcpu, irq) && !is_user) { vgic_put_irq(vcpu->kvm, irq); continue; } raw_spin_lock_irqsave(&irq->irq_lock, flags); + /* + * More fun with GICv2 SGIs! If we're clearing one of them + * from userspace, which source vcpu to clear? Let's not + * even think of it, and blow the whole set. + */ + if (is_vgic_v2_sgi(vcpu, irq)) + irq->source = 0; + if (irq->hw && vgic_irq_is_sgi(irq->intid)) { /* HW SGI? Ask the GIC to clear its pending bit */ int err; @@ -427,7 +427,7 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu, continue; } - if (irq->hw) + if (irq->hw && !is_user) vgic_hw_irq_cpending(vcpu, irq); else irq->pending_latch = false; @@ -437,33 +437,18 @@ void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu, } } +void vgic_mmio_write_cpending(struct kvm_vcpu *vcpu, + gpa_t addr, unsigned int len, + unsigned long val) +{ + __clear_pending(vcpu, addr, len, val, false); +} + int vgic_uaccess_write_cpending(struct kvm_vcpu *vcpu, gpa_t addr, unsigned int len, unsigned long val) { - u32 intid = VGIC_ADDR_TO_INTID(addr, 1); - int i; - unsigned long flags; - - for_each_set_bit(i, &val, len * 8) { - struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); - - raw_spin_lock_irqsave(&irq->irq_lock, flags); - /* - * More fun with GICv2 SGIs! If we're clearing one of them - * from userspace, which source vcpu to clear? Let's not - * even think of it, and blow the whole set. - */ - if (is_vgic_v2_sgi(vcpu, irq)) - irq->source = 0; - - irq->pending_latch = false; - - raw_spin_unlock_irqrestore(&irq->irq_lock, flags); - - vgic_put_irq(vcpu->kvm, irq); - } - + __clear_pending(vcpu, addr, len, val, true); return 0; } diff --git a/arch/arm64/lib/copy_page.S b/arch/arm64/lib/copy_page.S index c336d2ffdec559..6a56d7cf309da5 100644 --- a/arch/arm64/lib/copy_page.S +++ b/arch/arm64/lib/copy_page.S @@ -18,13 +18,6 @@ * x1 - src */ SYM_FUNC_START(__pi_copy_page) -alternative_if ARM64_HAS_NO_HW_PREFETCH - // Prefetch three cache lines ahead. - prfm pldl1strm, [x1, #128] - prfm pldl1strm, [x1, #256] - prfm pldl1strm, [x1, #384] -alternative_else_nop_endif - ldp x2, x3, [x1] ldp x4, x5, [x1, #16] ldp x6, x7, [x1, #32] @@ -39,10 +32,6 @@ alternative_else_nop_endif 1: tst x0, #(PAGE_SIZE - 1) -alternative_if ARM64_HAS_NO_HW_PREFETCH - prfm pldl1strm, [x1, #384] -alternative_else_nop_endif - stnp x2, x3, [x0, #-256] ldp x2, x3, [x1] stnp x4, x5, [x0, #16 - 256] diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c index 3cb101e8cb29ba..61886e43e3a10f 100644 --- a/arch/arm64/mm/dma-mapping.c +++ b/arch/arm64/mm/dma-mapping.c @@ -47,7 +47,7 @@ void arch_teardown_dma_ops(struct device *dev) #endif void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, - const struct iommu_ops *iommu, bool coherent) + bool coherent) { int cls = cache_line_size_of_cpu(); @@ -58,7 +58,7 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, ARCH_DMA_MINALIGN, cls); dev->dma_coherent = coherent; - if (iommu) + if (device_iommu_mapped(dev)) iommu_setup_dma_ops(dev, dma_base, dma_base + size - 1); xen_setup_dma_ops(dev); diff --git a/arch/arm64/mm/hugetlbpage.c b/arch/arm64/mm/hugetlbpage.c index f5aae342632cbf..8116ac599f801d 100644 --- a/arch/arm64/mm/hugetlbpage.c +++ b/arch/arm64/mm/hugetlbpage.c @@ -51,7 +51,7 @@ void __init arm64_hugetlb_cma_reserve(void) * page allocator. Just warn if there is any change * breaking this assumption. */ - WARN_ON(order <= MAX_ORDER); + WARN_ON(order <= MAX_PAGE_ORDER); hugetlb_cma_reserve(order); } #endif /* CONFIG_CMA */ diff --git a/arch/arm64/mm/kasan_init.c b/arch/arm64/mm/kasan_init.c index 555285ebd5af13..4c7ad574b946bf 100644 --- a/arch/arm64/mm/kasan_init.c +++ b/arch/arm64/mm/kasan_init.c @@ -170,6 +170,11 @@ asmlinkage void __init kasan_early_init(void) { BUILD_BUG_ON(KASAN_SHADOW_OFFSET != KASAN_SHADOW_END - (1UL << (64 - KASAN_SHADOW_SCALE_SHIFT))); + /* + * We cannot check the actual value of KASAN_SHADOW_START during build, + * as it depends on vabits_actual. As a best-effort approach, check + * potential values calculated based on VA_BITS and VA_BITS_MIN. + */ BUILD_BUG_ON(!IS_ALIGNED(_KASAN_SHADOW_START(VA_BITS), PGDIR_SIZE)); BUILD_BUG_ON(!IS_ALIGNED(_KASAN_SHADOW_START(VA_BITS_MIN), PGDIR_SIZE)); BUILD_BUG_ON(!IS_ALIGNED(KASAN_SHADOW_END, PGDIR_SIZE)); diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 15f6347d23b690..1ac7467d34c9c3 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -52,9 +52,6 @@ u64 vabits_actual __ro_after_init = VA_BITS_MIN; EXPORT_SYMBOL(vabits_actual); #endif -u64 kimage_vaddr __ro_after_init = (u64)&_text; -EXPORT_SYMBOL(kimage_vaddr); - u64 kimage_voffset __ro_after_init; EXPORT_SYMBOL(kimage_voffset); @@ -674,6 +671,9 @@ static int __init map_entry_trampoline(void) { int i; + if (!arm64_kernel_unmapped_at_el0()) + return 0; + pgprot_t prot = kernel_exec_prot(); phys_addr_t pa_start = __pa_symbol(__entry_tramp_text_start); diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c index 7d4af64e398286..8955da5c47cf77 100644 --- a/arch/arm64/net/bpf_jit_comp.c +++ b/arch/arm64/net/bpf_jit_comp.c @@ -1828,7 +1828,7 @@ static void restore_args(struct jit_ctx *ctx, int args_off, int nregs) * */ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, - struct bpf_tramp_links *tlinks, void *orig_call, + struct bpf_tramp_links *tlinks, void *func_addr, int nregs, u32 flags) { int i; @@ -1926,7 +1926,7 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, if (flags & BPF_TRAMP_F_IP_ARG) { /* save ip address of the traced function */ - emit_addr_mov_i64(A64_R(10), (const u64)orig_call, ctx); + emit_addr_mov_i64(A64_R(10), (const u64)func_addr, ctx); emit(A64_STR64I(A64_R(10), A64_SP, ip_off), ctx); } @@ -2026,18 +2026,10 @@ static int prepare_trampoline(struct jit_ctx *ctx, struct bpf_tramp_image *im, return ctx->idx; } -int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, - void *image_end, const struct btf_func_model *m, - u32 flags, struct bpf_tramp_links *tlinks, - void *orig_call) +static int btf_func_model_nregs(const struct btf_func_model *m) { - int i, ret; int nregs = m->nr_args; - int max_insns = ((long)image_end - (long)image) / AARCH64_INSN_SIZE; - struct jit_ctx ctx = { - .image = NULL, - .idx = 0, - }; + int i; /* extra registers needed for struct argument */ for (i = 0; i < MAX_BPF_FUNC_ARGS; i++) { @@ -2046,22 +2038,49 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, nregs += (m->arg_size[i] + 7) / 8 - 1; } + return nregs; +} + +int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags, + struct bpf_tramp_links *tlinks, void *func_addr) +{ + struct jit_ctx ctx = { + .image = NULL, + .idx = 0, + }; + struct bpf_tramp_image im; + int nregs, ret; + + nregs = btf_func_model_nregs(m); /* the first 8 registers are used for arguments */ if (nregs > 8) return -ENOTSUPP; - ret = prepare_trampoline(&ctx, im, tlinks, orig_call, nregs, flags); + ret = prepare_trampoline(&ctx, &im, tlinks, func_addr, nregs, flags); if (ret < 0) return ret; - if (ret > max_insns) - return -EFBIG; + return ret < 0 ? ret : ret * AARCH64_INSN_SIZE; +} - ctx.image = image; - ctx.idx = 0; +int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, + void *image_end, const struct btf_func_model *m, + u32 flags, struct bpf_tramp_links *tlinks, + void *func_addr) +{ + int ret, nregs; + struct jit_ctx ctx = { + .image = image, + .idx = 0, + }; + + nregs = btf_func_model_nregs(m); + /* the first 8 registers are used for arguments */ + if (nregs > 8) + return -ENOTSUPP; jit_fill_hole(image, (unsigned int)(image_end - image)); - ret = prepare_trampoline(&ctx, im, tlinks, orig_call, nregs, flags); + ret = prepare_trampoline(&ctx, im, tlinks, func_addr, nregs, flags); if (ret > 0 && validate_code(&ctx) < 0) ret = -EINVAL; diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps index b98c38288a9d35..b912b1409fc09a 100644 --- a/arch/arm64/tools/cpucaps +++ b/arch/arm64/tools/cpucaps @@ -37,10 +37,10 @@ HAS_GIC_PRIO_MASKING HAS_GIC_PRIO_RELAXED_SYNC HAS_HCX HAS_LDAPR +HAS_LPA2 HAS_LSE_ATOMICS HAS_MOPS HAS_NESTED_VIRT -HAS_NO_HW_PREFETCH HAS_PAN HAS_S1PIE HAS_RAS_EXTN @@ -84,7 +84,6 @@ WORKAROUND_2077057 WORKAROUND_2457168 WORKAROUND_2645198 WORKAROUND_2658417 -WORKAROUND_2966298 WORKAROUND_AMPERE_AC03_CPU_38 WORKAROUND_TRBE_OVERWRITE_FILL_MODE WORKAROUND_TSB_FLUSH_FAILURE @@ -100,3 +99,4 @@ WORKAROUND_NVIDIA_CARMEL_CNP WORKAROUND_QCOM_FALKOR_E1003 WORKAROUND_REPEAT_TLBI WORKAROUND_SPECULATIVE_AT +WORKAROUND_SPECULATIVE_UNPRIV_LOAD diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg index 96cbeeab4eec33..4c9b679343674a 100644 --- a/arch/arm64/tools/sysreg +++ b/arch/arm64/tools/sysreg @@ -1002,6 +1002,27 @@ UnsignedEnum 3:0 BT EndEnum EndSysreg +Sysreg ID_AA64PFR2_EL1 3 0 0 4 2 +Res0 63:36 +UnsignedEnum 35:32 FPMR + 0b0000 NI + 0b0001 IMP +EndEnum +Res0 31:12 +UnsignedEnum 11:8 MTEFAR + 0b0000 NI + 0b0001 IMP +EndEnum +UnsignedEnum 7:4 MTESTOREONLY + 0b0000 NI + 0b0001 IMP +EndEnum +UnsignedEnum 3:0 MTEPERM + 0b0000 NI + 0b0001 IMP +EndEnum +EndSysreg + Sysreg ID_AA64ZFR0_EL1 3 0 0 4 4 Res0 63:60 UnsignedEnum 59:56 F64MM @@ -1058,7 +1079,11 @@ UnsignedEnum 63 FA64 0b0 NI 0b1 IMP EndEnum -Res0 62:60 +Res0 62:61 +UnsignedEnum 60 LUTv2 + 0b0 NI + 0b1 IMP +EndEnum UnsignedEnum 59:56 SMEver 0b0000 SME 0b0001 SME2 @@ -1086,7 +1111,14 @@ UnsignedEnum 42 F16F16 0b0 NI 0b1 IMP EndEnum -Res0 41:40 +UnsignedEnum 41 F8F16 + 0b0 NI + 0b1 IMP +EndEnum +UnsignedEnum 40 F8F32 + 0b0 NI + 0b1 IMP +EndEnum UnsignedEnum 39:36 I8I32 0b0000 NI 0b1111 IMP @@ -1107,7 +1139,49 @@ UnsignedEnum 32 F32F32 0b0 NI 0b1 IMP EndEnum -Res0 31:0 +Res0 31 +UnsignedEnum 30 SF8FMA + 0b0 NI + 0b1 IMP +EndEnum +UnsignedEnum 29 SF8DP4 + 0b0 NI + 0b1 IMP +EndEnum +UnsignedEnum 28 SF8DP2 + 0b0 NI + 0b1 IMP +EndEnum +Res0 27:0 +EndSysreg + +Sysreg ID_AA64FPFR0_EL1 3 0 0 4 7 +Res0 63:32 +UnsignedEnum 31 F8CVT + 0b0 NI + 0b1 IMP +EndEnum +UnsignedEnum 30 F8FMA + 0b0 NI + 0b1 IMP +EndEnum +UnsignedEnum 29 F8DP4 + 0b0 NI + 0b1 IMP +EndEnum +UnsignedEnum 28 F8DP2 + 0b0 NI + 0b1 IMP +EndEnum +Res0 27:2 +UnsignedEnum 1 F8E4M3 + 0b0 NI + 0b1 IMP +EndEnum +UnsignedEnum 0 F8E5M2 + 0b0 NI + 0b1 IMP +EndEnum EndSysreg Sysreg ID_AA64DFR0_EL1 3 0 0 5 0 @@ -1115,7 +1189,10 @@ Enum 63:60 HPMN0 0b0000 UNPREDICTABLE 0b0001 DEF EndEnum -Res0 59:56 +UnsignedEnum 59:56 ExtTrcBuff + 0b0000 NI + 0b0001 IMP +EndEnum UnsignedEnum 55:52 BRBE 0b0000 NI 0b0001 IMP @@ -1327,6 +1404,7 @@ UnsignedEnum 11:8 API 0b0011 PAuth2 0b0100 FPAC 0b0101 FPACCOMBINE + 0b0110 PAuth_LR EndEnum UnsignedEnum 7:4 APA 0b0000 NI @@ -1335,6 +1413,7 @@ UnsignedEnum 7:4 APA 0b0011 PAuth2 0b0100 FPAC 0b0101 FPACCOMBINE + 0b0110 PAuth_LR EndEnum UnsignedEnum 3:0 DPB 0b0000 NI @@ -1344,7 +1423,14 @@ EndEnum EndSysreg Sysreg ID_AA64ISAR2_EL1 3 0 0 6 2 -Res0 63:56 +UnsignedEnum 63:60 ATS1A + 0b0000 NI + 0b0001 IMP +EndEnum +UnsignedEnum 59:56 LUT + 0b0000 NI + 0b0001 IMP +EndEnum UnsignedEnum 55:52 CSSC 0b0000 NI 0b0001 IMP @@ -1353,7 +1439,19 @@ UnsignedEnum 51:48 RPRFM 0b0000 NI 0b0001 IMP EndEnum -Res0 47:32 +Res0 47:44 +UnsignedEnum 43:40 PRFMSLC + 0b0000 NI + 0b0001 IMP +EndEnum +UnsignedEnum 39:36 SYSINSTR_128 + 0b0000 NI + 0b0001 IMP +EndEnum +UnsignedEnum 35:32 SYSREG_128 + 0b0000 NI + 0b0001 IMP +EndEnum UnsignedEnum 31:28 CLRBHB 0b0000 NI 0b0001 IMP @@ -1377,6 +1475,7 @@ UnsignedEnum 15:12 APA3 0b0011 PAuth2 0b0100 FPAC 0b0101 FPACCOMBINE + 0b0110 PAuth_LR EndEnum UnsignedEnum 11:8 GPA3 0b0000 NI @@ -1392,6 +1491,23 @@ UnsignedEnum 3:0 WFxT EndEnum EndSysreg +Sysreg ID_AA64ISAR3_EL1 3 0 0 6 3 +Res0 63:12 +UnsignedEnum 11:8 TLBIW + 0b0000 NI + 0b0001 IMP +EndEnum +UnsignedEnum 7:4 FAMINMAX + 0b0000 NI + 0b0001 IMP +EndEnum +UnsignedEnum 3:0 CPA + 0b0000 NI + 0b0001 IMP + 0b0010 CPA2 +EndEnum +EndSysreg + Sysreg ID_AA64MMFR0_EL1 3 0 0 7 0 UnsignedEnum 63:60 ECV 0b0000 NI @@ -1680,7 +1796,8 @@ Field 63 TIDCP Field 62 SPINTMASK Field 61 NMI Field 60 EnTP2 -Res0 59:58 +Field 59 TCSO +Field 58 TCSO0 Field 57 EPAN Field 56 EnALS Field 55 EnAS0 @@ -1709,7 +1826,7 @@ EndEnum Field 37 ITFSB Field 36 BT1 Field 35 BT0 -Res0 34 +Field 34 EnFPM Field 33 MSCEn Field 32 CMOW Field 31 EnIA @@ -1747,7 +1864,8 @@ Field 0 M EndSysreg SysregFields CPACR_ELx -Res0 63:29 +Res0 63:30 +Field 29 E0POE Field 28 TTA Res0 27:26 Field 25:24 SMEN @@ -1790,6 +1908,41 @@ Sysreg SMCR_EL1 3 0 1 2 6 Fields SMCR_ELx EndSysreg +SysregFields GCSCR_ELx +Res0 63:10 +Field 9 STREn +Field 8 PUSHMEn +Res0 7 +Field 6 EXLOCKEN +Field 5 RVCHKEN +Res0 4:1 +Field 0 PCRSEL +EndSysregFields + +Sysreg GCSCR_EL1 3 0 2 5 0 +Fields GCSCR_ELx +EndSysreg + +SysregFields GCSPR_ELx +Field 63:3 PTR +Res0 2:0 +EndSysregFields + +Sysreg GCSPR_EL1 3 0 2 5 1 +Fields GCSPR_ELx +EndSysreg + +Sysreg GCSCRE0_EL1 3 0 2 5 2 +Res0 63:11 +Field 10 nTR +Field 9 STREn +Field 8 PUSHMEn +Res0 7:6 +Field 5 RVCHKEN +Res0 4:1 +Field 0 PCRSEL +EndSysreg + Sysreg ALLINT 3 0 4 3 0 Res0 63:14 Field 13 ALLINT @@ -1933,10 +2086,18 @@ Sysreg CONTEXTIDR_EL1 3 0 13 0 1 Fields CONTEXTIDR_ELx EndSysreg +Sysreg RCWSMASK_EL1 3 0 13 0 3 +Field 63:0 RCWSMASK +EndSysreg + Sysreg TPIDR_EL1 3 0 13 0 4 Field 63:0 ThreadID EndSysreg +Sysreg RCWMASK_EL1 3 0 13 0 6 +Field 63:0 RCWMASK +EndSysreg + Sysreg SCXTNUM_EL1 3 0 13 0 7 Field 63:0 SoftwareContextNumber EndSysreg @@ -2004,9 +2165,10 @@ Field 27:24 CWG Field 23:20 ERG Field 19:16 DminLine Enum 15:14 L1Ip - 0b00 VPIPT + # This was named as VPIPT in the ARM but now documented as reserved + 0b00 RESERVED_VPIPT # This is named as AIVIVT in the ARM but documented as reserved - 0b01 RESERVED + 0b01 RESERVED_AIVIVT 0b10 VIPT 0b11 PIPT EndEnum @@ -2020,12 +2182,39 @@ Field 4 DZP Field 3:0 BS EndSysreg +Sysreg GCSPR_EL0 3 3 2 5 1 +Fields GCSPR_ELx +EndSysreg + Sysreg SVCR 3 3 4 2 2 Res0 63:2 Field 1 ZA Field 0 SM EndSysreg +Sysreg FPMR 3 3 4 4 2 +Res0 63:38 +Field 37:32 LSCALE2 +Field 31:24 NSCALE +Res0 23 +Field 22:16 LSCALE +Field 15 OSC +Field 14 OSM +Res0 13:9 +UnsignedEnum 8:6 F8D + 0b000 E5M2 + 0b001 E4M3 +EndEnum +UnsignedEnum 5:3 F8S2 + 0b000 E5M2 + 0b001 E4M3 +EndEnum +UnsignedEnum 2:0 F8S1 + 0b000 E5M2 + 0b001 E4M3 +EndEnum +EndSysreg + SysregFields HFGxTR_EL2 Field 63 nAMAIR2_EL1 Field 62 nMAIR2_EL1 @@ -2102,7 +2291,9 @@ Fields HFGxTR_EL2 EndSysreg Sysreg HFGITR_EL2 3 4 1 1 6 -Res0 63:61 +Res0 63 +Field 62 ATS1E1A +Res0 61 Field 60 COSPRCTX Field 59 nGCSEPP Field 58 nGCSSTR_EL1 @@ -2295,12 +2486,57 @@ Field 1 DBGBVRn_EL1 Field 0 DBGBCRn_EL1 EndSysreg +Sysreg HAFGRTR_EL2 3 4 3 1 6 +Res0 63:50 +Field 49 AMEVTYPER115_EL0 +Field 48 AMEVCNTR115_EL0 +Field 47 AMEVTYPER114_EL0 +Field 46 AMEVCNTR114_EL0 +Field 45 AMEVTYPER113_EL0 +Field 44 AMEVCNTR113_EL0 +Field 43 AMEVTYPER112_EL0 +Field 42 AMEVCNTR112_EL0 +Field 41 AMEVTYPER111_EL0 +Field 40 AMEVCNTR111_EL0 +Field 39 AMEVTYPER110_EL0 +Field 38 AMEVCNTR110_EL0 +Field 37 AMEVTYPER19_EL0 +Field 36 AMEVCNTR19_EL0 +Field 35 AMEVTYPER18_EL0 +Field 34 AMEVCNTR18_EL0 +Field 33 AMEVTYPER17_EL0 +Field 32 AMEVCNTR17_EL0 +Field 31 AMEVTYPER16_EL0 +Field 30 AMEVCNTR16_EL0 +Field 29 AMEVTYPER15_EL0 +Field 28 AMEVCNTR15_EL0 +Field 27 AMEVTYPER14_EL0 +Field 26 AMEVCNTR14_EL0 +Field 25 AMEVTYPER13_EL0 +Field 24 AMEVCNTR13_EL0 +Field 23 AMEVTYPER12_EL0 +Field 22 AMEVCNTR12_EL0 +Field 21 AMEVTYPER11_EL0 +Field 20 AMEVCNTR11_EL0 +Field 19 AMEVTYPER10_EL0 +Field 18 AMEVCNTR10_EL0 +Field 17 AMCNTEN1 +Res0 16:5 +Field 4 AMEVCNTR03_EL0 +Field 3 AMEVCNTR02_EL0 +Field 2 AMEVCNTR01_EL0 +Field 1 AMEVCNTR00_EL0 +Field 0 AMCNTEN0 +EndSysreg + Sysreg ZCR_EL2 3 4 1 2 0 Fields ZCR_ELx EndSysreg Sysreg HCRX_EL2 3 4 1 2 2 -Res0 63:23 +Res0 63:25 +Field 24 PACMEn +Field 23 EnFPM Field 22 GCSEn Field 21 EnIDCP128 Field 20 EnSDERR @@ -2348,6 +2584,14 @@ Sysreg SMCR_EL2 3 4 1 2 6 Fields SMCR_ELx EndSysreg +Sysreg GCSCR_EL2 3 4 2 5 0 +Fields GCSCR_ELx +EndSysreg + +Sysreg GCSPR_EL2 3 4 2 5 1 +Fields GCSPR_ELx +EndSysreg + Sysreg DACR32_EL2 3 4 3 0 0 Res0 63:32 Field 31:30 D15 @@ -2407,6 +2651,14 @@ Sysreg SMCR_EL12 3 5 1 2 6 Fields SMCR_ELx EndSysreg +Sysreg GCSCR_EL12 3 5 2 5 0 +Fields GCSCR_ELx +EndSysreg + +Sysreg GCSPR_EL12 3 5 2 5 1 +Fields GCSPR_ELx +EndSysreg + Sysreg FAR_EL12 3 5 6 0 0 Field 63:0 ADDR EndSysreg @@ -2471,6 +2723,33 @@ Field 1 PIE Field 0 PnCH EndSysreg +SysregFields MAIR2_ELx +Field 63:56 Attr7 +Field 55:48 Attr6 +Field 47:40 Attr5 +Field 39:32 Attr4 +Field 31:24 Attr3 +Field 23:16 Attr2 +Field 15:8 Attr1 +Field 7:0 Attr0 +EndSysregFields + +Sysreg MAIR2_EL1 3 0 10 2 1 +Fields MAIR2_ELx +EndSysreg + +Sysreg MAIR2_EL2 3 4 10 1 1 +Fields MAIR2_ELx +EndSysreg + +Sysreg AMAIR2_EL1 3 0 10 3 1 +Field 63:0 ImpDef +EndSysreg + +Sysreg AMAIR2_EL2 3 4 10 3 1 +Field 63:0 ImpDef +EndSysreg + SysregFields PIRx_ELx Field 63:60 Perm15 Field 59:56 Perm14 @@ -2510,6 +2789,26 @@ Sysreg PIR_EL2 3 4 10 2 3 Fields PIRx_ELx EndSysreg +Sysreg POR_EL0 3 3 10 2 4 +Fields PIRx_ELx +EndSysreg + +Sysreg POR_EL1 3 0 10 2 4 +Fields PIRx_ELx +EndSysreg + +Sysreg POR_EL12 3 5 10 2 4 +Fields PIRx_ELx +EndSysreg + +Sysreg S2POR_EL1 3 0 10 2 5 +Fields PIRx_ELx +EndSysreg + +Sysreg S2PIR_EL2 3 4 10 2 5 +Fields PIRx_ELx +EndSysreg + Sysreg LORSA_EL1 3 0 10 4 0 Res0 63:52 Field 51:16 SA diff --git a/arch/csky/abiv1/inc/abi/cacheflush.h b/arch/csky/abiv1/inc/abi/cacheflush.h index 908d8b0bc4fdc6..d011a81575d21e 100644 --- a/arch/csky/abiv1/inc/abi/cacheflush.h +++ b/arch/csky/abiv1/inc/abi/cacheflush.h @@ -43,6 +43,7 @@ static inline void flush_anon_page(struct vm_area_struct *vma, */ extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end); #define flush_cache_vmap(start, end) cache_wbinv_all() +#define flush_cache_vmap_early(start, end) do { } while (0) #define flush_cache_vunmap(start, end) cache_wbinv_all() #define flush_icache_range(start, end) cache_wbinv_range(start, end) diff --git a/arch/csky/abiv2/inc/abi/cacheflush.h b/arch/csky/abiv2/inc/abi/cacheflush.h index 40be16907267d6..6513ac5d257888 100644 --- a/arch/csky/abiv2/inc/abi/cacheflush.h +++ b/arch/csky/abiv2/inc/abi/cacheflush.h @@ -41,6 +41,7 @@ void flush_icache_mm_range(struct mm_struct *mm, void flush_icache_deferred(struct mm_struct *mm); #define flush_cache_vmap(start, end) do { } while (0) +#define flush_cache_vmap_early(start, end) do { } while (0) #define flush_cache_vunmap(start, end) do { } while (0) #define copy_to_user_page(vma, page, vaddr, dst, src, len) \ diff --git a/arch/csky/configs/defconfig b/arch/csky/configs/defconfig index af722e4dfb47d8..ff559e5162aa1c 100644 --- a/arch/csky/configs/defconfig +++ b/arch/csky/configs/defconfig @@ -34,7 +34,8 @@ CONFIG_GENERIC_PHY=y CONFIG_EXT4_FS=y CONFIG_FANOTIFY=y CONFIG_QUOTA=y -CONFIG_FSCACHE=m +CONFIG_NETFS_SUPPORT=m +CONFIG_FSCACHE=y CONFIG_FSCACHE_STATS=y CONFIG_CACHEFILES=m CONFIG_MSDOS_FS=y diff --git a/arch/csky/include/asm/ftrace.h b/arch/csky/include/asm/ftrace.h index 9b86341731b69f..fd215c38ef2775 100644 --- a/arch/csky/include/asm/ftrace.h +++ b/arch/csky/include/asm/ftrace.h @@ -26,5 +26,9 @@ static inline unsigned long ftrace_call_adjust(unsigned long addr) struct dyn_arch_ftrace { }; + +void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, + unsigned long frame_pointer); + #endif /* !__ASSEMBLY__ */ #endif /* __ASM_CSKY_FTRACE_H */ diff --git a/arch/csky/include/asm/irq_work.h b/arch/csky/include/asm/irq_work.h index 33aaf39d6f94f6..d39fcc1f5395f6 100644 --- a/arch/csky/include/asm/irq_work.h +++ b/arch/csky/include/asm/irq_work.h @@ -7,5 +7,5 @@ static inline bool arch_irq_work_has_interrupt(void) { return true; } -extern void arch_irq_work_raise(void); + #endif /* __ASM_CSKY_IRQ_WORK_H */ diff --git a/arch/csky/include/asm/jump_label.h b/arch/csky/include/asm/jump_label.h index d488ba6084bc6b..98a3f4b168bd26 100644 --- a/arch/csky/include/asm/jump_label.h +++ b/arch/csky/include/asm/jump_label.h @@ -43,5 +43,10 @@ label: return true; } +enum jump_label_type; +void arch_jump_label_transform_static(struct jump_entry *entry, + enum jump_label_type type); +#define arch_jump_label_transform_static arch_jump_label_transform_static + #endif /* __ASSEMBLY__ */ #endif /* __ASM_CSKY_JUMP_LABEL_H */ diff --git a/arch/csky/include/asm/traps.h b/arch/csky/include/asm/traps.h index 732c4aaa2e2601..6bbbbe43165f24 100644 --- a/arch/csky/include/asm/traps.h +++ b/arch/csky/include/asm/traps.h @@ -55,6 +55,6 @@ asmlinkage void trap_c(struct pt_regs *regs); asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags); -void trap_init(void); +asmlinkage void do_page_fault(struct pt_regs *regs); #endif /* __ASM_CSKY_TRAPS_H */ diff --git a/arch/csky/kernel/traps.c b/arch/csky/kernel/traps.c index 6e426fba01193b..c2246b07cc9c16 100644 --- a/arch/csky/kernel/traps.c +++ b/arch/csky/kernel/traps.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. +#include #include #include #include diff --git a/arch/csky/kernel/vdso/vgettimeofday.c b/arch/csky/kernel/vdso/vgettimeofday.c index c4831145eed55b..55af30e8375288 100644 --- a/arch/csky/kernel/vdso/vgettimeofday.c +++ b/arch/csky/kernel/vdso/vgettimeofday.c @@ -2,36 +2,27 @@ #include #include +#include extern -int __vdso_clock_gettime(clockid_t clock, - struct old_timespec32 *ts); int __vdso_clock_gettime(clockid_t clock, struct old_timespec32 *ts) { return __cvdso_clock_gettime32(clock, ts); } -int __vdso_clock_gettime64(clockid_t clock, - struct __kernel_timespec *ts); int __vdso_clock_gettime64(clockid_t clock, struct __kernel_timespec *ts) { return __cvdso_clock_gettime(clock, ts); } -extern -int __vdso_gettimeofday(struct __kernel_old_timeval *tv, - struct timezone *tz); int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz) { return __cvdso_gettimeofday(tv, tz); } -extern -int __vdso_clock_getres(clockid_t clock_id, - struct old_timespec32 *res); int __vdso_clock_getres(clockid_t clock_id, struct old_timespec32 *res) { diff --git a/arch/hexagon/include/asm/io.h b/arch/hexagon/include/asm/io.h index e2b308e32a379d..522d321ea85a75 100644 --- a/arch/hexagon/include/asm/io.h +++ b/arch/hexagon/include/asm/io.h @@ -58,12 +58,6 @@ static inline void *phys_to_virt(unsigned long address) return __va(address); } -/* - * convert a physical pointer to a virtual kernel pointer for - * /dev/mem access. - */ -#define xlate_dev_mem_ptr(p) __va(p) - /* * IO port access primitives. Hexagon doesn't have special IO access * instructions; all I/O is memory mapped. @@ -174,9 +168,6 @@ static inline void writel(u32 data, volatile void __iomem *addr) #define _PAGE_IOREMAP (_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \ (__HEXAGON_C_DEV << 6)) -#define ioremap_uc(addr, size) ioremap((addr), (size)) - - #define __raw_writel writel static inline void memcpy_fromio(void *dst, const volatile void __iomem *src, diff --git a/arch/hexagon/include/asm/irq.h b/arch/hexagon/include/asm/irq.h index 1f7f1292f70124..a60d26754caae9 100644 --- a/arch/hexagon/include/asm/irq.h +++ b/arch/hexagon/include/asm/irq.h @@ -20,4 +20,7 @@ #include +struct pt_regs; +void arch_do_IRQ(struct pt_regs *); + #endif diff --git a/arch/hexagon/include/asm/page.h b/arch/hexagon/include/asm/page.h index 9c03b9965f07a0..10f1bc07423ccf 100644 --- a/arch/hexagon/include/asm/page.h +++ b/arch/hexagon/include/asm/page.h @@ -78,6 +78,9 @@ typedef struct page *pgtable_t; #define __pgd(x) ((pgd_t) { (x) }) #define __pgprot(x) ((pgprot_t) { (x) }) +/* Needed for PAGE_OFFSET used in the macro right below */ +#include + /* * We need a __pa and a __va routine for kernel space. * MIPS says they're only used during mem_init. @@ -125,8 +128,16 @@ static inline void clear_page(void *page) */ #define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) -#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT) -#define pfn_to_virt(pfn) __va((pfn) << PAGE_SHIFT) +static inline unsigned long virt_to_pfn(const void *kaddr) +{ + return __pa(kaddr) >> PAGE_SHIFT; +} + +static inline void *pfn_to_virt(unsigned long pfn) +{ + return (void *)((unsigned long)__va(pfn) << PAGE_SHIFT); +} + #define page_to_virt(page) __va(page_to_phys(page)) diff --git a/arch/hexagon/include/uapi/asm/user.h b/arch/hexagon/include/uapi/asm/user.h index 7327ec59b22f54..abae6a4b58137f 100644 --- a/arch/hexagon/include/uapi/asm/user.h +++ b/arch/hexagon/include/uapi/asm/user.h @@ -56,15 +56,10 @@ struct user_regs_struct { unsigned long pc; unsigned long cause; unsigned long badva; -#if CONFIG_HEXAGON_ARCH_VERSION < 4 - unsigned long pad1; /* pad out to 48 words total */ - unsigned long pad2; /* pad out to 48 words total */ - unsigned long pad3; /* pad out to 48 words total */ -#else + /* cs0 and cs1 are only available with HEXAGON_ARCH_VERSION >= 4 */ unsigned long cs0; unsigned long cs1; unsigned long pad1; /* pad out to 48 words total */ -#endif }; #endif diff --git a/arch/hexagon/kernel/process.c b/arch/hexagon/kernel/process.c index dd7f74ea2c2040..2a77bfd7569450 100644 --- a/arch/hexagon/kernel/process.c +++ b/arch/hexagon/kernel/process.c @@ -5,6 +5,7 @@ * Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. */ +#include #include #include #include @@ -152,6 +153,7 @@ unsigned long __get_wchan(struct task_struct *p) * Returns 0 if there's no need to re-check for more work. */ +int do_work_pending(struct pt_regs *regs, u32 thread_info_flags); int do_work_pending(struct pt_regs *regs, u32 thread_info_flags) { if (!(thread_info_flags & _TIF_WORK_MASK)) { diff --git a/arch/hexagon/kernel/ptrace.c b/arch/hexagon/kernel/ptrace.c index 125f19995b76e5..905b06790ab70e 100644 --- a/arch/hexagon/kernel/ptrace.c +++ b/arch/hexagon/kernel/ptrace.c @@ -74,7 +74,7 @@ static int genregs_set(struct task_struct *target, unsigned int pos, unsigned int count, const void *kbuf, const void __user *ubuf) { - int ret; + int ret, ignore_offset; unsigned long bucket; struct pt_regs *regs = task_pt_regs(target); @@ -111,12 +111,15 @@ static int genregs_set(struct task_struct *target, #if CONFIG_HEXAGON_ARCH_VERSION >=4 INEXT(®s->cs0, cs0); INEXT(®s->cs1, cs1); + ignore_offset = offsetof(struct user_regs_struct, pad1); +#else + ignore_offset = offsetof(struct user_regs_struct, cs0); #endif /* Ignore the rest, if needed */ if (!ret) user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, - offsetof(struct user_regs_struct, pad1), -1); + ignore_offset, -1); else return ret; diff --git a/arch/hexagon/kernel/reset.c b/arch/hexagon/kernel/reset.c index da36114d928f05..efd70a8d25265e 100644 --- a/arch/hexagon/kernel/reset.c +++ b/arch/hexagon/kernel/reset.c @@ -3,6 +3,7 @@ * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. */ +#include #include #include diff --git a/arch/hexagon/kernel/signal.c b/arch/hexagon/kernel/signal.c index bcba31e9e0aebc..d301f4621553ad 100644 --- a/arch/hexagon/kernel/signal.c +++ b/arch/hexagon/kernel/signal.c @@ -220,7 +220,7 @@ no_restart: * Architecture-specific wrappers for signal-related system calls */ -asmlinkage int sys_rt_sigreturn(void) +SYSCALL_DEFINE0(rt_sigreturn) { struct pt_regs *regs = current_pt_regs(); struct rt_sigframe __user *frame; diff --git a/arch/hexagon/kernel/smp.c b/arch/hexagon/kernel/smp.c index 4e8bee25b8c682..608884bc339676 100644 --- a/arch/hexagon/kernel/smp.c +++ b/arch/hexagon/kernel/smp.c @@ -79,7 +79,7 @@ void smp_vm_unmask_irq(void *info) * Specifically, first arg is irq, second is the irq_desc. */ -irqreturn_t handle_ipi(int irq, void *desc) +static irqreturn_t handle_ipi(int irq, void *desc) { int cpu = smp_processor_id(); struct ipi_data *ipi = &per_cpu(ipi_data, cpu); @@ -124,7 +124,7 @@ void __init smp_prepare_boot_cpu(void) * to point to current thread info */ -void start_secondary(void) +static void start_secondary(void) { unsigned long thread_ptr; unsigned int cpu, irq; diff --git a/arch/hexagon/kernel/time.c b/arch/hexagon/kernel/time.c index febc95714d756d..f0f207e2a69477 100644 --- a/arch/hexagon/kernel/time.c +++ b/arch/hexagon/kernel/time.c @@ -17,7 +17,9 @@ #include #include +#include #include +#include #define TIMER_ENABLE BIT(0) @@ -160,7 +162,7 @@ static irqreturn_t timer_interrupt(int irq, void *devid) * This runs just before the delay loop is calibrated, and * is used for delay calibration. */ -void __init time_init_deferred(void) +static void __init time_init_deferred(void) { struct resource *resource = NULL; struct clock_event_device *ce_dev = &hexagon_clockevent_dev; diff --git a/arch/hexagon/kernel/traps.c b/arch/hexagon/kernel/traps.c index 6447763ce5a941..75e062722d285b 100644 --- a/arch/hexagon/kernel/traps.c +++ b/arch/hexagon/kernel/traps.c @@ -281,6 +281,7 @@ static void cache_error(struct pt_regs *regs) /* * General exception handler */ +void do_genex(struct pt_regs *regs); void do_genex(struct pt_regs *regs) { /* @@ -331,13 +332,7 @@ void do_genex(struct pt_regs *regs) } } -/* Indirect system call dispatch */ -long sys_syscall(void) -{ - printk(KERN_ERR "sys_syscall invoked!\n"); - return -ENOSYS; -} - +void do_trap0(struct pt_regs *regs); void do_trap0(struct pt_regs *regs) { syscall_fn syscall; @@ -415,6 +410,7 @@ void do_trap0(struct pt_regs *regs) /* * Machine check exception handler */ +void do_machcheck(struct pt_regs *regs); void do_machcheck(struct pt_regs *regs) { /* Halt and catch fire */ @@ -425,6 +421,7 @@ void do_machcheck(struct pt_regs *regs) * Treat this like the old 0xdb trap. */ +void do_debug_exception(struct pt_regs *regs); void do_debug_exception(struct pt_regs *regs) { regs->hvmer.vmest &= ~HVM_VMEST_CAUSE_MSK; diff --git a/arch/hexagon/kernel/vdso.c b/arch/hexagon/kernel/vdso.c index b70970ac809f9a..2e4872d6212464 100644 --- a/arch/hexagon/kernel/vdso.c +++ b/arch/hexagon/kernel/vdso.c @@ -10,6 +10,7 @@ #include #include +#include #include static struct page *vdso_page; diff --git a/arch/hexagon/kernel/vm_events.c b/arch/hexagon/kernel/vm_events.c index 59ef72e4a4e53f..2b881a89b2066f 100644 --- a/arch/hexagon/kernel/vm_events.c +++ b/arch/hexagon/kernel/vm_events.c @@ -73,13 +73,6 @@ void show_regs(struct pt_regs *regs) pt_psp(regs), pt_badva(regs), ints_enabled(regs)); } -void dummy_handler(struct pt_regs *regs) -{ - unsigned int elr = pt_elr(regs); - printk(KERN_ERR "Unimplemented handler; ELR=0x%08x\n", elr); -} - - void arch_do_IRQ(struct pt_regs *regs) { int irq = pt_cause(regs); diff --git a/arch/hexagon/mm/init.c b/arch/hexagon/mm/init.c index 146115c9de6177..3458f39ca2ac20 100644 --- a/arch/hexagon/mm/init.c +++ b/arch/hexagon/mm/init.c @@ -12,6 +12,7 @@ #include #include #include +#include #include /* @@ -86,7 +87,7 @@ void sync_icache_dcache(pte_t pte) * In this mode, we only have one pg_data_t * structure: contig_mem_data. */ -void __init paging_init(void) +static void __init paging_init(void) { unsigned long max_zone_pfn[MAX_NR_ZONES] = {0, }; diff --git a/arch/hexagon/mm/uaccess.c b/arch/hexagon/mm/uaccess.c index 650bca92f0b750..3204e9ba6d6f06 100644 --- a/arch/hexagon/mm/uaccess.c +++ b/arch/hexagon/mm/uaccess.c @@ -35,11 +35,3 @@ __kernel_size_t __clear_user_hexagon(void __user *dest, unsigned long count) return count; } - -unsigned long clear_user_hexagon(void __user *dest, unsigned long count) -{ - if (!access_ok(dest, count)) - return count; - else - return __clear_user_hexagon(dest, count); -} diff --git a/arch/hexagon/mm/vm_fault.c b/arch/hexagon/mm/vm_fault.c index 7295ea3f8cc8d3..3771fb453898cd 100644 --- a/arch/hexagon/mm/vm_fault.c +++ b/arch/hexagon/mm/vm_fault.c @@ -12,6 +12,7 @@ */ #include +#include #include #include #include @@ -33,7 +34,7 @@ /* * Canonical page fault handler */ -void do_page_fault(unsigned long address, long cause, struct pt_regs *regs) +static void do_page_fault(unsigned long address, long cause, struct pt_regs *regs) { struct vm_area_struct *vma; struct mm_struct *mm = current->mm; diff --git a/arch/hexagon/mm/vm_tlb.c b/arch/hexagon/mm/vm_tlb.c index 53482f2a9ff941..8b6405e2234bb9 100644 --- a/arch/hexagon/mm/vm_tlb.c +++ b/arch/hexagon/mm/vm_tlb.c @@ -14,6 +14,7 @@ #include #include #include +#include /* * Initial VM implementation has only one map active at a time, with diff --git a/arch/loongarch/Kbuild b/arch/loongarch/Kbuild index beb8499dd8ed84..bfa21465d83afc 100644 --- a/arch/loongarch/Kbuild +++ b/arch/loongarch/Kbuild @@ -4,6 +4,7 @@ obj-y += net/ obj-y += vdso/ obj-$(CONFIG_KVM) += kvm/ +obj-$(CONFIG_BUILTIN_DTB) += boot/dts/ # for cleaning subdir- += boot diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig index ee123820a4760a..10959e6c358325 100644 --- a/arch/loongarch/Kconfig +++ b/arch/loongarch/Kconfig @@ -5,6 +5,7 @@ config LOONGARCH select ACPI select ACPI_GENERIC_GSI if ACPI select ACPI_MCFG if ACPI + select ACPI_HOTPLUG_CPU if ACPI_PROCESSOR && HOTPLUG_CPU select ACPI_PPTT if ACPI select ACPI_SYSTEM_POWER_STATES_SUPPORT if ACPI select ARCH_BINFMT_ELF_STATE @@ -71,6 +72,7 @@ config LOONGARCH select GENERIC_CLOCKEVENTS select GENERIC_CMOS_UPDATE select GENERIC_CPU_AUTOPROBE + select GENERIC_CPU_DEVICES select GENERIC_ENTRY select GENERIC_GETTIMEOFDAY select GENERIC_IOREMAP if !ARCH_IOREMAP @@ -140,6 +142,7 @@ config LOONGARCH select HAVE_REGS_AND_STACK_ACCESS_API select HAVE_RETHOOK select HAVE_RSEQ + select HAVE_RUST select HAVE_SAMPLE_FTRACE_DIRECT select HAVE_SAMPLE_FTRACE_DIRECT_MULTI select HAVE_SETUP_PER_CPU_AREA if NUMA @@ -374,6 +377,24 @@ config CMDLINE_FORCE endchoice +config BUILTIN_DTB + bool "Enable built-in dtb in kernel" + depends on OF + help + Some existing systems do not provide a canonical device tree to + the kernel at boot time. Let's provide a device tree table in the + kernel, keyed by the dts filename, containing the relevant DTBs. + + Built-in DTBs are generic enough and can be used as references. + +config BUILTIN_DTB_NAME + string "Source file for built-in dtb" + depends on BUILTIN_DTB + help + Base name (without suffix, relative to arch/loongarch/boot/dts/) + for the DTS file that will be used to produce the DTB linked into + the kernel. + config DMI bool "Enable DMI scanning" select DMI_SCAN_MACHINE_NON_EFI_FALLBACK @@ -575,6 +596,9 @@ config ARCH_SELECTS_CRASH_DUMP depends on CRASH_DUMP select RELOCATABLE +config ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION + def_bool CRASH_CORE + config RELOCATABLE bool "Relocatable kernel" help diff --git a/arch/loongarch/Makefile b/arch/loongarch/Makefile index 4ba8d67ddb0977..983aa2b1629a69 100644 --- a/arch/loongarch/Makefile +++ b/arch/loongarch/Makefile @@ -6,6 +6,7 @@ boot := arch/loongarch/boot KBUILD_DEFCONFIG := loongson3_defconfig +KBUILD_DTBS := dtbs image-name-y := vmlinux image-name-$(CONFIG_EFI_ZBOOT) := vmlinuz @@ -81,8 +82,11 @@ KBUILD_AFLAGS_MODULE += -Wa,-mla-global-with-abs KBUILD_CFLAGS_MODULE += -fplt -Wa,-mla-global-with-abs,-mla-local-with-abs endif +KBUILD_RUSTFLAGS_MODULE += -Crelocation-model=pic + ifeq ($(CONFIG_RELOCATABLE),y) KBUILD_CFLAGS_KERNEL += -fPIE +KBUILD_RUSTFLAGS_KERNEL += -Crelocation-model=pie LDFLAGS_vmlinux += -static -pie --no-dynamic-linker -z notext $(call ld-option, --apply-dynamic-relocs) endif @@ -141,7 +145,7 @@ endif vdso-install-y += arch/loongarch/vdso/vdso.so.dbg -all: $(notdir $(KBUILD_IMAGE)) +all: $(notdir $(KBUILD_IMAGE)) $(KBUILD_DTBS) vmlinuz.efi: vmlinux.efi diff --git a/arch/loongarch/boot/dts/Makefile b/arch/loongarch/boot/dts/Makefile index 5f1f55e911adf5..747d0c3f638929 100644 --- a/arch/loongarch/boot/dts/Makefile +++ b/arch/loongarch/boot/dts/Makefile @@ -1,4 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -dtstree := $(srctree)/$(src) -dtb-y := $(patsubst $(dtstree)/%.dts,%.dtb, $(wildcard $(dtstree)/*.dts)) +dtb-y = loongson-2k0500-ref.dtb loongson-2k1000-ref.dtb loongson-2k2000-ref.dtb + +obj-$(CONFIG_BUILTIN_DTB) += $(addsuffix .dtb.o, $(CONFIG_BUILTIN_DTB_NAME)) diff --git a/arch/loongarch/boot/dts/loongson-2k0500-ref.dts b/arch/loongarch/boot/dts/loongson-2k0500-ref.dts new file mode 100644 index 00000000000000..b38071a4d0b023 --- /dev/null +++ b/arch/loongarch/boot/dts/loongson-2k0500-ref.dts @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023 Loongson Technology Corporation Limited + */ + +/dts-v1/; + +#include "loongson-2k0500.dtsi" + +/ { + compatible = "loongson,ls2k0500-ref", "loongson,ls2k0500"; + model = "Loongson-2K0500 Reference Board"; + + aliases { + ethernet0 = &gmac0; + ethernet1 = &gmac1; + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + memory@200000 { + device_type = "memory"; + reg = <0x0 0x00200000 0x0 0x0ee00000>, + <0x0 0x90000000 0x0 0x60000000>; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x0 0x2000000>; + linux,cma-default; + }; + }; +}; + +&gmac0 { + status = "okay"; + + phy-mode = "rgmii"; + bus_id = <0x0>; +}; + +&gmac1 { + status = "okay"; + + phy-mode = "rgmii"; + bus_id = <0x1>; +}; + +&i2c0 { + status = "okay"; + + #address-cells = <1>; + #size-cells = <0>; + eeprom@57{ + compatible = "atmel,24c16"; + reg = <0x57>; + pagesize = <16>; + }; +}; + +&ehci0 { + status = "okay"; +}; + +&ohci0 { + status = "okay"; +}; + +&sata { + status = "okay"; +}; + +&uart0 { + status = "okay"; +}; + +&rtc0 { + status = "okay"; +}; diff --git a/arch/loongarch/boot/dts/loongson-2k0500.dtsi b/arch/loongarch/boot/dts/loongson-2k0500.dtsi new file mode 100644 index 00000000000000..444779c21034b5 --- /dev/null +++ b/arch/loongarch/boot/dts/loongson-2k0500.dtsi @@ -0,0 +1,266 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023 Loongson Technology Corporation Limited + */ + +/dts-v1/; + +#include + +/ { + #address-cells = <2>; + #size-cells = <2>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "loongson,la264"; + device_type = "cpu"; + reg = <0x0>; + clocks = <&cpu_clk>; + }; + }; + + cpu_clk: cpu-clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <500000000>; + }; + + cpuintc: interrupt-controller { + compatible = "loongson,cpu-interrupt-controller"; + #interrupt-cells = <1>; + interrupt-controller; + }; + + bus@10000000 { + compatible = "simple-bus"; + ranges = <0x0 0x10000000 0x0 0x10000000 0x0 0x10000000>, + <0x0 0x02000000 0x0 0x02000000 0x0 0x02000000>, + <0x0 0x20000000 0x0 0x20000000 0x0 0x10000000>, + <0x0 0x40000000 0x0 0x40000000 0x0 0x40000000>, + <0xfe 0x0 0xfe 0x0 0x0 0x40000000>; + #address-cells = <2>; + #size-cells = <2>; + + isa@16400000 { + compatible = "isa"; + #size-cells = <1>; + #address-cells = <2>; + ranges = <1 0x0 0x0 0x16400000 0x4000>; + }; + + liointc0: interrupt-controller@1fe11400 { + compatible = "loongson,liointc-2.0"; + reg = <0x0 0x1fe11400 0x0 0x40>, + <0x0 0x1fe11040 0x0 0x8>; + reg-names = "main", "isr0"; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&cpuintc>; + interrupts = <2>; + interrupt-names = "int0"; + + loongson,parent_int_map = <0xffffffff>, /* int0 */ + <0x00000000>, /* int1 */ + <0x00000000>, /* int2 */ + <0x00000000>; /* int3 */ + }; + + liointc1: interrupt-controller@1fe11440 { + compatible = "loongson,liointc-2.0"; + reg = <0x0 0x1fe11440 0x0 0x40>, + <0x0 0x1fe11048 0x0 0x8>; + reg-names = "main", "isr0"; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&cpuintc>; + interrupts = <4>; + interrupt-names = "int2"; + + loongson,parent_int_map = <0x00000000>, /* int0 */ + <0x00000000>, /* int1 */ + <0xffffffff>, /* int2 */ + <0x00000000>; /* int3 */ + }; + + eiointc: interrupt-controller@1fe11600 { + compatible = "loongson,ls2k0500-eiointc"; + reg = <0x0 0x1fe11600 0x0 0xea00>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&cpuintc>; + interrupts = <3>; + }; + + gmac0: ethernet@1f020000 { + compatible = "snps,dwmac-3.70a"; + reg = <0x0 0x1f020000 0x0 0x10000>; + interrupt-parent = <&liointc0>; + interrupts = <12 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "macirq"; + status = "disabled"; + }; + + gmac1: ethernet@1f030000 { + compatible = "snps,dwmac-3.70a"; + reg = <0x0 0x1f030000 0x0 0x10000>; + interrupt-parent = <&liointc0>; + interrupts = <14 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "macirq"; + status = "disabled"; + }; + + sata: sata@1f040000 { + compatible = "snps,spear-ahci"; + reg = <0x0 0x1f040000 0x0 0x10000>; + interrupt-parent = <&eiointc>; + interrupts = <75>; + status = "disabled"; + }; + + ehci0: usb@1f050000 { + compatible = "generic-ehci"; + reg = <0x0 0x1f050000 0x0 0x8000>; + interrupt-parent = <&eiointc>; + interrupts = <71>; + status = "disabled"; + }; + + ohci0: usb@1f058000 { + compatible = "generic-ohci"; + reg = <0x0 0x1f058000 0x0 0x8000>; + interrupt-parent = <&eiointc>; + interrupts = <72>; + status = "disabled"; + }; + + uart0: serial@1ff40800 { + compatible = "ns16550a"; + reg = <0x0 0x1ff40800 0x0 0x10>; + clock-frequency = <100000000>; + interrupt-parent = <&eiointc>; + interrupts = <2>; + no-loopback-test; + status = "disabled"; + }; + + i2c0: i2c@1ff48000 { + compatible = "loongson,ls2k-i2c"; + reg = <0x0 0x1ff48000 0x0 0x0800>; + interrupt-parent = <&eiointc>; + interrupts = <14>; + status = "disabled"; + }; + + i2c@1ff48800 { + compatible = "loongson,ls2k-i2c"; + reg = <0x0 0x1ff48800 0x0 0x0800>; + interrupt-parent = <&eiointc>; + interrupts = <15>; + status = "disabled"; + }; + + i2c@1ff49000 { + compatible = "loongson,ls2k-i2c"; + reg = <0x0 0x1ff49000 0x0 0x0800>; + interrupt-parent = <&eiointc>; + interrupts = <16>; + status = "disabled"; + }; + + i2c@1ff49800 { + compatible = "loongson,ls2k-i2c"; + reg = <0x0 0x1ff49800 0x0 0x0800>; + interrupt-parent = <&eiointc>; + interrupts = <17>; + status = "disabled"; + }; + + i2c@1ff4a000 { + compatible = "loongson,ls2k-i2c"; + reg = <0x0 0x1ff4a000 0x0 0x0800>; + interrupt-parent = <&eiointc>; + interrupts = <18>; + status = "disabled"; + }; + + i2c@1ff4a800 { + compatible = "loongson,ls2k-i2c"; + reg = <0x0 0x1ff4a800 0x0 0x0800>; + interrupt-parent = <&eiointc>; + interrupts = <19>; + status = "disabled"; + }; + + pmc: power-management@1ff6c000 { + compatible = "loongson,ls2k0500-pmc", "syscon"; + reg = <0x0 0x1ff6c000 0x0 0x58>; + interrupt-parent = <&eiointc>; + interrupts = <56>; + loongson,suspend-address = <0x0 0x1c000500>; + + syscon-reboot { + compatible = "syscon-reboot"; + offset = <0x30>; + mask = <0x1>; + }; + + syscon-poweroff { + compatible = "syscon-poweroff"; + regmap = <&pmc>; + offset = <0x14>; + mask = <0x3c00>; + value = <0x3c00>; + }; + }; + + rtc0: rtc@1ff6c100 { + compatible = "loongson,ls2k0500-rtc", "loongson,ls7a-rtc"; + reg = <0x0 0x1ff6c100 0x0 0x100>; + interrupt-parent = <&eiointc>; + interrupts = <35>; + status = "disabled"; + }; + + pcie@1a000000 { + compatible = "loongson,ls2k-pci"; + reg = <0x0 0x1a000000 0x0 0x02000000>, + <0xfe 0x0 0x0 0x20000000>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + bus-range = <0x0 0x5>; + ranges = <0x01000000 0x0 0x00004000 0x0 0x16404000 0x0 0x00004000>, + <0x02000000 0x0 0x40000000 0x0 0x40000000 0x0 0x40000000>; + + pcie@0,0 { + reg = <0x0000 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + interrupt-parent = <&eiointc>; + #interrupt-cells = <1>; + interrupt-map-mask = <0x0 0x0 0x0 0x0>; + interrupt-map = <0x0 0x0 0x0 0x0 &eiointc 81>; + ranges; + }; + + pcie@1,0 { + reg = <0x0800 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + interrupt-parent = <&eiointc>; + #interrupt-cells = <1>; + interrupt-map-mask = <0x0 0x0 0x0 0x0>; + interrupt-map = <0x0 0x0 0x0 0x0 &eiointc 82>; + ranges; + }; + }; + }; +}; diff --git a/arch/loongarch/boot/dts/loongson-2k1000-ref.dts b/arch/loongarch/boot/dts/loongson-2k1000-ref.dts new file mode 100644 index 00000000000000..132a2d1ea8bce1 --- /dev/null +++ b/arch/loongarch/boot/dts/loongson-2k1000-ref.dts @@ -0,0 +1,183 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023 Loongson Technology Corporation Limited + */ + +/dts-v1/; + +#include "loongson-2k1000.dtsi" + +/ { + compatible = "loongson,ls2k1000-ref", "loongson,ls2k1000"; + model = "Loongson-2K1000 Reference Board"; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + memory@200000 { + device_type = "memory"; + reg = <0x0 0x00200000 0x0 0x06e00000>, + <0x0 0x08000000 0x0 0x07000000>, + <0x0 0x90000000 0x1 0xe0000000>; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x0 0x2000000>; + linux,cma-default; + }; + }; +}; + +&gmac0 { + status = "okay"; + + phy-mode = "rgmii"; + phy-handle = <&phy0>; + mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + phy0: ethernet-phy@0 { + reg = <0>; + }; + }; +}; + +&gmac1 { + status = "okay"; + + phy-mode = "rgmii"; + phy-handle = <&phy1>; + mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + phy1: ethernet-phy@1 { + reg = <16>; + }; + }; +}; + +&i2c2 { + status = "okay"; + + pinctrl-0 = <&i2c0_pins_default>; + pinctrl-names = "default"; + + #address-cells = <1>; + #size-cells = <0>; + eeprom@57{ + compatible = "atmel,24c16"; + reg = <0x57>; + pagesize = <16>; + }; +}; + +&spi0 { + status = "okay"; + + #address-cells = <1>; + #size-cells = <0>; + spidev@0 { + compatible = "rohm,dh2228fv"; + spi-max-frequency = <100000000>; + reg = <0>; + }; +}; + +&ehci0 { + status = "okay"; +}; + +&ohci0 { + status = "okay"; +}; + +&sata { + status = "okay"; +}; + +&uart0 { + status = "okay"; +}; + +&clk { + status = "okay"; +}; + +&rtc0 { + status = "okay"; +}; + +&pctrl { + status = "okay"; + + sdio_pins_default: sdio-pins { + sdio-pinmux { + groups = "sdio"; + function = "sdio"; + }; + sdio-det-pinmux { + groups = "pwm2"; + function = "gpio"; + }; + }; + + pwm1_pins_default: pwm1-pins { + pinmux { + groups = "pwm1"; + function = "pwm1"; + }; + }; + + pwm0_pins_default: pwm0-pins { + pinmux { + groups = "pwm0"; + function = "pwm0"; + }; + }; + + i2c1_pins_default: i2c1-pins { + pinmux { + groups = "i2c1"; + function = "i2c1"; + }; + }; + + i2c0_pins_default: i2c0-pins { + pinmux { + groups = "i2c0"; + function = "i2c0"; + }; + }; + + nand_pins_default: nand-pins { + pinmux { + groups = "nand"; + function = "nand"; + }; + }; + + hda_pins_default: hda-pins { + grp0-pinmux { + groups = "hda"; + function = "hda"; + }; + grp1-pinmux { + groups = "i2s"; + function = "gpio"; + }; + }; +}; diff --git a/arch/loongarch/boot/dts/loongson-2k1000.dtsi b/arch/loongarch/boot/dts/loongson-2k1000.dtsi new file mode 100644 index 00000000000000..49a70f8c3cab22 --- /dev/null +++ b/arch/loongarch/boot/dts/loongson-2k1000.dtsi @@ -0,0 +1,492 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023 Loongson Technology Corporation Limited + */ + +/dts-v1/; + +#include +#include +#include + +/ { + #address-cells = <2>; + #size-cells = <2>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@0 { + compatible = "loongson,la264"; + device_type = "cpu"; + reg= <0x0>; + clocks = <&clk LOONGSON2_NODE_CLK>; + }; + + cpu1: cpu@1 { + compatible = "loongson,la264"; + device_type = "cpu"; + reg = <0x1>; + clocks = <&clk LOONGSON2_NODE_CLK>; + }; + }; + + ref_100m: clock-ref-100m { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + clock-output-names = "ref_100m"; + }; + + cpuintc: interrupt-controller { + compatible = "loongson,cpu-interrupt-controller"; + #interrupt-cells = <1>; + interrupt-controller; + }; + + /* i2c of the dvi eeprom edid */ + i2c-gpio-0 { + compatible = "i2c-gpio"; + scl-gpios = <&gpio0 0 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + sda-gpios = <&gpio0 1 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + i2c-gpio,delay-us = <5>; /* ~100 kHz */ + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + /* i2c of the eeprom edid */ + i2c-gpio-1 { + compatible = "i2c-gpio"; + scl-gpios = <&gpio0 33 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + sda-gpios = <&gpio0 32 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + i2c-gpio,delay-us = <5>; /* ~100 kHz */ + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + thermal-zones { + cpu-thermal { + polling-delay-passive = <1000>; + polling-delay = <5000>; + thermal-sensors = <&tsensor 0>; + + trips { + cpu_alert: cpu-alert { + temperature = <33000>; + hysteresis = <2000>; + type = "active"; + }; + + cpu_crit: cpu-crit { + temperature = <85000>; + hysteresis = <5000>; + type = "critical"; + }; + }; + }; + }; + + bus@10000000 { + compatible = "simple-bus"; + ranges = <0x0 0x10000000 0x0 0x10000000 0x0 0x10000000>, + <0x0 0x02000000 0x0 0x02000000 0x0 0x02000000>, + <0x0 0x20000000 0x0 0x20000000 0x0 0x10000000>, + <0x0 0x40000000 0x0 0x40000000 0x0 0x40000000>, + <0xfe 0x0 0xfe 0x0 0x0 0x40000000>; + #address-cells = <2>; + #size-cells = <2>; + dma-coherent; + + liointc0: interrupt-controller@1fe01400 { + compatible = "loongson,liointc-2.0"; + reg = <0x0 0x1fe01400 0x0 0x40>, + <0x0 0x1fe01040 0x0 0x8>, + <0x0 0x1fe01140 0x0 0x8>; + reg-names = "main", "isr0", "isr1"; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&cpuintc>; + interrupts = <2>; + interrupt-names = "int0"; + loongson,parent_int_map = <0xffffffff>, /* int0 */ + <0x00000000>, /* int1 */ + <0x00000000>, /* int2 */ + <0x00000000>; /* int3 */ + }; + + liointc1: interrupt-controller@1fe01440 { + compatible = "loongson,liointc-2.0"; + reg = <0x0 0x1fe01440 0x0 0x40>, + <0x0 0x1fe01048 0x0 0x8>, + <0x0 0x1fe01148 0x0 0x8>; + reg-names = "main", "isr0", "isr1"; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&cpuintc>; + interrupts = <3>; + interrupt-names = "int1"; + loongson,parent_int_map = <0x00000000>, /* int0 */ + <0xffffffff>, /* int1 */ + <0x00000000>, /* int2 */ + <0x00000000>; /* int3 */ + }; + + chipid@1fe00000 { + compatible = "loongson,ls2k-chipid"; + reg = <0x0 0x1fe00000 0x0 0x30>; + little-endian; + }; + + pctrl: pinctrl@1fe00420 { + compatible = "loongson,ls2k-pinctrl"; + reg = <0x0 0x1fe00420 0x0 0x18>; + status = "disabled"; + }; + + clk: clock-controller@1fe00480 { + compatible = "loongson,ls2k-clk"; + reg = <0x0 0x1fe00480 0x0 0x58>; + #clock-cells = <1>; + clocks = <&ref_100m>; + clock-names = "ref_100m"; + status = "disabled"; + }; + + gpio0: gpio@1fe00500 { + compatible = "loongson,ls2k-gpio"; + reg = <0x0 0x1fe00500 0x0 0x38>; + ngpios = <64>; + #gpio-cells = <2>; + gpio-controller; + gpio-ranges = <&pctrl 0x0 0x0 15>, + <&pctrl 16 16 15>, + <&pctrl 32 32 10>, + <&pctrl 44 44 20>; + interrupt-parent = <&liointc1>; + interrupts = <28 IRQ_TYPE_LEVEL_HIGH>, + <29 IRQ_TYPE_LEVEL_HIGH>, + <30 IRQ_TYPE_LEVEL_HIGH>, + <30 IRQ_TYPE_LEVEL_HIGH>, + <26 IRQ_TYPE_LEVEL_HIGH>, + <26 IRQ_TYPE_LEVEL_HIGH>, + <26 IRQ_TYPE_LEVEL_HIGH>, + <26 IRQ_TYPE_LEVEL_HIGH>, + <26 IRQ_TYPE_LEVEL_HIGH>, + <26 IRQ_TYPE_LEVEL_HIGH>, + <26 IRQ_TYPE_LEVEL_HIGH>, + <26 IRQ_TYPE_LEVEL_HIGH>, + <26 IRQ_TYPE_LEVEL_HIGH>, + <26 IRQ_TYPE_LEVEL_HIGH>, + <26 IRQ_TYPE_LEVEL_HIGH>, + <>, + <26 IRQ_TYPE_LEVEL_HIGH>, + <26 IRQ_TYPE_LEVEL_HIGH>, + <26 IRQ_TYPE_LEVEL_HIGH>, + <26 IRQ_TYPE_LEVEL_HIGH>, + <26 IRQ_TYPE_LEVEL_HIGH>, + <26 IRQ_TYPE_LEVEL_HIGH>, + <26 IRQ_TYPE_LEVEL_HIGH>, + <26 IRQ_TYPE_LEVEL_HIGH>, + <26 IRQ_TYPE_LEVEL_HIGH>, + <26 IRQ_TYPE_LEVEL_HIGH>, + <26 IRQ_TYPE_LEVEL_HIGH>, + <26 IRQ_TYPE_LEVEL_HIGH>, + <26 IRQ_TYPE_LEVEL_HIGH>, + <26 IRQ_TYPE_LEVEL_HIGH>, + <26 IRQ_TYPE_LEVEL_HIGH>, + <26 IRQ_TYPE_LEVEL_HIGH>, + <27 IRQ_TYPE_LEVEL_HIGH>, + <27 IRQ_TYPE_LEVEL_HIGH>, + <27 IRQ_TYPE_LEVEL_HIGH>, + <27 IRQ_TYPE_LEVEL_HIGH>, + <27 IRQ_TYPE_LEVEL_HIGH>, + <>, + <27 IRQ_TYPE_LEVEL_HIGH>, + <27 IRQ_TYPE_LEVEL_HIGH>, + <27 IRQ_TYPE_LEVEL_HIGH>, + <27 IRQ_TYPE_LEVEL_HIGH>, + <>, + <>, + <27 IRQ_TYPE_LEVEL_HIGH>, + <27 IRQ_TYPE_LEVEL_HIGH>, + <27 IRQ_TYPE_LEVEL_HIGH>, + <27 IRQ_TYPE_LEVEL_HIGH>, + <27 IRQ_TYPE_LEVEL_HIGH>, + <27 IRQ_TYPE_LEVEL_HIGH>, + <27 IRQ_TYPE_LEVEL_HIGH>, + <27 IRQ_TYPE_LEVEL_HIGH>, + <27 IRQ_TYPE_LEVEL_HIGH>, + <27 IRQ_TYPE_LEVEL_HIGH>, + <27 IRQ_TYPE_LEVEL_HIGH>, + <27 IRQ_TYPE_LEVEL_HIGH>, + <27 IRQ_TYPE_LEVEL_HIGH>, + <27 IRQ_TYPE_LEVEL_HIGH>, + <27 IRQ_TYPE_LEVEL_HIGH>, + <27 IRQ_TYPE_LEVEL_HIGH>, + <27 IRQ_TYPE_LEVEL_HIGH>, + <27 IRQ_TYPE_LEVEL_HIGH>, + <27 IRQ_TYPE_LEVEL_HIGH>, + <27 IRQ_TYPE_LEVEL_HIGH>; + }; + + tsensor: thermal-sensor@1fe01500 { + compatible = "loongson,ls2k1000-thermal"; + reg = <0x0 0x1fe01500 0x0 0x30>; + interrupt-parent = <&liointc0>; + interrupts = <7 IRQ_TYPE_LEVEL_HIGH>; + #thermal-sensor-cells = <1>; + }; + + dma-controller@1fe00c00 { + compatible = "loongson,ls2k1000-apbdma"; + reg = <0x0 0x1fe00c00 0x0 0x8>; + interrupt-parent = <&liointc1>; + interrupts = <12 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_APB_CLK>; + #dma-cells = <1>; + status = "disabled"; + }; + + dma-controller@1fe00c10 { + compatible = "loongson,ls2k1000-apbdma"; + reg = <0x0 0x1fe00c10 0x0 0x8>; + interrupt-parent = <&liointc1>; + interrupts = <13 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_APB_CLK>; + #dma-cells = <1>; + status = "disabled"; + }; + + dma-controller@1fe00c20 { + compatible = "loongson,ls2k1000-apbdma"; + reg = <0x0 0x1fe00c20 0x0 0x8>; + interrupt-parent = <&liointc1>; + interrupts = <14 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_APB_CLK>; + #dma-cells = <1>; + status = "disabled"; + }; + + dma-controller@1fe00c30 { + compatible = "loongson,ls2k1000-apbdma"; + reg = <0x0 0x1fe00c30 0x0 0x8>; + interrupt-parent = <&liointc1>; + interrupts = <15 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_APB_CLK>; + #dma-cells = <1>; + status = "disabled"; + }; + + dma-controller@1fe00c40 { + compatible = "loongson,ls2k1000-apbdma"; + reg = <0x0 0x1fe00c40 0x0 0x8>; + interrupt-parent = <&liointc1>; + interrupts = <16 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk LOONGSON2_APB_CLK>; + #dma-cells = <1>; + status = "disabled"; + }; + + uart0: serial@1fe20000 { + compatible = "ns16550a"; + reg = <0x0 0x1fe20000 0x0 0x10>; + clock-frequency = <125000000>; + interrupt-parent = <&liointc0>; + interrupts = <0x0 IRQ_TYPE_LEVEL_HIGH>; + no-loopback-test; + status = "disabled"; + }; + + i2c2: i2c@1fe21000 { + compatible = "loongson,ls2k-i2c"; + reg = <0x0 0x1fe21000 0x0 0x8>; + interrupt-parent = <&liointc0>; + interrupts = <22 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + i2c3: i2c@1fe21800 { + compatible = "loongson,ls2k-i2c"; + reg = <0x0 0x1fe21800 0x0 0x8>; + interrupt-parent = <&liointc0>; + interrupts = <23 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + pmc: power-management@1fe27000 { + compatible = "loongson,ls2k1000-pmc", "loongson,ls2k0500-pmc", "syscon"; + reg = <0x0 0x1fe27000 0x0 0x58>; + interrupt-parent = <&liointc1>; + interrupts = <11 IRQ_TYPE_LEVEL_HIGH>; + loongson,suspend-address = <0x0 0x1c000500>; + + syscon-reboot { + compatible = "syscon-reboot"; + offset = <0x30>; + mask = <0x1>; + }; + + syscon-poweroff { + compatible = "syscon-poweroff"; + regmap = <&pmc>; + offset = <0x14>; + mask = <0x3c00>; + value = <0x3c00>; + }; + }; + + rtc0: rtc@1fe27800 { + compatible = "loongson,ls2k1000-rtc"; + reg = <0x0 0x1fe27800 0x0 0x100>; + interrupt-parent = <&liointc1>; + interrupts = <8 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + spi0: spi@1fff0220 { + compatible = "loongson,ls2k1000-spi"; + reg = <0x0 0x1fff0220 0x0 0x10>; + clocks = <&clk LOONGSON2_BOOT_CLK>; + status = "disabled"; + }; + + pcie@1a000000 { + compatible = "loongson,ls2k-pci"; + reg = <0x0 0x1a000000 0x0 0x02000000>, + <0xfe 0x0 0x0 0x20000000>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + bus-range = <0x0 0xff>; + ranges = <0x01000000 0x0 0x00008000 0x0 0x18008000 0x0 0x00008000>, + <0x02000000 0x0 0x60000000 0x0 0x60000000 0x0 0x20000000>; + + gmac0: ethernet@3,0 { + reg = <0x1800 0x0 0x0 0x0 0x0>; + interrupt-parent = <&liointc0>; + interrupts = <12 IRQ_TYPE_LEVEL_HIGH>, + <13 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "macirq", "eth_lpi"; + status = "disabled"; + }; + + gmac1: ethernet@3,1 { + reg = <0x1900 0x0 0x0 0x0 0x0>; + interrupt-parent = <&liointc0>; + interrupts = <14 IRQ_TYPE_LEVEL_HIGH>, + <15 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "macirq", "eth_lpi"; + status = "disabled"; + }; + + ehci0: usb@4,1 { + reg = <0x2100 0x0 0x0 0x0 0x0>; + interrupt-parent = <&liointc1>; + interrupts = <18 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + ohci0: usb@4,2 { + reg = <0x2200 0x0 0x0 0x0 0x0>; + interrupt-parent = <&liointc1>; + interrupts = <19 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + display@6,0 { + reg = <0x3000 0x0 0x0 0x0 0x0>; + interrupt-parent = <&liointc0>; + interrupts = <28 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + hda@7,0 { + reg = <0x3800 0x0 0x0 0x0 0x0>; + interrupt-parent = <&liointc0>; + interrupts = <4 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + sata: sata@8,0 { + reg = <0x4000 0x0 0x0 0x0 0x0>; + interrupt-parent = <&liointc0>; + interrupts = <19 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + pcie@9,0 { + reg = <0x4800 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + #interrupt-cells = <1>; + interrupt-map-mask = <0x0 0x0 0x0 0x0>; + interrupt-map = <0x0 0x0 0x0 0x0 &liointc1 0x0 IRQ_TYPE_LEVEL_HIGH>; + ranges; + }; + + pcie@a,0 { + reg = <0x5000 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + interrupt-parent = <&liointc1>; + #interrupt-cells = <1>; + interrupt-map-mask = <0x0 0x0 0x0 0x0>; + interrupt-map = <0x0 0x0 0x0 0x0 &liointc1 1 IRQ_TYPE_LEVEL_HIGH>; + ranges; + }; + + pcie@b,0 { + reg = <0x5800 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + interrupt-parent = <&liointc1>; + #interrupt-cells = <1>; + interrupt-map-mask = <0x0 0x0 0x0 0x0>; + interrupt-map = <0x0 0x0 0x0 0x0 &liointc1 2 IRQ_TYPE_LEVEL_HIGH>; + ranges; + }; + + pcie@c,0 { + reg = <0x6000 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + interrupt-parent = <&liointc1>; + #interrupt-cells = <1>; + interrupt-map-mask = <0x0 0x0 0x0 0x0>; + interrupt-map = <0x0 0x0 0x0 0x0 &liointc1 3 IRQ_TYPE_LEVEL_HIGH>; + ranges; + }; + + pcie@d,0 { + reg = <0x6800 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + interrupt-parent = <&liointc1>; + #interrupt-cells = <1>; + interrupt-map-mask = <0x0 0x0 0x0 0x0>; + interrupt-map = <0x0 0x0 0x0 0x0 &liointc1 4 IRQ_TYPE_LEVEL_HIGH>; + ranges; + }; + + pcie@e,0 { + reg = <0x7000 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + interrupt-parent = <&liointc1>; + #interrupt-cells = <1>; + interrupt-map-mask = <0x0 0x0 0x0 0x0>; + interrupt-map = <0x0 0x0 0x0 0x0 &liointc1 5 IRQ_TYPE_LEVEL_HIGH>; + ranges; + }; + }; + }; +}; diff --git a/arch/loongarch/boot/dts/loongson-2k2000-ref.dts b/arch/loongarch/boot/dts/loongson-2k2000-ref.dts new file mode 100644 index 00000000000000..dca91caf895e3c --- /dev/null +++ b/arch/loongarch/boot/dts/loongson-2k2000-ref.dts @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023 Loongson Technology Corporation Limited + */ + +/dts-v1/; + +#include "loongson-2k2000.dtsi" + +/ { + compatible = "loongson,ls2k2000-ref", "loongson,ls2k2000"; + model = "Loongson-2K2000 Reference Board"; + + aliases { + serial0 = &uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + memory@200000 { + device_type = "memory"; + reg = <0x0 0x00200000 0x0 0x0ee00000>, + <0x0 0x90000000 0x0 0x70000000>; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x0 0x2000000>; + linux,cma-default; + }; + }; +}; + +&sata { + status = "okay"; +}; + +&uart0 { + status = "okay"; +}; + +&rtc0 { + status = "okay"; +}; + +&xhci0 { + status = "okay"; +}; + +&xhci1 { + status = "okay"; +}; + +&gmac0 { + status = "okay"; +}; + +&gmac1 { + status = "okay"; +}; + +&gmac2 { + status = "okay"; +}; diff --git a/arch/loongarch/boot/dts/loongson-2k2000.dtsi b/arch/loongarch/boot/dts/loongson-2k2000.dtsi new file mode 100644 index 00000000000000..a231949b5f553a --- /dev/null +++ b/arch/loongarch/boot/dts/loongson-2k2000.dtsi @@ -0,0 +1,300 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023 Loongson Technology Corporation Limited + */ + +/dts-v1/; + +#include + +/ { + #address-cells = <2>; + #size-cells = <2>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu0: cpu@1 { + compatible = "loongson,la364"; + device_type = "cpu"; + reg = <0x0>; + clocks = <&cpu_clk>; + }; + + cpu1: cpu@2 { + compatible = "loongson,la364"; + device_type = "cpu"; + reg = <0x1>; + clocks = <&cpu_clk>; + }; + }; + + cpu_clk: cpu-clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <1400000000>; + }; + + cpuintc: interrupt-controller { + compatible = "loongson,cpu-interrupt-controller"; + #interrupt-cells = <1>; + interrupt-controller; + }; + + bus@10000000 { + compatible = "simple-bus"; + ranges = <0x0 0x10000000 0x0 0x10000000 0x0 0x10000000>, + <0x0 0x02000000 0x0 0x02000000 0x0 0x02000000>, + <0x0 0x40000000 0x0 0x40000000 0x0 0x40000000>, + <0xfe 0x0 0xfe 0x0 0x0 0x40000000>; + #address-cells = <2>; + #size-cells = <2>; + + pmc: power-management@100d0000 { + compatible = "loongson,ls2k2000-pmc", "loongson,ls2k0500-pmc", "syscon"; + reg = <0x0 0x100d0000 0x0 0x58>; + interrupt-parent = <&eiointc>; + interrupts = <47>; + loongson,suspend-address = <0x0 0x1c000500>; + + syscon-reboot { + compatible = "syscon-reboot"; + offset = <0x30>; + mask = <0x1>; + }; + + syscon-poweroff { + compatible = "syscon-poweroff"; + regmap = <&pmc>; + offset = <0x14>; + mask = <0x3c00>; + value = <0x3c00>; + }; + }; + + liointc: interrupt-controller@1fe01400 { + compatible = "loongson,liointc-1.0"; + reg = <0x0 0x1fe01400 0x0 0x64>; + + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&cpuintc>; + interrupts = <2>; + interrupt-names = "int0"; + loongson,parent_int_map = <0xffffffff>, /* int0 */ + <0x00000000>, /* int1 */ + <0x00000000>, /* int2 */ + <0x00000000>; /* int3 */ + }; + + eiointc: interrupt-controller@1fe01600 { + compatible = "loongson,ls2k2000-eiointc"; + reg = <0x0 0x1fe01600 0x0 0xea00>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&cpuintc>; + interrupts = <3>; + }; + + pic: interrupt-controller@10000000 { + compatible = "loongson,pch-pic-1.0"; + reg = <0x0 0x10000000 0x0 0x400>; + interrupt-controller; + #interrupt-cells = <2>; + loongson,pic-base-vec = <0>; + interrupt-parent = <&eiointc>; + }; + + msi: msi-controller@1fe01140 { + compatible = "loongson,pch-msi-1.0"; + reg = <0x0 0x1fe01140 0x0 0x8>; + msi-controller; + loongson,msi-base-vec = <64>; + loongson,msi-num-vecs = <192>; + interrupt-parent = <&eiointc>; + }; + + rtc0: rtc@100d0100 { + compatible = "loongson,ls2k2000-rtc", "loongson,ls7a-rtc"; + reg = <0x0 0x100d0100 0x0 0x100>; + interrupt-parent = <&pic>; + interrupts = <52 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + }; + + uart0: serial@1fe001e0 { + compatible = "ns16550a"; + reg = <0x0 0x1fe001e0 0x0 0x10>; + clock-frequency = <100000000>; + interrupt-parent = <&liointc>; + interrupts = <10 IRQ_TYPE_LEVEL_HIGH>; + no-loopback-test; + status = "disabled"; + }; + + pcie@1a000000 { + compatible = "loongson,ls2k-pci"; + reg = <0x0 0x1a000000 0x0 0x02000000>, + <0xfe 0x0 0x0 0x20000000>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + bus-range = <0x0 0xff>; + ranges = <0x01000000 0x0 0x00008000 0x0 0x18400000 0x0 0x00008000>, + <0x02000000 0x0 0x60000000 0x0 0x60000000 0x0 0x20000000>; + + gmac0: ethernet@3,0 { + reg = <0x1800 0x0 0x0 0x0 0x0>; + interrupts = <12 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&pic>; + status = "disabled"; + }; + + gmac1: ethernet@3,1 { + reg = <0x1900 0x0 0x0 0x0 0x0>; + interrupts = <14 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&pic>; + status = "disabled"; + }; + + gmac2: ethernet@3,2 { + reg = <0x1a00 0x0 0x0 0x0 0x0>; + interrupts = <17 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&pic>; + status = "disabled"; + }; + + xhci0: usb@4,0 { + reg = <0x2000 0x0 0x0 0x0 0x0>; + interrupts = <48 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&pic>; + status = "disabled"; + }; + + xhci1: usb@19,0 { + reg = <0xc800 0x0 0x0 0x0 0x0>; + interrupts = <22 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&pic>; + status = "disabled"; + }; + + display@6,1 { + reg = <0x3100 0x0 0x0 0x0 0x0>; + interrupts = <28 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&pic>; + status = "disabled"; + }; + + hda@7,0 { + reg = <0x3800 0x0 0x0 0x0 0x0>; + interrupts = <58 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&pic>; + status = "disabled"; + }; + + sata: sata@8,0 { + reg = <0x4000 0x0 0x0 0x0 0x0>; + interrupts = <16 IRQ_TYPE_LEVEL_HIGH>; + interrupt-parent = <&pic>; + status = "disabled"; + }; + + pcie@9,0 { + reg = <0x4800 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + interrupt-parent = <&pic>; + #interrupt-cells = <1>; + interrupt-map-mask = <0x0 0x0 0x0 0x0>; + interrupt-map = <0x0 0x0 0x0 0x0 &pic 32 IRQ_TYPE_LEVEL_HIGH>; + ranges; + }; + + pcie@a,0 { + reg = <0x5000 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + interrupt-parent = <&pic>; + #interrupt-cells = <1>; + interrupt-map-mask = <0x0 0x0 0x0 0x0>; + interrupt-map = <0x0 0x0 0x0 0x0 &pic 33 IRQ_TYPE_LEVEL_HIGH>; + ranges; + }; + + pcie@b,0 { + reg = <0x5800 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + interrupt-parent = <&pic>; + #interrupt-cells = <1>; + interrupt-map-mask = <0x0 0x0 0x0 0x0>; + interrupt-map = <0x0 0x0 0x0 0x0 &pic 34 IRQ_TYPE_LEVEL_HIGH>; + ranges; + }; + + pcie@c,0 { + reg = <0x6000 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + interrupt-parent = <&pic>; + #interrupt-cells = <1>; + interrupt-map-mask = <0x0 0x0 0x0 0x0>; + interrupt-map = <0x0 0x0 0x0 0x0 &pic 35 IRQ_TYPE_LEVEL_HIGH>; + ranges; + }; + + pcie@d,0 { + reg = <0x6800 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + interrupt-parent = <&pic>; + #interrupt-cells = <1>; + interrupt-map-mask = <0x0 0x0 0x0 0x0>; + interrupt-map = <0x0 0x0 0x0 0x0 &pic 36 IRQ_TYPE_LEVEL_HIGH>; + ranges; + }; + + pcie@e,0 { + reg = <0x7000 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + interrupt-parent = <&pic>; + #interrupt-cells = <1>; + interrupt-map-mask = <0x0 0x0 0x0 0x0>; + interrupt-map = <0x0 0x0 0x0 0x0 &pic 37 IRQ_TYPE_LEVEL_HIGH>; + ranges; + }; + + pcie@f,0 { + reg = <0x7800 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + interrupt-parent = <&pic>; + #interrupt-cells = <1>; + interrupt-map-mask = <0x0 0x0 0x0 0x0>; + interrupt-map = <0x0 0x0 0x0 0x0 &pic 40 IRQ_TYPE_LEVEL_HIGH>; + ranges; + }; + + pcie@10,0 { + reg = <0x8000 0x0 0x0 0x0 0x0>; + #address-cells = <3>; + #size-cells = <2>; + device_type = "pci"; + interrupt-parent = <&pic>; + #interrupt-cells = <1>; + interrupt-map-mask = <0x0 0x0 0x0 0x0>; + interrupt-map = <0x0 0x0 0x0 0x0 &pic 30 IRQ_TYPE_LEVEL_HIGH>; + ranges; + }; + }; + }; +}; diff --git a/arch/loongarch/configs/loongson3_defconfig b/arch/loongarch/configs/loongson3_defconfig index 33795e4a5bd632..f18c2ba871eff6 100644 --- a/arch/loongarch/configs/loongson3_defconfig +++ b/arch/loongarch/configs/loongson3_defconfig @@ -6,6 +6,8 @@ CONFIG_HIGH_RES_TIMERS=y CONFIG_BPF_SYSCALL=y CONFIG_BPF_JIT=y CONFIG_PREEMPT=y +CONFIG_PREEMPT_DYNAMIC=y +CONFIG_SCHED_CORE=y CONFIG_BSD_PROCESS_ACCT=y CONFIG_BSD_PROCESS_ACCT_V3=y CONFIG_TASKSTATS=y @@ -19,6 +21,7 @@ CONFIG_BLK_CGROUP=y CONFIG_CFS_BANDWIDTH=y CONFIG_RT_GROUP_SCHED=y CONFIG_CGROUP_PIDS=y +CONFIG_CGROUP_RDMA=y CONFIG_CGROUP_FREEZER=y CONFIG_CGROUP_HUGETLB=y CONFIG_CPUSETS=y @@ -26,6 +29,7 @@ CONFIG_CGROUP_DEVICE=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_PERF=y CONFIG_CGROUP_BPF=y +CONFIG_CGROUP_MISC=y CONFIG_NAMESPACES=y CONFIG_USER_NS=y CONFIG_CHECKPOINT_RESTORE=y @@ -35,6 +39,8 @@ CONFIG_BLK_DEV_INITRD=y CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y CONFIG_PERF_EVENTS=y +CONFIG_KEXEC=y +CONFIG_CRASH_DUMP=y CONFIG_LOONGARCH=y CONFIG_64BIT=y CONFIG_MACH_LOONGSON64=y @@ -44,13 +50,11 @@ CONFIG_DMI=y CONFIG_EFI=y CONFIG_SMP=y CONFIG_HOTPLUG_CPU=y -CONFIG_NR_CPUS=64 +CONFIG_NR_CPUS=256 CONFIG_NUMA=y CONFIG_CPU_HAS_FPU=y CONFIG_CPU_HAS_LSX=y CONFIG_CPU_HAS_LASX=y -CONFIG_KEXEC=y -CONFIG_CRASH_DUMP=y CONFIG_RANDOMIZE_BASE=y CONFIG_SUSPEND=y CONFIG_HIBERNATION=y @@ -62,10 +66,6 @@ CONFIG_ACPI_IPMI=m CONFIG_ACPI_HOTPLUG_CPU=y CONFIG_ACPI_PCI_SLOT=y CONFIG_ACPI_HOTPLUG_MEMORY=y -CONFIG_EFI_ZBOOT=y -CONFIG_EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER=y -CONFIG_EFI_CAPSULE_LOADER=m -CONFIG_EFI_TEST=m CONFIG_VIRTUALIZATION=y CONFIG_KVM=m CONFIG_JUMP_LABEL=y @@ -74,10 +74,18 @@ CONFIG_MODULE_FORCE_LOAD=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y +CONFIG_BLK_DEV_ZONED=y CONFIG_BLK_DEV_THROTTLING=y +CONFIG_BLK_DEV_THROTTLING_LOW=y +CONFIG_BLK_WBT=y +CONFIG_BLK_CGROUP_IOLATENCY=y +CONFIG_BLK_CGROUP_FC_APPID=y +CONFIG_BLK_CGROUP_IOCOST=y +CONFIG_BLK_CGROUP_IOPRIO=y CONFIG_PARTITION_ADVANCED=y CONFIG_BSD_DISKLABEL=y CONFIG_UNIXWARE_DISKLABEL=y +CONFIG_CMDLINE_PARTITION=y CONFIG_IOSCHED_BFQ=y CONFIG_BFQ_GROUP_IOSCHED=y CONFIG_BINFMT_MISC=m @@ -93,6 +101,8 @@ CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE=y CONFIG_MEMORY_HOTREMOVE=y CONFIG_KSM=y CONFIG_TRANSPARENT_HUGEPAGE=y +CONFIG_CMA=y +CONFIG_CMA_SYSFS=y CONFIG_USERFAULTFD=y CONFIG_NET=y CONFIG_PACKET=y @@ -128,6 +138,7 @@ CONFIG_IPV6_ROUTER_PREF=y CONFIG_IPV6_ROUTE_INFO=y CONFIG_INET6_ESP=m CONFIG_IPV6_MROUTE=y +CONFIG_MPTCP=y CONFIG_NETWORK_PHY_TIMESTAMPING=y CONFIG_NETFILTER=y CONFIG_BRIDGE_NETFILTER=m @@ -276,7 +287,6 @@ CONFIG_BRIDGE_EBT_T_NAT=m CONFIG_BRIDGE_EBT_ARP=m CONFIG_BRIDGE_EBT_IP=m CONFIG_BRIDGE_EBT_IP6=m -CONFIG_BPFILTER=y CONFIG_IP_SCTP=m CONFIG_RDS=y CONFIG_L2TP=m @@ -304,7 +314,6 @@ CONFIG_NET_CLS_ACT=y CONFIG_NET_ACT_POLICE=m CONFIG_NET_ACT_GACT=m CONFIG_NET_ACT_MIRRED=m -CONFIG_NET_ACT_IPT=m CONFIG_NET_ACT_NAT=m CONFIG_NET_ACT_BPF=m CONFIG_OPENVSWITCH=m @@ -354,6 +363,7 @@ CONFIG_PCIEAER=y CONFIG_PCI_IOV=y CONFIG_HOTPLUG_PCI=y CONFIG_HOTPLUG_PCI_SHPC=y +CONFIG_PCI_HOST_GENERIC=y CONFIG_PCCARD=m CONFIG_YENTA=m CONFIG_RAPIDIO=y @@ -367,6 +377,10 @@ CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y CONFIG_FW_LOADER_COMPRESS=y CONFIG_FW_LOADER_COMPRESS_ZSTD=y +CONFIG_EFI_ZBOOT=y +CONFIG_EFI_BOOTLOADER_CONTROL=m +CONFIG_EFI_CAPSULE_LOADER=m +CONFIG_EFI_TEST=m CONFIG_MTD=m CONFIG_MTD_BLOCK=m CONFIG_MTD_CFI=m @@ -588,6 +602,7 @@ CONFIG_RTW89_8852AE=m CONFIG_RTW89_8852CE=m CONFIG_ZD1211RW=m CONFIG_USB_NET_RNDIS_WLAN=m +CONFIG_USB4_NET=m CONFIG_INPUT_MOUSEDEV=y CONFIG_INPUT_MOUSEDEV_PSAUX=y CONFIG_INPUT_EVDEV=y @@ -693,6 +708,9 @@ CONFIG_SND_HDA_CODEC_SIGMATEL=y CONFIG_SND_HDA_CODEC_HDMI=y CONFIG_SND_HDA_CODEC_CONEXANT=y CONFIG_SND_USB_AUDIO=m +CONFIG_SND_SOC=m +CONFIG_SND_SOC_LOONGSON_CARD=m +CONFIG_SND_VIRTIO=m CONFIG_HIDRAW=y CONFIG_UHID=m CONFIG_HID_A4TECH=m @@ -740,6 +758,11 @@ CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_EFI=y CONFIG_RTC_DRV_LOONGSON=y CONFIG_DMADEVICES=y +CONFIG_LS2X_APB_DMA=y +CONFIG_UDMABUF=y +CONFIG_DMABUF_HEAPS=y +CONFIG_DMABUF_HEAPS_SYSTEM=y +CONFIG_DMABUF_HEAPS_CMA=y CONFIG_UIO=m CONFIG_UIO_PDRV_GENIRQ=m CONFIG_UIO_DMEM_GENIRQ=m @@ -780,7 +803,15 @@ CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y CONFIG_DEVFREQ_GOV_PERFORMANCE=y CONFIG_DEVFREQ_GOV_POWERSAVE=y CONFIG_DEVFREQ_GOV_USERSPACE=y +CONFIG_NTB=m +CONFIG_NTB_MSI=y +CONFIG_NTB_IDT=m +CONFIG_NTB_EPF=m +CONFIG_NTB_SWITCHTEC=m +CONFIG_NTB_PERF=m +CONFIG_NTB_TRANSPORT=m CONFIG_PWM=y +CONFIG_USB4=y CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT2_FS_POSIX_ACL=y @@ -799,6 +830,10 @@ CONFIG_GFS2_FS_LOCKING_DLM=y CONFIG_OCFS2_FS=m CONFIG_BTRFS_FS=y CONFIG_BTRFS_FS_POSIX_ACL=y +CONFIG_F2FS_FS=m +CONFIG_F2FS_FS_SECURITY=y +CONFIG_F2FS_CHECK_FS=y +CONFIG_F2FS_FS_COMPRESSION=y CONFIG_FANOTIFY=y CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y CONFIG_QUOTA=y @@ -885,7 +920,6 @@ CONFIG_KEY_DH_OPERATIONS=y CONFIG_SECURITY=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SELINUX_BOOTPARAM=y -CONFIG_SECURITY_SELINUX_DISABLE=y CONFIG_SECURITY_APPARMOR=y CONFIG_SECURITY_YAMA=y CONFIG_DEFAULT_SECURITY_DAC=y @@ -916,6 +950,9 @@ CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_USER_API_AEAD=m CONFIG_CRYPTO_CRC32_LOONGARCH=m CONFIG_CRYPTO_DEV_VIRTIO=m +CONFIG_DMA_CMA=y +CONFIG_DMA_NUMA_CMA=y +CONFIG_CMA_SIZE_MBYTES=0 CONFIG_PRINTK_TIME=y CONFIG_STRIP_ASM_SYMS=y CONFIG_MAGIC_SYSRQ=y diff --git a/arch/loongarch/include/asm/bootinfo.h b/arch/loongarch/include/asm/bootinfo.h index c60796869b2b80..6d5846dd075cbd 100644 --- a/arch/loongarch/include/asm/bootinfo.h +++ b/arch/loongarch/include/asm/bootinfo.h @@ -24,13 +24,15 @@ struct loongson_board_info { const char *board_vendor; }; +#define NR_WORDS DIV_ROUND_UP(NR_CPUS, BITS_PER_LONG) + struct loongson_system_configuration { int nr_cpus; int nr_nodes; int boot_cpu_id; int cores_per_node; int cores_per_package; - unsigned long cores_io_master; + unsigned long cores_io_master[NR_WORDS]; unsigned long suspend_addr; const char *cpuname; }; @@ -42,7 +44,7 @@ extern struct loongson_system_configuration loongson_sysconf; static inline bool io_master(int cpu) { - return test_bit(cpu, &loongson_sysconf.cores_io_master); + return test_bit(cpu, loongson_sysconf.cores_io_master); } #endif /* _ASM_BOOTINFO_H */ diff --git a/arch/loongarch/include/asm/crash_core.h b/arch/loongarch/include/asm/crash_core.h new file mode 100644 index 00000000000000..218bdbfa527ba8 --- /dev/null +++ b/arch/loongarch/include/asm/crash_core.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef _LOONGARCH_CRASH_CORE_H +#define _LOONGARCH_CRASH_CORE_H + +#define CRASH_ALIGN SZ_2M + +#define CRASH_ADDR_LOW_MAX SZ_4G +#define CRASH_ADDR_HIGH_MAX memblock_end_of_DRAM() + +extern phys_addr_t memblock_end_of_DRAM(void); + +#endif diff --git a/arch/loongarch/include/asm/efi.h b/arch/loongarch/include/asm/efi.h index 91d81f9730ab3f..eddc8e79b3fae7 100644 --- a/arch/loongarch/include/asm/efi.h +++ b/arch/loongarch/include/asm/efi.h @@ -32,6 +32,4 @@ static inline unsigned long efi_get_kimg_min_align(void) #define EFI_KIMG_PREFERRED_ADDRESS PHYSADDR(VMLINUX_LOAD_ADDRESS) -unsigned long kernel_entry_address(unsigned long kernel_addr); - #endif /* _ASM_LOONGARCH_EFI_H */ diff --git a/arch/loongarch/include/asm/elf.h b/arch/loongarch/include/asm/elf.h index 9b16a3b8e70608..f16bd42456e4cc 100644 --- a/arch/loongarch/include/asm/elf.h +++ b/arch/loongarch/include/asm/elf.h @@ -241,8 +241,6 @@ void loongarch_dump_regs64(u64 *uregs, const struct pt_regs *regs); do { \ current->thread.vdso = &vdso_info; \ \ - loongarch_set_personality_fcsr(state); \ - \ if (personality(current->personality) != PER_LINUX) \ set_personality(PER_LINUX); \ } while (0) @@ -259,7 +257,6 @@ do { \ clear_thread_flag(TIF_32BIT_ADDR); \ \ current->thread.vdso = &vdso_info; \ - loongarch_set_personality_fcsr(state); \ \ p = personality(current->personality); \ if (p != PER_LINUX32 && p != PER_LINUX) \ @@ -340,6 +337,4 @@ extern int arch_elf_pt_proc(void *ehdr, void *phdr, struct file *elf, extern int arch_check_elf(void *ehdr, bool has_interpreter, void *interp_ehdr, struct arch_elf_state *state); -extern void loongarch_set_personality_fcsr(struct arch_elf_state *state); - #endif /* _ASM_ELF_H */ diff --git a/arch/loongarch/include/asm/ftrace.h b/arch/loongarch/include/asm/ftrace.h index a11996eb5892dd..de891c2c83d4a9 100644 --- a/arch/loongarch/include/asm/ftrace.h +++ b/arch/loongarch/include/asm/ftrace.h @@ -63,7 +63,7 @@ ftrace_regs_get_instruction_pointer(struct ftrace_regs *fregs) static __always_inline void ftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs, unsigned long ip) { - regs_set_return_value(&fregs->regs, ip); + instruction_pointer_set(&fregs->regs, ip); } #define ftrace_regs_get_argument(fregs, n) \ diff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h index 11328700d4fa8d..2d62f7b0d377b5 100644 --- a/arch/loongarch/include/asm/kvm_host.h +++ b/arch/loongarch/include/asm/kvm_host.h @@ -45,7 +45,10 @@ struct kvm_vcpu_stat { u64 signal_exits; }; +#define KVM_MEM_HUGEPAGE_CAPABLE (1UL << 0) +#define KVM_MEM_HUGEPAGE_INCAPABLE (1UL << 1) struct kvm_arch_memory_slot { + unsigned long flags; }; struct kvm_context { @@ -92,8 +95,10 @@ enum emulation_result { }; #define KVM_LARCH_FPU (0x1 << 0) -#define KVM_LARCH_SWCSR_LATEST (0x1 << 1) -#define KVM_LARCH_HWCSR_USABLE (0x1 << 2) +#define KVM_LARCH_LSX (0x1 << 1) +#define KVM_LARCH_LASX (0x1 << 2) +#define KVM_LARCH_SWCSR_LATEST (0x1 << 3) +#define KVM_LARCH_HWCSR_USABLE (0x1 << 4) struct kvm_vcpu_arch { /* @@ -175,6 +180,21 @@ static inline void writel_sw_gcsr(struct loongarch_csrs *csr, int reg, unsigned csr->csrs[reg] = val; } +static inline bool kvm_guest_has_fpu(struct kvm_vcpu_arch *arch) +{ + return arch->cpucfg[2] & CPUCFG2_FP; +} + +static inline bool kvm_guest_has_lsx(struct kvm_vcpu_arch *arch) +{ + return arch->cpucfg[2] & CPUCFG2_LSX; +} + +static inline bool kvm_guest_has_lasx(struct kvm_vcpu_arch *arch) +{ + return arch->cpucfg[2] & CPUCFG2_LASX; +} + /* Debug: dump vcpu state */ int kvm_arch_vcpu_dump_regs(struct kvm_vcpu *vcpu); @@ -183,7 +203,6 @@ void kvm_flush_tlb_all(void); void kvm_flush_tlb_gpa(struct kvm_vcpu *vcpu, unsigned long gpa); int kvm_handle_mm_fault(struct kvm_vcpu *vcpu, unsigned long badv, bool write); -#define KVM_ARCH_WANT_MMU_NOTIFIER void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte); int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end, bool blockable); int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end); diff --git a/arch/loongarch/include/asm/kvm_vcpu.h b/arch/loongarch/include/asm/kvm_vcpu.h index 553cfa2b2b1cfb..0cb4fdb8a9b597 100644 --- a/arch/loongarch/include/asm/kvm_vcpu.h +++ b/arch/loongarch/include/asm/kvm_vcpu.h @@ -55,7 +55,26 @@ void kvm_save_fpu(struct loongarch_fpu *fpu); void kvm_restore_fpu(struct loongarch_fpu *fpu); void kvm_restore_fcsr(struct loongarch_fpu *fpu); -void kvm_acquire_timer(struct kvm_vcpu *vcpu); +#ifdef CONFIG_CPU_HAS_LSX +int kvm_own_lsx(struct kvm_vcpu *vcpu); +void kvm_save_lsx(struct loongarch_fpu *fpu); +void kvm_restore_lsx(struct loongarch_fpu *fpu); +#else +static inline int kvm_own_lsx(struct kvm_vcpu *vcpu) { return -EINVAL; } +static inline void kvm_save_lsx(struct loongarch_fpu *fpu) { } +static inline void kvm_restore_lsx(struct loongarch_fpu *fpu) { } +#endif + +#ifdef CONFIG_CPU_HAS_LASX +int kvm_own_lasx(struct kvm_vcpu *vcpu); +void kvm_save_lasx(struct loongarch_fpu *fpu); +void kvm_restore_lasx(struct loongarch_fpu *fpu); +#else +static inline int kvm_own_lasx(struct kvm_vcpu *vcpu) { return -EINVAL; } +static inline void kvm_save_lasx(struct loongarch_fpu *fpu) { } +static inline void kvm_restore_lasx(struct loongarch_fpu *fpu) { } +#endif + void kvm_init_timer(struct kvm_vcpu *vcpu, unsigned long hz); void kvm_reset_timer(struct kvm_vcpu *vcpu); void kvm_save_timer(struct kvm_vcpu *vcpu); diff --git a/arch/loongarch/include/asm/pgtable.h b/arch/loongarch/include/asm/pgtable.h index 29d9b12298bc84..8b5df1bbf9e9c2 100644 --- a/arch/loongarch/include/asm/pgtable.h +++ b/arch/loongarch/include/asm/pgtable.h @@ -523,6 +523,7 @@ static inline pmd_t pmd_wrprotect(pmd_t pmd) return pmd; } +#define pmd_dirty pmd_dirty static inline int pmd_dirty(pmd_t pmd) { return !!(pmd_val(pmd) & (_PAGE_DIRTY | _PAGE_MODIFIED)); diff --git a/arch/loongarch/include/asm/shmparam.h b/arch/loongarch/include/asm/shmparam.h deleted file mode 100644 index c9554f48d2dfab..00000000000000 --- a/arch/loongarch/include/asm/shmparam.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2020-2022 Loongson Technology Corporation Limited - */ -#ifndef _ASM_SHMPARAM_H -#define _ASM_SHMPARAM_H - -#define __ARCH_FORCE_SHMLBA 1 - -#define SHMLBA SZ_64K /* attach addr a multiple of this */ - -#endif /* _ASM_SHMPARAM_H */ diff --git a/arch/loongarch/include/uapi/asm/kvm.h b/arch/loongarch/include/uapi/asm/kvm.h index c6ad2ee6106cb0..923d0bd382941a 100644 --- a/arch/loongarch/include/uapi/asm/kvm.h +++ b/arch/loongarch/include/uapi/asm/kvm.h @@ -79,6 +79,7 @@ struct kvm_fpu { #define LOONGARCH_REG_64(TYPE, REG) (TYPE | KVM_REG_SIZE_U64 | (REG << LOONGARCH_REG_SHIFT)) #define KVM_IOC_CSRID(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CSR, REG) #define KVM_IOC_CPUCFG(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CPUCFG, REG) +#define KVM_LOONGARCH_VCPU_CPUCFG 0 struct kvm_debug_exit_arch { }; diff --git a/arch/loongarch/kernel/acpi.c b/arch/loongarch/kernel/acpi.c index 8e00a754e54894..b6b097bbf8668a 100644 --- a/arch/loongarch/kernel/acpi.c +++ b/arch/loongarch/kernel/acpi.c @@ -119,7 +119,7 @@ acpi_parse_eio_master(union acpi_subtable_headers *header, const unsigned long e return -EINVAL; core = eiointc->node * CORES_PER_EIO_NODE; - set_bit(core, &(loongson_sysconf.cores_io_master)); + set_bit(core, loongson_sysconf.cores_io_master); return 0; } diff --git a/arch/loongarch/kernel/asm-offsets.c b/arch/loongarch/kernel/asm-offsets.c index 173fe514fc9ecf..bee9f7a3108f0e 100644 --- a/arch/loongarch/kernel/asm-offsets.c +++ b/arch/loongarch/kernel/asm-offsets.c @@ -15,7 +15,7 @@ #include #include -void output_ptreg_defines(void) +static void __used output_ptreg_defines(void) { COMMENT("LoongArch pt_regs offsets."); OFFSET(PT_R0, pt_regs, regs[0]); @@ -62,7 +62,7 @@ void output_ptreg_defines(void) BLANK(); } -void output_task_defines(void) +static void __used output_task_defines(void) { COMMENT("LoongArch task_struct offsets."); OFFSET(TASK_STATE, task_struct, __state); @@ -77,7 +77,7 @@ void output_task_defines(void) BLANK(); } -void output_thread_info_defines(void) +static void __used output_thread_info_defines(void) { COMMENT("LoongArch thread_info offsets."); OFFSET(TI_TASK, thread_info, task); @@ -93,7 +93,7 @@ void output_thread_info_defines(void) BLANK(); } -void output_thread_defines(void) +static void __used output_thread_defines(void) { COMMENT("LoongArch specific thread_struct offsets."); OFFSET(THREAD_REG01, task_struct, thread.reg01); @@ -129,7 +129,7 @@ void output_thread_defines(void) BLANK(); } -void output_thread_fpu_defines(void) +static void __used output_thread_fpu_defines(void) { OFFSET(THREAD_FPR0, loongarch_fpu, fpr[0]); OFFSET(THREAD_FPR1, loongarch_fpu, fpr[1]); @@ -170,7 +170,7 @@ void output_thread_fpu_defines(void) BLANK(); } -void output_thread_lbt_defines(void) +static void __used output_thread_lbt_defines(void) { OFFSET(THREAD_SCR0, loongarch_lbt, scr0); OFFSET(THREAD_SCR1, loongarch_lbt, scr1); @@ -180,7 +180,7 @@ void output_thread_lbt_defines(void) BLANK(); } -void output_mm_defines(void) +static void __used output_mm_defines(void) { COMMENT("Size of struct page"); DEFINE(STRUCT_PAGE_SIZE, sizeof(struct page)); @@ -212,7 +212,7 @@ void output_mm_defines(void) BLANK(); } -void output_sc_defines(void) +static void __used output_sc_defines(void) { COMMENT("Linux sigcontext offsets."); OFFSET(SC_REGS, sigcontext, sc_regs); @@ -220,7 +220,7 @@ void output_sc_defines(void) BLANK(); } -void output_signal_defines(void) +static void __used output_signal_defines(void) { COMMENT("Linux signal numbers."); DEFINE(_SIGHUP, SIGHUP); @@ -258,7 +258,7 @@ void output_signal_defines(void) } #ifdef CONFIG_SMP -void output_smpboot_defines(void) +static void __used output_smpboot_defines(void) { COMMENT("Linux smp cpu boot offsets."); OFFSET(CPU_BOOT_STACK, secondary_data, stack); @@ -268,7 +268,7 @@ void output_smpboot_defines(void) #endif #ifdef CONFIG_HIBERNATION -void output_pbe_defines(void) +static void __used output_pbe_defines(void) { COMMENT("Linux struct pbe offsets."); OFFSET(PBE_ADDRESS, pbe, address); @@ -280,7 +280,7 @@ void output_pbe_defines(void) #endif #ifdef CONFIG_FUNCTION_GRAPH_TRACER -void output_fgraph_ret_regs_defines(void) +static void __used output_fgraph_ret_regs_defines(void) { COMMENT("LoongArch fgraph_ret_regs offsets."); OFFSET(FGRET_REGS_A0, fgraph_ret_regs, regs[0]); @@ -291,7 +291,7 @@ void output_fgraph_ret_regs_defines(void) } #endif -void output_kvm_defines(void) +static void __used output_kvm_defines(void) { COMMENT("KVM/LoongArch Specific offsets."); diff --git a/arch/loongarch/kernel/efi.c b/arch/loongarch/kernel/efi.c index acb5d3385675c9..000825406c1f62 100644 --- a/arch/loongarch/kernel/efi.c +++ b/arch/loongarch/kernel/efi.c @@ -140,4 +140,6 @@ void __init efi_init(void) early_memunmap(tbl, sizeof(*tbl)); } + + efi_esrt_init(); } diff --git a/arch/loongarch/kernel/elf.c b/arch/loongarch/kernel/elf.c index 183e94fc9c69ce..0fa81ced28dcdd 100644 --- a/arch/loongarch/kernel/elf.c +++ b/arch/loongarch/kernel/elf.c @@ -23,8 +23,3 @@ int arch_check_elf(void *_ehdr, bool has_interpreter, void *_interp_ehdr, { return 0; } - -void loongarch_set_personality_fcsr(struct arch_elf_state *state) -{ - current->thread.fpu.fcsr = boot_cpu_data.fpu_csr0; -} diff --git a/arch/loongarch/kernel/env.c b/arch/loongarch/kernel/env.c index 6b3bfb0092e60b..2f1f5b08638f81 100644 --- a/arch/loongarch/kernel/env.c +++ b/arch/loongarch/kernel/env.c @@ -5,13 +5,16 @@ * Copyright (C) 2020-2022 Loongson Technology Corporation Limited */ #include +#include #include #include #include +#include #include #include #include #include +#include u64 efi_system_table; struct loongson_system_configuration loongson_sysconf; @@ -36,7 +39,16 @@ void __init init_environ(void) static int __init init_cpu_fullname(void) { - int cpu; + struct device_node *root; + int cpu, ret; + char *model; + + /* Parsing cpuname from DTS model property */ + root = of_find_node_by_path("/"); + ret = of_property_read_string(root, "model", (const char **)&model); + of_node_put(root); + if (ret == 0) + loongson_sysconf.cpuname = strsep(&model, " "); if (loongson_sysconf.cpuname && !strncmp(loongson_sysconf.cpuname, "Loongson", 8)) { for (cpu = 0; cpu < NR_CPUS; cpu++) @@ -46,6 +58,26 @@ static int __init init_cpu_fullname(void) } arch_initcall(init_cpu_fullname); +static int __init fdt_cpu_clk_init(void) +{ + struct clk *clk; + struct device_node *np; + + np = of_get_cpu_node(0, NULL); + if (!np) + return -ENODEV; + + clk = of_clk_get(np, 0); + if (IS_ERR(clk)) + return -ENODEV; + + cpu_clock_freq = clk_get_rate(clk); + clk_put(clk); + + return 0; +} +late_initcall(fdt_cpu_clk_init); + static ssize_t boardinfo_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { diff --git a/arch/loongarch/kernel/fpu.S b/arch/loongarch/kernel/fpu.S index d53ab10f464465..4382e36ae3d444 100644 --- a/arch/loongarch/kernel/fpu.S +++ b/arch/loongarch/kernel/fpu.S @@ -349,6 +349,7 @@ SYM_FUNC_START(_restore_lsx_upper) lsx_restore_all_upper a0 t0 t1 jr ra SYM_FUNC_END(_restore_lsx_upper) +EXPORT_SYMBOL(_restore_lsx_upper) SYM_FUNC_START(_init_lsx_upper) lsx_init_all_upper t1 @@ -384,6 +385,7 @@ SYM_FUNC_START(_restore_lasx_upper) lasx_restore_all_upper a0 t0 t1 jr ra SYM_FUNC_END(_restore_lasx_upper) +EXPORT_SYMBOL(_restore_lasx_upper) SYM_FUNC_START(_init_lasx_upper) lasx_init_all_upper t1 diff --git a/arch/loongarch/kernel/head.S b/arch/loongarch/kernel/head.S index 53b883db078620..c4f7de2e28054c 100644 --- a/arch/loongarch/kernel/head.S +++ b/arch/loongarch/kernel/head.S @@ -34,7 +34,6 @@ pe_header: SYM_DATA(kernel_asize, .long _kernel_asize); SYM_DATA(kernel_fsize, .long _kernel_fsize); -SYM_DATA(kernel_offset, .long _kernel_offset); #endif @@ -75,6 +74,11 @@ SYM_CODE_START(kernel_entry) # kernel entry point la.pcrel t0, fw_arg2 st.d a2, t0, 0 +#ifdef CONFIG_PAGE_SIZE_4KB + li.d t0, 0 + li.d t1, CSR_STFILL + csrxchg t0, t1, LOONGARCH_CSR_IMPCTL1 +#endif /* KSave3 used for percpu base, initialized as 0 */ csrwr zero, PERCPU_BASE_KS /* GPR21 used for percpu base (runtime), initialized as 0 */ @@ -127,6 +131,11 @@ SYM_CODE_START(smpboot_entry) JUMP_VIRT_ADDR t0, t1 +#ifdef CONFIG_PAGE_SIZE_4KB + li.d t0, 0 + li.d t1, CSR_STFILL + csrxchg t0, t1, LOONGARCH_CSR_IMPCTL1 +#endif /* Enable PG */ li.w t0, 0xb0 # PLV=0, IE=0, PG=1 csrwr t0, LOONGARCH_CSR_CRMD diff --git a/arch/loongarch/kernel/image-vars.h b/arch/loongarch/kernel/image-vars.h index 5087416b9678d6..41ddcf56d21c78 100644 --- a/arch/loongarch/kernel/image-vars.h +++ b/arch/loongarch/kernel/image-vars.h @@ -11,7 +11,6 @@ __efistub_strcmp = strcmp; __efistub_kernel_entry = kernel_entry; __efistub_kernel_asize = kernel_asize; __efistub_kernel_fsize = kernel_fsize; -__efistub_kernel_offset = kernel_offset; #if defined(CONFIG_EFI_EARLYCON) || defined(CONFIG_SYSFB) __efistub_screen_info = screen_info; #endif diff --git a/arch/loongarch/kernel/numa.c b/arch/loongarch/kernel/numa.c index 6e65ff12d5c7dc..8fe21f868f72d4 100644 --- a/arch/loongarch/kernel/numa.c +++ b/arch/loongarch/kernel/numa.c @@ -226,32 +226,6 @@ static void __init node_mem_init(unsigned int node) #ifdef CONFIG_ACPI_NUMA -/* - * Sanity check to catch more bad NUMA configurations (they are amazingly - * common). Make sure the nodes cover all memory. - */ -static bool __init numa_meminfo_cover_memory(const struct numa_meminfo *mi) -{ - int i; - u64 numaram, biosram; - - numaram = 0; - for (i = 0; i < mi->nr_blks; i++) { - u64 s = mi->blk[i].start >> PAGE_SHIFT; - u64 e = mi->blk[i].end >> PAGE_SHIFT; - - numaram += e - s; - numaram -= __absent_pages_in_range(mi->blk[i].nid, s, e); - if ((s64)numaram < 0) - numaram = 0; - } - max_pfn = max_low_pfn; - biosram = max_pfn - absent_pages_in_range(0, max_pfn); - - BUG_ON((s64)(biosram - numaram) >= (1 << (20 - PAGE_SHIFT))); - return true; -} - static void __init add_node_intersection(u32 node, u64 start, u64 size, u32 type) { static unsigned long num_physpages; @@ -396,7 +370,7 @@ int __init init_numa_memory(void) return -EINVAL; init_node_memblock(); - if (numa_meminfo_cover_memory(&numa_meminfo) == false) + if (!memblock_validate_numa_coverage(SZ_1M)) return -EINVAL; for_each_node_mask(node, node_possible_map) { diff --git a/arch/loongarch/kernel/process.c b/arch/loongarch/kernel/process.c index 767d94cce0de07..f2ff8b5d591e4f 100644 --- a/arch/loongarch/kernel/process.c +++ b/arch/loongarch/kernel/process.c @@ -85,6 +85,7 @@ void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) regs->csr_euen = euen; lose_fpu(0); lose_lbt(0); + current->thread.fpu.fcsr = boot_cpu_data.fpu_csr0; clear_thread_flag(TIF_LSX_CTX_LIVE); clear_thread_flag(TIF_LASX_CTX_LIVE); diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c index d183a745fb85d4..edf2bba8013067 100644 --- a/arch/loongarch/kernel/setup.c +++ b/arch/loongarch/kernel/setup.c @@ -252,38 +252,23 @@ static void __init arch_reserve_vmcore(void) #endif } -/* 2MB alignment for crash kernel regions */ -#define CRASH_ALIGN SZ_2M -#define CRASH_ADDR_MAX SZ_4G - -static void __init arch_parse_crashkernel(void) +static void __init arch_reserve_crashkernel(void) { -#ifdef CONFIG_KEXEC int ret; - unsigned long long total_mem; + unsigned long long low_size = 0; unsigned long long crash_base, crash_size; + char *cmdline = boot_command_line; + bool high = false; - total_mem = memblock_phys_mem_size(); - ret = parse_crashkernel(boot_command_line, total_mem, - &crash_size, &crash_base, - NULL, NULL); - if (ret < 0 || crash_size <= 0) + if (!IS_ENABLED(CONFIG_KEXEC_CORE)) return; - if (crash_base <= 0) { - crash_base = memblock_phys_alloc_range(crash_size, CRASH_ALIGN, CRASH_ALIGN, CRASH_ADDR_MAX); - if (!crash_base) { - pr_warn("crashkernel reservation failed - No suitable area found.\n"); - return; - } - } else if (!memblock_phys_alloc_range(crash_size, CRASH_ALIGN, crash_base, crash_base + crash_size)) { - pr_warn("Invalid memory region reserved for crash kernel\n"); + ret = parse_crashkernel(cmdline, memblock_phys_mem_size(), + &crash_size, &crash_base, &low_size, &high); + if (ret) return; - } - crashk_res.start = crash_base; - crashk_res.end = crash_base + crash_size - 1; -#endif + reserve_crashkernel_generic(cmdline, crash_size, crash_base, low_size, high); } static void __init fdt_setup(void) @@ -295,8 +280,12 @@ static void __init fdt_setup(void) if (acpi_os_get_root_pointer()) return; - /* Look for a device tree configuration table entry */ - fdt_pointer = efi_fdt_pointer(); + /* Prefer to use built-in dtb, checking its legality first. */ + if (!fdt_check_header(__dtb_start)) + fdt_pointer = __dtb_start; + else + fdt_pointer = efi_fdt_pointer(); /* Fallback to firmware dtb */ + if (!fdt_pointer || fdt_check_header(fdt_pointer)) return; @@ -330,7 +319,9 @@ static void __init bootcmdline_init(char **cmdline_p) if (boot_command_line[0]) strlcat(boot_command_line, " ", COMMAND_LINE_SIZE); - strlcat(boot_command_line, init_command_line, COMMAND_LINE_SIZE); + if (!strstr(boot_command_line, init_command_line)) + strlcat(boot_command_line, init_command_line, COMMAND_LINE_SIZE); + goto out; } #endif @@ -357,7 +348,7 @@ out: void __init platform_init(void) { arch_reserve_vmcore(); - arch_parse_crashkernel(); + arch_reserve_crashkernel(); #ifdef CONFIG_ACPI_TABLE_UPGRADE acpi_table_upgrade(); @@ -467,15 +458,6 @@ static void __init resource_init(void) request_resource(res, &data_resource); request_resource(res, &bss_resource); } - -#ifdef CONFIG_KEXEC - if (crashk_res.start < crashk_res.end) { - insert_resource(&iomem_resource, &crashk_res); - pr_info("Reserving %ldMB of memory at %ldMB for crashkernel\n", - (unsigned long)((crashk_res.end - crashk_res.start + 1) >> 20), - (unsigned long)(crashk_res.start >> 20)); - } -#endif } static int __init add_legacy_isa_io(struct fwnode_handle *fwnode, diff --git a/arch/loongarch/kernel/signal.c b/arch/loongarch/kernel/signal.c index 4a3686d1334949..7a555b60017193 100644 --- a/arch/loongarch/kernel/signal.c +++ b/arch/loongarch/kernel/signal.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/loongarch/kernel/smp.c b/arch/loongarch/kernel/smp.c index 5bca12d16e0691..2b49d30eb7c018 100644 --- a/arch/loongarch/kernel/smp.c +++ b/arch/loongarch/kernel/smp.c @@ -208,7 +208,7 @@ static void __init fdt_smp_setup(void) } loongson_sysconf.nr_cpus = num_processors; - set_bit(0, &(loongson_sysconf.cores_io_master)); + set_bit(0, loongson_sysconf.cores_io_master); #endif } @@ -216,6 +216,9 @@ void __init loongson_smp_setup(void) { fdt_smp_setup(); + if (loongson_sysconf.cores_per_package == 0) + loongson_sysconf.cores_per_package = num_processors; + cpu_data[0].core = cpu_logical_map(0) % loongson_sysconf.cores_per_package; cpu_data[0].package = cpu_logical_map(0) / loongson_sysconf.cores_per_package; @@ -506,7 +509,6 @@ asmlinkage void start_secondary(void) sync_counter(); cpu = raw_smp_processor_id(); set_my_cpu_offset(per_cpu_offset(cpu)); - rcutree_report_cpu_starting(cpu); cpu_probe(); constant_clockevent_init(); diff --git a/arch/loongarch/kernel/topology.c b/arch/loongarch/kernel/topology.c index 3fd1660066983b..75d5c51a7cd3de 100644 --- a/arch/loongarch/kernel/topology.c +++ b/arch/loongarch/kernel/topology.c @@ -10,47 +10,9 @@ #include -static DEFINE_PER_CPU(struct cpu, cpu_devices); - #ifdef CONFIG_HOTPLUG_CPU -int arch_register_cpu(int cpu) +bool arch_cpu_is_hotpluggable(int cpu) { - int ret; - struct cpu *c = &per_cpu(cpu_devices, cpu); - - c->hotpluggable = 1; - ret = register_cpu(c, cpu); - if (ret < 0) - pr_warn("register_cpu %d failed (%d)\n", cpu, ret); - - return ret; -} -EXPORT_SYMBOL(arch_register_cpu); - -void arch_unregister_cpu(int cpu) -{ - struct cpu *c = &per_cpu(cpu_devices, cpu); - - c->hotpluggable = 0; - unregister_cpu(c); + return !io_master(cpu); } -EXPORT_SYMBOL(arch_unregister_cpu); #endif - -static int __init topology_init(void) -{ - int i, ret; - - for_each_present_cpu(i) { - struct cpu *c = &per_cpu(cpu_devices, i); - - c->hotpluggable = !io_master(i); - ret = register_cpu(c, i); - if (ret < 0) - pr_warn("topology_init: register_cpu %d failed (%d)\n", i, ret); - } - - return 0; -} - -subsys_initcall(topology_init); diff --git a/arch/loongarch/kernel/vmlinux.lds.S b/arch/loongarch/kernel/vmlinux.lds.S index bb2ec86f37a8eb..a5d0cd2035da04 100644 --- a/arch/loongarch/kernel/vmlinux.lds.S +++ b/arch/loongarch/kernel/vmlinux.lds.S @@ -143,7 +143,6 @@ SECTIONS _kernel_fsize = _edata - _text; _kernel_vsize = _end - __initdata_begin; _kernel_rsize = _edata - __initdata_begin; - _kernel_offset = kernel_offset - _text; #endif .gptab.sdata : { diff --git a/arch/loongarch/kvm/Kconfig b/arch/loongarch/kvm/Kconfig index fda425babfb203..61f7e33b1f9573 100644 --- a/arch/loongarch/kvm/Kconfig +++ b/arch/loongarch/kvm/Kconfig @@ -22,14 +22,13 @@ config KVM depends on AS_HAS_LVZ_EXTENSION depends on HAVE_KVM select HAVE_KVM_DIRTY_RING_ACQ_REL - select HAVE_KVM_EVENTFD select HAVE_KVM_VCPU_ASYNC_IOCTL + select KVM_COMMON select KVM_GENERIC_DIRTYLOG_READ_PROTECT select KVM_GENERIC_HARDWARE_ENABLING + select KVM_GENERIC_MMU_NOTIFIER select KVM_MMIO select KVM_XFER_TO_GUEST_WORK - select MMU_NOTIFIER - select PREEMPT_NOTIFIERS help Support hosting virtualized guest machines using hardware virtualization extensions. You will need diff --git a/arch/loongarch/kvm/exit.c b/arch/loongarch/kvm/exit.c index ce8de3fa472cc6..ed1d89d53e2e6d 100644 --- a/arch/loongarch/kvm/exit.c +++ b/arch/loongarch/kvm/exit.c @@ -200,17 +200,8 @@ int kvm_emu_idle(struct kvm_vcpu *vcpu) ++vcpu->stat.idle_exits; trace_kvm_exit_idle(vcpu, KVM_TRACE_EXIT_IDLE); - if (!kvm_arch_vcpu_runnable(vcpu)) { - /* - * Switch to the software timer before halt-polling/blocking as - * the guest's timer may be a break event for the vCPU, and the - * hypervisor timer runs only when the CPU is in guest mode. - * Switch before halt-polling so that KVM recognizes an expired - * timer before blocking. - */ - kvm_save_timer(vcpu); - kvm_vcpu_block(vcpu); - } + if (!kvm_arch_vcpu_runnable(vcpu)) + kvm_vcpu_halt(vcpu); return EMULATE_DONE; } @@ -643,6 +634,11 @@ static int kvm_handle_fpu_disabled(struct kvm_vcpu *vcpu) { struct kvm_run *run = vcpu->run; + if (!kvm_guest_has_fpu(&vcpu->arch)) { + kvm_queue_exception(vcpu, EXCCODE_INE, 0); + return RESUME_GUEST; + } + /* * If guest FPU not present, the FPU operation should have been * treated as a reserved instruction! @@ -659,6 +655,36 @@ static int kvm_handle_fpu_disabled(struct kvm_vcpu *vcpu) return RESUME_GUEST; } +/* + * kvm_handle_lsx_disabled() - Guest used LSX while disabled in root. + * @vcpu: Virtual CPU context. + * + * Handle when the guest attempts to use LSX when it is disabled in the root + * context. + */ +static int kvm_handle_lsx_disabled(struct kvm_vcpu *vcpu) +{ + if (kvm_own_lsx(vcpu)) + kvm_queue_exception(vcpu, EXCCODE_INE, 0); + + return RESUME_GUEST; +} + +/* + * kvm_handle_lasx_disabled() - Guest used LASX while disabled in root. + * @vcpu: Virtual CPU context. + * + * Handle when the guest attempts to use LASX when it is disabled in the root + * context. + */ +static int kvm_handle_lasx_disabled(struct kvm_vcpu *vcpu) +{ + if (kvm_own_lasx(vcpu)) + kvm_queue_exception(vcpu, EXCCODE_INE, 0); + + return RESUME_GUEST; +} + /* * LoongArch KVM callback handling for unimplemented guest exiting */ @@ -687,6 +713,8 @@ static exit_handle_fn kvm_fault_tables[EXCCODE_INT_START] = { [EXCCODE_TLBS] = kvm_handle_write_fault, [EXCCODE_TLBM] = kvm_handle_write_fault, [EXCCODE_FPDIS] = kvm_handle_fpu_disabled, + [EXCCODE_LSXDIS] = kvm_handle_lsx_disabled, + [EXCCODE_LASXDIS] = kvm_handle_lasx_disabled, [EXCCODE_GSPR] = kvm_handle_gspr, }; diff --git a/arch/loongarch/kvm/main.c b/arch/loongarch/kvm/main.c index 1c1d5199500eec..86a2f2d0cb27e3 100644 --- a/arch/loongarch/kvm/main.c +++ b/arch/loongarch/kvm/main.c @@ -287,7 +287,6 @@ int kvm_arch_hardware_enable(void) if (env & CSR_GCFG_MATC_ROOT) gcfg |= CSR_GCFG_MATC_ROOT; - gcfg |= CSR_GCFG_TIT; write_csr_gcfg(gcfg); kvm_flush_tlb_all(); diff --git a/arch/loongarch/kvm/mmu.c b/arch/loongarch/kvm/mmu.c index 80480df5f55054..50a6acd7ffe4c9 100644 --- a/arch/loongarch/kvm/mmu.c +++ b/arch/loongarch/kvm/mmu.c @@ -13,6 +13,16 @@ #include #include +static inline bool kvm_hugepage_capable(struct kvm_memory_slot *slot) +{ + return slot->arch.flags & KVM_MEM_HUGEPAGE_CAPABLE; +} + +static inline bool kvm_hugepage_incapable(struct kvm_memory_slot *slot) +{ + return slot->arch.flags & KVM_MEM_HUGEPAGE_INCAPABLE; +} + static inline void kvm_ptw_prepare(struct kvm *kvm, kvm_ptw_ctx *ctx) { ctx->level = kvm->arch.root_level; @@ -365,6 +375,69 @@ void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm, kvm_ptw_top(kvm->arch.pgd, start << PAGE_SHIFT, end << PAGE_SHIFT, &ctx); } +int kvm_arch_prepare_memory_region(struct kvm *kvm, const struct kvm_memory_slot *old, + struct kvm_memory_slot *new, enum kvm_mr_change change) +{ + gpa_t gpa_start; + hva_t hva_start; + size_t size, gpa_offset, hva_offset; + + if ((change != KVM_MR_MOVE) && (change != KVM_MR_CREATE)) + return 0; + /* + * Prevent userspace from creating a memory region outside of the + * VM GPA address space + */ + if ((new->base_gfn + new->npages) > (kvm->arch.gpa_size >> PAGE_SHIFT)) + return -ENOMEM; + + new->arch.flags = 0; + size = new->npages * PAGE_SIZE; + gpa_start = new->base_gfn << PAGE_SHIFT; + hva_start = new->userspace_addr; + if (IS_ALIGNED(size, PMD_SIZE) && IS_ALIGNED(gpa_start, PMD_SIZE) + && IS_ALIGNED(hva_start, PMD_SIZE)) + new->arch.flags |= KVM_MEM_HUGEPAGE_CAPABLE; + else { + /* + * Pages belonging to memslots that don't have the same + * alignment within a PMD for userspace and GPA cannot be + * mapped with PMD entries, because we'll end up mapping + * the wrong pages. + * + * Consider a layout like the following: + * + * memslot->userspace_addr: + * +-----+--------------------+--------------------+---+ + * |abcde|fgh Stage-1 block | Stage-1 block tv|xyz| + * +-----+--------------------+--------------------+---+ + * + * memslot->base_gfn << PAGE_SIZE: + * +---+--------------------+--------------------+-----+ + * |abc|def Stage-2 block | Stage-2 block |tvxyz| + * +---+--------------------+--------------------+-----+ + * + * If we create those stage-2 blocks, we'll end up with this + * incorrect mapping: + * d -> f + * e -> g + * f -> h + */ + gpa_offset = gpa_start & (PMD_SIZE - 1); + hva_offset = hva_start & (PMD_SIZE - 1); + if (gpa_offset != hva_offset) { + new->arch.flags |= KVM_MEM_HUGEPAGE_INCAPABLE; + } else { + if (gpa_offset == 0) + gpa_offset = PMD_SIZE; + if ((size + gpa_offset) < (PMD_SIZE * 2)) + new->arch.flags |= KVM_MEM_HUGEPAGE_INCAPABLE; + } + } + + return 0; +} + void kvm_arch_commit_memory_region(struct kvm *kvm, struct kvm_memory_slot *old, const struct kvm_memory_slot *new, @@ -562,47 +635,23 @@ out: } static bool fault_supports_huge_mapping(struct kvm_memory_slot *memslot, - unsigned long hva, unsigned long map_size, bool write) + unsigned long hva, bool write) { - size_t size; - gpa_t gpa_start; - hva_t uaddr_start, uaddr_end; + hva_t start, end; /* Disable dirty logging on HugePages */ if (kvm_slot_dirty_track_enabled(memslot) && write) return false; - size = memslot->npages * PAGE_SIZE; - gpa_start = memslot->base_gfn << PAGE_SHIFT; - uaddr_start = memslot->userspace_addr; - uaddr_end = uaddr_start + size; + if (kvm_hugepage_capable(memslot)) + return true; - /* - * Pages belonging to memslots that don't have the same alignment - * within a PMD for userspace and GPA cannot be mapped with stage-2 - * PMD entries, because we'll end up mapping the wrong pages. - * - * Consider a layout like the following: - * - * memslot->userspace_addr: - * +-----+--------------------+--------------------+---+ - * |abcde|fgh Stage-1 block | Stage-1 block tv|xyz| - * +-----+--------------------+--------------------+---+ - * - * memslot->base_gfn << PAGE_SIZE: - * +---+--------------------+--------------------+-----+ - * |abc|def Stage-2 block | Stage-2 block |tvxyz| - * +---+--------------------+--------------------+-----+ - * - * If we create those stage-2 blocks, we'll end up with this incorrect - * mapping: - * d -> f - * e -> g - * f -> h - */ - if ((gpa_start & (map_size - 1)) != (uaddr_start & (map_size - 1))) + if (kvm_hugepage_incapable(memslot)) return false; + start = memslot->userspace_addr; + end = start + memslot->npages * PAGE_SIZE; + /* * Next, let's make sure we're not trying to map anything not covered * by the memslot. This means we have to prohibit block size mappings @@ -615,8 +664,7 @@ static bool fault_supports_huge_mapping(struct kvm_memory_slot *memslot, * userspace_addr or the base_gfn, as both are equally aligned (per * the check above) and equally sized. */ - return (hva & ~(map_size - 1)) >= uaddr_start && - (hva & ~(map_size - 1)) + map_size <= uaddr_end; + return (hva >= ALIGN(start, PMD_SIZE)) && (hva < ALIGN_DOWN(end, PMD_SIZE)); } /* @@ -627,7 +675,7 @@ static bool fault_supports_huge_mapping(struct kvm_memory_slot *memslot, * * There are several ways to safely use this helper: * - * - Check mmu_invalidate_retry_hva() after grabbing the mapping level, before + * - Check mmu_invalidate_retry_gfn() after grabbing the mapping level, before * consuming it. In this case, mmu_lock doesn't need to be held during the * lookup, but it does need to be held while checking the MMU notifier. * @@ -807,7 +855,7 @@ retry: /* Check if an invalidation has taken place since we got pfn */ spin_lock(&kvm->mmu_lock); - if (mmu_invalidate_retry_hva(kvm, mmu_seq, hva)) { + if (mmu_invalidate_retry_gfn(kvm, mmu_seq, gfn)) { /* * This can happen when mappings are changed asynchronously, but * also synchronously if a COW is triggered by @@ -842,7 +890,7 @@ retry: /* Disable dirty logging on HugePages */ level = 0; - if (!fault_supports_huge_mapping(memslot, hva, PMD_SIZE, write)) { + if (!fault_supports_huge_mapping(memslot, hva, write)) { level = 0; } else { level = host_pfn_mapping_level(kvm, gfn, memslot); @@ -901,12 +949,6 @@ void kvm_arch_sync_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot) { } -int kvm_arch_prepare_memory_region(struct kvm *kvm, const struct kvm_memory_slot *old, - struct kvm_memory_slot *new, enum kvm_mr_change change) -{ - return 0; -} - void kvm_arch_flush_remote_tlbs_memslot(struct kvm *kvm, const struct kvm_memory_slot *memslot) { diff --git a/arch/loongarch/kvm/switch.S b/arch/loongarch/kvm/switch.S index 0ed9040307b715..ba976509bfe819 100644 --- a/arch/loongarch/kvm/switch.S +++ b/arch/loongarch/kvm/switch.S @@ -245,6 +245,37 @@ SYM_FUNC_START(kvm_restore_fpu) jr ra SYM_FUNC_END(kvm_restore_fpu) +#ifdef CONFIG_CPU_HAS_LSX +SYM_FUNC_START(kvm_save_lsx) + fpu_save_csr a0 t1 + fpu_save_cc a0 t1 t2 + lsx_save_data a0 t1 + jr ra +SYM_FUNC_END(kvm_save_lsx) + +SYM_FUNC_START(kvm_restore_lsx) + lsx_restore_data a0 t1 + fpu_restore_cc a0 t1 t2 + fpu_restore_csr a0 t1 t2 + jr ra +SYM_FUNC_END(kvm_restore_lsx) +#endif + +#ifdef CONFIG_CPU_HAS_LASX +SYM_FUNC_START(kvm_save_lasx) + fpu_save_csr a0 t1 + fpu_save_cc a0 t1 t2 + lasx_save_data a0 t1 + jr ra +SYM_FUNC_END(kvm_save_lasx) + +SYM_FUNC_START(kvm_restore_lasx) + lasx_restore_data a0 t1 + fpu_restore_cc a0 t1 t2 + fpu_restore_csr a0 t1 t2 + jr ra +SYM_FUNC_END(kvm_restore_lasx) +#endif .section ".rodata" SYM_DATA(kvm_exception_size, .quad kvm_exc_entry_end - kvm_exc_entry) SYM_DATA(kvm_enter_guest_size, .quad kvm_enter_guest_end - kvm_enter_guest) diff --git a/arch/loongarch/kvm/timer.c b/arch/loongarch/kvm/timer.c index 284bf553fefef5..111328f6087285 100644 --- a/arch/loongarch/kvm/timer.c +++ b/arch/loongarch/kvm/timer.c @@ -64,41 +64,24 @@ void kvm_init_timer(struct kvm_vcpu *vcpu, unsigned long timer_hz) kvm_write_sw_gcsr(vcpu->arch.csr, LOONGARCH_CSR_TVAL, 0); } -/* - * Restore hard timer state and enable guest to access timer registers - * without trap, should be called with irq disabled - */ -void kvm_acquire_timer(struct kvm_vcpu *vcpu) -{ - unsigned long cfg; - - cfg = read_csr_gcfg(); - if (!(cfg & CSR_GCFG_TIT)) - return; - - /* Enable guest access to hard timer */ - write_csr_gcfg(cfg & ~CSR_GCFG_TIT); - - /* - * Freeze the soft-timer and sync the guest stable timer with it. We do - * this with interrupts disabled to avoid latency. - */ - hrtimer_cancel(&vcpu->arch.swtimer); -} - /* * Restore soft timer state from saved context. */ void kvm_restore_timer(struct kvm_vcpu *vcpu) { - unsigned long cfg, delta, period; + unsigned long cfg, estat; + unsigned long ticks, delta, period; ktime_t expire, now; struct loongarch_csrs *csr = vcpu->arch.csr; /* * Set guest stable timer cfg csr + * Disable timer before restore estat CSR register, avoid to + * get invalid timer interrupt for old timer cfg */ cfg = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_TCFG); + + write_gcsr_timercfg(0); kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_ESTAT); kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_TCFG); if (!(cfg & CSR_TCFG_EN)) { @@ -107,24 +90,56 @@ void kvm_restore_timer(struct kvm_vcpu *vcpu) return; } + /* + * Freeze the soft-timer and sync the guest stable timer with it. + */ + hrtimer_cancel(&vcpu->arch.swtimer); + + /* + * From LoongArch Reference Manual Volume 1 Chapter 7.6.2 + * If oneshot timer is fired, CSR TVAL will be -1, there are two + * conditions: + * 1) timer is fired during exiting to host + * 2) timer is fired and vm is doing timer irq, and then exiting to + * host. Host should not inject timer irq to avoid spurious + * timer interrupt again + */ + ticks = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_TVAL); + estat = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_ESTAT); + if (!(cfg & CSR_TCFG_PERIOD) && (ticks > cfg)) { + /* + * Writing 0 to LOONGARCH_CSR_TVAL will inject timer irq + * and set CSR TVAL with -1 + */ + write_gcsr_timertick(0); + + /* + * Writing CSR_TINTCLR_TI to LOONGARCH_CSR_TINTCLR will clear + * timer interrupt, and CSR TVAL keeps unchanged with -1, it + * avoids spurious timer interrupt + */ + if (!(estat & CPU_TIMER)) + gcsr_write(CSR_TINTCLR_TI, LOONGARCH_CSR_TINTCLR); + return; + } + /* * Set remainder tick value if not expired */ + delta = 0; now = ktime_get(); expire = vcpu->arch.expire; if (ktime_before(now, expire)) delta = ktime_to_tick(vcpu, ktime_sub(expire, now)); - else { - if (cfg & CSR_TCFG_PERIOD) { - period = cfg & CSR_TCFG_VAL; - delta = ktime_to_tick(vcpu, ktime_sub(now, expire)); - delta = period - (delta % period); - } else - delta = 0; + else if (cfg & CSR_TCFG_PERIOD) { + period = cfg & CSR_TCFG_VAL; + delta = ktime_to_tick(vcpu, ktime_sub(now, expire)); + delta = period - (delta % period); + /* * Inject timer here though sw timer should inject timer * interrupt async already, since sw timer may be cancelled - * during injecting intr async in function kvm_acquire_timer + * during injecting intr async */ kvm_queue_irq(vcpu, INT_TI); } @@ -139,27 +154,41 @@ void kvm_restore_timer(struct kvm_vcpu *vcpu) */ static void _kvm_save_timer(struct kvm_vcpu *vcpu) { - unsigned long ticks, delta; + unsigned long ticks, delta, cfg; ktime_t expire; struct loongarch_csrs *csr = vcpu->arch.csr; + cfg = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_TCFG); ticks = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_TVAL); - delta = tick_to_ns(vcpu, ticks); - expire = ktime_add_ns(ktime_get(), delta); - vcpu->arch.expire = expire; - if (ticks) { + + /* + * From LoongArch Reference Manual Volume 1 Chapter 7.6.2 + * If period timer is fired, CSR TVAL will be reloaded from CSR TCFG + * If oneshot timer is fired, CSR TVAL will be -1 + * Here judge one-shot timer fired by checking whether TVAL is larger + * than TCFG + */ + if (ticks < cfg) { + delta = tick_to_ns(vcpu, ticks); + expire = ktime_add_ns(ktime_get(), delta); + vcpu->arch.expire = expire; + /* - * Update hrtimer to use new timeout * HRTIMER_MODE_PINNED is suggested since vcpu may run in * the same physical cpu in next time */ - hrtimer_cancel(&vcpu->arch.swtimer); hrtimer_start(&vcpu->arch.swtimer, expire, HRTIMER_MODE_ABS_PINNED); - } else + } else if (vcpu->stat.generic.blocking) { /* - * Inject timer interrupt so that hall polling can dectect and exit + * Inject timer interrupt so that halt polling can dectect and exit. + * VCPU is scheduled out already and sleeps in rcuwait queue and + * will not poll pending events again. kvm_queue_irq() is not enough, + * hrtimer swtimer should be used here. */ - kvm_queue_irq(vcpu, INT_TI); + expire = ktime_add_ns(ktime_get(), 10); + vcpu->arch.expire = expire; + hrtimer_start(&vcpu->arch.swtimer, expire, HRTIMER_MODE_ABS_PINNED); + } } /* @@ -168,21 +197,15 @@ static void _kvm_save_timer(struct kvm_vcpu *vcpu) */ void kvm_save_timer(struct kvm_vcpu *vcpu) { - unsigned long cfg; struct loongarch_csrs *csr = vcpu->arch.csr; preempt_disable(); - cfg = read_csr_gcfg(); - if (!(cfg & CSR_GCFG_TIT)) { - /* Disable guest use of hard timer */ - write_csr_gcfg(cfg | CSR_GCFG_TIT); - - /* Save hard timer state */ - kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TCFG); - kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TVAL); - if (kvm_read_sw_gcsr(csr, LOONGARCH_CSR_TCFG) & CSR_TCFG_EN) - _kvm_save_timer(vcpu); - } + + /* Save hard timer state */ + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TCFG); + kvm_save_hw_gcsr(csr, LOONGARCH_CSR_TVAL); + if (kvm_read_sw_gcsr(csr, LOONGARCH_CSR_TCFG) & CSR_TCFG_EN) + _kvm_save_timer(vcpu); /* Save timer-related state to vCPU context */ kvm_save_hw_gcsr(csr, LOONGARCH_CSR_ESTAT); diff --git a/arch/loongarch/kvm/trace.h b/arch/loongarch/kvm/trace.h index a1e35d6554185c..c2484ad4cffa21 100644 --- a/arch/loongarch/kvm/trace.h +++ b/arch/loongarch/kvm/trace.h @@ -102,6 +102,8 @@ TRACE_EVENT(kvm_exit_gspr, #define KVM_TRACE_AUX_DISCARD 4 #define KVM_TRACE_AUX_FPU 1 +#define KVM_TRACE_AUX_LSX 2 +#define KVM_TRACE_AUX_LASX 3 #define kvm_trace_symbol_aux_op \ { KVM_TRACE_AUX_SAVE, "save" }, \ @@ -111,7 +113,9 @@ TRACE_EVENT(kvm_exit_gspr, { KVM_TRACE_AUX_DISCARD, "discard" } #define kvm_trace_symbol_aux_state \ - { KVM_TRACE_AUX_FPU, "FPU" } + { KVM_TRACE_AUX_FPU, "FPU" }, \ + { KVM_TRACE_AUX_LSX, "LSX" }, \ + { KVM_TRACE_AUX_LASX, "LASX" } TRACE_EVENT(kvm_aux, TP_PROTO(struct kvm_vcpu *vcpu, unsigned int op, diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c index 73d0c2b9c1a576..27701991886dda 100644 --- a/arch/loongarch/kvm/vcpu.c +++ b/arch/loongarch/kvm/vcpu.c @@ -95,7 +95,6 @@ static int kvm_pre_enter_guest(struct kvm_vcpu *vcpu) * check vmid before vcpu enter guest */ local_irq_disable(); - kvm_acquire_timer(vcpu); kvm_deliver_intr(vcpu); kvm_deliver_exception(vcpu); /* Make sure the vcpu mode has been written */ @@ -187,8 +186,15 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) { - return kvm_pending_timer(vcpu) || + int ret; + + /* Protect from TOD sync and vcpu_load/put() */ + preempt_disable(); + ret = kvm_pending_timer(vcpu) || kvm_read_hw_gcsr(LOONGARCH_CSR_ESTAT) & (1 << INT_TI); + preempt_enable(); + + return ret; } int kvm_arch_vcpu_dump_regs(struct kvm_vcpu *vcpu) @@ -244,23 +250,6 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, return -EINVAL; } -/** - * kvm_migrate_count() - Migrate timer. - * @vcpu: Virtual CPU. - * - * Migrate hrtimer to the current CPU by cancelling and restarting it - * if the hrtimer is active. - * - * Must be called when the vCPU is migrated to a different CPU, so that - * the timer can interrupt the guest at the new CPU, and the timer irq can - * be delivered to the vCPU. - */ -static void kvm_migrate_count(struct kvm_vcpu *vcpu) -{ - if (hrtimer_cancel(&vcpu->arch.swtimer)) - hrtimer_restart(&vcpu->arch.swtimer); -} - static int _kvm_getcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 *val) { unsigned long gintc; @@ -309,6 +298,76 @@ static int _kvm_setcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 val) return ret; } +static int _kvm_get_cpucfg(int id, u64 *v) +{ + int ret = 0; + + if (id < 0 && id >= KVM_MAX_CPUCFG_REGS) + return -EINVAL; + + switch (id) { + case 2: + /* Return CPUCFG2 features which have been supported by KVM */ + *v = CPUCFG2_FP | CPUCFG2_FPSP | CPUCFG2_FPDP | + CPUCFG2_FPVERS | CPUCFG2_LLFTP | CPUCFG2_LLFTPREV | + CPUCFG2_LAM; + /* + * If LSX is supported by CPU, it is also supported by KVM, + * as we implement it. + */ + if (cpu_has_lsx) + *v |= CPUCFG2_LSX; + /* + * if LASX is supported by CPU, it is also supported by KVM, + * as we implement it. + */ + if (cpu_has_lasx) + *v |= CPUCFG2_LASX; + + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +static int kvm_check_cpucfg(int id, u64 val) +{ + u64 mask; + int ret = 0; + + if (id < 0 && id >= KVM_MAX_CPUCFG_REGS) + return -EINVAL; + + if (_kvm_get_cpucfg(id, &mask)) + return ret; + + switch (id) { + case 2: + /* CPUCFG2 features checking */ + if (val & ~mask) + /* The unsupported features should not be set */ + ret = -EINVAL; + else if (!(val & CPUCFG2_LLFTP)) + /* The LLFTP must be set, as guest must has a constant timer */ + ret = -EINVAL; + else if ((val & CPUCFG2_FP) && (!(val & CPUCFG2_FPSP) || !(val & CPUCFG2_FPDP))) + /* Single and double float point must both be set when enable FP */ + ret = -EINVAL; + else if ((val & CPUCFG2_LSX) && !(val & CPUCFG2_FP)) + /* FP should be set when enable LSX */ + ret = -EINVAL; + else if ((val & CPUCFG2_LASX) && !(val & CPUCFG2_LSX)) + /* LSX, FP should be set when enable LASX, and FP has been checked before. */ + ret = -EINVAL; + break; + default: + break; + } + return ret; +} + static int kvm_get_one_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg, u64 *v) { @@ -378,10 +437,10 @@ static int kvm_set_one_reg(struct kvm_vcpu *vcpu, break; case KVM_REG_LOONGARCH_CPUCFG: id = KVM_GET_IOC_CPUCFG_IDX(reg->id); - if (id >= 0 && id < KVM_MAX_CPUCFG_REGS) - vcpu->arch.cpucfg[id] = (u32)v; - else - ret = -EINVAL; + ret = kvm_check_cpucfg(id, v); + if (ret) + break; + vcpu->arch.cpucfg[id] = (u32)v; break; case KVM_REG_LOONGARCH_KVM: switch (reg->id) { @@ -471,10 +530,94 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, return -EINVAL; } +static int kvm_loongarch_cpucfg_has_attr(struct kvm_vcpu *vcpu, + struct kvm_device_attr *attr) +{ + switch (attr->attr) { + case 2: + return 0; + default: + return -ENXIO; + } + + return -ENXIO; +} + +static int kvm_loongarch_vcpu_has_attr(struct kvm_vcpu *vcpu, + struct kvm_device_attr *attr) +{ + int ret = -ENXIO; + + switch (attr->group) { + case KVM_LOONGARCH_VCPU_CPUCFG: + ret = kvm_loongarch_cpucfg_has_attr(vcpu, attr); + break; + default: + break; + } + + return ret; +} + +static int kvm_loongarch_get_cpucfg_attr(struct kvm_vcpu *vcpu, + struct kvm_device_attr *attr) +{ + int ret = 0; + uint64_t val; + uint64_t __user *uaddr = (uint64_t __user *)attr->addr; + + ret = _kvm_get_cpucfg(attr->attr, &val); + if (ret) + return ret; + + put_user(val, uaddr); + + return ret; +} + +static int kvm_loongarch_vcpu_get_attr(struct kvm_vcpu *vcpu, + struct kvm_device_attr *attr) +{ + int ret = -ENXIO; + + switch (attr->group) { + case KVM_LOONGARCH_VCPU_CPUCFG: + ret = kvm_loongarch_get_cpucfg_attr(vcpu, attr); + break; + default: + break; + } + + return ret; +} + +static int kvm_loongarch_cpucfg_set_attr(struct kvm_vcpu *vcpu, + struct kvm_device_attr *attr) +{ + return -ENXIO; +} + +static int kvm_loongarch_vcpu_set_attr(struct kvm_vcpu *vcpu, + struct kvm_device_attr *attr) +{ + int ret = -ENXIO; + + switch (attr->group) { + case KVM_LOONGARCH_VCPU_CPUCFG: + ret = kvm_loongarch_cpucfg_set_attr(vcpu, attr); + break; + default: + break; + } + + return ret; +} + long kvm_arch_vcpu_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { long r; + struct kvm_device_attr attr; void __user *argp = (void __user *)arg; struct kvm_vcpu *vcpu = filp->private_data; @@ -514,6 +657,27 @@ long kvm_arch_vcpu_ioctl(struct file *filp, r = kvm_vcpu_ioctl_enable_cap(vcpu, &cap); break; } + case KVM_HAS_DEVICE_ATTR: { + r = -EFAULT; + if (copy_from_user(&attr, argp, sizeof(attr))) + break; + r = kvm_loongarch_vcpu_has_attr(vcpu, &attr); + break; + } + case KVM_GET_DEVICE_ATTR: { + r = -EFAULT; + if (copy_from_user(&attr, argp, sizeof(attr))) + break; + r = kvm_loongarch_vcpu_get_attr(vcpu, &attr); + break; + } + case KVM_SET_DEVICE_ATTR: { + r = -EFAULT; + if (copy_from_user(&attr, argp, sizeof(attr))) + break; + r = kvm_loongarch_vcpu_set_attr(vcpu, &attr); + break; + } default: r = -ENOIOCTLCMD; break; @@ -561,12 +725,96 @@ void kvm_own_fpu(struct kvm_vcpu *vcpu) preempt_enable(); } +#ifdef CONFIG_CPU_HAS_LSX +/* Enable LSX and restore context */ +int kvm_own_lsx(struct kvm_vcpu *vcpu) +{ + if (!kvm_guest_has_fpu(&vcpu->arch) || !kvm_guest_has_lsx(&vcpu->arch)) + return -EINVAL; + + preempt_disable(); + + /* Enable LSX for guest */ + set_csr_euen(CSR_EUEN_LSXEN | CSR_EUEN_FPEN); + switch (vcpu->arch.aux_inuse & KVM_LARCH_FPU) { + case KVM_LARCH_FPU: + /* + * Guest FPU state already loaded, + * only restore upper LSX state + */ + _restore_lsx_upper(&vcpu->arch.fpu); + break; + default: + /* Neither FP or LSX already active, + * restore full LSX state + */ + kvm_restore_lsx(&vcpu->arch.fpu); + break; + } + + trace_kvm_aux(vcpu, KVM_TRACE_AUX_RESTORE, KVM_TRACE_AUX_LSX); + vcpu->arch.aux_inuse |= KVM_LARCH_LSX | KVM_LARCH_FPU; + preempt_enable(); + + return 0; +} +#endif + +#ifdef CONFIG_CPU_HAS_LASX +/* Enable LASX and restore context */ +int kvm_own_lasx(struct kvm_vcpu *vcpu) +{ + if (!kvm_guest_has_fpu(&vcpu->arch) || !kvm_guest_has_lsx(&vcpu->arch) || !kvm_guest_has_lasx(&vcpu->arch)) + return -EINVAL; + + preempt_disable(); + + set_csr_euen(CSR_EUEN_FPEN | CSR_EUEN_LSXEN | CSR_EUEN_LASXEN); + switch (vcpu->arch.aux_inuse & (KVM_LARCH_FPU | KVM_LARCH_LSX)) { + case KVM_LARCH_LSX: + case KVM_LARCH_LSX | KVM_LARCH_FPU: + /* Guest LSX state already loaded, only restore upper LASX state */ + _restore_lasx_upper(&vcpu->arch.fpu); + break; + case KVM_LARCH_FPU: + /* Guest FP state already loaded, only restore upper LSX & LASX state */ + _restore_lsx_upper(&vcpu->arch.fpu); + _restore_lasx_upper(&vcpu->arch.fpu); + break; + default: + /* Neither FP or LSX already active, restore full LASX state */ + kvm_restore_lasx(&vcpu->arch.fpu); + break; + } + + trace_kvm_aux(vcpu, KVM_TRACE_AUX_RESTORE, KVM_TRACE_AUX_LASX); + vcpu->arch.aux_inuse |= KVM_LARCH_LASX | KVM_LARCH_LSX | KVM_LARCH_FPU; + preempt_enable(); + + return 0; +} +#endif + /* Save context and disable FPU */ void kvm_lose_fpu(struct kvm_vcpu *vcpu) { preempt_disable(); - if (vcpu->arch.aux_inuse & KVM_LARCH_FPU) { + if (vcpu->arch.aux_inuse & KVM_LARCH_LASX) { + kvm_save_lasx(&vcpu->arch.fpu); + vcpu->arch.aux_inuse &= ~(KVM_LARCH_LSX | KVM_LARCH_FPU | KVM_LARCH_LASX); + trace_kvm_aux(vcpu, KVM_TRACE_AUX_SAVE, KVM_TRACE_AUX_LASX); + + /* Disable LASX & LSX & FPU */ + clear_csr_euen(CSR_EUEN_FPEN | CSR_EUEN_LSXEN | CSR_EUEN_LASXEN); + } else if (vcpu->arch.aux_inuse & KVM_LARCH_LSX) { + kvm_save_lsx(&vcpu->arch.fpu); + vcpu->arch.aux_inuse &= ~(KVM_LARCH_LSX | KVM_LARCH_FPU); + trace_kvm_aux(vcpu, KVM_TRACE_AUX_SAVE, KVM_TRACE_AUX_LSX); + + /* Disable LSX & FPU */ + clear_csr_euen(CSR_EUEN_FPEN | CSR_EUEN_LSXEN); + } else if (vcpu->arch.aux_inuse & KVM_LARCH_FPU) { kvm_save_fpu(&vcpu->arch.fpu); vcpu->arch.aux_inuse &= ~KVM_LARCH_FPU; trace_kvm_aux(vcpu, KVM_TRACE_AUX_SAVE, KVM_TRACE_AUX_FPU); @@ -789,17 +1037,6 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) unsigned long flags; local_irq_save(flags); - if (vcpu->arch.last_sched_cpu != cpu) { - kvm_debug("[%d->%d]KVM vCPU[%d] switch\n", - vcpu->arch.last_sched_cpu, cpu, vcpu->vcpu_id); - /* - * Migrate the timer interrupt to the current CPU so that it - * always interrupts the guest and synchronously triggers a - * guest timer interrupt. - */ - kvm_migrate_count(vcpu); - } - /* Restore guest state to registers */ _kvm_vcpu_load(vcpu, cpu); local_irq_restore(flags); diff --git a/arch/loongarch/mm/tlb.c b/arch/loongarch/mm/tlb.c index 2c0a411f23aa77..0b95d32b30c947 100644 --- a/arch/loongarch/mm/tlb.c +++ b/arch/loongarch/mm/tlb.c @@ -284,12 +284,16 @@ static void setup_tlb_handler(int cpu) set_handler(EXCCODE_TLBNR * VECSIZE, handle_tlb_protect, VECSIZE); set_handler(EXCCODE_TLBNX * VECSIZE, handle_tlb_protect, VECSIZE); set_handler(EXCCODE_TLBPE * VECSIZE, handle_tlb_protect, VECSIZE); - } + } else { + int vec_sz __maybe_unused; + void *addr __maybe_unused; + struct page *page __maybe_unused; + + /* Avoid lockdep warning */ + rcutree_report_cpu_starting(cpu); + #ifdef CONFIG_NUMA - else { - void *addr; - struct page *page; - const int vec_sz = sizeof(exception_handlers); + vec_sz = sizeof(exception_handlers); if (pcpu_handlers[cpu]) return; @@ -305,8 +309,8 @@ static void setup_tlb_handler(int cpu) csr_write64(pcpu_handlers[cpu], LOONGARCH_CSR_EENTRY); csr_write64(pcpu_handlers[cpu], LOONGARCH_CSR_MERRENTRY); csr_write64(pcpu_handlers[cpu] + 80*VECSIZE, LOONGARCH_CSR_TLBRENTRY); - } #endif + } } void tlb_init(int cpu) diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c index 4fcd6cd6da234d..e73323d759d0b8 100644 --- a/arch/loongarch/net/bpf_jit.c +++ b/arch/loongarch/net/bpf_jit.c @@ -201,6 +201,11 @@ bool bpf_jit_supports_kfunc_call(void) return true; } +bool bpf_jit_supports_far_kfunc_call(void) +{ + return true; +} + /* initialized on the first pass of build_body() */ static int out_offset = -1; static int emit_bpf_tail_call(struct jit_ctx *ctx) @@ -465,7 +470,6 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext const u8 dst = regmap[insn->dst_reg]; const s16 off = insn->off; const s32 imm = insn->imm; - const u64 imm64 = (u64)(insn + 1)->imm << 32 | (u32)insn->imm; const bool is32 = BPF_CLASS(insn->code) == BPF_ALU || BPF_CLASS(insn->code) == BPF_JMP32; switch (code) { @@ -923,8 +927,12 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext /* dst = imm64 */ case BPF_LD | BPF_IMM | BPF_DW: + { + const u64 imm64 = (u64)(insn + 1)->imm << 32 | (u32)insn->imm; + move_imm(ctx, dst, imm64, is32); return 1; + } /* dst = *(size *)(src + off) */ case BPF_LDX | BPF_MEM | BPF_B: diff --git a/arch/loongarch/vdso/vgettimeofday.c b/arch/loongarch/vdso/vgettimeofday.c index 8f22863bd7ea81..0885c1f3a89df7 100644 --- a/arch/loongarch/vdso/vgettimeofday.c +++ b/arch/loongarch/vdso/vgettimeofday.c @@ -5,23 +5,18 @@ * Copyright (C) 2020-2022 Loongson Technology Corporation Limited */ #include +#include -extern -int __vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts); int __vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts) { return __cvdso_clock_gettime(clock, ts); } -extern -int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz); int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz) { return __cvdso_gettimeofday(tv, tz); } -extern -int __vdso_clock_getres(clockid_t clock_id, struct __kernel_timespec *res); int __vdso_clock_getres(clockid_t clock_id, struct __kernel_timespec *res) { return __cvdso_clock_getres(clock_id, res); diff --git a/arch/m68k/Kconfig.cpu b/arch/m68k/Kconfig.cpu index ad69b466a08bd1..9dcf245c9cbfab 100644 --- a/arch/m68k/Kconfig.cpu +++ b/arch/m68k/Kconfig.cpu @@ -402,7 +402,7 @@ config ARCH_FORCE_MAX_ORDER default "10" help The kernel page allocator limits the size of maximal physically - contiguous allocations. The limit is called MAX_ORDER and it + contiguous allocations. The limit is called MAX_PAGE_ORDER and it defines the maximal power of two of number of pages that can be allocated as a single contiguous block. This option allows overriding the default setting when ability to allocate very diff --git a/arch/m68k/coldfire/vectors.c b/arch/m68k/coldfire/vectors.c index c26c255b530d8a..4321fd89d83e16 100644 --- a/arch/m68k/coldfire/vectors.c +++ b/arch/m68k/coldfire/vectors.c @@ -12,14 +12,13 @@ #include #include #include +#include #include #include #include #include #include -#include "vectors.h" - /***************************************************************************/ #ifdef TRAP_DBG_INTERRUPT diff --git a/arch/m68k/coldfire/vectors.h b/arch/m68k/coldfire/vectors.h deleted file mode 100644 index 0b01450a43530c..00000000000000 --- a/arch/m68k/coldfire/vectors.h +++ /dev/null @@ -1,3 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ - -void trap_init(void); diff --git a/arch/m68k/configs/amiga_defconfig b/arch/m68k/configs/amiga_defconfig index 7e6b74b6eecd39..b4d71fea558f1f 100644 --- a/arch/m68k/configs/amiga_defconfig +++ b/arch/m68k/configs/amiga_defconfig @@ -453,6 +453,7 @@ CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m CONFIG_OCFS2_FS=m # CONFIG_OCFS2_DEBUG_MASKLOG is not set +CONFIG_BCACHEFS_FS=m CONFIG_FANOTIFY=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_AUTOFS_FS=m @@ -550,7 +551,6 @@ CONFIG_NLS_MAC_TURKISH=m CONFIG_DLM=m CONFIG_ENCRYPTED_KEYS=m CONFIG_HARDENED_USERCOPY=y -CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m CONFIG_CRYPTO_TEST=m diff --git a/arch/m68k/configs/apollo_defconfig b/arch/m68k/configs/apollo_defconfig index 0b403e2efcd5e3..682d8cd3dd3cea 100644 --- a/arch/m68k/configs/apollo_defconfig +++ b/arch/m68k/configs/apollo_defconfig @@ -410,6 +410,7 @@ CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m CONFIG_OCFS2_FS=m # CONFIG_OCFS2_DEBUG_MASKLOG is not set +CONFIG_BCACHEFS_FS=m CONFIG_FANOTIFY=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_AUTOFS_FS=m @@ -507,7 +508,6 @@ CONFIG_NLS_MAC_TURKISH=m CONFIG_DLM=m CONFIG_ENCRYPTED_KEYS=m CONFIG_HARDENED_USERCOPY=y -CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m CONFIG_CRYPTO_TEST=m diff --git a/arch/m68k/configs/atari_defconfig b/arch/m68k/configs/atari_defconfig index 57aac3f4b001ef..15259ced84632b 100644 --- a/arch/m68k/configs/atari_defconfig +++ b/arch/m68k/configs/atari_defconfig @@ -430,6 +430,7 @@ CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m CONFIG_OCFS2_FS=m # CONFIG_OCFS2_DEBUG_MASKLOG is not set +CONFIG_BCACHEFS_FS=m CONFIG_FANOTIFY=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_AUTOFS_FS=m @@ -527,7 +528,6 @@ CONFIG_NLS_MAC_TURKISH=m CONFIG_DLM=m CONFIG_ENCRYPTED_KEYS=m CONFIG_HARDENED_USERCOPY=y -CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m CONFIG_CRYPTO_TEST=m diff --git a/arch/m68k/configs/bvme6000_defconfig b/arch/m68k/configs/bvme6000_defconfig index 3c160636a2e913..7395c12caef6e8 100644 --- a/arch/m68k/configs/bvme6000_defconfig +++ b/arch/m68k/configs/bvme6000_defconfig @@ -402,6 +402,7 @@ CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m CONFIG_OCFS2_FS=m # CONFIG_OCFS2_DEBUG_MASKLOG is not set +CONFIG_BCACHEFS_FS=m CONFIG_FANOTIFY=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_AUTOFS_FS=m @@ -499,7 +500,6 @@ CONFIG_NLS_MAC_TURKISH=m CONFIG_DLM=m CONFIG_ENCRYPTED_KEYS=m CONFIG_HARDENED_USERCOPY=y -CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m CONFIG_CRYPTO_TEST=m diff --git a/arch/m68k/configs/hp300_defconfig b/arch/m68k/configs/hp300_defconfig index 23cf07c49d1411..92506bc7f78dae 100644 --- a/arch/m68k/configs/hp300_defconfig +++ b/arch/m68k/configs/hp300_defconfig @@ -412,6 +412,7 @@ CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m CONFIG_OCFS2_FS=m # CONFIG_OCFS2_DEBUG_MASKLOG is not set +CONFIG_BCACHEFS_FS=m CONFIG_FANOTIFY=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_AUTOFS_FS=m @@ -509,7 +510,6 @@ CONFIG_NLS_MAC_TURKISH=m CONFIG_DLM=m CONFIG_ENCRYPTED_KEYS=m CONFIG_HARDENED_USERCOPY=y -CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m CONFIG_CRYPTO_TEST=m diff --git a/arch/m68k/configs/mac_defconfig b/arch/m68k/configs/mac_defconfig index 619a0d93ce5bb2..144bc8c0d8b590 100644 --- a/arch/m68k/configs/mac_defconfig +++ b/arch/m68k/configs/mac_defconfig @@ -269,9 +269,6 @@ CONFIG_RDS_TCP=m CONFIG_L2TP=m CONFIG_BRIDGE=m CONFIG_ATALK=m -CONFIG_DEV_APPLETALK=m -CONFIG_IPDDP=m -CONFIG_IPDDP_ENCAP=y CONFIG_6LOWPAN=m CONFIG_6LOWPAN_GHC_EXT_HDR_HOP=m CONFIG_6LOWPAN_GHC_UDP=m @@ -432,6 +429,7 @@ CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m CONFIG_OCFS2_FS=m # CONFIG_OCFS2_DEBUG_MASKLOG is not set +CONFIG_BCACHEFS_FS=m CONFIG_FANOTIFY=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_AUTOFS_FS=m @@ -529,7 +527,6 @@ CONFIG_NLS_MAC_TURKISH=m CONFIG_DLM=m CONFIG_ENCRYPTED_KEYS=m CONFIG_HARDENED_USERCOPY=y -CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m CONFIG_CRYPTO_TEST=m diff --git a/arch/m68k/configs/multi_defconfig b/arch/m68k/configs/multi_defconfig index d9430bc2b2dea5..07594c72949773 100644 --- a/arch/m68k/configs/multi_defconfig +++ b/arch/m68k/configs/multi_defconfig @@ -289,9 +289,6 @@ CONFIG_RDS_TCP=m CONFIG_L2TP=m CONFIG_BRIDGE=m CONFIG_ATALK=m -CONFIG_DEV_APPLETALK=m -CONFIG_IPDDP=m -CONFIG_IPDDP_ENCAP=y CONFIG_6LOWPAN=m CONFIG_6LOWPAN_GHC_EXT_HDR_HOP=m CONFIG_6LOWPAN_GHC_UDP=m @@ -518,6 +515,7 @@ CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m CONFIG_OCFS2_FS=m # CONFIG_OCFS2_DEBUG_MASKLOG is not set +CONFIG_BCACHEFS_FS=m CONFIG_FANOTIFY=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_AUTOFS_FS=m @@ -615,7 +613,6 @@ CONFIG_NLS_MAC_TURKISH=m CONFIG_DLM=m CONFIG_ENCRYPTED_KEYS=m CONFIG_HARDENED_USERCOPY=y -CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m CONFIG_CRYPTO_TEST=m diff --git a/arch/m68k/configs/mvme147_defconfig b/arch/m68k/configs/mvme147_defconfig index eb6132f29bf50f..c34de6c1de203f 100644 --- a/arch/m68k/configs/mvme147_defconfig +++ b/arch/m68k/configs/mvme147_defconfig @@ -401,6 +401,7 @@ CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m CONFIG_OCFS2_FS=m # CONFIG_OCFS2_DEBUG_MASKLOG is not set +CONFIG_BCACHEFS_FS=m CONFIG_FANOTIFY=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_AUTOFS_FS=m @@ -498,7 +499,6 @@ CONFIG_NLS_MAC_TURKISH=m CONFIG_DLM=m CONFIG_ENCRYPTED_KEYS=m CONFIG_HARDENED_USERCOPY=y -CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m CONFIG_CRYPTO_TEST=m diff --git a/arch/m68k/configs/mvme16x_defconfig b/arch/m68k/configs/mvme16x_defconfig index d0bad674cbb7ae..83bc029d1f3353 100644 --- a/arch/m68k/configs/mvme16x_defconfig +++ b/arch/m68k/configs/mvme16x_defconfig @@ -402,6 +402,7 @@ CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m CONFIG_OCFS2_FS=m # CONFIG_OCFS2_DEBUG_MASKLOG is not set +CONFIG_BCACHEFS_FS=m CONFIG_FANOTIFY=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_AUTOFS_FS=m @@ -499,7 +500,6 @@ CONFIG_NLS_MAC_TURKISH=m CONFIG_DLM=m CONFIG_ENCRYPTED_KEYS=m CONFIG_HARDENED_USERCOPY=y -CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m CONFIG_CRYPTO_TEST=m diff --git a/arch/m68k/configs/q40_defconfig b/arch/m68k/configs/q40_defconfig index dad6bcfcaeed35..4f551dac2ed72e 100644 --- a/arch/m68k/configs/q40_defconfig +++ b/arch/m68k/configs/q40_defconfig @@ -419,6 +419,7 @@ CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m CONFIG_OCFS2_FS=m # CONFIG_OCFS2_DEBUG_MASKLOG is not set +CONFIG_BCACHEFS_FS=m CONFIG_FANOTIFY=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_AUTOFS_FS=m @@ -516,7 +517,6 @@ CONFIG_NLS_MAC_TURKISH=m CONFIG_DLM=m CONFIG_ENCRYPTED_KEYS=m CONFIG_HARDENED_USERCOPY=y -CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m CONFIG_CRYPTO_TEST=m diff --git a/arch/m68k/configs/sun3_defconfig b/arch/m68k/configs/sun3_defconfig index eb1b489b3139cc..b1bf01182bd32f 100644 --- a/arch/m68k/configs/sun3_defconfig +++ b/arch/m68k/configs/sun3_defconfig @@ -400,6 +400,7 @@ CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m CONFIG_OCFS2_FS=m # CONFIG_OCFS2_DEBUG_MASKLOG is not set +CONFIG_BCACHEFS_FS=m CONFIG_FANOTIFY=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_AUTOFS_FS=m @@ -497,7 +498,6 @@ CONFIG_NLS_MAC_TURKISH=m CONFIG_DLM=m CONFIG_ENCRYPTED_KEYS=m CONFIG_HARDENED_USERCOPY=y -CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m CONFIG_CRYPTO_TEST=m diff --git a/arch/m68k/configs/sun3x_defconfig b/arch/m68k/configs/sun3x_defconfig index 9395898265465d..5c9a3f71f036e3 100644 --- a/arch/m68k/configs/sun3x_defconfig +++ b/arch/m68k/configs/sun3x_defconfig @@ -400,6 +400,7 @@ CONFIG_REISERFS_FS=m CONFIG_JFS_FS=m CONFIG_OCFS2_FS=m # CONFIG_OCFS2_DEBUG_MASKLOG is not set +CONFIG_BCACHEFS_FS=m CONFIG_FANOTIFY=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_AUTOFS_FS=m @@ -497,7 +498,6 @@ CONFIG_NLS_MAC_TURKISH=m CONFIG_DLM=m CONFIG_ENCRYPTED_KEYS=m CONFIG_HARDENED_USERCOPY=y -CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_USER=m CONFIG_CRYPTO_CRYPTD=m CONFIG_CRYPTO_TEST=m diff --git a/arch/m68k/emu/nfcon.c b/arch/m68k/emu/nfcon.c index 3a74d493eb3e6e..17b2987c2bf543 100644 --- a/arch/m68k/emu/nfcon.c +++ b/arch/m68k/emu/nfcon.c @@ -23,9 +23,9 @@ static int stderr_id; static struct tty_port nfcon_tty_port; static struct tty_driver *nfcon_tty_driver; -static void nfputs(const char *str, unsigned int count) +static void nfputs(const u8 *str, size_t count) { - char buf[68]; + u8 buf[68]; unsigned long phys = virt_to_phys(buf); buf[64] = 0; diff --git a/arch/m68k/include/asm/cacheflush_mm.h b/arch/m68k/include/asm/cacheflush_mm.h index ed12358c4783b4..9a71b0148461a4 100644 --- a/arch/m68k/include/asm/cacheflush_mm.h +++ b/arch/m68k/include/asm/cacheflush_mm.h @@ -191,6 +191,7 @@ extern void cache_push_v(unsigned long vaddr, int len); #define flush_cache_all() __flush_cache_all() #define flush_cache_vmap(start, end) flush_cache_all() +#define flush_cache_vmap_early(start, end) do { } while (0) #define flush_cache_vunmap(start, end) flush_cache_all() static inline void flush_cache_mm(struct mm_struct *mm) diff --git a/arch/m68k/include/asm/io_mm.h b/arch/m68k/include/asm/io_mm.h index 47525f2a57e1b4..090aec54b8fa6e 100644 --- a/arch/m68k/include/asm/io_mm.h +++ b/arch/m68k/include/asm/io_mm.h @@ -389,12 +389,6 @@ static inline void isa_delay(void) #define __ARCH_HAS_NO_PAGE_ZERO_MAPPED 1 -/* - * Convert a physical pointer to a virtual kernel pointer for /dev/mem - * access - */ -#define xlate_dev_mem_ptr(p) __va(p) - #define readb_relaxed(addr) readb(addr) #define readw_relaxed(addr) readw(addr) #define readl_relaxed(addr) readl(addr) diff --git a/arch/m68k/include/asm/kmap.h b/arch/m68k/include/asm/kmap.h index 4efb3efa593a4f..b778f015c917f9 100644 --- a/arch/m68k/include/asm/kmap.h +++ b/arch/m68k/include/asm/kmap.h @@ -25,7 +25,6 @@ static inline void __iomem *ioremap(unsigned long physaddr, unsigned long size) return __ioremap(physaddr, size, IOMAP_NOCACHE_SER); } -#define ioremap_uc ioremap #define ioremap_wt ioremap_wt static inline void __iomem *ioremap_wt(unsigned long physaddr, unsigned long size) diff --git a/arch/m68k/include/asm/processor.h b/arch/m68k/include/asm/processor.h index 7a2da780830b8f..8f2676c3a9882d 100644 --- a/arch/m68k/include/asm/processor.h +++ b/arch/m68k/include/asm/processor.h @@ -8,6 +8,7 @@ #ifndef __ASM_M68K_PROCESSOR_H #define __ASM_M68K_PROCESSOR_H +#include #include #include #include diff --git a/arch/m68k/kernel/syscalls/syscall.tbl b/arch/m68k/kernel/syscalls/syscall.tbl index 7a4b780e82cbdc..7fd43fd4c9f2e2 100644 --- a/arch/m68k/kernel/syscalls/syscall.tbl +++ b/arch/m68k/kernel/syscalls/syscall.tbl @@ -456,3 +456,8 @@ 454 common futex_wake sys_futex_wake 455 common futex_wait sys_futex_wait 456 common futex_requeue sys_futex_requeue +457 common statmount sys_statmount +458 common listmount sys_listmount +459 common lsm_get_self_attr sys_lsm_get_self_attr +460 common lsm_set_self_attr sys_lsm_set_self_attr +461 common lsm_list_modules sys_lsm_list_modules diff --git a/arch/microblaze/configs/mmu_defconfig b/arch/microblaze/configs/mmu_defconfig index 7b2d7f6f23c0dc..4da7bc4ac4a37a 100644 --- a/arch/microblaze/configs/mmu_defconfig +++ b/arch/microblaze/configs/mmu_defconfig @@ -3,11 +3,9 @@ CONFIG_POSIX_MQUEUE=y CONFIG_AUDIT=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y -CONFIG_SYSFS_DEPRECATED=y -CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_EXPERT=y # CONFIG_BASE_FULL is not set CONFIG_KALLSYMS_ALL=y -CONFIG_EXPERT=y CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR=1 CONFIG_XILINX_MICROBLAZE0_USE_PCMP_INSTR=1 CONFIG_XILINX_MICROBLAZE0_USE_BARREL=1 @@ -20,7 +18,6 @@ CONFIG_CMDLINE_FORCE=y CONFIG_HIGHMEM=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y -# CONFIG_BLK_DEV_BSG is not set CONFIG_PARTITION_ADVANCED=y # CONFIG_EFI_PARTITION is not set CONFIG_CMA=y @@ -28,6 +25,10 @@ CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y CONFIG_INET=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y # CONFIG_IPV6 is not set CONFIG_BRIDGE=m CONFIG_PCI=y @@ -43,6 +44,7 @@ CONFIG_NETDEVICES=y CONFIG_XILINX_EMACLITE=y CONFIG_XILINX_AXI_EMAC=y CONFIG_XILINX_LL_TEMAC=y +CONFIG_MARVELL_PHY=y # CONFIG_INPUT is not set # CONFIG_SERIO is not set # CONFIG_VT is not set @@ -77,14 +79,13 @@ CONFIG_TMPFS=y CONFIG_CRAMFS=y CONFIG_ROMFS_FS=y CONFIG_NFS_FS=y +CONFIG_ROOT_NFS=y CONFIG_CIFS=y -CONFIG_CIFS_STATS2=y CONFIG_ENCRYPTED_KEYS=y CONFIG_DMA_CMA=y CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y CONFIG_KGDB=y CONFIG_KGDB_TESTS=y CONFIG_KGDB_KDB=y -CONFIG_DEBUG_SLAB=y CONFIG_DETECT_HUNG_TASK=y CONFIG_DEBUG_SPINLOCK=y diff --git a/arch/microblaze/include/asm/ftrace.h b/arch/microblaze/include/asm/ftrace.h index 6a92bed37794ce..4ca38b92a3a209 100644 --- a/arch/microblaze/include/asm/ftrace.h +++ b/arch/microblaze/include/asm/ftrace.h @@ -10,6 +10,7 @@ #ifndef __ASSEMBLY__ extern void _mcount(void); extern void ftrace_call_graph(void); +void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr); #endif #ifdef CONFIG_DYNAMIC_FTRACE diff --git a/arch/microblaze/include/asm/pgtable.h b/arch/microblaze/include/asm/pgtable.h index 3042eb98bb56a1..e4ea2ec3642f06 100644 --- a/arch/microblaze/include/asm/pgtable.h +++ b/arch/microblaze/include/asm/pgtable.h @@ -336,6 +336,7 @@ static inline void set_pte(pte_t *ptep, pte_t pte) } #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG +struct vm_area_struct; static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long address, pte_t *ptep) { diff --git a/arch/microblaze/kernel/syscalls/syscall.tbl b/arch/microblaze/kernel/syscalls/syscall.tbl index 5b6a0b02b7de0a..b00ab2cabab92a 100644 --- a/arch/microblaze/kernel/syscalls/syscall.tbl +++ b/arch/microblaze/kernel/syscalls/syscall.tbl @@ -462,3 +462,8 @@ 454 common futex_wake sys_futex_wake 455 common futex_wait sys_futex_wait 456 common futex_requeue sys_futex_requeue +457 common statmount sys_statmount +458 common listmount sys_listmount +459 common lsm_get_self_attr sys_lsm_get_self_attr +460 common lsm_set_self_attr sys_lsm_set_self_attr +461 common lsm_list_modules sys_lsm_list_modules diff --git a/arch/microblaze/kernel/traps.c b/arch/microblaze/kernel/traps.c index 94b6fe93147d5a..080aa769218db4 100644 --- a/arch/microblaze/kernel/traps.c +++ b/arch/microblaze/kernel/traps.c @@ -8,6 +8,7 @@ * for more details. */ +#include #include #include #include diff --git a/arch/mips/Kbuild b/arch/mips/Kbuild index af2967bffb73df..e2d623621a00ee 100644 --- a/arch/mips/Kbuild +++ b/arch/mips/Kbuild @@ -1,10 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -# Fail on warnings - also for files referenced in subdirs -# -Werror can be disabled for specific files using: -# CFLAGS_ := -Wno-error -ifeq ($(W),) -subdir-ccflags-y := -Werror -endif # platform specific definitions include $(srctree)/arch/mips/Kbuild.platforms diff --git a/arch/mips/alchemy/common/prom.c b/arch/mips/alchemy/common/prom.c index b13d8adf3be47d..20d30f6265cdce 100644 --- a/arch/mips/alchemy/common/prom.c +++ b/arch/mips/alchemy/common/prom.c @@ -40,6 +40,7 @@ #include #include +#include int prom_argc; char **prom_argv; diff --git a/arch/mips/alchemy/common/setup.c b/arch/mips/alchemy/common/setup.c index 2388d68786f4a7..a7a6d31a7a4148 100644 --- a/arch/mips/alchemy/common/setup.c +++ b/arch/mips/alchemy/common/setup.c @@ -30,13 +30,11 @@ #include #include /* for dma_default_coherent */ +#include #include #include -extern void __init board_setup(void); -extern void __init alchemy_set_lpj(void); - static bool alchemy_dma_coherent(void) { switch (alchemy_get_cputype()) { diff --git a/arch/mips/alchemy/devboards/db1200.c b/arch/mips/alchemy/devboards/db1200.c index f521874ebb07b2..67f067706af273 100644 --- a/arch/mips/alchemy/devboards/db1200.c +++ b/arch/mips/alchemy/devboards/db1200.c @@ -847,7 +847,7 @@ int __init db1200_dev_setup(void) i2c_register_board_info(0, db1200_i2c_devs, ARRAY_SIZE(db1200_i2c_devs)); spi_register_board_info(db1200_spi_devs, - ARRAY_SIZE(db1200_i2c_devs)); + ARRAY_SIZE(db1200_spi_devs)); /* SWITCHES: S6.8 I2C/SPI selector (OFF=I2C ON=SPI) * S6.7 AC97/I2S selector (OFF=AC97 ON=I2S) diff --git a/arch/mips/alchemy/devboards/db1550.c b/arch/mips/alchemy/devboards/db1550.c index fd91d9c9a2525d..6c6837181f5555 100644 --- a/arch/mips/alchemy/devboards/db1550.c +++ b/arch/mips/alchemy/devboards/db1550.c @@ -589,7 +589,7 @@ int __init db1550_dev_setup(void) i2c_register_board_info(0, db1550_i2c_devs, ARRAY_SIZE(db1550_i2c_devs)); spi_register_board_info(db1550_spi_devs, - ARRAY_SIZE(db1550_i2c_devs)); + ARRAY_SIZE(db1550_spi_devs)); c = clk_get(NULL, "psc0_intclk"); if (!IS_ERR(c)) { diff --git a/arch/mips/bcm47xx/buttons.c b/arch/mips/bcm47xx/buttons.c index 437a737c01dd05..46994f9bb8219c 100644 --- a/arch/mips/bcm47xx/buttons.c +++ b/arch/mips/bcm47xx/buttons.c @@ -147,21 +147,21 @@ static const struct gpio_keys_button bcm47xx_buttons_buffalo_whr_g125[] __initconst = { BCM47XX_GPIO_KEY(0, KEY_WPS_BUTTON), BCM47XX_GPIO_KEY(4, KEY_RESTART), - BCM47XX_GPIO_KEY(5, BTN_0), /* Router / AP mode swtich */ + BCM47XX_GPIO_KEY(5, BTN_0), /* Router / AP mode switch */ }; static const struct gpio_keys_button bcm47xx_buttons_buffalo_whr_g54s[] __initconst = { BCM47XX_GPIO_KEY(0, KEY_WPS_BUTTON), BCM47XX_GPIO_KEY_H(4, KEY_RESTART), - BCM47XX_GPIO_KEY(5, BTN_0), /* Router / AP mode swtich */ + BCM47XX_GPIO_KEY(5, BTN_0), /* Router / AP mode switch */ }; static const struct gpio_keys_button bcm47xx_buttons_buffalo_whr_hp_g54[] __initconst = { BCM47XX_GPIO_KEY(0, KEY_WPS_BUTTON), BCM47XX_GPIO_KEY(4, KEY_RESTART), - BCM47XX_GPIO_KEY(5, BTN_0), /* Router / AP mode swtich */ + BCM47XX_GPIO_KEY(5, BTN_0), /* Router / AP mode switch */ }; static const struct gpio_keys_button diff --git a/arch/mips/bcm63xx/boards/board_bcm963xx.c b/arch/mips/bcm63xx/boards/board_bcm963xx.c index 01aff80a59672d..99f321b6e417bd 100644 --- a/arch/mips/bcm63xx/boards/board_bcm963xx.c +++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c @@ -702,7 +702,7 @@ static struct ssb_sprom bcm63xx_sprom = { .boardflags_hi = 0x0000, }; -int bcm63xx_get_fallback_sprom(struct ssb_bus *bus, struct ssb_sprom *out) +static int bcm63xx_get_fallback_sprom(struct ssb_bus *bus, struct ssb_sprom *out) { if (bus->bustype == SSB_BUSTYPE_PCI) { memcpy(out, &bcm63xx_sprom, sizeof(struct ssb_sprom)); diff --git a/arch/mips/bcm63xx/clk.c b/arch/mips/bcm63xx/clk.c index 86a6e25908664b..3144965fb7dc4f 100644 --- a/arch/mips/bcm63xx/clk.c +++ b/arch/mips/bcm63xx/clk.c @@ -174,7 +174,7 @@ static void enetsw_set(struct clk *clk, int enable) } if (enable) { - /* reset switch core afer clock change */ + /* reset switch core after clock change */ bcm63xx_core_set_reset(BCM63XX_RESET_ENETSW, 1); msleep(10); bcm63xx_core_set_reset(BCM63XX_RESET_ENETSW, 0); @@ -304,7 +304,7 @@ static void xtm_set(struct clk *clk, int enable) bcm_hwclock_set(CKCTL_6368_SAR_EN, enable); if (enable) { - /* reset sar core afer clock change */ + /* reset sar core after clock change */ bcm63xx_core_set_reset(BCM63XX_RESET_SAR, 1); mdelay(1); bcm63xx_core_set_reset(BCM63XX_RESET_SAR, 0); diff --git a/arch/mips/bcm63xx/dev-rng.c b/arch/mips/bcm63xx/dev-rng.c index d277b4dc6c688e..f94151f7c96fe1 100644 --- a/arch/mips/bcm63xx/dev-rng.c +++ b/arch/mips/bcm63xx/dev-rng.c @@ -26,7 +26,7 @@ static struct platform_device bcm63xx_rng_device = { .resource = rng_resources, }; -int __init bcm63xx_rng_register(void) +static int __init bcm63xx_rng_register(void) { if (!BCMCPU_IS_6368()) return -ENODEV; diff --git a/arch/mips/bcm63xx/dev-uart.c b/arch/mips/bcm63xx/dev-uart.c index 3bc7f3bfc9ad5c..5d6bf0445b299c 100644 --- a/arch/mips/bcm63xx/dev-uart.c +++ b/arch/mips/bcm63xx/dev-uart.c @@ -10,6 +10,7 @@ #include #include #include +#include static struct resource uart0_resources[] = { { diff --git a/arch/mips/bcm63xx/dev-wdt.c b/arch/mips/bcm63xx/dev-wdt.c index 42130914a3c210..302bf7ed5ad5ab 100644 --- a/arch/mips/bcm63xx/dev-wdt.c +++ b/arch/mips/bcm63xx/dev-wdt.c @@ -34,7 +34,7 @@ static struct platform_device bcm63xx_wdt_device = { }, }; -int __init bcm63xx_wdt_register(void) +static int __init bcm63xx_wdt_register(void) { wdt_resources[0].start = bcm63xx_regset_address(RSET_WDT); wdt_resources[0].end = wdt_resources[0].start; diff --git a/arch/mips/bcm63xx/irq.c b/arch/mips/bcm63xx/irq.c index 2548013442f6d9..6240a8f88ea366 100644 --- a/arch/mips/bcm63xx/irq.c +++ b/arch/mips/bcm63xx/irq.c @@ -72,7 +72,7 @@ static inline int enable_irq_for_cpu(int cpu, struct irq_data *d, */ #define BUILD_IPIC_INTERNAL(width) \ -void __dispatch_internal_##width(int cpu) \ +static void __dispatch_internal_##width(int cpu) \ { \ u32 pending[width / 32]; \ unsigned int src, tgt; \ diff --git a/arch/mips/bcm63xx/setup.c b/arch/mips/bcm63xx/setup.c index d811e3e03f819a..c13ddb544a23bf 100644 --- a/arch/mips/bcm63xx/setup.c +++ b/arch/mips/bcm63xx/setup.c @@ -159,7 +159,7 @@ void __init plat_mem_setup(void) board_setup(); } -int __init bcm63xx_register_devices(void) +static int __init bcm63xx_register_devices(void) { /* register gpiochip */ bcm63xx_gpio_init(); diff --git a/arch/mips/bcm63xx/timer.c b/arch/mips/bcm63xx/timer.c index a86065854c0c8c..74b83807df30a7 100644 --- a/arch/mips/bcm63xx/timer.c +++ b/arch/mips/bcm63xx/timer.c @@ -178,7 +178,7 @@ int bcm63xx_timer_set(int id, int monotonic, unsigned int countdown_us) EXPORT_SYMBOL(bcm63xx_timer_set); -int bcm63xx_timer_init(void) +static int bcm63xx_timer_init(void) { int ret, irq; u32 reg; diff --git a/arch/mips/boot/compressed/dbg.c b/arch/mips/boot/compressed/dbg.c index f6728a8fd1c3d2..95405292accdff 100644 --- a/arch/mips/boot/compressed/dbg.c +++ b/arch/mips/boot/compressed/dbg.c @@ -3,12 +3,14 @@ * MIPS-specific debug support for pre-boot environment * * NOTE: putc() is board specific, if your board have a 16550 compatible uart, - * please select SYS_SUPPORTS_ZBOOT_UART16550 for your machine. othewise, you + * please select SYS_SUPPORTS_ZBOOT_UART16550 for your machine. otherwise, you * need to implement your own putc(). */ #include #include +#include "decompress.h" + void __weak putc(char c) { } diff --git a/arch/mips/boot/compressed/decompress.c b/arch/mips/boot/compressed/decompress.c index c5dd415254d3d6..adb6d5b0e6ebc0 100644 --- a/arch/mips/boot/compressed/decompress.c +++ b/arch/mips/boot/compressed/decompress.c @@ -19,6 +19,8 @@ #include #include +#include "decompress.h" + /* * These two variables specify the free mem region * that can be used for temporary malloc area @@ -26,20 +28,6 @@ unsigned long free_mem_ptr; unsigned long free_mem_end_ptr; -/* The linker tells us where the image is. */ -extern unsigned char __image_begin[], __image_end[]; - -/* debug interfaces */ -#ifdef CONFIG_DEBUG_ZBOOT -extern void puts(const char *s); -extern void puthex(unsigned long long val); -#else -#define puts(s) do {} while (0) -#define puthex(val) do {} while (0) -#endif - -extern char __appended_dtb[]; - void error(char *x) { puts("\n\n"); diff --git a/arch/mips/boot/compressed/decompress.h b/arch/mips/boot/compressed/decompress.h new file mode 100644 index 00000000000000..073b64593b3d4c --- /dev/null +++ b/arch/mips/boot/compressed/decompress.h @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0 +#ifndef _DECOMPRESSOR_H +#define _DECOMPRESSOR_H + +/* The linker tells us where the image is. */ +extern unsigned char __image_begin[], __image_end[]; + +/* debug interfaces */ +#ifdef CONFIG_DEBUG_ZBOOT +extern void putc(char c); +extern void puts(const char *s); +extern void puthex(unsigned long long val); +#else +#define putc(s) do {} while (0) +#define puts(s) do {} while (0) +#define puthex(val) do {} while (0) +#endif + +extern char __appended_dtb[]; + +void error(char *x); +void decompress_kernel(unsigned long boot_heap_start); + +#endif diff --git a/arch/mips/boot/compressed/head.S b/arch/mips/boot/compressed/head.S index 5795d0af1e1b2e..d237a834b85ee5 100644 --- a/arch/mips/boot/compressed/head.S +++ b/arch/mips/boot/compressed/head.S @@ -25,8 +25,8 @@ /* Clear BSS */ PTR_LA a0, _edata PTR_LA a2, _end -1: sw zero, 0(a0) - addiu a0, a0, 4 +1: PTR_S zero, 0(a0) + PTR_ADDIU a0, a0, PTRSIZE bne a2, a0, 1b PTR_LA a0, (.heap) /* heap address */ diff --git a/arch/mips/boot/compressed/string.c b/arch/mips/boot/compressed/string.c index 0b593b70922865..f0eb251e44e5a8 100644 --- a/arch/mips/boot/compressed/string.c +++ b/arch/mips/boot/compressed/string.c @@ -7,6 +7,7 @@ #include #include +#include void *memcpy(void *dest, const void *src, size_t n) { diff --git a/arch/mips/boot/elf2ecoff.c b/arch/mips/boot/elf2ecoff.c index 6972b97235daf4..549c5d6ef6d7c7 100644 --- a/arch/mips/boot/elf2ecoff.c +++ b/arch/mips/boot/elf2ecoff.c @@ -443,7 +443,7 @@ int main(int argc, char *argv[]) efh.f_symptr = 0; efh.f_nsyms = 0; efh.f_opthdr = sizeof eah; - efh.f_flags = 0x100f; /* Stripped, not sharable. */ + efh.f_flags = 0x100f; /* Stripped, not shareable. */ memset(esecs, 0, sizeof esecs); strcpy(esecs[0].s_name, ".text"); diff --git a/arch/mips/cavium-octeon/csrc-octeon.c b/arch/mips/cavium-octeon/csrc-octeon.c index 124817609ce013..af62a210a40b91 100644 --- a/arch/mips/cavium-octeon/csrc-octeon.c +++ b/arch/mips/cavium-octeon/csrc-octeon.c @@ -113,7 +113,7 @@ static struct clocksource clocksource_mips = { unsigned long long notrace sched_clock(void) { - /* 64-bit arithmatic can overflow, so use 128-bit. */ + /* 64-bit arithmetic can overflow, so use 128-bit. */ u64 t1, t2, t3; unsigned long long rv; u64 mult = clocksource_mips.mult; diff --git a/arch/mips/cavium-octeon/executive/cvmx-boot-vector.c b/arch/mips/cavium-octeon/executive/cvmx-boot-vector.c index b7019d21808e04..76446db66defdc 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-boot-vector.c +++ b/arch/mips/cavium-octeon/executive/cvmx-boot-vector.c @@ -143,7 +143,7 @@ static void cvmx_boot_vector_init(void *mem) uint64_t v = _cvmx_bootvector_data[i]; if (OCTEON_IS_OCTEON1PLUS() && (i == 0 || i == 7)) - v &= 0xffffffff00000000ull; /* KScratch not availble. */ + v &= 0xffffffff00000000ull; /* KScratch not available */ cvmx_write_csr(CVMX_MIO_BOOT_LOC_ADR, i * 8); cvmx_write_csr(CVMX_MIO_BOOT_LOC_DAT, v); } diff --git a/arch/mips/cavium-octeon/executive/cvmx-bootmem.c b/arch/mips/cavium-octeon/executive/cvmx-bootmem.c index 334bf8e577e501..628ebdf4b9c55d 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-bootmem.c +++ b/arch/mips/cavium-octeon/executive/cvmx-bootmem.c @@ -264,7 +264,7 @@ int64_t cvmx_bootmem_phy_alloc(uint64_t req_size, uint64_t address_min, * Convert !0 address_min and 0 address_max to special case of * range that specifies an exact memory block to allocate. Do * this before other checks and adjustments so that this - * tranformation will be validated. + * transformation will be validated. */ if (address_min && !address_max) address_max = address_min + req_size; diff --git a/arch/mips/cavium-octeon/executive/cvmx-cmd-queue.c b/arch/mips/cavium-octeon/executive/cvmx-cmd-queue.c index aa7bbf8d0df558..042a6bc44b5c25 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-cmd-queue.c +++ b/arch/mips/cavium-octeon/executive/cvmx-cmd-queue.c @@ -192,7 +192,7 @@ cvmx_cmd_queue_result_t cvmx_cmd_queue_initialize(cvmx_cmd_queue_id_t queue_id, } /* - * Shutdown a queue a free it's command buffers to the FPA. The + * Shutdown a queue and free its command buffers to the FPA. The * hardware connected to the queue must be stopped before this * function is called. * @@ -285,7 +285,7 @@ int cvmx_cmd_queue_length(cvmx_cmd_queue_id_t queue_id) /* * Return the command buffer to be written to. The purpose of this - * function is to allow CVMX routine access t othe low level buffer + * function is to allow CVMX routine access to the low level buffer * for initial hardware setup. User applications should not call this * function directly. * diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-jtag.c b/arch/mips/cavium-octeon/executive/cvmx-helper-jtag.c index 607b4e65957977..1fceb7fd2c944c 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper-jtag.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-jtag.c @@ -103,7 +103,7 @@ uint32_t cvmx_helper_qlm_jtag_shift(int qlm, int bits, uint32_t data) /** * Shift long sequences of zeros into the QLM JTAG chain. It is * common to need to shift more than 32 bits of zeros into the - * chain. This function is a convience wrapper around + * chain. This function is a convenience wrapper around * cvmx_helper_qlm_jtag_shift() to shift more than 32 bits of * zeros at a time. * diff --git a/arch/mips/cavium-octeon/executive/cvmx-pko.c b/arch/mips/cavium-octeon/executive/cvmx-pko.c index 15faca494c8072..6e70b859a0ac6c 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-pko.c +++ b/arch/mips/cavium-octeon/executive/cvmx-pko.c @@ -615,7 +615,7 @@ int cvmx_pko_rate_limit_bits(int port, uint64_t bits_s, int burst) /* * Each packet has a 12 bytes of interframe gap, an 8 byte * preamble, and a 4 byte CRC. These are not included in the - * per word count. Multiply by 8 to covert to bits and divide + * per word count. Multiply by 8 to convert to bits and divide * by 256 for limit granularity. */ pko_mem_port_rate0.s.rate_pkt = (12 + 8 + 4) * 8 * tokens_per_bit / 256; diff --git a/arch/mips/cavium-octeon/octeon-platform.c b/arch/mips/cavium-octeon/octeon-platform.c index f76783c24338b9..5e1dd4e6e82fb8 100644 --- a/arch/mips/cavium-octeon/octeon-platform.c +++ b/arch/mips/cavium-octeon/octeon-platform.c @@ -973,7 +973,7 @@ int __init octeon_prune_device_tree(void) * zero. */ - /* Asume that CS1 immediately follows. */ + /* Assume that CS1 immediately follows. */ mio_boot_reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs + 1)); region1_base = mio_boot_reg_cfg.s.base << 16; diff --git a/arch/mips/cobalt/setup.c b/arch/mips/cobalt/setup.c index 2e099d55a564a6..9a266bf7833993 100644 --- a/arch/mips/cobalt/setup.c +++ b/arch/mips/cobalt/setup.c @@ -23,9 +23,6 @@ #include -extern void cobalt_machine_restart(char *command); -extern void cobalt_machine_halt(void); - const char *get_system_type(void) { switch (cobalt_board_id) { diff --git a/arch/mips/configs/ip22_defconfig b/arch/mips/configs/ip22_defconfig index dc49b09d492b72..e22e8b825903fa 100644 --- a/arch/mips/configs/ip22_defconfig +++ b/arch/mips/configs/ip22_defconfig @@ -173,7 +173,6 @@ CONFIG_NET_ACT_POLICE=y CONFIG_NET_ACT_GACT=m CONFIG_GACT_PROB=y CONFIG_NET_ACT_MIRRED=m -CONFIG_NET_ACT_IPT=m CONFIG_NET_ACT_NAT=m CONFIG_NET_ACT_PEDIT=m CONFIG_NET_ACT_SIMP=m diff --git a/arch/mips/configs/ip27_defconfig b/arch/mips/configs/ip27_defconfig index b51f738a39a05a..4714074c8bd7f5 100644 --- a/arch/mips/configs/ip27_defconfig +++ b/arch/mips/configs/ip27_defconfig @@ -287,7 +287,8 @@ CONFIG_BTRFS_FS_POSIX_ACL=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_FUSE_FS=m CONFIG_CUSE=m -CONFIG_FSCACHE=m +CONFIG_NETFS_SUPPORT=m +CONFIG_FSCACHE=y CONFIG_FSCACHE_STATS=y CONFIG_CACHEFILES=m CONFIG_PROC_KCORE=y diff --git a/arch/mips/configs/lemote2f_defconfig b/arch/mips/configs/lemote2f_defconfig index 38f17b65842187..3389e6e885d9fa 100644 --- a/arch/mips/configs/lemote2f_defconfig +++ b/arch/mips/configs/lemote2f_defconfig @@ -238,7 +238,8 @@ CONFIG_BTRFS_FS=m CONFIG_QUOTA=y CONFIG_QFMT_V2=m CONFIG_AUTOFS_FS=m -CONFIG_FSCACHE=m +CONFIG_NETFS_SUPPORT=m +CONFIG_FSCACHE=y CONFIG_CACHEFILES=m CONFIG_ISO9660_FS=m CONFIG_JOLIET=y diff --git a/arch/mips/configs/loongson3_defconfig b/arch/mips/configs/loongson3_defconfig index 07839a4b397e5b..78f4987520664b 100644 --- a/arch/mips/configs/loongson3_defconfig +++ b/arch/mips/configs/loongson3_defconfig @@ -356,7 +356,8 @@ CONFIG_QFMT_V2=m CONFIG_AUTOFS_FS=y CONFIG_FUSE_FS=m CONFIG_VIRTIO_FS=m -CONFIG_FSCACHE=m +CONFIG_NETFS_SUPPORT=m +CONFIG_FSCACHE=y CONFIG_ISO9660_FS=m CONFIG_JOLIET=y CONFIG_MSDOS_FS=m diff --git a/arch/mips/configs/malta_defconfig b/arch/mips/configs/malta_defconfig index 6f80460245573e..4390d30206d903 100644 --- a/arch/mips/configs/malta_defconfig +++ b/arch/mips/configs/malta_defconfig @@ -202,7 +202,6 @@ CONFIG_NET_ACT_POLICE=y CONFIG_NET_ACT_GACT=m CONFIG_GACT_PROB=y CONFIG_NET_ACT_MIRRED=m -CONFIG_NET_ACT_IPT=m CONFIG_NET_ACT_NAT=m CONFIG_NET_ACT_PEDIT=m CONFIG_NET_ACT_SIMP=m diff --git a/arch/mips/configs/malta_kvm_defconfig b/arch/mips/configs/malta_kvm_defconfig index 16a91eeff67fe9..d63d8be8cb5049 100644 --- a/arch/mips/configs/malta_kvm_defconfig +++ b/arch/mips/configs/malta_kvm_defconfig @@ -206,7 +206,6 @@ CONFIG_NET_ACT_POLICE=y CONFIG_NET_ACT_GACT=m CONFIG_GACT_PROB=y CONFIG_NET_ACT_MIRRED=m -CONFIG_NET_ACT_IPT=m CONFIG_NET_ACT_NAT=m CONFIG_NET_ACT_PEDIT=m CONFIG_NET_ACT_SIMP=m diff --git a/arch/mips/configs/maltaup_xpa_defconfig b/arch/mips/configs/maltaup_xpa_defconfig index 264aba29ea4fea..338bb6544a9349 100644 --- a/arch/mips/configs/maltaup_xpa_defconfig +++ b/arch/mips/configs/maltaup_xpa_defconfig @@ -203,7 +203,6 @@ CONFIG_NET_ACT_POLICE=y CONFIG_NET_ACT_GACT=m CONFIG_GACT_PROB=y CONFIG_NET_ACT_MIRRED=m -CONFIG_NET_ACT_IPT=m CONFIG_NET_ACT_NAT=m CONFIG_NET_ACT_PEDIT=m CONFIG_NET_ACT_SIMP=m diff --git a/arch/mips/configs/pic32mzda_defconfig b/arch/mips/configs/pic32mzda_defconfig index 166d2ad372d142..54774f90c23eaf 100644 --- a/arch/mips/configs/pic32mzda_defconfig +++ b/arch/mips/configs/pic32mzda_defconfig @@ -68,7 +68,8 @@ CONFIG_EXT4_FS_POSIX_ACL=y CONFIG_EXT4_FS_SECURITY=y CONFIG_AUTOFS_FS=m CONFIG_FUSE_FS=m -CONFIG_FSCACHE=m +CONFIG_NETFS_SUPPORT=m +CONFIG_FSCACHE=y CONFIG_ISO9660_FS=m CONFIG_JOLIET=y CONFIG_ZISOFS=y diff --git a/arch/mips/configs/rb532_defconfig b/arch/mips/configs/rb532_defconfig index 02ec6c1a51163e..517f1b060bf49a 100644 --- a/arch/mips/configs/rb532_defconfig +++ b/arch/mips/configs/rb532_defconfig @@ -96,7 +96,6 @@ CONFIG_NET_ACT_POLICE=y CONFIG_NET_ACT_GACT=m CONFIG_GACT_PROB=y CONFIG_NET_ACT_MIRRED=m -CONFIG_NET_ACT_IPT=m CONFIG_NET_ACT_PEDIT=m CONFIG_HAMRADIO=y CONFIG_MTD=y diff --git a/arch/mips/fw/arc/memory.c b/arch/mips/fw/arc/memory.c index 66188739f54d20..fb78e6fd5de480 100644 --- a/arch/mips/fw/arc/memory.c +++ b/arch/mips/fw/arc/memory.c @@ -37,7 +37,7 @@ static unsigned int nr_prom_mem __initdata; */ #define ARC_PAGE_SHIFT 12 -struct linux_mdesc * __init ArcGetMemoryDescriptor(struct linux_mdesc *Current) +static struct linux_mdesc * __init ArcGetMemoryDescriptor(struct linux_mdesc *Current) { return (struct linux_mdesc *) ARC_CALL1(get_mdesc, Current); } diff --git a/arch/mips/fw/arc/promlib.c b/arch/mips/fw/arc/promlib.c index 5e9e840a93144c..93e1e70393eeb9 100644 --- a/arch/mips/fw/arc/promlib.c +++ b/arch/mips/fw/arc/promlib.c @@ -15,11 +15,11 @@ /* * For 64bit kernels working with a 32bit ARC PROM pointer arguments * for ARC calls need to reside in CKEG0/1. But as soon as the kernel - * switches to it's first kernel thread stack is set to an address in + * switches to its first kernel thread stack is set to an address in * XKPHYS, so anything on stack can't be used anymore. This is solved - * by using a * static declartion variables are put into BSS, which is + * by using a * static declaration variables are put into BSS, which is * linked to a CKSEG0 address. Since this is only used on UP platforms - * there is not spinlock needed + * there is no spinlock needed */ #define O32_STATIC static #else diff --git a/arch/mips/include/asm/cache.h b/arch/mips/include/asm/cache.h index 3424a7908c0fa3..8b08db3fb17aae 100644 --- a/arch/mips/include/asm/cache.h +++ b/arch/mips/include/asm/cache.h @@ -17,5 +17,11 @@ #define __read_mostly __section(".data..read_mostly") extern void cache_noop(void); +extern void r3k_cache_init(void); +extern unsigned long r3k_cache_size(unsigned long); +extern unsigned long r3k_cache_lsize(unsigned long); +extern void r4k_cache_init(void); +extern void octeon_cache_init(void); +extern void au1x00_fixup_config_od(void); #endif /* _ASM_CACHE_H */ diff --git a/arch/mips/include/asm/cacheflush.h b/arch/mips/include/asm/cacheflush.h index f36c2519ed9768..1f14132b3fc98a 100644 --- a/arch/mips/include/asm/cacheflush.h +++ b/arch/mips/include/asm/cacheflush.h @@ -97,6 +97,8 @@ static inline void flush_cache_vmap(unsigned long start, unsigned long end) __flush_cache_vmap(); } +#define flush_cache_vmap_early(start, end) do { } while (0) + extern void (*__flush_cache_vunmap)(void); static inline void flush_cache_vunmap(unsigned long start, unsigned long end) diff --git a/arch/mips/include/asm/debug.h b/arch/mips/include/asm/debug.h index c7013e1cb53fb7..e70392429246e1 100644 --- a/arch/mips/include/asm/debug.h +++ b/arch/mips/include/asm/debug.h @@ -10,7 +10,7 @@ /* * mips_debugfs_dir corresponds to the "mips" directory at the top level - * of the DebugFS hierarchy. MIPS-specific DebugFS entires should be + * of the DebugFS hierarchy. MIPS-specific DebugFS entries should be * placed beneath this directory. */ extern struct dentry *mips_debugfs_dir; diff --git a/arch/mips/include/asm/dmi.h b/arch/mips/include/asm/dmi.h index 27415a288adf56..dc397f630c6608 100644 --- a/arch/mips/include/asm/dmi.h +++ b/arch/mips/include/asm/dmi.h @@ -5,7 +5,7 @@ #include #include -#define dmi_early_remap(x, l) ioremap_cache(x, l) +#define dmi_early_remap(x, l) ioremap(x, l) #define dmi_early_unmap(x, l) iounmap(x) #define dmi_remap(x, l) ioremap_cache(x, l) #define dmi_unmap(x) iounmap(x) diff --git a/arch/mips/include/asm/ftrace.h b/arch/mips/include/asm/ftrace.h index db497a8167da29..dc025888f6d289 100644 --- a/arch/mips/include/asm/ftrace.h +++ b/arch/mips/include/asm/ftrace.h @@ -85,6 +85,10 @@ struct dyn_arch_ftrace { }; #endif /* CONFIG_DYNAMIC_FTRACE */ + +void prepare_ftrace_return(unsigned long *parent_ra_addr, unsigned long self_ra, + unsigned long fp); + #endif /* __ASSEMBLY__ */ #endif /* CONFIG_FUNCTION_TRACER */ #endif /* _ASM_MIPS_FTRACE_H */ diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h index 062dd4e6b954e4..af58d6ae06b85e 100644 --- a/arch/mips/include/asm/io.h +++ b/arch/mips/include/asm/io.h @@ -13,7 +13,6 @@ #define _ASM_IO_H #include -#include #include #include @@ -25,7 +24,6 @@ #include #include #include -#include #include #include @@ -41,6 +39,11 @@ # define __raw_ioswabq(a, x) (x) # define ____raw_ioswabq(a, x) (x) +# define _ioswabb ioswabb +# define _ioswabw ioswabw +# define _ioswabl ioswabl +# define _ioswabq ioswabq + # define __relaxed_ioswabb ioswabb # define __relaxed_ioswabw ioswabw # define __relaxed_ioswabl ioswabl @@ -114,23 +117,6 @@ static inline phys_addr_t virt_to_phys(const volatile void *x) return __virt_to_phys(x); } -/* - * phys_to_virt - map physical address to virtual - * @address: address to remap - * - * The returned virtual address is a current CPU mapping for - * the memory address given. It is only valid to use this function on - * addresses that have a kernel mapping - * - * This function does not handle bus mappings for DMA transfers. In - * almost all conceivable cases a device driver should not be using - * this function - */ -static inline void * phys_to_virt(unsigned long address) -{ - return __va(address); -} - /* * ISA I/O bus memory addresses are 1:1 with the physical address. */ @@ -139,11 +125,6 @@ static inline unsigned long isa_virt_to_bus(volatile void *address) return virt_to_phys(address); } -static inline void *isa_bus_to_virt(unsigned long address) -{ - return phys_to_virt(address); -} - /* * Change "struct page" to physical address. */ @@ -166,7 +147,6 @@ void iounmap(const volatile void __iomem *addr); */ #define ioremap(offset, size) \ ioremap_prot((offset), (size), _CACHE_UNCACHED) -#define ioremap_uc ioremap /* * ioremap_cache - map bus memory into CPU space @@ -179,7 +159,7 @@ void iounmap(const volatile void __iomem *addr); * address is not guaranteed to be usable directly as a virtual * address. * - * This version of ioremap ensures that the memory is marked cachable by + * This version of ioremap ensures that the memory is marked cacheable by * the CPU. Also enables full write-combining. Useful for some * memory-like regions on I/O busses. */ @@ -197,7 +177,7 @@ void iounmap(const volatile void __iomem *addr); * address is not guaranteed to be usable directly as a virtual * address. * - * This version of ioremap ensures that the memory is marked uncachable + * This version of ioremap ensures that the memory is marked uncacheable * but accelerated by means of write-combining feature. It is specifically * useful for PCIe prefetchable windows, which may vastly improve a * communications performance. If it was determined on boot stage, what @@ -207,8 +187,6 @@ void iounmap(const volatile void __iomem *addr); #define ioremap_wc(offset, size) \ ioremap_prot((offset), (size), boot_cpu_data.writecombine) -#include - #if defined(CONFIG_CPU_CAVIUM_OCTEON) #define war_io_reorder_wmb() wmb() #else @@ -296,9 +274,9 @@ static inline type pfx##read##bwlq(const volatile void __iomem *mem) \ return pfx##ioswab##bwlq(__mem, __val); \ } -#define __BUILD_IOPORT_SINGLE(pfx, bwlq, type, barrier, relax, p) \ +#define __BUILD_IOPORT_SINGLE(pfx, bwlq, type, barrier, relax) \ \ -static inline void pfx##out##bwlq##p(type val, unsigned long port) \ +static inline void pfx##out##bwlq(type val, unsigned long port) \ { \ volatile type *__addr; \ type __val; \ @@ -318,7 +296,7 @@ static inline void pfx##out##bwlq##p(type val, unsigned long port) \ *__addr = __val; \ } \ \ -static inline type pfx##in##bwlq##p(unsigned long port) \ +static inline type pfx##in##bwlq(unsigned long port) \ { \ volatile type *__addr; \ type __val; \ @@ -360,11 +338,10 @@ __BUILD_MEMORY_PFX(__mem_, q, u64, 0) #endif #define __BUILD_IOPORT_PFX(bus, bwlq, type) \ - __BUILD_IOPORT_SINGLE(bus, bwlq, type, 1, 0,) \ - __BUILD_IOPORT_SINGLE(bus, bwlq, type, 1, 0, _p) + __BUILD_IOPORT_SINGLE(bus, bwlq, type, 1, 0) #define BUILDIO_IOPORT(bwlq, type) \ - __BUILD_IOPORT_PFX(, bwlq, type) \ + __BUILD_IOPORT_PFX(_, bwlq, type) \ __BUILD_IOPORT_PFX(__mem_, bwlq, type) BUILDIO_IOPORT(b, u8) @@ -412,14 +389,6 @@ __BUILDIO(q, u64) #define writeq_be(val, addr) \ __raw_writeq(cpu_to_be64((val)), (__force unsigned *)(addr)) -/* - * Some code tests for these symbols - */ -#ifdef CONFIG_64BIT -#define readq readq -#define writeq writeq -#endif - #define __BUILD_MEMORY_STRING(bwlq, type) \ \ static inline void writes##bwlq(volatile void __iomem *mem, \ @@ -480,18 +449,6 @@ BUILDSTRING(l, u32) BUILDSTRING(q, u64) #endif -static inline void memset_io(volatile void __iomem *addr, unsigned char val, int count) -{ - memset((void __force *) addr, val, count); -} -static inline void memcpy_fromio(void *dst, const volatile void __iomem *src, int count) -{ - memcpy(dst, (void __force *) src, count); -} -static inline void memcpy_toio(volatile void __iomem *dst, const void *src, int count) -{ - memcpy((void __force *) dst, src, count); -} /* * The caches on some architectures aren't dma-coherent and have need to @@ -548,13 +505,66 @@ extern void (*_dma_cache_inv)(unsigned long start, unsigned long size); #define csr_out32(v, a) (*(volatile u32 *)((unsigned long)(a) + __CSR_32_ADJUST) = (v)) #define csr_in32(a) (*(volatile u32 *)((unsigned long)(a) + __CSR_32_ADJUST)) -/* - * Convert a physical pointer to a virtual kernel pointer for /dev/mem - * access - */ -#define xlate_dev_mem_ptr(p) __va(p) -#define unxlate_dev_mem_ptr(p, v) do { } while (0) +#define __raw_readb __raw_readb +#define __raw_readw __raw_readw +#define __raw_readl __raw_readl +#ifdef CONFIG_64BIT +#define __raw_readq __raw_readq +#endif +#define __raw_writeb __raw_writeb +#define __raw_writew __raw_writew +#define __raw_writel __raw_writel +#ifdef CONFIG_64BIT +#define __raw_writeq __raw_writeq +#endif + +#define readb readb +#define readw readw +#define readl readl +#ifdef CONFIG_64BIT +#define readq readq +#endif +#define writeb writeb +#define writew writew +#define writel writel +#ifdef CONFIG_64BIT +#define writeq writeq +#endif + +#define readsb readsb +#define readsw readsw +#define readsl readsl +#ifdef CONFIG_64BIT +#define readsq readsq +#endif +#define writesb writesb +#define writesw writesw +#define writesl writesl +#ifdef CONFIG_64BIT +#define writesq writesq +#endif + +#define _inb _inb +#define _inw _inw +#define _inl _inl +#define insb insb +#define insw insw +#define insl insl + +#define _outb _outb +#define _outw _outw +#define _outl _outl +#define outsb outsb +#define outsw outsw +#define outsl outsl void __ioread64_copy(void *to, const void __iomem *from, size_t count); +#include + +static inline void *isa_bus_to_virt(unsigned long address) +{ + return phys_to_virt(address); +} + #endif /* _ASM_IO_H */ diff --git a/arch/mips/include/asm/jump_label.h b/arch/mips/include/asm/jump_label.h index c5c6864e64bc43..081be98c71ef48 100644 --- a/arch/mips/include/asm/jump_label.h +++ b/arch/mips/include/asm/jump_label.h @@ -15,6 +15,9 @@ #include #include +struct module; +extern void jump_label_apply_nops(struct module *mod); + #define JUMP_LABEL_NOP_SIZE 4 #ifdef CONFIG_64BIT diff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h index 54a85f1d4f2c8d..179f320cc2313b 100644 --- a/arch/mips/include/asm/kvm_host.h +++ b/arch/mips/include/asm/kvm_host.h @@ -810,8 +810,6 @@ int kvm_mips_mkclean_gpa_pt(struct kvm *kvm, gfn_t start_gfn, gfn_t end_gfn); pgd_t *kvm_pgd_alloc(void); void kvm_mmu_free_memory_caches(struct kvm_vcpu *vcpu); -#define KVM_ARCH_WANT_MMU_NOTIFIER - /* Emulation */ enum emulation_result update_pc(struct kvm_vcpu *vcpu, u32 cause); int kvm_get_badinstr(u32 *opc, struct kvm_vcpu *vcpu, u32 *out); diff --git a/arch/mips/include/asm/mach-au1x00/au1000.h b/arch/mips/include/asm/mach-au1x00/au1000.h index a7eec3364a64ab..41546777902ba0 100644 --- a/arch/mips/include/asm/mach-au1x00/au1000.h +++ b/arch/mips/include/asm/mach-au1x00/au1000.h @@ -597,6 +597,9 @@ #include +void alchemy_set_lpj(void); +void board_setup(void); + /* helpers to access the SYS_* registers */ static inline unsigned long alchemy_rdsys(int regofs) { diff --git a/arch/mips/include/asm/mach-au1x00/au1000_dma.h b/arch/mips/include/asm/mach-au1x00/au1000_dma.h index 0a0cd4270c6f26..b82e513c8523a4 100644 --- a/arch/mips/include/asm/mach-au1x00/au1000_dma.h +++ b/arch/mips/include/asm/mach-au1x00/au1000_dma.h @@ -259,7 +259,7 @@ static inline void set_dma_mode(unsigned int dmanr, unsigned int mode) if (!chan) return; /* - * set_dma_mode is only allowed to change endianess, direction, + * set_dma_mode is only allowed to change endianness, direction, * transfer size, device FIFO width, and coherency settings. * Make sure anything else is masked off. */ diff --git a/arch/mips/include/asm/mach-au1x00/gpio-au1000.h b/arch/mips/include/asm/mach-au1x00/gpio-au1000.h index 82bc2766e2ec13..d820b481ac5641 100644 --- a/arch/mips/include/asm/mach-au1x00/gpio-au1000.h +++ b/arch/mips/include/asm/mach-au1x00/gpio-au1000.h @@ -435,7 +435,7 @@ static inline void alchemy_gpio2_disable_int(int gpio2) /** * alchemy_gpio2_enable - Activate GPIO2 block. * - * The GPIO2 block must be enabled excplicitly to work. On systems + * The GPIO2 block must be enabled explicitly to work. On systems * where this isn't done by the bootloader, this macro can be used. */ static inline void alchemy_gpio2_enable(void) diff --git a/arch/mips/include/asm/mach-cobalt/cobalt.h b/arch/mips/include/asm/mach-cobalt/cobalt.h index 5b9fce73f11d13..97f9d5e9446d22 100644 --- a/arch/mips/include/asm/mach-cobalt/cobalt.h +++ b/arch/mips/include/asm/mach-cobalt/cobalt.h @@ -19,4 +19,7 @@ extern int cobalt_board_id; #define COBALT_BRD_ID_QUBE2 0x5 #define COBALT_BRD_ID_RAQ2 0x6 +void cobalt_machine_halt(void); +void cobalt_machine_restart(char *command); + #endif /* __ASM_COBALT_H */ diff --git a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h index 5855ba1bd1ecf3..40eaa72e54d070 100644 --- a/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h +++ b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h @@ -55,7 +55,7 @@ extern __iomem void *ltq_sys1_membase; #define ltq_sys1_w32_mask(clear, set, reg) \ ltq_sys1_w32((ltq_sys1_r32(reg) & ~(clear)) | (set), reg) -/* allow the gpio and pinctrl drivers to talk to eachother */ +/* allow the gpio and pinctrl drivers to talk to each other */ extern int pinctrl_falcon_get_range_size(int id); extern void pinctrl_falcon_add_gpio_range(struct pinctrl_gpio_range *range); diff --git a/arch/mips/include/asm/mach-loongson64/loongson_hwmon.h b/arch/mips/include/asm/mach-loongson64/loongson_hwmon.h index 545f91f2ae16ac..721eafc4644e50 100644 --- a/arch/mips/include/asm/mach-loongson64/loongson_hwmon.h +++ b/arch/mips/include/asm/mach-loongson64/loongson_hwmon.h @@ -42,7 +42,7 @@ struct loongson_fan_policy { /* period between two check. (Unit: S) */ u8 adjust_period; - /* fan adjust usually depend on a temprature input */ + /* fan adjust usually depend on a temperature input */ get_temp_fun depend_temp; /* up_step/down_step used when type is STEP_SPEED_POLICY */ diff --git a/arch/mips/include/asm/mach-loongson64/loongson_regs.h b/arch/mips/include/asm/mach-loongson64/loongson_regs.h index b5be7511f6cde7..fec76750760492 100644 --- a/arch/mips/include/asm/mach-loongson64/loongson_regs.h +++ b/arch/mips/include/asm/mach-loongson64/loongson_regs.h @@ -227,7 +227,7 @@ static inline void csr_writeq(u64 val, u32 reg) #define LOONGSON_CSR_NODECNT 0x408 #define LOONGSON_CSR_CPUTEMP 0x428 -/* PerCore CSR, only accessable by local cores */ +/* PerCore CSR, only accessible by local cores */ #define LOONGSON_CSR_IPI_STATUS 0x1000 #define LOONGSON_CSR_IPI_EN 0x1004 #define LOONGSON_CSR_IPI_SET 0x1008 diff --git a/arch/mips/include/asm/mach-loongson64/mmzone.h b/arch/mips/include/asm/mach-loongson64/mmzone.h index ebb1deaa77b9d5..a3d65d37b8b5d5 100644 --- a/arch/mips/include/asm/mach-loongson64/mmzone.h +++ b/arch/mips/include/asm/mach-loongson64/mmzone.h @@ -18,7 +18,6 @@ extern struct pglist_data *__node_data[]; #define NODE_DATA(n) (__node_data[n]) -extern void setup_zero_pages(void); extern void __init prom_init_numa_memory(void); #endif /* _ASM_MACH_MMZONE_H */ diff --git a/arch/mips/include/asm/mach-malta/spaces.h b/arch/mips/include/asm/mach-malta/spaces.h index d7e54971ec668b..1ce4ba97852f7c 100644 --- a/arch/mips/include/asm/mach-malta/spaces.h +++ b/arch/mips/include/asm/mach-malta/spaces.h @@ -23,13 +23,13 @@ * The kernel is still located in 0x80000000(kseg0). However, * the physical mask has been shifted to 0x80000000 which exploits the alias * on the Malta board. As a result of which, we override the __pa_symbol - * to peform direct mapping from virtual to physical addresses. In other + * to perform direct mapping from virtual to physical addresses. In other * words, the 0x80000000 virtual address maps to 0x80000000 physical address * which in turn aliases to 0x0. We do this in order to be able to use a flat * 2GB of memory (0x80000000 - 0xffffffff) so we can avoid the I/O hole in * 0x10000000 - 0x1fffffff. * The last 64KB of physical memory are reserved for correct HIGHMEM - * macros arithmetics. + * macros arithmetic. * */ diff --git a/arch/mips/include/asm/mips-boards/bonito64.h b/arch/mips/include/asm/mips-boards/bonito64.h index 5368891d424b77..31a31fe78d7759 100644 --- a/arch/mips/include/asm/mips-boards/bonito64.h +++ b/arch/mips/include/asm/mips-boards/bonito64.h @@ -16,7 +16,7 @@ */ /* Revision 1.48 autogenerated on 08/17/99 15:20:01 */ -/* This bonito64 version editted from bonito.h Revision 1.48 on 11/09/00 */ +/* This bonito64 version edited from bonito.h Revision 1.48 on 11/09/00 */ #ifndef _ASM_MIPS_BOARDS_BONITO64_H #define _ASM_MIPS_BOARDS_BONITO64_H diff --git a/arch/mips/include/asm/mips-cpc.h b/arch/mips/include/asm/mips-cpc.h index b54453f1648c1f..5f3a7a9f42bf0d 100644 --- a/arch/mips/include/asm/mips-cpc.h +++ b/arch/mips/include/asm/mips-cpc.h @@ -22,7 +22,7 @@ extern void __iomem *mips_cpc_base; * the CPC * * Returns the default physical base address of the Cluster Power Controller - * memory mapped registers. This is platform dependant & must therefore be + * memory mapped registers. This is platform dependent & must therefore be * implemented per-platform. */ extern phys_addr_t mips_cpc_default_phys_base(void); diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index 2d53704d9f2461..ec58cb76d076d5 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -98,7 +98,7 @@ /* * R4640/R4650 cp0 register names. These registers are listed - * here only for completeness; without MMU these CPUs are not useable + * here only for completeness; without MMU these CPUs are not usable * by Linux. A future ELKS port might take make Linux run on them * though ... */ @@ -461,7 +461,7 @@ #define EXCCODE_THREAD 25 /* Thread exceptions (MT) */ #define EXCCODE_DSPDIS 26 /* DSP disabled exception */ #define EXCCODE_GE 27 /* Virtualized guest exception (VZ) */ -#define EXCCODE_CACHEERR 30 /* Parity/ECC occured on a core */ +#define EXCCODE_CACHEERR 30 /* Parity/ECC occurred on a core */ /* Implementation specific trap codes used by MIPS cores */ #define MIPS_EXCCODE_TLBPAR 16 /* TLB parity error exception */ diff --git a/arch/mips/include/asm/mmiowb.h b/arch/mips/include/asm/mmiowb.h index a40824e3ef8e34..cf27752fd2202a 100644 --- a/arch/mips/include/asm/mmiowb.h +++ b/arch/mips/include/asm/mmiowb.h @@ -2,9 +2,9 @@ #ifndef _ASM_MMIOWB_H #define _ASM_MMIOWB_H -#include +#include -#define mmiowb() iobarrier_w() +#define mmiowb() wmb() #include diff --git a/arch/mips/include/asm/mmzone.h b/arch/mips/include/asm/mmzone.h index 602a21aee9d4c9..14226ea420361c 100644 --- a/arch/mips/include/asm/mmzone.h +++ b/arch/mips/include/asm/mmzone.h @@ -20,4 +20,6 @@ #define nid_to_addrbase(nid) 0 #endif +extern void setup_zero_pages(void); + #endif /* _ASM_MMZONE_H_ */ diff --git a/arch/mips/include/asm/octeon/cvmx-bootinfo.h b/arch/mips/include/asm/octeon/cvmx-bootinfo.h index c1c0b3230e0a9c..028bf1d6daeeb6 100644 --- a/arch/mips/include/asm/octeon/cvmx-bootinfo.h +++ b/arch/mips/include/asm/octeon/cvmx-bootinfo.h @@ -114,7 +114,7 @@ struct cvmx_bootinfo { /* * flags indicating various configuration options. These - * flags supercede the 'flags' variable and should be used + * flags supersede the 'flags' variable and should be used * instead if available. */ uint32_t config_flags; diff --git a/arch/mips/include/asm/octeon/cvmx-cmd-queue.h b/arch/mips/include/asm/octeon/cvmx-cmd-queue.h index a07a36f7d8141c..67e1b2162b1945 100644 --- a/arch/mips/include/asm/octeon/cvmx-cmd-queue.h +++ b/arch/mips/include/asm/octeon/cvmx-cmd-queue.h @@ -145,7 +145,7 @@ typedef struct { /** * This structure contains the global state of all command queues. * It is stored in a bootmem named block and shared by all - * applications running on Octeon. Tickets are stored in a differnet + * applications running on Octeon. Tickets are stored in a different * cache line that queue information to reduce the contention on the * ll/sc used to get a ticket. If this is not the case, the update * of queue state causes the ll/sc to fail quite often. @@ -172,7 +172,7 @@ cvmx_cmd_queue_result_t cvmx_cmd_queue_initialize(cvmx_cmd_queue_id_t queue_id, int pool_size); /** - * Shutdown a queue a free it's command buffers to the FPA. The + * Shutdown a queue and free its command buffers to the FPA. The * hardware connected to the queue must be stopped before this * function is called. * @@ -194,7 +194,7 @@ int cvmx_cmd_queue_length(cvmx_cmd_queue_id_t queue_id); /** * Return the command buffer to be written to. The purpose of this - * function is to allow CVMX routine access t othe low level buffer + * function is to allow CVMX routine access to the low level buffer * for initial hardware setup. User applications should not call this * function directly. * diff --git a/arch/mips/include/asm/octeon/cvmx-pko.h b/arch/mips/include/asm/octeon/cvmx-pko.h index 5fec8476e42123..f18a7f24daf824 100644 --- a/arch/mips/include/asm/octeon/cvmx-pko.h +++ b/arch/mips/include/asm/octeon/cvmx-pko.h @@ -91,7 +91,7 @@ typedef enum { } cvmx_pko_status_t; /** - * This enumeration represents the differnet locking modes supported by PKO. + * This enumeration represents the different locking modes supported by PKO. */ typedef enum { /* diff --git a/arch/mips/include/asm/octeon/cvmx-pow.h b/arch/mips/include/asm/octeon/cvmx-pow.h index a3b23811e0c304..21b4378244fafb 100644 --- a/arch/mips/include/asm/octeon/cvmx-pow.h +++ b/arch/mips/include/asm/octeon/cvmx-pow.h @@ -1342,7 +1342,7 @@ static inline void cvmx_pow_tag_sw_wait(void) * This function does NOT wait for previous tag switches to complete, * so the caller must ensure that there is not a pending tag switch. * - * @wait: When set, call stalls until work becomes avaiable, or times out. + * @wait: When set, call stalls until work becomes available, or times out. * If not set, returns immediately. * * Returns: the WQE pointer from POW. Returns NULL if no work @@ -1376,7 +1376,7 @@ static inline struct cvmx_wqe *cvmx_pow_work_request_sync_nocheck(cvmx_pow_wait_ * This function waits for any previous tag switch to complete before * requesting the new work. * - * @wait: When set, call stalls until work becomes avaiable, or times out. + * @wait: When set, call stalls until work becomes available, or times out. * If not set, returns immediately. * * Returns: the WQE pointer from POW. Returns NULL if no work diff --git a/arch/mips/include/asm/octeon/octeon-model.h b/arch/mips/include/asm/octeon/octeon-model.h index 6c68517c277027..e53b61a8e32f17 100644 --- a/arch/mips/include/asm/octeon/octeon-model.h +++ b/arch/mips/include/asm/octeon/octeon-model.h @@ -54,7 +54,7 @@ #define OM_CHECK_SUBMODEL 0x02000000 /* Match all models previous than the one specified */ #define OM_MATCH_PREVIOUS_MODELS 0x04000000 -/* Ignores the minor revison on newer parts */ +/* Ignores the minor revision on newer parts */ #define OM_IGNORE_MINOR_REVISION 0x08000000 #define OM_FLAG_MASK 0xff000000 @@ -226,7 +226,7 @@ #define OCTEON_CN52XX_PASS2 OCTEON_CN52XX_PASS2_X /* - * CN3XXX models with old revision enconding + * CN3XXX models with old revision encoding */ #define OCTEON_CN38XX_PASS1 0x000d0000 #define OCTEON_CN38XX_PASS2 0x000d0001 diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h index 5978a8dfb917b0..ef9585d96f6b08 100644 --- a/arch/mips/include/asm/page.h +++ b/arch/mips/include/asm/page.h @@ -173,7 +173,7 @@ static inline unsigned long ___pa(unsigned long x) if (IS_ENABLED(CONFIG_64BIT)) { /* * For MIPS64 the virtual address may either be in one of - * the compatibility segements ckseg0 or ckseg1, or it may + * the compatibility segments ckseg0 or ckseg1, or it may * be in xkphys. */ return x < CKSEG0 ? XPHYSADDR(x) : CPHYSADDR(x); diff --git a/arch/mips/include/asm/pci.h b/arch/mips/include/asm/pci.h index 3fd6e22c108b41..d993df6302dcf4 100644 --- a/arch/mips/include/asm/pci.h +++ b/arch/mips/include/asm/pci.h @@ -23,7 +23,7 @@ #ifdef CONFIG_PCI_DRIVERS_LEGACY /* - * Each pci channel is a top-level PCI bus seem by CPU. A machine with + * Each PCI channel is a top-level PCI bus seem by CPU. A machine with * multiple PCI channels may have multiple PCI host controllers or a * single controller supporting multiple channels. */ diff --git a/arch/mips/include/asm/pgtable-bits.h b/arch/mips/include/asm/pgtable-bits.h index 421e78c30253cb..088623ba7b8b17 100644 --- a/arch/mips/include/asm/pgtable-bits.h +++ b/arch/mips/include/asm/pgtable-bits.h @@ -201,7 +201,7 @@ enum pgtable_bits { * The final layouts of the PTE bits are: * * 64-bit, R1 or earlier: CCC D V G [S H] M A W R P - * 32-bit, R1 or earler: CCC D V G M A W R P + * 32-bit, R1 or earlier: CCC D V G M A W R P * 64-bit, R2 or later: CCC D V G RI/R XI [S H] M A W P * 32-bit, R2 or later: CCC D V G RI/R XI M A W P */ diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h index 430b208c01307b..e27a4c83c54869 100644 --- a/arch/mips/include/asm/pgtable.h +++ b/arch/mips/include/asm/pgtable.h @@ -655,6 +655,7 @@ static inline pmd_t pmd_mkwrite_novma(pmd_t pmd) return pmd; } +#define pmd_dirty pmd_dirty static inline int pmd_dirty(pmd_t pmd) { return !!(pmd_val(pmd) & _PAGE_MODIFIED); diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h index ae2cd37a38f05f..ca7662cc65a7ea 100644 --- a/arch/mips/include/asm/processor.h +++ b/arch/mips/include/asm/processor.h @@ -402,4 +402,6 @@ extern int mips_set_process_fp_mode(struct task_struct *task, #define GET_FP_MODE(task) mips_get_process_fp_mode(task) #define SET_FP_MODE(task,value) mips_set_process_fp_mode(task, value) +void show_registers(struct pt_regs *regs); + #endif /* _ASM_PROCESSOR_H */ diff --git a/arch/mips/include/asm/r4kcache.h b/arch/mips/include/asm/r4kcache.h index 431a1c9d53fc71..da1cd1bbdbc5d1 100644 --- a/arch/mips/include/asm/r4kcache.h +++ b/arch/mips/include/asm/r4kcache.h @@ -24,6 +24,10 @@ #include #include +extern void r5k_sc_init(void); +extern void rm7k_sc_init(void); +extern int mips_sc_init(void); + extern void (*r4k_blast_dcache)(void); extern void (*r4k_blast_icache)(void); diff --git a/arch/mips/include/asm/setup.h b/arch/mips/include/asm/setup.h index 8c56b862fd9c2b..4dce41138bad6d 100644 --- a/arch/mips/include/asm/setup.h +++ b/arch/mips/include/asm/setup.h @@ -27,5 +27,6 @@ extern unsigned long ebase; extern unsigned int hwrena; extern void per_cpu_trap_init(bool); extern void cpu_cache_init(void); +extern void tlb_init(void); #endif /* __SETUP_H */ diff --git a/arch/mips/include/asm/sgi/mc.h b/arch/mips/include/asm/sgi/mc.h index 3a070cec97e7d7..5e96f9d3262497 100644 --- a/arch/mips/include/asm/sgi/mc.h +++ b/arch/mips/include/asm/sgi/mc.h @@ -96,7 +96,7 @@ struct sgimc_regs { volatile u32 lbursttp; /* Time period for long bursts */ /* MC chip can drive up to 4 bank 4 SIMMs each. All SIMMs in bank must - * be the same size. The size encoding for supported SIMMs is bellow */ + * be the same size. The size encoding for supported SIMMs is below */ u32 _unused11[9]; volatile u32 mconfig0; /* Memory config register zero */ u32 _unused12; diff --git a/arch/mips/include/asm/signal.h b/arch/mips/include/asm/signal.h index 23d6b8015c79ac..8de81ccef7adab 100644 --- a/arch/mips/include/asm/signal.h +++ b/arch/mips/include/asm/signal.h @@ -31,5 +31,6 @@ extern struct mips_abi mips_abi_32; extern int protected_save_fp_context(void __user *sc); extern int protected_restore_fp_context(void __user *sc); +void do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags); #endif /* _ASM_SIGNAL_H */ diff --git a/arch/mips/include/asm/smp-ops.h b/arch/mips/include/asm/smp-ops.h index 0c59e168f8008c..1617b207723fb2 100644 --- a/arch/mips/include/asm/smp-ops.h +++ b/arch/mips/include/asm/smp-ops.h @@ -13,8 +13,6 @@ #include -#include - #ifdef CONFIG_SMP #include diff --git a/arch/mips/include/asm/smp.h b/arch/mips/include/asm/smp.h index 901bc61fa7ae92..bc2c240f414b6b 100644 --- a/arch/mips/include/asm/smp.h +++ b/arch/mips/include/asm/smp.h @@ -11,13 +11,11 @@ #ifndef __ASM_SMP_H #define __ASM_SMP_H -#include +#include #include -#include #include #include -#include #include extern int smp_num_siblings; @@ -63,6 +61,8 @@ extern asmlinkage void smp_bootstrap(void); extern void calculate_cpu_foreign_map(void); +asmlinkage void start_secondary(void); + /* * this function sends a 'reschedule' IPI to another CPU. * it goes straight through and wastes no time serializing diff --git a/arch/mips/include/asm/sn/klconfig.h b/arch/mips/include/asm/sn/klconfig.h index 117f85e4bef59a..3d1670b3e05273 100644 --- a/arch/mips/include/asm/sn/klconfig.h +++ b/arch/mips/include/asm/sn/klconfig.h @@ -851,7 +851,7 @@ typedef union kldev_s { /* for device structure allocation */ /* * TBD - Allocation issues. * - * Do we need to Mark off sepatate heaps for lboard_t, rboard_t, component, + * Do we need to Mark off separate heaps for lboard_t, rboard_t, component, * errinfo and allocate from them, or have a single heap and allocate all * structures from it. Debug is easier in the former method since we can * dump all similar structs in one command, but there will be lots of holes, diff --git a/arch/mips/include/asm/spram.h b/arch/mips/include/asm/spram.h index 373f2a5d495d8c..9f6a2cb1943a1e 100644 --- a/arch/mips/include/asm/spram.h +++ b/arch/mips/include/asm/spram.h @@ -3,7 +3,7 @@ #define _MIPS_SPRAM_H #if defined(CONFIG_MIPS_SPRAM) -extern __init void spram_config(void); +extern void spram_config(void); #else static inline void spram_config(void) { } #endif /* CONFIG_MIPS_SPRAM */ diff --git a/arch/mips/include/asm/sync.h b/arch/mips/include/asm/sync.h index aabd097933fe97..44c04a82d0b7d4 100644 --- a/arch/mips/include/asm/sync.h +++ b/arch/mips/include/asm/sync.h @@ -19,7 +19,7 @@ * * Ordering barriers can be more efficient than completion barriers, since: * - * a) Ordering barriers only require memory access instructions which preceed + * a) Ordering barriers only require memory access instructions which precede * them in program order (older instructions) to reach a point in the * load/store datapath beyond which reordering is not possible before * allowing memory access instructions which follow them (younger diff --git a/arch/mips/include/asm/syscalls.h b/arch/mips/include/asm/syscalls.h new file mode 100644 index 00000000000000..59f9c0c9fa0aa8 --- /dev/null +++ b/arch/mips/include/asm/syscalls.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef _ASM_MIPS_SYSCALLS_H +#define _ASM_MIPS_SYSCALLS_H + +#include +#include + +asmlinkage void sys_sigreturn(void); +asmlinkage void sys_rt_sigreturn(void); +asmlinkage int sysm_pipe(void); +asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len, + unsigned long __user *user_mask_ptr); +asmlinkage long mipsmt_sys_sched_getaffinity(pid_t pid, unsigned int len, + unsigned long __user *user_mask_ptr); +asmlinkage long sys32_fallocate(int fd, int mode, unsigned offset_a2, + unsigned offset_a3, unsigned len_a4, + unsigned len_a5); +asmlinkage long sys32_fadvise64_64(int fd, int __pad, + unsigned long a2, unsigned long a3, + unsigned long a4, unsigned long a5, + int flags); +asmlinkage ssize_t sys32_readahead(int fd, u32 pad0, u64 a2, u64 a3, + size_t count); +asmlinkage long sys32_sync_file_range(int fd, int __pad, + unsigned long a2, unsigned long a3, + unsigned long a4, unsigned long a5, + int flags); +asmlinkage void sys32_rt_sigreturn(void); +asmlinkage void sys32_sigreturn(void); +asmlinkage int sys32_sigsuspend(compat_sigset_t __user *uset); +asmlinkage void sysn32_rt_sigreturn(void); + +#endif diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h index ecae7470faa405..b9d76e8ac5a23d 100644 --- a/arch/mips/include/asm/thread_info.h +++ b/arch/mips/include/asm/thread_info.h @@ -27,7 +27,7 @@ struct thread_info { unsigned long flags; /* low level flags */ unsigned long tp_value; /* thread pointer */ __u32 cpu; /* current CPU */ - int preempt_count; /* 0 => preemptable, <0 => BUG */ + int preempt_count; /* 0 => preemptible, <0 => BUG */ struct pt_regs *regs; long syscall; /* syscall number */ }; diff --git a/arch/mips/include/asm/timex.h b/arch/mips/include/asm/timex.h index 2e107886f97ac7..7ef06dcdc46ec5 100644 --- a/arch/mips/include/asm/timex.h +++ b/arch/mips/include/asm/timex.h @@ -46,7 +46,7 @@ typedef unsigned int cycles_t; * * There is a suggested workaround and also the erratum can't strike if * the compare interrupt isn't being used as the clock source device. - * However for now the implementaton of this function doesn't get these + * However for now the implementation of this function doesn't get these * fine details right. */ static inline int can_use_mips_counter(unsigned int prid) diff --git a/arch/mips/include/asm/tlbex.h b/arch/mips/include/asm/tlbex.h index 6d97e23f30abdd..24a2d06cc1c390 100644 --- a/arch/mips/include/asm/tlbex.h +++ b/arch/mips/include/asm/tlbex.h @@ -23,6 +23,7 @@ void build_update_entries(u32 **p, unsigned int tmp, unsigned int ptep); void build_tlb_write_entry(u32 **p, struct uasm_label **l, struct uasm_reloc **r, enum tlb_write_entry wmode); +void build_tlb_refill_handler(void); extern void handle_tlbl(void); extern char handle_tlbl_end[]; diff --git a/arch/mips/include/asm/traps.h b/arch/mips/include/asm/traps.h index 15cde638b4070c..2a8a258730c902 100644 --- a/arch/mips/include/asm/traps.h +++ b/arch/mips/include/asm/traps.h @@ -39,4 +39,30 @@ extern char except_vec_nmi[]; register_nmi_notifier(&fn##_nb); \ }) +asmlinkage void do_ade(struct pt_regs *regs); +asmlinkage void do_be(struct pt_regs *regs); +asmlinkage void do_ov(struct pt_regs *regs); +asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31); +asmlinkage void do_bp(struct pt_regs *regs); +asmlinkage void do_tr(struct pt_regs *regs); +asmlinkage void do_ri(struct pt_regs *regs); +asmlinkage void do_cpu(struct pt_regs *regs); +asmlinkage void do_msa_fpe(struct pt_regs *regs, unsigned int msacsr); +asmlinkage void do_msa(struct pt_regs *regs); +asmlinkage void do_mdmx(struct pt_regs *regs); +asmlinkage void do_watch(struct pt_regs *regs); +asmlinkage void do_mcheck(struct pt_regs *regs); +asmlinkage void do_mt(struct pt_regs *regs); +asmlinkage void do_dsp(struct pt_regs *regs); +asmlinkage void do_reserved(struct pt_regs *regs); +asmlinkage void do_ftlb(void); +asmlinkage void do_gsexc(struct pt_regs *regs, u32 diag1); +asmlinkage void do_daddi_ov(struct pt_regs *regs); +asmlinkage void do_page_fault(struct pt_regs *regs, + unsigned long write, unsigned long address); + +asmlinkage void cache_parity_error(void); +asmlinkage void ejtag_exception_handler(struct pt_regs *regs); +asmlinkage void __noreturn nmi_exception_handler(struct pt_regs *regs); + #endif /* _ASM_TRAPS_H */ diff --git a/arch/mips/include/asm/uasm.h b/arch/mips/include/asm/uasm.h index 296bcf31abb571..b43bfd44525213 100644 --- a/arch/mips/include/asm/uasm.h +++ b/arch/mips/include/asm/uasm.h @@ -193,9 +193,7 @@ struct uasm_label { void uasm_build_label(struct uasm_label **lab, u32 *addr, int lid); -#ifdef CONFIG_64BIT int uasm_in_compat_space_p(long addr); -#endif int uasm_rel_hi(long val); int uasm_rel_lo(long val); void UASM_i_LA_mostly(u32 **buf, unsigned int rs, long addr); diff --git a/arch/mips/include/asm/vdso/vdso.h b/arch/mips/include/asm/vdso/vdso.h index a327ca21270ecc..6cd88191fefa9c 100644 --- a/arch/mips/include/asm/vdso/vdso.h +++ b/arch/mips/include/asm/vdso/vdso.h @@ -32,7 +32,7 @@ static inline unsigned long get_vdso_base(void) #else /* * Get the base load address of the VDSO. We have to avoid generating - * relocations and references to the GOT because ld.so does not peform + * relocations and references to the GOT because ld.so does not perform * relocations on the VDSO. We use the current offset from the VDSO base * and perform a PC-relative branch which gives the absolute address in * ra, and take the difference. The assembler chokes on diff --git a/arch/mips/include/uapi/asm/mman.h b/arch/mips/include/uapi/asm/mman.h index c6e1fc77c99688..9c48d9a21aa01f 100644 --- a/arch/mips/include/uapi/asm/mman.h +++ b/arch/mips/include/uapi/asm/mman.h @@ -88,7 +88,7 @@ #define MADV_HUGEPAGE 14 /* Worth backing with hugepages */ #define MADV_NOHUGEPAGE 15 /* Not worth backing with hugepages */ -#define MADV_DONTDUMP 16 /* Explicity exclude from the core dump, +#define MADV_DONTDUMP 16 /* Explicitly exclude from core dump, overrides the coredump filter bits */ #define MADV_DODUMP 17 /* Clear the MADV_NODUMP flag */ diff --git a/arch/mips/include/uapi/asm/msgbuf.h b/arch/mips/include/uapi/asm/msgbuf.h index 128af72f2dfead..d546642fc67e67 100644 --- a/arch/mips/include/uapi/asm/msgbuf.h +++ b/arch/mips/include/uapi/asm/msgbuf.h @@ -62,7 +62,7 @@ struct msqid64_ds { unsigned long __unused5; }; #else -#warning no endianess set +#warning no endianness set #endif #endif /* _ASM_MSGBUF_H */ diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index b406d8bfb15a36..bda7f193baab9f 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -179,7 +179,6 @@ void __init check_bugs32(void) static inline int cpu_has_confreg(void) { #ifdef CONFIG_CPU_R3000 - extern unsigned long r3k_cache_size(unsigned long); unsigned long size1, size2; unsigned long cfg = read_c0_conf(); @@ -1139,7 +1138,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) * This processor doesn't have an MMU, so it's not * "real easy" to run Linux on it. It is left purely * for documentation. Commented out because it shares - * it's c0_prid id number with the TX3900. + * its c0_prid id number with the TX3900. */ c->cputype = CPU_R4650; __cpu_name[cpu] = "R4650"; diff --git a/arch/mips/kernel/cpu-r3k-probe.c b/arch/mips/kernel/cpu-r3k-probe.c index be93469c0e0eca..0c826f729f7527 100644 --- a/arch/mips/kernel/cpu-r3k-probe.c +++ b/arch/mips/kernel/cpu-r3k-probe.c @@ -42,7 +42,6 @@ void __init check_bugs32(void) static inline int cpu_has_confreg(void) { #ifdef CONFIG_CPU_R3000 - extern unsigned long r3k_cache_size(unsigned long); unsigned long size1, size2; unsigned long cfg = read_c0_conf(); diff --git a/arch/mips/kernel/elf.c b/arch/mips/kernel/elf.c index 5582a4ca1e9e36..7aa2c2360ff602 100644 --- a/arch/mips/kernel/elf.c +++ b/arch/mips/kernel/elf.c @@ -11,6 +11,7 @@ #include #include +#include #ifdef CONFIG_MIPS_FP_SUPPORT @@ -309,6 +310,11 @@ void mips_set_personality_nan(struct arch_elf_state *state) struct cpuinfo_mips *c = &boot_cpu_data; struct task_struct *t = current; + /* Do this early so t->thread.fpu.fcr31 won't be clobbered in case + * we are preempted before the lose_fpu(0) in start_thread. + */ + lose_fpu(0); + t->thread.fpu.fcr31 = c->fpu_csr31; switch (state->nan_2008) { case 0: diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S index b6de8e88c1bd42..a572ce36a24f21 100644 --- a/arch/mips/kernel/genex.S +++ b/arch/mips/kernel/genex.S @@ -272,18 +272,17 @@ NESTED(except_vec_vi, 0, sp) .set push .set noreorder PTR_LA v1, except_vec_vi_handler -FEXPORT(except_vec_vi_lui) - lui v0, 0 /* Patched */ jr v1 FEXPORT(except_vec_vi_ori) - ori v0, 0 /* Patched */ + ori v0, zero, 0 /* Offset in vi_handlers[] */ .set pop END(except_vec_vi) EXPORT(except_vec_vi_end) /* * Common Vectored Interrupt code - * Complete the register saves and invoke the handler which is passed in $v0 + * Complete the register saves and invoke the handler, $v0 holds + * offset into vi_handlers[] */ NESTED(except_vec_vi_handler, 0, sp) SAVE_TEMP @@ -331,6 +330,7 @@ NESTED(except_vec_vi_handler, 0, sp) /* Save task's sp on IRQ stack so that unwinding can follow it */ LONG_S s1, 0(sp) 2: + PTR_L v0, vi_handlers(v0) jalr v0 /* Restore sp */ diff --git a/arch/mips/kernel/kprobes.c b/arch/mips/kernel/kprobes.c index 316b27d0d2fbd0..dc39f5b3fb8307 100644 --- a/arch/mips/kernel/kprobes.c +++ b/arch/mips/kernel/kprobes.c @@ -55,7 +55,7 @@ NOKPROBE_SYMBOL(insn_has_delayslot); * one; putting breakpoint on top of atomic ll/sc pair is bad idea; * so we need to prevent it and refuse kprobes insertion for such * instructions; cannot do much about breakpoint in the middle of - * ll/sc pair; it is upto user to avoid those places + * ll/sc pair; it is up to user to avoid those places */ static int insn_has_ll_or_sc(union mips_instruction insn) { diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index 6b61be486303bb..a0c0a7a654e941 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c @@ -42,6 +42,7 @@ #include #include #include +#include #ifdef __MIPSEB__ #define merge_64(r1, r2) ((((r1) & 0xffffffffUL) << 32) + ((r2) & 0xffffffffUL)) diff --git a/arch/mips/kernel/machine_kexec.c b/arch/mips/kernel/machine_kexec.c index 432bfd3e7f220a..4e3579bbd6200b 100644 --- a/arch/mips/kernel/machine_kexec.c +++ b/arch/mips/kernel/machine_kexec.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c index 3f00788b08718d..84b3affb9de88a 100644 --- a/arch/mips/kernel/mips-cm.c +++ b/arch/mips/kernel/mips-cm.c @@ -201,7 +201,7 @@ phys_addr_t __mips_cm_phys_base(void) phys_addr_t mips_cm_phys_base(void) __attribute__((weak, alias("__mips_cm_phys_base"))); -phys_addr_t __mips_cm_l2sync_phys_base(void) +static phys_addr_t __mips_cm_l2sync_phys_base(void) { u32 base_reg; diff --git a/arch/mips/kernel/mips-mt-fpaff.c b/arch/mips/kernel/mips-mt-fpaff.c index 67e130d3f0385d..10172fc4f627b8 100644 --- a/arch/mips/kernel/mips-mt-fpaff.c +++ b/arch/mips/kernel/mips-mt-fpaff.c @@ -15,6 +15,7 @@ #include #include #include +#include /* * CPU mask used to set process affinity for MT VPEs/TCs with FPUs diff --git a/arch/mips/kernel/mips-mt.c b/arch/mips/kernel/mips-mt.c index f88b7919f11f49..c07d64438b5bfb 100644 --- a/arch/mips/kernel/mips-mt.c +++ b/arch/mips/kernel/mips-mt.c @@ -19,6 +19,7 @@ #include #include #include +#include int vpelimit; diff --git a/arch/mips/kernel/module.c b/arch/mips/kernel/module.c index 0c936cbf20c534..7b2fbaa9cac579 100644 --- a/arch/mips/kernel/module.c +++ b/arch/mips/kernel/module.c @@ -20,8 +20,7 @@ #include #include #include - -extern void jump_label_apply_nops(struct module *mod); +#include struct mips_hi16 { struct mips_hi16 *next; diff --git a/arch/mips/kernel/prom.c b/arch/mips/kernel/prom.c index f88ce78e13e3a2..6062e6fa589a87 100644 --- a/arch/mips/kernel/prom.c +++ b/arch/mips/kernel/prom.c @@ -28,6 +28,8 @@ __init void mips_set_machine_name(const char *name) strscpy(mips_machine_name, name, sizeof(mips_machine_name)); pr_info("MIPS: machine is %s\n", mips_get_machine_name()); + + dump_stack_set_arch_desc(name); } char *mips_get_machine_name(void) diff --git a/arch/mips/kernel/r4k-bugs64.c b/arch/mips/kernel/r4k-bugs64.c index 6ffefb2c6971e2..1e300330078ddb 100644 --- a/arch/mips/kernel/r4k-bugs64.c +++ b/arch/mips/kernel/r4k-bugs64.c @@ -14,6 +14,7 @@ #include #include #include +#include static char bug64hit[] __initdata = "reliable operation impossible!\n%s"; diff --git a/arch/mips/kernel/relocate.c b/arch/mips/kernel/relocate.c index 58fc8d089402bd..7eeeaf1ff95d26 100644 --- a/arch/mips/kernel/relocate.c +++ b/arch/mips/kernel/relocate.c @@ -380,7 +380,7 @@ void *__init relocate_kernel(void) } #endif /* CONFIG_USE_OF */ - /* Copy the kernel to it's new location */ + /* Copy the kernel to its new location */ memcpy(loc_new, &_text, kernel_length); /* Perform relocations on the new kernel */ diff --git a/arch/mips/kernel/relocate_kernel.S b/arch/mips/kernel/relocate_kernel.S index 8f0a7263a9d61f..de894a0211d7a6 100644 --- a/arch/mips/kernel/relocate_kernel.S +++ b/arch/mips/kernel/relocate_kernel.S @@ -70,7 +70,7 @@ copy_word: done: #ifdef CONFIG_SMP /* kexec_flag reset is signal to other CPUs what kernel - was moved to it's location. Note - we need relocated address + was moved to its location. Note - we need relocated address of kexec_flag. */ bal 1f diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 2d2ca024bd47af..9c30de15159761 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -146,7 +147,7 @@ static unsigned long __init init_initrd(void) /* * Board specific code or command line parser should have * already set up initrd_start and initrd_end. In these cases - * perfom sanity checks and use them if all looks good. + * perform sanity checks and use them if all looks good. */ if (!initrd_start || initrd_end <= initrd_start) goto disable; @@ -321,11 +322,11 @@ static void __init bootmem_init(void) panic("Incorrect memory mapping !!!"); if (max_pfn > PFN_DOWN(HIGHMEM_START)) { + max_low_pfn = PFN_DOWN(HIGHMEM_START); #ifdef CONFIG_HIGHMEM - highstart_pfn = PFN_DOWN(HIGHMEM_START); + highstart_pfn = max_low_pfn; highend_pfn = max_pfn; #else - max_low_pfn = PFN_DOWN(HIGHMEM_START); max_pfn = max_low_pfn; #endif } diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h index f50d48435c6803..136eb20ac024fc 100644 --- a/arch/mips/kernel/signal-common.h +++ b/arch/mips/kernel/signal-common.h @@ -40,4 +40,7 @@ _restore_fp_context(void __user *fpregs, void __user *csr); extern asmlinkage int _save_msa_all_upper(void __user *buf); extern asmlinkage int _restore_msa_all_upper(void __user *buf); +extern int setup_sigcontext(struct pt_regs *, struct sigcontext __user *); +extern int restore_sigcontext(struct pt_regs *, struct sigcontext __user *); + #endif /* __SIGNAL_COMMON_H */ diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 479999b7f2de73..4a10f18a880604 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -38,6 +38,7 @@ #include #include #include +#include #include "signal-common.h" @@ -569,7 +570,7 @@ void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, return (void __user __force *)(-1UL); /* - * FPU emulator may have it's own trampoline active just + * FPU emulator may have its own trampoline active just * above the user stack, 16-bytes before the next lowest * 16 byte boundary. Try to avoid trashing it. */ diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 59b8965433c2fd..73081d4ee8c1c9 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "signal-common.h" diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c index cfc77b69420a1f..139d2596b0d409 100644 --- a/arch/mips/kernel/signal_n32.c +++ b/arch/mips/kernel/signal_n32.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "signal-common.h" @@ -32,9 +33,6 @@ */ #define __NR_N32_restart_syscall 6214 -extern int setup_sigcontext(struct pt_regs *, struct sigcontext __user *); -extern int restore_sigcontext(struct pt_regs *, struct sigcontext __user *); - struct ucontextn32 { u32 uc_flags; s32 uc_link; diff --git a/arch/mips/kernel/signal_o32.c b/arch/mips/kernel/signal_o32.c index 299a7a28ca33f2..4f04584596507a 100644 --- a/arch/mips/kernel/signal_o32.c +++ b/arch/mips/kernel/signal_o32.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "signal-common.h" diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 82e2e051b4161c..0b53d35a116e70 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -468,11 +469,13 @@ int __cpu_up(unsigned int cpu, struct task_struct *tidle) return 0; } +#ifdef CONFIG_PROFILING /* Not really SMP stuff ... */ int setup_profiling_timer(unsigned int multiplier) { return 0; } +#endif static void flush_tlb_all_ipi(void *info) { diff --git a/arch/mips/kernel/spram.c b/arch/mips/kernel/spram.c index d5d96214cce50d..71c7e5e27567fd 100644 --- a/arch/mips/kernel/spram.c +++ b/arch/mips/kernel/spram.c @@ -12,6 +12,7 @@ #include #include #include +#include /* * These definitions are correct for the 24K/34K/74K SPRAM sample diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index ae93a607ddf7ed..1bfc34a2e5b328 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c @@ -39,6 +39,7 @@ #include #include #include +#include #include /* diff --git a/arch/mips/kernel/syscalls/syscall_n32.tbl b/arch/mips/kernel/syscalls/syscall_n32.tbl index a842b41c8e064c..83cfc9eb6b88e6 100644 --- a/arch/mips/kernel/syscalls/syscall_n32.tbl +++ b/arch/mips/kernel/syscalls/syscall_n32.tbl @@ -395,3 +395,8 @@ 454 n32 futex_wake sys_futex_wake 455 n32 futex_wait sys_futex_wait 456 n32 futex_requeue sys_futex_requeue +457 n32 statmount sys_statmount +458 n32 listmount sys_listmount +459 n32 lsm_get_self_attr sys_lsm_get_self_attr +460 n32 lsm_set_self_attr sys_lsm_set_self_attr +461 n32 lsm_list_modules sys_lsm_list_modules diff --git a/arch/mips/kernel/syscalls/syscall_n64.tbl b/arch/mips/kernel/syscalls/syscall_n64.tbl index 116ff501bf9263..532b855df58957 100644 --- a/arch/mips/kernel/syscalls/syscall_n64.tbl +++ b/arch/mips/kernel/syscalls/syscall_n64.tbl @@ -371,3 +371,8 @@ 454 n64 futex_wake sys_futex_wake 455 n64 futex_wait sys_futex_wait 456 n64 futex_requeue sys_futex_requeue +457 n64 statmount sys_statmount +458 n64 listmount sys_listmount +459 n64 lsm_get_self_attr sys_lsm_get_self_attr +460 n64 lsm_set_self_attr sys_lsm_set_self_attr +461 n64 lsm_list_modules sys_lsm_list_modules diff --git a/arch/mips/kernel/syscalls/syscall_o32.tbl b/arch/mips/kernel/syscalls/syscall_o32.tbl index 525cc54bc63bf7..f45c9530ea93a1 100644 --- a/arch/mips/kernel/syscalls/syscall_o32.tbl +++ b/arch/mips/kernel/syscalls/syscall_o32.tbl @@ -444,3 +444,8 @@ 454 o32 futex_wake sys_futex_wake 455 o32 futex_wait sys_futex_wait 456 o32 futex_requeue sys_futex_requeue +457 o32 statmount sys_statmount +458 o32 listmount sys_listmount +459 o32 lsm_get_self_attr sys_lsm_get_self_attr +460 o32 lsm_set_self_attr sys_lsm_set_self_attr +461 o32 lsm_list_modules sys_lsm_list_modules diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 246c6a6b02614c..a1c1cb5de91321 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -2007,7 +2007,13 @@ unsigned long vi_handlers[64]; void reserve_exception_space(phys_addr_t addr, unsigned long size) { - memblock_reserve(addr, size); + /* + * reserve exception space on CPUs other than CPU0 + * is too late, since memblock is unavailable when APs + * up + */ + if (smp_processor_id() == 0) + memblock_reserve(addr, size); } void __init *set_except_vector(int n, void *addr) @@ -2055,110 +2061,71 @@ static void do_default_vi(void) panic("Caught unexpected vectored interrupt."); } -static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs) +void *set_vi_handler(int n, vi_handler_t addr) { + extern const u8 except_vec_vi[]; + extern const u8 except_vec_vi_ori[], except_vec_vi_end[]; + extern const u8 rollback_except_vec_vi[]; unsigned long handler; unsigned long old_handler = vi_handlers[n]; int srssets = current_cpu_data.srsets; u16 *h; unsigned char *b; + const u8 *vec_start; + int ori_offset; + int handler_len; BUG_ON(!cpu_has_veic && !cpu_has_vint); if (addr == NULL) { handler = (unsigned long) do_default_vi; - srs = 0; } else handler = (unsigned long) addr; vi_handlers[n] = handler; b = (unsigned char *)(ebase + 0x200 + n*VECTORSPACING); - if (srs >= srssets) - panic("Shadow register set %d not supported", srs); - if (cpu_has_veic) { if (board_bind_eic_interrupt) - board_bind_eic_interrupt(n, srs); + board_bind_eic_interrupt(n, 0); } else if (cpu_has_vint) { /* SRSMap is only defined if shadow sets are implemented */ if (srssets > 1) - change_c0_srsmap(0xf << n*4, srs << n*4); + change_c0_srsmap(0xf << n*4, 0 << n*4); } - if (srs == 0) { - /* - * If no shadow set is selected then use the default handler - * that does normal register saving and standard interrupt exit - */ - extern const u8 except_vec_vi[], except_vec_vi_lui[]; - extern const u8 except_vec_vi_ori[], except_vec_vi_end[]; - extern const u8 rollback_except_vec_vi[]; - const u8 *vec_start = using_rollback_handler() ? - rollback_except_vec_vi : except_vec_vi; + vec_start = using_rollback_handler() ? rollback_except_vec_vi : + except_vec_vi; #if defined(CONFIG_CPU_MICROMIPS) || defined(CONFIG_CPU_BIG_ENDIAN) - const int lui_offset = except_vec_vi_lui - vec_start + 2; - const int ori_offset = except_vec_vi_ori - vec_start + 2; + ori_offset = except_vec_vi_ori - vec_start + 2; #else - const int lui_offset = except_vec_vi_lui - vec_start; - const int ori_offset = except_vec_vi_ori - vec_start; + ori_offset = except_vec_vi_ori - vec_start; #endif - const int handler_len = except_vec_vi_end - vec_start; + handler_len = except_vec_vi_end - vec_start; - if (handler_len > VECTORSPACING) { - /* - * Sigh... panicing won't help as the console - * is probably not configured :( - */ - panic("VECTORSPACING too small"); - } - - set_handler(((unsigned long)b - ebase), vec_start, -#ifdef CONFIG_CPU_MICROMIPS - (handler_len - 1)); -#else - handler_len); -#endif - h = (u16 *)(b + lui_offset); - *h = (handler >> 16) & 0xffff; - h = (u16 *)(b + ori_offset); - *h = (handler & 0xffff); - local_flush_icache_range((unsigned long)b, - (unsigned long)(b+handler_len)); - } - else { + if (handler_len > VECTORSPACING) { /* - * In other cases jump directly to the interrupt handler. It - * is the handler's responsibility to save registers if required - * (eg hi/lo) and return from the exception using "eret". + * Sigh... panicing won't help as the console + * is probably not configured :( */ - u32 insn; + panic("VECTORSPACING too small"); + } - h = (u16 *)b; - /* j handler */ + set_handler(((unsigned long)b - ebase), vec_start, #ifdef CONFIG_CPU_MICROMIPS - insn = 0xd4000000 | (((u32)handler & 0x07ffffff) >> 1); + (handler_len - 1)); #else - insn = 0x08000000 | (((u32)handler & 0x0fffffff) >> 2); + handler_len); #endif - h[0] = (insn >> 16) & 0xffff; - h[1] = insn & 0xffff; - h[2] = 0; - h[3] = 0; - local_flush_icache_range((unsigned long)b, - (unsigned long)(b+8)); - } + /* insert offset into vi_handlers[] */ + h = (u16 *)(b + ori_offset); + *h = n * sizeof(handler); + local_flush_icache_range((unsigned long)b, + (unsigned long)(b+handler_len)); return (void *)old_handler; } -void *set_vi_handler(int n, vi_handler_t addr) -{ - return set_vi_srs_handler(n, addr, 0); -} - -extern void tlb_init(void); - /* * Timer interrupt */ @@ -2418,7 +2385,7 @@ void __init trap_init(void) set_except_vector(i, handle_reserved); /* - * Copy the EJTAG debug exception vector handler code to it's final + * Copy the EJTAG debug exception vector handler code to its final * destination. */ if (cpu_has_ejtag && board_ejtag_handler_setup) diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index f4cf94e92ec3ab..db652c99b72e32 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c @@ -91,6 +91,7 @@ #include #include #include +#include #include #include "access-helper.h" diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c index e9a0cfd02ae202..737d0d4fdcd351 100644 --- a/arch/mips/kernel/vpe.c +++ b/arch/mips/kernel/vpe.c @@ -6,9 +6,9 @@ * Copyright (C) 2004, 2005 MIPS Technologies, Inc. All rights reserved. * Copyright (C) 2013 Imagination Technologies Ltd. * - * VPE spport module for loading a MIPS SP program into VPE1. The SP + * VPE support module for loading a MIPS SP program into VPE1. The SP * environment is rather simple since there are no TLBs. It needs - * to be relocatable (or partiall linked). Initialize your stack in + * to be relocatable (or partially linked). Initialize your stack in * the startup-code. The loader looks for the symbol __start and sets * up the execution to resume from there. To load and run, simply do * a cat SP 'binary' to the /dev/vpe1 device. diff --git a/arch/mips/kvm/Kconfig b/arch/mips/kvm/Kconfig index a8cdba75f98dde..18e7a17d51158e 100644 --- a/arch/mips/kvm/Kconfig +++ b/arch/mips/kvm/Kconfig @@ -20,13 +20,11 @@ config KVM depends on HAVE_KVM depends on MIPS_FP_SUPPORT select EXPORT_UASM - select PREEMPT_NOTIFIERS + select KVM_COMMON select KVM_GENERIC_DIRTYLOG_READ_PROTECT - select HAVE_KVM_EVENTFD select HAVE_KVM_VCPU_ASYNC_IOCTL select KVM_MMIO - select MMU_NOTIFIER - select INTERVAL_TREE + select KVM_GENERIC_MMU_NOTIFIER select KVM_GENERIC_HARDWARE_ENABLING help Support for hosting Guest kernels. diff --git a/arch/mips/kvm/emulate.c b/arch/mips/kvm/emulate.c index e64372b8f66afc..0feec52222fb97 100644 --- a/arch/mips/kvm/emulate.c +++ b/arch/mips/kvm/emulate.c @@ -531,7 +531,7 @@ static void kvm_mips_resume_hrtimer(struct kvm_vcpu *vcpu, * to be used for a period of time, but the exact ktime corresponding to the * final Count that must be restored is not known. * - * It is gauranteed that a timer interrupt immediately after restore will be + * It is guaranteed that a timer interrupt immediately after restore will be * handled, but not if CP0_Compare is exactly at @count. That case should * already be handled when the hardware timer state is saved. * diff --git a/arch/mips/lantiq/prom.c b/arch/mips/lantiq/prom.c index a3cf293658581e..0c45767eacf674 100644 --- a/arch/mips/lantiq/prom.c +++ b/arch/mips/lantiq/prom.c @@ -108,10 +108,9 @@ void __init prom_init(void) prom_init_cmdline(); #if defined(CONFIG_MIPS_MT_SMP) - if (cpu_has_mipsmt) { - lantiq_smp_ops = vsmp_smp_ops; + lantiq_smp_ops = vsmp_smp_ops; + if (cpu_has_mipsmt) lantiq_smp_ops.init_secondary = lantiq_init_secondary; - register_smp_ops(&lantiq_smp_ops); - } + register_smp_ops(&lantiq_smp_ops); #endif } diff --git a/arch/mips/loongson2ef/common/platform.c b/arch/mips/loongson2ef/common/platform.c index 0084820cffaa8d..b10300a527af24 100644 --- a/arch/mips/loongson2ef/common/platform.c +++ b/arch/mips/loongson2ef/common/platform.c @@ -17,7 +17,7 @@ static int __init loongson2_cpufreq_init(void) { struct cpuinfo_mips *c = ¤t_cpu_data; - /* Only 2F revision and it's successors support CPUFreq */ + /* Only 2F revision and its successors support CPUFreq */ if ((c->processor_id & PRID_REV_MASK) >= PRID_REV_LOONGSON2F) return platform_device_register(&loongson2_cpufreq_device); diff --git a/arch/mips/loongson64/init.c b/arch/mips/loongson64/init.c index f25caa6aa9d306..553142c1f14fe2 100644 --- a/arch/mips/loongson64/init.c +++ b/arch/mips/loongson64/init.c @@ -103,6 +103,9 @@ void __init szmem(unsigned int node) if (loongson_sysconf.vgabios_addr) memblock_reserve(virt_to_phys((void *)loongson_sysconf.vgabios_addr), SZ_256K); + /* set nid for reserved memory */ + memblock_set_node((u64)node << 44, (u64)(node + 1) << 44, + &memblock.reserved, node); } #ifndef CONFIG_NUMA diff --git a/arch/mips/loongson64/numa.c b/arch/mips/loongson64/numa.c index 8f61e93c0c5bcf..68dafd6d3e2571 100644 --- a/arch/mips/loongson64/numa.c +++ b/arch/mips/loongson64/numa.c @@ -132,6 +132,8 @@ static void __init node_mem_init(unsigned int node) /* Reserve pfn range 0~node[0]->node_start_pfn */ memblock_reserve(0, PAGE_SIZE * start_pfn); + /* set nid for reserved memory on node 0 */ + memblock_set_node(0, 1ULL << 44, &memblock.reserved, 0); } } diff --git a/arch/mips/loongson64/smp.c b/arch/mips/loongson64/smp.c index 498bdc1bb0ede8..5a990cdef91a6f 100644 --- a/arch/mips/loongson64/smp.c +++ b/arch/mips/loongson64/smp.c @@ -516,7 +516,7 @@ static void __init loongson3_prepare_cpus(unsigned int max_cpus) } /* - * Setup the PC, SP, and GP of a secondary processor and start it runing! + * Setup the PC, SP, and GP of a secondary processor and start it running! */ static int loongson3_boot_secondary(int cpu, struct task_struct *idle) { diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index 187d1c16361cfa..10413b6f6662bc 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -1485,10 +1485,6 @@ static void loongson3_sc_init(void) return; } -extern int r5k_sc_init(void); -extern int rm7k_sc_init(void); -extern int mips_sc_init(void); - static void setup_scache(void) { struct cpuinfo_mips *c = ¤t_cpu_data; @@ -1654,7 +1650,7 @@ static void coherency_setup(void) /* * c0_status.cu=0 specifies that updates by the sc instruction use - * the coherency mode specified by the TLB; 1 means cachable + * the coherency mode specified by the TLB; 1 means cacheable * coherent update on write will be used. Not all processors have * this bit and; some wire it to zero, others like Toshiba had the * silly idea of putting something else there ... @@ -1828,7 +1824,7 @@ static struct notifier_block r4k_cache_pm_notifier_block = { .notifier_call = r4k_cache_pm_notifier, }; -int __init r4k_cache_init_pm(void) +static int __init r4k_cache_init_pm(void) { return cpu_pm_register_notifier(&r4k_cache_pm_notifier_block); } diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c index 7f830634dbe7db..df1ced4fc3b506 100644 --- a/arch/mips/mm/cache.c +++ b/arch/mips/mm/cache.c @@ -205,22 +205,13 @@ static inline void setup_protection_map(void) void cpu_cache_init(void) { - if (cpu_has_3k_cache) { - extern void __weak r3k_cache_init(void); - + if (IS_ENABLED(CONFIG_CPU_R3000) && cpu_has_3k_cache) r3k_cache_init(); - } - if (cpu_has_4k_cache) { - extern void __weak r4k_cache_init(void); - + if (IS_ENABLED(CONFIG_CPU_R4K_CACHE_TLB) && cpu_has_4k_cache) r4k_cache_init(); - } - - if (cpu_has_octeon_cache) { - extern void __weak octeon_cache_init(void); + if (IS_ENABLED(CONFIG_CPU_CAVIUM_OCTEON) && cpu_has_octeon_cache) octeon_cache_init(); - } setup_protection_map(); } diff --git a/arch/mips/mm/cex-gen.S b/arch/mips/mm/cex-gen.S index 45dff5cd4b8e7a..e528583d13311d 100644 --- a/arch/mips/mm/cex-gen.S +++ b/arch/mips/mm/cex-gen.S @@ -25,7 +25,7 @@ * This is a very bad place to be. Our cache error * detection has triggered. If we have write-back data * in the cache, we may not be able to recover. As a - * first-order desperate measure, turn off KSEG0 cacheing. + * first-order desperate measure, turn off KSEG0 caching. */ mfc0 k0,CP0_CONFIG li k1,~CONF_CM_CMASK diff --git a/arch/mips/mm/dma-noncoherent.c b/arch/mips/mm/dma-noncoherent.c index 3c4fc97b9f394b..0f3cec663a12cd 100644 --- a/arch/mips/mm/dma-noncoherent.c +++ b/arch/mips/mm/dma-noncoherent.c @@ -138,7 +138,7 @@ void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size, #ifdef CONFIG_ARCH_HAS_SETUP_DMA_OPS void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, - const struct iommu_ops *iommu, bool coherent) + bool coherent) { dev->dma_coherent = coherent; } diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c index d7878208bd3fa9..aaa9a242ebbabc 100644 --- a/arch/mips/mm/fault.c +++ b/arch/mips/mm/fault.c @@ -26,6 +26,7 @@ #include #include #include /* For VMALLOC_END */ +#include #include int show_unhandled_signals = 1; diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index 5dcb525a899543..39f129205b0c30 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -421,8 +422,17 @@ void __init paging_init(void) " %ldk highmem ignored\n", (highend_pfn - max_low_pfn) << (PAGE_SHIFT - 10)); max_zone_pfns[ZONE_HIGHMEM] = max_low_pfn; + + max_mapnr = max_low_pfn; + } else if (highend_pfn) { + max_mapnr = highend_pfn; + } else { + max_mapnr = max_low_pfn; } +#else + max_mapnr = max_low_pfn; #endif + high_memory = (void *) __va(max_low_pfn << PAGE_SHIFT); free_area_init(max_zone_pfns); } @@ -458,13 +468,6 @@ void __init mem_init(void) */ BUILD_BUG_ON(IS_ENABLED(CONFIG_32BIT) && (PFN_PTE_SHIFT > PAGE_SHIFT)); -#ifdef CONFIG_HIGHMEM - max_mapnr = highend_pfn ? highend_pfn : max_low_pfn; -#else - max_mapnr = max_low_pfn; -#endif - high_memory = (void *) __va(max_low_pfn << PAGE_SHIFT); - maar_init(); memblock_free_all(); setup_zero_pages(); /* Setup zeroed pages. */ diff --git a/arch/mips/mm/ioremap.c b/arch/mips/mm/ioremap.c index b6dad2fd5575d7..d8243d61ef3252 100644 --- a/arch/mips/mm/ioremap.c +++ b/arch/mips/mm/ioremap.c @@ -72,6 +72,10 @@ void __iomem *ioremap_prot(phys_addr_t phys_addr, unsigned long size, flags == _CACHE_UNCACHED) return (void __iomem *) CKSEG1ADDR(phys_addr); + /* Early remaps should use the unmapped regions til' VM is available */ + if (WARN_ON_ONCE(!slab_is_available())) + return NULL; + /* * Don't allow anybody to remap RAM that may be allocated by the page * allocator, since that could lead to races & data clobbering. diff --git a/arch/mips/mm/pgtable-64.c b/arch/mips/mm/pgtable-64.c index c76d21f7dffbb1..1e544827dea9dc 100644 --- a/arch/mips/mm/pgtable-64.c +++ b/arch/mips/mm/pgtable-64.c @@ -89,6 +89,7 @@ void pud_init(void *addr) } #endif +#ifdef CONFIG_TRANSPARENT_HUGEPAGE pmd_t mk_pmd(struct page *page, pgprot_t prot) { pmd_t pmd; @@ -103,6 +104,7 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr, { *pmdp = pmd; } +#endif void __init pagetable_init(void) { diff --git a/arch/mips/mm/tlb-r3k.c b/arch/mips/mm/tlb-r3k.c index 53dfa2b9316ba9..173f7b36033bd2 100644 --- a/arch/mips/mm/tlb-r3k.c +++ b/arch/mips/mm/tlb-r3k.c @@ -23,11 +23,11 @@ #include #include #include +#include +#include #undef DEBUG_TLB -extern void build_tlb_refill_handler(void); - /* CP0 hazard avoidance. */ #define BARRIER \ __asm__ __volatile__( \ @@ -183,7 +183,7 @@ void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte) int idx, pid; /* - * Handle debugger faulting in for debugee. + * Handle debugger faulting in for debuggee. */ if (current->active_mm != vma->vm_mm) return; diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c index 93c2d695588a1c..4106084e57d728 100644 --- a/arch/mips/mm/tlb-r4k.c +++ b/arch/mips/mm/tlb-r4k.c @@ -22,9 +22,9 @@ #include #include #include +#include #include - -extern void build_tlb_refill_handler(void); +#include /* * LOONGSON-2 has a 4 entry itlb which is a subset of jtlb, LOONGSON-3 has @@ -301,7 +301,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte) int idx, pid; /* - * Handle debugger faulting in for debugee. + * Handle debugger faulting in for debuggee. */ if (current->active_mm != vma->vm_mm) return; @@ -458,6 +458,7 @@ EXPORT_SYMBOL(has_transparent_hugepage); int temp_tlb_entry; +#ifndef CONFIG_64BIT __init int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1, unsigned long entryhi, unsigned long pagemask) { @@ -496,6 +497,7 @@ out: local_irq_restore(flags); return ret; } +#endif static int ntlb; static int __init set_ntlb(char *str) diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index b4e1c783e61779..4017fa0e2f68d2 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c @@ -789,7 +789,7 @@ void build_get_pmde64(u32 **p, struct uasm_label **l, struct uasm_reloc **r, if (check_for_high_segbits) { /* - * The kernel currently implicitely assumes that the + * The kernel currently implicitly assumes that the * MIPS SEGBITS parameter for the processor is * (PGDIR_SHIFT+PGDIR_BITS) or less, and will never * allocate virtual addresses outside the maximum @@ -1715,7 +1715,7 @@ iPTE_SW(u32 **p, struct uasm_reloc **r, unsigned int pte, unsigned int ptr, /* * Check if PTE is present, if not then jump to LABEL. PTR points to * the page table where this PTE is located, PTE will be re-loaded - * with it's original value. + * with its original value. */ static void build_pte_present(u32 **p, struct uasm_reloc **r, diff --git a/arch/mips/net/bpf_jit_comp32.c b/arch/mips/net/bpf_jit_comp32.c index ace5db3fbd171f..40a878b672f5d3 100644 --- a/arch/mips/net/bpf_jit_comp32.c +++ b/arch/mips/net/bpf_jit_comp32.c @@ -95,7 +95,7 @@ /* * Mapping of 64-bit eBPF registers to 32-bit native MIPS registers. * - * 1) Native register pairs are ordered according to CPU endiannes, following + * 1) Native register pairs are ordered according to CPU endianness, following * the MIPS convention for passing 64-bit arguments and return values. * 2) The eBPF return value, arguments and callee-saved registers are mapped * to their native MIPS equivalents. diff --git a/arch/mips/pci/ops-loongson2.c b/arch/mips/pci/ops-loongson2.c index 0d1b36ba1c21c9..068113f5c49d48 100644 --- a/arch/mips/pci/ops-loongson2.c +++ b/arch/mips/pci/ops-loongson2.c @@ -49,7 +49,7 @@ static int loongson_pcibios_config_access(unsigned char access_type, */ #ifdef CONFIG_CS5536 /* cs5536_pci_conf_read4/write4() will call _rdmsr/_wrmsr() to - * access the regsters PCI_MSR_ADDR, PCI_MSR_DATA_LO, + * access the registers PCI_MSR_ADDR, PCI_MSR_DATA_LO, * PCI_MSR_DATA_HI, which is bigger than PCI_MSR_CTRL, so, it * will not go this branch, but the others. so, no calling dead * loop here. diff --git a/arch/mips/pci/pci-alchemy.c b/arch/mips/pci/pci-alchemy.c index 1c722dd0c1302d..58625d1b64658e 100644 --- a/arch/mips/pci/pci-alchemy.c +++ b/arch/mips/pci/pci-alchemy.c @@ -453,7 +453,7 @@ static int alchemy_pci_probe(struct platform_device *pdev) /* we can't ioremap the entire pci config space because it's too large, * nor can we dynamically ioremap it because some drivers use the - * PCI config routines from within atomic contex and that becomes a + * PCI config routines from within atomic context and that becomes a * problem in get_vm_area(). Instead we use one wired TLB entry to * handle all config accesses for all busses. */ diff --git a/arch/mips/pci/pci-ar2315.c b/arch/mips/pci/pci-ar2315.c index e17d862cfa4c6a..a925842ee1256f 100644 --- a/arch/mips/pci/pci-ar2315.c +++ b/arch/mips/pci/pci-ar2315.c @@ -16,7 +16,7 @@ * the CFG_SEL bit in the PCI_MISC_CONFIG register. * * Devices on the bus can perform DMA requests via chip BAR1. PCI host - * controller BARs are programmend as if an external device is programmed. + * controller BARs are programmed as if an external device is programmed. * Which means that during configuration, IDSEL pin of the chip should be * asserted. * diff --git a/arch/mips/pci/pci-ip27.c b/arch/mips/pci/pci-ip27.c index d85cbf84e41c3e..973faea61cad54 100644 --- a/arch/mips/pci/pci-ip27.c +++ b/arch/mips/pci/pci-ip27.c @@ -7,6 +7,9 @@ * Copyright (C) 1999, 2000, 04 Ralf Baechle (ralf@linux-mips.org) * Copyright (C) 1999, 2000 Silicon Graphics, Inc. */ + +#include + #include #include #include diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c index 80f7293166bb76..68a8cefed420bf 100644 --- a/arch/mips/pci/pci-lantiq.c +++ b/arch/mips/pci/pci-lantiq.c @@ -152,7 +152,7 @@ static int ltq_pci_startup(struct platform_device *pdev) temp_buffer &= ~0xf0000; /* enable internal arbiter */ temp_buffer |= (1 << INTERNAL_ARB_ENABLE_BIT); - /* enable internal PCI master reqest */ + /* enable internal PCI master request */ temp_buffer &= (~(3 << PCI_MASTER0_REQ_MASK_2BITS)); /* enable EBU request */ diff --git a/arch/mips/pci/pci-octeon.c b/arch/mips/pci/pci-octeon.c index d19d9d45630921..36d12cea351223 100644 --- a/arch/mips/pci/pci-octeon.c +++ b/arch/mips/pci/pci-octeon.c @@ -376,7 +376,7 @@ static void octeon_pci_initialize(void) ctl_status.s.timer = 1; cvmx_write_csr(CVMX_NPI_CTL_STATUS, ctl_status.u64); - /* Deassert PCI reset and advertize PCX Host Mode Device Capability + /* Deassert PCI reset and advertise PCX Host Mode Device Capability (64b) */ cvmx_write_csr(CVMX_CIU_SOFT_PRST, 0x4); cvmx_read_csr(CVMX_CIU_SOFT_PRST); diff --git a/arch/mips/pci/pci-xtalk-bridge.c b/arch/mips/pci/pci-xtalk-bridge.c index 68d5211afea8b4..45ddbaa6c12379 100644 --- a/arch/mips/pci/pci-xtalk-bridge.c +++ b/arch/mips/pci/pci-xtalk-bridge.c @@ -114,7 +114,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, * * The function is complicated by the ultimate brokenness of the IOC3 chip * which is used in SGI systems. The IOC3 can only handle 32-bit PCI - * accesses and does only decode parts of it's address space. + * accesses and does only decode parts of its address space. */ static int pci_conf0_read_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) diff --git a/arch/mips/pci/pcie-octeon.c b/arch/mips/pci/pcie-octeon.c index c9edd3fb380df5..2583e318e8c6b3 100644 --- a/arch/mips/pci/pcie-octeon.c +++ b/arch/mips/pci/pcie-octeon.c @@ -1037,7 +1037,7 @@ retry: in_fif_p_count = dbg_data.s.data & 0xff; } while (in_fif_p_count != ((old_in_fif_p_count+1) & 0xff)); - /* Update in_fif_p_count for it's offset with respect to out_p_count */ + /* Update in_fif_p_count for its offset with respect to out_p_count */ in_fif_p_count = (in_fif_p_count + in_p_offset) & 0xff; /* Read the OUT_P_COUNT from the debug select */ diff --git a/arch/mips/power/cpu.c b/arch/mips/power/cpu.c index a15e29dfc7b38f..d8ef7778e5352a 100644 --- a/arch/mips/power/cpu.c +++ b/arch/mips/power/cpu.c @@ -6,6 +6,7 @@ * Author: Hu Hongbing * Wu Zhangjin */ +#include #include #include #include diff --git a/arch/mips/power/hibernate.c b/arch/mips/power/hibernate.c index 94ab17c3c49d2c..192879e76c8575 100644 --- a/arch/mips/power/hibernate.c +++ b/arch/mips/power/hibernate.c @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 +#include #include extern int restore_image(void); diff --git a/arch/mips/ralink/mt7621.c b/arch/mips/ralink/mt7621.c index 137781d0bd0a12..5a9fd3fe41d7c5 100644 --- a/arch/mips/ralink/mt7621.c +++ b/arch/mips/ralink/mt7621.c @@ -175,7 +175,7 @@ void __init prom_soc_init(struct ralink_soc_info *soc_info) * mips_cm_probe() wipes out bootloader * config for CM regions and we have to configure them * again. This SoC cannot talk to pamlbus devices - * witout proper iocu region set up. + * without proper iocu region set up. * * FIXME: it would be better to do this with values * from DT, but we need this very early because diff --git a/arch/mips/sgi-ip27/Makefile b/arch/mips/sgi-ip27/Makefile index 27c14ede191eb7..9877fcc512b157 100644 --- a/arch/mips/sgi-ip27/Makefile +++ b/arch/mips/sgi-ip27/Makefile @@ -5,7 +5,7 @@ obj-y := ip27-berr.o ip27-irq.o ip27-init.o ip27-klconfig.o \ ip27-klnuma.o ip27-memory.o ip27-nmi.o ip27-reset.o ip27-timer.o \ - ip27-hubio.o ip27-xtalk.o + ip27-xtalk.o obj-$(CONFIG_EARLY_PRINTK) += ip27-console.o obj-$(CONFIG_SMP) += ip27-smp.o diff --git a/arch/mips/sgi-ip27/ip27-berr.c b/arch/mips/sgi-ip27/ip27-berr.c index 923a63a51cda39..9eb497cb5d525c 100644 --- a/arch/mips/sgi-ip27/ip27-berr.c +++ b/arch/mips/sgi-ip27/ip27-berr.c @@ -22,6 +22,8 @@ #include #include +#include "ip27-common.h" + static void dump_hub_information(unsigned long errst0, unsigned long errst1) { static char *err_type[2][8] = { @@ -57,7 +59,7 @@ static void dump_hub_information(unsigned long errst0, unsigned long errst1) [st0.pi_stat0_fmt.s0_err_type] ? : "invalid"); } -int ip27_be_handler(struct pt_regs *regs, int is_fixup) +static int ip27_be_handler(struct pt_regs *regs, int is_fixup) { unsigned long errst0, errst1; int data = regs->cp0_cause & 4; diff --git a/arch/mips/sgi-ip27/ip27-common.h b/arch/mips/sgi-ip27/ip27-common.h index ed008a08464c20..a0059fa1393453 100644 --- a/arch/mips/sgi-ip27/ip27-common.h +++ b/arch/mips/sgi-ip27/ip27-common.h @@ -10,6 +10,7 @@ extern void hub_rt_clock_event_init(void); extern void hub_rtc_init(nasid_t nasid); extern void install_cpu_nmi_handler(int slice); extern void install_ipi(void); +extern void ip27_be_init(void); extern void ip27_reboot_setup(void); extern const struct plat_smp_ops ip27_smp_ops; extern unsigned long node_getfirstfree(nasid_t nasid); @@ -17,4 +18,5 @@ extern void per_cpu_init(void); extern void replicate_kernel_text(void); extern void setup_replication_mask(void); + #endif /* __IP27_COMMON_H */ diff --git a/arch/mips/sgi-ip27/ip27-hubio.c b/arch/mips/sgi-ip27/ip27-hubio.c deleted file mode 100644 index 8352eb6403b437..00000000000000 --- a/arch/mips/sgi-ip27/ip27-hubio.c +++ /dev/null @@ -1,185 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc. - * Copyright (C) 2004 Christoph Hellwig. - * - * Support functions for the HUB ASIC - mostly PIO mapping related. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - - -static int force_fire_and_forget = 1; - -/** - * hub_pio_map - establish a HUB PIO mapping - * - * @hub: hub to perform PIO mapping on - * @widget: widget ID to perform PIO mapping for - * @xtalk_addr: xtalk_address that needs to be mapped - * @size: size of the PIO mapping - * - **/ -unsigned long hub_pio_map(nasid_t nasid, xwidgetnum_t widget, - unsigned long xtalk_addr, size_t size) -{ - unsigned i; - - /* use small-window mapping if possible */ - if ((xtalk_addr % SWIN_SIZE) + size <= SWIN_SIZE) - return NODE_SWIN_BASE(nasid, widget) + (xtalk_addr % SWIN_SIZE); - - if ((xtalk_addr % BWIN_SIZE) + size > BWIN_SIZE) { - printk(KERN_WARNING "PIO mapping at hub %d widget %d addr 0x%lx" - " too big (%ld)\n", - nasid, widget, xtalk_addr, size); - return 0; - } - - xtalk_addr &= ~(BWIN_SIZE-1); - for (i = 0; i < HUB_NUM_BIG_WINDOW; i++) { - if (test_and_set_bit(i, hub_data(nasid)->h_bigwin_used)) - continue; - - /* - * The code below does a PIO write to setup an ITTE entry. - * - * We need to prevent other CPUs from seeing our updated - * memory shadow of the ITTE (in the piomap) until the ITTE - * entry is actually set up; otherwise, another CPU might - * attempt a PIO prematurely. - * - * Also, the only way we can know that an entry has been - * received by the hub and can be used by future PIO reads/ - * writes is by reading back the ITTE entry after writing it. - * - * For these two reasons, we PIO read back the ITTE entry - * after we write it. - */ - IIO_ITTE_PUT(nasid, i, HUB_PIO_MAP_TO_MEM, widget, xtalk_addr); - __raw_readq(IIO_ITTE_GET(nasid, i)); - - return NODE_BWIN_BASE(nasid, widget) + (xtalk_addr % BWIN_SIZE); - } - - printk(KERN_WARNING "unable to establish PIO mapping for at" - " hub %d widget %d addr 0x%lx\n", - nasid, widget, xtalk_addr); - return 0; -} - - -/* - * hub_setup_prb(nasid, prbnum, credits, conveyor) - * - * Put a PRB into fire-and-forget mode if conveyor isn't set. Otherwise, - * put it into conveyor belt mode with the specified number of credits. - */ -static void hub_setup_prb(nasid_t nasid, int prbnum, int credits) -{ - union iprb_u prb; - int prb_offset; - - /* - * Get the current register value. - */ - prb_offset = IIO_IOPRB(prbnum); - prb.iprb_regval = REMOTE_HUB_L(nasid, prb_offset); - - /* - * Clear out some fields. - */ - prb.iprb_ovflow = 1; - prb.iprb_bnakctr = 0; - prb.iprb_anakctr = 0; - - /* - * Enable or disable fire-and-forget mode. - */ - prb.iprb_ff = force_fire_and_forget ? 1 : 0; - - /* - * Set the appropriate number of PIO credits for the widget. - */ - prb.iprb_xtalkctr = credits; - - /* - * Store the new value to the register. - */ - REMOTE_HUB_S(nasid, prb_offset, prb.iprb_regval); -} - -/** - * hub_set_piomode - set pio mode for a given hub - * - * @nasid: physical node ID for the hub in question - * - * Put the hub into either "PIO conveyor belt" mode or "fire-and-forget" mode. - * To do this, we have to make absolutely sure that no PIOs are in progress - * so we turn off access to all widgets for the duration of the function. - * - * XXX - This code should really check what kind of widget we're talking - * to. Bridges can only handle three requests, but XG will do more. - * How many can crossbow handle to widget 0? We're assuming 1. - * - * XXX - There is a bug in the crossbow that link reset PIOs do not - * return write responses. The easiest solution to this problem is to - * leave widget 0 (xbow) in fire-and-forget mode at all times. This - * only affects pio's to xbow registers, which should be rare. - **/ -static void hub_set_piomode(nasid_t nasid) -{ - u64 ii_iowa; - union hubii_wcr_u ii_wcr; - unsigned i; - - ii_iowa = REMOTE_HUB_L(nasid, IIO_OUTWIDGET_ACCESS); - REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, 0); - - ii_wcr.wcr_reg_value = REMOTE_HUB_L(nasid, IIO_WCR); - - if (ii_wcr.iwcr_dir_con) { - /* - * Assume a bridge here. - */ - hub_setup_prb(nasid, 0, 3); - } else { - /* - * Assume a crossbow here. - */ - hub_setup_prb(nasid, 0, 1); - } - - /* - * XXX - Here's where we should take the widget type into - * when account assigning credits. - */ - for (i = HUB_WIDGET_ID_MIN; i <= HUB_WIDGET_ID_MAX; i++) - hub_setup_prb(nasid, i, 3); - - REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, ii_iowa); -} - -/* - * hub_pio_init - PIO-related hub initialization - * - * @hub: hubinfo structure for our hub - */ -void hub_pio_init(nasid_t nasid) -{ - unsigned i; - - /* initialize big window piomaps for this hub */ - bitmap_zero(hub_data(nasid)->h_bigwin_used, HUB_NUM_BIG_WINDOW); - for (i = 0; i < HUB_NUM_BIG_WINDOW; i++) - IIO_ITTE_DISABLE(nasid, i); - - hub_set_piomode(nasid); -} diff --git a/arch/mips/sgi-ip27/ip27-irq.c b/arch/mips/sgi-ip27/ip27-irq.c index a0dd3bd2b81b35..8f5299b269e7e7 100644 --- a/arch/mips/sgi-ip27/ip27-irq.c +++ b/arch/mips/sgi-ip27/ip27-irq.c @@ -23,6 +23,8 @@ #include #include +#include "ip27-common.h" + struct hub_irq_data { u64 *irq_mask[2]; cpuid_t cpu; diff --git a/arch/mips/sgi-ip27/ip27-memory.c b/arch/mips/sgi-ip27/ip27-memory.c index f79c4839371661..b8ca94cfb4fef3 100644 --- a/arch/mips/sgi-ip27/ip27-memory.c +++ b/arch/mips/sgi-ip27/ip27-memory.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include diff --git a/arch/mips/sgi-ip27/ip27-nmi.c b/arch/mips/sgi-ip27/ip27-nmi.c index 84889b57d5ff68..fc2816398d0cf0 100644 --- a/arch/mips/sgi-ip27/ip27-nmi.c +++ b/arch/mips/sgi-ip27/ip27-nmi.c @@ -11,6 +11,8 @@ #include #include +#include "ip27-common.h" + #if 0 #define NODE_NUM_CPUS(n) CNODE_NUM_CPUS(n) #else @@ -23,16 +25,7 @@ typedef unsigned long machreg_t; static arch_spinlock_t nmi_lock = __ARCH_SPIN_LOCK_UNLOCKED; - -/* - * Let's see what else we need to do here. Set up sp, gp? - */ -void nmi_dump(void) -{ - void cont_nmi_dump(void); - - cont_nmi_dump(); -} +static void nmi_dump(void); void install_cpu_nmi_handler(int slice) { @@ -53,7 +46,7 @@ void install_cpu_nmi_handler(int slice) * into the eframe format for the node under consideration. */ -void nmi_cpu_eframe_save(nasid_t nasid, int slice) +static void nmi_cpu_eframe_save(nasid_t nasid, int slice) { struct reg_struct *nr; int i; @@ -129,7 +122,7 @@ void nmi_cpu_eframe_save(nasid_t nasid, int slice) pr_emerg("\n"); } -void nmi_dump_hub_irq(nasid_t nasid, int slice) +static void nmi_dump_hub_irq(nasid_t nasid, int slice) { u64 mask0, mask1, pend0, pend1; @@ -153,7 +146,7 @@ void nmi_dump_hub_irq(nasid_t nasid, int slice) * Copy the cpu registers which have been saved in the IP27prom format * into the eframe format for the node under consideration. */ -void nmi_node_eframe_save(nasid_t nasid) +static void nmi_node_eframe_save(nasid_t nasid) { int slice; @@ -170,8 +163,7 @@ void nmi_node_eframe_save(nasid_t nasid) /* * Save the nmi cpu registers for all cpus in the system. */ -void -nmi_eframes_save(void) +static void nmi_eframes_save(void) { nasid_t nasid; @@ -179,8 +171,7 @@ nmi_eframes_save(void) nmi_node_eframe_save(nasid); } -void -cont_nmi_dump(void) +static void nmi_dump(void) { #ifndef REAL_NMI_SIGNAL static atomic_t nmied_cpus = ATOMIC_INIT(0); diff --git a/arch/mips/sgi-ip30/ip30-console.c b/arch/mips/sgi-ip30/ip30-console.c index b91f8c4fdc7860..7c6dcf6e73f701 100644 --- a/arch/mips/sgi-ip30/ip30-console.c +++ b/arch/mips/sgi-ip30/ip30-console.c @@ -3,6 +3,7 @@ #include #include +#include static inline struct ioc3_uartregs *console_uart(void) { diff --git a/arch/mips/sgi-ip30/ip30-setup.c b/arch/mips/sgi-ip30/ip30-setup.c index 75a34684e70459..e8547636a7482a 100644 --- a/arch/mips/sgi-ip30/ip30-setup.c +++ b/arch/mips/sgi-ip30/ip30-setup.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include diff --git a/arch/mips/sgi-ip32/crime.c b/arch/mips/sgi-ip32/crime.c index a8e0c776ca6c62..b8a0e4cfa9ce88 100644 --- a/arch/mips/sgi-ip32/crime.c +++ b/arch/mips/sgi-ip32/crime.c @@ -18,6 +18,8 @@ #include #include +#include "ip32-common.h" + struct sgi_crime __iomem *crime; struct sgi_mace __iomem *mace; @@ -39,7 +41,7 @@ void __init crime_init(void) id, rev, field, (unsigned long) CRIME_BASE); } -irqreturn_t crime_memerr_intr(unsigned int irq, void *dev_id) +irqreturn_t crime_memerr_intr(int irq, void *dev_id) { unsigned long stat, addr; int fatal = 0; @@ -90,7 +92,7 @@ irqreturn_t crime_memerr_intr(unsigned int irq, void *dev_id) return IRQ_HANDLED; } -irqreturn_t crime_cpuerr_intr(unsigned int irq, void *dev_id) +irqreturn_t crime_cpuerr_intr(int irq, void *dev_id) { unsigned long stat = crime->cpu_error_stat & CRIME_CPU_ERROR_MASK; unsigned long addr = crime->cpu_error_addr & CRIME_CPU_ERROR_ADDR_MASK; diff --git a/arch/mips/sgi-ip32/ip32-berr.c b/arch/mips/sgi-ip32/ip32-berr.c index 478b63b4c808f3..7cbc27941f9283 100644 --- a/arch/mips/sgi-ip32/ip32-berr.c +++ b/arch/mips/sgi-ip32/ip32-berr.c @@ -18,6 +18,8 @@ #include #include +#include "ip32-common.h" + static int ip32_be_handler(struct pt_regs *regs, int is_fixup) { int data = regs->cp0_cause & 4; diff --git a/arch/mips/sgi-ip32/ip32-common.h b/arch/mips/sgi-ip32/ip32-common.h new file mode 100644 index 00000000000000..cfc0225b141939 --- /dev/null +++ b/arch/mips/sgi-ip32/ip32-common.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __IP32_COMMON_H +#define __IP32_COMMON_H + +#include +#include + +void __init crime_init(void); +irqreturn_t crime_memerr_intr(int irq, void *dev_id); +irqreturn_t crime_cpuerr_intr(int irq, void *dev_id); +void __init ip32_be_init(void); +void ip32_prepare_poweroff(void); + +#endif /* __IP32_COMMON_H */ diff --git a/arch/mips/sgi-ip32/ip32-irq.c b/arch/mips/sgi-ip32/ip32-irq.c index e21ea1de05e319..29d04468a06b8f 100644 --- a/arch/mips/sgi-ip32/ip32-irq.c +++ b/arch/mips/sgi-ip32/ip32-irq.c @@ -28,6 +28,8 @@ #include #include +#include "ip32-common.h" + /* issue a PIO read to make sure no PIO writes are pending */ static inline void flush_crime_bus(void) { @@ -107,10 +109,6 @@ static inline void flush_mace_bus(void) * is quite different anyway. */ -/* Some initial interrupts to set up */ -extern irqreturn_t crime_memerr_intr(int irq, void *dev_id); -extern irqreturn_t crime_cpuerr_intr(int irq, void *dev_id); - /* * This is for pure CRIME interrupts - ie not MACE. The advantage? * We get to split the register in half and do faster lookups. diff --git a/arch/mips/sgi-ip32/ip32-memory.c b/arch/mips/sgi-ip32/ip32-memory.c index 3fc8d0a0bdfa45..5fee33744f674b 100644 --- a/arch/mips/sgi-ip32/ip32-memory.c +++ b/arch/mips/sgi-ip32/ip32-memory.c @@ -15,6 +15,7 @@ #include #include #include +#include extern void crime_init(void); diff --git a/arch/mips/sgi-ip32/ip32-reset.c b/arch/mips/sgi-ip32/ip32-reset.c index 18d1c115cd534a..6bdc1421cda46c 100644 --- a/arch/mips/sgi-ip32/ip32-reset.c +++ b/arch/mips/sgi-ip32/ip32-reset.c @@ -29,6 +29,8 @@ #include #include +#include "ip32-common.h" + #define POWERDOWN_TIMEOUT 120 /* * Blink frequency during reboot grace period and when panicked. diff --git a/arch/mips/sgi-ip32/ip32-setup.c b/arch/mips/sgi-ip32/ip32-setup.c index 8019dae1721a81..aeb0805aae57ba 100644 --- a/arch/mips/sgi-ip32/ip32-setup.c +++ b/arch/mips/sgi-ip32/ip32-setup.c @@ -26,8 +26,7 @@ #include #include -extern void ip32_be_init(void); -extern void crime_init(void); +#include "ip32-common.h" #ifdef CONFIG_SGI_O2MACE_ETH /* diff --git a/arch/mips/txx9/generic/pci.c b/arch/mips/txx9/generic/pci.c index 5ae30b78d38d3b..d9249f5a632e0c 100644 --- a/arch/mips/txx9/generic/pci.c +++ b/arch/mips/txx9/generic/pci.c @@ -348,7 +348,7 @@ static void final_fixup(struct pci_dev *dev) unsigned char bist; int ret; - /* Do build-in self test */ + /* Do built-in self test */ ret = pci_read_config_byte(dev, PCI_BIST, &bist); if ((ret != PCIBIOS_SUCCESSFUL) || !(bist & PCI_BIST_CAPABLE)) return; diff --git a/arch/mips/vdso/vgettimeofday.c b/arch/mips/vdso/vgettimeofday.c index 6b83b6376a4b58..604afea3f33630 100644 --- a/arch/mips/vdso/vgettimeofday.c +++ b/arch/mips/vdso/vgettimeofday.c @@ -9,6 +9,7 @@ */ #include #include +#include #if _MIPS_SIM != _MIPS_SIM_ABI64 int __vdso_clock_gettime(clockid_t clock, diff --git a/arch/nios2/Kconfig b/arch/nios2/Kconfig index d54464021a618e..58d9565dc2c770 100644 --- a/arch/nios2/Kconfig +++ b/arch/nios2/Kconfig @@ -50,7 +50,7 @@ config ARCH_FORCE_MAX_ORDER default "10" help The kernel page allocator limits the size of maximal physically - contiguous allocations. The limit is called MAX_ORDER and it + contiguous allocations. The limit is called MAX_PAGE_ORDER and it defines the maximal power of two of number of pages that can be allocated as a single contiguous block. This option allows overriding the default setting when ability to allocate very diff --git a/arch/nios2/include/asm/cacheflush.h b/arch/nios2/include/asm/cacheflush.h index 348cea0977927a..81484a776b333a 100644 --- a/arch/nios2/include/asm/cacheflush.h +++ b/arch/nios2/include/asm/cacheflush.h @@ -38,6 +38,7 @@ void flush_icache_pages(struct vm_area_struct *vma, struct page *page, #define flush_icache_pages flush_icache_pages #define flush_cache_vmap(start, end) flush_dcache_range(start, end) +#define flush_cache_vmap_early(start, end) do { } while (0) #define flush_cache_vunmap(start, end) flush_dcache_range(start, end) extern void copy_to_user_page(struct vm_area_struct *vma, struct page *page, diff --git a/arch/nios2/include/asm/traps.h b/arch/nios2/include/asm/traps.h index 82a48473280d87..afd77bef01c65d 100644 --- a/arch/nios2/include/asm/traps.h +++ b/arch/nios2/include/asm/traps.h @@ -14,6 +14,8 @@ #ifndef __ASSEMBLY__ void _exception(int signo, struct pt_regs *regs, int code, unsigned long addr); +void do_page_fault(struct pt_regs *regs, unsigned long cause, + unsigned long address); #endif #endif /* _ASM_NIOS2_TRAPS_H */ diff --git a/arch/parisc/include/asm/cacheflush.h b/arch/parisc/include/asm/cacheflush.h index b4006f2a97052d..ba4c05bc24d690 100644 --- a/arch/parisc/include/asm/cacheflush.h +++ b/arch/parisc/include/asm/cacheflush.h @@ -41,6 +41,7 @@ void flush_kernel_vmap_range(void *vaddr, int size); void invalidate_kernel_vmap_range(void *vaddr, int size); #define flush_cache_vmap(start, end) flush_cache_all() +#define flush_cache_vmap_early(start, end) do { } while (0) #define flush_cache_vunmap(start, end) flush_cache_all() void flush_dcache_folio(struct folio *folio); diff --git a/arch/parisc/include/asm/io.h b/arch/parisc/include/asm/io.h index 366537042465a1..a63190af2f055f 100644 --- a/arch/parisc/include/asm/io.h +++ b/arch/parisc/include/asm/io.h @@ -132,8 +132,6 @@ static inline void gsc_writeq(unsigned long long val, unsigned long addr) #define ioremap_wc(addr, size) \ ioremap_prot((addr), (size), _PAGE_IOREMAP) -#define ioremap_uc(addr, size) \ - ioremap_prot((addr), (size), _PAGE_IOREMAP) #define pci_iounmap pci_iounmap @@ -267,12 +265,6 @@ extern void iowrite64be(u64 val, void __iomem *addr); #define iowrite16_rep iowrite16_rep #define iowrite32_rep iowrite32_rep -/* - * Convert a physical pointer to a virtual kernel pointer for /dev/mem - * access - */ -#define xlate_dev_mem_ptr(p) __va(p) - extern int devmem_is_allowed(unsigned long pfn); #include diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c index 904ca3b9e7a715..c69f6d5946e906 100644 --- a/arch/parisc/kernel/firmware.c +++ b/arch/parisc/kernel/firmware.c @@ -123,10 +123,10 @@ static unsigned long f_extend(unsigned long address) #ifdef CONFIG_64BIT if(unlikely(parisc_narrow_firmware)) { if((address & 0xff000000) == 0xf0000000) - return 0xf0f0f0f000000000UL | (u32)address; + return (0xfffffff0UL << 32) | (u32)address; if((address & 0xf0000000) == 0xf0000000) - return 0xffffffff00000000UL | (u32)address; + return (0xffffffffUL << 32) | (u32)address; } #endif return address; diff --git a/arch/parisc/kernel/kexec_file.c b/arch/parisc/kernel/kexec_file.c index 8c534204f0fdac..3fc82130b6c3f4 100644 --- a/arch/parisc/kernel/kexec_file.c +++ b/arch/parisc/kernel/kexec_file.c @@ -38,8 +38,8 @@ static void *elf_load(struct kimage *image, char *kernel_buf, for (i = 0; i < image->nr_segments; i++) image->segment[i].mem = __pa(image->segment[i].mem); - pr_debug("Loaded the kernel at 0x%lx, entry at 0x%lx\n", - kernel_load_addr, image->start); + kexec_dprintk("Loaded the kernel at 0x%lx, entry at 0x%lx\n", + kernel_load_addr, image->start); if (initrd != NULL) { kbuf.buffer = initrd; @@ -51,7 +51,7 @@ static void *elf_load(struct kimage *image, char *kernel_buf, if (ret) goto out; - pr_debug("Loaded initrd at 0x%lx\n", kbuf.mem); + kexec_dprintk("Loaded initrd at 0x%lx\n", kbuf.mem); image->arch.initrd_start = kbuf.mem; image->arch.initrd_end = kbuf.mem + initrd_len; } @@ -68,7 +68,7 @@ static void *elf_load(struct kimage *image, char *kernel_buf, if (ret) goto out; - pr_debug("Loaded cmdline at 0x%lx\n", kbuf.mem); + kexec_dprintk("Loaded cmdline at 0x%lx\n", kbuf.mem); image->arch.cmdline = kbuf.mem; } out: diff --git a/arch/parisc/kernel/syscalls/syscall.tbl b/arch/parisc/kernel/syscalls/syscall.tbl index a47798fed54e39..b236a84c4e127e 100644 --- a/arch/parisc/kernel/syscalls/syscall.tbl +++ b/arch/parisc/kernel/syscalls/syscall.tbl @@ -455,3 +455,8 @@ 454 common futex_wake sys_futex_wake 455 common futex_wait sys_futex_wait 456 common futex_requeue sys_futex_requeue +457 common statmount sys_statmount +458 common listmount sys_listmount +459 common lsm_get_self_attr sys_lsm_get_self_attr +460 common lsm_set_self_attr sys_lsm_set_self_attr +461 common lsm_list_modules sys_lsm_list_modules diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c index a2a3e89f2d9ab3..f876af56e13fdd 100644 --- a/arch/parisc/mm/init.c +++ b/arch/parisc/mm/init.c @@ -33,6 +33,7 @@ #include #include #include +#include extern int data_start; extern void parisc_kernel_start(void); /* Kernel entry point in head.S */ diff --git a/arch/parisc/video/fbdev.c b/arch/parisc/video/fbdev.c index 137561d982460c..e4f8ac99fc9e04 100644 --- a/arch/parisc/video/fbdev.c +++ b/arch/parisc/video/fbdev.c @@ -21,6 +21,6 @@ int fb_is_primary_device(struct fb_info *info) return true; /* return true if it's the default built-in framebuffer driver */ - return (sti->info == info); + return (sti->dev == info->device); } EXPORT_SYMBOL(fb_is_primary_device); diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 1f11a62809f205..b9fc064d38d281 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -189,6 +189,7 @@ config PPC select EDAC_ATOMIC_SCRUB select EDAC_SUPPORT select FTRACE_MCOUNT_USE_PATCHABLE_FUNCTION_ENTRY if ARCH_USING_PATCHABLE_FUNCTION_ENTRY + select FUNCTION_ALIGNMENT_4B select GENERIC_ATOMIC64 if PPC32 select GENERIC_CLOCKEVENTS_BROADCAST if SMP select GENERIC_CMOS_UPDATE @@ -858,6 +859,7 @@ config THREAD_SHIFT int "Thread shift" if EXPERT range 13 15 default "15" if PPC_256K_PAGES + default "15" if PPC_PSERIES || PPC_POWERNV default "14" if PPC64 default "13" help @@ -915,7 +917,7 @@ config ARCH_FORCE_MAX_ORDER default "10" help The kernel page allocator limits the size of maximal physically - contiguous allocations. The limit is called MAX_ORDER and it + contiguous allocations. The limit is called MAX_PAGE_ORDER and it defines the maximal power of two of number of pages that can be allocated as a single contiguous block. This option allows overriding the default setting when ability to allocate very diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug index ea4033abc07dae..8c80b154e814ea 100644 --- a/arch/powerpc/Kconfig.debug +++ b/arch/powerpc/Kconfig.debug @@ -271,7 +271,6 @@ config PPC_EARLY_DEBUG_USBGECKO config PPC_EARLY_DEBUG_PS3GELIC bool "Early debugging through the PS3 Ethernet port" depends on PPC_PS3 - select PS3GELIC_UDBG help Select this to enable early debugging for the PlayStation3 via UDP broadcasts sent out through the Ethernet port. diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index f19dbaa1d54136..051247027da0ba 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -10,15 +10,26 @@ # Rewritten by Cort Dougan and Paul Mackerras # +ifdef cross_compiling + ifeq ($(CROSS_COMPILE),) + # Auto detect cross compiler prefix. + # Look for: (powerpc(64(le)?)?)(-unknown)?-linux(-gnu)?- + CC_ARCHES := powerpc powerpc64 powerpc64le + CC_SUFFIXES := linux linux-gnu unknown-linux-gnu + CROSS_COMPILE := $(call cc-cross-prefix, $(foreach a,$(CC_ARCHES), \ + $(foreach s,$(CC_SUFFIXES),$(a)-$(s)-))) + endif +endif + HAS_BIARCH := $(call cc-option-yn, -m32) # Set default 32 bits cross compilers for vdso and boot wrapper CROSS32_COMPILE ?= # If we're on a ppc/ppc64/ppc64le machine use that defconfig, otherwise just use -# ppc64_defconfig because we have nothing better to go on. +# ppc64le_defconfig because we have nothing better to go on. uname := $(shell uname -m) -KBUILD_DEFCONFIG := $(if $(filter ppc%,$(uname)),$(uname),ppc64)_defconfig +KBUILD_DEFCONFIG := $(if $(filter ppc%,$(uname)),$(uname),ppc64le)_defconfig new_nm := $(shell if $(NM) --help 2>&1 | grep -- '--synthetic' > /dev/null; then echo y; else echo n; fi) @@ -161,7 +172,7 @@ CFLAGS-y += $(CONFIG_TUNE_CPU) asinstr := $(call as-instr,lis 9$(comma)foo@high,-DHAVE_AS_ATHIGH=1) -KBUILD_CPPFLAGS += -I $(srctree)/arch/$(ARCH) $(asinstr) +KBUILD_CPPFLAGS += -I $(srctree)/arch/powerpc $(asinstr) KBUILD_AFLAGS += $(AFLAGS-y) KBUILD_CFLAGS += $(call cc-option,-msoft-float) KBUILD_CFLAGS += $(CFLAGS-y) @@ -232,7 +243,7 @@ BOOT_TARGETS2 := zImage% dtbImage% treeImage.% cuImage.% simpleImage.% uImage.% PHONY += $(BOOT_TARGETS1) $(BOOT_TARGETS2) -boot := arch/$(ARCH)/boot +boot := arch/powerpc/boot $(BOOT_TARGETS1): vmlinux $(Q)$(MAKE) $(build)=$(boot) $(patsubst %,$(boot)/%,$@) @@ -336,7 +347,7 @@ PHONY += $(generated_configs) define archhelp echo '* zImage - Build default images selected by kernel config' - echo ' zImage.* - Compressed kernel image (arch/$(ARCH)/boot/zImage.*)' + echo ' zImage.* - Compressed kernel image (arch/powerpc/boot/zImage.*)' echo ' uImage - U-Boot native image format' echo ' cuImage.
- Backwards compatible U-Boot image for older' echo ' versions which do not support device trees' @@ -347,12 +358,12 @@ define archhelp echo ' (your) ~/bin/$(INSTALLKERNEL) or' echo ' (distribution) /sbin/$(INSTALLKERNEL) or' echo ' install to $$(INSTALL_PATH) and run lilo' - echo ' *_defconfig - Select default config from arch/$(ARCH)/configs' + echo ' *_defconfig - Select default config from arch/powerpc/configs' echo '' echo ' Targets with
embed a device tree blob inside the image' echo ' These targets support board with firmware that does not' echo ' support passing a device tree directly. Replace
with the' - echo ' name of a dts file from the arch/$(ARCH)/boot/dts/ directory' + echo ' name of a dts file from the arch/powerpc/boot/dts/ directory' echo ' (minus the .dts extension).' echo $(foreach cfg,$(generated_configs), diff --git a/arch/powerpc/boot/dts/fsl/t1023si-post.dtsi b/arch/powerpc/boot/dts/fsl/t1023si-post.dtsi index d552044c5afc08..aa5152ca812011 100644 --- a/arch/powerpc/boot/dts/fsl/t1023si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/t1023si-post.dtsi @@ -367,45 +367,46 @@ reg = <0xf0000 0x1000>; interrupts = <18 2 0 0>; fsl,tmu-range = <0xb0000 0xa0026 0x80048 0x30061>; - fsl,tmu-calibration = <0x00000000 0x0000000f - 0x00000001 0x00000017 - 0x00000002 0x0000001e - 0x00000003 0x00000026 - 0x00000004 0x0000002e - 0x00000005 0x00000035 - 0x00000006 0x0000003d - 0x00000007 0x00000044 - 0x00000008 0x0000004c - 0x00000009 0x00000053 - 0x0000000a 0x0000005b - 0x0000000b 0x00000064 - - 0x00010000 0x00000011 - 0x00010001 0x0000001c - 0x00010002 0x00000024 - 0x00010003 0x0000002b - 0x00010004 0x00000034 - 0x00010005 0x00000039 - 0x00010006 0x00000042 - 0x00010007 0x0000004c - 0x00010008 0x00000051 - 0x00010009 0x0000005a - 0x0001000a 0x00000063 - - 0x00020000 0x00000013 - 0x00020001 0x00000019 - 0x00020002 0x00000024 - 0x00020003 0x0000002c - 0x00020004 0x00000035 - 0x00020005 0x0000003d - 0x00020006 0x00000046 - 0x00020007 0x00000050 - 0x00020008 0x00000059 - - 0x00030000 0x00000002 - 0x00030001 0x0000000d - 0x00030002 0x00000019 - 0x00030003 0x00000024>; + fsl,tmu-calibration = + <0x00000000 0x0000000f>, + <0x00000001 0x00000017>, + <0x00000002 0x0000001e>, + <0x00000003 0x00000026>, + <0x00000004 0x0000002e>, + <0x00000005 0x00000035>, + <0x00000006 0x0000003d>, + <0x00000007 0x00000044>, + <0x00000008 0x0000004c>, + <0x00000009 0x00000053>, + <0x0000000a 0x0000005b>, + <0x0000000b 0x00000064>, + + <0x00010000 0x00000011>, + <0x00010001 0x0000001c>, + <0x00010002 0x00000024>, + <0x00010003 0x0000002b>, + <0x00010004 0x00000034>, + <0x00010005 0x00000039>, + <0x00010006 0x00000042>, + <0x00010007 0x0000004c>, + <0x00010008 0x00000051>, + <0x00010009 0x0000005a>, + <0x0001000a 0x00000063>, + + <0x00020000 0x00000013>, + <0x00020001 0x00000019>, + <0x00020002 0x00000024>, + <0x00020003 0x0000002c>, + <0x00020004 0x00000035>, + <0x00020005 0x0000003d>, + <0x00020006 0x00000046>, + <0x00020007 0x00000050>, + <0x00020008 0x00000059>, + + <0x00030000 0x00000002>, + <0x00030001 0x0000000d>, + <0x00030002 0x00000019>, + <0x00030003 0x00000024>; #thermal-sensor-cells = <1>; }; diff --git a/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi b/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi index ad0ab33336b88c..77678862320401 100644 --- a/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/t1040si-post.dtsi @@ -447,41 +447,42 @@ reg = <0xf0000 0x1000>; interrupts = <18 2 0 0>; fsl,tmu-range = <0xa0000 0x90026 0x8004a 0x1006a>; - fsl,tmu-calibration = <0x00000000 0x00000025 - 0x00000001 0x00000028 - 0x00000002 0x0000002d - 0x00000003 0x00000031 - 0x00000004 0x00000036 - 0x00000005 0x0000003a - 0x00000006 0x00000040 - 0x00000007 0x00000044 - 0x00000008 0x0000004a - 0x00000009 0x0000004f - 0x0000000a 0x00000054 - - 0x00010000 0x0000000d - 0x00010001 0x00000013 - 0x00010002 0x00000019 - 0x00010003 0x0000001f - 0x00010004 0x00000025 - 0x00010005 0x0000002d - 0x00010006 0x00000033 - 0x00010007 0x00000043 - 0x00010008 0x0000004b - 0x00010009 0x00000053 - - 0x00020000 0x00000010 - 0x00020001 0x00000017 - 0x00020002 0x0000001f - 0x00020003 0x00000029 - 0x00020004 0x00000031 - 0x00020005 0x0000003c - 0x00020006 0x00000042 - 0x00020007 0x0000004d - 0x00020008 0x00000056 - - 0x00030000 0x00000012 - 0x00030001 0x0000001d>; + fsl,tmu-calibration = + <0x00000000 0x00000025>, + <0x00000001 0x00000028>, + <0x00000002 0x0000002d>, + <0x00000003 0x00000031>, + <0x00000004 0x00000036>, + <0x00000005 0x0000003a>, + <0x00000006 0x00000040>, + <0x00000007 0x00000044>, + <0x00000008 0x0000004a>, + <0x00000009 0x0000004f>, + <0x0000000a 0x00000054>, + + <0x00010000 0x0000000d>, + <0x00010001 0x00000013>, + <0x00010002 0x00000019>, + <0x00010003 0x0000001f>, + <0x00010004 0x00000025>, + <0x00010005 0x0000002d>, + <0x00010006 0x00000033>, + <0x00010007 0x00000043>, + <0x00010008 0x0000004b>, + <0x00010009 0x00000053>, + + <0x00020000 0x00000010>, + <0x00020001 0x00000017>, + <0x00020002 0x0000001f>, + <0x00020003 0x00000029>, + <0x00020004 0x00000031>, + <0x00020005 0x0000003c>, + <0x00020006 0x00000042>, + <0x00020007 0x0000004d>, + <0x00020008 0x00000056>, + + <0x00030000 0x00000012>, + <0x00030001 0x0000001d>; #thermal-sensor-cells = <1>; }; diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig index 6e7b9e8fd2251a..544a65fda77bcb 100644 --- a/arch/powerpc/configs/ppc64_defconfig +++ b/arch/powerpc/configs/ppc64_defconfig @@ -92,6 +92,7 @@ CONFIG_MEMORY_HOTPLUG=y CONFIG_MEMORY_HOTREMOVE=y CONFIG_KSM=y CONFIG_TRANSPARENT_HUGEPAGE=y +CONFIG_MEM_SOFT_DIRTY=y CONFIG_ZONE_DEVICE=y CONFIG_NET=y CONFIG_PACKET=y diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig index f279703425d453..66c7b28d745042 100644 --- a/arch/powerpc/configs/ppc6xx_defconfig +++ b/arch/powerpc/configs/ppc6xx_defconfig @@ -274,7 +274,6 @@ CONFIG_NET_ACT_POLICE=m CONFIG_NET_ACT_GACT=m CONFIG_GACT_PROB=y CONFIG_NET_ACT_MIRRED=m -CONFIG_NET_ACT_IPT=m CONFIG_NET_ACT_NAT=m CONFIG_NET_ACT_PEDIT=m CONFIG_NET_ACT_SIMP=m diff --git a/arch/powerpc/configs/ps3_defconfig b/arch/powerpc/configs/ps3_defconfig index 2b175ddf82f0bc..aa8bb0208bcc8f 100644 --- a/arch/powerpc/configs/ps3_defconfig +++ b/arch/powerpc/configs/ps3_defconfig @@ -24,6 +24,7 @@ CONFIG_PS3_VRAM=m CONFIG_PS3_LPM=m # CONFIG_PPC_OF_BOOT_TRAMPOLINE is not set CONFIG_KEXEC=y +# CONFIG_PPC64_BIG_ENDIAN_ELF_ABI_V2 is not set CONFIG_PPC_4K_PAGES=y CONFIG_SCHED_SMT=y CONFIG_PM=y diff --git a/arch/powerpc/crypto/aes-gcm-p10-glue.c b/arch/powerpc/crypto/aes-gcm-p10-glue.c index 4b6e899895e7be..f62ee54076c06d 100644 --- a/arch/powerpc/crypto/aes-gcm-p10-glue.c +++ b/arch/powerpc/crypto/aes-gcm-p10-glue.c @@ -37,7 +37,7 @@ asmlinkage void aes_p10_gcm_encrypt(u8 *in, u8 *out, size_t len, void *rkey, u8 *iv, void *Xi); asmlinkage void aes_p10_gcm_decrypt(u8 *in, u8 *out, size_t len, void *rkey, u8 *iv, void *Xi); -asmlinkage void gcm_init_htable(unsigned char htable[256], unsigned char Xi[16]); +asmlinkage void gcm_init_htable(unsigned char htable[], unsigned char Xi[]); asmlinkage void gcm_ghash_p10(unsigned char *Xi, unsigned char *Htable, unsigned char *aad, unsigned int alen); diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h index cb77eddca54b99..927d585652bc75 100644 --- a/arch/powerpc/include/asm/book3s/64/pgtable.h +++ b/arch/powerpc/include/asm/book3s/64/pgtable.h @@ -17,12 +17,6 @@ #define _PAGE_EXEC 0x00001 /* execute permission */ #define _PAGE_WRITE 0x00002 /* write access allowed */ #define _PAGE_READ 0x00004 /* read access allowed */ -#define _PAGE_NA _PAGE_PRIVILEGED -#define _PAGE_NAX _PAGE_EXEC -#define _PAGE_RO _PAGE_READ -#define _PAGE_ROX (_PAGE_READ | _PAGE_EXEC) -#define _PAGE_RW (_PAGE_READ | _PAGE_WRITE) -#define _PAGE_RWX (_PAGE_READ | _PAGE_WRITE | _PAGE_EXEC) #define _PAGE_PRIVILEGED 0x00008 /* kernel access only */ #define _PAGE_SAO 0x00010 /* Strong access order */ #define _PAGE_NON_IDEMPOTENT 0x00020 /* non idempotent memory */ @@ -532,8 +526,8 @@ static inline bool pte_user(pte_t pte) static inline bool pte_access_permitted(pte_t pte, bool write) { /* - * _PAGE_READ is needed for any access and will be - * cleared for PROT_NONE + * _PAGE_READ is needed for any access and will be cleared for + * PROT_NONE. Execute-only mapping via PROT_EXEC also returns false. */ if (!pte_present(pte) || !pte_user(pte) || !pte_read(pte)) return false; diff --git a/arch/powerpc/include/asm/book3s/64/tlbflush.h b/arch/powerpc/include/asm/book3s/64/tlbflush.h index 1950c1b825b404..fd642b729775a9 100644 --- a/arch/powerpc/include/asm/book3s/64/tlbflush.h +++ b/arch/powerpc/include/asm/book3s/64/tlbflush.h @@ -158,11 +158,6 @@ static inline void flush_tlb_fix_spurious_fault(struct vm_area_struct *vma, */ } -static inline bool __pte_protnone(unsigned long pte) -{ - return (pte & (pgprot_val(PAGE_NONE) | _PAGE_RWX)) == pgprot_val(PAGE_NONE); -} - static inline bool __pte_flags_need_flush(unsigned long oldval, unsigned long newval) { @@ -179,8 +174,8 @@ static inline bool __pte_flags_need_flush(unsigned long oldval, /* * We do not expect kernel mappings or non-PTEs or not-present PTEs. */ - VM_WARN_ON_ONCE(!__pte_protnone(oldval) && oldval & _PAGE_PRIVILEGED); - VM_WARN_ON_ONCE(!__pte_protnone(newval) && newval & _PAGE_PRIVILEGED); + VM_WARN_ON_ONCE(oldval & _PAGE_PRIVILEGED); + VM_WARN_ON_ONCE(newval & _PAGE_PRIVILEGED); VM_WARN_ON_ONCE(!(oldval & _PAGE_PTE)); VM_WARN_ON_ONCE(!(newval & _PAGE_PTE)); VM_WARN_ON_ONCE(!(oldval & _PAGE_PRESENT)); diff --git a/arch/powerpc/include/asm/ftrace.h b/arch/powerpc/include/asm/ftrace.h index 9e5a39b6a3114b..1ebd2ca97f1201 100644 --- a/arch/powerpc/include/asm/ftrace.h +++ b/arch/powerpc/include/asm/ftrace.h @@ -25,7 +25,7 @@ static inline unsigned long ftrace_call_adjust(unsigned long addr) if (IS_ENABLED(CONFIG_ARCH_USING_PATCHABLE_FUNCTION_ENTRY)) addr += MCOUNT_INSN_SIZE; - return addr; + return addr; } unsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip, diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h index ddb99e982917e9..a41e542ba94dd9 100644 --- a/arch/powerpc/include/asm/hvcall.h +++ b/arch/powerpc/include/asm/hvcall.h @@ -349,7 +349,16 @@ #define H_GET_ENERGY_SCALE_INFO 0x450 #define H_PKS_SIGNED_UPDATE 0x454 #define H_WATCHDOG 0x45C -#define MAX_HCALL_OPCODE H_WATCHDOG +#define H_GUEST_GET_CAPABILITIES 0x460 +#define H_GUEST_SET_CAPABILITIES 0x464 +#define H_GUEST_CREATE 0x470 +#define H_GUEST_CREATE_VCPU 0x474 +#define H_GUEST_GET_STATE 0x478 +#define H_GUEST_SET_STATE 0x47C +#define H_GUEST_RUN_VCPU 0x480 +#define H_GUEST_COPY_MEMORY 0x484 +#define H_GUEST_DELETE 0x488 +#define MAX_HCALL_OPCODE H_GUEST_DELETE /* Scope args for H_SCM_UNBIND_ALL */ #define H_UNBIND_SCOPE_ALL (0x1) @@ -393,15 +402,6 @@ #define H_ENTER_NESTED 0xF804 #define H_TLB_INVALIDATE 0xF808 #define H_COPY_TOFROM_GUEST 0xF80C -#define H_GUEST_GET_CAPABILITIES 0x460 -#define H_GUEST_SET_CAPABILITIES 0x464 -#define H_GUEST_CREATE 0x470 -#define H_GUEST_CREATE_VCPU 0x474 -#define H_GUEST_GET_STATE 0x478 -#define H_GUEST_SET_STATE 0x47C -#define H_GUEST_RUN_VCPU 0x480 -#define H_GUEST_COPY_MEMORY 0x484 -#define H_GUEST_DELETE 0x488 /* Flags for H_SVM_PAGE_IN */ #define H_PAGE_IN_SHARED 0x1 diff --git a/arch/powerpc/include/asm/hvconsole.h b/arch/powerpc/include/asm/hvconsole.h index ccb2034506f0f1..d841a97010a0f8 100644 --- a/arch/powerpc/include/asm/hvconsole.h +++ b/arch/powerpc/include/asm/hvconsole.h @@ -21,8 +21,8 @@ * Vio firmware always attempts to fetch MAX_VIO_GET_CHARS chars. The 'count' * parm is included to conform to put_chars() function pointer template */ -extern int hvc_get_chars(uint32_t vtermno, char *buf, int count); -extern int hvc_put_chars(uint32_t vtermno, const char *buf, int count); +extern ssize_t hvc_get_chars(uint32_t vtermno, u8 *buf, size_t count); +extern ssize_t hvc_put_chars(uint32_t vtermno, const u8 *buf, size_t count); /* Provided by HVC VIO */ void hvc_vio_init_early(void); diff --git a/arch/powerpc/include/asm/hvsi.h b/arch/powerpc/include/asm/hvsi.h index 464a7519ed6443..9058edcb632b49 100644 --- a/arch/powerpc/include/asm/hvsi.h +++ b/arch/powerpc/include/asm/hvsi.h @@ -64,7 +64,7 @@ struct hvsi_priv { unsigned int inbuf_len; /* data in input buffer */ unsigned char inbuf[HVSI_INBUF_SIZE]; unsigned int inbuf_cur; /* Cursor in input buffer */ - unsigned int inbuf_pktlen; /* packet length from cursor */ + size_t inbuf_pktlen; /* packet length from cursor */ atomic_t seqno; /* packet sequence number */ unsigned int opened:1; /* driver opened */ unsigned int established:1; /* protocol established */ @@ -72,24 +72,26 @@ struct hvsi_priv { unsigned int mctrl_update:1; /* modem control updated */ unsigned short mctrl; /* modem control */ struct tty_struct *tty; /* tty structure */ - int (*get_chars)(uint32_t termno, char *buf, int count); - int (*put_chars)(uint32_t termno, const char *buf, int count); + ssize_t (*get_chars)(uint32_t termno, u8 *buf, size_t count); + ssize_t (*put_chars)(uint32_t termno, const u8 *buf, size_t count); uint32_t termno; }; /* hvsi lib functions */ struct hvc_struct; extern void hvsilib_init(struct hvsi_priv *pv, - int (*get_chars)(uint32_t termno, char *buf, int count), - int (*put_chars)(uint32_t termno, const char *buf, - int count), + ssize_t (*get_chars)(uint32_t termno, u8 *buf, + size_t count), + ssize_t (*put_chars)(uint32_t termno, const u8 *buf, + size_t count), int termno, int is_console); extern int hvsilib_open(struct hvsi_priv *pv, struct hvc_struct *hp); extern void hvsilib_close(struct hvsi_priv *pv, struct hvc_struct *hp); extern int hvsilib_read_mctrl(struct hvsi_priv *pv); extern int hvsilib_write_mctrl(struct hvsi_priv *pv, int dtr); extern void hvsilib_establish(struct hvsi_priv *pv); -extern int hvsilib_get_chars(struct hvsi_priv *pv, char *buf, int count); -extern int hvsilib_put_chars(struct hvsi_priv *pv, const char *buf, int count); +extern ssize_t hvsilib_get_chars(struct hvsi_priv *pv, u8 *buf, size_t count); +extern ssize_t hvsilib_put_chars(struct hvsi_priv *pv, const u8 *buf, + size_t count); #endif /* _HVSI_H */ diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h index 5220274a62772a..08c550ed49be68 100644 --- a/arch/powerpc/include/asm/io.h +++ b/arch/powerpc/include/asm/io.h @@ -709,12 +709,6 @@ static inline void name at \ #define memcpy_fromio memcpy_fromio #define memcpy_toio memcpy_toio -/* - * Convert a physical pointer to a virtual kernel pointer for /dev/mem - * access - */ -#define xlate_dev_mem_ptr(p) __va(p) - /* * We don't do relaxed operations yet, at least not with this semantic */ @@ -900,7 +894,6 @@ void __iomem *ioremap_wt(phys_addr_t address, unsigned long size); #endif void __iomem *ioremap_coherent(phys_addr_t address, unsigned long size); -#define ioremap_uc(addr, size) ioremap((addr), (size)) #define ioremap_cache(addr, size) \ ioremap_prot((addr), (size), pgprot_val(PAGE_KERNEL)) diff --git a/arch/powerpc/include/asm/irq_work.h b/arch/powerpc/include/asm/irq_work.h index b8b0be8f1a07ee..c6d3078bd8c3b4 100644 --- a/arch/powerpc/include/asm/irq_work.h +++ b/arch/powerpc/include/asm/irq_work.h @@ -6,6 +6,5 @@ static inline bool arch_irq_work_has_interrupt(void) { return true; } -extern void arch_irq_work_raise(void); #endif /* _ASM_POWERPC_IRQ_WORK_H */ diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h index 4f527d09c92b97..3e1e2a698c9e70 100644 --- a/arch/powerpc/include/asm/kvm_book3s.h +++ b/arch/powerpc/include/asm/kvm_book3s.h @@ -302,6 +302,7 @@ void kvmhv_nested_exit(void); void kvmhv_vm_nested_init(struct kvm *kvm); long kvmhv_set_partition_table(struct kvm_vcpu *vcpu); long kvmhv_copy_tofrom_guest_nested(struct kvm_vcpu *vcpu); +void kvmhv_flush_lpid(u64 lpid); void kvmhv_set_ptbl_entry(u64 lpid, u64 dw0, u64 dw1); void kvmhv_release_all_nested(struct kvm *kvm); long kvmhv_enter_nested_guest(struct kvm_vcpu *vcpu); @@ -593,13 +594,17 @@ static inline u##size kvmppc_get_##reg(struct kvm_vcpu *vcpu) \ KVMPPC_BOOK3S_VCORE_ACCESSOR(vtb, 64, KVMPPC_GSID_VTB) -KVMPPC_BOOK3S_VCORE_ACCESSOR(tb_offset, 64, KVMPPC_GSID_TB_OFFSET) KVMPPC_BOOK3S_VCORE_ACCESSOR_GET(arch_compat, 32, KVMPPC_GSID_LOGICAL_PVR) KVMPPC_BOOK3S_VCORE_ACCESSOR_GET(lpcr, 64, KVMPPC_GSID_LPCR) +KVMPPC_BOOK3S_VCORE_ACCESSOR_SET(tb_offset, 64, KVMPPC_GSID_TB_OFFSET) + +static inline u64 kvmppc_get_tb_offset(struct kvm_vcpu *vcpu) +{ + return vcpu->arch.vcore->tb_offset; +} static inline u64 kvmppc_get_dec_expires(struct kvm_vcpu *vcpu) { - WARN_ON(kvmhv_nestedv2_cached_reload(vcpu, KVMPPC_GSID_TB_OFFSET) < 0); WARN_ON(kvmhv_nestedv2_cached_reload(vcpu, KVMPPC_GSID_DEC_EXPIRY_TB) < 0); return vcpu->arch.dec_expires; } @@ -607,7 +612,6 @@ static inline u64 kvmppc_get_dec_expires(struct kvm_vcpu *vcpu) static inline void kvmppc_set_dec_expires(struct kvm_vcpu *vcpu, u64 val) { vcpu->arch.dec_expires = val; - WARN_ON(kvmhv_nestedv2_cached_reload(vcpu, KVMPPC_GSID_TB_OFFSET) < 0); kvmhv_nestedv2_mark_dirty(vcpu, KVMPPC_GSID_DEC_EXPIRY_TB); } diff --git a/arch/powerpc/include/asm/kvm_book3s_64.h b/arch/powerpc/include/asm/kvm_book3s_64.h index 2477021bff540b..d8729ec81ca083 100644 --- a/arch/powerpc/include/asm/kvm_book3s_64.h +++ b/arch/powerpc/include/asm/kvm_book3s_64.h @@ -682,6 +682,7 @@ void kvmhv_nestedv2_vcpu_free(struct kvm_vcpu *vcpu, struct kvmhv_nestedv2_io *i int kvmhv_nestedv2_flush_vcpu(struct kvm_vcpu *vcpu, u64 time_limit); int kvmhv_nestedv2_set_ptbl_entry(unsigned long lpid, u64 dw0, u64 dw1); int kvmhv_nestedv2_parse_output(struct kvm_vcpu *vcpu); +int kvmhv_nestedv2_set_vpa(struct kvm_vcpu *vcpu, unsigned long vpa); #endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */ diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index 8799b37be295cf..8abac532146e7b 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h @@ -63,8 +63,6 @@ #include -#define KVM_ARCH_WANT_MMU_NOTIFIER - #define HPTEG_CACHE_NUM (1 << 15) #define HPTEG_HASH_BITS_PTE 13 #define HPTEG_HASH_BITS_PTE_LONG 12 diff --git a/arch/powerpc/include/asm/linkage.h b/arch/powerpc/include/asm/linkage.h index b88d1d2cf30447..b71b9582e75468 100644 --- a/arch/powerpc/include/asm/linkage.h +++ b/arch/powerpc/include/asm/linkage.h @@ -4,9 +4,6 @@ #include -#define __ALIGN .align 2 -#define __ALIGN_STR ".align 2" - #ifdef CONFIG_PPC64_ELF_ABI_V1 #define cond_syscall(x) \ asm ("\t.weak " #x "\n\t.set " #x ", sys_ni_syscall\n" \ diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h index 52cc25864a1be2..d8b7e246a32f59 100644 --- a/arch/powerpc/include/asm/mmu.h +++ b/arch/powerpc/include/asm/mmu.h @@ -412,5 +412,9 @@ extern void *abatron_pteptrs[2]; #include #endif +#if defined(CONFIG_FA_DUMP) || defined(CONFIG_PRESERVE_FA_DUMP) +#define __HAVE_ARCH_RESERVED_KERNEL_PAGES +#endif + #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_MMU_H_ */ diff --git a/arch/powerpc/include/asm/mmzone.h b/arch/powerpc/include/asm/mmzone.h index 4c6c6dbd182f45..da827d2d08666e 100644 --- a/arch/powerpc/include/asm/mmzone.h +++ b/arch/powerpc/include/asm/mmzone.h @@ -42,14 +42,6 @@ u64 memory_hotplug_max(void); #else #define memory_hotplug_max() memblock_end_of_DRAM() #endif /* CONFIG_NUMA */ -#ifdef CONFIG_FA_DUMP -#define __HAVE_ARCH_RESERVED_KERNEL_PAGES -#endif - -#ifdef CONFIG_MEMORY_HOTPLUG -extern int create_section_mapping(unsigned long start, unsigned long end, - int nid, pgprot_t prot); -#endif #endif /* __KERNEL__ */ #endif /* _ASM_MMZONE_H_ */ diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h index b66b0c615f4f19..af304e6cb486c5 100644 --- a/arch/powerpc/include/asm/opal.h +++ b/arch/powerpc/include/asm/opal.h @@ -313,9 +313,11 @@ extern int early_init_dt_scan_recoverable_ranges(unsigned long node, const char *uname, int depth, void *data); void __init opal_configure_cores(void); -extern int opal_get_chars(uint32_t vtermno, char *buf, int count); -extern int opal_put_chars(uint32_t vtermno, const char *buf, int total_len); -extern int opal_put_chars_atomic(uint32_t vtermno, const char *buf, int total_len); +extern ssize_t opal_get_chars(uint32_t vtermno, u8 *buf, size_t count); +extern ssize_t opal_put_chars(uint32_t vtermno, const u8 *buf, + size_t total_len); +extern ssize_t opal_put_chars_atomic(uint32_t vtermno, const u8 *buf, + size_t total_len); extern int opal_flush_chars(uint32_t vtermno, bool wait); extern int opal_flush_console(uint32_t vtermno); diff --git a/arch/powerpc/include/asm/papr-sysparm.h b/arch/powerpc/include/asm/papr-sysparm.h index f5fdbd8ae9dba9..0dbbff59101d6f 100644 --- a/arch/powerpc/include/asm/papr-sysparm.h +++ b/arch/powerpc/include/asm/papr-sysparm.h @@ -2,8 +2,10 @@ #ifndef _ASM_POWERPC_PAPR_SYSPARM_H #define _ASM_POWERPC_PAPR_SYSPARM_H +#include + typedef struct { - const u32 token; + u32 token; } papr_sysparm_t; #define mk_papr_sysparm(x_) ((papr_sysparm_t){ .token = x_, }) @@ -20,11 +22,14 @@ typedef struct { #define PAPR_SYSPARM_TLB_BLOCK_INVALIDATE_ATTRS mk_papr_sysparm(50) #define PAPR_SYSPARM_LPAR_NAME mk_papr_sysparm(55) -enum { - PAPR_SYSPARM_MAX_INPUT = 1024, - PAPR_SYSPARM_MAX_OUTPUT = 4000, -}; - +/** + * struct papr_sysparm_buf - RTAS work area layout for system parameter functions. + * + * This is the memory layout of the buffers passed to/from + * ibm,get-system-parameter and ibm,set-system-parameter. It is + * distinct from the papr_sysparm_io_block structure that is passed + * between user space and the kernel. + */ struct papr_sysparm_buf { __be16 len; char val[PAPR_SYSPARM_MAX_OUTPUT]; diff --git a/arch/powerpc/include/asm/paravirt.h b/arch/powerpc/include/asm/paravirt.h index ac4279208d6332..b78b82d6605776 100644 --- a/arch/powerpc/include/asm/paravirt.h +++ b/arch/powerpc/include/asm/paravirt.h @@ -76,6 +76,17 @@ static inline bool is_vcpu_idle(int vcpu) { return lppaca_of(vcpu).idle; } + +static inline bool vcpu_is_dispatched(int vcpu) +{ + /* + * This is the yield_count. An "odd" value (low bit on) means that + * the processor is yielded (either because of an OS yield or a + * hypervisor preempt). An even value implies that the processor is + * currently executing. + */ + return (!(yield_count_of(vcpu) & 1)); +} #else static inline bool is_shared_processor(void) { @@ -109,6 +120,10 @@ static inline bool is_vcpu_idle(int vcpu) { return false; } +static inline bool vcpu_is_dispatched(int vcpu) +{ + return true; +} #endif #define vcpu_is_preempted vcpu_is_preempted @@ -134,12 +149,12 @@ static inline bool vcpu_is_preempted(int cpu) * If the hypervisor has dispatched the target CPU on a physical * processor, then the target CPU is definitely not preempted. */ - if (!(yield_count_of(cpu) & 1)) + if (vcpu_is_dispatched(cpu)) return false; /* - * If the target CPU has yielded to Hypervisor but OS has not - * requested idle then the target CPU is definitely preempted. + * if the target CPU is not dispatched and the guest OS + * has not marked the CPU idle, then it is hypervisor preempted. */ if (!is_vcpu_idle(cpu)) return true; @@ -166,7 +181,7 @@ static inline bool vcpu_is_preempted(int cpu) /* * The PowerVM hypervisor dispatches VMs on a whole core - * basis. So we know that a thread sibling of the local CPU + * basis. So we know that a thread sibling of the executing CPU * cannot have been preempted by the hypervisor, even if it * has called H_CONFER, which will set the yield bit. */ @@ -174,15 +189,17 @@ static inline bool vcpu_is_preempted(int cpu) return false; /* - * If any of the threads of the target CPU's core are not - * preempted or ceded, then consider target CPU to be - * non-preempted. + * The specific target CPU was marked by guest OS as idle, but + * then also check all other cpus in the core for PowerVM + * because it does core scheduling and one of the vcpu + * of the core getting preempted by hypervisor implies + * other vcpus can also be considered preempted. */ first_cpu = cpu_first_thread_sibling(cpu); for (i = first_cpu; i < first_cpu + threads_per_core; i++) { if (i == cpu) continue; - if (!(yield_count_of(i) & 1)) + if (vcpu_is_dispatched(i)) return false; if (!is_vcpu_idle(i)) return true; diff --git a/arch/powerpc/include/asm/ppc-pci.h b/arch/powerpc/include/asm/ppc-pci.h index d9fcff5750271d..ce2b1b5eebddcf 100644 --- a/arch/powerpc/include/asm/ppc-pci.h +++ b/arch/powerpc/include/asm/ppc-pci.h @@ -35,6 +35,9 @@ extern void init_pci_config_tokens (void); extern unsigned long get_phb_buid (struct device_node *); extern int rtas_setup_phb(struct pci_controller *phb); +int rtas_pci_dn_read_config(struct pci_dn *pdn, int where, int size, u32 *val); +int rtas_pci_dn_write_config(struct pci_dn *pdn, int where, int size, u32 val); + #ifdef CONFIG_EEH void eeh_addr_cache_insert_dev(struct pci_dev *dev); @@ -44,8 +47,6 @@ void eeh_slot_error_detail(struct eeh_pe *pe, int severity); int eeh_pci_enable(struct eeh_pe *pe, int function); int eeh_pe_reset_full(struct eeh_pe *pe, bool include_passed); void eeh_save_bars(struct eeh_dev *edev); -int rtas_write_config(struct pci_dn *, int where, int size, u32 val); -int rtas_read_config(struct pci_dn *, int where, int size, u32 *val); void eeh_pe_state_mark(struct eeh_pe *pe, int state); void eeh_pe_mark_isolated(struct eeh_pe *pe); void eeh_pe_state_clear(struct eeh_pe *pe, int state, bool include_passed); diff --git a/arch/powerpc/include/asm/ps3.h b/arch/powerpc/include/asm/ps3.h index a5f36546a05240..d13d8fdc341149 100644 --- a/arch/powerpc/include/asm/ps3.h +++ b/arch/powerpc/include/asm/ps3.h @@ -514,4 +514,10 @@ u64 ps3_get_spe_id(void *arg); void ps3_early_mm_init(void); +#ifdef CONFIG_PPC_EARLY_DEBUG_PS3GELIC +void udbg_shutdown_ps3gelic(void); +#else +static inline void udbg_shutdown_ps3gelic(void) {} +#endif + #endif diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index 4ae4ab9090a2d4..7fd09f25452d4f 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -1361,6 +1361,7 @@ #define PVR_POWER8E 0x004B #define PVR_POWER8NVL 0x004C #define PVR_POWER8 0x004D +#define PVR_HX_C2000 0x0066 #define PVR_POWER9 0x004E #define PVR_POWER10 0x0080 #define PVR_BE 0x0070 diff --git a/arch/powerpc/include/asm/reg_a2.h b/arch/powerpc/include/asm/reg_a2.h deleted file mode 100644 index 74fba29e94913d..00000000000000 --- a/arch/powerpc/include/asm/reg_a2.h +++ /dev/null @@ -1,154 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Register definitions specific to the A2 core - * - * Copyright (C) 2008 Ben. Herrenschmidt (benh@kernel.crashing.org), IBM Corp. - */ - -#ifndef __ASM_POWERPC_REG_A2_H__ -#define __ASM_POWERPC_REG_A2_H__ - -#include - -#define SPRN_TENSR 0x1b5 -#define SPRN_TENS 0x1b6 /* Thread ENable Set */ -#define SPRN_TENC 0x1b7 /* Thread ENable Clear */ - -#define SPRN_A2_CCR0 0x3f0 /* Core Configuration Register 0 */ -#define SPRN_A2_CCR1 0x3f1 /* Core Configuration Register 1 */ -#define SPRN_A2_CCR2 0x3f2 /* Core Configuration Register 2 */ -#define SPRN_MMUCR0 0x3fc /* MMU Control Register 0 */ -#define SPRN_MMUCR1 0x3fd /* MMU Control Register 1 */ -#define SPRN_MMUCR2 0x3fe /* MMU Control Register 2 */ -#define SPRN_MMUCR3 0x3ff /* MMU Control Register 3 */ - -#define SPRN_IAR 0x372 - -#define SPRN_IUCR0 0x3f3 -#define IUCR0_ICBI_ACK 0x1000 - -#define SPRN_XUCR0 0x3f6 /* Execution Unit Config Register 0 */ - -#define A2_IERAT_SIZE 16 -#define A2_DERAT_SIZE 32 - -/* A2 MMUCR0 bits */ -#define MMUCR0_ECL 0x80000000 /* Extended Class for TLB fills */ -#define MMUCR0_TID_NZ 0x40000000 /* TID is non-zero */ -#define MMUCR0_TS 0x10000000 /* Translation space for TLB fills */ -#define MMUCR0_TGS 0x20000000 /* Guest space for TLB fills */ -#define MMUCR0_TLBSEL 0x0c000000 /* TLB or ERAT target for TLB fills */ -#define MMUCR0_TLBSEL_U 0x00000000 /* TLBSEL = UTLB */ -#define MMUCR0_TLBSEL_I 0x08000000 /* TLBSEL = I-ERAT */ -#define MMUCR0_TLBSEL_D 0x0c000000 /* TLBSEL = D-ERAT */ -#define MMUCR0_LOCKSRSH 0x02000000 /* Use TLB lock on tlbsx. */ -#define MMUCR0_TID_MASK 0x000000ff /* TID field */ - -/* A2 MMUCR1 bits */ -#define MMUCR1_IRRE 0x80000000 /* I-ERAT round robin enable */ -#define MMUCR1_DRRE 0x40000000 /* D-ERAT round robin enable */ -#define MMUCR1_REE 0x20000000 /* Reference Exception Enable*/ -#define MMUCR1_CEE 0x10000000 /* Change exception enable */ -#define MMUCR1_CSINV_ALL 0x00000000 /* Inval ERAT on all CS evts */ -#define MMUCR1_CSINV_NISYNC 0x04000000 /* Inval ERAT on all ex isync*/ -#define MMUCR1_CSINV_NEVER 0x0c000000 /* Don't inval ERAT on CS */ -#define MMUCR1_ICTID 0x00080000 /* IERAT class field as TID */ -#define MMUCR1_ITTID 0x00040000 /* IERAT thdid field as TID */ -#define MMUCR1_DCTID 0x00020000 /* DERAT class field as TID */ -#define MMUCR1_DTTID 0x00010000 /* DERAT thdid field as TID */ -#define MMUCR1_DCCD 0x00008000 /* DERAT class ignore */ -#define MMUCR1_TLBWE_BINV 0x00004000 /* back invalidate on tlbwe */ - -/* A2 MMUCR2 bits */ -#define MMUCR2_PSSEL_SHIFT 4 - -/* A2 MMUCR3 bits */ -#define MMUCR3_THID 0x0000000f /* Thread ID */ - -/* *** ERAT TLB bits definitions */ -#define TLB0_EPN_MASK ASM_CONST(0xfffffffffffff000) -#define TLB0_CLASS_MASK ASM_CONST(0x0000000000000c00) -#define TLB0_CLASS_00 ASM_CONST(0x0000000000000000) -#define TLB0_CLASS_01 ASM_CONST(0x0000000000000400) -#define TLB0_CLASS_10 ASM_CONST(0x0000000000000800) -#define TLB0_CLASS_11 ASM_CONST(0x0000000000000c00) -#define TLB0_V ASM_CONST(0x0000000000000200) -#define TLB0_X ASM_CONST(0x0000000000000100) -#define TLB0_SIZE_MASK ASM_CONST(0x00000000000000f0) -#define TLB0_SIZE_4K ASM_CONST(0x0000000000000010) -#define TLB0_SIZE_64K ASM_CONST(0x0000000000000030) -#define TLB0_SIZE_1M ASM_CONST(0x0000000000000050) -#define TLB0_SIZE_16M ASM_CONST(0x0000000000000070) -#define TLB0_SIZE_1G ASM_CONST(0x00000000000000a0) -#define TLB0_THDID_MASK ASM_CONST(0x000000000000000f) -#define TLB0_THDID_0 ASM_CONST(0x0000000000000001) -#define TLB0_THDID_1 ASM_CONST(0x0000000000000002) -#define TLB0_THDID_2 ASM_CONST(0x0000000000000004) -#define TLB0_THDID_3 ASM_CONST(0x0000000000000008) -#define TLB0_THDID_ALL ASM_CONST(0x000000000000000f) - -#define TLB1_RESVATTR ASM_CONST(0x00f0000000000000) -#define TLB1_U0 ASM_CONST(0x0008000000000000) -#define TLB1_U1 ASM_CONST(0x0004000000000000) -#define TLB1_U2 ASM_CONST(0x0002000000000000) -#define TLB1_U3 ASM_CONST(0x0001000000000000) -#define TLB1_R ASM_CONST(0x0000800000000000) -#define TLB1_C ASM_CONST(0x0000400000000000) -#define TLB1_RPN_MASK ASM_CONST(0x000003fffffff000) -#define TLB1_W ASM_CONST(0x0000000000000800) -#define TLB1_I ASM_CONST(0x0000000000000400) -#define TLB1_M ASM_CONST(0x0000000000000200) -#define TLB1_G ASM_CONST(0x0000000000000100) -#define TLB1_E ASM_CONST(0x0000000000000080) -#define TLB1_VF ASM_CONST(0x0000000000000040) -#define TLB1_UX ASM_CONST(0x0000000000000020) -#define TLB1_SX ASM_CONST(0x0000000000000010) -#define TLB1_UW ASM_CONST(0x0000000000000008) -#define TLB1_SW ASM_CONST(0x0000000000000004) -#define TLB1_UR ASM_CONST(0x0000000000000002) -#define TLB1_SR ASM_CONST(0x0000000000000001) - -/* A2 erativax attributes definitions */ -#define ERATIVAX_RS_IS_ALL 0x000 -#define ERATIVAX_RS_IS_TID 0x040 -#define ERATIVAX_RS_IS_CLASS 0x080 -#define ERATIVAX_RS_IS_FULLMATCH 0x0c0 -#define ERATIVAX_CLASS_00 0x000 -#define ERATIVAX_CLASS_01 0x010 -#define ERATIVAX_CLASS_10 0x020 -#define ERATIVAX_CLASS_11 0x030 -#define ERATIVAX_PSIZE_4K (TLB_PSIZE_4K >> 1) -#define ERATIVAX_PSIZE_64K (TLB_PSIZE_64K >> 1) -#define ERATIVAX_PSIZE_1M (TLB_PSIZE_1M >> 1) -#define ERATIVAX_PSIZE_16M (TLB_PSIZE_16M >> 1) -#define ERATIVAX_PSIZE_1G (TLB_PSIZE_1G >> 1) - -/* A2 eratilx attributes definitions */ -#define ERATILX_T_ALL 0 -#define ERATILX_T_TID 1 -#define ERATILX_T_TGS 2 -#define ERATILX_T_FULLMATCH 3 -#define ERATILX_T_CLASS0 4 -#define ERATILX_T_CLASS1 5 -#define ERATILX_T_CLASS2 6 -#define ERATILX_T_CLASS3 7 - -/* XUCR0 bits */ -#define XUCR0_TRACE_UM_T0 0x40000000 /* Thread 0 */ -#define XUCR0_TRACE_UM_T1 0x20000000 /* Thread 1 */ -#define XUCR0_TRACE_UM_T2 0x10000000 /* Thread 2 */ -#define XUCR0_TRACE_UM_T3 0x08000000 /* Thread 3 */ - -/* A2 CCR0 register */ -#define A2_CCR0_PME_DISABLED 0x00000000 -#define A2_CCR0_PME_SLEEP 0x40000000 -#define A2_CCR0_PME_RVW 0x80000000 -#define A2_CCR0_PME_DISABLED2 0xc0000000 - -/* A2 CCR2 register */ -#define A2_CCR2_ERAT_ONLY_MODE 0x00000001 -#define A2_CCR2_ENABLE_ICSWX 0x00000002 -#define A2_CCR2_ENABLE_PC 0x20000000 -#define A2_CCR2_ENABLE_TRACE 0x40000000 - -#endif /* __ASM_POWERPC_REG_A2_H__ */ diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h index c697c3c746946d..9bb2210c8d4417 100644 --- a/arch/powerpc/include/asm/rtas.h +++ b/arch/powerpc/include/asm/rtas.h @@ -3,6 +3,7 @@ #define _POWERPC_RTAS_H #ifdef __KERNEL__ +#include #include #include #include @@ -201,12 +202,25 @@ typedef struct { /* Memory set aside for sys_rtas to use with calls that need a work area. */ #define RTAS_USER_REGION_SIZE (64 * 1024) -/* RTAS return status codes */ -#define RTAS_HARDWARE_ERROR -1 /* Hardware Error */ -#define RTAS_BUSY -2 /* RTAS Busy */ -#define RTAS_INVALID_PARAMETER -3 /* Invalid indicator/domain/sensor etc. */ -#define RTAS_EXTENDED_DELAY_MIN 9900 -#define RTAS_EXTENDED_DELAY_MAX 9905 +/* + * Common RTAS function return values, derived from the table "RTAS + * Status Word Values" in PAPR+ v2.13 7.2.8: "Return Codes". If a + * function can return a value in this table then generally it has the + * meaning listed here. More extended commentary in the documentation + * for rtas_call(). + * + * RTAS functions may use negative and positive numbers not in this + * set for function-specific error and success conditions, + * respectively. + */ +#define RTAS_SUCCESS 0 /* Success. */ +#define RTAS_HARDWARE_ERROR -1 /* Hardware or other unspecified error. */ +#define RTAS_BUSY -2 /* Retry immediately. */ +#define RTAS_INVALID_PARAMETER -3 /* Invalid indicator/domain/sensor etc. */ +#define RTAS_UNEXPECTED_STATE_CHANGE -7 /* Seems limited to EEH and slot reset. */ +#define RTAS_EXTENDED_DELAY_MIN 9900 /* Retry after delaying for ~1ms. */ +#define RTAS_EXTENDED_DELAY_MAX 9905 /* Retry after delaying for ~100s. */ +#define RTAS_ML_ISOLATION_ERROR -9000 /* Multi-level isolation error. */ /* statuses specific to ibm,suspend-me */ #define RTAS_SUSPEND_ABORTED 9000 /* Suspension aborted */ @@ -268,7 +282,7 @@ typedef struct { #define RTAS_TYPE_DEALLOC 0xE3 #define RTAS_TYPE_DUMP 0xE4 #define RTAS_TYPE_HOTPLUG 0xE5 -/* I don't add PowerMGM events right now, this is a different topic */ +/* I don't add PowerMGM events right now, this is a different topic */ #define RTAS_TYPE_PMGM_POWER_SW_ON 0x60 #define RTAS_TYPE_PMGM_POWER_SW_OFF 0x61 #define RTAS_TYPE_PMGM_LID_OPEN 0x62 @@ -408,44 +422,41 @@ static inline bool rtas_function_implemented(const rtas_fn_handle_t handle) { return rtas_function_token(handle) != RTAS_UNKNOWN_SERVICE; } -extern int rtas_token(const char *service); -extern int rtas_service_present(const char *service); -extern int rtas_call(int token, int, int, int *, ...); +int rtas_token(const char *service); +int rtas_call(int token, int nargs, int nret, int *outputs, ...); void rtas_call_unlocked(struct rtas_args *args, int token, int nargs, int nret, ...); -extern void __noreturn rtas_restart(char *cmd); -extern void rtas_power_off(void); -extern void __noreturn rtas_halt(void); -extern void rtas_os_term(char *str); +void __noreturn rtas_restart(char *cmd); +void rtas_power_off(void); +void __noreturn rtas_halt(void); +void rtas_os_term(char *str); void rtas_activate_firmware(void); -extern int rtas_get_sensor(int sensor, int index, int *state); -extern int rtas_get_sensor_fast(int sensor, int index, int *state); -extern int rtas_get_power_level(int powerdomain, int *level); -extern int rtas_set_power_level(int powerdomain, int level, int *setlevel); -extern bool rtas_indicator_present(int token, int *maxindex); -extern int rtas_set_indicator(int indicator, int index, int new_value); -extern int rtas_set_indicator_fast(int indicator, int index, int new_value); -extern void rtas_progress(char *s, unsigned short hex); +int rtas_get_sensor(int sensor, int index, int *state); +int rtas_get_sensor_fast(int sensor, int index, int *state); +int rtas_get_power_level(int powerdomain, int *level); +int rtas_set_power_level(int powerdomain, int level, int *setlevel); +bool rtas_indicator_present(int token, int *maxindex); +int rtas_set_indicator(int indicator, int index, int new_value); +int rtas_set_indicator_fast(int indicator, int index, int new_value); +void rtas_progress(char *s, unsigned short hex); int rtas_ibm_suspend_me(int *fw_status); int rtas_error_rc(int rtas_rc); struct rtc_time; -extern time64_t rtas_get_boot_time(void); -extern void rtas_get_rtc_time(struct rtc_time *rtc_time); -extern int rtas_set_rtc_time(struct rtc_time *rtc_time); +time64_t rtas_get_boot_time(void); +void rtas_get_rtc_time(struct rtc_time *rtc_time); +int rtas_set_rtc_time(struct rtc_time *rtc_time); -extern unsigned int rtas_busy_delay_time(int status); +unsigned int rtas_busy_delay_time(int status); bool rtas_busy_delay(int status); -extern int early_init_dt_scan_rtas(unsigned long node, - const char *uname, int depth, void *data); +int early_init_dt_scan_rtas(unsigned long node, const char *uname, int depth, void *data); -extern void pSeries_log_error(char *buf, unsigned int err_type, int fatal); +void pSeries_log_error(char *buf, unsigned int err_type, int fatal); #ifdef CONFIG_PPC_PSERIES extern time64_t last_rtas_event; -extern int clobbering_unread_rtas_event(void); -extern void post_mobility_fixup(void); +int clobbering_unread_rtas_event(void); int rtas_syscall_dispatch_ibm_suspend_me(u64 handle); #else static inline int clobbering_unread_rtas_event(void) { return 0; } @@ -456,14 +467,14 @@ static inline int rtas_syscall_dispatch_ibm_suspend_me(u64 handle) #endif #ifdef CONFIG_PPC_RTAS_DAEMON -extern void rtas_cancel_event_scan(void); +void rtas_cancel_event_scan(void); #else static inline void rtas_cancel_event_scan(void) { } #endif /* Error types logged. */ #define ERR_FLAG_ALREADY_LOGGED 0x0 -#define ERR_FLAG_BOOT 0x1 /* log was pulled from NVRAM on boot */ +#define ERR_FLAG_BOOT 0x1 /* log was pulled from NVRAM on boot */ #define ERR_TYPE_RTAS_LOG 0x2 /* from rtas event-scan */ #define ERR_TYPE_KERNEL_PANIC 0x4 /* from die()/panic() */ #define ERR_TYPE_KERNEL_PANIC_GZ 0x8 /* ditto, compressed */ @@ -473,7 +484,7 @@ static inline void rtas_cancel_event_scan(void) { } (ERR_TYPE_RTAS_LOG | ERR_TYPE_KERNEL_PANIC | ERR_TYPE_KERNEL_PANIC_GZ) #define RTAS_DEBUG KERN_DEBUG "RTAS: " - + #define RTAS_ERROR_LOG_MAX 2048 /* @@ -481,7 +492,7 @@ static inline void rtas_cancel_event_scan(void) { } * for all rtas calls that require an error buffer argument. * This includes 'check-exception' and 'rtas-last-error'. */ -extern int rtas_get_error_log_max(void); +int rtas_get_error_log_max(void); /* Event Scan Parameters */ #define EVENT_SCAN_ALL_EVENTS 0xf0000000 @@ -502,6 +513,8 @@ extern char rtas_data_buf[RTAS_DATA_BUF_SIZE]; /* RMO buffer reserved for user-space RTAS use */ extern unsigned long rtas_rmo_buf; +extern struct mutex rtas_ibm_get_vpd_lock; + #define GLOBAL_INTERRUPT_QUEUE 9005 /** @@ -520,8 +533,8 @@ static inline u32 rtas_config_addr(int busno, int devfn, int reg) (devfn << 8) | (reg & 0xff); } -extern void rtas_give_timebase(void); -extern void rtas_take_timebase(void); +void rtas_give_timebase(void); +void rtas_take_timebase(void); #ifdef CONFIG_PPC_RTAS static inline int page_is_rtas_user_buf(unsigned long pfn) @@ -534,7 +547,7 @@ static inline int page_is_rtas_user_buf(unsigned long pfn) /* Not the best place to put pSeries_coalesce_init, will be fixed when we * move some of the rtas suspend-me stuff to pseries */ -extern void pSeries_coalesce_init(void); +void pSeries_coalesce_init(void); void rtas_initialize(void); #else static inline int page_is_rtas_user_buf(unsigned long pfn) { return 0;} @@ -542,8 +555,6 @@ static inline void pSeries_coalesce_init(void) { } static inline void rtas_initialize(void) { } #endif -extern int call_rtas(const char *, int, int, unsigned long *, ...); - #ifdef CONFIG_HV_PERF_CTRS void read_24x7_sys_info(void); #else diff --git a/arch/powerpc/include/uapi/asm/papr-miscdev.h b/arch/powerpc/include/uapi/asm/papr-miscdev.h new file mode 100644 index 00000000000000..49a2a270b7f3bd --- /dev/null +++ b/arch/powerpc/include/uapi/asm/papr-miscdev.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_PAPR_MISCDEV_H_ +#define _UAPI_PAPR_MISCDEV_H_ + +enum { + PAPR_MISCDEV_IOC_ID = 0xb2, +}; + +#endif /* _UAPI_PAPR_MISCDEV_H_ */ diff --git a/arch/powerpc/include/uapi/asm/papr-sysparm.h b/arch/powerpc/include/uapi/asm/papr-sysparm.h new file mode 100644 index 00000000000000..9f9a0f267ea57c --- /dev/null +++ b/arch/powerpc/include/uapi/asm/papr-sysparm.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_PAPR_SYSPARM_H_ +#define _UAPI_PAPR_SYSPARM_H_ + +#include +#include +#include + +enum { + PAPR_SYSPARM_MAX_INPUT = 1024, + PAPR_SYSPARM_MAX_OUTPUT = 4000, +}; + +struct papr_sysparm_io_block { + __u32 parameter; + __u16 length; + char data[PAPR_SYSPARM_MAX_OUTPUT]; +}; + +/** + * PAPR_SYSPARM_IOC_GET - Retrieve the value of a PAPR system parameter. + * + * Uses _IOWR because of one corner case: Retrieving the value of the + * "OS Service Entitlement Status" parameter (60) requires the caller + * to supply input data (a date string) in the buffer passed to + * firmware. So the @length and @data of the incoming + * papr_sysparm_io_block are always used to initialize the work area + * supplied to ibm,get-system-parameter. No other parameters are known + * to parameterize the result this way, and callers are encouraged + * (but not required) to zero-initialize @length and @data in the + * common case. + * + * On error the contents of the ioblock are indeterminate. + * + * Return: + * 0: Success; @length is the length of valid data in @data, not to exceed @PAPR_SYSPARM_MAX_OUTPUT. + * -EIO: Platform error. (-1) + * -EINVAL: Incorrect data length or format. (-9999) + * -EPERM: The calling partition is not allowed to access this parameter. (-9002) + * -EOPNOTSUPP: Parameter not supported on this platform (-3) + */ +#define PAPR_SYSPARM_IOC_GET _IOWR(PAPR_MISCDEV_IOC_ID, 1, struct papr_sysparm_io_block) + +/** + * PAPR_SYSPARM_IOC_SET - Update the value of a PAPR system parameter. + * + * The contents of the ioblock are unchanged regardless of success. + * + * Return: + * 0: Success; the parameter has been updated. + * -EIO: Platform error. (-1) + * -EINVAL: Incorrect data length or format. (-9999) + * -EPERM: The calling partition is not allowed to access this parameter. (-9002) + * -EOPNOTSUPP: Parameter not supported on this platform (-3) + */ +#define PAPR_SYSPARM_IOC_SET _IOW(PAPR_MISCDEV_IOC_ID, 2, struct papr_sysparm_io_block) + +#endif /* _UAPI_PAPR_SYSPARM_H_ */ diff --git a/arch/powerpc/include/uapi/asm/papr-vpd.h b/arch/powerpc/include/uapi/asm/papr-vpd.h new file mode 100644 index 00000000000000..1c88e87cb4208e --- /dev/null +++ b/arch/powerpc/include/uapi/asm/papr-vpd.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_PAPR_VPD_H_ +#define _UAPI_PAPR_VPD_H_ + +#include +#include + +struct papr_location_code { + /* + * PAPR+ v2.13 12.3.2.4 Converged Location Code Rules - Length + * Restrictions. 79 characters plus nul. + */ + char str[80]; +}; + +/* + * ioctl for /dev/papr-vpd. Returns a VPD handle fd corresponding to + * the location code. + */ +#define PAPR_VPD_IOC_CREATE_HANDLE _IOW(PAPR_MISCDEV_IOC_ID, 0, struct papr_location_code) + +#endif /* _UAPI_PAPR_VPD_H_ */ diff --git a/arch/powerpc/kernel/cpu_specs_book3s_64.h b/arch/powerpc/kernel/cpu_specs_book3s_64.h index c370c1b804a903..3ff9757df4c072 100644 --- a/arch/powerpc/kernel/cpu_specs_book3s_64.h +++ b/arch/powerpc/kernel/cpu_specs_book3s_64.h @@ -238,6 +238,21 @@ static struct cpu_spec cpu_specs[] __initdata = { .machine_check_early = __machine_check_early_realmode_p8, .platform = "power8", }, + { /* 2.07-compliant processor, HeXin C2000 processor */ + .pvr_mask = 0xffff0000, + .pvr_value = 0x00660000, + .cpu_name = "HX-C2000", + .cpu_features = CPU_FTRS_POWER8, + .cpu_user_features = COMMON_USER_POWER8, + .cpu_user_features2 = COMMON_USER2_POWER8, + .mmu_features = MMU_FTRS_POWER8, + .icache_bsize = 128, + .dcache_bsize = 128, + .cpu_setup = __setup_cpu_power8, + .cpu_restore = __restore_cpu_power8, + .machine_check_early = __machine_check_early_realmode_p8, + .platform = "power8", + }, { /* 3.00-compliant processor, i.e. Power9 "architected" mode */ .pvr_mask = 0xffffffff, .pvr_value = 0x0f000005, diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index e97a0fd0ae905d..6f6801da9dc1e2 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -20,9 +20,9 @@ #include #include -static struct cpu_spec the_cpu_spec __read_mostly; +static struct cpu_spec the_cpu_spec __ro_after_init; -struct cpu_spec* cur_cpu_spec __read_mostly = NULL; +struct cpu_spec *cur_cpu_spec __ro_after_init = NULL; EXPORT_SYMBOL(cur_cpu_spec); /* The platform string corresponding to the real PVR */ diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S index 7ab4c8c0f1abcb..dcf0591ad3c2d2 100644 --- a/arch/powerpc/kernel/exceptions-64e.S +++ b/arch/powerpc/kernel/exceptions-64e.S @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/powerpc/kernel/firmware.c b/arch/powerpc/kernel/firmware.c index 20328f72f9f2ba..8987eee33dc8f2 100644 --- a/arch/powerpc/kernel/firmware.c +++ b/arch/powerpc/kernel/firmware.c @@ -23,6 +23,8 @@ EXPORT_SYMBOL_GPL(powerpc_firmware_features); #if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_KVM_GUEST) DEFINE_STATIC_KEY_FALSE(kvm_guest); +EXPORT_SYMBOL_GPL(kvm_guest); + int __init check_kvm_guest(void) { struct device_node *hyper_node; diff --git a/arch/powerpc/kernel/interrupt.c b/arch/powerpc/kernel/interrupt.c index c4f6d3c69ba9d3..eca293794a1e83 100644 --- a/arch/powerpc/kernel/interrupt.c +++ b/arch/powerpc/kernel/interrupt.c @@ -3,6 +3,7 @@ #include #include #include +#include #include /* for show_regs */ #include diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index eddc031c4b95f4..7e793b503e29f1 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -70,14 +71,33 @@ struct rtas_filter { * ppc64le, and we want to keep it that way. It does * not make sense for this to be set when @filter * is NULL. + * @lock: Pointer to an optional dedicated per-function mutex. This + * should be set for functions that require multiple calls in + * sequence to complete a single operation, and such sequences + * will disrupt each other if allowed to interleave. Users of + * this function are required to hold the associated lock for + * the duration of the call sequence. Add an explanatory + * comment to the function table entry if setting this member. */ struct rtas_function { s32 token; const bool banned_for_syscall_on_le:1; const char * const name; const struct rtas_filter *filter; + struct mutex *lock; }; +/* + * Per-function locks for sequence-based RTAS functions. + */ +static DEFINE_MUTEX(rtas_ibm_activate_firmware_lock); +static DEFINE_MUTEX(rtas_ibm_get_dynamic_sensor_state_lock); +static DEFINE_MUTEX(rtas_ibm_get_indices_lock); +static DEFINE_MUTEX(rtas_ibm_lpar_perftools_lock); +static DEFINE_MUTEX(rtas_ibm_physical_attestation_lock); +static DEFINE_MUTEX(rtas_ibm_set_dynamic_indicator_lock); +DEFINE_MUTEX(rtas_ibm_get_vpd_lock); + static struct rtas_function rtas_function_table[] __ro_after_init = { [RTAS_FNIDX__CHECK_EXCEPTION] = { .name = "check-exception", @@ -125,6 +145,13 @@ static struct rtas_function rtas_function_table[] __ro_after_init = { .buf_idx1 = -1, .size_idx1 = -1, .buf_idx2 = -1, .size_idx2 = -1, }, + /* + * PAPR+ as of v2.13 doesn't explicitly impose any + * restriction, but this typically requires multiple + * calls before success, and there's no reason to + * allow sequences to interleave. + */ + .lock = &rtas_ibm_activate_firmware_lock, }, [RTAS_FNIDX__IBM_CBE_START_PTCAL] = { .name = "ibm,cbe-start-ptcal", @@ -196,6 +223,13 @@ static struct rtas_function rtas_function_table[] __ro_after_init = { .buf_idx1 = 1, .size_idx1 = -1, .buf_idx2 = -1, .size_idx2 = -1, }, + /* + * PAPR+ v2.13 R1–7.3.19–3 is explicit that the OS + * must not call ibm,get-dynamic-sensor-state with + * different inputs until a non-retry status has been + * returned. + */ + .lock = &rtas_ibm_get_dynamic_sensor_state_lock, }, [RTAS_FNIDX__IBM_GET_INDICES] = { .name = "ibm,get-indices", @@ -203,6 +237,12 @@ static struct rtas_function rtas_function_table[] __ro_after_init = { .buf_idx1 = 2, .size_idx1 = 3, .buf_idx2 = -1, .size_idx2 = -1, }, + /* + * PAPR+ v2.13 R1–7.3.17–2 says that the OS must not + * interleave ibm,get-indices call sequences with + * different inputs. + */ + .lock = &rtas_ibm_get_indices_lock, }, [RTAS_FNIDX__IBM_GET_RIO_TOPOLOGY] = { .name = "ibm,get-rio-topology", @@ -220,6 +260,11 @@ static struct rtas_function rtas_function_table[] __ro_after_init = { .buf_idx1 = 0, .size_idx1 = -1, .buf_idx2 = 1, .size_idx2 = 2, }, + /* + * PAPR+ v2.13 R1–7.3.20–4 indicates that sequences + * should not be allowed to interleave. + */ + .lock = &rtas_ibm_get_vpd_lock, }, [RTAS_FNIDX__IBM_GET_XIVE] = { .name = "ibm,get-xive", @@ -239,6 +284,11 @@ static struct rtas_function rtas_function_table[] __ro_after_init = { .buf_idx1 = 2, .size_idx1 = 3, .buf_idx2 = -1, .size_idx2 = -1, }, + /* + * PAPR+ v2.13 R1–7.3.26–6 says the OS should allow + * only one call sequence in progress at a time. + */ + .lock = &rtas_ibm_lpar_perftools_lock, }, [RTAS_FNIDX__IBM_MANAGE_FLASH_IMAGE] = { .name = "ibm,manage-flash-image", @@ -277,6 +327,14 @@ static struct rtas_function rtas_function_table[] __ro_after_init = { .buf_idx1 = 0, .size_idx1 = 1, .buf_idx2 = -1, .size_idx2 = -1, }, + /* + * This follows a sequence-based pattern similar to + * ibm,get-vpd et al. Since PAPR+ restricts + * interleaving call sequences for other functions of + * this style, assume the restriction applies here, + * even though it's not explicit in the spec. + */ + .lock = &rtas_ibm_physical_attestation_lock, }, [RTAS_FNIDX__IBM_PLATFORM_DUMP] = { .name = "ibm,platform-dump", @@ -284,6 +342,13 @@ static struct rtas_function rtas_function_table[] __ro_after_init = { .buf_idx1 = 4, .size_idx1 = 5, .buf_idx2 = -1, .size_idx2 = -1, }, + /* + * PAPR+ v2.13 7.3.3.4.1 indicates that concurrent + * sequences of ibm,platform-dump are allowed if they + * are operating on different dump tags. So leave the + * lock pointer unset for now. This may need + * reconsideration if kernel-internal users appear. + */ }, [RTAS_FNIDX__IBM_POWER_OFF_UPS] = { .name = "ibm,power-off-ups", @@ -326,6 +391,12 @@ static struct rtas_function rtas_function_table[] __ro_after_init = { .buf_idx1 = 2, .size_idx1 = -1, .buf_idx2 = -1, .size_idx2 = -1, }, + /* + * PAPR+ v2.13 R1–7.3.18–3 says the OS must not call + * this function with different inputs until a + * non-retry status has been returned. + */ + .lock = &rtas_ibm_set_dynamic_indicator_lock, }, [RTAS_FNIDX__IBM_SET_EEH_OPTION] = { .name = "ibm,set-eeh-option", @@ -454,6 +525,11 @@ static struct rtas_function rtas_function_table[] __ro_after_init = { }, }; +#define for_each_rtas_function(funcp) \ + for (funcp = &rtas_function_table[0]; \ + funcp < &rtas_function_table[ARRAY_SIZE(rtas_function_table)]; \ + ++funcp) + /* * Nearly all RTAS calls need to be serialized. All uses of the * default rtas_args block must hold rtas_lock. @@ -525,10 +601,10 @@ static DEFINE_XARRAY(rtas_token_to_function_xarray); static int __init rtas_token_to_function_xarray_init(void) { + const struct rtas_function *func; int err = 0; - for (size_t i = 0; i < ARRAY_SIZE(rtas_function_table); ++i) { - const struct rtas_function *func = &rtas_function_table[i]; + for_each_rtas_function(func) { const s32 token = func->token; if (token == RTAS_UNKNOWN_SERVICE) @@ -544,6 +620,21 @@ static int __init rtas_token_to_function_xarray_init(void) } arch_initcall(rtas_token_to_function_xarray_init); +/* + * For use by sys_rtas(), where the token value is provided by user + * space and we don't want to warn on failed lookups. + */ +static const struct rtas_function *rtas_token_to_function_untrusted(s32 token) +{ + return xa_load(&rtas_token_to_function_xarray, token); +} + +/* + * Reverse lookup for deriving the function descriptor from a + * known-good token value in contexts where the former is not already + * available. @token must be valid, e.g. derived from the result of a + * prior lookup against the function table. + */ static const struct rtas_function *rtas_token_to_function(s32 token) { const struct rtas_function *func; @@ -551,12 +642,22 @@ static const struct rtas_function *rtas_token_to_function(s32 token) if (WARN_ONCE(token < 0, "invalid token %d", token)) return NULL; - func = xa_load(&rtas_token_to_function_xarray, token); - - if (WARN_ONCE(!func, "unexpected failed lookup for token %d", token)) - return NULL; + func = rtas_token_to_function_untrusted(token); + if (func) + return func; + /* + * Fall back to linear scan in case the reverse mapping hasn't + * been initialized yet. + */ + if (xa_empty(&rtas_token_to_function_xarray)) { + for_each_rtas_function(func) { + if (func->token == token) + return func; + } + } - return func; + WARN_ONCE(true, "unexpected failed lookup for token %d", token); + return NULL; } /* This is here deliberately so it's only used in this file */ @@ -570,28 +671,25 @@ static void __do_enter_rtas(struct rtas_args *args) static void __do_enter_rtas_trace(struct rtas_args *args) { - const char *name = NULL; + const struct rtas_function *func = rtas_token_to_function(be32_to_cpu(args->token)); - if (args == &rtas_args) - lockdep_assert_held(&rtas_lock); /* - * If the tracepoints that consume the function name aren't - * active, avoid the lookup. + * If there is a per-function lock, it must be held by the + * caller. */ - if ((trace_rtas_input_enabled() || trace_rtas_output_enabled())) { - const s32 token = be32_to_cpu(args->token); - const struct rtas_function *func = rtas_token_to_function(token); + if (func->lock) + lockdep_assert_held(func->lock); - name = func->name; - } + if (args == &rtas_args) + lockdep_assert_held(&rtas_lock); - trace_rtas_input(args, name); + trace_rtas_input(args, func->name); trace_rtas_ll_entry(args); __do_enter_rtas(args); trace_rtas_ll_exit(args); - trace_rtas_output(args, name); + trace_rtas_output(args, func->name); } static void do_enter_rtas(struct rtas_args *args) @@ -670,7 +768,7 @@ static void call_rtas_display_status_delay(char c) static int pending_newline = 0; /* did last write end with unprinted newline? */ static int width = 16; - if (c == '\n') { + if (c == '\n') { while (width-- > 0) call_rtas_display_status(' '); width = 16; @@ -680,7 +778,7 @@ static void call_rtas_display_status_delay(char c) if (pending_newline) { call_rtas_display_status('\r'); call_rtas_display_status('\n'); - } + } pending_newline = 0; if (width--) { call_rtas_display_status(c); @@ -820,7 +918,7 @@ void rtas_progress(char *s, unsigned short hex) else rtas_call(display_character, 1, 1, NULL, '\r'); } - + if (row_width) width = row_width[current_line]; else @@ -840,9 +938,9 @@ void rtas_progress(char *s, unsigned short hex) spin_unlock(&progress_lock); return; } - + /* RTAS wants CR-LF, not just LF */ - + if (*os == '\n') { rtas_call(display_character, 1, 1, NULL, '\r'); rtas_call(display_character, 1, 1, NULL, '\n'); @@ -852,7 +950,7 @@ void rtas_progress(char *s, unsigned short hex) */ rtas_call(display_character, 1, 1, NULL, *os); } - + if (row_width) width = row_width[current_line]; else @@ -861,15 +959,15 @@ void rtas_progress(char *s, unsigned short hex) width--; rtas_call(display_character, 1, 1, NULL, *os); } - + os++; - + /* if we overwrite the screen length */ if (width <= 0) while ((*os != 0) && (*os != '\n') && (*os != '\r')) os++; } - + spin_unlock(&progress_lock); } EXPORT_SYMBOL_GPL(rtas_progress); /* needed by rtas_flash module */ @@ -900,11 +998,6 @@ int rtas_token(const char *service) } EXPORT_SYMBOL_GPL(rtas_token); -int rtas_service_present(const char *service) -{ - return rtas_token(service) != RTAS_UNKNOWN_SERVICE; -} - #ifdef CONFIG_RTAS_ERROR_LOGGING static u32 rtas_error_log_max __ro_after_init = RTAS_ERROR_LOG_MAX; @@ -1638,10 +1731,14 @@ void rtas_activate_firmware(void) return; } + mutex_lock(&rtas_ibm_activate_firmware_lock); + do { fwrc = rtas_call(token, 0, 1, NULL); } while (rtas_busy_delay(fwrc)); + mutex_unlock(&rtas_ibm_activate_firmware_lock); + if (fwrc) pr_err("ibm,activate-firmware failed (%i)\n", fwrc); } @@ -1713,24 +1810,18 @@ static bool in_rmo_buf(u32 base, u32 end) end < (rtas_rmo_buf + RTAS_USER_REGION_SIZE); } -static bool block_rtas_call(int token, int nargs, +static bool block_rtas_call(const struct rtas_function *func, int nargs, struct rtas_args *args) { - const struct rtas_function *func; const struct rtas_filter *f; - const bool is_platform_dump = token == rtas_function_token(RTAS_FN_IBM_PLATFORM_DUMP); - const bool is_config_conn = token == rtas_function_token(RTAS_FN_IBM_CONFIGURE_CONNECTOR); + const bool is_platform_dump = + func == &rtas_function_table[RTAS_FNIDX__IBM_PLATFORM_DUMP]; + const bool is_config_conn = + func == &rtas_function_table[RTAS_FNIDX__IBM_CONFIGURE_CONNECTOR]; u32 base, size, end; /* - * If this token doesn't correspond to a function the kernel - * understands, you're not allowed to call it. - */ - func = rtas_token_to_function(token); - if (!func) - goto err; - /* - * And only functions with filters attached are allowed. + * Only functions with filters attached are allowed. */ f = func->filter; if (!f) @@ -1787,14 +1878,15 @@ static bool block_rtas_call(int token, int nargs, return false; err: pr_err_ratelimited("sys_rtas: RTAS call blocked - exploit attempt?\n"); - pr_err_ratelimited("sys_rtas: token=0x%x, nargs=%d (called by %s)\n", - token, nargs, current->comm); + pr_err_ratelimited("sys_rtas: %s nargs=%d (called by %s)\n", + func->name, nargs, current->comm); return true; } /* We assume to be passed big endian arguments */ SYSCALL_DEFINE1(rtas, struct rtas_args __user *, uargs) { + const struct rtas_function *func; struct pin_cookie cookie; struct rtas_args args; unsigned long flags; @@ -1824,13 +1916,18 @@ SYSCALL_DEFINE1(rtas, struct rtas_args __user *, uargs) nargs * sizeof(rtas_arg_t)) != 0) return -EFAULT; - if (token == RTAS_UNKNOWN_SERVICE) + /* + * If this token doesn't correspond to a function the kernel + * understands, you're not allowed to call it. + */ + func = rtas_token_to_function_untrusted(token); + if (!func) return -EINVAL; args.rets = &args.args[nargs]; memset(args.rets, 0, nret * sizeof(rtas_arg_t)); - if (block_rtas_call(token, nargs, &args)) + if (block_rtas_call(func, nargs, &args)) return -EINVAL; if (token_is_restricted_errinjct(token)) { @@ -1863,6 +1960,15 @@ SYSCALL_DEFINE1(rtas, struct rtas_args __user *, uargs) buff_copy = get_errorlog_buffer(); + /* + * If this function has a mutex assigned to it, we must + * acquire it to avoid interleaving with any kernel-based uses + * of the same function. Kernel-based sequences acquire the + * appropriate mutex explicitly. + */ + if (func->lock) + mutex_lock(func->lock); + raw_spin_lock_irqsave(&rtas_lock, flags); cookie = lockdep_pin_lock(&rtas_lock); @@ -1878,6 +1984,9 @@ SYSCALL_DEFINE1(rtas, struct rtas_args __user *, uargs) lockdep_unpin_lock(&rtas_lock, cookie); raw_spin_unlock_irqrestore(&rtas_lock, flags); + if (func->lock) + mutex_unlock(func->lock); + if (buff_copy) { if (errbuf) log_error(errbuf, ERR_TYPE_RTAS_LOG, 0); diff --git a/arch/powerpc/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c index e1fdc7473b72c1..fccf96e897f6a7 100644 --- a/arch/powerpc/kernel/rtas_pci.c +++ b/arch/powerpc/kernel/rtas_pci.c @@ -43,7 +43,7 @@ static inline int config_access_valid(struct pci_dn *dn, int where) return 0; } -int rtas_read_config(struct pci_dn *pdn, int where, int size, u32 *val) +int rtas_pci_dn_read_config(struct pci_dn *pdn, int where, int size, u32 *val) { int returnval = -1; unsigned long buid, addr; @@ -87,7 +87,7 @@ static int rtas_pci_read_config(struct pci_bus *bus, pdn = pci_get_pdn_by_devfn(bus, devfn); /* Validity of pdn is checked in here */ - ret = rtas_read_config(pdn, where, size, val); + ret = rtas_pci_dn_read_config(pdn, where, size, val); if (*val == EEH_IO_ERROR_VALUE(size) && eeh_dev_check_failure(pdn_to_eeh_dev(pdn))) return PCIBIOS_DEVICE_NOT_FOUND; @@ -95,7 +95,7 @@ static int rtas_pci_read_config(struct pci_bus *bus, return ret; } -int rtas_write_config(struct pci_dn *pdn, int where, int size, u32 val) +int rtas_pci_dn_write_config(struct pci_dn *pdn, int where, int size, u32 val) { unsigned long buid, addr; int ret; @@ -134,7 +134,7 @@ static int rtas_pci_write_config(struct pci_bus *bus, pdn = pci_get_pdn_by_devfn(bus, devfn); /* Validity of pdn is checked in here. */ - return rtas_write_config(pdn, where, size, val); + return rtas_pci_dn_write_config(pdn, where, size, val); } static struct pci_ops rtas_pci_ops = { diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index ab691c89d78725..693334c20d07db 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -77,10 +77,10 @@ static DEFINE_PER_CPU(int, cpu_state) = { 0 }; #endif struct task_struct *secondary_current; -bool has_big_cores; -bool coregroup_enabled; -bool thread_group_shares_l2; -bool thread_group_shares_l3; +bool has_big_cores __ro_after_init; +bool coregroup_enabled __ro_after_init; +bool thread_group_shares_l2 __ro_after_init; +bool thread_group_shares_l3 __ro_after_init; DEFINE_PER_CPU(cpumask_var_t, cpu_sibling_map); DEFINE_PER_CPU(cpumask_var_t, cpu_smallcore_map); @@ -93,15 +93,6 @@ EXPORT_PER_CPU_SYMBOL(cpu_l2_cache_map); EXPORT_PER_CPU_SYMBOL(cpu_core_map); EXPORT_SYMBOL_GPL(has_big_cores); -enum { -#ifdef CONFIG_SCHED_SMT - smt_idx, -#endif - cache_idx, - mc_idx, - die_idx, -}; - #define MAX_THREAD_LIST_SIZE 8 #define THREAD_GROUP_SHARE_L1 1 #define THREAD_GROUP_SHARE_L2_L3 2 @@ -987,7 +978,7 @@ static int __init init_thread_group_cache_map(int cpu, int cache_property) return 0; } -static bool shared_caches; +static bool shared_caches __ro_after_init; #ifdef CONFIG_SCHED_SMT /* cpumask of CPUs with asymmetric SMT dependency */ @@ -1003,6 +994,13 @@ static int powerpc_smt_flags(void) } #endif +/* + * On shared processor LPARs scheduled on a big core (which has two or more + * independent thread groups per core), prefer lower numbered CPUs, so + * that workload consolidates to lesser number of cores. + */ +static __ro_after_init DEFINE_STATIC_KEY_FALSE(splpar_asym_pack); + /* * P9 has a slightly odd architecture where pairs of cores share an L2 cache. * This topology makes it *much* cheaper to migrate tasks between adjacent cores @@ -1011,9 +1009,20 @@ static int powerpc_smt_flags(void) */ static int powerpc_shared_cache_flags(void) { + if (static_branch_unlikely(&splpar_asym_pack)) + return SD_SHARE_PKG_RESOURCES | SD_ASYM_PACKING; + return SD_SHARE_PKG_RESOURCES; } +static int powerpc_shared_proc_flags(void) +{ + if (static_branch_unlikely(&splpar_asym_pack)) + return SD_ASYM_PACKING; + + return 0; +} + /* * We can't just pass cpu_l2_cache_mask() directly because * returns a non-const pointer and the compiler barfs on that. @@ -1037,6 +1046,10 @@ static struct cpumask *cpu_coregroup_mask(int cpu) static bool has_coregroup_support(void) { + /* Coregroup identification not available on shared systems */ + if (is_shared_processor()) + return 0; + return coregroup_enabled; } @@ -1045,16 +1058,6 @@ static const struct cpumask *cpu_mc_mask(int cpu) return cpu_coregroup_mask(cpu); } -static struct sched_domain_topology_level powerpc_topology[] = { -#ifdef CONFIG_SCHED_SMT - { cpu_smt_mask, powerpc_smt_flags, SD_INIT_NAME(SMT) }, -#endif - { shared_cache_mask, powerpc_shared_cache_flags, SD_INIT_NAME(CACHE) }, - { cpu_mc_mask, SD_INIT_NAME(MC) }, - { cpu_cpu_mask, SD_INIT_NAME(PKG) }, - { NULL, }, -}; - static int __init init_big_cores(void) { int cpu; @@ -1682,43 +1685,45 @@ void start_secondary(void *unused) BUG(); } -static void __init fixup_topology(void) +static struct sched_domain_topology_level powerpc_topology[6]; + +static void __init build_sched_topology(void) { - int i; + int i = 0; + + if (is_shared_processor() && has_big_cores) + static_branch_enable(&splpar_asym_pack); #ifdef CONFIG_SCHED_SMT if (has_big_cores) { pr_info("Big cores detected but using small core scheduling\n"); - powerpc_topology[smt_idx].mask = smallcore_smt_mask; + powerpc_topology[i++] = (struct sched_domain_topology_level){ + smallcore_smt_mask, powerpc_smt_flags, SD_INIT_NAME(SMT) + }; + } else { + powerpc_topology[i++] = (struct sched_domain_topology_level){ + cpu_smt_mask, powerpc_smt_flags, SD_INIT_NAME(SMT) + }; } #endif + if (shared_caches) { + powerpc_topology[i++] = (struct sched_domain_topology_level){ + shared_cache_mask, powerpc_shared_cache_flags, SD_INIT_NAME(CACHE) + }; + } + if (has_coregroup_support()) { + powerpc_topology[i++] = (struct sched_domain_topology_level){ + cpu_mc_mask, powerpc_shared_proc_flags, SD_INIT_NAME(MC) + }; + } + powerpc_topology[i++] = (struct sched_domain_topology_level){ + cpu_cpu_mask, powerpc_shared_proc_flags, SD_INIT_NAME(PKG) + }; - if (!has_coregroup_support()) - powerpc_topology[mc_idx].mask = powerpc_topology[cache_idx].mask; - - /* - * Try to consolidate topology levels here instead of - * allowing scheduler to degenerate. - * - Dont consolidate if masks are different. - * - Dont consolidate if sd_flags exists and are different. - */ - for (i = 1; i <= die_idx; i++) { - if (powerpc_topology[i].mask != powerpc_topology[i - 1].mask) - continue; - - if (powerpc_topology[i].sd_flags && powerpc_topology[i - 1].sd_flags && - powerpc_topology[i].sd_flags != powerpc_topology[i - 1].sd_flags) - continue; - - if (!powerpc_topology[i - 1].sd_flags) - powerpc_topology[i - 1].sd_flags = powerpc_topology[i].sd_flags; + /* There must be one trailing NULL entry left. */ + BUG_ON(i >= ARRAY_SIZE(powerpc_topology) - 1); - powerpc_topology[i].mask = powerpc_topology[i + 1].mask; - powerpc_topology[i].sd_flags = powerpc_topology[i + 1].sd_flags; -#ifdef CONFIG_SCHED_DEBUG - powerpc_topology[i].name = powerpc_topology[i + 1].name; -#endif - } + set_sched_topology(powerpc_topology); } void __init smp_cpus_done(unsigned int max_cpus) @@ -1733,9 +1738,20 @@ void __init smp_cpus_done(unsigned int max_cpus) smp_ops->bringup_done(); dump_numa_cpu_topology(); + build_sched_topology(); +} - fixup_topology(); - set_sched_topology(powerpc_topology); +/* + * For asym packing, by default lower numbered CPU has higher priority. + * On shared processors, pack to lower numbered core. However avoid moving + * between thread_groups within the same core. + */ +int arch_asym_cpu_priority(int cpu) +{ + if (static_branch_unlikely(&splpar_asym_pack)) + return -cpu / threads_per_core; + + return -cpu; } #ifdef CONFIG_HOTPLUG_CPU diff --git a/arch/powerpc/kernel/swsusp_64.c b/arch/powerpc/kernel/swsusp_64.c index 16ee3baaf09ad5..50fa8fc9ef958e 100644 --- a/arch/powerpc/kernel/swsusp_64.c +++ b/arch/powerpc/kernel/swsusp_64.c @@ -11,6 +11,8 @@ #include #include +void do_after_copyback(void); + void do_after_copyback(void) { iommu_restore(); diff --git a/arch/powerpc/kernel/syscalls/syscall.tbl b/arch/powerpc/kernel/syscalls/syscall.tbl index 7fab411378f2dd..17173b82ca21dc 100644 --- a/arch/powerpc/kernel/syscalls/syscall.tbl +++ b/arch/powerpc/kernel/syscalls/syscall.tbl @@ -543,3 +543,8 @@ 454 common futex_wake sys_futex_wake 455 common futex_wait sys_futex_wait 456 common futex_requeue sys_futex_requeue +457 common statmount sys_statmount +458 common listmount sys_listmount +459 common lsm_get_self_attr sys_lsm_get_self_attr +460 common lsm_set_self_attr sys_lsm_set_self_attr +461 common lsm_list_modules sys_lsm_list_modules diff --git a/arch/powerpc/kernel/trace/ftrace_entry.S b/arch/powerpc/kernel/trace/ftrace_entry.S index 40677416d7b262..76dbe9fd2c0f22 100644 --- a/arch/powerpc/kernel/trace/ftrace_entry.S +++ b/arch/powerpc/kernel/trace/ftrace_entry.S @@ -162,7 +162,6 @@ _GLOBAL(ftrace_regs_caller) .globl ftrace_regs_call ftrace_regs_call: bl ftrace_stub - nop ftrace_regs_exit 1 _GLOBAL(ftrace_caller) @@ -171,7 +170,6 @@ _GLOBAL(ftrace_caller) .globl ftrace_call ftrace_call: bl ftrace_stub - nop ftrace_regs_exit 0 _GLOBAL(ftrace_stub) diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 5ea2014aff90dc..11e062b47d3f80 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -1439,10 +1439,12 @@ static int emulate_instruction(struct pt_regs *regs) return -EINVAL; } +#ifdef CONFIG_GENERIC_BUG int is_valid_bugaddr(unsigned long addr) { return is_kernel_addr(addr); } +#endif #ifdef CONFIG_MATH_EMULATION static int emulate_math(struct pt_regs *regs) diff --git a/arch/powerpc/kernel/udbg_16550.c b/arch/powerpc/kernel/udbg_16550.c index 74ddf836f7a264..a0467e528b7002 100644 --- a/arch/powerpc/kernel/udbg_16550.c +++ b/arch/powerpc/kernel/udbg_16550.c @@ -7,7 +7,6 @@ #include #include #include -#include #include extern u8 real_readb(volatile u8 __iomem *addr); diff --git a/arch/powerpc/kernel/vdso/Makefile b/arch/powerpc/kernel/vdso/Makefile index 0c7d82c270c37a..1b93655c2857e5 100644 --- a/arch/powerpc/kernel/vdso/Makefile +++ b/arch/powerpc/kernel/vdso/Makefile @@ -71,7 +71,7 @@ AS64FLAGS := -D__VDSO64__ targets += vdso32.lds CPPFLAGS_vdso32.lds += -P -C -Upowerpc targets += vdso64.lds -CPPFLAGS_vdso64.lds += -P -C -U$(ARCH) +CPPFLAGS_vdso64.lds += -P -C # link rule for the .so file, .lds has to be first $(obj)/vdso32.so.dbg: $(src)/vdso32.lds $(obj-vdso32) $(obj)/vgettimeofday-32.o FORCE diff --git a/arch/powerpc/kexec/core.c b/arch/powerpc/kexec/core.c index 85846cadb9b555..27fa9098a5b74b 100644 --- a/arch/powerpc/kexec/core.c +++ b/arch/powerpc/kexec/core.c @@ -75,6 +75,7 @@ void arch_crash_save_vmcoreinfo(void) VMCOREINFO_OFFSET(mmu_psize_def, shift); #endif VMCOREINFO_SYMBOL(cur_cpu_spec); + VMCOREINFO_OFFSET(cpu_spec, cpu_features); VMCOREINFO_OFFSET(cpu_spec, mmu_features); vmcoreinfo_append_str("NUMBER(RADIX_MMU)=%d\n", early_radix_enabled()); vmcoreinfo_append_str("KERNELOFFSET=%lx\n", kaslr_offset()); diff --git a/arch/powerpc/kexec/core_64.c b/arch/powerpc/kexec/core_64.c index 0bee7ca9a77c62..762e4d09aacfab 100644 --- a/arch/powerpc/kexec/core_64.c +++ b/arch/powerpc/kexec/core_64.c @@ -283,8 +283,7 @@ static void kexec_prepare_cpus(void) * We could use a smaller stack if we don't care about anything using * current, but that audit has not been performed. */ -static union thread_union kexec_stack __init_task_data = - { }; +static union thread_union kexec_stack = { }; /* * For similar reasons to the stack above, the kexecing CPU needs to be on a diff --git a/arch/powerpc/kexec/elf_64.c b/arch/powerpc/kexec/elf_64.c index eeb258002d1e02..904016cf89ea46 100644 --- a/arch/powerpc/kexec/elf_64.c +++ b/arch/powerpc/kexec/elf_64.c @@ -59,7 +59,7 @@ static void *elf64_load(struct kimage *image, char *kernel_buf, if (ret) goto out; - pr_debug("Loaded the kernel at 0x%lx\n", kernel_load_addr); + kexec_dprintk("Loaded the kernel at 0x%lx\n", kernel_load_addr); ret = kexec_load_purgatory(image, &pbuf); if (ret) { @@ -67,7 +67,7 @@ static void *elf64_load(struct kimage *image, char *kernel_buf, goto out; } - pr_debug("Loaded purgatory at 0x%lx\n", pbuf.mem); + kexec_dprintk("Loaded purgatory at 0x%lx\n", pbuf.mem); /* Load additional segments needed for panic kernel */ if (image->type == KEXEC_TYPE_CRASH) { @@ -99,7 +99,7 @@ static void *elf64_load(struct kimage *image, char *kernel_buf, goto out; initrd_load_addr = kbuf.mem; - pr_debug("Loaded initrd at 0x%lx\n", initrd_load_addr); + kexec_dprintk("Loaded initrd at 0x%lx\n", initrd_load_addr); } fdt = of_kexec_alloc_and_setup_fdt(image, initrd_load_addr, @@ -132,7 +132,7 @@ static void *elf64_load(struct kimage *image, char *kernel_buf, fdt_load_addr = kbuf.mem; - pr_debug("Loaded device tree at 0x%lx\n", fdt_load_addr); + kexec_dprintk("Loaded device tree at 0x%lx\n", fdt_load_addr); slave_code = elf_info.buffer + elf_info.proghdrs[0].p_offset; ret = setup_purgatory_ppc64(image, slave_code, fdt, kernel_load_addr, diff --git a/arch/powerpc/kexec/file_load_64.c b/arch/powerpc/kexec/file_load_64.c index 961a6dd6736566..5b4c5cb2335485 100644 --- a/arch/powerpc/kexec/file_load_64.c +++ b/arch/powerpc/kexec/file_load_64.c @@ -577,7 +577,7 @@ static int add_usable_mem_property(void *fdt, struct device_node *dn, NODE_PATH_LEN, dn); return -EOVERFLOW; } - pr_debug("Memory node path: %s\n", path); + kexec_dprintk("Memory node path: %s\n", path); /* Now that we know the path, find its offset in kdump kernel's fdt */ node = fdt_path_offset(fdt, path); @@ -590,8 +590,8 @@ static int add_usable_mem_property(void *fdt, struct device_node *dn, /* Get the address & size cells */ n_mem_addr_cells = of_n_addr_cells(dn); n_mem_size_cells = of_n_size_cells(dn); - pr_debug("address cells: %d, size cells: %d\n", n_mem_addr_cells, - n_mem_size_cells); + kexec_dprintk("address cells: %d, size cells: %d\n", n_mem_addr_cells, + n_mem_size_cells); um_info->idx = 0; if (!check_realloc_usable_mem(um_info, 2)) { @@ -664,7 +664,7 @@ static int update_usable_mem_fdt(void *fdt, struct crash_mem *usable_mem) node = fdt_path_offset(fdt, "/ibm,dynamic-reconfiguration-memory"); if (node == -FDT_ERR_NOTFOUND) - pr_debug("No dynamic reconfiguration memory found\n"); + kexec_dprintk("No dynamic reconfiguration memory found\n"); else if (node < 0) { pr_err("Malformed device tree: error reading /ibm,dynamic-reconfiguration-memory.\n"); return -EINVAL; @@ -776,8 +776,8 @@ static void update_backup_region_phdr(struct kimage *image, Elf64_Ehdr *ehdr) for (i = 0; i < ehdr->e_phnum; i++) { if (phdr->p_paddr == BACKUP_SRC_START) { phdr->p_offset = image->arch.backup_start; - pr_debug("Backup region offset updated to 0x%lx\n", - image->arch.backup_start); + kexec_dprintk("Backup region offset updated to 0x%lx\n", + image->arch.backup_start); return; } } @@ -850,7 +850,7 @@ int load_crashdump_segments_ppc64(struct kimage *image, pr_err("Failed to load backup segment\n"); return ret; } - pr_debug("Loaded the backup region at 0x%lx\n", kbuf->mem); + kexec_dprintk("Loaded the backup region at 0x%lx\n", kbuf->mem); /* Load elfcorehdr segment - to export crashing kernel's vmcore */ ret = load_elfcorehdr_segment(image, kbuf); @@ -858,8 +858,8 @@ int load_crashdump_segments_ppc64(struct kimage *image, pr_err("Failed to load elfcorehdr segment\n"); return ret; } - pr_debug("Loaded elf core header at 0x%lx, bufsz=0x%lx memsz=0x%lx\n", - image->elf_load_addr, kbuf->bufsz, kbuf->memsz); + kexec_dprintk("Loaded elf core header at 0x%lx, bufsz=0x%lx memsz=0x%lx\n", + image->elf_load_addr, kbuf->bufsz, kbuf->memsz); return 0; } diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig index 902611954200df..074263429faf2e 100644 --- a/arch/powerpc/kvm/Kconfig +++ b/arch/powerpc/kvm/Kconfig @@ -19,13 +19,11 @@ if VIRTUALIZATION config KVM bool - select PREEMPT_NOTIFIERS - select HAVE_KVM_EVENTFD + select KVM_COMMON select HAVE_KVM_VCPU_ASYNC_IOCTL select KVM_VFIO select IRQ_BYPASS_MANAGER select HAVE_KVM_IRQ_BYPASS - select INTERVAL_TREE config KVM_BOOK3S_HANDLER bool @@ -42,7 +40,7 @@ config KVM_BOOK3S_64_HANDLER config KVM_BOOK3S_PR_POSSIBLE bool select KVM_MMIO - select MMU_NOTIFIER + select KVM_GENERIC_MMU_NOTIFIER config KVM_BOOK3S_HV_POSSIBLE bool @@ -85,7 +83,7 @@ config KVM_BOOK3S_64_HV tristate "KVM for POWER7 and later using hypervisor mode in host" depends on KVM_BOOK3S_64 && PPC_POWERNV select KVM_BOOK3S_HV_POSSIBLE - select MMU_NOTIFIER + select KVM_GENERIC_MMU_NOTIFIER select CMA help Support running unmodified book3s_64 guest kernels in @@ -194,7 +192,7 @@ config KVM_E500V2 depends on !CONTEXT_TRACKING_USER select KVM select KVM_MMIO - select MMU_NOTIFIER + select KVM_GENERIC_MMU_NOTIFIER help Support running unmodified E500 guest kernels in virtual machines on E500v2 host processors. @@ -211,7 +209,7 @@ config KVM_E500MC select KVM select KVM_MMIO select KVM_BOOKE_HV - select MMU_NOTIFIER + select KVM_GENERIC_MMU_NOTIFIER help Support running unmodified E500MC/E5500/E6500 guest kernels in virtual machines on E500MC/E5500/E6500 host processors. @@ -225,7 +223,6 @@ config KVM_MPIC bool "KVM in-kernel MPIC emulation" depends on KVM && PPC_E500 select HAVE_KVM_IRQCHIP - select HAVE_KVM_IRQFD select HAVE_KVM_IRQ_ROUTING select HAVE_KVM_MSI help @@ -238,7 +235,6 @@ config KVM_XICS bool "KVM in-kernel XICS emulation" depends on KVM_BOOK3S_64 && !KVM_MPIC select HAVE_KVM_IRQCHIP - select HAVE_KVM_IRQFD default y help Include support for the XICS (eXternal Interrupt Controller diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c index 6cd20ab9e94eed..8acec144120eaf 100644 --- a/arch/powerpc/kvm/book3s.c +++ b/arch/powerpc/kvm/book3s.c @@ -302,11 +302,11 @@ static int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu, switch (priority) { case BOOK3S_IRQPRIO_DECREMENTER: - deliver = (kvmppc_get_msr(vcpu) & MSR_EE) && !crit; + deliver = !kvmhv_is_nestedv2() && (kvmppc_get_msr(vcpu) & MSR_EE) && !crit; vec = BOOK3S_INTERRUPT_DECREMENTER; break; case BOOK3S_IRQPRIO_EXTERNAL: - deliver = (kvmppc_get_msr(vcpu) & MSR_EE) && !crit; + deliver = !kvmhv_is_nestedv2() && (kvmppc_get_msr(vcpu) & MSR_EE) && !crit; vec = BOOK3S_INTERRUPT_EXTERNAL; break; case BOOK3S_IRQPRIO_SYSTEM_RESET: diff --git a/arch/powerpc/kvm/book3s_64_mmu_radix.c b/arch/powerpc/kvm/book3s_64_mmu_radix.c index 175a8eb2681fca..4a1abb9f7c0581 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_radix.c +++ b/arch/powerpc/kvm/book3s_64_mmu_radix.c @@ -40,6 +40,9 @@ unsigned long __kvmhv_copy_tofrom_guest_radix(int lpid, int pid, unsigned long quadrant, ret = n; bool is_load = !!to; + if (kvmhv_is_nestedv2()) + return H_UNSUPPORTED; + /* Can't access quadrants 1 or 2 in non-HV mode, call the HV to do it */ if (kvmhv_on_pseries()) return plpar_hcall_norets(H_COPY_TOFROM_GUEST, lpid, pid, eaddr, @@ -97,7 +100,7 @@ static long kvmhv_copy_tofrom_guest_radix(struct kvm_vcpu *vcpu, gva_t eaddr, void *to, void *from, unsigned long n) { int lpid = vcpu->kvm->arch.lpid; - int pid = kvmppc_get_pid(vcpu); + int pid; /* This would cause a data segment intr so don't allow the access */ if (eaddr & (0x3FFUL << 52)) @@ -110,6 +113,8 @@ static long kvmhv_copy_tofrom_guest_radix(struct kvm_vcpu *vcpu, gva_t eaddr, /* If accessing quadrant 3 then pid is expected to be 0 */ if (((eaddr >> 62) & 0x3) == 0x3) pid = 0; + else + pid = kvmppc_get_pid(vcpu); eaddr &= ~(0xFFFUL << 52); diff --git a/arch/powerpc/kvm/book3s_64_vio.c b/arch/powerpc/kvm/book3s_64_vio.c index 14c6d7e318da59..b569ebaa590e2d 100644 --- a/arch/powerpc/kvm/book3s_64_vio.c +++ b/arch/powerpc/kvm/book3s_64_vio.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 1ed6ec140701d5..52427fc2a33fa4 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -650,7 +650,8 @@ static unsigned long do_h_register_vpa(struct kvm_vcpu *vcpu, return err; } -static void kvmppc_update_vpa(struct kvm_vcpu *vcpu, struct kvmppc_vpa *vpap) +static void kvmppc_update_vpa(struct kvm_vcpu *vcpu, struct kvmppc_vpa *vpap, + struct kvmppc_vpa *old_vpap) { struct kvm *kvm = vcpu->kvm; void *va; @@ -690,9 +691,8 @@ static void kvmppc_update_vpa(struct kvm_vcpu *vcpu, struct kvmppc_vpa *vpap) kvmppc_unpin_guest_page(kvm, va, gpa, false); va = NULL; } - if (vpap->pinned_addr) - kvmppc_unpin_guest_page(kvm, vpap->pinned_addr, vpap->gpa, - vpap->dirty); + *old_vpap = *vpap; + vpap->gpa = gpa; vpap->pinned_addr = va; vpap->dirty = false; @@ -702,6 +702,9 @@ static void kvmppc_update_vpa(struct kvm_vcpu *vcpu, struct kvmppc_vpa *vpap) static void kvmppc_update_vpas(struct kvm_vcpu *vcpu) { + struct kvm *kvm = vcpu->kvm; + struct kvmppc_vpa old_vpa = { 0 }; + if (!(vcpu->arch.vpa.update_pending || vcpu->arch.slb_shadow.update_pending || vcpu->arch.dtl.update_pending)) @@ -709,17 +712,34 @@ static void kvmppc_update_vpas(struct kvm_vcpu *vcpu) spin_lock(&vcpu->arch.vpa_update_lock); if (vcpu->arch.vpa.update_pending) { - kvmppc_update_vpa(vcpu, &vcpu->arch.vpa); - if (vcpu->arch.vpa.pinned_addr) + kvmppc_update_vpa(vcpu, &vcpu->arch.vpa, &old_vpa); + if (old_vpa.pinned_addr) { + if (kvmhv_is_nestedv2()) + kvmhv_nestedv2_set_vpa(vcpu, ~0ull); + kvmppc_unpin_guest_page(kvm, old_vpa.pinned_addr, old_vpa.gpa, + old_vpa.dirty); + } + if (vcpu->arch.vpa.pinned_addr) { init_vpa(vcpu, vcpu->arch.vpa.pinned_addr); + if (kvmhv_is_nestedv2()) + kvmhv_nestedv2_set_vpa(vcpu, __pa(vcpu->arch.vpa.pinned_addr)); + } } if (vcpu->arch.dtl.update_pending) { - kvmppc_update_vpa(vcpu, &vcpu->arch.dtl); + kvmppc_update_vpa(vcpu, &vcpu->arch.dtl, &old_vpa); + if (old_vpa.pinned_addr) + kvmppc_unpin_guest_page(kvm, old_vpa.pinned_addr, old_vpa.gpa, + old_vpa.dirty); vcpu->arch.dtl_ptr = vcpu->arch.dtl.pinned_addr; vcpu->arch.dtl_index = 0; } - if (vcpu->arch.slb_shadow.update_pending) - kvmppc_update_vpa(vcpu, &vcpu->arch.slb_shadow); + if (vcpu->arch.slb_shadow.update_pending) { + kvmppc_update_vpa(vcpu, &vcpu->arch.slb_shadow, &old_vpa); + if (old_vpa.pinned_addr) + kvmppc_unpin_guest_page(kvm, old_vpa.pinned_addr, old_vpa.gpa, + old_vpa.dirty); + } + spin_unlock(&vcpu->arch.vpa_update_lock); } @@ -1597,7 +1617,7 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, * That can happen due to a bug, or due to a machine check * occurring at just the wrong time. */ - if (__kvmppc_get_msr_hv(vcpu) & MSR_HV) { + if (!kvmhv_is_nestedv2() && (__kvmppc_get_msr_hv(vcpu) & MSR_HV)) { printk(KERN_EMERG "KVM trap in HV mode!\n"); printk(KERN_EMERG "trap=0x%x | pc=0x%lx | msr=0x%llx\n", vcpu->arch.trap, kvmppc_get_pc(vcpu), @@ -1688,7 +1708,7 @@ static int kvmppc_handle_exit_hv(struct kvm_vcpu *vcpu, { int i; - if (unlikely(__kvmppc_get_msr_hv(vcpu) & MSR_PR)) { + if (!kvmhv_is_nestedv2() && unlikely(__kvmppc_get_msr_hv(vcpu) & MSR_PR)) { /* * Guest userspace executed sc 1. This can only be * reached by the P9 path because the old path @@ -4084,6 +4104,8 @@ static int kvmhv_vcpu_entry_nestedv2(struct kvm_vcpu *vcpu, u64 time_limit, if (rc < 0) return -EINVAL; + kvmppc_gse_put_u64(io->vcpu_run_input, KVMPPC_GSID_LPCR, lpcr); + accumulate_time(vcpu, &vcpu->arch.in_guest); rc = plpar_guest_run_vcpu(0, vcpu->kvm->arch.lpid, vcpu->vcpu_id, &trap, &i); @@ -4736,13 +4758,19 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit, if (!nested) { kvmppc_core_prepare_to_enter(vcpu); - if (__kvmppc_get_msr_hv(vcpu) & MSR_EE) { - if (xive_interrupt_pending(vcpu)) + if (test_bit(BOOK3S_IRQPRIO_EXTERNAL, + &vcpu->arch.pending_exceptions) || + xive_interrupt_pending(vcpu)) { + /* + * For nested HV, don't synthesize but always pass MER, + * the L0 will be able to optimise that more + * effectively than manipulating registers directly. + */ + if (!kvmhv_on_pseries() && (__kvmppc_get_msr_hv(vcpu) & MSR_EE)) kvmppc_inject_interrupt_hv(vcpu, - BOOK3S_INTERRUPT_EXTERNAL, 0); - } else if (test_bit(BOOK3S_IRQPRIO_EXTERNAL, - &vcpu->arch.pending_exceptions)) { - lpcr |= LPCR_MER; + BOOK3S_INTERRUPT_EXTERNAL, 0); + else + lpcr |= LPCR_MER; } } else if (vcpu->arch.pending_exceptions || vcpu->arch.doorbell_request || @@ -4806,7 +4834,7 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 time_limit, * entering a nested guest in which case the decrementer is now owned * by L2 and the L1 decrementer is provided in hdec_expires */ - if (kvmppc_core_pending_dec(vcpu) && + if (!kvmhv_is_nestedv2() && kvmppc_core_pending_dec(vcpu) && ((tb < kvmppc_dec_expires_host_tb(vcpu)) || (trap == BOOK3S_INTERRUPT_SYSCALL && kvmppc_get_gpr(vcpu, 3) == H_ENTER_NESTED))) @@ -4949,7 +4977,7 @@ static int kvmppc_vcpu_run_hv(struct kvm_vcpu *vcpu) if (run->exit_reason == KVM_EXIT_PAPR_HCALL) { accumulate_time(vcpu, &vcpu->arch.hcall); - if (WARN_ON_ONCE(__kvmppc_get_msr_hv(vcpu) & MSR_PR)) { + if (!kvmhv_is_nestedv2() && WARN_ON_ONCE(__kvmppc_get_msr_hv(vcpu) & MSR_PR)) { /* * These should have been caught reflected * into the guest by now. Final sanity check: @@ -5691,10 +5719,12 @@ static void kvmppc_core_destroy_vm_hv(struct kvm *kvm) kvmhv_set_ptbl_entry(kvm->arch.lpid, 0, 0); } - if (kvmhv_is_nestedv2()) + if (kvmhv_is_nestedv2()) { + kvmhv_flush_lpid(kvm->arch.lpid); plpar_guest_delete(0, kvm->arch.lpid); - else + } else { kvmppc_free_lpid(kvm->arch.lpid); + } kvmppc_free_pimap(kvm); } @@ -6210,7 +6240,7 @@ static int kvmhv_svm_off(struct kvm *kvm) } srcu_idx = srcu_read_lock(&kvm->srcu); - for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++) { + for (i = 0; i < kvm_arch_nr_memslot_as_ids(kvm); i++) { struct kvm_memory_slot *memslot; struct kvm_memslots *slots = __kvm_memslots(kvm, i); int bkt; diff --git a/arch/powerpc/kvm/book3s_hv_nested.c b/arch/powerpc/kvm/book3s_hv_nested.c index 3b658b8696bca6..5c375ec1a3c608 100644 --- a/arch/powerpc/kvm/book3s_hv_nested.c +++ b/arch/powerpc/kvm/book3s_hv_nested.c @@ -503,7 +503,7 @@ void kvmhv_nested_exit(void) } } -static void kvmhv_flush_lpid(u64 lpid) +void kvmhv_flush_lpid(u64 lpid) { long rc; diff --git a/arch/powerpc/kvm/book3s_hv_nestedv2.c b/arch/powerpc/kvm/book3s_hv_nestedv2.c index fd3c4f2d948056..5378eb40b162f2 100644 --- a/arch/powerpc/kvm/book3s_hv_nestedv2.c +++ b/arch/powerpc/kvm/book3s_hv_nestedv2.c @@ -855,6 +855,35 @@ free_gsb: } EXPORT_SYMBOL_GPL(kvmhv_nestedv2_set_ptbl_entry); +/** + * kvmhv_nestedv2_set_vpa() - register L2 VPA with L0 + * @vcpu: vcpu + * @vpa: L1 logical real address + */ +int kvmhv_nestedv2_set_vpa(struct kvm_vcpu *vcpu, unsigned long vpa) +{ + struct kvmhv_nestedv2_io *io; + struct kvmppc_gs_buff *gsb; + int rc = 0; + + io = &vcpu->arch.nestedv2_io; + gsb = io->vcpu_run_input; + + kvmppc_gsb_reset(gsb); + rc = kvmppc_gse_put_u64(gsb, KVMPPC_GSID_VPA, vpa); + if (rc < 0) + goto out; + + rc = kvmppc_gsb_send(gsb, 0); + if (rc < 0) + pr_err("KVM-NESTEDv2: couldn't register the L2 VPA (rc=%d)\n", rc); + +out: + kvmppc_gsb_reset(gsb); + return rc; +} +EXPORT_SYMBOL_GPL(kvmhv_nestedv2_set_vpa); + /** * kvmhv_nestedv2_parse_output() - receive values from H_GUEST_RUN_VCPU output * @vcpu: vcpu diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c index 9118242063fbbd..5b92619a05fdf2 100644 --- a/arch/powerpc/kvm/book3s_pr.c +++ b/arch/powerpc/kvm/book3s_pr.c @@ -604,6 +604,7 @@ static void kvmppc_set_pvr_pr(struct kvm_vcpu *vcpu, u32 pvr) case PVR_POWER8: case PVR_POWER8E: case PVR_POWER8NVL: + case PVR_HX_C2000: case PVR_POWER9: vcpu->arch.hflags |= BOOK3S_HFLAG_MULTI_PGSIZE | BOOK3S_HFLAG_NEW_TLBIE; diff --git a/arch/powerpc/kvm/emulate_loadstore.c b/arch/powerpc/kvm/emulate_loadstore.c index 077fd88a0b6836..ec60c797971876 100644 --- a/arch/powerpc/kvm/emulate_loadstore.c +++ b/arch/powerpc/kvm/emulate_loadstore.c @@ -93,7 +93,6 @@ int kvmppc_emulate_loadstore(struct kvm_vcpu *vcpu) emulated = EMULATE_FAIL; vcpu->arch.regs.msr = kvmppc_get_msr(vcpu); - kvmhv_nestedv2_reload_ptregs(vcpu, &vcpu->arch.regs); if (analyse_instr(&op, &vcpu->arch.regs, inst) == 0) { int type = op.type & INSTR_TYPE_MASK; int size = GETSIZE(op.type); @@ -112,7 +111,7 @@ int kvmppc_emulate_loadstore(struct kvm_vcpu *vcpu) op.reg, size, !instr_byte_swap); if ((op.type & UPDATE) && (emulated != EMULATE_FAIL)) - kvmppc_set_gpr(vcpu, op.update_reg, op.ea); + kvmppc_set_gpr(vcpu, op.update_reg, vcpu->arch.vaddr_accessed); break; } @@ -132,7 +131,7 @@ int kvmppc_emulate_loadstore(struct kvm_vcpu *vcpu) KVM_MMIO_REG_FPR|op.reg, size, 1); if ((op.type & UPDATE) && (emulated != EMULATE_FAIL)) - kvmppc_set_gpr(vcpu, op.update_reg, op.ea); + kvmppc_set_gpr(vcpu, op.update_reg, vcpu->arch.vaddr_accessed); break; #endif @@ -224,16 +223,17 @@ int kvmppc_emulate_loadstore(struct kvm_vcpu *vcpu) break; } #endif - case STORE: - /* if need byte reverse, op.val has been reversed by - * analyse_instr(). - */ - emulated = kvmppc_handle_store(vcpu, op.val, size, 1); + case STORE: { + int instr_byte_swap = op.type & BYTEREV; + + emulated = kvmppc_handle_store(vcpu, kvmppc_get_gpr(vcpu, op.reg), + size, !instr_byte_swap); if ((op.type & UPDATE) && (emulated != EMULATE_FAIL)) - kvmppc_set_gpr(vcpu, op.update_reg, op.ea); + kvmppc_set_gpr(vcpu, op.update_reg, vcpu->arch.vaddr_accessed); break; + } #ifdef CONFIG_PPC_FPU case STORE_FP: if (kvmppc_check_fp_disabled(vcpu)) @@ -254,7 +254,7 @@ int kvmppc_emulate_loadstore(struct kvm_vcpu *vcpu) kvmppc_get_fpr(vcpu, op.reg), size, 1); if ((op.type & UPDATE) && (emulated != EMULATE_FAIL)) - kvmppc_set_gpr(vcpu, op.update_reg, op.ea); + kvmppc_set_gpr(vcpu, op.update_reg, vcpu->arch.vaddr_accessed); break; #endif @@ -358,7 +358,6 @@ int kvmppc_emulate_loadstore(struct kvm_vcpu *vcpu) } trace_kvm_ppc_instr(ppc_inst_val(inst), kvmppc_get_pc(vcpu), emulated); - kvmhv_nestedv2_mark_dirty_ptregs(vcpu, &vcpu->arch.regs); /* Advance past emulated instruction. */ if (emulated != EMULATE_FAIL) diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index f6af752698d036..23407fbd73c934 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -528,7 +528,6 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_ENABLE_CAP: case KVM_CAP_ONE_REG: case KVM_CAP_IOEVENTFD: - case KVM_CAP_DEVICE_CTRL: case KVM_CAP_IMMEDIATE_EXIT: case KVM_CAP_SET_GUEST_DEBUG: r = 1; @@ -578,7 +577,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) break; #endif -#ifdef CONFIG_HAVE_KVM_IRQFD +#ifdef CONFIG_HAVE_KVM_IRQCHIP case KVM_CAP_IRQFD_RESAMPLE: r = !xive_enabled(); break; @@ -632,13 +631,8 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) break; #endif case KVM_CAP_SYNC_MMU: -#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE - r = hv_enabled; -#elif defined(KVM_ARCH_WANT_MMU_NOTIFIER) + BUILD_BUG_ON(!IS_ENABLED(CONFIG_KVM_GENERIC_MMU_NOTIFIER)); r = 1; -#else - r = 0; -#endif break; #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE case KVM_CAP_PPC_HTAB_FD: diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index 51ad0397c17abf..6eac63e79a8995 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -45,7 +45,7 @@ obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o # so it is only needed for modules, and only for older linkers which # do not support --save-restore-funcs ifndef CONFIG_LD_IS_BFD -extra-$(CONFIG_PPC64) += crtsavres.o +always-$(CONFIG_PPC64) += crtsavres.o endif obj-$(CONFIG_PPC_BOOK3S_64) += copyuser_power7.o copypage_power7.o \ diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c index a4ab8625061a66..5766180f5380a6 100644 --- a/arch/powerpc/lib/sstep.c +++ b/arch/powerpc/lib/sstep.c @@ -586,6 +586,8 @@ static int do_fp_load(struct instruction_op *op, unsigned long ea, } u; nb = GETSIZE(op->type); + if (nb > sizeof(u)) + return -EINVAL; if (!address_ok(regs, ea, nb)) return -EFAULT; rn = op->reg; @@ -636,6 +638,8 @@ static int do_fp_store(struct instruction_op *op, unsigned long ea, } u; nb = GETSIZE(op->type); + if (nb > sizeof(u)) + return -EINVAL; if (!address_ok(regs, ea, nb)) return -EFAULT; rn = op->reg; @@ -680,6 +684,9 @@ static nokprobe_inline int do_vec_load(int rn, unsigned long ea, u8 b[sizeof(__vector128)]; } u = {}; + if (size > sizeof(u)) + return -EINVAL; + if (!address_ok(regs, ea & ~0xfUL, 16)) return -EFAULT; /* align to multiple of size */ @@ -688,7 +695,7 @@ static nokprobe_inline int do_vec_load(int rn, unsigned long ea, if (err) return err; if (unlikely(cross_endian)) - do_byte_reverse(&u.b[ea & 0xf], size); + do_byte_reverse(&u.b[ea & 0xf], min_t(size_t, size, sizeof(u))); preempt_disable(); if (regs->msr & MSR_VEC) put_vr(rn, &u.v); @@ -707,6 +714,9 @@ static nokprobe_inline int do_vec_store(int rn, unsigned long ea, u8 b[sizeof(__vector128)]; } u; + if (size > sizeof(u)) + return -EINVAL; + if (!address_ok(regs, ea & ~0xfUL, 16)) return -EFAULT; /* align to multiple of size */ @@ -719,7 +729,7 @@ static nokprobe_inline int do_vec_store(int rn, unsigned long ea, u.v = current->thread.vr_state.vr[rn]; preempt_enable(); if (unlikely(cross_endian)) - do_byte_reverse(&u.b[ea & 0xf], size); + do_byte_reverse(&u.b[ea & 0xf], min_t(size_t, size, sizeof(u))); return copy_mem_out(&u.b[ea & 0xf], ea, size, regs); } #endif /* CONFIG_ALTIVEC */ diff --git a/arch/powerpc/mm/book3s64/hash_utils.c b/arch/powerpc/mm/book3s64/hash_utils.c index ad2afa08e62ed9..0626a25b0d728b 100644 --- a/arch/powerpc/mm/book3s64/hash_utils.c +++ b/arch/powerpc/mm/book3s64/hash_utils.c @@ -310,9 +310,16 @@ unsigned long htab_convert_pte_flags(unsigned long pteflags, unsigned long flags else rflags |= 0x3; } + VM_WARN_ONCE(!(pteflags & _PAGE_RWX), "no-access mapping request"); } else { if (pteflags & _PAGE_RWX) rflags |= 0x2; + /* + * We should never hit this in normal fault handling because + * a permission check (check_pte_access()) will bubble this + * to higher level linux handler even for PAGE_NONE. + */ + VM_WARN_ONCE(!(pteflags & _PAGE_RWX), "no-access mapping request"); if (!((pteflags & _PAGE_WRITE) && (pteflags & _PAGE_DIRTY))) rflags |= 0x1; } diff --git a/arch/powerpc/mm/book3s64/iommu_api.c b/arch/powerpc/mm/book3s64/iommu_api.c index d19fb1f3007d2d..c0e8d597e4cb2d 100644 --- a/arch/powerpc/mm/book3s64/iommu_api.c +++ b/arch/powerpc/mm/book3s64/iommu_api.c @@ -97,7 +97,7 @@ static long mm_iommu_do_alloc(struct mm_struct *mm, unsigned long ua, } mmap_read_lock(mm); - chunk = (1UL << (PAGE_SHIFT + MAX_ORDER)) / + chunk = (1UL << (PAGE_SHIFT + MAX_PAGE_ORDER)) / sizeof(struct vm_area_struct *); chunk = min(chunk, entries); for (entry = 0; entry < entries; entry += chunk) { diff --git a/arch/powerpc/mm/book3s64/pgtable.c b/arch/powerpc/mm/book3s64/pgtable.c index be229290a6a775..3438ab72c346b8 100644 --- a/arch/powerpc/mm/book3s64/pgtable.c +++ b/arch/powerpc/mm/book3s64/pgtable.c @@ -542,6 +542,7 @@ void ptep_modify_prot_commit(struct vm_area_struct *vma, unsigned long addr, set_pte_at(vma->vm_mm, addr, ptep, pte); } +#ifdef CONFIG_TRANSPARENT_HUGEPAGE /* * For hash translation mode, we use the deposited table to store hash slot * information and they are stored at PTRS_PER_PMD offset from related pmd @@ -563,6 +564,7 @@ int pmd_move_must_withdraw(struct spinlock *new_pmd_ptl, return true; } +#endif /* * Does the CPU support tlbie? diff --git a/arch/powerpc/mm/book3s64/pkeys.c b/arch/powerpc/mm/book3s64/pkeys.c index 12573396203381..a974baf8f3278e 100644 --- a/arch/powerpc/mm/book3s64/pkeys.c +++ b/arch/powerpc/mm/book3s64/pkeys.c @@ -89,7 +89,8 @@ static int __init scan_pkey_feature(void) unsigned long pvr = mfspr(SPRN_PVR); if (PVR_VER(pvr) == PVR_POWER8 || PVR_VER(pvr) == PVR_POWER8E || - PVR_VER(pvr) == PVR_POWER8NVL || PVR_VER(pvr) == PVR_POWER9) + PVR_VER(pvr) == PVR_POWER8NVL || PVR_VER(pvr) == PVR_POWER9 || + PVR_VER(pvr) == PVR_HX_C2000) pkeys_total = 32; } } diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index f7c683b672c184..0a540b37aab62c 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -615,7 +615,7 @@ void __init gigantic_hugetlb_cma_reserve(void) order = mmu_psize_to_shift(MMU_PAGE_16G) - PAGE_SHIFT; if (order) { - VM_WARN_ON(order <= MAX_ORDER); + VM_WARN_ON(order <= MAX_PAGE_ORDER); hugetlb_cma_reserve(order); } } diff --git a/arch/powerpc/mm/init-common.c b/arch/powerpc/mm/init-common.c index 119ef491f79760..d3a7726ecf512c 100644 --- a/arch/powerpc/mm/init-common.c +++ b/arch/powerpc/mm/init-common.c @@ -126,7 +126,7 @@ void pgtable_cache_add(unsigned int shift) * as to leave enough 0 bits in the address to contain it. */ unsigned long minalign = max(MAX_PGTABLE_INDEX_SIZE + 1, HUGEPD_SHIFT_MASK + 1); - struct kmem_cache *new; + struct kmem_cache *new = NULL; /* It would be nice if this was a BUILD_BUG_ON(), but at the * moment, gcc doesn't seem to recognize is_power_of_2 as a @@ -139,7 +139,8 @@ void pgtable_cache_add(unsigned int shift) align = max_t(unsigned long, align, minalign); name = kasprintf(GFP_KERNEL, "pgtable-2^%d", shift); - new = kmem_cache_create(name, table_size, align, 0, ctor(shift)); + if (name) + new = kmem_cache_create(name, table_size, align, 0, ctor(shift)); if (!new) panic("Could not allocate pgtable cache for order %d", shift); diff --git a/arch/powerpc/mm/mmu_decl.h b/arch/powerpc/mm/mmu_decl.h index 7f9ff0640124af..72341b9fb5521f 100644 --- a/arch/powerpc/mm/mmu_decl.h +++ b/arch/powerpc/mm/mmu_decl.h @@ -181,3 +181,8 @@ static inline bool debug_pagealloc_enabled_or_kfence(void) { return IS_ENABLED(CONFIG_KFENCE) || debug_pagealloc_enabled(); } + +#ifdef CONFIG_MEMORY_HOTPLUG +int create_section_mapping(unsigned long start, unsigned long end, + int nid, pgprot_t prot); +#endif diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index 10b946e9c6e756..b7ff680cde9649 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -2312,7 +2312,7 @@ static void record_and_restart(struct perf_event *event, unsigned long val, struct cpu_hw_events *cpuhw; cpuhw = this_cpu_ptr(&cpu_hw_events); power_pmu_bhrb_read(event, cpuhw); - perf_sample_save_brstack(&data, event, &cpuhw->bhrb_stack); + perf_sample_save_brstack(&data, event, &cpuhw->bhrb_stack, NULL); } if (event->attr.sample_type & PERF_SAMPLE_DATA_SRC && diff --git a/arch/powerpc/perf/hv-gpci.c b/arch/powerpc/perf/hv-gpci.c index 39dbe6b348df28..27f18119fda174 100644 --- a/arch/powerpc/perf/hv-gpci.c +++ b/arch/powerpc/perf/hv-gpci.c @@ -534,6 +534,9 @@ static ssize_t affinity_domain_via_partition_show(struct device *dev, struct dev if (!ret) goto parse_result; + if (ret && (ret != H_PARAMETER)) + goto out; + /* * ret value as 'H_PARAMETER' implies that the current buffer size * can't accommodate all the information, and a partial buffer diff --git a/arch/powerpc/perf/imc-pmu.c b/arch/powerpc/perf/imc-pmu.c index 5d12ca386c1fcb..8664a7d297ad81 100644 --- a/arch/powerpc/perf/imc-pmu.c +++ b/arch/powerpc/perf/imc-pmu.c @@ -299,6 +299,8 @@ static int update_events_in_group(struct device_node *node, struct imc_pmu *pmu) attr_group->attrs = attrs; do { ev_val_str = kasprintf(GFP_KERNEL, "event=0x%x", pmu->events[i].value); + if (!ev_val_str) + continue; dev_str = device_str_attr_create(pmu->events[i].name, ev_val_str); if (!dev_str) continue; @@ -306,6 +308,8 @@ static int update_events_in_group(struct device_node *node, struct imc_pmu *pmu) attrs[j++] = dev_str; if (pmu->events[i].scale) { ev_scale_str = kasprintf(GFP_KERNEL, "%s.scale", pmu->events[i].name); + if (!ev_scale_str) + continue; dev_str = device_str_attr_create(ev_scale_str, pmu->events[i].scale); if (!dev_str) continue; @@ -315,6 +319,8 @@ static int update_events_in_group(struct device_node *node, struct imc_pmu *pmu) if (pmu->events[i].unit) { ev_unit_str = kasprintf(GFP_KERNEL, "%s.unit", pmu->events[i].name); + if (!ev_unit_str) + continue; dev_str = device_str_attr_create(ev_unit_str, pmu->events[i].unit); if (!dev_str) continue; diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig index 1624ebf95497ba..35a1f4b9f8272b 100644 --- a/arch/powerpc/platforms/44x/Kconfig +++ b/arch/powerpc/platforms/44x/Kconfig @@ -173,6 +173,7 @@ config ISS4xx config CURRITUCK bool "IBM Currituck (476fpe) Support" depends on PPC_47x + select I2C select SWIOTLB select 476FPE select FORCE_PCI diff --git a/arch/powerpc/platforms/44x/idle.c b/arch/powerpc/platforms/44x/idle.c index f533b495e7db32..e2eeef8dff7875 100644 --- a/arch/powerpc/platforms/44x/idle.c +++ b/arch/powerpc/platforms/44x/idle.c @@ -27,7 +27,7 @@ static void ppc44x_idle(void) isync(); } -int __init ppc44x_idle_init(void) +static int __init ppc44x_idle_init(void) { if (!mode_spin) { /* If we are not setting spin mode diff --git a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c index 6f08d07aee3b37..e995eb30bf096f 100644 --- a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c +++ b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c @@ -17,6 +17,8 @@ #include #include +#include "mpc5121_ads.h" + static struct device_node *cpld_pic_node; static struct irq_domain *cpld_pic_host; diff --git a/arch/powerpc/platforms/512x/pdm360ng.c b/arch/powerpc/platforms/512x/pdm360ng.c index ce51cfeeb0665d..8bbbf78bb42bdd 100644 --- a/arch/powerpc/platforms/512x/pdm360ng.c +++ b/arch/powerpc/platforms/512x/pdm360ng.c @@ -101,7 +101,7 @@ static inline void __init pdm360ng_touchscreen_init(void) } #endif /* CONFIG_TOUCHSCREEN_ADS7846 */ -void __init pdm360ng_init(void) +static void __init pdm360ng_init(void) { mpc512x_init(); pdm360ng_touchscreen_init(); diff --git a/arch/powerpc/platforms/83xx/suspend.c b/arch/powerpc/platforms/83xx/suspend.c index 9833c36bda8385..c9664e46b03d70 100644 --- a/arch/powerpc/platforms/83xx/suspend.c +++ b/arch/powerpc/platforms/83xx/suspend.c @@ -261,9 +261,10 @@ static int mpc83xx_suspend_begin(suspend_state_t state) static int agent_thread_fn(void *data) { + set_freezable(); + while (1) { - wait_event_interruptible(agent_wq, pci_pm_state >= 2); - try_to_freeze(); + wait_event_freezable(agent_wq, pci_pm_state >= 2); if (signal_pending(current) || pci_pm_state < 2) continue; diff --git a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c index ec9f60fbebc71e..e0cec670d8dbc9 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c @@ -76,7 +76,7 @@ static void __init mpc85xx_rdb_setup_arch(void) /* P1025 has pins muxed for QE and other functions. To * enable QE UEC mode, we need to set bit QE0 for UCC1 * in Eth mode, QE0 and QE3 for UCC5 in Eth mode, QE9 - * and QE12 for QE MII management singals in PMUXCR + * and QE12 for QE MII management signals in PMUXCR * register. */ setbits32(&guts->pmuxcr, MPC85xx_PMUXCR_QE(0) | diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig index 67467cd6f34cd5..06b1e5c49d6f7f 100644 --- a/arch/powerpc/platforms/86xx/Kconfig +++ b/arch/powerpc/platforms/86xx/Kconfig @@ -52,10 +52,3 @@ config MPC8641 select MPIC default y if GEF_SBC610 || GEF_SBC310 || GEF_PPC9A \ || MVME7100 - -config MPC8610 - bool - select HAVE_PCI - select FSL_PCI if PCI - select PPC_UDBG_16550 - select MPIC diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 10c1320adfd0be..030de2b8c145f6 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -145,10 +145,11 @@ spufs_evict_inode(struct inode *inode) static void spufs_prune_dir(struct dentry *dir) { - struct dentry *dentry, *tmp; + struct dentry *dentry; + struct hlist_node *n; inode_lock(d_inode(dir)); - list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_child) { + hlist_for_each_entry_safe(dentry, n, &dir->d_children, d_sib) { spin_lock(&dentry->d_lock); if (simple_positive(dentry)) { dget_dlock(dentry); diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c index ef985ba2bf21ff..0761d98e5be3ff 100644 --- a/arch/powerpc/platforms/pasemi/setup.c +++ b/arch/powerpc/platforms/pasemi/setup.c @@ -64,7 +64,7 @@ static void __noreturn pas_restart(char *cmd) } #ifdef CONFIG_PPC_PASEMI_NEMO -void pas_shutdown(void) +static void pas_shutdown(void) { /* Set the PLD bit that makes the SB600 think the power button is being pressed */ void __iomem *pld_map = ioremap(0xf5000000,4096); diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index c83d1e14077e95..15644be31990d9 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c @@ -413,7 +413,7 @@ static void __init smp_psurge_setup_cpu(int cpu_nr) printk(KERN_ERR "Couldn't get primary IPI interrupt"); } -void __init smp_psurge_take_timebase(void) +static void __init smp_psurge_take_timebase(void) { if (psurge_type != PSURGE_DUAL) return; @@ -429,7 +429,7 @@ void __init smp_psurge_take_timebase(void) set_dec(tb_ticks_per_jiffy/2); } -void __init smp_psurge_give_timebase(void) +static void __init smp_psurge_give_timebase(void) { /* Nothing to do here */ } diff --git a/arch/powerpc/platforms/powernv/opal-irqchip.c b/arch/powerpc/platforms/powernv/opal-irqchip.c index f9a7001dacb7a1..56a1f7ce78d2c7 100644 --- a/arch/powerpc/platforms/powernv/opal-irqchip.c +++ b/arch/powerpc/platforms/powernv/opal-irqchip.c @@ -275,6 +275,8 @@ int __init opal_event_init(void) else name = kasprintf(GFP_KERNEL, "opal"); + if (!name) + continue; /* Install interrupt handler */ rc = request_irq(r->start, opal_interrupt, r->flags & IRQD_TRIGGER_MASK, name, NULL); diff --git a/arch/powerpc/platforms/powernv/opal-powercap.c b/arch/powerpc/platforms/powernv/opal-powercap.c index 7bfe4cbeb35a99..ea917266aa1725 100644 --- a/arch/powerpc/platforms/powernv/opal-powercap.c +++ b/arch/powerpc/platforms/powernv/opal-powercap.c @@ -196,6 +196,12 @@ void __init opal_powercap_init(void) j = 0; pcaps[i].pg.name = kasprintf(GFP_KERNEL, "%pOFn", node); + if (!pcaps[i].pg.name) { + kfree(pcaps[i].pattrs); + kfree(pcaps[i].pg.attrs); + goto out_pcaps_pattrs; + } + if (has_min) { powercap_add_attr(min, "powercap-min", &pcaps[i].pattrs[j]); diff --git a/arch/powerpc/platforms/powernv/opal-prd.c b/arch/powerpc/platforms/powernv/opal-prd.c index 327e2f76905d56..b66b06efcef1e1 100644 --- a/arch/powerpc/platforms/powernv/opal-prd.c +++ b/arch/powerpc/platforms/powernv/opal-prd.c @@ -66,6 +66,8 @@ static bool opal_prd_range_is_valid(uint64_t addr, uint64_t size) const char *label; addrp = of_get_address(node, 0, &range_size, NULL); + if (!addrp) + continue; range_addr = of_read_number(addrp, 2); range_end = range_addr + range_size; diff --git a/arch/powerpc/platforms/powernv/opal-xscom.c b/arch/powerpc/platforms/powernv/opal-xscom.c index 262cd6fac90714..748c2b97fa5370 100644 --- a/arch/powerpc/platforms/powernv/opal-xscom.c +++ b/arch/powerpc/platforms/powernv/opal-xscom.c @@ -165,6 +165,11 @@ static int scom_debug_init_one(struct dentry *root, struct device_node *dn, ent->chip = chip; snprintf(ent->name, 16, "%08x", chip); ent->path.data = (void *)kasprintf(GFP_KERNEL, "%pOF", dn); + if (!ent->path.data) { + kfree(ent); + return -ENOMEM; + } + ent->path.size = strlen((char *)ent->path.data); dir = debugfs_create_dir(ent->name, root); diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index cdf3838f08d376..45dd77e3ccf6f8 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c @@ -424,7 +424,7 @@ static int __init opal_message_init(struct device_node *opal_node) return 0; } -int opal_get_chars(uint32_t vtermno, char *buf, int count) +ssize_t opal_get_chars(uint32_t vtermno, u8 *buf, size_t count) { s64 rc; __be64 evt, len; @@ -441,10 +441,11 @@ int opal_get_chars(uint32_t vtermno, char *buf, int count) return 0; } -static int __opal_put_chars(uint32_t vtermno, const char *data, int total_len, bool atomic) +static ssize_t __opal_put_chars(uint32_t vtermno, const u8 *data, + size_t total_len, bool atomic) { unsigned long flags = 0 /* shut up gcc */; - int written; + ssize_t written; __be64 olen; s64 rc; @@ -484,7 +485,7 @@ static int __opal_put_chars(uint32_t vtermno, const char *data, int total_len, b if (atomic) { /* Should not happen */ pr_warn("atomic console write returned partial " - "len=%d written=%d\n", total_len, written); + "len=%zu written=%zd\n", total_len, written); } if (!written) written = -EAGAIN; @@ -497,7 +498,7 @@ out: return written; } -int opal_put_chars(uint32_t vtermno, const char *data, int total_len) +ssize_t opal_put_chars(uint32_t vtermno, const u8 *data, size_t total_len) { return __opal_put_chars(vtermno, data, total_len, false); } @@ -508,7 +509,8 @@ int opal_put_chars(uint32_t vtermno, const char *data, int total_len) * true at the moment because console space can race with OPAL's console * writes. */ -int opal_put_chars_atomic(uint32_t vtermno, const char *data, int total_len) +ssize_t opal_put_chars_atomic(uint32_t vtermno, const u8 *data, + size_t total_len) { return __opal_put_chars(vtermno, data, total_len, true); } diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 28fac477007316..23f5b5093ec18f 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -1389,7 +1389,7 @@ static long pnv_pci_ioda2_setup_default_config(struct pnv_ioda_pe *pe) * DMA window can be larger than available memory, which will * cause errors later. */ - const u64 maxblock = 1UL << (PAGE_SHIFT + MAX_ORDER); + const u64 maxblock = 1UL << (PAGE_SHIFT + MAX_PAGE_ORDER); /* * We create the default window as big as we can. The constraint is diff --git a/arch/powerpc/platforms/powernv/subcore.c b/arch/powerpc/platforms/powernv/subcore.c index 191424468f10aa..393e747541fbeb 100644 --- a/arch/powerpc/platforms/powernv/subcore.c +++ b/arch/powerpc/platforms/powernv/subcore.c @@ -425,7 +425,8 @@ static int subcore_init(void) if (pvr_ver != PVR_POWER8 && pvr_ver != PVR_POWER8E && - pvr_ver != PVR_POWER8NVL) + pvr_ver != PVR_POWER8NVL && + pvr_ver != PVR_HX_C2000) return 0; /* diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig index a44869e5ea70f8..e9c1087dd42ec6 100644 --- a/arch/powerpc/platforms/ps3/Kconfig +++ b/arch/powerpc/platforms/ps3/Kconfig @@ -167,16 +167,4 @@ config PS3_LPM profiling support of the Cell processor with programs like perfmon2, then say Y or M, otherwise say N. -config PS3GELIC_UDBG - bool "PS3 udbg output via UDP broadcasts on Ethernet" - depends on PPC_PS3 - help - Enables udbg early debugging output by sending broadcast UDP - via the Ethernet port (UDP port number 18194). - - This driver uses a trivial implementation and is independent - from the main PS3 gelic network driver. - - If in doubt, say N here. - endmenu diff --git a/arch/powerpc/platforms/ps3/Makefile b/arch/powerpc/platforms/ps3/Makefile index 86bf2967a8d4a9..bc79bb124d1e7d 100644 --- a/arch/powerpc/platforms/ps3/Makefile +++ b/arch/powerpc/platforms/ps3/Makefile @@ -3,7 +3,7 @@ obj-y += setup.o mm.o time.o hvcall.o htab.o repository.o obj-y += interrupt.o exports.o os-area.o obj-y += system-bus.o -obj-$(CONFIG_PS3GELIC_UDBG) += gelic_udbg.o +obj-$(CONFIG_PPC_EARLY_DEBUG_PS3GELIC) += gelic_udbg.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SPU_BASE) += spu.o obj-y += device-init.o diff --git a/arch/powerpc/platforms/ps3/device-init.c b/arch/powerpc/platforms/ps3/device-init.c index e87360a0fb40dc..878bc160246e20 100644 --- a/arch/powerpc/platforms/ps3/device-init.c +++ b/arch/powerpc/platforms/ps3/device-init.c @@ -827,6 +827,7 @@ static int ps3_probe_thread(void *data) if (res) goto fail_free_irq; + set_freezable(); /* Loop here processing the requested notification events. */ do { try_to_freeze(); diff --git a/arch/powerpc/platforms/ps3/gelic_udbg.c b/arch/powerpc/platforms/ps3/gelic_udbg.c index 6b298010fd841c..a5202c18c236c1 100644 --- a/arch/powerpc/platforms/ps3/gelic_udbg.c +++ b/arch/powerpc/platforms/ps3/gelic_udbg.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index 1476c5e4433c3a..f936962a29469c 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile @@ -4,6 +4,7 @@ ccflags-$(CONFIG_PPC_PSERIES_DEBUG) += -DDEBUG obj-y := lpar.o hvCall.o nvram.o reconfig.o \ of_helpers.o rtas-work-area.o papr-sysparm.o \ + papr-vpd.o \ setup.o iommu.o event_sources.o ras.o \ firmware.o power.o dlpar.o mobility.o rng.o \ pci.o pci_dlpar.o eeh_pseries.o msi.o \ diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c index def184da51cf0e..b1ae0c0d118782 100644 --- a/arch/powerpc/platforms/pseries/eeh_pseries.c +++ b/arch/powerpc/platforms/pseries/eeh_pseries.c @@ -252,7 +252,7 @@ static int pseries_eeh_cap_start(struct pci_dn *pdn) if (!pdn) return 0; - rtas_read_config(pdn, PCI_STATUS, 2, &status); + rtas_pci_dn_read_config(pdn, PCI_STATUS, 2, &status); if (!(status & PCI_STATUS_CAP_LIST)) return 0; @@ -270,11 +270,11 @@ static int pseries_eeh_find_cap(struct pci_dn *pdn, int cap) return 0; while (cnt--) { - rtas_read_config(pdn, pos, 1, &pos); + rtas_pci_dn_read_config(pdn, pos, 1, &pos); if (pos < 0x40) break; pos &= ~3; - rtas_read_config(pdn, pos + PCI_CAP_LIST_ID, 1, &id); + rtas_pci_dn_read_config(pdn, pos + PCI_CAP_LIST_ID, 1, &id); if (id == 0xff) break; if (id == cap) @@ -294,7 +294,7 @@ static int pseries_eeh_find_ecap(struct pci_dn *pdn, int cap) if (!edev || !edev->pcie_cap) return 0; - if (rtas_read_config(pdn, pos, 4, &header) != PCIBIOS_SUCCESSFUL) + if (rtas_pci_dn_read_config(pdn, pos, 4, &header) != PCIBIOS_SUCCESSFUL) return 0; else if (!header) return 0; @@ -307,7 +307,7 @@ static int pseries_eeh_find_ecap(struct pci_dn *pdn, int cap) if (pos < 256) break; - if (rtas_read_config(pdn, pos, 4, &header) != PCIBIOS_SUCCESSFUL) + if (rtas_pci_dn_read_config(pdn, pos, 4, &header) != PCIBIOS_SUCCESSFUL) break; } @@ -412,8 +412,8 @@ static void pseries_eeh_init_edev(struct pci_dn *pdn) if ((pdn->class_code >> 8) == PCI_CLASS_BRIDGE_PCI) { edev->mode |= EEH_DEV_BRIDGE; if (edev->pcie_cap) { - rtas_read_config(pdn, edev->pcie_cap + PCI_EXP_FLAGS, - 2, &pcie_flags); + rtas_pci_dn_read_config(pdn, edev->pcie_cap + PCI_EXP_FLAGS, + 2, &pcie_flags); pcie_flags = (pcie_flags & PCI_EXP_FLAGS_TYPE) >> 4; if (pcie_flags == PCI_EXP_TYPE_ROOT_PORT) edev->mode |= EEH_DEV_ROOT_PORT; @@ -676,7 +676,7 @@ static int pseries_eeh_read_config(struct eeh_dev *edev, int where, int size, u3 { struct pci_dn *pdn = eeh_dev_to_pdn(edev); - return rtas_read_config(pdn, where, size, val); + return rtas_pci_dn_read_config(pdn, where, size, val); } /** @@ -692,7 +692,7 @@ static int pseries_eeh_write_config(struct eeh_dev *edev, int where, int size, u { struct pci_dn *pdn = eeh_dev_to_pdn(edev); - return rtas_write_config(pdn, where, size, val); + return rtas_pci_dn_write_config(pdn, where, size, val); } #ifdef CONFIG_PCI_IOV diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c index a43bfb01720aef..3fe3ddb30c04b4 100644 --- a/arch/powerpc/platforms/pseries/hotplug-memory.c +++ b/arch/powerpc/platforms/pseries/hotplug-memory.c @@ -208,8 +208,10 @@ static int dlpar_change_lmb_state(struct drmem_lmb *lmb, bool online) int rc; mem_block = lmb_to_memblock(lmb); - if (!mem_block) + if (!mem_block) { + pr_err("Failed memory block lookup for LMB 0x%x\n", lmb->drc_index); return -EINVAL; + } if (online && mem_block->dev.offline) rc = device_online(&mem_block->dev); @@ -436,14 +438,15 @@ static int dlpar_memory_remove_by_index(u32 drc_index) } } - if (!lmb_found) + if (!lmb_found) { + pr_debug("Failed to look up LMB for drc index %x\n", drc_index); rc = -EINVAL; - - if (rc) + } else if (rc) { pr_debug("Failed to hot-remove memory at %llx\n", lmb->base_addr); - else + } else { pr_debug("Memory at %llx was hot-removed\n", lmb->base_addr); + } return rc; } @@ -575,6 +578,7 @@ static int dlpar_add_lmb(struct drmem_lmb *lmb) rc = update_lmb_associativity_index(lmb); if (rc) { dlpar_release_drc(lmb->drc_index); + pr_err("Failed to configure LMB 0x%x\n", lmb->drc_index); return rc; } @@ -588,12 +592,14 @@ static int dlpar_add_lmb(struct drmem_lmb *lmb) /* Add the memory */ rc = __add_memory(nid, lmb->base_addr, block_sz, MHP_MEMMAP_ON_MEMORY); if (rc) { + pr_err("Failed to add LMB 0x%x to node %u", lmb->drc_index, nid); invalidate_lmb_associativity_index(lmb); return rc; } rc = dlpar_online_lmb(lmb); if (rc) { + pr_err("Failed to online LMB 0x%x on node %u\n", lmb->drc_index, nid); __remove_memory(lmb->base_addr, block_sz); invalidate_lmb_associativity_index(lmb); } else { diff --git a/arch/powerpc/platforms/pseries/hvconsole.c b/arch/powerpc/platforms/pseries/hvconsole.c index 1ac52963e08b47..8803c947998e1e 100644 --- a/arch/powerpc/platforms/pseries/hvconsole.c +++ b/arch/powerpc/platforms/pseries/hvconsole.c @@ -25,7 +25,7 @@ * firmware. * @count: not used? */ -int hvc_get_chars(uint32_t vtermno, char *buf, int count) +ssize_t hvc_get_chars(uint32_t vtermno, u8 *buf, size_t count) { long ret; unsigned long retbuf[PLPAR_HCALL_BUFSIZE]; @@ -52,7 +52,7 @@ EXPORT_SYMBOL(hvc_get_chars); * firmware. Must be at least 16 bytes, even if count is less than 16. * @count: Send this number of characters. */ -int hvc_put_chars(uint32_t vtermno, const char *buf, int count) +ssize_t hvc_put_chars(uint32_t vtermno, const u8 *buf, size_t count) { unsigned long *lbuf = (unsigned long *) buf; long ret; diff --git a/arch/powerpc/platforms/pseries/papr-sysparm.c b/arch/powerpc/platforms/pseries/papr-sysparm.c index fedc61599e6cc7..7063ce8884e442 100644 --- a/arch/powerpc/platforms/pseries/papr-sysparm.c +++ b/arch/powerpc/platforms/pseries/papr-sysparm.c @@ -2,14 +2,20 @@ #define pr_fmt(fmt) "papr-sysparm: " fmt +#include #include +#include +#include #include #include +#include #include #include -#include +#include +#include #include #include +#include struct papr_sysparm_buf *papr_sysparm_buf_alloc(void) { @@ -23,6 +29,46 @@ void papr_sysparm_buf_free(struct papr_sysparm_buf *buf) kfree(buf); } +static size_t papr_sysparm_buf_get_length(const struct papr_sysparm_buf *buf) +{ + return be16_to_cpu(buf->len); +} + +static void papr_sysparm_buf_set_length(struct papr_sysparm_buf *buf, size_t length) +{ + WARN_ONCE(length > sizeof(buf->val), + "bogus length %zu, clamping to safe value", length); + length = min(sizeof(buf->val), length); + buf->len = cpu_to_be16(length); +} + +/* + * For use on buffers returned from ibm,get-system-parameter before + * returning them to callers. Ensures the encoded length of valid data + * cannot overrun buf->val[]. + */ +static void papr_sysparm_buf_clamp_length(struct papr_sysparm_buf *buf) +{ + papr_sysparm_buf_set_length(buf, papr_sysparm_buf_get_length(buf)); +} + +/* + * Perform some basic diligence on the system parameter buffer before + * submitting it to RTAS. + */ +static bool papr_sysparm_buf_can_submit(const struct papr_sysparm_buf *buf) +{ + /* + * Firmware ought to reject buffer lengths that exceed the + * maximum specified in PAPR, but there's no reason for the + * kernel to allow them either. + */ + if (papr_sysparm_buf_get_length(buf) > sizeof(buf->val)) + return false; + + return true; +} + /** * papr_sysparm_get() - Retrieve the value of a PAPR system parameter. * @param: PAPR system parameter token as described in @@ -47,7 +93,6 @@ void papr_sysparm_buf_free(struct papr_sysparm_buf *buf) * * Return: 0 on success, -errno otherwise. @buf is unmodified on error. */ - int papr_sysparm_get(papr_sysparm_t param, struct papr_sysparm_buf *buf) { const s32 token = rtas_function_token(RTAS_FN_IBM_GET_SYSTEM_PARAMETER); @@ -63,6 +108,9 @@ int papr_sysparm_get(papr_sysparm_t param, struct papr_sysparm_buf *buf) if (token == RTAS_UNKNOWN_SERVICE) return -ENOENT; + if (!papr_sysparm_buf_can_submit(buf)) + return -EINVAL; + work_area = rtas_work_area_alloc(sizeof(*buf)); memcpy(rtas_work_area_raw_buf(work_area), buf, sizeof(*buf)); @@ -77,6 +125,7 @@ int papr_sysparm_get(papr_sysparm_t param, struct papr_sysparm_buf *buf) case 0: ret = 0; memcpy(buf, rtas_work_area_raw_buf(work_area), sizeof(*buf)); + papr_sysparm_buf_clamp_length(buf); break; case -3: /* parameter not implemented */ ret = -EOPNOTSUPP; @@ -115,6 +164,9 @@ int papr_sysparm_set(papr_sysparm_t param, const struct papr_sysparm_buf *buf) if (token == RTAS_UNKNOWN_SERVICE) return -ENOENT; + if (!papr_sysparm_buf_can_submit(buf)) + return -EINVAL; + work_area = rtas_work_area_alloc(sizeof(*buf)); memcpy(rtas_work_area_raw_buf(work_area), buf, sizeof(*buf)); @@ -149,3 +201,152 @@ int papr_sysparm_set(papr_sysparm_t param, const struct papr_sysparm_buf *buf) return ret; } + +static struct papr_sysparm_buf * +papr_sysparm_buf_from_user(const struct papr_sysparm_io_block __user *user_iob) +{ + struct papr_sysparm_buf *kern_spbuf; + long err; + u16 len; + + /* + * The length of valid data that userspace claims to be in + * user_iob->data[]. + */ + if (get_user(len, &user_iob->length)) + return ERR_PTR(-EFAULT); + + static_assert(sizeof(user_iob->data) >= PAPR_SYSPARM_MAX_INPUT); + static_assert(sizeof(kern_spbuf->val) >= PAPR_SYSPARM_MAX_INPUT); + + if (len > PAPR_SYSPARM_MAX_INPUT) + return ERR_PTR(-EINVAL); + + kern_spbuf = papr_sysparm_buf_alloc(); + if (!kern_spbuf) + return ERR_PTR(-ENOMEM); + + papr_sysparm_buf_set_length(kern_spbuf, len); + + if (len > 0 && copy_from_user(kern_spbuf->val, user_iob->data, len)) { + err = -EFAULT; + goto free_sysparm_buf; + } + + return kern_spbuf; + +free_sysparm_buf: + papr_sysparm_buf_free(kern_spbuf); + return ERR_PTR(err); +} + +static int papr_sysparm_buf_to_user(const struct papr_sysparm_buf *kern_spbuf, + struct papr_sysparm_io_block __user *user_iob) +{ + u16 len_out = papr_sysparm_buf_get_length(kern_spbuf); + + if (put_user(len_out, &user_iob->length)) + return -EFAULT; + + static_assert(sizeof(user_iob->data) >= PAPR_SYSPARM_MAX_OUTPUT); + static_assert(sizeof(kern_spbuf->val) >= PAPR_SYSPARM_MAX_OUTPUT); + + if (copy_to_user(user_iob->data, kern_spbuf->val, PAPR_SYSPARM_MAX_OUTPUT)) + return -EFAULT; + + return 0; +} + +static long papr_sysparm_ioctl_get(struct papr_sysparm_io_block __user *user_iob) +{ + struct papr_sysparm_buf *kern_spbuf; + papr_sysparm_t param; + long ret; + + if (get_user(param.token, &user_iob->parameter)) + return -EFAULT; + + kern_spbuf = papr_sysparm_buf_from_user(user_iob); + if (IS_ERR(kern_spbuf)) + return PTR_ERR(kern_spbuf); + + ret = papr_sysparm_get(param, kern_spbuf); + if (ret) + goto free_sysparm_buf; + + ret = papr_sysparm_buf_to_user(kern_spbuf, user_iob); + if (ret) + goto free_sysparm_buf; + + ret = 0; + +free_sysparm_buf: + papr_sysparm_buf_free(kern_spbuf); + return ret; +} + + +static long papr_sysparm_ioctl_set(struct papr_sysparm_io_block __user *user_iob) +{ + struct papr_sysparm_buf *kern_spbuf; + papr_sysparm_t param; + long ret; + + if (get_user(param.token, &user_iob->parameter)) + return -EFAULT; + + kern_spbuf = papr_sysparm_buf_from_user(user_iob); + if (IS_ERR(kern_spbuf)) + return PTR_ERR(kern_spbuf); + + ret = papr_sysparm_set(param, kern_spbuf); + if (ret) + goto free_sysparm_buf; + + ret = 0; + +free_sysparm_buf: + papr_sysparm_buf_free(kern_spbuf); + return ret; +} + +static long papr_sysparm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) +{ + void __user *argp = (__force void __user *)arg; + long ret; + + switch (ioctl) { + case PAPR_SYSPARM_IOC_GET: + ret = papr_sysparm_ioctl_get(argp); + break; + case PAPR_SYSPARM_IOC_SET: + if (filp->f_mode & FMODE_WRITE) + ret = papr_sysparm_ioctl_set(argp); + else + ret = -EBADF; + break; + default: + ret = -ENOIOCTLCMD; + break; + } + return ret; +} + +static const struct file_operations papr_sysparm_ops = { + .unlocked_ioctl = papr_sysparm_ioctl, +}; + +static struct miscdevice papr_sysparm_dev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "papr-sysparm", + .fops = &papr_sysparm_ops, +}; + +static __init int papr_sysparm_init(void) +{ + if (!rtas_function_implemented(RTAS_FN_IBM_GET_SYSTEM_PARAMETER)) + return -ENODEV; + + return misc_register(&papr_sysparm_dev); +} +machine_device_initcall(pseries, papr_sysparm_init); diff --git a/arch/powerpc/platforms/pseries/papr-vpd.c b/arch/powerpc/platforms/pseries/papr-vpd.c new file mode 100644 index 00000000000000..c29e85db5f351b --- /dev/null +++ b/arch/powerpc/platforms/pseries/papr-vpd.c @@ -0,0 +1,541 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#define pr_fmt(fmt) "papr-vpd: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Function-specific return values for ibm,get-vpd, derived from PAPR+ + * v2.13 7.3.20 "ibm,get-vpd RTAS Call". + */ +#define RTAS_IBM_GET_VPD_COMPLETE 0 /* All VPD has been retrieved. */ +#define RTAS_IBM_GET_VPD_MORE_DATA 1 /* More VPD is available. */ +#define RTAS_IBM_GET_VPD_START_OVER -4 /* VPD changed, restart call sequence. */ + +/** + * struct rtas_ibm_get_vpd_params - Parameters (in and out) for ibm,get-vpd. + * @loc_code: In: Caller-provided location code buffer. Must be RTAS-addressable. + * @work_area: In: Caller-provided work area buffer for results. + * @sequence: In: Sequence number. Out: Next sequence number. + * @written: Out: Bytes written by ibm,get-vpd to @work_area. + * @status: Out: RTAS call status. + */ +struct rtas_ibm_get_vpd_params { + const struct papr_location_code *loc_code; + struct rtas_work_area *work_area; + u32 sequence; + u32 written; + s32 status; +}; + +/** + * rtas_ibm_get_vpd() - Call ibm,get-vpd to fill a work area buffer. + * @params: See &struct rtas_ibm_get_vpd_params. + * + * Calls ibm,get-vpd until it errors or successfully deposits data + * into the supplied work area. Handles RTAS retry statuses. Maps RTAS + * error statuses to reasonable errno values. + * + * The caller is expected to invoke rtas_ibm_get_vpd() multiple times + * to retrieve all the VPD for the provided location code. Only one + * sequence should be in progress at any time; starting a new sequence + * will disrupt any sequence already in progress. Serialization of VPD + * retrieval sequences is the responsibility of the caller. + * + * The caller should inspect @params.status to determine whether more + * calls are needed to complete the sequence. + * + * Context: May sleep. + * Return: -ve on error, 0 otherwise. + */ +static int rtas_ibm_get_vpd(struct rtas_ibm_get_vpd_params *params) +{ + const struct papr_location_code *loc_code = params->loc_code; + struct rtas_work_area *work_area = params->work_area; + u32 rets[2]; + s32 fwrc; + int ret; + + lockdep_assert_held(&rtas_ibm_get_vpd_lock); + + do { + fwrc = rtas_call(rtas_function_token(RTAS_FN_IBM_GET_VPD), 4, 3, + rets, + __pa(loc_code), + rtas_work_area_phys(work_area), + rtas_work_area_size(work_area), + params->sequence); + } while (rtas_busy_delay(fwrc)); + + switch (fwrc) { + case RTAS_HARDWARE_ERROR: + ret = -EIO; + break; + case RTAS_INVALID_PARAMETER: + ret = -EINVAL; + break; + case RTAS_IBM_GET_VPD_START_OVER: + ret = -EAGAIN; + break; + case RTAS_IBM_GET_VPD_MORE_DATA: + params->sequence = rets[0]; + fallthrough; + case RTAS_IBM_GET_VPD_COMPLETE: + params->written = rets[1]; + /* + * Kernel or firmware bug, do not continue. + */ + if (WARN(params->written > rtas_work_area_size(work_area), + "possible write beyond end of work area")) + ret = -EFAULT; + else + ret = 0; + break; + default: + ret = -EIO; + pr_err_ratelimited("unexpected ibm,get-vpd status %d\n", fwrc); + break; + } + + params->status = fwrc; + return ret; +} + +/* + * Internal VPD "blob" APIs for accumulating ibm,get-vpd results into + * an immutable buffer to be attached to a file descriptor. + */ +struct vpd_blob { + const char *data; + size_t len; +}; + +static bool vpd_blob_has_data(const struct vpd_blob *blob) +{ + return blob->data && blob->len; +} + +static void vpd_blob_free(const struct vpd_blob *blob) +{ + if (blob) { + kvfree(blob->data); + kfree(blob); + } +} + +/** + * vpd_blob_extend() - Append data to a &struct vpd_blob. + * @blob: The blob to extend. + * @data: The new data to append to @blob. + * @len: The length of @data. + * + * Context: May sleep. + * Return: -ENOMEM on allocation failure, 0 otherwise. + */ +static int vpd_blob_extend(struct vpd_blob *blob, const char *data, size_t len) +{ + const size_t new_len = blob->len + len; + const size_t old_len = blob->len; + const char *old_ptr = blob->data; + char *new_ptr; + + new_ptr = old_ptr ? + kvrealloc(old_ptr, old_len, new_len, GFP_KERNEL_ACCOUNT) : + kvmalloc(len, GFP_KERNEL_ACCOUNT); + + if (!new_ptr) + return -ENOMEM; + + memcpy(&new_ptr[old_len], data, len); + blob->data = new_ptr; + blob->len = new_len; + return 0; +} + +/** + * vpd_blob_generate() - Construct a new &struct vpd_blob. + * @generator: Function that supplies the blob data. + * @arg: Context pointer supplied by caller, passed to @generator. + * + * The @generator callback is invoked until it returns NULL. @arg is + * passed to @generator in its first argument on each call. When + * @generator returns data, it should store the data length in its + * second argument. + * + * Context: May sleep. + * Return: A completely populated &struct vpd_blob, or NULL on error. + */ +static const struct vpd_blob * +vpd_blob_generate(const char * (*generator)(void *, size_t *), void *arg) +{ + struct vpd_blob *blob; + const char *buf; + size_t len; + int err = 0; + + blob = kzalloc(sizeof(*blob), GFP_KERNEL_ACCOUNT); + if (!blob) + return NULL; + + while (err == 0 && (buf = generator(arg, &len))) + err = vpd_blob_extend(blob, buf, len); + + if (err != 0 || !vpd_blob_has_data(blob)) + goto free_blob; + + return blob; +free_blob: + vpd_blob_free(blob); + return NULL; +} + +/* + * Internal VPD sequence APIs. A VPD sequence is a series of calls to + * ibm,get-vpd for a given location code. The sequence ends when an + * error is encountered or all VPD for the location code has been + * returned. + */ + +/** + * struct vpd_sequence - State for managing a VPD sequence. + * @error: Shall be zero as long as the sequence has not encountered an error, + * -ve errno otherwise. Use vpd_sequence_set_err() to update this. + * @params: Parameter block to pass to rtas_ibm_get_vpd(). + */ +struct vpd_sequence { + int error; + struct rtas_ibm_get_vpd_params params; +}; + +/** + * vpd_sequence_begin() - Begin a VPD retrieval sequence. + * @seq: Uninitialized sequence state. + * @loc_code: Location code that defines the scope of the VPD to return. + * + * Initializes @seq with the resources necessary to carry out a VPD + * sequence. Callers must pass @seq to vpd_sequence_end() regardless + * of whether the sequence succeeds. + * + * Context: May sleep. + */ +static void vpd_sequence_begin(struct vpd_sequence *seq, + const struct papr_location_code *loc_code) +{ + /* + * Use a static data structure for the location code passed to + * RTAS to ensure it's in the RMA and avoid a separate work + * area allocation. Guarded by the function lock. + */ + static struct papr_location_code static_loc_code; + + /* + * We could allocate the work area before acquiring the + * function lock, but that would allow concurrent requests to + * exhaust the limited work area pool for no benefit. So + * allocate the work area under the lock. + */ + mutex_lock(&rtas_ibm_get_vpd_lock); + static_loc_code = *loc_code; + *seq = (struct vpd_sequence) { + .params = { + .work_area = rtas_work_area_alloc(SZ_4K), + .loc_code = &static_loc_code, + .sequence = 1, + }, + }; +} + +/** + * vpd_sequence_end() - Finalize a VPD retrieval sequence. + * @seq: Sequence state. + * + * Releases resources obtained by vpd_sequence_begin(). + */ +static void vpd_sequence_end(struct vpd_sequence *seq) +{ + rtas_work_area_free(seq->params.work_area); + mutex_unlock(&rtas_ibm_get_vpd_lock); +} + +/** + * vpd_sequence_should_stop() - Determine whether a VPD retrieval sequence + * should continue. + * @seq: VPD sequence state. + * + * Examines the sequence error state and outputs of the last call to + * ibm,get-vpd to determine whether the sequence in progress should + * continue or stop. + * + * Return: True if the sequence has encountered an error or if all VPD for + * this sequence has been retrieved. False otherwise. + */ +static bool vpd_sequence_should_stop(const struct vpd_sequence *seq) +{ + bool done; + + if (seq->error) + return true; + + switch (seq->params.status) { + case 0: + if (seq->params.written == 0) + done = false; /* Initial state. */ + else + done = true; /* All data consumed. */ + break; + case 1: + done = false; /* More data available. */ + break; + default: + done = true; /* Error encountered. */ + break; + } + + return done; +} + +static int vpd_sequence_set_err(struct vpd_sequence *seq, int err) +{ + /* Preserve the first error recorded. */ + if (seq->error == 0) + seq->error = err; + + return seq->error; +} + +/* + * Generator function to be passed to vpd_blob_generate(). + */ +static const char *vpd_sequence_fill_work_area(void *arg, size_t *len) +{ + struct vpd_sequence *seq = arg; + struct rtas_ibm_get_vpd_params *p = &seq->params; + + if (vpd_sequence_should_stop(seq)) + return NULL; + if (vpd_sequence_set_err(seq, rtas_ibm_get_vpd(p))) + return NULL; + *len = p->written; + return rtas_work_area_raw_buf(p->work_area); +} + +/* + * Higher-level VPD retrieval code below. These functions use the + * vpd_blob_* and vpd_sequence_* APIs defined above to create fd-based + * VPD handles for consumption by user space. + */ + +/** + * papr_vpd_run_sequence() - Run a single VPD retrieval sequence. + * @loc_code: Location code that defines the scope of VPD to return. + * + * Context: May sleep. Holds a mutex and an RTAS work area for its + * duration. Typically performs multiple sleepable slab + * allocations. + * + * Return: A populated &struct vpd_blob on success. Encoded error + * pointer otherwise. + */ +static const struct vpd_blob *papr_vpd_run_sequence(const struct papr_location_code *loc_code) +{ + const struct vpd_blob *blob; + struct vpd_sequence seq; + + vpd_sequence_begin(&seq, loc_code); + blob = vpd_blob_generate(vpd_sequence_fill_work_area, &seq); + if (!blob) + vpd_sequence_set_err(&seq, -ENOMEM); + vpd_sequence_end(&seq); + + if (seq.error) { + vpd_blob_free(blob); + return ERR_PTR(seq.error); + } + + return blob; +} + +/** + * papr_vpd_retrieve() - Return the VPD for a location code. + * @loc_code: Location code that defines the scope of VPD to return. + * + * Run VPD sequences against @loc_code until a blob is successfully + * instantiated, or a hard error is encountered, or a fatal signal is + * pending. + * + * Context: May sleep. + * Return: A fully populated VPD blob when successful. Encoded error + * pointer otherwise. + */ +static const struct vpd_blob *papr_vpd_retrieve(const struct papr_location_code *loc_code) +{ + const struct vpd_blob *blob; + + /* + * EAGAIN means the sequence errored with a -4 (VPD changed) + * status from ibm,get-vpd, and we should attempt a new + * sequence. PAPR+ v2.13 R1–7.3.20–5 indicates that this + * should be a transient condition, not something that happens + * continuously. But we'll stop trying on a fatal signal. + */ + do { + blob = papr_vpd_run_sequence(loc_code); + if (!IS_ERR(blob)) /* Success. */ + break; + if (PTR_ERR(blob) != -EAGAIN) /* Hard error. */ + break; + pr_info_ratelimited("VPD changed during retrieval, retrying\n"); + cond_resched(); + } while (!fatal_signal_pending(current)); + + return blob; +} + +static ssize_t papr_vpd_handle_read(struct file *file, char __user *buf, size_t size, loff_t *off) +{ + const struct vpd_blob *blob = file->private_data; + + /* bug: we should not instantiate a handle without any data attached. */ + if (!vpd_blob_has_data(blob)) { + pr_err_once("handle without data\n"); + return -EIO; + } + + return simple_read_from_buffer(buf, size, off, blob->data, blob->len); +} + +static int papr_vpd_handle_release(struct inode *inode, struct file *file) +{ + const struct vpd_blob *blob = file->private_data; + + vpd_blob_free(blob); + + return 0; +} + +static loff_t papr_vpd_handle_seek(struct file *file, loff_t off, int whence) +{ + const struct vpd_blob *blob = file->private_data; + + return fixed_size_llseek(file, off, whence, blob->len); +} + + +static const struct file_operations papr_vpd_handle_ops = { + .read = papr_vpd_handle_read, + .llseek = papr_vpd_handle_seek, + .release = papr_vpd_handle_release, +}; + +/** + * papr_vpd_create_handle() - Create a fd-based handle for reading VPD. + * @ulc: Location code in user memory; defines the scope of the VPD to + * retrieve. + * + * Handler for PAPR_VPD_IOC_CREATE_HANDLE ioctl command. Validates + * @ulc and instantiates an immutable VPD "blob" for it. The blob is + * attached to a file descriptor for reading by user space. The memory + * backing the blob is freed when the file is released. + * + * The entire requested VPD is retrieved by this call and all + * necessary RTAS interactions are performed before returning the fd + * to user space. This keeps the read handler simple and ensures that + * the kernel can prevent interleaving of ibm,get-vpd call sequences. + * + * Return: The installed fd number if successful, -ve errno otherwise. + */ +static long papr_vpd_create_handle(struct papr_location_code __user *ulc) +{ + struct papr_location_code klc; + const struct vpd_blob *blob; + struct file *file; + long err; + int fd; + + if (copy_from_user(&klc, ulc, sizeof(klc))) + return -EFAULT; + + if (!string_is_terminated(klc.str, ARRAY_SIZE(klc.str))) + return -EINVAL; + + blob = papr_vpd_retrieve(&klc); + if (IS_ERR(blob)) + return PTR_ERR(blob); + + fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC); + if (fd < 0) { + err = fd; + goto free_blob; + } + + file = anon_inode_getfile("[papr-vpd]", &papr_vpd_handle_ops, + (void *)blob, O_RDONLY); + if (IS_ERR(file)) { + err = PTR_ERR(file); + goto put_fd; + } + + file->f_mode |= FMODE_LSEEK | FMODE_PREAD; + fd_install(fd, file); + return fd; +put_fd: + put_unused_fd(fd); +free_blob: + vpd_blob_free(blob); + return err; +} + +/* + * Top-level ioctl handler for /dev/papr-vpd. + */ +static long papr_vpd_dev_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) +{ + void __user *argp = (__force void __user *)arg; + long ret; + + switch (ioctl) { + case PAPR_VPD_IOC_CREATE_HANDLE: + ret = papr_vpd_create_handle(argp); + break; + default: + ret = -ENOIOCTLCMD; + break; + } + return ret; +} + +static const struct file_operations papr_vpd_ops = { + .unlocked_ioctl = papr_vpd_dev_ioctl, +}; + +static struct miscdevice papr_vpd_dev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "papr-vpd", + .fops = &papr_vpd_ops, +}; + +static __init int papr_vpd_init(void) +{ + if (!rtas_function_implemented(RTAS_FN_IBM_GET_VPD)) + return -ENODEV; + + return misc_register(&papr_vpd_dev); +} +machine_device_initcall(pseries, papr_vpd_init); diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h index 8376f03f932a45..bba4ad192b0fe4 100644 --- a/arch/powerpc/platforms/pseries/pseries.h +++ b/arch/powerpc/platforms/pseries/pseries.h @@ -55,6 +55,7 @@ extern int dlpar_detach_node(struct device_node *); extern int dlpar_acquire_drc(u32 drc_index); extern int dlpar_release_drc(u32 drc_index); extern int dlpar_unisolate_drc(u32 drc_index); +extern void post_mobility_fixup(void); void queue_hotplug_event(struct pseries_hp_errorlog *hp_errlog); int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_errlog); diff --git a/arch/powerpc/platforms/pseries/suspend.c b/arch/powerpc/platforms/pseries/suspend.c index 5c43435472cc3b..382003dfdb9ab2 100644 --- a/arch/powerpc/platforms/pseries/suspend.c +++ b/arch/powerpc/platforms/pseries/suspend.c @@ -13,6 +13,7 @@ #include #include #include +#include "pseries.h" static struct device suspend_dev; diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index 3868483fbe292d..ef7707ea0db7bc 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c @@ -54,7 +54,7 @@ static void quirk_fsl_pcie_early(struct pci_dev *dev) /* if we aren't in host mode don't bother */ pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr_type); - if ((hdr_type & 0x7f) != PCI_HEADER_TYPE_BRIDGE) + if ((hdr_type & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_BRIDGE) return; dev->class = PCI_CLASS_BRIDGE_PCI_NORMAL; @@ -581,7 +581,7 @@ static int fsl_add_bridge(struct platform_device *pdev, int is_primary) hose->ops = &fsl_indirect_pcie_ops; /* For PCIE read HEADER_TYPE to identify controller mode */ early_read_config_byte(hose, 0, 0, PCI_HEADER_TYPE, &hdr_type); - if ((hdr_type & 0x7f) != PCI_HEADER_TYPE_BRIDGE) + if ((hdr_type & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_BRIDGE) goto no_bridge; } else { diff --git a/arch/powerpc/sysdev/grackle.c b/arch/powerpc/sysdev/grackle.c index fd2f94a884f046..7dce8278b71ee3 100644 --- a/arch/powerpc/sysdev/grackle.c +++ b/arch/powerpc/sysdev/grackle.c @@ -18,24 +18,8 @@ #define GRACKLE_CFA(b, d, o) (0x80 | ((b) << 8) | ((d) << 16) \ | (((o) & ~3) << 24)) -#define GRACKLE_PICR1_STG 0x00000040 #define GRACKLE_PICR1_LOOPSNOOP 0x00000010 -/* N.B. this is called before bridges is initialized, so we can't - use grackle_pcibios_{read,write}_config_dword. */ -static inline void grackle_set_stg(struct pci_controller* bp, int enable) -{ - unsigned int val; - - out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8)); - val = in_le32(bp->cfg_data); - val = enable? (val | GRACKLE_PICR1_STG) : - (val & ~GRACKLE_PICR1_STG); - out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8)); - out_le32(bp->cfg_data, val); - (void)in_le32(bp->cfg_data); -} - static inline void grackle_set_loop_snoop(struct pci_controller *bp, int enable) { unsigned int val; @@ -56,7 +40,4 @@ void __init setup_grackle(struct pci_controller *hose) pci_add_flags(PCI_REASSIGN_ALL_BUS); if (of_machine_is_compatible("AAPL,PowerBook1998")) grackle_set_loop_snoop(hose, 1); -#if 0 /* Disabled for now, HW problems ??? */ - grackle_set_stg(hose, 1); -#endif } diff --git a/arch/powerpc/sysdev/xics/icp-native.c b/arch/powerpc/sysdev/xics/icp-native.c index f6ec6dba92dcbc..700b67476a7d8d 100644 --- a/arch/powerpc/sysdev/xics/icp-native.c +++ b/arch/powerpc/sysdev/xics/icp-native.c @@ -236,6 +236,8 @@ static int __init icp_native_map_one_cpu(int hw_id, unsigned long addr, rname = kasprintf(GFP_KERNEL, "CPU %d [0x%x] Interrupt Presentation", cpu, hw_id); + if (!rname) + return -ENOMEM; if (!request_mem_region(addr, size, rname)) { pr_warn("icp_native: Could not reserve ICP MMIO for CPU %d, interrupt server #0x%x\n", cpu, hw_id); diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index cd4c9a204d08c9..bffbd869a06828 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -53,24 +53,28 @@ config RISCV select ARCH_USE_MEMTEST select ARCH_USE_QUEUED_RWLOCKS select ARCH_USES_CFI_TRAPS if CFI_CLANG + select ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH if SMP && MMU select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT if MMU select ARCH_WANT_FRAME_POINTERS select ARCH_WANT_GENERAL_HUGETLB if !RISCV_ISA_SVNAPOT select ARCH_WANT_HUGE_PMD_SHARE if 64BIT select ARCH_WANT_LD_ORPHAN_WARN if !XIP_KERNEL select ARCH_WANT_OPTIMIZE_HUGETLB_VMEMMAP + select ARCH_WANTS_NO_INSTR select ARCH_WANTS_THP_SWAP if HAVE_ARCH_TRANSPARENT_HUGEPAGE select BINFMT_FLAT_NO_DATA_START_OFFSET if !MMU select BUILDTIME_TABLE_SORT if MMU select CLINT_TIMER if !MMU select CLONE_BACKWARDS select COMMON_CLK - select CPU_PM if CPU_IDLE || HIBERNATION + select CPU_PM if CPU_IDLE || HIBERNATION || SUSPEND select EDAC_SUPPORT select FRAME_POINTER if PERF_EVENTS || (FUNCTION_TRACER && !DYNAMIC_FTRACE) + select FTRACE_MCOUNT_USE_PATCHABLE_FUNCTION_ENTRY if DYNAMIC_FTRACE select GENERIC_ARCH_TOPOLOGY select GENERIC_ATOMIC64 if !64BIT select GENERIC_CLOCKEVENTS_BROADCAST if SMP + select GENERIC_CPU_DEVICES select GENERIC_EARLY_IOREMAP select GENERIC_ENTRY select GENERIC_GETTIMEOFDAY if HAVE_GENERIC_VDSO @@ -113,6 +117,7 @@ config RISCV select HAVE_DEBUG_KMEMLEAK select HAVE_DMA_CONTIGUOUS if MMU select HAVE_DYNAMIC_FTRACE if !XIP_KERNEL && MMU && (CLANG_SUPPORTS_DYNAMIC_FTRACE || GCC_SUPPORTS_DYNAMIC_FTRACE) + select HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS select HAVE_DYNAMIC_FTRACE_WITH_REGS if HAVE_DYNAMIC_FTRACE select HAVE_FTRACE_MCOUNT_RECORD if !XIP_KERNEL select HAVE_FUNCTION_GRAPH_TRACER @@ -140,6 +145,8 @@ config RISCV select HAVE_REGS_AND_STACK_ACCESS_API select HAVE_RETHOOK if !XIP_KERNEL select HAVE_RSEQ + select HAVE_SAMPLE_FTRACE_DIRECT + select HAVE_SAMPLE_FTRACE_DIRECT_MULTI select HAVE_STACKPROTECTOR select HAVE_SYSCALL_TRACEPOINTS select HOTPLUG_CORE_SYNC_DEAD if HOTPLUG_CPU @@ -181,6 +188,20 @@ config HAVE_SHADOW_CALL_STACK # https://github.com/riscv-non-isa/riscv-elf-psabi-doc/commit/a484e843e6eeb51f0cb7b8819e50da6d2444d769 depends on $(ld-option,--no-relax-gp) +config RISCV_USE_LINKER_RELAXATION + def_bool y + # https://github.com/llvm/llvm-project/commit/6611d58f5bbcbec77262d392e2923e1d680f6985 + depends on !LD_IS_LLD || LLD_VERSION >= 150000 + +# https://github.com/llvm/llvm-project/commit/bbc0f99f3bc96f1db16f649fc21dd18e5b0918f6 +config ARCH_HAS_BROKEN_DWARF5 + def_bool y + depends on RISCV_USE_LINKER_RELAXATION + # https://github.com/llvm/llvm-project/commit/1df5ea29b43690b6622db2cad7b745607ca4de6a + depends on AS_IS_LLVM && AS_VERSION < 180000 + # https://github.com/llvm/llvm-project/commit/7ffabb61a5569444b5ac9322e22e5471cc5e4a77 + depends on LD_IS_LLD && LLD_VERSION < 180000 + config ARCH_MMAP_RND_BITS_MIN default 18 if 64BIT default 8 @@ -414,7 +435,9 @@ config NUMA depends on SMP && MMU select ARCH_SUPPORTS_NUMA_BALANCING select GENERIC_ARCH_NUMA + select HAVE_SETUP_PER_CPU_AREA select NEED_PER_CPU_EMBED_FIRST_CHUNK + select NEED_PER_CPU_PAGE_FIRST_CHUNK select OF_NUMA select USE_PERCPU_NUMA_NODE_ID help @@ -525,6 +548,28 @@ config RISCV_ISA_V_DEFAULT_ENABLE If you don't know what to do here, say Y. +config RISCV_ISA_V_UCOPY_THRESHOLD + int "Threshold size for vectorized user copies" + depends on RISCV_ISA_V + default 768 + help + Prefer using vectorized copy_to_user()/copy_from_user() when the + workload size exceeds this value. + +config RISCV_ISA_V_PREEMPTIVE + bool "Run kernel-mode Vector with kernel preemption" + depends on PREEMPTION + depends on RISCV_ISA_V + default y + help + Usually, in-kernel SIMD routines are run with preemption disabled. + Functions which envoke long running SIMD thus must yield core's + vector unit to prevent blocking other tasks for too long. + + This config allows kernel to run SIMD without explicitly disable + preemption. Enabling this config will result in higher memory + consumption due to the allocation of per-task's kernel Vector context. + config TOOLCHAIN_HAS_ZBB bool default y @@ -651,6 +696,20 @@ config RISCV_MISALIGNED load/store for both kernel and userspace. When disable, misaligned accesses will generate SIGBUS in userspace and panic in kernel. +config RISCV_EFFICIENT_UNALIGNED_ACCESS + bool "Assume the CPU supports fast unaligned memory accesses" + depends on NONPORTABLE + select DCACHE_WORD_ACCESS if MMU + select HAVE_EFFICIENT_UNALIGNED_ACCESS + help + Say Y here if you want the kernel to assume that the CPU supports + efficient unaligned memory accesses. When enabled, this option + improves the performance of the kernel on such CPUs. However, the + kernel will run much more slowly, or will not be able to run at all, + on CPUs that do not support efficient unaligned memory accesses. + + If unsure what to do here, say N. + endmenu # "Platform type" menu "Kernel features" @@ -722,6 +781,25 @@ config COMPAT If you want to execute 32-bit userspace applications, say Y. +config PARAVIRT + bool "Enable paravirtualization code" + depends on RISCV_SBI + help + This changes the kernel so it can modify itself when it is run + under a hypervisor, potentially improving performance significantly + over full virtualization. + +config PARAVIRT_TIME_ACCOUNTING + bool "Paravirtual steal time accounting" + depends on PARAVIRT + help + Select this option to enable fine granularity task steal time + accounting. Time spent executing other tasks in parallel with + the current vCPU is discounted from the vCPU power. To account for + that, there can be a small performance impact. + + If in doubt, say N here. + config RELOCATABLE bool "Build a relocatable kernel" depends on MMU && 64BIT && !XIP_KERNEL @@ -902,13 +980,13 @@ config RISCV_ISA_FALLBACK on the replacement properties, "riscv,isa-base" and "riscv,isa-extensions". -endmenu # "Boot options" - config BUILTIN_DTB - bool + bool "Built-in device tree" depends on OF && NONPORTABLE default y if XIP_KERNEL +endmenu # "Boot options" + config PORTABLE bool default !NONPORTABLE diff --git a/arch/riscv/Kconfig.errata b/arch/riscv/Kconfig.errata index e2c731cfed8cc6..910ba8837add86 100644 --- a/arch/riscv/Kconfig.errata +++ b/arch/riscv/Kconfig.errata @@ -53,6 +53,25 @@ config ERRATA_SIFIVE_CIP_1200 If you don't know what to do here, say "Y". +config ERRATA_STARFIVE_JH7100 + bool "StarFive JH7100 support" + depends on ARCH_STARFIVE + depends on !DMA_DIRECT_REMAP + depends on NONPORTABLE + select DMA_GLOBAL_POOL + select RISCV_DMA_NONCOHERENT + select RISCV_NONSTANDARD_CACHE_OPS + select SIFIVE_CCACHE + default n + help + The StarFive JH7100 was a test chip for the JH7110 and has + caches that are non-coherent with respect to peripheral DMAs. + It was designed before the Zicbom extension so needs non-standard + cache operations through the SiFive cache controller. + + Say "Y" if you want to support the BeagleV Starlight and/or + StarFive VisionFive V1 boards. + config ERRATA_THEAD bool "T-HEAD errata" depends on RISCV_ALTERNATIVE @@ -79,6 +98,7 @@ config ERRATA_THEAD_CMO depends on ERRATA_THEAD && MMU select DMA_DIRECT_REMAP select RISCV_DMA_NONCOHERENT + select RISCV_NONSTANDARD_CACHE_OPS default y help This will apply the cache management errata to handle the diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index a74be78678eb0b..0b7d109258e7d8 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile @@ -43,8 +43,7 @@ else KBUILD_LDFLAGS += -melf32lriscv endif -ifeq ($(CONFIG_LD_IS_LLD),y) -ifeq ($(call test-lt, $(CONFIG_LLD_VERSION), 150000),y) +ifndef CONFIG_RISCV_USE_LINKER_RELAXATION KBUILD_CFLAGS += -mno-relax KBUILD_AFLAGS += -mno-relax ifndef CONFIG_AS_IS_LLVM @@ -52,7 +51,6 @@ ifndef CONFIG_AS_IS_LLVM KBUILD_AFLAGS += -Wa,-mno-relax endif endif -endif ifeq ($(CONFIG_SHADOW_CALL_STACK),y) KBUILD_LDFLAGS += --no-relax-gp @@ -108,7 +106,9 @@ KBUILD_AFLAGS_MODULE += $(call as-option,-Wa$(comma)-mno-relax) # unaligned accesses. While unaligned accesses are explicitly allowed in the # RISC-V ISA, they're emulated by machine mode traps on all extant # architectures. It's faster to have GCC emit only aligned accesses. +ifneq ($(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS),y) KBUILD_CFLAGS += $(call cc-option,-mstrict-align) +endif ifeq ($(CONFIG_STACKPROTECTOR_PER_TASK),y) prepare: stack_protector_prepare @@ -163,6 +163,8 @@ BOOT_TARGETS := Image Image.gz loader loader.bin xipImage vmlinuz.efi all: $(notdir $(KBUILD_IMAGE)) +loader.bin: loader +Image.gz loader vmlinuz.efi: Image $(BOOT_TARGETS): vmlinux $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ @$(kecho) ' Kernel: $(boot)/$@ is ready' diff --git a/arch/riscv/boot/dts/microchip/mpfs-icicle-kit.dts b/arch/riscv/boot/dts/microchip/mpfs-icicle-kit.dts index dce96f27cc89a4..222a39d90f85da 100644 --- a/arch/riscv/boot/dts/microchip/mpfs-icicle-kit.dts +++ b/arch/riscv/boot/dts/microchip/mpfs-icicle-kit.dts @@ -192,6 +192,27 @@ status = "okay"; }; +&syscontroller_qspi { + /* + * The flash *is* there, but Icicle kits that have engineering sample + * silicon (write?) access to this flash to non-functional. The system + * controller itself can actually access it, but the MSS cannot write + * an image there. Instantiating a coreQSPI in the fabric & connecting + * it to the flash instead should work though. Pre-production or later + * silicon does not have this issue. + */ + status = "disabled"; + + sys_ctrl_flash: flash@0 { // MT25QL01GBBB8ESF-0SIT + compatible = "jedec,spi-nor"; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <20000000>; + spi-rx-bus-width = <1>; + reg = <0>; + }; +}; + &usb { status = "okay"; dr_mode = "host"; diff --git a/arch/riscv/boot/dts/microchip/mpfs.dtsi b/arch/riscv/boot/dts/microchip/mpfs.dtsi index 266489d43912fc..59fd2d4ea523b8 100644 --- a/arch/riscv/boot/dts/microchip/mpfs.dtsi +++ b/arch/riscv/boot/dts/microchip/mpfs.dtsi @@ -194,6 +194,12 @@ mboxes = <&mbox 0>; }; + scbclk: mssclkclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <80000000>; + }; + soc { #address-cells = <2>; #size-cells = <2>; @@ -524,5 +530,16 @@ #mbox-cells = <1>; status = "disabled"; }; + + syscontroller_qspi: spi@37020100 { + compatible = "microchip,mpfs-qspi", "microchip,coreqspi-rtl-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0 0x37020100 0x0 0x100>; + interrupt-parent = <&plic>; + interrupts = <110>; + clocks = <&scbclk>; + status = "disabled"; + }; }; }; diff --git a/arch/riscv/boot/dts/renesas/r9a07g043f.dtsi b/arch/riscv/boot/dts/renesas/r9a07g043f.dtsi index b0796015e36b1b..a92cfcfc021b4c 100644 --- a/arch/riscv/boot/dts/renesas/r9a07g043f.dtsi +++ b/arch/riscv/boot/dts/renesas/r9a07g043f.dtsi @@ -24,6 +24,10 @@ reg = <0x0>; status = "okay"; riscv,isa = "rv64imafdc"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", + "zicntr", "zicsr", "zifencei", + "zihpm"; mmu-type = "riscv,sv39"; i-cache-size = <0x8000>; i-cache-line-size = <0x40>; diff --git a/arch/riscv/boot/dts/sophgo/Makefile b/arch/riscv/boot/dts/sophgo/Makefile index 3fb65512c6312f..57ad82a61ea6fc 100644 --- a/arch/riscv/boot/dts/sophgo/Makefile +++ b/arch/riscv/boot/dts/sophgo/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 dtb-$(CONFIG_ARCH_SOPHGO) += cv1800b-milkv-duo.dtb +dtb-$(CONFIG_ARCH_SOPHGO) += cv1812h-huashan-pi.dtb dtb-$(CONFIG_ARCH_SOPHGO) += sg2042-milkv-pioneer.dtb diff --git a/arch/riscv/boot/dts/sophgo/cv1800b.dtsi b/arch/riscv/boot/dts/sophgo/cv1800b.dtsi index aec6401a467b02..165e9e320a8c72 100644 --- a/arch/riscv/boot/dts/sophgo/cv1800b.dtsi +++ b/arch/riscv/boot/dts/sophgo/cv1800b.dtsi @@ -3,120 +3,16 @@ * Copyright (C) 2023 Jisheng Zhang */ -#include +#include "cv18xx.dtsi" / { compatible = "sophgo,cv1800b"; - #address-cells = <1>; - #size-cells = <1>; - - cpus: cpus { - #address-cells = <1>; - #size-cells = <0>; - timebase-frequency = <25000000>; - - cpu0: cpu@0 { - compatible = "thead,c906", "riscv"; - device_type = "cpu"; - reg = <0>; - d-cache-block-size = <64>; - d-cache-sets = <512>; - d-cache-size = <65536>; - i-cache-block-size = <64>; - i-cache-sets = <128>; - i-cache-size = <32768>; - mmu-type = "riscv,sv39"; - riscv,isa = "rv64imafdc"; - riscv,isa-base = "rv64i"; - riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", - "zifencei", "zihpm"; - - cpu0_intc: interrupt-controller { - compatible = "riscv,cpu-intc"; - interrupt-controller; - #interrupt-cells = <1>; - }; - }; - }; - - osc: oscillator { - compatible = "fixed-clock"; - clock-output-names = "osc_25m"; - #clock-cells = <0>; - }; - - soc { - compatible = "simple-bus"; - interrupt-parent = <&plic>; - #address-cells = <1>; - #size-cells = <1>; - dma-noncoherent; - ranges; - - uart0: serial@4140000 { - compatible = "snps,dw-apb-uart"; - reg = <0x04140000 0x100>; - interrupts = <44 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&osc>; - reg-shift = <2>; - reg-io-width = <4>; - status = "disabled"; - }; - - uart1: serial@4150000 { - compatible = "snps,dw-apb-uart"; - reg = <0x04150000 0x100>; - interrupts = <45 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&osc>; - reg-shift = <2>; - reg-io-width = <4>; - status = "disabled"; - }; - - uart2: serial@4160000 { - compatible = "snps,dw-apb-uart"; - reg = <0x04160000 0x100>; - interrupts = <46 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&osc>; - reg-shift = <2>; - reg-io-width = <4>; - status = "disabled"; - }; - - uart3: serial@4170000 { - compatible = "snps,dw-apb-uart"; - reg = <0x04170000 0x100>; - interrupts = <47 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&osc>; - reg-shift = <2>; - reg-io-width = <4>; - status = "disabled"; - }; - - uart4: serial@41c0000 { - compatible = "snps,dw-apb-uart"; - reg = <0x041c0000 0x100>; - interrupts = <48 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&osc>; - reg-shift = <2>; - reg-io-width = <4>; - status = "disabled"; - }; +}; - plic: interrupt-controller@70000000 { - compatible = "sophgo,cv1800b-plic", "thead,c900-plic"; - reg = <0x70000000 0x4000000>; - interrupts-extended = <&cpu0_intc 11>, <&cpu0_intc 9>; - interrupt-controller; - #address-cells = <0>; - #interrupt-cells = <2>; - riscv,ndev = <101>; - }; +&plic { + compatible = "sophgo,cv1800b-plic", "thead,c900-plic"; +}; - clint: timer@74000000 { - compatible = "sophgo,cv1800b-clint", "thead,c900-clint"; - reg = <0x74000000 0x10000>; - interrupts-extended = <&cpu0_intc 3>, <&cpu0_intc 7>; - }; - }; +&clint { + compatible = "sophgo,cv1800b-clint", "thead,c900-clint"; }; diff --git a/arch/riscv/boot/dts/sophgo/cv1812h-huashan-pi.dts b/arch/riscv/boot/dts/sophgo/cv1812h-huashan-pi.dts new file mode 100644 index 00000000000000..aa361f3a86bb58 --- /dev/null +++ b/arch/riscv/boot/dts/sophgo/cv1812h-huashan-pi.dts @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2023 Inochi Amaoto + */ + +/dts-v1/; + +#include "cv1812h.dtsi" + +/ { + model = "Huashan Pi"; + compatible = "sophgo,huashan-pi", "sophgo,cv1812h"; + + aliases { + gpio0 = &gpio0; + gpio1 = &gpio1; + gpio2 = &gpio2; + gpio3 = &gpio3; + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + serial3 = &uart3; + serial4 = &uart4; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + coprocessor_rtos: region@8fe00000 { + reg = <0x8fe00000 0x200000>; + no-map; + }; + }; +}; + +&osc { + clock-frequency = <25000000>; +}; + +&uart0 { + status = "okay"; +}; diff --git a/arch/riscv/boot/dts/sophgo/cv1812h.dtsi b/arch/riscv/boot/dts/sophgo/cv1812h.dtsi new file mode 100644 index 00000000000000..3e7a942f5c1a5a --- /dev/null +++ b/arch/riscv/boot/dts/sophgo/cv1812h.dtsi @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2023 Inochi Amaoto + */ + +#include +#include "cv18xx.dtsi" + +/ { + compatible = "sophgo,cv1812h"; + + memory@80000000 { + device_type = "memory"; + reg = <0x80000000 0x10000000>; + }; +}; + +&plic { + compatible = "sophgo,cv1812h-plic", "thead,c900-plic"; +}; + +&clint { + compatible = "sophgo,cv1812h-clint", "thead,c900-clint"; +}; diff --git a/arch/riscv/boot/dts/sophgo/cv18xx.dtsi b/arch/riscv/boot/dts/sophgo/cv18xx.dtsi new file mode 100644 index 00000000000000..2d6f4a4b1e58b4 --- /dev/null +++ b/arch/riscv/boot/dts/sophgo/cv18xx.dtsi @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2023 Jisheng Zhang + * Copyright (C) 2023 Inochi Amaoto + */ + +#include + +/ { + #address-cells = <1>; + #size-cells = <1>; + + cpus: cpus { + #address-cells = <1>; + #size-cells = <0>; + timebase-frequency = <25000000>; + + cpu0: cpu@0 { + compatible = "thead,c906", "riscv"; + device_type = "cpu"; + reg = <0>; + d-cache-block-size = <64>; + d-cache-sets = <512>; + d-cache-size = <65536>; + i-cache-block-size = <64>; + i-cache-sets = <128>; + i-cache-size = <32768>; + mmu-type = "riscv,sv39"; + riscv,isa = "rv64imafdc"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", + "zifencei", "zihpm"; + + cpu0_intc: interrupt-controller { + compatible = "riscv,cpu-intc"; + interrupt-controller; + #interrupt-cells = <1>; + }; + }; + }; + + osc: oscillator { + compatible = "fixed-clock"; + clock-output-names = "osc_25m"; + #clock-cells = <0>; + }; + + soc { + compatible = "simple-bus"; + interrupt-parent = <&plic>; + #address-cells = <1>; + #size-cells = <1>; + dma-noncoherent; + ranges; + + gpio0: gpio@3020000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x3020000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + + porta: gpio-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <32>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <60 IRQ_TYPE_LEVEL_HIGH>; + }; + }; + + gpio1: gpio@3021000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x3021000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + + portb: gpio-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <32>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <61 IRQ_TYPE_LEVEL_HIGH>; + }; + }; + + gpio2: gpio@3022000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x3022000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + + portc: gpio-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <32>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <62 IRQ_TYPE_LEVEL_HIGH>; + }; + }; + + gpio3: gpio@3023000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x3023000 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + + portd: gpio-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <32>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <63 IRQ_TYPE_LEVEL_HIGH>; + }; + }; + + uart0: serial@4140000 { + compatible = "snps,dw-apb-uart"; + reg = <0x04140000 0x100>; + interrupts = <44 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&osc>; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; + }; + + uart1: serial@4150000 { + compatible = "snps,dw-apb-uart"; + reg = <0x04150000 0x100>; + interrupts = <45 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&osc>; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; + }; + + uart2: serial@4160000 { + compatible = "snps,dw-apb-uart"; + reg = <0x04160000 0x100>; + interrupts = <46 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&osc>; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; + }; + + uart3: serial@4170000 { + compatible = "snps,dw-apb-uart"; + reg = <0x04170000 0x100>; + interrupts = <47 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&osc>; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; + }; + + uart4: serial@41c0000 { + compatible = "snps,dw-apb-uart"; + reg = <0x041c0000 0x100>; + interrupts = <48 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&osc>; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; + }; + + plic: interrupt-controller@70000000 { + reg = <0x70000000 0x4000000>; + interrupts-extended = <&cpu0_intc 11>, <&cpu0_intc 9>; + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <2>; + riscv,ndev = <101>; + }; + + clint: timer@74000000 { + reg = <0x74000000 0x10000>; + interrupts-extended = <&cpu0_intc 3>, <&cpu0_intc 7>; + }; + }; +}; diff --git a/arch/riscv/boot/dts/sophgo/sg2042.dtsi b/arch/riscv/boot/dts/sophgo/sg2042.dtsi index 93256540d07882..ead1cc35d88b2f 100644 --- a/arch/riscv/boot/dts/sophgo/sg2042.dtsi +++ b/arch/riscv/boot/dts/sophgo/sg2042.dtsi @@ -93,144 +93,160 @@ <&cpu63_intc 3>; }; - clint_mtimer0: timer@70ac000000 { + clint_mtimer0: timer@70ac004000 { compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; - reg = <0x00000070 0xac000000 0x00000000 0x00007ff8>; + reg = <0x00000070 0xac004000 0x00000000 0x0000c000>; + reg-names = "mtimecmp"; interrupts-extended = <&cpu0_intc 7>, <&cpu1_intc 7>, <&cpu2_intc 7>, <&cpu3_intc 7>; }; - clint_mtimer1: timer@70ac010000 { + clint_mtimer1: timer@70ac014000 { compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; - reg = <0x00000070 0xac010000 0x00000000 0x00007ff8>; + reg = <0x00000070 0xac014000 0x00000000 0x0000c000>; + reg-names = "mtimecmp"; interrupts-extended = <&cpu4_intc 7>, <&cpu5_intc 7>, <&cpu6_intc 7>, <&cpu7_intc 7>; }; - clint_mtimer2: timer@70ac020000 { + clint_mtimer2: timer@70ac024000 { compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; - reg = <0x00000070 0xac020000 0x00000000 0x00007ff8>; + reg = <0x00000070 0xac024000 0x00000000 0x0000c000>; + reg-names = "mtimecmp"; interrupts-extended = <&cpu8_intc 7>, <&cpu9_intc 7>, <&cpu10_intc 7>, <&cpu11_intc 7>; }; - clint_mtimer3: timer@70ac030000 { + clint_mtimer3: timer@70ac034000 { compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; - reg = <0x00000070 0xac030000 0x00000000 0x00007ff8>; + reg = <0x00000070 0xac034000 0x00000000 0x0000c000>; + reg-names = "mtimecmp"; interrupts-extended = <&cpu12_intc 7>, <&cpu13_intc 7>, <&cpu14_intc 7>, <&cpu15_intc 7>; }; - clint_mtimer4: timer@70ac040000 { + clint_mtimer4: timer@70ac044000 { compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; - reg = <0x00000070 0xac040000 0x00000000 0x00007ff8>; + reg = <0x00000070 0xac044000 0x00000000 0x0000c000>; + reg-names = "mtimecmp"; interrupts-extended = <&cpu16_intc 7>, <&cpu17_intc 7>, <&cpu18_intc 7>, <&cpu19_intc 7>; }; - clint_mtimer5: timer@70ac050000 { + clint_mtimer5: timer@70ac054000 { compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; - reg = <0x00000070 0xac050000 0x00000000 0x00007ff8>; + reg = <0x00000070 0xac054000 0x00000000 0x0000c000>; + reg-names = "mtimecmp"; interrupts-extended = <&cpu20_intc 7>, <&cpu21_intc 7>, <&cpu22_intc 7>, <&cpu23_intc 7>; }; - clint_mtimer6: timer@70ac060000 { + clint_mtimer6: timer@70ac064000 { compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; - reg = <0x00000070 0xac060000 0x00000000 0x00007ff8>; + reg = <0x00000070 0xac064000 0x00000000 0x0000c000>; + reg-names = "mtimecmp"; interrupts-extended = <&cpu24_intc 7>, <&cpu25_intc 7>, <&cpu26_intc 7>, <&cpu27_intc 7>; }; - clint_mtimer7: timer@70ac070000 { + clint_mtimer7: timer@70ac074000 { compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; - reg = <0x00000070 0xac070000 0x00000000 0x00007ff8>; + reg = <0x00000070 0xac074000 0x00000000 0x0000c000>; + reg-names = "mtimecmp"; interrupts-extended = <&cpu28_intc 7>, <&cpu29_intc 7>, <&cpu30_intc 7>, <&cpu31_intc 7>; }; - clint_mtimer8: timer@70ac080000 { + clint_mtimer8: timer@70ac084000 { compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; - reg = <0x00000070 0xac080000 0x00000000 0x00007ff8>; + reg = <0x00000070 0xac084000 0x00000000 0x0000c000>; + reg-names = "mtimecmp"; interrupts-extended = <&cpu32_intc 7>, <&cpu33_intc 7>, <&cpu34_intc 7>, <&cpu35_intc 7>; }; - clint_mtimer9: timer@70ac090000 { + clint_mtimer9: timer@70ac094000 { compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; - reg = <0x00000070 0xac090000 0x00000000 0x00007ff8>; + reg = <0x00000070 0xac094000 0x00000000 0x0000c000>; + reg-names = "mtimecmp"; interrupts-extended = <&cpu36_intc 7>, <&cpu37_intc 7>, <&cpu38_intc 7>, <&cpu39_intc 7>; }; - clint_mtimer10: timer@70ac0a0000 { + clint_mtimer10: timer@70ac0a4000 { compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; - reg = <0x00000070 0xac0a0000 0x00000000 0x00007ff8>; + reg = <0x00000070 0xac0a4000 0x00000000 0x0000c000>; + reg-names = "mtimecmp"; interrupts-extended = <&cpu40_intc 7>, <&cpu41_intc 7>, <&cpu42_intc 7>, <&cpu43_intc 7>; }; - clint_mtimer11: timer@70ac0b0000 { + clint_mtimer11: timer@70ac0b4000 { compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; - reg = <0x00000070 0xac0b0000 0x00000000 0x00007ff8>; + reg = <0x00000070 0xac0b4000 0x00000000 0x0000c000>; + reg-names = "mtimecmp"; interrupts-extended = <&cpu44_intc 7>, <&cpu45_intc 7>, <&cpu46_intc 7>, <&cpu47_intc 7>; }; - clint_mtimer12: timer@70ac0c0000 { + clint_mtimer12: timer@70ac0c4000 { compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; - reg = <0x00000070 0xac0c0000 0x00000000 0x00007ff8>; + reg = <0x00000070 0xac0c4000 0x00000000 0x0000c000>; + reg-names = "mtimecmp"; interrupts-extended = <&cpu48_intc 7>, <&cpu49_intc 7>, <&cpu50_intc 7>, <&cpu51_intc 7>; }; - clint_mtimer13: timer@70ac0d0000 { + clint_mtimer13: timer@70ac0d4000 { compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; - reg = <0x00000070 0xac0d0000 0x00000000 0x00007ff8>; + reg = <0x00000070 0xac0d4000 0x00000000 0x0000c000>; + reg-names = "mtimecmp"; interrupts-extended = <&cpu52_intc 7>, <&cpu53_intc 7>, <&cpu54_intc 7>, <&cpu55_intc 7>; }; - clint_mtimer14: timer@70ac0e0000 { + clint_mtimer14: timer@70ac0e4000 { compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; - reg = <0x00000070 0xac0e0000 0x00000000 0x00007ff8>; + reg = <0x00000070 0xac0e4000 0x00000000 0x0000c000>; + reg-names = "mtimecmp"; interrupts-extended = <&cpu56_intc 7>, <&cpu57_intc 7>, <&cpu58_intc 7>, <&cpu59_intc 7>; }; - clint_mtimer15: timer@70ac0f0000 { + clint_mtimer15: timer@70ac0f4000 { compatible = "sophgo,sg2042-aclint-mtimer", "thead,c900-aclint-mtimer"; - reg = <0x00000070 0xac0f0000 0x00000000 0x00007ff8>; + reg = <0x00000070 0xac0f4000 0x00000000 0x0000c000>; + reg-names = "mtimecmp"; interrupts-extended = <&cpu60_intc 7>, <&cpu61_intc 7>, <&cpu62_intc 7>, diff --git a/arch/riscv/boot/dts/starfive/jh7100-common.dtsi b/arch/riscv/boot/dts/starfive/jh7100-common.dtsi index b93ce351a90f48..42fb61c36068cd 100644 --- a/arch/riscv/boot/dts/starfive/jh7100-common.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7100-common.dtsi @@ -12,6 +12,8 @@ / { aliases { + mmc0 = &sdio0; + mmc1 = &sdio1; serial0 = &uart3; }; @@ -39,6 +41,35 @@ label = "ack"; }; }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + dma-reserved@fa000000 { + reg = <0x0 0xfa000000 0x0 0x1000000>; + no-map; + }; + + linux,dma@107a000000 { + compatible = "shared-dma-pool"; + reg = <0x10 0x7a000000 0x0 0x1000000>; + no-map; + linux,dma-default; + }; + }; + + soc { + dma-ranges = <0x00 0x80000000 0x00 0x80000000 0x00 0x7a000000>, + <0x00 0xfa000000 0x10 0x7a000000 0x00 0x01000000>, + <0x00 0xfb000000 0x00 0xfb000000 0x07 0x85000000>; + }; + + wifi_pwrseq: wifi-pwrseq { + compatible = "mmc-pwrseq-simple"; + reset-gpios = <&gpio 37 GPIO_ACTIVE_LOW>; + }; }; &gpio { @@ -84,6 +115,78 @@ }; }; + sdio0_pins: sdio0-0 { + clk-pins { + pinmux = ; + bias-disable; + input-disable; + input-schmitt-disable; + }; + sdio-pins { + pinmux = , + , + , + , + , + ; + bias-pull-up; + input-enable; + input-schmitt-enable; + }; + }; + + sdio1_pins: sdio1-0 { + clk-pins { + pinmux = ; + bias-disable; + input-disable; + input-schmitt-disable; + }; + sdio-pins { + pinmux = , + , + , + , + ; + bias-pull-up; + input-enable; + input-schmitt-enable; + }; + }; + uart3_pins: uart3-0 { rx-pins { pinmux = ; }; +&sdio0 { + broken-cd; + bus-width = <4>; + cap-sd-highspeed; + pinctrl-names = "default"; + pinctrl-0 = <&sdio0_pins>; + status = "okay"; +}; + +&sdio1 { + #address-cells = <1>; + #size-cells = <0>; + bus-width = <4>; + cap-sd-highspeed; + cap-sdio-irq; + cap-power-off-card; + mmc-pwrseq = <&wifi_pwrseq>; + non-removable; + pinctrl-names = "default"; + pinctrl-0 = <&sdio1_pins>; + status = "okay"; + + wifi@1 { + compatible = "brcm,bcm4329-fmac"; + reg = <1>; + }; +}; + &uart3 { pinctrl-names = "default"; pinctrl-0 = <&uart3_pins>; diff --git a/arch/riscv/boot/dts/starfive/jh7100.dtsi b/arch/riscv/boot/dts/starfive/jh7100.dtsi index e68cafe7545f75..c216aaecac53f2 100644 --- a/arch/riscv/boot/dts/starfive/jh7100.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7100.dtsi @@ -32,6 +32,7 @@ i-tlb-sets = <1>; i-tlb-size = <32>; mmu-type = "riscv,sv39"; + next-level-cache = <&ccache>; riscv,isa = "rv64imafdc"; riscv,isa-base = "rv64i"; riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", @@ -60,6 +61,7 @@ i-tlb-sets = <1>; i-tlb-size = <32>; mmu-type = "riscv,sv39"; + next-level-cache = <&ccache>; riscv,isa = "rv64imafdc"; riscv,isa-base = "rv64i"; riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", @@ -144,26 +146,64 @@ interrupt-parent = <&plic>; #address-cells = <2>; #size-cells = <2>; + dma-noncoherent; ranges; clint: clint@2000000 { compatible = "starfive,jh7100-clint", "sifive,clint0"; reg = <0x0 0x2000000 0x0 0x10000>; - interrupts-extended = <&cpu0_intc 3 &cpu0_intc 7 - &cpu1_intc 3 &cpu1_intc 7>; + interrupts-extended = <&cpu0_intc 3>, <&cpu0_intc 7>, + <&cpu1_intc 3>, <&cpu1_intc 7>; + }; + + ccache: cache-controller@2010000 { + compatible = "starfive,jh7100-ccache", "sifive,ccache0", "cache"; + reg = <0x0 0x2010000 0x0 0x1000>; + interrupts = <128>, <130>, <131>, <129>; + cache-block-size = <64>; + cache-level = <2>; + cache-sets = <2048>; + cache-size = <2097152>; + cache-unified; }; plic: interrupt-controller@c000000 { compatible = "starfive,jh7100-plic", "sifive,plic-1.0.0"; reg = <0x0 0xc000000 0x0 0x4000000>; - interrupts-extended = <&cpu0_intc 11 &cpu0_intc 9 - &cpu1_intc 11 &cpu1_intc 9>; + interrupts-extended = <&cpu0_intc 11>, <&cpu0_intc 9>, + <&cpu1_intc 11>, <&cpu1_intc 9>; interrupt-controller; #address-cells = <0>; #interrupt-cells = <1>; riscv,ndev = <133>; }; + sdio0: mmc@10000000 { + compatible = "snps,dw-mshc"; + reg = <0x0 0x10000000 0x0 0x10000>; + clocks = <&clkgen JH7100_CLK_SDIO0_AHB>, + <&clkgen JH7100_CLK_SDIO0_CCLKINT_INV>; + clock-names = "biu", "ciu"; + interrupts = <4>; + data-addr = <0>; + fifo-depth = <32>; + fifo-watermark-aligned; + status = "disabled"; + }; + + sdio1: mmc@10010000 { + compatible = "snps,dw-mshc"; + reg = <0x0 0x10010000 0x0 0x10000>; + clocks = <&clkgen JH7100_CLK_SDIO1_AHB>, + <&clkgen JH7100_CLK_SDIO1_CCLKINT_INV>; + clock-names = "biu", "ciu"; + interrupts = <5>; + data-addr = <0>; + fifo-depth = <32>; + fifo-watermark-aligned; + status = "disabled"; + }; + clkgen: clock-controller@11800000 { compatible = "starfive,jh7100-clkgen"; reg = <0x0 0x11800000 0x0 0x10000>; diff --git a/arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts b/arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts index 70e8042c83046b..d9b4de9e475742 100644 --- a/arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts +++ b/arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts @@ -48,6 +48,10 @@ clock-frequency = <62500000>; }; +&sdhci_clk { + clock-frequency = <198000000>; +}; + &uart_sclk { clock-frequency = <100000000>; }; @@ -56,6 +60,22 @@ status = "okay"; }; +&emmc { + bus-width = <8>; + max-frequency = <198000000>; + mmc-hs400-1_8v; + non-removable; + no-sdio; + no-sd; + status = "okay"; +}; + +&sdio0 { + bus-width = <4>; + max-frequency = <198000000>; + status = "okay"; +}; + &uart0 { status = "okay"; }; diff --git a/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi b/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi index a802ab1104294b..1365d3a512a3b9 100644 --- a/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi +++ b/arch/riscv/boot/dts/thead/th1520-lichee-module-4a.dtsi @@ -29,6 +29,10 @@ clock-frequency = <62500000>; }; +&sdhci_clk { + clock-frequency = <198000000>; +}; + &uart_sclk { clock-frequency = <100000000>; }; @@ -36,3 +40,19 @@ &dmac0 { status = "okay"; }; + +&emmc { + bus-width = <8>; + max-frequency = <198000000>; + mmc-hs400-1_8v; + non-removable; + no-sdio; + no-sd; + status = "okay"; +}; + +&sdio0 { + bus-width = <4>; + max-frequency = <198000000>; + status = "okay"; +}; diff --git a/arch/riscv/boot/dts/thead/th1520.dtsi b/arch/riscv/boot/dts/thead/th1520.dtsi index ba4d2c673ac8d3..8b915e206f3a01 100644 --- a/arch/riscv/boot/dts/thead/th1520.dtsi +++ b/arch/riscv/boot/dts/thead/th1520.dtsi @@ -146,6 +146,13 @@ #clock-cells = <0>; }; + sdhci_clk: sdhci-clock { + compatible = "fixed-clock"; + clock-frequency = <198000000>; + clock-output-names = "sdhci_clk"; + #clock-cells = <0>; + }; + soc { compatible = "simple-bus"; interrupt-parent = <&plic>; @@ -304,6 +311,33 @@ status = "disabled"; }; + emmc: mmc@ffe7080000 { + compatible = "thead,th1520-dwcmshc"; + reg = <0xff 0xe7080000 0x0 0x10000>; + interrupts = <62 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&sdhci_clk>; + clock-names = "core"; + status = "disabled"; + }; + + sdio0: mmc@ffe7090000 { + compatible = "thead,th1520-dwcmshc"; + reg = <0xff 0xe7090000 0x0 0x10000>; + interrupts = <64 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&sdhci_clk>; + clock-names = "core"; + status = "disabled"; + }; + + sdio1: mmc@ffe70a0000 { + compatible = "thead,th1520-dwcmshc"; + reg = <0xff 0xe70a0000 0x0 0x10000>; + interrupts = <71 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&sdhci_clk>; + clock-names = "core"; + status = "disabled"; + }; + timer0: timer@ffefc32000 { compatible = "snps,dw-apb-timer"; reg = <0xff 0xefc32000 0x0 0x14>; diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig index 905881282a7cd1..eaf34e871e308f 100644 --- a/arch/riscv/configs/defconfig +++ b/arch/riscv/configs/defconfig @@ -149,6 +149,7 @@ CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_8250_DW=y CONFIG_SERIAL_OF_PLATFORM=y CONFIG_SERIAL_SH_SCI=y +CONFIG_SERIAL_EARLYCON_RISCV_SBI=y CONFIG_VIRTIO_CONSOLE=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_VIRTIO=y diff --git a/arch/riscv/configs/rv32_defconfig b/arch/riscv/configs/rv32_defconfig deleted file mode 100644 index 89b601e253a68d..00000000000000 --- a/arch/riscv/configs/rv32_defconfig +++ /dev/null @@ -1,139 +0,0 @@ -CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -CONFIG_NO_HZ_IDLE=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_BPF_SYSCALL=y -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -CONFIG_CGROUPS=y -CONFIG_CGROUP_SCHED=y -CONFIG_CFS_BANDWIDTH=y -CONFIG_CGROUP_BPF=y -CONFIG_NAMESPACES=y -CONFIG_USER_NS=y -CONFIG_CHECKPOINT_RESTORE=y -CONFIG_BLK_DEV_INITRD=y -CONFIG_EXPERT=y -# CONFIG_SYSFS_SYSCALL is not set -CONFIG_PROFILING=y -CONFIG_SOC_SIFIVE=y -CONFIG_SOC_VIRT=y -CONFIG_NONPORTABLE=y -CONFIG_ARCH_RV32I=y -CONFIG_SMP=y -CONFIG_HOTPLUG_CPU=y -CONFIG_PM=y -CONFIG_CPU_IDLE=y -CONFIG_VIRTUALIZATION=y -CONFIG_KVM=m -CONFIG_JUMP_LABEL=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_ADVANCED_ROUTER=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -CONFIG_IP_PNP_RARP=y -CONFIG_NETLINK_DIAG=y -CONFIG_NET_9P=y -CONFIG_NET_9P_VIRTIO=y -CONFIG_PCI=y -CONFIG_PCIEPORTBUS=y -CONFIG_PCI_HOST_GENERIC=y -CONFIG_PCIE_XILINX=y -CONFIG_DEVTMPFS=y -CONFIG_DEVTMPFS_MOUNT=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_VIRTIO_BLK=y -CONFIG_BLK_DEV_SD=y -CONFIG_BLK_DEV_SR=y -CONFIG_SCSI_VIRTIO=y -CONFIG_ATA=y -CONFIG_SATA_AHCI=y -CONFIG_SATA_AHCI_PLATFORM=y -CONFIG_NETDEVICES=y -CONFIG_VIRTIO_NET=y -CONFIG_MACB=y -CONFIG_E1000E=y -CONFIG_R8169=y -CONFIG_MICROSEMI_PHY=y -CONFIG_INPUT_MOUSEDEV=y -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_OF_PLATFORM=y -CONFIG_VIRTIO_CONSOLE=y -CONFIG_HW_RANDOM=y -CONFIG_HW_RANDOM_VIRTIO=y -CONFIG_SPI=y -CONFIG_SPI_SIFIVE=y -# CONFIG_PTP_1588_CLOCK is not set -CONFIG_DRM=y -CONFIG_DRM_RADEON=y -CONFIG_DRM_VIRTIO_GPU=y -CONFIG_FB=y -CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_USB=y -CONFIG_USB_XHCI_HCD=y -CONFIG_USB_XHCI_PLATFORM=y -CONFIG_USB_EHCI_HCD=y -CONFIG_USB_EHCI_HCD_PLATFORM=y -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_OHCI_HCD_PLATFORM=y -CONFIG_USB_STORAGE=y -CONFIG_USB_UAS=y -CONFIG_MMC=y -CONFIG_MMC_SPI=y -CONFIG_RTC_CLASS=y -CONFIG_VIRTIO_PCI=y -CONFIG_VIRTIO_BALLOON=y -CONFIG_VIRTIO_INPUT=y -CONFIG_VIRTIO_MMIO=y -CONFIG_RPMSG_CHAR=y -CONFIG_RPMSG_CTRL=y -CONFIG_RPMSG_VIRTIO=y -CONFIG_EXT4_FS=y -CONFIG_EXT4_FS_POSIX_ACL=y -CONFIG_AUTOFS_FS=y -CONFIG_MSDOS_FS=y -CONFIG_VFAT_FS=y -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y -CONFIG_HUGETLBFS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V4=y -CONFIG_NFS_V4_1=y -CONFIG_NFS_V4_2=y -CONFIG_ROOT_NFS=y -CONFIG_9P_FS=y -CONFIG_CRYPTO_USER_API_HASH=y -CONFIG_CRYPTO_DEV_VIRTIO=y -CONFIG_PRINTK_TIME=y -CONFIG_DEBUG_FS=y -CONFIG_DEBUG_PAGEALLOC=y -CONFIG_SCHED_STACK_END_CHECK=y -CONFIG_DEBUG_VM=y -CONFIG_DEBUG_VM_PGFLAGS=y -CONFIG_DEBUG_MEMORY_INIT=y -CONFIG_DEBUG_PER_CPU_MAPS=y -CONFIG_SOFTLOCKUP_DETECTOR=y -CONFIG_WQ_WATCHDOG=y -CONFIG_DEBUG_TIMEKEEPING=y -CONFIG_DEBUG_RT_MUTEXES=y -CONFIG_DEBUG_SPINLOCK=y -CONFIG_DEBUG_MUTEXES=y -CONFIG_DEBUG_RWSEMS=y -CONFIG_DEBUG_ATOMIC_SLEEP=y -CONFIG_STACKTRACE=y -CONFIG_DEBUG_LIST=y -CONFIG_DEBUG_PLIST=y -CONFIG_DEBUG_SG=y -# CONFIG_RCU_TRACE is not set -CONFIG_RCU_EQS_DEBUG=y -# CONFIG_FTRACE is not set -# CONFIG_RUNTIME_TESTING_MENU is not set -CONFIG_MEMTEST=y diff --git a/arch/riscv/errata/thead/errata.c b/arch/riscv/errata/thead/errata.c index 0554ed4bf087cf..b1c410bbc1aece 100644 --- a/arch/riscv/errata/thead/errata.c +++ b/arch/riscv/errata/thead/errata.c @@ -12,8 +12,10 @@ #include #include #include +#include #include #include +#include #include #include @@ -33,6 +35,69 @@ static bool errata_probe_pbmt(unsigned int stage, return false; } +/* + * th.dcache.ipa rs1 (invalidate, physical address) + * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | + * 0000001 01010 rs1 000 00000 0001011 + * th.dcache.iva rs1 (invalidate, virtual address) + * 0000001 00110 rs1 000 00000 0001011 + * + * th.dcache.cpa rs1 (clean, physical address) + * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | + * 0000001 01001 rs1 000 00000 0001011 + * th.dcache.cva rs1 (clean, virtual address) + * 0000001 00101 rs1 000 00000 0001011 + * + * th.dcache.cipa rs1 (clean then invalidate, physical address) + * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | + * 0000001 01011 rs1 000 00000 0001011 + * th.dcache.civa rs1 (clean then invalidate, virtual address) + * 0000001 00111 rs1 000 00000 0001011 + * + * th.sync.s (make sure all cache operations finished) + * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | + * 0000000 11001 00000 000 00000 0001011 + */ +#define THEAD_INVAL_A0 ".long 0x02a5000b" +#define THEAD_CLEAN_A0 ".long 0x0295000b" +#define THEAD_FLUSH_A0 ".long 0x02b5000b" +#define THEAD_SYNC_S ".long 0x0190000b" + +#define THEAD_CMO_OP(_op, _start, _size, _cachesize) \ +asm volatile("mv a0, %1\n\t" \ + "j 2f\n\t" \ + "3:\n\t" \ + THEAD_##_op##_A0 "\n\t" \ + "add a0, a0, %0\n\t" \ + "2:\n\t" \ + "bltu a0, %2, 3b\n\t" \ + THEAD_SYNC_S \ + : : "r"(_cachesize), \ + "r"((unsigned long)(_start) & ~((_cachesize) - 1UL)), \ + "r"((unsigned long)(_start) + (_size)) \ + : "a0") + +static void thead_errata_cache_inv(phys_addr_t paddr, size_t size) +{ + THEAD_CMO_OP(INVAL, paddr, size, riscv_cbom_block_size); +} + +static void thead_errata_cache_wback(phys_addr_t paddr, size_t size) +{ + THEAD_CMO_OP(CLEAN, paddr, size, riscv_cbom_block_size); +} + +static void thead_errata_cache_wback_inv(phys_addr_t paddr, size_t size) +{ + THEAD_CMO_OP(FLUSH, paddr, size, riscv_cbom_block_size); +} + +static const struct riscv_nonstd_cache_ops thead_errata_cmo_ops = { + .wback = &thead_errata_cache_wback, + .inv = &thead_errata_cache_inv, + .wback_inv = &thead_errata_cache_wback_inv, +}; + static bool errata_probe_cmo(unsigned int stage, unsigned long arch_id, unsigned long impid) { @@ -48,6 +113,7 @@ static bool errata_probe_cmo(unsigned int stage, if (stage == RISCV_ALTERNATIVES_BOOT) { riscv_cbom_block_size = L1_CACHE_BYTES; riscv_noncoherent_supported(); + riscv_noncoherent_register_cache_ops(&thead_errata_cmo_ops); } return true; @@ -77,8 +143,7 @@ static u32 thead_errata_probe(unsigned int stage, if (errata_probe_pbmt(stage, archid, impid)) cpu_req_errata |= BIT(ERRATA_THEAD_PBMT); - if (errata_probe_cmo(stage, archid, impid)) - cpu_req_errata |= BIT(ERRATA_THEAD_CMO); + errata_probe_cmo(stage, archid, impid); if (errata_probe_pmu(stage, archid, impid)) cpu_req_errata |= BIT(ERRATA_THEAD_PMU); diff --git a/arch/riscv/include/asm/arch_hweight.h b/arch/riscv/include/asm/arch_hweight.h new file mode 100644 index 00000000000000..c20236a0725b9e --- /dev/null +++ b/arch/riscv/include/asm/arch_hweight.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Based on arch/x86/include/asm/arch_hweight.h + */ + +#ifndef _ASM_RISCV_HWEIGHT_H +#define _ASM_RISCV_HWEIGHT_H + +#include +#include + +#if (BITS_PER_LONG == 64) +#define CPOPW "cpopw " +#elif (BITS_PER_LONG == 32) +#define CPOPW "cpop " +#else +#error "Unexpected BITS_PER_LONG" +#endif + +static __always_inline unsigned int __arch_hweight32(unsigned int w) +{ +#ifdef CONFIG_RISCV_ISA_ZBB + asm_volatile_goto(ALTERNATIVE("j %l[legacy]", "nop", 0, + RISCV_ISA_EXT_ZBB, 1) + : : : : legacy); + + asm (".option push\n" + ".option arch,+zbb\n" + CPOPW "%0, %0\n" + ".option pop\n" + : "+r" (w) : :); + + return w; + +legacy: +#endif + return __sw_hweight32(w); +} + +static inline unsigned int __arch_hweight16(unsigned int w) +{ + return __arch_hweight32(w & 0xffff); +} + +static inline unsigned int __arch_hweight8(unsigned int w) +{ + return __arch_hweight32(w & 0xff); +} + +#if BITS_PER_LONG == 64 +static __always_inline unsigned long __arch_hweight64(__u64 w) +{ +# ifdef CONFIG_RISCV_ISA_ZBB + asm_volatile_goto(ALTERNATIVE("j %l[legacy]", "nop", 0, + RISCV_ISA_EXT_ZBB, 1) + : : : : legacy); + + asm (".option push\n" + ".option arch,+zbb\n" + "cpop %0, %0\n" + ".option pop\n" + : "+r" (w) : :); + + return w; + +legacy: +# endif + return __sw_hweight64(w); +} +#else /* BITS_PER_LONG == 64 */ +static inline unsigned long __arch_hweight64(__u64 w) +{ + return __arch_hweight32((u32)w) + + __arch_hweight32((u32)(w >> 32)); +} +#endif /* !(BITS_PER_LONG == 64) */ + +#endif /* _ASM_RISCV_HWEIGHT_H */ diff --git a/arch/riscv/include/asm/archrandom.h b/arch/riscv/include/asm/archrandom.h new file mode 100644 index 00000000000000..5345360adfb9cf --- /dev/null +++ b/arch/riscv/include/asm/archrandom.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Kernel interface for the RISCV arch_random_* functions + * + * Copyright (c) 2023 Rivos Inc. + * + */ + +#ifndef ASM_RISCV_ARCHRANDOM_H +#define ASM_RISCV_ARCHRANDOM_H + +#include +#include + +#define SEED_RETRY_LOOPS 100 + +static inline bool __must_check csr_seed_long(unsigned long *v) +{ + unsigned int retry = SEED_RETRY_LOOPS, valid_seeds = 0; + const int needed_seeds = sizeof(long) / sizeof(u16); + u16 *entropy = (u16 *)v; + + do { + /* + * The SEED CSR must be accessed with a read-write instruction. + */ + unsigned long csr_seed = csr_swap(CSR_SEED, 0); + unsigned long opst = csr_seed & SEED_OPST_MASK; + + switch (opst) { + case SEED_OPST_ES16: + entropy[valid_seeds++] = csr_seed & SEED_ENTROPY_MASK; + if (valid_seeds == needed_seeds) + return true; + break; + + case SEED_OPST_DEAD: + pr_err_once("archrandom: Unrecoverable error\n"); + return false; + + case SEED_OPST_BIST: + case SEED_OPST_WAIT: + default: + cpu_relax(); + continue; + } + } while (--retry); + + return false; +} + +static inline size_t __must_check arch_get_random_longs(unsigned long *v, size_t max_longs) +{ + return 0; +} + +static inline size_t __must_check arch_get_random_seed_longs(unsigned long *v, size_t max_longs) +{ + if (!max_longs) + return 0; + + /* + * If Zkr is supported and csr_seed_long succeeds, we return one long + * worth of entropy. + */ + if (riscv_has_extension_likely(RISCV_ISA_EXT_ZKR) && csr_seed_long(v)) + return 1; + + return 0; +} + +#endif /* ASM_RISCV_ARCHRANDOM_H */ diff --git a/arch/riscv/include/asm/asm-extable.h b/arch/riscv/include/asm/asm-extable.h index 00a96e7a966445..0c8bfd54fc4e05 100644 --- a/arch/riscv/include/asm/asm-extable.h +++ b/arch/riscv/include/asm/asm-extable.h @@ -6,6 +6,7 @@ #define EX_TYPE_FIXUP 1 #define EX_TYPE_BPF 2 #define EX_TYPE_UACCESS_ERR_ZERO 3 +#define EX_TYPE_LOAD_UNALIGNED_ZEROPAD 4 #ifdef CONFIG_MMU @@ -47,6 +48,11 @@ #define EX_DATA_REG_ZERO_SHIFT 5 #define EX_DATA_REG_ZERO GENMASK(9, 5) +#define EX_DATA_REG_DATA_SHIFT 0 +#define EX_DATA_REG_DATA GENMASK(4, 0) +#define EX_DATA_REG_ADDR_SHIFT 5 +#define EX_DATA_REG_ADDR GENMASK(9, 5) + #define EX_DATA_REG(reg, gpr) \ "((.L__gpr_num_" #gpr ") << " __stringify(EX_DATA_REG_##reg##_SHIFT) ")" @@ -62,6 +68,15 @@ #define _ASM_EXTABLE_UACCESS_ERR(insn, fixup, err) \ _ASM_EXTABLE_UACCESS_ERR_ZERO(insn, fixup, err, zero) +#define _ASM_EXTABLE_LOAD_UNALIGNED_ZEROPAD(insn, fixup, data, addr) \ + __DEFINE_ASM_GPR_NUMS \ + __ASM_EXTABLE_RAW(#insn, #fixup, \ + __stringify(EX_TYPE_LOAD_UNALIGNED_ZEROPAD), \ + "(" \ + EX_DATA_REG(DATA, data) " | " \ + EX_DATA_REG(ADDR, addr) \ + ")") + #endif /* __ASSEMBLY__ */ #else /* CONFIG_MMU */ diff --git a/arch/riscv/include/asm/asm-prototypes.h b/arch/riscv/include/asm/asm-prototypes.h index 36b955c762ba08..cd627ec289f163 100644 --- a/arch/riscv/include/asm/asm-prototypes.h +++ b/arch/riscv/include/asm/asm-prototypes.h @@ -9,6 +9,33 @@ long long __lshrti3(long long a, int b); long long __ashrti3(long long a, int b); long long __ashlti3(long long a, int b); +#ifdef CONFIG_RISCV_ISA_V + +#ifdef CONFIG_MMU +asmlinkage int enter_vector_usercopy(void *dst, void *src, size_t n); +#endif /* CONFIG_MMU */ + +void xor_regs_2_(unsigned long bytes, unsigned long *__restrict p1, + const unsigned long *__restrict p2); +void xor_regs_3_(unsigned long bytes, unsigned long *__restrict p1, + const unsigned long *__restrict p2, + const unsigned long *__restrict p3); +void xor_regs_4_(unsigned long bytes, unsigned long *__restrict p1, + const unsigned long *__restrict p2, + const unsigned long *__restrict p3, + const unsigned long *__restrict p4); +void xor_regs_5_(unsigned long bytes, unsigned long *__restrict p1, + const unsigned long *__restrict p2, + const unsigned long *__restrict p3, + const unsigned long *__restrict p4, + const unsigned long *__restrict p5); + +#ifdef CONFIG_RISCV_ISA_V_PREEMPTIVE +asmlinkage void riscv_v_context_nesting_start(struct pt_regs *regs); +asmlinkage void riscv_v_context_nesting_end(struct pt_regs *regs); +#endif /* CONFIG_RISCV_ISA_V_PREEMPTIVE */ + +#endif /* CONFIG_RISCV_ISA_V */ #define DECLARE_DO_ERROR_INFO(name) asmlinkage void name(struct pt_regs *regs) diff --git a/arch/riscv/include/asm/bitops.h b/arch/riscv/include/asm/bitops.h index 224b4dc02b50bc..9ffc355370248a 100644 --- a/arch/riscv/include/asm/bitops.h +++ b/arch/riscv/include/asm/bitops.h @@ -271,7 +271,9 @@ legacy: #include #include -#include +#include + +#include #if (BITS_PER_LONG == 64) #define __AMO(op) "amo" #op ".d" diff --git a/arch/riscv/include/asm/cacheflush.h b/arch/riscv/include/asm/cacheflush.h index 3cb53c4df27cfe..a129dac4521d35 100644 --- a/arch/riscv/include/asm/cacheflush.h +++ b/arch/riscv/include/asm/cacheflush.h @@ -37,7 +37,8 @@ static inline void flush_dcache_page(struct page *page) flush_icache_mm(vma->vm_mm, 0) #ifdef CONFIG_64BIT -#define flush_cache_vmap(start, end) flush_tlb_kernel_range(start, end) +#define flush_cache_vmap(start, end) flush_tlb_kernel_range(start, end) +#define flush_cache_vmap_early(start, end) local_flush_tlb_kernel_range(start, end) #endif #ifndef CONFIG_SMP diff --git a/arch/riscv/include/asm/cfi.h b/arch/riscv/include/asm/cfi.h index 56bf9d69d5e38c..8f7a6225704499 100644 --- a/arch/riscv/include/asm/cfi.h +++ b/arch/riscv/include/asm/cfi.h @@ -7,8 +7,9 @@ * * Copyright (C) 2023 Google LLC */ +#include -#include +struct pt_regs; #ifdef CONFIG_CFI_CLANG enum bug_trap_type handle_cfi_failure(struct pt_regs *regs); diff --git a/arch/riscv/include/asm/checksum.h b/arch/riscv/include/asm/checksum.h new file mode 100644 index 00000000000000..a5b60b54b101c3 --- /dev/null +++ b/arch/riscv/include/asm/checksum.h @@ -0,0 +1,93 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Checksum routines + * + * Copyright (C) 2023 Rivos Inc. + */ +#ifndef __ASM_RISCV_CHECKSUM_H +#define __ASM_RISCV_CHECKSUM_H + +#include +#include + +#define ip_fast_csum ip_fast_csum + +extern unsigned int do_csum(const unsigned char *buff, int len); +#define do_csum do_csum + +/* Default version is sufficient for 32 bit */ +#ifndef CONFIG_32BIT +#define _HAVE_ARCH_IPV6_CSUM +__sum16 csum_ipv6_magic(const struct in6_addr *saddr, + const struct in6_addr *daddr, + __u32 len, __u8 proto, __wsum sum); +#endif + +/* Define riscv versions of functions before importing asm-generic/checksum.h */ +#include + +/** + * Quickly compute an IP checksum with the assumption that IPv4 headers will + * always be in multiples of 32-bits, and have an ihl of at least 5. + * + * @ihl: the number of 32 bit segments and must be greater than or equal to 5. + * @iph: assumed to be word aligned given that NET_IP_ALIGN is set to 2 on + * riscv, defining IP headers to be aligned. + */ +static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl) +{ + unsigned long csum = 0; + int pos = 0; + + do { + csum += ((const unsigned int *)iph)[pos]; + if (IS_ENABLED(CONFIG_32BIT)) + csum += csum < ((const unsigned int *)iph)[pos]; + } while (++pos < ihl); + + /* + * ZBB only saves three instructions on 32-bit and five on 64-bit so not + * worth checking if supported without Alternatives. + */ + if (IS_ENABLED(CONFIG_RISCV_ISA_ZBB) && + IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) { + unsigned long fold_temp; + + asm_volatile_goto(ALTERNATIVE("j %l[no_zbb]", "nop", 0, + RISCV_ISA_EXT_ZBB, 1) + : + : + : + : no_zbb); + + if (IS_ENABLED(CONFIG_32BIT)) { + asm(".option push \n\ + .option arch,+zbb \n\ + not %[fold_temp], %[csum] \n\ + rori %[csum], %[csum], 16 \n\ + sub %[csum], %[fold_temp], %[csum] \n\ + .option pop" + : [csum] "+r" (csum), [fold_temp] "=&r" (fold_temp)); + } else { + asm(".option push \n\ + .option arch,+zbb \n\ + rori %[fold_temp], %[csum], 32 \n\ + add %[csum], %[fold_temp], %[csum] \n\ + srli %[csum], %[csum], 32 \n\ + not %[fold_temp], %[csum] \n\ + roriw %[csum], %[csum], 16 \n\ + subw %[csum], %[fold_temp], %[csum] \n\ + .option pop" + : [csum] "+r" (csum), [fold_temp] "=&r" (fold_temp)); + } + return (__force __sum16)(csum >> 16); + } +no_zbb: +#ifndef CONFIG_32BIT + csum += ror64(csum, 32); + csum >>= 32; +#endif + return csum_fold((__force __wsum)csum); +} + +#endif /* __ASM_RISCV_CHECKSUM_H */ diff --git a/arch/riscv/include/asm/cpu_ops.h b/arch/riscv/include/asm/cpu_ops.h index aa128466c4d4ec..176b570ef98276 100644 --- a/arch/riscv/include/asm/cpu_ops.h +++ b/arch/riscv/include/asm/cpu_ops.h @@ -13,33 +13,23 @@ /** * struct cpu_operations - Callback operations for hotplugging CPUs. * - * @name: Name of the boot protocol. - * @cpu_prepare: Early one-time preparation step for a cpu. If there - * is a mechanism for doing so, tests whether it is - * possible to boot the given HART. * @cpu_start: Boots a cpu into the kernel. - * @cpu_disable: Prepares a cpu to die. May fail for some - * mechanism-specific reason, which will cause the hot - * unplug to be aborted. Called from the cpu to be killed. * @cpu_stop: Makes a cpu leave the kernel. Must not fail. Called from * the cpu being stopped. * @cpu_is_stopped: Ensures a cpu has left the kernel. Called from another * cpu. */ struct cpu_operations { - const char *name; - int (*cpu_prepare)(unsigned int cpu); int (*cpu_start)(unsigned int cpu, struct task_struct *tidle); #ifdef CONFIG_HOTPLUG_CPU - int (*cpu_disable)(unsigned int cpu); void (*cpu_stop)(void); int (*cpu_is_stopped)(unsigned int cpu); #endif }; extern const struct cpu_operations cpu_ops_spinwait; -extern const struct cpu_operations *cpu_ops[NR_CPUS]; -void __init cpu_set_ops(int cpu); +extern const struct cpu_operations *cpu_ops; +void __init cpu_set_ops(void); #endif /* ifndef __ASM_CPU_OPS_H */ diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h index a418c3112cd60c..5a626ed2c47a89 100644 --- a/arch/riscv/include/asm/cpufeature.h +++ b/arch/riscv/include/asm/cpufeature.h @@ -59,6 +59,8 @@ struct riscv_isa_ext_data { const unsigned int id; const char *name; const char *property; + const unsigned int *subset_ext_ids; + const unsigned int subset_ext_size; }; extern const struct riscv_isa_ext_data riscv_isa_ext[]; @@ -67,7 +69,7 @@ extern bool riscv_isa_fallback; unsigned long riscv_isa_extension_base(const unsigned long *isa_bitmap); -bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, int bit); +bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, unsigned int bit); #define riscv_isa_extension_available(isa_bitmap, ext) \ __riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_##ext) @@ -133,4 +135,6 @@ static __always_inline bool riscv_cpu_has_extension_unlikely(int cpu, const unsi return __riscv_isa_extension_available(hart_isa[cpu].isa, ext); } +DECLARE_STATIC_KEY_FALSE(fast_misaligned_access_speed_key); + #endif diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h index 306a19a5509c10..510014051f5dbb 100644 --- a/arch/riscv/include/asm/csr.h +++ b/arch/riscv/include/asm/csr.h @@ -411,6 +411,15 @@ #define CSR_VTYPE 0xc21 #define CSR_VLENB 0xc22 +/* Scalar Crypto Extension - Entropy */ +#define CSR_SEED 0x015 +#define SEED_OPST_MASK _AC(0xC0000000, UL) +#define SEED_OPST_BIST _AC(0x00000000, UL) +#define SEED_OPST_WAIT _AC(0x40000000, UL) +#define SEED_OPST_ES16 _AC(0x80000000, UL) +#define SEED_OPST_DEAD _AC(0xC0000000, UL) +#define SEED_ENTROPY_MASK _AC(0xFFFF, UL) + #ifdef CONFIG_RISCV_M_MODE # define CSR_STATUS CSR_MSTATUS # define CSR_IE CSR_MIE diff --git a/arch/riscv/include/asm/entry-common.h b/arch/riscv/include/asm/entry-common.h index 7ab5e34318c85f..2293e535f8659a 100644 --- a/arch/riscv/include/asm/entry-common.h +++ b/arch/riscv/include/asm/entry-common.h @@ -4,6 +4,23 @@ #define _ASM_RISCV_ENTRY_COMMON_H #include +#include +#include + +static inline void arch_exit_to_user_mode_prepare(struct pt_regs *regs, + unsigned long ti_work) +{ + if (ti_work & _TIF_RISCV_V_DEFER_RESTORE) { + clear_thread_flag(TIF_RISCV_V_DEFER_RESTORE); + /* + * We are already called with irq disabled, so go without + * keeping track of riscv_v_flags. + */ + riscv_v_vstate_restore(¤t->thread.vstate, regs); + } +} + +#define arch_exit_to_user_mode_prepare arch_exit_to_user_mode_prepare void handle_page_fault(struct pt_regs *regs); void handle_break(struct pt_regs *regs); diff --git a/arch/riscv/include/asm/errata_list.h b/arch/riscv/include/asm/errata_list.h index 83ed25e4355343..ea33288f8a25b4 100644 --- a/arch/riscv/include/asm/errata_list.h +++ b/arch/riscv/include/asm/errata_list.h @@ -24,9 +24,8 @@ #ifdef CONFIG_ERRATA_THEAD #define ERRATA_THEAD_PBMT 0 -#define ERRATA_THEAD_CMO 1 -#define ERRATA_THEAD_PMU 2 -#define ERRATA_THEAD_NUMBER 3 +#define ERRATA_THEAD_PMU 1 +#define ERRATA_THEAD_NUMBER 2 #endif #ifdef __ASSEMBLY__ @@ -94,54 +93,17 @@ asm volatile(ALTERNATIVE( \ #define ALT_THEAD_PMA(_val) #endif -/* - * th.dcache.ipa rs1 (invalidate, physical address) - * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | - * 0000001 01010 rs1 000 00000 0001011 - * th.dache.iva rs1 (invalida, virtual address) - * 0000001 00110 rs1 000 00000 0001011 - * - * th.dcache.cpa rs1 (clean, physical address) - * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | - * 0000001 01001 rs1 000 00000 0001011 - * th.dcache.cva rs1 (clean, virtual address) - * 0000001 00101 rs1 000 00000 0001011 - * - * th.dcache.cipa rs1 (clean then invalidate, physical address) - * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | - * 0000001 01011 rs1 000 00000 0001011 - * th.dcache.civa rs1 (... virtual address) - * 0000001 00111 rs1 000 00000 0001011 - * - * th.sync.s (make sure all cache operations finished) - * | 31 - 25 | 24 - 20 | 19 - 15 | 14 - 12 | 11 - 7 | 6 - 0 | - * 0000000 11001 00000 000 00000 0001011 - */ -#define THEAD_INVAL_A0 ".long 0x0265000b" -#define THEAD_CLEAN_A0 ".long 0x0255000b" -#define THEAD_FLUSH_A0 ".long 0x0275000b" -#define THEAD_SYNC_S ".long 0x0190000b" - #define ALT_CMO_OP(_op, _start, _size, _cachesize) \ -asm volatile(ALTERNATIVE_2( \ - __nops(6), \ +asm volatile(ALTERNATIVE( \ + __nops(5), \ "mv a0, %1\n\t" \ "j 2f\n\t" \ "3:\n\t" \ CBO_##_op(a0) \ "add a0, a0, %0\n\t" \ "2:\n\t" \ - "bltu a0, %2, 3b\n\t" \ - "nop", 0, RISCV_ISA_EXT_ZICBOM, CONFIG_RISCV_ISA_ZICBOM, \ - "mv a0, %1\n\t" \ - "j 2f\n\t" \ - "3:\n\t" \ - THEAD_##_op##_A0 "\n\t" \ - "add a0, a0, %0\n\t" \ - "2:\n\t" \ - "bltu a0, %2, 3b\n\t" \ - THEAD_SYNC_S, THEAD_VENDOR_ID, \ - ERRATA_THEAD_CMO, CONFIG_ERRATA_THEAD_CMO) \ + "bltu a0, %2, 3b\n\t", \ + 0, RISCV_ISA_EXT_ZICBOM, CONFIG_RISCV_ISA_ZICBOM) \ : : "r"(_cachesize), \ "r"((unsigned long)(_start) & ~((_cachesize) - 1UL)), \ "r"((unsigned long)(_start) + (_size)) \ diff --git a/arch/riscv/include/asm/ftrace.h b/arch/riscv/include/asm/ftrace.h index 2b2f5df7ef2c7d..32917212295234 100644 --- a/arch/riscv/include/asm/ftrace.h +++ b/arch/riscv/include/asm/ftrace.h @@ -128,7 +128,23 @@ do { \ struct dyn_ftrace; int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec); #define ftrace_init_nop ftrace_init_nop -#endif + +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS +struct ftrace_ops; +struct ftrace_regs; +void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, + struct ftrace_ops *op, struct ftrace_regs *fregs); +#define ftrace_graph_func ftrace_graph_func + +static inline void __arch_ftrace_set_direct_caller(struct pt_regs *regs, unsigned long addr) +{ + regs->t1 = addr; +} +#define arch_ftrace_set_direct_caller(fregs, addr) \ + __arch_ftrace_set_direct_caller(&(fregs)->regs, addr) +#endif /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */ + +#endif /* __ASSEMBLY__ */ #endif /* CONFIG_DYNAMIC_FTRACE */ diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h index 06d30526ef3b83..5340f818746b71 100644 --- a/arch/riscv/include/asm/hwcap.h +++ b/arch/riscv/include/asm/hwcap.h @@ -11,19 +11,13 @@ #include #define RISCV_ISA_EXT_a ('a' - 'a') -#define RISCV_ISA_EXT_b ('b' - 'a') #define RISCV_ISA_EXT_c ('c' - 'a') #define RISCV_ISA_EXT_d ('d' - 'a') #define RISCV_ISA_EXT_f ('f' - 'a') #define RISCV_ISA_EXT_h ('h' - 'a') #define RISCV_ISA_EXT_i ('i' - 'a') -#define RISCV_ISA_EXT_j ('j' - 'a') -#define RISCV_ISA_EXT_k ('k' - 'a') #define RISCV_ISA_EXT_m ('m' - 'a') -#define RISCV_ISA_EXT_p ('p' - 'a') #define RISCV_ISA_EXT_q ('q' - 'a') -#define RISCV_ISA_EXT_s ('s' - 'a') -#define RISCV_ISA_EXT_u ('u' - 'a') #define RISCV_ISA_EXT_v ('v' - 'a') /* @@ -57,8 +51,38 @@ #define RISCV_ISA_EXT_ZIHPM 42 #define RISCV_ISA_EXT_SMSTATEEN 43 #define RISCV_ISA_EXT_ZICOND 44 +#define RISCV_ISA_EXT_ZBC 45 +#define RISCV_ISA_EXT_ZBKB 46 +#define RISCV_ISA_EXT_ZBKC 47 +#define RISCV_ISA_EXT_ZBKX 48 +#define RISCV_ISA_EXT_ZKND 49 +#define RISCV_ISA_EXT_ZKNE 50 +#define RISCV_ISA_EXT_ZKNH 51 +#define RISCV_ISA_EXT_ZKR 52 +#define RISCV_ISA_EXT_ZKSED 53 +#define RISCV_ISA_EXT_ZKSH 54 +#define RISCV_ISA_EXT_ZKT 55 +#define RISCV_ISA_EXT_ZVBB 56 +#define RISCV_ISA_EXT_ZVBC 57 +#define RISCV_ISA_EXT_ZVKB 58 +#define RISCV_ISA_EXT_ZVKG 59 +#define RISCV_ISA_EXT_ZVKNED 60 +#define RISCV_ISA_EXT_ZVKNHA 61 +#define RISCV_ISA_EXT_ZVKNHB 62 +#define RISCV_ISA_EXT_ZVKSED 63 +#define RISCV_ISA_EXT_ZVKSH 64 +#define RISCV_ISA_EXT_ZVKT 65 +#define RISCV_ISA_EXT_ZFH 66 +#define RISCV_ISA_EXT_ZFHMIN 67 +#define RISCV_ISA_EXT_ZIHINTNTL 68 +#define RISCV_ISA_EXT_ZVFH 69 +#define RISCV_ISA_EXT_ZVFHMIN 70 +#define RISCV_ISA_EXT_ZFA 71 +#define RISCV_ISA_EXT_ZTSO 72 +#define RISCV_ISA_EXT_ZACAS 73 -#define RISCV_ISA_EXT_MAX 64 +#define RISCV_ISA_EXT_MAX 128 +#define RISCV_ISA_EXT_INVALID U32_MAX #ifdef CONFIG_RISCV_M_MODE #define RISCV_ISA_EXT_SxAIA RISCV_ISA_EXT_SMAIA diff --git a/arch/riscv/include/asm/hwprobe.h b/arch/riscv/include/asm/hwprobe.h index 5c48f48e79a678..630507dff5ead3 100644 --- a/arch/riscv/include/asm/hwprobe.h +++ b/arch/riscv/include/asm/hwprobe.h @@ -15,4 +15,28 @@ static inline bool riscv_hwprobe_key_is_valid(__s64 key) return key >= 0 && key <= RISCV_HWPROBE_MAX_KEY; } +static inline bool hwprobe_key_is_bitmask(__s64 key) +{ + switch (key) { + case RISCV_HWPROBE_KEY_BASE_BEHAVIOR: + case RISCV_HWPROBE_KEY_IMA_EXT_0: + case RISCV_HWPROBE_KEY_CPUPERF_0: + return true; + } + + return false; +} + +static inline bool riscv_hwprobe_pair_cmp(struct riscv_hwprobe *pair, + struct riscv_hwprobe *other_pair) +{ + if (pair->key != other_pair->key) + return false; + + if (hwprobe_key_is_bitmask(pair->key)) + return (pair->value & other_pair->value) == other_pair->value; + + return pair->value == other_pair->value; +} + #endif diff --git a/arch/riscv/include/asm/irq_work.h b/arch/riscv/include/asm/irq_work.h index b53891964ae037..b27a4d64fc6a04 100644 --- a/arch/riscv/include/asm/irq_work.h +++ b/arch/riscv/include/asm/irq_work.h @@ -6,5 +6,5 @@ static inline bool arch_irq_work_has_interrupt(void) { return IS_ENABLED(CONFIG_SMP); } -extern void arch_irq_work_raise(void); + #endif /* _ASM_RISCV_IRQ_WORK_H */ diff --git a/arch/riscv/include/asm/kfence.h b/arch/riscv/include/asm/kfence.h index 0bbffd528096d9..7388edd88986f9 100644 --- a/arch/riscv/include/asm/kfence.h +++ b/arch/riscv/include/asm/kfence.h @@ -18,9 +18,9 @@ static inline bool kfence_protect_page(unsigned long addr, bool protect) pte_t *pte = virt_to_kpte(addr); if (protect) - set_pte(pte, __pte(pte_val(*pte) & ~_PAGE_PRESENT)); + set_pte(pte, __pte(pte_val(ptep_get(pte)) & ~_PAGE_PRESENT)); else - set_pte(pte, __pte(pte_val(*pte) | _PAGE_PRESENT)); + set_pte(pte, __pte(pte_val(ptep_get(pte)) | _PAGE_PRESENT)); flush_tlb_kernel_range(addr, addr + PAGE_SIZE); diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h index 0eefd9c991ae24..484d04a92fa6b7 100644 --- a/arch/riscv/include/asm/kvm_host.h +++ b/arch/riscv/include/asm/kvm_host.h @@ -41,6 +41,7 @@ KVM_ARCH_REQ_FLAGS(4, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP) #define KVM_REQ_HFENCE \ KVM_ARCH_REQ_FLAGS(5, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP) +#define KVM_REQ_STEAL_UPDATE KVM_ARCH_REQ(6) enum kvm_riscv_hfence_type { KVM_RISCV_HFENCE_UNKNOWN = 0, @@ -262,13 +263,17 @@ struct kvm_vcpu_arch { /* 'static' configurations which are set only once */ struct kvm_vcpu_config cfg; + + /* SBI steal-time accounting */ + struct { + gpa_t shmem; + u64 last_steal; + } sta; }; static inline void kvm_arch_sync_events(struct kvm *kvm) {} static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {} -#define KVM_ARCH_WANT_MMU_NOTIFIER - #define KVM_RISCV_GSTAGE_TLB_MIN_ORDER 12 void kvm_riscv_local_hfence_gvma_vmid_gpa(unsigned long vmid, @@ -372,4 +377,7 @@ bool kvm_riscv_vcpu_has_interrupts(struct kvm_vcpu *vcpu, u64 mask); void kvm_riscv_vcpu_power_off(struct kvm_vcpu *vcpu); void kvm_riscv_vcpu_power_on(struct kvm_vcpu *vcpu); +void kvm_riscv_vcpu_sbi_sta_reset(struct kvm_vcpu *vcpu); +void kvm_riscv_vcpu_record_steal_time(struct kvm_vcpu *vcpu); + #endif /* __RISCV_KVM_HOST_H__ */ diff --git a/arch/riscv/include/asm/kvm_vcpu_sbi.h b/arch/riscv/include/asm/kvm_vcpu_sbi.h index 6a453f7f8b5626..b96705258cf964 100644 --- a/arch/riscv/include/asm/kvm_vcpu_sbi.h +++ b/arch/riscv/include/asm/kvm_vcpu_sbi.h @@ -15,9 +15,10 @@ #define KVM_SBI_VERSION_MINOR 0 enum kvm_riscv_sbi_ext_status { - KVM_RISCV_SBI_EXT_UNINITIALIZED, - KVM_RISCV_SBI_EXT_AVAILABLE, - KVM_RISCV_SBI_EXT_UNAVAILABLE, + KVM_RISCV_SBI_EXT_STATUS_UNINITIALIZED, + KVM_RISCV_SBI_EXT_STATUS_UNAVAILABLE, + KVM_RISCV_SBI_EXT_STATUS_ENABLED, + KVM_RISCV_SBI_EXT_STATUS_DISABLED, }; struct kvm_vcpu_sbi_context { @@ -36,7 +37,7 @@ struct kvm_vcpu_sbi_extension { unsigned long extid_start; unsigned long extid_end; - bool default_unavail; + bool default_disabled; /** * SBI extension handler. It can be defined for a given extension or group of @@ -59,11 +60,21 @@ int kvm_riscv_vcpu_set_reg_sbi_ext(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg); int kvm_riscv_vcpu_get_reg_sbi_ext(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg); +int kvm_riscv_vcpu_set_reg_sbi(struct kvm_vcpu *vcpu, + const struct kvm_one_reg *reg); +int kvm_riscv_vcpu_get_reg_sbi(struct kvm_vcpu *vcpu, + const struct kvm_one_reg *reg); const struct kvm_vcpu_sbi_extension *kvm_vcpu_sbi_find_ext( struct kvm_vcpu *vcpu, unsigned long extid); +bool riscv_vcpu_supports_sbi_ext(struct kvm_vcpu *vcpu, int idx); int kvm_riscv_vcpu_sbi_ecall(struct kvm_vcpu *vcpu, struct kvm_run *run); void kvm_riscv_vcpu_sbi_init(struct kvm_vcpu *vcpu); +int kvm_riscv_vcpu_get_reg_sbi_sta(struct kvm_vcpu *vcpu, unsigned long reg_num, + unsigned long *reg_val); +int kvm_riscv_vcpu_set_reg_sbi_sta(struct kvm_vcpu *vcpu, unsigned long reg_num, + unsigned long reg_val); + #ifdef CONFIG_RISCV_SBI_V01 extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_v01; #endif @@ -74,6 +85,7 @@ extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_rfence; extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_srst; extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_hsm; extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_dbcn; +extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_sta; extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_experimental; extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_vendor; diff --git a/arch/riscv/include/asm/paravirt.h b/arch/riscv/include/asm/paravirt.h new file mode 100644 index 00000000000000..c0abde70fc2ce9 --- /dev/null +++ b/arch/riscv/include/asm/paravirt.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_RISCV_PARAVIRT_H +#define _ASM_RISCV_PARAVIRT_H + +#ifdef CONFIG_PARAVIRT +#include + +struct static_key; +extern struct static_key paravirt_steal_enabled; +extern struct static_key paravirt_steal_rq_enabled; + +u64 dummy_steal_clock(int cpu); + +DECLARE_STATIC_CALL(pv_steal_clock, dummy_steal_clock); + +static inline u64 paravirt_steal_clock(int cpu) +{ + return static_call(pv_steal_clock)(cpu); +} + +int __init pv_time_init(void); + +#else + +#define pv_time_init() do {} while (0) + +#endif /* CONFIG_PARAVIRT */ +#endif /* _ASM_RISCV_PARAVIRT_H */ diff --git a/arch/riscv/include/asm/paravirt_api_clock.h b/arch/riscv/include/asm/paravirt_api_clock.h new file mode 100644 index 00000000000000..65ac7cee0dad74 --- /dev/null +++ b/arch/riscv/include/asm/paravirt_api_clock.h @@ -0,0 +1 @@ +#include diff --git a/arch/riscv/include/asm/pgtable-64.h b/arch/riscv/include/asm/pgtable-64.h index 9a2c780a11e953..b42017d76924f7 100644 --- a/arch/riscv/include/asm/pgtable-64.h +++ b/arch/riscv/include/asm/pgtable-64.h @@ -202,7 +202,7 @@ static inline int pud_user(pud_t pud) static inline void set_pud(pud_t *pudp, pud_t pud) { - *pudp = pud; + WRITE_ONCE(*pudp, pud); } static inline void pud_clear(pud_t *pudp) @@ -278,7 +278,7 @@ static inline unsigned long _pmd_pfn(pmd_t pmd) static inline void set_p4d(p4d_t *p4dp, p4d_t p4d) { if (pgtable_l4_enabled) - *p4dp = p4d; + WRITE_ONCE(*p4dp, p4d); else set_pud((pud_t *)p4dp, (pud_t){ p4d_val(p4d) }); } @@ -340,18 +340,12 @@ static inline struct page *p4d_page(p4d_t p4d) #define pud_index(addr) (((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1)) #define pud_offset pud_offset -static inline pud_t *pud_offset(p4d_t *p4d, unsigned long address) -{ - if (pgtable_l4_enabled) - return p4d_pgtable(*p4d) + pud_index(address); - - return (pud_t *)p4d; -} +pud_t *pud_offset(p4d_t *p4d, unsigned long address); static inline void set_pgd(pgd_t *pgdp, pgd_t pgd) { if (pgtable_l5_enabled) - *pgdp = pgd; + WRITE_ONCE(*pgdp, pgd); else set_p4d((p4d_t *)pgdp, (p4d_t){ pgd_val(pgd) }); } @@ -404,12 +398,6 @@ static inline struct page *pgd_page(pgd_t pgd) #define p4d_index(addr) (((addr) >> P4D_SHIFT) & (PTRS_PER_P4D - 1)) #define p4d_offset p4d_offset -static inline p4d_t *p4d_offset(pgd_t *pgd, unsigned long address) -{ - if (pgtable_l5_enabled) - return pgd_pgtable(*pgd) + p4d_index(address); - - return (p4d_t *)pgd; -} +p4d_t *p4d_offset(pgd_t *pgd, unsigned long address); #endif /* _ASM_RISCV_PGTABLE_64_H */ diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h index ab00235b018f89..0c94260b5d0c12 100644 --- a/arch/riscv/include/asm/pgtable.h +++ b/arch/riscv/include/asm/pgtable.h @@ -248,7 +248,7 @@ static inline int pmd_leaf(pmd_t pmd) static inline void set_pmd(pmd_t *pmdp, pmd_t pmd) { - *pmdp = pmd; + WRITE_ONCE(*pmdp, pmd); } static inline void pmd_clear(pmd_t *pmdp) @@ -510,7 +510,7 @@ static inline int pte_same(pte_t pte_a, pte_t pte_b) */ static inline void set_pte(pte_t *ptep, pte_t pteval) { - *ptep = pteval; + WRITE_ONCE(*ptep, pteval); } void flush_icache_pte(pte_t pte); @@ -544,19 +544,12 @@ static inline void pte_clear(struct mm_struct *mm, __set_pte_at(ptep, __pte(0)); } -#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS -static inline int ptep_set_access_flags(struct vm_area_struct *vma, - unsigned long address, pte_t *ptep, - pte_t entry, int dirty) -{ - if (!pte_same(*ptep, entry)) - __set_pte_at(ptep, entry); - /* - * update_mmu_cache will unconditionally execute, handling both - * the case that the PTE changed and the spurious fault case. - */ - return true; -} +#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS /* defined in mm/pgtable.c */ +extern int ptep_set_access_flags(struct vm_area_struct *vma, unsigned long address, + pte_t *ptep, pte_t entry, int dirty); +#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG /* defined in mm/pgtable.c */ +extern int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long address, + pte_t *ptep); #define __HAVE_ARCH_PTEP_GET_AND_CLEAR static inline pte_t ptep_get_and_clear(struct mm_struct *mm, @@ -569,16 +562,6 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm, return pte; } -#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG -static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, - unsigned long address, - pte_t *ptep) -{ - if (!pte_young(*ptep)) - return 0; - return test_and_clear_bit(_PAGE_ACCESSED_OFFSET, &pte_val(*ptep)); -} - #define __HAVE_ARCH_PTEP_SET_WRPROTECT static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long address, pte_t *ptep) @@ -673,6 +656,7 @@ static inline int pmd_write(pmd_t pmd) return pte_write(pmd_pte(pmd)); } +#define pmd_dirty pmd_dirty static inline int pmd_dirty(pmd_t pmd) { return pte_dirty(pmd_pte(pmd)); @@ -881,7 +865,7 @@ static inline pte_t pte_swp_clear_exclusive(pte_t pte) #define TASK_SIZE_MIN (PGDIR_SIZE_L3 * PTRS_PER_PGD / 2) #ifdef CONFIG_COMPAT -#define TASK_SIZE_32 (_AC(0x80000000, UL) - PAGE_SIZE) +#define TASK_SIZE_32 (_AC(0x80000000, UL)) #define TASK_SIZE (test_thread_flag(TIF_32BIT) ? \ TASK_SIZE_32 : TASK_SIZE_64) #else diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h index f19f861cda5490..a8509cc31ab25a 100644 --- a/arch/riscv/include/asm/processor.h +++ b/arch/riscv/include/asm/processor.h @@ -16,7 +16,7 @@ #ifdef CONFIG_64BIT #define DEFAULT_MAP_WINDOW (UL(1) << (MMAP_VA_BITS - 1)) -#define STACK_TOP_MAX TASK_SIZE_64 +#define STACK_TOP_MAX TASK_SIZE #define arch_get_mmap_end(addr, len, flags) \ ({ \ @@ -73,6 +73,43 @@ struct task_struct; struct pt_regs; +/* + * We use a flag to track in-kernel Vector context. Currently the flag has the + * following meaning: + * + * - bit 0: indicates whether the in-kernel Vector context is active. The + * activation of this state disables the preemption. On a non-RT kernel, it + * also disable bh. + * - bits 8: is used for tracking preemptible kernel-mode Vector, when + * RISCV_ISA_V_PREEMPTIVE is enabled. Calling kernel_vector_begin() does not + * disable the preemption if the thread's kernel_vstate.datap is allocated. + * Instead, the kernel set this bit field. Then the trap entry/exit code + * knows if we are entering/exiting the context that owns preempt_v. + * - 0: the task is not using preempt_v + * - 1: the task is actively using preempt_v. But whether does the task own + * the preempt_v context is decided by bits in RISCV_V_CTX_DEPTH_MASK. + * - bit 16-23 are RISCV_V_CTX_DEPTH_MASK, used by context tracking routine + * when preempt_v starts: + * - 0: the task is actively using, and own preempt_v context. + * - non-zero: the task was using preempt_v, but then took a trap within. + * Thus, the task does not own preempt_v. Any use of Vector will have to + * save preempt_v, if dirty, and fallback to non-preemptible kernel-mode + * Vector. + * - bit 30: The in-kernel preempt_v context is saved, and requries to be + * restored when returning to the context that owns the preempt_v. + * - bit 31: The in-kernel preempt_v context is dirty, as signaled by the + * trap entry code. Any context switches out-of current task need to save + * it to the task's in-kernel V context. Also, any traps nesting on-top-of + * preempt_v requesting to use V needs a save. + */ +#define RISCV_V_CTX_DEPTH_MASK 0x00ff0000 + +#define RISCV_V_CTX_UNIT_DEPTH 0x00010000 +#define RISCV_KERNEL_MODE_V 0x00000001 +#define RISCV_PREEMPT_V 0x00000100 +#define RISCV_PREEMPT_V_DIRTY 0x80000000 +#define RISCV_PREEMPT_V_NEED_RESTORE 0x40000000 + /* CPU-specific state of a task */ struct thread_struct { /* Callee-saved registers */ @@ -81,9 +118,11 @@ struct thread_struct { unsigned long s[12]; /* s[0]: frame pointer */ struct __riscv_d_ext_state fstate; unsigned long bad_cause; - unsigned long vstate_ctrl; + u32 riscv_v_flags; + u32 vstate_ctrl; struct __riscv_v_ext_state vstate; unsigned long align_ctl; + struct __riscv_v_ext_state kernel_vstate; }; /* Whitelist the fstate from the task_struct for hardened usercopy */ diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h index 0892f4421bc4a5..6e68f8dff76bc6 100644 --- a/arch/riscv/include/asm/sbi.h +++ b/arch/riscv/include/asm/sbi.h @@ -29,8 +29,10 @@ enum sbi_ext_id { SBI_EXT_RFENCE = 0x52464E43, SBI_EXT_HSM = 0x48534D, SBI_EXT_SRST = 0x53525354, + SBI_EXT_SUSP = 0x53555350, SBI_EXT_PMU = 0x504D55, SBI_EXT_DBCN = 0x4442434E, + SBI_EXT_STA = 0x535441, /* Experimentals extensions must lie within this range */ SBI_EXT_EXPERIMENTAL_START = 0x08000000, @@ -114,6 +116,14 @@ enum sbi_srst_reset_reason { SBI_SRST_RESET_REASON_SYS_FAILURE, }; +enum sbi_ext_susp_fid { + SBI_EXT_SUSP_SYSTEM_SUSPEND = 0, +}; + +enum sbi_ext_susp_sleep_type { + SBI_SUSP_SLEEP_TYPE_SUSPEND_TO_RAM = 0, +}; + enum sbi_ext_pmu_fid { SBI_EXT_PMU_NUM_COUNTERS = 0, SBI_EXT_PMU_COUNTER_GET_INFO, @@ -243,6 +253,22 @@ enum sbi_ext_dbcn_fid { SBI_EXT_DBCN_CONSOLE_WRITE_BYTE = 2, }; +/* SBI STA (steal-time accounting) extension */ +enum sbi_ext_sta_fid { + SBI_EXT_STA_STEAL_TIME_SET_SHMEM = 0, +}; + +struct sbi_sta_struct { + __le32 sequence; + __le32 flags; + __le64 steal; + u8 preempted; + u8 pad[47]; +} __packed; + +#define SBI_STA_SHMEM_DISABLE -1 + +/* SBI spec version fields */ #define SBI_SPEC_VERSION_DEFAULT 0x1 #define SBI_SPEC_VERSION_MAJOR_SHIFT 24 #define SBI_SPEC_VERSION_MAJOR_MASK 0x7f @@ -271,8 +297,13 @@ struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0, unsigned long arg3, unsigned long arg4, unsigned long arg5); +#ifdef CONFIG_RISCV_SBI_V01 void sbi_console_putchar(int ch); int sbi_console_getchar(void); +#else +static inline void sbi_console_putchar(int ch) { } +static inline int sbi_console_getchar(void) { return -ENOENT; } +#endif long sbi_get_mvendorid(void); long sbi_get_marchid(void); long sbi_get_mimpid(void); @@ -329,6 +360,11 @@ static inline unsigned long sbi_mk_version(unsigned long major, } int sbi_err_map_linux_errno(int err); + +extern bool sbi_debug_console_available; +int sbi_debug_console_write(const char *bytes, unsigned int num_bytes); +int sbi_debug_console_read(char *bytes, unsigned int num_bytes); + #else /* CONFIG_RISCV_SBI */ static inline int sbi_remote_fence_i(const struct cpumask *cpu_mask) { return -1; } static inline void sbi_init(void) {} diff --git a/arch/riscv/include/asm/sections.h b/arch/riscv/include/asm/sections.h index 32336e8a17cb07..a393d5035c5433 100644 --- a/arch/riscv/include/asm/sections.h +++ b/arch/riscv/include/asm/sections.h @@ -13,6 +13,7 @@ extern char _start_kernel[]; extern char __init_data_begin[], __init_data_end[]; extern char __init_text_begin[], __init_text_end[]; extern char __alt_start[], __alt_end[]; +extern char __exittext_begin[], __exittext_end[]; static inline bool is_va_kernel_text(uintptr_t va) { diff --git a/arch/riscv/include/asm/simd.h b/arch/riscv/include/asm/simd.h new file mode 100644 index 00000000000000..54efbf523d49c6 --- /dev/null +++ b/arch/riscv/include/asm/simd.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2017 Linaro Ltd. + * Copyright (C) 2023 SiFive + */ + +#ifndef __ASM_SIMD_H +#define __ASM_SIMD_H + +#include +#include +#include +#include +#include +#include + +#include + +#ifdef CONFIG_RISCV_ISA_V +/* + * may_use_simd - whether it is allowable at this time to issue vector + * instructions or access the vector register file + * + * Callers must not assume that the result remains true beyond the next + * preempt_enable() or return from softirq context. + */ +static __must_check inline bool may_use_simd(void) +{ + /* + * RISCV_KERNEL_MODE_V is only set while preemption is disabled, + * and is clear whenever preemption is enabled. + */ + if (in_hardirq() || in_nmi()) + return false; + + /* + * Nesting is acheived in preempt_v by spreading the control for + * preemptible and non-preemptible kernel-mode Vector into two fields. + * Always try to match with prempt_v if kernel V-context exists. Then, + * fallback to check non preempt_v if nesting happens, or if the config + * is not set. + */ + if (IS_ENABLED(CONFIG_RISCV_ISA_V_PREEMPTIVE) && current->thread.kernel_vstate.datap) { + if (!riscv_preempt_v_started(current)) + return true; + } + /* + * Non-preemptible kernel-mode Vector temporarily disables bh. So we + * must not return true on irq_disabled(). Otherwise we would fail the + * lockdep check calling local_bh_enable() + */ + return !irqs_disabled() && !(riscv_v_flags() & RISCV_KERNEL_MODE_V); +} + +#else /* ! CONFIG_RISCV_ISA_V */ + +static __must_check inline bool may_use_simd(void) +{ + return false; +} + +#endif /* ! CONFIG_RISCV_ISA_V */ + +#endif diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h index f90d8e42f3c791..7efdb0584d47ac 100644 --- a/arch/riscv/include/asm/switch_to.h +++ b/arch/riscv/include/asm/switch_to.h @@ -53,8 +53,7 @@ static inline void __switch_to_fpu(struct task_struct *prev, struct pt_regs *regs; regs = task_pt_regs(prev); - if (unlikely(regs->status & SR_SD)) - fstate_save(prev, regs); + fstate_save(prev, regs); fstate_restore(next, task_pt_regs(next)); } diff --git a/arch/riscv/include/asm/thread_info.h b/arch/riscv/include/asm/thread_info.h index 574779900bfb33..5d473343634b9d 100644 --- a/arch/riscv/include/asm/thread_info.h +++ b/arch/riscv/include/asm/thread_info.h @@ -28,7 +28,6 @@ #define THREAD_SHIFT (PAGE_SHIFT + THREAD_SIZE_ORDER) #define OVERFLOW_STACK_SIZE SZ_4K -#define SHADOW_OVERFLOW_STACK_SIZE (1024) #define IRQ_STACK_SIZE THREAD_SIZE @@ -103,12 +102,14 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src); #define TIF_NOTIFY_SIGNAL 9 /* signal notifications exist */ #define TIF_UPROBE 10 /* uprobe breakpoint or singlestep */ #define TIF_32BIT 11 /* compat-mode 32bit process */ +#define TIF_RISCV_V_DEFER_RESTORE 12 /* restore Vector before returing to user */ #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) #define _TIF_NOTIFY_SIGNAL (1 << TIF_NOTIFY_SIGNAL) #define _TIF_UPROBE (1 << TIF_UPROBE) +#define _TIF_RISCV_V_DEFER_RESTORE (1 << TIF_RISCV_V_DEFER_RESTORE) #define _TIF_WORK_MASK \ (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | _TIF_NEED_RESCHED | \ diff --git a/arch/riscv/include/asm/tlbbatch.h b/arch/riscv/include/asm/tlbbatch.h new file mode 100644 index 00000000000000..46014f70b9daa1 --- /dev/null +++ b/arch/riscv/include/asm/tlbbatch.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2023 Rivos Inc. + */ + +#ifndef _ASM_RISCV_TLBBATCH_H +#define _ASM_RISCV_TLBBATCH_H + +#include + +struct arch_tlbflush_unmap_batch { + struct cpumask cpumask; +}; + +#endif /* _ASM_RISCV_TLBBATCH_H */ diff --git a/arch/riscv/include/asm/tlbflush.h b/arch/riscv/include/asm/tlbflush.h index 8f3418c5f1724b..928f096dca21b4 100644 --- a/arch/riscv/include/asm/tlbflush.h +++ b/arch/riscv/include/asm/tlbflush.h @@ -41,11 +41,20 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr); void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end); void flush_tlb_kernel_range(unsigned long start, unsigned long end); +void local_flush_tlb_kernel_range(unsigned long start, unsigned long end); #ifdef CONFIG_TRANSPARENT_HUGEPAGE #define __HAVE_ARCH_FLUSH_PMD_TLB_RANGE void flush_pmd_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end); #endif + +bool arch_tlbbatch_should_defer(struct mm_struct *mm); +void arch_tlbbatch_add_pending(struct arch_tlbflush_unmap_batch *batch, + struct mm_struct *mm, + unsigned long uaddr); +void arch_flush_tlb_batched_pending(struct mm_struct *mm); +void arch_tlbbatch_flush(struct arch_tlbflush_unmap_batch *batch); + #else /* CONFIG_SMP && CONFIG_MMU */ #define flush_tlb_all() local_flush_tlb_all() diff --git a/arch/riscv/include/asm/topology.h b/arch/riscv/include/asm/topology.h index e316ab3b77f341..61183688bdd54e 100644 --- a/arch/riscv/include/asm/topology.h +++ b/arch/riscv/include/asm/topology.h @@ -9,6 +9,7 @@ #define arch_set_freq_scale topology_set_freq_scale #define arch_scale_freq_capacity topology_get_freq_scale #define arch_scale_freq_invariant topology_scale_freq_invariant +#define arch_scale_freq_ref topology_get_freq_ref /* Replace task scheduler's default cpu-invariant accounting */ #define arch_scale_cpu_capacity topology_get_cpu_scale diff --git a/arch/riscv/include/asm/vector.h b/arch/riscv/include/asm/vector.h index 87aaef656257cb..0cd6f0a027d1f7 100644 --- a/arch/riscv/include/asm/vector.h +++ b/arch/riscv/include/asm/vector.h @@ -22,6 +22,18 @@ extern unsigned long riscv_v_vsize; int riscv_v_setup_vsize(void); bool riscv_v_first_use_handler(struct pt_regs *regs); +void kernel_vector_begin(void); +void kernel_vector_end(void); +void get_cpu_vector_context(void); +void put_cpu_vector_context(void); +void riscv_v_thread_free(struct task_struct *tsk); +void __init riscv_v_setup_ctx_cache(void); +void riscv_v_thread_alloc(struct task_struct *tsk); + +static inline u32 riscv_v_flags(void) +{ + return READ_ONCE(current->thread.riscv_v_flags); +} static __always_inline bool has_vector(void) { @@ -162,36 +174,89 @@ static inline void riscv_v_vstate_discard(struct pt_regs *regs) __riscv_v_vstate_dirty(regs); } -static inline void riscv_v_vstate_save(struct task_struct *task, +static inline void riscv_v_vstate_save(struct __riscv_v_ext_state *vstate, struct pt_regs *regs) { if ((regs->status & SR_VS) == SR_VS_DIRTY) { - struct __riscv_v_ext_state *vstate = &task->thread.vstate; - __riscv_v_vstate_save(vstate, vstate->datap); __riscv_v_vstate_clean(regs); } } -static inline void riscv_v_vstate_restore(struct task_struct *task, +static inline void riscv_v_vstate_restore(struct __riscv_v_ext_state *vstate, struct pt_regs *regs) { if ((regs->status & SR_VS) != SR_VS_OFF) { - struct __riscv_v_ext_state *vstate = &task->thread.vstate; - __riscv_v_vstate_restore(vstate, vstate->datap); __riscv_v_vstate_clean(regs); } } +static inline void riscv_v_vstate_set_restore(struct task_struct *task, + struct pt_regs *regs) +{ + if ((regs->status & SR_VS) != SR_VS_OFF) { + set_tsk_thread_flag(task, TIF_RISCV_V_DEFER_RESTORE); + riscv_v_vstate_on(regs); + } +} + +#ifdef CONFIG_RISCV_ISA_V_PREEMPTIVE +static inline bool riscv_preempt_v_dirty(struct task_struct *task) +{ + return !!(task->thread.riscv_v_flags & RISCV_PREEMPT_V_DIRTY); +} + +static inline bool riscv_preempt_v_restore(struct task_struct *task) +{ + return !!(task->thread.riscv_v_flags & RISCV_PREEMPT_V_NEED_RESTORE); +} + +static inline void riscv_preempt_v_clear_dirty(struct task_struct *task) +{ + barrier(); + task->thread.riscv_v_flags &= ~RISCV_PREEMPT_V_DIRTY; +} + +static inline void riscv_preempt_v_set_restore(struct task_struct *task) +{ + barrier(); + task->thread.riscv_v_flags |= RISCV_PREEMPT_V_NEED_RESTORE; +} + +static inline bool riscv_preempt_v_started(struct task_struct *task) +{ + return !!(task->thread.riscv_v_flags & RISCV_PREEMPT_V); +} + +#else /* !CONFIG_RISCV_ISA_V_PREEMPTIVE */ +static inline bool riscv_preempt_v_dirty(struct task_struct *task) { return false; } +static inline bool riscv_preempt_v_restore(struct task_struct *task) { return false; } +static inline bool riscv_preempt_v_started(struct task_struct *task) { return false; } +#define riscv_preempt_v_clear_dirty(tsk) do {} while (0) +#define riscv_preempt_v_set_restore(tsk) do {} while (0) +#endif /* CONFIG_RISCV_ISA_V_PREEMPTIVE */ + static inline void __switch_to_vector(struct task_struct *prev, struct task_struct *next) { struct pt_regs *regs; - regs = task_pt_regs(prev); - riscv_v_vstate_save(prev, regs); - riscv_v_vstate_restore(next, task_pt_regs(next)); + if (riscv_preempt_v_started(prev)) { + if (riscv_preempt_v_dirty(prev)) { + __riscv_v_vstate_save(&prev->thread.kernel_vstate, + prev->thread.kernel_vstate.datap); + riscv_preempt_v_clear_dirty(prev); + } + } else { + regs = task_pt_regs(prev); + riscv_v_vstate_save(&prev->thread.vstate, regs); + } + + if (riscv_preempt_v_started(next)) + riscv_preempt_v_set_restore(next); + else + riscv_v_vstate_set_restore(next, task_pt_regs(next)); } void riscv_v_vstate_ctrl_init(struct task_struct *tsk); @@ -208,11 +273,14 @@ static inline bool riscv_v_vstate_query(struct pt_regs *regs) { return false; } static inline bool riscv_v_vstate_ctrl_user_allowed(void) { return false; } #define riscv_v_vsize (0) #define riscv_v_vstate_discard(regs) do {} while (0) -#define riscv_v_vstate_save(task, regs) do {} while (0) -#define riscv_v_vstate_restore(task, regs) do {} while (0) +#define riscv_v_vstate_save(vstate, regs) do {} while (0) +#define riscv_v_vstate_restore(vstate, regs) do {} while (0) #define __switch_to_vector(__prev, __next) do {} while (0) #define riscv_v_vstate_off(regs) do {} while (0) #define riscv_v_vstate_on(regs) do {} while (0) +#define riscv_v_thread_free(tsk) do {} while (0) +#define riscv_v_setup_ctx_cache() do {} while (0) +#define riscv_v_thread_alloc(tsk) do {} while (0) #endif /* CONFIG_RISCV_ISA_V */ diff --git a/arch/riscv/include/asm/word-at-a-time.h b/arch/riscv/include/asm/word-at-a-time.h index 7c086ac6ecd4a8..f3f031e34191d6 100644 --- a/arch/riscv/include/asm/word-at-a-time.h +++ b/arch/riscv/include/asm/word-at-a-time.h @@ -9,6 +9,7 @@ #define _ASM_RISCV_WORD_AT_A_TIME_H +#include #include struct word_at_a_time { @@ -45,4 +46,30 @@ static inline unsigned long find_zero(unsigned long mask) /* The mask we created is directly usable as a bytemask */ #define zero_bytemask(mask) (mask) +#ifdef CONFIG_DCACHE_WORD_ACCESS + +/* + * Load an unaligned word from kernel space. + * + * In the (very unlikely) case of the word being a page-crosser + * and the next page not being mapped, take the exception and + * return zeroes in the non-existing part. + */ +static inline unsigned long load_unaligned_zeropad(const void *addr) +{ + unsigned long ret; + + /* Load word from unaligned pointer addr */ + asm( + "1: " REG_L " %0, %2\n" + "2:\n" + _ASM_EXTABLE_LOAD_UNALIGNED_ZEROPAD(1b, 2b, %0, %1) + : "=&r" (ret) + : "r" (addr), "m" (*(unsigned long *)addr)); + + return ret; +} + +#endif /* CONFIG_DCACHE_WORD_ACCESS */ + #endif /* _ASM_RISCV_WORD_AT_A_TIME_H */ diff --git a/arch/riscv/include/asm/xip_fixup.h b/arch/riscv/include/asm/xip_fixup.h index d4ffc3c37649ff..b65bf6306f69c6 100644 --- a/arch/riscv/include/asm/xip_fixup.h +++ b/arch/riscv/include/asm/xip_fixup.h @@ -13,7 +13,7 @@ add \reg, \reg, t0 .endm .macro XIP_FIXUP_FLASH_OFFSET reg - la t1, __data_loc + la t0, __data_loc REG_L t1, _xip_phys_offset sub \reg, \reg, t1 add \reg, \reg, t0 diff --git a/arch/riscv/include/asm/xor.h b/arch/riscv/include/asm/xor.h new file mode 100644 index 00000000000000..96011861e46b4d --- /dev/null +++ b/arch/riscv/include/asm/xor.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2021 SiFive + */ + +#include +#include +#ifdef CONFIG_RISCV_ISA_V +#include +#include +#include + +static void xor_vector_2(unsigned long bytes, unsigned long *__restrict p1, + const unsigned long *__restrict p2) +{ + kernel_vector_begin(); + xor_regs_2_(bytes, p1, p2); + kernel_vector_end(); +} + +static void xor_vector_3(unsigned long bytes, unsigned long *__restrict p1, + const unsigned long *__restrict p2, + const unsigned long *__restrict p3) +{ + kernel_vector_begin(); + xor_regs_3_(bytes, p1, p2, p3); + kernel_vector_end(); +} + +static void xor_vector_4(unsigned long bytes, unsigned long *__restrict p1, + const unsigned long *__restrict p2, + const unsigned long *__restrict p3, + const unsigned long *__restrict p4) +{ + kernel_vector_begin(); + xor_regs_4_(bytes, p1, p2, p3, p4); + kernel_vector_end(); +} + +static void xor_vector_5(unsigned long bytes, unsigned long *__restrict p1, + const unsigned long *__restrict p2, + const unsigned long *__restrict p3, + const unsigned long *__restrict p4, + const unsigned long *__restrict p5) +{ + kernel_vector_begin(); + xor_regs_5_(bytes, p1, p2, p3, p4, p5); + kernel_vector_end(); +} + +static struct xor_block_template xor_block_rvv = { + .name = "rvv", + .do_2 = xor_vector_2, + .do_3 = xor_vector_3, + .do_4 = xor_vector_4, + .do_5 = xor_vector_5 +}; + +#undef XOR_TRY_TEMPLATES +#define XOR_TRY_TEMPLATES \ + do { \ + xor_speed(&xor_block_8regs); \ + xor_speed(&xor_block_32regs); \ + if (has_vector()) { \ + xor_speed(&xor_block_rvv);\ + } \ + } while (0) +#endif diff --git a/arch/riscv/include/uapi/asm/hwprobe.h b/arch/riscv/include/uapi/asm/hwprobe.h index b659ffcfcdb454..9f2a8e3ff2048e 100644 --- a/arch/riscv/include/uapi/asm/hwprobe.h +++ b/arch/riscv/include/uapi/asm/hwprobe.h @@ -30,6 +30,35 @@ struct riscv_hwprobe { #define RISCV_HWPROBE_EXT_ZBB (1 << 4) #define RISCV_HWPROBE_EXT_ZBS (1 << 5) #define RISCV_HWPROBE_EXT_ZICBOZ (1 << 6) +#define RISCV_HWPROBE_EXT_ZBC (1 << 7) +#define RISCV_HWPROBE_EXT_ZBKB (1 << 8) +#define RISCV_HWPROBE_EXT_ZBKC (1 << 9) +#define RISCV_HWPROBE_EXT_ZBKX (1 << 10) +#define RISCV_HWPROBE_EXT_ZKND (1 << 11) +#define RISCV_HWPROBE_EXT_ZKNE (1 << 12) +#define RISCV_HWPROBE_EXT_ZKNH (1 << 13) +#define RISCV_HWPROBE_EXT_ZKSED (1 << 14) +#define RISCV_HWPROBE_EXT_ZKSH (1 << 15) +#define RISCV_HWPROBE_EXT_ZKT (1 << 16) +#define RISCV_HWPROBE_EXT_ZVBB (1 << 17) +#define RISCV_HWPROBE_EXT_ZVBC (1 << 18) +#define RISCV_HWPROBE_EXT_ZVKB (1 << 19) +#define RISCV_HWPROBE_EXT_ZVKG (1 << 20) +#define RISCV_HWPROBE_EXT_ZVKNED (1 << 21) +#define RISCV_HWPROBE_EXT_ZVKNHA (1 << 22) +#define RISCV_HWPROBE_EXT_ZVKNHB (1 << 23) +#define RISCV_HWPROBE_EXT_ZVKSED (1 << 24) +#define RISCV_HWPROBE_EXT_ZVKSH (1 << 25) +#define RISCV_HWPROBE_EXT_ZVKT (1 << 26) +#define RISCV_HWPROBE_EXT_ZFH (1 << 27) +#define RISCV_HWPROBE_EXT_ZFHMIN (1 << 28) +#define RISCV_HWPROBE_EXT_ZIHINTNTL (1 << 29) +#define RISCV_HWPROBE_EXT_ZVFH (1 << 30) +#define RISCV_HWPROBE_EXT_ZVFHMIN (1 << 31) +#define RISCV_HWPROBE_EXT_ZFA (1ULL << 32) +#define RISCV_HWPROBE_EXT_ZTSO (1ULL << 33) +#define RISCV_HWPROBE_EXT_ZACAS (1ULL << 34) +#define RISCV_HWPROBE_EXT_ZICOND (1ULL << 35) #define RISCV_HWPROBE_KEY_CPUPERF_0 5 #define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0) #define RISCV_HWPROBE_MISALIGNED_EMULATED (1 << 0) @@ -40,4 +69,7 @@ struct riscv_hwprobe { #define RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE 6 /* Increase RISCV_HWPROBE_MAX_KEY when adding items. */ +/* Flags */ +#define RISCV_HWPROBE_WHICH_CPUS (1 << 0) + #endif diff --git a/arch/riscv/include/uapi/asm/kvm.h b/arch/riscv/include/uapi/asm/kvm.h index 60d3b21dead7d8..d6b7a5b958742c 100644 --- a/arch/riscv/include/uapi/asm/kvm.h +++ b/arch/riscv/include/uapi/asm/kvm.h @@ -157,9 +157,16 @@ enum KVM_RISCV_SBI_EXT_ID { KVM_RISCV_SBI_EXT_EXPERIMENTAL, KVM_RISCV_SBI_EXT_VENDOR, KVM_RISCV_SBI_EXT_DBCN, + KVM_RISCV_SBI_EXT_STA, KVM_RISCV_SBI_EXT_MAX, }; +/* SBI STA extension registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG */ +struct kvm_riscv_sbi_sta { + unsigned long shmem_lo; + unsigned long shmem_hi; +}; + /* Possible states for kvm_riscv_timer */ #define KVM_RISCV_TIMER_STATE_OFF 0 #define KVM_RISCV_TIMER_STATE_ON 1 @@ -241,6 +248,12 @@ enum KVM_RISCV_SBI_EXT_ID { #define KVM_REG_RISCV_VECTOR_REG(n) \ ((n) + sizeof(struct __riscv_v_ext_state) / sizeof(unsigned long)) +/* Registers for specific SBI extensions are mapped as type 10 */ +#define KVM_REG_RISCV_SBI_STATE (0x0a << KVM_REG_RISCV_TYPE_SHIFT) +#define KVM_REG_RISCV_SBI_STA (0x0 << KVM_REG_RISCV_SUBTYPE_SHIFT) +#define KVM_REG_RISCV_SBI_STA_REG(name) \ + (offsetof(struct kvm_riscv_sbi_sta, name) / sizeof(unsigned long)) + /* Device Control API: RISC-V AIA */ #define KVM_DEV_RISCV_APLIC_ALIGN 0x1000 #define KVM_DEV_RISCV_APLIC_SIZE 0x4000 diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index fee22a3d1b5346..f71910718053d8 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile @@ -11,7 +11,7 @@ endif CFLAGS_syscall_table.o += $(call cc-option,-Wno-override-init,) CFLAGS_compat_syscall_table.o += $(call cc-option,-Wno-override-init,) -ifdef CONFIG_KEXEC +ifdef CONFIG_KEXEC_CORE AFLAGS_kexec_relocate.o := -mcmodel=medany $(call cc-option,-mno-relax) endif @@ -50,6 +50,7 @@ obj-y += setup.o obj-y += signal.o obj-y += syscall_table.o obj-y += sys_riscv.o +obj-y += sys_hwprobe.o obj-y += time.o obj-y += traps.o obj-y += riscv_ksyms.o @@ -63,6 +64,7 @@ obj-$(CONFIG_MMU) += vdso.o vdso/ obj-$(CONFIG_RISCV_MISALIGNED) += traps_misaligned.o obj-$(CONFIG_FPU) += fpu.o obj-$(CONFIG_RISCV_ISA_V) += vector.o +obj-$(CONFIG_RISCV_ISA_V) += kernel_mode_vector.o obj-$(CONFIG_SMP) += smpboot.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SMP) += cpu_ops.o @@ -85,6 +87,7 @@ obj-$(CONFIG_SMP) += sbi-ipi.o obj-$(CONFIG_SMP) += cpu_ops_sbi.o endif obj-$(CONFIG_HOTPLUG_CPU) += cpu-hotplug.o +obj-$(CONFIG_PARAVIRT) += paravirt.o obj-$(CONFIG_KGDB) += kgdb.o obj-$(CONFIG_KEXEC_CORE) += kexec_relocate.o crash_save_regs.o machine_kexec.o obj-$(CONFIG_KEXEC_FILE) += elf_kexec.o machine_kexec_file.o diff --git a/arch/riscv/kernel/cfi.c b/arch/riscv/kernel/cfi.c index 820158d7a29130..6ec9dbd7292eec 100644 --- a/arch/riscv/kernel/cfi.c +++ b/arch/riscv/kernel/cfi.c @@ -4,7 +4,7 @@ * * Copyright (C) 2023 Google LLC */ -#include +#include #include /* diff --git a/arch/riscv/kernel/cpu-hotplug.c b/arch/riscv/kernel/cpu-hotplug.c index 457a18efcb1148..28b58fc5ad1996 100644 --- a/arch/riscv/kernel/cpu-hotplug.c +++ b/arch/riscv/kernel/cpu-hotplug.c @@ -18,7 +18,7 @@ bool cpu_has_hotplug(unsigned int cpu) { - if (cpu_ops[cpu]->cpu_stop) + if (cpu_ops->cpu_stop) return true; return false; @@ -29,25 +29,18 @@ bool cpu_has_hotplug(unsigned int cpu) */ int __cpu_disable(void) { - int ret = 0; unsigned int cpu = smp_processor_id(); - if (!cpu_ops[cpu] || !cpu_ops[cpu]->cpu_stop) + if (!cpu_ops->cpu_stop) return -EOPNOTSUPP; - if (cpu_ops[cpu]->cpu_disable) - ret = cpu_ops[cpu]->cpu_disable(cpu); - - if (ret) - return ret; - remove_cpu_topology(cpu); numa_remove_cpu(cpu); set_cpu_online(cpu, false); riscv_ipi_disable(); irq_migrate_all_off_this_cpu(); - return ret; + return 0; } #ifdef CONFIG_HOTPLUG_CPU @@ -62,8 +55,8 @@ void arch_cpuhp_cleanup_dead_cpu(unsigned int cpu) pr_notice("CPU%u: off\n", cpu); /* Verify from the firmware if the cpu is really stopped*/ - if (cpu_ops[cpu]->cpu_is_stopped) - ret = cpu_ops[cpu]->cpu_is_stopped(cpu); + if (cpu_ops->cpu_is_stopped) + ret = cpu_ops->cpu_is_stopped(cpu); if (ret) pr_warn("CPU%d may not have stopped: %d\n", cpu, ret); } @@ -77,7 +70,7 @@ void __noreturn arch_cpu_idle_dead(void) cpuhp_ap_report_dead(); - cpu_ops[smp_processor_id()]->cpu_stop(); + cpu_ops->cpu_stop(); /* It should never reach here */ BUG(); } diff --git a/arch/riscv/kernel/cpu_ops.c b/arch/riscv/kernel/cpu_ops.c index eb479a88a954ef..6a8bd8f4db0711 100644 --- a/arch/riscv/kernel/cpu_ops.c +++ b/arch/riscv/kernel/cpu_ops.c @@ -13,25 +13,21 @@ #include #include -const struct cpu_operations *cpu_ops[NR_CPUS] __ro_after_init; +const struct cpu_operations *cpu_ops __ro_after_init = &cpu_ops_spinwait; extern const struct cpu_operations cpu_ops_sbi; #ifndef CONFIG_RISCV_BOOT_SPINWAIT const struct cpu_operations cpu_ops_spinwait = { - .name = "", - .cpu_prepare = NULL, .cpu_start = NULL, }; #endif -void __init cpu_set_ops(int cpuid) +void __init cpu_set_ops(void) { #if IS_ENABLED(CONFIG_RISCV_SBI) if (sbi_probe_extension(SBI_EXT_HSM)) { - if (!cpuid) - pr_info("SBI HSM extension detected\n"); - cpu_ops[cpuid] = &cpu_ops_sbi; - } else + pr_info("SBI HSM extension detected\n"); + cpu_ops = &cpu_ops_sbi; + } #endif - cpu_ops[cpuid] = &cpu_ops_spinwait; } diff --git a/arch/riscv/kernel/cpu_ops_sbi.c b/arch/riscv/kernel/cpu_ops_sbi.c index efa0f0816634c4..1cc7df740eddc9 100644 --- a/arch/riscv/kernel/cpu_ops_sbi.c +++ b/arch/riscv/kernel/cpu_ops_sbi.c @@ -79,23 +79,7 @@ static int sbi_cpu_start(unsigned int cpuid, struct task_struct *tidle) return sbi_hsm_hart_start(hartid, boot_addr, hsm_data); } -static int sbi_cpu_prepare(unsigned int cpuid) -{ - if (!cpu_ops_sbi.cpu_start) { - pr_err("cpu start method not defined for CPU [%d]\n", cpuid); - return -ENODEV; - } - return 0; -} - #ifdef CONFIG_HOTPLUG_CPU -static int sbi_cpu_disable(unsigned int cpuid) -{ - if (!cpu_ops_sbi.cpu_stop) - return -EOPNOTSUPP; - return 0; -} - static void sbi_cpu_stop(void) { int ret; @@ -118,11 +102,8 @@ static int sbi_cpu_is_stopped(unsigned int cpuid) #endif const struct cpu_operations cpu_ops_sbi = { - .name = "sbi", - .cpu_prepare = sbi_cpu_prepare, .cpu_start = sbi_cpu_start, #ifdef CONFIG_HOTPLUG_CPU - .cpu_disable = sbi_cpu_disable, .cpu_stop = sbi_cpu_stop, .cpu_is_stopped = sbi_cpu_is_stopped, #endif diff --git a/arch/riscv/kernel/cpu_ops_spinwait.c b/arch/riscv/kernel/cpu_ops_spinwait.c index d98d19226b5f51..613872b0a21acb 100644 --- a/arch/riscv/kernel/cpu_ops_spinwait.c +++ b/arch/riscv/kernel/cpu_ops_spinwait.c @@ -39,15 +39,6 @@ static void cpu_update_secondary_bootdata(unsigned int cpuid, WRITE_ONCE(__cpu_spinwait_task_pointer[hartid], tidle); } -static int spinwait_cpu_prepare(unsigned int cpuid) -{ - if (!cpu_ops_spinwait.cpu_start) { - pr_err("cpu start method not defined for CPU [%d]\n", cpuid); - return -ENODEV; - } - return 0; -} - static int spinwait_cpu_start(unsigned int cpuid, struct task_struct *tidle) { /* @@ -64,7 +55,5 @@ static int spinwait_cpu_start(unsigned int cpuid, struct task_struct *tidle) } const struct cpu_operations cpu_ops_spinwait = { - .name = "spinwait", - .cpu_prepare = spinwait_cpu_prepare, .cpu_start = spinwait_cpu_start, }; diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c index b3785ffc15703c..89920f84d0a343 100644 --- a/arch/riscv/kernel/cpufeature.c +++ b/arch/riscv/kernel/cpufeature.c @@ -8,8 +8,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -44,6 +46,8 @@ struct riscv_isainfo hart_isa[NR_CPUS]; /* Performance information */ DEFINE_PER_CPU(long, misaligned_access_speed); +static cpumask_t fast_misaligned_access; + /** * riscv_isa_extension_base() - Get base extension word * @@ -70,7 +74,7 @@ EXPORT_SYMBOL_GPL(riscv_isa_extension_base); * * NOTE: If isa_bitmap is NULL then Host ISA bitmap will be used. */ -bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, int bit) +bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, unsigned int bit) { const unsigned long *bmap = (isa_bitmap) ? isa_bitmap : riscv_isa; @@ -102,17 +106,101 @@ static bool riscv_isa_extension_check(int id) return false; } return true; + case RISCV_ISA_EXT_INVALID: + return false; } return true; } -#define __RISCV_ISA_EXT_DATA(_name, _id) { \ - .name = #_name, \ - .property = #_name, \ - .id = _id, \ +#define _RISCV_ISA_EXT_DATA(_name, _id, _subset_exts, _subset_exts_size) { \ + .name = #_name, \ + .property = #_name, \ + .id = _id, \ + .subset_ext_ids = _subset_exts, \ + .subset_ext_size = _subset_exts_size \ } +#define __RISCV_ISA_EXT_DATA(_name, _id) _RISCV_ISA_EXT_DATA(_name, _id, NULL, 0) + +/* Used to declare pure "lasso" extension (Zk for instance) */ +#define __RISCV_ISA_EXT_BUNDLE(_name, _bundled_exts) \ + _RISCV_ISA_EXT_DATA(_name, RISCV_ISA_EXT_INVALID, _bundled_exts, ARRAY_SIZE(_bundled_exts)) + +/* Used to declare extensions that are a superset of other extensions (Zvbb for instance) */ +#define __RISCV_ISA_EXT_SUPERSET(_name, _id, _sub_exts) \ + _RISCV_ISA_EXT_DATA(_name, _id, _sub_exts, ARRAY_SIZE(_sub_exts)) + +static const unsigned int riscv_zk_bundled_exts[] = { + RISCV_ISA_EXT_ZBKB, + RISCV_ISA_EXT_ZBKC, + RISCV_ISA_EXT_ZBKX, + RISCV_ISA_EXT_ZKND, + RISCV_ISA_EXT_ZKNE, + RISCV_ISA_EXT_ZKR, + RISCV_ISA_EXT_ZKT, +}; + +static const unsigned int riscv_zkn_bundled_exts[] = { + RISCV_ISA_EXT_ZBKB, + RISCV_ISA_EXT_ZBKC, + RISCV_ISA_EXT_ZBKX, + RISCV_ISA_EXT_ZKND, + RISCV_ISA_EXT_ZKNE, + RISCV_ISA_EXT_ZKNH, +}; + +static const unsigned int riscv_zks_bundled_exts[] = { + RISCV_ISA_EXT_ZBKB, + RISCV_ISA_EXT_ZBKC, + RISCV_ISA_EXT_ZKSED, + RISCV_ISA_EXT_ZKSH +}; + +#define RISCV_ISA_EXT_ZVKN \ + RISCV_ISA_EXT_ZVKNED, \ + RISCV_ISA_EXT_ZVKNHB, \ + RISCV_ISA_EXT_ZVKB, \ + RISCV_ISA_EXT_ZVKT + +static const unsigned int riscv_zvkn_bundled_exts[] = { + RISCV_ISA_EXT_ZVKN +}; + +static const unsigned int riscv_zvknc_bundled_exts[] = { + RISCV_ISA_EXT_ZVKN, + RISCV_ISA_EXT_ZVBC +}; + +static const unsigned int riscv_zvkng_bundled_exts[] = { + RISCV_ISA_EXT_ZVKN, + RISCV_ISA_EXT_ZVKG +}; + +#define RISCV_ISA_EXT_ZVKS \ + RISCV_ISA_EXT_ZVKSED, \ + RISCV_ISA_EXT_ZVKSH, \ + RISCV_ISA_EXT_ZVKB, \ + RISCV_ISA_EXT_ZVKT + +static const unsigned int riscv_zvks_bundled_exts[] = { + RISCV_ISA_EXT_ZVKS +}; + +static const unsigned int riscv_zvksc_bundled_exts[] = { + RISCV_ISA_EXT_ZVKS, + RISCV_ISA_EXT_ZVBC +}; + +static const unsigned int riscv_zvksg_bundled_exts[] = { + RISCV_ISA_EXT_ZVKS, + RISCV_ISA_EXT_ZVKG +}; + +static const unsigned int riscv_zvbb_exts[] = { + RISCV_ISA_EXT_ZVKB +}; + /* * The canonical order of ISA extension names in the ISA string is defined in * chapter 27 of the unprivileged specification. @@ -160,10 +248,6 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = { __RISCV_ISA_EXT_DATA(d, RISCV_ISA_EXT_d), __RISCV_ISA_EXT_DATA(q, RISCV_ISA_EXT_q), __RISCV_ISA_EXT_DATA(c, RISCV_ISA_EXT_c), - __RISCV_ISA_EXT_DATA(b, RISCV_ISA_EXT_b), - __RISCV_ISA_EXT_DATA(k, RISCV_ISA_EXT_k), - __RISCV_ISA_EXT_DATA(j, RISCV_ISA_EXT_j), - __RISCV_ISA_EXT_DATA(p, RISCV_ISA_EXT_p), __RISCV_ISA_EXT_DATA(v, RISCV_ISA_EXT_v), __RISCV_ISA_EXT_DATA(h, RISCV_ISA_EXT_h), __RISCV_ISA_EXT_DATA(zicbom, RISCV_ISA_EXT_ZICBOM), @@ -172,11 +256,49 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = { __RISCV_ISA_EXT_DATA(zicond, RISCV_ISA_EXT_ZICOND), __RISCV_ISA_EXT_DATA(zicsr, RISCV_ISA_EXT_ZICSR), __RISCV_ISA_EXT_DATA(zifencei, RISCV_ISA_EXT_ZIFENCEI), + __RISCV_ISA_EXT_DATA(zihintntl, RISCV_ISA_EXT_ZIHINTNTL), __RISCV_ISA_EXT_DATA(zihintpause, RISCV_ISA_EXT_ZIHINTPAUSE), __RISCV_ISA_EXT_DATA(zihpm, RISCV_ISA_EXT_ZIHPM), + __RISCV_ISA_EXT_DATA(zacas, RISCV_ISA_EXT_ZACAS), + __RISCV_ISA_EXT_DATA(zfa, RISCV_ISA_EXT_ZFA), + __RISCV_ISA_EXT_DATA(zfh, RISCV_ISA_EXT_ZFH), + __RISCV_ISA_EXT_DATA(zfhmin, RISCV_ISA_EXT_ZFHMIN), __RISCV_ISA_EXT_DATA(zba, RISCV_ISA_EXT_ZBA), __RISCV_ISA_EXT_DATA(zbb, RISCV_ISA_EXT_ZBB), + __RISCV_ISA_EXT_DATA(zbc, RISCV_ISA_EXT_ZBC), + __RISCV_ISA_EXT_DATA(zbkb, RISCV_ISA_EXT_ZBKB), + __RISCV_ISA_EXT_DATA(zbkc, RISCV_ISA_EXT_ZBKC), + __RISCV_ISA_EXT_DATA(zbkx, RISCV_ISA_EXT_ZBKX), __RISCV_ISA_EXT_DATA(zbs, RISCV_ISA_EXT_ZBS), + __RISCV_ISA_EXT_BUNDLE(zk, riscv_zk_bundled_exts), + __RISCV_ISA_EXT_BUNDLE(zkn, riscv_zkn_bundled_exts), + __RISCV_ISA_EXT_DATA(zknd, RISCV_ISA_EXT_ZKND), + __RISCV_ISA_EXT_DATA(zkne, RISCV_ISA_EXT_ZKNE), + __RISCV_ISA_EXT_DATA(zknh, RISCV_ISA_EXT_ZKNH), + __RISCV_ISA_EXT_DATA(zkr, RISCV_ISA_EXT_ZKR), + __RISCV_ISA_EXT_BUNDLE(zks, riscv_zks_bundled_exts), + __RISCV_ISA_EXT_DATA(zkt, RISCV_ISA_EXT_ZKT), + __RISCV_ISA_EXT_DATA(zksed, RISCV_ISA_EXT_ZKSED), + __RISCV_ISA_EXT_DATA(zksh, RISCV_ISA_EXT_ZKSH), + __RISCV_ISA_EXT_DATA(ztso, RISCV_ISA_EXT_ZTSO), + __RISCV_ISA_EXT_SUPERSET(zvbb, RISCV_ISA_EXT_ZVBB, riscv_zvbb_exts), + __RISCV_ISA_EXT_DATA(zvbc, RISCV_ISA_EXT_ZVBC), + __RISCV_ISA_EXT_DATA(zvfh, RISCV_ISA_EXT_ZVFH), + __RISCV_ISA_EXT_DATA(zvfhmin, RISCV_ISA_EXT_ZVFHMIN), + __RISCV_ISA_EXT_DATA(zvkb, RISCV_ISA_EXT_ZVKB), + __RISCV_ISA_EXT_DATA(zvkg, RISCV_ISA_EXT_ZVKG), + __RISCV_ISA_EXT_BUNDLE(zvkn, riscv_zvkn_bundled_exts), + __RISCV_ISA_EXT_BUNDLE(zvknc, riscv_zvknc_bundled_exts), + __RISCV_ISA_EXT_DATA(zvkned, RISCV_ISA_EXT_ZVKNED), + __RISCV_ISA_EXT_BUNDLE(zvkng, riscv_zvkng_bundled_exts), + __RISCV_ISA_EXT_DATA(zvknha, RISCV_ISA_EXT_ZVKNHA), + __RISCV_ISA_EXT_DATA(zvknhb, RISCV_ISA_EXT_ZVKNHB), + __RISCV_ISA_EXT_BUNDLE(zvks, riscv_zvks_bundled_exts), + __RISCV_ISA_EXT_BUNDLE(zvksc, riscv_zvksc_bundled_exts), + __RISCV_ISA_EXT_DATA(zvksed, RISCV_ISA_EXT_ZVKSED), + __RISCV_ISA_EXT_DATA(zvksh, RISCV_ISA_EXT_ZVKSH), + __RISCV_ISA_EXT_BUNDLE(zvksg, riscv_zvksg_bundled_exts), + __RISCV_ISA_EXT_DATA(zvkt, RISCV_ISA_EXT_ZVKT), __RISCV_ISA_EXT_DATA(smaia, RISCV_ISA_EXT_SMAIA), __RISCV_ISA_EXT_DATA(smstateen, RISCV_ISA_EXT_SMSTATEEN), __RISCV_ISA_EXT_DATA(ssaia, RISCV_ISA_EXT_SSAIA), @@ -189,6 +311,31 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = { const size_t riscv_isa_ext_count = ARRAY_SIZE(riscv_isa_ext); +static void __init match_isa_ext(const struct riscv_isa_ext_data *ext, const char *name, + const char *name_end, struct riscv_isainfo *isainfo) +{ + if ((name_end - name == strlen(ext->name)) && + !strncasecmp(name, ext->name, name_end - name)) { + /* + * If this is a bundle, enable all the ISA extensions that + * comprise the bundle. + */ + if (ext->subset_ext_size) { + for (int i = 0; i < ext->subset_ext_size; i++) { + if (riscv_isa_extension_check(ext->subset_ext_ids[i])) + set_bit(ext->subset_ext_ids[i], isainfo->isa); + } + } + + /* + * This is valid even for bundle extensions which uses the RISCV_ISA_EXT_INVALID id + * (rejected by riscv_isa_extension_check()). + */ + if (riscv_isa_extension_check(ext->id)) + set_bit(ext->id, isainfo->isa); + } +} + static void __init riscv_parse_isa_string(unsigned long *this_hwcap, struct riscv_isainfo *isainfo, unsigned long *isa2hwcap, const char *isa) { @@ -321,14 +468,6 @@ static void __init riscv_parse_isa_string(unsigned long *this_hwcap, struct risc if (*isa == '_') ++isa; -#define SET_ISA_EXT_MAP(name, bit) \ - do { \ - if ((ext_end - ext == strlen(name)) && \ - !strncasecmp(ext, name, strlen(name)) && \ - riscv_isa_extension_check(bit)) \ - set_bit(bit, isainfo->isa); \ - } while (false) \ - if (unlikely(ext_err)) continue; if (!ext_long) { @@ -340,10 +479,8 @@ static void __init riscv_parse_isa_string(unsigned long *this_hwcap, struct risc } } else { for (int i = 0; i < riscv_isa_ext_count; i++) - SET_ISA_EXT_MAP(riscv_isa_ext[i].name, - riscv_isa_ext[i].id); + match_isa_ext(&riscv_isa_ext[i], ext, ext_end, isainfo); } -#undef SET_ISA_EXT_MAP } } @@ -442,18 +579,26 @@ static int __init riscv_fill_hwcap_from_ext_list(unsigned long *isa2hwcap) } for (int i = 0; i < riscv_isa_ext_count; i++) { + const struct riscv_isa_ext_data *ext = &riscv_isa_ext[i]; + if (of_property_match_string(cpu_node, "riscv,isa-extensions", - riscv_isa_ext[i].property) < 0) + ext->property) < 0) continue; - if (!riscv_isa_extension_check(riscv_isa_ext[i].id)) - continue; + if (ext->subset_ext_size) { + for (int j = 0; j < ext->subset_ext_size; j++) { + if (riscv_isa_extension_check(ext->subset_ext_ids[i])) + set_bit(ext->subset_ext_ids[j], isainfo->isa); + } + } - /* Only single letter extensions get set in hwcap */ - if (strnlen(riscv_isa_ext[i].name, 2) == 1) - this_hwcap |= isa2hwcap[riscv_isa_ext[i].id]; + if (riscv_isa_extension_check(ext->id)) { + set_bit(ext->id, isainfo->isa); - set_bit(riscv_isa_ext[i].id, isainfo->isa); + /* Only single letter extensions get set in hwcap */ + if (strnlen(riscv_isa_ext[i].name, 2) == 1) + this_hwcap |= isa2hwcap[riscv_isa_ext[i].id]; + } } of_node_put(cpu_node); @@ -643,6 +788,16 @@ static int check_unaligned_access(void *param) (speed == RISCV_HWPROBE_MISALIGNED_FAST) ? "fast" : "slow"); per_cpu(misaligned_access_speed, cpu) = speed; + + /* + * Set the value of fast_misaligned_access of a CPU. These operations + * are atomic to avoid race conditions. + */ + if (speed == RISCV_HWPROBE_MISALIGNED_FAST) + cpumask_set_cpu(cpu, &fast_misaligned_access); + else + cpumask_clear_cpu(cpu, &fast_misaligned_access); + return 0; } @@ -655,13 +810,69 @@ static void check_unaligned_access_nonboot_cpu(void *param) check_unaligned_access(pages[cpu]); } +DEFINE_STATIC_KEY_FALSE(fast_misaligned_access_speed_key); + +static void modify_unaligned_access_branches(cpumask_t *mask, int weight) +{ + if (cpumask_weight(mask) == weight) + static_branch_enable_cpuslocked(&fast_misaligned_access_speed_key); + else + static_branch_disable_cpuslocked(&fast_misaligned_access_speed_key); +} + +static void set_unaligned_access_static_branches_except_cpu(int cpu) +{ + /* + * Same as set_unaligned_access_static_branches, except excludes the + * given CPU from the result. When a CPU is hotplugged into an offline + * state, this function is called before the CPU is set to offline in + * the cpumask, and thus the CPU needs to be explicitly excluded. + */ + + cpumask_t fast_except_me; + + cpumask_and(&fast_except_me, &fast_misaligned_access, cpu_online_mask); + cpumask_clear_cpu(cpu, &fast_except_me); + + modify_unaligned_access_branches(&fast_except_me, num_online_cpus() - 1); +} + +static void set_unaligned_access_static_branches(void) +{ + /* + * This will be called after check_unaligned_access_all_cpus so the + * result of unaligned access speed for all CPUs will be available. + * + * To avoid the number of online cpus changing between reading + * cpu_online_mask and calling num_online_cpus, cpus_read_lock must be + * held before calling this function. + */ + + cpumask_t fast_and_online; + + cpumask_and(&fast_and_online, &fast_misaligned_access, cpu_online_mask); + + modify_unaligned_access_branches(&fast_and_online, num_online_cpus()); +} + +static int lock_and_set_unaligned_access_static_branch(void) +{ + cpus_read_lock(); + set_unaligned_access_static_branches(); + cpus_read_unlock(); + + return 0; +} + +arch_initcall_sync(lock_and_set_unaligned_access_static_branch); + static int riscv_online_cpu(unsigned int cpu) { static struct page *buf; /* We are already set since the last check */ if (per_cpu(misaligned_access_speed, cpu) != RISCV_HWPROBE_MISALIGNED_UNKNOWN) - return 0; + goto exit; buf = alloc_pages(GFP_KERNEL, MISALIGNED_BUFFER_ORDER); if (!buf) { @@ -671,6 +882,17 @@ static int riscv_online_cpu(unsigned int cpu) check_unaligned_access(buf); __free_pages(buf, MISALIGNED_BUFFER_ORDER); + +exit: + set_unaligned_access_static_branches(); + + return 0; +} + +static int riscv_offline_cpu(unsigned int cpu) +{ + set_unaligned_access_static_branches_except_cpu(cpu); + return 0; } @@ -705,9 +927,12 @@ static int check_unaligned_access_all_cpus(void) /* Check core 0. */ smp_call_on_cpu(0, check_unaligned_access, bufs[0], true); - /* Setup hotplug callback for any new CPUs that come online. */ + /* + * Setup hotplug callbacks for any new CPUs that come online or go + * offline. + */ cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "riscv:online", - riscv_online_cpu, NULL); + riscv_online_cpu, riscv_offline_cpu); out: unaligned_emulation_finish(); diff --git a/arch/riscv/kernel/efi.c b/arch/riscv/kernel/efi.c index aa6209a74c83ff..b64bf1624a0529 100644 --- a/arch/riscv/kernel/efi.c +++ b/arch/riscv/kernel/efi.c @@ -60,7 +60,7 @@ int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md) static int __init set_permissions(pte_t *ptep, unsigned long addr, void *data) { efi_memory_desc_t *md = data; - pte_t pte = READ_ONCE(*ptep); + pte_t pte = ptep_get(ptep); unsigned long val; if (md->attribute & EFI_MEMORY_RO) { diff --git a/arch/riscv/kernel/elf_kexec.c b/arch/riscv/kernel/elf_kexec.c index e60fbd8660c4a5..5bd1ec3341fe9c 100644 --- a/arch/riscv/kernel/elf_kexec.c +++ b/arch/riscv/kernel/elf_kexec.c @@ -216,7 +216,6 @@ static void *elf_kexec_load(struct kimage *image, char *kernel_buf, if (ret) goto out; kernel_start = image->start; - pr_notice("The entry point of kernel at 0x%lx\n", image->start); /* Add the kernel binary to the image */ ret = riscv_kexec_elf_load(image, &ehdr, &elf_info, @@ -252,8 +251,8 @@ static void *elf_kexec_load(struct kimage *image, char *kernel_buf, image->elf_load_addr = kbuf.mem; image->elf_headers_sz = headers_sz; - pr_debug("Loaded elf core header at 0x%lx bufsz=0x%lx memsz=0x%lx\n", - image->elf_load_addr, kbuf.bufsz, kbuf.memsz); + kexec_dprintk("Loaded elf core header at 0x%lx bufsz=0x%lx memsz=0x%lx\n", + image->elf_load_addr, kbuf.bufsz, kbuf.memsz); /* Setup cmdline for kdump kernel case */ modified_cmdline = setup_kdump_cmdline(image, cmdline, @@ -275,6 +274,8 @@ static void *elf_kexec_load(struct kimage *image, char *kernel_buf, pr_err("Error loading purgatory ret=%d\n", ret); goto out; } + kexec_dprintk("Loaded purgatory at 0x%lx\n", kbuf.mem); + ret = kexec_purgatory_get_set_symbol(image, "riscv_kernel_entry", &kernel_start, sizeof(kernel_start), 0); @@ -293,7 +294,7 @@ static void *elf_kexec_load(struct kimage *image, char *kernel_buf, if (ret) goto out; initrd_pbase = kbuf.mem; - pr_notice("Loaded initrd at 0x%lx\n", initrd_pbase); + kexec_dprintk("Loaded initrd at 0x%lx\n", initrd_pbase); } /* Add the DTB to the image */ @@ -318,7 +319,7 @@ static void *elf_kexec_load(struct kimage *image, char *kernel_buf, } /* Cache the fdt buffer address for memory cleanup */ image->arch.fdt = fdt; - pr_notice("Loaded device tree at 0x%lx\n", kbuf.mem); + kexec_dprintk("Loaded device tree at 0x%lx\n", kbuf.mem); goto out; out_free_fdt: diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S index 54ca4564a92631..9d1a305d55087b 100644 --- a/arch/riscv/kernel/entry.S +++ b/arch/riscv/kernel/entry.S @@ -83,6 +83,10 @@ SYM_CODE_START(handle_exception) /* Load the kernel shadow call stack pointer if coming from userspace */ scs_load_current_if_task_changed s5 +#ifdef CONFIG_RISCV_ISA_V_PREEMPTIVE + move a0, sp + call riscv_v_context_nesting_start +#endif move a0, sp /* pt_regs */ la ra, ret_from_exception @@ -138,6 +142,10 @@ SYM_CODE_START_NOALIGN(ret_from_exception) */ csrw CSR_SCRATCH, tp 1: +#ifdef CONFIG_RISCV_ISA_V_PREEMPTIVE + move a0, sp + call riscv_v_context_nesting_end +#endif REG_L a0, PT_STATUS(sp) /* * The current load reservation is effectively part of the processor's diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c index 03a6434a8cdd00..f5aa24d9e1c150 100644 --- a/arch/riscv/kernel/ftrace.c +++ b/arch/riscv/kernel/ftrace.c @@ -178,32 +178,28 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, } #ifdef CONFIG_DYNAMIC_FTRACE +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS +void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, + struct ftrace_ops *op, struct ftrace_regs *fregs) +{ + struct pt_regs *regs = arch_ftrace_get_regs(fregs); + unsigned long *parent = (unsigned long *)®s->ra; + + prepare_ftrace_return(parent, ip, frame_pointer(regs)); +} +#else /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */ extern void ftrace_graph_call(void); -extern void ftrace_graph_regs_call(void); int ftrace_enable_ftrace_graph_caller(void) { - int ret; - - ret = __ftrace_modify_call((unsigned long)&ftrace_graph_call, - (unsigned long)&prepare_ftrace_return, true, true); - if (ret) - return ret; - - return __ftrace_modify_call((unsigned long)&ftrace_graph_regs_call, + return __ftrace_modify_call((unsigned long)&ftrace_graph_call, (unsigned long)&prepare_ftrace_return, true, true); } int ftrace_disable_ftrace_graph_caller(void) { - int ret; - - ret = __ftrace_modify_call((unsigned long)&ftrace_graph_call, - (unsigned long)&prepare_ftrace_return, false, true); - if (ret) - return ret; - - return __ftrace_modify_call((unsigned long)&ftrace_graph_regs_call, + return __ftrace_modify_call((unsigned long)&ftrace_graph_call, (unsigned long)&prepare_ftrace_return, false, true); } +#endif /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */ #endif /* CONFIG_DYNAMIC_FTRACE */ #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S index 76ace1e0b46f62..4236a69c35cb33 100644 --- a/arch/riscv/kernel/head.S +++ b/arch/riscv/kernel/head.S @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -89,6 +88,7 @@ relocate_enable_mmu: /* Compute satp for kernel page tables, but don't load it yet */ srl a2, a0, PAGE_SHIFT la a1, satp_mode + XIP_FIXUP_OFFSET a1 REG_L a1, 0(a1) or a2, a2, a1 @@ -265,10 +265,12 @@ SYM_CODE_START(_start_kernel) la sp, _end + THREAD_SIZE XIP_FIXUP_OFFSET sp mv s0, a0 + mv s1, a1 call __copy_data - /* Restore a0 copy */ + /* Restore a0 & a1 copy */ mv a0, s0 + mv a1, s1 #endif #ifndef CONFIG_XIP_KERNEL diff --git a/arch/riscv/kernel/kernel_mode_vector.c b/arch/riscv/kernel/kernel_mode_vector.c new file mode 100644 index 00000000000000..6afe80c7f03ab0 --- /dev/null +++ b/arch/riscv/kernel/kernel_mode_vector.c @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2012 ARM Ltd. + * Author: Catalin Marinas + * Copyright (C) 2017 Linaro Ltd. + * Copyright (C) 2021 SiFive + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#ifdef CONFIG_RISCV_ISA_V_PREEMPTIVE +#include +#endif + +static inline void riscv_v_flags_set(u32 flags) +{ + WRITE_ONCE(current->thread.riscv_v_flags, flags); +} + +static inline void riscv_v_start(u32 flags) +{ + int orig; + + orig = riscv_v_flags(); + BUG_ON((orig & flags) != 0); + riscv_v_flags_set(orig | flags); + barrier(); +} + +static inline void riscv_v_stop(u32 flags) +{ + int orig; + + barrier(); + orig = riscv_v_flags(); + BUG_ON((orig & flags) == 0); + riscv_v_flags_set(orig & ~flags); +} + +/* + * Claim ownership of the CPU vector context for use by the calling context. + * + * The caller may freely manipulate the vector context metadata until + * put_cpu_vector_context() is called. + */ +void get_cpu_vector_context(void) +{ + /* + * disable softirqs so it is impossible for softirqs to nest + * get_cpu_vector_context() when kernel is actively using Vector. + */ + if (!IS_ENABLED(CONFIG_PREEMPT_RT)) + local_bh_disable(); + else + preempt_disable(); + + riscv_v_start(RISCV_KERNEL_MODE_V); +} + +/* + * Release the CPU vector context. + * + * Must be called from a context in which get_cpu_vector_context() was + * previously called, with no call to put_cpu_vector_context() in the + * meantime. + */ +void put_cpu_vector_context(void) +{ + riscv_v_stop(RISCV_KERNEL_MODE_V); + + if (!IS_ENABLED(CONFIG_PREEMPT_RT)) + local_bh_enable(); + else + preempt_enable(); +} + +#ifdef CONFIG_RISCV_ISA_V_PREEMPTIVE +static __always_inline u32 *riscv_v_flags_ptr(void) +{ + return ¤t->thread.riscv_v_flags; +} + +static inline void riscv_preempt_v_set_dirty(void) +{ + *riscv_v_flags_ptr() |= RISCV_PREEMPT_V_DIRTY; +} + +static inline void riscv_preempt_v_reset_flags(void) +{ + *riscv_v_flags_ptr() &= ~(RISCV_PREEMPT_V_DIRTY | RISCV_PREEMPT_V_NEED_RESTORE); +} + +static inline void riscv_v_ctx_depth_inc(void) +{ + *riscv_v_flags_ptr() += RISCV_V_CTX_UNIT_DEPTH; +} + +static inline void riscv_v_ctx_depth_dec(void) +{ + *riscv_v_flags_ptr() -= RISCV_V_CTX_UNIT_DEPTH; +} + +static inline u32 riscv_v_ctx_get_depth(void) +{ + return *riscv_v_flags_ptr() & RISCV_V_CTX_DEPTH_MASK; +} + +static int riscv_v_stop_kernel_context(void) +{ + if (riscv_v_ctx_get_depth() != 0 || !riscv_preempt_v_started(current)) + return 1; + + riscv_preempt_v_clear_dirty(current); + riscv_v_stop(RISCV_PREEMPT_V); + return 0; +} + +static int riscv_v_start_kernel_context(bool *is_nested) +{ + struct __riscv_v_ext_state *kvstate, *uvstate; + + kvstate = ¤t->thread.kernel_vstate; + if (!kvstate->datap) + return -ENOENT; + + if (riscv_preempt_v_started(current)) { + WARN_ON(riscv_v_ctx_get_depth() == 0); + *is_nested = true; + get_cpu_vector_context(); + if (riscv_preempt_v_dirty(current)) { + __riscv_v_vstate_save(kvstate, kvstate->datap); + riscv_preempt_v_clear_dirty(current); + } + riscv_preempt_v_set_restore(current); + return 0; + } + + /* Transfer the ownership of V from user to kernel, then save */ + riscv_v_start(RISCV_PREEMPT_V | RISCV_PREEMPT_V_DIRTY); + if ((task_pt_regs(current)->status & SR_VS) == SR_VS_DIRTY) { + uvstate = ¤t->thread.vstate; + __riscv_v_vstate_save(uvstate, uvstate->datap); + } + riscv_preempt_v_clear_dirty(current); + return 0; +} + +/* low-level V context handling code, called with irq disabled */ +asmlinkage void riscv_v_context_nesting_start(struct pt_regs *regs) +{ + int depth; + + if (!riscv_preempt_v_started(current)) + return; + + depth = riscv_v_ctx_get_depth(); + if (depth == 0 && (regs->status & SR_VS) == SR_VS_DIRTY) + riscv_preempt_v_set_dirty(); + + riscv_v_ctx_depth_inc(); +} + +asmlinkage void riscv_v_context_nesting_end(struct pt_regs *regs) +{ + struct __riscv_v_ext_state *vstate = ¤t->thread.kernel_vstate; + u32 depth; + + WARN_ON(!irqs_disabled()); + + if (!riscv_preempt_v_started(current)) + return; + + riscv_v_ctx_depth_dec(); + depth = riscv_v_ctx_get_depth(); + if (depth == 0) { + if (riscv_preempt_v_restore(current)) { + __riscv_v_vstate_restore(vstate, vstate->datap); + __riscv_v_vstate_clean(regs); + riscv_preempt_v_reset_flags(); + } + } +} +#else +#define riscv_v_start_kernel_context(nested) (-ENOENT) +#define riscv_v_stop_kernel_context() (-ENOENT) +#endif /* CONFIG_RISCV_ISA_V_PREEMPTIVE */ + +/* + * kernel_vector_begin(): obtain the CPU vector registers for use by the calling + * context + * + * Must not be called unless may_use_simd() returns true. + * Task context in the vector registers is saved back to memory as necessary. + * + * A matching call to kernel_vector_end() must be made before returning from the + * calling context. + * + * The caller may freely use the vector registers until kernel_vector_end() is + * called. + */ +void kernel_vector_begin(void) +{ + bool nested = false; + + if (WARN_ON(!has_vector())) + return; + + BUG_ON(!may_use_simd()); + + if (riscv_v_start_kernel_context(&nested)) { + get_cpu_vector_context(); + riscv_v_vstate_save(¤t->thread.vstate, task_pt_regs(current)); + } + + if (!nested) + riscv_v_vstate_set_restore(current, task_pt_regs(current)); + + riscv_v_enable(); +} +EXPORT_SYMBOL_GPL(kernel_vector_begin); + +/* + * kernel_vector_end(): give the CPU vector registers back to the current task + * + * Must be called from a context in which kernel_vector_begin() was previously + * called, with no call to kernel_vector_end() in the meantime. + * + * The caller must not use the vector registers after this function is called, + * unless kernel_vector_begin() is called again in the meantime. + */ +void kernel_vector_end(void) +{ + if (WARN_ON(!has_vector())) + return; + + riscv_v_disable(); + + if (riscv_v_stop_kernel_context()) + put_cpu_vector_context(); +} +EXPORT_SYMBOL_GPL(kernel_vector_end); diff --git a/arch/riscv/kernel/machine_kexec.c b/arch/riscv/kernel/machine_kexec.c index 2d139b724bc842..ed9cad20c039d9 100644 --- a/arch/riscv/kernel/machine_kexec.c +++ b/arch/riscv/kernel/machine_kexec.c @@ -18,30 +18,6 @@ #include #include -/* - * kexec_image_info - Print received image details - */ -static void -kexec_image_info(const struct kimage *image) -{ - unsigned long i; - - pr_debug("Kexec image info:\n"); - pr_debug("\ttype: %d\n", image->type); - pr_debug("\tstart: %lx\n", image->start); - pr_debug("\thead: %lx\n", image->head); - pr_debug("\tnr_segments: %lu\n", image->nr_segments); - - for (i = 0; i < image->nr_segments; i++) { - pr_debug("\t segment[%lu]: %016lx - %016lx", i, - image->segment[i].mem, - image->segment[i].mem + image->segment[i].memsz); - pr_debug("\t\t0x%lx bytes, %lu pages\n", - (unsigned long) image->segment[i].memsz, - (unsigned long) image->segment[i].memsz / PAGE_SIZE); - } -} - /* * machine_kexec_prepare - Initialize kexec * @@ -60,8 +36,6 @@ machine_kexec_prepare(struct kimage *image) unsigned int control_code_buffer_sz = 0; int i = 0; - kexec_image_info(image); - /* Find the Flattened Device Tree and save its physical address */ for (i = 0; i < image->nr_segments; i++) { if (image->segment[i].memsz <= sizeof(fdt)) diff --git a/arch/riscv/kernel/mcount-dyn.S b/arch/riscv/kernel/mcount-dyn.S index 58dd96a2a15340..b7561288e8da61 100644 --- a/arch/riscv/kernel/mcount-dyn.S +++ b/arch/riscv/kernel/mcount-dyn.S @@ -3,12 +3,12 @@ #include #include +#include #include #include #include #include #include -#include #include .text @@ -57,31 +57,150 @@ .endm #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS - .macro SAVE_ALL + +/** +* SAVE_ABI_REGS - save regs against the pt_regs struct +* +* @all: tell if saving all the regs +* +* If all is set, all the regs will be saved, otherwise only ABI +* related regs (a0-a7,epc,ra and optional s0) will be saved. +* +* After the stack is established, +* +* 0(sp) stores the PC of the traced function which can be accessed +* by &(fregs)->regs->epc in tracing function. Note that the real +* function entry address should be computed with -FENTRY_RA_OFFSET. +* +* 8(sp) stores the function return address (i.e. parent IP) that +* can be accessed by &(fregs)->regs->ra in tracing function. +* +* The other regs are saved at the respective localtion and accessed +* by the respective pt_regs member. +* +* Here is the layout of stack for your reference. +* +* PT_SIZE_ON_STACK -> +++++++++ +* + ..... + +* + t3-t6 + +* + s2-s11+ +* + a0-a7 + --++++-> ftrace_caller saved +* + s1 + + +* + s0 + --+ +* + t0-t2 + + +* + tp + + +* + gp + + +* + sp + + +* + ra + --+ // parent IP +* sp -> + epc + --+ // PC +* +++++++++ +**/ + .macro SAVE_ABI_REGS, all=0 addi sp, sp, -PT_SIZE_ON_STACK - REG_S t0, PT_EPC(sp) - REG_S x1, PT_RA(sp) - REG_S x2, PT_SP(sp) - REG_S x3, PT_GP(sp) - REG_S x4, PT_TP(sp) - REG_S x5, PT_T0(sp) - save_from_x6_to_x31 + REG_S t0, PT_EPC(sp) + REG_S x1, PT_RA(sp) + + // save the ABI regs + + REG_S x10, PT_A0(sp) + REG_S x11, PT_A1(sp) + REG_S x12, PT_A2(sp) + REG_S x13, PT_A3(sp) + REG_S x14, PT_A4(sp) + REG_S x15, PT_A5(sp) + REG_S x16, PT_A6(sp) + REG_S x17, PT_A7(sp) + + // save the leftover regs + + .if \all == 1 + REG_S x2, PT_SP(sp) + REG_S x3, PT_GP(sp) + REG_S x4, PT_TP(sp) + REG_S x5, PT_T0(sp) + REG_S x6, PT_T1(sp) + REG_S x7, PT_T2(sp) + REG_S x8, PT_S0(sp) + REG_S x9, PT_S1(sp) + REG_S x18, PT_S2(sp) + REG_S x19, PT_S3(sp) + REG_S x20, PT_S4(sp) + REG_S x21, PT_S5(sp) + REG_S x22, PT_S6(sp) + REG_S x23, PT_S7(sp) + REG_S x24, PT_S8(sp) + REG_S x25, PT_S9(sp) + REG_S x26, PT_S10(sp) + REG_S x27, PT_S11(sp) + REG_S x28, PT_T3(sp) + REG_S x29, PT_T4(sp) + REG_S x30, PT_T5(sp) + REG_S x31, PT_T6(sp) + + // save s0 if FP_TEST defined + + .else +#ifdef HAVE_FUNCTION_GRAPH_FP_TEST + REG_S x8, PT_S0(sp) +#endif + .endif .endm - .macro RESTORE_ALL - REG_L x1, PT_RA(sp) - REG_L x2, PT_SP(sp) - REG_L x3, PT_GP(sp) - REG_L x4, PT_TP(sp) - /* Restore t0 with PT_EPC */ - REG_L x5, PT_EPC(sp) - restore_from_x6_to_x31 + .macro RESTORE_ABI_REGS, all=0 + REG_L t0, PT_EPC(sp) + REG_L x1, PT_RA(sp) + REG_L x10, PT_A0(sp) + REG_L x11, PT_A1(sp) + REG_L x12, PT_A2(sp) + REG_L x13, PT_A3(sp) + REG_L x14, PT_A4(sp) + REG_L x15, PT_A5(sp) + REG_L x16, PT_A6(sp) + REG_L x17, PT_A7(sp) + .if \all == 1 + REG_L x2, PT_SP(sp) + REG_L x3, PT_GP(sp) + REG_L x4, PT_TP(sp) + REG_L x6, PT_T1(sp) + REG_L x7, PT_T2(sp) + REG_L x8, PT_S0(sp) + REG_L x9, PT_S1(sp) + REG_L x18, PT_S2(sp) + REG_L x19, PT_S3(sp) + REG_L x20, PT_S4(sp) + REG_L x21, PT_S5(sp) + REG_L x22, PT_S6(sp) + REG_L x23, PT_S7(sp) + REG_L x24, PT_S8(sp) + REG_L x25, PT_S9(sp) + REG_L x26, PT_S10(sp) + REG_L x27, PT_S11(sp) + REG_L x28, PT_T3(sp) + REG_L x29, PT_T4(sp) + REG_L x30, PT_T5(sp) + REG_L x31, PT_T6(sp) + + .else +#ifdef HAVE_FUNCTION_GRAPH_FP_TEST + REG_L x8, PT_S0(sp) +#endif + .endif addi sp, sp, PT_SIZE_ON_STACK .endm + + .macro PREPARE_ARGS + addi a0, t0, -FENTRY_RA_OFFSET + la a1, function_trace_op + REG_L a2, 0(a1) + mv a1, ra + mv a3, sp + .endm + #endif /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */ +#ifndef CONFIG_DYNAMIC_FTRACE_WITH_REGS SYM_FUNC_START(ftrace_caller) SAVE_ABI @@ -105,34 +224,39 @@ SYM_INNER_LABEL(ftrace_graph_call, SYM_L_GLOBAL) call ftrace_stub #endif RESTORE_ABI - jr t0 + jr t0 SYM_FUNC_END(ftrace_caller) -#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS +#else /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */ SYM_FUNC_START(ftrace_regs_caller) - SAVE_ALL - - addi a0, t0, -FENTRY_RA_OFFSET - la a1, function_trace_op - REG_L a2, 0(a1) - mv a1, ra - mv a3, sp + mv t1, zero + SAVE_ABI_REGS 1 + PREPARE_ARGS SYM_INNER_LABEL(ftrace_regs_call, SYM_L_GLOBAL) call ftrace_stub -#ifdef CONFIG_FUNCTION_GRAPH_TRACER - addi a0, sp, PT_RA - REG_L a1, PT_EPC(sp) - addi a1, a1, -FENTRY_RA_OFFSET -#ifdef HAVE_FUNCTION_GRAPH_FP_TEST - mv a2, s0 -#endif -SYM_INNER_LABEL(ftrace_graph_regs_call, SYM_L_GLOBAL) + RESTORE_ABI_REGS 1 + bnez t1, .Ldirect + jr t0 +.Ldirect: + jr t1 +SYM_FUNC_END(ftrace_regs_caller) + +SYM_FUNC_START(ftrace_caller) + SAVE_ABI_REGS 0 + PREPARE_ARGS + +SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL) call ftrace_stub -#endif - RESTORE_ALL - jr t0 -SYM_FUNC_END(ftrace_regs_caller) + RESTORE_ABI_REGS 0 + jr t0 +SYM_FUNC_END(ftrace_caller) #endif /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */ + +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS +SYM_CODE_START(ftrace_stub_direct_tramp) + jr t0 +SYM_CODE_END(ftrace_stub_direct_tramp) +#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */ diff --git a/arch/riscv/kernel/mcount.S b/arch/riscv/kernel/mcount.S index b4dd9ed6849e30..d7ec69ac6910c6 100644 --- a/arch/riscv/kernel/mcount.S +++ b/arch/riscv/kernel/mcount.S @@ -4,12 +4,12 @@ #include #include #include +#include #include #include #include #include #include -#include #include .text diff --git a/arch/riscv/kernel/module.c b/arch/riscv/kernel/module.c index aac019ed63b1bd..5e5a82644451e1 100644 --- a/arch/riscv/kernel/module.c +++ b/arch/riscv/kernel/module.c @@ -723,8 +723,8 @@ static int add_relocation_to_accumulate(struct module *me, int type, if (!bucket) { kfree(entry); - kfree(rel_head); kfree(rel_head->rel_entry); + kfree(rel_head); return -ENOMEM; } @@ -747,6 +747,10 @@ initialize_relocation_hashtable(unsigned int num_relocations, { /* Can safely assume that bits is not greater than sizeof(long) */ unsigned long hashtable_size = roundup_pow_of_two(num_relocations); + /* + * When hashtable_size == 1, hashtable_bits == 0. + * This is valid because the hashing algorithm returns 0 in this case. + */ unsigned int hashtable_bits = ilog2(hashtable_size); /* @@ -760,10 +764,10 @@ initialize_relocation_hashtable(unsigned int num_relocations, hashtable_size <<= should_double_size; *relocation_hashtable = kmalloc_array(hashtable_size, - sizeof(*relocation_hashtable), + sizeof(**relocation_hashtable), GFP_KERNEL); if (!*relocation_hashtable) - return -ENOMEM; + return 0; __hash_init(*relocation_hashtable, hashtable_size); @@ -779,6 +783,7 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, Elf_Sym *sym; void *location; unsigned int i, type; + unsigned int j_idx = 0; Elf_Addr v; int res; unsigned int num_relocations = sechdrs[relsec].sh_size / sizeof(*rel); @@ -789,8 +794,8 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, hashtable_bits = initialize_relocation_hashtable(num_relocations, &relocation_hashtable); - if (hashtable_bits < 0) - return hashtable_bits; + if (!relocation_hashtable) + return -ENOMEM; INIT_LIST_HEAD(&used_buckets_list); @@ -829,9 +834,10 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, v = sym->st_value + rel[i].r_addend; if (type == R_RISCV_PCREL_LO12_I || type == R_RISCV_PCREL_LO12_S) { - unsigned int j; + unsigned int j = j_idx; + bool found = false; - for (j = 0; j < sechdrs[relsec].sh_size / sizeof(*rel); j++) { + do { unsigned long hi20_loc = sechdrs[sechdrs[relsec].sh_info].sh_addr + rel[j].r_offset; @@ -860,16 +866,26 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, hi20 = (offset + 0x800) & 0xfffff000; lo12 = offset - hi20; v = lo12; + found = true; break; } - } - if (j == sechdrs[relsec].sh_size / sizeof(*rel)) { + + j++; + if (j > sechdrs[relsec].sh_size / sizeof(*rel)) + j = 0; + + } while (j_idx != j); + + if (!found) { pr_err( "%s: Can not find HI20 relocation information\n", me->name); return -EINVAL; } + + /* Record the previous j-loop end index */ + j_idx = j; } if (reloc_handlers[type].accumulate_handler) @@ -894,7 +910,8 @@ void *module_alloc(unsigned long size) { return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, GFP_KERNEL, - PAGE_KERNEL, 0, NUMA_NO_NODE, + PAGE_KERNEL, VM_FLUSH_RESET_PERMS, + NUMA_NO_NODE, __builtin_return_address(0)); } #endif diff --git a/arch/riscv/kernel/paravirt.c b/arch/riscv/kernel/paravirt.c new file mode 100644 index 00000000000000..8e114f5930cec6 --- /dev/null +++ b/arch/riscv/kernel/paravirt.c @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 Ventana Micro Systems Inc. + */ + +#define pr_fmt(fmt) "riscv-pv: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +struct static_key paravirt_steal_enabled; +struct static_key paravirt_steal_rq_enabled; + +static u64 native_steal_clock(int cpu) +{ + return 0; +} + +DEFINE_STATIC_CALL(pv_steal_clock, native_steal_clock); + +static bool steal_acc = true; +static int __init parse_no_stealacc(char *arg) +{ + steal_acc = false; + return 0; +} + +early_param("no-steal-acc", parse_no_stealacc); + +DEFINE_PER_CPU(struct sbi_sta_struct, steal_time) __aligned(64); + +static bool __init has_pv_steal_clock(void) +{ + if (sbi_spec_version >= sbi_mk_version(2, 0) && + sbi_probe_extension(SBI_EXT_STA) > 0) { + pr_info("SBI STA extension detected\n"); + return true; + } + + return false; +} + +static int sbi_sta_steal_time_set_shmem(unsigned long lo, unsigned long hi, + unsigned long flags) +{ + struct sbiret ret; + + ret = sbi_ecall(SBI_EXT_STA, SBI_EXT_STA_STEAL_TIME_SET_SHMEM, + lo, hi, flags, 0, 0, 0); + if (ret.error) { + if (lo == SBI_STA_SHMEM_DISABLE && hi == SBI_STA_SHMEM_DISABLE) + pr_warn("Failed to disable steal-time shmem"); + else + pr_warn("Failed to set steal-time shmem"); + return sbi_err_map_linux_errno(ret.error); + } + + return 0; +} + +static int pv_time_cpu_online(unsigned int cpu) +{ + struct sbi_sta_struct *st = this_cpu_ptr(&steal_time); + phys_addr_t pa = __pa(st); + unsigned long lo = (unsigned long)pa; + unsigned long hi = IS_ENABLED(CONFIG_32BIT) ? upper_32_bits((u64)pa) : 0; + + return sbi_sta_steal_time_set_shmem(lo, hi, 0); +} + +static int pv_time_cpu_down_prepare(unsigned int cpu) +{ + return sbi_sta_steal_time_set_shmem(SBI_STA_SHMEM_DISABLE, + SBI_STA_SHMEM_DISABLE, 0); +} + +static u64 pv_time_steal_clock(int cpu) +{ + struct sbi_sta_struct *st = per_cpu_ptr(&steal_time, cpu); + u32 sequence; + u64 steal; + + /* + * Check the sequence field before and after reading the steal + * field. Repeat the read if it is different or odd. + */ + do { + sequence = READ_ONCE(st->sequence); + virt_rmb(); + steal = READ_ONCE(st->steal); + virt_rmb(); + } while ((le32_to_cpu(sequence) & 1) || + sequence != READ_ONCE(st->sequence)); + + return le64_to_cpu(steal); +} + +int __init pv_time_init(void) +{ + int ret; + + if (!has_pv_steal_clock()) + return 0; + + ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, + "riscv/pv_time:online", + pv_time_cpu_online, + pv_time_cpu_down_prepare); + if (ret < 0) + return ret; + + static_call_update(pv_steal_clock, pv_time_steal_clock); + + static_key_slow_inc(¶virt_steal_enabled); + if (steal_acc) + static_key_slow_inc(¶virt_steal_rq_enabled); + + pr_info("Computing paravirt steal-time\n"); + + return 0; +} diff --git a/arch/riscv/kernel/patch.c b/arch/riscv/kernel/patch.c index 13ee7bf589a15e..37e87fdcf6a000 100644 --- a/arch/riscv/kernel/patch.c +++ b/arch/riscv/kernel/patch.c @@ -14,6 +14,7 @@ #include #include #include +#include struct patch_insn { void *addr; @@ -25,6 +26,14 @@ struct patch_insn { int riscv_patch_in_stop_machine = false; #ifdef CONFIG_MMU + +static inline bool is_kernel_exittext(uintptr_t addr) +{ + return system_state < SYSTEM_RUNNING && + addr >= (uintptr_t)__exittext_begin && + addr < (uintptr_t)__exittext_end; +} + /* * The fix_to_virt(, idx) needs a const value (not a dynamic variable of * reg-a0) or BUILD_BUG_ON failed with "idx >= __end_of_fixed_addresses". @@ -35,7 +44,7 @@ static __always_inline void *patch_map(void *addr, const unsigned int fixmap) uintptr_t uintaddr = (uintptr_t) addr; struct page *page; - if (core_kernel_text(uintaddr)) + if (core_kernel_text(uintaddr) || is_kernel_exittext(uintaddr)) page = phys_to_page(__pa_symbol(addr)); else if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX)) page = vmalloc_to_page(addr); diff --git a/arch/riscv/kernel/pi/cmdline_early.c b/arch/riscv/kernel/pi/cmdline_early.c index 68e786c84c949b..f6d4dedffb8422 100644 --- a/arch/riscv/kernel/pi/cmdline_early.c +++ b/arch/riscv/kernel/pi/cmdline_early.c @@ -38,8 +38,7 @@ static char *get_early_cmdline(uintptr_t dtb_pa) if (IS_ENABLED(CONFIG_CMDLINE_EXTEND) || IS_ENABLED(CONFIG_CMDLINE_FORCE) || fdt_cmdline_size == 0 /* CONFIG_CMDLINE_FALLBACK */) { - strncat(early_cmdline, CONFIG_CMDLINE, - COMMAND_LINE_SIZE - fdt_cmdline_size); + strlcat(early_cmdline, CONFIG_CMDLINE, COMMAND_LINE_SIZE); } return early_cmdline; diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c index 4f21d970a1292b..92922dbd5b5c1f 100644 --- a/arch/riscv/kernel/process.c +++ b/arch/riscv/kernel/process.c @@ -171,6 +171,7 @@ void flush_thread(void) riscv_v_vstate_off(task_pt_regs(current)); kfree(current->thread.vstate.datap); memset(¤t->thread.vstate, 0, sizeof(struct __riscv_v_ext_state)); + clear_tsk_thread_flag(current, TIF_RISCV_V_DEFER_RESTORE); #endif } @@ -178,7 +179,7 @@ void arch_release_task_struct(struct task_struct *tsk) { /* Free the vector context of datap. */ if (has_vector()) - kfree(tsk->thread.vstate.datap); + riscv_v_thread_free(tsk); } int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) @@ -187,6 +188,8 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) *dst = *src; /* clear entire V context, including datap for a new task */ memset(&dst->thread.vstate, 0, sizeof(struct __riscv_v_ext_state)); + memset(&dst->thread.kernel_vstate, 0, sizeof(struct __riscv_v_ext_state)); + clear_tsk_thread_flag(dst, TIF_RISCV_V_DEFER_RESTORE); return 0; } @@ -221,7 +224,15 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) childregs->a0 = 0; /* Return value of fork() */ p->thread.s[0] = 0; } + p->thread.riscv_v_flags = 0; + if (has_vector()) + riscv_v_thread_alloc(p); p->thread.ra = (unsigned long)ret_from_fork; p->thread.sp = (unsigned long)childregs; /* kernel sp */ return 0; } + +void __init arch_task_cache_init(void) +{ + riscv_v_setup_ctx_cache(); +} diff --git a/arch/riscv/kernel/ptrace.c b/arch/riscv/kernel/ptrace.c index 2afe460de16a62..e8515aa9d80bf8 100644 --- a/arch/riscv/kernel/ptrace.c +++ b/arch/riscv/kernel/ptrace.c @@ -99,8 +99,11 @@ static int riscv_vr_get(struct task_struct *target, * Ensure the vector registers have been saved to the memory before * copying them to membuf. */ - if (target == current) - riscv_v_vstate_save(current, task_pt_regs(current)); + if (target == current) { + get_cpu_vector_context(); + riscv_v_vstate_save(¤t->thread.vstate, task_pt_regs(current)); + put_cpu_vector_context(); + } ptrace_vstate.vstart = vstate->vstart; ptrace_vstate.vl = vstate->vl; diff --git a/arch/riscv/kernel/sbi.c b/arch/riscv/kernel/sbi.c index 5a62ed1da45332..e66e0999a80057 100644 --- a/arch/riscv/kernel/sbi.c +++ b/arch/riscv/kernel/sbi.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -571,6 +572,66 @@ long sbi_get_mimpid(void) } EXPORT_SYMBOL_GPL(sbi_get_mimpid); +bool sbi_debug_console_available; + +int sbi_debug_console_write(const char *bytes, unsigned int num_bytes) +{ + phys_addr_t base_addr; + struct sbiret ret; + + if (!sbi_debug_console_available) + return -EOPNOTSUPP; + + if (is_vmalloc_addr(bytes)) + base_addr = page_to_phys(vmalloc_to_page(bytes)) + + offset_in_page(bytes); + else + base_addr = __pa(bytes); + if (PAGE_SIZE < (offset_in_page(bytes) + num_bytes)) + num_bytes = PAGE_SIZE - offset_in_page(bytes); + + if (IS_ENABLED(CONFIG_32BIT)) + ret = sbi_ecall(SBI_EXT_DBCN, SBI_EXT_DBCN_CONSOLE_WRITE, + num_bytes, lower_32_bits(base_addr), + upper_32_bits(base_addr), 0, 0, 0); + else + ret = sbi_ecall(SBI_EXT_DBCN, SBI_EXT_DBCN_CONSOLE_WRITE, + num_bytes, base_addr, 0, 0, 0, 0); + + if (ret.error == SBI_ERR_FAILURE) + return -EIO; + return ret.error ? sbi_err_map_linux_errno(ret.error) : ret.value; +} + +int sbi_debug_console_read(char *bytes, unsigned int num_bytes) +{ + phys_addr_t base_addr; + struct sbiret ret; + + if (!sbi_debug_console_available) + return -EOPNOTSUPP; + + if (is_vmalloc_addr(bytes)) + base_addr = page_to_phys(vmalloc_to_page(bytes)) + + offset_in_page(bytes); + else + base_addr = __pa(bytes); + if (PAGE_SIZE < (offset_in_page(bytes) + num_bytes)) + num_bytes = PAGE_SIZE - offset_in_page(bytes); + + if (IS_ENABLED(CONFIG_32BIT)) + ret = sbi_ecall(SBI_EXT_DBCN, SBI_EXT_DBCN_CONSOLE_READ, + num_bytes, lower_32_bits(base_addr), + upper_32_bits(base_addr), 0, 0, 0); + else + ret = sbi_ecall(SBI_EXT_DBCN, SBI_EXT_DBCN_CONSOLE_READ, + num_bytes, base_addr, 0, 0, 0, 0); + + if (ret.error == SBI_ERR_FAILURE) + return -EIO; + return ret.error ? sbi_err_map_linux_errno(ret.error) : ret.value; +} + void __init sbi_init(void) { int ret; @@ -612,6 +673,11 @@ void __init sbi_init(void) sbi_srst_reboot_nb.priority = 192; register_restart_handler(&sbi_srst_reboot_nb); } + if ((sbi_spec_version >= sbi_mk_version(2, 0)) && + (sbi_probe_extension(SBI_EXT_DBCN) > 0)) { + pr_info("SBI DBCN extension detected\n"); + sbi_debug_console_available = true; + } } else { __sbi_set_timer = __sbi_set_timer_v01; __sbi_send_ipi = __sbi_send_ipi_v01; diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c index 535a837de55d1b..4f73c0ae44b25d 100644 --- a/arch/riscv/kernel/setup.c +++ b/arch/riscv/kernel/setup.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -51,7 +50,6 @@ atomic_t hart_lottery __section(".sdata") #endif ; unsigned long boot_cpu_hartid; -static DEFINE_PER_CPU(struct cpu, cpu_devices); /* * Place kernel memory regions on the resource tree so that @@ -299,23 +297,10 @@ void __init setup_arch(char **cmdline_p) riscv_user_isa_enable(); } -static int __init topology_init(void) +bool arch_cpu_is_hotpluggable(int cpu) { - int i, ret; - - for_each_possible_cpu(i) { - struct cpu *cpu = &per_cpu(cpu_devices, i); - - cpu->hotpluggable = cpu_has_hotplug(i); - ret = register_cpu(cpu, i); - if (unlikely(ret)) - pr_warn("Warning: %s: register_cpu %d failed (%d)\n", - __func__, i, ret); - } - - return 0; + return cpu_has_hotplug(cpu); } -subsys_initcall(topology_init); void free_initmem(void) { diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c index 88b6220b260879..501e66debf6972 100644 --- a/arch/riscv/kernel/signal.c +++ b/arch/riscv/kernel/signal.c @@ -86,12 +86,15 @@ static long save_v_state(struct pt_regs *regs, void __user **sc_vec) /* datap is designed to be 16 byte aligned for better performance */ WARN_ON(unlikely(!IS_ALIGNED((unsigned long)datap, 16))); - riscv_v_vstate_save(current, regs); + get_cpu_vector_context(); + riscv_v_vstate_save(¤t->thread.vstate, regs); + put_cpu_vector_context(); + /* Copy everything of vstate but datap. */ err = __copy_to_user(&state->v_state, ¤t->thread.vstate, offsetof(struct __riscv_v_ext_state, datap)); /* Copy the pointer datap itself. */ - err |= __put_user(datap, &state->v_state.datap); + err |= __put_user((__force void *)datap, &state->v_state.datap); /* Copy the whole vector content to user space datap. */ err |= __copy_to_user(datap, current->thread.vstate.datap, riscv_v_vsize); /* Copy magic to the user space after saving all vector conetext */ @@ -134,7 +137,7 @@ static long __restore_v_state(struct pt_regs *regs, void __user *sc_vec) if (unlikely(err)) return err; - riscv_v_vstate_restore(current, regs); + riscv_v_vstate_set_restore(current, regs); return err; } diff --git a/arch/riscv/kernel/smp.c b/arch/riscv/kernel/smp.c index 40420afbb1a09f..45dd4035416efd 100644 --- a/arch/riscv/kernel/smp.c +++ b/arch/riscv/kernel/smp.c @@ -81,7 +81,7 @@ static inline void ipi_cpu_crash_stop(unsigned int cpu, struct pt_regs *regs) #ifdef CONFIG_HOTPLUG_CPU if (cpu_has_hotplug(cpu)) - cpu_ops[cpu]->cpu_stop(); + cpu_ops->cpu_stop(); #endif for(;;) diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c index d162bf339beb16..519b6bd946e5d1 100644 --- a/arch/riscv/kernel/smpboot.c +++ b/arch/riscv/kernel/smpboot.c @@ -49,7 +49,6 @@ void __init smp_prepare_boot_cpu(void) void __init smp_prepare_cpus(unsigned int max_cpus) { int cpuid; - int ret; unsigned int curr_cpuid; init_cpu_topology(); @@ -66,11 +65,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus) for_each_possible_cpu(cpuid) { if (cpuid == curr_cpuid) continue; - if (cpu_ops[cpuid]->cpu_prepare) { - ret = cpu_ops[cpuid]->cpu_prepare(cpuid); - if (ret) - continue; - } set_cpu_present(cpuid, true); numa_store_cpu_info(cpuid); } @@ -125,18 +119,7 @@ static int __init acpi_parse_rintc(union acpi_subtable_headers *header, const un static void __init acpi_parse_and_init_cpus(void) { - int cpuid; - - cpu_set_ops(0); - acpi_table_parse_madt(ACPI_MADT_TYPE_RINTC, acpi_parse_rintc, 0); - - for (cpuid = 1; cpuid < nr_cpu_ids; cpuid++) { - if (cpuid_to_hartid_map(cpuid) != INVALID_HARTID) { - cpu_set_ops(cpuid); - set_cpu_possible(cpuid, true); - } - } } #else #define acpi_parse_and_init_cpus(...) do { } while (0) @@ -150,8 +133,6 @@ static void __init of_parse_and_init_cpus(void) int cpuid = 1; int rc; - cpu_set_ops(0); - for_each_of_cpu_node(dn) { rc = riscv_early_of_processor_hartid(dn, &hart); if (rc < 0) @@ -179,27 +160,28 @@ static void __init of_parse_and_init_cpus(void) if (cpuid > nr_cpu_ids) pr_warn("Total number of cpus [%d] is greater than nr_cpus option value [%d]\n", cpuid, nr_cpu_ids); - - for (cpuid = 1; cpuid < nr_cpu_ids; cpuid++) { - if (cpuid_to_hartid_map(cpuid) != INVALID_HARTID) { - cpu_set_ops(cpuid); - set_cpu_possible(cpuid, true); - } - } } void __init setup_smp(void) { + int cpuid; + + cpu_set_ops(); + if (acpi_disabled) of_parse_and_init_cpus(); else acpi_parse_and_init_cpus(); + + for (cpuid = 1; cpuid < nr_cpu_ids; cpuid++) + if (cpuid_to_hartid_map(cpuid) != INVALID_HARTID) + set_cpu_possible(cpuid, true); } static int start_secondary_cpu(int cpu, struct task_struct *tidle) { - if (cpu_ops[cpu]->cpu_start) - return cpu_ops[cpu]->cpu_start(cpu, tidle); + if (cpu_ops->cpu_start) + return cpu_ops->cpu_start(cpu, tidle); return -EOPNOTSUPP; } diff --git a/arch/riscv/kernel/suspend.c b/arch/riscv/kernel/suspend.c index 3c89b8ec69c49c..239509367e4233 100644 --- a/arch/riscv/kernel/suspend.c +++ b/arch/riscv/kernel/suspend.c @@ -4,8 +4,12 @@ * Copyright (c) 2022 Ventana Micro Systems Inc. */ +#define pr_fmt(fmt) "suspend: " fmt + #include +#include #include +#include #include void suspend_save_csrs(struct suspend_context *context) @@ -85,3 +89,43 @@ int cpu_suspend(unsigned long arg, return rc; } + +#ifdef CONFIG_RISCV_SBI +static int sbi_system_suspend(unsigned long sleep_type, + unsigned long resume_addr, + unsigned long opaque) +{ + struct sbiret ret; + + ret = sbi_ecall(SBI_EXT_SUSP, SBI_EXT_SUSP_SYSTEM_SUSPEND, + sleep_type, resume_addr, opaque, 0, 0, 0); + if (ret.error) + return sbi_err_map_linux_errno(ret.error); + + return ret.value; +} + +static int sbi_system_suspend_enter(suspend_state_t state) +{ + return cpu_suspend(SBI_SUSP_SLEEP_TYPE_SUSPEND_TO_RAM, sbi_system_suspend); +} + +static const struct platform_suspend_ops sbi_system_suspend_ops = { + .valid = suspend_valid_only_mem, + .enter = sbi_system_suspend_enter, +}; + +static int __init sbi_system_suspend_init(void) +{ + if (sbi_spec_version >= sbi_mk_version(2, 0) && + sbi_probe_extension(SBI_EXT_SUSP) > 0) { + pr_info("SBI SUSP extension detected\n"); + if (IS_ENABLED(CONFIG_SUSPEND)) + suspend_set_ops(&sbi_system_suspend_ops); + } + + return 0; +} + +arch_initcall(sbi_system_suspend_init); +#endif /* CONFIG_RISCV_SBI */ diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c new file mode 100644 index 00000000000000..a7c56b41efd24d --- /dev/null +++ b/arch/riscv/kernel/sys_hwprobe.c @@ -0,0 +1,411 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * The hwprobe interface, for allowing userspace to probe to see which features + * are supported by the hardware. See Documentation/arch/riscv/hwprobe.rst for + * more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static void hwprobe_arch_id(struct riscv_hwprobe *pair, + const struct cpumask *cpus) +{ + u64 id = -1ULL; + bool first = true; + int cpu; + + for_each_cpu(cpu, cpus) { + u64 cpu_id; + + switch (pair->key) { + case RISCV_HWPROBE_KEY_MVENDORID: + cpu_id = riscv_cached_mvendorid(cpu); + break; + case RISCV_HWPROBE_KEY_MIMPID: + cpu_id = riscv_cached_mimpid(cpu); + break; + case RISCV_HWPROBE_KEY_MARCHID: + cpu_id = riscv_cached_marchid(cpu); + break; + } + + if (first) { + id = cpu_id; + first = false; + } + + /* + * If there's a mismatch for the given set, return -1 in the + * value. + */ + if (id != cpu_id) { + id = -1ULL; + break; + } + } + + pair->value = id; +} + +static void hwprobe_isa_ext0(struct riscv_hwprobe *pair, + const struct cpumask *cpus) +{ + int cpu; + u64 missing = 0; + + pair->value = 0; + if (has_fpu()) + pair->value |= RISCV_HWPROBE_IMA_FD; + + if (riscv_isa_extension_available(NULL, c)) + pair->value |= RISCV_HWPROBE_IMA_C; + + if (has_vector()) + pair->value |= RISCV_HWPROBE_IMA_V; + + /* + * Loop through and record extensions that 1) anyone has, and 2) anyone + * doesn't have. + */ + for_each_cpu(cpu, cpus) { + struct riscv_isainfo *isainfo = &hart_isa[cpu]; + +#define EXT_KEY(ext) \ + do { \ + if (__riscv_isa_extension_available(isainfo->isa, RISCV_ISA_EXT_##ext)) \ + pair->value |= RISCV_HWPROBE_EXT_##ext; \ + else \ + missing |= RISCV_HWPROBE_EXT_##ext; \ + } while (false) + + /* + * Only use EXT_KEY() for extensions which can be exposed to userspace, + * regardless of the kernel's configuration, as no other checks, besides + * presence in the hart_isa bitmap, are made. + */ + EXT_KEY(ZBA); + EXT_KEY(ZBB); + EXT_KEY(ZBS); + EXT_KEY(ZICBOZ); + EXT_KEY(ZBC); + + EXT_KEY(ZBKB); + EXT_KEY(ZBKC); + EXT_KEY(ZBKX); + EXT_KEY(ZKND); + EXT_KEY(ZKNE); + EXT_KEY(ZKNH); + EXT_KEY(ZKSED); + EXT_KEY(ZKSH); + EXT_KEY(ZKT); + EXT_KEY(ZIHINTNTL); + EXT_KEY(ZTSO); + EXT_KEY(ZACAS); + EXT_KEY(ZICOND); + + if (has_vector()) { + EXT_KEY(ZVBB); + EXT_KEY(ZVBC); + EXT_KEY(ZVKB); + EXT_KEY(ZVKG); + EXT_KEY(ZVKNED); + EXT_KEY(ZVKNHA); + EXT_KEY(ZVKNHB); + EXT_KEY(ZVKSED); + EXT_KEY(ZVKSH); + EXT_KEY(ZVKT); + EXT_KEY(ZVFH); + EXT_KEY(ZVFHMIN); + } + + if (has_fpu()) { + EXT_KEY(ZFH); + EXT_KEY(ZFHMIN); + EXT_KEY(ZFA); + } +#undef EXT_KEY + } + + /* Now turn off reporting features if any CPU is missing it. */ + pair->value &= ~missing; +} + +static bool hwprobe_ext0_has(const struct cpumask *cpus, unsigned long ext) +{ + struct riscv_hwprobe pair; + + hwprobe_isa_ext0(&pair, cpus); + return (pair.value & ext); +} + +static u64 hwprobe_misaligned(const struct cpumask *cpus) +{ + int cpu; + u64 perf = -1ULL; + + for_each_cpu(cpu, cpus) { + int this_perf = per_cpu(misaligned_access_speed, cpu); + + if (perf == -1ULL) + perf = this_perf; + + if (perf != this_perf) { + perf = RISCV_HWPROBE_MISALIGNED_UNKNOWN; + break; + } + } + + if (perf == -1ULL) + return RISCV_HWPROBE_MISALIGNED_UNKNOWN; + + return perf; +} + +static void hwprobe_one_pair(struct riscv_hwprobe *pair, + const struct cpumask *cpus) +{ + switch (pair->key) { + case RISCV_HWPROBE_KEY_MVENDORID: + case RISCV_HWPROBE_KEY_MARCHID: + case RISCV_HWPROBE_KEY_MIMPID: + hwprobe_arch_id(pair, cpus); + break; + /* + * The kernel already assumes that the base single-letter ISA + * extensions are supported on all harts, and only supports the + * IMA base, so just cheat a bit here and tell that to + * userspace. + */ + case RISCV_HWPROBE_KEY_BASE_BEHAVIOR: + pair->value = RISCV_HWPROBE_BASE_BEHAVIOR_IMA; + break; + + case RISCV_HWPROBE_KEY_IMA_EXT_0: + hwprobe_isa_ext0(pair, cpus); + break; + + case RISCV_HWPROBE_KEY_CPUPERF_0: + pair->value = hwprobe_misaligned(cpus); + break; + + case RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE: + pair->value = 0; + if (hwprobe_ext0_has(cpus, RISCV_HWPROBE_EXT_ZICBOZ)) + pair->value = riscv_cboz_block_size; + break; + + /* + * For forward compatibility, unknown keys don't fail the whole + * call, but get their element key set to -1 and value set to 0 + * indicating they're unrecognized. + */ + default: + pair->key = -1; + pair->value = 0; + break; + } +} + +static int hwprobe_get_values(struct riscv_hwprobe __user *pairs, + size_t pair_count, size_t cpusetsize, + unsigned long __user *cpus_user, + unsigned int flags) +{ + size_t out; + int ret; + cpumask_t cpus; + + /* Check the reserved flags. */ + if (flags != 0) + return -EINVAL; + + /* + * The interface supports taking in a CPU mask, and returns values that + * are consistent across that mask. Allow userspace to specify NULL and + * 0 as a shortcut to all online CPUs. + */ + cpumask_clear(&cpus); + if (!cpusetsize && !cpus_user) { + cpumask_copy(&cpus, cpu_online_mask); + } else { + if (cpusetsize > cpumask_size()) + cpusetsize = cpumask_size(); + + ret = copy_from_user(&cpus, cpus_user, cpusetsize); + if (ret) + return -EFAULT; + + /* + * Userspace must provide at least one online CPU, without that + * there's no way to define what is supported. + */ + cpumask_and(&cpus, &cpus, cpu_online_mask); + if (cpumask_empty(&cpus)) + return -EINVAL; + } + + for (out = 0; out < pair_count; out++, pairs++) { + struct riscv_hwprobe pair; + + if (get_user(pair.key, &pairs->key)) + return -EFAULT; + + pair.value = 0; + hwprobe_one_pair(&pair, &cpus); + ret = put_user(pair.key, &pairs->key); + if (ret == 0) + ret = put_user(pair.value, &pairs->value); + + if (ret) + return -EFAULT; + } + + return 0; +} + +static int hwprobe_get_cpus(struct riscv_hwprobe __user *pairs, + size_t pair_count, size_t cpusetsize, + unsigned long __user *cpus_user, + unsigned int flags) +{ + cpumask_t cpus, one_cpu; + bool clear_all = false; + size_t i; + int ret; + + if (flags != RISCV_HWPROBE_WHICH_CPUS) + return -EINVAL; + + if (!cpusetsize || !cpus_user) + return -EINVAL; + + if (cpusetsize > cpumask_size()) + cpusetsize = cpumask_size(); + + ret = copy_from_user(&cpus, cpus_user, cpusetsize); + if (ret) + return -EFAULT; + + if (cpumask_empty(&cpus)) + cpumask_copy(&cpus, cpu_online_mask); + + cpumask_and(&cpus, &cpus, cpu_online_mask); + + cpumask_clear(&one_cpu); + + for (i = 0; i < pair_count; i++) { + struct riscv_hwprobe pair, tmp; + int cpu; + + ret = copy_from_user(&pair, &pairs[i], sizeof(pair)); + if (ret) + return -EFAULT; + + if (!riscv_hwprobe_key_is_valid(pair.key)) { + clear_all = true; + pair = (struct riscv_hwprobe){ .key = -1, }; + ret = copy_to_user(&pairs[i], &pair, sizeof(pair)); + if (ret) + return -EFAULT; + } + + if (clear_all) + continue; + + tmp = (struct riscv_hwprobe){ .key = pair.key, }; + + for_each_cpu(cpu, &cpus) { + cpumask_set_cpu(cpu, &one_cpu); + + hwprobe_one_pair(&tmp, &one_cpu); + + if (!riscv_hwprobe_pair_cmp(&tmp, &pair)) + cpumask_clear_cpu(cpu, &cpus); + + cpumask_clear_cpu(cpu, &one_cpu); + } + } + + if (clear_all) + cpumask_clear(&cpus); + + ret = copy_to_user(cpus_user, &cpus, cpusetsize); + if (ret) + return -EFAULT; + + return 0; +} + +static int do_riscv_hwprobe(struct riscv_hwprobe __user *pairs, + size_t pair_count, size_t cpusetsize, + unsigned long __user *cpus_user, + unsigned int flags) +{ + if (flags & RISCV_HWPROBE_WHICH_CPUS) + return hwprobe_get_cpus(pairs, pair_count, cpusetsize, + cpus_user, flags); + + return hwprobe_get_values(pairs, pair_count, cpusetsize, + cpus_user, flags); +} + +#ifdef CONFIG_MMU + +static int __init init_hwprobe_vdso_data(void) +{ + struct vdso_data *vd = __arch_get_k_vdso_data(); + struct arch_vdso_data *avd = &vd->arch_data; + u64 id_bitsmash = 0; + struct riscv_hwprobe pair; + int key; + + /* + * Initialize vDSO data with the answers for the "all CPUs" case, to + * save a syscall in the common case. + */ + for (key = 0; key <= RISCV_HWPROBE_MAX_KEY; key++) { + pair.key = key; + hwprobe_one_pair(&pair, cpu_online_mask); + + WARN_ON_ONCE(pair.key < 0); + + avd->all_cpu_hwprobe_values[key] = pair.value; + /* + * Smash together the vendor, arch, and impl IDs to see if + * they're all 0 or any negative. + */ + if (key <= RISCV_HWPROBE_KEY_MIMPID) + id_bitsmash |= pair.value; + } + + /* + * If the arch, vendor, and implementation ID are all the same across + * all harts, then assume all CPUs are the same, and allow the vDSO to + * answer queries for arbitrary masks. However if all values are 0 (not + * populated) or any value returns -1 (varies across CPUs), then the + * vDSO should defer to the kernel for exotic cpu masks. + */ + avd->homogeneous_cpus = id_bitsmash != 0 && id_bitsmash != -1; + return 0; +} + +arch_initcall_sync(init_hwprobe_vdso_data); + +#endif /* CONFIG_MMU */ + +SYSCALL_DEFINE5(riscv_hwprobe, struct riscv_hwprobe __user *, pairs, + size_t, pair_count, size_t, cpusetsize, unsigned long __user *, + cpus, unsigned int, flags) +{ + return do_riscv_hwprobe(pairs, pair_count, cpusetsize, + cpus, flags); +} diff --git a/arch/riscv/kernel/sys_riscv.c b/arch/riscv/kernel/sys_riscv.c index a2ca5b7756a5b0..f1c1416a9f1e51 100644 --- a/arch/riscv/kernel/sys_riscv.c +++ b/arch/riscv/kernel/sys_riscv.c @@ -7,15 +7,7 @@ #include #include -#include -#include -#include -#include -#include -#include -#include #include -#include static long riscv_sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, @@ -77,283 +69,6 @@ SYSCALL_DEFINE3(riscv_flush_icache, uintptr_t, start, uintptr_t, end, return 0; } -/* - * The hwprobe interface, for allowing userspace to probe to see which features - * are supported by the hardware. See Documentation/arch/riscv/hwprobe.rst for more - * details. - */ -static void hwprobe_arch_id(struct riscv_hwprobe *pair, - const struct cpumask *cpus) -{ - u64 id = -1ULL; - bool first = true; - int cpu; - - for_each_cpu(cpu, cpus) { - u64 cpu_id; - - switch (pair->key) { - case RISCV_HWPROBE_KEY_MVENDORID: - cpu_id = riscv_cached_mvendorid(cpu); - break; - case RISCV_HWPROBE_KEY_MIMPID: - cpu_id = riscv_cached_mimpid(cpu); - break; - case RISCV_HWPROBE_KEY_MARCHID: - cpu_id = riscv_cached_marchid(cpu); - break; - } - - if (first) { - id = cpu_id; - first = false; - } - - /* - * If there's a mismatch for the given set, return -1 in the - * value. - */ - if (id != cpu_id) { - id = -1ULL; - break; - } - } - - pair->value = id; -} - -static void hwprobe_isa_ext0(struct riscv_hwprobe *pair, - const struct cpumask *cpus) -{ - int cpu; - u64 missing = 0; - - pair->value = 0; - if (has_fpu()) - pair->value |= RISCV_HWPROBE_IMA_FD; - - if (riscv_isa_extension_available(NULL, c)) - pair->value |= RISCV_HWPROBE_IMA_C; - - if (has_vector()) - pair->value |= RISCV_HWPROBE_IMA_V; - - /* - * Loop through and record extensions that 1) anyone has, and 2) anyone - * doesn't have. - */ - for_each_cpu(cpu, cpus) { - struct riscv_isainfo *isainfo = &hart_isa[cpu]; - -#define EXT_KEY(ext) \ - do { \ - if (__riscv_isa_extension_available(isainfo->isa, RISCV_ISA_EXT_##ext)) \ - pair->value |= RISCV_HWPROBE_EXT_##ext; \ - else \ - missing |= RISCV_HWPROBE_EXT_##ext; \ - } while (false) - - /* - * Only use EXT_KEY() for extensions which can be exposed to userspace, - * regardless of the kernel's configuration, as no other checks, besides - * presence in the hart_isa bitmap, are made. - */ - EXT_KEY(ZBA); - EXT_KEY(ZBB); - EXT_KEY(ZBS); - EXT_KEY(ZICBOZ); -#undef EXT_KEY - } - - /* Now turn off reporting features if any CPU is missing it. */ - pair->value &= ~missing; -} - -static bool hwprobe_ext0_has(const struct cpumask *cpus, u64 ext) -{ - struct riscv_hwprobe pair; - - hwprobe_isa_ext0(&pair, cpus); - return (pair.value & ext); -} - -static u64 hwprobe_misaligned(const struct cpumask *cpus) -{ - int cpu; - u64 perf = -1ULL; - - for_each_cpu(cpu, cpus) { - int this_perf = per_cpu(misaligned_access_speed, cpu); - - if (perf == -1ULL) - perf = this_perf; - - if (perf != this_perf) { - perf = RISCV_HWPROBE_MISALIGNED_UNKNOWN; - break; - } - } - - if (perf == -1ULL) - return RISCV_HWPROBE_MISALIGNED_UNKNOWN; - - return perf; -} - -static void hwprobe_one_pair(struct riscv_hwprobe *pair, - const struct cpumask *cpus) -{ - switch (pair->key) { - case RISCV_HWPROBE_KEY_MVENDORID: - case RISCV_HWPROBE_KEY_MARCHID: - case RISCV_HWPROBE_KEY_MIMPID: - hwprobe_arch_id(pair, cpus); - break; - /* - * The kernel already assumes that the base single-letter ISA - * extensions are supported on all harts, and only supports the - * IMA base, so just cheat a bit here and tell that to - * userspace. - */ - case RISCV_HWPROBE_KEY_BASE_BEHAVIOR: - pair->value = RISCV_HWPROBE_BASE_BEHAVIOR_IMA; - break; - - case RISCV_HWPROBE_KEY_IMA_EXT_0: - hwprobe_isa_ext0(pair, cpus); - break; - - case RISCV_HWPROBE_KEY_CPUPERF_0: - pair->value = hwprobe_misaligned(cpus); - break; - - case RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE: - pair->value = 0; - if (hwprobe_ext0_has(cpus, RISCV_HWPROBE_EXT_ZICBOZ)) - pair->value = riscv_cboz_block_size; - break; - - /* - * For forward compatibility, unknown keys don't fail the whole - * call, but get their element key set to -1 and value set to 0 - * indicating they're unrecognized. - */ - default: - pair->key = -1; - pair->value = 0; - break; - } -} - -static int do_riscv_hwprobe(struct riscv_hwprobe __user *pairs, - size_t pair_count, size_t cpu_count, - unsigned long __user *cpus_user, - unsigned int flags) -{ - size_t out; - int ret; - cpumask_t cpus; - - /* Check the reserved flags. */ - if (flags != 0) - return -EINVAL; - - /* - * The interface supports taking in a CPU mask, and returns values that - * are consistent across that mask. Allow userspace to specify NULL and - * 0 as a shortcut to all online CPUs. - */ - cpumask_clear(&cpus); - if (!cpu_count && !cpus_user) { - cpumask_copy(&cpus, cpu_online_mask); - } else { - if (cpu_count > cpumask_size()) - cpu_count = cpumask_size(); - - ret = copy_from_user(&cpus, cpus_user, cpu_count); - if (ret) - return -EFAULT; - - /* - * Userspace must provide at least one online CPU, without that - * there's no way to define what is supported. - */ - cpumask_and(&cpus, &cpus, cpu_online_mask); - if (cpumask_empty(&cpus)) - return -EINVAL; - } - - for (out = 0; out < pair_count; out++, pairs++) { - struct riscv_hwprobe pair; - - if (get_user(pair.key, &pairs->key)) - return -EFAULT; - - pair.value = 0; - hwprobe_one_pair(&pair, &cpus); - ret = put_user(pair.key, &pairs->key); - if (ret == 0) - ret = put_user(pair.value, &pairs->value); - - if (ret) - return -EFAULT; - } - - return 0; -} - -#ifdef CONFIG_MMU - -static int __init init_hwprobe_vdso_data(void) -{ - struct vdso_data *vd = __arch_get_k_vdso_data(); - struct arch_vdso_data *avd = &vd->arch_data; - u64 id_bitsmash = 0; - struct riscv_hwprobe pair; - int key; - - /* - * Initialize vDSO data with the answers for the "all CPUs" case, to - * save a syscall in the common case. - */ - for (key = 0; key <= RISCV_HWPROBE_MAX_KEY; key++) { - pair.key = key; - hwprobe_one_pair(&pair, cpu_online_mask); - - WARN_ON_ONCE(pair.key < 0); - - avd->all_cpu_hwprobe_values[key] = pair.value; - /* - * Smash together the vendor, arch, and impl IDs to see if - * they're all 0 or any negative. - */ - if (key <= RISCV_HWPROBE_KEY_MIMPID) - id_bitsmash |= pair.value; - } - - /* - * If the arch, vendor, and implementation ID are all the same across - * all harts, then assume all CPUs are the same, and allow the vDSO to - * answer queries for arbitrary masks. However if all values are 0 (not - * populated) or any value returns -1 (varies across CPUs), then the - * vDSO should defer to the kernel for exotic cpu masks. - */ - avd->homogeneous_cpus = id_bitsmash != 0 && id_bitsmash != -1; - return 0; -} - -arch_initcall_sync(init_hwprobe_vdso_data); - -#endif /* CONFIG_MMU */ - -SYSCALL_DEFINE5(riscv_hwprobe, struct riscv_hwprobe __user *, pairs, - size_t, pair_count, size_t, cpu_count, unsigned long __user *, - cpus, unsigned int, flags) -{ - return do_riscv_hwprobe(pairs, pair_count, cpu_count, - cpus, flags); -} - /* Not defined using SYSCALL_DEFINE0 to avoid error injection */ asmlinkage long __riscv_sys_ni_syscall(const struct pt_regs *__unused) { diff --git a/arch/riscv/kernel/time.c b/arch/riscv/kernel/time.c index 23641e82a9df2a..ba347719778976 100644 --- a/arch/riscv/kernel/time.c +++ b/arch/riscv/kernel/time.c @@ -12,6 +12,7 @@ #include #include #include +#include unsigned long riscv_timebase __ro_after_init; EXPORT_SYMBOL_GPL(riscv_timebase); @@ -45,4 +46,6 @@ void __init time_init(void) timer_probe(); tick_setup_hrtimer_broadcast(); + + pv_time_init(); } diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps_misaligned.c index 5255f8134aeff5..8ded225e8c5b13 100644 --- a/arch/riscv/kernel/traps_misaligned.c +++ b/arch/riscv/kernel/traps_misaligned.c @@ -319,7 +319,7 @@ static inline int get_insn(struct pt_regs *regs, ulong mepc, ulong *r_insn) static inline int load_u8(struct pt_regs *regs, const u8 *addr, u8 *r_val) { if (user_mode(regs)) { - return __get_user(*r_val, addr); + return __get_user(*r_val, (u8 __user *)addr); } else { *r_val = *addr; return 0; @@ -329,7 +329,7 @@ static inline int load_u8(struct pt_regs *regs, const u8 *addr, u8 *r_val) static inline int store_u8(struct pt_regs *regs, u8 *addr, u8 val) { if (user_mode(regs)) { - return __put_user(val, addr); + return __put_user(val, (u8 __user *)addr); } else { *addr = val; return 0; @@ -343,7 +343,7 @@ static inline int store_u8(struct pt_regs *regs, u8 *addr, u8 val) if (user_mode(regs)) { \ __ret = __get_user(insn, insn_addr); \ } else { \ - insn = *insn_addr; \ + insn = *(__force u16 *)insn_addr; \ __ret = 0; \ } \ \ diff --git a/arch/riscv/kernel/vdso/hwprobe.c b/arch/riscv/kernel/vdso/hwprobe.c index cadf725ef79837..1e926e4b5881b6 100644 --- a/arch/riscv/kernel/vdso/hwprobe.c +++ b/arch/riscv/kernel/vdso/hwprobe.c @@ -3,26 +3,22 @@ * Copyright 2023 Rivos, Inc */ +#include #include #include #include extern int riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, - size_t cpu_count, unsigned long *cpus, + size_t cpusetsize, unsigned long *cpus, unsigned int flags); -/* Add a prototype to avoid -Wmissing-prototypes warning. */ -int __vdso_riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, - size_t cpu_count, unsigned long *cpus, - unsigned int flags); - -int __vdso_riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, - size_t cpu_count, unsigned long *cpus, - unsigned int flags) +static int riscv_vdso_get_values(struct riscv_hwprobe *pairs, size_t pair_count, + size_t cpusetsize, unsigned long *cpus, + unsigned int flags) { const struct vdso_data *vd = __arch_get_vdso_data(); const struct arch_vdso_data *avd = &vd->arch_data; - bool all_cpus = !cpu_count && !cpus; + bool all_cpus = !cpusetsize && !cpus; struct riscv_hwprobe *p = pairs; struct riscv_hwprobe *end = pairs + pair_count; @@ -33,7 +29,7 @@ int __vdso_riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, * masks. */ if ((flags != 0) || (!all_cpus && !avd->homogeneous_cpus)) - return riscv_hwprobe(pairs, pair_count, cpu_count, cpus, flags); + return riscv_hwprobe(pairs, pair_count, cpusetsize, cpus, flags); /* This is something we can handle, fill out the pairs. */ while (p < end) { @@ -50,3 +46,71 @@ int __vdso_riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, return 0; } + +static int riscv_vdso_get_cpus(struct riscv_hwprobe *pairs, size_t pair_count, + size_t cpusetsize, unsigned long *cpus, + unsigned int flags) +{ + const struct vdso_data *vd = __arch_get_vdso_data(); + const struct arch_vdso_data *avd = &vd->arch_data; + struct riscv_hwprobe *p = pairs; + struct riscv_hwprobe *end = pairs + pair_count; + unsigned char *c = (unsigned char *)cpus; + bool empty_cpus = true; + bool clear_all = false; + int i; + + if (!cpusetsize || !cpus) + return -EINVAL; + + for (i = 0; i < cpusetsize; i++) { + if (c[i]) { + empty_cpus = false; + break; + } + } + + if (empty_cpus || flags != RISCV_HWPROBE_WHICH_CPUS || !avd->homogeneous_cpus) + return riscv_hwprobe(pairs, pair_count, cpusetsize, cpus, flags); + + while (p < end) { + if (riscv_hwprobe_key_is_valid(p->key)) { + struct riscv_hwprobe t = { + .key = p->key, + .value = avd->all_cpu_hwprobe_values[p->key], + }; + + if (!riscv_hwprobe_pair_cmp(&t, p)) + clear_all = true; + } else { + clear_all = true; + p->key = -1; + p->value = 0; + } + p++; + } + + if (clear_all) { + for (i = 0; i < cpusetsize; i++) + c[i] = 0; + } + + return 0; +} + +/* Add a prototype to avoid -Wmissing-prototypes warning. */ +int __vdso_riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, + size_t cpusetsize, unsigned long *cpus, + unsigned int flags); + +int __vdso_riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, + size_t cpusetsize, unsigned long *cpus, + unsigned int flags) +{ + if (flags & RISCV_HWPROBE_WHICH_CPUS) + return riscv_vdso_get_cpus(pairs, pair_count, cpusetsize, + cpus, flags); + + return riscv_vdso_get_values(pairs, pair_count, cpusetsize, + cpus, flags); +} diff --git a/arch/riscv/kernel/vdso/vgettimeofday.c b/arch/riscv/kernel/vdso/vgettimeofday.c index cc0d80699c3107..b3505780258499 100644 --- a/arch/riscv/kernel/vdso/vgettimeofday.c +++ b/arch/riscv/kernel/vdso/vgettimeofday.c @@ -8,23 +8,18 @@ #include #include +#include -extern -int __vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts); int __vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts) { return __cvdso_clock_gettime(clock, ts); } -extern -int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz); int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz) { return __cvdso_gettimeofday(tv, tz); } -extern -int __vdso_clock_getres(clockid_t clock_id, struct __kernel_timespec *res); int __vdso_clock_getres(clockid_t clock_id, struct __kernel_timespec *res) { return __cvdso_clock_getres(clock_id, res); diff --git a/arch/riscv/kernel/vector.c b/arch/riscv/kernel/vector.c index 578b6292487e1b..6727d1d3b8f282 100644 --- a/arch/riscv/kernel/vector.c +++ b/arch/riscv/kernel/vector.c @@ -21,6 +21,10 @@ #include static bool riscv_v_implicit_uacc = IS_ENABLED(CONFIG_RISCV_ISA_V_DEFAULT_ENABLE); +static struct kmem_cache *riscv_v_user_cachep; +#ifdef CONFIG_RISCV_ISA_V_PREEMPTIVE +static struct kmem_cache *riscv_v_kernel_cachep; +#endif unsigned long riscv_v_vsize __read_mostly; EXPORT_SYMBOL_GPL(riscv_v_vsize); @@ -47,6 +51,21 @@ int riscv_v_setup_vsize(void) return 0; } +void __init riscv_v_setup_ctx_cache(void) +{ + if (!has_vector()) + return; + + riscv_v_user_cachep = kmem_cache_create_usercopy("riscv_vector_ctx", + riscv_v_vsize, 16, SLAB_PANIC, + 0, riscv_v_vsize, NULL); +#ifdef CONFIG_RISCV_ISA_V_PREEMPTIVE + riscv_v_kernel_cachep = kmem_cache_create("riscv_vector_kctx", + riscv_v_vsize, 16, + SLAB_PANIC, NULL); +#endif +} + static bool insn_is_vector(u32 insn_buf) { u32 opcode = insn_buf & __INSN_OPCODE_MASK; @@ -80,20 +99,37 @@ static bool insn_is_vector(u32 insn_buf) return false; } -static int riscv_v_thread_zalloc(void) +static int riscv_v_thread_zalloc(struct kmem_cache *cache, + struct __riscv_v_ext_state *ctx) { void *datap; - datap = kzalloc(riscv_v_vsize, GFP_KERNEL); + datap = kmem_cache_zalloc(cache, GFP_KERNEL); if (!datap) return -ENOMEM; - current->thread.vstate.datap = datap; - memset(¤t->thread.vstate, 0, offsetof(struct __riscv_v_ext_state, - datap)); + ctx->datap = datap; + memset(ctx, 0, offsetof(struct __riscv_v_ext_state, datap)); return 0; } +void riscv_v_thread_alloc(struct task_struct *tsk) +{ +#ifdef CONFIG_RISCV_ISA_V_PREEMPTIVE + riscv_v_thread_zalloc(riscv_v_kernel_cachep, &tsk->thread.kernel_vstate); +#endif +} + +void riscv_v_thread_free(struct task_struct *tsk) +{ + if (tsk->thread.vstate.datap) + kmem_cache_free(riscv_v_user_cachep, tsk->thread.vstate.datap); +#ifdef CONFIG_RISCV_ISA_V_PREEMPTIVE + if (tsk->thread.kernel_vstate.datap) + kmem_cache_free(riscv_v_kernel_cachep, tsk->thread.kernel_vstate.datap); +#endif +} + #define VSTATE_CTRL_GET_CUR(x) ((x) & PR_RISCV_V_VSTATE_CTRL_CUR_MASK) #define VSTATE_CTRL_GET_NEXT(x) (((x) & PR_RISCV_V_VSTATE_CTRL_NEXT_MASK) >> 2) #define VSTATE_CTRL_MAKE_NEXT(x) (((x) << 2) & PR_RISCV_V_VSTATE_CTRL_NEXT_MASK) @@ -122,7 +158,8 @@ static inline void riscv_v_ctrl_set(struct task_struct *tsk, int cur, int nxt, ctrl |= VSTATE_CTRL_MAKE_NEXT(nxt); if (inherit) ctrl |= PR_RISCV_V_VSTATE_CTRL_INHERIT; - tsk->thread.vstate_ctrl = ctrl; + tsk->thread.vstate_ctrl &= ~PR_RISCV_V_VSTATE_CTRL_MASK; + tsk->thread.vstate_ctrl |= ctrl; } bool riscv_v_vstate_ctrl_user_allowed(void) @@ -162,12 +199,12 @@ bool riscv_v_first_use_handler(struct pt_regs *regs) * context where VS has been off. So, try to allocate the user's V * context and resume execution. */ - if (riscv_v_thread_zalloc()) { + if (riscv_v_thread_zalloc(riscv_v_user_cachep, ¤t->thread.vstate)) { force_sig(SIGBUS); return true; } riscv_v_vstate_on(regs); - riscv_v_vstate_restore(current, regs); + riscv_v_vstate_set_restore(current, regs); return true; } diff --git a/arch/riscv/kernel/vmlinux-xip.lds.S b/arch/riscv/kernel/vmlinux-xip.lds.S index 50767647fbc649..8c3daa1b05313a 100644 --- a/arch/riscv/kernel/vmlinux-xip.lds.S +++ b/arch/riscv/kernel/vmlinux-xip.lds.S @@ -29,10 +29,12 @@ SECTIONS HEAD_TEXT_SECTION INIT_TEXT_SECTION(PAGE_SIZE) /* we have to discard exit text and such at runtime, not link time */ + __exittext_begin = .; .exit.text : { EXIT_TEXT } + __exittext_end = .; .text : { _text = .; diff --git a/arch/riscv/kernel/vmlinux.lds.S b/arch/riscv/kernel/vmlinux.lds.S index 492dd4b8f3d69a..002ca58dd998cb 100644 --- a/arch/riscv/kernel/vmlinux.lds.S +++ b/arch/riscv/kernel/vmlinux.lds.S @@ -69,10 +69,12 @@ SECTIONS __soc_builtin_dtb_table_end = .; } /* we have to discard exit text and such at runtime, not link time */ + __exittext_begin = .; .exit.text : { EXIT_TEXT } + __exittext_end = .; __init_text_end = .; . = ALIGN(SECTION_ALIGN); diff --git a/arch/riscv/kvm/Kconfig b/arch/riscv/kvm/Kconfig index dfc237d7875b53..d490db94385883 100644 --- a/arch/riscv/kvm/Kconfig +++ b/arch/riscv/kvm/Kconfig @@ -20,18 +20,17 @@ if VIRTUALIZATION config KVM tristate "Kernel-based Virtual Machine (KVM) support (EXPERIMENTAL)" depends on RISCV_SBI && MMU - select HAVE_KVM_EVENTFD select HAVE_KVM_IRQCHIP - select HAVE_KVM_IRQFD select HAVE_KVM_IRQ_ROUTING select HAVE_KVM_MSI select HAVE_KVM_VCPU_ASYNC_IOCTL + select KVM_COMMON select KVM_GENERIC_DIRTYLOG_READ_PROTECT select KVM_GENERIC_HARDWARE_ENABLING select KVM_MMIO select KVM_XFER_TO_GUEST_WORK - select MMU_NOTIFIER - select PREEMPT_NOTIFIERS + select KVM_GENERIC_MMU_NOTIFIER + select SCHED_INFO help Support hosting virtualized guest machines. diff --git a/arch/riscv/kvm/Makefile b/arch/riscv/kvm/Makefile index 4c2067fc59fcbf..c9646521f1132e 100644 --- a/arch/riscv/kvm/Makefile +++ b/arch/riscv/kvm/Makefile @@ -26,6 +26,7 @@ kvm-$(CONFIG_RISCV_SBI_V01) += vcpu_sbi_v01.o kvm-y += vcpu_sbi_base.o kvm-y += vcpu_sbi_replace.o kvm-y += vcpu_sbi_hsm.o +kvm-y += vcpu_sbi_sta.o kvm-y += vcpu_timer.o kvm-$(CONFIG_RISCV_PMU_SBI) += vcpu_pmu.o vcpu_sbi_pmu.o kvm-y += aia.o diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c index 068c7459387102..a9e2fd7245e1e9 100644 --- a/arch/riscv/kvm/mmu.c +++ b/arch/riscv/kvm/mmu.c @@ -103,7 +103,7 @@ static bool gstage_get_leaf_entry(struct kvm *kvm, gpa_t addr, *ptep_level = current_level; ptep = (pte_t *)kvm->arch.pgd; ptep = &ptep[gstage_pte_index(addr, current_level)]; - while (ptep && pte_val(*ptep)) { + while (ptep && pte_val(ptep_get(ptep))) { if (gstage_pte_leaf(ptep)) { *ptep_level = current_level; *ptepp = ptep; @@ -113,7 +113,7 @@ static bool gstage_get_leaf_entry(struct kvm *kvm, gpa_t addr, if (current_level) { current_level--; *ptep_level = current_level; - ptep = (pte_t *)gstage_pte_page_vaddr(*ptep); + ptep = (pte_t *)gstage_pte_page_vaddr(ptep_get(ptep)); ptep = &ptep[gstage_pte_index(addr, current_level)]; } else { ptep = NULL; @@ -149,25 +149,25 @@ static int gstage_set_pte(struct kvm *kvm, u32 level, if (gstage_pte_leaf(ptep)) return -EEXIST; - if (!pte_val(*ptep)) { + if (!pte_val(ptep_get(ptep))) { if (!pcache) return -ENOMEM; next_ptep = kvm_mmu_memory_cache_alloc(pcache); if (!next_ptep) return -ENOMEM; - *ptep = pfn_pte(PFN_DOWN(__pa(next_ptep)), - __pgprot(_PAGE_TABLE)); + set_pte(ptep, pfn_pte(PFN_DOWN(__pa(next_ptep)), + __pgprot(_PAGE_TABLE))); } else { if (gstage_pte_leaf(ptep)) return -EEXIST; - next_ptep = (pte_t *)gstage_pte_page_vaddr(*ptep); + next_ptep = (pte_t *)gstage_pte_page_vaddr(ptep_get(ptep)); } current_level--; ptep = &next_ptep[gstage_pte_index(addr, current_level)]; } - *ptep = *new_pte; + set_pte(ptep, *new_pte); if (gstage_pte_leaf(ptep)) gstage_remote_tlb_flush(kvm, current_level, addr); @@ -239,11 +239,11 @@ static void gstage_op_pte(struct kvm *kvm, gpa_t addr, BUG_ON(addr & (page_size - 1)); - if (!pte_val(*ptep)) + if (!pte_val(ptep_get(ptep))) return; if (ptep_level && !gstage_pte_leaf(ptep)) { - next_ptep = (pte_t *)gstage_pte_page_vaddr(*ptep); + next_ptep = (pte_t *)gstage_pte_page_vaddr(ptep_get(ptep)); next_ptep_level = ptep_level - 1; ret = gstage_level_to_page_size(next_ptep_level, &next_page_size); @@ -261,7 +261,7 @@ static void gstage_op_pte(struct kvm *kvm, gpa_t addr, if (op == GSTAGE_OP_CLEAR) set_pte(ptep, __pte(0)); else if (op == GSTAGE_OP_WP) - set_pte(ptep, __pte(pte_val(*ptep) & ~_PAGE_WRITE)); + set_pte(ptep, __pte(pte_val(ptep_get(ptep)) & ~_PAGE_WRITE)); gstage_remote_tlb_flush(kvm, ptep_level, addr); } } @@ -603,7 +603,7 @@ bool kvm_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range) &ptep, &ptep_level)) return false; - return pte_young(*ptep); + return pte_young(ptep_get(ptep)); } int kvm_riscv_gstage_map(struct kvm_vcpu *vcpu, diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c index e087c809073c1b..b5ca9f2e98acd2 100644 --- a/arch/riscv/kvm/vcpu.c +++ b/arch/riscv/kvm/vcpu.c @@ -83,6 +83,8 @@ static void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu) vcpu->arch.hfence_tail = 0; memset(vcpu->arch.hfence_queue, 0, sizeof(vcpu->arch.hfence_queue)); + kvm_riscv_vcpu_sbi_sta_reset(vcpu); + /* Reset the guest CSRs for hotplug usecase */ if (loaded) kvm_arch_vcpu_load(vcpu, smp_processor_id()); @@ -541,6 +543,8 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) kvm_riscv_vcpu_aia_load(vcpu, cpu); + kvm_make_request(KVM_REQ_STEAL_UPDATE, vcpu); + vcpu->cpu = cpu; } @@ -614,6 +618,9 @@ static void kvm_riscv_check_vcpu_requests(struct kvm_vcpu *vcpu) if (kvm_check_request(KVM_REQ_HFENCE, vcpu)) kvm_riscv_hfence_process(vcpu); + + if (kvm_check_request(KVM_REQ_STEAL_UPDATE, vcpu)) + kvm_riscv_vcpu_record_steal_time(vcpu); } } @@ -757,8 +764,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) /* Update HVIP CSR for current CPU */ kvm_riscv_update_hvip(vcpu); - if (ret <= 0 || - kvm_riscv_gstage_vmid_ver_changed(&vcpu->kvm->arch.vmid) || + if (kvm_riscv_gstage_vmid_ver_changed(&vcpu->kvm->arch.vmid) || kvm_request_pending(vcpu) || xfer_to_guest_mode_work_pending()) { vcpu->mode = OUTSIDE_GUEST_MODE; diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c index f8c9fa0c03c5ab..fc34557f5356e2 100644 --- a/arch/riscv/kvm/vcpu_onereg.c +++ b/arch/riscv/kvm/vcpu_onereg.c @@ -485,7 +485,7 @@ static int kvm_riscv_vcpu_set_reg_csr(struct kvm_vcpu *vcpu, if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN)) rc = kvm_riscv_vcpu_smstateen_set_csr(vcpu, reg_num, reg_val); -break; + break; default: rc = -ENOENT; break; @@ -931,50 +931,106 @@ static inline unsigned long num_isa_ext_regs(const struct kvm_vcpu *vcpu) return copy_isa_ext_reg_indices(vcpu, NULL);; } -static inline unsigned long num_sbi_ext_regs(void) +static int copy_sbi_ext_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) { - /* - * number of KVM_REG_RISCV_SBI_SINGLE + - * 2 x (number of KVM_REG_RISCV_SBI_MULTI) - */ - return KVM_RISCV_SBI_EXT_MAX + 2*(KVM_REG_RISCV_SBI_MULTI_REG_LAST+1); -} - -static int copy_sbi_ext_reg_indices(u64 __user *uindices) -{ - int n; + unsigned int n = 0; - /* copy KVM_REG_RISCV_SBI_SINGLE */ - n = KVM_RISCV_SBI_EXT_MAX; - for (int i = 0; i < n; i++) { + for (int i = 0; i < KVM_RISCV_SBI_EXT_MAX; i++) { u64 size = IS_ENABLED(CONFIG_32BIT) ? KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64; u64 reg = KVM_REG_RISCV | size | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | i; + if (!riscv_vcpu_supports_sbi_ext(vcpu, i)) + continue; + if (uindices) { if (put_user(reg, uindices)) return -EFAULT; uindices++; } + + n++; } - /* copy KVM_REG_RISCV_SBI_MULTI */ - n = KVM_REG_RISCV_SBI_MULTI_REG_LAST + 1; - for (int i = 0; i < n; i++) { - u64 size = IS_ENABLED(CONFIG_32BIT) ? - KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64; - u64 reg = KVM_REG_RISCV | size | KVM_REG_RISCV_SBI_EXT | - KVM_REG_RISCV_SBI_MULTI_EN | i; + return n; +} + +static unsigned long num_sbi_ext_regs(struct kvm_vcpu *vcpu) +{ + return copy_sbi_ext_reg_indices(vcpu, NULL); +} + +static int copy_sbi_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) +{ + struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context; + int total = 0; + + if (scontext->ext_status[KVM_RISCV_SBI_EXT_STA] == KVM_RISCV_SBI_EXT_STATUS_ENABLED) { + u64 size = IS_ENABLED(CONFIG_32BIT) ? KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64; + int n = sizeof(struct kvm_riscv_sbi_sta) / sizeof(unsigned long); + + for (int i = 0; i < n; i++) { + u64 reg = KVM_REG_RISCV | size | + KVM_REG_RISCV_SBI_STATE | + KVM_REG_RISCV_SBI_STA | i; + + if (uindices) { + if (put_user(reg, uindices)) + return -EFAULT; + uindices++; + } + } + + total += n; + } + + return total; +} + +static inline unsigned long num_sbi_regs(struct kvm_vcpu *vcpu) +{ + return copy_sbi_reg_indices(vcpu, NULL); +} + +static inline unsigned long num_vector_regs(const struct kvm_vcpu *vcpu) +{ + if (!riscv_isa_extension_available(vcpu->arch.isa, v)) + return 0; + + /* vstart, vl, vtype, vcsr, vlenb and 32 vector regs */ + return 37; +} + +static int copy_vector_reg_indices(const struct kvm_vcpu *vcpu, + u64 __user *uindices) +{ + const struct kvm_cpu_context *cntx = &vcpu->arch.guest_context; + int n = num_vector_regs(vcpu); + u64 reg, size; + int i; + + if (n == 0) + return 0; + + /* copy vstart, vl, vtype, vcsr and vlenb */ + size = IS_ENABLED(CONFIG_32BIT) ? KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64; + for (i = 0; i < 5; i++) { + reg = KVM_REG_RISCV | size | KVM_REG_RISCV_VECTOR | i; if (uindices) { if (put_user(reg, uindices)) return -EFAULT; uindices++; } + } - reg = KVM_REG_RISCV | size | KVM_REG_RISCV_SBI_EXT | - KVM_REG_RISCV_SBI_MULTI_DIS | i; + /* vector_regs have a variable 'vlenb' size */ + size = __builtin_ctzl(cntx->vector.vlenb); + size <<= KVM_REG_SIZE_SHIFT; + for (i = 0; i < 32; i++) { + reg = KVM_REG_RISCV | KVM_REG_RISCV_VECTOR | size | + KVM_REG_RISCV_VECTOR_REG(i); if (uindices) { if (put_user(reg, uindices)) @@ -983,7 +1039,7 @@ static int copy_sbi_ext_reg_indices(u64 __user *uindices) } } - return num_sbi_ext_regs(); + return n; } /* @@ -1001,8 +1057,10 @@ unsigned long kvm_riscv_vcpu_num_regs(struct kvm_vcpu *vcpu) res += num_timer_regs(); res += num_fp_f_regs(vcpu); res += num_fp_d_regs(vcpu); + res += num_vector_regs(vcpu); res += num_isa_ext_regs(vcpu); - res += num_sbi_ext_regs(); + res += num_sbi_ext_regs(vcpu); + res += num_sbi_regs(vcpu); return res; } @@ -1045,14 +1103,25 @@ int kvm_riscv_vcpu_copy_reg_indices(struct kvm_vcpu *vcpu, return ret; uindices += ret; + ret = copy_vector_reg_indices(vcpu, uindices); + if (ret < 0) + return ret; + uindices += ret; + ret = copy_isa_ext_reg_indices(vcpu, uindices); if (ret < 0) return ret; uindices += ret; - ret = copy_sbi_ext_reg_indices(uindices); + ret = copy_sbi_ext_reg_indices(vcpu, uindices); if (ret < 0) return ret; + uindices += ret; + + ret = copy_sbi_reg_indices(vcpu, uindices); + if (ret < 0) + return ret; + uindices += ret; return 0; } @@ -1075,12 +1144,14 @@ int kvm_riscv_vcpu_set_reg(struct kvm_vcpu *vcpu, case KVM_REG_RISCV_FP_D: return kvm_riscv_vcpu_set_reg_fp(vcpu, reg, KVM_REG_RISCV_FP_D); + case KVM_REG_RISCV_VECTOR: + return kvm_riscv_vcpu_set_reg_vector(vcpu, reg); case KVM_REG_RISCV_ISA_EXT: return kvm_riscv_vcpu_set_reg_isa_ext(vcpu, reg); case KVM_REG_RISCV_SBI_EXT: return kvm_riscv_vcpu_set_reg_sbi_ext(vcpu, reg); - case KVM_REG_RISCV_VECTOR: - return kvm_riscv_vcpu_set_reg_vector(vcpu, reg); + case KVM_REG_RISCV_SBI_STATE: + return kvm_riscv_vcpu_set_reg_sbi(vcpu, reg); default: break; } @@ -1106,12 +1177,14 @@ int kvm_riscv_vcpu_get_reg(struct kvm_vcpu *vcpu, case KVM_REG_RISCV_FP_D: return kvm_riscv_vcpu_get_reg_fp(vcpu, reg, KVM_REG_RISCV_FP_D); + case KVM_REG_RISCV_VECTOR: + return kvm_riscv_vcpu_get_reg_vector(vcpu, reg); case KVM_REG_RISCV_ISA_EXT: return kvm_riscv_vcpu_get_reg_isa_ext(vcpu, reg); case KVM_REG_RISCV_SBI_EXT: return kvm_riscv_vcpu_get_reg_sbi_ext(vcpu, reg); - case KVM_REG_RISCV_VECTOR: - return kvm_riscv_vcpu_get_reg_vector(vcpu, reg); + case KVM_REG_RISCV_SBI_STATE: + return kvm_riscv_vcpu_get_reg_sbi(vcpu, reg); default: break; } diff --git a/arch/riscv/kvm/vcpu_sbi.c b/arch/riscv/kvm/vcpu_sbi.c index a04ff98085d939..72a2ffb8dcd158 100644 --- a/arch/riscv/kvm/vcpu_sbi.c +++ b/arch/riscv/kvm/vcpu_sbi.c @@ -70,6 +70,10 @@ static const struct kvm_riscv_sbi_extension_entry sbi_ext[] = { .ext_idx = KVM_RISCV_SBI_EXT_DBCN, .ext_ptr = &vcpu_sbi_ext_dbcn, }, + { + .ext_idx = KVM_RISCV_SBI_EXT_STA, + .ext_ptr = &vcpu_sbi_ext_sta, + }, { .ext_idx = KVM_RISCV_SBI_EXT_EXPERIMENTAL, .ext_ptr = &vcpu_sbi_ext_experimental, @@ -80,6 +84,34 @@ static const struct kvm_riscv_sbi_extension_entry sbi_ext[] = { }, }; +static const struct kvm_riscv_sbi_extension_entry * +riscv_vcpu_get_sbi_ext(struct kvm_vcpu *vcpu, unsigned long idx) +{ + const struct kvm_riscv_sbi_extension_entry *sext = NULL; + + if (idx >= KVM_RISCV_SBI_EXT_MAX) + return NULL; + + for (int i = 0; i < ARRAY_SIZE(sbi_ext); i++) { + if (sbi_ext[i].ext_idx == idx) { + sext = &sbi_ext[i]; + break; + } + } + + return sext; +} + +bool riscv_vcpu_supports_sbi_ext(struct kvm_vcpu *vcpu, int idx) +{ + struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context; + const struct kvm_riscv_sbi_extension_entry *sext; + + sext = riscv_vcpu_get_sbi_ext(vcpu, idx); + + return sext && scontext->ext_status[sext->ext_idx] != KVM_RISCV_SBI_EXT_STATUS_UNAVAILABLE; +} + void kvm_riscv_vcpu_sbi_forward(struct kvm_vcpu *vcpu, struct kvm_run *run) { struct kvm_cpu_context *cp = &vcpu->arch.guest_context; @@ -140,28 +172,19 @@ static int riscv_vcpu_set_sbi_ext_single(struct kvm_vcpu *vcpu, unsigned long reg_num, unsigned long reg_val) { - unsigned long i; - const struct kvm_riscv_sbi_extension_entry *sext = NULL; struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context; - - if (reg_num >= KVM_RISCV_SBI_EXT_MAX) - return -ENOENT; + const struct kvm_riscv_sbi_extension_entry *sext; if (reg_val != 1 && reg_val != 0) return -EINVAL; - for (i = 0; i < ARRAY_SIZE(sbi_ext); i++) { - if (sbi_ext[i].ext_idx == reg_num) { - sext = &sbi_ext[i]; - break; - } - } - if (!sext) + sext = riscv_vcpu_get_sbi_ext(vcpu, reg_num); + if (!sext || scontext->ext_status[sext->ext_idx] == KVM_RISCV_SBI_EXT_STATUS_UNAVAILABLE) return -ENOENT; scontext->ext_status[sext->ext_idx] = (reg_val) ? - KVM_RISCV_SBI_EXT_AVAILABLE : - KVM_RISCV_SBI_EXT_UNAVAILABLE; + KVM_RISCV_SBI_EXT_STATUS_ENABLED : + KVM_RISCV_SBI_EXT_STATUS_DISABLED; return 0; } @@ -170,24 +193,16 @@ static int riscv_vcpu_get_sbi_ext_single(struct kvm_vcpu *vcpu, unsigned long reg_num, unsigned long *reg_val) { - unsigned long i; - const struct kvm_riscv_sbi_extension_entry *sext = NULL; struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context; + const struct kvm_riscv_sbi_extension_entry *sext; - if (reg_num >= KVM_RISCV_SBI_EXT_MAX) - return -ENOENT; - - for (i = 0; i < ARRAY_SIZE(sbi_ext); i++) { - if (sbi_ext[i].ext_idx == reg_num) { - sext = &sbi_ext[i]; - break; - } - } - if (!sext) + sext = riscv_vcpu_get_sbi_ext(vcpu, reg_num); + if (!sext || scontext->ext_status[sext->ext_idx] == KVM_RISCV_SBI_EXT_STATUS_UNAVAILABLE) return -ENOENT; *reg_val = scontext->ext_status[sext->ext_idx] == - KVM_RISCV_SBI_EXT_AVAILABLE; + KVM_RISCV_SBI_EXT_STATUS_ENABLED; + return 0; } @@ -310,6 +325,69 @@ int kvm_riscv_vcpu_get_reg_sbi_ext(struct kvm_vcpu *vcpu, return 0; } +int kvm_riscv_vcpu_set_reg_sbi(struct kvm_vcpu *vcpu, + const struct kvm_one_reg *reg) +{ + unsigned long __user *uaddr = + (unsigned long __user *)(unsigned long)reg->addr; + unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | + KVM_REG_SIZE_MASK | + KVM_REG_RISCV_SBI_STATE); + unsigned long reg_subtype, reg_val; + + if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) + return -EINVAL; + + if (copy_from_user(®_val, uaddr, KVM_REG_SIZE(reg->id))) + return -EFAULT; + + reg_subtype = reg_num & KVM_REG_RISCV_SUBTYPE_MASK; + reg_num &= ~KVM_REG_RISCV_SUBTYPE_MASK; + + switch (reg_subtype) { + case KVM_REG_RISCV_SBI_STA: + return kvm_riscv_vcpu_set_reg_sbi_sta(vcpu, reg_num, reg_val); + default: + return -EINVAL; + } + + return 0; +} + +int kvm_riscv_vcpu_get_reg_sbi(struct kvm_vcpu *vcpu, + const struct kvm_one_reg *reg) +{ + unsigned long __user *uaddr = + (unsigned long __user *)(unsigned long)reg->addr; + unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | + KVM_REG_SIZE_MASK | + KVM_REG_RISCV_SBI_STATE); + unsigned long reg_subtype, reg_val; + int ret; + + if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) + return -EINVAL; + + reg_subtype = reg_num & KVM_REG_RISCV_SUBTYPE_MASK; + reg_num &= ~KVM_REG_RISCV_SUBTYPE_MASK; + + switch (reg_subtype) { + case KVM_REG_RISCV_SBI_STA: + ret = kvm_riscv_vcpu_get_reg_sbi_sta(vcpu, reg_num, ®_val); + break; + default: + return -EINVAL; + } + + if (ret) + return ret; + + if (copy_to_user(uaddr, ®_val, KVM_REG_SIZE(reg->id))) + return -EFAULT; + + return 0; +} + const struct kvm_vcpu_sbi_extension *kvm_vcpu_sbi_find_ext( struct kvm_vcpu *vcpu, unsigned long extid) { @@ -325,7 +403,7 @@ const struct kvm_vcpu_sbi_extension *kvm_vcpu_sbi_find_ext( if (ext->extid_start <= extid && ext->extid_end >= extid) { if (entry->ext_idx >= KVM_RISCV_SBI_EXT_MAX || scontext->ext_status[entry->ext_idx] == - KVM_RISCV_SBI_EXT_AVAILABLE) + KVM_RISCV_SBI_EXT_STATUS_ENABLED) return ext; return NULL; @@ -413,12 +491,12 @@ void kvm_riscv_vcpu_sbi_init(struct kvm_vcpu *vcpu) if (ext->probe && !ext->probe(vcpu)) { scontext->ext_status[entry->ext_idx] = - KVM_RISCV_SBI_EXT_UNAVAILABLE; + KVM_RISCV_SBI_EXT_STATUS_UNAVAILABLE; continue; } - scontext->ext_status[entry->ext_idx] = ext->default_unavail ? - KVM_RISCV_SBI_EXT_UNAVAILABLE : - KVM_RISCV_SBI_EXT_AVAILABLE; + scontext->ext_status[entry->ext_idx] = ext->default_disabled ? + KVM_RISCV_SBI_EXT_STATUS_DISABLED : + KVM_RISCV_SBI_EXT_STATUS_ENABLED; } } diff --git a/arch/riscv/kvm/vcpu_sbi_replace.c b/arch/riscv/kvm/vcpu_sbi_replace.c index 23b57c931b1522..9c2ab3dfa93aa5 100644 --- a/arch/riscv/kvm/vcpu_sbi_replace.c +++ b/arch/riscv/kvm/vcpu_sbi_replace.c @@ -204,6 +204,6 @@ static int kvm_sbi_ext_dbcn_handler(struct kvm_vcpu *vcpu, const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_dbcn = { .extid_start = SBI_EXT_DBCN, .extid_end = SBI_EXT_DBCN, - .default_unavail = true, + .default_disabled = true, .handler = kvm_sbi_ext_dbcn_handler, }; diff --git a/arch/riscv/kvm/vcpu_sbi_sta.c b/arch/riscv/kvm/vcpu_sbi_sta.c new file mode 100644 index 00000000000000..01f09fe8c3b020 --- /dev/null +++ b/arch/riscv/kvm/vcpu_sbi_sta.c @@ -0,0 +1,208 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023 Ventana Micro Systems Inc. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +void kvm_riscv_vcpu_sbi_sta_reset(struct kvm_vcpu *vcpu) +{ + vcpu->arch.sta.shmem = INVALID_GPA; + vcpu->arch.sta.last_steal = 0; +} + +void kvm_riscv_vcpu_record_steal_time(struct kvm_vcpu *vcpu) +{ + gpa_t shmem = vcpu->arch.sta.shmem; + u64 last_steal = vcpu->arch.sta.last_steal; + u32 *sequence_ptr, sequence; + u64 *steal_ptr, steal; + unsigned long hva; + gfn_t gfn; + + if (shmem == INVALID_GPA) + return; + + /* + * shmem is 64-byte aligned (see the enforcement in + * kvm_sbi_sta_steal_time_set_shmem()) and the size of sbi_sta_struct + * is 64 bytes, so we know all its offsets are in the same page. + */ + gfn = shmem >> PAGE_SHIFT; + hva = kvm_vcpu_gfn_to_hva(vcpu, gfn); + + if (WARN_ON(kvm_is_error_hva(hva))) { + vcpu->arch.sta.shmem = INVALID_GPA; + return; + } + + sequence_ptr = (u32 *)(hva + offset_in_page(shmem) + + offsetof(struct sbi_sta_struct, sequence)); + steal_ptr = (u64 *)(hva + offset_in_page(shmem) + + offsetof(struct sbi_sta_struct, steal)); + + if (WARN_ON(get_user(sequence, sequence_ptr))) + return; + + sequence = le32_to_cpu(sequence); + sequence += 1; + + if (WARN_ON(put_user(cpu_to_le32(sequence), sequence_ptr))) + return; + + if (!WARN_ON(get_user(steal, steal_ptr))) { + steal = le64_to_cpu(steal); + vcpu->arch.sta.last_steal = READ_ONCE(current->sched_info.run_delay); + steal += vcpu->arch.sta.last_steal - last_steal; + WARN_ON(put_user(cpu_to_le64(steal), steal_ptr)); + } + + sequence += 1; + WARN_ON(put_user(cpu_to_le32(sequence), sequence_ptr)); + + kvm_vcpu_mark_page_dirty(vcpu, gfn); +} + +static int kvm_sbi_sta_steal_time_set_shmem(struct kvm_vcpu *vcpu) +{ + struct kvm_cpu_context *cp = &vcpu->arch.guest_context; + unsigned long shmem_phys_lo = cp->a0; + unsigned long shmem_phys_hi = cp->a1; + u32 flags = cp->a2; + struct sbi_sta_struct zero_sta = {0}; + unsigned long hva; + bool writable; + gpa_t shmem; + int ret; + + if (flags != 0) + return SBI_ERR_INVALID_PARAM; + + if (shmem_phys_lo == SBI_STA_SHMEM_DISABLE && + shmem_phys_hi == SBI_STA_SHMEM_DISABLE) { + vcpu->arch.sta.shmem = INVALID_GPA; + return 0; + } + + if (shmem_phys_lo & (SZ_64 - 1)) + return SBI_ERR_INVALID_PARAM; + + shmem = shmem_phys_lo; + + if (shmem_phys_hi != 0) { + if (IS_ENABLED(CONFIG_32BIT)) + shmem |= ((gpa_t)shmem_phys_hi << 32); + else + return SBI_ERR_INVALID_ADDRESS; + } + + hva = kvm_vcpu_gfn_to_hva_prot(vcpu, shmem >> PAGE_SHIFT, &writable); + if (kvm_is_error_hva(hva) || !writable) + return SBI_ERR_INVALID_ADDRESS; + + ret = kvm_vcpu_write_guest(vcpu, shmem, &zero_sta, sizeof(zero_sta)); + if (ret) + return SBI_ERR_FAILURE; + + vcpu->arch.sta.shmem = shmem; + vcpu->arch.sta.last_steal = current->sched_info.run_delay; + + return 0; +} + +static int kvm_sbi_ext_sta_handler(struct kvm_vcpu *vcpu, struct kvm_run *run, + struct kvm_vcpu_sbi_return *retdata) +{ + struct kvm_cpu_context *cp = &vcpu->arch.guest_context; + unsigned long funcid = cp->a6; + int ret; + + switch (funcid) { + case SBI_EXT_STA_STEAL_TIME_SET_SHMEM: + ret = kvm_sbi_sta_steal_time_set_shmem(vcpu); + break; + default: + ret = SBI_ERR_NOT_SUPPORTED; + break; + } + + retdata->err_val = ret; + + return 0; +} + +static unsigned long kvm_sbi_ext_sta_probe(struct kvm_vcpu *vcpu) +{ + return !!sched_info_on(); +} + +const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_sta = { + .extid_start = SBI_EXT_STA, + .extid_end = SBI_EXT_STA, + .handler = kvm_sbi_ext_sta_handler, + .probe = kvm_sbi_ext_sta_probe, +}; + +int kvm_riscv_vcpu_get_reg_sbi_sta(struct kvm_vcpu *vcpu, + unsigned long reg_num, + unsigned long *reg_val) +{ + switch (reg_num) { + case KVM_REG_RISCV_SBI_STA_REG(shmem_lo): + *reg_val = (unsigned long)vcpu->arch.sta.shmem; + break; + case KVM_REG_RISCV_SBI_STA_REG(shmem_hi): + if (IS_ENABLED(CONFIG_32BIT)) + *reg_val = upper_32_bits(vcpu->arch.sta.shmem); + else + *reg_val = 0; + break; + default: + return -EINVAL; + } + + return 0; +} + +int kvm_riscv_vcpu_set_reg_sbi_sta(struct kvm_vcpu *vcpu, + unsigned long reg_num, + unsigned long reg_val) +{ + switch (reg_num) { + case KVM_REG_RISCV_SBI_STA_REG(shmem_lo): + if (IS_ENABLED(CONFIG_32BIT)) { + gpa_t hi = upper_32_bits(vcpu->arch.sta.shmem); + + vcpu->arch.sta.shmem = reg_val; + vcpu->arch.sta.shmem |= hi << 32; + } else { + vcpu->arch.sta.shmem = reg_val; + } + break; + case KVM_REG_RISCV_SBI_STA_REG(shmem_hi): + if (IS_ENABLED(CONFIG_32BIT)) { + gpa_t lo = lower_32_bits(vcpu->arch.sta.shmem); + + vcpu->arch.sta.shmem = ((gpa_t)reg_val << 32); + vcpu->arch.sta.shmem |= lo; + } else if (reg_val != 0) { + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + return 0; +} diff --git a/arch/riscv/kvm/vcpu_switch.S b/arch/riscv/kvm/vcpu_switch.S index d74df8eb4d71a5..0c26189aa01cf5 100644 --- a/arch/riscv/kvm/vcpu_switch.S +++ b/arch/riscv/kvm/vcpu_switch.S @@ -15,7 +15,7 @@ .altmacro .option norelax -ENTRY(__kvm_riscv_switch_to) +SYM_FUNC_START(__kvm_riscv_switch_to) /* Save Host GPRs (except A0 and T0-T6) */ REG_S ra, (KVM_ARCH_HOST_RA)(a0) REG_S sp, (KVM_ARCH_HOST_SP)(a0) @@ -45,7 +45,7 @@ ENTRY(__kvm_riscv_switch_to) REG_L t0, (KVM_ARCH_GUEST_SSTATUS)(a0) REG_L t1, (KVM_ARCH_GUEST_HSTATUS)(a0) REG_L t2, (KVM_ARCH_GUEST_SCOUNTEREN)(a0) - la t4, __kvm_switch_return + la t4, .Lkvm_switch_return REG_L t5, (KVM_ARCH_GUEST_SEPC)(a0) /* Save Host and Restore Guest SSTATUS */ @@ -113,7 +113,7 @@ ENTRY(__kvm_riscv_switch_to) /* Back to Host */ .align 2 -__kvm_switch_return: +.Lkvm_switch_return: /* Swap Guest A0 with SSCRATCH */ csrrw a0, CSR_SSCRATCH, a0 @@ -208,9 +208,9 @@ __kvm_switch_return: /* Return to C code */ ret -ENDPROC(__kvm_riscv_switch_to) +SYM_FUNC_END(__kvm_riscv_switch_to) -ENTRY(__kvm_riscv_unpriv_trap) +SYM_CODE_START(__kvm_riscv_unpriv_trap) /* * We assume that faulting unpriv load/store instruction is * 4-byte long and blindly increment SEPC by 4. @@ -231,12 +231,10 @@ ENTRY(__kvm_riscv_unpriv_trap) csrr a1, CSR_HTINST REG_S a1, (KVM_ARCH_TRAP_HTINST)(a0) sret -ENDPROC(__kvm_riscv_unpriv_trap) +SYM_CODE_END(__kvm_riscv_unpriv_trap) #ifdef CONFIG_FPU - .align 3 - .global __kvm_riscv_fp_f_save -__kvm_riscv_fp_f_save: +SYM_FUNC_START(__kvm_riscv_fp_f_save) csrr t2, CSR_SSTATUS li t1, SR_FS csrs CSR_SSTATUS, t1 @@ -276,10 +274,9 @@ __kvm_riscv_fp_f_save: sw t0, KVM_ARCH_FP_F_FCSR(a0) csrw CSR_SSTATUS, t2 ret +SYM_FUNC_END(__kvm_riscv_fp_f_save) - .align 3 - .global __kvm_riscv_fp_d_save -__kvm_riscv_fp_d_save: +SYM_FUNC_START(__kvm_riscv_fp_d_save) csrr t2, CSR_SSTATUS li t1, SR_FS csrs CSR_SSTATUS, t1 @@ -319,10 +316,9 @@ __kvm_riscv_fp_d_save: sw t0, KVM_ARCH_FP_D_FCSR(a0) csrw CSR_SSTATUS, t2 ret +SYM_FUNC_END(__kvm_riscv_fp_d_save) - .align 3 - .global __kvm_riscv_fp_f_restore -__kvm_riscv_fp_f_restore: +SYM_FUNC_START(__kvm_riscv_fp_f_restore) csrr t2, CSR_SSTATUS li t1, SR_FS lw t0, KVM_ARCH_FP_F_FCSR(a0) @@ -362,10 +358,9 @@ __kvm_riscv_fp_f_restore: fscsr t0 csrw CSR_SSTATUS, t2 ret +SYM_FUNC_END(__kvm_riscv_fp_f_restore) - .align 3 - .global __kvm_riscv_fp_d_restore -__kvm_riscv_fp_d_restore: +SYM_FUNC_START(__kvm_riscv_fp_d_restore) csrr t2, CSR_SSTATUS li t1, SR_FS lw t0, KVM_ARCH_FP_D_FCSR(a0) @@ -405,4 +400,5 @@ __kvm_riscv_fp_d_restore: fscsr t0 csrw CSR_SSTATUS, t2 ret +SYM_FUNC_END(__kvm_riscv_fp_d_restore) #endif diff --git a/arch/riscv/kvm/vcpu_vector.c b/arch/riscv/kvm/vcpu_vector.c index b339a2682f252b..d92d1348045c8c 100644 --- a/arch/riscv/kvm/vcpu_vector.c +++ b/arch/riscv/kvm/vcpu_vector.c @@ -76,6 +76,7 @@ int kvm_riscv_vcpu_alloc_vector_context(struct kvm_vcpu *vcpu, cntx->vector.datap = kmalloc(riscv_v_vsize, GFP_KERNEL); if (!cntx->vector.datap) return -ENOMEM; + cntx->vector.vlenb = riscv_v_vsize / 32; vcpu->arch.host_context.vector.datap = kzalloc(riscv_v_vsize, GFP_KERNEL); if (!vcpu->arch.host_context.vector.datap) @@ -115,6 +116,9 @@ static int kvm_riscv_vcpu_vreg_addr(struct kvm_vcpu *vcpu, case KVM_REG_RISCV_VECTOR_CSR_REG(vcsr): *reg_addr = &cntx->vector.vcsr; break; + case KVM_REG_RISCV_VECTOR_CSR_REG(vlenb): + *reg_addr = &cntx->vector.vlenb; + break; case KVM_REG_RISCV_VECTOR_CSR_REG(datap): default: return -ENOENT; @@ -173,6 +177,18 @@ int kvm_riscv_vcpu_set_reg_vector(struct kvm_vcpu *vcpu, if (!riscv_isa_extension_available(isa, v)) return -ENOENT; + if (reg_num == KVM_REG_RISCV_VECTOR_CSR_REG(vlenb)) { + struct kvm_cpu_context *cntx = &vcpu->arch.guest_context; + unsigned long reg_val; + + if (copy_from_user(®_val, uaddr, reg_size)) + return -EFAULT; + if (reg_val != cntx->vector.vlenb) + return -EINVAL; + + return 0; + } + rc = kvm_riscv_vcpu_vreg_addr(vcpu, reg_num, reg_size, ®_addr); if (rc) return rc; diff --git a/arch/riscv/kvm/vm.c b/arch/riscv/kvm/vm.c index 7e2b50c692c1bb..ce58bc48e5b87b 100644 --- a/arch/riscv/kvm/vm.c +++ b/arch/riscv/kvm/vm.c @@ -179,7 +179,6 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) r = kvm_riscv_aia_available(); break; case KVM_CAP_IOEVENTFD: - case KVM_CAP_DEVICE_CTRL: case KVM_CAP_USER_MEMORY: case KVM_CAP_SYNC_MMU: case KVM_CAP_DESTROY_MEMORY_REGION_WORKS: diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile index 26cb2502ecf896..bd6e6c1b0497b4 100644 --- a/arch/riscv/lib/Makefile +++ b/arch/riscv/lib/Makefile @@ -6,8 +6,14 @@ lib-y += memmove.o lib-y += strcmp.o lib-y += strlen.o lib-y += strncmp.o +lib-y += csum.o +ifeq ($(CONFIG_MMU), y) +lib-$(CONFIG_RISCV_ISA_V) += uaccess_vector.o +endif lib-$(CONFIG_MMU) += uaccess.o lib-$(CONFIG_64BIT) += tishift.o lib-$(CONFIG_RISCV_ISA_ZICBOZ) += clear_page.o obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o +lib-$(CONFIG_RISCV_ISA_V) += xor.o +lib-$(CONFIG_RISCV_ISA_V) += riscv_v_helpers.o diff --git a/arch/riscv/lib/clear_page.S b/arch/riscv/lib/clear_page.S index b22de1231144c2..20ff03f5b0f23e 100644 --- a/arch/riscv/lib/clear_page.S +++ b/arch/riscv/lib/clear_page.S @@ -4,9 +4,9 @@ */ #include +#include #include #include -#include #include #include #include diff --git a/arch/riscv/lib/csum.c b/arch/riscv/lib/csum.c new file mode 100644 index 00000000000000..af3df5274ccbae --- /dev/null +++ b/arch/riscv/lib/csum.c @@ -0,0 +1,328 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Checksum library + * + * Influenced by arch/arm64/lib/csum.c + * Copyright (C) 2023 Rivos Inc. + */ +#include +#include +#include +#include +#include + +#include + +#include + +/* Default version is sufficient for 32 bit */ +#ifndef CONFIG_32BIT +__sum16 csum_ipv6_magic(const struct in6_addr *saddr, + const struct in6_addr *daddr, + __u32 len, __u8 proto, __wsum csum) +{ + unsigned int ulen, uproto; + unsigned long sum = (__force unsigned long)csum; + + sum += (__force unsigned long)saddr->s6_addr32[0]; + sum += (__force unsigned long)saddr->s6_addr32[1]; + sum += (__force unsigned long)saddr->s6_addr32[2]; + sum += (__force unsigned long)saddr->s6_addr32[3]; + + sum += (__force unsigned long)daddr->s6_addr32[0]; + sum += (__force unsigned long)daddr->s6_addr32[1]; + sum += (__force unsigned long)daddr->s6_addr32[2]; + sum += (__force unsigned long)daddr->s6_addr32[3]; + + ulen = (__force unsigned int)htonl((unsigned int)len); + sum += ulen; + + uproto = (__force unsigned int)htonl(proto); + sum += uproto; + + /* + * Zbb support saves 4 instructions, so not worth checking without + * alternatives if supported + */ + if (IS_ENABLED(CONFIG_RISCV_ISA_ZBB) && + IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) { + unsigned long fold_temp; + + /* + * Zbb is likely available when the kernel is compiled with Zbb + * support, so nop when Zbb is available and jump when Zbb is + * not available. + */ + asm_volatile_goto(ALTERNATIVE("j %l[no_zbb]", "nop", 0, + RISCV_ISA_EXT_ZBB, 1) + : + : + : + : no_zbb); + asm(".option push \n\ + .option arch,+zbb \n\ + rori %[fold_temp], %[sum], 32 \n\ + add %[sum], %[fold_temp], %[sum] \n\ + srli %[sum], %[sum], 32 \n\ + not %[fold_temp], %[sum] \n\ + roriw %[sum], %[sum], 16 \n\ + subw %[sum], %[fold_temp], %[sum] \n\ + .option pop" + : [sum] "+r" (sum), [fold_temp] "=&r" (fold_temp)); + return (__force __sum16)(sum >> 16); + } +no_zbb: + sum += ror64(sum, 32); + sum >>= 32; + return csum_fold((__force __wsum)sum); +} +EXPORT_SYMBOL(csum_ipv6_magic); +#endif /* !CONFIG_32BIT */ + +#ifdef CONFIG_32BIT +#define OFFSET_MASK 3 +#elif CONFIG_64BIT +#define OFFSET_MASK 7 +#endif + +static inline __no_sanitize_address unsigned long +do_csum_common(const unsigned long *ptr, const unsigned long *end, + unsigned long data) +{ + unsigned int shift; + unsigned long csum = 0, carry = 0; + + /* + * Do 32-bit reads on RV32 and 64-bit reads otherwise. This should be + * faster than doing 32-bit reads on architectures that support larger + * reads. + */ + while (ptr < end) { + csum += data; + carry += csum < data; + data = *(ptr++); + } + + /* + * Perform alignment (and over-read) bytes on the tail if any bytes + * leftover. + */ + shift = ((long)ptr - (long)end) * 8; +#ifdef __LITTLE_ENDIAN + data = (data << shift) >> shift; +#else + data = (data >> shift) << shift; +#endif + csum += data; + carry += csum < data; + csum += carry; + csum += csum < carry; + + return csum; +} + +/* + * Algorithm accounts for buff being misaligned. + * If buff is not aligned, will over-read bytes but not use the bytes that it + * shouldn't. The same thing will occur on the tail-end of the read. + */ +static inline __no_sanitize_address unsigned int +do_csum_with_alignment(const unsigned char *buff, int len) +{ + unsigned int offset, shift; + unsigned long csum, data; + const unsigned long *ptr, *end; + + /* + * Align address to closest word (double word on rv64) that comes before + * buff. This should always be in the same page and cache line. + * Directly call KASAN with the alignment we will be using. + */ + offset = (unsigned long)buff & OFFSET_MASK; + kasan_check_read(buff, len); + ptr = (const unsigned long *)(buff - offset); + + /* + * Clear the most significant bytes that were over-read if buff was not + * aligned. + */ + shift = offset * 8; + data = *(ptr++); +#ifdef __LITTLE_ENDIAN + data = (data >> shift) << shift; +#else + data = (data << shift) >> shift; +#endif + end = (const unsigned long *)(buff + len); + csum = do_csum_common(ptr, end, data); + +#ifdef CC_HAS_ASM_GOTO_TIED_OUTPUT + /* + * Zbb support saves 6 instructions, so not worth checking without + * alternatives if supported + */ + if (IS_ENABLED(CONFIG_RISCV_ISA_ZBB) && + IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) { + unsigned long fold_temp; + + /* + * Zbb is likely available when the kernel is compiled with Zbb + * support, so nop when Zbb is available and jump when Zbb is + * not available. + */ + asm_volatile_goto(ALTERNATIVE("j %l[no_zbb]", "nop", 0, + RISCV_ISA_EXT_ZBB, 1) + : + : + : + : no_zbb); + +#ifdef CONFIG_32BIT + asm_volatile_goto(".option push \n\ + .option arch,+zbb \n\ + rori %[fold_temp], %[csum], 16 \n\ + andi %[offset], %[offset], 1 \n\ + add %[csum], %[fold_temp], %[csum] \n\ + beq %[offset], zero, %l[end] \n\ + rev8 %[csum], %[csum] \n\ + .option pop" + : [csum] "+r" (csum), [fold_temp] "=&r" (fold_temp) + : [offset] "r" (offset) + : + : end); + + return (unsigned short)csum; +#else /* !CONFIG_32BIT */ + asm_volatile_goto(".option push \n\ + .option arch,+zbb \n\ + rori %[fold_temp], %[csum], 32 \n\ + add %[csum], %[fold_temp], %[csum] \n\ + srli %[csum], %[csum], 32 \n\ + roriw %[fold_temp], %[csum], 16 \n\ + addw %[csum], %[fold_temp], %[csum] \n\ + andi %[offset], %[offset], 1 \n\ + beq %[offset], zero, %l[end] \n\ + rev8 %[csum], %[csum] \n\ + .option pop" + : [csum] "+r" (csum), [fold_temp] "=&r" (fold_temp) + : [offset] "r" (offset) + : + : end); + + return (csum << 16) >> 48; +#endif /* !CONFIG_32BIT */ +end: + return csum >> 16; + } +no_zbb: +#endif /* CC_HAS_ASM_GOTO_TIED_OUTPUT */ +#ifndef CONFIG_32BIT + csum += ror64(csum, 32); + csum >>= 32; +#endif + csum = (u32)csum + ror32((u32)csum, 16); + if (offset & 1) + return (u16)swab32(csum); + return csum >> 16; +} + +/* + * Does not perform alignment, should only be used if machine has fast + * misaligned accesses, or when buff is known to be aligned. + */ +static inline __no_sanitize_address unsigned int +do_csum_no_alignment(const unsigned char *buff, int len) +{ + unsigned long csum, data; + const unsigned long *ptr, *end; + + ptr = (const unsigned long *)(buff); + data = *(ptr++); + + kasan_check_read(buff, len); + + end = (const unsigned long *)(buff + len); + csum = do_csum_common(ptr, end, data); + + /* + * Zbb support saves 6 instructions, so not worth checking without + * alternatives if supported + */ + if (IS_ENABLED(CONFIG_RISCV_ISA_ZBB) && + IS_ENABLED(CONFIG_RISCV_ALTERNATIVE)) { + unsigned long fold_temp; + + /* + * Zbb is likely available when the kernel is compiled with Zbb + * support, so nop when Zbb is available and jump when Zbb is + * not available. + */ + asm_volatile_goto(ALTERNATIVE("j %l[no_zbb]", "nop", 0, + RISCV_ISA_EXT_ZBB, 1) + : + : + : + : no_zbb); + +#ifdef CONFIG_32BIT + asm (".option push \n\ + .option arch,+zbb \n\ + rori %[fold_temp], %[csum], 16 \n\ + add %[csum], %[fold_temp], %[csum] \n\ + .option pop" + : [csum] "+r" (csum), [fold_temp] "=&r" (fold_temp) + : + : ); + +#else /* !CONFIG_32BIT */ + asm (".option push \n\ + .option arch,+zbb \n\ + rori %[fold_temp], %[csum], 32 \n\ + add %[csum], %[fold_temp], %[csum] \n\ + srli %[csum], %[csum], 32 \n\ + roriw %[fold_temp], %[csum], 16 \n\ + addw %[csum], %[fold_temp], %[csum] \n\ + .option pop" + : [csum] "+r" (csum), [fold_temp] "=&r" (fold_temp) + : + : ); +#endif /* !CONFIG_32BIT */ + return csum >> 16; + } +no_zbb: +#ifndef CONFIG_32BIT + csum += ror64(csum, 32); + csum >>= 32; +#endif + csum = (u32)csum + ror32((u32)csum, 16); + return csum >> 16; +} + +/* + * Perform a checksum on an arbitrary memory address. + * Will do a light-weight address alignment if buff is misaligned, unless + * cpu supports fast misaligned accesses. + */ +unsigned int do_csum(const unsigned char *buff, int len) +{ + if (unlikely(len <= 0)) + return 0; + + /* + * Significant performance gains can be seen by not doing alignment + * on machines with fast misaligned accesses. + * + * There is some duplicate code between the "with_alignment" and + * "no_alignment" implmentations, but the overlap is too awkward to be + * able to fit in one function without introducing multiple static + * branches. The largest chunk of overlap was delegated into the + * do_csum_common function. + */ + if (static_branch_likely(&fast_misaligned_access_speed_key)) + return do_csum_no_alignment(buff, len); + + if (((unsigned long)buff & OFFSET_MASK) == 0) + return do_csum_no_alignment(buff, len); + + return do_csum_with_alignment(buff, len); +} diff --git a/arch/riscv/lib/riscv_v_helpers.c b/arch/riscv/lib/riscv_v_helpers.c new file mode 100644 index 00000000000000..be38a93cedaec5 --- /dev/null +++ b/arch/riscv/lib/riscv_v_helpers.c @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 SiFive + * Author: Andy Chiu + */ +#include +#include + +#include +#include + +#ifdef CONFIG_MMU +#include +#endif + +#ifdef CONFIG_MMU +size_t riscv_v_usercopy_threshold = CONFIG_RISCV_ISA_V_UCOPY_THRESHOLD; +int __asm_vector_usercopy(void *dst, void *src, size_t n); +int fallback_scalar_usercopy(void *dst, void *src, size_t n); +asmlinkage int enter_vector_usercopy(void *dst, void *src, size_t n) +{ + size_t remain, copied; + + /* skip has_vector() check because it has been done by the asm */ + if (!may_use_simd()) + goto fallback; + + kernel_vector_begin(); + remain = __asm_vector_usercopy(dst, src, n); + kernel_vector_end(); + + if (remain) { + copied = n - remain; + dst += copied; + src += copied; + n = remain; + goto fallback; + } + + return remain; + +fallback: + return fallback_scalar_usercopy(dst, src, n); +} +#endif diff --git a/arch/riscv/lib/tishift.S b/arch/riscv/lib/tishift.S index ef90075c4b0a9c..c8294bf72c0644 100644 --- a/arch/riscv/lib/tishift.S +++ b/arch/riscv/lib/tishift.S @@ -4,7 +4,7 @@ */ #include -#include +#include SYM_FUNC_START(__lshrti3) beqz a2, .L1 diff --git a/arch/riscv/lib/uaccess.S b/arch/riscv/lib/uaccess.S index 3ab438f30d1328..bc22c078aba81a 100644 --- a/arch/riscv/lib/uaccess.S +++ b/arch/riscv/lib/uaccess.S @@ -1,8 +1,10 @@ #include -#include +#include #include #include #include +#include +#include .macro fixup op reg addr lbl 100: @@ -11,6 +13,13 @@ .endm SYM_FUNC_START(__asm_copy_to_user) +#ifdef CONFIG_RISCV_ISA_V + ALTERNATIVE("j fallback_scalar_usercopy", "nop", 0, RISCV_ISA_EXT_v, CONFIG_RISCV_ISA_V) + REG_L t0, riscv_v_usercopy_threshold + bltu a2, t0, fallback_scalar_usercopy + tail enter_vector_usercopy +#endif +SYM_FUNC_START(fallback_scalar_usercopy) /* Enable access to user memory */ li t6, SR_SUM @@ -181,6 +190,7 @@ SYM_FUNC_START(__asm_copy_to_user) sub a0, t5, a0 ret SYM_FUNC_END(__asm_copy_to_user) +SYM_FUNC_END(fallback_scalar_usercopy) EXPORT_SYMBOL(__asm_copy_to_user) SYM_FUNC_ALIAS(__asm_copy_from_user, __asm_copy_to_user) EXPORT_SYMBOL(__asm_copy_from_user) diff --git a/arch/riscv/lib/uaccess_vector.S b/arch/riscv/lib/uaccess_vector.S new file mode 100644 index 00000000000000..51ab5588e9ff36 --- /dev/null +++ b/arch/riscv/lib/uaccess_vector.S @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include +#include +#include +#include +#include + +#define pDst a0 +#define pSrc a1 +#define iNum a2 + +#define iVL a3 + +#define ELEM_LMUL_SETTING m8 +#define vData v0 + + .macro fixup op reg addr lbl +100: + \op \reg, \addr + _asm_extable 100b, \lbl + .endm + +SYM_FUNC_START(__asm_vector_usercopy) + /* Enable access to user memory */ + li t6, SR_SUM + csrs CSR_STATUS, t6 + +loop: + vsetvli iVL, iNum, e8, ELEM_LMUL_SETTING, ta, ma + fixup vle8.v vData, (pSrc), 10f + sub iNum, iNum, iVL + add pSrc, pSrc, iVL + fixup vse8.v vData, (pDst), 11f + add pDst, pDst, iVL + bnez iNum, loop + + /* Exception fixup for vector load is shared with normal exit */ +10: + /* Disable access to user memory */ + csrc CSR_STATUS, t6 + mv a0, iNum + ret + + /* Exception fixup code for vector store. */ +11: + /* Undo the subtraction after vle8.v */ + add iNum, iNum, iVL + /* Make sure the scalar fallback skip already processed bytes */ + csrr t2, CSR_VSTART + sub iNum, iNum, t2 + j 10b +SYM_FUNC_END(__asm_vector_usercopy) diff --git a/arch/riscv/lib/xor.S b/arch/riscv/lib/xor.S new file mode 100644 index 00000000000000..b28f2430e52fa5 --- /dev/null +++ b/arch/riscv/lib/xor.S @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2021 SiFive + */ +#include +#include +#include + +SYM_FUNC_START(xor_regs_2_) + vsetvli a3, a0, e8, m8, ta, ma + vle8.v v0, (a1) + vle8.v v8, (a2) + sub a0, a0, a3 + vxor.vv v16, v0, v8 + add a2, a2, a3 + vse8.v v16, (a1) + add a1, a1, a3 + bnez a0, xor_regs_2_ + ret +SYM_FUNC_END(xor_regs_2_) +EXPORT_SYMBOL(xor_regs_2_) + +SYM_FUNC_START(xor_regs_3_) + vsetvli a4, a0, e8, m8, ta, ma + vle8.v v0, (a1) + vle8.v v8, (a2) + sub a0, a0, a4 + vxor.vv v0, v0, v8 + vle8.v v16, (a3) + add a2, a2, a4 + vxor.vv v16, v0, v16 + add a3, a3, a4 + vse8.v v16, (a1) + add a1, a1, a4 + bnez a0, xor_regs_3_ + ret +SYM_FUNC_END(xor_regs_3_) +EXPORT_SYMBOL(xor_regs_3_) + +SYM_FUNC_START(xor_regs_4_) + vsetvli a5, a0, e8, m8, ta, ma + vle8.v v0, (a1) + vle8.v v8, (a2) + sub a0, a0, a5 + vxor.vv v0, v0, v8 + vle8.v v16, (a3) + add a2, a2, a5 + vxor.vv v0, v0, v16 + vle8.v v24, (a4) + add a3, a3, a5 + vxor.vv v16, v0, v24 + add a4, a4, a5 + vse8.v v16, (a1) + add a1, a1, a5 + bnez a0, xor_regs_4_ + ret +SYM_FUNC_END(xor_regs_4_) +EXPORT_SYMBOL(xor_regs_4_) + +SYM_FUNC_START(xor_regs_5_) + vsetvli a6, a0, e8, m8, ta, ma + vle8.v v0, (a1) + vle8.v v8, (a2) + sub a0, a0, a6 + vxor.vv v0, v0, v8 + vle8.v v16, (a3) + add a2, a2, a6 + vxor.vv v0, v0, v16 + vle8.v v24, (a4) + add a3, a3, a6 + vxor.vv v0, v0, v24 + vle8.v v8, (a5) + add a4, a4, a6 + vxor.vv v16, v0, v8 + add a5, a5, a6 + vse8.v v16, (a1) + add a1, a1, a6 + bnez a0, xor_regs_5_ + ret +SYM_FUNC_END(xor_regs_5_) +EXPORT_SYMBOL(xor_regs_5_) diff --git a/arch/riscv/mm/Makefile b/arch/riscv/mm/Makefile index 3a4dfc8babcf8c..2c869f8026a889 100644 --- a/arch/riscv/mm/Makefile +++ b/arch/riscv/mm/Makefile @@ -13,10 +13,9 @@ endif KCOV_INSTRUMENT_init.o := n obj-y += init.o -obj-$(CONFIG_MMU) += extable.o fault.o pageattr.o +obj-$(CONFIG_MMU) += extable.o fault.o pageattr.o pgtable.o obj-y += cacheflush.o obj-y += context.o -obj-y += pgtable.o obj-y += pmem.o ifeq ($(CONFIG_MMU),y) diff --git a/arch/riscv/mm/dma-noncoherent.c b/arch/riscv/mm/dma-noncoherent.c index 4e4e469b8dd66c..843107f834b231 100644 --- a/arch/riscv/mm/dma-noncoherent.c +++ b/arch/riscv/mm/dma-noncoherent.c @@ -129,7 +129,7 @@ void arch_dma_prep_coherent(struct page *page, size_t size) } void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size, - const struct iommu_ops *iommu, bool coherent) + bool coherent) { WARN_TAINT(!coherent && riscv_cbom_block_size > ARCH_DMA_MINALIGN, TAINT_CPU_OUT_OF_SPEC, diff --git a/arch/riscv/mm/extable.c b/arch/riscv/mm/extable.c index 35484d830fd6d7..dd1530af3ef15b 100644 --- a/arch/riscv/mm/extable.c +++ b/arch/riscv/mm/extable.c @@ -27,6 +27,14 @@ static bool ex_handler_fixup(const struct exception_table_entry *ex, return true; } +static inline unsigned long regs_get_gpr(struct pt_regs *regs, unsigned int offset) +{ + if (unlikely(!offset || offset > MAX_REG_OFFSET)) + return 0; + + return *(unsigned long *)((unsigned long)regs + offset); +} + static inline void regs_set_gpr(struct pt_regs *regs, unsigned int offset, unsigned long val) { @@ -50,6 +58,27 @@ static bool ex_handler_uaccess_err_zero(const struct exception_table_entry *ex, return true; } +static bool +ex_handler_load_unaligned_zeropad(const struct exception_table_entry *ex, + struct pt_regs *regs) +{ + int reg_data = FIELD_GET(EX_DATA_REG_DATA, ex->data); + int reg_addr = FIELD_GET(EX_DATA_REG_ADDR, ex->data); + unsigned long data, addr, offset; + + addr = regs_get_gpr(regs, reg_addr * sizeof(unsigned long)); + + offset = addr & 0x7UL; + addr &= ~0x7UL; + + data = *(unsigned long *)addr >> (offset * 8); + + regs_set_gpr(regs, reg_data * sizeof(unsigned long), data); + + regs->epc = get_ex_fixup(ex); + return true; +} + bool fixup_exception(struct pt_regs *regs) { const struct exception_table_entry *ex; @@ -65,6 +94,8 @@ bool fixup_exception(struct pt_regs *regs) return ex_handler_bpf(ex, regs); case EX_TYPE_UACCESS_ERR_ZERO: return ex_handler_uaccess_err_zero(ex, regs); + case EX_TYPE_LOAD_UNALIGNED_ZEROPAD: + return ex_handler_load_unaligned_zeropad(ex, regs); } BUG(); diff --git a/arch/riscv/mm/fault.c b/arch/riscv/mm/fault.c index 081339ddf47ef4..3ba1d4dde5dd1a 100644 --- a/arch/riscv/mm/fault.c +++ b/arch/riscv/mm/fault.c @@ -136,24 +136,24 @@ static inline void vmalloc_fault(struct pt_regs *regs, int code, unsigned long a pgd = (pgd_t *)pfn_to_virt(pfn) + index; pgd_k = init_mm.pgd + index; - if (!pgd_present(*pgd_k)) { + if (!pgd_present(pgdp_get(pgd_k))) { no_context(regs, addr); return; } - set_pgd(pgd, *pgd_k); + set_pgd(pgd, pgdp_get(pgd_k)); p4d_k = p4d_offset(pgd_k, addr); - if (!p4d_present(*p4d_k)) { + if (!p4d_present(p4dp_get(p4d_k))) { no_context(regs, addr); return; } pud_k = pud_offset(p4d_k, addr); - if (!pud_present(*pud_k)) { + if (!pud_present(pudp_get(pud_k))) { no_context(regs, addr); return; } - if (pud_leaf(*pud_k)) + if (pud_leaf(pudp_get(pud_k))) goto flush_tlb; /* @@ -161,11 +161,11 @@ static inline void vmalloc_fault(struct pt_regs *regs, int code, unsigned long a * to copy individual PTEs */ pmd_k = pmd_offset(pud_k, addr); - if (!pmd_present(*pmd_k)) { + if (!pmd_present(pmdp_get(pmd_k))) { no_context(regs, addr); return; } - if (pmd_leaf(*pmd_k)) + if (pmd_leaf(pmdp_get(pmd_k))) goto flush_tlb; /* @@ -175,7 +175,7 @@ static inline void vmalloc_fault(struct pt_regs *regs, int code, unsigned long a * silently loop forever. */ pte_k = pte_offset_kernel(pmd_k, addr); - if (!pte_present(*pte_k)) { + if (!pte_present(ptep_get(pte_k))) { no_context(regs, addr); return; } diff --git a/arch/riscv/mm/hugetlbpage.c b/arch/riscv/mm/hugetlbpage.c index b52f0210481fac..431596c0e20e04 100644 --- a/arch/riscv/mm/hugetlbpage.c +++ b/arch/riscv/mm/hugetlbpage.c @@ -54,7 +54,7 @@ pte_t *huge_pte_alloc(struct mm_struct *mm, } if (sz == PMD_SIZE) { - if (want_pmd_share(vma, addr) && pud_none(*pud)) + if (want_pmd_share(vma, addr) && pud_none(pudp_get(pud))) pte = huge_pmd_share(mm, vma, addr, pud); else pte = (pte_t *)pmd_alloc(mm, pud, addr); @@ -93,11 +93,11 @@ pte_t *huge_pte_offset(struct mm_struct *mm, pmd_t *pmd; pgd = pgd_offset(mm, addr); - if (!pgd_present(*pgd)) + if (!pgd_present(pgdp_get(pgd))) return NULL; p4d = p4d_offset(pgd, addr); - if (!p4d_present(*p4d)) + if (!p4d_present(p4dp_get(p4d))) return NULL; pud = pud_offset(p4d, addr); @@ -105,7 +105,7 @@ pte_t *huge_pte_offset(struct mm_struct *mm, /* must be pud huge, non-present or none */ return (pte_t *)pud; - if (!pud_present(*pud)) + if (!pud_present(pudp_get(pud))) return NULL; pmd = pmd_offset(pud, addr); @@ -113,7 +113,7 @@ pte_t *huge_pte_offset(struct mm_struct *mm, /* must be pmd huge, non-present or none */ return (pte_t *)pmd; - if (!pmd_present(*pmd)) + if (!pmd_present(pmdp_get(pmd))) return NULL; for_each_napot_order(order) { @@ -293,7 +293,7 @@ void huge_pte_clear(struct mm_struct *mm, pte_t *ptep, unsigned long sz) { - pte_t pte = READ_ONCE(*ptep); + pte_t pte = ptep_get(ptep); int i, pte_num; if (!pte_napot(pte)) { diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c index 2e011cbddf3af3..32cad6a65ccd23 100644 --- a/arch/riscv/mm/init.c +++ b/arch/riscv/mm/init.c @@ -174,6 +174,9 @@ void __init mem_init(void) /* Limit the memory size via mem. */ static phys_addr_t memory_limit; +#ifdef CONFIG_XIP_KERNEL +#define memory_limit (*(phys_addr_t *)XIP_FIXUP(&memory_limit)) +#endif /* CONFIG_XIP_KERNEL */ static int __init early_mem(char *p) { @@ -952,7 +955,7 @@ static void __init create_fdt_early_page_table(uintptr_t fix_fdt_va, * setup_vm_final installs the linear mapping. For 32-bit kernel, as the * kernel is mapped in the linear mapping, that makes no difference. */ - dtb_early_va = kernel_mapping_pa_to_va(XIP_FIXUP(dtb_pa)); + dtb_early_va = kernel_mapping_pa_to_va(dtb_pa); #endif dtb_early_pa = dtb_pa; @@ -1055,9 +1058,13 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa) #endif kernel_map.virt_addr = KERNEL_LINK_ADDR + kernel_map.virt_offset; - kernel_map.page_offset = _AC(CONFIG_PAGE_OFFSET, UL); #ifdef CONFIG_XIP_KERNEL +#ifdef CONFIG_64BIT + kernel_map.page_offset = PAGE_OFFSET_L3; +#else + kernel_map.page_offset = _AC(CONFIG_PAGE_OFFSET, UL); +#endif kernel_map.xiprom = (uintptr_t)CONFIG_XIP_PHYS_ADDR; kernel_map.xiprom_sz = (uintptr_t)(&_exiprom) - (uintptr_t)(&_xiprom); @@ -1067,6 +1074,7 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa) kernel_map.va_kernel_xip_pa_offset = kernel_map.virt_addr - kernel_map.xiprom; #else + kernel_map.page_offset = _AC(CONFIG_PAGE_OFFSET, UL); kernel_map.phys_addr = (uintptr_t)(&_start); kernel_map.size = (uintptr_t)(&_end) - kernel_map.phys_addr; #endif @@ -1383,10 +1391,29 @@ void __init misc_mem_init(void) } #ifdef CONFIG_SPARSEMEM_VMEMMAP +void __meminit vmemmap_set_pmd(pmd_t *pmd, void *p, int node, + unsigned long addr, unsigned long next) +{ + pmd_set_huge(pmd, virt_to_phys(p), PAGE_KERNEL); +} + +int __meminit vmemmap_check_pmd(pmd_t *pmdp, int node, + unsigned long addr, unsigned long next) +{ + vmemmap_verify((pte_t *)pmdp, node, addr, next); + return 1; +} + int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node, struct vmem_altmap *altmap) { - return vmemmap_populate_basepages(start, end, node, NULL); + /* + * Note that SPARSEMEM_VMEMMAP is only selected for rv64 and that we + * can't use hugepage mappings for 2-level page table because in case of + * memory hotplug, we are not able to update all the page tables with + * the new PMDs. + */ + return vmemmap_populate_hugepages(start, end, node, NULL); } #endif diff --git a/arch/riscv/mm/kasan_init.c b/arch/riscv/mm/kasan_init.c index 5e39dcf23fdbc1..c301c8d291d2df 100644 --- a/arch/riscv/mm/kasan_init.c +++ b/arch/riscv/mm/kasan_init.c @@ -31,7 +31,7 @@ static void __init kasan_populate_pte(pmd_t *pmd, unsigned long vaddr, unsigned phys_addr_t phys_addr; pte_t *ptep, *p; - if (pmd_none(*pmd)) { + if (pmd_none(pmdp_get(pmd))) { p = memblock_alloc(PTRS_PER_PTE * sizeof(pte_t), PAGE_SIZE); set_pmd(pmd, pfn_pmd(PFN_DOWN(__pa(p)), PAGE_TABLE)); } @@ -39,7 +39,7 @@ static void __init kasan_populate_pte(pmd_t *pmd, unsigned long vaddr, unsigned ptep = pte_offset_kernel(pmd, vaddr); do { - if (pte_none(*ptep)) { + if (pte_none(ptep_get(ptep))) { phys_addr = memblock_phys_alloc(PAGE_SIZE, PAGE_SIZE); set_pte(ptep, pfn_pte(PFN_DOWN(phys_addr), PAGE_KERNEL)); memset(__va(phys_addr), KASAN_SHADOW_INIT, PAGE_SIZE); @@ -53,7 +53,7 @@ static void __init kasan_populate_pmd(pud_t *pud, unsigned long vaddr, unsigned pmd_t *pmdp, *p; unsigned long next; - if (pud_none(*pud)) { + if (pud_none(pudp_get(pud))) { p = memblock_alloc(PTRS_PER_PMD * sizeof(pmd_t), PAGE_SIZE); set_pud(pud, pfn_pud(PFN_DOWN(__pa(p)), PAGE_TABLE)); } @@ -63,7 +63,8 @@ static void __init kasan_populate_pmd(pud_t *pud, unsigned long vaddr, unsigned do { next = pmd_addr_end(vaddr, end); - if (pmd_none(*pmdp) && IS_ALIGNED(vaddr, PMD_SIZE) && (next - vaddr) >= PMD_SIZE) { + if (pmd_none(pmdp_get(pmdp)) && IS_ALIGNED(vaddr, PMD_SIZE) && + (next - vaddr) >= PMD_SIZE) { phys_addr = memblock_phys_alloc(PMD_SIZE, PMD_SIZE); if (phys_addr) { set_pmd(pmdp, pfn_pmd(PFN_DOWN(phys_addr), PAGE_KERNEL)); @@ -83,7 +84,7 @@ static void __init kasan_populate_pud(p4d_t *p4d, pud_t *pudp, *p; unsigned long next; - if (p4d_none(*p4d)) { + if (p4d_none(p4dp_get(p4d))) { p = memblock_alloc(PTRS_PER_PUD * sizeof(pud_t), PAGE_SIZE); set_p4d(p4d, pfn_p4d(PFN_DOWN(__pa(p)), PAGE_TABLE)); } @@ -93,7 +94,8 @@ static void __init kasan_populate_pud(p4d_t *p4d, do { next = pud_addr_end(vaddr, end); - if (pud_none(*pudp) && IS_ALIGNED(vaddr, PUD_SIZE) && (next - vaddr) >= PUD_SIZE) { + if (pud_none(pudp_get(pudp)) && IS_ALIGNED(vaddr, PUD_SIZE) && + (next - vaddr) >= PUD_SIZE) { phys_addr = memblock_phys_alloc(PUD_SIZE, PUD_SIZE); if (phys_addr) { set_pud(pudp, pfn_pud(PFN_DOWN(phys_addr), PAGE_KERNEL)); @@ -113,7 +115,7 @@ static void __init kasan_populate_p4d(pgd_t *pgd, p4d_t *p4dp, *p; unsigned long next; - if (pgd_none(*pgd)) { + if (pgd_none(pgdp_get(pgd))) { p = memblock_alloc(PTRS_PER_P4D * sizeof(p4d_t), PAGE_SIZE); set_pgd(pgd, pfn_pgd(PFN_DOWN(__pa(p)), PAGE_TABLE)); } @@ -123,7 +125,8 @@ static void __init kasan_populate_p4d(pgd_t *pgd, do { next = p4d_addr_end(vaddr, end); - if (p4d_none(*p4dp) && IS_ALIGNED(vaddr, P4D_SIZE) && (next - vaddr) >= P4D_SIZE) { + if (p4d_none(p4dp_get(p4dp)) && IS_ALIGNED(vaddr, P4D_SIZE) && + (next - vaddr) >= P4D_SIZE) { phys_addr = memblock_phys_alloc(P4D_SIZE, P4D_SIZE); if (phys_addr) { set_p4d(p4dp, pfn_p4d(PFN_DOWN(phys_addr), PAGE_KERNEL)); @@ -145,7 +148,7 @@ static void __init kasan_populate_pgd(pgd_t *pgdp, do { next = pgd_addr_end(vaddr, end); - if (pgd_none(*pgdp) && IS_ALIGNED(vaddr, PGDIR_SIZE) && + if (pgd_none(pgdp_get(pgdp)) && IS_ALIGNED(vaddr, PGDIR_SIZE) && (next - vaddr) >= PGDIR_SIZE) { phys_addr = memblock_phys_alloc(PGDIR_SIZE, PGDIR_SIZE); if (phys_addr) { @@ -168,7 +171,7 @@ static void __init kasan_early_clear_pud(p4d_t *p4dp, if (!pgtable_l4_enabled) { pudp = (pud_t *)p4dp; } else { - base_pud = pt_ops.get_pud_virt(pfn_to_phys(_p4d_pfn(*p4dp))); + base_pud = pt_ops.get_pud_virt(pfn_to_phys(_p4d_pfn(p4dp_get(p4dp)))); pudp = base_pud + pud_index(vaddr); } @@ -193,7 +196,7 @@ static void __init kasan_early_clear_p4d(pgd_t *pgdp, if (!pgtable_l5_enabled) { p4dp = (p4d_t *)pgdp; } else { - base_p4d = pt_ops.get_p4d_virt(pfn_to_phys(_pgd_pfn(*pgdp))); + base_p4d = pt_ops.get_p4d_virt(pfn_to_phys(_pgd_pfn(pgdp_get(pgdp)))); p4dp = base_p4d + p4d_index(vaddr); } @@ -239,14 +242,14 @@ static void __init kasan_early_populate_pud(p4d_t *p4dp, if (!pgtable_l4_enabled) { pudp = (pud_t *)p4dp; } else { - base_pud = pt_ops.get_pud_virt(pfn_to_phys(_p4d_pfn(*p4dp))); + base_pud = pt_ops.get_pud_virt(pfn_to_phys(_p4d_pfn(p4dp_get(p4dp)))); pudp = base_pud + pud_index(vaddr); } do { next = pud_addr_end(vaddr, end); - if (pud_none(*pudp) && IS_ALIGNED(vaddr, PUD_SIZE) && + if (pud_none(pudp_get(pudp)) && IS_ALIGNED(vaddr, PUD_SIZE) && (next - vaddr) >= PUD_SIZE) { phys_addr = __pa((uintptr_t)kasan_early_shadow_pmd); set_pud(pudp, pfn_pud(PFN_DOWN(phys_addr), PAGE_TABLE)); @@ -277,14 +280,14 @@ static void __init kasan_early_populate_p4d(pgd_t *pgdp, if (!pgtable_l5_enabled) { p4dp = (p4d_t *)pgdp; } else { - base_p4d = pt_ops.get_p4d_virt(pfn_to_phys(_pgd_pfn(*pgdp))); + base_p4d = pt_ops.get_p4d_virt(pfn_to_phys(_pgd_pfn(pgdp_get(pgdp)))); p4dp = base_p4d + p4d_index(vaddr); } do { next = p4d_addr_end(vaddr, end); - if (p4d_none(*p4dp) && IS_ALIGNED(vaddr, P4D_SIZE) && + if (p4d_none(p4dp_get(p4dp)) && IS_ALIGNED(vaddr, P4D_SIZE) && (next - vaddr) >= P4D_SIZE) { phys_addr = __pa((uintptr_t)kasan_early_shadow_pud); set_p4d(p4dp, pfn_p4d(PFN_DOWN(phys_addr), PAGE_TABLE)); @@ -305,7 +308,7 @@ static void __init kasan_early_populate_pgd(pgd_t *pgdp, do { next = pgd_addr_end(vaddr, end); - if (pgd_none(*pgdp) && IS_ALIGNED(vaddr, PGDIR_SIZE) && + if (pgd_none(pgdp_get(pgdp)) && IS_ALIGNED(vaddr, PGDIR_SIZE) && (next - vaddr) >= PGDIR_SIZE) { phys_addr = __pa((uintptr_t)kasan_early_shadow_p4d); set_pgd(pgdp, pfn_pgd(PFN_DOWN(phys_addr), PAGE_TABLE)); @@ -381,7 +384,7 @@ static void __init kasan_shallow_populate_pud(p4d_t *p4d, do { next = pud_addr_end(vaddr, end); - if (pud_none(*pud_k)) { + if (pud_none(pudp_get(pud_k))) { p = memblock_alloc(PAGE_SIZE, PAGE_SIZE); set_pud(pud_k, pfn_pud(PFN_DOWN(__pa(p)), PAGE_TABLE)); continue; @@ -401,7 +404,7 @@ static void __init kasan_shallow_populate_p4d(pgd_t *pgd, do { next = p4d_addr_end(vaddr, end); - if (p4d_none(*p4d_k)) { + if (p4d_none(p4dp_get(p4d_k))) { p = memblock_alloc(PAGE_SIZE, PAGE_SIZE); set_p4d(p4d_k, pfn_p4d(PFN_DOWN(__pa(p)), PAGE_TABLE)); continue; @@ -420,7 +423,7 @@ static void __init kasan_shallow_populate_pgd(unsigned long vaddr, unsigned long do { next = pgd_addr_end(vaddr, end); - if (pgd_none(*pgd_k)) { + if (pgd_none(pgdp_get(pgd_k))) { p = memblock_alloc(PAGE_SIZE, PAGE_SIZE); set_pgd(pgd_k, pfn_pgd(PFN_DOWN(__pa(p)), PAGE_TABLE)); continue; @@ -438,6 +441,14 @@ static void __init kasan_shallow_populate(void *start, void *end) kasan_shallow_populate_pgd(vaddr, vend); } +#ifdef CONFIG_KASAN_VMALLOC +void __init kasan_populate_early_vm_area_shadow(void *start, unsigned long size) +{ + kasan_populate(kasan_mem_to_shadow(start), + kasan_mem_to_shadow(start + size)); +} +#endif + static void __init create_tmp_mapping(void) { void *ptr; @@ -451,7 +462,7 @@ static void __init create_tmp_mapping(void) /* Copy the last p4d since it is shared with the kernel mapping. */ if (pgtable_l5_enabled) { - ptr = (p4d_t *)pgd_page_vaddr(*pgd_offset_k(KASAN_SHADOW_END)); + ptr = (p4d_t *)pgd_page_vaddr(pgdp_get(pgd_offset_k(KASAN_SHADOW_END))); memcpy(tmp_p4d, ptr, sizeof(p4d_t) * PTRS_PER_P4D); set_pgd(&tmp_pg_dir[pgd_index(KASAN_SHADOW_END)], pfn_pgd(PFN_DOWN(__pa(tmp_p4d)), PAGE_TABLE)); @@ -462,7 +473,7 @@ static void __init create_tmp_mapping(void) /* Copy the last pud since it is shared with the kernel mapping. */ if (pgtable_l4_enabled) { - ptr = (pud_t *)p4d_page_vaddr(*(base_p4d + p4d_index(KASAN_SHADOW_END))); + ptr = (pud_t *)p4d_page_vaddr(p4dp_get(base_p4d + p4d_index(KASAN_SHADOW_END))); memcpy(tmp_pud, ptr, sizeof(pud_t) * PTRS_PER_PUD); set_p4d(&base_p4d[p4d_index(KASAN_SHADOW_END)], pfn_p4d(PFN_DOWN(__pa(tmp_pud)), PAGE_TABLE)); diff --git a/arch/riscv/mm/pageattr.c b/arch/riscv/mm/pageattr.c index fc5fc4f785c481..410056a50aa9f9 100644 --- a/arch/riscv/mm/pageattr.c +++ b/arch/riscv/mm/pageattr.c @@ -29,7 +29,7 @@ static unsigned long set_pageattr_masks(unsigned long val, struct mm_walk *walk) static int pageattr_p4d_entry(p4d_t *p4d, unsigned long addr, unsigned long next, struct mm_walk *walk) { - p4d_t val = READ_ONCE(*p4d); + p4d_t val = p4dp_get(p4d); if (p4d_leaf(val)) { val = __p4d(set_pageattr_masks(p4d_val(val), walk)); @@ -42,7 +42,7 @@ static int pageattr_p4d_entry(p4d_t *p4d, unsigned long addr, static int pageattr_pud_entry(pud_t *pud, unsigned long addr, unsigned long next, struct mm_walk *walk) { - pud_t val = READ_ONCE(*pud); + pud_t val = pudp_get(pud); if (pud_leaf(val)) { val = __pud(set_pageattr_masks(pud_val(val), walk)); @@ -55,7 +55,7 @@ static int pageattr_pud_entry(pud_t *pud, unsigned long addr, static int pageattr_pmd_entry(pmd_t *pmd, unsigned long addr, unsigned long next, struct mm_walk *walk) { - pmd_t val = READ_ONCE(*pmd); + pmd_t val = pmdp_get(pmd); if (pmd_leaf(val)) { val = __pmd(set_pageattr_masks(pmd_val(val), walk)); @@ -68,7 +68,7 @@ static int pageattr_pmd_entry(pmd_t *pmd, unsigned long addr, static int pageattr_pte_entry(pte_t *pte, unsigned long addr, unsigned long next, struct mm_walk *walk) { - pte_t val = READ_ONCE(*pte); + pte_t val = ptep_get(pte); val = __pte(set_pageattr_masks(pte_val(val), walk)); set_pte(pte, val); @@ -108,10 +108,10 @@ static int __split_linear_mapping_pmd(pud_t *pudp, vaddr <= (vaddr & PMD_MASK) && end >= next) continue; - if (pmd_leaf(*pmdp)) { + if (pmd_leaf(pmdp_get(pmdp))) { struct page *pte_page; - unsigned long pfn = _pmd_pfn(*pmdp); - pgprot_t prot = __pgprot(pmd_val(*pmdp) & ~_PAGE_PFN_MASK); + unsigned long pfn = _pmd_pfn(pmdp_get(pmdp)); + pgprot_t prot = __pgprot(pmd_val(pmdp_get(pmdp)) & ~_PAGE_PFN_MASK); pte_t *ptep_new; int i; @@ -148,10 +148,10 @@ static int __split_linear_mapping_pud(p4d_t *p4dp, vaddr <= (vaddr & PUD_MASK) && end >= next) continue; - if (pud_leaf(*pudp)) { + if (pud_leaf(pudp_get(pudp))) { struct page *pmd_page; - unsigned long pfn = _pud_pfn(*pudp); - pgprot_t prot = __pgprot(pud_val(*pudp) & ~_PAGE_PFN_MASK); + unsigned long pfn = _pud_pfn(pudp_get(pudp)); + pgprot_t prot = __pgprot(pud_val(pudp_get(pudp)) & ~_PAGE_PFN_MASK); pmd_t *pmdp_new; int i; @@ -197,10 +197,10 @@ static int __split_linear_mapping_p4d(pgd_t *pgdp, vaddr <= (vaddr & P4D_MASK) && end >= next) continue; - if (p4d_leaf(*p4dp)) { + if (p4d_leaf(p4dp_get(p4dp))) { struct page *pud_page; - unsigned long pfn = _p4d_pfn(*p4dp); - pgprot_t prot = __pgprot(p4d_val(*p4dp) & ~_PAGE_PFN_MASK); + unsigned long pfn = _p4d_pfn(p4dp_get(p4dp)); + pgprot_t prot = __pgprot(p4d_val(p4dp_get(p4dp)) & ~_PAGE_PFN_MASK); pud_t *pudp_new; int i; @@ -305,8 +305,13 @@ static int __set_memory(unsigned long addr, int numpages, pgprot_t set_mask, goto unlock; } } else if (is_kernel_mapping(start) || is_linear_mapping(start)) { - lm_start = (unsigned long)lm_alias(start); - lm_end = (unsigned long)lm_alias(end); + if (is_kernel_mapping(start)) { + lm_start = (unsigned long)lm_alias(start); + lm_end = (unsigned long)lm_alias(end); + } else { + lm_start = start; + lm_end = end; + } ret = split_linear_mapping(lm_start, lm_end); if (ret) @@ -378,7 +383,7 @@ int set_direct_map_invalid_noflush(struct page *page) int set_direct_map_default_noflush(struct page *page) { return __set_memory((unsigned long)page_address(page), 1, - PAGE_KERNEL, __pgprot(0)); + PAGE_KERNEL, __pgprot(_PAGE_EXEC)); } #ifdef CONFIG_DEBUG_PAGEALLOC @@ -406,29 +411,29 @@ bool kernel_page_present(struct page *page) pte_t *pte; pgd = pgd_offset_k(addr); - if (!pgd_present(*pgd)) + if (!pgd_present(pgdp_get(pgd))) return false; - if (pgd_leaf(*pgd)) + if (pgd_leaf(pgdp_get(pgd))) return true; p4d = p4d_offset(pgd, addr); - if (!p4d_present(*p4d)) + if (!p4d_present(p4dp_get(p4d))) return false; - if (p4d_leaf(*p4d)) + if (p4d_leaf(p4dp_get(p4d))) return true; pud = pud_offset(p4d, addr); - if (!pud_present(*pud)) + if (!pud_present(pudp_get(pud))) return false; - if (pud_leaf(*pud)) + if (pud_leaf(pudp_get(pud))) return true; pmd = pmd_offset(pud, addr); - if (!pmd_present(*pmd)) + if (!pmd_present(pmdp_get(pmd))) return false; - if (pmd_leaf(*pmd)) + if (pmd_leaf(pmdp_get(pmd))) return true; pte = pte_offset_kernel(pmd, addr); - return pte_present(*pte); + return pte_present(ptep_get(pte)); } diff --git a/arch/riscv/mm/pgtable.c b/arch/riscv/mm/pgtable.c index fef4e7328e4905..ef887efcb67900 100644 --- a/arch/riscv/mm/pgtable.c +++ b/arch/riscv/mm/pgtable.c @@ -5,6 +5,47 @@ #include #include +int ptep_set_access_flags(struct vm_area_struct *vma, + unsigned long address, pte_t *ptep, + pte_t entry, int dirty) +{ + if (!pte_same(ptep_get(ptep), entry)) + __set_pte_at(ptep, entry); + /* + * update_mmu_cache will unconditionally execute, handling both + * the case that the PTE changed and the spurious fault case. + */ + return true; +} + +int ptep_test_and_clear_young(struct vm_area_struct *vma, + unsigned long address, + pte_t *ptep) +{ + if (!pte_young(ptep_get(ptep))) + return 0; + return test_and_clear_bit(_PAGE_ACCESSED_OFFSET, &pte_val(*ptep)); +} +EXPORT_SYMBOL_GPL(ptep_test_and_clear_young); + +#ifdef CONFIG_64BIT +pud_t *pud_offset(p4d_t *p4d, unsigned long address) +{ + if (pgtable_l4_enabled) + return p4d_pgtable(p4dp_get(p4d)) + pud_index(address); + + return (pud_t *)p4d; +} + +p4d_t *p4d_offset(pgd_t *pgd, unsigned long address) +{ + if (pgtable_l5_enabled) + return pgd_pgtable(pgdp_get(pgd)) + p4d_index(address); + + return (p4d_t *)pgd; +} +#endif + #ifdef CONFIG_HAVE_ARCH_HUGE_VMAP int p4d_set_huge(p4d_t *p4d, phys_addr_t addr, pgprot_t prot) { @@ -25,7 +66,7 @@ int pud_set_huge(pud_t *pud, phys_addr_t phys, pgprot_t prot) int pud_clear_huge(pud_t *pud) { - if (!pud_leaf(READ_ONCE(*pud))) + if (!pud_leaf(pudp_get(pud))) return 0; pud_clear(pud); return 1; @@ -33,7 +74,7 @@ int pud_clear_huge(pud_t *pud) int pud_free_pmd_page(pud_t *pud, unsigned long addr) { - pmd_t *pmd = pud_pgtable(*pud); + pmd_t *pmd = pud_pgtable(pudp_get(pud)); int i; pud_clear(pud); @@ -63,7 +104,7 @@ int pmd_set_huge(pmd_t *pmd, phys_addr_t phys, pgprot_t prot) int pmd_clear_huge(pmd_t *pmd) { - if (!pmd_leaf(READ_ONCE(*pmd))) + if (!pmd_leaf(pmdp_get(pmd))) return 0; pmd_clear(pmd); return 1; @@ -71,7 +112,7 @@ int pmd_clear_huge(pmd_t *pmd) int pmd_free_pte_page(pmd_t *pmd, unsigned long addr) { - pte_t *pte = (pte_t *)pmd_page_vaddr(*pmd); + pte_t *pte = (pte_t *)pmd_page_vaddr(pmdp_get(pmd)); pmd_clear(pmd); @@ -88,7 +129,7 @@ pmd_t pmdp_collapse_flush(struct vm_area_struct *vma, pmd_t pmd = pmdp_huge_get_and_clear(vma->vm_mm, address, pmdp); VM_BUG_ON(address & ~HPAGE_PMD_MASK); - VM_BUG_ON(pmd_trans_huge(*pmdp)); + VM_BUG_ON(pmd_trans_huge(pmdp_get(pmdp))); /* * When leaf PTE entries (regular pages) are collapsed into a leaf * PMD entry (huge page), a valid non-leaf PTE is converted into a diff --git a/arch/riscv/mm/tlbflush.c b/arch/riscv/mm/tlbflush.c index e6659d7368b354..8d12b26f5ac37b 100644 --- a/arch/riscv/mm/tlbflush.c +++ b/arch/riscv/mm/tlbflush.c @@ -66,6 +66,11 @@ static inline void local_flush_tlb_range_asid(unsigned long start, local_flush_tlb_range_threshold_asid(start, size, stride, asid); } +void local_flush_tlb_kernel_range(unsigned long start, unsigned long end) +{ + local_flush_tlb_range_asid(start, end, PAGE_SIZE, FLUSH_TLB_NO_ASID); +} + static void __ipi_flush_tlb_all(void *info) { local_flush_tlb_all(); @@ -93,29 +98,23 @@ static void __ipi_flush_tlb_range_asid(void *info) local_flush_tlb_range_asid(d->start, d->size, d->stride, d->asid); } -static void __flush_tlb_range(struct mm_struct *mm, unsigned long start, - unsigned long size, unsigned long stride) +static void __flush_tlb_range(struct cpumask *cmask, unsigned long asid, + unsigned long start, unsigned long size, + unsigned long stride) { struct flush_tlb_range_data ftd; - const struct cpumask *cmask; - unsigned long asid = FLUSH_TLB_NO_ASID; bool broadcast; - if (mm) { - unsigned int cpuid; + if (cpumask_empty(cmask)) + return; - cmask = mm_cpumask(mm); - if (cpumask_empty(cmask)) - return; + if (cmask != cpu_online_mask) { + unsigned int cpuid; cpuid = get_cpu(); /* check if the tlbflush needs to be sent to other CPUs */ broadcast = cpumask_any_but(cmask, cpuid) < nr_cpu_ids; - - if (static_branch_unlikely(&use_asid_allocator)) - asid = atomic_long_read(&mm->context.id) & asid_mask; } else { - cmask = cpu_online_mask; broadcast = true; } @@ -135,25 +134,34 @@ static void __flush_tlb_range(struct mm_struct *mm, unsigned long start, local_flush_tlb_range_asid(start, size, stride, asid); } - if (mm) + if (cmask != cpu_online_mask) put_cpu(); } +static inline unsigned long get_mm_asid(struct mm_struct *mm) +{ + return static_branch_unlikely(&use_asid_allocator) ? + atomic_long_read(&mm->context.id) & asid_mask : FLUSH_TLB_NO_ASID; +} + void flush_tlb_mm(struct mm_struct *mm) { - __flush_tlb_range(mm, 0, FLUSH_TLB_MAX_SIZE, PAGE_SIZE); + __flush_tlb_range(mm_cpumask(mm), get_mm_asid(mm), + 0, FLUSH_TLB_MAX_SIZE, PAGE_SIZE); } void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, unsigned long end, unsigned int page_size) { - __flush_tlb_range(mm, start, end - start, page_size); + __flush_tlb_range(mm_cpumask(mm), get_mm_asid(mm), + start, end - start, page_size); } void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) { - __flush_tlb_range(vma->vm_mm, addr, PAGE_SIZE, PAGE_SIZE); + __flush_tlb_range(mm_cpumask(vma->vm_mm), get_mm_asid(vma->vm_mm), + addr, PAGE_SIZE, PAGE_SIZE); } void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, @@ -185,18 +193,44 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, } } - __flush_tlb_range(vma->vm_mm, start, end - start, stride_size); + __flush_tlb_range(mm_cpumask(vma->vm_mm), get_mm_asid(vma->vm_mm), + start, end - start, stride_size); } void flush_tlb_kernel_range(unsigned long start, unsigned long end) { - __flush_tlb_range(NULL, start, end - start, PAGE_SIZE); + __flush_tlb_range((struct cpumask *)cpu_online_mask, FLUSH_TLB_NO_ASID, + start, end - start, PAGE_SIZE); } #ifdef CONFIG_TRANSPARENT_HUGEPAGE void flush_pmd_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { - __flush_tlb_range(vma->vm_mm, start, end - start, PMD_SIZE); + __flush_tlb_range(mm_cpumask(vma->vm_mm), get_mm_asid(vma->vm_mm), + start, end - start, PMD_SIZE); } #endif + +bool arch_tlbbatch_should_defer(struct mm_struct *mm) +{ + return true; +} + +void arch_tlbbatch_add_pending(struct arch_tlbflush_unmap_batch *batch, + struct mm_struct *mm, + unsigned long uaddr) +{ + cpumask_or(&batch->cpumask, &batch->cpumask, mm_cpumask(mm)); +} + +void arch_flush_tlb_batched_pending(struct mm_struct *mm) +{ + flush_tlb_mm(mm); +} + +void arch_tlbbatch_flush(struct arch_tlbflush_unmap_batch *batch) +{ + __flush_tlb_range(&batch->cpumask, FLUSH_TLB_NO_ASID, 0, + FLUSH_TLB_MAX_SIZE, PAGE_SIZE); +} diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c index 8581693e62d396..719a97e7edb2c1 100644 --- a/arch/riscv/net/bpf_jit_comp64.c +++ b/arch/riscv/net/bpf_jit_comp64.c @@ -795,6 +795,7 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, struct bpf_tramp_links *fentry = &tlinks[BPF_TRAMP_FENTRY]; struct bpf_tramp_links *fexit = &tlinks[BPF_TRAMP_FEXIT]; struct bpf_tramp_links *fmod_ret = &tlinks[BPF_TRAMP_MODIFY_RETURN]; + bool is_struct_ops = flags & BPF_TRAMP_F_INDIRECT; void *orig_call = func_addr; bool save_ret; u32 insn; @@ -878,7 +879,7 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, stack_size = round_up(stack_size, 16); - if (func_addr) { + if (!is_struct_ops) { /* For the trampoline called from function entry, * the frame of traced function and the frame of * trampoline need to be considered. @@ -998,7 +999,7 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, emit_ld(RV_REG_S1, -sreg_off, RV_REG_FP, ctx); - if (func_addr) { + if (!is_struct_ops) { /* trampoline called from function entry */ emit_ld(RV_REG_T0, stack_size - 8, RV_REG_SP, ctx); emit_ld(RV_REG_FP, stack_size - 16, RV_REG_SP, ctx); @@ -1029,23 +1030,28 @@ out: return ret; } -int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, - void *image_end, const struct btf_func_model *m, - u32 flags, struct bpf_tramp_links *tlinks, - void *func_addr) +int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags, + struct bpf_tramp_links *tlinks, void *func_addr) { - int ret; + struct bpf_tramp_image im; struct rv_jit_context ctx; + int ret; ctx.ninsns = 0; ctx.insns = NULL; ctx.ro_insns = NULL; - ret = __arch_prepare_bpf_trampoline(im, m, tlinks, func_addr, flags, &ctx); - if (ret < 0) - return ret; + ret = __arch_prepare_bpf_trampoline(&im, m, tlinks, func_addr, flags, &ctx); - if (ninsns_rvoff(ret) > (long)image_end - (long)image) - return -EFBIG; + return ret < 0 ? ret : ninsns_rvoff(ctx.ninsns); +} + +int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, + void *image_end, const struct btf_func_model *m, + u32 flags, struct bpf_tramp_links *tlinks, + void *func_addr) +{ + int ret; + struct rv_jit_context ctx; ctx.ninsns = 0; /* diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index d5d8f99d1f2551..fe565f3a3a917d 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -123,7 +123,6 @@ config S390 select ARCH_USE_BUILTIN_BSWAP select ARCH_USE_CMPXCHG_LOCKREF select ARCH_USE_SYM_ANNOTATIONS - select ARCH_WANTS_DYNAMIC_TASK_STRUCT select ARCH_WANTS_NO_INSTR select ARCH_WANT_DEFAULT_BPF_JIT select ARCH_WANT_IPC_PARSE_VERSION @@ -146,7 +145,7 @@ config S390 select GENERIC_TIME_VSYSCALL select GENERIC_VDSO_TIME_NS select GENERIC_IOREMAP if PCI - select HAVE_ALIGNED_STRUCT_PAGE if SLUB + select HAVE_ALIGNED_STRUCT_PAGE select HAVE_ARCH_AUDITSYSCALL select HAVE_ARCH_JUMP_LABEL select HAVE_ARCH_JUMP_LABEL_RELATIVE @@ -217,7 +216,6 @@ config S390 select HAVE_VIRT_CPU_ACCOUNTING_IDLE select IOMMU_HELPER if PCI select IOMMU_SUPPORT if PCI - select KEXEC select MMU_GATHER_MERGE_VMAS select MMU_GATHER_NO_GATHER select MMU_GATHER_RCU_TABLE_FREE @@ -444,7 +442,7 @@ config COMMAND_LINE_SIZE line. config COMPAT - def_bool y + def_bool n prompt "Kernel support for 31 bit emulation" select ARCH_WANT_OLD_COMPAT_IPC select COMPAT_OLD_SIGACTION @@ -455,7 +453,9 @@ config COMPAT Select this option if you want to enable your system kernel to handle system-calls from ELF binaries for 31 bit ESA. This option (and some other stuff like libraries and such) is needed for - executing 31 bit applications. It is safe to say "Y". + executing 31 bit applications. + + If unsure say N. config SMP def_bool y diff --git a/arch/s390/boot/ipl_parm.c b/arch/s390/boot/ipl_parm.c index 2ab4872fbee1c9..b24de9aabf7d8a 100644 --- a/arch/s390/boot/ipl_parm.c +++ b/arch/s390/boot/ipl_parm.c @@ -274,7 +274,7 @@ void parse_boot_command_line(void) memory_limit = round_down(memparse(val, NULL), PAGE_SIZE); if (!strcmp(param, "vmalloc") && val) { - vmalloc_size = round_up(memparse(val, NULL), PAGE_SIZE); + vmalloc_size = round_up(memparse(val, NULL), _SEGMENT_SIZE); vmalloc_size_set = 1; } diff --git a/arch/s390/boot/startup.c b/arch/s390/boot/startup.c index 8104e0e3d188d8..9cc76e631759b1 100644 --- a/arch/s390/boot/startup.c +++ b/arch/s390/boot/startup.c @@ -255,7 +255,8 @@ static unsigned long setup_kernel_memory_layout(void) VMALLOC_END = MODULES_VADDR; /* allow vmalloc area to occupy up to about 1/2 of the rest virtual space left */ - vmalloc_size = min(vmalloc_size, round_down(VMALLOC_END / 2, _REGION3_SIZE)); + vsize = round_down(VMALLOC_END / 2, _SEGMENT_SIZE); + vmalloc_size = min(vmalloc_size, vsize); VMALLOC_START = VMALLOC_END - vmalloc_size; /* split remaining virtual space between 1:1 mapping & vmemmap array */ diff --git a/arch/s390/configs/debug_defconfig b/arch/s390/configs/debug_defconfig index 6de44ede4e14dd..cae2dd34fbb49d 100644 --- a/arch/s390/configs/debug_defconfig +++ b/arch/s390/configs/debug_defconfig @@ -40,6 +40,7 @@ CONFIG_SCHED_AUTOGROUP=y CONFIG_EXPERT=y # CONFIG_SYSFS_SYSCALL is not set CONFIG_PROFILING=y +CONFIG_KEXEC=y CONFIG_KEXEC_FILE=y CONFIG_KEXEC_SIG=y CONFIG_CRASH_DUMP=y @@ -373,7 +374,6 @@ CONFIG_NET_ACT_POLICE=m CONFIG_NET_ACT_GACT=m CONFIG_GACT_PROB=y CONFIG_NET_ACT_MIRRED=m -CONFIG_NET_ACT_IPT=m CONFIG_NET_ACT_NAT=m CONFIG_NET_ACT_PEDIT=m CONFIG_NET_ACT_SIMP=m @@ -637,8 +637,9 @@ CONFIG_FUSE_FS=y CONFIG_CUSE=m CONFIG_VIRTIO_FS=m CONFIG_OVERLAY_FS=m +CONFIG_NETFS_SUPPORT=m CONFIG_NETFS_STATS=y -CONFIG_FSCACHE=m +CONFIG_FSCACHE=y CONFIG_CACHEFILES=m CONFIG_ISO9660_FS=y CONFIG_JOLIET=y diff --git a/arch/s390/configs/defconfig b/arch/s390/configs/defconfig index bcae47da6b7cd2..42b988873e5443 100644 --- a/arch/s390/configs/defconfig +++ b/arch/s390/configs/defconfig @@ -38,6 +38,7 @@ CONFIG_SCHED_AUTOGROUP=y CONFIG_EXPERT=y # CONFIG_SYSFS_SYSCALL is not set CONFIG_PROFILING=y +CONFIG_KEXEC=y CONFIG_KEXEC_FILE=y CONFIG_KEXEC_SIG=y CONFIG_CRASH_DUMP=y @@ -363,7 +364,6 @@ CONFIG_NET_ACT_POLICE=m CONFIG_NET_ACT_GACT=m CONFIG_GACT_PROB=y CONFIG_NET_ACT_MIRRED=m -CONFIG_NET_ACT_IPT=m CONFIG_NET_ACT_NAT=m CONFIG_NET_ACT_PEDIT=m CONFIG_NET_ACT_SIMP=m @@ -622,8 +622,9 @@ CONFIG_FUSE_FS=y CONFIG_CUSE=m CONFIG_VIRTIO_FS=m CONFIG_OVERLAY_FS=m +CONFIG_NETFS_SUPPORT=m CONFIG_NETFS_STATS=y -CONFIG_FSCACHE=m +CONFIG_FSCACHE=y CONFIG_CACHEFILES=m CONFIG_ISO9660_FS=y CONFIG_JOLIET=y diff --git a/arch/s390/configs/zfcpdump_defconfig b/arch/s390/configs/zfcpdump_defconfig index 47028450eee157..30d2a16876650e 100644 --- a/arch/s390/configs/zfcpdump_defconfig +++ b/arch/s390/configs/zfcpdump_defconfig @@ -10,7 +10,6 @@ CONFIG_BLK_DEV_INITRD=y CONFIG_CC_OPTIMIZE_FOR_SIZE=y CONFIG_CRASH_DUMP=y CONFIG_MARCH_Z13=y -# CONFIG_COMPAT is not set CONFIG_NR_CPUS=2 CONFIG_HZ_100=y # CONFIG_CHSC_SCH is not set diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index c773820e4af90a..c6fe5405de4a4c 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -597,7 +597,9 @@ static int ctr_aes_crypt(struct skcipher_request *req) * final block may be < AES_BLOCK_SIZE, copy only nbytes */ if (nbytes) { - cpacf_kmctr(sctx->fc, sctx->key, buf, walk.src.virt.addr, + memset(buf, 0, AES_BLOCK_SIZE); + memcpy(buf, walk.src.virt.addr, nbytes); + cpacf_kmctr(sctx->fc, sctx->key, buf, buf, AES_BLOCK_SIZE, walk.iv); memcpy(walk.dst.virt.addr, buf, nbytes); crypto_inc(walk.iv, AES_BLOCK_SIZE); diff --git a/arch/s390/crypto/chacha-glue.c b/arch/s390/crypto/chacha-glue.c index 5fae187f947a08..ed9959e6f7149e 100644 --- a/arch/s390/crypto/chacha-glue.c +++ b/arch/s390/crypto/chacha-glue.c @@ -82,7 +82,7 @@ void chacha_crypt_arch(u32 *state, u8 *dst, const u8 *src, * it cannot handle a block of data or less, but otherwise * it can handle data of arbitrary size */ - if (bytes <= CHACHA_BLOCK_SIZE || nrounds != 20 || !MACHINE_HAS_VX) + if (bytes <= CHACHA_BLOCK_SIZE || nrounds != 20 || !cpu_has_vx()) chacha_crypt_generic(state, dst, src, bytes, nrounds); else chacha20_crypt_s390(state, dst, src, bytes, diff --git a/arch/s390/crypto/paes_s390.c b/arch/s390/crypto/paes_s390.c index 8b541e44151d4d..55ee5567a5ea92 100644 --- a/arch/s390/crypto/paes_s390.c +++ b/arch/s390/crypto/paes_s390.c @@ -693,9 +693,11 @@ static int ctr_paes_crypt(struct skcipher_request *req) * final block may be < AES_BLOCK_SIZE, copy only nbytes */ if (nbytes) { + memset(buf, 0, AES_BLOCK_SIZE); + memcpy(buf, walk.src.virt.addr, nbytes); while (1) { if (cpacf_kmctr(ctx->fc, ¶m, buf, - walk.src.virt.addr, AES_BLOCK_SIZE, + buf, AES_BLOCK_SIZE, walk.iv) == AES_BLOCK_SIZE) break; if (__paes_convert_key(ctx)) diff --git a/arch/s390/include/asm/ap.h b/arch/s390/include/asm/ap.h index 40c2b82f083a3e..43ac4a64f49b02 100644 --- a/arch/s390/include/asm/ap.h +++ b/arch/s390/include/asm/ap.h @@ -88,7 +88,7 @@ static inline bool ap_instructions_available(void) } /* TAPQ register GR2 response struct */ -struct ap_tapq_gr2 { +struct ap_tapq_hwinfo { union { unsigned long value; struct { @@ -96,11 +96,13 @@ struct ap_tapq_gr2 { unsigned int apinfo : 32; /* ap type, ... */ }; struct { - unsigned int s : 1; /* APSC */ - unsigned int m : 1; /* AP4KM */ - unsigned int c : 1; /* AP4KC */ - unsigned int mode : 3; - unsigned int n : 1; /* APXA */ + unsigned int apsc : 1; /* APSC */ + unsigned int mex4k : 1; /* AP4KM */ + unsigned int crt4k : 1; /* AP4KC */ + unsigned int cca : 1; /* D */ + unsigned int accel : 1; /* A */ + unsigned int ep11 : 1; /* X */ + unsigned int apxa : 1; /* APXA */ unsigned int : 1; unsigned int class : 8; unsigned int bs : 2; /* SE bind/assoc */ @@ -126,11 +128,12 @@ struct ap_tapq_gr2 { /** * ap_tapq(): Test adjunct processor queue. * @qid: The AP queue number - * @info: Pointer to queue descriptor + * @info: Pointer to tapq hwinfo struct * * Returns AP queue status structure. */ -static inline struct ap_queue_status ap_tapq(ap_qid_t qid, struct ap_tapq_gr2 *info) +static inline struct ap_queue_status ap_tapq(ap_qid_t qid, + struct ap_tapq_hwinfo *info) { union ap_queue_status_reg reg1; unsigned long reg2; @@ -158,7 +161,7 @@ static inline struct ap_queue_status ap_tapq(ap_qid_t qid, struct ap_tapq_gr2 *i * Returns AP queue status structure. */ static inline struct ap_queue_status ap_test_queue(ap_qid_t qid, int tbit, - struct ap_tapq_gr2 *info) + struct ap_tapq_hwinfo *info) { if (tbit) qid |= 1UL << 23; /* set T bit*/ diff --git a/arch/s390/include/asm/ctlreg.h b/arch/s390/include/asm/ctlreg.h index 6d4b85f2b541c6..72a9556d04f3b0 100644 --- a/arch/s390/include/asm/ctlreg.h +++ b/arch/s390/include/asm/ctlreg.h @@ -141,22 +141,26 @@ static __always_inline void local_ctl_store(unsigned int cr, struct ctlreg *reg) : [cr] "i" (cr)); } -static __always_inline void local_ctl_set_bit(unsigned int cr, unsigned int bit) +static __always_inline struct ctlreg local_ctl_set_bit(unsigned int cr, unsigned int bit) { - struct ctlreg reg; + struct ctlreg new, old; - local_ctl_store(cr, ®); - reg.val |= 1UL << bit; - local_ctl_load(cr, ®); + local_ctl_store(cr, &old); + new = old; + new.val |= 1UL << bit; + local_ctl_load(cr, &new); + return old; } -static __always_inline void local_ctl_clear_bit(unsigned int cr, unsigned int bit) +static __always_inline struct ctlreg local_ctl_clear_bit(unsigned int cr, unsigned int bit) { - struct ctlreg reg; + struct ctlreg new, old; - local_ctl_store(cr, ®); - reg.val &= ~(1UL << bit); - local_ctl_load(cr, ®); + local_ctl_store(cr, &old); + new = old; + new.val &= ~(1UL << bit); + local_ctl_load(cr, &new); + return old; } struct lowcore; diff --git a/arch/s390/include/asm/facility.h b/arch/s390/include/asm/facility.h index 94b6919026dfb8..796007125dff21 100644 --- a/arch/s390/include/asm/facility.h +++ b/arch/s390/include/asm/facility.h @@ -111,4 +111,10 @@ static inline void stfle(u64 *stfle_fac_list, int size) preempt_enable(); } +/** + * stfle_size - Actual size of the facility list as specified by stfle + * (number of double words) + */ +unsigned int stfle_size(void); + #endif /* __ASM_FACILITY_H */ diff --git a/arch/s390/include/asm/fpu/api.h b/arch/s390/include/asm/fpu/api.h index 9acf48e53a87fb..d6ca8bc6ca68b7 100644 --- a/arch/s390/include/asm/fpu/api.h +++ b/arch/s390/include/asm/fpu/api.h @@ -46,26 +46,33 @@ #include #include +#include void save_fpu_regs(void); void load_fpu_regs(void); void __load_fpu_regs(void); -static inline int test_fp_ctl(u32 fpc) +/** + * sfpc_safe - Set floating point control register safely. + * @fpc: new value for floating point control register + * + * Set floating point control register. This may lead to an exception, + * since a saved value may have been modified by user space (ptrace, + * signal return, kvm registers) to an invalid value. In such a case + * set the floating point control register to zero. + */ +static inline void sfpc_safe(u32 fpc) { - u32 orig_fpc; - int rc; - - asm volatile( - " efpc %1\n" - " sfpc %2\n" - "0: sfpc %1\n" - " la %0,0\n" - "1:\n" - EX_TABLE(0b,1b) - : "=d" (rc), "=&d" (orig_fpc) - : "d" (fpc), "0" (-EINVAL)); - return rc; + asm volatile("\n" + "0: sfpc %[fpc]\n" + "1: nopr %%r7\n" + ".pushsection .fixup, \"ax\"\n" + "2: lghi %[fpc],0\n" + " jg 0b\n" + ".popsection\n" + EX_TABLE(1b, 2b) + : [fpc] "+d" (fpc) + : : "memory"); } #define KERNEL_FPC 1 diff --git a/arch/s390/include/asm/fpu/internal.h b/arch/s390/include/asm/fpu/internal.h index 8634581b901131..d511c4cf5afb73 100644 --- a/arch/s390/include/asm/fpu/internal.h +++ b/arch/s390/include/asm/fpu/internal.h @@ -10,8 +10,14 @@ #define _ASM_S390_FPU_INTERNAL_H #include +#include #include +static inline bool cpu_has_vx(void) +{ + return likely(test_facility(129)); +} + static inline void save_vx_regs(__vector128 *vxrs) { asm volatile( @@ -41,7 +47,7 @@ static inline void fpregs_store(_s390_fp_regs *fpregs, struct fpu *fpu) { fpregs->pad = 0; fpregs->fpc = fpu->fpc; - if (MACHINE_HAS_VX) + if (cpu_has_vx()) convert_vx_to_fp((freg_t *)&fpregs->fprs, fpu->vxrs); else memcpy((freg_t *)&fpregs->fprs, fpu->fprs, @@ -51,7 +57,7 @@ static inline void fpregs_store(_s390_fp_regs *fpregs, struct fpu *fpu) static inline void fpregs_load(_s390_fp_regs *fpregs, struct fpu *fpu) { fpu->fpc = fpregs->fpc; - if (MACHINE_HAS_VX) + if (cpu_has_vx()) convert_fp_to_vx(fpu->vxrs, (freg_t *)&fpregs->fprs); else memcpy(fpu->fprs, (freg_t *)&fpregs->fprs, diff --git a/arch/s390/include/asm/irq_work.h b/arch/s390/include/asm/irq_work.h index 603783766d0abb..f00c9f610d5a8e 100644 --- a/arch/s390/include/asm/irq_work.h +++ b/arch/s390/include/asm/irq_work.h @@ -7,6 +7,4 @@ static inline bool arch_irq_work_has_interrupt(void) return true; } -void arch_irq_work_raise(void); - #endif /* _ASM_S390_IRQ_WORK_H */ diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index 67a298b6cf6e9f..52664105a473f9 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h @@ -818,7 +818,7 @@ struct s390_io_adapter { struct kvm_s390_cpu_model { /* facility mask supported by kvm & hosting machine */ - __u64 fac_mask[S390_ARCH_FAC_LIST_SIZE_U64]; + __u64 fac_mask[S390_ARCH_FAC_MASK_SIZE_U64]; struct kvm_s390_vm_cpu_subfunc subfuncs; /* facility list requested by guest (in dma page) */ __u64 *fac_list; diff --git a/arch/s390/include/asm/pci_io.h b/arch/s390/include/asm/pci_io.h index 287bb88f76986e..2686bee800e3d5 100644 --- a/arch/s390/include/asm/pci_io.h +++ b/arch/s390/include/asm/pci_io.h @@ -11,6 +11,8 @@ /* I/O size constraints */ #define ZPCI_MAX_READ_SIZE 8 #define ZPCI_MAX_WRITE_SIZE 128 +#define ZPCI_BOUNDARY_SIZE (1 << 12) +#define ZPCI_BOUNDARY_MASK (ZPCI_BOUNDARY_SIZE - 1) /* I/O Map */ #define ZPCI_IOMAP_SHIFT 48 @@ -125,16 +127,18 @@ out: int zpci_write_block(volatile void __iomem *dst, const void *src, unsigned long len); -static inline u8 zpci_get_max_write_size(u64 src, u64 dst, int len, int max) +static inline int zpci_get_max_io_size(u64 src, u64 dst, int len, int max) { - int count = len > max ? max : len, size = 1; + int offset = dst & ZPCI_BOUNDARY_MASK; + int size; - while (!(src & 0x1) && !(dst & 0x1) && ((size << 1) <= count)) { - dst = dst >> 1; - src = src >> 1; - size = size << 1; - } - return size; + size = min3(len, ZPCI_BOUNDARY_SIZE - offset, max); + if (IS_ALIGNED(src, 8) && IS_ALIGNED(dst, 8) && IS_ALIGNED(size, 8)) + return size; + + if (size >= 8) + return 8; + return rounddown_pow_of_two(size); } static inline int zpci_memcpy_fromio(void *dst, @@ -144,9 +148,9 @@ static inline int zpci_memcpy_fromio(void *dst, int size, rc = 0; while (n > 0) { - size = zpci_get_max_write_size((u64 __force) src, - (u64) dst, n, - ZPCI_MAX_READ_SIZE); + size = zpci_get_max_io_size((u64 __force) src, + (u64) dst, n, + ZPCI_MAX_READ_SIZE); rc = zpci_read_single(dst, src, size); if (rc) break; @@ -166,9 +170,9 @@ static inline int zpci_memcpy_toio(volatile void __iomem *dst, return -EINVAL; while (n > 0) { - size = zpci_get_max_write_size((u64 __force) dst, - (u64) src, n, - ZPCI_MAX_WRITE_SIZE); + size = zpci_get_max_io_size((u64 __force) dst, + (u64) src, n, + ZPCI_MAX_WRITE_SIZE); if (size > 8) /* main path */ rc = zpci_write_block(dst, src, size); else diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index 601e87fa8a9ab1..1299b56e43f6f9 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h @@ -770,6 +770,7 @@ static inline int pud_write(pud_t pud) return (pud_val(pud) & _REGION3_ENTRY_WRITE) != 0; } +#define pmd_dirty pmd_dirty static inline int pmd_dirty(pmd_t pmd) { return (pmd_val(pmd) & _SEGMENT_ENTRY_DIRTY) != 0; diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index c15eadbb998343..c0b6e74d899a49 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h @@ -184,11 +184,7 @@ struct thread_struct { struct gs_cb *gs_cb; /* Current guarded storage cb */ struct gs_cb *gs_bc_cb; /* Broadcast guarded storage cb */ struct pgm_tdb trap_tdb; /* Transaction abort diagnose block */ - /* - * Warning: 'fpu' is dynamically-sized. It *MUST* be at - * the end. - */ - struct fpu fpu; /* FP and VX register save area */ + struct fpu fpu; /* FP and VX register save area */ }; /* Flag to disable transactions. */ @@ -331,14 +327,36 @@ static inline unsigned long __extract_psw(void) return (((unsigned long) reg1) << 32) | ((unsigned long) reg2); } -static inline void local_mcck_enable(void) +static inline unsigned long __local_mcck_save(void) { - __load_psw_mask(__extract_psw() | PSW_MASK_MCHECK); + unsigned long mask = __extract_psw(); + + __load_psw_mask(mask & ~PSW_MASK_MCHECK); + return mask & PSW_MASK_MCHECK; +} + +#define local_mcck_save(mflags) \ +do { \ + typecheck(unsigned long, mflags); \ + mflags = __local_mcck_save(); \ +} while (0) + +static inline void local_mcck_restore(unsigned long mflags) +{ + unsigned long mask = __extract_psw(); + + mask &= ~PSW_MASK_MCHECK; + __load_psw_mask(mask | mflags); } static inline void local_mcck_disable(void) { - __load_psw_mask(__extract_psw() & ~PSW_MASK_MCHECK); + __local_mcck_save(); +} + +static inline void local_mcck_enable(void) +{ + __load_psw_mask(__extract_psw() | PSW_MASK_MCHECK); } /* diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h index df316436d2e140..03bcaa8effb222 100644 --- a/arch/s390/include/asm/setup.h +++ b/arch/s390/include/asm/setup.h @@ -28,7 +28,6 @@ #define MACHINE_FLAG_TOPOLOGY BIT(10) #define MACHINE_FLAG_TE BIT(11) #define MACHINE_FLAG_TLB_LC BIT(12) -#define MACHINE_FLAG_VX BIT(13) #define MACHINE_FLAG_TLB_GUEST BIT(14) #define MACHINE_FLAG_NX BIT(15) #define MACHINE_FLAG_GS BIT(16) @@ -90,7 +89,6 @@ extern unsigned long mio_wb_bit_mask; #define MACHINE_HAS_TOPOLOGY (S390_lowcore.machine_flags & MACHINE_FLAG_TOPOLOGY) #define MACHINE_HAS_TE (S390_lowcore.machine_flags & MACHINE_FLAG_TE) #define MACHINE_HAS_TLB_LC (S390_lowcore.machine_flags & MACHINE_FLAG_TLB_LC) -#define MACHINE_HAS_VX (S390_lowcore.machine_flags & MACHINE_FLAG_VX) #define MACHINE_HAS_TLB_GUEST (S390_lowcore.machine_flags & MACHINE_FLAG_TLB_GUEST) #define MACHINE_HAS_NX (S390_lowcore.machine_flags & MACHINE_FLAG_NX) #define MACHINE_HAS_GS (S390_lowcore.machine_flags & MACHINE_FLAG_GS) diff --git a/arch/s390/include/asm/sysinfo.h b/arch/s390/include/asm/sysinfo.h index ab1c6316055c20..edca5a751df412 100644 --- a/arch/s390/include/asm/sysinfo.h +++ b/arch/s390/include/asm/sysinfo.h @@ -40,6 +40,10 @@ struct sysinfo_1_1_1 { unsigned int ncr; unsigned int npr; unsigned int ntr; + char reserved_3[4]; + char model_var_cap[16]; + unsigned int model_var_cap_rating; + unsigned int nvr; }; struct sysinfo_1_2_1 { diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 353def93973b31..7a562b4199c81b 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -41,7 +41,7 @@ obj-y += sysinfo.o lgr.o os_info.o ctlreg.o obj-y += runtime_instr.o cache.o fpu.o dumpstack.o guarded_storage.o sthyi.o obj-y += entry.o reipl.o kdebugfs.o alternative.o obj-y += nospec-branch.o ipl_vmparm.o machine_kexec_reloc.o unwind_bc.o -obj-y += smp.o text_amode31.o stacktrace.o abs_lowcore.o +obj-y += smp.o text_amode31.o stacktrace.o abs_lowcore.o facility.o extra-y += vmlinux.lds diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c index cecedd01d4eca2..f8fc6c25d0510b 100644 --- a/arch/s390/kernel/compat_signal.c +++ b/arch/s390/kernel/compat_signal.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "compat_linux.h" #include "compat_ptrace.h" #include "entry.h" @@ -98,10 +99,6 @@ static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs) if (!is_ri_task(current) && (user_sregs.regs.psw.mask & PSW32_MASK_RI)) return -EINVAL; - /* Test the floating-point-control word. */ - if (test_fp_ctl(user_sregs.fpregs.fpc)) - return -EINVAL; - /* Use regs->psw.mask instead of PSW_USER_BITS to preserve PER bit. */ regs->psw.mask = (regs->psw.mask & ~(PSW_MASK_USER | PSW_MASK_RI)) | (__u64)(user_sregs.regs.psw.mask & PSW32_MASK_USER) << 32 | @@ -137,7 +134,7 @@ static int save_sigregs_ext32(struct pt_regs *regs, return -EFAULT; /* Save vector registers to signal stack */ - if (MACHINE_HAS_VX) { + if (cpu_has_vx()) { for (i = 0; i < __NUM_VXRS_LOW; i++) vxrs[i] = current->thread.fpu.vxrs[i].low; if (__copy_to_user(&sregs_ext->vxrs_low, vxrs, @@ -165,7 +162,7 @@ static int restore_sigregs_ext32(struct pt_regs *regs, *(__u32 *)®s->gprs[i] = gprs_high[i]; /* Restore vector registers from signal stack */ - if (MACHINE_HAS_VX) { + if (cpu_has_vx()) { if (__copy_from_user(vxrs, &sregs_ext->vxrs_low, sizeof(sregs_ext->vxrs_low)) || __copy_from_user(current->thread.fpu.vxrs + __NUM_VXRS_LOW, @@ -265,7 +262,7 @@ static int setup_frame32(struct ksignal *ksig, sigset_t *set, * the machine supports it */ frame_size = sizeof(*frame) - sizeof(frame->sregs_ext.__reserved); - if (!MACHINE_HAS_VX) + if (!cpu_has_vx()) frame_size -= sizeof(frame->sregs_ext.vxrs_low) + sizeof(frame->sregs_ext.vxrs_high); frame = get_sigframe(&ksig->ka, regs, frame_size); @@ -348,11 +345,12 @@ static int setup_rt_frame32(struct ksignal *ksig, sigset_t *set, * the machine supports it */ uc_flags = UC_GPRS_HIGH; - if (MACHINE_HAS_VX) { + if (cpu_has_vx()) { uc_flags |= UC_VXRS; - } else + } else { frame_size -= sizeof(frame->uc.uc_mcontext_ext.vxrs_low) + sizeof(frame->uc.uc_mcontext_ext.vxrs_high); + } frame = get_sigframe(&ksig->ka, regs, frame_size); if (frame == (void __user *) -1UL) return -EFAULT; diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c index 514feadd4c588b..5c46c26593054a 100644 --- a/arch/s390/kernel/crash_dump.c +++ b/arch/s390/kernel/crash_dump.c @@ -22,6 +22,7 @@ #include #include #include +#include #define PTR_ADD(x, y) (((char *) (x)) + ((unsigned long) (y))) #define PTR_SUB(x, y) (((char *) (x)) - ((unsigned long) (y))) @@ -319,7 +320,7 @@ static void *fill_cpu_elf_notes(void *ptr, int cpu, struct save_area *sa) ptr = nt_init(ptr, NT_S390_TODPREG, &sa->todpreg, sizeof(sa->todpreg)); ptr = nt_init(ptr, NT_S390_CTRS, &sa->ctrs, sizeof(sa->ctrs)); ptr = nt_init(ptr, NT_S390_PREFIX, &sa->prefix, sizeof(sa->prefix)); - if (MACHINE_HAS_VX) { + if (cpu_has_vx()) { ptr = nt_init(ptr, NT_S390_VXRS_HIGH, &sa->vxrs_high, sizeof(sa->vxrs_high)); ptr = nt_init(ptr, NT_S390_VXRS_LOW, @@ -343,7 +344,7 @@ static size_t get_cpu_elf_notes_size(void) size += nt_size(NT_S390_TODPREG, sizeof(sa->todpreg)); size += nt_size(NT_S390_CTRS, sizeof(sa->ctrs)); size += nt_size(NT_S390_PREFIX, sizeof(sa->prefix)); - if (MACHINE_HAS_VX) { + if (cpu_has_vx()) { size += nt_size(NT_S390_VXRS_HIGH, sizeof(sa->vxrs_high)); size += nt_size(NT_S390_VXRS_LOW, sizeof(sa->vxrs_low)); } diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index eb43e5922a25d7..2345ea332b97e2 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -229,10 +229,8 @@ static __init void detect_machine_facilities(void) } if (test_facility(51)) S390_lowcore.machine_flags |= MACHINE_FLAG_TLB_LC; - if (test_facility(129)) { - S390_lowcore.machine_flags |= MACHINE_FLAG_VX; + if (test_facility(129)) system_ctl_set_bit(0, CR0_VECTOR_BIT); - } if (test_facility(130)) S390_lowcore.machine_flags |= MACHINE_FLAG_NX; if (test_facility(133)) @@ -271,14 +269,6 @@ static inline void setup_access_registers(void) restore_access_regs(acrs); } -static int __init disable_vector_extension(char *str) -{ - S390_lowcore.machine_flags &= ~MACHINE_FLAG_VX; - system_ctl_clear_bit(0, CR0_VECTOR_BIT); - return 0; -} -early_param("novx", disable_vector_extension); - char __bootdata(early_command_line)[COMMAND_LINE_SIZE]; static void __init setup_boot_command_line(void) { diff --git a/arch/s390/kernel/facility.c b/arch/s390/kernel/facility.c new file mode 100644 index 00000000000000..f02127219a27b9 --- /dev/null +++ b/arch/s390/kernel/facility.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright IBM Corp. 2023 + */ + +#include + +unsigned int stfle_size(void) +{ + static unsigned int size; + unsigned int r; + u64 dummy; + + r = READ_ONCE(size); + if (!r) { + r = __stfle_asm(&dummy, 1) + 1; + WRITE_ONCE(size, r); + } + return r; +} +EXPORT_SYMBOL(stfle_size); diff --git a/arch/s390/kernel/fpu.c b/arch/s390/kernel/fpu.c index 4666b29ac8a1eb..a4f3449cc81416 100644 --- a/arch/s390/kernel/fpu.c +++ b/arch/s390/kernel/fpu.c @@ -24,7 +24,7 @@ void __kernel_fpu_begin(struct kernel_fpu *state, u32 flags) /* Save floating point control */ asm volatile("stfpc %0" : "=Q" (state->fpc)); - if (!MACHINE_HAS_VX) { + if (!cpu_has_vx()) { if (flags & KERNEL_VXR_V0V7) { /* Save floating-point registers */ asm volatile("std 0,%0" : "=Q" (state->fprs[0])); @@ -106,7 +106,7 @@ void __kernel_fpu_end(struct kernel_fpu *state, u32 flags) /* Restore floating-point controls */ asm volatile("lfpc %0" : : "Q" (state->fpc)); - if (!MACHINE_HAS_VX) { + if (!cpu_has_vx()) { if (flags & KERNEL_VXR_V0V7) { /* Restore floating-point registers */ asm volatile("ld 0,%0" : : "Q" (state->fprs[0])); @@ -177,11 +177,11 @@ EXPORT_SYMBOL(__kernel_fpu_end); void __load_fpu_regs(void) { - struct fpu *state = ¤t->thread.fpu; unsigned long *regs = current->thread.fpu.regs; + struct fpu *state = ¤t->thread.fpu; - asm volatile("lfpc %0" : : "Q" (state->fpc)); - if (likely(MACHINE_HAS_VX)) { + sfpc_safe(state->fpc); + if (likely(cpu_has_vx())) { asm volatile("lgr 1,%0\n" "VLM 0,15,0,1\n" "VLM 16,31,256,1\n" @@ -208,7 +208,6 @@ void __load_fpu_regs(void) } clear_cpu_flag(CIF_FPU); } -EXPORT_SYMBOL(__load_fpu_regs); void load_fpu_regs(void) { @@ -232,7 +231,7 @@ void save_fpu_regs(void) regs = current->thread.fpu.regs; asm volatile("stfpc %0" : "=Q" (state->fpc)); - if (likely(MACHINE_HAS_VX)) { + if (likely(cpu_has_vx())) { asm volatile("lgr 1,%0\n" "VSTM 0,15,0,1\n" "VSTM 16,31,256,1\n" diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c index bb0d4d68fcbe19..aa22ffc16bcd3d 100644 --- a/arch/s390/kernel/machine_kexec.c +++ b/arch/s390/kernel/machine_kexec.c @@ -91,7 +91,7 @@ static noinline void __machine_kdump(void *image) } /* Store status of the boot CPU */ mcesa = __va(S390_lowcore.mcesad & MCESA_ORIGIN_MASK); - if (MACHINE_HAS_VX) + if (cpu_has_vx()) save_vx_regs((__vector128 *) mcesa->vector_save_area); if (MACHINE_HAS_GS) { local_ctl_store(2, &cr2_old.reg); diff --git a/arch/s390/kernel/nmi.c b/arch/s390/kernel/nmi.c index 0daf0f1cdfc936..9ad44c26d1a288 100644 --- a/arch/s390/kernel/nmi.c +++ b/arch/s390/kernel/nmi.c @@ -32,6 +32,7 @@ #include #include #include +#include struct mcck_struct { unsigned int kill_task : 1; @@ -45,7 +46,7 @@ static DEFINE_PER_CPU(struct mcck_struct, cpu_mcck); static inline int nmi_needs_mcesa(void) { - return MACHINE_HAS_VX || MACHINE_HAS_GS; + return cpu_has_vx() || MACHINE_HAS_GS; } /* @@ -159,16 +160,17 @@ NOKPROBE_SYMBOL(s390_handle_damage); void s390_handle_mcck(void) { struct mcck_struct mcck; + unsigned long mflags; /* * Disable machine checks and get the current state of accumulated * machine checks. Afterwards delete the old state and enable machine * checks again. */ - local_mcck_disable(); + local_mcck_save(mflags); mcck = *this_cpu_ptr(&cpu_mcck); memset(this_cpu_ptr(&cpu_mcck), 0, sizeof(mcck)); - local_mcck_enable(); + local_mcck_restore(mflags); if (mcck.channel_report) crw_handle_channel_report(); @@ -234,7 +236,7 @@ static int notrace s390_validate_registers(union mci mci) } mcesa = __va(S390_lowcore.mcesad & MCESA_ORIGIN_MASK); - if (!MACHINE_HAS_VX) { + if (!cpu_has_vx()) { /* Validate floating point registers */ asm volatile( " ld 0,0(%0)\n" diff --git a/arch/s390/kernel/perf_pai_crypto.c b/arch/s390/kernel/perf_pai_crypto.c index 39a91b00438a7f..bf8a672b15a41a 100644 --- a/arch/s390/kernel/perf_pai_crypto.c +++ b/arch/s390/kernel/perf_pai_crypto.c @@ -111,11 +111,11 @@ static void paicrypt_event_destroy(struct perf_event *event) mutex_unlock(&pai_reserve_mutex); } -static u64 paicrypt_getctr(struct paicrypt_map *cpump, int nr, bool kernel) +static u64 paicrypt_getctr(unsigned long *page, int nr, bool kernel) { if (kernel) nr += PAI_CRYPTO_MAXCTR; - return cpump->page[nr]; + return page[nr]; } /* Read the counter values. Return value from location in CMP. For event @@ -129,13 +129,13 @@ static u64 paicrypt_getdata(struct perf_event *event, bool kernel) int i; if (event->attr.config != PAI_CRYPTO_BASE) { - return paicrypt_getctr(cpump, + return paicrypt_getctr(cpump->page, event->attr.config - PAI_CRYPTO_BASE, kernel); } for (i = 1; i <= paicrypt_cnt; i++) { - u64 val = paicrypt_getctr(cpump, i, kernel); + u64 val = paicrypt_getctr(cpump->page, i, kernel); if (!val) continue; @@ -317,10 +317,14 @@ static void paicrypt_start(struct perf_event *event, int flags) * Events are added, deleted and re-added when 2 or more events * are active at the same time. */ - if (!event->hw.last_tag) { - event->hw.last_tag = 1; - sum = paicrypt_getall(event); /* Get current value */ - local64_set(&event->hw.prev_count, sum); + if (!event->attr.sample_period) { /* Counting */ + if (!event->hw.last_tag) { + event->hw.last_tag = 1; + sum = paicrypt_getall(event); /* Get current value */ + local64_set(&event->hw.prev_count, sum); + } + } else { /* Sampling */ + perf_sched_cb_inc(event->pmu); } } @@ -336,19 +340,18 @@ static int paicrypt_add(struct perf_event *event, int flags) local_ctl_set_bit(0, CR0_CRYPTOGRAPHY_COUNTER_BIT); } cpump->event = event; - if (flags & PERF_EF_START && !event->attr.sample_period) { - /* Only counting needs initial counter value */ + if (flags & PERF_EF_START) paicrypt_start(event, PERF_EF_RELOAD); - } event->hw.state = 0; - if (event->attr.sample_period) - perf_sched_cb_inc(event->pmu); return 0; } static void paicrypt_stop(struct perf_event *event, int flags) { - paicrypt_read(event); + if (!event->attr.sample_period) /* Counting */ + paicrypt_read(event); + else /* Sampling */ + perf_sched_cb_dec(event->pmu); event->hw.state = PERF_HES_STOPPED; } @@ -357,11 +360,7 @@ static void paicrypt_del(struct perf_event *event, int flags) struct paicrypt_mapptr *mp = this_cpu_ptr(paicrypt_root.mapptr); struct paicrypt_map *cpump = mp->mapptr; - if (event->attr.sample_period) - perf_sched_cb_dec(event->pmu); - if (!event->attr.sample_period) - /* Only counting needs to read counter */ - paicrypt_stop(event, PERF_EF_UPDATE); + paicrypt_stop(event, PERF_EF_UPDATE); if (--cpump->active_events == 0) { local_ctl_clear_bit(0, CR0_CRYPTOGRAPHY_COUNTER_BIT); WRITE_ONCE(S390_lowcore.ccd, 0); @@ -373,8 +372,7 @@ static void paicrypt_del(struct perf_event *event, int flags) * 2 bytes: Number of counter * 8 bytes: Value of counter */ -static size_t paicrypt_copy(struct pai_userdata *userdata, - struct paicrypt_map *cpump, +static size_t paicrypt_copy(struct pai_userdata *userdata, unsigned long *page, bool exclude_user, bool exclude_kernel) { int i, outidx = 0; @@ -383,9 +381,9 @@ static size_t paicrypt_copy(struct pai_userdata *userdata, u64 val = 0; if (!exclude_kernel) - val += paicrypt_getctr(cpump, i, true); + val += paicrypt_getctr(page, i, true); if (!exclude_user) - val += paicrypt_getctr(cpump, i, false); + val += paicrypt_getctr(page, i, false); if (val) { userdata[outidx].num = i; userdata[outidx].value = val; @@ -395,25 +393,14 @@ static size_t paicrypt_copy(struct pai_userdata *userdata, return outidx * sizeof(struct pai_userdata); } -static int paicrypt_push_sample(void) +static int paicrypt_push_sample(size_t rawsize, struct paicrypt_map *cpump, + struct perf_event *event) { - struct paicrypt_mapptr *mp = this_cpu_ptr(paicrypt_root.mapptr); - struct paicrypt_map *cpump = mp->mapptr; - struct perf_event *event = cpump->event; struct perf_sample_data data; struct perf_raw_record raw; struct pt_regs regs; - size_t rawsize; int overflow; - if (!cpump->event) /* No event active */ - return 0; - rawsize = paicrypt_copy(cpump->save, cpump, - cpump->event->attr.exclude_user, - cpump->event->attr.exclude_kernel); - if (!rawsize) /* No incremented counters */ - return 0; - /* Setup perf sample */ memset(®s, 0, sizeof(regs)); memset(&raw, 0, sizeof(raw)); @@ -444,6 +431,25 @@ static int paicrypt_push_sample(void) return overflow; } +/* Check if there is data to be saved on schedule out of a task. */ +static int paicrypt_have_sample(void) +{ + struct paicrypt_mapptr *mp = this_cpu_ptr(paicrypt_root.mapptr); + struct paicrypt_map *cpump = mp->mapptr; + struct perf_event *event = cpump->event; + size_t rawsize; + int rc = 0; + + if (!event) /* No event active */ + return 0; + rawsize = paicrypt_copy(cpump->save, cpump->page, + cpump->event->attr.exclude_user, + cpump->event->attr.exclude_kernel); + if (rawsize) /* No incremented counters */ + rc = paicrypt_push_sample(rawsize, cpump, event); + return rc; +} + /* Called on schedule-in and schedule-out. No access to event structure, * but for sampling only event CRYPTO_ALL is allowed. */ @@ -453,7 +459,7 @@ static void paicrypt_sched_task(struct perf_event_pmu_context *pmu_ctx, bool sch * results on schedule_out and if page was dirty, clear values. */ if (!sched_in) - paicrypt_push_sample(); + paicrypt_have_sample(); } /* Attribute definitions for paicrypt interface. As with other CPU diff --git a/arch/s390/kernel/perf_pai_ext.c b/arch/s390/kernel/perf_pai_ext.c index e7013a2e896050..af7f2b538c8fd4 100644 --- a/arch/s390/kernel/perf_pai_ext.c +++ b/arch/s390/kernel/perf_pai_ext.c @@ -276,9 +276,9 @@ static int paiext_event_init(struct perf_event *event) return 0; } -static u64 paiext_getctr(struct paiext_map *cpump, int nr) +static u64 paiext_getctr(unsigned long *area, int nr) { - return cpump->area[nr]; + return area[nr]; } /* Read the counter values. Return value from location in buffer. For event @@ -292,10 +292,11 @@ static u64 paiext_getdata(struct perf_event *event) int i; if (event->attr.config != PAI_NNPA_BASE) - return paiext_getctr(cpump, event->attr.config - PAI_NNPA_BASE); + return paiext_getctr(cpump->area, + event->attr.config - PAI_NNPA_BASE); for (i = 1; i <= paiext_cnt; i++) - sum += paiext_getctr(cpump, i); + sum += paiext_getctr(cpump->area, i); return sum; } @@ -320,11 +321,15 @@ static void paiext_start(struct perf_event *event, int flags) { u64 sum; - if (event->hw.last_tag) - return; - event->hw.last_tag = 1; - sum = paiext_getall(event); /* Get current value */ - local64_set(&event->hw.prev_count, sum); + if (!event->attr.sample_period) { /* Counting */ + if (!event->hw.last_tag) { + event->hw.last_tag = 1; + sum = paiext_getall(event); /* Get current value */ + local64_set(&event->hw.prev_count, sum); + } + } else { /* Sampling */ + perf_sched_cb_inc(event->pmu); + } } static int paiext_add(struct perf_event *event, int flags) @@ -341,21 +346,19 @@ static int paiext_add(struct perf_event *event, int flags) debug_sprintf_event(paiext_dbg, 4, "%s 1508 %llx acc %llx\n", __func__, S390_lowcore.aicd, pcb->acc); } - if (flags & PERF_EF_START && !event->attr.sample_period) { - /* Only counting needs initial counter value */ + cpump->event = event; + if (flags & PERF_EF_START) paiext_start(event, PERF_EF_RELOAD); - } event->hw.state = 0; - if (event->attr.sample_period) { - cpump->event = event; - perf_sched_cb_inc(event->pmu); - } return 0; } static void paiext_stop(struct perf_event *event, int flags) { - paiext_read(event); + if (!event->attr.sample_period) /* Counting */ + paiext_read(event); + else /* Sampling */ + perf_sched_cb_dec(event->pmu); event->hw.state = PERF_HES_STOPPED; } @@ -365,12 +368,7 @@ static void paiext_del(struct perf_event *event, int flags) struct paiext_map *cpump = mp->mapptr; struct paiext_cb *pcb = cpump->paiext_cb; - if (event->attr.sample_period) - perf_sched_cb_dec(event->pmu); - if (!event->attr.sample_period) { - /* Only counting needs to read counter */ - paiext_stop(event, PERF_EF_UPDATE); - } + paiext_stop(event, PERF_EF_UPDATE); if (--cpump->active_events == 0) { /* Disable CPU instruction lookup for PAIE1 control block */ local_ctl_clear_bit(0, CR0_PAI_EXTENSION_BIT); @@ -386,13 +384,12 @@ static void paiext_del(struct perf_event *event, int flags) * 2 bytes: Number of counter * 8 bytes: Value of counter */ -static size_t paiext_copy(struct paiext_map *cpump) +static size_t paiext_copy(struct pai_userdata *userdata, unsigned long *area) { - struct pai_userdata *userdata = cpump->save; int i, outidx = 0; for (i = 1; i <= paiext_cnt; i++) { - u64 val = paiext_getctr(cpump, i); + u64 val = paiext_getctr(area, i); if (val) { userdata[outidx].num = i; @@ -418,21 +415,14 @@ static size_t paiext_copy(struct paiext_map *cpump) * sched_task() callback. That callback is not active after paiext_del() * returns and has deleted the event on that CPU. */ -static int paiext_push_sample(void) +static int paiext_push_sample(size_t rawsize, struct paiext_map *cpump, + struct perf_event *event) { - struct paiext_mapptr *mp = this_cpu_ptr(paiext_root.mapptr); - struct paiext_map *cpump = mp->mapptr; - struct perf_event *event = cpump->event; struct perf_sample_data data; struct perf_raw_record raw; struct pt_regs regs; - size_t rawsize; int overflow; - rawsize = paiext_copy(cpump); - if (!rawsize) /* No incremented counters */ - return 0; - /* Setup perf sample */ memset(®s, 0, sizeof(regs)); memset(&raw, 0, sizeof(raw)); @@ -461,6 +451,23 @@ static int paiext_push_sample(void) return overflow; } +/* Check if there is data to be saved on schedule out of a task. */ +static int paiext_have_sample(void) +{ + struct paiext_mapptr *mp = this_cpu_ptr(paiext_root.mapptr); + struct paiext_map *cpump = mp->mapptr; + struct perf_event *event = cpump->event; + size_t rawsize; + int rc = 0; + + if (!event) + return 0; + rawsize = paiext_copy(cpump->save, cpump->area); + if (rawsize) /* Incremented counters */ + rc = paiext_push_sample(rawsize, cpump, event); + return rc; +} + /* Called on schedule-in and schedule-out. No access to event structure, * but for sampling only event NNPA_ALL is allowed. */ @@ -470,7 +477,7 @@ static void paiext_sched_task(struct perf_event_pmu_context *pmu_ctx, bool sched * results on schedule_out and if page was dirty, clear values. */ if (!sched_in) - paiext_push_sample(); + paiext_have_sample(); } /* Attribute definitions for pai extension1 interface. As with other CPU diff --git a/arch/s390/kernel/perf_regs.c b/arch/s390/kernel/perf_regs.c index 6e9e5d5e927ef5..3d93656bd94890 100644 --- a/arch/s390/kernel/perf_regs.c +++ b/arch/s390/kernel/perf_regs.c @@ -20,8 +20,10 @@ u64 perf_reg_value(struct pt_regs *regs, int idx) return 0; idx -= PERF_REG_S390_FP0; - fp = MACHINE_HAS_VX ? *(freg_t *)(current->thread.fpu.vxrs + idx) - : current->thread.fpu.fprs[idx]; + if (cpu_has_vx()) + fp = *(freg_t *)(current->thread.fpu.vxrs + idx); + else + fp = current->thread.fpu.fprs[idx]; return fp.ui; } diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 2580004177248b..4e3b366589fb6a 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -89,7 +89,7 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) */ save_fpu_regs(); - memcpy(dst, src, arch_task_struct_size); + *dst = *src; dst->thread.fpu.regs = dst->thread.fpu.fprs; /* diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c index 0a999c8226d733..65c1464eea4fcc 100644 --- a/arch/s390/kernel/processor.c +++ b/arch/s390/kernel/processor.c @@ -201,11 +201,8 @@ static int __init setup_hwcaps(void) if (MACHINE_HAS_TE) elf_hwcap |= HWCAP_TE; - /* - * Vector extension can be disabled with the "novx" parameter. - * Use MACHINE_HAS_VX instead of facility bit 129. - */ - if (MACHINE_HAS_VX) { + /* vector */ + if (test_facility(129)) { elf_hwcap |= HWCAP_VXRS; if (test_facility(134)) elf_hwcap |= HWCAP_VXRS_BCD; diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 046403471c5d7d..f1897a8bb22107 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "entry.h" @@ -254,7 +255,7 @@ static unsigned long __peek_user(struct task_struct *child, addr_t addr) * or the child->thread.fpu.vxrs array */ offset = addr - offsetof(struct user, regs.fp_regs.fprs); - if (MACHINE_HAS_VX) + if (cpu_has_vx()) tmp = *(addr_t *) ((addr_t) child->thread.fpu.vxrs + 2*offset); else @@ -392,8 +393,7 @@ static int __poke_user(struct task_struct *child, addr_t addr, addr_t data) /* * floating point control reg. is in the thread structure */ - if ((unsigned int) data != 0 || - test_fp_ctl(data >> (BITS_PER_LONG - 32))) + if ((unsigned int)data != 0) return -EINVAL; child->thread.fpu.fpc = data >> (BITS_PER_LONG - 32); @@ -403,7 +403,7 @@ static int __poke_user(struct task_struct *child, addr_t addr, addr_t data) * or the child->thread.fpu.vxrs array */ offset = addr - offsetof(struct user, regs.fp_regs.fprs); - if (MACHINE_HAS_VX) + if (cpu_has_vx()) *(addr_t *)((addr_t) child->thread.fpu.vxrs + 2*offset) = data; else @@ -630,7 +630,7 @@ static u32 __peek_user_compat(struct task_struct *child, addr_t addr) * or the child->thread.fpu.vxrs array */ offset = addr - offsetof(struct compat_user, regs.fp_regs.fprs); - if (MACHINE_HAS_VX) + if (cpu_has_vx()) tmp = *(__u32 *) ((addr_t) child->thread.fpu.vxrs + 2*offset); else @@ -748,8 +748,6 @@ static int __poke_user_compat(struct task_struct *child, /* * floating point control reg. is in the thread structure */ - if (test_fp_ctl(tmp)) - return -EINVAL; child->thread.fpu.fpc = data; } else if (addr < offsetof(struct compat_user, regs.fp_regs) + sizeof(s390_fp_regs)) { @@ -758,7 +756,7 @@ static int __poke_user_compat(struct task_struct *child, * or the child->thread.fpu.vxrs array */ offset = addr - offsetof(struct compat_user, regs.fp_regs.fprs); - if (MACHINE_HAS_VX) + if (cpu_has_vx()) *(__u32 *)((addr_t) child->thread.fpu.vxrs + 2*offset) = tmp; else @@ -914,19 +912,18 @@ static int s390_fpregs_set(struct task_struct *target, if (target == current) save_fpu_regs(); - if (MACHINE_HAS_VX) + if (cpu_has_vx()) convert_vx_to_fp(fprs, target->thread.fpu.vxrs); else memcpy(&fprs, target->thread.fpu.fprs, sizeof(fprs)); - /* If setting FPC, must validate it first. */ if (count > 0 && pos < offsetof(s390_fp_regs, fprs)) { u32 ufpc[2] = { target->thread.fpu.fpc, 0 }; rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &ufpc, 0, offsetof(s390_fp_regs, fprs)); if (rc) return rc; - if (ufpc[1] != 0 || test_fp_ctl(ufpc[0])) + if (ufpc[1] != 0) return -EINVAL; target->thread.fpu.fpc = ufpc[0]; } @@ -937,7 +934,7 @@ static int s390_fpregs_set(struct task_struct *target, if (rc) return rc; - if (MACHINE_HAS_VX) + if (cpu_has_vx()) convert_fp_to_vx(target->thread.fpu.vxrs, fprs); else memcpy(target->thread.fpu.fprs, &fprs, sizeof(fprs)); @@ -988,7 +985,7 @@ static int s390_vxrs_low_get(struct task_struct *target, __u64 vxrs[__NUM_VXRS_LOW]; int i; - if (!MACHINE_HAS_VX) + if (!cpu_has_vx()) return -ENODEV; if (target == current) save_fpu_regs(); @@ -1005,7 +1002,7 @@ static int s390_vxrs_low_set(struct task_struct *target, __u64 vxrs[__NUM_VXRS_LOW]; int i, rc; - if (!MACHINE_HAS_VX) + if (!cpu_has_vx()) return -ENODEV; if (target == current) save_fpu_regs(); @@ -1025,7 +1022,7 @@ static int s390_vxrs_high_get(struct task_struct *target, const struct user_regset *regset, struct membuf to) { - if (!MACHINE_HAS_VX) + if (!cpu_has_vx()) return -ENODEV; if (target == current) save_fpu_regs(); @@ -1040,7 +1037,7 @@ static int s390_vxrs_high_set(struct task_struct *target, { int rc; - if (!MACHINE_HAS_VX) + if (!cpu_has_vx()) return -ENODEV; if (target == current) save_fpu_regs(); diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 5701356f4f3302..d1f3b56e7afc2b 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -408,15 +408,15 @@ static void __init setup_lowcore(void) lc->restart_psw.mask = PSW_KERNEL_BITS & ~PSW_MASK_DAT; lc->restart_psw.addr = __pa(restart_int_handler); - lc->external_new_psw.mask = PSW_KERNEL_BITS | PSW_MASK_MCHECK; + lc->external_new_psw.mask = PSW_KERNEL_BITS; lc->external_new_psw.addr = (unsigned long) ext_int_handler; - lc->svc_new_psw.mask = PSW_KERNEL_BITS | PSW_MASK_MCHECK; + lc->svc_new_psw.mask = PSW_KERNEL_BITS; lc->svc_new_psw.addr = (unsigned long) system_call; - lc->program_new_psw.mask = PSW_KERNEL_BITS | PSW_MASK_MCHECK; + lc->program_new_psw.mask = PSW_KERNEL_BITS; lc->program_new_psw.addr = (unsigned long) pgm_check_handler; lc->mcck_new_psw.mask = PSW_KERNEL_BITS; lc->mcck_new_psw.addr = (unsigned long) mcck_int_handler; - lc->io_new_psw.mask = PSW_KERNEL_BITS | PSW_MASK_MCHECK; + lc->io_new_psw.mask = PSW_KERNEL_BITS; lc->io_new_psw.addr = (unsigned long) io_int_handler; lc->clock_comparator = clock_comparator_max; lc->current_task = (unsigned long)&init_task; @@ -819,22 +819,6 @@ static void __init setup_randomness(void) static_branch_enable(&s390_arch_random_available); } -/* - * Find the correct size for the task_struct. This depends on - * the size of the struct fpu at the end of the thread_struct - * which is embedded in the task_struct. - */ -static void __init setup_task_size(void) -{ - int task_size = sizeof(struct task_struct); - - if (!MACHINE_HAS_VX) { - task_size -= sizeof(__vector128) * __NUM_VXRS; - task_size += sizeof(freg_t) * __NUM_FPRS; - } - arch_task_struct_size = task_size; -} - /* * Issue diagnose 318 to set the control program name and * version codes. @@ -927,7 +911,6 @@ void __init setup_arch(char **cmdline_p) os_info_init(); setup_ipl(); - setup_task_size(); setup_control_program_code(); /* Do some memory reservations *before* memory is added to memblock */ diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index d63557d3868c1b..43e9661cd715ce 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -149,10 +150,6 @@ static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs) if (!is_ri_task(current) && (user_sregs.regs.psw.mask & PSW_MASK_RI)) return -EINVAL; - /* Test the floating-point-control word. */ - if (test_fp_ctl(user_sregs.fpregs.fpc)) - return -EINVAL; - /* Use regs->psw.mask instead of PSW_USER_BITS to preserve PER bit. */ regs->psw.mask = (regs->psw.mask & ~(PSW_MASK_USER | PSW_MASK_RI)) | (user_sregs.regs.psw.mask & (PSW_MASK_USER | PSW_MASK_RI)); @@ -182,7 +179,7 @@ static int save_sigregs_ext(struct pt_regs *regs, int i; /* Save vector registers to signal stack */ - if (MACHINE_HAS_VX) { + if (cpu_has_vx()) { for (i = 0; i < __NUM_VXRS_LOW; i++) vxrs[i] = current->thread.fpu.vxrs[i].low; if (__copy_to_user(&sregs_ext->vxrs_low, vxrs, @@ -202,7 +199,7 @@ static int restore_sigregs_ext(struct pt_regs *regs, int i; /* Restore vector registers from signal stack */ - if (MACHINE_HAS_VX) { + if (cpu_has_vx()) { if (__copy_from_user(vxrs, &sregs_ext->vxrs_low, sizeof(sregs_ext->vxrs_low)) || __copy_from_user(current->thread.fpu.vxrs + __NUM_VXRS_LOW, @@ -300,7 +297,7 @@ static int setup_frame(int sig, struct k_sigaction *ka, * included in the signal frame on a 31-bit system. */ frame_size = sizeof(*frame) - sizeof(frame->sregs_ext); - if (MACHINE_HAS_VX) + if (cpu_has_vx()) frame_size += sizeof(frame->sregs_ext); frame = get_sigframe(ka, regs, frame_size); if (frame == (void __user *) -1UL) @@ -377,7 +374,7 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, * included in the signal frame on a 31-bit system. */ uc_flags = 0; - if (MACHINE_HAS_VX) { + if (cpu_has_vx()) { frame_size += sizeof(_sigregs_ext); uc_flags |= UC_VXRS; } diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index f7fcfff09acf3d..c39d9f0d4b1c61 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -582,7 +582,7 @@ int smp_store_status(int cpu) if (__pcpu_sigp_relax(pcpu->address, SIGP_STORE_STATUS_AT_ADDRESS, pa) != SIGP_CC_ORDER_CODE_ACCEPTED) return -EIO; - if (!MACHINE_HAS_VX && !MACHINE_HAS_GS) + if (!cpu_has_vx() && !MACHINE_HAS_GS) return 0; pa = lc->mcesad & MCESA_ORIGIN_MASK; if (MACHINE_HAS_GS) @@ -638,7 +638,7 @@ void __init smp_save_dump_ipl_cpu(void) copy_oldmem_kernel(regs, __LC_FPREGS_SAVE_AREA, 512); save_area_add_regs(sa, regs); memblock_free(regs, 512); - if (MACHINE_HAS_VX) + if (cpu_has_vx()) save_area_add_vxrs(sa, boot_cpu_vector_save_area); } @@ -671,7 +671,7 @@ void __init smp_save_dump_secondary_cpus(void) panic("could not allocate memory for save area\n"); __pcpu_sigp_relax(addr, SIGP_STORE_STATUS_AT_ADDRESS, __pa(page)); save_area_add_regs(sa, page); - if (MACHINE_HAS_VX) { + if (cpu_has_vx()) { __pcpu_sigp_relax(addr, SIGP_STORE_ADDITIONAL_STATUS, __pa(page)); save_area_add_vxrs(sa, page); } diff --git a/arch/s390/kernel/syscalls/syscall.tbl b/arch/s390/kernel/syscalls/syscall.tbl index 86fec9b080f61b..095bb86339a7d3 100644 --- a/arch/s390/kernel/syscalls/syscall.tbl +++ b/arch/s390/kernel/syscalls/syscall.tbl @@ -459,3 +459,8 @@ 454 common futex_wake sys_futex_wake sys_futex_wake 455 common futex_wait sys_futex_wait sys_futex_wait 456 common futex_requeue sys_futex_requeue sys_futex_requeue +457 common statmount sys_statmount sys_statmount +458 common listmount sys_listmount sys_listmount +459 common lsm_get_self_attr sys_lsm_get_self_attr sys_lsm_get_self_attr +460 common lsm_set_self_attr sys_lsm_set_self_attr sys_lsm_set_self_attr +461 common lsm_list_modules sys_lsm_list_modules sys_lsm_list_modules diff --git a/arch/s390/kernel/sysinfo.c b/arch/s390/kernel/sysinfo.c index b5e364358ce43a..f6f8f498c9be39 100644 --- a/arch/s390/kernel/sysinfo.c +++ b/arch/s390/kernel/sysinfo.c @@ -81,10 +81,12 @@ static bool convert_ext_name(unsigned char encoding, char *name, size_t len) static void stsi_1_1_1(struct seq_file *m, struct sysinfo_1_1_1 *info) { + bool has_var_cap; int i; if (stsi(info, 1, 1, 1)) return; + has_var_cap = !!info->model_var_cap[0]; EBCASC(info->manufacturer, sizeof(info->manufacturer)); EBCASC(info->type, sizeof(info->type)); EBCASC(info->model, sizeof(info->model)); @@ -93,6 +95,8 @@ static void stsi_1_1_1(struct seq_file *m, struct sysinfo_1_1_1 *info) EBCASC(info->model_capacity, sizeof(info->model_capacity)); EBCASC(info->model_perm_cap, sizeof(info->model_perm_cap)); EBCASC(info->model_temp_cap, sizeof(info->model_temp_cap)); + if (has_var_cap) + EBCASC(info->model_var_cap, sizeof(info->model_var_cap)); seq_printf(m, "Manufacturer: %-16.16s\n", info->manufacturer); seq_printf(m, "Type: %-4.4s\n", info->type); if (info->lic) @@ -120,12 +124,18 @@ static void stsi_1_1_1(struct seq_file *m, struct sysinfo_1_1_1 *info) seq_printf(m, "Model Temp. Capacity: %-16.16s %08u\n", info->model_temp_cap, info->model_temp_cap_rating); + if (has_var_cap && info->model_var_cap_rating) + seq_printf(m, "Model Var. Capacity: %-16.16s %08u\n", + info->model_var_cap, + info->model_var_cap_rating); if (info->ncr) seq_printf(m, "Nominal Cap. Rating: %08u\n", info->ncr); if (info->npr) seq_printf(m, "Nominal Perm. Rating: %08u\n", info->npr); if (info->ntr) seq_printf(m, "Nominal Temp. Rating: %08u\n", info->ntr); + if (has_var_cap && info->nvr) + seq_printf(m, "Nominal Var. Rating: %08u\n", info->nvr); if (info->cai) { seq_printf(m, "Capacity Adj. Ind.: %d\n", info->cai); seq_printf(m, "Capacity Ch. Reason: %d\n", info->ccr); diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 1d2aa448d1031c..46dac4540ca8e1 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -43,10 +43,12 @@ static inline void __user *get_trap_ip(struct pt_regs *regs) return (void __user *) (address - (regs->int_code >> 16)); } +#ifdef CONFIG_GENERIC_BUG int is_valid_bugaddr(unsigned long addr) { return 1; } +#endif void do_report_trap(struct pt_regs *regs, int si_signo, int si_code, char *str) { @@ -193,7 +195,7 @@ static void vector_exception(struct pt_regs *regs) { int si_code, vic; - if (!MACHINE_HAS_VX) { + if (!cpu_has_vx()) { do_trap(regs, SIGILL, ILL_ILLOPN, "illegal operation"); return; } @@ -286,6 +288,17 @@ static void __init test_monitor_call(void) void __init trap_init(void) { + unsigned long flags; + struct ctlreg cr0; + + local_irq_save(flags); + cr0 = local_ctl_clear_bit(0, CR0_LOW_ADDRESS_PROTECTION_BIT); + psw_bits(S390_lowcore.external_new_psw).mcheck = 1; + psw_bits(S390_lowcore.program_new_psw).mcheck = 1; + psw_bits(S390_lowcore.svc_new_psw).mcheck = 1; + psw_bits(S390_lowcore.io_new_psw).mcheck = 1; + local_ctl_load(0, &cr0); + local_irq_restore(flags); local_mcck_enable(); test_monitor_call(); } diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S index 2ae201ebf90b97..e32ef446f45115 100644 --- a/arch/s390/kernel/vmlinux.lds.S +++ b/arch/s390/kernel/vmlinux.lds.S @@ -52,6 +52,7 @@ SECTIONS SOFTIRQENTRY_TEXT FTRACE_HOTPATCH_TRAMPOLINES_TEXT *(.text.*_indirect_*) + *(.fixup) *(.gnu.warning) . = ALIGN(PAGE_SIZE); _etext = .; /* End of text section */ diff --git a/arch/s390/kvm/Kconfig b/arch/s390/kvm/Kconfig index 45fdf2a9b2e326..72e9b7dcdf7d97 100644 --- a/arch/s390/kvm/Kconfig +++ b/arch/s390/kvm/Kconfig @@ -20,19 +20,16 @@ config KVM def_tristate y prompt "Kernel-based Virtual Machine (KVM) support" depends on HAVE_KVM - select PREEMPT_NOTIFIERS select HAVE_KVM_CPU_RELAX_INTERCEPT select HAVE_KVM_VCPU_ASYNC_IOCTL - select HAVE_KVM_EVENTFD select KVM_ASYNC_PF select KVM_ASYNC_PF_SYNC + select KVM_COMMON select HAVE_KVM_IRQCHIP - select HAVE_KVM_IRQFD select HAVE_KVM_IRQ_ROUTING select HAVE_KVM_INVALID_WAKEUPS select HAVE_KVM_NO_POLL select KVM_VFIO - select INTERVAL_TREE select MMU_NOTIFIER help Support hosting paravirtualized guest machines using the SIE diff --git a/arch/s390/kvm/guestdbg.c b/arch/s390/kvm/guestdbg.c index 3765c4223bf944..80879fc73c9005 100644 --- a/arch/s390/kvm/guestdbg.c +++ b/arch/s390/kvm/guestdbg.c @@ -213,8 +213,8 @@ int kvm_s390_import_bp_data(struct kvm_vcpu *vcpu, else if (dbg->arch.nr_hw_bp > MAX_BP_COUNT) return -EINVAL; - bp_data = memdup_user(dbg->arch.hw_bp, - sizeof(*bp_data) * dbg->arch.nr_hw_bp); + bp_data = memdup_array_user(dbg->arch.hw_bp, dbg->arch.nr_hw_bp, + sizeof(*bp_data)); if (IS_ERR(bp_data)) return PTR_ERR(bp_data); diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index efaebba5ee19c7..fc4007cc067a68 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -639,7 +639,7 @@ static int __write_machine_check(struct kvm_vcpu *vcpu, rc |= put_guest_lc(vcpu, mci.val, (u64 __user *) __LC_MCCK_CODE); /* Register-save areas */ - if (MACHINE_HAS_VX) { + if (cpu_has_vx()) { convert_vx_to_fp(fprs, (__vector128 *) vcpu->run->s.regs.vrs); rc |= write_guest_lc(vcpu, __LC_FPREGS_SAVE_AREA, fprs, 128); } else { diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 7aa0e668488f0d..ea63ac76988914 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -563,7 +563,6 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_ENABLE_CAP: case KVM_CAP_S390_CSS_SUPPORT: case KVM_CAP_IOEVENTFD: - case KVM_CAP_DEVICE_CTRL: case KVM_CAP_S390_IRQCHIP: case KVM_CAP_VM_ATTRIBUTES: case KVM_CAP_MP_STATE: @@ -618,7 +617,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) r = MACHINE_HAS_ESOP; break; case KVM_CAP_S390_VECTOR_REGISTERS: - r = MACHINE_HAS_VX; + r = test_facility(129); break; case KVM_CAP_S390_RI: r = test_facility(64); @@ -767,7 +766,7 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap) mutex_lock(&kvm->lock); if (kvm->created_vcpus) { r = -EBUSY; - } else if (MACHINE_HAS_VX) { + } else if (cpu_has_vx()) { set_kvm_facility(kvm->arch.model.fac_mask, 129); set_kvm_facility(kvm->arch.model.fac_list, 129); if (test_facility(134)) { @@ -3962,9 +3961,9 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) if (test_kvm_facility(vcpu->kvm, 156)) vcpu->run->kvm_valid_regs |= KVM_SYNC_ETOKEN; /* fprs can be synchronized via vrs, even if the guest has no vx. With - * MACHINE_HAS_VX, (load|store)_fpu_regs() will work with vrs format. + * cpu_has_vx(), (load|store)_fpu_regs() will work with vrs format. */ - if (MACHINE_HAS_VX) + if (cpu_has_vx()) vcpu->run->kvm_valid_regs |= KVM_SYNC_VRS; else vcpu->run->kvm_valid_regs |= KVM_SYNC_FPRS; @@ -4316,18 +4315,13 @@ int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) vcpu_load(vcpu); - if (test_fp_ctl(fpu->fpc)) { - ret = -EINVAL; - goto out; - } vcpu->run->s.regs.fpc = fpu->fpc; - if (MACHINE_HAS_VX) + if (cpu_has_vx()) convert_fp_to_vx((__vector128 *) vcpu->run->s.regs.vrs, (freg_t *) fpu->fprs); else memcpy(vcpu->run->s.regs.fprs, &fpu->fprs, sizeof(fpu->fprs)); -out: vcpu_put(vcpu); return ret; } @@ -4336,9 +4330,7 @@ int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) { vcpu_load(vcpu); - /* make sure we have the latest values */ - save_fpu_regs(); - if (MACHINE_HAS_VX) + if (cpu_has_vx()) convert_vx_to_fp((freg_t *) fpu->fprs, (__vector128 *) vcpu->run->s.regs.vrs); else @@ -4963,14 +4955,11 @@ static void sync_regs(struct kvm_vcpu *vcpu) save_fpu_regs(); vcpu->arch.host_fpregs.fpc = current->thread.fpu.fpc; vcpu->arch.host_fpregs.regs = current->thread.fpu.regs; - if (MACHINE_HAS_VX) + if (cpu_has_vx()) current->thread.fpu.regs = vcpu->run->s.regs.vrs; else current->thread.fpu.regs = vcpu->run->s.regs.fprs; current->thread.fpu.fpc = vcpu->run->s.regs.fpc; - if (test_fp_ctl(current->thread.fpu.fpc)) - /* User space provided an invalid FPC, let's clear it */ - current->thread.fpu.fpc = 0; /* Sync fmt2 only data */ if (likely(!kvm_s390_pv_cpu_is_protected(vcpu))) { @@ -5145,7 +5134,7 @@ int kvm_s390_store_status_unloaded(struct kvm_vcpu *vcpu, unsigned long gpa) gpa -= __LC_FPREGS_SAVE_AREA; /* manually convert vector registers if necessary */ - if (MACHINE_HAS_VX) { + if (cpu_has_vx()) { convert_vx_to_fp(fprs, (__vector128 *) vcpu->run->s.regs.vrs); rc = write_guest_abs(vcpu, gpa + __LC_FPREGS_SAVE_AREA, fprs, 128); diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c index 8207a892bbe22f..fef42e2a80a2ae 100644 --- a/arch/s390/kvm/vsie.c +++ b/arch/s390/kvm/vsie.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "kvm-s390.h" #include "gaccess.h" @@ -984,12 +985,26 @@ static void retry_vsie_icpt(struct vsie_page *vsie_page) static int handle_stfle(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) { struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s; - __u32 fac = READ_ONCE(vsie_page->scb_o->fac) & 0x7ffffff8U; + __u32 fac = READ_ONCE(vsie_page->scb_o->fac); + /* + * Alternate-STFLE-Interpretive-Execution facilities are not supported + * -> format-0 flcb + */ if (fac && test_kvm_facility(vcpu->kvm, 7)) { retry_vsie_icpt(vsie_page); + /* + * The facility list origin (FLO) is in bits 1 - 28 of the FLD + * so we need to mask here before reading. + */ + fac = fac & 0x7ffffff8U; + /* + * format-0 -> size of nested guest's facility list == guest's size + * guest's size == host's size, since STFLE is interpretatively executed + * using a format-0 for the guest, too. + */ if (read_guest_real(vcpu, fac, &vsie_page->fac, - sizeof(vsie_page->fac))) + stfle_size() * sizeof(u64))) return set_validity_icpt(scb_s, 0x1090U); scb_s->fac = (__u32)(__u64) &vsie_page->fac; } diff --git a/arch/s390/lib/test_unwind.c b/arch/s390/lib/test_unwind.c index 7231bf97b93adb..2848e3fb2ff5e1 100644 --- a/arch/s390/lib/test_unwind.c +++ b/arch/s390/lib/test_unwind.c @@ -350,15 +350,15 @@ static noinline int unwindme_func3(struct unwindme *u) /* This function must appear in the backtrace. */ static noinline int unwindme_func2(struct unwindme *u) { - unsigned long flags; + unsigned long flags, mflags; int rc; if (u->flags & UWM_SWITCH_STACK) { local_irq_save(flags); - local_mcck_disable(); + local_mcck_save(mflags); rc = call_on_stack(1, S390_lowcore.nodat_stack, int, unwindme_func3, struct unwindme *, u); - local_mcck_enable(); + local_mcck_restore(mflags); local_irq_restore(flags); return rc; } else { diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index ab4098886e562f..ac4c78546d9737 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -280,7 +280,6 @@ static void do_sigbus(struct pt_regs *regs) static void do_exception(struct pt_regs *regs, int access) { struct vm_area_struct *vma; - struct task_struct *tsk; unsigned long address; struct mm_struct *mm; enum fault_type type; @@ -289,7 +288,6 @@ static void do_exception(struct pt_regs *regs, int access) vm_fault_t fault; bool is_write; - tsk = current; /* * The instruction that caused the program check has * been nullified. Don't signal single step via SIGTRAP. @@ -297,7 +295,7 @@ static void do_exception(struct pt_regs *regs, int access) clear_thread_flag(TIF_PER_TRAP); if (kprobe_page_fault(regs, 14)) return; - mm = tsk->mm; + mm = current->mm; address = get_fault_address(regs); is_write = fault_is_write(regs); type = get_fault_type(regs); diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index 5cb92941540b32..99422926efe1b5 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c @@ -125,32 +125,23 @@ static inline pte_t ptep_flush_lazy(struct mm_struct *mm, static inline pgste_t pgste_get_lock(pte_t *ptep) { - unsigned long new = 0; + unsigned long value = 0; #ifdef CONFIG_PGSTE - unsigned long old; - - asm( - " lg %0,%2\n" - "0: lgr %1,%0\n" - " nihh %0,0xff7f\n" /* clear PCL bit in old */ - " oihh %1,0x0080\n" /* set PCL bit in new */ - " csg %0,%1,%2\n" - " jl 0b\n" - : "=&d" (old), "=&d" (new), "=Q" (ptep[PTRS_PER_PTE]) - : "Q" (ptep[PTRS_PER_PTE]) : "cc", "memory"); + unsigned long *ptr = (unsigned long *)(ptep + PTRS_PER_PTE); + + do { + value = __atomic64_or_barrier(PGSTE_PCL_BIT, ptr); + } while (value & PGSTE_PCL_BIT); + value |= PGSTE_PCL_BIT; #endif - return __pgste(new); + return __pgste(value); } static inline void pgste_set_unlock(pte_t *ptep, pgste_t pgste) { #ifdef CONFIG_PGSTE - asm( - " nihh %1,0xff7f\n" /* clear PCL bit */ - " stg %1,%0\n" - : "=Q" (ptep[PTRS_PER_PTE]) - : "d" (pgste_val(pgste)), "Q" (ptep[PTRS_PER_PTE]) - : "cc", "memory"); + barrier(); + WRITE_ONCE(*(unsigned long *)(ptep + PTRS_PER_PTE), pgste_val(pgste) & ~PGSTE_PCL_BIT); #endif } diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c index bf06b7283f0ca6..b418333bb08635 100644 --- a/arch/s390/net/bpf_jit_comp.c +++ b/arch/s390/net/bpf_jit_comp.c @@ -779,7 +779,7 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, int i, bool extra_pass, u32 stack_depth) { struct bpf_insn *insn = &fp->insnsi[i]; - s16 branch_oc_off = insn->off; + s32 branch_oc_off = insn->off; u32 dst_reg = insn->dst_reg; u32 src_reg = insn->src_reg; int last, insn_count = 1; @@ -2362,7 +2362,8 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, return -ENOTSUPP; /* Return to %r14, since func_addr and %r0 are not available. */ - if (!func_addr && !(flags & BPF_TRAMP_F_ORIG_STACK)) + if ((!func_addr && !(flags & BPF_TRAMP_F_ORIG_STACK)) || + (flags & BPF_TRAMP_F_INDIRECT)) flags |= BPF_TRAMP_F_SKIP_FRAME; /* @@ -2637,6 +2638,21 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, return 0; } +int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags, + struct bpf_tramp_links *tlinks, void *orig_call) +{ + struct bpf_tramp_image im; + struct bpf_tramp_jit tjit; + int ret; + + memset(&tjit, 0, sizeof(tjit)); + + ret = __arch_prepare_bpf_trampoline(&im, &tjit, m, flags, + tlinks, orig_call); + + return ret < 0 ? ret : tjit.common.prg; +} + int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *image_end, const struct btf_func_model *m, u32 flags, struct bpf_tramp_links *tlinks, @@ -2644,30 +2660,27 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, { struct bpf_tramp_jit tjit; int ret; - int i; - for (i = 0; i < 2; i++) { - if (i == 0) { - /* Compute offsets, check whether the code fits. */ - memset(&tjit, 0, sizeof(tjit)); - } else { - /* Generate the code. */ - tjit.common.prg = 0; - tjit.common.prg_buf = image; - } - ret = __arch_prepare_bpf_trampoline(im, &tjit, m, flags, - tlinks, func_addr); - if (ret < 0) - return ret; - if (tjit.common.prg > (char *)image_end - (char *)image) - /* - * Use the same error code as for exceeding - * BPF_MAX_TRAMP_LINKS. - */ - return -E2BIG; - } + /* Compute offsets, check whether the code fits. */ + memset(&tjit, 0, sizeof(tjit)); + ret = __arch_prepare_bpf_trampoline(im, &tjit, m, flags, + tlinks, func_addr); + + if (ret < 0) + return ret; + if (tjit.common.prg > (char *)image_end - (char *)image) + /* + * Use the same error code as for exceeding + * BPF_MAX_TRAMP_LINKS. + */ + return -E2BIG; + + tjit.common.prg = 0; + tjit.common.prg_buf = image; + ret = __arch_prepare_bpf_trampoline(im, &tjit, m, flags, + tlinks, func_addr); - return tjit.common.prg; + return ret < 0 ? ret : tjit.common.prg; } bool bpf_jit_supports_subprog_tailcalls(void) diff --git a/arch/s390/pci/pci_mmio.c b/arch/s390/pci/pci_mmio.c index 5880893329310d..a90499c087f0c5 100644 --- a/arch/s390/pci/pci_mmio.c +++ b/arch/s390/pci/pci_mmio.c @@ -97,9 +97,9 @@ static inline int __memcpy_toio_inuser(void __iomem *dst, return -EINVAL; while (n > 0) { - size = zpci_get_max_write_size((u64 __force) dst, - (u64 __force) src, n, - ZPCI_MAX_WRITE_SIZE); + size = zpci_get_max_io_size((u64 __force) dst, + (u64 __force) src, n, + ZPCI_MAX_WRITE_SIZE); if (size > 8) /* main path */ rc = __pcistb_mio_inuser(dst, src, size, &status); else @@ -242,9 +242,9 @@ static inline int __memcpy_fromio_inuser(void __user *dst, u8 status; while (n > 0) { - size = zpci_get_max_write_size((u64 __force) src, - (u64 __force) dst, n, - ZPCI_MAX_READ_SIZE); + size = zpci_get_max_io_size((u64 __force) src, + (u64 __force) dst, n, + ZPCI_MAX_READ_SIZE); rc = __pcilg_mio_inuser(dst, src, size, &status); if (rc) break; diff --git a/arch/s390/tools/gen_facilities.c b/arch/s390/tools/gen_facilities.c index cb0aff5c0187a1..68580cbea4e629 100644 --- a/arch/s390/tools/gen_facilities.c +++ b/arch/s390/tools/gen_facilities.c @@ -46,6 +46,7 @@ static struct facility_def facility_defs[] = { #endif #ifdef CONFIG_HAVE_MARCH_Z13_FEATURES 53, /* load-and-zero-rightmost-byte, etc. */ + 129, /* vector */ #endif #ifdef CONFIG_HAVE_MARCH_Z14_FEATURES 58, /* miscellaneous-instruction-extension 2 */ diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index 0f279360838a4a..30d117f9ad7eea 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c @@ -1220,7 +1220,7 @@ static int __init arch_setup(void) lcdc_info.ch[0].num_modes = ARRAY_SIZE(ecovec_dvi_modes); /* No backlight */ - gpio_backlight_data.fbdev = NULL; + gpio_backlight_data.dev = NULL; gpio_set_value(GPIO_PTA2, 1); gpio_set_value(GPIO_PTU1, 1); diff --git a/arch/sh/configs/sdk7786_defconfig b/arch/sh/configs/sdk7786_defconfig index cf59b98446e4d3..7b427c17fbfecb 100644 --- a/arch/sh/configs/sdk7786_defconfig +++ b/arch/sh/configs/sdk7786_defconfig @@ -171,7 +171,8 @@ CONFIG_BTRFS_FS=y CONFIG_AUTOFS_FS=m CONFIG_FUSE_FS=y CONFIG_CUSE=m -CONFIG_FSCACHE=m +CONFIG_NETFS_SUPPORT=m +CONFIG_FSCACHE=y CONFIG_CACHEFILES=m CONFIG_ISO9660_FS=m CONFIG_JOLIET=y diff --git a/arch/sh/configs/titan_defconfig b/arch/sh/configs/titan_defconfig index 871092753591a0..c1032559ecd4a5 100644 --- a/arch/sh/configs/titan_defconfig +++ b/arch/sh/configs/titan_defconfig @@ -138,7 +138,6 @@ CONFIG_NET_ACT_POLICE=m CONFIG_NET_ACT_GACT=m CONFIG_GACT_PROB=y CONFIG_NET_ACT_MIRRED=m -CONFIG_NET_ACT_IPT=m CONFIG_NET_ACT_PEDIT=m CONFIG_FW_LOADER=m CONFIG_CONNECTOR=m diff --git a/arch/sh/include/asm/cacheflush.h b/arch/sh/include/asm/cacheflush.h index 878b6b551bd2d0..51112f54552b32 100644 --- a/arch/sh/include/asm/cacheflush.h +++ b/arch/sh/include/asm/cacheflush.h @@ -90,6 +90,7 @@ extern void copy_from_user_page(struct vm_area_struct *vma, unsigned long len); #define flush_cache_vmap(start, end) local_flush_cache_all(NULL) +#define flush_cache_vmap_early(start, end) do { } while (0) #define flush_cache_vunmap(start, end) local_flush_cache_all(NULL) #define flush_dcache_mmap_lock(mapping) do { } while (0) diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h index ac521f287fa596..cf5eab840d5796 100644 --- a/arch/sh/include/asm/io.h +++ b/arch/sh/include/asm/io.h @@ -302,15 +302,6 @@ unsigned long long poke_real_address_q(unsigned long long addr, ioremap_prot((addr), (size), pgprot_val(PAGE_KERNEL)) #endif /* CONFIG_MMU */ -#define ioremap_uc ioremap - -/* - * Convert a physical pointer to a virtual kernel pointer for /dev/mem - * access - */ -#define xlate_dev_mem_ptr(p) __va(p) -#define unxlate_dev_mem_ptr(p, v) do { } while (0) - #include #define ARCH_HAS_VALID_PHYS_ADDR_RANGE diff --git a/arch/sh/include/asm/traps_32.h b/arch/sh/include/asm/traps_32.h index 8c5bbb7b6053cf..8f14071bea7226 100644 --- a/arch/sh/include/asm/traps_32.h +++ b/arch/sh/include/asm/traps_32.h @@ -43,6 +43,9 @@ static inline void trigger_address_error(void) asmlinkage void do_address_error(struct pt_regs *regs, unsigned long writeaccess, unsigned long address); +asmlinkage void do_page_fault(struct pt_regs *regs, + unsigned long error_code, + unsigned long address); asmlinkage void do_divide_error(unsigned long r4); asmlinkage void do_reserved_inst(void); asmlinkage void do_illegal_slot_inst(void); diff --git a/arch/sh/kernel/syscalls/syscall.tbl b/arch/sh/kernel/syscalls/syscall.tbl index 363fae0fe9bf48..86fe269f02203b 100644 --- a/arch/sh/kernel/syscalls/syscall.tbl +++ b/arch/sh/kernel/syscalls/syscall.tbl @@ -459,3 +459,8 @@ 454 common futex_wake sys_futex_wake 455 common futex_wait sys_futex_wait 456 common futex_requeue sys_futex_requeue +457 common statmount sys_statmount +458 common listmount sys_listmount +459 common lsm_get_self_attr sys_lsm_get_self_attr +460 common lsm_set_self_attr sys_lsm_set_self_attr +461 common lsm_list_modules sys_lsm_list_modules diff --git a/arch/sh/kernel/vsyscall/Makefile b/arch/sh/kernel/vsyscall/Makefile index 6e86644480488f..118744d349e21e 100644 --- a/arch/sh/kernel/vsyscall/Makefile +++ b/arch/sh/kernel/vsyscall/Makefile @@ -1,11 +1,10 @@ # SPDX-License-Identifier: GPL-2.0 obj-y += vsyscall.o vsyscall-syscall.o vsyscall-syms.o -$(obj)/vsyscall-syscall.o: \ - $(foreach F,trapa,$(obj)/vsyscall-$F.so) +$(obj)/vsyscall-syscall.o: $(obj)/vsyscall-trapa.so # Teach kbuild about targets -targets += $(foreach F,trapa,vsyscall-$F.o vsyscall-$F.so) +targets += vsyscall-trapa.o vsyscall-traps.so targets += vsyscall-note.o vsyscall.lds vsyscall-dummy.o # The DSO images are built using a special linker script diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig index 511c17aede4a96..455311d9a5e9c9 100644 --- a/arch/sh/mm/Kconfig +++ b/arch/sh/mm/Kconfig @@ -26,7 +26,7 @@ config ARCH_FORCE_MAX_ORDER default "10" help The kernel page allocator limits the size of maximal physically - contiguous allocations. The limit is called MAX_ORDER and it + contiguous allocations. The limit is called MAX_PAGE:_ORDER and it defines the maximal power of two of number of pages that can be allocated as a single contiguous block. This option allows overriding the default setting when ability to allocate very diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 49849790e66dc3..204c43cb3d4356 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig @@ -277,7 +277,7 @@ config ARCH_FORCE_MAX_ORDER default "12" help The kernel page allocator limits the size of maximal physically - contiguous allocations. The limit is called MAX_ORDER and it + contiguous allocations. The limit is called MAX_PAGE_ORDER and it defines the maximal power of two of number of pages that can be allocated as a single contiguous block. This option allows overriding the default setting when ability to allocate very diff --git a/arch/sparc/boot/Makefile b/arch/sparc/boot/Makefile index 45e5c76d449ea1..339c42d35089ac 100644 --- a/arch/sparc/boot/Makefile +++ b/arch/sparc/boot/Makefile @@ -24,16 +24,16 @@ ifeq ($(CONFIG_SPARC64),y) $(obj)/zImage: $(obj)/image FORCE $(call if_changed,gzip) - @echo ' kernel: $@ is ready' + @$(kecho) 'Kernel: $@ is ready' '(#'$(or $(KBUILD_BUILD_VERSION),`cat .version`)')' $(obj)/vmlinux.aout: vmlinux FORCE $(call if_changed,elftoaout) - @echo ' kernel: $@ is ready' + @$(kecho) 'Kernel: $@ is ready' '(#'$(or $(KBUILD_BUILD_VERSION),`cat .version`)')' else $(obj)/zImage: $(obj)/image FORCE $(call if_changed,strip) - @echo ' kernel: $@ is ready' + @$(kecho) 'Kernel: $@ is ready' '(#'$(or $(KBUILD_BUILD_VERSION),`cat .version`)')' # The following lines make a readable image for U-Boot. # uImage - Binary file read by U-boot @@ -59,13 +59,13 @@ targets += uImage $(obj)/uImage: $(obj)/image.gz FORCE $(call if_changed,uimage) $(call if_changed,uimage.o) - @echo ' Image $@ is ready' + @$(kecho) 'Kernel: $@ is ready' '(#'$(or $(KBUILD_BUILD_VERSION),`cat .version`)')' endif $(obj)/image: vmlinux FORCE $(call if_changed,strip) - @echo ' kernel: $@ is ready' + @$(kecho) 'Kernel: $@ is ready' '(#'$(or $(KBUILD_BUILD_VERSION),`cat .version`)')' $(obj)/tftpboot.img: $(obj)/image $(obj)/piggyback System.map $(ROOT_IMG) FORCE $(call if_changed,elftoaout) diff --git a/arch/sparc/include/asm/cacheflush_32.h b/arch/sparc/include/asm/cacheflush_32.h index f3b7270bf71b26..9fee0ccfccb8e1 100644 --- a/arch/sparc/include/asm/cacheflush_32.h +++ b/arch/sparc/include/asm/cacheflush_32.h @@ -48,6 +48,7 @@ static inline void flush_dcache_page(struct page *page) #define flush_dcache_mmap_unlock(mapping) do { } while (0) #define flush_cache_vmap(start, end) flush_cache_all() +#define flush_cache_vmap_early(start, end) do { } while (0) #define flush_cache_vunmap(start, end) flush_cache_all() /* When a context switch happens we must flush all user windows so that diff --git a/arch/sparc/include/asm/cacheflush_64.h b/arch/sparc/include/asm/cacheflush_64.h index 0e879004efff16..2b1261b77ecd1b 100644 --- a/arch/sparc/include/asm/cacheflush_64.h +++ b/arch/sparc/include/asm/cacheflush_64.h @@ -75,6 +75,7 @@ void flush_ptrace_access(struct vm_area_struct *, struct page *, #define flush_dcache_mmap_unlock(mapping) do { } while (0) #define flush_cache_vmap(start, end) do { } while (0) +#define flush_cache_vmap_early(start, end) do { } while (0) #define flush_cache_vunmap(start, end) do { } while (0) #endif /* !__ASSEMBLY__ */ diff --git a/arch/sparc/include/asm/io_64.h b/arch/sparc/include/asm/io_64.h index 9303270b22f3cf..c9528e4719cd22 100644 --- a/arch/sparc/include/asm/io_64.h +++ b/arch/sparc/include/asm/io_64.h @@ -423,7 +423,6 @@ static inline void __iomem *ioremap(unsigned long offset, unsigned long size) return (void __iomem *)offset; } -#define ioremap_uc(X,Y) ioremap((X),(Y)) #define ioremap_wc(X,Y) ioremap((X),(Y)) #define ioremap_wt(X,Y) ioremap((X),(Y)) static inline void __iomem *ioremap_np(unsigned long offset, unsigned long size) @@ -470,12 +469,6 @@ static inline int sbus_can_burst64(void) struct device; void sbus_set_sbus64(struct device *, int); -/* - * Convert a physical pointer to a virtual kernel pointer for /dev/mem - * access - */ -#define xlate_dev_mem_ptr(p) __va(p) - #endif #endif /* !(__SPARC64_IO_H) */ diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h index 5e41033bf4ca4b..a8c871b7d78608 100644 --- a/arch/sparc/include/asm/pgtable_64.h +++ b/arch/sparc/include/asm/pgtable_64.h @@ -706,6 +706,7 @@ static inline unsigned long pmd_write(pmd_t pmd) #define pud_write(pud) pte_write(__pte(pud_val(pud))) #ifdef CONFIG_TRANSPARENT_HUGEPAGE +#define pmd_dirty pmd_dirty static inline unsigned long pmd_dirty(pmd_t pmd) { pte_t pte = __pte(pmd_val(pmd)); diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index 0984bb6f0f17b1..58ea4ef9b622bd 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -5,7 +5,6 @@ # asflags-y := -ansi -ccflags-y := -Werror # Undefine sparc when processing vmlinux.lds - it is used # And teach CPP we are doing $(BITS) builds (for this case) diff --git a/arch/sparc/kernel/asm-offsets.c b/arch/sparc/kernel/asm-offsets.c index 5784f2df489a4d..3d9b9855dce917 100644 --- a/arch/sparc/kernel/asm-offsets.c +++ b/arch/sparc/kernel/asm-offsets.c @@ -19,14 +19,14 @@ #include #ifdef CONFIG_SPARC32 -int sparc32_foo(void) +static int __used sparc32_foo(void) { DEFINE(AOFF_thread_fork_kpsr, offsetof(struct thread_struct, fork_kpsr)); return 0; } #else -int sparc64_foo(void) +static int __used sparc64_foo(void) { #ifdef CONFIG_HIBERNATION BLANK(); @@ -45,7 +45,7 @@ int sparc64_foo(void) } #endif -int foo(void) +static int __used foo(void) { BLANK(); DEFINE(AOFF_task_thread, offsetof(struct task_struct, thread)); diff --git a/arch/sparc/kernel/pci_sabre.c b/arch/sparc/kernel/pci_sabre.c index 3c38ca40a22bac..a84598568300d3 100644 --- a/arch/sparc/kernel/pci_sabre.c +++ b/arch/sparc/kernel/pci_sabre.c @@ -13,7 +13,10 @@ #include #include #include -#include +#include +#include +#include +#include #include #include @@ -456,7 +459,6 @@ static void sabre_pbm_init(struct pci_pbm_info *pbm, static const struct of_device_id sabre_match[]; static int sabre_probe(struct platform_device *op) { - const struct of_device_id *match; const struct linux_prom64_registers *pr_regs; struct device_node *dp = op->dev.of_node; struct pci_pbm_info *pbm; @@ -466,8 +468,7 @@ static int sabre_probe(struct platform_device *op) const u32 *vdma; u64 clear_irq; - match = of_match_device(sabre_match, &op->dev); - hummingbird_p = match && (match->data != NULL); + hummingbird_p = (uintptr_t)device_get_match_data(&op->dev); if (!hummingbird_p) { struct device_node *cpu_dp; diff --git a/arch/sparc/kernel/pci_schizo.c b/arch/sparc/kernel/pci_schizo.c index 23b47f7fdb1d52..5d8dd49495863d 100644 --- a/arch/sparc/kernel/pci_schizo.c +++ b/arch/sparc/kernel/pci_schizo.c @@ -11,7 +11,10 @@ #include #include #include -#include +#include +#include +#include +#include #include #include @@ -1459,15 +1462,13 @@ out_err: return err; } -static const struct of_device_id schizo_match[]; static int schizo_probe(struct platform_device *op) { - const struct of_device_id *match; + unsigned long chip_type = (unsigned long)device_get_match_data(&op->dev); - match = of_match_device(schizo_match, &op->dev); - if (!match) + if (!chip_type) return -EINVAL; - return __schizo_init(op, (unsigned long)match->data); + return __schizo_init(op, chip_type); } /* The ordering of this table is very important. Some Tomatillo diff --git a/arch/sparc/kernel/pci_sun4v.c b/arch/sparc/kernel/pci_sun4v.c index c80b0a21d709cd..083e5f05a7f0c3 100644 --- a/arch/sparc/kernel/pci_sun4v.c +++ b/arch/sparc/kernel/pci_sun4v.c @@ -194,7 +194,7 @@ static void *dma_4v_alloc_coherent(struct device *dev, size_t size, size = IO_PAGE_ALIGN(size); order = get_order(size); - if (unlikely(order > MAX_ORDER)) + if (unlikely(order > MAX_PAGE_ORDER)) return NULL; npages = size >> IO_PAGE_SHIFT; diff --git a/arch/sparc/kernel/syscalls/syscall.tbl b/arch/sparc/kernel/syscalls/syscall.tbl index 7bcaa3d5ea442e..b23d59313589aa 100644 --- a/arch/sparc/kernel/syscalls/syscall.tbl +++ b/arch/sparc/kernel/syscalls/syscall.tbl @@ -502,3 +502,8 @@ 454 common futex_wake sys_futex_wake 455 common futex_wait sys_futex_wait 456 common futex_requeue sys_futex_requeue +457 common statmount sys_statmount +458 common listmount sys_listmount +459 common lsm_get_self_attr sys_lsm_get_self_attr +460 common lsm_set_self_attr sys_lsm_set_self_attr +461 common lsm_list_modules sys_lsm_list_modules diff --git a/arch/sparc/kernel/traps_32.c b/arch/sparc/kernel/traps_32.c index 179aabfa712ea0..bb149f6cc34b8b 100644 --- a/arch/sparc/kernel/traps_32.c +++ b/arch/sparc/kernel/traps_32.c @@ -10,6 +10,7 @@ * I hate traps on the sparc, grrr... */ +#include #include #include #include diff --git a/arch/sparc/kernel/traps_64.c b/arch/sparc/kernel/traps_64.c index 08ffd17d5ec340..dd048023bff5a3 100644 --- a/arch/sparc/kernel/traps_64.c +++ b/arch/sparc/kernel/traps_64.c @@ -9,6 +9,7 @@ * I like traps on v9, :)))) */ +#include #include #include #include @@ -897,7 +898,7 @@ void __init cheetah_ecache_flush_init(void) /* Now allocate error trap reporting scoreboard. */ sz = NR_CPUS * (2 * sizeof(struct cheetah_err_info)); - for (order = 0; order <= MAX_ORDER; order++) { + for (order = 0; order < NR_PAGE_ORDERS; order++) { if ((PAGE_SIZE << order) >= sz) break; } diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile index 063556fe2cb1d8..59669ebddd4e1c 100644 --- a/arch/sparc/lib/Makefile +++ b/arch/sparc/lib/Makefile @@ -3,7 +3,6 @@ # asflags-y := -ansi -DST_DIV0=0x02 -ccflags-y := -Werror lib-$(CONFIG_SPARC32) += ashrdi3.o lib-$(CONFIG_SPARC32) += memcpy.o memset.o diff --git a/arch/sparc/mm/Makefile b/arch/sparc/mm/Makefile index 871354aa3c002b..809d993f6d8882 100644 --- a/arch/sparc/mm/Makefile +++ b/arch/sparc/mm/Makefile @@ -3,7 +3,6 @@ # asflags-y := -ansi -ccflags-y := -Werror obj-$(CONFIG_SPARC64) += ultra.o tlb.o tsb.o obj-y += fault_$(BITS).o diff --git a/arch/sparc/mm/tsb.c b/arch/sparc/mm/tsb.c index 5e2931a184094b..6acd8a4c1e2aff 100644 --- a/arch/sparc/mm/tsb.c +++ b/arch/sparc/mm/tsb.c @@ -402,8 +402,8 @@ void tsb_grow(struct mm_struct *mm, unsigned long tsb_index, unsigned long rss) unsigned long new_rss_limit; gfp_t gfp_flags; - if (max_tsb_size > PAGE_SIZE << MAX_ORDER) - max_tsb_size = PAGE_SIZE << MAX_ORDER; + if (max_tsb_size > PAGE_SIZE << MAX_PAGE_ORDER) + max_tsb_size = PAGE_SIZE << MAX_PAGE_ORDER; new_cache_index = 0; for (new_size = 8192; new_size < max_tsb_size; new_size <<= 1UL) { diff --git a/arch/sparc/prom/Makefile b/arch/sparc/prom/Makefile index 397b79af77f7b0..a1adc75d805512 100644 --- a/arch/sparc/prom/Makefile +++ b/arch/sparc/prom/Makefile @@ -3,7 +3,6 @@ # Linux. # asflags := -ansi -ccflags := -Werror lib-y := bootstr_$(BITS).o lib-y += init_$(BITS).o diff --git a/arch/sparc/vdso/Makefile b/arch/sparc/vdso/Makefile index d08c3a0443f3a7..7f5eedf1f5e0ad 100644 --- a/arch/sparc/vdso/Makefile +++ b/arch/sparc/vdso/Makefile @@ -3,9 +3,6 @@ # Building vDSO images for sparc. # -VDSO64-$(CONFIG_SPARC64) := y -VDSOCOMPAT-$(CONFIG_COMPAT) := y - # files to link into the vdso vobjs-y := vdso-note.o vclock_gettime.o @@ -13,22 +10,15 @@ vobjs-y := vdso-note.o vclock_gettime.o obj-y += vma.o # vDSO images to build -vdso_img-$(VDSO64-y) += 64 -vdso_img-$(VDSOCOMPAT-y) += 32 +obj-$(CONFIG_SPARC64) += vdso-image-64.o +obj-$(CONFIG_COMPAT) += vdso-image-32.o -vobjs := $(foreach F,$(vobjs-y),$(obj)/$F) +vobjs := $(addprefix $(obj)/, $(vobjs-y)) $(obj)/vdso.o: $(obj)/vdso.so targets += vdso.lds $(vobjs-y) - -# Build the vDSO image C files and link them in. -vdso_img_objs := $(vdso_img-y:%=vdso-image-%.o) -vdso_img_cfiles := $(vdso_img-y:%=vdso-image-%.c) -vdso_img_sodbg := $(vdso_img-y:%=vdso%.so.dbg) -obj-y += $(vdso_img_objs) -targets += $(vdso_img_cfiles) -targets += $(vdso_img_sodbg) $(vdso_img-y:%=vdso%.so) +targets += $(foreach x, 32 64, vdso-image-$(x).c vdso$(x).so vdso$(x).so.dbg) CPPFLAGS_vdso.lds += -P -C diff --git a/arch/um/Makefile-skas b/arch/um/Makefile-skas index ac35de5316a6a5..67323b02899990 100644 --- a/arch/um/Makefile-skas +++ b/arch/um/Makefile-skas @@ -4,7 +4,12 @@ # GPROF_OPT += -pg + +ifdef CONFIG_CC_IS_CLANG +GCOV_OPT += -fprofile-instr-generate -fcoverage-mapping +else GCOV_OPT += -fprofile-arcs -ftest-coverage +endif CFLAGS-$(CONFIG_GCOV) += $(GCOV_OPT) CFLAGS-$(CONFIG_GPROF) += $(GPROF_OPT) diff --git a/arch/um/drivers/chan.h b/arch/um/drivers/chan.h index 3fec3b8406e98a..e14b9cdf7a33df 100644 --- a/arch/um/drivers/chan.h +++ b/arch/um/drivers/chan.h @@ -30,7 +30,7 @@ struct chan { extern void chan_interrupt(struct line *line, int irq); extern int parse_chan_pair(char *str, struct line *line, int device, const struct chan_opts *opts, char **error_out); -extern int write_chan(struct chan *chan, const char *buf, int len, +extern int write_chan(struct chan *chan, const u8 *buf, size_t len, int write_irq); extern int console_write_chan(struct chan *chan, const char *buf, int len); diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c index 26a702a0651549..37538b4168da6a 100644 --- a/arch/um/drivers/chan_kern.c +++ b/arch/um/drivers/chan_kern.c @@ -33,14 +33,14 @@ static void not_configged_close(int fd, void *data) "UML\n"); } -static int not_configged_read(int fd, char *c_out, void *data) +static int not_configged_read(int fd, u8 *c_out, void *data) { printk(KERN_ERR "Using a channel type which is configured out of " "UML\n"); return -EIO; } -static int not_configged_write(int fd, const char *buf, int len, void *data) +static int not_configged_write(int fd, const u8 *buf, size_t len, void *data) { printk(KERN_ERR "Using a channel type which is configured out of " "UML\n"); @@ -247,8 +247,7 @@ void deactivate_chan(struct chan *chan, int irq) deactivate_fd(chan->fd, irq); } -int write_chan(struct chan *chan, const char *buf, int len, - int write_irq) +int write_chan(struct chan *chan, const u8 *buf, size_t len, int write_irq) { int n, ret = 0; @@ -540,7 +539,7 @@ void chan_interrupt(struct line *line, int irq) struct tty_port *port = &line->port; struct chan *chan = line->chan_in; int err; - char c; + u8 c; if (!chan || !chan->ops->read) goto out; diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c index 25727ed648b727..ec04e47b9d799d 100644 --- a/arch/um/drivers/chan_user.c +++ b/arch/um/drivers/chan_user.c @@ -19,7 +19,7 @@ void generic_close(int fd, void *unused) close(fd); } -int generic_read(int fd, char *c_out, void *unused) +int generic_read(int fd, __u8 *c_out, void *unused) { int n; @@ -35,7 +35,7 @@ int generic_read(int fd, char *c_out, void *unused) /* XXX Trivial wrapper around write */ -int generic_write(int fd, const char *buf, int n, void *unused) +int generic_write(int fd, const __u8 *buf, size_t n, void *unused) { int err; @@ -141,7 +141,7 @@ struct winch_data { int pipe_fd; }; -static int winch_thread(void *arg) +static __noreturn int winch_thread(void *arg) { struct winch_data *data = arg; sigset_t sigs; @@ -153,8 +153,8 @@ static int winch_thread(void *arg) pipe_fd = data->pipe_fd; count = write(pipe_fd, &c, sizeof(c)); if (count != sizeof(c)) - printk(UM_KERN_ERR "winch_thread : failed to write " - "synchronization byte, err = %d\n", -count); + os_info("winch_thread : failed to write synchronization byte, err = %d\n", + -count); /* * We are not using SIG_IGN on purpose, so don't fix it as I thought to @@ -166,29 +166,29 @@ static int winch_thread(void *arg) sigfillset(&sigs); /* Block all signals possible. */ if (sigprocmask(SIG_SETMASK, &sigs, NULL) < 0) { - printk(UM_KERN_ERR "winch_thread : sigprocmask failed, " - "errno = %d\n", errno); - exit(1); + os_info("winch_thread : sigprocmask failed, errno = %d\n", + errno); + goto wait_kill; } /* In sigsuspend(), block anything else than SIGWINCH. */ sigdelset(&sigs, SIGWINCH); if (setsid() < 0) { - printk(UM_KERN_ERR "winch_thread : setsid failed, errno = %d\n", + os_info("winch_thread : setsid failed, errno = %d\n", errno); - exit(1); + goto wait_kill; } if (ioctl(pty_fd, TIOCSCTTY, 0) < 0) { - printk(UM_KERN_ERR "winch_thread : TIOCSCTTY failed on " - "fd %d err = %d\n", pty_fd, errno); - exit(1); + os_info("winch_thread : TIOCSCTTY failed on " + "fd %d err = %d\n", pty_fd, errno); + goto wait_kill; } if (tcsetpgrp(pty_fd, os_getpid()) < 0) { - printk(UM_KERN_ERR "winch_thread : tcsetpgrp failed on " - "fd %d err = %d\n", pty_fd, errno); - exit(1); + os_info("winch_thread : tcsetpgrp failed on fd %d err = %d\n", + pty_fd, errno); + goto wait_kill; } /* @@ -199,8 +199,8 @@ static int winch_thread(void *arg) */ count = read(pipe_fd, &c, sizeof(c)); if (count != sizeof(c)) - printk(UM_KERN_ERR "winch_thread : failed to read " - "synchronization byte, err = %d\n", errno); + os_info("winch_thread : failed to read synchronization byte, err = %d\n", + errno); while(1) { /* @@ -211,9 +211,15 @@ static int winch_thread(void *arg) count = write(pipe_fd, &c, sizeof(c)); if (count != sizeof(c)) - printk(UM_KERN_ERR "winch_thread : write failed, " - "err = %d\n", errno); + os_info("winch_thread : write failed, err = %d\n", + errno); } + +wait_kill: + c = 2; + count = write(pipe_fd, &c, sizeof(c)); + while (1) + pause(); } static int winch_tramp(int fd, struct tty_port *port, int *fd_out, diff --git a/arch/um/drivers/chan_user.h b/arch/um/drivers/chan_user.h index 4e51b85e2a23a5..e158e16fb3cc98 100644 --- a/arch/um/drivers/chan_user.h +++ b/arch/um/drivers/chan_user.h @@ -7,6 +7,7 @@ #define __CHAN_USER_H__ #include +#include struct chan_opts { void (*const announce)(char *dev_name, int dev); @@ -19,8 +20,8 @@ struct chan_ops { void *(*init)(char *, int, const struct chan_opts *); int (*open)(int, int, int, void *, char **); void (*close)(int, void *); - int (*read)(int, char *, void *); - int (*write)(int, const char *, int, void *); + int (*read)(int, __u8 *, void *); + int (*write)(int, const __u8 *, size_t, void *); int (*console_write)(int, const char *, int); int (*window_size)(int, void *, unsigned short *, unsigned short *); void (*free)(void *); @@ -31,8 +32,8 @@ extern const struct chan_ops fd_ops, null_ops, port_ops, pts_ops, pty_ops, tty_ops, xterm_ops; extern void generic_close(int fd, void *unused); -extern int generic_read(int fd, char *c_out, void *unused); -extern int generic_write(int fd, const char *buf, int n, void *unused); +extern int generic_read(int fd, __u8 *c_out, void *unused); +extern int generic_write(int fd, const __u8 *buf, size_t n, void *unused); extern int generic_console_write(int fd, const char *buf, int n); extern int generic_window_size(int fd, void *unused, unsigned short *rows_out, unsigned short *cols_out); diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index b98545f3edb503..ffc5cb92fa3677 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -83,7 +83,7 @@ unsigned int line_chars_in_buffer(struct tty_struct *tty) * * Must be called while holding line->lock! */ -static int buffer_data(struct line *line, const char *buf, int len) +static int buffer_data(struct line *line, const u8 *buf, size_t len) { int end, room; @@ -629,15 +629,18 @@ static irqreturn_t winch_interrupt(int irq, void *data) if (fd != -1) { err = generic_read(fd, &c, NULL); - if (err < 0) { + /* A read of 2 means the winch thread failed and has warned */ + if (err < 0 || (err == 1 && c == 2)) { if (err != -EAGAIN) { winch->fd = -1; list_del(&winch->list); os_close_file(fd); - printk(KERN_ERR "winch_interrupt : " - "read failed, errno = %d\n", -err); - printk(KERN_ERR "fd %d is losing SIGWINCH " - "support\n", winch->tty_fd); + if (err < 0) { + printk(KERN_ERR "winch_interrupt : read failed, errno = %d\n", + -err); + printk(KERN_ERR "fd %d is losing SIGWINCH support\n", + winch->tty_fd); + } INIT_WORK(&winch->work, __free_winch); schedule_work(&winch->work); return IRQ_HANDLED; diff --git a/arch/um/drivers/line.h b/arch/um/drivers/line.h index e84fb9b4165e86..e8bd6f3dfb5077 100644 --- a/arch/um/drivers/line.h +++ b/arch/um/drivers/line.h @@ -47,9 +47,9 @@ struct line { * * buffer points to a buffer allocated on demand, of length * LINE_BUFSIZE, head to the start of the ring, tail to the end.*/ - char *buffer; - char *head; - char *tail; + u8 *buffer; + u8 *head; + u8 *tail; int sigio; struct delayed_work task; diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index 3d7836c4650701..cabcc501b448a3 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c @@ -204,7 +204,7 @@ static int uml_net_close(struct net_device *dev) return 0; } -static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct uml_net_private *lp = netdev_priv(dev); unsigned long flags; diff --git a/arch/um/drivers/null.c b/arch/um/drivers/null.c index 87087763a417f9..30d59b8481b407 100644 --- a/arch/um/drivers/null.c +++ b/arch/um/drivers/null.c @@ -28,7 +28,7 @@ static int null_open(int input, int output, int primary, void *d, return (fd < 0) ? -errno : fd; } -static int null_read(int fd, char *c_out, void *unused) +static int null_read(int fd, __u8 *c_out, void *unused) { return -ENODEV; } diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 50206feac577d5..92ee2697ff3984 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -798,7 +798,6 @@ static int ubd_open_dev(struct ubd *ubd_dev) ubd_dev->cow.fd = err; } if (ubd_dev->no_trim == 0) { - ubd_dev->queue->limits.discard_granularity = SECTOR_SIZE; blk_queue_max_discard_sectors(ubd_dev->queue, UBD_MAX_REQUEST); blk_queue_max_write_zeroes_sectors(ubd_dev->queue, UBD_MAX_REQUEST); } diff --git a/arch/um/drivers/virt-pci.c b/arch/um/drivers/virt-pci.c index ffe2ee8a02465b..97a37c06299721 100644 --- a/arch/um/drivers/virt-pci.c +++ b/arch/um/drivers/virt-pci.c @@ -971,7 +971,7 @@ static long um_pci_map_platform(unsigned long offset, size_t size, *ops = &um_pci_device_bar_ops; *priv = &um_pci_platform_device->resptr[0]; - return 0; + return offset; } static const struct logic_iomem_region_ops um_pci_platform_ops = { diff --git a/arch/um/include/asm/mmu.h b/arch/um/include/asm/mmu.h index 5b072aba5b658f..a7555e43ed14ae 100644 --- a/arch/um/include/asm/mmu.h +++ b/arch/um/include/asm/mmu.h @@ -12,7 +12,6 @@ typedef struct mm_context { struct mm_id id; struct uml_arch_mm_context arch; - struct page *stub_pages[2]; } mm_context_t; extern void __switch_mm(struct mm_id * mm_idp); diff --git a/arch/um/include/asm/processor-generic.h b/arch/um/include/asm/processor-generic.h index 7414154b8e9aea..6c3779541845bd 100644 --- a/arch/um/include/asm/processor-generic.h +++ b/arch/um/include/asm/processor-generic.h @@ -22,7 +22,6 @@ struct mm_struct; struct thread_struct { struct pt_regs regs; struct pt_regs *segv_regs; - int singlestep_syscall; void *fault_addr; jmp_buf *fault_catcher; struct task_struct *prev_sched; diff --git a/arch/um/include/shared/kern_util.h b/arch/um/include/shared/kern_util.h index d8b8b4f07e429d..789b83013f355c 100644 --- a/arch/um/include/shared/kern_util.h +++ b/arch/um/include/shared/kern_util.h @@ -34,7 +34,6 @@ extern int handle_page_fault(unsigned long address, unsigned long ip, extern unsigned int do_IRQ(int irq, struct uml_pt_regs *regs); extern void initial_thread_cb(void (*proc)(void *), void *arg); -extern int is_syscall(unsigned long addr); extern void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs); @@ -50,7 +49,7 @@ extern void do_uml_exitcalls(void); * Are we disallowed to sleep? Used to choose between GFP_KERNEL and * GFP_ATOMIC. */ -extern int __cant_sleep(void); +extern int __uml_cant_sleep(void); extern int get_current_pid(void); extern int copy_from_user_proc(void *to, void *from, int size); extern char *uml_strdup(const char *string); @@ -58,7 +57,7 @@ extern char *uml_strdup(const char *string); extern unsigned long to_irq_stack(unsigned long *mask_out); extern unsigned long from_irq_stack(int nested); -extern int singlestepping(void *t); +extern int singlestepping(void); extern void segv_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs); extern void bus_handler(int sig, struct siginfo *si, struct uml_pt_regs *regs); diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h index 0df646c6651ea0..aff8906304ea8c 100644 --- a/arch/um/include/shared/os.h +++ b/arch/um/include/shared/os.h @@ -323,9 +323,6 @@ extern void sigio_broken(int fd); extern int __add_sigio_fd(int fd); extern int __ignore_sigio_fd(int fd); -/* prctl.c */ -extern int os_arch_prctl(int pid, int option, unsigned long *arg2); - /* tty.c */ extern int get_pty(void); diff --git a/arch/um/include/shared/ptrace_user.h b/arch/um/include/shared/ptrace_user.h index 95455e8996e725..8a705d8f96ce6e 100644 --- a/arch/um/include/shared/ptrace_user.h +++ b/arch/um/include/shared/ptrace_user.h @@ -12,45 +12,4 @@ extern int ptrace_getregs(long pid, unsigned long *regs_out); extern int ptrace_setregs(long pid, unsigned long *regs_in); -/* syscall emulation path in ptrace */ - -#ifndef PTRACE_SYSEMU -#define PTRACE_SYSEMU 31 -#endif -#ifndef PTRACE_SYSEMU_SINGLESTEP -#define PTRACE_SYSEMU_SINGLESTEP 32 -#endif - -/* On architectures, that started to support PTRACE_O_TRACESYSGOOD - * in linux 2.4, there are two different definitions of - * PTRACE_SETOPTIONS: linux 2.4 uses 21 while linux 2.6 uses 0x4200. - * For binary compatibility, 2.6 also supports the old "21", named - * PTRACE_OLDSETOPTION. On these architectures, UML always must use - * "21", to ensure the kernel runs on 2.4 and 2.6 host without - * recompilation. So, we use PTRACE_OLDSETOPTIONS in UML. - * We also want to be able to build the kernel on 2.4, which doesn't - * have PTRACE_OLDSETOPTIONS. So, if it is missing, we declare - * PTRACE_OLDSETOPTIONS to be the same as PTRACE_SETOPTIONS. - * - * On architectures, that start to support PTRACE_O_TRACESYSGOOD on - * linux 2.6, PTRACE_OLDSETOPTIONS never is defined, and also isn't - * supported by the host kernel. In that case, our trick lets us use - * the new 0x4200 with the name PTRACE_OLDSETOPTIONS. - */ -#ifndef PTRACE_OLDSETOPTIONS -#define PTRACE_OLDSETOPTIONS PTRACE_SETOPTIONS -#endif - -void set_using_sysemu(int value); -int get_using_sysemu(void); -extern int sysemu_supported; - -#define SELECT_PTRACE_OPERATION(sysemu_mode, singlestep_mode) \ - (((int[3][3] ) { \ - { PTRACE_SYSCALL, PTRACE_SYSCALL, PTRACE_SINGLESTEP }, \ - { PTRACE_SYSEMU, PTRACE_SYSEMU, PTRACE_SINGLESTEP }, \ - { PTRACE_SYSEMU, PTRACE_SYSEMU_SINGLESTEP, \ - PTRACE_SYSEMU_SINGLESTEP } }) \ - [sysemu_mode][singlestep_mode]) - #endif diff --git a/arch/um/include/shared/registers.h b/arch/um/include/shared/registers.h index 2f9c3ce5b45e8c..a0450326521cd5 100644 --- a/arch/um/include/shared/registers.h +++ b/arch/um/include/shared/registers.h @@ -14,8 +14,6 @@ extern int save_fp_registers(int pid, unsigned long *fp_regs); extern int restore_fp_registers(int pid, unsigned long *fp_regs); extern int save_fpx_registers(int pid, unsigned long *fp_regs); extern int restore_fpx_registers(int pid, unsigned long *fp_regs); -extern int save_registers(int pid, struct uml_pt_regs *regs); -extern int restore_pid_registers(int pid, struct uml_pt_regs *regs); extern int init_pid_registers(int pid); extern void get_safe_registers(unsigned long *regs, unsigned long *fp_regs); extern int get_fp_registers(int pid, unsigned long *regs); diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index 106b7da2f8d6f7..ab95648e93e156 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -220,7 +220,7 @@ void arch_cpu_idle(void) um_idle_sleep(); } -int __cant_sleep(void) { +int __uml_cant_sleep(void) { return in_atomic() || irqs_disabled() || in_interrupt(); /* Is in_interrupt() really needed? */ } @@ -332,17 +332,9 @@ int __init make_proc_sysemu(void) late_initcall(make_proc_sysemu); -int singlestepping(void * t) +int singlestepping(void) { - struct task_struct *task = t ? t : current; - - if (!test_thread_flag(TIF_SINGLESTEP)) - return 0; - - if (task->thread.singlestep_syscall) - return 1; - - return 2; + return test_thread_flag(TIF_SINGLESTEP); } /* diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index 5154b27de580f7..6600a278279674 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -12,7 +12,6 @@ void user_enable_single_step(struct task_struct *child) { set_tsk_thread_flag(child, TIF_SINGLESTEP); - child->thread.singlestep_syscall = 0; #ifdef SUBARCH_SET_SINGLESTEPPING SUBARCH_SET_SINGLESTEPPING(child, 1); @@ -22,7 +21,6 @@ void user_enable_single_step(struct task_struct *child) void user_disable_single_step(struct task_struct *child) { clear_tsk_thread_flag(child, TIF_SINGLESTEP); - child->thread.singlestep_syscall = 0; #ifdef SUBARCH_SET_SINGLESTEPPING SUBARCH_SET_SINGLESTEPPING(child, 0); diff --git a/arch/um/kernel/signal.c b/arch/um/kernel/signal.c index ae4658f576ab7a..a56b44522766fe 100644 --- a/arch/um/kernel/signal.c +++ b/arch/um/kernel/signal.c @@ -120,18 +120,6 @@ void do_signal(struct pt_regs *regs) } } - /* - * This closes a way to execute a system call on the host. If - * you set a breakpoint on a system call instruction and singlestep - * from it, the tracing thread used to PTRACE_SINGLESTEP the process - * rather than PTRACE_SYSCALL it, allowing the system call to execute - * on the host. The tracing thread will check this flag and - * PTRACE_SYSCALL if necessary. - */ - if (test_thread_flag(TIF_SINGLESTEP)) - current->thread.singlestep_syscall = - is_syscall(PT_REGS_IP(¤t->thread.regs)); - /* * if there's no signal to deliver, we just put the saved sigmask * back diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c index aaee96f07172da..198269e384c43b 100644 --- a/arch/um/kernel/skas/uaccess.c +++ b/arch/um/kernel/skas/uaccess.c @@ -236,7 +236,9 @@ EXPORT_SYMBOL(strnlen_user); * argument and comparison of the previous * futex value with another constant. * - * @encoded_op: encoded operation to execute + * @op: operation to execute + * @oparg: argument to operation + * @oval: old value at uaddr * @uaddr: pointer to user space address * * Return: diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c index fddd1dec27e6d3..3e270da6b6f67e 100644 --- a/arch/um/kernel/time.c +++ b/arch/um/kernel/time.c @@ -432,9 +432,29 @@ static void time_travel_update_time(unsigned long long next, bool idle) time_travel_del_event(&ne); } +static void time_travel_update_time_rel(unsigned long long offs) +{ + unsigned long flags; + + /* + * Disable interrupts before calculating the new time so + * that a real timer interrupt (signal) can't happen at + * a bad time e.g. after we read time_travel_time but + * before we've completed updating the time. + */ + local_irq_save(flags); + time_travel_update_time(time_travel_time + offs, false); + local_irq_restore(flags); +} + void time_travel_ndelay(unsigned long nsec) { - time_travel_update_time(time_travel_time + nsec, false); + /* + * Not strictly needed to use _rel() version since this is + * only used in INFCPU/EXT modes, but it doesn't hurt and + * is more readable too. + */ + time_travel_update_time_rel(nsec); } EXPORT_SYMBOL(time_travel_ndelay); @@ -568,7 +588,11 @@ static void time_travel_set_start(void) #define time_travel_time 0 #define time_travel_ext_waiting 0 -static inline void time_travel_update_time(unsigned long long ns, bool retearly) +static inline void time_travel_update_time(unsigned long long ns, bool idle) +{ +} + +static inline void time_travel_update_time_rel(unsigned long long offs) { } @@ -720,9 +744,7 @@ static u64 timer_read(struct clocksource *cs) */ if (!irqs_disabled() && !in_interrupt() && !in_softirq() && !time_travel_ext_waiting) - time_travel_update_time(time_travel_time + - TIMER_MULTIPLIER, - false); + time_travel_update_time_rel(TIMER_MULTIPLIER); return time_travel_time / TIMER_MULTIPLIER; } diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index b1bfed0c85288f..7a9820797eae24 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -373,10 +373,10 @@ int __init linux_main(int argc, char **argv) max_physmem = TASK_SIZE - uml_physmem - iomem_size - MIN_VMALLOC; /* - * Zones have to begin on a 1 << MAX_ORDER page boundary, + * Zones have to begin on a 1 << MAX_PAGE_ORDER page boundary, * so this makes sure that's true for highmem */ - max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1); + max_physmem &= ~((1 << (PAGE_SHIFT + MAX_PAGE_ORDER)) - 1); if (physmem_size + iomem_size > max_physmem) { highmem = physmem_size + iomem_size - max_physmem; physmem_size -= highmem; diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c index b459745f52e248..3cb8ac63be6ed9 100644 --- a/arch/um/os-Linux/helper.c +++ b/arch/um/os-Linux/helper.c @@ -46,7 +46,7 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv) unsigned long stack, sp; int pid, fds[2], ret, n; - stack = alloc_stack(0, __cant_sleep()); + stack = alloc_stack(0, __uml_cant_sleep()); if (stack == 0) return -ENOMEM; @@ -70,7 +70,7 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv) data.pre_data = pre_data; data.argv = argv; data.fd = fds[1]; - data.buf = __cant_sleep() ? uml_kmalloc(PATH_MAX, UM_GFP_ATOMIC) : + data.buf = __uml_cant_sleep() ? uml_kmalloc(PATH_MAX, UM_GFP_ATOMIC) : uml_kmalloc(PATH_MAX, UM_GFP_KERNEL); pid = clone(helper_child, (void *) sp, CLONE_VM, &data); if (pid < 0) { @@ -121,7 +121,7 @@ int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, unsigned long stack, sp; int pid, status, err; - stack = alloc_stack(0, __cant_sleep()); + stack = alloc_stack(0, __uml_cant_sleep()); if (stack == 0) return -ENOMEM; diff --git a/arch/um/os-Linux/registers.c b/arch/um/os-Linux/registers.c index b123955be7accf..bd80b921add06c 100644 --- a/arch/um/os-Linux/registers.c +++ b/arch/um/os-Linux/registers.c @@ -11,26 +11,6 @@ #include #include -int save_registers(int pid, struct uml_pt_regs *regs) -{ - int err; - - err = ptrace(PTRACE_GETREGS, pid, 0, regs->gp); - if (err < 0) - return -errno; - return 0; -} - -int restore_pid_registers(int pid, struct uml_pt_regs *regs) -{ - int err; - - err = ptrace(PTRACE_SETREGS, pid, 0, regs->gp); - if (err < 0) - return -errno; - return 0; -} - /* This is set once at boot time and not changed thereafter */ static unsigned long exec_regs[MAX_REG_NR]; diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c index 9464833e741af3..1f5c3f2523d1e2 100644 --- a/arch/um/os-Linux/skas/process.c +++ b/arch/um/os-Linux/skas/process.c @@ -177,48 +177,11 @@ static void handle_segv(int pid, struct uml_pt_regs *regs, unsigned long *aux_fp segv(regs->faultinfo, 0, 1, NULL); } -/* - * To use the same value of using_sysemu as the caller, ask it that value - * (in local_using_sysemu - */ -static void handle_trap(int pid, struct uml_pt_regs *regs, - int local_using_sysemu) +static void handle_trap(int pid, struct uml_pt_regs *regs) { - int err, status; - if ((UPT_IP(regs) >= STUB_START) && (UPT_IP(regs) < STUB_END)) fatal_sigsegv(); - if (!local_using_sysemu) - { - err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, - __NR_getpid); - if (err < 0) { - printk(UM_KERN_ERR "%s - nullifying syscall failed, errno = %d\n", - __func__, errno); - fatal_sigsegv(); - } - - err = ptrace(PTRACE_SYSCALL, pid, 0, 0); - if (err < 0) { - printk(UM_KERN_ERR "%s - continuing to end of syscall failed, errno = %d\n", - __func__, errno); - fatal_sigsegv(); - } - - CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED | __WALL)); - if ((err < 0) || !WIFSTOPPED(status) || - (WSTOPSIG(status) != SIGTRAP + 0x80)) { - err = ptrace_dump_regs(pid); - if (err) - printk(UM_KERN_ERR "Failed to get registers from process, errno = %d\n", - -err); - printk(UM_KERN_ERR "%s - failed to wait at end of syscall, errno = %d, status = %d\n", - __func__, errno, status); - fatal_sigsegv(); - } - } - handle_syscall(regs); } @@ -226,7 +189,7 @@ extern char __syscall_stub_start[]; /** * userspace_tramp() - userspace trampoline - * @stack: pointer to the new userspace stack page, can be NULL, if? FIXME: + * @stack: pointer to the new userspace stack page * * The userspace trampoline is used to setup a new userspace process in start_userspace() after it was clone()'ed. * This function will run on a temporary stack page. @@ -241,9 +204,13 @@ extern char __syscall_stub_start[]; */ static int userspace_tramp(void *stack) { + struct sigaction sa; void *addr; int fd; unsigned long long offset; + unsigned long segv_handler = STUB_CODE + + (unsigned long) stub_segv_handler - + (unsigned long) __syscall_stub_start; ptrace(PTRACE_TRACEME, 0, 0, 0); @@ -254,39 +221,30 @@ static int userspace_tramp(void *stack) addr = mmap64((void *) STUB_CODE, UM_KERN_PAGE_SIZE, PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset); if (addr == MAP_FAILED) { - printk(UM_KERN_ERR "mapping mmap stub at 0x%lx failed, errno = %d\n", - STUB_CODE, errno); + os_info("mapping mmap stub at 0x%lx failed, errno = %d\n", + STUB_CODE, errno); exit(1); } - if (stack != NULL) { - fd = phys_mapping(uml_to_phys(stack), &offset); - addr = mmap((void *) STUB_DATA, - STUB_DATA_PAGES * UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE, - MAP_FIXED | MAP_SHARED, fd, offset); - if (addr == MAP_FAILED) { - printk(UM_KERN_ERR "mapping segfault stack at 0x%lx failed, errno = %d\n", - STUB_DATA, errno); - exit(1); - } + fd = phys_mapping(uml_to_phys(stack), &offset); + addr = mmap((void *) STUB_DATA, + STUB_DATA_PAGES * UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE, + MAP_FIXED | MAP_SHARED, fd, offset); + if (addr == MAP_FAILED) { + os_info("mapping segfault stack at 0x%lx failed, errno = %d\n", + STUB_DATA, errno); + exit(1); } - if (stack != NULL) { - struct sigaction sa; - - unsigned long v = STUB_CODE + - (unsigned long) stub_segv_handler - - (unsigned long) __syscall_stub_start; - - set_sigstack((void *) STUB_DATA, STUB_DATA_PAGES * UM_KERN_PAGE_SIZE); - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_ONSTACK | SA_NODEFER | SA_SIGINFO; - sa.sa_sigaction = (void *) v; - sa.sa_restorer = NULL; - if (sigaction(SIGSEGV, &sa, NULL) < 0) { - printk(UM_KERN_ERR "%s - setting SIGSEGV handler failed - errno = %d\n", - __func__, errno); - exit(1); - } + + set_sigstack((void *) STUB_DATA, STUB_DATA_PAGES * UM_KERN_PAGE_SIZE); + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_ONSTACK | SA_NODEFER | SA_SIGINFO; + sa.sa_sigaction = (void *) segv_handler; + sa.sa_restorer = NULL; + if (sigaction(SIGSEGV, &sa, NULL) < 0) { + os_info("%s - setting SIGSEGV handler failed - errno = %d\n", + __func__, errno); + exit(1); } kill(os_getpid(), SIGSTOP); @@ -298,7 +256,7 @@ int kill_userspace_mm[NR_CPUS]; /** * start_userspace() - prepare a new userspace process - * @stub_stack: pointer to the stub stack. Can be NULL, if? FIXME: + * @stub_stack: pointer to the stub stack. * * Setups a new temporary stack page that is used while userspace_tramp() runs * Clones the kernel process into a new userspace process, with FDs only. @@ -355,10 +313,10 @@ int start_userspace(unsigned long stub_stack) goto out_kill; } - if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL, + if (ptrace(PTRACE_SETOPTIONS, pid, NULL, (void *) PTRACE_O_TRACESYSGOOD) < 0) { err = -errno; - printk(UM_KERN_ERR "%s : PTRACE_OLDSETOPTIONS failed, errno = %d\n", + printk(UM_KERN_ERR "%s : PTRACE_SETOPTIONS failed, errno = %d\n", __func__, errno); goto out_kill; } @@ -380,8 +338,6 @@ int start_userspace(unsigned long stub_stack) void userspace(struct uml_pt_regs *regs, unsigned long *aux_fp_regs) { int err, status, op, pid = userspace_pid[0]; - /* To prevent races if using_sysemu changes under us.*/ - int local_using_sysemu; siginfo_t si; /* Handle any immediate reschedules or signals */ @@ -411,11 +367,10 @@ void userspace(struct uml_pt_regs *regs, unsigned long *aux_fp_regs) fatal_sigsegv(); } - /* Now we set local_using_sysemu to be used for one loop */ - local_using_sysemu = get_using_sysemu(); - - op = SELECT_PTRACE_OPERATION(local_using_sysemu, - singlestepping(NULL)); + if (singlestepping()) + op = PTRACE_SYSEMU_SINGLESTEP; + else + op = PTRACE_SYSEMU; if (ptrace(op, pid, 0, 0)) { printk(UM_KERN_ERR "%s - ptrace continue failed, op = %d, errno = %d\n", @@ -474,7 +429,7 @@ void userspace(struct uml_pt_regs *regs, unsigned long *aux_fp_regs) else handle_segv(pid, regs, aux_fp_regs); break; case SIGTRAP + 0x80: - handle_trap(pid, regs, local_using_sysemu); + handle_trap(pid, regs); break; case SIGTRAP: relay_signal(SIGTRAP, (struct siginfo *)&si, regs); @@ -597,10 +552,10 @@ int copy_context_skas0(unsigned long new_stack, int pid) goto out_kill; } - if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL, + if (ptrace(PTRACE_SETOPTIONS, pid, NULL, (void *)PTRACE_O_TRACESYSGOOD) < 0) { err = -errno; - printk(UM_KERN_ERR "%s : PTRACE_OLDSETOPTIONS failed, errno = %d\n", + printk(UM_KERN_ERR "%s : PTRACE_SETOPTIONS failed, errno = %d\n", __func__, errno); goto out_kill; } diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index e3ee4db58b40d0..8b0e98ab842cca 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c @@ -112,102 +112,32 @@ static int start_ptraced_child(void) return pid; } -/* When testing for SYSEMU support, if it is one of the broken versions, we - * must just avoid using sysemu, not panic, but only if SYSEMU features are - * broken. - * So only for SYSEMU features we test mustpanic, while normal host features - * must work anyway! - */ -static int stop_ptraced_child(int pid, int exitcode, int mustexit) +static void stop_ptraced_child(int pid, int exitcode) { - int status, n, ret = 0; + int status, n; + + if (ptrace(PTRACE_CONT, pid, 0, 0) < 0) + fatal_perror("stop_ptraced_child : ptrace failed"); - if (ptrace(PTRACE_CONT, pid, 0, 0) < 0) { - perror("stop_ptraced_child : ptrace failed"); - return -1; - } CATCH_EINTR(n = waitpid(pid, &status, 0)); if (!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) { int exit_with = WEXITSTATUS(status); - if (exit_with == 2) - non_fatal("check_ptrace : child exited with status 2. " - "\nDisabling SYSEMU support.\n"); - non_fatal("check_ptrace : child exited with exitcode %d, while " - "expecting %d; status 0x%x\n", exit_with, - exitcode, status); - if (mustexit) - exit(1); - ret = -1; + fatal("stop_ptraced_child : child exited with exitcode %d, " + "while expecting %d; status 0x%x\n", exit_with, + exitcode, status); } - - return ret; -} - -/* Changed only during early boot */ -static int force_sysemu_disabled = 0; - -static int __init nosysemu_cmd_param(char *str, int* add) -{ - force_sysemu_disabled = 1; - return 0; } -__uml_setup("nosysemu", nosysemu_cmd_param, -"nosysemu\n" -" Turns off syscall emulation patch for ptrace (SYSEMU).\n" -" SYSEMU is a performance-patch introduced by Laurent Vivier. It changes\n" -" behaviour of ptrace() and helps reduce host context switch rates.\n" -" To make it work, you need a kernel patch for your host, too.\n" -" See http://perso.wanadoo.fr/laurent.vivier/UML/ for further \n" -" information.\n\n"); - static void __init check_sysemu(void) { - unsigned long regs[MAX_REG_NR]; int pid, n, status, count=0; - os_info("Checking syscall emulation patch for ptrace..."); - sysemu_supported = 0; - pid = start_ptraced_child(); - - if (ptrace(PTRACE_SYSEMU, pid, 0, 0) < 0) - goto fail; - - CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); - if (n < 0) - fatal_perror("check_sysemu : wait failed"); - if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) - fatal("check_sysemu : expected SIGTRAP, got status = %d\n", - status); - - if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0) - fatal_perror("check_sysemu : PTRACE_GETREGS failed"); - if (PT_SYSCALL_NR(regs) != __NR_getpid) { - non_fatal("check_sysemu got system call number %d, " - "expected %d...", PT_SYSCALL_NR(regs), __NR_getpid); - goto fail; - } - - n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, os_getpid()); - if (n < 0) { - non_fatal("check_sysemu : failed to modify system call " - "return"); - goto fail; - } - - if (stop_ptraced_child(pid, 0, 0) < 0) - goto fail_stopped; - - sysemu_supported = 1; - os_info("OK\n"); - set_using_sysemu(!force_sysemu_disabled); - - os_info("Checking advanced syscall emulation patch for ptrace..."); + os_info("Checking syscall emulation for ptrace..."); pid = start_ptraced_child(); - if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0, + if ((ptrace(PTRACE_SETOPTIONS, pid, 0, (void *) PTRACE_O_TRACESYSGOOD) < 0)) - fatal_perror("check_sysemu: PTRACE_OLDSETOPTIONS failed"); + fatal_perror("check_sysemu: PTRACE_SETOPTIONS failed"); while (1) { count++; @@ -240,20 +170,15 @@ static void __init check_sysemu(void) goto fail; } } - if (stop_ptraced_child(pid, 0, 0) < 0) - goto fail_stopped; + stop_ptraced_child(pid, 0); - sysemu_supported = 2; os_info("OK\n"); - if (!force_sysemu_disabled) - set_using_sysemu(sysemu_supported); return; fail: - stop_ptraced_child(pid, 1, 0); -fail_stopped: - non_fatal("missing\n"); + stop_ptraced_child(pid, 1); + fatal("missing\n"); } static void __init check_ptrace(void) @@ -263,9 +188,9 @@ static void __init check_ptrace(void) os_info("Checking that ptrace can change system call numbers..."); pid = start_ptraced_child(); - if ((ptrace(PTRACE_OLDSETOPTIONS, pid, 0, + if ((ptrace(PTRACE_SETOPTIONS, pid, 0, (void *) PTRACE_O_TRACESYSGOOD) < 0)) - fatal_perror("check_ptrace: PTRACE_OLDSETOPTIONS failed"); + fatal_perror("check_ptrace: PTRACE_SETOPTIONS failed"); while (1) { if (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) @@ -291,7 +216,7 @@ static void __init check_ptrace(void) break; } } - stop_ptraced_child(pid, 0, 1); + stop_ptraced_child(pid, 0); os_info("OK\n"); check_sysemu(); } @@ -370,7 +295,7 @@ void __init os_early_checks(void) pid = start_ptraced_child(); if (init_pid_registers(pid)) fatal("Failed to initialize default registers"); - stop_ptraced_child(pid, 1, 1); + stop_ptraced_child(pid, 1); } int __init parse_iomem(char *str, int *add) diff --git a/arch/um/os-Linux/util.c b/arch/um/os-Linux/util.c index fc0f2a9dee5af9..1dca4ffbd572f7 100644 --- a/arch/um/os-Linux/util.c +++ b/arch/um/os-Linux/util.c @@ -173,23 +173,38 @@ __uml_setup("quiet", quiet_cmd_param, "quiet\n" " Turns off information messages during boot.\n\n"); +/* + * The os_info/os_warn functions will be called by helper threads. These + * have a very limited stack size and using the libc formatting functions + * may overflow the stack. + * So pull in the kernel vscnprintf and use that instead with a fixed + * on-stack buffer. + */ +int vscnprintf(char *buf, size_t size, const char *fmt, va_list args); + void os_info(const char *fmt, ...) { + char buf[256]; va_list list; + int len; if (quiet_info) return; va_start(list, fmt); - vfprintf(stderr, fmt, list); + len = vscnprintf(buf, sizeof(buf), fmt, list); + fwrite(buf, len, 1, stderr); va_end(list); } void os_warn(const char *fmt, ...) { + char buf[256]; va_list list; + int len; va_start(list, fmt); - vfprintf(stderr, fmt, list); + len = vscnprintf(buf, sizeof(buf), fmt, list); + fwrite(buf, len, 1, stderr); va_end(list); } diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 1566748f16c424..5edec175b9bfc9 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -59,6 +59,7 @@ config X86 # select ACPI_LEGACY_TABLES_LOOKUP if ACPI select ACPI_SYSTEM_POWER_STATES_SUPPORT if ACPI + select ACPI_HOTPLUG_CPU if ACPI_PROCESSOR && HOTPLUG_CPU select ARCH_32BIT_OFF_T if X86_32 select ARCH_CLOCKSOURCE_INIT select ARCH_CORRECT_STACKTRACE_ON_KRETPROBE @@ -71,6 +72,7 @@ config X86 select ARCH_HAS_CACHE_LINE_SIZE select ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION select ARCH_HAS_CPU_FINALIZE_INIT + select ARCH_HAS_CPU_PASID if IOMMU_SVA select ARCH_HAS_CURRENT_STACK_POINTER select ARCH_HAS_DEBUG_VIRTUAL select ARCH_HAS_DEBUG_VM_PGTABLE if !X86_PAE @@ -88,6 +90,7 @@ config X86 select ARCH_HAS_PMEM_API if X86_64 select ARCH_HAS_PTE_DEVMAP if X86_64 select ARCH_HAS_PTE_SPECIAL + select ARCH_HAS_HW_PTE_YOUNG select ARCH_HAS_NONLEAF_PMD_YOUNG if PGTABLE_LEVELS > 2 select ARCH_HAS_UACCESS_FLUSHCACHE if X86_64 select ARCH_HAS_COPY_MC if X86_64 @@ -147,6 +150,7 @@ config X86 select GENERIC_CLOCKEVENTS_MIN_ADJUST select GENERIC_CMOS_UPDATE select GENERIC_CPU_AUTOPROBE + select GENERIC_CPU_DEVICES select GENERIC_CPU_VULNERABILITIES select GENERIC_EARLY_IOREMAP select GENERIC_ENTRY @@ -169,7 +173,7 @@ config X86 select HAS_IOPORT select HAVE_ACPI_APEI if ACPI select HAVE_ACPI_APEI_NMI if ACPI - select HAVE_ALIGNED_STRUCT_PAGE if SLUB + select HAVE_ALIGNED_STRUCT_PAGE select HAVE_ARCH_AUDITSYSCALL select HAVE_ARCH_HUGE_VMAP if X86_64 || X86_PAE select HAVE_ARCH_HUGE_VMALLOC if X86_64 @@ -384,10 +388,6 @@ config HAVE_INTEL_TXT def_bool y depends on INTEL_IOMMU && ACPI -config X86_32_SMP - def_bool y - depends on X86_32 && SMP - config X86_64_SMP def_bool y depends on X86_64 && SMP @@ -1415,7 +1415,7 @@ config HIGHMEM4G config HIGHMEM64G bool "64GB" - depends on !M486SX && !M486 && !M586 && !M586TSC && !M586MMX && !MGEODE_LX && !MGEODEGX1 && !MCYRIXIII && !MELAN && !MWINCHIPC6 && !MWINCHIP3D && !MK6 + depends on X86_HAVE_PAE select X86_PAE help Select this if you have a 32-bit processor and more than 4 @@ -1472,7 +1472,7 @@ config HIGHMEM config X86_PAE bool "PAE (Physical Address Extension) Support" - depends on X86_32 && !HIGHMEM4G + depends on X86_32 && X86_HAVE_PAE select PHYS_ADDR_T_64BIT select SWIOTLB help @@ -1970,6 +1970,11 @@ config INTEL_TDX_HOST depends on CPU_SUP_INTEL depends on X86_64 depends on KVM_INTEL + depends on X86_X2APIC + select ARCH_KEEP_MEMBLOCK + depends on CONTIG_ALLOC + depends on !KEXEC_CORE + depends on X86_MCE help Intel Trust Domain Extensions (TDX) protects guest VMs from malicious host and certain physical attacks. This option enables necessary TDX diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu index 00468adf180f1d..b9224cf2ee4d6f 100644 --- a/arch/x86/Kconfig.cpu +++ b/arch/x86/Kconfig.cpu @@ -362,9 +362,13 @@ config X86_TSC def_bool y depends on (MWINCHIP3D || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2 || MATOM) || X86_64 +config X86_HAVE_PAE + def_bool y + depends on MCRUSOE || MEFFICEON || MCYRIXIII || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC7 || MCORE2 || MATOM || X86_64 + config X86_CMPXCHG64 def_bool y - depends on X86_PAE || X86_64 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586TSC || M586MMX || MATOM || MGEODE_LX || MGEODEGX1 || MK6 || MK7 || MK8 + depends on X86_HAVE_PAE || M586TSC || M586MMX || MK6 || MK7 # this should be set for all -march=.. options where the compiler # generates cmov. diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index 71fc531b95b4ee..f19c038409aa0d 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -53,7 +53,7 @@ KBUILD_CFLAGS += -D__DISABLE_EXPORTS KBUILD_CFLAGS += $(call cc-option,-Wa$(comma)-mrelax-relocations=no) KBUILD_CFLAGS += -include $(srctree)/include/linux/hidden.h -# sev.c indirectly inludes inat-table.h which is generated during +# sev.c indirectly includes inat-table.h which is generated during # compilation and stored in $(objtree). Add the directory to the includes so # that the compiler finds it even with out-of-tree builds (make O=/some/path). CFLAGS_sev.o += -I$(objtree)/arch/x86/lib/ diff --git a/arch/x86/boot/compressed/ident_map_64.c b/arch/x86/boot/compressed/ident_map_64.c index 473ba59b82a815..d040080d7edbd6 100644 --- a/arch/x86/boot/compressed/ident_map_64.c +++ b/arch/x86/boot/compressed/ident_map_64.c @@ -386,3 +386,8 @@ void do_boot_page_fault(struct pt_regs *regs, unsigned long error_code) */ kernel_add_identity_map(address, end); } + +void do_boot_nmi_trap(struct pt_regs *regs, unsigned long error_code) +{ + /* Empty handler to ignore NMI during early boot */ +} diff --git a/arch/x86/boot/compressed/idt_64.c b/arch/x86/boot/compressed/idt_64.c index 3cdf94b4145674..d100284bbef47b 100644 --- a/arch/x86/boot/compressed/idt_64.c +++ b/arch/x86/boot/compressed/idt_64.c @@ -61,6 +61,7 @@ void load_stage2_idt(void) boot_idt_desc.address = (unsigned long)boot_idt; set_idt_entry(X86_TRAP_PF, boot_page_fault); + set_idt_entry(X86_TRAP_NMI, boot_nmi_trap); #ifdef CONFIG_AMD_MEM_ENCRYPT /* diff --git a/arch/x86/boot/compressed/idt_handlers_64.S b/arch/x86/boot/compressed/idt_handlers_64.S index 22890e199f5b44..4d03c8562f637d 100644 --- a/arch/x86/boot/compressed/idt_handlers_64.S +++ b/arch/x86/boot/compressed/idt_handlers_64.S @@ -70,6 +70,7 @@ SYM_FUNC_END(\name) .code64 EXCEPTION_HANDLER boot_page_fault do_boot_page_fault error_code=1 +EXCEPTION_HANDLER boot_nmi_trap do_boot_nmi_trap error_code=0 #ifdef CONFIG_AMD_MEM_ENCRYPT EXCEPTION_HANDLER boot_stage1_vc do_vc_no_ghcb error_code=1 diff --git a/arch/x86/boot/compressed/mem.c b/arch/x86/boot/compressed/mem.c index b3c3a4be7471f1..dbba332e4a12d7 100644 --- a/arch/x86/boot/compressed/mem.c +++ b/arch/x86/boot/compressed/mem.c @@ -8,7 +8,7 @@ /* * accept_memory() and process_unaccepted_memory() called from EFI stub which - * runs before decompresser and its early_tdx_detect(). + * runs before decompressor and its early_tdx_detect(). * * Enumerate TDX directly from the early users. */ diff --git a/arch/x86/boot/compressed/misc.h b/arch/x86/boot/compressed/misc.h index c0d502bd871616..bc2f0f17fb90ec 100644 --- a/arch/x86/boot/compressed/misc.h +++ b/arch/x86/boot/compressed/misc.h @@ -196,6 +196,7 @@ static inline void cleanup_exception_handling(void) { } /* IDT Entry Points */ void boot_page_fault(void); +void boot_nmi_trap(void); void boot_stage1_vc(void); void boot_stage2_vc(void); diff --git a/arch/x86/boot/pm.c b/arch/x86/boot/pm.c index 40031a61471200..5941f930f6c5a8 100644 --- a/arch/x86/boot/pm.c +++ b/arch/x86/boot/pm.c @@ -11,6 +11,7 @@ */ #include "boot.h" +#include #include /* @@ -67,13 +68,13 @@ static void setup_gdt(void) being 8-byte unaligned. Intel recommends 16 byte alignment. */ static const u64 boot_gdt[] __attribute__((aligned(16))) = { /* CS: code, read/execute, 4 GB, base 0 */ - [GDT_ENTRY_BOOT_CS] = GDT_ENTRY(0xc09b, 0, 0xfffff), + [GDT_ENTRY_BOOT_CS] = GDT_ENTRY(DESC_CODE32, 0, 0xfffff), /* DS: data, read/write, 4 GB, base 0 */ - [GDT_ENTRY_BOOT_DS] = GDT_ENTRY(0xc093, 0, 0xfffff), + [GDT_ENTRY_BOOT_DS] = GDT_ENTRY(DESC_DATA32, 0, 0xfffff), /* TSS: 32-bit tss, 104 bytes, base 4096 */ /* We only have a TSS here to keep Intel VT happy; we don't actually use it for anything. */ - [GDT_ENTRY_BOOT_TSS] = GDT_ENTRY(0x0089, 4096, 103), + [GDT_ENTRY_BOOT_TSS] = GDT_ENTRY(DESC_TSS32, 4096, 103), }; /* Xen HVM incorrectly stores a pointer to the gdt_ptr, instead of the gdt_ptr contents. Thus, make it static so it will diff --git a/arch/x86/boot/string.c b/arch/x86/boot/string.c index 1c8541ae3b3ac8..c23f3b9c84fe9c 100644 --- a/arch/x86/boot/string.c +++ b/arch/x86/boot/string.c @@ -49,7 +49,7 @@ int strcmp(const char *str1, const char *str2) { const unsigned char *s1 = (const unsigned char *)str1; const unsigned char *s2 = (const unsigned char *)str2; - int delta = 0; + int delta; while (*s1 || *s2) { delta = *s1 - *s2; diff --git a/arch/x86/coco/tdx/tdx-shared.c b/arch/x86/coco/tdx/tdx-shared.c index 78e413269791ee..1655aa56a0a512 100644 --- a/arch/x86/coco/tdx/tdx-shared.c +++ b/arch/x86/coco/tdx/tdx-shared.c @@ -22,13 +22,13 @@ static unsigned long try_accept_one(phys_addr_t start, unsigned long len, */ switch (pg_level) { case PG_LEVEL_4K: - page_size = 0; + page_size = TDX_PS_4K; break; case PG_LEVEL_2M: - page_size = 1; + page_size = TDX_PS_2M; break; case PG_LEVEL_1G: - page_size = 2; + page_size = TDX_PS_1G; break; default: return 0; diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c index cf1f13c8217569..c1cb90369915b8 100644 --- a/arch/x86/coco/tdx/tdx.c +++ b/arch/x86/coco/tdx/tdx.c @@ -887,7 +887,7 @@ void __init tdx_early_init(void) * there. * * Intel-TDX has a secure RDMSR hypercall, but that needs to be - * implemented seperately in the low level startup ASM code. + * implemented separately in the low level startup ASM code. * Until that is in place, disable parallel bringup for TDX. */ x86_cpuinit.parallel_bringup = false; diff --git a/arch/x86/crypto/Kconfig b/arch/x86/crypto/Kconfig index 9bbfd01cfa2f13..c9e59589a1cee1 100644 --- a/arch/x86/crypto/Kconfig +++ b/arch/x86/crypto/Kconfig @@ -189,7 +189,7 @@ config CRYPTO_SERPENT_AVX2_X86_64 Processes 16 blocks in parallel. config CRYPTO_SM4_AESNI_AVX_X86_64 - tristate "Ciphers: SM4 with modes: ECB, CBC, CFB, CTR (AES-NI/AVX)" + tristate "Ciphers: SM4 with modes: ECB, CBC, CTR (AES-NI/AVX)" depends on X86 && 64BIT select CRYPTO_SKCIPHER select CRYPTO_SIMD @@ -197,7 +197,7 @@ config CRYPTO_SM4_AESNI_AVX_X86_64 select CRYPTO_SM4 help Length-preserving ciphers: SM4 cipher algorithms - (OSCCA GB/T 32907-2016) with ECB, CBC, CFB, and CTR modes + (OSCCA GB/T 32907-2016) with ECB, CBC, and CTR modes Architecture: x86_64 using: - AES-NI (AES New Instructions) @@ -210,7 +210,7 @@ config CRYPTO_SM4_AESNI_AVX_X86_64 If unsure, say N. config CRYPTO_SM4_AESNI_AVX2_X86_64 - tristate "Ciphers: SM4 with modes: ECB, CBC, CFB, CTR (AES-NI/AVX2)" + tristate "Ciphers: SM4 with modes: ECB, CBC, CTR (AES-NI/AVX2)" depends on X86 && 64BIT select CRYPTO_SKCIPHER select CRYPTO_SIMD @@ -219,7 +219,7 @@ config CRYPTO_SM4_AESNI_AVX2_X86_64 select CRYPTO_SM4_AESNI_AVX_X86_64 help Length-preserving ciphers: SM4 cipher algorithms - (OSCCA GB/T 32907-2016) with ECB, CBC, CFB, and CTR modes + (OSCCA GB/T 32907-2016) with ECB, CBC, and CTR modes Architecture: x86_64 using: - AES-NI (AES New Instructions) diff --git a/arch/x86/crypto/aesni-intel_asm.S b/arch/x86/crypto/aesni-intel_asm.S index 187f913cc2390b..411d8c83e88a86 100644 --- a/arch/x86/crypto/aesni-intel_asm.S +++ b/arch/x86/crypto/aesni-intel_asm.S @@ -666,7 +666,7 @@ ALL_F: .octa 0xffffffffffffffffffffffffffffffff .ifc \operation, dec movdqa %xmm1, %xmm3 - pxor %xmm1, %xmm9 # Cyphertext XOR E(K, Yn) + pxor %xmm1, %xmm9 # Ciphertext XOR E(K, Yn) mov \PLAIN_CYPH_LEN, %r10 add %r13, %r10 diff --git a/arch/x86/crypto/aesni-intel_avx-x86_64.S b/arch/x86/crypto/aesni-intel_avx-x86_64.S index 74dd230973cf9e..8c9749ed0651b1 100644 --- a/arch/x86/crypto/aesni-intel_avx-x86_64.S +++ b/arch/x86/crypto/aesni-intel_avx-x86_64.S @@ -747,7 +747,7 @@ VARIABLE_OFFSET = 16*8 .if \ENC_DEC == DEC vmovdqa %xmm1, %xmm3 - pxor %xmm1, %xmm9 # Cyphertext XOR E(K, Yn) + pxor %xmm1, %xmm9 # Ciphertext XOR E(K, Yn) mov \PLAIN_CYPH_LEN, %r10 add %r13, %r10 diff --git a/arch/x86/crypto/crc32c-pcl-intel-asm_64.S b/arch/x86/crypto/crc32c-pcl-intel-asm_64.S index 81ce0f4db555ce..bbcff1fb78cb2b 100644 --- a/arch/x86/crypto/crc32c-pcl-intel-asm_64.S +++ b/arch/x86/crypto/crc32c-pcl-intel-asm_64.S @@ -184,7 +184,7 @@ SYM_FUNC_START(crc_pcl) xor crc1,crc1 xor crc2,crc2 - # Fall thruogh into top of crc array (crc_128) + # Fall through into top of crc array (crc_128) ################################################################ ## 3) CRC Array: diff --git a/arch/x86/crypto/sha1_ssse3_glue.c b/arch/x86/crypto/sha1_ssse3_glue.c index 959afa705e95ca..ab8bc54f254d37 100644 --- a/arch/x86/crypto/sha1_ssse3_glue.c +++ b/arch/x86/crypto/sha1_ssse3_glue.c @@ -2,8 +2,8 @@ /* * Cryptographic API. * - * Glue code for the SHA1 Secure Hash Algorithm assembler implementation using - * Supplemental SSE3 instructions. + * Glue code for the SHA1 Secure Hash Algorithm assembler implementations + * using SSSE3, AVX, AVX2, and SHA-NI instructions. * * This file is based on sha1_generic.c * @@ -28,6 +28,9 @@ #include static const struct x86_cpu_id module_cpu_ids[] = { +#ifdef CONFIG_AS_SHA1_NI + X86_MATCH_FEATURE(X86_FEATURE_SHA_NI, NULL), +#endif X86_MATCH_FEATURE(X86_FEATURE_AVX2, NULL), X86_MATCH_FEATURE(X86_FEATURE_AVX, NULL), X86_MATCH_FEATURE(X86_FEATURE_SSSE3, NULL), diff --git a/arch/x86/crypto/sha256_ssse3_glue.c b/arch/x86/crypto/sha256_ssse3_glue.c index 4c0383a90e1147..e04a43d9f7d551 100644 --- a/arch/x86/crypto/sha256_ssse3_glue.c +++ b/arch/x86/crypto/sha256_ssse3_glue.c @@ -1,8 +1,8 @@ /* * Cryptographic API. * - * Glue code for the SHA256 Secure Hash Algorithm assembler - * implementation using supplemental SSE3 / AVX / AVX2 instructions. + * Glue code for the SHA256 Secure Hash Algorithm assembler implementations + * using SSSE3, AVX, AVX2, and SHA-NI instructions. * * This file is based on sha256_generic.c * @@ -45,6 +45,9 @@ asmlinkage void sha256_transform_ssse3(struct sha256_state *state, const u8 *data, int blocks); static const struct x86_cpu_id module_cpu_ids[] = { +#ifdef CONFIG_AS_SHA256_NI + X86_MATCH_FEATURE(X86_FEATURE_SHA_NI, NULL), +#endif X86_MATCH_FEATURE(X86_FEATURE_AVX2, NULL), X86_MATCH_FEATURE(X86_FEATURE_AVX, NULL), X86_MATCH_FEATURE(X86_FEATURE_SSSE3, NULL), diff --git a/arch/x86/crypto/sha512-avx-asm.S b/arch/x86/crypto/sha512-avx-asm.S index d902b8ea072184..5bfce4b045fdfb 100644 --- a/arch/x86/crypto/sha512-avx-asm.S +++ b/arch/x86/crypto/sha512-avx-asm.S @@ -84,7 +84,7 @@ frame_size = frame_WK + WK_SIZE # Useful QWORD "arrays" for simpler memory references # MSG, DIGEST, K_t, W_t are arrays -# WK_2(t) points to 1 of 2 qwords at frame.WK depdending on t being odd/even +# WK_2(t) points to 1 of 2 qwords at frame.WK depending on t being odd/even # Input message (arg1) #define MSG(i) 8*i(msg) diff --git a/arch/x86/crypto/sha512-ssse3-asm.S b/arch/x86/crypto/sha512-ssse3-asm.S index 65be3015681626..30a2c4777f9d5f 100644 --- a/arch/x86/crypto/sha512-ssse3-asm.S +++ b/arch/x86/crypto/sha512-ssse3-asm.S @@ -82,7 +82,7 @@ frame_size = frame_WK + WK_SIZE # Useful QWORD "arrays" for simpler memory references # MSG, DIGEST, K_t, W_t are arrays -# WK_2(t) points to 1 of 2 qwords at frame.WK depdending on t being odd/even +# WK_2(t) points to 1 of 2 qwords at frame.WK depending on t being odd/even # Input message (arg1) #define MSG(i) 8*i(msg) diff --git a/arch/x86/crypto/sm4-aesni-avx-asm_64.S b/arch/x86/crypto/sm4-aesni-avx-asm_64.S index e2668d2fe6ce18..2bf611eaa19119 100644 --- a/arch/x86/crypto/sm4-aesni-avx-asm_64.S +++ b/arch/x86/crypto/sm4-aesni-avx-asm_64.S @@ -534,55 +534,3 @@ SYM_TYPED_FUNC_START(sm4_aesni_avx_cbc_dec_blk8) FRAME_END RET; SYM_FUNC_END(sm4_aesni_avx_cbc_dec_blk8) - -/* - * void sm4_aesni_avx_cfb_dec_blk8(const u32 *rk, u8 *dst, - * const u8 *src, u8 *iv) - */ -SYM_TYPED_FUNC_START(sm4_aesni_avx_cfb_dec_blk8) - /* input: - * %rdi: round key array, CTX - * %rsi: dst (8 blocks) - * %rdx: src (8 blocks) - * %rcx: iv - */ - FRAME_BEGIN - - /* Load input */ - vmovdqu (%rcx), RA0; - vmovdqu 0 * 16(%rdx), RA1; - vmovdqu 1 * 16(%rdx), RA2; - vmovdqu 2 * 16(%rdx), RA3; - vmovdqu 3 * 16(%rdx), RB0; - vmovdqu 4 * 16(%rdx), RB1; - vmovdqu 5 * 16(%rdx), RB2; - vmovdqu 6 * 16(%rdx), RB3; - - /* Update IV */ - vmovdqu 7 * 16(%rdx), RNOT; - vmovdqu RNOT, (%rcx); - - call __sm4_crypt_blk8; - - vpxor (0 * 16)(%rdx), RA0, RA0; - vpxor (1 * 16)(%rdx), RA1, RA1; - vpxor (2 * 16)(%rdx), RA2, RA2; - vpxor (3 * 16)(%rdx), RA3, RA3; - vpxor (4 * 16)(%rdx), RB0, RB0; - vpxor (5 * 16)(%rdx), RB1, RB1; - vpxor (6 * 16)(%rdx), RB2, RB2; - vpxor (7 * 16)(%rdx), RB3, RB3; - - vmovdqu RA0, (0 * 16)(%rsi); - vmovdqu RA1, (1 * 16)(%rsi); - vmovdqu RA2, (2 * 16)(%rsi); - vmovdqu RA3, (3 * 16)(%rsi); - vmovdqu RB0, (4 * 16)(%rsi); - vmovdqu RB1, (5 * 16)(%rsi); - vmovdqu RB2, (6 * 16)(%rsi); - vmovdqu RB3, (7 * 16)(%rsi); - - vzeroall; - FRAME_END - RET; -SYM_FUNC_END(sm4_aesni_avx_cfb_dec_blk8) diff --git a/arch/x86/crypto/sm4-aesni-avx2-asm_64.S b/arch/x86/crypto/sm4-aesni-avx2-asm_64.S index 98ede94592877c..9ff5ba0755916b 100644 --- a/arch/x86/crypto/sm4-aesni-avx2-asm_64.S +++ b/arch/x86/crypto/sm4-aesni-avx2-asm_64.S @@ -439,58 +439,3 @@ SYM_TYPED_FUNC_START(sm4_aesni_avx2_cbc_dec_blk16) FRAME_END RET; SYM_FUNC_END(sm4_aesni_avx2_cbc_dec_blk16) - -/* - * void sm4_aesni_avx2_cfb_dec_blk16(const u32 *rk, u8 *dst, - * const u8 *src, u8 *iv) - */ -SYM_TYPED_FUNC_START(sm4_aesni_avx2_cfb_dec_blk16) - /* input: - * %rdi: round key array, CTX - * %rsi: dst (16 blocks) - * %rdx: src (16 blocks) - * %rcx: iv - */ - FRAME_BEGIN - - vzeroupper; - - /* Load input */ - vmovdqu (%rcx), RNOTx; - vinserti128 $1, (%rdx), RNOT, RA0; - vmovdqu (0 * 32 + 16)(%rdx), RA1; - vmovdqu (1 * 32 + 16)(%rdx), RA2; - vmovdqu (2 * 32 + 16)(%rdx), RA3; - vmovdqu (3 * 32 + 16)(%rdx), RB0; - vmovdqu (4 * 32 + 16)(%rdx), RB1; - vmovdqu (5 * 32 + 16)(%rdx), RB2; - vmovdqu (6 * 32 + 16)(%rdx), RB3; - - /* Update IV */ - vmovdqu (7 * 32 + 16)(%rdx), RNOTx; - vmovdqu RNOTx, (%rcx); - - call __sm4_crypt_blk16; - - vpxor (0 * 32)(%rdx), RA0, RA0; - vpxor (1 * 32)(%rdx), RA1, RA1; - vpxor (2 * 32)(%rdx), RA2, RA2; - vpxor (3 * 32)(%rdx), RA3, RA3; - vpxor (4 * 32)(%rdx), RB0, RB0; - vpxor (5 * 32)(%rdx), RB1, RB1; - vpxor (6 * 32)(%rdx), RB2, RB2; - vpxor (7 * 32)(%rdx), RB3, RB3; - - vmovdqu RA0, (0 * 32)(%rsi); - vmovdqu RA1, (1 * 32)(%rsi); - vmovdqu RA2, (2 * 32)(%rsi); - vmovdqu RA3, (3 * 32)(%rsi); - vmovdqu RB0, (4 * 32)(%rsi); - vmovdqu RB1, (5 * 32)(%rsi); - vmovdqu RB2, (6 * 32)(%rsi); - vmovdqu RB3, (7 * 32)(%rsi); - - vzeroall; - FRAME_END - RET; -SYM_FUNC_END(sm4_aesni_avx2_cfb_dec_blk16) diff --git a/arch/x86/crypto/sm4-avx.h b/arch/x86/crypto/sm4-avx.h index 1bceab7516aa1e..b5b5e67e40edec 100644 --- a/arch/x86/crypto/sm4-avx.h +++ b/arch/x86/crypto/sm4-avx.h @@ -14,10 +14,6 @@ int sm4_cbc_encrypt(struct skcipher_request *req); int sm4_avx_cbc_decrypt(struct skcipher_request *req, unsigned int bsize, sm4_crypt_func func); -int sm4_cfb_encrypt(struct skcipher_request *req); -int sm4_avx_cfb_decrypt(struct skcipher_request *req, - unsigned int bsize, sm4_crypt_func func); - int sm4_avx_ctr_crypt(struct skcipher_request *req, unsigned int bsize, sm4_crypt_func func); diff --git a/arch/x86/crypto/sm4_aesni_avx2_glue.c b/arch/x86/crypto/sm4_aesni_avx2_glue.c index 84bc718f49a3d7..1148fd4cd57f8e 100644 --- a/arch/x86/crypto/sm4_aesni_avx2_glue.c +++ b/arch/x86/crypto/sm4_aesni_avx2_glue.c @@ -23,8 +23,6 @@ asmlinkage void sm4_aesni_avx2_ctr_enc_blk16(const u32 *rk, u8 *dst, const u8 *src, u8 *iv); asmlinkage void sm4_aesni_avx2_cbc_dec_blk16(const u32 *rk, u8 *dst, const u8 *src, u8 *iv); -asmlinkage void sm4_aesni_avx2_cfb_dec_blk16(const u32 *rk, u8 *dst, - const u8 *src, u8 *iv); static int sm4_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, unsigned int key_len) @@ -41,12 +39,6 @@ static int cbc_decrypt(struct skcipher_request *req) } -static int cfb_decrypt(struct skcipher_request *req) -{ - return sm4_avx_cfb_decrypt(req, SM4_CRYPT16_BLOCK_SIZE, - sm4_aesni_avx2_cfb_dec_blk16); -} - static int ctr_crypt(struct skcipher_request *req) { return sm4_avx_ctr_crypt(req, SM4_CRYPT16_BLOCK_SIZE, @@ -87,24 +79,6 @@ static struct skcipher_alg sm4_aesni_avx2_skciphers[] = { .setkey = sm4_skcipher_setkey, .encrypt = sm4_cbc_encrypt, .decrypt = cbc_decrypt, - }, { - .base = { - .cra_name = "__cfb(sm4)", - .cra_driver_name = "__cfb-sm4-aesni-avx2", - .cra_priority = 500, - .cra_flags = CRYPTO_ALG_INTERNAL, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct sm4_ctx), - .cra_module = THIS_MODULE, - }, - .min_keysize = SM4_KEY_SIZE, - .max_keysize = SM4_KEY_SIZE, - .ivsize = SM4_BLOCK_SIZE, - .chunksize = SM4_BLOCK_SIZE, - .walksize = 16 * SM4_BLOCK_SIZE, - .setkey = sm4_skcipher_setkey, - .encrypt = sm4_cfb_encrypt, - .decrypt = cfb_decrypt, }, { .base = { .cra_name = "__ctr(sm4)", diff --git a/arch/x86/crypto/sm4_aesni_avx_glue.c b/arch/x86/crypto/sm4_aesni_avx_glue.c index 7800f77d68add9..85b4ca78b47b57 100644 --- a/arch/x86/crypto/sm4_aesni_avx_glue.c +++ b/arch/x86/crypto/sm4_aesni_avx_glue.c @@ -27,8 +27,6 @@ asmlinkage void sm4_aesni_avx_ctr_enc_blk8(const u32 *rk, u8 *dst, const u8 *src, u8 *iv); asmlinkage void sm4_aesni_avx_cbc_dec_blk8(const u32 *rk, u8 *dst, const u8 *src, u8 *iv); -asmlinkage void sm4_aesni_avx_cfb_dec_blk8(const u32 *rk, u8 *dst, - const u8 *src, u8 *iv); static int sm4_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, unsigned int key_len) @@ -188,116 +186,6 @@ static int cbc_decrypt(struct skcipher_request *req) sm4_aesni_avx_cbc_dec_blk8); } -int sm4_cfb_encrypt(struct skcipher_request *req) -{ - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); - struct sm4_ctx *ctx = crypto_skcipher_ctx(tfm); - struct skcipher_walk walk; - unsigned int nbytes; - int err; - - err = skcipher_walk_virt(&walk, req, false); - - while ((nbytes = walk.nbytes) > 0) { - u8 keystream[SM4_BLOCK_SIZE]; - const u8 *iv = walk.iv; - const u8 *src = walk.src.virt.addr; - u8 *dst = walk.dst.virt.addr; - - while (nbytes >= SM4_BLOCK_SIZE) { - sm4_crypt_block(ctx->rkey_enc, keystream, iv); - crypto_xor_cpy(dst, src, keystream, SM4_BLOCK_SIZE); - iv = dst; - src += SM4_BLOCK_SIZE; - dst += SM4_BLOCK_SIZE; - nbytes -= SM4_BLOCK_SIZE; - } - if (iv != walk.iv) - memcpy(walk.iv, iv, SM4_BLOCK_SIZE); - - /* tail */ - if (walk.nbytes == walk.total && nbytes > 0) { - sm4_crypt_block(ctx->rkey_enc, keystream, walk.iv); - crypto_xor_cpy(dst, src, keystream, nbytes); - nbytes = 0; - } - - err = skcipher_walk_done(&walk, nbytes); - } - - return err; -} -EXPORT_SYMBOL_GPL(sm4_cfb_encrypt); - -int sm4_avx_cfb_decrypt(struct skcipher_request *req, - unsigned int bsize, sm4_crypt_func func) -{ - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); - struct sm4_ctx *ctx = crypto_skcipher_ctx(tfm); - struct skcipher_walk walk; - unsigned int nbytes; - int err; - - err = skcipher_walk_virt(&walk, req, false); - - while ((nbytes = walk.nbytes) > 0) { - const u8 *src = walk.src.virt.addr; - u8 *dst = walk.dst.virt.addr; - - kernel_fpu_begin(); - - while (nbytes >= bsize) { - func(ctx->rkey_enc, dst, src, walk.iv); - dst += bsize; - src += bsize; - nbytes -= bsize; - } - - while (nbytes >= SM4_BLOCK_SIZE) { - u8 keystream[SM4_BLOCK_SIZE * 8]; - unsigned int nblocks = min(nbytes >> 4, 8u); - - memcpy(keystream, walk.iv, SM4_BLOCK_SIZE); - if (nblocks > 1) - memcpy(&keystream[SM4_BLOCK_SIZE], src, - (nblocks - 1) * SM4_BLOCK_SIZE); - memcpy(walk.iv, src + (nblocks - 1) * SM4_BLOCK_SIZE, - SM4_BLOCK_SIZE); - - sm4_aesni_avx_crypt8(ctx->rkey_enc, keystream, - keystream, nblocks); - - crypto_xor_cpy(dst, src, keystream, - nblocks * SM4_BLOCK_SIZE); - dst += nblocks * SM4_BLOCK_SIZE; - src += nblocks * SM4_BLOCK_SIZE; - nbytes -= nblocks * SM4_BLOCK_SIZE; - } - - kernel_fpu_end(); - - /* tail */ - if (walk.nbytes == walk.total && nbytes > 0) { - u8 keystream[SM4_BLOCK_SIZE]; - - sm4_crypt_block(ctx->rkey_enc, keystream, walk.iv); - crypto_xor_cpy(dst, src, keystream, nbytes); - nbytes = 0; - } - - err = skcipher_walk_done(&walk, nbytes); - } - - return err; -} -EXPORT_SYMBOL_GPL(sm4_avx_cfb_decrypt); - -static int cfb_decrypt(struct skcipher_request *req) -{ - return sm4_avx_cfb_decrypt(req, SM4_CRYPT8_BLOCK_SIZE, - sm4_aesni_avx_cfb_dec_blk8); -} - int sm4_avx_ctr_crypt(struct skcipher_request *req, unsigned int bsize, sm4_crypt_func func) { @@ -406,24 +294,6 @@ static struct skcipher_alg sm4_aesni_avx_skciphers[] = { .setkey = sm4_skcipher_setkey, .encrypt = sm4_cbc_encrypt, .decrypt = cbc_decrypt, - }, { - .base = { - .cra_name = "__cfb(sm4)", - .cra_driver_name = "__cfb-sm4-aesni-avx", - .cra_priority = 400, - .cra_flags = CRYPTO_ALG_INTERNAL, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct sm4_ctx), - .cra_module = THIS_MODULE, - }, - .min_keysize = SM4_KEY_SIZE, - .max_keysize = SM4_KEY_SIZE, - .ivsize = SM4_BLOCK_SIZE, - .chunksize = SM4_BLOCK_SIZE, - .walksize = 8 * SM4_BLOCK_SIZE, - .setkey = sm4_skcipher_setkey, - .encrypt = sm4_cfb_encrypt, - .decrypt = cfb_decrypt, }, { .base = { .cra_name = "__ctr(sm4)", diff --git a/arch/x86/entry/calling.h b/arch/x86/entry/calling.h index f6907627172ba9..9f1d94790a5491 100644 --- a/arch/x86/entry/calling.h +++ b/arch/x86/entry/calling.h @@ -175,8 +175,7 @@ For 32-bit we have the following conventions - kernel is built with #define THIS_CPU_user_pcid_flush_mask \ PER_CPU_VAR(cpu_tlbstate) + TLB_STATE_user_pcid_flush_mask -.macro SWITCH_TO_USER_CR3_NOSTACK scratch_reg:req scratch_reg2:req - ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_PTI +.macro SWITCH_TO_USER_CR3 scratch_reg:req scratch_reg2:req mov %cr3, \scratch_reg ALTERNATIVE "jmp .Lwrcr3_\@", "", X86_FEATURE_PCID @@ -206,13 +205,20 @@ For 32-bit we have the following conventions - kernel is built with /* Flip the PGD to the user version */ orq $(PTI_USER_PGTABLE_MASK), \scratch_reg mov \scratch_reg, %cr3 +.endm + +.macro SWITCH_TO_USER_CR3_NOSTACK scratch_reg:req scratch_reg2:req + ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_PTI + SWITCH_TO_USER_CR3 \scratch_reg \scratch_reg2 .Lend_\@: .endm .macro SWITCH_TO_USER_CR3_STACK scratch_reg:req + ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_PTI pushq %rax - SWITCH_TO_USER_CR3_NOSTACK scratch_reg=\scratch_reg scratch_reg2=%rax + SWITCH_TO_USER_CR3 scratch_reg=\scratch_reg scratch_reg2=%rax popq %rax +.Lend_\@: .endm .macro SAVE_AND_SWITCH_TO_KERNEL_CR3 scratch_reg:req save_reg:req diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S index de6469dffe3a46..c40f89ab1b4c70 100644 --- a/arch/x86/entry/entry_64.S +++ b/arch/x86/entry/entry_64.S @@ -559,17 +559,27 @@ __irqentry_text_end: SYM_CODE_START_LOCAL(common_interrupt_return) SYM_INNER_LABEL(swapgs_restore_regs_and_return_to_usermode, SYM_L_GLOBAL) IBRS_EXIT -#ifdef CONFIG_DEBUG_ENTRY - /* Assert that pt_regs indicates user mode. */ - testb $3, CS(%rsp) - jnz 1f - ud2 -1: -#endif #ifdef CONFIG_XEN_PV ALTERNATIVE "", "jmp xenpv_restore_regs_and_return_to_usermode", X86_FEATURE_XENPV #endif +#ifdef CONFIG_PAGE_TABLE_ISOLATION + ALTERNATIVE "", "jmp .Lpti_restore_regs_and_return_to_usermode", X86_FEATURE_PTI +#endif + + STACKLEAK_ERASE + POP_REGS + add $8, %rsp /* orig_ax */ + UNWIND_HINT_IRET_REGS + +.Lswapgs_and_iret: + swapgs + /* Assert that the IRET frame indicates user mode. */ + testb $3, 8(%rsp) + jnz .Lnative_iret + ud2 +#ifdef CONFIG_PAGE_TABLE_ISOLATION +.Lpti_restore_regs_and_return_to_usermode: POP_REGS pop_rdi=0 /* @@ -596,13 +606,14 @@ SYM_INNER_LABEL(swapgs_restore_regs_and_return_to_usermode, SYM_L_GLOBAL) */ STACKLEAK_ERASE_NOCLOBBER - SWITCH_TO_USER_CR3_STACK scratch_reg=%rdi + push %rax + SWITCH_TO_USER_CR3 scratch_reg=%rdi scratch_reg2=%rax + pop %rax /* Restore RDI. */ popq %rdi - swapgs - jmp .Lnative_iret - + jmp .Lswapgs_and_iret +#endif SYM_INNER_LABEL(restore_regs_and_return_to_kernel, SYM_L_GLOBAL) #ifdef CONFIG_DEBUG_ENTRY diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl index c8fac520580353..5f8591ce7f25e7 100644 --- a/arch/x86/entry/syscalls/syscall_32.tbl +++ b/arch/x86/entry/syscalls/syscall_32.tbl @@ -461,3 +461,8 @@ 454 i386 futex_wake sys_futex_wake 455 i386 futex_wait sys_futex_wait 456 i386 futex_requeue sys_futex_requeue +457 i386 statmount sys_statmount +458 i386 listmount sys_listmount +459 i386 lsm_get_self_attr sys_lsm_get_self_attr +460 i386 lsm_set_self_attr sys_lsm_set_self_attr +461 i386 lsm_list_modules sys_lsm_list_modules diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl index 8cb8bf68721cf6..7e8d46f4147f57 100644 --- a/arch/x86/entry/syscalls/syscall_64.tbl +++ b/arch/x86/entry/syscalls/syscall_64.tbl @@ -378,6 +378,11 @@ 454 common futex_wake sys_futex_wake 455 common futex_wait sys_futex_wait 456 common futex_requeue sys_futex_requeue +457 common statmount sys_statmount +458 common listmount sys_listmount +459 common lsm_get_self_attr sys_lsm_get_self_attr +460 common lsm_set_self_attr sys_lsm_set_self_attr +461 common lsm_list_modules sys_lsm_list_modules # # Due to a historical design error, certain syscalls are numbered differently diff --git a/arch/x86/entry/vdso/vclock_gettime.c b/arch/x86/entry/vdso/vclock_gettime.c index 7d70935b6758f0..0debc194bd7819 100644 --- a/arch/x86/entry/vdso/vclock_gettime.c +++ b/arch/x86/entry/vdso/vclock_gettime.c @@ -11,12 +11,10 @@ #include #include #include +#include #include "../../../../lib/vdso/gettimeofday.c" -extern int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz); -extern __kernel_old_time_t __vdso_time(__kernel_old_time_t *t); - int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz) { return __cvdso_gettimeofday(tv, tz); @@ -35,9 +33,6 @@ __kernel_old_time_t time(__kernel_old_time_t *t) __attribute__((weak, alias("__v #if defined(CONFIG_X86_64) && !defined(BUILD_VDSO32_64) /* both 64-bit and x32 use these */ -extern int __vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts); -extern int __vdso_clock_getres(clockid_t clock, struct __kernel_timespec *res); - int __vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts) { return __cvdso_clock_gettime(clock, ts); @@ -56,9 +51,6 @@ int clock_getres(clockid_t, struct __kernel_timespec *) #else /* i386 only */ -extern int __vdso_clock_gettime(clockid_t clock, struct old_timespec32 *ts); -extern int __vdso_clock_getres(clockid_t clock, struct old_timespec32 *res); - int __vdso_clock_gettime(clockid_t clock, struct old_timespec32 *ts) { return __cvdso_clock_gettime32(clock, ts); diff --git a/arch/x86/events/amd/brs.c b/arch/x86/events/amd/brs.c index ed308719236ca3..780acd3dff22a2 100644 --- a/arch/x86/events/amd/brs.c +++ b/arch/x86/events/amd/brs.c @@ -125,7 +125,7 @@ int amd_brs_hw_config(struct perf_event *event) * Where X is the number of taken branches due to interrupt * skid. Skid is large. * - * Where Y is the occurences of the event while BRS is + * Where Y is the occurrences of the event while BRS is * capturing the lbr_nr entries. * * By using retired taken branches, we limit the impact on the diff --git a/arch/x86/events/amd/core.c b/arch/x86/events/amd/core.c index e24976593a298a..81f6d8275b6bf2 100644 --- a/arch/x86/events/amd/core.c +++ b/arch/x86/events/amd/core.c @@ -940,7 +940,7 @@ static int amd_pmu_v2_handle_irq(struct pt_regs *regs) continue; if (has_branch_stack(event)) - perf_sample_save_brstack(&data, event, &cpuc->lbr_stack); + perf_sample_save_brstack(&data, event, &cpuc->lbr_stack, NULL); if (perf_event_overflow(event, &data, regs)) x86_pmu_stop(event, 0); @@ -1184,7 +1184,7 @@ static void amd_put_event_constraints_f17h(struct cpu_hw_events *cpuc, * period of each one and given that the BRS saturates, it would not be possible * to guarantee correlated content for all events. Therefore, in situations * where multiple events want to use BRS, the kernel enforces mutual exclusion. - * Exclusion is enforced by chosing only one counter for events using BRS. + * Exclusion is enforced by choosing only one counter for events using BRS. * The event scheduling logic will then automatically multiplex the * events and ensure that at most one event is actively using BRS. * diff --git a/arch/x86/events/amd/ibs.c b/arch/x86/events/amd/ibs.c index 6911c5399d02f3..e91970b01d6243 100644 --- a/arch/x86/events/amd/ibs.c +++ b/arch/x86/events/amd/ibs.c @@ -287,6 +287,9 @@ static int perf_ibs_init(struct perf_event *event) if (config & ~perf_ibs->config_mask) return -EINVAL; + if (has_branch_stack(event)) + return -EOPNOTSUPP; + ret = validate_group(event); if (ret) return ret; diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index 40ad1425ffa24b..09050641ce5d3c 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -601,7 +601,7 @@ int x86_pmu_hw_config(struct perf_event *event) } } - if (event->attr.branch_sample_type & PERF_SAMPLE_BRANCH_CALL_STACK) + if (branch_sample_call_stack(event)) event->attach_state |= PERF_ATTACH_TASK_DATA; /* @@ -1702,7 +1702,7 @@ int x86_pmu_handle_irq(struct pt_regs *regs) perf_sample_data_init(&data, 0, event->hw.last_period); if (has_branch_stack(event)) - perf_sample_save_brstack(&data, event, &cpuc->lbr_stack); + perf_sample_save_brstack(&data, event, &cpuc->lbr_stack, NULL); if (perf_event_overflow(event, &data, regs)) x86_pmu_stop(event, 0); diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 0f2786d4e405aa..3804f21ab0494f 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -2527,9 +2527,14 @@ static void intel_pmu_assign_event(struct perf_event *event, int idx) perf_report_aux_output_id(event, idx); } +static __always_inline bool intel_pmu_needs_branch_stack(struct perf_event *event) +{ + return event->hw.flags & PERF_X86_EVENT_NEEDS_BRANCH_STACK; +} + static void intel_pmu_del_event(struct perf_event *event) { - if (needs_branch_stack(event)) + if (intel_pmu_needs_branch_stack(event)) intel_pmu_lbr_del(event); if (event->attr.precise_ip) intel_pmu_pebs_del(event); @@ -2787,6 +2792,7 @@ static void intel_pmu_enable_fixed(struct perf_event *event) static void intel_pmu_enable_event(struct perf_event *event) { + u64 enable_mask = ARCH_PERFMON_EVENTSEL_ENABLE; struct hw_perf_event *hwc = &event->hw; int idx = hwc->idx; @@ -2795,8 +2801,10 @@ static void intel_pmu_enable_event(struct perf_event *event) switch (idx) { case 0 ... INTEL_PMC_IDX_FIXED - 1: + if (branch_sample_counters(event)) + enable_mask |= ARCH_PERFMON_EVENTSEL_BR_CNTR; intel_set_masks(event, idx); - __x86_pmu_enable_event(hwc, ARCH_PERFMON_EVENTSEL_ENABLE); + __x86_pmu_enable_event(hwc, enable_mask); break; case INTEL_PMC_IDX_FIXED ... INTEL_PMC_IDX_FIXED_BTS - 1: case INTEL_PMC_IDX_METRIC_BASE ... INTEL_PMC_IDX_METRIC_END: @@ -2820,7 +2828,7 @@ static void intel_pmu_add_event(struct perf_event *event) { if (event->attr.precise_ip) intel_pmu_pebs_add(event); - if (needs_branch_stack(event)) + if (intel_pmu_needs_branch_stack(event)) intel_pmu_lbr_add(event); } @@ -3047,7 +3055,7 @@ static int handle_pmi_common(struct pt_regs *regs, u64 status) perf_sample_data_init(&data, 0, event->hw.last_period); if (has_branch_stack(event)) - perf_sample_save_brstack(&data, event, &cpuc->lbr_stack); + intel_pmu_lbr_save_brstack(&data, cpuc, event); if (perf_event_overflow(event, &data, regs)) x86_pmu_stop(event, 0); @@ -3612,6 +3620,13 @@ intel_get_event_constraints(struct cpu_hw_events *cpuc, int idx, if (cpuc->excl_cntrs) return intel_get_excl_constraints(cpuc, event, idx, c2); + /* Not all counters support the branch counter feature. */ + if (branch_sample_counters(event)) { + c2 = dyn_constraint(cpuc, c2, idx); + c2->idxmsk64 &= x86_pmu.lbr_counters; + c2->weight = hweight64(c2->idxmsk64); + } + return c2; } @@ -3897,7 +3912,62 @@ static int intel_pmu_hw_config(struct perf_event *event) x86_pmu.pebs_aliases(event); } - if (needs_branch_stack(event)) { + if (needs_branch_stack(event) && is_sampling_event(event)) + event->hw.flags |= PERF_X86_EVENT_NEEDS_BRANCH_STACK; + + if (branch_sample_counters(event)) { + struct perf_event *leader, *sibling; + int num = 0; + + if (!(x86_pmu.flags & PMU_FL_BR_CNTR) || + (event->attr.config & ~INTEL_ARCH_EVENT_MASK)) + return -EINVAL; + + /* + * The branch counter logging is not supported in the call stack + * mode yet, since we cannot simply flush the LBR during e.g., + * multiplexing. Also, there is no obvious usage with the call + * stack mode. Simply forbids it for now. + * + * If any events in the group enable the branch counter logging + * feature, the group is treated as a branch counter logging + * group, which requires the extra space to store the counters. + */ + leader = event->group_leader; + if (branch_sample_call_stack(leader)) + return -EINVAL; + if (branch_sample_counters(leader)) + num++; + leader->hw.flags |= PERF_X86_EVENT_BRANCH_COUNTERS; + + for_each_sibling_event(sibling, leader) { + if (branch_sample_call_stack(sibling)) + return -EINVAL; + if (branch_sample_counters(sibling)) + num++; + } + + if (num > fls(x86_pmu.lbr_counters)) + return -EINVAL; + /* + * Only applying the PERF_SAMPLE_BRANCH_COUNTERS doesn't + * require any branch stack setup. + * Clear the bit to avoid unnecessary branch stack setup. + */ + if (0 == (event->attr.branch_sample_type & + ~(PERF_SAMPLE_BRANCH_PLM_ALL | + PERF_SAMPLE_BRANCH_COUNTERS))) + event->hw.flags &= ~PERF_X86_EVENT_NEEDS_BRANCH_STACK; + + /* + * Force the leader to be a LBR event. So LBRs can be reset + * with the leader event. See intel_pmu_lbr_del() for details. + */ + if (!intel_pmu_needs_branch_stack(leader)) + return -EINVAL; + } + + if (intel_pmu_needs_branch_stack(event)) { ret = intel_pmu_setup_lbr_filter(event); if (ret) return ret; @@ -4027,7 +4097,7 @@ static int intel_pmu_hw_config(struct perf_event *event) /* * Currently, the only caller of this function is the atomic_switch_perf_msrs(). - * The host perf conext helps to prepare the values of the real hardware for + * The host perf context helps to prepare the values of the real hardware for * a set of msrs that need to be switched atomically in a vmx transaction. * * For example, the pseudocode needed to add a new msr should look like: @@ -4380,8 +4450,13 @@ cmt_get_event_constraints(struct cpu_hw_events *cpuc, int idx, */ if (event->attr.precise_ip == 3) { /* Force instruction:ppp on PMC0, 1 and Fixed counter 0 */ - if (constraint_match(&fixed0_constraint, event->hw.config)) - return &fixed0_counter0_1_constraint; + if (constraint_match(&fixed0_constraint, event->hw.config)) { + /* The fixed counter 0 doesn't support LBR event logging. */ + if (branch_sample_counters(event)) + return &counter0_1_constraint; + else + return &fixed0_counter0_1_constraint; + } switch (c->idxmsk64 & 0x3ull) { case 0x1: @@ -4560,7 +4635,7 @@ int intel_cpuc_prepare(struct cpu_hw_events *cpuc, int cpu) goto err; } - if (x86_pmu.flags & (PMU_FL_EXCL_CNTRS | PMU_FL_TFA)) { + if (x86_pmu.flags & (PMU_FL_EXCL_CNTRS | PMU_FL_TFA | PMU_FL_BR_CNTR)) { size_t sz = X86_PMC_IDX_MAX * sizeof(struct event_constraint); cpuc->constraint_list = kzalloc_node(sz, GFP_KERNEL, cpu_to_node(cpu)); @@ -5532,11 +5607,41 @@ static ssize_t branches_show(struct device *cdev, static DEVICE_ATTR_RO(branches); +static ssize_t branch_counter_nr_show(struct device *cdev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", fls(x86_pmu.lbr_counters)); +} + +static DEVICE_ATTR_RO(branch_counter_nr); + +static ssize_t branch_counter_width_show(struct device *cdev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", LBR_INFO_BR_CNTR_BITS); +} + +static DEVICE_ATTR_RO(branch_counter_width); + static struct attribute *lbr_attrs[] = { &dev_attr_branches.attr, + &dev_attr_branch_counter_nr.attr, + &dev_attr_branch_counter_width.attr, NULL }; +static umode_t +lbr_is_visible(struct kobject *kobj, struct attribute *attr, int i) +{ + /* branches */ + if (i == 0) + return x86_pmu.lbr_nr ? attr->mode : 0; + + return (x86_pmu.flags & PMU_FL_BR_CNTR) ? attr->mode : 0; +} + static char pmu_name_str[30]; static ssize_t pmu_name_show(struct device *cdev, @@ -5563,6 +5668,15 @@ static struct attribute *intel_pmu_attrs[] = { NULL, }; +static umode_t +default_is_visible(struct kobject *kobj, struct attribute *attr, int i) +{ + if (attr == &dev_attr_allow_tsx_force_abort.attr) + return x86_pmu.flags & PMU_FL_TFA ? attr->mode : 0; + + return attr->mode; +} + static umode_t tsx_is_visible(struct kobject *kobj, struct attribute *attr, int i) { @@ -5584,27 +5698,12 @@ mem_is_visible(struct kobject *kobj, struct attribute *attr, int i) return pebs_is_visible(kobj, attr, i); } -static umode_t -lbr_is_visible(struct kobject *kobj, struct attribute *attr, int i) -{ - return x86_pmu.lbr_nr ? attr->mode : 0; -} - static umode_t exra_is_visible(struct kobject *kobj, struct attribute *attr, int i) { return x86_pmu.version >= 2 ? attr->mode : 0; } -static umode_t -default_is_visible(struct kobject *kobj, struct attribute *attr, int i) -{ - if (attr == &dev_attr_allow_tsx_force_abort.attr) - return x86_pmu.flags & PMU_FL_TFA ? attr->mode : 0; - - return attr->mode; -} - static struct attribute_group group_events_td = { .name = "events", }; diff --git a/arch/x86/events/intel/cstate.c b/arch/x86/events/intel/cstate.c index cbeb6d2bf5b459..4b50a3a9818aec 100644 --- a/arch/x86/events/intel/cstate.c +++ b/arch/x86/events/intel/cstate.c @@ -41,7 +41,7 @@ * MSR_CORE_C1_RES: CORE C1 Residency Counter * perf code: 0x00 * Available model: SLM,AMT,GLM,CNL,ICX,TNT,ADL,RPL - * MTL + * MTL,SRF,GRR * Scope: Core (each processor core has a MSR) * MSR_CORE_C3_RESIDENCY: CORE C3 Residency Counter * perf code: 0x01 @@ -52,7 +52,8 @@ * perf code: 0x02 * Available model: SLM,AMT,NHM,WSM,SNB,IVB,HSW,BDW, * SKL,KNL,GLM,CNL,KBL,CML,ICL,ICX, - * TGL,TNT,RKL,ADL,RPL,SPR,MTL + * TGL,TNT,RKL,ADL,RPL,SPR,MTL,SRF, + * GRR * Scope: Core * MSR_CORE_C7_RESIDENCY: CORE C7 Residency Counter * perf code: 0x03 @@ -75,7 +76,7 @@ * perf code: 0x02 * Available model: SLM,AMT,NHM,WSM,SNB,IVB,HSW,BDW, * SKL,KNL,GLM,CNL,KBL,CML,ICL,ICX, - * TGL,TNT,RKL,ADL,RPL,SPR,MTL + * TGL,TNT,RKL,ADL,RPL,SPR,MTL,SRF * Scope: Package (physical package) * MSR_PKG_C7_RESIDENCY: Package C7 Residency Counter. * perf code: 0x03 @@ -97,6 +98,10 @@ * Available model: HSW ULT,KBL,GLM,CNL,CML,ICL,TGL, * TNT,RKL,ADL,RPL,MTL * Scope: Package (physical package) + * MSR_MODULE_C6_RES_MS: Module C6 Residency Counter. + * perf code: 0x00 + * Available model: SRF,GRR + * Scope: A cluster of cores shared L2 cache * */ @@ -130,6 +135,7 @@ static ssize_t cstate_get_attr_cpumask(struct device *dev, struct cstate_model { unsigned long core_events; unsigned long pkg_events; + unsigned long module_events; unsigned long quirks; }; @@ -189,20 +195,20 @@ static struct attribute *attrs_empty[] = { * "events" group (with empty attrs) before updating * it with detected events. */ -static struct attribute_group core_events_attr_group = { +static struct attribute_group cstate_events_attr_group = { .name = "events", .attrs = attrs_empty, }; -DEFINE_CSTATE_FORMAT_ATTR(core_event, event, "config:0-63"); -static struct attribute *core_format_attrs[] = { - &format_attr_core_event.attr, +DEFINE_CSTATE_FORMAT_ATTR(cstate_event, event, "config:0-63"); +static struct attribute *cstate_format_attrs[] = { + &format_attr_cstate_event.attr, NULL, }; -static struct attribute_group core_format_attr_group = { +static struct attribute_group cstate_format_attr_group = { .name = "format", - .attrs = core_format_attrs, + .attrs = cstate_format_attrs, }; static cpumask_t cstate_core_cpu_mask; @@ -217,9 +223,9 @@ static struct attribute_group cpumask_attr_group = { .attrs = cstate_cpumask_attrs, }; -static const struct attribute_group *core_attr_groups[] = { - &core_events_attr_group, - &core_format_attr_group, +static const struct attribute_group *cstate_attr_groups[] = { + &cstate_events_attr_group, + &cstate_format_attr_group, &cpumask_attr_group, NULL, }; @@ -268,30 +274,30 @@ static struct perf_msr pkg_msr[] = { [PERF_CSTATE_PKG_C10_RES] = { MSR_PKG_C10_RESIDENCY, &group_cstate_pkg_c10, test_msr }, }; -static struct attribute_group pkg_events_attr_group = { - .name = "events", - .attrs = attrs_empty, -}; +static cpumask_t cstate_pkg_cpu_mask; -DEFINE_CSTATE_FORMAT_ATTR(pkg_event, event, "config:0-63"); -static struct attribute *pkg_format_attrs[] = { - &format_attr_pkg_event.attr, - NULL, -}; -static struct attribute_group pkg_format_attr_group = { - .name = "format", - .attrs = pkg_format_attrs, +/* cstate_module PMU */ +static struct pmu cstate_module_pmu; +static bool has_cstate_module; + +enum perf_cstate_module_events { + PERF_CSTATE_MODULE_C6_RES = 0, + + PERF_CSTATE_MODULE_EVENT_MAX, }; -static cpumask_t cstate_pkg_cpu_mask; +PMU_EVENT_ATTR_STRING(c6-residency, attr_cstate_module_c6, "event=0x00"); -static const struct attribute_group *pkg_attr_groups[] = { - &pkg_events_attr_group, - &pkg_format_attr_group, - &cpumask_attr_group, - NULL, +static unsigned long module_msr_mask; + +PMU_EVENT_GROUP(events, cstate_module_c6); + +static struct perf_msr module_msr[] = { + [PERF_CSTATE_MODULE_C6_RES] = { MSR_MODULE_C6_RES_MS, &group_cstate_module_c6, test_msr }, }; +static cpumask_t cstate_module_cpu_mask; + static ssize_t cstate_get_attr_cpumask(struct device *dev, struct device_attribute *attr, char *buf) @@ -302,6 +308,8 @@ static ssize_t cstate_get_attr_cpumask(struct device *dev, return cpumap_print_to_pagebuf(true, buf, &cstate_core_cpu_mask); else if (pmu == &cstate_pkg_pmu) return cpumap_print_to_pagebuf(true, buf, &cstate_pkg_cpu_mask); + else if (pmu == &cstate_module_pmu) + return cpumap_print_to_pagebuf(true, buf, &cstate_module_cpu_mask); else return 0; } @@ -342,6 +350,15 @@ static int cstate_pmu_event_init(struct perf_event *event) event->hw.event_base = pkg_msr[cfg].msr; cpu = cpumask_any_and(&cstate_pkg_cpu_mask, topology_die_cpumask(event->cpu)); + } else if (event->pmu == &cstate_module_pmu) { + if (cfg >= PERF_CSTATE_MODULE_EVENT_MAX) + return -EINVAL; + cfg = array_index_nospec((unsigned long)cfg, PERF_CSTATE_MODULE_EVENT_MAX); + if (!(module_msr_mask & (1 << cfg))) + return -EINVAL; + event->hw.event_base = module_msr[cfg].msr; + cpu = cpumask_any_and(&cstate_module_cpu_mask, + topology_cluster_cpumask(event->cpu)); } else { return -ENOENT; } @@ -429,6 +446,17 @@ static int cstate_cpu_exit(unsigned int cpu) perf_pmu_migrate_context(&cstate_pkg_pmu, cpu, target); } } + + if (has_cstate_module && + cpumask_test_and_clear_cpu(cpu, &cstate_module_cpu_mask)) { + + target = cpumask_any_but(topology_cluster_cpumask(cpu), cpu); + /* Migrate events if there is a valid target */ + if (target < nr_cpu_ids) { + cpumask_set_cpu(target, &cstate_module_cpu_mask); + perf_pmu_migrate_context(&cstate_module_pmu, cpu, target); + } + } return 0; } @@ -455,6 +483,15 @@ static int cstate_cpu_init(unsigned int cpu) if (has_cstate_pkg && target >= nr_cpu_ids) cpumask_set_cpu(cpu, &cstate_pkg_cpu_mask); + /* + * If this is the first online thread of that cluster, set it + * in the cluster cpu mask as the designated reader. + */ + target = cpumask_any_and(&cstate_module_cpu_mask, + topology_cluster_cpumask(cpu)); + if (has_cstate_module && target >= nr_cpu_ids) + cpumask_set_cpu(cpu, &cstate_module_cpu_mask); + return 0; } @@ -477,8 +514,13 @@ static const struct attribute_group *pkg_attr_update[] = { NULL, }; +static const struct attribute_group *module_attr_update[] = { + &group_cstate_module_c6, + NULL +}; + static struct pmu cstate_core_pmu = { - .attr_groups = core_attr_groups, + .attr_groups = cstate_attr_groups, .attr_update = core_attr_update, .name = "cstate_core", .task_ctx_nr = perf_invalid_context, @@ -493,7 +535,7 @@ static struct pmu cstate_core_pmu = { }; static struct pmu cstate_pkg_pmu = { - .attr_groups = pkg_attr_groups, + .attr_groups = cstate_attr_groups, .attr_update = pkg_attr_update, .name = "cstate_pkg", .task_ctx_nr = perf_invalid_context, @@ -507,6 +549,21 @@ static struct pmu cstate_pkg_pmu = { .module = THIS_MODULE, }; +static struct pmu cstate_module_pmu = { + .attr_groups = cstate_attr_groups, + .attr_update = module_attr_update, + .name = "cstate_module", + .task_ctx_nr = perf_invalid_context, + .event_init = cstate_pmu_event_init, + .add = cstate_pmu_event_add, + .del = cstate_pmu_event_del, + .start = cstate_pmu_event_start, + .stop = cstate_pmu_event_stop, + .read = cstate_pmu_event_update, + .capabilities = PERF_PMU_CAP_NO_INTERRUPT | PERF_PMU_CAP_NO_EXCLUDE, + .module = THIS_MODULE, +}; + static const struct cstate_model nhm_cstates __initconst = { .core_events = BIT(PERF_CSTATE_CORE_C3_RES) | BIT(PERF_CSTATE_CORE_C6_RES), @@ -621,6 +678,22 @@ static const struct cstate_model glm_cstates __initconst = { BIT(PERF_CSTATE_PKG_C10_RES), }; +static const struct cstate_model grr_cstates __initconst = { + .core_events = BIT(PERF_CSTATE_CORE_C1_RES) | + BIT(PERF_CSTATE_CORE_C6_RES), + + .module_events = BIT(PERF_CSTATE_MODULE_C6_RES), +}; + +static const struct cstate_model srf_cstates __initconst = { + .core_events = BIT(PERF_CSTATE_CORE_C1_RES) | + BIT(PERF_CSTATE_CORE_C6_RES), + + .pkg_events = BIT(PERF_CSTATE_PKG_C6_RES), + + .module_events = BIT(PERF_CSTATE_MODULE_C6_RES), +}; + static const struct x86_cpu_id intel_cstates_match[] __initconst = { X86_MATCH_INTEL_FAM6_MODEL(NEHALEM, &nhm_cstates), @@ -673,6 +746,8 @@ static const struct x86_cpu_id intel_cstates_match[] __initconst = { X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT, &glm_cstates), X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT_L, &glm_cstates), X86_MATCH_INTEL_FAM6_MODEL(ATOM_GRACEMONT, &adl_cstates), + X86_MATCH_INTEL_FAM6_MODEL(ATOM_CRESTMONT_X, &srf_cstates), + X86_MATCH_INTEL_FAM6_MODEL(ATOM_CRESTMONT, &grr_cstates), X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L, &icl_cstates), X86_MATCH_INTEL_FAM6_MODEL(ICELAKE, &icl_cstates), @@ -714,10 +789,14 @@ static int __init cstate_probe(const struct cstate_model *cm) pkg_msr_mask = perf_msr_probe(pkg_msr, PERF_CSTATE_PKG_EVENT_MAX, true, (void *) &cm->pkg_events); + module_msr_mask = perf_msr_probe(module_msr, PERF_CSTATE_MODULE_EVENT_MAX, + true, (void *) &cm->module_events); + has_cstate_core = !!core_msr_mask; has_cstate_pkg = !!pkg_msr_mask; + has_cstate_module = !!module_msr_mask; - return (has_cstate_core || has_cstate_pkg) ? 0 : -ENODEV; + return (has_cstate_core || has_cstate_pkg || has_cstate_module) ? 0 : -ENODEV; } static inline void cstate_cleanup(void) @@ -730,6 +809,9 @@ static inline void cstate_cleanup(void) if (has_cstate_pkg) perf_pmu_unregister(&cstate_pkg_pmu); + + if (has_cstate_module) + perf_pmu_unregister(&cstate_module_pmu); } static int __init cstate_init(void) @@ -766,6 +848,16 @@ static int __init cstate_init(void) return err; } } + + if (has_cstate_module) { + err = perf_pmu_register(&cstate_module_pmu, cstate_module_pmu.name, -1); + if (err) { + has_cstate_module = false; + pr_info("Failed to register cstate cluster pmu\n"); + cstate_cleanup(); + return err; + } + } return 0; } diff --git a/arch/x86/events/intel/ds.c b/arch/x86/events/intel/ds.c index bf97ab904d40f7..d49d661ec0a7d1 100644 --- a/arch/x86/events/intel/ds.c +++ b/arch/x86/events/intel/ds.c @@ -1755,7 +1755,7 @@ static void setup_pebs_fixed_sample_data(struct perf_event *event, setup_pebs_time(event, data, pebs->tsc); if (has_branch_stack(event)) - perf_sample_save_brstack(data, event, &cpuc->lbr_stack); + perf_sample_save_brstack(data, event, &cpuc->lbr_stack, NULL); } static void adaptive_pebs_save_regs(struct pt_regs *regs, @@ -1912,7 +1912,7 @@ static void setup_pebs_adaptive_sample_data(struct perf_event *event, if (has_branch_stack(event)) { intel_pmu_store_pebs_lbrs(lbr); - perf_sample_save_brstack(data, event, &cpuc->lbr_stack); + intel_pmu_lbr_save_brstack(data, cpuc, event); } } diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c index c3b0d15a9841b5..78cd5084104e9c 100644 --- a/arch/x86/events/intel/lbr.c +++ b/arch/x86/events/intel/lbr.c @@ -676,6 +676,25 @@ void intel_pmu_lbr_del(struct perf_event *event) WARN_ON_ONCE(cpuc->lbr_users < 0); WARN_ON_ONCE(cpuc->lbr_pebs_users < 0); perf_sched_cb_dec(event->pmu); + + /* + * The logged occurrences information is only valid for the + * current LBR group. If another LBR group is scheduled in + * later, the information from the stale LBRs will be wrongly + * interpreted. Reset the LBRs here. + * + * Only clear once for a branch counter group with the leader + * event. Because + * - Cannot simply reset the LBRs with the !cpuc->lbr_users. + * Because it's possible that the last LBR user is not in a + * branch counter group, e.g., a branch_counters group + + * several normal LBR events. + * - The LBR reset can be done with any one of the events in a + * branch counter group, since they are always scheduled together. + * It's easy to force the leader event an LBR event. + */ + if (is_branch_counters_group(event) && event == event->group_leader) + intel_pmu_lbr_reset(); } static inline bool vlbr_exclude_host(void) @@ -866,6 +885,8 @@ static __always_inline u16 get_lbr_cycles(u64 info) return cycles; } +static_assert((64 - PERF_BRANCH_ENTRY_INFO_BITS_MAX) > LBR_INFO_BR_CNTR_NUM * LBR_INFO_BR_CNTR_BITS); + static void intel_pmu_store_lbr(struct cpu_hw_events *cpuc, struct lbr_entry *entries) { @@ -898,11 +919,67 @@ static void intel_pmu_store_lbr(struct cpu_hw_events *cpuc, e->abort = !!(info & LBR_INFO_ABORT); e->cycles = get_lbr_cycles(info); e->type = get_lbr_br_type(info); + + /* + * Leverage the reserved field of cpuc->lbr_entries[i] to + * temporarily store the branch counters information. + * The later code will decide what content can be disclosed + * to the perf tool. Pleae see intel_pmu_lbr_counters_reorder(). + */ + e->reserved = (info >> LBR_INFO_BR_CNTR_OFFSET) & LBR_INFO_BR_CNTR_FULL_MASK; } cpuc->lbr_stack.nr = i; } +/* + * The enabled order may be different from the counter order. + * Update the lbr_counters with the enabled order. + */ +static void intel_pmu_lbr_counters_reorder(struct cpu_hw_events *cpuc, + struct perf_event *event) +{ + int i, j, pos = 0, order[X86_PMC_IDX_MAX]; + struct perf_event *leader, *sibling; + u64 src, dst, cnt; + + leader = event->group_leader; + if (branch_sample_counters(leader)) + order[pos++] = leader->hw.idx; + + for_each_sibling_event(sibling, leader) { + if (!branch_sample_counters(sibling)) + continue; + order[pos++] = sibling->hw.idx; + } + + WARN_ON_ONCE(!pos); + + for (i = 0; i < cpuc->lbr_stack.nr; i++) { + src = cpuc->lbr_entries[i].reserved; + dst = 0; + for (j = 0; j < pos; j++) { + cnt = (src >> (order[j] * LBR_INFO_BR_CNTR_BITS)) & LBR_INFO_BR_CNTR_MASK; + dst |= cnt << j * LBR_INFO_BR_CNTR_BITS; + } + cpuc->lbr_counters[i] = dst; + cpuc->lbr_entries[i].reserved = 0; + } +} + +void intel_pmu_lbr_save_brstack(struct perf_sample_data *data, + struct cpu_hw_events *cpuc, + struct perf_event *event) +{ + if (is_branch_counters_group(event)) { + intel_pmu_lbr_counters_reorder(cpuc, event); + perf_sample_save_brstack(data, event, &cpuc->lbr_stack, cpuc->lbr_counters); + return; + } + + perf_sample_save_brstack(data, event, &cpuc->lbr_stack, NULL); +} + static void intel_pmu_arch_lbr_read(struct cpu_hw_events *cpuc) { intel_pmu_store_lbr(cpuc, NULL); @@ -1173,8 +1250,10 @@ intel_pmu_lbr_filter(struct cpu_hw_events *cpuc) for (i = 0; i < cpuc->lbr_stack.nr; ) { if (!cpuc->lbr_entries[i].from) { j = i; - while (++j < cpuc->lbr_stack.nr) + while (++j < cpuc->lbr_stack.nr) { cpuc->lbr_entries[j-1] = cpuc->lbr_entries[j]; + cpuc->lbr_counters[j-1] = cpuc->lbr_counters[j]; + } cpuc->lbr_stack.nr--; if (!cpuc->lbr_entries[i].from) continue; @@ -1525,8 +1604,12 @@ void __init intel_pmu_arch_lbr_init(void) x86_pmu.lbr_mispred = ecx.split.lbr_mispred; x86_pmu.lbr_timed_lbr = ecx.split.lbr_timed_lbr; x86_pmu.lbr_br_type = ecx.split.lbr_br_type; + x86_pmu.lbr_counters = ecx.split.lbr_counters; x86_pmu.lbr_nr = lbr_nr; + if (!!x86_pmu.lbr_counters) + x86_pmu.flags |= PMU_FL_BR_CNTR; + if (x86_pmu.lbr_mispred) static_branch_enable(&x86_lbr_mispred); if (x86_pmu.lbr_timed_lbr) diff --git a/arch/x86/events/intel/uncore.c b/arch/x86/events/intel/uncore.c index 01023aa5125bbc..7927c0b832faa4 100644 --- a/arch/x86/events/intel/uncore.c +++ b/arch/x86/events/intel/uncore.c @@ -1814,6 +1814,14 @@ static const struct intel_uncore_init_fun spr_uncore_init __initconst = { .uncore_units_ignore = spr_uncore_units_ignore, }; +static const struct intel_uncore_init_fun gnr_uncore_init __initconst = { + .cpu_init = gnr_uncore_cpu_init, + .pci_init = gnr_uncore_pci_init, + .mmio_init = gnr_uncore_mmio_init, + .use_discovery = true, + .uncore_units_ignore = gnr_uncore_units_ignore, +}; + static const struct intel_uncore_init_fun generic_uncore_init __initconst = { .cpu_init = intel_uncore_generic_uncore_cpu_init, .pci_init = intel_uncore_generic_uncore_pci_init, @@ -1865,8 +1873,12 @@ static const struct x86_cpu_id intel_uncore_match[] __initconst = { X86_MATCH_INTEL_FAM6_MODEL(METEORLAKE_L, &mtl_uncore_init), X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X, &spr_uncore_init), X86_MATCH_INTEL_FAM6_MODEL(EMERALDRAPIDS_X, &spr_uncore_init), + X86_MATCH_INTEL_FAM6_MODEL(GRANITERAPIDS_X, &gnr_uncore_init), + X86_MATCH_INTEL_FAM6_MODEL(GRANITERAPIDS_D, &gnr_uncore_init), X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT_D, &snr_uncore_init), X86_MATCH_INTEL_FAM6_MODEL(ATOM_GRACEMONT, &adl_uncore_init), + X86_MATCH_INTEL_FAM6_MODEL(ATOM_CRESTMONT_X, &gnr_uncore_init), + X86_MATCH_INTEL_FAM6_MODEL(ATOM_CRESTMONT, &gnr_uncore_init), {}, }; MODULE_DEVICE_TABLE(x86cpu, intel_uncore_match); diff --git a/arch/x86/events/intel/uncore.h b/arch/x86/events/intel/uncore.h index c30fb5bb1222b3..4838502d89aed3 100644 --- a/arch/x86/events/intel/uncore.h +++ b/arch/x86/events/intel/uncore.h @@ -72,9 +72,9 @@ struct intel_uncore_type { unsigned single_fixed:1; unsigned pair_ctr_ctl:1; union { - unsigned *msr_offsets; - unsigned *pci_offsets; - unsigned *mmio_offsets; + u64 *msr_offsets; + u64 *pci_offsets; + u64 *mmio_offsets; }; unsigned *box_ids; struct event_constraint unconstrainted; @@ -593,6 +593,7 @@ extern struct list_head pci2phy_map_head; extern struct pci_extra_dev *uncore_extra_pci_dev; extern struct event_constraint uncore_constraint_empty; extern int spr_uncore_units_ignore[]; +extern int gnr_uncore_units_ignore[]; /* uncore_snb.c */ int snb_uncore_pci_init(void); @@ -634,6 +635,9 @@ void icx_uncore_mmio_init(void); int spr_uncore_pci_init(void); void spr_uncore_cpu_init(void); void spr_uncore_mmio_init(void); +int gnr_uncore_pci_init(void); +void gnr_uncore_cpu_init(void); +void gnr_uncore_mmio_init(void); /* uncore_nhmex.c */ void nhmex_uncore_cpu_init(void); diff --git a/arch/x86/events/intel/uncore_discovery.c b/arch/x86/events/intel/uncore_discovery.c index cb488e41807c76..9a698a92962a10 100644 --- a/arch/x86/events/intel/uncore_discovery.c +++ b/arch/x86/events/intel/uncore_discovery.c @@ -125,7 +125,8 @@ uncore_insert_box_info(struct uncore_unit_discovery *unit, int die, bool parsed) { struct intel_uncore_discovery_type *type; - unsigned int *box_offset, *ids; + unsigned int *ids; + u64 *box_offset; int i; if (!unit->ctl || !unit->ctl_offset || !unit->ctr_offset) { @@ -153,7 +154,7 @@ uncore_insert_box_info(struct uncore_unit_discovery *unit, if (!type) return; - box_offset = kcalloc(type->num_boxes + 1, sizeof(unsigned int), GFP_KERNEL); + box_offset = kcalloc(type->num_boxes + 1, sizeof(u64), GFP_KERNEL); if (!box_offset) return; diff --git a/arch/x86/events/intel/uncore_discovery.h b/arch/x86/events/intel/uncore_discovery.h index 6ee80ad3423e4e..22e769a8110393 100644 --- a/arch/x86/events/intel/uncore_discovery.h +++ b/arch/x86/events/intel/uncore_discovery.h @@ -125,7 +125,7 @@ struct intel_uncore_discovery_type { u8 ctr_offset; /* Counter 0 offset */ u16 num_boxes; /* number of boxes for the uncore block */ unsigned int *ids; /* Box IDs */ - unsigned int *box_offset; /* Box offset */ + u64 *box_offset; /* Box offset */ }; bool intel_uncore_has_discovery_tables(int *ignore); diff --git a/arch/x86/events/intel/uncore_nhmex.c b/arch/x86/events/intel/uncore_nhmex.c index 173e2674be6ef2..56eea2c66cfb8c 100644 --- a/arch/x86/events/intel/uncore_nhmex.c +++ b/arch/x86/events/intel/uncore_nhmex.c @@ -306,7 +306,7 @@ static const struct attribute_group nhmex_uncore_cbox_format_group = { }; /* msr offset for each instance of cbox */ -static unsigned nhmex_cbox_msr_offsets[] = { +static u64 nhmex_cbox_msr_offsets[] = { 0x0, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x240, 0x2c0, }; diff --git a/arch/x86/events/intel/uncore_snbep.c b/arch/x86/events/intel/uncore_snbep.c index 8250f0f59c2bbe..a96496bef678bb 100644 --- a/arch/x86/events/intel/uncore_snbep.c +++ b/arch/x86/events/intel/uncore_snbep.c @@ -1396,6 +1396,29 @@ err: return ret; } +static int topology_gidnid_map(int nodeid, u32 gidnid) +{ + int i, die_id = -1; + + /* + * every three bits in the Node ID mapping register maps + * to a particular node. + */ + for (i = 0; i < 8; i++) { + if (nodeid == GIDNIDMAP(gidnid, i)) { + if (topology_max_die_per_package() > 1) + die_id = i; + else + die_id = topology_phys_to_logical_pkg(i); + if (die_id < 0) + die_id = -ENODEV; + break; + } + } + + return die_id; +} + /* * build pci bus to socket mapping */ @@ -1435,22 +1458,7 @@ static int snbep_pci2phy_map_init(int devid, int nodeid_loc, int idmap_loc, bool break; } - /* - * every three bits in the Node ID mapping register maps - * to a particular node. - */ - for (i = 0; i < 8; i++) { - if (nodeid == GIDNIDMAP(config, i)) { - if (topology_max_die_per_package() > 1) - die_id = i; - else - die_id = topology_phys_to_logical_pkg(i); - if (die_id < 0) - die_id = -ENODEV; - map->pbus_to_dieid[bus] = die_id; - break; - } - } + map->pbus_to_dieid[bus] = topology_gidnid_map(nodeid, config); raw_spin_unlock(&pci2phy_map_lock); } else { segment = pci_domain_nr(ubox_dev->bus); @@ -5278,7 +5286,7 @@ void snr_uncore_mmio_init(void) /* ICX uncore support */ -static unsigned icx_cha_msr_offsets[] = { +static u64 icx_cha_msr_offsets[] = { 0x2a0, 0x2ae, 0x2bc, 0x2ca, 0x2d8, 0x2e6, 0x2f4, 0x302, 0x310, 0x31e, 0x32c, 0x33a, 0x348, 0x356, 0x364, 0x372, 0x380, 0x38e, 0x3aa, 0x3b8, 0x3c6, 0x3d4, 0x3e2, 0x3f0, 0x3fe, 0x40c, 0x41a, @@ -5326,7 +5334,7 @@ static struct intel_uncore_type icx_uncore_chabox = { .format_group = &snr_uncore_chabox_format_group, }; -static unsigned icx_msr_offsets[] = { +static u64 icx_msr_offsets[] = { 0x0, 0x20, 0x40, 0x90, 0xb0, 0xd0, }; @@ -5596,7 +5604,7 @@ static int discover_upi_topology(struct intel_uncore_type *type, int ubox_did, i struct pci_dev *ubox = NULL; struct pci_dev *dev = NULL; u32 nid, gid; - int i, idx, ret = -EPERM; + int idx, lgc_pkg, ret = -EPERM; struct intel_uncore_topology *upi; unsigned int devfn; @@ -5611,20 +5619,21 @@ static int discover_upi_topology(struct intel_uncore_type *type, int ubox_did, i break; } - for (i = 0; i < 8; i++) { - if (nid != GIDNIDMAP(gid, i)) - continue; - for (idx = 0; idx < type->num_boxes; idx++) { - upi = &type->topology[nid][idx]; - devfn = PCI_DEVFN(dev_link0 + idx, ICX_UPI_REGS_ADDR_FUNCTION); - dev = pci_get_domain_bus_and_slot(pci_domain_nr(ubox->bus), - ubox->bus->number, - devfn); - if (dev) { - ret = upi_fill_topology(dev, upi, idx); - if (ret) - goto err; - } + lgc_pkg = topology_gidnid_map(nid, gid); + if (lgc_pkg < 0) { + ret = -EPERM; + goto err; + } + for (idx = 0; idx < type->num_boxes; idx++) { + upi = &type->topology[lgc_pkg][idx]; + devfn = PCI_DEVFN(dev_link0 + idx, ICX_UPI_REGS_ADDR_FUNCTION); + dev = pci_get_domain_bus_and_slot(pci_domain_nr(ubox->bus), + ubox->bus->number, + devfn); + if (dev) { + ret = upi_fill_topology(dev, upi, idx); + if (ret) + goto err; } } } @@ -6079,13 +6088,16 @@ static struct uncore_event_desc spr_uncore_imc_events[] = { { /* end: all zeroes */ }, }; +#define SPR_UNCORE_MMIO_COMMON_FORMAT() \ + SPR_UNCORE_COMMON_FORMAT(), \ + .ops = &spr_uncore_mmio_ops + static struct intel_uncore_type spr_uncore_imc = { - SPR_UNCORE_COMMON_FORMAT(), + SPR_UNCORE_MMIO_COMMON_FORMAT(), .name = "imc", .fixed_ctr_bits = 48, .fixed_ctr = SNR_IMC_MMIO_PMON_FIXED_CTR, .fixed_ctl = SNR_IMC_MMIO_PMON_FIXED_CTL, - .ops = &spr_uncore_mmio_ops, .event_descs = spr_uncore_imc_events, }; @@ -6181,7 +6193,7 @@ static struct intel_uncore_type *spr_uncores[UNCORE_SPR_NUM_UNCORE_TYPES] = { */ #define SPR_UNCORE_UPI_NUM_BOXES 4 -static unsigned int spr_upi_pci_offsets[SPR_UNCORE_UPI_NUM_BOXES] = { +static u64 spr_upi_pci_offsets[SPR_UNCORE_UPI_NUM_BOXES] = { 0, 0x8000, 0x10000, 0x18000 }; @@ -6412,7 +6424,8 @@ static void uncore_type_customized_copy(struct intel_uncore_type *to_type, static struct intel_uncore_type ** uncore_get_uncores(enum uncore_access_type type_id, int num_extra, - struct intel_uncore_type **extra) + struct intel_uncore_type **extra, int max_num_types, + struct intel_uncore_type **uncores) { struct intel_uncore_type **types, **start_types; int i; @@ -6421,9 +6434,9 @@ uncore_get_uncores(enum uncore_access_type type_id, int num_extra, /* Only copy the customized features */ for (; *types; types++) { - if ((*types)->type_id >= UNCORE_SPR_NUM_UNCORE_TYPES) + if ((*types)->type_id >= max_num_types) continue; - uncore_type_customized_copy(*types, spr_uncores[(*types)->type_id]); + uncore_type_customized_copy(*types, uncores[(*types)->type_id]); } for (i = 0; i < num_extra; i++, types++) @@ -6470,7 +6483,9 @@ void spr_uncore_cpu_init(void) uncore_msr_uncores = uncore_get_uncores(UNCORE_ACCESS_MSR, UNCORE_SPR_MSR_EXTRA_UNCORES, - spr_msr_uncores); + spr_msr_uncores, + UNCORE_SPR_NUM_UNCORE_TYPES, + spr_uncores); type = uncore_find_type_by_id(uncore_msr_uncores, UNCORE_SPR_CHA); if (type) { @@ -6552,7 +6567,9 @@ int spr_uncore_pci_init(void) spr_update_device_location(UNCORE_SPR_M3UPI); uncore_pci_uncores = uncore_get_uncores(UNCORE_ACCESS_PCI, UNCORE_SPR_PCI_EXTRA_UNCORES, - spr_pci_uncores); + spr_pci_uncores, + UNCORE_SPR_NUM_UNCORE_TYPES, + spr_uncores); return 0; } @@ -6560,15 +6577,116 @@ void spr_uncore_mmio_init(void) { int ret = snbep_pci2phy_map_init(0x3250, SKX_CPUNODEID, SKX_GIDNIDMAP, true); - if (ret) - uncore_mmio_uncores = uncore_get_uncores(UNCORE_ACCESS_MMIO, 0, NULL); - else { + if (ret) { + uncore_mmio_uncores = uncore_get_uncores(UNCORE_ACCESS_MMIO, 0, NULL, + UNCORE_SPR_NUM_UNCORE_TYPES, + spr_uncores); + } else { uncore_mmio_uncores = uncore_get_uncores(UNCORE_ACCESS_MMIO, UNCORE_SPR_MMIO_EXTRA_UNCORES, - spr_mmio_uncores); + spr_mmio_uncores, + UNCORE_SPR_NUM_UNCORE_TYPES, + spr_uncores); spr_uncore_imc_free_running.num_boxes = uncore_type_max_boxes(uncore_mmio_uncores, UNCORE_SPR_IMC) / 2; } } /* end of SPR uncore support */ + +/* GNR uncore support */ + +#define UNCORE_GNR_NUM_UNCORE_TYPES 23 +#define UNCORE_GNR_TYPE_15 15 +#define UNCORE_GNR_B2UPI 18 +#define UNCORE_GNR_TYPE_21 21 +#define UNCORE_GNR_TYPE_22 22 + +int gnr_uncore_units_ignore[] = { + UNCORE_SPR_UPI, + UNCORE_GNR_TYPE_15, + UNCORE_GNR_B2UPI, + UNCORE_GNR_TYPE_21, + UNCORE_GNR_TYPE_22, + UNCORE_IGNORE_END +}; + +static struct intel_uncore_type gnr_uncore_ubox = { + .name = "ubox", + .attr_update = uncore_alias_groups, +}; + +static struct intel_uncore_type gnr_uncore_b2cmi = { + SPR_UNCORE_PCI_COMMON_FORMAT(), + .name = "b2cmi", +}; + +static struct intel_uncore_type gnr_uncore_b2cxl = { + SPR_UNCORE_MMIO_COMMON_FORMAT(), + .name = "b2cxl", +}; + +static struct intel_uncore_type gnr_uncore_mdf_sbo = { + .name = "mdf_sbo", + .attr_update = uncore_alias_groups, +}; + +static struct intel_uncore_type *gnr_uncores[UNCORE_GNR_NUM_UNCORE_TYPES] = { + &spr_uncore_chabox, + &spr_uncore_iio, + &spr_uncore_irp, + NULL, + &spr_uncore_pcu, + &gnr_uncore_ubox, + &spr_uncore_imc, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &gnr_uncore_b2cmi, + &gnr_uncore_b2cxl, + NULL, + NULL, + &gnr_uncore_mdf_sbo, + NULL, + NULL, +}; + +static struct freerunning_counters gnr_iio_freerunning[] = { + [SPR_IIO_MSR_IOCLK] = { 0x290e, 0x01, 0x10, 1, 48 }, + [SPR_IIO_MSR_BW_IN] = { 0x360e, 0x10, 0x80, 8, 48 }, + [SPR_IIO_MSR_BW_OUT] = { 0x2e0e, 0x10, 0x80, 8, 48 }, +}; + +void gnr_uncore_cpu_init(void) +{ + uncore_msr_uncores = uncore_get_uncores(UNCORE_ACCESS_MSR, + UNCORE_SPR_MSR_EXTRA_UNCORES, + spr_msr_uncores, + UNCORE_GNR_NUM_UNCORE_TYPES, + gnr_uncores); + spr_uncore_iio_free_running.num_boxes = uncore_type_max_boxes(uncore_msr_uncores, UNCORE_SPR_IIO); + spr_uncore_iio_free_running.freerunning = gnr_iio_freerunning; +} + +int gnr_uncore_pci_init(void) +{ + uncore_pci_uncores = uncore_get_uncores(UNCORE_ACCESS_PCI, 0, NULL, + UNCORE_GNR_NUM_UNCORE_TYPES, + gnr_uncores); + return 0; +} + +void gnr_uncore_mmio_init(void) +{ + uncore_mmio_uncores = uncore_get_uncores(UNCORE_ACCESS_MMIO, 0, NULL, + UNCORE_GNR_NUM_UNCORE_TYPES, + gnr_uncores); +} + +/* end of GNR uncore support */ diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h index 53dd5d495ba6c7..fb56518356ecfb 100644 --- a/arch/x86/events/perf_event.h +++ b/arch/x86/events/perf_event.h @@ -110,6 +110,11 @@ static inline bool is_topdown_event(struct perf_event *event) return is_metric_event(event) || is_slots_event(event); } +static inline bool is_branch_counters_group(struct perf_event *event) +{ + return event->group_leader->hw.flags & PERF_X86_EVENT_BRANCH_COUNTERS; +} + struct amd_nb { int nb_id; /* NorthBridge id */ int refcnt; /* reference count */ @@ -283,6 +288,7 @@ struct cpu_hw_events { int lbr_pebs_users; struct perf_branch_stack lbr_stack; struct perf_branch_entry lbr_entries[MAX_LBR_ENTRIES]; + u64 lbr_counters[MAX_LBR_ENTRIES]; /* branch stack extra */ union { struct er_account *lbr_sel; struct er_account *lbr_ctl; @@ -888,6 +894,7 @@ struct x86_pmu { unsigned int lbr_mispred:1; unsigned int lbr_timed_lbr:1; unsigned int lbr_br_type:1; + unsigned int lbr_counters:4; void (*lbr_reset)(void); void (*lbr_read)(struct cpu_hw_events *cpuc); @@ -1012,6 +1019,7 @@ do { \ #define PMU_FL_INSTR_LATENCY 0x80 /* Support Instruction Latency in PEBS Memory Info Record */ #define PMU_FL_MEM_LOADS_AUX 0x100 /* Require an auxiliary event for the complete memory info */ #define PMU_FL_RETIRE_LATENCY 0x200 /* Support Retire Latency in PEBS */ +#define PMU_FL_BR_CNTR 0x400 /* Support branch counter logging */ #define EVENT_VAR(_id) event_attr_##_id #define EVENT_PTR(_id) &event_attr_##_id.attr.attr @@ -1552,6 +1560,10 @@ void intel_pmu_store_pebs_lbrs(struct lbr_entry *lbr); void intel_ds_init(void); +void intel_pmu_lbr_save_brstack(struct perf_sample_data *data, + struct cpu_hw_events *cpuc, + struct perf_event *event); + void intel_pmu_lbr_swap_task_ctx(struct perf_event_pmu_context *prev_epc, struct perf_event_pmu_context *next_epc); diff --git a/arch/x86/events/perf_event_flags.h b/arch/x86/events/perf_event_flags.h index 1dc19b9b4426ab..6c977c19f2cd7b 100644 --- a/arch/x86/events/perf_event_flags.h +++ b/arch/x86/events/perf_event_flags.h @@ -20,3 +20,5 @@ PERF_ARCH(TOPDOWN, 0x04000) /* Count Topdown slots/metrics events */ PERF_ARCH(PEBS_STLAT, 0x08000) /* st+stlat data address sampling */ PERF_ARCH(AMD_BRS, 0x10000) /* AMD Branch Sampling */ PERF_ARCH(PEBS_LAT_HYBRID, 0x20000) /* ld and st lat for hybrid */ +PERF_ARCH(NEEDS_BRANCH_STACK, 0x40000) /* require branch stack setup */ +PERF_ARCH(BRANCH_COUNTERS, 0x80000) /* logs the counters in the extra space of each branch */ diff --git a/arch/x86/hyperv/hv_apic.c b/arch/x86/hyperv/hv_apic.c index 97bfe5f0531f39..5fc45543e95502 100644 --- a/arch/x86/hyperv/hv_apic.c +++ b/arch/x86/hyperv/hv_apic.c @@ -209,7 +209,7 @@ static bool __send_ipi_mask(const struct cpumask *mask, int vector, /* * This particular version of the IPI hypercall can - * only target upto 64 CPUs. + * only target up to 64 CPUs. */ if (vcpu >= 64) goto do_ex_hypercall; diff --git a/arch/x86/hyperv/irqdomain.c b/arch/x86/hyperv/irqdomain.c index 42c70d28ef272d..3215a4a07408a8 100644 --- a/arch/x86/hyperv/irqdomain.c +++ b/arch/x86/hyperv/irqdomain.c @@ -212,7 +212,7 @@ static void hv_irq_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) * This interrupt is already mapped. Let's unmap first. * * We don't use retarget interrupt hypercalls here because - * Microsoft Hypervisor doens't allow root to change the vector + * Microsoft Hypervisor doesn't allow root to change the vector * or specify VPs outside of the set that is initially used * during mapping. */ diff --git a/arch/x86/hyperv/ivm.c b/arch/x86/hyperv/ivm.c index 02e55237d919af..7dcbf153ad7257 100644 --- a/arch/x86/hyperv/ivm.c +++ b/arch/x86/hyperv/ivm.c @@ -144,7 +144,7 @@ void __noreturn hv_ghcb_terminate(unsigned int set, unsigned int reason) /* Tell the hypervisor what went wrong. */ val |= GHCB_SEV_TERM_REASON(set, reason); - /* Request Guest Termination from Hypvervisor */ + /* Request Guest Termination from Hypervisor */ wr_ghcb_msr(val); VMGEXIT(); diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h index 65f79092c9d9e1..fcd20c6dc7f90c 100644 --- a/arch/x86/include/asm/alternative.h +++ b/arch/x86/include/asm/alternative.h @@ -10,6 +10,9 @@ #define ALT_FLAG_NOT (1 << 0) #define ALT_NOT(feature) ((ALT_FLAG_NOT << ALT_FLAGS_SHIFT) | (feature)) +#define ALT_FLAG_DIRECT_CALL (1 << 1) +#define ALT_DIRECT_CALL(feature) ((ALT_FLAG_DIRECT_CALL << ALT_FLAGS_SHIFT) | (feature)) +#define ALT_CALL_ALWAYS ALT_DIRECT_CALL(X86_FEATURE_ALWAYS) #ifndef __ASSEMBLY__ @@ -86,6 +89,8 @@ struct alt_instr { u8 replacementlen; /* length of new instruction */ } __packed; +extern struct alt_instr __alt_instructions[], __alt_instructions_end[]; + /* * Debug flag that can be tested to see whether alternative * instructions were patched in already: @@ -101,11 +106,10 @@ extern void apply_fineibt(s32 *start_retpoline, s32 *end_retpoine, s32 *start_cfi, s32 *end_cfi); struct module; -struct paravirt_patch_site; struct callthunk_sites { s32 *call_start, *call_end; - struct paravirt_patch_site *pv_start, *pv_end; + struct alt_instr *alt_start, *alt_end; }; #ifdef CONFIG_CALL_THUNKS @@ -150,6 +154,8 @@ static inline int alternatives_text_reserved(void *start, void *end) } #endif /* CONFIG_SMP */ +#define ALT_CALL_INSTR "call BUG_func" + #define b_replacement(num) "664"#num #define e_replacement(num) "665"#num @@ -330,6 +336,22 @@ static inline int alternatives_text_reserved(void *start, void *end) */ #define ASM_NO_INPUT_CLOBBER(clbr...) "i" (0) : clbr +/* Macro for creating assembler functions avoiding any C magic. */ +#define DEFINE_ASM_FUNC(func, instr, sec) \ + asm (".pushsection " #sec ", \"ax\"\n" \ + ".global " #func "\n\t" \ + ".type " #func ", @function\n\t" \ + ASM_FUNC_ALIGN "\n" \ + #func ":\n\t" \ + ASM_ENDBR \ + instr "\n\t" \ + ASM_RET \ + ".size " #func ", . - " #func "\n\t" \ + ".popsection") + +void BUG_func(void); +void nop_func(void); + #else /* __ASSEMBLY__ */ #ifdef CONFIG_SMP @@ -370,6 +392,10 @@ static inline int alternatives_text_reserved(void *start, void *end) .byte \alt_len .endm +.macro ALT_CALL_INSTR + call BUG_func +.endm + /* * Define an alternative between two instructions. If @feature is * present, early code in apply_alternatives() replaces @oldinstr with diff --git a/arch/x86/include/asm/amd_nb.h b/arch/x86/include/asm/amd_nb.h index ed0eaf65c43721..5c37944c8a5eec 100644 --- a/arch/x86/include/asm/amd_nb.h +++ b/arch/x86/include/asm/amd_nb.h @@ -104,7 +104,7 @@ static inline bool amd_gart_present(void) if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) return false; - /* GART present only on Fam15h, upto model 0fh */ + /* GART present only on Fam15h, up to model 0fh */ if (boot_cpu_data.x86 == 0xf || boot_cpu_data.x86 == 0x10 || (boot_cpu_data.x86 == 0x15 && boot_cpu_data.x86_model < 0x10)) return true; diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h index d21f48f1c242e0..9d159b771dc814 100644 --- a/arch/x86/include/asm/apic.h +++ b/arch/x86/include/asm/apic.h @@ -272,8 +272,6 @@ struct apic { void (*send_IPI_all)(int vector); void (*send_IPI_self)(int vector); - enum apic_delivery_modes delivery_mode; - u32 disable_esr : 1, dest_mode_logical : 1, x2apic_set_max_apicid : 1, diff --git a/arch/x86/include/asm/apicdef.h b/arch/x86/include/asm/apicdef.h index 4b125e5b31873a..094106b6a5384f 100644 --- a/arch/x86/include/asm/apicdef.h +++ b/arch/x86/include/asm/apicdef.h @@ -20,6 +20,13 @@ */ #define IO_APIC_SLOT_SIZE 1024 +#define APIC_DELIVERY_MODE_FIXED 0 +#define APIC_DELIVERY_MODE_LOWESTPRIO 1 +#define APIC_DELIVERY_MODE_SMI 2 +#define APIC_DELIVERY_MODE_NMI 4 +#define APIC_DELIVERY_MODE_INIT 5 +#define APIC_DELIVERY_MODE_EXTINT 7 + #define APIC_ID 0x20 #define APIC_LVR 0x30 @@ -165,279 +172,10 @@ #define APIC_CPUID(apicid) ((apicid) & XAPIC_DEST_CPUS_MASK) #define NUM_APIC_CLUSTERS ((BAD_APICID + 1) >> XAPIC_DEST_CPUS_SHIFT) -#ifndef __ASSEMBLY__ -/* - * the local APIC register structure, memory mapped. Not terribly well - * tested, but we might eventually use this one in the future - the - * problem why we cannot use it right now is the P5 APIC, it has an - * errata which cannot take 8-bit reads and writes, only 32-bit ones ... - */ -#define u32 unsigned int - -struct local_apic { - -/*000*/ struct { u32 __reserved[4]; } __reserved_01; - -/*010*/ struct { u32 __reserved[4]; } __reserved_02; - -/*020*/ struct { /* APIC ID Register */ - u32 __reserved_1 : 24, - phys_apic_id : 4, - __reserved_2 : 4; - u32 __reserved[3]; - } id; - -/*030*/ const - struct { /* APIC Version Register */ - u32 version : 8, - __reserved_1 : 8, - max_lvt : 8, - __reserved_2 : 8; - u32 __reserved[3]; - } version; - -/*040*/ struct { u32 __reserved[4]; } __reserved_03; - -/*050*/ struct { u32 __reserved[4]; } __reserved_04; - -/*060*/ struct { u32 __reserved[4]; } __reserved_05; - -/*070*/ struct { u32 __reserved[4]; } __reserved_06; - -/*080*/ struct { /* Task Priority Register */ - u32 priority : 8, - __reserved_1 : 24; - u32 __reserved_2[3]; - } tpr; - -/*090*/ const - struct { /* Arbitration Priority Register */ - u32 priority : 8, - __reserved_1 : 24; - u32 __reserved_2[3]; - } apr; - -/*0A0*/ const - struct { /* Processor Priority Register */ - u32 priority : 8, - __reserved_1 : 24; - u32 __reserved_2[3]; - } ppr; - -/*0B0*/ struct { /* End Of Interrupt Register */ - u32 eoi; - u32 __reserved[3]; - } eoi; - -/*0C0*/ struct { u32 __reserved[4]; } __reserved_07; - -/*0D0*/ struct { /* Logical Destination Register */ - u32 __reserved_1 : 24, - logical_dest : 8; - u32 __reserved_2[3]; - } ldr; - -/*0E0*/ struct { /* Destination Format Register */ - u32 __reserved_1 : 28, - model : 4; - u32 __reserved_2[3]; - } dfr; - -/*0F0*/ struct { /* Spurious Interrupt Vector Register */ - u32 spurious_vector : 8, - apic_enabled : 1, - focus_cpu : 1, - __reserved_2 : 22; - u32 __reserved_3[3]; - } svr; - -/*100*/ struct { /* In Service Register */ -/*170*/ u32 bitfield; - u32 __reserved[3]; - } isr [8]; - -/*180*/ struct { /* Trigger Mode Register */ -/*1F0*/ u32 bitfield; - u32 __reserved[3]; - } tmr [8]; - -/*200*/ struct { /* Interrupt Request Register */ -/*270*/ u32 bitfield; - u32 __reserved[3]; - } irr [8]; - -/*280*/ union { /* Error Status Register */ - struct { - u32 send_cs_error : 1, - receive_cs_error : 1, - send_accept_error : 1, - receive_accept_error : 1, - __reserved_1 : 1, - send_illegal_vector : 1, - receive_illegal_vector : 1, - illegal_register_address : 1, - __reserved_2 : 24; - u32 __reserved_3[3]; - } error_bits; - struct { - u32 errors; - u32 __reserved_3[3]; - } all_errors; - } esr; - -/*290*/ struct { u32 __reserved[4]; } __reserved_08; - -/*2A0*/ struct { u32 __reserved[4]; } __reserved_09; - -/*2B0*/ struct { u32 __reserved[4]; } __reserved_10; - -/*2C0*/ struct { u32 __reserved[4]; } __reserved_11; - -/*2D0*/ struct { u32 __reserved[4]; } __reserved_12; - -/*2E0*/ struct { u32 __reserved[4]; } __reserved_13; - -/*2F0*/ struct { u32 __reserved[4]; } __reserved_14; - -/*300*/ struct { /* Interrupt Command Register 1 */ - u32 vector : 8, - delivery_mode : 3, - destination_mode : 1, - delivery_status : 1, - __reserved_1 : 1, - level : 1, - trigger : 1, - __reserved_2 : 2, - shorthand : 2, - __reserved_3 : 12; - u32 __reserved_4[3]; - } icr1; - -/*310*/ struct { /* Interrupt Command Register 2 */ - union { - u32 __reserved_1 : 24, - phys_dest : 4, - __reserved_2 : 4; - u32 __reserved_3 : 24, - logical_dest : 8; - } dest; - u32 __reserved_4[3]; - } icr2; - -/*320*/ struct { /* LVT - Timer */ - u32 vector : 8, - __reserved_1 : 4, - delivery_status : 1, - __reserved_2 : 3, - mask : 1, - timer_mode : 1, - __reserved_3 : 14; - u32 __reserved_4[3]; - } lvt_timer; - -/*330*/ struct { /* LVT - Thermal Sensor */ - u32 vector : 8, - delivery_mode : 3, - __reserved_1 : 1, - delivery_status : 1, - __reserved_2 : 3, - mask : 1, - __reserved_3 : 15; - u32 __reserved_4[3]; - } lvt_thermal; - -/*340*/ struct { /* LVT - Performance Counter */ - u32 vector : 8, - delivery_mode : 3, - __reserved_1 : 1, - delivery_status : 1, - __reserved_2 : 3, - mask : 1, - __reserved_3 : 15; - u32 __reserved_4[3]; - } lvt_pc; - -/*350*/ struct { /* LVT - LINT0 */ - u32 vector : 8, - delivery_mode : 3, - __reserved_1 : 1, - delivery_status : 1, - polarity : 1, - remote_irr : 1, - trigger : 1, - mask : 1, - __reserved_2 : 15; - u32 __reserved_3[3]; - } lvt_lint0; - -/*360*/ struct { /* LVT - LINT1 */ - u32 vector : 8, - delivery_mode : 3, - __reserved_1 : 1, - delivery_status : 1, - polarity : 1, - remote_irr : 1, - trigger : 1, - mask : 1, - __reserved_2 : 15; - u32 __reserved_3[3]; - } lvt_lint1; - -/*370*/ struct { /* LVT - Error */ - u32 vector : 8, - __reserved_1 : 4, - delivery_status : 1, - __reserved_2 : 3, - mask : 1, - __reserved_3 : 15; - u32 __reserved_4[3]; - } lvt_error; - -/*380*/ struct { /* Timer Initial Count Register */ - u32 initial_count; - u32 __reserved_2[3]; - } timer_icr; - -/*390*/ const - struct { /* Timer Current Count Register */ - u32 curr_count; - u32 __reserved_2[3]; - } timer_ccr; - -/*3A0*/ struct { u32 __reserved[4]; } __reserved_16; - -/*3B0*/ struct { u32 __reserved[4]; } __reserved_17; - -/*3C0*/ struct { u32 __reserved[4]; } __reserved_18; - -/*3D0*/ struct { u32 __reserved[4]; } __reserved_19; - -/*3E0*/ struct { /* Timer Divide Configuration Register */ - u32 divisor : 4, - __reserved_1 : 28; - u32 __reserved_2[3]; - } timer_dcr; - -/*3F0*/ struct { u32 __reserved[4]; } __reserved_20; - -} __attribute__ ((packed)); - -#undef u32 - #ifdef CONFIG_X86_32 #define BAD_APICID 0xFFu #else #define BAD_APICID 0xFFFFu #endif -enum apic_delivery_modes { - APIC_DELIVERY_MODE_FIXED = 0, - APIC_DELIVERY_MODE_LOWESTPRIO = 1, - APIC_DELIVERY_MODE_SMI = 2, - APIC_DELIVERY_MODE_NMI = 4, - APIC_DELIVERY_MODE_INIT = 5, - APIC_DELIVERY_MODE_EXTINT = 7, -}; - -#endif /* !__ASSEMBLY__ */ #endif /* _ASM_X86_APICDEF_H */ diff --git a/arch/x86/include/asm/barrier.h b/arch/x86/include/asm/barrier.h index 35389b2af88ee8..0216f63a366b54 100644 --- a/arch/x86/include/asm/barrier.h +++ b/arch/x86/include/asm/barrier.h @@ -81,22 +81,4 @@ do { \ #include -/* - * Make previous memory operations globally visible before - * a WRMSR. - * - * MFENCE makes writes visible, but only affects load/store - * instructions. WRMSR is unfortunately not a load/store - * instruction and is unaffected by MFENCE. The LFENCE ensures - * that the WRMSR is not reordered. - * - * Most WRMSRs are full serializing instructions themselves and - * do not require this barrier. This is only required for the - * IA32_TSC_DEADLINE and X2APIC MSRs. - */ -static inline void weak_wrmsr_fence(void) -{ - asm volatile("mfence; lfence" : : : "memory"); -} - #endif /* _ASM_X86_BARRIER_H */ diff --git a/arch/x86/include/asm/cfi.h b/arch/x86/include/asm/cfi.h index 58dacd90daefc4..7cd7525579051d 100644 --- a/arch/x86/include/asm/cfi.h +++ b/arch/x86/include/asm/cfi.h @@ -7,16 +7,140 @@ * * Copyright (C) 2022 Google LLC */ +#include +#include -#include +/* + * An overview of the various calling conventions... + * + * Traditional: + * + * foo: + * ... code here ... + * ret + * + * direct caller: + * call foo + * + * indirect caller: + * lea foo(%rip), %r11 + * ... + * call *%r11 + * + * + * IBT: + * + * foo: + * endbr64 + * ... code here ... + * ret + * + * direct caller: + * call foo / call foo+4 + * + * indirect caller: + * lea foo(%rip), %r11 + * ... + * call *%r11 + * + * + * kCFI: + * + * __cfi_foo: + * movl $0x12345678, %eax + * # 11 nops when CONFIG_CALL_PADDING + * foo: + * endbr64 # when IBT + * ... code here ... + * ret + * + * direct call: + * call foo # / call foo+4 when IBT + * + * indirect call: + * lea foo(%rip), %r11 + * ... + * movl $(-0x12345678), %r10d + * addl -4(%r11), %r10d # -15 when CONFIG_CALL_PADDING + * jz 1f + * ud2 + * 1:call *%r11 + * + * + * FineIBT (builds as kCFI + CALL_PADDING + IBT + RETPOLINE and runtime patches into): + * + * __cfi_foo: + * endbr64 + * subl 0x12345678, %r10d + * jz foo + * ud2 + * nop + * foo: + * osp nop3 # was endbr64 + * ... code here ... + * ret + * + * direct caller: + * call foo / call foo+4 + * + * indirect caller: + * lea foo(%rip), %r11 + * ... + * movl $0x12345678, %r10d + * subl $16, %r11 + * nop4 + * call *%r11 + * + */ +enum cfi_mode { + CFI_DEFAULT, /* FineIBT if hardware has IBT, otherwise kCFI */ + CFI_OFF, /* Taditional / IBT depending on .config */ + CFI_KCFI, /* Optionally CALL_PADDING, IBT, RETPOLINE */ + CFI_FINEIBT, /* see arch/x86/kernel/alternative.c */ +}; + +extern enum cfi_mode cfi_mode; + +struct pt_regs; #ifdef CONFIG_CFI_CLANG enum bug_trap_type handle_cfi_failure(struct pt_regs *regs); +#define __bpfcall +extern u32 cfi_bpf_hash; +extern u32 cfi_bpf_subprog_hash; + +static inline int cfi_get_offset(void) +{ + switch (cfi_mode) { + case CFI_FINEIBT: + return 16; + case CFI_KCFI: + if (IS_ENABLED(CONFIG_CALL_PADDING)) + return 16; + return 5; + default: + return 0; + } +} +#define cfi_get_offset cfi_get_offset + +extern u32 cfi_get_func_hash(void *func); + #else static inline enum bug_trap_type handle_cfi_failure(struct pt_regs *regs) { return BUG_TRAP_TYPE_NONE; } +#define cfi_bpf_hash 0U +#define cfi_bpf_subprog_hash 0U +static inline u32 cfi_get_func_hash(void *func) +{ + return 0; +} #endif /* CONFIG_CFI_CLANG */ +#if HAS_KERNEL_IBT == 1 +#define CFI_NOSEAL(x) asm(IBT_NOSEAL(__stringify(x))) +#endif + #endif /* _ASM_X86_CFI_H */ diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index fecc4fe1d68aff..f8f9a9b7939587 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h @@ -23,10 +23,6 @@ static inline void prefill_possible_map(void) {} #endif /* CONFIG_SMP */ -struct x86_cpu { - struct cpu cpu; -}; - #ifdef CONFIG_HOTPLUG_CPU extern void soft_restart_cpu(void); #endif diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index 4af140cf5719e6..fdf723b6f6d0ce 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -81,10 +81,8 @@ #define X86_FEATURE_K6_MTRR ( 3*32+ 1) /* AMD K6 nonstandard MTRRs */ #define X86_FEATURE_CYRIX_ARR ( 3*32+ 2) /* Cyrix ARRs (= MTRRs) */ #define X86_FEATURE_CENTAUR_MCR ( 3*32+ 3) /* Centaur MCRs (= MTRRs) */ - -/* CPU types for specific tunings: */ #define X86_FEATURE_K8 ( 3*32+ 4) /* "" Opteron, Athlon64 */ -/* FREE, was #define X86_FEATURE_K7 ( 3*32+ 5) "" Athlon */ +#define X86_FEATURE_ZEN5 ( 3*32+ 5) /* "" CPU based on Zen5 microarchitecture */ #define X86_FEATURE_P3 ( 3*32+ 6) /* "" P3 */ #define X86_FEATURE_P4 ( 3*32+ 7) /* "" P4 */ #define X86_FEATURE_CONSTANT_TSC ( 3*32+ 8) /* TSC ticks at a constant rate */ @@ -198,6 +196,7 @@ #define X86_FEATURE_CAT_L3 ( 7*32+ 4) /* Cache Allocation Technology L3 */ #define X86_FEATURE_CAT_L2 ( 7*32+ 5) /* Cache Allocation Technology L2 */ #define X86_FEATURE_CDP_L3 ( 7*32+ 6) /* Code and Data Prioritization L3 */ +#define X86_FEATURE_TDX_HOST_PLATFORM ( 7*32+ 7) /* Platform supports being a TDX host */ #define X86_FEATURE_HW_PSTATE ( 7*32+ 8) /* AMD HW-PState */ #define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */ #define X86_FEATURE_XCOMPACTED ( 7*32+10) /* "" Use compacted XSTATE (XSAVES or XSAVEC) */ @@ -218,7 +217,7 @@ #define X86_FEATURE_IBRS ( 7*32+25) /* Indirect Branch Restricted Speculation */ #define X86_FEATURE_IBPB ( 7*32+26) /* Indirect Branch Prediction Barrier */ #define X86_FEATURE_STIBP ( 7*32+27) /* Single Thread Indirect Branch Predictors */ -#define X86_FEATURE_ZEN (7*32+28) /* "" CPU based on Zen microarchitecture */ +#define X86_FEATURE_ZEN ( 7*32+28) /* "" Generic flag for all Zen and newer */ #define X86_FEATURE_L1TF_PTEINV ( 7*32+29) /* "" L1TF workaround PTE inversion */ #define X86_FEATURE_IBRS_ENHANCED ( 7*32+30) /* Enhanced IBRS */ #define X86_FEATURE_MSR_IA32_FEAT_CTL ( 7*32+31) /* "" MSR IA32_FEAT_CTL configured */ @@ -308,10 +307,14 @@ #define X86_FEATURE_SMBA (11*32+21) /* "" Slow Memory Bandwidth Allocation */ #define X86_FEATURE_BMEC (11*32+22) /* "" Bandwidth Monitoring Event Configuration */ #define X86_FEATURE_USER_SHSTK (11*32+23) /* Shadow stack support for user mode applications */ - #define X86_FEATURE_SRSO (11*32+24) /* "" AMD BTB untrain RETs */ #define X86_FEATURE_SRSO_ALIAS (11*32+25) /* "" AMD BTB untrain RETs through aliasing */ #define X86_FEATURE_IBPB_ON_VMEXIT (11*32+26) /* "" Issue an IBPB only on VMEXIT */ +#define X86_FEATURE_APIC_MSRS_FENCE (11*32+27) /* "" IA32_TSC_DEADLINE and X2APIC MSRs need fencing */ +#define X86_FEATURE_ZEN2 (11*32+28) /* "" CPU based on Zen2 microarchitecture */ +#define X86_FEATURE_ZEN3 (11*32+29) /* "" CPU based on Zen3 microarchitecture */ +#define X86_FEATURE_ZEN4 (11*32+30) /* "" CPU based on Zen4 microarchitecture */ +#define X86_FEATURE_ZEN1 (11*32+31) /* "" CPU based on Zen1 microarchitecture */ /* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */ #define X86_FEATURE_AVX_VNNI (12*32+ 4) /* AVX VNNI instructions */ @@ -495,6 +498,7 @@ #define X86_BUG_EIBRS_PBRSB X86_BUG(28) /* EIBRS is vulnerable to Post Barrier RSB Predictions */ #define X86_BUG_SMT_RSB X86_BUG(29) /* CPU is vulnerable to Cross-Thread Return Address Predictions */ #define X86_BUG_GDS X86_BUG(30) /* CPU is affected by Gather Data Sampling */ +#define X86_BUG_TDX_PW_MCE X86_BUG(31) /* CPU may incur #MC if non-TD software does partial write to TDX private memory */ /* BUG word 2 */ #define X86_BUG_SRSO X86_BUG(1*32 + 0) /* AMD SRSO bug */ diff --git a/arch/x86/include/asm/current.h b/arch/x86/include/asm/current.h index a1168e7b69e5b7..dd4b67101bb7ed 100644 --- a/arch/x86/include/asm/current.h +++ b/arch/x86/include/asm/current.h @@ -2,6 +2,7 @@ #ifndef _ASM_X86_CURRENT_H #define _ASM_X86_CURRENT_H +#include #include #ifndef __ASSEMBLY__ diff --git a/arch/x86/include/asm/debugreg.h b/arch/x86/include/asm/debugreg.h index 66eb5e1ac4fb93..0cec92c430cc9d 100644 --- a/arch/x86/include/asm/debugreg.h +++ b/arch/x86/include/asm/debugreg.h @@ -5,6 +5,7 @@ #include #include #include +#include DECLARE_PER_CPU(unsigned long, cpu_dr7); diff --git a/arch/x86/include/asm/desc_defs.h b/arch/x86/include/asm/desc_defs.h index f7e7099af595c9..d440a65af8f394 100644 --- a/arch/x86/include/asm/desc_defs.h +++ b/arch/x86/include/asm/desc_defs.h @@ -8,6 +8,56 @@ * archs. */ +/* + * Low-level interface mapping flags/field names to bits + */ + +/* Flags for _DESC_S (non-system) descriptors */ +#define _DESC_ACCESSED 0x0001 +#define _DESC_DATA_WRITABLE 0x0002 +#define _DESC_CODE_READABLE 0x0002 +#define _DESC_DATA_EXPAND_DOWN 0x0004 +#define _DESC_CODE_CONFORMING 0x0004 +#define _DESC_CODE_EXECUTABLE 0x0008 + +/* Common flags */ +#define _DESC_S 0x0010 +#define _DESC_DPL(dpl) ((dpl) << 5) +#define _DESC_PRESENT 0x0080 + +#define _DESC_LONG_CODE 0x2000 +#define _DESC_DB 0x4000 +#define _DESC_GRANULARITY_4K 0x8000 + +/* System descriptors have a numeric "type" field instead of flags */ +#define _DESC_SYSTEM(code) (code) + +/* + * High-level interface mapping intended usage to low-level combinations + * of flags + */ + +#define _DESC_DATA (_DESC_S | _DESC_PRESENT | _DESC_ACCESSED | \ + _DESC_DATA_WRITABLE) +#define _DESC_CODE (_DESC_S | _DESC_PRESENT | _DESC_ACCESSED | \ + _DESC_CODE_READABLE | _DESC_CODE_EXECUTABLE) + +#define DESC_DATA16 (_DESC_DATA) +#define DESC_CODE16 (_DESC_CODE) + +#define DESC_DATA32 (_DESC_DATA | _DESC_GRANULARITY_4K | _DESC_DB) +#define DESC_DATA32_BIOS (_DESC_DATA | _DESC_DB) + +#define DESC_CODE32 (_DESC_CODE | _DESC_GRANULARITY_4K | _DESC_DB) +#define DESC_CODE32_BIOS (_DESC_CODE | _DESC_DB) + +#define DESC_TSS32 (_DESC_SYSTEM(9) | _DESC_PRESENT) + +#define DESC_DATA64 (_DESC_DATA | _DESC_GRANULARITY_4K | _DESC_DB) +#define DESC_CODE64 (_DESC_CODE | _DESC_GRANULARITY_4K | _DESC_LONG_CODE) + +#define DESC_USER (_DESC_DPL(3)) + #ifndef __ASSEMBLY__ #include @@ -22,19 +72,19 @@ struct desc_struct { #define GDT_ENTRY_INIT(flags, base, limit) \ { \ - .limit0 = (u16) (limit), \ - .limit1 = ((limit) >> 16) & 0x0F, \ - .base0 = (u16) (base), \ - .base1 = ((base) >> 16) & 0xFF, \ - .base2 = ((base) >> 24) & 0xFF, \ - .type = (flags & 0x0f), \ - .s = (flags >> 4) & 0x01, \ - .dpl = (flags >> 5) & 0x03, \ - .p = (flags >> 7) & 0x01, \ - .avl = (flags >> 12) & 0x01, \ - .l = (flags >> 13) & 0x01, \ - .d = (flags >> 14) & 0x01, \ - .g = (flags >> 15) & 0x01, \ + .limit0 = ((limit) >> 0) & 0xFFFF, \ + .limit1 = ((limit) >> 16) & 0x000F, \ + .base0 = ((base) >> 0) & 0xFFFF, \ + .base1 = ((base) >> 16) & 0x00FF, \ + .base2 = ((base) >> 24) & 0x00FF, \ + .type = ((flags) >> 0) & 0x000F, \ + .s = ((flags) >> 4) & 0x0001, \ + .dpl = ((flags) >> 5) & 0x0003, \ + .p = ((flags) >> 7) & 0x0001, \ + .avl = ((flags) >> 12) & 0x0001, \ + .l = ((flags) >> 13) & 0x0001, \ + .d = ((flags) >> 14) & 0x0001, \ + .g = ((flags) >> 15) & 0x0001, \ } enum { @@ -94,6 +144,7 @@ struct gate_struct { typedef struct gate_struct gate_desc; +#ifndef _SETUP static inline unsigned long gate_offset(const gate_desc *g) { #ifdef CONFIG_X86_64 @@ -108,6 +159,7 @@ static inline unsigned long gate_segment(const gate_desc *g) { return g->segment; } +#endif struct desc_ptr { unsigned short size; diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h index a0234dfd103176..1e16bd5ac781d8 100644 --- a/arch/x86/include/asm/elf.h +++ b/arch/x86/include/asm/elf.h @@ -150,7 +150,7 @@ do { \ ((x)->e_machine == EM_X86_64) #define compat_elf_check_arch(x) \ - ((elf_check_arch_ia32(x) && ia32_enabled()) || \ + ((elf_check_arch_ia32(x) && ia32_enabled_verbose()) || \ (IS_ENABLED(CONFIG_X86_X32_ABI) && (x)->e_machine == EM_X86_64)) static inline void elf_common_init(struct thread_struct *t, diff --git a/arch/x86/include/asm/extable_fixup_types.h b/arch/x86/include/asm/extable_fixup_types.h index 991e31cfde94cc..fe6312045042f8 100644 --- a/arch/x86/include/asm/extable_fixup_types.h +++ b/arch/x86/include/asm/extable_fixup_types.h @@ -4,7 +4,7 @@ /* * Our IMM is signed, as such it must live at the top end of the word. Also, - * since C99 hex constants are of ambigious type, force cast the mask to 'int' + * since C99 hex constants are of ambiguous type, force cast the mask to 'int' * so that FIELD_GET() will DTRT and sign extend the value when it extracts it. */ #define EX_DATA_TYPE_MASK ((int)0x000000FF) diff --git a/arch/x86/include/asm/fpu/types.h b/arch/x86/include/asm/fpu/types.h index eb810074f1e745..ace9aa3b78a305 100644 --- a/arch/x86/include/asm/fpu/types.h +++ b/arch/x86/include/asm/fpu/types.h @@ -5,6 +5,8 @@ #ifndef _ASM_X86_FPU_H #define _ASM_X86_FPU_H +#include + /* * The legacy x87 FPU state format, as saved by FSAVE and * restored by the FRSTOR instructions: @@ -415,7 +417,7 @@ struct fpu_state_perm { * * This master permission field is only to be used when * task.fpu.fpstate based checks fail to validate whether the task - * is allowed to expand it's xfeatures set which requires to + * is allowed to expand its xfeatures set which requires to * allocate a larger sized fpstate buffer. * * Do not access this field directly. Use the provided helper diff --git a/arch/x86/include/asm/ia32.h b/arch/x86/include/asm/ia32.h index 9805629479d968..c7ef6ea2fa993c 100644 --- a/arch/x86/include/asm/ia32.h +++ b/arch/x86/include/asm/ia32.h @@ -2,7 +2,6 @@ #ifndef _ASM_X86_IA32_H #define _ASM_X86_IA32_H - #ifdef CONFIG_IA32_EMULATION #include @@ -91,4 +90,14 @@ static inline void ia32_disable(void) {} #endif +static inline bool ia32_enabled_verbose(void) +{ + bool enabled = ia32_enabled(); + + if (IS_ENABLED(CONFIG_IA32_EMULATION) && !enabled) + pr_notice_once("32-bit emulation disabled. You can reenable with ia32_emulation=on\n"); + + return enabled; +} + #endif /* _ASM_X86_IA32_H */ diff --git a/arch/x86/include/asm/intel-family.h b/arch/x86/include/asm/intel-family.h index 197316121f04e1..b65e9c46b92210 100644 --- a/arch/x86/include/asm/intel-family.h +++ b/arch/x86/include/asm/intel-family.h @@ -162,6 +162,8 @@ #define INTEL_FAM6_ATOM_CRESTMONT_X 0xAF /* Sierra Forest */ #define INTEL_FAM6_ATOM_CRESTMONT 0xB6 /* Grand Ridge */ +#define INTEL_FAM6_ATOM_DARKMONT_X 0xDD /* Clearwater Forest */ + /* Xeon Phi */ #define INTEL_FAM6_XEON_PHI_KNL 0x57 /* Knights Landing */ diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h index 76238842406a2f..3814a9263d64ea 100644 --- a/arch/x86/include/asm/io.h +++ b/arch/x86/include/asm/io.h @@ -242,7 +242,7 @@ static inline void slow_down_io(void) #endif -#define BUILDIO(bwl, bw, type) \ +#define BUILDIO(bwl, type) \ static inline void out##bwl##_p(type value, u16 port) \ { \ out##bwl(value, port); \ @@ -288,9 +288,9 @@ static inline void ins##bwl(u16 port, void *addr, unsigned long count) \ } \ } -BUILDIO(b, b, u8) -BUILDIO(w, w, u16) -BUILDIO(l, , u32) +BUILDIO(b, u8) +BUILDIO(w, u16) +BUILDIO(l, u32) #undef BUILDIO #define inb_p inb_p diff --git a/arch/x86/include/asm/iosf_mbi.h b/arch/x86/include/asm/iosf_mbi.h index a1911fea87392e..af7541c11821ff 100644 --- a/arch/x86/include/asm/iosf_mbi.h +++ b/arch/x86/include/asm/iosf_mbi.h @@ -111,7 +111,7 @@ int iosf_mbi_modify(u8 port, u8 opcode, u32 offset, u32 mdr, u32 mask); * This function will block all kernel access to the PMIC I2C bus, so that the * P-Unit can safely access the PMIC over the shared I2C bus. * - * Note on these systems the i2c-bus driver will request a sempahore from the + * Note on these systems the i2c-bus driver will request a semaphore from the * P-Unit for exclusive access to the PMIC bus when i2c drivers are accessing * it, but this does not appear to be sufficient, we still need to avoid making * certain P-Unit requests during the access window to avoid problems. diff --git a/arch/x86/include/asm/irq_work.h b/arch/x86/include/asm/irq_work.h index 800ffce0db29e3..6b4d36c9516557 100644 --- a/arch/x86/include/asm/irq_work.h +++ b/arch/x86/include/asm/irq_work.h @@ -9,7 +9,6 @@ static inline bool arch_irq_work_has_interrupt(void) { return boot_cpu_has(X86_FEATURE_APIC); } -extern void arch_irq_work_raise(void); #else static inline bool arch_irq_work_has_interrupt(void) { diff --git a/arch/x86/include/asm/kvm-x86-ops.h b/arch/x86/include/asm/kvm-x86-ops.h index 26b628d84594b9..378ed944b849fb 100644 --- a/arch/x86/include/asm/kvm-x86-ops.h +++ b/arch/x86/include/asm/kvm-x86-ops.h @@ -55,8 +55,10 @@ KVM_X86_OP(set_rflags) KVM_X86_OP(get_if_flag) KVM_X86_OP(flush_tlb_all) KVM_X86_OP(flush_tlb_current) +#if IS_ENABLED(CONFIG_HYPERV) KVM_X86_OP_OPTIONAL(flush_remote_tlbs) KVM_X86_OP_OPTIONAL(flush_remote_tlbs_range) +#endif KVM_X86_OP(flush_tlb_gva) KVM_X86_OP(flush_tlb_guest) KVM_X86_OP(vcpu_pre_run) @@ -135,6 +137,7 @@ KVM_X86_OP(msr_filter_changed) KVM_X86_OP(complete_emulated_msr) KVM_X86_OP(vcpu_deliver_sipi_vector) KVM_X86_OP_OPTIONAL_RET0(vcpu_get_apicv_inhibit_reasons); +KVM_X86_OP_OPTIONAL(get_untagged_addr) #undef KVM_X86_OP #undef KVM_X86_OP_OPTIONAL diff --git a/arch/x86/include/asm/kvm-x86-pmu-ops.h b/arch/x86/include/asm/kvm-x86-pmu-ops.h index 6c98f4bb4228ba..058bc636356a11 100644 --- a/arch/x86/include/asm/kvm-x86-pmu-ops.h +++ b/arch/x86/include/asm/kvm-x86-pmu-ops.h @@ -22,7 +22,7 @@ KVM_X86_PMU_OP(get_msr) KVM_X86_PMU_OP(set_msr) KVM_X86_PMU_OP(refresh) KVM_X86_PMU_OP(init) -KVM_X86_PMU_OP(reset) +KVM_X86_PMU_OP_OPTIONAL(reset) KVM_X86_PMU_OP_OPTIONAL(deliver_pmi) KVM_X86_PMU_OP_OPTIONAL(cleanup) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index d7036982332e33..b5b2d0fde57968 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -133,7 +133,8 @@ | X86_CR4_PGE | X86_CR4_PCE | X86_CR4_OSFXSR | X86_CR4_PCIDE \ | X86_CR4_OSXSAVE | X86_CR4_SMEP | X86_CR4_FSGSBASE \ | X86_CR4_OSXMMEXCPT | X86_CR4_LA57 | X86_CR4_VMXE \ - | X86_CR4_SMAP | X86_CR4_PKE | X86_CR4_UMIP)) + | X86_CR4_SMAP | X86_CR4_PKE | X86_CR4_UMIP \ + | X86_CR4_LAM_SUP)) #define CR8_RESERVED_BITS (~(unsigned long)X86_CR8_TPR) @@ -500,8 +501,23 @@ struct kvm_pmc { u8 idx; bool is_paused; bool intr; + /* + * Base value of the PMC counter, relative to the *consumed* count in + * the associated perf_event. This value includes counter updates from + * the perf_event and emulated_count since the last time the counter + * was reprogrammed, but it is *not* the current value as seen by the + * guest or userspace. + * + * The count is relative to the associated perf_event so that KVM + * doesn't need to reprogram the perf_event every time the guest writes + * to the counter. + */ u64 counter; - u64 prev_counter; + /* + * PMC events triggered by KVM emulation that haven't been fully + * processed, i.e. haven't undergone overflow detection. + */ + u64 emulated_counter; u64 eventsel; struct perf_event *perf_event; struct kvm_vcpu *vcpu; @@ -937,8 +953,10 @@ struct kvm_vcpu_arch { /* used for guest single stepping over the given code position */ unsigned long singlestep_rip; +#ifdef CONFIG_KVM_HYPERV bool hyperv_enabled; struct kvm_vcpu_hv *hyperv; +#endif #ifdef CONFIG_KVM_XEN struct kvm_vcpu_xen xen; #endif @@ -1095,6 +1113,7 @@ enum hv_tsc_page_status { HV_TSC_PAGE_BROKEN, }; +#ifdef CONFIG_KVM_HYPERV /* Hyper-V emulation context */ struct kvm_hv { struct mutex hv_lock; @@ -1125,9 +1144,9 @@ struct kvm_hv { */ unsigned int synic_auto_eoi_used; - struct hv_partition_assist_pg *hv_pa_pg; struct kvm_hv_syndbg hv_syndbg; }; +#endif struct msr_bitmap_range { u32 flags; @@ -1136,6 +1155,7 @@ struct msr_bitmap_range { unsigned long *bitmap; }; +#ifdef CONFIG_KVM_XEN /* Xen emulation context */ struct kvm_xen { struct mutex xen_lock; @@ -1147,6 +1167,7 @@ struct kvm_xen { struct idr evtchn_ports; unsigned long poll_mask[BITS_TO_LONGS(KVM_MAX_VCPUS)]; }; +#endif enum kvm_irqchip_mode { KVM_IRQCHIP_NONE, @@ -1255,6 +1276,7 @@ enum kvm_apicv_inhibit { }; struct kvm_arch { + unsigned long vm_type; unsigned long n_used_mmu_pages; unsigned long n_requested_mmu_pages; unsigned long n_max_mmu_pages; @@ -1347,8 +1369,13 @@ struct kvm_arch { /* reads protected by irq_srcu, writes by irq_lock */ struct hlist_head mask_notifier_list; +#ifdef CONFIG_KVM_HYPERV struct kvm_hv hyperv; +#endif + +#ifdef CONFIG_KVM_XEN struct kvm_xen xen; +#endif bool backwards_tsc_observed; bool boot_vcpu_runs_old_kvmclock; @@ -1406,9 +1433,8 @@ struct kvm_arch { * the MMU lock in read mode + RCU or * the MMU lock in write mode * - * For writes, this list is protected by: - * the MMU lock in read mode + the tdp_mmu_pages_lock or - * the MMU lock in write mode + * For writes, this list is protected by tdp_mmu_pages_lock; see + * below for the details. * * Roots will remain in the list until their tdp_mmu_root_count * drops to zero, at which point the thread that decremented the @@ -1425,8 +1451,10 @@ struct kvm_arch { * - possible_nx_huge_pages; * - the possible_nx_huge_page_link field of kvm_mmu_page structs used * by the TDP MMU - * It is acceptable, but not necessary, to acquire this lock when - * the thread holds the MMU lock in write mode. + * Because the lock is only taken within the MMU lock, strictly + * speaking it is redundant to acquire this lock when the thread + * holds the MMU lock in write mode. However it often simplifies + * the code to do so. */ spinlock_t tdp_mmu_pages_lock; #endif /* CONFIG_X86_64 */ @@ -1441,6 +1469,7 @@ struct kvm_arch { #if IS_ENABLED(CONFIG_HYPERV) hpa_t hv_root_tdp; spinlock_t hv_root_tdp_lock; + struct hv_partition_assist_pg *hv_pa_pg; #endif /* * VM-scope maximum vCPU ID. Used to determine the size of structures @@ -1613,9 +1642,11 @@ struct kvm_x86_ops { void (*flush_tlb_all)(struct kvm_vcpu *vcpu); void (*flush_tlb_current)(struct kvm_vcpu *vcpu); +#if IS_ENABLED(CONFIG_HYPERV) int (*flush_remote_tlbs)(struct kvm *kvm); int (*flush_remote_tlbs_range)(struct kvm *kvm, gfn_t gfn, gfn_t nr_pages); +#endif /* * Flush any TLB entries associated with the given GVA. @@ -1652,7 +1683,7 @@ struct kvm_x86_ops { /* Whether or not a virtual NMI is pending in hardware. */ bool (*is_vnmi_pending)(struct kvm_vcpu *vcpu); /* - * Attempt to pend a virtual NMI in harware. Returns %true on success + * Attempt to pend a virtual NMI in hardware. Returns %true on success * to allow using static_call_ret0 as the fallback. */ bool (*set_vnmi_pending)(struct kvm_vcpu *vcpu); @@ -1761,6 +1792,8 @@ struct kvm_x86_ops { * Returns vCPU specific APICv inhibit reasons */ unsigned long (*vcpu_get_apicv_inhibit_reasons)(struct kvm_vcpu *vcpu); + + gva_t (*get_untagged_addr)(struct kvm_vcpu *vcpu, gva_t gva, unsigned int flags); }; struct kvm_x86_nested_ops { @@ -1824,6 +1857,7 @@ static inline struct kvm *kvm_arch_alloc_vm(void) #define __KVM_HAVE_ARCH_VM_FREE void kvm_arch_free_vm(struct kvm *kvm); +#if IS_ENABLED(CONFIG_HYPERV) #define __KVM_HAVE_ARCH_FLUSH_REMOTE_TLBS static inline int kvm_arch_flush_remote_tlbs(struct kvm *kvm) { @@ -1835,6 +1869,15 @@ static inline int kvm_arch_flush_remote_tlbs(struct kvm *kvm) } #define __KVM_HAVE_ARCH_FLUSH_REMOTE_TLBS_RANGE +static inline int kvm_arch_flush_remote_tlbs_range(struct kvm *kvm, gfn_t gfn, + u64 nr_pages) +{ + if (!kvm_x86_ops.flush_remote_tlbs_range) + return -EOPNOTSUPP; + + return static_call(kvm_x86_flush_remote_tlbs_range)(kvm, gfn, nr_pages); +} +#endif /* CONFIG_HYPERV */ #define kvm_arch_pmi_in_guest(vcpu) \ ((vcpu) && (vcpu)->arch.handling_intr_from_guest) @@ -1848,6 +1891,9 @@ int kvm_mmu_create(struct kvm_vcpu *vcpu); void kvm_mmu_init_vm(struct kvm *kvm); void kvm_mmu_uninit_vm(struct kvm *kvm); +void kvm_mmu_init_memslot_memory_attributes(struct kvm *kvm, + struct kvm_memory_slot *slot); + void kvm_mmu_after_set_cpuid(struct kvm_vcpu *vcpu); void kvm_mmu_reset_context(struct kvm_vcpu *vcpu); void kvm_mmu_slot_remove_write_access(struct kvm *kvm, @@ -2086,6 +2132,12 @@ void kvm_mmu_new_pgd(struct kvm_vcpu *vcpu, gpa_t new_pgd); void kvm_configure_mmu(bool enable_tdp, int tdp_forced_root_level, int tdp_max_root_level, int tdp_huge_page_level); +#ifdef CONFIG_KVM_PRIVATE_MEM +#define kvm_arch_has_private_mem(kvm) ((kvm)->arch.vm_type != KVM_X86_DEFAULT_VM) +#else +#define kvm_arch_has_private_mem(kvm) false +#endif + static inline u16 kvm_read_ldt(void) { u16 ldt; @@ -2133,16 +2185,15 @@ enum { #define HF_SMM_MASK (1 << 1) #define HF_SMM_INSIDE_NMI_MASK (1 << 2) -# define __KVM_VCPU_MULTIPLE_ADDRESS_SPACE -# define KVM_ADDRESS_SPACE_NUM 2 +# define KVM_MAX_NR_ADDRESS_SPACES 2 +/* SMM is currently unsupported for guests with private memory. */ +# define kvm_arch_nr_memslot_as_ids(kvm) (kvm_arch_has_private_mem(kvm) ? 1 : 2) # define kvm_arch_vcpu_memslots_id(vcpu) ((vcpu)->arch.hflags & HF_SMM_MASK ? 1 : 0) # define kvm_memslots_for_spte_role(kvm, role) __kvm_memslots(kvm, (role).smm) #else # define kvm_memslots_for_spte_role(kvm, role) __kvm_memslots(kvm, 0) #endif -#define KVM_ARCH_WANT_MMU_NOTIFIER - int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v); int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu); int kvm_cpu_has_extint(struct kvm_vcpu *v); diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h index 6de6e1d95952b0..de3118305838e9 100644 --- a/arch/x86/include/asm/mce.h +++ b/arch/x86/include/asm/mce.h @@ -311,6 +311,7 @@ enum smca_bank_types { SMCA_PIE, /* Power, Interrupts, etc. */ SMCA_UMC, /* Unified Memory Controller */ SMCA_UMC_V2, + SMCA_MA_LLC, /* Memory Attached Last Level Cache */ SMCA_PB, /* Parameter Block */ SMCA_PSP, /* Platform Security Processor */ SMCA_PSP_V2, @@ -326,6 +327,8 @@ enum smca_bank_types { SMCA_SHUB, /* System HUB Unit */ SMCA_SATA, /* SATA Unit */ SMCA_USB, /* USB Unit */ + SMCA_USR_DP, /* Ultra Short Reach Data Plane Controller */ + SMCA_USR_CP, /* Ultra Short Reach Control Plane Controller */ SMCA_GMI_PCS, /* GMI PCS Unit */ SMCA_XGMI_PHY, /* xGMI PHY Unit */ SMCA_WAFL_PHY, /* WAFL PHY Unit */ @@ -333,7 +336,6 @@ enum smca_bank_types { N_SMCA_BANK_TYPES }; -extern const char *smca_get_long_name(enum smca_bank_types t); extern bool amd_mce_is_memory_error(struct mce *m); extern int mce_threshold_create_device(unsigned int cpu); diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 1d51e1850ed03d..f1bd7b91b3c637 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -237,6 +237,11 @@ #define LBR_INFO_CYCLES 0xffff #define LBR_INFO_BR_TYPE_OFFSET 56 #define LBR_INFO_BR_TYPE (0xfull << LBR_INFO_BR_TYPE_OFFSET) +#define LBR_INFO_BR_CNTR_OFFSET 32 +#define LBR_INFO_BR_CNTR_NUM 4 +#define LBR_INFO_BR_CNTR_BITS 2 +#define LBR_INFO_BR_CNTR_MASK GENMASK_ULL(LBR_INFO_BR_CNTR_BITS - 1, 0) +#define LBR_INFO_BR_CNTR_FULL_MASK GENMASK_ULL(LBR_INFO_BR_CNTR_NUM * LBR_INFO_BR_CNTR_BITS - 1, 0) #define MSR_ARCH_LBR_CTL 0x000014ce #define ARCH_LBR_CTL_LBREN BIT(0) @@ -536,6 +541,9 @@ #define MSR_RELOAD_PMC0 0x000014c1 #define MSR_RELOAD_FIXED_CTR0 0x00001309 +/* KeyID partitioning between MKTME and TDX */ +#define MSR_IA32_MKTME_KEYID_PARTITIONING 0x00000087 + /* * AMD64 MSRs. Not complete. See the architecture manual for a more * complete list. diff --git a/arch/x86/include/asm/mwait.h b/arch/x86/include/asm/mwait.h index 778df05f853918..920426d691ce71 100644 --- a/arch/x86/include/asm/mwait.h +++ b/arch/x86/include/asm/mwait.h @@ -87,6 +87,15 @@ static __always_inline void __mwaitx(unsigned long eax, unsigned long ebx, :: "a" (eax), "b" (ebx), "c" (ecx)); } +/* + * Re-enable interrupts right upon calling mwait in such a way that + * no interrupt can fire _before_ the execution of mwait, ie: no + * instruction must be placed between "sti" and "mwait". + * + * This is necessary because if an interrupt queues a timer before + * executing mwait, it would otherwise go unnoticed and the next tick + * would not be reprogrammed accordingly before mwait ever wakes up. + */ static __always_inline void __sti_mwait(unsigned long eax, unsigned long ecx) { mds_idle_clear_cpu_buffers(); @@ -115,8 +124,15 @@ static __always_inline void mwait_idle_with_hints(unsigned long eax, unsigned lo } __monitor((void *)¤t_thread_info()->flags, 0, 0); - if (!need_resched()) - __mwait(eax, ecx); + + if (!need_resched()) { + if (ecx & 1) { + __mwait(eax, ecx); + } else { + __sti_mwait(eax, ecx); + raw_local_irq_disable(); + } + } } current_clr_polling(); } diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h index f93e9b96927ac2..262e65539f83c8 100644 --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h @@ -49,7 +49,7 @@ * but there is still a cushion vs. the RSB depth. The algorithm does not * claim to be perfect and it can be speculated around by the CPU, but it * is considered that it obfuscates the problem enough to make exploitation - * extremly difficult. + * extremely difficult. */ #define RET_DEPTH_SHIFT 5 #define RSB_RET_STUFF_LOOPS 16 @@ -208,7 +208,7 @@ /* * Abuse ANNOTATE_RETPOLINE_SAFE on a NOP to indicate UNRET_END, should - * eventually turn into it's own annotation. + * eventually turn into its own annotation. */ .macro VALIDATE_UNRET_END #if defined(CONFIG_NOINSTR_VALIDATION) && \ diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h index 6c8ff12140aea9..d4eb9e1d61b8ef 100644 --- a/arch/x86/include/asm/paravirt.h +++ b/arch/x86/include/asm/paravirt.h @@ -6,6 +6,10 @@ #include +#ifndef __ASSEMBLY__ +struct mm_struct; +#endif + #ifdef CONFIG_PARAVIRT #include #include @@ -142,8 +146,7 @@ static inline void write_cr0(unsigned long x) static __always_inline unsigned long read_cr2(void) { return PVOP_ALT_CALLEE0(unsigned long, mmu.read_cr2, - "mov %%cr2, %%rax;", - ALT_NOT(X86_FEATURE_XENPV)); + "mov %%cr2, %%rax;", ALT_NOT_XEN); } static __always_inline void write_cr2(unsigned long x) @@ -154,13 +157,12 @@ static __always_inline void write_cr2(unsigned long x) static inline unsigned long __read_cr3(void) { return PVOP_ALT_CALL0(unsigned long, mmu.read_cr3, - "mov %%cr3, %%rax;", ALT_NOT(X86_FEATURE_XENPV)); + "mov %%cr3, %%rax;", ALT_NOT_XEN); } static inline void write_cr3(unsigned long x) { - PVOP_ALT_VCALL1(mmu.write_cr3, x, - "mov %%rdi, %%cr3", ALT_NOT(X86_FEATURE_XENPV)); + PVOP_ALT_VCALL1(mmu.write_cr3, x, "mov %%rdi, %%cr3", ALT_NOT_XEN); } static inline void __write_cr4(unsigned long x) @@ -182,7 +184,7 @@ extern noinstr void pv_native_wbinvd(void); static __always_inline void wbinvd(void) { - PVOP_ALT_VCALL0(cpu.wbinvd, "wbinvd", ALT_NOT(X86_FEATURE_XENPV)); + PVOP_ALT_VCALL0(cpu.wbinvd, "wbinvd", ALT_NOT_XEN); } static inline u64 paravirt_read_msr(unsigned msr) @@ -390,27 +392,25 @@ static inline void paravirt_release_p4d(unsigned long pfn) static inline pte_t __pte(pteval_t val) { return (pte_t) { PVOP_ALT_CALLEE1(pteval_t, mmu.make_pte, val, - "mov %%rdi, %%rax", - ALT_NOT(X86_FEATURE_XENPV)) }; + "mov %%rdi, %%rax", ALT_NOT_XEN) }; } static inline pteval_t pte_val(pte_t pte) { return PVOP_ALT_CALLEE1(pteval_t, mmu.pte_val, pte.pte, - "mov %%rdi, %%rax", ALT_NOT(X86_FEATURE_XENPV)); + "mov %%rdi, %%rax", ALT_NOT_XEN); } static inline pgd_t __pgd(pgdval_t val) { return (pgd_t) { PVOP_ALT_CALLEE1(pgdval_t, mmu.make_pgd, val, - "mov %%rdi, %%rax", - ALT_NOT(X86_FEATURE_XENPV)) }; + "mov %%rdi, %%rax", ALT_NOT_XEN) }; } static inline pgdval_t pgd_val(pgd_t pgd) { return PVOP_ALT_CALLEE1(pgdval_t, mmu.pgd_val, pgd.pgd, - "mov %%rdi, %%rax", ALT_NOT(X86_FEATURE_XENPV)); + "mov %%rdi, %%rax", ALT_NOT_XEN); } #define __HAVE_ARCH_PTEP_MODIFY_PROT_TRANSACTION @@ -444,14 +444,13 @@ static inline void set_pmd(pmd_t *pmdp, pmd_t pmd) static inline pmd_t __pmd(pmdval_t val) { return (pmd_t) { PVOP_ALT_CALLEE1(pmdval_t, mmu.make_pmd, val, - "mov %%rdi, %%rax", - ALT_NOT(X86_FEATURE_XENPV)) }; + "mov %%rdi, %%rax", ALT_NOT_XEN) }; } static inline pmdval_t pmd_val(pmd_t pmd) { return PVOP_ALT_CALLEE1(pmdval_t, mmu.pmd_val, pmd.pmd, - "mov %%rdi, %%rax", ALT_NOT(X86_FEATURE_XENPV)); + "mov %%rdi, %%rax", ALT_NOT_XEN); } static inline void set_pud(pud_t *pudp, pud_t pud) @@ -464,7 +463,7 @@ static inline pud_t __pud(pudval_t val) pudval_t ret; ret = PVOP_ALT_CALLEE1(pudval_t, mmu.make_pud, val, - "mov %%rdi, %%rax", ALT_NOT(X86_FEATURE_XENPV)); + "mov %%rdi, %%rax", ALT_NOT_XEN); return (pud_t) { ret }; } @@ -472,7 +471,7 @@ static inline pud_t __pud(pudval_t val) static inline pudval_t pud_val(pud_t pud) { return PVOP_ALT_CALLEE1(pudval_t, mmu.pud_val, pud.pud, - "mov %%rdi, %%rax", ALT_NOT(X86_FEATURE_XENPV)); + "mov %%rdi, %%rax", ALT_NOT_XEN); } static inline void pud_clear(pud_t *pudp) @@ -492,8 +491,7 @@ static inline void set_p4d(p4d_t *p4dp, p4d_t p4d) static inline p4d_t __p4d(p4dval_t val) { p4dval_t ret = PVOP_ALT_CALLEE1(p4dval_t, mmu.make_p4d, val, - "mov %%rdi, %%rax", - ALT_NOT(X86_FEATURE_XENPV)); + "mov %%rdi, %%rax", ALT_NOT_XEN); return (p4d_t) { ret }; } @@ -501,7 +499,7 @@ static inline p4d_t __p4d(p4dval_t val) static inline p4dval_t p4d_val(p4d_t p4d) { return PVOP_ALT_CALLEE1(p4dval_t, mmu.p4d_val, p4d.p4d, - "mov %%rdi, %%rax", ALT_NOT(X86_FEATURE_XENPV)); + "mov %%rdi, %%rax", ALT_NOT_XEN); } static inline void __set_pgd(pgd_t *pgdp, pgd_t pgd) @@ -687,17 +685,17 @@ bool __raw_callee_save___native_vcpu_is_preempted(long cpu); static __always_inline unsigned long arch_local_save_flags(void) { return PVOP_ALT_CALLEE0(unsigned long, irq.save_fl, "pushf; pop %%rax;", - ALT_NOT(X86_FEATURE_XENPV)); + ALT_NOT_XEN); } static __always_inline void arch_local_irq_disable(void) { - PVOP_ALT_VCALLEE0(irq.irq_disable, "cli;", ALT_NOT(X86_FEATURE_XENPV)); + PVOP_ALT_VCALLEE0(irq.irq_disable, "cli;", ALT_NOT_XEN); } static __always_inline void arch_local_irq_enable(void) { - PVOP_ALT_VCALLEE0(irq.irq_enable, "sti;", ALT_NOT(X86_FEATURE_XENPV)); + PVOP_ALT_VCALLEE0(irq.irq_enable, "sti;", ALT_NOT_XEN); } static __always_inline unsigned long arch_local_irq_save(void) @@ -726,52 +724,25 @@ static __always_inline unsigned long arch_local_irq_save(void) #undef PVOP_VCALL4 #undef PVOP_CALL4 -#define DEFINE_PARAVIRT_ASM(func, instr, sec) \ - asm (".pushsection " #sec ", \"ax\"\n" \ - ".global " #func "\n\t" \ - ".type " #func ", @function\n\t" \ - ASM_FUNC_ALIGN "\n" \ - #func ":\n\t" \ - ASM_ENDBR \ - instr "\n\t" \ - ASM_RET \ - ".size " #func ", . - " #func "\n\t" \ - ".popsection") - extern void default_banner(void); void native_pv_lock_init(void) __init; #else /* __ASSEMBLY__ */ -#define _PVSITE(ptype, ops, word, algn) \ -771:; \ - ops; \ -772:; \ - .pushsection .parainstructions,"a"; \ - .align algn; \ - word 771b; \ - .byte ptype; \ - .byte 772b-771b; \ - _ASM_ALIGN; \ - .popsection - - #ifdef CONFIG_X86_64 #ifdef CONFIG_PARAVIRT_XXL +#ifdef CONFIG_DEBUG_ENTRY -#define PARA_PATCH(off) ((off) / 8) -#define PARA_SITE(ptype, ops) _PVSITE(ptype, ops, .quad, 8) #define PARA_INDIRECT(addr) *addr(%rip) -#ifdef CONFIG_DEBUG_ENTRY .macro PARA_IRQ_save_fl - PARA_SITE(PARA_PATCH(PV_IRQ_save_fl), - ANNOTATE_RETPOLINE_SAFE; - call PARA_INDIRECT(pv_ops+PV_IRQ_save_fl);) + ANNOTATE_RETPOLINE_SAFE; + call PARA_INDIRECT(pv_ops+PV_IRQ_save_fl); .endm -#define SAVE_FLAGS ALTERNATIVE "PARA_IRQ_save_fl;", "pushf; pop %rax;", \ - ALT_NOT(X86_FEATURE_XENPV) +#define SAVE_FLAGS ALTERNATIVE_2 "PARA_IRQ_save_fl;", \ + "ALT_CALL_INSTR;", ALT_CALL_ALWAYS, \ + "pushf; pop %rax;", ALT_NOT_XEN #endif #endif /* CONFIG_PARAVIRT_XXL */ #endif /* CONFIG_X86_64 */ diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h index 772d03487520e5..8d4fbe1be48954 100644 --- a/arch/x86/include/asm/paravirt_types.h +++ b/arch/x86/include/asm/paravirt_types.h @@ -2,18 +2,10 @@ #ifndef _ASM_X86_PARAVIRT_TYPES_H #define _ASM_X86_PARAVIRT_TYPES_H -#ifndef __ASSEMBLY__ -/* These all sit in the .parainstructions section to tell us what to patch. */ -struct paravirt_patch_site { - u8 *instr; /* original instructions */ - u8 type; /* type of this instruction */ - u8 len; /* length of original instruction */ -}; -#endif - #ifdef CONFIG_PARAVIRT #ifndef __ASSEMBLY__ +#include #include #include @@ -250,43 +242,11 @@ struct paravirt_patch_template { extern struct pv_info pv_info; extern struct paravirt_patch_template pv_ops; -#define PARAVIRT_PATCH(x) \ - (offsetof(struct paravirt_patch_template, x) / sizeof(void *)) - -#define paravirt_type(op) \ - [paravirt_typenum] "i" (PARAVIRT_PATCH(op)), \ - [paravirt_opptr] "m" (pv_ops.op) -/* - * Generate some code, and mark it as patchable by the - * apply_paravirt() alternate instruction patcher. - */ -#define _paravirt_alt(insn_string, type) \ - "771:\n\t" insn_string "\n" "772:\n" \ - ".pushsection .parainstructions,\"a\"\n" \ - _ASM_ALIGN "\n" \ - _ASM_PTR " 771b\n" \ - " .byte " type "\n" \ - " .byte 772b-771b\n" \ - _ASM_ALIGN "\n" \ - ".popsection\n" - -/* Generate patchable code, with the default asm parameters. */ -#define paravirt_alt(insn_string) \ - _paravirt_alt(insn_string, "%c[paravirt_typenum]") - -/* Simple instruction patching code. */ -#define NATIVE_LABEL(a,x,b) "\n\t.globl " a #x "_" #b "\n" a #x "_" #b ":\n\t" - -unsigned int paravirt_patch(u8 type, void *insn_buff, unsigned long addr, unsigned int len); +#define paravirt_ptr(op) [paravirt_opptr] "m" (pv_ops.op) int paravirt_disable_iospace(void); -/* - * This generates an indirect call based on the operation type number. - * The type number, computed in PARAVIRT_PATCH, is derived from the - * offset into the paravirt_patch_template structure, and can therefore be - * freely converted back into a structure offset. - */ +/* This generates an indirect call based on the operation type number. */ #define PARAVIRT_CALL \ ANNOTATE_RETPOLINE_SAFE \ "call *%[paravirt_opptr];" @@ -319,12 +279,6 @@ int paravirt_disable_iospace(void); * However, x86_64 also has to clobber all caller saved registers, which * unfortunately, are quite a bit (r8 - r11) * - * The call instruction itself is marked by placing its start address - * and size into the .parainstructions section, so that - * apply_paravirt() in arch/i386/kernel/alternative.c can do the - * appropriate patching under the control of the backend pv_init_ops - * implementation. - * * Unfortunately there's no way to get gcc to generate the args setup * for the call, and then allow the call itself to be generated by an * inline asm. Because of this, we must do the complete arg setup and @@ -423,14 +377,27 @@ int paravirt_disable_iospace(void); __mask & __eax; \ }) - +/* + * Use alternative patching for paravirt calls: + * - For replacing an indirect call with a direct one, use the "normal" + * ALTERNATIVE() macro with the indirect call as the initial code sequence, + * which will be replaced with the related direct call by using the + * ALT_FLAG_DIRECT_CALL special case and the "always on" feature. + * - In case the replacement is either a direct call or a short code sequence + * depending on a feature bit, the ALTERNATIVE_2() macro is being used. + * The indirect call is the initial code sequence again, while the special + * code sequence is selected with the specified feature bit. In case the + * feature is not active, the direct call is used as above via the + * ALT_FLAG_DIRECT_CALL special case and the "always on" feature. + */ #define ____PVOP_CALL(ret, op, call_clbr, extra_clbr, ...) \ ({ \ PVOP_CALL_ARGS; \ PVOP_TEST_NULL(op); \ - asm volatile(paravirt_alt(PARAVIRT_CALL) \ + asm volatile(ALTERNATIVE(PARAVIRT_CALL, ALT_CALL_INSTR, \ + ALT_CALL_ALWAYS) \ : call_clbr, ASM_CALL_CONSTRAINT \ - : paravirt_type(op), \ + : paravirt_ptr(op), \ ##__VA_ARGS__ \ : "memory", "cc" extra_clbr); \ ret; \ @@ -441,10 +408,11 @@ int paravirt_disable_iospace(void); ({ \ PVOP_CALL_ARGS; \ PVOP_TEST_NULL(op); \ - asm volatile(ALTERNATIVE(paravirt_alt(PARAVIRT_CALL), \ - alt, cond) \ + asm volatile(ALTERNATIVE_2(PARAVIRT_CALL, \ + ALT_CALL_INSTR, ALT_CALL_ALWAYS, \ + alt, cond) \ : call_clbr, ASM_CALL_CONSTRAINT \ - : paravirt_type(op), \ + : paravirt_ptr(op), \ ##__VA_ARGS__ \ : "memory", "cc" extra_clbr); \ ret; \ @@ -542,8 +510,6 @@ int paravirt_disable_iospace(void); __PVOP_VCALL(op, PVOP_CALL_ARG1(arg1), PVOP_CALL_ARG2(arg2), \ PVOP_CALL_ARG3(arg3), PVOP_CALL_ARG4(arg4)) -void _paravirt_nop(void); -void paravirt_BUG(void); unsigned long paravirt_ret0(void); #ifdef CONFIG_PARAVIRT_XXL u64 _paravirt_ident_64(u64); @@ -553,11 +519,11 @@ void pv_native_irq_enable(void); unsigned long pv_native_read_cr2(void); #endif -#define paravirt_nop ((void *)_paravirt_nop) - -extern struct paravirt_patch_site __parainstructions[], - __parainstructions_end[]; +#define paravirt_nop ((void *)nop_func) #endif /* __ASSEMBLY__ */ + +#define ALT_NOT_XEN ALT_NOT(X86_FEATURE_XENPV) + #endif /* CONFIG_PARAVIRT */ #endif /* _ASM_X86_PARAVIRT_TYPES_H */ diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h index 20624b80f89041..5e01883eb51ee8 100644 --- a/arch/x86/include/asm/percpu.h +++ b/arch/x86/include/asm/percpu.h @@ -24,8 +24,8 @@ #else /* ...!ASSEMBLY */ -#include #include +#include #ifdef CONFIG_SMP #define __percpu_prefix "%%"__stringify(__percpu_seg)":" diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h index 2618ec7c3d1d33..3736b8a46c04de 100644 --- a/arch/x86/include/asm/perf_event.h +++ b/arch/x86/include/asm/perf_event.h @@ -31,6 +31,7 @@ #define ARCH_PERFMON_EVENTSEL_ENABLE (1ULL << 22) #define ARCH_PERFMON_EVENTSEL_INV (1ULL << 23) #define ARCH_PERFMON_EVENTSEL_CMASK 0xFF000000ULL +#define ARCH_PERFMON_EVENTSEL_BR_CNTR (1ULL << 35) #define INTEL_FIXED_BITS_MASK 0xFULL #define INTEL_FIXED_BITS_STRIDE 4 @@ -223,6 +224,9 @@ union cpuid28_ecx { unsigned int lbr_timed_lbr:1; /* Branch Type Field Supported */ unsigned int lbr_br_type:1; + unsigned int reserved:13; + /* Branch counters (Event Logging) Supported */ + unsigned int lbr_counters:4; } split; unsigned int full; }; diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h index 57bab91bbf504e..9d077bca6a103e 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h @@ -141,6 +141,7 @@ static inline int pte_young(pte_t pte) return pte_flags(pte) & _PAGE_ACCESSED; } +#define pmd_dirty pmd_dirty static inline bool pmd_dirty(pmd_t pmd) { return pmd_flags(pmd) & _PAGE_DIRTY_BITS; @@ -1679,12 +1680,6 @@ static inline bool arch_has_pfn_modify_check(void) return boot_cpu_has_bug(X86_BUG_L1TF); } -#define arch_has_hw_pte_young arch_has_hw_pte_young -static inline bool arch_has_hw_pte_young(void) -{ - return true; -} - #define arch_check_zapped_pte arch_check_zapped_pte void arch_check_zapped_pte(struct vm_area_struct *vma, pte_t pte); diff --git a/arch/x86/include/asm/pgtable_64.h b/arch/x86/include/asm/pgtable_64.h index a629b1b9f65a61..24af25b1551a56 100644 --- a/arch/x86/include/asm/pgtable_64.h +++ b/arch/x86/include/asm/pgtable_64.h @@ -203,7 +203,7 @@ static inline void native_pgd_clear(pgd_t *pgd) * F (2) in swp entry is used to record when a pagetable is * writeprotected by userfaultfd WP support. * - * E (3) in swp entry is used to rememeber PG_anon_exclusive. + * E (3) in swp entry is used to remember PG_anon_exclusive. * * Bit 7 in swp entry should be 0 because pmd_present checks not only P, * but also L and G. diff --git a/arch/x86/include/asm/preempt.h b/arch/x86/include/asm/preempt.h index 4527e1430c6dc1..af77235fded63b 100644 --- a/arch/x86/include/asm/preempt.h +++ b/arch/x86/include/asm/preempt.h @@ -6,7 +6,6 @@ #include #include -#include #include /* We use the MSB mostly because its available */ diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index ae81a7191c1c0e..26620d7642a9fc 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -749,4 +749,22 @@ enum mds_mitigations { extern bool gds_ucode_mitigated(void); +/* + * Make previous memory operations globally visible before + * a WRMSR. + * + * MFENCE makes writes visible, but only affects load/store + * instructions. WRMSR is unfortunately not a load/store + * instruction and is unaffected by MFENCE. The LFENCE ensures + * that the WRMSR is not reordered. + * + * Most WRMSRs are full serializing instructions themselves and + * do not require this barrier. This is only required for the + * IA32_TSC_DEADLINE and X2APIC MSRs. + */ +static inline void weak_wrmsr_fence(void) +{ + alternative("mfence; lfence", "", ALT_NOT(X86_FEATURE_APIC_MSRS_FENCE)); +} + #endif /* _ASM_X86_PROCESSOR_H */ diff --git a/arch/x86/include/asm/qspinlock_paravirt.h b/arch/x86/include/asm/qspinlock_paravirt.h index 85b6e3609cb926..ef9697f20129af 100644 --- a/arch/x86/include/asm/qspinlock_paravirt.h +++ b/arch/x86/include/asm/qspinlock_paravirt.h @@ -56,8 +56,8 @@ __PV_CALLEE_SAVE_REGS_THUNK(__pv_queued_spin_unlock_slowpath, ".spinlock.text"); "pop %rdx\n\t" \ FRAME_END -DEFINE_PARAVIRT_ASM(__raw_callee_save___pv_queued_spin_unlock, - PV_UNLOCK_ASM, .spinlock.text); +DEFINE_ASM_FUNC(__raw_callee_save___pv_queued_spin_unlock, + PV_UNLOCK_ASM, .spinlock.text); #else /* CONFIG_64BIT */ diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h index bf483fcb4e5744..5c83729c8e71ff 100644 --- a/arch/x86/include/asm/setup.h +++ b/arch/x86/include/asm/setup.h @@ -31,8 +31,6 @@ #include #include -extern u64 relocated_ramdisk; - /* Interrupt control for vSMPowered x86_64 systems */ #ifdef CONFIG_X86_64 void vsmp_init(void); diff --git a/arch/x86/include/asm/shared/tdx.h b/arch/x86/include/asm/shared/tdx.h index ccce7ebd867728..fdfd41511b0211 100644 --- a/arch/x86/include/asm/shared/tdx.h +++ b/arch/x86/include/asm/shared/tdx.h @@ -55,6 +55,12 @@ (TDX_RDX | TDX_RBX | TDX_RSI | TDX_RDI | TDX_R8 | TDX_R9 | \ TDX_R10 | TDX_R11 | TDX_R12 | TDX_R13 | TDX_R14 | TDX_R15) +/* TDX supported page sizes from the TDX module ABI. */ +#define TDX_PS_4K 0 +#define TDX_PS_2M 1 +#define TDX_PS_1G 2 +#define TDX_PS_NR (TDX_PS_1G + 1) + #ifndef __ASSEMBLY__ #include diff --git a/arch/x86/include/asm/syscall_wrapper.h b/arch/x86/include/asm/syscall_wrapper.h index 21f9407be5d357..7e88705e907f41 100644 --- a/arch/x86/include/asm/syscall_wrapper.h +++ b/arch/x86/include/asm/syscall_wrapper.h @@ -58,12 +58,29 @@ extern long __ia32_sys_ni_syscall(const struct pt_regs *regs); ,,regs->di,,regs->si,,regs->dx \ ,,regs->r10,,regs->r8,,regs->r9) \ + +/* SYSCALL_PT_ARGS is Adapted from s390x */ +#define SYSCALL_PT_ARG6(m, t1, t2, t3, t4, t5, t6) \ + SYSCALL_PT_ARG5(m, t1, t2, t3, t4, t5), m(t6, (regs->bp)) +#define SYSCALL_PT_ARG5(m, t1, t2, t3, t4, t5) \ + SYSCALL_PT_ARG4(m, t1, t2, t3, t4), m(t5, (regs->di)) +#define SYSCALL_PT_ARG4(m, t1, t2, t3, t4) \ + SYSCALL_PT_ARG3(m, t1, t2, t3), m(t4, (regs->si)) +#define SYSCALL_PT_ARG3(m, t1, t2, t3) \ + SYSCALL_PT_ARG2(m, t1, t2), m(t3, (regs->dx)) +#define SYSCALL_PT_ARG2(m, t1, t2) \ + SYSCALL_PT_ARG1(m, t1), m(t2, (regs->cx)) +#define SYSCALL_PT_ARG1(m, t1) m(t1, (regs->bx)) +#define SYSCALL_PT_ARGS(x, ...) SYSCALL_PT_ARG##x(__VA_ARGS__) + +#define __SC_COMPAT_CAST(t, a) \ + (__typeof(__builtin_choose_expr(__TYPE_IS_L(t), 0, 0U))) \ + (unsigned int)a + /* Mapping of registers to parameters for syscalls on i386 */ #define SC_IA32_REGS_TO_ARGS(x, ...) \ - __MAP(x,__SC_ARGS \ - ,,(unsigned int)regs->bx,,(unsigned int)regs->cx \ - ,,(unsigned int)regs->dx,,(unsigned int)regs->si \ - ,,(unsigned int)regs->di,,(unsigned int)regs->bp) + SYSCALL_PT_ARGS(x, __SC_COMPAT_CAST, \ + __MAP(x, __SC_TYPE, __VA_ARGS__)) \ #define __SYS_STUB0(abi, name) \ long __##abi##_##name(const struct pt_regs *regs); \ diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h index f3d5305a60fc50..eba178996d8459 100644 --- a/arch/x86/include/asm/tdx.h +++ b/arch/x86/include/asm/tdx.h @@ -24,8 +24,16 @@ #define TDX_SEAMCALL_GP (TDX_SW_ERROR | X86_TRAP_GP) #define TDX_SEAMCALL_UD (TDX_SW_ERROR | X86_TRAP_UD) +/* + * TDX module SEAMCALL leaf function error codes + */ +#define TDX_SUCCESS 0ULL +#define TDX_RND_NO_ENTROPY 0x8000020300000000ULL + #ifndef __ASSEMBLY__ +#include + /* * Used by the #VE exception handler to gather the #VE exception * info from the TDX module. This is a software only structure @@ -83,6 +91,36 @@ static inline long tdx_kvm_hypercall(unsigned int nr, unsigned long p1, u64 __seamcall(u64 fn, struct tdx_module_args *args); u64 __seamcall_ret(u64 fn, struct tdx_module_args *args); u64 __seamcall_saved_ret(u64 fn, struct tdx_module_args *args); +void tdx_init(void); + +#include + +typedef u64 (*sc_func_t)(u64 fn, struct tdx_module_args *args); + +static inline u64 sc_retry(sc_func_t func, u64 fn, + struct tdx_module_args *args) +{ + int retry = RDRAND_RETRY_LOOPS; + u64 ret; + + do { + ret = func(fn, args); + } while (ret == TDX_RND_NO_ENTROPY && --retry); + + return ret; +} + +#define seamcall(_fn, _args) sc_retry(__seamcall, (_fn), (_args)) +#define seamcall_ret(_fn, _args) sc_retry(__seamcall_ret, (_fn), (_args)) +#define seamcall_saved_ret(_fn, _args) sc_retry(__seamcall_saved_ret, (_fn), (_args)) +int tdx_cpu_enable(void); +int tdx_enable(void); +const char *tdx_dump_mce_info(struct mce *m); +#else +static inline void tdx_init(void) { } +static inline int tdx_cpu_enable(void) { return -ENODEV; } +static inline int tdx_enable(void) { return -ENODEV; } +static inline const char *tdx_dump_mce_info(struct mce *m) { return NULL; } #endif /* CONFIG_INTEL_TDX_HOST */ #endif /* !__ASSEMBLY__ */ diff --git a/arch/x86/include/asm/text-patching.h b/arch/x86/include/asm/text-patching.h index 29832c338cdc5a..0b70653a98c157 100644 --- a/arch/x86/include/asm/text-patching.h +++ b/arch/x86/include/asm/text-patching.h @@ -6,18 +6,6 @@ #include #include -struct paravirt_patch_site; -#ifdef CONFIG_PARAVIRT -void apply_paravirt(struct paravirt_patch_site *start, - struct paravirt_patch_site *end); -#else -static inline void apply_paravirt(struct paravirt_patch_site *start, - struct paravirt_patch_site *end) -{} -#define __parainstructions NULL -#define __parainstructions_end NULL -#endif - /* * Currently, the max observed size in the kernel code is * JUMP_LABEL_NOP_SIZE/RELATIVEJUMP_SIZE, which are 5. diff --git a/arch/x86/include/asm/traps.h b/arch/x86/include/asm/traps.h index b1c9cea6ba88bb..1f1deaecd364b8 100644 --- a/arch/x86/include/asm/traps.h +++ b/arch/x86/include/asm/traps.h @@ -14,7 +14,6 @@ asmlinkage __visible notrace struct pt_regs *sync_regs(struct pt_regs *eregs); asmlinkage __visible notrace struct pt_regs *fixup_bad_iret(struct pt_regs *bad_regs); -void __init trap_init(void); asmlinkage __visible noinstr struct pt_regs *vc_switch_off_ist(struct pt_regs *eregs); #endif diff --git a/arch/x86/include/asm/uv/uv_hub.h b/arch/x86/include/asm/uv/uv_hub.h index 5fa76c2ced51fa..ea877fd83114c2 100644 --- a/arch/x86/include/asm/uv/uv_hub.h +++ b/arch/x86/include/asm/uv/uv_hub.h @@ -653,7 +653,7 @@ static inline int uv_blade_to_node(int blade) return uv_socket_to_node(blade); } -/* Blade number of current cpu. Numnbered 0 .. <#blades -1> */ +/* Blade number of current cpu. Numbered 0 .. <#blades -1> */ static inline int uv_numa_blade_id(void) { return uv_hub_info->numa_blade_id; diff --git a/arch/x86/include/asm/vdso/gettimeofday.h b/arch/x86/include/asm/vdso/gettimeofday.h index c81858d903dc0f..8e048ca980df85 100644 --- a/arch/x86/include/asm/vdso/gettimeofday.h +++ b/arch/x86/include/asm/vdso/gettimeofday.h @@ -321,7 +321,7 @@ static __always_inline u64 vdso_calc_delta(u64 cycles, u64 last, u64 mask, u32 mult) { /* - * Due to the MSB/Sign-bit being used as invald marker (see + * Due to the MSB/Sign-bit being used as invalid marker (see * arch_vdso_cycles_valid() above), the effective mask is S64_MAX. */ u64 delta = (cycles - last) & S64_MAX; @@ -337,8 +337,6 @@ u64 vdso_calc_delta(u64 cycles, u64 last, u64 mask, u32 mult) } #define vdso_calc_delta vdso_calc_delta -int __vdso_clock_gettime64(clockid_t clock, struct __kernel_timespec *ts); - #endif /* !__ASSEMBLY__ */ #endif /* __ASM_VDSO_GETTIMEOFDAY_H */ diff --git a/arch/x86/include/asm/xen/interface_64.h b/arch/x86/include/asm/xen/interface_64.h index c599ec269a2544..c10f279aae9361 100644 --- a/arch/x86/include/asm/xen/interface_64.h +++ b/arch/x86/include/asm/xen/interface_64.h @@ -61,7 +61,7 @@ * RING1 -> RING3 kernel mode. * RING2 -> RING3 kernel mode. * RING3 -> RING3 user mode. - * However RING0 indicates that the guest kernel should return to iteself + * However RING0 indicates that the guest kernel should return to itself * directly with * orb $3,1*8(%rsp) * iretq diff --git a/arch/x86/include/uapi/asm/amd_hsmp.h b/arch/x86/include/uapi/asm/amd_hsmp.h index fce22686c834f6..e5d182c7373c8e 100644 --- a/arch/x86/include/uapi/asm/amd_hsmp.h +++ b/arch/x86/include/uapi/asm/amd_hsmp.h @@ -238,7 +238,7 @@ static const struct hsmp_msg_desc hsmp_msg_desc_table[] = { /* * HSMP_GET_DIMM_THERMAL, num_args = 1, response_sz = 1 * input: args[0] = DIMM address[7:0] - * output: args[0] = temperature in degree celcius[31:21] + update rate in ms[16:8] + + * output: args[0] = temperature in degree celsius[31:21] + update rate in ms[16:8] + * DIMM address[7:0] */ {1, 1, HSMP_GET}, diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h index 1a6a1f98794967..a448d0964fc06e 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -562,4 +562,7 @@ struct kvm_pmu_event_filter { /* x86-specific KVM_EXIT_HYPERCALL flags. */ #define KVM_EXIT_HYPERCALL_LONG_MODE BIT(0) +#define KVM_X86_DEFAULT_VM 0 +#define KVM_X86_SW_PROTECTED_VM 1 + #endif /* _ASM_X86_KVM_H */ diff --git a/arch/x86/include/uapi/asm/signal.h b/arch/x86/include/uapi/asm/signal.h index 777c3a0f4e230a..f777346450ec3d 100644 --- a/arch/x86/include/uapi/asm/signal.h +++ b/arch/x86/include/uapi/asm/signal.h @@ -4,7 +4,6 @@ #ifndef __ASSEMBLY__ #include -#include #include /* Avoid too many header ordering problems. */ diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index aae7456ece0700..1d85cb7071cb21 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -30,6 +30,7 @@ #include #include #include +#include int __read_mostly alternatives_patched; @@ -160,7 +161,6 @@ extern s32 __retpoline_sites[], __retpoline_sites_end[]; extern s32 __return_sites[], __return_sites_end[]; extern s32 __cfi_sites[], __cfi_sites_end[]; extern s32 __ibt_endbr_seal[], __ibt_endbr_seal_end[]; -extern struct alt_instr __alt_instructions[], __alt_instructions_end[]; extern s32 __smp_locks[], __smp_locks_end[]; void text_poke_early(void *addr, const void *opcode, size_t len); @@ -395,6 +395,63 @@ apply_relocation(u8 *buf, size_t len, u8 *dest, u8 *src, size_t src_len) } } +/* Low-level backend functions usable from alternative code replacements. */ +DEFINE_ASM_FUNC(nop_func, "", .entry.text); +EXPORT_SYMBOL_GPL(nop_func); + +noinstr void BUG_func(void) +{ + BUG(); +} +EXPORT_SYMBOL(BUG_func); + +#define CALL_RIP_REL_OPCODE 0xff +#define CALL_RIP_REL_MODRM 0x15 + +/* + * Rewrite the "call BUG_func" replacement to point to the target of the + * indirect pv_ops call "call *disp(%ip)". + */ +static int alt_replace_call(u8 *instr, u8 *insn_buff, struct alt_instr *a) +{ + void *target, *bug = &BUG_func; + s32 disp; + + if (a->replacementlen != 5 || insn_buff[0] != CALL_INSN_OPCODE) { + pr_err("ALT_FLAG_DIRECT_CALL set for a non-call replacement instruction\n"); + BUG(); + } + + if (a->instrlen != 6 || + instr[0] != CALL_RIP_REL_OPCODE || + instr[1] != CALL_RIP_REL_MODRM) { + pr_err("ALT_FLAG_DIRECT_CALL set for unrecognized indirect call\n"); + BUG(); + } + + /* Skip CALL_RIP_REL_OPCODE and CALL_RIP_REL_MODRM */ + disp = *(s32 *)(instr + 2); +#ifdef CONFIG_X86_64 + /* ff 15 00 00 00 00 call *0x0(%rip) */ + /* target address is stored at "next instruction + disp". */ + target = *(void **)(instr + a->instrlen + disp); +#else + /* ff 15 00 00 00 00 call *0x0 */ + /* target address is stored at disp. */ + target = *(void **)disp; +#endif + if (!target) + target = bug; + + /* (BUG_func - .) + (target - BUG_func) := target - . */ + *(s32 *)(insn_buff + 1) += target - bug; + + if (target == &nop_func) + return 0; + + return 5; +} + /* * Replace instructions with better alternatives for this CPU type. This runs * before SMP is initialized to avoid SMP problems with self modifying code. @@ -452,16 +509,21 @@ void __init_or_module noinline apply_alternatives(struct alt_instr *start, continue; } - DPRINTK(ALT, "feat: %s%d*32+%d, old: (%pS (%px) len: %d), repl: (%px, len: %d)", - (a->flags & ALT_FLAG_NOT) ? "!" : "", + DPRINTK(ALT, "feat: %d*32+%d, old: (%pS (%px) len: %d), repl: (%px, len: %d) flags: 0x%x", a->cpuid >> 5, a->cpuid & 0x1f, instr, instr, a->instrlen, - replacement, a->replacementlen); + replacement, a->replacementlen, a->flags); memcpy(insn_buff, replacement, a->replacementlen); insn_buff_sz = a->replacementlen; + if (a->flags & ALT_FLAG_DIRECT_CALL) { + insn_buff_sz = alt_replace_call(instr, insn_buff, a); + if (insn_buff_sz < 0) + continue; + } + for (; insn_buff_sz < a->instrlen; insn_buff_sz++) insn_buff[insn_buff_sz] = 0x90; @@ -842,15 +904,82 @@ void __init_or_module apply_seal_endbr(s32 *start, s32 *end) { } #endif /* CONFIG_X86_KERNEL_IBT */ #ifdef CONFIG_FINEIBT +#define __CFI_DEFAULT CFI_DEFAULT +#elif defined(CONFIG_CFI_CLANG) +#define __CFI_DEFAULT CFI_KCFI +#else +#define __CFI_DEFAULT CFI_OFF +#endif -enum cfi_mode { - CFI_DEFAULT, - CFI_OFF, - CFI_KCFI, - CFI_FINEIBT, -}; +enum cfi_mode cfi_mode __ro_after_init = __CFI_DEFAULT; + +#ifdef CONFIG_CFI_CLANG +struct bpf_insn; + +/* Must match bpf_func_t / DEFINE_BPF_PROG_RUN() */ +extern unsigned int __bpf_prog_runX(const void *ctx, + const struct bpf_insn *insn); + +/* + * Force a reference to the external symbol so the compiler generates + * __kcfi_typid. + */ +__ADDRESSABLE(__bpf_prog_runX); + +/* u32 __ro_after_init cfi_bpf_hash = __kcfi_typeid___bpf_prog_runX; */ +asm ( +" .pushsection .data..ro_after_init,\"aw\",@progbits \n" +" .type cfi_bpf_hash,@object \n" +" .globl cfi_bpf_hash \n" +" .p2align 2, 0x0 \n" +"cfi_bpf_hash: \n" +" .long __kcfi_typeid___bpf_prog_runX \n" +" .size cfi_bpf_hash, 4 \n" +" .popsection \n" +); + +/* Must match bpf_callback_t */ +extern u64 __bpf_callback_fn(u64, u64, u64, u64, u64); + +__ADDRESSABLE(__bpf_callback_fn); + +/* u32 __ro_after_init cfi_bpf_subprog_hash = __kcfi_typeid___bpf_callback_fn; */ +asm ( +" .pushsection .data..ro_after_init,\"aw\",@progbits \n" +" .type cfi_bpf_subprog_hash,@object \n" +" .globl cfi_bpf_subprog_hash \n" +" .p2align 2, 0x0 \n" +"cfi_bpf_subprog_hash: \n" +" .long __kcfi_typeid___bpf_callback_fn \n" +" .size cfi_bpf_subprog_hash, 4 \n" +" .popsection \n" +); + +u32 cfi_get_func_hash(void *func) +{ + u32 hash; + + func -= cfi_get_offset(); + switch (cfi_mode) { + case CFI_FINEIBT: + func += 7; + break; + case CFI_KCFI: + func += 1; + break; + default: + return 0; + } + + if (get_kernel_nofault(hash, func)) + return 0; + + return hash; +} +#endif + +#ifdef CONFIG_FINEIBT -static enum cfi_mode cfi_mode __ro_after_init = CFI_DEFAULT; static bool cfi_rand __ro_after_init = true; static u32 cfi_seed __ro_after_init; @@ -1159,8 +1288,11 @@ static void __apply_fineibt(s32 *start_retpoline, s32 *end_retpoline, goto err; if (cfi_rand) { - if (builtin) + if (builtin) { cfi_seed = get_random_u32(); + cfi_bpf_hash = cfi_rehash(cfi_bpf_hash); + cfi_bpf_subprog_hash = cfi_rehash(cfi_bpf_subprog_hash); + } ret = cfi_rand_preamble(start_cfi, end_cfi); if (ret) @@ -1421,46 +1553,6 @@ int alternatives_text_reserved(void *start, void *end) } #endif /* CONFIG_SMP */ -#ifdef CONFIG_PARAVIRT - -/* Use this to add nops to a buffer, then text_poke the whole buffer. */ -static void __init_or_module add_nops(void *insns, unsigned int len) -{ - while (len > 0) { - unsigned int noplen = len; - if (noplen > ASM_NOP_MAX) - noplen = ASM_NOP_MAX; - memcpy(insns, x86_nops[noplen], noplen); - insns += noplen; - len -= noplen; - } -} - -void __init_or_module apply_paravirt(struct paravirt_patch_site *start, - struct paravirt_patch_site *end) -{ - struct paravirt_patch_site *p; - char insn_buff[MAX_PATCH_LEN]; - - for (p = start; p < end; p++) { - unsigned int used; - - BUG_ON(p->len > MAX_PATCH_LEN); - /* prep the buffer with the original instructions */ - memcpy(insn_buff, p->instr, p->len); - used = paravirt_patch(p->type, insn_buff, (unsigned long)p->instr, p->len); - - BUG_ON(used > p->len); - - /* Pad the rest with nops */ - add_nops(insn_buff + used, p->len - used); - text_poke_early(p->instr, insn_buff, p->len); - } -} -extern struct paravirt_patch_site __start_parainstructions[], - __stop_parainstructions[]; -#endif /* CONFIG_PARAVIRT */ - /* * Self-test for the INT3 based CALL emulation code. * @@ -1596,28 +1688,11 @@ void __init alternative_instructions(void) */ /* - * Paravirt patching and alternative patching can be combined to - * replace a function call with a short direct code sequence (e.g. - * by setting a constant return value instead of doing that in an - * external function). - * In order to make this work the following sequence is required: - * 1. set (artificial) features depending on used paravirt - * functions which can later influence alternative patching - * 2. apply paravirt patching (generally replacing an indirect - * function call with a direct one) - * 3. apply alternative patching (e.g. replacing a direct function - * call with a custom code sequence) - * Doing paravirt patching after alternative patching would clobber - * the optimization of the custom code with a function call again. + * Make sure to set (artificial) features depending on used paravirt + * functions which can later influence alternative patching. */ paravirt_set_cap(); - /* - * First patch paravirt functions, such that we overwrite the indirect - * call with the direct call. - */ - apply_paravirt(__parainstructions, __parainstructions_end); - __apply_fineibt(__retpoline_sites, __retpoline_sites_end, __cfi_sites, __cfi_sites_end, true); @@ -1628,10 +1703,6 @@ void __init alternative_instructions(void) apply_retpolines(__retpoline_sites, __retpoline_sites_end); apply_returns(__return_sites, __return_sites_end); - /* - * Then patch alternatives, such that those paravirt calls that are in - * alternatives can be overwritten by their immediate fragments. - */ apply_alternatives(__alt_instructions, __alt_instructions_end); /* @@ -1906,7 +1977,7 @@ static void *__text_poke(text_poke_f func, void *addr, const void *src, size_t l * Note that the caller must ensure that if the modified code is part of a * module, the module would not be removed during poking. This can be achieved * by registering a module notifier, and ordering module removal and patching - * trough a mutex. + * through a mutex. */ void *text_poke(void *addr, const void *opcode, size_t len) { diff --git a/arch/x86/kernel/amd_gart_64.c b/arch/x86/kernel/amd_gart_64.c index 56a917df410d30..2ae98f754e5918 100644 --- a/arch/x86/kernel/amd_gart_64.c +++ b/arch/x86/kernel/amd_gart_64.c @@ -776,7 +776,7 @@ int __init gart_iommu_init(void) iommu_size >> PAGE_SHIFT); /* * Tricky. The GART table remaps the physical memory range, - * so the CPU wont notice potential aliases and if the memory + * so the CPU won't notice potential aliases and if the memory * is remapped to UC later on, we might surprise the PCI devices * with a stray writeout of a cacheline. So play it sure and * do an explicit, full-scale wbinvd() _after_ having marked all diff --git a/arch/x86/kernel/aperture_64.c b/arch/x86/kernel/aperture_64.c index 4feaa670d5783b..89c0c8a3fc7e6c 100644 --- a/arch/x86/kernel/aperture_64.c +++ b/arch/x86/kernel/aperture_64.c @@ -259,10 +259,9 @@ static u32 __init search_agp_bridge(u32 *order, int *valid_agp) order); } - /* No multi-function device? */ type = read_pci_config_byte(bus, slot, func, PCI_HEADER_TYPE); - if (!(type & 0x80)) + if (!(type & PCI_HEADER_TYPE_MFD)) break; } } diff --git a/arch/x86/kernel/apic/Makefile b/arch/x86/kernel/apic/Makefile index 2ee867d796d971..3bf0487cf3b731 100644 --- a/arch/x86/kernel/apic/Makefile +++ b/arch/x86/kernel/apic/Makefile @@ -4,7 +4,7 @@ # # Leads to non-deterministic coverage that is not a function of syscall inputs. -# In particualr, smp_apic_timer_interrupt() is called in random places. +# In particular, smp_apic_timer_interrupt() is called in random places. KCOV_INSTRUMENT := n obj-$(CONFIG_X86_LOCAL_APIC) += apic.o apic_common.o apic_noop.o ipi.o vector.o init.o diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 41093cf20acdce..4667bc4b00ab8a 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -782,7 +782,7 @@ bool __init apic_needs_pit(void) /* * If interrupt delivery mode is legacy PIC or virtual wire without - * configuration, the local APIC timer wont be set up. Make sure + * configuration, the local APIC timer won't be set up. Make sure * that the PIT is initialized. */ if (apic_intr_mode == APIC_PIC || diff --git a/arch/x86/kernel/apic/apic_flat_64.c b/arch/x86/kernel/apic/apic_flat_64.c index 7139867d69cd2d..b295a056a4fc5c 100644 --- a/arch/x86/kernel/apic/apic_flat_64.c +++ b/arch/x86/kernel/apic/apic_flat_64.c @@ -82,7 +82,6 @@ static struct apic apic_flat __ro_after_init = { .acpi_madt_oem_check = flat_acpi_madt_oem_check, .apic_id_registered = default_apic_id_registered, - .delivery_mode = APIC_DELIVERY_MODE_FIXED, .dest_mode_logical = true, .disable_esr = 0, @@ -154,7 +153,6 @@ static struct apic apic_physflat __ro_after_init = { .acpi_madt_oem_check = physflat_acpi_madt_oem_check, .apic_id_registered = default_apic_id_registered, - .delivery_mode = APIC_DELIVERY_MODE_FIXED, .dest_mode_logical = false, .disable_esr = 0, diff --git a/arch/x86/kernel/apic/apic_noop.c b/arch/x86/kernel/apic/apic_noop.c index b00d52ae84fa95..9f1d553eb48f48 100644 --- a/arch/x86/kernel/apic/apic_noop.c +++ b/arch/x86/kernel/apic/apic_noop.c @@ -47,7 +47,6 @@ static void noop_apic_write(u32 reg, u32 val) struct apic apic_noop __ro_after_init = { .name = "noop", - .delivery_mode = APIC_DELIVERY_MODE_FIXED, .dest_mode_logical = true, .disable_esr = 0, diff --git a/arch/x86/kernel/apic/apic_numachip.c b/arch/x86/kernel/apic/apic_numachip.c index 456a14c44f67ab..7d0c51b9d3bca8 100644 --- a/arch/x86/kernel/apic/apic_numachip.c +++ b/arch/x86/kernel/apic/apic_numachip.c @@ -222,7 +222,6 @@ static const struct apic apic_numachip1 __refconst = { .probe = numachip1_probe, .acpi_madt_oem_check = numachip1_acpi_madt_oem_check, - .delivery_mode = APIC_DELIVERY_MODE_FIXED, .dest_mode_logical = false, .disable_esr = 0, @@ -259,7 +258,6 @@ static const struct apic apic_numachip2 __refconst = { .probe = numachip2_probe, .acpi_madt_oem_check = numachip2_acpi_madt_oem_check, - .delivery_mode = APIC_DELIVERY_MODE_FIXED, .dest_mode_logical = false, .disable_esr = 0, diff --git a/arch/x86/kernel/apic/bigsmp_32.c b/arch/x86/kernel/apic/bigsmp_32.c index 7ee3c486cb3365..5a0d60b38e6bf0 100644 --- a/arch/x86/kernel/apic/bigsmp_32.c +++ b/arch/x86/kernel/apic/bigsmp_32.c @@ -80,7 +80,6 @@ static struct apic apic_bigsmp __ro_after_init = { .name = "bigsmp", .probe = probe_bigsmp, - .delivery_mode = APIC_DELIVERY_MODE_FIXED, .dest_mode_logical = false, .disable_esr = 1, diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 00da6cf6b07dcb..40c7cf180c2031 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -997,7 +997,7 @@ static int alloc_isa_irq_from_domain(struct irq_domain *domain, /* * Legacy ISA IRQ has already been allocated, just add pin to * the pin list associated with this IRQ and program the IOAPIC - * entry. The IOAPIC entry + * entry. */ if (irq_data && irq_data->parent_data) { if (!mp_check_pin_attr(irq, info)) diff --git a/arch/x86/kernel/apic/probe_32.c b/arch/x86/kernel/apic/probe_32.c index 5eb3fbe472da9d..c0f78059f06aca 100644 --- a/arch/x86/kernel/apic/probe_32.c +++ b/arch/x86/kernel/apic/probe_32.c @@ -45,7 +45,6 @@ static struct apic apic_default __ro_after_init = { .probe = probe_default, .apic_id_registered = default_apic_id_registered, - .delivery_mode = APIC_DELIVERY_MODE_FIXED, .dest_mode_logical = true, .disable_esr = 0, diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c index 319448d87b99a7..185738c727661e 100644 --- a/arch/x86/kernel/apic/vector.c +++ b/arch/x86/kernel/apic/vector.c @@ -738,8 +738,8 @@ int __init arch_probe_nr_irqs(void) void lapic_assign_legacy_vector(unsigned int irq, bool replace) { /* - * Use assign system here so it wont get accounted as allocated - * and moveable in the cpu hotplug check and it prevents managed + * Use assign system here so it won't get accounted as allocated + * and movable in the cpu hotplug check and it prevents managed * irq reservation from touching it. */ irq_matrix_assign_system(vector_matrix, ISA_IRQ_VECTOR(irq), replace); diff --git a/arch/x86/kernel/apic/x2apic_cluster.c b/arch/x86/kernel/apic/x2apic_cluster.c index a8306089c91bca..28a7d3f2312d21 100644 --- a/arch/x86/kernel/apic/x2apic_cluster.c +++ b/arch/x86/kernel/apic/x2apic_cluster.c @@ -227,7 +227,6 @@ static struct apic apic_x2apic_cluster __ro_after_init = { .probe = x2apic_cluster_probe, .acpi_madt_oem_check = x2apic_acpi_madt_oem_check, - .delivery_mode = APIC_DELIVERY_MODE_FIXED, .dest_mode_logical = true, .disable_esr = 0, diff --git a/arch/x86/kernel/apic/x2apic_phys.c b/arch/x86/kernel/apic/x2apic_phys.c index 558a4a8824f478..409815a4066828 100644 --- a/arch/x86/kernel/apic/x2apic_phys.c +++ b/arch/x86/kernel/apic/x2apic_phys.c @@ -145,7 +145,6 @@ static struct apic apic_x2apic_phys __ro_after_init = { .probe = x2apic_phys_probe, .acpi_madt_oem_check = x2apic_acpi_madt_oem_check, - .delivery_mode = APIC_DELIVERY_MODE_FIXED, .dest_mode_logical = false, .disable_esr = 0, diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c index 1b0d7336a28fe9..f1766b18dcd07d 100644 --- a/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/arch/x86/kernel/apic/x2apic_uv_x.c @@ -805,7 +805,6 @@ static struct apic apic_x2apic_uv_x __ro_after_init = { .probe = uv_probe, .acpi_madt_oem_check = uv_acpi_madt_oem_check, - .delivery_mode = APIC_DELIVERY_MODE_FIXED, .dest_mode_logical = false, .disable_esr = 0, diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c index 5934ee5bc087ed..76a5ced278c2ae 100644 --- a/arch/x86/kernel/apm_32.c +++ b/arch/x86/kernel/apm_32.c @@ -420,7 +420,7 @@ static DEFINE_MUTEX(apm_mutex); * This is for buggy BIOS's that refer to (real mode) segment 0x40 * even though they are called in protected mode. */ -static struct desc_struct bad_bios_desc = GDT_ENTRY_INIT(0x4092, +static struct desc_struct bad_bios_desc = GDT_ENTRY_INIT(DESC_DATA32_BIOS, (unsigned long)__va(0x400UL), PAGE_SIZE - 0x400 - 1); static const char driver_version[] = "1.16ac"; /* no spaces */ diff --git a/arch/x86/kernel/callthunks.c b/arch/x86/kernel/callthunks.c index e9ad518a5003cd..64ad2ddea12194 100644 --- a/arch/x86/kernel/callthunks.c +++ b/arch/x86/kernel/callthunks.c @@ -233,14 +233,13 @@ patch_call_sites(s32 *start, s32 *end, const struct core_text *ct) } static __init_or_module void -patch_paravirt_call_sites(struct paravirt_patch_site *start, - struct paravirt_patch_site *end, - const struct core_text *ct) +patch_alt_call_sites(struct alt_instr *start, struct alt_instr *end, + const struct core_text *ct) { - struct paravirt_patch_site *p; + struct alt_instr *a; - for (p = start; p < end; p++) - patch_call(p->instr, ct); + for (a = start; a < end; a++) + patch_call((void *)&a->instr_offset + a->instr_offset, ct); } static __init_or_module void @@ -248,7 +247,7 @@ callthunks_setup(struct callthunk_sites *cs, const struct core_text *ct) { prdbg("Patching call sites %s\n", ct->name); patch_call_sites(cs->call_start, cs->call_end, ct); - patch_paravirt_call_sites(cs->pv_start, cs->pv_end, ct); + patch_alt_call_sites(cs->alt_start, cs->alt_end, ct); prdbg("Patching call sites done%s\n", ct->name); } @@ -257,8 +256,8 @@ void __init callthunks_patch_builtin_calls(void) struct callthunk_sites cs = { .call_start = __call_sites, .call_end = __call_sites_end, - .pv_start = __parainstructions, - .pv_end = __parainstructions_end + .alt_start = __alt_instructions, + .alt_end = __alt_instructions_end }; if (!cpu_feature_enabled(X86_FEATURE_CALL_DEPTH)) diff --git a/arch/x86/kernel/cfi.c b/arch/x86/kernel/cfi.c index 8674a5c0c031d3..e6bf78fac14622 100644 --- a/arch/x86/kernel/cfi.c +++ b/arch/x86/kernel/cfi.c @@ -4,10 +4,10 @@ * * Copyright (C) 2022 Google LLC */ -#include +#include +#include #include #include -#include /* * Returns the target address and the expected type when regs->ip points diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index f322ebd053a91e..f3abca334199d8 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -34,87 +34,6 @@ */ static u32 nodes_per_socket = 1; -/* - * AMD errata checking - * - * Errata are defined as arrays of ints using the AMD_LEGACY_ERRATUM() or - * AMD_OSVW_ERRATUM() macros. The latter is intended for newer errata that - * have an OSVW id assigned, which it takes as first argument. Both take a - * variable number of family-specific model-stepping ranges created by - * AMD_MODEL_RANGE(). - * - * Example: - * - * const int amd_erratum_319[] = - * AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x10, 0x2, 0x1, 0x4, 0x2), - * AMD_MODEL_RANGE(0x10, 0x8, 0x0, 0x8, 0x0), - * AMD_MODEL_RANGE(0x10, 0x9, 0x0, 0x9, 0x0)); - */ - -#define AMD_LEGACY_ERRATUM(...) { -1, __VA_ARGS__, 0 } -#define AMD_OSVW_ERRATUM(osvw_id, ...) { osvw_id, __VA_ARGS__, 0 } -#define AMD_MODEL_RANGE(f, m_start, s_start, m_end, s_end) \ - ((f << 24) | (m_start << 16) | (s_start << 12) | (m_end << 4) | (s_end)) -#define AMD_MODEL_RANGE_FAMILY(range) (((range) >> 24) & 0xff) -#define AMD_MODEL_RANGE_START(range) (((range) >> 12) & 0xfff) -#define AMD_MODEL_RANGE_END(range) ((range) & 0xfff) - -static const int amd_erratum_400[] = - AMD_OSVW_ERRATUM(1, AMD_MODEL_RANGE(0xf, 0x41, 0x2, 0xff, 0xf), - AMD_MODEL_RANGE(0x10, 0x2, 0x1, 0xff, 0xf)); - -static const int amd_erratum_383[] = - AMD_OSVW_ERRATUM(3, AMD_MODEL_RANGE(0x10, 0, 0, 0xff, 0xf)); - -/* #1054: Instructions Retired Performance Counter May Be Inaccurate */ -static const int amd_erratum_1054[] = - AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x17, 0, 0, 0x2f, 0xf)); - -static const int amd_zenbleed[] = - AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x17, 0x30, 0x0, 0x4f, 0xf), - AMD_MODEL_RANGE(0x17, 0x60, 0x0, 0x7f, 0xf), - AMD_MODEL_RANGE(0x17, 0x90, 0x0, 0x91, 0xf), - AMD_MODEL_RANGE(0x17, 0xa0, 0x0, 0xaf, 0xf)); - -static const int amd_div0[] = - AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x17, 0x00, 0x0, 0x2f, 0xf), - AMD_MODEL_RANGE(0x17, 0x50, 0x0, 0x5f, 0xf)); - -static const int amd_erratum_1485[] = - AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x19, 0x10, 0x0, 0x1f, 0xf), - AMD_MODEL_RANGE(0x19, 0x60, 0x0, 0xaf, 0xf)); - -static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum) -{ - int osvw_id = *erratum++; - u32 range; - u32 ms; - - if (osvw_id >= 0 && osvw_id < 65536 && - cpu_has(cpu, X86_FEATURE_OSVW)) { - u64 osvw_len; - - rdmsrl(MSR_AMD64_OSVW_ID_LENGTH, osvw_len); - if (osvw_id < osvw_len) { - u64 osvw_bits; - - rdmsrl(MSR_AMD64_OSVW_STATUS + (osvw_id >> 6), - osvw_bits); - return osvw_bits & (1ULL << (osvw_id & 0x3f)); - } - } - - /* OSVW unavailable or ID unknown, match family-model-stepping range */ - ms = (cpu->x86_model << 4) | cpu->x86_stepping; - while ((range = *erratum++)) - if ((cpu->x86 == AMD_MODEL_RANGE_FAMILY(range)) && - (ms >= AMD_MODEL_RANGE_START(range)) && - (ms <= AMD_MODEL_RANGE_END(range))) - return true; - - return false; -} - static inline int rdmsrl_amd_safe(unsigned msr, unsigned long long *p) { u32 gprs[8] = { 0 }; @@ -616,6 +535,62 @@ static void bsp_init_amd(struct cpuinfo_x86 *c) } resctrl_cpu_detect(c); + + /* Figure out Zen generations: */ + switch (c->x86) { + case 0x17: + switch (c->x86_model) { + case 0x00 ... 0x2f: + case 0x50 ... 0x5f: + setup_force_cpu_cap(X86_FEATURE_ZEN1); + break; + case 0x30 ... 0x4f: + case 0x60 ... 0x7f: + case 0x90 ... 0x91: + case 0xa0 ... 0xaf: + setup_force_cpu_cap(X86_FEATURE_ZEN2); + break; + default: + goto warn; + } + break; + + case 0x19: + switch (c->x86_model) { + case 0x00 ... 0x0f: + case 0x20 ... 0x5f: + setup_force_cpu_cap(X86_FEATURE_ZEN3); + break; + case 0x10 ... 0x1f: + case 0x60 ... 0xaf: + setup_force_cpu_cap(X86_FEATURE_ZEN4); + break; + default: + goto warn; + } + break; + + case 0x1a: + switch (c->x86_model) { + case 0x00 ... 0x0f: + case 0x20 ... 0x2f: + case 0x40 ... 0x4f: + case 0x70 ... 0x7f: + setup_force_cpu_cap(X86_FEATURE_ZEN5); + break; + default: + goto warn; + } + break; + + default: + break; + } + + return; + +warn: + WARN_ONCE(1, "Family 0x%x, model: 0x%x??\n", c->x86, c->x86_model); } static void early_detect_mem_encrypt(struct cpuinfo_x86 *c) @@ -739,15 +714,6 @@ static void early_init_amd(struct cpuinfo_x86 *c) if (c->x86 == 0x16 && c->x86_model <= 0xf) msr_set_bit(MSR_AMD64_LS_CFG, 15); - /* - * Check whether the machine is affected by erratum 400. This is - * used to select the proper idle routine and to enable the check - * whether the machine is affected in arch_post_acpi_init(), which - * sets the X86_BUG_AMD_APIC_C1E bug depending on the MSR check. - */ - if (cpu_has_amd_erratum(c, amd_erratum_400)) - set_cpu_bug(c, X86_BUG_AMD_E400); - early_detect_mem_encrypt(c); /* Re-enable TopologyExtensions if switched off by BIOS */ @@ -814,6 +780,16 @@ static void init_amd_k8(struct cpuinfo_x86 *c) msr_set_bit(MSR_K7_HWCR, 6); #endif set_cpu_bug(c, X86_BUG_SWAPGS_FENCE); + + /* + * Check models and steppings affected by erratum 400. This is + * used to select the proper idle routine and to enable the + * check whether the machine is affected in arch_post_acpi_subsys_init() + * which sets the X86_BUG_AMD_APIC_C1E bug depending on the MSR check. + */ + if (c->x86_model > 0x41 || + (c->x86_model == 0x41 && c->x86_stepping >= 0x2)) + setup_force_cpu_bug(X86_BUG_AMD_E400); } static void init_amd_gh(struct cpuinfo_x86 *c) @@ -847,8 +823,17 @@ static void init_amd_gh(struct cpuinfo_x86 *c) */ msr_clear_bit(MSR_AMD64_BU_CFG2, 24); - if (cpu_has_amd_erratum(c, amd_erratum_383)) - set_cpu_bug(c, X86_BUG_AMD_TLB_MMATCH); + set_cpu_bug(c, X86_BUG_AMD_TLB_MMATCH); + + /* + * Check models and steppings affected by erratum 400. This is + * used to select the proper idle routine and to enable the + * check whether the machine is affected in arch_post_acpi_subsys_init() + * which sets the X86_BUG_AMD_APIC_C1E bug depending on the MSR check. + */ + if (c->x86_model > 0x2 || + (c->x86_model == 0x2 && c->x86_stepping >= 0x1)) + setup_force_cpu_bug(X86_BUG_AMD_E400); } static void init_amd_ln(struct cpuinfo_x86 *c) @@ -941,6 +926,19 @@ static void init_amd_bd(struct cpuinfo_x86 *c) clear_rdrand_cpuid_bit(c); } +static void fix_erratum_1386(struct cpuinfo_x86 *c) +{ + /* + * Work around Erratum 1386. The XSAVES instruction malfunctions in + * certain circumstances on Zen1/2 uarch, and not all parts have had + * updated microcode at the time of writing (March 2023). + * + * Affected parts all have no supervisor XSAVE states, meaning that + * the XSAVEC instruction (which works fine) is equivalent. + */ + clear_cpu_cap(c, X86_FEATURE_XSAVES); +} + void init_spectral_chicken(struct cpuinfo_x86 *c) { #ifdef CONFIG_CPU_UNRET_ENTRY @@ -951,34 +949,28 @@ void init_spectral_chicken(struct cpuinfo_x86 *c) * * This suppresses speculation from the middle of a basic block, i.e. it * suppresses non-branch predictions. - * - * We use STIBP as a heuristic to filter out Zen2 from the rest of F17H */ - if (!cpu_has(c, X86_FEATURE_HYPERVISOR) && cpu_has(c, X86_FEATURE_AMD_STIBP)) { + if (!cpu_has(c, X86_FEATURE_HYPERVISOR)) { if (!rdmsrl_safe(MSR_ZEN2_SPECTRAL_CHICKEN, &value)) { value |= MSR_ZEN2_SPECTRAL_CHICKEN_BIT; wrmsrl_safe(MSR_ZEN2_SPECTRAL_CHICKEN, value); } } #endif - /* - * Work around Erratum 1386. The XSAVES instruction malfunctions in - * certain circumstances on Zen1/2 uarch, and not all parts have had - * updated microcode at the time of writing (March 2023). - * - * Affected parts all have no supervisor XSAVE states, meaning that - * the XSAVEC instruction (which works fine) is equivalent. - */ - clear_cpu_cap(c, X86_FEATURE_XSAVES); } -static void init_amd_zn(struct cpuinfo_x86 *c) +static void init_amd_zen_common(void) { - set_cpu_cap(c, X86_FEATURE_ZEN); - + setup_force_cpu_cap(X86_FEATURE_ZEN); #ifdef CONFIG_NUMA node_reclaim_distance = 32; #endif +} + +static void init_amd_zen1(struct cpuinfo_x86 *c) +{ + init_amd_zen_common(); + fix_erratum_1386(c); /* Fix up CPUID bits, but only if not virtualised. */ if (!cpu_has(c, X86_FEATURE_HYPERVISOR)) { @@ -986,15 +978,10 @@ static void init_amd_zn(struct cpuinfo_x86 *c) /* Erratum 1076: CPB feature bit not being set in CPUID. */ if (!cpu_has(c, X86_FEATURE_CPB)) set_cpu_cap(c, X86_FEATURE_CPB); - - /* - * Zen3 (Fam19 model < 0x10) parts are not susceptible to - * Branch Type Confusion, but predate the allocation of the - * BTC_NO bit. - */ - if (c->x86 == 0x19 && !cpu_has(c, X86_FEATURE_BTC_NO)) - set_cpu_cap(c, X86_FEATURE_BTC_NO); } + + pr_notice_once("AMD Zen1 DIV0 bug detected. Disable SMT for full protection.\n"); + setup_force_cpu_bug(X86_BUG_DIV0); } static bool cpu_has_zenbleed_microcode(void) @@ -1018,11 +1005,8 @@ static bool cpu_has_zenbleed_microcode(void) return true; } -static void zenbleed_check(struct cpuinfo_x86 *c) +static void zen2_zenbleed_check(struct cpuinfo_x86 *c) { - if (!cpu_has_amd_erratum(c, amd_zenbleed)) - return; - if (cpu_has(c, X86_FEATURE_HYPERVISOR)) return; @@ -1037,6 +1021,42 @@ static void zenbleed_check(struct cpuinfo_x86 *c) } } +static void init_amd_zen2(struct cpuinfo_x86 *c) +{ + init_amd_zen_common(); + init_spectral_chicken(c); + fix_erratum_1386(c); + zen2_zenbleed_check(c); +} + +static void init_amd_zen3(struct cpuinfo_x86 *c) +{ + init_amd_zen_common(); + + if (!cpu_has(c, X86_FEATURE_HYPERVISOR)) { + /* + * Zen3 (Fam19 model < 0x10) parts are not susceptible to + * Branch Type Confusion, but predate the allocation of the + * BTC_NO bit. + */ + if (!cpu_has(c, X86_FEATURE_BTC_NO)) + set_cpu_cap(c, X86_FEATURE_BTC_NO); + } +} + +static void init_amd_zen4(struct cpuinfo_x86 *c) +{ + init_amd_zen_common(); + + if (!cpu_has(c, X86_FEATURE_HYPERVISOR)) + msr_set_bit(MSR_ZEN4_BP_CFG, MSR_ZEN4_BP_CFG_SHARED_BTB_FIX_BIT); +} + +static void init_amd_zen5(struct cpuinfo_x86 *c) +{ + init_amd_zen_common(); +} + static void init_amd(struct cpuinfo_x86 *c) { u64 vm_cr; @@ -1072,11 +1092,19 @@ static void init_amd(struct cpuinfo_x86 *c) case 0x12: init_amd_ln(c); break; case 0x15: init_amd_bd(c); break; case 0x16: init_amd_jg(c); break; - case 0x17: init_spectral_chicken(c); - fallthrough; - case 0x19: init_amd_zn(c); break; } + if (boot_cpu_has(X86_FEATURE_ZEN1)) + init_amd_zen1(c); + else if (boot_cpu_has(X86_FEATURE_ZEN2)) + init_amd_zen2(c); + else if (boot_cpu_has(X86_FEATURE_ZEN3)) + init_amd_zen3(c); + else if (boot_cpu_has(X86_FEATURE_ZEN4)) + init_amd_zen4(c); + else if (boot_cpu_has(X86_FEATURE_ZEN5)) + init_amd_zen5(c); + /* * Enable workaround for FXSAVE leak on CPUs * without a XSaveErPtr feature @@ -1136,7 +1164,7 @@ static void init_amd(struct cpuinfo_x86 *c) * Counter May Be Inaccurate". */ if (cpu_has(c, X86_FEATURE_IRPERF) && - !cpu_has_amd_erratum(c, amd_erratum_1054)) + (boot_cpu_has(X86_FEATURE_ZEN1) && c->x86_model > 0x2f)) msr_set_bit(MSR_K7_HWCR, MSR_K7_HWCR_IRPERF_EN_BIT); check_null_seg_clears_base(c); @@ -1152,16 +1180,8 @@ static void init_amd(struct cpuinfo_x86 *c) cpu_has(c, X86_FEATURE_AUTOIBRS)) WARN_ON_ONCE(msr_set_bit(MSR_EFER, _EFER_AUTOIBRS)); - zenbleed_check(c); - - if (cpu_has_amd_erratum(c, amd_div0)) { - pr_notice_once("AMD Zen1 DIV0 bug detected. Disable SMT for full protection.\n"); - setup_force_cpu_bug(X86_BUG_DIV0); - } - - if (!cpu_has(c, X86_FEATURE_HYPERVISOR) && - cpu_has_amd_erratum(c, amd_erratum_1485)) - msr_set_bit(MSR_ZEN4_BP_CFG, MSR_ZEN4_BP_CFG_SHARED_BTB_FIX_BIT); + /* AMD CPUs don't need fencing after x2APIC/TSC_DEADLINE MSR writes. */ + clear_cpu_cap(c, X86_FEATURE_APIC_MSRS_FENCE); } #ifdef CONFIG_X86_32 @@ -1315,7 +1335,7 @@ static void zenbleed_check_cpu(void *unused) { struct cpuinfo_x86 *c = &cpu_data(smp_processor_id()); - zenbleed_check(c); + zen2_zenbleed_check(c); } void amd_check_microcode(void) diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index b14fc8c1c9538f..0b97bcde70c610 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -66,6 +66,7 @@ #include #include #include +#include #include "cpu.h" @@ -188,45 +189,37 @@ DEFINE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page) = { .gdt = { * TLS descriptors are currently at a different place compared to i386. * Hopefully nobody expects them at a fixed place (Wine?) */ - [GDT_ENTRY_KERNEL32_CS] = GDT_ENTRY_INIT(0xc09b, 0, 0xfffff), - [GDT_ENTRY_KERNEL_CS] = GDT_ENTRY_INIT(0xa09b, 0, 0xfffff), - [GDT_ENTRY_KERNEL_DS] = GDT_ENTRY_INIT(0xc093, 0, 0xfffff), - [GDT_ENTRY_DEFAULT_USER32_CS] = GDT_ENTRY_INIT(0xc0fb, 0, 0xfffff), - [GDT_ENTRY_DEFAULT_USER_DS] = GDT_ENTRY_INIT(0xc0f3, 0, 0xfffff), - [GDT_ENTRY_DEFAULT_USER_CS] = GDT_ENTRY_INIT(0xa0fb, 0, 0xfffff), + [GDT_ENTRY_KERNEL32_CS] = GDT_ENTRY_INIT(DESC_CODE32, 0, 0xfffff), + [GDT_ENTRY_KERNEL_CS] = GDT_ENTRY_INIT(DESC_CODE64, 0, 0xfffff), + [GDT_ENTRY_KERNEL_DS] = GDT_ENTRY_INIT(DESC_DATA64, 0, 0xfffff), + [GDT_ENTRY_DEFAULT_USER32_CS] = GDT_ENTRY_INIT(DESC_CODE32 | DESC_USER, 0, 0xfffff), + [GDT_ENTRY_DEFAULT_USER_DS] = GDT_ENTRY_INIT(DESC_DATA64 | DESC_USER, 0, 0xfffff), + [GDT_ENTRY_DEFAULT_USER_CS] = GDT_ENTRY_INIT(DESC_CODE64 | DESC_USER, 0, 0xfffff), #else - [GDT_ENTRY_KERNEL_CS] = GDT_ENTRY_INIT(0xc09a, 0, 0xfffff), - [GDT_ENTRY_KERNEL_DS] = GDT_ENTRY_INIT(0xc092, 0, 0xfffff), - [GDT_ENTRY_DEFAULT_USER_CS] = GDT_ENTRY_INIT(0xc0fa, 0, 0xfffff), - [GDT_ENTRY_DEFAULT_USER_DS] = GDT_ENTRY_INIT(0xc0f2, 0, 0xfffff), + [GDT_ENTRY_KERNEL_CS] = GDT_ENTRY_INIT(DESC_CODE32, 0, 0xfffff), + [GDT_ENTRY_KERNEL_DS] = GDT_ENTRY_INIT(DESC_DATA32, 0, 0xfffff), + [GDT_ENTRY_DEFAULT_USER_CS] = GDT_ENTRY_INIT(DESC_CODE32 | DESC_USER, 0, 0xfffff), + [GDT_ENTRY_DEFAULT_USER_DS] = GDT_ENTRY_INIT(DESC_DATA32 | DESC_USER, 0, 0xfffff), /* * Segments used for calling PnP BIOS have byte granularity. * They code segments and data segments have fixed 64k limits, * the transfer segment sizes are set at run time. */ - /* 32-bit code */ - [GDT_ENTRY_PNPBIOS_CS32] = GDT_ENTRY_INIT(0x409a, 0, 0xffff), - /* 16-bit code */ - [GDT_ENTRY_PNPBIOS_CS16] = GDT_ENTRY_INIT(0x009a, 0, 0xffff), - /* 16-bit data */ - [GDT_ENTRY_PNPBIOS_DS] = GDT_ENTRY_INIT(0x0092, 0, 0xffff), - /* 16-bit data */ - [GDT_ENTRY_PNPBIOS_TS1] = GDT_ENTRY_INIT(0x0092, 0, 0), - /* 16-bit data */ - [GDT_ENTRY_PNPBIOS_TS2] = GDT_ENTRY_INIT(0x0092, 0, 0), + [GDT_ENTRY_PNPBIOS_CS32] = GDT_ENTRY_INIT(DESC_CODE32_BIOS, 0, 0xffff), + [GDT_ENTRY_PNPBIOS_CS16] = GDT_ENTRY_INIT(DESC_CODE16, 0, 0xffff), + [GDT_ENTRY_PNPBIOS_DS] = GDT_ENTRY_INIT(DESC_DATA16, 0, 0xffff), + [GDT_ENTRY_PNPBIOS_TS1] = GDT_ENTRY_INIT(DESC_DATA16, 0, 0), + [GDT_ENTRY_PNPBIOS_TS2] = GDT_ENTRY_INIT(DESC_DATA16, 0, 0), /* * The APM segments have byte granularity and their bases * are set at run time. All have 64k limits. */ - /* 32-bit code */ - [GDT_ENTRY_APMBIOS_BASE] = GDT_ENTRY_INIT(0x409a, 0, 0xffff), - /* 16-bit code */ - [GDT_ENTRY_APMBIOS_BASE+1] = GDT_ENTRY_INIT(0x009a, 0, 0xffff), - /* data */ - [GDT_ENTRY_APMBIOS_BASE+2] = GDT_ENTRY_INIT(0x4092, 0, 0xffff), - - [GDT_ENTRY_ESPFIX_SS] = GDT_ENTRY_INIT(0xc092, 0, 0xfffff), - [GDT_ENTRY_PERCPU] = GDT_ENTRY_INIT(0xc092, 0, 0xfffff), + [GDT_ENTRY_APMBIOS_BASE] = GDT_ENTRY_INIT(DESC_CODE32_BIOS, 0, 0xffff), + [GDT_ENTRY_APMBIOS_BASE+1] = GDT_ENTRY_INIT(DESC_CODE16, 0, 0xffff), + [GDT_ENTRY_APMBIOS_BASE+2] = GDT_ENTRY_INIT(DESC_DATA32_BIOS, 0, 0xffff), + + [GDT_ENTRY_ESPFIX_SS] = GDT_ENTRY_INIT(DESC_DATA32, 0, 0xfffff), + [GDT_ENTRY_PERCPU] = GDT_ENTRY_INIT(DESC_DATA32, 0, 0xfffff), #endif } }; EXPORT_PER_CPU_SYMBOL_GPL(gdt_page); @@ -1856,6 +1849,13 @@ static void identify_cpu(struct cpuinfo_x86 *c) c->topo.apicid = apic->phys_pkg_id(c->topo.initial_apicid, 0); #endif + + /* + * Set default APIC and TSC_DEADLINE MSR fencing flag. AMD and + * Hygon will clear it in ->c_init() below. + */ + set_cpu_cap(c, X86_FEATURE_APIC_MSRS_FENCE); + /* * Vendor-specific initialization. In this section we * canonicalize the feature flags, meaning if there are @@ -1987,6 +1987,7 @@ static __init void identify_boot_cpu(void) setup_cr_pinning(); tsx_init(); + tdx_init(); lkgs_init(); } diff --git a/arch/x86/kernel/cpu/hygon.c b/arch/x86/kernel/cpu/hygon.c index 6f247d66758de6..f0cd95502faaee 100644 --- a/arch/x86/kernel/cpu/hygon.c +++ b/arch/x86/kernel/cpu/hygon.c @@ -354,6 +354,9 @@ static void init_hygon(struct cpuinfo_x86 *c) set_cpu_bug(c, X86_BUG_SYSRET_SS_ATTRS); check_null_seg_clears_base(c); + + /* Hygon CPUs don't need fencing after x2APIC/TSC_DEADLINE MSR writes. */ + clear_cpu_cap(c, X86_FEATURE_APIC_MSRS_FENCE); } static void cpu_detect_tlb_hygon(struct cpuinfo_x86 *c) diff --git a/arch/x86/kernel/cpu/intel_epb.c b/arch/x86/kernel/cpu/intel_epb.c index e4c3ba91321c95..f18d35fe27a928 100644 --- a/arch/x86/kernel/cpu/intel_epb.c +++ b/arch/x86/kernel/cpu/intel_epb.c @@ -237,4 +237,4 @@ err_out_online: cpuhp_remove_state(CPUHP_AP_X86_INTEL_EPB_ONLINE); return ret; } -subsys_initcall(intel_epb_init); +late_initcall(intel_epb_init); diff --git a/arch/x86/kernel/cpu/mce/amd.c b/arch/x86/kernel/cpu/mce/amd.c index f3517b8a8e91a2..2b46eb0fdf3acd 100644 --- a/arch/x86/kernel/cpu/mce/amd.c +++ b/arch/x86/kernel/cpu/mce/amd.c @@ -87,42 +87,40 @@ struct smca_bank { static DEFINE_PER_CPU_READ_MOSTLY(struct smca_bank[MAX_NR_BANKS], smca_banks); static DEFINE_PER_CPU_READ_MOSTLY(u8[N_SMCA_BANK_TYPES], smca_bank_counts); -struct smca_bank_name { - const char *name; /* Short name for sysfs */ - const char *long_name; /* Long name for pretty-printing */ -}; - -static struct smca_bank_name smca_names[] = { - [SMCA_LS ... SMCA_LS_V2] = { "load_store", "Load Store Unit" }, - [SMCA_IF] = { "insn_fetch", "Instruction Fetch Unit" }, - [SMCA_L2_CACHE] = { "l2_cache", "L2 Cache" }, - [SMCA_DE] = { "decode_unit", "Decode Unit" }, - [SMCA_RESERVED] = { "reserved", "Reserved" }, - [SMCA_EX] = { "execution_unit", "Execution Unit" }, - [SMCA_FP] = { "floating_point", "Floating Point Unit" }, - [SMCA_L3_CACHE] = { "l3_cache", "L3 Cache" }, - [SMCA_CS ... SMCA_CS_V2] = { "coherent_slave", "Coherent Slave" }, - [SMCA_PIE] = { "pie", "Power, Interrupts, etc." }, +static const char * const smca_names[] = { + [SMCA_LS ... SMCA_LS_V2] = "load_store", + [SMCA_IF] = "insn_fetch", + [SMCA_L2_CACHE] = "l2_cache", + [SMCA_DE] = "decode_unit", + [SMCA_RESERVED] = "reserved", + [SMCA_EX] = "execution_unit", + [SMCA_FP] = "floating_point", + [SMCA_L3_CACHE] = "l3_cache", + [SMCA_CS ... SMCA_CS_V2] = "coherent_slave", + [SMCA_PIE] = "pie", /* UMC v2 is separate because both of them can exist in a single system. */ - [SMCA_UMC] = { "umc", "Unified Memory Controller" }, - [SMCA_UMC_V2] = { "umc_v2", "Unified Memory Controller v2" }, - [SMCA_PB] = { "param_block", "Parameter Block" }, - [SMCA_PSP ... SMCA_PSP_V2] = { "psp", "Platform Security Processor" }, - [SMCA_SMU ... SMCA_SMU_V2] = { "smu", "System Management Unit" }, - [SMCA_MP5] = { "mp5", "Microprocessor 5 Unit" }, - [SMCA_MPDMA] = { "mpdma", "MPDMA Unit" }, - [SMCA_NBIO] = { "nbio", "Northbridge IO Unit" }, - [SMCA_PCIE ... SMCA_PCIE_V2] = { "pcie", "PCI Express Unit" }, - [SMCA_XGMI_PCS] = { "xgmi_pcs", "Ext Global Memory Interconnect PCS Unit" }, - [SMCA_NBIF] = { "nbif", "NBIF Unit" }, - [SMCA_SHUB] = { "shub", "System Hub Unit" }, - [SMCA_SATA] = { "sata", "SATA Unit" }, - [SMCA_USB] = { "usb", "USB Unit" }, - [SMCA_GMI_PCS] = { "gmi_pcs", "Global Memory Interconnect PCS Unit" }, - [SMCA_XGMI_PHY] = { "xgmi_phy", "Ext Global Memory Interconnect PHY Unit" }, - [SMCA_WAFL_PHY] = { "wafl_phy", "WAFL PHY Unit" }, - [SMCA_GMI_PHY] = { "gmi_phy", "Global Memory Interconnect PHY Unit" }, + [SMCA_UMC] = "umc", + [SMCA_UMC_V2] = "umc_v2", + [SMCA_MA_LLC] = "ma_llc", + [SMCA_PB] = "param_block", + [SMCA_PSP ... SMCA_PSP_V2] = "psp", + [SMCA_SMU ... SMCA_SMU_V2] = "smu", + [SMCA_MP5] = "mp5", + [SMCA_MPDMA] = "mpdma", + [SMCA_NBIO] = "nbio", + [SMCA_PCIE ... SMCA_PCIE_V2] = "pcie", + [SMCA_XGMI_PCS] = "xgmi_pcs", + [SMCA_NBIF] = "nbif", + [SMCA_SHUB] = "shub", + [SMCA_SATA] = "sata", + [SMCA_USB] = "usb", + [SMCA_USR_DP] = "usr_dp", + [SMCA_USR_CP] = "usr_cp", + [SMCA_GMI_PCS] = "gmi_pcs", + [SMCA_XGMI_PHY] = "xgmi_phy", + [SMCA_WAFL_PHY] = "wafl_phy", + [SMCA_GMI_PHY] = "gmi_phy", }; static const char *smca_get_name(enum smca_bank_types t) @@ -130,17 +128,8 @@ static const char *smca_get_name(enum smca_bank_types t) if (t >= N_SMCA_BANK_TYPES) return NULL; - return smca_names[t].name; -} - -const char *smca_get_long_name(enum smca_bank_types t) -{ - if (t >= N_SMCA_BANK_TYPES) - return NULL; - - return smca_names[t].long_name; + return smca_names[t]; } -EXPORT_SYMBOL_GPL(smca_get_long_name); enum smca_bank_types smca_get_bank_type(unsigned int cpu, unsigned int bank) { @@ -178,6 +167,7 @@ static const struct smca_hwid smca_hwid_mcatypes[] = { { SMCA_CS, HWID_MCATYPE(0x2E, 0x0) }, { SMCA_PIE, HWID_MCATYPE(0x2E, 0x1) }, { SMCA_CS_V2, HWID_MCATYPE(0x2E, 0x2) }, + { SMCA_MA_LLC, HWID_MCATYPE(0x2E, 0x4) }, /* Unified Memory Controller MCA type */ { SMCA_UMC, HWID_MCATYPE(0x96, 0x0) }, @@ -212,6 +202,8 @@ static const struct smca_hwid smca_hwid_mcatypes[] = { { SMCA_SHUB, HWID_MCATYPE(0x80, 0x0) }, { SMCA_SATA, HWID_MCATYPE(0xA8, 0x0) }, { SMCA_USB, HWID_MCATYPE(0xAA, 0x0) }, + { SMCA_USR_DP, HWID_MCATYPE(0x170, 0x0) }, + { SMCA_USR_CP, HWID_MCATYPE(0x180, 0x0) }, { SMCA_GMI_PCS, HWID_MCATYPE(0x241, 0x0) }, { SMCA_XGMI_PHY, HWID_MCATYPE(0x259, 0x0) }, { SMCA_WAFL_PHY, HWID_MCATYPE(0x267, 0x0) }, diff --git a/arch/x86/kernel/cpu/mce/core.c b/arch/x86/kernel/cpu/mce/core.c index 7b397370b4d64c..bc39252bc54f2e 100644 --- a/arch/x86/kernel/cpu/mce/core.c +++ b/arch/x86/kernel/cpu/mce/core.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -52,6 +53,7 @@ #include #include #include +#include #include "internal.h" @@ -228,11 +230,20 @@ static void wait_for_panic(void) panic("Panicing machine check CPU died"); } +static const char *mce_dump_aux_info(struct mce *m) +{ + if (boot_cpu_has_bug(X86_BUG_TDX_PW_MCE)) + return tdx_dump_mce_info(m); + + return NULL; +} + static noinstr void mce_panic(const char *msg, struct mce *final, char *exp) { struct llist_node *pending; struct mce_evt_llist *l; int apei_err = 0; + const char *memmsg; /* * Allow instrumentation around external facilities usage. Not that it @@ -283,9 +294,29 @@ static noinstr void mce_panic(const char *msg, struct mce *final, char *exp) } if (exp) pr_emerg(HW_ERR "Machine check: %s\n", exp); + + memmsg = mce_dump_aux_info(final); + if (memmsg) + pr_emerg(HW_ERR "Machine check: %s\n", memmsg); + if (!fake_panic) { if (panic_timeout == 0) panic_timeout = mca_cfg.panic_timeout; + + /* + * Kdump skips the poisoned page in order to avoid + * touching the error bits again. Poison the page even + * if the error is fatal and the machine is about to + * panic. + */ + if (kexec_crash_loaded()) { + if (final && (final->status & MCI_STATUS_ADDRV)) { + struct page *p; + p = pfn_to_online_page(final->addr >> PAGE_SHIFT); + if (p) + SetPageHWPoison(p); + } + } panic(msg); } else pr_emerg(HW_ERR "Fake kernel panic: %s\n", msg); @@ -670,6 +701,16 @@ bool machine_check_poll(enum mcp_flags flags, mce_banks_t *b) barrier(); m.status = mce_rdmsrl(mca_msr_reg(i, MCA_STATUS)); + /* + * Update storm tracking here, before checking for the + * MCI_STATUS_VAL bit. Valid corrected errors count + * towards declaring, or maintaining, storm status. No + * error in a bank counts towards avoiding, or ending, + * storm status. + */ + if (!mca_cfg.cmci_disabled) + mce_track_storm(&m); + /* If this entry is not valid, ignore it */ if (!(m.status & MCI_STATUS_VAL)) continue; @@ -1601,13 +1642,6 @@ static unsigned long check_interval = INITIAL_CHECK_INTERVAL; static DEFINE_PER_CPU(unsigned long, mce_next_interval); /* in jiffies */ static DEFINE_PER_CPU(struct timer_list, mce_timer); -static unsigned long mce_adjust_timer_default(unsigned long interval) -{ - return interval; -} - -static unsigned long (*mce_adjust_timer)(unsigned long interval) = mce_adjust_timer_default; - static void __start_timer(struct timer_list *t, unsigned long interval) { unsigned long when = jiffies + interval; @@ -1637,15 +1671,9 @@ static void mce_timer_fn(struct timer_list *t) iv = __this_cpu_read(mce_next_interval); - if (mce_available(this_cpu_ptr(&cpu_info))) { + if (mce_available(this_cpu_ptr(&cpu_info))) mc_poll_banks(); - if (mce_intel_cmci_poll()) { - iv = mce_adjust_timer(iv); - goto done; - } - } - /* * Alert userspace if needed. If we logged an MCE, reduce the polling * interval, otherwise increase the polling interval. @@ -1655,23 +1683,29 @@ static void mce_timer_fn(struct timer_list *t) else iv = min(iv * 2, round_jiffies_relative(check_interval * HZ)); -done: - __this_cpu_write(mce_next_interval, iv); - __start_timer(t, iv); + if (mce_get_storm_mode()) { + __start_timer(t, HZ); + } else { + __this_cpu_write(mce_next_interval, iv); + __start_timer(t, iv); + } } /* - * Ensure that the timer is firing in @interval from now. + * When a storm starts on any bank on this CPU, switch to polling + * once per second. When the storm ends, revert to the default + * polling interval. */ -void mce_timer_kick(unsigned long interval) +void mce_timer_kick(bool storm) { struct timer_list *t = this_cpu_ptr(&mce_timer); - unsigned long iv = __this_cpu_read(mce_next_interval); - __start_timer(t, interval); + mce_set_storm_mode(storm); - if (interval < iv) - __this_cpu_write(mce_next_interval, interval); + if (storm) + __start_timer(t, HZ); + else + __this_cpu_write(mce_next_interval, check_interval * HZ); } /* Must not be called in IRQ context where del_timer_sync() can deadlock */ @@ -1995,7 +2029,6 @@ static void mce_zhaoxin_feature_init(struct cpuinfo_x86 *c) intel_init_cmci(); intel_init_lmce(); - mce_adjust_timer = cmci_intel_adjust_timer; } static void mce_zhaoxin_feature_clear(struct cpuinfo_x86 *c) @@ -2008,7 +2041,6 @@ static void __mcheck_cpu_init_vendor(struct cpuinfo_x86 *c) switch (c->x86_vendor) { case X86_VENDOR_INTEL: mce_intel_feature_init(c); - mce_adjust_timer = cmci_intel_adjust_timer; break; case X86_VENDOR_AMD: { @@ -2568,9 +2600,6 @@ static int mce_device_create(unsigned int cpu) int err; int i, j; - if (!mce_available(&boot_cpu_data)) - return -EIO; - dev = per_cpu(mce_device, cpu); if (dev) return 0; @@ -2665,8 +2694,6 @@ static void mce_reenable_cpu(void) static int mce_cpu_dead(unsigned int cpu) { - mce_intel_hcpu_update(cpu); - /* intentionally ignoring frozen here */ if (!cpuhp_tasks_frozen) cmci_rediscover(); diff --git a/arch/x86/kernel/cpu/mce/inject.c b/arch/x86/kernel/cpu/mce/inject.c index 4d8d4bcf915ddd..72f0695c3dc1dd 100644 --- a/arch/x86/kernel/cpu/mce/inject.c +++ b/arch/x86/kernel/cpu/mce/inject.c @@ -746,6 +746,7 @@ static void check_hw_inj_possible(void) wrmsrl_safe(mca_msr_reg(bank, MCA_STATUS), status); rdmsrl_safe(mca_msr_reg(bank, MCA_STATUS), &status); + wrmsrl_safe(mca_msr_reg(bank, MCA_STATUS), 0); if (!status) { hw_injection_possible = false; diff --git a/arch/x86/kernel/cpu/mce/intel.c b/arch/x86/kernel/cpu/mce/intel.c index 52bce533ddcc7e..399b62e223d2db 100644 --- a/arch/x86/kernel/cpu/mce/intel.c +++ b/arch/x86/kernel/cpu/mce/intel.c @@ -41,15 +41,6 @@ */ static DEFINE_PER_CPU(mce_banks_t, mce_banks_owned); -/* - * CMCI storm detection backoff counter - * - * During storm, we reset this counter to INITIAL_CHECK_INTERVAL in case we've - * encountered an error. If not, we decrement it by one. We signal the end of - * the CMCI storm when it reaches 0. - */ -static DEFINE_PER_CPU(int, cmci_backoff_cnt); - /* * cmci_discover_lock protects against parallel discovery attempts * which could race against each other. @@ -63,22 +54,26 @@ static DEFINE_RAW_SPINLOCK(cmci_discover_lock); */ static DEFINE_SPINLOCK(cmci_poll_lock); +/* Linux non-storm CMCI threshold (may be overridden by BIOS) */ #define CMCI_THRESHOLD 1 -#define CMCI_POLL_INTERVAL (30 * HZ) -#define CMCI_STORM_INTERVAL (HZ) -#define CMCI_STORM_THRESHOLD 15 -static DEFINE_PER_CPU(unsigned long, cmci_time_stamp); -static DEFINE_PER_CPU(unsigned int, cmci_storm_cnt); -static DEFINE_PER_CPU(unsigned int, cmci_storm_state); - -enum { - CMCI_STORM_NONE, - CMCI_STORM_ACTIVE, - CMCI_STORM_SUBSIDED, -}; +/* + * MCi_CTL2 threshold for each bank when there is no storm. + * Default value for each bank may have been set by BIOS. + */ +static u16 cmci_threshold[MAX_NR_BANKS]; -static atomic_t cmci_storm_on_cpus; +/* + * High threshold to limit CMCI rate during storms. Max supported is + * 0x7FFF. Use this slightly smaller value so it has a distinctive + * signature when some asks "Why am I not seeing all corrected errors?" + * A high threshold is used instead of just disabling CMCI for a + * bank because both corrected and uncorrected errors may be logged + * in the same bank and signalled with CMCI. The threshold only applies + * to corrected errors, so keeping CMCI enabled means that uncorrected + * errors will still be processed in a timely fashion. + */ +#define CMCI_STORM_THRESHOLD 32749 static int cmci_supported(int *banks) { @@ -134,204 +129,166 @@ static bool lmce_supported(void) return tmp & FEAT_CTL_LMCE_ENABLED; } -bool mce_intel_cmci_poll(void) +/* + * Set a new CMCI threshold value. Preserve the state of the + * MCI_CTL2_CMCI_EN bit in case this happens during a + * cmci_rediscover() operation. + */ +static void cmci_set_threshold(int bank, int thresh) { - if (__this_cpu_read(cmci_storm_state) == CMCI_STORM_NONE) - return false; - - /* - * Reset the counter if we've logged an error in the last poll - * during the storm. - */ - if (machine_check_poll(0, this_cpu_ptr(&mce_banks_owned))) - this_cpu_write(cmci_backoff_cnt, INITIAL_CHECK_INTERVAL); - else - this_cpu_dec(cmci_backoff_cnt); + unsigned long flags; + u64 val; - return true; + raw_spin_lock_irqsave(&cmci_discover_lock, flags); + rdmsrl(MSR_IA32_MCx_CTL2(bank), val); + val &= ~MCI_CTL2_CMCI_THRESHOLD_MASK; + wrmsrl(MSR_IA32_MCx_CTL2(bank), val | thresh); + raw_spin_unlock_irqrestore(&cmci_discover_lock, flags); } -void mce_intel_hcpu_update(unsigned long cpu) +void mce_intel_handle_storm(int bank, bool on) { - if (per_cpu(cmci_storm_state, cpu) == CMCI_STORM_ACTIVE) - atomic_dec(&cmci_storm_on_cpus); + if (on) + cmci_set_threshold(bank, CMCI_STORM_THRESHOLD); + else + cmci_set_threshold(bank, cmci_threshold[bank]); +} - per_cpu(cmci_storm_state, cpu) = CMCI_STORM_NONE; +/* + * The interrupt handler. This is called on every event. + * Just call the poller directly to log any events. + * This could in theory increase the threshold under high load, + * but doesn't for now. + */ +static void intel_threshold_interrupt(void) +{ + machine_check_poll(MCP_TIMESTAMP, this_cpu_ptr(&mce_banks_owned)); } -static void cmci_toggle_interrupt_mode(bool on) +/* + * Check all the reasons why current CPU cannot claim + * ownership of a bank. + * 1: CPU already owns this bank + * 2: BIOS owns this bank + * 3: Some other CPU owns this bank + */ +static bool cmci_skip_bank(int bank, u64 *val) { - unsigned long flags, *owned; - int bank; - u64 val; + unsigned long *owned = (void *)this_cpu_ptr(&mce_banks_owned); - raw_spin_lock_irqsave(&cmci_discover_lock, flags); - owned = this_cpu_ptr(mce_banks_owned); - for_each_set_bit(bank, owned, MAX_NR_BANKS) { - rdmsrl(MSR_IA32_MCx_CTL2(bank), val); + if (test_bit(bank, owned)) + return true; - if (on) - val |= MCI_CTL2_CMCI_EN; - else - val &= ~MCI_CTL2_CMCI_EN; + /* Skip banks in firmware first mode */ + if (test_bit(bank, mce_banks_ce_disabled)) + return true; - wrmsrl(MSR_IA32_MCx_CTL2(bank), val); - } - raw_spin_unlock_irqrestore(&cmci_discover_lock, flags); -} + rdmsrl(MSR_IA32_MCx_CTL2(bank), *val); -unsigned long cmci_intel_adjust_timer(unsigned long interval) -{ - if ((this_cpu_read(cmci_backoff_cnt) > 0) && - (__this_cpu_read(cmci_storm_state) == CMCI_STORM_ACTIVE)) { - mce_notify_irq(); - return CMCI_STORM_INTERVAL; + /* Already owned by someone else? */ + if (*val & MCI_CTL2_CMCI_EN) { + clear_bit(bank, owned); + __clear_bit(bank, this_cpu_ptr(mce_poll_banks)); + return true; } - switch (__this_cpu_read(cmci_storm_state)) { - case CMCI_STORM_ACTIVE: - - /* - * We switch back to interrupt mode once the poll timer has - * silenced itself. That means no events recorded and the timer - * interval is back to our poll interval. - */ - __this_cpu_write(cmci_storm_state, CMCI_STORM_SUBSIDED); - if (!atomic_sub_return(1, &cmci_storm_on_cpus)) - pr_notice("CMCI storm subsided: switching to interrupt mode\n"); + return false; +} - fallthrough; +/* + * Decide which CMCI interrupt threshold to use: + * 1: If this bank is in storm mode from whichever CPU was + * the previous owner, stay in storm mode. + * 2: If ignoring any threshold set by BIOS, set Linux default + * 3: Try to honor BIOS threshold (unless buggy BIOS set it at zero). + */ +static u64 cmci_pick_threshold(u64 val, int *bios_zero_thresh) +{ + if ((val & MCI_CTL2_CMCI_THRESHOLD_MASK) == CMCI_STORM_THRESHOLD) + return val; - case CMCI_STORM_SUBSIDED: + if (!mca_cfg.bios_cmci_threshold) { + val &= ~MCI_CTL2_CMCI_THRESHOLD_MASK; + val |= CMCI_THRESHOLD; + } else if (!(val & MCI_CTL2_CMCI_THRESHOLD_MASK)) { /* - * We wait for all CPUs to go back to SUBSIDED state. When that - * happens we switch back to interrupt mode. + * If bios_cmci_threshold boot option was specified + * but the threshold is zero, we'll try to initialize + * it to 1. */ - if (!atomic_read(&cmci_storm_on_cpus)) { - __this_cpu_write(cmci_storm_state, CMCI_STORM_NONE); - cmci_toggle_interrupt_mode(true); - cmci_recheck(); - } - return CMCI_POLL_INTERVAL; - default: - - /* We have shiny weather. Let the poll do whatever it thinks. */ - return interval; + *bios_zero_thresh = 1; + val |= CMCI_THRESHOLD; } + + return val; } -static bool cmci_storm_detect(void) +/* + * Try to claim ownership of a bank. + */ +static void cmci_claim_bank(int bank, u64 val, int bios_zero_thresh, int *bios_wrong_thresh) { - unsigned int cnt = __this_cpu_read(cmci_storm_cnt); - unsigned long ts = __this_cpu_read(cmci_time_stamp); - unsigned long now = jiffies; - int r; + struct mca_storm_desc *storm = this_cpu_ptr(&storm_desc); - if (__this_cpu_read(cmci_storm_state) != CMCI_STORM_NONE) - return true; + val |= MCI_CTL2_CMCI_EN; + wrmsrl(MSR_IA32_MCx_CTL2(bank), val); + rdmsrl(MSR_IA32_MCx_CTL2(bank), val); - if (time_before_eq(now, ts + CMCI_STORM_INTERVAL)) { - cnt++; - } else { - cnt = 1; - __this_cpu_write(cmci_time_stamp, now); + /* If the enable bit did not stick, this bank should be polled. */ + if (!(val & MCI_CTL2_CMCI_EN)) { + WARN_ON(!test_bit(bank, this_cpu_ptr(mce_poll_banks))); + storm->banks[bank].poll_only = true; + return; } - __this_cpu_write(cmci_storm_cnt, cnt); - if (cnt <= CMCI_STORM_THRESHOLD) - return false; - - cmci_toggle_interrupt_mode(false); - __this_cpu_write(cmci_storm_state, CMCI_STORM_ACTIVE); - r = atomic_add_return(1, &cmci_storm_on_cpus); - mce_timer_kick(CMCI_STORM_INTERVAL); - this_cpu_write(cmci_backoff_cnt, INITIAL_CHECK_INTERVAL); + /* This CPU successfully set the enable bit. */ + set_bit(bank, (void *)this_cpu_ptr(&mce_banks_owned)); - if (r == 1) - pr_notice("CMCI storm detected: switching to poll mode\n"); - return true; -} + if ((val & MCI_CTL2_CMCI_THRESHOLD_MASK) == CMCI_STORM_THRESHOLD) { + pr_notice("CPU%d BANK%d CMCI inherited storm\n", smp_processor_id(), bank); + mce_inherit_storm(bank); + cmci_storm_begin(bank); + } else { + __clear_bit(bank, this_cpu_ptr(mce_poll_banks)); + } -/* - * The interrupt handler. This is called on every event. - * Just call the poller directly to log any events. - * This could in theory increase the threshold under high load, - * but doesn't for now. - */ -static void intel_threshold_interrupt(void) -{ - if (cmci_storm_detect()) - return; + /* + * We are able to set thresholds for some banks that + * had a threshold of 0. This means the BIOS has not + * set the thresholds properly or does not work with + * this boot option. Note down now and report later. + */ + if (mca_cfg.bios_cmci_threshold && bios_zero_thresh && + (val & MCI_CTL2_CMCI_THRESHOLD_MASK)) + *bios_wrong_thresh = 1; - machine_check_poll(MCP_TIMESTAMP, this_cpu_ptr(&mce_banks_owned)); + /* Save default threshold for each bank */ + if (cmci_threshold[bank] == 0) + cmci_threshold[bank] = val & MCI_CTL2_CMCI_THRESHOLD_MASK; } /* * Enable CMCI (Corrected Machine Check Interrupt) for available MCE banks * on this CPU. Use the algorithm recommended in the SDM to discover shared - * banks. + * banks. Called during initial bootstrap, and also for hotplug CPU operations + * to rediscover/reassign machine check banks. */ static void cmci_discover(int banks) { - unsigned long *owned = (void *)this_cpu_ptr(&mce_banks_owned); + int bios_wrong_thresh = 0; unsigned long flags; int i; - int bios_wrong_thresh = 0; raw_spin_lock_irqsave(&cmci_discover_lock, flags); for (i = 0; i < banks; i++) { u64 val; int bios_zero_thresh = 0; - if (test_bit(i, owned)) + if (cmci_skip_bank(i, &val)) continue; - /* Skip banks in firmware first mode */ - if (test_bit(i, mce_banks_ce_disabled)) - continue; - - rdmsrl(MSR_IA32_MCx_CTL2(i), val); - - /* Already owned by someone else? */ - if (val & MCI_CTL2_CMCI_EN) { - clear_bit(i, owned); - __clear_bit(i, this_cpu_ptr(mce_poll_banks)); - continue; - } - - if (!mca_cfg.bios_cmci_threshold) { - val &= ~MCI_CTL2_CMCI_THRESHOLD_MASK; - val |= CMCI_THRESHOLD; - } else if (!(val & MCI_CTL2_CMCI_THRESHOLD_MASK)) { - /* - * If bios_cmci_threshold boot option was specified - * but the threshold is zero, we'll try to initialize - * it to 1. - */ - bios_zero_thresh = 1; - val |= CMCI_THRESHOLD; - } - - val |= MCI_CTL2_CMCI_EN; - wrmsrl(MSR_IA32_MCx_CTL2(i), val); - rdmsrl(MSR_IA32_MCx_CTL2(i), val); - - /* Did the enable bit stick? -- the bank supports CMCI */ - if (val & MCI_CTL2_CMCI_EN) { - set_bit(i, owned); - __clear_bit(i, this_cpu_ptr(mce_poll_banks)); - /* - * We are able to set thresholds for some banks that - * had a threshold of 0. This means the BIOS has not - * set the thresholds properly or does not work with - * this boot option. Note down now and report later. - */ - if (mca_cfg.bios_cmci_threshold && bios_zero_thresh && - (val & MCI_CTL2_CMCI_THRESHOLD_MASK)) - bios_wrong_thresh = 1; - } else { - WARN_ON(!test_bit(i, this_cpu_ptr(mce_poll_banks))); - } + val = cmci_pick_threshold(val, &bios_zero_thresh); + cmci_claim_bank(i, val, bios_zero_thresh, &bios_wrong_thresh); } raw_spin_unlock_irqrestore(&cmci_discover_lock, flags); if (mca_cfg.bios_cmci_threshold && bios_wrong_thresh) { @@ -370,6 +327,9 @@ static void __cmci_disable_bank(int bank) val &= ~MCI_CTL2_CMCI_EN; wrmsrl(MSR_IA32_MCx_CTL2(bank), val); __clear_bit(bank, this_cpu_ptr(mce_banks_owned)); + + if ((val & MCI_CTL2_CMCI_THRESHOLD_MASK) == CMCI_STORM_THRESHOLD) + cmci_storm_end(bank); } /* diff --git a/arch/x86/kernel/cpu/mce/internal.h b/arch/x86/kernel/cpu/mce/internal.h index e13a26c9c0ac67..01f8f03969e63e 100644 --- a/arch/x86/kernel/cpu/mce/internal.h +++ b/arch/x86/kernel/cpu/mce/internal.h @@ -41,9 +41,7 @@ struct dentry *mce_get_debugfs_dir(void); extern mce_banks_t mce_banks_ce_disabled; #ifdef CONFIG_X86_MCE_INTEL -unsigned long cmci_intel_adjust_timer(unsigned long interval); -bool mce_intel_cmci_poll(void); -void mce_intel_hcpu_update(unsigned long cpu); +void mce_intel_handle_storm(int bank, bool on); void cmci_disable_bank(int bank); void intel_init_cmci(void); void intel_init_lmce(void); @@ -51,9 +49,7 @@ void intel_clear_lmce(void); bool intel_filter_mce(struct mce *m); bool intel_mce_usable_address(struct mce *m); #else -# define cmci_intel_adjust_timer mce_adjust_timer_default -static inline bool mce_intel_cmci_poll(void) { return false; } -static inline void mce_intel_hcpu_update(unsigned long cpu) { } +static inline void mce_intel_handle_storm(int bank, bool on) { } static inline void cmci_disable_bank(int bank) { } static inline void intel_init_cmci(void) { } static inline void intel_init_lmce(void) { } @@ -62,7 +58,63 @@ static inline bool intel_filter_mce(struct mce *m) { return false; } static inline bool intel_mce_usable_address(struct mce *m) { return false; } #endif -void mce_timer_kick(unsigned long interval); +void mce_timer_kick(bool storm); + +#ifdef CONFIG_X86_MCE_THRESHOLD +void cmci_storm_begin(unsigned int bank); +void cmci_storm_end(unsigned int bank); +void mce_track_storm(struct mce *mce); +void mce_inherit_storm(unsigned int bank); +bool mce_get_storm_mode(void); +void mce_set_storm_mode(bool storm); +#else +static inline void cmci_storm_begin(unsigned int bank) {} +static inline void cmci_storm_end(unsigned int bank) {} +static inline void mce_track_storm(struct mce *mce) {} +static inline void mce_inherit_storm(unsigned int bank) {} +static inline bool mce_get_storm_mode(void) { return false; } +static inline void mce_set_storm_mode(bool storm) {} +#endif + +/* + * history: Bitmask tracking errors occurrence. Each set bit + * represents an error seen. + * + * timestamp: Last time (in jiffies) that the bank was polled. + * in_storm_mode: Is this bank in storm mode? + * poll_only: Bank does not support CMCI, skip storm tracking. + */ +struct storm_bank { + u64 history; + u64 timestamp; + bool in_storm_mode; + bool poll_only; +}; + +#define NUM_HISTORY_BITS (sizeof(u64) * BITS_PER_BYTE) + +/* How many errors within the history buffer mark the start of a storm. */ +#define STORM_BEGIN_THRESHOLD 5 + +/* + * How many polls of machine check bank without an error before declaring + * the storm is over. Since it is tracked by the bitmasks in the history + * field of struct storm_bank the mask is 30 bits [0 ... 29]. + */ +#define STORM_END_POLL_THRESHOLD 29 + +/* + * banks: per-cpu, per-bank details + * stormy_bank_count: count of MC banks in storm state + * poll_mode: CPU is in poll mode + */ +struct mca_storm_desc { + struct storm_bank banks[MAX_NR_BANKS]; + u8 stormy_bank_count; + bool poll_mode; +}; + +DECLARE_PER_CPU(struct mca_storm_desc, storm_desc); #ifdef CONFIG_ACPI_APEI int apei_write_mce(struct mce *m); diff --git a/arch/x86/kernel/cpu/mce/threshold.c b/arch/x86/kernel/cpu/mce/threshold.c index ef4e7bb5fd88c6..89e31e1e5c9c1e 100644 --- a/arch/x86/kernel/cpu/mce/threshold.c +++ b/arch/x86/kernel/cpu/mce/threshold.c @@ -29,3 +29,118 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_threshold) trace_threshold_apic_exit(THRESHOLD_APIC_VECTOR); apic_eoi(); } + +DEFINE_PER_CPU(struct mca_storm_desc, storm_desc); + +void mce_inherit_storm(unsigned int bank) +{ + struct mca_storm_desc *storm = this_cpu_ptr(&storm_desc); + + /* + * Previous CPU owning this bank had put it into storm mode, + * but the precise history of that storm is unknown. Assume + * the worst (all recent polls of the bank found a valid error + * logged). This will avoid the new owner prematurely declaring + * the storm has ended. + */ + storm->banks[bank].history = ~0ull; + storm->banks[bank].timestamp = jiffies; +} + +bool mce_get_storm_mode(void) +{ + return __this_cpu_read(storm_desc.poll_mode); +} + +void mce_set_storm_mode(bool storm) +{ + __this_cpu_write(storm_desc.poll_mode, storm); +} + +static void mce_handle_storm(unsigned int bank, bool on) +{ + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_INTEL: + mce_intel_handle_storm(bank, on); + break; + } +} + +void cmci_storm_begin(unsigned int bank) +{ + struct mca_storm_desc *storm = this_cpu_ptr(&storm_desc); + + __set_bit(bank, this_cpu_ptr(mce_poll_banks)); + storm->banks[bank].in_storm_mode = true; + + /* + * If this is the first bank on this CPU to enter storm mode + * start polling. + */ + if (++storm->stormy_bank_count == 1) + mce_timer_kick(true); +} + +void cmci_storm_end(unsigned int bank) +{ + struct mca_storm_desc *storm = this_cpu_ptr(&storm_desc); + + __clear_bit(bank, this_cpu_ptr(mce_poll_banks)); + storm->banks[bank].history = 0; + storm->banks[bank].in_storm_mode = false; + + /* If no banks left in storm mode, stop polling. */ + if (!this_cpu_dec_return(storm_desc.stormy_bank_count)) + mce_timer_kick(false); +} + +void mce_track_storm(struct mce *mce) +{ + struct mca_storm_desc *storm = this_cpu_ptr(&storm_desc); + unsigned long now = jiffies, delta; + unsigned int shift = 1; + u64 history = 0; + + /* No tracking needed for banks that do not support CMCI */ + if (storm->banks[mce->bank].poll_only) + return; + + /* + * When a bank is in storm mode it is polled once per second and + * the history mask will record about the last minute of poll results. + * If it is not in storm mode, then the bank is only checked when + * there is a CMCI interrupt. Check how long it has been since + * this bank was last checked, and adjust the amount of "shift" + * to apply to history. + */ + if (!storm->banks[mce->bank].in_storm_mode) { + delta = now - storm->banks[mce->bank].timestamp; + shift = (delta + HZ) / HZ; + } + + /* If it has been a long time since the last poll, clear history. */ + if (shift < NUM_HISTORY_BITS) + history = storm->banks[mce->bank].history << shift; + + storm->banks[mce->bank].timestamp = now; + + /* History keeps track of corrected errors. VAL=1 && UC=0 */ + if ((mce->status & MCI_STATUS_VAL) && mce_is_correctable(mce)) + history |= 1; + + storm->banks[mce->bank].history = history; + + if (storm->banks[mce->bank].in_storm_mode) { + if (history & GENMASK_ULL(STORM_END_POLL_THRESHOLD, 0)) + return; + printk_deferred(KERN_NOTICE "CPU%d BANK%d CMCI storm subsided\n", smp_processor_id(), mce->bank); + mce_handle_storm(mce->bank, false); + cmci_storm_end(mce->bank); + } else { + if (hweight64(history) < STORM_BEGIN_THRESHOLD) + return; + printk_deferred(KERN_NOTICE "CPU%d BANK%d CMCI storm detected\n", smp_processor_id(), mce->bank); + mce_handle_storm(mce->bank, true); + cmci_storm_begin(mce->bank); + } +} diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index 070426b9895fed..857e608af641ad 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c @@ -370,14 +370,14 @@ static __init struct microcode_intel *get_microcode_blob(struct ucode_cpu_info * { struct cpio_data cp; + intel_collect_cpu_info(&uci->cpu_sig); + if (!load_builtin_intel_microcode(&cp)) cp = find_microcode_in_initrd(ucode_path); if (!(cp.data && cp.size)) return NULL; - intel_collect_cpu_info(&uci->cpu_sig); - return scan_microcode(cp.data, cp.size, uci, save); } @@ -410,13 +410,13 @@ void __init load_ucode_intel_bsp(struct early_load_data *ed) { struct ucode_cpu_info uci; - ed->old_rev = intel_get_microcode_revision(); - uci.mc = get_microcode_blob(&uci, false); - if (uci.mc && apply_microcode_early(&uci) == UCODE_UPDATED) - ucode_patch_va = UCODE_BSP_LOADED; + ed->old_rev = uci.cpu_sig.rev; - ed->new_rev = uci.cpu_sig.rev; + if (uci.mc && apply_microcode_early(&uci) == UCODE_UPDATED) { + ucode_patch_va = UCODE_BSP_LOADED; + ed->new_rev = uci.cpu_sig.rev; + } } void load_ucode_intel_ap(void) @@ -457,12 +457,6 @@ static enum ucode_state apply_microcode_late(int cpu) if (ret != UCODE_UPDATED && ret != UCODE_OK) return ret; - if (!cpu && uci->cpu_sig.rev != cur_rev) { - pr_info("Updated to revision 0x%x, date = %04x-%02x-%02x\n", - uci->cpu_sig.rev, mc->hdr.date & 0xffff, mc->hdr.date >> 24, - (mc->hdr.date >> 16) & 0xff); - } - cpu_data(cpu).microcode = uci->cpu_sig.rev; if (!cpu) boot_cpu_data.microcode = uci->cpu_sig.rev; diff --git a/arch/x86/kernel/cpu/mtrr/generic.c b/arch/x86/kernel/cpu/mtrr/generic.c index 2d6aa5d2e3d77e..d3524778a54517 100644 --- a/arch/x86/kernel/cpu/mtrr/generic.c +++ b/arch/x86/kernel/cpu/mtrr/generic.c @@ -428,6 +428,10 @@ void __init mtrr_copy_map(void) * from the x86_init.hyper.init_platform() hook. It can be called only once. * The MTRR state can't be changed afterwards. To ensure that, X86_FEATURE_MTRR * is cleared. + * + * @var: MTRR variable range array to use + * @num_var: length of the @var array + * @def_type: default caching type */ void mtrr_overwrite_state(struct mtrr_var_range *var, unsigned int num_var, mtrr_type def_type) @@ -492,13 +496,15 @@ static u8 type_merge(u8 type, u8 new_type, u8 *uniform) /** * mtrr_type_lookup - look up memory type in MTRR * + * @start: Begin of the physical address range + * @end: End of the physical address range + * @uniform: output argument: + * - 1: the returned MTRR type is valid for the whole region + * - 0: otherwise + * * Return Values: * MTRR_TYPE_(type) - The effective MTRR type for the region * MTRR_TYPE_INVALID - MTRR is disabled - * - * Output Argument: - * uniform - Set to 1 when the returned MTRR type is valid for the whole - * region, set to 0 else. */ u8 mtrr_type_lookup(u64 start, u64 end, u8 *uniform) { diff --git a/arch/x86/kernel/cpu/sgx/ioctl.c b/arch/x86/kernel/cpu/sgx/ioctl.c index 5d390df2144066..b65ab214bdf57d 100644 --- a/arch/x86/kernel/cpu/sgx/ioctl.c +++ b/arch/x86/kernel/cpu/sgx/ioctl.c @@ -581,7 +581,7 @@ err_out: * * Flush any outstanding enqueued EADD operations and perform EINIT. The * Launch Enclave Public Key Hash MSRs are rewritten as necessary to match - * the enclave's MRSIGNER, which is caculated from the provided sigstruct. + * the enclave's MRSIGNER, which is calculated from the provided sigstruct. * * Return: * - 0: Success. diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c index c92d88680dbf16..b6b044356f1b40 100644 --- a/arch/x86/kernel/crash.c +++ b/arch/x86/kernel/crash.c @@ -170,7 +170,7 @@ static int elf_header_exclude_ranges(struct crash_mem *cmem) int ret = 0; /* Exclude the low 1M because it is always reserved */ - ret = crash_exclude_mem_range(cmem, 0, (1<<20)-1); + ret = crash_exclude_mem_range(cmem, 0, SZ_1M - 1); if (ret) return ret; @@ -198,8 +198,8 @@ static int prepare_elf64_ram_headers_callback(struct resource *res, void *arg) } /* Prepare elf headers. Return addr and size */ -static int prepare_elf_headers(struct kimage *image, void **addr, - unsigned long *sz, unsigned long *nr_mem_ranges) +static int prepare_elf_headers(void **addr, unsigned long *sz, + unsigned long *nr_mem_ranges) { struct crash_mem *cmem; int ret; @@ -221,7 +221,7 @@ static int prepare_elf_headers(struct kimage *image, void **addr, *nr_mem_ranges = cmem->nr_ranges; /* By default prepare 64bit headers */ - ret = crash_prepare_elf64_headers(cmem, IS_ENABLED(CONFIG_X86_64), addr, sz); + ret = crash_prepare_elf64_headers(cmem, IS_ENABLED(CONFIG_X86_64), addr, sz); out: vfree(cmem); @@ -349,7 +349,7 @@ int crash_load_segments(struct kimage *image) .buf_max = ULONG_MAX, .top_down = false }; /* Prepare elf headers and add a segment */ - ret = prepare_elf_headers(image, &kbuf.buffer, &kbuf.bufsz, &pnum); + ret = prepare_elf_headers(&kbuf.buffer, &kbuf.bufsz, &pnum); if (ret) return ret; @@ -386,8 +386,8 @@ int crash_load_segments(struct kimage *image) if (ret) return ret; image->elf_load_addr = kbuf.mem; - pr_debug("Loaded ELF headers at 0x%lx bufsz=0x%lx memsz=0x%lx\n", - image->elf_load_addr, kbuf.bufsz, kbuf.memsz); + kexec_dprintk("Loaded ELF headers at 0x%lx bufsz=0x%lx memsz=0x%lx\n", + image->elf_load_addr, kbuf.bufsz, kbuf.memsz); return ret; } @@ -452,7 +452,7 @@ void arch_crash_handle_hotplug_event(struct kimage *image) * Create the new elfcorehdr reflecting the changes to CPU and/or * memory resources. */ - if (prepare_elf_headers(image, &elfbuf, &elfsz, &nr_mem_ranges)) { + if (prepare_elf_headers(&elfbuf, &elfsz, &nr_mem_ranges)) { pr_err("unable to create new elfcorehdr"); goto out; } diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c index a6c1867fc7aa3e..59f4aefc6bc162 100644 --- a/arch/x86/kernel/early-quirks.c +++ b/arch/x86/kernel/early-quirks.c @@ -779,13 +779,13 @@ static int __init check_dev_quirk(int num, int slot, int func) type = read_pci_config_byte(num, slot, func, PCI_HEADER_TYPE); - if ((type & 0x7f) == PCI_HEADER_TYPE_BRIDGE) { + if ((type & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_BRIDGE) { sec = read_pci_config_byte(num, slot, func, PCI_SECONDARY_BUS); if (sec > num) early_pci_scan_bus(sec); } - if (!(type & 0x80)) + if (!(type & PCI_HEADER_TYPE_MFD)) return -1; return 0; diff --git a/arch/x86/kernel/fpu/bugs.c b/arch/x86/kernel/fpu/bugs.c index 794e7015120372..a06b876bbf2d11 100644 --- a/arch/x86/kernel/fpu/bugs.c +++ b/arch/x86/kernel/fpu/bugs.c @@ -2,6 +2,7 @@ /* * x86 FPU bug checks: */ +#include #include /* diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c index a21a4d0ecc345b..520deb411a7025 100644 --- a/arch/x86/kernel/fpu/core.c +++ b/arch/x86/kernel/fpu/core.c @@ -308,7 +308,7 @@ EXPORT_SYMBOL_GPL(fpu_update_guest_xfd); * Must be invoked from KVM after a VMEXIT before enabling interrupts when * XFD write emulation is disabled. This is required because the guest can * freely modify XFD and the state at VMEXIT is not guaranteed to be the - * same as the state on VMENTER. So software state has to be udpated before + * same as the state on VMENTER. So software state has to be updated before * any operation which depends on it can take place. * * Note: It can be invoked unconditionally even when write emulation is diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c index 05a110c9711116..dc0956067944dc 100644 --- a/arch/x86/kernel/head64.c +++ b/arch/x86/kernel/head64.c @@ -71,9 +71,9 @@ EXPORT_SYMBOL(vmemmap_base); * GDT used on the boot CPU before switching to virtual addresses. */ static struct desc_struct startup_gdt[GDT_ENTRIES] __initdata = { - [GDT_ENTRY_KERNEL32_CS] = GDT_ENTRY_INIT(0xc09b, 0, 0xfffff), - [GDT_ENTRY_KERNEL_CS] = GDT_ENTRY_INIT(0xa09b, 0, 0xfffff), - [GDT_ENTRY_KERNEL_DS] = GDT_ENTRY_INIT(0xc093, 0, 0xfffff), + [GDT_ENTRY_KERNEL32_CS] = GDT_ENTRY_INIT(DESC_CODE32, 0, 0xfffff), + [GDT_ENTRY_KERNEL_CS] = GDT_ENTRY_INIT(DESC_CODE64, 0, 0xfffff), + [GDT_ENTRY_KERNEL_DS] = GDT_ENTRY_INIT(DESC_DATA64, 0, 0xfffff), }; /* diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S index 0f8103240fda31..d4918d03efb4b7 100644 --- a/arch/x86/kernel/head_64.S +++ b/arch/x86/kernel/head_64.S @@ -114,6 +114,28 @@ SYM_CODE_START_NOALIGN(startup_64) /* Form the CR3 value being sure to include the CR3 modifier */ addq $(early_top_pgt - __START_KERNEL_map), %rax + +#ifdef CONFIG_AMD_MEM_ENCRYPT + mov %rax, %rdi + mov %rax, %r14 + + addq phys_base(%rip), %rdi + + /* + * For SEV guests: Verify that the C-bit is correct. A malicious + * hypervisor could lie about the C-bit position to perform a ROP + * attack on the guest by writing to the unencrypted stack and wait for + * the next RET instruction. + */ + call sev_verify_cbit + + /* + * Restore CR3 value without the phys_base which will be added + * below, before writing %cr3. + */ + mov %r14, %rax +#endif + jmp 1f SYM_CODE_END(startup_64) @@ -182,7 +204,7 @@ SYM_INNER_LABEL(secondary_startup_64_no_verify, SYM_L_GLOBAL) /* Enable PAE mode, PSE, PGE and LA57 */ orl $(X86_CR4_PAE | X86_CR4_PSE | X86_CR4_PGE), %ecx #ifdef CONFIG_X86_5LEVEL - testl $1, __pgtable_l5_enabled(%rip) + testb $1, __pgtable_l5_enabled(%rip) jz 1f orl $X86_CR4_LA57, %ecx 1: @@ -192,22 +214,13 @@ SYM_INNER_LABEL(secondary_startup_64_no_verify, SYM_L_GLOBAL) /* Setup early boot stage 4-/5-level pagetables. */ addq phys_base(%rip), %rax - /* - * For SEV guests: Verify that the C-bit is correct. A malicious - * hypervisor could lie about the C-bit position to perform a ROP - * attack on the guest by writing to the unencrypted stack and wait for - * the next RET instruction. - */ - movq %rax, %rdi - call sev_verify_cbit - /* * Switch to new page-table * * For the boot CPU this switches to early_top_pgt which still has the - * indentity mappings present. The secondary CPUs will switch to the + * identity mappings present. The secondary CPUs will switch to the * init_top_pgt here, away from the trampoline_pgd and unmap the - * indentity mapped ranges. + * identity mapped ranges. */ movq %rax, %cr3 diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index 41eecf180b7f4a..a38d0c93a66e82 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c @@ -707,7 +707,7 @@ static void __init hpet_select_clockevents(void) hpet_base.nr_clockevents = 0; - /* No point if MSI is disabled or CPU has an Always Runing APIC Timer */ + /* No point if MSI is disabled or CPU has an Always Running APIC Timer */ if (hpet_msi_disable || boot_cpu_has(X86_FEATURE_ARAT)) return; @@ -965,7 +965,7 @@ static bool __init mwait_pc10_supported(void) * and per CPU timer interrupts. * * The probability that this problem is going to be solved in the - * forseeable future is close to zero, so the kernel has to be cluttered + * foreseeable future is close to zero, so the kernel has to be cluttered * with heuristics to keep up with the ever growing amount of hardware and * firmware trainwrecks. Hopefully some day hardware people will understand * that the approach of "This can be fixed in software" is not sustainable. @@ -1438,7 +1438,7 @@ irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id) memset(&curr_time, 0, sizeof(struct rtc_time)); if (hpet_rtc_flags & (RTC_UIE | RTC_AIE)) { - if (unlikely(mc146818_get_time(&curr_time) < 0)) { + if (unlikely(mc146818_get_time(&curr_time, 10) < 0)) { pr_err_ratelimited("unable to read current time from RTC\n"); return IRQ_HANDLED; } diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c index a61c12c0127097..2a422e00ed4b42 100644 --- a/arch/x86/kernel/kexec-bzimage64.c +++ b/arch/x86/kernel/kexec-bzimage64.c @@ -82,7 +82,7 @@ static int setup_cmdline(struct kimage *image, struct boot_params *params, cmdline_ptr[cmdline_len - 1] = '\0'; - pr_debug("Final command line is: %s\n", cmdline_ptr); + kexec_dprintk("Final command line is: %s\n", cmdline_ptr); cmdline_ptr_phys = bootparams_load_addr + cmdline_offset; cmdline_low_32 = cmdline_ptr_phys & 0xffffffffUL; cmdline_ext_32 = cmdline_ptr_phys >> 32; @@ -272,7 +272,12 @@ setup_boot_parameters(struct kimage *image, struct boot_params *params, nr_e820_entries = params->e820_entries; + kexec_dprintk("E820 memmap:\n"); for (i = 0; i < nr_e820_entries; i++) { + kexec_dprintk("%016llx-%016llx (%d)\n", + params->e820_table[i].addr, + params->e820_table[i].addr + params->e820_table[i].size - 1, + params->e820_table[i].type); if (params->e820_table[i].type != E820_TYPE_RAM) continue; start = params->e820_table[i].addr; @@ -424,7 +429,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel, * command line. Make sure it does not overflow */ if (cmdline_len + MAX_ELFCOREHDR_STR_LEN > header->cmdline_size) { - pr_debug("Appending elfcorehdr= to command line exceeds maximum allowed length\n"); + pr_err("Appending elfcorehdr= to command line exceeds maximum allowed length\n"); return ERR_PTR(-EINVAL); } @@ -445,7 +450,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel, return ERR_PTR(ret); } - pr_debug("Loaded purgatory at 0x%lx\n", pbuf.mem); + kexec_dprintk("Loaded purgatory at 0x%lx\n", pbuf.mem); /* @@ -490,8 +495,8 @@ static void *bzImage64_load(struct kimage *image, char *kernel, if (ret) goto out_free_params; bootparam_load_addr = kbuf.mem; - pr_debug("Loaded boot_param, command line and misc at 0x%lx bufsz=0x%lx memsz=0x%lx\n", - bootparam_load_addr, kbuf.bufsz, kbuf.bufsz); + kexec_dprintk("Loaded boot_param, command line and misc at 0x%lx bufsz=0x%lx memsz=0x%lx\n", + bootparam_load_addr, kbuf.bufsz, kbuf.memsz); /* Load kernel */ kbuf.buffer = kernel + kern16_size; @@ -505,8 +510,8 @@ static void *bzImage64_load(struct kimage *image, char *kernel, goto out_free_params; kernel_load_addr = kbuf.mem; - pr_debug("Loaded 64bit kernel at 0x%lx bufsz=0x%lx memsz=0x%lx\n", - kernel_load_addr, kbuf.bufsz, kbuf.memsz); + kexec_dprintk("Loaded 64bit kernel at 0x%lx bufsz=0x%lx memsz=0x%lx\n", + kernel_load_addr, kbuf.bufsz, kbuf.memsz); /* Load initrd high */ if (initrd) { @@ -520,8 +525,8 @@ static void *bzImage64_load(struct kimage *image, char *kernel, goto out_free_params; initrd_load_addr = kbuf.mem; - pr_debug("Loaded initrd at 0x%lx bufsz=0x%lx memsz=0x%lx\n", - initrd_load_addr, initrd_len, initrd_len); + kexec_dprintk("Loaded initrd at 0x%lx bufsz=0x%lx memsz=0x%lx\n", + initrd_load_addr, initrd_len, initrd_len); setup_initrd(params, initrd_load_addr, initrd_len); } diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index 0ddb3bd0f1aac7..dfe9945b9becee 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -803,8 +803,8 @@ extern bool __raw_callee_save___kvm_vcpu_is_preempted(long); "cmpb $0, " __stringify(KVM_STEAL_TIME_preempted) "+steal_time(%rax)\n\t" \ "setne %al\n\t" -DEFINE_PARAVIRT_ASM(__raw_callee_save___kvm_vcpu_is_preempted, - PV_VCPU_PREEMPTED_ASM, .text); +DEFINE_ASM_FUNC(__raw_callee_save___kvm_vcpu_is_preempted, + PV_VCPU_PREEMPTED_ASM, .text); #endif static void __init kvm_guest_init(void) @@ -942,7 +942,7 @@ static void __init kvm_init_platform(void) * Reset the host's shared pages list related to kernel * specific page encryption status settings before we load a * new kernel by kexec. Reset the page encryption status - * during early boot intead of just before kexec to avoid SMP + * during early boot instead of just before kexec to avoid SMP * races during kvm_pv_guest_cpu_reboot(). * NOTE: We cannot reset the complete shared pages list * here as we need to retain the UEFI/OVMF firmware diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c index fb8f52149be9ad..5bb395551c441e 100644 --- a/arch/x86/kernel/kvmclock.c +++ b/arch/x86/kernel/kvmclock.c @@ -24,8 +24,8 @@ static int kvmclock __initdata = 1; static int kvmclock_vsyscall __initdata = 1; -static int msr_kvm_system_time __ro_after_init = MSR_KVM_SYSTEM_TIME; -static int msr_kvm_wall_clock __ro_after_init = MSR_KVM_WALL_CLOCK; +static int msr_kvm_system_time __ro_after_init; +static int msr_kvm_wall_clock __ro_after_init; static u64 kvm_sched_clock_offset __ro_after_init; static int __init parse_no_kvmclock(char *arg) @@ -42,7 +42,7 @@ static int __init parse_no_kvmclock_vsyscall(char *arg) } early_param("no-kvmclock-vsyscall", parse_no_kvmclock_vsyscall); -/* Aligned to page sizes to match whats mapped via vsyscalls to userspace */ +/* Aligned to page sizes to match what's mapped via vsyscalls to userspace */ #define HVC_BOOT_ARRAY_SIZE \ (PAGE_SIZE / sizeof(struct pvclock_vsyscall_time_info)) @@ -195,7 +195,8 @@ static void kvm_setup_secondary_clock(void) void kvmclock_disable(void) { - native_write_msr(msr_kvm_system_time, 0, 0); + if (msr_kvm_system_time) + native_write_msr(msr_kvm_system_time, 0, 0); } static void __init kvmclock_init_mem(void) @@ -294,7 +295,10 @@ void __init kvmclock_init(void) if (kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE2)) { msr_kvm_system_time = MSR_KVM_SYSTEM_TIME_NEW; msr_kvm_wall_clock = MSR_KVM_WALL_CLOCK_NEW; - } else if (!kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE)) { + } else if (kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE)) { + msr_kvm_system_time = MSR_KVM_SYSTEM_TIME; + msr_kvm_wall_clock = MSR_KVM_WALL_CLOCK; + } else { return; } diff --git a/arch/x86/kernel/ldt.c b/arch/x86/kernel/ldt.c index adc67f98819aa4..7a814b41402de5 100644 --- a/arch/x86/kernel/ldt.c +++ b/arch/x86/kernel/ldt.c @@ -7,7 +7,7 @@ * This handles calls from both 32bit and 64bit mode. * * Lock order: - * contex.ldt_usr_sem + * context.ldt_usr_sem * mmap_lock * context.lock */ @@ -49,7 +49,7 @@ void load_mm_ldt(struct mm_struct *mm) /* * Any change to mm->context.ldt is followed by an IPI to all * CPUs with the mm active. The LDT will not be freed until - * after the IPI is handled by all such CPUs. This means that, + * after the IPI is handled by all such CPUs. This means that * if the ldt_struct changes before we return, the values we see * will be safe, and the new values will be loaded before we run * any user code. @@ -685,7 +685,7 @@ SYSCALL_DEFINE3(modify_ldt, int , func , void __user * , ptr , } /* * The SYSCALL_DEFINE() macros give us an 'unsigned long' - * return type, but tht ABI for sys_modify_ldt() expects + * return type, but the ABI for sys_modify_ldt() expects * 'int'. This cast gives us an int-sized value in %rax * for the return code. The 'unsigned' is necessary so * the compiler does not try to sign-extend the negative diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c index 1a3e2c05a8a5b6..bc0a5348b4a627 100644 --- a/arch/x86/kernel/machine_kexec_64.c +++ b/arch/x86/kernel/machine_kexec_64.c @@ -42,12 +42,9 @@ struct init_pgtable_data { static int mem_region_callback(struct resource *res, void *arg) { struct init_pgtable_data *data = arg; - unsigned long mstart, mend; - - mstart = res->start; - mend = mstart + resource_size(res) - 1; - return kernel_ident_mapping_init(data->info, data->level4p, mstart, mend); + return kernel_ident_mapping_init(data->info, data->level4p, + res->start, res->end + 1); } static int diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c index 5f71a0cf4399a5..e18914c0e38a66 100644 --- a/arch/x86/kernel/module.c +++ b/arch/x86/kernel/module.c @@ -276,7 +276,7 @@ int module_finalize(const Elf_Ehdr *hdr, struct module *me) { const Elf_Shdr *s, *alt = NULL, *locks = NULL, - *para = NULL, *orc = NULL, *orc_ip = NULL, + *orc = NULL, *orc_ip = NULL, *retpolines = NULL, *returns = NULL, *ibt_endbr = NULL, *calls = NULL, *cfi = NULL; char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; @@ -286,8 +286,6 @@ int module_finalize(const Elf_Ehdr *hdr, alt = s; if (!strcmp(".smp_locks", secstrings + s->sh_name)) locks = s; - if (!strcmp(".parainstructions", secstrings + s->sh_name)) - para = s; if (!strcmp(".orc_unwind", secstrings + s->sh_name)) orc = s; if (!strcmp(".orc_unwind_ip", secstrings + s->sh_name)) @@ -304,14 +302,6 @@ int module_finalize(const Elf_Ehdr *hdr, ibt_endbr = s; } - /* - * See alternative_instructions() for the ordering rules between the - * various patching types. - */ - if (para) { - void *pseg = (void *)para->sh_addr; - apply_paravirt(pseg, pseg + para->sh_size); - } if (retpolines || cfi) { void *rseg = NULL, *cseg = NULL; unsigned int rsize = 0, csize = 0; @@ -341,7 +331,7 @@ int module_finalize(const Elf_Ehdr *hdr, void *aseg = (void *)alt->sh_addr; apply_alternatives(aseg, aseg + alt->sh_size); } - if (calls || para) { + if (calls || alt) { struct callthunk_sites cs = {}; if (calls) { @@ -349,9 +339,9 @@ int module_finalize(const Elf_Ehdr *hdr, cs.call_end = (void *)calls->sh_addr + calls->sh_size; } - if (para) { - cs.pv_start = (void *)para->sh_addr; - cs.pv_end = (void *)para->sh_addr + para->sh_size; + if (alt) { + cs.alt_start = (void *)alt->sh_addr; + cs.alt_end = (void *)alt->sh_addr + alt->sh_size; } callthunks_patch_module_calls(&cs, me); diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c index 97f1436c1a2034..5358d43886adc5 100644 --- a/arch/x86/kernel/paravirt.c +++ b/arch/x86/kernel/paravirt.c @@ -34,14 +34,8 @@ #include #include -/* - * nop stub, which must not clobber anything *including the stack* to - * avoid confusing the entry prologues. - */ -DEFINE_PARAVIRT_ASM(_paravirt_nop, "", .entry.text); - /* stub always returning 0. */ -DEFINE_PARAVIRT_ASM(paravirt_ret0, "xor %eax,%eax", .entry.text); +DEFINE_ASM_FUNC(paravirt_ret0, "xor %eax,%eax", .entry.text); void __init default_banner(void) { @@ -49,26 +43,12 @@ void __init default_banner(void) pv_info.name); } -/* Undefined instruction for dealing with missing ops pointers. */ -noinstr void paravirt_BUG(void) -{ - BUG(); -} - -static unsigned paravirt_patch_call(void *insn_buff, const void *target, - unsigned long addr, unsigned len) -{ - __text_gen_insn(insn_buff, CALL_INSN_OPCODE, - (void *)addr, target, CALL_INSN_SIZE); - return CALL_INSN_SIZE; -} - #ifdef CONFIG_PARAVIRT_XXL -DEFINE_PARAVIRT_ASM(_paravirt_ident_64, "mov %rdi, %rax", .text); -DEFINE_PARAVIRT_ASM(pv_native_save_fl, "pushf; pop %rax", .noinstr.text); -DEFINE_PARAVIRT_ASM(pv_native_irq_disable, "cli", .noinstr.text); -DEFINE_PARAVIRT_ASM(pv_native_irq_enable, "sti", .noinstr.text); -DEFINE_PARAVIRT_ASM(pv_native_read_cr2, "mov %cr2, %rax", .noinstr.text); +DEFINE_ASM_FUNC(_paravirt_ident_64, "mov %rdi, %rax", .text); +DEFINE_ASM_FUNC(pv_native_save_fl, "pushf; pop %rax", .noinstr.text); +DEFINE_ASM_FUNC(pv_native_irq_disable, "cli", .noinstr.text); +DEFINE_ASM_FUNC(pv_native_irq_enable, "sti", .noinstr.text); +DEFINE_ASM_FUNC(pv_native_read_cr2, "mov %cr2, %rax", .noinstr.text); #endif DEFINE_STATIC_KEY_TRUE(virt_spin_lock_key); @@ -85,28 +65,6 @@ static void native_tlb_remove_table(struct mmu_gather *tlb, void *table) tlb_remove_page(tlb, table); } -unsigned int paravirt_patch(u8 type, void *insn_buff, unsigned long addr, - unsigned int len) -{ - /* - * Neat trick to map patch type back to the call within the - * corresponding structure. - */ - void *opfunc = *((void **)&pv_ops + type); - unsigned ret; - - if (opfunc == NULL) - /* If there's no function, patch it with paravirt_BUG() */ - ret = paravirt_patch_call(insn_buff, paravirt_BUG, addr, len); - else if (opfunc == _paravirt_nop) - ret = 0; - else - /* Otherwise call the function. */ - ret = paravirt_patch_call(insn_buff, opfunc, addr, len); - - return ret; -} - struct static_key paravirt_steal_enabled; struct static_key paravirt_steal_rq_enabled; diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index b6f4e8399fca20..ab49ade31b0dc4 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -477,7 +477,7 @@ void native_tss_update_io_bitmap(void) /* * Make sure that the TSS limit is covering the IO bitmap. It might have * been cut down by a VMEXIT to 0x67 which would cause a subsequent I/O - * access from user space to trigger a #GP because tbe bitmap is outside + * access from user space to trigger a #GP because the bitmap is outside * the TSS limit. */ refresh_tss_limit(); diff --git a/arch/x86/kernel/rtc.c b/arch/x86/kernel/rtc.c index 1309b9b053386b..2e7066980f3e8b 100644 --- a/arch/x86/kernel/rtc.c +++ b/arch/x86/kernel/rtc.c @@ -67,7 +67,7 @@ void mach_get_cmos_time(struct timespec64 *now) return; } - if (mc146818_get_time(&tm)) { + if (mc146818_get_time(&tm, 1000)) { pr_err("Unable to read current time from RTC\n"); now->tv_sec = now->tv_nsec = 0; return; diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 1526747bedf2fd..84201071dfacd1 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -226,8 +226,6 @@ static void __init reserve_brk(void) _brk_start = 0; } -u64 relocated_ramdisk; - #ifdef CONFIG_BLK_DEV_INITRD static u64 __init get_ramdisk_image(void) @@ -261,7 +259,7 @@ static void __init relocate_initrd(void) u64 area_size = PAGE_ALIGN(ramdisk_size); /* We need to move the initrd down into directly mapped mem */ - relocated_ramdisk = memblock_phys_alloc_range(area_size, PAGE_SIZE, 0, + u64 relocated_ramdisk = memblock_phys_alloc_range(area_size, PAGE_SIZE, 0, PFN_PHYS(max_pfn_mapped)); if (!relocated_ramdisk) panic("Cannot find place for new RAMDISK of size %lld\n", @@ -1033,6 +1031,8 @@ void __init setup_arch(char **cmdline_p) * * Moreover, on machines with SandyBridge graphics or in setups that use * crashkernel the entire 1M is reserved anyway. + * + * Note the host kernel TDX also requires the first 1MB being reserved. */ x86_platform.realmode_reserve(); diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c index 2c97bf7b56ae4d..b30d6e180df7c4 100644 --- a/arch/x86/kernel/setup_percpu.c +++ b/arch/x86/kernel/setup_percpu.c @@ -106,8 +106,8 @@ void __init pcpu_populate_pte(unsigned long addr) static inline void setup_percpu_segment(int cpu) { #ifdef CONFIG_X86_32 - struct desc_struct d = GDT_ENTRY_INIT(0x8092, per_cpu_offset(cpu), - 0xFFFFF); + struct desc_struct d = GDT_ENTRY_INIT(DESC_DATA32, + per_cpu_offset(cpu), 0xFFFFF); write_gdt_entry(get_cpu_gdt_rw(cpu), GDT_ENTRY_PERCPU, &d, DESCTYPE_S); #endif diff --git a/arch/x86/kernel/sev-shared.c b/arch/x86/kernel/sev-shared.c index ccb0915e84e10c..1d24ec6799157b 100644 --- a/arch/x86/kernel/sev-shared.c +++ b/arch/x86/kernel/sev-shared.c @@ -96,7 +96,7 @@ static void __noreturn sev_es_terminate(unsigned int set, unsigned int reason) /* Tell the hypervisor what went wrong. */ val |= GHCB_SEV_TERM_REASON(set, reason); - /* Request Guest Termination from Hypvervisor */ + /* Request Guest Termination from Hypervisor */ sev_es_wr_ghcb_msr(val); VMGEXIT(); diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index 65fe2094da59b8..31b6f5dddfc274 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 2cc2aa120b4b39..3f57ce68a3f1ec 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -757,6 +757,7 @@ const struct cpumask *cpu_clustergroup_mask(int cpu) { return cpu_l2c_shared_mask(cpu); } +EXPORT_SYMBOL_GPL(cpu_clustergroup_mask); static void impress_friends(void) { diff --git a/arch/x86/kernel/topology.c b/arch/x86/kernel/topology.c index 0bab0313003362..d42c28b8bfd80c 100644 --- a/arch/x86/kernel/topology.c +++ b/arch/x86/kernel/topology.c @@ -35,38 +35,9 @@ #include #include -static DEFINE_PER_CPU(struct x86_cpu, cpu_devices); - #ifdef CONFIG_HOTPLUG_CPU -int arch_register_cpu(int cpu) +bool arch_cpu_is_hotpluggable(int cpu) { - struct x86_cpu *xc = per_cpu_ptr(&cpu_devices, cpu); - - xc->cpu.hotpluggable = cpu > 0; - return register_cpu(&xc->cpu, cpu); -} -EXPORT_SYMBOL(arch_register_cpu); - -void arch_unregister_cpu(int num) -{ - unregister_cpu(&per_cpu(cpu_devices, num).cpu); -} -EXPORT_SYMBOL(arch_unregister_cpu); -#else /* CONFIG_HOTPLUG_CPU */ - -int __init arch_register_cpu(int num) -{ - return register_cpu(&per_cpu(cpu_devices, num).cpu, num); + return cpu > 0; } #endif /* CONFIG_HOTPLUG_CPU */ - -static int __init topology_init(void) -{ - int i; - - for_each_present_cpu(i) - arch_register_cpu(i); - - return 0; -} -subsys_initcall(topology_init); diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index c876f1d36a81a7..c3b2f863acf0f3 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -565,7 +566,7 @@ static bool fixup_iopl_exception(struct pt_regs *regs) */ static bool try_fixup_enqcmd_gp(void) { -#ifdef CONFIG_IOMMU_SVA +#ifdef CONFIG_ARCH_HAS_CPU_PASID u32 pasid; /* @@ -591,7 +592,7 @@ static bool try_fixup_enqcmd_gp(void) if (!mm_valid_pasid(current->mm)) return false; - pasid = current->mm->pasid; + pasid = mm_get_enqcmd_pasid(current->mm); /* * Did this thread already have its PASID activated? diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S index 54a5596adaa61e..a349dbfc6d5ab4 100644 --- a/arch/x86/kernel/vmlinux.lds.S +++ b/arch/x86/kernel/vmlinux.lds.S @@ -267,19 +267,6 @@ SECTIONS } #endif - /* - * start address and size of operations which during runtime - * can be patched with virtualization friendly instructions or - * baremetal native ones. Think page table operations. - * Details in paravirt_types.h - */ - . = ALIGN(8); - .parainstructions : AT(ADDR(.parainstructions) - LOAD_OFFSET) { - __parainstructions = .; - *(.parainstructions) - __parainstructions_end = .; - } - #ifdef CONFIG_RETPOLINE /* * List of instructions that call/jmp/jcc to retpoline thunks diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig index 950c12868d3040..87e3da7b043979 100644 --- a/arch/x86/kvm/Kconfig +++ b/arch/x86/kvm/Kconfig @@ -23,17 +23,15 @@ config KVM depends on HAVE_KVM depends on HIGH_RES_TIMERS depends on X86_LOCAL_APIC - select PREEMPT_NOTIFIERS - select MMU_NOTIFIER + select KVM_COMMON + select KVM_GENERIC_MMU_NOTIFIER select HAVE_KVM_IRQCHIP select HAVE_KVM_PFNCACHE - select HAVE_KVM_IRQFD select HAVE_KVM_DIRTY_RING_TSO select HAVE_KVM_DIRTY_RING_ACQ_REL select IRQ_BYPASS_MANAGER select HAVE_KVM_IRQ_BYPASS select HAVE_KVM_IRQ_ROUTING - select HAVE_KVM_EVENTFD select KVM_ASYNC_PF select USER_RETURN_NOTIFIER select KVM_MMIO @@ -46,7 +44,6 @@ config KVM select KVM_XFER_TO_GUEST_WORK select KVM_GENERIC_DIRTYLOG_READ_PROTECT select KVM_VFIO - select INTERVAL_TREE select HAVE_KVM_PM_NOTIFIER if PM select KVM_GENERIC_HARDWARE_ENABLING help @@ -65,18 +62,30 @@ config KVM config KVM_WERROR bool "Compile KVM with -Werror" - # KASAN may cause the build to fail due to larger frames - default y if X86_64 && !KASAN - # We use the dependency on !COMPILE_TEST to not be enabled - # blindly in allmodconfig or allyesconfig configurations - depends on KVM - depends on (X86_64 && !KASAN) || !COMPILE_TEST - depends on EXPERT + # Disallow KVM's -Werror if KASAN is enabled, e.g. to guard against + # randomized configs from selecting KVM_WERROR=y, which doesn't play + # nice with KASAN. KASAN builds generates warnings for the default + # FRAME_WARN, i.e. KVM_WERROR=y with KASAN=y requires special tuning. + # Building KVM with -Werror and KASAN is still doable via enabling + # the kernel-wide WERROR=y. + depends on KVM && EXPERT && !KASAN help Add -Werror to the build flags for KVM. If in doubt, say "N". +config KVM_SW_PROTECTED_VM + bool "Enable support for KVM software-protected VMs" + depends on EXPERT + depends on KVM && X86_64 + select KVM_GENERIC_PRIVATE_MEM + help + Enable support for KVM software-protected VMs. Currently "protected" + means the VM can be backed with memory provided by + KVM_CREATE_GUEST_MEMFD. + + If unsure, say "N". + config KVM_INTEL tristate "KVM for Intel (and compatible) processors support" depends on KVM && IA32_FEAT_CTL @@ -129,6 +138,20 @@ config KVM_SMM If unsure, say Y. +config KVM_HYPERV + bool "Support for Microsoft Hyper-V emulation" + depends on KVM + default y + help + Provides KVM support for emulating Microsoft Hyper-V. This allows KVM + to expose a subset of the paravirtualized interfaces defined in the + Hyper-V Hypervisor Top-Level Functional Specification (TLFS): + https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/tlfs + These interfaces are required for the correct and performant functioning + of Windows and Hyper-V guests on KVM. + + If unsure, say "Y". + config KVM_XEN bool "Support for Xen hypercall interface" depends on KVM diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile index 80e3fe184d17e6..475b5fa917a62d 100644 --- a/arch/x86/kvm/Makefile +++ b/arch/x86/kvm/Makefile @@ -11,25 +11,27 @@ include $(srctree)/virt/kvm/Makefile.kvm kvm-y += x86.o emulate.o i8259.o irq.o lapic.o \ i8254.o ioapic.o irq_comm.o cpuid.o pmu.o mtrr.o \ - hyperv.o debugfs.o mmu/mmu.o mmu/page_track.o \ + debugfs.o mmu/mmu.o mmu/page_track.o \ mmu/spte.o -ifdef CONFIG_HYPERV -kvm-y += kvm_onhyperv.o -endif - kvm-$(CONFIG_X86_64) += mmu/tdp_iter.o mmu/tdp_mmu.o +kvm-$(CONFIG_KVM_HYPERV) += hyperv.o kvm-$(CONFIG_KVM_XEN) += xen.o kvm-$(CONFIG_KVM_SMM) += smm.o kvm-intel-y += vmx/vmx.o vmx/vmenter.o vmx/pmu_intel.o vmx/vmcs12.o \ - vmx/hyperv.o vmx/nested.o vmx/posted_intr.o + vmx/nested.o vmx/posted_intr.o + kvm-intel-$(CONFIG_X86_SGX_KVM) += vmx/sgx.o +kvm-intel-$(CONFIG_KVM_HYPERV) += vmx/hyperv.o vmx/hyperv_evmcs.o kvm-amd-y += svm/svm.o svm/vmenter.o svm/pmu.o svm/nested.o svm/avic.o \ - svm/sev.o svm/hyperv.o + svm/sev.o +kvm-amd-$(CONFIG_KVM_HYPERV) += svm/hyperv.o ifdef CONFIG_HYPERV +kvm-y += kvm_onhyperv.o +kvm-intel-y += vmx/vmx_onhyperv.o vmx/hyperv_evmcs.o kvm-amd-y += svm/svm_onhyperv.o endif diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index dda6fc4cfae886..adba49afb5fe63 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -105,7 +105,7 @@ static inline struct kvm_cpuid_entry2 *cpuid_entry2_find( /* * If the index isn't significant, use the first entry with a - * matching function. It's userspace's responsibilty to not + * matching function. It's userspace's responsibility to not * provide "duplicate" entries in all cases. */ if (!(e->flags & KVM_CPUID_FLAG_SIGNIFCANT_INDEX) || e->index == index) @@ -314,11 +314,15 @@ EXPORT_SYMBOL_GPL(kvm_update_cpuid_runtime); static bool kvm_cpuid_has_hyperv(struct kvm_cpuid_entry2 *entries, int nent) { +#ifdef CONFIG_KVM_HYPERV struct kvm_cpuid_entry2 *entry; entry = cpuid_entry2_find(entries, nent, HYPERV_CPUID_INTERFACE, KVM_CPUID_INDEX_NOT_SIGNIFICANT); return entry && entry->eax == HYPERV_CPUID_SIGNATURE_EAX; +#else + return false; +#endif } static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) @@ -433,11 +437,13 @@ static int kvm_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *e2, return 0; } +#ifdef CONFIG_KVM_HYPERV if (kvm_cpuid_has_hyperv(e2, nent)) { r = kvm_hv_vcpu_init(vcpu); if (r) return r; } +#endif r = kvm_check_cpuid(vcpu, e2, nent); if (r) @@ -469,7 +475,7 @@ int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu, return -E2BIG; if (cpuid->nent) { - e = vmemdup_user(entries, array_size(sizeof(*e), cpuid->nent)); + e = vmemdup_array_user(entries, cpuid->nent, sizeof(*e)); if (IS_ERR(e)) return PTR_ERR(e); @@ -513,7 +519,7 @@ int kvm_vcpu_ioctl_set_cpuid2(struct kvm_vcpu *vcpu, return -E2BIG; if (cpuid->nent) { - e2 = vmemdup_user(entries, array_size(sizeof(*e2), cpuid->nent)); + e2 = vmemdup_array_user(entries, cpuid->nent, sizeof(*e2)); if (IS_ERR(e2)) return PTR_ERR(e2); } @@ -671,7 +677,7 @@ void kvm_set_cpu_caps(void) kvm_cpu_cap_mask(CPUID_7_1_EAX, F(AVX_VNNI) | F(AVX512_BF16) | F(CMPCCXADD) | F(FZRM) | F(FSRS) | F(FSRC) | - F(AMX_FP16) | F(AVX_IFMA) + F(AMX_FP16) | F(AVX_IFMA) | F(LAM) ); kvm_cpu_cap_init_kvm_defined(CPUID_7_1_EDX, @@ -679,6 +685,11 @@ void kvm_set_cpu_caps(void) F(AMX_COMPLEX) ); + kvm_cpu_cap_init_kvm_defined(CPUID_7_2_EDX, + F(INTEL_PSFD) | F(IPRED_CTRL) | F(RRSBA_CTRL) | F(DDPD_U) | + F(BHI_CTRL) | F(MCDT_NO) + ); + kvm_cpu_cap_mask(CPUID_D_1_EAX, F(XSAVEOPT) | F(XSAVEC) | F(XGETBV1) | F(XSAVES) | f_xfd ); @@ -960,13 +971,13 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function) break; /* function 7 has additional index. */ case 7: - entry->eax = min(entry->eax, 1u); + max_idx = entry->eax = min(entry->eax, 2u); cpuid_entry_override(entry, CPUID_7_0_EBX); cpuid_entry_override(entry, CPUID_7_ECX); cpuid_entry_override(entry, CPUID_7_EDX); - /* KVM only supports 0x7.0 and 0x7.1, capped above via min(). */ - if (entry->eax == 1) { + /* KVM only supports up to 0x7.2, capped above via min(). */ + if (max_idx >= 1) { entry = do_host_cpuid(array, function, 1); if (!entry) goto out; @@ -976,6 +987,16 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function) entry->ebx = 0; entry->ecx = 0; } + if (max_idx >= 2) { + entry = do_host_cpuid(array, function, 2); + if (!entry) + goto out; + + cpuid_entry_override(entry, CPUID_7_2_EDX); + entry->ecx = 0; + entry->ebx = 0; + entry->eax = 0; + } break; case 0xa: { /* Architectural Performance Monitoring */ union cpuid10_eax eax; diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h index 0b90532b6e2614..856e3037e74f3f 100644 --- a/arch/x86/kvm/cpuid.h +++ b/arch/x86/kvm/cpuid.h @@ -47,11 +47,6 @@ static inline bool kvm_vcpu_is_legal_gpa(struct kvm_vcpu *vcpu, gpa_t gpa) return !(gpa & vcpu->arch.reserved_gpa_bits); } -static inline bool kvm_vcpu_is_illegal_gpa(struct kvm_vcpu *vcpu, gpa_t gpa) -{ - return !kvm_vcpu_is_legal_gpa(vcpu, gpa); -} - static inline bool kvm_vcpu_is_legal_aligned_gpa(struct kvm_vcpu *vcpu, gpa_t gpa, gpa_t alignment) { @@ -279,4 +274,12 @@ static __always_inline bool guest_can_use(struct kvm_vcpu *vcpu, vcpu->arch.governed_features.enabled); } +static inline bool kvm_vcpu_is_legal_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) +{ + if (guest_can_use(vcpu, X86_FEATURE_LAM)) + cr3 &= ~(X86_CR3_LAM_U48 | X86_CR3_LAM_U57); + + return kvm_vcpu_is_legal_gpa(vcpu, cr3); +} + #endif diff --git a/arch/x86/kvm/debugfs.c b/arch/x86/kvm/debugfs.c index eea6ea7f14af98..95ea1a1f7403ea 100644 --- a/arch/x86/kvm/debugfs.c +++ b/arch/x86/kvm/debugfs.c @@ -111,7 +111,7 @@ static int kvm_mmu_rmaps_stat_show(struct seq_file *m, void *v) mutex_lock(&kvm->slots_lock); write_lock(&kvm->mmu_lock); - for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++) { + for (i = 0; i < kvm_arch_nr_memslot_as_ids(kvm); i++) { int bkt; slots = __kvm_memslots(kvm, i); diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 2673cd5c46cb48..e223043ef5b26f 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -687,8 +687,8 @@ static unsigned insn_alignment(struct x86_emulate_ctxt *ctxt, unsigned size) static __always_inline int __linearize(struct x86_emulate_ctxt *ctxt, struct segmented_address addr, unsigned *max_size, unsigned size, - bool write, bool fetch, - enum x86emul_mode mode, ulong *linear) + enum x86emul_mode mode, ulong *linear, + unsigned int flags) { struct desc_struct desc; bool usable; @@ -701,7 +701,7 @@ static __always_inline int __linearize(struct x86_emulate_ctxt *ctxt, *max_size = 0; switch (mode) { case X86EMUL_MODE_PROT64: - *linear = la; + *linear = la = ctxt->ops->get_untagged_addr(ctxt, la, flags); va_bits = ctxt_virt_addr_bits(ctxt); if (!__is_canonical_address(la, va_bits)) goto bad; @@ -717,11 +717,11 @@ static __always_inline int __linearize(struct x86_emulate_ctxt *ctxt, if (!usable) goto bad; /* code segment in protected mode or read-only data segment */ - if ((((ctxt->mode != X86EMUL_MODE_REAL) && (desc.type & 8)) - || !(desc.type & 2)) && write) + if ((((ctxt->mode != X86EMUL_MODE_REAL) && (desc.type & 8)) || !(desc.type & 2)) && + (flags & X86EMUL_F_WRITE)) goto bad; /* unreadable code segment */ - if (!fetch && (desc.type & 8) && !(desc.type & 2)) + if (!(flags & X86EMUL_F_FETCH) && (desc.type & 8) && !(desc.type & 2)) goto bad; lim = desc_limit_scaled(&desc); if (!(desc.type & 8) && (desc.type & 4)) { @@ -757,8 +757,8 @@ static int linearize(struct x86_emulate_ctxt *ctxt, ulong *linear) { unsigned max_size; - return __linearize(ctxt, addr, &max_size, size, write, false, - ctxt->mode, linear); + return __linearize(ctxt, addr, &max_size, size, ctxt->mode, linear, + write ? X86EMUL_F_WRITE : 0); } static inline int assign_eip(struct x86_emulate_ctxt *ctxt, ulong dst) @@ -771,7 +771,8 @@ static inline int assign_eip(struct x86_emulate_ctxt *ctxt, ulong dst) if (ctxt->op_bytes != sizeof(unsigned long)) addr.ea = dst & ((1UL << (ctxt->op_bytes << 3)) - 1); - rc = __linearize(ctxt, addr, &max_size, 1, false, true, ctxt->mode, &linear); + rc = __linearize(ctxt, addr, &max_size, 1, ctxt->mode, &linear, + X86EMUL_F_FETCH); if (rc == X86EMUL_CONTINUE) ctxt->_eip = addr.ea; return rc; @@ -907,8 +908,8 @@ static int __do_insn_fetch_bytes(struct x86_emulate_ctxt *ctxt, int op_size) * boundary check itself. Instead, we use max_size to check * against op_size. */ - rc = __linearize(ctxt, addr, &max_size, 0, false, true, ctxt->mode, - &linear); + rc = __linearize(ctxt, addr, &max_size, 0, ctxt->mode, &linear, + X86EMUL_F_FETCH); if (unlikely(rc != X86EMUL_CONTINUE)) return rc; @@ -3439,8 +3440,10 @@ static int em_invlpg(struct x86_emulate_ctxt *ctxt) { int rc; ulong linear; + unsigned int max_size; - rc = linearize(ctxt, ctxt->src.addr.mem, 1, false, &linear); + rc = __linearize(ctxt, ctxt->src.addr.mem, &max_size, 1, ctxt->mode, + &linear, X86EMUL_F_INVLPG); if (rc == X86EMUL_CONTINUE) ctxt->ops->invlpg(ctxt, linear); /* Disable writeback. */ diff --git a/arch/x86/kvm/governed_features.h b/arch/x86/kvm/governed_features.h index 423a73395c102c..ad463b1ed4e4a8 100644 --- a/arch/x86/kvm/governed_features.h +++ b/arch/x86/kvm/governed_features.h @@ -16,6 +16,7 @@ KVM_GOVERNED_X86_FEATURE(PAUSEFILTER) KVM_GOVERNED_X86_FEATURE(PFTHRESHOLD) KVM_GOVERNED_X86_FEATURE(VGIF) KVM_GOVERNED_X86_FEATURE(VNMI) +KVM_GOVERNED_X86_FEATURE(LAM) #undef KVM_GOVERNED_X86_FEATURE #undef KVM_GOVERNED_FEATURE diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 238afd7335e46d..4943f6b2bbee49 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -2388,7 +2388,7 @@ static u16 kvm_hvcall_signal_event(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *h if (!eventfd) return HV_STATUS_INVALID_PORT_ID; - eventfd_signal(eventfd, 1); + eventfd_signal(eventfd); return HV_STATUS_SUCCESS; } diff --git a/arch/x86/kvm/hyperv.h b/arch/x86/kvm/hyperv.h index f83b8db72b118c..1dc0b6604526a1 100644 --- a/arch/x86/kvm/hyperv.h +++ b/arch/x86/kvm/hyperv.h @@ -24,6 +24,8 @@ #include #include "x86.h" +#ifdef CONFIG_KVM_HYPERV + /* "Hv#1" signature */ #define HYPERV_CPUID_SIGNATURE_EAX 0x31237648 @@ -105,6 +107,17 @@ int kvm_hv_synic_set_irq(struct kvm *kvm, u32 vcpu_id, u32 sint); void kvm_hv_synic_send_eoi(struct kvm_vcpu *vcpu, int vector); int kvm_hv_activate_synic(struct kvm_vcpu *vcpu, bool dont_zero_synic_pages); +static inline bool kvm_hv_synic_has_vector(struct kvm_vcpu *vcpu, int vector) +{ + return to_hv_vcpu(vcpu) && test_bit(vector, to_hv_synic(vcpu)->vec_bitmap); +} + +static inline bool kvm_hv_synic_auto_eoi_set(struct kvm_vcpu *vcpu, int vector) +{ + return to_hv_vcpu(vcpu) && + test_bit(vector, to_hv_synic(vcpu)->auto_eoi_bitmap); +} + void kvm_hv_vcpu_uninit(struct kvm_vcpu *vcpu); bool kvm_hv_assist_page_enabled(struct kvm_vcpu *vcpu); @@ -236,6 +249,76 @@ static inline int kvm_hv_verify_vp_assist(struct kvm_vcpu *vcpu) return kvm_hv_get_assist_page(vcpu); } +static inline void kvm_hv_nested_transtion_tlb_flush(struct kvm_vcpu *vcpu, + bool tdp_enabled) +{ + /* + * KVM_REQ_HV_TLB_FLUSH flushes entries from either L1's VP_ID or + * L2's VP_ID upon request from the guest. Make sure we check for + * pending entries in the right FIFO upon L1/L2 transition as these + * requests are put by other vCPUs asynchronously. + */ + if (to_hv_vcpu(vcpu) && tdp_enabled) + kvm_make_request(KVM_REQ_HV_TLB_FLUSH, vcpu); +} + int kvm_hv_vcpu_flush_tlb(struct kvm_vcpu *vcpu); +#else /* CONFIG_KVM_HYPERV */ +static inline void kvm_hv_setup_tsc_page(struct kvm *kvm, + struct pvclock_vcpu_time_info *hv_clock) {} +static inline void kvm_hv_request_tsc_page_update(struct kvm *kvm) {} +static inline void kvm_hv_init_vm(struct kvm *kvm) {} +static inline void kvm_hv_destroy_vm(struct kvm *kvm) {} +static inline int kvm_hv_vcpu_init(struct kvm_vcpu *vcpu) +{ + return 0; +} +static inline void kvm_hv_vcpu_uninit(struct kvm_vcpu *vcpu) {} +static inline bool kvm_hv_hypercall_enabled(struct kvm_vcpu *vcpu) +{ + return false; +} +static inline int kvm_hv_hypercall(struct kvm_vcpu *vcpu) +{ + return HV_STATUS_ACCESS_DENIED; +} +static inline void kvm_hv_vcpu_purge_flush_tlb(struct kvm_vcpu *vcpu) {} +static inline void kvm_hv_free_pa_page(struct kvm *kvm) {} +static inline bool kvm_hv_synic_has_vector(struct kvm_vcpu *vcpu, int vector) +{ + return false; +} +static inline bool kvm_hv_synic_auto_eoi_set(struct kvm_vcpu *vcpu, int vector) +{ + return false; +} +static inline void kvm_hv_synic_send_eoi(struct kvm_vcpu *vcpu, int vector) {} +static inline bool kvm_hv_invtsc_suppressed(struct kvm_vcpu *vcpu) +{ + return false; +} +static inline void kvm_hv_set_cpuid(struct kvm_vcpu *vcpu, bool hyperv_enabled) {} +static inline bool kvm_hv_has_stimer_pending(struct kvm_vcpu *vcpu) +{ + return false; +} +static inline bool kvm_hv_is_tlb_flush_hcall(struct kvm_vcpu *vcpu) +{ + return false; +} +static inline bool guest_hv_cpuid_has_l2_tlb_flush(struct kvm_vcpu *vcpu) +{ + return false; +} +static inline int kvm_hv_verify_vp_assist(struct kvm_vcpu *vcpu) +{ + return 0; +} +static inline u32 kvm_hv_get_vpindex(struct kvm_vcpu *vcpu) +{ + return vcpu->vcpu_idx; +} +static inline void kvm_hv_nested_transtion_tlb_flush(struct kvm_vcpu *vcpu, bool tdp_enabled) {} +#endif /* CONFIG_KVM_HYPERV */ -#endif +#endif /* __ARCH_X86_KVM_HYPERV_H__ */ diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c index b2c397dd2bc662..ad9ca8a60144c7 100644 --- a/arch/x86/kvm/irq.c +++ b/arch/x86/kvm/irq.c @@ -118,8 +118,10 @@ static int kvm_cpu_get_extint(struct kvm_vcpu *v) if (!lapic_in_kernel(v)) return v->arch.interrupt.nr; +#ifdef CONFIG_KVM_XEN if (kvm_xen_has_interrupt(v)) return v->kvm->arch.xen.upcall_vector; +#endif if (irqchip_split(v->kvm)) { int vector = v->arch.pending_external_vector; diff --git a/arch/x86/kvm/irq_comm.c b/arch/x86/kvm/irq_comm.c index 16d076a1b91acc..68f3f6c2604693 100644 --- a/arch/x86/kvm/irq_comm.c +++ b/arch/x86/kvm/irq_comm.c @@ -144,7 +144,7 @@ int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, return kvm_irq_delivery_to_apic(kvm, NULL, &irq, NULL); } - +#ifdef CONFIG_KVM_HYPERV static int kvm_hv_set_sint(struct kvm_kernel_irq_routing_entry *e, struct kvm *kvm, int irq_source_id, int level, bool line_status) @@ -154,6 +154,7 @@ static int kvm_hv_set_sint(struct kvm_kernel_irq_routing_entry *e, return kvm_hv_synic_set_irq(kvm, e->hv_sint.vcpu, e->hv_sint.sint); } +#endif int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *e, struct kvm *kvm, int irq_source_id, int level, @@ -163,9 +164,11 @@ int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *e, int r; switch (e->type) { +#ifdef CONFIG_KVM_HYPERV case KVM_IRQ_ROUTING_HV_SINT: return kvm_hv_set_sint(e, kvm, irq_source_id, level, line_status); +#endif case KVM_IRQ_ROUTING_MSI: if (kvm_msi_route_invalid(kvm, e)) @@ -314,11 +317,13 @@ int kvm_set_routing_entry(struct kvm *kvm, if (kvm_msi_route_invalid(kvm, e)) return -EINVAL; break; +#ifdef CONFIG_KVM_HYPERV case KVM_IRQ_ROUTING_HV_SINT: e->set = kvm_hv_set_sint; e->hv_sint.vcpu = ue->u.hv_sint.vcpu; e->hv_sint.sint = ue->u.hv_sint.sint; break; +#endif #ifdef CONFIG_KVM_XEN case KVM_IRQ_ROUTING_XEN_EVTCHN: return kvm_xen_setup_evtchn(kvm, e, ue); @@ -438,5 +443,7 @@ void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu, void kvm_arch_irq_routing_update(struct kvm *kvm) { +#ifdef CONFIG_KVM_HYPERV kvm_hv_irq_routing_update(kvm); +#endif } diff --git a/arch/x86/kvm/kvm_emulate.h b/arch/x86/kvm/kvm_emulate.h index be7aeb9b8ea3b1..e6d149825169dd 100644 --- a/arch/x86/kvm/kvm_emulate.h +++ b/arch/x86/kvm/kvm_emulate.h @@ -88,6 +88,12 @@ struct x86_instruction_info { #define X86EMUL_IO_NEEDED 5 /* IO is needed to complete emulation */ #define X86EMUL_INTERCEPTED 6 /* Intercepted by nested VMCB/VMCS */ +/* x86-specific emulation flags */ +#define X86EMUL_F_WRITE BIT(0) +#define X86EMUL_F_FETCH BIT(1) +#define X86EMUL_F_IMPLICIT BIT(2) +#define X86EMUL_F_INVLPG BIT(3) + struct x86_emulate_ops { void (*vm_bugged)(struct x86_emulate_ctxt *ctxt); /* @@ -224,6 +230,9 @@ struct x86_emulate_ops { int (*leave_smm)(struct x86_emulate_ctxt *ctxt); void (*triple_fault)(struct x86_emulate_ctxt *ctxt); int (*set_xcr)(struct x86_emulate_ctxt *ctxt, u32 index, u64 xcr); + + gva_t (*get_untagged_addr)(struct x86_emulate_ctxt *ctxt, gva_t addr, + unsigned int flags); }; /* Type, address-of, and value of an instruction's operand. */ diff --git a/arch/x86/kvm/kvm_onhyperv.h b/arch/x86/kvm/kvm_onhyperv.h index f9ca3e7432b2e8..eefab3dc8498b7 100644 --- a/arch/x86/kvm/kvm_onhyperv.h +++ b/arch/x86/kvm/kvm_onhyperv.h @@ -10,6 +10,26 @@ int hv_flush_remote_tlbs_range(struct kvm *kvm, gfn_t gfn, gfn_t nr_pages); int hv_flush_remote_tlbs(struct kvm *kvm); void hv_track_root_tdp(struct kvm_vcpu *vcpu, hpa_t root_tdp); +static inline hpa_t hv_get_partition_assist_page(struct kvm_vcpu *vcpu) +{ + /* + * Partition assist page is something which Hyper-V running in L0 + * requires from KVM running in L1 before direct TLB flush for L2 + * guests can be enabled. KVM doesn't currently use the page but to + * comply with TLFS it still needs to be allocated. For now, this + * is a single page shared among all vCPUs. + */ + struct hv_partition_assist_pg **p_hv_pa_pg = + &vcpu->kvm->arch.hv_pa_pg; + + if (!*p_hv_pa_pg) + *p_hv_pa_pg = kzalloc(PAGE_SIZE, GFP_KERNEL_ACCOUNT); + + if (!*p_hv_pa_pg) + return INVALID_PAGE; + + return __pa(*p_hv_pa_pg); +} #else /* !CONFIG_HYPERV */ static inline int hv_flush_remote_tlbs(struct kvm *kvm) { diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 245b20973caee4..3242f3da245767 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -1475,8 +1475,7 @@ static int apic_set_eoi(struct kvm_lapic *apic) apic_clear_isr(vector, apic); apic_update_ppr(apic); - if (to_hv_vcpu(apic->vcpu) && - test_bit(vector, to_hv_synic(apic->vcpu)->vec_bitmap)) + if (kvm_hv_synic_has_vector(apic->vcpu, vector)) kvm_hv_synic_send_eoi(apic->vcpu, vector); kvm_ioapic_send_eoi(apic, vector); @@ -2905,7 +2904,7 @@ int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu) */ apic_clear_irr(vector, apic); - if (to_hv_vcpu(vcpu) && test_bit(vector, to_hv_synic(vcpu)->auto_eoi_bitmap)) { + if (kvm_hv_synic_auto_eoi_set(vcpu, vector)) { /* * For auto-EOI interrupts, there might be another pending * interrupt above PPR, so check whether to raise another diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h index bb8c86eefac047..60f21bb4c27b19 100644 --- a/arch/x86/kvm/mmu.h +++ b/arch/x86/kvm/mmu.h @@ -146,6 +146,14 @@ static inline unsigned long kvm_get_active_pcid(struct kvm_vcpu *vcpu) return kvm_get_pcid(vcpu, kvm_read_cr3(vcpu)); } +static inline unsigned long kvm_get_active_cr3_lam_bits(struct kvm_vcpu *vcpu) +{ + if (!guest_can_use(vcpu, X86_FEATURE_LAM)) + return 0; + + return kvm_read_cr3(vcpu) & (X86_CR3_LAM_U48 | X86_CR3_LAM_U57); +} + static inline void kvm_mmu_load_pgd(struct kvm_vcpu *vcpu) { u64 root_hpa = vcpu->arch.mmu->root.hpa; diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index c57e181bba21b4..2d6cdeab1f8a3e 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -271,15 +271,11 @@ static inline unsigned long kvm_mmu_get_guest_pgd(struct kvm_vcpu *vcpu, static inline bool kvm_available_flush_remote_tlbs_range(void) { +#if IS_ENABLED(CONFIG_HYPERV) return kvm_x86_ops.flush_remote_tlbs_range; -} - -int kvm_arch_flush_remote_tlbs_range(struct kvm *kvm, gfn_t gfn, u64 nr_pages) -{ - if (!kvm_x86_ops.flush_remote_tlbs_range) - return -EOPNOTSUPP; - - return static_call(kvm_x86_flush_remote_tlbs_range)(kvm, gfn, nr_pages); +#else + return false; +#endif } static gfn_t kvm_mmu_page_get_gfn(struct kvm_mmu_page *sp, int index); @@ -795,16 +791,26 @@ static struct kvm_lpage_info *lpage_info_slot(gfn_t gfn, return &slot->arch.lpage_info[level - 2][idx]; } +/* + * The most significant bit in disallow_lpage tracks whether or not memory + * attributes are mixed, i.e. not identical for all gfns at the current level. + * The lower order bits are used to refcount other cases where a hugepage is + * disallowed, e.g. if KVM has shadow a page table at the gfn. + */ +#define KVM_LPAGE_MIXED_FLAG BIT(31) + static void update_gfn_disallow_lpage_count(const struct kvm_memory_slot *slot, gfn_t gfn, int count) { struct kvm_lpage_info *linfo; - int i; + int old, i; for (i = PG_LEVEL_2M; i <= KVM_MAX_HUGEPAGE_LEVEL; ++i) { linfo = lpage_info_slot(gfn, slot, i); + + old = linfo->disallow_lpage; linfo->disallow_lpage += count; - WARN_ON_ONCE(linfo->disallow_lpage < 0); + WARN_ON_ONCE((old ^ linfo->disallow_lpage) & KVM_LPAGE_MIXED_FLAG); } } @@ -987,7 +993,7 @@ static void pte_list_desc_remove_entry(struct kvm *kvm, /* * The head descriptor is empty. If there are no tail descriptors, - * nullify the rmap head to mark the list as emtpy, else point the rmap + * nullify the rmap head to mark the list as empty, else point the rmap * head at the next descriptor, i.e. the new head. */ if (!head_desc->more) @@ -1382,7 +1388,7 @@ void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm, gfn_t end = slot->base_gfn + gfn_offset + __fls(mask); if (READ_ONCE(eager_page_split)) - kvm_mmu_try_split_huge_pages(kvm, slot, start, end, PG_LEVEL_4K); + kvm_mmu_try_split_huge_pages(kvm, slot, start, end + 1, PG_LEVEL_4K); kvm_mmu_slot_gfn_write_protect(kvm, slot, start, PG_LEVEL_2M); @@ -2840,9 +2846,9 @@ int mmu_try_to_unsync_pages(struct kvm *kvm, const struct kvm_memory_slot *slot, /* * Recheck after taking the spinlock, a different vCPU * may have since marked the page unsync. A false - * positive on the unprotected check above is not + * negative on the unprotected check above is not * possible as clearing sp->unsync _must_ hold mmu_lock - * for write, i.e. unsync cannot transition from 0->1 + * for write, i.e. unsync cannot transition from 1->0 * while this CPU holds mmu_lock for read (or write). */ if (READ_ONCE(sp->unsync)) @@ -3056,7 +3062,7 @@ static void direct_pte_prefetch(struct kvm_vcpu *vcpu, u64 *sptep) * * There are several ways to safely use this helper: * - * - Check mmu_invalidate_retry_hva() after grabbing the mapping level, before + * - Check mmu_invalidate_retry_gfn() after grabbing the mapping level, before * consuming it. In this case, mmu_lock doesn't need to be held during the * lookup, but it does need to be held while checking the MMU notifier. * @@ -3137,9 +3143,9 @@ out: return level; } -int kvm_mmu_max_mapping_level(struct kvm *kvm, - const struct kvm_memory_slot *slot, gfn_t gfn, - int max_level) +static int __kvm_mmu_max_mapping_level(struct kvm *kvm, + const struct kvm_memory_slot *slot, + gfn_t gfn, int max_level, bool is_private) { struct kvm_lpage_info *linfo; int host_level; @@ -3151,6 +3157,9 @@ int kvm_mmu_max_mapping_level(struct kvm *kvm, break; } + if (is_private) + return max_level; + if (max_level == PG_LEVEL_4K) return PG_LEVEL_4K; @@ -3158,6 +3167,16 @@ int kvm_mmu_max_mapping_level(struct kvm *kvm, return min(host_level, max_level); } +int kvm_mmu_max_mapping_level(struct kvm *kvm, + const struct kvm_memory_slot *slot, gfn_t gfn, + int max_level) +{ + bool is_private = kvm_slot_can_be_private(slot) && + kvm_mem_is_private(kvm, gfn); + + return __kvm_mmu_max_mapping_level(kvm, slot, gfn, max_level, is_private); +} + void kvm_mmu_hugepage_adjust(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault) { struct kvm_memory_slot *slot = fault->slot; @@ -3178,8 +3197,9 @@ void kvm_mmu_hugepage_adjust(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault * Enforce the iTLB multihit workaround after capturing the requested * level, which will be used to do precise, accurate accounting. */ - fault->req_level = kvm_mmu_max_mapping_level(vcpu->kvm, slot, - fault->gfn, fault->max_level); + fault->req_level = __kvm_mmu_max_mapping_level(vcpu->kvm, slot, + fault->gfn, fault->max_level, + fault->is_private); if (fault->req_level == PG_LEVEL_4K || fault->huge_page_disallowed) return; @@ -3556,7 +3576,7 @@ static void mmu_free_root_page(struct kvm *kvm, hpa_t *root_hpa, return; if (is_tdp_mmu_page(sp)) - kvm_tdp_mmu_put_root(kvm, sp, false); + kvm_tdp_mmu_put_root(kvm, sp); else if (!--sp->root_count && sp->role.invalid) kvm_mmu_prepare_zap_page(kvm, sp, invalid_list); @@ -3739,7 +3759,7 @@ static int mmu_first_shadow_root_alloc(struct kvm *kvm) kvm_page_track_write_tracking_enabled(kvm)) goto out_success; - for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++) { + for (i = 0; i < kvm_arch_nr_memslot_as_ids(kvm); i++) { slots = __kvm_memslots(kvm, i); kvm_for_each_memslot(slot, bkt, slots) { /* @@ -3782,7 +3802,7 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu) hpa_t root; root_pgd = kvm_mmu_get_guest_pgd(vcpu, mmu); - root_gfn = root_pgd >> PAGE_SHIFT; + root_gfn = (root_pgd & __PT_BASE_ADDR_MASK) >> PAGE_SHIFT; if (!kvm_vcpu_is_visible_gfn(vcpu, root_gfn)) { mmu->root.hpa = kvm_mmu_get_dummy_root(); @@ -4259,6 +4279,55 @@ void kvm_arch_async_page_ready(struct kvm_vcpu *vcpu, struct kvm_async_pf *work) kvm_mmu_do_page_fault(vcpu, work->cr2_or_gpa, 0, true, NULL); } +static inline u8 kvm_max_level_for_order(int order) +{ + BUILD_BUG_ON(KVM_MAX_HUGEPAGE_LEVEL > PG_LEVEL_1G); + + KVM_MMU_WARN_ON(order != KVM_HPAGE_GFN_SHIFT(PG_LEVEL_1G) && + order != KVM_HPAGE_GFN_SHIFT(PG_LEVEL_2M) && + order != KVM_HPAGE_GFN_SHIFT(PG_LEVEL_4K)); + + if (order >= KVM_HPAGE_GFN_SHIFT(PG_LEVEL_1G)) + return PG_LEVEL_1G; + + if (order >= KVM_HPAGE_GFN_SHIFT(PG_LEVEL_2M)) + return PG_LEVEL_2M; + + return PG_LEVEL_4K; +} + +static void kvm_mmu_prepare_memory_fault_exit(struct kvm_vcpu *vcpu, + struct kvm_page_fault *fault) +{ + kvm_prepare_memory_fault_exit(vcpu, fault->gfn << PAGE_SHIFT, + PAGE_SIZE, fault->write, fault->exec, + fault->is_private); +} + +static int kvm_faultin_pfn_private(struct kvm_vcpu *vcpu, + struct kvm_page_fault *fault) +{ + int max_order, r; + + if (!kvm_slot_can_be_private(fault->slot)) { + kvm_mmu_prepare_memory_fault_exit(vcpu, fault); + return -EFAULT; + } + + r = kvm_gmem_get_pfn(vcpu->kvm, fault->slot, fault->gfn, &fault->pfn, + &max_order); + if (r) { + kvm_mmu_prepare_memory_fault_exit(vcpu, fault); + return r; + } + + fault->max_level = min(kvm_max_level_for_order(max_order), + fault->max_level); + fault->map_writable = !(fault->slot->flags & KVM_MEM_READONLY); + + return RET_PF_CONTINUE; +} + static int __kvm_faultin_pfn(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault) { struct kvm_memory_slot *slot = fault->slot; @@ -4291,6 +4360,14 @@ static int __kvm_faultin_pfn(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault return RET_PF_EMULATE; } + if (fault->is_private != kvm_mem_is_private(vcpu->kvm, fault->gfn)) { + kvm_mmu_prepare_memory_fault_exit(vcpu, fault); + return -EFAULT; + } + + if (fault->is_private) + return kvm_faultin_pfn_private(vcpu, fault); + async = false; fault->pfn = __gfn_to_pfn_memslot(slot, fault->gfn, false, false, &async, fault->write, &fault->map_writable, @@ -4366,7 +4443,7 @@ static bool is_page_fault_stale(struct kvm_vcpu *vcpu, return true; return fault->slot && - mmu_invalidate_retry_hva(vcpu->kvm, fault->mmu_seq, fault->hva); + mmu_invalidate_retry_gfn(vcpu->kvm, fault->mmu_seq, fault->gfn); } static int direct_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault) @@ -6228,7 +6305,7 @@ static bool kvm_rmap_zap_gfn_range(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_e if (!kvm_memslots_have_rmaps(kvm)) return flush; - for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++) { + for (i = 0; i < kvm_arch_nr_memslot_as_ids(kvm); i++) { slots = __kvm_memslots(kvm, i); kvm_for_each_memslot_in_gfn_range(&iter, slots, gfn_start, gfn_end) { @@ -6260,7 +6337,9 @@ void kvm_zap_gfn_range(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end) write_lock(&kvm->mmu_lock); - kvm_mmu_invalidate_begin(kvm, 0, -1ul); + kvm_mmu_invalidate_begin(kvm); + + kvm_mmu_invalidate_range_add(kvm, gfn_start, gfn_end); flush = kvm_rmap_zap_gfn_range(kvm, gfn_start, gfn_end); @@ -6270,7 +6349,7 @@ void kvm_zap_gfn_range(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end) if (flush) kvm_flush_remote_tlbs_range(kvm, gfn_start, gfn_end - gfn_start); - kvm_mmu_invalidate_end(kvm, 0, -1ul); + kvm_mmu_invalidate_end(kvm); write_unlock(&kvm->mmu_lock); } @@ -6544,7 +6623,7 @@ void kvm_mmu_try_split_huge_pages(struct kvm *kvm, kvm_tdp_mmu_try_split_huge_pages(kvm, memslot, start, end, target_level, false); /* - * A TLB flush is unnecessary at this point for the same resons as in + * A TLB flush is unnecessary at this point for the same reasons as in * kvm_mmu_slot_try_split_huge_pages(). */ } @@ -6723,7 +6802,7 @@ void kvm_mmu_invalidate_mmio_sptes(struct kvm *kvm, u64 gen) * modifier prior to checking for a wrap of the MMIO generation so * that a wrap in any address space is detected. */ - gen &= ~((u64)KVM_ADDRESS_SPACE_NUM - 1); + gen &= ~((u64)kvm_arch_nr_memslot_as_ids(kvm) - 1); /* * The very rare case: if the MMIO generation number has wrapped, @@ -7176,3 +7255,163 @@ void kvm_mmu_pre_destroy_vm(struct kvm *kvm) if (kvm->arch.nx_huge_page_recovery_thread) kthread_stop(kvm->arch.nx_huge_page_recovery_thread); } + +#ifdef CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES +bool kvm_arch_pre_set_memory_attributes(struct kvm *kvm, + struct kvm_gfn_range *range) +{ + /* + * Zap SPTEs even if the slot can't be mapped PRIVATE. KVM x86 only + * supports KVM_MEMORY_ATTRIBUTE_PRIVATE, and so it *seems* like KVM + * can simply ignore such slots. But if userspace is making memory + * PRIVATE, then KVM must prevent the guest from accessing the memory + * as shared. And if userspace is making memory SHARED and this point + * is reached, then at least one page within the range was previously + * PRIVATE, i.e. the slot's possible hugepage ranges are changing. + * Zapping SPTEs in this case ensures KVM will reassess whether or not + * a hugepage can be used for affected ranges. + */ + if (WARN_ON_ONCE(!kvm_arch_has_private_mem(kvm))) + return false; + + return kvm_unmap_gfn_range(kvm, range); +} + +static bool hugepage_test_mixed(struct kvm_memory_slot *slot, gfn_t gfn, + int level) +{ + return lpage_info_slot(gfn, slot, level)->disallow_lpage & KVM_LPAGE_MIXED_FLAG; +} + +static void hugepage_clear_mixed(struct kvm_memory_slot *slot, gfn_t gfn, + int level) +{ + lpage_info_slot(gfn, slot, level)->disallow_lpage &= ~KVM_LPAGE_MIXED_FLAG; +} + +static void hugepage_set_mixed(struct kvm_memory_slot *slot, gfn_t gfn, + int level) +{ + lpage_info_slot(gfn, slot, level)->disallow_lpage |= KVM_LPAGE_MIXED_FLAG; +} + +static bool hugepage_has_attrs(struct kvm *kvm, struct kvm_memory_slot *slot, + gfn_t gfn, int level, unsigned long attrs) +{ + const unsigned long start = gfn; + const unsigned long end = start + KVM_PAGES_PER_HPAGE(level); + + if (level == PG_LEVEL_2M) + return kvm_range_has_memory_attributes(kvm, start, end, attrs); + + for (gfn = start; gfn < end; gfn += KVM_PAGES_PER_HPAGE(level - 1)) { + if (hugepage_test_mixed(slot, gfn, level - 1) || + attrs != kvm_get_memory_attributes(kvm, gfn)) + return false; + } + return true; +} + +bool kvm_arch_post_set_memory_attributes(struct kvm *kvm, + struct kvm_gfn_range *range) +{ + unsigned long attrs = range->arg.attributes; + struct kvm_memory_slot *slot = range->slot; + int level; + + lockdep_assert_held_write(&kvm->mmu_lock); + lockdep_assert_held(&kvm->slots_lock); + + /* + * Calculate which ranges can be mapped with hugepages even if the slot + * can't map memory PRIVATE. KVM mustn't create a SHARED hugepage over + * a range that has PRIVATE GFNs, and conversely converting a range to + * SHARED may now allow hugepages. + */ + if (WARN_ON_ONCE(!kvm_arch_has_private_mem(kvm))) + return false; + + /* + * The sequence matters here: upper levels consume the result of lower + * level's scanning. + */ + for (level = PG_LEVEL_2M; level <= KVM_MAX_HUGEPAGE_LEVEL; level++) { + gfn_t nr_pages = KVM_PAGES_PER_HPAGE(level); + gfn_t gfn = gfn_round_for_level(range->start, level); + + /* Process the head page if it straddles the range. */ + if (gfn != range->start || gfn + nr_pages > range->end) { + /* + * Skip mixed tracking if the aligned gfn isn't covered + * by the memslot, KVM can't use a hugepage due to the + * misaligned address regardless of memory attributes. + */ + if (gfn >= slot->base_gfn) { + if (hugepage_has_attrs(kvm, slot, gfn, level, attrs)) + hugepage_clear_mixed(slot, gfn, level); + else + hugepage_set_mixed(slot, gfn, level); + } + gfn += nr_pages; + } + + /* + * Pages entirely covered by the range are guaranteed to have + * only the attributes which were just set. + */ + for ( ; gfn + nr_pages <= range->end; gfn += nr_pages) + hugepage_clear_mixed(slot, gfn, level); + + /* + * Process the last tail page if it straddles the range and is + * contained by the memslot. Like the head page, KVM can't + * create a hugepage if the slot size is misaligned. + */ + if (gfn < range->end && + (gfn + nr_pages) <= (slot->base_gfn + slot->npages)) { + if (hugepage_has_attrs(kvm, slot, gfn, level, attrs)) + hugepage_clear_mixed(slot, gfn, level); + else + hugepage_set_mixed(slot, gfn, level); + } + } + return false; +} + +void kvm_mmu_init_memslot_memory_attributes(struct kvm *kvm, + struct kvm_memory_slot *slot) +{ + int level; + + if (!kvm_arch_has_private_mem(kvm)) + return; + + for (level = PG_LEVEL_2M; level <= KVM_MAX_HUGEPAGE_LEVEL; level++) { + /* + * Don't bother tracking mixed attributes for pages that can't + * be huge due to alignment, i.e. process only pages that are + * entirely contained by the memslot. + */ + gfn_t end = gfn_round_for_level(slot->base_gfn + slot->npages, level); + gfn_t start = gfn_round_for_level(slot->base_gfn, level); + gfn_t nr_pages = KVM_PAGES_PER_HPAGE(level); + gfn_t gfn; + + if (start < slot->base_gfn) + start += nr_pages; + + /* + * Unlike setting attributes, every potential hugepage needs to + * be manually checked as the attributes may already be mixed. + */ + for (gfn = start; gfn < end; gfn += nr_pages) { + unsigned long attrs = kvm_get_memory_attributes(kvm, gfn); + + if (hugepage_has_attrs(kvm, slot, gfn, level, attrs)) + hugepage_clear_mixed(slot, gfn, level); + else + hugepage_set_mixed(slot, gfn, level); + } + } +} +#endif diff --git a/arch/x86/kvm/mmu/mmu_internal.h b/arch/x86/kvm/mmu/mmu_internal.h index decc1f1536694f..0669a8a668cacd 100644 --- a/arch/x86/kvm/mmu/mmu_internal.h +++ b/arch/x86/kvm/mmu/mmu_internal.h @@ -13,6 +13,7 @@ #endif /* Page table builder macros common to shadow (host) PTEs and guest PTEs. */ +#define __PT_BASE_ADDR_MASK GENMASK_ULL(51, 12) #define __PT_LEVEL_SHIFT(level, bits_per_level) \ (PAGE_SHIFT + ((level) - 1) * (bits_per_level)) #define __PT_INDEX(address, level, bits_per_level) \ @@ -201,6 +202,7 @@ struct kvm_page_fault { /* Derived from mmu and global state. */ const bool is_tdp; + const bool is_private; const bool nx_huge_page_workaround_enabled; /* @@ -296,6 +298,7 @@ static inline int kvm_mmu_do_page_fault(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, .max_level = KVM_MAX_HUGEPAGE_LEVEL, .req_level = PG_LEVEL_4K, .goal_level = PG_LEVEL_4K, + .is_private = kvm_mem_is_private(vcpu->kvm, cr2_or_gpa >> PAGE_SHIFT), }; int r; diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h index c85255073f6723..4d4e98fe4f3548 100644 --- a/arch/x86/kvm/mmu/paging_tmpl.h +++ b/arch/x86/kvm/mmu/paging_tmpl.h @@ -62,7 +62,7 @@ #endif /* Common logic, but per-type values. These also need to be undefined. */ -#define PT_BASE_ADDR_MASK ((pt_element_t)(((1ULL << 52) - 1) & ~(u64)(PAGE_SIZE-1))) +#define PT_BASE_ADDR_MASK ((pt_element_t)__PT_BASE_ADDR_MASK) #define PT_LVL_ADDR_MASK(lvl) __PT_LVL_ADDR_MASK(PT_BASE_ADDR_MASK, lvl, PT_LEVEL_BITS) #define PT_LVL_OFFSET_MASK(lvl) __PT_LVL_OFFSET_MASK(PT_BASE_ADDR_MASK, lvl, PT_LEVEL_BITS) #define PT_INDEX(addr, lvl) __PT_INDEX(addr, lvl, PT_LEVEL_BITS) diff --git a/arch/x86/kvm/mmu/tdp_iter.c b/arch/x86/kvm/mmu/tdp_iter.c index bd30ebfb2f2c96..04c247bfe318bc 100644 --- a/arch/x86/kvm/mmu/tdp_iter.c +++ b/arch/x86/kvm/mmu/tdp_iter.c @@ -146,7 +146,7 @@ static bool try_step_up(struct tdp_iter *iter) * Step to the next SPTE in a pre-order traversal of the paging structure. * To get to the next SPTE, the iterator either steps down towards the goal * GFN, if at a present, non-last-level SPTE, or over to a SPTE mapping a - * highter GFN. + * higher GFN. * * The basic algorithm is as follows: * 1. If the current SPTE is a non-last-level SPTE, step down into the page diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c index 6cd4dd631a2fac..6ae19b4ee5b1cb 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.c +++ b/arch/x86/kvm/mmu/tdp_mmu.c @@ -73,11 +73,8 @@ static void tdp_mmu_free_sp_rcu_callback(struct rcu_head *head) tdp_mmu_free_sp(sp); } -void kvm_tdp_mmu_put_root(struct kvm *kvm, struct kvm_mmu_page *root, - bool shared) +void kvm_tdp_mmu_put_root(struct kvm *kvm, struct kvm_mmu_page *root) { - kvm_lockdep_assert_mmu_lock_held(kvm, shared); - if (!refcount_dec_and_test(&root->tdp_mmu_root_count)) return; @@ -106,10 +103,16 @@ void kvm_tdp_mmu_put_root(struct kvm *kvm, struct kvm_mmu_page *root, */ static struct kvm_mmu_page *tdp_mmu_next_root(struct kvm *kvm, struct kvm_mmu_page *prev_root, - bool shared, bool only_valid) + bool only_valid) { struct kvm_mmu_page *next_root; + /* + * While the roots themselves are RCU-protected, fields such as + * role.invalid are protected by mmu_lock. + */ + lockdep_assert_held(&kvm->mmu_lock); + rcu_read_lock(); if (prev_root) @@ -132,7 +135,7 @@ static struct kvm_mmu_page *tdp_mmu_next_root(struct kvm *kvm, rcu_read_unlock(); if (prev_root) - kvm_tdp_mmu_put_root(kvm, prev_root, shared); + kvm_tdp_mmu_put_root(kvm, prev_root); return next_root; } @@ -144,26 +147,22 @@ static struct kvm_mmu_page *tdp_mmu_next_root(struct kvm *kvm, * recent root. (Unless keeping a live reference is desirable.) * * If shared is set, this function is operating under the MMU lock in read - * mode. In the unlikely event that this thread must free a root, the lock - * will be temporarily dropped and reacquired in write mode. + * mode. */ -#define __for_each_tdp_mmu_root_yield_safe(_kvm, _root, _as_id, _shared, _only_valid)\ - for (_root = tdp_mmu_next_root(_kvm, NULL, _shared, _only_valid); \ - _root; \ - _root = tdp_mmu_next_root(_kvm, _root, _shared, _only_valid)) \ - if (kvm_lockdep_assert_mmu_lock_held(_kvm, _shared) && \ - kvm_mmu_page_as_id(_root) != _as_id) { \ +#define __for_each_tdp_mmu_root_yield_safe(_kvm, _root, _as_id, _only_valid)\ + for (_root = tdp_mmu_next_root(_kvm, NULL, _only_valid); \ + ({ lockdep_assert_held(&(_kvm)->mmu_lock); }), _root; \ + _root = tdp_mmu_next_root(_kvm, _root, _only_valid)) \ + if (kvm_mmu_page_as_id(_root) != _as_id) { \ } else -#define for_each_valid_tdp_mmu_root_yield_safe(_kvm, _root, _as_id, _shared) \ - __for_each_tdp_mmu_root_yield_safe(_kvm, _root, _as_id, _shared, true) +#define for_each_valid_tdp_mmu_root_yield_safe(_kvm, _root, _as_id) \ + __for_each_tdp_mmu_root_yield_safe(_kvm, _root, _as_id, true) -#define for_each_tdp_mmu_root_yield_safe(_kvm, _root, _shared) \ - for (_root = tdp_mmu_next_root(_kvm, NULL, _shared, false); \ - _root; \ - _root = tdp_mmu_next_root(_kvm, _root, _shared, false)) \ - if (!kvm_lockdep_assert_mmu_lock_held(_kvm, _shared)) { \ - } else +#define for_each_tdp_mmu_root_yield_safe(_kvm, _root) \ + for (_root = tdp_mmu_next_root(_kvm, NULL, false); \ + ({ lockdep_assert_held(&(_kvm)->mmu_lock); }), _root; \ + _root = tdp_mmu_next_root(_kvm, _root, false)) /* * Iterate over all TDP MMU roots. Requires that mmu_lock be held for write, @@ -276,28 +275,18 @@ static void tdp_unaccount_mmu_page(struct kvm *kvm, struct kvm_mmu_page *sp) * * @kvm: kvm instance * @sp: the page to be removed - * @shared: This operation may not be running under the exclusive use of - * the MMU lock and the operation must synchronize with other - * threads that might be adding or removing pages. */ -static void tdp_mmu_unlink_sp(struct kvm *kvm, struct kvm_mmu_page *sp, - bool shared) +static void tdp_mmu_unlink_sp(struct kvm *kvm, struct kvm_mmu_page *sp) { tdp_unaccount_mmu_page(kvm, sp); if (!sp->nx_huge_page_disallowed) return; - if (shared) - spin_lock(&kvm->arch.tdp_mmu_pages_lock); - else - lockdep_assert_held_write(&kvm->mmu_lock); - + spin_lock(&kvm->arch.tdp_mmu_pages_lock); sp->nx_huge_page_disallowed = false; untrack_possible_nx_huge_page(kvm, sp); - - if (shared) - spin_unlock(&kvm->arch.tdp_mmu_pages_lock); + spin_unlock(&kvm->arch.tdp_mmu_pages_lock); } /** @@ -326,7 +315,7 @@ static void handle_removed_pt(struct kvm *kvm, tdp_ptep_t pt, bool shared) trace_kvm_mmu_prepare_zap_page(sp); - tdp_mmu_unlink_sp(kvm, sp, shared); + tdp_mmu_unlink_sp(kvm, sp); for (i = 0; i < SPTE_ENT_PER_PAGE; i++) { tdp_ptep_t sptep = pt + i; @@ -832,7 +821,8 @@ bool kvm_tdp_mmu_zap_leafs(struct kvm *kvm, gfn_t start, gfn_t end, bool flush) { struct kvm_mmu_page *root; - for_each_tdp_mmu_root_yield_safe(kvm, root, false) + lockdep_assert_held_write(&kvm->mmu_lock); + for_each_tdp_mmu_root_yield_safe(kvm, root) flush = tdp_mmu_zap_leafs(kvm, root, start, end, true, flush); return flush; @@ -854,7 +844,8 @@ void kvm_tdp_mmu_zap_all(struct kvm *kvm) * is being destroyed or the userspace VMM has exited. In both cases, * KVM_RUN is unreachable, i.e. no vCPUs will ever service the request. */ - for_each_tdp_mmu_root_yield_safe(kvm, root, false) + lockdep_assert_held_write(&kvm->mmu_lock); + for_each_tdp_mmu_root_yield_safe(kvm, root) tdp_mmu_zap_root(kvm, root, false); } @@ -868,7 +859,7 @@ void kvm_tdp_mmu_zap_invalidated_roots(struct kvm *kvm) read_lock(&kvm->mmu_lock); - for_each_tdp_mmu_root_yield_safe(kvm, root, true) { + for_each_tdp_mmu_root_yield_safe(kvm, root) { if (!root->tdp_mmu_scheduled_root_to_zap) continue; @@ -891,7 +882,7 @@ void kvm_tdp_mmu_zap_invalidated_roots(struct kvm *kvm) * the root must be reachable by mmu_notifiers while it's being * zapped */ - kvm_tdp_mmu_put_root(kvm, root, true); + kvm_tdp_mmu_put_root(kvm, root); } read_unlock(&kvm->mmu_lock); @@ -1125,7 +1116,7 @@ bool kvm_tdp_mmu_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range, { struct kvm_mmu_page *root; - __for_each_tdp_mmu_root_yield_safe(kvm, root, range->slot->as_id, false, false) + __for_each_tdp_mmu_root_yield_safe(kvm, root, range->slot->as_id, false) flush = tdp_mmu_zap_leafs(kvm, root, range->start, range->end, range->may_block, flush); @@ -1314,7 +1305,7 @@ bool kvm_tdp_mmu_wrprot_slot(struct kvm *kvm, lockdep_assert_held_read(&kvm->mmu_lock); - for_each_valid_tdp_mmu_root_yield_safe(kvm, root, slot->as_id, true) + for_each_valid_tdp_mmu_root_yield_safe(kvm, root, slot->as_id) spte_set |= wrprot_gfn_range(kvm, root, slot->base_gfn, slot->base_gfn + slot->npages, min_level); @@ -1346,6 +1337,8 @@ static struct kvm_mmu_page *tdp_mmu_alloc_sp_for_split(struct kvm *kvm, { struct kvm_mmu_page *sp; + kvm_lockdep_assert_mmu_lock_held(kvm, shared); + /* * Since we are allocating while under the MMU lock we have to be * careful about GFP flags. Use GFP_NOWAIT to avoid blocking on direct @@ -1496,11 +1489,10 @@ void kvm_tdp_mmu_try_split_huge_pages(struct kvm *kvm, int r = 0; kvm_lockdep_assert_mmu_lock_held(kvm, shared); - - for_each_valid_tdp_mmu_root_yield_safe(kvm, root, slot->as_id, shared) { + for_each_valid_tdp_mmu_root_yield_safe(kvm, root, slot->as_id) { r = tdp_mmu_split_huge_pages_root(kvm, root, start, end, target_level, shared); if (r) { - kvm_tdp_mmu_put_root(kvm, root, shared); + kvm_tdp_mmu_put_root(kvm, root); break; } } @@ -1522,12 +1514,13 @@ static bool clear_dirty_gfn_range(struct kvm *kvm, struct kvm_mmu_page *root, rcu_read_lock(); - tdp_root_for_each_leaf_pte(iter, root, start, end) { + tdp_root_for_each_pte(iter, root, start, end) { retry: - if (tdp_mmu_iter_cond_resched(kvm, &iter, false, true)) + if (!is_shadow_present_pte(iter.old_spte) || + !is_last_spte(iter.old_spte, iter.level)) continue; - if (!is_shadow_present_pte(iter.old_spte)) + if (tdp_mmu_iter_cond_resched(kvm, &iter, false, true)) continue; KVM_MMU_WARN_ON(kvm_ad_enabled() && @@ -1560,8 +1553,7 @@ bool kvm_tdp_mmu_clear_dirty_slot(struct kvm *kvm, bool spte_set = false; lockdep_assert_held_read(&kvm->mmu_lock); - - for_each_valid_tdp_mmu_root_yield_safe(kvm, root, slot->as_id, true) + for_each_valid_tdp_mmu_root_yield_safe(kvm, root, slot->as_id) spte_set |= clear_dirty_gfn_range(kvm, root, slot->base_gfn, slot->base_gfn + slot->npages); @@ -1695,8 +1687,7 @@ void kvm_tdp_mmu_zap_collapsible_sptes(struct kvm *kvm, struct kvm_mmu_page *root; lockdep_assert_held_read(&kvm->mmu_lock); - - for_each_valid_tdp_mmu_root_yield_safe(kvm, root, slot->as_id, true) + for_each_valid_tdp_mmu_root_yield_safe(kvm, root, slot->as_id) zap_collapsible_spte_range(kvm, root, slot); } diff --git a/arch/x86/kvm/mmu/tdp_mmu.h b/arch/x86/kvm/mmu/tdp_mmu.h index 733a3aef3a96ea..20d97aa46c490f 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.h +++ b/arch/x86/kvm/mmu/tdp_mmu.h @@ -17,8 +17,7 @@ __must_check static inline bool kvm_tdp_mmu_get_root(struct kvm_mmu_page *root) return refcount_inc_not_zero(&root->tdp_mmu_root_count); } -void kvm_tdp_mmu_put_root(struct kvm *kvm, struct kvm_mmu_page *root, - bool shared); +void kvm_tdp_mmu_put_root(struct kvm *kvm, struct kvm_mmu_page *root); bool kvm_tdp_mmu_zap_leafs(struct kvm *kvm, gfn_t start, gfn_t end, bool flush); bool kvm_tdp_mmu_zap_sp(struct kvm *kvm, struct kvm_mmu_page *sp); diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 9ae07db6f0f648..87cc6c8809ad88 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -127,9 +127,9 @@ static void kvm_perf_overflow(struct perf_event *perf_event, struct kvm_pmc *pmc = perf_event->overflow_handler_context; /* - * Ignore overflow events for counters that are scheduled to be - * reprogrammed, e.g. if a PMI for the previous event races with KVM's - * handling of a related guest WRMSR. + * Ignore asynchronous overflow events for counters that are scheduled + * to be reprogrammed, e.g. if a PMI for the previous event races with + * KVM's handling of a related guest WRMSR. */ if (test_and_set_bit(pmc->idx, pmc_to_pmu(pmc)->reprogram_pmi)) return; @@ -161,6 +161,15 @@ static u64 pmc_get_pebs_precise_level(struct kvm_pmc *pmc) return 1; } +static u64 get_sample_period(struct kvm_pmc *pmc, u64 counter_value) +{ + u64 sample_period = (-counter_value) & pmc_bitmask(pmc); + + if (!sample_period) + sample_period = pmc_bitmask(pmc) + 1; + return sample_period; +} + static int pmc_reprogram_counter(struct kvm_pmc *pmc, u32 type, u64 config, bool exclude_user, bool exclude_kernel, bool intr) @@ -215,17 +224,30 @@ static int pmc_reprogram_counter(struct kvm_pmc *pmc, u32 type, u64 config, return 0; } -static void pmc_pause_counter(struct kvm_pmc *pmc) +static bool pmc_pause_counter(struct kvm_pmc *pmc) { u64 counter = pmc->counter; - - if (!pmc->perf_event || pmc->is_paused) - return; + u64 prev_counter; /* update counter, reset event value to avoid redundant accumulation */ - counter += perf_event_pause(pmc->perf_event, true); + if (pmc->perf_event && !pmc->is_paused) + counter += perf_event_pause(pmc->perf_event, true); + + /* + * Snapshot the previous counter *after* accumulating state from perf. + * If overflow already happened, hardware (via perf) is responsible for + * generating a PMI. KVM just needs to detect overflow on emulated + * counter events that haven't yet been processed. + */ + prev_counter = counter & pmc_bitmask(pmc); + + counter += pmc->emulated_counter; pmc->counter = counter & pmc_bitmask(pmc); + + pmc->emulated_counter = 0; pmc->is_paused = true; + + return pmc->counter < prev_counter; } static bool pmc_resume_counter(struct kvm_pmc *pmc) @@ -250,6 +272,51 @@ static bool pmc_resume_counter(struct kvm_pmc *pmc) return true; } +static void pmc_release_perf_event(struct kvm_pmc *pmc) +{ + if (pmc->perf_event) { + perf_event_release_kernel(pmc->perf_event); + pmc->perf_event = NULL; + pmc->current_config = 0; + pmc_to_pmu(pmc)->event_count--; + } +} + +static void pmc_stop_counter(struct kvm_pmc *pmc) +{ + if (pmc->perf_event) { + pmc->counter = pmc_read_counter(pmc); + pmc_release_perf_event(pmc); + } +} + +static void pmc_update_sample_period(struct kvm_pmc *pmc) +{ + if (!pmc->perf_event || pmc->is_paused || + !is_sampling_event(pmc->perf_event)) + return; + + perf_event_period(pmc->perf_event, + get_sample_period(pmc, pmc->counter)); +} + +void pmc_write_counter(struct kvm_pmc *pmc, u64 val) +{ + /* + * Drop any unconsumed accumulated counts, the WRMSR is a write, not a + * read-modify-write. Adjust the counter value so that its value is + * relative to the current count, as reading the current count from + * perf is faster than pausing and repgrogramming the event in order to + * reset it to '0'. Note, this very sneakily offsets the accumulated + * emulated count too, by using pmc_read_counter()! + */ + pmc->emulated_counter = 0; + pmc->counter += val - pmc_read_counter(pmc); + pmc->counter &= pmc_bitmask(pmc); + pmc_update_sample_period(pmc); +} +EXPORT_SYMBOL_GPL(pmc_write_counter); + static int filter_cmp(const void *pa, const void *pb, u64 mask) { u64 a = *(u64 *)pa & mask; @@ -383,14 +450,15 @@ static void reprogram_counter(struct kvm_pmc *pmc) struct kvm_pmu *pmu = pmc_to_pmu(pmc); u64 eventsel = pmc->eventsel; u64 new_config = eventsel; + bool emulate_overflow; u8 fixed_ctr_ctrl; - pmc_pause_counter(pmc); + emulate_overflow = pmc_pause_counter(pmc); if (!pmc_event_is_allowed(pmc)) goto reprogram_complete; - if (pmc->counter < pmc->prev_counter) + if (emulate_overflow) __kvm_perf_overflow(pmc, false); if (eventsel & ARCH_PERFMON_EVENTSEL_PIN_CONTROL) @@ -430,7 +498,6 @@ static void reprogram_counter(struct kvm_pmc *pmc) reprogram_complete: clear_bit(pmc->idx, (unsigned long *)&pmc_to_pmu(pmc)->reprogram_pmi); - pmc->prev_counter = 0; } void kvm_pmu_handle_event(struct kvm_vcpu *vcpu) @@ -639,32 +706,60 @@ int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) return 0; } -/* refresh PMU settings. This function generally is called when underlying - * settings are changed (such as changes of PMU CPUID by guest VMs), which - * should rarely happen. +static void kvm_pmu_reset(struct kvm_vcpu *vcpu) +{ + struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); + struct kvm_pmc *pmc; + int i; + + pmu->need_cleanup = false; + + bitmap_zero(pmu->reprogram_pmi, X86_PMC_IDX_MAX); + + for_each_set_bit(i, pmu->all_valid_pmc_idx, X86_PMC_IDX_MAX) { + pmc = static_call(kvm_x86_pmu_pmc_idx_to_pmc)(pmu, i); + if (!pmc) + continue; + + pmc_stop_counter(pmc); + pmc->counter = 0; + pmc->emulated_counter = 0; + + if (pmc_is_gp(pmc)) + pmc->eventsel = 0; + } + + pmu->fixed_ctr_ctrl = pmu->global_ctrl = pmu->global_status = 0; + + static_call_cond(kvm_x86_pmu_reset)(vcpu); +} + + +/* + * Refresh the PMU configuration for the vCPU, e.g. if userspace changes CPUID + * and/or PERF_CAPABILITIES. */ void kvm_pmu_refresh(struct kvm_vcpu *vcpu) { if (KVM_BUG_ON(kvm_vcpu_has_run(vcpu), vcpu->kvm)) return; + /* + * Stop/release all existing counters/events before realizing the new + * vPMU model. + */ + kvm_pmu_reset(vcpu); + bitmap_zero(vcpu_to_pmu(vcpu)->all_valid_pmc_idx, X86_PMC_IDX_MAX); static_call(kvm_x86_pmu_refresh)(vcpu); } -void kvm_pmu_reset(struct kvm_vcpu *vcpu) -{ - static_call(kvm_x86_pmu_reset)(vcpu); -} - void kvm_pmu_init(struct kvm_vcpu *vcpu) { struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); memset(pmu, 0, sizeof(*pmu)); static_call(kvm_x86_pmu_init)(vcpu); - pmu->event_count = 0; - pmu->need_cleanup = false; kvm_pmu_refresh(vcpu); } @@ -700,8 +795,7 @@ void kvm_pmu_destroy(struct kvm_vcpu *vcpu) static void kvm_pmu_incr_counter(struct kvm_pmc *pmc) { - pmc->prev_counter = pmc->counter; - pmc->counter = (pmc->counter + 1) & pmc_bitmask(pmc); + pmc->emulated_counter++; kvm_pmu_request_counter_reprogram(pmc); } diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index 1d64113de4883e..7caeb3d8d4fd17 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -66,7 +66,8 @@ static inline u64 pmc_read_counter(struct kvm_pmc *pmc) { u64 counter, enabled, running; - counter = pmc->counter; + counter = pmc->counter + pmc->emulated_counter; + if (pmc->perf_event && !pmc->is_paused) counter += perf_event_read_value(pmc->perf_event, &enabled, &running); @@ -74,29 +75,7 @@ static inline u64 pmc_read_counter(struct kvm_pmc *pmc) return counter & pmc_bitmask(pmc); } -static inline void pmc_write_counter(struct kvm_pmc *pmc, u64 val) -{ - pmc->counter += val - pmc_read_counter(pmc); - pmc->counter &= pmc_bitmask(pmc); -} - -static inline void pmc_release_perf_event(struct kvm_pmc *pmc) -{ - if (pmc->perf_event) { - perf_event_release_kernel(pmc->perf_event); - pmc->perf_event = NULL; - pmc->current_config = 0; - pmc_to_pmu(pmc)->event_count--; - } -} - -static inline void pmc_stop_counter(struct kvm_pmc *pmc) -{ - if (pmc->perf_event) { - pmc->counter = pmc_read_counter(pmc); - pmc_release_perf_event(pmc); - } -} +void pmc_write_counter(struct kvm_pmc *pmc, u64 val); static inline bool pmc_is_gp(struct kvm_pmc *pmc) { @@ -146,25 +125,6 @@ static inline struct kvm_pmc *get_fixed_pmc(struct kvm_pmu *pmu, u32 msr) return NULL; } -static inline u64 get_sample_period(struct kvm_pmc *pmc, u64 counter_value) -{ - u64 sample_period = (-counter_value) & pmc_bitmask(pmc); - - if (!sample_period) - sample_period = pmc_bitmask(pmc) + 1; - return sample_period; -} - -static inline void pmc_update_sample_period(struct kvm_pmc *pmc) -{ - if (!pmc->perf_event || pmc->is_paused || - !is_sampling_event(pmc->perf_event)) - return; - - perf_event_period(pmc->perf_event, - get_sample_period(pmc, pmc->counter)); -} - static inline bool pmc_speculative_in_use(struct kvm_pmc *pmc) { struct kvm_pmu *pmu = pmc_to_pmu(pmc); @@ -261,7 +221,6 @@ bool kvm_pmu_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr); int kvm_pmu_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info); int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info); void kvm_pmu_refresh(struct kvm_vcpu *vcpu); -void kvm_pmu_reset(struct kvm_vcpu *vcpu); void kvm_pmu_init(struct kvm_vcpu *vcpu); void kvm_pmu_cleanup(struct kvm_vcpu *vcpu); void kvm_pmu_destroy(struct kvm_vcpu *vcpu); diff --git a/arch/x86/kvm/reverse_cpuid.h b/arch/x86/kvm/reverse_cpuid.h index b816506783755a..aadefcaa9561d0 100644 --- a/arch/x86/kvm/reverse_cpuid.h +++ b/arch/x86/kvm/reverse_cpuid.h @@ -16,6 +16,7 @@ enum kvm_only_cpuid_leafs { CPUID_7_1_EDX, CPUID_8000_0007_EDX, CPUID_8000_0022_EAX, + CPUID_7_2_EDX, NR_KVM_CPU_CAPS, NKVMCAPINTS = NR_KVM_CPU_CAPS - NCAPINTS, @@ -46,6 +47,14 @@ enum kvm_only_cpuid_leafs { #define X86_FEATURE_AMX_COMPLEX KVM_X86_FEATURE(CPUID_7_1_EDX, 8) #define X86_FEATURE_PREFETCHITI KVM_X86_FEATURE(CPUID_7_1_EDX, 14) +/* Intel-defined sub-features, CPUID level 0x00000007:2 (EDX) */ +#define X86_FEATURE_INTEL_PSFD KVM_X86_FEATURE(CPUID_7_2_EDX, 0) +#define X86_FEATURE_IPRED_CTRL KVM_X86_FEATURE(CPUID_7_2_EDX, 1) +#define KVM_X86_FEATURE_RRSBA_CTRL KVM_X86_FEATURE(CPUID_7_2_EDX, 2) +#define X86_FEATURE_DDPD_U KVM_X86_FEATURE(CPUID_7_2_EDX, 3) +#define X86_FEATURE_BHI_CTRL KVM_X86_FEATURE(CPUID_7_2_EDX, 4) +#define X86_FEATURE_MCDT_NO KVM_X86_FEATURE(CPUID_7_2_EDX, 5) + /* CPUID level 0x80000007 (EDX). */ #define KVM_X86_FEATURE_CONSTANT_TSC KVM_X86_FEATURE(CPUID_8000_0007_EDX, 8) @@ -80,6 +89,7 @@ static const struct cpuid_reg reverse_cpuid[] = { [CPUID_8000_0007_EDX] = {0x80000007, 0, CPUID_EDX}, [CPUID_8000_0021_EAX] = {0x80000021, 0, CPUID_EAX}, [CPUID_8000_0022_EAX] = {0x80000022, 0, CPUID_EAX}, + [CPUID_7_2_EDX] = { 7, 2, CPUID_EDX}, }; /* @@ -106,18 +116,19 @@ static __always_inline void reverse_cpuid_check(unsigned int x86_leaf) */ static __always_inline u32 __feature_translate(int x86_feature) { - if (x86_feature == X86_FEATURE_SGX1) - return KVM_X86_FEATURE_SGX1; - else if (x86_feature == X86_FEATURE_SGX2) - return KVM_X86_FEATURE_SGX2; - else if (x86_feature == X86_FEATURE_SGX_EDECCSSA) - return KVM_X86_FEATURE_SGX_EDECCSSA; - else if (x86_feature == X86_FEATURE_CONSTANT_TSC) - return KVM_X86_FEATURE_CONSTANT_TSC; - else if (x86_feature == X86_FEATURE_PERFMON_V2) - return KVM_X86_FEATURE_PERFMON_V2; - - return x86_feature; +#define KVM_X86_TRANSLATE_FEATURE(f) \ + case X86_FEATURE_##f: return KVM_X86_FEATURE_##f + + switch (x86_feature) { + KVM_X86_TRANSLATE_FEATURE(SGX1); + KVM_X86_TRANSLATE_FEATURE(SGX2); + KVM_X86_TRANSLATE_FEATURE(SGX_EDECCSSA); + KVM_X86_TRANSLATE_FEATURE(CONSTANT_TSC); + KVM_X86_TRANSLATE_FEATURE(PERFMON_V2); + KVM_X86_TRANSLATE_FEATURE(RRSBA_CTRL); + default: + return x86_feature; + } } static __always_inline u32 __feature_leaf(int x86_feature) diff --git a/arch/x86/kvm/svm/hyperv.h b/arch/x86/kvm/svm/hyperv.h index 02f4784b5d446b..d3f8bfc05832ee 100644 --- a/arch/x86/kvm/svm/hyperv.h +++ b/arch/x86/kvm/svm/hyperv.h @@ -11,6 +11,7 @@ #include "../hyperv.h" #include "svm.h" +#ifdef CONFIG_KVM_HYPERV static inline void nested_svm_hv_update_vm_vp_ids(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); @@ -41,5 +42,13 @@ static inline bool nested_svm_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu) } void svm_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu); +#else /* CONFIG_KVM_HYPERV */ +static inline void nested_svm_hv_update_vm_vp_ids(struct kvm_vcpu *vcpu) {} +static inline bool nested_svm_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu) +{ + return false; +} +static inline void svm_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu) {} +#endif /* CONFIG_KVM_HYPERV */ #endif /* __ARCH_X86_KVM_SVM_HYPERV_H__ */ diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c index 3fea8c47679e68..dee62362a360ad 100644 --- a/arch/x86/kvm/svm/nested.c +++ b/arch/x86/kvm/svm/nested.c @@ -187,7 +187,6 @@ void recalc_intercepts(struct vcpu_svm *svm) */ static bool nested_svm_vmrun_msrpm(struct vcpu_svm *svm) { - struct hv_vmcb_enlightenments *hve = &svm->nested.ctl.hv_enlightenments; int i; /* @@ -198,11 +197,16 @@ static bool nested_svm_vmrun_msrpm(struct vcpu_svm *svm) * - Nested hypervisor (L1) is using Hyper-V emulation interface and * tells KVM (L0) there were no changes in MSR bitmap for L2. */ - if (!svm->nested.force_msr_bitmap_recalc && - kvm_hv_hypercall_enabled(&svm->vcpu) && - hve->hv_enlightenments_control.msr_bitmap && - (svm->nested.ctl.clean & BIT(HV_VMCB_NESTED_ENLIGHTENMENTS))) - goto set_msrpm_base_pa; +#ifdef CONFIG_KVM_HYPERV + if (!svm->nested.force_msr_bitmap_recalc) { + struct hv_vmcb_enlightenments *hve = &svm->nested.ctl.hv_enlightenments; + + if (kvm_hv_hypercall_enabled(&svm->vcpu) && + hve->hv_enlightenments_control.msr_bitmap && + (svm->nested.ctl.clean & BIT(HV_VMCB_NESTED_ENLIGHTENMENTS))) + goto set_msrpm_base_pa; + } +#endif if (!(vmcb12_is_intercept(&svm->nested.ctl, INTERCEPT_MSR_PROT))) return true; @@ -230,7 +234,9 @@ static bool nested_svm_vmrun_msrpm(struct vcpu_svm *svm) svm->nested.force_msr_bitmap_recalc = false; +#ifdef CONFIG_KVM_HYPERV set_msrpm_base_pa: +#endif svm->vmcb->control.msrpm_base_pa = __sme_set(__pa(svm->nested.msrpm)); return true; @@ -247,18 +253,6 @@ static bool nested_svm_check_bitmap_pa(struct kvm_vcpu *vcpu, u64 pa, u32 size) kvm_vcpu_is_legal_gpa(vcpu, addr + size - 1); } -static bool nested_svm_check_tlb_ctl(struct kvm_vcpu *vcpu, u8 tlb_ctl) -{ - /* Nested FLUSHBYASID is not supported yet. */ - switch(tlb_ctl) { - case TLB_CONTROL_DO_NOTHING: - case TLB_CONTROL_FLUSH_ALL_ASID: - return true; - default: - return false; - } -} - static bool __nested_vmcb_check_controls(struct kvm_vcpu *vcpu, struct vmcb_ctrl_area_cached *control) { @@ -278,9 +272,6 @@ static bool __nested_vmcb_check_controls(struct kvm_vcpu *vcpu, IOPM_SIZE))) return false; - if (CC(!nested_svm_check_tlb_ctl(vcpu, control->tlb_ctl))) - return false; - if (CC((control->int_ctl & V_NMI_ENABLE_MASK) && !vmcb12_is_intercept(control, INTERCEPT_NMI))) { return false; @@ -311,7 +302,7 @@ static bool __nested_vmcb_check_save(struct kvm_vcpu *vcpu, if ((save->efer & EFER_LME) && (save->cr0 & X86_CR0_PG)) { if (CC(!(save->cr4 & X86_CR4_PAE)) || CC(!(save->cr0 & X86_CR0_PE)) || - CC(kvm_vcpu_is_illegal_gpa(vcpu, save->cr3))) + CC(!kvm_vcpu_is_legal_cr3(vcpu, save->cr3))) return false; } @@ -378,12 +369,14 @@ void __nested_copy_vmcb_control_to_cache(struct kvm_vcpu *vcpu, to->msrpm_base_pa &= ~0x0fffULL; to->iopm_base_pa &= ~0x0fffULL; +#ifdef CONFIG_KVM_HYPERV /* Hyper-V extensions (Enlightened VMCB) */ if (kvm_hv_hypercall_enabled(vcpu)) { to->clean = from->clean; memcpy(&to->hv_enlightenments, &from->hv_enlightenments, sizeof(to->hv_enlightenments)); } +#endif } void nested_copy_vmcb_control_to_cache(struct vcpu_svm *svm, @@ -487,14 +480,8 @@ static void nested_save_pending_event_to_vmcb12(struct vcpu_svm *svm, static void nested_svm_transition_tlb_flush(struct kvm_vcpu *vcpu) { - /* - * KVM_REQ_HV_TLB_FLUSH flushes entries from either L1's VP_ID or - * L2's VP_ID upon request from the guest. Make sure we check for - * pending entries in the right FIFO upon L1/L2 transition as these - * requests are put by other vCPUs asynchronously. - */ - if (to_hv_vcpu(vcpu) && npt_enabled) - kvm_make_request(KVM_REQ_HV_TLB_FLUSH, vcpu); + /* Handle pending Hyper-V TLB flush requests */ + kvm_hv_nested_transtion_tlb_flush(vcpu, npt_enabled); /* * TODO: optimize unconditional TLB flush/MMU sync. A partial list of @@ -520,7 +507,7 @@ static void nested_svm_transition_tlb_flush(struct kvm_vcpu *vcpu) static int nested_svm_load_cr3(struct kvm_vcpu *vcpu, unsigned long cr3, bool nested_npt, bool reload_pdptrs) { - if (CC(kvm_vcpu_is_illegal_gpa(vcpu, cr3))) + if (CC(!kvm_vcpu_is_legal_cr3(vcpu, cr3))) return -EINVAL; if (reload_pdptrs && !nested_npt && is_pae_paging(vcpu) && diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c index 373ff6a6687b3a..b6a7ad4d691450 100644 --- a/arch/x86/kvm/svm/pmu.c +++ b/arch/x86/kvm/svm/pmu.c @@ -161,7 +161,6 @@ static int amd_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) pmc = get_gp_pmc_amd(pmu, msr, PMU_TYPE_COUNTER); if (pmc) { pmc_write_counter(pmc, data); - pmc_update_sample_period(pmc); return 0; } /* MSR_EVNTSELn */ @@ -233,21 +232,6 @@ static void amd_pmu_init(struct kvm_vcpu *vcpu) } } -static void amd_pmu_reset(struct kvm_vcpu *vcpu) -{ - struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); - int i; - - for (i = 0; i < KVM_AMD_PMC_MAX_GENERIC; i++) { - struct kvm_pmc *pmc = &pmu->gp_counters[i]; - - pmc_stop_counter(pmc); - pmc->counter = pmc->prev_counter = pmc->eventsel = 0; - } - - pmu->global_ctrl = pmu->global_status = 0; -} - struct kvm_pmu_ops amd_pmu_ops __initdata = { .hw_event_available = amd_hw_event_available, .pmc_idx_to_pmc = amd_pmc_idx_to_pmc, @@ -259,7 +243,6 @@ struct kvm_pmu_ops amd_pmu_ops __initdata = { .set_msr = amd_pmu_set_msr, .refresh = amd_pmu_refresh, .init = amd_pmu_init, - .reset = amd_pmu_reset, .EVENTSEL_EVENT = AMD64_EVENTSEL_EVENT, .MAX_NR_GP_COUNTERS = KVM_AMD_PMC_MAX_GENERIC, .MIN_NR_GP_COUNTERS = AMD64_NUM_COUNTERS, diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 6ee925d6664846..f760106c31f8a5 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -2191,10 +2191,13 @@ void __init sev_hardware_setup(void) /* * SEV must obviously be supported in hardware. Sanity check that the * CPU supports decode assists, which is mandatory for SEV guests to - * support instruction emulation. + * support instruction emulation. Ditto for flushing by ASID, as SEV + * guests are bound to a single ASID, i.e. KVM can't rotate to a new + * ASID to effect a TLB flush. */ if (!boot_cpu_has(X86_FEATURE_SEV) || - WARN_ON_ONCE(!boot_cpu_has(X86_FEATURE_DECODEASSISTS))) + WARN_ON_ONCE(!boot_cpu_has(X86_FEATURE_DECODEASSISTS)) || + WARN_ON_ONCE(!boot_cpu_has(X86_FEATURE_FLUSHBYASID))) goto out; /* Retrieve SEV CPUID information */ diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index a8bd4e909a1e69..e90b429c84f158 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -3563,8 +3563,15 @@ static void svm_inject_nmi(struct kvm_vcpu *vcpu) if (svm->nmi_l1_to_l2) return; - svm->nmi_masked = true; - svm_set_iret_intercept(svm); + /* + * No need to manually track NMI masking when vNMI is enabled, hardware + * automatically sets V_NMI_BLOCKING_MASK as appropriate, including the + * case where software directly injects an NMI. + */ + if (!is_vnmi_enabled(svm)) { + svm->nmi_masked = true; + svm_set_iret_intercept(svm); + } ++vcpu->stat.nmi_injections; } @@ -4744,7 +4751,7 @@ static int svm_check_emulate_instruction(struct kvm_vcpu *vcpu, int emul_type, * Emulation is possible for SEV guests if and only if a prefilled * buffer containing the bytes of the intercepted instruction is * available. SEV guest memory is encrypted with a guest specific key - * and cannot be decrypted by KVM, i.e. KVM would read cyphertext and + * and cannot be decrypted by KVM, i.e. KVM would read ciphertext and * decode garbage. * * If KVM is NOT trying to simply skip an instruction, inject #UD if @@ -5079,6 +5086,13 @@ static __init void svm_set_cpu_caps(void) kvm_cpu_cap_set(X86_FEATURE_SVM); kvm_cpu_cap_set(X86_FEATURE_VMCBCLEAN); + /* + * KVM currently flushes TLBs on *every* nested SVM transition, + * and so for all intents and purposes KVM supports flushing by + * ASID, i.e. KVM is guaranteed to honor every L1 ASID flush. + */ + kvm_cpu_cap_set(X86_FEATURE_FLUSHBYASID); + if (nrips) kvm_cpu_cap_set(X86_FEATURE_NRIPS); diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index c409f934c377fc..8ef95139cd2455 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -148,7 +148,9 @@ struct vmcb_ctrl_area_cached { u64 virt_ext; u32 clean; union { +#if IS_ENABLED(CONFIG_HYPERV) || IS_ENABLED(CONFIG_KVM_HYPERV) struct hv_vmcb_enlightenments hv_enlightenments; +#endif u8 reserved_sw[32]; }; }; diff --git a/arch/x86/kvm/svm/svm_onhyperv.c b/arch/x86/kvm/svm/svm_onhyperv.c index 7af8422d338210..3971b3ea5d04b3 100644 --- a/arch/x86/kvm/svm/svm_onhyperv.c +++ b/arch/x86/kvm/svm/svm_onhyperv.c @@ -18,18 +18,14 @@ int svm_hv_enable_l2_tlb_flush(struct kvm_vcpu *vcpu) { struct hv_vmcb_enlightenments *hve; - struct hv_partition_assist_pg **p_hv_pa_pg = - &to_kvm_hv(vcpu->kvm)->hv_pa_pg; + hpa_t partition_assist_page = hv_get_partition_assist_page(vcpu); - if (!*p_hv_pa_pg) - *p_hv_pa_pg = kzalloc(PAGE_SIZE, GFP_KERNEL); - - if (!*p_hv_pa_pg) + if (partition_assist_page == INVALID_PAGE) return -ENOMEM; hve = &to_svm(vcpu)->vmcb->control.hv_enlightenments; - hve->partition_assist_page = __pa(*p_hv_pa_pg); + hve->partition_assist_page = partition_assist_page; hve->hv_vm_id = (unsigned long)vcpu->kvm; if (!hve->hv_enlightenments_control.nested_flush_hypercall) { hve->hv_enlightenments_control.nested_flush_hypercall = 1; diff --git a/arch/x86/kvm/svm/vmenter.S b/arch/x86/kvm/svm/vmenter.S index ef2ebabb059c8c..9499f9c6b07711 100644 --- a/arch/x86/kvm/svm/vmenter.S +++ b/arch/x86/kvm/svm/vmenter.S @@ -270,16 +270,16 @@ SYM_FUNC_START(__svm_vcpu_run) RESTORE_GUEST_SPEC_CTRL_BODY RESTORE_HOST_SPEC_CTRL_BODY -10: cmpb $0, kvm_rebooting +10: cmpb $0, _ASM_RIP(kvm_rebooting) jne 2b ud2 -30: cmpb $0, kvm_rebooting +30: cmpb $0, _ASM_RIP(kvm_rebooting) jne 4b ud2 -50: cmpb $0, kvm_rebooting +50: cmpb $0, _ASM_RIP(kvm_rebooting) jne 6b ud2 -70: cmpb $0, kvm_rebooting +70: cmpb $0, _ASM_RIP(kvm_rebooting) jne 8b ud2 @@ -381,7 +381,7 @@ SYM_FUNC_START(__svm_sev_es_vcpu_run) RESTORE_GUEST_SPEC_CTRL_BODY RESTORE_HOST_SPEC_CTRL_BODY -3: cmpb $0, kvm_rebooting +3: cmpb $0, _ASM_RIP(kvm_rebooting) jne 2b ud2 diff --git a/arch/x86/kvm/vmx/hyperv.c b/arch/x86/kvm/vmx/hyperv.c index 313b8bb5b8a7cb..fab6a1ad98dc18 100644 --- a/arch/x86/kvm/vmx/hyperv.c +++ b/arch/x86/kvm/vmx/hyperv.c @@ -13,419 +13,6 @@ #define CC KVM_NESTED_VMENTER_CONSISTENCY_CHECK -/* - * Enlightened VMCSv1 doesn't support these: - * - * POSTED_INTR_NV = 0x00000002, - * GUEST_INTR_STATUS = 0x00000810, - * APIC_ACCESS_ADDR = 0x00002014, - * POSTED_INTR_DESC_ADDR = 0x00002016, - * EOI_EXIT_BITMAP0 = 0x0000201c, - * EOI_EXIT_BITMAP1 = 0x0000201e, - * EOI_EXIT_BITMAP2 = 0x00002020, - * EOI_EXIT_BITMAP3 = 0x00002022, - * GUEST_PML_INDEX = 0x00000812, - * PML_ADDRESS = 0x0000200e, - * VM_FUNCTION_CONTROL = 0x00002018, - * EPTP_LIST_ADDRESS = 0x00002024, - * VMREAD_BITMAP = 0x00002026, - * VMWRITE_BITMAP = 0x00002028, - * - * TSC_MULTIPLIER = 0x00002032, - * PLE_GAP = 0x00004020, - * PLE_WINDOW = 0x00004022, - * VMX_PREEMPTION_TIMER_VALUE = 0x0000482E, - * - * Currently unsupported in KVM: - * GUEST_IA32_RTIT_CTL = 0x00002814, - */ -#define EVMCS1_SUPPORTED_PINCTRL \ - (PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \ - PIN_BASED_EXT_INTR_MASK | \ - PIN_BASED_NMI_EXITING | \ - PIN_BASED_VIRTUAL_NMIS) - -#define EVMCS1_SUPPORTED_EXEC_CTRL \ - (CPU_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \ - CPU_BASED_HLT_EXITING | \ - CPU_BASED_CR3_LOAD_EXITING | \ - CPU_BASED_CR3_STORE_EXITING | \ - CPU_BASED_UNCOND_IO_EXITING | \ - CPU_BASED_MOV_DR_EXITING | \ - CPU_BASED_USE_TSC_OFFSETTING | \ - CPU_BASED_MWAIT_EXITING | \ - CPU_BASED_MONITOR_EXITING | \ - CPU_BASED_INVLPG_EXITING | \ - CPU_BASED_RDPMC_EXITING | \ - CPU_BASED_INTR_WINDOW_EXITING | \ - CPU_BASED_CR8_LOAD_EXITING | \ - CPU_BASED_CR8_STORE_EXITING | \ - CPU_BASED_RDTSC_EXITING | \ - CPU_BASED_TPR_SHADOW | \ - CPU_BASED_USE_IO_BITMAPS | \ - CPU_BASED_MONITOR_TRAP_FLAG | \ - CPU_BASED_USE_MSR_BITMAPS | \ - CPU_BASED_NMI_WINDOW_EXITING | \ - CPU_BASED_PAUSE_EXITING | \ - CPU_BASED_ACTIVATE_SECONDARY_CONTROLS) - -#define EVMCS1_SUPPORTED_2NDEXEC \ - (SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | \ - SECONDARY_EXEC_WBINVD_EXITING | \ - SECONDARY_EXEC_ENABLE_VPID | \ - SECONDARY_EXEC_ENABLE_EPT | \ - SECONDARY_EXEC_UNRESTRICTED_GUEST | \ - SECONDARY_EXEC_DESC | \ - SECONDARY_EXEC_ENABLE_RDTSCP | \ - SECONDARY_EXEC_ENABLE_INVPCID | \ - SECONDARY_EXEC_ENABLE_XSAVES | \ - SECONDARY_EXEC_RDSEED_EXITING | \ - SECONDARY_EXEC_RDRAND_EXITING | \ - SECONDARY_EXEC_TSC_SCALING | \ - SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE | \ - SECONDARY_EXEC_PT_USE_GPA | \ - SECONDARY_EXEC_PT_CONCEAL_VMX | \ - SECONDARY_EXEC_BUS_LOCK_DETECTION | \ - SECONDARY_EXEC_NOTIFY_VM_EXITING | \ - SECONDARY_EXEC_ENCLS_EXITING) - -#define EVMCS1_SUPPORTED_3RDEXEC (0ULL) - -#define EVMCS1_SUPPORTED_VMEXIT_CTRL \ - (VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR | \ - VM_EXIT_SAVE_DEBUG_CONTROLS | \ - VM_EXIT_ACK_INTR_ON_EXIT | \ - VM_EXIT_HOST_ADDR_SPACE_SIZE | \ - VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | \ - VM_EXIT_SAVE_IA32_PAT | \ - VM_EXIT_LOAD_IA32_PAT | \ - VM_EXIT_SAVE_IA32_EFER | \ - VM_EXIT_LOAD_IA32_EFER | \ - VM_EXIT_CLEAR_BNDCFGS | \ - VM_EXIT_PT_CONCEAL_PIP | \ - VM_EXIT_CLEAR_IA32_RTIT_CTL) - -#define EVMCS1_SUPPORTED_VMENTRY_CTRL \ - (VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR | \ - VM_ENTRY_LOAD_DEBUG_CONTROLS | \ - VM_ENTRY_IA32E_MODE | \ - VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | \ - VM_ENTRY_LOAD_IA32_PAT | \ - VM_ENTRY_LOAD_IA32_EFER | \ - VM_ENTRY_LOAD_BNDCFGS | \ - VM_ENTRY_PT_CONCEAL_PIP | \ - VM_ENTRY_LOAD_IA32_RTIT_CTL) - -#define EVMCS1_SUPPORTED_VMFUNC (0) - -#define EVMCS1_OFFSET(x) offsetof(struct hv_enlightened_vmcs, x) -#define EVMCS1_FIELD(number, name, clean_field)[ROL16(number, 6)] = \ - {EVMCS1_OFFSET(name), clean_field} - -const struct evmcs_field vmcs_field_to_evmcs_1[] = { - /* 64 bit rw */ - EVMCS1_FIELD(GUEST_RIP, guest_rip, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE), - EVMCS1_FIELD(GUEST_RSP, guest_rsp, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC), - EVMCS1_FIELD(GUEST_RFLAGS, guest_rflags, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC), - EVMCS1_FIELD(HOST_IA32_PAT, host_ia32_pat, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), - EVMCS1_FIELD(HOST_IA32_EFER, host_ia32_efer, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), - EVMCS1_FIELD(HOST_IA32_PERF_GLOBAL_CTRL, host_ia32_perf_global_ctrl, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), - EVMCS1_FIELD(HOST_CR0, host_cr0, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), - EVMCS1_FIELD(HOST_CR3, host_cr3, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), - EVMCS1_FIELD(HOST_CR4, host_cr4, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), - EVMCS1_FIELD(HOST_IA32_SYSENTER_ESP, host_ia32_sysenter_esp, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), - EVMCS1_FIELD(HOST_IA32_SYSENTER_EIP, host_ia32_sysenter_eip, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), - EVMCS1_FIELD(HOST_RIP, host_rip, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), - EVMCS1_FIELD(IO_BITMAP_A, io_bitmap_a, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_IO_BITMAP), - EVMCS1_FIELD(IO_BITMAP_B, io_bitmap_b, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_IO_BITMAP), - EVMCS1_FIELD(MSR_BITMAP, msr_bitmap, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_MSR_BITMAP), - EVMCS1_FIELD(GUEST_ES_BASE, guest_es_base, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_CS_BASE, guest_cs_base, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_SS_BASE, guest_ss_base, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_DS_BASE, guest_ds_base, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_FS_BASE, guest_fs_base, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_GS_BASE, guest_gs_base, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_LDTR_BASE, guest_ldtr_base, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_TR_BASE, guest_tr_base, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_GDTR_BASE, guest_gdtr_base, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_IDTR_BASE, guest_idtr_base, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(TSC_OFFSET, tsc_offset, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2), - EVMCS1_FIELD(VIRTUAL_APIC_PAGE_ADDR, virtual_apic_page_addr, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2), - EVMCS1_FIELD(VMCS_LINK_POINTER, vmcs_link_pointer, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), - EVMCS1_FIELD(GUEST_IA32_DEBUGCTL, guest_ia32_debugctl, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), - EVMCS1_FIELD(GUEST_IA32_PAT, guest_ia32_pat, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), - EVMCS1_FIELD(GUEST_IA32_EFER, guest_ia32_efer, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), - EVMCS1_FIELD(GUEST_IA32_PERF_GLOBAL_CTRL, guest_ia32_perf_global_ctrl, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), - EVMCS1_FIELD(GUEST_PDPTR0, guest_pdptr0, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), - EVMCS1_FIELD(GUEST_PDPTR1, guest_pdptr1, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), - EVMCS1_FIELD(GUEST_PDPTR2, guest_pdptr2, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), - EVMCS1_FIELD(GUEST_PDPTR3, guest_pdptr3, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), - EVMCS1_FIELD(GUEST_PENDING_DBG_EXCEPTIONS, guest_pending_dbg_exceptions, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), - EVMCS1_FIELD(GUEST_SYSENTER_ESP, guest_sysenter_esp, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), - EVMCS1_FIELD(GUEST_SYSENTER_EIP, guest_sysenter_eip, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), - EVMCS1_FIELD(CR0_GUEST_HOST_MASK, cr0_guest_host_mask, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR), - EVMCS1_FIELD(CR4_GUEST_HOST_MASK, cr4_guest_host_mask, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR), - EVMCS1_FIELD(CR0_READ_SHADOW, cr0_read_shadow, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR), - EVMCS1_FIELD(CR4_READ_SHADOW, cr4_read_shadow, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR), - EVMCS1_FIELD(GUEST_CR0, guest_cr0, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR), - EVMCS1_FIELD(GUEST_CR3, guest_cr3, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR), - EVMCS1_FIELD(GUEST_CR4, guest_cr4, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR), - EVMCS1_FIELD(GUEST_DR7, guest_dr7, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR), - EVMCS1_FIELD(HOST_FS_BASE, host_fs_base, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER), - EVMCS1_FIELD(HOST_GS_BASE, host_gs_base, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER), - EVMCS1_FIELD(HOST_TR_BASE, host_tr_base, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER), - EVMCS1_FIELD(HOST_GDTR_BASE, host_gdtr_base, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER), - EVMCS1_FIELD(HOST_IDTR_BASE, host_idtr_base, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER), - EVMCS1_FIELD(HOST_RSP, host_rsp, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER), - EVMCS1_FIELD(EPT_POINTER, ept_pointer, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_XLAT), - EVMCS1_FIELD(GUEST_BNDCFGS, guest_bndcfgs, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), - EVMCS1_FIELD(XSS_EXIT_BITMAP, xss_exit_bitmap, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2), - EVMCS1_FIELD(ENCLS_EXITING_BITMAP, encls_exiting_bitmap, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2), - EVMCS1_FIELD(TSC_MULTIPLIER, tsc_multiplier, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2), - /* - * Not used by KVM: - * - * EVMCS1_FIELD(0x00006828, guest_ia32_s_cet, - * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), - * EVMCS1_FIELD(0x0000682A, guest_ssp, - * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC), - * EVMCS1_FIELD(0x0000682C, guest_ia32_int_ssp_table_addr, - * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), - * EVMCS1_FIELD(0x00002816, guest_ia32_lbr_ctl, - * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), - * EVMCS1_FIELD(0x00006C18, host_ia32_s_cet, - * HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), - * EVMCS1_FIELD(0x00006C1A, host_ssp, - * HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), - * EVMCS1_FIELD(0x00006C1C, host_ia32_int_ssp_table_addr, - * HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), - */ - - /* 64 bit read only */ - EVMCS1_FIELD(GUEST_PHYSICAL_ADDRESS, guest_physical_address, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE), - EVMCS1_FIELD(EXIT_QUALIFICATION, exit_qualification, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE), - /* - * Not defined in KVM: - * - * EVMCS1_FIELD(0x00006402, exit_io_instruction_ecx, - * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE); - * EVMCS1_FIELD(0x00006404, exit_io_instruction_esi, - * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE); - * EVMCS1_FIELD(0x00006406, exit_io_instruction_esi, - * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE); - * EVMCS1_FIELD(0x00006408, exit_io_instruction_eip, - * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE); - */ - EVMCS1_FIELD(GUEST_LINEAR_ADDRESS, guest_linear_address, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE), - - /* - * No mask defined in the spec as Hyper-V doesn't currently support - * these. Future proof by resetting the whole clean field mask on - * access. - */ - EVMCS1_FIELD(VM_EXIT_MSR_STORE_ADDR, vm_exit_msr_store_addr, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL), - EVMCS1_FIELD(VM_EXIT_MSR_LOAD_ADDR, vm_exit_msr_load_addr, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL), - EVMCS1_FIELD(VM_ENTRY_MSR_LOAD_ADDR, vm_entry_msr_load_addr, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL), - - /* 32 bit rw */ - EVMCS1_FIELD(TPR_THRESHOLD, tpr_threshold, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE), - EVMCS1_FIELD(GUEST_INTERRUPTIBILITY_INFO, guest_interruptibility_info, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC), - EVMCS1_FIELD(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_PROC), - EVMCS1_FIELD(EXCEPTION_BITMAP, exception_bitmap, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EXCPN), - EVMCS1_FIELD(VM_ENTRY_CONTROLS, vm_entry_controls, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_ENTRY), - EVMCS1_FIELD(VM_ENTRY_INTR_INFO_FIELD, vm_entry_intr_info_field, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT), - EVMCS1_FIELD(VM_ENTRY_EXCEPTION_ERROR_CODE, - vm_entry_exception_error_code, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT), - EVMCS1_FIELD(VM_ENTRY_INSTRUCTION_LEN, vm_entry_instruction_len, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT), - EVMCS1_FIELD(HOST_IA32_SYSENTER_CS, host_ia32_sysenter_cs, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), - EVMCS1_FIELD(PIN_BASED_VM_EXEC_CONTROL, pin_based_vm_exec_control, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1), - EVMCS1_FIELD(VM_EXIT_CONTROLS, vm_exit_controls, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1), - EVMCS1_FIELD(SECONDARY_VM_EXEC_CONTROL, secondary_vm_exec_control, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1), - EVMCS1_FIELD(GUEST_ES_LIMIT, guest_es_limit, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_CS_LIMIT, guest_cs_limit, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_SS_LIMIT, guest_ss_limit, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_DS_LIMIT, guest_ds_limit, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_FS_LIMIT, guest_fs_limit, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_GS_LIMIT, guest_gs_limit, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_LDTR_LIMIT, guest_ldtr_limit, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_TR_LIMIT, guest_tr_limit, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_GDTR_LIMIT, guest_gdtr_limit, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_IDTR_LIMIT, guest_idtr_limit, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_ES_AR_BYTES, guest_es_ar_bytes, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_CS_AR_BYTES, guest_cs_ar_bytes, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_SS_AR_BYTES, guest_ss_ar_bytes, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_DS_AR_BYTES, guest_ds_ar_bytes, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_FS_AR_BYTES, guest_fs_ar_bytes, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_GS_AR_BYTES, guest_gs_ar_bytes, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_LDTR_AR_BYTES, guest_ldtr_ar_bytes, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_TR_AR_BYTES, guest_tr_ar_bytes, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_ACTIVITY_STATE, guest_activity_state, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), - EVMCS1_FIELD(GUEST_SYSENTER_CS, guest_sysenter_cs, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), - - /* 32 bit read only */ - EVMCS1_FIELD(VM_INSTRUCTION_ERROR, vm_instruction_error, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE), - EVMCS1_FIELD(VM_EXIT_REASON, vm_exit_reason, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE), - EVMCS1_FIELD(VM_EXIT_INTR_INFO, vm_exit_intr_info, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE), - EVMCS1_FIELD(VM_EXIT_INTR_ERROR_CODE, vm_exit_intr_error_code, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE), - EVMCS1_FIELD(IDT_VECTORING_INFO_FIELD, idt_vectoring_info_field, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE), - EVMCS1_FIELD(IDT_VECTORING_ERROR_CODE, idt_vectoring_error_code, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE), - EVMCS1_FIELD(VM_EXIT_INSTRUCTION_LEN, vm_exit_instruction_len, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE), - EVMCS1_FIELD(VMX_INSTRUCTION_INFO, vmx_instruction_info, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE), - - /* No mask defined in the spec (not used) */ - EVMCS1_FIELD(PAGE_FAULT_ERROR_CODE_MASK, page_fault_error_code_mask, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL), - EVMCS1_FIELD(PAGE_FAULT_ERROR_CODE_MATCH, page_fault_error_code_match, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL), - EVMCS1_FIELD(CR3_TARGET_COUNT, cr3_target_count, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL), - EVMCS1_FIELD(VM_EXIT_MSR_STORE_COUNT, vm_exit_msr_store_count, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL), - EVMCS1_FIELD(VM_EXIT_MSR_LOAD_COUNT, vm_exit_msr_load_count, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL), - EVMCS1_FIELD(VM_ENTRY_MSR_LOAD_COUNT, vm_entry_msr_load_count, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL), - - /* 16 bit rw */ - EVMCS1_FIELD(HOST_ES_SELECTOR, host_es_selector, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), - EVMCS1_FIELD(HOST_CS_SELECTOR, host_cs_selector, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), - EVMCS1_FIELD(HOST_SS_SELECTOR, host_ss_selector, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), - EVMCS1_FIELD(HOST_DS_SELECTOR, host_ds_selector, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), - EVMCS1_FIELD(HOST_FS_SELECTOR, host_fs_selector, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), - EVMCS1_FIELD(HOST_GS_SELECTOR, host_gs_selector, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), - EVMCS1_FIELD(HOST_TR_SELECTOR, host_tr_selector, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), - EVMCS1_FIELD(GUEST_ES_SELECTOR, guest_es_selector, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_CS_SELECTOR, guest_cs_selector, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_SS_SELECTOR, guest_ss_selector, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_DS_SELECTOR, guest_ds_selector, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_FS_SELECTOR, guest_fs_selector, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_GS_SELECTOR, guest_gs_selector, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_LDTR_SELECTOR, guest_ldtr_selector, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(GUEST_TR_SELECTOR, guest_tr_selector, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), - EVMCS1_FIELD(VIRTUAL_PROCESSOR_ID, virtual_processor_id, - HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_XLAT), -}; -const unsigned int nr_evmcs_1_fields = ARRAY_SIZE(vmcs_field_to_evmcs_1); - u64 nested_get_evmptr(struct kvm_vcpu *vcpu) { struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu); @@ -608,40 +195,6 @@ int nested_evmcs_check_controls(struct vmcs12 *vmcs12) return 0; } -#if IS_ENABLED(CONFIG_HYPERV) -DEFINE_STATIC_KEY_FALSE(__kvm_is_using_evmcs); - -/* - * KVM on Hyper-V always uses the latest known eVMCSv1 revision, the assumption - * is: in case a feature has corresponding fields in eVMCS described and it was - * exposed in VMX feature MSRs, KVM is free to use it. Warn if KVM meets a - * feature which has no corresponding eVMCS field, this likely means that KVM - * needs to be updated. - */ -#define evmcs_check_vmcs_conf(field, ctrl) \ - do { \ - typeof(vmcs_conf->field) unsupported; \ - \ - unsupported = vmcs_conf->field & ~EVMCS1_SUPPORTED_ ## ctrl; \ - if (unsupported) { \ - pr_warn_once(#field " unsupported with eVMCS: 0x%llx\n",\ - (u64)unsupported); \ - vmcs_conf->field &= EVMCS1_SUPPORTED_ ## ctrl; \ - } \ - } \ - while (0) - -void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf) -{ - evmcs_check_vmcs_conf(cpu_based_exec_ctrl, EXEC_CTRL); - evmcs_check_vmcs_conf(pin_based_exec_ctrl, PINCTRL); - evmcs_check_vmcs_conf(cpu_based_2nd_exec_ctrl, 2NDEXEC); - evmcs_check_vmcs_conf(cpu_based_3rd_exec_ctrl, 3RDEXEC); - evmcs_check_vmcs_conf(vmentry_ctrl, VMENTRY_CTRL); - evmcs_check_vmcs_conf(vmexit_ctrl, VMEXIT_CTRL); -} -#endif - int nested_enable_evmcs(struct kvm_vcpu *vcpu, uint16_t *vmcs_version) { diff --git a/arch/x86/kvm/vmx/hyperv.h b/arch/x86/kvm/vmx/hyperv.h index 9623fe1651c48b..a87407412615c2 100644 --- a/arch/x86/kvm/vmx/hyperv.h +++ b/arch/x86/kvm/vmx/hyperv.h @@ -2,199 +2,89 @@ #ifndef __KVM_X86_VMX_HYPERV_H #define __KVM_X86_VMX_HYPERV_H -#include - -#include -#include -#include - -#include "../hyperv.h" - -#include "capabilities.h" -#include "vmcs.h" +#include #include "vmcs12.h" +#include "vmx.h" -struct vmcs_config; - -#define current_evmcs ((struct hv_enlightened_vmcs *)this_cpu_read(current_vmcs)) - -#define KVM_EVMCS_VERSION 1 +#define EVMPTR_INVALID (-1ULL) +#define EVMPTR_MAP_PENDING (-2ULL) -struct evmcs_field { - u16 offset; - u16 clean_field; +enum nested_evmptrld_status { + EVMPTRLD_DISABLED, + EVMPTRLD_SUCCEEDED, + EVMPTRLD_VMFAIL, + EVMPTRLD_ERROR, }; -extern const struct evmcs_field vmcs_field_to_evmcs_1[]; -extern const unsigned int nr_evmcs_1_fields; - -static __always_inline int evmcs_field_offset(unsigned long field, - u16 *clean_field) -{ - unsigned int index = ROL16(field, 6); - const struct evmcs_field *evmcs_field; - - if (unlikely(index >= nr_evmcs_1_fields)) - return -ENOENT; - - evmcs_field = &vmcs_field_to_evmcs_1[index]; - - /* - * Use offset=0 to detect holes in eVMCS. This offset belongs to - * 'revision_id' but this field has no encoding and is supposed to - * be accessed directly. - */ - if (unlikely(!evmcs_field->offset)) - return -ENOENT; - - if (clean_field) - *clean_field = evmcs_field->clean_field; - - return evmcs_field->offset; -} - -static inline u64 evmcs_read_any(struct hv_enlightened_vmcs *evmcs, - unsigned long field, u16 offset) +#ifdef CONFIG_KVM_HYPERV +static inline bool evmptr_is_valid(u64 evmptr) { - /* - * vmcs12_read_any() doesn't care whether the supplied structure - * is 'struct vmcs12' or 'struct hv_enlightened_vmcs' as it takes - * the exact offset of the required field, use it for convenience - * here. - */ - return vmcs12_read_any((void *)evmcs, field, offset); + return evmptr != EVMPTR_INVALID && evmptr != EVMPTR_MAP_PENDING; } -#if IS_ENABLED(CONFIG_HYPERV) - -DECLARE_STATIC_KEY_FALSE(__kvm_is_using_evmcs); - -static __always_inline bool kvm_is_using_evmcs(void) +static inline bool nested_vmx_is_evmptr12_valid(struct vcpu_vmx *vmx) { - return static_branch_unlikely(&__kvm_is_using_evmcs); + return evmptr_is_valid(vmx->nested.hv_evmcs_vmptr); } -static __always_inline int get_evmcs_offset(unsigned long field, - u16 *clean_field) +static inline bool evmptr_is_set(u64 evmptr) { - int offset = evmcs_field_offset(field, clean_field); - - WARN_ONCE(offset < 0, "accessing unsupported EVMCS field %lx\n", field); - return offset; + return evmptr != EVMPTR_INVALID; } -static __always_inline void evmcs_write64(unsigned long field, u64 value) +static inline bool nested_vmx_is_evmptr12_set(struct vcpu_vmx *vmx) { - u16 clean_field; - int offset = get_evmcs_offset(field, &clean_field); - - if (offset < 0) - return; - - *(u64 *)((char *)current_evmcs + offset) = value; - - current_evmcs->hv_clean_fields &= ~clean_field; + return evmptr_is_set(vmx->nested.hv_evmcs_vmptr); } -static __always_inline void evmcs_write32(unsigned long field, u32 value) +static inline struct hv_enlightened_vmcs *nested_vmx_evmcs(struct vcpu_vmx *vmx) { - u16 clean_field; - int offset = get_evmcs_offset(field, &clean_field); - - if (offset < 0) - return; - - *(u32 *)((char *)current_evmcs + offset) = value; - current_evmcs->hv_clean_fields &= ~clean_field; + return vmx->nested.hv_evmcs; } -static __always_inline void evmcs_write16(unsigned long field, u16 value) +static inline bool guest_cpuid_has_evmcs(struct kvm_vcpu *vcpu) { - u16 clean_field; - int offset = get_evmcs_offset(field, &clean_field); - - if (offset < 0) - return; - - *(u16 *)((char *)current_evmcs + offset) = value; - current_evmcs->hv_clean_fields &= ~clean_field; + /* + * eVMCS is exposed to the guest if Hyper-V is enabled in CPUID and + * eVMCS has been explicitly enabled by userspace. + */ + return vcpu->arch.hyperv_enabled && + to_vmx(vcpu)->nested.enlightened_vmcs_enabled; } -static __always_inline u64 evmcs_read64(unsigned long field) +u64 nested_get_evmptr(struct kvm_vcpu *vcpu); +uint16_t nested_get_evmcs_version(struct kvm_vcpu *vcpu); +int nested_enable_evmcs(struct kvm_vcpu *vcpu, + uint16_t *vmcs_version); +void nested_evmcs_filter_control_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata); +int nested_evmcs_check_controls(struct vmcs12 *vmcs12); +bool nested_evmcs_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu); +void vmx_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu); +#else +static inline bool evmptr_is_valid(u64 evmptr) { - int offset = get_evmcs_offset(field, NULL); - - if (offset < 0) - return 0; - - return *(u64 *)((char *)current_evmcs + offset); + return false; } -static __always_inline u32 evmcs_read32(unsigned long field) +static inline bool nested_vmx_is_evmptr12_valid(struct vcpu_vmx *vmx) { - int offset = get_evmcs_offset(field, NULL); - - if (offset < 0) - return 0; - - return *(u32 *)((char *)current_evmcs + offset); + return false; } -static __always_inline u16 evmcs_read16(unsigned long field) +static inline bool evmptr_is_set(u64 evmptr) { - int offset = get_evmcs_offset(field, NULL); - - if (offset < 0) - return 0; - - return *(u16 *)((char *)current_evmcs + offset); + return false; } -static inline void evmcs_load(u64 phys_addr) +static inline bool nested_vmx_is_evmptr12_set(struct vcpu_vmx *vmx) { - struct hv_vp_assist_page *vp_ap = - hv_get_vp_assist_page(smp_processor_id()); - - if (current_evmcs->hv_enlightenments_control.nested_flush_hypercall) - vp_ap->nested_control.features.directhypercall = 1; - vp_ap->current_nested_vmcs = phys_addr; - vp_ap->enlighten_vmentry = 1; + return false; } -void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf); -#else /* !IS_ENABLED(CONFIG_HYPERV) */ -static __always_inline bool kvm_is_using_evmcs(void) { return false; } -static __always_inline void evmcs_write64(unsigned long field, u64 value) {} -static __always_inline void evmcs_write32(unsigned long field, u32 value) {} -static __always_inline void evmcs_write16(unsigned long field, u16 value) {} -static __always_inline u64 evmcs_read64(unsigned long field) { return 0; } -static __always_inline u32 evmcs_read32(unsigned long field) { return 0; } -static __always_inline u16 evmcs_read16(unsigned long field) { return 0; } -static inline void evmcs_load(u64 phys_addr) {} -#endif /* IS_ENABLED(CONFIG_HYPERV) */ - -#define EVMPTR_INVALID (-1ULL) -#define EVMPTR_MAP_PENDING (-2ULL) - -static inline bool evmptr_is_valid(u64 evmptr) +static inline struct hv_enlightened_vmcs *nested_vmx_evmcs(struct vcpu_vmx *vmx) { - return evmptr != EVMPTR_INVALID && evmptr != EVMPTR_MAP_PENDING; + return NULL; } - -enum nested_evmptrld_status { - EVMPTRLD_DISABLED, - EVMPTRLD_SUCCEEDED, - EVMPTRLD_VMFAIL, - EVMPTRLD_ERROR, -}; - -u64 nested_get_evmptr(struct kvm_vcpu *vcpu); -uint16_t nested_get_evmcs_version(struct kvm_vcpu *vcpu); -int nested_enable_evmcs(struct kvm_vcpu *vcpu, - uint16_t *vmcs_version); -void nested_evmcs_filter_control_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata); -int nested_evmcs_check_controls(struct vmcs12 *vmcs12); -bool nested_evmcs_l2_tlb_flush_enabled(struct kvm_vcpu *vcpu); -void vmx_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu); +#endif #endif /* __KVM_X86_VMX_HYPERV_H */ diff --git a/arch/x86/kvm/vmx/hyperv_evmcs.c b/arch/x86/kvm/vmx/hyperv_evmcs.c new file mode 100644 index 00000000000000..904bfcd1519b0b --- /dev/null +++ b/arch/x86/kvm/vmx/hyperv_evmcs.c @@ -0,0 +1,315 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * This file contains common code for working with Enlightened VMCS which is + * used both by Hyper-V on KVM and KVM on Hyper-V. + */ + +#include "hyperv_evmcs.h" + +#define EVMCS1_OFFSET(x) offsetof(struct hv_enlightened_vmcs, x) +#define EVMCS1_FIELD(number, name, clean_field)[ROL16(number, 6)] = \ + {EVMCS1_OFFSET(name), clean_field} + +const struct evmcs_field vmcs_field_to_evmcs_1[] = { + /* 64 bit rw */ + EVMCS1_FIELD(GUEST_RIP, guest_rip, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE), + EVMCS1_FIELD(GUEST_RSP, guest_rsp, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC), + EVMCS1_FIELD(GUEST_RFLAGS, guest_rflags, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC), + EVMCS1_FIELD(HOST_IA32_PAT, host_ia32_pat, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), + EVMCS1_FIELD(HOST_IA32_EFER, host_ia32_efer, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), + EVMCS1_FIELD(HOST_IA32_PERF_GLOBAL_CTRL, host_ia32_perf_global_ctrl, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), + EVMCS1_FIELD(HOST_CR0, host_cr0, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), + EVMCS1_FIELD(HOST_CR3, host_cr3, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), + EVMCS1_FIELD(HOST_CR4, host_cr4, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), + EVMCS1_FIELD(HOST_IA32_SYSENTER_ESP, host_ia32_sysenter_esp, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), + EVMCS1_FIELD(HOST_IA32_SYSENTER_EIP, host_ia32_sysenter_eip, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), + EVMCS1_FIELD(HOST_RIP, host_rip, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), + EVMCS1_FIELD(IO_BITMAP_A, io_bitmap_a, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_IO_BITMAP), + EVMCS1_FIELD(IO_BITMAP_B, io_bitmap_b, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_IO_BITMAP), + EVMCS1_FIELD(MSR_BITMAP, msr_bitmap, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_MSR_BITMAP), + EVMCS1_FIELD(GUEST_ES_BASE, guest_es_base, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_CS_BASE, guest_cs_base, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_SS_BASE, guest_ss_base, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_DS_BASE, guest_ds_base, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_FS_BASE, guest_fs_base, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_GS_BASE, guest_gs_base, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_LDTR_BASE, guest_ldtr_base, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_TR_BASE, guest_tr_base, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_GDTR_BASE, guest_gdtr_base, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_IDTR_BASE, guest_idtr_base, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(TSC_OFFSET, tsc_offset, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2), + EVMCS1_FIELD(VIRTUAL_APIC_PAGE_ADDR, virtual_apic_page_addr, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2), + EVMCS1_FIELD(VMCS_LINK_POINTER, vmcs_link_pointer, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), + EVMCS1_FIELD(GUEST_IA32_DEBUGCTL, guest_ia32_debugctl, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), + EVMCS1_FIELD(GUEST_IA32_PAT, guest_ia32_pat, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), + EVMCS1_FIELD(GUEST_IA32_EFER, guest_ia32_efer, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), + EVMCS1_FIELD(GUEST_IA32_PERF_GLOBAL_CTRL, guest_ia32_perf_global_ctrl, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), + EVMCS1_FIELD(GUEST_PDPTR0, guest_pdptr0, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), + EVMCS1_FIELD(GUEST_PDPTR1, guest_pdptr1, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), + EVMCS1_FIELD(GUEST_PDPTR2, guest_pdptr2, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), + EVMCS1_FIELD(GUEST_PDPTR3, guest_pdptr3, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), + EVMCS1_FIELD(GUEST_PENDING_DBG_EXCEPTIONS, guest_pending_dbg_exceptions, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), + EVMCS1_FIELD(GUEST_SYSENTER_ESP, guest_sysenter_esp, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), + EVMCS1_FIELD(GUEST_SYSENTER_EIP, guest_sysenter_eip, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), + EVMCS1_FIELD(CR0_GUEST_HOST_MASK, cr0_guest_host_mask, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR), + EVMCS1_FIELD(CR4_GUEST_HOST_MASK, cr4_guest_host_mask, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR), + EVMCS1_FIELD(CR0_READ_SHADOW, cr0_read_shadow, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR), + EVMCS1_FIELD(CR4_READ_SHADOW, cr4_read_shadow, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR), + EVMCS1_FIELD(GUEST_CR0, guest_cr0, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR), + EVMCS1_FIELD(GUEST_CR3, guest_cr3, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR), + EVMCS1_FIELD(GUEST_CR4, guest_cr4, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR), + EVMCS1_FIELD(GUEST_DR7, guest_dr7, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CRDR), + EVMCS1_FIELD(HOST_FS_BASE, host_fs_base, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER), + EVMCS1_FIELD(HOST_GS_BASE, host_gs_base, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER), + EVMCS1_FIELD(HOST_TR_BASE, host_tr_base, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER), + EVMCS1_FIELD(HOST_GDTR_BASE, host_gdtr_base, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER), + EVMCS1_FIELD(HOST_IDTR_BASE, host_idtr_base, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER), + EVMCS1_FIELD(HOST_RSP, host_rsp, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER), + EVMCS1_FIELD(EPT_POINTER, ept_pointer, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_XLAT), + EVMCS1_FIELD(GUEST_BNDCFGS, guest_bndcfgs, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), + EVMCS1_FIELD(XSS_EXIT_BITMAP, xss_exit_bitmap, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2), + EVMCS1_FIELD(ENCLS_EXITING_BITMAP, encls_exiting_bitmap, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2), + EVMCS1_FIELD(TSC_MULTIPLIER, tsc_multiplier, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2), + /* + * Not used by KVM: + * + * EVMCS1_FIELD(0x00006828, guest_ia32_s_cet, + * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), + * EVMCS1_FIELD(0x0000682A, guest_ssp, + * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC), + * EVMCS1_FIELD(0x0000682C, guest_ia32_int_ssp_table_addr, + * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), + * EVMCS1_FIELD(0x00002816, guest_ia32_lbr_ctl, + * HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), + * EVMCS1_FIELD(0x00006C18, host_ia32_s_cet, + * HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), + * EVMCS1_FIELD(0x00006C1A, host_ssp, + * HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), + * EVMCS1_FIELD(0x00006C1C, host_ia32_int_ssp_table_addr, + * HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), + */ + + /* 64 bit read only */ + EVMCS1_FIELD(GUEST_PHYSICAL_ADDRESS, guest_physical_address, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE), + EVMCS1_FIELD(EXIT_QUALIFICATION, exit_qualification, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE), + /* + * Not defined in KVM: + * + * EVMCS1_FIELD(0x00006402, exit_io_instruction_ecx, + * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE); + * EVMCS1_FIELD(0x00006404, exit_io_instruction_esi, + * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE); + * EVMCS1_FIELD(0x00006406, exit_io_instruction_esi, + * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE); + * EVMCS1_FIELD(0x00006408, exit_io_instruction_eip, + * HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE); + */ + EVMCS1_FIELD(GUEST_LINEAR_ADDRESS, guest_linear_address, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE), + + /* + * No mask defined in the spec as Hyper-V doesn't currently support + * these. Future proof by resetting the whole clean field mask on + * access. + */ + EVMCS1_FIELD(VM_EXIT_MSR_STORE_ADDR, vm_exit_msr_store_addr, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL), + EVMCS1_FIELD(VM_EXIT_MSR_LOAD_ADDR, vm_exit_msr_load_addr, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL), + EVMCS1_FIELD(VM_ENTRY_MSR_LOAD_ADDR, vm_entry_msr_load_addr, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL), + + /* 32 bit rw */ + EVMCS1_FIELD(TPR_THRESHOLD, tpr_threshold, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE), + EVMCS1_FIELD(GUEST_INTERRUPTIBILITY_INFO, guest_interruptibility_info, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_BASIC), + EVMCS1_FIELD(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_PROC), + EVMCS1_FIELD(EXCEPTION_BITMAP, exception_bitmap, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EXCPN), + EVMCS1_FIELD(VM_ENTRY_CONTROLS, vm_entry_controls, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_ENTRY), + EVMCS1_FIELD(VM_ENTRY_INTR_INFO_FIELD, vm_entry_intr_info_field, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT), + EVMCS1_FIELD(VM_ENTRY_EXCEPTION_ERROR_CODE, + vm_entry_exception_error_code, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT), + EVMCS1_FIELD(VM_ENTRY_INSTRUCTION_LEN, vm_entry_instruction_len, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_EVENT), + EVMCS1_FIELD(HOST_IA32_SYSENTER_CS, host_ia32_sysenter_cs, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), + EVMCS1_FIELD(PIN_BASED_VM_EXEC_CONTROL, pin_based_vm_exec_control, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1), + EVMCS1_FIELD(VM_EXIT_CONTROLS, vm_exit_controls, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1), + EVMCS1_FIELD(SECONDARY_VM_EXEC_CONTROL, secondary_vm_exec_control, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1), + EVMCS1_FIELD(GUEST_ES_LIMIT, guest_es_limit, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_CS_LIMIT, guest_cs_limit, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_SS_LIMIT, guest_ss_limit, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_DS_LIMIT, guest_ds_limit, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_FS_LIMIT, guest_fs_limit, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_GS_LIMIT, guest_gs_limit, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_LDTR_LIMIT, guest_ldtr_limit, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_TR_LIMIT, guest_tr_limit, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_GDTR_LIMIT, guest_gdtr_limit, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_IDTR_LIMIT, guest_idtr_limit, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_ES_AR_BYTES, guest_es_ar_bytes, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_CS_AR_BYTES, guest_cs_ar_bytes, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_SS_AR_BYTES, guest_ss_ar_bytes, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_DS_AR_BYTES, guest_ds_ar_bytes, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_FS_AR_BYTES, guest_fs_ar_bytes, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_GS_AR_BYTES, guest_gs_ar_bytes, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_LDTR_AR_BYTES, guest_ldtr_ar_bytes, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_TR_AR_BYTES, guest_tr_ar_bytes, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_ACTIVITY_STATE, guest_activity_state, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), + EVMCS1_FIELD(GUEST_SYSENTER_CS, guest_sysenter_cs, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1), + + /* 32 bit read only */ + EVMCS1_FIELD(VM_INSTRUCTION_ERROR, vm_instruction_error, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE), + EVMCS1_FIELD(VM_EXIT_REASON, vm_exit_reason, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE), + EVMCS1_FIELD(VM_EXIT_INTR_INFO, vm_exit_intr_info, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE), + EVMCS1_FIELD(VM_EXIT_INTR_ERROR_CODE, vm_exit_intr_error_code, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE), + EVMCS1_FIELD(IDT_VECTORING_INFO_FIELD, idt_vectoring_info_field, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE), + EVMCS1_FIELD(IDT_VECTORING_ERROR_CODE, idt_vectoring_error_code, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE), + EVMCS1_FIELD(VM_EXIT_INSTRUCTION_LEN, vm_exit_instruction_len, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE), + EVMCS1_FIELD(VMX_INSTRUCTION_INFO, vmx_instruction_info, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE), + + /* No mask defined in the spec (not used) */ + EVMCS1_FIELD(PAGE_FAULT_ERROR_CODE_MASK, page_fault_error_code_mask, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL), + EVMCS1_FIELD(PAGE_FAULT_ERROR_CODE_MATCH, page_fault_error_code_match, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL), + EVMCS1_FIELD(CR3_TARGET_COUNT, cr3_target_count, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL), + EVMCS1_FIELD(VM_EXIT_MSR_STORE_COUNT, vm_exit_msr_store_count, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL), + EVMCS1_FIELD(VM_EXIT_MSR_LOAD_COUNT, vm_exit_msr_load_count, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL), + EVMCS1_FIELD(VM_ENTRY_MSR_LOAD_COUNT, vm_entry_msr_load_count, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL), + + /* 16 bit rw */ + EVMCS1_FIELD(HOST_ES_SELECTOR, host_es_selector, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), + EVMCS1_FIELD(HOST_CS_SELECTOR, host_cs_selector, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), + EVMCS1_FIELD(HOST_SS_SELECTOR, host_ss_selector, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), + EVMCS1_FIELD(HOST_DS_SELECTOR, host_ds_selector, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), + EVMCS1_FIELD(HOST_FS_SELECTOR, host_fs_selector, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), + EVMCS1_FIELD(HOST_GS_SELECTOR, host_gs_selector, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), + EVMCS1_FIELD(HOST_TR_SELECTOR, host_tr_selector, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1), + EVMCS1_FIELD(GUEST_ES_SELECTOR, guest_es_selector, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_CS_SELECTOR, guest_cs_selector, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_SS_SELECTOR, guest_ss_selector, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_DS_SELECTOR, guest_ds_selector, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_FS_SELECTOR, guest_fs_selector, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_GS_SELECTOR, guest_gs_selector, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_LDTR_SELECTOR, guest_ldtr_selector, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(GUEST_TR_SELECTOR, guest_tr_selector, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2), + EVMCS1_FIELD(VIRTUAL_PROCESSOR_ID, virtual_processor_id, + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_XLAT), +}; +const unsigned int nr_evmcs_1_fields = ARRAY_SIZE(vmcs_field_to_evmcs_1); diff --git a/arch/x86/kvm/vmx/hyperv_evmcs.h b/arch/x86/kvm/vmx/hyperv_evmcs.h new file mode 100644 index 00000000000000..a543fccfc5747a --- /dev/null +++ b/arch/x86/kvm/vmx/hyperv_evmcs.h @@ -0,0 +1,166 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * This file contains common definitions for working with Enlightened VMCS which + * are used both by Hyper-V on KVM and KVM on Hyper-V. + */ +#ifndef __KVM_X86_VMX_HYPERV_EVMCS_H +#define __KVM_X86_VMX_HYPERV_EVMCS_H + +#include + +#include "capabilities.h" +#include "vmcs12.h" + +#define KVM_EVMCS_VERSION 1 + +/* + * Enlightened VMCSv1 doesn't support these: + * + * POSTED_INTR_NV = 0x00000002, + * GUEST_INTR_STATUS = 0x00000810, + * APIC_ACCESS_ADDR = 0x00002014, + * POSTED_INTR_DESC_ADDR = 0x00002016, + * EOI_EXIT_BITMAP0 = 0x0000201c, + * EOI_EXIT_BITMAP1 = 0x0000201e, + * EOI_EXIT_BITMAP2 = 0x00002020, + * EOI_EXIT_BITMAP3 = 0x00002022, + * GUEST_PML_INDEX = 0x00000812, + * PML_ADDRESS = 0x0000200e, + * VM_FUNCTION_CONTROL = 0x00002018, + * EPTP_LIST_ADDRESS = 0x00002024, + * VMREAD_BITMAP = 0x00002026, + * VMWRITE_BITMAP = 0x00002028, + * + * TSC_MULTIPLIER = 0x00002032, + * PLE_GAP = 0x00004020, + * PLE_WINDOW = 0x00004022, + * VMX_PREEMPTION_TIMER_VALUE = 0x0000482E, + * + * Currently unsupported in KVM: + * GUEST_IA32_RTIT_CTL = 0x00002814, + */ +#define EVMCS1_SUPPORTED_PINCTRL \ + (PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \ + PIN_BASED_EXT_INTR_MASK | \ + PIN_BASED_NMI_EXITING | \ + PIN_BASED_VIRTUAL_NMIS) + +#define EVMCS1_SUPPORTED_EXEC_CTRL \ + (CPU_BASED_ALWAYSON_WITHOUT_TRUE_MSR | \ + CPU_BASED_HLT_EXITING | \ + CPU_BASED_CR3_LOAD_EXITING | \ + CPU_BASED_CR3_STORE_EXITING | \ + CPU_BASED_UNCOND_IO_EXITING | \ + CPU_BASED_MOV_DR_EXITING | \ + CPU_BASED_USE_TSC_OFFSETTING | \ + CPU_BASED_MWAIT_EXITING | \ + CPU_BASED_MONITOR_EXITING | \ + CPU_BASED_INVLPG_EXITING | \ + CPU_BASED_RDPMC_EXITING | \ + CPU_BASED_INTR_WINDOW_EXITING | \ + CPU_BASED_CR8_LOAD_EXITING | \ + CPU_BASED_CR8_STORE_EXITING | \ + CPU_BASED_RDTSC_EXITING | \ + CPU_BASED_TPR_SHADOW | \ + CPU_BASED_USE_IO_BITMAPS | \ + CPU_BASED_MONITOR_TRAP_FLAG | \ + CPU_BASED_USE_MSR_BITMAPS | \ + CPU_BASED_NMI_WINDOW_EXITING | \ + CPU_BASED_PAUSE_EXITING | \ + CPU_BASED_ACTIVATE_SECONDARY_CONTROLS) + +#define EVMCS1_SUPPORTED_2NDEXEC \ + (SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | \ + SECONDARY_EXEC_WBINVD_EXITING | \ + SECONDARY_EXEC_ENABLE_VPID | \ + SECONDARY_EXEC_ENABLE_EPT | \ + SECONDARY_EXEC_UNRESTRICTED_GUEST | \ + SECONDARY_EXEC_DESC | \ + SECONDARY_EXEC_ENABLE_RDTSCP | \ + SECONDARY_EXEC_ENABLE_INVPCID | \ + SECONDARY_EXEC_ENABLE_XSAVES | \ + SECONDARY_EXEC_RDSEED_EXITING | \ + SECONDARY_EXEC_RDRAND_EXITING | \ + SECONDARY_EXEC_TSC_SCALING | \ + SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE | \ + SECONDARY_EXEC_PT_USE_GPA | \ + SECONDARY_EXEC_PT_CONCEAL_VMX | \ + SECONDARY_EXEC_BUS_LOCK_DETECTION | \ + SECONDARY_EXEC_NOTIFY_VM_EXITING | \ + SECONDARY_EXEC_ENCLS_EXITING) + +#define EVMCS1_SUPPORTED_3RDEXEC (0ULL) + +#define EVMCS1_SUPPORTED_VMEXIT_CTRL \ + (VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR | \ + VM_EXIT_SAVE_DEBUG_CONTROLS | \ + VM_EXIT_ACK_INTR_ON_EXIT | \ + VM_EXIT_HOST_ADDR_SPACE_SIZE | \ + VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | \ + VM_EXIT_SAVE_IA32_PAT | \ + VM_EXIT_LOAD_IA32_PAT | \ + VM_EXIT_SAVE_IA32_EFER | \ + VM_EXIT_LOAD_IA32_EFER | \ + VM_EXIT_CLEAR_BNDCFGS | \ + VM_EXIT_PT_CONCEAL_PIP | \ + VM_EXIT_CLEAR_IA32_RTIT_CTL) + +#define EVMCS1_SUPPORTED_VMENTRY_CTRL \ + (VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR | \ + VM_ENTRY_LOAD_DEBUG_CONTROLS | \ + VM_ENTRY_IA32E_MODE | \ + VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | \ + VM_ENTRY_LOAD_IA32_PAT | \ + VM_ENTRY_LOAD_IA32_EFER | \ + VM_ENTRY_LOAD_BNDCFGS | \ + VM_ENTRY_PT_CONCEAL_PIP | \ + VM_ENTRY_LOAD_IA32_RTIT_CTL) + +#define EVMCS1_SUPPORTED_VMFUNC (0) + +struct evmcs_field { + u16 offset; + u16 clean_field; +}; + +extern const struct evmcs_field vmcs_field_to_evmcs_1[]; +extern const unsigned int nr_evmcs_1_fields; + +static __always_inline int evmcs_field_offset(unsigned long field, + u16 *clean_field) +{ + const struct evmcs_field *evmcs_field; + unsigned int index = ROL16(field, 6); + + if (unlikely(index >= nr_evmcs_1_fields)) + return -ENOENT; + + evmcs_field = &vmcs_field_to_evmcs_1[index]; + + /* + * Use offset=0 to detect holes in eVMCS. This offset belongs to + * 'revision_id' but this field has no encoding and is supposed to + * be accessed directly. + */ + if (unlikely(!evmcs_field->offset)) + return -ENOENT; + + if (clean_field) + *clean_field = evmcs_field->clean_field; + + return evmcs_field->offset; +} + +static inline u64 evmcs_read_any(struct hv_enlightened_vmcs *evmcs, + unsigned long field, u16 offset) +{ + /* + * vmcs12_read_any() doesn't care whether the supplied structure + * is 'struct vmcs12' or 'struct hv_enlightened_vmcs' as it takes + * the exact offset of the required field, use it for convenience + * here. + */ + return vmcs12_read_any((void *)evmcs, field, offset); +} + +#endif /* __KVM_X86_VMX_HYPERV_H */ diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index c5ec0ef51ff78f..6329a306856b28 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -179,7 +179,7 @@ static int nested_vmx_failValid(struct kvm_vcpu *vcpu, * VM_INSTRUCTION_ERROR is not shadowed. Enlightened VMCS 'shadows' all * fields and thus must be synced. */ - if (to_vmx(vcpu)->nested.hv_evmcs_vmptr != EVMPTR_INVALID) + if (nested_vmx_is_evmptr12_set(to_vmx(vcpu))) to_vmx(vcpu)->nested.need_vmcs12_to_shadow_sync = true; return kvm_skip_emulated_instruction(vcpu); @@ -194,7 +194,7 @@ static int nested_vmx_fail(struct kvm_vcpu *vcpu, u32 vm_instruction_error) * can't be done if there isn't a current VMCS. */ if (vmx->nested.current_vmptr == INVALID_GPA && - !evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) + !nested_vmx_is_evmptr12_valid(vmx)) return nested_vmx_failInvalid(vcpu); return nested_vmx_failValid(vcpu, vm_instruction_error); @@ -226,10 +226,11 @@ static void vmx_disable_shadow_vmcs(struct vcpu_vmx *vmx) static inline void nested_release_evmcs(struct kvm_vcpu *vcpu) { +#ifdef CONFIG_KVM_HYPERV struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(vcpu); struct vcpu_vmx *vmx = to_vmx(vcpu); - if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) { + if (nested_vmx_is_evmptr12_valid(vmx)) { kvm_vcpu_unmap(vcpu, &vmx->nested.hv_evmcs_map, true); vmx->nested.hv_evmcs = NULL; } @@ -241,6 +242,34 @@ static inline void nested_release_evmcs(struct kvm_vcpu *vcpu) hv_vcpu->nested.vm_id = 0; hv_vcpu->nested.vp_id = 0; } +#endif +} + +static bool nested_evmcs_handle_vmclear(struct kvm_vcpu *vcpu, gpa_t vmptr) +{ +#ifdef CONFIG_KVM_HYPERV + struct vcpu_vmx *vmx = to_vmx(vcpu); + /* + * When Enlightened VMEntry is enabled on the calling CPU we treat + * memory area pointer by vmptr as Enlightened VMCS (as there's no good + * way to distinguish it from VMCS12) and we must not corrupt it by + * writing to the non-existent 'launch_state' field. The area doesn't + * have to be the currently active EVMCS on the calling CPU and there's + * nothing KVM has to do to transition it from 'active' to 'non-active' + * state. It is possible that the area will stay mapped as + * vmx->nested.hv_evmcs but this shouldn't be a problem. + */ + if (!guest_cpuid_has_evmcs(vcpu) || + !evmptr_is_valid(nested_get_evmptr(vcpu))) + return false; + + if (nested_vmx_evmcs(vmx) && vmptr == vmx->nested.hv_evmcs_vmptr) + nested_release_evmcs(vcpu); + + return true; +#else + return false; +#endif } static void vmx_sync_vmcs_host_state(struct vcpu_vmx *vmx, @@ -572,7 +601,6 @@ static inline bool nested_vmx_prepare_msr_bitmap(struct kvm_vcpu *vcpu, int msr; unsigned long *msr_bitmap_l1; unsigned long *msr_bitmap_l0 = vmx->nested.vmcs02.msr_bitmap; - struct hv_enlightened_vmcs *evmcs = vmx->nested.hv_evmcs; struct kvm_host_map *map = &vmx->nested.msr_bitmap_map; /* Nothing to do if the MSR bitmap is not in use. */ @@ -588,10 +616,13 @@ static inline bool nested_vmx_prepare_msr_bitmap(struct kvm_vcpu *vcpu, * - Nested hypervisor (L1) has enabled 'Enlightened MSR Bitmap' feature * and tells KVM (L0) there were no changes in MSR bitmap for L2. */ - if (!vmx->nested.force_msr_bitmap_recalc && evmcs && - evmcs->hv_enlightenments_control.msr_bitmap && - evmcs->hv_clean_fields & HV_VMX_ENLIGHTENED_CLEAN_FIELD_MSR_BITMAP) - return true; + if (!vmx->nested.force_msr_bitmap_recalc) { + struct hv_enlightened_vmcs *evmcs = nested_vmx_evmcs(vmx); + + if (evmcs && evmcs->hv_enlightenments_control.msr_bitmap && + evmcs->hv_clean_fields & HV_VMX_ENLIGHTENED_CLEAN_FIELD_MSR_BITMAP) + return true; + } if (kvm_vcpu_map(vcpu, gpa_to_gfn(vmcs12->msr_bitmap), map)) return false; @@ -1085,7 +1116,7 @@ static int nested_vmx_load_cr3(struct kvm_vcpu *vcpu, unsigned long cr3, bool nested_ept, bool reload_pdptrs, enum vm_entry_failure_code *entry_failure_code) { - if (CC(kvm_vcpu_is_illegal_gpa(vcpu, cr3))) { + if (CC(!kvm_vcpu_is_legal_cr3(vcpu, cr3))) { *entry_failure_code = ENTRY_FAIL_DEFAULT; return -EINVAL; } @@ -1139,14 +1170,8 @@ static void nested_vmx_transition_tlb_flush(struct kvm_vcpu *vcpu, { struct vcpu_vmx *vmx = to_vmx(vcpu); - /* - * KVM_REQ_HV_TLB_FLUSH flushes entries from either L1's VP_ID or - * L2's VP_ID upon request from the guest. Make sure we check for - * pending entries in the right FIFO upon L1/L2 transition as these - * requests are put by other vCPUs asynchronously. - */ - if (to_hv_vcpu(vcpu) && enable_ept) - kvm_make_request(KVM_REQ_HV_TLB_FLUSH, vcpu); + /* Handle pending Hyper-V TLB flush requests */ + kvm_hv_nested_transtion_tlb_flush(vcpu, enable_ept); /* * If vmcs12 doesn't use VPID, L1 expects linear and combined mappings @@ -1578,8 +1603,9 @@ static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx) static void copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx, u32 hv_clean_fields) { +#ifdef CONFIG_KVM_HYPERV struct vmcs12 *vmcs12 = vmx->nested.cached_vmcs12; - struct hv_enlightened_vmcs *evmcs = vmx->nested.hv_evmcs; + struct hv_enlightened_vmcs *evmcs = nested_vmx_evmcs(vmx); struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(&vmx->vcpu); /* HV_VMX_ENLIGHTENED_CLEAN_FIELD_NONE */ @@ -1818,12 +1844,16 @@ static void copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx, u32 hv_clean_fields */ return; +#else /* CONFIG_KVM_HYPERV */ + KVM_BUG_ON(1, vmx->vcpu.kvm); +#endif /* CONFIG_KVM_HYPERV */ } static void copy_vmcs12_to_enlightened(struct vcpu_vmx *vmx) { +#ifdef CONFIG_KVM_HYPERV struct vmcs12 *vmcs12 = vmx->nested.cached_vmcs12; - struct hv_enlightened_vmcs *evmcs = vmx->nested.hv_evmcs; + struct hv_enlightened_vmcs *evmcs = nested_vmx_evmcs(vmx); /* * Should not be changed by KVM: @@ -1992,6 +2022,9 @@ static void copy_vmcs12_to_enlightened(struct vcpu_vmx *vmx) evmcs->guest_bndcfgs = vmcs12->guest_bndcfgs; return; +#else /* CONFIG_KVM_HYPERV */ + KVM_BUG_ON(1, vmx->vcpu.kvm); +#endif /* CONFIG_KVM_HYPERV */ } /* @@ -2001,6 +2034,7 @@ static void copy_vmcs12_to_enlightened(struct vcpu_vmx *vmx) static enum nested_evmptrld_status nested_vmx_handle_enlightened_vmptrld( struct kvm_vcpu *vcpu, bool from_launch) { +#ifdef CONFIG_KVM_HYPERV struct vcpu_vmx *vmx = to_vmx(vcpu); bool evmcs_gpa_changed = false; u64 evmcs_gpa; @@ -2082,13 +2116,16 @@ static enum nested_evmptrld_status nested_vmx_handle_enlightened_vmptrld( } return EVMPTRLD_SUCCEEDED; +#else + return EVMPTRLD_DISABLED; +#endif } void nested_sync_vmcs12_to_shadow(struct kvm_vcpu *vcpu) { struct vcpu_vmx *vmx = to_vmx(vcpu); - if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) + if (nested_vmx_is_evmptr12_valid(vmx)) copy_vmcs12_to_enlightened(vmx); else copy_vmcs12_to_shadow(vmx); @@ -2242,7 +2279,7 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct loaded_vmcs *vmcs0 u32 exec_control; u64 guest_efer = nested_vmx_calc_efer(vmx, vmcs12); - if (vmx->nested.dirty_vmcs12 || evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) + if (vmx->nested.dirty_vmcs12 || nested_vmx_is_evmptr12_valid(vmx)) prepare_vmcs02_early_rare(vmx, vmcs12); /* @@ -2403,7 +2440,7 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct loaded_vmcs *vmcs0 static void prepare_vmcs02_rare(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12) { - struct hv_enlightened_vmcs *hv_evmcs = vmx->nested.hv_evmcs; + struct hv_enlightened_vmcs *hv_evmcs = nested_vmx_evmcs(vmx); if (!hv_evmcs || !(hv_evmcs->hv_clean_fields & HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP2)) { @@ -2535,15 +2572,15 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, enum vm_entry_failure_code *entry_failure_code) { struct vcpu_vmx *vmx = to_vmx(vcpu); + struct hv_enlightened_vmcs *evmcs = nested_vmx_evmcs(vmx); bool load_guest_pdptrs_vmcs12 = false; - if (vmx->nested.dirty_vmcs12 || evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) { + if (vmx->nested.dirty_vmcs12 || nested_vmx_is_evmptr12_valid(vmx)) { prepare_vmcs02_rare(vmx, vmcs12); vmx->nested.dirty_vmcs12 = false; - load_guest_pdptrs_vmcs12 = !evmptr_is_valid(vmx->nested.hv_evmcs_vmptr) || - !(vmx->nested.hv_evmcs->hv_clean_fields & - HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1); + load_guest_pdptrs_vmcs12 = !nested_vmx_is_evmptr12_valid(vmx) || + !(evmcs->hv_clean_fields & HV_VMX_ENLIGHTENED_CLEAN_FIELD_GUEST_GRP1); } if (vmx->nested.nested_run_pending && @@ -2664,9 +2701,8 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, * bits when it changes a field in eVMCS. Mark all fields as clean * here. */ - if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) - vmx->nested.hv_evmcs->hv_clean_fields |= - HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL; + if (nested_vmx_is_evmptr12_valid(vmx)) + evmcs->hv_clean_fields |= HV_VMX_ENLIGHTENED_CLEAN_FIELD_ALL; return 0; } @@ -2717,7 +2753,7 @@ static bool nested_vmx_check_eptp(struct kvm_vcpu *vcpu, u64 new_eptp) } /* Reserved bits should not be set */ - if (CC(kvm_vcpu_is_illegal_gpa(vcpu, new_eptp) || ((new_eptp >> 7) & 0x1f))) + if (CC(!kvm_vcpu_is_legal_gpa(vcpu, new_eptp) || ((new_eptp >> 7) & 0x1f))) return false; /* AD, if set, should be supported */ @@ -2888,8 +2924,10 @@ static int nested_vmx_check_controls(struct kvm_vcpu *vcpu, nested_check_vm_entry_controls(vcpu, vmcs12)) return -EINVAL; +#ifdef CONFIG_KVM_HYPERV if (guest_cpuid_has_evmcs(vcpu)) return nested_evmcs_check_controls(vmcs12); +#endif return 0; } @@ -2912,7 +2950,7 @@ static int nested_vmx_check_host_state(struct kvm_vcpu *vcpu, if (CC(!nested_host_cr0_valid(vcpu, vmcs12->host_cr0)) || CC(!nested_host_cr4_valid(vcpu, vmcs12->host_cr4)) || - CC(kvm_vcpu_is_illegal_gpa(vcpu, vmcs12->host_cr3))) + CC(!kvm_vcpu_is_legal_cr3(vcpu, vmcs12->host_cr3))) return -EINVAL; if (CC(is_noncanonical_address(vmcs12->host_ia32_sysenter_esp, vcpu)) || @@ -3161,6 +3199,7 @@ static int nested_vmx_check_vmentry_hw(struct kvm_vcpu *vcpu) return 0; } +#ifdef CONFIG_KVM_HYPERV static bool nested_get_evmcs_page(struct kvm_vcpu *vcpu) { struct vcpu_vmx *vmx = to_vmx(vcpu); @@ -3188,6 +3227,7 @@ static bool nested_get_evmcs_page(struct kvm_vcpu *vcpu) return true; } +#endif static bool nested_get_vmcs12_pages(struct kvm_vcpu *vcpu) { @@ -3279,6 +3319,7 @@ static bool nested_get_vmcs12_pages(struct kvm_vcpu *vcpu) static bool vmx_get_nested_state_pages(struct kvm_vcpu *vcpu) { +#ifdef CONFIG_KVM_HYPERV /* * Note: nested_get_evmcs_page() also updates 'vp_assist_page' copy * in 'struct kvm_vcpu_hv' in case eVMCS is in use, this is mandatory @@ -3295,6 +3336,7 @@ static bool vmx_get_nested_state_pages(struct kvm_vcpu *vcpu) return false; } +#endif if (is_guest_mode(vcpu) && !nested_get_vmcs12_pages(vcpu)) return false; @@ -3538,7 +3580,7 @@ vmentry_fail_vmexit: load_vmcs12_host_state(vcpu, vmcs12); vmcs12->vm_exit_reason = exit_reason.full; - if (enable_shadow_vmcs || evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) + if (enable_shadow_vmcs || nested_vmx_is_evmptr12_valid(vmx)) vmx->nested.need_vmcs12_to_shadow_sync = true; return NVMX_VMENTRY_VMEXIT; } @@ -3569,7 +3611,7 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) if (CC(evmptrld_status == EVMPTRLD_VMFAIL)) return nested_vmx_failInvalid(vcpu); - if (CC(!evmptr_is_valid(vmx->nested.hv_evmcs_vmptr) && + if (CC(!nested_vmx_is_evmptr12_valid(vmx) && vmx->nested.current_vmptr == INVALID_GPA)) return nested_vmx_failInvalid(vcpu); @@ -3584,8 +3626,10 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch) if (CC(vmcs12->hdr.shadow_vmcs)) return nested_vmx_failInvalid(vcpu); - if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) { - copy_enlightened_to_vmcs12(vmx, vmx->nested.hv_evmcs->hv_clean_fields); + if (nested_vmx_is_evmptr12_valid(vmx)) { + struct hv_enlightened_vmcs *evmcs = nested_vmx_evmcs(vmx); + + copy_enlightened_to_vmcs12(vmx, evmcs->hv_clean_fields); /* Enlightened VMCS doesn't have launch state */ vmcs12->launch_state = !launch; } else if (enable_shadow_vmcs) { @@ -4329,11 +4373,11 @@ static void sync_vmcs02_to_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) { struct vcpu_vmx *vmx = to_vmx(vcpu); - if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) + if (nested_vmx_is_evmptr12_valid(vmx)) sync_vmcs02_to_vmcs12_rare(vcpu, vmcs12); vmx->nested.need_sync_vmcs02_to_vmcs12_rare = - !evmptr_is_valid(vmx->nested.hv_evmcs_vmptr); + !nested_vmx_is_evmptr12_valid(vmx); vmcs12->guest_cr0 = vmcs12_guest_cr0(vcpu, vmcs12); vmcs12->guest_cr4 = vmcs12_guest_cr4(vcpu, vmcs12); @@ -4732,6 +4776,7 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason, /* trying to cancel vmlaunch/vmresume is a bug */ WARN_ON_ONCE(vmx->nested.nested_run_pending); +#ifdef CONFIG_KVM_HYPERV if (kvm_check_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu)) { /* * KVM_REQ_GET_NESTED_STATE_PAGES is also used to map @@ -4741,6 +4786,7 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason, */ (void)nested_get_evmcs_page(vcpu); } +#endif /* Service pending TLB flush requests for L2 before switching to L1. */ kvm_service_local_tlb_flush_requests(vcpu); @@ -4854,7 +4900,7 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason, } if ((vm_exit_reason != -1) && - (enable_shadow_vmcs || evmptr_is_valid(vmx->nested.hv_evmcs_vmptr))) + (enable_shadow_vmcs || nested_vmx_is_evmptr12_valid(vmx))) vmx->nested.need_vmcs12_to_shadow_sync = true; /* in case we halted in L2 */ @@ -4980,6 +5026,7 @@ int get_vmx_mem_address(struct kvm_vcpu *vcpu, unsigned long exit_qualification, else *ret = off; + *ret = vmx_get_untagged_addr(vcpu, *ret, 0); /* Long mode: #GP(0)/#SS(0) if the memory address is in a * non-canonical form. This is the only check on the memory * destination for long mode! @@ -5292,18 +5339,7 @@ static int handle_vmclear(struct kvm_vcpu *vcpu) if (vmptr == vmx->nested.vmxon_ptr) return nested_vmx_fail(vcpu, VMXERR_VMCLEAR_VMXON_POINTER); - /* - * When Enlightened VMEntry is enabled on the calling CPU we treat - * memory area pointer by vmptr as Enlightened VMCS (as there's no good - * way to distinguish it from VMCS12) and we must not corrupt it by - * writing to the non-existent 'launch_state' field. The area doesn't - * have to be the currently active EVMCS on the calling CPU and there's - * nothing KVM has to do to transition it from 'active' to 'non-active' - * state. It is possible that the area will stay mapped as - * vmx->nested.hv_evmcs but this shouldn't be a problem. - */ - if (likely(!guest_cpuid_has_evmcs(vcpu) || - !evmptr_is_valid(nested_get_evmptr(vcpu)))) { + if (likely(!nested_evmcs_handle_vmclear(vcpu, vmptr))) { if (vmptr == vmx->nested.current_vmptr) nested_release_vmcs12(vcpu); @@ -5320,8 +5356,6 @@ static int handle_vmclear(struct kvm_vcpu *vcpu) vmptr + offsetof(struct vmcs12, launch_state), &zero, sizeof(zero)); - } else if (vmx->nested.hv_evmcs && vmptr == vmx->nested.hv_evmcs_vmptr) { - nested_release_evmcs(vcpu); } return nested_vmx_succeed(vcpu); @@ -5360,7 +5394,7 @@ static int handle_vmread(struct kvm_vcpu *vcpu) /* Decode instruction info and find the field to read */ field = kvm_register_read(vcpu, (((instr_info) >> 28) & 0xf)); - if (!evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) { + if (!nested_vmx_is_evmptr12_valid(vmx)) { /* * In VMX non-root operation, when the VMCS-link pointer is INVALID_GPA, * any VMREAD sets the ALU flags for VMfailInvalid. @@ -5398,7 +5432,7 @@ static int handle_vmread(struct kvm_vcpu *vcpu) return nested_vmx_fail(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT); /* Read the field, zero-extended to a u64 value */ - value = evmcs_read_any(vmx->nested.hv_evmcs, field, offset); + value = evmcs_read_any(nested_vmx_evmcs(vmx), field, offset); } /* @@ -5586,7 +5620,7 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu) return nested_vmx_fail(vcpu, VMXERR_VMPTRLD_VMXON_POINTER); /* Forbid normal VMPTRLD if Enlightened version was used */ - if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) + if (nested_vmx_is_evmptr12_valid(vmx)) return 1; if (vmx->nested.current_vmptr != vmptr) { @@ -5649,7 +5683,7 @@ static int handle_vmptrst(struct kvm_vcpu *vcpu) if (!nested_vmx_check_permission(vcpu)) return 1; - if (unlikely(evmptr_is_valid(to_vmx(vcpu)->nested.hv_evmcs_vmptr))) + if (unlikely(nested_vmx_is_evmptr12_valid(to_vmx(vcpu)))) return 1; if (get_vmx_mem_address(vcpu, exit_qual, instr_info, @@ -5797,6 +5831,10 @@ static int handle_invvpid(struct kvm_vcpu *vcpu) vpid02 = nested_get_vpid02(vcpu); switch (type) { case VMX_VPID_EXTENT_INDIVIDUAL_ADDR: + /* + * LAM doesn't apply to addresses that are inputs to TLB + * invalidation. + */ if (!operand.vpid || is_noncanonical_address(operand.gla, vcpu)) return nested_vmx_fail(vcpu, @@ -6208,11 +6246,13 @@ static bool nested_vmx_l0_wants_exit(struct kvm_vcpu *vcpu, * Handle L2's bus locks in L0 directly. */ return true; +#ifdef CONFIG_KVM_HYPERV case EXIT_REASON_VMCALL: /* Hyper-V L2 TLB flush hypercall is handled by L0 */ return guest_hv_cpuid_has_l2_tlb_flush(vcpu) && nested_evmcs_l2_tlb_flush_enabled(vcpu) && kvm_hv_is_tlb_flush_hcall(vcpu); +#endif default: break; } @@ -6435,7 +6475,7 @@ static int vmx_get_nested_state(struct kvm_vcpu *vcpu, kvm_state.size += sizeof(user_vmx_nested_state->vmcs12); /* 'hv_evmcs_vmptr' can also be EVMPTR_MAP_PENDING here */ - if (vmx->nested.hv_evmcs_vmptr != EVMPTR_INVALID) + if (nested_vmx_is_evmptr12_set(vmx)) kvm_state.flags |= KVM_STATE_NESTED_EVMCS; if (is_guest_mode(vcpu) && @@ -6491,7 +6531,7 @@ static int vmx_get_nested_state(struct kvm_vcpu *vcpu, } else { copy_vmcs02_to_vmcs12_rare(vcpu, get_vmcs12(vcpu)); if (!vmx->nested.need_vmcs12_to_shadow_sync) { - if (evmptr_is_valid(vmx->nested.hv_evmcs_vmptr)) + if (nested_vmx_is_evmptr12_valid(vmx)) /* * L1 hypervisor is not obliged to keep eVMCS * clean fields data always up-to-date while @@ -6561,7 +6601,7 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu, * code was changed such that flag signals vmcs12 should * be copied into eVMCS in guest memory. * - * To preserve backwards compatability, allow user + * To preserve backwards compatibility, allow user * to set this flag even when there is no VMXON region. */ if (kvm_state->flags & ~KVM_STATE_NESTED_EVMCS) @@ -6632,6 +6672,7 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu, return -EINVAL; set_current_vmptr(vmx, kvm_state->hdr.vmx.vmcs12_pa); +#ifdef CONFIG_KVM_HYPERV } else if (kvm_state->flags & KVM_STATE_NESTED_EVMCS) { /* * nested_vmx_handle_enlightened_vmptrld() cannot be called @@ -6641,6 +6682,7 @@ static int vmx_set_nested_state(struct kvm_vcpu *vcpu, */ vmx->nested.hv_evmcs_vmptr = EVMPTR_MAP_PENDING; kvm_make_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu); +#endif } else { return -EINVAL; } @@ -7096,7 +7138,9 @@ struct kvm_x86_nested_ops vmx_nested_ops = { .set_state = vmx_set_nested_state, .get_nested_state_pages = vmx_get_nested_state_pages, .write_log_dirty = nested_vmx_write_pml_buffer, +#ifdef CONFIG_KVM_HYPERV .enable_evmcs = nested_enable_evmcs, .get_evmcs_version = nested_get_evmcs_version, .hv_inject_synthetic_vmexit_post_tlb_flush = vmx_hv_inject_synthetic_vmexit_post_tlb_flush, +#endif }; diff --git a/arch/x86/kvm/vmx/nested.h b/arch/x86/kvm/vmx/nested.h index b4b9d51438c6b3..cce4e2aa30fbf8 100644 --- a/arch/x86/kvm/vmx/nested.h +++ b/arch/x86/kvm/vmx/nested.h @@ -3,6 +3,7 @@ #define __KVM_X86_VMX_NESTED_H #include "kvm_cache_regs.h" +#include "hyperv.h" #include "vmcs12.h" #include "vmx.h" @@ -57,7 +58,7 @@ static inline int vmx_has_valid_vmcs12(struct kvm_vcpu *vcpu) /* 'hv_evmcs_vmptr' can also be EVMPTR_MAP_PENDING here */ return vmx->nested.current_vmptr != -1ull || - vmx->nested.hv_evmcs_vmptr != EVMPTR_INVALID; + nested_vmx_is_evmptr12_set(vmx); } static inline u16 nested_get_vpid02(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 820d3e1f6b4f82..a6216c8747291f 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -437,11 +437,9 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) !(msr & MSR_PMC_FULL_WIDTH_BIT)) data = (s64)(s32)data; pmc_write_counter(pmc, data); - pmc_update_sample_period(pmc); break; } else if ((pmc = get_fixed_pmc(pmu, msr))) { pmc_write_counter(pmc, data); - pmc_update_sample_period(pmc); break; } else if ((pmc = get_gp_pmc(pmu, msr, MSR_P6_EVNTSEL0))) { reserved_bits = pmu->reserved_bits; @@ -632,26 +630,6 @@ static void intel_pmu_init(struct kvm_vcpu *vcpu) static void intel_pmu_reset(struct kvm_vcpu *vcpu) { - struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); - struct kvm_pmc *pmc = NULL; - int i; - - for (i = 0; i < KVM_INTEL_PMC_MAX_GENERIC; i++) { - pmc = &pmu->gp_counters[i]; - - pmc_stop_counter(pmc); - pmc->counter = pmc->prev_counter = pmc->eventsel = 0; - } - - for (i = 0; i < KVM_PMC_MAX_FIXED; i++) { - pmc = &pmu->fixed_counters[i]; - - pmc_stop_counter(pmc); - pmc->counter = pmc->prev_counter = 0; - } - - pmu->fixed_ctr_ctrl = pmu->global_ctrl = pmu->global_status = 0; - intel_pmu_release_guest_lbr_event(vcpu); } diff --git a/arch/x86/kvm/vmx/sgx.c b/arch/x86/kvm/vmx/sgx.c index 3e822e58249753..6fef01e0536e50 100644 --- a/arch/x86/kvm/vmx/sgx.c +++ b/arch/x86/kvm/vmx/sgx.c @@ -37,6 +37,7 @@ static int sgx_get_encls_gva(struct kvm_vcpu *vcpu, unsigned long offset, if (!IS_ALIGNED(*gva, alignment)) { fault = true; } else if (likely(is_64_bit_mode(vcpu))) { + *gva = vmx_get_untagged_addr(vcpu, *gva, 0); fault = is_noncanonical_address(*gva, vcpu); } else { *gva &= 0xffffffff; diff --git a/arch/x86/kvm/vmx/vmenter.S b/arch/x86/kvm/vmx/vmenter.S index be275a0410a899..906ecd00151135 100644 --- a/arch/x86/kvm/vmx/vmenter.S +++ b/arch/x86/kvm/vmx/vmenter.S @@ -289,7 +289,7 @@ SYM_INNER_LABEL_ALIGN(vmx_vmexit, SYM_L_GLOBAL) RET .Lfixup: - cmpb $0, kvm_rebooting + cmpb $0, _ASM_RIP(kvm_rebooting) jne .Lvmfail ud2 .Lvmfail: diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index be20a60047b1f2..e262bc2ba4e569 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -66,6 +66,7 @@ #include "vmx.h" #include "x86.h" #include "smm.h" +#include "vmx_onhyperv.h" MODULE_AUTHOR("Qumranet"); MODULE_LICENSE("GPL"); @@ -523,22 +524,14 @@ module_param(enlightened_vmcs, bool, 0444); static int hv_enable_l2_tlb_flush(struct kvm_vcpu *vcpu) { struct hv_enlightened_vmcs *evmcs; - struct hv_partition_assist_pg **p_hv_pa_pg = - &to_kvm_hv(vcpu->kvm)->hv_pa_pg; - /* - * Synthetic VM-Exit is not enabled in current code and so All - * evmcs in singe VM shares same assist page. - */ - if (!*p_hv_pa_pg) - *p_hv_pa_pg = kzalloc(PAGE_SIZE, GFP_KERNEL_ACCOUNT); + hpa_t partition_assist_page = hv_get_partition_assist_page(vcpu); - if (!*p_hv_pa_pg) + if (partition_assist_page == INVALID_PAGE) return -ENOMEM; evmcs = (struct hv_enlightened_vmcs *)to_vmx(vcpu)->loaded_vmcs->vmcs; - evmcs->partition_assist_page = - __pa(*p_hv_pa_pg); + evmcs->partition_assist_page = partition_assist_page; evmcs->hv_vm_id = (unsigned long)vcpu->kvm; evmcs->hv_enlightenments_control.nested_flush_hypercall = 1; @@ -1809,7 +1802,7 @@ static void vmx_inject_exception(struct kvm_vcpu *vcpu) * do generate error codes with bits 31:16 set, and so KVM's * ABI lets userspace shove in arbitrary 32-bit values. Drop * the upper bits to avoid VM-Fail, losing information that - * does't really exist is preferable to killing the VM. + * doesn't really exist is preferable to killing the VM. */ vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, (u16)ex->error_code); intr_info |= INTR_INFO_DELIVER_CODE_MASK; @@ -2055,6 +2048,7 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) if (vmx_get_vmx_msr(&vmx->nested.msrs, msr_info->index, &msr_info->data)) return 1; +#ifdef CONFIG_KVM_HYPERV /* * Enlightened VMCS v1 doesn't have certain VMCS fields but * instead of just ignoring the features, different Hyper-V @@ -2065,6 +2059,7 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) if (!msr_info->host_initiated && guest_cpuid_has_evmcs(vcpu)) nested_evmcs_filter_control_msr(vcpu, msr_info->index, &msr_info->data); +#endif break; case MSR_IA32_RTIT_CTL: if (!vmx_pt_mode_is_host_guest()) @@ -3400,7 +3395,8 @@ static void vmx_load_mmu_pgd(struct kvm_vcpu *vcpu, hpa_t root_hpa, update_guest_cr3 = false; vmx_ept_load_pdptrs(vcpu); } else { - guest_cr3 = root_hpa | kvm_get_active_pcid(vcpu); + guest_cr3 = root_hpa | kvm_get_active_pcid(vcpu) | + kvm_get_active_cr3_lam_bits(vcpu); } if (update_guest_cr3) @@ -4833,7 +4829,10 @@ static void __vmx_vcpu_reset(struct kvm_vcpu *vcpu) vmx->nested.posted_intr_nv = -1; vmx->nested.vmxon_ptr = INVALID_GPA; vmx->nested.current_vmptr = INVALID_GPA; + +#ifdef CONFIG_KVM_HYPERV vmx->nested.hv_evmcs_vmptr = EVMPTR_INVALID; +#endif vcpu->arch.microcode_version = 0x100000000ULL; vmx->msr_ia32_feature_control_valid_bits = FEAT_CTL_LOCKED; @@ -5782,7 +5781,7 @@ static int handle_ept_violation(struct kvm_vcpu *vcpu) * would also use advanced VM-exit information for EPT violations to * reconstruct the page fault error code. */ - if (unlikely(allow_smaller_maxphyaddr && kvm_vcpu_is_illegal_gpa(vcpu, gpa))) + if (unlikely(allow_smaller_maxphyaddr && !kvm_vcpu_is_legal_gpa(vcpu, gpa))) return kvm_emulate_instruction(vcpu, 0); return kvm_mmu_page_fault(vcpu, gpa, error_code, NULL, 0); @@ -6757,10 +6756,10 @@ static void vmx_set_apic_access_page_addr(struct kvm_vcpu *vcpu) return; /* - * Grab the memslot so that the hva lookup for the mmu_notifier retry - * is guaranteed to use the same memslot as the pfn lookup, i.e. rely - * on the pfn lookup's validation of the memslot to ensure a valid hva - * is used for the retry check. + * Explicitly grab the memslot using KVM's internal slot ID to ensure + * KVM doesn't unintentionally grab a userspace memslot. It _should_ + * be impossible for userspace to create a memslot for the APIC when + * APICv is enabled, but paranoia won't hurt in this case. */ slot = id_to_memslot(slots, APIC_ACCESS_PAGE_PRIVATE_MEMSLOT); if (!slot || slot->flags & KVM_MEMSLOT_INVALID) @@ -6785,8 +6784,7 @@ static void vmx_set_apic_access_page_addr(struct kvm_vcpu *vcpu) return; read_lock(&vcpu->kvm->mmu_lock); - if (mmu_invalidate_retry_hva(kvm, mmu_seq, - gfn_to_hva_memslot(slot, gfn))) { + if (mmu_invalidate_retry_gfn(kvm, mmu_seq, gfn)) { kvm_make_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu); read_unlock(&vcpu->kvm->mmu_lock); goto out; @@ -7674,6 +7672,9 @@ static void nested_vmx_cr_fixed1_bits_update(struct kvm_vcpu *vcpu) cr4_fixed1_update(X86_CR4_UMIP, ecx, feature_bit(UMIP)); cr4_fixed1_update(X86_CR4_LA57, ecx, feature_bit(LA57)); + entry = kvm_find_cpuid_entry_index(vcpu, 0x7, 1); + cr4_fixed1_update(X86_CR4_LAM_SUP, eax, feature_bit(LAM)); + #undef cr4_fixed1_update } @@ -7760,6 +7761,7 @@ static void vmx_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) kvm_governed_feature_check_and_set(vcpu, X86_FEATURE_XSAVES); kvm_governed_feature_check_and_set(vcpu, X86_FEATURE_VMX); + kvm_governed_feature_check_and_set(vcpu, X86_FEATURE_LAM); vmx_setup_uret_msrs(vmx); @@ -8206,6 +8208,50 @@ static void vmx_vm_destroy(struct kvm *kvm) free_pages((unsigned long)kvm_vmx->pid_table, vmx_get_pid_table_order(kvm)); } +/* + * Note, the SDM states that the linear address is masked *after* the modified + * canonicality check, whereas KVM masks (untags) the address and then performs + * a "normal" canonicality check. Functionally, the two methods are identical, + * and when the masking occurs relative to the canonicality check isn't visible + * to software, i.e. KVM's behavior doesn't violate the SDM. + */ +gva_t vmx_get_untagged_addr(struct kvm_vcpu *vcpu, gva_t gva, unsigned int flags) +{ + int lam_bit; + unsigned long cr3_bits; + + if (flags & (X86EMUL_F_FETCH | X86EMUL_F_IMPLICIT | X86EMUL_F_INVLPG)) + return gva; + + if (!is_64_bit_mode(vcpu)) + return gva; + + /* + * Bit 63 determines if the address should be treated as user address + * or a supervisor address. + */ + if (!(gva & BIT_ULL(63))) { + cr3_bits = kvm_get_active_cr3_lam_bits(vcpu); + if (!(cr3_bits & (X86_CR3_LAM_U57 | X86_CR3_LAM_U48))) + return gva; + + /* LAM_U48 is ignored if LAM_U57 is set. */ + lam_bit = cr3_bits & X86_CR3_LAM_U57 ? 56 : 47; + } else { + if (!kvm_is_cr4_bit_set(vcpu, X86_CR4_LAM_SUP)) + return gva; + + lam_bit = kvm_is_cr4_bit_set(vcpu, X86_CR4_LA57) ? 56 : 47; + } + + /* + * Untag the address by sign-extending the lam_bit, but NOT to bit 63. + * Bit 63 is retained from the raw virtual address so that untagging + * doesn't change a user access to a supervisor access, and vice versa. + */ + return (sign_extend64(gva, lam_bit) & ~BIT_ULL(63)) | (gva & BIT_ULL(63)); +} + static struct kvm_x86_ops vmx_x86_ops __initdata = { .name = KBUILD_MODNAME, @@ -8346,6 +8392,8 @@ static struct kvm_x86_ops vmx_x86_ops __initdata = { .complete_emulated_msr = kvm_complete_insn_gp, .vcpu_deliver_sipi_vector = kvm_vcpu_deliver_sipi_vector, + + .get_untagged_addr = vmx_get_untagged_addr, }; static unsigned int vmx_handle_intel_pt_intr(void) diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h index c2130d2c8e24bb..e3b0985bb74a1f 100644 --- a/arch/x86/kvm/vmx/vmx.h +++ b/arch/x86/kvm/vmx/vmx.h @@ -241,9 +241,11 @@ struct nested_vmx { bool guest_mode; } smm; +#ifdef CONFIG_KVM_HYPERV gpa_t hv_evmcs_vmptr; struct kvm_host_map hv_evmcs_map; struct hv_enlightened_vmcs *hv_evmcs; +#endif }; struct vcpu_vmx { @@ -420,6 +422,8 @@ void vmx_enable_intercept_for_msr(struct kvm_vcpu *vcpu, u32 msr, int type); u64 vmx_get_l2_tsc_offset(struct kvm_vcpu *vcpu); u64 vmx_get_l2_tsc_multiplier(struct kvm_vcpu *vcpu); +gva_t vmx_get_untagged_addr(struct kvm_vcpu *vcpu, gva_t gva, unsigned int flags); + static inline void vmx_set_intercept_for_msr(struct kvm_vcpu *vcpu, u32 msr, int type, bool value) { @@ -745,14 +749,4 @@ static inline bool vmx_can_use_ipiv(struct kvm_vcpu *vcpu) return lapic_in_kernel(vcpu) && enable_ipiv; } -static inline bool guest_cpuid_has_evmcs(struct kvm_vcpu *vcpu) -{ - /* - * eVMCS is exposed to the guest if Hyper-V is enabled in CPUID and - * eVMCS has been explicitly enabled by userspace. - */ - return vcpu->arch.hyperv_enabled && - to_vmx(vcpu)->nested.enlightened_vmcs_enabled; -} - #endif /* __KVM_X86_VMX_H */ diff --git a/arch/x86/kvm/vmx/vmx_onhyperv.c b/arch/x86/kvm/vmx/vmx_onhyperv.c new file mode 100644 index 00000000000000..b9a8b91166d020 --- /dev/null +++ b/arch/x86/kvm/vmx/vmx_onhyperv.c @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include "capabilities.h" +#include "vmx_onhyperv.h" + +DEFINE_STATIC_KEY_FALSE(__kvm_is_using_evmcs); + +/* + * KVM on Hyper-V always uses the latest known eVMCSv1 revision, the assumption + * is: in case a feature has corresponding fields in eVMCS described and it was + * exposed in VMX feature MSRs, KVM is free to use it. Warn if KVM meets a + * feature which has no corresponding eVMCS field, this likely means that KVM + * needs to be updated. + */ +#define evmcs_check_vmcs_conf(field, ctrl) \ + do { \ + typeof(vmcs_conf->field) unsupported; \ + \ + unsupported = vmcs_conf->field & ~EVMCS1_SUPPORTED_ ## ctrl; \ + if (unsupported) { \ + pr_warn_once(#field " unsupported with eVMCS: 0x%llx\n",\ + (u64)unsupported); \ + vmcs_conf->field &= EVMCS1_SUPPORTED_ ## ctrl; \ + } \ + } \ + while (0) + +void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf) +{ + evmcs_check_vmcs_conf(cpu_based_exec_ctrl, EXEC_CTRL); + evmcs_check_vmcs_conf(pin_based_exec_ctrl, PINCTRL); + evmcs_check_vmcs_conf(cpu_based_2nd_exec_ctrl, 2NDEXEC); + evmcs_check_vmcs_conf(cpu_based_3rd_exec_ctrl, 3RDEXEC); + evmcs_check_vmcs_conf(vmentry_ctrl, VMENTRY_CTRL); + evmcs_check_vmcs_conf(vmexit_ctrl, VMEXIT_CTRL); +} diff --git a/arch/x86/kvm/vmx/vmx_onhyperv.h b/arch/x86/kvm/vmx/vmx_onhyperv.h new file mode 100644 index 00000000000000..eb48153bfd73c0 --- /dev/null +++ b/arch/x86/kvm/vmx/vmx_onhyperv.h @@ -0,0 +1,125 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __ARCH_X86_KVM_VMX_ONHYPERV_H__ +#define __ARCH_X86_KVM_VMX_ONHYPERV_H__ + +#include +#include + +#include + +#include "capabilities.h" +#include "hyperv_evmcs.h" +#include "vmcs12.h" + +#define current_evmcs ((struct hv_enlightened_vmcs *)this_cpu_read(current_vmcs)) + +#if IS_ENABLED(CONFIG_HYPERV) + +DECLARE_STATIC_KEY_FALSE(__kvm_is_using_evmcs); + +static __always_inline bool kvm_is_using_evmcs(void) +{ + return static_branch_unlikely(&__kvm_is_using_evmcs); +} + +static __always_inline int get_evmcs_offset(unsigned long field, + u16 *clean_field) +{ + int offset = evmcs_field_offset(field, clean_field); + + WARN_ONCE(offset < 0, "accessing unsupported EVMCS field %lx\n", field); + return offset; +} + +static __always_inline void evmcs_write64(unsigned long field, u64 value) +{ + u16 clean_field; + int offset = get_evmcs_offset(field, &clean_field); + + if (offset < 0) + return; + + *(u64 *)((char *)current_evmcs + offset) = value; + + current_evmcs->hv_clean_fields &= ~clean_field; +} + +static __always_inline void evmcs_write32(unsigned long field, u32 value) +{ + u16 clean_field; + int offset = get_evmcs_offset(field, &clean_field); + + if (offset < 0) + return; + + *(u32 *)((char *)current_evmcs + offset) = value; + current_evmcs->hv_clean_fields &= ~clean_field; +} + +static __always_inline void evmcs_write16(unsigned long field, u16 value) +{ + u16 clean_field; + int offset = get_evmcs_offset(field, &clean_field); + + if (offset < 0) + return; + + *(u16 *)((char *)current_evmcs + offset) = value; + current_evmcs->hv_clean_fields &= ~clean_field; +} + +static __always_inline u64 evmcs_read64(unsigned long field) +{ + int offset = get_evmcs_offset(field, NULL); + + if (offset < 0) + return 0; + + return *(u64 *)((char *)current_evmcs + offset); +} + +static __always_inline u32 evmcs_read32(unsigned long field) +{ + int offset = get_evmcs_offset(field, NULL); + + if (offset < 0) + return 0; + + return *(u32 *)((char *)current_evmcs + offset); +} + +static __always_inline u16 evmcs_read16(unsigned long field) +{ + int offset = get_evmcs_offset(field, NULL); + + if (offset < 0) + return 0; + + return *(u16 *)((char *)current_evmcs + offset); +} + +static inline void evmcs_load(u64 phys_addr) +{ + struct hv_vp_assist_page *vp_ap = + hv_get_vp_assist_page(smp_processor_id()); + + if (current_evmcs->hv_enlightenments_control.nested_flush_hypercall) + vp_ap->nested_control.features.directhypercall = 1; + vp_ap->current_nested_vmcs = phys_addr; + vp_ap->enlighten_vmentry = 1; +} + +void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf); +#else /* !IS_ENABLED(CONFIG_HYPERV) */ +static __always_inline bool kvm_is_using_evmcs(void) { return false; } +static __always_inline void evmcs_write64(unsigned long field, u64 value) {} +static __always_inline void evmcs_write32(unsigned long field, u32 value) {} +static __always_inline void evmcs_write16(unsigned long field, u16 value) {} +static __always_inline u64 evmcs_read64(unsigned long field) { return 0; } +static __always_inline u32 evmcs_read32(unsigned long field) { return 0; } +static __always_inline u16 evmcs_read16(unsigned long field) { return 0; } +static inline void evmcs_load(u64 phys_addr) {} +#endif /* IS_ENABLED(CONFIG_HYPERV) */ + +#endif /* __ARCH_X86_KVM_VMX_ONHYPERV_H__ */ diff --git a/arch/x86/kvm/vmx/vmx_ops.h b/arch/x86/kvm/vmx/vmx_ops.h index 33af7b4c6eb4a6..f41ce3c24123a9 100644 --- a/arch/x86/kvm/vmx/vmx_ops.h +++ b/arch/x86/kvm/vmx/vmx_ops.h @@ -6,7 +6,7 @@ #include -#include "hyperv.h" +#include "vmx_onhyperv.h" #include "vmcs.h" #include "../x86.h" diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 1a3aaa7dafae44..363b1c08020578 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1284,7 +1284,7 @@ int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) * stuff CR3, e.g. for RSM emulation, and there is no guarantee that * the current vCPU mode is accurate. */ - if (kvm_vcpu_is_illegal_gpa(vcpu, cr3)) + if (!kvm_vcpu_is_legal_cr3(vcpu, cr3)) return 1; if (is_pae_paging(vcpu) && !load_pdptrs(vcpu, cr3)) @@ -1504,6 +1504,8 @@ static unsigned num_msrs_to_save; static const u32 emulated_msrs_all[] = { MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK, MSR_KVM_SYSTEM_TIME_NEW, MSR_KVM_WALL_CLOCK_NEW, + +#ifdef CONFIG_KVM_HYPERV HV_X64_MSR_GUEST_OS_ID, HV_X64_MSR_HYPERCALL, HV_X64_MSR_TIME_REF_COUNT, HV_X64_MSR_REFERENCE_TSC, HV_X64_MSR_TSC_FREQUENCY, HV_X64_MSR_APIC_FREQUENCY, @@ -1521,6 +1523,7 @@ static const u32 emulated_msrs_all[] = { HV_X64_MSR_SYNDBG_CONTROL, HV_X64_MSR_SYNDBG_STATUS, HV_X64_MSR_SYNDBG_SEND_BUFFER, HV_X64_MSR_SYNDBG_RECV_BUFFER, HV_X64_MSR_SYNDBG_PENDING_BUFFER, +#endif MSR_KVM_ASYNC_PF_EN, MSR_KVM_STEAL_TIME, MSR_KVM_PV_EOI_EN, MSR_KVM_ASYNC_PF_INT, MSR_KVM_ASYNC_PF_ACK, @@ -2510,26 +2513,29 @@ static inline int gtod_is_based_on_tsc(int mode) } #endif -static void kvm_track_tsc_matching(struct kvm_vcpu *vcpu) +static void kvm_track_tsc_matching(struct kvm_vcpu *vcpu, bool new_generation) { #ifdef CONFIG_X86_64 - bool vcpus_matched; struct kvm_arch *ka = &vcpu->kvm->arch; struct pvclock_gtod_data *gtod = &pvclock_gtod_data; - vcpus_matched = (ka->nr_vcpus_matched_tsc + 1 == - atomic_read(&vcpu->kvm->online_vcpus)); + /* + * To use the masterclock, the host clocksource must be based on TSC + * and all vCPUs must have matching TSCs. Note, the count for matching + * vCPUs doesn't include the reference vCPU, hence "+1". + */ + bool use_master_clock = (ka->nr_vcpus_matched_tsc + 1 == + atomic_read(&vcpu->kvm->online_vcpus)) && + gtod_is_based_on_tsc(gtod->clock.vclock_mode); /* - * Once the masterclock is enabled, always perform request in - * order to update it. - * - * In order to enable masterclock, the host clocksource must be TSC - * and the vcpus need to have matched TSCs. When that happens, - * perform request to enable masterclock. + * Request a masterclock update if the masterclock needs to be toggled + * on/off, or when starting a new generation and the masterclock is + * enabled (compute_guest_tsc() requires the masterclock snapshot to be + * taken _after_ the new generation is created). */ - if (ka->use_master_clock || - (gtod_is_based_on_tsc(gtod->clock.vclock_mode) && vcpus_matched)) + if ((ka->use_master_clock && new_generation) || + (ka->use_master_clock != use_master_clock)) kvm_make_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu); trace_kvm_track_tsc(vcpu->vcpu_id, ka->nr_vcpus_matched_tsc, @@ -2706,7 +2712,7 @@ static void __kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 offset, u64 tsc, vcpu->arch.this_tsc_nsec = kvm->arch.cur_tsc_nsec; vcpu->arch.this_tsc_write = kvm->arch.cur_tsc_write; - kvm_track_tsc_matching(vcpu); + kvm_track_tsc_matching(vcpu, !matched); } static void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *user_value) @@ -3104,7 +3110,8 @@ u64 get_kvmclock_ns(struct kvm *kvm) static void kvm_setup_guest_pvclock(struct kvm_vcpu *v, struct gfn_to_pfn_cache *gpc, - unsigned int offset) + unsigned int offset, + bool force_tsc_unstable) { struct kvm_vcpu_arch *vcpu = &v->arch; struct pvclock_vcpu_time_info *guest_hv_clock; @@ -3141,6 +3148,10 @@ static void kvm_setup_guest_pvclock(struct kvm_vcpu *v, } memcpy(guest_hv_clock, &vcpu->hv_clock, sizeof(*guest_hv_clock)); + + if (force_tsc_unstable) + guest_hv_clock->flags &= ~PVCLOCK_TSC_STABLE_BIT; + smp_wmb(); guest_hv_clock->version = ++vcpu->hv_clock.version; @@ -3161,6 +3172,16 @@ static int kvm_guest_time_update(struct kvm_vcpu *v) u64 tsc_timestamp, host_tsc; u8 pvclock_flags; bool use_master_clock; +#ifdef CONFIG_KVM_XEN + /* + * For Xen guests we may need to override PVCLOCK_TSC_STABLE_BIT as unless + * explicitly told to use TSC as its clocksource Xen will not set this bit. + * This default behaviour led to bugs in some guest kernels which cause + * problems if they observe PVCLOCK_TSC_STABLE_BIT in the pvclock flags. + */ + bool xen_pvclock_tsc_unstable = + ka->xen_hvm_config.flags & KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE; +#endif kernel_ns = 0; host_tsc = 0; @@ -3239,13 +3260,15 @@ static int kvm_guest_time_update(struct kvm_vcpu *v) vcpu->hv_clock.flags = pvclock_flags; if (vcpu->pv_time.active) - kvm_setup_guest_pvclock(v, &vcpu->pv_time, 0); + kvm_setup_guest_pvclock(v, &vcpu->pv_time, 0, false); #ifdef CONFIG_KVM_XEN if (vcpu->xen.vcpu_info_cache.active) kvm_setup_guest_pvclock(v, &vcpu->xen.vcpu_info_cache, - offsetof(struct compat_vcpu_info, time)); + offsetof(struct compat_vcpu_info, time), + xen_pvclock_tsc_unstable); if (vcpu->xen.vcpu_time_info_cache.active) - kvm_setup_guest_pvclock(v, &vcpu->xen.vcpu_time_info_cache, 0); + kvm_setup_guest_pvclock(v, &vcpu->xen.vcpu_time_info_cache, 0, + xen_pvclock_tsc_unstable); #endif kvm_hv_setup_tsc_page(v->kvm, &vcpu->hv_clock); return 0; @@ -4020,6 +4043,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) * the need to ignore the workaround. */ break; +#ifdef CONFIG_KVM_HYPERV case HV_X64_MSR_GUEST_OS_ID ... HV_X64_MSR_SINT15: case HV_X64_MSR_SYNDBG_CONTROL ... HV_X64_MSR_SYNDBG_PENDING_BUFFER: case HV_X64_MSR_SYNDBG_OPTIONS: @@ -4032,6 +4056,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) case HV_X64_MSR_TSC_INVARIANT_CONTROL: return kvm_hv_set_msr_common(vcpu, msr, data, msr_info->host_initiated); +#endif case MSR_IA32_BBL_CR_CTL3: /* Drop writes to this legacy MSR -- see rdmsr * counterpart for further detail. @@ -4377,6 +4402,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) */ msr_info->data = 0x20000000; break; +#ifdef CONFIG_KVM_HYPERV case HV_X64_MSR_GUEST_OS_ID ... HV_X64_MSR_SINT15: case HV_X64_MSR_SYNDBG_CONTROL ... HV_X64_MSR_SYNDBG_PENDING_BUFFER: case HV_X64_MSR_SYNDBG_OPTIONS: @@ -4390,6 +4416,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) return kvm_hv_get_msr_common(vcpu, msr_info->index, &msr_info->data, msr_info->host_initiated); +#endif case MSR_IA32_BBL_CR_CTL3: /* This legacy MSR exists but isn't fully documented in current * silicon. It is however accessed by winxp in very narrow @@ -4527,6 +4554,7 @@ static inline bool kvm_can_mwait_in_guest(void) boot_cpu_has(X86_FEATURE_ARAT); } +#ifdef CONFIG_KVM_HYPERV static int kvm_ioctl_get_supported_hv_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 __user *cpuid_arg) { @@ -4547,6 +4575,14 @@ static int kvm_ioctl_get_supported_hv_cpuid(struct kvm_vcpu *vcpu, return 0; } +#endif + +static bool kvm_is_vm_type_supported(unsigned long type) +{ + return type == KVM_X86_DEFAULT_VM || + (type == KVM_X86_SW_PROTECTED_VM && + IS_ENABLED(CONFIG_KVM_SW_PROTECTED_VM) && tdp_enabled); +} int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) { @@ -4573,9 +4609,11 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_PIT_STATE2: case KVM_CAP_SET_IDENTITY_MAP_ADDR: case KVM_CAP_VCPU_EVENTS: +#ifdef CONFIG_KVM_HYPERV case KVM_CAP_HYPERV: case KVM_CAP_HYPERV_VAPIC: case KVM_CAP_HYPERV_SPIN: + case KVM_CAP_HYPERV_TIME: case KVM_CAP_HYPERV_SYNIC: case KVM_CAP_HYPERV_SYNIC2: case KVM_CAP_HYPERV_VP_INDEX: @@ -4585,6 +4623,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_HYPERV_CPUID: case KVM_CAP_HYPERV_ENFORCE_CPUID: case KVM_CAP_SYS_HYPERV_CPUID: +#endif case KVM_CAP_PCI_SEGMENT: case KVM_CAP_DEBUGREGS: case KVM_CAP_X86_ROBUST_SINGLESTEP: @@ -4594,7 +4633,6 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_GET_TSC_KHZ: case KVM_CAP_KVMCLOCK_CTRL: case KVM_CAP_READONLY_MEM: - case KVM_CAP_HYPERV_TIME: case KVM_CAP_IOAPIC_POLARITY_IGNORED: case KVM_CAP_TSC_DEADLINE_TIMER: case KVM_CAP_DISABLE_QUIRKS: @@ -4625,6 +4663,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_ENABLE_CAP: case KVM_CAP_VM_DISABLE_NX_HUGE_PAGES: case KVM_CAP_IRQFD_RESAMPLE: + case KVM_CAP_MEMORY_FAULT_INFO: r = 1; break; case KVM_CAP_EXIT_HYPERCALL: @@ -4638,7 +4677,8 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL | KVM_XEN_HVM_CONFIG_SHARED_INFO | KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL | - KVM_XEN_HVM_CONFIG_EVTCHN_SEND; + KVM_XEN_HVM_CONFIG_EVTCHN_SEND | + KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE; if (sched_info_on()) r |= KVM_XEN_HVM_CONFIG_RUNSTATE | KVM_XEN_HVM_CONFIG_RUNSTATE_UPDATE_FLAG; @@ -4704,12 +4744,14 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) r = kvm_x86_ops.nested_ops->get_state ? kvm_x86_ops.nested_ops->get_state(NULL, NULL, 0) : 0; break; +#ifdef CONFIG_KVM_HYPERV case KVM_CAP_HYPERV_DIRECT_TLBFLUSH: r = kvm_x86_ops.enable_l2_tlb_flush != NULL; break; case KVM_CAP_HYPERV_ENLIGHTENED_VMCS: r = kvm_x86_ops.nested_ops->enable_evmcs != NULL; break; +#endif case KVM_CAP_SMALLER_MAXPHYADDR: r = (int) allow_smaller_maxphyaddr; break; @@ -4738,6 +4780,11 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_X86_NOTIFY_VMEXIT: r = kvm_caps.has_notify_vmexit; break; + case KVM_CAP_VM_TYPES: + r = BIT(KVM_X86_DEFAULT_VM); + if (kvm_is_vm_type_supported(KVM_X86_SW_PROTECTED_VM)) + r |= BIT(KVM_X86_SW_PROTECTED_VM); + break; default: break; } @@ -4871,9 +4918,11 @@ long kvm_arch_dev_ioctl(struct file *filp, case KVM_GET_MSRS: r = msr_io(NULL, argp, do_get_msr_feature, 1); break; +#ifdef CONFIG_KVM_HYPERV case KVM_GET_SUPPORTED_HV_CPUID: r = kvm_ioctl_get_supported_hv_cpuid(NULL, argp); break; +#endif case KVM_GET_DEVICE_ATTR: { struct kvm_device_attr attr; r = -EFAULT; @@ -5699,14 +5748,11 @@ static int kvm_vcpu_ioctl_device_attr(struct kvm_vcpu *vcpu, static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, struct kvm_enable_cap *cap) { - int r; - uint16_t vmcs_version; - void __user *user_ptr; - if (cap->flags) return -EINVAL; switch (cap->cap) { +#ifdef CONFIG_KVM_HYPERV case KVM_CAP_HYPERV_SYNIC2: if (cap->args[0]) return -EINVAL; @@ -5718,16 +5764,22 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, return kvm_hv_activate_synic(vcpu, cap->cap == KVM_CAP_HYPERV_SYNIC2); case KVM_CAP_HYPERV_ENLIGHTENED_VMCS: - if (!kvm_x86_ops.nested_ops->enable_evmcs) - return -ENOTTY; - r = kvm_x86_ops.nested_ops->enable_evmcs(vcpu, &vmcs_version); - if (!r) { - user_ptr = (void __user *)(uintptr_t)cap->args[0]; - if (copy_to_user(user_ptr, &vmcs_version, - sizeof(vmcs_version))) - r = -EFAULT; + { + int r; + uint16_t vmcs_version; + void __user *user_ptr; + + if (!kvm_x86_ops.nested_ops->enable_evmcs) + return -ENOTTY; + r = kvm_x86_ops.nested_ops->enable_evmcs(vcpu, &vmcs_version); + if (!r) { + user_ptr = (void __user *)(uintptr_t)cap->args[0]; + if (copy_to_user(user_ptr, &vmcs_version, + sizeof(vmcs_version))) + r = -EFAULT; + } + return r; } - return r; case KVM_CAP_HYPERV_DIRECT_TLBFLUSH: if (!kvm_x86_ops.enable_l2_tlb_flush) return -ENOTTY; @@ -5736,6 +5788,7 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, case KVM_CAP_HYPERV_ENFORCE_CPUID: return kvm_hv_set_enforce_cpuid(vcpu, cap->args[0]); +#endif case KVM_CAP_ENFORCE_PV_FEATURE_CPUID: vcpu->arch.pv_cpuid.enforce = cap->args[0]; @@ -6128,9 +6181,11 @@ long kvm_arch_vcpu_ioctl(struct file *filp, srcu_read_unlock(&vcpu->kvm->srcu, idx); break; } +#ifdef CONFIG_KVM_HYPERV case KVM_GET_SUPPORTED_HV_CPUID: r = kvm_ioctl_get_supported_hv_cpuid(vcpu, argp); break; +#endif #ifdef CONFIG_KVM_XEN case KVM_XEN_VCPU_GET_ATTR: { struct kvm_xen_vcpu_attr xva; @@ -7188,6 +7243,7 @@ set_pit2_out: r = static_call(kvm_x86_mem_enc_unregister_region)(kvm, ®ion); break; } +#ifdef CONFIG_KVM_HYPERV case KVM_HYPERV_EVENTFD: { struct kvm_hyperv_eventfd hvevfd; @@ -7197,6 +7253,7 @@ set_pit2_out: r = kvm_vm_ioctl_hv_eventfd(kvm, &hvevfd); break; } +#endif case KVM_SET_PMU_EVENT_FILTER: r = kvm_vm_ioctl_set_pmu_event_filter(kvm, argp); break; @@ -8432,6 +8489,15 @@ static void emulator_vm_bugged(struct x86_emulate_ctxt *ctxt) kvm_vm_bugged(kvm); } +static gva_t emulator_get_untagged_addr(struct x86_emulate_ctxt *ctxt, + gva_t addr, unsigned int flags) +{ + if (!kvm_x86_ops.get_untagged_addr) + return addr; + + return static_call(kvm_x86_get_untagged_addr)(emul_to_vcpu(ctxt), addr, flags); +} + static const struct x86_emulate_ops emulate_ops = { .vm_bugged = emulator_vm_bugged, .read_gpr = emulator_read_gpr, @@ -8476,6 +8542,7 @@ static const struct x86_emulate_ops emulate_ops = { .leave_smm = emulator_leave_smm, .triple_fault = emulator_triple_fault, .set_xcr = emulator_set_xcr, + .get_untagged_addr = emulator_get_untagged_addr, }; static void toggle_interruptibility(struct kvm_vcpu *vcpu, u32 mask) @@ -10165,7 +10232,7 @@ static void kvm_inject_exception(struct kvm_vcpu *vcpu) * * But, if a VM-Exit occurs during instruction execution, and KVM does NOT skip * the instruction or inject an exception, then KVM can incorrecty inject a new - * asynchrounous event if the event became pending after the CPU fetched the + * asynchronous event if the event became pending after the CPU fetched the * instruction (in the guest). E.g. if a page fault (#PF, #NPF, EPT violation) * occurs and is resolved by KVM, a coincident NMI, SMI, IRQ, etc... can be * injected on the restarted instruction instead of being deferred until the @@ -10186,7 +10253,7 @@ static int kvm_check_and_inject_events(struct kvm_vcpu *vcpu, int r; /* - * Process nested events first, as nested VM-Exit supercedes event + * Process nested events first, as nested VM-Exit supersedes event * re-injection. If there's an event queued for re-injection, it will * be saved into the appropriate vmc{b,s}12 fields on nested VM-Exit. */ @@ -10575,19 +10642,20 @@ static void vcpu_scan_ioapic(struct kvm_vcpu *vcpu) static void vcpu_load_eoi_exitmap(struct kvm_vcpu *vcpu) { - u64 eoi_exit_bitmap[4]; - if (!kvm_apic_hw_enabled(vcpu->arch.apic)) return; +#ifdef CONFIG_KVM_HYPERV if (to_hv_vcpu(vcpu)) { + u64 eoi_exit_bitmap[4]; + bitmap_or((ulong *)eoi_exit_bitmap, vcpu->arch.ioapic_handled_vectors, to_hv_synic(vcpu)->vec_bitmap, 256); static_call_cond(kvm_x86_load_eoi_exitmap)(vcpu, eoi_exit_bitmap); return; } - +#endif static_call_cond(kvm_x86_load_eoi_exitmap)( vcpu, (u64 *)vcpu->arch.ioapic_handled_vectors); } @@ -10678,9 +10746,11 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) * the flushes are considered "remote" and not "local" because * the requests can be initiated from other vCPUs. */ +#ifdef CONFIG_KVM_HYPERV if (kvm_check_request(KVM_REQ_HV_TLB_FLUSH, vcpu) && kvm_hv_vcpu_flush_tlb(vcpu)) kvm_vcpu_flush_tlb_guest(vcpu); +#endif if (kvm_check_request(KVM_REQ_REPORT_TPR_ACCESS, vcpu)) { vcpu->run->exit_reason = KVM_EXIT_TPR_ACCESS; @@ -10733,6 +10803,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) vcpu_load_eoi_exitmap(vcpu); if (kvm_check_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu)) kvm_vcpu_reload_apic_access_page(vcpu); +#ifdef CONFIG_KVM_HYPERV if (kvm_check_request(KVM_REQ_HV_CRASH, vcpu)) { vcpu->run->exit_reason = KVM_EXIT_SYSTEM_EVENT; vcpu->run->system_event.type = KVM_SYSTEM_EVENT_CRASH; @@ -10763,6 +10834,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) */ if (kvm_check_request(KVM_REQ_HV_STIMER, vcpu)) kvm_hv_process_stimers(vcpu); +#endif if (kvm_check_request(KVM_REQ_APICV_UPDATE, vcpu)) kvm_vcpu_update_apicv(vcpu); if (kvm_check_request(KVM_REQ_APF_READY, vcpu)) @@ -10884,7 +10956,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) /* * Assert that vCPU vs. VM APICv state is consistent. An APICv * update must kick and wait for all vCPUs before toggling the - * per-VM state, and responsing vCPUs must wait for the update + * per-VM state, and responding vCPUs must wait for the update * to complete before servicing KVM_REQ_APICV_UPDATE. */ WARN_ON_ONCE((kvm_vcpu_apicv_activated(vcpu) != kvm_vcpu_apicv_active(vcpu)) && @@ -11081,6 +11153,7 @@ static int vcpu_run(struct kvm_vcpu *vcpu) { int r; + vcpu->run->exit_reason = KVM_EXIT_UNKNOWN; vcpu->arch.l1tf_flush_l1d = true; for (;;) { @@ -11598,7 +11671,7 @@ static bool kvm_is_valid_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) */ if (!(sregs->cr4 & X86_CR4_PAE) || !(sregs->efer & EFER_LMA)) return false; - if (kvm_vcpu_is_illegal_gpa(vcpu, sregs->cr3)) + if (!kvm_vcpu_is_legal_cr3(vcpu, sregs->cr3)) return false; } else { /* @@ -12207,7 +12280,6 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) } if (!init_event) { - kvm_pmu_reset(vcpu); vcpu->arch.smbase = 0x30000; vcpu->arch.msr_misc_features_enables = 0; @@ -12424,7 +12496,9 @@ void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) void kvm_arch_free_vm(struct kvm *kvm) { - kfree(to_kvm_hv(kvm)->hv_pa_pg); +#if IS_ENABLED(CONFIG_HYPERV) + kfree(kvm->arch.hv_pa_pg); +#endif __kvm_arch_free_vm(kvm); } @@ -12434,9 +12508,11 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) int ret; unsigned long flags; - if (type) + if (!kvm_is_vm_type_supported(type)) return -EINVAL; + kvm->arch.vm_type = type; + ret = kvm_page_track_init(kvm); if (ret) goto out; @@ -12575,8 +12651,8 @@ void __user * __x86_set_memory_region(struct kvm *kvm, int id, gpa_t gpa, hva = slot->userspace_addr; } - for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++) { - struct kvm_userspace_memory_region m; + for (i = 0; i < kvm_arch_nr_memslot_as_ids(kvm); i++) { + struct kvm_userspace_memory_region2 m; m.slot = id | (i << 16); m.flags = 0; @@ -12726,6 +12802,10 @@ static int kvm_alloc_memslot_metadata(struct kvm *kvm, } } +#ifdef CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES + kvm_mmu_init_memslot_memory_attributes(kvm, slot); +#endif + if (kvm_page_track_create_memslot(kvm, slot, npages)) goto out_free; @@ -13536,6 +13616,10 @@ int kvm_handle_invpcid(struct kvm_vcpu *vcpu, unsigned long type, gva_t gva) switch (type) { case INVPCID_TYPE_INDIV_ADDR: + /* + * LAM doesn't apply to addresses that are inputs to TLB + * invalidation. + */ if ((!pcid_enabled && (operand.pcid != 0)) || is_noncanonical_address(operand.gla, vcpu)) { kvm_inject_gp(vcpu, 0); diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index 5184fde1dc541a..2f7e1916665800 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -530,6 +530,8 @@ bool kvm_msr_allowed(struct kvm_vcpu *vcpu, u32 index, u32 type); __reserved_bits |= X86_CR4_VMXE; \ if (!__cpu_has(__c, X86_FEATURE_PCID)) \ __reserved_bits |= X86_CR4_PCIDE; \ + if (!__cpu_has(__c, X86_FEATURE_LAM)) \ + __reserved_bits |= X86_CR4_LAM_SUP; \ __reserved_bits; \ }) diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c index e53fad915a6264..4b4e738c6f1b79 100644 --- a/arch/x86/kvm/xen.c +++ b/arch/x86/kvm/xen.c @@ -1162,7 +1162,9 @@ int kvm_xen_hvm_config(struct kvm *kvm, struct kvm_xen_hvm_config *xhc) { /* Only some feature flags need to be *enabled* by userspace */ u32 permitted_flags = KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL | - KVM_XEN_HVM_CONFIG_EVTCHN_SEND; + KVM_XEN_HVM_CONFIG_EVTCHN_SEND | + KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE; + u32 old_flags; if (xhc->flags & ~permitted_flags) return -EINVAL; @@ -1183,9 +1185,14 @@ int kvm_xen_hvm_config(struct kvm *kvm, struct kvm_xen_hvm_config *xhc) else if (!xhc->msr && kvm->arch.xen_hvm_config.msr) static_branch_slow_dec_deferred(&kvm_xen_enabled); + old_flags = kvm->arch.xen_hvm_config.flags; memcpy(&kvm->arch.xen_hvm_config, xhc, sizeof(*xhc)); mutex_unlock(&kvm->arch.xen.xen_lock); + + if ((old_flags ^ xhc->flags) & KVM_XEN_HVM_CONFIG_PVCLOCK_TSC_UNSTABLE) + kvm_make_all_cpus_request(kvm, KVM_REQ_CLOCK_UPDATE); + return 0; } @@ -2088,7 +2095,7 @@ static bool kvm_xen_hcall_evtchn_send(struct kvm_vcpu *vcpu, u64 param, u64 *r) if (ret < 0 && ret != -ENOTCONN) return false; } else { - eventfd_signal(evtchnfd->deliver.eventfd.ctx, 1); + eventfd_signal(evtchnfd->deliver.eventfd.ctx); } *r = 0; diff --git a/arch/x86/lib/cache-smp.c b/arch/x86/lib/cache-smp.c index 7c48ff4ae8d196..7af743bd3b1309 100644 --- a/arch/x86/lib/cache-smp.c +++ b/arch/x86/lib/cache-smp.c @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 +#include #include #include diff --git a/arch/x86/lib/delay.c b/arch/x86/lib/delay.c index 0e65d00e2339ff..23f81ca3f06b41 100644 --- a/arch/x86/lib/delay.c +++ b/arch/x86/lib/delay.c @@ -128,7 +128,7 @@ static void delay_halt_mwaitx(u64 unused, u64 cycles) delay = min_t(u64, MWAITX_MAX_WAIT_CYCLES, cycles); /* - * Use cpu_tss_rw as a cacheline-aligned, seldomly accessed per-cpu + * Use cpu_tss_rw as a cacheline-aligned, seldom accessed per-cpu * variable as the monitor target. */ __monitorx(raw_cpu_ptr(&cpu_tss_rw), 0, 0); diff --git a/arch/x86/lib/misc.c b/arch/x86/lib/misc.c index 92cd8ecc3a2c8c..40b81c338ae5b9 100644 --- a/arch/x86/lib/misc.c +++ b/arch/x86/lib/misc.c @@ -8,7 +8,7 @@ */ int num_digits(int val) { - int m = 10; + long long m = 10; int d = 1; if (val < 0) { diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index a190aae8ceaf70..a0dffaca6d2bfc 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -1013,7 +1013,7 @@ static void __meminit free_pte_table(pte_t *pte_start, pmd_t *pmd) return; } - /* free a pte talbe */ + /* free a pte table */ free_pagetable(pmd_page(*pmd), 0); spin_lock(&init_mm.page_table_lock); pmd_clear(pmd); @@ -1031,7 +1031,7 @@ static void __meminit free_pmd_table(pmd_t *pmd_start, pud_t *pud) return; } - /* free a pmd talbe */ + /* free a pmd table */ free_pagetable(pud_page(*pud), 0); spin_lock(&init_mm.page_table_lock); pud_clear(pud); @@ -1049,7 +1049,7 @@ static void __meminit free_pud_table(pud_t *pud_start, p4d_t *p4d) return; } - /* free a pud talbe */ + /* free a pud table */ free_pagetable(p4d_page(*p4d), 0); spin_lock(&init_mm.page_table_lock); p4d_clear(p4d); diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c index b29ceb19e46ec3..adc497b93f0374 100644 --- a/arch/x86/mm/numa.c +++ b/arch/x86/mm/numa.c @@ -449,37 +449,6 @@ int __node_distance(int from, int to) } EXPORT_SYMBOL(__node_distance); -/* - * Sanity check to catch more bad NUMA configurations (they are amazingly - * common). Make sure the nodes cover all memory. - */ -static bool __init numa_meminfo_cover_memory(const struct numa_meminfo *mi) -{ - u64 numaram, e820ram; - int i; - - numaram = 0; - for (i = 0; i < mi->nr_blks; i++) { - u64 s = mi->blk[i].start >> PAGE_SHIFT; - u64 e = mi->blk[i].end >> PAGE_SHIFT; - numaram += e - s; - numaram -= __absent_pages_in_range(mi->blk[i].nid, s, e); - if ((s64)numaram < 0) - numaram = 0; - } - - e820ram = max_pfn - absent_pages_in_range(0, max_pfn); - - /* We seem to lose 3 pages somewhere. Allow 1M of slack. */ - if ((s64)(e820ram - numaram) >= (1 << (20 - PAGE_SHIFT))) { - printk(KERN_ERR "NUMA: nodes only cover %LuMB of your %LuMB e820 RAM. Not used.\n", - (numaram << PAGE_SHIFT) >> 20, - (e820ram << PAGE_SHIFT) >> 20); - return false; - } - return true; -} - /* * Mark all currently memblock-reserved physical memory (which covers the * kernel's own memory ranges) as hot-unswappable. @@ -585,7 +554,8 @@ static int __init numa_register_memblks(struct numa_meminfo *mi) return -EINVAL; } } - if (!numa_meminfo_cover_memory(mi)) + + if (!memblock_validate_numa_coverage(SZ_1M)) return -EINVAL; /* Finally register nodes. */ diff --git a/arch/x86/mm/pat/memtype.c b/arch/x86/mm/pat/memtype.c index de10800cd4dd48..0904d7e8e12608 100644 --- a/arch/x86/mm/pat/memtype.c +++ b/arch/x86/mm/pat/memtype.c @@ -14,7 +14,7 @@ * memory ranges: uncached, write-combining, write-through, write-protected, * and the most commonly used and default attribute: write-back caching. * - * PAT support supercedes and augments MTRR support in a compatible fashion: MTRR is + * PAT support supersedes and augments MTRR support in a compatible fashion: MTRR is * a hardware interface to enumerate a limited number of physical memory ranges * and set their caching attributes explicitly, programmed into the CPU via MSRs. * Even modern CPUs have MTRRs enabled - but these are typically not touched diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c index bda9f129835e95..e9b448d1b1b70f 100644 --- a/arch/x86/mm/pat/set_memory.c +++ b/arch/x86/mm/pat/set_memory.c @@ -1621,7 +1621,7 @@ repeat: /* * We need to keep the pfn from the existing PTE, - * after all we're only going to change it's attributes + * after all we're only going to change its attributes * not the memory it points to */ new_pte = pfn_pte(pfn, new_prot); @@ -2447,7 +2447,7 @@ int __init kernel_unmap_pages_in_pgd(pgd_t *pgd, unsigned long address, /* * The typical sequence for unmapping is to find a pte through * lookup_address_in_pgd() (ideally, it should never return NULL because - * the address is already mapped) and change it's protections. As pfn is + * the address is already mapped) and change its protections. As pfn is * the *target* of a mapping, it's not useful while unmapping. */ struct cpa_data cpa = { diff --git a/arch/x86/mm/pti.c b/arch/x86/mm/pti.c index 5dd733944629fa..669ba1c345b389 100644 --- a/arch/x86/mm/pti.c +++ b/arch/x86/mm/pti.c @@ -6,7 +6,7 @@ * * https://github.com/IAIK/KAISER * - * The original work was written by and and signed off by for the Linux + * The original work was written by and signed off by for the Linux * kernel by: * * Signed-off-by: Richard Fellner diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c index 453ea95b667dad..5768d386efab6e 100644 --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c @@ -355,7 +355,7 @@ static void l1d_flush_evaluate(unsigned long prev_mm, unsigned long next_mm, /* * Validate that it is not running on an SMT sibling as this would - * make the excercise pointless because the siblings share L1D. If + * make the exercise pointless because the siblings share L1D. If * it runs on a SMT sibling, notify it with SIGBUS on return to * user/guest */ diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index e89e415aa74353..919f647c740fb5 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -17,6 +17,7 @@ #include #include #include +#include static bool all_callee_regs_used[4] = {true, true, true, true}; @@ -51,9 +52,11 @@ static u8 *emit_code(u8 *ptr, u32 bytes, unsigned int len) do { EMIT4(b1, b2, b3, b4); EMIT(off, 4); } while (0) #ifdef CONFIG_X86_KERNEL_IBT -#define EMIT_ENDBR() EMIT(gen_endbr(), 4) +#define EMIT_ENDBR() EMIT(gen_endbr(), 4) +#define EMIT_ENDBR_POISON() EMIT(gen_endbr_poison(), 4) #else #define EMIT_ENDBR() +#define EMIT_ENDBR_POISON() #endif static bool is_imm8(int value) @@ -304,6 +307,88 @@ static void pop_callee_regs(u8 **pprog, bool *callee_regs_used) *pprog = prog; } +static void emit_nops(u8 **pprog, int len) +{ + u8 *prog = *pprog; + int i, noplen; + + while (len > 0) { + noplen = len; + + if (noplen > ASM_NOP_MAX) + noplen = ASM_NOP_MAX; + + for (i = 0; i < noplen; i++) + EMIT1(x86_nops[noplen][i]); + len -= noplen; + } + + *pprog = prog; +} + +/* + * Emit the various CFI preambles, see asm/cfi.h and the comments about FineIBT + * in arch/x86/kernel/alternative.c + */ + +static void emit_fineibt(u8 **pprog, u32 hash) +{ + u8 *prog = *pprog; + + EMIT_ENDBR(); + EMIT3_off32(0x41, 0x81, 0xea, hash); /* subl $hash, %r10d */ + EMIT2(0x74, 0x07); /* jz.d8 +7 */ + EMIT2(0x0f, 0x0b); /* ud2 */ + EMIT1(0x90); /* nop */ + EMIT_ENDBR_POISON(); + + *pprog = prog; +} + +static void emit_kcfi(u8 **pprog, u32 hash) +{ + u8 *prog = *pprog; + + EMIT1_off32(0xb8, hash); /* movl $hash, %eax */ +#ifdef CONFIG_CALL_PADDING + EMIT1(0x90); + EMIT1(0x90); + EMIT1(0x90); + EMIT1(0x90); + EMIT1(0x90); + EMIT1(0x90); + EMIT1(0x90); + EMIT1(0x90); + EMIT1(0x90); + EMIT1(0x90); + EMIT1(0x90); +#endif + EMIT_ENDBR(); + + *pprog = prog; +} + +static void emit_cfi(u8 **pprog, u32 hash) +{ + u8 *prog = *pprog; + + switch (cfi_mode) { + case CFI_FINEIBT: + emit_fineibt(&prog, hash); + break; + + case CFI_KCFI: + emit_kcfi(&prog, hash); + break; + + default: + EMIT_ENDBR(); + break; + } + + *pprog = prog; +} + /* * Emit x86-64 prologue code for BPF program. * bpf_tail_call helper will skip the first X86_TAIL_CALL_OFFSET bytes @@ -315,12 +400,11 @@ static void emit_prologue(u8 **pprog, u32 stack_depth, bool ebpf_from_cbpf, { u8 *prog = *pprog; + emit_cfi(&prog, is_subprog ? cfi_bpf_subprog_hash : cfi_bpf_hash); /* BPF trampoline can be made to work without these nops, * but let's waste 5 bytes for now and optimize later */ - EMIT_ENDBR(); - memcpy(prog, x86_nops[5], X86_PATCH_SIZE); - prog += X86_PATCH_SIZE; + emit_nops(&prog, X86_PATCH_SIZE); if (!ebpf_from_cbpf) { if (tail_call_reachable && !is_subprog) /* When it's the entry of the whole tailcall context, @@ -626,8 +710,7 @@ static void emit_bpf_tail_call_direct(struct bpf_prog *bpf_prog, if (stack_depth) EMIT3_off32(0x48, 0x81, 0xC4, round_up(stack_depth, 8)); - memcpy(prog, x86_nops[5], X86_PATCH_SIZE); - prog += X86_PATCH_SIZE; + emit_nops(&prog, X86_PATCH_SIZE); /* out: */ ctx->tail_call_direct_label = prog - start; @@ -989,25 +1072,6 @@ static void detect_reg_usage(struct bpf_insn *insn, int insn_cnt, } } -static void emit_nops(u8 **pprog, int len) -{ - u8 *prog = *pprog; - int i, noplen; - - while (len > 0) { - noplen = len; - - if (noplen > ASM_NOP_MAX) - noplen = ASM_NOP_MAX; - - for (i = 0; i < noplen; i++) - EMIT1(x86_nops[noplen][i]); - len -= noplen; - } - - *pprog = prog; -} - /* emit the 3-byte VEX prefix * * r: same as rex.r, extra bit for ModRM reg field @@ -2143,7 +2207,7 @@ static void save_args(const struct btf_func_model *m, u8 **prog, } else { /* Only copy the arguments on-stack to current * 'stack_size' and ignore the regs, used to - * prepare the arguments on-stack for orign call. + * prepare the arguments on-stack for origin call. */ if (for_call_origin) { nr_regs += arg_regs; @@ -2198,7 +2262,8 @@ static void restore_regs(const struct btf_func_model *m, u8 **prog, static int invoke_bpf_prog(const struct btf_func_model *m, u8 **pprog, struct bpf_tramp_link *l, int stack_size, - int run_ctx_off, bool save_ret) + int run_ctx_off, bool save_ret, + void *image, void *rw_image) { u8 *prog = *pprog; u8 *jmp_insn; @@ -2226,7 +2291,7 @@ static int invoke_bpf_prog(const struct btf_func_model *m, u8 **pprog, else EMIT4(0x48, 0x8D, 0x75, -run_ctx_off); - if (emit_rsb_call(&prog, bpf_trampoline_enter(p), prog)) + if (emit_rsb_call(&prog, bpf_trampoline_enter(p), image + (prog - (u8 *)rw_image))) return -EINVAL; /* remember prog start time returned by __bpf_prog_enter */ emit_mov_reg(&prog, true, BPF_REG_6, BPF_REG_0); @@ -2250,7 +2315,7 @@ static int invoke_bpf_prog(const struct btf_func_model *m, u8 **pprog, (long) p->insnsi >> 32, (u32) (long) p->insnsi); /* call JITed bpf program or interpreter */ - if (emit_rsb_call(&prog, p->bpf_func, prog)) + if (emit_rsb_call(&prog, p->bpf_func, image + (prog - (u8 *)rw_image))) return -EINVAL; /* @@ -2277,7 +2342,7 @@ static int invoke_bpf_prog(const struct btf_func_model *m, u8 **pprog, EMIT3_off32(0x48, 0x8D, 0x95, -run_ctx_off); else EMIT4(0x48, 0x8D, 0x55, -run_ctx_off); - if (emit_rsb_call(&prog, bpf_trampoline_exit(p), prog)) + if (emit_rsb_call(&prog, bpf_trampoline_exit(p), image + (prog - (u8 *)rw_image))) return -EINVAL; *pprog = prog; @@ -2312,14 +2377,15 @@ static int emit_cond_near_jump(u8 **pprog, void *func, void *ip, u8 jmp_cond) static int invoke_bpf(const struct btf_func_model *m, u8 **pprog, struct bpf_tramp_links *tl, int stack_size, - int run_ctx_off, bool save_ret) + int run_ctx_off, bool save_ret, + void *image, void *rw_image) { int i; u8 *prog = *pprog; for (i = 0; i < tl->nr_links; i++) { if (invoke_bpf_prog(m, &prog, tl->links[i], stack_size, - run_ctx_off, save_ret)) + run_ctx_off, save_ret, image, rw_image)) return -EINVAL; } *pprog = prog; @@ -2328,7 +2394,8 @@ static int invoke_bpf(const struct btf_func_model *m, u8 **pprog, static int invoke_bpf_mod_ret(const struct btf_func_model *m, u8 **pprog, struct bpf_tramp_links *tl, int stack_size, - int run_ctx_off, u8 **branches) + int run_ctx_off, u8 **branches, + void *image, void *rw_image) { u8 *prog = *pprog; int i; @@ -2339,7 +2406,8 @@ static int invoke_bpf_mod_ret(const struct btf_func_model *m, u8 **pprog, emit_mov_imm32(&prog, false, BPF_REG_0, 0); emit_stx(&prog, BPF_DW, BPF_REG_FP, BPF_REG_0, -8); for (i = 0; i < tl->nr_links; i++) { - if (invoke_bpf_prog(m, &prog, tl->links[i], stack_size, run_ctx_off, true)) + if (invoke_bpf_prog(m, &prog, tl->links[i], stack_size, run_ctx_off, true, + image, rw_image)) return -EINVAL; /* mod_ret prog stored return value into [rbp - 8]. Emit: @@ -2422,10 +2490,11 @@ static int invoke_bpf_mod_ret(const struct btf_func_model *m, u8 **pprog, * add rsp, 8 // skip eth_type_trans's frame * ret // return to its caller */ -int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *image_end, - const struct btf_func_model *m, u32 flags, - struct bpf_tramp_links *tlinks, - void *func_addr) +static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_image, + void *rw_image_end, void *image, + const struct btf_func_model *m, u32 flags, + struct bpf_tramp_links *tlinks, + void *func_addr) { int i, ret, nr_regs = m->nr_args, stack_size = 0; int regs_off, nregs_off, ip_off, run_ctx_off, arg_stack_off, rbx_off; @@ -2437,10 +2506,19 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i u8 *prog; bool save_ret; + /* + * F_INDIRECT is only compatible with F_RET_FENTRY_RET, it is + * explicitly incompatible with F_CALL_ORIG | F_SKIP_FRAME | F_IP_ARG + * because @func_addr. + */ + WARN_ON_ONCE((flags & BPF_TRAMP_F_INDIRECT) && + (flags & ~(BPF_TRAMP_F_INDIRECT | BPF_TRAMP_F_RET_FENTRY_RET))); + /* extra registers for struct arguments */ - for (i = 0; i < m->nr_args; i++) + for (i = 0; i < m->nr_args; i++) { if (m->arg_flags[i] & BTF_FMODEL_STRUCT_ARG) nr_regs += (m->arg_size[i] + 7) / 8 - 1; + } /* x86-64 supports up to MAX_BPF_FUNC_ARGS arguments. 1-6 * are passed through regs, the remains are through stack. @@ -2521,22 +2599,29 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i orig_call += X86_PATCH_SIZE; } - prog = image; + prog = rw_image; - EMIT_ENDBR(); - /* - * This is the direct-call trampoline, as such it needs accounting - * for the __fentry__ call. - */ - x86_call_depth_emit_accounting(&prog, NULL); + if (flags & BPF_TRAMP_F_INDIRECT) { + /* + * Indirect call for bpf_struct_ops + */ + emit_cfi(&prog, cfi_get_func_hash(func_addr)); + } else { + /* + * Direct-call fentry stub, as such it needs accounting for the + * __fentry__ call. + */ + x86_call_depth_emit_accounting(&prog, NULL); + } EMIT1(0x55); /* push rbp */ EMIT3(0x48, 0x89, 0xE5); /* mov rbp, rsp */ - if (!is_imm8(stack_size)) + if (!is_imm8(stack_size)) { /* sub rsp, stack_size */ EMIT3_off32(0x48, 0x81, 0xEC, stack_size); - else + } else { /* sub rsp, stack_size */ EMIT4(0x48, 0x83, 0xEC, stack_size); + } if (flags & BPF_TRAMP_F_TAIL_CALL_CTX) EMIT1(0x50); /* push rax */ /* mov QWORD PTR [rbp - rbx_off], rbx */ @@ -2563,16 +2648,18 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i if (flags & BPF_TRAMP_F_CALL_ORIG) { /* arg1: mov rdi, im */ emit_mov_imm64(&prog, BPF_REG_1, (long) im >> 32, (u32) (long) im); - if (emit_rsb_call(&prog, __bpf_tramp_enter, prog)) { + if (emit_rsb_call(&prog, __bpf_tramp_enter, + image + (prog - (u8 *)rw_image))) { ret = -EINVAL; goto cleanup; } } - if (fentry->nr_links) + if (fentry->nr_links) { if (invoke_bpf(m, &prog, fentry, regs_off, run_ctx_off, - flags & BPF_TRAMP_F_RET_FENTRY_RET)) + flags & BPF_TRAMP_F_RET_FENTRY_RET, image, rw_image)) return -EINVAL; + } if (fmod_ret->nr_links) { branches = kcalloc(fmod_ret->nr_links, sizeof(u8 *), @@ -2581,7 +2668,7 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i return -ENOMEM; if (invoke_bpf_mod_ret(m, &prog, fmod_ret, regs_off, - run_ctx_off, branches)) { + run_ctx_off, branches, image, rw_image)) { ret = -EINVAL; goto cleanup; } @@ -2591,27 +2678,27 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i restore_regs(m, &prog, regs_off); save_args(m, &prog, arg_stack_off, true); - if (flags & BPF_TRAMP_F_TAIL_CALL_CTX) + if (flags & BPF_TRAMP_F_TAIL_CALL_CTX) { /* Before calling the original function, restore the * tail_call_cnt from stack to rax. */ RESTORE_TAIL_CALL_CNT(stack_size); + } if (flags & BPF_TRAMP_F_ORIG_STACK) { emit_ldx(&prog, BPF_DW, BPF_REG_6, BPF_REG_FP, 8); EMIT2(0xff, 0xd3); /* call *rbx */ } else { /* call original function */ - if (emit_rsb_call(&prog, orig_call, prog)) { + if (emit_rsb_call(&prog, orig_call, image + (prog - (u8 *)rw_image))) { ret = -EINVAL; goto cleanup; } } /* remember return value in a stack for bpf prog to access */ emit_stx(&prog, BPF_DW, BPF_REG_FP, BPF_REG_0, -8); - im->ip_after_call = prog; - memcpy(prog, x86_nops[5], X86_PATCH_SIZE); - prog += X86_PATCH_SIZE; + im->ip_after_call = image + (prog - (u8 *)rw_image); + emit_nops(&prog, X86_PATCH_SIZE); } if (fmod_ret->nr_links) { @@ -2624,16 +2711,19 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i /* Update the branches saved in invoke_bpf_mod_ret with the * aligned address of do_fexit. */ - for (i = 0; i < fmod_ret->nr_links; i++) - emit_cond_near_jump(&branches[i], prog, branches[i], - X86_JNE); + for (i = 0; i < fmod_ret->nr_links; i++) { + emit_cond_near_jump(&branches[i], image + (prog - (u8 *)rw_image), + image + (branches[i] - (u8 *)rw_image), X86_JNE); + } } - if (fexit->nr_links) - if (invoke_bpf(m, &prog, fexit, regs_off, run_ctx_off, false)) { + if (fexit->nr_links) { + if (invoke_bpf(m, &prog, fexit, regs_off, run_ctx_off, + false, image, rw_image)) { ret = -EINVAL; goto cleanup; } + } if (flags & BPF_TRAMP_F_RESTORE_REGS) restore_regs(m, &prog, regs_off); @@ -2643,18 +2733,19 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i * restored to R0. */ if (flags & BPF_TRAMP_F_CALL_ORIG) { - im->ip_epilogue = prog; + im->ip_epilogue = image + (prog - (u8 *)rw_image); /* arg1: mov rdi, im */ emit_mov_imm64(&prog, BPF_REG_1, (long) im >> 32, (u32) (long) im); - if (emit_rsb_call(&prog, __bpf_tramp_exit, prog)) { + if (emit_rsb_call(&prog, __bpf_tramp_exit, image + (prog - (u8 *)rw_image))) { ret = -EINVAL; goto cleanup; } - } else if (flags & BPF_TRAMP_F_TAIL_CALL_CTX) + } else if (flags & BPF_TRAMP_F_TAIL_CALL_CTX) { /* Before running the original function, restore the * tail_call_cnt from stack to rax. */ RESTORE_TAIL_CALL_CNT(stack_size); + } /* restore return value of orig_call or fentry prog back into RAX */ if (save_ret) @@ -2662,22 +2753,94 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i emit_ldx(&prog, BPF_DW, BPF_REG_6, BPF_REG_FP, -rbx_off); EMIT1(0xC9); /* leave */ - if (flags & BPF_TRAMP_F_SKIP_FRAME) + if (flags & BPF_TRAMP_F_SKIP_FRAME) { /* skip our return address and return to parent */ EMIT4(0x48, 0x83, 0xC4, 8); /* add rsp, 8 */ - emit_return(&prog, prog); + } + emit_return(&prog, image + (prog - (u8 *)rw_image)); /* Make sure the trampoline generation logic doesn't overflow */ - if (WARN_ON_ONCE(prog > (u8 *)image_end - BPF_INSN_SAFETY)) { + if (WARN_ON_ONCE(prog > (u8 *)rw_image_end - BPF_INSN_SAFETY)) { ret = -EFAULT; goto cleanup; } - ret = prog - (u8 *)image; + ret = prog - (u8 *)rw_image + BPF_INSN_SAFETY; cleanup: kfree(branches); return ret; } +void *arch_alloc_bpf_trampoline(unsigned int size) +{ + return bpf_prog_pack_alloc(size, jit_fill_hole); +} + +void arch_free_bpf_trampoline(void *image, unsigned int size) +{ + bpf_prog_pack_free(image, size); +} + +void arch_protect_bpf_trampoline(void *image, unsigned int size) +{ +} + +void arch_unprotect_bpf_trampoline(void *image, unsigned int size) +{ +} + +int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *image_end, + const struct btf_func_model *m, u32 flags, + struct bpf_tramp_links *tlinks, + void *func_addr) +{ + void *rw_image, *tmp; + int ret; + u32 size = image_end - image; + + /* rw_image doesn't need to be in module memory range, so we can + * use kvmalloc. + */ + rw_image = kvmalloc(size, GFP_KERNEL); + if (!rw_image) + return -ENOMEM; + + ret = __arch_prepare_bpf_trampoline(im, rw_image, rw_image + size, image, m, + flags, tlinks, func_addr); + if (ret < 0) + goto out; + + tmp = bpf_arch_text_copy(image, rw_image, size); + if (IS_ERR(tmp)) + ret = PTR_ERR(tmp); +out: + kvfree(rw_image); + return ret; +} + +int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags, + struct bpf_tramp_links *tlinks, void *func_addr) +{ + struct bpf_tramp_image im; + void *image; + int ret; + + /* Allocate a temporary buffer for __arch_prepare_bpf_trampoline(). + * This will NOT cause fragmentation in direct map, as we do not + * call set_memory_*() on this buffer. + * + * We cannot use kvmalloc here, because we need image to be in + * module memory range. + */ + image = bpf_jit_alloc_exec(PAGE_SIZE); + if (!image) + return -ENOMEM; + + ret = __arch_prepare_bpf_trampoline(&im, image, image + PAGE_SIZE, image, + m, flags, tlinks, func_addr); + bpf_jit_free_exec(image); + return ret; +} + static int emit_bpf_dispatcher(u8 **pprog, int a, int b, s64 *progs, u8 *image, u8 *buf) { u8 *jg_reloc, *prog = *pprog; @@ -2935,9 +3098,16 @@ out_image: jit_data->header = header; jit_data->rw_header = rw_header; } - prog->bpf_func = (void *)image; + /* + * ctx.prog_offset is used when CFI preambles put code *before* + * the function. See emit_cfi(). For FineIBT specifically this code + * can also be executed and bpf_prog_kallsyms_add() will + * generate an additional symbol to cover this, hence also + * decrement proglen. + */ + prog->bpf_func = (void *)image + cfi_get_offset(); prog->jited = 1; - prog->jited_len = proglen; + prog->jited_len = proglen - cfi_get_offset(); } else { prog = orig_prog; } @@ -2992,6 +3162,7 @@ void bpf_jit_free(struct bpf_prog *prog) kvfree(jit_data->addrs); kfree(jit_data); } + prog->bpf_func = (void *)prog->bpf_func - cfi_get_offset(); hdr = bpf_jit_binary_pack_hdr(prog); bpf_jit_binary_pack_free(hdr, NULL); WARN_ON_ONCE(!bpf_prog_kallsyms_verify_off(prog)); diff --git a/arch/x86/net/bpf_jit_comp32.c b/arch/x86/net/bpf_jit_comp32.c index 429a89c5468b57..b18ce19981ece4 100644 --- a/arch/x86/net/bpf_jit_comp32.c +++ b/arch/x86/net/bpf_jit_comp32.c @@ -1194,7 +1194,7 @@ struct jit_context { #define PROLOGUE_SIZE 35 /* - * Emit prologue code for BPF program and check it's size. + * Emit prologue code for BPF program and check its size. * bpf_tail_call helper will skip it while jumping into another program. */ static void emit_prologue(u8 **pprog, u32 stack_depth) diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index ea2eb2ec90e2bc..55c4b07ec1f631 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c @@ -283,6 +283,9 @@ static int setup_mcfg_map(struct acpi_pci_root_info *ci) info->mcfg_added = false; seg = info->sd.domain; + dev_dbg(dev, "%s(%04x %pR ECAM %pa)\n", __func__, seg, + &root->secondary, &root->mcfg_addr); + /* return success if MMCFG is not in use */ if (raw_pci_ext_ops && raw_pci_ext_ops != &pci_mmcfg) return 0; diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c index 4b3efaa82ab7c1..0cc9520666efbb 100644 --- a/arch/x86/pci/mmconfig-shared.c +++ b/arch/x86/pci/mmconfig-shared.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* - * mmconfig-shared.c - Low-level direct PCI config space access via - * MMCONFIG - common code between i386 and x86-64. + * Low-level direct PCI config space access via ECAM - common code between + * i386 and x86-64. * * This code does: * - known chipset handling @@ -11,6 +11,8 @@ * themselves. */ +#define pr_fmt(fmt) "PCI: " fmt + #include #include #include @@ -24,9 +26,7 @@ #include #include -#define PREFIX "PCI: " - -/* Indicate if the mmcfg resources have been placed into the resource table. */ +/* Indicate if the ECAM resources have been placed into the resource table */ static bool pci_mmcfg_running_state; static bool pci_mmcfg_arch_init_failed; static DEFINE_MUTEX(pci_mmcfg_lock); @@ -90,7 +90,7 @@ static struct pci_mmcfg_region *pci_mmconfig_alloc(int segment, int start, res->end = addr + PCI_MMCFG_BUS_OFFSET(end + 1) - 1; res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; snprintf(new->name, PCI_MMCFG_RESOURCE_NAME_LEN, - "PCI MMCONFIG %04x [bus %02x-%02x]", segment, start, end); + "PCI ECAM %04x [bus %02x-%02x]", segment, start, end); res->name = new->name; return new; @@ -102,16 +102,15 @@ struct pci_mmcfg_region *__init pci_mmconfig_add(int segment, int start, struct pci_mmcfg_region *new; new = pci_mmconfig_alloc(segment, start, end, addr); - if (new) { - mutex_lock(&pci_mmcfg_lock); - list_add_sorted(new); - mutex_unlock(&pci_mmcfg_lock); + if (!new) + return NULL; - pr_info(PREFIX - "MMCONFIG for domain %04x [bus %02x-%02x] at %pR " - "(base %#lx)\n", - segment, start, end, &new->res, (unsigned long)addr); - } + mutex_lock(&pci_mmcfg_lock); + list_add_sorted(new); + mutex_unlock(&pci_mmcfg_lock); + + pr_info("ECAM %pR (base %#lx) for domain %04x [bus %02x-%02x]\n", + &new->res, (unsigned long)addr, segment, start, end); return new; } @@ -205,7 +204,7 @@ static const char *__init pci_mmcfg_amd_fam10h(void) msr <<= 32; msr |= low; - /* mmconfig is not enable */ + /* ECAM is not enabled */ if (!(msr & FAM10H_MMIO_CONF_ENABLE)) return NULL; @@ -367,7 +366,7 @@ static int __init pci_mmcfg_check_hostbridge(void) name = pci_mmcfg_probes[i].probe(); if (name) - pr_info(PREFIX "%s with MMCONFIG support\n", name); + pr_info("%s with ECAM support\n", name); } /* some end_bus_number is crazy, fix it */ @@ -443,9 +442,11 @@ static bool is_acpi_reserved(u64 start, u64 end, enum e820_type not_used) return mcfg_res.flags; } -static bool is_efi_mmio(u64 start, u64 end, enum e820_type not_used) +static bool is_efi_mmio(struct resource *res) { #ifdef CONFIG_EFI + u64 start = res->start; + u64 end = res->start + resource_size(res); efi_memory_desc_t *md; u64 size, mmio_start, mmio_end; @@ -455,11 +456,6 @@ static bool is_efi_mmio(u64 start, u64 end, enum e820_type not_used) mmio_start = md->phys_addr; mmio_end = mmio_start + size; - /* - * N.B. Caller supplies (start, start + size), - * so to match, mmio_end is the first address - * *past* the EFI_MEMORY_MAPPED_IO area. - */ if (mmio_start <= start && end <= mmio_end) return true; } @@ -490,11 +486,10 @@ static bool __ref is_mmconf_reserved(check_reserved_t is_reserved, return false; if (dev) - dev_info(dev, "MMCONFIG at %pR reserved as %s\n", + dev_info(dev, "ECAM %pR reserved as %s\n", &cfg->res, method); else - pr_info(PREFIX "MMCONFIG at %pR reserved as %s\n", - &cfg->res, method); + pr_info("ECAM %pR reserved as %s\n", &cfg->res, method); if (old_size != size) { /* update end_bus */ @@ -503,47 +498,51 @@ static bool __ref is_mmconf_reserved(check_reserved_t is_reserved, cfg->res.end = cfg->res.start + PCI_MMCFG_BUS_OFFSET(num_buses) - 1; snprintf(cfg->name, PCI_MMCFG_RESOURCE_NAME_LEN, - "PCI MMCONFIG %04x [bus %02x-%02x]", + "PCI ECAM %04x [bus %02x-%02x]", cfg->segment, cfg->start_bus, cfg->end_bus); if (dev) - dev_info(dev, - "MMCONFIG " - "at %pR (base %#lx) (size reduced!)\n", - &cfg->res, (unsigned long) cfg->address); + dev_info(dev, "ECAM %pR (base %#lx) (size reduced!)\n", + &cfg->res, (unsigned long) cfg->address); else - pr_info(PREFIX - "MMCONFIG for %04x [bus%02x-%02x] " - "at %pR (base %#lx) (size reduced!)\n", - cfg->segment, cfg->start_bus, cfg->end_bus, - &cfg->res, (unsigned long) cfg->address); + pr_info("ECAM %pR (base %#lx) for %04x [bus%02x-%02x] (size reduced!)\n", + &cfg->res, (unsigned long) cfg->address, + cfg->segment, cfg->start_bus, cfg->end_bus); } return true; } -static bool __ref -pci_mmcfg_check_reserved(struct device *dev, struct pci_mmcfg_region *cfg, int early) +static bool __ref pci_mmcfg_reserved(struct device *dev, + struct pci_mmcfg_region *cfg, int early) { + struct resource *conflict; + if (!early && !acpi_disabled) { if (is_mmconf_reserved(is_acpi_reserved, cfg, dev, "ACPI motherboard resource")) return true; if (dev) - dev_info(dev, FW_INFO - "MMCONFIG at %pR not reserved in " - "ACPI motherboard resources\n", + dev_info(dev, FW_INFO "ECAM %pR not reserved in ACPI motherboard resources\n", &cfg->res); else - pr_info(FW_INFO PREFIX - "MMCONFIG at %pR not reserved in " - "ACPI motherboard resources\n", - &cfg->res); - - if (is_mmconf_reserved(is_efi_mmio, cfg, dev, - "EfiMemoryMappedIO")) + pr_info(FW_INFO "ECAM %pR not reserved in ACPI motherboard resources\n", + &cfg->res); + + if (is_efi_mmio(&cfg->res)) { + pr_info("ECAM %pR is EfiMemoryMappedIO; assuming valid\n", + &cfg->res); + conflict = insert_resource_conflict(&iomem_resource, + &cfg->res); + if (conflict) + pr_warn("ECAM %pR conflicts with %s %pR\n", + &cfg->res, conflict->name, conflict); + else + pr_info("ECAM %pR reserved to work around lack of ACPI motherboard _CRS\n", + &cfg->res); return true; + } } /* @@ -569,30 +568,31 @@ static void __init pci_mmcfg_reject_broken(int early) struct pci_mmcfg_region *cfg; list_for_each_entry(cfg, &pci_mmcfg_list, list) { - if (pci_mmcfg_check_reserved(NULL, cfg, early) == 0) { - pr_info(PREFIX "not using MMCONFIG\n"); + if (!pci_mmcfg_reserved(NULL, cfg, early)) { + pr_info("not using ECAM (%pR not reserved)\n", + &cfg->res); free_all_mmcfg(); return; } } } -static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg, - struct acpi_mcfg_allocation *cfg) +static bool __init acpi_mcfg_valid_entry(struct acpi_table_mcfg *mcfg, + struct acpi_mcfg_allocation *cfg) { if (cfg->address < 0xFFFFFFFF) - return 0; + return true; if (!strncmp(mcfg->header.oem_id, "SGI", 3)) - return 0; + return true; if ((mcfg->header.revision >= 1) && (dmi_get_bios_year() >= 2010)) - return 0; + return true; - pr_err(PREFIX "MCFG region for %04x [bus %02x-%02x] at %#llx " - "is above 4GB, ignored\n", cfg->pci_segment, - cfg->start_bus_number, cfg->end_bus_number, cfg->address); - return -EINVAL; + pr_err("ECAM at %#llx for %04x [bus %02x-%02x] is above 4GB, ignored\n", + cfg->address, cfg->pci_segment, cfg->start_bus_number, + cfg->end_bus_number); + return false; } static int __init pci_parse_mcfg(struct acpi_table_header *header) @@ -616,21 +616,21 @@ static int __init pci_parse_mcfg(struct acpi_table_header *header) i -= sizeof(struct acpi_mcfg_allocation); } if (entries == 0) { - pr_err(PREFIX "MMCONFIG has no entries\n"); + pr_err("MCFG has no entries\n"); return -ENODEV; } cfg_table = (struct acpi_mcfg_allocation *) &mcfg[1]; for (i = 0; i < entries; i++) { cfg = &cfg_table[i]; - if (acpi_mcfg_check_entry(mcfg, cfg)) { + if (!acpi_mcfg_valid_entry(mcfg, cfg)) { free_all_mmcfg(); return -ENODEV; } if (pci_mmconfig_add(cfg->pci_segment, cfg->start_bus_number, cfg->end_bus_number, cfg->address) == NULL) { - pr_warn(PREFIX "no memory for MCFG entries\n"); + pr_warn("no memory for MCFG entries\n"); free_all_mmcfg(); return -ENOMEM; } @@ -667,6 +667,8 @@ static int pci_mmcfg_for_each_region(int (*func)(__u64 start, __u64 size, static void __init __pci_mmcfg_init(int early) { + pr_debug("%s(%s)\n", __func__, early ? "early" : "late"); + pci_mmcfg_reject_broken(early); if (list_empty(&pci_mmcfg_list)) return; @@ -693,6 +695,8 @@ static int __initdata known_bridge; void __init pci_mmcfg_early_init(void) { + pr_debug("%s() pci_probe %#x\n", __func__, pci_probe); + if (pci_probe & PCI_PROBE_MMCONF) { if (pci_mmcfg_check_hostbridge()) known_bridge = 1; @@ -706,14 +710,16 @@ void __init pci_mmcfg_early_init(void) void __init pci_mmcfg_late_init(void) { - /* MMCONFIG disabled */ + pr_debug("%s() pci_probe %#x\n", __func__, pci_probe); + + /* ECAM disabled */ if ((pci_probe & PCI_PROBE_MMCONF) == 0) return; if (known_bridge) return; - /* MMCONFIG hasn't been enabled yet, try again */ + /* ECAM hasn't been enabled yet, try again */ if (pci_probe & PCI_PROBE_MASK & ~PCI_PROBE_MMCONF) { acpi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg); __pci_mmcfg_init(0); @@ -726,7 +732,9 @@ static int __init pci_mmcfg_late_insert_resources(void) pci_mmcfg_running_state = true; - /* If we are not using MMCONFIG, don't insert the resources. */ + pr_debug("%s() pci_probe %#x\n", __func__, pci_probe); + + /* If we are not using ECAM, don't insert the resources. */ if ((pci_probe & PCI_PROBE_MMCONF) == 0) return 1; @@ -735,21 +743,24 @@ static int __init pci_mmcfg_late_insert_resources(void) * marked so it won't cause request errors when __request_region is * called. */ - list_for_each_entry(cfg, &pci_mmcfg_list, list) - if (!cfg->res.parent) + list_for_each_entry(cfg, &pci_mmcfg_list, list) { + if (!cfg->res.parent) { + pr_debug("%s() insert %pR\n", __func__, &cfg->res); insert_resource(&iomem_resource, &cfg->res); + } + } return 0; } /* - * Perform MMCONFIG resource insertion after PCI initialization to allow for + * Perform ECAM resource insertion after PCI initialization to allow for * misprogrammed MCFG tables that state larger sizes but actually conflict * with other system resources. */ late_initcall(pci_mmcfg_late_insert_resources); -/* Add MMCFG information for host bridges */ +/* Add ECAM information for host bridges */ int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end, phys_addr_t addr) { @@ -757,6 +768,8 @@ int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end, struct resource *tmp = NULL; struct pci_mmcfg_region *cfg; + dev_dbg(dev, "%s(%04x [bus %02x-%02x])\n", __func__, seg, start, end); + if (!(pci_probe & PCI_PROBE_MMCONF) || pci_mmcfg_arch_init_failed) return -ENODEV; @@ -767,15 +780,17 @@ int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end, cfg = pci_mmconfig_lookup(seg, start); if (cfg) { if (cfg->end_bus < end) - dev_info(dev, FW_INFO - "MMCONFIG for " - "domain %04x [bus %02x-%02x] " - "only partially covers this bridge\n", - cfg->segment, cfg->start_bus, cfg->end_bus); + dev_info(dev, FW_INFO "ECAM %pR for domain %04x [bus %02x-%02x] only partially covers this bridge\n", + &cfg->res, cfg->segment, cfg->start_bus, + cfg->end_bus); mutex_unlock(&pci_mmcfg_lock); return -EEXIST; } + /* + * Don't move earlier; we must return -EEXIST, not -EINVAL, if + * pci_mmconfig_lookup() finds something + */ if (!addr) { mutex_unlock(&pci_mmcfg_lock); return -EINVAL; @@ -784,10 +799,10 @@ int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end, rc = -EBUSY; cfg = pci_mmconfig_alloc(seg, start, end, addr); if (cfg == NULL) { - dev_warn(dev, "fail to add MMCONFIG (out of memory)\n"); + dev_warn(dev, "fail to add ECAM (out of memory)\n"); rc = -ENOMEM; - } else if (!pci_mmcfg_check_reserved(dev, cfg, 0)) { - dev_warn(dev, FW_BUG "MMCONFIG %pR isn't reserved\n", + } else if (!pci_mmcfg_reserved(dev, cfg, 0)) { + dev_warn(dev, FW_BUG "ECAM %pR isn't reserved\n", &cfg->res); } else { /* Insert resource if it's not in boot stage */ @@ -796,16 +811,13 @@ int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end, &cfg->res); if (tmp) { - dev_warn(dev, - "MMCONFIG %pR conflicts with " - "%s %pR\n", + dev_warn(dev, "ECAM %pR conflicts with %s %pR\n", &cfg->res, tmp->name, tmp); } else if (pci_mmcfg_arch_map(cfg)) { - dev_warn(dev, "fail to map MMCONFIG %pR.\n", - &cfg->res); + dev_warn(dev, "fail to map ECAM %pR\n", &cfg->res); } else { list_add_sorted(cfg); - dev_info(dev, "MMCONFIG at %pR (base %#lx)\n", + dev_info(dev, "ECAM %pR (base %#lx)\n", &cfg->res, (unsigned long)addr); cfg = NULL; rc = 0; @@ -823,7 +835,7 @@ int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end, return rc; } -/* Delete MMCFG information for host bridges */ +/* Delete ECAM information for host bridges */ int pci_mmconfig_delete(u16 seg, u8 start, u8 end) { struct pci_mmcfg_region *cfg; diff --git a/arch/x86/pci/mmconfig_32.c b/arch/x86/pci/mmconfig_32.c index bfa7898753220b..f9ef97c593cf1a 100644 --- a/arch/x86/pci/mmconfig_32.c +++ b/arch/x86/pci/mmconfig_32.c @@ -131,7 +131,7 @@ const struct pci_raw_ops pci_mmcfg = { int __init pci_mmcfg_arch_init(void) { - printk(KERN_INFO "PCI: Using MMCONFIG for extended config space\n"); + printk(KERN_INFO "PCI: Using ECAM for extended config space\n"); raw_pci_ext_ops = &pci_mmcfg; return 1; } diff --git a/arch/x86/pci/mmconfig_64.c b/arch/x86/pci/mmconfig_64.c index 0c7b6e66c64484..cb5aa79a759e1c 100644 --- a/arch/x86/pci/mmconfig_64.c +++ b/arch/x86/pci/mmconfig_64.c @@ -6,6 +6,8 @@ * space mapped. This allows lockless config space operation. */ +#define pr_fmt(fmt) "PCI: " fmt + #include #include #include @@ -14,8 +16,6 @@ #include #include -#define PREFIX "PCI: " - static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn) { struct pci_mmcfg_region *cfg = pci_mmconfig_lookup(seg, bus); @@ -111,6 +111,25 @@ static void __iomem *mcfg_ioremap(struct pci_mmcfg_region *cfg) return addr; } +int pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg) +{ + cfg->virt = mcfg_ioremap(cfg); + if (!cfg->virt) { + pr_err("can't map ECAM at %pR\n", &cfg->res); + return -ENOMEM; + } + + return 0; +} + +void pci_mmcfg_arch_unmap(struct pci_mmcfg_region *cfg) +{ + if (cfg && cfg->virt) { + iounmap(cfg->virt + PCI_MMCFG_BUS_OFFSET(cfg->start_bus)); + cfg->virt = NULL; + } +} + int __init pci_mmcfg_arch_init(void) { struct pci_mmcfg_region *cfg; @@ -133,22 +152,3 @@ void __init pci_mmcfg_arch_free(void) list_for_each_entry(cfg, &pci_mmcfg_list, list) pci_mmcfg_arch_unmap(cfg); } - -int pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg) -{ - cfg->virt = mcfg_ioremap(cfg); - if (!cfg->virt) { - pr_err(PREFIX "can't map MMCONFIG at %pR\n", &cfg->res); - return -ENOMEM; - } - - return 0; -} - -void pci_mmcfg_arch_unmap(struct pci_mmcfg_region *cfg) -{ - if (cfg && cfg->virt) { - iounmap(cfg->virt + PCI_MMCFG_BUS_OFFSET(cfg->start_bus)); - cfg->virt = NULL; - } -} diff --git a/arch/x86/pci/pcbios.c b/arch/x86/pci/pcbios.c index 4f15280732edb9..244c643bb0b5f8 100644 --- a/arch/x86/pci/pcbios.c +++ b/arch/x86/pci/pcbios.c @@ -3,6 +3,8 @@ * BIOS32 and PCI BIOS handling. */ +#include +#include #include #include #include @@ -29,8 +31,19 @@ #define PCIBIOS_HW_TYPE1_SPEC 0x10 #define PCIBIOS_HW_TYPE2_SPEC 0x20 +/* + * Returned in EAX: + * - AH: return code + */ +#define PCIBIOS_RETURN_CODE GENMASK(15, 8) + int pcibios_enabled; +static u8 pcibios_get_return_code(u32 eax) +{ + return FIELD_GET(PCIBIOS_RETURN_CODE, eax); +} + /* According to the BIOS specification at: * http://members.datafast.net.au/dft0802/specs/bios21.pdf, we could * restrict the x zone to some pages and make it ro. But this may be @@ -154,7 +167,7 @@ static int __init check_pcibios(void) : "memory"); local_irq_restore(flags); - status = (eax >> 8) & 0xff; + status = pcibios_get_return_code(eax); hw_mech = eax & 0xff; major_ver = (ebx >> 8) & 0xff; minor_ver = ebx & 0xff; @@ -227,7 +240,7 @@ static int pci_bios_read(unsigned int seg, unsigned int bus, raw_spin_unlock_irqrestore(&pci_config_lock, flags); - return (int)((result & 0xff00) >> 8); + return pcibios_get_return_code(result); } static int pci_bios_write(unsigned int seg, unsigned int bus, @@ -269,7 +282,7 @@ static int pci_bios_write(unsigned int seg, unsigned int bus, raw_spin_unlock_irqrestore(&pci_config_lock, flags); - return (int)((result & 0xff00) >> 8); + return pcibios_get_return_code(result); } @@ -385,9 +398,10 @@ struct irq_routing_table * pcibios_get_irq_routing_table(void) "m" (opt) : "memory"); DBG("OK ret=%d, size=%d, map=%x\n", ret, opt.size, map); - if (ret & 0xff00) - printk(KERN_ERR "PCI: Error %02x when fetching IRQ routing table.\n", (ret >> 8) & 0xff); - else if (opt.size) { + ret = pcibios_get_return_code(ret); + if (ret) { + printk(KERN_ERR "PCI: Error %02x when fetching IRQ routing table.\n", ret); + } else if (opt.size) { rt = kmalloc(sizeof(struct irq_routing_table) + opt.size, GFP_KERNEL); if (rt) { memset(rt, 0, sizeof(struct irq_routing_table)); @@ -415,7 +429,7 @@ int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq) "b" ((dev->bus->number << 8) | dev->devfn), "c" ((irq << 8) | (pin + 10)), "S" (&pci_indirect)); - return !(ret & 0xff00); + return pcibios_get_return_code(ret) == PCIBIOS_SUCCESSFUL; } EXPORT_SYMBOL(pcibios_set_irq_routing); diff --git a/arch/x86/pci/sta2x11-fixup.c b/arch/x86/pci/sta2x11-fixup.c index 7368afc039987b..8c8ddc4dcc08dc 100644 --- a/arch/x86/pci/sta2x11-fixup.c +++ b/arch/x86/pci/sta2x11-fixup.c @@ -14,6 +14,7 @@ #include #include #include +#include #define STA2X11_SWIOTLB_SIZE (4*1024*1024) diff --git a/arch/x86/platform/intel-quark/imr_selftest.c b/arch/x86/platform/intel-quark/imr_selftest.c index 761f3689f60a6b..84ba715f44d128 100644 --- a/arch/x86/platform/intel-quark/imr_selftest.c +++ b/arch/x86/platform/intel-quark/imr_selftest.c @@ -6,7 +6,7 @@ * Copyright(c) 2015 Bryan O'Donoghue * * IMR self test. The purpose of this module is to run a set of tests on the - * IMR API to validate it's sanity. We check for overlapping, reserved + * IMR API to validate its sanity. We check for overlapping, reserved * addresses and setup/teardown sanity. * */ diff --git a/arch/x86/platform/pvh/head.S b/arch/x86/platform/pvh/head.S index c4365a05ab83b3..f7235ef87bc32b 100644 --- a/arch/x86/platform/pvh/head.S +++ b/arch/x86/platform/pvh/head.S @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -41,7 +42,7 @@ * Bit 8 (TF) must be cleared. Other bits are all unspecified. * * All other processor registers and flag bits are unspecified. The OS is in - * charge of setting up it's own stack, GDT and IDT. + * charge of setting up its own stack, GDT and IDT. */ #define PVH_GDT_ENTRY_CS 1 @@ -148,11 +149,11 @@ SYM_DATA_END(gdt) SYM_DATA_START_LOCAL(gdt_start) .quad 0x0000000000000000 /* NULL descriptor */ #ifdef CONFIG_X86_64 - .quad GDT_ENTRY(0xa09a, 0, 0xfffff) /* PVH_CS_SEL */ + .quad GDT_ENTRY(DESC_CODE64, 0, 0xfffff) /* PVH_CS_SEL */ #else - .quad GDT_ENTRY(0xc09a, 0, 0xfffff) /* PVH_CS_SEL */ + .quad GDT_ENTRY(DESC_CODE32, 0, 0xfffff) /* PVH_CS_SEL */ #endif - .quad GDT_ENTRY(0xc092, 0, 0xfffff) /* PVH_DS_SEL */ + .quad GDT_ENTRY(DESC_DATA32, 0, 0xfffff) /* PVH_DS_SEL */ SYM_DATA_END_LABEL(gdt_start, SYM_L_LOCAL, gdt_end) .balign 16 diff --git a/arch/x86/platform/uv/uv_irq.c b/arch/x86/platform/uv/uv_irq.c index 4221259a5870ab..a379501b7a69ec 100644 --- a/arch/x86/platform/uv/uv_irq.c +++ b/arch/x86/platform/uv/uv_irq.c @@ -35,7 +35,7 @@ static void uv_program_mmr(struct irq_cfg *cfg, struct uv_irq_2_mmr_pnode *info) mmr_value = 0; entry = (struct uv_IO_APIC_route_entry *)&mmr_value; entry->vector = cfg->vector; - entry->delivery_mode = apic->delivery_mode; + entry->delivery_mode = APIC_DELIVERY_MODE_FIXED; entry->dest_mode = apic->dest_mode_logical; entry->polarity = 0; entry->trigger = 0; diff --git a/arch/x86/platform/uv/uv_nmi.c b/arch/x86/platform/uv/uv_nmi.c index e03207de28806b..5c50e550ab635f 100644 --- a/arch/x86/platform/uv/uv_nmi.c +++ b/arch/x86/platform/uv/uv_nmi.c @@ -741,7 +741,7 @@ static void uv_nmi_dump_state_cpu(int cpu, struct pt_regs *regs) this_cpu_write(uv_cpu_nmi.state, UV_NMI_STATE_DUMP_DONE); } -/* Trigger a slave CPU to dump it's state */ +/* Trigger a slave CPU to dump its state */ static void uv_nmi_trigger_dump(int cpu) { int retry = uv_nmi_trigger_delay; diff --git a/arch/x86/platform/uv/uv_time.c b/arch/x86/platform/uv/uv_time.c index ff5afc8a5a41ea..3712afc3534dea 100644 --- a/arch/x86/platform/uv/uv_time.c +++ b/arch/x86/platform/uv/uv_time.c @@ -270,7 +270,7 @@ static int uv_rtc_unset_timer(int cpu, int force) * Read the RTC. * * Starting with HUB rev 2.0, the UV RTC register is replicated across all - * cachelines of it's own page. This allows faster simultaneous reads + * cachelines of its own page. This allows faster simultaneous reads * from a given socket. */ static u64 uv_read_rtc(struct clocksource *cs) diff --git a/arch/x86/realmode/init.c b/arch/x86/realmode/init.c index 788e5559549f39..f9bc444a3064d3 100644 --- a/arch/x86/realmode/init.c +++ b/arch/x86/realmode/init.c @@ -61,7 +61,7 @@ void __init reserve_real_mode(void) set_real_mode_mem(mem); /* - * Unconditionally reserve the entire fisrt 1M, see comment in + * Unconditionally reserve the entire first 1M, see comment in * setup_arch(). */ memblock_reserve(0, SZ_1M); diff --git a/arch/x86/realmode/rm/reboot.S b/arch/x86/realmode/rm/reboot.S index f10515b10e0a01..e714b4624e3676 100644 --- a/arch/x86/realmode/rm/reboot.S +++ b/arch/x86/realmode/rm/reboot.S @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ #include +#include #include #include #include @@ -153,5 +154,5 @@ SYM_DATA_START(machine_real_restart_gdt) * base value 0x100; since this is consistent with real mode * semantics we don't have to reload the segments once CR0.PE = 0. */ - .quad GDT_ENTRY(0x0093, 0x100, 0xffff) + .quad GDT_ENTRY(DESC_DATA16, 0x100, 0xffff) SYM_DATA_END(machine_real_restart_gdt) diff --git a/arch/x86/tools/Makefile b/arch/x86/tools/Makefile index 90e820ac9771fe..7278e2545c3500 100644 --- a/arch/x86/tools/Makefile +++ b/arch/x86/tools/Makefile @@ -17,7 +17,7 @@ reformatter = $(srctree)/arch/x86/tools/objdump_reformat.awk chkobjdump = $(srctree)/arch/x86/tools/chkobjdump.awk quiet_cmd_posttest = TEST $@ - cmd_posttest = ($(OBJDUMP) -v | $(AWK) -f $(chkobjdump)) || $(OBJDUMP) -d -j .text $(objtree)/vmlinux | $(AWK) -f $(reformatter) | $(obj)/insn_decoder_test $(posttest_64bit) $(posttest_verbose) + cmd_posttest = $(OBJDUMP) -d -j .text $(objtree)/vmlinux | $(AWK) -f $(reformatter) | $(obj)/insn_decoder_test $(posttest_64bit) $(posttest_verbose) quiet_cmd_sanitytest = TEST $@ cmd_sanitytest = $(obj)/insn_sanity $(posttest_64bit) -m 1000000 diff --git a/arch/x86/tools/chkobjdump.awk b/arch/x86/tools/chkobjdump.awk deleted file mode 100644 index a4cf678cf5c80e..00000000000000 --- a/arch/x86/tools/chkobjdump.awk +++ /dev/null @@ -1,34 +0,0 @@ -# GNU objdump version checker -# -# Usage: -# objdump -v | awk -f chkobjdump.awk -BEGIN { - # objdump version 2.19 or later is OK for the test. - od_ver = 2; - od_sver = 19; -} - -/^GNU objdump/ { - verstr = "" - gsub(/\(.*\)/, ""); - for (i = 3; i <= NF; i++) - if (match($(i), "^[0-9]")) { - verstr = $(i); - break; - } - if (verstr == "") { - printf("Warning: Failed to find objdump version number.\n"); - exit 0; - } - split(verstr, ver, "."); - if (ver[1] > od_ver || - (ver[1] == od_ver && ver[2] >= od_sver)) { - exit 1; - } else { - printf("Warning: objdump version %s is older than %d.%d\n", - verstr, od_ver, od_sver); - print("Warning: Skipping posttest."); - # Logic is inverted, because we just skip test without error. - exit 0; - } -} diff --git a/arch/x86/tools/objdump_reformat.awk b/arch/x86/tools/objdump_reformat.awk index f418c91b71f011..20b08a6c4d3337 100644 --- a/arch/x86/tools/objdump_reformat.awk +++ b/arch/x86/tools/objdump_reformat.awk @@ -11,8 +11,8 @@ BEGIN { prev_addr = "" prev_hex = "" prev_mnemonic = "" - bad_expr = "(\\(bad\\)|^rex|^.byte|^rep(z|nz)$|^lock$|^es$|^cs$|^ss$|^ds$|^fs$|^gs$|^data(16|32)$|^addr(16|32|64))" - fwait_expr = "^9b " + bad_expr = "(\\(bad\\)||^rex|^.byte|^rep(z|nz)$|^lock$|^es$|^cs$|^ss$|^ds$|^fs$|^gs$|^data(16|32)$|^addr(16|32|64))" + fwait_expr = "^9b[ \t]*fwait" fwait_str="9b\tfwait" } @@ -22,7 +22,7 @@ BEGIN { } /^ *[0-9a-f]+:/ { - if (split($0, field, "\t") < 3) { + if (split($0, field, /: |\t/) < 3) { # This is a continuation of the same insn. prev_hex = prev_hex field[2] } else { diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c index d30949e25ebd9b..a3bae2b24626bc 100644 --- a/arch/x86/tools/relocs.c +++ b/arch/x86/tools/relocs.c @@ -66,7 +66,7 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = { [S_REL] = "^(__init_(begin|end)|" "__x86_cpu_dev_(start|end)|" - "(__parainstructions|__alt_instructions)(_end)?|" + "__alt_instructions(_end)?|" "(__iommu_table|__apicdrivers|__smp_locks)(_end)?|" "__(start|end)_pci_.*|" #if CONFIG_FW_LOADER diff --git a/arch/x86/um/asm/elf.h b/arch/x86/um/asm/elf.h index 6523eb7c3bd177..6052200fe92568 100644 --- a/arch/x86/um/asm/elf.h +++ b/arch/x86/um/asm/elf.h @@ -168,8 +168,8 @@ do { \ (pr_reg)[18] = (_regs)->regs.gp[18]; \ (pr_reg)[19] = (_regs)->regs.gp[19]; \ (pr_reg)[20] = (_regs)->regs.gp[20]; \ - (pr_reg)[21] = current->thread.arch.fs; \ - (pr_reg)[22] = 0; \ + (pr_reg)[21] = (_regs)->regs.gp[21]; \ + (pr_reg)[22] = (_regs)->regs.gp[22]; \ (pr_reg)[23] = 0; \ (pr_reg)[24] = 0; \ (pr_reg)[25] = 0; \ diff --git a/arch/x86/um/asm/processor_64.h b/arch/x86/um/asm/processor_64.h index 1ef9c21877bc85..f901595089365f 100644 --- a/arch/x86/um/asm/processor_64.h +++ b/arch/x86/um/asm/processor_64.h @@ -10,13 +10,11 @@ struct arch_thread { unsigned long debugregs[8]; int debugregs_seq; - unsigned long fs; struct faultinfo faultinfo; }; #define INIT_ARCH_THREAD { .debugregs = { [ 0 ... 7 ] = 0 }, \ .debugregs_seq = 0, \ - .fs = 0, \ .faultinfo = { 0, 0, 0 } } #define STACKSLOTS_PER_LINE 4 @@ -28,7 +26,6 @@ static inline void arch_flush_thread(struct arch_thread *thread) static inline void arch_copy_thread(struct arch_thread *from, struct arch_thread *to) { - to->fs = from->fs; } #define current_sp() ({ void *sp; __asm__("movq %%rsp, %0" : "=r" (sp) : ); sp; }) diff --git a/arch/x86/um/os-Linux/Makefile b/arch/x86/um/os-Linux/Makefile index ae169125d03fcc..5249bbc30dcdb1 100644 --- a/arch/x86/um/os-Linux/Makefile +++ b/arch/x86/um/os-Linux/Makefile @@ -6,7 +6,6 @@ obj-y = registers.o task_size.o mcontext.o obj-$(CONFIG_X86_32) += tls.o -obj-$(CONFIG_64BIT) += prctl.o USER_OBJS := $(obj-y) diff --git a/arch/x86/um/os-Linux/prctl.c b/arch/x86/um/os-Linux/prctl.c deleted file mode 100644 index 8431e87ac33338..00000000000000 --- a/arch/x86/um/os-Linux/prctl.c +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright (C) 2007 Jeff Dike (jdike@{addtoit.com,linux.intel.com}) - * Licensed under the GPL - */ - -#include -#include - -int os_arch_prctl(int pid, int option, unsigned long *arg2) -{ - return ptrace(PTRACE_ARCH_PRCTL, pid, (unsigned long) arg2, option); -} diff --git a/arch/x86/um/ptrace_32.c b/arch/x86/um/ptrace_32.c index 0bc4b73a9cdeab..7f1abde2c84b5b 100644 --- a/arch/x86/um/ptrace_32.c +++ b/arch/x86/um/ptrace_32.c @@ -25,30 +25,6 @@ void arch_switch_to(struct task_struct *to) printk(KERN_WARNING "arch_switch_tls failed, errno = EINVAL\n"); } -int is_syscall(unsigned long addr) -{ - unsigned short instr; - int n; - - n = copy_from_user(&instr, (void __user *) addr, sizeof(instr)); - if (n) { - /* access_process_vm() grants access to vsyscall and stub, - * while copy_from_user doesn't. Maybe access_process_vm is - * slow, but that doesn't matter, since it will be called only - * in case of singlestepping, if copy_from_user failed. - */ - n = access_process_vm(current, addr, &instr, sizeof(instr), - FOLL_FORCE); - if (n != sizeof(instr)) { - printk(KERN_ERR "is_syscall : failed to read " - "instruction from 0x%lx\n", addr); - return 1; - } - } - /* int 0x80 or sysenter */ - return (instr == 0x80cd) || (instr == 0x340f); -} - /* determines which flags the user has access to. */ /* 1 = access 0 = no access */ #define FLAG_MASK 0x00044dd5 diff --git a/arch/x86/um/ptrace_64.c b/arch/x86/um/ptrace_64.c index 289d0159b041e2..aa68d83d3f441b 100644 --- a/arch/x86/um/ptrace_64.c +++ b/arch/x86/um/ptrace_64.c @@ -188,32 +188,6 @@ int peek_user(struct task_struct *child, long addr, long data) return put_user(tmp, (unsigned long *) data); } -/* XXX Mostly copied from sys-i386 */ -int is_syscall(unsigned long addr) -{ - unsigned short instr; - int n; - - n = copy_from_user(&instr, (void __user *) addr, sizeof(instr)); - if (n) { - /* - * access_process_vm() grants access to vsyscall and stub, - * while copy_from_user doesn't. Maybe access_process_vm is - * slow, but that doesn't matter, since it will be called only - * in case of singlestepping, if copy_from_user failed. - */ - n = access_process_vm(current, addr, &instr, sizeof(instr), - FOLL_FORCE); - if (n != sizeof(instr)) { - printk("is_syscall : failed to read instruction from " - "0x%lx\n", addr); - return 1; - } - } - /* sysenter */ - return instr == 0x050f; -} - static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) { int err, n, cpu = ((struct thread_info *) child->stack)->cpu; diff --git a/arch/x86/um/shared/sysdep/ptrace_32.h b/arch/x86/um/shared/sysdep/ptrace_32.h index db8478a83a0970..0c4989842fbe6c 100644 --- a/arch/x86/um/shared/sysdep/ptrace_32.h +++ b/arch/x86/um/shared/sysdep/ptrace_32.h @@ -8,10 +8,6 @@ #define MAX_FP_NR HOST_FPX_SIZE -void set_using_sysemu(int value); -int get_using_sysemu(void); -extern int sysemu_supported; - #define UPT_SYSCALL_ARG1(r) UPT_BX(r) #define UPT_SYSCALL_ARG2(r) UPT_CX(r) #define UPT_SYSCALL_ARG3(r) UPT_DX(r) diff --git a/arch/x86/um/shared/sysdep/ptrace_user.h b/arch/x86/um/shared/sysdep/ptrace_user.h index 44782bbad41ea9..1d1a824fa65282 100644 --- a/arch/x86/um/shared/sysdep/ptrace_user.h +++ b/arch/x86/um/shared/sysdep/ptrace_user.h @@ -15,14 +15,12 @@ #define FP_SIZE ((HOST_FPX_SIZE > HOST_FP_SIZE) ? HOST_FPX_SIZE : HOST_FP_SIZE) #else #define FP_SIZE HOST_FP_SIZE +#endif /* - * x86_64 FC3 doesn't define this in /usr/include/linux/ptrace.h even though - * it's defined in the kernel's include/linux/ptrace.h. Additionally, use the - * 2.4 name and value for 2.4 host compatibility. + * glibc before 2.27 does not include PTRACE_SYSEMU_SINGLESTEP in its enum, + * ensure we have a definition by (re-)defining it here. */ -#ifndef PTRACE_OLDSETOPTIONS -#define PTRACE_OLDSETOPTIONS 21 -#endif - +#ifndef PTRACE_SYSEMU_SINGLESTEP +#define PTRACE_SYSEMU_SINGLESTEP 32 #endif diff --git a/arch/x86/um/shared/sysdep/stub_32.h b/arch/x86/um/shared/sysdep/stub_32.h index 38fa894b65d088..ea8b5a2d67afb9 100644 --- a/arch/x86/um/shared/sysdep/stub_32.h +++ b/arch/x86/um/shared/sysdep/stub_32.h @@ -12,72 +12,79 @@ #define STUB_MMAP_NR __NR_mmap2 #define MMAP_OFFSET(o) ((o) >> UM_KERN_PAGE_SHIFT) -static inline long stub_syscall0(long syscall) +static __always_inline long stub_syscall0(long syscall) { long ret; - __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall)); + __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall) + : "memory"); return ret; } -static inline long stub_syscall1(long syscall, long arg1) +static __always_inline long stub_syscall1(long syscall, long arg1) { long ret; - __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1)); + __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1) + : "memory"); return ret; } -static inline long stub_syscall2(long syscall, long arg1, long arg2) +static __always_inline long stub_syscall2(long syscall, long arg1, long arg2) { long ret; __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1), - "c" (arg2)); + "c" (arg2) + : "memory"); return ret; } -static inline long stub_syscall3(long syscall, long arg1, long arg2, long arg3) +static __always_inline long stub_syscall3(long syscall, long arg1, long arg2, + long arg3) { long ret; __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1), - "c" (arg2), "d" (arg3)); + "c" (arg2), "d" (arg3) + : "memory"); return ret; } -static inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3, - long arg4) +static __always_inline long stub_syscall4(long syscall, long arg1, long arg2, + long arg3, long arg4) { long ret; __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1), - "c" (arg2), "d" (arg3), "S" (arg4)); + "c" (arg2), "d" (arg3), "S" (arg4) + : "memory"); return ret; } -static inline long stub_syscall5(long syscall, long arg1, long arg2, long arg3, - long arg4, long arg5) +static __always_inline long stub_syscall5(long syscall, long arg1, long arg2, + long arg3, long arg4, long arg5) { long ret; __asm__ volatile ("int $0x80" : "=a" (ret) : "0" (syscall), "b" (arg1), - "c" (arg2), "d" (arg3), "S" (arg4), "D" (arg5)); + "c" (arg2), "d" (arg3), "S" (arg4), "D" (arg5) + : "memory"); return ret; } -static inline void trap_myself(void) +static __always_inline void trap_myself(void) { __asm("int3"); } -static inline void remap_stack_and_trap(void) +static __always_inline void remap_stack_and_trap(void) { __asm__ volatile ( "movl %%esp,%%ebx ;" diff --git a/arch/x86/um/shared/sysdep/stub_64.h b/arch/x86/um/shared/sysdep/stub_64.h index 2de1c8f8817341..b24168ef0ac49f 100644 --- a/arch/x86/um/shared/sysdep/stub_64.h +++ b/arch/x86/um/shared/sysdep/stub_64.h @@ -16,7 +16,7 @@ #define __syscall_clobber "r11","rcx","memory" #define __syscall "syscall" -static inline long stub_syscall0(long syscall) +static __always_inline long stub_syscall0(long syscall) { long ret; @@ -27,7 +27,7 @@ static inline long stub_syscall0(long syscall) return ret; } -static inline long stub_syscall2(long syscall, long arg1, long arg2) +static __always_inline long stub_syscall2(long syscall, long arg1, long arg2) { long ret; @@ -38,7 +38,8 @@ static inline long stub_syscall2(long syscall, long arg1, long arg2) return ret; } -static inline long stub_syscall3(long syscall, long arg1, long arg2, long arg3) +static __always_inline long stub_syscall3(long syscall, long arg1, long arg2, + long arg3) { long ret; @@ -50,7 +51,7 @@ static inline long stub_syscall3(long syscall, long arg1, long arg2, long arg3) return ret; } -static inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3, +static __always_inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3, long arg4) { long ret; @@ -64,8 +65,8 @@ static inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3, return ret; } -static inline long stub_syscall5(long syscall, long arg1, long arg2, long arg3, - long arg4, long arg5) +static __always_inline long stub_syscall5(long syscall, long arg1, long arg2, + long arg3, long arg4, long arg5) { long ret; @@ -78,12 +79,12 @@ static inline long stub_syscall5(long syscall, long arg1, long arg2, long arg3, return ret; } -static inline void trap_myself(void) +static __always_inline void trap_myself(void) { __asm("int3"); } -static inline void remap_stack_and_trap(void) +static __always_inline void remap_stack_and_trap(void) { __asm__ volatile ( "movq %0,%%rax ;" diff --git a/arch/x86/um/syscalls_64.c b/arch/x86/um/syscalls_64.c index 27b29ae6c471b8..6a00a28c9cca77 100644 --- a/arch/x86/um/syscalls_64.c +++ b/arch/x86/um/syscalls_64.c @@ -16,60 +16,24 @@ long arch_prctl(struct task_struct *task, int option, unsigned long __user *arg2) { - unsigned long *ptr = arg2, tmp; - long ret; - int pid = task->mm->context.id.u.pid; - - /* - * With ARCH_SET_FS (and ARCH_SET_GS is treated similarly to - * be safe), we need to call arch_prctl on the host because - * setting %fs may result in something else happening (like a - * GDT or thread.fs being set instead). So, we let the host - * fiddle the registers and thread struct and restore the - * registers afterwards. - * - * So, the saved registers are stored to the process (this - * needed because a stub may have been the last thing to run), - * arch_prctl is run on the host, then the registers are read - * back. - */ - switch (option) { - case ARCH_SET_FS: - case ARCH_SET_GS: - ret = restore_pid_registers(pid, ¤t->thread.regs.regs); - if (ret) - return ret; - break; - case ARCH_GET_FS: - case ARCH_GET_GS: - /* - * With these two, we read to a local pointer and - * put_user it to the userspace pointer that we were - * given. If addr isn't valid (because it hasn't been - * faulted in or is just bogus), we want put_user to - * fault it in (or return -EFAULT) instead of having - * the host return -EFAULT. - */ - ptr = &tmp; - } - - ret = os_arch_prctl(pid, option, ptr); - if (ret) - return ret; + long ret = -EINVAL; switch (option) { case ARCH_SET_FS: - current->thread.arch.fs = (unsigned long) ptr; - ret = save_registers(pid, ¤t->thread.regs.regs); + current->thread.regs.regs.gp[FS_BASE / sizeof(unsigned long)] = + (unsigned long) arg2; + ret = 0; break; case ARCH_SET_GS: - ret = save_registers(pid, ¤t->thread.regs.regs); + current->thread.regs.regs.gp[GS_BASE / sizeof(unsigned long)] = + (unsigned long) arg2; + ret = 0; break; case ARCH_GET_FS: - ret = put_user(tmp, arg2); + ret = put_user(current->thread.regs.regs.gp[FS_BASE / sizeof(unsigned long)], arg2); break; case ARCH_GET_GS: - ret = put_user(tmp, arg2); + ret = put_user(current->thread.regs.regs.gp[GS_BASE / sizeof(unsigned long)], arg2); break; } @@ -83,10 +47,10 @@ SYSCALL_DEFINE2(arch_prctl, int, option, unsigned long, arg2) void arch_switch_to(struct task_struct *to) { - if ((to->thread.arch.fs == 0) || (to->mm == NULL)) - return; - - arch_prctl(to, ARCH_SET_FS, (void __user *) to->thread.arch.fs); + /* + * Nothing needs to be done on x86_64. + * The FS_BASE/GS_BASE registers are saved in the ptrace register set. + */ } SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len, diff --git a/arch/x86/um/sysrq_64.c b/arch/x86/um/sysrq_64.c index ef1eb4f4f6126d..0bf6de40abffe1 100644 --- a/arch/x86/um/sysrq_64.c +++ b/arch/x86/um/sysrq_64.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include diff --git a/arch/x86/um/tls_64.c b/arch/x86/um/tls_64.c index ebd3855d9b1323..c51a613f6f5c41 100644 --- a/arch/x86/um/tls_64.c +++ b/arch/x86/um/tls_64.c @@ -12,7 +12,7 @@ int arch_set_tls(struct task_struct *t, unsigned long tls) * If CLONE_SETTLS is set, we need to save the thread id * so it can be set during context switches. */ - t->thread.arch.fs = tls; + t->thread.regs.regs.gp[FS_BASE / sizeof(unsigned long)] = tls; return 0; } diff --git a/arch/x86/virt/vmx/tdx/Makefile b/arch/x86/virt/vmx/tdx/Makefile index 46ef8f73aebbb1..90da47eb85eec3 100644 --- a/arch/x86/virt/vmx/tdx/Makefile +++ b/arch/x86/virt/vmx/tdx/Makefile @@ -1,2 +1,2 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-y += seamcall.o +obj-y += seamcall.o tdx.o diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c new file mode 100644 index 00000000000000..4d6826a76f7881 --- /dev/null +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -0,0 +1,1492 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(c) 2023 Intel Corporation. + * + * Intel Trusted Domain Extensions (TDX) support + */ + +#define pr_fmt(fmt) "virt/tdx: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "tdx.h" + +static u32 tdx_global_keyid __ro_after_init; +static u32 tdx_guest_keyid_start __ro_after_init; +static u32 tdx_nr_guest_keyids __ro_after_init; + +static DEFINE_PER_CPU(bool, tdx_lp_initialized); + +static struct tdmr_info_list tdx_tdmr_list; + +static enum tdx_module_status_t tdx_module_status; +static DEFINE_MUTEX(tdx_module_lock); + +/* All TDX-usable memory regions. Protected by mem_hotplug_lock. */ +static LIST_HEAD(tdx_memlist); + +typedef void (*sc_err_func_t)(u64 fn, u64 err, struct tdx_module_args *args); + +static inline void seamcall_err(u64 fn, u64 err, struct tdx_module_args *args) +{ + pr_err("SEAMCALL (0x%016llx) failed: 0x%016llx\n", fn, err); +} + +static inline void seamcall_err_ret(u64 fn, u64 err, + struct tdx_module_args *args) +{ + seamcall_err(fn, err, args); + pr_err("RCX 0x%016llx RDX 0x%016llx R08 0x%016llx\n", + args->rcx, args->rdx, args->r8); + pr_err("R09 0x%016llx R10 0x%016llx R11 0x%016llx\n", + args->r9, args->r10, args->r11); +} + +static inline int sc_retry_prerr(sc_func_t func, sc_err_func_t err_func, + u64 fn, struct tdx_module_args *args) +{ + u64 sret = sc_retry(func, fn, args); + + if (sret == TDX_SUCCESS) + return 0; + + if (sret == TDX_SEAMCALL_VMFAILINVALID) + return -ENODEV; + + if (sret == TDX_SEAMCALL_GP) + return -EOPNOTSUPP; + + if (sret == TDX_SEAMCALL_UD) + return -EACCES; + + err_func(fn, sret, args); + return -EIO; +} + +#define seamcall_prerr(__fn, __args) \ + sc_retry_prerr(__seamcall, seamcall_err, (__fn), (__args)) + +#define seamcall_prerr_ret(__fn, __args) \ + sc_retry_prerr(__seamcall_ret, seamcall_err_ret, (__fn), (__args)) + +/* + * Do the module global initialization once and return its result. + * It can be done on any cpu. It's always called with interrupts + * disabled. + */ +static int try_init_module_global(void) +{ + struct tdx_module_args args = {}; + static DEFINE_RAW_SPINLOCK(sysinit_lock); + static bool sysinit_done; + static int sysinit_ret; + + lockdep_assert_irqs_disabled(); + + raw_spin_lock(&sysinit_lock); + + if (sysinit_done) + goto out; + + /* RCX is module attributes and all bits are reserved */ + args.rcx = 0; + sysinit_ret = seamcall_prerr(TDH_SYS_INIT, &args); + + /* + * The first SEAMCALL also detects the TDX module, thus + * it can fail due to the TDX module is not loaded. + * Dump message to let the user know. + */ + if (sysinit_ret == -ENODEV) + pr_err("module not loaded\n"); + + sysinit_done = true; +out: + raw_spin_unlock(&sysinit_lock); + return sysinit_ret; +} + +/** + * tdx_cpu_enable - Enable TDX on local cpu + * + * Do one-time TDX module per-cpu initialization SEAMCALL (and TDX module + * global initialization SEAMCALL if not done) on local cpu to make this + * cpu be ready to run any other SEAMCALLs. + * + * Always call this function via IPI function calls. + * + * Return 0 on success, otherwise errors. + */ +int tdx_cpu_enable(void) +{ + struct tdx_module_args args = {}; + int ret; + + if (!boot_cpu_has(X86_FEATURE_TDX_HOST_PLATFORM)) + return -ENODEV; + + lockdep_assert_irqs_disabled(); + + if (__this_cpu_read(tdx_lp_initialized)) + return 0; + + /* + * The TDX module global initialization is the very first step + * to enable TDX. Need to do it first (if hasn't been done) + * before the per-cpu initialization. + */ + ret = try_init_module_global(); + if (ret) + return ret; + + ret = seamcall_prerr(TDH_SYS_LP_INIT, &args); + if (ret) + return ret; + + __this_cpu_write(tdx_lp_initialized, true); + + return 0; +} +EXPORT_SYMBOL_GPL(tdx_cpu_enable); + +/* + * Add a memory region as a TDX memory block. The caller must make sure + * all memory regions are added in address ascending order and don't + * overlap. + */ +static int add_tdx_memblock(struct list_head *tmb_list, unsigned long start_pfn, + unsigned long end_pfn, int nid) +{ + struct tdx_memblock *tmb; + + tmb = kmalloc(sizeof(*tmb), GFP_KERNEL); + if (!tmb) + return -ENOMEM; + + INIT_LIST_HEAD(&tmb->list); + tmb->start_pfn = start_pfn; + tmb->end_pfn = end_pfn; + tmb->nid = nid; + + /* @tmb_list is protected by mem_hotplug_lock */ + list_add_tail(&tmb->list, tmb_list); + return 0; +} + +static void free_tdx_memlist(struct list_head *tmb_list) +{ + /* @tmb_list is protected by mem_hotplug_lock */ + while (!list_empty(tmb_list)) { + struct tdx_memblock *tmb = list_first_entry(tmb_list, + struct tdx_memblock, list); + + list_del(&tmb->list); + kfree(tmb); + } +} + +/* + * Ensure that all memblock memory regions are convertible to TDX + * memory. Once this has been established, stash the memblock + * ranges off in a secondary structure because memblock is modified + * in memory hotplug while TDX memory regions are fixed. + */ +static int build_tdx_memlist(struct list_head *tmb_list) +{ + unsigned long start_pfn, end_pfn; + int i, nid, ret; + + for_each_mem_pfn_range(i, MAX_NUMNODES, &start_pfn, &end_pfn, &nid) { + /* + * The first 1MB is not reported as TDX convertible memory. + * Although the first 1MB is always reserved and won't end up + * to the page allocator, it is still in memblock's memory + * regions. Skip them manually to exclude them as TDX memory. + */ + start_pfn = max(start_pfn, PHYS_PFN(SZ_1M)); + if (start_pfn >= end_pfn) + continue; + + /* + * Add the memory regions as TDX memory. The regions in + * memblock has already guaranteed they are in address + * ascending order and don't overlap. + */ + ret = add_tdx_memblock(tmb_list, start_pfn, end_pfn, nid); + if (ret) + goto err; + } + + return 0; +err: + free_tdx_memlist(tmb_list); + return ret; +} + +static int read_sys_metadata_field(u64 field_id, u64 *data) +{ + struct tdx_module_args args = {}; + int ret; + + /* + * TDH.SYS.RD -- reads one global metadata field + * - RDX (in): the field to read + * - R8 (out): the field data + */ + args.rdx = field_id; + ret = seamcall_prerr_ret(TDH_SYS_RD, &args); + if (ret) + return ret; + + *data = args.r8; + + return 0; +} + +static int read_sys_metadata_field16(u64 field_id, + int offset, + struct tdx_tdmr_sysinfo *ts) +{ + u16 *ts_member = ((void *)ts) + offset; + u64 tmp; + int ret; + + if (WARN_ON_ONCE(MD_FIELD_ID_ELE_SIZE_CODE(field_id) != + MD_FIELD_ID_ELE_SIZE_16BIT)) + return -EINVAL; + + ret = read_sys_metadata_field(field_id, &tmp); + if (ret) + return ret; + + *ts_member = tmp; + + return 0; +} + +struct field_mapping { + u64 field_id; + int offset; +}; + +#define TD_SYSINFO_MAP(_field_id, _offset) \ + { .field_id = MD_FIELD_ID_##_field_id, \ + .offset = offsetof(struct tdx_tdmr_sysinfo, _offset) } + +/* Map TD_SYSINFO fields into 'struct tdx_tdmr_sysinfo': */ +static const struct field_mapping fields[] = { + TD_SYSINFO_MAP(MAX_TDMRS, max_tdmrs), + TD_SYSINFO_MAP(MAX_RESERVED_PER_TDMR, max_reserved_per_tdmr), + TD_SYSINFO_MAP(PAMT_4K_ENTRY_SIZE, pamt_entry_size[TDX_PS_4K]), + TD_SYSINFO_MAP(PAMT_2M_ENTRY_SIZE, pamt_entry_size[TDX_PS_2M]), + TD_SYSINFO_MAP(PAMT_1G_ENTRY_SIZE, pamt_entry_size[TDX_PS_1G]), +}; + +static int get_tdx_tdmr_sysinfo(struct tdx_tdmr_sysinfo *tdmr_sysinfo) +{ + int ret; + int i; + + /* Populate 'tdmr_sysinfo' fields using the mapping structure above: */ + for (i = 0; i < ARRAY_SIZE(fields); i++) { + ret = read_sys_metadata_field16(fields[i].field_id, + fields[i].offset, + tdmr_sysinfo); + if (ret) + return ret; + } + + return 0; +} + +/* Calculate the actual TDMR size */ +static int tdmr_size_single(u16 max_reserved_per_tdmr) +{ + int tdmr_sz; + + /* + * The actual size of TDMR depends on the maximum + * number of reserved areas. + */ + tdmr_sz = sizeof(struct tdmr_info); + tdmr_sz += sizeof(struct tdmr_reserved_area) * max_reserved_per_tdmr; + + return ALIGN(tdmr_sz, TDMR_INFO_ALIGNMENT); +} + +static int alloc_tdmr_list(struct tdmr_info_list *tdmr_list, + struct tdx_tdmr_sysinfo *tdmr_sysinfo) +{ + size_t tdmr_sz, tdmr_array_sz; + void *tdmr_array; + + tdmr_sz = tdmr_size_single(tdmr_sysinfo->max_reserved_per_tdmr); + tdmr_array_sz = tdmr_sz * tdmr_sysinfo->max_tdmrs; + + /* + * To keep things simple, allocate all TDMRs together. + * The buffer needs to be physically contiguous to make + * sure each TDMR is physically contiguous. + */ + tdmr_array = alloc_pages_exact(tdmr_array_sz, + GFP_KERNEL | __GFP_ZERO); + if (!tdmr_array) + return -ENOMEM; + + tdmr_list->tdmrs = tdmr_array; + + /* + * Keep the size of TDMR to find the target TDMR + * at a given index in the TDMR list. + */ + tdmr_list->tdmr_sz = tdmr_sz; + tdmr_list->max_tdmrs = tdmr_sysinfo->max_tdmrs; + tdmr_list->nr_consumed_tdmrs = 0; + + return 0; +} + +static void free_tdmr_list(struct tdmr_info_list *tdmr_list) +{ + free_pages_exact(tdmr_list->tdmrs, + tdmr_list->max_tdmrs * tdmr_list->tdmr_sz); +} + +/* Get the TDMR from the list at the given index. */ +static struct tdmr_info *tdmr_entry(struct tdmr_info_list *tdmr_list, + int idx) +{ + int tdmr_info_offset = tdmr_list->tdmr_sz * idx; + + return (void *)tdmr_list->tdmrs + tdmr_info_offset; +} + +#define TDMR_ALIGNMENT SZ_1G +#define TDMR_ALIGN_DOWN(_addr) ALIGN_DOWN((_addr), TDMR_ALIGNMENT) +#define TDMR_ALIGN_UP(_addr) ALIGN((_addr), TDMR_ALIGNMENT) + +static inline u64 tdmr_end(struct tdmr_info *tdmr) +{ + return tdmr->base + tdmr->size; +} + +/* + * Take the memory referenced in @tmb_list and populate the + * preallocated @tdmr_list, following all the special alignment + * and size rules for TDMR. + */ +static int fill_out_tdmrs(struct list_head *tmb_list, + struct tdmr_info_list *tdmr_list) +{ + struct tdx_memblock *tmb; + int tdmr_idx = 0; + + /* + * Loop over TDX memory regions and fill out TDMRs to cover them. + * To keep it simple, always try to use one TDMR to cover one + * memory region. + * + * In practice TDX supports at least 64 TDMRs. A 2-socket system + * typically only consumes less than 10 of those. This code is + * dumb and simple and may use more TMDRs than is strictly + * required. + */ + list_for_each_entry(tmb, tmb_list, list) { + struct tdmr_info *tdmr = tdmr_entry(tdmr_list, tdmr_idx); + u64 start, end; + + start = TDMR_ALIGN_DOWN(PFN_PHYS(tmb->start_pfn)); + end = TDMR_ALIGN_UP(PFN_PHYS(tmb->end_pfn)); + + /* + * A valid size indicates the current TDMR has already + * been filled out to cover the previous memory region(s). + */ + if (tdmr->size) { + /* + * Loop to the next if the current memory region + * has already been fully covered. + */ + if (end <= tdmr_end(tdmr)) + continue; + + /* Otherwise, skip the already covered part. */ + if (start < tdmr_end(tdmr)) + start = tdmr_end(tdmr); + + /* + * Create a new TDMR to cover the current memory + * region, or the remaining part of it. + */ + tdmr_idx++; + if (tdmr_idx >= tdmr_list->max_tdmrs) { + pr_warn("initialization failed: TDMRs exhausted.\n"); + return -ENOSPC; + } + + tdmr = tdmr_entry(tdmr_list, tdmr_idx); + } + + tdmr->base = start; + tdmr->size = end - start; + } + + /* @tdmr_idx is always the index of the last valid TDMR. */ + tdmr_list->nr_consumed_tdmrs = tdmr_idx + 1; + + /* + * Warn early that kernel is about to run out of TDMRs. + * + * This is an indication that TDMR allocation has to be + * reworked to be smarter to not run into an issue. + */ + if (tdmr_list->max_tdmrs - tdmr_list->nr_consumed_tdmrs < TDMR_NR_WARN) + pr_warn("consumed TDMRs reaching limit: %d used out of %d\n", + tdmr_list->nr_consumed_tdmrs, + tdmr_list->max_tdmrs); + + return 0; +} + +/* + * Calculate PAMT size given a TDMR and a page size. The returned + * PAMT size is always aligned up to 4K page boundary. + */ +static unsigned long tdmr_get_pamt_sz(struct tdmr_info *tdmr, int pgsz, + u16 pamt_entry_size) +{ + unsigned long pamt_sz, nr_pamt_entries; + + switch (pgsz) { + case TDX_PS_4K: + nr_pamt_entries = tdmr->size >> PAGE_SHIFT; + break; + case TDX_PS_2M: + nr_pamt_entries = tdmr->size >> PMD_SHIFT; + break; + case TDX_PS_1G: + nr_pamt_entries = tdmr->size >> PUD_SHIFT; + break; + default: + WARN_ON_ONCE(1); + return 0; + } + + pamt_sz = nr_pamt_entries * pamt_entry_size; + /* TDX requires PAMT size must be 4K aligned */ + pamt_sz = ALIGN(pamt_sz, PAGE_SIZE); + + return pamt_sz; +} + +/* + * Locate a NUMA node which should hold the allocation of the @tdmr + * PAMT. This node will have some memory covered by the TDMR. The + * relative amount of memory covered is not considered. + */ +static int tdmr_get_nid(struct tdmr_info *tdmr, struct list_head *tmb_list) +{ + struct tdx_memblock *tmb; + + /* + * A TDMR must cover at least part of one TMB. That TMB will end + * after the TDMR begins. But, that TMB may have started before + * the TDMR. Find the next 'tmb' that _ends_ after this TDMR + * begins. Ignore 'tmb' start addresses. They are irrelevant. + */ + list_for_each_entry(tmb, tmb_list, list) { + if (tmb->end_pfn > PHYS_PFN(tdmr->base)) + return tmb->nid; + } + + /* + * Fall back to allocating the TDMR's metadata from node 0 when + * no TDX memory block can be found. This should never happen + * since TDMRs originate from TDX memory blocks. + */ + pr_warn("TDMR [0x%llx, 0x%llx): unable to find local NUMA node for PAMT allocation, fallback to use node 0.\n", + tdmr->base, tdmr_end(tdmr)); + return 0; +} + +/* + * Allocate PAMTs from the local NUMA node of some memory in @tmb_list + * within @tdmr, and set up PAMTs for @tdmr. + */ +static int tdmr_set_up_pamt(struct tdmr_info *tdmr, + struct list_head *tmb_list, + u16 pamt_entry_size[]) +{ + unsigned long pamt_base[TDX_PS_NR]; + unsigned long pamt_size[TDX_PS_NR]; + unsigned long tdmr_pamt_base; + unsigned long tdmr_pamt_size; + struct page *pamt; + int pgsz, nid; + + nid = tdmr_get_nid(tdmr, tmb_list); + + /* + * Calculate the PAMT size for each TDX supported page size + * and the total PAMT size. + */ + tdmr_pamt_size = 0; + for (pgsz = TDX_PS_4K; pgsz < TDX_PS_NR; pgsz++) { + pamt_size[pgsz] = tdmr_get_pamt_sz(tdmr, pgsz, + pamt_entry_size[pgsz]); + tdmr_pamt_size += pamt_size[pgsz]; + } + + /* + * Allocate one chunk of physically contiguous memory for all + * PAMTs. This helps minimize the PAMT's use of reserved areas + * in overlapped TDMRs. + */ + pamt = alloc_contig_pages(tdmr_pamt_size >> PAGE_SHIFT, GFP_KERNEL, + nid, &node_online_map); + if (!pamt) + return -ENOMEM; + + /* + * Break the contiguous allocation back up into the + * individual PAMTs for each page size. + */ + tdmr_pamt_base = page_to_pfn(pamt) << PAGE_SHIFT; + for (pgsz = TDX_PS_4K; pgsz < TDX_PS_NR; pgsz++) { + pamt_base[pgsz] = tdmr_pamt_base; + tdmr_pamt_base += pamt_size[pgsz]; + } + + tdmr->pamt_4k_base = pamt_base[TDX_PS_4K]; + tdmr->pamt_4k_size = pamt_size[TDX_PS_4K]; + tdmr->pamt_2m_base = pamt_base[TDX_PS_2M]; + tdmr->pamt_2m_size = pamt_size[TDX_PS_2M]; + tdmr->pamt_1g_base = pamt_base[TDX_PS_1G]; + tdmr->pamt_1g_size = pamt_size[TDX_PS_1G]; + + return 0; +} + +static void tdmr_get_pamt(struct tdmr_info *tdmr, unsigned long *pamt_base, + unsigned long *pamt_size) +{ + unsigned long pamt_bs, pamt_sz; + + /* + * The PAMT was allocated in one contiguous unit. The 4K PAMT + * should always point to the beginning of that allocation. + */ + pamt_bs = tdmr->pamt_4k_base; + pamt_sz = tdmr->pamt_4k_size + tdmr->pamt_2m_size + tdmr->pamt_1g_size; + + WARN_ON_ONCE((pamt_bs & ~PAGE_MASK) || (pamt_sz & ~PAGE_MASK)); + + *pamt_base = pamt_bs; + *pamt_size = pamt_sz; +} + +static void tdmr_do_pamt_func(struct tdmr_info *tdmr, + void (*pamt_func)(unsigned long base, unsigned long size)) +{ + unsigned long pamt_base, pamt_size; + + tdmr_get_pamt(tdmr, &pamt_base, &pamt_size); + + /* Do nothing if PAMT hasn't been allocated for this TDMR */ + if (!pamt_size) + return; + + if (WARN_ON_ONCE(!pamt_base)) + return; + + pamt_func(pamt_base, pamt_size); +} + +static void free_pamt(unsigned long pamt_base, unsigned long pamt_size) +{ + free_contig_range(pamt_base >> PAGE_SHIFT, pamt_size >> PAGE_SHIFT); +} + +static void tdmr_free_pamt(struct tdmr_info *tdmr) +{ + tdmr_do_pamt_func(tdmr, free_pamt); +} + +static void tdmrs_free_pamt_all(struct tdmr_info_list *tdmr_list) +{ + int i; + + for (i = 0; i < tdmr_list->nr_consumed_tdmrs; i++) + tdmr_free_pamt(tdmr_entry(tdmr_list, i)); +} + +/* Allocate and set up PAMTs for all TDMRs */ +static int tdmrs_set_up_pamt_all(struct tdmr_info_list *tdmr_list, + struct list_head *tmb_list, + u16 pamt_entry_size[]) +{ + int i, ret = 0; + + for (i = 0; i < tdmr_list->nr_consumed_tdmrs; i++) { + ret = tdmr_set_up_pamt(tdmr_entry(tdmr_list, i), tmb_list, + pamt_entry_size); + if (ret) + goto err; + } + + return 0; +err: + tdmrs_free_pamt_all(tdmr_list); + return ret; +} + +/* + * Convert TDX private pages back to normal by using MOVDIR64B to + * clear these pages. Note this function doesn't flush cache of + * these TDX private pages. The caller should make sure of that. + */ +static void reset_tdx_pages(unsigned long base, unsigned long size) +{ + const void *zero_page = (const void *)page_address(ZERO_PAGE(0)); + unsigned long phys, end; + + end = base + size; + for (phys = base; phys < end; phys += 64) + movdir64b(__va(phys), zero_page); + + /* + * MOVDIR64B uses WC protocol. Use memory barrier to + * make sure any later user of these pages sees the + * updated data. + */ + mb(); +} + +static void tdmr_reset_pamt(struct tdmr_info *tdmr) +{ + tdmr_do_pamt_func(tdmr, reset_tdx_pages); +} + +static void tdmrs_reset_pamt_all(struct tdmr_info_list *tdmr_list) +{ + int i; + + for (i = 0; i < tdmr_list->nr_consumed_tdmrs; i++) + tdmr_reset_pamt(tdmr_entry(tdmr_list, i)); +} + +static unsigned long tdmrs_count_pamt_kb(struct tdmr_info_list *tdmr_list) +{ + unsigned long pamt_size = 0; + int i; + + for (i = 0; i < tdmr_list->nr_consumed_tdmrs; i++) { + unsigned long base, size; + + tdmr_get_pamt(tdmr_entry(tdmr_list, i), &base, &size); + pamt_size += size; + } + + return pamt_size / 1024; +} + +static int tdmr_add_rsvd_area(struct tdmr_info *tdmr, int *p_idx, u64 addr, + u64 size, u16 max_reserved_per_tdmr) +{ + struct tdmr_reserved_area *rsvd_areas = tdmr->reserved_areas; + int idx = *p_idx; + + /* Reserved area must be 4K aligned in offset and size */ + if (WARN_ON(addr & ~PAGE_MASK || size & ~PAGE_MASK)) + return -EINVAL; + + if (idx >= max_reserved_per_tdmr) { + pr_warn("initialization failed: TDMR [0x%llx, 0x%llx): reserved areas exhausted.\n", + tdmr->base, tdmr_end(tdmr)); + return -ENOSPC; + } + + /* + * Consume one reserved area per call. Make no effort to + * optimize or reduce the number of reserved areas which are + * consumed by contiguous reserved areas, for instance. + */ + rsvd_areas[idx].offset = addr - tdmr->base; + rsvd_areas[idx].size = size; + + *p_idx = idx + 1; + + return 0; +} + +/* + * Go through @tmb_list to find holes between memory areas. If any of + * those holes fall within @tdmr, set up a TDMR reserved area to cover + * the hole. + */ +static int tdmr_populate_rsvd_holes(struct list_head *tmb_list, + struct tdmr_info *tdmr, + int *rsvd_idx, + u16 max_reserved_per_tdmr) +{ + struct tdx_memblock *tmb; + u64 prev_end; + int ret; + + /* + * Start looking for reserved blocks at the + * beginning of the TDMR. + */ + prev_end = tdmr->base; + list_for_each_entry(tmb, tmb_list, list) { + u64 start, end; + + start = PFN_PHYS(tmb->start_pfn); + end = PFN_PHYS(tmb->end_pfn); + + /* Break if this region is after the TDMR */ + if (start >= tdmr_end(tdmr)) + break; + + /* Exclude regions before this TDMR */ + if (end < tdmr->base) + continue; + + /* + * Skip over memory areas that + * have already been dealt with. + */ + if (start <= prev_end) { + prev_end = end; + continue; + } + + /* Add the hole before this region */ + ret = tdmr_add_rsvd_area(tdmr, rsvd_idx, prev_end, + start - prev_end, + max_reserved_per_tdmr); + if (ret) + return ret; + + prev_end = end; + } + + /* Add the hole after the last region if it exists. */ + if (prev_end < tdmr_end(tdmr)) { + ret = tdmr_add_rsvd_area(tdmr, rsvd_idx, prev_end, + tdmr_end(tdmr) - prev_end, + max_reserved_per_tdmr); + if (ret) + return ret; + } + + return 0; +} + +/* + * Go through @tdmr_list to find all PAMTs. If any of those PAMTs + * overlaps with @tdmr, set up a TDMR reserved area to cover the + * overlapping part. + */ +static int tdmr_populate_rsvd_pamts(struct tdmr_info_list *tdmr_list, + struct tdmr_info *tdmr, + int *rsvd_idx, + u16 max_reserved_per_tdmr) +{ + int i, ret; + + for (i = 0; i < tdmr_list->nr_consumed_tdmrs; i++) { + struct tdmr_info *tmp = tdmr_entry(tdmr_list, i); + unsigned long pamt_base, pamt_size, pamt_end; + + tdmr_get_pamt(tmp, &pamt_base, &pamt_size); + /* Each TDMR must already have PAMT allocated */ + WARN_ON_ONCE(!pamt_size || !pamt_base); + + pamt_end = pamt_base + pamt_size; + /* Skip PAMTs outside of the given TDMR */ + if ((pamt_end <= tdmr->base) || + (pamt_base >= tdmr_end(tdmr))) + continue; + + /* Only mark the part within the TDMR as reserved */ + if (pamt_base < tdmr->base) + pamt_base = tdmr->base; + if (pamt_end > tdmr_end(tdmr)) + pamt_end = tdmr_end(tdmr); + + ret = tdmr_add_rsvd_area(tdmr, rsvd_idx, pamt_base, + pamt_end - pamt_base, + max_reserved_per_tdmr); + if (ret) + return ret; + } + + return 0; +} + +/* Compare function called by sort() for TDMR reserved areas */ +static int rsvd_area_cmp_func(const void *a, const void *b) +{ + struct tdmr_reserved_area *r1 = (struct tdmr_reserved_area *)a; + struct tdmr_reserved_area *r2 = (struct tdmr_reserved_area *)b; + + if (r1->offset + r1->size <= r2->offset) + return -1; + if (r1->offset >= r2->offset + r2->size) + return 1; + + /* Reserved areas cannot overlap. The caller must guarantee. */ + WARN_ON_ONCE(1); + return -1; +} + +/* + * Populate reserved areas for the given @tdmr, including memory holes + * (via @tmb_list) and PAMTs (via @tdmr_list). + */ +static int tdmr_populate_rsvd_areas(struct tdmr_info *tdmr, + struct list_head *tmb_list, + struct tdmr_info_list *tdmr_list, + u16 max_reserved_per_tdmr) +{ + int ret, rsvd_idx = 0; + + ret = tdmr_populate_rsvd_holes(tmb_list, tdmr, &rsvd_idx, + max_reserved_per_tdmr); + if (ret) + return ret; + + ret = tdmr_populate_rsvd_pamts(tdmr_list, tdmr, &rsvd_idx, + max_reserved_per_tdmr); + if (ret) + return ret; + + /* TDX requires reserved areas listed in address ascending order */ + sort(tdmr->reserved_areas, rsvd_idx, sizeof(struct tdmr_reserved_area), + rsvd_area_cmp_func, NULL); + + return 0; +} + +/* + * Populate reserved areas for all TDMRs in @tdmr_list, including memory + * holes (via @tmb_list) and PAMTs. + */ +static int tdmrs_populate_rsvd_areas_all(struct tdmr_info_list *tdmr_list, + struct list_head *tmb_list, + u16 max_reserved_per_tdmr) +{ + int i; + + for (i = 0; i < tdmr_list->nr_consumed_tdmrs; i++) { + int ret; + + ret = tdmr_populate_rsvd_areas(tdmr_entry(tdmr_list, i), + tmb_list, tdmr_list, max_reserved_per_tdmr); + if (ret) + return ret; + } + + return 0; +} + +/* + * Construct a list of TDMRs on the preallocated space in @tdmr_list + * to cover all TDX memory regions in @tmb_list based on the TDX module + * TDMR global information in @tdmr_sysinfo. + */ +static int construct_tdmrs(struct list_head *tmb_list, + struct tdmr_info_list *tdmr_list, + struct tdx_tdmr_sysinfo *tdmr_sysinfo) +{ + int ret; + + ret = fill_out_tdmrs(tmb_list, tdmr_list); + if (ret) + return ret; + + ret = tdmrs_set_up_pamt_all(tdmr_list, tmb_list, + tdmr_sysinfo->pamt_entry_size); + if (ret) + return ret; + + ret = tdmrs_populate_rsvd_areas_all(tdmr_list, tmb_list, + tdmr_sysinfo->max_reserved_per_tdmr); + if (ret) + tdmrs_free_pamt_all(tdmr_list); + + /* + * The tdmr_info_list is read-only from here on out. + * Ensure that these writes are seen by other CPUs. + * Pairs with a smp_rmb() in is_pamt_page(). + */ + smp_wmb(); + + return ret; +} + +static int config_tdx_module(struct tdmr_info_list *tdmr_list, u64 global_keyid) +{ + struct tdx_module_args args = {}; + u64 *tdmr_pa_array; + size_t array_sz; + int i, ret; + + /* + * TDMRs are passed to the TDX module via an array of physical + * addresses of each TDMR. The array itself also has certain + * alignment requirement. + */ + array_sz = tdmr_list->nr_consumed_tdmrs * sizeof(u64); + array_sz = roundup_pow_of_two(array_sz); + if (array_sz < TDMR_INFO_PA_ARRAY_ALIGNMENT) + array_sz = TDMR_INFO_PA_ARRAY_ALIGNMENT; + + tdmr_pa_array = kzalloc(array_sz, GFP_KERNEL); + if (!tdmr_pa_array) + return -ENOMEM; + + for (i = 0; i < tdmr_list->nr_consumed_tdmrs; i++) + tdmr_pa_array[i] = __pa(tdmr_entry(tdmr_list, i)); + + args.rcx = __pa(tdmr_pa_array); + args.rdx = tdmr_list->nr_consumed_tdmrs; + args.r8 = global_keyid; + ret = seamcall_prerr(TDH_SYS_CONFIG, &args); + + /* Free the array as it is not required anymore. */ + kfree(tdmr_pa_array); + + return ret; +} + +static int do_global_key_config(void *unused) +{ + struct tdx_module_args args = {}; + + return seamcall_prerr(TDH_SYS_KEY_CONFIG, &args); +} + +/* + * Attempt to configure the global KeyID on all physical packages. + * + * This requires running code on at least one CPU in each package. + * TDMR initialization) will fail will fail if any package in the + * system has no online CPUs. + * + * This code takes no affirmative steps to online CPUs. Callers (aka. + * KVM) can ensure success by ensuring sufficient CPUs are online and + * can run SEAMCALLs. + */ +static int config_global_keyid(void) +{ + cpumask_var_t packages; + int cpu, ret = -EINVAL; + + if (!zalloc_cpumask_var(&packages, GFP_KERNEL)) + return -ENOMEM; + + /* + * Hardware doesn't guarantee cache coherency across different + * KeyIDs. The kernel needs to flush PAMT's dirty cachelines + * (associated with KeyID 0) before the TDX module can use the + * global KeyID to access the PAMT. Given PAMTs are potentially + * large (~1/256th of system RAM), just use WBINVD. + */ + wbinvd_on_all_cpus(); + + for_each_online_cpu(cpu) { + /* + * The key configuration only needs to be done once per + * package and will return an error if configured more + * than once. Avoid doing it multiple times per package. + */ + if (cpumask_test_and_set_cpu(topology_physical_package_id(cpu), + packages)) + continue; + + /* + * TDH.SYS.KEY.CONFIG cannot run concurrently on + * different cpus. Do it one by one. + */ + ret = smp_call_on_cpu(cpu, do_global_key_config, NULL, true); + if (ret) + break; + } + + free_cpumask_var(packages); + return ret; +} + +static int init_tdmr(struct tdmr_info *tdmr) +{ + u64 next; + + /* + * Initializing a TDMR can be time consuming. To avoid long + * SEAMCALLs, the TDX module may only initialize a part of the + * TDMR in each call. + */ + do { + struct tdx_module_args args = { + .rcx = tdmr->base, + }; + int ret; + + ret = seamcall_prerr_ret(TDH_SYS_TDMR_INIT, &args); + if (ret) + return ret; + /* + * RDX contains 'next-to-initialize' address if + * TDH.SYS.TDMR.INIT did not fully complete and + * should be retried. + */ + next = args.rdx; + cond_resched(); + /* Keep making SEAMCALLs until the TDMR is done */ + } while (next < tdmr->base + tdmr->size); + + return 0; +} + +static int init_tdmrs(struct tdmr_info_list *tdmr_list) +{ + int i; + + /* + * This operation is costly. It can be parallelized, + * but keep it simple for now. + */ + for (i = 0; i < tdmr_list->nr_consumed_tdmrs; i++) { + int ret; + + ret = init_tdmr(tdmr_entry(tdmr_list, i)); + if (ret) + return ret; + } + + return 0; +} + +static int init_tdx_module(void) +{ + struct tdx_tdmr_sysinfo tdmr_sysinfo; + int ret; + + /* + * To keep things simple, assume that all TDX-protected memory + * will come from the page allocator. Make sure all pages in the + * page allocator are TDX-usable memory. + * + * Build the list of "TDX-usable" memory regions which cover all + * pages in the page allocator to guarantee that. Do it while + * holding mem_hotplug_lock read-lock as the memory hotplug code + * path reads the @tdx_memlist to reject any new memory. + */ + get_online_mems(); + + ret = build_tdx_memlist(&tdx_memlist); + if (ret) + goto out_put_tdxmem; + + ret = get_tdx_tdmr_sysinfo(&tdmr_sysinfo); + if (ret) + goto err_free_tdxmem; + + /* Allocate enough space for constructing TDMRs */ + ret = alloc_tdmr_list(&tdx_tdmr_list, &tdmr_sysinfo); + if (ret) + goto err_free_tdxmem; + + /* Cover all TDX-usable memory regions in TDMRs */ + ret = construct_tdmrs(&tdx_memlist, &tdx_tdmr_list, &tdmr_sysinfo); + if (ret) + goto err_free_tdmrs; + + /* Pass the TDMRs and the global KeyID to the TDX module */ + ret = config_tdx_module(&tdx_tdmr_list, tdx_global_keyid); + if (ret) + goto err_free_pamts; + + /* Config the key of global KeyID on all packages */ + ret = config_global_keyid(); + if (ret) + goto err_reset_pamts; + + /* Initialize TDMRs to complete the TDX module initialization */ + ret = init_tdmrs(&tdx_tdmr_list); + if (ret) + goto err_reset_pamts; + + pr_info("%lu KB allocated for PAMT\n", tdmrs_count_pamt_kb(&tdx_tdmr_list)); + +out_put_tdxmem: + /* + * @tdx_memlist is written here and read at memory hotplug time. + * Lock out memory hotplug code while building it. + */ + put_online_mems(); + return ret; + +err_reset_pamts: + /* + * Part of PAMTs may already have been initialized by the + * TDX module. Flush cache before returning PAMTs back + * to the kernel. + */ + wbinvd_on_all_cpus(); + /* + * According to the TDX hardware spec, if the platform + * doesn't have the "partial write machine check" + * erratum, any kernel read/write will never cause #MC + * in kernel space, thus it's OK to not convert PAMTs + * back to normal. But do the conversion anyway here + * as suggested by the TDX spec. + */ + tdmrs_reset_pamt_all(&tdx_tdmr_list); +err_free_pamts: + tdmrs_free_pamt_all(&tdx_tdmr_list); +err_free_tdmrs: + free_tdmr_list(&tdx_tdmr_list); +err_free_tdxmem: + free_tdx_memlist(&tdx_memlist); + goto out_put_tdxmem; +} + +static int __tdx_enable(void) +{ + int ret; + + ret = init_tdx_module(); + if (ret) { + pr_err("module initialization failed (%d)\n", ret); + tdx_module_status = TDX_MODULE_ERROR; + return ret; + } + + pr_info("module initialized\n"); + tdx_module_status = TDX_MODULE_INITIALIZED; + + return 0; +} + +/** + * tdx_enable - Enable TDX module to make it ready to run TDX guests + * + * This function assumes the caller has: 1) held read lock of CPU hotplug + * lock to prevent any new cpu from becoming online; 2) done both VMXON + * and tdx_cpu_enable() on all online cpus. + * + * This function requires there's at least one online cpu for each CPU + * package to succeed. + * + * This function can be called in parallel by multiple callers. + * + * Return 0 if TDX is enabled successfully, otherwise error. + */ +int tdx_enable(void) +{ + int ret; + + if (!boot_cpu_has(X86_FEATURE_TDX_HOST_PLATFORM)) + return -ENODEV; + + lockdep_assert_cpus_held(); + + mutex_lock(&tdx_module_lock); + + switch (tdx_module_status) { + case TDX_MODULE_UNINITIALIZED: + ret = __tdx_enable(); + break; + case TDX_MODULE_INITIALIZED: + /* Already initialized, great, tell the caller. */ + ret = 0; + break; + default: + /* Failed to initialize in the previous attempts */ + ret = -EINVAL; + break; + } + + mutex_unlock(&tdx_module_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(tdx_enable); + +static bool is_pamt_page(unsigned long phys) +{ + struct tdmr_info_list *tdmr_list = &tdx_tdmr_list; + int i; + + /* Ensure that all remote 'tdmr_list' writes are visible: */ + smp_rmb(); + + /* + * The TDX module is no longer returning TDX_SYS_NOT_READY and + * is initialized. The 'tdmr_list' was initialized long ago + * and is now read-only. + */ + for (i = 0; i < tdmr_list->nr_consumed_tdmrs; i++) { + unsigned long base, size; + + tdmr_get_pamt(tdmr_entry(tdmr_list, i), &base, &size); + + if (phys >= base && phys < (base + size)) + return true; + } + + return false; +} + +/* + * Return whether the memory page at the given physical address is TDX + * private memory or not. + * + * This can be imprecise for two known reasons: + * 1. PAMTs are private memory and exist before the TDX module is + * ready and TDH_PHYMEM_PAGE_RDMD works. This is a relatively + * short window that occurs once per boot. + * 2. TDH_PHYMEM_PAGE_RDMD reflects the TDX module's knowledge of the + * page. However, the page can still cause #MC until it has been + * fully converted to shared using 64-byte writes like MOVDIR64B. + * Buggy hosts might still leave #MC-causing memory in place which + * this function can not detect. + */ +static bool paddr_is_tdx_private(unsigned long phys) +{ + struct tdx_module_args args = { + .rcx = phys & PAGE_MASK, + }; + u64 sret; + + if (!boot_cpu_has(X86_FEATURE_TDX_HOST_PLATFORM)) + return false; + + /* Get page type from the TDX module */ + sret = __seamcall_ret(TDH_PHYMEM_PAGE_RDMD, &args); + + /* + * The SEAMCALL will not return success unless there is a + * working, "ready" TDX module. Assume an absence of TDX + * private pages until SEAMCALL is working. + */ + if (sret) + return false; + + /* + * SEAMCALL was successful -- read page type (via RCX): + * + * - PT_NDA: Page is not used by the TDX module + * - PT_RSVD: Reserved for Non-TDX use + * - Others: Page is used by the TDX module + * + * Note PAMT pages are marked as PT_RSVD but they are also TDX + * private memory. + */ + switch (args.rcx) { + case PT_NDA: + return false; + case PT_RSVD: + return is_pamt_page(phys); + default: + return true; + } +} + +/* + * Some TDX-capable CPUs have an erratum. A write to TDX private + * memory poisons that memory, and a subsequent read of that memory + * triggers #MC. + * + * Help distinguish erratum-triggered #MCs from a normal hardware one. + * Just print additional message to show such #MC may be result of the + * erratum. + */ +const char *tdx_dump_mce_info(struct mce *m) +{ + if (!m || !mce_is_memory_error(m) || !mce_usable_address(m)) + return NULL; + + if (!paddr_is_tdx_private(m->addr)) + return NULL; + + return "TDX private memory error. Possible kernel bug."; +} + +static __init int record_keyid_partitioning(u32 *tdx_keyid_start, + u32 *nr_tdx_keyids) +{ + u32 _nr_mktme_keyids, _tdx_keyid_start, _nr_tdx_keyids; + int ret; + + /* + * IA32_MKTME_KEYID_PARTIONING: + * Bit [31:0]: Number of MKTME KeyIDs. + * Bit [63:32]: Number of TDX private KeyIDs. + */ + ret = rdmsr_safe(MSR_IA32_MKTME_KEYID_PARTITIONING, &_nr_mktme_keyids, + &_nr_tdx_keyids); + if (ret || !_nr_tdx_keyids) + return -EINVAL; + + /* TDX KeyIDs start after the last MKTME KeyID. */ + _tdx_keyid_start = _nr_mktme_keyids + 1; + + *tdx_keyid_start = _tdx_keyid_start; + *nr_tdx_keyids = _nr_tdx_keyids; + + return 0; +} + +static bool is_tdx_memory(unsigned long start_pfn, unsigned long end_pfn) +{ + struct tdx_memblock *tmb; + + /* + * This check assumes that the start_pfn<->end_pfn range does not + * cross multiple @tdx_memlist entries. A single memory online + * event across multiple memblocks (from which @tdx_memlist + * entries are derived at the time of module initialization) is + * not possible. This is because memory offline/online is done + * on granularity of 'struct memory_block', and the hotpluggable + * memory region (one memblock) must be multiple of memory_block. + */ + list_for_each_entry(tmb, &tdx_memlist, list) { + if (start_pfn >= tmb->start_pfn && end_pfn <= tmb->end_pfn) + return true; + } + return false; +} + +static int tdx_memory_notifier(struct notifier_block *nb, unsigned long action, + void *v) +{ + struct memory_notify *mn = v; + + if (action != MEM_GOING_ONLINE) + return NOTIFY_OK; + + /* + * Empty list means TDX isn't enabled. Allow any memory + * to go online. + */ + if (list_empty(&tdx_memlist)) + return NOTIFY_OK; + + /* + * The TDX memory configuration is static and can not be + * changed. Reject onlining any memory which is outside of + * the static configuration whether it supports TDX or not. + */ + if (is_tdx_memory(mn->start_pfn, mn->start_pfn + mn->nr_pages)) + return NOTIFY_OK; + + return NOTIFY_BAD; +} + +static struct notifier_block tdx_memory_nb = { + .notifier_call = tdx_memory_notifier, +}; + +static void __init check_tdx_erratum(void) +{ + /* + * These CPUs have an erratum. A partial write from non-TD + * software (e.g. via MOVNTI variants or UC/WC mapping) to TDX + * private memory poisons that memory, and a subsequent read of + * that memory triggers #MC. + */ + switch (boot_cpu_data.x86_model) { + case INTEL_FAM6_SAPPHIRERAPIDS_X: + case INTEL_FAM6_EMERALDRAPIDS_X: + setup_force_cpu_bug(X86_BUG_TDX_PW_MCE); + } +} + +void __init tdx_init(void) +{ + u32 tdx_keyid_start, nr_tdx_keyids; + int err; + + err = record_keyid_partitioning(&tdx_keyid_start, &nr_tdx_keyids); + if (err) + return; + + pr_info("BIOS enabled: private KeyID range [%u, %u)\n", + tdx_keyid_start, tdx_keyid_start + nr_tdx_keyids); + + /* + * The TDX module itself requires one 'global KeyID' to protect + * its metadata. If there's only one TDX KeyID, there won't be + * any left for TDX guests thus there's no point to enable TDX + * at all. + */ + if (nr_tdx_keyids < 2) { + pr_err("initialization failed: too few private KeyIDs available.\n"); + return; + } + + /* + * At this point, hibernation_available() indicates whether or + * not hibernation support has been permanently disabled. + */ + if (hibernation_available()) { + pr_err("initialization failed: Hibernation support is enabled\n"); + return; + } + + err = register_memory_notifier(&tdx_memory_nb); + if (err) { + pr_err("initialization failed: register_memory_notifier() failed (%d)\n", + err); + return; + } + +#if defined(CONFIG_ACPI) && defined(CONFIG_SUSPEND) + pr_info("Disable ACPI S3. Turn off TDX in the BIOS to use ACPI S3.\n"); + acpi_suspend_lowlevel = NULL; +#endif + + /* + * Just use the first TDX KeyID as the 'global KeyID' and + * leave the rest for TDX guests. + */ + tdx_global_keyid = tdx_keyid_start; + tdx_guest_keyid_start = tdx_keyid_start + 1; + tdx_nr_guest_keyids = nr_tdx_keyids - 1; + + setup_force_cpu_cap(X86_FEATURE_TDX_HOST_PLATFORM); + + check_tdx_erratum(); +} diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h new file mode 100644 index 00000000000000..b701f69485d323 --- /dev/null +++ b/arch/x86/virt/vmx/tdx/tdx.h @@ -0,0 +1,121 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _X86_VIRT_TDX_H +#define _X86_VIRT_TDX_H + +#include + +/* + * This file contains both macros and data structures defined by the TDX + * architecture and Linux defined software data structures and functions. + * The two should not be mixed together for better readability. The + * architectural definitions come first. + */ + +/* + * TDX module SEAMCALL leaf functions + */ +#define TDH_PHYMEM_PAGE_RDMD 24 +#define TDH_SYS_KEY_CONFIG 31 +#define TDH_SYS_INIT 33 +#define TDH_SYS_RD 34 +#define TDH_SYS_LP_INIT 35 +#define TDH_SYS_TDMR_INIT 36 +#define TDH_SYS_CONFIG 45 + +/* TDX page types */ +#define PT_NDA 0x0 +#define PT_RSVD 0x1 + +/* + * Global scope metadata field ID. + * + * See Table "Global Scope Metadata", TDX module 1.5 ABI spec. + */ +#define MD_FIELD_ID_MAX_TDMRS 0x9100000100000008ULL +#define MD_FIELD_ID_MAX_RESERVED_PER_TDMR 0x9100000100000009ULL +#define MD_FIELD_ID_PAMT_4K_ENTRY_SIZE 0x9100000100000010ULL +#define MD_FIELD_ID_PAMT_2M_ENTRY_SIZE 0x9100000100000011ULL +#define MD_FIELD_ID_PAMT_1G_ENTRY_SIZE 0x9100000100000012ULL + +/* + * Sub-field definition of metadata field ID. + * + * See Table "MD_FIELD_ID (Metadata Field Identifier / Sequence Header) + * Definition", TDX module 1.5 ABI spec. + * + * - Bit 33:32: ELEMENT_SIZE_CODE -- size of a single element of metadata + * + * 0: 8 bits + * 1: 16 bits + * 2: 32 bits + * 3: 64 bits + */ +#define MD_FIELD_ID_ELE_SIZE_CODE(_field_id) \ + (((_field_id) & GENMASK_ULL(33, 32)) >> 32) + +#define MD_FIELD_ID_ELE_SIZE_16BIT 1 + +struct tdmr_reserved_area { + u64 offset; + u64 size; +} __packed; + +#define TDMR_INFO_ALIGNMENT 512 +#define TDMR_INFO_PA_ARRAY_ALIGNMENT 512 + +struct tdmr_info { + u64 base; + u64 size; + u64 pamt_1g_base; + u64 pamt_1g_size; + u64 pamt_2m_base; + u64 pamt_2m_size; + u64 pamt_4k_base; + u64 pamt_4k_size; + /* + * The actual number of reserved areas depends on the value of + * field MD_FIELD_ID_MAX_RESERVED_PER_TDMR in the TDX module + * global metadata. + */ + DECLARE_FLEX_ARRAY(struct tdmr_reserved_area, reserved_areas); +} __packed __aligned(TDMR_INFO_ALIGNMENT); + +/* + * Do not put any hardware-defined TDX structure representations below + * this comment! + */ + +/* Kernel defined TDX module status during module initialization. */ +enum tdx_module_status_t { + TDX_MODULE_UNINITIALIZED, + TDX_MODULE_INITIALIZED, + TDX_MODULE_ERROR +}; + +struct tdx_memblock { + struct list_head list; + unsigned long start_pfn; + unsigned long end_pfn; + int nid; +}; + +/* "TDMR info" part of "Global Scope Metadata" for constructing TDMRs */ +struct tdx_tdmr_sysinfo { + u16 max_tdmrs; + u16 max_reserved_per_tdmr; + u16 pamt_entry_size[TDX_PS_NR]; +}; + +/* Warn if kernel has less than TDMR_NR_WARN TDMRs after allocation */ +#define TDMR_NR_WARN 4 + +struct tdmr_info_list { + void *tdmrs; /* Flexible array to hold 'tdmr_info's */ + int nr_consumed_tdmrs; /* How many 'tdmr_info's are in use */ + + /* Metadata for finding target 'tdmr_info' and freeing @tdmrs */ + int tdmr_sz; /* Size of one 'tdmr_info' */ + int max_tdmrs; /* How many 'tdmr_info's are allocated */ +}; + +#endif diff --git a/arch/x86/xen/irq.c b/arch/x86/xen/irq.c index 6092fea7d65164..39982f955cfe93 100644 --- a/arch/x86/xen/irq.c +++ b/arch/x86/xen/irq.c @@ -45,7 +45,7 @@ static const typeof(pv_ops) xen_irq_ops __initconst = { /* Initial interrupt flag handling only called while interrupts off. */ .save_fl = __PV_IS_CALLEE_SAVE(paravirt_ret0), .irq_disable = __PV_IS_CALLEE_SAVE(paravirt_nop), - .irq_enable = __PV_IS_CALLEE_SAVE(paravirt_BUG), + .irq_enable = __PV_IS_CALLEE_SAVE(BUG_func), .safe_halt = xen_safe_halt, .halt = xen_halt, diff --git a/arch/x86/xen/mmu_pv.c b/arch/x86/xen/mmu_pv.c index b6830554ff6905..72af496a160c8b 100644 --- a/arch/x86/xen/mmu_pv.c +++ b/arch/x86/xen/mmu_pv.c @@ -34,7 +34,7 @@ * would need to validate the whole pagetable before going on. * Naturally, this is quite slow. The solution is to "pin" a * pagetable, which enforces all the constraints on the pagetable even - * when it is not actively in use. This menas that Xen can be assured + * when it is not actively in use. This means that Xen can be assured * that it is still valid when you do load it into %cr3, and doesn't * need to revalidate it. * diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index 7d792077e5fdc7..6f248d87e496aa 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -144,7 +144,7 @@ config XTENSA_VARIANT_CUSTOM_NAME depends on XTENSA_VARIANT_CUSTOM help Provide the name of a custom Xtensa processor variant. - This CORENAME selects arch/xtensa/variant/CORENAME. + This CORENAME selects arch/xtensa/variants/CORENAME. Don't forget you have to select MMU if you have one. config XTENSA_VARIANT_NAME @@ -793,7 +793,7 @@ config ARCH_FORCE_MAX_ORDER default "10" help The kernel page allocator limits the size of maximal physically - contiguous allocations. The limit is called MAX_ORDER and it + contiguous allocations. The limit is called MAX_PAGE_ORDER and it defines the maximal power of two of number of pages that can be allocated as a single contiguous block. This option allows overriding the default setting when ability to allocate very diff --git a/arch/xtensa/Makefile b/arch/xtensa/Makefile index bfd8e433ed621e..4c14a02179eba5 100644 --- a/arch/xtensa/Makefile +++ b/arch/xtensa/Makefile @@ -35,15 +35,19 @@ KBUILD_CFLAGS += -ffreestanding -D__linux__ KBUILD_CFLAGS += -pipe -mlongcalls -mtext-section-literals KBUILD_CFLAGS += $(call cc-option,-mforce-no-pic,) KBUILD_CFLAGS += $(call cc-option,-mno-serialize-volatile,) +KBUILD_CFLAGS += $(call cc-option,-mno-fdpic,) ifneq ($(CONFIG_KERNEL_ABI_CALL0),) KBUILD_CFLAGS += -mabi=call0 KBUILD_AFLAGS += -mabi=call0 endif KBUILD_AFLAGS += -mlongcalls -mtext-section-literals +KBUILD_AFLAGS += $(call cc-option,-mno-fdpic,) + +KBUILD_LDFLAGS += -m elf32xtensa ifneq ($(CONFIG_LD_NO_RELAX),) -KBUILD_LDFLAGS := --no-relax +KBUILD_LDFLAGS += --no-relax endif CHECKFLAGS += -D$(if $(CONFIG_CPU_BIG_ENDIAN),__XTENSA_EB__,__XTENSA_EL__) diff --git a/arch/xtensa/include/asm/asmmacro.h b/arch/xtensa/include/asm/asmmacro.h index 01bf7d9dbb1910..a52d49a16ce7d0 100644 --- a/arch/xtensa/include/asm/asmmacro.h +++ b/arch/xtensa/include/asm/asmmacro.h @@ -11,7 +11,7 @@ #ifndef _XTENSA_ASMMACRO_H #define _XTENSA_ASMMACRO_H -#include +#include #include /* diff --git a/arch/xtensa/include/asm/cacheflush.h b/arch/xtensa/include/asm/cacheflush.h index 785a00ce83c11e..38bcecb0e457d9 100644 --- a/arch/xtensa/include/asm/cacheflush.h +++ b/arch/xtensa/include/asm/cacheflush.h @@ -116,8 +116,9 @@ void flush_cache_page(struct vm_area_struct*, #define flush_cache_mm(mm) flush_cache_all() #define flush_cache_dup_mm(mm) flush_cache_mm(mm) -#define flush_cache_vmap(start,end) flush_cache_all() -#define flush_cache_vunmap(start,end) flush_cache_all() +#define flush_cache_vmap(start,end) flush_cache_all() +#define flush_cache_vmap_early(start,end) do { } while (0) +#define flush_cache_vunmap(start,end) flush_cache_all() void flush_dcache_folio(struct folio *folio); #define flush_dcache_folio flush_dcache_folio @@ -140,6 +141,7 @@ void local_flush_cache_page(struct vm_area_struct *vma, #define flush_cache_dup_mm(mm) do { } while (0) #define flush_cache_vmap(start,end) do { } while (0) +#define flush_cache_vmap_early(start,end) do { } while (0) #define flush_cache_vunmap(start,end) do { } while (0) #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0 diff --git a/arch/xtensa/include/asm/kasan.h b/arch/xtensa/include/asm/kasan.h index 216b6f32c37596..8d2b4248466fd5 100644 --- a/arch/xtensa/include/asm/kasan.h +++ b/arch/xtensa/include/asm/kasan.h @@ -18,6 +18,8 @@ #define KASAN_SHADOW_START (XCHAL_PAGE_TABLE_VADDR + XCHAL_PAGE_TABLE_SIZE) /* Size of the shadow map */ #define KASAN_SHADOW_SIZE (-KASAN_START_VADDR >> KASAN_SHADOW_SCALE_SHIFT) +/* End of the shadow map */ +#define KASAN_SHADOW_END (KASAN_SHADOW_START + KASAN_SHADOW_SIZE) /* Offset for mem to shadow address transformation */ #define KASAN_SHADOW_OFFSET __XTENSA_UL_CONST(CONFIG_KASAN_SHADOW_OFFSET) diff --git a/arch/xtensa/kernel/syscalls/syscall.tbl b/arch/xtensa/kernel/syscalls/syscall.tbl index 06eefa9c145886..dd116598fb2517 100644 --- a/arch/xtensa/kernel/syscalls/syscall.tbl +++ b/arch/xtensa/kernel/syscalls/syscall.tbl @@ -427,3 +427,8 @@ 454 common futex_wake sys_futex_wake 455 common futex_wait sys_futex_wait 456 common futex_requeue sys_futex_requeue +457 common statmount sys_statmount +458 common listmount sys_listmount +459 common lsm_get_self_attr sys_lsm_get_self_attr +460 common lsm_set_self_attr sys_lsm_set_self_attr +461 common lsm_list_modules sys_lsm_list_modules diff --git a/arch/xtensa/lib/pci-auto.c b/arch/xtensa/lib/pci-auto.c index aa6752237985af..05fc02f9e1c78b 100644 --- a/arch/xtensa/lib/pci-auto.c +++ b/arch/xtensa/lib/pci-auto.c @@ -11,6 +11,7 @@ * Based on work from Matt Porter */ +#include #include #include #include @@ -222,10 +223,11 @@ pciauto_postscan_setup_bridge(struct pci_dev *dev, int current_bus, int sub_bus, int __init pciauto_bus_scan(struct pci_controller *pci_ctrl, int current_bus) { - int sub_bus, pci_devfn, pci_class, cmdstat, found_multi=0; + int sub_bus, pci_devfn, pci_class, cmdstat; unsigned short vid; unsigned char header_type; struct pci_dev *dev = &pciauto_dev; + bool found_multi = false; pciauto_dev.bus = &pciauto_bus; pciauto_dev.sysdata = pci_ctrl; @@ -261,11 +263,11 @@ int __init pciauto_bus_scan(struct pci_controller *pci_ctrl, int current_bus) continue; if (!PCI_FUNC(pci_devfn)) - found_multi = header_type & 0x80; + found_multi = FIELD_GET(PCI_HEADER_TYPE_MFD, header_type); pci_read_config_word(dev, PCI_VENDOR_ID, &vid); if (vid == 0xffff || vid == 0x0000) { - found_multi = 0; + found_multi = false; continue; } diff --git a/arch/xtensa/platforms/iss/console.c b/arch/xtensa/platforms/iss/console.c index 7d1f8b398a464d..8896e691c051ea 100644 --- a/arch/xtensa/platforms/iss/console.c +++ b/arch/xtensa/platforms/iss/console.c @@ -65,7 +65,7 @@ static void rs_poll(struct timer_list *unused) struct tty_port *port = &serial_port; int i = 0; int rd = 1; - unsigned char c; + u8 c; while (simc_poll(0)) { rd = simc_read(0, &c, 1); diff --git a/block/Kconfig b/block/Kconfig index 55ae2286a4ded1..1de4682d48ccbd 100644 --- a/block/Kconfig +++ b/block/Kconfig @@ -78,6 +78,26 @@ config BLK_DEV_INTEGRITY_T10 select CRC_T10DIF select CRC64_ROCKSOFT +config BLK_DEV_WRITE_MOUNTED + bool "Allow writing to mounted block devices" + default y + help + When a block device is mounted, writing to its buffer cache is very + likely going to cause filesystem corruption. It is also rather easy to + crash the kernel in this way since the filesystem has no practical way + of detecting these writes to buffer cache and verifying its metadata + integrity. However there are some setups that need this capability + like running fsck on read-only mounted root device, modifying some + features on mounted ext4 filesystem, and similar. If you say N, the + kernel will prevent processes from writing to block devices that are + mounted by filesystems which provides some more protection from runaway + privileged processes and generally makes it much harder to crash + filesystem drivers. Note however that this does not prevent + underlying device(s) from being modified by other means, e.g. by + directly submitting SCSI commands or through access to lower layers of + storage stack. If in doubt, say Y. The configuration can be overridden + with the bdev_allow_write_mounted boot option. + config BLK_DEV_ZONED bool "Zoned block device support" select MQ_IOSCHED_DEADLINE diff --git a/block/bdev.c b/block/bdev.c index 750aec178b6abf..e9f1b12bd75c7b 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -30,6 +30,9 @@ #include "../fs/internal.h" #include "blk.h" +/* Should we allow writing to mounted block devices? */ +static bool bdev_allow_write_mounted = IS_ENABLED(CONFIG_BLK_DEV_WRITE_MOUNTED); + struct bdev_inode { struct block_device bdev; struct inode vfs_inode; @@ -207,85 +210,88 @@ int sync_blockdev_range(struct block_device *bdev, loff_t lstart, loff_t lend) EXPORT_SYMBOL(sync_blockdev_range); /** - * freeze_bdev - lock a filesystem and force it into a consistent state + * bdev_freeze - lock a filesystem and force it into a consistent state * @bdev: blockdevice to lock * * If a superblock is found on this device, we take the s_umount semaphore * on it to make sure nobody unmounts until the snapshot creation is done. * The reference counter (bd_fsfreeze_count) guarantees that only the last * unfreeze process can unfreeze the frozen filesystem actually when multiple - * freeze requests arrive simultaneously. It counts up in freeze_bdev() and - * count down in thaw_bdev(). When it becomes 0, thaw_bdev() will unfreeze + * freeze requests arrive simultaneously. It counts up in bdev_freeze() and + * count down in bdev_thaw(). When it becomes 0, thaw_bdev() will unfreeze * actually. + * + * Return: On success zero is returned, negative error code on failure. */ -int freeze_bdev(struct block_device *bdev) +int bdev_freeze(struct block_device *bdev) { - struct super_block *sb; int error = 0; mutex_lock(&bdev->bd_fsfreeze_mutex); - if (++bdev->bd_fsfreeze_count > 1) - goto done; - - sb = get_active_super(bdev); - if (!sb) - goto sync; - if (sb->s_op->freeze_super) - error = sb->s_op->freeze_super(sb, FREEZE_HOLDER_USERSPACE); - else - error = freeze_super(sb, FREEZE_HOLDER_USERSPACE); - deactivate_super(sb); - if (error) { - bdev->bd_fsfreeze_count--; - goto done; + if (atomic_inc_return(&bdev->bd_fsfreeze_count) > 1) { + mutex_unlock(&bdev->bd_fsfreeze_mutex); + return 0; } - bdev->bd_fsfreeze_sb = sb; -sync: - sync_blockdev(bdev); -done: + mutex_lock(&bdev->bd_holder_lock); + if (bdev->bd_holder_ops && bdev->bd_holder_ops->freeze) { + error = bdev->bd_holder_ops->freeze(bdev); + lockdep_assert_not_held(&bdev->bd_holder_lock); + } else { + mutex_unlock(&bdev->bd_holder_lock); + error = sync_blockdev(bdev); + } + + if (error) + atomic_dec(&bdev->bd_fsfreeze_count); + mutex_unlock(&bdev->bd_fsfreeze_mutex); return error; } -EXPORT_SYMBOL(freeze_bdev); +EXPORT_SYMBOL(bdev_freeze); /** - * thaw_bdev - unlock filesystem + * bdev_thaw - unlock filesystem * @bdev: blockdevice to unlock * - * Unlocks the filesystem and marks it writeable again after freeze_bdev(). + * Unlocks the filesystem and marks it writeable again after bdev_freeze(). + * + * Return: On success zero is returned, negative error code on failure. */ -int thaw_bdev(struct block_device *bdev) +int bdev_thaw(struct block_device *bdev) { - struct super_block *sb; - int error = -EINVAL; + int error = -EINVAL, nr_freeze; mutex_lock(&bdev->bd_fsfreeze_mutex); - if (!bdev->bd_fsfreeze_count) + + /* + * If this returns < 0 it means that @bd_fsfreeze_count was + * already 0 and no decrement was performed. + */ + nr_freeze = atomic_dec_if_positive(&bdev->bd_fsfreeze_count); + if (nr_freeze < 0) goto out; error = 0; - if (--bdev->bd_fsfreeze_count > 0) + if (nr_freeze > 0) goto out; - sb = bdev->bd_fsfreeze_sb; - if (!sb) - goto out; + mutex_lock(&bdev->bd_holder_lock); + if (bdev->bd_holder_ops && bdev->bd_holder_ops->thaw) { + error = bdev->bd_holder_ops->thaw(bdev); + lockdep_assert_not_held(&bdev->bd_holder_lock); + } else { + mutex_unlock(&bdev->bd_holder_lock); + } - if (sb->s_op->thaw_super) - error = sb->s_op->thaw_super(sb, FREEZE_HOLDER_USERSPACE); - else - error = thaw_super(sb, FREEZE_HOLDER_USERSPACE); if (error) - bdev->bd_fsfreeze_count++; - else - bdev->bd_fsfreeze_sb = NULL; + atomic_inc(&bdev->bd_fsfreeze_count); out: mutex_unlock(&bdev->bd_fsfreeze_mutex); return error; } -EXPORT_SYMBOL(thaw_bdev); +EXPORT_SYMBOL(bdev_thaw); /* * pseudo-fs @@ -729,9 +735,60 @@ void blkdev_put_no_open(struct block_device *bdev) { put_device(&bdev->bd_device); } - + +static bool bdev_writes_blocked(struct block_device *bdev) +{ + return bdev->bd_writers == -1; +} + +static void bdev_block_writes(struct block_device *bdev) +{ + bdev->bd_writers = -1; +} + +static void bdev_unblock_writes(struct block_device *bdev) +{ + bdev->bd_writers = 0; +} + +static bool bdev_may_open(struct block_device *bdev, blk_mode_t mode) +{ + if (bdev_allow_write_mounted) + return true; + /* Writes blocked? */ + if (mode & BLK_OPEN_WRITE && bdev_writes_blocked(bdev)) + return false; + if (mode & BLK_OPEN_RESTRICT_WRITES && bdev->bd_writers > 0) + return false; + return true; +} + +static void bdev_claim_write_access(struct block_device *bdev, blk_mode_t mode) +{ + if (bdev_allow_write_mounted) + return; + + /* Claim exclusive or shared write access. */ + if (mode & BLK_OPEN_RESTRICT_WRITES) + bdev_block_writes(bdev); + else if (mode & BLK_OPEN_WRITE) + bdev->bd_writers++; +} + +static void bdev_yield_write_access(struct block_device *bdev, blk_mode_t mode) +{ + if (bdev_allow_write_mounted) + return; + + /* Yield exclusive or shared write access. */ + if (mode & BLK_OPEN_RESTRICT_WRITES) + bdev_unblock_writes(bdev); + else if (mode & BLK_OPEN_WRITE) + bdev->bd_writers--; +} + /** - * blkdev_get_by_dev - open a block device by device number + * bdev_open_by_dev - open a block device by device number * @dev: device number of block device to open * @mode: open mode (BLK_OPEN_*) * @holder: exclusive holder identifier @@ -743,32 +800,46 @@ void blkdev_put_no_open(struct block_device *bdev) * * Use this interface ONLY if you really do not have anything better - i.e. when * you are behind a truly sucky interface and all you are given is a device - * number. Everything else should use blkdev_get_by_path(). + * number. Everything else should use bdev_open_by_path(). * * CONTEXT: * Might sleep. * * RETURNS: - * Reference to the block_device on success, ERR_PTR(-errno) on failure. + * Handle with a reference to the block_device on success, ERR_PTR(-errno) on + * failure. */ -struct block_device *blkdev_get_by_dev(dev_t dev, blk_mode_t mode, void *holder, - const struct blk_holder_ops *hops) +struct bdev_handle *bdev_open_by_dev(dev_t dev, blk_mode_t mode, void *holder, + const struct blk_holder_ops *hops) { - bool unblock_events = true; + struct bdev_handle *handle = kmalloc(sizeof(struct bdev_handle), + GFP_KERNEL); struct block_device *bdev; + bool unblock_events = true; struct gendisk *disk; int ret; + if (!handle) + return ERR_PTR(-ENOMEM); + ret = devcgroup_check_permission(DEVCG_DEV_BLOCK, MAJOR(dev), MINOR(dev), ((mode & BLK_OPEN_READ) ? DEVCG_ACC_READ : 0) | ((mode & BLK_OPEN_WRITE) ? DEVCG_ACC_WRITE : 0)); if (ret) - return ERR_PTR(ret); + goto free_handle; + + /* Blocking writes requires exclusive opener */ + if (mode & BLK_OPEN_RESTRICT_WRITES && !holder) { + ret = -EINVAL; + goto free_handle; + } bdev = blkdev_get_no_open(dev); - if (!bdev) - return ERR_PTR(-ENXIO); + if (!bdev) { + ret = -ENXIO; + goto free_handle; + } disk = bdev->bd_disk; if (holder) { @@ -791,12 +862,16 @@ struct block_device *blkdev_get_by_dev(dev_t dev, blk_mode_t mode, void *holder, goto abort_claiming; if (!try_module_get(disk->fops->owner)) goto abort_claiming; + ret = -EBUSY; + if (!bdev_may_open(bdev, mode)) + goto abort_claiming; if (bdev_is_partition(bdev)) ret = blkdev_get_part(bdev, mode); else ret = blkdev_get_whole(bdev, mode); if (ret) goto put_module; + bdev_claim_write_access(bdev, mode); if (holder) { bd_finish_claiming(bdev, holder, hops); @@ -817,7 +892,10 @@ struct block_device *blkdev_get_by_dev(dev_t dev, blk_mode_t mode, void *holder, if (unblock_events) disk_unblock_events(disk); - return bdev; + handle->bdev = bdev; + handle->holder = holder; + handle->mode = mode; + return handle; put_module: module_put(disk->fops->owner); abort_claiming: @@ -827,34 +905,14 @@ abort_claiming: disk_unblock_events(disk); put_blkdev: blkdev_put_no_open(bdev); +free_handle: + kfree(handle); return ERR_PTR(ret); } -EXPORT_SYMBOL(blkdev_get_by_dev); - -struct bdev_handle *bdev_open_by_dev(dev_t dev, blk_mode_t mode, void *holder, - const struct blk_holder_ops *hops) -{ - struct bdev_handle *handle = kmalloc(sizeof(*handle), GFP_KERNEL); - struct block_device *bdev; - - if (!handle) - return ERR_PTR(-ENOMEM); - bdev = blkdev_get_by_dev(dev, mode, holder, hops); - if (IS_ERR(bdev)) { - kfree(handle); - return ERR_CAST(bdev); - } - handle->bdev = bdev; - handle->holder = holder; - if (holder) - mode |= BLK_OPEN_EXCL; - handle->mode = mode; - return handle; -} EXPORT_SYMBOL(bdev_open_by_dev); /** - * blkdev_get_by_path - open a block device by name + * bdev_open_by_path - open a block device by name * @path: path to the block device to open * @mode: open mode (BLK_OPEN_*) * @holder: exclusive holder identifier @@ -868,29 +926,9 @@ EXPORT_SYMBOL(bdev_open_by_dev); * Might sleep. * * RETURNS: - * Reference to the block_device on success, ERR_PTR(-errno) on failure. + * Handle with a reference to the block_device on success, ERR_PTR(-errno) on + * failure. */ -struct block_device *blkdev_get_by_path(const char *path, blk_mode_t mode, - void *holder, const struct blk_holder_ops *hops) -{ - struct block_device *bdev; - dev_t dev; - int error; - - error = lookup_bdev(path, &dev); - if (error) - return ERR_PTR(error); - - bdev = blkdev_get_by_dev(dev, mode, holder, hops); - if (!IS_ERR(bdev) && (mode & BLK_OPEN_WRITE) && bdev_read_only(bdev)) { - blkdev_put(bdev, holder); - return ERR_PTR(-EACCES); - } - - return bdev; -} -EXPORT_SYMBOL(blkdev_get_by_path); - struct bdev_handle *bdev_open_by_path(const char *path, blk_mode_t mode, void *holder, const struct blk_holder_ops *hops) { @@ -913,8 +951,9 @@ struct bdev_handle *bdev_open_by_path(const char *path, blk_mode_t mode, } EXPORT_SYMBOL(bdev_open_by_path); -void blkdev_put(struct block_device *bdev, void *holder) +void bdev_release(struct bdev_handle *handle) { + struct block_device *bdev = handle->bdev; struct gendisk *disk = bdev->bd_disk; /* @@ -928,8 +967,10 @@ void blkdev_put(struct block_device *bdev, void *holder) sync_blockdev(bdev); mutex_lock(&disk->open_mutex); - if (holder) - bd_end_claim(bdev, holder); + bdev_yield_write_access(bdev, handle->mode); + + if (handle->holder) + bd_end_claim(bdev, handle->holder); /* * Trigger event checking and tell drivers to flush MEDIA_CHANGE @@ -946,12 +987,6 @@ void blkdev_put(struct block_device *bdev, void *holder) module_put(disk->fops->owner); blkdev_put_no_open(bdev); -} -EXPORT_SYMBOL(blkdev_put); - -void bdev_release(struct bdev_handle *handle) -{ - blkdev_put(handle->bdev, handle->holder); kfree(handle); } EXPORT_SYMBOL(bdev_release); @@ -1102,3 +1137,12 @@ void bdev_statx_dioalign(struct inode *inode, struct kstat *stat) blkdev_put_no_open(bdev); } + +static int __init setup_bdev_allow_write_mounted(char *str) +{ + if (kstrtobool(str, &bdev_allow_write_mounted)) + pr_warn("Invalid option string for bdev_allow_write_mounted:" + " '%s'\n", str); + return 1; +} +__setup("bdev_allow_write_mounted=", setup_bdev_allow_write_mounted); diff --git a/block/bio-integrity.c b/block/bio-integrity.c index ec8ac8cf6e1b98..c9a16fba58b9c4 100644 --- a/block/bio-integrity.c +++ b/block/bio-integrity.c @@ -69,15 +69,15 @@ struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio, memset(bip, 0, sizeof(*bip)); + /* always report as many vecs as asked explicitly, not inline vecs */ + bip->bip_max_vcnt = nr_vecs; if (nr_vecs > inline_vecs) { - bip->bip_max_vcnt = nr_vecs; bip->bip_vec = bvec_alloc(&bs->bvec_integrity_pool, &bip->bip_max_vcnt, gfp_mask); if (!bip->bip_vec) goto err; } else { bip->bip_vec = bip->bip_inline_vecs; - bip->bip_max_vcnt = inline_vecs; } bip->bip_bio = bio; @@ -91,6 +91,47 @@ err: } EXPORT_SYMBOL(bio_integrity_alloc); +static void bio_integrity_unpin_bvec(struct bio_vec *bv, int nr_vecs, + bool dirty) +{ + int i; + + for (i = 0; i < nr_vecs; i++) { + if (dirty && !PageCompound(bv[i].bv_page)) + set_page_dirty_lock(bv[i].bv_page); + unpin_user_page(bv[i].bv_page); + } +} + +static void bio_integrity_uncopy_user(struct bio_integrity_payload *bip) +{ + unsigned short nr_vecs = bip->bip_max_vcnt - 1; + struct bio_vec *copy = &bip->bip_vec[1]; + size_t bytes = bip->bip_iter.bi_size; + struct iov_iter iter; + int ret; + + iov_iter_bvec(&iter, ITER_DEST, copy, nr_vecs, bytes); + ret = copy_to_iter(bvec_virt(bip->bip_vec), bytes, &iter); + WARN_ON_ONCE(ret != bytes); + + bio_integrity_unpin_bvec(copy, nr_vecs, true); +} + +static void bio_integrity_unmap_user(struct bio_integrity_payload *bip) +{ + bool dirty = bio_data_dir(bip->bip_bio) == READ; + + if (bip->bip_flags & BIP_COPY_USER) { + if (dirty) + bio_integrity_uncopy_user(bip); + kfree(bvec_virt(bip->bip_vec)); + return; + } + + bio_integrity_unpin_bvec(bip->bip_vec, bip->bip_max_vcnt, dirty); +} + /** * bio_integrity_free - Free bio integrity payload * @bio: bio containing bip to be freed @@ -105,6 +146,8 @@ void bio_integrity_free(struct bio *bio) if (bip->bip_flags & BIP_BLOCK_INTEGRITY) kfree(bvec_virt(bip->bip_vec)); + else if (bip->bip_flags & BIP_INTEGRITY_USER) + bio_integrity_unmap_user(bip); __bio_integrity_free(bs, bip); bio->bi_integrity = NULL; @@ -160,6 +203,177 @@ int bio_integrity_add_page(struct bio *bio, struct page *page, } EXPORT_SYMBOL(bio_integrity_add_page); +static int bio_integrity_copy_user(struct bio *bio, struct bio_vec *bvec, + int nr_vecs, unsigned int len, + unsigned int direction, u32 seed) +{ + bool write = direction == ITER_SOURCE; + struct bio_integrity_payload *bip; + struct iov_iter iter; + void *buf; + int ret; + + buf = kmalloc(len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (write) { + iov_iter_bvec(&iter, direction, bvec, nr_vecs, len); + if (!copy_from_iter_full(buf, len, &iter)) { + ret = -EFAULT; + goto free_buf; + } + + bip = bio_integrity_alloc(bio, GFP_KERNEL, 1); + } else { + memset(buf, 0, len); + + /* + * We need to preserve the original bvec and the number of vecs + * in it for completion handling + */ + bip = bio_integrity_alloc(bio, GFP_KERNEL, nr_vecs + 1); + } + + if (IS_ERR(bip)) { + ret = PTR_ERR(bip); + goto free_buf; + } + + if (write) + bio_integrity_unpin_bvec(bvec, nr_vecs, false); + else + memcpy(&bip->bip_vec[1], bvec, nr_vecs * sizeof(*bvec)); + + ret = bio_integrity_add_page(bio, virt_to_page(buf), len, + offset_in_page(buf)); + if (ret != len) { + ret = -ENOMEM; + goto free_bip; + } + + bip->bip_flags |= BIP_INTEGRITY_USER | BIP_COPY_USER; + bip->bip_iter.bi_sector = seed; + return 0; +free_bip: + bio_integrity_free(bio); +free_buf: + kfree(buf); + return ret; +} + +static int bio_integrity_init_user(struct bio *bio, struct bio_vec *bvec, + int nr_vecs, unsigned int len, u32 seed) +{ + struct bio_integrity_payload *bip; + + bip = bio_integrity_alloc(bio, GFP_KERNEL, nr_vecs); + if (IS_ERR(bip)) + return PTR_ERR(bip); + + memcpy(bip->bip_vec, bvec, nr_vecs * sizeof(*bvec)); + bip->bip_flags |= BIP_INTEGRITY_USER; + bip->bip_iter.bi_sector = seed; + bip->bip_iter.bi_size = len; + return 0; +} + +static unsigned int bvec_from_pages(struct bio_vec *bvec, struct page **pages, + int nr_vecs, ssize_t bytes, ssize_t offset) +{ + unsigned int nr_bvecs = 0; + int i, j; + + for (i = 0; i < nr_vecs; i = j) { + size_t size = min_t(size_t, bytes, PAGE_SIZE - offset); + struct folio *folio = page_folio(pages[i]); + + bytes -= size; + for (j = i + 1; j < nr_vecs; j++) { + size_t next = min_t(size_t, PAGE_SIZE, bytes); + + if (page_folio(pages[j]) != folio || + pages[j] != pages[j - 1] + 1) + break; + unpin_user_page(pages[j]); + size += next; + bytes -= next; + } + + bvec_set_page(&bvec[nr_bvecs], pages[i], size, offset); + offset = 0; + nr_bvecs++; + } + + return nr_bvecs; +} + +int bio_integrity_map_user(struct bio *bio, void __user *ubuf, ssize_t bytes, + u32 seed) +{ + struct request_queue *q = bdev_get_queue(bio->bi_bdev); + unsigned int align = q->dma_pad_mask | queue_dma_alignment(q); + struct page *stack_pages[UIO_FASTIOV], **pages = stack_pages; + struct bio_vec stack_vec[UIO_FASTIOV], *bvec = stack_vec; + unsigned int direction, nr_bvecs; + struct iov_iter iter; + int ret, nr_vecs; + size_t offset; + bool copy; + + if (bio_integrity(bio)) + return -EINVAL; + if (bytes >> SECTOR_SHIFT > queue_max_hw_sectors(q)) + return -E2BIG; + + if (bio_data_dir(bio) == READ) + direction = ITER_DEST; + else + direction = ITER_SOURCE; + + iov_iter_ubuf(&iter, direction, ubuf, bytes); + nr_vecs = iov_iter_npages(&iter, BIO_MAX_VECS + 1); + if (nr_vecs > BIO_MAX_VECS) + return -E2BIG; + if (nr_vecs > UIO_FASTIOV) { + bvec = kcalloc(nr_vecs, sizeof(*bvec), GFP_KERNEL); + if (!bvec) + return -ENOMEM; + pages = NULL; + } + + copy = !iov_iter_is_aligned(&iter, align, align); + ret = iov_iter_extract_pages(&iter, &pages, bytes, nr_vecs, 0, &offset); + if (unlikely(ret < 0)) + goto free_bvec; + + nr_bvecs = bvec_from_pages(bvec, pages, nr_vecs, bytes, offset); + if (pages != stack_pages) + kvfree(pages); + if (nr_bvecs > queue_max_integrity_segments(q)) + copy = true; + + if (copy) + ret = bio_integrity_copy_user(bio, bvec, nr_bvecs, bytes, + direction, seed); + else + ret = bio_integrity_init_user(bio, bvec, nr_bvecs, bytes, seed); + if (ret) + goto release_pages; + if (bvec != stack_vec) + kfree(bvec); + + return 0; + +release_pages: + bio_integrity_unpin_bvec(bvec, nr_bvecs, false); +free_bvec: + if (bvec != stack_vec) + kfree(bvec); + return ret; +} +EXPORT_SYMBOL_GPL(bio_integrity_map_user); + /** * bio_integrity_process - Process integrity metadata for a bio * @bio: bio to generate/verify integrity metadata for diff --git a/block/bio.c b/block/bio.c index 816d412c06e9b4..b9642a41f286e5 100644 --- a/block/bio.c +++ b/block/bio.c @@ -944,7 +944,7 @@ bool bvec_try_merge_hw_page(struct request_queue *q, struct bio_vec *bv, if ((addr1 | mask) != (addr2 | mask)) return false; - if (bv->bv_len + len > queue_max_segment_size(q)) + if (len > queue_max_segment_size(q) - bv->bv_len) return false; return bvec_try_merge_page(bv, page, len, offset, same_page); } @@ -966,10 +966,13 @@ int bio_add_hw_page(struct request_queue *q, struct bio *bio, struct page *page, unsigned int len, unsigned int offset, unsigned int max_sectors, bool *same_page) { + unsigned int max_size = max_sectors << SECTOR_SHIFT; + if (WARN_ON_ONCE(bio_flagged(bio, BIO_CLONED))) return 0; - if (((bio->bi_iter.bi_size + len) >> SECTOR_SHIFT) > max_sectors) + len = min3(len, max_size, queue_max_segment_size(q)); + if (len > max_size - bio->bi_iter.bi_size) return 0; if (bio->bi_vcnt > 0) { @@ -1145,13 +1148,22 @@ EXPORT_SYMBOL(bio_add_folio); void __bio_release_pages(struct bio *bio, bool mark_dirty) { - struct bvec_iter_all iter_all; - struct bio_vec *bvec; + struct folio_iter fi; - bio_for_each_segment_all(bvec, bio, iter_all) { - if (mark_dirty && !PageCompound(bvec->bv_page)) - set_page_dirty_lock(bvec->bv_page); - bio_release_page(bio, bvec->bv_page); + bio_for_each_folio_all(fi, bio) { + struct page *page; + size_t done = 0; + + if (mark_dirty) { + folio_lock(fi.folio); + folio_mark_dirty(fi.folio); + folio_unlock(fi.folio); + } + page = folio_page(fi.folio, fi.offset / PAGE_SIZE); + do { + bio_release_page(bio, page++); + done += PAGE_SIZE; + } while (done < fi.length); } } EXPORT_SYMBOL_GPL(__bio_release_pages); @@ -1439,18 +1451,12 @@ EXPORT_SYMBOL(bio_free_pages); * bio_set_pages_dirty() and bio_check_pages_dirty() are support functions * for performing direct-IO in BIOs. * - * The problem is that we cannot run set_page_dirty() from interrupt context + * The problem is that we cannot run folio_mark_dirty() from interrupt context * because the required locks are not interrupt-safe. So what we can do is to * mark the pages dirty _before_ performing IO. And in interrupt context, * check that the pages are still dirty. If so, fine. If not, redirty them * in process context. * - * We special-case compound pages here: normally this means reads into hugetlb - * pages. The logic in here doesn't really work right for compound pages - * because the VM does not uniformly chase down the head page in all cases. - * But dirtiness of compound pages is pretty meaningless anyway: the VM doesn't - * handle them at all. So we skip compound pages here at an early stage. - * * Note that this code is very hard to test under normal circumstances because * direct-io pins the pages with get_user_pages(). This makes * is_page_cache_freeable return false, and the VM will not clean the pages. @@ -1466,12 +1472,12 @@ EXPORT_SYMBOL(bio_free_pages); */ void bio_set_pages_dirty(struct bio *bio) { - struct bio_vec *bvec; - struct bvec_iter_all iter_all; + struct folio_iter fi; - bio_for_each_segment_all(bvec, bio, iter_all) { - if (!PageCompound(bvec->bv_page)) - set_page_dirty_lock(bvec->bv_page); + bio_for_each_folio_all(fi, bio) { + folio_lock(fi.folio); + folio_mark_dirty(fi.folio); + folio_unlock(fi.folio); } } EXPORT_SYMBOL_GPL(bio_set_pages_dirty); @@ -1515,12 +1521,11 @@ static void bio_dirty_fn(struct work_struct *work) void bio_check_pages_dirty(struct bio *bio) { - struct bio_vec *bvec; + struct folio_iter fi; unsigned long flags; - struct bvec_iter_all iter_all; - bio_for_each_segment_all(bvec, bio, iter_all) { - if (!PageDirty(bvec->bv_page) && !PageCompound(bvec->bv_page)) + bio_for_each_folio_all(fi, bio) { + if (!folio_test_dirty(fi.folio)) goto defer; } diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index 4b48c2c4409813..ff93c385ba5afb 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -300,7 +300,7 @@ static inline struct blkcg *blkcg_parent(struct blkcg *blkcg) * @disk: gendisk the new blkg is associated with * @gfp_mask: allocation mask to use * - * Allocate a new blkg assocating @blkcg and @q. + * Allocate a new blkg associating @blkcg and @disk. */ static struct blkcg_gq *blkg_alloc(struct blkcg *blkcg, struct gendisk *disk, gfp_t gfp_mask) @@ -575,13 +575,13 @@ static void blkg_destroy(struct blkcg_gq *blkg) static void blkg_destroy_all(struct gendisk *disk) { struct request_queue *q = disk->queue; - struct blkcg_gq *blkg, *n; + struct blkcg_gq *blkg; int count = BLKG_DESTROY_BATCH_SIZE; int i; restart: spin_lock_irq(&q->queue_lock); - list_for_each_entry_safe(blkg, n, &q->blkg_list, q_node) { + list_for_each_entry(blkg, &q->blkg_list, q_node) { struct blkcg *blkcg = blkg->blkcg; if (hlist_unhashed(&blkg->blkcg_node)) @@ -2064,6 +2064,9 @@ void bio_associate_blkg(struct bio *bio) { struct cgroup_subsys_state *css; + if (blk_op_is_passthrough(bio->bi_opf)) + return; + rcu_read_lock(); if (bio->bi_blkg) diff --git a/block/blk-cgroup.h b/block/blk-cgroup.h index fd482439afbc9a..b927a4a0ad0301 100644 --- a/block/blk-cgroup.h +++ b/block/blk-cgroup.h @@ -252,7 +252,8 @@ static inline struct blkcg_gq *blkg_lookup(struct blkcg *blkcg, if (blkcg == &blkcg_root) return q->root_blkg; - blkg = rcu_dereference(blkcg->blkg_hint); + blkg = rcu_dereference_check(blkcg->blkg_hint, + lockdep_is_held(&q->queue_lock)); if (blkg && blkg->q == q) return blkg; diff --git a/block/blk-core.c b/block/blk-core.c index 2eca76ccf4ee01..11342af420d0c4 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -772,6 +772,15 @@ void submit_bio_noacct(struct bio *bio) bio_clear_polled(bio); switch (bio_op(bio)) { + case REQ_OP_READ: + case REQ_OP_WRITE: + break; + case REQ_OP_FLUSH: + /* + * REQ_OP_FLUSH can't be submitted through bios, it is only + * synthetized in struct request by the flush state machine. + */ + goto not_supported; case REQ_OP_DISCARD: if (!bdev_max_discard_sectors(bdev)) goto not_supported; @@ -785,6 +794,10 @@ void submit_bio_noacct(struct bio *bio) if (status != BLK_STS_OK) goto end_io; break; + case REQ_OP_WRITE_ZEROES: + if (!q->limits.max_write_zeroes_sectors) + goto not_supported; + break; case REQ_OP_ZONE_RESET: case REQ_OP_ZONE_OPEN: case REQ_OP_ZONE_CLOSE: @@ -796,12 +809,15 @@ void submit_bio_noacct(struct bio *bio) if (!bdev_is_zoned(bio->bi_bdev) || !blk_queue_zone_resetall(q)) goto not_supported; break; - case REQ_OP_WRITE_ZEROES: - if (!q->limits.max_write_zeroes_sectors) - goto not_supported; - break; + case REQ_OP_DRV_IN: + case REQ_OP_DRV_OUT: + /* + * Driver private operations are only used with passthrough + * requests. + */ + fallthrough; default: - break; + goto not_supported; } if (blk_throtl_bio(bio)) diff --git a/block/blk-iocost.c b/block/blk-iocost.c index 089fcb9cfce370..c8beec6d7df086 100644 --- a/block/blk-iocost.c +++ b/block/blk-iocost.c @@ -1261,7 +1261,7 @@ static void weight_updated(struct ioc_gq *iocg, struct ioc_now *now) static bool iocg_activate(struct ioc_gq *iocg, struct ioc_now *now) { struct ioc *ioc = iocg->ioc; - u64 last_period, cur_period; + u64 __maybe_unused last_period, cur_period; u64 vtime, vtarget; int i; diff --git a/block/blk-map.c b/block/blk-map.c index 8584babf3ea0ca..71210cdb34426d 100644 --- a/block/blk-map.c +++ b/block/blk-map.c @@ -205,12 +205,19 @@ static int bio_copy_user_iov(struct request *rq, struct rq_map_data *map_data, /* * success */ - if ((iov_iter_rw(iter) == WRITE && - (!map_data || !map_data->null_mapped)) || - (map_data && map_data->from_user)) { + if (iov_iter_rw(iter) == WRITE && + (!map_data || !map_data->null_mapped)) { ret = bio_copy_from_iter(bio, iter); if (ret) goto cleanup; + } else if (map_data && map_data->from_user) { + struct iov_iter iter2 = *iter; + + /* This is the copy-in part of SG_DXFER_TO_FROM_DEV. */ + iter2.data_source = ITER_SOURCE; + ret = bio_copy_from_iter(bio, &iter2); + if (ret) + goto cleanup; } else { if (bmd->is_our_pages) zero_fill_bio(bio); diff --git a/block/blk-merge.c b/block/blk-merge.c index 65e75efa9bd366..2d470cf2173e29 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -115,17 +115,13 @@ static struct bio *bio_split_discard(struct bio *bio, *nsegs = 1; - /* Zero-sector (unknown) and one-sector granularities are the same. */ granularity = max(lim->discard_granularity >> 9, 1U); max_discard_sectors = min(lim->max_discard_sectors, bio_allowed_max_sectors(lim)); max_discard_sectors -= max_discard_sectors % granularity; - - if (unlikely(!max_discard_sectors)) { - /* XXX: warn */ + if (unlikely(!max_discard_sectors)) return NULL; - } if (bio_sectors(bio) <= max_discard_sectors) return NULL; diff --git a/block/blk-mq-debugfs.c b/block/blk-mq-debugfs.c index 5cbeb9344f2f5c..94668e72ab09bf 100644 --- a/block/blk-mq-debugfs.c +++ b/block/blk-mq-debugfs.c @@ -479,23 +479,6 @@ out: return res; } -static int hctx_run_show(void *data, struct seq_file *m) -{ - struct blk_mq_hw_ctx *hctx = data; - - seq_printf(m, "%lu\n", hctx->run); - return 0; -} - -static ssize_t hctx_run_write(void *data, const char __user *buf, size_t count, - loff_t *ppos) -{ - struct blk_mq_hw_ctx *hctx = data; - - hctx->run = 0; - return count; -} - static int hctx_active_show(void *data, struct seq_file *m) { struct blk_mq_hw_ctx *hctx = data; @@ -624,7 +607,6 @@ static const struct blk_mq_debugfs_attr blk_mq_debugfs_hctx_attrs[] = { {"tags_bitmap", 0400, hctx_tags_bitmap_show}, {"sched_tags", 0400, hctx_sched_tags_show}, {"sched_tags_bitmap", 0400, hctx_sched_tags_bitmap_show}, - {"run", 0600, hctx_run_show, hctx_run_write}, {"active", 0400, hctx_active_show}, {"dispatch_busy", 0400, hctx_dispatch_busy_show}, {"type", 0400, hctx_type_show}, diff --git a/block/blk-mq-sched.c b/block/blk-mq-sched.c index 67c95f31b15bb1..451a2c1f1f3218 100644 --- a/block/blk-mq-sched.c +++ b/block/blk-mq-sched.c @@ -324,8 +324,6 @@ void blk_mq_sched_dispatch_requests(struct blk_mq_hw_ctx *hctx) if (unlikely(blk_mq_hctx_stopped(hctx) || blk_queue_quiesced(q))) return; - hctx->run++; - /* * A return of -EAGAIN is an indication that hctx->dispatch is not * empty and we must run again in order to avoid starving flushes. diff --git a/block/blk-mq.c b/block/blk-mq.c index ac18f802c027ea..aa87fcfda1ecfc 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -772,11 +772,16 @@ static void req_bio_endio(struct request *rq, struct bio *bio, /* * Partial zone append completions cannot be supported as the * BIO fragments may end up not being written sequentially. + * For such case, force the completed nbytes to be equal to + * the BIO size so that bio_advance() sets the BIO remaining + * size to 0 and we end up calling bio_endio() before returning. */ - if (bio->bi_iter.bi_size != nbytes) + if (bio->bi_iter.bi_size != nbytes) { bio->bi_status = BLK_STS_IOERR; - else + nbytes = bio->bi_iter.bi_size; + } else { bio->bi_iter.bi_sector = rq->__sector; + } } bio_advance(bio, nbytes); @@ -1248,7 +1253,8 @@ void blk_mq_start_request(struct request *rq) trace_block_rq_issue(rq); - if (test_bit(QUEUE_FLAG_STATS, &q->queue_flags)) { + if (test_bit(QUEUE_FLAG_STATS, &q->queue_flags) && + !blk_rq_is_passthrough(rq)) { rq->io_start_time_ns = ktime_get_ns(); rq->stats_sectors = blk_rq_sectors(rq); rq->rq_flags |= RQF_STATS; @@ -1858,6 +1864,22 @@ static bool blk_mq_mark_tag_wait(struct blk_mq_hw_ctx *hctx, wait->flags &= ~WQ_FLAG_EXCLUSIVE; __add_wait_queue(wq, wait); + /* + * Add one explicit barrier since blk_mq_get_driver_tag() may + * not imply barrier in case of failure. + * + * Order adding us to wait queue and allocating driver tag. + * + * The pair is the one implied in sbitmap_queue_wake_up() which + * orders clearing sbitmap tag bits and waitqueue_active() in + * __sbitmap_queue_wake_up(), since waitqueue_active() is lockless + * + * Otherwise, re-order of adding wait queue and getting driver tag + * may cause __sbitmap_queue_wake_up() to wake up nothing because + * the waitqueue_active() may not observe us in wait queue. + */ + smp_mb(); + /* * It's possible that a tag was freed in the window between the * allocation failure and adding the hardware queue to the wait @@ -2890,8 +2912,11 @@ static struct request *blk_mq_get_new_requests(struct request_queue *q, return NULL; } -/* return true if this @rq can be used for @bio */ -static bool blk_mq_can_use_cached_rq(struct request *rq, struct blk_plug *plug, +/* + * Check if we can use the passed on request for submitting the passed in bio, + * and remove it from the request list if it can be used. + */ +static bool blk_mq_use_cached_rq(struct request *rq, struct blk_plug *plug, struct bio *bio) { enum hctx_type type = blk_mq_get_hctx_type(bio->bi_opf); @@ -2951,12 +2976,6 @@ void blk_mq_submit_bio(struct bio *bio) blk_status_t ret; bio = blk_queue_bounce(bio, q); - if (bio_may_exceed_limits(bio, &q->limits)) { - bio = __bio_split_to_limits(bio, &q->limits, &nr_segs); - if (!bio) - return; - } - bio_set_ioprio(bio); if (plug) { @@ -2965,16 +2984,26 @@ void blk_mq_submit_bio(struct bio *bio) rq = NULL; } if (rq) { + if (unlikely(bio_may_exceed_limits(bio, &q->limits))) { + bio = __bio_split_to_limits(bio, &q->limits, &nr_segs); + if (!bio) + return; + } if (!bio_integrity_prep(bio)) return; if (blk_mq_attempt_bio_merge(q, bio, nr_segs)) return; - if (blk_mq_can_use_cached_rq(rq, plug, bio)) + if (blk_mq_use_cached_rq(rq, plug, bio)) goto done; percpu_ref_get(&q->q_usage_counter); } else { if (unlikely(bio_queue_enter(bio))) return; + if (unlikely(bio_may_exceed_limits(bio, &q->limits))) { + bio = __bio_split_to_limits(bio, &q->limits, &nr_segs); + if (!bio) + goto fail; + } if (!bio_integrity_prep(bio)) goto fail; } diff --git a/block/blk-rq-qos.h b/block/blk-rq-qos.h index f48ee150d6673e..37245c97ee6150 100644 --- a/block/blk-rq-qos.h +++ b/block/blk-rq-qos.h @@ -118,7 +118,7 @@ static inline void rq_qos_cleanup(struct request_queue *q, struct bio *bio) static inline void rq_qos_done(struct request_queue *q, struct request *rq) { - if (q->rq_qos) + if (q->rq_qos && !blk_rq_is_passthrough(rq)) __rq_qos_done(q->rq_qos, rq); } diff --git a/block/blk-settings.c b/block/blk-settings.c index 0046b447268f91..06ea91e51b8b2e 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -48,7 +48,7 @@ void blk_set_default_limits(struct queue_limits *lim) lim->max_discard_sectors = 0; lim->max_hw_discard_sectors = 0; lim->max_secure_erase_sectors = 0; - lim->discard_granularity = 0; + lim->discard_granularity = 512; lim->discard_alignment = 0; lim->discard_misaligned = 0; lim->logical_block_size = lim->physical_block_size = lim->io_min = 512; @@ -56,7 +56,7 @@ void blk_set_default_limits(struct queue_limits *lim) lim->alignment_offset = 0; lim->io_opt = 0; lim->misaligned = 0; - lim->zoned = BLK_ZONED_NONE; + lim->zoned = false; lim->zone_write_granularity = 0; lim->dma_alignment = 511; } @@ -127,8 +127,7 @@ void blk_queue_max_hw_sectors(struct request_queue *q, unsigned int max_hw_secto if ((max_hw_sectors << 9) < PAGE_SIZE) { max_hw_sectors = 1 << (PAGE_SHIFT - 9); - printk(KERN_INFO "%s: set to minimum %d\n", - __func__, max_hw_sectors); + pr_info("%s: set to minimum %u\n", __func__, max_hw_sectors); } max_hw_sectors = round_down(max_hw_sectors, @@ -140,7 +139,7 @@ void blk_queue_max_hw_sectors(struct request_queue *q, unsigned int max_hw_secto if (limits->max_user_sectors) max_sectors = min(max_sectors, limits->max_user_sectors); else - max_sectors = min(max_sectors, BLK_DEF_MAX_SECTORS); + max_sectors = min(max_sectors, BLK_DEF_MAX_SECTORS_CAP); max_sectors = round_down(max_sectors, limits->logical_block_size >> SECTOR_SHIFT); @@ -248,8 +247,7 @@ void blk_queue_max_segments(struct request_queue *q, unsigned short max_segments { if (!max_segments) { max_segments = 1; - printk(KERN_INFO "%s: set to minimum %d\n", - __func__, max_segments); + pr_info("%s: set to minimum %u\n", __func__, max_segments); } q->limits.max_segments = max_segments; @@ -285,8 +283,7 @@ void blk_queue_max_segment_size(struct request_queue *q, unsigned int max_size) { if (max_size < PAGE_SIZE) { max_size = PAGE_SIZE; - printk(KERN_INFO "%s: set to minimum %d\n", - __func__, max_size); + pr_info("%s: set to minimum %u\n", __func__, max_size); } /* see blk_queue_virt_boundary() for the explanation */ @@ -312,6 +309,9 @@ void blk_queue_logical_block_size(struct request_queue *q, unsigned int size) limits->logical_block_size = size; + if (limits->discard_granularity < limits->logical_block_size) + limits->discard_granularity = limits->logical_block_size; + if (limits->physical_block_size < size) limits->physical_block_size = size; @@ -342,6 +342,9 @@ void blk_queue_physical_block_size(struct request_queue *q, unsigned int size) if (q->limits.physical_block_size < q->limits.logical_block_size) q->limits.physical_block_size = q->limits.logical_block_size; + if (q->limits.discard_granularity < q->limits.physical_block_size) + q->limits.discard_granularity = q->limits.physical_block_size; + if (q->limits.io_min < q->limits.physical_block_size) q->limits.io_min = q->limits.physical_block_size; } @@ -740,8 +743,7 @@ void blk_queue_segment_boundary(struct request_queue *q, unsigned long mask) { if (mask < PAGE_SIZE - 1) { mask = PAGE_SIZE - 1; - printk(KERN_INFO "%s: set to minimum %lx\n", - __func__, mask); + pr_info("%s: set to minimum %lx\n", __func__, mask); } q->limits.seg_boundary_mask = mask; @@ -841,8 +843,6 @@ void blk_queue_write_cache(struct request_queue *q, bool wc, bool fua) blk_queue_flag_set(QUEUE_FLAG_FUA, q); else blk_queue_flag_clear(QUEUE_FLAG_FUA, q); - - wbt_set_write_cache(q, test_bit(QUEUE_FLAG_WC, &q->queue_flags)); } EXPORT_SYMBOL_GPL(blk_queue_write_cache); @@ -884,81 +884,22 @@ bool blk_queue_can_use_dma_map_merging(struct request_queue *q, } EXPORT_SYMBOL_GPL(blk_queue_can_use_dma_map_merging); -static bool disk_has_partitions(struct gendisk *disk) -{ - unsigned long idx; - struct block_device *part; - bool ret = false; - - rcu_read_lock(); - xa_for_each(&disk->part_tbl, idx, part) { - if (bdev_is_partition(part)) { - ret = true; - break; - } - } - rcu_read_unlock(); - - return ret; -} - /** - * disk_set_zoned - configure the zoned model for a disk - * @disk: the gendisk of the queue to configure - * @model: the zoned model to set - * - * Set the zoned model of @disk to @model. - * - * When @model is BLK_ZONED_HM (host managed), this should be called only - * if zoned block device support is enabled (CONFIG_BLK_DEV_ZONED option). - * If @model specifies BLK_ZONED_HA (host aware), the effective model used - * depends on CONFIG_BLK_DEV_ZONED settings and on the existence of partitions - * on the disk. + * disk_set_zoned - inidicate a zoned device + * @disk: gendisk to configure */ -void disk_set_zoned(struct gendisk *disk, enum blk_zoned_model model) +void disk_set_zoned(struct gendisk *disk) { struct request_queue *q = disk->queue; - unsigned int old_model = q->limits.zoned; - - switch (model) { - case BLK_ZONED_HM: - /* - * Host managed devices are supported only if - * CONFIG_BLK_DEV_ZONED is enabled. - */ - WARN_ON_ONCE(!IS_ENABLED(CONFIG_BLK_DEV_ZONED)); - break; - case BLK_ZONED_HA: - /* - * Host aware devices can be treated either as regular block - * devices (similar to drive managed devices) or as zoned block - * devices to take advantage of the zone command set, similarly - * to host managed devices. We try the latter if there are no - * partitions and zoned block device support is enabled, else - * we do nothing special as far as the block layer is concerned. - */ - if (!IS_ENABLED(CONFIG_BLK_DEV_ZONED) || - disk_has_partitions(disk)) - model = BLK_ZONED_NONE; - break; - case BLK_ZONED_NONE: - default: - if (WARN_ON_ONCE(model != BLK_ZONED_NONE)) - model = BLK_ZONED_NONE; - break; - } - q->limits.zoned = model; - if (model != BLK_ZONED_NONE) { - /* - * Set the zone write granularity to the device logical block - * size by default. The driver can change this value if needed. - */ - blk_queue_zone_write_granularity(q, - queue_logical_block_size(q)); - } else if (old_model != BLK_ZONED_NONE) { - disk_clear_zone_settings(disk); - } + WARN_ON_ONCE(!IS_ENABLED(CONFIG_BLK_DEV_ZONED)); + + /* + * Set the zone write granularity to the device logical block + * size by default. The driver can change this value if needed. + */ + q->limits.zoned = true; + blk_queue_zone_write_granularity(q, queue_logical_block_size(q)); } EXPORT_SYMBOL_GPL(disk_set_zoned); diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 0b2d0476632407..6b2429cad81af1 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -241,7 +241,7 @@ queue_max_sectors_store(struct request_queue *q, const char *page, size_t count) if (max_sectors_kb == 0) { q->limits.max_user_sectors = 0; max_sectors_kb = min(max_hw_sectors_kb, - BLK_DEF_MAX_SECTORS >> 1); + BLK_DEF_MAX_SECTORS_CAP >> 1); } else { if (max_sectors_kb > max_hw_sectors_kb || max_sectors_kb < page_kb) @@ -309,14 +309,9 @@ QUEUE_SYSFS_BIT_FNS(stable_writes, STABLE_WRITES, 0); static ssize_t queue_zoned_show(struct request_queue *q, char *page) { - switch (blk_queue_zoned_model(q)) { - case BLK_ZONED_HA: - return sprintf(page, "host-aware\n"); - case BLK_ZONED_HM: + if (blk_queue_is_zoned(q)) return sprintf(page, "host-managed\n"); - default: - return sprintf(page, "none\n"); - } + return sprintf(page, "none\n"); } static ssize_t queue_nr_zones_show(struct request_queue *q, char *page) diff --git a/block/blk-wbt.c b/block/blk-wbt.c index 0bb613139becbb..5ba3cd574eacbd 100644 --- a/block/blk-wbt.c +++ b/block/blk-wbt.c @@ -84,8 +84,6 @@ struct rq_wb { u64 sync_issue; void *sync_cookie; - unsigned int wc; - unsigned long last_issue; /* last non-throttled issue */ unsigned long last_comp; /* last non-throttled comp */ unsigned long min_lat_nsec; @@ -207,7 +205,8 @@ static void wbt_rqw_done(struct rq_wb *rwb, struct rq_wait *rqw, */ if (wb_acct & WBT_DISCARD) limit = rwb->wb_background; - else if (rwb->wc && !wb_recent_wait(rwb)) + else if (test_bit(QUEUE_FLAG_WC, &rwb->rqos.disk->queue->queue_flags) && + !wb_recent_wait(rwb)) limit = 0; else limit = rwb->wb_normal; @@ -699,13 +698,6 @@ static void wbt_requeue(struct rq_qos *rqos, struct request *rq) } } -void wbt_set_write_cache(struct request_queue *q, bool write_cache_on) -{ - struct rq_qos *rqos = wbt_rq_qos(q); - if (rqos) - RQWB(rqos)->wc = write_cache_on; -} - /* * Enable wbt if defaults are configured that way */ @@ -918,7 +910,6 @@ int wbt_init(struct gendisk *disk) rwb->last_comp = rwb->last_issue = jiffies; rwb->win_nsec = RWB_WINDOW_NSEC; rwb->enable_state = WBT_STATE_ON_DEFAULT; - rwb->wc = test_bit(QUEUE_FLAG_WC, &q->queue_flags); rwb->rq_depth.default_depth = RWB_DEF_DEPTH; rwb->min_lat_nsec = wbt_default_latency_nsec(q); rwb->rq_depth.queue_depth = blk_queue_depth(q); diff --git a/block/blk-wbt.h b/block/blk-wbt.h index 8a029e138f7ace..e5fc653b9b76f6 100644 --- a/block/blk-wbt.h +++ b/block/blk-wbt.h @@ -12,8 +12,6 @@ u64 wbt_get_min_lat(struct request_queue *q); void wbt_set_min_lat(struct request_queue *q, u64 val); bool wbt_disabled(struct request_queue *); -void wbt_set_write_cache(struct request_queue *, bool); - u64 wbt_default_latency_nsec(struct request_queue *); #else @@ -24,9 +22,6 @@ static inline void wbt_disable_default(struct gendisk *disk) static inline void wbt_enable_default(struct gendisk *disk) { } -static inline void wbt_set_write_cache(struct request_queue *q, bool wc) -{ -} #endif /* CONFIG_BLK_WBT */ diff --git a/block/blk-zoned.c b/block/blk-zoned.c index 619ee41a51cc8c..d343e5756a9c80 100644 --- a/block/blk-zoned.c +++ b/block/blk-zoned.c @@ -498,7 +498,6 @@ static int blk_revalidate_zone_cb(struct blk_zone *zone, unsigned int idx, set_bit(idx, args->conv_zones_bitmap); break; case BLK_ZONE_TYPE_SEQWRITE_REQ: - case BLK_ZONE_TYPE_SEQWRITE_PREF: if (!args->seq_zones_wlock) { args->seq_zones_wlock = blk_alloc_zone_bitmap(q->node, args->nr_zones); @@ -506,6 +505,7 @@ static int blk_revalidate_zone_cb(struct blk_zone *zone, unsigned int idx, return -ENOMEM; } break; + case BLK_ZONE_TYPE_SEQWRITE_PREF: default: pr_warn("%s: Invalid zone type 0x%x at sectors %llu\n", disk->disk_name, (int)zone->type, zone->start); @@ -615,22 +615,3 @@ int blk_revalidate_disk_zones(struct gendisk *disk, return ret; } EXPORT_SYMBOL_GPL(blk_revalidate_disk_zones); - -void disk_clear_zone_settings(struct gendisk *disk) -{ - struct request_queue *q = disk->queue; - - blk_mq_freeze_queue(q); - - disk_free_zone_bitmaps(disk); - blk_queue_flag_clear(QUEUE_FLAG_ZONE_RESETALL, q); - q->required_elevator_features &= ~ELEVATOR_F_ZBD_SEQ_WRITE; - disk->nr_zones = 0; - disk->max_open_zones = 0; - disk->max_active_zones = 0; - q->limits.chunk_sectors = 0; - q->limits.zone_write_granularity = 0; - q->limits.max_zone_append_sectors = 0; - - blk_mq_unfreeze_queue(q); -} diff --git a/block/blk.h b/block/blk.h index 08a358bc0919e2..1ef920f72e0f87 100644 --- a/block/blk.h +++ b/block/blk.h @@ -395,14 +395,12 @@ static inline struct bio *blk_queue_bounce(struct bio *bio, #ifdef CONFIG_BLK_DEV_ZONED void disk_free_zone_bitmaps(struct gendisk *disk); -void disk_clear_zone_settings(struct gendisk *disk); int blkdev_report_zones_ioctl(struct block_device *bdev, unsigned int cmd, unsigned long arg); int blkdev_zone_mgmt_ioctl(struct block_device *bdev, blk_mode_t mode, unsigned int cmd, unsigned long arg); #else /* CONFIG_BLK_DEV_ZONED */ static inline void disk_free_zone_bitmaps(struct gendisk *disk) {} -static inline void disk_clear_zone_settings(struct gendisk *disk) {} static inline int blkdev_report_zones_ioctl(struct block_device *bdev, unsigned int cmd, unsigned long arg) { diff --git a/block/fops.c b/block/fops.c index 0abaac705dafb0..0cf8cf72cdfa10 100644 --- a/block/fops.c +++ b/block/fops.c @@ -410,9 +410,24 @@ static int blkdev_get_block(struct inode *inode, sector_t iblock, return 0; } -static int blkdev_writepage(struct page *page, struct writeback_control *wbc) +/* + * We cannot call mpage_writepages() as it does not take the buffer lock. + * We must use block_write_full_folio() directly which holds the buffer + * lock. The buffer lock provides the synchronisation with writeback + * that filesystems rely on when they use the blockdev's mapping. + */ +static int blkdev_writepages(struct address_space *mapping, + struct writeback_control *wbc) { - return block_write_full_page(page, blkdev_get_block, wbc); + struct blk_plug plug; + int err; + + blk_start_plug(&plug); + err = write_cache_pages(mapping, wbc, block_write_full_folio, + blkdev_get_block); + blk_finish_plug(&plug); + + return err; } static int blkdev_read_folio(struct file *file, struct folio *folio) @@ -449,7 +464,7 @@ const struct address_space_operations def_blk_aops = { .invalidate_folio = block_invalidate_folio, .read_folio = blkdev_read_folio, .readahead = blkdev_readahead, - .writepage = blkdev_writepage, + .writepages = blkdev_writepages, .write_begin = blkdev_write_begin, .write_end = blkdev_write_end, .migrate_folio = buffer_migrate_folio_norefs, @@ -500,7 +515,7 @@ const struct address_space_operations def_blk_aops = { .readahead = blkdev_readahead, .writepages = blkdev_writepages, .is_partially_uptodate = iomap_is_partially_uptodate, - .error_remove_page = generic_error_remove_page, + .error_remove_folio = generic_error_remove_folio, .migrate_folio = filemap_migrate_folio, }; #endif /* CONFIG_BUFFER_HEAD */ diff --git a/block/genhd.c b/block/genhd.c index c9d06f72c587e8..d74fb5b4ae6818 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -432,7 +432,9 @@ int __must_check device_add_disk(struct device *parent, struct gendisk *disk, DISK_MAX_PARTS); disk->minors = DISK_MAX_PARTS; } - if (disk->first_minor + disk->minors > MINORMASK + 1) + if (disk->first_minor > MINORMASK || + disk->minors > MINORMASK + 1 || + disk->first_minor + disk->minors > MINORMASK + 1) goto out_exit_elevator; } else { if (WARN_ON(disk->minors)) @@ -542,6 +544,7 @@ out_put_holder_dir: kobject_put(disk->part0->bd_holder_dir); out_del_block_link: sysfs_remove_link(block_depr, dev_name(ddev)); + pm_runtime_set_memalloc_noio(ddev, false); out_device_del: device_del(ddev); out_free_ext_minor: diff --git a/block/ioctl.c b/block/ioctl.c index 4160f4e6bd5b4b..438f79c564cfc0 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -18,10 +18,8 @@ static int blkpg_do_ioctl(struct block_device *bdev, { struct gendisk *disk = bdev->bd_disk; struct blkpg_partition p; - long long start, length; + sector_t start, length; - if (disk->flags & GENHD_FL_NO_PART) - return -EINVAL; if (!capable(CAP_SYS_ADMIN)) return -EACCES; if (copy_from_user(&p, upart, sizeof(struct blkpg_partition))) @@ -35,14 +33,17 @@ static int blkpg_do_ioctl(struct block_device *bdev, if (op == BLKPG_DEL_PARTITION) return bdev_del_partition(disk, p.pno); + if (p.start < 0 || p.length <= 0 || p.start + p.length < 0) + return -EINVAL; + /* Check that the partition is aligned to the block size */ + if (!IS_ALIGNED(p.start | p.length, bdev_logical_block_size(bdev))) + return -EINVAL; + start = p.start >> SECTOR_SHIFT; length = p.length >> SECTOR_SHIFT; switch (op) { case BLKPG_ADD_PARTITION: - /* check if partition is aligned to blocksize */ - if (p.start & (bdev_logical_block_size(bdev) - 1)) - return -EINVAL; return bdev_add_partition(disk, p.pno, start, length); case BLKPG_RESIZE_PARTITION: return bdev_resize_partition(disk, p.pno, start, length); diff --git a/block/ioprio.c b/block/ioprio.c index b5a942519a797c..73301a261429ff 100644 --- a/block/ioprio.c +++ b/block/ioprio.c @@ -139,32 +139,6 @@ out: return ret; } -/* - * If the task has set an I/O priority, use that. Otherwise, return - * the default I/O priority. - * - * Expected to be called for current task or with task_lock() held to keep - * io_context stable. - */ -int __get_task_ioprio(struct task_struct *p) -{ - struct io_context *ioc = p->io_context; - int prio; - - if (p != current) - lockdep_assert_held(&p->alloc_lock); - if (ioc) - prio = ioc->ioprio; - else - prio = IOPRIO_DEFAULT; - - if (IOPRIO_PRIO_CLASS(prio) == IOPRIO_CLASS_NONE) - prio = IOPRIO_PRIO_VALUE(task_nice_ioclass(p), - task_nice_ioprio(p)); - return prio; -} -EXPORT_SYMBOL_GPL(__get_task_ioprio); - static int get_task_ioprio(struct task_struct *p) { int ret; diff --git a/block/partitions/core.c b/block/partitions/core.c index f47ffcfdfcec22..5f5ed5c75f04d9 100644 --- a/block/partitions/core.c +++ b/block/partitions/core.c @@ -305,18 +305,10 @@ static struct block_device *add_partition(struct gendisk *disk, int partno, * Partitions are not supported on zoned block devices that are used as * such. */ - switch (disk->queue->limits.zoned) { - case BLK_ZONED_HM: + if (bdev_is_zoned(disk->part0)) { pr_warn("%s: partitions not supported on host managed zoned block device\n", disk->disk_name); return ERR_PTR(-ENXIO); - case BLK_ZONED_HA: - pr_info("%s: disabling host aware zoned block device support due to partitions\n", - disk->disk_name); - disk_set_zoned(disk, BLK_ZONED_NONE); - break; - case BLK_ZONED_NONE: - break; } if (xa_load(&disk->part_tbl, partno)) @@ -447,6 +439,11 @@ int bdev_add_partition(struct gendisk *disk, int partno, sector_t start, goto out; } + if (disk->flags & GENHD_FL_NO_PART) { + ret = -EINVAL; + goto out; + } + if (partition_overlaps(disk, start, length, -1)) { ret = -EBUSY; goto out; @@ -570,8 +567,8 @@ static bool blk_add_partition(struct gendisk *disk, part = add_partition(disk, p, from, size, state->parts[p].flags, &state->parts[p].info); if (IS_ERR(part) && PTR_ERR(part) != -ENXIO) { - printk(KERN_ERR " %s: p%d could not be added: %ld\n", - disk->disk_name, p, -PTR_ERR(part)); + printk(KERN_ERR " %s: p%d could not be added: %pe\n", + disk->disk_name, p, part); return true; } @@ -613,7 +610,7 @@ static int blk_add_partitions(struct gendisk *disk) /* * Partitions are not supported on host managed zoned block devices. */ - if (disk->queue->limits.zoned == BLK_ZONED_HM) { + if (bdev_is_zoned(disk->part0)) { pr_warn("%s: ignoring partition table on host managed zoned block device\n", disk->disk_name); ret = 0; diff --git a/crypto/Kconfig b/crypto/Kconfig index 70661f58ee41c4..7d156c75f15f2d 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -661,15 +661,6 @@ config CRYPTO_CBC This block cipher mode is required for IPSec ESP (XFRM_ESP). -config CRYPTO_CFB - tristate "CFB (Cipher Feedback)" - select CRYPTO_SKCIPHER - select CRYPTO_MANAGER - help - CFB (Cipher Feedback) mode (NIST SP800-38A) - - This block cipher mode is required for TPM2 Cryptography. - config CRYPTO_CTR tristate "CTR (Counter)" select CRYPTO_SKCIPHER @@ -735,20 +726,6 @@ config CRYPTO_LRW See https://people.csail.mit.edu/rivest/pubs/LRW02.pdf -config CRYPTO_OFB - tristate "OFB (Output Feedback)" - select CRYPTO_SKCIPHER - select CRYPTO_MANAGER - help - OFB (Output Feedback) mode (NIST SP800-38A) - - This mode makes a block cipher into a synchronous - stream cipher. It generates keystream blocks, which are then XORed - with the plaintext blocks to get the ciphertext. Flipping a bit in the - ciphertext produces a flipped bit in the plaintext at the same - location. This property allows many error correcting codes to function - normally even when applied before encryption. - config CRYPTO_PCBC tristate "PCBC (Propagating Cipher Block Chaining)" select CRYPTO_SKCIPHER diff --git a/crypto/Makefile b/crypto/Makefile index 5ac6876f935a3f..408f0a1f9ab91b 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -92,7 +92,6 @@ obj-$(CONFIG_CRYPTO_BLAKE2B) += blake2b_generic.o CFLAGS_blake2b_generic.o := -Wframe-larger-than=4096 # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105930 obj-$(CONFIG_CRYPTO_ECB) += ecb.o obj-$(CONFIG_CRYPTO_CBC) += cbc.o -obj-$(CONFIG_CRYPTO_CFB) += cfb.o obj-$(CONFIG_CRYPTO_PCBC) += pcbc.o obj-$(CONFIG_CRYPTO_CTS) += cts.o obj-$(CONFIG_CRYPTO_LRW) += lrw.o @@ -186,7 +185,6 @@ obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o obj-$(CONFIG_CRYPTO_USER_API_RNG) += algif_rng.o obj-$(CONFIG_CRYPTO_USER_API_AEAD) += algif_aead.o obj-$(CONFIG_CRYPTO_ZSTD) += zstd.o -obj-$(CONFIG_CRYPTO_OFB) += ofb.o obj-$(CONFIG_CRYPTO_ECC) += ecc.o obj-$(CONFIG_CRYPTO_ESSIV) += essiv.o obj-$(CONFIG_CRYPTO_CURVE25519) += curve25519-generic.o diff --git a/crypto/af_alg.c b/crypto/af_alg.c index ea6fb8e89d0653..68cc9290cabe9a 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -1116,9 +1116,13 @@ EXPORT_SYMBOL_GPL(af_alg_sendmsg); void af_alg_free_resources(struct af_alg_async_req *areq) { struct sock *sk = areq->sk; + struct af_alg_ctx *ctx; af_alg_free_areq_sgls(areq); sock_kfree_s(sk, areq, areq->areqlen); + + ctx = alg_sk(sk)->private; + ctx->inflight = false; } EXPORT_SYMBOL_GPL(af_alg_free_resources); @@ -1188,11 +1192,19 @@ EXPORT_SYMBOL_GPL(af_alg_poll); struct af_alg_async_req *af_alg_alloc_areq(struct sock *sk, unsigned int areqlen) { - struct af_alg_async_req *areq = sock_kmalloc(sk, areqlen, GFP_KERNEL); + struct af_alg_ctx *ctx = alg_sk(sk)->private; + struct af_alg_async_req *areq; + + /* Only one AIO request can be in flight. */ + if (ctx->inflight) + return ERR_PTR(-EBUSY); + areq = sock_kmalloc(sk, areqlen, GFP_KERNEL); if (unlikely(!areq)) return ERR_PTR(-ENOMEM); + ctx->inflight = true; + areq->areqlen = areqlen; areq->sk = sk; areq->first_rsgl.sgl.sgt.sgl = areq->first_rsgl.sgl.sgl; diff --git a/crypto/algapi.c b/crypto/algapi.c index 4fe95c44804733..85bc279b4233fa 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c @@ -341,6 +341,7 @@ __crypto_register_alg(struct crypto_alg *alg, struct list_head *algs_to_put) } if (!strcmp(q->cra_driver_name, alg->cra_name) || + !strcmp(q->cra_driver_name, alg->cra_driver_name) || !strcmp(q->cra_name, alg->cra_driver_name)) goto err; } diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index 9ada9b741af8dc..02cea2149504ab 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -47,6 +47,52 @@ static int skcipher_sendmsg(struct socket *sock, struct msghdr *msg, return af_alg_sendmsg(sock, msg, size, ivsize); } +static int algif_skcipher_export(struct sock *sk, struct skcipher_request *req) +{ + struct alg_sock *ask = alg_sk(sk); + struct crypto_skcipher *tfm; + struct af_alg_ctx *ctx; + struct alg_sock *pask; + unsigned statesize; + struct sock *psk; + int err; + + if (!(req->base.flags & CRYPTO_SKCIPHER_REQ_NOTFINAL)) + return 0; + + ctx = ask->private; + psk = ask->parent; + pask = alg_sk(psk); + tfm = pask->private; + + statesize = crypto_skcipher_statesize(tfm); + ctx->state = sock_kmalloc(sk, statesize, GFP_ATOMIC); + if (!ctx->state) + return -ENOMEM; + + err = crypto_skcipher_export(req, ctx->state); + if (err) { + sock_kzfree_s(sk, ctx->state, statesize); + ctx->state = NULL; + } + + return err; +} + +static void algif_skcipher_done(void *data, int err) +{ + struct af_alg_async_req *areq = data; + struct sock *sk = areq->sk; + + if (err) + goto out; + + err = algif_skcipher_export(sk, &areq->cra_u.skcipher_req); + +out: + af_alg_async_cb(data, err); +} + static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, size_t ignored, int flags) { @@ -58,6 +104,7 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, struct crypto_skcipher *tfm = pask->private; unsigned int bs = crypto_skcipher_chunksize(tfm); struct af_alg_async_req *areq; + unsigned cflags = 0; int err = 0; size_t len = 0; @@ -82,8 +129,10 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, * If more buffers are to be expected to be processed, process only * full block size buffers. */ - if (ctx->more || len < ctx->used) + if (ctx->more || len < ctx->used) { len -= len % bs; + cflags |= CRYPTO_SKCIPHER_REQ_NOTFINAL; + } /* * Create a per request TX SGL for this request which tracks the @@ -107,6 +156,16 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, skcipher_request_set_crypt(&areq->cra_u.skcipher_req, areq->tsgl, areq->first_rsgl.sgl.sgt.sgl, len, ctx->iv); + if (ctx->state) { + err = crypto_skcipher_import(&areq->cra_u.skcipher_req, + ctx->state); + sock_kzfree_s(sk, ctx->state, crypto_skcipher_statesize(tfm)); + ctx->state = NULL; + if (err) + goto free; + cflags |= CRYPTO_SKCIPHER_REQ_CONT; + } + if (msg->msg_iocb && !is_sync_kiocb(msg->msg_iocb)) { /* AIO operation */ sock_hold(sk); @@ -116,8 +175,9 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, areq->outlen = len; skcipher_request_set_callback(&areq->cra_u.skcipher_req, + cflags | CRYPTO_TFM_REQ_MAY_SLEEP, - af_alg_async_cb, areq); + algif_skcipher_done, areq); err = ctx->enc ? crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) : crypto_skcipher_decrypt(&areq->cra_u.skcipher_req); @@ -130,6 +190,7 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, } else { /* Synchronous operation */ skcipher_request_set_callback(&areq->cra_u.skcipher_req, + cflags | CRYPTO_TFM_REQ_MAY_SLEEP | CRYPTO_TFM_REQ_MAY_BACKLOG, crypto_req_done, &ctx->wait); @@ -137,8 +198,11 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) : crypto_skcipher_decrypt(&areq->cra_u.skcipher_req), &ctx->wait); - } + if (!err) + err = algif_skcipher_export( + sk, &areq->cra_u.skcipher_req); + } free: af_alg_free_resources(areq); @@ -301,6 +365,8 @@ static void skcipher_sock_destruct(struct sock *sk) af_alg_pull_tsgl(sk, ctx->used, NULL, 0); sock_kzfree_s(sk, ctx->iv, crypto_skcipher_ivsize(tfm)); + if (ctx->state) + sock_kzfree_s(sk, ctx->state, crypto_skcipher_statesize(tfm)); sock_kfree_s(sk, ctx, ctx->len); af_alg_release_parent(sk); } diff --git a/crypto/arc4.c b/crypto/arc4.c index eb3590dc92826c..1a4825c97c5ae1 100644 --- a/crypto/arc4.c +++ b/crypto/arc4.c @@ -14,6 +14,8 @@ #include #include +#define ARC4_ALIGN __alignof__(struct arc4_ctx) + static int crypto_arc4_setkey(struct crypto_lskcipher *tfm, const u8 *in_key, unsigned int key_len) { @@ -23,10 +25,15 @@ static int crypto_arc4_setkey(struct crypto_lskcipher *tfm, const u8 *in_key, } static int crypto_arc4_crypt(struct crypto_lskcipher *tfm, const u8 *src, - u8 *dst, unsigned nbytes, u8 *iv, bool final) + u8 *dst, unsigned nbytes, u8 *siv, u32 flags) { struct arc4_ctx *ctx = crypto_lskcipher_ctx(tfm); + if (!(flags & CRYPTO_LSKCIPHER_FLAG_CONT)) + memcpy(siv, ctx, sizeof(*ctx)); + + ctx = (struct arc4_ctx *)siv; + arc4_crypt(ctx, dst, src, nbytes); return 0; } @@ -45,9 +52,11 @@ static struct lskcipher_alg arc4_alg = { .co.base.cra_priority = 100, .co.base.cra_blocksize = ARC4_BLOCK_SIZE, .co.base.cra_ctxsize = sizeof(struct arc4_ctx), + .co.base.cra_alignmask = ARC4_ALIGN - 1, .co.base.cra_module = THIS_MODULE, .co.min_keysize = ARC4_MIN_KEY_SIZE, .co.max_keysize = ARC4_MAX_KEY_SIZE, + .co.statesize = sizeof(struct arc4_ctx), .setkey = crypto_arc4_setkey, .encrypt = crypto_arc4_crypt, .decrypt = crypto_arc4_crypt, diff --git a/crypto/cbc.c b/crypto/cbc.c index 28345b8d921c6a..eedddef9ce40cc 100644 --- a/crypto/cbc.c +++ b/crypto/cbc.c @@ -51,9 +51,10 @@ out: } static int crypto_cbc_encrypt(struct crypto_lskcipher *tfm, const u8 *src, - u8 *dst, unsigned len, u8 *iv, bool final) + u8 *dst, unsigned len, u8 *iv, u32 flags) { struct crypto_lskcipher **ctx = crypto_lskcipher_ctx(tfm); + bool final = flags & CRYPTO_LSKCIPHER_FLAG_FINAL; struct crypto_lskcipher *cipher = *ctx; int rem; @@ -119,9 +120,10 @@ out: } static int crypto_cbc_decrypt(struct crypto_lskcipher *tfm, const u8 *src, - u8 *dst, unsigned len, u8 *iv, bool final) + u8 *dst, unsigned len, u8 *iv, u32 flags) { struct crypto_lskcipher **ctx = crypto_lskcipher_ctx(tfm); + bool final = flags & CRYPTO_LSKCIPHER_FLAG_FINAL; struct crypto_lskcipher *cipher = *ctx; int rem; diff --git a/crypto/cfb.c b/crypto/cfb.c deleted file mode 100644 index 5c36b7b65e2aac..00000000000000 --- a/crypto/cfb.c +++ /dev/null @@ -1,254 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * CFB: Cipher FeedBack mode - * - * Copyright (c) 2018 James.Bottomley@HansenPartnership.com - * - * CFB is a stream cipher mode which is layered on to a block - * encryption scheme. It works very much like a one time pad where - * the pad is generated initially from the encrypted IV and then - * subsequently from the encrypted previous block of ciphertext. The - * pad is XOR'd into the plain text to get the final ciphertext. - * - * The scheme of CFB is best described by wikipedia: - * - * https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#CFB - * - * Note that since the pad for both encryption and decryption is - * generated by an encryption operation, CFB never uses the block - * decryption function. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -static unsigned int crypto_cfb_bsize(struct crypto_skcipher *tfm) -{ - return crypto_cipher_blocksize(skcipher_cipher_simple(tfm)); -} - -static void crypto_cfb_encrypt_one(struct crypto_skcipher *tfm, - const u8 *src, u8 *dst) -{ - crypto_cipher_encrypt_one(skcipher_cipher_simple(tfm), dst, src); -} - -/* final encrypt and decrypt is the same */ -static void crypto_cfb_final(struct skcipher_walk *walk, - struct crypto_skcipher *tfm) -{ - const unsigned long alignmask = crypto_skcipher_alignmask(tfm); - u8 tmp[MAX_CIPHER_BLOCKSIZE + MAX_CIPHER_ALIGNMASK]; - u8 *stream = PTR_ALIGN(tmp + 0, alignmask + 1); - u8 *src = walk->src.virt.addr; - u8 *dst = walk->dst.virt.addr; - u8 *iv = walk->iv; - unsigned int nbytes = walk->nbytes; - - crypto_cfb_encrypt_one(tfm, iv, stream); - crypto_xor_cpy(dst, stream, src, nbytes); -} - -static int crypto_cfb_encrypt_segment(struct skcipher_walk *walk, - struct crypto_skcipher *tfm) -{ - const unsigned int bsize = crypto_cfb_bsize(tfm); - unsigned int nbytes = walk->nbytes; - u8 *src = walk->src.virt.addr; - u8 *dst = walk->dst.virt.addr; - u8 *iv = walk->iv; - - do { - crypto_cfb_encrypt_one(tfm, iv, dst); - crypto_xor(dst, src, bsize); - iv = dst; - - src += bsize; - dst += bsize; - } while ((nbytes -= bsize) >= bsize); - - memcpy(walk->iv, iv, bsize); - - return nbytes; -} - -static int crypto_cfb_encrypt_inplace(struct skcipher_walk *walk, - struct crypto_skcipher *tfm) -{ - const unsigned int bsize = crypto_cfb_bsize(tfm); - unsigned int nbytes = walk->nbytes; - u8 *src = walk->src.virt.addr; - u8 *iv = walk->iv; - u8 tmp[MAX_CIPHER_BLOCKSIZE]; - - do { - crypto_cfb_encrypt_one(tfm, iv, tmp); - crypto_xor(src, tmp, bsize); - iv = src; - - src += bsize; - } while ((nbytes -= bsize) >= bsize); - - memcpy(walk->iv, iv, bsize); - - return nbytes; -} - -static int crypto_cfb_encrypt(struct skcipher_request *req) -{ - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); - struct skcipher_walk walk; - unsigned int bsize = crypto_cfb_bsize(tfm); - int err; - - err = skcipher_walk_virt(&walk, req, false); - - while (walk.nbytes >= bsize) { - if (walk.src.virt.addr == walk.dst.virt.addr) - err = crypto_cfb_encrypt_inplace(&walk, tfm); - else - err = crypto_cfb_encrypt_segment(&walk, tfm); - err = skcipher_walk_done(&walk, err); - } - - if (walk.nbytes) { - crypto_cfb_final(&walk, tfm); - err = skcipher_walk_done(&walk, 0); - } - - return err; -} - -static int crypto_cfb_decrypt_segment(struct skcipher_walk *walk, - struct crypto_skcipher *tfm) -{ - const unsigned int bsize = crypto_cfb_bsize(tfm); - unsigned int nbytes = walk->nbytes; - u8 *src = walk->src.virt.addr; - u8 *dst = walk->dst.virt.addr; - u8 *iv = walk->iv; - - do { - crypto_cfb_encrypt_one(tfm, iv, dst); - crypto_xor(dst, src, bsize); - iv = src; - - src += bsize; - dst += bsize; - } while ((nbytes -= bsize) >= bsize); - - memcpy(walk->iv, iv, bsize); - - return nbytes; -} - -static int crypto_cfb_decrypt_inplace(struct skcipher_walk *walk, - struct crypto_skcipher *tfm) -{ - const unsigned int bsize = crypto_cfb_bsize(tfm); - unsigned int nbytes = walk->nbytes; - u8 *src = walk->src.virt.addr; - u8 * const iv = walk->iv; - u8 tmp[MAX_CIPHER_BLOCKSIZE]; - - do { - crypto_cfb_encrypt_one(tfm, iv, tmp); - memcpy(iv, src, bsize); - crypto_xor(src, tmp, bsize); - src += bsize; - } while ((nbytes -= bsize) >= bsize); - - return nbytes; -} - -static int crypto_cfb_decrypt_blocks(struct skcipher_walk *walk, - struct crypto_skcipher *tfm) -{ - if (walk->src.virt.addr == walk->dst.virt.addr) - return crypto_cfb_decrypt_inplace(walk, tfm); - else - return crypto_cfb_decrypt_segment(walk, tfm); -} - -static int crypto_cfb_decrypt(struct skcipher_request *req) -{ - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); - struct skcipher_walk walk; - const unsigned int bsize = crypto_cfb_bsize(tfm); - int err; - - err = skcipher_walk_virt(&walk, req, false); - - while (walk.nbytes >= bsize) { - err = crypto_cfb_decrypt_blocks(&walk, tfm); - err = skcipher_walk_done(&walk, err); - } - - if (walk.nbytes) { - crypto_cfb_final(&walk, tfm); - err = skcipher_walk_done(&walk, 0); - } - - return err; -} - -static int crypto_cfb_create(struct crypto_template *tmpl, struct rtattr **tb) -{ - struct skcipher_instance *inst; - struct crypto_alg *alg; - int err; - - inst = skcipher_alloc_instance_simple(tmpl, tb); - if (IS_ERR(inst)) - return PTR_ERR(inst); - - alg = skcipher_ialg_simple(inst); - - /* CFB mode is a stream cipher. */ - inst->alg.base.cra_blocksize = 1; - - /* - * To simplify the implementation, configure the skcipher walk to only - * give a partial block at the very end, never earlier. - */ - inst->alg.chunksize = alg->cra_blocksize; - - inst->alg.encrypt = crypto_cfb_encrypt; - inst->alg.decrypt = crypto_cfb_decrypt; - - err = skcipher_register_instance(tmpl, inst); - if (err) - inst->free(inst); - - return err; -} - -static struct crypto_template crypto_cfb_tmpl = { - .name = "cfb", - .create = crypto_cfb_create, - .module = THIS_MODULE, -}; - -static int __init crypto_cfb_module_init(void) -{ - return crypto_register_template(&crypto_cfb_tmpl); -} - -static void __exit crypto_cfb_module_exit(void) -{ - crypto_unregister_template(&crypto_cfb_tmpl); -} - -subsys_initcall(crypto_cfb_module_init); -module_exit(crypto_cfb_module_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("CFB block cipher mode of operation"); -MODULE_ALIAS_CRYPTO("cfb"); -MODULE_IMPORT_NS(CRYPTO_INTERNAL); diff --git a/crypto/drbg.c b/crypto/drbg.c index e01f8c7769d036..3addce90930c3e 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -111,9 +111,9 @@ * as stdrng. Each DRBG receives an increasing cra_priority values the later * they are defined in this array (see drbg_fill_array). * - * HMAC DRBGs are favored over Hash DRBGs over CTR DRBGs, and - * the SHA256 / AES 256 over other ciphers. Thus, the favored - * DRBGs are the latest entries in this array. + * HMAC DRBGs are favored over Hash DRBGs over CTR DRBGs, and the + * HMAC-SHA512 / SHA256 / AES 256 over other ciphers. Thus, the + * favored DRBGs are the latest entries in this array. */ static const struct drbg_core drbg_cores[] = { #ifdef CONFIG_CRYPTO_DRBG_CTR @@ -139,12 +139,6 @@ static const struct drbg_core drbg_cores[] = { #endif /* CONFIG_CRYPTO_DRBG_CTR */ #ifdef CONFIG_CRYPTO_DRBG_HASH { - .flags = DRBG_HASH | DRBG_STRENGTH128, - .statelen = 55, /* 440 bits */ - .blocklen_bytes = 20, - .cra_name = "sha1", - .backend_cra_name = "sha1", - }, { .flags = DRBG_HASH | DRBG_STRENGTH256, .statelen = 111, /* 888 bits */ .blocklen_bytes = 48, @@ -166,12 +160,6 @@ static const struct drbg_core drbg_cores[] = { #endif /* CONFIG_CRYPTO_DRBG_HASH */ #ifdef CONFIG_CRYPTO_DRBG_HMAC { - .flags = DRBG_HMAC | DRBG_STRENGTH128, - .statelen = 20, /* block length of cipher */ - .blocklen_bytes = 20, - .cra_name = "hmac_sha1", - .backend_cra_name = "hmac(sha1)", - }, { .flags = DRBG_HMAC | DRBG_STRENGTH256, .statelen = 48, /* block length of cipher */ .blocklen_bytes = 48, @@ -648,8 +636,6 @@ MODULE_ALIAS_CRYPTO("drbg_pr_hmac_sha384"); MODULE_ALIAS_CRYPTO("drbg_nopr_hmac_sha384"); MODULE_ALIAS_CRYPTO("drbg_pr_hmac_sha256"); MODULE_ALIAS_CRYPTO("drbg_nopr_hmac_sha256"); -MODULE_ALIAS_CRYPTO("drbg_pr_hmac_sha1"); -MODULE_ALIAS_CRYPTO("drbg_nopr_hmac_sha1"); /* update function of HMAC DRBG as defined in 10.1.2.2 */ static int drbg_hmac_update(struct drbg_state *drbg, struct list_head *seed, @@ -768,8 +754,6 @@ MODULE_ALIAS_CRYPTO("drbg_pr_sha384"); MODULE_ALIAS_CRYPTO("drbg_nopr_sha384"); MODULE_ALIAS_CRYPTO("drbg_pr_sha256"); MODULE_ALIAS_CRYPTO("drbg_nopr_sha256"); -MODULE_ALIAS_CRYPTO("drbg_pr_sha1"); -MODULE_ALIAS_CRYPTO("drbg_nopr_sha1"); /* * Increment buffer @@ -1475,11 +1459,11 @@ static int drbg_generate(struct drbg_state *drbg, int err = 0; pr_devel("DRBG: start to perform self test\n"); if (drbg->core->flags & DRBG_HMAC) - err = alg_test("drbg_pr_hmac_sha256", - "drbg_pr_hmac_sha256", 0, 0); + err = alg_test("drbg_pr_hmac_sha512", + "drbg_pr_hmac_sha512", 0, 0); else if (drbg->core->flags & DRBG_CTR) - err = alg_test("drbg_pr_ctr_aes128", - "drbg_pr_ctr_aes128", 0, 0); + err = alg_test("drbg_pr_ctr_aes256", + "drbg_pr_ctr_aes256", 0, 0); else err = alg_test("drbg_pr_sha256", "drbg_pr_sha256", 0, 0); @@ -2017,11 +2001,13 @@ static inline int __init drbg_healthcheck_sanity(void) return 0; #ifdef CONFIG_CRYPTO_DRBG_CTR - drbg_convert_tfm_core("drbg_nopr_ctr_aes128", &coreref, &pr); -#elif defined CONFIG_CRYPTO_DRBG_HASH + drbg_convert_tfm_core("drbg_nopr_ctr_aes256", &coreref, &pr); +#endif +#ifdef CONFIG_CRYPTO_DRBG_HASH drbg_convert_tfm_core("drbg_nopr_sha256", &coreref, &pr); -#else - drbg_convert_tfm_core("drbg_nopr_hmac_sha256", &coreref, &pr); +#endif +#ifdef CONFIG_CRYPTO_DRBG_HMAC + drbg_convert_tfm_core("drbg_nopr_hmac_sha512", &coreref, &pr); #endif drbg = kzalloc(sizeof(struct drbg_state), GFP_KERNEL); diff --git a/crypto/ecb.c b/crypto/ecb.c index cc7625d1a475e8..e3a67789050ee2 100644 --- a/crypto/ecb.c +++ b/crypto/ecb.c @@ -32,22 +32,24 @@ static int crypto_ecb_crypt(struct crypto_cipher *cipher, const u8 *src, } static int crypto_ecb_encrypt2(struct crypto_lskcipher *tfm, const u8 *src, - u8 *dst, unsigned len, u8 *iv, bool final) + u8 *dst, unsigned len, u8 *iv, u32 flags) { struct crypto_cipher **ctx = crypto_lskcipher_ctx(tfm); struct crypto_cipher *cipher = *ctx; - return crypto_ecb_crypt(cipher, src, dst, len, final, + return crypto_ecb_crypt(cipher, src, dst, len, + flags & CRYPTO_LSKCIPHER_FLAG_FINAL, crypto_cipher_alg(cipher)->cia_encrypt); } static int crypto_ecb_decrypt2(struct crypto_lskcipher *tfm, const u8 *src, - u8 *dst, unsigned len, u8 *iv, bool final) + u8 *dst, unsigned len, u8 *iv, u32 flags) { struct crypto_cipher **ctx = crypto_lskcipher_ctx(tfm); struct crypto_cipher *cipher = *ctx; - return crypto_ecb_crypt(cipher, src, dst, len, final, + return crypto_ecb_crypt(cipher, src, dst, len, + flags & CRYPTO_LSKCIPHER_FLAG_FINAL, crypto_cipher_alg(cipher)->cia_decrypt); } diff --git a/crypto/lskcipher.c b/crypto/lskcipher.c index 9edc897309510b..0b6dd8aa21f2ed 100644 --- a/crypto/lskcipher.c +++ b/crypto/lskcipher.c @@ -88,8 +88,9 @@ EXPORT_SYMBOL_GPL(crypto_lskcipher_setkey); static int crypto_lskcipher_crypt_unaligned( struct crypto_lskcipher *tfm, const u8 *src, u8 *dst, unsigned len, u8 *iv, int (*crypt)(struct crypto_lskcipher *tfm, const u8 *src, - u8 *dst, unsigned len, u8 *iv, bool final)) + u8 *dst, unsigned len, u8 *iv, u32 flags)) { + unsigned statesize = crypto_lskcipher_statesize(tfm); unsigned ivsize = crypto_lskcipher_ivsize(tfm); unsigned bs = crypto_lskcipher_blocksize(tfm); unsigned cs = crypto_lskcipher_chunksize(tfm); @@ -104,7 +105,7 @@ static int crypto_lskcipher_crypt_unaligned( if (!tiv) return -ENOMEM; - memcpy(tiv, iv, ivsize); + memcpy(tiv, iv, ivsize + statesize); p = kmalloc(PAGE_SIZE, GFP_ATOMIC); err = -ENOMEM; @@ -119,7 +120,7 @@ static int crypto_lskcipher_crypt_unaligned( chunk &= ~(cs - 1); memcpy(p, src, chunk); - err = crypt(tfm, p, p, chunk, tiv, true); + err = crypt(tfm, p, p, chunk, tiv, CRYPTO_LSKCIPHER_FLAG_FINAL); if (err) goto out; @@ -132,7 +133,7 @@ static int crypto_lskcipher_crypt_unaligned( err = len ? -EINVAL : 0; out: - memcpy(iv, tiv, ivsize); + memcpy(iv, tiv, ivsize + statesize); kfree_sensitive(p); kfree_sensitive(tiv); return err; @@ -143,7 +144,7 @@ static int crypto_lskcipher_crypt(struct crypto_lskcipher *tfm, const u8 *src, int (*crypt)(struct crypto_lskcipher *tfm, const u8 *src, u8 *dst, unsigned len, u8 *iv, - bool final)) + u32 flags)) { unsigned long alignmask = crypto_lskcipher_alignmask(tfm); struct lskcipher_alg *alg = crypto_lskcipher_alg(tfm); @@ -156,7 +157,7 @@ static int crypto_lskcipher_crypt(struct crypto_lskcipher *tfm, const u8 *src, goto out; } - ret = crypt(tfm, src, dst, len, iv, true); + ret = crypt(tfm, src, dst, len, iv, CRYPTO_LSKCIPHER_FLAG_FINAL); out: return crypto_lskcipher_errstat(alg, ret); @@ -197,23 +198,45 @@ EXPORT_SYMBOL_GPL(crypto_lskcipher_decrypt); static int crypto_lskcipher_crypt_sg(struct skcipher_request *req, int (*crypt)(struct crypto_lskcipher *tfm, const u8 *src, u8 *dst, - unsigned len, u8 *iv, - bool final)) + unsigned len, u8 *ivs, + u32 flags)) { struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); struct crypto_lskcipher **ctx = crypto_skcipher_ctx(skcipher); + u8 *ivs = skcipher_request_ctx(req); struct crypto_lskcipher *tfm = *ctx; struct skcipher_walk walk; + unsigned ivsize; + u32 flags; int err; + ivsize = crypto_lskcipher_ivsize(tfm); + ivs = PTR_ALIGN(ivs, crypto_skcipher_alignmask(skcipher) + 1); + + flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP; + + if (req->base.flags & CRYPTO_SKCIPHER_REQ_CONT) + flags |= CRYPTO_LSKCIPHER_FLAG_CONT; + else + memcpy(ivs, req->iv, ivsize); + + if (!(req->base.flags & CRYPTO_SKCIPHER_REQ_NOTFINAL)) + flags |= CRYPTO_LSKCIPHER_FLAG_FINAL; + err = skcipher_walk_virt(&walk, req, false); while (walk.nbytes) { err = crypt(tfm, walk.src.virt.addr, walk.dst.virt.addr, - walk.nbytes, walk.iv, walk.nbytes == walk.total); + walk.nbytes, ivs, + flags & ~(walk.nbytes == walk.total ? + 0 : CRYPTO_LSKCIPHER_FLAG_FINAL)); err = skcipher_walk_done(&walk, err); + flags |= CRYPTO_LSKCIPHER_FLAG_CONT; } + if (flags & CRYPTO_LSKCIPHER_FLAG_FINAL) + memcpy(req->iv, ivs, ivsize); + return err; } @@ -276,6 +299,7 @@ static void __maybe_unused crypto_lskcipher_show( seq_printf(m, "max keysize : %u\n", skcipher->co.max_keysize); seq_printf(m, "ivsize : %u\n", skcipher->co.ivsize); seq_printf(m, "chunksize : %u\n", skcipher->co.chunksize); + seq_printf(m, "statesize : %u\n", skcipher->co.statesize); } static int __maybe_unused crypto_lskcipher_report( @@ -618,6 +642,7 @@ struct lskcipher_instance *lskcipher_alloc_instance_simple( inst->alg.co.min_keysize = cipher_alg->co.min_keysize; inst->alg.co.max_keysize = cipher_alg->co.max_keysize; inst->alg.co.ivsize = cipher_alg->co.base.cra_blocksize; + inst->alg.co.statesize = cipher_alg->co.statesize; /* Use struct crypto_lskcipher * by default, can be overridden */ inst->alg.co.base.cra_ctxsize = sizeof(struct crypto_lskcipher *); diff --git a/crypto/ofb.c b/crypto/ofb.c deleted file mode 100644 index b630fdecceee33..00000000000000 --- a/crypto/ofb.c +++ /dev/null @@ -1,106 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -/* - * OFB: Output FeedBack mode - * - * Copyright (C) 2018 ARM Limited or its affiliates. - * All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include - -static int crypto_ofb_crypt(struct skcipher_request *req) -{ - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); - struct crypto_cipher *cipher = skcipher_cipher_simple(tfm); - const unsigned int bsize = crypto_cipher_blocksize(cipher); - struct skcipher_walk walk; - int err; - - err = skcipher_walk_virt(&walk, req, false); - - while (walk.nbytes >= bsize) { - const u8 *src = walk.src.virt.addr; - u8 *dst = walk.dst.virt.addr; - u8 * const iv = walk.iv; - unsigned int nbytes = walk.nbytes; - - do { - crypto_cipher_encrypt_one(cipher, iv, iv); - crypto_xor_cpy(dst, src, iv, bsize); - dst += bsize; - src += bsize; - } while ((nbytes -= bsize) >= bsize); - - err = skcipher_walk_done(&walk, nbytes); - } - - if (walk.nbytes) { - crypto_cipher_encrypt_one(cipher, walk.iv, walk.iv); - crypto_xor_cpy(walk.dst.virt.addr, walk.src.virt.addr, walk.iv, - walk.nbytes); - err = skcipher_walk_done(&walk, 0); - } - return err; -} - -static int crypto_ofb_create(struct crypto_template *tmpl, struct rtattr **tb) -{ - struct skcipher_instance *inst; - struct crypto_alg *alg; - int err; - - inst = skcipher_alloc_instance_simple(tmpl, tb); - if (IS_ERR(inst)) - return PTR_ERR(inst); - - alg = skcipher_ialg_simple(inst); - - /* OFB mode is a stream cipher. */ - inst->alg.base.cra_blocksize = 1; - - /* - * To simplify the implementation, configure the skcipher walk to only - * give a partial block at the very end, never earlier. - */ - inst->alg.chunksize = alg->cra_blocksize; - - inst->alg.encrypt = crypto_ofb_crypt; - inst->alg.decrypt = crypto_ofb_crypt; - - err = skcipher_register_instance(tmpl, inst); - if (err) - inst->free(inst); - - return err; -} - -static struct crypto_template crypto_ofb_tmpl = { - .name = "ofb", - .create = crypto_ofb_create, - .module = THIS_MODULE, -}; - -static int __init crypto_ofb_module_init(void) -{ - return crypto_register_template(&crypto_ofb_tmpl); -} - -static void __exit crypto_ofb_module_exit(void) -{ - crypto_unregister_template(&crypto_ofb_tmpl); -} - -subsys_initcall(crypto_ofb_module_init); -module_exit(crypto_ofb_module_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("OFB block cipher mode of operation"); -MODULE_ALIAS_CRYPTO("ofb"); -MODULE_IMPORT_NS(CRYPTO_INTERNAL); diff --git a/crypto/rsa.c b/crypto/rsa.c index c79613cdce6e44..b9cd11fb7d3672 100644 --- a/crypto/rsa.c +++ b/crypto/rsa.c @@ -220,6 +220,8 @@ static int rsa_check_exponent_fips(MPI e) } e_max = mpi_alloc(0); + if (!e_max) + return -ENOMEM; mpi_set_bit(e_max, 256); if (mpi_cmp(e, e_max) >= 0) { diff --git a/crypto/scompress.c b/crypto/scompress.c index 442a82c9de7def..b108a30a760014 100644 --- a/crypto/scompress.c +++ b/crypto/scompress.c @@ -117,6 +117,7 @@ static int scomp_acomp_comp_decomp(struct acomp_req *req, int dir) struct crypto_scomp *scomp = *tfm_ctx; void **ctx = acomp_request_ctx(req); struct scomp_scratch *scratch; + unsigned int dlen; int ret; if (!req->src || !req->slen || req->slen > SCOMP_SCRATCH_SIZE) @@ -128,6 +129,8 @@ static int scomp_acomp_comp_decomp(struct acomp_req *req, int dir) if (!req->dlen || req->dlen > SCOMP_SCRATCH_SIZE) req->dlen = SCOMP_SCRATCH_SIZE; + dlen = req->dlen; + scratch = raw_cpu_ptr(&scomp_scratch); spin_lock(&scratch->lock); @@ -145,6 +148,9 @@ static int scomp_acomp_comp_decomp(struct acomp_req *req, int dir) ret = -ENOMEM; goto out; } + } else if (req->dlen > dlen) { + ret = -ENOSPC; + goto out; } scatterwalk_map_and_copy(scratch->dst, req->dst, 0, req->dlen, 1); diff --git a/crypto/shash.c b/crypto/shash.c index d5194221c88cb9..c3f7f6a2528036 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -23,12 +23,8 @@ static inline struct crypto_istat_hash *shash_get_stat(struct shash_alg *alg) static inline int crypto_shash_errstat(struct shash_alg *alg, int err) { - if (!IS_ENABLED(CONFIG_CRYPTO_STATS)) - return err; - - if (err && err != -EINPROGRESS && err != -EBUSY) + if (IS_ENABLED(CONFIG_CRYPTO_STATS) && err) atomic64_inc(&shash_get_stat(alg)->err_cnt); - return err; } diff --git a/crypto/skcipher.c b/crypto/skcipher.c index ac8b8c04265429..bc70e159d27df5 100644 --- a/crypto/skcipher.c +++ b/crypto/skcipher.c @@ -698,6 +698,64 @@ int crypto_skcipher_decrypt(struct skcipher_request *req) } EXPORT_SYMBOL_GPL(crypto_skcipher_decrypt); +static int crypto_lskcipher_export(struct skcipher_request *req, void *out) +{ + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + u8 *ivs = skcipher_request_ctx(req); + + ivs = PTR_ALIGN(ivs, crypto_skcipher_alignmask(tfm) + 1); + + memcpy(out, ivs + crypto_skcipher_ivsize(tfm), + crypto_skcipher_statesize(tfm)); + + return 0; +} + +static int crypto_lskcipher_import(struct skcipher_request *req, const void *in) +{ + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + u8 *ivs = skcipher_request_ctx(req); + + ivs = PTR_ALIGN(ivs, crypto_skcipher_alignmask(tfm) + 1); + + memcpy(ivs + crypto_skcipher_ivsize(tfm), in, + crypto_skcipher_statesize(tfm)); + + return 0; +} + +static int skcipher_noexport(struct skcipher_request *req, void *out) +{ + return 0; +} + +static int skcipher_noimport(struct skcipher_request *req, const void *in) +{ + return 0; +} + +int crypto_skcipher_export(struct skcipher_request *req, void *out) +{ + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + struct skcipher_alg *alg = crypto_skcipher_alg(tfm); + + if (alg->co.base.cra_type != &crypto_skcipher_type) + return crypto_lskcipher_export(req, out); + return alg->export(req, out); +} +EXPORT_SYMBOL_GPL(crypto_skcipher_export); + +int crypto_skcipher_import(struct skcipher_request *req, const void *in) +{ + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + struct skcipher_alg *alg = crypto_skcipher_alg(tfm); + + if (alg->co.base.cra_type != &crypto_skcipher_type) + return crypto_lskcipher_import(req, in); + return alg->import(req, in); +} +EXPORT_SYMBOL_GPL(crypto_skcipher_import); + static void crypto_skcipher_exit_tfm(struct crypto_tfm *tfm) { struct crypto_skcipher *skcipher = __crypto_skcipher_cast(tfm); @@ -713,8 +771,17 @@ static int crypto_skcipher_init_tfm(struct crypto_tfm *tfm) skcipher_set_needkey(skcipher); - if (tfm->__crt_alg->cra_type != &crypto_skcipher_type) + if (tfm->__crt_alg->cra_type != &crypto_skcipher_type) { + unsigned am = crypto_skcipher_alignmask(skcipher); + unsigned reqsize; + + reqsize = am & ~(crypto_tfm_ctx_alignment() - 1); + reqsize += crypto_skcipher_ivsize(skcipher); + reqsize += crypto_skcipher_statesize(skcipher); + crypto_skcipher_set_reqsize(skcipher, reqsize); + return crypto_init_lskcipher_ops_sg(tfm); + } if (alg->exit) skcipher->base.exit = crypto_skcipher_exit_tfm; @@ -756,6 +823,7 @@ static void crypto_skcipher_show(struct seq_file *m, struct crypto_alg *alg) seq_printf(m, "ivsize : %u\n", skcipher->ivsize); seq_printf(m, "chunksize : %u\n", skcipher->chunksize); seq_printf(m, "walksize : %u\n", skcipher->walksize); + seq_printf(m, "statesize : %u\n", skcipher->statesize); } static int __maybe_unused crypto_skcipher_report( @@ -870,7 +938,9 @@ int skcipher_prepare_alg_common(struct skcipher_alg_common *alg) struct crypto_istat_cipher *istat = skcipher_get_stat_common(alg); struct crypto_alg *base = &alg->base; - if (alg->ivsize > PAGE_SIZE / 8 || alg->chunksize > PAGE_SIZE / 8) + if (alg->ivsize > PAGE_SIZE / 8 || alg->chunksize > PAGE_SIZE / 8 || + alg->statesize > PAGE_SIZE / 2 || + (alg->ivsize + alg->statesize) > PAGE_SIZE / 2) return -EINVAL; if (!alg->chunksize) @@ -899,6 +969,12 @@ static int skcipher_prepare_alg(struct skcipher_alg *alg) if (!alg->walksize) alg->walksize = alg->chunksize; + if (!alg->statesize) { + alg->import = skcipher_noimport; + alg->export = skcipher_noexport; + } else if (!(alg->import && alg->export)) + return -EINVAL; + base->cra_type = &crypto_skcipher_type; base->cra_flags |= CRYPTO_ALG_TYPE_SKCIPHER; diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index 202ca1a3105d50..ea4d1cea9c0697 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -1524,8 +1524,6 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) ret = min(ret, tcrypt_test("xts(aes)")); ret = min(ret, tcrypt_test("ctr(aes)")); ret = min(ret, tcrypt_test("rfc3686(ctr(aes))")); - ret = min(ret, tcrypt_test("ofb(aes)")); - ret = min(ret, tcrypt_test("cfb(aes)")); ret = min(ret, tcrypt_test("xctr(aes)")); break; @@ -1845,14 +1843,12 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) case 191: ret = min(ret, tcrypt_test("ecb(sm4)")); ret = min(ret, tcrypt_test("cbc(sm4)")); - ret = min(ret, tcrypt_test("cfb(sm4)")); ret = min(ret, tcrypt_test("ctr(sm4)")); ret = min(ret, tcrypt_test("xts(sm4)")); break; case 192: ret = min(ret, tcrypt_test("ecb(aria)")); ret = min(ret, tcrypt_test("cbc(aria)")); - ret = min(ret, tcrypt_test("cfb(aria)")); ret = min(ret, tcrypt_test("ctr(aria)")); break; case 200: @@ -1880,10 +1876,6 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) speed_template_16_24_32); test_cipher_speed("ctr(aes)", DECRYPT, sec, NULL, 0, speed_template_16_24_32); - test_cipher_speed("cfb(aes)", ENCRYPT, sec, NULL, 0, - speed_template_16_24_32); - test_cipher_speed("cfb(aes)", DECRYPT, sec, NULL, 0, - speed_template_16_24_32); break; case 201: @@ -2115,10 +2107,6 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) speed_template_16); test_cipher_speed("cts(cbc(sm4))", DECRYPT, sec, NULL, 0, speed_template_16); - test_cipher_speed("cfb(sm4)", ENCRYPT, sec, NULL, 0, - speed_template_16); - test_cipher_speed("cfb(sm4)", DECRYPT, sec, NULL, 0, - speed_template_16); test_cipher_speed("ctr(sm4)", ENCRYPT, sec, NULL, 0, speed_template_16); test_cipher_speed("ctr(sm4)", DECRYPT, sec, NULL, 0, @@ -2198,10 +2186,6 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) speed_template_16_24_32); test_cipher_speed("cbc(aria)", DECRYPT, sec, NULL, 0, speed_template_16_24_32); - test_cipher_speed("cfb(aria)", ENCRYPT, sec, NULL, 0, - speed_template_16_24_32); - test_cipher_speed("cfb(aria)", DECRYPT, sec, NULL, 0, - speed_template_16_24_32); test_cipher_speed("ctr(aria)", ENCRYPT, sec, NULL, 0, speed_template_16_24_32); test_cipher_speed("ctr(aria)", DECRYPT, sec, NULL, 0, @@ -2436,14 +2420,6 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) speed_template_16_24_32); test_acipher_speed("ctr(aes)", DECRYPT, sec, NULL, 0, speed_template_16_24_32); - test_acipher_speed("cfb(aes)", ENCRYPT, sec, NULL, 0, - speed_template_16_24_32); - test_acipher_speed("cfb(aes)", DECRYPT, sec, NULL, 0, - speed_template_16_24_32); - test_acipher_speed("ofb(aes)", ENCRYPT, sec, NULL, 0, - speed_template_16_24_32); - test_acipher_speed("ofb(aes)", DECRYPT, sec, NULL, 0, - speed_template_16_24_32); test_acipher_speed("rfc3686(ctr(aes))", ENCRYPT, sec, NULL, 0, speed_template_20_28_36); test_acipher_speed("rfc3686(ctr(aes))", DECRYPT, sec, NULL, 0, @@ -2463,18 +2439,6 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) test_acipher_speed("cbc(des3_ede)", DECRYPT, sec, des3_speed_template, DES3_SPEED_VECTORS, speed_template_24); - test_acipher_speed("cfb(des3_ede)", ENCRYPT, sec, - des3_speed_template, DES3_SPEED_VECTORS, - speed_template_24); - test_acipher_speed("cfb(des3_ede)", DECRYPT, sec, - des3_speed_template, DES3_SPEED_VECTORS, - speed_template_24); - test_acipher_speed("ofb(des3_ede)", ENCRYPT, sec, - des3_speed_template, DES3_SPEED_VECTORS, - speed_template_24); - test_acipher_speed("ofb(des3_ede)", DECRYPT, sec, - des3_speed_template, DES3_SPEED_VECTORS, - speed_template_24); break; case 502: @@ -2486,14 +2450,6 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) speed_template_8); test_acipher_speed("cbc(des)", DECRYPT, sec, NULL, 0, speed_template_8); - test_acipher_speed("cfb(des)", ENCRYPT, sec, NULL, 0, - speed_template_8); - test_acipher_speed("cfb(des)", DECRYPT, sec, NULL, 0, - speed_template_8); - test_acipher_speed("ofb(des)", ENCRYPT, sec, NULL, 0, - speed_template_8); - test_acipher_speed("ofb(des)", DECRYPT, sec, NULL, 0, - speed_template_8); break; case 503: @@ -2632,10 +2588,6 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) speed_template_16); test_acipher_speed("cbc(sm4)", DECRYPT, sec, NULL, 0, speed_template_16); - test_acipher_speed("cfb(sm4)", ENCRYPT, sec, NULL, 0, - speed_template_16); - test_acipher_speed("cfb(sm4)", DECRYPT, sec, NULL, 0, - speed_template_16); test_acipher_speed("ctr(sm4)", ENCRYPT, sec, NULL, 0, speed_template_16); test_acipher_speed("ctr(sm4)", DECRYPT, sec, NULL, 0, @@ -2682,14 +2634,6 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) speed_template_16_24_32, num_mb); test_mb_skcipher_speed("ctr(aes)", DECRYPT, sec, NULL, 0, speed_template_16_24_32, num_mb); - test_mb_skcipher_speed("cfb(aes)", ENCRYPT, sec, NULL, 0, - speed_template_16_24_32, num_mb); - test_mb_skcipher_speed("cfb(aes)", DECRYPT, sec, NULL, 0, - speed_template_16_24_32, num_mb); - test_mb_skcipher_speed("ofb(aes)", ENCRYPT, sec, NULL, 0, - speed_template_16_24_32, num_mb); - test_mb_skcipher_speed("ofb(aes)", DECRYPT, sec, NULL, 0, - speed_template_16_24_32, num_mb); test_mb_skcipher_speed("rfc3686(ctr(aes))", ENCRYPT, sec, NULL, 0, speed_template_20_28_36, num_mb); test_mb_skcipher_speed("rfc3686(ctr(aes))", DECRYPT, sec, NULL, @@ -2709,18 +2653,6 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) test_mb_skcipher_speed("cbc(des3_ede)", DECRYPT, sec, des3_speed_template, DES3_SPEED_VECTORS, speed_template_24, num_mb); - test_mb_skcipher_speed("cfb(des3_ede)", ENCRYPT, sec, - des3_speed_template, DES3_SPEED_VECTORS, - speed_template_24, num_mb); - test_mb_skcipher_speed("cfb(des3_ede)", DECRYPT, sec, - des3_speed_template, DES3_SPEED_VECTORS, - speed_template_24, num_mb); - test_mb_skcipher_speed("ofb(des3_ede)", ENCRYPT, sec, - des3_speed_template, DES3_SPEED_VECTORS, - speed_template_24, num_mb); - test_mb_skcipher_speed("ofb(des3_ede)", DECRYPT, sec, - des3_speed_template, DES3_SPEED_VECTORS, - speed_template_24, num_mb); break; case 602: @@ -2732,14 +2664,6 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb) speed_template_8, num_mb); test_mb_skcipher_speed("cbc(des)", DECRYPT, sec, NULL, 0, speed_template_8, num_mb); - test_mb_skcipher_speed("cfb(des)", ENCRYPT, sec, NULL, 0, - speed_template_8, num_mb); - test_mb_skcipher_speed("cfb(des)", DECRYPT, sec, NULL, 0, - speed_template_8, num_mb); - test_mb_skcipher_speed("ofb(des)", ENCRYPT, sec, NULL, 0, - speed_template_8, num_mb); - test_mb_skcipher_speed("ofb(des)", DECRYPT, sec, NULL, 0, - speed_template_8, num_mb); break; case 603: diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 15c7a3011269b7..c26aeda8578781 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -4608,25 +4608,6 @@ static const struct alg_test_desc alg_test_descs[] = { .einval_allowed = 1, } } - }, { - .alg = "cfb(aes)", - .test = alg_test_skcipher, - .fips_allowed = 1, - .suite = { - .cipher = __VECS(aes_cfb_tv_template) - }, - }, { - .alg = "cfb(aria)", - .test = alg_test_skcipher, - .suite = { - .cipher = __VECS(aria_cfb_tv_template) - }, - }, { - .alg = "cfb(sm4)", - .test = alg_test_skcipher, - .suite = { - .cipher = __VECS(sm4_cfb_tv_template) - } }, { .alg = "chacha20", .test = alg_test_skcipher, @@ -4815,6 +4796,16 @@ static const struct alg_test_desc alg_test_descs[] = { .decomp = __VECS(deflate_decomp_tv_template) } } + }, { + .alg = "deflate-iaa", + .test = alg_test_comp, + .fips_allowed = 1, + .suite = { + .comp = { + .comp = __VECS(deflate_comp_tv_template), + .decomp = __VECS(deflate_decomp_tv_template) + } + } }, { .alg = "dh", .test = alg_test_kpp, @@ -4845,14 +4836,6 @@ static const struct alg_test_desc alg_test_descs[] = { .suite = { .drbg = __VECS(drbg_nopr_ctr_aes256_tv_template) } - }, { - /* - * There is no need to specifically test the DRBG with every - * backend cipher -- covered by drbg_nopr_hmac_sha256 test - */ - .alg = "drbg_nopr_hmac_sha1", - .fips_allowed = 1, - .test = alg_test_null, }, { .alg = "drbg_nopr_hmac_sha256", .test = alg_test_drbg, @@ -4861,7 +4844,10 @@ static const struct alg_test_desc alg_test_descs[] = { .drbg = __VECS(drbg_nopr_hmac_sha256_tv_template) } }, { - /* covered by drbg_nopr_hmac_sha256 test */ + /* + * There is no need to specifically test the DRBG with every + * backend cipher -- covered by drbg_nopr_hmac_sha512 test + */ .alg = "drbg_nopr_hmac_sha384", .test = alg_test_null, }, { @@ -4871,10 +4857,6 @@ static const struct alg_test_desc alg_test_descs[] = { .suite = { .drbg = __VECS(drbg_nopr_hmac_sha512_tv_template) } - }, { - .alg = "drbg_nopr_sha1", - .fips_allowed = 1, - .test = alg_test_null, }, { .alg = "drbg_nopr_sha256", .test = alg_test_drbg, @@ -4906,10 +4888,6 @@ static const struct alg_test_desc alg_test_descs[] = { .alg = "drbg_pr_ctr_aes256", .fips_allowed = 1, .test = alg_test_null, - }, { - .alg = "drbg_pr_hmac_sha1", - .fips_allowed = 1, - .test = alg_test_null, }, { .alg = "drbg_pr_hmac_sha256", .test = alg_test_drbg, @@ -4925,10 +4903,6 @@ static const struct alg_test_desc alg_test_descs[] = { .alg = "drbg_pr_hmac_sha512", .test = alg_test_null, .fips_allowed = 1, - }, { - .alg = "drbg_pr_sha1", - .fips_allowed = 1, - .test = alg_test_null, }, { .alg = "drbg_pr_sha256", .test = alg_test_drbg, @@ -5419,26 +5393,6 @@ static const struct alg_test_desc alg_test_descs[] = { .suite = { .hash = __VECS(nhpoly1305_tv_template) } - }, { - .alg = "ofb(aes)", - .test = alg_test_skcipher, - .fips_allowed = 1, - .suite = { - .cipher = __VECS(aes_ofb_tv_template) - } - }, { - /* Same as ofb(aes) except the key is stored in - * hardware secure memory which we reference by index - */ - .alg = "ofb(paes)", - .test = alg_test_null, - .fips_allowed = 1, - }, { - .alg = "ofb(sm4)", - .test = alg_test_skcipher, - .suite = { - .cipher = __VECS(sm4_ofb_tv_template) - } }, { .alg = "pcbc(fcrypt)", .test = alg_test_skcipher, diff --git a/crypto/testmgr.h b/crypto/testmgr.h index d7e98397549b5b..986f331a5fc247 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -14704,104 +14704,6 @@ static const struct cipher_testvec sm4_ctr_rfc3686_tv_template[] = { } }; -static const struct cipher_testvec sm4_ofb_tv_template[] = { - { /* From: draft-ribose-cfrg-sm4-02, paragraph 12.2.3 */ - .key = "\x01\x23\x45\x67\x89\xab\xcd\xef" - "\xfe\xdc\xba\x98\x76\x54\x32\x10", - .klen = 16, - .iv = "\x01\x23\x45\x67\x89\xab\xcd\xef" - "\xfe\xdc\xba\x98\x76\x54\x32\x10", - .ptext = "\x01\x23\x45\x67\x89\xab\xcd\xef" - "\xfe\xdc\xba\x98\x76\x54\x32\x10" - "\x01\x23\x45\x67\x89\xab\xcd\xef" - "\xfe\xdc\xba\x98\x76\x54\x32\x10", - .ctext = "\x69\x3d\x9a\x53\x5b\xad\x5b\xb1" - "\x78\x6f\x53\xd7\x25\x3a\x70\x56" - "\xf2\x07\x5d\x28\xb5\x23\x5f\x58" - "\xd5\x00\x27\xe4\x17\x7d\x2b\xce", - .len = 32, - }, { /* From: draft-ribose-cfrg-sm4-09, appendix A.2.3, Example 1 */ - .key = "\x01\x23\x45\x67\x89\xab\xcd\xef" - "\xfe\xdc\xba\x98\x76\x54\x32\x10", - .klen = 16, - .iv = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - .ptext = "\xaa\xaa\xaa\xaa\xbb\xbb\xbb\xbb" - "\xcc\xcc\xcc\xcc\xdd\xdd\xdd\xdd" - "\xee\xee\xee\xee\xff\xff\xff\xff" - "\xaa\xaa\xaa\xaa\xbb\xbb\xbb\xbb", - .ctext = "\xac\x32\x36\xcb\x86\x1d\xd3\x16" - "\xe6\x41\x3b\x4e\x3c\x75\x24\xb7" - "\x1d\x01\xac\xa2\x48\x7c\xa5\x82" - "\xcb\xf5\x46\x3e\x66\x98\x53\x9b", - .len = 32, - }, { /* From: draft-ribose-cfrg-sm4-09, appendix A.2.3, Example 2 */ - .key = "\xfe\xdc\xba\x98\x76\x54\x32\x10" - "\x01\x23\x45\x67\x89\xab\xcd\xef", - .klen = 16, - .iv = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - .ptext = "\xaa\xaa\xaa\xaa\xbb\xbb\xbb\xbb" - "\xcc\xcc\xcc\xcc\xdd\xdd\xdd\xdd" - "\xee\xee\xee\xee\xff\xff\xff\xff" - "\xaa\xaa\xaa\xaa\xbb\xbb\xbb\xbb", - .ctext = "\x5d\xcc\xcd\x25\xa8\x4b\xa1\x65" - "\x60\xd7\xf2\x65\x88\x70\x68\x49" - "\x33\xfa\x16\xbd\x5c\xd9\xc8\x56" - "\xca\xca\xa1\xe1\x01\x89\x7a\x97", - .len = 32, - } -}; - -static const struct cipher_testvec sm4_cfb_tv_template[] = { - { /* From: draft-ribose-cfrg-sm4-02, paragraph 12.2.4 */ - .key = "\x01\x23\x45\x67\x89\xab\xcd\xef" - "\xfe\xdc\xba\x98\x76\x54\x32\x10", - .klen = 16, - .iv = "\x01\x23\x45\x67\x89\xab\xcd\xef" - "\xfe\xdc\xba\x98\x76\x54\x32\x10", - .ptext = "\x01\x23\x45\x67\x89\xab\xcd\xef" - "\xfe\xdc\xba\x98\x76\x54\x32\x10" - "\x01\x23\x45\x67\x89\xab\xcd\xef" - "\xfe\xdc\xba\x98\x76\x54\x32\x10", - .ctext = "\x69\x3d\x9a\x53\x5b\xad\x5b\xb1" - "\x78\x6f\x53\xd7\x25\x3a\x70\x56" - "\x9e\xd2\x58\xa8\x5a\x04\x67\xcc" - "\x92\xaa\xb3\x93\xdd\x97\x89\x95", - .len = 32, - }, { /* From: draft-ribose-cfrg-sm4-09, appendix A.2.4, Example 1 */ - .key = "\x01\x23\x45\x67\x89\xab\xcd\xef" - "\xfe\xdc\xba\x98\x76\x54\x32\x10", - .klen = 16, - .iv = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - .ptext = "\xaa\xaa\xaa\xaa\xbb\xbb\xbb\xbb" - "\xcc\xcc\xcc\xcc\xdd\xdd\xdd\xdd" - "\xee\xee\xee\xee\xff\xff\xff\xff" - "\xaa\xaa\xaa\xaa\xbb\xbb\xbb\xbb", - .ctext = "\xac\x32\x36\xcb\x86\x1d\xd3\x16" - "\xe6\x41\x3b\x4e\x3c\x75\x24\xb7" - "\x69\xd4\xc5\x4e\xd4\x33\xb9\xa0" - "\x34\x60\x09\xbe\xb3\x7b\x2b\x3f", - .len = 32, - }, { /* From: draft-ribose-cfrg-sm4-09, appendix A.2.4, Example 2 */ - .key = "\xfe\xdc\xba\x98\x76\x54\x32\x10" - "\x01\x23\x45\x67\x89\xab\xcd\xef", - .klen = 16, - .iv = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - .ptext = "\xaa\xaa\xaa\xaa\xbb\xbb\xbb\xbb" - "\xcc\xcc\xcc\xcc\xdd\xdd\xdd\xdd" - "\xee\xee\xee\xee\xff\xff\xff\xff" - "\xaa\xaa\xaa\xaa\xbb\xbb\xbb\xbb", - .ctext = "\x5d\xcc\xcd\x25\xa8\x4b\xa1\x65" - "\x60\xd7\xf2\x65\x88\x70\x68\x49" - "\x0d\x9b\x86\xff\x20\xc3\xbf\xe1" - "\x15\xff\xa0\x2c\xa6\x19\x2c\xc5", - .len = 32, - } -}; - static const struct cipher_testvec sm4_cts_tv_template[] = { /* Generated from AES-CTS test vectors */ { @@ -17064,104 +16966,6 @@ static const struct cipher_testvec aes_cbc_tv_template[] = { }, }; -static const struct cipher_testvec aes_cfb_tv_template[] = { - { /* From NIST SP800-38A */ - .key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6" - "\xab\xf7\x15\x88\x09\xcf\x4f\x3c", - .klen = 16, - .iv = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - .ptext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96" - "\xe9\x3d\x7e\x11\x73\x93\x17\x2a" - "\xae\x2d\x8a\x57\x1e\x03\xac\x9c" - "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" - "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11" - "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef" - "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17" - "\xad\x2b\x41\x7b\xe6\x6c\x37\x10", - .ctext = "\x3b\x3f\xd9\x2e\xb7\x2d\xad\x20" - "\x33\x34\x49\xf8\xe8\x3c\xfb\x4a" - "\xc8\xa6\x45\x37\xa0\xb3\xa9\x3f" - "\xcd\xe3\xcd\xad\x9f\x1c\xe5\x8b" - "\x26\x75\x1f\x67\xa3\xcb\xb1\x40" - "\xb1\x80\x8c\xf1\x87\xa4\xf4\xdf" - "\xc0\x4b\x05\x35\x7c\x5d\x1c\x0e" - "\xea\xc4\xc6\x6f\x9f\xf7\xf2\xe6", - .len = 64, - }, { - .key = "\x8e\x73\xb0\xf7\xda\x0e\x64\x52" - "\xc8\x10\xf3\x2b\x80\x90\x79\xe5" - "\x62\xf8\xea\xd2\x52\x2c\x6b\x7b", - .klen = 24, - .iv = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - .ptext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96" - "\xe9\x3d\x7e\x11\x73\x93\x17\x2a" - "\xae\x2d\x8a\x57\x1e\x03\xac\x9c" - "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" - "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11" - "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef" - "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17" - "\xad\x2b\x41\x7b\xe6\x6c\x37\x10", - .ctext = "\xcd\xc8\x0d\x6f\xdd\xf1\x8c\xab" - "\x34\xc2\x59\x09\xc9\x9a\x41\x74" - "\x67\xce\x7f\x7f\x81\x17\x36\x21" - "\x96\x1a\x2b\x70\x17\x1d\x3d\x7a" - "\x2e\x1e\x8a\x1d\xd5\x9b\x88\xb1" - "\xc8\xe6\x0f\xed\x1e\xfa\xc4\xc9" - "\xc0\x5f\x9f\x9c\xa9\x83\x4f\xa0" - "\x42\xae\x8f\xba\x58\x4b\x09\xff", - .len = 64, - }, { - .key = "\x60\x3d\xeb\x10\x15\xca\x71\xbe" - "\x2b\x73\xae\xf0\x85\x7d\x77\x81" - "\x1f\x35\x2c\x07\x3b\x61\x08\xd7" - "\x2d\x98\x10\xa3\x09\x14\xdf\xf4", - .klen = 32, - .iv = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - .ptext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96" - "\xe9\x3d\x7e\x11\x73\x93\x17\x2a" - "\xae\x2d\x8a\x57\x1e\x03\xac\x9c" - "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" - "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11" - "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef" - "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17" - "\xad\x2b\x41\x7b\xe6\x6c\x37\x10", - .ctext = "\xdc\x7e\x84\xbf\xda\x79\x16\x4b" - "\x7e\xcd\x84\x86\x98\x5d\x38\x60" - "\x39\xff\xed\x14\x3b\x28\xb1\xc8" - "\x32\x11\x3c\x63\x31\xe5\x40\x7b" - "\xdf\x10\x13\x24\x15\xe5\x4b\x92" - "\xa1\x3e\xd0\xa8\x26\x7a\xe2\xf9" - "\x75\xa3\x85\x74\x1a\xb9\xce\xf8" - "\x20\x31\x62\x3d\x55\xb1\xe4\x71", - .len = 64, - }, { /* > 16 bytes, not a multiple of 16 bytes */ - .key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6" - "\xab\xf7\x15\x88\x09\xcf\x4f\x3c", - .klen = 16, - .iv = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - .ptext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96" - "\xe9\x3d\x7e\x11\x73\x93\x17\x2a" - "\xae", - .ctext = "\x3b\x3f\xd9\x2e\xb7\x2d\xad\x20" - "\x33\x34\x49\xf8\xe8\x3c\xfb\x4a" - "\xc8", - .len = 17, - }, { /* < 16 bytes */ - .key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6" - "\xab\xf7\x15\x88\x09\xcf\x4f\x3c", - .klen = 16, - .iv = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - .ptext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f", - .ctext = "\x3b\x3f\xd9\x2e\xb7\x2d\xad", - .len = 7, - }, -}; - static const struct aead_testvec hmac_md5_ecb_cipher_null_tv_template[] = { { /* Input data from RFC 2410 Case 1 */ #ifdef __LITTLE_ENDIAN @@ -20852,55 +20656,6 @@ static const struct cipher_testvec aes_ctr_rfc3686_tv_template[] = { }, }; -static const struct cipher_testvec aes_ofb_tv_template[] = { - { /* From NIST Special Publication 800-38A, Appendix F.5 */ - .key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6" - "\xab\xf7\x15\x88\x09\xcf\x4f\x3c", - .klen = 16, - .iv = "\x00\x01\x02\x03\x04\x05\x06\x07\x08" - "\x09\x0a\x0b\x0c\x0d\x0e\x0f", - .ptext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96" - "\xe9\x3d\x7e\x11\x73\x93\x17\x2a" - "\xae\x2d\x8a\x57\x1e\x03\xac\x9c" - "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51" - "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11" - "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef" - "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17" - "\xad\x2b\x41\x7b\xe6\x6c\x37\x10", - .ctext = "\x3b\x3f\xd9\x2e\xb7\x2d\xad\x20" - "\x33\x34\x49\xf8\xe8\x3c\xfb\x4a" - "\x77\x89\x50\x8d\x16\x91\x8f\x03\xf5" - "\x3c\x52\xda\xc5\x4e\xd8\x25" - "\x97\x40\x05\x1e\x9c\x5f\xec\xf6\x43" - "\x44\xf7\xa8\x22\x60\xed\xcc" - "\x30\x4c\x65\x28\xf6\x59\xc7\x78" - "\x66\xa5\x10\xd9\xc1\xd6\xae\x5e", - .len = 64, - }, { /* > 16 bytes, not a multiple of 16 bytes */ - .key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6" - "\xab\xf7\x15\x88\x09\xcf\x4f\x3c", - .klen = 16, - .iv = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - .ptext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96" - "\xe9\x3d\x7e\x11\x73\x93\x17\x2a" - "\xae", - .ctext = "\x3b\x3f\xd9\x2e\xb7\x2d\xad\x20" - "\x33\x34\x49\xf8\xe8\x3c\xfb\x4a" - "\x77", - .len = 17, - }, { /* < 16 bytes */ - .key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6" - "\xab\xf7\x15\x88\x09\xcf\x4f\x3c", - .klen = 16, - .iv = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - .ptext = "\x6b\xc1\xbe\xe2\x2e\x40\x9f", - .ctext = "\x3b\x3f\xd9\x2e\xb7\x2d\xad", - .len = 7, - } -}; - static const struct aead_testvec aes_gcm_tv_template[] = { { /* From McGrew & Viega - http://citeseer.ist.psu.edu/656989.html */ .key = zeroed_string, @@ -29349,909 +29104,6 @@ static const struct cipher_testvec aria_ctr_tv_template[] = { } }; -static const struct cipher_testvec aria_cfb_tv_template[] = { - { - .key = "\x7f\x92\xd5\x06\x30\x6b\xc0\x23" - "\x87\xa8\x8e\x6d\xc7\xc5\xd7\xf1", - .klen = 16, - .iv = "\x5f\xce\x89\xb3\xd5\x7f\x7f\xf0" - "\xfd\xab\x56\xa6\x6e\xda\x7c\x57", - .ptext = "\x36\x36\x89\x09\xcd\xa8\xd3\x91" - "\x48\x3e\x3c\x11\xcf\xd0\x4f\xc0", - .ctext = "\x19\x28\xb5\xf2\x1c\xbc\xf8\xaf" - "\xb9\xae\x1b\x23\x4f\xe1\x6e\x40", - }, { - .key = "\x51\xe3\x8c\xe9\x76\xcd\xff\x37" - "\xd6\x1a\x18\x2f\x68\x2f\xb6\xfe", - .klen = 16, - .iv = "\x3d\x2d\x85\x75\x6e\x18\x8a\x52" - "\x53\x39\xfc\xc1\xf5\xc0\x56\x22", - .ptext = "\xc6\xae\xaa\x0d\x90\xf2\x38\x93" - "\xac\xd2\x3f\xc7\x74\x8d\x13\x7e" - "\xfa\x3f\x70\x52\xfb\x04\x0e\xed" - "\x0e\x60\x75\x84\x21\xdf\x13\xa1", - .ctext = "\x3f\x8c\xa9\x19\xd6\xb4\xfb\xed" - "\x9c\x6d\xaa\x1b\xe1\xc1\xe6\xa8" - "\x47\x35\x7d\xa3\x96\x7d\x53\x60" - "\xa9\x33\x9c\x34\xae\x7d\x7c\x74", - .len = 32, - }, { - .key = "\x26\xf8\x8c\x26\x0a\x37\x51\x8f" - "\xe7\x9c\x74\x77\x7a\x3e\xbb\x5d", - .klen = 16, - .iv = "\xd7\x33\xf3\xa9\x5b\xb4\x86\xea" - "\xe3\x7d\x50\x62\x3b\x73\xaf\xc4", - .ptext = "\xda\x89\xd9\x3c\xcc\xe4\x73\xb0" - "\xef\x3e\x5f\x46\x62\x88\xd5\x26" - "\x3b\xd3\xb5\x81\x78\x70\x1b\xd2" - "\x39\x56\x34\x63\x2c\xc5\x51\x13" - "\x48\x29\x3a\x58\xbe\x41\xc5\x80" - "\x2c\x80\xa7\x3c\x14\xb4\x89\x5e", - .ctext = "\x28\xd8\xa7\xf8\x74\x98\x00\xfc" - "\xd6\x48\xad\xbd\xbe\x3f\x0e\x7b" - "\xa3\xec\x03\x6a\xfb\xc9\x01\x83" - "\xb3\x2f\xda\x5e\x66\xa0\xc3\xec" - "\xe9\xd4\x72\x2a\xa2\x90\x41\xcf" - "\xde\x30\x79\xc3\x82\x10\x51\xe1", - .len = 48, - }, { - .key = "\x8e\xe5\x5f\xe2\x39\x80\xf5\x2b" - "\x77\xb5\xca\x90\xda\x1d\x22\x17", - .klen = 16, - .iv = "\xd9\xa0\x57\x80\xc8\x96\x70\x86" - "\x07\x2c\xf4\x61\x79\x09\x01\x8f", - .ptext = "\x37\x32\x98\xd4\x86\x2b\x3b\x80" - "\x07\x60\xba\xf0\x2e\xc3\x4a\x57" - "\xf5\xb5\xd7\xbf\xd2\x2a\x9b\x4a" - "\xe6\x08\xf0\xbe\x77\xd1\x62\x40" - "\xa0\x82\x09\x60\x47\xbb\x16\x56" - "\x50\x1f\xab\x8b\x10\xfe\xf0\x5c" - "\x05\x32\x63\x1a\xc4\x46\x6f\x55" - "\x32\xde\x41\x5a\xf7\x52\xd7\xfa", - .ctext = "\x29\x31\x55\xd2\xe5\x0b\x81\x39" - "\xf9\xbc\x63\xe2\xfa\x26\x99\xde" - "\x5c\xd3\x0a\x56\xe5\xfc\x83\xdd" - "\xab\x26\x90\x7d\xa8\x0f\x01\xa6" - "\x0e\x01\xdc\x1f\xfa\xa7\xdd\x09" - "\xf9\xbf\x12\xf4\xc6\x9f\xbd\x57" - "\x23\x68\x54\x0f\xe0\xcf\x1c\x6d" - "\xe1\x5e\x0b\x4a\x1e\x71\x1d\xaa", - .len = 64, - }, { - .key = "\x30\x9d\x59\x8d\x64\x76\xad\x37" - "\xba\xbc\x46\x6a\x69\x17\x3c\xac", - .klen = 16, - .iv = "\x6f\xdd\xa2\x9b\x86\x32\x14\x2e" - "\x54\x74\x8f\x3d\xe2\xd6\x85\x44", - .ptext = "\x4f\x4a\x31\x64\xc6\xa5\x29\xaa" - "\xad\xfd\x32\x94\x1f\x56\x57\xd1" - "\x9d\x7e\x3d\x49\x00\x36\xb1\x5d" - "\xb2\x92\x83\x70\x1e\xa3\x97\xa6" - "\x65\x53\x39\xeb\x53\x8f\xb1\x38" - "\x91\xac\x17\x11\x1c\x03\x69\x53" - "\xf5\xdf\xdb\x2c\x1b\x9a\x6e\x6b" - "\xb6\x02\xc4\xfa\x95\x01\x33\xa8" - "\xda\x7e\x18\x2c\xf4\x7e\x6e\x67" - "\xce\x8f\x9f\xea\x46\x66\x99\xb8", - .ctext = "\x38\xbc\xf5\x9d\x0e\x26\xa6\x18" - "\x95\x0b\x23\x54\x09\xa1\xf9\x46" - "\x7a\x31\xa0\xd7\x4a\xec\xb3\x10" - "\x8a\x8e\x99\x78\x6c\x6e\x76\xf2" - "\x63\x8a\x3b\x90\xaa\xd5\x64\x65" - "\x5a\x52\xb0\x36\x4c\xce\xed\xc7" - "\x51\x3c\x06\xb0\xee\x54\xec\x10" - "\xc0\x5f\xfd\xa9\x44\x9a\x29\x32" - "\x19\x79\x7d\x2b\x14\x26\x96\x13" - "\x9d\xa5\x61\xbd\xb6\x72\x37\x26", - .len = 80, - }, { - .key = "\xe1\xc7\x25\x4d\xbd\xa5\x74\xdf" - "\xc7\x8b\xfb\xe3\x2d\x3a\x82\xd3", - .klen = 16, - .iv = "\x17\x94\x77\x2f\x92\xb8\x87\xc2" - "\xcc\x6f\x70\x26\x87\xc7\x10\x8a", - .ptext = "\xc8\xfd\xc2\xb3\xcf\xa0\xeb\x41" - "\x4c\xf4\xd0\x34\xd0\x95\xab\xae" - "\x82\x5c\xfd\xfa\x13\x86\x25\xce" - "\xf4\x13\x32\xcd\xc6\x6d\xf6\x50" - "\x12\x4a\x5b\x66\x3a\xd3\xfb\x1a" - "\xaf\x06\xea\xf4\x65\x59\xd6\xc2" - "\x84\xa0\x53\x97\x61\x30\x70\x15" - "\xac\x45\x8e\xe8\xeb\xa1\x72\x93" - "\x26\x76\x98\x6f\xe4\x86\xca\xf0" - "\x57\x89\xf2\x2b\xd4\xcf\x2d\x95" - "\x86\x26\x20\x0e\x62\xfe\x8f\x1e" - "\x5d\xcb\x2b\x7e\xdd\xab\xac\xda", - .ctext = "\xdf\x79\x58\x30\x6f\x47\x12\x78" - "\x04\xb2\x0b\x1a\x62\x22\xe2\x9f" - "\xfe\x90\x50\x41\x1b\x6a\x6a\x9c" - "\x4e\x77\x8f\xca\xd1\x68\x31\xcd" - "\x41\x82\xa5\x5b\xc0\x08\x2b\x37" - "\x62\xec\x95\xf1\x56\x12\x38\x66" - "\x84\x82\x72\xda\x00\x21\x96\x82" - "\x33\xd4\x99\xaa\xb9\xeb\xd5\xc3" - "\x2b\xa8\xf7\xdc\x13\x0e\x21\x9f" - "\x4b\xf9\x42\x58\xa8\x39\x10\xd5" - "\x86\xa5\xc6\x78\x3b\x34\x05\x03" - "\x54\x43\x2b\x80\xa9\x53\x4d\x0e", - .len = 96, - }, { - .key = "\x6e\x49\x20\xd5\xb7\x01\x83\x4e" - "\xac\x45\x8f\xe1\x05\x3f\xd5\xb1", - .klen = 16, - .iv = "\xee\xb7\x0d\x65\x00\x38\xab\x71" - "\x70\x6e\xb3\x97\x86\xd3\xcd\xad", - .ptext = "\x51\x8b\x9c\xa0\x9a\x8b\x4c\xb9" - "\x16\x01\x6a\x1f\xdf\xf0\xf9\x9e" - "\x25\x1b\xc2\xa6\x21\x25\xeb\x97" - "\x4b\xf6\xcb\x3b\xcd\x61\xfd\x94" - "\x37\x03\xb3\xd9\x74\x6e\x4d\xbb" - "\xfd\x87\x2b\xec\x4c\x2c\xbf\xe2" - "\x94\x1a\xe6\xd9\xaf\x0e\x78\x17" - "\x58\x2b\x1d\x73\x9a\x9c\x63\x18" - "\x88\x7a\x0e\x87\x2f\xf0\xb0\xdb" - "\xc9\x9d\x79\x51\x34\x39\x4f\x07" - "\xa2\x7c\x21\x04\x91\x3b\x79\x79" - "\xfe\xd5\x51\x46\xd5\xcd\x28\xc0" - "\xad\xb8\x55\xb2\xb2\x5a\x9a\xa2" - "\xe2\x0c\xfc\x55\x7d\x60\xd2\x95", - .ctext = "\xe4\x25\x0d\x22\xeb\xbe\x5e\x90" - "\x01\xe5\xae\xc9\x94\xbd\x93\x89" - "\x5e\x5a\x5a\x2f\xf6\xdf\xf8\x16" - "\xd3\xb2\xed\x29\x51\xe2\x75\xb0" - "\x1a\x48\xb5\xe6\xd3\x58\x40\xc7" - "\x6f\x6f\xcf\x57\x82\x43\x5a\x36" - "\xef\x27\xe1\x34\x85\x01\xec\x98" - "\x00\xbd\x94\x6f\x12\x39\xa8\x13" - "\xfe\x3c\x39\xc0\xc6\xe1\xcc\x05" - "\x0e\xd5\xc9\xda\xbd\xdd\xdb\xaa" - "\x5a\xaa\x8e\xe8\xa8\x0a\xc5\x18" - "\xb4\x1d\x13\x81\xc9\xc4\xaa\x61" - "\xa9\xbd\xaa\x03\x12\x93\xbb\xed" - "\x0c\x6e\xbd\x1c\x05\x16\x8a\x59", - .len = 112, - }, { - .key = "\xb6\x08\x1d\x31\xaf\xf4\x17\x46" - "\xa4\xbb\x0f\xbd\x67\x3c\x73\x15", - .klen = 16, - .iv = "\x0c\x85\x2f\x62\xe5\xf4\x35\x96" - "\xb1\x9b\x5d\x00\x10\xe9\x70\x12", - .ptext = "\x3a\x87\x7f\x67\xf1\x81\x7a\x05" - "\xb4\xa6\xfe\xdf\x36\x31\x6d\x9e" - "\x0e\xa9\x44\xa0\xb0\x05\xa9\x41" - "\x9c\x14\x44\x5a\xd5\x1c\x50\x08" - "\x95\xc2\xf2\xaf\x3f\x29\xc9\x3e" - "\x95\x5e\xc6\xb4\x2b\xf4\x3e\xe3" - "\x1b\xeb\x3d\x73\xfb\xd7\x1e\x2b" - "\x0c\x3d\x58\x6c\xb4\x41\x9b\xfe" - "\x2f\x7e\x1c\x10\x81\x36\x2d\x79" - "\xaf\xab\x10\x44\x2e\xcc\x0d\x6c" - "\x9c\x14\xc2\xe4\xae\xb0\xbb\xda" - "\x6a\xe0\x42\x3d\x96\x9f\x78\x7d" - "\x70\x86\xa5\x92\x9f\xee\xcd\x3f" - "\x6a\x55\x84\x98\x28\x03\x02\xc2" - "\xf7\xec\x7a\xfa\xb1\xd9\xa8\xd8" - "\x1c\xc3\xaa\xd5\x61\x7f\x10\x0c", - .ctext = "\xa7\x4c\x96\x55\x7c\x07\xce\xb2" - "\x6f\x63\x9f\xc6\x8b\x6f\xc6\x4a" - "\x85\xf2\x4b\xdf\x62\x0c\x6c\x8d" - "\x13\x5d\xd3\x40\x58\xa6\xf9\x03" - "\xd9\xf2\x48\x4e\x12\x64\x9a\x55" - "\xa2\xa3\xd0\x19\xe5\x5b\xaa\x62" - "\x7b\xe9\x2a\x23\xab\xb5\xa6\xcf" - "\x53\x59\x70\xc6\xb8\x92\x12\x3b" - "\x93\x68\x24\xba\x7d\xd6\xc0\x5b" - "\x06\x2e\x7f\x2e\x32\x5d\x42\x9c" - "\x13\x8e\x92\x3c\x99\x20\x32\x2b" - "\x4a\x41\xb2\x4a\x81\xe8\x6e\x7f" - "\x5b\x8e\xca\x4d\xd7\x29\x96\xde" - "\x30\x9c\xa6\x84\x90\xe7\xc2\xae" - "\xf4\x7e\x73\x32\x4c\x25\xec\xef" - "\x58\x69\x63\x3f\x4e\x71\x4b\x1c", - .len = 128, - }, { - .key = "\xc0\xa1\x36\x3d\x81\x9a\xd2\x17" - "\x2e\x23\xc9\xb7\xff\xdf\x47\x6c", - .klen = 16, - .iv = "\x96\x3b\x0e\xbd\xec\x9a\x0e\xad" - "\x8c\xaf\x36\x3d\xff\x29\x8b\x33", - .ptext = "\x87\x96\x77\x1a\x10\x81\x63\x8a" - "\x63\xde\x88\xa9\x9d\xa9\x01\xf2" - "\xdf\xc9\x25\x35\x48\x3a\x15\xdf" - "\x20\x6b\x91\x7c\x56\xe5\x10\x7a" - "\x2d\x2e\x0f\x30\x32\xed\xa9\x1f" - "\x71\x4e\x68\x77\xe8\xa8\x5b\xdd" - "\x3c\x5e\x68\x6b\xab\x03\xe4\xf8" - "\x42\xc1\x61\x9a\x50\xfb\xc7\x6a" - "\x1a\x31\xa7\x87\xd0\x24\xcb\x5e" - "\xc0\x3b\x12\x28\xca\x26\x7b\xb3" - "\x14\xc1\x7f\x66\xff\x3b\xa4\x80" - "\x59\x77\x4f\xa0\xd4\xb2\xd9\x8a" - "\xb6\x67\xe6\x28\xd3\x6f\xf2\xcf" - "\xb8\x6d\x2d\xc4\x2a\x69\x89\xff" - "\xcf\xbb\x11\x2e\x2a\x2b\x7c\xfd" - "\xcd\x56\x02\x95\xc9\x54\x6e\x62" - "\x6a\x97\x75\x1a\x21\x16\x46\xfb" - "\xc2\xab\x62\x54\xef\xba\xae\x46", - .ctext = "\x11\x7f\xea\x49\xaf\x24\x52\xa2" - "\xde\x60\x99\x58\x23\xf9\x9e\x91" - "\x94\x52\x31\xa3\x28\x07\x14\xad" - "\x00\x24\x4a\x4a\xe7\x18\xd7\x24" - "\xcc\x8b\x66\x53\x82\x65\x31\xa5" - "\x54\x76\x59\x0b\x69\x6f\x90\x2c" - "\x8d\xa5\x2b\x61\x05\x80\xfb\xe0" - "\xf9\x6e\xaf\xb9\xc4\x15\x67\xcc" - "\x15\xce\xa0\xc0\xf2\xae\xa6\x15" - "\x24\x9a\xe5\xcb\x09\x42\xcf\x41" - "\x95\xa4\x8d\xbf\xe8\xb8\x40\xcd" - "\xb0\x33\x2c\xb3\xc4\xdd\xf9\x45" - "\xda\xb2\xeb\xb3\xf8\xfa\x7f\xe3" - "\xc0\x3a\x98\xe7\x17\x4a\x0c\x60" - "\xb2\x22\xba\x3b\x21\x85\x27\x56" - "\xe0\xb2\xf7\x2a\x59\xb1\x56\x20" - "\x0b\xa9\x13\x73\xe0\x6f\x61\x32" - "\xa5\x38\x14\xb3\xe3\xaa\x70\x44", - .len = 144, - }, { - .key = "\xd4\x14\xc6\xcc\x16\x1b\x95\xf9" - "\x05\x26\x23\x81\x19\x27\xad\x7b", - .klen = 16, - .iv = "\x9c\x8b\xfb\x65\xa4\x61\xee\x69" - "\x44\xbf\x59\xde\x03\x61\x11\x12", - .ptext = "\x8d\x94\x48\x47\xa9\x52\x16\xfb" - "\x6b\xaf\x59\x6d\xab\x74\xbf\x5c" - "\xb6\x09\x21\x12\x42\x98\x13\xa1" - "\xa8\x6f\xb9\x6d\x4d\xa6\xdc\xea" - "\x61\x02\x3c\xa7\xcd\x1a\x28\x8c" - "\x66\xb8\x4d\x60\x67\x82\xcc\x8d" - "\x1e\xda\x8f\x28\xe5\x02\xdc\x2c" - "\x54\x84\x2a\x06\xb5\xd1\x34\x57" - "\xb8\x28\x4d\xf5\x69\xb9\xf3\x33" - "\x5e\x0b\xa6\x62\x35\x9b\xfb\x97" - "\x3e\xc6\xec\xaf\x74\xe8\x72\x91" - "\xb2\xc6\x56\xb3\x23\x29\x43\xe0" - "\xfb\xcc\x21\x38\x64\x78\x9e\x78" - "\xbb\x6e\x0d\x7b\xfd\x05\x74\x01" - "\x7c\x94\xe0\xb0\xd7\x92\xfc\x58" - "\x28\xfc\xe2\x7b\x7f\xf7\x31\x0d" - "\x90\xb7\x60\x78\xa8\x9f\x52\xe3" - "\xe6\xaa\x2a\xb4\xa7\x09\x60\x53" - "\x42\x0e\x15\x31\xf6\x48\xa3\x0a" - "\x20\xf0\x79\x67\xb1\x83\x26\x66", - .ctext = "\x5b\xc0\xe8\x17\xa4\xf9\xea\xce" - "\x9e\xf9\xe0\xb1\xac\x37\xe9\x41" - "\xc8\x06\xf9\x1c\x1a\xfc\xe8\x7a" - "\x38\xf2\x80\x66\xc2\x70\x59\x4e" - "\xe0\x32\x5b\x27\x39\xf5\xfb\x03" - "\xc8\xaf\xd6\x7e\x57\xc7\xc6\x71" - "\xd9\xd0\x48\x39\xb1\x0d\xa8\x1a" - "\x23\x8a\x3d\x05\xe2\x90\x7e\x18" - "\xd7\x20\x04\x3b\x82\x76\x3f\xaa" - "\xc2\x89\xb6\x9e\x14\x2f\x46\xcd" - "\x51\x9b\xa8\x7b\x62\x7b\x9c\x17" - "\xc4\xe1\x8b\x3f\xb5\x4d\xac\x66" - "\x49\xf6\xb6\x4c\x3e\x16\x46\xb0" - "\xca\x04\xef\x72\x5c\x03\x0a\xe5" - "\x2f\x4e\x36\x38\x36\x9f\xf4\xe2" - "\x81\x7a\x4c\xdf\x36\x27\xd5\x9d" - "\x03\xad\x1d\x3a\xe9\x2a\x99\xb0" - "\x2c\xba\x13\x75\xc8\x37\x97\x11" - "\xf4\x15\x0f\xb7\x75\x26\xa1\x14" - "\x79\xec\x1f\xab\xd2\x10\x8c\x5f", - .len = 160, - }, { - .key = "\x7f\x92\xd5\x06\x30\x6b\xc0\x23" - "\x87\xa8\x8e\x6d\xc7\xc5\xd7\xf1" - "\x5f\xce\x89\xb3\xd5\x7f\x7f\xf0", - .klen = 24, - .iv = "\xfd\xab\x56\xa6\x6e\xda\x7c\x57" - "\x36\x36\x89\x09\xcd\xa8\xd3\x91", - .ptext = "\x48\x3e\x3c\x11\xcf\xd0\x4f\xc0" - "\x51\xe3\x8c\xe9\x76\xcd\xff\x37", - .ctext = "\xa4\x12\x2f\xc4\xf0\x6d\xd9\x46" - "\xe4\xe6\xd1\x0b\x6d\x14\xf0\x8f", - .len = 16, - }, { - .key = "\xd6\x1a\x18\x2f\x68\x2f\xb6\xfe" - "\x3d\x2d\x85\x75\x6e\x18\x8a\x52" - "\x53\x39\xfc\xc1\xf5\xc0\x56\x22", - .klen = 24, - .iv = "\xc6\xae\xaa\x0d\x90\xf2\x38\x93" - "\xac\xd2\x3f\xc7\x74\x8d\x13\x7e", - .ptext = "\xfa\x3f\x70\x52\xfb\x04\x0e\xed" - "\x0e\x60\x75\x84\x21\xdf\x13\xa1" - "\x26\xf8\x8c\x26\x0a\x37\x51\x8f" - "\xe7\x9c\x74\x77\x7a\x3e\xbb\x5d", - .ctext = "\x80\x2b\xf0\x88\xb9\x4b\x8d\xf5" - "\xc3\x0e\x15\x5b\xea\x5d\x5b\xa8" - "\x52\xe7\x83\x3c\xa1\x51\x1c\x1f" - "\x38\xd9\x7c\x88\x3c\x3a\xcd\x3e", - .len = 32, - }, { - .key = "\xd7\x33\xf3\xa9\x5b\xb4\x86\xea" - "\xe3\x7d\x50\x62\x3b\x73\xaf\xc4" - "\xda\x89\xd9\x3c\xcc\xe4\x73\xb0", - .klen = 24, - .iv = "\xef\x3e\x5f\x46\x62\x88\xd5\x26" - "\x3b\xd3\xb5\x81\x78\x70\x1b\xd2", - .ptext = "\x39\x56\x34\x63\x2c\xc5\x51\x13" - "\x48\x29\x3a\x58\xbe\x41\xc5\x80" - "\x2c\x80\xa7\x3c\x14\xb4\x89\x5e" - "\x8e\xe5\x5f\xe2\x39\x80\xf5\x2b" - "\x77\xb5\xca\x90\xda\x1d\x22\x17" - "\xd9\xa0\x57\x80\xc8\x96\x70\x86", - .ctext = "\x65\x01\x3c\xb0\xac\x4c\x63\xb6" - "\xe7\xf1\xf4\x61\x35\xf4\x36\xde" - "\xeb\x0f\x8c\x34\xd1\x78\xb4\x00" - "\xb2\xc1\x7c\x28\xb2\xb7\xbb\xa3" - "\xc6\xb7\x27\xf7\x6d\x56\x79\xfa" - "\x61\x57\xba\x30\x6f\x56\xe9\x8c", - .len = 48, - }, { - .key = "\x07\x2c\xf4\x61\x79\x09\x01\x8f" - "\x37\x32\x98\xd4\x86\x2b\x3b\x80" - "\x07\x60\xba\xf0\x2e\xc3\x4a\x57", - .klen = 24, - .iv = "\xf5\xb5\xd7\xbf\xd2\x2a\x9b\x4a" - "\xe6\x08\xf0\xbe\x77\xd1\x62\x40", - .ptext = "\xa0\x82\x09\x60\x47\xbb\x16\x56" - "\x50\x1f\xab\x8b\x10\xfe\xf0\x5c" - "\x05\x32\x63\x1a\xc4\x46\x6f\x55" - "\x32\xde\x41\x5a\xf7\x52\xd7\xfa" - "\x30\x9d\x59\x8d\x64\x76\xad\x37" - "\xba\xbc\x46\x6a\x69\x17\x3c\xac" - "\x6f\xdd\xa2\x9b\x86\x32\x14\x2e" - "\x54\x74\x8f\x3d\xe2\xd6\x85\x44", - .ctext = "\x5a\xfb\xb1\x2c\x6e\xe5\xb8\xe0" - "\x80\xb6\x77\xa8\xfe\x10\x3a\x99" - "\xbf\xc0\x2a\xfe\x6f\x38\xf2\x1d" - "\x53\x6c\x05\x83\xb1\x13\x00\x87" - "\x92\x92\x42\x70\xcf\x9f\xf7\x8f" - "\x53\x55\x18\x6f\x35\x68\x35\x50" - "\x3a\xc8\x45\x3e\xa3\xf1\x33\x2e" - "\xa1\x65\x42\xe2\x6d\x31\x8c\x4b", - .len = 64, - }, { - .key = "\x4f\x4a\x31\x64\xc6\xa5\x29\xaa" - "\xad\xfd\x32\x94\x1f\x56\x57\xd1" - "\x9d\x7e\x3d\x49\x00\x36\xb1\x5d", - .klen = 24, - .iv = "\xb2\x92\x83\x70\x1e\xa3\x97\xa6" - "\x65\x53\x39\xeb\x53\x8f\xb1\x38", - .ptext = "\x91\xac\x17\x11\x1c\x03\x69\x53" - "\xf5\xdf\xdb\x2c\x1b\x9a\x6e\x6b" - "\xb6\x02\xc4\xfa\x95\x01\x33\xa8" - "\xda\x7e\x18\x2c\xf4\x7e\x6e\x67" - "\xce\x8f\x9f\xea\x46\x66\x99\xb8" - "\xe1\xc7\x25\x4d\xbd\xa5\x74\xdf" - "\xc7\x8b\xfb\xe3\x2d\x3a\x82\xd3" - "\x17\x94\x77\x2f\x92\xb8\x87\xc2" - "\xcc\x6f\x70\x26\x87\xc7\x10\x8a" - "\xc8\xfd\xc2\xb3\xcf\xa0\xeb\x41", - .ctext = "\xc9\x5f\xe0\x60\x61\x38\x7e\x79" - "\x52\x68\x64\x8f\x55\x9b\x6b\x72" - "\xa5\x17\x61\xb7\xce\x02\xa9\xa4" - "\x5c\x73\x45\x33\xd1\x07\x5e\xdc" - "\xe5\xbe\xa7\xde\x69\xa0\x97\x98" - "\x02\xef\xa4\x67\x51\x60\x69\x4f" - "\x03\xf5\xa8\x5f\x03\x69\xbc\xc2" - "\x34\x59\x7e\xd4\xd2\xb3\x32\x2f" - "\x0c\xb4\x37\xca\xc4\xc7\x93\xf4" - "\xa4\xab\x01\x3f\x91\x29\x55\x98", - .len = 80, - }, { - .key = "\x4c\xf4\xd0\x34\xd0\x95\xab\xae" - "\x82\x5c\xfd\xfa\x13\x86\x25\xce" - "\xf4\x13\x32\xcd\xc6\x6d\xf6\x50", - .klen = 24, - .iv = "\x12\x4a\x5b\x66\x3a\xd3\xfb\x1a" - "\xaf\x06\xea\xf4\x65\x59\xd6\xc2", - .ptext = "\x84\xa0\x53\x97\x61\x30\x70\x15" - "\xac\x45\x8e\xe8\xeb\xa1\x72\x93" - "\x26\x76\x98\x6f\xe4\x86\xca\xf0" - "\x57\x89\xf2\x2b\xd4\xcf\x2d\x95" - "\x86\x26\x20\x0e\x62\xfe\x8f\x1e" - "\x5d\xcb\x2b\x7e\xdd\xab\xac\xda" - "\x6e\x49\x20\xd5\xb7\x01\x83\x4e" - "\xac\x45\x8f\xe1\x05\x3f\xd5\xb1" - "\xee\xb7\x0d\x65\x00\x38\xab\x71" - "\x70\x6e\xb3\x97\x86\xd3\xcd\xad" - "\x51\x8b\x9c\xa0\x9a\x8b\x4c\xb9" - "\x16\x01\x6a\x1f\xdf\xf0\xf9\x9e", - .ctext = "\x03\x2c\x39\x24\x99\xb5\xf6\x79" - "\x91\x89\xb7\xf8\x89\x68\x37\x9d" - "\xa2\x80\x95\x74\x87\x64\xb9\xeb" - "\x85\x28\x92\x9a\x6e\xd3\x3b\x50" - "\x4c\x80\x5b\xe4\xf2\x7e\xda\x2a" - "\xd4\xf8\xcb\xe3\x6f\xdf\xae\x0e" - "\xc5\x6c\x0b\x49\x2e\x29\x1c\xf2" - "\x3f\x44\x44\x12\x67\xa6\xff\x44" - "\xe0\xec\xd8\xf7\x32\xde\x21\x15" - "\xab\x8f\x98\x4d\xed\xb0\x42\xfd" - "\x83\x94\xe2\xcc\x69\x6d\xe8\xdb" - "\x62\x93\x1f\xd0\xf4\x8c\x62\xc0", - .len = 96, - }, { - .key = "\x25\x1b\xc2\xa6\x21\x25\xeb\x97" - "\x4b\xf6\xcb\x3b\xcd\x61\xfd\x94" - "\x37\x03\xb3\xd9\x74\x6e\x4d\xbb", - .klen = 24, - .iv = "\xfd\x87\x2b\xec\x4c\x2c\xbf\xe2" - "\x94\x1a\xe6\xd9\xaf\x0e\x78\x17", - .ptext = "\x58\x2b\x1d\x73\x9a\x9c\x63\x18" - "\x88\x7a\x0e\x87\x2f\xf0\xb0\xdb" - "\xc9\x9d\x79\x51\x34\x39\x4f\x07" - "\xa2\x7c\x21\x04\x91\x3b\x79\x79" - "\xfe\xd5\x51\x46\xd5\xcd\x28\xc0" - "\xad\xb8\x55\xb2\xb2\x5a\x9a\xa2" - "\xe2\x0c\xfc\x55\x7d\x60\xd2\x95" - "\xb6\x08\x1d\x31\xaf\xf4\x17\x46" - "\xa4\xbb\x0f\xbd\x67\x3c\x73\x15" - "\x0c\x85\x2f\x62\xe5\xf4\x35\x96" - "\xb1\x9b\x5d\x00\x10\xe9\x70\x12" - "\x3a\x87\x7f\x67\xf1\x81\x7a\x05" - "\xb4\xa6\xfe\xdf\x36\x31\x6d\x9e" - "\x0e\xa9\x44\xa0\xb0\x05\xa9\x41", - .ctext = "\xd4\x9a\x04\x54\x05\xd2\xe6\x3f" - "\xb0\xa4\x36\x5e\x1e\x9c\x35\xb0" - "\xc0\x89\xbd\x1c\xaa\x45\xa6\xc8" - "\x16\x68\x4a\x06\x93\x67\x88\xd7" - "\x72\x6e\x48\x0a\x17\xa3\x52\x8b" - "\x96\x5f\x41\xf6\x17\x64\x55\x8b" - "\xac\xce\xf6\x8c\xce\xd2\xd4\xd4" - "\x8d\x92\x32\xe0\x0d\xb4\xf7\x4a" - "\x90\xaf\x7b\x85\x21\x46\x2e\xa6" - "\x9e\xac\x0d\x22\xf2\x26\xf6\xd3" - "\x27\xcd\x59\xa0\xe2\xbb\x22\xcd" - "\x35\xb6\x28\x45\x0a\x46\xb0\x3a" - "\xac\x3e\xd3\x5b\xc6\x54\xa2\xa3" - "\x6d\xbb\xb3\xcd\xc5\x64\x62\x92", - .len = 112, - }, { - .key = "\x9c\x14\x44\x5a\xd5\x1c\x50\x08" - "\x95\xc2\xf2\xaf\x3f\x29\xc9\x3e" - "\x95\x5e\xc6\xb4\x2b\xf4\x3e\xe3", - .klen = 24, - .iv = "\x1b\xeb\x3d\x73\xfb\xd7\x1e\x2b" - "\x0c\x3d\x58\x6c\xb4\x41\x9b\xfe", - .ptext = "\x2f\x7e\x1c\x10\x81\x36\x2d\x79" - "\xaf\xab\x10\x44\x2e\xcc\x0d\x6c" - "\x9c\x14\xc2\xe4\xae\xb0\xbb\xda" - "\x6a\xe0\x42\x3d\x96\x9f\x78\x7d" - "\x70\x86\xa5\x92\x9f\xee\xcd\x3f" - "\x6a\x55\x84\x98\x28\x03\x02\xc2" - "\xf7\xec\x7a\xfa\xb1\xd9\xa8\xd8" - "\x1c\xc3\xaa\xd5\x61\x7f\x10\x0c" - "\xc0\xa1\x36\x3d\x81\x9a\xd2\x17" - "\x2e\x23\xc9\xb7\xff\xdf\x47\x6c" - "\x96\x3b\x0e\xbd\xec\x9a\x0e\xad" - "\x8c\xaf\x36\x3d\xff\x29\x8b\x33" - "\x87\x96\x77\x1a\x10\x81\x63\x8a" - "\x63\xde\x88\xa9\x9d\xa9\x01\xf2" - "\xdf\xc9\x25\x35\x48\x3a\x15\xdf" - "\x20\x6b\x91\x7c\x56\xe5\x10\x7a", - .ctext = "\xbc\x57\x2a\x88\x0a\xd0\x06\x4f" - "\xdb\x7b\x03\x9f\x97\x1a\x20\xfe" - "\x15\x91\xb4\xed\x5d\x78\x89\x2a" - "\x67\x6b\x9c\x47\x36\xc2\x80\x0e" - "\x03\x8d\x6f\xfc\x94\xc7\xc5\xc2" - "\xeb\x43\x74\x5d\xfe\xc4\x5a\xa1" - "\x80\x51\x8a\x63\xd1\x27\x1b\x0a" - "\x88\x2c\xc4\x7f\x1a\xa3\x28\xe5" - "\xfd\xd0\x8a\xd4\x36\xa6\x19\xd5" - "\xff\x41\x7a\x8b\x6e\x9a\x97\x14" - "\x2a\xc8\xd0\xb8\xa3\x8e\x64\x32" - "\xb7\x2d\x76\x9b\x3b\xe2\x3f\x91" - "\xb4\x64\xbf\x59\x67\x14\xc3\xf5" - "\xa8\x92\x4b\x85\xdf\x80\xcb\xb5" - "\xc7\x80\xf9\x4a\xbc\xed\x67\x5a" - "\x0b\x58\x65\x1f\xc9\x6e\x9b\x0a", - .len = 128, - }, { - .key = "\x2d\x2e\x0f\x30\x32\xed\xa9\x1f" - "\x71\x4e\x68\x77\xe8\xa8\x5b\xdd" - "\x3c\x5e\x68\x6b\xab\x03\xe4\xf8", - .klen = 24, - .iv = "\x42\xc1\x61\x9a\x50\xfb\xc7\x6a" - "\x1a\x31\xa7\x87\xd0\x24\xcb\x5e", - .ptext = "\xc0\x3b\x12\x28\xca\x26\x7b\xb3" - "\x14\xc1\x7f\x66\xff\x3b\xa4\x80" - "\x59\x77\x4f\xa0\xd4\xb2\xd9\x8a" - "\xb6\x67\xe6\x28\xd3\x6f\xf2\xcf" - "\xb8\x6d\x2d\xc4\x2a\x69\x89\xff" - "\xcf\xbb\x11\x2e\x2a\x2b\x7c\xfd" - "\xcd\x56\x02\x95\xc9\x54\x6e\x62" - "\x6a\x97\x75\x1a\x21\x16\x46\xfb" - "\xc2\xab\x62\x54\xef\xba\xae\x46" - "\xd4\x14\xc6\xcc\x16\x1b\x95\xf9" - "\x05\x26\x23\x81\x19\x27\xad\x7b" - "\x9c\x8b\xfb\x65\xa4\x61\xee\x69" - "\x44\xbf\x59\xde\x03\x61\x11\x12" - "\x8d\x94\x48\x47\xa9\x52\x16\xfb" - "\x6b\xaf\x59\x6d\xab\x74\xbf\x5c" - "\xb6\x09\x21\x12\x42\x98\x13\xa1" - "\xa8\x6f\xb9\x6d\x4d\xa6\xdc\xea" - "\x61\x02\x3c\xa7\xcd\x1a\x28\x8c", - .ctext = "\xd7\xb4\xfc\xcc\x1f\xf7\xfc\x7d" - "\x69\xfa\xcb\x01\x60\xf3\x5a\x14" - "\xfe\x8c\x4e\xfa\x09\xb5\x0d\xda" - "\xff\xdd\xba\xdf\xa3\x6b\x3a\x87" - "\x21\xbb\xf8\x62\x14\x22\xdd\x9b" - "\x92\x23\xaa\xd7\xcc\xb2\x15\xd0" - "\xbd\x81\x95\x24\xc2\xc6\x53\x5b" - "\xf7\x3c\xa0\xf7\x36\xbc\xbf\xf3" - "\xfc\x1c\x6e\xe0\x71\x8d\xa1\x3d" - "\x8e\x1a\xc5\xba\xd5\x68\xd4\x7a" - "\xe0\x4f\x0a\x14\x89\x0b\xa6\x2f" - "\x18\xc5\x38\x76\xf1\xe7\x5c\xae" - "\x7a\xbb\x27\x1c\xf0\x7c\x6c\x14" - "\x07\xb7\x49\x6e\x29\x04\x38\x31" - "\x91\xe8\x1d\x0f\xfc\x3b\xb8\x20" - "\x58\x64\x11\xa1\xf5\xba\xa3\x62" - "\x92\xcf\x44\x63\x2c\xe8\x10\xb5" - "\xf0\x97\x86\xcb\x5f\xc1\x80\x7a", - .len = 144, - }, { - .key = "\x66\xb8\x4d\x60\x67\x82\xcc\x8d" - "\x1e\xda\x8f\x28\xe5\x02\xdc\x2c" - "\x54\x84\x2a\x06\xb5\xd1\x34\x57", - .klen = 24, - .iv = "\xb8\x28\x4d\xf5\x69\xb9\xf3\x33" - "\x5e\x0b\xa6\x62\x35\x9b\xfb\x97", - .ptext = "\x3e\xc6\xec\xaf\x74\xe8\x72\x91" - "\xb2\xc6\x56\xb3\x23\x29\x43\xe0" - "\xfb\xcc\x21\x38\x64\x78\x9e\x78" - "\xbb\x6e\x0d\x7b\xfd\x05\x74\x01" - "\x7c\x94\xe0\xb0\xd7\x92\xfc\x58" - "\x28\xfc\xe2\x7b\x7f\xf7\x31\x0d" - "\x90\xb7\x60\x78\xa8\x9f\x52\xe3" - "\xe6\xaa\x2a\xb4\xa7\x09\x60\x53" - "\x42\x0e\x15\x31\xf6\x48\xa3\x0a" - "\x20\xf0\x79\x67\xb1\x83\x26\x66" - "\xe0\xb1\xb3\xbd\x1c\x76\x36\xfd" - "\x45\x87\xa4\x14\x1b\xef\xe7\x16" - "\xf7\xfa\x30\x3d\xb9\x52\x8f\x2e" - "\x01\x68\xc1\x7d\xa2\x15\x49\x74" - "\x53\x82\xc2\x10\xa8\x45\x73\x4d" - "\x41\xcc\x24\xa3\x42\xff\x30\xd1" - "\x02\x21\xdc\xd9\x08\xf7\xe7\x4c" - "\x33\x2d\x62\xc7\x38\xf5\xc2\xbe" - "\x52\xf1\x34\x78\x34\x53\x30\x5b" - "\x43\x43\x51\x6a\x02\x81\x64\x0c", - .ctext = "\x71\xf6\x96\x02\x07\x71\x1a\x08" - "\x7c\xfe\x33\xc4\xc9\xbe\xe2\xed" - "\xd0\xcc\x5d\x27\x75\xb4\x5d\x8d" - "\x24\x03\xe4\x96\x31\x94\x0e\x38" - "\x14\x4f\xad\x16\x58\x0d\x73\xdc" - "\xbe\x5b\xcb\x38\xeb\x4d\xbc\x9a" - "\x44\x69\x7a\x12\x91\x14\x52\xfa" - "\xd2\xa2\xc5\x66\xd7\xaf\x4d\xb9" - "\xb1\x58\x24\x10\xde\x6a\xee\x7e" - "\x45\xf3\x76\xea\x47\x8a\xe6\x96" - "\x41\xf2\x96\x2d\x3c\xec\xcf\xc6" - "\x1d\xf4\x26\xc0\xea\x90\x27\x6e" - "\x87\xef\xb5\x39\x38\xdb\xad\xbf" - "\x57\x9a\x1d\xbc\x1d\xe5\x16\x91" - "\x41\x45\xbe\x67\x6c\x42\x0f\xad" - "\xcf\xfb\xcd\xf1\x4c\xd8\x73\xe7" - "\x24\x3b\xd7\x03\xeb\xd1\xb1\x1b" - "\x7d\xc9\x3d\x34\xd7\xb8\x69\x03" - "\x76\x95\x32\x26\xed\x88\x76\x89" - "\x13\xc6\xc8\xa6\x60\xf9\x73\x4d", - .len = 160, - }, { - .key = "\x82\x8e\x9e\x06\x7b\xc2\xe9\xb3" - "\x06\xa3\xfa\x99\x42\x67\x87\xac" - "\x21\xc7\xb0\x98\x6c\xf8\x26\x57" - "\x08\xdd\x92\x02\x77\x7b\x35\xe7", - .klen = 32, - .iv = "\xa1\xad\xcb\xdd\xd5\x19\xb6\xd4" - "\x0b\x62\x58\xb0\x6c\xa0\xc1\x58", - .ptext = "\x14\x0d\x8a\x09\x16\x00\x00\xf1" - "\xc0\x20\x86\xf9\x21\xd1\x34\xe2", - .ctext = "\x05\xe3\x34\xaf\x6c\x83\x14\x8b" - "\x9d\x1c\xd6\x87\x74\x91\xdf\x17", - .len = 16, - }, { - .key = "\xc9\xf3\xc4\x93\xd0\xcc\xaf\xb1" - "\x1a\x42\x93\x71\xd8\x4e\xd8\xaa" - "\x52\xad\x93\x2f\xe5\xd9\xaa\x5b" - "\x47\x37\x3a\xed\x13\x92\x35\x16", - .klen = 32, - .iv = "\x81\xc8\x50\xd1\x74\xc3\x1c\x73" - "\xbb\xab\x72\x83\x90\x5a\x15\xcb", - .ptext = "\x65\x11\x93\xaf\xe1\x69\x6c\xbe" - "\x25\x8c\x76\x87\x53\xa4\x80\xae" - "\x51\x94\x36\x3f\xca\xe7\x45\x41" - "\x76\x05\xbf\x8f\x9c\xad\xc0\xe3", - .ctext = "\x6B\x00\x6E\x49\x7A\x6D\xE3\x04" - "\x4E\xF7\x9F\x8A\x1F\x14\xBD\xB1" - "\xD3\x5D\xA4\x30\x26\x85\x85\xEF" - "\x12\xBC\xC7\xA1\x65\x82\xA7\x74", - .len = 32, - }, { - .key = "\xd5\x9f\x52\x34\x12\x99\x8e\x42" - "\xe0\x85\x04\x6f\xeb\xf1\x5d\xd0" - "\xc1\xbf\x3f\x84\xd9\x1e\x71\x44" - "\xd4\xb9\x40\x3c\x02\x2e\x21\x19", - .klen = 32, - .iv = "\x28\xc1\x97\x64\x81\x52\x57\x0e" - "\x02\x8c\xab\x4c\xe2\x60\x14\xa5", - .ptext = "\x5a\xb1\x33\x48\xaa\x51\xe9\xa4" - "\x5c\x2d\xbe\x33\xcc\xc4\x7f\x96" - "\xe8\xde\x2b\xe7\x35\x7a\x11\x4b" - "\x13\x08\x32\xc6\x41\xd8\xec\x54" - "\xa3\xd3\xda\x35\x43\x69\xf6\x88" - "\x97\xca\x00\x1b\x02\x59\x24\x82", - .ctext = "\x03\xaf\x76\xbd\x5e\x5b\xca\xc0" - "\xae\x44\xa2\x2f\xc2\x76\x2f\x50" - "\x6a\x73\x28\xf2\xba\xe8\xb2\xb8" - "\x43\x61\x41\x92\xff\xac\xcb\xa6" - "\x84\x31\xe3\x34\xd0\x37\x81\xab" - "\x2b\x0e\x97\x3c\x4a\x2d\xa4\x83", - .len = 48, - }, { - .key = "\x9c\x5d\xd7\x66\x36\xfa\x02\x20" - "\x99\x61\x62\x86\x0f\x43\x2e\x05" - "\x25\x8b\xfb\xf1\xae\x4c\xde\x18" - "\x0b\xf8\xd0\x9d\xaa\xd4\x56\x04", - .klen = 32, - .iv = "\xcd\xa8\x61\x89\x8d\xbb\x72\xb6" - "\x1e\xfe\x03\x34\x54\x88\x23\xe2", - .ptext = "\x66\x42\x60\x24\xf3\xe4\xe9\x7e" - "\x42\x20\xf4\x61\xce\x1c\x5e\x44" - "\x02\x26\x91\xf7\x41\xa4\xab\x34" - "\x29\x49\xdd\x78\x19\x8f\x10\x10" - "\xf0\x61\xcf\x77\x18\x17\x61\xdf" - "\xc4\xa8\x35\x0e\x75\x1b\x84\x6b" - "\xc3\x3f\x31\x59\x5a\x9c\xf4\xc3" - "\x43\xa9\xb7\xf8\x65\x40\x40\xba", - .ctext = "\xb6\x41\x55\x8f\xeb\x16\x1e\x4c" - "\x81\xa0\x85\x6c\xf0\x07\xa5\x2a" - "\x12\x0f\x1d\xb2\xaa\xba\x85\x0f" - "\xa6\x27\x1a\x91\xa6\xc5\x8c\x2a" - "\xde\x8d\x3a\xa9\x8b\xcf\x24\xf1" - "\x82\x51\x6b\xc8\x01\xd7\x7b\x89" - "\x6c\xfc\xb1\x96\x6c\xa2\xd7\x1f" - "\x4b\x7a\xd9\x8d\x34\xaa\xa0\x8a", - .len = 64, - }, { - .key = "\x4b\x4e\x11\x91\x27\xcf\x8c\x66" - "\x17\xfa\x5b\x4c\xa8\xb8\x0f\xa1" - "\x99\x5b\x07\x56\xe1\x8d\x94\x8b" - "\xf2\x86\x5a\x5f\x40\x83\xfa\x06", - .klen = 32, - .iv = "\xfd\x73\xee\x1c\x27\xf3\xb4\x38" - "\xc5\x7c\x2e\xc5\x6e\xdb\x49\x0d", - .ptext = "\x0a\xe2\xdd\x97\xdd\x5e\xd4\xb3" - "\xc1\x49\x8f\x53\xb2\x40\x85\x1c" - "\x90\x37\x2d\xbd\x21\x6b\x1f\x80" - "\x56\x98\x76\x1e\xcf\x6c\x78\xd8" - "\xa0\x3c\x79\xc3\x56\xf7\xfc\x64" - "\x35\x58\x1c\x7c\xc4\x5f\x2a\x25" - "\x8c\x01\x98\x1e\x1c\x1f\x15\x64" - "\x50\xb5\xfa\x02\xd3\x54\xe5\x29" - "\xe3\xd2\xa3\x83\x54\x40\x54\xc5" - "\xd8\x1c\xc9\x84\x7d\xc8\x31\x49", - .ctext = "\x53\x2a\xa8\xa0\x15\xaf\x2f\xc4" - "\x7d\x31\xb4\x61\x80\x5f\xd1\xb6" - "\xa4\x29\x40\x72\x1b\xb2\x96\xb7" - "\x4d\x5e\x5b\x53\x44\xa4\xf1\xe9" - "\xf0\x27\x2f\x26\x84\x66\x13\xa4" - "\xb2\x19\x55\xb1\x18\xf3\x69\xfd" - "\xb0\x2f\x08\x3f\xa5\x41\xe2\x34" - "\x5e\x63\x57\x0e\xef\x17\x78\xbc" - "\xc3\x65\x7c\xbe\x6b\xa3\xa3\xef" - "\x58\x05\x30\x5a\x08\xbd\xf7\x0e", - .len = 80, - }, { - .key = "\x77\x3b\xf5\xe7\x20\xf7\xe0\x0c" - "\x3d\x3a\x83\x17\x83\x79\xd8\x29" - "\x5a\x0a\x25\x7f\xe0\x21\x23\xff" - "\x31\xfd\x60\x10\xe6\x63\xe2\xaf", - .klen = 32, - .iv = "\xdb\x4c\x0d\xc0\x36\xdb\xc7\xa1" - "\xa4\x91\xd9\x05\xe6\xc4\x98\x00", - .ptext = "\x8d\x4d\xc6\x5e\x01\x82\xb3\x39" - "\xc8\x64\xa7\xcb\x05\x19\x84\x80" - "\x3f\x9c\xa8\x4f\x64\xb3\x11\x4b" - "\x0e\x21\xc4\x75\x04\x1d\x6f\xd5" - "\x04\x04\x4d\xc9\xc0\x4b\x4a\x9c" - "\x26\xb7\x68\x5a\xe4\xd0\x61\xe3" - "\x2c\x93\x8e\x3f\xb4\x67\x07\x31" - "\x02\x52\x0c\x0f\xe6\x6d\xa3\xd0" - "\x48\x95\x83\x67\x23\x64\x31\x50" - "\xd2\x5f\x69\x68\x8b\x71\xbf\x01" - "\x29\x99\x86\x36\x2e\xdf\xf1\x7c" - "\x08\x8c\x78\x7a\x93\x9a\x7d\x1b", - .ctext = "\x92\x90\x48\x2f\x3a\x6b\x68\x43" - "\x28\x9b\x7d\x1e\x46\x28\xd8\x58" - "\x0f\x47\x8b\xb5\x83\x35\x35\x3e" - "\xdf\x59\x3d\xb3\x47\xfc\xfc\x52" - "\x86\xeb\xb3\x58\x54\xd5\x0a\xb4" - "\xad\xbd\x5c\x09\xfc\x08\xc2\x01" - "\x5e\x9b\x30\x11\xc4\x40\x2e\x32" - "\x9c\xa0\xf1\xfd\xae\xd4\x75\x5e" - "\x52\xd9\x19\x4d\xc1\xd4\xb6\x19" - "\x88\xfb\x29\x17\x15\xbb\x60\xd6" - "\x5a\xe9\x82\x89\xaf\x30\x4e\xd4" - "\x47\xde\x86\x88\x95\x4c\x13\x59", - .len = 96, - }, { - .key = "\xe0\x6a\x30\xe1\x35\xb5\xb0\x7c" - "\x54\xc5\x73\x9b\x00\xe5\xe7\x02" - "\xbe\x16\x59\xdc\xd9\x03\x17\x53" - "\xa8\x37\xd1\x5f\x13\x8e\x45\xdb", - .klen = 32, - .iv = "\x54\xe9\x1c\xde\xfb\x26\x0e\x48" - "\x35\x50\x4d\x9b\x4d\x12\x21\x0d", - .ptext = "\x73\x72\xcf\xdb\xbd\xbc\xc0\xdf" - "\x6b\xbb\xdf\x65\x6f\x2f\x43\x3b" - "\x2d\x7c\x0e\x07\x7f\xa0\x95\xdd" - "\xfc\x67\xc1\x11\x7a\xe2\xb5\x4a" - "\xd1\x15\xb0\xd8\xe2\xf0\x35\x48" - "\xd8\x81\x6a\x35\xae\x67\xbf\x61" - "\xf2\x8a\xcf\x04\xc8\x09\x8b\x63" - "\x31\x74\x95\xa5\x8d\x3c\xea\xe2" - "\x5f\x67\xc4\x7e\x51\x88\xbf\xb5" - "\x78\xef\x3a\x76\xd8\x1d\x00\x75" - "\x2b\x7b\x28\x7c\xde\x4b\x39\x01" - "\x5d\xde\x92\xfe\x90\x07\x09\xfd" - "\xa5\xd1\xd3\x72\x11\x6d\xa4\x4e" - "\xd1\x6e\x16\xd1\xf6\x39\x4f\xa0", - .ctext = "\x3b\xc5\xee\xfc\x05\xaf\xa6\xb7" - "\xfe\x12\x24\x79\x31\xad\x32\xb5" - "\x64\x5a\x17\xc9\xbf\x1f\xdc\xce" - "\x8d\x73\x00\x71\xd9\xfb\xd2\xe6" - "\xc3\x54\xb4\xf3\x36\xe8\x89\x12" - "\x5a\x32\x0b\xa6\xec\x5f\x89\xe7" - "\xe8\x34\x92\xa6\xce\xde\x8f\xf9" - "\x4f\xda\xed\x61\x8e\xb2\x81\xbe" - "\xf2\x15\x85\xbe\xa1\x5f\x19\x85" - "\x71\x7e\xda\x46\x59\xed\x5d\xb0" - "\xd9\x68\x97\xe0\xcd\x1d\x1b\x65" - "\xf5\xc9\x44\xe2\xb4\x42\x17\x7c" - "\xe7\x58\xf3\x2f\xcf\xbe\x5c\x66" - "\xaa\xd3\x61\xa5\x9a\x79\xbb\xa0", - .len = 112, - }, { - .key = "\x60\xb6\xde\x17\xca\x4c\xe7\xe0" - "\x07\x0d\x80\xc5\x8a\x2d\x5a\xc2" - "\x2c\xb9\xa4\x5f\x2a\x85\x2c\x3d" - "\x6d\x67\xc8\xee\x0f\xa2\xf4\x09", - .klen = 32, - .iv = "\x1a\xa5\xbc\x7e\x93\xf6\xdd\x28" - "\xb7\x69\x27\xa1\x84\x95\x25\x5a", - .ptext = "\x7b\x88\x00\xeb\xa5\xba\xa1\xa7" - "\xd4\x40\x16\x74\x2b\x42\x37\xda" - "\xe0\xaf\x89\x59\x41\x2f\x62\x00" - "\xf5\x5a\x4e\x3b\x85\x27\xb2\xed" - "\x1b\xa7\xaf\xbe\x89\xf3\x49\xb7" - "\x8c\x63\xc9\x0c\x52\x00\x5f\x38" - "\x3b\x3c\x0c\x4f\xdd\xe1\xbf\x90" - "\x4a\x48\xbf\x3a\x95\xcb\x48\xa2" - "\x92\x7c\x79\x81\xde\x18\x6e\x92" - "\x1f\x36\xa9\x5d\x8d\xc4\xb6\x4d" - "\xb2\xb4\x0e\x09\x6d\xf3\x3d\x01" - "\x3d\x9b\x40\x47\xbc\x69\x31\xa1" - "\x6a\x71\x26\xdc\xac\x10\x56\x63" - "\x15\x23\x7d\x10\xe3\x76\x82\x41" - "\xcd\x80\x57\x2f\xfc\x4d\x22\x7b" - "\x57\xbb\x9a\x0a\x03\xe9\xb3\x13", - .ctext = "\x37\x0d\x47\x21\xbc\x28\x0b\xf7" - "\x85\x5f\x60\x57\xf2\x7f\x92\x20" - "\x53\x1a\xbf\xd1\x7f\x8c\x39\x29" - "\x0e\x18\xab\x0c\x00\x92\xd3\x68" - "\x60\x56\x3b\x00\xef\xf8\x02\xfa" - "\xcb\x92\x1a\x91\xe1\xf0\x4f\x8a" - "\xc6\x4f\x65\x16\x71\x8b\x5d\xd5" - "\x79\xa9\x6d\x68\x1b\x59\xe7\x2a" - "\x1c\xd0\x5d\xfb\x06\x3b\x15\x72" - "\xa8\xd1\x59\x9a\xb2\x6c\xf2\xd5" - "\x19\xef\xde\x03\x4c\x75\x65\x38" - "\x5b\xda\xc9\xf0\x44\x99\xb2\x6e" - "\x78\xfb\x85\x5a\x92\x91\x1a\x0a" - "\x13\x0c\x1b\x1c\xbe\xbe\x46\x6e" - "\x73\xff\xc2\x6e\xb9\x06\x16\x7e" - "\xf6\xc0\x01\x30\x34\x56\x46\x55", - .len = 128, - }, { - .key = "\x2a\xed\x7d\x76\xfc\xc5\x49\x50" - "\xf4\x90\x0f\xcc\x5d\xff\x0c\x3c" - "\x14\x06\xaf\x68\x8f\xd7\xb6\x25" - "\x1e\x10\x95\x2a\x71\x33\x17\x20", - .klen = 32, - .iv = "\x5b\x58\x47\xf8\xd5\x1e\x91\x81" - "\x46\xe7\x25\x3a\x02\x45\x9c\x65", - .ptext = "\x10\xaf\xde\x5c\x30\x79\x43\x28" - "\x1c\x03\xf8\x50\x0f\x30\xa5\xef" - "\x84\x19\x4c\x09\x40\x03\x75\x1f" - "\x92\x8f\x88\x01\xda\x31\x7a\xe4" - "\x48\xe3\xab\xb4\xe6\x1b\x0f\xac" - "\xd9\xfa\x8d\x23\xe4\xc6\xa4\xa9" - "\x2d\x9a\x54\x52\x44\x5c\x3c\x52" - "\x61\xf0\x00\xca\xed\xab\xed\xe2" - "\x44\x0b\xe0\x18\xba\xa5\x63\xd8" - "\xdc\x5e\x1a\x4c\xf8\xde\x5e\x75" - "\xdf\x42\x27\x7b\xe9\x11\x2f\x41" - "\x3a\x72\x54\x3d\x44\x9c\x3e\x87" - "\x8d\x8d\x43\x2f\xb2\xff\x87\xd4" - "\xad\x98\x68\x72\x53\x61\x19\x7c" - "\x20\x79\x8c\x2b\x37\x0b\x96\x15" - "\xa5\x7d\x4e\x01\xe6\xea\xb6\xfa" - "\xaa\xd3\x9d\xa2\xd9\x11\xc3\xc9" - "\xd4\x0e\x3f\x3e\xfe\x35\x1e\xe5", - .ctext = "\xb0\x2b\x75\x5f\x33\x1b\x05\x49" - "\x06\xf1\x43\x91\xc2\x85\xfa\xac" - "\x74\xd5\x8c\xc9\x47\x6e\x5a\xf6" - "\x69\x33\x4c\xcb\x2f\x36\x4b\x41" - "\xec\x05\x69\xab\x7f\x42\xc9\xd2" - "\x26\x64\x51\x9e\x3d\x65\x35\xf0" - "\x8d\x5e\x8a\xb1\xee\xdf\x1a\x98" - "\x36\xd2\x37\x49\x5b\xe2\x57\x00" - "\x1d\x72\x7e\xe8\x38\x11\x83\x15" - "\xc7\x4e\x65\xa4\x2c\x9e\x6a\x3e" - "\xb4\x78\x3f\xe9\x91\x5d\x06\xa9" - "\xf1\xfc\x6b\x08\xe5\x2b\x2a\x99" - "\x65\xa7\x2e\x47\xf9\xc2\xb1\x8b" - "\x88\x2f\xb7\x62\x84\x63\x94\x00" - "\x49\xa7\xd0\x2b\x54\x7a\x69\xb3" - "\x04\x66\xfc\x97\x40\x92\xd1\xb8" - "\xb4\x2a\x9e\xdb\x31\xcd\x48\x84" - "\x29\x3b\x02\xac\xb8\x54\x95\xb4", - .len = 144, - }, { - .key = "\x7b\xa7\x4d\x0a\x37\x30\xb9\xf5" - "\x2a\x79\xb4\xbf\xdb\x7f\x9b\x64" - "\x23\x43\xb5\x18\x34\xc4\x5f\xdf" - "\xd9\x2a\x66\x58\x00\x44\xb5\xd9", - .klen = 32, - .iv = "\x75\x34\x30\xc1\xf0\x69\xdf\x0a" - "\x52\xce\x4f\x1e\x2c\x41\x35\xec", - .ptext = "\x81\x47\x55\x3a\xcd\xfe\xa2\x3d" - "\x45\x53\xa7\x67\x61\x74\x25\x80" - "\x98\x89\xfe\xf8\x6a\x9f\x51\x7c" - "\xa4\xe4\xe7\xc7\xe0\x1a\xce\xbb" - "\x4b\x46\x43\xb0\xab\xa8\xd6\x0c" - "\xa0\xf0\xc8\x13\x29\xaf\xb8\x01" - "\x6b\x0c\x7e\x56\xae\xb8\x58\x72" - "\xa9\x24\x44\x61\xff\xf1\xac\xf8" - "\x09\xa8\x48\x21\xd6\xab\x41\x73" - "\x70\x6b\x92\x06\x61\xdc\xb4\x85" - "\x76\x26\x7a\x84\xc3\x9e\x3a\x14" - "\xe7\xf4\x2d\x95\x92\xad\x18\xcc" - "\x44\xd4\x2c\x36\x57\xed\x2b\x9b" - "\x3f\x2b\xcd\xe5\x11\xe3\x62\x33" - "\x42\x3f\xb8\x2a\xb1\x37\x3f\x8b" - "\xe8\xbd\x6b\x0b\x9f\x38\x5a\x5f" - "\x82\x34\xb7\x96\x35\x58\xde\xab" - "\x94\x98\x41\x5b\x3f\xac\x0a\x34" - "\x56\xc0\x02\xef\x81\x6d\xb1\xff" - "\x34\xe8\xc7\x6a\x31\x79\xba\xd8", - .ctext = "\x4e\x00\x7c\x52\x45\x76\xf9\x3d" - "\x1a\xd1\x72\xbc\xb9\x0f\xa9\xfb" - "\x0a\xf5\xe8\x11\x66\x8b\xad\x68" - "\x5a\x2e\xbf\x09\x33\x9d\xb6\x67" - "\xe5\xcb\x0a\xe0\xac\xed\x73\x4b" - "\xbb\x15\xde\xd8\xab\x33\x28\x5f" - "\x96\x07\x3c\x28\x79\x88\x84\xc7" - "\x13\xf7\x0d\xa5\x97\x3b\xd9\xb1" - "\xf2\x65\xb0\xac\xbb\x8a\x97\xd1" - "\x70\x3a\x91\x65\xc8\x39\x04\xe7" - "\x1a\x9c\x80\x65\x2b\x69\x4b\xdc" - "\xdc\xc7\xf1\x31\xda\xab\xb4\xd7" - "\x46\x2e\x1d\xc9\x2e\xe9\x46\xec" - "\xa4\xa1\x91\x6b\x4a\x09\xf9\x39" - "\x7b\x7d\x6d\xf5\x43\x7f\xcc\x74" - "\x96\xfa\x48\xd0\xe1\x74\x24\xd0" - "\x19\x22\x24\x84\x2b\x12\x10\x46" - "\x90\xbd\xa9\x93\xb7\xf7\x36\xd4" - "\x48\xc7\x32\x83\x8c\xa9\xcd\x5a" - "\x2f\x05\x33\xc1\x5b\x50\x70\xc4", - .len = 160, - } -}; - static const struct aead_testvec aria_gcm_tv_template[] = { { .key = "\xe9\x1e\x5e\x75\xda\x65\x55\x4a" diff --git a/drivers/Makefile b/drivers/Makefile index d828329c268da3..37fd6ce3bd7f59 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -71,9 +71,8 @@ obj-y += gpu/ obj-$(CONFIG_CONNECTOR) += connector/ -# i810fb and intelfb depend on char/agp/ +# i810fb depends on char/agp/ obj-$(CONFIG_FB_I810) += video/fbdev/i810/ -obj-$(CONFIG_FB_INTEL) += video/fbdev/intelfb/ obj-$(CONFIG_PARPORT) += parport/ obj-y += base/ block/ misc/ mfd/ nfc/ diff --git a/drivers/accel/drm_accel.c b/drivers/accel/drm_accel.c index 294b572a9c331f..24cac4c0274bb6 100644 --- a/drivers/accel/drm_accel.c +++ b/drivers/accel/drm_accel.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include diff --git a/drivers/accel/habanalabs/common/device.c b/drivers/accel/habanalabs/common/device.c index 9711e8fc979d9a..a73bd4be94b156 100644 --- a/drivers/accel/habanalabs/common/device.c +++ b/drivers/accel/habanalabs/common/device.c @@ -853,6 +853,9 @@ static int device_early_init(struct hl_device *hdev) gaudi2_set_asic_funcs(hdev); strscpy(hdev->asic_name, "GAUDI2B", sizeof(hdev->asic_name)); break; + case ASIC_GAUDI2C: + gaudi2_set_asic_funcs(hdev); + strscpy(hdev->asic_name, "GAUDI2C", sizeof(hdev->asic_name)); break; default: dev_err(hdev->dev, "Unrecognized ASIC type %d\n", @@ -1041,18 +1044,21 @@ static bool is_pci_link_healthy(struct hl_device *hdev) return (vendor_id == PCI_VENDOR_ID_HABANALABS); } -static void hl_device_eq_heartbeat(struct hl_device *hdev) +static int hl_device_eq_heartbeat_check(struct hl_device *hdev) { - u64 event_mask = HL_NOTIFIER_EVENT_DEVICE_RESET | HL_NOTIFIER_EVENT_DEVICE_UNAVAILABLE; struct asic_fixed_properties *prop = &hdev->asic_prop; if (!prop->cpucp_info.eq_health_check_supported) - return; + return 0; - if (hdev->eq_heartbeat_received) + if (hdev->eq_heartbeat_received) { hdev->eq_heartbeat_received = false; - else - hl_device_cond_reset(hdev, HL_DRV_RESET_HARD, event_mask); + } else { + dev_err(hdev->dev, "EQ heartbeat event was not received!\n"); + return -EIO; + } + + return 0; } static void hl_device_heartbeat(struct work_struct *work) @@ -1069,10 +1075,9 @@ static void hl_device_heartbeat(struct work_struct *work) /* * For EQ health check need to check if driver received the heartbeat eq event * in order to validate the eq is working. + * Only if both the EQ is healthy and we managed to send the next heartbeat reschedule. */ - hl_device_eq_heartbeat(hdev); - - if (!hdev->asic_funcs->send_heartbeat(hdev)) + if ((!hl_device_eq_heartbeat_check(hdev)) && (!hdev->asic_funcs->send_heartbeat(hdev))) goto reschedule; if (hl_device_operational(hdev, NULL)) @@ -2035,7 +2040,7 @@ device_reset: if (ctx) hl_ctx_put(ctx); - return hl_device_reset(hdev, flags); + return hl_device_reset(hdev, flags | HL_DRV_RESET_HARD); } static void hl_notifier_event_send(struct hl_notifier_event *notifier_event, u64 event_mask) @@ -2044,7 +2049,7 @@ static void hl_notifier_event_send(struct hl_notifier_event *notifier_event, u64 notifier_event->events_mask |= event_mask; if (notifier_event->eventfd) - eventfd_signal(notifier_event->eventfd, 1); + eventfd_signal(notifier_event->eventfd); mutex_unlock(¬ifier_event->lock); } diff --git a/drivers/accel/habanalabs/common/firmware_if.c b/drivers/accel/habanalabs/common/firmware_if.c index 47e8384134aa91..3558a6a8e1925a 100644 --- a/drivers/accel/habanalabs/common/firmware_if.c +++ b/drivers/accel/habanalabs/common/firmware_if.c @@ -646,39 +646,27 @@ int hl_fw_send_heartbeat(struct hl_device *hdev) return rc; } -static bool fw_report_boot_dev0(struct hl_device *hdev, u32 err_val, - u32 sts_val) +static bool fw_report_boot_dev0(struct hl_device *hdev, u32 err_val, u32 sts_val) { bool err_exists = false; if (!(err_val & CPU_BOOT_ERR0_ENABLED)) return false; - if (err_val & CPU_BOOT_ERR0_DRAM_INIT_FAIL) { - dev_err(hdev->dev, - "Device boot error - DRAM initialization failed\n"); - err_exists = true; - } + if (err_val & CPU_BOOT_ERR0_DRAM_INIT_FAIL) + dev_err(hdev->dev, "Device boot error - DRAM initialization failed\n"); - if (err_val & CPU_BOOT_ERR0_FIT_CORRUPTED) { + if (err_val & CPU_BOOT_ERR0_FIT_CORRUPTED) dev_err(hdev->dev, "Device boot error - FIT image corrupted\n"); - err_exists = true; - } - if (err_val & CPU_BOOT_ERR0_TS_INIT_FAIL) { - dev_err(hdev->dev, - "Device boot error - Thermal Sensor initialization failed\n"); - err_exists = true; - } + if (err_val & CPU_BOOT_ERR0_TS_INIT_FAIL) + dev_err(hdev->dev, "Device boot error - Thermal Sensor initialization failed\n"); if (err_val & CPU_BOOT_ERR0_BMC_WAIT_SKIPPED) { if (hdev->bmc_enable) { - dev_err(hdev->dev, - "Device boot error - Skipped waiting for BMC\n"); - err_exists = true; + dev_err(hdev->dev, "Device boot error - Skipped waiting for BMC\n"); } else { - dev_info(hdev->dev, - "Device boot message - Skipped waiting for BMC\n"); + dev_info(hdev->dev, "Device boot message - Skipped waiting for BMC\n"); /* This is an info so we don't want it to disable the * device */ @@ -686,48 +674,29 @@ static bool fw_report_boot_dev0(struct hl_device *hdev, u32 err_val, } } - if (err_val & CPU_BOOT_ERR0_NIC_DATA_NOT_RDY) { - dev_err(hdev->dev, - "Device boot error - Serdes data from BMC not available\n"); - err_exists = true; - } + if (err_val & CPU_BOOT_ERR0_NIC_DATA_NOT_RDY) + dev_err(hdev->dev, "Device boot error - Serdes data from BMC not available\n"); - if (err_val & CPU_BOOT_ERR0_NIC_FW_FAIL) { - dev_err(hdev->dev, - "Device boot error - NIC F/W initialization failed\n"); - err_exists = true; - } + if (err_val & CPU_BOOT_ERR0_NIC_FW_FAIL) + dev_err(hdev->dev, "Device boot error - NIC F/W initialization failed\n"); - if (err_val & CPU_BOOT_ERR0_SECURITY_NOT_RDY) { - dev_err(hdev->dev, - "Device boot warning - security not ready\n"); - err_exists = true; - } + if (err_val & CPU_BOOT_ERR0_SECURITY_NOT_RDY) + dev_err(hdev->dev, "Device boot warning - security not ready\n"); - if (err_val & CPU_BOOT_ERR0_SECURITY_FAIL) { + if (err_val & CPU_BOOT_ERR0_SECURITY_FAIL) dev_err(hdev->dev, "Device boot error - security failure\n"); - err_exists = true; - } - if (err_val & CPU_BOOT_ERR0_EFUSE_FAIL) { + if (err_val & CPU_BOOT_ERR0_EFUSE_FAIL) dev_err(hdev->dev, "Device boot error - eFuse failure\n"); - err_exists = true; - } - if (err_val & CPU_BOOT_ERR0_SEC_IMG_VER_FAIL) { + if (err_val & CPU_BOOT_ERR0_SEC_IMG_VER_FAIL) dev_err(hdev->dev, "Device boot error - Failed to load preboot secondary image\n"); - err_exists = true; - } - if (err_val & CPU_BOOT_ERR0_PLL_FAIL) { + if (err_val & CPU_BOOT_ERR0_PLL_FAIL) dev_err(hdev->dev, "Device boot error - PLL failure\n"); - err_exists = true; - } - if (err_val & CPU_BOOT_ERR0_TMP_THRESH_INIT_FAIL) { + if (err_val & CPU_BOOT_ERR0_TMP_THRESH_INIT_FAIL) dev_err(hdev->dev, "Device boot error - Failed to set threshold for temperature sensor\n"); - err_exists = true; - } if (err_val & CPU_BOOT_ERR0_DEVICE_UNUSABLE_FAIL) { /* Ignore this bit, don't prevent driver loading */ @@ -735,52 +704,32 @@ static bool fw_report_boot_dev0(struct hl_device *hdev, u32 err_val, err_val &= ~CPU_BOOT_ERR0_DEVICE_UNUSABLE_FAIL; } - if (err_val & CPU_BOOT_ERR0_BINNING_FAIL) { + if (err_val & CPU_BOOT_ERR0_BINNING_FAIL) dev_err(hdev->dev, "Device boot error - binning failure\n"); - err_exists = true; - } if (sts_val & CPU_BOOT_DEV_STS0_ENABLED) dev_dbg(hdev->dev, "Device status0 %#x\n", sts_val); + if (err_val & CPU_BOOT_ERR0_DRAM_SKIPPED) + dev_err(hdev->dev, "Device boot warning - Skipped DRAM initialization\n"); + + if (err_val & CPU_BOOT_ERR_ENG_ARC_MEM_SCRUB_FAIL) + dev_err(hdev->dev, "Device boot error - ARC memory scrub failed\n"); + + /* All warnings should go here in order not to reach the unknown error validation */ if (err_val & CPU_BOOT_ERR0_EEPROM_FAIL) { dev_err(hdev->dev, "Device boot error - EEPROM failure detected\n"); err_exists = true; } - /* All warnings should go here in order not to reach the unknown error validation */ - if (err_val & CPU_BOOT_ERR0_DRAM_SKIPPED) { - dev_warn(hdev->dev, - "Device boot warning - Skipped DRAM initialization\n"); - /* This is a warning so we don't want it to disable the - * device - */ - err_val &= ~CPU_BOOT_ERR0_DRAM_SKIPPED; - } + if (err_val & CPU_BOOT_ERR0_PRI_IMG_VER_FAIL) + dev_warn(hdev->dev, "Device boot warning - Failed to load preboot primary image\n"); - if (err_val & CPU_BOOT_ERR0_PRI_IMG_VER_FAIL) { - dev_warn(hdev->dev, - "Device boot warning - Failed to load preboot primary image\n"); - /* This is a warning so we don't want it to disable the - * device as we have a secondary preboot image - */ - err_val &= ~CPU_BOOT_ERR0_PRI_IMG_VER_FAIL; - } - - if (err_val & CPU_BOOT_ERR0_TPM_FAIL) { - dev_warn(hdev->dev, - "Device boot warning - TPM failure\n"); - /* This is a warning so we don't want it to disable the - * device - */ - err_val &= ~CPU_BOOT_ERR0_TPM_FAIL; - } + if (err_val & CPU_BOOT_ERR0_TPM_FAIL) + dev_warn(hdev->dev, "Device boot warning - TPM failure\n"); - if (!err_exists && (err_val & ~CPU_BOOT_ERR0_ENABLED)) { - dev_err(hdev->dev, - "Device boot error - unknown ERR0 error 0x%08x\n", err_val); + if (err_val & CPU_BOOT_ERR_FATAL_MASK) err_exists = true; - } /* return error only if it's in the predefined mask */ if (err_exists && ((err_val & ~CPU_BOOT_ERR0_ENABLED) & @@ -3295,6 +3244,14 @@ int hl_fw_get_sec_attest_info(struct hl_device *hdev, struct cpucp_sec_attest_in HL_CPUCP_SEC_ATTEST_INFO_TINEOUT_USEC); } +int hl_fw_get_dev_info_signed(struct hl_device *hdev, + struct cpucp_dev_info_signed *dev_info_signed, u32 nonce) +{ + return hl_fw_get_sec_attest_data(hdev, CPUCP_PACKET_INFO_SIGNED_GET, dev_info_signed, + sizeof(struct cpucp_dev_info_signed), 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) { diff --git a/drivers/accel/habanalabs/common/habanalabs.h b/drivers/accel/habanalabs/common/habanalabs.h index 1655c101c70528..2a900c9941fee6 100644 --- a/drivers/accel/habanalabs/common/habanalabs.h +++ b/drivers/accel/habanalabs/common/habanalabs.h @@ -1262,6 +1262,7 @@ struct hl_dec { * @ASIC_GAUDI_SEC: Gaudi secured device (HL-2000). * @ASIC_GAUDI2: Gaudi2 device. * @ASIC_GAUDI2B: Gaudi2B device. + * @ASIC_GAUDI2C: Gaudi2C device. */ enum hl_asic_type { ASIC_INVALID, @@ -1270,6 +1271,7 @@ enum hl_asic_type { ASIC_GAUDI_SEC, ASIC_GAUDI2, ASIC_GAUDI2B, + ASIC_GAUDI2C, }; struct hl_cs_parser; @@ -3519,6 +3521,9 @@ struct hl_device { u8 heartbeat; }; +/* Retrieve PCI device name in case of a PCI device or dev name in simulator */ +#define HL_DEV_NAME(hdev) \ + ((hdev)->pdev ? dev_name(&(hdev)->pdev->dev) : "NA-DEVICE") /** * struct hl_cs_encaps_sig_handle - encapsulated signals handle structure @@ -3594,6 +3599,14 @@ static inline bool hl_is_fw_sw_ver_below(struct hl_device *hdev, u32 fw_sw_major return false; } +static inline bool hl_is_fw_sw_ver_equal_or_greater(struct hl_device *hdev, u32 fw_sw_major, + u32 fw_sw_minor) +{ + return (hdev->fw_sw_major_ver > fw_sw_major || + (hdev->fw_sw_major_ver == fw_sw_major && + hdev->fw_sw_minor_ver >= fw_sw_minor)); +} + /* * Kernel module functions that can be accessed by entire module */ @@ -3954,6 +3967,8 @@ long hl_fw_get_max_power(struct hl_device *hdev); void hl_fw_set_max_power(struct hl_device *hdev); int hl_fw_get_sec_attest_info(struct hl_device *hdev, struct cpucp_sec_attest_info *sec_attest_info, u32 nonce); +int hl_fw_get_dev_info_signed(struct hl_device *hdev, + struct cpucp_dev_info_signed *dev_info_signed, u32 nonce); int hl_set_voltage(struct hl_device *hdev, int sensor_index, u32 attr, long value); int hl_set_current(struct hl_device *hdev, int sensor_index, u32 attr, long value); int hl_set_power(struct hl_device *hdev, int sensor_index, u32 attr, long value); diff --git a/drivers/accel/habanalabs/common/habanalabs_drv.c b/drivers/accel/habanalabs/common/habanalabs_drv.c index 306a5bc9bf8949..e542fd40e16c6d 100644 --- a/drivers/accel/habanalabs/common/habanalabs_drv.c +++ b/drivers/accel/habanalabs/common/habanalabs_drv.c @@ -141,6 +141,9 @@ static enum hl_asic_type get_asic_type(struct hl_device *hdev) case REV_ID_B: asic_type = ASIC_GAUDI2B; break; + case REV_ID_C: + asic_type = ASIC_GAUDI2C; + break; default: break; } @@ -670,6 +673,38 @@ static pci_ers_result_t hl_pci_err_slot_reset(struct pci_dev *pdev) return PCI_ERS_RESULT_RECOVERED; } +static void hl_pci_reset_prepare(struct pci_dev *pdev) +{ + struct hl_device *hdev; + + hdev = pci_get_drvdata(pdev); + if (!hdev) + return; + + hdev->disabled = true; +} + +static void hl_pci_reset_done(struct pci_dev *pdev) +{ + struct hl_device *hdev; + u32 flags; + + hdev = pci_get_drvdata(pdev); + if (!hdev) + return; + + /* + * Schedule a thread to trigger hard reset. + * The reason for this handler, is for rare cases where the driver is up + * and FLR occurs. This is valid only when working with no VM, so FW handles FLR + * and resets the device. FW will go back preboot stage, so driver needs to perform + * hard reset in order to load FW fit again. + */ + flags = HL_DRV_RESET_HARD | HL_DRV_RESET_BYPASS_REQ_TO_FW; + + hl_device_reset(hdev, flags); +} + static const struct dev_pm_ops hl_pm_ops = { .suspend = hl_pmops_suspend, .resume = hl_pmops_resume, @@ -679,6 +714,8 @@ static const struct pci_error_handlers hl_pci_err_handler = { .error_detected = hl_pci_err_detected, .slot_reset = hl_pci_err_slot_reset, .resume = hl_pci_err_resume, + .reset_prepare = hl_pci_reset_prepare, + .reset_done = hl_pci_reset_done, }; static struct pci_driver hl_pci_driver = { diff --git a/drivers/accel/habanalabs/common/habanalabs_ioctl.c b/drivers/accel/habanalabs/common/habanalabs_ioctl.c index 8ef36effb95bc4..1dd6e23172caa3 100644 --- a/drivers/accel/habanalabs/common/habanalabs_ioctl.c +++ b/drivers/accel/habanalabs/common/habanalabs_ioctl.c @@ -19,6 +19,9 @@ #include +/* make sure there is space for all the signed info */ +static_assert(sizeof(struct cpucp_info) <= SEC_DEV_INFO_BUF_SZ); + static u32 hl_debug_struct_size[HL_DEBUG_OP_TIMESTAMP + 1] = { [HL_DEBUG_OP_ETR] = sizeof(struct hl_debug_params_etr), [HL_DEBUG_OP_ETF] = sizeof(struct hl_debug_params_etf), @@ -685,7 +688,7 @@ static int sec_attest_info(struct hl_fpriv *hpriv, struct hl_info_args *args) if (!sec_attest_info) return -ENOMEM; - info = kmalloc(sizeof(*info), GFP_KERNEL); + info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) { rc = -ENOMEM; goto free_sec_attest_info; @@ -719,6 +722,53 @@ free_sec_attest_info: return rc; } +static int dev_info_signed(struct hl_fpriv *hpriv, struct hl_info_args *args) +{ + void __user *out = (void __user *) (uintptr_t) args->return_pointer; + struct cpucp_dev_info_signed *dev_info_signed; + struct hl_info_signed *info; + u32 max_size = args->return_size; + int rc; + + if ((!max_size) || (!out)) + return -EINVAL; + + dev_info_signed = kzalloc(sizeof(*dev_info_signed), GFP_KERNEL); + if (!dev_info_signed) + return -ENOMEM; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + rc = -ENOMEM; + goto free_dev_info_signed; + } + + rc = hl_fw_get_dev_info_signed(hpriv->hdev, + dev_info_signed, args->sec_attest_nonce); + if (rc) + goto free_info; + + info->nonce = le32_to_cpu(dev_info_signed->nonce); + info->info_sig_len = dev_info_signed->info_sig_len; + info->pub_data_len = le16_to_cpu(dev_info_signed->pub_data_len); + info->certificate_len = le16_to_cpu(dev_info_signed->certificate_len); + info->dev_info_len = sizeof(struct cpucp_info); + memcpy(&info->info_sig, &dev_info_signed->info_sig, sizeof(info->info_sig)); + memcpy(&info->public_data, &dev_info_signed->public_data, sizeof(info->public_data)); + memcpy(&info->certificate, &dev_info_signed->certificate, sizeof(info->certificate)); + memcpy(&info->dev_info, &dev_info_signed->info, info->dev_info_len); + + rc = copy_to_user(out, info, min_t(size_t, max_size, sizeof(*info))) ? -EFAULT : 0; + +free_info: + kfree(info); +free_dev_info_signed: + kfree(dev_info_signed); + + return rc; +} + + static int eventfd_register(struct hl_fpriv *hpriv, struct hl_info_args *args) { int rc; @@ -1089,6 +1139,9 @@ static int _hl_info_ioctl(struct hl_fpriv *hpriv, void *data, case HL_INFO_FW_GENERIC_REQ: return send_fw_generic_request(hdev, args); + case HL_INFO_DEV_SIGNED: + return dev_info_signed(hpriv, args); + default: dev_err(dev, "Invalid request %d\n", args->op); rc = -EINVAL; diff --git a/drivers/accel/habanalabs/common/hwmon.c b/drivers/accel/habanalabs/common/hwmon.c index 8598056216e751..1ee2ee07e9ed51 100644 --- a/drivers/accel/habanalabs/common/hwmon.c +++ b/drivers/accel/habanalabs/common/hwmon.c @@ -578,10 +578,6 @@ int hl_get_temperature(struct hl_device *hdev, CPUCP_PKT_CTL_OPCODE_SHIFT); pkt.sensor_index = __cpu_to_le16(sensor_index); pkt.type = __cpu_to_le16(attr); - - dev_dbg(hdev->dev, "get temp, ctl 0x%x, sensor %d, type %d\n", - pkt.ctl, pkt.sensor_index, pkt.type); - rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), 0, &result); diff --git a/drivers/accel/habanalabs/common/memory.c b/drivers/accel/habanalabs/common/memory.c index 0b8689fe0b64db..3348ad12c23751 100644 --- a/drivers/accel/habanalabs/common/memory.c +++ b/drivers/accel/habanalabs/common/memory.c @@ -955,8 +955,8 @@ static int map_phys_pg_pack(struct hl_ctx *ctx, u64 vaddr, (i + 1) == phys_pg_pack->npages); if (rc) { dev_err(hdev->dev, - "map failed for handle %u, npages: %llu, mapped: %llu", - phys_pg_pack->handle, phys_pg_pack->npages, + "map failed (%d) for handle %u, npages: %llu, mapped: %llu\n", + rc, phys_pg_pack->handle, phys_pg_pack->npages, mapped_pg_cnt); goto err; } @@ -1186,7 +1186,8 @@ static int map_device_va(struct hl_ctx *ctx, struct hl_mem_in *args, u64 *device rc = map_phys_pg_pack(ctx, ret_vaddr, phys_pg_pack); if (rc) { - dev_err(hdev->dev, "mapping page pack failed for handle %u\n", handle); + dev_err(hdev->dev, "mapping page pack failed (%d) for handle %u\n", + rc, handle); mutex_unlock(&hdev->mmu_lock); goto map_err; } diff --git a/drivers/accel/habanalabs/common/mmu/mmu.c b/drivers/accel/habanalabs/common/mmu/mmu.c index b2145716c60533..b654302a68fc08 100644 --- a/drivers/accel/habanalabs/common/mmu/mmu.c +++ b/drivers/accel/habanalabs/common/mmu/mmu.c @@ -596,6 +596,7 @@ int hl_mmu_if_set_funcs(struct hl_device *hdev) break; case ASIC_GAUDI2: case ASIC_GAUDI2B: + case ASIC_GAUDI2C: /* MMUs in Gaudi2 are always host resident */ hl_mmu_v2_hr_set_funcs(hdev, &hdev->mmu_func[MMU_HR_PGT]); break; diff --git a/drivers/accel/habanalabs/common/sysfs.c b/drivers/accel/habanalabs/common/sysfs.c index 01f89f029355e6..8a9f9883215765 100644 --- a/drivers/accel/habanalabs/common/sysfs.c +++ b/drivers/accel/habanalabs/common/sysfs.c @@ -8,6 +8,7 @@ #include "habanalabs.h" #include +#include static ssize_t clk_max_freq_mhz_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -80,12 +81,27 @@ static ssize_t vrm_ver_show(struct device *dev, struct device_attribute *attr, c { struct hl_device *hdev = dev_get_drvdata(dev); struct cpucp_info *cpucp_info; + u32 infineon_second_stage_version; + u32 infineon_second_stage_first_instance; + u32 infineon_second_stage_second_instance; + u32 infineon_second_stage_third_instance; + u32 mask = 0xff; cpucp_info = &hdev->asic_prop.cpucp_info; + infineon_second_stage_version = le32_to_cpu(cpucp_info->infineon_second_stage_version); + infineon_second_stage_first_instance = infineon_second_stage_version & mask; + infineon_second_stage_second_instance = + (infineon_second_stage_version >> 8) & mask; + infineon_second_stage_third_instance = + (infineon_second_stage_version >> 16) & mask; + if (cpucp_info->infineon_second_stage_version) - return sprintf(buf, "%#04x %#04x\n", le32_to_cpu(cpucp_info->infineon_version), - le32_to_cpu(cpucp_info->infineon_second_stage_version)); + return sprintf(buf, "%#04x %#04x:%#04x:%#04x\n", + le32_to_cpu(cpucp_info->infineon_version), + infineon_second_stage_first_instance, + infineon_second_stage_second_instance, + infineon_second_stage_third_instance); else return sprintf(buf, "%#04x\n", le32_to_cpu(cpucp_info->infineon_version)); } @@ -251,6 +267,9 @@ static ssize_t device_type_show(struct device *dev, case ASIC_GAUDI2B: str = "GAUDI2B"; break; + case ASIC_GAUDI2C: + str = "GAUDI2C"; + break; default: dev_err(hdev->dev, "Unrecognized ASIC type %d\n", hdev->asic_type); @@ -383,6 +402,21 @@ static ssize_t security_enabled_show(struct device *dev, return sprintf(buf, "%d\n", hdev->asic_prop.fw_security_enabled); } +static ssize_t module_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct hl_device *hdev = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", le32_to_cpu(hdev->asic_prop.cpucp_info.card_location)); +} + +static ssize_t parent_device_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct hl_device *hdev = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", HL_DEV_NAME(hdev)); +} + static DEVICE_ATTR_RO(armcp_kernel_ver); static DEVICE_ATTR_RO(armcp_ver); static DEVICE_ATTR_RO(cpld_ver); @@ -402,6 +436,8 @@ static DEVICE_ATTR_RO(thermal_ver); static DEVICE_ATTR_RO(uboot_ver); static DEVICE_ATTR_RO(fw_os_ver); static DEVICE_ATTR_RO(security_enabled); +static DEVICE_ATTR_RO(module_id); +static DEVICE_ATTR_RO(parent_device); static struct bin_attribute bin_attr_eeprom = { .attr = {.name = "eeprom", .mode = (0444)}, @@ -427,6 +463,8 @@ static struct attribute *hl_dev_attrs[] = { &dev_attr_uboot_ver.attr, &dev_attr_fw_os_ver.attr, &dev_attr_security_enabled.attr, + &dev_attr_module_id.attr, + &dev_attr_parent_device.attr, NULL, }; diff --git a/drivers/accel/habanalabs/gaudi2/gaudi2.c b/drivers/accel/habanalabs/gaudi2/gaudi2.c index 819660c684cfc9..e0e5615ef9b0f6 100644 --- a/drivers/accel/habanalabs/gaudi2/gaudi2.c +++ b/drivers/accel/habanalabs/gaudi2/gaudi2.c @@ -7858,39 +7858,44 @@ static bool gaudi2_handle_ecc_event(struct hl_device *hdev, u16 event_type, return !!ecc_data->is_critical; } -static void handle_lower_qman_data_on_err(struct hl_device *hdev, u64 qman_base, u64 event_mask) +static void handle_lower_qman_data_on_err(struct hl_device *hdev, u64 qman_base, u32 engine_id) { - u32 lo, hi, cq_ptr_size, arc_cq_ptr_size; - u64 cq_ptr, arc_cq_ptr, cp_current_inst; + struct undefined_opcode_info *undef_opcode = &hdev->captured_err_info.undef_opcode; + u64 cq_ptr, cp_current_inst; + u32 lo, hi, cq_size, cp_sts; + bool is_arc_cq; - lo = RREG32(qman_base + QM_CQ_PTR_LO_4_OFFSET); - hi = RREG32(qman_base + QM_CQ_PTR_HI_4_OFFSET); - cq_ptr = ((u64) hi) << 32 | lo; - cq_ptr_size = RREG32(qman_base + QM_CQ_TSIZE_4_OFFSET); + cp_sts = RREG32(qman_base + QM_CP_STS_4_OFFSET); + is_arc_cq = FIELD_GET(PDMA0_QM_CP_STS_CUR_CQ_MASK, cp_sts); /* 0 - legacy CQ, 1 - ARC_CQ */ - lo = RREG32(qman_base + QM_ARC_CQ_PTR_LO_OFFSET); - hi = RREG32(qman_base + QM_ARC_CQ_PTR_HI_OFFSET); - arc_cq_ptr = ((u64) hi) << 32 | lo; - arc_cq_ptr_size = RREG32(qman_base + QM_ARC_CQ_TSIZE_OFFSET); + if (is_arc_cq) { + lo = RREG32(qman_base + QM_ARC_CQ_PTR_LO_STS_OFFSET); + hi = RREG32(qman_base + QM_ARC_CQ_PTR_HI_STS_OFFSET); + cq_ptr = ((u64) hi) << 32 | lo; + cq_size = RREG32(qman_base + QM_ARC_CQ_TSIZE_STS_OFFSET); + } else { + lo = RREG32(qman_base + QM_CQ_PTR_LO_STS_4_OFFSET); + hi = RREG32(qman_base + QM_CQ_PTR_HI_STS_4_OFFSET); + cq_ptr = ((u64) hi) << 32 | lo; + cq_size = RREG32(qman_base + QM_CQ_TSIZE_STS_4_OFFSET); + } lo = RREG32(qman_base + QM_CP_CURRENT_INST_LO_4_OFFSET); hi = RREG32(qman_base + QM_CP_CURRENT_INST_HI_4_OFFSET); cp_current_inst = ((u64) hi) << 32 | lo; dev_info(hdev->dev, - "LowerQM. CQ: {ptr %#llx, size %u}, ARC_CQ: {ptr %#llx, size %u}, CP: {instruction %#llx}\n", - cq_ptr, cq_ptr_size, arc_cq_ptr, arc_cq_ptr_size, cp_current_inst); + "LowerQM. %sCQ: {ptr %#llx, size %u}, CP: {instruction %#018llx}\n", + is_arc_cq ? "ARC_" : "", cq_ptr, cq_size, cp_current_inst); - if (event_mask & HL_NOTIFIER_EVENT_UNDEFINED_OPCODE) { - if (arc_cq_ptr) { - hdev->captured_err_info.undef_opcode.cq_addr = arc_cq_ptr; - hdev->captured_err_info.undef_opcode.cq_size = arc_cq_ptr_size; - } else { - hdev->captured_err_info.undef_opcode.cq_addr = cq_ptr; - hdev->captured_err_info.undef_opcode.cq_size = cq_ptr_size; - } - - hdev->captured_err_info.undef_opcode.stream_id = QMAN_STREAMS; + if (undef_opcode->write_enable) { + memset(undef_opcode, 0, sizeof(*undef_opcode)); + undef_opcode->timestamp = ktime_get(); + undef_opcode->cq_addr = cq_ptr; + undef_opcode->cq_size = cq_size; + undef_opcode->engine_id = engine_id; + undef_opcode->stream_id = QMAN_STREAMS; + undef_opcode->write_enable = 0; } } @@ -7929,21 +7934,12 @@ static int gaudi2_handle_qman_err_generic(struct hl_device *hdev, u16 event_type error_count++; } - if (i == QMAN_STREAMS && error_count) { - /* check for undefined opcode */ - if (glbl_sts_val & PDMA0_QM_GLBL_ERR_STS_CP_UNDEF_CMD_ERR_MASK && - hdev->captured_err_info.undef_opcode.write_enable) { - memset(&hdev->captured_err_info.undef_opcode, 0, - sizeof(hdev->captured_err_info.undef_opcode)); - - hdev->captured_err_info.undef_opcode.write_enable = false; - hdev->captured_err_info.undef_opcode.timestamp = ktime_get(); - hdev->captured_err_info.undef_opcode.engine_id = - gaudi2_queue_id_to_engine_id[qid_base]; - *event_mask |= HL_NOTIFIER_EVENT_UNDEFINED_OPCODE; - } - - handle_lower_qman_data_on_err(hdev, qman_base, *event_mask); + /* Check for undefined opcode error in lower QM */ + if ((i == QMAN_STREAMS) && + (glbl_sts_val & PDMA0_QM_GLBL_ERR_STS_CP_UNDEF_CMD_ERR_MASK)) { + handle_lower_qman_data_on_err(hdev, qman_base, + gaudi2_queue_id_to_engine_id[qid_base]); + *event_mask |= HL_NOTIFIER_EVENT_UNDEFINED_OPCODE; } } @@ -10007,6 +10003,8 @@ static void gaudi2_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_ent error_count = gaudi2_handle_pcie_drain(hdev, &eq_entry->pcie_drain_ind_data); reset_flags |= HL_DRV_RESET_FW_FATAL_ERR; event_mask |= HL_NOTIFIER_EVENT_GENERAL_HW_ERR; + if (hl_is_fw_sw_ver_equal_or_greater(hdev, 1, 13)) + is_critical = true; break; case GAUDI2_EVENT_PSOC59_RPM_ERROR_OR_DRAIN: diff --git a/drivers/accel/habanalabs/include/gaudi2/asic_reg/gaudi2_regs.h b/drivers/accel/habanalabs/include/gaudi2/asic_reg/gaudi2_regs.h index a08378d0802b55..d21fcd3880b448 100644 --- a/drivers/accel/habanalabs/include/gaudi2/asic_reg/gaudi2_regs.h +++ b/drivers/accel/habanalabs/include/gaudi2/asic_reg/gaudi2_regs.h @@ -242,14 +242,15 @@ #define QM_FENCE2_OFFSET (mmPDMA0_QM_CP_FENCE2_RDATA_0 - mmPDMA0_QM_BASE) #define QM_SEI_STATUS_OFFSET (mmPDMA0_QM_SEI_STATUS - mmPDMA0_QM_BASE) -#define QM_CQ_PTR_LO_4_OFFSET (mmPDMA0_QM_CQ_PTR_LO_4 - mmPDMA0_QM_BASE) -#define QM_CQ_PTR_HI_4_OFFSET (mmPDMA0_QM_CQ_PTR_HI_4 - mmPDMA0_QM_BASE) -#define QM_CQ_TSIZE_4_OFFSET (mmPDMA0_QM_CQ_TSIZE_4 - mmPDMA0_QM_BASE) +#define QM_CQ_TSIZE_STS_4_OFFSET (mmPDMA0_QM_CQ_TSIZE_STS_4 - mmPDMA0_QM_BASE) +#define QM_CQ_PTR_LO_STS_4_OFFSET (mmPDMA0_QM_CQ_PTR_LO_STS_4 - mmPDMA0_QM_BASE) +#define QM_CQ_PTR_HI_STS_4_OFFSET (mmPDMA0_QM_CQ_PTR_HI_STS_4 - mmPDMA0_QM_BASE) -#define QM_ARC_CQ_PTR_LO_OFFSET (mmPDMA0_QM_ARC_CQ_PTR_LO - mmPDMA0_QM_BASE) -#define QM_ARC_CQ_PTR_HI_OFFSET (mmPDMA0_QM_ARC_CQ_PTR_HI - mmPDMA0_QM_BASE) -#define QM_ARC_CQ_TSIZE_OFFSET (mmPDMA0_QM_ARC_CQ_TSIZE - mmPDMA0_QM_BASE) +#define QM_ARC_CQ_TSIZE_STS_OFFSET (mmPDMA0_QM_ARC_CQ_TSIZE_STS - mmPDMA0_QM_BASE) +#define QM_ARC_CQ_PTR_LO_STS_OFFSET (mmPDMA0_QM_ARC_CQ_PTR_LO_STS - mmPDMA0_QM_BASE) +#define QM_ARC_CQ_PTR_HI_STS_OFFSET (mmPDMA0_QM_ARC_CQ_PTR_HI_STS - mmPDMA0_QM_BASE) +#define QM_CP_STS_4_OFFSET (mmPDMA0_QM_CP_STS_4 - mmPDMA0_QM_BASE) #define QM_CP_CURRENT_INST_LO_4_OFFSET (mmPDMA0_QM_CP_CURRENT_INST_LO_4 - mmPDMA0_QM_BASE) #define QM_CP_CURRENT_INST_HI_4_OFFSET (mmPDMA0_QM_CP_CURRENT_INST_HI_4 - mmPDMA0_QM_BASE) diff --git a/drivers/accel/habanalabs/include/hw_ip/pci/pci_general.h b/drivers/accel/habanalabs/include/hw_ip/pci/pci_general.h index f5d497dc9bdc17..4f951cada07766 100644 --- a/drivers/accel/habanalabs/include/hw_ip/pci/pci_general.h +++ b/drivers/accel/habanalabs/include/hw_ip/pci/pci_general.h @@ -25,6 +25,7 @@ enum hl_revision_id { REV_ID_INVALID = 0x00, REV_ID_A = 0x01, REV_ID_B = 0x02, + REV_ID_C = 0x03 }; #endif /* INCLUDE_PCI_GENERAL_H_ */ diff --git a/drivers/accel/ivpu/Kconfig b/drivers/accel/ivpu/Kconfig index 1a4c4ed9d11368..682c532452863e 100644 --- a/drivers/accel/ivpu/Kconfig +++ b/drivers/accel/ivpu/Kconfig @@ -1,16 +1,17 @@ # SPDX-License-Identifier: GPL-2.0-only config DRM_ACCEL_IVPU - tristate "Intel VPU for Meteor Lake and newer" + tristate "Intel NPU (Neural Processing Unit)" depends on DRM_ACCEL depends on X86_64 && !UML depends on PCI && PCI_MSI select FW_LOADER - select SHMEM + select DRM_GEM_SHMEM_HELPER select GENERIC_ALLOCATOR 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. + Choose this option if you have a system with an 14th generation + Intel CPU (Meteor Lake) or newer. Intel NPU (formerly called Intel VPU) + is 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/ivpu_debugfs.c b/drivers/accel/ivpu/ivpu_debugfs.c index ea453b985b4913..7cb962e2145349 100644 --- a/drivers/accel/ivpu/ivpu_debugfs.c +++ b/drivers/accel/ivpu/ivpu_debugfs.c @@ -14,6 +14,7 @@ #include "ivpu_fw.h" #include "ivpu_fw_log.h" #include "ivpu_gem.h" +#include "ivpu_hw.h" #include "ivpu_jsm_msg.h" #include "ivpu_pm.h" @@ -101,7 +102,7 @@ static int reset_pending_show(struct seq_file *s, void *v) { struct ivpu_device *vdev = seq_to_ivpu(s); - seq_printf(s, "%d\n", atomic_read(&vdev->pm->in_reset)); + seq_printf(s, "%d\n", atomic_read(&vdev->pm->reset_pending)); return 0; } @@ -115,6 +116,33 @@ static const struct drm_debugfs_info vdev_debugfs_list[] = { {"reset_pending", reset_pending_show, 0}, }; +static ssize_t +dvfs_mode_fops_write(struct file *file, const char __user *user_buf, size_t size, loff_t *pos) +{ + struct ivpu_device *vdev = file->private_data; + struct ivpu_fw_info *fw = vdev->fw; + u32 dvfs_mode; + int ret; + + ret = kstrtou32_from_user(user_buf, size, 0, &dvfs_mode); + if (ret < 0) + return ret; + + fw->dvfs_mode = dvfs_mode; + + ret = pci_try_reset_function(to_pci_dev(vdev->drm.dev)); + if (ret) + return ret; + + return size; +} + +static const struct file_operations dvfs_mode_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .write = dvfs_mode_fops_write, +}; + static int fw_log_show(struct seq_file *s, void *v) { struct ivpu_device *vdev = s->private; @@ -151,6 +179,33 @@ static const struct file_operations fw_log_fops = { .release = single_release, }; +static ssize_t +fw_profiling_freq_fops_write(struct file *file, const char __user *user_buf, + size_t size, loff_t *pos) +{ + struct ivpu_device *vdev = file->private_data; + bool enable; + int ret; + + ret = kstrtobool_from_user(user_buf, size, &enable); + if (ret < 0) + return ret; + + ivpu_hw_profiling_freq_drive(vdev, enable); + + ret = pci_try_reset_function(to_pci_dev(vdev->drm.dev)); + if (ret) + return ret; + + return size; +} + +static const struct file_operations fw_profiling_freq_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .write = fw_profiling_freq_fops_write, +}; + static ssize_t fw_trace_destination_mask_fops_write(struct file *file, const char __user *user_buf, size_t size, loff_t *pos) @@ -251,11 +306,18 @@ static ssize_t ivpu_force_recovery_fn(struct file *file, const char __user *user_buf, size_t size, loff_t *pos) { struct ivpu_device *vdev = file->private_data; + int ret; if (!size) return -EINVAL; - ivpu_pm_schedule_recovery(vdev); + ret = ivpu_rpm_get(vdev); + if (ret) + return ret; + + ivpu_pm_trigger_recovery(vdev, "debugfs"); + flush_work(&vdev->pm->recovery_work); + ivpu_rpm_put(vdev); return size; } @@ -280,6 +342,9 @@ void ivpu_debugfs_init(struct ivpu_device *vdev) debugfs_create_file("force_recovery", 0200, debugfs_root, vdev, &ivpu_force_recovery_fops); + debugfs_create_file("dvfs_mode", 0200, debugfs_root, vdev, + &dvfs_mode_fops); + debugfs_create_file("fw_log", 0644, debugfs_root, vdev, &fw_log_fops); debugfs_create_file("fw_trace_destination_mask", 0200, debugfs_root, vdev, @@ -291,4 +356,8 @@ void ivpu_debugfs_init(struct ivpu_device *vdev) debugfs_create_file("reset_engine", 0200, debugfs_root, vdev, &ivpu_reset_engine_fops); + + if (ivpu_hw_gen(vdev) >= IVPU_HW_40XX) + debugfs_create_file("fw_profiling_freq_drive", 0200, + debugfs_root, vdev, &fw_profiling_freq_fops); } diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index 7906030176538e..9418c73ee8ef8b 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -17,6 +18,7 @@ #include "ivpu_debugfs.h" #include "ivpu_drv.h" #include "ivpu_fw.h" +#include "ivpu_fw_log.h" #include "ivpu_gem.h" #include "ivpu_hw.h" #include "ivpu_ipc.h" @@ -31,8 +33,6 @@ __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; @@ -41,7 +41,7 @@ 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"); +MODULE_PARM_DESC(test_mode, "Test mode mask. See IVPU_TEST_MODE_* macros."); u8 ivpu_pll_min_ratio; module_param_named(pll_min_ratio, ivpu_pll_min_ratio, byte, 0644); @@ -67,22 +67,20 @@ struct ivpu_file_priv *ivpu_file_priv_get(struct ivpu_file_priv *file_priv) return file_priv; } -struct ivpu_file_priv *ivpu_file_priv_get_by_ctx_id(struct ivpu_device *vdev, unsigned long id) +static void file_priv_unbind(struct ivpu_device *vdev, struct ivpu_file_priv *file_priv) { - 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; + mutex_lock(&file_priv->lock); + if (file_priv->bound) { + ivpu_dbg(vdev, FILE, "file_priv unbind: ctx %u\n", file_priv->ctx.id); + + ivpu_cmdq_release_all_locked(file_priv); + ivpu_jsm_context_release(vdev, file_priv->ctx.id); + ivpu_bo_unbind_all_bos_from_context(vdev, &file_priv->ctx); + ivpu_mmu_user_context_fini(vdev, &file_priv->ctx); + file_priv->bound = false; + drm_WARN_ON(&vdev->drm, !xa_erase_irq(&vdev->context_xa, file_priv->ctx.id)); + } + mutex_unlock(&file_priv->lock); } static void file_priv_release(struct kref *ref) @@ -90,13 +88,15 @@ 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_dbg(vdev, FILE, "file_priv release: ctx %u bound %d\n", + file_priv->ctx.id, (bool)file_priv->bound); + + pm_runtime_get_sync(vdev->drm.dev); + mutex_lock(&vdev->context_list_lock); + file_priv_unbind(vdev, file_priv); + mutex_unlock(&vdev->context_list_lock); + pm_runtime_put_autosuspend(vdev->drm.dev); - 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); } @@ -178,9 +178,6 @@ static int ivpu_get_param_ioctl(struct drm_device *dev, void *data, struct drm_f case DRM_IVPU_PARAM_CONTEXT_BASE_ADDRESS: args->value = vdev->hw->ranges.user.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; @@ -220,17 +217,10 @@ static int ivpu_get_param_ioctl(struct drm_device *dev, void *data, struct drm_f 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; } @@ -243,50 +233,53 @@ 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; + int idx, 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; - } + if (!drm_dev_enter(dev, &idx)) + return -ENODEV; file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL); if (!file_priv) { ret = -ENOMEM; - goto err_xa_erase; + goto err_dev_exit; } file_priv->vdev = vdev; - file_priv->priority = DRM_IVPU_CONTEXT_PRIORITY_NORMAL; + file_priv->bound = true; kref_init(&file_priv->ref); mutex_init(&file_priv->lock); + mutex_lock(&vdev->context_list_lock); + + ret = xa_alloc_irq(&vdev->context_xa, &ctx_id, file_priv, + vdev->context_xa_limit, GFP_KERNEL); + if (ret) { + ivpu_err(vdev, "Failed to allocate context id: %d\n", ret); + goto err_unlock; + } + ret = ivpu_mmu_user_context_init(vdev, &file_priv->ctx, ctx_id); if (ret) - goto err_mutex_destroy; + goto err_xa_erase; - 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; - } + mutex_unlock(&vdev->context_list_lock); + drm_dev_exit(idx); + + file->driver_priv = file_priv; 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); +err_unlock: + mutex_unlock(&vdev->context_list_lock); + mutex_destroy(&file_priv->lock); + kfree(file_priv); +err_dev_exit: + drm_dev_exit(idx); return ret; } @@ -317,16 +310,14 @@ static int ivpu_wait_for_ready(struct ivpu_device *vdev) unsigned long timeout; int ret; - if (ivpu_test_mode == IVPU_TEST_MODE_FW_TEST) + if (ivpu_test_mode & IVPU_TEST_MODE_FW_TEST) return 0; - ivpu_ipc_consumer_add(vdev, &cons, IVPU_IPC_CHAN_BOOT_MSG); + ivpu_ipc_consumer_add(vdev, &cons, IVPU_IPC_CHAN_BOOT_MSG, NULL); timeout = jiffies + msecs_to_jiffies(vdev->timeout.boot); while (1) { - ret = ivpu_ipc_irq_handler(vdev); - if (ret) - break; + ivpu_ipc_irq_handler(vdev, NULL); ret = ivpu_ipc_receive(vdev, &cons, &ipc_hdr, NULL, 0); if (ret != -ETIMEDOUT || time_after_eq(jiffies, timeout)) break; @@ -344,8 +335,6 @@ static int ivpu_wait_for_ready(struct ivpu_device *vdev) if (!ret) ivpu_dbg(vdev, PM, "VPU ready message received successfully\n"); - else - ivpu_hw_diagnose_failure(vdev); return ret; } @@ -362,7 +351,7 @@ 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); + ivpu_fw_boot_params_setup(vdev, ivpu_bo_vaddr(vdev->fw->mem)); ret = ivpu_hw_boot_fw(vdev); if (ret) { @@ -373,6 +362,9 @@ int ivpu_boot(struct ivpu_device *vdev) ret = ivpu_wait_for_ready(vdev); if (ret) { ivpu_err(vdev, "Failed to boot the firmware: %d\n", ret); + ivpu_hw_diagnose_failure(vdev); + ivpu_mmu_evtq_dump(vdev); + ivpu_fw_log_dump(vdev); return ret; } @@ -414,7 +406,9 @@ static const struct drm_driver driver = { .open = ivpu_open, .postclose = ivpu_postclose, - .gem_prime_import = ivpu_gem_prime_import, + + .gem_create_object = ivpu_gem_create_object, + .gem_prime_import_sg_table = drm_gem_shmem_prime_import_sg_table, .ioctls = ivpu_drm_ioctls, .num_ioctls = ARRAY_SIZE(ivpu_drm_ioctls), @@ -427,6 +421,13 @@ static const struct drm_driver driver = { .minor = DRM_IVPU_DRIVER_MINOR, }; +static irqreturn_t ivpu_irq_thread_handler(int irq, void *arg) +{ + struct ivpu_device *vdev = arg; + + return ivpu_ipc_irq_thread_handler(vdev); +} + static int ivpu_irq_init(struct ivpu_device *vdev) { struct pci_dev *pdev = to_pci_dev(vdev->drm.dev); @@ -440,8 +441,8 @@ static int ivpu_irq_init(struct ivpu_device *vdev) 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); + ret = devm_request_threaded_irq(vdev->drm.dev, vdev->irq, vdev->hw->ops->irq_handler, + ivpu_irq_thread_handler, IRQF_NO_AUTOEN, DRIVER_NAME, vdev); if (ret) ivpu_err(vdev, "Failed to request an IRQ %d\n", ret); @@ -533,6 +534,15 @@ static int ivpu_dev_init(struct ivpu_device *vdev) 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); + INIT_LIST_HEAD(&vdev->bo_list); + + ret = drmm_mutex_init(&vdev->drm, &vdev->context_list_lock); + if (ret) + goto err_xa_destroy; + + ret = drmm_mutex_init(&vdev->drm, &vdev->bo_list_lock); + if (ret) + goto err_xa_destroy; ret = ivpu_pci_init(vdev); if (ret) @@ -550,7 +560,7 @@ static int ivpu_dev_init(struct ivpu_device *vdev) /* Power up early so the rest of init code can access VPU registers */ ret = ivpu_hw_power_up(vdev); if (ret) - goto err_xa_destroy; + goto err_power_down; ret = ivpu_mmu_global_context_init(vdev); if (ret) @@ -574,20 +584,15 @@ static int ivpu_dev_init(struct ivpu_device *vdev) ivpu_pm_init(vdev); - ret = ivpu_job_done_thread_init(vdev); - if (ret) - goto err_ipc_fini; - ret = ivpu_boot(vdev); if (ret) - goto err_job_done_thread_fini; + goto err_ipc_fini; + ivpu_job_done_consumer_init(vdev); 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: @@ -606,14 +611,30 @@ err_xa_destroy: return ret; } +static void ivpu_bo_unbind_all_user_contexts(struct ivpu_device *vdev) +{ + struct ivpu_file_priv *file_priv; + unsigned long ctx_id; + + mutex_lock(&vdev->context_list_lock); + + xa_for_each(&vdev->context_xa, ctx_id, file_priv) + file_priv_unbind(vdev, file_priv); + + mutex_unlock(&vdev->context_list_lock); +} + static void ivpu_dev_fini(struct ivpu_device *vdev) { ivpu_pm_disable(vdev); ivpu_shutdown(vdev); if (IVPU_WA(d3hot_after_power_off)) pci_set_power_state(to_pci_dev(vdev->drm.dev), PCI_D3hot); - ivpu_job_done_thread_fini(vdev); + + ivpu_jobs_abort_all(vdev); + ivpu_job_done_consumer_fini(vdev); ivpu_pm_cancel_recovery(vdev); + ivpu_bo_unbind_all_user_contexts(vdev); ivpu_ipc_fini(vdev); ivpu_fw_fini(vdev); diff --git a/drivers/accel/ivpu/ivpu_drv.h b/drivers/accel/ivpu/ivpu_drv.h index 417ddeca851736..069ace4adb2d19 100644 --- a/drivers/accel/ivpu/ivpu_drv.h +++ b/drivers/accel/ivpu/ivpu_drv.h @@ -17,9 +17,10 @@ #include #include "ivpu_mmu_context.h" +#include "ivpu_ipc.h" #define DRIVER_NAME "intel_vpu" -#define DRIVER_DESC "Driver for Intel Versatile Processing Unit (VPU)" +#define DRIVER_DESC "Driver for Intel NPU (Neural Processing Unit)" #define DRIVER_DATE "20230117" #define PCI_DEVICE_ID_MTL 0x7d1d @@ -55,6 +56,7 @@ #define IVPU_DBG_JSM BIT(10) #define IVPU_DBG_KREF BIT(11) #define IVPU_DBG_RPM BIT(12) +#define IVPU_DBG_MMU_MAP BIT(13) #define ivpu_err(vdev, fmt, ...) \ drm_err(&(vdev)->drm, "%s(): " fmt, __func__, ##__VA_ARGS__) @@ -88,6 +90,7 @@ struct ivpu_wa_table { bool d3hot_after_power_off; bool interrupt_clear_with_0; bool disable_clock_relinquish; + bool disable_d0i3_msg; }; struct ivpu_hw_info; @@ -112,11 +115,15 @@ struct ivpu_device { struct ivpu_mmu_context gctx; struct ivpu_mmu_context rctx; + struct mutex context_list_lock; /* Protects user context addition/removal */ struct xarray context_xa; struct xa_limit context_xa_limit; + struct mutex bo_list_lock; /* Protects bo_list */ + struct list_head bo_list; + struct xarray submitted_jobs_xa; - struct task_struct *job_done_thread; + struct ivpu_ipc_consumer job_done_consumer; atomic64_t unique_id_counter; @@ -126,6 +133,7 @@ struct ivpu_device { int tdr; int reschedule_suspend; int autosuspend; + int d0i3_entry_msg; } timeout; }; @@ -139,8 +147,8 @@ struct ivpu_file_priv { struct mutex lock; /* Protects cmdq */ struct ivpu_cmdq *cmdq[IVPU_NUM_ENGINES]; struct ivpu_mmu_context ctx; - u32 priority; bool has_mmu_faults; + bool bound; }; extern int ivpu_dbg_mask; @@ -148,13 +156,14 @@ extern u8 ivpu_pll_min_ratio; extern u8 ivpu_pll_max_ratio; extern bool ivpu_disable_mmu_cont_pages; -#define IVPU_TEST_MODE_DISABLED 0 -#define IVPU_TEST_MODE_FW_TEST 1 -#define IVPU_TEST_MODE_NULL_HW 2 +#define IVPU_TEST_MODE_FW_TEST BIT(0) +#define IVPU_TEST_MODE_NULL_HW BIT(1) +#define IVPU_TEST_MODE_NULL_SUBMISSION BIT(2) +#define IVPU_TEST_MODE_D0I3_MSG_DISABLE BIT(4) +#define IVPU_TEST_MODE_D0I3_MSG_ENABLE BIT(5) 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); diff --git a/drivers/accel/ivpu/ivpu_fw.c b/drivers/accel/ivpu/ivpu_fw.c index 691da521dde574..6576232f3e678e 100644 --- a/drivers/accel/ivpu/ivpu_fw.c +++ b/drivers/accel/ivpu/ivpu_fw.c @@ -33,12 +33,17 @@ #define ADDR_TO_L2_CACHE_CFG(addr) ((addr) >> 31) -#define IVPU_FW_CHECK_API(vdev, fw_hdr, name, min_major) \ +/* Check if FW API is compatible with the driver */ +#define IVPU_FW_CHECK_API_COMPAT(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) +/* Check if API version is lower that the given version */ +#define IVPU_FW_CHECK_API_VER_LT(vdev, fw_hdr, name, major, minor) \ + ivpu_fw_check_api_ver_lt(vdev, fw_hdr, #name, VPU_##name##_API_VER_INDEX, major, minor) + static char *ivpu_firmware; module_param_named_unsafe(firmware, ivpu_firmware, charp, 0644); MODULE_PARM_DESC(firmware, "VPU firmware binary in /lib/firmware/.."); @@ -105,6 +110,19 @@ ivpu_fw_check_api(struct ivpu_device *vdev, const struct vpu_firmware_header *fw return 0; } +static bool +ivpu_fw_check_api_ver_lt(struct ivpu_device *vdev, const struct vpu_firmware_header *fw_hdr, + const char *str, int index, u16 major, u16 minor) +{ + u16 fw_major = (u16)(fw_hdr->api_version[index] >> 16); + u16 fw_minor = (u16)(fw_hdr->api_version[index]); + + if (fw_major < major || (fw_major == major && fw_minor < minor)) + return true; + + return false; +} + static int ivpu_fw_parse(struct ivpu_device *vdev) { struct ivpu_fw_info *fw = vdev->fw; @@ -164,9 +182,9 @@ static int ivpu_fw_parse(struct ivpu_device *vdev) ivpu_info(vdev, "Firmware: %s, version: %s", fw->name, (const char *)fw_hdr + VPU_FW_HEADER_SIZE); - if (IVPU_FW_CHECK_API(vdev, fw_hdr, BOOT, 3)) + if (IVPU_FW_CHECK_API_COMPAT(vdev, fw_hdr, BOOT, 3)) return -EINVAL; - if (IVPU_FW_CHECK_API(vdev, fw_hdr, JSM, 3)) + if (IVPU_FW_CHECK_API_COMPAT(vdev, fw_hdr, JSM, 3)) return -EINVAL; fw->runtime_addr = runtime_addr; @@ -182,6 +200,8 @@ static int ivpu_fw_parse(struct ivpu_device *vdev) fw->trace_destination_mask = VPU_TRACE_DESTINATION_VERBOSE_TRACING; fw->trace_hw_component_mask = -1; + fw->dvfs_mode = 0; + 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", @@ -195,6 +215,24 @@ static void ivpu_fw_release(struct ivpu_device *vdev) release_firmware(vdev->fw->file); } +/* Initialize workarounds that depend on FW version */ +static void +ivpu_fw_init_wa(struct ivpu_device *vdev) +{ + const struct vpu_firmware_header *fw_hdr = (const void *)vdev->fw->file->data; + + if (IVPU_FW_CHECK_API_VER_LT(vdev, fw_hdr, BOOT, 3, 17) || + (ivpu_hw_gen(vdev) > IVPU_HW_37XX) || + (ivpu_test_mode & IVPU_TEST_MODE_D0I3_MSG_DISABLE)) + vdev->wa.disable_d0i3_msg = true; + + /* Force enable the feature for testing purposes */ + if (ivpu_test_mode & IVPU_TEST_MODE_D0I3_MSG_ENABLE) + vdev->wa.disable_d0i3_msg = false; + + IVPU_PRINT_WA(disable_d0i3_msg); +} + static int ivpu_fw_update_global_range(struct ivpu_device *vdev) { struct ivpu_fw_info *fw = vdev->fw; @@ -248,7 +286,7 @@ static int ivpu_fw_mem_init(struct ivpu_device *vdev) if (fw->shave_nn_size) { fw->mem_shave_nn = ivpu_bo_alloc_internal(vdev, vdev->hw->ranges.shave.start, - fw->shave_nn_size, DRM_IVPU_BO_UNCACHED); + fw->shave_nn_size, DRM_IVPU_BO_WC); if (!fw->mem_shave_nn) { ivpu_err(vdev, "Failed to allocate shavenn buffer\n"); ret = -ENOMEM; @@ -297,6 +335,8 @@ int ivpu_fw_init(struct ivpu_device *vdev) if (ret) goto err_fw_release; + ivpu_fw_init_wa(vdev); + ret = ivpu_fw_mem_init(vdev); if (ret) goto err_fw_release; @@ -422,14 +462,31 @@ static void ivpu_fw_boot_params_print(struct ivpu_device *vdev, struct vpu_boot_ boot_params->punit_telemetry_sram_size); ivpu_dbg(vdev, FW_BOOT, "boot_params.vpu_telemetry_enable = 0x%x\n", boot_params->vpu_telemetry_enable); + ivpu_dbg(vdev, FW_BOOT, "boot_params.dvfs_mode = %u\n", + boot_params->dvfs_mode); + ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_delayed_entry = %d\n", + boot_params->d0i3_delayed_entry); + ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_residency_time_us = %lld\n", + boot_params->d0i3_residency_time_us); + ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_entry_vpu_ts = %llu\n", + boot_params->d0i3_entry_vpu_ts); } 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 */ + /* In case of warm boot only update variable params */ if (!ivpu_fw_is_cold_boot(vdev)) { + boot_params->d0i3_residency_time_us = + ktime_us_delta(ktime_get_boottime(), vdev->hw->d0i3_entry_host_ts); + boot_params->d0i3_entry_vpu_ts = vdev->hw->d0i3_entry_vpu_ts; + + ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_residency_time_us = %lld\n", + boot_params->d0i3_residency_time_us); + ivpu_dbg(vdev, FW_BOOT, "boot_params.d0i3_entry_vpu_ts = %llu\n", + boot_params->d0i3_entry_vpu_ts); + boot_params->save_restore_ret_address = 0; vdev->pm->is_warmboot = true; wmb(); /* Flush WC buffers after writing save_restore_ret_address */ @@ -442,6 +499,13 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params boot_params->vpu_id = to_pci_dev(vdev->drm.dev)->bus->number; boot_params->frequency = ivpu_hw_reg_pll_freq_get(vdev); + /* + * This param is a debug firmware feature. It switches default clock + * to higher resolution one for fine-grained and more accurate firmware + * task profiling. + */ + boot_params->perf_clk_frequency = ivpu_hw_profiling_freq_get(vdev); + /* * Uncached region of VPU address space, covers IPC buffers, job queues * and log buffers, programmable to L2$ Uncached by VPU MTRR @@ -493,6 +557,11 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params 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); + boot_params->dvfs_mode = vdev->fw->dvfs_mode; + if (!IVPU_WA(disable_d0i3_msg)) + boot_params->d0i3_delayed_entry = 1; + boot_params->d0i3_residency_time_us = 0; + boot_params->d0i3_entry_vpu_ts = 0; wmb(); /* Flush WC buffers after writing bootparams */ diff --git a/drivers/accel/ivpu/ivpu_fw.h b/drivers/accel/ivpu/ivpu_fw.h index 10ae2847f0ef3c..66b60fa161b522 100644 --- a/drivers/accel/ivpu/ivpu_fw.h +++ b/drivers/accel/ivpu/ivpu_fw.h @@ -27,6 +27,7 @@ struct ivpu_fw_info { u32 trace_level; u32 trace_destination_mask; u64 trace_hw_component_mask; + u32 dvfs_mode; }; int ivpu_fw_init(struct ivpu_device *vdev); diff --git a/drivers/accel/ivpu/ivpu_gem.c b/drivers/accel/ivpu/ivpu_gem.c index c91852f2edc82a..e9ddbe9f50ebef 100644 --- a/drivers/accel/ivpu/ivpu_gem.c +++ b/drivers/accel/ivpu/ivpu_gem.c @@ -20,215 +20,15 @@ #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 = ivpu_bo_size(bo) >> 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, ivpu_bo_size(bo) >> 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 = ivpu_bo_size(bo) >> 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 = ivpu_bo_size(bo) >> 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) +static inline void ivpu_dbg_bo(struct ivpu_device *vdev, struct ivpu_bo *bo, const char *action) { - unsigned int i, npages = ivpu_bo_size(bo) >> PAGE_SHIFT; - - if (ivpu_bo_cache_mode(bo) != DRM_IVPU_BO_CACHED) - set_pages_array_wb(bo->pages, ivpu_bo_size(bo) >> 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_dbg(vdev, BO, + "%6s: bo %8p vpu_addr %9llx size %8zu ctx %d has_pages %d dma_mapped %d mmu_mapped %d wc %d imported %d\n", + action, bo, bo->vpu_addr, ivpu_bo_size(bo), bo->ctx ? bo->ctx->id : 0, + (bool)bo->base.pages, (bool)bo->base.sgt, bo->mmu_mapped, bo->base.map_wc, + (bool)bo->base.base.import_attach); } /* @@ -245,21 +45,19 @@ int __must_check ivpu_bo_pin(struct ivpu_bo *bo) 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; - } + ivpu_dbg_bo(vdev, bo, "pin"); + drm_WARN_ON(&vdev->drm, !bo->ctx); + + if (!bo->mmu_mapped) { + struct sg_table *sgt = drm_gem_shmem_get_pages_sgt(&bo->base); - if (!bo->sgt) { - ret = ivpu_bo_alloc_and_map_pages_locked(bo); - if (ret) + if (IS_ERR(sgt)) { + ret = PTR_ERR(sgt); + ivpu_err(vdev, "Failed to map BO in IOMMU: %d\n", ret); goto unlock; - } + } - if (!bo->mmu_mapped) { - ret = ivpu_mmu_context_map_sgt(vdev, bo->ctx, bo->vpu_addr, bo->sgt, + ret = ivpu_mmu_context_map_sgt(vdev, bo->ctx, bo->vpu_addr, sgt, ivpu_bo_is_snooped(bo)); if (ret) { ivpu_err(vdev, "Failed to map BO in MMU: %d\n", ret); @@ -279,250 +77,187 @@ 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; + int idx, ret; - if (!range) { - if (bo->flags & DRM_IVPU_BO_SHAVE_MEM) - range = &vdev->hw->ranges.shave; - else if (bo->flags & DRM_IVPU_BO_DMA_MEM) - range = &vdev->hw->ranges.dma; - else - range = &vdev->hw->ranges.user; - } + if (!drm_dev_enter(&vdev->drm, &idx)) + return -ENODEV; + + mutex_lock(&bo->lock); - mutex_lock(&ctx->lock); - ret = ivpu_mmu_context_insert_node_locked(ctx, range, ivpu_bo_size(bo), &bo->mm_node); + ret = ivpu_mmu_context_insert_node(ctx, range, ivpu_bo_size(bo), &bo->mm_node); if (!ret) { bo->ctx = ctx; bo->vpu_addr = bo->mm_node.start; - list_add_tail(&bo->ctx_node, &ctx->bo_list); + } else { + ivpu_err(vdev, "Failed to add BO to context %u: %d\n", ctx->id, ret); } - mutex_unlock(&ctx->lock); + + ivpu_dbg_bo(vdev, bo, "alloc"); + + mutex_unlock(&bo->lock); + + drm_dev_exit(idx); return ret; } -static void ivpu_bo_free_vpu_addr(struct ivpu_bo *bo) +static void ivpu_bo_unbind_locked(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); + lockdep_assert(lockdep_is_held(&bo->lock) || !kref_read(&bo->base.base.refcount)); if (bo->mmu_mapped) { - drm_WARN_ON(&vdev->drm, !bo->sgt); - ivpu_mmu_context_unmap_sgt(vdev, ctx, bo->vpu_addr, bo->sgt); + drm_WARN_ON(&vdev->drm, !bo->ctx); + drm_WARN_ON(&vdev->drm, !bo->vpu_addr); + drm_WARN_ON(&vdev->drm, !bo->base.sgt); + ivpu_mmu_context_unmap_sgt(vdev, bo->ctx, bo->vpu_addr, bo->base.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); + if (bo->ctx) { + ivpu_mmu_context_remove_node(bo->ctx, &bo->mm_node); + bo->ctx = NULL; + } - mutex_unlock(&bo->lock); + if (bo->base.base.import_attach) + return; + + dma_resv_lock(bo->base.base.resv, NULL); + if (bo->base.sgt) { + dma_unmap_sgtable(vdev->drm.dev, bo->base.sgt, DMA_BIDIRECTIONAL, 0); + sg_free_table(bo->base.sgt); + kfree(bo->base.sgt); + bo->base.sgt = NULL; + } + dma_resv_unlock(bo->base.base.resv); } -void ivpu_bo_remove_all_bos_from_context(struct ivpu_mmu_context *ctx) +void ivpu_bo_unbind_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx) { - struct ivpu_bo *bo, *tmp; + struct ivpu_bo *bo; + + if (drm_WARN_ON(&vdev->drm, !ctx)) + return; - list_for_each_entry_safe(bo, tmp, &ctx->bo_list, ctx_node) - ivpu_bo_free_vpu_addr(bo); + mutex_lock(&vdev->bo_list_lock); + list_for_each_entry(bo, &vdev->bo_list, bo_list_node) { + mutex_lock(&bo->lock); + if (bo->ctx == ctx) { + ivpu_dbg_bo(vdev, bo, "unbind"); + ivpu_bo_unbind_locked(bo); + } + mutex_unlock(&bo->lock); + } + mutex_unlock(&vdev->bo_list_lock); } -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 drm_gem_object *ivpu_gem_create_object(struct drm_device *dev, size_t size) { struct ivpu_bo *bo; - int ret = 0; - if (drm_WARN_ON(&vdev->drm, size == 0 || !PAGE_ALIGNED(size))) + if (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); + bo->base.base.funcs = &ivpu_gem_funcs; + bo->base.pages_mark_dirty_on_put = true; /* VPU can dirty a BO anytime */ - 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; + INIT_LIST_HEAD(&bo->bo_list_node); + mutex_init(&bo->lock); -err_release: - drm_gem_object_release(&bo->base); -err_free: - kfree(bo); - return ERR_PTR(ret); + return &bo->base.base; } -static void ivpu_bo_free(struct drm_gem_object *obj) +static struct ivpu_bo * +ivpu_bo_create(struct ivpu_device *vdev, u64 size, u32 flags) { - 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); + struct drm_gem_shmem_object *shmem; + struct ivpu_bo *bo; - if (bo->ctx) - ivpu_bo_free_vpu_addr(bo); + switch (flags & DRM_IVPU_BO_CACHE_MASK) { + case DRM_IVPU_BO_CACHED: + case DRM_IVPU_BO_WC: + break; + default: + return ERR_PTR(-EINVAL); + } - if (bo->sgt) - ivpu_bo_unmap_and_free_pages(bo); + shmem = drm_gem_shmem_create(&vdev->drm, size); + if (IS_ERR(shmem)) + return ERR_CAST(shmem); - if (bo->base.import_attach) - drm_prime_gem_destroy(&bo->base, bo->sgt); + bo = to_ivpu_bo(&shmem->base); + bo->base.map_wc = flags & DRM_IVPU_BO_WC; + bo->flags = flags; - drm_gem_object_release(&bo->base); + mutex_lock(&vdev->bo_list_lock); + list_add_tail(&bo->bo_list_node, &vdev->bo_list); + mutex_unlock(&vdev->bo_list_lock); - mutex_destroy(&bo->lock); - kfree(bo); + return bo; } -static int ivpu_bo_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) +static int ivpu_bo_open(struct drm_gem_object *obj, struct drm_file *file) { + struct ivpu_file_priv *file_priv = file->driver_priv; + struct ivpu_device *vdev = file_priv->vdev; 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, ivpu_bo_size(bo), bo->ops->name); + struct ivpu_addr_range *range; - 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); + if (bo->ctx) { + ivpu_warn(vdev, "Can't add BO to ctx %u: already in ctx %u\n", + file_priv->ctx.id, bo->ctx->id); + return -EALREADY; } - 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); + if (bo->flags & DRM_IVPU_BO_SHAVE_MEM) + range = &vdev->hw->ranges.shave; + else if (bo->flags & DRM_IVPU_BO_DMA_MEM) + range = &vdev->hw->ranges.dma; + else + range = &vdev->hw->ranges.user; - return drm_prime_pages_to_sg(obj->dev, bo->pages, npages); + return ivpu_bo_alloc_vpu_addr(bo, &file_priv->ctx, range); } -static vm_fault_t ivpu_vm_fault(struct vm_fault *vmf) +static void ivpu_bo_free(struct drm_gem_object *obj) { - struct vm_area_struct *vma = vmf->vma; - struct drm_gem_object *obj = vma->vm_private_data; + struct ivpu_device *vdev = to_ivpu_device(obj->dev); 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); + ivpu_dbg_bo(vdev, bo, "free"); - if (!bo->sgt) { - err = ivpu_bo_alloc_and_map_pages_locked(bo); - if (err) { - ret = vmf_error(err); - goto unlock; - } - } + mutex_lock(&vdev->bo_list_lock); + list_del(&bo->bo_list_node); + mutex_unlock(&vdev->bo_list_lock); - /* 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)); - } + drm_WARN_ON(&vdev->drm, !dma_resv_test_signaled(obj->resv, DMA_RESV_USAGE_READ)); -unlock: - mutex_unlock(&bo->lock); + ivpu_bo_unbind_locked(bo); + mutex_destroy(&bo->lock); - return ret; + drm_WARN_ON(obj->dev, bo->base.pages_use_count > 1); + drm_gem_shmem_free(&bo->base); } -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, + .open = ivpu_bo_open, + .print_info = drm_gem_shmem_object_print_info, + .pin = drm_gem_shmem_object_pin, + .unpin = drm_gem_shmem_object_unpin, + .get_sg_table = drm_gem_shmem_object_get_sg_table, + .vmap = drm_gem_shmem_object_vmap, + .vunmap = drm_gem_shmem_object_vunmap, + .mmap = drm_gem_shmem_object_mmap, + .vm_ops = &drm_gem_shmem_vm_ops, }; -int -ivpu_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file) +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; @@ -537,23 +272,18 @@ ivpu_bo_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file) if (size == 0) return -EINVAL; - bo = ivpu_bo_alloc(vdev, &file_priv->ctx, size, args->flags, &shmem_ops, NULL, 0); + bo = ivpu_bo_create(vdev, size, args->flags); 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) { + ret = drm_gem_handle_create(file, &bo->base.base, &args->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, ivpu_bo_size(bo), bo->flags); + drm_gem_object_put(&bo->base.base); return ret; } @@ -563,8 +293,8 @@ ivpu_bo_alloc_internal(struct ivpu_device *vdev, u64 vpu_addr, u64 size, u32 fla { const struct ivpu_addr_range *range; struct ivpu_addr_range fixed_range; + struct iosys_map map; struct ivpu_bo *bo; - pgprot_t prot; int ret; drm_WARN_ON(&vdev->drm, !PAGE_ALIGNED(vpu_addr)); @@ -578,81 +308,47 @@ ivpu_bo_alloc_internal(struct ivpu_device *vdev, u64 vpu_addr, u64 size, u32 fla range = &vdev->hw->ranges.global; } - bo = ivpu_bo_alloc(vdev, &vdev->gctx, size, flags, &internal_ops, range, 0); + bo = ivpu_bo_create(vdev, size, flags); 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); + ret = ivpu_bo_alloc_vpu_addr(bo, &vdev->gctx, range); if (ret) goto err_put; - if (ivpu_bo_cache_mode(bo) != DRM_IVPU_BO_CACHED) - drm_clflush_pages(bo->pages, ivpu_bo_size(bo) >> PAGE_SHIFT); - - if (bo->flags & DRM_IVPU_BO_WC) - set_pages_array_wc(bo->pages, ivpu_bo_size(bo) >> PAGE_SHIFT); - else if (bo->flags & DRM_IVPU_BO_UNCACHED) - set_pages_array_uc(bo->pages, ivpu_bo_size(bo) >> PAGE_SHIFT); - - prot = ivpu_bo_pgprot(bo, PAGE_KERNEL); - bo->kvaddr = vmap(bo->pages, ivpu_bo_size(bo) >> PAGE_SHIFT, VM_MAP, prot); - if (!bo->kvaddr) { - ivpu_err(vdev, "Failed to map BO into kernel virtual memory\n"); + ret = ivpu_bo_pin(bo); + if (ret) goto err_put; - } - ivpu_dbg(vdev, BO, "alloc internal: ctx 0 vpu_addr 0x%llx size %zu flags 0x%x\n", - bo->vpu_addr, ivpu_bo_size(bo), flags); + dma_resv_lock(bo->base.base.resv, NULL); + ret = drm_gem_shmem_vmap(&bo->base, &map); + dma_resv_unlock(bo->base.base.resv); + if (ret) + goto err_put; return bo; err_put: - drm_gem_object_put(&bo->base); + drm_gem_object_put(&bo->base.base); return NULL; } void ivpu_bo_free_internal(struct ivpu_bo *bo) { - drm_gem_object_put(&bo->base); -} + struct iosys_map map = IOSYS_MAP_INIT_VADDR(bo->base.vaddr); -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; + dma_resv_lock(bo->base.base.resv, NULL); + drm_gem_shmem_vunmap(&bo->base, &map); + dma_resv_unlock(bo->base.base.resv); - 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); + drm_gem_object_put(&bo->base.base); } 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; @@ -665,21 +361,12 @@ int ivpu_bo_info_ioctl(struct drm_device *dev, void *data, struct drm_file *file 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; } @@ -712,43 +399,38 @@ int ivpu_bo_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file static void ivpu_bo_print_info(struct ivpu_bo *bo, struct drm_printer *p) { - unsigned long dma_refcount = 0; + mutex_lock(&bo->lock); + + drm_printf(p, "%-9p %-3u 0x%-12llx %-10lu 0x%-8x %-4u", + bo, bo->ctx->id, bo->vpu_addr, bo->base.base.size, + bo->flags, kref_read(&bo->base.base.refcount)); + + if (bo->base.pages) + drm_printf(p, " has_pages"); - if (bo->base.dma_buf && bo->base.dma_buf->file) - dma_refcount = atomic_long_read(&bo->base.dma_buf->file->f_count); + if (bo->mmu_mapped) + drm_printf(p, " mmu_mapped"); - drm_printf(p, "%5u %6d %16llx %10lu %10u %12lu %14s\n", - bo->ctx->id, bo->handle, bo->vpu_addr, ivpu_bo_size(bo), - kref_read(&bo->base.refcount), dma_refcount, bo->ops->name); + if (bo->base.base.import_attach) + drm_printf(p, " imported"); + + drm_printf(p, "\n"); + + mutex_unlock(&bo->lock); } 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"); + drm_printf(p, "%-9s %-3s %-14s %-10s %-10s %-4s %s\n", + "bo", "ctx", "vpu_addr", "size", "flags", "refs", "attribs"); - mutex_lock(&vdev->gctx.lock); - list_for_each_entry(bo, &vdev->gctx.bo_list, ctx_node) + mutex_lock(&vdev->bo_list_lock); + list_for_each_entry(bo, &vdev->bo_list, bo_list_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); - } + mutex_unlock(&vdev->bo_list_lock); } void ivpu_bo_list_print(struct drm_device *dev) diff --git a/drivers/accel/ivpu/ivpu_gem.h b/drivers/accel/ivpu/ivpu_gem.h index a0b4d4a32b3bf7..a8559211c70d41 100644 --- a/drivers/accel/ivpu/ivpu_gem.h +++ b/drivers/accel/ivpu/ivpu_gem.h @@ -6,84 +6,51 @@ #define __IVPU_GEM_H__ #include +#include #include -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 drm_gem_shmem_object base; struct ivpu_mmu_context *ctx; - struct list_head ctx_node; + struct list_head bo_list_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; + struct mutex lock; /* Protects: ctx, mmu_mapped, vpu_addr */ 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); + u32 job_status; /* Valid only for command buffer */ + bool mmu_mapped; }; 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); +void ivpu_bo_unbind_all_bos_from_context(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx); -struct ivpu_bo * -ivpu_bo_alloc_internal(struct ivpu_device *vdev, u64 vpu_addr, u64 size, u32 flags); +struct drm_gem_object *ivpu_gem_create_object(struct drm_device *dev, size_t size); +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); +void ivpu_bo_list(struct drm_device *dev, struct drm_printer *p); +void ivpu_bo_list_print(struct drm_device *dev); + static inline struct ivpu_bo *to_ivpu_bo(struct drm_gem_object *obj) { - return container_of(obj, struct ivpu_bo, base); + return container_of(obj, struct ivpu_bo, base.base); } static inline void *ivpu_bo_vaddr(struct ivpu_bo *bo) { - return bo->kvaddr; + return bo->base.vaddr; } static inline size_t ivpu_bo_size(struct ivpu_bo *bo) { - return bo->base.size; -} - -static inline struct page *ivpu_bo_get_page(struct ivpu_bo *bo, u64 offset) -{ - if (offset > ivpu_bo_size(bo) || !bo->pages) - return NULL; - - return bo->pages[offset / PAGE_SIZE]; + return bo->base.base.size; } static inline u32 ivpu_bo_cache_mode(struct ivpu_bo *bo) @@ -96,20 +63,9 @@ 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); + return to_ivpu_device(bo->base.base.dev); } static inline void *ivpu_to_cpu_addr(struct ivpu_bo *bo, u32 vpu_addr) diff --git a/drivers/accel/ivpu/ivpu_hw.h b/drivers/accel/ivpu/ivpu_hw.h index 1079e06255ba6d..b2909168a0a690 100644 --- a/drivers/accel/ivpu/ivpu_hw.h +++ b/drivers/accel/ivpu/ivpu_hw.h @@ -15,8 +15,11 @@ struct ivpu_hw_ops { int (*power_down)(struct ivpu_device *vdev); int (*reset)(struct ivpu_device *vdev); bool (*is_idle)(struct ivpu_device *vdev); + int (*wait_for_idle)(struct ivpu_device *vdev); void (*wdt_disable)(struct ivpu_device *vdev); void (*diagnose_failure)(struct ivpu_device *vdev); + u32 (*profiling_freq_get)(struct ivpu_device *vdev); + void (*profiling_freq_drive)(struct ivpu_device *vdev, bool enable); 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); @@ -58,6 +61,8 @@ struct ivpu_hw_info { u32 sku; u16 config; int dma_bits; + ktime_t d0i3_entry_host_ts; + u64 d0i3_entry_vpu_ts; }; extern const struct ivpu_hw_ops ivpu_hw_37xx_ops; @@ -85,6 +90,11 @@ static inline bool ivpu_hw_is_idle(struct ivpu_device *vdev) return vdev->hw->ops->is_idle(vdev); }; +static inline int ivpu_hw_wait_for_idle(struct ivpu_device *vdev) +{ + return vdev->hw->ops->wait_for_idle(vdev); +}; + static inline int ivpu_hw_power_down(struct ivpu_device *vdev) { ivpu_dbg(vdev, PM, "HW power down\n"); @@ -104,6 +114,16 @@ static inline void ivpu_hw_wdt_disable(struct ivpu_device *vdev) vdev->hw->ops->wdt_disable(vdev); }; +static inline u32 ivpu_hw_profiling_freq_get(struct ivpu_device *vdev) +{ + return vdev->hw->ops->profiling_freq_get(vdev); +}; + +static inline void ivpu_hw_profiling_freq_drive(struct ivpu_device *vdev, bool enable) +{ + return vdev->hw->ops->profiling_freq_drive(vdev, enable); +}; + /* Register indirect accesses */ static inline u32 ivpu_hw_reg_pll_freq_get(struct ivpu_device *vdev) { diff --git a/drivers/accel/ivpu/ivpu_hw_37xx.c b/drivers/accel/ivpu/ivpu_hw_37xx.c index d530384f8d6070..f15a93d8305782 100644 --- a/drivers/accel/ivpu/ivpu_hw_37xx.c +++ b/drivers/accel/ivpu/ivpu_hw_37xx.c @@ -29,6 +29,7 @@ #define PLL_REF_CLK_FREQ (50 * 1000000) #define PLL_SIMULATION_FREQ (10 * 1000000) +#define PLL_PROF_CLK_FREQ (38400 * 1000) #define PLL_DEFAULT_EPP_VALUE 0x80 #define TIM_SAFE_ENABLE 0xf1d0dead @@ -37,7 +38,7 @@ #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 IDLE_TIMEOUT_US (5 * USEC_PER_MSEC) #define ICB_0_IRQ_MASK ((REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, HOST_IPC_FIFO_INT)) | \ (REG_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, MMU_IRQ_0_INT)) | \ @@ -96,6 +97,7 @@ static void ivpu_hw_timeouts_init(struct ivpu_device *vdev) vdev->timeout.tdr = 2000; vdev->timeout.reschedule_suspend = 10; vdev->timeout.autosuspend = 10; + vdev->timeout.d0i3_entry_msg = 5; } static int ivpu_pll_wait_for_cmd_send(struct ivpu_device *vdev) @@ -722,10 +724,23 @@ static bool ivpu_hw_37xx_is_idle(struct ivpu_device *vdev) REG_TEST_FLD(VPU_37XX_BUTTRESS_VPU_STATUS, IDLE, val); } +static int ivpu_hw_37xx_wait_for_idle(struct ivpu_device *vdev) +{ + return REGB_POLL_FLD(VPU_37XX_BUTTRESS_VPU_STATUS, IDLE, 0x1, IDLE_TIMEOUT_US); +} + +static void ivpu_hw_37xx_save_d0i3_entry_timestamp(struct ivpu_device *vdev) +{ + vdev->hw->d0i3_entry_host_ts = ktime_get_boottime(); + vdev->hw->d0i3_entry_vpu_ts = REGV_RD64(VPU_37XX_CPU_SS_TIM_PERF_FREE_CNT); +} + static int ivpu_hw_37xx_power_down(struct ivpu_device *vdev) { int ret = 0; + ivpu_hw_37xx_save_d0i3_entry_timestamp(vdev); + if (!ivpu_hw_37xx_is_idle(vdev)) ivpu_warn(vdev, "VPU not idle during power down\n"); @@ -760,6 +775,16 @@ static void ivpu_hw_37xx_wdt_disable(struct ivpu_device *vdev) REGV_WR32(VPU_37XX_CPU_SS_TIM_GEN_CONFIG, val); } +static u32 ivpu_hw_37xx_profiling_freq_get(struct ivpu_device *vdev) +{ + return PLL_PROF_CLK_FREQ; +} + +static void ivpu_hw_37xx_profiling_freq_drive(struct ivpu_device *vdev, bool enable) +{ + /* Profiling freq - is a debug feature. Unavailable on VPU 37XX. */ +} + static u32 ivpu_hw_37xx_pll_to_freq(u32 ratio, u32 config) { u32 pll_clock = PLL_REF_CLK_FREQ * ratio; @@ -850,38 +875,35 @@ static void ivpu_hw_37xx_irq_disable(struct ivpu_device *vdev) static void ivpu_hw_37xx_irq_wdt_nce_handler(struct ivpu_device *vdev) { - ivpu_err_ratelimited(vdev, "WDT NCE irq\n"); - - ivpu_pm_schedule_recovery(vdev); + ivpu_pm_trigger_recovery(vdev, "WDT NCE IRQ"); } static void ivpu_hw_37xx_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); + ivpu_pm_trigger_recovery(vdev, "WDT MSS IRQ"); } static void ivpu_hw_37xx_irq_noc_firewall_handler(struct ivpu_device *vdev) { - ivpu_err_ratelimited(vdev, "NOC Firewall irq\n"); - - ivpu_pm_schedule_recovery(vdev); + ivpu_pm_trigger_recovery(vdev, "NOC Firewall IRQ"); } /* Handler for IRQs from VPU core (irqV) */ -static u32 ivpu_hw_37xx_irqv_handler(struct ivpu_device *vdev, int irq) +static bool ivpu_hw_37xx_irqv_handler(struct ivpu_device *vdev, int irq, bool *wake_thread) { u32 status = REGV_RD32(VPU_37XX_HOST_SS_ICB_STATUS_0) & ICB_0_IRQ_MASK; + if (!status) + return false; + REGV_WR32(VPU_37XX_HOST_SS_ICB_CLEAR_0, status); if (REG_TEST_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, MMU_IRQ_0_INT, status)) ivpu_mmu_irq_evtq_handler(vdev); if (REG_TEST_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, HOST_IPC_FIFO_INT, status)) - ivpu_ipc_irq_handler(vdev); + ivpu_ipc_irq_handler(vdev, wake_thread); if (REG_TEST_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, MMU_IRQ_1_INT, status)) ivpu_dbg(vdev, IRQ, "MMU sync complete\n"); @@ -898,17 +920,17 @@ static u32 ivpu_hw_37xx_irqv_handler(struct ivpu_device *vdev, int irq) if (REG_TEST_FLD(VPU_37XX_HOST_SS_ICB_STATUS_0, NOC_FIREWALL_INT, status)) ivpu_hw_37xx_irq_noc_firewall_handler(vdev); - return status; + return true; } /* Handler for IRQs from Buttress core (irqB) */ -static u32 ivpu_hw_37xx_irqb_handler(struct ivpu_device *vdev, int irq) +static bool ivpu_hw_37xx_irqb_handler(struct ivpu_device *vdev, int irq) { u32 status = REGB_RD32(VPU_37XX_BUTTRESS_INTERRUPT_STAT) & BUTTRESS_IRQ_MASK; bool schedule_recovery = false; - if (status == 0) - return 0; + if (!status) + return false; if (REG_TEST_FLD(VPU_37XX_BUTTRESS_INTERRUPT_STAT, FREQ_CHANGE, status)) ivpu_dbg(vdev, IRQ, "FREQ_CHANGE irq: %08x", @@ -942,25 +964,29 @@ static u32 ivpu_hw_37xx_irqb_handler(struct ivpu_device *vdev, int irq) REGB_WR32(VPU_37XX_BUTTRESS_INTERRUPT_STAT, status); if (schedule_recovery) - ivpu_pm_schedule_recovery(vdev); + ivpu_pm_trigger_recovery(vdev, "Buttress IRQ"); - return status; + return true; } static irqreturn_t ivpu_hw_37xx_irq_handler(int irq, void *ptr) { struct ivpu_device *vdev = ptr; - u32 ret_irqv, ret_irqb; + bool irqv_handled, irqb_handled, wake_thread = false; REGB_WR32(VPU_37XX_BUTTRESS_GLOBAL_INT_MASK, 0x1); - ret_irqv = ivpu_hw_37xx_irqv_handler(vdev, irq); - ret_irqb = ivpu_hw_37xx_irqb_handler(vdev, irq); + irqv_handled = ivpu_hw_37xx_irqv_handler(vdev, irq, &wake_thread); + irqb_handled = ivpu_hw_37xx_irqb_handler(vdev, irq); /* Re-enable global interrupts to re-trigger MSI for pending interrupts */ REGB_WR32(VPU_37XX_BUTTRESS_GLOBAL_INT_MASK, 0x0); - return IRQ_RETVAL(ret_irqb | ret_irqv); + if (wake_thread) + return IRQ_WAKE_THREAD; + if (irqv_handled || irqb_handled) + return IRQ_HANDLED; + return IRQ_NONE; } static void ivpu_hw_37xx_diagnose_failure(struct ivpu_device *vdev) @@ -997,11 +1023,14 @@ const struct ivpu_hw_ops ivpu_hw_37xx_ops = { .info_init = ivpu_hw_37xx_info_init, .power_up = ivpu_hw_37xx_power_up, .is_idle = ivpu_hw_37xx_is_idle, + .wait_for_idle = ivpu_hw_37xx_wait_for_idle, .power_down = ivpu_hw_37xx_power_down, .reset = ivpu_hw_37xx_reset, .boot_fw = ivpu_hw_37xx_boot_fw, .wdt_disable = ivpu_hw_37xx_wdt_disable, .diagnose_failure = ivpu_hw_37xx_diagnose_failure, + .profiling_freq_get = ivpu_hw_37xx_profiling_freq_get, + .profiling_freq_drive = ivpu_hw_37xx_profiling_freq_drive, .reg_pll_freq_get = ivpu_hw_37xx_reg_pll_freq_get, .reg_telemetry_offset_get = ivpu_hw_37xx_reg_telemetry_offset_get, .reg_telemetry_size_get = ivpu_hw_37xx_reg_telemetry_size_get, diff --git a/drivers/accel/ivpu/ivpu_hw_37xx_reg.h b/drivers/accel/ivpu/ivpu_hw_37xx_reg.h index 4083beb5e9dbab..f6fec19192020c 100644 --- a/drivers/accel/ivpu/ivpu_hw_37xx_reg.h +++ b/drivers/accel/ivpu/ivpu_hw_37xx_reg.h @@ -240,6 +240,8 @@ #define VPU_37XX_CPU_SS_TIM_GEN_CONFIG 0x06021008u #define VPU_37XX_CPU_SS_TIM_GEN_CONFIG_WDOG_TO_INT_CLR_MASK BIT_MASK(9) +#define VPU_37XX_CPU_SS_TIM_PERF_FREE_CNT 0x06029000u + #define VPU_37XX_CPU_SS_DOORBELL_0 0x06300000u #define VPU_37XX_CPU_SS_DOORBELL_0_SET_MASK BIT_MASK(0) diff --git a/drivers/accel/ivpu/ivpu_hw_40xx.c b/drivers/accel/ivpu/ivpu_hw_40xx.c index e691c49c984105..704288084f3737 100644 --- a/drivers/accel/ivpu/ivpu_hw_40xx.c +++ b/drivers/accel/ivpu/ivpu_hw_40xx.c @@ -39,6 +39,7 @@ #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 (5 * USEC_PER_MSEC) #define WEIGHTS_DEFAULT 0xf711f711u #define WEIGHTS_ATS_DEFAULT 0x0000f711u @@ -139,18 +140,21 @@ static void ivpu_hw_timeouts_init(struct ivpu_device *vdev) vdev->timeout.tdr = 2000000; vdev->timeout.reschedule_suspend = 1000; vdev->timeout.autosuspend = -1; + vdev->timeout.d0i3_entry_msg = 500; } else if (ivpu_is_simics(vdev)) { vdev->timeout.boot = 50; vdev->timeout.jsm = 500; vdev->timeout.tdr = 10000; vdev->timeout.reschedule_suspend = 10; vdev->timeout.autosuspend = -1; + vdev->timeout.d0i3_entry_msg = 100; } else { vdev->timeout.boot = 1000; vdev->timeout.jsm = 500; vdev->timeout.tdr = 2000; vdev->timeout.reschedule_suspend = 10; vdev->timeout.autosuspend = 10; + vdev->timeout.d0i3_entry_msg = 5; } } @@ -742,7 +746,7 @@ static int ivpu_hw_40xx_info_init(struct ivpu_device *vdev) return 0; } -static int ivpu_hw_40xx_reset(struct ivpu_device *vdev) +static int ivpu_hw_40xx_ip_reset(struct ivpu_device *vdev) { int ret; u32 val; @@ -764,6 +768,23 @@ static int ivpu_hw_40xx_reset(struct ivpu_device *vdev) return ret; } +static int ivpu_hw_40xx_reset(struct ivpu_device *vdev) +{ + int ret = 0; + + if (ivpu_hw_40xx_ip_reset(vdev)) { + ivpu_err(vdev, "Failed to reset VPU IP\n"); + ret = -EIO; + } + + if (ivpu_pll_disable(vdev)) { + ivpu_err(vdev, "Failed to disable PLL\n"); + ret = -EIO; + } + + return ret; +} + static int ivpu_hw_40xx_d0i3_enable(struct ivpu_device *vdev) { int ret; @@ -824,12 +845,6 @@ static int ivpu_hw_40xx_power_up(struct ivpu_device *vdev) { int ret; - ret = ivpu_hw_40xx_reset(vdev); - if (ret) { - ivpu_err(vdev, "Failed to reset HW: %d\n", ret); - return ret; - } - ret = ivpu_hw_40xx_d0i3_disable(vdev); if (ret) ivpu_warn(vdev, "Failed to disable D0I3: %d\n", ret); @@ -898,11 +913,24 @@ static bool ivpu_hw_40xx_is_idle(struct ivpu_device *vdev) REG_TEST_FLD(VPU_40XX_BUTTRESS_VPU_STATUS, IDLE, val); } +static int ivpu_hw_40xx_wait_for_idle(struct ivpu_device *vdev) +{ + return REGB_POLL_FLD(VPU_40XX_BUTTRESS_VPU_STATUS, IDLE, 0x1, IDLE_TIMEOUT_US); +} + +static void ivpu_hw_40xx_save_d0i3_entry_timestamp(struct ivpu_device *vdev) +{ + vdev->hw->d0i3_entry_host_ts = ktime_get_boottime(); + vdev->hw->d0i3_entry_vpu_ts = REGV_RD64(VPU_40XX_CPU_SS_TIM_PERF_EXT_FREE_CNT); +} + static int ivpu_hw_40xx_power_down(struct ivpu_device *vdev) { int ret = 0; - if (!ivpu_hw_40xx_is_idle(vdev) && ivpu_hw_40xx_reset(vdev)) + ivpu_hw_40xx_save_d0i3_entry_timestamp(vdev); + + if (!ivpu_hw_40xx_is_idle(vdev) && ivpu_hw_40xx_ip_reset(vdev)) ivpu_warn(vdev, "Failed to reset the VPU\n"); if (ivpu_pll_disable(vdev)) { @@ -933,6 +961,19 @@ static void ivpu_hw_40xx_wdt_disable(struct ivpu_device *vdev) REGV_WR32(VPU_40XX_CPU_SS_TIM_GEN_CONFIG, val); } +static u32 ivpu_hw_40xx_profiling_freq_get(struct ivpu_device *vdev) +{ + return vdev->hw->pll.profiling_freq; +} + +static void ivpu_hw_40xx_profiling_freq_drive(struct ivpu_device *vdev, bool enable) +{ + if (enable) + vdev->hw->pll.profiling_freq = PLL_PROFILING_FREQ_HIGH; + else + vdev->hw->pll.profiling_freq = PLL_PROFILING_FREQ_DEFAULT; +} + /* Register indirect accesses */ static u32 ivpu_hw_40xx_reg_pll_freq_get(struct ivpu_device *vdev) { @@ -1008,28 +1049,27 @@ static void ivpu_hw_40xx_irq_disable(struct ivpu_device *vdev) static void ivpu_hw_40xx_irq_wdt_nce_handler(struct ivpu_device *vdev) { /* TODO: For LNN hang consider engine reset instead of full recovery */ - ivpu_pm_schedule_recovery(vdev); + ivpu_pm_trigger_recovery(vdev, "WDT NCE IRQ"); } static void ivpu_hw_40xx_irq_wdt_mss_handler(struct ivpu_device *vdev) { ivpu_hw_wdt_disable(vdev); - ivpu_pm_schedule_recovery(vdev); + ivpu_pm_trigger_recovery(vdev, "WDT MSS IRQ"); } static void ivpu_hw_40xx_irq_noc_firewall_handler(struct ivpu_device *vdev) { - ivpu_pm_schedule_recovery(vdev); + ivpu_pm_trigger_recovery(vdev, "NOC Firewall IRQ"); } /* Handler for IRQs from VPU core (irqV) */ -static irqreturn_t ivpu_hw_40xx_irqv_handler(struct ivpu_device *vdev, int irq) +static bool ivpu_hw_40xx_irqv_handler(struct ivpu_device *vdev, int irq, bool *wake_thread) { u32 status = REGV_RD32(VPU_40XX_HOST_SS_ICB_STATUS_0) & ICB_0_IRQ_MASK; - irqreturn_t ret = IRQ_NONE; if (!status) - return IRQ_NONE; + return false; REGV_WR32(VPU_40XX_HOST_SS_ICB_CLEAR_0, status); @@ -1037,7 +1077,7 @@ static irqreturn_t ivpu_hw_40xx_irqv_handler(struct ivpu_device *vdev, int irq) ivpu_mmu_irq_evtq_handler(vdev); if (REG_TEST_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, HOST_IPC_FIFO_INT, status)) - ret |= ivpu_ipc_irq_handler(vdev); + ivpu_ipc_irq_handler(vdev, wake_thread); if (REG_TEST_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, MMU_IRQ_1_INT, status)) ivpu_dbg(vdev, IRQ, "MMU sync complete\n"); @@ -1054,17 +1094,17 @@ static irqreturn_t ivpu_hw_40xx_irqv_handler(struct ivpu_device *vdev, int irq) if (REG_TEST_FLD(VPU_40XX_HOST_SS_ICB_STATUS_0, NOC_FIREWALL_INT, status)) ivpu_hw_40xx_irq_noc_firewall_handler(vdev); - return ret; + return true; } /* Handler for IRQs from Buttress core (irqB) */ -static irqreturn_t ivpu_hw_40xx_irqb_handler(struct ivpu_device *vdev, int irq) +static bool ivpu_hw_40xx_irqb_handler(struct ivpu_device *vdev, int irq) { bool schedule_recovery = false; u32 status = REGB_RD32(VPU_40XX_BUTTRESS_INTERRUPT_STAT) & BUTTRESS_IRQ_MASK; - if (status == 0) - return IRQ_NONE; + if (!status) + return false; if (REG_TEST_FLD(VPU_40XX_BUTTRESS_INTERRUPT_STAT, FREQ_CHANGE, status)) ivpu_dbg(vdev, IRQ, "FREQ_CHANGE"); @@ -1114,28 +1154,29 @@ static irqreturn_t ivpu_hw_40xx_irqb_handler(struct ivpu_device *vdev, int irq) REGB_WR32(VPU_40XX_BUTTRESS_INTERRUPT_STAT, status); if (schedule_recovery) - ivpu_pm_schedule_recovery(vdev); + ivpu_pm_trigger_recovery(vdev, "Buttress IRQ"); - return IRQ_HANDLED; + return true; } static irqreturn_t ivpu_hw_40xx_irq_handler(int irq, void *ptr) { + bool irqv_handled, irqb_handled, wake_thread = false; struct ivpu_device *vdev = ptr; - irqreturn_t ret = IRQ_NONE; REGB_WR32(VPU_40XX_BUTTRESS_GLOBAL_INT_MASK, 0x1); - ret |= ivpu_hw_40xx_irqv_handler(vdev, irq); - ret |= ivpu_hw_40xx_irqb_handler(vdev, irq); + irqv_handled = ivpu_hw_40xx_irqv_handler(vdev, irq, &wake_thread); + irqb_handled = ivpu_hw_40xx_irqb_handler(vdev, irq); /* Re-enable global interrupts to re-trigger MSI for pending interrupts */ REGB_WR32(VPU_40XX_BUTTRESS_GLOBAL_INT_MASK, 0x0); - if (ret & IRQ_WAKE_THREAD) + if (wake_thread) return IRQ_WAKE_THREAD; - - return ret; + if (irqv_handled || irqb_handled) + return IRQ_HANDLED; + return IRQ_NONE; } static void ivpu_hw_40xx_diagnose_failure(struct ivpu_device *vdev) @@ -1185,11 +1226,14 @@ const struct ivpu_hw_ops ivpu_hw_40xx_ops = { .info_init = ivpu_hw_40xx_info_init, .power_up = ivpu_hw_40xx_power_up, .is_idle = ivpu_hw_40xx_is_idle, + .wait_for_idle = ivpu_hw_40xx_wait_for_idle, .power_down = ivpu_hw_40xx_power_down, .reset = ivpu_hw_40xx_reset, .boot_fw = ivpu_hw_40xx_boot_fw, .wdt_disable = ivpu_hw_40xx_wdt_disable, .diagnose_failure = ivpu_hw_40xx_diagnose_failure, + .profiling_freq_get = ivpu_hw_40xx_profiling_freq_get, + .profiling_freq_drive = ivpu_hw_40xx_profiling_freq_drive, .reg_pll_freq_get = ivpu_hw_40xx_reg_pll_freq_get, .reg_telemetry_offset_get = ivpu_hw_40xx_reg_telemetry_offset_get, .reg_telemetry_size_get = ivpu_hw_40xx_reg_telemetry_size_get, diff --git a/drivers/accel/ivpu/ivpu_ipc.c b/drivers/accel/ivpu/ivpu_ipc.c index a4ca40b184d4e6..fa66c39b57ecaa 100644 --- a/drivers/accel/ivpu/ivpu_ipc.c +++ b/drivers/accel/ivpu/ivpu_ipc.c @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include "ivpu_drv.h" @@ -17,19 +17,12 @@ #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) { @@ -139,8 +132,49 @@ 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) +static void +ivpu_ipc_rx_msg_add(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; + + lockdep_assert_held(&ipc->cons_lock); + lockdep_assert_irqs_disabled(); + + 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; + rx_msg->callback = cons->rx_callback; + + if (rx_msg->callback) { + list_add_tail(&rx_msg->link, &ipc->cb_msg_list); + } else { + spin_lock(&cons->rx_lock); + list_add_tail(&rx_msg->link, &cons->rx_msg_list); + spin_unlock(&cons->rx_lock); + wake_up(&cons->rx_msg_wq); + } +} + +static void +ivpu_ipc_rx_msg_del(struct ivpu_device *vdev, struct ivpu_ipc_rx_msg *rx_msg) +{ + list_del(&rx_msg->link); + ivpu_ipc_rx_mark_free(vdev, rx_msg->ipc_hdr, rx_msg->jsm_msg); + atomic_dec(&vdev->ipc->rx_msg_count); + kfree(rx_msg); +} + +void ivpu_ipc_consumer_add(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, + u32 channel, ivpu_ipc_rx_callback_t rx_callback) { struct ivpu_ipc_info *ipc = vdev->ipc; @@ -148,13 +182,15 @@ ivpu_ipc_consumer_add(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, cons->channel = channel; cons->tx_vpu_addr = 0; cons->request_id = 0; - spin_lock_init(&cons->rx_msg_lock); + cons->aborted = false; + cons->rx_callback = rx_callback; + spin_lock_init(&cons->rx_lock); INIT_LIST_HEAD(&cons->rx_msg_list); init_waitqueue_head(&cons->rx_msg_wq); - spin_lock_irq(&ipc->cons_list_lock); + spin_lock_irq(&ipc->cons_lock); list_add_tail(&cons->link, &ipc->cons_list); - spin_unlock_irq(&ipc->cons_list_lock); + spin_unlock_irq(&ipc->cons_lock); } void ivpu_ipc_consumer_del(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons) @@ -162,18 +198,14 @@ void ivpu_ipc_consumer_del(struct ivpu_device *vdev, struct ivpu_ipc_consumer *c struct ivpu_ipc_info *ipc = vdev->ipc; struct ivpu_ipc_rx_msg *rx_msg, *r; - spin_lock_irq(&ipc->cons_list_lock); + spin_lock_irq(&ipc->cons_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); + spin_unlock_irq(&ipc->cons_lock); + + spin_lock_irq(&cons->rx_lock); + list_for_each_entry_safe(rx_msg, r, &cons->rx_msg_list, link) + ivpu_ipc_rx_msg_del(vdev, rx_msg); + spin_unlock_irq(&cons->rx_lock); ivpu_ipc_tx_release(vdev, cons->tx_vpu_addr); } @@ -202,52 +234,61 @@ unlock: return ret; } +static bool ivpu_ipc_rx_need_wakeup(struct ivpu_ipc_consumer *cons) +{ + bool ret; + + spin_lock_irq(&cons->rx_lock); + ret = !list_empty(&cons->rx_msg_list) || cons->aborted; + spin_unlock_irq(&cons->rx_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 vpu_jsm_msg *jsm_msg, unsigned long timeout_ms) { - struct ivpu_ipc_info *ipc = vdev->ipc; struct ivpu_ipc_rx_msg *rx_msg; int wait_ret, ret = 0; + if (drm_WARN_ONCE(&vdev->drm, cons->rx_callback, "Consumer works only in async mode\n")) + return -EINVAL; + wait_ret = wait_event_timeout(cons->rx_msg_wq, - (IS_KTHREAD() && kthread_should_stop()) || - !list_empty(&cons->rx_msg_list), + ivpu_ipc_rx_need_wakeup(cons), msecs_to_jiffies(timeout_ms)); - if (IS_KTHREAD() && kthread_should_stop()) - return -EINTR; - if (wait_ret == 0) return -ETIMEDOUT; - spin_lock_irq(&cons->rx_msg_lock); + spin_lock_irq(&cons->rx_lock); + if (cons->aborted) { + spin_unlock_irq(&cons->rx_lock); + return -ECANCELED; + } 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); + spin_unlock_irq(&cons->rx_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)); + u32 size = min_t(int, rx_msg->ipc_hdr->data_size, sizeof(*jsm_msg)); 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); + if (jsm_msg) + memcpy(jsm_msg, 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); - + ivpu_ipc_rx_msg_del(vdev, rx_msg); + spin_unlock_irq(&cons->rx_lock); return ret; } @@ -260,7 +301,7 @@ ivpu_ipc_send_receive_internal(struct ivpu_device *vdev, struct vpu_jsm_msg *req struct ivpu_ipc_consumer cons; int ret; - ivpu_ipc_consumer_add(vdev, &cons, channel); + ivpu_ipc_consumer_add(vdev, &cons, channel, NULL); ret = ivpu_ipc_send(vdev, &cons, req); if (ret) { @@ -285,33 +326,41 @@ consumer_del: 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) +int ivpu_ipc_send_receive_active(struct ivpu_device *vdev, struct vpu_jsm_msg *req, + enum vpu_ipc_msg_type expected_resp, 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; + drm_WARN_ON(&vdev->drm, pm_runtime_status_suspended(vdev->drm.dev)); - ret = ivpu_ipc_send_receive_internal(vdev, req, expected_resp_type, resp, - channel, timeout_ms); + ret = ivpu_ipc_send_receive_internal(vdev, req, expected_resp, resp, channel, timeout_ms); if (ret != -ETIMEDOUT) - goto rpm_put; + return ret; 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); - } + if (hb_ret == -ETIMEDOUT) + ivpu_pm_trigger_recovery(vdev, "IPC timeout"); + + return ret; +} + +int ivpu_ipc_send_receive(struct ivpu_device *vdev, struct vpu_jsm_msg *req, + enum vpu_ipc_msg_type expected_resp, struct vpu_jsm_msg *resp, + u32 channel, unsigned long timeout_ms) +{ + int ret; + + ret = ivpu_rpm_get(vdev); + if (ret < 0) + return ret; + + ret = ivpu_ipc_send_receive_active(vdev, req, expected_resp, resp, channel, timeout_ms); -rpm_put: ivpu_rpm_put(vdev); return ret; } @@ -329,35 +378,7 @@ ivpu_ipc_match_consumer(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons 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) +void ivpu_ipc_irq_handler(struct ivpu_device *vdev, bool *wake_thread) { struct ivpu_ipc_info *ipc = vdev->ipc; struct ivpu_ipc_consumer *cons; @@ -375,7 +396,7 @@ int ivpu_ipc_irq_handler(struct ivpu_device *vdev) vpu_addr = ivpu_hw_reg_ipc_rx_addr_get(vdev); if (vpu_addr == REG_IO_ERROR) { ivpu_err_ratelimited(vdev, "Failed to read IPC rx addr register\n"); - return -EIO; + return; } ipc_hdr = ivpu_to_cpu_addr(ipc->mem_rx, vpu_addr); @@ -405,15 +426,15 @@ int ivpu_ipc_irq_handler(struct ivpu_device *vdev) } dispatched = false; - spin_lock_irqsave(&ipc->cons_list_lock, flags); + spin_lock_irqsave(&ipc->cons_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); + ivpu_ipc_rx_msg_add(vdev, cons, ipc_hdr, jsm_msg); dispatched = true; break; } } - spin_unlock_irqrestore(&ipc->cons_list_lock, flags); + spin_unlock_irqrestore(&ipc->cons_lock, flags); if (!dispatched) { ivpu_dbg(vdev, IPC, "IPC RX msg 0x%x dropped (no consumer)\n", vpu_addr); @@ -421,7 +442,28 @@ int ivpu_ipc_irq_handler(struct ivpu_device *vdev) } } - return 0; + if (wake_thread) + *wake_thread = !list_empty(&ipc->cb_msg_list); +} + +irqreturn_t ivpu_ipc_irq_thread_handler(struct ivpu_device *vdev) +{ + struct ivpu_ipc_info *ipc = vdev->ipc; + struct ivpu_ipc_rx_msg *rx_msg, *r; + struct list_head cb_msg_list; + + INIT_LIST_HEAD(&cb_msg_list); + + spin_lock_irq(&ipc->cons_lock); + list_splice_tail_init(&ipc->cb_msg_list, &cb_msg_list); + spin_unlock_irq(&ipc->cons_lock); + + list_for_each_entry_safe(rx_msg, r, &cb_msg_list, link) { + rx_msg->callback(vdev, rx_msg->ipc_hdr, rx_msg->jsm_msg); + ivpu_ipc_rx_msg_del(vdev, rx_msg); + } + + return IRQ_HANDLED; } int ivpu_ipc_init(struct ivpu_device *vdev) @@ -456,10 +498,10 @@ int ivpu_ipc_init(struct ivpu_device *vdev) goto err_free_rx; } + spin_lock_init(&ipc->cons_lock); INIT_LIST_HEAD(&ipc->cons_list); - spin_lock_init(&ipc->cons_list_lock); + INIT_LIST_HEAD(&ipc->cb_msg_list); drmm_mutex_init(&vdev->drm, &ipc->lock); - ivpu_ipc_reset(vdev); return 0; @@ -472,6 +514,13 @@ err_free_tx: void ivpu_ipc_fini(struct ivpu_device *vdev) { + struct ivpu_ipc_info *ipc = vdev->ipc; + + drm_WARN_ON(&vdev->drm, ipc->on); + drm_WARN_ON(&vdev->drm, !list_empty(&ipc->cons_list)); + drm_WARN_ON(&vdev->drm, !list_empty(&ipc->cb_msg_list)); + drm_WARN_ON(&vdev->drm, atomic_read(&ipc->rx_msg_count) > 0); + ivpu_ipc_mem_fini(vdev); } @@ -488,16 +537,27 @@ void ivpu_ipc_disable(struct ivpu_device *vdev) { struct ivpu_ipc_info *ipc = vdev->ipc; struct ivpu_ipc_consumer *cons, *c; - unsigned long flags; + struct ivpu_ipc_rx_msg *rx_msg, *r; + + drm_WARN_ON(&vdev->drm, !list_empty(&ipc->cb_msg_list)); 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) + spin_lock_irq(&ipc->cons_lock); + list_for_each_entry_safe(cons, c, &ipc->cons_list, link) { + spin_lock(&cons->rx_lock); + if (!cons->rx_callback) + cons->aborted = true; + list_for_each_entry_safe(rx_msg, r, &cons->rx_msg_list, link) + ivpu_ipc_rx_msg_del(vdev, rx_msg); + spin_unlock(&cons->rx_lock); wake_up(&cons->rx_msg_wq); - spin_unlock_irqrestore(&ipc->cons_list_lock, flags); + } + spin_unlock_irq(&ipc->cons_lock); + + drm_WARN_ON(&vdev->drm, atomic_read(&ipc->rx_msg_count) > 0); } void ivpu_ipc_reset(struct ivpu_device *vdev) @@ -505,6 +565,7 @@ void ivpu_ipc_reset(struct ivpu_device *vdev) struct ivpu_ipc_info *ipc = vdev->ipc; mutex_lock(&ipc->lock); + drm_WARN_ON(&vdev->drm, ipc->on); memset(ivpu_bo_vaddr(ipc->mem_tx), 0, ivpu_bo_size(ipc->mem_tx)); memset(ivpu_bo_vaddr(ipc->mem_rx), 0, ivpu_bo_size(ipc->mem_rx)); diff --git a/drivers/accel/ivpu/ivpu_ipc.h b/drivers/accel/ivpu/ivpu_ipc.h index 68f5b6668e00b9..40ca3cc4e61f73 100644 --- a/drivers/accel/ivpu/ivpu_ipc.h +++ b/drivers/accel/ivpu/ivpu_ipc.h @@ -42,13 +42,26 @@ struct ivpu_ipc_hdr { u8 status; } __packed __aligned(IVPU_IPC_ALIGNMENT); +typedef void (*ivpu_ipc_rx_callback_t)(struct ivpu_device *vdev, + struct ivpu_ipc_hdr *ipc_hdr, + struct vpu_jsm_msg *jsm_msg); + +struct ivpu_ipc_rx_msg { + struct list_head link; + struct ivpu_ipc_hdr *ipc_hdr; + struct vpu_jsm_msg *jsm_msg; + ivpu_ipc_rx_callback_t callback; +}; + struct ivpu_ipc_consumer { struct list_head link; u32 channel; u32 tx_vpu_addr; u32 request_id; + bool aborted; + ivpu_ipc_rx_callback_t rx_callback; - spinlock_t rx_msg_lock; /* Protects rx_msg_list */ + spinlock_t rx_lock; /* Protects rx_msg_list and aborted */ struct list_head rx_msg_list; wait_queue_head_t rx_msg_wq; }; @@ -60,8 +73,9 @@ struct ivpu_ipc_info { atomic_t rx_msg_count; - spinlock_t cons_list_lock; /* Protects cons_list */ + spinlock_t cons_lock; /* Protects cons_list and cb_msg_list */ struct list_head cons_list; + struct list_head cb_msg_list; atomic_t request_id; struct mutex lock; /* Lock on status */ @@ -75,19 +89,22 @@ 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_irq_handler(struct ivpu_device *vdev, bool *wake_thread); +irqreturn_t ivpu_ipc_irq_thread_handler(struct ivpu_device *vdev); void ivpu_ipc_consumer_add(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, - u32 channel); + u32 channel, ivpu_ipc_rx_callback_t callback); 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, + struct ivpu_ipc_hdr *ipc_buf, struct vpu_jsm_msg *jsm_msg, unsigned long timeout_ms); +int ivpu_ipc_send_receive_active(struct ivpu_device *vdev, struct vpu_jsm_msg *req, + enum vpu_ipc_msg_type expected_resp, struct vpu_jsm_msg *resp, + u32 channel, 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); + enum vpu_ipc_msg_type expected_resp, 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 index 8983e3a4fdf91a..0440bee3ecafd5 100644 --- a/drivers/accel/ivpu/ivpu_job.c +++ b/drivers/accel/ivpu/ivpu_job.c @@ -7,7 +7,6 @@ #include #include -#include #include #include #include @@ -24,10 +23,6 @@ #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); @@ -117,22 +112,20 @@ static void ivpu_cmdq_release_locked(struct ivpu_file_priv *file_priv, u16 engin } } -void ivpu_cmdq_release_all(struct ivpu_file_priv *file_priv) +void ivpu_cmdq_release_all_locked(struct ivpu_file_priv *file_priv) { int i; - mutex_lock(&file_priv->lock); + lockdep_assert_held(&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 + * and FW loses 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) @@ -166,15 +159,13 @@ 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; + mutex_lock(&vdev->context_list_lock); + xa_for_each(&vdev->context_xa, ctx_id, file_priv) ivpu_cmdq_reset_all(file_priv); - ivpu_file_priv_put(&file_priv); - } + mutex_unlock(&vdev->context_list_lock); + } static int ivpu_cmdq_push_job(struct ivpu_cmdq *cmdq, struct ivpu_job *job) @@ -196,6 +187,8 @@ static int ivpu_cmdq_push_job(struct ivpu_cmdq *cmdq, struct ivpu_job *job) entry->batch_buf_addr = job->cmd_buf_vpu_addr; entry->job_id = job->job_id; entry->flags = 0; + if (unlikely(ivpu_test_mode & IVPU_TEST_MODE_NULL_SUBMISSION)) + entry->flags = VPU_JOB_FLAGS_NULL_SUBMISSION_MASK; wmb(); /* Ensure that tail is updated after filling entry */ header->tail = next_entry; wmb(); /* Flush WC buffer for jobq header */ @@ -246,60 +239,32 @@ static struct dma_fence *ivpu_fence_create(struct ivpu_device *vdev) 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) +static void ivpu_job_destroy(struct ivpu_job *job) { - struct ivpu_job *job = container_of(ref, struct ivpu_job, ref); struct ivpu_device *vdev = job->vdev; u32 i; + ivpu_dbg(vdev, JOB, "Job destroyed: id %3u ctx %2d engine %d", + job->job_id, job->file_priv->ctx.id, job->engine_idx); + for (i = 0; i < job->bo_count; i++) if (job->bos[i]) - drm_gem_object_put(&job->bos[i]->base); + drm_gem_object_put(&job->bos[i]->base.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) +ivpu_job_create(struct ivpu_file_priv *file_priv, u32 engine_idx, u32 bo_count) { struct ivpu_device *vdev = file_priv->vdev; struct ivpu_job *job; - int ret; - - ret = ivpu_rpm_get(vdev); - if (ret < 0) - return NULL; job = kzalloc(struct_size(job, bos, bo_count), GFP_KERNEL); if (!job) - goto err_rpm_put; - - kref_init(&job->ref); + return NULL; job->vdev = vdev; job->engine_idx = engine_idx; @@ -313,17 +278,14 @@ ivpu_create_job(struct ivpu_file_priv *file_priv, u32 engine_idx, u32 bo_count) 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) +static int ivpu_job_signal_and_destroy(struct ivpu_device *vdev, u32 job_id, u32 job_status) { struct ivpu_job *job; @@ -340,21 +302,11 @@ static int ivpu_job_done(struct ivpu_device *vdev, u32 job_id, u32 job_status) 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; + ivpu_job_destroy(job); + ivpu_stop_job_timeout_detection(vdev); - 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); + ivpu_rpm_put(vdev); + return 0; } void ivpu_jobs_abort_all(struct ivpu_device *vdev) @@ -363,10 +315,10 @@ void ivpu_jobs_abort_all(struct ivpu_device *vdev) unsigned long id; xa_for_each(&vdev->submitted_jobs_xa, id, job) - ivpu_job_done(vdev, id, VPU_JSM_STATUS_ABORTED); + ivpu_job_signal_and_destroy(vdev, id, VPU_JSM_STATUS_ABORTED); } -static int ivpu_direct_job_submission(struct ivpu_job *job) +static int ivpu_job_submit(struct ivpu_job *job) { struct ivpu_file_priv *file_priv = job->file_priv; struct ivpu_device *vdev = job->vdev; @@ -374,51 +326,65 @@ static int ivpu_direct_job_submission(struct ivpu_job *job) struct ivpu_cmdq *cmdq; int ret; + ret = ivpu_rpm_get(vdev); + if (ret < 0) + return 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); + ivpu_warn_ratelimited(vdev, "Failed get job queue, ctx %d engine %d\n", + file_priv->ctx.id, job->engine_idx); ret = -EINVAL; - goto err_unlock; + goto err_unlock_file_priv; } 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); + xa_lock(&vdev->submitted_jobs_xa); + 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; + ivpu_dbg(vdev, JOB, "Too many active jobs in ctx %d\n", + file_priv->ctx.id); + ret = -EBUSY; + goto err_unlock_submitted_jobs_xa; } ret = ivpu_cmdq_push_job(cmdq, job); if (ret) - goto err_xa_erase; + goto err_erase_xa; - 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); + ivpu_start_job_timeout_detection(vdev); - if (ivpu_test_mode == IVPU_TEST_MODE_NULL_HW) { - ivpu_job_done(vdev, job->job_id, VPU_JSM_STATUS_SUCCESS); + if (unlikely(ivpu_test_mode & IVPU_TEST_MODE_NULL_HW)) { cmdq->jobq->header.head = cmdq->jobq->header.tail; wmb(); /* Flush WC buffer for jobq header */ } else { ivpu_cmdq_ring_db(vdev, cmdq); } + ivpu_dbg(vdev, JOB, "Job submitted: id %3u ctx %2d engine %d addr 0x%llx next %d\n", + job->job_id, file_priv->ctx.id, job->engine_idx, + job->cmd_buf_vpu_addr, cmdq->jobq->header.tail); + + xa_unlock(&vdev->submitted_jobs_xa); + mutex_unlock(&file_priv->lock); + + if (unlikely(ivpu_test_mode & IVPU_TEST_MODE_NULL_HW)) + ivpu_job_signal_and_destroy(vdev, job->job_id, VPU_JSM_STATUS_SUCCESS); + return 0; -err_xa_erase: - xa_erase(&vdev->submitted_jobs_xa, job->job_id); -err_job_put: - job_put(job); -err_unlock: +err_erase_xa: + __xa_erase(&vdev->submitted_jobs_xa, job->job_id); +err_unlock_submitted_jobs_xa: + xa_unlock(&vdev->submitted_jobs_xa); +err_unlock_file_priv: mutex_unlock(&file_priv->lock); + ivpu_rpm_put(vdev); return ret; } @@ -448,7 +414,7 @@ ivpu_job_prepare_bos_for_submit(struct drm_file *file, struct ivpu_job *job, u32 } bo = job->bos[CMD_BUF_IDX]; - if (!dma_resv_test_signaled(bo->base.resv, DMA_RESV_USAGE_READ)) { + if (!dma_resv_test_signaled(bo->base.base.resv, DMA_RESV_USAGE_READ)) { ivpu_warn(vdev, "Buffer is already in use\n"); return -EBUSY; } @@ -468,7 +434,7 @@ ivpu_job_prepare_bos_for_submit(struct drm_file *file, struct ivpu_job *job, u32 } for (i = 0; i < buf_count; i++) { - ret = dma_resv_reserve_fences(job->bos[i]->base.resv, 1); + ret = dma_resv_reserve_fences(job->bos[i]->base.base.resv, 1); if (ret) { ivpu_warn(vdev, "Failed to reserve fences: %d\n", ret); goto unlock_reservations; @@ -477,7 +443,7 @@ ivpu_job_prepare_bos_for_submit(struct drm_file *file, struct ivpu_job *job, u32 for (i = 0; i < buf_count; i++) { usage = (i == CMD_BUF_IDX) ? DMA_RESV_USAGE_WRITE : DMA_RESV_USAGE_BOOKKEEP; - dma_resv_add_fence(job->bos[i]->base.resv, job->done_fence, usage); + dma_resv_add_fence(job->bos[i]->base.base.resv, job->done_fence, usage); } unlock_reservations: @@ -500,6 +466,9 @@ int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file) if (params->engine > DRM_IVPU_ENGINE_COPY) return -EINVAL; + if (params->priority > DRM_IVPU_JOB_PRIORITY_REALTIME) + return -EINVAL; + if (params->buffer_count == 0 || params->buffer_count > JOB_MAX_BUFFER_COUNT) return -EINVAL; @@ -521,102 +490,82 @@ int ivpu_submit_ioctl(struct drm_device *dev, void *data, struct drm_file *file) params->buffer_count * sizeof(u32)); if (ret) { ret = -EFAULT; - goto free_handles; + goto err_free_handles; } if (!drm_dev_enter(&vdev->drm, &idx)) { ret = -ENODEV; - goto free_handles; + goto err_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); + job = ivpu_job_create(file_priv, params->engine, params->buffer_count); if (!job) { ivpu_err(vdev, "Failed to create job\n"); ret = -ENOMEM; - goto dev_exit; + goto err_exit_dev; } 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; + ivpu_err(vdev, "Failed to prepare job: %d\n", ret); + goto err_destroy_job; } - 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); - } + down_read(&vdev->pm->reset_lock); + ret = ivpu_job_submit(job); + up_read(&vdev->pm->reset_lock); + if (ret) + goto err_signal_fence; -job_put: - job_put(job); -dev_exit: drm_dev_exit(idx); -free_handles: kfree(buf_handles); + return ret; +err_signal_fence: + dma_fence_signal(job->done_fence); +err_destroy_job: + ivpu_job_destroy(job); +err_exit_dev: + drm_dev_exit(idx); +err_free_handles: + kfree(buf_handles); return ret; } -static int ivpu_job_done_thread(void *arg) +static void +ivpu_job_done_callback(struct ivpu_device *vdev, struct ivpu_ipc_hdr *ipc_hdr, + struct vpu_jsm_msg *jsm_msg) { - 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; + struct vpu_ipc_msg_payload_job_done *payload; 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); - } - } + if (!jsm_msg) { + ivpu_err(vdev, "IPC message has no JSM payload\n"); + return; } - ivpu_ipc_consumer_del(vdev, &cons); - - ivpu_jobs_abort_all(vdev); + if (jsm_msg->result != VPU_JSM_STATUS_SUCCESS) { + ivpu_err(vdev, "Invalid JSM message result: %d\n", jsm_msg->result); + return; + } - ivpu_dbg(vdev, JOB, "Stopped %s\n", __func__); - return 0; + payload = (struct vpu_ipc_msg_payload_job_done *)&jsm_msg->payload; + ret = ivpu_job_signal_and_destroy(vdev, payload->job_id, payload->job_status); + if (!ret && !xa_empty(&vdev->submitted_jobs_xa)) + ivpu_start_job_timeout_detection(vdev); } -int ivpu_job_done_thread_init(struct ivpu_device *vdev) +void ivpu_job_done_consumer_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; + ivpu_ipc_consumer_add(vdev, &vdev->job_done_consumer, + VPU_IPC_CHAN_JOB_RET, ivpu_job_done_callback); } -void ivpu_job_done_thread_fini(struct ivpu_device *vdev) +void ivpu_job_done_consumer_fini(struct ivpu_device *vdev) { - kthread_stop_put(vdev->job_done_thread); + ivpu_ipc_consumer_del(vdev, &vdev->job_done_consumer); } diff --git a/drivers/accel/ivpu/ivpu_job.h b/drivers/accel/ivpu/ivpu_job.h index 5514c2d8a6096d..ca4984071cc76b 100644 --- a/drivers/accel/ivpu/ivpu_job.h +++ b/drivers/accel/ivpu/ivpu_job.h @@ -43,7 +43,6 @@ struct ivpu_cmdq { 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; @@ -56,11 +55,11 @@ struct ivpu_job { 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_release_all_locked(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_job_done_consumer_init(struct ivpu_device *vdev); +void ivpu_job_done_consumer_fini(struct ivpu_device *vdev); void ivpu_jobs_abort_all(struct ivpu_device *vdev); diff --git a/drivers/accel/ivpu/ivpu_jsm_msg.c b/drivers/accel/ivpu/ivpu_jsm_msg.c index 0c2fe7142024ce..8cea0dd731b915 100644 --- a/drivers/accel/ivpu/ivpu_jsm_msg.c +++ b/drivers/accel/ivpu/ivpu_jsm_msg.c @@ -4,6 +4,7 @@ */ #include "ivpu_drv.h" +#include "ivpu_hw.h" #include "ivpu_ipc.h" #include "ivpu_jsm_msg.h" @@ -36,6 +37,17 @@ const char *ivpu_jsm_msg_type_to_str(enum vpu_ipc_msg_type type) IVPU_CASE_TO_STR(VPU_JSM_MSG_DESTROY_CMD_QUEUE); IVPU_CASE_TO_STR(VPU_JSM_MSG_SET_CONTEXT_SCHED_PROPERTIES); IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_REGISTER_DB); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_RESUME_CMDQ); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_SUSPEND_CMDQ); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_RESUME_CMDQ_RSP); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_SUSPEND_CMDQ_DONE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_SET_SCHEDULING_LOG); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_SET_SCHEDULING_LOG_RSP); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_SCHEDULING_LOG_NOTIFICATION); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_ENGINE_RESUME); + IVPU_CASE_TO_STR(VPU_JSM_MSG_HWS_RESUME_ENGINE_DONE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_STATE_DUMP); + IVPU_CASE_TO_STR(VPU_JSM_MSG_STATE_DUMP_RSP); IVPU_CASE_TO_STR(VPU_JSM_MSG_BLOB_DEINIT); IVPU_CASE_TO_STR(VPU_JSM_MSG_DYNDBG_CONTROL); IVPU_CASE_TO_STR(VPU_JSM_MSG_JOB_DONE); @@ -65,6 +77,12 @@ const char *ivpu_jsm_msg_type_to_str(enum vpu_ipc_msg_type type) IVPU_CASE_TO_STR(VPU_JSM_MSG_SET_CONTEXT_SCHED_PROPERTIES_RSP); IVPU_CASE_TO_STR(VPU_JSM_MSG_BLOB_DEINIT_DONE); IVPU_CASE_TO_STR(VPU_JSM_MSG_DYNDBG_CONTROL_RSP); + IVPU_CASE_TO_STR(VPU_JSM_MSG_PWR_D0I3_ENTER); + IVPU_CASE_TO_STR(VPU_JSM_MSG_PWR_D0I3_ENTER_DONE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_DCT_ENABLE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_DCT_ENABLE_DONE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_DCT_DISABLE); + IVPU_CASE_TO_STR(VPU_JSM_MSG_DCT_DISABLE_DONE); } #undef IVPU_CASE_TO_STR @@ -243,3 +261,23 @@ int ivpu_jsm_context_release(struct ivpu_device *vdev, u32 host_ssid) return ivpu_ipc_send_receive(vdev, &req, VPU_JSM_MSG_SSID_RELEASE_DONE, &resp, VPU_IPC_CHAN_ASYNC_CMD, vdev->timeout.jsm); } + +int ivpu_jsm_pwr_d0i3_enter(struct ivpu_device *vdev) +{ + struct vpu_jsm_msg req = { .type = VPU_JSM_MSG_PWR_D0I3_ENTER }; + struct vpu_jsm_msg resp; + int ret; + + if (IVPU_WA(disable_d0i3_msg)) + return 0; + + req.payload.pwr_d0i3_enter.send_response = 1; + + ret = ivpu_ipc_send_receive_active(vdev, &req, VPU_JSM_MSG_PWR_D0I3_ENTER_DONE, + &resp, VPU_IPC_CHAN_GEN_CMD, + vdev->timeout.d0i3_entry_msg); + if (ret) + return ret; + + return ivpu_hw_wait_for_idle(vdev); +} diff --git a/drivers/accel/ivpu/ivpu_jsm_msg.h b/drivers/accel/ivpu/ivpu_jsm_msg.h index 66979a948c7c6f..ae75e5dbcc41d3 100644 --- a/drivers/accel/ivpu/ivpu_jsm_msg.h +++ b/drivers/accel/ivpu/ivpu_jsm_msg.h @@ -22,4 +22,5 @@ int ivpu_jsm_trace_get_capability(struct ivpu_device *vdev, u32 *trace_destinati 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); +int ivpu_jsm_pwr_d0i3_enter(struct ivpu_device *vdev); #endif diff --git a/drivers/accel/ivpu/ivpu_mmu.c b/drivers/accel/ivpu/ivpu_mmu.c index 2538c78fbebe28..9a3122ffce03c1 100644 --- a/drivers/accel/ivpu/ivpu_mmu.c +++ b/drivers/accel/ivpu/ivpu_mmu.c @@ -7,6 +7,7 @@ #include #include "ivpu_drv.h" +#include "ivpu_hw.h" #include "ivpu_hw_reg_io.h" #include "ivpu_mmu.h" #include "ivpu_mmu_context.h" @@ -230,7 +231,12 @@ (REG_FLD(IVPU_MMU_REG_GERROR, MSI_PRIQ_ABT)) | \ (REG_FLD(IVPU_MMU_REG_GERROR, MSI_ABT))) -static char *ivpu_mmu_event_to_str(u32 cmd) +#define IVPU_MMU_CERROR_NONE 0x0 +#define IVPU_MMU_CERROR_ILL 0x1 +#define IVPU_MMU_CERROR_ABT 0x2 +#define IVPU_MMU_CERROR_ATC_INV_SYNC 0x3 + +static const char *ivpu_mmu_event_to_str(u32 cmd) { switch (cmd) { case IVPU_MMU_EVT_F_UUT: @@ -276,6 +282,22 @@ static char *ivpu_mmu_event_to_str(u32 cmd) } } +static const char *ivpu_mmu_cmdq_err_to_str(u32 err) +{ + switch (err) { + case IVPU_MMU_CERROR_NONE: + return "No CMDQ Error"; + case IVPU_MMU_CERROR_ILL: + return "Illegal command"; + case IVPU_MMU_CERROR_ABT: + return "External abort on CMDQ read"; + case IVPU_MMU_CERROR_ATC_INV_SYNC: + return "Sync failed to complete ATS invalidation"; + default: + return "Unknown CMDQ Error"; + } +} + static void ivpu_mmu_config_check(struct ivpu_device *vdev) { u32 val_ref; @@ -479,10 +501,7 @@ static int ivpu_mmu_cmdq_sync(struct ivpu_device *vdev) 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); + val = FIELD_PREP(IVPU_MMU_CMD_OPCODE, CMD_SYNC); ret = ivpu_mmu_cmdq_cmd_write(vdev, "SYNC", val, 0); if (ret) @@ -492,8 +511,16 @@ static int ivpu_mmu_cmdq_sync(struct ivpu_device *vdev) REGV_WR32(IVPU_MMU_REG_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); + if (ret) { + u32 err; + + val = REGV_RD32(IVPU_MMU_REG_CMDQ_CONS); + err = REG_GET_FLD(IVPU_MMU_REG_CMDQ_CONS, ERR, val); + + ivpu_err(vdev, "Timed out waiting for MMU consumer: %d, error: %s\n", ret, + ivpu_mmu_cmdq_err_to_str(err)); + ivpu_hw_diagnose_failure(vdev); + } return ret; } @@ -750,9 +777,12 @@ int ivpu_mmu_init(struct ivpu_device *vdev) ivpu_dbg(vdev, MMU, "Init..\n"); - drmm_mutex_init(&vdev->drm, &mmu->lock); ivpu_mmu_config_check(vdev); + ret = drmm_mutex_init(&vdev->drm, &mmu->lock); + if (ret) + return ret; + ret = ivpu_mmu_structs_alloc(vdev); if (ret) return ret; @@ -857,7 +887,6 @@ static u32 *ivpu_mmu_get_event(struct ivpu_device *vdev) void ivpu_mmu_irq_evtq_handler(struct ivpu_device *vdev) { - bool schedule_recovery = false; u32 *event; u32 ssid; @@ -867,14 +896,21 @@ void ivpu_mmu_irq_evtq_handler(struct ivpu_device *vdev) 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 (ssid == IVPU_GLOBAL_CONTEXT_MMU_SSID) { + ivpu_pm_trigger_recovery(vdev, "MMU event"); + return; + } + + ivpu_mmu_user_context_mark_invalid(vdev, ssid); } +} - if (schedule_recovery) - ivpu_pm_schedule_recovery(vdev); +void ivpu_mmu_evtq_dump(struct ivpu_device *vdev) +{ + u32 *event; + + while ((event = ivpu_mmu_get_event(vdev)) != NULL) + ivpu_mmu_dump_event(vdev, event); } void ivpu_mmu_irq_gerr_handler(struct ivpu_device *vdev) diff --git a/drivers/accel/ivpu/ivpu_mmu.h b/drivers/accel/ivpu/ivpu_mmu.h index cb551126806baa..6fa35c24071062 100644 --- a/drivers/accel/ivpu/ivpu_mmu.h +++ b/drivers/accel/ivpu/ivpu_mmu.h @@ -46,5 +46,6 @@ 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); +void ivpu_mmu_evtq_dump(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 index c1050a2df95434..fe61612992364c 100644 --- a/drivers/accel/ivpu/ivpu_mmu_context.c +++ b/drivers/accel/ivpu/ivpu_mmu_context.c @@ -5,6 +5,9 @@ #include #include +#include + +#include #include "ivpu_drv.h" #include "ivpu_hw.h" @@ -39,12 +42,57 @@ #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 void *ivpu_pgtable_alloc_page(struct ivpu_device *vdev, dma_addr_t *dma) +{ + dma_addr_t dma_addr; + struct page *page; + void *cpu; + + page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO); + if (!page) + return NULL; + + set_pages_array_wc(&page, 1); + + dma_addr = dma_map_page(vdev->drm.dev, page, 0, PAGE_SIZE, DMA_BIDIRECTIONAL); + if (dma_mapping_error(vdev->drm.dev, dma_addr)) + goto err_free_page; + + cpu = vmap(&page, 1, VM_MAP, pgprot_writecombine(PAGE_KERNEL)); + if (!cpu) + goto err_dma_unmap_page; + + + *dma = dma_addr; + return cpu; + +err_dma_unmap_page: + dma_unmap_page(vdev->drm.dev, dma_addr, PAGE_SIZE, DMA_BIDIRECTIONAL); + +err_free_page: + put_page(page); + return NULL; +} + +static void ivpu_pgtable_free_page(struct ivpu_device *vdev, u64 *cpu_addr, dma_addr_t dma_addr) +{ + struct page *page; + + if (cpu_addr) { + page = vmalloc_to_page(cpu_addr); + vunmap(cpu_addr); + dma_unmap_page(vdev->drm.dev, dma_addr & ~IVPU_MMU_ENTRY_FLAGS_MASK, PAGE_SIZE, + DMA_BIDIRECTIONAL); + set_pages_array_wb(&page, 1); + put_page(page); + } +} + static int ivpu_mmu_pgtable_init(struct ivpu_device *vdev, struct ivpu_mmu_pgtable *pgtable) { dma_addr_t pgd_dma; - pgtable->pgd_dma_ptr = dma_alloc_coherent(vdev->drm.dev, IVPU_MMU_PGTABLE_SIZE, &pgd_dma, - GFP_KERNEL); + pgtable->pgd_dma_ptr = ivpu_pgtable_alloc_page(vdev, &pgd_dma); if (!pgtable->pgd_dma_ptr) return -ENOMEM; @@ -53,13 +101,6 @@ static int ivpu_mmu_pgtable_init(struct ivpu_device *vdev, struct ivpu_mmu_pgtab return 0; } -static void ivpu_mmu_pgtable_free(struct ivpu_device *vdev, u64 *cpu_addr, dma_addr_t dma_addr) -{ - if (cpu_addr) - dma_free_coherent(vdev->drm.dev, IVPU_MMU_PGTABLE_SIZE, cpu_addr, - dma_addr & ~IVPU_MMU_ENTRY_FLAGS_MASK); -} - static void ivpu_mmu_pgtables_free(struct ivpu_device *vdev, struct ivpu_mmu_pgtable *pgtable) { int pgd_idx, pud_idx, pmd_idx; @@ -84,19 +125,19 @@ static void ivpu_mmu_pgtables_free(struct ivpu_device *vdev, struct ivpu_mmu_pgt pte_dma_ptr = pgtable->pte_ptrs[pgd_idx][pud_idx][pmd_idx]; pte_dma = pgtable->pmd_ptrs[pgd_idx][pud_idx][pmd_idx]; - ivpu_mmu_pgtable_free(vdev, pte_dma_ptr, pte_dma); + ivpu_pgtable_free_page(vdev, pte_dma_ptr, pte_dma); } kfree(pgtable->pte_ptrs[pgd_idx][pud_idx]); - ivpu_mmu_pgtable_free(vdev, pmd_dma_ptr, pmd_dma); + ivpu_pgtable_free_page(vdev, pmd_dma_ptr, pmd_dma); } kfree(pgtable->pmd_ptrs[pgd_idx]); kfree(pgtable->pte_ptrs[pgd_idx]); - ivpu_mmu_pgtable_free(vdev, pud_dma_ptr, pud_dma); + ivpu_pgtable_free_page(vdev, pud_dma_ptr, pud_dma); } - ivpu_mmu_pgtable_free(vdev, pgtable->pgd_dma_ptr, pgtable->pgd_dma); + ivpu_pgtable_free_page(vdev, pgtable->pgd_dma_ptr, pgtable->pgd_dma); } static u64* @@ -108,7 +149,7 @@ ivpu_mmu_ensure_pud(struct ivpu_device *vdev, struct ivpu_mmu_pgtable *pgtable, if (pud_dma_ptr) return pud_dma_ptr; - pud_dma_ptr = dma_alloc_wc(vdev->drm.dev, IVPU_MMU_PGTABLE_SIZE, &pud_dma, GFP_KERNEL); + pud_dma_ptr = ivpu_pgtable_alloc_page(vdev, &pud_dma); if (!pud_dma_ptr) return NULL; @@ -131,7 +172,7 @@ err_free_pmd_ptrs: kfree(pgtable->pmd_ptrs[pgd_idx]); err_free_pud_dma_ptr: - ivpu_mmu_pgtable_free(vdev, pud_dma_ptr, pud_dma); + ivpu_pgtable_free_page(vdev, pud_dma_ptr, pud_dma); return NULL; } @@ -145,7 +186,7 @@ ivpu_mmu_ensure_pmd(struct ivpu_device *vdev, struct ivpu_mmu_pgtable *pgtable, if (pmd_dma_ptr) return pmd_dma_ptr; - pmd_dma_ptr = dma_alloc_wc(vdev->drm.dev, IVPU_MMU_PGTABLE_SIZE, &pmd_dma, GFP_KERNEL); + pmd_dma_ptr = ivpu_pgtable_alloc_page(vdev, &pmd_dma); if (!pmd_dma_ptr) return NULL; @@ -160,7 +201,7 @@ ivpu_mmu_ensure_pmd(struct ivpu_device *vdev, struct ivpu_mmu_pgtable *pgtable, return pmd_dma_ptr; err_free_pmd_dma_ptr: - ivpu_mmu_pgtable_free(vdev, pmd_dma_ptr, pmd_dma); + ivpu_pgtable_free_page(vdev, pmd_dma_ptr, pmd_dma); return NULL; } @@ -174,7 +215,7 @@ ivpu_mmu_ensure_pte(struct ivpu_device *vdev, struct ivpu_mmu_pgtable *pgtable, if (pte_dma_ptr) return pte_dma_ptr; - pte_dma_ptr = dma_alloc_wc(vdev->drm.dev, IVPU_MMU_PGTABLE_SIZE, &pte_dma, GFP_KERNEL); + pte_dma_ptr = ivpu_pgtable_alloc_page(vdev, &pte_dma); if (!pte_dma_ptr) return NULL; @@ -249,38 +290,6 @@ static void ivpu_mmu_context_unmap_page(struct ivpu_mmu_context *ctx, u64 vpu_ad ctx->pgtable.pte_ptrs[pgd_idx][pud_idx][pmd_idx][pte_idx] = IVPU_MMU_ENTRY_INVALID; } -static void -ivpu_mmu_context_flush_page_tables(struct ivpu_mmu_context *ctx, u64 vpu_addr, size_t size) -{ - struct ivpu_mmu_pgtable *pgtable = &ctx->pgtable; - u64 end_addr = vpu_addr + size; - - /* Align to PMD entry (2 MB) */ - vpu_addr &= ~(IVPU_MMU_PTE_MAP_SIZE - 1); - - while (vpu_addr < end_addr) { - int pgd_idx = FIELD_GET(IVPU_MMU_PGD_INDEX_MASK, vpu_addr); - u64 pud_end = (pgd_idx + 1) * (u64)IVPU_MMU_PUD_MAP_SIZE; - - while (vpu_addr < end_addr && vpu_addr < pud_end) { - int pud_idx = FIELD_GET(IVPU_MMU_PUD_INDEX_MASK, vpu_addr); - u64 pmd_end = (pud_idx + 1) * (u64)IVPU_MMU_PMD_MAP_SIZE; - - while (vpu_addr < end_addr && vpu_addr < pmd_end) { - int pmd_idx = FIELD_GET(IVPU_MMU_PMD_INDEX_MASK, vpu_addr); - - clflush_cache_range(pgtable->pte_ptrs[pgd_idx][pud_idx][pmd_idx], - IVPU_MMU_PGTABLE_SIZE); - vpu_addr += IVPU_MMU_PTE_MAP_SIZE; - } - clflush_cache_range(pgtable->pmd_ptrs[pgd_idx][pud_idx], - IVPU_MMU_PGTABLE_SIZE); - } - clflush_cache_range(pgtable->pud_ptrs[pgd_idx], IVPU_MMU_PGTABLE_SIZE); - } - clflush_cache_range(pgtable->pgd_dma_ptr, 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, u64 prot) @@ -327,6 +336,9 @@ ivpu_mmu_context_map_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, u64 prot; u64 i; + if (drm_WARN_ON(&vdev->drm, !ctx)) + return -EINVAL; + if (!IS_ALIGNED(vpu_addr, IVPU_MMU_PAGE_SIZE)) return -EINVAL; @@ -343,16 +355,21 @@ ivpu_mmu_context_map_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, dma_addr_t dma_addr = sg_dma_address(sg) - sg->offset; size_t size = sg_dma_len(sg) + sg->offset; + ivpu_dbg(vdev, MMU_MAP, "Map ctx: %u dma_addr: 0x%llx vpu_addr: 0x%llx size: %lu\n", + ctx->id, dma_addr, vpu_addr, size); + 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; } + /* Ensure page table modifications are flushed from wc buffers to memory */ + wmb(); + mutex_unlock(&ctx->lock); ret = ivpu_mmu_invalidate_tlb(vdev, ctx->id); @@ -369,19 +386,25 @@ ivpu_mmu_context_unmap_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ct int ret; u64 i; - if (!IS_ALIGNED(vpu_addr, IVPU_MMU_PAGE_SIZE)) - ivpu_warn(vdev, "Unaligned vpu_addr: 0x%llx\n", vpu_addr); + if (drm_WARN_ON(&vdev->drm, !ctx)) + return; mutex_lock(&ctx->lock); for_each_sgtable_dma_sg(sgt, sg, i) { + dma_addr_t dma_addr = sg_dma_address(sg) - sg->offset; size_t size = sg_dma_len(sg) + sg->offset; + ivpu_dbg(vdev, MMU_MAP, "Unmap ctx: %u dma_addr: 0x%llx vpu_addr: 0x%llx size: %lu\n", + ctx->id, dma_addr, vpu_addr, size); + ivpu_mmu_context_unmap_pages(ctx, vpu_addr, size); - ivpu_mmu_context_flush_page_tables(ctx, vpu_addr, size); vpu_addr += size; } + /* Ensure page table modifications are flushed from wc buffers to memory */ + wmb(); + mutex_unlock(&ctx->lock); ret = ivpu_mmu_invalidate_tlb(vdev, ctx->id); @@ -390,28 +413,34 @@ ivpu_mmu_context_unmap_sgt(struct ivpu_device *vdev, struct ivpu_mmu_context *ct } 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) +ivpu_mmu_context_insert_node(struct ivpu_mmu_context *ctx, const struct ivpu_addr_range *range, + u64 size, struct drm_mm_node *node) { - lockdep_assert_held(&ctx->lock); + int ret; + + WARN_ON(!range); + mutex_lock(&ctx->lock); if (!ivpu_disable_mmu_cont_pages && size >= IVPU_MMU_CONT_PAGES_SIZE) { - if (!drm_mm_insert_node_in_range(&ctx->mm, node, size, IVPU_MMU_CONT_PAGES_SIZE, 0, - range->start, range->end, DRM_MM_INSERT_BEST)) - return 0; + ret = drm_mm_insert_node_in_range(&ctx->mm, node, size, IVPU_MMU_CONT_PAGES_SIZE, 0, + range->start, range->end, DRM_MM_INSERT_BEST); + if (!ret) + goto unlock; } - return drm_mm_insert_node_in_range(&ctx->mm, node, size, IVPU_MMU_PAGE_SIZE, 0, - range->start, range->end, DRM_MM_INSERT_BEST); + ret = drm_mm_insert_node_in_range(&ctx->mm, node, size, IVPU_MMU_PAGE_SIZE, 0, + range->start, range->end, DRM_MM_INSERT_BEST); +unlock: + mutex_unlock(&ctx->lock); + return ret; } void -ivpu_mmu_context_remove_node_locked(struct ivpu_mmu_context *ctx, struct drm_mm_node *node) +ivpu_mmu_context_remove_node(struct ivpu_mmu_context *ctx, struct drm_mm_node *node) { - lockdep_assert_held(&ctx->lock); - + mutex_lock(&ctx->lock); drm_mm_remove_node(node); + mutex_unlock(&ctx->lock); } static int @@ -421,7 +450,6 @@ ivpu_mmu_context_init(struct ivpu_device *vdev, struct ivpu_mmu_context *ctx, u3 int ret; mutex_init(&ctx->lock); - INIT_LIST_HEAD(&ctx->bo_list); ret = ivpu_mmu_pgtable_init(vdev, &ctx->pgtable); if (ret) { diff --git a/drivers/accel/ivpu/ivpu_mmu_context.h b/drivers/accel/ivpu/ivpu_mmu_context.h index f15d8c630d8ad0..535db3a1fc74ff 100644 --- a/drivers/accel/ivpu/ivpu_mmu_context.h +++ b/drivers/accel/ivpu/ivpu_mmu_context.h @@ -23,10 +23,9 @@ struct ivpu_mmu_pgtable { }; struct ivpu_mmu_context { - struct mutex lock; /* protects: mm, pgtable, bo_list */ + struct mutex lock; /* Protects: mm, pgtable */ struct drm_mm mm; struct ivpu_mmu_pgtable pgtable; - struct list_head bo_list; u32 id; }; @@ -39,11 +38,9 @@ int ivpu_mmu_user_context_init(struct ivpu_device *vdev, struct ivpu_mmu_context 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_insert_node(struct ivpu_mmu_context *ctx, const struct ivpu_addr_range *range, + u64 size, struct drm_mm_node *node); +void ivpu_mmu_context_remove_node(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); diff --git a/drivers/accel/ivpu/ivpu_pm.c b/drivers/accel/ivpu/ivpu_pm.c index e9b16cbc26f49e..f501f27ebafdf6 100644 --- a/drivers/accel/ivpu/ivpu_pm.c +++ b/drivers/accel/ivpu/ivpu_pm.c @@ -13,8 +13,10 @@ #include "ivpu_drv.h" #include "ivpu_hw.h" #include "ivpu_fw.h" +#include "ivpu_fw_log.h" #include "ivpu_ipc.h" #include "ivpu_job.h" +#include "ivpu_jsm_msg.h" #include "ivpu_mmu.h" #include "ivpu_pm.h" @@ -22,6 +24,10 @@ 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"); +static unsigned long ivpu_tdr_timeout_ms; +module_param_named(tdr_timeout_ms, ivpu_tdr_timeout_ms, ulong, 0644); +MODULE_PARM_DESC(tdr_timeout_ms, "Timeout for device hang detection, in milliseconds, 0 - default"); + #define PM_RESCHEDULE_LIMIT 5 static void ivpu_pm_prepare_cold_boot(struct ivpu_device *vdev) @@ -69,27 +75,31 @@ retry: ret = ivpu_hw_power_up(vdev); if (ret) { ivpu_err(vdev, "Failed to power up HW: %d\n", ret); - return ret; + goto err_power_down; } ret = ivpu_mmu_enable(vdev); if (ret) { ivpu_err(vdev, "Failed to resume MMU: %d\n", ret); - ivpu_hw_power_down(vdev); - return ret; + goto err_power_down; } 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); - } + if (ret) + goto err_mmu_disable; + + return 0; + +err_mmu_disable: + ivpu_mmu_disable(vdev); +err_power_down: + ivpu_hw_power_down(vdev); + + if (!ivpu_fw_is_cold_boot(vdev)) { + ivpu_pm_prepare_cold_boot(vdev); + goto retry; + } else { + ivpu_err(vdev, "Failed to resume the FW: %d\n", ret); } return ret; @@ -102,6 +112,14 @@ static void ivpu_pm_recovery_work(struct work_struct *work) char *evt[2] = {"IVPU_PM_EVENT=IVPU_RECOVER", NULL}; int ret; + ivpu_err(vdev, "Recovering the VPU (reset #%d)\n", atomic_read(&vdev->pm->reset_counter)); + + ret = pm_runtime_resume_and_get(vdev->drm.dev); + if (ret) + ivpu_err(vdev, "Failed to resume VPU: %d\n", ret); + + ivpu_fw_log_dump(vdev); + retry: ret = pci_try_reset_function(to_pci_dev(vdev->drm.dev)); if (ret == -EAGAIN && !drm_dev_is_unplugged(&vdev->drm)) { @@ -113,11 +131,13 @@ retry: ivpu_err(vdev, "Failed to reset VPU: %d\n", ret); kobject_uevent_env(&vdev->drm.dev->kobj, KOBJ_CHANGE, evt); + pm_runtime_mark_last_busy(vdev->drm.dev); + pm_runtime_put_autosuspend(vdev->drm.dev); } -void ivpu_pm_schedule_recovery(struct ivpu_device *vdev) +void ivpu_pm_trigger_recovery(struct ivpu_device *vdev, const char *reason) { - struct ivpu_pm_info *pm = vdev->pm; + ivpu_err(vdev, "Recovery triggered by %s\n", reason); if (ivpu_disable_recovery) { ivpu_err(vdev, "Recovery not available when disable_recovery param is set\n"); @@ -129,13 +149,35 @@ void ivpu_pm_schedule_recovery(struct ivpu_device *vdev) 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); + /* Trigger recovery if it's not in progress */ + if (atomic_cmpxchg(&vdev->pm->reset_pending, 0, 1) == 0) { + ivpu_hw_diagnose_failure(vdev); + ivpu_hw_irq_disable(vdev); /* Disable IRQ early to protect from IRQ storm */ + queue_work(system_long_wq, &vdev->pm->recovery_work); } } +static void ivpu_job_timeout_work(struct work_struct *work) +{ + struct ivpu_pm_info *pm = container_of(work, struct ivpu_pm_info, job_timeout_work.work); + struct ivpu_device *vdev = pm->vdev; + + ivpu_pm_trigger_recovery(vdev, "TDR"); +} + +void ivpu_start_job_timeout_detection(struct ivpu_device *vdev) +{ + unsigned long timeout_ms = ivpu_tdr_timeout_ms ? ivpu_tdr_timeout_ms : vdev->timeout.tdr; + + /* No-op if already queued */ + queue_delayed_work(system_wq, &vdev->pm->job_timeout_work, msecs_to_jiffies(timeout_ms)); +} + +void ivpu_stop_job_timeout_detection(struct ivpu_device *vdev) +{ + cancel_delayed_work_sync(&vdev->pm->job_timeout_work); +} + int ivpu_pm_suspend_cb(struct device *dev) { struct drm_device *drm = dev_get_drvdata(dev); @@ -153,6 +195,8 @@ int ivpu_pm_suspend_cb(struct device *dev) } } + ivpu_jsm_pwr_d0i3_enter(vdev); + ivpu_suspend(vdev); ivpu_pm_prepare_warm_boot(vdev); @@ -188,8 +232,12 @@ 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); + bool hw_is_idle = true; int ret; + drm_WARN_ON(&vdev->drm, !xa_empty(&vdev->submitted_jobs_xa)); + drm_WARN_ON(&vdev->drm, work_pending(&vdev->pm->recovery_work)); + ivpu_dbg(vdev, PM, "Runtime suspend..\n"); if (!ivpu_hw_is_idle(vdev) && vdev->pm->suspend_reschedule_counter) { @@ -200,12 +248,18 @@ int ivpu_pm_runtime_suspend_cb(struct device *dev) return -EAGAIN; } + if (!vdev->pm->suspend_reschedule_counter) + hw_is_idle = false; + else if (ivpu_jsm_pwr_d0i3_enter(vdev)) + hw_is_idle = false; + 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"); + if (!hw_is_idle) { + ivpu_err(vdev, "VPU failed to enter idle, force suspended.\n"); + ivpu_fw_log_dump(vdev); ivpu_pm_prepare_cold_boot(vdev); } else { ivpu_pm_prepare_warm_boot(vdev); @@ -266,11 +320,12 @@ 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_inc(&vdev->pm->reset_counter); - atomic_set(&vdev->pm->in_reset, 1); + atomic_set(&vdev->pm->reset_pending, 1); + + pm_runtime_get_sync(vdev->drm.dev); + down_write(&vdev->pm->reset_lock); ivpu_prepare_for_reset(vdev); ivpu_hw_reset(vdev); ivpu_pm_prepare_cold_boot(vdev); @@ -287,9 +342,11 @@ void ivpu_pm_reset_done_cb(struct pci_dev *pdev) ret = ivpu_resume(vdev); if (ret) ivpu_err(vdev, "Failed to set RESUME state: %d\n", ret); - atomic_set(&vdev->pm->in_reset, 0); + up_write(&vdev->pm->reset_lock); + atomic_set(&vdev->pm->reset_pending, 0); ivpu_dbg(vdev, PM, "Post-reset done.\n"); + pm_runtime_mark_last_busy(vdev->drm.dev); pm_runtime_put_autosuspend(vdev->drm.dev); } @@ -302,8 +359,12 @@ void ivpu_pm_init(struct ivpu_device *vdev) pm->vdev = vdev; pm->suspend_reschedule_counter = PM_RESCHEDULE_LIMIT; - atomic_set(&pm->in_reset, 0); + init_rwsem(&pm->reset_lock); + atomic_set(&pm->reset_pending, 0); + atomic_set(&pm->reset_counter, 0); + INIT_WORK(&pm->recovery_work, ivpu_pm_recovery_work); + INIT_DELAYED_WORK(&pm->job_timeout_work, ivpu_job_timeout_work); if (ivpu_disable_recovery) delay = -1; @@ -318,6 +379,7 @@ void ivpu_pm_init(struct ivpu_device *vdev) void ivpu_pm_cancel_recovery(struct ivpu_device *vdev) { + drm_WARN_ON(&vdev->drm, delayed_work_pending(&vdev->pm->job_timeout_work)); cancel_work_sync(&vdev->pm->recovery_work); } diff --git a/drivers/accel/ivpu/ivpu_pm.h b/drivers/accel/ivpu/ivpu_pm.h index 044db150be0787..ec60fbeefefc65 100644 --- a/drivers/accel/ivpu/ivpu_pm.h +++ b/drivers/accel/ivpu/ivpu_pm.h @@ -6,15 +6,18 @@ #ifndef __IVPU_PM_H__ #define __IVPU_PM_H__ +#include #include struct ivpu_device; struct ivpu_pm_info { struct ivpu_device *vdev; + struct delayed_work job_timeout_work; struct work_struct recovery_work; - atomic_t in_reset; + struct rw_semaphore reset_lock; atomic_t reset_counter; + atomic_t reset_pending; bool is_warmboot; u32 suspend_reschedule_counter; }; @@ -36,6 +39,8 @@ int __must_check ivpu_rpm_get(struct ivpu_device *vdev); int __must_check ivpu_rpm_get_if_active(struct ivpu_device *vdev); void ivpu_rpm_put(struct ivpu_device *vdev); -void ivpu_pm_schedule_recovery(struct ivpu_device *vdev); +void ivpu_pm_trigger_recovery(struct ivpu_device *vdev, const char *reason); +void ivpu_start_job_timeout_detection(struct ivpu_device *vdev); +void ivpu_stop_job_timeout_detection(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 index 6b71be92ba6538..04c954258563a1 100644 --- a/drivers/accel/ivpu/vpu_boot_api.h +++ b/drivers/accel/ivpu/vpu_boot_api.h @@ -11,7 +11,10 @@ * 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. + * VPU_BOOT_API_VER_PATCH will be ignored. KMD and compatibility is not affected if this changes + * This information is collected by using vpuip_2/application/vpuFirmware/make_std_fw_image.py + * If a header is missing this info we ignore the header, if a header is missing or contains + * partial info a build error will be generated. */ /* @@ -24,12 +27,12 @@ * Minor version changes when API backward compatibility is preserved. * Resets to 0 if Major version is incremented. */ -#define VPU_BOOT_API_VER_MINOR 12 +#define VPU_BOOT_API_VER_MINOR 20 /* * API header changed (field names, documentation, formatting) but API itself has not been changed */ -#define VPU_BOOT_API_VER_PATCH 2 +#define VPU_BOOT_API_VER_PATCH 4 /* * Index in the API version table @@ -63,6 +66,12 @@ struct vpu_firmware_header { /* Size of memory require for firmware execution */ u32 runtime_size; u32 shave_nn_fw_size; + /* Size of primary preemption buffer. */ + u32 preemption_buffer_1_size; + /* Size of secondary preemption buffer. */ + u32 preemption_buffer_2_size; + /* Space reserved for future preemption-related fields. */ + u32 preemption_reserved[6]; }; /* @@ -89,6 +98,14 @@ enum VPU_BOOT_L2_CACHE_CFG_TYPE { VPU_BOOT_L2_CACHE_CFG_NUM = 2 }; +/** VPU MCA ECC signalling mode. By default, no signalling is used */ +enum VPU_BOOT_MCA_ECC_SIGNAL_TYPE { + VPU_BOOT_MCA_ECC_NONE = 0, + VPU_BOOT_MCA_ECC_CORR = 1, + VPU_BOOT_MCA_ECC_FATAL = 2, + VPU_BOOT_MCA_ECC_BOTH = 3 +}; + /** * Logging destinations. * @@ -131,9 +148,11 @@ enum vpu_trace_destination { #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 +/* VPU 30xx HW component IDs are sequential, so define first and last IDs. */ +#define VPU_TRACE_PROC_BIT_30XX_FIRST VPU_TRACE_PROC_BIT_LRT +#define VPU_TRACE_PROC_BIT_30XX_LAST VPU_TRACE_PROC_BIT_SHV_15 +#define VPU_TRACE_PROC_BIT_KMB_FIRST VPU_TRACE_PROC_BIT_30XX_FIRST +#define VPU_TRACE_PROC_BIT_KMB_LAST VPU_TRACE_PROC_BIT_30XX_LAST struct vpu_boot_l2_cache_config { u8 use; @@ -148,6 +167,25 @@ struct vpu_warm_boot_section { u32 is_clear_op; }; +/* + * When HW scheduling mode is enabled, a present period is defined. + * It will be used by VPU to swap between normal and focus priorities + * to prevent starving of normal priority band (when implemented). + * Host must provide a valid value at boot time in + * `vpu_focus_present_timer_ms`. If the value provided by the host is not within the + * defined range a default value will be used. Here we define the min. and max. + * allowed values and the and default value of the present period. Units are milliseconds. + */ +#define VPU_PRESENT_CALL_PERIOD_MS_DEFAULT 50 +#define VPU_PRESENT_CALL_PERIOD_MS_MIN 16 +#define VPU_PRESENT_CALL_PERIOD_MS_MAX 10000 + +/** + * Macros to enable various operation modes within the VPU. + * To be defined as part of 32 bit mask. + */ +#define VPU_OP_MODE_SURVIVABILITY 0x1 + struct vpu_boot_params { u32 magic; u32 vpu_id; @@ -218,6 +256,7 @@ struct vpu_boot_params { * the threshold will not be logged); applies to every enabled logging * destination and loggable HW component. See 'mvLog_t' enum for acceptable * values. + * TODO: EISW-33556: Move log level definition (mvLog_t) to this file. */ u32 default_trace_level; u32 boot_type; @@ -249,7 +288,36 @@ struct vpu_boot_params { u32 temp_sensor_period_ms; /** PLL ratio for efficient clock frequency */ u32 pn_freq_pll_ratio; - u32 pad4[28]; + /** DVFS Mode: Default: 0, Max Performance: 1, On Demand: 2, Power Save: 3 */ + u32 dvfs_mode; + /** + * Depending on DVFS Mode: + * On-demand: Default if 0. + * Bit 0-7 - uint8_t: Highest residency percent + * Bit 8-15 - uint8_t: High residency percent + * Bit 16-23 - uint8_t: Low residency percent + * Bit 24-31 - uint8_t: Lowest residency percent + * Bit 32-35 - unsigned 4b: PLL Ratio increase amount on highest residency + * Bit 36-39 - unsigned 4b: PLL Ratio increase amount on high residency + * Bit 40-43 - unsigned 4b: PLL Ratio decrease amount on low residency + * Bit 44-47 - unsigned 4b: PLL Ratio decrease amount on lowest frequency + * Bit 48-55 - uint8_t: Period (ms) for residency decisions + * Bit 56-63 - uint8_t: Averaging windows (as multiples of period. Max: 30 decimal) + * Power Save/Max Performance: Unused + */ + u64 dvfs_param; + /** + * D0i3 delayed entry + * Bit0: Disable CPU state save on D0i2 entry flow. + * 0: Every D0i2 entry saves state. Save state IPC message ignored. + * 1: IPC message required to save state on D0i3 entry flow. + */ + u32 d0i3_delayed_entry; + /* Time spent by VPU in D0i3 state */ + u64 d0i3_residency_time_us; + /* Value of VPU perf counter at the time of entering D0i3 state . */ + u64 d0i3_entry_vpu_ts; + u32 pad4[20]; /* Warm boot information: 0x400 - 0x43F */ u32 warm_boot_sections_count; u32 warm_boot_start_address_reference; @@ -274,8 +342,12 @@ struct vpu_boot_params { u32 vpu_scheduling_mode; /* Present call period in milliseconds. */ u32 vpu_focus_present_timer_ms; - /* Unused/reserved: 0x478 - 0xFFF */ - u32 pad6[738]; + /* VPU ECC Signaling */ + u32 vpu_uses_ecc_mca_signal; + /* Values defined by VPU_OP_MODE* macros */ + u32 vpu_operation_mode; + /* Unused/reserved: 0x480 - 0xFFF */ + u32 pad6[736]; }; /* diff --git a/drivers/accel/ivpu/vpu_jsm_api.h b/drivers/accel/ivpu/vpu_jsm_api.h index 2949ec8365bd54..7da7622742bee3 100644 --- a/drivers/accel/ivpu/vpu_jsm_api.h +++ b/drivers/accel/ivpu/vpu_jsm_api.h @@ -22,12 +22,12 @@ /* * Minor version changes when API backward compatibility is preserved. */ -#define VPU_JSM_API_VER_MINOR 0 +#define VPU_JSM_API_VER_MINOR 15 /* * API header changed (field names, documentation, formatting) but API itself has not been changed */ -#define VPU_JSM_API_VER_PATCH 1 +#define VPU_JSM_API_VER_PATCH 0 /* * Index in the API version table @@ -84,11 +84,13 @@ * Job flags bit masks. */ #define VPU_JOB_FLAGS_NULL_SUBMISSION_MASK 0x00000001 +#define VPU_JOB_FLAGS_PRIVATE_DATA_MASK 0xFF000000 /* * Sizes of the reserved areas in jobs, in bytes. */ -#define VPU_JOB_RESERVED_BYTES 16 +#define VPU_JOB_RESERVED_BYTES 8 + /* * Sizes of the reserved areas in job queues, in bytes. */ @@ -108,6 +110,20 @@ */ #define VPU_DYNDBG_CMD_MAX_LEN 96 +/* + * For HWS command queue scheduling, we can prioritise command queues inside the + * same process with a relative in-process priority. Valid values for relative + * priority are given below - max and min. + */ +#define VPU_HWS_COMMAND_QUEUE_MAX_IN_PROCESS_PRIORITY 7 +#define VPU_HWS_COMMAND_QUEUE_MIN_IN_PROCESS_PRIORITY -7 + +/* + * For HWS priority scheduling, we can have multiple realtime priority bands. + * They are numbered 0 to a MAX. + */ +#define VPU_HWS_MAX_REALTIME_PRIORITY_LEVEL 31U + /* * Job format. */ @@ -117,8 +133,14 @@ struct vpu_job_queue_entry { 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 */ + u64 primary_preempt_buf_addr; + /**< Address of the primary preemption buffer to use for this job */ + u32 primary_preempt_buf_size; + /**< Size of the primary preemption buffer to use for this job */ + u32 secondary_preempt_buf_size; + /**< Size of secondary preemption buffer to use for this job */ + u64 secondary_preempt_buf_addr; + /**< Address of secondary preemption buffer to use for this job */ u8 reserved_0[VPU_JOB_RESERVED_BYTES]; }; @@ -152,6 +174,46 @@ enum vpu_trace_entity_type { VPU_TRACE_ENTITY_TYPE_HW_COMPONENT = 2, }; +/* + * HWS specific log buffer header details. + * Total size is 32 bytes. + */ +struct vpu_hws_log_buffer_header { + /* Written by VPU after adding a log entry. Initialised by host to 0. */ + u32 first_free_entry_index; + /* Incremented by VPU every time the VPU overwrites the 0th entry; + * initialised by host to 0. + */ + u32 wraparound_count; + /* + * This is the number of buffers that can be stored in the log buffer provided by the host. + * It is written by host before passing buffer to VPU. VPU should consider it read-only. + */ + u64 num_of_entries; + u64 reserved[2]; +}; + +/* + * HWS specific log buffer entry details. + * Total size is 32 bytes. + */ +struct vpu_hws_log_buffer_entry { + /* VPU timestamp must be an invariant timer tick (not impacted by DVFS) */ + u64 vpu_timestamp; + /* + * Operation type: + * 0 - context state change + * 1 - queue new work + * 2 - queue unwait sync object + * 3 - queue no more work + * 4 - queue wait sync object + */ + u32 operation_type; + u32 reserved; + /* Operation data depends on operation type */ + u64 operation_data[2]; +}; + /* * Host <-> VPU IPC messages types. */ @@ -228,6 +290,23 @@ enum vpu_ipc_msg_type { * deallocated or reassigned to another context. */ VPU_JSM_MSG_HWS_REGISTER_DB = 0x1117, + /** Control command: Log buffer setting */ + VPU_JSM_MSG_HWS_SET_SCHEDULING_LOG = 0x1118, + /* Control command: Suspend command queue. */ + VPU_JSM_MSG_HWS_SUSPEND_CMDQ = 0x1119, + /* Control command: Resume command queue */ + VPU_JSM_MSG_HWS_RESUME_CMDQ = 0x111a, + /* Control command: Resume engine after reset */ + VPU_JSM_MSG_HWS_ENGINE_RESUME = 0x111b, + /* Control command: Enable survivability/DCT mode */ + VPU_JSM_MSG_DCT_ENABLE = 0x111c, + /* Control command: Disable survivability/DCT mode */ + VPU_JSM_MSG_DCT_DISABLE = 0x111d, + /** + * Dump VPU state. To be used for debug purposes only. + * NOTE: Please introduce new ASYNC commands before this one. * + */ + VPU_JSM_MSG_STATE_DUMP = 0x11FF, /* IPC Host -> Device, General commands */ VPU_JSM_MSG_GENERAL_CMD = 0x1200, VPU_JSM_MSG_BLOB_DEINIT = VPU_JSM_MSG_GENERAL_CMD, @@ -236,6 +315,10 @@ enum vpu_ipc_msg_type { * Linux command: `echo '' > /dynamic_debug/control`. */ VPU_JSM_MSG_DYNDBG_CONTROL = 0x1201, + /** + * Perform the save procedure for the D0i3 entry + */ + VPU_JSM_MSG_PWR_D0I3_ENTER = 0x1202, /* IPC Device -> Host, Job completion */ VPU_JSM_MSG_JOB_DONE = 0x2100, /* IPC Device -> Host, Async command completion */ @@ -304,11 +387,35 @@ enum vpu_ipc_msg_type { 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, + /** Response to control command: Log buffer setting */ + VPU_JSM_MSG_HWS_SET_SCHEDULING_LOG_RSP = 0x2218, + /* IPC Device -> Host, HWS notify index entry of log buffer written */ + VPU_JSM_MSG_HWS_SCHEDULING_LOG_NOTIFICATION = 0x2219, + /* IPC Device -> Host, HWS completion of a context suspend request */ + VPU_JSM_MSG_HWS_SUSPEND_CMDQ_DONE = 0x221a, + /* Response to control command: Resume command queue */ + VPU_JSM_MSG_HWS_RESUME_CMDQ_RSP = 0x221b, + /* Response to control command: Resume engine command response */ + VPU_JSM_MSG_HWS_RESUME_ENGINE_DONE = 0x221c, + /* Response to control command: Enable survivability/DCT mode */ + VPU_JSM_MSG_DCT_ENABLE_DONE = 0x221d, + /* Response to control command: Disable survivability/DCT mode */ + VPU_JSM_MSG_DCT_DISABLE_DONE = 0x221e, + /** + * Response to state dump control command. + * NOTE: Please introduce new ASYNC responses before this one. * + */ + VPU_JSM_MSG_STATE_DUMP_RSP = 0x22FF, /* 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, + /** + * Acknowledgment of completion of the save procedure initiated by + * VPU_JSM_MSG_PWR_D0I3_ENTER + */ + VPU_JSM_MSG_PWR_D0I3_ENTER_DONE = 0x2302, }; enum vpu_ipc_msg_status { VPU_JSM_MSG_FREE, VPU_JSM_MSG_ALLOCATED }; @@ -593,12 +700,12 @@ struct vpu_ipc_msg_payload_hws_priority_band_setup { * Default quantum in 100ns units for scheduling across processes * within a priority band */ - u64 process_quantum[VPU_HWS_NUM_PRIORITY_BANDS]; + u32 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]; + u32 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. @@ -608,32 +715,51 @@ struct vpu_ipc_msg_payload_hws_priority_band_setup { u32 reserved_0; }; -/* HWS create command queue request */ +/* + * @brief HWS create command queue request. + * Host will create a command queue via this command. + * Note: Cmdq group is a handle of an object which + * may contain one or more command queues. + * @see VPU_JSM_MSG_CREATE_CMD_QUEUE + * @see VPU_JSM_MSG_CREATE_CMD_QUEUE_RSP + */ struct vpu_ipc_msg_payload_hws_create_cmdq { /* Process id */ u64 process_id; /* Host SSID */ u32 host_ssid; - /* Zero Padding */ - u32 reserved; + /* Engine for which queue is being created */ + u32 engine_idx; + /* + * Cmdq group may be set to 0 or equal to + * cmdq_id while each priority band contains + * only single engine instances. + */ + u64 cmdq_group; /* Command queue id */ u64 cmdq_id; /* Command queue base */ u64 cmdq_base; /* Command queue size */ u32 cmdq_size; - /* Reserved */ + /* Zero padding */ u32 reserved_0; }; -/* HWS create command queue response */ +/* + * @brief HWS create command queue response. + * @see VPU_JSM_MSG_CREATE_CMD_QUEUE + * @see VPU_JSM_MSG_CREATE_CMD_QUEUE_RSP + */ struct vpu_ipc_msg_payload_hws_create_cmdq_rsp { /* Process id */ u64 process_id; /* Host SSID */ u32 host_ssid; - /* Zero Padding */ - u32 reserved; + /* Engine for which queue is being created */ + u32 engine_idx; + /* Command queue group */ + u64 cmdq_group; /* Command queue id */ u64 cmdq_id; }; @@ -661,7 +787,7 @@ struct vpu_ipc_msg_payload_hws_set_context_sched_properties { /* Inside realtime band assigns a further priority */ u32 realtime_priority_level; /* Priority relative to other contexts in the same process */ - u32 in_process_priority; + s32 in_process_priority; /* Zero padding / Reserved */ u32 reserved_1; /* Context quantum relative to other contexts of same priority in the same process */ @@ -694,6 +820,123 @@ struct vpu_jsm_hws_register_db { u64 cmdq_size; }; +/* + * @brief Structure to set another buffer to be used for scheduling-related logging. + * The size of the logging buffer and the number of entries is defined as part of the + * buffer itself as described next. + * The log buffer received from the host is made up of; + * - header: 32 bytes in size, as shown in 'struct vpu_hws_log_buffer_header'. + * The header contains the number of log entries in the buffer. + * - log entry: 0 to n-1, each log entry is 32 bytes in size, as shown in + * 'struct vpu_hws_log_buffer_entry'. + * The entry contains the VPU timestamp, operation type and data. + * The host should provide the notify index value of log buffer to VPU. This is a + * value defined within the log buffer and when written to will generate the + * scheduling log notification. + * The host should set engine_idx and vpu_log_buffer_va to 0 to disable logging + * for a particular engine. + * VPU will handle one log buffer for each of supported engines. + * VPU should allow the logging to consume one host_ssid. + * @see VPU_JSM_MSG_HWS_SET_SCHEDULING_LOG + * @see VPU_JSM_MSG_HWS_SET_SCHEDULING_LOG_RSP + * @see VPU_JSM_MSG_HWS_SCHEDULING_LOG_NOTIFICATION + */ +struct vpu_ipc_msg_payload_hws_set_scheduling_log { + /* Engine ordinal */ + u32 engine_idx; + /* Host SSID */ + u32 host_ssid; + /* + * VPU log buffer virtual address. + * Set to 0 to disable logging for this engine. + */ + u64 vpu_log_buffer_va; + /* + * Notify index of log buffer. VPU_JSM_MSG_HWS_SCHEDULING_LOG_NOTIFICATION + * is generated when an event log is written to this index. + */ + u64 notify_index; +}; + +/* + * @brief The scheduling log notification is generated by VPU when it writes + * an event into the log buffer at the notify_index. VPU notifies host with + * VPU_JSM_MSG_HWS_SCHEDULING_LOG_NOTIFICATION. This is an asynchronous + * message from VPU to host. + * @see VPU_JSM_MSG_HWS_SCHEDULING_LOG_NOTIFICATION + * @see VPU_JSM_MSG_HWS_SET_SCHEDULING_LOG + */ +struct vpu_ipc_msg_payload_hws_scheduling_log_notification { + /* Engine ordinal */ + u32 engine_idx; + /* Zero Padding */ + u32 reserved_0; +}; + +/* + * @brief HWS suspend command queue request and done structure. + * Host will request the suspend of contexts and VPU will; + * - Suspend all work on this context + * - Preempt any running work + * - Asynchronously perform the above and return success immediately once + * all items above are started successfully + * - Notify the host of completion of these operations via + * VPU_JSM_MSG_HWS_SUSPEND_CMDQ_DONE + * - Reject any other context operations on a context with an in-flight + * suspend request running + * Same structure used when VPU notifies host of completion of a context suspend + * request. The ids and suspend fence value reported in this command will match + * the one in the request from the host to suspend the context. Once suspend is + * complete, VPU will not access any data relating to this command queue until + * it is resumed. + * @see VPU_JSM_MSG_HWS_SUSPEND_CMDQ + * @see VPU_JSM_MSG_HWS_SUSPEND_CMDQ_DONE + */ +struct vpu_ipc_msg_payload_hws_suspend_cmdq { + /* Host SSID */ + u32 host_ssid; + /* Zero Padding */ + u32 reserved_0; + /* Command queue id */ + u64 cmdq_id; + /* + * Suspend fence value - reported by the VPU suspend context + * completed once suspend is complete. + */ + u64 suspend_fence_value; +}; + +/* + * @brief HWS Resume command queue request / response structure. + * Host will request the resume of a context; + * - VPU will resume all work on this context + * - Scheduler will allow this context to be scheduled + * @see VPU_JSM_MSG_HWS_RESUME_CMDQ + * @see VPU_JSM_MSG_HWS_RESUME_CMDQ_RSP + */ +struct vpu_ipc_msg_payload_hws_resume_cmdq { + /* Host SSID */ + u32 host_ssid; + /* Zero Padding */ + u32 reserved_0; + /* Command queue id */ + u64 cmdq_id; +}; + +/* + * @brief HWS Resume engine request / response structure. + * After a HWS engine reset, all scheduling is stopped on VPU until a engine resume. + * Host shall send this command to resume scheduling of any valid queue. + * @see VPU_JSM_MSG_HWS_RESUME_ENGINE + * @see VPU_JSM_MSG_HWS_RESUME_ENGINE_DONE + */ +struct vpu_ipc_msg_payload_hws_resume_engine { + /* Engine to be resumed */ + u32 engine_idx; + /* Reserved */ + u32 reserved_0; +}; + /** * Payload for VPU_JSM_MSG_TRACE_SET_CONFIG[_RSP] and * VPU_JSM_MSG_TRACE_GET_CONFIG_RSP messages. @@ -938,6 +1181,35 @@ struct vpu_ipc_msg_payload_dyndbg_control { char dyndbg_cmd[VPU_DYNDBG_CMD_MAX_LEN]; }; +/** + * Payload for VPU_JSM_MSG_PWR_D0I3_ENTER + * + * This is a bi-directional payload. + */ +struct vpu_ipc_msg_payload_pwr_d0i3_enter { + /** + * 0: VPU_JSM_MSG_PWR_D0I3_ENTER_DONE is not sent to the host driver + * The driver will poll for D0i2 Idle state transitions. + * 1: VPU_JSM_MSG_PWR_D0I3_ENTER_DONE is sent after VPU state save is complete + */ + u32 send_response; + u32 reserved_0; +}; + +/** + * Payload for VPU_JSM_MSG_DCT_ENABLE message. + * + * Default values for DCT active/inactive times are 5.3ms and 30ms respectively, + * corresponding to a 85% duty cycle. This payload allows the host to tune these + * values according to application requirements. + */ +struct vpu_ipc_msg_payload_pwr_dct_control { + /** Duty cycle active time in microseconds */ + u32 dct_active_us; + /** Duty cycle inactive time in microseconds */ + u32 dct_inactive_us; +}; + /* * Payloads union, used to define complete message format. */ @@ -974,6 +1246,13 @@ union vpu_ipc_msg_payload { 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; + struct vpu_ipc_msg_payload_hws_set_scheduling_log hws_set_scheduling_log; + struct vpu_ipc_msg_payload_hws_scheduling_log_notification hws_scheduling_log_notification; + struct vpu_ipc_msg_payload_hws_suspend_cmdq hws_suspend_cmdq; + struct vpu_ipc_msg_payload_hws_resume_cmdq hws_resume_cmdq; + struct vpu_ipc_msg_payload_hws_resume_engine hws_resume_engine; + struct vpu_ipc_msg_payload_pwr_d0i3_enter pwr_d0i3_enter; + struct vpu_ipc_msg_payload_pwr_dct_control pwr_dct_control; }; /* diff --git a/drivers/accel/qaic/Makefile b/drivers/accel/qaic/Makefile index 2418418f7a5055..3f7f6dfde7f2c2 100644 --- a/drivers/accel/qaic/Makefile +++ b/drivers/accel/qaic/Makefile @@ -9,4 +9,5 @@ qaic-y := \ mhi_controller.o \ qaic_control.o \ qaic_data.o \ - qaic_drv.o + qaic_drv.o \ + qaic_timesync.o diff --git a/drivers/accel/qaic/mhi_controller.c b/drivers/accel/qaic/mhi_controller.c index 1405623b03e4ee..cb77d048ed54b7 100644 --- a/drivers/accel/qaic/mhi_controller.c +++ b/drivers/accel/qaic/mhi_controller.c @@ -348,7 +348,7 @@ static struct mhi_channel_config aic100_channels[] = { .local_elements = 0, .event_ring = 0, .dir = DMA_TO_DEVICE, - .ee_mask = MHI_CH_EE_SBL | MHI_CH_EE_AMSS, + .ee_mask = MHI_CH_EE_SBL, .pollcfg = 0, .doorbell = MHI_DB_BRST_DISABLE, .lpm_notify = false, @@ -364,7 +364,39 @@ static struct mhi_channel_config aic100_channels[] = { .local_elements = 0, .event_ring = 0, .dir = DMA_FROM_DEVICE, - .ee_mask = MHI_CH_EE_SBL | MHI_CH_EE_AMSS, + .ee_mask = MHI_CH_EE_SBL, + .pollcfg = 0, + .doorbell = MHI_DB_BRST_DISABLE, + .lpm_notify = false, + .offload_channel = false, + .doorbell_mode_switch = false, + .auto_queue = false, + .wake_capable = false, + }, + { + .name = "QAIC_TIMESYNC_PERIODIC", + .num = 22, + .num_elements = 32, + .local_elements = 0, + .event_ring = 0, + .dir = DMA_TO_DEVICE, + .ee_mask = MHI_CH_EE_AMSS, + .pollcfg = 0, + .doorbell = MHI_DB_BRST_DISABLE, + .lpm_notify = false, + .offload_channel = false, + .doorbell_mode_switch = false, + .auto_queue = false, + .wake_capable = false, + }, + { + .num = 23, + .name = "QAIC_TIMESYNC_PERIODIC", + .num_elements = 32, + .local_elements = 0, + .event_ring = 0, + .dir = DMA_FROM_DEVICE, + .ee_mask = MHI_CH_EE_AMSS, .pollcfg = 0, .doorbell = MHI_DB_BRST_DISABLE, .lpm_notify = false, @@ -450,7 +482,7 @@ static void mhi_status_cb(struct mhi_controller *mhi_cntrl, enum mhi_callback re pci_err(qdev->pdev, "Fatal error received from device. Attempting to recover\n"); /* this event occurs in non-atomic context */ if (reason == MHI_CB_SYS_ERROR) - qaic_dev_reset_clean_local_state(qdev, true); + qaic_dev_reset_clean_local_state(qdev); } static int mhi_reset_and_async_power_up(struct mhi_controller *mhi_cntrl) @@ -481,7 +513,7 @@ static int mhi_reset_and_async_power_up(struct mhi_controller *mhi_cntrl) } struct mhi_controller *qaic_mhi_register_controller(struct pci_dev *pci_dev, void __iomem *mhi_bar, - int mhi_irq) + int mhi_irq, bool shared_msi) { struct mhi_controller *mhi_cntrl; int ret; @@ -513,6 +545,10 @@ struct mhi_controller *qaic_mhi_register_controller(struct pci_dev *pci_dev, voi return ERR_PTR(-ENOMEM); mhi_cntrl->irq[0] = mhi_irq; + + if (shared_msi) /* MSI shared with data path, no IRQF_NO_SUSPEND */ + mhi_cntrl->irq_flags = IRQF_SHARED; + mhi_cntrl->fw_image = "qcom/aic100/sbl.bin"; /* use latest configured timeout */ diff --git a/drivers/accel/qaic/mhi_controller.h b/drivers/accel/qaic/mhi_controller.h index 2ae45d768e2476..500e7f4af2afe9 100644 --- a/drivers/accel/qaic/mhi_controller.h +++ b/drivers/accel/qaic/mhi_controller.h @@ -8,7 +8,7 @@ #define MHICONTROLLERQAIC_H_ struct mhi_controller *qaic_mhi_register_controller(struct pci_dev *pci_dev, void __iomem *mhi_bar, - int mhi_irq); + int mhi_irq, bool shared_msi); void qaic_mhi_free_controller(struct mhi_controller *mhi_cntrl, bool link_up); void qaic_mhi_start_reset(struct mhi_controller *mhi_cntrl); void qaic_mhi_reset_done(struct mhi_controller *mhi_cntrl); diff --git a/drivers/accel/qaic/qaic.h b/drivers/accel/qaic/qaic.h index e3f4c30f3ffd21..582836f9538f95 100644 --- a/drivers/accel/qaic/qaic.h +++ b/drivers/accel/qaic/qaic.h @@ -31,6 +31,15 @@ #define to_drm(qddev) (&(qddev)->drm) #define to_accel_kdev(qddev) (to_drm(qddev)->accel->kdev) /* Return Linux device of accel node */ +enum __packed dev_states { + /* Device is offline or will be very soon */ + QAIC_OFFLINE, + /* Device is booting, not clear if it's in a usable state */ + QAIC_BOOT, + /* Device is fully operational */ + QAIC_ONLINE, +}; + extern bool datapath_polling; struct qaic_user { @@ -121,8 +130,10 @@ struct qaic_device { struct workqueue_struct *cntl_wq; /* Synchronizes all the users of device during cleanup */ struct srcu_struct dev_lock; - /* true: Device under reset; false: Device not under reset */ - bool in_reset; + /* Track the state of the device during resets */ + enum dev_states dev_state; + /* true: single MSI is used to operate device */ + bool single_msi; /* * true: A tx MHI transaction has failed and a rx buffer is still queued * in control device. Such a buffer is considered lost rx buffer @@ -137,6 +148,10 @@ struct qaic_device { u32 (*gen_crc)(void *msg); /* Validate the CRC of a control message */ bool (*valid_crc)(void *msg); + /* MHI "QAIC_TIMESYNC" channel device */ + struct mhi_device *qts_ch; + /* Work queue for tasks related to MHI "QAIC_TIMESYNC" channel */ + struct workqueue_struct *qts_wq; }; struct qaic_drm_device { @@ -268,7 +283,7 @@ void wakeup_dbc(struct qaic_device *qdev, u32 dbc_id); void release_dbc(struct qaic_device *qdev, u32 dbc_id); void wake_all_cntl(struct qaic_device *qdev); -void qaic_dev_reset_clean_local_state(struct qaic_device *qdev, bool exit_reset); +void qaic_dev_reset_clean_local_state(struct qaic_device *qdev); struct drm_gem_object *qaic_gem_prime_import(struct drm_device *dev, struct dma_buf *dma_buf); diff --git a/drivers/accel/qaic/qaic_control.c b/drivers/accel/qaic/qaic_control.c index 388abd40024ba4..9e8a8cbadf6bb9 100644 --- a/drivers/accel/qaic/qaic_control.c +++ b/drivers/accel/qaic/qaic_control.c @@ -1022,7 +1022,8 @@ static void *msg_xfer(struct qaic_device *qdev, struct wrapper_list *wrappers, u int xfer_count = 0; int retry_count; - if (qdev->in_reset) { + /* Allow QAIC_BOOT state since we need to check control protocol version */ + if (qdev->dev_state == QAIC_OFFLINE) { mutex_unlock(&qdev->cntl_mutex); return ERR_PTR(-ENODEV); } @@ -1138,7 +1139,7 @@ static int abort_dma_cont(struct qaic_device *qdev, struct wrapper_list *wrapper if (!list_is_first(&wrapper->list, &wrappers->list)) kref_put(&wrapper->ref_count, free_wrapper); - wrapper = add_wrapper(wrappers, offsetof(struct wrapper_msg, trans) + sizeof(*out_trans)); + wrapper = add_wrapper(wrappers, sizeof(*wrapper)); if (!wrapper) return -ENOMEM; @@ -1306,7 +1307,7 @@ int qaic_manage_ioctl(struct drm_device *dev, void *data, struct drm_file *file_ qdev = usr->qddev->qdev; qdev_rcu_id = srcu_read_lock(&qdev->dev_lock); - if (qdev->in_reset) { + if (qdev->dev_state != QAIC_ONLINE) { srcu_read_unlock(&qdev->dev_lock, qdev_rcu_id); srcu_read_unlock(&usr->qddev_lock, usr_rcu_id); return -ENODEV; diff --git a/drivers/accel/qaic/qaic_data.c b/drivers/accel/qaic/qaic_data.c index d42f002bc0cffa..03c9a793da35ad 100644 --- a/drivers/accel/qaic/qaic_data.c +++ b/drivers/accel/qaic/qaic_data.c @@ -51,6 +51,7 @@ }) #define NUM_EVENTS 128 #define NUM_DELAYS 10 +#define fifo_at(base, offset) ((base) + (offset) * get_dbc_req_elem_size()) static unsigned int wait_exec_default_timeout_ms = 5000; /* 5 sec default */ module_param(wait_exec_default_timeout_ms, uint, 0600); @@ -451,7 +452,7 @@ static int create_sgt(struct qaic_device *qdev, struct sg_table **sgt_out, u64 s * later */ buf_extra = (PAGE_SIZE - size % PAGE_SIZE) % PAGE_SIZE; - max_order = min(MAX_ORDER - 1, get_order(size)); + max_order = min(MAX_PAGE_ORDER, get_order(size)); } else { /* allocate a single page for book keeping */ nr_pages = 1; @@ -689,7 +690,7 @@ int qaic_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *fi qdev = usr->qddev->qdev; qdev_rcu_id = srcu_read_lock(&qdev->dev_lock); - if (qdev->in_reset) { + if (qdev->dev_state != QAIC_ONLINE) { ret = -ENODEV; goto unlock_dev_srcu; } @@ -748,7 +749,7 @@ int qaic_mmap_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file qdev = usr->qddev->qdev; qdev_rcu_id = srcu_read_lock(&qdev->dev_lock); - if (qdev->in_reset) { + if (qdev->dev_state != QAIC_ONLINE) { ret = -ENODEV; goto unlock_dev_srcu; } @@ -967,7 +968,7 @@ int qaic_attach_slice_bo_ioctl(struct drm_device *dev, void *data, struct drm_fi qdev = usr->qddev->qdev; qdev_rcu_id = srcu_read_lock(&qdev->dev_lock); - if (qdev->in_reset) { + if (qdev->dev_state != QAIC_ONLINE) { ret = -ENODEV; goto unlock_dev_srcu; } @@ -1056,6 +1057,16 @@ unlock_usr_srcu: return ret; } +static inline u32 fifo_space_avail(u32 head, u32 tail, u32 q_size) +{ + u32 avail = head - tail - 1; + + if (head <= tail) + avail += q_size; + + return avail; +} + static inline int copy_exec_reqs(struct qaic_device *qdev, struct bo_slice *slice, u32 dbc_id, u32 head, u32 *ptail) { @@ -1064,27 +1075,20 @@ static inline int copy_exec_reqs(struct qaic_device *qdev, struct bo_slice *slic u32 tail = *ptail; u32 avail; - avail = head - tail; - if (head <= tail) - avail += dbc->nelem; - - --avail; - + avail = fifo_space_avail(head, tail, dbc->nelem); if (avail < slice->nents) return -EAGAIN; if (tail + slice->nents > dbc->nelem) { avail = dbc->nelem - tail; avail = min_t(u32, avail, slice->nents); - memcpy(dbc->req_q_base + tail * get_dbc_req_elem_size(), reqs, - sizeof(*reqs) * avail); + memcpy(fifo_at(dbc->req_q_base, tail), reqs, sizeof(*reqs) * avail); reqs += avail; avail = slice->nents - avail; if (avail) memcpy(dbc->req_q_base, reqs, sizeof(*reqs) * avail); } else { - memcpy(dbc->req_q_base + tail * get_dbc_req_elem_size(), reqs, - sizeof(*reqs) * slice->nents); + memcpy(fifo_at(dbc->req_q_base, tail), reqs, sizeof(*reqs) * slice->nents); } *ptail = (tail + slice->nents) % dbc->nelem; @@ -1092,46 +1096,31 @@ static inline int copy_exec_reqs(struct qaic_device *qdev, struct bo_slice *slic return 0; } -/* - * Based on the value of resize we may only need to transmit first_n - * entries and the last entry, with last_bytes to send from the last entry. - * Note that first_n could be 0. - */ static inline int copy_partial_exec_reqs(struct qaic_device *qdev, struct bo_slice *slice, - u64 resize, u32 dbc_id, u32 head, u32 *ptail) + u64 resize, struct dma_bridge_chan *dbc, u32 head, + u32 *ptail) { - struct dma_bridge_chan *dbc = &qdev->dbc[dbc_id]; struct dbc_req *reqs = slice->reqs; struct dbc_req *last_req; u32 tail = *ptail; - u64 total_bytes; u64 last_bytes; u32 first_n; u32 avail; - int ret; - int i; - - avail = head - tail; - if (head <= tail) - avail += dbc->nelem; - --avail; + avail = fifo_space_avail(head, tail, dbc->nelem); - total_bytes = 0; - for (i = 0; i < slice->nents; i++) { - total_bytes += le32_to_cpu(reqs[i].len); - if (total_bytes >= resize) + /* + * After this for loop is complete, first_n represents the index + * of the last DMA request of this slice that needs to be + * transferred after resizing and last_bytes represents DMA size + * of that request. + */ + last_bytes = resize; + for (first_n = 0; first_n < slice->nents; first_n++) + if (last_bytes > le32_to_cpu(reqs[first_n].len)) + last_bytes -= le32_to_cpu(reqs[first_n].len); + else break; - } - - if (total_bytes < resize) { - /* User space should have used the full buffer path. */ - ret = -EINVAL; - return ret; - } - - first_n = i; - last_bytes = i ? resize + le32_to_cpu(reqs[i].len) - total_bytes : resize; if (avail < (first_n + 1)) return -EAGAIN; @@ -1140,22 +1129,21 @@ static inline int copy_partial_exec_reqs(struct qaic_device *qdev, struct bo_sli if (tail + first_n > dbc->nelem) { avail = dbc->nelem - tail; avail = min_t(u32, avail, first_n); - memcpy(dbc->req_q_base + tail * get_dbc_req_elem_size(), reqs, - sizeof(*reqs) * avail); + memcpy(fifo_at(dbc->req_q_base, tail), reqs, sizeof(*reqs) * avail); last_req = reqs + avail; avail = first_n - avail; if (avail) memcpy(dbc->req_q_base, last_req, sizeof(*reqs) * avail); } else { - memcpy(dbc->req_q_base + tail * get_dbc_req_elem_size(), reqs, - sizeof(*reqs) * first_n); + memcpy(fifo_at(dbc->req_q_base, tail), reqs, sizeof(*reqs) * first_n); } } - /* Copy over the last entry. Here we need to adjust len to the left over + /* + * Copy over the last entry. Here we need to adjust len to the left over * size, and set src and dst to the entry it is copied to. */ - last_req = dbc->req_q_base + (tail + first_n) % dbc->nelem * get_dbc_req_elem_size(); + last_req = fifo_at(dbc->req_q_base, (tail + first_n) % dbc->nelem); memcpy(last_req, reqs + slice->nents - 1, sizeof(*reqs)); /* @@ -1166,6 +1154,9 @@ static inline int copy_partial_exec_reqs(struct qaic_device *qdev, struct bo_sli last_req->len = cpu_to_le32((u32)last_bytes); last_req->src_addr = reqs[first_n].src_addr; last_req->dest_addr = reqs[first_n].dest_addr; + if (!last_bytes) + /* Disable DMA transfer */ + last_req->cmd = GENMASK(7, 2) & reqs[first_n].cmd; *ptail = (tail + first_n + 1) % dbc->nelem; @@ -1225,26 +1216,17 @@ static int send_bo_list_to_device(struct qaic_device *qdev, struct drm_file *fil bo->req_id = dbc->next_req_id++; list_for_each_entry(slice, &bo->slices, slice) { - /* - * If this slice does not fall under the given - * resize then skip this slice and continue the loop - */ - if (is_partial && pexec[i].resize && pexec[i].resize <= slice->offset) - continue; - for (j = 0; j < slice->nents; j++) slice->reqs[j].req_id = cpu_to_le16(bo->req_id); - /* - * If it is a partial execute ioctl call then check if - * resize has cut this slice short then do a partial copy - * else do complete copy - */ - if (is_partial && pexec[i].resize && - pexec[i].resize < slice->offset + slice->size) + if (is_partial && (!pexec[i].resize || pexec[i].resize <= slice->offset)) + /* Configure the slice for no DMA transfer */ + ret = copy_partial_exec_reqs(qdev, slice, 0, dbc, head, tail); + else if (is_partial && pexec[i].resize < slice->offset + slice->size) + /* Configure the slice to be partially DMA transferred */ ret = copy_partial_exec_reqs(qdev, slice, - pexec[i].resize - slice->offset, - dbc->id, head, tail); + pexec[i].resize - slice->offset, dbc, + head, tail); else ret = copy_exec_reqs(qdev, slice, dbc->id, head, tail); if (ret) { @@ -1357,7 +1339,7 @@ static int __qaic_execute_bo_ioctl(struct drm_device *dev, void *data, struct dr qdev = usr->qddev->qdev; qdev_rcu_id = srcu_read_lock(&qdev->dev_lock); - if (qdev->in_reset) { + if (qdev->dev_state != QAIC_ONLINE) { ret = -ENODEV; goto unlock_dev_srcu; } @@ -1464,6 +1446,16 @@ irqreturn_t dbc_irq_handler(int irq, void *data) rcu_id = srcu_read_lock(&dbc->ch_lock); + if (datapath_polling) { + srcu_read_unlock(&dbc->ch_lock, rcu_id); + /* + * Normally datapath_polling will not have irqs enabled, but + * when running with only one MSI the interrupt is shared with + * MHI so it cannot be disabled. Return ASAP instead. + */ + return IRQ_HANDLED; + } + if (!dbc->usr) { srcu_read_unlock(&dbc->ch_lock, rcu_id); return IRQ_HANDLED; @@ -1486,7 +1478,8 @@ irqreturn_t dbc_irq_handler(int irq, void *data) return IRQ_NONE; } - disable_irq_nosync(irq); + if (!dbc->qdev->single_msi) + disable_irq_nosync(irq); srcu_read_unlock(&dbc->ch_lock, rcu_id); return IRQ_WAKE_THREAD; } @@ -1502,7 +1495,7 @@ void irq_polling_work(struct work_struct *work) rcu_id = srcu_read_lock(&dbc->ch_lock); while (1) { - if (dbc->qdev->in_reset) { + if (dbc->qdev->dev_state != QAIC_ONLINE) { srcu_read_unlock(&dbc->ch_lock, rcu_id); return; } @@ -1557,12 +1550,12 @@ irqreturn_t dbc_irq_threaded_fn(int irq, void *data) u32 tail; rcu_id = srcu_read_lock(&dbc->ch_lock); + qdev = dbc->qdev; head = readl(dbc->dbc_base + RSPHP_OFF); if (head == U32_MAX) /* PCI link error */ goto error_out; - qdev = dbc->qdev; read_fifo: if (!event_count) { @@ -1643,14 +1636,14 @@ read_fifo: goto read_fifo; normal_out: - if (likely(!datapath_polling)) + if (!qdev->single_msi && likely(!datapath_polling)) enable_irq(irq); - else + else if (unlikely(datapath_polling)) schedule_work(&dbc->poll_work); /* checking the fifo and enabling irqs is a race, missed event check */ tail = readl(dbc->dbc_base + RSPTP_OFF); if (tail != U32_MAX && head != tail) { - if (likely(!datapath_polling)) + if (!qdev->single_msi && likely(!datapath_polling)) disable_irq_nosync(irq); goto read_fifo; } @@ -1659,9 +1652,9 @@ normal_out: error_out: srcu_read_unlock(&dbc->ch_lock, rcu_id); - if (likely(!datapath_polling)) + if (!qdev->single_msi && likely(!datapath_polling)) enable_irq(irq); - else + else if (unlikely(datapath_polling)) schedule_work(&dbc->poll_work); return IRQ_HANDLED; @@ -1692,7 +1685,7 @@ int qaic_wait_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file qdev = usr->qddev->qdev; qdev_rcu_id = srcu_read_lock(&qdev->dev_lock); - if (qdev->in_reset) { + if (qdev->dev_state != QAIC_ONLINE) { ret = -ENODEV; goto unlock_dev_srcu; } @@ -1761,7 +1754,7 @@ int qaic_perf_stats_bo_ioctl(struct drm_device *dev, void *data, struct drm_file qdev = usr->qddev->qdev; qdev_rcu_id = srcu_read_lock(&qdev->dev_lock); - if (qdev->in_reset) { + if (qdev->dev_state != QAIC_ONLINE) { ret = -ENODEV; goto unlock_dev_srcu; } @@ -1852,7 +1845,7 @@ int qaic_detach_slice_bo_ioctl(struct drm_device *dev, void *data, struct drm_fi qdev = usr->qddev->qdev; qdev_rcu_id = srcu_read_lock(&qdev->dev_lock); - if (qdev->in_reset) { + if (qdev->dev_state != QAIC_ONLINE) { ret = -ENODEV; goto unlock_dev_srcu; } diff --git a/drivers/accel/qaic/qaic_drv.c b/drivers/accel/qaic/qaic_drv.c index 6f58095767df6c..2a313eb69b1219 100644 --- a/drivers/accel/qaic/qaic_drv.c +++ b/drivers/accel/qaic/qaic_drv.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,7 @@ #include "mhi_controller.h" #include "qaic.h" +#include "qaic_timesync.h" MODULE_IMPORT_NS(DMA_BUF); @@ -42,9 +44,6 @@ MODULE_PARM_DESC(datapath_polling, "Operate the datapath in polling mode"); static bool link_up; static DEFINE_IDA(qaic_usrs); -static int qaic_create_drm_device(struct qaic_device *qdev, s32 partition_id); -static void qaic_destroy_drm_device(struct qaic_device *qdev, s32 partition_id); - static void free_usr(struct kref *kref) { struct qaic_user *usr = container_of(kref, struct qaic_user, ref_count); @@ -63,7 +62,7 @@ static int qaic_open(struct drm_device *dev, struct drm_file *file) int ret; rcu_id = srcu_read_lock(&qdev->dev_lock); - if (qdev->in_reset) { + if (qdev->dev_state != QAIC_ONLINE) { ret = -ENODEV; goto dev_unlock; } @@ -120,7 +119,7 @@ static void qaic_postclose(struct drm_device *dev, struct drm_file *file) if (qddev) { qdev = qddev->qdev; qdev_rcu_id = srcu_read_lock(&qdev->dev_lock); - if (!qdev->in_reset) { + if (qdev->dev_state == QAIC_ONLINE) { qaic_release_usr(qdev, usr); for (i = 0; i < qdev->num_dbc; ++i) if (qdev->dbc[i].usr && qdev->dbc[i].usr->handle == usr->handle) @@ -182,13 +181,6 @@ static int qaic_create_drm_device(struct qaic_device *qdev, s32 partition_id) qddev->partition_id = partition_id; - /* - * drm_dev_unregister() sets the driver data to NULL and - * drm_dev_register() does not update the driver data. During a SOC - * reset drm dev is unregistered and registered again leaving the - * driver data to NULL. - */ - dev_set_drvdata(to_accel_kdev(qddev), drm->accel); ret = drm_dev_register(drm, 0); if (ret) pci_dbg(qdev->pdev, "drm_dev_register failed %d\n", ret); @@ -202,7 +194,6 @@ static void qaic_destroy_drm_device(struct qaic_device *qdev, s32 partition_id) struct drm_device *drm = to_drm(qddev); struct qaic_user *usr; - drm_dev_get(drm); drm_dev_unregister(drm); qddev->partition_id = 0; /* @@ -231,7 +222,6 @@ static void qaic_destroy_drm_device(struct qaic_device *qdev, s32 partition_id) mutex_lock(&qddev->users_mutex); } mutex_unlock(&qddev->users_mutex); - drm_dev_put(drm); } static int qaic_mhi_probe(struct mhi_device *mhi_dev, const struct mhi_device_id *id) @@ -253,8 +243,6 @@ static int qaic_mhi_probe(struct mhi_device *mhi_dev, const struct mhi_device_id qdev = pci_get_drvdata(to_pci_dev(mhi_dev->mhi_cntrl->cntrl_dev)); - qdev->in_reset = false; - dev_set_drvdata(&mhi_dev->dev, qdev); qdev->cntl_ch = mhi_dev; @@ -264,6 +252,7 @@ static int qaic_mhi_probe(struct mhi_device *mhi_dev, const struct mhi_device_id return ret; } + qdev->dev_state = QAIC_BOOT; ret = get_cntl_version(qdev, NULL, &major, &minor); if (ret || major != CNTL_MAJOR || minor > CNTL_MINOR) { pci_err(qdev->pdev, "%s: Control protocol version (%d.%d) not supported. Supported version is (%d.%d). Ret: %d\n", @@ -271,8 +260,8 @@ static int qaic_mhi_probe(struct mhi_device *mhi_dev, const struct mhi_device_id ret = -EINVAL; goto close_control; } - - ret = qaic_create_drm_device(qdev, QAIC_NO_PARTITION); + qdev->dev_state = QAIC_ONLINE; + kobject_uevent(&(to_accel_kdev(qdev->qddev))->kobj, KOBJ_ONLINE); return ret; @@ -290,7 +279,8 @@ static void qaic_notify_reset(struct qaic_device *qdev) { int i; - qdev->in_reset = true; + kobject_uevent(&(to_accel_kdev(qdev->qddev))->kobj, KOBJ_OFFLINE); + qdev->dev_state = QAIC_OFFLINE; /* wake up any waiters to avoid waiting for timeouts at sync */ wake_all_cntl(qdev); for (i = 0; i < qdev->num_dbc; ++i) @@ -298,21 +288,15 @@ static void qaic_notify_reset(struct qaic_device *qdev) synchronize_srcu(&qdev->dev_lock); } -void qaic_dev_reset_clean_local_state(struct qaic_device *qdev, bool exit_reset) +void qaic_dev_reset_clean_local_state(struct qaic_device *qdev) { int i; qaic_notify_reset(qdev); - /* remove drmdevs to prevent new users from coming in */ - qaic_destroy_drm_device(qdev, QAIC_NO_PARTITION); - /* start tearing things down */ for (i = 0; i < qdev->num_dbc; ++i) release_dbc(qdev, i); - - if (exit_reset) - qdev->in_reset = false; } static void cleanup_qdev(struct qaic_device *qdev) @@ -324,6 +308,7 @@ static void cleanup_qdev(struct qaic_device *qdev) cleanup_srcu_struct(&qdev->dev_lock); pci_set_drvdata(qdev->pdev, NULL); destroy_workqueue(qdev->cntl_wq); + destroy_workqueue(qdev->qts_wq); } static struct qaic_device *create_qdev(struct pci_dev *pdev, const struct pci_device_id *id) @@ -336,6 +321,7 @@ static struct qaic_device *create_qdev(struct pci_dev *pdev, const struct pci_de if (!qdev) return NULL; + qdev->dev_state = QAIC_OFFLINE; if (id->device == PCI_DEV_AIC100) { qdev->num_dbc = 16; qdev->dbc = devm_kcalloc(&pdev->dev, qdev->num_dbc, sizeof(*qdev->dbc), GFP_KERNEL); @@ -347,6 +333,12 @@ static struct qaic_device *create_qdev(struct pci_dev *pdev, const struct pci_de if (!qdev->cntl_wq) return NULL; + qdev->qts_wq = alloc_workqueue("qaic_ts", WQ_UNBOUND, 0); + if (!qdev->qts_wq) { + destroy_workqueue(qdev->cntl_wq); + return NULL; + } + pci_set_drvdata(pdev, qdev); qdev->pdev = pdev; @@ -424,14 +416,24 @@ static int init_msi(struct qaic_device *qdev, struct pci_dev *pdev) int i; /* Managed release since we use pcim_enable_device */ - ret = pci_alloc_irq_vectors(pdev, 1, 32, PCI_IRQ_MSI); - if (ret < 0) - return ret; + ret = pci_alloc_irq_vectors(pdev, 32, 32, PCI_IRQ_MSI); + if (ret == -ENOSPC) { + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI); + if (ret < 0) + return ret; - if (ret < 32) { - pci_err(pdev, "%s: Requested 32 MSIs. Obtained %d MSIs which is less than the 32 required.\n", - __func__, ret); - return -ENODEV; + /* + * Operate in one MSI mode. All interrupts will be directed to + * MSI0; every interrupt will wake up all the interrupt handlers + * (MHI and DBC[0-15]). Since the interrupt is now shared, it is + * not disabled during DBC threaded handler, but only one thread + * will be allowed to run per DBC, so while it can be + * interrupted, it shouldn't race with itself. + */ + qdev->single_msi = true; + pci_info(pdev, "Allocating 32 MSIs failed, operating in 1 MSI mode. Performance may be impacted.\n"); + } else if (ret < 0) { + return ret; } mhi_irq = pci_irq_vector(pdev, 0); @@ -439,15 +441,17 @@ static int init_msi(struct qaic_device *qdev, struct pci_dev *pdev) return mhi_irq; for (i = 0; i < qdev->num_dbc; ++i) { - ret = devm_request_threaded_irq(&pdev->dev, pci_irq_vector(pdev, i + 1), + ret = devm_request_threaded_irq(&pdev->dev, + pci_irq_vector(pdev, qdev->single_msi ? 0 : i + 1), dbc_irq_handler, dbc_irq_threaded_fn, IRQF_SHARED, "qaic_dbc", &qdev->dbc[i]); if (ret) return ret; if (datapath_polling) { - qdev->dbc[i].irq = pci_irq_vector(pdev, i + 1); - disable_irq_nosync(qdev->dbc[i].irq); + qdev->dbc[i].irq = pci_irq_vector(pdev, qdev->single_msi ? 0 : i + 1); + if (!qdev->single_msi) + disable_irq_nosync(qdev->dbc[i].irq); INIT_WORK(&qdev->dbc[i].poll_work, irq_polling_work); } } @@ -479,14 +483,21 @@ static int qaic_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto cleanup_qdev; } - qdev->mhi_cntrl = qaic_mhi_register_controller(pdev, qdev->bar_0, mhi_irq); + ret = qaic_create_drm_device(qdev, QAIC_NO_PARTITION); + if (ret) + goto cleanup_qdev; + + qdev->mhi_cntrl = qaic_mhi_register_controller(pdev, qdev->bar_0, mhi_irq, + qdev->single_msi); if (IS_ERR(qdev->mhi_cntrl)) { ret = PTR_ERR(qdev->mhi_cntrl); - goto cleanup_qdev; + goto cleanup_drm_dev; } return 0; +cleanup_drm_dev: + qaic_destroy_drm_device(qdev, QAIC_NO_PARTITION); cleanup_qdev: cleanup_qdev(qdev); return ret; @@ -499,7 +510,8 @@ static void qaic_pci_remove(struct pci_dev *pdev) if (!qdev) return; - qaic_dev_reset_clean_local_state(qdev, false); + qaic_dev_reset_clean_local_state(qdev); + qaic_destroy_drm_device(qdev, QAIC_NO_PARTITION); qaic_mhi_free_controller(qdev->mhi_cntrl, link_up); cleanup_qdev(qdev); } @@ -522,14 +534,13 @@ static void qaic_pci_reset_prepare(struct pci_dev *pdev) qaic_notify_reset(qdev); qaic_mhi_start_reset(qdev->mhi_cntrl); - qaic_dev_reset_clean_local_state(qdev, false); + qaic_dev_reset_clean_local_state(qdev); } static void qaic_pci_reset_done(struct pci_dev *pdev) { struct qaic_device *qdev = pci_get_drvdata(pdev); - qdev->in_reset = false; qaic_mhi_reset_done(qdev->mhi_cntrl); } @@ -586,6 +597,10 @@ static int __init qaic_init(void) goto free_pci; } + ret = qaic_timesync_init(); + if (ret) + pr_debug("qaic: qaic_timesync_init failed %d\n", ret); + return 0; free_pci: @@ -611,6 +626,7 @@ static void __exit qaic_exit(void) * reinitializing the link_up state after the cleanup is done. */ link_up = true; + qaic_timesync_deinit(); mhi_driver_unregister(&qaic_mhi_driver); pci_unregister_driver(&qaic_pci_driver); } diff --git a/drivers/accel/qaic/qaic_timesync.c b/drivers/accel/qaic/qaic_timesync.c new file mode 100644 index 00000000000000..301f4462d51bd6 --- /dev/null +++ b/drivers/accel/qaic/qaic_timesync.c @@ -0,0 +1,395 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qaic.h" +#include "qaic_timesync.h" + +#define QTIMER_REG_OFFSET 0xa28 +#define QAIC_TIMESYNC_SIGNATURE 0x55aa +#define QAIC_CONV_QTIMER_TO_US(qtimer) (mul_u64_u32_div(qtimer, 10, 192)) + +static unsigned int timesync_delay_ms = 1000; /* 1 sec default */ +module_param(timesync_delay_ms, uint, 0600); +MODULE_PARM_DESC(timesync_delay_ms, "Delay in ms between two consecutive timesync operations"); + +enum qts_msg_type { + QAIC_TS_CMD_TO_HOST, + QAIC_TS_SYNC_REQ, + QAIC_TS_ACK_TO_HOST, + QAIC_TS_MSG_TYPE_MAX +}; + +/** + * struct qts_hdr - Timesync message header structure. + * @signature: Unique signature to identify the timesync message. + * @reserved_1: Reserved for future use. + * @reserved_2: Reserved for future use. + * @msg_type: sub-type of the timesync message. + * @reserved_3: Reserved for future use. + */ +struct qts_hdr { + __le16 signature; + __le16 reserved_1; + u8 reserved_2; + u8 msg_type; + __le16 reserved_3; +} __packed; + +/** + * struct qts_timeval - Structure to carry time information. + * @tv_sec: Seconds part of the time. + * @tv_usec: uS (microseconds) part of the time. + */ +struct qts_timeval { + __le64 tv_sec; + __le64 tv_usec; +} __packed; + +/** + * struct qts_host_time_sync_msg_data - Structure to denote the timesync message. + * @header: Header of the timesync message. + * @data: Time information. + */ +struct qts_host_time_sync_msg_data { + struct qts_hdr header; + struct qts_timeval data; +} __packed; + +/** + * struct mqts_dev - MHI QAIC Timesync Control device. + * @qdev: Pointer to the root device struct driven by QAIC driver. + * @mhi_dev: Pointer to associated MHI device. + * @timer: Timer handle used for timesync. + * @qtimer_addr: Device QTimer register pointer. + * @buff_in_use: atomic variable to track if the sync_msg buffer is in use. + * @dev: Device pointer to qdev->pdev->dev stored for easy access. + * @sync_msg: Buffer used to send timesync message over MHI. + */ +struct mqts_dev { + struct qaic_device *qdev; + struct mhi_device *mhi_dev; + struct timer_list timer; + void __iomem *qtimer_addr; + atomic_t buff_in_use; + struct device *dev; + struct qts_host_time_sync_msg_data *sync_msg; +}; + +struct qts_resp_msg { + struct qts_hdr hdr; +} __packed; + +struct qts_resp { + struct qts_resp_msg data; + struct work_struct work; + struct qaic_device *qdev; +}; + +#ifdef readq +static u64 read_qtimer(const volatile void __iomem *addr) +{ + return readq(addr); +} +#else +static u64 read_qtimer(const volatile void __iomem *addr) +{ + u64 low, high; + + low = readl(addr); + high = readl(addr + sizeof(u32)); + return low | (high << 32); +} +#endif + +static void qaic_timesync_ul_xfer_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result) +{ + struct mqts_dev *mqtsdev = dev_get_drvdata(&mhi_dev->dev); + + dev_dbg(mqtsdev->dev, "%s status: %d xfer_len: %zu\n", __func__, + mhi_result->transaction_status, mhi_result->bytes_xferd); + + atomic_set(&mqtsdev->buff_in_use, 0); +} + +static void qaic_timesync_dl_xfer_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result) +{ + struct mqts_dev *mqtsdev = dev_get_drvdata(&mhi_dev->dev); + + dev_err(mqtsdev->dev, "%s no data expected on dl channel\n", __func__); +} + +static void qaic_timesync_timer(struct timer_list *t) +{ + struct mqts_dev *mqtsdev = from_timer(mqtsdev, t, timer); + struct qts_host_time_sync_msg_data *sync_msg; + u64 device_qtimer_us; + u64 device_qtimer; + u64 host_time_us; + u64 offset_us; + u64 host_sec; + int ret; + + if (atomic_read(&mqtsdev->buff_in_use)) { + dev_dbg(mqtsdev->dev, "%s buffer not free, schedule next cycle\n", __func__); + goto mod_timer; + } + atomic_set(&mqtsdev->buff_in_use, 1); + + sync_msg = mqtsdev->sync_msg; + sync_msg->header.signature = cpu_to_le16(QAIC_TIMESYNC_SIGNATURE); + sync_msg->header.msg_type = QAIC_TS_SYNC_REQ; + /* Read host UTC time and convert to uS*/ + host_time_us = div_u64(ktime_get_real_ns(), NSEC_PER_USEC); + device_qtimer = read_qtimer(mqtsdev->qtimer_addr); + device_qtimer_us = QAIC_CONV_QTIMER_TO_US(device_qtimer); + /* Offset between host UTC and device time */ + offset_us = host_time_us - device_qtimer_us; + + host_sec = div_u64(offset_us, USEC_PER_SEC); + sync_msg->data.tv_usec = cpu_to_le64(offset_us - host_sec * USEC_PER_SEC); + sync_msg->data.tv_sec = cpu_to_le64(host_sec); + ret = mhi_queue_buf(mqtsdev->mhi_dev, DMA_TO_DEVICE, sync_msg, sizeof(*sync_msg), MHI_EOT); + if (ret && (ret != -EAGAIN)) { + dev_err(mqtsdev->dev, "%s unable to queue to mhi:%d\n", __func__, ret); + return; + } else if (ret == -EAGAIN) { + atomic_set(&mqtsdev->buff_in_use, 0); + } + +mod_timer: + ret = mod_timer(t, jiffies + msecs_to_jiffies(timesync_delay_ms)); + if (ret) + dev_err(mqtsdev->dev, "%s mod_timer error:%d\n", __func__, ret); +} + +static int qaic_timesync_probe(struct mhi_device *mhi_dev, const struct mhi_device_id *id) +{ + struct qaic_device *qdev = pci_get_drvdata(to_pci_dev(mhi_dev->mhi_cntrl->cntrl_dev)); + struct mqts_dev *mqtsdev; + struct timer_list *timer; + int ret; + + mqtsdev = kzalloc(sizeof(*mqtsdev), GFP_KERNEL); + if (!mqtsdev) { + ret = -ENOMEM; + goto out; + } + + timer = &mqtsdev->timer; + mqtsdev->mhi_dev = mhi_dev; + mqtsdev->qdev = qdev; + mqtsdev->dev = &qdev->pdev->dev; + + mqtsdev->sync_msg = kzalloc(sizeof(*mqtsdev->sync_msg), GFP_KERNEL); + if (!mqtsdev->sync_msg) { + ret = -ENOMEM; + goto free_mqts_dev; + } + atomic_set(&mqtsdev->buff_in_use, 0); + + ret = mhi_prepare_for_transfer(mhi_dev); + if (ret) + goto free_sync_msg; + + /* Qtimer register pointer */ + mqtsdev->qtimer_addr = qdev->bar_0 + QTIMER_REG_OFFSET; + timer_setup(timer, qaic_timesync_timer, 0); + timer->expires = jiffies + msecs_to_jiffies(timesync_delay_ms); + add_timer(timer); + dev_set_drvdata(&mhi_dev->dev, mqtsdev); + + return 0; + +free_sync_msg: + kfree(mqtsdev->sync_msg); +free_mqts_dev: + kfree(mqtsdev); +out: + return ret; +}; + +static void qaic_timesync_remove(struct mhi_device *mhi_dev) +{ + struct mqts_dev *mqtsdev = dev_get_drvdata(&mhi_dev->dev); + + del_timer_sync(&mqtsdev->timer); + mhi_unprepare_from_transfer(mqtsdev->mhi_dev); + kfree(mqtsdev->sync_msg); + kfree(mqtsdev); +} + +static const struct mhi_device_id qaic_timesync_match_table[] = { + { .chan = "QAIC_TIMESYNC_PERIODIC"}, + {}, +}; + +MODULE_DEVICE_TABLE(mhi, qaic_timesync_match_table); + +static struct mhi_driver qaic_timesync_driver = { + .id_table = qaic_timesync_match_table, + .remove = qaic_timesync_remove, + .probe = qaic_timesync_probe, + .ul_xfer_cb = qaic_timesync_ul_xfer_cb, + .dl_xfer_cb = qaic_timesync_dl_xfer_cb, + .driver = { + .name = "qaic_timesync_periodic", + }, +}; + +static void qaic_boot_timesync_worker(struct work_struct *work) +{ + struct qts_resp *resp = container_of(work, struct qts_resp, work); + struct qts_host_time_sync_msg_data *req; + struct qts_resp_msg data = resp->data; + struct qaic_device *qdev = resp->qdev; + struct mhi_device *mhi_dev; + struct timespec64 ts; + int ret; + + mhi_dev = qdev->qts_ch; + /* Queue the response message beforehand to avoid race conditions */ + ret = mhi_queue_buf(mhi_dev, DMA_FROM_DEVICE, &resp->data, sizeof(resp->data), MHI_EOT); + if (ret) { + kfree(resp); + dev_warn(&mhi_dev->dev, "Failed to re-queue response buffer %d\n", ret); + return; + } + + switch (data.hdr.msg_type) { + case QAIC_TS_CMD_TO_HOST: + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + break; + + req->header = data.hdr; + req->header.msg_type = QAIC_TS_SYNC_REQ; + ktime_get_real_ts64(&ts); + req->data.tv_sec = cpu_to_le64(ts.tv_sec); + req->data.tv_usec = cpu_to_le64(div_u64(ts.tv_nsec, NSEC_PER_USEC)); + + ret = mhi_queue_buf(mhi_dev, DMA_TO_DEVICE, req, sizeof(*req), MHI_EOT); + if (ret) { + kfree(req); + dev_dbg(&mhi_dev->dev, "Failed to send request message. Error %d\n", ret); + } + break; + case QAIC_TS_ACK_TO_HOST: + dev_dbg(&mhi_dev->dev, "ACK received from device\n"); + break; + default: + dev_err(&mhi_dev->dev, "Invalid message type %u.\n", data.hdr.msg_type); + } +} + +static int qaic_boot_timesync_queue_resp(struct mhi_device *mhi_dev, struct qaic_device *qdev) +{ + struct qts_resp *resp; + int ret; + + resp = kzalloc(sizeof(*resp), GFP_KERNEL); + if (!resp) + return -ENOMEM; + + resp->qdev = qdev; + INIT_WORK(&resp->work, qaic_boot_timesync_worker); + + ret = mhi_queue_buf(mhi_dev, DMA_FROM_DEVICE, &resp->data, sizeof(resp->data), MHI_EOT); + if (ret) { + kfree(resp); + dev_warn(&mhi_dev->dev, "Failed to queue response buffer %d\n", ret); + return ret; + } + + return 0; +} + +static void qaic_boot_timesync_remove(struct mhi_device *mhi_dev) +{ + struct qaic_device *qdev; + + qdev = dev_get_drvdata(&mhi_dev->dev); + mhi_unprepare_from_transfer(qdev->qts_ch); + qdev->qts_ch = NULL; +} + +static int qaic_boot_timesync_probe(struct mhi_device *mhi_dev, const struct mhi_device_id *id) +{ + struct qaic_device *qdev = pci_get_drvdata(to_pci_dev(mhi_dev->mhi_cntrl->cntrl_dev)); + int ret; + + ret = mhi_prepare_for_transfer(mhi_dev); + if (ret) + return ret; + + qdev->qts_ch = mhi_dev; + dev_set_drvdata(&mhi_dev->dev, qdev); + + ret = qaic_boot_timesync_queue_resp(mhi_dev, qdev); + if (ret) { + dev_set_drvdata(&mhi_dev->dev, NULL); + qdev->qts_ch = NULL; + mhi_unprepare_from_transfer(mhi_dev); + } + + return ret; +} + +static void qaic_boot_timesync_ul_xfer_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result) +{ + kfree(mhi_result->buf_addr); +} + +static void qaic_boot_timesync_dl_xfer_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result) +{ + struct qts_resp *resp = container_of(mhi_result->buf_addr, struct qts_resp, data); + + if (mhi_result->transaction_status || mhi_result->bytes_xferd != sizeof(resp->data)) { + kfree(resp); + return; + } + + queue_work(resp->qdev->qts_wq, &resp->work); +} + +static const struct mhi_device_id qaic_boot_timesync_match_table[] = { + { .chan = "QAIC_TIMESYNC"}, + {}, +}; + +static struct mhi_driver qaic_boot_timesync_driver = { + .id_table = qaic_boot_timesync_match_table, + .remove = qaic_boot_timesync_remove, + .probe = qaic_boot_timesync_probe, + .ul_xfer_cb = qaic_boot_timesync_ul_xfer_cb, + .dl_xfer_cb = qaic_boot_timesync_dl_xfer_cb, + .driver = { + .name = "qaic_timesync", + }, +}; + +int qaic_timesync_init(void) +{ + int ret; + + ret = mhi_driver_register(&qaic_timesync_driver); + if (ret) + return ret; + ret = mhi_driver_register(&qaic_boot_timesync_driver); + + return ret; +} + +void qaic_timesync_deinit(void) +{ + mhi_driver_unregister(&qaic_boot_timesync_driver); + mhi_driver_unregister(&qaic_timesync_driver); +} diff --git a/drivers/accel/qaic/qaic_timesync.h b/drivers/accel/qaic/qaic_timesync.h new file mode 100644 index 00000000000000..851b7acd43bbbd --- /dev/null +++ b/drivers/accel/qaic/qaic_timesync.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __QAIC_TIMESYNC_H__ +#define __QAIC_TIMESYNC_H__ + +int qaic_timesync_init(void); +void qaic_timesync_deinit(void); +#endif /* __QAIC_TIMESYNC_H__ */ diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index f819e760ff195a..3c3f8037ebeddd 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -61,6 +61,10 @@ config ACPI_CCA_REQUIRED config ACPI_TABLE_LIB bool +config ACPI_THERMAL_LIB + depends on THERMAL + bool + config ACPI_DEBUGGER bool "AML debugger interface" select ACPI_DEBUG @@ -310,7 +314,6 @@ config ACPI_HOTPLUG_CPU bool depends on ACPI_PROCESSOR && HOTPLUG_CPU select ACPI_CONTAINER - default y config ACPI_PROCESSOR_AGGREGATOR tristate "Processor Aggregator" @@ -327,6 +330,7 @@ config ACPI_THERMAL tristate "Thermal Zone" depends on ACPI_PROCESSOR select THERMAL + select ACPI_THERMAL_LIB default y help This driver supports ACPI thermal zones. Most mobile and diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index eaa09bf52f1760..12ef8180d272c7 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -37,7 +37,7 @@ acpi-$(CONFIG_ACPI_SLEEP) += proc.o # ACPI Bus and Device Drivers # acpi-y += bus.o glue.o -acpi-y += scan.o +acpi-y += scan.o mipi-disco-img.o acpi-y += resource.o acpi-y += acpi_processor.o acpi-y += processor_core.o @@ -89,6 +89,7 @@ obj-$(CONFIG_ACPI_TAD) += acpi_tad.o obj-$(CONFIG_ACPI_PCI_SLOT) += pci_slot.o obj-$(CONFIG_ACPI_PROCESSOR) += processor.o obj-$(CONFIG_ACPI) += container.o +obj-$(CONFIG_ACPI_THERMAL_LIB) += thermal_lib.o obj-$(CONFIG_ACPI_THERMAL) += thermal.o obj-$(CONFIG_ACPI_PLATFORM_PROFILE) += platform_profile.o obj-$(CONFIG_ACPI_NFIT) += nfit/ diff --git a/drivers/acpi/acpi_extlog.c b/drivers/acpi/acpi_extlog.c index e120a96e1eaee8..ca87a093913599 100644 --- a/drivers/acpi/acpi_extlog.c +++ b/drivers/acpi/acpi_extlog.c @@ -145,9 +145,14 @@ static int extlog_print(struct notifier_block *nb, unsigned long val, static u32 err_seq; estatus = extlog_elog_entry_check(cpu, bank); - if (estatus == NULL || (mce->kflags & MCE_HANDLED_CEC)) + if (!estatus) return NOTIFY_DONE; + if (mce->kflags & MCE_HANDLED_CEC) { + estatus->block_status = 0; + return NOTIFY_DONE; + } + memcpy(elog_buf, (void *)estatus, ELOG_ENTRY_LEN); /* clear record status to enable BIOS to update it again */ estatus->block_status = 0; @@ -303,9 +308,10 @@ err: static void __exit extlog_exit(void) { mce_unregister_decode_chain(&extlog_mce_dec); - ((struct extlog_l1_head *)extlog_l1_addr)->flags &= ~FLAG_OS_OPTIN; - if (extlog_l1_addr) + if (extlog_l1_addr) { + ((struct extlog_l1_head *)extlog_l1_addr)->flags &= ~FLAG_OS_OPTIN; acpi_os_unmap_iomem(extlog_l1_addr, l1_size); + } if (elog_addr) acpi_os_unmap_iomem(elog_addr, elog_size); release_mem_region(elog_base, elog_size); diff --git a/drivers/acpi/acpi_lpit.c b/drivers/acpi/acpi_lpit.c index c5598b6d5db8b0..794962c5c88e95 100644 --- a/drivers/acpi/acpi_lpit.c +++ b/drivers/acpi/acpi_lpit.c @@ -105,7 +105,7 @@ static void lpit_update_residency(struct lpit_residency_info *info, return; info->frequency = lpit_native->counter_frequency ? - lpit_native->counter_frequency : tsc_khz * 1000; + lpit_native->counter_frequency : mul_u32_u32(tsc_khz, 1000U); if (!info->frequency) info->frequency = 1; diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 875de44961bf4b..04e273167e92a6 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -167,13 +167,9 @@ static struct pwm_lookup byt_pwm_lookup[] = { static void byt_pwm_setup(struct lpss_private_data *pdata) { - u64 uid; - /* Only call pwm_add_table for the first PWM controller */ - if (acpi_dev_uid_to_integer(pdata->adev, &uid) || uid != 1) - return; - - pwm_add_table(byt_pwm_lookup, ARRAY_SIZE(byt_pwm_lookup)); + if (acpi_dev_uid_match(pdata->adev, 1)) + pwm_add_table(byt_pwm_lookup, ARRAY_SIZE(byt_pwm_lookup)); } #define LPSS_I2C_ENABLE 0x6c @@ -218,13 +214,9 @@ static struct pwm_lookup bsw_pwm_lookup[] = { static void bsw_pwm_setup(struct lpss_private_data *pdata) { - u64 uid; - /* Only call pwm_add_table for the first PWM controller */ - if (acpi_dev_uid_to_integer(pdata->adev, &uid) || uid != 1) - return; - - pwm_add_table(bsw_pwm_lookup, ARRAY_SIZE(bsw_pwm_lookup)); + if (acpi_dev_uid_match(pdata->adev, 1)) + pwm_add_table(bsw_pwm_lookup, ARRAY_SIZE(bsw_pwm_lookup)); } static const struct property_entry lpt_spi_properties[] = { @@ -461,8 +453,9 @@ static int register_device_clock(struct acpi_device *adev, if (!clk_name) return -ENOMEM; clk = clk_register_fractional_divider(NULL, clk_name, parent, + 0, prv_base, 1, 15, 16, 15, CLK_FRAC_DIVIDER_POWER_OF_TWO_PS, - prv_base, 1, 15, 16, 15, 0, NULL); + NULL); parent = clk_name; clk_name = kasprintf(GFP_KERNEL, "%s-update", devname); @@ -570,34 +563,6 @@ static struct device *acpi_lpss_find_device(const char *hid, const char *uid) return bus_find_device(&pci_bus_type, NULL, &data, match_hid_uid); } -static bool acpi_lpss_dep(struct acpi_device *adev, acpi_handle handle) -{ - struct acpi_handle_list dep_devices; - acpi_status status; - bool ret = false; - int i; - - if (!acpi_has_method(adev->handle, "_DEP")) - return false; - - status = acpi_evaluate_reference(adev->handle, "_DEP", NULL, - &dep_devices); - if (ACPI_FAILURE(status)) { - dev_dbg(&adev->dev, "Failed to evaluate _DEP.\n"); - return false; - } - - for (i = 0; i < dep_devices.count; i++) { - if (dep_devices.handles[i] == handle) { - ret = true; - break; - } - } - - acpi_handle_list_free(&dep_devices); - return ret; -} - static void acpi_lpss_link_consumer(struct device *dev1, const struct lpss_device_links *link) { @@ -608,7 +573,7 @@ static void acpi_lpss_link_consumer(struct device *dev1, return; if ((link->dep_missing_ids && dmi_check_system(link->dep_missing_ids)) - || acpi_lpss_dep(ACPI_COMPANION(dev2), ACPI_HANDLE(dev1))) + || acpi_device_dep(ACPI_HANDLE(dev2), ACPI_HANDLE(dev1))) device_link_add(dev2, dev1, link->flags); put_device(dev2); @@ -624,7 +589,7 @@ static void acpi_lpss_link_supplier(struct device *dev1, return; if ((link->dep_missing_ids && dmi_check_system(link->dep_missing_ids)) - || acpi_lpss_dep(ACPI_COMPANION(dev1), ACPI_HANDLE(dev2))) + || acpi_device_dep(ACPI_HANDLE(dev1), ACPI_HANDLE(dev2))) device_link_add(dev1, dev2, link->flags); put_device(dev2); diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 0f5218e361df5c..4fe2ef54088c65 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -184,24 +184,6 @@ static void __init acpi_pcc_cpufreq_init(void) {} /* Initialization */ #ifdef CONFIG_ACPI_HOTPLUG_CPU -int __weak acpi_map_cpu(acpi_handle handle, - phys_cpuid_t physid, u32 acpi_id, int *pcpu) -{ - return -ENODEV; -} - -int __weak acpi_unmap_cpu(int cpu) -{ - return -ENODEV; -} - -int __weak arch_register_cpu(int cpu) -{ - return -ENODEV; -} - -void __weak arch_unregister_cpu(int cpu) {} - static int acpi_processor_hotadd_init(struct acpi_processor *pr) { unsigned long long sta; diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index 6cee536c229a63..4afdda9db0195c 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -67,7 +67,7 @@ MODULE_PARM_DESC(hw_changes_brightness, static bool device_id_scheme = false; module_param(device_id_scheme, bool, 0444); -static int only_lcd = -1; +static int only_lcd; module_param(only_lcd, int, 0444); static bool may_report_brightness_keys; @@ -500,6 +500,15 @@ static const struct dmi_system_id video_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3350"), }, }, + { + .callback = video_set_report_key_events, + .driver_data = (void *)((uintptr_t)REPORT_BRIGHTNESS_KEY_EVENTS), + .ident = "COLORFUL X15 AT 23", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "COLORFUL"), + DMI_MATCH(DMI_PRODUCT_NAME, "X15 AT 23"), + }, + }, /* * Some machines change the brightness themselves when a brightness * hotkey gets pressed, despite us telling them not to. In this case @@ -1713,12 +1722,12 @@ static void acpi_video_dev_register_backlight(struct acpi_video_device *device) return; count++; - acpi_get_parent(device->dev->handle, &acpi_parent); - - pdev = acpi_get_pci_dev(acpi_parent); - if (pdev) { - parent = &pdev->dev; - pci_dev_put(pdev); + if (ACPI_SUCCESS(acpi_get_parent(device->dev->handle, &acpi_parent))) { + pdev = acpi_get_pci_dev(acpi_parent); + if (pdev) { + parent = &pdev->dev; + pci_dev_put(pdev); + } } memset(&props, 0, sizeof(struct backlight_properties)); @@ -2137,57 +2146,6 @@ static int __init intel_opregion_present(void) return opregion; } -/* Check if the chassis-type indicates there is no builtin LCD panel */ -static bool dmi_is_desktop(void) -{ - const char *chassis_type; - unsigned long type; - - chassis_type = dmi_get_system_info(DMI_CHASSIS_TYPE); - if (!chassis_type) - return false; - - if (kstrtoul(chassis_type, 10, &type) != 0) - return false; - - switch (type) { - case 0x03: /* Desktop */ - case 0x04: /* Low Profile Desktop */ - case 0x05: /* Pizza Box */ - case 0x06: /* Mini Tower */ - case 0x07: /* Tower */ - case 0x10: /* Lunch Box */ - case 0x11: /* Main Server Chassis */ - return true; - } - - return false; -} - -/* - * We're seeing a lot of bogus backlight interfaces on newer machines - * without a LCD such as desktops, servers and HDMI sticks. Checking the - * lcd flag fixes this, enable this by default on any machines which are: - * 1. Win8 ready (where we also prefer the native backlight driver, so - * normally the acpi_video code should not register there anyways); *and* - * 2.1 Report a desktop/server DMI chassis-type, or - * 2.2 Are an ACPI-reduced-hardware platform (and thus won't use the EC for - backlight control) - */ -static bool should_check_lcd_flag(void) -{ - if (!acpi_osi_is_win8()) - return false; - - if (dmi_is_desktop()) - return true; - - if (acpi_reduced_hardware()) - return true; - - return false; -} - int acpi_video_register(void) { int ret = 0; @@ -2201,9 +2159,6 @@ int acpi_video_register(void) goto leave; } - if (only_lcd == -1) - only_lcd = should_check_lcd_flag(); - dmi_check_system(video_dmi_table); ret = acpi_bus_register_driver(&acpi_video_bus); diff --git a/drivers/acpi/acpi_watchdog.c b/drivers/acpi/acpi_watchdog.c index ca28183f4d1329..8e9e001da38f54 100644 --- a/drivers/acpi/acpi_watchdog.c +++ b/drivers/acpi/acpi_watchdog.c @@ -81,7 +81,7 @@ static const struct acpi_table_wdat *acpi_watchdog_get_wdat(void) return wdat; } -/** +/* * Returns true if this system should prefer ACPI based watchdog instead of * the native one (which are typically the same hardware). */ diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c index 013eb621dc92a7..89fb9331c611e4 100644 --- a/drivers/acpi/apei/einj.c +++ b/drivers/acpi/apei/einj.c @@ -73,6 +73,7 @@ static u32 notrigger; static u32 vendor_flags; static struct debugfs_blob_wrapper vendor_blob; +static struct debugfs_blob_wrapper vendor_errors; static char vendor_dev[64]; /* @@ -182,6 +183,21 @@ static int einj_timedout(u64 *t) return 0; } +static void get_oem_vendor_struct(u64 paddr, int offset, + struct vendor_error_type_extension *v) +{ + unsigned long vendor_size; + u64 target_pa = paddr + offset + sizeof(struct vendor_error_type_extension); + + vendor_size = v->length - sizeof(struct vendor_error_type_extension); + + if (vendor_size) + vendor_errors.data = acpi_os_map_memory(target_pa, vendor_size); + + if (vendor_errors.data) + vendor_errors.size = vendor_size; +} + static void check_vendor_extension(u64 paddr, struct set_error_type_with_address *v5param) { @@ -194,6 +210,7 @@ static void check_vendor_extension(u64 paddr, v = acpi_os_map_iomem(paddr + offset, sizeof(*v)); if (!v) return; + get_oem_vendor_struct(paddr, offset, v); sbdf = v->pcie_sbdf; sprintf(vendor_dev, "%x:%x:%x.%x vendor_id=%x device_id=%x rev_id=%x\n", sbdf >> 24, (sbdf >> 16) & 0xff, @@ -577,38 +594,40 @@ static u64 error_param2; static u64 error_param3; static u64 error_param4; static struct dentry *einj_debug_dir; -static const char * const einj_error_type_string[] = { - "0x00000001\tProcessor Correctable\n", - "0x00000002\tProcessor Uncorrectable non-fatal\n", - "0x00000004\tProcessor Uncorrectable fatal\n", - "0x00000008\tMemory Correctable\n", - "0x00000010\tMemory Uncorrectable non-fatal\n", - "0x00000020\tMemory Uncorrectable fatal\n", - "0x00000040\tPCI Express Correctable\n", - "0x00000080\tPCI Express Uncorrectable non-fatal\n", - "0x00000100\tPCI Express Uncorrectable fatal\n", - "0x00000200\tPlatform Correctable\n", - "0x00000400\tPlatform Uncorrectable non-fatal\n", - "0x00000800\tPlatform Uncorrectable fatal\n", - "0x00001000\tCXL.cache Protocol Correctable\n", - "0x00002000\tCXL.cache Protocol Uncorrectable non-fatal\n", - "0x00004000\tCXL.cache Protocol Uncorrectable fatal\n", - "0x00008000\tCXL.mem Protocol Correctable\n", - "0x00010000\tCXL.mem Protocol Uncorrectable non-fatal\n", - "0x00020000\tCXL.mem Protocol Uncorrectable fatal\n", +static struct { u32 mask; const char *str; } const einj_error_type_string[] = { + { BIT(0), "Processor Correctable" }, + { BIT(1), "Processor Uncorrectable non-fatal" }, + { BIT(2), "Processor Uncorrectable fatal" }, + { BIT(3), "Memory Correctable" }, + { BIT(4), "Memory Uncorrectable non-fatal" }, + { BIT(5), "Memory Uncorrectable fatal" }, + { BIT(6), "PCI Express Correctable" }, + { BIT(7), "PCI Express Uncorrectable non-fatal" }, + { BIT(8), "PCI Express Uncorrectable fatal" }, + { BIT(9), "Platform Correctable" }, + { BIT(10), "Platform Uncorrectable non-fatal" }, + { BIT(11), "Platform Uncorrectable fatal"}, + { BIT(12), "CXL.cache Protocol Correctable" }, + { BIT(13), "CXL.cache Protocol Uncorrectable non-fatal" }, + { BIT(14), "CXL.cache Protocol Uncorrectable fatal" }, + { BIT(15), "CXL.mem Protocol Correctable" }, + { BIT(16), "CXL.mem Protocol Uncorrectable non-fatal" }, + { BIT(17), "CXL.mem Protocol Uncorrectable fatal" }, + { BIT(31), "Vendor Defined Error Types" }, }; static int available_error_type_show(struct seq_file *m, void *v) { int rc; - u32 available_error_type = 0; + u32 error_type = 0; - rc = einj_get_available_error_type(&available_error_type); + rc = einj_get_available_error_type(&error_type); if (rc) return rc; for (int pos = 0; pos < ARRAY_SIZE(einj_error_type_string); pos++) - if (available_error_type & BIT(pos)) - seq_puts(m, einj_error_type_string[pos]); + if (error_type & einj_error_type_string[pos].mask) + seq_printf(m, "0x%08x\t%s\n", einj_error_type_string[pos].mask, + einj_error_type_string[pos].str); return 0; } @@ -767,6 +786,10 @@ static int __init einj_init(void) einj_debug_dir, &vendor_flags); } + if (vendor_errors.size) + debugfs_create_blob("oem_error", 0600, einj_debug_dir, + &vendor_errors); + pr_info("Error INJection is initialized.\n"); return 0; @@ -792,6 +815,8 @@ static void __exit einj_exit(void) sizeof(struct einj_parameter); acpi_os_unmap_iomem(einj_param, size); + if (vendor_errors.size) + acpi_os_unmap_memory(vendor_errors.data, vendor_errors.size); } einj_exec_ctx_init(&ctx); apei_exec_post_unmap_gars(&ctx); diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 63ad0541db3817..7b7c605166e0c1 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -101,6 +102,20 @@ static inline bool is_hest_type_generic_v2(struct ghes *ghes) return ghes->generic->header.type == ACPI_HEST_TYPE_GENERIC_ERROR_V2; } +/* + * A platform may describe one error source for the handling of synchronous + * errors (e.g. MCE or SEA), or for handling asynchronous errors (e.g. SCI + * or External Interrupt). On x86, the HEST notifications are always + * asynchronous, so only SEA on ARM is delivered as a synchronous + * notification. + */ +static inline bool is_hest_sync_notify(struct ghes *ghes) +{ + u8 notify_type = ghes->generic->notify.type; + + return notify_type == ACPI_HEST_NOTIFY_SEA; +} + /* * This driver isn't really modular, however for the time being, * continuing to use module_param is the easiest way to remain @@ -489,7 +504,7 @@ static bool ghes_do_memory_failure(u64 physical_addr, int flags) } static bool ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, - int sev) + int sev, bool sync) { int flags = -1; int sec_sev = ghes_severity(gdata->error_severity); @@ -503,7 +518,7 @@ static bool ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, (gdata->flags & CPER_SEC_ERROR_THRESHOLD_EXCEEDED)) flags = MF_SOFT_OFFLINE; if (sev == GHES_SEV_RECOVERABLE && sec_sev == GHES_SEV_RECOVERABLE) - flags = 0; + flags = sync ? MF_ACTION_REQUIRED : 0; if (flags != -1) return ghes_do_memory_failure(mem_err->physical_addr, flags); @@ -511,9 +526,11 @@ static bool ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, return false; } -static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata, int sev) +static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata, + int sev, bool sync) { struct cper_sec_proc_arm *err = acpi_hest_get_payload(gdata); + int flags = sync ? MF_ACTION_REQUIRED : 0; bool queued = false; int sec_sev, i; char *p; @@ -538,7 +555,7 @@ static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata, int s * and don't filter out 'corrected' error here. */ if (is_cache && has_pa) { - queued = ghes_do_memory_failure(err_info->physical_fault_addr, 0); + queued = ghes_do_memory_failure(err_info->physical_fault_addr, flags); p += err_info->length; continue; } @@ -657,6 +674,78 @@ static void ghes_defer_non_standard_event(struct acpi_hest_generic_data *gdata, schedule_work(&entry->work); } +/* + * Only a single callback can be registered for CXL CPER events. + */ +static DECLARE_RWSEM(cxl_cper_rw_sem); +static cxl_cper_callback cper_callback; + +/* CXL Event record UUIDs are formatted as GUIDs and reported in section type */ + +/* + * General Media Event Record + * CXL rev 3.0 Section 8.2.9.2.1.1; Table 8-43 + */ +#define CPER_SEC_CXL_GEN_MEDIA_GUID \ + GUID_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 + */ +#define CPER_SEC_CXL_DRAM_GUID \ + GUID_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 + */ +#define CPER_SEC_CXL_MEM_MODULE_GUID \ + GUID_INIT(0xfe927475, 0xdd59, 0x4339, \ + 0xa5, 0x86, 0x79, 0xba, 0xb1, 0x13, 0xb7, 0x74) + +static void cxl_cper_post_event(enum cxl_event_type event_type, + struct cxl_cper_event_rec *rec) +{ + if (rec->hdr.length <= sizeof(rec->hdr) || + rec->hdr.length > sizeof(*rec)) { + pr_err(FW_WARN "CXL CPER Invalid section length (%u)\n", + rec->hdr.length); + return; + } + + if (!(rec->hdr.validation_bits & CPER_CXL_COMP_EVENT_LOG_VALID)) { + pr_err(FW_WARN "CXL CPER invalid event\n"); + return; + } + + guard(rwsem_read)(&cxl_cper_rw_sem); + if (cper_callback) + cper_callback(event_type, rec); +} + +int cxl_cper_register_callback(cxl_cper_callback callback) +{ + guard(rwsem_write)(&cxl_cper_rw_sem); + if (cper_callback) + return -EINVAL; + cper_callback = callback; + return 0; +} +EXPORT_SYMBOL_NS_GPL(cxl_cper_register_callback, CXL); + +int cxl_cper_unregister_callback(cxl_cper_callback callback) +{ + guard(rwsem_write)(&cxl_cper_rw_sem); + if (callback != cper_callback) + return -EINVAL; + cper_callback = NULL; + return 0; +} +EXPORT_SYMBOL_NS_GPL(cxl_cper_unregister_callback, CXL); + static bool ghes_do_proc(struct ghes *ghes, const struct acpi_hest_generic_status *estatus) { @@ -666,6 +755,7 @@ static bool ghes_do_proc(struct ghes *ghes, const guid_t *fru_id = &guid_null; char *fru_text = ""; bool queued = false; + bool sync = is_hest_sync_notify(ghes); sev = ghes_severity(estatus->error_severity); apei_estatus_for_each_section(estatus, gdata) { @@ -683,13 +773,29 @@ static bool ghes_do_proc(struct ghes *ghes, atomic_notifier_call_chain(&ghes_report_chain, sev, mem_err); arch_apei_report_mem_error(sev, mem_err); - queued = ghes_handle_memory_failure(gdata, sev); + queued = ghes_handle_memory_failure(gdata, sev, sync); } else if (guid_equal(sec_type, &CPER_SEC_PCIE)) { ghes_handle_aer(gdata); } else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) { - queued = ghes_handle_arm_hw_error(gdata, sev); + queued = ghes_handle_arm_hw_error(gdata, sev, sync); + } else if (guid_equal(sec_type, &CPER_SEC_CXL_GEN_MEDIA_GUID)) { + struct cxl_cper_event_rec *rec = + acpi_hest_get_payload(gdata); + + cxl_cper_post_event(CXL_CPER_EVENT_GEN_MEDIA, rec); + } else if (guid_equal(sec_type, &CPER_SEC_CXL_DRAM_GUID)) { + struct cxl_cper_event_rec *rec = + acpi_hest_get_payload(gdata); + + cxl_cper_post_event(CXL_CPER_EVENT_DRAM, rec); + } else if (guid_equal(sec_type, + &CPER_SEC_CXL_MEM_MODULE_GUID)) { + struct cxl_cper_event_rec *rec = + acpi_hest_get_payload(gdata); + + cxl_cper_post_event(CXL_CPER_EVENT_MEM_MODULE, rec); } else { void *err = acpi_hest_get_payload(gdata); diff --git a/drivers/acpi/arm64/Makefile b/drivers/acpi/arm64/Makefile index 143debc1ba4a9d..726944648c9bce 100644 --- a/drivers/acpi/arm64/Makefile +++ b/drivers/acpi/arm64/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_ACPI_GTDT) += gtdt.o obj-$(CONFIG_ACPI_APMT) += apmt.o obj-$(CONFIG_ARM_AMBA) += amba.o obj-y += dma.o init.o +obj-y += thermal_cpufreq.o diff --git a/drivers/acpi/arm64/thermal_cpufreq.c b/drivers/acpi/arm64/thermal_cpufreq.c new file mode 100644 index 00000000000000..582854914c5cdd --- /dev/null +++ b/drivers/acpi/arm64/thermal_cpufreq.c @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include + +#include "../internal.h" + +#define SMCCC_SOC_ID_T241 0x036b0241 + +int acpi_arch_thermal_cpufreq_pctg(void) +{ + s32 soc_id = arm_smccc_get_soc_id_version(); + + /* + * Check JEP106 code for NVIDIA Tegra241 chip (036b:0241) and + * reduce the CPUFREQ Thermal reduction percentage to 5%. + */ + if (soc_id == SMCCC_SOC_ID_T241) + return 5; + + return 0; +} +EXPORT_SYMBOL_GPL(acpi_arch_thermal_cpufreq_pctg); diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 72e64c0718c9a3..569bd15f211be9 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -408,7 +408,7 @@ static void acpi_bus_decode_usb_osc(const char *msg, u32 bits) static u8 sb_usb_uuid_str[] = "23A0D13A-26AB-486C-9C5F-0FFA525A575A"; static void acpi_bus_osc_negotiate_usb_control(void) { - u32 capbuf[3]; + u32 capbuf[3], *capbuf_ret; struct acpi_osc_context context = { .uuid_str = sb_usb_uuid_str, .rev = 1, @@ -428,7 +428,12 @@ static void acpi_bus_osc_negotiate_usb_control(void) control = OSC_USB_USB3_TUNNELING | OSC_USB_DP_TUNNELING | OSC_USB_PCIE_TUNNELING | OSC_USB_XDOMAIN; - capbuf[OSC_QUERY_DWORD] = 0; + /* + * Run _OSC first with query bit set, trying to get control over + * all tunneling. The platform can then clear out bits in the + * control dword that it does not want to grant to the OS. + */ + capbuf[OSC_QUERY_DWORD] = OSC_QUERY_ENABLE; capbuf[OSC_SUPPORT_DWORD] = 0; capbuf[OSC_CONTROL_DWORD] = control; @@ -441,8 +446,29 @@ static void acpi_bus_osc_negotiate_usb_control(void) goto out_free; } + /* + * Run _OSC again now with query bit clear and the control dword + * matching what the platform granted (which may not have all + * the control bits set). + */ + capbuf_ret = context.ret.pointer; + + capbuf[OSC_QUERY_DWORD] = 0; + capbuf[OSC_CONTROL_DWORD] = capbuf_ret[OSC_CONTROL_DWORD]; + + kfree(context.ret.pointer); + + status = acpi_run_osc(handle, &context); + if (ACPI_FAILURE(status)) + return; + + if (context.ret.length != sizeof(capbuf)) { + pr_info("USB4 _OSC: returned invalid length buffer\n"); + goto out_free; + } + osc_sb_native_usb4_control = - control & acpi_osc_ctx_get_pci_control(&context); + control & acpi_osc_ctx_get_pci_control(&context); acpi_bus_decode_usb_osc("USB4 _OSC: OS supports", control); acpi_bus_decode_usb_osc("USB4 _OSC: OS controls", diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 1e76a64cce0a91..cc61020756beb8 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -480,6 +480,7 @@ static int acpi_button_suspend(struct device *dev) static int acpi_button_resume(struct device *dev) { + struct input_dev *input; struct acpi_device *device = to_acpi_device(dev); struct acpi_button *button = acpi_driver_data(device); @@ -489,6 +490,14 @@ static int acpi_button_resume(struct device *dev) button->last_time = ktime_get(); acpi_lid_initialize_state(device); } + + if (button->type == ACPI_BUTTON_TYPE_POWER) { + input = button->input; + input_report_key(input, KEY_WAKEUP, 1); + input_sync(input); + input_report_key(input, KEY_WAKEUP, 0); + input_sync(input); + } return 0; } #endif @@ -579,6 +588,7 @@ static int acpi_button_add(struct acpi_device *device) switch (button->type) { case ACPI_BUTTON_TYPE_POWER: input_set_capability(input, EV_KEY, KEY_POWER); + input_set_capability(input, EV_KEY, KEY_WAKEUP); break; case ACPI_BUTTON_TYPE_SLEEP: diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index 7ff269a78c2088..d155a86a861483 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -39,6 +39,9 @@ #include #include #include +#include +#include +#include #include @@ -1760,3 +1763,104 @@ unsigned int cppc_get_transition_latency(int cpu_num) return latency_ns; } EXPORT_SYMBOL_GPL(cppc_get_transition_latency); + +/* Minimum struct length needed for the DMI processor entry we want */ +#define DMI_ENTRY_PROCESSOR_MIN_LENGTH 48 + +/* Offset in the DMI processor structure for the max frequency */ +#define DMI_PROCESSOR_MAX_SPEED 0x14 + +/* Callback function used to retrieve the max frequency from DMI */ +static void cppc_find_dmi_mhz(const struct dmi_header *dm, void *private) +{ + const u8 *dmi_data = (const u8 *)dm; + u16 *mhz = (u16 *)private; + + if (dm->type == DMI_ENTRY_PROCESSOR && + dm->length >= DMI_ENTRY_PROCESSOR_MIN_LENGTH) { + u16 val = (u16)get_unaligned((const u16 *) + (dmi_data + DMI_PROCESSOR_MAX_SPEED)); + *mhz = val > *mhz ? val : *mhz; + } +} + +/* Look up the max frequency in DMI */ +static u64 cppc_get_dmi_max_khz(void) +{ + u16 mhz = 0; + + dmi_walk(cppc_find_dmi_mhz, &mhz); + + /* + * Real stupid fallback value, just in case there is no + * actual value set. + */ + mhz = mhz ? mhz : 1; + + return KHZ_PER_MHZ * mhz; +} + +/* + * If CPPC lowest_freq and nominal_freq registers are exposed then we can + * use them to convert perf to freq and vice versa. The conversion is + * extrapolated as an affine function passing by the 2 points: + * - (Low perf, Low freq) + * - (Nominal perf, Nominal freq) + */ +unsigned int cppc_perf_to_khz(struct cppc_perf_caps *caps, unsigned int perf) +{ + s64 retval, offset = 0; + static u64 max_khz; + u64 mul, div; + + if (caps->lowest_freq && caps->nominal_freq) { + mul = caps->nominal_freq - caps->lowest_freq; + mul *= KHZ_PER_MHZ; + div = caps->nominal_perf - caps->lowest_perf; + offset = caps->nominal_freq * KHZ_PER_MHZ - + div64_u64(caps->nominal_perf * mul, div); + } else { + if (!max_khz) + max_khz = cppc_get_dmi_max_khz(); + mul = max_khz; + div = caps->highest_perf; + } + + retval = offset + div64_u64(perf * mul, div); + if (retval >= 0) + return retval; + return 0; +} +EXPORT_SYMBOL_GPL(cppc_perf_to_khz); + +unsigned int cppc_khz_to_perf(struct cppc_perf_caps *caps, unsigned int freq) +{ + s64 retval, offset = 0; + static u64 max_khz; + u64 mul, div; + + if (caps->lowest_freq && caps->nominal_freq) { + mul = caps->nominal_perf - caps->lowest_perf; + div = caps->nominal_freq - caps->lowest_freq; + /* + * We don't need to convert to kHz for computing offset and can + * directly use nominal_freq and lowest_freq as the div64_u64 + * will remove the frequency unit. + */ + offset = caps->nominal_perf - + div64_u64(caps->nominal_freq * mul, div); + /* But we need it for computing the perf level. */ + div *= KHZ_PER_MHZ; + } else { + if (!max_khz) + max_khz = cppc_get_dmi_max_khz(); + mul = caps->highest_perf; + div = max_khz; + } + + retval = offset + div64_u64(freq * mul, div); + if (retval >= 0) + return retval; + return 0; +} +EXPORT_SYMBOL_GPL(cppc_khz_to_perf); diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index a59c11df737542..dbdee2924594a9 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -525,12 +525,10 @@ static void acpi_ec_clear(struct acpi_ec *ec) static void acpi_ec_enable_event(struct acpi_ec *ec) { - unsigned long flags; - - spin_lock_irqsave(&ec->lock, flags); + spin_lock(&ec->lock); if (acpi_ec_started(ec)) __acpi_ec_enable_event(ec); - spin_unlock_irqrestore(&ec->lock, flags); + spin_unlock(&ec->lock); /* Drain additional events if hardware requires that */ if (EC_FLAGS_CLEAR_ON_RESUME) @@ -546,11 +544,9 @@ static void __acpi_ec_flush_work(void) static void acpi_ec_disable_event(struct acpi_ec *ec) { - unsigned long flags; - - spin_lock_irqsave(&ec->lock, flags); + spin_lock(&ec->lock); __acpi_ec_disable_event(ec); - spin_unlock_irqrestore(&ec->lock, flags); + spin_unlock(&ec->lock); /* * When ec_freeze_events is true, we need to flush events in @@ -571,10 +567,9 @@ void acpi_ec_flush_work(void) static bool acpi_ec_guard_event(struct acpi_ec *ec) { - unsigned long flags; bool guarded; - spin_lock_irqsave(&ec->lock, flags); + spin_lock(&ec->lock); /* * If firmware SCI_EVT clearing timing is "event", we actually * don't know when the SCI_EVT will be cleared by firmware after @@ -590,31 +585,29 @@ static bool acpi_ec_guard_event(struct acpi_ec *ec) guarded = ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT && ec->event_state != EC_EVENT_READY && (!ec->curr || ec->curr->command != ACPI_EC_COMMAND_QUERY); - spin_unlock_irqrestore(&ec->lock, flags); + spin_unlock(&ec->lock); return guarded; } static int ec_transaction_polled(struct acpi_ec *ec) { - unsigned long flags; int ret = 0; - spin_lock_irqsave(&ec->lock, flags); + spin_lock(&ec->lock); if (ec->curr && (ec->curr->flags & ACPI_EC_COMMAND_POLL)) ret = 1; - spin_unlock_irqrestore(&ec->lock, flags); + spin_unlock(&ec->lock); return ret; } static int ec_transaction_completed(struct acpi_ec *ec) { - unsigned long flags; int ret = 0; - spin_lock_irqsave(&ec->lock, flags); + spin_lock(&ec->lock); if (ec->curr && (ec->curr->flags & ACPI_EC_COMMAND_COMPLETE)) ret = 1; - spin_unlock_irqrestore(&ec->lock, flags); + spin_unlock(&ec->lock); return ret; } @@ -756,7 +749,6 @@ static int ec_guard(struct acpi_ec *ec) static int ec_poll(struct acpi_ec *ec) { - unsigned long flags; int repeat = 5; /* number of command restarts */ while (repeat--) { @@ -765,14 +757,14 @@ static int ec_poll(struct acpi_ec *ec) do { if (!ec_guard(ec)) return 0; - spin_lock_irqsave(&ec->lock, flags); + spin_lock(&ec->lock); advance_transaction(ec, false); - spin_unlock_irqrestore(&ec->lock, flags); + spin_unlock(&ec->lock); } while (time_before(jiffies, delay)); pr_debug("controller reset, restart transaction\n"); - spin_lock_irqsave(&ec->lock, flags); + spin_lock(&ec->lock); start_transaction(ec); - spin_unlock_irqrestore(&ec->lock, flags); + spin_unlock(&ec->lock); } return -ETIME; } @@ -780,11 +772,10 @@ static int ec_poll(struct acpi_ec *ec) static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, struct transaction *t) { - unsigned long tmp; int ret = 0; /* start transaction */ - spin_lock_irqsave(&ec->lock, tmp); + spin_lock(&ec->lock); /* Enable GPE for command processing (IBF=0/OBF=1) */ if (!acpi_ec_submit_flushable_request(ec)) { ret = -EINVAL; @@ -795,11 +786,11 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, ec->curr = t; ec_dbg_req("Command(%s) started", acpi_ec_cmd_string(t->command)); start_transaction(ec); - spin_unlock_irqrestore(&ec->lock, tmp); + spin_unlock(&ec->lock); ret = ec_poll(ec); - spin_lock_irqsave(&ec->lock, tmp); + spin_lock(&ec->lock); if (t->irq_count == ec_storm_threshold) acpi_ec_unmask_events(ec); ec_dbg_req("Command(%s) stopped", acpi_ec_cmd_string(t->command)); @@ -808,7 +799,7 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, acpi_ec_complete_request(ec); ec_dbg_ref(ec, "Decrease command"); unlock: - spin_unlock_irqrestore(&ec->lock, tmp); + spin_unlock(&ec->lock); return ret; } @@ -936,9 +927,7 @@ EXPORT_SYMBOL(ec_get_handle); static void acpi_ec_start(struct acpi_ec *ec, bool resuming) { - unsigned long flags; - - spin_lock_irqsave(&ec->lock, flags); + spin_lock(&ec->lock); if (!test_and_set_bit(EC_FLAGS_STARTED, &ec->flags)) { ec_dbg_drv("Starting EC"); /* Enable GPE for event processing (SCI_EVT=1) */ @@ -948,31 +937,28 @@ static void acpi_ec_start(struct acpi_ec *ec, bool resuming) } ec_log_drv("EC started"); } - spin_unlock_irqrestore(&ec->lock, flags); + spin_unlock(&ec->lock); } static bool acpi_ec_stopped(struct acpi_ec *ec) { - unsigned long flags; bool flushed; - spin_lock_irqsave(&ec->lock, flags); + spin_lock(&ec->lock); flushed = acpi_ec_flushed(ec); - spin_unlock_irqrestore(&ec->lock, flags); + spin_unlock(&ec->lock); return flushed; } static void acpi_ec_stop(struct acpi_ec *ec, bool suspending) { - unsigned long flags; - - spin_lock_irqsave(&ec->lock, flags); + spin_lock(&ec->lock); if (acpi_ec_started(ec)) { ec_dbg_drv("Stopping EC"); set_bit(EC_FLAGS_STOPPED, &ec->flags); - spin_unlock_irqrestore(&ec->lock, flags); + spin_unlock(&ec->lock); wait_event(ec->wait, acpi_ec_stopped(ec)); - spin_lock_irqsave(&ec->lock, flags); + spin_lock(&ec->lock); /* Disable GPE for event processing (SCI_EVT=1) */ if (!suspending) { acpi_ec_complete_request(ec); @@ -983,29 +969,25 @@ static void acpi_ec_stop(struct acpi_ec *ec, bool suspending) clear_bit(EC_FLAGS_STOPPED, &ec->flags); ec_log_drv("EC stopped"); } - spin_unlock_irqrestore(&ec->lock, flags); + spin_unlock(&ec->lock); } static void acpi_ec_enter_noirq(struct acpi_ec *ec) { - unsigned long flags; - - spin_lock_irqsave(&ec->lock, flags); + spin_lock(&ec->lock); ec->busy_polling = true; ec->polling_guard = 0; ec_log_drv("interrupt blocked"); - spin_unlock_irqrestore(&ec->lock, flags); + spin_unlock(&ec->lock); } static void acpi_ec_leave_noirq(struct acpi_ec *ec) { - unsigned long flags; - - spin_lock_irqsave(&ec->lock, flags); + spin_lock(&ec->lock); ec->busy_polling = ec_busy_polling; ec->polling_guard = ec_polling_guard; ec_log_drv("interrupt unblocked"); - spin_unlock_irqrestore(&ec->lock, flags); + spin_unlock(&ec->lock); } void acpi_ec_block_transactions(void) @@ -1137,9 +1119,9 @@ static void acpi_ec_event_processor(struct work_struct *work) ec_dbg_evt("Query(0x%02x) stopped", handler->query_bit); - spin_lock_irq(&ec->lock); + spin_lock(&ec->lock); ec->queries_in_progress--; - spin_unlock_irq(&ec->lock); + spin_unlock(&ec->lock); acpi_ec_put_query_handler(handler); kfree(q); @@ -1202,12 +1184,12 @@ static int acpi_ec_submit_query(struct acpi_ec *ec) */ ec_dbg_evt("Query(0x%02x) scheduled", value); - spin_lock_irq(&ec->lock); + spin_lock(&ec->lock); ec->queries_in_progress++; queue_work(ec_query_wq, &q->work); - spin_unlock_irq(&ec->lock); + spin_unlock(&ec->lock); return 0; @@ -1223,14 +1205,14 @@ static void acpi_ec_event_handler(struct work_struct *work) ec_dbg_evt("Event started"); - spin_lock_irq(&ec->lock); + spin_lock(&ec->lock); while (ec->events_to_process) { - spin_unlock_irq(&ec->lock); + spin_unlock(&ec->lock); acpi_ec_submit_query(ec); - spin_lock_irq(&ec->lock); + spin_lock(&ec->lock); ec->events_to_process--; } @@ -1247,11 +1229,11 @@ static void acpi_ec_event_handler(struct work_struct *work) ec_dbg_evt("Event stopped"); - spin_unlock_irq(&ec->lock); + spin_unlock(&ec->lock); guard_timeout = !!ec_guard(ec); - spin_lock_irq(&ec->lock); + spin_lock(&ec->lock); /* Take care of SCI_EVT unless someone else is doing that. */ if (guard_timeout && !ec->curr) @@ -1264,7 +1246,7 @@ static void acpi_ec_event_handler(struct work_struct *work) ec->events_in_progress--; - spin_unlock_irq(&ec->lock); + spin_unlock(&ec->lock); } static void clear_gpe_and_advance_transaction(struct acpi_ec *ec, bool interrupt) @@ -1289,13 +1271,11 @@ static void clear_gpe_and_advance_transaction(struct acpi_ec *ec, bool interrupt static void acpi_ec_handle_interrupt(struct acpi_ec *ec) { - unsigned long flags; - - spin_lock_irqsave(&ec->lock, flags); + spin_lock(&ec->lock); clear_gpe_and_advance_transaction(ec, true); - spin_unlock_irqrestore(&ec->lock, flags); + spin_unlock(&ec->lock); } static u32 acpi_ec_gpe_handler(acpi_handle gpe_device, @@ -1458,8 +1438,8 @@ static bool install_gpe_event_handler(struct acpi_ec *ec) static bool install_gpio_irq_event_handler(struct acpi_ec *ec) { - return request_irq(ec->irq, acpi_ec_irq_handler, IRQF_SHARED, - "ACPI EC", ec) >= 0; + return request_threaded_irq(ec->irq, NULL, acpi_ec_irq_handler, + IRQF_SHARED | IRQF_ONESHOT, "ACPI EC", ec) >= 0; } /** @@ -2105,7 +2085,7 @@ bool acpi_ec_dispatch_gpe(void) * Dispatch the EC GPE in-band, but do not report wakeup in any case * to allow the caller to process events properly after that. */ - spin_lock_irq(&first_ec->lock); + spin_lock(&first_ec->lock); if (acpi_ec_gpe_status_set(first_ec)) { pm_pr_dbg("ACPI EC GPE status set\n"); @@ -2114,7 +2094,7 @@ bool acpi_ec_dispatch_gpe(void) work_in_progress = acpi_ec_work_in_progress(first_ec); } - spin_unlock_irq(&first_ec->lock); + spin_unlock(&first_ec->lock); if (!work_in_progress) return false; @@ -2127,11 +2107,11 @@ bool acpi_ec_dispatch_gpe(void) pm_pr_dbg("ACPI EC work flushed\n"); - spin_lock_irq(&first_ec->lock); + spin_lock(&first_ec->lock); work_in_progress = acpi_ec_work_in_progress(first_ec); - spin_unlock_irq(&first_ec->lock); + spin_unlock(&first_ec->lock); } while (work_in_progress && !pm_wakeup_pending()); return false; diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 866c7c4ed23317..6588525c45efaa 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -85,6 +85,20 @@ bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent); acpi_status acpi_sysfs_table_handler(u32 event, void *table, void *context); void acpi_scan_table_notify(void); +int acpi_active_trip_temp(struct acpi_device *adev, int id, int *ret_temp); +int acpi_passive_trip_temp(struct acpi_device *adev, int *ret_temp); +int acpi_hot_trip_temp(struct acpi_device *adev, int *ret_temp); +int acpi_critical_trip_temp(struct acpi_device *adev, int *ret_temp); + +#ifdef CONFIG_ARM64 +int acpi_arch_thermal_cpufreq_pctg(void); +#else +static inline int acpi_arch_thermal_cpufreq_pctg(void) +{ + return 0; +} +#endif + /* -------------------------------------------------------------------------- Device Node Initialization / Removal -------------------------------------------------------------------------- */ @@ -148,8 +162,11 @@ int acpi_wakeup_device_init(void); #ifdef CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC void acpi_early_processor_control_setup(void); void acpi_early_processor_set_pdc(void); - +#ifdef CONFIG_X86 void acpi_proc_quirk_mwait_check(void); +#else +static inline void acpi_proc_quirk_mwait_check(void) {} +#endif bool processor_physically_present(acpi_handle handle); #else static inline void acpi_early_processor_control_setup(void) {} @@ -276,4 +293,13 @@ void acpi_init_lpit(void); static inline void acpi_init_lpit(void) { } #endif +/*-------------------------------------------------------------------------- + ACPI _CRS CSI-2 and MIPI DisCo for Imaging + -------------------------------------------------------------------------- */ + +void acpi_mipi_check_crs_csi2(acpi_handle handle); +void acpi_mipi_scan_crs_csi2(void); +void acpi_mipi_init_crs_csi2_swnodes(void); +void acpi_mipi_crs_csi2_cleanup(void); + #endif /* _ACPI_INTERNAL_H_ */ diff --git a/drivers/acpi/mipi-disco-img.c b/drivers/acpi/mipi-disco-img.c new file mode 100644 index 00000000000000..7286cf4579bcfb --- /dev/null +++ b/drivers/acpi/mipi-disco-img.c @@ -0,0 +1,725 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * MIPI DisCo for Imaging support. + * + * Copyright (C) 2023 Intel Corporation + * + * Support MIPI DisCo for Imaging by parsing ACPI _CRS CSI-2 records defined in + * Section 6.4.3.8.2.4 "Camera Serial Interface (CSI-2) Connection Resource + * Descriptor" of ACPI 6.5 and using device properties defined by the MIPI DisCo + * for Imaging specification. + * + * The implementation looks for the information in the ACPI namespace (CSI-2 + * resource descriptors in _CRS) and constructs software nodes compatible with + * Documentation/firmware-guide/acpi/dsd/graph.rst to represent the CSI-2 + * connection graph. The software nodes are then populated with the data + * extracted from the _CRS CSI-2 resource descriptors and the MIPI DisCo + * for Imaging device properties present in _DSD for the ACPI device objects + * with CSI-2 connections. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "internal.h" + +static LIST_HEAD(acpi_mipi_crs_csi2_list); + +static void acpi_mipi_data_tag(acpi_handle handle, void *context) +{ +} + +/* Connection data extracted from one _CRS CSI-2 resource descriptor. */ +struct crs_csi2_connection { + struct list_head entry; + struct acpi_resource_csi2_serialbus csi2_data; + acpi_handle remote_handle; + char remote_name[]; +}; + +/* Data extracted from _CRS CSI-2 resource descriptors for one device. */ +struct crs_csi2 { + struct list_head entry; + acpi_handle handle; + struct acpi_device_software_nodes *swnodes; + struct list_head connections; + u32 port_count; +}; + +struct csi2_resources_walk_data { + acpi_handle handle; + struct list_head connections; +}; + +static acpi_status parse_csi2_resource(struct acpi_resource *res, void *context) +{ + struct csi2_resources_walk_data *crwd = context; + struct acpi_resource_csi2_serialbus *csi2_res; + struct acpi_resource_source *csi2_res_src; + u16 csi2_res_src_length; + struct crs_csi2_connection *conn; + acpi_handle remote_handle; + + if (res->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) + return AE_OK; + + csi2_res = &res->data.csi2_serial_bus; + + if (csi2_res->type != ACPI_RESOURCE_SERIAL_TYPE_CSI2) + return AE_OK; + + csi2_res_src = &csi2_res->resource_source; + if (ACPI_FAILURE(acpi_get_handle(NULL, csi2_res_src->string_ptr, + &remote_handle))) { + acpi_handle_debug(crwd->handle, + "unable to find resource source\n"); + return AE_OK; + } + csi2_res_src_length = csi2_res_src->string_length; + if (!csi2_res_src_length) { + acpi_handle_debug(crwd->handle, + "invalid resource source string length\n"); + return AE_OK; + } + + conn = kmalloc(struct_size(conn, remote_name, csi2_res_src_length + 1), + GFP_KERNEL); + if (!conn) + return AE_OK; + + conn->csi2_data = *csi2_res; + strscpy(conn->remote_name, csi2_res_src->string_ptr, csi2_res_src_length); + conn->csi2_data.resource_source.string_ptr = conn->remote_name; + conn->remote_handle = remote_handle; + + list_add(&conn->entry, &crwd->connections); + + return AE_OK; +} + +static struct crs_csi2 *acpi_mipi_add_crs_csi2(acpi_handle handle, + struct list_head *list) +{ + struct crs_csi2 *csi2; + + csi2 = kzalloc(sizeof(*csi2), GFP_KERNEL); + if (!csi2) + return NULL; + + csi2->handle = handle; + INIT_LIST_HEAD(&csi2->connections); + csi2->port_count = 1; + + if (ACPI_FAILURE(acpi_attach_data(handle, acpi_mipi_data_tag, csi2))) { + kfree(csi2); + return NULL; + } + + list_add(&csi2->entry, list); + + return csi2; +} + +static struct crs_csi2 *acpi_mipi_get_crs_csi2(acpi_handle handle) +{ + struct crs_csi2 *csi2; + + if (ACPI_FAILURE(acpi_get_data_full(handle, acpi_mipi_data_tag, + (void **)&csi2, NULL))) + return NULL; + + return csi2; +} + +static void csi_csr2_release_connections(struct list_head *list) +{ + struct crs_csi2_connection *conn, *conn_tmp; + + list_for_each_entry_safe(conn, conn_tmp, list, entry) { + list_del(&conn->entry); + kfree(conn); + } +} + +static void acpi_mipi_del_crs_csi2(struct crs_csi2 *csi2) +{ + list_del(&csi2->entry); + acpi_detach_data(csi2->handle, acpi_mipi_data_tag); + kfree(csi2->swnodes); + csi_csr2_release_connections(&csi2->connections); + kfree(csi2); +} + +/** + * acpi_mipi_check_crs_csi2 - Look for CSI-2 resources in _CRS + * @handle: Device object handle to evaluate _CRS for. + * + * Find all CSI-2 resource descriptors in the given device's _CRS + * and collect them into a list. + */ +void acpi_mipi_check_crs_csi2(acpi_handle handle) +{ + struct csi2_resources_walk_data crwd = { + .handle = handle, + .connections = LIST_HEAD_INIT(crwd.connections), + }; + struct crs_csi2 *csi2; + + /* + * Avoid allocating _CRS CSI-2 objects for devices without any CSI-2 + * resource descriptions in _CRS to reduce overhead. + */ + acpi_walk_resources(handle, METHOD_NAME__CRS, parse_csi2_resource, &crwd); + if (list_empty(&crwd.connections)) + return; + + /* + * Create a _CRS CSI-2 entry to store the extracted connection + * information and add it to the global list. + */ + csi2 = acpi_mipi_add_crs_csi2(handle, &acpi_mipi_crs_csi2_list); + if (!csi2) { + csi_csr2_release_connections(&crwd.connections); + return; /* Nothing really can be done about this. */ + } + + list_replace(&crwd.connections, &csi2->connections); +} + +#define NO_CSI2_PORT (UINT_MAX - 1) + +static void alloc_crs_csi2_swnodes(struct crs_csi2 *csi2) +{ + size_t port_count = csi2->port_count; + struct acpi_device_software_nodes *swnodes; + size_t alloc_size; + unsigned int i; + + /* + * Allocate memory for ports, node pointers (number of nodes + + * 1 (guardian), nodes (root + number of ports * 2 (because for + * every port there is an endpoint)). + */ + if (check_mul_overflow(sizeof(*swnodes->ports) + + sizeof(*swnodes->nodes) * 2 + + sizeof(*swnodes->nodeptrs) * 2, + port_count, &alloc_size) || + check_add_overflow(sizeof(*swnodes) + + sizeof(*swnodes->nodes) + + sizeof(*swnodes->nodeptrs) * 2, + alloc_size, &alloc_size)) { + acpi_handle_info(csi2->handle, + "too many _CRS CSI-2 resource handles (%zu)", + port_count); + return; + } + + swnodes = kmalloc(alloc_size, GFP_KERNEL); + if (!swnodes) + return; + + swnodes->ports = (struct acpi_device_software_node_port *)(swnodes + 1); + swnodes->nodes = (struct software_node *)(swnodes->ports + port_count); + swnodes->nodeptrs = (const struct software_node **)(swnodes->nodes + 1 + + 2 * port_count); + swnodes->num_ports = port_count; + + for (i = 0; i < 2 * port_count + 1; i++) + swnodes->nodeptrs[i] = &swnodes->nodes[i]; + + swnodes->nodeptrs[i] = NULL; + + for (i = 0; i < port_count; i++) + swnodes->ports[i].port_nr = NO_CSI2_PORT; + + csi2->swnodes = swnodes; +} + +#define ACPI_CRS_CSI2_PHY_TYPE_C 0 +#define ACPI_CRS_CSI2_PHY_TYPE_D 1 + +static unsigned int next_csi2_port_index(struct acpi_device_software_nodes *swnodes, + unsigned int port_nr) +{ + unsigned int i; + + for (i = 0; i < swnodes->num_ports; i++) { + struct acpi_device_software_node_port *port = &swnodes->ports[i]; + + if (port->port_nr == port_nr) + return i; + + if (port->port_nr == NO_CSI2_PORT) { + port->port_nr = port_nr; + return i; + } + } + + return NO_CSI2_PORT; +} + +/* Print graph port name into a buffer, return non-zero on failure. */ +#define GRAPH_PORT_NAME(var, num) \ + (snprintf((var), sizeof(var), SWNODE_GRAPH_PORT_NAME_FMT, (num)) >= \ + sizeof(var)) + +static void extract_crs_csi2_conn_info(acpi_handle local_handle, + struct acpi_device_software_nodes *local_swnodes, + struct crs_csi2_connection *conn) +{ + struct crs_csi2 *remote_csi2 = acpi_mipi_get_crs_csi2(conn->remote_handle); + struct acpi_device_software_nodes *remote_swnodes; + struct acpi_device_software_node_port *local_port, *remote_port; + struct software_node *local_node, *remote_node; + unsigned int local_index, remote_index; + unsigned int bus_type; + + /* + * If the previous steps have failed to make room for a _CRS CSI-2 + * representation for the remote end of the given connection, skip it. + */ + if (!remote_csi2) + return; + + remote_swnodes = remote_csi2->swnodes; + if (!remote_swnodes) + return; + + switch (conn->csi2_data.phy_type) { + case ACPI_CRS_CSI2_PHY_TYPE_C: + bus_type = V4L2_FWNODE_BUS_TYPE_CSI2_CPHY; + break; + + case ACPI_CRS_CSI2_PHY_TYPE_D: + bus_type = V4L2_FWNODE_BUS_TYPE_CSI2_DPHY; + break; + + default: + acpi_handle_info(local_handle, "unknown CSI-2 PHY type %u\n", + conn->csi2_data.phy_type); + return; + } + + local_index = next_csi2_port_index(local_swnodes, + conn->csi2_data.local_port_instance); + if (WARN_ON_ONCE(local_index >= local_swnodes->num_ports)) + return; + + remote_index = next_csi2_port_index(remote_swnodes, + conn->csi2_data.resource_source.index); + if (WARN_ON_ONCE(remote_index >= remote_swnodes->num_ports)) + return; + + local_port = &local_swnodes->ports[local_index]; + local_node = &local_swnodes->nodes[ACPI_DEVICE_SWNODE_EP(local_index)]; + local_port->crs_csi2_local = true; + + remote_port = &remote_swnodes->ports[remote_index]; + remote_node = &remote_swnodes->nodes[ACPI_DEVICE_SWNODE_EP(remote_index)]; + + local_port->remote_ep[0] = SOFTWARE_NODE_REFERENCE(remote_node); + remote_port->remote_ep[0] = SOFTWARE_NODE_REFERENCE(local_node); + + local_port->ep_props[ACPI_DEVICE_SWNODE_EP_REMOTE_EP] = + PROPERTY_ENTRY_REF_ARRAY("remote-endpoint", + local_port->remote_ep); + + local_port->ep_props[ACPI_DEVICE_SWNODE_EP_BUS_TYPE] = + PROPERTY_ENTRY_U32("bus-type", bus_type); + + local_port->ep_props[ACPI_DEVICE_SWNODE_EP_REG] = + PROPERTY_ENTRY_U32("reg", 0); + + local_port->port_props[ACPI_DEVICE_SWNODE_PORT_REG] = + PROPERTY_ENTRY_U32("reg", conn->csi2_data.local_port_instance); + + if (GRAPH_PORT_NAME(local_port->port_name, + conn->csi2_data.local_port_instance)) + acpi_handle_info(local_handle, "local port %u name too long", + conn->csi2_data.local_port_instance); + + remote_port->ep_props[ACPI_DEVICE_SWNODE_EP_REMOTE_EP] = + PROPERTY_ENTRY_REF_ARRAY("remote-endpoint", + remote_port->remote_ep); + + remote_port->ep_props[ACPI_DEVICE_SWNODE_EP_BUS_TYPE] = + PROPERTY_ENTRY_U32("bus-type", bus_type); + + remote_port->ep_props[ACPI_DEVICE_SWNODE_EP_REG] = + PROPERTY_ENTRY_U32("reg", 0); + + remote_port->port_props[ACPI_DEVICE_SWNODE_PORT_REG] = + PROPERTY_ENTRY_U32("reg", conn->csi2_data.resource_source.index); + + if (GRAPH_PORT_NAME(remote_port->port_name, + conn->csi2_data.resource_source.index)) + acpi_handle_info(local_handle, "remote port %u name too long", + conn->csi2_data.resource_source.index); +} + +static void prepare_crs_csi2_swnodes(struct crs_csi2 *csi2) +{ + struct acpi_device_software_nodes *local_swnodes = csi2->swnodes; + acpi_handle local_handle = csi2->handle; + struct crs_csi2_connection *conn; + + /* Bail out if the allocation of swnodes has failed. */ + if (!local_swnodes) + return; + + list_for_each_entry(conn, &csi2->connections, entry) + extract_crs_csi2_conn_info(local_handle, local_swnodes, conn); +} + +/** + * acpi_mipi_scan_crs_csi2 - Create ACPI _CRS CSI-2 software nodes + * + * Note that this function must be called before any struct acpi_device objects + * are bound to any ACPI drivers or scan handlers, so it cannot assume the + * existence of struct acpi_device objects for every device present in the ACPI + * namespace. + * + * acpi_scan_lock in scan.c must be held when calling this function. + */ +void acpi_mipi_scan_crs_csi2(void) +{ + struct crs_csi2 *csi2; + LIST_HEAD(aux_list); + + /* Count references to each ACPI handle in the CSI-2 connection graph. */ + list_for_each_entry(csi2, &acpi_mipi_crs_csi2_list, entry) { + struct crs_csi2_connection *conn; + + list_for_each_entry(conn, &csi2->connections, entry) { + struct crs_csi2 *remote_csi2; + + csi2->port_count++; + + remote_csi2 = acpi_mipi_get_crs_csi2(conn->remote_handle); + if (remote_csi2) { + remote_csi2->port_count++; + continue; + } + /* + * The remote endpoint has no _CRS CSI-2 list entry yet, + * so create one for it and add it to the list. + */ + acpi_mipi_add_crs_csi2(conn->remote_handle, &aux_list); + } + } + list_splice(&aux_list, &acpi_mipi_crs_csi2_list); + + /* + * Allocate software nodes for representing the CSI-2 information. + * + * This needs to be done for all of the list entries in one go, because + * they may point to each other without restrictions and the next step + * relies on the availability of swnodes memory for each list entry. + */ + list_for_each_entry(csi2, &acpi_mipi_crs_csi2_list, entry) + alloc_crs_csi2_swnodes(csi2); + + /* + * Set up software node properties using data from _CRS CSI-2 resource + * descriptors. + */ + list_for_each_entry(csi2, &acpi_mipi_crs_csi2_list, entry) + prepare_crs_csi2_swnodes(csi2); +} + +/* + * Get the index of the next property in the property array, with a given + * maximum value. + */ +#define NEXT_PROPERTY(index, max) \ + (WARN_ON((index) > ACPI_DEVICE_SWNODE_##max) ? \ + ACPI_DEVICE_SWNODE_##max : (index)++) + +static void init_csi2_port_local(struct acpi_device *adev, + struct acpi_device_software_node_port *port, + struct fwnode_handle *port_fwnode, + unsigned int index) +{ + acpi_handle handle = acpi_device_handle(adev); + unsigned int num_link_freqs; + int ret; + + ret = fwnode_property_count_u64(port_fwnode, "mipi-img-link-frequencies"); + if (ret <= 0) + return; + + num_link_freqs = ret; + if (num_link_freqs > ACPI_DEVICE_CSI2_DATA_LANES) { + acpi_handle_info(handle, "Too many link frequencies: %u\n", + num_link_freqs); + num_link_freqs = ACPI_DEVICE_CSI2_DATA_LANES; + } + + ret = fwnode_property_read_u64_array(port_fwnode, + "mipi-img-link-frequencies", + port->link_frequencies, + num_link_freqs); + if (ret) { + acpi_handle_info(handle, "Unable to get link frequencies (%d)\n", + ret); + return; + } + + port->ep_props[NEXT_PROPERTY(index, EP_LINK_FREQUENCIES)] = + PROPERTY_ENTRY_U64_ARRAY_LEN("link-frequencies", + port->link_frequencies, + num_link_freqs); +} + +static void init_csi2_port(struct acpi_device *adev, + struct acpi_device_software_nodes *swnodes, + struct acpi_device_software_node_port *port, + struct fwnode_handle *port_fwnode, + unsigned int port_index) +{ + unsigned int ep_prop_index = ACPI_DEVICE_SWNODE_EP_CLOCK_LANES; + acpi_handle handle = acpi_device_handle(adev); + u8 val[ACPI_DEVICE_CSI2_DATA_LANES]; + int num_lanes = 0; + int ret; + + if (GRAPH_PORT_NAME(port->port_name, port->port_nr)) + return; + + swnodes->nodes[ACPI_DEVICE_SWNODE_PORT(port_index)] = + SOFTWARE_NODE(port->port_name, port->port_props, + &swnodes->nodes[ACPI_DEVICE_SWNODE_ROOT]); + + ret = fwnode_property_read_u8(port_fwnode, "mipi-img-clock-lane", val); + if (!ret) + port->ep_props[NEXT_PROPERTY(ep_prop_index, EP_CLOCK_LANES)] = + PROPERTY_ENTRY_U32("clock-lanes", val[0]); + + ret = fwnode_property_count_u8(port_fwnode, "mipi-img-data-lanes"); + if (ret > 0) { + num_lanes = ret; + + if (num_lanes > ACPI_DEVICE_CSI2_DATA_LANES) { + acpi_handle_info(handle, "Too many data lanes: %u\n", + num_lanes); + num_lanes = ACPI_DEVICE_CSI2_DATA_LANES; + } + + ret = fwnode_property_read_u8_array(port_fwnode, + "mipi-img-data-lanes", + val, num_lanes); + if (!ret) { + unsigned int i; + + for (i = 0; i < num_lanes; i++) + port->data_lanes[i] = val[i]; + + port->ep_props[NEXT_PROPERTY(ep_prop_index, EP_DATA_LANES)] = + PROPERTY_ENTRY_U32_ARRAY_LEN("data-lanes", + port->data_lanes, + num_lanes); + } + } + + ret = fwnode_property_count_u8(port_fwnode, "mipi-img-lane-polarities"); + if (ret < 0) { + acpi_handle_debug(handle, "Lane polarity bytes missing\n"); + } else if (ret * BITS_PER_TYPE(u8) < num_lanes + 1) { + acpi_handle_info(handle, "Too few lane polarity bits (%zu vs. %d)\n", + ret * BITS_PER_TYPE(u8), num_lanes + 1); + } else { + unsigned long mask = 0; + int byte_count = ret; + unsigned int i; + + /* + * The total number of lanes is ACPI_DEVICE_CSI2_DATA_LANES + 1 + * (data lanes + clock lane). It is not expected to ever be + * greater than the number of bits in an unsigned long + * variable, but ensure that this is the case. + */ + BUILD_BUG_ON(BITS_PER_TYPE(unsigned long) <= ACPI_DEVICE_CSI2_DATA_LANES); + + if (byte_count > sizeof(mask)) { + acpi_handle_info(handle, "Too many lane polarities: %d\n", + byte_count); + byte_count = sizeof(mask); + } + fwnode_property_read_u8_array(port_fwnode, "mipi-img-lane-polarities", + val, byte_count); + + for (i = 0; i < byte_count; i++) + mask |= (unsigned long)val[i] << BITS_PER_TYPE(u8) * i; + + for (i = 0; i <= num_lanes; i++) + port->lane_polarities[i] = test_bit(i, &mask); + + port->ep_props[NEXT_PROPERTY(ep_prop_index, EP_LANE_POLARITIES)] = + PROPERTY_ENTRY_U32_ARRAY_LEN("lane-polarities", + port->lane_polarities, + num_lanes + 1); + } + + swnodes->nodes[ACPI_DEVICE_SWNODE_EP(port_index)] = + SOFTWARE_NODE("endpoint@0", swnodes->ports[port_index].ep_props, + &swnodes->nodes[ACPI_DEVICE_SWNODE_PORT(port_index)]); + + if (port->crs_csi2_local) + init_csi2_port_local(adev, port, port_fwnode, ep_prop_index); +} + +#define MIPI_IMG_PORT_PREFIX "mipi-img-port-" + +static struct fwnode_handle *get_mipi_port_handle(struct fwnode_handle *adev_fwnode, + unsigned int port_nr) +{ + char port_name[sizeof(MIPI_IMG_PORT_PREFIX) + 2]; + + if (snprintf(port_name, sizeof(port_name), "%s%u", + MIPI_IMG_PORT_PREFIX, port_nr) >= sizeof(port_name)) + return NULL; + + return fwnode_get_named_child_node(adev_fwnode, port_name); +} + +static void init_crs_csi2_swnodes(struct crs_csi2 *csi2) +{ + struct acpi_buffer buffer = { .length = ACPI_ALLOCATE_BUFFER }; + struct acpi_device_software_nodes *swnodes = csi2->swnodes; + acpi_handle handle = csi2->handle; + unsigned int prop_index = 0; + struct fwnode_handle *adev_fwnode; + struct acpi_device *adev; + acpi_status status; + unsigned int i; + u32 val; + int ret; + + /* + * Bail out if the swnodes are not available (either they have not been + * allocated or they have been assigned to the device already). + */ + if (!swnodes) + return; + + adev = acpi_fetch_acpi_dev(handle); + if (!adev) + return; + + adev_fwnode = acpi_fwnode_handle(adev); + + /* + * If the "rotation" property is not present, but _PLD is there, + * evaluate it to get the "rotation" value. + */ + if (!fwnode_property_present(adev_fwnode, "rotation")) { + struct acpi_pld_info *pld; + + status = acpi_get_physical_device_location(handle, &pld); + if (ACPI_SUCCESS(status)) { + swnodes->dev_props[NEXT_PROPERTY(prop_index, DEV_ROTATION)] = + PROPERTY_ENTRY_U32("rotation", + pld->rotation * 45U); + kfree(pld); + } + } + + if (!fwnode_property_read_u32(adev_fwnode, "mipi-img-clock-frequency", &val)) + swnodes->dev_props[NEXT_PROPERTY(prop_index, DEV_CLOCK_FREQUENCY)] = + PROPERTY_ENTRY_U32("clock-frequency", val); + + if (!fwnode_property_read_u32(adev_fwnode, "mipi-img-led-max-current", &val)) + swnodes->dev_props[NEXT_PROPERTY(prop_index, DEV_LED_MAX_MICROAMP)] = + PROPERTY_ENTRY_U32("led-max-microamp", val); + + if (!fwnode_property_read_u32(adev_fwnode, "mipi-img-flash-max-current", &val)) + swnodes->dev_props[NEXT_PROPERTY(prop_index, DEV_FLASH_MAX_MICROAMP)] = + PROPERTY_ENTRY_U32("flash-max-microamp", val); + + if (!fwnode_property_read_u32(adev_fwnode, "mipi-img-flash-max-timeout-us", &val)) + swnodes->dev_props[NEXT_PROPERTY(prop_index, DEV_FLASH_MAX_TIMEOUT_US)] = + PROPERTY_ENTRY_U32("flash-max-timeout-us", val); + + status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); + if (ACPI_FAILURE(status)) { + acpi_handle_info(handle, "Unable to get the path name\n"); + return; + } + + swnodes->nodes[ACPI_DEVICE_SWNODE_ROOT] = + SOFTWARE_NODE(buffer.pointer, swnodes->dev_props, NULL); + + for (i = 0; i < swnodes->num_ports; i++) { + struct acpi_device_software_node_port *port = &swnodes->ports[i]; + struct fwnode_handle *port_fwnode; + + /* + * The MIPI DisCo for Imaging specification defines _DSD device + * properties for providing CSI-2 port parameters that can be + * accessed through the generic device properties framework. To + * access them, it is first necessary to find the data node + * representing the port under the given ACPI device object. + */ + port_fwnode = get_mipi_port_handle(adev_fwnode, port->port_nr); + if (!port_fwnode) { + acpi_handle_info(handle, + "MIPI port name too long for port %u\n", + port->port_nr); + continue; + } + + init_csi2_port(adev, swnodes, port, port_fwnode, i); + + fwnode_handle_put(port_fwnode); + } + + ret = software_node_register_node_group(swnodes->nodeptrs); + if (ret < 0) { + acpi_handle_info(handle, + "Unable to register software nodes (%d)\n", ret); + return; + } + + adev->swnodes = swnodes; + adev_fwnode->secondary = software_node_fwnode(swnodes->nodes); + + /* + * Prevents the swnodes from this csi2 entry from being assigned again + * or freed prematurely. + */ + csi2->swnodes = NULL; +} + +/** + * acpi_mipi_init_crs_csi2_swnodes - Initialize _CRS CSI-2 software nodes + * + * Use MIPI DisCo for Imaging device properties to finalize the initialization + * of CSI-2 software nodes for all ACPI device objects that have been already + * enumerated. + */ +void acpi_mipi_init_crs_csi2_swnodes(void) +{ + struct crs_csi2 *csi2, *csi2_tmp; + + list_for_each_entry_safe(csi2, csi2_tmp, &acpi_mipi_crs_csi2_list, entry) + init_crs_csi2_swnodes(csi2); +} + +/** + * acpi_mipi_crs_csi2_cleanup - Free _CRS CSI-2 temporary data + */ +void acpi_mipi_crs_csi2_cleanup(void) +{ + struct crs_csi2 *csi2, *csi2_tmp; + + list_for_each_entry_safe(csi2, csi2_tmp, &acpi_mipi_crs_csi2_list, entry) + acpi_mipi_del_crs_csi2(csi2); +} diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 9923855377570c..802f8a56d1fa2d 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -1186,7 +1186,7 @@ static ssize_t bus_dsm_mask_show(struct device *dev, struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus); struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); - return sprintf(buf, "%#lx\n", acpi_desc->bus_dsm_mask); + return sysfs_emit(buf, "%#lx\n", acpi_desc->bus_dsm_mask); } static struct device_attribute dev_attr_bus_dsm_mask = __ATTR(dsm_mask, 0444, bus_dsm_mask_show, NULL); @@ -1198,7 +1198,7 @@ static ssize_t revision_show(struct device *dev, struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus); struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); - return sprintf(buf, "%d\n", acpi_desc->acpi_header.revision); + return sysfs_emit(buf, "%d\n", acpi_desc->acpi_header.revision); } static DEVICE_ATTR_RO(revision); @@ -1209,7 +1209,7 @@ static ssize_t hw_error_scrub_show(struct device *dev, struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus); struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); - return sprintf(buf, "%d\n", acpi_desc->scrub_mode); + return sysfs_emit(buf, "%d\n", acpi_desc->scrub_mode); } /* @@ -1278,7 +1278,7 @@ static ssize_t scrub_show(struct device *dev, mutex_lock(&acpi_desc->init_mutex); busy = test_bit(ARS_BUSY, &acpi_desc->scrub_flags) && !test_bit(ARS_CANCEL, &acpi_desc->scrub_flags); - rc = sprintf(buf, "%d%s", acpi_desc->scrub_count, busy ? "+\n" : "\n"); + rc = sysfs_emit(buf, "%d%s", acpi_desc->scrub_count, busy ? "+\n" : "\n"); /* Allow an admin to poll the busy state at a higher rate */ if (busy && capable(CAP_SYS_RAWIO) && !test_and_set_bit(ARS_POLL, &acpi_desc->scrub_flags)) { @@ -1382,7 +1382,7 @@ static ssize_t handle_show(struct device *dev, { struct acpi_nfit_memory_map *memdev = to_nfit_memdev(dev); - return sprintf(buf, "%#x\n", memdev->device_handle); + return sysfs_emit(buf, "%#x\n", memdev->device_handle); } static DEVICE_ATTR_RO(handle); @@ -1391,7 +1391,7 @@ static ssize_t phys_id_show(struct device *dev, { struct acpi_nfit_memory_map *memdev = to_nfit_memdev(dev); - return sprintf(buf, "%#x\n", memdev->physical_id); + return sysfs_emit(buf, "%#x\n", memdev->physical_id); } static DEVICE_ATTR_RO(phys_id); @@ -1400,7 +1400,7 @@ static ssize_t vendor_show(struct device *dev, { struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev); - return sprintf(buf, "0x%04x\n", be16_to_cpu(dcr->vendor_id)); + return sysfs_emit(buf, "0x%04x\n", be16_to_cpu(dcr->vendor_id)); } static DEVICE_ATTR_RO(vendor); @@ -1409,7 +1409,7 @@ static ssize_t rev_id_show(struct device *dev, { struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev); - return sprintf(buf, "0x%04x\n", be16_to_cpu(dcr->revision_id)); + return sysfs_emit(buf, "0x%04x\n", be16_to_cpu(dcr->revision_id)); } static DEVICE_ATTR_RO(rev_id); @@ -1418,7 +1418,7 @@ static ssize_t device_show(struct device *dev, { struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev); - return sprintf(buf, "0x%04x\n", be16_to_cpu(dcr->device_id)); + return sysfs_emit(buf, "0x%04x\n", be16_to_cpu(dcr->device_id)); } static DEVICE_ATTR_RO(device); @@ -1427,7 +1427,7 @@ static ssize_t subsystem_vendor_show(struct device *dev, { struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev); - return sprintf(buf, "0x%04x\n", be16_to_cpu(dcr->subsystem_vendor_id)); + return sysfs_emit(buf, "0x%04x\n", be16_to_cpu(dcr->subsystem_vendor_id)); } static DEVICE_ATTR_RO(subsystem_vendor); @@ -1436,7 +1436,7 @@ static ssize_t subsystem_rev_id_show(struct device *dev, { struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev); - return sprintf(buf, "0x%04x\n", + return sysfs_emit(buf, "0x%04x\n", be16_to_cpu(dcr->subsystem_revision_id)); } static DEVICE_ATTR_RO(subsystem_rev_id); @@ -1446,7 +1446,7 @@ static ssize_t subsystem_device_show(struct device *dev, { struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev); - return sprintf(buf, "0x%04x\n", be16_to_cpu(dcr->subsystem_device_id)); + return sysfs_emit(buf, "0x%04x\n", be16_to_cpu(dcr->subsystem_device_id)); } static DEVICE_ATTR_RO(subsystem_device); @@ -1465,7 +1465,7 @@ static ssize_t format_show(struct device *dev, { struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev); - return sprintf(buf, "0x%04x\n", le16_to_cpu(dcr->code)); + return sysfs_emit(buf, "0x%04x\n", le16_to_cpu(dcr->code)); } static DEVICE_ATTR_RO(format); @@ -1498,7 +1498,7 @@ static ssize_t format1_show(struct device *dev, continue; if (nfit_dcr->dcr->code == dcr->code) continue; - rc = sprintf(buf, "0x%04x\n", + rc = sysfs_emit(buf, "0x%04x\n", le16_to_cpu(nfit_dcr->dcr->code)); break; } @@ -1515,7 +1515,7 @@ static ssize_t formats_show(struct device *dev, { struct nvdimm *nvdimm = to_nvdimm(dev); - return sprintf(buf, "%d\n", num_nvdimm_formats(nvdimm)); + return sysfs_emit(buf, "%d\n", num_nvdimm_formats(nvdimm)); } static DEVICE_ATTR_RO(formats); @@ -1524,7 +1524,7 @@ static ssize_t serial_show(struct device *dev, { struct acpi_nfit_control_region *dcr = to_nfit_dcr(dev); - return sprintf(buf, "0x%08x\n", be32_to_cpu(dcr->serial_number)); + return sysfs_emit(buf, "0x%08x\n", be32_to_cpu(dcr->serial_number)); } static DEVICE_ATTR_RO(serial); @@ -1536,7 +1536,7 @@ static ssize_t family_show(struct device *dev, if (nfit_mem->family < 0) return -ENXIO; - return sprintf(buf, "%d\n", nfit_mem->family); + return sysfs_emit(buf, "%d\n", nfit_mem->family); } static DEVICE_ATTR_RO(family); @@ -1548,7 +1548,7 @@ static ssize_t dsm_mask_show(struct device *dev, if (nfit_mem->family < 0) return -ENXIO; - return sprintf(buf, "%#lx\n", nfit_mem->dsm_mask); + return sysfs_emit(buf, "%#lx\n", nfit_mem->dsm_mask); } static DEVICE_ATTR_RO(dsm_mask); @@ -1562,7 +1562,7 @@ static ssize_t flags_show(struct device *dev, if (test_bit(NFIT_MEM_DIRTY, &nfit_mem->flags)) flags |= ACPI_NFIT_MEM_FLUSH_FAILED; - return sprintf(buf, "%s%s%s%s%s%s%s\n", + return sysfs_emit(buf, "%s%s%s%s%s%s%s\n", flags & ACPI_NFIT_MEM_SAVE_FAILED ? "save_fail " : "", flags & ACPI_NFIT_MEM_RESTORE_FAILED ? "restore_fail " : "", flags & ACPI_NFIT_MEM_FLUSH_FAILED ? "flush_fail " : "", @@ -1579,7 +1579,7 @@ static ssize_t id_show(struct device *dev, struct nvdimm *nvdimm = to_nvdimm(dev); struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); - return sprintf(buf, "%s\n", nfit_mem->id); + return sysfs_emit(buf, "%s\n", nfit_mem->id); } static DEVICE_ATTR_RO(id); @@ -1589,7 +1589,7 @@ static ssize_t dirty_shutdown_show(struct device *dev, struct nvdimm *nvdimm = to_nvdimm(dev); struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); - return sprintf(buf, "%d\n", nfit_mem->dirty_shutdown); + return sysfs_emit(buf, "%d\n", nfit_mem->dirty_shutdown); } static DEVICE_ATTR_RO(dirty_shutdown); @@ -2172,7 +2172,7 @@ static ssize_t range_index_show(struct device *dev, struct nd_region *nd_region = to_nd_region(dev); struct nfit_spa *nfit_spa = nd_region_provider_data(nd_region); - return sprintf(buf, "%d\n", nfit_spa->spa->range_index); + return sysfs_emit(buf, "%d\n", nfit_spa->spa->range_index); } static DEVICE_ATTR_RO(range_index); @@ -2257,26 +2257,23 @@ static int acpi_nfit_init_interleave_set(struct acpi_nfit_desc *acpi_desc, struct nd_region_desc *ndr_desc, struct acpi_nfit_system_address *spa) { + u16 nr = ndr_desc->num_mappings; + struct nfit_set_info2 *info2 __free(kfree) = + kcalloc(nr, sizeof(*info2), GFP_KERNEL); + struct nfit_set_info *info __free(kfree) = + kcalloc(nr, sizeof(*info), GFP_KERNEL); struct device *dev = acpi_desc->dev; struct nd_interleave_set *nd_set; - u16 nr = ndr_desc->num_mappings; - struct nfit_set_info2 *info2; - struct nfit_set_info *info; int i; + if (!info || !info2) + return -ENOMEM; + nd_set = devm_kzalloc(dev, sizeof(*nd_set), GFP_KERNEL); if (!nd_set) return -ENOMEM; import_guid(&nd_set->type_guid, spa->range_guid); - info = devm_kcalloc(dev, nr, sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - info2 = devm_kcalloc(dev, nr, sizeof(*info2), GFP_KERNEL); - if (!info2) - return -ENOMEM; - for (i = 0; i < nr; i++) { struct nd_mapping_desc *mapping = &ndr_desc->mapping[i]; struct nvdimm *nvdimm = mapping->nvdimm; @@ -2337,8 +2334,6 @@ static int acpi_nfit_init_interleave_set(struct acpi_nfit_desc *acpi_desc, } ndr_desc->nd_set = nd_set; - devm_kfree(dev, info); - devm_kfree(dev, info2); return 0; } diff --git a/drivers/acpi/numa/hmat.c b/drivers/acpi/numa/hmat.c index 9ef5f1bdcfdbcf..d6b85f0f6082f7 100644 --- a/drivers/acpi/numa/hmat.c +++ b/drivers/acpi/numa/hmat.c @@ -58,14 +58,22 @@ struct target_cache { struct node_cache_attrs cache_attrs; }; +enum { + NODE_ACCESS_CLASS_0 = 0, + NODE_ACCESS_CLASS_1, + NODE_ACCESS_CLASS_GENPORT_SINK, + NODE_ACCESS_CLASS_MAX, +}; + struct memory_target { struct list_head node; unsigned int memory_pxm; unsigned int processor_pxm; struct resource memregions; - struct node_hmem_attrs hmem_attrs[2]; + struct access_coordinate coord[NODE_ACCESS_CLASS_MAX]; struct list_head caches; struct node_cache_attrs cache_attrs; + u8 gen_port_device_handle[ACPI_SRAT_DEVICE_HANDLE_SIZE]; bool registered; }; @@ -100,6 +108,47 @@ static struct memory_target *find_mem_target(unsigned int mem_pxm) return NULL; } +static struct memory_target *acpi_find_genport_target(u32 uid) +{ + struct memory_target *target; + u32 target_uid; + u8 *uid_ptr; + + list_for_each_entry(target, &targets, node) { + uid_ptr = target->gen_port_device_handle + 8; + target_uid = *(u32 *)uid_ptr; + if (uid == target_uid) + return target; + } + + return NULL; +} + +/** + * acpi_get_genport_coordinates - Retrieve the access coordinates for a generic port + * @uid: ACPI unique id + * @coord: The access coordinates written back out for the generic port + * + * Return: 0 on success. Errno on failure. + * + * Only supports device handles that are ACPI. Assume ACPI0016 HID for CXL. + */ +int acpi_get_genport_coordinates(u32 uid, + struct access_coordinate *coord) +{ + struct memory_target *target; + + guard(mutex)(&target_lock); + target = acpi_find_genport_target(uid); + if (!target) + return -ENOENT; + + *coord = target->coord[NODE_ACCESS_CLASS_GENPORT_SINK]; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(acpi_get_genport_coordinates, CXL); + static __init void alloc_memory_initiator(unsigned int cpu_pxm) { struct memory_initiator *initiator; @@ -120,8 +169,7 @@ static __init void alloc_memory_initiator(unsigned int cpu_pxm) list_add_tail(&initiator->node, &initiators); } -static __init void alloc_memory_target(unsigned int mem_pxm, - resource_size_t start, resource_size_t len) +static __init struct memory_target *alloc_target(unsigned int mem_pxm) { struct memory_target *target; @@ -129,7 +177,7 @@ static __init void alloc_memory_target(unsigned int mem_pxm, if (!target) { target = kzalloc(sizeof(*target), GFP_KERNEL); if (!target) - return; + return NULL; target->memory_pxm = mem_pxm; target->processor_pxm = PXM_INVAL; target->memregions = (struct resource) { @@ -142,6 +190,19 @@ static __init void alloc_memory_target(unsigned int mem_pxm, INIT_LIST_HEAD(&target->caches); } + return target; +} + +static __init void alloc_memory_target(unsigned int mem_pxm, + resource_size_t start, + resource_size_t len) +{ + struct memory_target *target; + + target = alloc_target(mem_pxm); + if (!target) + return; + /* * There are potentially multiple ranges per PXM, so record each * in the per-target memregions resource tree. @@ -152,6 +213,18 @@ static __init void alloc_memory_target(unsigned int mem_pxm, start, start + len, mem_pxm); } +static __init void alloc_genport_target(unsigned int mem_pxm, u8 *handle) +{ + struct memory_target *target; + + target = alloc_target(mem_pxm); + if (!target) + return; + + memcpy(target->gen_port_device_handle, handle, + ACPI_SRAT_DEVICE_HANDLE_SIZE); +} + static __init const char *hmat_data_type(u8 type) { switch (type) { @@ -228,24 +301,24 @@ static void hmat_update_target_access(struct memory_target *target, { switch (type) { case ACPI_HMAT_ACCESS_LATENCY: - target->hmem_attrs[access].read_latency = value; - target->hmem_attrs[access].write_latency = value; + target->coord[access].read_latency = value; + target->coord[access].write_latency = value; break; case ACPI_HMAT_READ_LATENCY: - target->hmem_attrs[access].read_latency = value; + target->coord[access].read_latency = value; break; case ACPI_HMAT_WRITE_LATENCY: - target->hmem_attrs[access].write_latency = value; + target->coord[access].write_latency = value; break; case ACPI_HMAT_ACCESS_BANDWIDTH: - target->hmem_attrs[access].read_bandwidth = value; - target->hmem_attrs[access].write_bandwidth = value; + target->coord[access].read_bandwidth = value; + target->coord[access].write_bandwidth = value; break; case ACPI_HMAT_READ_BANDWIDTH: - target->hmem_attrs[access].read_bandwidth = value; + target->coord[access].read_bandwidth = value; break; case ACPI_HMAT_WRITE_BANDWIDTH: - target->hmem_attrs[access].write_bandwidth = value; + target->coord[access].write_bandwidth = value; break; default: break; @@ -291,11 +364,28 @@ static __init void hmat_add_locality(struct acpi_hmat_locality *hmat_loc) } } +static __init void hmat_update_target(unsigned int tgt_pxm, unsigned int init_pxm, + u8 mem_hier, u8 type, u32 value) +{ + struct memory_target *target = find_mem_target(tgt_pxm); + + if (mem_hier != ACPI_HMAT_MEMORY) + return; + + if (target && target->processor_pxm == init_pxm) { + hmat_update_target_access(target, type, value, + NODE_ACCESS_CLASS_0); + /* If the node has a CPU, update access 1 */ + if (node_state(pxm_to_node(init_pxm), N_CPU)) + hmat_update_target_access(target, type, value, + NODE_ACCESS_CLASS_1); + } +} + static __init int hmat_parse_locality(union acpi_subtable_headers *header, const unsigned long end) { struct acpi_hmat_locality *hmat_loc = (void *)header; - struct memory_target *target; unsigned int init, targ, total_size, ipds, tpds; u32 *inits, *targs, value; u16 *entries; @@ -336,15 +426,8 @@ static __init int hmat_parse_locality(union acpi_subtable_headers *header, inits[init], targs[targ], value, hmat_data_type_suffix(type)); - if (mem_hier == ACPI_HMAT_MEMORY) { - target = find_mem_target(targs[targ]); - if (target && target->processor_pxm == inits[init]) { - hmat_update_target_access(target, type, value, 0); - /* If the node has a CPU, update access 1 */ - if (node_state(pxm_to_node(inits[init]), N_CPU)) - hmat_update_target_access(target, type, value, 1); - } - } + hmat_update_target(targs[targ], inits[init], + mem_hier, type, value); } } @@ -491,6 +574,27 @@ static __init int srat_parse_mem_affinity(union acpi_subtable_headers *header, return 0; } +static __init int srat_parse_genport_affinity(union acpi_subtable_headers *header, + const unsigned long end) +{ + struct acpi_srat_generic_affinity *ga = (void *)header; + + if (!ga) + return -EINVAL; + + if (!(ga->flags & ACPI_SRAT_GENERIC_AFFINITY_ENABLED)) + return 0; + + /* Skip PCI device_handle for now */ + if (ga->device_handle_type != 0) + return 0; + + alloc_genport_target(ga->proximity_domain, + (u8 *)ga->device_handle); + + return 0; +} + static u32 hmat_initiator_perf(struct memory_target *target, struct memory_initiator *initiator, struct acpi_hmat_locality *hmat_loc) @@ -592,6 +696,11 @@ static void hmat_update_target_attrs(struct memory_target *target, u32 best = 0; int i; + /* Don't update for generic port if there's no device handle */ + if (access == NODE_ACCESS_CLASS_GENPORT_SINK && + !(*(u16 *)target->gen_port_device_handle)) + return; + bitmap_zero(p_nodes, MAX_NUMNODES); /* * If the Address Range Structure provides a local processor pxm, set @@ -661,6 +770,14 @@ static void __hmat_register_target_initiators(struct memory_target *target, } } +static void hmat_register_generic_target_initiators(struct memory_target *target) +{ + static DECLARE_BITMAP(p_nodes, MAX_NUMNODES); + + __hmat_register_target_initiators(target, p_nodes, + NODE_ACCESS_CLASS_GENPORT_SINK); +} + static void hmat_register_target_initiators(struct memory_target *target) { static DECLARE_BITMAP(p_nodes, MAX_NUMNODES); @@ -681,7 +798,7 @@ static void hmat_register_target_cache(struct memory_target *target) static void hmat_register_target_perf(struct memory_target *target, int access) { unsigned mem_nid = pxm_to_node(target->memory_pxm); - node_set_perf_attrs(mem_nid, &target->hmem_attrs[access], access); + node_set_perf_attrs(mem_nid, &target->coord[access], access); } static void hmat_register_target_devices(struct memory_target *target) @@ -712,6 +829,17 @@ static void hmat_register_target(struct memory_target *target) */ hmat_register_target_devices(target); + /* + * Register generic port perf numbers. The nid may not be + * initialized and is still NUMA_NO_NODE. + */ + mutex_lock(&target_lock); + if (*(u16 *)target->gen_port_device_handle) { + hmat_register_generic_target_initiators(target); + target->registered = true; + } + mutex_unlock(&target_lock); + /* * Skip offline nodes. This can happen when memory * marked EFI_MEMORY_SP, "specific purpose", is applied @@ -726,8 +854,8 @@ static void hmat_register_target(struct memory_target *target) if (!target->registered) { hmat_register_target_initiators(target); hmat_register_target_cache(target); - hmat_register_target_perf(target, 0); - hmat_register_target_perf(target, 1); + hmat_register_target_perf(target, NODE_ACCESS_CLASS_0); + hmat_register_target_perf(target, NODE_ACCESS_CLASS_1); target->registered = true; } mutex_unlock(&target_lock); @@ -765,7 +893,7 @@ static int hmat_set_default_dram_perf(void) int rc; int nid, pxm; struct memory_target *target; - struct node_hmem_attrs *attrs; + struct access_coordinate *attrs; if (!default_dram_type) return -EIO; @@ -775,7 +903,7 @@ static int hmat_set_default_dram_perf(void) target = find_mem_target(pxm); if (!target) continue; - attrs = &target->hmem_attrs[1]; + attrs = &target->coord[1]; rc = mt_set_default_dram_perf(nid, attrs, "ACPI HMAT"); if (rc) return rc; @@ -789,7 +917,7 @@ static int hmat_calculate_adistance(struct notifier_block *self, { static DECLARE_BITMAP(p_nodes, MAX_NUMNODES); struct memory_target *target; - struct node_hmem_attrs *perf; + struct access_coordinate *perf; int *adist = data; int pxm; @@ -802,7 +930,7 @@ static int hmat_calculate_adistance(struct notifier_block *self, hmat_update_target_attrs(target, p_nodes, 1); mutex_unlock(&target_lock); - perf = &target->hmem_attrs[1]; + perf = &target->coord[1]; if (mt_perf_to_adistance(perf, adist)) return NOTIFY_OK; @@ -870,6 +998,13 @@ static __init int hmat_init(void) ACPI_SRAT_TYPE_MEMORY_AFFINITY, srat_parse_mem_affinity, 0) < 0) goto out_put; + + if (acpi_table_parse_entries(ACPI_SIG_SRAT, + sizeof(struct acpi_table_srat), + ACPI_SRAT_TYPE_GENERIC_PORT_AFFINITY, + srat_parse_genport_affinity, 0) < 0) + goto out_put; + acpi_put_table(tbl); status = acpi_get_table(ACPI_SIG_HMAT, 0, &tbl); diff --git a/drivers/acpi/numa/srat.c b/drivers/acpi/numa/srat.c index 12f330b0eac01a..0214518fc582f4 100644 --- a/drivers/acpi/numa/srat.c +++ b/drivers/acpi/numa/srat.c @@ -67,9 +67,9 @@ int acpi_map_pxm_to_node(int pxm) node = pxm_to_node_map[pxm]; if (node == NUMA_NO_NODE) { - if (nodes_weight(nodes_found_map) >= MAX_NUMNODES) - return NUMA_NO_NODE; node = first_unset_node(nodes_found_map); + if (node >= MAX_NUMNODES) + return NUMA_NO_NODE; __acpi_map_pxm_to_node(pxm, node); node_set(node, nodes_found_map); } @@ -183,7 +183,7 @@ static int __init slit_valid(struct acpi_table_slit *slit) int i, j; int d = slit->locality_count; for (i = 0; i < d; i++) { - for (j = 0; j < d; j++) { + for (j = 0; j < d; j++) { u8 val = slit->entry[d*i + j]; if (i == j) { if (val != LOCAL_DISTANCE) @@ -430,7 +430,7 @@ acpi_parse_gi_affinity(union acpi_subtable_headers *header, return -EINVAL; node = acpi_map_pxm_to_node(gi_affinity->proximity_domain); - if (node == NUMA_NO_NODE || node >= MAX_NUMNODES) { + if (node == NUMA_NO_NODE) { pr_err("SRAT: Too many proximity domains.\n"); return -EINVAL; } @@ -532,7 +532,7 @@ int __init acpi_numa_init(void) */ /* fake_pxm is the next unused PXM value after SRAT parsing */ - for (i = 0, fake_pxm = -1; i < MAX_NUMNODES - 1; i++) { + for (i = 0, fake_pxm = -1; i < MAX_NUMNODES; i++) { if (node_to_pxm_map[i] > fake_pxm) fake_pxm = node_to_pxm_map[i]; } diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index c09cc3c68633da..70af3fbbebe54c 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -544,11 +544,7 @@ acpi_os_predefined_override(const struct acpi_predefined_names *init_val, static irqreturn_t acpi_irq(int irq, void *dev_id) { - u32 handled; - - handled = (*acpi_irq_handler) (acpi_irq_context); - - if (handled) { + if ((*acpi_irq_handler)(acpi_irq_context)) { acpi_irq_handled++; return IRQ_HANDLED; } else { @@ -582,7 +578,8 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler, acpi_irq_handler = handler; acpi_irq_context = context; - if (request_irq(irq, acpi_irq, IRQF_SHARED, "acpi", acpi_irq)) { + if (request_threaded_irq(irq, NULL, acpi_irq, IRQF_SHARED | IRQF_ONESHOT, + "acpi", acpi_irq)) { pr_err("SCI (IRQ%d) allocation failed\n", irq); acpi_irq_handler = NULL; return AE_NOT_ACQUIRED; @@ -1063,9 +1060,7 @@ int __init acpi_debugger_init(void) acpi_status acpi_os_execute(acpi_execute_type type, acpi_osd_exec_callback function, void *context) { - acpi_status status = AE_OK; struct acpi_os_dpc *dpc; - struct workqueue_struct *queue; int ret; ACPI_DEBUG_PRINT((ACPI_DB_EXEC, @@ -1076,9 +1071,9 @@ acpi_status acpi_os_execute(acpi_execute_type type, ret = acpi_debugger_create_thread(function, context); if (ret) { pr_err("Kernel thread creation failed\n"); - status = AE_ERROR; + return AE_ERROR; } - goto out_thread; + return AE_OK; } /* @@ -1096,43 +1091,41 @@ acpi_status acpi_os_execute(acpi_execute_type type, dpc->function = function; dpc->context = context; + INIT_WORK(&dpc->work, acpi_os_execute_deferred); /* * To prevent lockdep from complaining unnecessarily, make sure that * there is a different static lockdep key for each workqueue by using * INIT_WORK() for each of them separately. */ - if (type == OSL_NOTIFY_HANDLER) { - queue = kacpi_notify_wq; - INIT_WORK(&dpc->work, acpi_os_execute_deferred); - } else if (type == OSL_GPE_HANDLER) { - queue = kacpid_wq; - INIT_WORK(&dpc->work, acpi_os_execute_deferred); - } else { + switch (type) { + case OSL_NOTIFY_HANDLER: + ret = queue_work(kacpi_notify_wq, &dpc->work); + break; + case OSL_GPE_HANDLER: + /* + * On some machines, a software-initiated SMI causes corruption + * unless the SMI runs on CPU 0. An SMI can be initiated by + * any AML, but typically it's done in GPE-related methods that + * are run via workqueues, so we can avoid the known corruption + * cases by always queueing on CPU 0. + */ + ret = queue_work_on(0, kacpid_wq, &dpc->work); + break; + default: pr_err("Unsupported os_execute type %d.\n", type); - status = AE_ERROR; + goto err; } - - if (ACPI_FAILURE(status)) - goto err_workqueue; - - /* - * On some machines, a software-initiated SMI causes corruption unless - * the SMI runs on CPU 0. An SMI can be initiated by any AML, but - * typically it's done in GPE-related methods that are run via - * workqueues, so we can avoid the known corruption cases by always - * queueing on CPU 0. - */ - ret = queue_work_on(0, queue, &dpc->work); if (!ret) { pr_err("Unable to queue work\n"); - status = AE_ERROR; + goto err; } -err_workqueue: - if (ACPI_FAILURE(status)) - kfree(dpc); -out_thread: - return status; + + return AE_OK; + +err: + kfree(dpc); + return AE_ERROR; } EXPORT_SYMBOL(acpi_os_execute); @@ -1522,20 +1515,18 @@ void acpi_os_delete_lock(acpi_spinlock handle) acpi_cpu_flags acpi_os_acquire_lock(acpi_spinlock lockp) __acquires(lockp) { - acpi_cpu_flags flags; - - spin_lock_irqsave(lockp, flags); - return flags; + spin_lock(lockp); + return 0; } /* * Release a spinlock. See above. */ -void acpi_os_release_lock(acpi_spinlock lockp, acpi_cpu_flags flags) +void acpi_os_release_lock(acpi_spinlock lockp, acpi_cpu_flags not_used) __releases(lockp) { - spin_unlock_irqrestore(lockp, flags); + spin_unlock(lockp); } #ifndef ACPI_USE_LOCAL_CACHE @@ -1672,7 +1663,7 @@ acpi_status __init acpi_os_initialize(void) acpi_status __init acpi_os_initialize1(void) { kacpid_wq = alloc_workqueue("kacpid", 0, 1); - kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 1); + kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 0); kacpi_hotplug_wq = alloc_ordered_workqueue("kacpi_hotplug", 0); BUG_ON(!kacpid_wq); BUG_ON(!kacpi_notify_wq); diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index b7c6287eccca28..1219adb11ab927 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -17,6 +17,8 @@ #include #include +#include "internal.h" + #ifdef CONFIG_CPU_FREQ /* If a passive cooling situation is detected, primarily CPUfreq is used, as it @@ -26,12 +28,21 @@ */ #define CPUFREQ_THERMAL_MIN_STEP 0 -#define CPUFREQ_THERMAL_MAX_STEP 3 -static DEFINE_PER_CPU(unsigned int, cpufreq_thermal_reduction_pctg); +static int cpufreq_thermal_max_step __read_mostly = 3; + +/* + * Minimum throttle percentage for processor_thermal cooling device. + * The processor_thermal driver uses it to calculate the percentage amount by + * which cpu frequency must be reduced for each cooling state. This is also used + * to calculate the maximum number of throttling steps or cooling states. + */ +static int cpufreq_thermal_reduction_pctg __read_mostly = 20; -#define reduction_pctg(cpu) \ - per_cpu(cpufreq_thermal_reduction_pctg, phys_package_first_cpu(cpu)) +static DEFINE_PER_CPU(unsigned int, cpufreq_thermal_reduction_step); + +#define reduction_step(cpu) \ + per_cpu(cpufreq_thermal_reduction_step, phys_package_first_cpu(cpu)) /* * Emulate "per package data" using per cpu data (which should really be @@ -71,7 +82,7 @@ static int cpufreq_get_max_state(unsigned int cpu) if (!cpu_has_cpufreq(cpu)) return 0; - return CPUFREQ_THERMAL_MAX_STEP; + return cpufreq_thermal_max_step; } static int cpufreq_get_cur_state(unsigned int cpu) @@ -79,7 +90,7 @@ static int cpufreq_get_cur_state(unsigned int cpu) if (!cpu_has_cpufreq(cpu)) return 0; - return reduction_pctg(cpu); + return reduction_step(cpu); } static int cpufreq_set_cur_state(unsigned int cpu, int state) @@ -92,7 +103,7 @@ static int cpufreq_set_cur_state(unsigned int cpu, int state) if (!cpu_has_cpufreq(cpu)) return 0; - reduction_pctg(cpu) = state; + reduction_step(cpu) = state; /* * Update all the CPUs in the same package because they all @@ -113,7 +124,8 @@ static int cpufreq_set_cur_state(unsigned int cpu, int state) if (!policy) return -EINVAL; - max_freq = (policy->cpuinfo.max_freq * (100 - reduction_pctg(i) * 20)) / 100; + max_freq = (policy->cpuinfo.max_freq * + (100 - reduction_step(i) * cpufreq_thermal_reduction_pctg)) / 100; cpufreq_cpu_put(policy); @@ -126,10 +138,29 @@ static int cpufreq_set_cur_state(unsigned int cpu, int state) return 0; } +static void acpi_thermal_cpufreq_config(void) +{ + int cpufreq_pctg = acpi_arch_thermal_cpufreq_pctg(); + + if (!cpufreq_pctg) + return; + + cpufreq_thermal_reduction_pctg = cpufreq_pctg; + + /* + * Derive the MAX_STEP from minimum throttle percentage so that the reduction + * percentage doesn't end up becoming negative. Also, cap the MAX_STEP so that + * the CPU performance doesn't become 0. + */ + cpufreq_thermal_max_step = (100 / cpufreq_pctg) - 2; +} + void acpi_thermal_cpufreq_init(struct cpufreq_policy *policy) { unsigned int cpu; + acpi_thermal_cpufreq_config(); + for_each_cpu(cpu, policy->related_cpus) { struct acpi_processor *pr = per_cpu(processors, cpu); int ret; @@ -190,7 +221,7 @@ static int acpi_processor_max_state(struct acpi_processor *pr) /* * There exists four states according to - * cpufreq_thermal_reduction_pctg. 0, 1, 2, 3 + * cpufreq_thermal_reduction_step. 0, 1, 2, 3 */ max_state += cpufreq_get_max_state(pr->id); if (pr->flags.throttling) diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 6979a3f9f90a84..a6ead5204046b1 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -2,14 +2,17 @@ /* * ACPI device specific properties support. * - * Copyright (C) 2014, Intel Corporation + * Copyright (C) 2014 - 2023, Intel Corporation * All rights reserved. * * Authors: Mika Westerberg * Darren Hart * Rafael J. Wysocki + * Sakari Ailus */ +#define pr_fmt(fmt) "ACPI: " fmt + #include #include #include @@ -800,28 +803,16 @@ static int acpi_get_ref_args(struct fwnode_reference_args *args, { u32 nargs = 0, i; - /* - * Find the referred data extension node under the - * referred device node. - */ - for (; *element < end && (*element)->type == ACPI_TYPE_STRING; - (*element)++) { - const char *child_name = (*element)->string.pointer; - - ref_fwnode = acpi_fwnode_get_named_child_node(ref_fwnode, child_name); - if (!ref_fwnode) - return -EINVAL; - } - /* * Assume the following integer elements are all args. Stop counting on - * the first reference or end of the package arguments. In case of - * neither reference, nor integer, return an error, we can't parse it. + * the first reference (possibly represented as a string) or end of the + * package arguments. In case of neither reference, nor integer, return + * an error, we can't parse it. */ for (i = 0; (*element) + i < end && i < num_args; i++) { acpi_object_type type = (*element)[i].type; - if (type == ACPI_TYPE_LOCAL_REFERENCE) + if (type == ACPI_TYPE_LOCAL_REFERENCE || type == ACPI_TYPE_STRING) break; if (type == ACPI_TYPE_INTEGER) @@ -845,6 +836,44 @@ static int acpi_get_ref_args(struct fwnode_reference_args *args, return 0; } +static struct fwnode_handle *acpi_parse_string_ref(const struct fwnode_handle *fwnode, + const char *refstring) +{ + acpi_handle scope, handle; + struct acpi_data_node *dn; + struct acpi_device *device; + acpi_status status; + + if (is_acpi_device_node(fwnode)) { + scope = to_acpi_device_node(fwnode)->handle; + } else if (is_acpi_data_node(fwnode)) { + scope = to_acpi_data_node(fwnode)->handle; + } else { + pr_debug("Bad node type for node %pfw\n", fwnode); + return NULL; + } + + status = acpi_get_handle(scope, refstring, &handle); + if (ACPI_FAILURE(status)) { + acpi_handle_debug(scope, "Unable to get an ACPI handle for %s\n", + refstring); + return NULL; + } + + device = acpi_fetch_acpi_dev(handle); + if (device) + return acpi_fwnode_handle(device); + + status = acpi_get_data_full(handle, acpi_nondev_subnode_tag, + (void **)&dn, NULL); + if (ACPI_FAILURE(status) || !dn) { + acpi_handle_debug(handle, "Subnode not found\n"); + return NULL; + } + + return &dn->fwnode; +} + /** * __acpi_node_get_property_reference - returns handle to the referenced object * @fwnode: Firmware node to get the property from @@ -852,6 +881,7 @@ static int acpi_get_ref_args(struct fwnode_reference_args *args, * @index: Index of the reference to return * @num_args: Maximum number of arguments after each reference * @args: Location to store the returned reference with optional arguments + * (may be NULL) * * Find property with @name, verifify that it is a package containing at least * one object reference and if so, store the ACPI device object pointer to the @@ -887,6 +917,7 @@ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, const union acpi_object *element, *end; const union acpi_object *obj; const struct acpi_device_data *data; + struct fwnode_handle *ref_fwnode; struct acpi_device *device; int ret, idx = 0; @@ -908,18 +939,35 @@ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, if (!device) return -EINVAL; + if (!args) + return 0; + args->fwnode = acpi_fwnode_handle(device); args->nargs = 0; + + return 0; + case ACPI_TYPE_STRING: + if (index) + return -ENOENT; + + ref_fwnode = acpi_parse_string_ref(fwnode, obj->string.pointer); + if (!ref_fwnode) + return -EINVAL; + + args->fwnode = ref_fwnode; + args->nargs = 0; + return 0; case ACPI_TYPE_PACKAGE: /* * If it is not a single reference, then it is a package of - * references followed by number of ints as follows: + * references, followed by number of ints as follows: * * Package () { REF, INT, REF, INT, INT } * - * The index argument is then used to determine which reference - * the caller wants (along with the arguments). + * Here, REF may be either a local reference or a string. The + * index argument is then used to determine which reference the + * caller wants (along with the arguments). */ break; default: @@ -950,6 +998,24 @@ int __acpi_node_get_property_reference(const struct fwnode_handle *fwnode, if (idx == index) return 0; + break; + case ACPI_TYPE_STRING: + ref_fwnode = acpi_parse_string_ref(fwnode, + element->string.pointer); + if (!ref_fwnode) + return -EINVAL; + + element++; + + ret = acpi_get_ref_args(idx == index ? args : NULL, + ref_fwnode, &element, end, + num_args); + if (ret < 0) + return ret; + + if (idx == index) + return 0; + break; case ACPI_TYPE_INTEGER: if (idx == index) diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 9bd9f79cd40990..dacad1d846c0db 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -461,6 +461,13 @@ static const struct dmi_system_id irq1_level_low_skip_override[] = { DMI_MATCH(DMI_BOARD_NAME, "B1502CBA"), }, }, + { + /* Asus ExpertBook B1502CGA */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_BOARD_NAME, "B1502CGA"), + }, + }, { /* Asus ExpertBook B2402CBA */ .matches = { @@ -482,6 +489,20 @@ static const struct dmi_system_id irq1_level_low_skip_override[] = { DMI_MATCH(DMI_BOARD_NAME, "B2502CBA"), }, }, + { + /* Asus Vivobook E1504GA */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_BOARD_NAME, "E1504GA"), + }, + }, + { + /* Asus Vivobook E1504GAB */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_BOARD_NAME, "E1504GAB"), + }, + }, { /* LG Electronics 17U70P */ .matches = { @@ -510,6 +531,13 @@ static const struct dmi_system_id irq1_edge_low_force_override[] = { DMI_MATCH(DMI_BOARD_NAME, "GMxXGxx"), }, }, + { + /* TongFang GMxXGxx sold as Eluktronics Inc. RP-15 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Eluktronics Inc."), + DMI_MATCH(DMI_BOARD_NAME, "RP-15"), + }, + }, { /* TongFang GM6XGxX/TUXEDO Stellaris 16 Gen5 AMD */ .matches = { @@ -548,6 +576,18 @@ static const struct dmi_system_id irq1_edge_low_force_override[] = { DMI_MATCH(DMI_BOARD_NAME, "GM6BG0Q"), }, }, + { + /* Infinity E15-5A165-BM */ + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "GM5RG1E0009COM"), + }, + }, + { + /* Infinity E15-5A305-1M */ + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "GM5RGEE0016COM"), + }, + }, { } }; diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 02bb2cce423f47..e6ed1ba91e5c91 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1532,7 +1532,6 @@ int acpi_dma_get_range(struct device *dev, const struct bus_dma_region **map) r->cpu_start = rentry->res->start; r->dma_start = rentry->res->start - rentry->offset; r->size = resource_size(rentry->res); - r->offset = rentry->offset; r++; } } @@ -1562,8 +1561,7 @@ static inline const struct iommu_ops *acpi_iommu_fwspec_ops(struct device *dev) return fwspec ? fwspec->ops : NULL; } -static const struct iommu_ops *acpi_iommu_configure_id(struct device *dev, - const u32 *id_in) +static int acpi_iommu_configure_id(struct device *dev, const u32 *id_in) { int err; const struct iommu_ops *ops; @@ -1577,7 +1575,7 @@ static const struct iommu_ops *acpi_iommu_configure_id(struct device *dev, ops = acpi_iommu_fwspec_ops(dev); if (ops) { mutex_unlock(&iommu_probe_device_lock); - return ops; + return 0; } err = iort_iommu_configure_id(dev, id_in); @@ -1594,12 +1592,14 @@ static const struct iommu_ops *acpi_iommu_configure_id(struct device *dev, /* Ignore all other errors apart from EPROBE_DEFER */ if (err == -EPROBE_DEFER) { - return ERR_PTR(err); + return err; } else if (err) { dev_dbg(dev, "Adding to IOMMU failed: %d\n", err); - return NULL; + return -ENODEV; } - return acpi_iommu_fwspec_ops(dev); + if (!acpi_iommu_fwspec_ops(dev)) + return -ENODEV; + return 0; } #else /* !CONFIG_IOMMU_API */ @@ -1611,10 +1611,9 @@ int acpi_iommu_fwspec_init(struct device *dev, u32 id, return -ENODEV; } -static const struct iommu_ops *acpi_iommu_configure_id(struct device *dev, - const u32 *id_in) +static int acpi_iommu_configure_id(struct device *dev, const u32 *id_in) { - return NULL; + return -ENODEV; } #endif /* !CONFIG_IOMMU_API */ @@ -1628,7 +1627,7 @@ static const struct iommu_ops *acpi_iommu_configure_id(struct device *dev, int acpi_dma_configure_id(struct device *dev, enum dev_dma_attr attr, const u32 *input_id) { - const struct iommu_ops *iommu; + int ret; if (attr == DEV_DMA_NOT_SUPPORTED) { set_dma_ops(dev, &dma_dummy_ops); @@ -1637,12 +1636,16 @@ int acpi_dma_configure_id(struct device *dev, enum dev_dma_attr attr, acpi_arch_dma_setup(dev); - iommu = acpi_iommu_configure_id(dev, input_id); - if (PTR_ERR(iommu) == -EPROBE_DEFER) + ret = acpi_iommu_configure_id(dev, input_id); + if (ret == -EPROBE_DEFER) return -EPROBE_DEFER; - arch_setup_dma_ops(dev, 0, U64_MAX, - iommu, attr == DEV_DMA_COHERENT); + /* + * Historically this routine doesn't fail driver probing due to errors + * in acpi_iommu_configure_id() + */ + + arch_setup_dma_ops(dev, 0, U64_MAX, attr == DEV_DMA_COHERENT); return 0; } @@ -1732,6 +1735,7 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device) * Some ACPI devs contain SerialBus resources even though they are not * attached to a serial bus at all. */ + {ACPI_VIDEO_HID, }, {"MSHW0028", }, /* * HIDs of device with an UartSerialBusV2 resource for which userspace @@ -1981,10 +1985,9 @@ static void acpi_scan_init_hotplug(struct acpi_device *adev) } } -static u32 acpi_scan_check_dep(acpi_handle handle, bool check_dep) +static u32 acpi_scan_check_dep(acpi_handle handle) { struct acpi_handle_list dep_devices; - acpi_status status; u32 count; int i; @@ -1994,12 +1997,10 @@ static u32 acpi_scan_check_dep(acpi_handle handle, bool check_dep) * 2. ACPI nodes describing USB ports. * Still, checking for _HID catches more then just these cases ... */ - if (!check_dep || !acpi_has_method(handle, "_DEP") || - !acpi_has_method(handle, "_HID")) + if (!acpi_has_method(handle, "_DEP") || !acpi_has_method(handle, "_HID")) return 0; - status = acpi_evaluate_reference(handle, "_DEP", NULL, &dep_devices); - if (ACPI_FAILURE(status)) { + if (!acpi_evaluate_reference(handle, "_DEP", NULL, &dep_devices)) { acpi_handle_debug(handle, "Failed to evaluate _DEP.\n"); return 0; } @@ -2008,6 +2009,7 @@ static u32 acpi_scan_check_dep(acpi_handle handle, bool check_dep) struct acpi_device_info *info; struct acpi_dep_data *dep; bool skip, honor_dep; + acpi_status status; status = acpi_get_object_info(dep_devices.handles[i], &info); if (ACPI_FAILURE(status)) { @@ -2041,7 +2043,13 @@ static u32 acpi_scan_check_dep(acpi_handle handle, bool check_dep) return count; } -static acpi_status acpi_bus_check_add(acpi_handle handle, bool check_dep, +static acpi_status acpi_scan_check_crs_csi2_cb(acpi_handle handle, u32 a, void *b, void **c) +{ + acpi_mipi_check_crs_csi2(handle); + return AE_OK; +} + +static acpi_status acpi_bus_check_add(acpi_handle handle, bool first_pass, struct acpi_device **adev_p) { struct acpi_device *device = acpi_fetch_acpi_dev(handle); @@ -2059,9 +2067,25 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, bool check_dep, if (acpi_device_should_be_hidden(handle)) return AE_OK; - /* Bail out if there are dependencies. */ - if (acpi_scan_check_dep(handle, check_dep) > 0) - return AE_CTRL_DEPTH; + if (first_pass) { + acpi_mipi_check_crs_csi2(handle); + + /* Bail out if there are dependencies. */ + if (acpi_scan_check_dep(handle) > 0) { + /* + * The entire CSI-2 connection graph needs to be + * extracted before any drivers or scan handlers + * are bound to struct device objects, so scan + * _CRS CSI-2 resource descriptors for all + * devices below the current handle. + */ + acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, + ACPI_UINT32_MAX, + acpi_scan_check_crs_csi2_cb, + NULL, NULL, NULL); + return AE_CTRL_DEPTH; + } + } fallthrough; case ACPI_TYPE_ANY: /* for ACPI_ROOT_OBJECT */ @@ -2084,10 +2108,10 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, bool check_dep, } /* - * If check_dep is true at this point, the device has no dependencies, + * If first_pass is true at this point, the device has no dependencies, * or the creation of the device object would have been postponed above. */ - acpi_add_single_object(&device, handle, type, !check_dep); + acpi_add_single_object(&device, handle, type, !first_pass); if (!device) return AE_CTRL_DEPTH; @@ -2431,6 +2455,13 @@ static void acpi_scan_postponed_branch(acpi_handle handle) acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, acpi_bus_check_add_2, NULL, NULL, (void **)&adev); + + /* + * Populate the ACPI _CRS CSI-2 software nodes for the ACPI devices that + * have been added above. + */ + acpi_mipi_init_crs_csi2_swnodes(); + acpi_bus_attach(adev, NULL); } @@ -2499,12 +2530,22 @@ int acpi_bus_scan(acpi_handle handle) if (!device) return -ENODEV; + /* + * Set up ACPI _CRS CSI-2 software nodes using information extracted + * from the _CRS CSI-2 resource descriptors during the ACPI namespace + * walk above and MIPI DisCo for Imaging device properties. + */ + acpi_mipi_scan_crs_csi2(); + acpi_mipi_init_crs_csi2_swnodes(); + acpi_bus_attach(device, (void *)true); /* Pass 2: Enumerate all of the remaining devices. */ acpi_scan_postponed(); + acpi_mipi_crs_csi2_cleanup(); + return 0; } EXPORT_SYMBOL(acpi_bus_scan); diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index c1516337f66828..b07f7d091d133c 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -251,8 +251,9 @@ int __init_or_acpilib acpi_table_parse_entries_array( return -ENODEV; } - count = acpi_parse_entries_array(id, table_size, table_header, - proc, proc_num, max_entries); + count = acpi_parse_entries_array(id, table_size, + (union fw_table_header *)table_header, + proc, proc_num, max_entries); acpi_put_table(table_header); return count; diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index f74d81abdbfc07..4748e806125344 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -31,6 +31,8 @@ #include #include +#include "internal.h" + #define ACPI_THERMAL_CLASS "thermal_zone" #define ACPI_THERMAL_DEVICE_NAME "Thermal Zone" #define ACPI_THERMAL_NOTIFY_TEMPERATURE 0x80 @@ -90,7 +92,7 @@ struct acpi_thermal_passive { struct acpi_thermal_trip trip; unsigned long tc1; unsigned long tc2; - unsigned long tsp; + unsigned long delay; }; struct acpi_thermal_active { @@ -188,24 +190,19 @@ static int active_trip_index(struct acpi_thermal *tz, static long get_passive_temp(struct acpi_thermal *tz) { - unsigned long long tmp; - acpi_status status; + int temp; - status = acpi_evaluate_integer(tz->device->handle, "_PSV", NULL, &tmp); - if (ACPI_FAILURE(status)) + if (acpi_passive_trip_temp(tz->device, &temp)) return THERMAL_TEMP_INVALID; - return tmp; + return temp; } static long get_active_temp(struct acpi_thermal *tz, int index) { - char method[] = { '_', 'A', 'C', '0' + index, '\0' }; - unsigned long long tmp; - acpi_status status; + int temp; - status = acpi_evaluate_integer(tz->device->handle, method, NULL, &tmp); - if (ACPI_FAILURE(status)) + if (acpi_active_trip_temp(tz->device, index, &temp)) return THERMAL_TEMP_INVALID; /* @@ -215,10 +212,10 @@ static long get_active_temp(struct acpi_thermal *tz, int index) if (act > 0) { unsigned long long override = celsius_to_deci_kelvin(act); - if (tmp > override) - tmp = override; + if (temp > override) + return override; } - return tmp; + return temp; } static void acpi_thermal_update_trip(struct acpi_thermal *tz, @@ -247,7 +244,6 @@ static bool update_trip_devices(struct acpi_thermal *tz, { struct acpi_handle_list devices = { 0 }; char method[] = "_PSL"; - acpi_status status; if (index != ACPI_THERMAL_TRIP_PASSIVE) { method[1] = 'A'; @@ -255,8 +251,7 @@ static bool update_trip_devices(struct acpi_thermal *tz, method[3] = '0' + index; } - status = acpi_evaluate_reference(tz->device->handle, method, NULL, &devices); - if (ACPI_FAILURE(status)) { + if (!acpi_evaluate_reference(tz->device->handle, method, NULL, &devices)) { acpi_handle_info(tz->device->handle, "%s evaluation failure\n", method); return false; } @@ -297,6 +292,7 @@ static int acpi_thermal_adjust_trip(struct thermal_trip *trip, void *data) struct acpi_thermal_trip *acpi_trip = trip->priv; struct adjust_trip_data *atd = data; struct acpi_thermal *tz = atd->tz; + int temp; if (!acpi_trip || !acpi_thermal_trip_valid(acpi_trip)) return 0; @@ -307,9 +303,11 @@ static int acpi_thermal_adjust_trip(struct thermal_trip *trip, void *data) acpi_thermal_update_trip_devices(tz, trip); if (acpi_thermal_trip_valid(acpi_trip)) - trip->temperature = acpi_thermal_temp(tz, acpi_trip->temp_dk); + temp = acpi_thermal_temp(tz, acpi_trip->temp_dk); else - trip->temperature = THERMAL_TEMP_INVALID; + temp = THERMAL_TEMP_INVALID; + + thermal_zone_set_trip_temp(tz->thermal_zone, trip, temp); return 0; } @@ -339,13 +337,12 @@ static void acpi_thermal_trips_update(struct acpi_thermal *tz, u32 event) dev_name(&adev->dev), event, 0); } -static long acpi_thermal_get_critical_trip(struct acpi_thermal *tz) +static int acpi_thermal_get_critical_trip(struct acpi_thermal *tz) { - unsigned long long tmp; - acpi_status status; + int temp; if (crt > 0) { - tmp = celsius_to_deci_kelvin(crt); + temp = celsius_to_deci_kelvin(crt); goto set; } if (crt == -1) { @@ -353,38 +350,34 @@ static long acpi_thermal_get_critical_trip(struct acpi_thermal *tz) return THERMAL_TEMP_INVALID; } - status = acpi_evaluate_integer(tz->device->handle, "_CRT", NULL, &tmp); - if (ACPI_FAILURE(status)) { - acpi_handle_debug(tz->device->handle, "No critical threshold\n"); + if (acpi_critical_trip_temp(tz->device, &temp)) return THERMAL_TEMP_INVALID; - } - if (tmp <= 2732) { + + if (temp <= 2732) { /* * Below zero (Celsius) values clearly aren't right for sure, * so discard them as invalid. */ - pr_info(FW_BUG "Invalid critical threshold (%llu)\n", tmp); + pr_info(FW_BUG "Invalid critical threshold (%d)\n", temp); return THERMAL_TEMP_INVALID; } set: - acpi_handle_debug(tz->device->handle, "Critical threshold [%llu]\n", tmp); - return tmp; + acpi_handle_debug(tz->device->handle, "Critical threshold [%d]\n", temp); + return temp; } -static long acpi_thermal_get_hot_trip(struct acpi_thermal *tz) +static int acpi_thermal_get_hot_trip(struct acpi_thermal *tz) { - unsigned long long tmp; - acpi_status status; + int temp; - status = acpi_evaluate_integer(tz->device->handle, "_HOT", NULL, &tmp); - if (ACPI_FAILURE(status)) { + if (acpi_hot_trip_temp(tz->device, &temp) || temp == THERMAL_TEMP_INVALID) { acpi_handle_debug(tz->device->handle, "No hot threshold\n"); return THERMAL_TEMP_INVALID; } - acpi_handle_debug(tz->device->handle, "Hot threshold [%llu]\n", tmp); - return tmp; + acpi_handle_debug(tz->device->handle, "Hot threshold [%d]\n", temp); + return temp; } static bool passive_trip_params_init(struct acpi_thermal *tz) @@ -404,11 +397,17 @@ static bool passive_trip_params_init(struct acpi_thermal *tz) tz->trips.passive.tc2 = tmp; + status = acpi_evaluate_integer(tz->device->handle, "_TFP", NULL, &tmp); + if (ACPI_SUCCESS(status)) { + tz->trips.passive.delay = tmp; + return true; + } + status = acpi_evaluate_integer(tz->device->handle, "_TSP", NULL, &tmp); if (ACPI_FAILURE(status)) return false; - tz->trips.passive.tsp = tmp; + tz->trips.passive.delay = tmp * 100; return true; } @@ -904,7 +903,7 @@ static int acpi_thermal_add(struct acpi_device *device) acpi_trip = &tz->trips.passive.trip; if (acpi_thermal_trip_valid(acpi_trip)) { - passive_delay = tz->trips.passive.tsp * 100; + passive_delay = tz->trips.passive.delay; trip->type = THERMAL_TRIP_PASSIVE; trip->temperature = acpi_thermal_temp(tz, acpi_trip->temp_dk); @@ -1142,6 +1141,7 @@ static void __exit acpi_thermal_exit(void) module_init(acpi_thermal_init); module_exit(acpi_thermal_exit); +MODULE_IMPORT_NS(ACPI_THERMAL); MODULE_AUTHOR("Paul Diefenbaugh"); MODULE_DESCRIPTION("ACPI Thermal Zone Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/acpi/thermal_lib.c b/drivers/acpi/thermal_lib.c new file mode 100644 index 00000000000000..4e0519ca9739ef --- /dev/null +++ b/drivers/acpi/thermal_lib.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2023 Linaro Limited + * Copyright 2023 Intel Corporation + * + * Library routines for retrieving trip point temperature values from the + * platform firmware via ACPI. + */ +#include +#include +#include +#include "internal.h" + +/* + * Minimum temperature for full military grade is 218°K (-55°C) and + * max temperature is 448°K (175°C). We can consider those values as + * the boundaries for the [trips] temperature returned by the + * firmware. Any values out of these boundaries may be considered + * bogus and we can assume the firmware has no data to provide. + */ +#define TEMP_MIN_DECIK 2180ULL +#define TEMP_MAX_DECIK 4480ULL + +static int acpi_trip_temp(struct acpi_device *adev, char *obj_name, + int *ret_temp) +{ + unsigned long long temp; + acpi_status status; + + status = acpi_evaluate_integer(adev->handle, obj_name, NULL, &temp); + if (ACPI_FAILURE(status)) { + acpi_handle_debug(adev->handle, "%s evaluation failed\n", obj_name); + return -ENODATA; + } + + if (temp >= TEMP_MIN_DECIK && temp <= TEMP_MAX_DECIK) { + *ret_temp = temp; + } else { + acpi_handle_debug(adev->handle, "%s result %llu out of range\n", + obj_name, temp); + *ret_temp = THERMAL_TEMP_INVALID; + } + + return 0; +} + +int acpi_active_trip_temp(struct acpi_device *adev, int id, int *ret_temp) +{ + char obj_name[] = {'_', 'A', 'C', '0' + id, '\0'}; + + if (id < 0 || id > 9) + return -EINVAL; + + return acpi_trip_temp(adev, obj_name, ret_temp); +} +EXPORT_SYMBOL_NS_GPL(acpi_active_trip_temp, ACPI_THERMAL); + +int acpi_passive_trip_temp(struct acpi_device *adev, int *ret_temp) +{ + return acpi_trip_temp(adev, "_PSV", ret_temp); +} +EXPORT_SYMBOL_NS_GPL(acpi_passive_trip_temp, ACPI_THERMAL); + +int acpi_hot_trip_temp(struct acpi_device *adev, int *ret_temp) +{ + return acpi_trip_temp(adev, "_HOT", ret_temp); +} +EXPORT_SYMBOL_NS_GPL(acpi_hot_trip_temp, ACPI_THERMAL); + +int acpi_critical_trip_temp(struct acpi_device *adev, int *ret_temp) +{ + return acpi_trip_temp(adev, "_CRT", ret_temp); +} +EXPORT_SYMBOL_NS_GPL(acpi_critical_trip_temp, ACPI_THERMAL); + +static int thermal_temp(int error, int temp_decik, int *ret_temp) +{ + if (error) + return error; + + if (temp_decik == THERMAL_TEMP_INVALID) + *ret_temp = THERMAL_TEMP_INVALID; + else + *ret_temp = deci_kelvin_to_millicelsius(temp_decik); + + return 0; +} + +/** + * thermal_acpi_active_trip_temp - Retrieve active trip point temperature + * @adev: Target thermal zone ACPI device object. + * @id: Active cooling level (0 - 9). + * @ret_temp: Address to store the retrieved temperature value on success. + * + * Evaluate the _ACx object for the thermal zone represented by @adev to obtain + * the temperature of the active cooling trip point corresponding to the active + * cooling level given by @id. + * + * Return 0 on success or a negative error value on failure. + */ +int thermal_acpi_active_trip_temp(struct acpi_device *adev, int id, int *ret_temp) +{ + int temp_decik; + int ret = acpi_active_trip_temp(adev, id, &temp_decik); + + return thermal_temp(ret, temp_decik, ret_temp); +} +EXPORT_SYMBOL_GPL(thermal_acpi_active_trip_temp); + +/** + * thermal_acpi_passive_trip_temp - Retrieve passive trip point temperature + * @adev: Target thermal zone ACPI device object. + * @ret_temp: Address to store the retrieved temperature value on success. + * + * Evaluate the _PSV object for the thermal zone represented by @adev to obtain + * the temperature of the passive cooling trip point. + * + * Return 0 on success or -ENODATA on failure. + */ +int thermal_acpi_passive_trip_temp(struct acpi_device *adev, int *ret_temp) +{ + int temp_decik; + int ret = acpi_passive_trip_temp(adev, &temp_decik); + + return thermal_temp(ret, temp_decik, ret_temp); +} +EXPORT_SYMBOL_GPL(thermal_acpi_passive_trip_temp); + +/** + * thermal_acpi_hot_trip_temp - Retrieve hot trip point temperature + * @adev: Target thermal zone ACPI device object. + * @ret_temp: Address to store the retrieved temperature value on success. + * + * Evaluate the _HOT object for the thermal zone represented by @adev to obtain + * the temperature of the trip point at which the system is expected to be put + * into the S4 sleep state. + * + * Return 0 on success or -ENODATA on failure. + */ +int thermal_acpi_hot_trip_temp(struct acpi_device *adev, int *ret_temp) +{ + int temp_decik; + int ret = acpi_hot_trip_temp(adev, &temp_decik); + + return thermal_temp(ret, temp_decik, ret_temp); +} +EXPORT_SYMBOL_GPL(thermal_acpi_hot_trip_temp); + +/** + * thermal_acpi_critical_trip_temp - Retrieve critical trip point temperature + * @adev: Target thermal zone ACPI device object. + * @ret_temp: Address to store the retrieved temperature value on success. + * + * Evaluate the _CRT object for the thermal zone represented by @adev to obtain + * the temperature of the critical cooling trip point. + * + * Return 0 on success or -ENODATA on failure. + */ +int thermal_acpi_critical_trip_temp(struct acpi_device *adev, int *ret_temp) +{ + int temp_decik; + int ret = acpi_critical_trip_temp(adev, &temp_decik); + + return thermal_temp(ret, temp_decik, ret_temp); +} +EXPORT_SYMBOL_GPL(thermal_acpi_critical_trip_temp); diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 62944e35fcee29..abac5cc254774d 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -329,21 +329,18 @@ const char *acpi_get_subsystem_id(acpi_handle handle) } EXPORT_SYMBOL_GPL(acpi_get_subsystem_id); -acpi_status -acpi_evaluate_reference(acpi_handle handle, - acpi_string pathname, - struct acpi_object_list *arguments, - struct acpi_handle_list *list) +bool acpi_evaluate_reference(acpi_handle handle, acpi_string pathname, + struct acpi_object_list *arguments, + struct acpi_handle_list *list) { - acpi_status status = AE_OK; - union acpi_object *package = NULL; - union acpi_object *element = NULL; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - u32 i = 0; - + union acpi_object *package; + acpi_status status; + bool ret = false; + u32 i; if (!list) - return AE_BAD_PARAMETER; + return false; /* Evaluate object. */ @@ -353,62 +350,47 @@ acpi_evaluate_reference(acpi_handle handle, package = buffer.pointer; - if ((buffer.length == 0) || !package) { - status = AE_BAD_DATA; - acpi_util_eval_error(handle, pathname, status); - goto end; - } - if (package->type != ACPI_TYPE_PACKAGE) { - status = AE_BAD_DATA; - acpi_util_eval_error(handle, pathname, status); - goto end; - } - if (!package->package.count) { - status = AE_BAD_DATA; - acpi_util_eval_error(handle, pathname, status); - goto end; - } + if (buffer.length == 0 || !package || + package->type != ACPI_TYPE_PACKAGE || !package->package.count) + goto err; - list->handles = kcalloc(package->package.count, sizeof(*list->handles), GFP_KERNEL); - if (!list->handles) { - kfree(package); - return AE_NO_MEMORY; - } list->count = package->package.count; + list->handles = kcalloc(list->count, sizeof(*list->handles), GFP_KERNEL); + if (!list->handles) + goto err_clear; /* Extract package data. */ for (i = 0; i < list->count; i++) { + union acpi_object *element = &(package->package.elements[i]); - element = &(package->package.elements[i]); + if (element->type != ACPI_TYPE_LOCAL_REFERENCE || + !element->reference.handle) + goto err_free; - if (element->type != ACPI_TYPE_LOCAL_REFERENCE) { - status = AE_BAD_DATA; - acpi_util_eval_error(handle, pathname, status); - break; - } - - if (!element->reference.handle) { - status = AE_NULL_ENTRY; - acpi_util_eval_error(handle, pathname, status); - break; - } /* Get the acpi_handle. */ list->handles[i] = element->reference.handle; acpi_handle_debug(list->handles[i], "Found in reference list\n"); } - if (ACPI_FAILURE(status)) { - list->count = 0; - kfree(list->handles); - list->handles = NULL; - } + ret = true; end: kfree(buffer.pointer); - return status; + return ret; + +err_free: + kfree(list->handles); + list->handles = NULL; + +err_clear: + list->count = 0; + +err: + acpi_util_eval_error(handle, pathname, status); + goto end; } EXPORT_SYMBOL(acpi_evaluate_reference); @@ -426,7 +408,7 @@ bool acpi_handle_list_equal(struct acpi_handle_list *list1, { return list1->count == list2->count && !memcmp(list1->handles, list2->handles, - list1->count * sizeof(acpi_handle)); + list1->count * sizeof(*list1->handles)); } EXPORT_SYMBOL_GPL(acpi_handle_list_equal); @@ -468,6 +450,40 @@ void acpi_handle_list_free(struct acpi_handle_list *list) } EXPORT_SYMBOL_GPL(acpi_handle_list_free); +/** + * acpi_device_dep - Check ACPI device dependency + * @target: ACPI handle of the target ACPI device. + * @match: ACPI handle to look up in the target's _DEP list. + * + * Return true if @match is present in the list returned by _DEP for + * @target or false otherwise. + */ +bool acpi_device_dep(acpi_handle target, acpi_handle match) +{ + struct acpi_handle_list dep_devices; + bool ret = false; + int i; + + if (!acpi_has_method(target, "_DEP")) + return false; + + if (!acpi_evaluate_reference(target, "_DEP", NULL, &dep_devices)) { + acpi_handle_debug(target, "Failed to evaluate _DEP.\n"); + return false; + } + + for (i = 0; i < dep_devices.count; i++) { + if (dep_devices.handles[i] == match) { + ret = true; + break; + } + } + + acpi_handle_list_free(&dep_devices); + return ret; +} +EXPORT_SYMBOL_GPL(acpi_device_dep); + acpi_status acpi_get_physical_device_location(acpi_handle handle, struct acpi_pld_info **pld) { @@ -824,54 +840,6 @@ bool acpi_check_dsm(acpi_handle handle, const guid_t *guid, u64 rev, u64 funcs) } EXPORT_SYMBOL(acpi_check_dsm); -/** - * acpi_dev_uid_match - Match device by supplied UID - * @adev: ACPI device to match. - * @uid2: Unique ID of the device. - * - * Matches UID in @adev with given @uid2. - * - * Returns: - * - %true if matches. - * - %false otherwise. - */ -bool acpi_dev_uid_match(struct acpi_device *adev, const char *uid2) -{ - const char *uid1 = acpi_device_uid(adev); - - return uid1 && uid2 && !strcmp(uid1, uid2); -} -EXPORT_SYMBOL_GPL(acpi_dev_uid_match); - -/** - * acpi_dev_hid_uid_match - Match device by supplied HID and UID - * @adev: ACPI device to match. - * @hid2: Hardware ID of the device. - * @uid2: Unique ID of the device, pass NULL to not check _UID. - * - * Matches HID and UID in @adev with given @hid2 and @uid2. Absence of @uid2 - * will be treated as a match. If user wants to validate @uid2, it should be - * done before calling this function. - * - * Returns: - * - %true if matches or @uid2 is NULL. - * - %false otherwise. - */ -bool acpi_dev_hid_uid_match(struct acpi_device *adev, - const char *hid2, const char *uid2) -{ - const char *hid1 = acpi_device_hid(adev); - - if (strcmp(hid1, hid2)) - return false; - - if (!uid2) - return true; - - return acpi_dev_uid_match(adev, uid2); -} -EXPORT_SYMBOL(acpi_dev_hid_uid_match); - /** * acpi_dev_uid_to_integer - treat ACPI device _UID as integer * @adev: ACPI device to get _UID from diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 92128aae2d0601..8dd23b19e99731 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -1921,7 +1921,7 @@ static void binder_deferred_fd_close(int fd) if (!twcb) return; init_task_work(&twcb->twork, binder_do_fd_close); - twcb->file = close_fd_get_file(fd); + twcb->file = file_close_fd(fd); if (twcb->file) { // pin it until binder_do_fd_close(); see comments there get_file(twcb->file); @@ -2077,9 +2077,8 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, * Convert the address to an offset relative to * the base of the transaction buffer. */ - fda_offset = - (parent->buffer - (uintptr_t)buffer->user_data) + - fda->parent_offset; + fda_offset = parent->buffer - buffer->user_data + + fda->parent_offset; for (fd_index = 0; fd_index < fda->num_fds; fd_index++) { u32 fd; @@ -2597,7 +2596,7 @@ static int binder_translate_fd_array(struct list_head *pf_head, * Convert the address to an offset relative to * the base of the transaction buffer. */ - fda_offset = (parent->buffer - (uintptr_t)t->buffer->user_data) + + fda_offset = parent->buffer - t->buffer->user_data + fda->parent_offset; sender_ufda_base = (void __user *)(uintptr_t)sender_uparent->buffer + fda->parent_offset; @@ -2672,8 +2671,9 @@ static int binder_fixup_parent(struct list_head *pf_head, proc->pid, thread->pid); return -EINVAL; } - buffer_offset = bp->parent_offset + - (uintptr_t)parent->buffer - (uintptr_t)b->user_data; + + buffer_offset = bp->parent_offset + parent->buffer - b->user_data; + return binder_add_fixup(pf_head, buffer_offset, bp->buffer, 0); } @@ -3225,7 +3225,7 @@ static void binder_transaction(struct binder_proc *proc, t->buffer = binder_alloc_new_buf(&target_proc->alloc, tr->data_size, tr->offsets_size, extra_buffers_size, - !reply && (t->flags & TF_ONE_WAY), current->tgid); + !reply && (t->flags & TF_ONE_WAY)); if (IS_ERR(t->buffer)) { char *s; @@ -3250,7 +3250,7 @@ static void binder_transaction(struct binder_proc *proc, ALIGN(extra_buffers_size, sizeof(void *)) - ALIGN(secctx_sz, sizeof(u64)); - t->security_ctx = (uintptr_t)t->buffer->user_data + buf_offset; + t->security_ctx = t->buffer->user_data + buf_offset; err = binder_alloc_copy_to_buffer(&target_proc->alloc, t->buffer, buf_offset, secctx, secctx_sz); @@ -3527,8 +3527,7 @@ static void binder_transaction(struct binder_proc *proc, goto err_translate_failed; } /* Fixup buffer pointer to target proc address space */ - bp->buffer = (uintptr_t) - t->buffer->user_data + sg_buf_offset; + bp->buffer = t->buffer->user_data + sg_buf_offset; sg_buf_offset += ALIGN(bp->length, sizeof(u64)); num_valid = (buffer_offset - off_start_offset) / @@ -4698,7 +4697,7 @@ retry: } trd->data_size = t->buffer->data_size; trd->offsets_size = t->buffer->offsets_size; - trd->data.ptr.buffer = (uintptr_t)t->buffer->user_data; + trd->data.ptr.buffer = t->buffer->user_data; trd->data.ptr.offsets = trd->data.ptr.buffer + ALIGN(t->buffer->data_size, sizeof(void *)); @@ -5030,7 +5029,7 @@ static __poll_t binder_poll(struct file *filp, thread = binder_get_thread(proc); if (!thread) - return POLLERR; + return EPOLLERR; binder_inner_proc_lock(thread->proc); thread->looper |= BINDER_LOOPER_STATE_POLL; @@ -5981,9 +5980,9 @@ static void print_binder_transaction_ilocked(struct seq_file *m, } if (buffer->target_node) seq_printf(m, " node %d", buffer->target_node->debug_id); - seq_printf(m, " size %zd:%zd data %pK\n", + seq_printf(m, " size %zd:%zd offset %lx\n", buffer->data_size, buffer->offsets_size, - buffer->user_data); + proc->alloc.buffer - buffer->user_data); } static void print_binder_work_ilocked(struct seq_file *m, diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index 138f6d43d13b29..e0e4dc38b69207 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -26,7 +26,7 @@ #include "binder_alloc.h" #include "binder_trace.h" -struct list_lru binder_alloc_lru; +struct list_lru binder_freelist; static DEFINE_MUTEX(binder_alloc_mmap_lock); @@ -125,23 +125,20 @@ static void binder_insert_allocated_buffer_locked( static struct binder_buffer *binder_alloc_prepare_to_free_locked( struct binder_alloc *alloc, - uintptr_t user_ptr) + unsigned long user_ptr) { struct rb_node *n = alloc->allocated_buffers.rb_node; struct binder_buffer *buffer; - void __user *uptr; - - uptr = (void __user *)user_ptr; while (n) { buffer = rb_entry(n, struct binder_buffer, rb_node); BUG_ON(buffer->free); - if (uptr < buffer->user_data) + if (user_ptr < buffer->user_data) { n = n->rb_left; - else if (uptr > buffer->user_data) + } else if (user_ptr > buffer->user_data) { n = n->rb_right; - else { + } else { /* * Guard against user threads attempting to * free the buffer when in use by kernel or @@ -168,145 +165,168 @@ static struct binder_buffer *binder_alloc_prepare_to_free_locked( * Return: Pointer to buffer or NULL */ struct binder_buffer *binder_alloc_prepare_to_free(struct binder_alloc *alloc, - uintptr_t user_ptr) + unsigned long user_ptr) { struct binder_buffer *buffer; - mutex_lock(&alloc->mutex); + spin_lock(&alloc->lock); buffer = binder_alloc_prepare_to_free_locked(alloc, user_ptr); - mutex_unlock(&alloc->mutex); + spin_unlock(&alloc->lock); return buffer; } -static int binder_update_page_range(struct binder_alloc *alloc, int allocate, - void __user *start, void __user *end) +static inline void +binder_set_installed_page(struct binder_lru_page *lru_page, + struct page *page) +{ + /* Pairs with acquire in binder_get_installed_page() */ + smp_store_release(&lru_page->page_ptr, page); +} + +static inline struct page * +binder_get_installed_page(struct binder_lru_page *lru_page) +{ + /* Pairs with release in binder_set_installed_page() */ + return smp_load_acquire(&lru_page->page_ptr); +} + +static void binder_lru_freelist_add(struct binder_alloc *alloc, + unsigned long start, unsigned long end) { - void __user *page_addr; - unsigned long user_page_addr; struct binder_lru_page *page; - struct vm_area_struct *vma = NULL; - struct mm_struct *mm = NULL; - bool need_mm = false; + unsigned long page_addr; - binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: %s pages %pK-%pK\n", alloc->pid, - allocate ? "allocate" : "free", start, end); + trace_binder_update_page_range(alloc, false, start, end); - if (end <= start) - return 0; + for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) { + size_t index; + int ret; - trace_binder_update_page_range(alloc, allocate, start, end); + index = (page_addr - alloc->buffer) / PAGE_SIZE; + page = &alloc->pages[index]; - if (allocate == 0) - goto free_range; + if (!binder_get_installed_page(page)) + continue; - for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) { - page = &alloc->pages[(page_addr - alloc->buffer) / PAGE_SIZE]; - if (!page->page_ptr) { - need_mm = true; - break; - } + trace_binder_free_lru_start(alloc, index); + + ret = list_lru_add_obj(&binder_freelist, &page->lru); + WARN_ON(!ret); + + trace_binder_free_lru_end(alloc, index); } +} + +static int binder_install_single_page(struct binder_alloc *alloc, + struct binder_lru_page *lru_page, + unsigned long addr) +{ + struct page *page; + int ret = 0; - if (need_mm && mmget_not_zero(alloc->mm)) - mm = alloc->mm; + if (!mmget_not_zero(alloc->mm)) + return -ESRCH; - if (mm) { - mmap_write_lock(mm); - vma = alloc->vma; + /* + * Protected with mmap_sem in write mode as multiple tasks + * might race to install the same page. + */ + mmap_write_lock(alloc->mm); + if (binder_get_installed_page(lru_page)) + goto out; + + if (!alloc->vma) { + pr_err("%d: %s failed, no vma\n", alloc->pid, __func__); + ret = -ESRCH; + goto out; } - if (!vma && need_mm) { - binder_alloc_debug(BINDER_DEBUG_USER_ERROR, - "%d: binder_alloc_buf failed to map pages in userspace, no vma\n", - alloc->pid); - goto err_no_vma; + page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO); + if (!page) { + pr_err("%d: failed to allocate page\n", alloc->pid); + ret = -ENOMEM; + goto out; } - for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) { + ret = vm_insert_page(alloc->vma, addr, page); + if (ret) { + pr_err("%d: %s failed to insert page at offset %lx with %d\n", + alloc->pid, __func__, addr - alloc->buffer, ret); + __free_page(page); + ret = -ENOMEM; + goto out; + } + + /* Mark page installation complete and safe to use */ + binder_set_installed_page(lru_page, page); +out: + mmap_write_unlock(alloc->mm); + mmput_async(alloc->mm); + return ret; +} + +static int binder_install_buffer_pages(struct binder_alloc *alloc, + struct binder_buffer *buffer, + size_t size) +{ + struct binder_lru_page *page; + unsigned long start, final; + unsigned long page_addr; + + start = buffer->user_data & PAGE_MASK; + final = PAGE_ALIGN(buffer->user_data + size); + + for (page_addr = start; page_addr < final; page_addr += PAGE_SIZE) { + unsigned long index; int ret; - bool on_lru; - size_t index; index = (page_addr - alloc->buffer) / PAGE_SIZE; page = &alloc->pages[index]; - if (page->page_ptr) { - trace_binder_alloc_lru_start(alloc, index); - - on_lru = list_lru_del(&binder_alloc_lru, &page->lru); - WARN_ON(!on_lru); - - trace_binder_alloc_lru_end(alloc, index); + if (binder_get_installed_page(page)) continue; - } - - if (WARN_ON(!vma)) - goto err_page_ptr_cleared; trace_binder_alloc_page_start(alloc, index); - page->page_ptr = alloc_page(GFP_KERNEL | - __GFP_HIGHMEM | - __GFP_ZERO); - if (!page->page_ptr) { - pr_err("%d: binder_alloc_buf failed for page at %pK\n", - alloc->pid, page_addr); - goto err_alloc_page_failed; - } - page->alloc = alloc; - INIT_LIST_HEAD(&page->lru); - - user_page_addr = (uintptr_t)page_addr; - ret = vm_insert_page(vma, user_page_addr, page[0].page_ptr); - if (ret) { - pr_err("%d: binder_alloc_buf failed to map page at %lx in userspace\n", - alloc->pid, user_page_addr); - goto err_vm_insert_page_failed; - } - if (index + 1 > alloc->pages_high) - alloc->pages_high = index + 1; + ret = binder_install_single_page(alloc, page, page_addr); + if (ret) + return ret; trace_binder_alloc_page_end(alloc, index); } - if (mm) { - mmap_write_unlock(mm); - mmput(mm); - } + return 0; +} -free_range: - for (page_addr = end - PAGE_SIZE; 1; page_addr -= PAGE_SIZE) { - bool ret; - size_t index; +/* The range of pages should exclude those shared with other buffers */ +static void binder_lru_freelist_del(struct binder_alloc *alloc, + unsigned long start, unsigned long end) +{ + struct binder_lru_page *page; + unsigned long page_addr; + + trace_binder_update_page_range(alloc, true, start, end); + + for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) { + unsigned long index; + bool on_lru; index = (page_addr - alloc->buffer) / PAGE_SIZE; page = &alloc->pages[index]; - trace_binder_free_lru_start(alloc, index); + if (page->page_ptr) { + trace_binder_alloc_lru_start(alloc, index); - ret = list_lru_add(&binder_alloc_lru, &page->lru); - WARN_ON(!ret); + on_lru = list_lru_del_obj(&binder_freelist, &page->lru); + WARN_ON(!on_lru); - trace_binder_free_lru_end(alloc, index); - if (page_addr == start) - break; - continue; - -err_vm_insert_page_failed: - __free_page(page->page_ptr); - page->page_ptr = NULL; -err_alloc_page_failed: -err_page_ptr_cleared: - if (page_addr == start) - break; - } -err_no_vma: - if (mm) { - mmap_write_unlock(mm); - mmput(mm); + trace_binder_alloc_lru_end(alloc, index); + continue; + } + + if (index + 1 > alloc->pages_high) + alloc->pages_high = index + 1; } - return vma ? -ENOMEM : -ESRCH; } static inline void binder_alloc_set_vma(struct binder_alloc *alloc, @@ -323,7 +343,44 @@ static inline struct vm_area_struct *binder_alloc_get_vma( return smp_load_acquire(&alloc->vma); } -static bool debug_low_async_space_locked(struct binder_alloc *alloc, int pid) +static void debug_no_space_locked(struct binder_alloc *alloc) +{ + size_t largest_alloc_size = 0; + struct binder_buffer *buffer; + size_t allocated_buffers = 0; + size_t largest_free_size = 0; + size_t total_alloc_size = 0; + size_t total_free_size = 0; + size_t free_buffers = 0; + size_t buffer_size; + struct rb_node *n; + + for (n = rb_first(&alloc->allocated_buffers); n; n = rb_next(n)) { + buffer = rb_entry(n, struct binder_buffer, rb_node); + buffer_size = binder_alloc_buffer_size(alloc, buffer); + allocated_buffers++; + total_alloc_size += buffer_size; + if (buffer_size > largest_alloc_size) + largest_alloc_size = buffer_size; + } + + for (n = rb_first(&alloc->free_buffers); n; n = rb_next(n)) { + buffer = rb_entry(n, struct binder_buffer, rb_node); + buffer_size = binder_alloc_buffer_size(alloc, buffer); + free_buffers++; + total_free_size += buffer_size; + if (buffer_size > largest_free_size) + largest_free_size = buffer_size; + } + + binder_alloc_debug(BINDER_DEBUG_USER_ERROR, + "allocated: %zd (num: %zd largest: %zd), free: %zd (num: %zd largest: %zd)\n", + total_alloc_size, allocated_buffers, + largest_alloc_size, total_free_size, + free_buffers, largest_free_size); +} + +static bool debug_low_async_space_locked(struct binder_alloc *alloc) { /* * Find the amount and size of buffers allocated by the current caller; @@ -332,10 +389,20 @@ static bool debug_low_async_space_locked(struct binder_alloc *alloc, int pid) * and at some point we'll catch them in the act. This is more efficient * than keeping a map per pid. */ - struct rb_node *n; struct binder_buffer *buffer; size_t total_alloc_size = 0; + int pid = current->tgid; size_t num_buffers = 0; + struct rb_node *n; + + /* + * Only start detecting spammers once we have less than 20% of async + * space left (which is less than 10% of total buffer size). + */ + if (alloc->free_async_space >= alloc->buffer_size / 10) { + alloc->oneway_spam_detected = false; + return false; + } for (n = rb_first(&alloc->allocated_buffers); n != NULL; n = rb_next(n)) { @@ -344,8 +411,7 @@ static bool debug_low_async_space_locked(struct binder_alloc *alloc, int pid) continue; if (!buffer->async_transaction) continue; - total_alloc_size += binder_alloc_buffer_size(alloc, buffer) - + sizeof(struct binder_buffer); + total_alloc_size += binder_alloc_buffer_size(alloc, buffer); num_buffers++; } @@ -366,58 +432,28 @@ static bool debug_low_async_space_locked(struct binder_alloc *alloc, int pid) return false; } +/* Callers preallocate @new_buffer, it is freed by this function if unused */ static struct binder_buffer *binder_alloc_new_buf_locked( struct binder_alloc *alloc, - size_t data_size, - size_t offsets_size, - size_t extra_buffers_size, - int is_async, - int pid) + struct binder_buffer *new_buffer, + size_t size, + int is_async) { struct rb_node *n = alloc->free_buffers.rb_node; + struct rb_node *best_fit = NULL; struct binder_buffer *buffer; + unsigned long next_used_page; + unsigned long curr_last_page; size_t buffer_size; - struct rb_node *best_fit = NULL; - void __user *has_page_addr; - void __user *end_page_addr; - size_t size, data_offsets_size; - int ret; - - /* Check binder_alloc is fully initialized */ - if (!binder_alloc_get_vma(alloc)) { - binder_alloc_debug(BINDER_DEBUG_USER_ERROR, - "%d: binder_alloc_buf, no vma\n", - alloc->pid); - return ERR_PTR(-ESRCH); - } - - data_offsets_size = ALIGN(data_size, sizeof(void *)) + - ALIGN(offsets_size, sizeof(void *)); - if (data_offsets_size < data_size || data_offsets_size < offsets_size) { - binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: got transaction with invalid size %zd-%zd\n", - alloc->pid, data_size, offsets_size); - return ERR_PTR(-EINVAL); - } - size = data_offsets_size + ALIGN(extra_buffers_size, sizeof(void *)); - if (size < data_offsets_size || size < extra_buffers_size) { - binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: got transaction with invalid extra_buffers_size %zd\n", - alloc->pid, extra_buffers_size); - return ERR_PTR(-EINVAL); - } - if (is_async && - alloc->free_async_space < size + sizeof(struct binder_buffer)) { + if (is_async && alloc->free_async_space < size) { binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, "%d: binder_alloc_buf size %zd failed, no async space left\n", alloc->pid, size); - return ERR_PTR(-ENOSPC); + buffer = ERR_PTR(-ENOSPC); + goto out; } - /* Pad 0-size buffers so they get assigned unique addresses */ - size = max(size, sizeof(void *)); - while (n) { buffer = rb_entry(n, struct binder_buffer, rb_node); BUG_ON(!buffer->free); @@ -426,121 +462,92 @@ static struct binder_buffer *binder_alloc_new_buf_locked( if (size < buffer_size) { best_fit = n; n = n->rb_left; - } else if (size > buffer_size) + } else if (size > buffer_size) { n = n->rb_right; - else { + } else { best_fit = n; break; } } - if (best_fit == NULL) { - size_t allocated_buffers = 0; - size_t largest_alloc_size = 0; - size_t total_alloc_size = 0; - size_t free_buffers = 0; - size_t largest_free_size = 0; - size_t total_free_size = 0; - - for (n = rb_first(&alloc->allocated_buffers); n != NULL; - n = rb_next(n)) { - buffer = rb_entry(n, struct binder_buffer, rb_node); - buffer_size = binder_alloc_buffer_size(alloc, buffer); - allocated_buffers++; - total_alloc_size += buffer_size; - if (buffer_size > largest_alloc_size) - largest_alloc_size = buffer_size; - } - for (n = rb_first(&alloc->free_buffers); n != NULL; - n = rb_next(n)) { - buffer = rb_entry(n, struct binder_buffer, rb_node); - buffer_size = binder_alloc_buffer_size(alloc, buffer); - free_buffers++; - total_free_size += buffer_size; - if (buffer_size > largest_free_size) - largest_free_size = buffer_size; - } + + if (unlikely(!best_fit)) { binder_alloc_debug(BINDER_DEBUG_USER_ERROR, "%d: binder_alloc_buf size %zd failed, no address space\n", alloc->pid, size); - binder_alloc_debug(BINDER_DEBUG_USER_ERROR, - "allocated: %zd (num: %zd largest: %zd), free: %zd (num: %zd largest: %zd)\n", - total_alloc_size, allocated_buffers, - largest_alloc_size, total_free_size, - free_buffers, largest_free_size); - return ERR_PTR(-ENOSPC); + debug_no_space_locked(alloc); + buffer = ERR_PTR(-ENOSPC); + goto out; } - if (n == NULL) { + + if (buffer_size != size) { + /* Found an oversized buffer and needs to be split */ buffer = rb_entry(best_fit, struct binder_buffer, rb_node); buffer_size = binder_alloc_buffer_size(alloc, buffer); + + WARN_ON(n || buffer_size == size); + new_buffer->user_data = buffer->user_data + size; + list_add(&new_buffer->entry, &buffer->entry); + new_buffer->free = 1; + binder_insert_free_buffer(alloc, new_buffer); + new_buffer = NULL; } binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, "%d: binder_alloc_buf size %zd got buffer %pK size %zd\n", alloc->pid, size, buffer, buffer_size); - has_page_addr = (void __user *) - (((uintptr_t)buffer->user_data + buffer_size) & PAGE_MASK); - WARN_ON(n && buffer_size != size); - end_page_addr = - (void __user *)PAGE_ALIGN((uintptr_t)buffer->user_data + size); - if (end_page_addr > has_page_addr) - end_page_addr = has_page_addr; - ret = binder_update_page_range(alloc, 1, (void __user *) - PAGE_ALIGN((uintptr_t)buffer->user_data), end_page_addr); - if (ret) - return ERR_PTR(ret); - - if (buffer_size != size) { - struct binder_buffer *new_buffer; - - new_buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); - if (!new_buffer) { - pr_err("%s: %d failed to alloc new buffer struct\n", - __func__, alloc->pid); - goto err_alloc_buf_struct_failed; - } - new_buffer->user_data = (u8 __user *)buffer->user_data + size; - list_add(&new_buffer->entry, &buffer->entry); - new_buffer->free = 1; - binder_insert_free_buffer(alloc, new_buffer); - } + /* + * Now we remove the pages from the freelist. A clever calculation + * with buffer_size determines if the last page is shared with an + * adjacent in-use buffer. In such case, the page has been already + * removed from the freelist so we trim our range short. + */ + next_used_page = (buffer->user_data + buffer_size) & PAGE_MASK; + curr_last_page = PAGE_ALIGN(buffer->user_data + size); + binder_lru_freelist_del(alloc, PAGE_ALIGN(buffer->user_data), + min(next_used_page, curr_last_page)); - rb_erase(best_fit, &alloc->free_buffers); + rb_erase(&buffer->rb_node, &alloc->free_buffers); buffer->free = 0; buffer->allow_user_free = 0; binder_insert_allocated_buffer_locked(alloc, buffer); - binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: binder_alloc_buf size %zd got %pK\n", - alloc->pid, size, buffer); - buffer->data_size = data_size; - buffer->offsets_size = offsets_size; buffer->async_transaction = is_async; - buffer->extra_buffers_size = extra_buffers_size; - buffer->pid = pid; buffer->oneway_spam_suspect = false; if (is_async) { - alloc->free_async_space -= size + sizeof(struct binder_buffer); + alloc->free_async_space -= size; binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC, "%d: binder_alloc_buf size %zd async free %zd\n", alloc->pid, size, alloc->free_async_space); - if (alloc->free_async_space < alloc->buffer_size / 10) { - /* - * Start detecting spammers once we have less than 20% - * of async space left (which is less than 10% of total - * buffer size). - */ - buffer->oneway_spam_suspect = debug_low_async_space_locked(alloc, pid); - } else { - alloc->oneway_spam_detected = false; - } + if (debug_low_async_space_locked(alloc)) + buffer->oneway_spam_suspect = true; } + +out: + /* Discard possibly unused new_buffer */ + kfree(new_buffer); return buffer; +} -err_alloc_buf_struct_failed: - binder_update_page_range(alloc, 0, (void __user *) - PAGE_ALIGN((uintptr_t)buffer->user_data), - end_page_addr); - return ERR_PTR(-ENOMEM); +/* Calculate the sanitized total size, returns 0 for invalid request */ +static inline size_t sanitized_size(size_t data_size, + size_t offsets_size, + size_t extra_buffers_size) +{ + size_t total, tmp; + + /* Align to pointer size and check for overflows */ + tmp = ALIGN(data_size, sizeof(void *)) + + ALIGN(offsets_size, sizeof(void *)); + if (tmp < data_size || tmp < offsets_size) + return 0; + total = tmp + ALIGN(extra_buffers_size, sizeof(void *)); + if (total < tmp || total < extra_buffers_size) + return 0; + + /* Pad 0-sized buffers so they get a unique address */ + total = max(total, sizeof(void *)); + + return total; } /** @@ -550,87 +557,101 @@ err_alloc_buf_struct_failed: * @offsets_size: user specified buffer offset * @extra_buffers_size: size of extra space for meta-data (eg, security context) * @is_async: buffer for async transaction - * @pid: pid to attribute allocation to (used for debugging) * * Allocate a new buffer given the requested sizes. Returns * the kernel version of the buffer pointer. The size allocated * is the sum of the three given sizes (each rounded up to * pointer-sized boundary) * - * Return: The allocated buffer or %NULL if error + * Return: The allocated buffer or %ERR_PTR(-errno) if error */ struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc, size_t data_size, size_t offsets_size, size_t extra_buffers_size, - int is_async, - int pid) + int is_async) { - struct binder_buffer *buffer; + struct binder_buffer *buffer, *next; + size_t size; + int ret; + + /* Check binder_alloc is fully initialized */ + if (!binder_alloc_get_vma(alloc)) { + binder_alloc_debug(BINDER_DEBUG_USER_ERROR, + "%d: binder_alloc_buf, no vma\n", + alloc->pid); + return ERR_PTR(-ESRCH); + } + + size = sanitized_size(data_size, offsets_size, extra_buffers_size); + if (unlikely(!size)) { + binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, + "%d: got transaction with invalid size %zd-%zd-%zd\n", + alloc->pid, data_size, offsets_size, + extra_buffers_size); + return ERR_PTR(-EINVAL); + } + + /* Preallocate the next buffer */ + next = kzalloc(sizeof(*next), GFP_KERNEL); + if (!next) + return ERR_PTR(-ENOMEM); - mutex_lock(&alloc->mutex); - buffer = binder_alloc_new_buf_locked(alloc, data_size, offsets_size, - extra_buffers_size, is_async, pid); - mutex_unlock(&alloc->mutex); + spin_lock(&alloc->lock); + buffer = binder_alloc_new_buf_locked(alloc, next, size, is_async); + if (IS_ERR(buffer)) { + spin_unlock(&alloc->lock); + goto out; + } + + buffer->data_size = data_size; + buffer->offsets_size = offsets_size; + buffer->extra_buffers_size = extra_buffers_size; + buffer->pid = current->tgid; + spin_unlock(&alloc->lock); + + ret = binder_install_buffer_pages(alloc, buffer, size); + if (ret) { + binder_alloc_free_buf(alloc, buffer); + buffer = ERR_PTR(ret); + } +out: return buffer; } -static void __user *buffer_start_page(struct binder_buffer *buffer) +static unsigned long buffer_start_page(struct binder_buffer *buffer) { - return (void __user *)((uintptr_t)buffer->user_data & PAGE_MASK); + return buffer->user_data & PAGE_MASK; } -static void __user *prev_buffer_end_page(struct binder_buffer *buffer) +static unsigned long prev_buffer_end_page(struct binder_buffer *buffer) { - return (void __user *) - (((uintptr_t)(buffer->user_data) - 1) & PAGE_MASK); + return (buffer->user_data - 1) & PAGE_MASK; } static void binder_delete_free_buffer(struct binder_alloc *alloc, struct binder_buffer *buffer) { - struct binder_buffer *prev, *next = NULL; - bool to_free = true; + struct binder_buffer *prev, *next; + + if (PAGE_ALIGNED(buffer->user_data)) + goto skip_freelist; BUG_ON(alloc->buffers.next == &buffer->entry); prev = binder_buffer_prev(buffer); BUG_ON(!prev->free); - if (prev_buffer_end_page(prev) == buffer_start_page(buffer)) { - to_free = false; - binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: merge free, buffer %pK share page with %pK\n", - alloc->pid, buffer->user_data, - prev->user_data); - } + if (prev_buffer_end_page(prev) == buffer_start_page(buffer)) + goto skip_freelist; if (!list_is_last(&buffer->entry, &alloc->buffers)) { next = binder_buffer_next(buffer); - if (buffer_start_page(next) == buffer_start_page(buffer)) { - to_free = false; - binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: merge free, buffer %pK share page with %pK\n", - alloc->pid, - buffer->user_data, - next->user_data); - } + if (buffer_start_page(next) == buffer_start_page(buffer)) + goto skip_freelist; } - if (PAGE_ALIGNED(buffer->user_data)) { - binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: merge free, buffer start %pK is page aligned\n", - alloc->pid, buffer->user_data); - to_free = false; - } - - if (to_free) { - binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%d: merge free, buffer %pK do not share page with %pK or %pK\n", - alloc->pid, buffer->user_data, - prev->user_data, - next ? next->user_data : NULL); - binder_update_page_range(alloc, 0, buffer_start_page(buffer), - buffer_start_page(buffer) + PAGE_SIZE); - } + binder_lru_freelist_add(alloc, buffer_start_page(buffer), + buffer_start_page(buffer) + PAGE_SIZE); +skip_freelist: list_del(&buffer->entry); kfree(buffer); } @@ -657,17 +678,14 @@ static void binder_free_buf_locked(struct binder_alloc *alloc, BUG_ON(buffer->user_data > alloc->buffer + alloc->buffer_size); if (buffer->async_transaction) { - alloc->free_async_space += buffer_size + sizeof(struct binder_buffer); - + alloc->free_async_space += buffer_size; binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC, "%d: binder_free_buf size %zd async free %zd\n", alloc->pid, size, alloc->free_async_space); } - binder_update_page_range(alloc, 0, - (void __user *)PAGE_ALIGN((uintptr_t)buffer->user_data), - (void __user *)(((uintptr_t) - buffer->user_data + buffer_size) & PAGE_MASK)); + binder_lru_freelist_add(alloc, PAGE_ALIGN(buffer->user_data), + (buffer->user_data + buffer_size) & PAGE_MASK); rb_erase(&buffer->rb_node, &alloc->allocated_buffers); buffer->free = 1; @@ -691,8 +709,68 @@ static void binder_free_buf_locked(struct binder_alloc *alloc, binder_insert_free_buffer(alloc, buffer); } +/** + * binder_alloc_get_page() - get kernel pointer for given buffer offset + * @alloc: binder_alloc for this proc + * @buffer: binder buffer to be accessed + * @buffer_offset: offset into @buffer data + * @pgoffp: address to copy final page offset to + * + * Lookup the struct page corresponding to the address + * at @buffer_offset into @buffer->user_data. If @pgoffp is not + * NULL, the byte-offset into the page is written there. + * + * The caller is responsible to ensure that the offset points + * to a valid address within the @buffer and that @buffer is + * not freeable by the user. Since it can't be freed, we are + * guaranteed that the corresponding elements of @alloc->pages[] + * cannot change. + * + * Return: struct page + */ +static struct page *binder_alloc_get_page(struct binder_alloc *alloc, + struct binder_buffer *buffer, + binder_size_t buffer_offset, + pgoff_t *pgoffp) +{ + binder_size_t buffer_space_offset = buffer_offset + + (buffer->user_data - alloc->buffer); + pgoff_t pgoff = buffer_space_offset & ~PAGE_MASK; + size_t index = buffer_space_offset >> PAGE_SHIFT; + struct binder_lru_page *lru_page; + + lru_page = &alloc->pages[index]; + *pgoffp = pgoff; + return lru_page->page_ptr; +} + +/** + * binder_alloc_clear_buf() - zero out buffer + * @alloc: binder_alloc for this proc + * @buffer: binder buffer to be cleared + * + * memset the given buffer to 0 + */ static void binder_alloc_clear_buf(struct binder_alloc *alloc, - struct binder_buffer *buffer); + struct binder_buffer *buffer) +{ + size_t bytes = binder_alloc_buffer_size(alloc, buffer); + binder_size_t buffer_offset = 0; + + while (bytes) { + unsigned long size; + struct page *page; + pgoff_t pgoff; + + page = binder_alloc_get_page(alloc, buffer, + buffer_offset, &pgoff); + size = min_t(size_t, bytes, PAGE_SIZE - pgoff); + memset_page(page, pgoff, 0, size); + bytes -= size; + buffer_offset += size; + } +} + /** * binder_alloc_free_buf() - free a binder buffer * @alloc: binder_alloc for this proc @@ -706,18 +784,18 @@ void binder_alloc_free_buf(struct binder_alloc *alloc, /* * We could eliminate the call to binder_alloc_clear_buf() * from binder_alloc_deferred_release() by moving this to - * binder_alloc_free_buf_locked(). However, that could - * increase contention for the alloc mutex if clear_on_free - * is used frequently for large buffers. The mutex is not + * binder_free_buf_locked(). However, that could + * increase contention for the alloc->lock if clear_on_free + * is used frequently for large buffers. This lock is not * needed for correctness here. */ if (buffer->clear_on_free) { binder_alloc_clear_buf(alloc, buffer); buffer->clear_on_free = false; } - mutex_lock(&alloc->mutex); + spin_lock(&alloc->lock); binder_free_buf_locked(alloc, buffer); - mutex_unlock(&alloc->mutex); + spin_unlock(&alloc->lock); } /** @@ -736,9 +814,9 @@ void binder_alloc_free_buf(struct binder_alloc *alloc, int binder_alloc_mmap_handler(struct binder_alloc *alloc, struct vm_area_struct *vma) { - int ret; - const char *failure_string; struct binder_buffer *buffer; + const char *failure_string; + int ret, i; if (unlikely(vma->vm_mm != alloc->mm)) { ret = -EINVAL; @@ -756,7 +834,7 @@ int binder_alloc_mmap_handler(struct binder_alloc *alloc, SZ_4M); mutex_unlock(&binder_alloc_mmap_lock); - alloc->buffer = (void __user *)vma->vm_start; + alloc->buffer = vma->vm_start; alloc->pages = kcalloc(alloc->buffer_size / PAGE_SIZE, sizeof(alloc->pages[0]), @@ -767,6 +845,11 @@ int binder_alloc_mmap_handler(struct binder_alloc *alloc, goto err_alloc_pages_failed; } + for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) { + alloc->pages[i].alloc = alloc; + INIT_LIST_HEAD(&alloc->pages[i].lru); + } + buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); if (!buffer) { ret = -ENOMEM; @@ -789,7 +872,7 @@ err_alloc_buf_struct_failed: kfree(alloc->pages); alloc->pages = NULL; err_alloc_pages_failed: - alloc->buffer = NULL; + alloc->buffer = 0; mutex_lock(&binder_alloc_mmap_lock); alloc->buffer_size = 0; err_already_mapped: @@ -810,7 +893,7 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc) struct binder_buffer *buffer; buffers = 0; - mutex_lock(&alloc->mutex); + spin_lock(&alloc->lock); BUG_ON(alloc->vma); while ((n = rb_first(&alloc->allocated_buffers))) { @@ -842,25 +925,25 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc) int i; for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) { - void __user *page_addr; + unsigned long page_addr; bool on_lru; if (!alloc->pages[i].page_ptr) continue; - on_lru = list_lru_del(&binder_alloc_lru, - &alloc->pages[i].lru); + on_lru = list_lru_del_obj(&binder_freelist, + &alloc->pages[i].lru); page_addr = alloc->buffer + i * PAGE_SIZE; binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, - "%s: %d: page %d at %pK %s\n", - __func__, alloc->pid, i, page_addr, + "%s: %d: page %d %s\n", + __func__, alloc->pid, i, on_lru ? "on lru" : "active"); __free_page(alloc->pages[i].page_ptr); page_count++; } kfree(alloc->pages); } - mutex_unlock(&alloc->mutex); + spin_unlock(&alloc->lock); if (alloc->mm) mmdrop(alloc->mm); @@ -869,16 +952,6 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc) __func__, alloc->pid, buffers, page_count); } -static void print_binder_buffer(struct seq_file *m, const char *prefix, - struct binder_buffer *buffer) -{ - seq_printf(m, "%s %d: %pK size %zd:%zd:%zd %s\n", - prefix, buffer->debug_id, buffer->user_data, - buffer->data_size, buffer->offsets_size, - buffer->extra_buffers_size, - buffer->transaction ? "active" : "delivered"); -} - /** * binder_alloc_print_allocated() - print buffer info * @m: seq_file for output via seq_printf() @@ -890,13 +963,20 @@ static void print_binder_buffer(struct seq_file *m, const char *prefix, void binder_alloc_print_allocated(struct seq_file *m, struct binder_alloc *alloc) { + struct binder_buffer *buffer; struct rb_node *n; - mutex_lock(&alloc->mutex); - for (n = rb_first(&alloc->allocated_buffers); n != NULL; n = rb_next(n)) - print_binder_buffer(m, " buffer", - rb_entry(n, struct binder_buffer, rb_node)); - mutex_unlock(&alloc->mutex); + spin_lock(&alloc->lock); + for (n = rb_first(&alloc->allocated_buffers); n; n = rb_next(n)) { + buffer = rb_entry(n, struct binder_buffer, rb_node); + seq_printf(m, " buffer %d: %lx size %zd:%zd:%zd %s\n", + buffer->debug_id, + buffer->user_data - alloc->buffer, + buffer->data_size, buffer->offsets_size, + buffer->extra_buffers_size, + buffer->transaction ? "active" : "delivered"); + } + spin_unlock(&alloc->lock); } /** @@ -913,7 +993,7 @@ void binder_alloc_print_pages(struct seq_file *m, int lru = 0; int free = 0; - mutex_lock(&alloc->mutex); + spin_lock(&alloc->lock); /* * Make sure the binder_alloc is fully initialized, otherwise we might * read inconsistent state. @@ -929,7 +1009,7 @@ void binder_alloc_print_pages(struct seq_file *m, lru++; } } - mutex_unlock(&alloc->mutex); + spin_unlock(&alloc->lock); seq_printf(m, " pages: %d:%d:%d\n", active, lru, free); seq_printf(m, " pages high watermark: %zu\n", alloc->pages_high); } @@ -945,10 +1025,10 @@ int binder_alloc_get_allocated_count(struct binder_alloc *alloc) struct rb_node *n; int count = 0; - mutex_lock(&alloc->mutex); + spin_lock(&alloc->lock); for (n = rb_first(&alloc->allocated_buffers); n != NULL; n = rb_next(n)) count++; - mutex_unlock(&alloc->mutex); + spin_unlock(&alloc->lock); return count; } @@ -981,33 +1061,39 @@ enum lru_status binder_alloc_free_page(struct list_head *item, void *cb_arg) __must_hold(lock) { - struct mm_struct *mm = NULL; - struct binder_lru_page *page = container_of(item, - struct binder_lru_page, - lru); - struct binder_alloc *alloc; - uintptr_t page_addr; - size_t index; + struct binder_lru_page *page = container_of(item, typeof(*page), lru); + struct binder_alloc *alloc = page->alloc; + struct mm_struct *mm = alloc->mm; struct vm_area_struct *vma; + struct page *page_to_free; + unsigned long page_addr; + size_t index; - alloc = page->alloc; - if (!mutex_trylock(&alloc->mutex)) - goto err_get_alloc_mutex_failed; - + if (!mmget_not_zero(mm)) + goto err_mmget; + if (!mmap_read_trylock(mm)) + goto err_mmap_read_lock_failed; + if (!spin_trylock(&alloc->lock)) + goto err_get_alloc_lock_failed; if (!page->page_ptr) goto err_page_already_freed; index = page - alloc->pages; - page_addr = (uintptr_t)alloc->buffer + index * PAGE_SIZE; + page_addr = alloc->buffer + index * PAGE_SIZE; - mm = alloc->mm; - if (!mmget_not_zero(mm)) - goto err_mmget; - if (!mmap_read_trylock(mm)) - goto err_mmap_read_lock_failed; - vma = binder_alloc_get_vma(alloc); + vma = vma_lookup(mm, page_addr); + if (vma && vma != binder_alloc_get_vma(alloc)) + goto err_invalid_vma; + + trace_binder_unmap_kernel_start(alloc, index); + + page_to_free = page->page_ptr; + page->page_ptr = NULL; + + trace_binder_unmap_kernel_end(alloc, index); list_lru_isolate(lru, item); + spin_unlock(&alloc->lock); spin_unlock(lock); if (vma) { @@ -1017,39 +1103,35 @@ enum lru_status binder_alloc_free_page(struct list_head *item, trace_binder_unmap_user_end(alloc, index); } + mmap_read_unlock(mm); mmput_async(mm); - - trace_binder_unmap_kernel_start(alloc, index); - - __free_page(page->page_ptr); - page->page_ptr = NULL; - - trace_binder_unmap_kernel_end(alloc, index); + __free_page(page_to_free); spin_lock(lock); - mutex_unlock(&alloc->mutex); return LRU_REMOVED_RETRY; +err_invalid_vma: +err_page_already_freed: + spin_unlock(&alloc->lock); +err_get_alloc_lock_failed: + mmap_read_unlock(mm); err_mmap_read_lock_failed: mmput_async(mm); err_mmget: -err_page_already_freed: - mutex_unlock(&alloc->mutex); -err_get_alloc_mutex_failed: return LRU_SKIP; } static unsigned long binder_shrink_count(struct shrinker *shrink, struct shrink_control *sc) { - return list_lru_count(&binder_alloc_lru); + return list_lru_count(&binder_freelist); } static unsigned long binder_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) { - return list_lru_walk(&binder_alloc_lru, binder_alloc_free_page, + return list_lru_walk(&binder_freelist, binder_alloc_free_page, NULL, sc->nr_to_scan); } @@ -1067,7 +1149,7 @@ void binder_alloc_init(struct binder_alloc *alloc) alloc->pid = current->group_leader->pid; alloc->mm = current->mm; mmgrab(alloc->mm); - mutex_init(&alloc->mutex); + spin_lock_init(&alloc->lock); INIT_LIST_HEAD(&alloc->buffers); } @@ -1075,13 +1157,13 @@ int binder_alloc_shrinker_init(void) { int ret; - ret = list_lru_init(&binder_alloc_lru); + ret = list_lru_init(&binder_freelist); if (ret) return ret; binder_shrinker = shrinker_alloc(0, "android-binder"); if (!binder_shrinker) { - list_lru_destroy(&binder_alloc_lru); + list_lru_destroy(&binder_freelist); return -ENOMEM; } @@ -1096,7 +1178,7 @@ int binder_alloc_shrinker_init(void) void binder_alloc_shrinker_exit(void) { shrinker_free(binder_shrinker); - list_lru_destroy(&binder_alloc_lru); + list_lru_destroy(&binder_freelist); } /** @@ -1131,68 +1213,6 @@ static inline bool check_buffer(struct binder_alloc *alloc, (!buffer->allow_user_free || !buffer->transaction); } -/** - * binder_alloc_get_page() - get kernel pointer for given buffer offset - * @alloc: binder_alloc for this proc - * @buffer: binder buffer to be accessed - * @buffer_offset: offset into @buffer data - * @pgoffp: address to copy final page offset to - * - * Lookup the struct page corresponding to the address - * at @buffer_offset into @buffer->user_data. If @pgoffp is not - * NULL, the byte-offset into the page is written there. - * - * The caller is responsible to ensure that the offset points - * to a valid address within the @buffer and that @buffer is - * not freeable by the user. Since it can't be freed, we are - * guaranteed that the corresponding elements of @alloc->pages[] - * cannot change. - * - * Return: struct page - */ -static struct page *binder_alloc_get_page(struct binder_alloc *alloc, - struct binder_buffer *buffer, - binder_size_t buffer_offset, - pgoff_t *pgoffp) -{ - binder_size_t buffer_space_offset = buffer_offset + - (buffer->user_data - alloc->buffer); - pgoff_t pgoff = buffer_space_offset & ~PAGE_MASK; - size_t index = buffer_space_offset >> PAGE_SHIFT; - struct binder_lru_page *lru_page; - - lru_page = &alloc->pages[index]; - *pgoffp = pgoff; - return lru_page->page_ptr; -} - -/** - * binder_alloc_clear_buf() - zero out buffer - * @alloc: binder_alloc for this proc - * @buffer: binder buffer to be cleared - * - * memset the given buffer to 0 - */ -static void binder_alloc_clear_buf(struct binder_alloc *alloc, - struct binder_buffer *buffer) -{ - size_t bytes = binder_alloc_buffer_size(alloc, buffer); - binder_size_t buffer_offset = 0; - - while (bytes) { - unsigned long size; - struct page *page; - pgoff_t pgoff; - - page = binder_alloc_get_page(alloc, buffer, - buffer_offset, &pgoff); - size = min_t(size_t, bytes, PAGE_SIZE - pgoff); - memset_page(page, pgoff, 0, size); - bytes -= size; - buffer_offset += size; - } -} - /** * binder_alloc_copy_user_to_buffer() - copy src user to tgt user * @alloc: binder_alloc for this proc @@ -1287,4 +1307,3 @@ int binder_alloc_copy_from_buffer(struct binder_alloc *alloc, return binder_alloc_do_buffer_copy(alloc, false, buffer, buffer_offset, dest, bytes); } - diff --git a/drivers/android/binder_alloc.h b/drivers/android/binder_alloc.h index dc1e2b01dd64db..70387234477e0c 100644 --- a/drivers/android/binder_alloc.h +++ b/drivers/android/binder_alloc.h @@ -9,13 +9,13 @@ #include #include #include -#include +#include #include #include #include #include -extern struct list_lru binder_alloc_lru; +extern struct list_lru binder_freelist; struct binder_transaction; /** @@ -49,21 +49,19 @@ struct binder_buffer { unsigned async_transaction:1; unsigned oneway_spam_suspect:1; unsigned debug_id:27; - struct binder_transaction *transaction; - struct binder_node *target_node; size_t data_size; size_t offsets_size; size_t extra_buffers_size; - void __user *user_data; - int pid; + unsigned long user_data; + int pid; }; /** * struct binder_lru_page - page object used for binder shrinker * @page_ptr: pointer to physical page in mmap'd space - * @lru: entry in binder_alloc_lru + * @lru: entry in binder_freelist * @alloc: binder_alloc for a proc */ struct binder_lru_page { @@ -74,7 +72,7 @@ struct binder_lru_page { /** * struct binder_alloc - per-binder proc state for binder allocator - * @mutex: protects binder_alloc fields + * @lock: protects binder_alloc fields * @vma: vm_area_struct passed to mmap_handler * (invariant after mmap) * @mm: copy of task->mm (invariant after open) @@ -98,10 +96,10 @@ struct binder_lru_page { * struct binder_buffer objects used to track the user buffers */ struct binder_alloc { - struct mutex mutex; + spinlock_t lock; struct vm_area_struct *vma; struct mm_struct *mm; - void __user *buffer; + unsigned long buffer; struct list_head buffers; struct rb_root free_buffers; struct rb_root allocated_buffers; @@ -121,27 +119,26 @@ static inline void binder_selftest_alloc(struct binder_alloc *alloc) {} enum lru_status binder_alloc_free_page(struct list_head *item, struct list_lru_one *lru, spinlock_t *lock, void *cb_arg); -extern struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc, - size_t data_size, - size_t offsets_size, - size_t extra_buffers_size, - int is_async, - int pid); -extern void binder_alloc_init(struct binder_alloc *alloc); -extern int binder_alloc_shrinker_init(void); -extern void binder_alloc_shrinker_exit(void); -extern void binder_alloc_vma_close(struct binder_alloc *alloc); -extern struct binder_buffer * +struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc, + size_t data_size, + size_t offsets_size, + size_t extra_buffers_size, + int is_async); +void binder_alloc_init(struct binder_alloc *alloc); +int binder_alloc_shrinker_init(void); +void binder_alloc_shrinker_exit(void); +void binder_alloc_vma_close(struct binder_alloc *alloc); +struct binder_buffer * binder_alloc_prepare_to_free(struct binder_alloc *alloc, - uintptr_t user_ptr); -extern void binder_alloc_free_buf(struct binder_alloc *alloc, - struct binder_buffer *buffer); -extern int binder_alloc_mmap_handler(struct binder_alloc *alloc, - struct vm_area_struct *vma); -extern void binder_alloc_deferred_release(struct binder_alloc *alloc); -extern int binder_alloc_get_allocated_count(struct binder_alloc *alloc); -extern void binder_alloc_print_allocated(struct seq_file *m, - struct binder_alloc *alloc); + unsigned long user_ptr); +void binder_alloc_free_buf(struct binder_alloc *alloc, + struct binder_buffer *buffer); +int binder_alloc_mmap_handler(struct binder_alloc *alloc, + struct vm_area_struct *vma); +void binder_alloc_deferred_release(struct binder_alloc *alloc); +int binder_alloc_get_allocated_count(struct binder_alloc *alloc); +void binder_alloc_print_allocated(struct seq_file *m, + struct binder_alloc *alloc); void binder_alloc_print_pages(struct seq_file *m, struct binder_alloc *alloc); @@ -156,9 +153,9 @@ binder_alloc_get_free_async_space(struct binder_alloc *alloc) { size_t free_async_space; - mutex_lock(&alloc->mutex); + spin_lock(&alloc->lock); free_async_space = alloc->free_async_space; - mutex_unlock(&alloc->mutex); + spin_unlock(&alloc->lock); return free_async_space; } diff --git a/drivers/android/binder_alloc_selftest.c b/drivers/android/binder_alloc_selftest.c index c2b323bc3b3a53..81442fe20a695f 100644 --- a/drivers/android/binder_alloc_selftest.c +++ b/drivers/android/binder_alloc_selftest.c @@ -72,6 +72,10 @@ enum buf_end_align_type { * buf1 ]|[ buf2 | buf2 | buf2 ][ ... */ NEXT_NEXT_UNALIGNED, + /** + * @LOOP_END: The number of enum values in &buf_end_align_type. + * It is used for controlling loop termination. + */ LOOP_END, }; @@ -93,11 +97,11 @@ static bool check_buffer_pages_allocated(struct binder_alloc *alloc, struct binder_buffer *buffer, size_t size) { - void __user *page_addr; - void __user *end; + unsigned long page_addr; + unsigned long end; int page_index; - end = (void __user *)PAGE_ALIGN((uintptr_t)buffer->user_data + size); + end = PAGE_ALIGN(buffer->user_data + size); page_addr = buffer->user_data; for (; page_addr < end; page_addr += PAGE_SIZE) { page_index = (page_addr - alloc->buffer) / PAGE_SIZE; @@ -119,7 +123,7 @@ static void binder_selftest_alloc_buf(struct binder_alloc *alloc, int i; for (i = 0; i < BUFFER_NUM; i++) { - buffers[i] = binder_alloc_new_buf(alloc, sizes[i], 0, 0, 0, 0); + buffers[i] = binder_alloc_new_buf(alloc, sizes[i], 0, 0, 0); if (IS_ERR(buffers[i]) || !check_buffer_pages_allocated(alloc, buffers[i], sizes[i])) { @@ -158,8 +162,8 @@ static void binder_selftest_free_page(struct binder_alloc *alloc) int i; unsigned long count; - while ((count = list_lru_count(&binder_alloc_lru))) { - list_lru_walk(&binder_alloc_lru, binder_alloc_free_page, + while ((count = list_lru_count(&binder_freelist))) { + list_lru_walk(&binder_freelist, binder_alloc_free_page, NULL, count); } @@ -183,7 +187,7 @@ static void binder_selftest_alloc_free(struct binder_alloc *alloc, /* Allocate from lru. */ binder_selftest_alloc_buf(alloc, buffers, sizes, seq); - if (list_lru_count(&binder_alloc_lru)) + if (list_lru_count(&binder_freelist)) pr_err("lru list should be empty but is not\n"); binder_selftest_free_buf(alloc, buffers, sizes, seq, end); diff --git a/drivers/android/binder_trace.h b/drivers/android/binder_trace.h index 8cc07e6a4273e7..fe38c6fc65d0f8 100644 --- a/drivers/android/binder_trace.h +++ b/drivers/android/binder_trace.h @@ -317,7 +317,7 @@ DEFINE_EVENT(binder_buffer_class, binder_transaction_update_buffer_release, TRACE_EVENT(binder_update_page_range, TP_PROTO(struct binder_alloc *alloc, bool allocate, - void __user *start, void __user *end), + unsigned long start, unsigned long end), TP_ARGS(alloc, allocate, start, end), TP_STRUCT__entry( __field(int, proc) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index 1224ab7aa0708b..3001d754ac369e 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 3a5f3255f51b39..d2460fa985b7e3 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -48,6 +48,7 @@ enum { enum board_ids { /* board IDs by feature in alphabetical order */ board_ahci, + board_ahci_43bit_dma, board_ahci_ign_iferr, board_ahci_low_power, board_ahci_no_debounce_delay, @@ -128,6 +129,13 @@ static const struct ata_port_info ahci_port_info[] = { .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, }, + [board_ahci_43bit_dma] = { + AHCI_HFLAGS (AHCI_HFLAG_43BIT_ONLY), + .flags = AHCI_FLAG_COMMON, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_ops, + }, [board_ahci_ign_iferr] = { AHCI_HFLAGS (AHCI_HFLAG_IGN_IRQ_IF_ERR), .flags = AHCI_FLAG_COMMON, @@ -597,11 +605,11 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(PROMISE, 0x3f20), board_ahci }, /* PDC42819 */ { PCI_VDEVICE(PROMISE, 0x3781), board_ahci }, /* FastTrak TX8660 ahci-mode */ - /* Asmedia */ + /* ASMedia */ { PCI_VDEVICE(ASMEDIA, 0x0601), board_ahci }, /* ASM1060 */ { PCI_VDEVICE(ASMEDIA, 0x0602), board_ahci }, /* ASM1060 */ - { PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci }, /* ASM1061 */ - { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci }, /* ASM1062 */ + { PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci_43bit_dma }, /* ASM1061 */ + { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci_43bit_dma }, /* ASM1061/1062 */ { PCI_VDEVICE(ASMEDIA, 0x0621), board_ahci }, /* ASM1061R */ { PCI_VDEVICE(ASMEDIA, 0x0622), board_ahci }, /* ASM1062R */ { PCI_VDEVICE(ASMEDIA, 0x0624), board_ahci }, /* ASM1062+JMB575 */ @@ -663,6 +671,11 @@ MODULE_PARM_DESC(mobile_lpm_policy, "Default LPM policy for mobile chipsets"); static void ahci_pci_save_initial_config(struct pci_dev *pdev, struct ahci_host_priv *hpriv) { + if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA && pdev->device == 0x1166) { + dev_info(&pdev->dev, "ASM1166 has only six ports\n"); + hpriv->saved_port_map = 0x3f; + } + if (pdev->vendor == PCI_VENDOR_ID_JMICRON && pdev->device == 0x2361) { dev_info(&pdev->dev, "JMB361 has only one port\n"); hpriv->saved_port_map = 1; @@ -949,11 +962,20 @@ static int ahci_pci_device_resume(struct device *dev) #endif /* CONFIG_PM */ -static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac) +static int ahci_configure_dma_masks(struct pci_dev *pdev, + struct ahci_host_priv *hpriv) { - const int dma_bits = using_dac ? 64 : 32; + int dma_bits; int rc; + if (hpriv->cap & HOST_CAP_64) { + dma_bits = 64; + if (hpriv->flags & AHCI_HFLAG_43BIT_ONLY) + dma_bits = 43; + } else { + dma_bits = 32; + } + /* * If the device fixup already set the dma_mask to some non-standard * value, don't extend it here. This happens on STA2X11, for example. @@ -1926,7 +1948,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ahci_gtf_filter_workaround(host); /* initialize adapter */ - rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64); + rc = ahci_configure_dma_masks(pdev, hpriv); if (rc) return rc; diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 4bae95b06ae3c9..df8f8a1a3a34c3 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -247,6 +247,7 @@ enum { AHCI_HFLAG_SUSPEND_PHYS = BIT(26), /* handle PHYs during suspend/resume */ AHCI_HFLAG_NO_SXS = BIT(28), /* SXS not supported */ + AHCI_HFLAG_43BIT_ONLY = BIT(29), /* 43bit DMA addr limit */ /* ap->flags bits */ diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c index b6656c287175c7..0fb1934875f208 100644 --- a/drivers/ata/libata-sata.c +++ b/drivers/ata/libata-sata.c @@ -784,7 +784,7 @@ bool sata_lpm_ignore_phy_events(struct ata_link *link) EXPORT_SYMBOL_GPL(sata_lpm_ignore_phy_events); static const char *ata_lpm_policy_names[] = { - [ATA_LPM_UNKNOWN] = "max_performance", + [ATA_LPM_UNKNOWN] = "keep_firmware_settings", [ATA_LPM_MAX_POWER] = "max_performance", [ATA_LPM_MED_POWER] = "medium_power", [ATA_LPM_MED_POWER_WITH_DIPM] = "med_power_with_dipm", diff --git a/drivers/ata/pata_pxa.c b/drivers/ata/pata_pxa.c index 5275c6464f57fc..538bd3423d859d 100644 --- a/drivers/ata/pata_pxa.c +++ b/drivers/ata/pata_pxa.c @@ -274,10 +274,9 @@ static int pxa_ata_probe(struct platform_device *pdev) /* * Request the DMA channel */ - data->dma_chan = - dma_request_slave_channel(&pdev->dev, "data"); - if (!data->dma_chan) - return -EBUSY; + data->dma_chan = dma_request_chan(&pdev->dev, "data"); + if (IS_ERR(data->dma_chan)) + return PTR_ERR(data->dma_chan); ret = dmaengine_slave_config(data->dma_chan, &config); if (ret < 0) { dev_err(&pdev->dev, "dma configuration failed: %d\n", ret); diff --git a/drivers/atm/atmtcp.c b/drivers/atm/atmtcp.c index 96bea1ab1eccf4..d4aa0f353b6c80 100644 --- a/drivers/atm/atmtcp.c +++ b/drivers/atm/atmtcp.c @@ -494,6 +494,7 @@ static void __exit atmtcp_exit(void) deregister_atm_ioctl(&atmtcp_ioctl_ops); } +MODULE_DESCRIPTION("ATM over TCP"); MODULE_LICENSE("GPL"); module_init(atmtcp_init); module_exit(atmtcp_exit); diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index a31ffe16e626f7..3011cf1a84a9dd 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c @@ -2318,4 +2318,5 @@ static int __init eni_init(void) module_init(eni_init); /* @@@ since exit routine not defined, this module can not be unloaded */ +MODULE_DESCRIPTION("Efficient Networks ENI155P ATM NIC driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/atm/idt77105.c b/drivers/atm/idt77105.c index bfca7b8a6f31e8..fcd70e094a2e97 100644 --- a/drivers/atm/idt77105.c +++ b/drivers/atm/idt77105.c @@ -372,4 +372,5 @@ static void __exit idt77105_exit(void) module_exit(idt77105_exit); +MODULE_DESCRIPTION("IDT77105 PHY driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c index 9bba8f280a4d4c..d213adcefe3386 100644 --- a/drivers/atm/iphase.c +++ b/drivers/atm/iphase.c @@ -90,6 +90,7 @@ module_param(IA_RX_BUF, int, 0); module_param(IA_RX_BUF_SZ, int, 0); module_param(IADebugFlag, uint, 0644); +MODULE_DESCRIPTION("Driver for Interphase ATM PCI NICs"); MODULE_LICENSE("GPL"); /**************************** IA_LIB **********************************/ diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c index 1a50de39f5b5a8..27153d6bc7815f 100644 --- a/drivers/atm/nicstar.c +++ b/drivers/atm/nicstar.c @@ -171,6 +171,7 @@ static const struct atmdev_ops atm_ops = { static struct timer_list ns_timer; static char *mac[NS_MAX_CARDS]; module_param_array(mac, charp, NULL, 0); +MODULE_DESCRIPTION("ATM NIC driver for IDT 77201/77211 \"NICStAR\" and Fore ForeRunnerLE."); MODULE_LICENSE("GPL"); /* Functions */ diff --git a/drivers/atm/suni.c b/drivers/atm/suni.c index 21e5acc766b8b8..32802ea9521cd4 100644 --- a/drivers/atm/suni.c +++ b/drivers/atm/suni.c @@ -387,4 +387,5 @@ int suni_init(struct atm_dev *dev) EXPORT_SYMBOL(suni_init); +MODULE_DESCRIPTION("S/UNI PHY driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig index 64012cda4d1267..d944d5298eca82 100644 --- a/drivers/auxdisplay/Kconfig +++ b/drivers/auxdisplay/Kconfig @@ -112,10 +112,7 @@ config CFAG12864B depends on X86 depends on FB depends on KS0108 - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS + select FB_SYSMEM_HELPERS default n help If you have a Crystalfontz 128x64 2-color LCD, cfag12864b Series, @@ -170,10 +167,7 @@ config IMG_ASCII_LCD config HT16K33 tristate "Holtek Ht16K33 LED controller with keyscan" depends on FB && I2C && INPUT - select FB_SYS_FOPS - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT + select FB_SYSMEM_HELPERS select INPUT_MATRIXKMAP select FB_BACKLIGHT select NEW_LEDS diff --git a/drivers/auxdisplay/cfag12864bfb.c b/drivers/auxdisplay/cfag12864bfb.c index 729845bcc803af..5ba19c339f088f 100644 --- a/drivers/auxdisplay/cfag12864bfb.c +++ b/drivers/auxdisplay/cfag12864bfb.c @@ -51,16 +51,15 @@ static int cfag12864bfb_mmap(struct fb_info *info, struct vm_area_struct *vma) { struct page *pages = virt_to_page(cfag12864b_buffer); + vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); + return vm_map_pages_zero(vma, &pages, 1); } static const struct fb_ops cfag12864bfb_ops = { .owner = THIS_MODULE, - .fb_read = fb_sys_read, - .fb_write = fb_sys_write, - .fb_fillrect = sys_fillrect, - .fb_copyarea = sys_copyarea, - .fb_imageblit = sys_imageblit, + __FB_DEFAULT_SYSMEM_OPS_RDWR, + __FB_DEFAULT_SYSMEM_OPS_DRAW, .fb_mmap = cfag12864bfb_mmap, }; @@ -72,6 +71,7 @@ static int cfag12864bfb_probe(struct platform_device *device) if (!info) goto none; + info->flags = FBINFO_VIRTFB; info->screen_buffer = cfag12864b_buffer; info->screen_size = CFAG12864B_SIZE; info->fbops = &cfag12864bfb_ops; diff --git a/drivers/auxdisplay/ht16k33.c b/drivers/auxdisplay/ht16k33.c index 3a2d883872249e..a90430b7d07ba4 100644 --- a/drivers/auxdisplay/ht16k33.c +++ b/drivers/auxdisplay/ht16k33.c @@ -351,17 +351,16 @@ static int ht16k33_mmap(struct fb_info *info, struct vm_area_struct *vma) struct ht16k33_priv *priv = info->par; struct page *pages = virt_to_page(priv->fbdev.buffer); + vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); + return vm_map_pages_zero(vma, &pages, 1); } static const struct fb_ops ht16k33_fb_ops = { .owner = THIS_MODULE, - .fb_read = fb_sys_read, - .fb_write = fb_sys_write, + __FB_DEFAULT_SYSMEM_OPS_RDWR, .fb_blank = ht16k33_blank, - .fb_fillrect = sys_fillrect, - .fb_copyarea = sys_copyarea, - .fb_imageblit = sys_imageblit, + __FB_DEFAULT_SYSMEM_OPS_DRAW, .fb_mmap = ht16k33_mmap, }; @@ -640,6 +639,7 @@ static int ht16k33_fbdev_probe(struct device *dev, struct ht16k33_priv *priv, INIT_DELAYED_WORK(&priv->work, ht16k33_fb_update); fbdev->info->fbops = &ht16k33_fb_ops; + fbdev->info->flags |= FBINFO_VIRTFB; fbdev->info->screen_buffer = fbdev->buffer; fbdev->info->screen_size = HT16K33_FB_SIZE; fbdev->info->fix = ht16k33_fb_fix; diff --git a/drivers/auxdisplay/img-ascii-lcd.c b/drivers/auxdisplay/img-ascii-lcd.c index fa23e415f260ec..56efda0740fbc1 100644 --- a/drivers/auxdisplay/img-ascii-lcd.c +++ b/drivers/auxdisplay/img-ascii-lcd.c @@ -8,9 +8,9 @@ #include #include #include -#include -#include +#include #include +#include #include #include @@ -225,17 +225,11 @@ MODULE_DEVICE_TABLE(of, img_ascii_lcd_matches); */ static int img_ascii_lcd_probe(struct platform_device *pdev) { - const struct of_device_id *match; - const struct img_ascii_lcd_config *cfg; struct device *dev = &pdev->dev; + const struct img_ascii_lcd_config *cfg = device_get_match_data(dev); struct img_ascii_lcd_ctx *ctx; int err; - match = of_match_device(img_ascii_lcd_matches, dev); - if (!match) - return -ENODEV; - - cfg = match->data; ctx = devm_kzalloc(dev, sizeof(*ctx) + cfg->num_chars, GFP_KERNEL); if (!ctx) return -ENOMEM; diff --git a/drivers/base/arch_numa.c b/drivers/base/arch_numa.c index eaa31e567d1ece..5b59d133b6af4f 100644 --- a/drivers/base/arch_numa.c +++ b/drivers/base/arch_numa.c @@ -144,7 +144,7 @@ void __init early_map_cpu_to_node(unsigned int cpu, int nid) unsigned long __per_cpu_offset[NR_CPUS] __read_mostly; EXPORT_SYMBOL(__per_cpu_offset); -static int __init early_cpu_to_node(int cpu) +int __init early_cpu_to_node(int cpu) { return cpu_to_node_map[cpu]; } diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index b741b5ba82bd6e..018ac202de345e 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -19,6 +19,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include @@ -26,7 +27,8 @@ static DEFINE_PER_CPU(struct scale_freq_data __rcu *, sft_data); static struct cpumask scale_freq_counters_mask; static bool scale_freq_invariant; -static DEFINE_PER_CPU(u32, freq_factor) = 1; +DEFINE_PER_CPU(unsigned long, capacity_freq_ref) = 1; +EXPORT_PER_CPU_SYMBOL_GPL(capacity_freq_ref); static bool supports_scale_freq_counters(const struct cpumask *cpus) { @@ -170,9 +172,9 @@ DEFINE_PER_CPU(unsigned long, thermal_pressure); * operating on stale data when hot-plug is used for some CPUs. The * @capped_freq reflects the currently allowed max CPUs frequency due to * thermal capping. It might be also a boost frequency value, which is bigger - * than the internal 'freq_factor' max frequency. In such case the pressure - * value should simply be removed, since this is an indication that there is - * no thermal throttling. The @capped_freq must be provided in kHz. + * than the internal 'capacity_freq_ref' max frequency. In such case the + * pressure value should simply be removed, since this is an indication that + * there is no thermal throttling. The @capped_freq must be provided in kHz. */ void topology_update_thermal_pressure(const struct cpumask *cpus, unsigned long capped_freq) @@ -183,10 +185,7 @@ void topology_update_thermal_pressure(const struct cpumask *cpus, cpu = cpumask_first(cpus); max_capacity = arch_scale_cpu_capacity(cpu); - max_freq = per_cpu(freq_factor, cpu); - - /* Convert to MHz scale which is used in 'freq_factor' */ - capped_freq /= 1000; + max_freq = arch_scale_freq_ref(cpu); /* * Handle properly the boost frequencies, which should simply clean @@ -220,20 +219,34 @@ static DECLARE_WORK(update_topology_flags_work, update_topology_flags_workfn); static DEVICE_ATTR_RO(cpu_capacity); -static int register_cpu_capacity_sysctl(void) +static int cpu_capacity_sysctl_add(unsigned int cpu) { - int i; - struct device *cpu; + struct device *cpu_dev = get_cpu_device(cpu); - for_each_possible_cpu(i) { - cpu = get_cpu_device(i); - if (!cpu) { - pr_err("%s: too early to get CPU%d device!\n", - __func__, i); - continue; - } - device_create_file(cpu, &dev_attr_cpu_capacity); - } + if (!cpu_dev) + return -ENOENT; + + device_create_file(cpu_dev, &dev_attr_cpu_capacity); + + return 0; +} + +static int cpu_capacity_sysctl_remove(unsigned int cpu) +{ + struct device *cpu_dev = get_cpu_device(cpu); + + if (!cpu_dev) + return -ENOENT; + + device_remove_file(cpu_dev, &dev_attr_cpu_capacity); + + return 0; +} + +static int register_cpu_capacity_sysctl(void) +{ + cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "topology/cpu-capacity", + cpu_capacity_sysctl_add, cpu_capacity_sysctl_remove); return 0; } @@ -279,13 +292,13 @@ void topology_normalize_cpu_scale(void) capacity_scale = 1; for_each_possible_cpu(cpu) { - capacity = raw_capacity[cpu] * per_cpu(freq_factor, cpu); + capacity = raw_capacity[cpu] * per_cpu(capacity_freq_ref, cpu); capacity_scale = max(capacity, capacity_scale); } pr_debug("cpu_capacity: capacity_scale=%llu\n", capacity_scale); for_each_possible_cpu(cpu) { - capacity = raw_capacity[cpu] * per_cpu(freq_factor, cpu); + capacity = raw_capacity[cpu] * per_cpu(capacity_freq_ref, cpu); capacity = div64_u64(capacity << SCHED_CAPACITY_SHIFT, capacity_scale); topology_set_cpu_scale(cpu, capacity); @@ -321,15 +334,15 @@ bool __init topology_parse_cpu_capacity(struct device_node *cpu_node, int cpu) cpu_node, raw_capacity[cpu]); /* - * Update freq_factor for calculating early boot cpu capacities. + * Update capacity_freq_ref for calculating early boot CPU capacities. * For non-clk CPU DVFS mechanism, there's no way to get the * frequency value now, assuming they are running at the same - * frequency (by keeping the initial freq_factor value). + * frequency (by keeping the initial capacity_freq_ref value). */ cpu_clk = of_clk_get(cpu_node, 0); if (!PTR_ERR_OR_ZERO(cpu_clk)) { - per_cpu(freq_factor, cpu) = - clk_get_rate(cpu_clk) / 1000; + per_cpu(capacity_freq_ref, cpu) = + clk_get_rate(cpu_clk) / HZ_PER_KHZ; clk_put(cpu_clk); } } else { @@ -345,11 +358,16 @@ bool __init topology_parse_cpu_capacity(struct device_node *cpu_node, int cpu) return !ret; } +void __weak freq_inv_set_max_ratio(int cpu, u64 max_rate) +{ +} + #ifdef CONFIG_ACPI_CPPC_LIB #include void topology_init_cpu_capacity_cppc(void) { + u64 capacity, capacity_scale = 0; struct cppc_perf_caps perf_caps; int cpu; @@ -366,6 +384,10 @@ void topology_init_cpu_capacity_cppc(void) (perf_caps.highest_perf >= perf_caps.nominal_perf) && (perf_caps.highest_perf >= perf_caps.lowest_perf)) { raw_capacity[cpu] = perf_caps.highest_perf; + capacity_scale = max_t(u64, capacity_scale, raw_capacity[cpu]); + + per_cpu(capacity_freq_ref, cpu) = cppc_perf_to_khz(&perf_caps, raw_capacity[cpu]); + pr_debug("cpu_capacity: CPU%d cpu_capacity=%u (raw).\n", cpu, raw_capacity[cpu]); continue; @@ -376,7 +398,18 @@ void topology_init_cpu_capacity_cppc(void) goto exit; } - topology_normalize_cpu_scale(); + for_each_possible_cpu(cpu) { + freq_inv_set_max_ratio(cpu, + per_cpu(capacity_freq_ref, cpu) * HZ_PER_KHZ); + + capacity = raw_capacity[cpu]; + capacity = div64_u64(capacity << SCHED_CAPACITY_SHIFT, + capacity_scale); + topology_set_cpu_scale(cpu, capacity); + pr_debug("cpu_capacity: CPU%d cpu_capacity=%lu\n", + cpu, topology_get_cpu_scale(cpu)); + } + schedule_work(&update_topology_flags_work); pr_debug("cpu_capacity: cpu_capacity initialization done\n"); @@ -410,8 +443,11 @@ init_cpu_capacity_callback(struct notifier_block *nb, cpumask_andnot(cpus_to_visit, cpus_to_visit, policy->related_cpus); - for_each_cpu(cpu, policy->related_cpus) - per_cpu(freq_factor, cpu) = policy->cpuinfo.max_freq / 1000; + for_each_cpu(cpu, policy->related_cpus) { + per_cpu(capacity_freq_ref, cpu) = policy->cpuinfo.max_freq; + freq_inv_set_max_ratio(cpu, + per_cpu(capacity_freq_ref, cpu) * HZ_PER_KHZ); + } if (cpumask_empty(cpus_to_visit)) { topology_normalize_cpu_scale(); diff --git a/drivers/base/auxiliary.c b/drivers/base/auxiliary.c index 4d4c2c8d26c480..d3a2c40c2f1272 100644 --- a/drivers/base/auxiliary.c +++ b/drivers/base/auxiliary.c @@ -244,7 +244,7 @@ static void auxiliary_bus_shutdown(struct device *dev) auxdrv->shutdown(auxdev); } -static struct bus_type auxiliary_bus_type = { +static const struct bus_type auxiliary_bus_type = { .name = "auxiliary", .probe = auxiliary_bus_probe, .remove = auxiliary_bus_remove, diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 84a21084d67d16..daee55c9b2d9e1 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -1030,7 +1030,7 @@ static void device_insertion_sort_klist(struct device *a, struct list_head *list list_move_tail(&a->p->knode_bus.n_node, list); } -void bus_sort_breadthfirst(struct bus_type *bus, +void bus_sort_breadthfirst(const struct bus_type *bus, int (*compare)(const struct device *a, const struct device *b)) { @@ -1194,7 +1194,7 @@ static void system_root_device_release(struct device *dev) kfree(dev); } -static int subsys_register(struct bus_type *subsys, +static int subsys_register(const struct bus_type *subsys, const struct attribute_group **groups, struct kobject *parent_of_root) { @@ -1264,7 +1264,7 @@ err_sp: * directory itself and not some create fake root-device placed in * /sys/devices/system/. */ -int subsys_system_register(struct bus_type *subsys, +int subsys_system_register(const struct bus_type *subsys, const struct attribute_group **groups) { return subsys_register(subsys, groups, &system_kset->kobj); @@ -1282,7 +1282,7 @@ EXPORT_SYMBOL_GPL(subsys_system_register); * There's no restriction on device naming. This is for kernel software * constructs which need sysfs interface. */ -int subsys_virtual_register(struct bus_type *subsys, +int subsys_virtual_register(const struct bus_type *subsys, const struct attribute_group **groups) { struct kobject *virtual_dir; diff --git a/drivers/base/class.c b/drivers/base/class.c index 7e78aee0fd6c39..7b38fdf8e1d78e 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -213,6 +213,7 @@ int class_register(const struct class *cls) return 0; err_out: + lockdep_unregister_key(key); kfree(cp); return error; } diff --git a/drivers/base/container.c b/drivers/base/container.c index 1ba42d2d353223..f40588ebc3f557 100644 --- a/drivers/base/container.c +++ b/drivers/base/container.c @@ -24,7 +24,7 @@ static int container_offline(struct device *dev) return cdev->offline ? cdev->offline(cdev) : 0; } -struct bus_type container_subsys = { +const struct bus_type container_subsys = { .name = CONTAINER_BUS_NAME, .dev_name = CONTAINER_BUS_NAME, .online = trivial_online, diff --git a/drivers/base/core.c b/drivers/base/core.c index 67ba592afc7776..14d46af40f9a15 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -298,7 +298,7 @@ static inline bool device_link_flag_is_sync_state_only(u32 flags) * Check if @target depends on @dev or any device dependent on it (its child or * its consumer etc). Return 1 if that is the case or 0 otherwise. */ -int device_is_dependent(struct device *dev, void *target) +static int device_is_dependent(struct device *dev, void *target) { struct device_link *link; int ret; @@ -1641,7 +1641,7 @@ static void device_links_purge(struct device *dev) #define FW_DEVLINK_FLAGS_RPM (FW_DEVLINK_FLAGS_ON | \ DL_FLAG_PM_RUNTIME) -static u32 fw_devlink_flags = FW_DEVLINK_FLAGS_ON; +static u32 fw_devlink_flags = FW_DEVLINK_FLAGS_RPM; static int __init fw_devlink_setup(char *arg) { if (!arg) @@ -4944,13 +4944,14 @@ define_dev_printk_level(_dev_info, KERN_INFO); * * return dev_err_probe(dev, err, ...); * - * Note that it is deemed acceptable to use this function for error - * prints during probe even if the @err is known to never be -EPROBE_DEFER. + * Using this helper in your probe function is totally fine even if @err is + * known to never be -EPROBE_DEFER. * The benefit compared to a normal dev_err() is the standardized format - * of the error code and the fact that the error code is returned. + * of the error code, it being emitted symbolically (i.e. you get "EAGAIN" + * instead of "-35") and the fact that the error code is returned which allows + * more compact error paths. * * Returns @err. - * */ int dev_err_probe(const struct device *dev, int err, const char *fmt, ...) { diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 548491de818ef1..47de0f140ba65e 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -525,19 +525,42 @@ bool cpu_is_hotpluggable(unsigned int cpu) EXPORT_SYMBOL_GPL(cpu_is_hotpluggable); #ifdef CONFIG_GENERIC_CPU_DEVICES -static DEFINE_PER_CPU(struct cpu, cpu_devices); -#endif +DEFINE_PER_CPU(struct cpu, cpu_devices); + +bool __weak arch_cpu_is_hotpluggable(int cpu) +{ + return false; +} + +int __weak arch_register_cpu(int cpu) +{ + struct cpu *c = &per_cpu(cpu_devices, cpu); + + c->hotpluggable = arch_cpu_is_hotpluggable(cpu); + + return register_cpu(c, cpu); +} + +#ifdef CONFIG_HOTPLUG_CPU +void __weak arch_unregister_cpu(int num) +{ + unregister_cpu(&per_cpu(cpu_devices, num)); +} +#endif /* CONFIG_HOTPLUG_CPU */ +#endif /* CONFIG_GENERIC_CPU_DEVICES */ static void __init cpu_dev_register_generic(void) { -#ifdef CONFIG_GENERIC_CPU_DEVICES - int i; + int i, ret; - for_each_possible_cpu(i) { - if (register_cpu(&per_cpu(cpu_devices, i), i)) - panic("Failed to register CPU device"); + if (!IS_ENABLED(CONFIG_GENERIC_CPU_DEVICES)) + return; + + for_each_present_cpu(i) { + ret = arch_register_cpu(i); + if (ret) + pr_warn("register_cpu %d failed (%d)\n", i, ret); } -#endif } #ifdef CONFIG_GENERIC_CPU_VULNERABILITIES diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 0c3725c3eefa46..85152537dbf12d 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -313,7 +313,7 @@ static void deferred_probe_timeout_work_func(struct work_struct *work) mutex_lock(&deferred_probe_mutex); list_for_each_entry(p, &deferred_probe_pending_list, deferred_probe) - dev_info(p->device, "deferred probe pending\n"); + dev_info(p->device, "deferred probe pending: %s", p->deferred_probe_reason ?: "(reason unknown)\n"); mutex_unlock(&deferred_probe_mutex); fw_devlink_probing_done(); diff --git a/drivers/base/firmware_loader/sysfs_upload.c b/drivers/base/firmware_loader/sysfs_upload.c index a0af8f5f13d888..829270067d1632 100644 --- a/drivers/base/firmware_loader/sysfs_upload.c +++ b/drivers/base/firmware_loader/sysfs_upload.c @@ -27,6 +27,7 @@ static const char * const fw_upload_err_str[] = { [FW_UPLOAD_ERR_INVALID_SIZE] = "invalid-file-size", [FW_UPLOAD_ERR_RW_ERROR] = "read-write-error", [FW_UPLOAD_ERR_WEAROUT] = "flash-wearout", + [FW_UPLOAD_ERR_FW_INVALID] = "firmware-invalid", }; static const char *fw_upload_progress(struct device *dev, diff --git a/drivers/base/init.c b/drivers/base/init.c index 397eb9880cecb8..c4954835128cfe 100644 --- a/drivers/base/init.c +++ b/drivers/base/init.c @@ -35,8 +35,8 @@ void __init driver_init(void) of_core_init(); platform_bus_init(); auxiliary_bus_init(); - cpu_dev_init(); memory_dev_init(); node_dev_init(); + cpu_dev_init(); container_dev_init(); } diff --git a/drivers/base/isa.c b/drivers/base/isa.c index 675ad313922462..e23d0b49a79345 100644 --- a/drivers/base/isa.c +++ b/drivers/base/isa.c @@ -82,7 +82,7 @@ static int isa_bus_resume(struct device *dev) return 0; } -static struct bus_type isa_bus_type = { +static const struct bus_type isa_bus_type = { .name = "isa", .match = isa_bus_match, .probe = isa_bus_probe, diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 8a13babd826ce3..14f964a7719bd0 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -68,7 +68,7 @@ static inline unsigned long phys_to_block_id(unsigned long phys) static int memory_subsys_online(struct device *dev); static int memory_subsys_offline(struct device *dev); -static struct bus_type memory_subsys = { +static const struct bus_type memory_subsys = { .name = MEMORY_CLASS_NAME, .dev_name = MEMORY_CLASS_NAME, .online = memory_subsys_online, diff --git a/drivers/base/node.c b/drivers/base/node.c index 493d533f837556..1c05640461dd16 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -21,7 +21,7 @@ #include #include -static struct bus_type node_subsys = { +static const struct bus_type node_subsys = { .name = "node", .dev_name = "node", }; @@ -74,14 +74,14 @@ static BIN_ATTR_RO(cpulist, CPULIST_FILE_MAX_BYTES); * @dev: Device for this memory access class * @list_node: List element in the node's access list * @access: The access class rank - * @hmem_attrs: Heterogeneous memory performance attributes + * @coord: Heterogeneous memory performance coordinates */ struct node_access_nodes { struct device dev; struct list_head list_node; unsigned int access; #ifdef CONFIG_HMEM_REPORTING - struct node_hmem_attrs hmem_attrs; + struct access_coordinate coord; #endif }; #define to_access_nodes(dev) container_of(dev, struct node_access_nodes, dev) @@ -167,7 +167,7 @@ static ssize_t property##_show(struct device *dev, \ char *buf) \ { \ return sysfs_emit(buf, "%u\n", \ - to_access_nodes(dev)->hmem_attrs.property); \ + to_access_nodes(dev)->coord.property); \ } \ static DEVICE_ATTR_RO(property) @@ -187,10 +187,10 @@ static struct attribute *access_attrs[] = { /** * node_set_perf_attrs - Set the performance values for given access class * @nid: Node identifier to be set - * @hmem_attrs: Heterogeneous memory performance attributes + * @coord: Heterogeneous memory performance coordinates * @access: The access class the for the given attributes */ -void node_set_perf_attrs(unsigned int nid, struct node_hmem_attrs *hmem_attrs, +void node_set_perf_attrs(unsigned int nid, struct access_coordinate *coord, unsigned int access) { struct node_access_nodes *c; @@ -205,7 +205,7 @@ void node_set_perf_attrs(unsigned int nid, struct node_hmem_attrs *hmem_attrs, if (!c) return; - c->hmem_attrs = *hmem_attrs; + c->coord = *coord; for (i = 0; access_attrs[i] != NULL; i++) { if (sysfs_add_file_to_group(&c->dev.kobj, access_attrs[i], "initiators")) { @@ -868,11 +868,15 @@ int __register_one_node(int nid) { int error; int cpu; + struct node *node; - node_devices[nid] = kzalloc(sizeof(struct node), GFP_KERNEL); - if (!node_devices[nid]) + node = kzalloc(sizeof(struct node), GFP_KERNEL); + if (!node) return -ENOMEM; + INIT_LIST_HEAD(&node->access_list); + node_devices[nid] = node; + error = register_node(node_devices[nid], nid); /* link cpu under this node */ @@ -881,7 +885,6 @@ int __register_one_node(int nid) register_cpu_under_node(cpu, nid); } - INIT_LIST_HEAD(&node_devices[nid]->access_list); node_init_caches(nid); return error; diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile index 8fdd0073eeebce..01f11629d241cd 100644 --- a/drivers/base/power/Makefile +++ b/drivers/base/power/Makefile @@ -2,7 +2,6 @@ obj-$(CONFIG_PM) += sysfs.o generic_ops.o common.o qos.o runtime.o wakeirq.o obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o wakeup_stats.o obj-$(CONFIG_PM_TRACE_RTC) += trace.o -obj-$(CONFIG_PM_GENERIC_DOMAINS) += domain.o domain_governor.o obj-$(CONFIG_HAVE_CLK) += clock_ops.o obj-$(CONFIG_PM_QOS_KUNIT_TEST) += qos-test.o diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c index 4110c19c08dcd7..e18ba676cdf645 100644 --- a/drivers/base/power/clock_ops.c +++ b/drivers/base/power/clock_ops.c @@ -793,7 +793,7 @@ static int pm_clk_notify(struct notifier_block *nb, * the remaining members of @clknb should be populated prior to calling this * routine. */ -void pm_clk_add_notifier(struct bus_type *bus, +void pm_clk_add_notifier(const struct bus_type *bus, struct pm_clk_notifier_block *clknb) { if (!bus || !clknb) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c deleted file mode 100644 index da1777e39eaa52..00000000000000 --- a/drivers/base/power/domain.c +++ /dev/null @@ -1,3433 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * drivers/base/power/domain.c - Common code related to device power domains. - * - * Copyright (C) 2011 Rafael J. Wysocki , Renesas Electronics Corp. - */ -#define pr_fmt(fmt) "PM: " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "power.h" - -#define GENPD_RETRY_MAX_MS 250 /* Approximate */ - -#define GENPD_DEV_CALLBACK(genpd, type, callback, dev) \ -({ \ - type (*__routine)(struct device *__d); \ - type __ret = (type)0; \ - \ - __routine = genpd->dev_ops.callback; \ - if (__routine) { \ - __ret = __routine(dev); \ - } \ - __ret; \ -}) - -static LIST_HEAD(gpd_list); -static DEFINE_MUTEX(gpd_list_lock); - -struct genpd_lock_ops { - void (*lock)(struct generic_pm_domain *genpd); - void (*lock_nested)(struct generic_pm_domain *genpd, int depth); - int (*lock_interruptible)(struct generic_pm_domain *genpd); - void (*unlock)(struct generic_pm_domain *genpd); -}; - -static void genpd_lock_mtx(struct generic_pm_domain *genpd) -{ - mutex_lock(&genpd->mlock); -} - -static void genpd_lock_nested_mtx(struct generic_pm_domain *genpd, - int depth) -{ - mutex_lock_nested(&genpd->mlock, depth); -} - -static int genpd_lock_interruptible_mtx(struct generic_pm_domain *genpd) -{ - return mutex_lock_interruptible(&genpd->mlock); -} - -static void genpd_unlock_mtx(struct generic_pm_domain *genpd) -{ - return mutex_unlock(&genpd->mlock); -} - -static const struct genpd_lock_ops genpd_mtx_ops = { - .lock = genpd_lock_mtx, - .lock_nested = genpd_lock_nested_mtx, - .lock_interruptible = genpd_lock_interruptible_mtx, - .unlock = genpd_unlock_mtx, -}; - -static void genpd_lock_spin(struct generic_pm_domain *genpd) - __acquires(&genpd->slock) -{ - unsigned long flags; - - spin_lock_irqsave(&genpd->slock, flags); - genpd->lock_flags = flags; -} - -static void genpd_lock_nested_spin(struct generic_pm_domain *genpd, - int depth) - __acquires(&genpd->slock) -{ - unsigned long flags; - - spin_lock_irqsave_nested(&genpd->slock, flags, depth); - genpd->lock_flags = flags; -} - -static int genpd_lock_interruptible_spin(struct generic_pm_domain *genpd) - __acquires(&genpd->slock) -{ - unsigned long flags; - - spin_lock_irqsave(&genpd->slock, flags); - genpd->lock_flags = flags; - return 0; -} - -static void genpd_unlock_spin(struct generic_pm_domain *genpd) - __releases(&genpd->slock) -{ - spin_unlock_irqrestore(&genpd->slock, genpd->lock_flags); -} - -static const struct genpd_lock_ops genpd_spin_ops = { - .lock = genpd_lock_spin, - .lock_nested = genpd_lock_nested_spin, - .lock_interruptible = genpd_lock_interruptible_spin, - .unlock = genpd_unlock_spin, -}; - -#define genpd_lock(p) p->lock_ops->lock(p) -#define genpd_lock_nested(p, d) p->lock_ops->lock_nested(p, d) -#define genpd_lock_interruptible(p) p->lock_ops->lock_interruptible(p) -#define genpd_unlock(p) p->lock_ops->unlock(p) - -#define genpd_status_on(genpd) (genpd->status == GENPD_STATE_ON) -#define genpd_is_irq_safe(genpd) (genpd->flags & GENPD_FLAG_IRQ_SAFE) -#define genpd_is_always_on(genpd) (genpd->flags & GENPD_FLAG_ALWAYS_ON) -#define genpd_is_active_wakeup(genpd) (genpd->flags & GENPD_FLAG_ACTIVE_WAKEUP) -#define genpd_is_cpu_domain(genpd) (genpd->flags & GENPD_FLAG_CPU_DOMAIN) -#define genpd_is_rpm_always_on(genpd) (genpd->flags & GENPD_FLAG_RPM_ALWAYS_ON) -#define genpd_is_opp_table_fw(genpd) (genpd->flags & GENPD_FLAG_OPP_TABLE_FW) - -static inline bool irq_safe_dev_in_sleep_domain(struct device *dev, - const struct generic_pm_domain *genpd) -{ - bool ret; - - ret = pm_runtime_is_irq_safe(dev) && !genpd_is_irq_safe(genpd); - - /* - * Warn once if an IRQ safe device is attached to a domain, which - * callbacks are allowed to sleep. This indicates a suboptimal - * configuration for PM, but it doesn't matter for an always on domain. - */ - if (genpd_is_always_on(genpd) || genpd_is_rpm_always_on(genpd)) - return ret; - - if (ret) - dev_warn_once(dev, "PM domain %s will not be powered off\n", - genpd->name); - - return ret; -} - -static int genpd_runtime_suspend(struct device *dev); - -/* - * Get the generic PM domain for a particular struct device. - * This validates the struct device pointer, the PM domain pointer, - * and checks that the PM domain pointer is a real generic PM domain. - * Any failure results in NULL being returned. - */ -static struct generic_pm_domain *dev_to_genpd_safe(struct device *dev) -{ - if (IS_ERR_OR_NULL(dev) || IS_ERR_OR_NULL(dev->pm_domain)) - return NULL; - - /* A genpd's always have its ->runtime_suspend() callback assigned. */ - if (dev->pm_domain->ops.runtime_suspend == genpd_runtime_suspend) - return pd_to_genpd(dev->pm_domain); - - return NULL; -} - -/* - * This should only be used where we are certain that the pm_domain - * attached to the device is a genpd domain. - */ -static struct generic_pm_domain *dev_to_genpd(struct device *dev) -{ - if (IS_ERR_OR_NULL(dev->pm_domain)) - return ERR_PTR(-EINVAL); - - return pd_to_genpd(dev->pm_domain); -} - -static int genpd_stop_dev(const struct generic_pm_domain *genpd, - struct device *dev) -{ - return GENPD_DEV_CALLBACK(genpd, int, stop, dev); -} - -static int genpd_start_dev(const struct generic_pm_domain *genpd, - struct device *dev) -{ - return GENPD_DEV_CALLBACK(genpd, int, start, dev); -} - -static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd) -{ - bool ret = false; - - if (!WARN_ON(atomic_read(&genpd->sd_count) == 0)) - ret = !!atomic_dec_and_test(&genpd->sd_count); - - return ret; -} - -static void genpd_sd_counter_inc(struct generic_pm_domain *genpd) -{ - atomic_inc(&genpd->sd_count); - smp_mb__after_atomic(); -} - -#ifdef CONFIG_DEBUG_FS -static struct dentry *genpd_debugfs_dir; - -static void genpd_debug_add(struct generic_pm_domain *genpd); - -static void genpd_debug_remove(struct generic_pm_domain *genpd) -{ - if (!genpd_debugfs_dir) - return; - - debugfs_lookup_and_remove(genpd->name, genpd_debugfs_dir); -} - -static void genpd_update_accounting(struct generic_pm_domain *genpd) -{ - u64 delta, now; - - now = ktime_get_mono_fast_ns(); - if (now <= genpd->accounting_time) - return; - - delta = now - genpd->accounting_time; - - /* - * If genpd->status is active, it means we are just - * out of off and so update the idle time and vice - * versa. - */ - if (genpd->status == GENPD_STATE_ON) - genpd->states[genpd->state_idx].idle_time += delta; - else - genpd->on_time += delta; - - genpd->accounting_time = now; -} -#else -static inline void genpd_debug_add(struct generic_pm_domain *genpd) {} -static inline void genpd_debug_remove(struct generic_pm_domain *genpd) {} -static inline void genpd_update_accounting(struct generic_pm_domain *genpd) {} -#endif - -static int _genpd_reeval_performance_state(struct generic_pm_domain *genpd, - unsigned int state) -{ - struct generic_pm_domain_data *pd_data; - struct pm_domain_data *pdd; - struct gpd_link *link; - - /* New requested state is same as Max requested state */ - if (state == genpd->performance_state) - return state; - - /* New requested state is higher than Max requested state */ - if (state > genpd->performance_state) - return state; - - /* Traverse all devices within the domain */ - list_for_each_entry(pdd, &genpd->dev_list, list_node) { - pd_data = to_gpd_data(pdd); - - if (pd_data->performance_state > state) - state = pd_data->performance_state; - } - - /* - * Traverse all sub-domains within the domain. This can be - * done without any additional locking as the link->performance_state - * field is protected by the parent genpd->lock, which is already taken. - * - * Also note that link->performance_state (subdomain's performance state - * requirement to parent domain) is different from - * link->child->performance_state (current performance state requirement - * of the devices/sub-domains of the subdomain) and so can have a - * different value. - * - * Note that we also take vote from powered-off sub-domains into account - * as the same is done for devices right now. - */ - list_for_each_entry(link, &genpd->parent_links, parent_node) { - if (link->performance_state > state) - state = link->performance_state; - } - - return state; -} - -static int genpd_xlate_performance_state(struct generic_pm_domain *genpd, - struct generic_pm_domain *parent, - unsigned int pstate) -{ - if (!parent->set_performance_state) - return pstate; - - return dev_pm_opp_xlate_performance_state(genpd->opp_table, - parent->opp_table, - pstate); -} - -static int _genpd_set_performance_state(struct generic_pm_domain *genpd, - unsigned int state, int depth) -{ - struct generic_pm_domain *parent; - struct gpd_link *link; - int parent_state, ret; - - if (state == genpd->performance_state) - return 0; - - /* Propagate to parents of genpd */ - list_for_each_entry(link, &genpd->child_links, child_node) { - parent = link->parent; - - /* Find parent's performance state */ - ret = genpd_xlate_performance_state(genpd, parent, state); - if (unlikely(ret < 0)) - goto err; - - parent_state = ret; - - genpd_lock_nested(parent, depth + 1); - - link->prev_performance_state = link->performance_state; - link->performance_state = parent_state; - parent_state = _genpd_reeval_performance_state(parent, - parent_state); - ret = _genpd_set_performance_state(parent, parent_state, depth + 1); - if (ret) - link->performance_state = link->prev_performance_state; - - genpd_unlock(parent); - - if (ret) - goto err; - } - - if (genpd->set_performance_state) { - ret = genpd->set_performance_state(genpd, state); - if (ret) - goto err; - } - - genpd->performance_state = state; - return 0; - -err: - /* Encountered an error, lets rollback */ - list_for_each_entry_continue_reverse(link, &genpd->child_links, - child_node) { - parent = link->parent; - - genpd_lock_nested(parent, depth + 1); - - parent_state = link->prev_performance_state; - link->performance_state = parent_state; - - parent_state = _genpd_reeval_performance_state(parent, - parent_state); - if (_genpd_set_performance_state(parent, parent_state, depth + 1)) { - pr_err("%s: Failed to roll back to %d performance state\n", - parent->name, parent_state); - } - - genpd_unlock(parent); - } - - return ret; -} - -static int genpd_set_performance_state(struct device *dev, unsigned int state) -{ - struct generic_pm_domain *genpd = dev_to_genpd(dev); - struct generic_pm_domain_data *gpd_data = dev_gpd_data(dev); - unsigned int prev_state; - int ret; - - prev_state = gpd_data->performance_state; - if (prev_state == state) - return 0; - - gpd_data->performance_state = state; - state = _genpd_reeval_performance_state(genpd, state); - - ret = _genpd_set_performance_state(genpd, state, 0); - if (ret) - gpd_data->performance_state = prev_state; - - return ret; -} - -static int genpd_drop_performance_state(struct device *dev) -{ - unsigned int prev_state = dev_gpd_data(dev)->performance_state; - - if (!genpd_set_performance_state(dev, 0)) - return prev_state; - - return 0; -} - -static void genpd_restore_performance_state(struct device *dev, - unsigned int state) -{ - if (state) - genpd_set_performance_state(dev, state); -} - -static int genpd_dev_pm_set_performance_state(struct device *dev, - unsigned int state) -{ - struct generic_pm_domain *genpd = dev_to_genpd(dev); - int ret = 0; - - genpd_lock(genpd); - if (pm_runtime_suspended(dev)) { - dev_gpd_data(dev)->rpm_pstate = state; - } else { - ret = genpd_set_performance_state(dev, state); - if (!ret) - dev_gpd_data(dev)->rpm_pstate = 0; - } - genpd_unlock(genpd); - - return ret; -} - -/** - * dev_pm_genpd_set_performance_state- Set performance state of device's power - * domain. - * - * @dev: Device for which the performance-state needs to be set. - * @state: Target performance state of the device. This can be set as 0 when the - * device doesn't have any performance state constraints left (And so - * the device wouldn't participate anymore to find the target - * performance state of the genpd). - * - * It is assumed that the users guarantee that the genpd wouldn't be detached - * while this routine is getting called. - * - * Returns 0 on success and negative error values on failures. - */ -int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state) -{ - struct generic_pm_domain *genpd; - - genpd = dev_to_genpd_safe(dev); - if (!genpd) - return -ENODEV; - - if (WARN_ON(!dev->power.subsys_data || - !dev->power.subsys_data->domain_data)) - return -EINVAL; - - return genpd_dev_pm_set_performance_state(dev, state); -} -EXPORT_SYMBOL_GPL(dev_pm_genpd_set_performance_state); - -/** - * dev_pm_genpd_set_next_wakeup - Notify PM framework of an impending wakeup. - * - * @dev: Device to handle - * @next: impending interrupt/wakeup for the device - * - * - * Allow devices to inform of the next wakeup. It's assumed that the users - * guarantee that the genpd wouldn't be detached while this routine is getting - * called. Additionally, it's also assumed that @dev isn't runtime suspended - * (RPM_SUSPENDED)." - * Although devices are expected to update the next_wakeup after the end of - * their usecase as well, it is possible the devices themselves may not know - * about that, so stale @next will be ignored when powering off the domain. - */ -void dev_pm_genpd_set_next_wakeup(struct device *dev, ktime_t next) -{ - struct generic_pm_domain *genpd; - struct gpd_timing_data *td; - - genpd = dev_to_genpd_safe(dev); - if (!genpd) - return; - - td = to_gpd_data(dev->power.subsys_data->domain_data)->td; - if (td) - td->next_wakeup = next; -} -EXPORT_SYMBOL_GPL(dev_pm_genpd_set_next_wakeup); - -/** - * dev_pm_genpd_get_next_hrtimer - Return the next_hrtimer for the genpd - * @dev: A device that is attached to the genpd. - * - * This routine should typically be called for a device, at the point of when a - * GENPD_NOTIFY_PRE_OFF notification has been sent for it. - * - * Returns the aggregated value of the genpd's next hrtimer or KTIME_MAX if no - * valid value have been set. - */ -ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev) -{ - struct generic_pm_domain *genpd; - - genpd = dev_to_genpd_safe(dev); - if (!genpd) - return KTIME_MAX; - - if (genpd->gd) - return genpd->gd->next_hrtimer; - - return KTIME_MAX; -} -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; - ktime_t time_start; - s64 elapsed_ns; - int ret; - - /* Notify consumers that we are about to power on. */ - ret = raw_notifier_call_chain_robust(&genpd->power_notifiers, - GENPD_NOTIFY_PRE_ON, - GENPD_NOTIFY_OFF, NULL); - ret = notifier_to_errno(ret); - if (ret) - return ret; - - if (!genpd->power_on) - goto out; - - timed = timed && genpd->gd && !genpd->states[state_idx].fwnode; - if (!timed) { - ret = genpd->power_on(genpd); - if (ret) - goto err; - - goto out; - } - - time_start = ktime_get(); - ret = genpd->power_on(genpd); - if (ret) - goto err; - - elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start)); - if (elapsed_ns <= genpd->states[state_idx].power_on_latency_ns) - goto out; - - genpd->states[state_idx].power_on_latency_ns = elapsed_ns; - genpd->gd->max_off_time_changed = true; - pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n", - genpd->name, "on", elapsed_ns); - -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, - NULL); - return ret; -} - -static int _genpd_power_off(struct generic_pm_domain *genpd, bool timed) -{ - unsigned int state_idx = genpd->state_idx; - ktime_t time_start; - s64 elapsed_ns; - int ret; - - /* Notify consumers that we are about to power off. */ - ret = raw_notifier_call_chain_robust(&genpd->power_notifiers, - GENPD_NOTIFY_PRE_OFF, - GENPD_NOTIFY_ON, NULL); - ret = notifier_to_errno(ret); - if (ret) - return ret; - - if (!genpd->power_off) - goto out; - - timed = timed && genpd->gd && !genpd->states[state_idx].fwnode; - if (!timed) { - ret = genpd->power_off(genpd); - if (ret) - goto busy; - - goto out; - } - - time_start = ktime_get(); - ret = genpd->power_off(genpd); - if (ret) - goto busy; - - elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start)); - if (elapsed_ns <= genpd->states[state_idx].power_off_latency_ns) - goto out; - - genpd->states[state_idx].power_off_latency_ns = elapsed_ns; - genpd->gd->max_off_time_changed = true; - pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n", - genpd->name, "off", elapsed_ns); - -out: - raw_notifier_call_chain(&genpd->power_notifiers, GENPD_NOTIFY_OFF, - NULL); - return 0; -busy: - raw_notifier_call_chain(&genpd->power_notifiers, GENPD_NOTIFY_ON, NULL); - return ret; -} - -/** - * genpd_queue_power_off_work - Queue up the execution of genpd_power_off(). - * @genpd: PM domain to power off. - * - * Queue up the execution of genpd_power_off() unless it's already been done - * before. - */ -static void genpd_queue_power_off_work(struct generic_pm_domain *genpd) -{ - queue_work(pm_wq, &genpd->power_off_work); -} - -/** - * genpd_power_off - Remove power from a given PM domain. - * @genpd: PM domain to power down. - * @one_dev_on: If invoked from genpd's ->runtime_suspend|resume() callback, the - * RPM status of the releated device is in an intermediate state, not yet turned - * into RPM_SUSPENDED. This means genpd_power_off() must allow one device to not - * be RPM_SUSPENDED, while it tries to power off the PM domain. - * @depth: nesting count for lockdep. - * - * If all of the @genpd's devices have been suspended and all of its subdomains - * have been powered down, remove power from @genpd. - */ -static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on, - unsigned int depth) -{ - struct pm_domain_data *pdd; - struct gpd_link *link; - unsigned int not_suspended = 0; - int ret; - - /* - * Do not try to power off the domain in the following situations: - * (1) The domain is already in the "power off" state. - * (2) System suspend is in progress. - */ - if (!genpd_status_on(genpd) || genpd->prepared_count > 0) - return 0; - - /* - * Abort power off for the PM domain in the following situations: - * (1) The domain is configured as always on. - * (2) When the domain has a subdomain being powered on. - */ - if (genpd_is_always_on(genpd) || - genpd_is_rpm_always_on(genpd) || - atomic_read(&genpd->sd_count) > 0) - return -EBUSY; - - /* - * The children must be in their deepest (powered-off) states to allow - * the parent to be powered off. Note that, there's no need for - * additional locking, as powering on a child, requires the parent's - * lock to be acquired first. - */ - list_for_each_entry(link, &genpd->parent_links, parent_node) { - struct generic_pm_domain *child = link->child; - if (child->state_idx < child->state_count - 1) - return -EBUSY; - } - - list_for_each_entry(pdd, &genpd->dev_list, list_node) { - /* - * Do not allow PM domain to be powered off, when an IRQ safe - * device is part of a non-IRQ safe domain. - */ - if (!pm_runtime_suspended(pdd->dev) || - irq_safe_dev_in_sleep_domain(pdd->dev, genpd)) - not_suspended++; - } - - if (not_suspended > 1 || (not_suspended == 1 && !one_dev_on)) - return -EBUSY; - - if (genpd->gov && genpd->gov->power_down_ok) { - if (!genpd->gov->power_down_ok(&genpd->domain)) - return -EAGAIN; - } - - /* Default to shallowest state. */ - if (!genpd->gov) - genpd->state_idx = 0; - - /* Don't power off, if a child domain is waiting to power on. */ - if (atomic_read(&genpd->sd_count) > 0) - return -EBUSY; - - ret = _genpd_power_off(genpd, true); - if (ret) { - genpd->states[genpd->state_idx].rejected++; - return ret; - } - - genpd->status = GENPD_STATE_OFF; - genpd_update_accounting(genpd); - genpd->states[genpd->state_idx].usage++; - - list_for_each_entry(link, &genpd->child_links, child_node) { - genpd_sd_counter_dec(link->parent); - genpd_lock_nested(link->parent, depth + 1); - genpd_power_off(link->parent, false, depth + 1); - genpd_unlock(link->parent); - } - - return 0; -} - -/** - * genpd_power_on - Restore power to a given PM domain and its parents. - * @genpd: PM domain to power up. - * @depth: nesting count for lockdep. - * - * Restore power to @genpd and all of its parents so that it is possible to - * resume a device belonging to it. - */ -static int genpd_power_on(struct generic_pm_domain *genpd, unsigned int depth) -{ - struct gpd_link *link; - int ret = 0; - - if (genpd_status_on(genpd)) - return 0; - - /* - * The list is guaranteed not to change while the loop below is being - * executed, unless one of the parents' .power_on() callbacks fiddles - * with it. - */ - list_for_each_entry(link, &genpd->child_links, child_node) { - struct generic_pm_domain *parent = link->parent; - - genpd_sd_counter_inc(parent); - - genpd_lock_nested(parent, depth + 1); - ret = genpd_power_on(parent, depth + 1); - genpd_unlock(parent); - - if (ret) { - genpd_sd_counter_dec(parent); - goto err; - } - } - - ret = _genpd_power_on(genpd, true); - if (ret) - goto err; - - genpd->status = GENPD_STATE_ON; - genpd_update_accounting(genpd); - - return 0; - - err: - list_for_each_entry_continue_reverse(link, - &genpd->child_links, - child_node) { - genpd_sd_counter_dec(link->parent); - genpd_lock_nested(link->parent, depth + 1); - genpd_power_off(link->parent, false, depth + 1); - genpd_unlock(link->parent); - } - - return ret; -} - -static int genpd_dev_pm_start(struct device *dev) -{ - struct generic_pm_domain *genpd = dev_to_genpd(dev); - - return genpd_start_dev(genpd, dev); -} - -static int genpd_dev_pm_qos_notifier(struct notifier_block *nb, - unsigned long val, void *ptr) -{ - struct generic_pm_domain_data *gpd_data; - struct device *dev; - - gpd_data = container_of(nb, struct generic_pm_domain_data, nb); - dev = gpd_data->base.dev; - - for (;;) { - struct generic_pm_domain *genpd = ERR_PTR(-ENODATA); - struct pm_domain_data *pdd; - struct gpd_timing_data *td; - - spin_lock_irq(&dev->power.lock); - - pdd = dev->power.subsys_data ? - dev->power.subsys_data->domain_data : NULL; - if (pdd) { - td = to_gpd_data(pdd)->td; - if (td) { - td->constraint_changed = true; - genpd = dev_to_genpd(dev); - } - } - - spin_unlock_irq(&dev->power.lock); - - if (!IS_ERR(genpd)) { - genpd_lock(genpd); - genpd->gd->max_off_time_changed = true; - genpd_unlock(genpd); - } - - dev = dev->parent; - if (!dev || dev->power.ignore_children) - break; - } - - return NOTIFY_DONE; -} - -/** - * genpd_power_off_work_fn - Power off PM domain whose subdomain count is 0. - * @work: Work structure used for scheduling the execution of this function. - */ -static void genpd_power_off_work_fn(struct work_struct *work) -{ - struct generic_pm_domain *genpd; - - genpd = container_of(work, struct generic_pm_domain, power_off_work); - - genpd_lock(genpd); - genpd_power_off(genpd, false, 0); - genpd_unlock(genpd); -} - -/** - * __genpd_runtime_suspend - walk the hierarchy of ->runtime_suspend() callbacks - * @dev: Device to handle. - */ -static int __genpd_runtime_suspend(struct device *dev) -{ - int (*cb)(struct device *__dev); - - if (dev->type && dev->type->pm) - cb = dev->type->pm->runtime_suspend; - else if (dev->class && dev->class->pm) - cb = dev->class->pm->runtime_suspend; - else if (dev->bus && dev->bus->pm) - cb = dev->bus->pm->runtime_suspend; - else - cb = NULL; - - if (!cb && dev->driver && dev->driver->pm) - cb = dev->driver->pm->runtime_suspend; - - return cb ? cb(dev) : 0; -} - -/** - * __genpd_runtime_resume - walk the hierarchy of ->runtime_resume() callbacks - * @dev: Device to handle. - */ -static int __genpd_runtime_resume(struct device *dev) -{ - int (*cb)(struct device *__dev); - - if (dev->type && dev->type->pm) - cb = dev->type->pm->runtime_resume; - else if (dev->class && dev->class->pm) - cb = dev->class->pm->runtime_resume; - else if (dev->bus && dev->bus->pm) - cb = dev->bus->pm->runtime_resume; - else - cb = NULL; - - if (!cb && dev->driver && dev->driver->pm) - cb = dev->driver->pm->runtime_resume; - - return cb ? cb(dev) : 0; -} - -/** - * genpd_runtime_suspend - Suspend a device belonging to I/O PM domain. - * @dev: Device to suspend. - * - * Carry out a runtime suspend of a device under the assumption that its - * pm_domain field points to the domain member of an object of type - * struct generic_pm_domain representing a PM domain consisting of I/O devices. - */ -static int genpd_runtime_suspend(struct device *dev) -{ - struct generic_pm_domain *genpd; - bool (*suspend_ok)(struct device *__dev); - struct generic_pm_domain_data *gpd_data = dev_gpd_data(dev); - struct gpd_timing_data *td = gpd_data->td; - bool runtime_pm = pm_runtime_enabled(dev); - ktime_t time_start = 0; - s64 elapsed_ns; - int ret; - - dev_dbg(dev, "%s()\n", __func__); - - genpd = dev_to_genpd(dev); - if (IS_ERR(genpd)) - return -EINVAL; - - /* - * A runtime PM centric subsystem/driver may re-use the runtime PM - * callbacks for other purposes than runtime PM. In those scenarios - * runtime PM is disabled. Under these circumstances, we shall skip - * validating/measuring the PM QoS latency. - */ - suspend_ok = genpd->gov ? genpd->gov->suspend_ok : NULL; - if (runtime_pm && suspend_ok && !suspend_ok(dev)) - return -EBUSY; - - /* Measure suspend latency. */ - if (td && runtime_pm) - time_start = ktime_get(); - - ret = __genpd_runtime_suspend(dev); - if (ret) - return ret; - - ret = genpd_stop_dev(genpd, dev); - if (ret) { - __genpd_runtime_resume(dev); - return ret; - } - - /* Update suspend latency value if the measured time exceeds it. */ - if (td && runtime_pm) { - elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start)); - if (elapsed_ns > td->suspend_latency_ns) { - td->suspend_latency_ns = elapsed_ns; - dev_dbg(dev, "suspend latency exceeded, %lld ns\n", - elapsed_ns); - genpd->gd->max_off_time_changed = true; - td->constraint_changed = true; - } - } - - /* - * If power.irq_safe is set, this routine may be run with - * IRQs disabled, so suspend only if the PM domain also is irq_safe. - */ - if (irq_safe_dev_in_sleep_domain(dev, genpd)) - return 0; - - genpd_lock(genpd); - genpd_power_off(genpd, true, 0); - gpd_data->rpm_pstate = genpd_drop_performance_state(dev); - genpd_unlock(genpd); - - return 0; -} - -/** - * genpd_runtime_resume - Resume a device belonging to I/O PM domain. - * @dev: Device to resume. - * - * Carry out a runtime resume of a device under the assumption that its - * pm_domain field points to the domain member of an object of type - * struct generic_pm_domain representing a PM domain consisting of I/O devices. - */ -static int genpd_runtime_resume(struct device *dev) -{ - struct generic_pm_domain *genpd; - struct generic_pm_domain_data *gpd_data = dev_gpd_data(dev); - struct gpd_timing_data *td = gpd_data->td; - bool timed = td && pm_runtime_enabled(dev); - ktime_t time_start = 0; - s64 elapsed_ns; - int ret; - - dev_dbg(dev, "%s()\n", __func__); - - genpd = dev_to_genpd(dev); - if (IS_ERR(genpd)) - return -EINVAL; - - /* - * As we don't power off a non IRQ safe domain, which holds - * an IRQ safe device, we don't need to restore power to it. - */ - if (irq_safe_dev_in_sleep_domain(dev, genpd)) - goto out; - - genpd_lock(genpd); - genpd_restore_performance_state(dev, gpd_data->rpm_pstate); - ret = genpd_power_on(genpd, 0); - genpd_unlock(genpd); - - if (ret) - return ret; - - out: - /* Measure resume latency. */ - if (timed) - time_start = ktime_get(); - - ret = genpd_start_dev(genpd, dev); - if (ret) - goto err_poweroff; - - ret = __genpd_runtime_resume(dev); - if (ret) - goto err_stop; - - /* Update resume latency value if the measured time exceeds it. */ - if (timed) { - elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start)); - if (elapsed_ns > td->resume_latency_ns) { - td->resume_latency_ns = elapsed_ns; - dev_dbg(dev, "resume latency exceeded, %lld ns\n", - elapsed_ns); - genpd->gd->max_off_time_changed = true; - td->constraint_changed = true; - } - } - - return 0; - -err_stop: - genpd_stop_dev(genpd, dev); -err_poweroff: - if (!pm_runtime_is_irq_safe(dev) || genpd_is_irq_safe(genpd)) { - genpd_lock(genpd); - genpd_power_off(genpd, true, 0); - gpd_data->rpm_pstate = genpd_drop_performance_state(dev); - genpd_unlock(genpd); - } - - return ret; -} - -static bool pd_ignore_unused; -static int __init pd_ignore_unused_setup(char *__unused) -{ - pd_ignore_unused = true; - return 1; -} -__setup("pd_ignore_unused", pd_ignore_unused_setup); - -/** - * genpd_power_off_unused - Power off all PM domains with no devices in use. - */ -static int __init genpd_power_off_unused(void) -{ - struct generic_pm_domain *genpd; - - if (pd_ignore_unused) { - pr_warn("genpd: Not disabling unused power domains\n"); - return 0; - } - - mutex_lock(&gpd_list_lock); - - list_for_each_entry(genpd, &gpd_list, gpd_list_node) - genpd_queue_power_off_work(genpd); - - mutex_unlock(&gpd_list_lock); - - return 0; -} -late_initcall(genpd_power_off_unused); - -#ifdef CONFIG_PM_SLEEP - -/** - * genpd_sync_power_off - Synchronously power off a PM domain and its parents. - * @genpd: PM domain to power off, if possible. - * @use_lock: use the lock. - * @depth: nesting count for lockdep. - * - * Check if the given PM domain can be powered off (during system suspend or - * hibernation) and do that if so. Also, in that case propagate to its parents. - * - * This function is only called in "noirq" and "syscore" stages of system power - * transitions. The "noirq" callbacks may be executed asynchronously, thus in - * these cases the lock must be held. - */ -static void genpd_sync_power_off(struct generic_pm_domain *genpd, bool use_lock, - unsigned int depth) -{ - struct gpd_link *link; - - if (!genpd_status_on(genpd) || genpd_is_always_on(genpd)) - return; - - if (genpd->suspended_count != genpd->device_count - || atomic_read(&genpd->sd_count) > 0) - return; - - /* Check that the children are in their deepest (powered-off) state. */ - list_for_each_entry(link, &genpd->parent_links, parent_node) { - struct generic_pm_domain *child = link->child; - if (child->state_idx < child->state_count - 1) - return; - } - - /* Choose the deepest state when suspending */ - genpd->state_idx = genpd->state_count - 1; - if (_genpd_power_off(genpd, false)) - return; - - genpd->status = GENPD_STATE_OFF; - - list_for_each_entry(link, &genpd->child_links, child_node) { - genpd_sd_counter_dec(link->parent); - - if (use_lock) - genpd_lock_nested(link->parent, depth + 1); - - genpd_sync_power_off(link->parent, use_lock, depth + 1); - - if (use_lock) - genpd_unlock(link->parent); - } -} - -/** - * genpd_sync_power_on - Synchronously power on a PM domain and its parents. - * @genpd: PM domain to power on. - * @use_lock: use the lock. - * @depth: nesting count for lockdep. - * - * This function is only called in "noirq" and "syscore" stages of system power - * transitions. The "noirq" callbacks may be executed asynchronously, thus in - * these cases the lock must be held. - */ -static void genpd_sync_power_on(struct generic_pm_domain *genpd, bool use_lock, - unsigned int depth) -{ - struct gpd_link *link; - - if (genpd_status_on(genpd)) - return; - - list_for_each_entry(link, &genpd->child_links, child_node) { - genpd_sd_counter_inc(link->parent); - - if (use_lock) - genpd_lock_nested(link->parent, depth + 1); - - genpd_sync_power_on(link->parent, use_lock, depth + 1); - - if (use_lock) - genpd_unlock(link->parent); - } - - _genpd_power_on(genpd, false); - genpd->status = GENPD_STATE_ON; -} - -/** - * genpd_prepare - Start power transition of a device in a PM domain. - * @dev: Device to start the transition of. - * - * Start a power transition of a device (during a system-wide power transition) - * under the assumption that its pm_domain field points to the domain member of - * an object of type struct generic_pm_domain representing a PM domain - * consisting of I/O devices. - */ -static int genpd_prepare(struct device *dev) -{ - struct generic_pm_domain *genpd; - int ret; - - dev_dbg(dev, "%s()\n", __func__); - - genpd = dev_to_genpd(dev); - if (IS_ERR(genpd)) - return -EINVAL; - - genpd_lock(genpd); - - if (genpd->prepared_count++ == 0) - genpd->suspended_count = 0; - - genpd_unlock(genpd); - - ret = pm_generic_prepare(dev); - if (ret < 0) { - genpd_lock(genpd); - - genpd->prepared_count--; - - genpd_unlock(genpd); - } - - /* Never return 1, as genpd don't cope with the direct_complete path. */ - return ret >= 0 ? 0 : ret; -} - -/** - * genpd_finish_suspend - Completion of suspend or hibernation of device in an - * I/O pm domain. - * @dev: Device to suspend. - * @suspend_noirq: Generic suspend_noirq callback. - * @resume_noirq: Generic resume_noirq callback. - * - * Stop the device and remove power from the domain if all devices in it have - * been stopped. - */ -static int genpd_finish_suspend(struct device *dev, - int (*suspend_noirq)(struct device *dev), - int (*resume_noirq)(struct device *dev)) -{ - struct generic_pm_domain *genpd; - int ret = 0; - - genpd = dev_to_genpd(dev); - if (IS_ERR(genpd)) - return -EINVAL; - - ret = suspend_noirq(dev); - if (ret) - return ret; - - if (device_wakeup_path(dev) && genpd_is_active_wakeup(genpd)) - return 0; - - if (genpd->dev_ops.stop && genpd->dev_ops.start && - !pm_runtime_status_suspended(dev)) { - ret = genpd_stop_dev(genpd, dev); - if (ret) { - resume_noirq(dev); - return ret; - } - } - - genpd_lock(genpd); - genpd->suspended_count++; - genpd_sync_power_off(genpd, true, 0); - genpd_unlock(genpd); - - return 0; -} - -/** - * genpd_suspend_noirq - Completion of suspend of device in an I/O PM domain. - * @dev: Device to suspend. - * - * Stop the device and remove power from the domain if all devices in it have - * been stopped. - */ -static int genpd_suspend_noirq(struct device *dev) -{ - dev_dbg(dev, "%s()\n", __func__); - - return genpd_finish_suspend(dev, - pm_generic_suspend_noirq, - pm_generic_resume_noirq); -} - -/** - * genpd_finish_resume - Completion of resume of device in an I/O PM domain. - * @dev: Device to resume. - * @resume_noirq: Generic resume_noirq callback. - * - * Restore power to the device's PM domain, if necessary, and start the device. - */ -static int genpd_finish_resume(struct device *dev, - int (*resume_noirq)(struct device *dev)) -{ - struct generic_pm_domain *genpd; - int ret; - - dev_dbg(dev, "%s()\n", __func__); - - genpd = dev_to_genpd(dev); - if (IS_ERR(genpd)) - return -EINVAL; - - if (device_wakeup_path(dev) && genpd_is_active_wakeup(genpd)) - return resume_noirq(dev); - - genpd_lock(genpd); - genpd_sync_power_on(genpd, true, 0); - genpd->suspended_count--; - genpd_unlock(genpd); - - if (genpd->dev_ops.stop && genpd->dev_ops.start && - !pm_runtime_status_suspended(dev)) { - ret = genpd_start_dev(genpd, dev); - if (ret) - return ret; - } - - return pm_generic_resume_noirq(dev); -} - -/** - * genpd_resume_noirq - Start of resume of device in an I/O PM domain. - * @dev: Device to resume. - * - * Restore power to the device's PM domain, if necessary, and start the device. - */ -static int genpd_resume_noirq(struct device *dev) -{ - dev_dbg(dev, "%s()\n", __func__); - - return genpd_finish_resume(dev, pm_generic_resume_noirq); -} - -/** - * genpd_freeze_noirq - Completion of freezing a device in an I/O PM domain. - * @dev: Device to freeze. - * - * Carry out a late freeze of a device under the assumption that its - * pm_domain field points to the domain member of an object of type - * struct generic_pm_domain representing a power domain consisting of I/O - * devices. - */ -static int genpd_freeze_noirq(struct device *dev) -{ - dev_dbg(dev, "%s()\n", __func__); - - return genpd_finish_suspend(dev, - pm_generic_freeze_noirq, - pm_generic_thaw_noirq); -} - -/** - * genpd_thaw_noirq - Early thaw of device in an I/O PM domain. - * @dev: Device to thaw. - * - * Start the device, unless power has been removed from the domain already - * before the system transition. - */ -static int genpd_thaw_noirq(struct device *dev) -{ - dev_dbg(dev, "%s()\n", __func__); - - return genpd_finish_resume(dev, pm_generic_thaw_noirq); -} - -/** - * genpd_poweroff_noirq - Completion of hibernation of device in an - * I/O PM domain. - * @dev: Device to poweroff. - * - * Stop the device and remove power from the domain if all devices in it have - * been stopped. - */ -static int genpd_poweroff_noirq(struct device *dev) -{ - dev_dbg(dev, "%s()\n", __func__); - - return genpd_finish_suspend(dev, - pm_generic_poweroff_noirq, - pm_generic_restore_noirq); -} - -/** - * genpd_restore_noirq - Start of restore of device in an I/O PM domain. - * @dev: Device to resume. - * - * Make sure the domain will be in the same power state as before the - * hibernation the system is resuming from and start the device if necessary. - */ -static int genpd_restore_noirq(struct device *dev) -{ - dev_dbg(dev, "%s()\n", __func__); - - return genpd_finish_resume(dev, pm_generic_restore_noirq); -} - -/** - * genpd_complete - Complete power transition of a device in a power domain. - * @dev: Device to complete the transition of. - * - * Complete a power transition of a device (during a system-wide power - * transition) under the assumption that its pm_domain field points to the - * domain member of an object of type struct generic_pm_domain representing - * a power domain consisting of I/O devices. - */ -static void genpd_complete(struct device *dev) -{ - struct generic_pm_domain *genpd; - - dev_dbg(dev, "%s()\n", __func__); - - genpd = dev_to_genpd(dev); - if (IS_ERR(genpd)) - return; - - pm_generic_complete(dev); - - genpd_lock(genpd); - - genpd->prepared_count--; - if (!genpd->prepared_count) - genpd_queue_power_off_work(genpd); - - genpd_unlock(genpd); -} - -static void genpd_switch_state(struct device *dev, bool suspend) -{ - struct generic_pm_domain *genpd; - bool use_lock; - - genpd = dev_to_genpd_safe(dev); - if (!genpd) - return; - - use_lock = genpd_is_irq_safe(genpd); - - if (use_lock) - genpd_lock(genpd); - - if (suspend) { - genpd->suspended_count++; - genpd_sync_power_off(genpd, use_lock, 0); - } else { - genpd_sync_power_on(genpd, use_lock, 0); - genpd->suspended_count--; - } - - if (use_lock) - genpd_unlock(genpd); -} - -/** - * dev_pm_genpd_suspend - Synchronously try to suspend the genpd for @dev - * @dev: The device that is attached to the genpd, that can be suspended. - * - * This routine should typically be called for a device that needs to be - * suspended during the syscore suspend phase. It may also be called during - * suspend-to-idle to suspend a corresponding CPU device that is attached to a - * genpd. - */ -void dev_pm_genpd_suspend(struct device *dev) -{ - genpd_switch_state(dev, true); -} -EXPORT_SYMBOL_GPL(dev_pm_genpd_suspend); - -/** - * dev_pm_genpd_resume - Synchronously try to resume the genpd for @dev - * @dev: The device that is attached to the genpd, which needs to be resumed. - * - * This routine should typically be called for a device that needs to be resumed - * during the syscore resume phase. It may also be called during suspend-to-idle - * to resume a corresponding CPU device that is attached to a genpd. - */ -void dev_pm_genpd_resume(struct device *dev) -{ - genpd_switch_state(dev, false); -} -EXPORT_SYMBOL_GPL(dev_pm_genpd_resume); - -#else /* !CONFIG_PM_SLEEP */ - -#define genpd_prepare NULL -#define genpd_suspend_noirq NULL -#define genpd_resume_noirq NULL -#define genpd_freeze_noirq NULL -#define genpd_thaw_noirq NULL -#define genpd_poweroff_noirq NULL -#define genpd_restore_noirq NULL -#define genpd_complete NULL - -#endif /* CONFIG_PM_SLEEP */ - -static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev, - bool has_governor) -{ - struct generic_pm_domain_data *gpd_data; - struct gpd_timing_data *td; - int ret; - - ret = dev_pm_get_subsys_data(dev); - if (ret) - return ERR_PTR(ret); - - gpd_data = kzalloc(sizeof(*gpd_data), GFP_KERNEL); - if (!gpd_data) { - ret = -ENOMEM; - goto err_put; - } - - gpd_data->base.dev = dev; - gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier; - - /* Allocate data used by a governor. */ - if (has_governor) { - td = kzalloc(sizeof(*td), GFP_KERNEL); - if (!td) { - ret = -ENOMEM; - goto err_free; - } - - td->constraint_changed = true; - td->effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS; - td->next_wakeup = KTIME_MAX; - gpd_data->td = td; - } - - spin_lock_irq(&dev->power.lock); - - if (dev->power.subsys_data->domain_data) - ret = -EINVAL; - else - dev->power.subsys_data->domain_data = &gpd_data->base; - - spin_unlock_irq(&dev->power.lock); - - if (ret) - goto err_free; - - return gpd_data; - - err_free: - kfree(gpd_data->td); - kfree(gpd_data); - err_put: - dev_pm_put_subsys_data(dev); - return ERR_PTR(ret); -} - -static void genpd_free_dev_data(struct device *dev, - struct generic_pm_domain_data *gpd_data) -{ - spin_lock_irq(&dev->power.lock); - - dev->power.subsys_data->domain_data = NULL; - - spin_unlock_irq(&dev->power.lock); - - kfree(gpd_data->td); - kfree(gpd_data); - dev_pm_put_subsys_data(dev); -} - -static void genpd_update_cpumask(struct generic_pm_domain *genpd, - int cpu, bool set, unsigned int depth) -{ - struct gpd_link *link; - - if (!genpd_is_cpu_domain(genpd)) - return; - - list_for_each_entry(link, &genpd->child_links, child_node) { - struct generic_pm_domain *parent = link->parent; - - genpd_lock_nested(parent, depth + 1); - genpd_update_cpumask(parent, cpu, set, depth + 1); - genpd_unlock(parent); - } - - if (set) - cpumask_set_cpu(cpu, genpd->cpus); - else - cpumask_clear_cpu(cpu, genpd->cpus); -} - -static void genpd_set_cpumask(struct generic_pm_domain *genpd, int cpu) -{ - if (cpu >= 0) - genpd_update_cpumask(genpd, cpu, true, 0); -} - -static void genpd_clear_cpumask(struct generic_pm_domain *genpd, int cpu) -{ - if (cpu >= 0) - genpd_update_cpumask(genpd, cpu, false, 0); -} - -static int genpd_get_cpu(struct generic_pm_domain *genpd, struct device *dev) -{ - int cpu; - - if (!genpd_is_cpu_domain(genpd)) - return -1; - - for_each_possible_cpu(cpu) { - if (get_cpu_device(cpu) == dev) - return cpu; - } - - return -1; -} - -static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev, - struct device *base_dev) -{ - struct genpd_governor_data *gd = genpd->gd; - struct generic_pm_domain_data *gpd_data; - int ret; - - dev_dbg(dev, "%s()\n", __func__); - - gpd_data = genpd_alloc_dev_data(dev, gd); - if (IS_ERR(gpd_data)) - return PTR_ERR(gpd_data); - - gpd_data->cpu = genpd_get_cpu(genpd, base_dev); - - ret = genpd->attach_dev ? genpd->attach_dev(genpd, dev) : 0; - if (ret) - goto out; - - genpd_lock(genpd); - - genpd_set_cpumask(genpd, gpd_data->cpu); - dev_pm_domain_set(dev, &genpd->domain); - - genpd->device_count++; - if (gd) - gd->max_off_time_changed = true; - - list_add_tail(&gpd_data->base.list_node, &genpd->dev_list); - - genpd_unlock(genpd); - out: - if (ret) - genpd_free_dev_data(dev, gpd_data); - else - dev_pm_qos_add_notifier(dev, &gpd_data->nb, - DEV_PM_QOS_RESUME_LATENCY); - - return ret; -} - -/** - * pm_genpd_add_device - Add a device to an I/O PM domain. - * @genpd: PM domain to add the device to. - * @dev: Device to be added. - */ -int pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev) -{ - int ret; - - if (!genpd || !dev) - return -EINVAL; - - mutex_lock(&gpd_list_lock); - ret = genpd_add_device(genpd, dev, dev); - mutex_unlock(&gpd_list_lock); - - return ret; -} -EXPORT_SYMBOL_GPL(pm_genpd_add_device); - -static int genpd_remove_device(struct generic_pm_domain *genpd, - struct device *dev) -{ - struct generic_pm_domain_data *gpd_data; - struct pm_domain_data *pdd; - int ret = 0; - - dev_dbg(dev, "%s()\n", __func__); - - pdd = dev->power.subsys_data->domain_data; - gpd_data = to_gpd_data(pdd); - dev_pm_qos_remove_notifier(dev, &gpd_data->nb, - DEV_PM_QOS_RESUME_LATENCY); - - genpd_lock(genpd); - - if (genpd->prepared_count > 0) { - ret = -EAGAIN; - goto out; - } - - genpd->device_count--; - if (genpd->gd) - genpd->gd->max_off_time_changed = true; - - genpd_clear_cpumask(genpd, gpd_data->cpu); - dev_pm_domain_set(dev, NULL); - - list_del_init(&pdd->list_node); - - genpd_unlock(genpd); - - if (genpd->detach_dev) - genpd->detach_dev(genpd, dev); - - genpd_free_dev_data(dev, gpd_data); - - return 0; - - out: - genpd_unlock(genpd); - dev_pm_qos_add_notifier(dev, &gpd_data->nb, DEV_PM_QOS_RESUME_LATENCY); - - return ret; -} - -/** - * pm_genpd_remove_device - Remove a device from an I/O PM domain. - * @dev: Device to be removed. - */ -int pm_genpd_remove_device(struct device *dev) -{ - struct generic_pm_domain *genpd = dev_to_genpd_safe(dev); - - if (!genpd) - return -EINVAL; - - return genpd_remove_device(genpd, dev); -} -EXPORT_SYMBOL_GPL(pm_genpd_remove_device); - -/** - * dev_pm_genpd_add_notifier - Add a genpd power on/off notifier for @dev - * - * @dev: Device that should be associated with the notifier - * @nb: The notifier block to register - * - * Users may call this function to add a genpd power on/off notifier for an - * attached @dev. Only one notifier per device is allowed. The notifier is - * sent when genpd is powering on/off the PM domain. - * - * It is assumed that the user guarantee that the genpd wouldn't be detached - * while this routine is getting called. - * - * Returns 0 on success and negative error values on failures. - */ -int dev_pm_genpd_add_notifier(struct device *dev, struct notifier_block *nb) -{ - struct generic_pm_domain *genpd; - struct generic_pm_domain_data *gpd_data; - int ret; - - genpd = dev_to_genpd_safe(dev); - if (!genpd) - return -ENODEV; - - if (WARN_ON(!dev->power.subsys_data || - !dev->power.subsys_data->domain_data)) - return -EINVAL; - - gpd_data = to_gpd_data(dev->power.subsys_data->domain_data); - if (gpd_data->power_nb) - return -EEXIST; - - genpd_lock(genpd); - ret = raw_notifier_chain_register(&genpd->power_notifiers, nb); - genpd_unlock(genpd); - - if (ret) { - dev_warn(dev, "failed to add notifier for PM domain %s\n", - genpd->name); - return ret; - } - - gpd_data->power_nb = nb; - return 0; -} -EXPORT_SYMBOL_GPL(dev_pm_genpd_add_notifier); - -/** - * dev_pm_genpd_remove_notifier - Remove a genpd power on/off notifier for @dev - * - * @dev: Device that is associated with the notifier - * - * Users may call this function to remove a genpd power on/off notifier for an - * attached @dev. - * - * It is assumed that the user guarantee that the genpd wouldn't be detached - * while this routine is getting called. - * - * Returns 0 on success and negative error values on failures. - */ -int dev_pm_genpd_remove_notifier(struct device *dev) -{ - struct generic_pm_domain *genpd; - struct generic_pm_domain_data *gpd_data; - int ret; - - genpd = dev_to_genpd_safe(dev); - if (!genpd) - return -ENODEV; - - if (WARN_ON(!dev->power.subsys_data || - !dev->power.subsys_data->domain_data)) - return -EINVAL; - - gpd_data = to_gpd_data(dev->power.subsys_data->domain_data); - if (!gpd_data->power_nb) - return -ENODEV; - - genpd_lock(genpd); - ret = raw_notifier_chain_unregister(&genpd->power_notifiers, - gpd_data->power_nb); - genpd_unlock(genpd); - - if (ret) { - dev_warn(dev, "failed to remove notifier for PM domain %s\n", - genpd->name); - return ret; - } - - gpd_data->power_nb = NULL; - return 0; -} -EXPORT_SYMBOL_GPL(dev_pm_genpd_remove_notifier); - -static int genpd_add_subdomain(struct generic_pm_domain *genpd, - struct generic_pm_domain *subdomain) -{ - struct gpd_link *link, *itr; - int ret = 0; - - if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain) - || genpd == subdomain) - return -EINVAL; - - /* - * If the domain can be powered on/off in an IRQ safe - * context, ensure that the subdomain can also be - * powered on/off in that context. - */ - if (!genpd_is_irq_safe(genpd) && genpd_is_irq_safe(subdomain)) { - WARN(1, "Parent %s of subdomain %s must be IRQ safe\n", - genpd->name, subdomain->name); - return -EINVAL; - } - - link = kzalloc(sizeof(*link), GFP_KERNEL); - if (!link) - return -ENOMEM; - - genpd_lock(subdomain); - genpd_lock_nested(genpd, SINGLE_DEPTH_NESTING); - - if (!genpd_status_on(genpd) && genpd_status_on(subdomain)) { - ret = -EINVAL; - goto out; - } - - list_for_each_entry(itr, &genpd->parent_links, parent_node) { - if (itr->child == subdomain && itr->parent == genpd) { - ret = -EINVAL; - goto out; - } - } - - link->parent = genpd; - list_add_tail(&link->parent_node, &genpd->parent_links); - link->child = subdomain; - list_add_tail(&link->child_node, &subdomain->child_links); - if (genpd_status_on(subdomain)) - genpd_sd_counter_inc(genpd); - - out: - genpd_unlock(genpd); - genpd_unlock(subdomain); - if (ret) - kfree(link); - return ret; -} - -/** - * pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain. - * @genpd: Leader PM domain to add the subdomain to. - * @subdomain: Subdomain to be added. - */ -int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, - struct generic_pm_domain *subdomain) -{ - int ret; - - mutex_lock(&gpd_list_lock); - ret = genpd_add_subdomain(genpd, subdomain); - mutex_unlock(&gpd_list_lock); - - return ret; -} -EXPORT_SYMBOL_GPL(pm_genpd_add_subdomain); - -/** - * pm_genpd_remove_subdomain - Remove a subdomain from an I/O PM domain. - * @genpd: Leader PM domain to remove the subdomain from. - * @subdomain: Subdomain to be removed. - */ -int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, - struct generic_pm_domain *subdomain) -{ - struct gpd_link *l, *link; - int ret = -EINVAL; - - if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain)) - return -EINVAL; - - genpd_lock(subdomain); - genpd_lock_nested(genpd, SINGLE_DEPTH_NESTING); - - if (!list_empty(&subdomain->parent_links) || subdomain->device_count) { - pr_warn("%s: unable to remove subdomain %s\n", - genpd->name, subdomain->name); - ret = -EBUSY; - goto out; - } - - list_for_each_entry_safe(link, l, &genpd->parent_links, parent_node) { - if (link->child != subdomain) - continue; - - list_del(&link->parent_node); - list_del(&link->child_node); - kfree(link); - if (genpd_status_on(subdomain)) - genpd_sd_counter_dec(genpd); - - ret = 0; - break; - } - -out: - genpd_unlock(genpd); - genpd_unlock(subdomain); - - return ret; -} -EXPORT_SYMBOL_GPL(pm_genpd_remove_subdomain); - -static void genpd_free_default_power_state(struct genpd_power_state *states, - unsigned int state_count) -{ - kfree(states); -} - -static int genpd_set_default_power_state(struct generic_pm_domain *genpd) -{ - struct genpd_power_state *state; - - state = kzalloc(sizeof(*state), GFP_KERNEL); - if (!state) - return -ENOMEM; - - genpd->states = state; - genpd->state_count = 1; - genpd->free_states = genpd_free_default_power_state; - - return 0; -} - -static int genpd_alloc_data(struct generic_pm_domain *genpd) -{ - struct genpd_governor_data *gd = NULL; - int ret; - - if (genpd_is_cpu_domain(genpd) && - !zalloc_cpumask_var(&genpd->cpus, GFP_KERNEL)) - return -ENOMEM; - - if (genpd->gov) { - gd = kzalloc(sizeof(*gd), GFP_KERNEL); - if (!gd) { - ret = -ENOMEM; - goto free; - } - - gd->max_off_time_ns = -1; - gd->max_off_time_changed = true; - gd->next_wakeup = KTIME_MAX; - gd->next_hrtimer = KTIME_MAX; - } - - /* Use only one "off" state if there were no states declared */ - if (genpd->state_count == 0) { - ret = genpd_set_default_power_state(genpd); - if (ret) - goto free; - } - - genpd->gd = gd; - return 0; - -free: - if (genpd_is_cpu_domain(genpd)) - free_cpumask_var(genpd->cpus); - kfree(gd); - return ret; -} - -static void genpd_free_data(struct generic_pm_domain *genpd) -{ - if (genpd_is_cpu_domain(genpd)) - free_cpumask_var(genpd->cpus); - if (genpd->free_states) - genpd->free_states(genpd->states, genpd->state_count); - kfree(genpd->gd); -} - -static void genpd_lock_init(struct generic_pm_domain *genpd) -{ - if (genpd->flags & GENPD_FLAG_IRQ_SAFE) { - spin_lock_init(&genpd->slock); - genpd->lock_ops = &genpd_spin_ops; - } else { - mutex_init(&genpd->mlock); - genpd->lock_ops = &genpd_mtx_ops; - } -} - -/** - * pm_genpd_init - Initialize a generic I/O PM domain object. - * @genpd: PM domain object to initialize. - * @gov: PM domain governor to associate with the domain (may be NULL). - * @is_off: Initial value of the domain's power_is_off field. - * - * Returns 0 on successful initialization, else a negative error code. - */ -int pm_genpd_init(struct generic_pm_domain *genpd, - struct dev_power_governor *gov, bool is_off) -{ - int ret; - - if (IS_ERR_OR_NULL(genpd)) - return -EINVAL; - - INIT_LIST_HEAD(&genpd->parent_links); - INIT_LIST_HEAD(&genpd->child_links); - INIT_LIST_HEAD(&genpd->dev_list); - RAW_INIT_NOTIFIER_HEAD(&genpd->power_notifiers); - genpd_lock_init(genpd); - genpd->gov = gov; - INIT_WORK(&genpd->power_off_work, genpd_power_off_work_fn); - atomic_set(&genpd->sd_count, 0); - genpd->status = is_off ? GENPD_STATE_OFF : GENPD_STATE_ON; - genpd->device_count = 0; - genpd->provider = NULL; - genpd->has_provider = false; - genpd->accounting_time = ktime_get_mono_fast_ns(); - genpd->domain.ops.runtime_suspend = genpd_runtime_suspend; - genpd->domain.ops.runtime_resume = genpd_runtime_resume; - genpd->domain.ops.prepare = genpd_prepare; - genpd->domain.ops.suspend_noirq = genpd_suspend_noirq; - genpd->domain.ops.resume_noirq = genpd_resume_noirq; - genpd->domain.ops.freeze_noirq = genpd_freeze_noirq; - genpd->domain.ops.thaw_noirq = genpd_thaw_noirq; - genpd->domain.ops.poweroff_noirq = genpd_poweroff_noirq; - genpd->domain.ops.restore_noirq = genpd_restore_noirq; - genpd->domain.ops.complete = genpd_complete; - genpd->domain.start = genpd_dev_pm_start; - genpd->domain.set_performance_state = genpd_dev_pm_set_performance_state; - - if (genpd->flags & GENPD_FLAG_PM_CLK) { - genpd->dev_ops.stop = pm_clk_suspend; - genpd->dev_ops.start = pm_clk_resume; - } - - /* The always-on governor works better with the corresponding flag. */ - if (gov == &pm_domain_always_on_gov) - genpd->flags |= GENPD_FLAG_RPM_ALWAYS_ON; - - /* Always-on domains must be powered on at initialization. */ - if ((genpd_is_always_on(genpd) || genpd_is_rpm_always_on(genpd)) && - !genpd_status_on(genpd)) { - pr_err("always-on PM domain %s is not on\n", genpd->name); - return -EINVAL; - } - - /* Multiple states but no governor doesn't make sense. */ - if (!gov && genpd->state_count > 1) - pr_warn("%s: no governor for states\n", genpd->name); - - ret = genpd_alloc_data(genpd); - if (ret) - return ret; - - device_initialize(&genpd->dev); - dev_set_name(&genpd->dev, "%s", genpd->name); - - mutex_lock(&gpd_list_lock); - list_add(&genpd->gpd_list_node, &gpd_list); - mutex_unlock(&gpd_list_lock); - genpd_debug_add(genpd); - - return 0; -} -EXPORT_SYMBOL_GPL(pm_genpd_init); - -static int genpd_remove(struct generic_pm_domain *genpd) -{ - struct gpd_link *l, *link; - - if (IS_ERR_OR_NULL(genpd)) - return -EINVAL; - - genpd_lock(genpd); - - if (genpd->has_provider) { - genpd_unlock(genpd); - pr_err("Provider present, unable to remove %s\n", genpd->name); - return -EBUSY; - } - - if (!list_empty(&genpd->parent_links) || genpd->device_count) { - genpd_unlock(genpd); - pr_err("%s: unable to remove %s\n", __func__, genpd->name); - return -EBUSY; - } - - list_for_each_entry_safe(link, l, &genpd->child_links, child_node) { - list_del(&link->parent_node); - list_del(&link->child_node); - kfree(link); - } - - list_del(&genpd->gpd_list_node); - genpd_unlock(genpd); - genpd_debug_remove(genpd); - cancel_work_sync(&genpd->power_off_work); - genpd_free_data(genpd); - - pr_debug("%s: removed %s\n", __func__, genpd->name); - - return 0; -} - -/** - * pm_genpd_remove - Remove a generic I/O PM domain - * @genpd: Pointer to PM domain that is to be removed. - * - * To remove the PM domain, this function: - * - Removes the PM domain as a subdomain to any parent domains, - * if it was added. - * - Removes the PM domain from the list of registered PM domains. - * - * The PM domain will only be removed, if the associated provider has - * been removed, it is not a parent to any other PM domain and has no - * devices associated with it. - */ -int pm_genpd_remove(struct generic_pm_domain *genpd) -{ - int ret; - - mutex_lock(&gpd_list_lock); - ret = genpd_remove(genpd); - mutex_unlock(&gpd_list_lock); - - return ret; -} -EXPORT_SYMBOL_GPL(pm_genpd_remove); - -#ifdef CONFIG_PM_GENERIC_DOMAINS_OF - -/* - * Device Tree based PM domain providers. - * - * The code below implements generic device tree based PM domain providers that - * bind device tree nodes with generic PM domains registered in the system. - * - * Any driver that registers generic PM domains and needs to support binding of - * devices to these domains is supposed to register a PM domain provider, which - * maps a PM domain specifier retrieved from the device tree to a PM domain. - * - * Two simple mapping functions have been provided for convenience: - * - genpd_xlate_simple() for 1:1 device tree node to PM domain mapping. - * - genpd_xlate_onecell() for mapping of multiple PM domains per node by - * index. - */ - -/** - * struct of_genpd_provider - PM domain provider registration structure - * @link: Entry in global list of PM domain providers - * @node: Pointer to device tree node of PM domain provider - * @xlate: Provider-specific xlate callback mapping a set of specifier cells - * into a PM domain. - * @data: context pointer to be passed into @xlate callback - */ -struct of_genpd_provider { - struct list_head link; - struct device_node *node; - genpd_xlate_t xlate; - void *data; -}; - -/* List of registered PM domain providers. */ -static LIST_HEAD(of_genpd_providers); -/* Mutex to protect the list above. */ -static DEFINE_MUTEX(of_genpd_mutex); - -/** - * genpd_xlate_simple() - Xlate function for direct node-domain mapping - * @genpdspec: OF phandle args to map into a PM domain - * @data: xlate function private data - pointer to struct generic_pm_domain - * - * This is a generic xlate function that can be used to model PM domains that - * have their own device tree nodes. The private data of xlate function needs - * to be a valid pointer to struct generic_pm_domain. - */ -static struct generic_pm_domain *genpd_xlate_simple( - struct of_phandle_args *genpdspec, - void *data) -{ - return data; -} - -/** - * genpd_xlate_onecell() - Xlate function using a single index. - * @genpdspec: OF phandle args to map into a PM domain - * @data: xlate function private data - pointer to struct genpd_onecell_data - * - * This is a generic xlate function that can be used to model simple PM domain - * controllers that have one device tree node and provide multiple PM domains. - * A single cell is used as an index into an array of PM domains specified in - * the genpd_onecell_data struct when registering the provider. - */ -static struct generic_pm_domain *genpd_xlate_onecell( - struct of_phandle_args *genpdspec, - void *data) -{ - struct genpd_onecell_data *genpd_data = data; - unsigned int idx = genpdspec->args[0]; - - if (genpdspec->args_count != 1) - return ERR_PTR(-EINVAL); - - if (idx >= genpd_data->num_domains) { - pr_err("%s: invalid domain index %u\n", __func__, idx); - return ERR_PTR(-EINVAL); - } - - if (!genpd_data->domains[idx]) - return ERR_PTR(-ENOENT); - - return genpd_data->domains[idx]; -} - -/** - * genpd_add_provider() - Register a PM domain provider for a node - * @np: Device node pointer associated with the PM domain provider. - * @xlate: Callback for decoding PM domain from phandle arguments. - * @data: Context pointer for @xlate callback. - */ -static int genpd_add_provider(struct device_node *np, genpd_xlate_t xlate, - void *data) -{ - struct of_genpd_provider *cp; - - cp = kzalloc(sizeof(*cp), GFP_KERNEL); - if (!cp) - return -ENOMEM; - - cp->node = of_node_get(np); - cp->data = data; - cp->xlate = xlate; - fwnode_dev_initialized(&np->fwnode, true); - - mutex_lock(&of_genpd_mutex); - list_add(&cp->link, &of_genpd_providers); - mutex_unlock(&of_genpd_mutex); - pr_debug("Added domain provider from %pOF\n", np); - - return 0; -} - -static bool genpd_present(const struct generic_pm_domain *genpd) -{ - bool ret = false; - const struct generic_pm_domain *gpd; - - mutex_lock(&gpd_list_lock); - list_for_each_entry(gpd, &gpd_list, gpd_list_node) { - if (gpd == genpd) { - ret = true; - break; - } - } - mutex_unlock(&gpd_list_lock); - - return ret; -} - -/** - * of_genpd_add_provider_simple() - Register a simple PM domain provider - * @np: Device node pointer associated with the PM domain provider. - * @genpd: Pointer to PM domain associated with the PM domain provider. - */ -int of_genpd_add_provider_simple(struct device_node *np, - struct generic_pm_domain *genpd) -{ - int ret; - - if (!np || !genpd) - return -EINVAL; - - if (!genpd_present(genpd)) - return -EINVAL; - - genpd->dev.of_node = np; - - /* Parse genpd OPP table */ - if (!genpd_is_opp_table_fw(genpd) && genpd->set_performance_state) { - ret = dev_pm_opp_of_add_table(&genpd->dev); - if (ret) - return dev_err_probe(&genpd->dev, ret, "Failed to add OPP table\n"); - - /* - * Save table for faster processing while setting performance - * state. - */ - genpd->opp_table = dev_pm_opp_get_opp_table(&genpd->dev); - WARN_ON(IS_ERR(genpd->opp_table)); - } - - ret = genpd_add_provider(np, genpd_xlate_simple, genpd); - if (ret) { - if (!genpd_is_opp_table_fw(genpd) && genpd->set_performance_state) { - dev_pm_opp_put_opp_table(genpd->opp_table); - dev_pm_opp_of_remove_table(&genpd->dev); - } - - return ret; - } - - genpd->provider = &np->fwnode; - genpd->has_provider = true; - - return 0; -} -EXPORT_SYMBOL_GPL(of_genpd_add_provider_simple); - -/** - * of_genpd_add_provider_onecell() - Register a onecell PM domain provider - * @np: Device node pointer associated with the PM domain provider. - * @data: Pointer to the data associated with the PM domain provider. - */ -int of_genpd_add_provider_onecell(struct device_node *np, - struct genpd_onecell_data *data) -{ - struct generic_pm_domain *genpd; - unsigned int i; - int ret = -EINVAL; - - if (!np || !data) - return -EINVAL; - - if (!data->xlate) - data->xlate = genpd_xlate_onecell; - - for (i = 0; i < data->num_domains; i++) { - genpd = data->domains[i]; - - if (!genpd) - continue; - if (!genpd_present(genpd)) - goto error; - - genpd->dev.of_node = np; - - /* Parse genpd OPP table */ - if (!genpd_is_opp_table_fw(genpd) && genpd->set_performance_state) { - ret = dev_pm_opp_of_add_table_indexed(&genpd->dev, i); - if (ret) { - dev_err_probe(&genpd->dev, ret, - "Failed to add OPP table for index %d\n", i); - goto error; - } - - /* - * Save table for faster processing while setting - * performance state. - */ - genpd->opp_table = dev_pm_opp_get_opp_table(&genpd->dev); - WARN_ON(IS_ERR(genpd->opp_table)); - } - - genpd->provider = &np->fwnode; - genpd->has_provider = true; - } - - ret = genpd_add_provider(np, data->xlate, data); - if (ret < 0) - goto error; - - return 0; - -error: - while (i--) { - genpd = data->domains[i]; - - if (!genpd) - continue; - - genpd->provider = NULL; - genpd->has_provider = false; - - if (!genpd_is_opp_table_fw(genpd) && genpd->set_performance_state) { - dev_pm_opp_put_opp_table(genpd->opp_table); - dev_pm_opp_of_remove_table(&genpd->dev); - } - } - - return ret; -} -EXPORT_SYMBOL_GPL(of_genpd_add_provider_onecell); - -/** - * of_genpd_del_provider() - Remove a previously registered PM domain provider - * @np: Device node pointer associated with the PM domain provider - */ -void of_genpd_del_provider(struct device_node *np) -{ - struct of_genpd_provider *cp, *tmp; - struct generic_pm_domain *gpd; - - mutex_lock(&gpd_list_lock); - mutex_lock(&of_genpd_mutex); - list_for_each_entry_safe(cp, tmp, &of_genpd_providers, link) { - if (cp->node == np) { - /* - * For each PM domain associated with the - * provider, set the 'has_provider' to false - * so that the PM domain can be safely removed. - */ - list_for_each_entry(gpd, &gpd_list, gpd_list_node) { - if (gpd->provider == &np->fwnode) { - gpd->has_provider = false; - - if (genpd_is_opp_table_fw(gpd) || !gpd->set_performance_state) - continue; - - dev_pm_opp_put_opp_table(gpd->opp_table); - dev_pm_opp_of_remove_table(&gpd->dev); - } - } - - fwnode_dev_initialized(&cp->node->fwnode, false); - list_del(&cp->link); - of_node_put(cp->node); - kfree(cp); - break; - } - } - mutex_unlock(&of_genpd_mutex); - mutex_unlock(&gpd_list_lock); -} -EXPORT_SYMBOL_GPL(of_genpd_del_provider); - -/** - * genpd_get_from_provider() - Look-up PM domain - * @genpdspec: OF phandle args to use for look-up - * - * Looks for a PM domain provider under the node specified by @genpdspec and if - * found, uses xlate function of the provider to map phandle args to a PM - * domain. - * - * Returns a valid pointer to struct generic_pm_domain on success or ERR_PTR() - * on failure. - */ -static struct generic_pm_domain *genpd_get_from_provider( - struct of_phandle_args *genpdspec) -{ - struct generic_pm_domain *genpd = ERR_PTR(-ENOENT); - struct of_genpd_provider *provider; - - if (!genpdspec) - return ERR_PTR(-EINVAL); - - mutex_lock(&of_genpd_mutex); - - /* Check if we have such a provider in our array */ - list_for_each_entry(provider, &of_genpd_providers, link) { - if (provider->node == genpdspec->np) - genpd = provider->xlate(genpdspec, provider->data); - if (!IS_ERR(genpd)) - break; - } - - mutex_unlock(&of_genpd_mutex); - - return genpd; -} - -/** - * of_genpd_add_device() - Add a device to an I/O PM domain - * @genpdspec: OF phandle args to use for look-up PM domain - * @dev: Device to be added. - * - * Looks-up an I/O PM domain based upon phandle args provided and adds - * the device to the PM domain. Returns a negative error code on failure. - */ -int of_genpd_add_device(struct of_phandle_args *genpdspec, struct device *dev) -{ - struct generic_pm_domain *genpd; - int ret; - - if (!dev) - return -EINVAL; - - mutex_lock(&gpd_list_lock); - - genpd = genpd_get_from_provider(genpdspec); - if (IS_ERR(genpd)) { - ret = PTR_ERR(genpd); - goto out; - } - - ret = genpd_add_device(genpd, dev, dev); - -out: - mutex_unlock(&gpd_list_lock); - - return ret; -} -EXPORT_SYMBOL_GPL(of_genpd_add_device); - -/** - * of_genpd_add_subdomain - Add a subdomain to an I/O PM domain. - * @parent_spec: OF phandle args to use for parent PM domain look-up - * @subdomain_spec: OF phandle args to use for subdomain look-up - * - * Looks-up a parent PM domain and subdomain based upon phandle args - * provided and adds the subdomain to the parent PM domain. Returns a - * negative error code on failure. - */ -int of_genpd_add_subdomain(struct of_phandle_args *parent_spec, - struct of_phandle_args *subdomain_spec) -{ - struct generic_pm_domain *parent, *subdomain; - int ret; - - mutex_lock(&gpd_list_lock); - - parent = genpd_get_from_provider(parent_spec); - if (IS_ERR(parent)) { - ret = PTR_ERR(parent); - goto out; - } - - subdomain = genpd_get_from_provider(subdomain_spec); - if (IS_ERR(subdomain)) { - ret = PTR_ERR(subdomain); - goto out; - } - - ret = genpd_add_subdomain(parent, subdomain); - -out: - mutex_unlock(&gpd_list_lock); - - return ret == -ENOENT ? -EPROBE_DEFER : ret; -} -EXPORT_SYMBOL_GPL(of_genpd_add_subdomain); - -/** - * of_genpd_remove_subdomain - Remove a subdomain from an I/O PM domain. - * @parent_spec: OF phandle args to use for parent PM domain look-up - * @subdomain_spec: OF phandle args to use for subdomain look-up - * - * Looks-up a parent PM domain and subdomain based upon phandle args - * provided and removes the subdomain from the parent PM domain. Returns a - * negative error code on failure. - */ -int of_genpd_remove_subdomain(struct of_phandle_args *parent_spec, - struct of_phandle_args *subdomain_spec) -{ - struct generic_pm_domain *parent, *subdomain; - int ret; - - mutex_lock(&gpd_list_lock); - - parent = genpd_get_from_provider(parent_spec); - if (IS_ERR(parent)) { - ret = PTR_ERR(parent); - goto out; - } - - subdomain = genpd_get_from_provider(subdomain_spec); - if (IS_ERR(subdomain)) { - ret = PTR_ERR(subdomain); - goto out; - } - - ret = pm_genpd_remove_subdomain(parent, subdomain); - -out: - mutex_unlock(&gpd_list_lock); - - return ret; -} -EXPORT_SYMBOL_GPL(of_genpd_remove_subdomain); - -/** - * of_genpd_remove_last - Remove the last PM domain registered for a provider - * @np: Pointer to device node associated with provider - * - * Find the last PM domain that was added by a particular provider and - * remove this PM domain from the list of PM domains. The provider is - * identified by the 'provider' device structure that is passed. The PM - * domain will only be removed, if the provider associated with domain - * has been removed. - * - * Returns a valid pointer to struct generic_pm_domain on success or - * ERR_PTR() on failure. - */ -struct generic_pm_domain *of_genpd_remove_last(struct device_node *np) -{ - struct generic_pm_domain *gpd, *tmp, *genpd = ERR_PTR(-ENOENT); - int ret; - - if (IS_ERR_OR_NULL(np)) - return ERR_PTR(-EINVAL); - - mutex_lock(&gpd_list_lock); - list_for_each_entry_safe(gpd, tmp, &gpd_list, gpd_list_node) { - if (gpd->provider == &np->fwnode) { - ret = genpd_remove(gpd); - genpd = ret ? ERR_PTR(ret) : gpd; - break; - } - } - mutex_unlock(&gpd_list_lock); - - return genpd; -} -EXPORT_SYMBOL_GPL(of_genpd_remove_last); - -static void genpd_release_dev(struct device *dev) -{ - of_node_put(dev->of_node); - kfree(dev); -} - -static struct bus_type genpd_bus_type = { - .name = "genpd", -}; - -/** - * genpd_dev_pm_detach - Detach a device from its PM domain. - * @dev: Device to detach. - * @power_off: Currently not used - * - * Try to locate a corresponding generic PM domain, which the device was - * attached to previously. If such is found, the device is detached from it. - */ -static void genpd_dev_pm_detach(struct device *dev, bool power_off) -{ - struct generic_pm_domain *pd; - unsigned int i; - int ret = 0; - - pd = dev_to_genpd(dev); - if (IS_ERR(pd)) - return; - - dev_dbg(dev, "removing from PM domain %s\n", pd->name); - - /* Drop the default performance state */ - if (dev_gpd_data(dev)->default_pstate) { - dev_pm_genpd_set_performance_state(dev, 0); - dev_gpd_data(dev)->default_pstate = 0; - } - - for (i = 1; i < GENPD_RETRY_MAX_MS; i <<= 1) { - ret = genpd_remove_device(pd, dev); - if (ret != -EAGAIN) - break; - - mdelay(i); - cond_resched(); - } - - if (ret < 0) { - dev_err(dev, "failed to remove from PM domain %s: %d", - pd->name, ret); - return; - } - - /* Check if PM domain can be powered off after removing this device. */ - genpd_queue_power_off_work(pd); - - /* Unregister the device if it was created by genpd. */ - if (dev->bus == &genpd_bus_type) - device_unregister(dev); -} - -static void genpd_dev_pm_sync(struct device *dev) -{ - struct generic_pm_domain *pd; - - pd = dev_to_genpd(dev); - if (IS_ERR(pd)) - return; - - genpd_queue_power_off_work(pd); -} - -static int __genpd_dev_pm_attach(struct device *dev, struct device *base_dev, - unsigned int index, bool power_on) -{ - struct of_phandle_args pd_args; - struct generic_pm_domain *pd; - int pstate; - int ret; - - ret = of_parse_phandle_with_args(dev->of_node, "power-domains", - "#power-domain-cells", index, &pd_args); - if (ret < 0) - return ret; - - mutex_lock(&gpd_list_lock); - pd = genpd_get_from_provider(&pd_args); - of_node_put(pd_args.np); - if (IS_ERR(pd)) { - mutex_unlock(&gpd_list_lock); - dev_dbg(dev, "%s() failed to find PM domain: %ld\n", - __func__, PTR_ERR(pd)); - return driver_deferred_probe_check_state(base_dev); - } - - dev_dbg(dev, "adding to PM domain %s\n", pd->name); - - ret = genpd_add_device(pd, dev, base_dev); - mutex_unlock(&gpd_list_lock); - - if (ret < 0) - return dev_err_probe(dev, ret, "failed to add to PM domain %s\n", pd->name); - - dev->pm_domain->detach = genpd_dev_pm_detach; - dev->pm_domain->sync = genpd_dev_pm_sync; - - /* Set the default performance state */ - pstate = of_get_required_opp_performance_state(dev->of_node, index); - if (pstate < 0 && pstate != -ENODEV && pstate != -EOPNOTSUPP) { - ret = pstate; - goto err; - } else if (pstate > 0) { - ret = dev_pm_genpd_set_performance_state(dev, pstate); - if (ret) - goto err; - dev_gpd_data(dev)->default_pstate = pstate; - } - - if (power_on) { - genpd_lock(pd); - ret = genpd_power_on(pd, 0); - genpd_unlock(pd); - } - - if (ret) { - /* Drop the default performance state */ - if (dev_gpd_data(dev)->default_pstate) { - dev_pm_genpd_set_performance_state(dev, 0); - dev_gpd_data(dev)->default_pstate = 0; - } - - genpd_remove_device(pd, dev); - return -EPROBE_DEFER; - } - - return 1; - -err: - dev_err(dev, "failed to set required performance state for power-domain %s: %d\n", - pd->name, ret); - genpd_remove_device(pd, dev); - return ret; -} - -/** - * genpd_dev_pm_attach - Attach a device to its PM domain using DT. - * @dev: Device to attach. - * - * Parse device's OF node to find a PM domain specifier. If such is found, - * attaches the device to retrieved pm_domain ops. - * - * Returns 1 on successfully attached PM domain, 0 when the device don't need a - * PM domain or when multiple power-domains exists for it, else a negative error - * code. Note that if a power-domain exists for the device, but it cannot be - * found or turned on, then return -EPROBE_DEFER to ensure that the device is - * not probed and to re-try again later. - */ -int genpd_dev_pm_attach(struct device *dev) -{ - if (!dev->of_node) - return 0; - - /* - * Devices with multiple PM domains must be attached separately, as we - * can only attach one PM domain per device. - */ - if (of_count_phandle_with_args(dev->of_node, "power-domains", - "#power-domain-cells") != 1) - return 0; - - return __genpd_dev_pm_attach(dev, dev, 0, true); -} -EXPORT_SYMBOL_GPL(genpd_dev_pm_attach); - -/** - * genpd_dev_pm_attach_by_id - Associate a device with one of its PM domains. - * @dev: The device used to lookup the PM domain. - * @index: The index of the PM domain. - * - * Parse device's OF node to find a PM domain specifier at the provided @index. - * If such is found, creates a virtual device and attaches it to the retrieved - * pm_domain ops. To deal with detaching of the virtual device, the ->detach() - * callback in the struct dev_pm_domain are assigned to genpd_dev_pm_detach(). - * - * Returns the created virtual device if successfully attached PM domain, NULL - * when the device don't need a PM domain, else an ERR_PTR() in case of - * failures. If a power-domain exists for the device, but cannot be found or - * turned on, then ERR_PTR(-EPROBE_DEFER) is returned to ensure that the device - * is not probed and to re-try again later. - */ -struct device *genpd_dev_pm_attach_by_id(struct device *dev, - unsigned int index) -{ - struct device *virt_dev; - int num_domains; - int ret; - - if (!dev->of_node) - return NULL; - - /* Verify that the index is within a valid range. */ - num_domains = of_count_phandle_with_args(dev->of_node, "power-domains", - "#power-domain-cells"); - if (index >= num_domains) - return NULL; - - /* Allocate and register device on the genpd bus. */ - virt_dev = kzalloc(sizeof(*virt_dev), GFP_KERNEL); - if (!virt_dev) - return ERR_PTR(-ENOMEM); - - dev_set_name(virt_dev, "genpd:%u:%s", index, dev_name(dev)); - virt_dev->bus = &genpd_bus_type; - virt_dev->release = genpd_release_dev; - virt_dev->of_node = of_node_get(dev->of_node); - - ret = device_register(virt_dev); - if (ret) { - put_device(virt_dev); - return ERR_PTR(ret); - } - - /* Try to attach the device to the PM domain at the specified index. */ - ret = __genpd_dev_pm_attach(virt_dev, dev, index, false); - if (ret < 1) { - device_unregister(virt_dev); - return ret ? ERR_PTR(ret) : NULL; - } - - pm_runtime_enable(virt_dev); - genpd_queue_power_off_work(dev_to_genpd(virt_dev)); - - return virt_dev; -} -EXPORT_SYMBOL_GPL(genpd_dev_pm_attach_by_id); - -/** - * genpd_dev_pm_attach_by_name - Associate a device with one of its PM domains. - * @dev: The device used to lookup the PM domain. - * @name: The name of the PM domain. - * - * Parse device's OF node to find a PM domain specifier using the - * power-domain-names DT property. For further description see - * genpd_dev_pm_attach_by_id(). - */ -struct device *genpd_dev_pm_attach_by_name(struct device *dev, const char *name) -{ - int index; - - if (!dev->of_node) - return NULL; - - index = of_property_match_string(dev->of_node, "power-domain-names", - name); - if (index < 0) - return NULL; - - return genpd_dev_pm_attach_by_id(dev, index); -} - -static const struct of_device_id idle_state_match[] = { - { .compatible = "domain-idle-state", }, - { } -}; - -static int genpd_parse_state(struct genpd_power_state *genpd_state, - struct device_node *state_node) -{ - int err; - u32 residency; - u32 entry_latency, exit_latency; - - err = of_property_read_u32(state_node, "entry-latency-us", - &entry_latency); - if (err) { - pr_debug(" * %pOF missing entry-latency-us property\n", - state_node); - return -EINVAL; - } - - err = of_property_read_u32(state_node, "exit-latency-us", - &exit_latency); - if (err) { - pr_debug(" * %pOF missing exit-latency-us property\n", - state_node); - return -EINVAL; - } - - err = of_property_read_u32(state_node, "min-residency-us", &residency); - if (!err) - genpd_state->residency_ns = 1000LL * residency; - - genpd_state->power_on_latency_ns = 1000LL * exit_latency; - genpd_state->power_off_latency_ns = 1000LL * entry_latency; - genpd_state->fwnode = &state_node->fwnode; - - return 0; -} - -static int genpd_iterate_idle_states(struct device_node *dn, - struct genpd_power_state *states) -{ - int ret; - struct of_phandle_iterator it; - struct device_node *np; - int i = 0; - - ret = of_count_phandle_with_args(dn, "domain-idle-states", NULL); - if (ret <= 0) - return ret == -ENOENT ? 0 : ret; - - /* Loop over the phandles until all the requested entry is found */ - of_for_each_phandle(&it, ret, dn, "domain-idle-states", NULL, 0) { - np = it.node; - if (!of_match_node(idle_state_match, np)) - continue; - - if (!of_device_is_available(np)) - continue; - - if (states) { - ret = genpd_parse_state(&states[i], np); - if (ret) { - pr_err("Parsing idle state node %pOF failed with err %d\n", - np, ret); - of_node_put(np); - return ret; - } - } - i++; - } - - return i; -} - -/** - * of_genpd_parse_idle_states: Return array of idle states for the genpd. - * - * @dn: The genpd device node - * @states: The pointer to which the state array will be saved. - * @n: The count of elements in the array returned from this function. - * - * Returns the device states parsed from the OF node. The memory for the states - * is allocated by this function and is the responsibility of the caller to - * free the memory after use. If any or zero compatible domain idle states is - * found it returns 0 and in case of errors, a negative error code is returned. - */ -int of_genpd_parse_idle_states(struct device_node *dn, - struct genpd_power_state **states, int *n) -{ - struct genpd_power_state *st; - int ret; - - ret = genpd_iterate_idle_states(dn, NULL); - if (ret < 0) - return ret; - - if (!ret) { - *states = NULL; - *n = 0; - return 0; - } - - st = kcalloc(ret, sizeof(*st), GFP_KERNEL); - if (!st) - return -ENOMEM; - - ret = genpd_iterate_idle_states(dn, st); - if (ret <= 0) { - kfree(st); - return ret < 0 ? ret : -EINVAL; - } - - *states = st; - *n = ret; - - return 0; -} -EXPORT_SYMBOL_GPL(of_genpd_parse_idle_states); - -/** - * pm_genpd_opp_to_performance_state - Gets performance state of the genpd from its OPP node. - * - * @genpd_dev: Genpd's device for which the performance-state needs to be found. - * @opp: struct dev_pm_opp of the OPP for which we need to find performance - * state. - * - * Returns performance state encoded in the OPP of the genpd. This calls - * platform specific genpd->opp_to_performance_state() callback to translate - * power domain OPP to performance state. - * - * Returns performance state on success and 0 on failure. - */ -unsigned int pm_genpd_opp_to_performance_state(struct device *genpd_dev, - struct dev_pm_opp *opp) -{ - struct generic_pm_domain *genpd = NULL; - int state; - - genpd = container_of(genpd_dev, struct generic_pm_domain, dev); - - if (unlikely(!genpd->opp_to_performance_state)) - return 0; - - genpd_lock(genpd); - state = genpd->opp_to_performance_state(genpd, opp); - genpd_unlock(genpd); - - return state; -} -EXPORT_SYMBOL_GPL(pm_genpd_opp_to_performance_state); - -static int __init genpd_bus_init(void) -{ - return bus_register(&genpd_bus_type); -} -core_initcall(genpd_bus_init); - -#endif /* CONFIG_PM_GENERIC_DOMAINS_OF */ - - -/*** debugfs support ***/ - -#ifdef CONFIG_DEBUG_FS -/* - * TODO: This function is a slightly modified version of rtpm_status_show - * from sysfs.c, so generalize it. - */ -static void rtpm_status_str(struct seq_file *s, struct device *dev) -{ - static const char * const status_lookup[] = { - [RPM_ACTIVE] = "active", - [RPM_RESUMING] = "resuming", - [RPM_SUSPENDED] = "suspended", - [RPM_SUSPENDING] = "suspending" - }; - const char *p = ""; - - if (dev->power.runtime_error) - p = "error"; - else if (dev->power.disable_depth) - p = "unsupported"; - else if (dev->power.runtime_status < ARRAY_SIZE(status_lookup)) - p = status_lookup[dev->power.runtime_status]; - else - WARN_ON(1); - - seq_printf(s, "%-25s ", p); -} - -static void perf_status_str(struct seq_file *s, struct device *dev) -{ - struct generic_pm_domain_data *gpd_data; - - gpd_data = to_gpd_data(dev->power.subsys_data->domain_data); - seq_put_decimal_ull(s, "", gpd_data->performance_state); -} - -static int genpd_summary_one(struct seq_file *s, - struct generic_pm_domain *genpd) -{ - static const char * const status_lookup[] = { - [GENPD_STATE_ON] = "on", - [GENPD_STATE_OFF] = "off" - }; - struct pm_domain_data *pm_data; - const char *kobj_path; - struct gpd_link *link; - char state[16]; - int ret; - - ret = genpd_lock_interruptible(genpd); - if (ret) - return -ERESTARTSYS; - - if (WARN_ON(genpd->status >= ARRAY_SIZE(status_lookup))) - goto exit; - if (!genpd_status_on(genpd)) - snprintf(state, sizeof(state), "%s-%u", - status_lookup[genpd->status], genpd->state_idx); - else - snprintf(state, sizeof(state), "%s", - status_lookup[genpd->status]); - seq_printf(s, "%-30s %-50s %u", genpd->name, state, genpd->performance_state); - - /* - * Modifications on the list require holding locks on both - * parent and child, so we are safe. - * Also genpd->name is immutable. - */ - list_for_each_entry(link, &genpd->parent_links, parent_node) { - if (list_is_first(&link->parent_node, &genpd->parent_links)) - seq_printf(s, "\n%48s", " "); - seq_printf(s, "%s", link->child->name); - if (!list_is_last(&link->parent_node, &genpd->parent_links)) - seq_puts(s, ", "); - } - - list_for_each_entry(pm_data, &genpd->dev_list, list_node) { - kobj_path = kobject_get_path(&pm_data->dev->kobj, - genpd_is_irq_safe(genpd) ? - GFP_ATOMIC : GFP_KERNEL); - if (kobj_path == NULL) - continue; - - seq_printf(s, "\n %-50s ", kobj_path); - rtpm_status_str(s, pm_data->dev); - perf_status_str(s, pm_data->dev); - kfree(kobj_path); - } - - seq_puts(s, "\n"); -exit: - genpd_unlock(genpd); - - return 0; -} - -static int summary_show(struct seq_file *s, void *data) -{ - struct generic_pm_domain *genpd; - int ret = 0; - - seq_puts(s, "domain status children performance\n"); - seq_puts(s, " /device runtime status\n"); - seq_puts(s, "----------------------------------------------------------------------------------------------\n"); - - ret = mutex_lock_interruptible(&gpd_list_lock); - if (ret) - return -ERESTARTSYS; - - list_for_each_entry(genpd, &gpd_list, gpd_list_node) { - ret = genpd_summary_one(s, genpd); - if (ret) - break; - } - mutex_unlock(&gpd_list_lock); - - return ret; -} - -static int status_show(struct seq_file *s, void *data) -{ - static const char * const status_lookup[] = { - [GENPD_STATE_ON] = "on", - [GENPD_STATE_OFF] = "off" - }; - - struct generic_pm_domain *genpd = s->private; - int ret = 0; - - ret = genpd_lock_interruptible(genpd); - if (ret) - return -ERESTARTSYS; - - if (WARN_ON_ONCE(genpd->status >= ARRAY_SIZE(status_lookup))) - goto exit; - - if (genpd->status == GENPD_STATE_OFF) - seq_printf(s, "%s-%u\n", status_lookup[genpd->status], - genpd->state_idx); - else - seq_printf(s, "%s\n", status_lookup[genpd->status]); -exit: - genpd_unlock(genpd); - return ret; -} - -static int sub_domains_show(struct seq_file *s, void *data) -{ - struct generic_pm_domain *genpd = s->private; - struct gpd_link *link; - int ret = 0; - - ret = genpd_lock_interruptible(genpd); - if (ret) - return -ERESTARTSYS; - - list_for_each_entry(link, &genpd->parent_links, parent_node) - seq_printf(s, "%s\n", link->child->name); - - genpd_unlock(genpd); - return ret; -} - -static int idle_states_show(struct seq_file *s, void *data) -{ - struct generic_pm_domain *genpd = s->private; - u64 now, delta, idle_time = 0; - unsigned int i; - int ret = 0; - - ret = genpd_lock_interruptible(genpd); - if (ret) - return -ERESTARTSYS; - - seq_puts(s, "State Time Spent(ms) Usage Rejected\n"); - - for (i = 0; i < genpd->state_count; i++) { - idle_time += genpd->states[i].idle_time; - - if (genpd->status == GENPD_STATE_OFF && genpd->state_idx == i) { - now = ktime_get_mono_fast_ns(); - if (now > genpd->accounting_time) { - delta = now - genpd->accounting_time; - idle_time += delta; - } - } - - do_div(idle_time, NSEC_PER_MSEC); - seq_printf(s, "S%-13i %-14llu %-14llu %llu\n", i, idle_time, - genpd->states[i].usage, genpd->states[i].rejected); - } - - genpd_unlock(genpd); - return ret; -} - -static int active_time_show(struct seq_file *s, void *data) -{ - struct generic_pm_domain *genpd = s->private; - u64 now, on_time, delta = 0; - int ret = 0; - - ret = genpd_lock_interruptible(genpd); - if (ret) - return -ERESTARTSYS; - - if (genpd->status == GENPD_STATE_ON) { - now = ktime_get_mono_fast_ns(); - if (now > genpd->accounting_time) - delta = now - genpd->accounting_time; - } - - on_time = genpd->on_time + delta; - do_div(on_time, NSEC_PER_MSEC); - seq_printf(s, "%llu ms\n", on_time); - - genpd_unlock(genpd); - return ret; -} - -static int total_idle_time_show(struct seq_file *s, void *data) -{ - struct generic_pm_domain *genpd = s->private; - u64 now, delta, total = 0; - unsigned int i; - int ret = 0; - - ret = genpd_lock_interruptible(genpd); - if (ret) - return -ERESTARTSYS; - - for (i = 0; i < genpd->state_count; i++) { - total += genpd->states[i].idle_time; - - if (genpd->status == GENPD_STATE_OFF && genpd->state_idx == i) { - now = ktime_get_mono_fast_ns(); - if (now > genpd->accounting_time) { - delta = now - genpd->accounting_time; - total += delta; - } - } - } - - do_div(total, NSEC_PER_MSEC); - seq_printf(s, "%llu ms\n", total); - - genpd_unlock(genpd); - return ret; -} - - -static int devices_show(struct seq_file *s, void *data) -{ - struct generic_pm_domain *genpd = s->private; - struct pm_domain_data *pm_data; - const char *kobj_path; - int ret = 0; - - ret = genpd_lock_interruptible(genpd); - if (ret) - return -ERESTARTSYS; - - list_for_each_entry(pm_data, &genpd->dev_list, list_node) { - kobj_path = kobject_get_path(&pm_data->dev->kobj, - genpd_is_irq_safe(genpd) ? - GFP_ATOMIC : GFP_KERNEL); - if (kobj_path == NULL) - continue; - - seq_printf(s, "%s\n", kobj_path); - kfree(kobj_path); - } - - genpd_unlock(genpd); - return ret; -} - -static int perf_state_show(struct seq_file *s, void *data) -{ - struct generic_pm_domain *genpd = s->private; - - if (genpd_lock_interruptible(genpd)) - return -ERESTARTSYS; - - seq_printf(s, "%u\n", genpd->performance_state); - - genpd_unlock(genpd); - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(summary); -DEFINE_SHOW_ATTRIBUTE(status); -DEFINE_SHOW_ATTRIBUTE(sub_domains); -DEFINE_SHOW_ATTRIBUTE(idle_states); -DEFINE_SHOW_ATTRIBUTE(active_time); -DEFINE_SHOW_ATTRIBUTE(total_idle_time); -DEFINE_SHOW_ATTRIBUTE(devices); -DEFINE_SHOW_ATTRIBUTE(perf_state); - -static void genpd_debug_add(struct generic_pm_domain *genpd) -{ - struct dentry *d; - - if (!genpd_debugfs_dir) - return; - - d = debugfs_create_dir(genpd->name, genpd_debugfs_dir); - - debugfs_create_file("current_state", 0444, - d, genpd, &status_fops); - debugfs_create_file("sub_domains", 0444, - d, genpd, &sub_domains_fops); - debugfs_create_file("idle_states", 0444, - d, genpd, &idle_states_fops); - debugfs_create_file("active_time", 0444, - d, genpd, &active_time_fops); - debugfs_create_file("total_idle_time", 0444, - d, genpd, &total_idle_time_fops); - debugfs_create_file("devices", 0444, - d, genpd, &devices_fops); - if (genpd->set_performance_state) - debugfs_create_file("perf_state", 0444, - d, genpd, &perf_state_fops); -} - -static int __init genpd_debug_init(void) -{ - struct generic_pm_domain *genpd; - - genpd_debugfs_dir = debugfs_create_dir("pm_genpd", NULL); - - debugfs_create_file("pm_genpd_summary", S_IRUGO, genpd_debugfs_dir, - NULL, &summary_fops); - - list_for_each_entry(genpd, &gpd_list, gpd_list_node) - genpd_debug_add(genpd); - - return 0; -} -late_initcall(genpd_debug_init); - -static void __exit genpd_debug_exit(void) -{ - debugfs_remove_recursive(genpd_debugfs_dir); -} -__exitcall(genpd_debug_exit); -#endif /* CONFIG_DEBUG_FS */ diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c deleted file mode 100644 index cc2c3a5a6d35a4..00000000000000 --- a/drivers/base/power/domain_governor.c +++ /dev/null @@ -1,414 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * drivers/base/power/domain_governor.c - Governors for device PM domains. - * - * Copyright (C) 2011 Rafael J. Wysocki , Renesas Electronics Corp. - */ -#include -#include -#include -#include -#include -#include -#include - -static int dev_update_qos_constraint(struct device *dev, void *data) -{ - s64 *constraint_ns_p = data; - s64 constraint_ns; - - if (dev->power.subsys_data && dev->power.subsys_data->domain_data) { - struct gpd_timing_data *td = dev_gpd_data(dev)->td; - - /* - * Only take suspend-time QoS constraints of devices into - * account, because constraints updated after the device has - * been suspended are not guaranteed to be taken into account - * anyway. In order for them to take effect, the device has to - * be resumed and suspended again. - */ - constraint_ns = td ? td->effective_constraint_ns : - PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS; - } else { - /* - * The child is not in a domain and there's no info on its - * suspend/resume latencies, so assume them to be negligible and - * take its current PM QoS constraint (that's the only thing - * known at this point anyway). - */ - constraint_ns = dev_pm_qos_read_value(dev, DEV_PM_QOS_RESUME_LATENCY); - constraint_ns *= NSEC_PER_USEC; - } - - if (constraint_ns < *constraint_ns_p) - *constraint_ns_p = constraint_ns; - - return 0; -} - -/** - * default_suspend_ok - Default PM domain governor routine to suspend devices. - * @dev: Device to check. - */ -static bool default_suspend_ok(struct device *dev) -{ - struct gpd_timing_data *td = dev_gpd_data(dev)->td; - unsigned long flags; - s64 constraint_ns; - - dev_dbg(dev, "%s()\n", __func__); - - spin_lock_irqsave(&dev->power.lock, flags); - - if (!td->constraint_changed) { - bool ret = td->cached_suspend_ok; - - spin_unlock_irqrestore(&dev->power.lock, flags); - return ret; - } - td->constraint_changed = false; - td->cached_suspend_ok = false; - td->effective_constraint_ns = 0; - constraint_ns = __dev_pm_qos_resume_latency(dev); - - spin_unlock_irqrestore(&dev->power.lock, flags); - - if (constraint_ns == 0) - return false; - - constraint_ns *= NSEC_PER_USEC; - /* - * We can walk the children without any additional locking, because - * they all have been suspended at this point and their - * effective_constraint_ns fields won't be modified in parallel with us. - */ - if (!dev->power.ignore_children) - device_for_each_child(dev, &constraint_ns, - dev_update_qos_constraint); - - if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS) { - /* "No restriction", so the device is allowed to suspend. */ - td->effective_constraint_ns = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS; - td->cached_suspend_ok = true; - } else if (constraint_ns == 0) { - /* - * This triggers if one of the children that don't belong to a - * domain has a zero PM QoS constraint and it's better not to - * suspend then. effective_constraint_ns is zero already and - * cached_suspend_ok is false, so bail out. - */ - return false; - } else { - constraint_ns -= td->suspend_latency_ns + - td->resume_latency_ns; - /* - * effective_constraint_ns is zero already and cached_suspend_ok - * is false, so if the computed value is not positive, return - * right away. - */ - if (constraint_ns <= 0) - return false; - - td->effective_constraint_ns = constraint_ns; - td->cached_suspend_ok = true; - } - - /* - * The children have been suspended already, so we don't need to take - * their suspend latencies into account here. - */ - return td->cached_suspend_ok; -} - -static void update_domain_next_wakeup(struct generic_pm_domain *genpd, ktime_t now) -{ - ktime_t domain_wakeup = KTIME_MAX; - ktime_t next_wakeup; - struct pm_domain_data *pdd; - struct gpd_link *link; - - if (!(genpd->flags & GENPD_FLAG_MIN_RESIDENCY)) - return; - - /* - * Devices that have a predictable wakeup pattern, may specify - * their next wakeup. Let's find the next wakeup from all the - * devices attached to this domain and from all the sub-domains. - * It is possible that component's a next wakeup may have become - * stale when we read that here. We will ignore to ensure the domain - * is able to enter its optimal idle state. - */ - list_for_each_entry(pdd, &genpd->dev_list, list_node) { - next_wakeup = to_gpd_data(pdd)->td->next_wakeup; - if (next_wakeup != KTIME_MAX && !ktime_before(next_wakeup, now)) - if (ktime_before(next_wakeup, domain_wakeup)) - domain_wakeup = next_wakeup; - } - - list_for_each_entry(link, &genpd->parent_links, parent_node) { - struct genpd_governor_data *cgd = link->child->gd; - - next_wakeup = cgd ? cgd->next_wakeup : KTIME_MAX; - if (next_wakeup != KTIME_MAX && !ktime_before(next_wakeup, now)) - if (ktime_before(next_wakeup, domain_wakeup)) - domain_wakeup = next_wakeup; - } - - genpd->gd->next_wakeup = domain_wakeup; -} - -static bool next_wakeup_allows_state(struct generic_pm_domain *genpd, - unsigned int state, ktime_t now) -{ - ktime_t domain_wakeup = genpd->gd->next_wakeup; - s64 idle_time_ns, min_sleep_ns; - - min_sleep_ns = genpd->states[state].power_off_latency_ns + - genpd->states[state].residency_ns; - - idle_time_ns = ktime_to_ns(ktime_sub(domain_wakeup, now)); - - return idle_time_ns >= min_sleep_ns; -} - -static bool __default_power_down_ok(struct dev_pm_domain *pd, - unsigned int state) -{ - struct generic_pm_domain *genpd = pd_to_genpd(pd); - struct gpd_link *link; - struct pm_domain_data *pdd; - s64 min_off_time_ns; - s64 off_on_time_ns; - - off_on_time_ns = genpd->states[state].power_off_latency_ns + - genpd->states[state].power_on_latency_ns; - - min_off_time_ns = -1; - /* - * Check if subdomains can be off for enough time. - * - * All subdomains have been powered off already at this point. - */ - list_for_each_entry(link, &genpd->parent_links, parent_node) { - struct genpd_governor_data *cgd = link->child->gd; - - s64 sd_max_off_ns = cgd ? cgd->max_off_time_ns : -1; - - if (sd_max_off_ns < 0) - continue; - - /* - * Check if the subdomain is allowed to be off long enough for - * the current domain to turn off and on (that's how much time - * it will have to wait worst case). - */ - if (sd_max_off_ns <= off_on_time_ns) - return false; - - if (min_off_time_ns > sd_max_off_ns || min_off_time_ns < 0) - min_off_time_ns = sd_max_off_ns; - } - - /* - * Check if the devices in the domain can be off enough time. - */ - list_for_each_entry(pdd, &genpd->dev_list, list_node) { - struct gpd_timing_data *td; - s64 constraint_ns; - - /* - * Check if the device is allowed to be off long enough for the - * domain to turn off and on (that's how much time it will - * have to wait worst case). - */ - td = to_gpd_data(pdd)->td; - constraint_ns = td->effective_constraint_ns; - /* - * Zero means "no suspend at all" and this runs only when all - * devices in the domain are suspended, so it must be positive. - */ - if (constraint_ns == PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS) - continue; - - if (constraint_ns <= off_on_time_ns) - return false; - - if (min_off_time_ns > constraint_ns || min_off_time_ns < 0) - min_off_time_ns = constraint_ns; - } - - /* - * If the computed minimum device off time is negative, there are no - * latency constraints, so the domain can spend arbitrary time in the - * "off" state. - */ - if (min_off_time_ns < 0) - return true; - - /* - * The difference between the computed minimum subdomain or device off - * time and the time needed to turn the domain on is the maximum - * theoretical time this domain can spend in the "off" state. - */ - genpd->gd->max_off_time_ns = min_off_time_ns - - genpd->states[state].power_on_latency_ns; - return true; -} - -/** - * _default_power_down_ok - Default generic PM domain power off governor routine. - * @pd: PM domain to check. - * @now: current ktime. - * - * This routine must be executed under the PM domain's lock. - */ -static bool _default_power_down_ok(struct dev_pm_domain *pd, ktime_t now) -{ - struct generic_pm_domain *genpd = pd_to_genpd(pd); - struct genpd_governor_data *gd = genpd->gd; - int state_idx = genpd->state_count - 1; - struct gpd_link *link; - - /* - * Find the next wakeup from devices that can determine their own wakeup - * to find when the domain would wakeup and do it for every device down - * the hierarchy. It is not worth while to sleep if the state's residency - * cannot be met. - */ - update_domain_next_wakeup(genpd, now); - if ((genpd->flags & GENPD_FLAG_MIN_RESIDENCY) && (gd->next_wakeup != KTIME_MAX)) { - /* Let's find out the deepest domain idle state, the devices prefer */ - while (state_idx >= 0) { - if (next_wakeup_allows_state(genpd, state_idx, now)) { - gd->max_off_time_changed = true; - break; - } - state_idx--; - } - - if (state_idx < 0) { - state_idx = 0; - gd->cached_power_down_ok = false; - goto done; - } - } - - if (!gd->max_off_time_changed) { - genpd->state_idx = gd->cached_power_down_state_idx; - return gd->cached_power_down_ok; - } - - /* - * We have to invalidate the cached results for the parents, so - * use the observation that default_power_down_ok() is not - * going to be called for any parent until this instance - * returns. - */ - list_for_each_entry(link, &genpd->child_links, child_node) { - struct genpd_governor_data *pgd = link->parent->gd; - - if (pgd) - pgd->max_off_time_changed = true; - } - - gd->max_off_time_ns = -1; - gd->max_off_time_changed = false; - gd->cached_power_down_ok = true; - - /* - * Find a state to power down to, starting from the state - * determined by the next wakeup. - */ - while (!__default_power_down_ok(pd, state_idx)) { - if (state_idx == 0) { - gd->cached_power_down_ok = false; - break; - } - state_idx--; - } - -done: - genpd->state_idx = state_idx; - gd->cached_power_down_state_idx = genpd->state_idx; - return gd->cached_power_down_ok; -} - -static bool default_power_down_ok(struct dev_pm_domain *pd) -{ - return _default_power_down_ok(pd, ktime_get()); -} - -#ifdef CONFIG_CPU_IDLE -static bool cpu_power_down_ok(struct dev_pm_domain *pd) -{ - struct generic_pm_domain *genpd = pd_to_genpd(pd); - struct cpuidle_device *dev; - ktime_t domain_wakeup, next_hrtimer; - ktime_t now = ktime_get(); - s64 idle_duration_ns; - int cpu, i; - - /* Validate dev PM QoS constraints. */ - if (!_default_power_down_ok(pd, now)) - return false; - - if (!(genpd->flags & GENPD_FLAG_CPU_DOMAIN)) - return true; - - /* - * Find the next wakeup for any of the online CPUs within the PM domain - * and its subdomains. Note, we only need the genpd->cpus, as it already - * contains a mask of all CPUs from subdomains. - */ - domain_wakeup = ktime_set(KTIME_SEC_MAX, 0); - for_each_cpu_and(cpu, genpd->cpus, cpu_online_mask) { - dev = per_cpu(cpuidle_devices, cpu); - if (dev) { - next_hrtimer = READ_ONCE(dev->next_hrtimer); - if (ktime_before(next_hrtimer, domain_wakeup)) - domain_wakeup = next_hrtimer; - } - } - - /* The minimum idle duration is from now - until the next wakeup. */ - idle_duration_ns = ktime_to_ns(ktime_sub(domain_wakeup, now)); - if (idle_duration_ns <= 0) - return false; - - /* Store the next domain_wakeup to allow consumers to use it. */ - genpd->gd->next_hrtimer = domain_wakeup; - - /* - * Find the deepest idle state that has its residency value satisfied - * and by also taking into account the power off latency for the state. - * Start at the state picked by the dev PM QoS constraint validation. - */ - i = genpd->state_idx; - do { - if (idle_duration_ns >= (genpd->states[i].residency_ns + - genpd->states[i].power_off_latency_ns)) { - genpd->state_idx = i; - return true; - } - } while (--i >= 0); - - return false; -} - -struct dev_power_governor pm_domain_cpu_gov = { - .suspend_ok = default_suspend_ok, - .power_down_ok = cpu_power_down_ok, -}; -#endif - -struct dev_power_governor simple_qos_governor = { - .suspend_ok = default_suspend_ok, - .power_down_ok = default_power_down_ok, -}; - -/** - * pm_genpd_gov_always_on - A governor implementing an always-on policy - */ -struct dev_power_governor pm_domain_always_on_gov = { - .suspend_ok = default_suspend_ok, -}; diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index f85f3515c258fc..fadcd0379dc2db 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -587,7 +587,7 @@ bool dev_pm_skip_resume(struct device *dev) * The driver of @dev will not receive interrupts while this function is being * executed. */ -static int device_resume_noirq(struct device *dev, pm_message_t state, bool async) +static void device_resume_noirq(struct device *dev, pm_message_t state, bool async) { pm_callback_t callback = NULL; const char *info = NULL; @@ -655,7 +655,13 @@ Skip: Out: complete_all(&dev->power.completion); TRACE_RESUME(error); - return error; + + if (error) { + suspend_stats.failed_resume_noirq++; + dpm_save_failed_step(SUSPEND_RESUME_NOIRQ); + dpm_save_failed_dev(dev_name(dev)); + pm_dev_err(dev, state, async ? " async noirq" : " noirq", error); + } } static bool is_async(struct device *dev) @@ -669,23 +675,29 @@ static bool dpm_async_fn(struct device *dev, async_func_t func) reinit_completion(&dev->power.completion); if (is_async(dev)) { + dev->power.async_in_progress = true; + get_device(dev); - async_schedule_dev(func, dev); - return true; - } + if (async_schedule_dev_nocall(func, dev)) + return true; + + put_device(dev); + } + /* + * Because async_schedule_dev_nocall() above has returned false or it + * has not been called at all, func() is not running and it is safe to + * update the async_in_progress flag without extra synchronization. + */ + dev->power.async_in_progress = false; return false; } static void async_resume_noirq(void *data, async_cookie_t cookie) { struct device *dev = data; - int error; - - error = device_resume_noirq(dev, pm_transition, true); - if (error) - pm_dev_err(dev, pm_transition, " async", error); + device_resume_noirq(dev, pm_transition, true); put_device(dev); } @@ -699,35 +711,27 @@ static void dpm_noirq_resume_devices(pm_message_t state) pm_transition = state; /* - * Advanced the async threads upfront, - * in case the starting of async threads is - * delayed by non-async resuming devices. + * Trigger the resume of "async" devices upfront so they don't have to + * wait for the "non-async" ones they don't depend on. */ list_for_each_entry(dev, &dpm_noirq_list, power.entry) dpm_async_fn(dev, async_resume_noirq); while (!list_empty(&dpm_noirq_list)) { dev = to_device(dpm_noirq_list.next); - get_device(dev); list_move_tail(&dev->power.entry, &dpm_late_early_list); - mutex_unlock(&dpm_list_mtx); + if (!dev->power.async_in_progress) { + get_device(dev); - if (!is_async(dev)) { - int error; + mutex_unlock(&dpm_list_mtx); - error = device_resume_noirq(dev, state, false); - if (error) { - suspend_stats.failed_resume_noirq++; - dpm_save_failed_step(SUSPEND_RESUME_NOIRQ); - dpm_save_failed_dev(dev_name(dev)); - pm_dev_err(dev, state, " noirq", error); - } - } + device_resume_noirq(dev, state, false); - put_device(dev); + put_device(dev); - mutex_lock(&dpm_list_mtx); + mutex_lock(&dpm_list_mtx); + } } mutex_unlock(&dpm_list_mtx); async_synchronize_full(); @@ -758,7 +762,7 @@ void dpm_resume_noirq(pm_message_t state) * * Runtime PM is disabled for @dev while this function is being executed. */ -static int device_resume_early(struct device *dev, pm_message_t state, bool async) +static void device_resume_early(struct device *dev, pm_message_t state, bool async) { pm_callback_t callback = NULL; const char *info = NULL; @@ -811,18 +815,20 @@ Out: pm_runtime_enable(dev); complete_all(&dev->power.completion); - return error; + + if (error) { + suspend_stats.failed_resume_early++; + dpm_save_failed_step(SUSPEND_RESUME_EARLY); + dpm_save_failed_dev(dev_name(dev)); + pm_dev_err(dev, state, async ? " async early" : " early", error); + } } static void async_resume_early(void *data, async_cookie_t cookie) { struct device *dev = data; - int error; - - error = device_resume_early(dev, pm_transition, true); - if (error) - pm_dev_err(dev, pm_transition, " async", error); + device_resume_early(dev, pm_transition, true); put_device(dev); } @@ -840,35 +846,27 @@ void dpm_resume_early(pm_message_t state) pm_transition = state; /* - * Advanced the async threads upfront, - * in case the starting of async threads is - * delayed by non-async resuming devices. + * Trigger the resume of "async" devices upfront so they don't have to + * wait for the "non-async" ones they don't depend on. */ list_for_each_entry(dev, &dpm_late_early_list, power.entry) dpm_async_fn(dev, async_resume_early); while (!list_empty(&dpm_late_early_list)) { dev = to_device(dpm_late_early_list.next); - get_device(dev); list_move_tail(&dev->power.entry, &dpm_suspended_list); - mutex_unlock(&dpm_list_mtx); + if (!dev->power.async_in_progress) { + get_device(dev); - if (!is_async(dev)) { - int error; + mutex_unlock(&dpm_list_mtx); - error = device_resume_early(dev, state, false); - if (error) { - suspend_stats.failed_resume_early++; - dpm_save_failed_step(SUSPEND_RESUME_EARLY); - dpm_save_failed_dev(dev_name(dev)); - pm_dev_err(dev, state, " early", error); - } - } + device_resume_early(dev, state, false); - put_device(dev); + put_device(dev); - mutex_lock(&dpm_list_mtx); + mutex_lock(&dpm_list_mtx); + } } mutex_unlock(&dpm_list_mtx); async_synchronize_full(); @@ -893,7 +891,7 @@ EXPORT_SYMBOL_GPL(dpm_resume_start); * @state: PM transition of the system being carried out. * @async: If true, the device is being resumed asynchronously. */ -static int device_resume(struct device *dev, pm_message_t state, bool async) +static void device_resume(struct device *dev, pm_message_t state, bool async) { pm_callback_t callback = NULL; const char *info = NULL; @@ -975,17 +973,19 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) TRACE_RESUME(error); - return error; + if (error) { + suspend_stats.failed_resume++; + dpm_save_failed_step(SUSPEND_RESUME); + dpm_save_failed_dev(dev_name(dev)); + pm_dev_err(dev, state, async ? " async" : "", error); + } } static void async_resume(void *data, async_cookie_t cookie) { struct device *dev = data; - int error; - error = device_resume(dev, pm_transition, true); - if (error) - pm_dev_err(dev, pm_transition, " async", error); + device_resume(dev, pm_transition, true); put_device(dev); } @@ -1008,27 +1008,26 @@ void dpm_resume(pm_message_t state) pm_transition = state; async_error = 0; + /* + * Trigger the resume of "async" devices upfront so they don't have to + * wait for the "non-async" ones they don't depend on. + */ list_for_each_entry(dev, &dpm_suspended_list, power.entry) dpm_async_fn(dev, async_resume); while (!list_empty(&dpm_suspended_list)) { dev = to_device(dpm_suspended_list.next); + get_device(dev); - if (!is_async(dev)) { - int error; + if (!dev->power.async_in_progress) { mutex_unlock(&dpm_list_mtx); - error = device_resume(dev, state, false); - if (error) { - suspend_stats.failed_resume++; - dpm_save_failed_step(SUSPEND_RESUME); - dpm_save_failed_dev(dev_name(dev)); - pm_dev_err(dev, state, "", error); - } + device_resume(dev, state, false); mutex_lock(&dpm_list_mtx); } + if (!list_empty(&dev->power.entry)) list_move_tail(&dev->power.entry, &dpm_prepared_list); diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index 8e93167f1783a4..bd77f6734f14cd 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c @@ -201,7 +201,7 @@ static int dev_pm_qos_constraints_allocate(struct device *dev) if (!qos) return -ENOMEM; - n = kzalloc(3 * sizeof(*n), GFP_KERNEL); + n = kcalloc(3, sizeof(*n), GFP_KERNEL); if (!n) { kfree(qos); return -ENOMEM; diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 4545669cb9735a..05793c9fbb8499 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "../base.h" diff --git a/drivers/base/power/trace.c b/drivers/base/power/trace.c index 72b7a92337b188..cd6e559648b21b 100644 --- a/drivers/base/power/trace.c +++ b/drivers/base/power/trace.c @@ -120,7 +120,7 @@ static unsigned int read_magic_time(void) struct rtc_time time; unsigned int val; - if (mc146818_get_time(&time) < 0) { + if (mc146818_get_time(&time, 1000) < 0) { pr_err("Unable to read current time from RTC\n"); return 0; } diff --git a/drivers/base/property.c b/drivers/base/property.c index 8c40abed785247..a1b01ab4205280 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -473,7 +473,7 @@ int fwnode_property_match_string(const struct fwnode_handle *fwnode, const char **values; int nval, ret; - nval = fwnode_property_read_string_array(fwnode, propname, NULL, 0); + nval = fwnode_property_string_array_count(fwnode, propname); if (nval < 0) return nval; @@ -498,6 +498,41 @@ out_free: } EXPORT_SYMBOL_GPL(fwnode_property_match_string); +/** + * fwnode_property_match_property_string - find a property string value in an array and return index + * @fwnode: Firmware node to get the property of + * @propname: Name of the property holding the string value + * @array: String array to search in + * @n: Size of the @array + * + * Find a property string value in a given @array and if it is found return + * the index back. + * + * Return: index, starting from %0, if the string value was found in the @array (success), + * %-ENOENT when the string value was not found in the @array, + * %-EINVAL if given arguments are not valid, + * %-ENODATA if the property does not have a value, + * %-EPROTO or %-EILSEQ if the property is not a string, + * %-ENXIO if no suitable firmware interface is present. + */ +int fwnode_property_match_property_string(const struct fwnode_handle *fwnode, + const char *propname, const char * const *array, size_t n) +{ + const char *string; + int ret; + + ret = fwnode_property_read_string(fwnode, propname, &string); + if (ret) + return ret; + + ret = match_string(array, n, string); + if (ret < 0) + ret = -ENOENT; + + return ret; +} +EXPORT_SYMBOL_GPL(fwnode_property_match_property_string); + /** * fwnode_property_get_reference_args() - Find a reference with arguments * @fwnode: Firmware node where to look for the reference @@ -508,6 +543,7 @@ EXPORT_SYMBOL_GPL(fwnode_property_match_string); * @nargs: Number of arguments. Ignored if @nargs_prop is non-NULL. * @index: Index of the reference, from zero onwards. * @args: Result structure with reference and integer arguments. + * May be NULL. * * Obtain a reference based on a named property in an fwnode, with * integer arguments. @@ -594,6 +630,34 @@ const char *fwnode_get_name_prefix(const struct fwnode_handle *fwnode) return fwnode_call_ptr_op(fwnode, get_name_prefix); } +/** + * fwnode_name_eq - Return true if node name is equal + * @fwnode: The firmware node + * @name: The name to which to compare the node name + * + * Compare the name provided as an argument to the name of the node, stopping + * the comparison at either NUL or '@' character, whichever comes first. This + * function is generally used for comparing node names while ignoring the + * possible unit address of the node. + * + * Return: true if the node name matches with the name provided in the @name + * argument, false otherwise. + */ +bool fwnode_name_eq(const struct fwnode_handle *fwnode, const char *name) +{ + const char *node_name; + ptrdiff_t len; + + node_name = fwnode_get_name(fwnode); + if (!node_name) + return false; + + len = strchrnul(node_name, '@') - node_name; + + return str_has_prefix(node_name, name) == len; +} +EXPORT_SYMBOL_GPL(fwnode_name_eq); + /** * fwnode_get_parent - Return parent firwmare node * @fwnode: Firmware whose parent is retrieved diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 9a9ea514c2d817..583dd5d7d46bf3 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -318,6 +318,7 @@ struct regmap_ram_data { bool *read; bool *written; enum regmap_endian reg_endian; + bool (*noinc_reg)(struct regmap_ram_data *data, unsigned int reg); }; /* diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index bdd80b73c3e6c1..fb84cda92a753f 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c @@ -226,8 +226,8 @@ static ssize_t regmap_read_debugfs(struct regmap *map, unsigned int from, if (*ppos < 0 || !count) return -EINVAL; - if (count > (PAGE_SIZE << MAX_ORDER)) - count = PAGE_SIZE << MAX_ORDER; + if (count > (PAGE_SIZE << MAX_PAGE_ORDER)) + count = PAGE_SIZE << MAX_PAGE_ORDER; buf = kmalloc(count, GFP_KERNEL); if (!buf) @@ -373,8 +373,8 @@ static ssize_t regmap_reg_ranges_read_file(struct file *file, if (*ppos < 0 || !count) return -EINVAL; - if (count > (PAGE_SIZE << MAX_ORDER)) - count = PAGE_SIZE << MAX_ORDER; + if (count > (PAGE_SIZE << MAX_PAGE_ORDER)) + count = PAGE_SIZE << MAX_PAGE_ORDER; buf = kmalloc(count, GFP_KERNEL); if (!buf) diff --git a/drivers/base/regmap/regmap-kunit.c b/drivers/base/regmap/regmap-kunit.c index e14cc03a17f6c7..026bdcb45127f5 100644 --- a/drivers/base/regmap/regmap-kunit.c +++ b/drivers/base/regmap/regmap-kunit.c @@ -1186,6 +1186,65 @@ static void raw_write(struct kunit *test) regmap_exit(map); } +static bool reg_zero(struct device *dev, unsigned int reg) +{ + return reg == 0; +} + +static bool ram_reg_zero(struct regmap_ram_data *data, unsigned int reg) +{ + return reg == 0; +} + +static void raw_noinc_write(struct kunit *test) +{ + struct raw_test_types *t = (struct raw_test_types *)test->param_value; + struct regmap *map; + struct regmap_config config; + struct regmap_ram_data *data; + unsigned int val, val_test, val_last; + u16 val_array[BLOCK_TEST_SIZE]; + + config = raw_regmap_config; + config.volatile_reg = reg_zero; + config.writeable_noinc_reg = reg_zero; + config.readable_noinc_reg = reg_zero; + + map = gen_raw_regmap(&config, t, &data); + KUNIT_ASSERT_FALSE(test, IS_ERR(map)); + if (IS_ERR(map)) + return; + + data->noinc_reg = ram_reg_zero; + + get_random_bytes(&val_array, sizeof(val_array)); + + if (config.val_format_endian == REGMAP_ENDIAN_BIG) { + val_test = be16_to_cpu(val_array[1]) + 100; + val_last = be16_to_cpu(val_array[BLOCK_TEST_SIZE - 1]); + } else { + val_test = le16_to_cpu(val_array[1]) + 100; + val_last = le16_to_cpu(val_array[BLOCK_TEST_SIZE - 1]); + } + + /* Put some data into the register following the noinc register */ + KUNIT_EXPECT_EQ(test, 0, regmap_write(map, 1, val_test)); + + /* Write some data to the noinc register */ + KUNIT_EXPECT_EQ(test, 0, regmap_noinc_write(map, 0, val_array, + sizeof(val_array))); + + /* We should read back the last value written */ + KUNIT_EXPECT_EQ(test, 0, regmap_read(map, 0, &val)); + KUNIT_ASSERT_EQ(test, val_last, val); + + /* Make sure we didn't touch the register after the noinc register */ + KUNIT_EXPECT_EQ(test, 0, regmap_read(map, 1, &val)); + KUNIT_ASSERT_EQ(test, val_test, val); + + regmap_exit(map); +} + static void raw_sync(struct kunit *test) { struct raw_test_types *t = (struct raw_test_types *)test->param_value; @@ -1284,6 +1343,7 @@ static struct kunit_case regmap_test_cases[] = { KUNIT_CASE_PARAM(raw_read_defaults, raw_test_types_gen_params), KUNIT_CASE_PARAM(raw_write_read_single, raw_test_types_gen_params), KUNIT_CASE_PARAM(raw_write, raw_test_types_gen_params), + KUNIT_CASE_PARAM(raw_noinc_write, raw_test_types_gen_params), KUNIT_CASE_PARAM(raw_sync, raw_test_cache_types_gen_params), {} }; diff --git a/drivers/base/regmap/regmap-ram.c b/drivers/base/regmap/regmap-ram.c index 85f34a5dee04e2..192d6b131dff8e 100644 --- a/drivers/base/regmap/regmap-ram.c +++ b/drivers/base/regmap/regmap-ram.c @@ -65,12 +65,12 @@ struct regmap *__regmap_init_ram(const struct regmap_config *config, return ERR_PTR(-EINVAL); } - data->read = kcalloc(sizeof(bool), config->max_register + 1, + data->read = kcalloc(config->max_register + 1, sizeof(bool), GFP_KERNEL); if (!data->read) return ERR_PTR(-ENOMEM); - data->written = kcalloc(sizeof(bool), config->max_register + 1, + data->written = kcalloc(config->max_register + 1, sizeof(bool), GFP_KERNEL); if (!data->written) return ERR_PTR(-ENOMEM); diff --git a/drivers/base/regmap/regmap-raw-ram.c b/drivers/base/regmap/regmap-raw-ram.c index c9b800885f3ba4..93ae07b503fda1 100644 --- a/drivers/base/regmap/regmap-raw-ram.c +++ b/drivers/base/regmap/regmap-raw-ram.c @@ -41,10 +41,15 @@ static int regmap_raw_ram_gather_write(void *context, return -EINVAL; r = decode_reg(data->reg_endian, reg); - memcpy(&our_buf[r], val, val_len); - - for (i = 0; i < val_len / 2; i++) - data->written[r + i] = true; + if (data->noinc_reg && data->noinc_reg(data, r)) { + memcpy(&our_buf[r], val + val_len - 2, 2); + data->written[r] = true; + } else { + memcpy(&our_buf[r], val, val_len); + + for (i = 0; i < val_len / 2; i++) + data->written[r + i] = true; + } return 0; } @@ -70,10 +75,16 @@ static int regmap_raw_ram_read(void *context, return -EINVAL; r = decode_reg(data->reg_endian, reg); - memcpy(val, &our_buf[r], val_len); - - for (i = 0; i < val_len / 2; i++) - data->read[r + i] = true; + if (data->noinc_reg && data->noinc_reg(data, r)) { + for (i = 0; i < val_len; i += 2) + memcpy(val + i, &our_buf[r], 2); + data->read[r] = true; + } else { + memcpy(val, &our_buf[r], val_len); + + for (i = 0; i < val_len / 2; i++) + data->read[r + i] = true; + } return 0; } @@ -111,12 +122,12 @@ struct regmap *__regmap_init_raw_ram(const struct regmap_config *config, return ERR_PTR(-EINVAL); } - data->read = kcalloc(sizeof(bool), config->max_register + 1, + data->read = kcalloc(config->max_register + 1, sizeof(bool), GFP_KERNEL); if (!data->read) return ERR_PTR(-ENOMEM); - data->written = kcalloc(sizeof(bool), config->max_register + 1, + data->written = kcalloc(config->max_register + 1, sizeof(bool), GFP_KERNEL); if (!data->written) return ERR_PTR(-ENOMEM); diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index ea615774719941..6db77d8e45f924 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -2136,7 +2136,7 @@ static int regmap_noinc_readwrite(struct regmap *map, unsigned int reg, } /** - * regmap_noinc_write(): Write data from a register without incrementing the + * regmap_noinc_write(): Write data to a register without incrementing the * register number * * @map: Register map to write to diff --git a/drivers/base/soc.c b/drivers/base/soc.c index 8dec5228fde3d4..282c38aece0de8 100644 --- a/drivers/base/soc.c +++ b/drivers/base/soc.c @@ -28,7 +28,7 @@ struct soc_device { int soc_dev_num; }; -static struct bus_type soc_bus_type = { +static const struct bus_type soc_bus_type = { .name = "soc", }; static bool soc_bus_registered; @@ -106,7 +106,7 @@ static void soc_release(struct device *dev) { struct soc_device *soc_dev = container_of(dev, struct soc_device, dev); - ida_simple_remove(&soc_ida, soc_dev->soc_dev_num); + ida_free(&soc_ida, soc_dev->soc_dev_num); kfree(soc_dev->dev.groups); kfree(soc_dev); } @@ -155,7 +155,7 @@ struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr soc_attr_groups[1] = soc_dev_attr->custom_attr_group; /* Fetch a unique (reclaimable) SOC ID. */ - ret = ida_simple_get(&soc_ida, 0, 0, GFP_KERNEL); + ret = ida_alloc(&soc_ida, GFP_KERNEL); if (ret < 0) goto out3; soc_dev->soc_dev_num = ret; diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c index 1886995a0b3a30..36512fb75a201c 100644 --- a/drivers/base/swnode.c +++ b/drivers/base/swnode.c @@ -541,6 +541,9 @@ software_node_get_reference_args(const struct fwnode_handle *fwnode, if (nargs > NR_FWNODE_REFERENCE_ARGS) return -EINVAL; + if (!args) + return 0; + args->fwnode = software_node_get(refnode); args->nargs = nargs; @@ -747,10 +750,10 @@ static void software_node_release(struct kobject *kobj) struct swnode *swnode = kobj_to_swnode(kobj); if (swnode->parent) { - ida_simple_remove(&swnode->parent->child_ids, swnode->id); + ida_free(&swnode->parent->child_ids, swnode->id); list_del(&swnode->entry); } else { - ida_simple_remove(&swnode_root_ids, swnode->id); + ida_free(&swnode_root_ids, swnode->id); } if (swnode->allocated) @@ -776,8 +779,8 @@ swnode_register(const struct software_node *node, struct swnode *parent, if (!swnode) return ERR_PTR(-ENOMEM); - ret = ida_simple_get(parent ? &parent->child_ids : &swnode_root_ids, - 0, 0, GFP_KERNEL); + ret = ida_alloc(parent ? &parent->child_ids : &swnode_root_ids, + GFP_KERNEL); if (ret < 0) { kfree(swnode); return ERR_PTR(ret); diff --git a/drivers/bcma/driver_pci_host.c b/drivers/bcma/driver_pci_host.c index aa0581cda71855..ed3be52ab63d16 100644 --- a/drivers/bcma/driver_pci_host.c +++ b/drivers/bcma/driver_pci_host.c @@ -280,7 +280,7 @@ static u8 bcma_find_pci_capability(struct bcma_drv_pci *pc, unsigned int dev, /* check for Header type 0 */ bcma_extpci_read_config(pc, dev, func, PCI_HEADER_TYPE, &byte_val, sizeof(u8)); - if ((byte_val & 0x7F) != PCI_HEADER_TYPE_NORMAL) + if ((byte_val & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_NORMAL) return cap_ptr; /* check if the capability pointer field exists */ diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index cf6883756155a3..b1b47d88f5db44 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -333,6 +333,7 @@ aoeblk_gdalloc(void *vp) struct gendisk *gd; mempool_t *mp; struct blk_mq_tag_set *set; + sector_t ssize; ulong flags; int late = 0; int err; @@ -383,7 +384,8 @@ aoeblk_gdalloc(void *vp) WARN_ON(d->flags & DEVFL_TKILL); WARN_ON(d->gd); WARN_ON(d->flags & DEVFL_UP); - blk_queue_max_hw_sectors(gd->queue, BLK_DEF_MAX_SECTORS); + /* random number picked from the history block max_sectors cap */ + blk_queue_max_hw_sectors(gd->queue, 2560u); blk_queue_io_opt(gd->queue, SZ_2M); d->bufpool = mp; d->blkq = gd->queue; @@ -395,7 +397,7 @@ aoeblk_gdalloc(void *vp) gd->minors = AOE_PARTITIONS; gd->fops = &aoe_bdops; gd->private_data = d; - set_capacity(gd, d->ssize); + ssize = d->ssize; snprintf(gd->disk_name, sizeof gd->disk_name, "etherd/e%ld.%d", d->aoemajor, d->aoeminor); @@ -404,6 +406,8 @@ aoeblk_gdalloc(void *vp) spin_unlock_irqrestore(&d->lock, flags); + set_capacity(gd, ssize); + err = device_add_disk(NULL, gd, aoe_attr_groups); if (err) goto out_disk_cleanup; diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index 64b3a1c76f03d7..742b2908ff686a 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -838,8 +838,8 @@ static bool plausible_request_size(int size) } /* clear the bit corresponding to the piece of storage in question: - * size byte of data starting from sector. Only clear a bits of the affected - * one ore more _aligned_ BM_BLOCK_SIZE blocks. + * size byte of data starting from sector. Only clear bits of the affected + * one or more _aligned_ BM_BLOCK_SIZE blocks. * * called by worker on C_SYNC_TARGET and receiver on SyncSource. * @@ -957,7 +957,9 @@ static int _is_in_al(struct drbd_device *device, unsigned int enr) * @device: DRBD device. * @sector: The sector number. * - * This functions sleeps on al_wait. Returns 0 on success, -EINTR if interrupted. + * This functions sleeps on al_wait. + * + * Returns: %0 on success, -EINTR if interrupted. */ int drbd_rs_begin_io(struct drbd_device *device, sector_t sector) { @@ -1004,11 +1006,13 @@ retry: /** * drbd_try_rs_begin_io() - Gets an extent in the resync LRU cache, does not sleep - * @device: DRBD device. + * @peer_device: DRBD device. * @sector: The sector number. * * Gets an extent in the resync LRU cache, sets it to BME_NO_WRITES, then - * tries to set it to BME_LOCKED. Returns 0 upon success, and -EAGAIN + * tries to set it to BME_LOCKED. + * + * Returns: %0 upon success, and -EAGAIN * if there is still application IO going on in this area. */ int drbd_try_rs_begin_io(struct drbd_peer_device *peer_device, sector_t sector) @@ -1190,7 +1194,7 @@ void drbd_rs_cancel_all(struct drbd_device *device) * drbd_rs_del_all() - Gracefully remove all extents from the resync LRU * @device: DRBD device. * - * Returns 0 upon success, -EAGAIN if at least one reference count was + * Returns: %0 upon success, -EAGAIN if at least one reference count was * not zero. */ int drbd_rs_del_all(struct drbd_device *device) diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 11114a5d9e5c46..d0e41d52d6a9b5 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -3079,7 +3079,7 @@ static void raw_cmd_free(struct floppy_raw_cmd **ptr) } } -#define MAX_LEN (1UL << MAX_ORDER << PAGE_SHIFT) +#define MAX_LEN (1UL << MAX_PAGE_ORDER << PAGE_SHIFT) static int raw_cmd_copyin(int cmd, void __user *param, struct floppy_raw_cmd **rcmd) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 9f2d412fc560e1..f8145499da38c8 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -165,39 +165,37 @@ static loff_t get_loop_size(struct loop_device *lo, struct file *file) return get_size(lo->lo_offset, lo->lo_sizelimit, file); } +/* + * We support direct I/O only if lo_offset is aligned with the logical I/O size + * of backing device, and the logical block size of loop is bigger than that of + * the backing device. + */ +static bool lo_bdev_can_use_dio(struct loop_device *lo, + struct block_device *backing_bdev) +{ + unsigned short sb_bsize = bdev_logical_block_size(backing_bdev); + + if (queue_logical_block_size(lo->lo_queue) < sb_bsize) + return false; + if (lo->lo_offset & (sb_bsize - 1)) + return false; + return true; +} + static void __loop_update_dio(struct loop_device *lo, bool dio) { struct file *file = lo->lo_backing_file; - struct address_space *mapping = file->f_mapping; - struct inode *inode = mapping->host; - unsigned short sb_bsize = 0; - unsigned dio_align = 0; + struct inode *inode = file->f_mapping->host; + struct block_device *backing_bdev = NULL; bool use_dio; - if (inode->i_sb->s_bdev) { - sb_bsize = bdev_logical_block_size(inode->i_sb->s_bdev); - dio_align = sb_bsize - 1; - } + if (S_ISBLK(inode->i_mode)) + backing_bdev = I_BDEV(inode); + else if (inode->i_sb->s_bdev) + backing_bdev = inode->i_sb->s_bdev; - /* - * We support direct I/O only if lo_offset is aligned with the - * logical I/O size of backing device, and the logical block - * size of loop is bigger than the backing device's. - * - * TODO: the above condition may be loosed in the future, and - * direct I/O may be switched runtime at that time because most - * of requests in sane applications should be PAGE_SIZE aligned - */ - if (dio) { - if (queue_logical_block_size(lo->lo_queue) >= sb_bsize && - !(lo->lo_offset & dio_align) && - (file->f_mode & FMODE_CAN_ODIRECT)) - use_dio = true; - else - use_dio = false; - } else { - use_dio = false; - } + use_dio = dio && (file->f_mode & FMODE_CAN_ODIRECT) && + (!backing_bdev || lo_bdev_can_use_dio(lo, backing_bdev)); if (lo->use_dio == use_dio) return; @@ -245,9 +243,7 @@ static int lo_write_bvec(struct file *file, struct bio_vec *bvec, loff_t *ppos) iov_iter_bvec(&i, ITER_SOURCE, bvec, 1, bvec->bv_len); - file_start_write(file); bw = vfs_iter_write(file, &i, ppos, 0); - file_end_write(file); if (likely(bw == bvec->bv_len)) return 0; @@ -1303,8 +1299,6 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) loop_set_size(lo, new_size); } - loop_config_discard(lo); - /* update dio if lo_offset or transfer is changed */ __loop_update_dio(lo, lo->use_dio); @@ -2038,7 +2032,8 @@ static int loop_add(int i) } lo->lo_queue = lo->lo_disk->queue; - blk_queue_max_hw_sectors(lo->lo_queue, BLK_DEF_MAX_SECTORS); + /* random number picked from the history block max_sectors cap */ + blk_queue_max_hw_sectors(lo->lo_queue, 2560u); /* * By default, we do buffer IO, so it doesn't make sense to enable diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index b6414e1e645b76..33a8f37bb6a1f5 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -334,10 +334,8 @@ static int nbd_set_size(struct nbd_device *nbd, loff_t bytesize, if (!nbd->pid) return 0; - if (nbd->config->flags & NBD_FLAG_SEND_TRIM) { - nbd->disk->queue->limits.discard_granularity = blksize; + if (nbd->config->flags & NBD_FLAG_SEND_TRIM) blk_queue_max_discard_sectors(nbd->disk->queue, UINT_MAX); - } blk_queue_logical_block_size(nbd->disk->queue, blksize); blk_queue_physical_block_size(nbd->disk->queue, blksize); @@ -510,7 +508,7 @@ static int __sock_xmit(struct nbd_device *nbd, struct socket *sock, int send, struct iov_iter *iter, int msg_flags, int *sent) { int result; - struct msghdr msg; + struct msghdr msg = {} ; unsigned int noreclaim_flag; if (unlikely(!sock)) { @@ -526,10 +524,6 @@ static int __sock_xmit(struct nbd_device *nbd, struct socket *sock, int send, do { sock->sk->sk_allocation = GFP_NOIO | __GFP_MEMALLOC; sock->sk->sk_use_task_frag = false; - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_control = NULL; - msg.msg_controllen = 0; msg.msg_flags = msg_flags | MSG_NOSIGNAL; if (send) @@ -1357,7 +1351,6 @@ static void nbd_config_put(struct nbd_device *nbd) nbd->config = NULL; nbd->tag_set.timeout = 0; - nbd->disk->queue->limits.discard_granularity = 0; blk_queue_max_discard_sectors(nbd->disk->queue, 0); mutex_unlock(&nbd->config_lock); @@ -1850,7 +1843,6 @@ static struct nbd_device *nbd_dev_add(int index, unsigned int refs) * Tell the block layer that we are not a rotational device */ blk_queue_flag_set(QUEUE_FLAG_NONROT, disk->queue); - disk->queue->limits.discard_granularity = 0; blk_queue_max_discard_sectors(disk->queue, 0); blk_queue_max_segment_size(disk->queue, UINT_MAX); blk_queue_max_segments(disk->queue, USHRT_MAX); diff --git a/drivers/block/null_blk/main.c b/drivers/block/null_blk/main.c index 3021d58ca51c1f..36755f263e8ec0 100644 --- a/drivers/block/null_blk/main.c +++ b/drivers/block/null_blk/main.c @@ -1840,7 +1840,7 @@ static void null_del_dev(struct nullb *nullb) dev = nullb->dev; - ida_simple_remove(&nullb_indexes, nullb->index); + ida_free(&nullb_indexes, nullb->index); list_del_init(&nullb->list); @@ -1880,7 +1880,6 @@ static void null_config_discard(struct nullb *nullb) return; } - nullb->q->limits.discard_granularity = nullb->dev->blocksize; blk_queue_max_discard_sectors(nullb->q, UINT_MAX >> 9); } @@ -2175,7 +2174,7 @@ static int null_add_dev(struct nullb_device *dev) blk_queue_flag_set(QUEUE_FLAG_NONROT, nullb->q); mutex_lock(&lock); - rv = ida_simple_get(&nullb_indexes, 0, 0, GFP_KERNEL); + rv = ida_alloc(&nullb_indexes, GFP_KERNEL); if (rv < 0) { mutex_unlock(&lock); goto out_cleanup_zone; @@ -2186,10 +2185,8 @@ static int null_add_dev(struct nullb_device *dev) blk_queue_logical_block_size(nullb->q, dev->blocksize); blk_queue_physical_block_size(nullb->q, dev->blocksize); - if (!dev->max_sectors) - dev->max_sectors = queue_max_hw_sectors(nullb->q); - dev->max_sectors = min(dev->max_sectors, BLK_DEF_MAX_SECTORS); - blk_queue_max_hw_sectors(nullb->q, dev->max_sectors); + if (dev->max_sectors) + blk_queue_max_hw_sectors(nullb->q, dev->max_sectors); if (dev->virt_boundary) blk_queue_virt_boundary(nullb->q, PAGE_SIZE - 1); @@ -2289,12 +2286,6 @@ static int __init null_init(void) g_bs = PAGE_SIZE; } - if (g_max_sectors > BLK_DEF_MAX_SECTORS) { - pr_warn("invalid max sectors\n"); - pr_warn("defaults max sectors to %u\n", BLK_DEF_MAX_SECTORS); - g_max_sectors = BLK_DEF_MAX_SECTORS; - } - if (g_home_node != NUMA_NO_NODE && g_home_node >= nr_online_nodes) { pr_err("invalid home_node value\n"); g_home_node = NUMA_NO_NODE; diff --git a/drivers/block/null_blk/zoned.c b/drivers/block/null_blk/zoned.c index 55c5b48bc276fe..6f5e0994862eae 100644 --- a/drivers/block/null_blk/zoned.c +++ b/drivers/block/null_blk/zoned.c @@ -159,7 +159,7 @@ int null_register_zoned_dev(struct nullb *nullb) struct nullb_device *dev = nullb->dev; struct request_queue *q = nullb->q; - disk_set_zoned(nullb->disk, BLK_ZONED_HM); + disk_set_zoned(nullb->disk); blk_queue_flag_set(QUEUE_FLAG_ZONE_RESETALL, q); blk_queue_required_elevator_features(q, ELEVATOR_F_ZBD_SEQ_WRITE); blk_queue_chunk_sectors(q, dev->zone_size_sects); diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index a999b698b131f7..12b5d53ec85645 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -3452,14 +3452,15 @@ static bool rbd_lock_add_request(struct rbd_img_request *img_req) static void rbd_lock_del_request(struct rbd_img_request *img_req) { struct rbd_device *rbd_dev = img_req->rbd_dev; - bool need_wakeup; + bool need_wakeup = false; lockdep_assert_held(&rbd_dev->lock_rwsem); spin_lock(&rbd_dev->lock_lists_lock); - rbd_assert(!list_empty(&img_req->lock_item)); - list_del_init(&img_req->lock_item); - need_wakeup = (rbd_dev->lock_state == RBD_LOCK_STATE_RELEASING && - list_empty(&rbd_dev->running_list)); + if (!list_empty(&img_req->lock_item)) { + list_del_init(&img_req->lock_item); + need_wakeup = (rbd_dev->lock_state == RBD_LOCK_STATE_RELEASING && + list_empty(&rbd_dev->running_list)); + } spin_unlock(&rbd_dev->lock_lists_lock); if (need_wakeup) complete(&rbd_dev->releasing_wait); @@ -3842,14 +3843,19 @@ static void wake_lock_waiters(struct rbd_device *rbd_dev, int result) return; } - list_for_each_entry(img_req, &rbd_dev->acquiring_list, lock_item) { + while (!list_empty(&rbd_dev->acquiring_list)) { + img_req = list_first_entry(&rbd_dev->acquiring_list, + struct rbd_img_request, lock_item); mutex_lock(&img_req->state_mutex); rbd_assert(img_req->state == RBD_IMG_EXCLUSIVE_LOCK); + if (!result) + list_move_tail(&img_req->lock_item, + &rbd_dev->running_list); + else + list_del_init(&img_req->lock_item); rbd_img_schedule(img_req, result); mutex_unlock(&img_req->state_mutex); } - - list_splice_tail_init(&rbd_dev->acquiring_list, &rbd_dev->running_list); } static bool locker_equal(const struct ceph_locker *lhs, @@ -5326,7 +5332,7 @@ static void rbd_dev_release(struct device *dev) if (need_put) { destroy_workqueue(rbd_dev->task_wq); - ida_simple_remove(&rbd_dev_id_ida, rbd_dev->dev_id); + ida_free(&rbd_dev_id_ida, rbd_dev->dev_id); } rbd_dev_free(rbd_dev); @@ -5402,9 +5408,9 @@ static struct rbd_device *rbd_dev_create(struct rbd_client *rbdc, return NULL; /* 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), - GFP_KERNEL); + rbd_dev->dev_id = ida_alloc_max(&rbd_dev_id_ida, + minor_to_rbd_dev_id(1 << MINORBITS) - 1, + GFP_KERNEL); if (rbd_dev->dev_id < 0) goto fail_rbd_dev; @@ -5425,7 +5431,7 @@ static struct rbd_device *rbd_dev_create(struct rbd_client *rbdc, return rbd_dev; fail_dev_id: - ida_simple_remove(&rbd_dev_id_ida, rbd_dev->dev_id); + ida_free(&rbd_dev_id_ida, rbd_dev->dev_id); fail_rbd_dev: rbd_dev_free(rbd_dev); return NULL; diff --git a/drivers/block/rnbd/rnbd-clt.c b/drivers/block/rnbd/rnbd-clt.c index b0550b68645d38..4044c369d22a5f 100644 --- a/drivers/block/rnbd/rnbd-clt.c +++ b/drivers/block/rnbd/rnbd-clt.c @@ -1006,10 +1006,10 @@ static int rnbd_client_xfer_request(struct rnbd_clt_dev *dev, msg.prio = cpu_to_le16(req_get_ioprio(rq)); /* - * We only support discards with single segment for now. + * We only support discards/WRITE_ZEROES with single segment for now. * See queue limits. */ - if (req_op(rq) != REQ_OP_DISCARD) + if ((req_op(rq) != REQ_OP_DISCARD) && (req_op(rq) != REQ_OP_WRITE_ZEROES)) sg_cnt = blk_rq_map_sg(dev->queue, rq, iu->sgt.sgl); if (sg_cnt == 0) @@ -1362,6 +1362,8 @@ static void setup_request_queue(struct rnbd_clt_dev *dev, blk_queue_write_cache(dev->queue, !!(rsp->cache_policy & RNBD_WRITEBACK), !!(rsp->cache_policy & RNBD_FUA)); + blk_queue_max_write_zeroes_sectors(dev->queue, + le32_to_cpu(rsp->max_write_zeroes_sectors)); } static int rnbd_clt_setup_gen_disk(struct rnbd_clt_dev *dev, @@ -1567,8 +1569,8 @@ struct rnbd_clt_dev *rnbd_clt_map_device(const char *sessname, dev = init_dev(sess, access_mode, pathname, nr_poll_queues); if (IS_ERR(dev)) { - pr_err("map_device: failed to map device '%s' from session %s, can't initialize device, err: %ld\n", - pathname, sess->sessname, PTR_ERR(dev)); + pr_err("map_device: failed to map device '%s' from session %s, can't initialize device, err: %pe\n", + pathname, sess->sessname, dev); ret = PTR_ERR(dev); goto put_sess; } @@ -1626,10 +1628,11 @@ struct rnbd_clt_dev *rnbd_clt_map_device(const char *sessname, } rnbd_clt_info(dev, - "map_device: Device mapped as %s (nsectors: %llu, logical_block_size: %d, physical_block_size: %d, max_discard_sectors: %d, discard_granularity: %d, discard_alignment: %d, secure_discard: %d, max_segments: %d, max_hw_sectors: %d, wc: %d, fua: %d)\n", + "map_device: Device mapped as %s (nsectors: %llu, logical_block_size: %d, physical_block_size: %d, max_write_zeroes_sectors: %d, max_discard_sectors: %d, discard_granularity: %d, discard_alignment: %d, secure_discard: %d, max_segments: %d, max_hw_sectors: %d, wc: %d, fua: %d)\n", dev->gd->disk_name, le64_to_cpu(rsp->nsectors), le16_to_cpu(rsp->logical_block_size), le16_to_cpu(rsp->physical_block_size), + le32_to_cpu(rsp->max_write_zeroes_sectors), le32_to_cpu(rsp->max_discard_sectors), le32_to_cpu(rsp->discard_granularity), le32_to_cpu(rsp->discard_alignment), diff --git a/drivers/block/rnbd/rnbd-proto.h b/drivers/block/rnbd/rnbd-proto.h index e32f8f2c868a7b..f35be51d213c3f 100644 --- a/drivers/block/rnbd/rnbd-proto.h +++ b/drivers/block/rnbd/rnbd-proto.h @@ -128,7 +128,7 @@ enum rnbd_cache_policy { * @device_id: device_id on server side to identify the device * @nsectors: number of sectors in the usual 512b unit * @max_hw_sectors: max hardware sectors in the usual 512b unit - * @max_write_same_sectors: max sectors for WRITE SAME in the 512b unit + * @max_write_zeroes_sectors: max sectors for WRITE ZEROES in the 512b unit * @max_discard_sectors: max. sectors that can be discarded at once in 512b * unit. * @discard_granularity: size of the internal discard allocation unit in bytes @@ -145,7 +145,7 @@ struct rnbd_msg_open_rsp { __le32 device_id; __le64 nsectors; __le32 max_hw_sectors; - __le32 max_write_same_sectors; + __le32 max_write_zeroes_sectors; __le32 max_discard_sectors; __le32 discard_granularity; __le32 discard_alignment; @@ -186,7 +186,7 @@ struct rnbd_msg_io { * @RNBD_OP_FLUSH: flush the volatile write cache * @RNBD_OP_DISCARD: discard sectors * @RNBD_OP_SECURE_ERASE: securely erase sectors - * @RNBD_OP_WRITE_SAME: write the same sectors many times + * @RNBD_OP_WRITE_ZEROES: write zeroes sectors * @RNBD_F_SYNC: request is sync (sync write or read) * @RNBD_F_FUA: forced unit access @@ -199,7 +199,7 @@ enum rnbd_io_flags { RNBD_OP_FLUSH = 2, RNBD_OP_DISCARD = 3, RNBD_OP_SECURE_ERASE = 4, - RNBD_OP_WRITE_SAME = 5, + RNBD_OP_WRITE_ZEROES = 5, /* Flags */ RNBD_F_SYNC = 1<<(RNBD_OP_BITS + 0), @@ -236,6 +236,9 @@ static inline blk_opf_t rnbd_to_bio_flags(u32 rnbd_opf) case RNBD_OP_SECURE_ERASE: bio_opf = REQ_OP_SECURE_ERASE; break; + case RNBD_OP_WRITE_ZEROES: + bio_opf = REQ_OP_WRITE_ZEROES; + break; default: WARN(1, "Unknown RNBD type: %d (flags %d)\n", rnbd_op(rnbd_opf), rnbd_opf); @@ -268,6 +271,9 @@ static inline u32 rq_to_rnbd_flags(struct request *rq) case REQ_OP_SECURE_ERASE: rnbd_opf = RNBD_OP_SECURE_ERASE; break; + case REQ_OP_WRITE_ZEROES: + rnbd_opf = RNBD_OP_WRITE_ZEROES; + break; case REQ_OP_FLUSH: rnbd_opf = RNBD_OP_FLUSH; break; diff --git a/drivers/block/rnbd/rnbd-srv.c b/drivers/block/rnbd/rnbd-srv.c index 65de51f3dfd9a6..3a0d5dcec6f255 100644 --- a/drivers/block/rnbd/rnbd-srv.c +++ b/drivers/block/rnbd/rnbd-srv.c @@ -136,8 +136,8 @@ static int process_rdma(struct rnbd_srv_session *srv_sess, sess_dev = rnbd_get_sess_dev(dev_id, srv_sess); if (IS_ERR(sess_dev)) { - pr_err_ratelimited("Got I/O request on session %s for unknown device id %d\n", - srv_sess->sessname, dev_id); + pr_err_ratelimited("Got I/O request on session %s for unknown device id %d: %pe\n", + srv_sess->sessname, dev_id, sess_dev); err = -ENOTCONN; goto err; } @@ -544,7 +544,8 @@ static void rnbd_srv_fill_msg_open_rsp(struct rnbd_msg_open_rsp *rsp, rsp->max_segments = cpu_to_le16(bdev_max_segments(bdev)); rsp->max_hw_sectors = cpu_to_le32(queue_max_hw_sectors(bdev_get_queue(bdev))); - rsp->max_write_same_sectors = 0; + rsp->max_write_zeroes_sectors = + cpu_to_le32(bdev_write_zeroes_sectors(bdev)); rsp->max_discard_sectors = cpu_to_le32(bdev_max_discard_sectors(bdev)); rsp->discard_granularity = cpu_to_le32(bdev_discard_granularity(bdev)); rsp->discard_alignment = cpu_to_le32(bdev_discard_alignment(bdev)); @@ -585,6 +586,7 @@ static char *rnbd_srv_get_full_path(struct rnbd_srv_session *srv_sess, { char *full_path; char *a, *b; + int len; full_path = kmalloc(PATH_MAX, GFP_KERNEL); if (!full_path) @@ -596,19 +598,19 @@ static char *rnbd_srv_get_full_path(struct rnbd_srv_session *srv_sess, */ a = strnstr(dev_search_path, "%SESSNAME%", sizeof(dev_search_path)); if (a) { - int len = a - dev_search_path; + len = a - dev_search_path; len = snprintf(full_path, PATH_MAX, "%.*s/%s/%s", len, dev_search_path, srv_sess->sessname, dev_name); - if (len >= PATH_MAX) { - pr_err("Too long path: %s, %s, %s\n", - dev_search_path, srv_sess->sessname, dev_name); - kfree(full_path); - return ERR_PTR(-EINVAL); - } } else { - snprintf(full_path, PATH_MAX, "%s/%s", - dev_search_path, dev_name); + len = snprintf(full_path, PATH_MAX, "%s/%s", + dev_search_path, dev_name); + } + if (len >= PATH_MAX) { + pr_err("Too long path: %s, %s, %s\n", + dev_search_path, srv_sess->sessname, dev_name); + kfree(full_path); + return ERR_PTR(-EINVAL); } /* eliminitate duplicated slashes */ @@ -709,24 +711,24 @@ static int process_msg_open(struct rnbd_srv_session *srv_sess, full_path = rnbd_srv_get_full_path(srv_sess, open_msg->dev_name); if (IS_ERR(full_path)) { ret = PTR_ERR(full_path); - pr_err("Opening device '%s' for client %s failed, failed to get device full path, err: %d\n", - open_msg->dev_name, srv_sess->sessname, ret); + pr_err("Opening device '%s' for client %s failed, failed to get device full path, err: %pe\n", + open_msg->dev_name, srv_sess->sessname, full_path); goto reject; } bdev_handle = bdev_open_by_path(full_path, open_flags, NULL, NULL); if (IS_ERR(bdev_handle)) { ret = PTR_ERR(bdev_handle); - pr_err("Opening device '%s' on session %s failed, failed to open the block device, err: %d\n", - full_path, srv_sess->sessname, ret); + pr_err("Opening device '%s' on session %s failed, failed to open the block device, err: %pe\n", + full_path, srv_sess->sessname, bdev_handle); goto free_path; } srv_dev = rnbd_srv_get_or_create_srv_dev(bdev_handle->bdev, srv_sess, open_msg->access_mode); if (IS_ERR(srv_dev)) { - pr_err("Opening device '%s' on session %s failed, creating srv_dev failed, err: %ld\n", - full_path, srv_sess->sessname, PTR_ERR(srv_dev)); + pr_err("Opening device '%s' on session %s failed, creating srv_dev failed, err: %pe\n", + full_path, srv_sess->sessname, srv_dev); ret = PTR_ERR(srv_dev); goto blkdev_put; } @@ -736,8 +738,8 @@ static int process_msg_open(struct rnbd_srv_session *srv_sess, open_msg->access_mode == RNBD_ACCESS_RO, srv_dev); if (IS_ERR(srv_sess_dev)) { - pr_err("Opening device '%s' on session %s failed, creating sess_dev failed, err: %ld\n", - full_path, srv_sess->sessname, PTR_ERR(srv_sess_dev)); + pr_err("Opening device '%s' on session %s failed, creating sess_dev failed, err: %pe\n", + full_path, srv_sess->sessname, srv_sess_dev); ret = PTR_ERR(srv_sess_dev); goto srv_dev_put; } @@ -818,7 +820,7 @@ static int __init rnbd_srv_init_module(void) }; rtrs_ctx = rtrs_srv_open(&rtrs_ops, port_nr); if (IS_ERR(rtrs_ctx)) { - pr_err("rtrs_srv_open(), err: %d\n", err); + pr_err("rtrs_srv_open(), err: %pe\n", rtrs_ctx); return PTR_ERR(rtrs_ctx); } diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c index 83600b45e12a28..1dfb2e77898ba6 100644 --- a/drivers/block/ublk_drv.c +++ b/drivers/block/ublk_drv.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include #include @@ -250,7 +250,7 @@ static int ublk_dev_param_zoned_apply(struct ublk_device *ub) { const struct ublk_param_zoned *p = &ub->params.zoned; - disk_set_zoned(ub->ub_disk, BLK_ZONED_HM); + disk_set_zoned(ub->ub_disk); blk_queue_flag_set(QUEUE_FLAG_ZONE_RESETALL, ub->ub_disk->queue); blk_queue_required_elevator_features(ub->ub_disk->queue, ELEVATOR_F_ZBD_SEQ_WRITE); @@ -893,12 +893,9 @@ static int ublk_map_io(const struct ublk_queue *ubq, const struct request *req, */ if (ublk_need_map_req(req)) { struct iov_iter iter; - struct iovec iov; const int dir = ITER_DEST; - import_single_range(dir, u64_to_user_ptr(io->addr), rq_bytes, - &iov, &iter); - + import_ubuf(dir, u64_to_user_ptr(io->addr), rq_bytes, &iter); return ublk_copy_user_pages(req, 0, &iter, dir); } return rq_bytes; @@ -915,13 +912,11 @@ static int ublk_unmap_io(const struct ublk_queue *ubq, if (ublk_need_unmap_req(req)) { struct iov_iter iter; - struct iovec iov; const int dir = ITER_SOURCE; WARN_ON_ONCE(io->res > rq_bytes); - import_single_range(dir, u64_to_user_ptr(io->addr), io->res, - &iov, &iter); + import_ubuf(dir, u64_to_user_ptr(io->addr), io->res, &iter); return ublk_copy_user_pages(req, 0, &iter, dir); } return rq_bytes; diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 47556d8ccc320f..5bf98fd6a651a5 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -367,8 +367,6 @@ static void virtblk_done(struct virtqueue *vq) 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. */ @@ -722,52 +720,15 @@ fail_report: return ret; } -static void virtblk_revalidate_zones(struct virtio_blk *vblk) -{ - u8 model; - - virtio_cread(vblk->vdev, struct virtio_blk_config, - zoned.model, &model); - switch (model) { - default: - dev_err(&vblk->vdev->dev, "unknown zone model %d\n", model); - fallthrough; - case VIRTIO_BLK_Z_NONE: - case VIRTIO_BLK_Z_HA: - disk_set_zoned(vblk->disk, BLK_ZONED_NONE); - return; - case VIRTIO_BLK_Z_HM: - WARN_ON_ONCE(!vblk->zone_sectors); - 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, wg; - u8 model; - - virtio_cread(vdev, struct virtio_blk_config, - zoned.model, &model); - - switch (model) { - case VIRTIO_BLK_Z_NONE: - case VIRTIO_BLK_Z_HA: - /* Present the host-aware device as non-zoned */ - return 0; - case VIRTIO_BLK_Z_HM: - break; - 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); + disk_set_zoned(vblk->disk); blk_queue_flag_set(QUEUE_FLAG_ZONE_RESETALL, q); virtio_cread(vdev, struct virtio_blk_config, @@ -839,23 +800,12 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev, */ #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) { - u8 model; - - virtio_cread(vdev, struct virtio_blk_config, zoned.model, &model); - if (model == VIRTIO_BLK_Z_HM) { - dev_err(&vdev->dev, - "virtio_blk: zoned devices are not supported"); - return -EOPNOTSUPP; - } - - return 0; + dev_err(&vdev->dev, + "virtio_blk: zoned devices are not supported"); + return -EOPNOTSUPP; } #endif /* CONFIG_BLK_DEV_ZONED */ @@ -1005,7 +955,6 @@ 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); } @@ -1570,9 +1519,26 @@ static int virtblk_probe(struct virtio_device *vdev) * placed after the virtio_device_ready() call above. */ if (virtio_has_feature(vdev, VIRTIO_BLK_F_ZONED)) { - err = virtblk_probe_zoned_device(vdev, vblk, q); - if (err) + u8 model; + + virtio_cread(vdev, struct virtio_blk_config, zoned.model, + &model); + switch (model) { + case VIRTIO_BLK_Z_NONE: + case VIRTIO_BLK_Z_HA: + /* Present the host-aware device as non-zoned */ + break; + case VIRTIO_BLK_Z_HM: + err = virtblk_probe_zoned_device(vdev, vblk, q); + if (err) + goto out_cleanup_disk; + break; + default: + dev_err(&vdev->dev, "unsupported zone model %d\n", + model); + err = -EINVAL; goto out_cleanup_disk; + } } err = device_add_disk(&vdev->dev, vblk->disk, virtblk_attr_groups); diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h index 5ff50e76cee573..1432c83183d098 100644 --- a/drivers/block/xen-blkback/common.h +++ b/drivers/block/xen-blkback/common.h @@ -132,7 +132,7 @@ struct blkif_x86_32_request { struct blkif_x86_64_request_rw { uint8_t nr_segments; /* number of segments */ blkif_vdev_t handle; /* only for read/write requests */ - uint32_t _pad1; /* offsetof(blkif_reqest..,u.rw.id)==8 */ + uint32_t _pad1; /* offsetof(blkif_request..,u.rw.id)==8 */ uint64_t id; blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */ struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST]; diff --git a/drivers/block/zram/Kconfig b/drivers/block/zram/Kconfig index 0386b7da02aa3b..7b29cce60ab2f2 100644 --- a/drivers/block/zram/Kconfig +++ b/drivers/block/zram/Kconfig @@ -59,8 +59,8 @@ config ZRAM_WRITEBACK bool "Write back incompressible or idle page to backing device" depends on ZRAM help - With incompressible page, there is no memory saving to keep it - in memory. Instead, write it out to backing device. + This lets zram entries (incompressible or idle pages) be written + back to a backing device, helping save memory. For this feature, admin should set up backing device via /sys/block/zramX/backing_dev. @@ -69,9 +69,18 @@ config ZRAM_WRITEBACK See Documentation/admin-guide/blockdev/zram.rst for more information. +config ZRAM_TRACK_ENTRY_ACTIME + bool "Track access time of zram entries" + depends on ZRAM + help + With this feature zram tracks access time of every stored + entry (page), which can be used for a more fine grained IDLE + pages writeback. + config ZRAM_MEMORY_TRACKING bool "Track zRam block status" depends on ZRAM && DEBUG_FS + select ZRAM_TRACK_ENTRY_ACTIME help With this feature, admin can track the state of allocated blocks of zRAM. Admin could see the information via @@ -86,4 +95,4 @@ config ZRAM_MULTI_COMP This will enable multi-compression streams, so that ZRAM can re-compress pages using a potentially slower but more effective compression algorithm. Note, that IDLE page recompression - requires ZRAM_MEMORY_TRACKING. + requires ZRAM_TRACK_ENTRY_ACTIME. diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index d77d3664ca0805..6772e0c654fa7f 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -174,6 +174,14 @@ static inline u32 zram_get_priority(struct zram *zram, u32 index) return prio & ZRAM_COMP_PRIORITY_MASK; } +static void zram_accessed(struct zram *zram, u32 index) +{ + zram_clear_flag(zram, index, ZRAM_IDLE); +#ifdef CONFIG_ZRAM_TRACK_ENTRY_ACTIME + zram->table[index].ac_time = ktime_get_boottime(); +#endif +} + static inline void update_used_max(struct zram *zram, const unsigned long pages) { @@ -293,8 +301,9 @@ static void mark_idle(struct zram *zram, ktime_t cutoff) zram_slot_lock(zram, index); if (zram_allocated(zram, index) && !zram_test_flag(zram, index, ZRAM_UNDER_WB)) { -#ifdef CONFIG_ZRAM_MEMORY_TRACKING - is_idle = !cutoff || ktime_after(cutoff, zram->table[index].ac_time); +#ifdef CONFIG_ZRAM_TRACK_ENTRY_ACTIME + is_idle = !cutoff || ktime_after(cutoff, + zram->table[index].ac_time); #endif if (is_idle) zram_set_flag(zram, index, ZRAM_IDLE); @@ -317,7 +326,7 @@ static ssize_t idle_store(struct device *dev, */ u64 age_sec; - if (IS_ENABLED(CONFIG_ZRAM_MEMORY_TRACKING) && !kstrtoull(buf, 0, &age_sec)) + if (IS_ENABLED(CONFIG_ZRAM_TRACK_ENTRY_ACTIME) && !kstrtoull(buf, 0, &age_sec)) cutoff_time = ktime_sub(ktime_get_boottime(), ns_to_ktime(age_sec * NSEC_PER_SEC)); else @@ -841,12 +850,6 @@ static void zram_debugfs_destroy(void) debugfs_remove_recursive(zram_debugfs_root); } -static void zram_accessed(struct zram *zram, u32 index) -{ - zram_clear_flag(zram, index, ZRAM_IDLE); - zram->table[index].ac_time = ktime_get_boottime(); -} - static ssize_t read_block_state(struct file *file, char __user *buf, size_t count, loff_t *ppos) { @@ -930,10 +933,6 @@ static void zram_debugfs_unregister(struct zram *zram) #else static void zram_debugfs_create(void) {}; static void zram_debugfs_destroy(void) {}; -static void zram_accessed(struct zram *zram, u32 index) -{ - zram_clear_flag(zram, index, ZRAM_IDLE); -}; static void zram_debugfs_register(struct zram *zram) {}; static void zram_debugfs_unregister(struct zram *zram) {}; #endif @@ -1254,7 +1253,7 @@ static void zram_free_page(struct zram *zram, size_t index) { unsigned long handle; -#ifdef CONFIG_ZRAM_MEMORY_TRACKING +#ifdef CONFIG_ZRAM_TRACK_ENTRY_ACTIME zram->table[index].ac_time = 0; #endif if (zram_test_flag(zram, index, ZRAM_IDLE)) @@ -1322,9 +1321,9 @@ static int zram_read_from_zspool(struct zram *zram, struct page *page, void *mem; value = handle ? zram_get_element(zram, index) : 0; - mem = kmap_atomic(page); + mem = kmap_local_page(page); zram_fill_page(mem, PAGE_SIZE, value); - kunmap_atomic(mem); + kunmap_local(mem); return 0; } @@ -1337,14 +1336,14 @@ static int zram_read_from_zspool(struct zram *zram, struct page *page, src = zs_map_object(zram->mem_pool, handle, ZS_MM_RO); if (size == PAGE_SIZE) { - dst = kmap_atomic(page); + dst = kmap_local_page(page); memcpy(dst, src, PAGE_SIZE); - kunmap_atomic(dst); + kunmap_local(dst); ret = 0; } else { - dst = kmap_atomic(page); + dst = kmap_local_page(page); ret = zcomp_decompress(zstrm, src, size, dst); - kunmap_atomic(dst); + kunmap_local(dst); zcomp_stream_put(zram->comps[prio]); } zs_unmap_object(zram->mem_pool, handle); @@ -1417,21 +1416,21 @@ static int zram_write_page(struct zram *zram, struct page *page, u32 index) unsigned long element = 0; enum zram_pageflags flags = 0; - mem = kmap_atomic(page); + mem = kmap_local_page(page); if (page_same_filled(mem, &element)) { - kunmap_atomic(mem); + kunmap_local(mem); /* Free memory associated with this sector now. */ flags = ZRAM_SAME; atomic64_inc(&zram->stats.same_pages); goto out; } - kunmap_atomic(mem); + kunmap_local(mem); compress_again: zstrm = zcomp_stream_get(zram->comps[ZRAM_PRIMARY_COMP]); - src = kmap_atomic(page); + src = kmap_local_page(page); ret = zcomp_compress(zstrm, src, &comp_len); - kunmap_atomic(src); + kunmap_local(src); if (unlikely(ret)) { zcomp_stream_put(zram->comps[ZRAM_PRIMARY_COMP]); @@ -1495,10 +1494,10 @@ compress_again: src = zstrm->buffer; if (comp_len == PAGE_SIZE) - src = kmap_atomic(page); + src = kmap_local_page(page); memcpy(dst, src, comp_len); if (comp_len == PAGE_SIZE) - kunmap_atomic(src); + kunmap_local(src); zcomp_stream_put(zram->comps[ZRAM_PRIMARY_COMP]); zs_unmap_object(zram->mem_pool, handle); @@ -1615,9 +1614,9 @@ static int zram_recompress(struct zram *zram, u32 index, struct page *page, num_recomps++; zstrm = zcomp_stream_get(zram->comps[prio]); - src = kmap_atomic(page); + src = kmap_local_page(page); ret = zcomp_compress(zstrm, src, &comp_len_new); - kunmap_atomic(src); + kunmap_local(src); if (ret) { zcomp_stream_put(zram->comps[prio]); @@ -2227,7 +2226,6 @@ static int zram_add(void) ZRAM_LOGICAL_BLOCK_SIZE); blk_queue_io_min(zram->disk->queue, PAGE_SIZE); blk_queue_io_opt(zram->disk->queue, PAGE_SIZE); - zram->disk->queue->limits.discard_granularity = PAGE_SIZE; blk_queue_max_discard_sectors(zram->disk->queue, UINT_MAX); /* diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h index d090753f97bec4..3b94d12f41b406 100644 --- a/drivers/block/zram/zram_drv.h +++ b/drivers/block/zram/zram_drv.h @@ -69,7 +69,7 @@ struct zram_table_entry { unsigned long element; }; unsigned long flags; -#ifdef CONFIG_ZRAM_MEMORY_TRACKING +#ifdef CONFIG_ZRAM_TRACK_ENTRY_ACTIME ktime_t ac_time; #endif }; diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index 2462796a512a5f..cdc5c08824a0ad 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -535,6 +535,8 @@ static int btintel_version_info_tlv(struct hci_dev *hdev, bt_dev_info(hdev, "%s timestamp %u.%u buildtype %u build %u", variant, 2000 + (version->timestamp >> 8), version->timestamp & 0xff, version->build_type, version->build_num); + if (version->img_type == 0x03) + bt_dev_info(hdev, "Firmware SHA1: 0x%8.8x", version->git_sha1); return 0; } @@ -630,6 +632,9 @@ static int btintel_parse_version_tlv(struct hci_dev *hdev, memcpy(&version->otp_bd_addr, tlv->val, sizeof(bdaddr_t)); break; + case INTEL_TLV_GIT_SHA1: + version->git_sha1 = get_unaligned_le32(tlv->val); + break; default: /* Ignore rest of information */ break; diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h index 3a2d5b4219ddb5..d19fcdb9ff0b63 100644 --- a/drivers/bluetooth/btintel.h +++ b/drivers/bluetooth/btintel.h @@ -41,7 +41,8 @@ enum { INTEL_TLV_LIMITED_CCE, INTEL_TLV_SBE_TYPE, INTEL_TLV_OTP_BDADDR, - INTEL_TLV_UNLOCKED_STATE + INTEL_TLV_UNLOCKED_STATE, + INTEL_TLV_GIT_SHA1 }; struct intel_tlv { @@ -69,6 +70,7 @@ struct intel_version_tlv { u8 min_fw_build_yy; u8 limited_cce; u8 sbe_type; + u32 git_sha1; bdaddr_t otp_bd_addr; }; diff --git a/drivers/bluetooth/btmtkuart.c b/drivers/bluetooth/btmtkuart.c index 935feab815d973..3c84fcbda01aa3 100644 --- a/drivers/bluetooth/btmtkuart.c +++ b/drivers/bluetooth/btmtkuart.c @@ -336,7 +336,7 @@ mtk_stp_split(struct btmtkuart_dev *bdev, const unsigned char *data, int count, return data; } -static int btmtkuart_recv(struct hci_dev *hdev, const u8 *data, size_t count) +static void btmtkuart_recv(struct hci_dev *hdev, const u8 *data, size_t count) { struct btmtkuart_dev *bdev = hci_get_drvdata(hdev); const unsigned char *p_left = data, *p_h4; @@ -375,25 +375,20 @@ static int btmtkuart_recv(struct hci_dev *hdev, const u8 *data, size_t count) bt_dev_err(bdev->hdev, "Frame reassembly failed (%d)", err); bdev->rx_skb = NULL; - return err; + return; } sz_left -= sz_h4; p_left += sz_h4; } - - return 0; } -static int btmtkuart_receive_buf(struct serdev_device *serdev, const u8 *data, - size_t count) +static ssize_t btmtkuart_receive_buf(struct serdev_device *serdev, + const u8 *data, size_t count) { struct btmtkuart_dev *bdev = serdev_device_get_drvdata(serdev); - int err; - err = btmtkuart_recv(bdev->hdev, data, count); - if (err < 0) - return err; + btmtkuart_recv(bdev->hdev, data, count); bdev->hdev->stat.byte_rx += count; diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c index b7e66b7ac57022..1d592ac413d1ff 100644 --- a/drivers/bluetooth/btnxpuart.c +++ b/drivers/bluetooth/btnxpuart.c @@ -1264,8 +1264,8 @@ static const struct h4_recv_pkt nxp_recv_pkts[] = { { NXP_RECV_FW_REQ_V3, .recv = nxp_recv_fw_req_v3 }, }; -static int btnxpuart_receive_buf(struct serdev_device *serdev, const u8 *data, - size_t count) +static ssize_t btnxpuart_receive_buf(struct serdev_device *serdev, + const u8 *data, size_t count) { struct btnxpuart_dev *nxpdev = serdev_device_get_drvdata(serdev); @@ -1276,11 +1276,9 @@ static int btnxpuart_receive_buf(struct serdev_device *serdev, const u8 *data, if (IS_ERR(nxpdev->rx_skb)) { int err = PTR_ERR(nxpdev->rx_skb); /* Safe to ignore out-of-sync bootloader signatures */ - if (is_fw_downloading(nxpdev)) - return count; - bt_dev_err(nxpdev->hdev, "Frame reassembly failed (%d)", err); - nxpdev->rx_skb = NULL; - return err; + if (!is_fw_downloading(nxpdev)) + bt_dev_err(nxpdev->hdev, "Frame reassembly failed (%d)", err); + return count; } if (!is_fw_downloading(nxpdev)) nxpdev->hdev->stat.byte_rx += count; diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index b8e9de887b5de4..d31edad7a05607 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -550,6 +550,8 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3571), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x13d3, 0x3572), .driver_info = BTUSB_REALTEK | + BTUSB_WIDEBAND_SPEECH }, /* Realtek Bluetooth devices */ { USB_VENDOR_AND_INTERFACE_INFO(0x0bda, 0xe0, 0x01, 0x01), @@ -4629,6 +4631,10 @@ static int btusb_suspend(struct usb_interface *intf, pm_message_t message) BT_DBG("intf %p", intf); + /* Don't suspend if there are connections */ + if (hci_conn_count(data->hdev)) + return -EBUSY; + if (data->suspend_count++) return 0; @@ -4790,10 +4796,8 @@ static struct usb_driver btusb_driver = { .disable_hub_initiated_lpm = 1, #ifdef CONFIG_DEV_COREDUMP - .drvwrap = { - .driver = { - .coredump = btusb_coredump, - }, + .driver = { + .coredump = btusb_coredump, }, #endif }; diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index 067e248e359939..94b8c406f0c0ed 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -1815,6 +1815,24 @@ static void hci_coredump_qca(struct hci_dev *hdev) kfree_skb(skb); } +static int qca_get_data_path_id(struct hci_dev *hdev, __u8 *data_path_id) +{ + /* QCA uses 1 as non-HCI data path id for HFP */ + *data_path_id = 1; + return 0; +} + +static int qca_configure_hfp_offload(struct hci_dev *hdev) +{ + bt_dev_info(hdev, "HFP non-HCI data transport is supported"); + hdev->get_data_path_id = qca_get_data_path_id; + /* Do not need to send HCI_Configure_Data_Path to configure non-HCI + * data transport path for QCA controllers, so set below field as NULL. + */ + hdev->get_codec_config_data = NULL; + return 0; +} + static int qca_setup(struct hci_uart *hu) { struct hci_dev *hdev = hu->hdev; @@ -1969,6 +1987,10 @@ out: hu->hdev->set_bdaddr = qca_set_bdaddr_rome; else hu->hdev->set_bdaddr = qca_set_bdaddr; + + if (soc_type == QCA_QCA2066) + qca_configure_hfp_offload(hdev); + qca->fw_version = le16_to_cpu(ver.patch_ver); qca->controller_id = le16_to_cpu(ver.rom_ver); hci_devcd_register(hdev, hci_coredump_qca, qca_dmp_hdr, NULL); @@ -2039,6 +2061,7 @@ static const struct qca_device_data qca_soc_data_wcn3998 __maybe_unused = { static const struct qca_device_data qca_soc_data_qca2066 __maybe_unused = { .soc_type = QCA_QCA2066, .num_vregs = 0, + .capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES, }; static const struct qca_device_data qca_soc_data_qca6390 __maybe_unused = { diff --git a/drivers/bluetooth/hci_serdev.c b/drivers/bluetooth/hci_serdev.c index f16fd79bc02b8a..39c8b567da3c0e 100644 --- a/drivers/bluetooth/hci_serdev.c +++ b/drivers/bluetooth/hci_serdev.c @@ -271,8 +271,8 @@ static void hci_uart_write_wakeup(struct serdev_device *serdev) * * Return: number of processed bytes */ -static int hci_uart_receive_buf(struct serdev_device *serdev, const u8 *data, - size_t count) +static ssize_t hci_uart_receive_buf(struct serdev_device *serdev, + const u8 *data, size_t count) { struct hci_uart *hu = serdev_device_get_drvdata(serdev); diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index 2f6d5002e43d58..78b96cd63de9fb 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -1167,14 +1167,11 @@ error_cleanup_mc_io: * fsl_mc_bus_remove - callback invoked when the root MC bus is being * removed */ -static int fsl_mc_bus_remove(struct platform_device *pdev) +static void fsl_mc_bus_remove(struct platform_device *pdev) { struct fsl_mc *mc = platform_get_drvdata(pdev); struct fsl_mc_io *mc_io; - if (!fsl_mc_is_root_dprc(&mc->root_mc_bus_dev->dev)) - return -EINVAL; - mc_io = mc->root_mc_bus_dev->mc_io; fsl_mc_device_remove(mc->root_mc_bus_dev); fsl_destroy_mc_io(mc_io); @@ -1190,13 +1187,6 @@ static int fsl_mc_bus_remove(struct platform_device *pdev) (GCR1_P1_STOP | GCR1_P2_STOP), mc->fsl_mc_regs + FSL_MC_GCR1); } - - return 0; -} - -static void fsl_mc_bus_shutdown(struct platform_device *pdev) -{ - fsl_mc_bus_remove(pdev); } static const struct of_device_id fsl_mc_bus_match_table[] = { @@ -1220,8 +1210,8 @@ static struct platform_driver fsl_mc_bus_driver = { .acpi_match_table = fsl_mc_bus_acpi_match_table, }, .probe = fsl_mc_bus_probe, - .remove = fsl_mc_bus_remove, - .shutdown = fsl_mc_bus_shutdown, + .remove_new = fsl_mc_bus_remove, + .shutdown = fsl_mc_bus_remove, }; static int fsl_mc_bus_notifier(struct notifier_block *nb, diff --git a/drivers/bus/hisi_lpc.c b/drivers/bus/hisi_lpc.c index cdc4e38c113ef6..09340adbacc2cc 100644 --- a/drivers/bus/hisi_lpc.c +++ b/drivers/bus/hisi_lpc.c @@ -657,7 +657,7 @@ static int hisi_lpc_probe(struct platform_device *pdev) return ret; } -static int hisi_lpc_remove(struct platform_device *pdev) +static void hisi_lpc_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct hisi_lpc_dev *lpcdev = dev_get_drvdata(dev); @@ -669,8 +669,6 @@ static int hisi_lpc_remove(struct platform_device *pdev) of_platform_depopulate(dev); logic_pio_unregister_range(range); - - return 0; } static const struct of_device_id hisi_lpc_of_match[] = { @@ -691,6 +689,6 @@ static struct platform_driver hisi_lpc_driver = { .acpi_match_table = hisi_lpc_acpi_match, }, .probe = hisi_lpc_probe, - .remove = hisi_lpc_remove, + .remove_new = hisi_lpc_remove, }; builtin_platform_driver(hisi_lpc_driver); diff --git a/drivers/bus/imx-weim.c b/drivers/bus/imx-weim.c index 42c9386a7b423f..6b5da73c854176 100644 --- a/drivers/bus/imx-weim.c +++ b/drivers/bus/imx-weim.c @@ -11,7 +11,10 @@ #include #include #include -#include +#include +#include +#include +#include #include #include #include @@ -202,9 +205,7 @@ static int weim_timing_setup(struct device *dev, struct device_node *np, static int weim_parse_dt(struct platform_device *pdev) { - const struct of_device_id *of_id = of_match_device(weim_id_table, - &pdev->dev); - const struct imx_weim_devtype *devtype = of_id->data; + const struct imx_weim_devtype *devtype = device_get_match_data(&pdev->dev); int ret = 0, have_child = 0; struct device_node *child; struct weim_priv *priv; diff --git a/drivers/bus/mhi/ep/internal.h b/drivers/bus/mhi/ep/internal.h index a2125fa5fe2f97..577965f95fda9e 100644 --- a/drivers/bus/mhi/ep/internal.h +++ b/drivers/bus/mhi/ep/internal.h @@ -126,6 +126,7 @@ struct mhi_ep_ring { union mhi_ep_ring_ctx *ring_ctx; struct mhi_ring_element *ring_cache; enum mhi_ep_ring_type type; + struct delayed_work intmodt_work; u64 rbase; size_t rd_offset; size_t wr_offset; @@ -135,7 +136,9 @@ struct mhi_ep_ring { u32 ch_id; u32 er_index; u32 irq_vector; + u32 intmodt; bool started; + bool irq_pending; }; struct mhi_ep_cmd { @@ -159,6 +162,7 @@ struct mhi_ep_chan { void (*xfer_cb)(struct mhi_ep_device *mhi_dev, struct mhi_result *result); enum mhi_ch_state state; enum dma_data_direction dir; + size_t rd_offset; u64 tre_loc; u32 tre_size; u32 tre_bytes_left; diff --git a/drivers/bus/mhi/ep/main.c b/drivers/bus/mhi/ep/main.c index 600881808982aa..65fc1d738bec26 100644 --- a/drivers/bus/mhi/ep/main.c +++ b/drivers/bus/mhi/ep/main.c @@ -54,11 +54,27 @@ static int mhi_ep_send_event(struct mhi_ep_cntrl *mhi_cntrl, u32 ring_idx, mutex_unlock(&mhi_cntrl->event_lock); /* - * Raise IRQ to host only if the BEI flag is not set in TRE. Host might - * set this flag for interrupt moderation as per MHI protocol. + * As per the MHI specification, section 4.3, Interrupt moderation: + * + * 1. If BEI flag is not set, cancel any pending intmodt work if started + * for the event ring and raise IRQ immediately. + * + * 2. If both BEI and intmodt are set, and if no IRQ is pending for the + * same event ring, start the IRQ delayed work as per the value of + * intmodt. If previous IRQ is pending, then do nothing as the pending + * IRQ is enough for the host to process the current event ring element. + * + * 3. If BEI is set and intmodt is not set, no need to raise IRQ. */ - if (!bei) + if (!bei) { + if (READ_ONCE(ring->irq_pending)) + cancel_delayed_work(&ring->intmodt_work); + mhi_cntrl->raise_irq(mhi_cntrl, ring->irq_vector); + } else if (ring->intmodt && !READ_ONCE(ring->irq_pending)) { + WRITE_ONCE(ring->irq_pending, true); + schedule_delayed_work(&ring->intmodt_work, msecs_to_jiffies(ring->intmodt)); + } return 0; @@ -71,45 +87,77 @@ err_unlock: static int mhi_ep_send_completion_event(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_ring *ring, struct mhi_ring_element *tre, u32 len, enum mhi_ev_ccs code) { - struct mhi_ring_element event = {}; + struct mhi_ring_element *event; + int ret; + + event = kmem_cache_zalloc(mhi_cntrl->ev_ring_el_cache, GFP_KERNEL | GFP_DMA); + if (!event) + return -ENOMEM; - event.ptr = cpu_to_le64(ring->rbase + ring->rd_offset * sizeof(*tre)); - event.dword[0] = MHI_TRE_EV_DWORD0(code, len); - event.dword[1] = MHI_TRE_EV_DWORD1(ring->ch_id, MHI_PKT_TYPE_TX_EVENT); + event->ptr = cpu_to_le64(ring->rbase + ring->rd_offset * sizeof(*tre)); + event->dword[0] = MHI_TRE_EV_DWORD0(code, len); + event->dword[1] = MHI_TRE_EV_DWORD1(ring->ch_id, MHI_PKT_TYPE_TX_EVENT); - return mhi_ep_send_event(mhi_cntrl, ring->er_index, &event, MHI_TRE_DATA_GET_BEI(tre)); + ret = mhi_ep_send_event(mhi_cntrl, ring->er_index, event, MHI_TRE_DATA_GET_BEI(tre)); + kmem_cache_free(mhi_cntrl->ev_ring_el_cache, event); + + return ret; } int mhi_ep_send_state_change_event(struct mhi_ep_cntrl *mhi_cntrl, enum mhi_state state) { - struct mhi_ring_element event = {}; + struct mhi_ring_element *event; + int ret; - event.dword[0] = MHI_SC_EV_DWORD0(state); - event.dword[1] = MHI_SC_EV_DWORD1(MHI_PKT_TYPE_STATE_CHANGE_EVENT); + event = kmem_cache_zalloc(mhi_cntrl->ev_ring_el_cache, GFP_KERNEL | GFP_DMA); + if (!event) + return -ENOMEM; - return mhi_ep_send_event(mhi_cntrl, 0, &event, 0); + event->dword[0] = MHI_SC_EV_DWORD0(state); + event->dword[1] = MHI_SC_EV_DWORD1(MHI_PKT_TYPE_STATE_CHANGE_EVENT); + + ret = mhi_ep_send_event(mhi_cntrl, 0, event, 0); + kmem_cache_free(mhi_cntrl->ev_ring_el_cache, event); + + return ret; } int mhi_ep_send_ee_event(struct mhi_ep_cntrl *mhi_cntrl, enum mhi_ee_type exec_env) { - struct mhi_ring_element event = {}; + struct mhi_ring_element *event; + int ret; - event.dword[0] = MHI_EE_EV_DWORD0(exec_env); - event.dword[1] = MHI_SC_EV_DWORD1(MHI_PKT_TYPE_EE_EVENT); + event = kmem_cache_zalloc(mhi_cntrl->ev_ring_el_cache, GFP_KERNEL | GFP_DMA); + if (!event) + return -ENOMEM; + + event->dword[0] = MHI_EE_EV_DWORD0(exec_env); + event->dword[1] = MHI_SC_EV_DWORD1(MHI_PKT_TYPE_EE_EVENT); - return mhi_ep_send_event(mhi_cntrl, 0, &event, 0); + ret = mhi_ep_send_event(mhi_cntrl, 0, event, 0); + kmem_cache_free(mhi_cntrl->ev_ring_el_cache, event); + + return ret; } static int mhi_ep_send_cmd_comp_event(struct mhi_ep_cntrl *mhi_cntrl, enum mhi_ev_ccs code) { struct mhi_ep_ring *ring = &mhi_cntrl->mhi_cmd->ring; - struct mhi_ring_element event = {}; + struct mhi_ring_element *event; + int ret; + + event = kmem_cache_zalloc(mhi_cntrl->ev_ring_el_cache, GFP_KERNEL | GFP_DMA); + if (!event) + return -ENOMEM; + + event->ptr = cpu_to_le64(ring->rbase + ring->rd_offset * sizeof(struct mhi_ring_element)); + event->dword[0] = MHI_CC_EV_DWORD0(code); + event->dword[1] = MHI_CC_EV_DWORD1(MHI_PKT_TYPE_CMD_COMPLETION_EVENT); - event.ptr = cpu_to_le64(ring->rbase + ring->rd_offset * sizeof(struct mhi_ring_element)); - event.dword[0] = MHI_CC_EV_DWORD0(code); - event.dword[1] = MHI_CC_EV_DWORD1(MHI_PKT_TYPE_CMD_COMPLETION_EVENT); + ret = mhi_ep_send_event(mhi_cntrl, 0, event, 0); + kmem_cache_free(mhi_cntrl->ev_ring_el_cache, event); - return mhi_ep_send_event(mhi_cntrl, 0, &event, 0); + return ret; } static int mhi_ep_process_cmd_ring(struct mhi_ep_ring *ring, struct mhi_ring_element *el) @@ -151,6 +199,8 @@ static int mhi_ep_process_cmd_ring(struct mhi_ep_ring *ring, struct mhi_ring_ele goto err_unlock; } + + mhi_chan->rd_offset = ch_ring->rd_offset; } /* Set channel state to RUNNING */ @@ -280,22 +330,85 @@ bool mhi_ep_queue_is_empty(struct mhi_ep_device *mhi_dev, enum dma_data_directio struct mhi_ep_cntrl *mhi_cntrl = mhi_dev->mhi_cntrl; struct mhi_ep_ring *ring = &mhi_cntrl->mhi_chan[mhi_chan->chan].ring; - return !!(ring->rd_offset == ring->wr_offset); + return !!(mhi_chan->rd_offset == ring->wr_offset); } EXPORT_SYMBOL_GPL(mhi_ep_queue_is_empty); +static void mhi_ep_read_completion(struct mhi_ep_buf_info *buf_info) +{ + struct mhi_ep_device *mhi_dev = buf_info->mhi_dev; + struct mhi_ep_cntrl *mhi_cntrl = mhi_dev->mhi_cntrl; + struct mhi_ep_chan *mhi_chan = mhi_dev->ul_chan; + struct mhi_ep_ring *ring = &mhi_cntrl->mhi_chan[mhi_chan->chan].ring; + struct mhi_ring_element *el = &ring->ring_cache[ring->rd_offset]; + struct mhi_result result = {}; + int ret; + + if (mhi_chan->xfer_cb) { + result.buf_addr = buf_info->cb_buf; + result.dir = mhi_chan->dir; + result.bytes_xferd = buf_info->size; + + mhi_chan->xfer_cb(mhi_dev, &result); + } + + /* + * The host will split the data packet into multiple TREs if it can't fit + * the packet in a single TRE. In that case, CHAIN flag will be set by the + * host for all TREs except the last one. + */ + if (buf_info->code != MHI_EV_CC_OVERFLOW) { + if (MHI_TRE_DATA_GET_CHAIN(el)) { + /* + * IEOB (Interrupt on End of Block) flag will be set by the host if + * it expects the completion event for all TREs of a TD. + */ + if (MHI_TRE_DATA_GET_IEOB(el)) { + ret = mhi_ep_send_completion_event(mhi_cntrl, ring, el, + MHI_TRE_DATA_GET_LEN(el), + MHI_EV_CC_EOB); + if (ret < 0) { + dev_err(&mhi_chan->mhi_dev->dev, + "Error sending transfer compl. event\n"); + goto err_free_tre_buf; + } + } + } else { + /* + * IEOT (Interrupt on End of Transfer) flag will be set by the host + * for the last TRE of the TD and expects the completion event for + * the same. + */ + if (MHI_TRE_DATA_GET_IEOT(el)) { + ret = mhi_ep_send_completion_event(mhi_cntrl, ring, el, + MHI_TRE_DATA_GET_LEN(el), + MHI_EV_CC_EOT); + if (ret < 0) { + dev_err(&mhi_chan->mhi_dev->dev, + "Error sending transfer compl. event\n"); + goto err_free_tre_buf; + } + } + } + } + + mhi_ep_ring_inc_index(ring); + +err_free_tre_buf: + kmem_cache_free(mhi_cntrl->tre_buf_cache, buf_info->cb_buf); +} + static int mhi_ep_read_channel(struct mhi_ep_cntrl *mhi_cntrl, - struct mhi_ep_ring *ring, - struct mhi_result *result, - u32 len) + struct mhi_ep_ring *ring) { struct mhi_ep_chan *mhi_chan = &mhi_cntrl->mhi_chan[ring->ch_id]; struct device *dev = &mhi_cntrl->mhi_dev->dev; size_t tr_len, read_offset, write_offset; + struct mhi_ep_buf_info buf_info = {}; + u32 len = MHI_EP_DEFAULT_MTU; struct mhi_ring_element *el; bool tr_done = false; - void *write_addr; - u64 read_addr; + void *buf_addr; u32 buf_left; int ret; @@ -308,7 +421,7 @@ static int mhi_ep_read_channel(struct mhi_ep_cntrl *mhi_cntrl, return -ENODEV; } - el = &ring->ring_cache[ring->rd_offset]; + el = &ring->ring_cache[mhi_chan->rd_offset]; /* Check if there is data pending to be read from previous read operation */ if (mhi_chan->tre_bytes_left) { @@ -324,81 +437,51 @@ static int mhi_ep_read_channel(struct mhi_ep_cntrl *mhi_cntrl, read_offset = mhi_chan->tre_size - mhi_chan->tre_bytes_left; write_offset = len - buf_left; - read_addr = mhi_chan->tre_loc + read_offset; - write_addr = result->buf_addr + write_offset; + + buf_addr = kmem_cache_zalloc(mhi_cntrl->tre_buf_cache, GFP_KERNEL | GFP_DMA); + if (!buf_addr) + return -ENOMEM; + + buf_info.host_addr = mhi_chan->tre_loc + read_offset; + buf_info.dev_addr = buf_addr + write_offset; + buf_info.size = tr_len; + buf_info.cb = mhi_ep_read_completion; + buf_info.cb_buf = buf_addr; + buf_info.mhi_dev = mhi_chan->mhi_dev; + + if (mhi_chan->tre_bytes_left - tr_len) + buf_info.code = MHI_EV_CC_OVERFLOW; dev_dbg(dev, "Reading %zd bytes from channel (%u)\n", tr_len, ring->ch_id); - ret = mhi_cntrl->read_from_host(mhi_cntrl, read_addr, write_addr, tr_len); + ret = mhi_cntrl->read_async(mhi_cntrl, &buf_info); if (ret < 0) { dev_err(&mhi_chan->mhi_dev->dev, "Error reading from channel\n"); - return ret; + goto err_free_buf_addr; } buf_left -= tr_len; mhi_chan->tre_bytes_left -= tr_len; - /* - * Once the TRE (Transfer Ring Element) of a TD (Transfer Descriptor) has been - * read completely: - * - * 1. Send completion event to the host based on the flags set in TRE. - * 2. Increment the local read offset of the transfer ring. - */ if (!mhi_chan->tre_bytes_left) { - /* - * The host will split the data packet into multiple TREs if it can't fit - * the packet in a single TRE. In that case, CHAIN flag will be set by the - * host for all TREs except the last one. - */ - if (MHI_TRE_DATA_GET_CHAIN(el)) { - /* - * IEOB (Interrupt on End of Block) flag will be set by the host if - * it expects the completion event for all TREs of a TD. - */ - if (MHI_TRE_DATA_GET_IEOB(el)) { - ret = mhi_ep_send_completion_event(mhi_cntrl, ring, el, - MHI_TRE_DATA_GET_LEN(el), - MHI_EV_CC_EOB); - if (ret < 0) { - dev_err(&mhi_chan->mhi_dev->dev, - "Error sending transfer compl. event\n"); - return ret; - } - } - } else { - /* - * IEOT (Interrupt on End of Transfer) flag will be set by the host - * for the last TRE of the TD and expects the completion event for - * the same. - */ - if (MHI_TRE_DATA_GET_IEOT(el)) { - ret = mhi_ep_send_completion_event(mhi_cntrl, ring, el, - MHI_TRE_DATA_GET_LEN(el), - MHI_EV_CC_EOT); - if (ret < 0) { - dev_err(&mhi_chan->mhi_dev->dev, - "Error sending transfer compl. event\n"); - return ret; - } - } - + if (MHI_TRE_DATA_GET_IEOT(el)) tr_done = true; - } - mhi_ep_ring_inc_index(ring); + mhi_chan->rd_offset = (mhi_chan->rd_offset + 1) % ring->ring_size; } - - result->bytes_xferd += tr_len; } while (buf_left && !tr_done); return 0; + +err_free_buf_addr: + kmem_cache_free(mhi_cntrl->tre_buf_cache, buf_addr); + + return ret; } -static int mhi_ep_process_ch_ring(struct mhi_ep_ring *ring, struct mhi_ring_element *el) +static int mhi_ep_process_ch_ring(struct mhi_ep_ring *ring) { struct mhi_ep_cntrl *mhi_cntrl = ring->mhi_cntrl; struct mhi_result result = {}; - u32 len = MHI_EP_DEFAULT_MTU; struct mhi_ep_chan *mhi_chan; int ret; @@ -419,44 +502,59 @@ static int mhi_ep_process_ch_ring(struct mhi_ep_ring *ring, struct mhi_ring_elem mhi_chan->xfer_cb(mhi_chan->mhi_dev, &result); } else { /* UL channel */ - result.buf_addr = kzalloc(len, GFP_KERNEL); - if (!result.buf_addr) - return -ENOMEM; - do { - ret = mhi_ep_read_channel(mhi_cntrl, ring, &result, len); + ret = mhi_ep_read_channel(mhi_cntrl, ring); if (ret < 0) { dev_err(&mhi_chan->mhi_dev->dev, "Failed to read channel\n"); - kfree(result.buf_addr); return ret; } - result.dir = mhi_chan->dir; - mhi_chan->xfer_cb(mhi_chan->mhi_dev, &result); - result.bytes_xferd = 0; - memset(result.buf_addr, 0, len); - /* Read until the ring becomes empty */ } while (!mhi_ep_queue_is_empty(mhi_chan->mhi_dev, DMA_TO_DEVICE)); - - kfree(result.buf_addr); } return 0; } +static void mhi_ep_skb_completion(struct mhi_ep_buf_info *buf_info) +{ + struct mhi_ep_device *mhi_dev = buf_info->mhi_dev; + struct mhi_ep_cntrl *mhi_cntrl = mhi_dev->mhi_cntrl; + struct mhi_ep_chan *mhi_chan = mhi_dev->dl_chan; + struct mhi_ep_ring *ring = &mhi_cntrl->mhi_chan[mhi_chan->chan].ring; + struct mhi_ring_element *el = &ring->ring_cache[ring->rd_offset]; + struct device *dev = &mhi_dev->dev; + struct mhi_result result = {}; + int ret; + + if (mhi_chan->xfer_cb) { + result.buf_addr = buf_info->cb_buf; + result.dir = mhi_chan->dir; + result.bytes_xferd = buf_info->size; + + mhi_chan->xfer_cb(mhi_dev, &result); + } + + ret = mhi_ep_send_completion_event(mhi_cntrl, ring, el, buf_info->size, + buf_info->code); + if (ret) { + dev_err(dev, "Error sending transfer completion event\n"); + return; + } + + mhi_ep_ring_inc_index(ring); +} + /* TODO: Handle partially formed TDs */ int mhi_ep_queue_skb(struct mhi_ep_device *mhi_dev, struct sk_buff *skb) { struct mhi_ep_cntrl *mhi_cntrl = mhi_dev->mhi_cntrl; struct mhi_ep_chan *mhi_chan = mhi_dev->dl_chan; struct device *dev = &mhi_chan->mhi_dev->dev; + struct mhi_ep_buf_info buf_info = {}; struct mhi_ring_element *el; u32 buf_left, read_offset; struct mhi_ep_ring *ring; - enum mhi_ev_ccs code; - void *read_addr; - u64 write_addr; size_t tr_len; u32 tre_len; int ret; @@ -480,40 +578,44 @@ int mhi_ep_queue_skb(struct mhi_ep_device *mhi_dev, struct sk_buff *skb) goto err_exit; } - el = &ring->ring_cache[ring->rd_offset]; + el = &ring->ring_cache[mhi_chan->rd_offset]; tre_len = MHI_TRE_DATA_GET_LEN(el); tr_len = min(buf_left, tre_len); read_offset = skb->len - buf_left; - read_addr = skb->data + read_offset; - write_addr = MHI_TRE_DATA_GET_PTR(el); - dev_dbg(dev, "Writing %zd bytes to channel (%u)\n", tr_len, ring->ch_id); - ret = mhi_cntrl->write_to_host(mhi_cntrl, read_addr, write_addr, tr_len); - if (ret < 0) { - dev_err(dev, "Error writing to the channel\n"); - goto err_exit; - } + buf_info.dev_addr = skb->data + read_offset; + buf_info.host_addr = MHI_TRE_DATA_GET_PTR(el); + buf_info.size = tr_len; + buf_info.cb = mhi_ep_skb_completion; + buf_info.cb_buf = skb; + buf_info.mhi_dev = mhi_dev; - buf_left -= tr_len; /* * For all TREs queued by the host for DL channel, only the EOT flag will be set. * If the packet doesn't fit into a single TRE, send the OVERFLOW event to * the host so that the host can adjust the packet boundary to next TREs. Else send * the EOT event to the host indicating the packet boundary. */ - if (buf_left) - code = MHI_EV_CC_OVERFLOW; + if (buf_left - tr_len) + buf_info.code = MHI_EV_CC_OVERFLOW; else - code = MHI_EV_CC_EOT; + buf_info.code = MHI_EV_CC_EOT; - ret = mhi_ep_send_completion_event(mhi_cntrl, ring, el, tr_len, code); - if (ret) { - dev_err(dev, "Error sending transfer completion event\n"); + dev_dbg(dev, "Writing %zd bytes to channel (%u)\n", tr_len, ring->ch_id); + ret = mhi_cntrl->write_async(mhi_cntrl, &buf_info); + if (ret < 0) { + dev_err(dev, "Error writing to the channel\n"); goto err_exit; } - mhi_ep_ring_inc_index(ring); + buf_left -= tr_len; + + /* + * Update the read offset cached in mhi_chan. Actual read offset + * will be updated by the completion handler. + */ + mhi_chan->rd_offset = (mhi_chan->rd_offset + 1) % ring->ring_size; } while (buf_left); mutex_unlock(&mhi_chan->lock); @@ -714,7 +816,6 @@ static void mhi_ep_ch_ring_worker(struct work_struct *work) struct mhi_ep_cntrl *mhi_cntrl = container_of(work, struct mhi_ep_cntrl, ch_ring_work); struct device *dev = &mhi_cntrl->mhi_dev->dev; struct mhi_ep_ring_item *itr, *tmp; - struct mhi_ring_element *el; struct mhi_ep_ring *ring; struct mhi_ep_chan *chan; unsigned long flags; @@ -748,31 +849,29 @@ static void mhi_ep_ch_ring_worker(struct work_struct *work) if (ret) { dev_err(dev, "Error updating write offset for ring\n"); mutex_unlock(&chan->lock); - kfree(itr); + kmem_cache_free(mhi_cntrl->ring_item_cache, itr); continue; } /* Sanity check to make sure there are elements in the ring */ - if (ring->rd_offset == ring->wr_offset) { + if (chan->rd_offset == ring->wr_offset) { mutex_unlock(&chan->lock); - kfree(itr); + kmem_cache_free(mhi_cntrl->ring_item_cache, itr); continue; } - el = &ring->ring_cache[ring->rd_offset]; - dev_dbg(dev, "Processing the ring for channel (%u)\n", ring->ch_id); - ret = mhi_ep_process_ch_ring(ring, el); + ret = mhi_ep_process_ch_ring(ring); if (ret) { dev_err(dev, "Error processing ring for channel (%u): %d\n", ring->ch_id, ret); mutex_unlock(&chan->lock); - kfree(itr); + kmem_cache_free(mhi_cntrl->ring_item_cache, itr); continue; } mutex_unlock(&chan->lock); - kfree(itr); + kmem_cache_free(mhi_cntrl->ring_item_cache, itr); } } @@ -828,7 +927,7 @@ static void mhi_ep_queue_channel_db(struct mhi_ep_cntrl *mhi_cntrl, unsigned lon u32 ch_id = ch_idx + i; ring = &mhi_cntrl->mhi_chan[ch_id].ring; - item = kzalloc(sizeof(*item), GFP_ATOMIC); + item = kmem_cache_zalloc(mhi_cntrl->ring_item_cache, GFP_ATOMIC); if (!item) return; @@ -1365,6 +1464,10 @@ int mhi_ep_register_controller(struct mhi_ep_cntrl *mhi_cntrl, if (!mhi_cntrl || !mhi_cntrl->cntrl_dev || !mhi_cntrl->mmio || !mhi_cntrl->irq) return -EINVAL; + if (!mhi_cntrl->read_sync || !mhi_cntrl->write_sync || + !mhi_cntrl->read_async || !mhi_cntrl->write_async) + return -EINVAL; + ret = mhi_ep_chan_init(mhi_cntrl, config); if (ret) return ret; @@ -1375,6 +1478,29 @@ int mhi_ep_register_controller(struct mhi_ep_cntrl *mhi_cntrl, goto err_free_ch; } + mhi_cntrl->ev_ring_el_cache = kmem_cache_create("mhi_ep_event_ring_el", + sizeof(struct mhi_ring_element), 0, + SLAB_CACHE_DMA, NULL); + if (!mhi_cntrl->ev_ring_el_cache) { + ret = -ENOMEM; + goto err_free_cmd; + } + + mhi_cntrl->tre_buf_cache = kmem_cache_create("mhi_ep_tre_buf", MHI_EP_DEFAULT_MTU, 0, + SLAB_CACHE_DMA, NULL); + if (!mhi_cntrl->tre_buf_cache) { + ret = -ENOMEM; + goto err_destroy_ev_ring_el_cache; + } + + mhi_cntrl->ring_item_cache = kmem_cache_create("mhi_ep_ring_item", + sizeof(struct mhi_ep_ring_item), 0, + 0, NULL); + if (!mhi_cntrl->ev_ring_el_cache) { + ret = -ENOMEM; + goto err_destroy_tre_buf_cache; + } + INIT_WORK(&mhi_cntrl->state_work, mhi_ep_state_worker); INIT_WORK(&mhi_cntrl->reset_work, mhi_ep_reset_worker); INIT_WORK(&mhi_cntrl->cmd_ring_work, mhi_ep_cmd_ring_worker); @@ -1383,7 +1509,7 @@ int mhi_ep_register_controller(struct mhi_ep_cntrl *mhi_cntrl, mhi_cntrl->wq = alloc_workqueue("mhi_ep_wq", 0, 0); if (!mhi_cntrl->wq) { ret = -ENOMEM; - goto err_free_cmd; + goto err_destroy_ring_item_cache; } INIT_LIST_HEAD(&mhi_cntrl->st_transition_list); @@ -1442,6 +1568,12 @@ err_ida_free: ida_free(&mhi_ep_cntrl_ida, mhi_cntrl->index); err_destroy_wq: destroy_workqueue(mhi_cntrl->wq); +err_destroy_ring_item_cache: + kmem_cache_destroy(mhi_cntrl->ring_item_cache); +err_destroy_ev_ring_el_cache: + kmem_cache_destroy(mhi_cntrl->ev_ring_el_cache); +err_destroy_tre_buf_cache: + kmem_cache_destroy(mhi_cntrl->tre_buf_cache); err_free_cmd: kfree(mhi_cntrl->mhi_cmd); err_free_ch: @@ -1463,6 +1595,9 @@ void mhi_ep_unregister_controller(struct mhi_ep_cntrl *mhi_cntrl) free_irq(mhi_cntrl->irq, mhi_cntrl); + kmem_cache_destroy(mhi_cntrl->tre_buf_cache); + kmem_cache_destroy(mhi_cntrl->ev_ring_el_cache); + kmem_cache_destroy(mhi_cntrl->ring_item_cache); kfree(mhi_cntrl->mhi_cmd); kfree(mhi_cntrl->mhi_chan); diff --git a/drivers/bus/mhi/ep/ring.c b/drivers/bus/mhi/ep/ring.c index 115518ec76a43a..aeb53b2c34a8cd 100644 --- a/drivers/bus/mhi/ep/ring.c +++ b/drivers/bus/mhi/ep/ring.c @@ -30,7 +30,8 @@ static int __mhi_ep_cache_ring(struct mhi_ep_ring *ring, size_t end) { struct mhi_ep_cntrl *mhi_cntrl = ring->mhi_cntrl; struct device *dev = &mhi_cntrl->mhi_dev->dev; - size_t start, copy_size; + struct mhi_ep_buf_info buf_info = {}; + size_t start; int ret; /* Don't proceed in the case of event ring. This happens during mhi_ep_ring_start(). */ @@ -43,30 +44,34 @@ static int __mhi_ep_cache_ring(struct mhi_ep_ring *ring, size_t end) start = ring->wr_offset; if (start < end) { - copy_size = (end - start) * sizeof(struct mhi_ring_element); - ret = mhi_cntrl->read_from_host(mhi_cntrl, ring->rbase + - (start * sizeof(struct mhi_ring_element)), - &ring->ring_cache[start], copy_size); + buf_info.size = (end - start) * sizeof(struct mhi_ring_element); + buf_info.host_addr = ring->rbase + (start * sizeof(struct mhi_ring_element)); + buf_info.dev_addr = &ring->ring_cache[start]; + + ret = mhi_cntrl->read_sync(mhi_cntrl, &buf_info); if (ret < 0) return ret; } else { - copy_size = (ring->ring_size - start) * sizeof(struct mhi_ring_element); - ret = mhi_cntrl->read_from_host(mhi_cntrl, ring->rbase + - (start * sizeof(struct mhi_ring_element)), - &ring->ring_cache[start], copy_size); + buf_info.size = (ring->ring_size - start) * sizeof(struct mhi_ring_element); + buf_info.host_addr = ring->rbase + (start * sizeof(struct mhi_ring_element)); + buf_info.dev_addr = &ring->ring_cache[start]; + + ret = mhi_cntrl->read_sync(mhi_cntrl, &buf_info); if (ret < 0) return ret; if (end) { - ret = mhi_cntrl->read_from_host(mhi_cntrl, ring->rbase, - &ring->ring_cache[0], - end * sizeof(struct mhi_ring_element)); + buf_info.host_addr = ring->rbase; + buf_info.dev_addr = &ring->ring_cache[0]; + buf_info.size = end * sizeof(struct mhi_ring_element); + + ret = mhi_cntrl->read_sync(mhi_cntrl, &buf_info); if (ret < 0) return ret; } } - dev_dbg(dev, "Cached ring: start %zu end %zu size %zu\n", start, end, copy_size); + dev_dbg(dev, "Cached ring: start %zu end %zu size %zu\n", start, end, buf_info.size); return 0; } @@ -102,6 +107,7 @@ int mhi_ep_ring_add_element(struct mhi_ep_ring *ring, struct mhi_ring_element *e { struct mhi_ep_cntrl *mhi_cntrl = ring->mhi_cntrl; struct device *dev = &mhi_cntrl->mhi_dev->dev; + struct mhi_ep_buf_info buf_info = {}; size_t old_offset = 0; u32 num_free_elem; __le64 rp; @@ -133,12 +139,11 @@ int mhi_ep_ring_add_element(struct mhi_ep_ring *ring, struct mhi_ring_element *e rp = cpu_to_le64(ring->rd_offset * sizeof(*el) + ring->rbase); memcpy_toio((void __iomem *) &ring->ring_ctx->generic.rp, &rp, sizeof(u64)); - ret = mhi_cntrl->write_to_host(mhi_cntrl, el, ring->rbase + (old_offset * sizeof(*el)), - sizeof(*el)); - if (ret < 0) - return ret; + buf_info.host_addr = ring->rbase + (old_offset * sizeof(*el)); + buf_info.dev_addr = el; + buf_info.size = sizeof(*el); - return 0; + return mhi_cntrl->write_sync(mhi_cntrl, &buf_info); } void mhi_ep_ring_init(struct mhi_ep_ring *ring, enum mhi_ep_ring_type type, u32 id) @@ -157,6 +162,15 @@ void mhi_ep_ring_init(struct mhi_ep_ring *ring, enum mhi_ep_ring_type type, u32 } } +static void mhi_ep_raise_irq(struct work_struct *work) +{ + struct mhi_ep_ring *ring = container_of(work, struct mhi_ep_ring, intmodt_work.work); + struct mhi_ep_cntrl *mhi_cntrl = ring->mhi_cntrl; + + mhi_cntrl->raise_irq(mhi_cntrl, ring->irq_vector); + WRITE_ONCE(ring->irq_pending, false); +} + int mhi_ep_ring_start(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_ring *ring, union mhi_ep_ring_ctx *ctx) { @@ -173,8 +187,13 @@ int mhi_ep_ring_start(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_ring *ring, if (ring->type == RING_TYPE_CH) ring->er_index = le32_to_cpu(ring->ring_ctx->ch.erindex); - if (ring->type == RING_TYPE_ER) + if (ring->type == RING_TYPE_ER) { ring->irq_vector = le32_to_cpu(ring->ring_ctx->ev.msivec); + ring->intmodt = FIELD_GET(EV_CTX_INTMODT_MASK, + le32_to_cpu(ring->ring_ctx->ev.intmod)); + + INIT_DELAYED_WORK(&ring->intmodt_work, mhi_ep_raise_irq); + } /* During ring init, both rp and wp are equal */ memcpy_fromio(&val, (void __iomem *) &ring->ring_ctx->generic.rp, sizeof(u64)); @@ -201,6 +220,9 @@ int mhi_ep_ring_start(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_ring *ring, void mhi_ep_ring_reset(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_ring *ring) { + if (ring->type == RING_TYPE_ER) + cancel_delayed_work_sync(&ring->intmodt_work); + ring->started = false; kfree(ring->ring_cache); ring->ring_cache = NULL; diff --git a/drivers/bus/mhi/host/init.c b/drivers/bus/mhi/host/init.c index f78aefd2d7a362..65ceac1837f9a1 100644 --- a/drivers/bus/mhi/host/init.c +++ b/drivers/bus/mhi/host/init.c @@ -881,6 +881,7 @@ static int parse_config(struct mhi_controller *mhi_cntrl, if (!mhi_cntrl->timeout_ms) mhi_cntrl->timeout_ms = MHI_TIMEOUT_MS; + mhi_cntrl->ready_timeout_ms = config->ready_timeout_ms; mhi_cntrl->bounce_buf = config->use_bounce_buf; mhi_cntrl->buffer_len = config->buf_len; if (!mhi_cntrl->buffer_len) diff --git a/drivers/bus/mhi/host/internal.h b/drivers/bus/mhi/host/internal.h index 2e139e76de4c03..30ac415a3000f6 100644 --- a/drivers/bus/mhi/host/internal.h +++ b/drivers/bus/mhi/host/internal.h @@ -321,7 +321,7 @@ int __must_check mhi_read_reg_field(struct mhi_controller *mhi_cntrl, u32 *out); int __must_check mhi_poll_reg_field(struct mhi_controller *mhi_cntrl, void __iomem *base, u32 offset, u32 mask, - u32 val, u32 delayus); + u32 val, u32 delayus, u32 timeout_ms); void mhi_write_reg(struct mhi_controller *mhi_cntrl, void __iomem *base, u32 offset, u32 val); int __must_check mhi_write_reg_field(struct mhi_controller *mhi_cntrl, diff --git a/drivers/bus/mhi/host/main.c b/drivers/bus/mhi/host/main.c index dcf627b36e829e..abb561db9ae1d5 100644 --- a/drivers/bus/mhi/host/main.c +++ b/drivers/bus/mhi/host/main.c @@ -40,10 +40,11 @@ int __must_check mhi_read_reg_field(struct mhi_controller *mhi_cntrl, int __must_check mhi_poll_reg_field(struct mhi_controller *mhi_cntrl, void __iomem *base, u32 offset, - u32 mask, u32 val, u32 delayus) + u32 mask, u32 val, u32 delayus, + u32 timeout_ms) { int ret; - u32 out, retry = (mhi_cntrl->timeout_ms * 1000) / delayus; + u32 out, retry = (timeout_ms * 1000) / delayus; while (retry--) { ret = mhi_read_reg_field(mhi_cntrl, base, offset, mask, &out); @@ -268,7 +269,8 @@ static void mhi_del_ring_element(struct mhi_controller *mhi_cntrl, static bool is_valid_ring_ptr(struct mhi_ring *ring, dma_addr_t addr) { - return addr >= ring->iommu_base && addr < ring->iommu_base + ring->len; + return addr >= ring->iommu_base && addr < ring->iommu_base + ring->len && + !(addr & (sizeof(struct mhi_ring_element) - 1)); } int mhi_destroy_device(struct device *dev, void *data) @@ -642,6 +644,8 @@ static int parse_xfer_event(struct mhi_controller *mhi_cntrl, mhi_del_ring_element(mhi_cntrl, tre_ring); local_rp = tre_ring->rp; + read_unlock_bh(&mhi_chan->lock); + /* notify client */ mhi_chan->xfer_cb(mhi_chan->mhi_dev, &result); @@ -667,6 +671,8 @@ static int parse_xfer_event(struct mhi_controller *mhi_cntrl, kfree(buf_info->cb_buf); } } + + read_lock_bh(&mhi_chan->lock); } break; } /* CC_EOT */ @@ -1122,17 +1128,15 @@ static int mhi_queue(struct mhi_device *mhi_dev, struct mhi_buf_info *buf_info, if (unlikely(MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state))) return -EIO; - read_lock_irqsave(&mhi_cntrl->pm_lock, flags); - ret = mhi_is_ring_full(mhi_cntrl, tre_ring); - if (unlikely(ret)) { - ret = -EAGAIN; - goto exit_unlock; - } + if (unlikely(ret)) + return -EAGAIN; ret = mhi_gen_tre(mhi_cntrl, mhi_chan, buf_info, mflags); if (unlikely(ret)) - goto exit_unlock; + return ret; + + read_lock_irqsave(&mhi_cntrl->pm_lock, flags); /* Packet is queued, take a usage ref to exit M3 if necessary * for host->device buffer, balanced put is done on buffer completion @@ -1152,7 +1156,6 @@ static int mhi_queue(struct mhi_device *mhi_dev, struct mhi_buf_info *buf_info, if (dir == DMA_FROM_DEVICE) mhi_cntrl->runtime_put(mhi_cntrl); -exit_unlock: read_unlock_irqrestore(&mhi_cntrl->pm_lock, flags); return ret; @@ -1204,6 +1207,9 @@ int mhi_gen_tre(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, int eot, eob, chain, bei; int ret; + /* Protect accesses for reading and incrementing WP */ + write_lock_bh(&mhi_chan->lock); + buf_ring = &mhi_chan->buf_ring; tre_ring = &mhi_chan->tre_ring; @@ -1221,8 +1227,10 @@ int mhi_gen_tre(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, if (!info->pre_mapped) { ret = mhi_cntrl->map_single(mhi_cntrl, buf_info); - if (ret) + if (ret) { + write_unlock_bh(&mhi_chan->lock); return ret; + } } eob = !!(flags & MHI_EOB); @@ -1239,6 +1247,8 @@ int mhi_gen_tre(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan, mhi_add_ring_element(mhi_cntrl, tre_ring); mhi_add_ring_element(mhi_cntrl, buf_ring); + write_unlock_bh(&mhi_chan->lock); + return 0; } diff --git a/drivers/bus/mhi/host/pci_generic.c b/drivers/bus/mhi/host/pci_generic.c index 08f3f039dbddcf..cd6cd14b3d29b1 100644 --- a/drivers/bus/mhi/host/pci_generic.c +++ b/drivers/bus/mhi/host/pci_generic.c @@ -269,6 +269,16 @@ static struct mhi_event_config modem_qcom_v1_mhi_events[] = { MHI_EVENT_CONFIG_HW_DATA(5, 2048, 101) }; +static const struct mhi_controller_config modem_qcom_v2_mhiv_config = { + .max_channels = 128, + .timeout_ms = 8000, + .ready_timeout_ms = 50000, + .num_channels = ARRAY_SIZE(modem_qcom_v1_mhi_channels), + .ch_cfg = modem_qcom_v1_mhi_channels, + .num_events = ARRAY_SIZE(modem_qcom_v1_mhi_events), + .event_cfg = modem_qcom_v1_mhi_events, +}; + static const struct mhi_controller_config modem_qcom_v1_mhiv_config = { .max_channels = 128, .timeout_ms = 8000, @@ -278,6 +288,16 @@ static const struct mhi_controller_config modem_qcom_v1_mhiv_config = { .event_cfg = modem_qcom_v1_mhi_events, }; +static const struct mhi_pci_dev_info mhi_qcom_sdx75_info = { + .name = "qcom-sdx75m", + .fw = "qcom/sdx75m/xbl.elf", + .edl = "qcom/sdx75m/edl.mbn", + .config = &modem_qcom_v2_mhiv_config, + .bar_num = MHI_PCI_DEFAULT_BAR_NUM, + .dma_data_width = 32, + .sideband_wake = false, +}; + static const struct mhi_pci_dev_info mhi_qcom_sdx65_info = { .name = "qcom-sdx65m", .fw = "qcom/sdx65m/xbl.elf", @@ -600,6 +620,8 @@ static const struct pci_device_id mhi_pci_id_table[] = { .driver_data = (kernel_ulong_t) &mhi_telit_fn990_info }, { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0308), .driver_data = (kernel_ulong_t) &mhi_qcom_sdx65_info }, + { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0309), + .driver_data = (kernel_ulong_t) &mhi_qcom_sdx75_info }, { PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x1001), /* EM120R-GL (sdx24) */ .driver_data = (kernel_ulong_t) &mhi_quectel_em1xx_info }, { PCI_DEVICE(PCI_VENDOR_ID_QUECTEL, 0x1002), /* EM160R-GL (sdx24) */ diff --git a/drivers/bus/mhi/host/pm.c b/drivers/bus/mhi/host/pm.c index 8a4362d75fc437..a2f2feef14768a 100644 --- a/drivers/bus/mhi/host/pm.c +++ b/drivers/bus/mhi/host/pm.c @@ -163,6 +163,7 @@ int mhi_ready_state_transition(struct mhi_controller *mhi_cntrl) enum mhi_pm_state cur_state; struct device *dev = &mhi_cntrl->mhi_dev->dev; u32 interval_us = 25000; /* poll register field every 25 milliseconds */ + u32 timeout_ms; int ret, i; /* Check if device entered error state */ @@ -173,14 +174,18 @@ int mhi_ready_state_transition(struct mhi_controller *mhi_cntrl) /* Wait for RESET to be cleared and READY bit to be set by the device */ ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, MHICTRL, - MHICTRL_RESET_MASK, 0, interval_us); + MHICTRL_RESET_MASK, 0, interval_us, + mhi_cntrl->timeout_ms); if (ret) { dev_err(dev, "Device failed to clear MHI Reset\n"); return ret; } + timeout_ms = mhi_cntrl->ready_timeout_ms ? + mhi_cntrl->ready_timeout_ms : mhi_cntrl->timeout_ms; ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, MHISTATUS, - MHISTATUS_READY_MASK, 1, interval_us); + MHISTATUS_READY_MASK, 1, interval_us, + timeout_ms); if (ret) { dev_err(dev, "Device failed to enter MHI Ready\n"); return ret; @@ -479,7 +484,7 @@ static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl) /* Wait for the reset bit to be cleared by the device */ ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, MHICTRL, - MHICTRL_RESET_MASK, 0, 25000); + MHICTRL_RESET_MASK, 0, 25000, mhi_cntrl->timeout_ms); if (ret) dev_err(dev, "Device failed to clear MHI Reset\n"); @@ -492,8 +497,8 @@ static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl) if (!MHI_IN_PBL(mhi_get_exec_env(mhi_cntrl))) { /* wait for ready to be set */ ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, - MHISTATUS, - MHISTATUS_READY_MASK, 1, 25000); + MHISTATUS, MHISTATUS_READY_MASK, + 1, 25000, mhi_cntrl->timeout_ms); if (ret) dev_err(dev, "Device failed to enter READY state\n"); } @@ -1111,7 +1116,8 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl) if (state == MHI_STATE_SYS_ERR) { mhi_set_mhi_state(mhi_cntrl, MHI_STATE_RESET); ret = mhi_poll_reg_field(mhi_cntrl, mhi_cntrl->regs, MHICTRL, - MHICTRL_RESET_MASK, 0, interval_us); + MHICTRL_RESET_MASK, 0, interval_us, + mhi_cntrl->timeout_ms); if (ret) { dev_info(dev, "Failed to reset MHI due to syserr state\n"); goto error_exit; @@ -1202,14 +1208,18 @@ EXPORT_SYMBOL_GPL(mhi_power_down); int mhi_sync_power_up(struct mhi_controller *mhi_cntrl) { int ret = mhi_async_power_up(mhi_cntrl); + u32 timeout_ms; if (ret) return ret; + /* Some devices need more time to set ready during power up */ + timeout_ms = mhi_cntrl->ready_timeout_ms ? + mhi_cntrl->ready_timeout_ms : mhi_cntrl->timeout_ms; wait_event_timeout(mhi_cntrl->state_event, MHI_IN_MISSION_MODE(mhi_cntrl->ee) || MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state), - msecs_to_jiffies(mhi_cntrl->timeout_ms)); + msecs_to_jiffies(timeout_ms)); ret = (MHI_IN_MISSION_MODE(mhi_cntrl->ee)) ? 0 : -ETIMEDOUT; if (ret) diff --git a/drivers/bus/moxtet.c b/drivers/bus/moxtet.c index 5eb0fe73ddc45b..641c1a6adc8ae5 100644 --- a/drivers/bus/moxtet.c +++ b/drivers/bus/moxtet.c @@ -102,7 +102,7 @@ static int moxtet_match(struct device *dev, struct device_driver *drv) return 0; } -static struct bus_type moxtet_bus_type = { +static const struct bus_type moxtet_bus_type = { .name = "moxtet", .dev_groups = moxtet_dev_groups, .match = moxtet_match, @@ -755,7 +755,7 @@ static int moxtet_irq_setup(struct moxtet *moxtet) moxtet->irq.masked = ~0; ret = request_threaded_irq(moxtet->dev_irq, NULL, moxtet_irq_thread_fn, - IRQF_ONESHOT, "moxtet", moxtet); + IRQF_SHARED | IRQF_ONESHOT, "moxtet", moxtet); if (ret < 0) goto err_free; @@ -830,6 +830,12 @@ static void moxtet_remove(struct spi_device *spi) mutex_destroy(&moxtet->lock); } +static const struct spi_device_id moxtet_spi_ids[] = { + { "moxtet" }, + { }, +}; +MODULE_DEVICE_TABLE(spi, moxtet_spi_ids); + static const struct of_device_id moxtet_dt_ids[] = { { .compatible = "cznic,moxtet" }, {}, @@ -841,6 +847,7 @@ static struct spi_driver moxtet_spi_driver = { .name = "moxtet", .of_match_table = moxtet_dt_ids, }, + .id_table = moxtet_spi_ids, .probe = moxtet_probe, .remove = moxtet_remove, }; diff --git a/drivers/bus/omap-ocp2scp.c b/drivers/bus/omap-ocp2scp.c index e02d0656242b8c..7d7479ba0a7599 100644 --- a/drivers/bus/omap-ocp2scp.c +++ b/drivers/bus/omap-ocp2scp.c @@ -84,12 +84,10 @@ err0: return ret; } -static int omap_ocp2scp_remove(struct platform_device *pdev) +static void omap_ocp2scp_remove(struct platform_device *pdev) { pm_runtime_disable(&pdev->dev); device_for_each_child(&pdev->dev, NULL, ocp2scp_remove_devices); - - return 0; } #ifdef CONFIG_OF @@ -103,7 +101,7 @@ MODULE_DEVICE_TABLE(of, omap_ocp2scp_id_table); static struct platform_driver omap_ocp2scp_driver = { .probe = omap_ocp2scp_probe, - .remove = omap_ocp2scp_remove, + .remove_new = omap_ocp2scp_remove, .driver = { .name = "omap-ocp2scp", .of_match_table = of_match_ptr(omap_ocp2scp_id_table), diff --git a/drivers/bus/omap_l3_smx.c b/drivers/bus/omap_l3_smx.c index 31774648be9d21..ee6d29925e4df7 100644 --- a/drivers/bus/omap_l3_smx.c +++ b/drivers/bus/omap_l3_smx.c @@ -261,7 +261,7 @@ err0: return ret; } -static int omap3_l3_remove(struct platform_device *pdev) +static void omap3_l3_remove(struct platform_device *pdev) { struct omap3_l3 *l3 = platform_get_drvdata(pdev); @@ -269,13 +269,11 @@ static int omap3_l3_remove(struct platform_device *pdev) free_irq(l3->debug_irq, l3); iounmap(l3->rt); kfree(l3); - - return 0; } static struct platform_driver omap3_l3_driver = { .probe = omap3_l3_probe, - .remove = omap3_l3_remove, + .remove_new = omap3_l3_remove, .driver = { .name = "omap_l3_smx", .of_match_table = of_match_ptr(omap3_l3_match), diff --git a/drivers/bus/qcom-ssc-block-bus.c b/drivers/bus/qcom-ssc-block-bus.c index 3fef18a43c0177..5931974a21fa3a 100644 --- a/drivers/bus/qcom-ssc-block-bus.c +++ b/drivers/bus/qcom-ssc-block-bus.c @@ -350,7 +350,7 @@ static int qcom_ssc_block_bus_probe(struct platform_device *pdev) return 0; } -static int qcom_ssc_block_bus_remove(struct platform_device *pdev) +static void qcom_ssc_block_bus_remove(struct platform_device *pdev) { struct qcom_ssc_block_bus_data *data = platform_get_drvdata(pdev); @@ -363,8 +363,6 @@ static int qcom_ssc_block_bus_remove(struct platform_device *pdev) qcom_ssc_block_bus_pds_detach(&pdev->dev, data->pds, data->num_pds); pm_runtime_disable(&pdev->dev); pm_clk_destroy(&pdev->dev); - - return 0; } static const struct of_device_id qcom_ssc_block_bus_of_match[] = { @@ -375,7 +373,7 @@ MODULE_DEVICE_TABLE(of, qcom_ssc_block_bus_of_match); static struct platform_driver qcom_ssc_block_bus_driver = { .probe = qcom_ssc_block_bus_probe, - .remove = qcom_ssc_block_bus_remove, + .remove_new = qcom_ssc_block_bus_remove, .driver = { .name = "qcom-ssc-block-bus", .of_match_table = qcom_ssc_block_bus_of_match, diff --git a/drivers/bus/simple-pm-bus.c b/drivers/bus/simple-pm-bus.c index aafcc481de91de..50870c82788992 100644 --- a/drivers/bus/simple-pm-bus.c +++ b/drivers/bus/simple-pm-bus.c @@ -74,17 +74,16 @@ static int simple_pm_bus_probe(struct platform_device *pdev) return 0; } -static int simple_pm_bus_remove(struct platform_device *pdev) +static void simple_pm_bus_remove(struct platform_device *pdev) { const void *data = of_device_get_match_data(&pdev->dev); if (pdev->driver_override || data) - return 0; + return; dev_dbg(&pdev->dev, "%s\n", __func__); pm_runtime_disable(&pdev->dev); - return 0; } static int simple_pm_bus_runtime_suspend(struct device *dev) @@ -129,7 +128,7 @@ MODULE_DEVICE_TABLE(of, simple_pm_bus_of_match); static struct platform_driver simple_pm_bus_driver = { .probe = simple_pm_bus_probe, - .remove = simple_pm_bus_remove, + .remove_new = simple_pm_bus_remove, .driver = { .name = "simple-pm-bus", .of_match_table = simple_pm_bus_of_match, diff --git a/drivers/bus/sun50i-de2.c b/drivers/bus/sun50i-de2.c index 414f29cdedf0db..3339311ce06834 100644 --- a/drivers/bus/sun50i-de2.c +++ b/drivers/bus/sun50i-de2.c @@ -24,10 +24,9 @@ static int sun50i_de2_bus_probe(struct platform_device *pdev) return 0; } -static int sun50i_de2_bus_remove(struct platform_device *pdev) +static void sun50i_de2_bus_remove(struct platform_device *pdev) { sunxi_sram_release(&pdev->dev); - return 0; } static const struct of_device_id sun50i_de2_bus_of_match[] = { @@ -37,7 +36,7 @@ static const struct of_device_id sun50i_de2_bus_of_match[] = { static struct platform_driver sun50i_de2_bus_driver = { .probe = sun50i_de2_bus_probe, - .remove = sun50i_de2_bus_remove, + .remove_new = sun50i_de2_bus_remove, .driver = { .name = "sun50i-de2-bus", .of_match_table = sun50i_de2_bus_of_match, diff --git a/drivers/bus/sunxi-rsb.c b/drivers/bus/sunxi-rsb.c index db0ed4e5d315fa..fd3e9d82340a57 100644 --- a/drivers/bus/sunxi-rsb.c +++ b/drivers/bus/sunxi-rsb.c @@ -817,15 +817,13 @@ static int sunxi_rsb_probe(struct platform_device *pdev) return 0; } -static int sunxi_rsb_remove(struct platform_device *pdev) +static void sunxi_rsb_remove(struct platform_device *pdev) { struct sunxi_rsb *rsb = platform_get_drvdata(pdev); device_for_each_child(rsb->dev, NULL, sunxi_rsb_remove_devices); pm_runtime_disable(&pdev->dev); sunxi_rsb_hw_exit(rsb); - - return 0; } static const struct dev_pm_ops sunxi_rsb_dev_pm_ops = { @@ -842,7 +840,7 @@ MODULE_DEVICE_TABLE(of, sunxi_rsb_of_match_table); static struct platform_driver sunxi_rsb_driver = { .probe = sunxi_rsb_probe, - .remove = sunxi_rsb_remove, + .remove_new = sunxi_rsb_remove, .driver = { .name = RSB_CTRL_NAME, .of_match_table = sunxi_rsb_of_match_table, diff --git a/drivers/bus/tegra-aconnect.c b/drivers/bus/tegra-aconnect.c index ac58142301f49d..de80008bff92de 100644 --- a/drivers/bus/tegra-aconnect.c +++ b/drivers/bus/tegra-aconnect.c @@ -53,11 +53,9 @@ static int tegra_aconnect_probe(struct platform_device *pdev) return 0; } -static int tegra_aconnect_remove(struct platform_device *pdev) +static void tegra_aconnect_remove(struct platform_device *pdev) { pm_runtime_disable(&pdev->dev); - - return 0; } static int tegra_aconnect_runtime_resume(struct device *dev) @@ -106,7 +104,7 @@ MODULE_DEVICE_TABLE(of, tegra_aconnect_of_match); static struct platform_driver tegra_aconnect_driver = { .probe = tegra_aconnect_probe, - .remove = tegra_aconnect_remove, + .remove_new = tegra_aconnect_remove, .driver = { .name = "tegra-aconnect", .of_match_table = tegra_aconnect_of_match, diff --git a/drivers/bus/tegra-gmi.c b/drivers/bus/tegra-gmi.c index 59919e99f7cc1a..f5d6414df9f238 100644 --- a/drivers/bus/tegra-gmi.c +++ b/drivers/bus/tegra-gmi.c @@ -258,14 +258,12 @@ static int tegra_gmi_probe(struct platform_device *pdev) return 0; } -static int tegra_gmi_remove(struct platform_device *pdev) +static void tegra_gmi_remove(struct platform_device *pdev) { struct tegra_gmi *gmi = platform_get_drvdata(pdev); of_platform_depopulate(gmi->dev); tegra_gmi_disable(gmi); - - return 0; } static int __maybe_unused tegra_gmi_runtime_resume(struct device *dev) @@ -305,7 +303,7 @@ MODULE_DEVICE_TABLE(of, tegra_gmi_id_table); static struct platform_driver tegra_gmi_driver = { .probe = tegra_gmi_probe, - .remove = tegra_gmi_remove, + .remove_new = tegra_gmi_remove, .driver = { .name = "tegra-gmi", .of_match_table = tegra_gmi_id_table, diff --git a/drivers/bus/ti-pwmss.c b/drivers/bus/ti-pwmss.c index 480a4de76cd4b0..4969c556e7521b 100644 --- a/drivers/bus/ti-pwmss.c +++ b/drivers/bus/ti-pwmss.c @@ -33,10 +33,9 @@ static int pwmss_probe(struct platform_device *pdev) return ret; } -static int pwmss_remove(struct platform_device *pdev) +static void pwmss_remove(struct platform_device *pdev) { pm_runtime_disable(&pdev->dev); - return 0; } static struct platform_driver pwmss_driver = { @@ -45,7 +44,7 @@ static struct platform_driver pwmss_driver = { .of_match_table = pwmss_of_match, }, .probe = pwmss_probe, - .remove = pwmss_remove, + .remove_new = pwmss_remove, }; module_platform_driver(pwmss_driver); diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index 9ed9239b1228f6..245e5e827d0dcf 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -3397,7 +3397,7 @@ unprepare: return error; } -static int sysc_remove(struct platform_device *pdev) +static void sysc_remove(struct platform_device *pdev) { struct sysc *ddata = platform_get_drvdata(pdev); int error; @@ -3422,8 +3422,6 @@ static int sysc_remove(struct platform_device *pdev) unprepare: sysc_unprepare(ddata); - - return 0; } static const struct of_device_id sysc_match[] = { @@ -3449,7 +3447,7 @@ MODULE_DEVICE_TABLE(of, sysc_match); static struct platform_driver sysc_driver = { .probe = sysc_probe, - .remove = sysc_remove, + .remove_new = sysc_remove, .driver = { .name = "ti-sysc", .of_match_table = sysc_match, diff --git a/drivers/bus/ts-nbus.c b/drivers/bus/ts-nbus.c index 38c886dc2ed6d2..4fa932cb09150a 100644 --- a/drivers/bus/ts-nbus.c +++ b/drivers/bus/ts-nbus.c @@ -331,7 +331,7 @@ static int ts_nbus_probe(struct platform_device *pdev) return 0; } -static int ts_nbus_remove(struct platform_device *pdev) +static void ts_nbus_remove(struct platform_device *pdev) { struct ts_nbus *ts_nbus = dev_get_drvdata(&pdev->dev); @@ -339,8 +339,6 @@ static int ts_nbus_remove(struct platform_device *pdev) mutex_lock(&ts_nbus->lock); pwm_disable(ts_nbus->pwm); mutex_unlock(&ts_nbus->lock); - - return 0; } static const struct of_device_id ts_nbus_of_match[] = { @@ -351,7 +349,7 @@ MODULE_DEVICE_TABLE(of, ts_nbus_of_match); static struct platform_driver ts_nbus_driver = { .probe = ts_nbus_probe, - .remove = ts_nbus_remove, + .remove_new = ts_nbus_remove, .driver = { .name = "ts_nbus", .of_match_table = ts_nbus_of_match, diff --git a/drivers/cache/Kconfig b/drivers/cache/Kconfig index d6e5e3abaad8af..9345ce4976d76d 100644 --- a/drivers/cache/Kconfig +++ b/drivers/cache/Kconfig @@ -8,4 +8,10 @@ config AX45MP_L2_CACHE help Support for the L2 cache controller on Andes Technology AX45MP platforms. +config SIFIVE_CCACHE + bool "Sifive Composable Cache controller" + depends on ARCH_SIFIVE || ARCH_STARFIVE + help + Support for the composable cache controller on SiFive platforms. + endmenu diff --git a/drivers/cache/Makefile b/drivers/cache/Makefile index 2012e7fb978dc5..7657cff3bd6c74 100644 --- a/drivers/cache/Makefile +++ b/drivers/cache/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_AX45MP_L2_CACHE) += ax45mp_cache.o +obj-$(CONFIG_AX45MP_L2_CACHE) += ax45mp_cache.o +obj-$(CONFIG_SIFIVE_CCACHE) += sifive_ccache.o diff --git a/drivers/cache/sifive_ccache.c b/drivers/cache/sifive_ccache.c new file mode 100644 index 00000000000000..89ed6cd6b059eb --- /dev/null +++ b/drivers/cache/sifive_ccache.c @@ -0,0 +1,330 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * SiFive composable cache controller Driver + * + * Copyright (C) 2018-2022 SiFive, Inc. + * + */ + +#define pr_fmt(fmt) "CCACHE: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SIFIVE_CCACHE_DIRECCFIX_LOW 0x100 +#define SIFIVE_CCACHE_DIRECCFIX_HIGH 0x104 +#define SIFIVE_CCACHE_DIRECCFIX_COUNT 0x108 + +#define SIFIVE_CCACHE_DIRECCFAIL_LOW 0x120 +#define SIFIVE_CCACHE_DIRECCFAIL_HIGH 0x124 +#define SIFIVE_CCACHE_DIRECCFAIL_COUNT 0x128 + +#define SIFIVE_CCACHE_DATECCFIX_LOW 0x140 +#define SIFIVE_CCACHE_DATECCFIX_HIGH 0x144 +#define SIFIVE_CCACHE_DATECCFIX_COUNT 0x148 + +#define SIFIVE_CCACHE_DATECCFAIL_LOW 0x160 +#define SIFIVE_CCACHE_DATECCFAIL_HIGH 0x164 +#define SIFIVE_CCACHE_DATECCFAIL_COUNT 0x168 + +#define SIFIVE_CCACHE_CONFIG 0x00 +#define SIFIVE_CCACHE_CONFIG_BANK_MASK GENMASK_ULL(7, 0) +#define SIFIVE_CCACHE_CONFIG_WAYS_MASK GENMASK_ULL(15, 8) +#define SIFIVE_CCACHE_CONFIG_SETS_MASK GENMASK_ULL(23, 16) +#define SIFIVE_CCACHE_CONFIG_BLKS_MASK GENMASK_ULL(31, 24) + +#define SIFIVE_CCACHE_FLUSH64 0x200 +#define SIFIVE_CCACHE_FLUSH32 0x240 + +#define SIFIVE_CCACHE_WAYENABLE 0x08 +#define SIFIVE_CCACHE_ECCINJECTERR 0x40 + +#define SIFIVE_CCACHE_MAX_ECCINTR 4 +#define SIFIVE_CCACHE_LINE_SIZE 64 + +static void __iomem *ccache_base; +static int g_irq[SIFIVE_CCACHE_MAX_ECCINTR]; +static struct riscv_cacheinfo_ops ccache_cache_ops; +static int level; + +enum { + DIR_CORR = 0, + DATA_CORR, + DATA_UNCORR, + DIR_UNCORR, +}; + +enum { + QUIRK_NONSTANDARD_CACHE_OPS = BIT(0), + QUIRK_BROKEN_DATA_UNCORR = BIT(1), +}; + +#ifdef CONFIG_DEBUG_FS +static struct dentry *sifive_test; + +static ssize_t ccache_write(struct file *file, const char __user *data, + size_t count, loff_t *ppos) +{ + unsigned int val; + + if (kstrtouint_from_user(data, count, 0, &val)) + return -EINVAL; + if ((val < 0xFF) || (val >= 0x10000 && val < 0x100FF)) + writel(val, ccache_base + SIFIVE_CCACHE_ECCINJECTERR); + else + return -EINVAL; + return count; +} + +static const struct file_operations ccache_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .write = ccache_write +}; + +static void setup_sifive_debug(void) +{ + sifive_test = debugfs_create_dir("sifive_ccache_cache", NULL); + + debugfs_create_file("sifive_debug_inject_error", 0200, + sifive_test, NULL, &ccache_fops); +} +#endif + +static void ccache_config_read(void) +{ + u32 cfg; + + cfg = readl(ccache_base + SIFIVE_CCACHE_CONFIG); + pr_info("%llu banks, %llu ways, sets/bank=%llu, bytes/block=%llu\n", + FIELD_GET(SIFIVE_CCACHE_CONFIG_BANK_MASK, cfg), + FIELD_GET(SIFIVE_CCACHE_CONFIG_WAYS_MASK, cfg), + BIT_ULL(FIELD_GET(SIFIVE_CCACHE_CONFIG_SETS_MASK, cfg)), + BIT_ULL(FIELD_GET(SIFIVE_CCACHE_CONFIG_BLKS_MASK, cfg))); + + cfg = readl(ccache_base + SIFIVE_CCACHE_WAYENABLE); + pr_info("Index of the largest way enabled: %u\n", cfg); +} + +static const struct of_device_id sifive_ccache_ids[] = { + { .compatible = "sifive,fu540-c000-ccache" }, + { .compatible = "sifive,fu740-c000-ccache" }, + { .compatible = "starfive,jh7100-ccache", + .data = (void *)(QUIRK_NONSTANDARD_CACHE_OPS | QUIRK_BROKEN_DATA_UNCORR) }, + { .compatible = "sifive,ccache0" }, + { /* end of table */ } +}; + +static ATOMIC_NOTIFIER_HEAD(ccache_err_chain); + +int register_sifive_ccache_error_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_register(&ccache_err_chain, nb); +} +EXPORT_SYMBOL_GPL(register_sifive_ccache_error_notifier); + +int unregister_sifive_ccache_error_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(&ccache_err_chain, nb); +} +EXPORT_SYMBOL_GPL(unregister_sifive_ccache_error_notifier); + +#ifdef CONFIG_RISCV_NONSTANDARD_CACHE_OPS +static void ccache_flush_range(phys_addr_t start, size_t len) +{ + phys_addr_t end = start + len; + phys_addr_t line; + + if (!len) + return; + + mb(); + for (line = ALIGN_DOWN(start, SIFIVE_CCACHE_LINE_SIZE); line < end; + line += SIFIVE_CCACHE_LINE_SIZE) { +#ifdef CONFIG_32BIT + writel(line >> 4, ccache_base + SIFIVE_CCACHE_FLUSH32); +#else + writeq(line, ccache_base + SIFIVE_CCACHE_FLUSH64); +#endif + mb(); + } +} + +static const struct riscv_nonstd_cache_ops ccache_mgmt_ops __initconst = { + .wback = &ccache_flush_range, + .inv = &ccache_flush_range, + .wback_inv = &ccache_flush_range, +}; +#endif /* CONFIG_RISCV_NONSTANDARD_CACHE_OPS */ + +static int ccache_largest_wayenabled(void) +{ + return readl(ccache_base + SIFIVE_CCACHE_WAYENABLE) & 0xFF; +} + +static ssize_t number_of_ways_enabled_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%u\n", ccache_largest_wayenabled()); +} + +static DEVICE_ATTR_RO(number_of_ways_enabled); + +static struct attribute *priv_attrs[] = { + &dev_attr_number_of_ways_enabled.attr, + NULL, +}; + +static const struct attribute_group priv_attr_group = { + .attrs = priv_attrs, +}; + +static const struct attribute_group *ccache_get_priv_group(struct cacheinfo + *this_leaf) +{ + /* We want to use private group for composable cache only */ + if (this_leaf->level == level) + return &priv_attr_group; + else + return NULL; +} + +static irqreturn_t ccache_int_handler(int irq, void *device) +{ + unsigned int add_h, add_l; + + if (irq == g_irq[DIR_CORR]) { + add_h = readl(ccache_base + SIFIVE_CCACHE_DIRECCFIX_HIGH); + add_l = readl(ccache_base + SIFIVE_CCACHE_DIRECCFIX_LOW); + pr_err("DirError @ 0x%08X.%08X\n", add_h, add_l); + /* Reading this register clears the DirError interrupt sig */ + readl(ccache_base + SIFIVE_CCACHE_DIRECCFIX_COUNT); + atomic_notifier_call_chain(&ccache_err_chain, + SIFIVE_CCACHE_ERR_TYPE_CE, + "DirECCFix"); + } + if (irq == g_irq[DIR_UNCORR]) { + add_h = readl(ccache_base + SIFIVE_CCACHE_DIRECCFAIL_HIGH); + add_l = readl(ccache_base + SIFIVE_CCACHE_DIRECCFAIL_LOW); + /* Reading this register clears the DirFail interrupt sig */ + readl(ccache_base + SIFIVE_CCACHE_DIRECCFAIL_COUNT); + atomic_notifier_call_chain(&ccache_err_chain, + SIFIVE_CCACHE_ERR_TYPE_UE, + "DirECCFail"); + panic("CCACHE: DirFail @ 0x%08X.%08X\n", add_h, add_l); + } + if (irq == g_irq[DATA_CORR]) { + add_h = readl(ccache_base + SIFIVE_CCACHE_DATECCFIX_HIGH); + add_l = readl(ccache_base + SIFIVE_CCACHE_DATECCFIX_LOW); + pr_err("DataError @ 0x%08X.%08X\n", add_h, add_l); + /* Reading this register clears the DataError interrupt sig */ + readl(ccache_base + SIFIVE_CCACHE_DATECCFIX_COUNT); + atomic_notifier_call_chain(&ccache_err_chain, + SIFIVE_CCACHE_ERR_TYPE_CE, + "DatECCFix"); + } + if (irq == g_irq[DATA_UNCORR]) { + add_h = readl(ccache_base + SIFIVE_CCACHE_DATECCFAIL_HIGH); + add_l = readl(ccache_base + SIFIVE_CCACHE_DATECCFAIL_LOW); + pr_err("DataFail @ 0x%08X.%08X\n", add_h, add_l); + /* Reading this register clears the DataFail interrupt sig */ + readl(ccache_base + SIFIVE_CCACHE_DATECCFAIL_COUNT); + atomic_notifier_call_chain(&ccache_err_chain, + SIFIVE_CCACHE_ERR_TYPE_UE, + "DatECCFail"); + } + + return IRQ_HANDLED; +} + +static int __init sifive_ccache_init(void) +{ + struct device_node *np; + struct resource res; + int i, rc, intr_num; + const struct of_device_id *match; + unsigned long quirks; + + np = of_find_matching_node_and_match(NULL, sifive_ccache_ids, &match); + if (!np) + return -ENODEV; + + quirks = (uintptr_t)match->data; + + if (of_address_to_resource(np, 0, &res)) { + rc = -ENODEV; + goto err_node_put; + } + + ccache_base = ioremap(res.start, resource_size(&res)); + if (!ccache_base) { + rc = -ENOMEM; + goto err_node_put; + } + + if (of_property_read_u32(np, "cache-level", &level)) { + rc = -ENOENT; + goto err_unmap; + } + + intr_num = of_property_count_u32_elems(np, "interrupts"); + if (!intr_num) { + pr_err("No interrupts property\n"); + rc = -ENODEV; + goto err_unmap; + } + + for (i = 0; i < intr_num; i++) { + g_irq[i] = irq_of_parse_and_map(np, i); + + if (i == DATA_UNCORR && (quirks & QUIRK_BROKEN_DATA_UNCORR)) + continue; + + rc = request_irq(g_irq[i], ccache_int_handler, 0, "ccache_ecc", + NULL); + if (rc) { + pr_err("Could not request IRQ %d\n", g_irq[i]); + goto err_free_irq; + } + } + of_node_put(np); + +#ifdef CONFIG_RISCV_NONSTANDARD_CACHE_OPS + if (quirks & QUIRK_NONSTANDARD_CACHE_OPS) { + riscv_cbom_block_size = SIFIVE_CCACHE_LINE_SIZE; + riscv_noncoherent_supported(); + riscv_noncoherent_register_cache_ops(&ccache_mgmt_ops); + } +#endif + + ccache_config_read(); + + ccache_cache_ops.get_priv_group = ccache_get_priv_group; + riscv_set_cacheinfo_ops(&ccache_cache_ops); + +#ifdef CONFIG_DEBUG_FS + setup_sifive_debug(); +#endif + return 0; + +err_free_irq: + while (--i >= 0) + free_irq(g_irq[i], NULL); +err_unmap: + iounmap(ccache_base); +err_node_put: + of_node_put(np); + return rc; +} + +arch_initcall(sifive_ccache_init); diff --git a/drivers/cdx/cdx.c b/drivers/cdx/cdx.c index 4461c6c9313f03..b74d76afccb634 100644 --- a/drivers/cdx/cdx.c +++ b/drivers/cdx/cdx.c @@ -57,13 +57,17 @@ #include #include +#include #include +#include +#include #include #include #include #include #include #include +#include #include "cdx.h" /* Default DMA mask for devices on a CDX bus */ @@ -74,9 +78,13 @@ static DEFINE_IDA(cdx_controller_ida); /* Lock to protect controller ops */ static DEFINE_MUTEX(cdx_controller_lock); +/* Debugfs dir for cdx bus */ +static struct dentry *cdx_debugfs_dir; static char *compat_node_name = "xlnx,versal-net-cdx"; +static void cdx_destroy_res_attr(struct cdx_device *cdx_dev, int num); + /** * cdx_dev_reset - Reset a CDX device * @dev: CDX device @@ -145,6 +153,8 @@ static int cdx_unregister_device(struct device *dev, if (cdx_dev->enabled && cdx->ops->bus_disable) cdx->ops->bus_disable(cdx, cdx_dev->bus_num); } else { + cdx_destroy_res_attr(cdx_dev, MAX_CDX_DEV_RESOURCES); + debugfs_remove_recursive(cdx_dev->debugfs_dir); kfree(cdx_dev->driver_override); cdx_dev->driver_override = NULL; } @@ -548,6 +558,31 @@ static const struct attribute_group *cdx_dev_groups[] = { NULL, }; +static int cdx_debug_resource_show(struct seq_file *s, void *data) +{ + struct cdx_device *cdx_dev = s->private; + int i; + + for (i = 0; i < MAX_CDX_DEV_RESOURCES; i++) { + struct resource *res = &cdx_dev->res[i]; + + seq_printf(s, "%pr\n", res); + } + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(cdx_debug_resource); + +static void cdx_device_debugfs_init(struct cdx_device *cdx_dev) +{ + cdx_dev->debugfs_dir = debugfs_create_dir(dev_name(&cdx_dev->dev), cdx_debugfs_dir); + if (IS_ERR(cdx_dev->debugfs_dir)) + return; + + debugfs_create_file("resource", 0444, cdx_dev->debugfs_dir, cdx_dev, + &cdx_debug_resource_fops); +} + static ssize_t rescan_store(const struct bus_type *bus, const char *buf, size_t count) { @@ -569,12 +604,12 @@ static ssize_t rescan_store(const struct bus_type *bus, /* Rescan all the devices */ for_each_compatible_node(np, NULL, compat_node_name) { - if (!np) - return -EINVAL; - pd = of_find_device_by_node(np); - if (!pd) - return -EINVAL; + if (!pd) { + of_node_put(np); + count = -EINVAL; + goto unlock; + } cdx = platform_get_drvdata(pd); if (cdx && cdx->controller_registered && cdx->ops->scan) @@ -583,6 +618,7 @@ static ssize_t rescan_store(const struct bus_type *bus, put_device(&pd->dev); } +unlock: mutex_unlock(&cdx_controller_lock); return count; @@ -640,11 +676,105 @@ static void cdx_device_release(struct device *dev) kfree(cdx_dev); } +static const struct vm_operations_struct cdx_phys_vm_ops = { +#ifdef CONFIG_HAVE_IOREMAP_PROT + .access = generic_access_phys, +#endif +}; + +/** + * cdx_mmap_resource - map a CDX resource into user memory space + * @fp: File pointer. Not used in this function, but required where + * this API is registered as a callback. + * @kobj: kobject for mapping + * @attr: struct bin_attribute for the file being mapped + * @vma: struct vm_area_struct passed into the mmap + * + * Use the regular CDX mapping routines to map a CDX resource into userspace. + * + * Return: true on success, false otherwise. + */ +static int cdx_mmap_resource(struct file *fp, struct kobject *kobj, + struct bin_attribute *attr, + struct vm_area_struct *vma) +{ + struct cdx_device *cdx_dev = to_cdx_device(kobj_to_dev(kobj)); + int num = (unsigned long)attr->private; + struct resource *res; + unsigned long size; + + res = &cdx_dev->res[num]; + if (iomem_is_exclusive(res->start)) + return -EINVAL; + + /* Make sure the caller is mapping a valid resource for this device */ + size = ((cdx_resource_len(cdx_dev, num) - 1) >> PAGE_SHIFT) + 1; + if (vma->vm_pgoff + vma_pages(vma) > size) + return -EINVAL; + + /* + * Map memory region and vm->vm_pgoff is expected to be an + * offset within that region. + */ + vma->vm_page_prot = pgprot_device(vma->vm_page_prot); + vma->vm_pgoff += (cdx_resource_start(cdx_dev, num) >> PAGE_SHIFT); + vma->vm_ops = &cdx_phys_vm_ops; + return io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, + vma->vm_end - vma->vm_start, + vma->vm_page_prot); +} + +static void cdx_destroy_res_attr(struct cdx_device *cdx_dev, int num) +{ + int i; + + /* removing the bin attributes */ + for (i = 0; i < num; i++) { + struct bin_attribute *res_attr; + + res_attr = cdx_dev->res_attr[i]; + if (res_attr) { + sysfs_remove_bin_file(&cdx_dev->dev.kobj, res_attr); + kfree(res_attr); + } + } +} + +#define CDX_RES_ATTR_NAME_LEN 10 +static int cdx_create_res_attr(struct cdx_device *cdx_dev, int num) +{ + struct bin_attribute *res_attr; + char *res_attr_name; + int ret; + + res_attr = kzalloc(sizeof(*res_attr) + CDX_RES_ATTR_NAME_LEN, GFP_ATOMIC); + if (!res_attr) + return -ENOMEM; + + res_attr_name = (char *)(res_attr + 1); + + sysfs_bin_attr_init(res_attr); + + cdx_dev->res_attr[num] = res_attr; + sprintf(res_attr_name, "resource%d", num); + + res_attr->mmap = cdx_mmap_resource; + res_attr->attr.name = res_attr_name; + res_attr->attr.mode = 0600; + res_attr->size = cdx_resource_len(cdx_dev, num); + res_attr->private = (void *)(unsigned long)num; + ret = sysfs_create_bin_file(&cdx_dev->dev.kobj, res_attr); + if (ret) + kfree(res_attr); + + return ret; +} + int cdx_device_add(struct cdx_dev_params *dev_params) { struct cdx_controller *cdx = dev_params->cdx; struct cdx_device *cdx_dev; - int ret; + int ret, i; cdx_dev = kzalloc(sizeof(*cdx_dev), GFP_KERNEL); if (!cdx_dev) @@ -687,7 +817,28 @@ int cdx_device_add(struct cdx_dev_params *dev_params) goto fail; } + /* Create resource attributes */ + for (i = 0; i < MAX_CDX_DEV_RESOURCES; i++) { + if (cdx_resource_flags(cdx_dev, i) & IORESOURCE_MEM) { + /* skip empty resources */ + if (!cdx_resource_len(cdx_dev, i)) + continue; + + ret = cdx_create_res_attr(cdx_dev, i); + if (ret != 0) { + dev_err(&cdx_dev->dev, + "cdx device resource<%d> file creation failed: %d", i, ret); + goto resource_create_fail; + } + } + } + + cdx_device_debugfs_init(cdx_dev); + return 0; +resource_create_fail: + cdx_destroy_res_attr(cdx_dev, i); + device_del(&cdx_dev->dev); fail: /* * Do not free cdx_dev here as it would be freed in @@ -788,6 +939,12 @@ EXPORT_SYMBOL_NS_GPL(cdx_unregister_controller, CDX_BUS_CONTROLLER); static int __init cdx_bus_init(void) { - return bus_register(&cdx_bus_type); + int ret; + + ret = bus_register(&cdx_bus_type); + if (!ret) + cdx_debugfs_dir = debugfs_create_dir(cdx_bus_type.name, NULL); + + return ret; } postcore_initcall(cdx_bus_init); diff --git a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile index 25834557e48653..43b09cf193bb7d 100644 --- a/drivers/char/agp/Makefile +++ b/drivers/char/agp/Makefile @@ -1,12 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 agpgart-y := backend.o generic.o isoch.o -ifeq ($(CONFIG_DRM_LEGACY),y) -agpgart-$(CONFIG_COMPAT) += compat_ioctl.o -agpgart-y += frontend.o -endif - - obj-$(CONFIG_AGP) += agpgart.o obj-$(CONFIG_AGP_ALI) += ali-agp.o obj-$(CONFIG_AGP_ATI) += ati-agp.o diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index 8771dcc9b8e2f7..5c36ab85f80b77 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -185,15 +185,6 @@ void agp_put_bridge(struct agp_bridge_data *bridge); int agp_add_bridge(struct agp_bridge_data *bridge); void agp_remove_bridge(struct agp_bridge_data *bridge); -/* Frontend routines. */ -#if IS_ENABLED(CONFIG_DRM_LEGACY) -int agp_frontend_initialize(void); -void agp_frontend_cleanup(void); -#else -static inline int agp_frontend_initialize(void) { return 0; } -static inline void agp_frontend_cleanup(void) {} -#endif - /* Generic routines. */ void agp_generic_enable(struct agp_bridge_data *bridge, u32 mode); int agp_generic_create_gatt_table(struct agp_bridge_data *bridge); diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c index 0e19c600db5318..1776afd3ee0785 100644 --- a/drivers/char/agp/backend.c +++ b/drivers/char/agp/backend.c @@ -293,13 +293,6 @@ int agp_add_bridge(struct agp_bridge_data *bridge) } if (list_empty(&agp_bridges)) { - error = agp_frontend_initialize(); - if (error) { - dev_info(&bridge->dev->dev, - "agp_frontend_initialize() failed\n"); - goto frontend_err; - } - dev_info(&bridge->dev->dev, "AGP aperture is %dM @ 0x%lx\n", bridge->driver->fetch_size(), bridge->gart_bus_addr); @@ -308,8 +301,6 @@ int agp_add_bridge(struct agp_bridge_data *bridge) list_add(&bridge->list, &agp_bridges); return 0; -frontend_err: - agp_backend_cleanup(bridge); err_out: module_put(bridge->driver->owner); err_put_bridge: @@ -323,8 +314,6 @@ void agp_remove_bridge(struct agp_bridge_data *bridge) { agp_backend_cleanup(bridge); list_del(&bridge->list); - if (list_empty(&agp_bridges)) - agp_frontend_cleanup(); module_put(bridge->driver->owner); } EXPORT_SYMBOL_GPL(agp_remove_bridge); diff --git a/drivers/char/agp/compat_ioctl.c b/drivers/char/agp/compat_ioctl.c deleted file mode 100644 index 52ffe1706ce051..00000000000000 --- a/drivers/char/agp/compat_ioctl.c +++ /dev/null @@ -1,291 +0,0 @@ -/* - * AGPGART driver frontend compatibility ioctls - * Copyright (C) 2004 Silicon Graphics, Inc. - * Copyright (C) 2002-2003 Dave Jones - * Copyright (C) 1999 Jeff Hartmann - * Copyright (C) 1999 Precision Insight, Inc. - * Copyright (C) 1999 Xi Graphics, 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 - * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS 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 -#include -#include -#include -#include -#include -#include "agp.h" -#include "compat_ioctl.h" - -static int compat_agpioc_info_wrap(struct agp_file_private *priv, void __user *arg) -{ - struct agp_info32 userinfo; - struct agp_kern_info kerninfo; - - agp_copy_info(agp_bridge, &kerninfo); - - userinfo.version.major = kerninfo.version.major; - userinfo.version.minor = kerninfo.version.minor; - userinfo.bridge_id = kerninfo.device->vendor | - (kerninfo.device->device << 16); - userinfo.agp_mode = kerninfo.mode; - userinfo.aper_base = (compat_long_t)kerninfo.aper_base; - userinfo.aper_size = kerninfo.aper_size; - userinfo.pg_total = userinfo.pg_system = kerninfo.max_memory; - userinfo.pg_used = kerninfo.current_memory; - - if (copy_to_user(arg, &userinfo, sizeof(userinfo))) - return -EFAULT; - - return 0; -} - -static int compat_agpioc_reserve_wrap(struct agp_file_private *priv, void __user *arg) -{ - struct agp_region32 ureserve; - struct agp_region kreserve; - struct agp_client *client; - struct agp_file_private *client_priv; - - DBG(""); - if (copy_from_user(&ureserve, arg, sizeof(ureserve))) - return -EFAULT; - - if ((unsigned) ureserve.seg_count >= ~0U/sizeof(struct agp_segment32)) - return -EFAULT; - - kreserve.pid = ureserve.pid; - kreserve.seg_count = ureserve.seg_count; - - client = agp_find_client_by_pid(kreserve.pid); - - if (kreserve.seg_count == 0) { - /* remove a client */ - client_priv = agp_find_private(kreserve.pid); - - if (client_priv != NULL) { - set_bit(AGP_FF_IS_CLIENT, &client_priv->access_flags); - set_bit(AGP_FF_IS_VALID, &client_priv->access_flags); - } - if (client == NULL) { - /* client is already removed */ - return 0; - } - return agp_remove_client(kreserve.pid); - } else { - struct agp_segment32 *usegment; - struct agp_segment *ksegment; - int seg; - - if (ureserve.seg_count >= 16384) - return -EINVAL; - - usegment = kmalloc_array(ureserve.seg_count, - sizeof(*usegment), - GFP_KERNEL); - if (!usegment) - return -ENOMEM; - - ksegment = kmalloc_array(kreserve.seg_count, - sizeof(*ksegment), - GFP_KERNEL); - if (!ksegment) { - kfree(usegment); - return -ENOMEM; - } - - if (copy_from_user(usegment, (void __user *) ureserve.seg_list, - sizeof(*usegment) * ureserve.seg_count)) { - kfree(usegment); - kfree(ksegment); - return -EFAULT; - } - - for (seg = 0; seg < ureserve.seg_count; seg++) { - ksegment[seg].pg_start = usegment[seg].pg_start; - ksegment[seg].pg_count = usegment[seg].pg_count; - ksegment[seg].prot = usegment[seg].prot; - } - - kfree(usegment); - kreserve.seg_list = ksegment; - - if (client == NULL) { - /* Create the client and add the segment */ - client = agp_create_client(kreserve.pid); - - if (client == NULL) { - kfree(ksegment); - return -ENOMEM; - } - client_priv = agp_find_private(kreserve.pid); - - if (client_priv != NULL) { - set_bit(AGP_FF_IS_CLIENT, &client_priv->access_flags); - set_bit(AGP_FF_IS_VALID, &client_priv->access_flags); - } - } - return agp_create_segment(client, &kreserve); - } - /* Will never really happen */ - return -EINVAL; -} - -static int compat_agpioc_allocate_wrap(struct agp_file_private *priv, void __user *arg) -{ - struct agp_memory *memory; - struct agp_allocate32 alloc; - - DBG(""); - if (copy_from_user(&alloc, arg, sizeof(alloc))) - return -EFAULT; - - memory = agp_allocate_memory_wrap(alloc.pg_count, alloc.type); - - if (memory == NULL) - return -ENOMEM; - - alloc.key = memory->key; - alloc.physical = memory->physical; - - if (copy_to_user(arg, &alloc, sizeof(alloc))) { - agp_free_memory_wrap(memory); - return -EFAULT; - } - return 0; -} - -static int compat_agpioc_bind_wrap(struct agp_file_private *priv, void __user *arg) -{ - struct agp_bind32 bind_info; - struct agp_memory *memory; - - DBG(""); - if (copy_from_user(&bind_info, arg, sizeof(bind_info))) - return -EFAULT; - - memory = agp_find_mem_by_key(bind_info.key); - - if (memory == NULL) - return -EINVAL; - - return agp_bind_memory(memory, bind_info.pg_start); -} - -static int compat_agpioc_unbind_wrap(struct agp_file_private *priv, void __user *arg) -{ - struct agp_memory *memory; - struct agp_unbind32 unbind; - - DBG(""); - if (copy_from_user(&unbind, arg, sizeof(unbind))) - return -EFAULT; - - memory = agp_find_mem_by_key(unbind.key); - - if (memory == NULL) - return -EINVAL; - - return agp_unbind_memory(memory); -} - -long compat_agp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct agp_file_private *curr_priv = file->private_data; - int ret_val = -ENOTTY; - - mutex_lock(&(agp_fe.agp_mutex)); - - if ((agp_fe.current_controller == NULL) && - (cmd != AGPIOC_ACQUIRE32)) { - ret_val = -EINVAL; - goto ioctl_out; - } - if ((agp_fe.backend_acquired != true) && - (cmd != AGPIOC_ACQUIRE32)) { - ret_val = -EBUSY; - goto ioctl_out; - } - if (cmd != AGPIOC_ACQUIRE32) { - if (!(test_bit(AGP_FF_IS_CONTROLLER, &curr_priv->access_flags))) { - ret_val = -EPERM; - goto ioctl_out; - } - /* Use the original pid of the controller, - * in case it's threaded */ - - if (agp_fe.current_controller->pid != curr_priv->my_pid) { - ret_val = -EBUSY; - goto ioctl_out; - } - } - - switch (cmd) { - case AGPIOC_INFO32: - ret_val = compat_agpioc_info_wrap(curr_priv, (void __user *) arg); - break; - - case AGPIOC_ACQUIRE32: - ret_val = agpioc_acquire_wrap(curr_priv); - break; - - case AGPIOC_RELEASE32: - ret_val = agpioc_release_wrap(curr_priv); - break; - - case AGPIOC_SETUP32: - ret_val = agpioc_setup_wrap(curr_priv, (void __user *) arg); - break; - - case AGPIOC_RESERVE32: - ret_val = compat_agpioc_reserve_wrap(curr_priv, (void __user *) arg); - break; - - case AGPIOC_PROTECT32: - ret_val = agpioc_protect_wrap(curr_priv); - break; - - case AGPIOC_ALLOCATE32: - ret_val = compat_agpioc_allocate_wrap(curr_priv, (void __user *) arg); - break; - - case AGPIOC_DEALLOCATE32: - ret_val = agpioc_deallocate_wrap(curr_priv, (int) arg); - break; - - case AGPIOC_BIND32: - ret_val = compat_agpioc_bind_wrap(curr_priv, (void __user *) arg); - break; - - case AGPIOC_UNBIND32: - ret_val = compat_agpioc_unbind_wrap(curr_priv, (void __user *) arg); - break; - - case AGPIOC_CHIPSET_FLUSH32: - break; - } - -ioctl_out: - DBG("ioctl returns %d\n", ret_val); - mutex_unlock(&(agp_fe.agp_mutex)); - return ret_val; -} - diff --git a/drivers/char/agp/compat_ioctl.h b/drivers/char/agp/compat_ioctl.h deleted file mode 100644 index f30e0fd9796353..00000000000000 --- a/drivers/char/agp/compat_ioctl.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 1999 Jeff Hartmann - * Copyright (C) 1999 Precision Insight, Inc. - * Copyright (C) 1999 Xi Graphics, 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 - * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS 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 _AGP_COMPAT_IOCTL_H -#define _AGP_COMPAT_IOCTL_H - -#include -#include - -#define AGPIOC_INFO32 _IOR (AGPIOC_BASE, 0, compat_uptr_t) -#define AGPIOC_ACQUIRE32 _IO (AGPIOC_BASE, 1) -#define AGPIOC_RELEASE32 _IO (AGPIOC_BASE, 2) -#define AGPIOC_SETUP32 _IOW (AGPIOC_BASE, 3, compat_uptr_t) -#define AGPIOC_RESERVE32 _IOW (AGPIOC_BASE, 4, compat_uptr_t) -#define AGPIOC_PROTECT32 _IOW (AGPIOC_BASE, 5, compat_uptr_t) -#define AGPIOC_ALLOCATE32 _IOWR(AGPIOC_BASE, 6, compat_uptr_t) -#define AGPIOC_DEALLOCATE32 _IOW (AGPIOC_BASE, 7, compat_int_t) -#define AGPIOC_BIND32 _IOW (AGPIOC_BASE, 8, compat_uptr_t) -#define AGPIOC_UNBIND32 _IOW (AGPIOC_BASE, 9, compat_uptr_t) -#define AGPIOC_CHIPSET_FLUSH32 _IO (AGPIOC_BASE, 10) - -struct agp_info32 { - struct agp_version version; /* version of the driver */ - u32 bridge_id; /* bridge vendor/device */ - u32 agp_mode; /* mode info of bridge */ - compat_long_t aper_base; /* base of aperture */ - compat_size_t aper_size; /* size of aperture */ - compat_size_t pg_total; /* max pages (swap + system) */ - compat_size_t pg_system; /* max pages (system) */ - compat_size_t pg_used; /* current pages used */ -}; - -/* - * The "prot" down below needs still a "sleep" flag somehow ... - */ -struct agp_segment32 { - compat_off_t pg_start; /* starting page to populate */ - compat_size_t pg_count; /* number of pages */ - compat_int_t prot; /* prot flags for mmap */ -}; - -struct agp_region32 { - compat_pid_t pid; /* pid of process */ - compat_size_t seg_count; /* number of segments */ - struct agp_segment32 *seg_list; -}; - -struct agp_allocate32 { - compat_int_t key; /* tag of allocation */ - compat_size_t pg_count; /* number of pages */ - u32 type; /* 0 == normal, other devspec */ - u32 physical; /* device specific (some devices - * need a phys address of the - * actual page behind the gatt - * table) */ -}; - -struct agp_bind32 { - compat_int_t key; /* tag of allocation */ - compat_off_t pg_start; /* starting page to populate */ -}; - -struct agp_unbind32 { - compat_int_t key; /* tag of allocation */ - u32 priority; /* priority for paging out */ -}; - -extern struct agp_front_data agp_fe; - -int agpioc_acquire_wrap(struct agp_file_private *priv); -int agpioc_release_wrap(struct agp_file_private *priv); -int agpioc_protect_wrap(struct agp_file_private *priv); -int agpioc_setup_wrap(struct agp_file_private *priv, void __user *arg); -int agpioc_deallocate_wrap(struct agp_file_private *priv, int arg); -struct agp_file_private *agp_find_private(pid_t pid); -struct agp_client *agp_create_client(pid_t id); -int agp_remove_client(pid_t id); -int agp_create_segment(struct agp_client *client, struct agp_region *region); -void agp_free_memory_wrap(struct agp_memory *memory); -struct agp_memory *agp_allocate_memory_wrap(size_t pg_count, u32 type); -struct agp_memory *agp_find_mem_by_key(int key); -struct agp_client *agp_find_client_by_pid(pid_t id); - -#endif /* _AGP_COMPAT_H */ diff --git a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c deleted file mode 100644 index 321118a9cfa52b..00000000000000 --- a/drivers/char/agp/frontend.c +++ /dev/null @@ -1,1068 +0,0 @@ -/* - * AGPGART driver frontend - * Copyright (C) 2004 Silicon Graphics, Inc. - * Copyright (C) 2002-2003 Dave Jones - * Copyright (C) 1999 Jeff Hartmann - * Copyright (C) 1999 Precision Insight, Inc. - * Copyright (C) 1999 Xi Graphics, 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 - * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "agp.h" -#include "compat_ioctl.h" - -struct agp_front_data agp_fe; - -struct agp_memory *agp_find_mem_by_key(int key) -{ - struct agp_memory *curr; - - if (agp_fe.current_controller == NULL) - return NULL; - - curr = agp_fe.current_controller->pool; - - while (curr != NULL) { - if (curr->key == key) - break; - curr = curr->next; - } - - DBG("key=%d -> mem=%p", key, curr); - return curr; -} - -static void agp_remove_from_pool(struct agp_memory *temp) -{ - struct agp_memory *prev; - struct agp_memory *next; - - /* Check to see if this is even in the memory pool */ - - DBG("mem=%p", temp); - if (agp_find_mem_by_key(temp->key) != NULL) { - next = temp->next; - prev = temp->prev; - - if (prev != NULL) { - prev->next = next; - if (next != NULL) - next->prev = prev; - - } else { - /* This is the first item on the list */ - if (next != NULL) - next->prev = NULL; - - agp_fe.current_controller->pool = next; - } - } -} - -/* - * Routines for managing each client's segment list - - * These routines handle adding and removing segments - * to each auth'ed client. - */ - -static struct -agp_segment_priv *agp_find_seg_in_client(const struct agp_client *client, - unsigned long offset, - int size, pgprot_t page_prot) -{ - struct agp_segment_priv *seg; - int i; - off_t pg_start; - size_t pg_count; - - pg_start = offset / 4096; - pg_count = size / 4096; - seg = *(client->segments); - - for (i = 0; i < client->num_segments; i++) { - if ((seg[i].pg_start == pg_start) && - (seg[i].pg_count == pg_count) && - (pgprot_val(seg[i].prot) == pgprot_val(page_prot))) { - return seg + i; - } - } - - return NULL; -} - -static void agp_remove_seg_from_client(struct agp_client *client) -{ - DBG("client=%p", client); - - if (client->segments != NULL) { - if (*(client->segments) != NULL) { - DBG("Freeing %p from client %p", *(client->segments), client); - kfree(*(client->segments)); - } - DBG("Freeing %p from client %p", client->segments, client); - kfree(client->segments); - client->segments = NULL; - } -} - -static void agp_add_seg_to_client(struct agp_client *client, - struct agp_segment_priv ** seg, int num_segments) -{ - struct agp_segment_priv **prev_seg; - - prev_seg = client->segments; - - if (prev_seg != NULL) - agp_remove_seg_from_client(client); - - DBG("Adding seg %p (%d segments) to client %p", seg, num_segments, client); - client->num_segments = num_segments; - client->segments = seg; -} - -static pgprot_t agp_convert_mmap_flags(int prot) -{ - unsigned long prot_bits; - - prot_bits = calc_vm_prot_bits(prot, 0) | VM_SHARED; - return vm_get_page_prot(prot_bits); -} - -int agp_create_segment(struct agp_client *client, struct agp_region *region) -{ - struct agp_segment_priv **ret_seg; - struct agp_segment_priv *seg; - struct agp_segment *user_seg; - size_t i; - - seg = kzalloc((sizeof(struct agp_segment_priv) * region->seg_count), GFP_KERNEL); - if (seg == NULL) { - kfree(region->seg_list); - region->seg_list = NULL; - return -ENOMEM; - } - user_seg = region->seg_list; - - for (i = 0; i < region->seg_count; i++) { - seg[i].pg_start = user_seg[i].pg_start; - seg[i].pg_count = user_seg[i].pg_count; - seg[i].prot = agp_convert_mmap_flags(user_seg[i].prot); - } - kfree(region->seg_list); - region->seg_list = NULL; - - ret_seg = kmalloc(sizeof(void *), GFP_KERNEL); - if (ret_seg == NULL) { - kfree(seg); - return -ENOMEM; - } - *ret_seg = seg; - agp_add_seg_to_client(client, ret_seg, region->seg_count); - return 0; -} - -/* End - Routines for managing each client's segment list */ - -/* This function must only be called when current_controller != NULL */ -static void agp_insert_into_pool(struct agp_memory * temp) -{ - struct agp_memory *prev; - - prev = agp_fe.current_controller->pool; - - if (prev != NULL) { - prev->prev = temp; - temp->next = prev; - } - agp_fe.current_controller->pool = temp; -} - - -/* File private list routines */ - -struct agp_file_private *agp_find_private(pid_t pid) -{ - struct agp_file_private *curr; - - curr = agp_fe.file_priv_list; - - while (curr != NULL) { - if (curr->my_pid == pid) - return curr; - curr = curr->next; - } - - return NULL; -} - -static void agp_insert_file_private(struct agp_file_private * priv) -{ - struct agp_file_private *prev; - - prev = agp_fe.file_priv_list; - - if (prev != NULL) - prev->prev = priv; - priv->next = prev; - agp_fe.file_priv_list = priv; -} - -static void agp_remove_file_private(struct agp_file_private * priv) -{ - struct agp_file_private *next; - struct agp_file_private *prev; - - next = priv->next; - prev = priv->prev; - - if (prev != NULL) { - prev->next = next; - - if (next != NULL) - next->prev = prev; - - } else { - if (next != NULL) - next->prev = NULL; - - agp_fe.file_priv_list = next; - } -} - -/* End - File flag list routines */ - -/* - * Wrappers for agp_free_memory & agp_allocate_memory - * These make sure that internal lists are kept updated. - */ -void agp_free_memory_wrap(struct agp_memory *memory) -{ - agp_remove_from_pool(memory); - agp_free_memory(memory); -} - -struct agp_memory *agp_allocate_memory_wrap(size_t pg_count, u32 type) -{ - struct agp_memory *memory; - - memory = agp_allocate_memory(agp_bridge, pg_count, type); - if (memory == NULL) - return NULL; - - agp_insert_into_pool(memory); - return memory; -} - -/* Routines for managing the list of controllers - - * These routines manage the current controller, and the list of - * controllers - */ - -static struct agp_controller *agp_find_controller_by_pid(pid_t id) -{ - struct agp_controller *controller; - - controller = agp_fe.controllers; - - while (controller != NULL) { - if (controller->pid == id) - return controller; - controller = controller->next; - } - - return NULL; -} - -static struct agp_controller *agp_create_controller(pid_t id) -{ - struct agp_controller *controller; - - controller = kzalloc(sizeof(struct agp_controller), GFP_KERNEL); - if (controller == NULL) - return NULL; - - controller->pid = id; - return controller; -} - -static int agp_insert_controller(struct agp_controller *controller) -{ - struct agp_controller *prev_controller; - - prev_controller = agp_fe.controllers; - controller->next = prev_controller; - - if (prev_controller != NULL) - prev_controller->prev = controller; - - agp_fe.controllers = controller; - - return 0; -} - -static void agp_remove_all_clients(struct agp_controller *controller) -{ - struct agp_client *client; - struct agp_client *temp; - - client = controller->clients; - - while (client) { - struct agp_file_private *priv; - - temp = client; - agp_remove_seg_from_client(temp); - priv = agp_find_private(temp->pid); - - if (priv != NULL) { - clear_bit(AGP_FF_IS_VALID, &priv->access_flags); - clear_bit(AGP_FF_IS_CLIENT, &priv->access_flags); - } - client = client->next; - kfree(temp); - } -} - -static void agp_remove_all_memory(struct agp_controller *controller) -{ - struct agp_memory *memory; - struct agp_memory *temp; - - memory = controller->pool; - - while (memory) { - temp = memory; - memory = memory->next; - agp_free_memory_wrap(temp); - } -} - -static int agp_remove_controller(struct agp_controller *controller) -{ - struct agp_controller *prev_controller; - struct agp_controller *next_controller; - - prev_controller = controller->prev; - next_controller = controller->next; - - if (prev_controller != NULL) { - prev_controller->next = next_controller; - if (next_controller != NULL) - next_controller->prev = prev_controller; - - } else { - if (next_controller != NULL) - next_controller->prev = NULL; - - agp_fe.controllers = next_controller; - } - - agp_remove_all_memory(controller); - agp_remove_all_clients(controller); - - if (agp_fe.current_controller == controller) { - agp_fe.current_controller = NULL; - agp_fe.backend_acquired = false; - agp_backend_release(agp_bridge); - } - kfree(controller); - return 0; -} - -static void agp_controller_make_current(struct agp_controller *controller) -{ - struct agp_client *clients; - - clients = controller->clients; - - while (clients != NULL) { - struct agp_file_private *priv; - - priv = agp_find_private(clients->pid); - - if (priv != NULL) { - set_bit(AGP_FF_IS_VALID, &priv->access_flags); - set_bit(AGP_FF_IS_CLIENT, &priv->access_flags); - } - clients = clients->next; - } - - agp_fe.current_controller = controller; -} - -static void agp_controller_release_current(struct agp_controller *controller, - struct agp_file_private *controller_priv) -{ - struct agp_client *clients; - - clear_bit(AGP_FF_IS_VALID, &controller_priv->access_flags); - clients = controller->clients; - - while (clients != NULL) { - struct agp_file_private *priv; - - priv = agp_find_private(clients->pid); - - if (priv != NULL) - clear_bit(AGP_FF_IS_VALID, &priv->access_flags); - - clients = clients->next; - } - - agp_fe.current_controller = NULL; - agp_fe.used_by_controller = false; - agp_backend_release(agp_bridge); -} - -/* - * Routines for managing client lists - - * These routines are for managing the list of auth'ed clients. - */ - -static struct agp_client -*agp_find_client_in_controller(struct agp_controller *controller, pid_t id) -{ - struct agp_client *client; - - if (controller == NULL) - return NULL; - - client = controller->clients; - - while (client != NULL) { - if (client->pid == id) - return client; - client = client->next; - } - - return NULL; -} - -static struct agp_controller *agp_find_controller_for_client(pid_t id) -{ - struct agp_controller *controller; - - controller = agp_fe.controllers; - - while (controller != NULL) { - if ((agp_find_client_in_controller(controller, id)) != NULL) - return controller; - controller = controller->next; - } - - return NULL; -} - -struct agp_client *agp_find_client_by_pid(pid_t id) -{ - struct agp_client *temp; - - if (agp_fe.current_controller == NULL) - return NULL; - - temp = agp_find_client_in_controller(agp_fe.current_controller, id); - return temp; -} - -static void agp_insert_client(struct agp_client *client) -{ - struct agp_client *prev_client; - - prev_client = agp_fe.current_controller->clients; - client->next = prev_client; - - if (prev_client != NULL) - prev_client->prev = client; - - agp_fe.current_controller->clients = client; - agp_fe.current_controller->num_clients++; -} - -struct agp_client *agp_create_client(pid_t id) -{ - struct agp_client *new_client; - - new_client = kzalloc(sizeof(struct agp_client), GFP_KERNEL); - if (new_client == NULL) - return NULL; - - new_client->pid = id; - agp_insert_client(new_client); - return new_client; -} - -int agp_remove_client(pid_t id) -{ - struct agp_client *client; - struct agp_client *prev_client; - struct agp_client *next_client; - struct agp_controller *controller; - - controller = agp_find_controller_for_client(id); - if (controller == NULL) - return -EINVAL; - - client = agp_find_client_in_controller(controller, id); - if (client == NULL) - return -EINVAL; - - prev_client = client->prev; - next_client = client->next; - - if (prev_client != NULL) { - prev_client->next = next_client; - if (next_client != NULL) - next_client->prev = prev_client; - - } else { - if (next_client != NULL) - next_client->prev = NULL; - controller->clients = next_client; - } - - controller->num_clients--; - agp_remove_seg_from_client(client); - kfree(client); - return 0; -} - -/* End - Routines for managing client lists */ - -/* File Operations */ - -static int agp_mmap(struct file *file, struct vm_area_struct *vma) -{ - unsigned int size, current_size; - unsigned long offset; - struct agp_client *client; - struct agp_file_private *priv = file->private_data; - struct agp_kern_info kerninfo; - - mutex_lock(&(agp_fe.agp_mutex)); - - if (agp_fe.backend_acquired != true) - goto out_eperm; - - if (!(test_bit(AGP_FF_IS_VALID, &priv->access_flags))) - goto out_eperm; - - agp_copy_info(agp_bridge, &kerninfo); - size = vma->vm_end - vma->vm_start; - current_size = kerninfo.aper_size; - current_size = current_size * 0x100000; - offset = vma->vm_pgoff << PAGE_SHIFT; - DBG("%lx:%lx", offset, offset+size); - - if (test_bit(AGP_FF_IS_CLIENT, &priv->access_flags)) { - if ((size + offset) > current_size) - goto out_inval; - - client = agp_find_client_by_pid(current->pid); - - if (client == NULL) - goto out_eperm; - - if (!agp_find_seg_in_client(client, offset, size, vma->vm_page_prot)) - goto out_inval; - - DBG("client vm_ops=%p", kerninfo.vm_ops); - if (kerninfo.vm_ops) { - vma->vm_ops = kerninfo.vm_ops; - } else if (io_remap_pfn_range(vma, vma->vm_start, - (kerninfo.aper_base + offset) >> PAGE_SHIFT, - size, - pgprot_writecombine(vma->vm_page_prot))) { - goto out_again; - } - mutex_unlock(&(agp_fe.agp_mutex)); - return 0; - } - - if (test_bit(AGP_FF_IS_CONTROLLER, &priv->access_flags)) { - if (size != current_size) - goto out_inval; - - DBG("controller vm_ops=%p", kerninfo.vm_ops); - if (kerninfo.vm_ops) { - vma->vm_ops = kerninfo.vm_ops; - } else if (io_remap_pfn_range(vma, vma->vm_start, - kerninfo.aper_base >> PAGE_SHIFT, - size, - pgprot_writecombine(vma->vm_page_prot))) { - goto out_again; - } - mutex_unlock(&(agp_fe.agp_mutex)); - return 0; - } - -out_eperm: - mutex_unlock(&(agp_fe.agp_mutex)); - return -EPERM; - -out_inval: - mutex_unlock(&(agp_fe.agp_mutex)); - return -EINVAL; - -out_again: - mutex_unlock(&(agp_fe.agp_mutex)); - return -EAGAIN; -} - -static int agp_release(struct inode *inode, struct file *file) -{ - struct agp_file_private *priv = file->private_data; - - mutex_lock(&(agp_fe.agp_mutex)); - - DBG("priv=%p", priv); - - if (test_bit(AGP_FF_IS_CONTROLLER, &priv->access_flags)) { - struct agp_controller *controller; - - controller = agp_find_controller_by_pid(priv->my_pid); - - if (controller != NULL) { - if (controller == agp_fe.current_controller) - agp_controller_release_current(controller, priv); - agp_remove_controller(controller); - controller = NULL; - } - } - - if (test_bit(AGP_FF_IS_CLIENT, &priv->access_flags)) - agp_remove_client(priv->my_pid); - - agp_remove_file_private(priv); - kfree(priv); - file->private_data = NULL; - mutex_unlock(&(agp_fe.agp_mutex)); - return 0; -} - -static int agp_open(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - struct agp_file_private *priv; - struct agp_client *client; - - if (minor != AGPGART_MINOR) - return -ENXIO; - - mutex_lock(&(agp_fe.agp_mutex)); - - priv = kzalloc(sizeof(struct agp_file_private), GFP_KERNEL); - if (priv == NULL) { - mutex_unlock(&(agp_fe.agp_mutex)); - return -ENOMEM; - } - - set_bit(AGP_FF_ALLOW_CLIENT, &priv->access_flags); - priv->my_pid = current->pid; - - if (capable(CAP_SYS_RAWIO)) - /* Root priv, can be controller */ - set_bit(AGP_FF_ALLOW_CONTROLLER, &priv->access_flags); - - client = agp_find_client_by_pid(current->pid); - - if (client != NULL) { - set_bit(AGP_FF_IS_CLIENT, &priv->access_flags); - set_bit(AGP_FF_IS_VALID, &priv->access_flags); - } - file->private_data = (void *) priv; - agp_insert_file_private(priv); - DBG("private=%p, client=%p", priv, client); - - mutex_unlock(&(agp_fe.agp_mutex)); - - return 0; -} - -static int agpioc_info_wrap(struct agp_file_private *priv, void __user *arg) -{ - struct agp_info userinfo; - struct agp_kern_info kerninfo; - - agp_copy_info(agp_bridge, &kerninfo); - - memset(&userinfo, 0, sizeof(userinfo)); - userinfo.version.major = kerninfo.version.major; - userinfo.version.minor = kerninfo.version.minor; - userinfo.bridge_id = kerninfo.device->vendor | - (kerninfo.device->device << 16); - userinfo.agp_mode = kerninfo.mode; - userinfo.aper_base = kerninfo.aper_base; - userinfo.aper_size = kerninfo.aper_size; - userinfo.pg_total = userinfo.pg_system = kerninfo.max_memory; - userinfo.pg_used = kerninfo.current_memory; - - if (copy_to_user(arg, &userinfo, sizeof(struct agp_info))) - return -EFAULT; - - return 0; -} - -int agpioc_acquire_wrap(struct agp_file_private *priv) -{ - struct agp_controller *controller; - - DBG(""); - - if (!(test_bit(AGP_FF_ALLOW_CONTROLLER, &priv->access_flags))) - return -EPERM; - - if (agp_fe.current_controller != NULL) - return -EBUSY; - - if (!agp_bridge) - return -ENODEV; - - if (atomic_read(&agp_bridge->agp_in_use)) - return -EBUSY; - - atomic_inc(&agp_bridge->agp_in_use); - - agp_fe.backend_acquired = true; - - controller = agp_find_controller_by_pid(priv->my_pid); - - if (controller != NULL) { - agp_controller_make_current(controller); - } else { - controller = agp_create_controller(priv->my_pid); - - if (controller == NULL) { - agp_fe.backend_acquired = false; - agp_backend_release(agp_bridge); - return -ENOMEM; - } - agp_insert_controller(controller); - agp_controller_make_current(controller); - } - - set_bit(AGP_FF_IS_CONTROLLER, &priv->access_flags); - set_bit(AGP_FF_IS_VALID, &priv->access_flags); - return 0; -} - -int agpioc_release_wrap(struct agp_file_private *priv) -{ - DBG(""); - agp_controller_release_current(agp_fe.current_controller, priv); - return 0; -} - -int agpioc_setup_wrap(struct agp_file_private *priv, void __user *arg) -{ - struct agp_setup mode; - - DBG(""); - if (copy_from_user(&mode, arg, sizeof(struct agp_setup))) - return -EFAULT; - - agp_enable(agp_bridge, mode.agp_mode); - return 0; -} - -static int agpioc_reserve_wrap(struct agp_file_private *priv, void __user *arg) -{ - struct agp_region reserve; - struct agp_client *client; - struct agp_file_private *client_priv; - - DBG(""); - if (copy_from_user(&reserve, arg, sizeof(struct agp_region))) - return -EFAULT; - - if ((unsigned) reserve.seg_count >= ~0U/sizeof(struct agp_segment)) - return -EFAULT; - - client = agp_find_client_by_pid(reserve.pid); - - if (reserve.seg_count == 0) { - /* remove a client */ - client_priv = agp_find_private(reserve.pid); - - if (client_priv != NULL) { - set_bit(AGP_FF_IS_CLIENT, &client_priv->access_flags); - set_bit(AGP_FF_IS_VALID, &client_priv->access_flags); - } - if (client == NULL) { - /* client is already removed */ - return 0; - } - return agp_remove_client(reserve.pid); - } else { - struct agp_segment *segment; - - if (reserve.seg_count >= 16384) - return -EINVAL; - - segment = kmalloc((sizeof(struct agp_segment) * reserve.seg_count), - GFP_KERNEL); - - if (segment == NULL) - return -ENOMEM; - - if (copy_from_user(segment, (void __user *) reserve.seg_list, - sizeof(struct agp_segment) * reserve.seg_count)) { - kfree(segment); - return -EFAULT; - } - reserve.seg_list = segment; - - if (client == NULL) { - /* Create the client and add the segment */ - client = agp_create_client(reserve.pid); - - if (client == NULL) { - kfree(segment); - return -ENOMEM; - } - client_priv = agp_find_private(reserve.pid); - - if (client_priv != NULL) { - set_bit(AGP_FF_IS_CLIENT, &client_priv->access_flags); - set_bit(AGP_FF_IS_VALID, &client_priv->access_flags); - } - } - return agp_create_segment(client, &reserve); - } - /* Will never really happen */ - return -EINVAL; -} - -int agpioc_protect_wrap(struct agp_file_private *priv) -{ - DBG(""); - /* This function is not currently implemented */ - return -EINVAL; -} - -static int agpioc_allocate_wrap(struct agp_file_private *priv, void __user *arg) -{ - struct agp_memory *memory; - struct agp_allocate alloc; - - DBG(""); - if (copy_from_user(&alloc, arg, sizeof(struct agp_allocate))) - return -EFAULT; - - if (alloc.type >= AGP_USER_TYPES) - return -EINVAL; - - memory = agp_allocate_memory_wrap(alloc.pg_count, alloc.type); - - if (memory == NULL) - return -ENOMEM; - - alloc.key = memory->key; - alloc.physical = memory->physical; - - if (copy_to_user(arg, &alloc, sizeof(struct agp_allocate))) { - agp_free_memory_wrap(memory); - return -EFAULT; - } - return 0; -} - -int agpioc_deallocate_wrap(struct agp_file_private *priv, int arg) -{ - struct agp_memory *memory; - - DBG(""); - memory = agp_find_mem_by_key(arg); - - if (memory == NULL) - return -EINVAL; - - agp_free_memory_wrap(memory); - return 0; -} - -static int agpioc_bind_wrap(struct agp_file_private *priv, void __user *arg) -{ - struct agp_bind bind_info; - struct agp_memory *memory; - - DBG(""); - if (copy_from_user(&bind_info, arg, sizeof(struct agp_bind))) - return -EFAULT; - - memory = agp_find_mem_by_key(bind_info.key); - - if (memory == NULL) - return -EINVAL; - - return agp_bind_memory(memory, bind_info.pg_start); -} - -static int agpioc_unbind_wrap(struct agp_file_private *priv, void __user *arg) -{ - struct agp_memory *memory; - struct agp_unbind unbind; - - DBG(""); - if (copy_from_user(&unbind, arg, sizeof(struct agp_unbind))) - return -EFAULT; - - memory = agp_find_mem_by_key(unbind.key); - - if (memory == NULL) - return -EINVAL; - - return agp_unbind_memory(memory); -} - -static long agp_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct agp_file_private *curr_priv = file->private_data; - int ret_val = -ENOTTY; - - DBG("priv=%p, cmd=%x", curr_priv, cmd); - mutex_lock(&(agp_fe.agp_mutex)); - - if ((agp_fe.current_controller == NULL) && - (cmd != AGPIOC_ACQUIRE)) { - ret_val = -EINVAL; - goto ioctl_out; - } - if ((agp_fe.backend_acquired != true) && - (cmd != AGPIOC_ACQUIRE)) { - ret_val = -EBUSY; - goto ioctl_out; - } - if (cmd != AGPIOC_ACQUIRE) { - if (!(test_bit(AGP_FF_IS_CONTROLLER, &curr_priv->access_flags))) { - ret_val = -EPERM; - goto ioctl_out; - } - /* Use the original pid of the controller, - * in case it's threaded */ - - if (agp_fe.current_controller->pid != curr_priv->my_pid) { - ret_val = -EBUSY; - goto ioctl_out; - } - } - - switch (cmd) { - case AGPIOC_INFO: - ret_val = agpioc_info_wrap(curr_priv, (void __user *) arg); - break; - - case AGPIOC_ACQUIRE: - ret_val = agpioc_acquire_wrap(curr_priv); - break; - - case AGPIOC_RELEASE: - ret_val = agpioc_release_wrap(curr_priv); - break; - - case AGPIOC_SETUP: - ret_val = agpioc_setup_wrap(curr_priv, (void __user *) arg); - break; - - case AGPIOC_RESERVE: - ret_val = agpioc_reserve_wrap(curr_priv, (void __user *) arg); - break; - - case AGPIOC_PROTECT: - ret_val = agpioc_protect_wrap(curr_priv); - break; - - case AGPIOC_ALLOCATE: - ret_val = agpioc_allocate_wrap(curr_priv, (void __user *) arg); - break; - - case AGPIOC_DEALLOCATE: - ret_val = agpioc_deallocate_wrap(curr_priv, (int) arg); - break; - - case AGPIOC_BIND: - ret_val = agpioc_bind_wrap(curr_priv, (void __user *) arg); - break; - - case AGPIOC_UNBIND: - ret_val = agpioc_unbind_wrap(curr_priv, (void __user *) arg); - break; - - case AGPIOC_CHIPSET_FLUSH: - break; - } - -ioctl_out: - DBG("ioctl returns %d\n", ret_val); - mutex_unlock(&(agp_fe.agp_mutex)); - return ret_val; -} - -static const struct file_operations agp_fops = -{ - .owner = THIS_MODULE, - .llseek = no_llseek, - .unlocked_ioctl = agp_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = compat_agp_ioctl, -#endif - .mmap = agp_mmap, - .open = agp_open, - .release = agp_release, -}; - -static struct miscdevice agp_miscdev = -{ - .minor = AGPGART_MINOR, - .name = "agpgart", - .fops = &agp_fops -}; - -int agp_frontend_initialize(void) -{ - memset(&agp_fe, 0, sizeof(struct agp_front_data)); - mutex_init(&(agp_fe.agp_mutex)); - - if (misc_register(&agp_miscdev)) { - printk(KERN_ERR PFX "unable to get minor: %d\n", AGPGART_MINOR); - return -EIO; - } - return 0; -} - -void agp_frontend_cleanup(void) -{ - misc_deregister(&agp_miscdev); -} diff --git a/drivers/char/hw_random/atmel-rng.c b/drivers/char/hw_random/atmel-rng.c index a37367ebcbacf8..e9157255f8513c 100644 --- a/drivers/char/hw_random/atmel-rng.c +++ b/drivers/char/hw_random/atmel-rng.c @@ -161,15 +161,13 @@ static int atmel_trng_probe(struct platform_device *pdev) return ret; } -static int atmel_trng_remove(struct platform_device *pdev) +static void atmel_trng_remove(struct platform_device *pdev) { struct atmel_trng *trng = platform_get_drvdata(pdev); atmel_trng_cleanup(trng); pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); - - return 0; } static int __maybe_unused atmel_trng_runtime_suspend(struct device *dev) @@ -218,7 +216,7 @@ MODULE_DEVICE_TABLE(of, atmel_trng_dt_ids); static struct platform_driver atmel_trng_driver = { .probe = atmel_trng_probe, - .remove = atmel_trng_remove, + .remove_new = atmel_trng_remove, .driver = { .name = "atmel-trng", .pm = pm_ptr(&atmel_trng_pm_ops), diff --git a/drivers/char/hw_random/cctrng.c b/drivers/char/hw_random/cctrng.c index 1abbff04a015a5..c0d2f824769f88 100644 --- a/drivers/char/hw_random/cctrng.c +++ b/drivers/char/hw_random/cctrng.c @@ -560,7 +560,7 @@ post_pm_err: return rc; } -static int cctrng_remove(struct platform_device *pdev) +static void cctrng_remove(struct platform_device *pdev) { struct cctrng_drvdata *drvdata = platform_get_drvdata(pdev); struct device *dev = &pdev->dev; @@ -570,8 +570,6 @@ static int cctrng_remove(struct platform_device *pdev) cc_trng_pm_fini(drvdata); dev_info(dev, "ARM cctrng device terminated\n"); - - return 0; } static int __maybe_unused cctrng_suspend(struct device *dev) @@ -654,7 +652,7 @@ static struct platform_driver cctrng_driver = { .pm = &cctrng_pm, }, .probe = cctrng_probe, - .remove = cctrng_remove, + .remove_new = cctrng_remove, }; module_platform_driver(cctrng_driver); diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 420f155d251fb5..a3bbdd6e60fca2 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -23,10 +23,13 @@ #include #include #include +#include #include #define RNG_MODULE_NAME "hw_random" +#define RNG_BUFFER_SIZE (SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES) + static struct hwrng *current_rng; /* the current rng has been explicitly chosen by user via sysfs */ static int cur_rng_set_by_user; @@ -58,7 +61,7 @@ static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size, static size_t rng_buffer_size(void) { - return SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES; + return RNG_BUFFER_SIZE; } static void add_early_randomness(struct hwrng *rng) @@ -209,6 +212,7 @@ static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size, static ssize_t rng_dev_read(struct file *filp, char __user *buf, size_t size, loff_t *offp) { + u8 buffer[RNG_BUFFER_SIZE]; ssize_t ret = 0; int err = 0; int bytes_read, len; @@ -236,34 +240,37 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf, if (bytes_read < 0) { err = bytes_read; goto out_unlock_reading; + } else if (bytes_read == 0 && + (filp->f_flags & O_NONBLOCK)) { + err = -EAGAIN; + goto out_unlock_reading; } + data_avail = bytes_read; } - if (!data_avail) { - if (filp->f_flags & O_NONBLOCK) { - err = -EAGAIN; - goto out_unlock_reading; - } - } else { - len = data_avail; + len = data_avail; + if (len) { if (len > size) len = size; data_avail -= len; - if (copy_to_user(buf + ret, rng_buffer + data_avail, - len)) { + memcpy(buffer, rng_buffer + data_avail, len); + } + mutex_unlock(&reading_mutex); + put_rng(rng); + + if (len) { + if (copy_to_user(buf + ret, buffer, len)) { err = -EFAULT; - goto out_unlock_reading; + goto out; } size -= len; ret += len; } - mutex_unlock(&reading_mutex); - put_rng(rng); if (need_resched()) schedule_timeout_interruptible(1); @@ -274,6 +281,7 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf, } } out: + memzero_explicit(buffer, sizeof(buffer)); return ret ? : err; out_unlock_reading: diff --git a/drivers/char/hw_random/exynos-trng.c b/drivers/char/hw_random/exynos-trng.c index 30207b7ac5f4c5..0ed5d22fe667ae 100644 --- a/drivers/char/hw_random/exynos-trng.c +++ b/drivers/char/hw_random/exynos-trng.c @@ -173,7 +173,7 @@ err_pm_get: return ret; } -static int exynos_trng_remove(struct platform_device *pdev) +static void exynos_trng_remove(struct platform_device *pdev) { struct exynos_trng_dev *trng = platform_get_drvdata(pdev); @@ -181,8 +181,6 @@ static int exynos_trng_remove(struct platform_device *pdev) pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); - - return 0; } static int exynos_trng_suspend(struct device *dev) @@ -223,7 +221,7 @@ static struct platform_driver exynos_trng_driver = { .of_match_table = exynos_trng_dt_match, }, .probe = exynos_trng_probe, - .remove = exynos_trng_remove, + .remove_new = exynos_trng_remove, }; module_platform_driver(exynos_trng_driver); diff --git a/drivers/char/hw_random/ingenic-rng.c b/drivers/char/hw_random/ingenic-rng.c index 4f18c3fa5427fc..2f9b6483c4a12a 100644 --- a/drivers/char/hw_random/ingenic-rng.c +++ b/drivers/char/hw_random/ingenic-rng.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include @@ -114,15 +114,13 @@ static int ingenic_rng_probe(struct platform_device *pdev) return 0; } -static int ingenic_rng_remove(struct platform_device *pdev) +static void ingenic_rng_remove(struct platform_device *pdev) { struct ingenic_rng *priv = platform_get_drvdata(pdev); hwrng_unregister(&priv->rng); writel(0, priv->base + RNG_REG_ERNG_OFFSET); - - return 0; } static const struct of_device_id ingenic_rng_of_match[] = { @@ -134,7 +132,7 @@ MODULE_DEVICE_TABLE(of, ingenic_rng_of_match); static struct platform_driver ingenic_rng_driver = { .probe = ingenic_rng_probe, - .remove = ingenic_rng_remove, + .remove_new = ingenic_rng_remove, .driver = { .name = "ingenic-rng", .of_match_table = ingenic_rng_of_match, diff --git a/drivers/char/hw_random/jh7110-trng.c b/drivers/char/hw_random/jh7110-trng.c index 38474d48a25e16..9776f4daa04459 100644 --- a/drivers/char/hw_random/jh7110-trng.c +++ b/drivers/char/hw_random/jh7110-trng.c @@ -300,7 +300,7 @@ static int starfive_trng_probe(struct platform_device *pdev) ret = devm_request_irq(&pdev->dev, irq, starfive_trng_irq, 0, pdev->name, (void *)trng); if (ret) - return dev_err_probe(&pdev->dev, irq, + return dev_err_probe(&pdev->dev, ret, "Failed to register interrupt handler\n"); trng->hclk = devm_clk_get(&pdev->dev, "hclk"); @@ -369,8 +369,12 @@ static int __maybe_unused starfive_trng_resume(struct device *dev) return 0; } -static DEFINE_SIMPLE_DEV_PM_OPS(starfive_trng_pm_ops, starfive_trng_suspend, - starfive_trng_resume); +static const struct dev_pm_ops starfive_trng_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(starfive_trng_suspend, + starfive_trng_resume) + SET_RUNTIME_PM_OPS(starfive_trng_suspend, + starfive_trng_resume, NULL) +}; static const struct of_device_id trng_dt_ids[] __maybe_unused = { { .compatible = "starfive,jh7110-trng" }, diff --git a/drivers/char/hw_random/ks-sa-rng.c b/drivers/char/hw_random/ks-sa-rng.c index dff7b9db7044ce..36c34252b4f631 100644 --- a/drivers/char/hw_random/ks-sa-rng.c +++ b/drivers/char/hw_random/ks-sa-rng.c @@ -241,12 +241,10 @@ static int ks_sa_rng_probe(struct platform_device *pdev) return devm_hwrng_register(&pdev->dev, &ks_sa_rng->rng); } -static int ks_sa_rng_remove(struct platform_device *pdev) +static void ks_sa_rng_remove(struct platform_device *pdev) { pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); - - return 0; } static const struct of_device_id ks_sa_rng_dt_match[] = { @@ -263,7 +261,7 @@ static struct platform_driver ks_sa_rng_driver = { .of_match_table = ks_sa_rng_dt_match, }, .probe = ks_sa_rng_probe, - .remove = ks_sa_rng_remove, + .remove_new = ks_sa_rng_remove, }; module_platform_driver(ks_sa_rng_driver); diff --git a/drivers/char/hw_random/mxc-rnga.c b/drivers/char/hw_random/mxc-rnga.c index 008763c988ed8b..07ec000e4cd711 100644 --- a/drivers/char/hw_random/mxc-rnga.c +++ b/drivers/char/hw_random/mxc-rnga.c @@ -176,15 +176,13 @@ err_ioremap: return err; } -static int __exit mxc_rnga_remove(struct platform_device *pdev) +static void __exit mxc_rnga_remove(struct platform_device *pdev) { struct mxc_rng *mxc_rng = platform_get_drvdata(pdev); hwrng_unregister(&mxc_rng->rng); clk_disable_unprepare(mxc_rng->clk); - - return 0; } static const struct of_device_id mxc_rnga_of_match[] = { @@ -199,7 +197,7 @@ static struct platform_driver mxc_rnga_driver = { .name = "mxc_rnga", .of_match_table = mxc_rnga_of_match, }, - .remove = __exit_p(mxc_rnga_remove), + .remove_new = __exit_p(mxc_rnga_remove), }; module_platform_driver_probe(mxc_rnga_driver, mxc_rnga_probe); diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c index aaae16b98475a2..2e669e7c14d31c 100644 --- a/drivers/char/hw_random/n2-drv.c +++ b/drivers/char/hw_random/n2-drv.c @@ -781,7 +781,7 @@ out: return err; } -static int n2rng_remove(struct platform_device *op) +static void n2rng_remove(struct platform_device *op) { struct n2rng *np = platform_get_drvdata(op); @@ -790,8 +790,6 @@ static int n2rng_remove(struct platform_device *op) cancel_delayed_work_sync(&np->work); sun4v_hvapi_unregister(HV_GRP_RNG); - - return 0; } static struct n2rng_template n2_template = { @@ -860,7 +858,7 @@ static struct platform_driver n2rng_driver = { .of_match_table = n2rng_match, }, .probe = n2rng_probe, - .remove = n2rng_remove, + .remove_new = n2rng_remove, }; module_platform_driver(n2rng_driver); diff --git a/drivers/char/hw_random/npcm-rng.c b/drivers/char/hw_random/npcm-rng.c index 8a304b754217e0..bce8c4829a1f83 100644 --- a/drivers/char/hw_random/npcm-rng.c +++ b/drivers/char/hw_random/npcm-rng.c @@ -126,15 +126,13 @@ static int npcm_rng_probe(struct platform_device *pdev) return 0; } -static int npcm_rng_remove(struct platform_device *pdev) +static void npcm_rng_remove(struct platform_device *pdev) { struct npcm_rng *priv = platform_get_drvdata(pdev); devm_hwrng_unregister(&pdev->dev, &priv->rng); pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); - - return 0; } #ifdef CONFIG_PM @@ -178,7 +176,7 @@ static struct platform_driver npcm_rng_driver = { .of_match_table = of_match_ptr(rng_dt_id), }, .probe = npcm_rng_probe, - .remove = npcm_rng_remove, + .remove_new = npcm_rng_remove, }; module_platform_driver(npcm_rng_driver); diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c index be03f76a2a8089..d4c02e9004665e 100644 --- a/drivers/char/hw_random/omap-rng.c +++ b/drivers/char/hw_random/omap-rng.c @@ -509,7 +509,7 @@ err_ioremap: return ret; } -static int omap_rng_remove(struct platform_device *pdev) +static void omap_rng_remove(struct platform_device *pdev) { struct omap_rng_dev *priv = platform_get_drvdata(pdev); @@ -521,8 +521,6 @@ static int omap_rng_remove(struct platform_device *pdev) clk_disable_unprepare(priv->clk); clk_disable_unprepare(priv->clk_reg); - - return 0; } static int __maybe_unused omap_rng_suspend(struct device *dev) @@ -560,7 +558,7 @@ static struct platform_driver omap_rng_driver = { .of_match_table = of_match_ptr(omap_rng_of_match), }, .probe = omap_rng_probe, - .remove = omap_rng_remove, + .remove_new = omap_rng_remove, }; module_platform_driver(omap_rng_driver); diff --git a/drivers/char/hw_random/stm32-rng.c b/drivers/char/hw_random/stm32-rng.c index 41e1dbea5d2ebb..379bc245c52022 100644 --- a/drivers/char/hw_random/stm32-rng.c +++ b/drivers/char/hw_random/stm32-rng.c @@ -325,6 +325,7 @@ static int stm32_rng_init(struct hwrng *rng) (!(reg & RNG_CR_CONDRST)), 10, 50000); if (err) { + clk_disable_unprepare(priv->clk); dev_err((struct device *)priv->rng.priv, "%s: timeout %x!\n", __func__, reg); return -EINVAL; @@ -362,11 +363,9 @@ static int stm32_rng_init(struct hwrng *rng) return 0; } -static int stm32_rng_remove(struct platform_device *ofdev) +static void stm32_rng_remove(struct platform_device *ofdev) { pm_runtime_disable(&ofdev->dev); - - return 0; } static int __maybe_unused stm32_rng_runtime_suspend(struct device *dev) @@ -557,7 +556,7 @@ static struct platform_driver stm32_rng_driver = { .of_match_table = stm32_rng_match, }, .probe = stm32_rng_probe, - .remove = stm32_rng_remove, + .remove_new = stm32_rng_remove, }; module_platform_driver(stm32_rng_driver); diff --git a/drivers/char/hw_random/timeriomem-rng.c b/drivers/char/hw_random/timeriomem-rng.c index 3db9d868efb1a7..65b8260339f5be 100644 --- a/drivers/char/hw_random/timeriomem-rng.c +++ b/drivers/char/hw_random/timeriomem-rng.c @@ -174,13 +174,11 @@ static int timeriomem_rng_probe(struct platform_device *pdev) return 0; } -static int timeriomem_rng_remove(struct platform_device *pdev) +static void timeriomem_rng_remove(struct platform_device *pdev) { struct timeriomem_rng_private *priv = platform_get_drvdata(pdev); hrtimer_cancel(&priv->timer); - - return 0; } static const struct of_device_id timeriomem_rng_match[] = { @@ -195,7 +193,7 @@ static struct platform_driver timeriomem_rng_driver = { .of_match_table = timeriomem_rng_match, }, .probe = timeriomem_rng_probe, - .remove = timeriomem_rng_remove, + .remove_new = timeriomem_rng_remove, }; module_platform_driver(timeriomem_rng_driver); diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c index e41a84e6b4b56a..7a4b45393acb4b 100644 --- a/drivers/char/hw_random/virtio-rng.c +++ b/drivers/char/hw_random/virtio-rng.c @@ -135,7 +135,7 @@ static int probe_common(struct virtio_device *vdev) if (!vi) return -ENOMEM; - vi->index = index = ida_simple_get(&rng_index_ida, 0, 0, GFP_KERNEL); + vi->index = index = ida_alloc(&rng_index_ida, GFP_KERNEL); if (index < 0) { err = index; goto err_ida; @@ -166,7 +166,7 @@ static int probe_common(struct virtio_device *vdev) return 0; err_find: - ida_simple_remove(&rng_index_ida, index); + ida_free(&rng_index_ida, index); err_ida: kfree(vi); return err; @@ -184,7 +184,7 @@ static void remove_common(struct virtio_device *vdev) hwrng_unregister(&vi->hwrng); virtio_reset_device(vdev); vdev->config->del_vqs(vdev); - ida_simple_remove(&rng_index_ida, vi->index); + ida_free(&rng_index_ida, vi->index); kfree(vi); } @@ -208,7 +208,6 @@ static void virtrng_scan(struct virtio_device *vdev) vi->hwrng_register_done = true; } -#ifdef CONFIG_PM_SLEEP static int virtrng_freeze(struct virtio_device *vdev) { remove_common(vdev); @@ -238,7 +237,6 @@ static int virtrng_restore(struct virtio_device *vdev) return err; } -#endif static const struct virtio_device_id id_table[] = { { VIRTIO_ID_RNG, VIRTIO_DEV_ANY_ID }, @@ -252,10 +250,8 @@ static struct virtio_driver virtio_rng_driver = { .probe = virtrng_probe, .remove = virtrng_remove, .scan = virtrng_scan, -#ifdef CONFIG_PM_SLEEP - .freeze = virtrng_freeze, - .restore = virtrng_restore, -#endif + .freeze = pm_sleep_ptr(virtrng_freeze), + .restore = pm_sleep_ptr(virtrng_restore), }; module_virtio_driver(virtio_rng_driver); diff --git a/drivers/char/hw_random/xgene-rng.c b/drivers/char/hw_random/xgene-rng.c index 7382724bf501c2..642d13519464c0 100644 --- a/drivers/char/hw_random/xgene-rng.c +++ b/drivers/char/hw_random/xgene-rng.c @@ -357,15 +357,13 @@ static int xgene_rng_probe(struct platform_device *pdev) return 0; } -static int xgene_rng_remove(struct platform_device *pdev) +static void xgene_rng_remove(struct platform_device *pdev) { int rc; rc = device_init_wakeup(&pdev->dev, 0); if (rc) dev_err(&pdev->dev, "RNG init wakeup failed error %d\n", rc); - - return 0; } static const struct of_device_id xgene_rng_of_match[] = { @@ -377,7 +375,7 @@ MODULE_DEVICE_TABLE(of, xgene_rng_of_match); static struct platform_driver xgene_rng_driver = { .probe = xgene_rng_probe, - .remove = xgene_rng_remove, + .remove_new = xgene_rng_remove, .driver = { .name = "xgene-rng", .of_match_table = xgene_rng_of_match, diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index d6f14279684de1..b0eedc4595b378 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -3053,7 +3053,7 @@ static void cleanup_bmc_work(struct work_struct *work) int id = bmc->pdev.id; /* Unregister overwrites id */ platform_device_unregister(&bmc->pdev); - ida_simple_remove(&ipmi_bmc_ida, id); + ida_free(&ipmi_bmc_ida, id); } static void @@ -3169,7 +3169,7 @@ static int __ipmi_bmc_register(struct ipmi_smi *intf, bmc->pdev.name = "ipmi_bmc"; - rv = ida_simple_get(&ipmi_bmc_ida, 0, 0, GFP_KERNEL); + rv = ida_alloc(&ipmi_bmc_ida, GFP_KERNEL); if (rv < 0) { kfree(bmc); goto out; diff --git a/drivers/char/ipmi/ipmi_si_hardcode.c b/drivers/char/ipmi/ipmi_si_hardcode.c index ed5e91b1e040c2..0c92fa3eee8842 100644 --- a/drivers/char/ipmi/ipmi_si_hardcode.c +++ b/drivers/char/ipmi/ipmi_si_hardcode.c @@ -80,10 +80,10 @@ static void __init ipmi_hardcode_init_one(const char *si_type_str, } p.regsize = regsizes[i]; + p.regspacing = regspacings[i]; p.slave_addr = slave_addrs[i]; p.addr_source = SI_HARDCODED; p.regshift = regshifts[i]; - p.regsize = regsizes[i]; p.addr = addr; p.space = addr_space; diff --git a/drivers/char/ipmi/ipmi_si_platform.c b/drivers/char/ipmi/ipmi_si_platform.c index c3d8ac7873baa1..cd2edd8f8a0338 100644 --- a/drivers/char/ipmi/ipmi_si_platform.c +++ b/drivers/char/ipmi/ipmi_si_platform.c @@ -11,10 +11,11 @@ #include #include -#include -#include +#include #include #include +#include +#include #include #include "ipmi_si.h" #include "ipmi_dmi.h" @@ -224,7 +225,6 @@ MODULE_DEVICE_TABLE(of, of_ipmi_match); static int of_ipmi_probe(struct platform_device *pdev) { - const struct of_device_id *match; struct si_sm_io io; struct resource resource; const __be32 *regsize, *regspacing, *regshift; @@ -237,10 +237,6 @@ static int of_ipmi_probe(struct platform_device *pdev) dev_info(&pdev->dev, "probing via device tree\n"); - match = of_match_device(of_ipmi_match, &pdev->dev); - if (!match) - return -ENODEV; - if (!of_device_is_available(np)) return -EINVAL; @@ -269,7 +265,7 @@ static int of_ipmi_probe(struct platform_device *pdev) } memset(&io, 0, sizeof(io)); - io.si_type = (unsigned long) match->data; + io.si_type = (enum si_type)device_get_match_data(&pdev->dev); io.addr_source = SI_DEVICETREE; io.irq_setup = ipmi_std_irq_setup; diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c index 4c188e9e477cdf..ee951b265213fb 100644 --- a/drivers/char/ppdev.c +++ b/drivers/char/ppdev.c @@ -299,7 +299,7 @@ static int register_device(int minor, struct pp_struct *pp) goto err; } - index = ida_simple_get(&ida_index, 0, 0, GFP_KERNEL); + index = ida_alloc(&ida_index, GFP_KERNEL); memset(&ppdev_cb, 0, sizeof(ppdev_cb)); ppdev_cb.irq_func = pp_irq; ppdev_cb.flags = (pp->flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0; @@ -310,7 +310,7 @@ static int register_device(int minor, struct pp_struct *pp) if (!pdev) { pr_warn("%s: failed to register device!\n", name); rc = -ENXIO; - ida_simple_remove(&ida_index, index); + ida_free(&ida_index, index); goto err; } @@ -750,7 +750,7 @@ static int pp_release(struct inode *inode, struct file *file) if (pp->pdev) { parport_unregister_device(pp->pdev); - ida_simple_remove(&ida_index, pp->index); + ida_free(&ida_index, pp->index); pp->pdev = NULL; pr_debug(CHRDEV "%x: unregistered pardevice\n", minor); } diff --git a/drivers/char/random.c b/drivers/char/random.c index 4a9c79391dee93..456be28ba67cb4 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1364,7 +1364,6 @@ static void __cold try_to_generate_entropy(void) SYSCALL_DEFINE3(getrandom, char __user *, ubuf, size_t, len, unsigned int, flags) { struct iov_iter iter; - struct iovec iov; int ret; if (flags & ~(GRND_NONBLOCK | GRND_RANDOM | GRND_INSECURE)) @@ -1385,7 +1384,7 @@ SYSCALL_DEFINE3(getrandom, char __user *, ubuf, size_t, len, unsigned int, flags return ret; } - ret = import_single_range(ITER_DEST, ubuf, len, &iov, &iter); + ret = import_ubuf(ITER_DEST, ubuf, len, &iter); if (unlikely(ret)) return ret; return get_random_bytes_user(&iter); @@ -1491,7 +1490,6 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg) return 0; case RNDADDENTROPY: { struct iov_iter iter; - struct iovec iov; ssize_t ret; int len; @@ -1503,7 +1501,7 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg) return -EINVAL; if (get_user(len, p++)) return -EFAULT; - ret = import_single_range(ITER_SOURCE, p, len, &iov, &iter); + ret = import_ubuf(ITER_SOURCE, p, len, &iter); if (unlikely(ret)) return ret; ret = write_pool_user(&iter); diff --git a/drivers/char/tpm/tpm_i2c_nuvoton.c b/drivers/char/tpm/tpm_i2c_nuvoton.c index d7be03c41098ae..5490f7e0fa4369 100644 --- a/drivers/char/tpm/tpm_i2c_nuvoton.c +++ b/drivers/char/tpm/tpm_i2c_nuvoton.c @@ -19,7 +19,8 @@ #include #include #include -#include +#include +#include #include "tpm.h" /* I2C interface offsets */ @@ -524,7 +525,6 @@ static int get_vid(struct i2c_client *client, u32 *res) static int i2c_nuvoton_probe(struct i2c_client *client) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); int rc; struct tpm_chip *chip; struct device *dev = &client->dev; @@ -546,15 +546,8 @@ static int i2c_nuvoton_probe(struct i2c_client *client) if (!priv) return -ENOMEM; - if (dev->of_node) { - const struct of_device_id *of_id; - - of_id = of_match_device(dev->driver->of_match_table, dev); - if (of_id && of_id->data == OF_IS_TPM2) - chip->flags |= TPM_CHIP_FLAG_TPM2; - } else - if (id->driver_data == I2C_IS_TPM2) - chip->flags |= TPM_CHIP_FLAG_TPM2; + if (i2c_get_match_data(client)) + chip->flags |= TPM_CHIP_FLAG_TPM2; init_waitqueue_head(&priv->read_queue); diff --git a/drivers/char/tpm/tpm_tis_i2c_cr50.c b/drivers/char/tpm/tpm_tis_i2c_cr50.c index e70abd69e1ae30..adf22992138e5c 100644 --- a/drivers/char/tpm/tpm_tis_i2c_cr50.c +++ b/drivers/char/tpm/tpm_tis_i2c_cr50.c @@ -235,7 +235,7 @@ out: * @len: Number of bytes to write. * * The provided address is prepended to the data in 'buffer', the - * cobined address+data is sent to the TPM, then wait for TPM to + * combined address+data is sent to the TPM, then wait for TPM to * indicate it is done writing. * * Return: @@ -671,7 +671,6 @@ MODULE_DEVICE_TABLE(of, of_cr50_i2c_match); /** * tpm_cr50_i2c_probe() - Driver probe function. * @client: I2C client information. - * @id: I2C device id. * * Return: * - 0: Success. diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c index 5af804c17a7534..4c806a189ee533 100644 --- a/drivers/char/ttyprintk.c +++ b/drivers/char/ttyprintk.c @@ -40,7 +40,7 @@ static struct ttyprintk_port tpk_port; static int tpk_curr; -static char tpk_buffer[TPK_STR_SIZE + 4]; +static u8 tpk_buffer[TPK_STR_SIZE + 4]; static void tpk_flush(void) { @@ -51,9 +51,9 @@ static void tpk_flush(void) } } -static int tpk_printk(const u8 *buf, int count) +static int tpk_printk(const u8 *buf, size_t count) { - int i; + size_t i; for (i = 0; i < count; i++) { if (tpk_curr >= TPK_STR_SIZE) { diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 431e9e5bf9c15f..035f89f1a251e2 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -230,9 +230,6 @@ struct port { bool guest_connected; }; -/* This is the very early arch-specified put chars function. */ -static int (*early_put_chars)(u32, const char *, int); - static struct port *find_port_by_vtermno(u32 vtermno) { struct port *port; @@ -653,7 +650,7 @@ done: * Give out the data that's requested from the buffer that we have * queued up. */ -static ssize_t fill_readbuf(struct port *port, char __user *out_buf, +static ssize_t fill_readbuf(struct port *port, u8 __user *out_buf, size_t out_count, bool to_user) { struct port_buffer *buf; @@ -672,7 +669,7 @@ static ssize_t fill_readbuf(struct port *port, char __user *out_buf, if (ret) return -EFAULT; } else { - memcpy((__force char *)out_buf, buf->buf + buf->offset, + memcpy((__force u8 *)out_buf, buf->buf + buf->offset, out_count); } @@ -1107,16 +1104,13 @@ static const struct file_operations port_fops = { * it to finish: inefficient in theory, but in practice * implementations will do it immediately. */ -static int put_chars(u32 vtermno, const char *buf, int count) +static ssize_t put_chars(u32 vtermno, const u8 *buf, size_t count) { struct port *port; struct scatterlist sg[1]; void *data; int ret; - if (unlikely(early_put_chars)) - return early_put_chars(vtermno, buf, count); - port = find_port_by_vtermno(vtermno); if (!port) return -EPIPE; @@ -1138,14 +1132,10 @@ static int put_chars(u32 vtermno, const char *buf, int count) * We call out to fill_readbuf that gets us the required data from the * buffers that are queued up. */ -static int get_chars(u32 vtermno, char *buf, int count) +static ssize_t get_chars(u32 vtermno, u8 *buf, size_t count) { struct port *port; - /* If we've not set up the port yet, we have no input to give. */ - if (unlikely(early_put_chars)) - return 0; - port = find_port_by_vtermno(vtermno); if (!port) return -EPIPE; @@ -1153,7 +1143,7 @@ static int get_chars(u32 vtermno, char *buf, int count) /* If we don't have an input queue yet, we can't get input. */ BUG_ON(!port->in_vq); - return fill_readbuf(port, (__force char __user *)buf, count, false); + return fill_readbuf(port, (__force u8 __user *)buf, count, false); } static void resize_console(struct port *port) @@ -1201,21 +1191,6 @@ static const struct hv_ops hv_ops = { .notifier_hangup = notifier_del_vio, }; -/* - * Console drivers are initialized very early so boot messages can go - * out, so we do things slightly differently from the generic virtio - * initialization of the net and block drivers. - * - * At this stage, the console is output-only. It's too early to set - * up a virtqueue, so we let the drivers do some boutique early-output - * thing. - */ -int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int)) -{ - early_put_chars = put_chars; - return hvc_instantiate(0, 0, &hv_ops); -} - static int init_port_console(struct port *port) { int ret; @@ -1256,13 +1231,6 @@ static int init_port_console(struct port *port) spin_unlock_irq(&pdrvdata_lock); port->guest_connected = true; - /* - * Start using the new console output if this is the first - * console to come up. - */ - if (early_put_chars) - early_put_chars = NULL; - /* Notify host of port being opened */ send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 1); @@ -1999,7 +1967,6 @@ static int virtcons_probe(struct virtio_device *vdev) struct ports_device *portdev; int err; bool multiport; - bool early = early_put_chars != NULL; /* We only need a config space if features are offered */ if (!vdev->config->get && @@ -2010,9 +1977,6 @@ static int virtcons_probe(struct virtio_device *vdev) return -EINVAL; } - /* Ensure to read early_put_chars now */ - barrier(); - portdev = kmalloc(sizeof(*portdev), GFP_KERNEL); if (!portdev) { err = -ENOMEM; @@ -2100,18 +2064,6 @@ static int virtcons_probe(struct virtio_device *vdev) __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID, VIRTIO_CONSOLE_DEVICE_READY, 1); - /* - * If there was an early virtio console, assume that there are no - * other consoles. We need to wait until the hvc_alloc matches the - * hvc_instantiate, otherwise tty_open will complain, resulting in - * a "Warning: unable to open an initial console" boot failure. - * Without multiport this is done in add_port above. With multiport - * this might take some host<->guest communication - thus we have to - * wait. - */ - if (multiport && early) - wait_for_completion(&early_console_added); - return 0; free_chrdev: diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index c30d0d396f7a30..50af5fc7f57080 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -414,16 +414,6 @@ config COMMON_CLK_VC7 Renesas Versaclock7 is a family of configurable clock generator and jitter attenuator ICs with fractional and integer dividers. -config COMMON_CLK_STM32MP135 - def_bool COMMON_CLK && MACH_STM32MP13 - help - Support for stm32mp135 SoC family clocks - -config COMMON_CLK_STM32MP157 - def_bool COMMON_CLK && MACH_STM32MP157 - help - Support for stm32mp157 SoC family clocks - config COMMON_CLK_STM32F def_bool COMMON_CLK && (MACH_STM32F429 || MACH_STM32F469 || MACH_STM32F746) help @@ -504,6 +494,7 @@ source "drivers/clk/starfive/Kconfig" source "drivers/clk/sunxi/Kconfig" source "drivers/clk/sunxi-ng/Kconfig" source "drivers/clk/tegra/Kconfig" +source "drivers/clk/stm32/Kconfig" source "drivers/clk/ti/Kconfig" source "drivers/clk/uniphier/Kconfig" source "drivers/clk/visconti/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index ed71f2e0ee3674..14fa8d4ecc1fbe 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -70,7 +70,6 @@ obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o obj-$(CONFIG_COMMON_CLK_SP7021) += clk-sp7021.o obj-$(CONFIG_COMMON_CLK_STM32F) += clk-stm32f4.o obj-$(CONFIG_COMMON_CLK_STM32H7) += clk-stm32h7.o -obj-$(CONFIG_COMMON_CLK_STM32MP157) += clk-stm32mp1.o obj-$(CONFIG_COMMON_CLK_TPS68470) += clk-tps68470.o obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o obj-$(CONFIG_CLK_TWL) += clk-twl.o diff --git a/drivers/clk/clk-renesas-pcie.c b/drivers/clk/clk-renesas-pcie.c index 380245f635d66c..53e21ac302e6dd 100644 --- a/drivers/clk/clk-renesas-pcie.c +++ b/drivers/clk/clk-renesas-pcie.c @@ -7,6 +7,7 @@ * Currently supported: * - 9FGV0241 * - 9FGV0441 + * - 9FGV0841 * * Copyright (C) 2022 Marek Vasut */ @@ -42,6 +43,7 @@ #define RS9_REG_DID 0x6 #define RS9_REG_BCP 0x7 +#define RS9_REG_VID_MASK GENMASK(3, 0) #define RS9_REG_VID_IDT 0x01 #define RS9_REG_DID_TYPE_FGV (0x0 << RS9_REG_DID_TYPE_SHIFT) @@ -49,16 +51,10 @@ #define RS9_REG_DID_TYPE_DMV (0x2 << RS9_REG_DID_TYPE_SHIFT) #define RS9_REG_DID_TYPE_SHIFT 0x6 -/* Supported Renesas 9-series models. */ -enum rs9_model { - RENESAS_9FGV0241, - RENESAS_9FGV0441, -}; - /* Structure to describe features of a particular 9-series model */ struct rs9_chip_info { - const enum rs9_model model; unsigned int num_clks; + u8 outshift; u8 did; }; @@ -160,14 +156,12 @@ static const struct regmap_config rs9_regmap_config = { static u8 rs9_calc_dif(const struct rs9_driver_data *rs9, int idx) { - enum rs9_model model = rs9->chip_info->model; - - if (model == RENESAS_9FGV0241) - return BIT(idx) + 1; - else if (model == RENESAS_9FGV0441) - return BIT(idx); - - return 0; + /* + * On 9FGV0241, the DIF OE0 is BIT(1) and DIF OE(1) is BIT(2), + * on 9FGV0441 and 9FGV0841 the DIF OE0 is BIT(0) and so on. + * Increment the index in the 9FGV0241 special case here. + */ + return BIT(idx + rs9->chip_info->outshift); } static int rs9_get_output_config(struct rs9_driver_data *rs9, int idx) @@ -333,6 +327,7 @@ static int rs9_probe(struct i2c_client *client) if (ret < 0) return ret; + vid &= RS9_REG_VID_MASK; if (vid != RS9_REG_VID_IDT || did != rs9->chip_info->did) return dev_err_probe(&client->dev, -ENODEV, "Incorrect VID/DID: %#02x, %#02x. Expected %#02x, %#02x\n", @@ -380,20 +375,27 @@ static int __maybe_unused rs9_resume(struct device *dev) } static const struct rs9_chip_info renesas_9fgv0241_info = { - .model = RENESAS_9FGV0241, .num_clks = 2, + .outshift = 1, .did = RS9_REG_DID_TYPE_FGV | 0x02, }; static const struct rs9_chip_info renesas_9fgv0441_info = { - .model = RENESAS_9FGV0441, .num_clks = 4, + .outshift = 0, .did = RS9_REG_DID_TYPE_FGV | 0x04, }; +static const struct rs9_chip_info renesas_9fgv0841_info = { + .num_clks = 8, + .outshift = 0, + .did = RS9_REG_DID_TYPE_FGV | 0x08, +}; + static const struct i2c_device_id rs9_id[] = { { "9fgv0241", .driver_data = (kernel_ulong_t)&renesas_9fgv0241_info }, { "9fgv0441", .driver_data = (kernel_ulong_t)&renesas_9fgv0441_info }, + { "9fgv0841", .driver_data = (kernel_ulong_t)&renesas_9fgv0841_info }, { } }; MODULE_DEVICE_TABLE(i2c, rs9_id); @@ -401,6 +403,7 @@ MODULE_DEVICE_TABLE(i2c, rs9_id); static const struct of_device_id clk_rs9_of_match[] = { { .compatible = "renesas,9fgv0241", .data = &renesas_9fgv0241_info }, { .compatible = "renesas,9fgv0441", .data = &renesas_9fgv0441_info }, + { .compatible = "renesas,9fgv0841", .data = &renesas_9fgv0841_info }, { } }; MODULE_DEVICE_TABLE(of, clk_rs9_of_match); diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c index 845b451511d239..6e8dd7387cfdd4 100644 --- a/drivers/clk/clk-si5341.c +++ b/drivers/clk/clk-si5341.c @@ -895,10 +895,8 @@ static int si5341_output_clk_set_rate(struct clk_hw *hw, unsigned long rate, r[0] = r_div ? (r_div & 0xff) : 1; r[1] = (r_div >> 8) & 0xff; r[2] = (r_div >> 16) & 0xff; - err = regmap_bulk_write(output->data->regmap, + return regmap_bulk_write(output->data->regmap, SI5341_OUT_R_REG(output), r, 3); - - return 0; } static int si5341_output_reparent(struct clk_si5341_output *output, u8 index) diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c index a9a0bc448a4b19..4ce83c5265b878 100644 --- a/drivers/clk/clk-si5351.c +++ b/drivers/clk/clk-si5351.c @@ -506,6 +506,8 @@ static int si5351_pll_set_rate(struct clk_hw *hw, unsigned long rate, { struct si5351_hw_data *hwdata = container_of(hw, struct si5351_hw_data, hw); + struct si5351_platform_data *pdata = + hwdata->drvdata->client->dev.platform_data; u8 reg = (hwdata->num == 0) ? SI5351_PLLA_PARAMETERS : SI5351_PLLB_PARAMETERS; @@ -518,9 +520,10 @@ static int si5351_pll_set_rate(struct clk_hw *hw, unsigned long rate, (hwdata->params.p2 == 0) ? SI5351_CLK_INTEGER_MODE : 0); /* Do a pll soft reset on the affected pll */ - si5351_reg_write(hwdata->drvdata, SI5351_PLL_RESET, - hwdata->num == 0 ? SI5351_PLL_RESET_A : - SI5351_PLL_RESET_B); + if (pdata->pll_reset[hwdata->num]) + si5351_reg_write(hwdata->drvdata, SI5351_PLL_RESET, + hwdata->num == 0 ? SI5351_PLL_RESET_A : + SI5351_PLL_RESET_B); dev_dbg(&hwdata->drvdata->client->dev, "%s - %s: p1 = %lu, p2 = %lu, p3 = %lu, parent_rate = %lu, rate = %lu\n", @@ -1222,6 +1225,44 @@ static int si5351_dt_parse(struct i2c_client *client, } } + /* + * Parse PLL reset mode. For compatibility with older device trees, the + * default is to always reset a PLL after setting its rate. + */ + pdata->pll_reset[0] = true; + pdata->pll_reset[1] = true; + + of_property_for_each_u32(np, "silabs,pll-reset-mode", prop, p, num) { + if (num >= 2) { + dev_err(&client->dev, + "invalid pll %d on pll-reset-mode prop\n", num); + return -EINVAL; + } + + p = of_prop_next_u32(prop, p, &val); + if (!p) { + dev_err(&client->dev, + "missing pll-reset-mode for pll %d\n", num); + return -EINVAL; + } + + switch (val) { + case 0: + /* Reset PLL whenever its rate is adjusted */ + pdata->pll_reset[num] = true; + break; + case 1: + /* Don't reset PLL whenever its rate is adjusted */ + pdata->pll_reset[num] = false; + break; + default: + dev_err(&client->dev, + "invalid pll-reset-mode %d for pll %d\n", val, + num); + return -EINVAL; + } + } + /* per clkout properties */ for_each_child_of_node(np, child) { if (of_property_read_u32(child, "reg", &num)) { diff --git a/drivers/clk/clk-sp7021.c b/drivers/clk/clk-sp7021.c index 01d3c4c7b0b23f..7cb7d501d7a6eb 100644 --- a/drivers/clk/clk-sp7021.c +++ b/drivers/clk/clk-sp7021.c @@ -604,14 +604,14 @@ static int sp7021_clk_probe(struct platform_device *pdev) int i; clk_base = devm_platform_ioremap_resource(pdev, 0); - if (!clk_base) - return -ENXIO; + if (IS_ERR(clk_base)) + return PTR_ERR(clk_base); pll_base = devm_platform_ioremap_resource(pdev, 1); - if (!pll_base) - return -ENXIO; + if (IS_ERR(pll_base)) + return PTR_ERR(pll_base); sys_base = devm_platform_ioremap_resource(pdev, 2); - if (!sys_base) - return -ENXIO; + if (IS_ERR(sys_base)) + return PTR_ERR(sys_base); /* enable default clks */ for (i = 0; i < ARRAY_SIZE(sp_clken); i++) diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c deleted file mode 100644 index 939779f66867e0..00000000000000 --- a/drivers/clk/clk-stm32mp1.c +++ /dev/null @@ -1,2459 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) STMicroelectronics 2018 - All Rights Reserved - * Author: Olivier Bideau for STMicroelectronics. - * Author: Gabriel Fernandez for STMicroelectronics. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -static DEFINE_SPINLOCK(rlock); - -#define RCC_OCENSETR 0x0C -#define RCC_HSICFGR 0x18 -#define RCC_RDLSICR 0x144 -#define RCC_PLL1CR 0x80 -#define RCC_PLL1CFGR1 0x84 -#define RCC_PLL1CFGR2 0x88 -#define RCC_PLL2CR 0x94 -#define RCC_PLL2CFGR1 0x98 -#define RCC_PLL2CFGR2 0x9C -#define RCC_PLL3CR 0x880 -#define RCC_PLL3CFGR1 0x884 -#define RCC_PLL3CFGR2 0x888 -#define RCC_PLL4CR 0x894 -#define RCC_PLL4CFGR1 0x898 -#define RCC_PLL4CFGR2 0x89C -#define RCC_APB1ENSETR 0xA00 -#define RCC_APB2ENSETR 0xA08 -#define RCC_APB3ENSETR 0xA10 -#define RCC_APB4ENSETR 0x200 -#define RCC_APB5ENSETR 0x208 -#define RCC_AHB2ENSETR 0xA18 -#define RCC_AHB3ENSETR 0xA20 -#define RCC_AHB4ENSETR 0xA28 -#define RCC_AHB5ENSETR 0x210 -#define RCC_AHB6ENSETR 0x218 -#define RCC_AHB6LPENSETR 0x318 -#define RCC_RCK12SELR 0x28 -#define RCC_RCK3SELR 0x820 -#define RCC_RCK4SELR 0x824 -#define RCC_MPCKSELR 0x20 -#define RCC_ASSCKSELR 0x24 -#define RCC_MSSCKSELR 0x48 -#define RCC_SPI6CKSELR 0xC4 -#define RCC_SDMMC12CKSELR 0x8F4 -#define RCC_SDMMC3CKSELR 0x8F8 -#define RCC_FMCCKSELR 0x904 -#define RCC_I2C46CKSELR 0xC0 -#define RCC_I2C12CKSELR 0x8C0 -#define RCC_I2C35CKSELR 0x8C4 -#define RCC_UART1CKSELR 0xC8 -#define RCC_QSPICKSELR 0x900 -#define RCC_ETHCKSELR 0x8FC -#define RCC_RNG1CKSELR 0xCC -#define RCC_RNG2CKSELR 0x920 -#define RCC_GPUCKSELR 0x938 -#define RCC_USBCKSELR 0x91C -#define RCC_STGENCKSELR 0xD4 -#define RCC_SPDIFCKSELR 0x914 -#define RCC_SPI2S1CKSELR 0x8D8 -#define RCC_SPI2S23CKSELR 0x8DC -#define RCC_SPI2S45CKSELR 0x8E0 -#define RCC_CECCKSELR 0x918 -#define RCC_LPTIM1CKSELR 0x934 -#define RCC_LPTIM23CKSELR 0x930 -#define RCC_LPTIM45CKSELR 0x92C -#define RCC_UART24CKSELR 0x8E8 -#define RCC_UART35CKSELR 0x8EC -#define RCC_UART6CKSELR 0x8E4 -#define RCC_UART78CKSELR 0x8F0 -#define RCC_FDCANCKSELR 0x90C -#define RCC_SAI1CKSELR 0x8C8 -#define RCC_SAI2CKSELR 0x8CC -#define RCC_SAI3CKSELR 0x8D0 -#define RCC_SAI4CKSELR 0x8D4 -#define RCC_ADCCKSELR 0x928 -#define RCC_MPCKDIVR 0x2C -#define RCC_DSICKSELR 0x924 -#define RCC_CPERCKSELR 0xD0 -#define RCC_MCO1CFGR 0x800 -#define RCC_MCO2CFGR 0x804 -#define RCC_BDCR 0x140 -#define RCC_AXIDIVR 0x30 -#define RCC_MCUDIVR 0x830 -#define RCC_APB1DIVR 0x834 -#define RCC_APB2DIVR 0x838 -#define RCC_APB3DIVR 0x83C -#define RCC_APB4DIVR 0x3C -#define RCC_APB5DIVR 0x40 -#define RCC_TIMG1PRER 0x828 -#define RCC_TIMG2PRER 0x82C -#define RCC_RTCDIVR 0x44 -#define RCC_DBGCFGR 0x80C - -#define RCC_CLR 0x4 - -static const char * const ref12_parents[] = { - "ck_hsi", "ck_hse" -}; - -static const char * const ref3_parents[] = { - "ck_hsi", "ck_hse", "ck_csi" -}; - -static const char * const ref4_parents[] = { - "ck_hsi", "ck_hse", "ck_csi" -}; - -static const char * const cpu_src[] = { - "ck_hsi", "ck_hse", "pll1_p" -}; - -static const char * const axi_src[] = { - "ck_hsi", "ck_hse", "pll2_p" -}; - -static const char * const per_src[] = { - "ck_hsi", "ck_csi", "ck_hse" -}; - -static const char * const mcu_src[] = { - "ck_hsi", "ck_hse", "ck_csi", "pll3_p" -}; - -static const char * const sdmmc12_src[] = { - "ck_axi", "pll3_r", "pll4_p", "ck_hsi" -}; - -static const char * const sdmmc3_src[] = { - "ck_mcu", "pll3_r", "pll4_p", "ck_hsi" -}; - -static const char * const fmc_src[] = { - "ck_axi", "pll3_r", "pll4_p", "ck_per" -}; - -static const char * const qspi_src[] = { - "ck_axi", "pll3_r", "pll4_p", "ck_per" -}; - -static const char * const eth_src[] = { - "pll4_p", "pll3_q" -}; - -static const struct clk_parent_data ethrx_src[] = { - { .name = "ethck_k", .fw_name = "ETH_RX_CLK/ETH_REF_CLK" }, -}; - -static const char * const rng_src[] = { - "ck_csi", "pll4_r", "ck_lse", "ck_lsi" -}; - -static const char * const usbphy_src[] = { - "ck_hse", "pll4_r", "clk-hse-div2" -}; - -static const char * const usbo_src[] = { - "pll4_r", "ck_usbo_48m" -}; - -static const char * const stgen_src[] = { - "ck_hsi", "ck_hse" -}; - -static const char * const spdif_src[] = { - "pll4_p", "pll3_q", "ck_hsi" -}; - -static const char * const spi123_src[] = { - "pll4_p", "pll3_q", "i2s_ckin", "ck_per", "pll3_r" -}; - -static const char * const spi45_src[] = { - "pclk2", "pll4_q", "ck_hsi", "ck_csi", "ck_hse" -}; - -static const char * const spi6_src[] = { - "pclk5", "pll4_q", "ck_hsi", "ck_csi", "ck_hse", "pll3_q" -}; - -static const char * const cec_src[] = { - "ck_lse", "ck_lsi", "ck_csi" -}; - -static const char * const i2c12_src[] = { - "pclk1", "pll4_r", "ck_hsi", "ck_csi" -}; - -static const char * const i2c35_src[] = { - "pclk1", "pll4_r", "ck_hsi", "ck_csi" -}; - -static const char * const i2c46_src[] = { - "pclk5", "pll3_q", "ck_hsi", "ck_csi" -}; - -static const char * const lptim1_src[] = { - "pclk1", "pll4_p", "pll3_q", "ck_lse", "ck_lsi", "ck_per" -}; - -static const char * const lptim23_src[] = { - "pclk3", "pll4_q", "ck_per", "ck_lse", "ck_lsi" -}; - -static const char * const lptim45_src[] = { - "pclk3", "pll4_p", "pll3_q", "ck_lse", "ck_lsi", "ck_per" -}; - -static const char * const usart1_src[] = { - "pclk5", "pll3_q", "ck_hsi", "ck_csi", "pll4_q", "ck_hse" -}; - -static const char * const usart234578_src[] = { - "pclk1", "pll4_q", "ck_hsi", "ck_csi", "ck_hse" -}; - -static const char * const usart6_src[] = { - "pclk2", "pll4_q", "ck_hsi", "ck_csi", "ck_hse" -}; - -static const char * const fdcan_src[] = { - "ck_hse", "pll3_q", "pll4_q", "pll4_r" -}; - -static const char * const sai_src[] = { - "pll4_q", "pll3_q", "i2s_ckin", "ck_per", "pll3_r" -}; - -static const char * const sai2_src[] = { - "pll4_q", "pll3_q", "i2s_ckin", "ck_per", "spdif_ck_symb", "pll3_r" -}; - -static const char * const adc12_src[] = { - "pll4_r", "ck_per", "pll3_q" -}; - -static const char * const dsi_src[] = { - "ck_dsi_phy", "pll4_p" -}; - -static const char * const rtc_src[] = { - "off", "ck_lse", "ck_lsi", "ck_hse" -}; - -static const char * const mco1_src[] = { - "ck_hsi", "ck_hse", "ck_csi", "ck_lsi", "ck_lse" -}; - -static const char * const mco2_src[] = { - "ck_mpu", "ck_axi", "ck_mcu", "pll4_p", "ck_hse", "ck_hsi" -}; - -static const char * const ck_trace_src[] = { - "ck_axi" -}; - -static const struct clk_div_table axi_div_table[] = { - { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 }, - { 4, 4 }, { 5, 4 }, { 6, 4 }, { 7, 4 }, - { 0 }, -}; - -static const struct clk_div_table mcu_div_table[] = { - { 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 8 }, - { 4, 16 }, { 5, 32 }, { 6, 64 }, { 7, 128 }, - { 8, 256 }, { 9, 512 }, { 10, 512}, { 11, 512 }, - { 12, 512 }, { 13, 512 }, { 14, 512}, { 15, 512 }, - { 0 }, -}; - -static const struct clk_div_table apb_div_table[] = { - { 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 8 }, - { 4, 16 }, { 5, 16 }, { 6, 16 }, { 7, 16 }, - { 0 }, -}; - -static const struct clk_div_table ck_trace_div_table[] = { - { 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 8 }, - { 4, 16 }, { 5, 16 }, { 6, 16 }, { 7, 16 }, - { 0 }, -}; - -#define MAX_MUX_CLK 2 - -struct stm32_mmux { - u8 nbr_clk; - struct clk_hw *hws[MAX_MUX_CLK]; -}; - -struct stm32_clk_mmux { - struct clk_mux mux; - struct stm32_mmux *mmux; -}; - -struct stm32_mgate { - u8 nbr_clk; - u32 flag; -}; - -struct stm32_clk_mgate { - struct clk_gate gate; - struct stm32_mgate *mgate; - u32 mask; -}; - -struct clock_config { - u32 id; - const char *name; - const char *parent_name; - const char * const *parent_names; - const struct clk_parent_data *parent_data; - int num_parents; - unsigned long flags; - void *cfg; - struct clk_hw * (*func)(struct device *dev, - struct clk_hw_onecell_data *clk_data, - void __iomem *base, spinlock_t *lock, - const struct clock_config *cfg); -}; - -#define NO_ID ~0 - -struct gate_cfg { - u32 reg_off; - u8 bit_idx; - u8 gate_flags; -}; - -struct fixed_factor_cfg { - unsigned int mult; - unsigned int div; -}; - -struct div_cfg { - u32 reg_off; - u8 shift; - u8 width; - u8 div_flags; - const struct clk_div_table *table; -}; - -struct mux_cfg { - u32 reg_off; - u8 shift; - u8 width; - u8 mux_flags; - u32 *table; -}; - -struct stm32_gate_cfg { - struct gate_cfg *gate; - struct stm32_mgate *mgate; - const struct clk_ops *ops; -}; - -struct stm32_div_cfg { - struct div_cfg *div; - const struct clk_ops *ops; -}; - -struct stm32_mux_cfg { - struct mux_cfg *mux; - struct stm32_mmux *mmux; - const struct clk_ops *ops; -}; - -/* STM32 Composite clock */ -struct stm32_composite_cfg { - const struct stm32_gate_cfg *gate; - const struct stm32_div_cfg *div; - const struct stm32_mux_cfg *mux; -}; - -static struct clk_hw * -_clk_hw_register_gate(struct device *dev, - struct clk_hw_onecell_data *clk_data, - void __iomem *base, spinlock_t *lock, - const struct clock_config *cfg) -{ - struct gate_cfg *gate_cfg = cfg->cfg; - - return clk_hw_register_gate(dev, - cfg->name, - cfg->parent_name, - cfg->flags, - gate_cfg->reg_off + base, - gate_cfg->bit_idx, - gate_cfg->gate_flags, - lock); -} - -static struct clk_hw * -_clk_hw_register_fixed_factor(struct device *dev, - struct clk_hw_onecell_data *clk_data, - void __iomem *base, spinlock_t *lock, - const struct clock_config *cfg) -{ - struct fixed_factor_cfg *ff_cfg = cfg->cfg; - - return clk_hw_register_fixed_factor(dev, cfg->name, cfg->parent_name, - cfg->flags, ff_cfg->mult, - ff_cfg->div); -} - -static struct clk_hw * -_clk_hw_register_divider_table(struct device *dev, - struct clk_hw_onecell_data *clk_data, - void __iomem *base, spinlock_t *lock, - const struct clock_config *cfg) -{ - struct div_cfg *div_cfg = cfg->cfg; - - return clk_hw_register_divider_table(dev, - cfg->name, - cfg->parent_name, - cfg->flags, - div_cfg->reg_off + base, - div_cfg->shift, - div_cfg->width, - div_cfg->div_flags, - div_cfg->table, - lock); -} - -static struct clk_hw * -_clk_hw_register_mux(struct device *dev, - struct clk_hw_onecell_data *clk_data, - void __iomem *base, spinlock_t *lock, - const struct clock_config *cfg) -{ - struct mux_cfg *mux_cfg = cfg->cfg; - - return clk_hw_register_mux(dev, cfg->name, cfg->parent_names, - cfg->num_parents, cfg->flags, - mux_cfg->reg_off + base, mux_cfg->shift, - mux_cfg->width, mux_cfg->mux_flags, lock); -} - -/* MP1 Gate clock with set & clear registers */ - -static int mp1_gate_clk_enable(struct clk_hw *hw) -{ - if (!clk_gate_ops.is_enabled(hw)) - clk_gate_ops.enable(hw); - - return 0; -} - -static void mp1_gate_clk_disable(struct clk_hw *hw) -{ - struct clk_gate *gate = to_clk_gate(hw); - unsigned long flags = 0; - - if (clk_gate_ops.is_enabled(hw)) { - spin_lock_irqsave(gate->lock, flags); - writel_relaxed(BIT(gate->bit_idx), gate->reg + RCC_CLR); - spin_unlock_irqrestore(gate->lock, flags); - } -} - -static const struct clk_ops mp1_gate_clk_ops = { - .enable = mp1_gate_clk_enable, - .disable = mp1_gate_clk_disable, - .is_enabled = clk_gate_is_enabled, -}; - -static struct clk_hw *_get_stm32_mux(struct device *dev, void __iomem *base, - const struct stm32_mux_cfg *cfg, - spinlock_t *lock) -{ - struct stm32_clk_mmux *mmux; - struct clk_mux *mux; - struct clk_hw *mux_hw; - - if (cfg->mmux) { - mmux = devm_kzalloc(dev, sizeof(*mmux), GFP_KERNEL); - if (!mmux) - return ERR_PTR(-ENOMEM); - - mmux->mux.reg = cfg->mux->reg_off + base; - mmux->mux.shift = cfg->mux->shift; - mmux->mux.mask = (1 << cfg->mux->width) - 1; - mmux->mux.flags = cfg->mux->mux_flags; - mmux->mux.table = cfg->mux->table; - mmux->mux.lock = lock; - mmux->mmux = cfg->mmux; - mux_hw = &mmux->mux.hw; - cfg->mmux->hws[cfg->mmux->nbr_clk++] = mux_hw; - - } else { - mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); - if (!mux) - return ERR_PTR(-ENOMEM); - - mux->reg = cfg->mux->reg_off + base; - mux->shift = cfg->mux->shift; - mux->mask = (1 << cfg->mux->width) - 1; - mux->flags = cfg->mux->mux_flags; - mux->table = cfg->mux->table; - mux->lock = lock; - mux_hw = &mux->hw; - } - - return mux_hw; -} - -static struct clk_hw *_get_stm32_div(struct device *dev, void __iomem *base, - const struct stm32_div_cfg *cfg, - spinlock_t *lock) -{ - struct clk_divider *div; - - div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL); - - if (!div) - return ERR_PTR(-ENOMEM); - - div->reg = cfg->div->reg_off + base; - div->shift = cfg->div->shift; - div->width = cfg->div->width; - div->flags = cfg->div->div_flags; - div->table = cfg->div->table; - div->lock = lock; - - return &div->hw; -} - -static struct clk_hw *_get_stm32_gate(struct device *dev, void __iomem *base, - const struct stm32_gate_cfg *cfg, - spinlock_t *lock) -{ - struct stm32_clk_mgate *mgate; - struct clk_gate *gate; - struct clk_hw *gate_hw; - - if (cfg->mgate) { - mgate = devm_kzalloc(dev, sizeof(*mgate), GFP_KERNEL); - if (!mgate) - return ERR_PTR(-ENOMEM); - - mgate->gate.reg = cfg->gate->reg_off + base; - mgate->gate.bit_idx = cfg->gate->bit_idx; - mgate->gate.flags = cfg->gate->gate_flags; - mgate->gate.lock = lock; - mgate->mask = BIT(cfg->mgate->nbr_clk++); - - mgate->mgate = cfg->mgate; - - gate_hw = &mgate->gate.hw; - - } else { - gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL); - if (!gate) - return ERR_PTR(-ENOMEM); - - gate->reg = cfg->gate->reg_off + base; - gate->bit_idx = cfg->gate->bit_idx; - gate->flags = cfg->gate->gate_flags; - gate->lock = lock; - - gate_hw = &gate->hw; - } - - return gate_hw; -} - -static struct clk_hw * -clk_stm32_register_gate_ops(struct device *dev, - const char *name, - const char *parent_name, - const struct clk_parent_data *parent_data, - unsigned long flags, - void __iomem *base, - const struct stm32_gate_cfg *cfg, - spinlock_t *lock) -{ - struct clk_init_data init = { NULL }; - struct clk_hw *hw; - int ret; - - init.name = name; - if (parent_name) - init.parent_names = &parent_name; - if (parent_data) - init.parent_data = parent_data; - init.num_parents = 1; - init.flags = flags; - - init.ops = &clk_gate_ops; - - if (cfg->ops) - init.ops = cfg->ops; - - hw = _get_stm32_gate(dev, base, cfg, lock); - if (IS_ERR(hw)) - return ERR_PTR(-ENOMEM); - - hw->init = &init; - - ret = clk_hw_register(dev, hw); - if (ret) - hw = ERR_PTR(ret); - - return hw; -} - -static struct clk_hw * -clk_stm32_register_composite(struct device *dev, - const char *name, const char * const *parent_names, - const struct clk_parent_data *parent_data, - int num_parents, void __iomem *base, - const struct stm32_composite_cfg *cfg, - unsigned long flags, spinlock_t *lock) -{ - const struct clk_ops *mux_ops, *div_ops, *gate_ops; - struct clk_hw *mux_hw, *div_hw, *gate_hw; - - mux_hw = NULL; - div_hw = NULL; - gate_hw = NULL; - mux_ops = NULL; - div_ops = NULL; - gate_ops = NULL; - - if (cfg->mux) { - mux_hw = _get_stm32_mux(dev, base, cfg->mux, lock); - - if (!IS_ERR(mux_hw)) { - mux_ops = &clk_mux_ops; - - if (cfg->mux->ops) - mux_ops = cfg->mux->ops; - } - } - - if (cfg->div) { - div_hw = _get_stm32_div(dev, base, cfg->div, lock); - - if (!IS_ERR(div_hw)) { - div_ops = &clk_divider_ops; - - if (cfg->div->ops) - div_ops = cfg->div->ops; - } - } - - if (cfg->gate) { - gate_hw = _get_stm32_gate(dev, base, cfg->gate, lock); - - if (!IS_ERR(gate_hw)) { - gate_ops = &clk_gate_ops; - - if (cfg->gate->ops) - gate_ops = cfg->gate->ops; - } - } - - return clk_hw_register_composite(dev, name, parent_names, num_parents, - mux_hw, mux_ops, div_hw, div_ops, - gate_hw, gate_ops, flags); -} - -#define to_clk_mgate(_gate) container_of(_gate, struct stm32_clk_mgate, gate) - -static int mp1_mgate_clk_enable(struct clk_hw *hw) -{ - struct clk_gate *gate = to_clk_gate(hw); - struct stm32_clk_mgate *clk_mgate = to_clk_mgate(gate); - - clk_mgate->mgate->flag |= clk_mgate->mask; - - mp1_gate_clk_enable(hw); - - return 0; -} - -static void mp1_mgate_clk_disable(struct clk_hw *hw) -{ - struct clk_gate *gate = to_clk_gate(hw); - struct stm32_clk_mgate *clk_mgate = to_clk_mgate(gate); - - clk_mgate->mgate->flag &= ~clk_mgate->mask; - - if (clk_mgate->mgate->flag == 0) - mp1_gate_clk_disable(hw); -} - -static const struct clk_ops mp1_mgate_clk_ops = { - .enable = mp1_mgate_clk_enable, - .disable = mp1_mgate_clk_disable, - .is_enabled = clk_gate_is_enabled, - -}; - -#define to_clk_mmux(_mux) container_of(_mux, struct stm32_clk_mmux, mux) - -static u8 clk_mmux_get_parent(struct clk_hw *hw) -{ - return clk_mux_ops.get_parent(hw); -} - -static int clk_mmux_set_parent(struct clk_hw *hw, u8 index) -{ - struct clk_mux *mux = to_clk_mux(hw); - struct stm32_clk_mmux *clk_mmux = to_clk_mmux(mux); - struct clk_hw *hwp; - int ret, n; - - ret = clk_mux_ops.set_parent(hw, index); - if (ret) - return ret; - - hwp = clk_hw_get_parent(hw); - - for (n = 0; n < clk_mmux->mmux->nbr_clk; n++) - if (clk_mmux->mmux->hws[n] != hw) - clk_hw_reparent(clk_mmux->mmux->hws[n], hwp); - - return 0; -} - -static const struct clk_ops clk_mmux_ops = { - .get_parent = clk_mmux_get_parent, - .set_parent = clk_mmux_set_parent, - .determine_rate = __clk_mux_determine_rate, -}; - -/* STM32 PLL */ -struct stm32_pll_obj { - /* lock pll enable/disable registers */ - spinlock_t *lock; - void __iomem *reg; - struct clk_hw hw; - struct clk_mux mux; -}; - -#define to_pll(_hw) container_of(_hw, struct stm32_pll_obj, hw) - -#define PLL_ON BIT(0) -#define PLL_RDY BIT(1) -#define DIVN_MASK 0x1FF -#define DIVM_MASK 0x3F -#define DIVM_SHIFT 16 -#define DIVN_SHIFT 0 -#define FRAC_OFFSET 0xC -#define FRAC_MASK 0x1FFF -#define FRAC_SHIFT 3 -#define FRACLE BIT(16) -#define PLL_MUX_SHIFT 0 -#define PLL_MUX_MASK 3 - -static int __pll_is_enabled(struct clk_hw *hw) -{ - struct stm32_pll_obj *clk_elem = to_pll(hw); - - return readl_relaxed(clk_elem->reg) & PLL_ON; -} - -#define TIMEOUT 5 - -static int pll_enable(struct clk_hw *hw) -{ - struct stm32_pll_obj *clk_elem = to_pll(hw); - u32 reg; - unsigned long flags = 0; - unsigned int timeout = TIMEOUT; - int bit_status = 0; - - spin_lock_irqsave(clk_elem->lock, flags); - - if (__pll_is_enabled(hw)) - goto unlock; - - reg = readl_relaxed(clk_elem->reg); - reg |= PLL_ON; - writel_relaxed(reg, clk_elem->reg); - - /* We can't use readl_poll_timeout() because we can be blocked if - * someone enables this clock before clocksource changes. - * Only jiffies counter is available. Jiffies are incremented by - * interruptions and enable op does not allow to be interrupted. - */ - do { - bit_status = !(readl_relaxed(clk_elem->reg) & PLL_RDY); - - if (bit_status) - udelay(120); - - } while (bit_status && --timeout); - -unlock: - spin_unlock_irqrestore(clk_elem->lock, flags); - - return bit_status; -} - -static void pll_disable(struct clk_hw *hw) -{ - struct stm32_pll_obj *clk_elem = to_pll(hw); - u32 reg; - unsigned long flags = 0; - - spin_lock_irqsave(clk_elem->lock, flags); - - reg = readl_relaxed(clk_elem->reg); - reg &= ~PLL_ON; - writel_relaxed(reg, clk_elem->reg); - - spin_unlock_irqrestore(clk_elem->lock, flags); -} - -static u32 pll_frac_val(struct clk_hw *hw) -{ - struct stm32_pll_obj *clk_elem = to_pll(hw); - u32 reg, frac = 0; - - reg = readl_relaxed(clk_elem->reg + FRAC_OFFSET); - if (reg & FRACLE) - frac = (reg >> FRAC_SHIFT) & FRAC_MASK; - - return frac; -} - -static unsigned long pll_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct stm32_pll_obj *clk_elem = to_pll(hw); - u32 reg; - u32 frac, divm, divn; - u64 rate, rate_frac = 0; - - reg = readl_relaxed(clk_elem->reg + 4); - - divm = ((reg >> DIVM_SHIFT) & DIVM_MASK) + 1; - divn = ((reg >> DIVN_SHIFT) & DIVN_MASK) + 1; - rate = (u64)parent_rate * divn; - - do_div(rate, divm); - - frac = pll_frac_val(hw); - if (frac) { - rate_frac = (u64)parent_rate * (u64)frac; - do_div(rate_frac, (divm * 8192)); - } - - return rate + rate_frac; -} - -static int pll_is_enabled(struct clk_hw *hw) -{ - struct stm32_pll_obj *clk_elem = to_pll(hw); - unsigned long flags = 0; - int ret; - - spin_lock_irqsave(clk_elem->lock, flags); - ret = __pll_is_enabled(hw); - spin_unlock_irqrestore(clk_elem->lock, flags); - - return ret; -} - -static u8 pll_get_parent(struct clk_hw *hw) -{ - struct stm32_pll_obj *clk_elem = to_pll(hw); - struct clk_hw *mux_hw = &clk_elem->mux.hw; - - __clk_hw_set_clk(mux_hw, hw); - - return clk_mux_ops.get_parent(mux_hw); -} - -static const struct clk_ops pll_ops = { - .enable = pll_enable, - .disable = pll_disable, - .recalc_rate = pll_recalc_rate, - .is_enabled = pll_is_enabled, - .get_parent = pll_get_parent, -}; - -static struct clk_hw *clk_register_pll(struct device *dev, const char *name, - const char * const *parent_names, - int num_parents, - void __iomem *reg, - void __iomem *mux_reg, - unsigned long flags, - spinlock_t *lock) -{ - struct stm32_pll_obj *element; - struct clk_init_data init; - struct clk_hw *hw; - int err; - - element = devm_kzalloc(dev, sizeof(*element), GFP_KERNEL); - if (!element) - return ERR_PTR(-ENOMEM); - - init.name = name; - init.ops = &pll_ops; - init.flags = flags; - init.parent_names = parent_names; - init.num_parents = num_parents; - - element->mux.lock = lock; - element->mux.reg = mux_reg; - element->mux.shift = PLL_MUX_SHIFT; - element->mux.mask = PLL_MUX_MASK; - element->mux.flags = CLK_MUX_READ_ONLY; - element->mux.reg = mux_reg; - - element->hw.init = &init; - element->reg = reg; - element->lock = lock; - - hw = &element->hw; - err = clk_hw_register(dev, hw); - - if (err) - return ERR_PTR(err); - - return hw; -} - -/* Kernel Timer */ -struct timer_cker { - /* lock the kernel output divider register */ - spinlock_t *lock; - void __iomem *apbdiv; - void __iomem *timpre; - struct clk_hw hw; -}; - -#define to_timer_cker(_hw) container_of(_hw, struct timer_cker, hw) - -#define APB_DIV_MASK 0x07 -#define TIM_PRE_MASK 0x01 - -static unsigned long __bestmult(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct timer_cker *tim_ker = to_timer_cker(hw); - u32 prescaler; - unsigned int mult = 0; - - prescaler = readl_relaxed(tim_ker->apbdiv) & APB_DIV_MASK; - if (prescaler < 2) - return 1; - - mult = 2; - - if (rate / parent_rate >= 4) - mult = 4; - - return mult; -} - -static long timer_ker_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) -{ - unsigned long factor = __bestmult(hw, rate, *parent_rate); - - return *parent_rate * factor; -} - -static int timer_ker_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct timer_cker *tim_ker = to_timer_cker(hw); - unsigned long flags = 0; - unsigned long factor = __bestmult(hw, rate, parent_rate); - int ret = 0; - - spin_lock_irqsave(tim_ker->lock, flags); - - switch (factor) { - case 1: - break; - case 2: - writel_relaxed(0, tim_ker->timpre); - break; - case 4: - writel_relaxed(1, tim_ker->timpre); - break; - default: - ret = -EINVAL; - } - spin_unlock_irqrestore(tim_ker->lock, flags); - - return ret; -} - -static unsigned long timer_ker_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct timer_cker *tim_ker = to_timer_cker(hw); - u32 prescaler, timpre; - u32 mul; - - prescaler = readl_relaxed(tim_ker->apbdiv) & APB_DIV_MASK; - - timpre = readl_relaxed(tim_ker->timpre) & TIM_PRE_MASK; - - if (!prescaler) - return parent_rate; - - mul = (timpre + 1) * 2; - - return parent_rate * mul; -} - -static const struct clk_ops timer_ker_ops = { - .recalc_rate = timer_ker_recalc_rate, - .round_rate = timer_ker_round_rate, - .set_rate = timer_ker_set_rate, - -}; - -static struct clk_hw *clk_register_cktim(struct device *dev, const char *name, - const char *parent_name, - unsigned long flags, - void __iomem *apbdiv, - void __iomem *timpre, - spinlock_t *lock) -{ - struct timer_cker *tim_ker; - struct clk_init_data init; - struct clk_hw *hw; - int err; - - tim_ker = devm_kzalloc(dev, sizeof(*tim_ker), GFP_KERNEL); - if (!tim_ker) - return ERR_PTR(-ENOMEM); - - init.name = name; - init.ops = &timer_ker_ops; - init.flags = flags; - init.parent_names = &parent_name; - init.num_parents = 1; - - tim_ker->hw.init = &init; - tim_ker->lock = lock; - tim_ker->apbdiv = apbdiv; - tim_ker->timpre = timpre; - - hw = &tim_ker->hw; - err = clk_hw_register(dev, hw); - - if (err) - return ERR_PTR(err); - - return hw; -} - -/* The divider of RTC clock concerns only ck_hse clock */ -#define HSE_RTC 3 - -static unsigned long clk_divider_rtc_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - if (clk_hw_get_parent(hw) == clk_hw_get_parent_by_index(hw, HSE_RTC)) - return clk_divider_ops.recalc_rate(hw, parent_rate); - - return parent_rate; -} - -static int clk_divider_rtc_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - if (clk_hw_get_parent(hw) == clk_hw_get_parent_by_index(hw, HSE_RTC)) - return clk_divider_ops.set_rate(hw, rate, parent_rate); - - return parent_rate; -} - -static int clk_divider_rtc_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) -{ - if (req->best_parent_hw == clk_hw_get_parent_by_index(hw, HSE_RTC)) - return clk_divider_ops.determine_rate(hw, req); - - req->rate = req->best_parent_rate; - - return 0; -} - -static const struct clk_ops rtc_div_clk_ops = { - .recalc_rate = clk_divider_rtc_recalc_rate, - .set_rate = clk_divider_rtc_set_rate, - .determine_rate = clk_divider_rtc_determine_rate -}; - -struct stm32_pll_cfg { - u32 offset; - u32 muxoff; -}; - -static struct clk_hw *_clk_register_pll(struct device *dev, - struct clk_hw_onecell_data *clk_data, - void __iomem *base, spinlock_t *lock, - const struct clock_config *cfg) -{ - struct stm32_pll_cfg *stm_pll_cfg = cfg->cfg; - - return clk_register_pll(dev, cfg->name, cfg->parent_names, - cfg->num_parents, - base + stm_pll_cfg->offset, - base + stm_pll_cfg->muxoff, - cfg->flags, lock); -} - -struct stm32_cktim_cfg { - u32 offset_apbdiv; - u32 offset_timpre; -}; - -static struct clk_hw *_clk_register_cktim(struct device *dev, - struct clk_hw_onecell_data *clk_data, - void __iomem *base, spinlock_t *lock, - const struct clock_config *cfg) -{ - struct stm32_cktim_cfg *cktim_cfg = cfg->cfg; - - return clk_register_cktim(dev, cfg->name, cfg->parent_name, cfg->flags, - cktim_cfg->offset_apbdiv + base, - cktim_cfg->offset_timpre + base, lock); -} - -static struct clk_hw * -_clk_stm32_register_gate(struct device *dev, - struct clk_hw_onecell_data *clk_data, - void __iomem *base, spinlock_t *lock, - const struct clock_config *cfg) -{ - return clk_stm32_register_gate_ops(dev, - cfg->name, - cfg->parent_name, - cfg->parent_data, - cfg->flags, - base, - cfg->cfg, - lock); -} - -static struct clk_hw * -_clk_stm32_register_composite(struct device *dev, - struct clk_hw_onecell_data *clk_data, - void __iomem *base, spinlock_t *lock, - const struct clock_config *cfg) -{ - return clk_stm32_register_composite(dev, cfg->name, cfg->parent_names, - cfg->parent_data, cfg->num_parents, - base, cfg->cfg, cfg->flags, lock); -} - -#define GATE(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\ -{\ - .id = _id,\ - .name = _name,\ - .parent_name = _parent,\ - .flags = _flags,\ - .cfg = &(struct gate_cfg) {\ - .reg_off = _offset,\ - .bit_idx = _bit_idx,\ - .gate_flags = _gate_flags,\ - },\ - .func = _clk_hw_register_gate,\ -} - -#define FIXED_FACTOR(_id, _name, _parent, _flags, _mult, _div)\ -{\ - .id = _id,\ - .name = _name,\ - .parent_name = _parent,\ - .flags = _flags,\ - .cfg = &(struct fixed_factor_cfg) {\ - .mult = _mult,\ - .div = _div,\ - },\ - .func = _clk_hw_register_fixed_factor,\ -} - -#define DIV_TABLE(_id, _name, _parent, _flags, _offset, _shift, _width,\ - _div_flags, _div_table)\ -{\ - .id = _id,\ - .name = _name,\ - .parent_name = _parent,\ - .flags = _flags,\ - .cfg = &(struct div_cfg) {\ - .reg_off = _offset,\ - .shift = _shift,\ - .width = _width,\ - .div_flags = _div_flags,\ - .table = _div_table,\ - },\ - .func = _clk_hw_register_divider_table,\ -} - -#define DIV(_id, _name, _parent, _flags, _offset, _shift, _width, _div_flags)\ - DIV_TABLE(_id, _name, _parent, _flags, _offset, _shift, _width,\ - _div_flags, NULL) - -#define MUX(_id, _name, _parents, _flags, _offset, _shift, _width, _mux_flags)\ -{\ - .id = _id,\ - .name = _name,\ - .parent_names = _parents,\ - .num_parents = ARRAY_SIZE(_parents),\ - .flags = _flags,\ - .cfg = &(struct mux_cfg) {\ - .reg_off = _offset,\ - .shift = _shift,\ - .width = _width,\ - .mux_flags = _mux_flags,\ - },\ - .func = _clk_hw_register_mux,\ -} - -#define PLL(_id, _name, _parents, _flags, _offset_p, _offset_mux)\ -{\ - .id = _id,\ - .name = _name,\ - .parent_names = _parents,\ - .num_parents = ARRAY_SIZE(_parents),\ - .flags = CLK_IGNORE_UNUSED | (_flags),\ - .cfg = &(struct stm32_pll_cfg) {\ - .offset = _offset_p,\ - .muxoff = _offset_mux,\ - },\ - .func = _clk_register_pll,\ -} - -#define STM32_CKTIM(_name, _parent, _flags, _offset_apbdiv, _offset_timpre)\ -{\ - .id = NO_ID,\ - .name = _name,\ - .parent_name = _parent,\ - .flags = _flags,\ - .cfg = &(struct stm32_cktim_cfg) {\ - .offset_apbdiv = _offset_apbdiv,\ - .offset_timpre = _offset_timpre,\ - },\ - .func = _clk_register_cktim,\ -} - -#define STM32_TIM(_id, _name, _parent, _offset_set, _bit_idx)\ - GATE_MP1(_id, _name, _parent, CLK_SET_RATE_PARENT,\ - _offset_set, _bit_idx, 0) - -/* STM32 GATE */ -#define STM32_GATE(_id, _name, _parent, _flags, _gate)\ -{\ - .id = _id,\ - .name = _name,\ - .parent_name = _parent,\ - .flags = _flags,\ - .cfg = (struct stm32_gate_cfg *) {_gate},\ - .func = _clk_stm32_register_gate,\ -} - -#define STM32_GATE_PDATA(_id, _name, _parent, _flags, _gate)\ -{\ - .id = _id,\ - .name = _name,\ - .parent_data = _parent,\ - .flags = _flags,\ - .cfg = (struct stm32_gate_cfg *) {_gate},\ - .func = _clk_stm32_register_gate,\ -} - -#define _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags, _mgate, _ops)\ - (&(struct stm32_gate_cfg) {\ - &(struct gate_cfg) {\ - .reg_off = _gate_offset,\ - .bit_idx = _gate_bit_idx,\ - .gate_flags = _gate_flags,\ - },\ - .mgate = _mgate,\ - .ops = _ops,\ - }) - -#define _STM32_MGATE(_mgate)\ - (&per_gate_cfg[_mgate]) - -#define _GATE(_gate_offset, _gate_bit_idx, _gate_flags)\ - _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags,\ - NULL, NULL)\ - -#define _GATE_MP1(_gate_offset, _gate_bit_idx, _gate_flags)\ - _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags,\ - NULL, &mp1_gate_clk_ops)\ - -#define _MGATE_MP1(_mgate)\ - .gate = &per_gate_cfg[_mgate] - -#define GATE_MP1(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\ - STM32_GATE(_id, _name, _parent, _flags,\ - _GATE_MP1(_offset, _bit_idx, _gate_flags)) - -#define MGATE_MP1(_id, _name, _parent, _flags, _mgate)\ - STM32_GATE(_id, _name, _parent, _flags,\ - _STM32_MGATE(_mgate)) - -#define MGATE_MP1_PDATA(_id, _name, _parent, _flags, _mgate)\ - STM32_GATE_PDATA(_id, _name, _parent, _flags,\ - _STM32_MGATE(_mgate)) - -#define _STM32_DIV(_div_offset, _div_shift, _div_width,\ - _div_flags, _div_table, _ops)\ - .div = &(struct stm32_div_cfg) {\ - &(struct div_cfg) {\ - .reg_off = _div_offset,\ - .shift = _div_shift,\ - .width = _div_width,\ - .div_flags = _div_flags,\ - .table = _div_table,\ - },\ - .ops = _ops,\ - } - -#define _DIV(_div_offset, _div_shift, _div_width, _div_flags, _div_table)\ - _STM32_DIV(_div_offset, _div_shift, _div_width,\ - _div_flags, _div_table, NULL)\ - -#define _DIV_RTC(_div_offset, _div_shift, _div_width, _div_flags, _div_table)\ - _STM32_DIV(_div_offset, _div_shift, _div_width,\ - _div_flags, _div_table, &rtc_div_clk_ops) - -#define _STM32_MUX(_offset, _shift, _width, _mux_flags, _mmux, _ops)\ - .mux = &(struct stm32_mux_cfg) {\ - &(struct mux_cfg) {\ - .reg_off = _offset,\ - .shift = _shift,\ - .width = _width,\ - .mux_flags = _mux_flags,\ - .table = NULL,\ - },\ - .mmux = _mmux,\ - .ops = _ops,\ - } - -#define _MUX(_offset, _shift, _width, _mux_flags)\ - _STM32_MUX(_offset, _shift, _width, _mux_flags, NULL, NULL)\ - -#define _MMUX(_mmux) .mux = &ker_mux_cfg[_mmux] - -#define PARENT(_parent) ((const char *[]) { _parent}) - -#define _NO_MUX .mux = NULL -#define _NO_DIV .div = NULL -#define _NO_GATE .gate = NULL - -#define COMPOSITE(_id, _name, _parents, _flags, _gate, _mux, _div)\ -{\ - .id = _id,\ - .name = _name,\ - .parent_names = _parents,\ - .num_parents = ARRAY_SIZE(_parents),\ - .flags = _flags,\ - .cfg = &(struct stm32_composite_cfg) {\ - _gate,\ - _mux,\ - _div,\ - },\ - .func = _clk_stm32_register_composite,\ -} - -#define PCLK(_id, _name, _parent, _flags, _mgate)\ - MGATE_MP1(_id, _name, _parent, _flags, _mgate) - -#define PCLK_PDATA(_id, _name, _parent, _flags, _mgate)\ - MGATE_MP1_PDATA(_id, _name, _parent, _flags, _mgate) - -#define KCLK(_id, _name, _parents, _flags, _mgate, _mmux)\ - COMPOSITE(_id, _name, _parents, CLK_OPS_PARENT_ENABLE |\ - CLK_SET_RATE_NO_REPARENT | _flags,\ - _MGATE_MP1(_mgate),\ - _MMUX(_mmux),\ - _NO_DIV) - -enum { - G_SAI1, - G_SAI2, - G_SAI3, - G_SAI4, - G_SPI1, - G_SPI2, - G_SPI3, - G_SPI4, - G_SPI5, - G_SPI6, - G_SPDIF, - G_I2C1, - G_I2C2, - G_I2C3, - G_I2C4, - G_I2C5, - G_I2C6, - G_USART2, - G_UART4, - G_USART3, - G_UART5, - G_USART1, - G_USART6, - G_UART7, - G_UART8, - G_LPTIM1, - G_LPTIM2, - G_LPTIM3, - G_LPTIM4, - G_LPTIM5, - G_LTDC, - G_DSI, - G_QSPI, - G_FMC, - G_SDMMC1, - G_SDMMC2, - G_SDMMC3, - G_USBO, - G_USBPHY, - G_RNG1, - G_RNG2, - G_FDCAN, - G_DAC12, - G_CEC, - G_ADC12, - G_GPU, - G_STGEN, - G_DFSDM, - G_ADFSDM, - G_TIM2, - G_TIM3, - G_TIM4, - G_TIM5, - G_TIM6, - G_TIM7, - G_TIM12, - G_TIM13, - G_TIM14, - G_MDIO, - G_TIM1, - G_TIM8, - G_TIM15, - G_TIM16, - G_TIM17, - G_SYSCFG, - G_VREF, - G_TMPSENS, - G_PMBCTRL, - G_HDP, - G_IWDG2, - G_STGENRO, - G_DMA1, - G_DMA2, - G_DMAMUX, - G_DCMI, - G_CRYP2, - G_HASH2, - G_CRC2, - G_HSEM, - G_IPCC, - G_GPIOA, - G_GPIOB, - G_GPIOC, - G_GPIOD, - G_GPIOE, - G_GPIOF, - G_GPIOG, - G_GPIOH, - G_GPIOI, - G_GPIOJ, - G_GPIOK, - G_MDMA, - G_ETHCK, - G_ETHTX, - G_ETHRX, - G_ETHMAC, - G_CRC1, - G_USBH, - G_ETHSTP, - G_RTCAPB, - G_TZC1, - G_TZC2, - G_TZPC, - G_IWDG1, - G_BSEC, - G_GPIOZ, - G_CRYP1, - G_HASH1, - G_BKPSRAM, - G_DDRPERFM, - - G_LAST -}; - -static struct stm32_mgate mp1_mgate[G_LAST]; - -#define _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ - _mgate, _ops)\ - [_id] = {\ - &(struct gate_cfg) {\ - .reg_off = _gate_offset,\ - .bit_idx = _gate_bit_idx,\ - .gate_flags = _gate_flags,\ - },\ - .mgate = _mgate,\ - .ops = _ops,\ - } - -#define K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags)\ - _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ - NULL, &mp1_gate_clk_ops) - -#define K_MGATE(_id, _gate_offset, _gate_bit_idx, _gate_flags)\ - _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ - &mp1_mgate[_id], &mp1_mgate_clk_ops) - -/* Peripheral gates */ -static struct stm32_gate_cfg per_gate_cfg[G_LAST] = { - /* Multi gates */ - K_GATE(G_MDIO, RCC_APB1ENSETR, 31, 0), - K_MGATE(G_DAC12, RCC_APB1ENSETR, 29, 0), - K_MGATE(G_CEC, RCC_APB1ENSETR, 27, 0), - K_MGATE(G_SPDIF, RCC_APB1ENSETR, 26, 0), - K_MGATE(G_I2C5, RCC_APB1ENSETR, 24, 0), - K_MGATE(G_I2C3, RCC_APB1ENSETR, 23, 0), - K_MGATE(G_I2C2, RCC_APB1ENSETR, 22, 0), - K_MGATE(G_I2C1, RCC_APB1ENSETR, 21, 0), - K_MGATE(G_UART8, RCC_APB1ENSETR, 19, 0), - K_MGATE(G_UART7, RCC_APB1ENSETR, 18, 0), - K_MGATE(G_UART5, RCC_APB1ENSETR, 17, 0), - K_MGATE(G_UART4, RCC_APB1ENSETR, 16, 0), - K_MGATE(G_USART3, RCC_APB1ENSETR, 15, 0), - K_MGATE(G_USART2, RCC_APB1ENSETR, 14, 0), - K_MGATE(G_SPI3, RCC_APB1ENSETR, 12, 0), - K_MGATE(G_SPI2, RCC_APB1ENSETR, 11, 0), - K_MGATE(G_LPTIM1, RCC_APB1ENSETR, 9, 0), - K_GATE(G_TIM14, RCC_APB1ENSETR, 8, 0), - K_GATE(G_TIM13, RCC_APB1ENSETR, 7, 0), - K_GATE(G_TIM12, RCC_APB1ENSETR, 6, 0), - K_GATE(G_TIM7, RCC_APB1ENSETR, 5, 0), - K_GATE(G_TIM6, RCC_APB1ENSETR, 4, 0), - K_GATE(G_TIM5, RCC_APB1ENSETR, 3, 0), - K_GATE(G_TIM4, RCC_APB1ENSETR, 2, 0), - K_GATE(G_TIM3, RCC_APB1ENSETR, 1, 0), - K_GATE(G_TIM2, RCC_APB1ENSETR, 0, 0), - - K_MGATE(G_FDCAN, RCC_APB2ENSETR, 24, 0), - K_GATE(G_ADFSDM, RCC_APB2ENSETR, 21, 0), - K_GATE(G_DFSDM, RCC_APB2ENSETR, 20, 0), - K_MGATE(G_SAI3, RCC_APB2ENSETR, 18, 0), - K_MGATE(G_SAI2, RCC_APB2ENSETR, 17, 0), - K_MGATE(G_SAI1, RCC_APB2ENSETR, 16, 0), - K_MGATE(G_USART6, RCC_APB2ENSETR, 13, 0), - K_MGATE(G_SPI5, RCC_APB2ENSETR, 10, 0), - K_MGATE(G_SPI4, RCC_APB2ENSETR, 9, 0), - K_MGATE(G_SPI1, RCC_APB2ENSETR, 8, 0), - K_GATE(G_TIM17, RCC_APB2ENSETR, 4, 0), - K_GATE(G_TIM16, RCC_APB2ENSETR, 3, 0), - K_GATE(G_TIM15, RCC_APB2ENSETR, 2, 0), - K_GATE(G_TIM8, RCC_APB2ENSETR, 1, 0), - K_GATE(G_TIM1, RCC_APB2ENSETR, 0, 0), - - K_GATE(G_HDP, RCC_APB3ENSETR, 20, 0), - K_GATE(G_PMBCTRL, RCC_APB3ENSETR, 17, 0), - K_GATE(G_TMPSENS, RCC_APB3ENSETR, 16, 0), - K_GATE(G_VREF, RCC_APB3ENSETR, 13, 0), - K_GATE(G_SYSCFG, RCC_APB3ENSETR, 11, 0), - K_MGATE(G_SAI4, RCC_APB3ENSETR, 8, 0), - K_MGATE(G_LPTIM5, RCC_APB3ENSETR, 3, 0), - K_MGATE(G_LPTIM4, RCC_APB3ENSETR, 2, 0), - K_MGATE(G_LPTIM3, RCC_APB3ENSETR, 1, 0), - K_MGATE(G_LPTIM2, RCC_APB3ENSETR, 0, 0), - - K_GATE(G_STGENRO, RCC_APB4ENSETR, 20, 0), - K_MGATE(G_USBPHY, RCC_APB4ENSETR, 16, 0), - K_GATE(G_IWDG2, RCC_APB4ENSETR, 15, 0), - K_GATE(G_DDRPERFM, RCC_APB4ENSETR, 8, 0), - K_MGATE(G_DSI, RCC_APB4ENSETR, 4, 0), - K_MGATE(G_LTDC, RCC_APB4ENSETR, 0, 0), - - K_GATE(G_STGEN, RCC_APB5ENSETR, 20, 0), - K_GATE(G_BSEC, RCC_APB5ENSETR, 16, 0), - K_GATE(G_IWDG1, RCC_APB5ENSETR, 15, 0), - K_GATE(G_TZPC, RCC_APB5ENSETR, 13, 0), - K_GATE(G_TZC2, RCC_APB5ENSETR, 12, 0), - K_GATE(G_TZC1, RCC_APB5ENSETR, 11, 0), - K_GATE(G_RTCAPB, RCC_APB5ENSETR, 8, 0), - K_MGATE(G_USART1, RCC_APB5ENSETR, 4, 0), - K_MGATE(G_I2C6, RCC_APB5ENSETR, 3, 0), - K_MGATE(G_I2C4, RCC_APB5ENSETR, 2, 0), - K_MGATE(G_SPI6, RCC_APB5ENSETR, 0, 0), - - K_MGATE(G_SDMMC3, RCC_AHB2ENSETR, 16, 0), - K_MGATE(G_USBO, RCC_AHB2ENSETR, 8, 0), - K_MGATE(G_ADC12, RCC_AHB2ENSETR, 5, 0), - K_GATE(G_DMAMUX, RCC_AHB2ENSETR, 2, 0), - K_GATE(G_DMA2, RCC_AHB2ENSETR, 1, 0), - K_GATE(G_DMA1, RCC_AHB2ENSETR, 0, 0), - - K_GATE(G_IPCC, RCC_AHB3ENSETR, 12, 0), - K_GATE(G_HSEM, RCC_AHB3ENSETR, 11, 0), - K_GATE(G_CRC2, RCC_AHB3ENSETR, 7, 0), - K_MGATE(G_RNG2, RCC_AHB3ENSETR, 6, 0), - K_GATE(G_HASH2, RCC_AHB3ENSETR, 5, 0), - K_GATE(G_CRYP2, RCC_AHB3ENSETR, 4, 0), - K_GATE(G_DCMI, RCC_AHB3ENSETR, 0, 0), - - K_GATE(G_GPIOK, RCC_AHB4ENSETR, 10, 0), - K_GATE(G_GPIOJ, RCC_AHB4ENSETR, 9, 0), - K_GATE(G_GPIOI, RCC_AHB4ENSETR, 8, 0), - K_GATE(G_GPIOH, RCC_AHB4ENSETR, 7, 0), - K_GATE(G_GPIOG, RCC_AHB4ENSETR, 6, 0), - K_GATE(G_GPIOF, RCC_AHB4ENSETR, 5, 0), - K_GATE(G_GPIOE, RCC_AHB4ENSETR, 4, 0), - K_GATE(G_GPIOD, RCC_AHB4ENSETR, 3, 0), - K_GATE(G_GPIOC, RCC_AHB4ENSETR, 2, 0), - K_GATE(G_GPIOB, RCC_AHB4ENSETR, 1, 0), - K_GATE(G_GPIOA, RCC_AHB4ENSETR, 0, 0), - - K_GATE(G_BKPSRAM, RCC_AHB5ENSETR, 8, 0), - K_MGATE(G_RNG1, RCC_AHB5ENSETR, 6, 0), - K_GATE(G_HASH1, RCC_AHB5ENSETR, 5, 0), - K_GATE(G_CRYP1, RCC_AHB5ENSETR, 4, 0), - K_GATE(G_GPIOZ, RCC_AHB5ENSETR, 0, 0), - - K_GATE(G_USBH, RCC_AHB6ENSETR, 24, 0), - K_GATE(G_CRC1, RCC_AHB6ENSETR, 20, 0), - K_MGATE(G_SDMMC2, RCC_AHB6ENSETR, 17, 0), - K_MGATE(G_SDMMC1, RCC_AHB6ENSETR, 16, 0), - K_MGATE(G_QSPI, RCC_AHB6ENSETR, 14, 0), - K_MGATE(G_FMC, RCC_AHB6ENSETR, 12, 0), - K_GATE(G_ETHMAC, RCC_AHB6ENSETR, 10, 0), - K_GATE(G_ETHRX, RCC_AHB6ENSETR, 9, 0), - K_GATE(G_ETHTX, RCC_AHB6ENSETR, 8, 0), - K_GATE(G_ETHCK, RCC_AHB6ENSETR, 7, 0), - K_MGATE(G_GPU, RCC_AHB6ENSETR, 5, 0), - K_GATE(G_MDMA, RCC_AHB6ENSETR, 0, 0), - K_GATE(G_ETHSTP, RCC_AHB6LPENSETR, 11, 0), -}; - -enum { - M_SDMMC12, - M_SDMMC3, - M_FMC, - M_QSPI, - M_RNG1, - M_RNG2, - M_USBPHY, - M_USBO, - M_STGEN, - M_SPDIF, - M_SPI1, - M_SPI23, - M_SPI45, - M_SPI6, - M_CEC, - M_I2C12, - M_I2C35, - M_I2C46, - M_LPTIM1, - M_LPTIM23, - M_LPTIM45, - M_USART1, - M_UART24, - M_UART35, - M_USART6, - M_UART78, - M_SAI1, - M_SAI2, - M_SAI3, - M_SAI4, - M_DSI, - M_FDCAN, - M_ADC12, - M_ETHCK, - M_CKPER, - M_LAST -}; - -static struct stm32_mmux ker_mux[M_LAST]; - -#define _K_MUX(_id, _offset, _shift, _width, _mux_flags, _mmux, _ops)\ - [_id] = {\ - &(struct mux_cfg) {\ - .reg_off = _offset,\ - .shift = _shift,\ - .width = _width,\ - .mux_flags = _mux_flags,\ - .table = NULL,\ - },\ - .mmux = _mmux,\ - .ops = _ops,\ - } - -#define K_MUX(_id, _offset, _shift, _width, _mux_flags)\ - _K_MUX(_id, _offset, _shift, _width, _mux_flags,\ - NULL, NULL) - -#define K_MMUX(_id, _offset, _shift, _width, _mux_flags)\ - _K_MUX(_id, _offset, _shift, _width, _mux_flags,\ - &ker_mux[_id], &clk_mmux_ops) - -static const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = { - /* Kernel multi mux */ - K_MMUX(M_SDMMC12, RCC_SDMMC12CKSELR, 0, 3, 0), - K_MMUX(M_SPI23, RCC_SPI2S23CKSELR, 0, 3, 0), - K_MMUX(M_SPI45, RCC_SPI2S45CKSELR, 0, 3, 0), - K_MMUX(M_I2C12, RCC_I2C12CKSELR, 0, 3, 0), - K_MMUX(M_I2C35, RCC_I2C35CKSELR, 0, 3, 0), - K_MMUX(M_LPTIM23, RCC_LPTIM23CKSELR, 0, 3, 0), - K_MMUX(M_LPTIM45, RCC_LPTIM45CKSELR, 0, 3, 0), - K_MMUX(M_UART24, RCC_UART24CKSELR, 0, 3, 0), - K_MMUX(M_UART35, RCC_UART35CKSELR, 0, 3, 0), - K_MMUX(M_UART78, RCC_UART78CKSELR, 0, 3, 0), - K_MMUX(M_SAI1, RCC_SAI1CKSELR, 0, 3, 0), - K_MMUX(M_ETHCK, RCC_ETHCKSELR, 0, 2, 0), - K_MMUX(M_I2C46, RCC_I2C46CKSELR, 0, 3, 0), - - /* Kernel simple mux */ - K_MUX(M_RNG2, RCC_RNG2CKSELR, 0, 2, 0), - K_MUX(M_SDMMC3, RCC_SDMMC3CKSELR, 0, 3, 0), - K_MUX(M_FMC, RCC_FMCCKSELR, 0, 2, 0), - K_MUX(M_QSPI, RCC_QSPICKSELR, 0, 2, 0), - K_MUX(M_USBPHY, RCC_USBCKSELR, 0, 2, 0), - K_MUX(M_USBO, RCC_USBCKSELR, 4, 1, 0), - K_MUX(M_SPDIF, RCC_SPDIFCKSELR, 0, 2, 0), - K_MUX(M_SPI1, RCC_SPI2S1CKSELR, 0, 3, 0), - K_MUX(M_CEC, RCC_CECCKSELR, 0, 2, 0), - K_MUX(M_LPTIM1, RCC_LPTIM1CKSELR, 0, 3, 0), - K_MUX(M_USART6, RCC_UART6CKSELR, 0, 3, 0), - K_MUX(M_FDCAN, RCC_FDCANCKSELR, 0, 2, 0), - K_MUX(M_SAI2, RCC_SAI2CKSELR, 0, 3, 0), - K_MUX(M_SAI3, RCC_SAI3CKSELR, 0, 3, 0), - K_MUX(M_SAI4, RCC_SAI4CKSELR, 0, 3, 0), - K_MUX(M_ADC12, RCC_ADCCKSELR, 0, 2, 0), - K_MUX(M_DSI, RCC_DSICKSELR, 0, 1, 0), - K_MUX(M_CKPER, RCC_CPERCKSELR, 0, 2, 0), - K_MUX(M_RNG1, RCC_RNG1CKSELR, 0, 2, 0), - K_MUX(M_STGEN, RCC_STGENCKSELR, 0, 2, 0), - K_MUX(M_USART1, RCC_UART1CKSELR, 0, 3, 0), - K_MUX(M_SPI6, RCC_SPI6CKSELR, 0, 3, 0), -}; - -static const struct clock_config stm32mp1_clock_cfg[] = { - /* External / Internal Oscillators */ - GATE_MP1(CK_HSE, "ck_hse", "clk-hse", 0, RCC_OCENSETR, 8, 0), - /* ck_csi is used by IO compensation and should be critical */ - GATE_MP1(CK_CSI, "ck_csi", "clk-csi", CLK_IS_CRITICAL, - RCC_OCENSETR, 4, 0), - COMPOSITE(CK_HSI, "ck_hsi", PARENT("clk-hsi"), 0, - _GATE_MP1(RCC_OCENSETR, 0, 0), - _NO_MUX, - _DIV(RCC_HSICFGR, 0, 2, CLK_DIVIDER_POWER_OF_TWO | - CLK_DIVIDER_READ_ONLY, NULL)), - GATE(CK_LSI, "ck_lsi", "clk-lsi", 0, RCC_RDLSICR, 0, 0), - GATE(CK_LSE, "ck_lse", "clk-lse", 0, RCC_BDCR, 0, 0), - - FIXED_FACTOR(CK_HSE_DIV2, "clk-hse-div2", "ck_hse", 0, 1, 2), - - /* PLLs */ - PLL(PLL1, "pll1", ref12_parents, 0, RCC_PLL1CR, RCC_RCK12SELR), - PLL(PLL2, "pll2", ref12_parents, 0, RCC_PLL2CR, RCC_RCK12SELR), - PLL(PLL3, "pll3", ref3_parents, 0, RCC_PLL3CR, RCC_RCK3SELR), - PLL(PLL4, "pll4", ref4_parents, 0, RCC_PLL4CR, RCC_RCK4SELR), - - /* ODF */ - COMPOSITE(PLL1_P, "pll1_p", PARENT("pll1"), 0, - _GATE(RCC_PLL1CR, 4, 0), - _NO_MUX, - _DIV(RCC_PLL1CFGR2, 0, 7, 0, NULL)), - - COMPOSITE(PLL2_P, "pll2_p", PARENT("pll2"), 0, - _GATE(RCC_PLL2CR, 4, 0), - _NO_MUX, - _DIV(RCC_PLL2CFGR2, 0, 7, 0, NULL)), - - COMPOSITE(PLL2_Q, "pll2_q", PARENT("pll2"), 0, - _GATE(RCC_PLL2CR, 5, 0), - _NO_MUX, - _DIV(RCC_PLL2CFGR2, 8, 7, 0, NULL)), - - COMPOSITE(PLL2_R, "pll2_r", PARENT("pll2"), CLK_IS_CRITICAL, - _GATE(RCC_PLL2CR, 6, 0), - _NO_MUX, - _DIV(RCC_PLL2CFGR2, 16, 7, 0, NULL)), - - COMPOSITE(PLL3_P, "pll3_p", PARENT("pll3"), 0, - _GATE(RCC_PLL3CR, 4, 0), - _NO_MUX, - _DIV(RCC_PLL3CFGR2, 0, 7, 0, NULL)), - - COMPOSITE(PLL3_Q, "pll3_q", PARENT("pll3"), 0, - _GATE(RCC_PLL3CR, 5, 0), - _NO_MUX, - _DIV(RCC_PLL3CFGR2, 8, 7, 0, NULL)), - - COMPOSITE(PLL3_R, "pll3_r", PARENT("pll3"), 0, - _GATE(RCC_PLL3CR, 6, 0), - _NO_MUX, - _DIV(RCC_PLL3CFGR2, 16, 7, 0, NULL)), - - COMPOSITE(PLL4_P, "pll4_p", PARENT("pll4"), 0, - _GATE(RCC_PLL4CR, 4, 0), - _NO_MUX, - _DIV(RCC_PLL4CFGR2, 0, 7, 0, NULL)), - - COMPOSITE(PLL4_Q, "pll4_q", PARENT("pll4"), 0, - _GATE(RCC_PLL4CR, 5, 0), - _NO_MUX, - _DIV(RCC_PLL4CFGR2, 8, 7, 0, NULL)), - - COMPOSITE(PLL4_R, "pll4_r", PARENT("pll4"), 0, - _GATE(RCC_PLL4CR, 6, 0), - _NO_MUX, - _DIV(RCC_PLL4CFGR2, 16, 7, 0, NULL)), - - /* MUX system clocks */ - MUX(CK_PER, "ck_per", per_src, CLK_OPS_PARENT_ENABLE, - RCC_CPERCKSELR, 0, 2, 0), - - MUX(CK_MPU, "ck_mpu", cpu_src, CLK_OPS_PARENT_ENABLE | - CLK_IS_CRITICAL, RCC_MPCKSELR, 0, 2, 0), - - COMPOSITE(CK_AXI, "ck_axi", axi_src, CLK_IS_CRITICAL | - CLK_OPS_PARENT_ENABLE, - _NO_GATE, - _MUX(RCC_ASSCKSELR, 0, 2, 0), - _DIV(RCC_AXIDIVR, 0, 3, 0, axi_div_table)), - - COMPOSITE(CK_MCU, "ck_mcu", mcu_src, CLK_IS_CRITICAL | - CLK_OPS_PARENT_ENABLE, - _NO_GATE, - _MUX(RCC_MSSCKSELR, 0, 2, 0), - _DIV(RCC_MCUDIVR, 0, 4, 0, mcu_div_table)), - - DIV_TABLE(NO_ID, "pclk1", "ck_mcu", CLK_IGNORE_UNUSED, RCC_APB1DIVR, 0, - 3, CLK_DIVIDER_READ_ONLY, apb_div_table), - - DIV_TABLE(NO_ID, "pclk2", "ck_mcu", CLK_IGNORE_UNUSED, RCC_APB2DIVR, 0, - 3, CLK_DIVIDER_READ_ONLY, apb_div_table), - - DIV_TABLE(NO_ID, "pclk3", "ck_mcu", CLK_IGNORE_UNUSED, RCC_APB3DIVR, 0, - 3, CLK_DIVIDER_READ_ONLY, apb_div_table), - - DIV_TABLE(NO_ID, "pclk4", "ck_axi", CLK_IGNORE_UNUSED, RCC_APB4DIVR, 0, - 3, CLK_DIVIDER_READ_ONLY, apb_div_table), - - DIV_TABLE(NO_ID, "pclk5", "ck_axi", CLK_IGNORE_UNUSED, RCC_APB5DIVR, 0, - 3, CLK_DIVIDER_READ_ONLY, apb_div_table), - - /* Kernel Timers */ - STM32_CKTIM("ck1_tim", "pclk1", 0, RCC_APB1DIVR, RCC_TIMG1PRER), - STM32_CKTIM("ck2_tim", "pclk2", 0, RCC_APB2DIVR, RCC_TIMG2PRER), - - STM32_TIM(TIM2_K, "tim2_k", "ck1_tim", RCC_APB1ENSETR, 0), - STM32_TIM(TIM3_K, "tim3_k", "ck1_tim", RCC_APB1ENSETR, 1), - STM32_TIM(TIM4_K, "tim4_k", "ck1_tim", RCC_APB1ENSETR, 2), - STM32_TIM(TIM5_K, "tim5_k", "ck1_tim", RCC_APB1ENSETR, 3), - STM32_TIM(TIM6_K, "tim6_k", "ck1_tim", RCC_APB1ENSETR, 4), - STM32_TIM(TIM7_K, "tim7_k", "ck1_tim", RCC_APB1ENSETR, 5), - STM32_TIM(TIM12_K, "tim12_k", "ck1_tim", RCC_APB1ENSETR, 6), - STM32_TIM(TIM13_K, "tim13_k", "ck1_tim", RCC_APB1ENSETR, 7), - STM32_TIM(TIM14_K, "tim14_k", "ck1_tim", RCC_APB1ENSETR, 8), - STM32_TIM(TIM1_K, "tim1_k", "ck2_tim", RCC_APB2ENSETR, 0), - STM32_TIM(TIM8_K, "tim8_k", "ck2_tim", RCC_APB2ENSETR, 1), - STM32_TIM(TIM15_K, "tim15_k", "ck2_tim", RCC_APB2ENSETR, 2), - STM32_TIM(TIM16_K, "tim16_k", "ck2_tim", RCC_APB2ENSETR, 3), - STM32_TIM(TIM17_K, "tim17_k", "ck2_tim", RCC_APB2ENSETR, 4), - - /* Peripheral clocks */ - PCLK(TIM2, "tim2", "pclk1", CLK_IGNORE_UNUSED, G_TIM2), - PCLK(TIM3, "tim3", "pclk1", CLK_IGNORE_UNUSED, G_TIM3), - PCLK(TIM4, "tim4", "pclk1", CLK_IGNORE_UNUSED, G_TIM4), - PCLK(TIM5, "tim5", "pclk1", CLK_IGNORE_UNUSED, G_TIM5), - PCLK(TIM6, "tim6", "pclk1", CLK_IGNORE_UNUSED, G_TIM6), - PCLK(TIM7, "tim7", "pclk1", CLK_IGNORE_UNUSED, G_TIM7), - PCLK(TIM12, "tim12", "pclk1", CLK_IGNORE_UNUSED, G_TIM12), - PCLK(TIM13, "tim13", "pclk1", CLK_IGNORE_UNUSED, G_TIM13), - PCLK(TIM14, "tim14", "pclk1", CLK_IGNORE_UNUSED, G_TIM14), - PCLK(LPTIM1, "lptim1", "pclk1", 0, G_LPTIM1), - PCLK(SPI2, "spi2", "pclk1", 0, G_SPI2), - PCLK(SPI3, "spi3", "pclk1", 0, G_SPI3), - PCLK(USART2, "usart2", "pclk1", 0, G_USART2), - PCLK(USART3, "usart3", "pclk1", 0, G_USART3), - PCLK(UART4, "uart4", "pclk1", 0, G_UART4), - PCLK(UART5, "uart5", "pclk1", 0, G_UART5), - PCLK(UART7, "uart7", "pclk1", 0, G_UART7), - PCLK(UART8, "uart8", "pclk1", 0, G_UART8), - PCLK(I2C1, "i2c1", "pclk1", 0, G_I2C1), - PCLK(I2C2, "i2c2", "pclk1", 0, G_I2C2), - PCLK(I2C3, "i2c3", "pclk1", 0, G_I2C3), - PCLK(I2C5, "i2c5", "pclk1", 0, G_I2C5), - PCLK(SPDIF, "spdif", "pclk1", 0, G_SPDIF), - PCLK(CEC, "cec", "pclk1", 0, G_CEC), - PCLK(DAC12, "dac12", "pclk1", 0, G_DAC12), - PCLK(MDIO, "mdio", "pclk1", 0, G_MDIO), - PCLK(TIM1, "tim1", "pclk2", CLK_IGNORE_UNUSED, G_TIM1), - PCLK(TIM8, "tim8", "pclk2", CLK_IGNORE_UNUSED, G_TIM8), - PCLK(TIM15, "tim15", "pclk2", CLK_IGNORE_UNUSED, G_TIM15), - PCLK(TIM16, "tim16", "pclk2", CLK_IGNORE_UNUSED, G_TIM16), - PCLK(TIM17, "tim17", "pclk2", CLK_IGNORE_UNUSED, G_TIM17), - PCLK(SPI1, "spi1", "pclk2", 0, G_SPI1), - PCLK(SPI4, "spi4", "pclk2", 0, G_SPI4), - PCLK(SPI5, "spi5", "pclk2", 0, G_SPI5), - PCLK(USART6, "usart6", "pclk2", 0, G_USART6), - PCLK(SAI1, "sai1", "pclk2", 0, G_SAI1), - PCLK(SAI2, "sai2", "pclk2", 0, G_SAI2), - PCLK(SAI3, "sai3", "pclk2", 0, G_SAI3), - PCLK(DFSDM, "dfsdm", "pclk2", 0, G_DFSDM), - PCLK(FDCAN, "fdcan", "pclk2", 0, G_FDCAN), - PCLK(LPTIM2, "lptim2", "pclk3", 0, G_LPTIM2), - PCLK(LPTIM3, "lptim3", "pclk3", 0, G_LPTIM3), - PCLK(LPTIM4, "lptim4", "pclk3", 0, G_LPTIM4), - PCLK(LPTIM5, "lptim5", "pclk3", 0, G_LPTIM5), - PCLK(SAI4, "sai4", "pclk3", 0, G_SAI4), - PCLK(SYSCFG, "syscfg", "pclk3", 0, G_SYSCFG), - PCLK(VREF, "vref", "pclk3", 13, G_VREF), - PCLK(TMPSENS, "tmpsens", "pclk3", 0, G_TMPSENS), - PCLK(PMBCTRL, "pmbctrl", "pclk3", 0, G_PMBCTRL), - PCLK(HDP, "hdp", "pclk3", 0, G_HDP), - PCLK(LTDC, "ltdc", "pclk4", 0, G_LTDC), - PCLK(DSI, "dsi", "pclk4", 0, G_DSI), - PCLK(IWDG2, "iwdg2", "pclk4", 0, G_IWDG2), - PCLK(USBPHY, "usbphy", "pclk4", 0, G_USBPHY), - PCLK(STGENRO, "stgenro", "pclk4", 0, G_STGENRO), - PCLK(SPI6, "spi6", "pclk5", 0, G_SPI6), - PCLK(I2C4, "i2c4", "pclk5", 0, G_I2C4), - PCLK(I2C6, "i2c6", "pclk5", 0, G_I2C6), - PCLK(USART1, "usart1", "pclk5", 0, G_USART1), - PCLK(RTCAPB, "rtcapb", "pclk5", CLK_IGNORE_UNUSED | - CLK_IS_CRITICAL, G_RTCAPB), - PCLK(TZC1, "tzc1", "ck_axi", CLK_IGNORE_UNUSED, G_TZC1), - PCLK(TZC2, "tzc2", "ck_axi", CLK_IGNORE_UNUSED, G_TZC2), - PCLK(TZPC, "tzpc", "pclk5", CLK_IGNORE_UNUSED, G_TZPC), - PCLK(IWDG1, "iwdg1", "pclk5", 0, G_IWDG1), - PCLK(BSEC, "bsec", "pclk5", CLK_IGNORE_UNUSED, G_BSEC), - PCLK(STGEN, "stgen", "pclk5", CLK_IGNORE_UNUSED, G_STGEN), - PCLK(DMA1, "dma1", "ck_mcu", 0, G_DMA1), - PCLK(DMA2, "dma2", "ck_mcu", 0, G_DMA2), - PCLK(DMAMUX, "dmamux", "ck_mcu", 0, G_DMAMUX), - PCLK(ADC12, "adc12", "ck_mcu", 0, G_ADC12), - PCLK(USBO, "usbo", "ck_mcu", 0, G_USBO), - PCLK(SDMMC3, "sdmmc3", "ck_mcu", 0, G_SDMMC3), - PCLK(DCMI, "dcmi", "ck_mcu", 0, G_DCMI), - PCLK(CRYP2, "cryp2", "ck_mcu", 0, G_CRYP2), - PCLK(HASH2, "hash2", "ck_mcu", 0, G_HASH2), - PCLK(RNG2, "rng2", "ck_mcu", 0, G_RNG2), - PCLK(CRC2, "crc2", "ck_mcu", 0, G_CRC2), - PCLK(HSEM, "hsem", "ck_mcu", 0, G_HSEM), - PCLK(IPCC, "ipcc", "ck_mcu", 0, G_IPCC), - PCLK(GPIOA, "gpioa", "ck_mcu", 0, G_GPIOA), - PCLK(GPIOB, "gpiob", "ck_mcu", 0, G_GPIOB), - PCLK(GPIOC, "gpioc", "ck_mcu", 0, G_GPIOC), - PCLK(GPIOD, "gpiod", "ck_mcu", 0, G_GPIOD), - PCLK(GPIOE, "gpioe", "ck_mcu", 0, G_GPIOE), - PCLK(GPIOF, "gpiof", "ck_mcu", 0, G_GPIOF), - PCLK(GPIOG, "gpiog", "ck_mcu", 0, G_GPIOG), - PCLK(GPIOH, "gpioh", "ck_mcu", 0, G_GPIOH), - PCLK(GPIOI, "gpioi", "ck_mcu", 0, G_GPIOI), - PCLK(GPIOJ, "gpioj", "ck_mcu", 0, G_GPIOJ), - PCLK(GPIOK, "gpiok", "ck_mcu", 0, G_GPIOK), - PCLK(GPIOZ, "gpioz", "ck_axi", CLK_IGNORE_UNUSED, G_GPIOZ), - PCLK(CRYP1, "cryp1", "ck_axi", CLK_IGNORE_UNUSED, G_CRYP1), - PCLK(HASH1, "hash1", "ck_axi", CLK_IGNORE_UNUSED, G_HASH1), - PCLK(RNG1, "rng1", "ck_axi", 0, G_RNG1), - PCLK(BKPSRAM, "bkpsram", "ck_axi", CLK_IGNORE_UNUSED, G_BKPSRAM), - PCLK(MDMA, "mdma", "ck_axi", 0, G_MDMA), - PCLK(GPU, "gpu", "ck_axi", 0, G_GPU), - PCLK(ETHTX, "ethtx", "ck_axi", 0, G_ETHTX), - PCLK_PDATA(ETHRX, "ethrx", ethrx_src, 0, G_ETHRX), - PCLK(ETHMAC, "ethmac", "ck_axi", 0, G_ETHMAC), - PCLK(FMC, "fmc", "ck_axi", CLK_IGNORE_UNUSED, G_FMC), - PCLK(QSPI, "qspi", "ck_axi", CLK_IGNORE_UNUSED, G_QSPI), - PCLK(SDMMC1, "sdmmc1", "ck_axi", 0, G_SDMMC1), - PCLK(SDMMC2, "sdmmc2", "ck_axi", 0, G_SDMMC2), - PCLK(CRC1, "crc1", "ck_axi", 0, G_CRC1), - PCLK(USBH, "usbh", "ck_axi", 0, G_USBH), - PCLK(ETHSTP, "ethstp", "ck_axi", 0, G_ETHSTP), - PCLK(DDRPERFM, "ddrperfm", "pclk4", 0, G_DDRPERFM), - - /* Kernel clocks */ - KCLK(SDMMC1_K, "sdmmc1_k", sdmmc12_src, 0, G_SDMMC1, M_SDMMC12), - KCLK(SDMMC2_K, "sdmmc2_k", sdmmc12_src, 0, G_SDMMC2, M_SDMMC12), - KCLK(SDMMC3_K, "sdmmc3_k", sdmmc3_src, 0, G_SDMMC3, M_SDMMC3), - KCLK(FMC_K, "fmc_k", fmc_src, 0, G_FMC, M_FMC), - KCLK(QSPI_K, "qspi_k", qspi_src, 0, G_QSPI, M_QSPI), - KCLK(RNG1_K, "rng1_k", rng_src, 0, G_RNG1, M_RNG1), - KCLK(RNG2_K, "rng2_k", rng_src, 0, G_RNG2, M_RNG2), - KCLK(USBPHY_K, "usbphy_k", usbphy_src, 0, G_USBPHY, M_USBPHY), - KCLK(STGEN_K, "stgen_k", stgen_src, CLK_IS_CRITICAL, G_STGEN, M_STGEN), - KCLK(SPDIF_K, "spdif_k", spdif_src, 0, G_SPDIF, M_SPDIF), - KCLK(SPI1_K, "spi1_k", spi123_src, 0, G_SPI1, M_SPI1), - KCLK(SPI2_K, "spi2_k", spi123_src, 0, G_SPI2, M_SPI23), - KCLK(SPI3_K, "spi3_k", spi123_src, 0, G_SPI3, M_SPI23), - KCLK(SPI4_K, "spi4_k", spi45_src, 0, G_SPI4, M_SPI45), - KCLK(SPI5_K, "spi5_k", spi45_src, 0, G_SPI5, M_SPI45), - KCLK(SPI6_K, "spi6_k", spi6_src, 0, G_SPI6, M_SPI6), - KCLK(CEC_K, "cec_k", cec_src, 0, G_CEC, M_CEC), - KCLK(I2C1_K, "i2c1_k", i2c12_src, 0, G_I2C1, M_I2C12), - KCLK(I2C2_K, "i2c2_k", i2c12_src, 0, G_I2C2, M_I2C12), - KCLK(I2C3_K, "i2c3_k", i2c35_src, 0, G_I2C3, M_I2C35), - KCLK(I2C5_K, "i2c5_k", i2c35_src, 0, G_I2C5, M_I2C35), - KCLK(I2C4_K, "i2c4_k", i2c46_src, 0, G_I2C4, M_I2C46), - KCLK(I2C6_K, "i2c6_k", i2c46_src, 0, G_I2C6, M_I2C46), - KCLK(LPTIM1_K, "lptim1_k", lptim1_src, 0, G_LPTIM1, M_LPTIM1), - KCLK(LPTIM2_K, "lptim2_k", lptim23_src, 0, G_LPTIM2, M_LPTIM23), - KCLK(LPTIM3_K, "lptim3_k", lptim23_src, 0, G_LPTIM3, M_LPTIM23), - KCLK(LPTIM4_K, "lptim4_k", lptim45_src, 0, G_LPTIM4, M_LPTIM45), - KCLK(LPTIM5_K, "lptim5_k", lptim45_src, 0, G_LPTIM5, M_LPTIM45), - KCLK(USART1_K, "usart1_k", usart1_src, 0, G_USART1, M_USART1), - KCLK(USART2_K, "usart2_k", usart234578_src, 0, G_USART2, M_UART24), - KCLK(USART3_K, "usart3_k", usart234578_src, 0, G_USART3, M_UART35), - KCLK(UART4_K, "uart4_k", usart234578_src, 0, G_UART4, M_UART24), - KCLK(UART5_K, "uart5_k", usart234578_src, 0, G_UART5, M_UART35), - KCLK(USART6_K, "uart6_k", usart6_src, 0, G_USART6, M_USART6), - KCLK(UART7_K, "uart7_k", usart234578_src, 0, G_UART7, M_UART78), - KCLK(UART8_K, "uart8_k", usart234578_src, 0, G_UART8, M_UART78), - KCLK(FDCAN_K, "fdcan_k", fdcan_src, 0, G_FDCAN, M_FDCAN), - KCLK(SAI1_K, "sai1_k", sai_src, 0, G_SAI1, M_SAI1), - KCLK(SAI2_K, "sai2_k", sai2_src, 0, G_SAI2, M_SAI2), - KCLK(SAI3_K, "sai3_k", sai_src, 0, G_SAI3, M_SAI3), - KCLK(SAI4_K, "sai4_k", sai_src, 0, G_SAI4, M_SAI4), - KCLK(ADC12_K, "adc12_k", adc12_src, 0, G_ADC12, M_ADC12), - KCLK(DSI_K, "dsi_k", dsi_src, 0, G_DSI, M_DSI), - KCLK(ADFSDM_K, "adfsdm_k", sai_src, 0, G_ADFSDM, M_SAI1), - KCLK(USBO_K, "usbo_k", usbo_src, 0, G_USBO, M_USBO), - - /* Particulary Kernel Clocks (no mux or no gate) */ - MGATE_MP1(DFSDM_K, "dfsdm_k", "ck_mcu", 0, G_DFSDM), - MGATE_MP1(DSI_PX, "dsi_px", "pll4_q", CLK_SET_RATE_PARENT, G_DSI), - MGATE_MP1(LTDC_PX, "ltdc_px", "pll4_q", CLK_SET_RATE_PARENT, G_LTDC), - MGATE_MP1(GPU_K, "gpu_k", "pll2_q", 0, G_GPU), - MGATE_MP1(DAC12_K, "dac12_k", "ck_lsi", 0, G_DAC12), - - COMPOSITE(NO_ID, "ck_ker_eth", eth_src, CLK_OPS_PARENT_ENABLE | - CLK_SET_RATE_NO_REPARENT, - _NO_GATE, - _MMUX(M_ETHCK), - _NO_DIV), - - MGATE_MP1(ETHCK_K, "ethck_k", "ck_ker_eth", 0, G_ETHCK), - - DIV(ETHPTP_K, "ethptp_k", "ck_ker_eth", CLK_OPS_PARENT_ENABLE | - CLK_SET_RATE_NO_REPARENT, RCC_ETHCKSELR, 4, 4, 0), - - /* RTC clock */ - COMPOSITE(RTC, "ck_rtc", rtc_src, CLK_OPS_PARENT_ENABLE, - _GATE(RCC_BDCR, 20, 0), - _MUX(RCC_BDCR, 16, 2, 0), - _DIV_RTC(RCC_RTCDIVR, 0, 6, 0, NULL)), - - /* MCO clocks */ - COMPOSITE(CK_MCO1, "ck_mco1", mco1_src, CLK_OPS_PARENT_ENABLE | - CLK_SET_RATE_NO_REPARENT, - _GATE(RCC_MCO1CFGR, 12, 0), - _MUX(RCC_MCO1CFGR, 0, 3, 0), - _DIV(RCC_MCO1CFGR, 4, 4, 0, NULL)), - - COMPOSITE(CK_MCO2, "ck_mco2", mco2_src, CLK_OPS_PARENT_ENABLE | - CLK_SET_RATE_NO_REPARENT, - _GATE(RCC_MCO2CFGR, 12, 0), - _MUX(RCC_MCO2CFGR, 0, 3, 0), - _DIV(RCC_MCO2CFGR, 4, 4, 0, NULL)), - - /* Debug clocks */ - GATE(CK_DBG, "ck_sys_dbg", "ck_axi", CLK_IGNORE_UNUSED, - RCC_DBGCFGR, 8, 0), - - COMPOSITE(CK_TRACE, "ck_trace", ck_trace_src, CLK_OPS_PARENT_ENABLE, - _GATE(RCC_DBGCFGR, 9, 0), - _NO_MUX, - _DIV(RCC_DBGCFGR, 0, 3, 0, ck_trace_div_table)), -}; - -static const u32 stm32mp1_clock_secured[] = { - CK_HSE, - CK_HSI, - CK_CSI, - CK_LSI, - CK_LSE, - PLL1, - PLL2, - PLL1_P, - PLL2_P, - PLL2_Q, - PLL2_R, - CK_MPU, - CK_AXI, - SPI6, - I2C4, - I2C6, - USART1, - RTCAPB, - TZC1, - TZC2, - TZPC, - IWDG1, - BSEC, - STGEN, - GPIOZ, - CRYP1, - HASH1, - RNG1, - BKPSRAM, - RNG1_K, - STGEN_K, - SPI6_K, - I2C4_K, - I2C6_K, - USART1_K, - RTC, -}; - -static bool stm32_check_security(const struct clock_config *cfg) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(stm32mp1_clock_secured); i++) - if (cfg->id == stm32mp1_clock_secured[i]) - return true; - return false; -} - -struct stm32_rcc_match_data { - const struct clock_config *cfg; - unsigned int num; - unsigned int maxbinding; - u32 clear_offset; - bool (*check_security)(const struct clock_config *cfg); -}; - -static struct stm32_rcc_match_data stm32mp1_data = { - .cfg = stm32mp1_clock_cfg, - .num = ARRAY_SIZE(stm32mp1_clock_cfg), - .maxbinding = STM32MP1_LAST_CLK, - .clear_offset = RCC_CLR, -}; - -static struct stm32_rcc_match_data stm32mp1_data_secure = { - .cfg = stm32mp1_clock_cfg, - .num = ARRAY_SIZE(stm32mp1_clock_cfg), - .maxbinding = STM32MP1_LAST_CLK, - .clear_offset = RCC_CLR, - .check_security = &stm32_check_security -}; - -static const struct of_device_id stm32mp1_match_data[] = { - { - .compatible = "st,stm32mp1-rcc", - .data = &stm32mp1_data, - }, - { - .compatible = "st,stm32mp1-rcc-secure", - .data = &stm32mp1_data_secure, - }, - { } -}; -MODULE_DEVICE_TABLE(of, stm32mp1_match_data); - -static int stm32_register_hw_clk(struct device *dev, - struct clk_hw_onecell_data *clk_data, - void __iomem *base, spinlock_t *lock, - const struct clock_config *cfg) -{ - struct clk_hw **hws; - struct clk_hw *hw = ERR_PTR(-ENOENT); - - hws = clk_data->hws; - - if (cfg->func) - hw = (*cfg->func)(dev, clk_data, base, lock, cfg); - - if (IS_ERR(hw)) { - pr_err("Unable to register %s\n", cfg->name); - return PTR_ERR(hw); - } - - if (cfg->id != NO_ID) - hws[cfg->id] = hw; - - return 0; -} - -#define STM32_RESET_ID_MASK GENMASK(15, 0) - -struct stm32_reset_data { - /* reset lock */ - spinlock_t lock; - struct reset_controller_dev rcdev; - void __iomem *membase; - u32 clear_offset; -}; - -static inline struct stm32_reset_data * -to_stm32_reset_data(struct reset_controller_dev *rcdev) -{ - return container_of(rcdev, struct stm32_reset_data, rcdev); -} - -static int stm32_reset_update(struct reset_controller_dev *rcdev, - unsigned long id, bool assert) -{ - struct stm32_reset_data *data = to_stm32_reset_data(rcdev); - int reg_width = sizeof(u32); - int bank = id / (reg_width * BITS_PER_BYTE); - int offset = id % (reg_width * BITS_PER_BYTE); - - if (data->clear_offset) { - void __iomem *addr; - - addr = data->membase + (bank * reg_width); - if (!assert) - addr += data->clear_offset; - - writel(BIT(offset), addr); - - } else { - unsigned long flags; - u32 reg; - - spin_lock_irqsave(&data->lock, flags); - - reg = readl(data->membase + (bank * reg_width)); - - if (assert) - reg |= BIT(offset); - else - reg &= ~BIT(offset); - - writel(reg, data->membase + (bank * reg_width)); - - spin_unlock_irqrestore(&data->lock, flags); - } - - return 0; -} - -static int stm32_reset_assert(struct reset_controller_dev *rcdev, - unsigned long id) -{ - return stm32_reset_update(rcdev, id, true); -} - -static int stm32_reset_deassert(struct reset_controller_dev *rcdev, - unsigned long id) -{ - return stm32_reset_update(rcdev, id, false); -} - -static int stm32_reset_status(struct reset_controller_dev *rcdev, - unsigned long id) -{ - struct stm32_reset_data *data = to_stm32_reset_data(rcdev); - int reg_width = sizeof(u32); - int bank = id / (reg_width * BITS_PER_BYTE); - int offset = id % (reg_width * BITS_PER_BYTE); - u32 reg; - - reg = readl(data->membase + (bank * reg_width)); - - return !!(reg & BIT(offset)); -} - -static const struct reset_control_ops stm32_reset_ops = { - .assert = stm32_reset_assert, - .deassert = stm32_reset_deassert, - .status = stm32_reset_status, -}; - -static int stm32_rcc_reset_init(struct device *dev, void __iomem *base, - const struct of_device_id *match) -{ - const struct stm32_rcc_match_data *data = match->data; - struct stm32_reset_data *reset_data = NULL; - - reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL); - if (!reset_data) - return -ENOMEM; - - spin_lock_init(&reset_data->lock); - reset_data->membase = base; - reset_data->rcdev.owner = THIS_MODULE; - reset_data->rcdev.ops = &stm32_reset_ops; - reset_data->rcdev.of_node = dev_of_node(dev); - reset_data->rcdev.nr_resets = STM32_RESET_ID_MASK; - reset_data->clear_offset = data->clear_offset; - - return reset_controller_register(&reset_data->rcdev); -} - -static int stm32_rcc_clock_init(struct device *dev, void __iomem *base, - const struct of_device_id *match) -{ - const struct stm32_rcc_match_data *data = match->data; - struct clk_hw_onecell_data *clk_data; - struct clk_hw **hws; - int err, n, max_binding; - - max_binding = data->maxbinding; - - clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, max_binding), - GFP_KERNEL); - if (!clk_data) - return -ENOMEM; - - clk_data->num = max_binding; - - hws = clk_data->hws; - - for (n = 0; n < max_binding; n++) - hws[n] = ERR_PTR(-ENOENT); - - for (n = 0; n < data->num; n++) { - if (data->check_security && data->check_security(&data->cfg[n])) - continue; - - err = stm32_register_hw_clk(dev, clk_data, base, &rlock, - &data->cfg[n]); - if (err) { - dev_err(dev, "Can't register clk %s: %d\n", - data->cfg[n].name, err); - - return err; - } - } - - return of_clk_add_hw_provider(dev_of_node(dev), of_clk_hw_onecell_get, clk_data); -} - -static int stm32_rcc_init(struct device *dev, void __iomem *base, - const struct of_device_id *match_data) -{ - const struct of_device_id *match; - int err; - - match = of_match_node(match_data, dev_of_node(dev)); - if (!match) { - dev_err(dev, "match data not found\n"); - return -ENODEV; - } - - /* RCC Reset Configuration */ - err = stm32_rcc_reset_init(dev, base, match); - if (err) { - pr_err("stm32mp1 reset failed to initialize\n"); - return err; - } - - /* RCC Clock Configuration */ - err = stm32_rcc_clock_init(dev, base, match); - if (err) { - pr_err("stm32mp1 clock failed to initialize\n"); - return err; - } - - return 0; -} - -static int stm32mp1_rcc_init(struct device *dev) -{ - void __iomem *base; - int ret; - - base = of_iomap(dev_of_node(dev), 0); - if (!base) { - pr_err("%pOFn: unable to map resource", dev_of_node(dev)); - ret = -ENOMEM; - goto out; - } - - ret = stm32_rcc_init(dev, base, stm32mp1_match_data); - -out: - if (ret) { - if (base) - iounmap(base); - - of_node_put(dev_of_node(dev)); - } - - return ret; -} - -static int get_clock_deps(struct device *dev) -{ - static const char * const clock_deps_name[] = { - "hsi", "hse", "csi", "lsi", "lse", - }; - size_t deps_size = sizeof(struct clk *) * ARRAY_SIZE(clock_deps_name); - struct clk **clk_deps; - int i; - - clk_deps = devm_kzalloc(dev, deps_size, GFP_KERNEL); - if (!clk_deps) - return -ENOMEM; - - for (i = 0; i < ARRAY_SIZE(clock_deps_name); i++) { - struct clk *clk = of_clk_get_by_name(dev_of_node(dev), - clock_deps_name[i]); - - if (IS_ERR(clk)) { - if (PTR_ERR(clk) != -EINVAL && PTR_ERR(clk) != -ENOENT) - return PTR_ERR(clk); - } else { - /* Device gets a reference count on the clock */ - clk_deps[i] = devm_clk_get(dev, __clk_get_name(clk)); - clk_put(clk); - } - } - - return 0; -} - -static int stm32mp1_rcc_clocks_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - int ret = get_clock_deps(dev); - - if (!ret) - ret = stm32mp1_rcc_init(dev); - - return ret; -} - -static void stm32mp1_rcc_clocks_remove(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *child, *np = dev_of_node(dev); - - for_each_available_child_of_node(np, child) - of_clk_del_provider(child); -} - -static struct platform_driver stm32mp1_rcc_clocks_driver = { - .driver = { - .name = "stm32mp1_rcc", - .of_match_table = stm32mp1_match_data, - }, - .probe = stm32mp1_rcc_clocks_probe, - .remove_new = stm32mp1_rcc_clocks_remove, -}; - -static int __init stm32mp1_clocks_init(void) -{ - return platform_driver_register(&stm32mp1_rcc_clocks_driver); -} -core_initcall(stm32mp1_clocks_init); diff --git a/drivers/clk/clk-versaclock3.c b/drivers/clk/clk-versaclock3.c index 00930d7bca778e..76d7ea1964c3a5 100644 --- a/drivers/clk/clk-versaclock3.c +++ b/drivers/clk/clk-versaclock3.c @@ -37,7 +37,7 @@ #define VC3_PLL1_M_DIV(n) ((n) & GENMASK(5, 0)) #define VC3_PLL1_VCO_N_DIVIDER 0x9 -#define VC3_PLL1_LOOP_FILTER_N_DIV_MSB 0x0a +#define VC3_PLL1_LOOP_FILTER_N_DIV_MSB 0xa #define VC3_OUT_DIV1_DIV2_CTRL 0xf @@ -148,16 +148,16 @@ struct vc3_pfd_data { }; struct vc3_pll_data { + unsigned long vco_min; + unsigned long vco_max; u8 num; u8 int_div_msb_offs; u8 int_div_lsb_offs; - unsigned long vco_min; - unsigned long vco_max; }; struct vc3_div_data { - u8 offs; const struct clk_div_table *table; + u8 offs; u8 shift; u8 width; u8 flags; @@ -210,7 +210,7 @@ static const struct clk_div_table div3_divs[] = { static struct clk_hw *clk_out[6]; -static unsigned char vc3_pfd_mux_get_parent(struct clk_hw *hw) +static u8 vc3_pfd_mux_get_parent(struct clk_hw *hw) { struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw); const struct vc3_clk_data *pfd_mux = vc3->data; @@ -226,9 +226,8 @@ static int vc3_pfd_mux_set_parent(struct clk_hw *hw, u8 index) struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw); const struct vc3_clk_data *pfd_mux = vc3->data; - regmap_update_bits(vc3->regmap, pfd_mux->offs, pfd_mux->bitmsk, - index ? pfd_mux->bitmsk : 0); - return 0; + return regmap_update_bits(vc3->regmap, pfd_mux->offs, pfd_mux->bitmsk, + index ? pfd_mux->bitmsk : 0); } static const struct clk_ops vc3_pfd_mux_ops = { @@ -440,7 +439,7 @@ static const struct clk_ops vc3_pll_ops = { .set_rate = vc3_pll_set_rate, }; -static unsigned char vc3_div_mux_get_parent(struct clk_hw *hw) +static u8 vc3_div_mux_get_parent(struct clk_hw *hw) { struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw); const struct vc3_clk_data *div_mux = vc3->data; @@ -456,10 +455,8 @@ static int vc3_div_mux_set_parent(struct clk_hw *hw, u8 index) struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw); const struct vc3_clk_data *div_mux = vc3->data; - regmap_update_bits(vc3->regmap, div_mux->offs, div_mux->bitmsk, - index ? div_mux->bitmsk : 0); - - return 0; + return regmap_update_bits(vc3->regmap, div_mux->offs, div_mux->bitmsk, + index ? div_mux->bitmsk : 0); } static const struct clk_ops vc3_div_mux_ops = { @@ -477,7 +474,7 @@ static unsigned int vc3_get_div(const struct clk_div_table *table, if (clkt->val == val) return clkt->div; - return 0; + return 1; } static unsigned long vc3_div_recalc_rate(struct clk_hw *hw, @@ -524,10 +521,9 @@ static int vc3_div_set_rate(struct clk_hw *hw, unsigned long rate, value = divider_get_val(rate, parent_rate, div_data->table, div_data->width, div_data->flags); - regmap_update_bits(vc3->regmap, div_data->offs, - VC3_DIV_MASK(div_data->width) << div_data->shift, - value << div_data->shift); - return 0; + return regmap_update_bits(vc3->regmap, div_data->offs, + VC3_DIV_MASK(div_data->width) << div_data->shift, + value << div_data->shift); } static const struct clk_ops vc3_div_ops = { @@ -539,11 +535,9 @@ static const struct clk_ops vc3_div_ops = { static int vc3_clk_mux_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { - int ret; int frc; - ret = clk_mux_determine_rate_flags(hw, req, CLK_SET_RATE_PARENT); - if (ret) { + if (clk_mux_determine_rate_flags(hw, req, CLK_SET_RATE_PARENT)) { /* The below check is equivalent to (best_parent_rate/rate) */ if (req->best_parent_rate >= req->rate) { frc = DIV_ROUND_CLOSEST_ULL(req->best_parent_rate, @@ -552,13 +546,12 @@ static int vc3_clk_mux_determine_rate(struct clk_hw *hw, return clk_mux_determine_rate_flags(hw, req, CLK_SET_RATE_PARENT); } - ret = 0; } - return ret; + return 0; } -static unsigned char vc3_clk_mux_get_parent(struct clk_hw *hw) +static u8 vc3_clk_mux_get_parent(struct clk_hw *hw) { struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw); const struct vc3_clk_data *clk_mux = vc3->data; @@ -574,9 +567,8 @@ static int vc3_clk_mux_set_parent(struct clk_hw *hw, u8 index) struct vc3_hw_data *vc3 = container_of(hw, struct vc3_hw_data, hw); const struct vc3_clk_data *clk_mux = vc3->data; - regmap_update_bits(vc3->regmap, clk_mux->offs, - clk_mux->bitmsk, index ? clk_mux->bitmsk : 0); - return 0; + return regmap_update_bits(vc3->regmap, clk_mux->offs, clk_mux->bitmsk, + index ? clk_mux->bitmsk : 0); } static const struct clk_ops vc3_clk_mux_ops = { @@ -605,7 +597,7 @@ static struct vc3_hw_data clk_pfd_mux[] = { .offs = VC3_PLL_OP_CTRL, .bitmsk = BIT(VC3_PLL_OP_CTRL_PLL2_REFIN_SEL) }, - .hw.init = &(struct clk_init_data){ + .hw.init = &(struct clk_init_data) { .name = "pfd2_mux", .ops = &vc3_pfd_mux_ops, .parent_data = pfd_mux_parent_data, @@ -618,7 +610,7 @@ static struct vc3_hw_data clk_pfd_mux[] = { .offs = VC3_GENERAL_CTR, .bitmsk = BIT(VC3_GENERAL_CTR_PLL3_REFIN_SEL) }, - .hw.init = &(struct clk_init_data){ + .hw.init = &(struct clk_init_data) { .name = "pfd3_mux", .ops = &vc3_pfd_mux_ops, .parent_data = pfd_mux_parent_data, @@ -636,7 +628,7 @@ static struct vc3_hw_data clk_pfd[] = { .mdiv1_bitmsk = VC3_PLL1_M_DIV1, .mdiv2_bitmsk = VC3_PLL1_M_DIV2 }, - .hw.init = &(struct clk_init_data){ + .hw.init = &(struct clk_init_data) { .name = "pfd1", .ops = &vc3_pfd_ops, .parent_data = &(const struct clk_parent_data) { @@ -653,7 +645,7 @@ static struct vc3_hw_data clk_pfd[] = { .mdiv1_bitmsk = VC3_PLL2_M_DIV1, .mdiv2_bitmsk = VC3_PLL2_M_DIV2 }, - .hw.init = &(struct clk_init_data){ + .hw.init = &(struct clk_init_data) { .name = "pfd2", .ops = &vc3_pfd_ops, .parent_hws = (const struct clk_hw *[]) { @@ -670,7 +662,7 @@ static struct vc3_hw_data clk_pfd[] = { .mdiv1_bitmsk = VC3_PLL3_M_DIV1, .mdiv2_bitmsk = VC3_PLL3_M_DIV2 }, - .hw.init = &(struct clk_init_data){ + .hw.init = &(struct clk_init_data) { .name = "pfd3", .ops = &vc3_pfd_ops, .parent_hws = (const struct clk_hw *[]) { @@ -691,7 +683,7 @@ static struct vc3_hw_data clk_pll[] = { .vco_min = VC3_PLL1_VCO_MIN, .vco_max = VC3_PLL1_VCO_MAX }, - .hw.init = &(struct clk_init_data){ + .hw.init = &(struct clk_init_data) { .name = "pll1", .ops = &vc3_pll_ops, .parent_hws = (const struct clk_hw *[]) { @@ -709,7 +701,7 @@ static struct vc3_hw_data clk_pll[] = { .vco_min = VC3_PLL2_VCO_MIN, .vco_max = VC3_PLL2_VCO_MAX }, - .hw.init = &(struct clk_init_data){ + .hw.init = &(struct clk_init_data) { .name = "pll2", .ops = &vc3_pll_ops, .parent_hws = (const struct clk_hw *[]) { @@ -727,7 +719,7 @@ static struct vc3_hw_data clk_pll[] = { .vco_min = VC3_PLL3_VCO_MIN, .vco_max = VC3_PLL3_VCO_MAX }, - .hw.init = &(struct clk_init_data){ + .hw.init = &(struct clk_init_data) { .name = "pll3", .ops = &vc3_pll_ops, .parent_hws = (const struct clk_hw *[]) { @@ -760,7 +752,7 @@ static struct vc3_hw_data clk_div_mux[] = { .offs = VC3_GENERAL_CTR, .bitmsk = VC3_GENERAL_CTR_DIV1_SRC_SEL }, - .hw.init = &(struct clk_init_data){ + .hw.init = &(struct clk_init_data) { .name = "div1_mux", .ops = &vc3_div_mux_ops, .parent_data = div_mux_parent_data[VC3_DIV1_MUX], @@ -773,7 +765,7 @@ static struct vc3_hw_data clk_div_mux[] = { .offs = VC3_PLL3_CHARGE_PUMP_CTRL, .bitmsk = VC3_PLL3_CHARGE_PUMP_CTRL_OUTDIV3_SRC_SEL }, - .hw.init = &(struct clk_init_data){ + .hw.init = &(struct clk_init_data) { .name = "div3_mux", .ops = &vc3_div_mux_ops, .parent_data = div_mux_parent_data[VC3_DIV3_MUX], @@ -786,7 +778,7 @@ static struct vc3_hw_data clk_div_mux[] = { .offs = VC3_OUTPUT_CTR, .bitmsk = VC3_OUTPUT_CTR_DIV4_SRC_SEL }, - .hw.init = &(struct clk_init_data){ + .hw.init = &(struct clk_init_data) { .name = "div4_mux", .ops = &vc3_div_mux_ops, .parent_data = div_mux_parent_data[VC3_DIV4_MUX], @@ -805,7 +797,7 @@ static struct vc3_hw_data clk_div[] = { .width = 4, .flags = CLK_DIVIDER_READ_ONLY }, - .hw.init = &(struct clk_init_data){ + .hw.init = &(struct clk_init_data) { .name = "div1", .ops = &vc3_div_ops, .parent_hws = (const struct clk_hw *[]) { @@ -823,7 +815,7 @@ static struct vc3_hw_data clk_div[] = { .width = 4, .flags = CLK_DIVIDER_READ_ONLY }, - .hw.init = &(struct clk_init_data){ + .hw.init = &(struct clk_init_data) { .name = "div2", .ops = &vc3_div_ops, .parent_hws = (const struct clk_hw *[]) { @@ -841,7 +833,7 @@ static struct vc3_hw_data clk_div[] = { .width = 4, .flags = CLK_DIVIDER_READ_ONLY }, - .hw.init = &(struct clk_init_data){ + .hw.init = &(struct clk_init_data) { .name = "div3", .ops = &vc3_div_ops, .parent_hws = (const struct clk_hw *[]) { @@ -859,7 +851,7 @@ static struct vc3_hw_data clk_div[] = { .width = 4, .flags = CLK_DIVIDER_READ_ONLY }, - .hw.init = &(struct clk_init_data){ + .hw.init = &(struct clk_init_data) { .name = "div4", .ops = &vc3_div_ops, .parent_hws = (const struct clk_hw *[]) { @@ -877,7 +869,7 @@ static struct vc3_hw_data clk_div[] = { .width = 4, .flags = CLK_DIVIDER_READ_ONLY }, - .hw.init = &(struct clk_init_data){ + .hw.init = &(struct clk_init_data) { .name = "div5", .ops = &vc3_div_ops, .parent_hws = (const struct clk_hw *[]) { @@ -895,7 +887,7 @@ static struct vc3_hw_data clk_mux[] = { .offs = VC3_SE1_DIV4_CTRL, .bitmsk = VC3_SE1_DIV4_CTRL_SE1_CLK_SEL }, - .hw.init = &(struct clk_init_data){ + .hw.init = &(struct clk_init_data) { .name = "se1_mux", .ops = &vc3_clk_mux_ops, .parent_hws = (const struct clk_hw *[]) { @@ -911,7 +903,7 @@ static struct vc3_hw_data clk_mux[] = { .offs = VC3_SE2_CTRL_REG0, .bitmsk = VC3_SE2_CTRL_REG0_SE2_CLK_SEL }, - .hw.init = &(struct clk_init_data){ + .hw.init = &(struct clk_init_data) { .name = "se2_mux", .ops = &vc3_clk_mux_ops, .parent_hws = (const struct clk_hw *[]) { @@ -927,7 +919,7 @@ static struct vc3_hw_data clk_mux[] = { .offs = VC3_SE3_DIFF1_CTRL_REG, .bitmsk = VC3_SE3_DIFF1_CTRL_REG_SE3_CLK_SEL }, - .hw.init = &(struct clk_init_data){ + .hw.init = &(struct clk_init_data) { .name = "se3_mux", .ops = &vc3_clk_mux_ops, .parent_hws = (const struct clk_hw *[]) { @@ -943,7 +935,7 @@ static struct vc3_hw_data clk_mux[] = { .offs = VC3_DIFF1_CTRL_REG, .bitmsk = VC3_DIFF1_CTRL_REG_DIFF1_CLK_SEL }, - .hw.init = &(struct clk_init_data){ + .hw.init = &(struct clk_init_data) { .name = "diff1_mux", .ops = &vc3_clk_mux_ops, .parent_hws = (const struct clk_hw *[]) { @@ -959,7 +951,7 @@ static struct vc3_hw_data clk_mux[] = { .offs = VC3_DIFF2_CTRL_REG, .bitmsk = VC3_DIFF2_CTRL_REG_DIFF2_CLK_SEL }, - .hw.init = &(struct clk_init_data){ + .hw.init = &(struct clk_init_data) { .name = "diff2_mux", .ops = &vc3_clk_mux_ops, .parent_hws = (const struct clk_hw *[]) { diff --git a/drivers/clk/hisilicon/clk-hi3620.c b/drivers/clk/hisilicon/clk-hi3620.c index 2d7186905abdc0..5d0226530fdb2f 100644 --- a/drivers/clk/hisilicon/clk-hi3620.c +++ b/drivers/clk/hisilicon/clk-hi3620.c @@ -466,8 +466,10 @@ static void __init hi3620_mmc_clk_init(struct device_node *node) return; clk_data->clks = kcalloc(num, sizeof(*clk_data->clks), GFP_KERNEL); - if (!clk_data->clks) + if (!clk_data->clks) { + kfree(clk_data); return; + } for (i = 0; i < num; i++) { struct hisi_mmc_clock *mmc_clk = &hi3620_mmc_clks[i]; diff --git a/drivers/clk/imx/clk-imx8qxp.c b/drivers/clk/imx/clk-imx8qxp.c index 41f0a45aa162e1..7d8883916cacdd 100644 --- a/drivers/clk/imx/clk-imx8qxp.c +++ b/drivers/clk/imx/clk-imx8qxp.c @@ -66,6 +66,22 @@ static const char * const lcd_pxl_sels[] = { "lcd_pxl_bypass_div_clk", }; +static const char *const lvds0_sels[] = { + "clk_dummy", + "clk_dummy", + "clk_dummy", + "clk_dummy", + "mipi0_lvds_bypass_clk", +}; + +static const char *const lvds1_sels[] = { + "clk_dummy", + "clk_dummy", + "clk_dummy", + "clk_dummy", + "mipi1_lvds_bypass_clk", +}; + static const char * const mipi_sels[] = { "clk_dummy", "clk_dummy", @@ -207,9 +223,9 @@ static int imx8qxp_clk_probe(struct platform_device *pdev) /* MIPI-LVDS SS */ imx_clk_scu("mipi0_bypass_clk", IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_BYPASS); imx_clk_scu("mipi0_pixel_clk", IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_PER); - imx_clk_scu("mipi0_lvds_pixel_clk", IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_MISC2); imx_clk_scu("mipi0_lvds_bypass_clk", IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_BYPASS); - imx_clk_scu("mipi0_lvds_phy_clk", IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_MISC3); + imx_clk_scu2("mipi0_lvds_pixel_clk", lvds0_sels, ARRAY_SIZE(lvds0_sels), IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_MISC2); + imx_clk_scu2("mipi0_lvds_phy_clk", lvds0_sels, ARRAY_SIZE(lvds0_sels), IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_MISC3); imx_clk_scu2("mipi0_dsi_tx_esc_clk", mipi_sels, ARRAY_SIZE(mipi_sels), IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_MST_BUS); imx_clk_scu2("mipi0_dsi_rx_esc_clk", mipi_sels, ARRAY_SIZE(mipi_sels), IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_SLV_BUS); imx_clk_scu2("mipi0_dsi_phy_clk", mipi_sels, ARRAY_SIZE(mipi_sels), IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_PHY); @@ -219,9 +235,9 @@ static int imx8qxp_clk_probe(struct platform_device *pdev) imx_clk_scu("mipi1_bypass_clk", IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_BYPASS); imx_clk_scu("mipi1_pixel_clk", IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_PER); - imx_clk_scu("mipi1_lvds_pixel_clk", IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_MISC2); imx_clk_scu("mipi1_lvds_bypass_clk", IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_BYPASS); - imx_clk_scu("mipi1_lvds_phy_clk", IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_MISC3); + imx_clk_scu2("mipi1_lvds_pixel_clk", lvds1_sels, ARRAY_SIZE(lvds1_sels), IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_MISC2); + imx_clk_scu2("mipi1_lvds_phy_clk", lvds1_sels, ARRAY_SIZE(lvds1_sels), IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_MISC3); imx_clk_scu2("mipi1_dsi_tx_esc_clk", mipi_sels, ARRAY_SIZE(mipi_sels), IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_MST_BUS); imx_clk_scu2("mipi1_dsi_rx_esc_clk", mipi_sels, ARRAY_SIZE(mipi_sels), IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_SLV_BUS); diff --git a/drivers/clk/imx/clk-pll14xx.c b/drivers/clk/imx/clk-pll14xx.c index 0d58d85c375e97..d63564dbb12cad 100644 --- a/drivers/clk/imx/clk-pll14xx.c +++ b/drivers/clk/imx/clk-pll14xx.c @@ -104,15 +104,15 @@ static const struct imx_pll14xx_rate_table *imx_get_pll_settings( static long pll14xx_calc_rate(struct clk_pll14xx *pll, int mdiv, int pdiv, int sdiv, int kdiv, unsigned long prate) { - u64 fvco = prate; + u64 fout = prate; - /* fvco = (m * 65536 + k) * Fin / (p * 65536) */ - fvco *= (mdiv * 65536 + kdiv); + /* fout = (m * 65536 + k) * Fin / (p * 65536) / (1 << sdiv) */ + fout *= (mdiv * 65536 + kdiv); pdiv *= 65536; - do_div(fvco, pdiv << sdiv); + do_div(fout, pdiv << sdiv); - return fvco; + return fout; } static long pll1443x_calc_kdiv(int mdiv, int pdiv, int sdiv, @@ -131,7 +131,7 @@ static void imx_pll14xx_calc_settings(struct clk_pll14xx *pll, unsigned long rat { u32 pll_div_ctl0, pll_div_ctl1; int mdiv, pdiv, sdiv, kdiv; - long fvco, rate_min, rate_max, dist, best = LONG_MAX; + long fout, rate_min, rate_max, dist, best = LONG_MAX; const struct imx_pll14xx_rate_table *tt; /* @@ -143,6 +143,7 @@ static void imx_pll14xx_calc_settings(struct clk_pll14xx *pll, unsigned long rat * d) -32768 <= k <= 32767 * * fvco = (m * 65536 + k) * prate / (p * 65536) + * fout = (m * 65536 + k) * prate / (p * 65536) / (1 << sdiv) */ /* First try if we can get the desired rate from one of the static entries */ @@ -173,8 +174,8 @@ static void imx_pll14xx_calc_settings(struct clk_pll14xx *pll, unsigned long rat pr_debug("%s: in=%ld, want=%ld Only adjust kdiv %ld -> %d\n", clk_hw_get_name(&pll->hw), prate, rate, FIELD_GET(KDIV_MASK, pll_div_ctl1), kdiv); - fvco = pll14xx_calc_rate(pll, mdiv, pdiv, sdiv, kdiv, prate); - t->rate = (unsigned int)fvco; + fout = pll14xx_calc_rate(pll, mdiv, pdiv, sdiv, kdiv, prate); + t->rate = (unsigned int)fout; t->mdiv = mdiv; t->pdiv = pdiv; t->sdiv = sdiv; @@ -190,13 +191,13 @@ static void imx_pll14xx_calc_settings(struct clk_pll14xx *pll, unsigned long rat mdiv = clamp(mdiv, 64, 1023); kdiv = pll1443x_calc_kdiv(mdiv, pdiv, sdiv, rate, prate); - fvco = pll14xx_calc_rate(pll, mdiv, pdiv, sdiv, kdiv, prate); + fout = pll14xx_calc_rate(pll, mdiv, pdiv, sdiv, kdiv, prate); /* best match */ - dist = abs((long)rate - (long)fvco); + dist = abs((long)rate - (long)fout); if (dist < best) { best = dist; - t->rate = (unsigned int)fvco; + t->rate = (unsigned int)fout; t->mdiv = mdiv; t->pdiv = pdiv; t->sdiv = sdiv; diff --git a/drivers/clk/imx/clk-scu.c b/drivers/clk/imx/clk-scu.c index be89180dd19c1e..e48a904c001330 100644 --- a/drivers/clk/imx/clk-scu.c +++ b/drivers/clk/imx/clk-scu.c @@ -886,8 +886,10 @@ struct clk_hw *__imx_clk_gpr_scu(const char *name, const char * const *parent_na return ERR_PTR(-EINVAL); } - if (!imx_clk_is_resource_owned(rsrc_id)) + if (!imx_clk_is_resource_owned(rsrc_id)) { + kfree(clk_node); return NULL; + } clk = kzalloc(sizeof(*clk), GFP_KERNEL); if (!clk) { diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig index 48b42d11111cde..70a005e7e1b180 100644 --- a/drivers/clk/mediatek/Kconfig +++ b/drivers/clk/mediatek/Kconfig @@ -423,6 +423,15 @@ config COMMON_CLK_MT7986_ETHSYS This driver adds support for clocks for Ethernet and SGMII required on MediaTek MT7986 SoC. +config COMMON_CLK_MT7988 + tristate "Clock driver for MediaTek MT7988" + depends on ARCH_MEDIATEK || COMPILE_TEST + select COMMON_CLK_MEDIATEK + default ARCH_MEDIATEK + help + This driver supports MediaTek MT7988 basic clocks and clocks + required for various periperals found on this SoC. + config COMMON_CLK_MT8135 tristate "Clock driver for MediaTek MT8135" depends on (ARCH_MEDIATEK && ARM) || COMPILE_TEST diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile index dbeaa5b41177dc..eeccfa039896f3 100644 --- a/drivers/clk/mediatek/Makefile +++ b/drivers/clk/mediatek/Makefile @@ -62,6 +62,11 @@ 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 obj-$(CONFIG_COMMON_CLK_MT7986_ETHSYS) += clk-mt7986-eth.o +obj-$(CONFIG_COMMON_CLK_MT7988) += clk-mt7988-apmixed.o +obj-$(CONFIG_COMMON_CLK_MT7988) += clk-mt7988-topckgen.o +obj-$(CONFIG_COMMON_CLK_MT7988) += clk-mt7988-infracfg.o +obj-$(CONFIG_COMMON_CLK_MT7988) += clk-mt7988-eth.o +obj-$(CONFIG_COMMON_CLK_MT7988) += clk-mt7988-xfipll.o obj-$(CONFIG_COMMON_CLK_MT8135) += clk-mt8135-apmixedsys.o clk-mt8135.o obj-$(CONFIG_COMMON_CLK_MT8167) += clk-mt8167-apmixedsys.o clk-mt8167.o obj-$(CONFIG_COMMON_CLK_MT8167_AUDSYS) += clk-mt8167-aud.o diff --git a/drivers/clk/mediatek/clk-mt7988-apmixed.c b/drivers/clk/mediatek/clk-mt7988-apmixed.c new file mode 100644 index 00000000000000..baf9564351a335 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt7988-apmixed.c @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023 MediaTek Inc. + * Author: Sam Shih + * Author: Xiufeng Li + */ + +#include +#include +#include +#include +#include +#include "clk-mtk.h" +#include "clk-gate.h" +#include "clk-mux.h" +#include "clk-pll.h" +#include + +#define MT7988_PLL_FMAX (2500UL * MHZ) +#define MT7988_PCW_CHG_BIT 2 + +#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _rst_bar_mask, _pcwbits, _pd_reg, \ + _pd_shift, _tuner_reg, _tuner_en_reg, _tuner_en_bit, _pcw_reg, _pcw_shift, \ + _pcw_chg_reg) \ + { \ + .id = _id, \ + .name = _name, \ + .reg = _reg, \ + .pwr_reg = _pwr_reg, \ + .en_mask = _en_mask, \ + .flags = _flags, \ + .rst_bar_mask = BIT(_rst_bar_mask), \ + .fmax = MT7988_PLL_FMAX, \ + .pcwbits = _pcwbits, \ + .pd_reg = _pd_reg, \ + .pd_shift = _pd_shift, \ + .tuner_reg = _tuner_reg, \ + .tuner_en_reg = _tuner_en_reg, \ + .tuner_en_bit = _tuner_en_bit, \ + .pcw_reg = _pcw_reg, \ + .pcw_shift = _pcw_shift, \ + .pcw_chg_reg = _pcw_chg_reg, \ + .pcw_chg_bit = MT7988_PCW_CHG_BIT, \ + .parent_name = "clkxtal", \ + } + +static const struct mtk_pll_data plls[] = { + PLL(CLK_APMIXED_NETSYSPLL, "netsyspll", 0x0104, 0x0110, 0x00000001, 0, 0, 32, 0x0104, 4, 0, + 0, 0, 0x0108, 0, 0x0104), + PLL(CLK_APMIXED_MPLL, "mpll", 0x0114, 0x0120, 0xff000001, HAVE_RST_BAR, 23, 32, 0x0114, 4, + 0, 0, 0, 0x0118, 0, 0x0114), + PLL(CLK_APMIXED_MMPLL, "mmpll", 0x0124, 0x0130, 0xff000001, HAVE_RST_BAR, 23, 32, 0x0124, 4, + 0, 0, 0, 0x0128, 0, 0x0124), + PLL(CLK_APMIXED_APLL2, "apll2", 0x0134, 0x0140, 0x00000001, 0, 0, 32, 0x0134, 4, 0x0704, + 0x0700, 1, 0x0138, 0, 0x0134), + PLL(CLK_APMIXED_NET1PLL, "net1pll", 0x0144, 0x0150, 0xff000001, HAVE_RST_BAR, 23, 32, + 0x0144, 4, 0, 0, 0, 0x0148, 0, 0x0144), + PLL(CLK_APMIXED_NET2PLL, "net2pll", 0x0154, 0x0160, 0xff000001, (HAVE_RST_BAR | PLL_AO), 23, + 32, 0x0154, 4, 0, 0, 0, 0x0158, 0, 0x0154), + PLL(CLK_APMIXED_WEDMCUPLL, "wedmcupll", 0x0164, 0x0170, 0x00000001, 0, 0, 32, 0x0164, 4, 0, + 0, 0, 0x0168, 0, 0x0164), + PLL(CLK_APMIXED_SGMPLL, "sgmpll", 0x0174, 0x0180, 0x00000001, 0, 0, 32, 0x0174, 4, 0, 0, 0, + 0x0178, 0, 0x0174), + PLL(CLK_APMIXED_ARM_B, "arm_b", 0x0204, 0x0210, 0xff000001, (HAVE_RST_BAR | PLL_AO), 23, 32, + 0x0204, 4, 0, 0, 0, 0x0208, 0, 0x0204), + PLL(CLK_APMIXED_CCIPLL2_B, "ccipll2_b", 0x0214, 0x0220, 0xff000001, HAVE_RST_BAR, 23, 32, + 0x0214, 4, 0, 0, 0, 0x0218, 0, 0x0214), + PLL(CLK_APMIXED_USXGMIIPLL, "usxgmiipll", 0x0304, 0x0310, 0xff000001, HAVE_RST_BAR, 23, 32, + 0x0304, 4, 0, 0, 0, 0x0308, 0, 0x0304), + PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x0314, 0x0320, 0x00000001, 0, 0, 32, 0x0314, 4, 0, 0, + 0, 0x0318, 0, 0x0314), +}; + +static const struct of_device_id of_match_clk_mt7988_apmixed[] = { + { .compatible = "mediatek,mt7988-apmixedsys" }, + { /* sentinel */ } +}; + +static int clk_mt7988_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; + + r = mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + if (r) + goto free_apmixed_data; + + r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); + if (r) + goto unregister_plls; + + return r; + +unregister_plls: + mtk_clk_unregister_plls(plls, ARRAY_SIZE(plls), clk_data); +free_apmixed_data: + mtk_free_clk_data(clk_data); + return r; +} + +static struct platform_driver clk_mt7988_apmixed_drv = { + .probe = clk_mt7988_apmixed_probe, + .driver = { + .name = "clk-mt7988-apmixed", + .of_match_table = of_match_clk_mt7988_apmixed, + }, +}; +builtin_platform_driver(clk_mt7988_apmixed_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt7988-eth.c b/drivers/clk/mediatek/clk-mt7988-eth.c new file mode 100644 index 00000000000000..adf4a9d39b38f1 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt7988-eth.c @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023 MediaTek Inc. + * Author: Sam Shih + * Author: Xiufeng Li + */ + +#include +#include +#include +#include +#include +#include "clk-mtk.h" +#include "clk-gate.h" +#include "reset.h" +#include +#include + +static const struct mtk_gate_regs ethdma_cg_regs = { + .set_ofs = 0x30, + .clr_ofs = 0x30, + .sta_ofs = 0x30, +}; + +#define GATE_ETHDMA(_id, _name, _parent, _shift) \ + { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = ðdma_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr_inv, \ + } + +static const struct mtk_gate ethdma_clks[] = { + GATE_ETHDMA(CLK_ETHDMA_XGP1_EN, "ethdma_xgp1_en", "top_xtal", 0), + GATE_ETHDMA(CLK_ETHDMA_XGP2_EN, "ethdma_xgp2_en", "top_xtal", 1), + GATE_ETHDMA(CLK_ETHDMA_XGP3_EN, "ethdma_xgp3_en", "top_xtal", 2), + GATE_ETHDMA(CLK_ETHDMA_FE_EN, "ethdma_fe_en", "netsys_2x_sel", 6), + GATE_ETHDMA(CLK_ETHDMA_GP2_EN, "ethdma_gp2_en", "top_xtal", 7), + GATE_ETHDMA(CLK_ETHDMA_GP1_EN, "ethdma_gp1_en", "top_xtal", 8), + GATE_ETHDMA(CLK_ETHDMA_GP3_EN, "ethdma_gp3_en", "top_xtal", 10), + GATE_ETHDMA(CLK_ETHDMA_ESW_EN, "ethdma_esw_en", "netsys_gsw_sel", 16), + GATE_ETHDMA(CLK_ETHDMA_CRYPT0_EN, "ethdma_crypt0_en", "eip197_sel", 29), +}; + +static const struct mtk_clk_desc ethdma_desc = { + .clks = ethdma_clks, + .num_clks = ARRAY_SIZE(ethdma_clks), +}; + +static const struct mtk_gate_regs sgmii_cg_regs = { + .set_ofs = 0xe4, + .clr_ofs = 0xe4, + .sta_ofs = 0xe4, +}; + +#define GATE_SGMII(_id, _name, _parent, _shift) \ + { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &sgmii_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr_inv, \ + } + +static const struct mtk_gate sgmii0_clks[] = { + GATE_SGMII(CLK_SGM0_TX_EN, "sgm0_tx_en", "top_xtal", 2), + GATE_SGMII(CLK_SGM0_RX_EN, "sgm0_rx_en", "top_xtal", 3), +}; + +static const struct mtk_clk_desc sgmii0_desc = { + .clks = sgmii0_clks, + .num_clks = ARRAY_SIZE(sgmii0_clks), +}; + +static const struct mtk_gate sgmii1_clks[] = { + GATE_SGMII(CLK_SGM1_TX_EN, "sgm1_tx_en", "top_xtal", 2), + GATE_SGMII(CLK_SGM1_RX_EN, "sgm1_rx_en", "top_xtal", 3), +}; + +static const struct mtk_clk_desc sgmii1_desc = { + .clks = sgmii1_clks, + .num_clks = ARRAY_SIZE(sgmii1_clks), +}; + +static const struct mtk_gate_regs ethwarp_cg_regs = { + .set_ofs = 0x14, + .clr_ofs = 0x14, + .sta_ofs = 0x14, +}; + +#define GATE_ETHWARP(_id, _name, _parent, _shift) \ + { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = ðwarp_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr_inv, \ + } + +static const struct mtk_gate ethwarp_clks[] = { + GATE_ETHWARP(CLK_ETHWARP_WOCPU2_EN, "ethwarp_wocpu2_en", "netsys_mcu_sel", 13), + GATE_ETHWARP(CLK_ETHWARP_WOCPU1_EN, "ethwarp_wocpu1_en", "netsys_mcu_sel", 14), + GATE_ETHWARP(CLK_ETHWARP_WOCPU0_EN, "ethwarp_wocpu0_en", "netsys_mcu_sel", 15), +}; + +static u16 ethwarp_rst_ofs[] = { 0x8 }; + +static u16 ethwarp_idx_map[] = { + [MT7988_ETHWARP_RST_SWITCH] = 9, +}; + +static const struct mtk_clk_rst_desc ethwarp_rst_desc = { + .version = MTK_RST_SIMPLE, + .rst_bank_ofs = ethwarp_rst_ofs, + .rst_bank_nr = ARRAY_SIZE(ethwarp_rst_ofs), + .rst_idx_map = ethwarp_idx_map, + .rst_idx_map_nr = ARRAY_SIZE(ethwarp_idx_map), +}; + +static const struct mtk_clk_desc ethwarp_desc = { + .clks = ethwarp_clks, + .num_clks = ARRAY_SIZE(ethwarp_clks), + .rst_desc = ðwarp_rst_desc, +}; + +static const struct of_device_id of_match_clk_mt7988_eth[] = { + { .compatible = "mediatek,mt7988-ethsys", .data = ðdma_desc }, + { .compatible = "mediatek,mt7988-sgmiisys0", .data = &sgmii0_desc }, + { .compatible = "mediatek,mt7988-sgmiisys1", .data = &sgmii1_desc }, + { .compatible = "mediatek,mt7988-ethwarp", .data = ðwarp_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt7988_eth); + +static struct platform_driver clk_mt7988_eth_drv = { + .driver = { + .name = "clk-mt7988-eth", + .of_match_table = of_match_clk_mt7988_eth, + }, + .probe = mtk_clk_simple_probe, + .remove_new = mtk_clk_simple_remove, +}; +module_platform_driver(clk_mt7988_eth_drv); + +MODULE_DESCRIPTION("MediaTek MT7988 Ethernet clocks driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt7988-infracfg.c b/drivers/clk/mediatek/clk-mt7988-infracfg.c new file mode 100644 index 00000000000000..8011ef278bea3e --- /dev/null +++ b/drivers/clk/mediatek/clk-mt7988-infracfg.c @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023 MediaTek Inc. + * Author: Sam Shih + * Author: Xiufeng Li + */ + +#include +#include +#include +#include +#include +#include "clk-mtk.h" +#include "clk-gate.h" +#include "clk-mux.h" +#include + +static DEFINE_SPINLOCK(mt7988_clk_lock); + +static const char *const infra_mux_uart0_parents[] __initconst = { "csw_infra_f26m_sel", + "uart_sel" }; + +static const char *const infra_mux_uart1_parents[] __initconst = { "csw_infra_f26m_sel", + "uart_sel" }; + +static const char *const infra_mux_uart2_parents[] __initconst = { "csw_infra_f26m_sel", + "uart_sel" }; + +static const char *const infra_mux_spi0_parents[] __initconst = { "i2c_sel", "spi_sel" }; + +static const char *const infra_mux_spi1_parents[] __initconst = { "i2c_sel", "spim_mst_sel" }; + +static const char *const infra_pwm_bck_parents[] __initconst = { "top_rtc_32p7k", + "csw_infra_f26m_sel", "sysaxi_sel", + "pwm_sel" }; + +static const char *const infra_pcie_gfmux_tl_ck_o_p0_parents[] __initconst = { + "top_rtc_32p7k", "csw_infra_f26m_sel", "csw_infra_f26m_sel", "pextp_tl_sel" +}; + +static const char *const infra_pcie_gfmux_tl_ck_o_p1_parents[] __initconst = { + "top_rtc_32p7k", "csw_infra_f26m_sel", "csw_infra_f26m_sel", "pextp_tl_p1_sel" +}; + +static const char *const infra_pcie_gfmux_tl_ck_o_p2_parents[] __initconst = { + "top_rtc_32p7k", "csw_infra_f26m_sel", "csw_infra_f26m_sel", "pextp_tl_p2_sel" +}; + +static const char *const infra_pcie_gfmux_tl_ck_o_p3_parents[] __initconst = { + "top_rtc_32p7k", "csw_infra_f26m_sel", "csw_infra_f26m_sel", "pextp_tl_p3_sel" +}; + +static const struct mtk_mux infra_muxes[] = { + /* MODULE_CLK_SEL_0 */ + MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_UART0_SEL, "infra_mux_uart0_sel", + infra_mux_uart0_parents, 0x0018, 0x0010, 0x0014, 0, 1, -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_UART1_SEL, "infra_mux_uart1_sel", + infra_mux_uart1_parents, 0x0018, 0x0010, 0x0014, 1, 1, -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_UART2_SEL, "infra_mux_uart2_sel", + infra_mux_uart2_parents, 0x0018, 0x0010, 0x0014, 2, 1, -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_SPI0_SEL, "infra_mux_spi0_sel", infra_mux_spi0_parents, + 0x0018, 0x0010, 0x0014, 4, 1, -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_SPI1_SEL, "infra_mux_spi1_sel", infra_mux_spi1_parents, + 0x0018, 0x0010, 0x0014, 5, 1, -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_SPI2_SEL, "infra_mux_spi2_sel", infra_mux_spi0_parents, + 0x0018, 0x0010, 0x0014, 6, 1, -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_SEL, "infra_pwm_sel", infra_pwm_bck_parents, 0x0018, + 0x0010, 0x0014, 14, 2, -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK1_SEL, "infra_pwm_ck1_sel", infra_pwm_bck_parents, + 0x0018, 0x0010, 0x0014, 16, 2, -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK2_SEL, "infra_pwm_ck2_sel", infra_pwm_bck_parents, + 0x0018, 0x0010, 0x0014, 18, 2, -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK3_SEL, "infra_pwm_ck3_sel", infra_pwm_bck_parents, + 0x0018, 0x0010, 0x0014, 20, 2, -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK4_SEL, "infra_pwm_ck4_sel", infra_pwm_bck_parents, + 0x0018, 0x0010, 0x0014, 22, 2, -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK5_SEL, "infra_pwm_ck5_sel", infra_pwm_bck_parents, + 0x0018, 0x0010, 0x0014, 24, 2, -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK6_SEL, "infra_pwm_ck6_sel", infra_pwm_bck_parents, + 0x0018, 0x0010, 0x0014, 26, 2, -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK7_SEL, "infra_pwm_ck7_sel", infra_pwm_bck_parents, + 0x0018, 0x0010, 0x0014, 28, 2, -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK8_SEL, "infra_pwm_ck8_sel", infra_pwm_bck_parents, + 0x0018, 0x0010, 0x0014, 30, 2, -1, -1, -1), + /* MODULE_CLK_SEL_1 */ + MUX_GATE_CLR_SET_UPD(CLK_INFRA_PCIE_GFMUX_TL_O_P0_SEL, "infra_pcie_gfmux_tl_o_p0_sel", + infra_pcie_gfmux_tl_ck_o_p0_parents, 0x0028, 0x0020, 0x0024, 0, 2, -1, + -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_PCIE_GFMUX_TL_O_P1_SEL, "infra_pcie_gfmux_tl_o_p1_sel", + infra_pcie_gfmux_tl_ck_o_p1_parents, 0x0028, 0x0020, 0x0024, 2, 2, -1, + -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_PCIE_GFMUX_TL_O_P2_SEL, "infra_pcie_gfmux_tl_o_p2_sel", + infra_pcie_gfmux_tl_ck_o_p2_parents, 0x0028, 0x0020, 0x0024, 4, 2, -1, + -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_PCIE_GFMUX_TL_O_P3_SEL, "infra_pcie_gfmux_tl_o_p3_sel", + infra_pcie_gfmux_tl_ck_o_p3_parents, 0x0028, 0x0020, 0x0024, 6, 2, -1, + -1, -1), +}; + +static const struct mtk_gate_regs infra0_cg_regs = { + .set_ofs = 0x10, + .clr_ofs = 0x14, + .sta_ofs = 0x18, +}; + +static const struct mtk_gate_regs infra1_cg_regs = { + .set_ofs = 0x40, + .clr_ofs = 0x44, + .sta_ofs = 0x48, +}; + +static const struct mtk_gate_regs infra2_cg_regs = { + .set_ofs = 0x50, + .clr_ofs = 0x54, + .sta_ofs = 0x58, +}; + +static const struct mtk_gate_regs infra3_cg_regs = { + .set_ofs = 0x60, + .clr_ofs = 0x64, + .sta_ofs = 0x68, +}; + +#define GATE_INFRA0_FLAGS(_id, _name, _parent, _shift, _flags) \ + GATE_MTK_FLAGS(_id, _name, _parent, &infra0_cg_regs, _shift, &mtk_clk_gate_ops_setclr, \ + _flags) + +#define GATE_INFRA1_FLAGS(_id, _name, _parent, _shift, _flags) \ + GATE_MTK_FLAGS(_id, _name, _parent, &infra1_cg_regs, _shift, &mtk_clk_gate_ops_setclr, \ + _flags) + +#define GATE_INFRA2_FLAGS(_id, _name, _parent, _shift, _flags) \ + GATE_MTK_FLAGS(_id, _name, _parent, &infra2_cg_regs, _shift, &mtk_clk_gate_ops_setclr, \ + _flags) + +#define GATE_INFRA3_FLAGS(_id, _name, _parent, _shift, _flags) \ + GATE_MTK_FLAGS(_id, _name, _parent, &infra3_cg_regs, _shift, &mtk_clk_gate_ops_setclr, \ + _flags) + +#define GATE_INFRA0(_id, _name, _parent, _shift) GATE_INFRA0_FLAGS(_id, _name, _parent, _shift, 0) + +#define GATE_INFRA1(_id, _name, _parent, _shift) GATE_INFRA1_FLAGS(_id, _name, _parent, _shift, 0) + +#define GATE_INFRA2(_id, _name, _parent, _shift) GATE_INFRA2_FLAGS(_id, _name, _parent, _shift, 0) + +#define GATE_INFRA3(_id, _name, _parent, _shift) GATE_INFRA3_FLAGS(_id, _name, _parent, _shift, 0) + +static const struct mtk_gate infra_clks[] = { + /* INFRA0 */ + GATE_INFRA0(CLK_INFRA_PCIE_PERI_26M_CK_P0, "infra_pcie_peri_ck_26m_ck_p0", + "csw_infra_f26m_sel", 7), + GATE_INFRA0(CLK_INFRA_PCIE_PERI_26M_CK_P1, "infra_pcie_peri_ck_26m_ck_p1", + "csw_infra_f26m_sel", 8), + GATE_INFRA0(CLK_INFRA_PCIE_PERI_26M_CK_P2, "infra_pcie_peri_ck_26m_ck_p2", + "csw_infra_f26m_sel", 9), + GATE_INFRA0(CLK_INFRA_PCIE_PERI_26M_CK_P3, "infra_pcie_peri_ck_26m_ck_p3", + "csw_infra_f26m_sel", 10), + /* INFRA1 */ + GATE_INFRA1(CLK_INFRA_66M_GPT_BCK, "infra_hf_66m_gpt_bck", "sysaxi_sel", 0), + GATE_INFRA1(CLK_INFRA_66M_PWM_HCK, "infra_hf_66m_pwm_hck", "sysaxi_sel", 1), + GATE_INFRA1(CLK_INFRA_66M_PWM_BCK, "infra_hf_66m_pwm_bck", "infra_pwm_sel", 2), + GATE_INFRA1(CLK_INFRA_66M_PWM_CK1, "infra_hf_66m_pwm_ck1", "infra_pwm_ck1_sel", 3), + GATE_INFRA1(CLK_INFRA_66M_PWM_CK2, "infra_hf_66m_pwm_ck2", "infra_pwm_ck2_sel", 4), + GATE_INFRA1(CLK_INFRA_66M_PWM_CK3, "infra_hf_66m_pwm_ck3", "infra_pwm_ck3_sel", 5), + GATE_INFRA1(CLK_INFRA_66M_PWM_CK4, "infra_hf_66m_pwm_ck4", "infra_pwm_ck4_sel", 6), + GATE_INFRA1(CLK_INFRA_66M_PWM_CK5, "infra_hf_66m_pwm_ck5", "infra_pwm_ck5_sel", 7), + GATE_INFRA1(CLK_INFRA_66M_PWM_CK6, "infra_hf_66m_pwm_ck6", "infra_pwm_ck6_sel", 8), + GATE_INFRA1(CLK_INFRA_66M_PWM_CK7, "infra_hf_66m_pwm_ck7", "infra_pwm_ck7_sel", 9), + GATE_INFRA1(CLK_INFRA_66M_PWM_CK8, "infra_hf_66m_pwm_ck8", "infra_pwm_ck8_sel", 10), + GATE_INFRA1(CLK_INFRA_133M_CQDMA_BCK, "infra_hf_133m_cqdma_bck", "sysaxi_sel", 12), + GATE_INFRA1(CLK_INFRA_66M_AUD_SLV_BCK, "infra_66m_aud_slv_bck", "sysaxi_sel", 13), + GATE_INFRA1(CLK_INFRA_AUD_26M, "infra_f_faud_26m", "csw_infra_f26m_sel", 14), + GATE_INFRA1(CLK_INFRA_AUD_L, "infra_f_faud_l", "aud_l_sel", 15), + GATE_INFRA1(CLK_INFRA_AUD_AUD, "infra_f_aud_aud", "a1sys_sel", 16), + GATE_INFRA1(CLK_INFRA_AUD_EG2, "infra_f_faud_eg2", "a_tuner_sel", 18), + GATE_INFRA1_FLAGS(CLK_INFRA_DRAMC_F26M, "infra_dramc_f26m", "csw_infra_f26m_sel", 19, + CLK_IS_CRITICAL), + /* JTAG */ + GATE_INFRA1_FLAGS(CLK_INFRA_133M_DBG_ACKM, "infra_hf_133m_dbg_ackm", "sysaxi_sel", 20, + CLK_IS_CRITICAL), + GATE_INFRA1(CLK_INFRA_66M_AP_DMA_BCK, "infra_66m_ap_dma_bck", "sysaxi_sel", 21), + GATE_INFRA1(CLK_INFRA_66M_SEJ_BCK, "infra_hf_66m_sej_bck", "sysaxi_sel", 29), + GATE_INFRA1(CLK_INFRA_PRE_CK_SEJ_F13M, "infra_pre_ck_sej_f13m", "csw_infra_f26m_sel", 30), + /* INFRA2 */ + GATE_INFRA2(CLK_INFRA_26M_THERM_SYSTEM, "infra_hf_26m_therm_system", "csw_infra_f26m_sel", + 0), + GATE_INFRA2(CLK_INFRA_I2C_BCK, "infra_i2c_bck", "i2c_sel", 1), + GATE_INFRA2(CLK_INFRA_52M_UART0_CK, "infra_f_52m_uart0", "infra_mux_uart0_sel", 3), + GATE_INFRA2(CLK_INFRA_52M_UART1_CK, "infra_f_52m_uart1", "infra_mux_uart1_sel", 4), + GATE_INFRA2(CLK_INFRA_52M_UART2_CK, "infra_f_52m_uart2", "infra_mux_uart2_sel", 5), + GATE_INFRA2(CLK_INFRA_NFI, "infra_f_fnfi", "nfi1x_sel", 9), + GATE_INFRA2(CLK_INFRA_SPINFI, "infra_f_fspinfi", "spinfi_sel", 10), + GATE_INFRA2_FLAGS(CLK_INFRA_66M_NFI_HCK, "infra_hf_66m_nfi_hck", "sysaxi_sel", 11, + CLK_IS_CRITICAL), + GATE_INFRA2_FLAGS(CLK_INFRA_104M_SPI0, "infra_hf_104m_spi0", "infra_mux_spi0_sel", 12, + CLK_IS_CRITICAL), + GATE_INFRA2(CLK_INFRA_104M_SPI1, "infra_hf_104m_spi1", "infra_mux_spi1_sel", 13), + GATE_INFRA2(CLK_INFRA_104M_SPI2_BCK, "infra_hf_104m_spi2_bck", "infra_mux_spi2_sel", 14), + GATE_INFRA2_FLAGS(CLK_INFRA_66M_SPI0_HCK, "infra_hf_66m_spi0_hck", "sysaxi_sel", 15, + CLK_IS_CRITICAL), + GATE_INFRA2(CLK_INFRA_66M_SPI1_HCK, "infra_hf_66m_spi1_hck", "sysaxi_sel", 16), + GATE_INFRA2(CLK_INFRA_66M_SPI2_HCK, "infra_hf_66m_spi2_hck", "sysaxi_sel", 17), + GATE_INFRA2(CLK_INFRA_66M_FLASHIF_AXI, "infra_hf_66m_flashif_axi", "sysaxi_sel", 18), + GATE_INFRA2_FLAGS(CLK_INFRA_RTC, "infra_f_frtc", "top_rtc_32k", 19, CLK_IS_CRITICAL), + GATE_INFRA2(CLK_INFRA_26M_ADC_BCK, "infra_f_26m_adc_bck", "csw_infra_f26m_sel", 20), + GATE_INFRA2(CLK_INFRA_RC_ADC, "infra_f_frc_adc", "infra_f_26m_adc_bck", 21), + GATE_INFRA2(CLK_INFRA_MSDC400, "infra_f_fmsdc400", "emmc_400m_sel", 22), + GATE_INFRA2(CLK_INFRA_MSDC2_HCK, "infra_f_fmsdc2_hck", "emmc_250m_sel", 23), + GATE_INFRA2(CLK_INFRA_133M_MSDC_0_HCK, "infra_hf_133m_msdc_0_hck", "sysaxi_sel", 24), + GATE_INFRA2(CLK_INFRA_66M_MSDC_0_HCK, "infra_66m_msdc_0_hck", "sysaxi_sel", 25), + GATE_INFRA2(CLK_INFRA_133M_CPUM_BCK, "infra_hf_133m_cpum_bck", "sysaxi_sel", 26), + GATE_INFRA2(CLK_INFRA_BIST2FPC, "infra_hf_fbist2fpc", "nfi1x_sel", 27), + GATE_INFRA2(CLK_INFRA_I2C_X16W_MCK_CK_P1, "infra_hf_i2c_x16w_mck_ck_p1", "sysaxi_sel", 29), + GATE_INFRA2(CLK_INFRA_I2C_X16W_PCK_CK_P1, "infra_hf_i2c_x16w_pck_ck_p1", "sysaxi_sel", 31), + /* INFRA3 */ + GATE_INFRA3(CLK_INFRA_133M_USB_HCK, "infra_133m_usb_hck", "sysaxi_sel", 0), + GATE_INFRA3(CLK_INFRA_133M_USB_HCK_CK_P1, "infra_133m_usb_hck_ck_p1", "sysaxi_sel", 1), + GATE_INFRA3(CLK_INFRA_66M_USB_HCK, "infra_66m_usb_hck", "sysaxi_sel", 2), + GATE_INFRA3(CLK_INFRA_66M_USB_HCK_CK_P1, "infra_66m_usb_hck_ck_p1", "sysaxi_sel", 3), + GATE_INFRA3(CLK_INFRA_USB_SYS, "infra_usb_sys", "usb_sys_sel", 4), + GATE_INFRA3(CLK_INFRA_USB_SYS_CK_P1, "infra_usb_sys_ck_p1", "usb_sys_p1_sel", 5), + GATE_INFRA3(CLK_INFRA_USB_REF, "infra_usb_ref", "top_xtal", 6), + GATE_INFRA3(CLK_INFRA_USB_CK_P1, "infra_usb_ck_p1", "top_xtal", 7), + GATE_INFRA3_FLAGS(CLK_INFRA_USB_FRMCNT, "infra_usb_frmcnt", "usb_frmcnt_sel", 8, + CLK_IS_CRITICAL), + GATE_INFRA3_FLAGS(CLK_INFRA_USB_FRMCNT_CK_P1, "infra_usb_frmcnt_ck_p1", "usb_frmcnt_p1_sel", + 9, CLK_IS_CRITICAL), + GATE_INFRA3(CLK_INFRA_USB_PIPE, "infra_usb_pipe", "sspxtp_sel", 10), + GATE_INFRA3(CLK_INFRA_USB_PIPE_CK_P1, "infra_usb_pipe_ck_p1", "usb_phy_sel", 11), + GATE_INFRA3(CLK_INFRA_USB_UTMI, "infra_usb_utmi", "top_xtal", 12), + GATE_INFRA3(CLK_INFRA_USB_UTMI_CK_P1, "infra_usb_utmi_ck_p1", "top_xtal", 13), + GATE_INFRA3(CLK_INFRA_USB_XHCI, "infra_usb_xhci", "usb_xhci_sel", 14), + GATE_INFRA3(CLK_INFRA_USB_XHCI_CK_P1, "infra_usb_xhci_ck_p1", "usb_xhci_p1_sel", 15), + GATE_INFRA3(CLK_INFRA_PCIE_GFMUX_TL_P0, "infra_pcie_gfmux_tl_ck_p0", + "infra_pcie_gfmux_tl_o_p0_sel", 20), + GATE_INFRA3(CLK_INFRA_PCIE_GFMUX_TL_P1, "infra_pcie_gfmux_tl_ck_p1", + "infra_pcie_gfmux_tl_o_p1_sel", 21), + GATE_INFRA3(CLK_INFRA_PCIE_GFMUX_TL_P2, "infra_pcie_gfmux_tl_ck_p2", + "infra_pcie_gfmux_tl_o_p2_sel", 22), + GATE_INFRA3(CLK_INFRA_PCIE_GFMUX_TL_P3, "infra_pcie_gfmux_tl_ck_p3", + "infra_pcie_gfmux_tl_o_p3_sel", 23), + GATE_INFRA3(CLK_INFRA_PCIE_PIPE_P0, "infra_pcie_pipe_ck_p0", "top_xtal", 24), + GATE_INFRA3(CLK_INFRA_PCIE_PIPE_P1, "infra_pcie_pipe_ck_p1", "top_xtal", 25), + GATE_INFRA3(CLK_INFRA_PCIE_PIPE_P2, "infra_pcie_pipe_ck_p2", "top_xtal", 26), + GATE_INFRA3(CLK_INFRA_PCIE_PIPE_P3, "infra_pcie_pipe_ck_p3", "top_xtal", 27), + GATE_INFRA3(CLK_INFRA_133M_PCIE_CK_P0, "infra_133m_pcie_ck_p0", "sysaxi_sel", 28), + GATE_INFRA3(CLK_INFRA_133M_PCIE_CK_P1, "infra_133m_pcie_ck_p1", "sysaxi_sel", 29), + GATE_INFRA3(CLK_INFRA_133M_PCIE_CK_P2, "infra_133m_pcie_ck_p2", "sysaxi_sel", 30), + GATE_INFRA3(CLK_INFRA_133M_PCIE_CK_P3, "infra_133m_pcie_ck_p3", "sysaxi_sel", 31), +}; + +static const struct mtk_clk_desc infra_desc = { + .clks = infra_clks, + .num_clks = ARRAY_SIZE(infra_clks), + .mux_clks = infra_muxes, + .num_mux_clks = ARRAY_SIZE(infra_muxes), + .clk_lock = &mt7988_clk_lock, +}; + +static const struct of_device_id of_match_clk_mt7988_infracfg[] = { + { .compatible = "mediatek,mt7988-infracfg", .data = &infra_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt7988_infracfg); + +static struct platform_driver clk_mt7988_infracfg_drv = { + .driver = { + .name = "clk-mt7988-infracfg", + .of_match_table = of_match_clk_mt7988_infracfg, + }, + .probe = mtk_clk_simple_probe, + .remove_new = mtk_clk_simple_remove, +}; +module_platform_driver(clk_mt7988_infracfg_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt7988-topckgen.c b/drivers/clk/mediatek/clk-mt7988-topckgen.c new file mode 100644 index 00000000000000..760f8e0d2f26a8 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt7988-topckgen.c @@ -0,0 +1,325 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023 MediaTek Inc. + * Author: Sam Shih + * Author: Xiufeng Li + */ + +#include +#include +#include +#include +#include +#include "clk-mtk.h" +#include "clk-gate.h" +#include "clk-mux.h" +#include + +static DEFINE_SPINLOCK(mt7988_clk_lock); + +static const struct mtk_fixed_clk top_fixed_clks[] = { + FIXED_CLK(CLK_TOP_XTAL, "top_xtal", "clkxtal", 40000000), +}; + +static const struct mtk_fixed_factor top_divs[] = { + FACTOR(CLK_TOP_XTAL_D2, "top_xtal_d2", "top_xtal", 1, 2), + FACTOR(CLK_TOP_RTC_32K, "top_rtc_32k", "top_xtal", 1, 1250), + FACTOR(CLK_TOP_RTC_32P7K, "top_rtc_32p7k", "top_xtal", 1, 1220), + FACTOR(CLK_TOP_MPLL_D2, "mpll_d2", "mpll", 1, 2), + FACTOR(CLK_TOP_MPLL_D3_D2, "mpll_d3_d2", "mpll", 1, 2), + FACTOR(CLK_TOP_MPLL_D4, "mpll_d4", "mpll", 1, 4), + FACTOR(CLK_TOP_MPLL_D8, "mpll_d8", "mpll", 1, 8), + FACTOR(CLK_TOP_MPLL_D8_D2, "mpll_d8_d2", "mpll", 1, 16), + FACTOR(CLK_TOP_MMPLL_D2, "mmpll_d2", "mmpll", 1, 2), + FACTOR(CLK_TOP_MMPLL_D3_D5, "mmpll_d3_d5", "mmpll", 1, 15), + FACTOR(CLK_TOP_MMPLL_D4, "mmpll_d4", "mmpll", 1, 4), + FACTOR(CLK_TOP_MMPLL_D6_D2, "mmpll_d6_d2", "mmpll", 1, 12), + FACTOR(CLK_TOP_MMPLL_D8, "mmpll_d8", "mmpll", 1, 8), + FACTOR(CLK_TOP_APLL2_D4, "apll2_d4", "apll2", 1, 4), + FACTOR(CLK_TOP_NET1PLL_D4, "net1pll_d4", "net1pll", 1, 4), + FACTOR(CLK_TOP_NET1PLL_D5, "net1pll_d5", "net1pll", 1, 5), + FACTOR(CLK_TOP_NET1PLL_D5_D2, "net1pll_d5_d2", "net1pll", 1, 10), + FACTOR(CLK_TOP_NET1PLL_D5_D4, "net1pll_d5_d4", "net1pll", 1, 20), + FACTOR(CLK_TOP_NET1PLL_D8, "net1pll_d8", "net1pll", 1, 8), + FACTOR(CLK_TOP_NET1PLL_D8_D2, "net1pll_d8_d2", "net1pll", 1, 16), + FACTOR(CLK_TOP_NET1PLL_D8_D4, "net1pll_d8_d4", "net1pll", 1, 32), + FACTOR(CLK_TOP_NET1PLL_D8_D8, "net1pll_d8_d8", "net1pll", 1, 64), + FACTOR(CLK_TOP_NET1PLL_D8_D16, "net1pll_d8_d16", "net1pll", 1, 128), + FACTOR(CLK_TOP_NET2PLL_D2, "net2pll_d2", "net2pll", 1, 2), + FACTOR(CLK_TOP_NET2PLL_D4, "net2pll_d4", "net2pll", 1, 4), + FACTOR(CLK_TOP_NET2PLL_D4_D4, "net2pll_d4_d4", "net2pll", 1, 16), + FACTOR(CLK_TOP_NET2PLL_D4_D8, "net2pll_d4_d8", "net2pll", 1, 32), + FACTOR(CLK_TOP_NET2PLL_D6, "net2pll_d6", "net2pll", 1, 6), + FACTOR(CLK_TOP_NET2PLL_D8, "net2pll_d8", "net2pll", 1, 8), +}; + +static const char *const netsys_parents[] = { "top_xtal", "net2pll_d2", "mmpll_d2" }; +static const char *const netsys_500m_parents[] = { "top_xtal", "net1pll_d5", "net1pll_d5_d2" }; +static const char *const netsys_2x_parents[] = { "top_xtal", "net2pll", "mmpll" }; +static const char *const netsys_gsw_parents[] = { "top_xtal", "net1pll_d4", "net1pll_d5" }; +static const char *const eth_gmii_parents[] = { "top_xtal", "net1pll_d5_d4" }; +static const char *const netsys_mcu_parents[] = { "top_xtal", "net2pll", "mmpll", + "net1pll_d4", "net1pll_d5", "mpll" }; +static const char *const eip197_parents[] = { "top_xtal", "netsyspll", "net2pll", + "mmpll", "net1pll_d4", "net1pll_d5" }; +static const char *const axi_infra_parents[] = { "top_xtal", "net1pll_d8_d2" }; +static const char *const uart_parents[] = { "top_xtal", "mpll_d8", "mpll_d8_d2" }; +static const char *const emmc_250m_parents[] = { "top_xtal", "net1pll_d5_d2", "mmpll_d4" }; +static const char *const emmc_400m_parents[] = { "top_xtal", "msdcpll", "mmpll_d2", + "mpll_d2", "mmpll_d4", "net1pll_d8_d2" }; +static const char *const spi_parents[] = { "top_xtal", "mpll_d2", "mmpll_d4", + "net1pll_d8_d2", "net2pll_d6", "net1pll_d5_d4", + "mpll_d4", "net1pll_d8_d4" }; +static const char *const nfi1x_parents[] = { "top_xtal", "mmpll_d4", "net1pll_d8_d2", "net2pll_d6", + "mpll_d4", "mmpll_d8", "net1pll_d8_d4", "mpll_d8" }; +static const char *const spinfi_parents[] = { "top_xtal_d2", "top_xtal", "net1pll_d5_d4", + "mpll_d4", "mmpll_d8", "net1pll_d8_d4", + "mmpll_d6_d2", "mpll_d8" }; +static const char *const pwm_parents[] = { "top_xtal", "net1pll_d8_d2", "net1pll_d5_d4", + "mpll_d4", "mpll_d8_d2", "top_rtc_32k" }; +static const char *const i2c_parents[] = { "top_xtal", "net1pll_d5_d4", "mpll_d4", + "net1pll_d8_d4" }; +static const char *const pcie_mbist_250m_parents[] = { "top_xtal", "net1pll_d5_d2" }; +static const char *const pextp_tl_ck_parents[] = { "top_xtal", "net2pll_d6", "mmpll_d8", + "mpll_d8_d2", "top_rtc_32k" }; +static const char *const usb_frmcnt_parents[] = { "top_xtal", "mmpll_d3_d5" }; +static const char *const aud_parents[] = { "top_xtal", "apll2" }; +static const char *const a1sys_parents[] = { "top_xtal", "apll2_d4" }; +static const char *const aud_l_parents[] = { "top_xtal", "apll2", "mpll_d8_d2" }; +static const char *const sspxtp_parents[] = { "top_xtal_d2", "mpll_d8_d2" }; +static const char *const usxgmii_sbus_0_parents[] = { "top_xtal", "net1pll_d8_d4" }; +static const char *const sgm_0_parents[] = { "top_xtal", "sgmpll" }; +static const char *const sysapb_parents[] = { "top_xtal", "mpll_d3_d2" }; +static const char *const eth_refck_50m_parents[] = { "top_xtal", "net2pll_d4_d4" }; +static const char *const eth_sys_200m_parents[] = { "top_xtal", "net2pll_d4" }; +static const char *const eth_xgmii_parents[] = { "top_xtal_d2", "net1pll_d8_d8", "net1pll_d8_d16" }; +static const char *const bus_tops_parents[] = { "top_xtal", "net1pll_d5", "net2pll_d2" }; +static const char *const npu_tops_parents[] = { "top_xtal", "net2pll" }; +static const char *const dramc_md32_parents[] = { "top_xtal", "mpll_d2", "wedmcupll" }; +static const char *const da_xtp_glb_p0_parents[] = { "top_xtal", "net2pll_d8" }; +static const char *const mcusys_backup_625m_parents[] = { "top_xtal", "net1pll_d4" }; +static const char *const macsec_parents[] = { "top_xtal", "sgmpll", "net1pll_d8" }; +static const char *const netsys_tops_400m_parents[] = { "top_xtal", "net2pll_d2" }; +static const char *const eth_mii_parents[] = { "top_xtal_d2", "net2pll_d4_d8" }; + +static const struct mtk_mux top_muxes[] = { + /* CLK_CFG_0 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_SEL, "netsys_sel", netsys_parents, 0x000, 0x004, 0x008, + 0, 2, 7, 0x1c0, 0), + MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_500M_SEL, "netsys_500m_sel", netsys_500m_parents, 0x000, + 0x004, 0x008, 8, 2, 15, 0x1C0, 1), + MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_2X_SEL, "netsys_2x_sel", netsys_2x_parents, 0x000, + 0x004, 0x008, 16, 2, 23, 0x1C0, 2), + MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_GSW_SEL, "netsys_gsw_sel", netsys_gsw_parents, 0x000, + 0x004, 0x008, 24, 2, 31, 0x1C0, 3), + /* CLK_CFG_1 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_ETH_GMII_SEL, "eth_gmii_sel", eth_gmii_parents, 0x010, 0x014, + 0x018, 0, 1, 7, 0x1C0, 4), + MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_MCU_SEL, "netsys_mcu_sel", netsys_mcu_parents, 0x010, + 0x014, 0x018, 8, 3, 15, 0x1C0, 5), + MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_PAO_2X_SEL, "netsys_pao_2x_sel", netsys_mcu_parents, + 0x010, 0x014, 0x018, 16, 3, 23, 0x1C0, 6), + MUX_GATE_CLR_SET_UPD(CLK_TOP_EIP197_SEL, "eip197_sel", eip197_parents, 0x010, 0x014, 0x018, + 24, 3, 31, 0x1c0, 7), + /* CLK_CFG_2 */ + MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_AXI_INFRA_SEL, "axi_infra_sel", axi_infra_parents, 0x020, + 0x024, 0x028, 0, 1, 7, 0x1C0, 8, CLK_IS_CRITICAL), + MUX_GATE_CLR_SET_UPD(CLK_TOP_UART_SEL, "uart_sel", uart_parents, 0x020, 0x024, 0x028, 8, 2, + 15, 0x1c0, 9), + MUX_GATE_CLR_SET_UPD(CLK_TOP_EMMC_250M_SEL, "emmc_250m_sel", emmc_250m_parents, 0x020, + 0x024, 0x028, 16, 2, 23, 0x1C0, 10), + MUX_GATE_CLR_SET_UPD(CLK_TOP_EMMC_400M_SEL, "emmc_400m_sel", emmc_400m_parents, 0x020, + 0x024, 0x028, 24, 3, 31, 0x1C0, 11), + /* CLK_CFG_3 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_SPI_SEL, "spi_sel", spi_parents, 0x030, 0x034, 0x038, 0, 3, 7, + 0x1c0, 12), + MUX_GATE_CLR_SET_UPD(CLK_TOP_SPIM_MST_SEL, "spim_mst_sel", spi_parents, 0x030, 0x034, 0x038, + 8, 3, 15, 0x1c0, 13), + MUX_GATE_CLR_SET_UPD(CLK_TOP_NFI1X_SEL, "nfi1x_sel", nfi1x_parents, 0x030, 0x034, 0x038, 16, + 3, 23, 0x1c0, 14), + MUX_GATE_CLR_SET_UPD(CLK_TOP_SPINFI_SEL, "spinfi_sel", spinfi_parents, 0x030, 0x034, 0x038, + 24, 3, 31, 0x1c0, 15), + /* CLK_CFG_4 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_PWM_SEL, "pwm_sel", pwm_parents, 0x040, 0x044, 0x048, 0, 3, 7, + 0x1c0, 16), + MUX_GATE_CLR_SET_UPD(CLK_TOP_I2C_SEL, "i2c_sel", i2c_parents, 0x040, 0x044, 0x048, 8, 2, 15, + 0x1c0, 17), + MUX_GATE_CLR_SET_UPD(CLK_TOP_PCIE_MBIST_250M_SEL, "pcie_mbist_250m_sel", + pcie_mbist_250m_parents, 0x040, 0x044, 0x048, 16, 1, 23, 0x1C0, 18), + MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_TL_SEL, "pextp_tl_sel", pextp_tl_ck_parents, 0x040, + 0x044, 0x048, 24, 3, 31, 0x1C0, 19), + /* CLK_CFG_5 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_TL_P1_SEL, "pextp_tl_p1_sel", pextp_tl_ck_parents, 0x050, + 0x054, 0x058, 0, 3, 7, 0x1C0, 20), + MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_TL_P2_SEL, "pextp_tl_p2_sel", pextp_tl_ck_parents, 0x050, + 0x054, 0x058, 8, 3, 15, 0x1C0, 21), + MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_TL_P3_SEL, "pextp_tl_p3_sel", pextp_tl_ck_parents, 0x050, + 0x054, 0x058, 16, 3, 23, 0x1C0, 22), + MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_SYS_SEL, "usb_sys_sel", eth_gmii_parents, 0x050, 0x054, + 0x058, 24, 1, 31, 0x1C0, 23), + /* CLK_CFG_6 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_SYS_P1_SEL, "usb_sys_p1_sel", eth_gmii_parents, 0x060, + 0x064, 0x068, 0, 1, 7, 0x1C0, 24), + MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_XHCI_SEL, "usb_xhci_sel", eth_gmii_parents, 0x060, 0x064, + 0x068, 8, 1, 15, 0x1C0, 25), + MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_XHCI_P1_SEL, "usb_xhci_p1_sel", eth_gmii_parents, 0x060, + 0x064, 0x068, 16, 1, 23, 0x1C0, 26), + MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_FRMCNT_SEL, "usb_frmcnt_sel", usb_frmcnt_parents, 0x060, + 0x064, 0x068, 24, 1, 31, 0x1C0, 27), + /* CLK_CFG_7 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_FRMCNT_P1_SEL, "usb_frmcnt_p1_sel", usb_frmcnt_parents, + 0x070, 0x074, 0x078, 0, 1, 7, 0x1C0, 28), + MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD_SEL, "aud_sel", aud_parents, 0x070, 0x074, 0x078, 8, 1, 15, + 0x1c0, 29), + MUX_GATE_CLR_SET_UPD(CLK_TOP_A1SYS_SEL, "a1sys_sel", a1sys_parents, 0x070, 0x074, 0x078, 16, + 1, 23, 0x1c0, 30), + MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD_L_SEL, "aud_l_sel", aud_l_parents, 0x070, 0x074, 0x078, 24, + 2, 31, 0x1c4, 0), + /* CLK_CFG_8 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_A_TUNER_SEL, "a_tuner_sel", a1sys_parents, 0x080, 0x084, 0x088, + 0, 1, 7, 0x1c4, 1), + MUX_GATE_CLR_SET_UPD(CLK_TOP_SSPXTP_SEL, "sspxtp_sel", sspxtp_parents, 0x080, 0x084, 0x088, + 8, 1, 15, 0x1c4, 2), + MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_PHY_SEL, "usb_phy_sel", sspxtp_parents, 0x080, 0x084, + 0x088, 16, 1, 23, 0x1c4, 3), + MUX_GATE_CLR_SET_UPD(CLK_TOP_USXGMII_SBUS_0_SEL, "usxgmii_sbus_0_sel", + usxgmii_sbus_0_parents, 0x080, 0x084, 0x088, 24, 1, 31, 0x1C4, 4), + /* CLK_CFG_9 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_USXGMII_SBUS_1_SEL, "usxgmii_sbus_1_sel", + usxgmii_sbus_0_parents, 0x090, 0x094, 0x098, 0, 1, 7, 0x1C4, 5), + MUX_GATE_CLR_SET_UPD(CLK_TOP_SGM_0_SEL, "sgm_0_sel", sgm_0_parents, 0x090, 0x094, 0x098, 8, + 1, 15, 0x1c4, 6), + MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SGM_SBUS_0_SEL, "sgm_sbus_0_sel", usxgmii_sbus_0_parents, + 0x090, 0x094, 0x098, 16, 1, 23, 0x1C4, 7, CLK_IS_CRITICAL), + MUX_GATE_CLR_SET_UPD(CLK_TOP_SGM_1_SEL, "sgm_1_sel", sgm_0_parents, 0x090, 0x094, 0x098, 24, + 1, 31, 0x1c4, 8), + /* CLK_CFG_10 */ + MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SGM_SBUS_1_SEL, "sgm_sbus_1_sel", usxgmii_sbus_0_parents, + 0x0a0, 0x0a4, 0x0a8, 0, 1, 7, 0x1C4, 9, CLK_IS_CRITICAL), + MUX_GATE_CLR_SET_UPD(CLK_TOP_XFI_PHY_0_XTAL_SEL, "xfi_phy_0_xtal_sel", sspxtp_parents, + 0x0a0, 0x0a4, 0x0a8, 8, 1, 15, 0x1C4, 10), + MUX_GATE_CLR_SET_UPD(CLK_TOP_XFI_PHY_1_XTAL_SEL, "xfi_phy_1_xtal_sel", sspxtp_parents, + 0x0a0, 0x0a4, 0x0a8, 16, 1, 23, 0x1C4, 11), + /* CLK_CFG_11 */ + MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SYSAXI_SEL, "sysaxi_sel", axi_infra_parents, 0x0a0, + 0x0a4, 0x0a8, 24, 1, 31, 0x1C4, 12, CLK_IS_CRITICAL), + MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SYSAPB_SEL, "sysapb_sel", sysapb_parents, 0x0b0, 0x0b4, + 0x0b8, 0, 1, 7, 0x1c4, 13, CLK_IS_CRITICAL), + MUX_GATE_CLR_SET_UPD(CLK_TOP_ETH_REFCK_50M_SEL, "eth_refck_50m_sel", eth_refck_50m_parents, + 0x0b0, 0x0b4, 0x0b8, 8, 1, 15, 0x1C4, 14), + MUX_GATE_CLR_SET_UPD(CLK_TOP_ETH_SYS_200M_SEL, "eth_sys_200m_sel", eth_sys_200m_parents, + 0x0b0, 0x0b4, 0x0b8, 16, 1, 23, 0x1C4, 15), + MUX_GATE_CLR_SET_UPD(CLK_TOP_ETH_SYS_SEL, "eth_sys_sel", pcie_mbist_250m_parents, 0x0b0, + 0x0b4, 0x0b8, 24, 1, 31, 0x1C4, 16), + /* CLK_CFG_12 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_ETH_XGMII_SEL, "eth_xgmii_sel", eth_xgmii_parents, 0x0c0, + 0x0c4, 0x0c8, 0, 2, 7, 0x1C4, 17), + MUX_GATE_CLR_SET_UPD(CLK_TOP_BUS_TOPS_SEL, "bus_tops_sel", bus_tops_parents, 0x0c0, 0x0c4, + 0x0c8, 8, 2, 15, 0x1C4, 18), + MUX_GATE_CLR_SET_UPD(CLK_TOP_NPU_TOPS_SEL, "npu_tops_sel", npu_tops_parents, 0x0c0, 0x0c4, + 0x0c8, 16, 1, 23, 0x1C4, 19), + MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_DRAMC_SEL, "dramc_sel", sspxtp_parents, 0x0c0, 0x0c4, + 0x0c8, 24, 1, 31, 0x1C4, 20, CLK_IS_CRITICAL), + /* CLK_CFG_13 */ + MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_DRAMC_MD32_SEL, "dramc_md32_sel", dramc_md32_parents, + 0x0d0, 0x0d4, 0x0d8, 0, 2, 7, 0x1C4, 21, CLK_IS_CRITICAL), + MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_INFRA_F26M_SEL, "csw_infra_f26m_sel", sspxtp_parents, + 0x0d0, 0x0d4, 0x0d8, 8, 1, 15, 0x1C4, 22, CLK_IS_CRITICAL), + MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_P0_SEL, "pextp_p0_sel", sspxtp_parents, 0x0d0, 0x0d4, + 0x0d8, 16, 1, 23, 0x1C4, 23), + MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_P1_SEL, "pextp_p1_sel", sspxtp_parents, 0x0d0, 0x0d4, + 0x0d8, 24, 1, 31, 0x1C4, 24), + /* CLK_CFG_14 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_P2_SEL, "pextp_p2_sel", sspxtp_parents, 0x0e0, 0x0e4, + 0x0e8, 0, 1, 7, 0x1C4, 25), + MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_P3_SEL, "pextp_p3_sel", sspxtp_parents, 0x0e0, 0x0e4, + 0x0e8, 8, 1, 15, 0x1C4, 26), + MUX_GATE_CLR_SET_UPD(CLK_TOP_DA_XTP_GLB_P0_SEL, "da_xtp_glb_p0_sel", da_xtp_glb_p0_parents, + 0x0e0, 0x0e4, 0x0e8, 16, 1, 23, 0x1C4, 27), + MUX_GATE_CLR_SET_UPD(CLK_TOP_DA_XTP_GLB_P1_SEL, "da_xtp_glb_p1_sel", da_xtp_glb_p0_parents, + 0x0e0, 0x0e4, 0x0e8, 24, 1, 31, 0x1C4, 28), + /* CLK_CFG_15 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_DA_XTP_GLB_P2_SEL, "da_xtp_glb_p2_sel", da_xtp_glb_p0_parents, + 0x0f0, 0x0f4, 0x0f8, 0, 1, 7, 0x1C4, 29), + MUX_GATE_CLR_SET_UPD(CLK_TOP_DA_XTP_GLB_P3_SEL, "da_xtp_glb_p3_sel", da_xtp_glb_p0_parents, + 0x0f0, 0x0f4, 0x0f8, 8, 1, 15, 0x1C4, 30), + MUX_GATE_CLR_SET_UPD(CLK_TOP_CKM_SEL, "ckm_sel", sspxtp_parents, 0x0F0, 0x0f4, 0x0f8, 16, 1, + 23, 0x1c8, 0), + MUX_GATE_CLR_SET_UPD(CLK_TOP_DA_SEL, "da_sel", sspxtp_parents, 0x0f0, 0x0f4, 0x0f8, 24, 1, + 31, 0x1C8, 1), + /* CLK_CFG_16 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_SEL, "pextp_sel", sspxtp_parents, 0x0100, 0x104, 0x108, + 0, 1, 7, 0x1c8, 2), + MUX_GATE_CLR_SET_UPD(CLK_TOP_TOPS_P2_26M_SEL, "tops_p2_26m_sel", sspxtp_parents, 0x0100, + 0x104, 0x108, 8, 1, 15, 0x1C8, 3), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MCUSYS_BACKUP_625M_SEL, "mcusys_backup_625m_sel", + mcusys_backup_625m_parents, 0x0100, 0x104, 0x108, 16, 1, 23, 0x1C8, 4), + MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_SYNC_250M_SEL, "netsys_sync_250m_sel", + pcie_mbist_250m_parents, 0x0100, 0x104, 0x108, 24, 1, 31, 0x1c8, 5), + /* CLK_CFG_17 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_MACSEC_SEL, "macsec_sel", macsec_parents, 0x0110, 0x114, 0x118, + 0, 2, 7, 0x1c8, 6), + MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_TOPS_400M_SEL, "netsys_tops_400m_sel", + netsys_tops_400m_parents, 0x0110, 0x114, 0x118, 8, 1, 15, 0x1c8, 7), + MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_PPEFB_250M_SEL, "netsys_ppefb_250m_sel", + pcie_mbist_250m_parents, 0x0110, 0x114, 0x118, 16, 1, 23, 0x1c8, 8), + MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_WARP_SEL, "netsys_warp_sel", netsys_parents, 0x0110, + 0x114, 0x118, 24, 2, 31, 0x1C8, 9), + /* CLK_CFG_18 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_ETH_MII_SEL, "eth_mii_sel", eth_mii_parents, 0x0120, 0x124, + 0x128, 0, 1, 7, 0x1c8, 10), + MUX_GATE_CLR_SET_UPD(CLK_TOP_NPU_SEL, "ck_npu_sel", netsys_2x_parents, 0x0120, 0x124, 0x128, + 8, 2, 15, 0x1c8, 11), +}; + +static const struct mtk_composite top_aud_divs[] = { + DIV_GATE(CLK_TOP_AUD_I2S_M, "aud_i2s_m", "aud_sel", 0x0420, 0, 0x0420, 8, 8), +}; + +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), + .composite_clks = top_aud_divs, + .num_composite_clks = ARRAY_SIZE(top_aud_divs), + .clk_lock = &mt7988_clk_lock, +}; + +static const char *const mcu_bus_div_parents[] = { "top_xtal", "ccipll2_b", "net1pll_d4" }; + +static const char *const mcu_arm_div_parents[] = { "top_xtal", "arm_b", "net1pll_d4" }; + +static struct mtk_composite mcu_muxes[] = { + /* bus_pll_divider_cfg */ + MUX_GATE_FLAGS(CLK_MCU_BUS_DIV_SEL, "mcu_bus_div_sel", mcu_bus_div_parents, 0x7C0, 9, 2, -1, + CLK_IS_CRITICAL), + /* mp2_pll_divider_cfg */ + MUX_GATE_FLAGS(CLK_MCU_ARM_DIV_SEL, "mcu_arm_div_sel", mcu_arm_div_parents, 0x7A8, 9, 2, -1, + CLK_IS_CRITICAL), +}; + +static const struct mtk_clk_desc mcusys_desc = { + .composite_clks = mcu_muxes, + .num_composite_clks = ARRAY_SIZE(mcu_muxes), +}; + +static const struct of_device_id of_match_clk_mt7988_topckgen[] = { + { .compatible = "mediatek,mt7988-topckgen", .data = &topck_desc }, + { .compatible = "mediatek,mt7988-mcusys", .data = &mcusys_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt7988_topckgen); + +static struct platform_driver clk_mt7988_topckgen_drv = { + .probe = mtk_clk_simple_probe, + .remove_new = mtk_clk_simple_remove, + .driver = { + .name = "clk-mt7988-topckgen", + .of_match_table = of_match_clk_mt7988_topckgen, + }, +}; +module_platform_driver(clk_mt7988_topckgen_drv); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt7988-xfipll.c b/drivers/clk/mediatek/clk-mt7988-xfipll.c new file mode 100644 index 00000000000000..9b9ca5471158be --- /dev/null +++ b/drivers/clk/mediatek/clk-mt7988-xfipll.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023 Daniel Golle + */ + +#include +#include +#include +#include +#include +#include "clk-mtk.h" +#include "clk-gate.h" +#include + +/* Register to control USXGMII XFI PLL analog */ +#define XFI_PLL_ANA_GLB8 0x108 +#define RG_XFI_PLL_ANA_SWWA 0x02283248 + +static const struct mtk_gate_regs xfipll_cg_regs = { + .set_ofs = 0x8, + .clr_ofs = 0x8, + .sta_ofs = 0x8, +}; + +#define GATE_XFIPLL(_id, _name, _parent, _shift) \ + { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &xfipll_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr_inv, \ + } + +static const struct mtk_fixed_factor xfipll_divs[] = { + FACTOR(CLK_XFIPLL_PLL, "xfipll_pll", "top_xtal", 125, 32), +}; + +static const struct mtk_gate xfipll_clks[] = { + GATE_XFIPLL(CLK_XFIPLL_PLL_EN, "xfipll_pll_en", "xfipll_pll", 31), +}; + +static const struct mtk_clk_desc xfipll_desc = { + .clks = xfipll_clks, + .num_clks = ARRAY_SIZE(xfipll_clks), + .factor_clks = xfipll_divs, + .num_factor_clks = ARRAY_SIZE(xfipll_divs), +}; + +static int clk_mt7988_xfipll_probe(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + void __iomem *base = of_iomap(node, 0); + + if (!base) + return -ENOMEM; + + /* Apply software workaround for USXGMII PLL TCL issue */ + writel(RG_XFI_PLL_ANA_SWWA, base + XFI_PLL_ANA_GLB8); + iounmap(base); + + return mtk_clk_simple_probe(pdev); +}; + +static const struct of_device_id of_match_clk_mt7988_xfipll[] = { + { .compatible = "mediatek,mt7988-xfi-pll", .data = &xfipll_desc }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match_clk_mt7988_xfipll); + +static struct platform_driver clk_mt7988_xfipll_drv = { + .driver = { + .name = "clk-mt7988-xfipll", + .of_match_table = of_match_clk_mt7988_xfipll, + }, + .probe = clk_mt7988_xfipll_probe, + .remove_new = mtk_clk_simple_remove, +}; +module_platform_driver(clk_mt7988_xfipll_drv); + +MODULE_DESCRIPTION("MediaTek MT7988 XFI PLL clock driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/mediatek/clk-mt8188-topckgen.c b/drivers/clk/mediatek/clk-mt8188-topckgen.c index e330a4f9a0c3fd..f7ec599b20af70 100644 --- a/drivers/clk/mediatek/clk-mt8188-topckgen.c +++ b/drivers/clk/mediatek/clk-mt8188-topckgen.c @@ -475,29 +475,28 @@ static const char * const sspm_parents[] = { "mainpll_d4_d2" }; +/* + * Both DP/eDP can be parented to TVDPLL1 and TVDPLL2, but we force using + * TVDPLL1 on eDP and TVDPLL2 on DP to avoid changing the "other" PLL rate + * in dual output case, which would lead to corruption of functionality loss. + */ static const char * const dp_parents[] = { "clk26m", - "tvdpll1_d2", "tvdpll2_d2", - "tvdpll1_d4", "tvdpll2_d4", - "tvdpll1_d8", "tvdpll2_d8", - "tvdpll1_d16", "tvdpll2_d16" }; +static const u8 dp_parents_idx[] = { 0, 2, 4, 6, 8 }; static const char * const edp_parents[] = { "clk26m", "tvdpll1_d2", - "tvdpll2_d2", "tvdpll1_d4", - "tvdpll2_d4", "tvdpll1_d8", - "tvdpll2_d8", - "tvdpll1_d16", - "tvdpll2_d16" + "tvdpll1_d16" }; +static const u8 edp_parents_idx[] = { 0, 1, 3, 5, 7 }; static const char * const dpi_parents[] = { "clk26m", @@ -1038,10 +1037,12 @@ static const struct mtk_mux top_mtk_muxes[] = { MUX_GATE_CLR_SET_UPD(CLK_TOP_SSPM, "top_sspm", sspm_parents, 0x080, 0x084, 0x088, 24, 4, 31, 0x08, 3), /* CLK_CFG_9 */ - MUX_GATE_CLR_SET_UPD(CLK_TOP_DP, "top_dp", - dp_parents, 0x08C, 0x090, 0x094, 0, 4, 7, 0x08, 4), - MUX_GATE_CLR_SET_UPD(CLK_TOP_EDP, "top_edp", - edp_parents, 0x08C, 0x090, 0x094, 8, 4, 15, 0x08, 5), + MUX_GATE_CLR_SET_UPD_INDEXED(CLK_TOP_DP, "top_dp", + dp_parents, dp_parents_idx, 0x08C, 0x090, 0x094, + 0, 4, 7, 0x08, 4), + MUX_GATE_CLR_SET_UPD_INDEXED(CLK_TOP_EDP, "top_edp", + edp_parents, edp_parents_idx, 0x08C, 0x090, 0x094, + 8, 4, 15, 0x08, 5), MUX_GATE_CLR_SET_UPD(CLK_TOP_DPI, "top_dpi", dpi_parents, 0x08C, 0x090, 0x094, 16, 4, 23, 0x08, 6), MUX_GATE_CLR_SET_UPD(CLK_TOP_DISP_PWM0, "top_disp_pwm0", diff --git a/drivers/clk/mediatek/clk-mt8195-topckgen.c b/drivers/clk/mediatek/clk-mt8195-topckgen.c index 5c426a1c94c7f9..8f713a3341a96a 100644 --- a/drivers/clk/mediatek/clk-mt8195-topckgen.c +++ b/drivers/clk/mediatek/clk-mt8195-topckgen.c @@ -415,17 +415,28 @@ static const char * const pwrmcu_parents[] = { "mainpll_d4_d2" }; +/* + * Both DP/eDP can be parented to TVDPLL1 and TVDPLL2, but we force using + * TVDPLL1 on eDP and TVDPLL2 on DP to avoid changing the "other" PLL rate + * in dual output case, which would lead to corruption of functionality loss. + */ static const char * const dp_parents[] = { "clk26m", - "tvdpll1_d2", "tvdpll2_d2", - "tvdpll1_d4", "tvdpll2_d4", - "tvdpll1_d8", "tvdpll2_d8", - "tvdpll1_d16", "tvdpll2_d16" }; +static const u8 dp_parents_idx[] = { 0, 2, 4, 6, 8 }; + +static const char * const edp_parents[] = { + "clk26m", + "tvdpll1_d2", + "tvdpll1_d4", + "tvdpll1_d8", + "tvdpll1_d16" +}; +static const u8 edp_parents_idx[] = { 0, 1, 3, 5, 7 }; static const char * const disp_pwm_parents[] = { "clk26m", @@ -957,11 +968,11 @@ static const struct mtk_mux top_mtk_muxes[] = { MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_PWRMCU, "top_pwrmcu", pwrmcu_parents, 0x08C, 0x090, 0x094, 16, 3, 23, 0x08, 6, CLK_IS_CRITICAL | CLK_SET_RATE_PARENT), - MUX_GATE_CLR_SET_UPD(CLK_TOP_DP, "top_dp", - dp_parents, 0x08C, 0x090, 0x094, 24, 4, 31, 0x08, 7), + MUX_GATE_CLR_SET_UPD_INDEXED(CLK_TOP_DP, "top_dp", + dp_parents, dp_parents_idx, 0x08C, 0x090, 0x094, 24, 4, 31, 0x08, 7), /* CLK_CFG_10 */ - MUX_GATE_CLR_SET_UPD(CLK_TOP_EDP, "top_edp", - dp_parents, 0x098, 0x09C, 0x0A0, 0, 4, 7, 0x08, 8), + MUX_GATE_CLR_SET_UPD_INDEXED(CLK_TOP_EDP, "top_edp", + edp_parents, edp_parents_idx, 0x098, 0x09C, 0x0A0, 0, 4, 7, 0x08, 8), MUX_GATE_CLR_SET_UPD(CLK_TOP_DPI, "top_dpi", dp_parents, 0x098, 0x09C, 0x0A0, 8, 4, 15, 0x08, 9), MUX_GATE_CLR_SET_UPD(CLK_TOP_DISP_PWM0, "top_disp_pwm0", diff --git a/drivers/clk/mediatek/clk-mux.c b/drivers/clk/mediatek/clk-mux.c index c93bc7f926e5d4..60990296450bbb 100644 --- a/drivers/clk/mediatek/clk-mux.c +++ b/drivers/clk/mediatek/clk-mux.c @@ -89,6 +89,17 @@ static u8 mtk_clk_mux_get_parent(struct clk_hw *hw) regmap_read(mux->regmap, mux->data->mux_ofs, &val); val = (val >> mux->data->mux_shift) & mask; + if (mux->data->parent_index) { + int i; + + for (i = 0; i < mux->data->num_parents; i++) + if (mux->data->parent_index[i] == val) + return i; + + /* Not found: return an impossible index to generate error */ + return mux->data->num_parents + 1; + } + return val; } @@ -104,6 +115,9 @@ static int mtk_clk_mux_set_parent_setclr_lock(struct clk_hw *hw, u8 index) else __acquire(mux->lock); + if (mux->data->parent_index) + index = mux->data->parent_index[index]; + regmap_read(mux->regmap, mux->data->mux_ofs, &orig); val = (orig & ~(mask << mux->data->mux_shift)) | (index << mux->data->mux_shift); diff --git a/drivers/clk/mediatek/clk-mux.h b/drivers/clk/mediatek/clk-mux.h index 7ecb963b0ec688..943ad1d7ce4bed 100644 --- a/drivers/clk/mediatek/clk-mux.h +++ b/drivers/clk/mediatek/clk-mux.h @@ -21,6 +21,7 @@ struct mtk_mux { int id; const char *name; const char * const *parent_names; + const u8 *parent_index; unsigned int flags; u32 mux_ofs; @@ -37,9 +38,10 @@ struct mtk_mux { signed char num_parents; }; -#define GATE_CLR_SET_UPD_FLAGS(_id, _name, _parents, _mux_ofs, \ - _mux_set_ofs, _mux_clr_ofs, _shift, _width, \ - _gate, _upd_ofs, _upd, _flags, _ops) { \ +#define __GATE_CLR_SET_UPD_FLAGS(_id, _name, _parents, _paridx, \ + _num_parents, _mux_ofs, _mux_set_ofs, \ + _mux_clr_ofs, _shift, _width, _gate, _upd_ofs, \ + _upd, _flags, _ops) { \ .id = _id, \ .name = _name, \ .mux_ofs = _mux_ofs, \ @@ -51,11 +53,28 @@ struct mtk_mux { .gate_shift = _gate, \ .upd_shift = _upd, \ .parent_names = _parents, \ - .num_parents = ARRAY_SIZE(_parents), \ + .parent_index = _paridx, \ + .num_parents = _num_parents, \ .flags = _flags, \ .ops = &_ops, \ } +#define GATE_CLR_SET_UPD_FLAGS(_id, _name, _parents, _mux_ofs, \ + _mux_set_ofs, _mux_clr_ofs, _shift, _width, \ + _gate, _upd_ofs, _upd, _flags, _ops) \ + __GATE_CLR_SET_UPD_FLAGS(_id, _name, _parents, \ + NULL, ARRAY_SIZE(_parents), _mux_ofs, \ + _mux_set_ofs, _mux_clr_ofs, _shift, _width, \ + _gate, _upd_ofs, _upd, _flags, _ops) \ + +#define GATE_CLR_SET_UPD_FLAGS_INDEXED(_id, _name, _parents, _paridx, \ + _mux_ofs, _mux_set_ofs, _mux_clr_ofs, _shift, \ + _width, _gate, _upd_ofs, _upd, _flags, _ops) \ + __GATE_CLR_SET_UPD_FLAGS(_id, _name, _parents, \ + _paridx, ARRAY_SIZE(_paridx), _mux_ofs, \ + _mux_set_ofs, _mux_clr_ofs, _shift, _width, \ + _gate, _upd_ofs, _upd, _flags, _ops) \ + extern const struct clk_ops mtk_mux_clr_set_upd_ops; extern const struct clk_ops mtk_mux_gate_clr_set_upd_ops; @@ -67,6 +86,14 @@ extern const struct clk_ops mtk_mux_gate_clr_set_upd_ops; _gate, _upd_ofs, _upd, _flags, \ mtk_mux_gate_clr_set_upd_ops) +#define MUX_GATE_CLR_SET_UPD_FLAGS_INDEXED(_id, _name, _parents, \ + _paridx, _mux_ofs, _mux_set_ofs, _mux_clr_ofs, \ + _shift, _width, _gate, _upd_ofs, _upd, _flags) \ + GATE_CLR_SET_UPD_FLAGS_INDEXED(_id, _name, _parents, \ + _paridx, _mux_ofs, _mux_set_ofs, _mux_clr_ofs, \ + _shift, _width, _gate, _upd_ofs, _upd, _flags, \ + mtk_mux_gate_clr_set_upd_ops) + #define MUX_GATE_CLR_SET_UPD(_id, _name, _parents, _mux_ofs, \ _mux_set_ofs, _mux_clr_ofs, _shift, _width, \ _gate, _upd_ofs, _upd) \ @@ -75,6 +102,14 @@ extern const struct clk_ops mtk_mux_gate_clr_set_upd_ops; _width, _gate, _upd_ofs, _upd, \ CLK_SET_RATE_PARENT) +#define MUX_GATE_CLR_SET_UPD_INDEXED(_id, _name, _parents, _paridx, \ + _mux_ofs, _mux_set_ofs, _mux_clr_ofs, _shift, \ + _width, _gate, _upd_ofs, _upd) \ + MUX_GATE_CLR_SET_UPD_FLAGS_INDEXED(_id, _name, \ + _parents, _paridx, _mux_ofs, _mux_set_ofs, \ + _mux_clr_ofs, _shift, _width, _gate, _upd_ofs, \ + _upd, CLK_SET_RATE_PARENT) + #define MUX_CLR_SET_UPD(_id, _name, _parents, _mux_ofs, \ _mux_set_ofs, _mux_clr_ofs, _shift, _width, \ _upd_ofs, _upd) \ diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c index 513ab6b1b32292..ce453e1718e535 100644 --- a/drivers/clk/mediatek/clk-pll.c +++ b/drivers/clk/mediatek/clk-pll.c @@ -23,7 +23,7 @@ #define CON0_BASE_EN BIT(0) #define CON0_PWR_ON BIT(0) #define CON0_ISO_EN BIT(1) -#define PCW_CHG_MASK BIT(31) +#define PCW_CHG_BIT 31 #define AUDPLL_TUNER_EN BIT(31) @@ -114,7 +114,8 @@ static void mtk_pll_set_rate_regs(struct mtk_clk_pll *pll, u32 pcw, pll->data->pcw_shift); val |= pcw << pll->data->pcw_shift; writel(val, pll->pcw_addr); - chg = readl(pll->pcw_chg_addr) | PCW_CHG_MASK; + chg = readl(pll->pcw_chg_addr) | + BIT(pll->data->pcw_chg_bit ? : PCW_CHG_BIT); writel(chg, pll->pcw_chg_addr); if (pll->tuner_addr) writel(val + 1, pll->tuner_addr); diff --git a/drivers/clk/mediatek/clk-pll.h b/drivers/clk/mediatek/clk-pll.h index f17278ff15d78f..285c8db958b39e 100644 --- a/drivers/clk/mediatek/clk-pll.h +++ b/drivers/clk/mediatek/clk-pll.h @@ -48,6 +48,7 @@ struct mtk_pll_data { const char *parent_name; u32 en_reg; u8 pll_en_bit; /* Assume 0, indicates BIT(0) by default */ + u8 pcw_chg_bit; }; /* diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c index f373a8d48b1d3b..90f4c6103014c1 100644 --- a/drivers/clk/meson/g12a.c +++ b/drivers/clk/meson/g12a.c @@ -3549,6 +3549,22 @@ static struct clk_regmap g12a_cts_encp_sel = { }, }; +static struct clk_regmap g12a_cts_encl_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_VIID_CLK_DIV, + .mask = 0xf, + .shift = 12, + .table = mux_table_cts_sel, + }, + .hw.init = &(struct clk_init_data){ + .name = "cts_encl_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = g12a_cts_parent_hws, + .num_parents = ARRAY_SIZE(g12a_cts_parent_hws), + .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE, + }, +}; + static struct clk_regmap g12a_cts_vdac_sel = { .data = &(struct clk_regmap_mux_data){ .offset = HHI_VIID_CLK_DIV, @@ -3628,6 +3644,22 @@ static struct clk_regmap g12a_cts_encp = { }, }; +static struct clk_regmap g12a_cts_encl = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_VID_CLK_CNTL2, + .bit_idx = 3, + }, + .hw.init = &(struct clk_init_data) { + .name = "cts_encl", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_cts_encl_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + static struct clk_regmap g12a_cts_vdac = { .data = &(struct clk_regmap_gate_data){ .offset = HHI_VID_CLK_CNTL2, @@ -3722,6 +3754,66 @@ static struct clk_regmap g12a_mipi_dsi_pxclk = { }, }; +/* MIPI ISP Clocks */ + +static const struct clk_parent_data g12b_mipi_isp_parent_data[] = { + { .fw_name = "xtal", }, + { .hw = &g12a_gp0_pll.hw }, + { .hw = &g12a_hifi_pll.hw }, + { .hw = &g12a_fclk_div2p5.hw }, + { .hw = &g12a_fclk_div3.hw }, + { .hw = &g12a_fclk_div4.hw }, + { .hw = &g12a_fclk_div5.hw }, + { .hw = &g12a_fclk_div7.hw }, +}; + +static struct clk_regmap g12b_mipi_isp_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_ISP_CLK_CNTL, + .mask = 7, + .shift = 9, + }, + .hw.init = &(struct clk_init_data){ + .name = "mipi_isp_sel", + .ops = &clk_regmap_mux_ops, + .parent_data = g12b_mipi_isp_parent_data, + .num_parents = ARRAY_SIZE(g12b_mipi_isp_parent_data), + }, +}; + +static struct clk_regmap g12b_mipi_isp_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_ISP_CLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "mipi_isp_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_mipi_isp_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12b_mipi_isp = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_ISP_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "mipi_isp", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12b_mipi_isp_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + /* HDMI Clocks */ static const struct clk_parent_data g12a_hdmi_parent_data[] = { @@ -4214,9 +4306,12 @@ static MESON_GATE(g12a_htx_hdcp22, HHI_GCLK_MPEG2, 3); static MESON_GATE(g12a_htx_pclk, HHI_GCLK_MPEG2, 4); static MESON_GATE(g12a_bt656, HHI_GCLK_MPEG2, 6); static MESON_GATE(g12a_usb1_to_ddr, HHI_GCLK_MPEG2, 8); +static MESON_GATE(g12b_mipi_isp_gate, HHI_GCLK_MPEG2, 17); static MESON_GATE(g12a_mmc_pclk, HHI_GCLK_MPEG2, 11); static MESON_GATE(g12a_uart2, HHI_GCLK_MPEG2, 15); static MESON_GATE(g12a_vpu_intr, HHI_GCLK_MPEG2, 25); +static MESON_GATE(g12b_csi_phy1, HHI_GCLK_MPEG2, 28); +static MESON_GATE(g12b_csi_phy0, HHI_GCLK_MPEG2, 29); static MESON_GATE(g12a_gic, HHI_GCLK_MPEG2, 30); static MESON_GATE(g12a_vclk2_venci0, HHI_GCLK_OTHER, 1); @@ -4407,10 +4502,12 @@ static struct clk_hw *g12a_hw_clks[] = { [CLKID_VCLK2_DIV12] = &g12a_vclk2_div12.hw, [CLKID_CTS_ENCI_SEL] = &g12a_cts_enci_sel.hw, [CLKID_CTS_ENCP_SEL] = &g12a_cts_encp_sel.hw, + [CLKID_CTS_ENCL_SEL] = &g12a_cts_encl_sel.hw, [CLKID_CTS_VDAC_SEL] = &g12a_cts_vdac_sel.hw, [CLKID_HDMI_TX_SEL] = &g12a_hdmi_tx_sel.hw, [CLKID_CTS_ENCI] = &g12a_cts_enci.hw, [CLKID_CTS_ENCP] = &g12a_cts_encp.hw, + [CLKID_CTS_ENCL] = &g12a_cts_encl.hw, [CLKID_CTS_VDAC] = &g12a_cts_vdac.hw, [CLKID_HDMI_TX] = &g12a_hdmi_tx.hw, [CLKID_HDMI_SEL] = &g12a_hdmi_sel.hw, @@ -4632,10 +4729,12 @@ static struct clk_hw *g12b_hw_clks[] = { [CLKID_VCLK2_DIV12] = &g12a_vclk2_div12.hw, [CLKID_CTS_ENCI_SEL] = &g12a_cts_enci_sel.hw, [CLKID_CTS_ENCP_SEL] = &g12a_cts_encp_sel.hw, + [CLKID_CTS_ENCL_SEL] = &g12a_cts_encl_sel.hw, [CLKID_CTS_VDAC_SEL] = &g12a_cts_vdac_sel.hw, [CLKID_HDMI_TX_SEL] = &g12a_hdmi_tx_sel.hw, [CLKID_CTS_ENCI] = &g12a_cts_enci.hw, [CLKID_CTS_ENCP] = &g12a_cts_encp.hw, + [CLKID_CTS_ENCL] = &g12a_cts_encl.hw, [CLKID_CTS_VDAC] = &g12a_cts_vdac.hw, [CLKID_HDMI_TX] = &g12a_hdmi_tx.hw, [CLKID_HDMI_SEL] = &g12a_hdmi_sel.hw, @@ -4729,6 +4828,12 @@ static struct clk_hw *g12b_hw_clks[] = { [CLKID_MIPI_DSI_PXCLK_SEL] = &g12a_mipi_dsi_pxclk_sel.hw, [CLKID_MIPI_DSI_PXCLK_DIV] = &g12a_mipi_dsi_pxclk_div.hw, [CLKID_MIPI_DSI_PXCLK] = &g12a_mipi_dsi_pxclk.hw, + [CLKID_MIPI_ISP_SEL] = &g12b_mipi_isp_sel.hw, + [CLKID_MIPI_ISP_DIV] = &g12b_mipi_isp_div.hw, + [CLKID_MIPI_ISP] = &g12b_mipi_isp.hw, + [CLKID_MIPI_ISP_GATE] = &g12b_mipi_isp_gate.hw, + [CLKID_MIPI_ISP_CSI_PHY0] = &g12b_csi_phy0.hw, + [CLKID_MIPI_ISP_CSI_PHY1] = &g12b_csi_phy1.hw, }; static struct clk_hw *sm1_hw_clks[] = { @@ -4892,10 +4997,12 @@ static struct clk_hw *sm1_hw_clks[] = { [CLKID_VCLK2_DIV12] = &g12a_vclk2_div12.hw, [CLKID_CTS_ENCI_SEL] = &g12a_cts_enci_sel.hw, [CLKID_CTS_ENCP_SEL] = &g12a_cts_encp_sel.hw, + [CLKID_CTS_ENCL_SEL] = &g12a_cts_encl_sel.hw, [CLKID_CTS_VDAC_SEL] = &g12a_cts_vdac_sel.hw, [CLKID_HDMI_TX_SEL] = &g12a_hdmi_tx_sel.hw, [CLKID_CTS_ENCI] = &g12a_cts_enci.hw, [CLKID_CTS_ENCP] = &g12a_cts_encp.hw, + [CLKID_CTS_ENCL] = &g12a_cts_encl.hw, [CLKID_CTS_VDAC] = &g12a_cts_vdac.hw, [CLKID_HDMI_TX] = &g12a_hdmi_tx.hw, [CLKID_HDMI_SEL] = &g12a_hdmi_sel.hw, @@ -5123,10 +5230,12 @@ static struct clk_regmap *const g12a_clk_regmaps[] = { &g12a_vclk2_div12_en, &g12a_cts_enci_sel, &g12a_cts_encp_sel, + &g12a_cts_encl_sel, &g12a_cts_vdac_sel, &g12a_hdmi_tx_sel, &g12a_cts_enci, &g12a_cts_encp, + &g12a_cts_encl, &g12a_cts_vdac, &g12a_hdmi_tx, &g12a_hdmi_sel, @@ -5221,6 +5330,12 @@ static struct clk_regmap *const g12a_clk_regmaps[] = { &g12a_mipi_dsi_pxclk_sel, &g12a_mipi_dsi_pxclk_div, &g12a_mipi_dsi_pxclk, + &g12b_mipi_isp_sel, + &g12b_mipi_isp_div, + &g12b_mipi_isp, + &g12b_mipi_isp_gate, + &g12b_csi_phy1, + &g12b_csi_phy0, }; static const struct reg_sequence g12a_init_regs[] = { diff --git a/drivers/clk/meson/g12a.h b/drivers/clk/meson/g12a.h index f11ee3c598497c..27df99c4565aed 100644 --- a/drivers/clk/meson/g12a.h +++ b/drivers/clk/meson/g12a.h @@ -70,6 +70,7 @@ #define HHI_MALI_CLK_CNTL 0x1b0 #define HHI_VPU_CLKC_CNTL 0x1b4 #define HHI_VPU_CLK_CNTL 0x1bC +#define HHI_ISP_CLK_CNTL 0x1C0 #define HHI_NNA_CLK_CNTL 0x1C8 #define HHI_HDMI_CLK_CNTL 0x1CC #define HHI_VDEC_CLK_CNTL 0x1E0 diff --git a/drivers/clk/microchip/clk-mpfs-ccc.c b/drivers/clk/microchip/clk-mpfs-ccc.c index bce61c45e96748..3a3ea2d142f8a2 100644 --- a/drivers/clk/microchip/clk-mpfs-ccc.c +++ b/drivers/clk/microchip/clk-mpfs-ccc.c @@ -4,8 +4,8 @@ * * Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries */ -#include "asm-generic/errno-base.h" #include +#include #include #include #include diff --git a/drivers/clk/mmp/clk-of-pxa168.c b/drivers/clk/mmp/clk-of-pxa168.c index fb0df64cf053c4..c5a7ba1deaa3a1 100644 --- a/drivers/clk/mmp/clk-of-pxa168.c +++ b/drivers/clk/mmp/clk-of-pxa168.c @@ -308,18 +308,21 @@ static void __init pxa168_clk_init(struct device_node *np) pxa_unit->mpmu_base = of_iomap(np, 0); if (!pxa_unit->mpmu_base) { pr_err("failed to map mpmu registers\n"); + kfree(pxa_unit); return; } pxa_unit->apmu_base = of_iomap(np, 1); if (!pxa_unit->apmu_base) { pr_err("failed to map apmu registers\n"); + kfree(pxa_unit); return; } pxa_unit->apbc_base = of_iomap(np, 2); if (!pxa_unit->apbc_base) { pr_err("failed to map apbc registers\n"); + kfree(pxa_unit); return; } diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index dbc3950c596090..2a9da0939377ac 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -20,6 +20,16 @@ menuconfig COMMON_CLK_QCOM if COMMON_CLK_QCOM +config CLK_X1E80100_GCC + tristate "X1E80100 Global Clock Controller" + depends on ARM64 || COMPILE_TEST + select QCOM_GDSC + help + Support for the global clock controller on Qualcomm Technologies, Inc + X1E80100 devices. + Say Y if you want to use peripheral devices such as UART, SPI, I2C, + USB, UFS, SD/eMMC, PCIe, etc. + config QCOM_A53PLL tristate "MSM8916 A53 PLL" help @@ -427,6 +437,15 @@ config SC_CAMCC_7280 Say Y if you want to support camera devices and functionality such as capturing pictures. +config SC_CAMCC_8280XP + tristate "SC8280XP Camera Clock Controller" + select SC_GCC_8280XP + help + Support for the camera clock controller on Qualcomm Technologies, Inc + SC8280XP devices. + Say Y if you want to support camera devices and functionality such as + capturing pictures. + config SC_DISPCC_7180 tristate "SC7180 Display Clock Controller" depends on ARM64 || COMPILE_TEST @@ -668,6 +687,15 @@ config QDU_GCC_1000 QRU1000 devices. Say Y if you want to use peripheral devices such as UART, SPI, I2C, USB, SD, PCIe, etc. +config QDU_ECPRICC_1000 + tristate "QDU1000/QRU1000 ECPRI Clock Controller" + depends on ARM64 || COMPILE_TEST + select QDU_GCC_1000 + help + Support for the ECPRI clock controller on QDU1000 and + QRU1000 devices. Say Y if you want to support the ECPRI + clock controller functionality such as Ethernet. + config SDM_GCC_845 tristate "SDM845/SDM670 Global Clock Controller" depends on ARM64 || COMPILE_TEST @@ -843,6 +871,16 @@ config SM_DISPCC_8550 Say Y if you want to support display devices and functionality such as splash screen. +config SM_DISPCC_8650 + tristate "SM8650 Display Clock Controller" + depends on ARM64 || COMPILE_TEST + select SM_GCC_8650 + help + Support for the display clock controller on Qualcomm Technologies, Inc + SM8650 devices. + Say Y if you want to support display devices and functionality such as + splash screen. + config SM_GCC_4450 tristate "SM4450 Global Clock Controller" depends on ARM64 || COMPILE_TEST @@ -939,6 +977,15 @@ config SM_GCC_8550 Say Y if you want to use peripheral devices such as UART, SPI, I2C, USB, SD/UFS, PCIe etc. +config SM_GCC_8650 + tristate "SM8650 Global Clock Controller" + depends on ARM64 || COMPILE_TEST + select QCOM_GDSC + help + Support for the global clock controller on SM8650 devices. + Say Y if you want to use peripheral devices such as UART, + SPI, I2C, USB, SD/UFS, PCIe etc. + config SM_GPUCC_6115 tristate "SM6115 Graphics Clock Controller" select SM_GCC_6115 @@ -1020,6 +1067,14 @@ config SM_GPUCC_8550 Say Y if you want to support graphics controller devices and functionality such as 3D graphics. +config SM_GPUCC_8650 + tristate "SM8650 Graphics Clock Controller" + select SM_GCC_8650 + help + Support for the graphics clock controller on SM8650 devices. + 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" depends on ARM64 || COMPILE_TEST @@ -1028,6 +1083,14 @@ config SM_TCSRCC_8550 Support for the TCSR clock controller on SM8550 devices. Say Y if you want to use peripheral devices such as SD/UFS. +config SM_TCSRCC_8650 + tristate "SM8650 TCSR Clock Controller" + depends on ARM64 || COMPILE_TEST + select QCOM_GDSC + help + Support for the TCSR clock controller on SM8650 devices. + Say Y if you want to use peripheral devices such as SD/UFS. + config SM_VIDEOCC_8150 tristate "SM8150 Video Clock Controller" depends on ARM64 || COMPILE_TEST diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 17edd73f9839fc..582e06dc1d939e 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -21,6 +21,7 @@ clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o obj-$(CONFIG_CLK_GFM_LPASS_SM8250) += lpass-gfm-sm8250.o +obj-$(CONFIG_CLK_X1E80100_GCC) += gcc-x1e80100.o obj-$(CONFIG_IPQ_APSS_PLL) += apss-ipq-pll.o obj-$(CONFIG_IPQ_APSS_6018) += apss-ipq6018.o obj-$(CONFIG_IPQ_GCC_4019) += gcc-ipq4019.o @@ -65,9 +66,11 @@ 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_ECPRICC_1000) += ecpricc-qdu1000.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_CAMCC_8280XP) += camcc-sc8280xp.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 @@ -110,6 +113,7 @@ 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_DISPCC_8650) += dispcc-sm8650.o obj-$(CONFIG_SM_GCC_4450) += gcc-sm4450.o obj-$(CONFIG_SM_GCC_6115) += gcc-sm6115.o obj-$(CONFIG_SM_GCC_6125) += gcc-sm6125.o @@ -121,6 +125,7 @@ obj-$(CONFIG_SM_GCC_8250) += gcc-sm8250.o obj-$(CONFIG_SM_GCC_8350) += gcc-sm8350.o obj-$(CONFIG_SM_GCC_8450) += gcc-sm8450.o obj-$(CONFIG_SM_GCC_8550) += gcc-sm8550.o +obj-$(CONFIG_SM_GCC_8650) += gcc-sm8650.o obj-$(CONFIG_SM_GPUCC_6115) += gpucc-sm6115.o obj-$(CONFIG_SM_GPUCC_6125) += gpucc-sm6125.o obj-$(CONFIG_SM_GPUCC_6350) += gpucc-sm6350.o @@ -130,7 +135,9 @@ obj-$(CONFIG_SM_GPUCC_8250) += gpucc-sm8250.o obj-$(CONFIG_SM_GPUCC_8350) += gpucc-sm8350.o obj-$(CONFIG_SM_GPUCC_8450) += gpucc-sm8450.o obj-$(CONFIG_SM_GPUCC_8550) += gpucc-sm8550.o +obj-$(CONFIG_SM_GPUCC_8650) += gpucc-sm8650.o obj-$(CONFIG_SM_TCSRCC_8550) += tcsrcc-sm8550.o +obj-$(CONFIG_SM_TCSRCC_8650) += tcsrcc-sm8650.o obj-$(CONFIG_SM_VIDEOCC_8150) += videocc-sm8150.o obj-$(CONFIG_SM_VIDEOCC_8250) += videocc-sm8250.o obj-$(CONFIG_SM_VIDEOCC_8350) += videocc-sm8350.o diff --git a/drivers/clk/qcom/apss-ipq-pll.c b/drivers/clk/qcom/apss-ipq-pll.c index 41279e5437a620..678b805f13d455 100644 --- a/drivers/clk/qcom/apss-ipq-pll.c +++ b/drivers/clk/qcom/apss-ipq-pll.c @@ -73,6 +73,20 @@ static struct clk_alpha_pll ipq_pll_stromer_plus = { }, }; +static const struct alpha_pll_config ipq5018_pll_config = { + .l = 0x32, + .config_ctl_val = 0x4001075b, + .config_ctl_hi_val = 0x304, + .main_output_mask = BIT(0), + .aux_output_mask = BIT(1), + .early_output_mask = BIT(3), + .alpha_en_mask = BIT(24), + .status_val = 0x3, + .status_mask = GENMASK(10, 8), + .lock_det = BIT(2), + .test_ctl_hi_val = 0x00400003, +}; + static const struct alpha_pll_config ipq5332_pll_config = { .l = 0x2d, .config_ctl_val = 0x4001075b, @@ -129,6 +143,12 @@ struct apss_pll_data { const struct alpha_pll_config *pll_config; }; +static const struct apss_pll_data ipq5018_pll_data = { + .pll_type = CLK_ALPHA_PLL_TYPE_STROMER_PLUS, + .pll = &ipq_pll_stromer_plus, + .pll_config = &ipq5018_pll_config, +}; + static struct apss_pll_data ipq5332_pll_data = { .pll_type = CLK_ALPHA_PLL_TYPE_STROMER_PLUS, .pll = &ipq_pll_stromer_plus, @@ -195,6 +215,7 @@ static int apss_ipq_pll_probe(struct platform_device *pdev) } static const struct of_device_id apss_ipq_pll_match_table[] = { + { .compatible = "qcom,ipq5018-a53pll", .data = &ipq5018_pll_data }, { .compatible = "qcom,ipq5332-a53pll", .data = &ipq5332_pll_data }, { .compatible = "qcom,ipq6018-a53pll", .data = &ipq6018_pll_data }, { .compatible = "qcom,ipq8074-a53pll", .data = &ipq8074_pll_data }, diff --git a/drivers/clk/qcom/camcc-sc8280xp.c b/drivers/clk/qcom/camcc-sc8280xp.c new file mode 100644 index 00000000000000..3dcd79b0151517 --- /dev/null +++ b/drivers/clk/qcom/camcc-sc8280xp.c @@ -0,0 +1,3045 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023, Linaro Ltd. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "clk-alpha-pll.h" +#include "clk-branch.h" +#include "clk-rcg.h" +#include "clk-regmap.h" +#include "common.h" +#include "gdsc.h" +#include "reset.h" + +enum { + DT_IFACE, + DT_BI_TCXO, + DT_BI_TCXO_AO, + DT_SLEEP_CLK, +}; + +enum { + P_BI_TCXO, + P_CAMCC_PLL0_OUT_EVEN, + P_CAMCC_PLL0_OUT_MAIN, + P_CAMCC_PLL0_OUT_ODD, + P_CAMCC_PLL1_OUT_EVEN, + P_CAMCC_PLL2_OUT_AUX, + P_CAMCC_PLL2_OUT_EARLY, + P_CAMCC_PLL3_OUT_EVEN, + P_CAMCC_PLL4_OUT_EVEN, + P_CAMCC_PLL5_OUT_EVEN, + P_CAMCC_PLL6_OUT_EVEN, + P_CAMCC_PLL7_OUT_EVEN, + P_CAMCC_PLL7_OUT_ODD, + P_SLEEP_CLK, +}; + +static struct pll_vco lucid_vco[] = { + { 249600000, 1800000000, 0 }, +}; + +static struct pll_vco zonda_vco[] = { + { 595200000, 3600000000, 0 }, +}; + +static struct alpha_pll_config camcc_pll0_config = { + .l = 0x3e, + .alpha = 0x8000, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00002261, + .config_ctl_hi1_val = 0x2a9a699c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000000, + .test_ctl_hi1_val = 0x01800000, + .user_ctl_val = 0x00003100, + .user_ctl_hi_val = 0x00000805, + .user_ctl_hi1_val = 0x00000000, +}; + +static struct clk_alpha_pll camcc_pll0 = { + .offset = 0x0, + .vco_table = lucid_vco, + .num_vco = ARRAY_SIZE(lucid_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .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_lucid_5lpe_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_LUCID], + .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_lucid_ops, + }, +}; + +static const struct clk_div_table post_div_table_camcc_pll0_out_odd[] = { + { 0x3, 3 }, +}; + +static struct clk_alpha_pll_postdiv camcc_pll0_out_odd = { + .offset = 0x0, + .post_div_shift = 12, + .post_div_table = post_div_table_camcc_pll0_out_odd, + .num_post_div = ARRAY_SIZE(post_div_table_camcc_pll0_out_odd), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_pll0_out_odd", + .parent_hws = (const struct clk_hw*[]){ + &camcc_pll0.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ops, + }, +}; + +static struct alpha_pll_config camcc_pll1_config = { + .l = 0x21, + .alpha = 0x5555, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00002261, + .config_ctl_hi1_val = 0x2a9a699c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000000, + .test_ctl_hi1_val = 0x01800000, + .user_ctl_val = 0x00000100, + .user_ctl_hi_val = 0x00000805, + .user_ctl_hi1_val = 0x00000000, +}; + +static struct clk_alpha_pll camcc_pll1 = { + .offset = 0x1000, + .vco_table = lucid_vco, + .num_vco = ARRAY_SIZE(lucid_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .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_lucid_5lpe_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_LUCID], + .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_lucid_ops, + }, +}; + +static struct alpha_pll_config camcc_pll2_config = { + .l = 0x32, + .alpha = 0x0, + .config_ctl_val = 0x08200800, + .config_ctl_hi_val = 0x05028011, + .config_ctl_hi1_val = 0x08000000, +}; + +static struct clk_alpha_pll camcc_pll2 = { + .offset = 0x2000, + .vco_table = zonda_vco, + .num_vco = ARRAY_SIZE(zonda_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_ZONDA], + .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_zonda_ops, + }, + }, +}; + +static struct alpha_pll_config camcc_pll3_config = { + .l = 0x29, + .alpha = 0xaaaa, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00002261, + .config_ctl_hi1_val = 0x2a9a699c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000000, + .test_ctl_hi1_val = 0x01800000, + .user_ctl_val = 0x00000100, + .user_ctl_hi_val = 0x00000805, + .user_ctl_hi1_val = 0x00000000, +}; + +static struct clk_alpha_pll camcc_pll3 = { + .offset = 0x3000, + .vco_table = lucid_vco, + .num_vco = ARRAY_SIZE(lucid_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .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_lucid_5lpe_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_camcc_pll3_out_even[] = { + { 0x1, 2 }, +}; + +static struct clk_alpha_pll_postdiv camcc_pll3_out_even = { + .offset = 0x3000, + .post_div_shift = 8, + .post_div_table = post_div_table_camcc_pll3_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_camcc_pll3_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_pll3_out_even", + .parent_hws = (const struct clk_hw*[]){ + &camcc_pll3.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ops, + }, +}; + +static struct alpha_pll_config camcc_pll4_config = { + .l = 0x29, + .alpha = 0xaaaa, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00002261, + .config_ctl_hi1_val = 0x2a9a699c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000000, + .test_ctl_hi1_val = 0x01800000, + .user_ctl_val = 0x00000100, + .user_ctl_hi_val = 0x00000805, + .user_ctl_hi1_val = 0x00000000, +}; + +static struct clk_alpha_pll camcc_pll4 = { + .offset = 0x4000, + .vco_table = lucid_vco, + .num_vco = ARRAY_SIZE(lucid_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "camcc_pll4", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_5lpe_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_camcc_pll4_out_even[] = { + { 0x1, 2 }, +}; + +static struct clk_alpha_pll_postdiv camcc_pll4_out_even = { + .offset = 0x4000, + .post_div_shift = 8, + .post_div_table = post_div_table_camcc_pll4_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_camcc_pll4_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_pll4_out_even", + .parent_hws = (const struct clk_hw*[]){ + &camcc_pll4.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ops, + }, +}; + +static struct alpha_pll_config camcc_pll5_config = { + .l = 0x29, + .alpha = 0xaaaa, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00002261, + .config_ctl_hi1_val = 0x2a9a699c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000000, + .test_ctl_hi1_val = 0x01800000, + .user_ctl_val = 0x00000100, + .user_ctl_hi_val = 0x00000805, + .user_ctl_hi1_val = 0x00000000, +}; + +static struct clk_alpha_pll camcc_pll5 = { + .offset = 0x10000, + .vco_table = lucid_vco, + .num_vco = ARRAY_SIZE(lucid_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "camcc_pll5", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_5lpe_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_camcc_pll5_out_even[] = { + { 0x1, 2 }, +}; + +static struct clk_alpha_pll_postdiv camcc_pll5_out_even = { + .offset = 0x10000, + .post_div_shift = 8, + .post_div_table = post_div_table_camcc_pll5_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_camcc_pll5_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_pll5_out_even", + .parent_hws = (const struct clk_hw*[]){ + &camcc_pll5.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ops, + }, +}; + +static struct alpha_pll_config camcc_pll6_config = { + .l = 0x29, + .alpha = 0xaaaa, + .config_ctl_val = 0x20486699, + .config_ctl_hi_val = 0x00002261, + .config_ctl_hi1_val = 0x2a9a699c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000000, + .test_ctl_hi1_val = 0x01800000, + .user_ctl_val = 0x00000100, + .user_ctl_hi_val = 0x00000805, + .user_ctl_hi1_val = 0x00000000, +}; + +static struct clk_alpha_pll camcc_pll6 = { + .offset = 0x11000, + .vco_table = lucid_vco, + .num_vco = ARRAY_SIZE(lucid_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "camcc_pll6", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_5lpe_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_camcc_pll6_out_even[] = { + { 0x1, 2 }, +}; + +static struct clk_alpha_pll_postdiv camcc_pll6_out_even = { + .offset = 0x11000, + .post_div_shift = 8, + .post_div_table = post_div_table_camcc_pll6_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_camcc_pll6_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_pll6_out_even", + .parent_hws = (const struct clk_hw*[]){ + &camcc_pll6.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ops, + }, +}; + +static struct alpha_pll_config camcc_pll7_config = { + .l = 0x32, + .alpha = 0x0, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00002261, + .config_ctl_hi1_val = 0x2a9a699c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000000, + .test_ctl_hi1_val = 0x01800000, + .user_ctl_val = 0x00003100, + .user_ctl_hi_val = 0x00000805, + .user_ctl_hi1_val = 0x00000000, +}; + +static struct clk_alpha_pll camcc_pll7 = { + .offset = 0x12000, + .vco_table = lucid_vco, + .num_vco = ARRAY_SIZE(lucid_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "camcc_pll7", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_5lpe_ops, + }, + }, +}; + +static const struct clk_div_table post_div_table_camcc_pll7_out_even[] = { + { 0x1, 2 }, +}; + +static struct clk_alpha_pll_postdiv camcc_pll7_out_even = { + .offset = 0x12000, + .post_div_shift = 8, + .post_div_table = post_div_table_camcc_pll7_out_even, + .num_post_div = ARRAY_SIZE(post_div_table_camcc_pll7_out_even), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_pll7_out_even", + .parent_hws = (const struct clk_hw*[]){ + &camcc_pll7.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ops, + }, +}; + +static const struct clk_div_table post_div_table_camcc_pll7_out_odd[] = { + { 0x3, 3 }, +}; + +static struct clk_alpha_pll_postdiv camcc_pll7_out_odd = { + .offset = 0x12000, + .post_div_shift = 12, + .post_div_table = post_div_table_camcc_pll7_out_odd, + .num_post_div = ARRAY_SIZE(post_div_table_camcc_pll7_out_odd), + .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID], + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_pll7_out_odd", + .parent_hws = (const struct clk_hw*[]){ + &camcc_pll7.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_alpha_pll_postdiv_lucid_ops, + }, +}; + +static const struct parent_map camcc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_CAMCC_PLL0_OUT_MAIN, 1 }, + { P_CAMCC_PLL0_OUT_EVEN, 2 }, + { P_CAMCC_PLL0_OUT_ODD, 3 }, + { P_CAMCC_PLL7_OUT_EVEN, 5 }, +}; + +static const struct clk_parent_data camcc_parent_data_0[] = { + { .index = DT_BI_TCXO }, + { .hw = &camcc_pll0.clkr.hw }, + { .hw = &camcc_pll0_out_even.clkr.hw }, + { .hw = &camcc_pll0_out_odd.clkr.hw }, + { .hw = &camcc_pll7_out_even.clkr.hw }, +}; + +static const struct parent_map camcc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_CAMCC_PLL2_OUT_AUX, 2 }, + { P_CAMCC_PLL2_OUT_EARLY, 5 }, +}; + +static const struct clk_parent_data camcc_parent_data_1[] = { + { .index = DT_BI_TCXO }, + { .hw = &camcc_pll2.clkr.hw }, + { .hw = &camcc_pll2.clkr.hw }, +}; + +static const struct parent_map camcc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_CAMCC_PLL0_OUT_MAIN, 1 }, + { P_CAMCC_PLL0_OUT_EVEN, 2 }, + { P_CAMCC_PLL0_OUT_ODD, 3 }, + { P_CAMCC_PLL7_OUT_ODD, 4 }, + { P_CAMCC_PLL7_OUT_EVEN, 5 }, +}; + +static const struct clk_parent_data camcc_parent_data_2[] = { + { .index = DT_BI_TCXO }, + { .hw = &camcc_pll0.clkr.hw }, + { .hw = &camcc_pll0_out_even.clkr.hw }, + { .hw = &camcc_pll0_out_odd.clkr.hw }, + { .hw = &camcc_pll7_out_odd.clkr.hw }, + { .hw = &camcc_pll7_out_even.clkr.hw }, +}; + +static const struct parent_map camcc_parent_map_3[] = { + { P_BI_TCXO, 0 }, + { P_CAMCC_PLL0_OUT_MAIN, 1 }, + { P_CAMCC_PLL0_OUT_EVEN, 2 }, + { P_CAMCC_PLL0_OUT_ODD, 3 }, + { P_CAMCC_PLL7_OUT_EVEN, 5 }, + { P_CAMCC_PLL3_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data camcc_parent_data_3[] = { + { .index = DT_BI_TCXO }, + { .hw = &camcc_pll0.clkr.hw }, + { .hw = &camcc_pll0_out_even.clkr.hw }, + { .hw = &camcc_pll0_out_odd.clkr.hw }, + { .hw = &camcc_pll7_out_even.clkr.hw }, + { .hw = &camcc_pll3_out_even.clkr.hw }, +}; + +static const struct parent_map camcc_parent_map_4[] = { + { P_BI_TCXO, 0 }, + { P_CAMCC_PLL3_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data camcc_parent_data_4[] = { + { .index = DT_BI_TCXO }, + { .hw = &camcc_pll3_out_even.clkr.hw }, +}; + +static const struct parent_map camcc_parent_map_5[] = { + { P_BI_TCXO, 0 }, + { P_CAMCC_PLL4_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data camcc_parent_data_5[] = { + { .index = DT_BI_TCXO }, + { .hw = &camcc_pll4_out_even.clkr.hw }, +}; + +static const struct parent_map camcc_parent_map_6[] = { + { P_BI_TCXO, 0 }, + { P_CAMCC_PLL5_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data camcc_parent_data_6[] = { + { .index = DT_BI_TCXO }, + { .hw = &camcc_pll5_out_even.clkr.hw }, +}; + +static const struct parent_map camcc_parent_map_7[] = { + { P_BI_TCXO, 0 }, + { P_CAMCC_PLL6_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data camcc_parent_data_7[] = { + { .index = DT_BI_TCXO }, + { .hw = &camcc_pll6_out_even.clkr.hw }, +}; + +static const struct parent_map camcc_parent_map_8[] = { + { P_BI_TCXO, 0 }, + { P_CAMCC_PLL1_OUT_EVEN, 4 }, +}; + +static const struct clk_parent_data camcc_parent_data_8[] = { + { .index = DT_BI_TCXO }, + { .hw = &camcc_pll1_out_even.clkr.hw }, +}; + +static const struct parent_map camcc_parent_map_9[] = { + { P_SLEEP_CLK, 0 }, +}; + +static const struct clk_parent_data camcc_parent_data_9[] = { + { .fw_name = "sleep_clk" }, +}; + +static const struct parent_map camcc_parent_map_10[] = { + { P_BI_TCXO, 0 }, +}; + +static const struct clk_parent_data camcc_parent_data_10_ao[] = { + { .fw_name = "bi_tcxo_ao" }, +}; + +static const struct freq_tbl ftbl_camcc_bps_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(200000000, P_CAMCC_PLL0_OUT_ODD, 2, 0, 0), + F(400000000, P_CAMCC_PLL0_OUT_ODD, 1, 0, 0), + F(480000000, P_CAMCC_PLL7_OUT_EVEN, 1, 0, 0), + F(600000000, P_CAMCC_PLL0_OUT_MAIN, 2, 0, 0), + F(760000000, P_CAMCC_PLL3_OUT_EVEN, 1, 0, 0), +}; + +static struct clk_rcg2 camcc_bps_clk_src = { + .cmd_rcgr = 0x7010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_3, + .freq_tbl = ftbl_camcc_bps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_bps_clk_src", + .parent_data = camcc_parent_data_3, + .num_parents = ARRAY_SIZE(camcc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_camnoc_axi_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(150000000, P_CAMCC_PLL0_OUT_EVEN, 4, 0, 0), + F(266666667, P_CAMCC_PLL0_OUT_ODD, 1.5, 0, 0), + F(320000000, P_CAMCC_PLL7_OUT_ODD, 1, 0, 0), + F(400000000, P_CAMCC_PLL0_OUT_ODD, 1, 0, 0), + F(480000000, P_CAMCC_PLL7_OUT_EVEN, 1, 0, 0), +}; + +static struct clk_rcg2 camcc_camnoc_axi_clk_src = { + .cmd_rcgr = 0xc170, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_2, + .freq_tbl = ftbl_camcc_camnoc_axi_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_camnoc_axi_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_cci_0_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(37500000, P_CAMCC_PLL0_OUT_EVEN, 16, 0, 0), +}; + +static struct clk_rcg2 camcc_cci_0_clk_src = { + .cmd_rcgr = 0xc108, + .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 = 0xc124, + .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 struct clk_rcg2 camcc_cci_2_clk_src = { + .cmd_rcgr = 0xc204, + .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_2_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_3_clk_src = { + .cmd_rcgr = 0xc220, + .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_3_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(19200000, P_BI_TCXO, 1, 0, 0), + F(240000000, P_CAMCC_PLL0_OUT_EVEN, 2.5, 0, 0), + F(400000000, P_CAMCC_PLL0_OUT_ODD, 1, 0, 0), +}; + +static struct clk_rcg2 camcc_cphy_rx_clk_src = { + .cmd_rcgr = 0xa064, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .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_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_csi0phytimer_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(300000000, P_CAMCC_PLL0_OUT_EVEN, 2, 0, 0), +}; + +static struct clk_rcg2 camcc_csi0phytimer_clk_src = { + .cmd_rcgr = 0x6004, + .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 = 0x6028, + .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 = 0x604c, + .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 = 0x6074, + .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(19200000, P_BI_TCXO, 1, 0, 0), + F(100000000, P_CAMCC_PLL0_OUT_EVEN, 6, 0, 0), + F(200000000, P_CAMCC_PLL0_OUT_EVEN, 3, 0, 0), + F(300000000, P_CAMCC_PLL0_OUT_MAIN, 4, 0, 0), + F(400000000, P_CAMCC_PLL0_OUT_MAIN, 3, 0, 0), +}; + +static struct clk_rcg2 camcc_fast_ahb_clk_src = { + .cmd_rcgr = 0x703c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .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_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_icp_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(400000000, P_CAMCC_PLL0_OUT_ODD, 1, 0, 0), + F(600000000, P_CAMCC_PLL0_OUT_MAIN, 2, 0, 0), +}; + +static struct clk_rcg2 camcc_icp_clk_src = { + .cmd_rcgr = 0xc0b8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .freq_tbl = ftbl_camcc_icp_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_icp_clk_src", + .parent_data = camcc_parent_data_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_ife_0_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(400000000, P_CAMCC_PLL3_OUT_EVEN, 1, 0, 0), + F(558000000, P_CAMCC_PLL3_OUT_EVEN, 1, 0, 0), + F(637000000, P_CAMCC_PLL3_OUT_EVEN, 1, 0, 0), + F(760000000, P_CAMCC_PLL3_OUT_EVEN, 1, 0, 0), +}; + +static struct clk_rcg2 camcc_ife_0_clk_src = { + .cmd_rcgr = 0xa010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_4, + .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_4, + .num_parents = ARRAY_SIZE(camcc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_ife_0_csid_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(75000000, P_CAMCC_PLL0_OUT_EVEN, 8, 0, 0), + F(400000000, P_CAMCC_PLL0_OUT_ODD, 1, 0, 0), + F(480000000, P_CAMCC_PLL7_OUT_EVEN, 1, 0, 0), + F(600000000, P_CAMCC_PLL0_OUT_MAIN, 2, 0, 0), +}; + +static struct clk_rcg2 camcc_ife_0_csid_clk_src = { + .cmd_rcgr = 0xa03c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .freq_tbl = ftbl_camcc_ife_0_csid_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_ife_0_csid_clk_src", + .parent_data = camcc_parent_data_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_ife_1_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(400000000, P_CAMCC_PLL4_OUT_EVEN, 1, 0, 0), + F(558000000, P_CAMCC_PLL4_OUT_EVEN, 1, 0, 0), + F(637000000, P_CAMCC_PLL4_OUT_EVEN, 1, 0, 0), + F(760000000, P_CAMCC_PLL4_OUT_EVEN, 1, 0, 0), +}; + +static struct clk_rcg2 camcc_ife_1_clk_src = { + .cmd_rcgr = 0xb010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_5, + .freq_tbl = ftbl_camcc_ife_1_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_ife_1_clk_src", + .parent_data = camcc_parent_data_5, + .num_parents = ARRAY_SIZE(camcc_parent_data_5), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 camcc_ife_1_csid_clk_src = { + .cmd_rcgr = 0xb03c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .freq_tbl = ftbl_camcc_ife_0_csid_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_ife_1_csid_clk_src", + .parent_data = camcc_parent_data_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_ife_2_clk_src[] = { + F(400000000, P_CAMCC_PLL5_OUT_EVEN, 1, 0, 0), + F(558000000, P_CAMCC_PLL5_OUT_EVEN, 1, 0, 0), + F(637000000, P_CAMCC_PLL5_OUT_EVEN, 1, 0, 0), + F(760000000, P_CAMCC_PLL5_OUT_EVEN, 1, 0, 0), +}; + +static struct clk_rcg2 camcc_ife_2_clk_src = { + .cmd_rcgr = 0xf010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_6, + .freq_tbl = ftbl_camcc_ife_2_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_ife_2_clk_src", + .parent_data = camcc_parent_data_6, + .num_parents = ARRAY_SIZE(camcc_parent_data_6), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_ife_2_csid_clk_src[] = { + F(400000000, P_CAMCC_PLL0_OUT_ODD, 1, 0, 0), + F(480000000, P_CAMCC_PLL7_OUT_EVEN, 1, 0, 0), + F(600000000, P_CAMCC_PLL0_OUT_MAIN, 2, 0, 0), +}; + +static struct clk_rcg2 camcc_ife_2_csid_clk_src = { + .cmd_rcgr = 0xf03c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .freq_tbl = ftbl_camcc_ife_2_csid_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_ife_2_csid_clk_src", + .parent_data = camcc_parent_data_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_ife_3_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(400000000, P_CAMCC_PLL6_OUT_EVEN, 1, 0, 0), + F(558000000, P_CAMCC_PLL6_OUT_EVEN, 1, 0, 0), + F(637000000, P_CAMCC_PLL6_OUT_EVEN, 1, 0, 0), + F(760000000, P_CAMCC_PLL6_OUT_EVEN, 1, 0, 0), +}; + +static struct clk_rcg2 camcc_ife_3_clk_src = { + .cmd_rcgr = 0xf07c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_7, + .freq_tbl = ftbl_camcc_ife_3_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_ife_3_clk_src", + .parent_data = camcc_parent_data_7, + .num_parents = ARRAY_SIZE(camcc_parent_data_7), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 camcc_ife_3_csid_clk_src = { + .cmd_rcgr = 0xf0a8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .freq_tbl = ftbl_camcc_ife_2_csid_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_ife_3_csid_clk_src", + .parent_data = camcc_parent_data_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_ife_lite_0_clk_src[] = { + F(320000000, P_CAMCC_PLL7_OUT_ODD, 1, 0, 0), + F(400000000, P_CAMCC_PLL0_OUT_ODD, 1, 0, 0), + F(480000000, P_CAMCC_PLL7_OUT_EVEN, 1, 0, 0), + F(600000000, P_CAMCC_PLL0_OUT_MAIN, 2, 0, 0), +}; + +static struct clk_rcg2 camcc_ife_lite_0_clk_src = { + .cmd_rcgr = 0xc004, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_2, + .freq_tbl = ftbl_camcc_ife_lite_0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_0_clk_src", + .parent_data = camcc_parent_data_2, + .num_parents = ARRAY_SIZE(camcc_parent_data_2), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 camcc_ife_lite_0_csid_clk_src = { + .cmd_rcgr = 0xc020, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .freq_tbl = ftbl_camcc_ife_2_csid_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_0_csid_clk_src", + .parent_data = camcc_parent_data_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 camcc_ife_lite_1_clk_src = { + .cmd_rcgr = 0xc048, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_2, + .freq_tbl = ftbl_camcc_ife_lite_0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_1_clk_src", + .parent_data = camcc_parent_data_2, + .num_parents = ARRAY_SIZE(camcc_parent_data_2), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 camcc_ife_lite_1_csid_clk_src = { + .cmd_rcgr = 0xc064, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .freq_tbl = ftbl_camcc_ife_2_csid_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_1_csid_clk_src", + .parent_data = camcc_parent_data_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 camcc_ife_lite_2_clk_src = { + .cmd_rcgr = 0xc240, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_2, + .freq_tbl = ftbl_camcc_ife_lite_0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_2_clk_src", + .parent_data = camcc_parent_data_2, + .num_parents = ARRAY_SIZE(camcc_parent_data_2), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 camcc_ife_lite_2_csid_clk_src = { + .cmd_rcgr = 0xc25c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .freq_tbl = ftbl_camcc_ife_2_csid_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_2_csid_clk_src", + .parent_data = camcc_parent_data_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 camcc_ife_lite_3_clk_src = { + .cmd_rcgr = 0xc284, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_2, + .freq_tbl = ftbl_camcc_ife_lite_0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_3_clk_src", + .parent_data = camcc_parent_data_2, + .num_parents = ARRAY_SIZE(camcc_parent_data_2), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 camcc_ife_lite_3_csid_clk_src = { + .cmd_rcgr = 0xc2a0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .freq_tbl = ftbl_camcc_ife_2_csid_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_3_csid_clk_src", + .parent_data = camcc_parent_data_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_ipe_0_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(320000000, P_CAMCC_PLL1_OUT_EVEN, 1, 0, 0), + F(475000000, P_CAMCC_PLL1_OUT_EVEN, 1, 0, 0), + F(520000000, P_CAMCC_PLL1_OUT_EVEN, 1, 0, 0), + F(600000000, P_CAMCC_PLL1_OUT_EVEN, 1, 0, 0), +}; + +static struct clk_rcg2 camcc_ipe_0_clk_src = { + .cmd_rcgr = 0x8010, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_8, + .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_8, + .num_parents = ARRAY_SIZE(camcc_parent_data_8), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_jpeg_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(200000000, P_CAMCC_PLL0_OUT_ODD, 2, 0, 0), + F(400000000, P_CAMCC_PLL0_OUT_ODD, 1, 0, 0), + F(480000000, P_CAMCC_PLL7_OUT_EVEN, 1, 0, 0), + F(600000000, P_CAMCC_PLL0_OUT_MAIN, 2, 0, 0), +}; + +static struct clk_rcg2 camcc_jpeg_clk_src = { + .cmd_rcgr = 0xc08c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .freq_tbl = ftbl_camcc_jpeg_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_jpeg_clk_src", + .parent_data = camcc_parent_data_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_lrme_clk_src[] = { + F(240000000, P_CAMCC_PLL7_OUT_EVEN, 2, 0, 0), + F(300000000, P_CAMCC_PLL0_OUT_EVEN, 2, 0, 0), + F(320000000, P_CAMCC_PLL7_OUT_ODD, 1, 0, 0), + F(400000000, P_CAMCC_PLL0_OUT_MAIN, 3, 0, 0), +}; + +static struct clk_rcg2 camcc_lrme_clk_src = { + .cmd_rcgr = 0xc144, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_2, + .freq_tbl = ftbl_camcc_lrme_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_lrme_clk_src", + .parent_data = camcc_parent_data_2, + .num_parents = ARRAY_SIZE(camcc_parent_data_2), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_mclk0_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + 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 = 0x5004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = camcc_parent_map_1, + .freq_tbl = ftbl_camcc_mclk0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_mclk0_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_mclk1_clk_src = { + .cmd_rcgr = 0x5024, + .mnd_width = 8, + .hid_width = 5, + .parent_map = camcc_parent_map_1, + .freq_tbl = ftbl_camcc_mclk0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_mclk1_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_mclk2_clk_src = { + .cmd_rcgr = 0x5044, + .mnd_width = 8, + .hid_width = 5, + .parent_map = camcc_parent_map_1, + .freq_tbl = ftbl_camcc_mclk0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_mclk2_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_mclk3_clk_src = { + .cmd_rcgr = 0x5064, + .mnd_width = 8, + .hid_width = 5, + .parent_map = camcc_parent_map_1, + .freq_tbl = ftbl_camcc_mclk0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_mclk3_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_mclk4_clk_src = { + .cmd_rcgr = 0x5084, + .mnd_width = 8, + .hid_width = 5, + .parent_map = camcc_parent_map_1, + .freq_tbl = ftbl_camcc_mclk0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_mclk4_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_mclk5_clk_src = { + .cmd_rcgr = 0x50a4, + .mnd_width = 8, + .hid_width = 5, + .parent_map = camcc_parent_map_1, + .freq_tbl = ftbl_camcc_mclk0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_mclk5_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_mclk6_clk_src = { + .cmd_rcgr = 0x50c4, + .mnd_width = 8, + .hid_width = 5, + .parent_map = camcc_parent_map_1, + .freq_tbl = ftbl_camcc_mclk0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_mclk6_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_mclk7_clk_src = { + .cmd_rcgr = 0x50e4, + .mnd_width = 8, + .hid_width = 5, + .parent_map = camcc_parent_map_1, + .freq_tbl = ftbl_camcc_mclk0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_mclk7_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_sleep_clk_src[] = { + F(32000, P_SLEEP_CLK, 1, 0, 0), +}; + +static struct clk_rcg2 camcc_sleep_clk_src = { + .cmd_rcgr = 0xc1e8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_9, + .freq_tbl = ftbl_camcc_sleep_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_sleep_clk_src", + .parent_data = camcc_parent_data_9, + .num_parents = ARRAY_SIZE(camcc_parent_data_9), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_slow_ahb_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(80000000, P_CAMCC_PLL7_OUT_EVEN, 6, 0, 0), +}; + +static struct clk_rcg2 camcc_slow_ahb_clk_src = { + .cmd_rcgr = 0x7058, + .mnd_width = 8, + .hid_width = 5, + .parent_map = camcc_parent_map_0, + .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_0, + .num_parents = ARRAY_SIZE(camcc_parent_data_0), + .ops = &clk_rcg2_ops, + }, +}; + +static const struct freq_tbl ftbl_camcc_xo_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), +}; + +static struct clk_rcg2 camcc_xo_clk_src = { + .cmd_rcgr = 0xc1cc, + .mnd_width = 0, + .hid_width = 5, + .parent_map = camcc_parent_map_10, + .freq_tbl = ftbl_camcc_xo_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "camcc_xo_clk_src", + .parent_data = camcc_parent_data_10_ao, + .num_parents = ARRAY_SIZE(camcc_parent_data_10_ao), + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch camcc_bps_ahb_clk = { + .halt_reg = 0x7070, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x7070, + .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 = 0x7054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x7054, + .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 = 0x7038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x7038, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_bps_axi_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_camnoc_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_bps_clk = { + .halt_reg = 0x7028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x7028, + .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 = 0xc18c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc18c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_camnoc_axi_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_camnoc_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_camnoc_dcd_xo_clk = { + .halt_reg = 0xc194, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc194, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_camnoc_dcd_xo_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_xo_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_cci_0_clk = { + .halt_reg = 0xc120, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc120, + .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 = 0xc13c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc13c, + .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_cci_2_clk = { + .halt_reg = 0xc21c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc21c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_cci_2_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_cci_2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_cci_3_clk = { + .halt_reg = 0xc238, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc238, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_cci_3_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_cci_3_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 = 0xc1c8, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0xc1c8, + .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 = 0xc168, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc168, + .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 = 0x601c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x601c, + .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 = 0x6040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x6040, + .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 = 0x6064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x6064, + .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 = 0x608c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x608c, + .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 = 0x6020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x6020, + .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 = 0x6044, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x6044, + .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 = 0x6068, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x6068, + .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 = 0x6090, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x6090, + .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_gdsc_clk = { + .halt_reg = 0xc1e4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc1e4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_gdsc_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_xo_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_icp_ahb_clk = { + .halt_reg = 0xc0d8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc0d8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_icp_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_icp_clk = { + .halt_reg = 0xc0d0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc0d0, + .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_ife_0_axi_clk = { + .halt_reg = 0xa080, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa080, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_0_axi_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_camnoc_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_0_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_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 = 0xa07c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa07c, + .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 = 0xa054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa054, + .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 = 0xa038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa038, + .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 = 0xb068, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb068, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_1_axi_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_camnoc_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_1_clk = { + .halt_reg = 0xb028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb028, + .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 = 0xb064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb064, + .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 = 0xb054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb054, + .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 = 0xb038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb038, + .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 = 0xf068, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf068, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_2_axi_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_camnoc_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_2_clk = { + .halt_reg = 0xf028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf028, + .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 = 0xf064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf064, + .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 = 0xf054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf054, + .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 = 0xf038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf038, + .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_3_axi_clk = { + .halt_reg = 0xf0d4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf0d4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_3_axi_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_camnoc_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_3_clk = { + .halt_reg = 0xf094, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf094, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_3_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_ife_3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_3_cphy_rx_clk = { + .halt_reg = 0xf0d0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf0d0, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_3_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_3_csid_clk = { + .halt_reg = 0xf0c0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf0c0, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_3_csid_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_ife_3_csid_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_3_dsp_clk = { + .halt_reg = 0xf0a4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf0a4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_3_dsp_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_ife_3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_lite_0_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_0_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_ife_lite_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_lite_0_cphy_rx_clk = { + .halt_reg = 0xc040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_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_lite_0_csid_clk = { + .halt_reg = 0xc038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc038, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_0_csid_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_ife_lite_0_csid_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_lite_1_clk = { + .halt_reg = 0xc060, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc060, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_1_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_ife_lite_1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_lite_1_cphy_rx_clk = { + .halt_reg = 0xc084, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc084, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_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_lite_1_csid_clk = { + .halt_reg = 0xc07c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc07c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_1_csid_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_ife_lite_1_csid_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_lite_2_clk = { + .halt_reg = 0xc258, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc258, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_2_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_ife_lite_2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_lite_2_cphy_rx_clk = { + .halt_reg = 0xc27c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc27c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_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_lite_2_csid_clk = { + .halt_reg = 0xc274, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc274, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_2_csid_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_ife_lite_2_csid_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_lite_3_clk = { + .halt_reg = 0xc29c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc29c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_3_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_ife_lite_3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ife_lite_3_cphy_rx_clk = { + .halt_reg = 0xc2c0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc2c0, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_3_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_3_csid_clk = { + .halt_reg = 0xc2b8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc2b8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ife_lite_3_csid_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_ife_lite_3_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 = 0x8040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8040, + .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 = 0x803c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x803c, + .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 = 0x8038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8038, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ipe_0_axi_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_camnoc_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ipe_0_clk = { + .halt_reg = 0x8028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8028, + .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_ipe_1_ahb_clk = { + .halt_reg = 0x9028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9028, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ipe_1_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_1_areg_clk = { + .halt_reg = 0x9024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ipe_1_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_1_axi_clk = { + .halt_reg = 0x9020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ipe_1_axi_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_camnoc_axi_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_ipe_1_clk = { + .halt_reg = 0x9010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_ipe_1_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 = 0xc0a4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc0a4, + .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 = 0xc15c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc15c, + .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 = 0x501c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x501c, + .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 = 0x503c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x503c, + .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 = 0x505c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x505c, + .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 = 0x507c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x507c, + .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 = 0x509c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x509c, + .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_mclk5_clk = { + .halt_reg = 0x50bc, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x50bc, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_mclk5_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_mclk5_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_mclk6_clk = { + .halt_reg = 0x50dc, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x50dc, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_mclk6_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_mclk6_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_mclk7_clk = { + .halt_reg = 0x50fc, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x50fc, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_mclk7_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_mclk7_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch camcc_sleep_clk = { + .halt_reg = 0xc200, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc200, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "camcc_sleep_clk", + .parent_hws = (const struct clk_hw*[]){ + &camcc_sleep_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct gdsc titan_top_gdsc; + +static struct gdsc bps_gdsc = { + .gdscr = 0x7004, + .pd = { + .name = "bps_gdsc", + }, + .flags = HW_CTRL | RETAIN_FF_ENABLE, + .parent = &titan_top_gdsc.pd, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc ife_0_gdsc = { + .gdscr = 0xa004, + .pd = { + .name = "ife_0_gdsc", + }, + .flags = RETAIN_FF_ENABLE, + .parent = &titan_top_gdsc.pd, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc ife_1_gdsc = { + .gdscr = 0xb004, + .pd = { + .name = "ife_1_gdsc", + }, + .flags = RETAIN_FF_ENABLE, + .parent = &titan_top_gdsc.pd, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc ife_2_gdsc = { + .gdscr = 0xf004, + .pd = { + .name = "ife_2_gdsc", + }, + .flags = RETAIN_FF_ENABLE, + .parent = &titan_top_gdsc.pd, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc ife_3_gdsc = { + .gdscr = 0xf070, + .pd = { + .name = "ife_3_gdsc", + }, + .flags = RETAIN_FF_ENABLE, + .parent = &titan_top_gdsc.pd, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc ipe_0_gdsc = { + .gdscr = 0x8004, + .pd = { + .name = "ipe_0_gdsc", + }, + .flags = HW_CTRL | RETAIN_FF_ENABLE, + .parent = &titan_top_gdsc.pd, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc ipe_1_gdsc = { + .gdscr = 0x9004, + .pd = { + .name = "ipe_1_gdsc", + }, + .flags = HW_CTRL | RETAIN_FF_ENABLE, + .parent = &titan_top_gdsc.pd, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc titan_top_gdsc = { + .gdscr = 0xc1bc, + .pd = { + .name = "titan_top_gdsc", + }, + .flags = RETAIN_FF_ENABLE, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct clk_regmap *camcc_sc8280xp_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_CAMNOC_AXI_CLK_SRC] = &camcc_camnoc_axi_clk_src.clkr, + [CAMCC_CAMNOC_DCD_XO_CLK] = &camcc_camnoc_dcd_xo_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_CCI_2_CLK] = &camcc_cci_2_clk.clkr, + [CAMCC_CCI_2_CLK_SRC] = &camcc_cci_2_clk_src.clkr, + [CAMCC_CCI_3_CLK] = &camcc_cci_3_clk.clkr, + [CAMCC_CCI_3_CLK_SRC] = &camcc_cci_3_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_GDSC_CLK] = &camcc_gdsc_clk.clkr, + [CAMCC_ICP_AHB_CLK] = &camcc_icp_ahb_clk.clkr, + [CAMCC_ICP_CLK] = &camcc_icp_clk.clkr, + [CAMCC_ICP_CLK_SRC] = &camcc_icp_clk_src.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_3_AXI_CLK] = &camcc_ife_3_axi_clk.clkr, + [CAMCC_IFE_3_CLK] = &camcc_ife_3_clk.clkr, + [CAMCC_IFE_3_CLK_SRC] = &camcc_ife_3_clk_src.clkr, + [CAMCC_IFE_3_CPHY_RX_CLK] = &camcc_ife_3_cphy_rx_clk.clkr, + [CAMCC_IFE_3_CSID_CLK] = &camcc_ife_3_csid_clk.clkr, + [CAMCC_IFE_3_CSID_CLK_SRC] = &camcc_ife_3_csid_clk_src.clkr, + [CAMCC_IFE_3_DSP_CLK] = &camcc_ife_3_dsp_clk.clkr, + [CAMCC_IFE_LITE_0_CLK] = &camcc_ife_lite_0_clk.clkr, + [CAMCC_IFE_LITE_0_CLK_SRC] = &camcc_ife_lite_0_clk_src.clkr, + [CAMCC_IFE_LITE_0_CPHY_RX_CLK] = &camcc_ife_lite_0_cphy_rx_clk.clkr, + [CAMCC_IFE_LITE_0_CSID_CLK] = &camcc_ife_lite_0_csid_clk.clkr, + [CAMCC_IFE_LITE_0_CSID_CLK_SRC] = &camcc_ife_lite_0_csid_clk_src.clkr, + [CAMCC_IFE_LITE_1_CLK] = &camcc_ife_lite_1_clk.clkr, + [CAMCC_IFE_LITE_1_CLK_SRC] = &camcc_ife_lite_1_clk_src.clkr, + [CAMCC_IFE_LITE_1_CPHY_RX_CLK] = &camcc_ife_lite_1_cphy_rx_clk.clkr, + [CAMCC_IFE_LITE_1_CSID_CLK] = &camcc_ife_lite_1_csid_clk.clkr, + [CAMCC_IFE_LITE_1_CSID_CLK_SRC] = &camcc_ife_lite_1_csid_clk_src.clkr, + [CAMCC_IFE_LITE_2_CLK] = &camcc_ife_lite_2_clk.clkr, + [CAMCC_IFE_LITE_2_CLK_SRC] = &camcc_ife_lite_2_clk_src.clkr, + [CAMCC_IFE_LITE_2_CPHY_RX_CLK] = &camcc_ife_lite_2_cphy_rx_clk.clkr, + [CAMCC_IFE_LITE_2_CSID_CLK] = &camcc_ife_lite_2_csid_clk.clkr, + [CAMCC_IFE_LITE_2_CSID_CLK_SRC] = &camcc_ife_lite_2_csid_clk_src.clkr, + [CAMCC_IFE_LITE_3_CLK] = &camcc_ife_lite_3_clk.clkr, + [CAMCC_IFE_LITE_3_CLK_SRC] = &camcc_ife_lite_3_clk_src.clkr, + [CAMCC_IFE_LITE_3_CPHY_RX_CLK] = &camcc_ife_lite_3_cphy_rx_clk.clkr, + [CAMCC_IFE_LITE_3_CSID_CLK] = &camcc_ife_lite_3_csid_clk.clkr, + [CAMCC_IFE_LITE_3_CSID_CLK_SRC] = &camcc_ife_lite_3_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_IPE_1_AHB_CLK] = &camcc_ipe_1_ahb_clk.clkr, + [CAMCC_IPE_1_AREG_CLK] = &camcc_ipe_1_areg_clk.clkr, + [CAMCC_IPE_1_AXI_CLK] = &camcc_ipe_1_axi_clk.clkr, + [CAMCC_IPE_1_CLK] = &camcc_ipe_1_clk.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_MCLK5_CLK] = &camcc_mclk5_clk.clkr, + [CAMCC_MCLK5_CLK_SRC] = &camcc_mclk5_clk_src.clkr, + [CAMCC_MCLK6_CLK] = &camcc_mclk6_clk.clkr, + [CAMCC_MCLK6_CLK_SRC] = &camcc_mclk6_clk_src.clkr, + [CAMCC_MCLK7_CLK] = &camcc_mclk7_clk.clkr, + [CAMCC_MCLK7_CLK_SRC] = &camcc_mclk7_clk_src.clkr, + [CAMCC_PLL0] = &camcc_pll0.clkr, + [CAMCC_PLL0_OUT_EVEN] = &camcc_pll0_out_even.clkr, + [CAMCC_PLL0_OUT_ODD] = &camcc_pll0_out_odd.clkr, + [CAMCC_PLL1] = &camcc_pll1.clkr, + [CAMCC_PLL1_OUT_EVEN] = &camcc_pll1_out_even.clkr, + [CAMCC_PLL2] = &camcc_pll2.clkr, + [CAMCC_PLL3] = &camcc_pll3.clkr, + [CAMCC_PLL3_OUT_EVEN] = &camcc_pll3_out_even.clkr, + [CAMCC_PLL4] = &camcc_pll4.clkr, + [CAMCC_PLL4_OUT_EVEN] = &camcc_pll4_out_even.clkr, + [CAMCC_PLL5] = &camcc_pll5.clkr, + [CAMCC_PLL5_OUT_EVEN] = &camcc_pll5_out_even.clkr, + [CAMCC_PLL6] = &camcc_pll6.clkr, + [CAMCC_PLL6_OUT_EVEN] = &camcc_pll6_out_even.clkr, + [CAMCC_PLL7] = &camcc_pll7.clkr, + [CAMCC_PLL7_OUT_EVEN] = &camcc_pll7_out_even.clkr, + [CAMCC_PLL7_OUT_ODD] = &camcc_pll7_out_odd.clkr, + [CAMCC_SLEEP_CLK] = &camcc_sleep_clk.clkr, + [CAMCC_SLEEP_CLK_SRC] = &camcc_sleep_clk_src.clkr, + [CAMCC_SLOW_AHB_CLK_SRC] = &camcc_slow_ahb_clk_src.clkr, + [CAMCC_XO_CLK_SRC] = &camcc_xo_clk_src.clkr, +}; + +static struct gdsc *camcc_sc8280xp_gdscs[] = { + [BPS_GDSC] = &bps_gdsc, + [IFE_0_GDSC] = &ife_0_gdsc, + [IFE_1_GDSC] = &ife_1_gdsc, + [IFE_2_GDSC] = &ife_2_gdsc, + [IFE_3_GDSC] = &ife_3_gdsc, + [IPE_0_GDSC] = &ipe_0_gdsc, + [IPE_1_GDSC] = &ipe_1_gdsc, + [TITAN_TOP_GDSC] = &titan_top_gdsc, +}; + +static const struct qcom_reset_map camcc_sc8280xp_resets[] = { + [CAMCC_BPS_BCR] = { 0x7000 }, + [CAMCC_CAMNOC_BCR] = { 0xc16c }, + [CAMCC_CCI_BCR] = { 0xc104 }, + [CAMCC_CPAS_BCR] = { 0xc164 }, + [CAMCC_CSI0PHY_BCR] = { 0x6000 }, + [CAMCC_CSI1PHY_BCR] = { 0x6024 }, + [CAMCC_CSI2PHY_BCR] = { 0x6048 }, + [CAMCC_CSI3PHY_BCR] = { 0x6070 }, + [CAMCC_ICP_BCR] = { 0xc0b4 }, + [CAMCC_IFE_0_BCR] = { 0xa000 }, + [CAMCC_IFE_1_BCR] = { 0xb000 }, + [CAMCC_IFE_2_BCR] = { 0xf000 }, + [CAMCC_IFE_3_BCR] = { 0xf06c }, + [CAMCC_IFE_LITE_0_BCR] = { 0xc000 }, + [CAMCC_IFE_LITE_1_BCR] = { 0xc044 }, + [CAMCC_IFE_LITE_2_BCR] = { 0xc23c }, + [CAMCC_IFE_LITE_3_BCR] = { 0xc280 }, + [CAMCC_IPE_0_BCR] = { 0x8000 }, + [CAMCC_IPE_1_BCR] = { 0x9000 }, + [CAMCC_JPEG_BCR] = { 0xc088 }, + [CAMCC_LRME_BCR] = { 0xc140 }, +}; + +static const struct regmap_config camcc_sc8280xp_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x13020, + .fast_io = true, +}; + +static struct qcom_cc_desc camcc_sc8280xp_desc = { + .config = &camcc_sc8280xp_regmap_config, + .clks = camcc_sc8280xp_clocks, + .num_clks = ARRAY_SIZE(camcc_sc8280xp_clocks), + .resets = camcc_sc8280xp_resets, + .num_resets = ARRAY_SIZE(camcc_sc8280xp_resets), + .gdscs = camcc_sc8280xp_gdscs, + .num_gdscs = ARRAY_SIZE(camcc_sc8280xp_gdscs), +}; + +static const struct of_device_id camcc_sc8280xp_match_table[] = { + { .compatible = "qcom,sc8280xp-camcc" }, + { } +}; +MODULE_DEVICE_TABLE(of, camcc_sc8280xp_match_table); + +static int camcc_sc8280xp_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, &camcc_sc8280xp_desc); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + goto err_put_rpm; + } + + clk_lucid_pll_configure(&camcc_pll0, regmap, &camcc_pll0_config); + clk_lucid_pll_configure(&camcc_pll1, regmap, &camcc_pll1_config); + clk_zonda_pll_configure(&camcc_pll2, regmap, &camcc_pll2_config); + clk_lucid_pll_configure(&camcc_pll3, regmap, &camcc_pll3_config); + clk_lucid_pll_configure(&camcc_pll4, regmap, &camcc_pll4_config); + clk_lucid_pll_configure(&camcc_pll5, regmap, &camcc_pll5_config); + clk_lucid_pll_configure(&camcc_pll6, regmap, &camcc_pll6_config); + clk_lucid_pll_configure(&camcc_pll7, regmap, &camcc_pll7_config); + + /* + * Keep camcc_gdsc_clk always enabled: + */ + regmap_update_bits(regmap, 0xc1e4, BIT(0), 1); + + ret = qcom_cc_really_probe(pdev, &camcc_sc8280xp_desc, regmap); + if (ret) + goto err_disable; + + pm_runtime_put(&pdev->dev); + + return 0; + +err_disable: + regmap_update_bits(regmap, 0xc1e4, BIT(0), 0); +err_put_rpm: + pm_runtime_put_sync(&pdev->dev); + + return ret; +} + +static struct platform_driver camcc_sc8280xp_driver = { + .probe = camcc_sc8280xp_probe, + .driver = { + .name = "camcc-sc8280xp", + .of_match_table = camcc_sc8280xp_match_table, + }, +}; + +module_platform_driver(camcc_sc8280xp_driver); + +MODULE_DESCRIPTION("QCOM CAMCC SC8280XP Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/qcom/clk-branch.c b/drivers/clk/qcom/clk-branch.c index fc4735f74f0f15..c1dba33ac31af9 100644 --- a/drivers/clk/qcom/clk-branch.c +++ b/drivers/clk/qcom/clk-branch.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -134,6 +135,43 @@ static void clk_branch2_disable(struct clk_hw *hw) clk_branch_toggle(hw, false, clk_branch2_check_halt); } +static int clk_branch2_mem_enable(struct clk_hw *hw) +{ + struct clk_mem_branch *mem_br = to_clk_mem_branch(hw); + struct clk_branch branch = mem_br->branch; + u32 val; + int ret; + + regmap_update_bits(branch.clkr.regmap, mem_br->mem_enable_reg, + mem_br->mem_enable_ack_mask, mem_br->mem_enable_ack_mask); + + ret = regmap_read_poll_timeout(branch.clkr.regmap, mem_br->mem_ack_reg, + val, val & mem_br->mem_enable_ack_mask, 0, 200); + if (ret) { + WARN(1, "%s mem enable failed\n", clk_hw_get_name(&branch.clkr.hw)); + return ret; + } + + return clk_branch2_enable(hw); +} + +static void clk_branch2_mem_disable(struct clk_hw *hw) +{ + struct clk_mem_branch *mem_br = to_clk_mem_branch(hw); + + regmap_update_bits(mem_br->branch.clkr.regmap, mem_br->mem_enable_reg, + mem_br->mem_enable_ack_mask, 0); + + return clk_branch2_disable(hw); +} + +const struct clk_ops clk_branch2_mem_ops = { + .enable = clk_branch2_mem_enable, + .disable = clk_branch2_mem_disable, + .is_enabled = clk_is_enabled_regmap, +}; +EXPORT_SYMBOL_GPL(clk_branch2_mem_ops); + const struct clk_ops clk_branch2_ops = { .enable = clk_branch2_enable, .disable = clk_branch2_disable, diff --git a/drivers/clk/qcom/clk-branch.h b/drivers/clk/qcom/clk-branch.h index 0cf800b9d08d16..8ffed603c050b3 100644 --- a/drivers/clk/qcom/clk-branch.h +++ b/drivers/clk/qcom/clk-branch.h @@ -38,6 +38,23 @@ struct clk_branch { struct clk_regmap clkr; }; +/** + * struct clk_mem_branch - gating clock which are associated with memories + * + * @mem_enable_reg: branch clock memory gating register + * @mem_ack_reg: branch clock memory ack register + * @mem_enable_ack_mask: branch clock memory enable and ack field in @mem_ack_reg + * @branch: branch clock gating handle + * + * Clock which can gate its memories. + */ +struct clk_mem_branch { + u32 mem_enable_reg; + u32 mem_ack_reg; + u32 mem_enable_ack_mask; + struct clk_branch branch; +}; + /* Branch clock common bits for HLOS-owned clocks */ #define CBCR_CLK_OFF BIT(31) #define CBCR_NOC_FSM_STATUS GENMASK(30, 28) @@ -85,8 +102,12 @@ extern const struct clk_ops clk_branch_ops; extern const struct clk_ops clk_branch2_ops; extern const struct clk_ops clk_branch_simple_ops; extern const struct clk_ops clk_branch2_aon_ops; +extern const struct clk_ops clk_branch2_mem_ops; #define to_clk_branch(_hw) \ container_of(to_clk_regmap(_hw), struct clk_branch, clkr) +#define to_clk_mem_branch(_hw) \ + container_of(to_clk_branch(_hw), struct clk_mem_branch, branch) + #endif diff --git a/drivers/clk/qcom/clk-rpmh.c b/drivers/clk/qcom/clk-rpmh.c index 5d853fd432940c..bb82abeed88f3b 100644 --- a/drivers/clk/qcom/clk-rpmh.c +++ b/drivers/clk/qcom/clk-rpmh.c @@ -372,6 +372,9 @@ 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(clk3, _a2, "clka3", 2); +DEFINE_CLK_RPMH_VRM(clk4, _a2, "clka4", 2); +DEFINE_CLK_RPMH_VRM(clk5, _a2, "clka5", 2); DEFINE_CLK_RPMH_VRM(clk6, _a2, "clka6", 2); DEFINE_CLK_RPMH_VRM(clk7, _a2, "clka7", 2); DEFINE_CLK_RPMH_VRM(clk8, _a2, "clka8", 2); @@ -630,6 +633,37 @@ static const struct clk_rpmh_desc clk_rpmh_sm8550 = { .num_clks = ARRAY_SIZE(sm8550_rpmh_clocks), }; +static struct clk_hw *sm8650_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, + /* + * The clka3 RPMh resource is missing in cmd-db + * for current platforms, while the clka3 exists + * on the PMK8550, the clock is unconnected and + * unused. + */ + [RPMH_RF_CLK4] = &clk_rpmh_clk4_a2.hw, + [RPMH_RF_CLK4_A] = &clk_rpmh_clk4_a2_ao.hw, + [RPMH_RF_CLK5] = &clk_rpmh_clk5_a2.hw, + [RPMH_RF_CLK5_A] = &clk_rpmh_clk5_a2_ao.hw, + [RPMH_IPA_CLK] = &clk_rpmh_ipa.hw, +}; + +static const struct clk_rpmh_desc clk_rpmh_sm8650 = { + .clks = sm8650_rpmh_clocks, + .num_clks = ARRAY_SIZE(sm8650_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, @@ -737,6 +771,28 @@ static const struct clk_rpmh_desc clk_rpmh_sm4450 = { .num_clks = ARRAY_SIZE(sm4450_rpmh_clocks), }; +static struct clk_hw *x1e80100_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_CLK3] = &clk_rpmh_clk3_a2.hw, + [RPMH_RF_CLK3_A] = &clk_rpmh_clk3_a2_ao.hw, + [RPMH_RF_CLK4] = &clk_rpmh_clk4_a2.hw, + [RPMH_RF_CLK4_A] = &clk_rpmh_clk4_a2_ao.hw, + [RPMH_RF_CLK5] = &clk_rpmh_clk5_a2.hw, + [RPMH_RF_CLK5_A] = &clk_rpmh_clk5_a2_ao.hw, +}; + +static const struct clk_rpmh_desc clk_rpmh_x1e80100 = { + .clks = x1e80100_rpmh_clocks, + .num_clks = ARRAY_SIZE(x1e80100_rpmh_clocks), +}; + static struct clk_hw *of_clk_rpmh_hw_get(struct of_phandle_args *clkspec, void *data) { @@ -837,7 +893,9 @@ static const struct of_device_id clk_rpmh_match_table[] = { { .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,sm8650-rpmh-clk", .data = &clk_rpmh_sm8650}, { .compatible = "qcom,sc7280-rpmh-clk", .data = &clk_rpmh_sc7280}, + { .compatible = "qcom,x1e80100-rpmh-clk", .data = &clk_rpmh_x1e80100}, { } }; MODULE_DEVICE_TABLE(of, clk_rpmh_match_table); diff --git a/drivers/clk/qcom/dispcc-sm8550.c b/drivers/clk/qcom/dispcc-sm8550.c index aefa19f3c2c514..f96d8b81fd9adb 100644 --- a/drivers/clk/qcom/dispcc-sm8550.c +++ b/drivers/clk/qcom/dispcc-sm8550.c @@ -81,6 +81,10 @@ static const struct alpha_pll_config disp_cc_pll0_config = { .config_ctl_val = 0x20485699, .config_ctl_hi_val = 0x00182261, .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, .user_ctl_val = 0x00000000, .user_ctl_hi_val = 0x00000005, }; @@ -108,6 +112,10 @@ static const struct alpha_pll_config disp_cc_pll1_config = { .config_ctl_val = 0x20485699, .config_ctl_hi_val = 0x00182261, .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, .user_ctl_val = 0x00000000, .user_ctl_hi_val = 0x00000005, }; @@ -1766,8 +1774,8 @@ static int disp_cc_sm8550_probe(struct platform_device *pdev) goto err_put_rpm; } - 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); + clk_lucid_ole_pll_configure(&disp_cc_pll0, regmap, &disp_cc_pll0_config); + clk_lucid_ole_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); diff --git a/drivers/clk/qcom/dispcc-sm8650.c b/drivers/clk/qcom/dispcc-sm8650.c new file mode 100644 index 00000000000000..f3b1d9d16baeab --- /dev/null +++ b/drivers/clk/qcom/dispcc-sm8650.c @@ -0,0 +1,1818 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved + * Copyright (c) 2023, Linaro Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#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 "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, 2100000000, 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, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .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 = &(const 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, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .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 = &(const 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_DP0_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, 2 }, + { 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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(200000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + F(325000000, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + F(402000000, 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const struct clk_init_data) { + .name = "disp_cc_mdss_dptx1_usb_router_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_dptx2_aux_clk = { + .halt_reg = 0x808c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x808c, + .enable_mask = BIT(0), + .hw.init = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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 = &(const 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_sm8650_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_sm8650_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_sm8650_gdscs[] = { + [MDSS_GDSC] = &mdss_gdsc, + [MDSS_INT2_GDSC] = &mdss_int2_gdsc, +}; + +static const struct regmap_config disp_cc_sm8650_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x11008, + .fast_io = true, +}; + +static struct qcom_cc_desc disp_cc_sm8650_desc = { + .config = &disp_cc_sm8650_regmap_config, + .clks = disp_cc_sm8650_clocks, + .num_clks = ARRAY_SIZE(disp_cc_sm8650_clocks), + .resets = disp_cc_sm8650_resets, + .num_resets = ARRAY_SIZE(disp_cc_sm8650_resets), + .gdscs = disp_cc_sm8650_gdscs, + .num_gdscs = ARRAY_SIZE(disp_cc_sm8650_gdscs), +}; + +static const struct of_device_id disp_cc_sm8650_match_table[] = { + { .compatible = "qcom,sm8650-dispcc" }, + { } +}; +MODULE_DEVICE_TABLE(of, disp_cc_sm8650_match_table); + +static int disp_cc_sm8650_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_sm8650_desc); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + goto err_put_rpm; + } + + clk_lucid_ole_pll_configure(&disp_cc_pll0, regmap, &disp_cc_pll0_config); + clk_lucid_ole_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 */ + regmap_update_bits(regmap, 0xe054, BIT(0), BIT(0)); /* disp_cc_xo_clk */ + + ret = qcom_cc_really_probe(pdev, &disp_cc_sm8650_desc, regmap); + if (ret) + goto err_put_rpm; + + pm_runtime_put(&pdev->dev); + + return 0; + +err_put_rpm: + pm_runtime_put_sync(&pdev->dev); + + return ret; +} + +static struct platform_driver disp_cc_sm8650_driver = { + .probe = disp_cc_sm8650_probe, + .driver = { + .name = "disp_cc-sm8650", + .of_match_table = disp_cc_sm8650_match_table, + }, +}; + +static int __init disp_cc_sm8650_init(void) +{ + return platform_driver_register(&disp_cc_sm8650_driver); +} +subsys_initcall(disp_cc_sm8650_init); + +static void __exit disp_cc_sm8650_exit(void) +{ + platform_driver_unregister(&disp_cc_sm8650_driver); +} +module_exit(disp_cc_sm8650_exit); + +MODULE_DESCRIPTION("QTI DISPCC SM8650 Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/qcom/ecpricc-qdu1000.c b/drivers/clk/qcom/ecpricc-qdu1000.c new file mode 100644 index 00000000000000..c628054a70251f --- /dev/null +++ b/drivers/clk/qcom/ecpricc-qdu1000.c @@ -0,0 +1,2456 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include + +#include + +#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 "common.h" +#include "reset.h" + +enum { + DT_BI_TCXO, + DT_GCC_ECPRI_CC_GPLL0_OUT_MAIN, + DT_GCC_ECPRI_CC_GPLL1_OUT_EVEN, + DT_GCC_ECPRI_CC_GPLL2_OUT_MAIN, + DT_GCC_ECPRI_CC_GPLL3_OUT_MAIN, + DT_GCC_ECPRI_CC_GPLL4_OUT_MAIN, + DT_GCC_ECPRI_CC_GPLL5_OUT_EVEN, +}; + +enum { + P_BI_TCXO, + P_ECPRI_CC_PLL0_OUT_MAIN, + P_ECPRI_CC_PLL1_OUT_MAIN, + P_GCC_ECPRI_CC_GPLL0_OUT_MAIN, + P_GCC_ECPRI_CC_GPLL1_OUT_EVEN, + P_GCC_ECPRI_CC_GPLL2_OUT_MAIN, + P_GCC_ECPRI_CC_GPLL3_OUT_MAIN, + P_GCC_ECPRI_CC_GPLL4_OUT_MAIN, + P_GCC_ECPRI_CC_GPLL5_OUT_EVEN, +}; + +static const struct pll_vco lucid_evo_vco[] = { + { 249600000, 2020000000, 0 }, +}; + +/* 700 MHz configuration */ +static const struct alpha_pll_config ecpri_cc_pll0_config = { + .l = 0x24, + .alpha = 0x7555, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x32aa299c, + .user_ctl_val = 0x00000000, + .user_ctl_hi_val = 0x00000805, +}; + +static struct clk_alpha_pll ecpri_cc_pll0 = { + .offset = 0x0, + .vco_table = lucid_evo_vco, + .num_vco = ARRAY_SIZE(lucid_evo_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO], + .clkr = { + .enable_reg = 0x0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_pll0", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_evo_ops, + }, + }, +}; + +/* 806 MHz configuration */ +static const struct alpha_pll_config ecpri_cc_pll1_config = { + .l = 0x29, + .alpha = 0xfaaa, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x32aa299c, + .user_ctl_val = 0x00000000, + .user_ctl_hi_val = 0x00000805, +}; + +static struct clk_alpha_pll ecpri_cc_pll1 = { + .offset = 0x1000, + .vco_table = lucid_evo_vco, + .num_vco = ARRAY_SIZE(lucid_evo_vco), + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_EVO], + .clkr = { + .enable_reg = 0x0, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_pll1", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_evo_ops, + }, + }, +}; + +static const struct parent_map ecpri_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_GCC_ECPRI_CC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_ECPRI_CC_GPLL2_OUT_MAIN, 2 }, + { P_GCC_ECPRI_CC_GPLL5_OUT_EVEN, 3 }, + { P_ECPRI_CC_PLL1_OUT_MAIN, 4 }, + { P_GCC_ECPRI_CC_GPLL4_OUT_MAIN, 5 }, + { P_ECPRI_CC_PLL0_OUT_MAIN, 6 }, +}; + +static const struct clk_parent_data ecpri_cc_parent_data_0[] = { + { .index = DT_BI_TCXO }, + { .index = DT_GCC_ECPRI_CC_GPLL0_OUT_MAIN }, + { .index = DT_GCC_ECPRI_CC_GPLL2_OUT_MAIN }, + { .index = DT_GCC_ECPRI_CC_GPLL5_OUT_EVEN }, + { .hw = &ecpri_cc_pll1.clkr.hw }, + { .index = DT_GCC_ECPRI_CC_GPLL4_OUT_MAIN }, + { .hw = &ecpri_cc_pll0.clkr.hw }, +}; + +static const struct parent_map ecpri_cc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_GCC_ECPRI_CC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_ECPRI_CC_GPLL1_OUT_EVEN, 2 }, + { P_GCC_ECPRI_CC_GPLL3_OUT_MAIN, 3 }, + { P_ECPRI_CC_PLL1_OUT_MAIN, 4 }, + { P_GCC_ECPRI_CC_GPLL4_OUT_MAIN, 5 }, + { P_ECPRI_CC_PLL0_OUT_MAIN, 6 }, +}; + +static const struct clk_parent_data ecpri_cc_parent_data_1[] = { + { .index = DT_BI_TCXO }, + { .index = DT_GCC_ECPRI_CC_GPLL0_OUT_MAIN }, + { .index = DT_GCC_ECPRI_CC_GPLL1_OUT_EVEN }, + { .index = DT_GCC_ECPRI_CC_GPLL3_OUT_MAIN }, + { .hw = &ecpri_cc_pll1.clkr.hw }, + { .index = DT_GCC_ECPRI_CC_GPLL4_OUT_MAIN }, + { .hw = &ecpri_cc_pll0.clkr.hw }, +}; + +static const struct parent_map ecpri_cc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_GCC_ECPRI_CC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_ECPRI_CC_GPLL5_OUT_EVEN, 3 }, + { P_ECPRI_CC_PLL1_OUT_MAIN, 4 }, + { P_GCC_ECPRI_CC_GPLL4_OUT_MAIN, 5 }, + { P_ECPRI_CC_PLL0_OUT_MAIN, 6 }, +}; + +static const struct clk_parent_data ecpri_cc_parent_data_2[] = { + { .index = DT_BI_TCXO }, + { .index = DT_GCC_ECPRI_CC_GPLL0_OUT_MAIN }, + { .index = DT_GCC_ECPRI_CC_GPLL5_OUT_EVEN }, + { .hw = &ecpri_cc_pll1.clkr.hw }, + { .index = DT_GCC_ECPRI_CC_GPLL4_OUT_MAIN }, + { .hw = &ecpri_cc_pll0.clkr.hw }, +}; + +static const struct freq_tbl ftbl_ecpri_cc_ecpri_clk_src[] = { + F(466500000, P_GCC_ECPRI_CC_GPLL5_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 ecpri_cc_ecpri_clk_src = { + .cmd_rcgr = 0x9034, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_2, + .freq_tbl = ftbl_ecpri_cc_ecpri_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_ecpri_clk_src", + .parent_data = ecpri_cc_parent_data_2, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_2), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_ecpri_cc_ecpri_dma_clk_src[] = { + F(466500000, P_GCC_ECPRI_CC_GPLL5_OUT_EVEN, 1, 0, 0), + F(500000000, P_GCC_ECPRI_CC_GPLL2_OUT_MAIN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 ecpri_cc_ecpri_dma_clk_src = { + .cmd_rcgr = 0x9080, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_0, + .freq_tbl = ftbl_ecpri_cc_ecpri_dma_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_ecpri_dma_clk_src", + .parent_data = ecpri_cc_parent_data_0, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_ecpri_cc_ecpri_fast_clk_src[] = { + F(500000000, P_GCC_ECPRI_CC_GPLL2_OUT_MAIN, 1, 0, 0), + F(600000000, P_GCC_ECPRI_CC_GPLL0_OUT_MAIN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 ecpri_cc_ecpri_fast_clk_src = { + .cmd_rcgr = 0x904c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_0, + .freq_tbl = ftbl_ecpri_cc_ecpri_fast_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_ecpri_fast_clk_src", + .parent_data = ecpri_cc_parent_data_0, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_ecpri_cc_ecpri_oran_clk_src[] = { + F(500000000, P_GCC_ECPRI_CC_GPLL2_OUT_MAIN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 ecpri_cc_ecpri_oran_clk_src = { + .cmd_rcgr = 0x9064, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_0, + .freq_tbl = ftbl_ecpri_cc_ecpri_oran_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_ecpri_oran_clk_src", + .parent_data = ecpri_cc_parent_data_0, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_ecpri_cc_eth_100g_c2c0_hm_ff_clk_src[] = { + F(201500000, P_ECPRI_CC_PLL1_OUT_MAIN, 4, 0, 0), + F(403000000, P_ECPRI_CC_PLL1_OUT_MAIN, 2, 0, 0), + F(466500000, P_GCC_ECPRI_CC_GPLL5_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 ecpri_cc_eth_100g_c2c0_hm_ff_clk_src = { + .cmd_rcgr = 0x81b0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_0, + .freq_tbl = ftbl_ecpri_cc_eth_100g_c2c0_hm_ff_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_c2c0_hm_ff_clk_src", + .parent_data = ecpri_cc_parent_data_0, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_ecpri_cc_eth_100g_c2c_hm_macsec_clk_src[] = { + F(100000000, P_GCC_ECPRI_CC_GPLL0_OUT_MAIN, 6, 0, 0), + F(200000000, P_GCC_ECPRI_CC_GPLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 ecpri_cc_eth_100g_c2c_hm_macsec_clk_src = { + .cmd_rcgr = 0x8150, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_0, + .freq_tbl = ftbl_ecpri_cc_eth_100g_c2c_hm_macsec_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_c2c_hm_macsec_clk_src", + .parent_data = ecpri_cc_parent_data_0, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 ecpri_cc_eth_100g_dbg_c2c_hm_ff_clk_src = { + .cmd_rcgr = 0x81c8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_0, + .freq_tbl = ftbl_ecpri_cc_eth_100g_c2c0_hm_ff_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_dbg_c2c_hm_ff_clk_src", + .parent_data = ecpri_cc_parent_data_0, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 ecpri_cc_eth_100g_fh0_hm_ff_clk_src = { + .cmd_rcgr = 0x8168, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_0, + .freq_tbl = ftbl_ecpri_cc_eth_100g_c2c0_hm_ff_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh0_hm_ff_clk_src", + .parent_data = ecpri_cc_parent_data_0, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 ecpri_cc_eth_100g_fh0_macsec_clk_src = { + .cmd_rcgr = 0x8108, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_0, + .freq_tbl = ftbl_ecpri_cc_eth_100g_c2c_hm_macsec_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh0_macsec_clk_src", + .parent_data = ecpri_cc_parent_data_0, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 ecpri_cc_eth_100g_fh1_hm_ff_clk_src = { + .cmd_rcgr = 0x8180, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_0, + .freq_tbl = ftbl_ecpri_cc_ecpri_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh1_hm_ff_clk_src", + .parent_data = ecpri_cc_parent_data_0, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_ecpri_cc_eth_100g_fh1_macsec_clk_src[] = { + F(200000000, P_GCC_ECPRI_CC_GPLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 ecpri_cc_eth_100g_fh1_macsec_clk_src = { + .cmd_rcgr = 0x8120, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_0, + .freq_tbl = ftbl_ecpri_cc_eth_100g_fh1_macsec_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh1_macsec_clk_src", + .parent_data = ecpri_cc_parent_data_0, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 ecpri_cc_eth_100g_fh2_hm_ff_clk_src = { + .cmd_rcgr = 0x8198, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_0, + .freq_tbl = ftbl_ecpri_cc_eth_100g_c2c0_hm_ff_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh2_hm_ff_clk_src", + .parent_data = ecpri_cc_parent_data_0, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 ecpri_cc_eth_100g_fh2_macsec_clk_src = { + .cmd_rcgr = 0x8138, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_0, + .freq_tbl = ftbl_ecpri_cc_eth_100g_fh1_macsec_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh2_macsec_clk_src", + .parent_data = ecpri_cc_parent_data_0, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_0), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_ecpri_cc_eth_100g_mac_c2c_hm_ref_clk_src[] = { + F(533000000, P_GCC_ECPRI_CC_GPLL1_OUT_EVEN, 1, 0, 0), + F(700000000, P_GCC_ECPRI_CC_GPLL3_OUT_MAIN, 1, 0, 0), + F(806000000, P_GCC_ECPRI_CC_GPLL4_OUT_MAIN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 ecpri_cc_eth_100g_mac_c2c_hm_ref_clk_src = { + .cmd_rcgr = 0x8228, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_1, + .freq_tbl = ftbl_ecpri_cc_eth_100g_mac_c2c_hm_ref_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_mac_c2c_hm_ref_clk_src", + .parent_data = ecpri_cc_parent_data_1, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_1), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 ecpri_cc_eth_100g_mac_dbg_c2c_hm_ref_clk_src = { + .cmd_rcgr = 0x8240, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_1, + .freq_tbl = ftbl_ecpri_cc_eth_100g_mac_c2c_hm_ref_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_mac_dbg_c2c_hm_ref_clk_src", + .parent_data = ecpri_cc_parent_data_1, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_1), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 ecpri_cc_eth_100g_mac_fh0_hm_ref_clk_src = { + .cmd_rcgr = 0x81e0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_1, + .freq_tbl = ftbl_ecpri_cc_eth_100g_mac_c2c_hm_ref_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_mac_fh0_hm_ref_clk_src", + .parent_data = ecpri_cc_parent_data_1, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_1), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 ecpri_cc_eth_100g_mac_fh1_hm_ref_clk_src = { + .cmd_rcgr = 0x81f8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_1, + .freq_tbl = ftbl_ecpri_cc_eth_100g_mac_c2c_hm_ref_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_mac_fh1_hm_ref_clk_src", + .parent_data = ecpri_cc_parent_data_1, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_1), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 ecpri_cc_eth_100g_mac_fh2_hm_ref_clk_src = { + .cmd_rcgr = 0x8210, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_1, + .freq_tbl = ftbl_ecpri_cc_eth_100g_mac_c2c_hm_ref_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_mac_fh2_hm_ref_clk_src", + .parent_data = ecpri_cc_parent_data_1, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_1), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_ecpri_cc_mss_emac_clk_src[] = { + F(403000000, P_GCC_ECPRI_CC_GPLL4_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 ecpri_cc_mss_emac_clk_src = { + .cmd_rcgr = 0xe00c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = ecpri_cc_parent_map_2, + .freq_tbl = ftbl_ecpri_cc_mss_emac_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_mss_emac_clk_src", + .parent_data = ecpri_cc_parent_data_2, + .num_parents = ARRAY_SIZE(ecpri_cc_parent_data_2), + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_ecpri_fast_div2_clk_src = { + .reg = 0x907c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_ecpri_fast_div2_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_fast_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_eth_100g_c2c_hm_ff_0_div_clk_src = { + .reg = 0x8290, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_c2c_hm_ff_0_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_c2c0_hm_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_eth_100g_c2c_hm_ff_1_div_clk_src = { + .reg = 0x8294, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_c2c_hm_ff_1_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_c2c0_hm_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_eth_100g_dbg_c2c_hm_ff_0_div_clk_src = { + .reg = 0x8298, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_dbg_c2c_hm_ff_0_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_dbg_c2c_hm_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_eth_100g_dbg_c2c_hm_ff_1_div_clk_src = { + .reg = 0x829c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_dbg_c2c_hm_ff_1_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_dbg_c2c_hm_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_eth_100g_fh_0_hm_ff_0_div_clk_src = { + .reg = 0x8260, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_0_hm_ff_0_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh0_hm_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_eth_100g_fh_0_hm_ff_1_div_clk_src = { + .reg = 0x8264, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_0_hm_ff_1_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh0_hm_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_eth_100g_fh_0_hm_ff_2_div_clk_src = { + .reg = 0x8268, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_0_hm_ff_2_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh0_hm_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_eth_100g_fh_0_hm_ff_3_div_clk_src = { + .reg = 0x826c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_0_hm_ff_3_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh0_hm_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_eth_100g_fh_1_hm_ff_0_div_clk_src = { + .reg = 0x8270, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_1_hm_ff_0_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh1_hm_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_eth_100g_fh_1_hm_ff_1_div_clk_src = { + .reg = 0x8274, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_1_hm_ff_1_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh1_hm_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_eth_100g_fh_1_hm_ff_2_div_clk_src = { + .reg = 0x8278, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_1_hm_ff_2_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh1_hm_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_eth_100g_fh_1_hm_ff_3_div_clk_src = { + .reg = 0x827c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_1_hm_ff_3_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh1_hm_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_eth_100g_fh_2_hm_ff_0_div_clk_src = { + .reg = 0x8280, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_2_hm_ff_0_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh2_hm_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_eth_100g_fh_2_hm_ff_1_div_clk_src = { + .reg = 0x8284, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_2_hm_ff_1_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh2_hm_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_eth_100g_fh_2_hm_ff_2_div_clk_src = { + .reg = 0x8288, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_2_hm_ff_2_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh2_hm_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div ecpri_cc_eth_100g_fh_2_hm_ff_3_div_clk_src = { + .reg = 0x828c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_2_hm_ff_3_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh2_hm_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_branch ecpri_cc_ecpri_cg_clk = { + .halt_reg = 0x900c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x900c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_ecpri_cg_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_ecpri_dma_clk = { + .halt_reg = 0x902c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x902c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_ecpri_dma_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_dma_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_ecpri_dma_noc_clk = { + .halt_reg = 0xf004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_ecpri_dma_noc_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_dma_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_ecpri_fast_clk = { + .halt_reg = 0x9014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_ecpri_fast_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_fast_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_ecpri_fast_div2_clk = { + .halt_reg = 0x901c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x901c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_ecpri_fast_div2_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_fast_div2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_ecpri_fast_div2_noc_clk = { + .halt_reg = 0xf008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xf008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_ecpri_fast_div2_noc_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_fast_div2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_ecpri_fr_clk = { + .halt_reg = 0x9004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_ecpri_fr_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_ecpri_oran_div2_clk = { + .halt_reg = 0x9024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_ecpri_oran_div2_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_oran_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_eth_100g_c2c0_udp_fifo_clk = { + .halt_reg = 0x80cc, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80cc, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_c2c0_udp_fifo_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_eth_100g_c2c1_udp_fifo_clk = { + .halt_reg = 0x80d0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80d0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_c2c1_udp_fifo_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_c2c_0_hm_ff_0_clk = { + .mem_enable_reg = 0x8410, + .mem_ack_reg = 0x8424, + .mem_enable_ack_mask = BIT(0), + .branch = { + .halt_reg = 0x80b4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80b4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_c2c_0_hm_ff_0_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_c2c_hm_ff_0_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_c2c_0_hm_ff_1_clk = { + .mem_enable_reg = 0x8410, + .mem_ack_reg = 0x8424, + .mem_enable_ack_mask = BIT(1), + .branch = { + .halt_reg = 0x80bc, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80bc, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_c2c_0_hm_ff_1_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_c2c_hm_ff_1_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_c2c_hm_macsec_clk = { + .mem_enable_reg = 0x8410, + .mem_ack_reg = 0x8424, + .mem_enable_ack_mask = BIT(4), + .branch = { + .halt_reg = 0x80ac, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80ac, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_c2c_hm_macsec_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_c2c_hm_macsec_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_dbg_c2c_hm_ff_0_clk = { + .mem_enable_reg = 0x8414, + .mem_ack_reg = 0x8428, + .mem_enable_ack_mask = BIT(0), + .branch = { + .halt_reg = 0x80d8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80d8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_dbg_c2c_hm_ff_0_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_dbg_c2c_hm_ff_0_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_dbg_c2c_hm_ff_1_clk = { + .mem_enable_reg = 0x8414, + .mem_ack_reg = 0x8428, + .mem_enable_ack_mask = BIT(1), + .branch = { + .halt_reg = 0x80e0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80e0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_dbg_c2c_hm_ff_1_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_dbg_c2c_hm_ff_1_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_branch ecpri_cc_eth_100g_dbg_c2c_udp_fifo_clk = { + .halt_reg = 0x80f0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80f0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_dbg_c2c_udp_fifo_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_fh_0_hm_ff_0_clk = { + .mem_enable_reg = 0x8404, + .mem_ack_reg = 0x8418, + .mem_enable_ack_mask = BIT(0), + .branch = { + .halt_reg = 0x800c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x800c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_0_hm_ff_0_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh_0_hm_ff_0_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_fh_0_hm_ff_1_clk = { + .mem_enable_reg = 0x8404, + .mem_ack_reg = 0x8418, + .mem_enable_ack_mask = BIT(1), + .branch = { + .halt_reg = 0x8014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_0_hm_ff_1_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh_0_hm_ff_1_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_fh_0_hm_ff_2_clk = { + .mem_enable_reg = 0x8404, + .mem_ack_reg = 0x8418, + .mem_enable_ack_mask = BIT(2), + .branch = { + .halt_reg = 0x801c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x801c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_0_hm_ff_2_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh_0_hm_ff_2_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_fh_0_hm_ff_3_clk = { + .mem_enable_reg = 0x8404, + .mem_ack_reg = 0x8418, + .mem_enable_ack_mask = BIT(3), + .branch = { + .halt_reg = 0x8024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_0_hm_ff_3_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh_0_hm_ff_3_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_branch ecpri_cc_eth_100g_fh_0_udp_fifo_clk = { + .halt_reg = 0x8034, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8034, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_0_udp_fifo_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_fh_1_hm_ff_0_clk = { + .mem_enable_reg = 0x8408, + .mem_ack_reg = 0x841c, + .mem_enable_ack_mask = BIT(0), + .branch = { + .halt_reg = 0x8044, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8044, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_1_hm_ff_0_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh_1_hm_ff_0_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_fh_1_hm_ff_1_clk = { + .mem_enable_reg = 0x8408, + .mem_ack_reg = 0x841c, + .mem_enable_ack_mask = BIT(1), + .branch = { + .halt_reg = 0x804c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x804c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_1_hm_ff_1_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh_1_hm_ff_1_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_fh_1_hm_ff_2_clk = { + .mem_enable_reg = 0x8408, + .mem_ack_reg = 0x841c, + .mem_enable_ack_mask = BIT(2), + .branch = { + .halt_reg = 0x8054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8054, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_1_hm_ff_2_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh_1_hm_ff_2_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_fh_1_hm_ff_3_clk = { + .mem_enable_reg = 0x8408, + .mem_ack_reg = 0x841c, + .mem_enable_ack_mask = BIT(3), + .branch = { + .halt_reg = 0x805c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x805c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_1_hm_ff_3_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh_1_hm_ff_3_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_branch ecpri_cc_eth_100g_fh_1_udp_fifo_clk = { + .halt_reg = 0x806c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x806c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_1_udp_fifo_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_fh_2_hm_ff_0_clk = { + .mem_enable_reg = 0x840c, + .mem_ack_reg = 0x8420, + .mem_enable_ack_mask = BIT(0), + .branch = { + .halt_reg = 0x807c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x807c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_2_hm_ff_0_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh_2_hm_ff_0_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_fh_2_hm_ff_1_clk = { + .mem_enable_reg = 0x840c, + .mem_ack_reg = 0x8420, + .mem_enable_ack_mask = BIT(1), + .branch = { + .halt_reg = 0x8084, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8084, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_2_hm_ff_1_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh_2_hm_ff_1_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_fh_2_hm_ff_2_clk = { + .mem_enable_reg = 0x840c, + .mem_ack_reg = 0x8420, + .mem_enable_ack_mask = BIT(2), + .branch = { + .halt_reg = 0x808c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x808c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_2_hm_ff_2_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh_2_hm_ff_2_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_fh_2_hm_ff_3_clk = { + .mem_enable_reg = 0x840c, + .mem_ack_reg = 0x8420, + .mem_enable_ack_mask = BIT(3), + .branch = { + .halt_reg = 0x8094, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8094, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_2_hm_ff_3_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh_2_hm_ff_3_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_branch ecpri_cc_eth_100g_fh_2_udp_fifo_clk = { + .halt_reg = 0x80a4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80a4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_2_udp_fifo_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_fh_macsec_0_clk = { + .mem_enable_reg = 0x8404, + .mem_ack_reg = 0x8418, + .mem_enable_ack_mask = BIT(4), + .branch = { + .halt_reg = 0x8004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_macsec_0_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh0_macsec_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_fh_macsec_1_clk = { + .mem_enable_reg = 0x8408, + .mem_ack_reg = 0x841c, + .mem_enable_ack_mask = BIT(4), + .branch = { + .halt_reg = 0x803c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x803c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_macsec_1_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh1_macsec_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_fh_macsec_2_clk = { + .mem_enable_reg = 0x840c, + .mem_ack_reg = 0x8420, + .mem_enable_ack_mask = BIT(4), + .branch = { + .halt_reg = 0x8074, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8074, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_fh_macsec_2_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_fh2_macsec_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_mac_c2c_hm_ref_clk = { + .mem_enable_reg = 0x8410, + .mem_ack_reg = 0x8424, + .mem_enable_ack_mask = BIT(5), + .branch = { + .halt_reg = 0x80c4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80c4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_mac_c2c_hm_ref_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_mac_c2c_hm_ref_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_mac_dbg_c2c_hm_ref_clk = { + .mem_enable_reg = 0x8414, + .mem_ack_reg = 0x8428, + .mem_enable_ack_mask = BIT(5), + .branch = { + .halt_reg = 0x80e8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80e8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_mac_dbg_c2c_hm_ref_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_mac_dbg_c2c_hm_ref_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_mac_fh0_hm_ref_clk = { + .mem_enable_reg = 0x8404, + .mem_ack_reg = 0x8418, + .mem_enable_ack_mask = BIT(5), + .branch = { + .halt_reg = 0x802c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x802c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_mac_fh0_hm_ref_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_mac_fh0_hm_ref_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_mac_fh1_hm_ref_clk = { + .mem_enable_reg = 0x8408, + .mem_ack_reg = 0x841c, + .mem_enable_ack_mask = BIT(5), + .branch = { + .halt_reg = 0x8064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8064, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_mac_fh1_hm_ref_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_mac_fh1_hm_ref_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_100g_mac_fh2_hm_ref_clk = { + .mem_enable_reg = 0x840c, + .mem_ack_reg = 0x8420, + .mem_enable_ack_mask = BIT(5), + .branch = { + .halt_reg = 0x809c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x809c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_100g_mac_fh2_hm_ref_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_eth_100g_mac_fh2_hm_ref_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_branch ecpri_cc_eth_dbg_nfapi_axi_clk = { + .halt_reg = 0x80f4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80f4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_dbg_nfapi_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_dma_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_eth_dbg_noc_axi_clk = { + .halt_reg = 0x80fc, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x80fc, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_dbg_noc_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_mss_emac_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_phy_0_ock_sram_clk = { + .mem_enable_reg = 0x8404, + .mem_ack_reg = 0x8418, + .mem_enable_ack_mask = BIT(6), + .branch = { + .halt_reg = 0xd140, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd140, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_phy_0_ock_sram_clk", + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_phy_1_ock_sram_clk = { + .mem_enable_reg = 0x8408, + .mem_ack_reg = 0x841C, + .mem_enable_ack_mask = BIT(6), + .branch = { + .halt_reg = 0xd148, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd148, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_phy_1_ock_sram_clk", + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_phy_2_ock_sram_clk = { + .mem_enable_reg = 0x840c, + .mem_ack_reg = 0x8420, + .mem_enable_ack_mask = BIT(6), + .branch = { + .halt_reg = 0xd150, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd150, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_phy_2_ock_sram_clk", + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_phy_3_ock_sram_clk = { + .mem_enable_reg = 0x8410, + .mem_ack_reg = 0x8424, + .mem_enable_ack_mask = BIT(6), + .branch = { + .halt_reg = 0xd158, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd158, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_phy_3_ock_sram_clk", + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_mem_branch ecpri_cc_eth_phy_4_ock_sram_clk = { + .mem_enable_reg = 0x8414, + .mem_ack_reg = 0x8428, + .mem_enable_ack_mask = BIT(6), + .branch = { + .halt_reg = 0xd160, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd160, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_eth_phy_4_ock_sram_clk", + .ops = &clk_branch2_mem_ops, + }, + }, + }, +}; + +static struct clk_branch ecpri_cc_mss_emac_clk = { + .halt_reg = 0xe008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xe008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_mss_emac_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_mss_emac_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_mss_oran_clk = { + .halt_reg = 0xe004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xe004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_mss_oran_clk", + .parent_hws = (const struct clk_hw*[]) { + &ecpri_cc_ecpri_oran_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy0_lane0_rx_clk = { + .halt_reg = 0xd000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd000, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy0_lane0_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy0_lane0_tx_clk = { + .halt_reg = 0xd050, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd050, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy0_lane0_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy0_lane1_rx_clk = { + .halt_reg = 0xd004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy0_lane1_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy0_lane1_tx_clk = { + .halt_reg = 0xd054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd054, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy0_lane1_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy0_lane2_rx_clk = { + .halt_reg = 0xd008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy0_lane2_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy0_lane2_tx_clk = { + .halt_reg = 0xd058, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd058, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy0_lane2_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy0_lane3_rx_clk = { + .halt_reg = 0xd00c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd00c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy0_lane3_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy0_lane3_tx_clk = { + .halt_reg = 0xd05c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd05c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy0_lane3_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy1_lane0_rx_clk = { + .halt_reg = 0xd010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy1_lane0_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy1_lane0_tx_clk = { + .halt_reg = 0xd060, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd060, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy1_lane0_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy1_lane1_rx_clk = { + .halt_reg = 0xd014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy1_lane1_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy1_lane1_tx_clk = { + .halt_reg = 0xd064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd064, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy1_lane1_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy1_lane2_rx_clk = { + .halt_reg = 0xd018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy1_lane2_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy1_lane2_tx_clk = { + .halt_reg = 0xd068, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd068, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy1_lane2_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy1_lane3_rx_clk = { + .halt_reg = 0xd01c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd01c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy1_lane3_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy1_lane3_tx_clk = { + .halt_reg = 0xd06c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd06c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy1_lane3_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy2_lane0_rx_clk = { + .halt_reg = 0xd020, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd020, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy2_lane0_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy2_lane0_tx_clk = { + .halt_reg = 0xd070, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd070, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy2_lane0_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy2_lane1_rx_clk = { + .halt_reg = 0xd024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy2_lane1_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy2_lane1_tx_clk = { + .halt_reg = 0xd074, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd074, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy2_lane1_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy2_lane2_rx_clk = { + .halt_reg = 0xd028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd028, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy2_lane2_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy2_lane2_tx_clk = { + .halt_reg = 0xd078, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd078, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy2_lane2_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy2_lane3_rx_clk = { + .halt_reg = 0xd02c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd02c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy2_lane3_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy2_lane3_tx_clk = { + .halt_reg = 0xd07c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd07c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy2_lane3_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy3_lane0_rx_clk = { + .halt_reg = 0xd030, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd030, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy3_lane0_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy3_lane0_tx_clk = { + .halt_reg = 0xd080, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd080, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy3_lane0_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy3_lane1_rx_clk = { + .halt_reg = 0xd034, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd034, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy3_lane1_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy3_lane1_tx_clk = { + .halt_reg = 0xd084, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd084, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy3_lane1_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy3_lane2_rx_clk = { + .halt_reg = 0xd038, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd038, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy3_lane2_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy3_lane2_tx_clk = { + .halt_reg = 0xd088, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd088, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy3_lane2_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy3_lane3_rx_clk = { + .halt_reg = 0xd03c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd03c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy3_lane3_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy3_lane3_tx_clk = { + .halt_reg = 0xd08c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd08c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy3_lane3_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy4_lane0_rx_clk = { + .halt_reg = 0xd040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd040, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy4_lane0_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy4_lane0_tx_clk = { + .halt_reg = 0xd090, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd090, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy4_lane0_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy4_lane1_rx_clk = { + .halt_reg = 0xd044, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd044, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy4_lane1_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy4_lane1_tx_clk = { + .halt_reg = 0xd094, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd094, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy4_lane1_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy4_lane2_rx_clk = { + .halt_reg = 0xd048, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd048, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy4_lane2_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy4_lane2_tx_clk = { + .halt_reg = 0xd098, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd098, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy4_lane2_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy4_lane3_rx_clk = { + .halt_reg = 0xd04c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd04c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy4_lane3_rx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch ecpri_cc_phy4_lane3_tx_clk = { + .halt_reg = 0xd09c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xd09c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "ecpri_cc_phy4_lane3_tx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap *ecpri_cc_qdu1000_clocks[] = { + [ECPRI_CC_ECPRI_CG_CLK] = &ecpri_cc_ecpri_cg_clk.clkr, + [ECPRI_CC_ECPRI_CLK_SRC] = &ecpri_cc_ecpri_clk_src.clkr, + [ECPRI_CC_ECPRI_DMA_CLK] = &ecpri_cc_ecpri_dma_clk.clkr, + [ECPRI_CC_ECPRI_DMA_CLK_SRC] = &ecpri_cc_ecpri_dma_clk_src.clkr, + [ECPRI_CC_ECPRI_DMA_NOC_CLK] = &ecpri_cc_ecpri_dma_noc_clk.clkr, + [ECPRI_CC_ECPRI_FAST_CLK] = &ecpri_cc_ecpri_fast_clk.clkr, + [ECPRI_CC_ECPRI_FAST_CLK_SRC] = &ecpri_cc_ecpri_fast_clk_src.clkr, + [ECPRI_CC_ECPRI_FAST_DIV2_CLK] = &ecpri_cc_ecpri_fast_div2_clk.clkr, + [ECPRI_CC_ECPRI_FAST_DIV2_CLK_SRC] = &ecpri_cc_ecpri_fast_div2_clk_src.clkr, + [ECPRI_CC_ECPRI_FAST_DIV2_NOC_CLK] = &ecpri_cc_ecpri_fast_div2_noc_clk.clkr, + [ECPRI_CC_ECPRI_FR_CLK] = &ecpri_cc_ecpri_fr_clk.clkr, + [ECPRI_CC_ECPRI_ORAN_CLK_SRC] = &ecpri_cc_ecpri_oran_clk_src.clkr, + [ECPRI_CC_ECPRI_ORAN_DIV2_CLK] = &ecpri_cc_ecpri_oran_div2_clk.clkr, + [ECPRI_CC_ETH_100G_C2C0_HM_FF_CLK_SRC] = &ecpri_cc_eth_100g_c2c0_hm_ff_clk_src.clkr, + [ECPRI_CC_ETH_100G_C2C0_UDP_FIFO_CLK] = &ecpri_cc_eth_100g_c2c0_udp_fifo_clk.clkr, + [ECPRI_CC_ETH_100G_C2C1_UDP_FIFO_CLK] = &ecpri_cc_eth_100g_c2c1_udp_fifo_clk.clkr, + [ECPRI_CC_ETH_100G_C2C_0_HM_FF_0_CLK] = &ecpri_cc_eth_100g_c2c_0_hm_ff_0_clk.branch.clkr, + [ECPRI_CC_ETH_100G_C2C_0_HM_FF_1_CLK] = &ecpri_cc_eth_100g_c2c_0_hm_ff_1_clk.branch.clkr, + [ECPRI_CC_ETH_100G_C2C_HM_FF_0_DIV_CLK_SRC] = + &ecpri_cc_eth_100g_c2c_hm_ff_0_div_clk_src.clkr, + [ECPRI_CC_ETH_100G_C2C_HM_FF_1_DIV_CLK_SRC] = + &ecpri_cc_eth_100g_c2c_hm_ff_1_div_clk_src.clkr, + [ECPRI_CC_ETH_100G_C2C_HM_MACSEC_CLK] = &ecpri_cc_eth_100g_c2c_hm_macsec_clk.branch.clkr, + [ECPRI_CC_ETH_100G_C2C_HM_MACSEC_CLK_SRC] = &ecpri_cc_eth_100g_c2c_hm_macsec_clk_src.clkr, + [ECPRI_CC_ETH_100G_DBG_C2C_HM_FF_0_CLK] = + &ecpri_cc_eth_100g_dbg_c2c_hm_ff_0_clk.branch.clkr, + [ECPRI_CC_ETH_100G_DBG_C2C_HM_FF_0_DIV_CLK_SRC] = + &ecpri_cc_eth_100g_dbg_c2c_hm_ff_0_div_clk_src.clkr, + [ECPRI_CC_ETH_100G_DBG_C2C_HM_FF_1_CLK] = + &ecpri_cc_eth_100g_dbg_c2c_hm_ff_1_clk.branch.clkr, + [ECPRI_CC_ETH_100G_DBG_C2C_HM_FF_1_DIV_CLK_SRC] = + &ecpri_cc_eth_100g_dbg_c2c_hm_ff_1_div_clk_src.clkr, + [ECPRI_CC_ETH_100G_DBG_C2C_HM_FF_CLK_SRC] = &ecpri_cc_eth_100g_dbg_c2c_hm_ff_clk_src.clkr, + [ECPRI_CC_ETH_100G_DBG_C2C_UDP_FIFO_CLK] = &ecpri_cc_eth_100g_dbg_c2c_udp_fifo_clk.clkr, + [ECPRI_CC_ETH_100G_FH0_HM_FF_CLK_SRC] = &ecpri_cc_eth_100g_fh0_hm_ff_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH0_MACSEC_CLK_SRC] = &ecpri_cc_eth_100g_fh0_macsec_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH1_HM_FF_CLK_SRC] = &ecpri_cc_eth_100g_fh1_hm_ff_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH1_MACSEC_CLK_SRC] = &ecpri_cc_eth_100g_fh1_macsec_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH2_HM_FF_CLK_SRC] = &ecpri_cc_eth_100g_fh2_hm_ff_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH2_MACSEC_CLK_SRC] = &ecpri_cc_eth_100g_fh2_macsec_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH_0_HM_FF_0_CLK] = &ecpri_cc_eth_100g_fh_0_hm_ff_0_clk.branch.clkr, + [ECPRI_CC_ETH_100G_FH_0_HM_FF_0_DIV_CLK_SRC] = + &ecpri_cc_eth_100g_fh_0_hm_ff_0_div_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH_0_HM_FF_1_CLK] = &ecpri_cc_eth_100g_fh_0_hm_ff_1_clk.branch.clkr, + [ECPRI_CC_ETH_100G_FH_0_HM_FF_1_DIV_CLK_SRC] = + &ecpri_cc_eth_100g_fh_0_hm_ff_1_div_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH_0_HM_FF_2_CLK] = &ecpri_cc_eth_100g_fh_0_hm_ff_2_clk.branch.clkr, + [ECPRI_CC_ETH_100G_FH_0_HM_FF_2_DIV_CLK_SRC] = + &ecpri_cc_eth_100g_fh_0_hm_ff_2_div_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH_0_HM_FF_3_CLK] = &ecpri_cc_eth_100g_fh_0_hm_ff_3_clk.branch.clkr, + [ECPRI_CC_ETH_100G_FH_0_HM_FF_3_DIV_CLK_SRC] = + &ecpri_cc_eth_100g_fh_0_hm_ff_3_div_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH_0_UDP_FIFO_CLK] = &ecpri_cc_eth_100g_fh_0_udp_fifo_clk.clkr, + [ECPRI_CC_ETH_100G_FH_1_HM_FF_0_CLK] = &ecpri_cc_eth_100g_fh_1_hm_ff_0_clk.branch.clkr, + [ECPRI_CC_ETH_100G_FH_1_HM_FF_0_DIV_CLK_SRC] = + &ecpri_cc_eth_100g_fh_1_hm_ff_0_div_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH_1_HM_FF_1_CLK] = &ecpri_cc_eth_100g_fh_1_hm_ff_1_clk.branch.clkr, + [ECPRI_CC_ETH_100G_FH_1_HM_FF_1_DIV_CLK_SRC] = + &ecpri_cc_eth_100g_fh_1_hm_ff_1_div_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH_1_HM_FF_2_CLK] = &ecpri_cc_eth_100g_fh_1_hm_ff_2_clk.branch.clkr, + [ECPRI_CC_ETH_100G_FH_1_HM_FF_2_DIV_CLK_SRC] = + &ecpri_cc_eth_100g_fh_1_hm_ff_2_div_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH_1_HM_FF_3_CLK] = &ecpri_cc_eth_100g_fh_1_hm_ff_3_clk.branch.clkr, + [ECPRI_CC_ETH_100G_FH_1_HM_FF_3_DIV_CLK_SRC] = + &ecpri_cc_eth_100g_fh_1_hm_ff_3_div_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH_1_UDP_FIFO_CLK] = &ecpri_cc_eth_100g_fh_1_udp_fifo_clk.clkr, + [ECPRI_CC_ETH_100G_FH_2_HM_FF_0_CLK] = &ecpri_cc_eth_100g_fh_2_hm_ff_0_clk.branch.clkr, + [ECPRI_CC_ETH_100G_FH_2_HM_FF_0_DIV_CLK_SRC] = + &ecpri_cc_eth_100g_fh_2_hm_ff_0_div_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH_2_HM_FF_1_CLK] = &ecpri_cc_eth_100g_fh_2_hm_ff_1_clk.branch.clkr, + [ECPRI_CC_ETH_100G_FH_2_HM_FF_1_DIV_CLK_SRC] = + &ecpri_cc_eth_100g_fh_2_hm_ff_1_div_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH_2_HM_FF_2_CLK] = &ecpri_cc_eth_100g_fh_2_hm_ff_2_clk.branch.clkr, + [ECPRI_CC_ETH_100G_FH_2_HM_FF_2_DIV_CLK_SRC] = + &ecpri_cc_eth_100g_fh_2_hm_ff_2_div_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH_2_HM_FF_3_CLK] = &ecpri_cc_eth_100g_fh_2_hm_ff_3_clk.branch.clkr, + [ECPRI_CC_ETH_100G_FH_2_HM_FF_3_DIV_CLK_SRC] = + &ecpri_cc_eth_100g_fh_2_hm_ff_3_div_clk_src.clkr, + [ECPRI_CC_ETH_100G_FH_2_UDP_FIFO_CLK] = &ecpri_cc_eth_100g_fh_2_udp_fifo_clk.clkr, + [ECPRI_CC_ETH_100G_FH_MACSEC_0_CLK] = &ecpri_cc_eth_100g_fh_macsec_0_clk.branch.clkr, + [ECPRI_CC_ETH_100G_FH_MACSEC_1_CLK] = &ecpri_cc_eth_100g_fh_macsec_1_clk.branch.clkr, + [ECPRI_CC_ETH_100G_FH_MACSEC_2_CLK] = &ecpri_cc_eth_100g_fh_macsec_2_clk.branch.clkr, + [ECPRI_CC_ETH_100G_MAC_C2C_HM_REF_CLK] = &ecpri_cc_eth_100g_mac_c2c_hm_ref_clk.branch.clkr, + [ECPRI_CC_ETH_100G_MAC_C2C_HM_REF_CLK_SRC] = &ecpri_cc_eth_100g_mac_c2c_hm_ref_clk_src.clkr, + [ECPRI_CC_ETH_100G_MAC_DBG_C2C_HM_REF_CLK] = + &ecpri_cc_eth_100g_mac_dbg_c2c_hm_ref_clk.branch.clkr, + [ECPRI_CC_ETH_100G_MAC_DBG_C2C_HM_REF_CLK_SRC] = + &ecpri_cc_eth_100g_mac_dbg_c2c_hm_ref_clk_src.clkr, + [ECPRI_CC_ETH_100G_MAC_FH0_HM_REF_CLK] = &ecpri_cc_eth_100g_mac_fh0_hm_ref_clk.branch.clkr, + [ECPRI_CC_ETH_100G_MAC_FH0_HM_REF_CLK_SRC] = &ecpri_cc_eth_100g_mac_fh0_hm_ref_clk_src.clkr, + [ECPRI_CC_ETH_100G_MAC_FH1_HM_REF_CLK] = &ecpri_cc_eth_100g_mac_fh1_hm_ref_clk.branch.clkr, + [ECPRI_CC_ETH_100G_MAC_FH1_HM_REF_CLK_SRC] = &ecpri_cc_eth_100g_mac_fh1_hm_ref_clk_src.clkr, + [ECPRI_CC_ETH_100G_MAC_FH2_HM_REF_CLK] = &ecpri_cc_eth_100g_mac_fh2_hm_ref_clk.branch.clkr, + [ECPRI_CC_ETH_100G_MAC_FH2_HM_REF_CLK_SRC] = &ecpri_cc_eth_100g_mac_fh2_hm_ref_clk_src.clkr, + [ECPRI_CC_ETH_DBG_NFAPI_AXI_CLK] = &ecpri_cc_eth_dbg_nfapi_axi_clk.clkr, + [ECPRI_CC_ETH_DBG_NOC_AXI_CLK] = &ecpri_cc_eth_dbg_noc_axi_clk.clkr, + [ECPRI_CC_ETH_PHY_0_OCK_SRAM_CLK] = &ecpri_cc_eth_phy_0_ock_sram_clk.branch.clkr, + [ECPRI_CC_ETH_PHY_1_OCK_SRAM_CLK] = &ecpri_cc_eth_phy_1_ock_sram_clk.branch.clkr, + [ECPRI_CC_ETH_PHY_2_OCK_SRAM_CLK] = &ecpri_cc_eth_phy_2_ock_sram_clk.branch.clkr, + [ECPRI_CC_ETH_PHY_3_OCK_SRAM_CLK] = &ecpri_cc_eth_phy_3_ock_sram_clk.branch.clkr, + [ECPRI_CC_ETH_PHY_4_OCK_SRAM_CLK] = &ecpri_cc_eth_phy_4_ock_sram_clk.branch.clkr, + [ECPRI_CC_MSS_EMAC_CLK] = &ecpri_cc_mss_emac_clk.clkr, + [ECPRI_CC_MSS_EMAC_CLK_SRC] = &ecpri_cc_mss_emac_clk_src.clkr, + [ECPRI_CC_MSS_ORAN_CLK] = &ecpri_cc_mss_oran_clk.clkr, + [ECPRI_CC_PHY0_LANE0_RX_CLK] = &ecpri_cc_phy0_lane0_rx_clk.clkr, + [ECPRI_CC_PHY0_LANE0_TX_CLK] = &ecpri_cc_phy0_lane0_tx_clk.clkr, + [ECPRI_CC_PHY0_LANE1_RX_CLK] = &ecpri_cc_phy0_lane1_rx_clk.clkr, + [ECPRI_CC_PHY0_LANE1_TX_CLK] = &ecpri_cc_phy0_lane1_tx_clk.clkr, + [ECPRI_CC_PHY0_LANE2_RX_CLK] = &ecpri_cc_phy0_lane2_rx_clk.clkr, + [ECPRI_CC_PHY0_LANE2_TX_CLK] = &ecpri_cc_phy0_lane2_tx_clk.clkr, + [ECPRI_CC_PHY0_LANE3_RX_CLK] = &ecpri_cc_phy0_lane3_rx_clk.clkr, + [ECPRI_CC_PHY0_LANE3_TX_CLK] = &ecpri_cc_phy0_lane3_tx_clk.clkr, + [ECPRI_CC_PHY1_LANE0_RX_CLK] = &ecpri_cc_phy1_lane0_rx_clk.clkr, + [ECPRI_CC_PHY1_LANE0_TX_CLK] = &ecpri_cc_phy1_lane0_tx_clk.clkr, + [ECPRI_CC_PHY1_LANE1_RX_CLK] = &ecpri_cc_phy1_lane1_rx_clk.clkr, + [ECPRI_CC_PHY1_LANE1_TX_CLK] = &ecpri_cc_phy1_lane1_tx_clk.clkr, + [ECPRI_CC_PHY1_LANE2_RX_CLK] = &ecpri_cc_phy1_lane2_rx_clk.clkr, + [ECPRI_CC_PHY1_LANE2_TX_CLK] = &ecpri_cc_phy1_lane2_tx_clk.clkr, + [ECPRI_CC_PHY1_LANE3_RX_CLK] = &ecpri_cc_phy1_lane3_rx_clk.clkr, + [ECPRI_CC_PHY1_LANE3_TX_CLK] = &ecpri_cc_phy1_lane3_tx_clk.clkr, + [ECPRI_CC_PHY2_LANE0_RX_CLK] = &ecpri_cc_phy2_lane0_rx_clk.clkr, + [ECPRI_CC_PHY2_LANE0_TX_CLK] = &ecpri_cc_phy2_lane0_tx_clk.clkr, + [ECPRI_CC_PHY2_LANE1_RX_CLK] = &ecpri_cc_phy2_lane1_rx_clk.clkr, + [ECPRI_CC_PHY2_LANE1_TX_CLK] = &ecpri_cc_phy2_lane1_tx_clk.clkr, + [ECPRI_CC_PHY2_LANE2_RX_CLK] = &ecpri_cc_phy2_lane2_rx_clk.clkr, + [ECPRI_CC_PHY2_LANE2_TX_CLK] = &ecpri_cc_phy2_lane2_tx_clk.clkr, + [ECPRI_CC_PHY2_LANE3_RX_CLK] = &ecpri_cc_phy2_lane3_rx_clk.clkr, + [ECPRI_CC_PHY2_LANE3_TX_CLK] = &ecpri_cc_phy2_lane3_tx_clk.clkr, + [ECPRI_CC_PHY3_LANE0_RX_CLK] = &ecpri_cc_phy3_lane0_rx_clk.clkr, + [ECPRI_CC_PHY3_LANE0_TX_CLK] = &ecpri_cc_phy3_lane0_tx_clk.clkr, + [ECPRI_CC_PHY3_LANE1_RX_CLK] = &ecpri_cc_phy3_lane1_rx_clk.clkr, + [ECPRI_CC_PHY3_LANE1_TX_CLK] = &ecpri_cc_phy3_lane1_tx_clk.clkr, + [ECPRI_CC_PHY3_LANE2_RX_CLK] = &ecpri_cc_phy3_lane2_rx_clk.clkr, + [ECPRI_CC_PHY3_LANE2_TX_CLK] = &ecpri_cc_phy3_lane2_tx_clk.clkr, + [ECPRI_CC_PHY3_LANE3_RX_CLK] = &ecpri_cc_phy3_lane3_rx_clk.clkr, + [ECPRI_CC_PHY3_LANE3_TX_CLK] = &ecpri_cc_phy3_lane3_tx_clk.clkr, + [ECPRI_CC_PHY4_LANE0_RX_CLK] = &ecpri_cc_phy4_lane0_rx_clk.clkr, + [ECPRI_CC_PHY4_LANE0_TX_CLK] = &ecpri_cc_phy4_lane0_tx_clk.clkr, + [ECPRI_CC_PHY4_LANE1_RX_CLK] = &ecpri_cc_phy4_lane1_rx_clk.clkr, + [ECPRI_CC_PHY4_LANE1_TX_CLK] = &ecpri_cc_phy4_lane1_tx_clk.clkr, + [ECPRI_CC_PHY4_LANE2_RX_CLK] = &ecpri_cc_phy4_lane2_rx_clk.clkr, + [ECPRI_CC_PHY4_LANE2_TX_CLK] = &ecpri_cc_phy4_lane2_tx_clk.clkr, + [ECPRI_CC_PHY4_LANE3_RX_CLK] = &ecpri_cc_phy4_lane3_rx_clk.clkr, + [ECPRI_CC_PHY4_LANE3_TX_CLK] = &ecpri_cc_phy4_lane3_tx_clk.clkr, + [ECPRI_CC_PLL0] = &ecpri_cc_pll0.clkr, + [ECPRI_CC_PLL1] = &ecpri_cc_pll1.clkr, +}; + +static const struct qcom_reset_map ecpri_cc_qdu1000_resets[] = { + [ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_ECPRI_SS_BCR] = { 0x9000 }, + [ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_ETH_C2C_BCR] = { 0x80a8 }, + [ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_ETH_FH0_BCR] = { 0x8000 }, + [ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_ETH_FH1_BCR] = { 0x8038 }, + [ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_ETH_FH2_BCR] = { 0x8070 }, + [ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_ETH_WRAPPER_TOP_BCR] = { 0x8104 }, + [ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_MODEM_BCR] = { 0xe000 }, + [ECPRI_CC_CLK_CTL_TOP_ECPRI_CC_NOC_BCR] = { 0xf000 }, +}; + +static const struct regmap_config ecpri_cc_qdu1000_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x31bf0, + .fast_io = true, +}; + +static const struct qcom_cc_desc ecpri_cc_qdu1000_desc = { + .config = &ecpri_cc_qdu1000_regmap_config, + .clks = ecpri_cc_qdu1000_clocks, + .num_clks = ARRAY_SIZE(ecpri_cc_qdu1000_clocks), + .resets = ecpri_cc_qdu1000_resets, + .num_resets = ARRAY_SIZE(ecpri_cc_qdu1000_resets), +}; + +static const struct of_device_id ecpri_cc_qdu1000_match_table[] = { + { .compatible = "qcom,qdu1000-ecpricc" }, + { } +}; +MODULE_DEVICE_TABLE(of, ecpri_cc_qdu1000_match_table); + +static int ecpri_cc_qdu1000_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + + regmap = qcom_cc_map(pdev, &ecpri_cc_qdu1000_desc); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + clk_lucid_evo_pll_configure(&ecpri_cc_pll0, regmap, &ecpri_cc_pll0_config); + clk_lucid_evo_pll_configure(&ecpri_cc_pll1, regmap, &ecpri_cc_pll1_config); + + return qcom_cc_really_probe(pdev, &ecpri_cc_qdu1000_desc, regmap); +} + +static struct platform_driver ecpri_cc_qdu1000_driver = { + .probe = ecpri_cc_qdu1000_probe, + .driver = { + .name = "ecpri_cc-qdu1000", + .of_match_table = ecpri_cc_qdu1000_match_table, + }, +}; + +module_platform_driver(ecpri_cc_qdu1000_driver); + +MODULE_DESCRIPTION("QTI ECPRICC QDU1000 Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/qcom/gcc-msm8939.c b/drivers/clk/qcom/gcc-msm8939.c index b45f97c07eeb6f..7b9a3e99b58920 100644 --- a/drivers/clk/qcom/gcc-msm8939.c +++ b/drivers/clk/qcom/gcc-msm8939.c @@ -696,7 +696,7 @@ static struct clk_rcg2 apss_ahb_clk_src = { }, }; -static const struct freq_tbl ftbl_gcc_camss_csi0_1_clk[] = { +static const struct freq_tbl ftbl_gcc_camss_csi0_1_2_clk[] = { F(100000000, P_GPLL0, 8, 0, 0), F(200000000, P_GPLL0, 4, 0, 0), { } @@ -706,7 +706,7 @@ static struct clk_rcg2 csi0_clk_src = { .cmd_rcgr = 0x4e020, .hid_width = 5, .parent_map = gcc_xo_gpll0_map, - .freq_tbl = ftbl_gcc_camss_csi0_1_clk, + .freq_tbl = ftbl_gcc_camss_csi0_1_2_clk, .clkr.hw.init = &(struct clk_init_data){ .name = "csi0_clk_src", .parent_data = gcc_xo_gpll0_parent_data, @@ -719,7 +719,7 @@ static struct clk_rcg2 csi1_clk_src = { .cmd_rcgr = 0x4f020, .hid_width = 5, .parent_map = gcc_xo_gpll0_map, - .freq_tbl = ftbl_gcc_camss_csi0_1_clk, + .freq_tbl = ftbl_gcc_camss_csi0_1_2_clk, .clkr.hw.init = &(struct clk_init_data){ .name = "csi1_clk_src", .parent_data = gcc_xo_gpll0_parent_data, @@ -728,6 +728,19 @@ static struct clk_rcg2 csi1_clk_src = { }, }; +static struct clk_rcg2 csi2_clk_src = { + .cmd_rcgr = 0x3c020, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_map, + .freq_tbl = ftbl_gcc_camss_csi0_1_2_clk, + .clkr.hw.init = &(struct clk_init_data){ + .name = "csi2_clk_src", + .parent_data = gcc_xo_gpll0_parent_data, + .num_parents = ARRAY_SIZE(gcc_xo_gpll0_parent_data), + .ops = &clk_rcg2_ops, + }, +}; + static const struct freq_tbl ftbl_gcc_oxili_gfx3d_clk[] = { F(19200000, P_XO, 1, 0, 0), F(50000000, P_GPLL0, 16, 0, 0), @@ -2385,6 +2398,91 @@ static struct clk_branch gcc_camss_csi1rdi_clk = { }, }; +static struct clk_branch gcc_camss_csi2_ahb_clk = { + .halt_reg = 0x3c040, + .clkr = { + .enable_reg = 0x3c040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_camss_csi2_ahb_clk", + .parent_hws = (const struct clk_hw*[]){ + &camss_ahb_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_camss_csi2_clk = { + .halt_reg = 0x3c03c, + .clkr = { + .enable_reg = 0x3c03c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_camss_csi2_clk", + .parent_hws = (const struct clk_hw*[]){ + &csi2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_camss_csi2phy_clk = { + .halt_reg = 0x3c048, + .clkr = { + .enable_reg = 0x3c048, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_camss_csi2phy_clk", + .parent_hws = (const struct clk_hw*[]){ + &csi2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_camss_csi2pix_clk = { + .halt_reg = 0x3c058, + .clkr = { + .enable_reg = 0x3c058, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_camss_csi2pix_clk", + .parent_hws = (const struct clk_hw*[]){ + &csi2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_camss_csi2rdi_clk = { + .halt_reg = 0x3c050, + .clkr = { + .enable_reg = 0x3c050, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_camss_csi2rdi_clk", + .parent_hws = (const struct clk_hw*[]){ + &csi2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch gcc_camss_csi_vfe0_clk = { .halt_reg = 0x58050, .clkr = { @@ -3682,6 +3780,7 @@ static struct clk_regmap *gcc_msm8939_clocks[] = { [APSS_AHB_CLK_SRC] = &apss_ahb_clk_src.clkr, [CSI0_CLK_SRC] = &csi0_clk_src.clkr, [CSI1_CLK_SRC] = &csi1_clk_src.clkr, + [CSI2_CLK_SRC] = &csi2_clk_src.clkr, [GFX3D_CLK_SRC] = &gfx3d_clk_src.clkr, [VFE0_CLK_SRC] = &vfe0_clk_src.clkr, [BLSP1_QUP1_I2C_APPS_CLK_SRC] = &blsp1_qup1_i2c_apps_clk_src.clkr, @@ -3751,6 +3850,11 @@ static struct clk_regmap *gcc_msm8939_clocks[] = { [GCC_CAMSS_CSI1PHY_CLK] = &gcc_camss_csi1phy_clk.clkr, [GCC_CAMSS_CSI1PIX_CLK] = &gcc_camss_csi1pix_clk.clkr, [GCC_CAMSS_CSI1RDI_CLK] = &gcc_camss_csi1rdi_clk.clkr, + [GCC_CAMSS_CSI2_AHB_CLK] = &gcc_camss_csi2_ahb_clk.clkr, + [GCC_CAMSS_CSI2_CLK] = &gcc_camss_csi2_clk.clkr, + [GCC_CAMSS_CSI2PHY_CLK] = &gcc_camss_csi2phy_clk.clkr, + [GCC_CAMSS_CSI2PIX_CLK] = &gcc_camss_csi2pix_clk.clkr, + [GCC_CAMSS_CSI2RDI_CLK] = &gcc_camss_csi2rdi_clk.clkr, [GCC_CAMSS_CSI_VFE0_CLK] = &gcc_camss_csi_vfe0_clk.clkr, [GCC_CAMSS_GP0_CLK] = &gcc_camss_gp0_clk.clkr, [GCC_CAMSS_GP1_CLK] = &gcc_camss_gp1_clk.clkr, diff --git a/drivers/clk/qcom/gcc-sm8550.c b/drivers/clk/qcom/gcc-sm8550.c index 586126c4dd907c..b883dffe5f7aaa 100644 --- a/drivers/clk/qcom/gcc-sm8550.c +++ b/drivers/clk/qcom/gcc-sm8550.c @@ -401,7 +401,7 @@ static struct clk_rcg2 gcc_gp1_clk_src = { .parent_data = gcc_parent_data_1, .num_parents = ARRAY_SIZE(gcc_parent_data_1), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -416,7 +416,7 @@ static struct clk_rcg2 gcc_gp2_clk_src = { .parent_data = gcc_parent_data_1, .num_parents = ARRAY_SIZE(gcc_parent_data_1), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -431,7 +431,7 @@ static struct clk_rcg2 gcc_gp3_clk_src = { .parent_data = gcc_parent_data_1, .num_parents = ARRAY_SIZE(gcc_parent_data_1), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -451,7 +451,7 @@ static struct clk_rcg2 gcc_pcie_0_aux_clk_src = { .parent_data = gcc_parent_data_2, .num_parents = ARRAY_SIZE(gcc_parent_data_2), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -471,7 +471,7 @@ static struct clk_rcg2 gcc_pcie_0_phy_rchng_clk_src = { .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -486,7 +486,7 @@ static struct clk_rcg2 gcc_pcie_1_aux_clk_src = { .parent_data = gcc_parent_data_2, .num_parents = ARRAY_SIZE(gcc_parent_data_2), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -501,7 +501,7 @@ static struct clk_rcg2 gcc_pcie_1_phy_rchng_clk_src = { .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -521,7 +521,7 @@ static struct clk_rcg2 gcc_pdm2_clk_src = { .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -536,7 +536,7 @@ static struct clk_rcg2 gcc_qupv3_i2c_s0_clk_src = { .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -551,7 +551,7 @@ static struct clk_rcg2 gcc_qupv3_i2c_s1_clk_src = { .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -566,7 +566,7 @@ static struct clk_rcg2 gcc_qupv3_i2c_s2_clk_src = { .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -581,7 +581,7 @@ static struct clk_rcg2 gcc_qupv3_i2c_s3_clk_src = { .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -596,7 +596,7 @@ static struct clk_rcg2 gcc_qupv3_i2c_s4_clk_src = { .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -611,7 +611,7 @@ static struct clk_rcg2 gcc_qupv3_i2c_s5_clk_src = { .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -626,7 +626,7 @@ static struct clk_rcg2 gcc_qupv3_i2c_s6_clk_src = { .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -641,7 +641,7 @@ static struct clk_rcg2 gcc_qupv3_i2c_s7_clk_src = { .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -656,7 +656,7 @@ static struct clk_rcg2 gcc_qupv3_i2c_s8_clk_src = { .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -671,7 +671,7 @@ static struct clk_rcg2 gcc_qupv3_i2c_s9_clk_src = { .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -700,7 +700,7 @@ static struct clk_init_data gcc_qupv3_wrap1_s0_clk_src_init = { .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }; static struct clk_rcg2 gcc_qupv3_wrap1_s0_clk_src = { @@ -717,7 +717,7 @@ static struct clk_init_data gcc_qupv3_wrap1_s1_clk_src_init = { .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }; static struct clk_rcg2 gcc_qupv3_wrap1_s1_clk_src = { @@ -750,7 +750,7 @@ static struct clk_init_data gcc_qupv3_wrap1_s2_clk_src_init = { .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }; static struct clk_rcg2 gcc_qupv3_wrap1_s2_clk_src = { @@ -767,7 +767,7 @@ static struct clk_init_data gcc_qupv3_wrap1_s3_clk_src_init = { .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }; static struct clk_rcg2 gcc_qupv3_wrap1_s3_clk_src = { @@ -784,7 +784,7 @@ static struct clk_init_data gcc_qupv3_wrap1_s4_clk_src_init = { .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }; static struct clk_rcg2 gcc_qupv3_wrap1_s4_clk_src = { @@ -801,7 +801,7 @@ static struct clk_init_data gcc_qupv3_wrap1_s5_clk_src_init = { .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }; static struct clk_rcg2 gcc_qupv3_wrap1_s5_clk_src = { @@ -818,7 +818,7 @@ static struct clk_init_data gcc_qupv3_wrap1_s6_clk_src_init = { .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }; static struct clk_rcg2 gcc_qupv3_wrap1_s6_clk_src = { @@ -835,7 +835,7 @@ static struct clk_init_data gcc_qupv3_wrap1_s7_clk_src_init = { .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }; static struct clk_rcg2 gcc_qupv3_wrap1_s7_clk_src = { @@ -852,7 +852,7 @@ static struct clk_init_data gcc_qupv3_wrap2_s0_clk_src_init = { .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }; static struct clk_rcg2 gcc_qupv3_wrap2_s0_clk_src = { @@ -869,7 +869,7 @@ static struct clk_init_data gcc_qupv3_wrap2_s1_clk_src_init = { .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }; static struct clk_rcg2 gcc_qupv3_wrap2_s1_clk_src = { @@ -886,7 +886,7 @@ static struct clk_init_data gcc_qupv3_wrap2_s2_clk_src_init = { .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }; static struct clk_rcg2 gcc_qupv3_wrap2_s2_clk_src = { @@ -903,7 +903,7 @@ static struct clk_init_data gcc_qupv3_wrap2_s3_clk_src_init = { .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }; static struct clk_rcg2 gcc_qupv3_wrap2_s3_clk_src = { @@ -920,7 +920,7 @@ static struct clk_init_data gcc_qupv3_wrap2_s4_clk_src_init = { .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }; static struct clk_rcg2 gcc_qupv3_wrap2_s4_clk_src = { @@ -937,7 +937,7 @@ static struct clk_init_data gcc_qupv3_wrap2_s5_clk_src_init = { .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }; static struct clk_rcg2 gcc_qupv3_wrap2_s5_clk_src = { @@ -975,7 +975,7 @@ static struct clk_init_data gcc_qupv3_wrap2_s6_clk_src_init = { .parent_data = gcc_parent_data_8, .num_parents = ARRAY_SIZE(gcc_parent_data_8), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }; static struct clk_rcg2 gcc_qupv3_wrap2_s6_clk_src = { @@ -992,7 +992,7 @@ static struct clk_init_data gcc_qupv3_wrap2_s7_clk_src_init = { .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }; static struct clk_rcg2 gcc_qupv3_wrap2_s7_clk_src = { @@ -1025,7 +1025,7 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { .parent_data = gcc_parent_data_9, .num_parents = ARRAY_SIZE(gcc_parent_data_9), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -1048,7 +1048,7 @@ static struct clk_rcg2 gcc_sdcc4_apps_clk_src = { .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -1071,7 +1071,7 @@ static struct clk_rcg2 gcc_ufs_phy_axi_clk_src = { .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -1093,7 +1093,7 @@ static struct clk_rcg2 gcc_ufs_phy_ice_core_clk_src = { .parent_data = gcc_parent_data_3, .num_parents = ARRAY_SIZE(gcc_parent_data_3), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -1114,7 +1114,7 @@ static struct clk_rcg2 gcc_ufs_phy_phy_aux_clk_src = { .parent_data = gcc_parent_data_4, .num_parents = ARRAY_SIZE(gcc_parent_data_4), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -1136,7 +1136,7 @@ static struct clk_rcg2 gcc_ufs_phy_unipro_core_clk_src = { .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -1159,7 +1159,7 @@ static struct clk_rcg2 gcc_usb30_prim_master_clk_src = { .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -1174,7 +1174,7 @@ static struct clk_rcg2 gcc_usb30_prim_mock_utmi_clk_src = { .parent_data = gcc_parent_data_0, .num_parents = ARRAY_SIZE(gcc_parent_data_0), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -1189,7 +1189,7 @@ static struct clk_rcg2 gcc_usb3_prim_phy_aux_clk_src = { .parent_data = gcc_parent_data_2, .num_parents = ARRAY_SIZE(gcc_parent_data_2), .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_rcg2_shared_ops, }, }; @@ -2998,38 +2998,46 @@ static struct clk_branch gcc_video_axi1_clk = { static struct gdsc pcie_0_gdsc = { .gdscr = 0x6b004, + .collapse_ctrl = 0x52020, + .collapse_mask = BIT(0), .pd = { .name = "pcie_0_gdsc", }, .pwrsts = PWRSTS_OFF_ON, - .flags = POLL_CFG_GDSCR, + .flags = VOTABLE | POLL_CFG_GDSCR | RETAIN_FF_ENABLE, }; static struct gdsc pcie_0_phy_gdsc = { .gdscr = 0x6c000, + .collapse_ctrl = 0x52020, + .collapse_mask = BIT(3), .pd = { .name = "pcie_0_phy_gdsc", }, .pwrsts = PWRSTS_OFF_ON, - .flags = POLL_CFG_GDSCR, + .flags = VOTABLE | POLL_CFG_GDSCR | RETAIN_FF_ENABLE, }; static struct gdsc pcie_1_gdsc = { .gdscr = 0x8d004, + .collapse_ctrl = 0x52020, + .collapse_mask = BIT(1), .pd = { .name = "pcie_1_gdsc", }, .pwrsts = PWRSTS_OFF_ON, - .flags = POLL_CFG_GDSCR, + .flags = VOTABLE | POLL_CFG_GDSCR | RETAIN_FF_ENABLE, }; static struct gdsc pcie_1_phy_gdsc = { .gdscr = 0x8e000, + .collapse_ctrl = 0x52020, + .collapse_mask = BIT(4), .pd = { .name = "pcie_1_phy_gdsc", }, .pwrsts = PWRSTS_OFF_ON, - .flags = POLL_CFG_GDSCR, + .flags = VOTABLE | POLL_CFG_GDSCR | RETAIN_FF_ENABLE, }; static struct gdsc ufs_phy_gdsc = { @@ -3038,7 +3046,7 @@ static struct gdsc ufs_phy_gdsc = { .name = "ufs_phy_gdsc", }, .pwrsts = PWRSTS_OFF_ON, - .flags = POLL_CFG_GDSCR, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, }; static struct gdsc ufs_mem_phy_gdsc = { @@ -3047,7 +3055,7 @@ static struct gdsc ufs_mem_phy_gdsc = { .name = "ufs_mem_phy_gdsc", }, .pwrsts = PWRSTS_OFF_ON, - .flags = POLL_CFG_GDSCR, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, }; static struct gdsc usb30_prim_gdsc = { @@ -3056,7 +3064,7 @@ static struct gdsc usb30_prim_gdsc = { .name = "usb30_prim_gdsc", }, .pwrsts = PWRSTS_OFF_ON, - .flags = POLL_CFG_GDSCR, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, }; static struct gdsc usb3_phy_gdsc = { @@ -3065,7 +3073,7 @@ static struct gdsc usb3_phy_gdsc = { .name = "usb3_phy_gdsc", }, .pwrsts = PWRSTS_OFF_ON, - .flags = POLL_CFG_GDSCR, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, }; static struct clk_regmap *gcc_sm8550_clocks[] = { diff --git a/drivers/clk/qcom/gcc-sm8650.c b/drivers/clk/qcom/gcc-sm8650.c new file mode 100644 index 00000000000000..9174dd82308c2b --- /dev/null +++ b/drivers/clk/qcom/gcc-sm8650.c @@ -0,0 +1,3849 @@ +// 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) 2023, Linaro Limited + */ + +#include +#include +#include +#include +#include + +#include + +#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 "gdsc.h" +#include "reset.h" + +/* Need to match the order of clocks in DT binding */ +enum { + DT_BI_TCXO, + DT_BI_TCXO_AO, + DT_SLEEP_CLK, + + DT_PCIE_0_PIPE, + DT_PCIE_1_PIPE, + DT_PCIE_1_PHY_AUX, + + DT_UFS_PHY_RX_SYMBOL_0, + DT_UFS_PHY_RX_SYMBOL_1, + DT_UFS_PHY_TX_SYMBOL_0, + + DT_USB3_PHY_WRAPPER_GCC_USB30_PIPE, +}; + +enum { + P_BI_TCXO, + P_GCC_GPLL0_OUT_EVEN, + P_GCC_GPLL0_OUT_MAIN, + P_GCC_GPLL1_OUT_MAIN, + P_GCC_GPLL3_OUT_MAIN, + P_GCC_GPLL4_OUT_MAIN, + P_GCC_GPLL6_OUT_MAIN, + P_GCC_GPLL7_OUT_MAIN, + P_GCC_GPLL9_OUT_MAIN, + P_PCIE_0_PIPE_CLK, + P_PCIE_1_PHY_AUX_CLK, + P_PCIE_1_PIPE_CLK, + P_SLEEP_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_PIPE_CLK, +}; + +static struct clk_alpha_pll gcc_gpll0 = { + .offset = 0x0, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll0", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll0_ao = { + .offset = 0x0, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x57020, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll0_ao", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO_AO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_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_OLE], + .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_ole_ops, + }, +}; + +static struct clk_alpha_pll_postdiv gcc_gpll0_out_even_ao = { + .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_OLE], + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll0_out_even_ao", + .parent_hws = (const struct clk_hw*[]) { + &gcc_gpll0_ao.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_postdiv_lucid_ole_ops, + }, +}; + +static struct clk_alpha_pll gcc_gpll1 = { + .offset = 0x4000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll1", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll1_ao = { + .offset = 0x1000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x57020, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll1_ao", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO_AO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll3 = { + .offset = 0x3000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(3), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll3", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll3_ao = { + .offset = 0x3000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x57020, + .enable_mask = BIT(3), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll3_ao", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO_AO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll4 = { + .offset = 0x4000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(4), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll4", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll4_ao = { + .offset = 0x4000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x57020, + .enable_mask = BIT(4), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll4_ao", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO_AO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll6 = { + .offset = 0x6000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(6), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll6", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll6_ao = { + .offset = 0x6000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x57020, + .enable_mask = BIT(6), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll6_ao", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO_AO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll7 = { + .offset = 0x7000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(7), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll7", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll9 = { + .offset = 0x9000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(9), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll9", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_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_SLEEP_CLK, 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 }, + { .index = DT_SLEEP_CLK }, + { .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_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_2[] = { + { .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_3[] = { + { 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_3[] = { + { .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_4[] = { + { P_BI_TCXO, 0 }, + { P_SLEEP_CLK, 5 }, +}; + +static const struct clk_parent_data gcc_parent_data_4[] = { + { .index = DT_BI_TCXO }, + { .index = DT_SLEEP_CLK }, +}; + +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_8[] = { + { P_PCIE_1_PHY_AUX_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_8[] = { + { .index = DT_PCIE_1_PHY_AUX }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_10[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL7_OUT_MAIN, 2 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_10[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll7.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_11[] = { + { 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_11[] = { + { .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_12[] = { + { P_UFS_PHY_RX_SYMBOL_0_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_12[] = { + { .index = DT_UFS_PHY_RX_SYMBOL_0 }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_13[] = { + { P_UFS_PHY_RX_SYMBOL_1_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_13[] = { + { .index = DT_UFS_PHY_RX_SYMBOL_1 }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_14[] = { + { P_UFS_PHY_TX_SYMBOL_0_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_14[] = { + { .index = DT_UFS_PHY_TX_SYMBOL_0 }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_15[] = { + { P_USB3_PHY_WRAPPER_GCC_USB30_PIPE_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_15[] = { + { .index = DT_USB3_PHY_WRAPPER_GCC_USB30_PIPE }, + { .index = DT_BI_TCXO }, +}; + +static struct clk_regmap_phy_mux gcc_pcie_0_pipe_clk_src = { + .reg = 0x6b070, + .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, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_pcie_1_phy_aux_clk_src = { + .reg = 0x8d094, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_8, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_phy_aux_clk_src", + .parent_data = gcc_parent_data_8, + .num_parents = ARRAY_SIZE(gcc_parent_data_8), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_phy_mux gcc_pcie_1_pipe_clk_src = { + .reg = 0x8d078, + .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, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_ufs_phy_rx_symbol_0_clk_src = { + .reg = 0x77064, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_12, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_rx_symbol_0_clk_src", + .parent_data = gcc_parent_data_12, + .num_parents = ARRAY_SIZE(gcc_parent_data_12), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_ufs_phy_rx_symbol_1_clk_src = { + .reg = 0x770e0, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_13, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_rx_symbol_1_clk_src", + .parent_data = gcc_parent_data_13, + .num_parents = ARRAY_SIZE(gcc_parent_data_13), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_ufs_phy_tx_symbol_0_clk_src = { + .reg = 0x77054, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_14, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_tx_symbol_0_clk_src", + .parent_data = gcc_parent_data_14, + .num_parents = ARRAY_SIZE(gcc_parent_data_14), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb3_prim_phy_pipe_clk_src = { + .reg = 0x3906c, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_15, + .clkr = { + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_prim_phy_pipe_clk_src", + .parent_data = gcc_parent_data_15, + .num_parents = ARRAY_SIZE(gcc_parent_data_15), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_gcc_gp1_clk_src[] = { + F(50000000, P_GCC_GPLL0_OUT_EVEN, 6, 0, 0), + 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 = 0x64004, + .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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_gp2_clk_src = { + .cmd_rcgr = 0x65004, + .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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_gp3_clk_src = { + .cmd_rcgr = 0x66004, + .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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_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 = 0x6b074, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .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_4, + .num_parents = ARRAY_SIZE(gcc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_pcie_0_phy_rchng_clk_src[] = { + F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pcie_0_phy_rchng_clk_src = { + .cmd_rcgr = 0x6b058, + .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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_1_aux_clk_src = { + .cmd_rcgr = 0x8d07c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_aux_clk_src", + .parent_data = gcc_parent_data_4, + .num_parents = ARRAY_SIZE(gcc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_1_phy_rchng_clk_src = { + .cmd_rcgr = 0x8d060, + .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), + .flags = CLK_SET_RATE_PARENT, + .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 = 0x33010, + .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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_qupv3_i2c_s0_clk_src = { + .cmd_rcgr = 0x17008, + .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_qupv3_i2c_s0_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_qupv3_i2c_s1_clk_src = { + .cmd_rcgr = 0x17024, + .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_qupv3_i2c_s1_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_qupv3_i2c_s2_clk_src = { + .cmd_rcgr = 0x17040, + .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_qupv3_i2c_s2_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_qupv3_i2c_s3_clk_src = { + .cmd_rcgr = 0x1705c, + .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_qupv3_i2c_s3_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_qupv3_i2c_s4_clk_src = { + .cmd_rcgr = 0x17078, + .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_qupv3_i2c_s4_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_qupv3_i2c_s5_clk_src = { + .cmd_rcgr = 0x17094, + .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_qupv3_i2c_s5_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_qupv3_i2c_s6_clk_src = { + .cmd_rcgr = 0x170b0, + .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_qupv3_i2c_s6_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_qupv3_i2c_s7_clk_src = { + .cmd_rcgr = 0x170cc, + .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_qupv3_i2c_s7_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_qupv3_i2c_s8_clk_src = { + .cmd_rcgr = 0x170e8, + .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_qupv3_i2c_s8_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_qupv3_i2c_s9_clk_src = { + .cmd_rcgr = 0x17104, + .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_qupv3_i2c_s9_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap1_qspi_ref_clk_src[] = { + F(150000000, P_GCC_GPLL0_OUT_EVEN, 2, 0, 0), + F(240000000, P_GCC_GPLL0_OUT_MAIN, 2.5, 0, 0), + { } +}; + +static struct clk_init_data gcc_qupv3_wrap1_qspi_ref_clk_src_init = { + .name = "gcc_qupv3_wrap1_qspi_ref_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_qspi_ref_clk_src = { + .cmd_rcgr = 0x188a0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_qspi_ref_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_qspi_ref_clk_src_init, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap1_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(102400000, P_GCC_GPLL0_OUT_EVEN, 1, 128, 375), + F(112000000, P_GCC_GPLL0_OUT_EVEN, 1, 28, 75), + F(117964800, P_GCC_GPLL0_OUT_EVEN, 1, 6144, 15625), + F(120000000, P_GCC_GPLL0_OUT_MAIN, 5, 0, 0), + { } +}; + +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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s0_clk_src = { + .cmd_rcgr = 0x18010, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s1_clk_src = { + .cmd_rcgr = 0x18148, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s0_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s1_clk_src_init, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap1_s3_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), + { } +}; + +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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s3_clk_src = { + .cmd_rcgr = 0x18290, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s3_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s3_clk_src_init, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap1_s4_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(120000000, P_GCC_GPLL0_OUT_MAIN, 5, 0, 0), + { } +}; + +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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s4_clk_src = { + .cmd_rcgr = 0x183c8, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s4_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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s5_clk_src = { + .cmd_rcgr = 0x18500, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s3_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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s6_clk_src = { + .cmd_rcgr = 0x18638, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s4_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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s7_clk_src = { + .cmd_rcgr = 0x18770, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s3_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s7_clk_src_init, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap2_ibi_ctrl_0_clk_src[] = { + F(37500000, P_GCC_GPLL0_OUT_EVEN, 8, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_ibi_ctrl_0_clk_src = { + .cmd_rcgr = 0x1e9d4, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_2, + .freq_tbl = ftbl_gcc_qupv3_wrap2_ibi_ctrl_0_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_ibi_ctrl_0_clk_src", + .parent_data = gcc_parent_data_2, + .num_parents = ARRAY_SIZE(gcc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s0_clk_src_init = { + .name = "gcc_qupv3_wrap2_s0_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s0_clk_src = { + .cmd_rcgr = 0x1e010, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_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_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s1_clk_src = { + .cmd_rcgr = 0x1e148, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_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_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s2_clk_src = { + .cmd_rcgr = 0x1e280, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s4_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_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s3_clk_src = { + .cmd_rcgr = 0x1e3b8, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s4_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_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s4_clk_src = { + .cmd_rcgr = 0x1e4f0, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s3_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_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s5_clk_src = { + .cmd_rcgr = 0x1e628, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s3_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s5_clk_src_init, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap2_s6_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(128000000, P_GCC_GPLL0_OUT_MAIN, 1, 16, 75), + { } +}; + +static struct clk_init_data gcc_qupv3_wrap2_s6_clk_src_init = { + .name = "gcc_qupv3_wrap2_s6_clk_src", + .parent_data = gcc_parent_data_10, + .num_parents = ARRAY_SIZE(gcc_parent_data_10), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s6_clk_src = { + .cmd_rcgr = 0x1e760, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_10, + .freq_tbl = ftbl_gcc_qupv3_wrap2_s6_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s6_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s7_clk_src_init = { + .name = "gcc_qupv3_wrap2_s7_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s7_clk_src = { + .cmd_rcgr = 0x1e898, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap1_s3_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s7_clk_src_init, +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap3_qspi_ref_clk_src[] = { + F(300000000, P_GCC_GPLL0_OUT_EVEN, 1, 0, 0), + F(400000000, P_GCC_GPLL0_OUT_MAIN, 1.5, 0, 0), + { } +}; + +static struct clk_init_data gcc_qupv3_wrap3_qspi_ref_clk_src_init = { + .name = "gcc_qupv3_wrap3_qspi_ref_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap3_qspi_ref_clk_src = { + .cmd_rcgr = 0x19018, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap3_qspi_ref_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap3_qspi_ref_clk_src_init, +}; + +static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = { + F(400000, P_BI_TCXO, 12, 1, 4), + F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0), + F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0), + F(202000000, P_GCC_GPLL9_OUT_MAIN, 4, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .cmd_rcgr = 0x14018, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_11, + .freq_tbl = ftbl_gcc_sdcc2_apps_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc2_apps_clk_src", + .parent_data = gcc_parent_data_11, + .num_parents = ARRAY_SIZE(gcc_parent_data_11), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_sdcc4_apps_clk_src[] = { + F(400000, P_BI_TCXO, 12, 1, 4), + F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0), + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_sdcc4_apps_clk_src = { + .cmd_rcgr = 0x16018, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_sdcc4_apps_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc4_apps_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_ufs_phy_axi_clk_src[] = { + F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0), + F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0), + F(201500000, P_GCC_GPLL4_OUT_MAIN, 4, 0, 0), + F(403000000, P_GCC_GPLL4_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_ufs_phy_axi_clk_src = { + .cmd_rcgr = 0x77030, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_ufs_phy_axi_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_axi_clk_src", + .parent_data = gcc_parent_data_3, + .num_parents = ARRAY_SIZE(gcc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_ufs_phy_ice_core_clk_src[] = { + F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0), + F(201500000, P_GCC_GPLL4_OUT_MAIN, 4, 0, 0), + F(403000000, P_GCC_GPLL4_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_ufs_phy_ice_core_clk_src = { + .cmd_rcgr = 0x77080, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_ufs_phy_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_3, + .num_parents = ARRAY_SIZE(gcc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_ufs_phy_phy_aux_clk_src[] = { + F(9600000, P_BI_TCXO, 2, 0, 0), + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_ufs_phy_phy_aux_clk_src = { + .cmd_rcgr = 0x770b4, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_5, + .freq_tbl = ftbl_gcc_ufs_phy_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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_ufs_phy_unipro_core_clk_src = { + .cmd_rcgr = 0x77098, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_3, + .freq_tbl = ftbl_gcc_ufs_phy_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_3, + .num_parents = ARRAY_SIZE(gcc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb30_prim_master_clk_src[] = { + F(66666667, P_GCC_GPLL0_OUT_EVEN, 4.5, 0, 0), + 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 = 0x3902c, + .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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb30_prim_mock_utmi_clk_src = { + .cmd_rcgr = 0x39044, + .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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb3_prim_phy_aux_clk_src = { + .cmd_rcgr = 0x39070, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .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_4, + .num_parents = ARRAY_SIZE(gcc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_regmap_div gcc_qupv3_wrap1_s2_clk_src = { + .reg = 0x18280, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s2_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_qspi_ref_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_clk_src = { + .reg = 0x19010, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap3_s0_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap3_qspi_ref_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 = 0x3905c, + .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_pcie_axi_clk = { + .halt_reg = 0x10064, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x10064, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(12), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_noc_pcie_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_ufs_phy_axi_clk = { + .halt_reg = 0x770e4, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x770e4, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x770e4, + .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 = 0x770e4, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x770e4, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x770e4, + .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_usb3_prim_axi_clk = { + .halt_reg = 0x3908c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x3908c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x3908c, + .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_boot_rom_ahb_clk = { + .halt_reg = 0x38004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x38004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52000, + .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 = 0x26010, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x26010, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x26010, + .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 = 0x2601c, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x2601c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2601c, + .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_cfg_noc_pcie_anoc_ahb_clk = { + .halt_reg = 0x10050, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x10050, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(20), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_pcie_anoc_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_usb3_prim_axi_clk = { + .halt_reg = 0x39088, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x39088, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x39088, + .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_cnoc_pcie_sf_axi_clk = { + .halt_reg = 0x10058, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x10058, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(6), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cnoc_pcie_sf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ddrss_gpu_axi_clk = { + .halt_reg = 0x71154, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x71154, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x71154, + .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_ddrss_pcie_sf_qtb_clk = { + .halt_reg = 0x10074, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x10074, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(19), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ddrss_pcie_sf_qtb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_disp_hf_axi_clk = { + .halt_reg = 0x2700c, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x2700c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2700c, + .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_gp1_clk = { + .halt_reg = 0x64000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x64000, + .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 = 0x65000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x65000, + .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 = 0x66000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x66000, + .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_gpu_gpll0_clk_src = { + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x52000, + .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 = 0x52000, + .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 = 0x71010, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x71010, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x71010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_memnoc_gfx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_snoc_dvm_gfx_clk = { + .halt_reg = 0x71018, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x71018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_snoc_dvm_gfx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_aux_clk = { + .halt_reg = 0x6b03c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(3), + .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 = 0x6b038, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x6b038, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(2), + .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 = 0x6b02c, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x6b02c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(1), + .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_rchng_clk = { + .halt_reg = 0x6b054, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(22), + .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 = 0x6b048, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(4), + .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 = 0x6b020, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x6b020, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(0), + .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 = 0x6b01c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(5), + .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 = 0x8d038, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(29), + .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 = 0x8d034, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x8d034, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(28), + .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 = 0x8d028, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x8d028, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(27), + .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 = 0x8d044, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(24), + .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 = 0x8d05c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(23), + .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 = 0x8d050, + .halt_check = BRANCH_HALT_SKIP, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(30), + .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_slv_axi_clk = { + .halt_reg = 0x8d01c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x8d01c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(26), + .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 = 0x8d018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(25), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm2_clk = { + .halt_reg = 0x3300c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3300c, + .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 = 0x33004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x33004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x33004, + .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 = 0x33008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x33008, + .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 = 0x26008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x26008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x26008, + .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 = 0x2600c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2600c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2600c, + .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_disp_ahb_clk = { + .halt_reg = 0x27008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x27008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x27008, + .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_gpu_ahb_clk = { + .halt_reg = 0x71008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x71008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x71008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_gpu_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_pcie_ahb_clk = { + .halt_reg = 0x6b018, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x6b018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(11), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_pcie_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_cv_cpu_ahb_clk = { + .halt_reg = 0x32014, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x32014, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x32014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_video_cv_cpu_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_cvp_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_video_cvp_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_v_cpu_ahb_clk = { + .halt_reg = 0x32010, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x32010, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x32010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_video_v_cpu_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_vcodec_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_video_vcodec_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_i2c_core_clk = { + .halt_reg = 0x23004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(8), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_core_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_i2c_s0_clk = { + .halt_reg = 0x17004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(10), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s0_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_i2c_s0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_i2c_s1_clk = { + .halt_reg = 0x17020, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(11), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s1_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_i2c_s1_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_i2c_s2_clk = { + .halt_reg = 0x1703c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(12), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_i2c_s2_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_i2c_s3_clk = { + .halt_reg = 0x17058, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(13), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s3_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_i2c_s3_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_i2c_s4_clk = { + .halt_reg = 0x17074, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(14), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s4_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_i2c_s4_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_i2c_s5_clk = { + .halt_reg = 0x17090, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(15), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s5_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_i2c_s5_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_i2c_s6_clk = { + .halt_reg = 0x170ac, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(16), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s6_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_i2c_s6_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_i2c_s7_clk = { + .halt_reg = 0x170c8, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(17), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s7_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_i2c_s7_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_i2c_s8_clk = { + .halt_reg = 0x170e4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(14), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s8_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_i2c_s8_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_i2c_s9_clk = { + .halt_reg = 0x17100, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(15), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s9_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_i2c_s9_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_i2c_s_ahb_clk = { + .halt_reg = 0x23000, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x23000, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(7), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_i2c_s_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_core_2x_clk = { + .halt_reg = 0x23154, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .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 = 0x23144, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .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_qspi_ref_clk = { + .halt_reg = 0x1889c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(29), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_qspi_ref_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_qspi_ref_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap1_s0_clk = { + .halt_reg = 0x18004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .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 = 0x1813c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .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 = 0x18274, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .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 = 0x18284, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .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 = 0x183bc, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .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 = 0x184f4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .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 = 0x1862c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .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 = 0x18764, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(16), + .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_wrap2_core_2x_clk = { + .halt_reg = 0x232a4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .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 = 0x23294, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .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_ibi_ctrl_2_clk = { + .halt_reg = 0x1e9cc, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x1e9cc, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(27), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_ibi_ctrl_2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_ibi_ctrl_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_ibi_ctrl_3_clk = { + .halt_reg = 0x1e9d0, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x1e9d0, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(28), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_ibi_ctrl_3_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_ibi_ctrl_0_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap2_s0_clk = { + .halt_reg = 0x1e004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .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 = 0x1e13c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .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 = 0x1e274, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .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 = 0x1e3ac, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .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 = 0x1e4e4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .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 = 0x1e61c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .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 = 0x1e754, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(10), + .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_wrap2_s7_clk = { + .halt_reg = 0x1e88c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(17), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s7_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s7_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 = 0x233f4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(1), + .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 = 0x233e4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(0), + .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_ref_clk = { + .halt_reg = 0x19014, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(3), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap3_qspi_ref_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap3_qspi_ref_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 = 0x19004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(2), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap3_s0_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_wrap_1_m_ahb_clk = { + .halt_reg = 0x2313c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2313c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .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 = 0x23140, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x23140, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .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_ibi_2_ahb_clk = { + .halt_reg = 0x1e9c4, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x1e9c4, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(25), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_2_ibi_2_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_2_ibi_3_ahb_clk = { + .halt_reg = 0x1e9c8, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x1e9c8, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(26), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_2_ibi_3_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qupv3_wrap_2_m_ahb_clk = { + .halt_reg = 0x2328c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2328c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .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 = 0x23290, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x23290, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .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 = 0x233dc, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x233dc, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(30), + .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 = 0x233e0, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x233e0, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(31), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap_3_s_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc2_ahb_clk = { + .halt_reg = 0x14010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x14010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc2_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc2_apps_clk = { + .halt_reg = 0x14004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x14004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc2_apps_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_sdcc2_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc4_ahb_clk = { + .halt_reg = 0x16010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x16010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc4_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc4_apps_clk = { + .halt_reg = 0x16004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x16004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc4_apps_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_sdcc4_apps_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 = 0x77024, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x77024, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77024, + .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 = 0x77018, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x77018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77018, + .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 = 0x77018, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x77018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77018, + .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 = 0x77074, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x77074, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77074, + .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 = 0x77074, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x77074, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77074, + .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 = 0x770b0, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x770b0, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x770b0, + .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 = 0x770b0, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x770b0, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x770b0, + .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 = 0x7702c, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x7702c, + .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 = 0x770cc, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x770cc, + .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 = 0x77028, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x77028, + .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 = 0x77068, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x77068, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77068, + .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 = 0x77068, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x77068, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77068, + .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_usb30_prim_master_clk = { + .halt_reg = 0x39018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x39018, + .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 = 0x39028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x39028, + .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 = 0x39024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x39024, + .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 = 0x39060, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x39060, + .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 = 0x39064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x39064, + .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 = 0x39068, + .halt_check = BRANCH_HALT_DELAY, + .hwcg_reg = 0x39068, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x39068, + .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_video_axi0_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_video_axi0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_video_axi1_clk = { + .halt_reg = 0x32024, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x32024, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x32024, + .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 = 0x6b004, + .collapse_ctrl = 0x5214c, + .collapse_mask = BIT(0), + .pd = { + .name = "pcie_0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc pcie_0_phy_gdsc = { + .gdscr = 0x6c000, + .collapse_ctrl = 0x5214c, + .collapse_mask = BIT(3), + .pd = { + .name = "pcie_0_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc pcie_1_gdsc = { + .gdscr = 0x8d004, + .collapse_ctrl = 0x5214c, + .collapse_mask = BIT(1), + .pd = { + .name = "pcie_1_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc pcie_1_phy_gdsc = { + .gdscr = 0x8e000, + .collapse_ctrl = 0x5214c, + .collapse_mask = BIT(4), + .pd = { + .name = "pcie_1_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc ufs_phy_gdsc = { + .gdscr = 0x77004, + .pd = { + .name = "ufs_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc ufs_mem_phy_gdsc = { + .gdscr = 0x9e000, + .pd = { + .name = "ufs_mem_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc usb30_prim_gdsc = { + .gdscr = 0x39004, + .pd = { + .name = "usb30_prim_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc usb3_phy_gdsc = { + .gdscr = 0x50018, + .pd = { + .name = "usb3_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct clk_regmap *gcc_sm8650_clocks[] = { + [GCC_AGGRE_NOC_PCIE_AXI_CLK] = &gcc_aggre_noc_pcie_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_USB3_PRIM_AXI_CLK] = &gcc_aggre_usb3_prim_axi_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_CFG_NOC_PCIE_ANOC_AHB_CLK] = &gcc_cfg_noc_pcie_anoc_ahb_clk.clkr, + [GCC_CFG_NOC_USB3_PRIM_AXI_CLK] = &gcc_cfg_noc_usb3_prim_axi_clk.clkr, + [GCC_CNOC_PCIE_SF_AXI_CLK] = &gcc_cnoc_pcie_sf_axi_clk.clkr, + [GCC_DDRSS_GPU_AXI_CLK] = &gcc_ddrss_gpu_axi_clk.clkr, + [GCC_DDRSS_PCIE_SF_QTB_CLK] = &gcc_ddrss_pcie_sf_qtb_clk.clkr, + [GCC_DISP_HF_AXI_CLK] = &gcc_disp_hf_axi_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_GPLL3] = &gcc_gpll3.clkr, + [GCC_GPLL4] = &gcc_gpll4.clkr, + [GCC_GPLL6] = &gcc_gpll6.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_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_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_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_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_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_DISP_AHB_CLK] = &gcc_qmip_disp_ahb_clk.clkr, + [GCC_QMIP_GPU_AHB_CLK] = &gcc_qmip_gpu_ahb_clk.clkr, + [GCC_QMIP_PCIE_AHB_CLK] = &gcc_qmip_pcie_ahb_clk.clkr, + [GCC_QMIP_VIDEO_CV_CPU_AHB_CLK] = &gcc_qmip_video_cv_cpu_ahb_clk.clkr, + [GCC_QMIP_VIDEO_CVP_AHB_CLK] = &gcc_qmip_video_cvp_ahb_clk.clkr, + [GCC_QMIP_VIDEO_V_CPU_AHB_CLK] = &gcc_qmip_video_v_cpu_ahb_clk.clkr, + [GCC_QMIP_VIDEO_VCODEC_AHB_CLK] = &gcc_qmip_video_vcodec_ahb_clk.clkr, + [GCC_QUPV3_I2C_CORE_CLK] = &gcc_qupv3_i2c_core_clk.clkr, + [GCC_QUPV3_I2C_S0_CLK] = &gcc_qupv3_i2c_s0_clk.clkr, + [GCC_QUPV3_I2C_S0_CLK_SRC] = &gcc_qupv3_i2c_s0_clk_src.clkr, + [GCC_QUPV3_I2C_S1_CLK] = &gcc_qupv3_i2c_s1_clk.clkr, + [GCC_QUPV3_I2C_S1_CLK_SRC] = &gcc_qupv3_i2c_s1_clk_src.clkr, + [GCC_QUPV3_I2C_S2_CLK] = &gcc_qupv3_i2c_s2_clk.clkr, + [GCC_QUPV3_I2C_S2_CLK_SRC] = &gcc_qupv3_i2c_s2_clk_src.clkr, + [GCC_QUPV3_I2C_S3_CLK] = &gcc_qupv3_i2c_s3_clk.clkr, + [GCC_QUPV3_I2C_S3_CLK_SRC] = &gcc_qupv3_i2c_s3_clk_src.clkr, + [GCC_QUPV3_I2C_S4_CLK] = &gcc_qupv3_i2c_s4_clk.clkr, + [GCC_QUPV3_I2C_S4_CLK_SRC] = &gcc_qupv3_i2c_s4_clk_src.clkr, + [GCC_QUPV3_I2C_S5_CLK] = &gcc_qupv3_i2c_s5_clk.clkr, + [GCC_QUPV3_I2C_S5_CLK_SRC] = &gcc_qupv3_i2c_s5_clk_src.clkr, + [GCC_QUPV3_I2C_S6_CLK] = &gcc_qupv3_i2c_s6_clk.clkr, + [GCC_QUPV3_I2C_S6_CLK_SRC] = &gcc_qupv3_i2c_s6_clk_src.clkr, + [GCC_QUPV3_I2C_S7_CLK] = &gcc_qupv3_i2c_s7_clk.clkr, + [GCC_QUPV3_I2C_S7_CLK_SRC] = &gcc_qupv3_i2c_s7_clk_src.clkr, + [GCC_QUPV3_I2C_S8_CLK] = &gcc_qupv3_i2c_s8_clk.clkr, + [GCC_QUPV3_I2C_S8_CLK_SRC] = &gcc_qupv3_i2c_s8_clk_src.clkr, + [GCC_QUPV3_I2C_S9_CLK] = &gcc_qupv3_i2c_s9_clk.clkr, + [GCC_QUPV3_I2C_S9_CLK_SRC] = &gcc_qupv3_i2c_s9_clk_src.clkr, + [GCC_QUPV3_I2C_S_AHB_CLK] = &gcc_qupv3_i2c_s_ahb_clk.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_QSPI_REF_CLK] = &gcc_qupv3_wrap1_qspi_ref_clk.clkr, + [GCC_QUPV3_WRAP1_QSPI_REF_CLK_SRC] = &gcc_qupv3_wrap1_qspi_ref_clk_src.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_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_IBI_CTRL_0_CLK_SRC] = &gcc_qupv3_wrap2_ibi_ctrl_0_clk_src.clkr, + [GCC_QUPV3_WRAP2_IBI_CTRL_2_CLK] = &gcc_qupv3_wrap2_ibi_ctrl_2_clk.clkr, + [GCC_QUPV3_WRAP2_IBI_CTRL_3_CLK] = &gcc_qupv3_wrap2_ibi_ctrl_3_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_WRAP2_S7_CLK] = &gcc_qupv3_wrap2_s7_clk.clkr, + [GCC_QUPV3_WRAP2_S7_CLK_SRC] = &gcc_qupv3_wrap2_s7_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_REF_CLK] = &gcc_qupv3_wrap3_qspi_ref_clk.clkr, + [GCC_QUPV3_WRAP3_QSPI_REF_CLK_SRC] = &gcc_qupv3_wrap3_qspi_ref_clk_src.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_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_IBI_2_AHB_CLK] = &gcc_qupv3_wrap_2_ibi_2_ahb_clk.clkr, + [GCC_QUPV3_WRAP_2_IBI_3_AHB_CLK] = &gcc_qupv3_wrap_2_ibi_3_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_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.clkr, + [GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr, + [GCC_SDCC2_APPS_CLK_SRC] = &gcc_sdcc2_apps_clk_src.clkr, + [GCC_SDCC4_AHB_CLK] = &gcc_sdcc4_ahb_clk.clkr, + [GCC_SDCC4_APPS_CLK] = &gcc_sdcc4_apps_clk.clkr, + [GCC_SDCC4_APPS_CLK_SRC] = &gcc_sdcc4_apps_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_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_VIDEO_AXI0_CLK] = &gcc_video_axi0_clk.clkr, + [GCC_VIDEO_AXI1_CLK] = &gcc_video_axi1_clk.clkr, + [GCC_GPLL0_AO] = &gcc_gpll0_ao.clkr, + [GCC_GPLL0_OUT_EVEN_AO] = &gcc_gpll0_out_even_ao.clkr, + [GCC_GPLL1_AO] = &gcc_gpll1_ao.clkr, + [GCC_GPLL3_AO] = &gcc_gpll3_ao.clkr, + [GCC_GPLL4_AO] = &gcc_gpll4_ao.clkr, + [GCC_GPLL6_AO] = &gcc_gpll6_ao.clkr, +}; + +static const struct qcom_reset_map gcc_sm8650_resets[] = { + [GCC_CAMERA_BCR] = { 0x26000 }, + [GCC_DISPLAY_BCR] = { 0x27000 }, + [GCC_GPU_BCR] = { 0x71000 }, + [GCC_PCIE_0_BCR] = { 0x6b000 }, + [GCC_PCIE_0_LINK_DOWN_BCR] = { 0x6c014 }, + [GCC_PCIE_0_NOCSR_COM_PHY_BCR] = { 0x6c020 }, + [GCC_PCIE_0_PHY_BCR] = { 0x6c01c }, + [GCC_PCIE_0_PHY_NOCSR_COM_PHY_BCR] = { 0x6c028 }, + [GCC_PCIE_1_BCR] = { 0x8d000 }, + [GCC_PCIE_1_LINK_DOWN_BCR] = { 0x8e014 }, + [GCC_PCIE_1_NOCSR_COM_PHY_BCR] = { 0x8e020 }, + [GCC_PCIE_1_PHY_BCR] = { 0x8e01c }, + [GCC_PCIE_1_PHY_NOCSR_COM_PHY_BCR] = { 0x8e024 }, + [GCC_PCIE_PHY_BCR] = { 0x6f000 }, + [GCC_PCIE_PHY_CFG_AHB_BCR] = { 0x6f00c }, + [GCC_PCIE_PHY_COM_BCR] = { 0x6f010 }, + [GCC_PDM_BCR] = { 0x33000 }, + [GCC_QUPV3_WRAPPER_1_BCR] = { 0x18000 }, + [GCC_QUPV3_WRAPPER_2_BCR] = { 0x1e000 }, + [GCC_QUPV3_WRAPPER_3_BCR] = { 0x19000 }, + [GCC_QUPV3_WRAPPER_I2C_BCR] = { 0x17000 }, + [GCC_QUSB2PHY_PRIM_BCR] = { 0x12000 }, + [GCC_QUSB2PHY_SEC_BCR] = { 0x12004 }, + [GCC_SDCC2_BCR] = { 0x14000 }, + [GCC_SDCC4_BCR] = { 0x16000 }, + [GCC_UFS_PHY_BCR] = { 0x77000 }, + [GCC_USB30_PRIM_BCR] = { 0x39000 }, + [GCC_USB3_DP_PHY_PRIM_BCR] = { 0x50008 }, + [GCC_USB3_DP_PHY_SEC_BCR] = { 0x50014 }, + [GCC_USB3_PHY_PRIM_BCR] = { 0x50000 }, + [GCC_USB3_PHY_SEC_BCR] = { 0x5000c }, + [GCC_USB3PHY_PHY_PRIM_BCR] = { 0x50004 }, + [GCC_USB3PHY_PHY_SEC_BCR] = { 0x50010 }, + [GCC_VIDEO_AXI0_CLK_ARES] = { 0x32018, 2 }, + [GCC_VIDEO_AXI1_CLK_ARES] = { 0x32024, 2 }, + [GCC_VIDEO_BCR] = { 0x32000 }, +}; + +static const struct clk_rcg_dfs_data gcc_dfs_clocks[] = { + DEFINE_RCG_DFS(gcc_qupv3_wrap1_qspi_ref_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_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), + 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_wrap2_s7_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap3_qspi_ref_clk_src), +}; + +static struct gdsc *gcc_sm8650_gdscs[] = { + [PCIE_0_GDSC] = &pcie_0_gdsc, + [PCIE_0_PHY_GDSC] = &pcie_0_phy_gdsc, + [PCIE_1_GDSC] = &pcie_1_gdsc, + [PCIE_1_PHY_GDSC] = &pcie_1_phy_gdsc, + [UFS_PHY_GDSC] = &ufs_phy_gdsc, + [UFS_MEM_PHY_GDSC] = &ufs_mem_phy_gdsc, + [USB30_PRIM_GDSC] = &usb30_prim_gdsc, + [USB3_PHY_GDSC] = &usb3_phy_gdsc, +}; + +static const struct regmap_config gcc_sm8650_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x1f41f0, + .fast_io = true, +}; + +static const struct qcom_cc_desc gcc_sm8650_desc = { + .config = &gcc_sm8650_regmap_config, + .clks = gcc_sm8650_clocks, + .num_clks = ARRAY_SIZE(gcc_sm8650_clocks), + .resets = gcc_sm8650_resets, + .num_resets = ARRAY_SIZE(gcc_sm8650_resets), + .gdscs = gcc_sm8650_gdscs, + .num_gdscs = ARRAY_SIZE(gcc_sm8650_gdscs), +}; + +static const struct of_device_id gcc_sm8650_match_table[] = { + { .compatible = "qcom,sm8650-gcc" }, + { } +}; +MODULE_DEVICE_TABLE(of, gcc_sm8650_match_table); + +static int gcc_sm8650_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + int ret; + + regmap = qcom_cc_map(pdev, &gcc_sm8650_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 critical clock always-On */ + regmap_update_bits(regmap, 0x26004, BIT(0), BIT(0)); /* gcc_camera_ahb_clk */ + regmap_update_bits(regmap, 0x26028, BIT(0), BIT(0)); /* gcc_camera_xo_clk */ + regmap_update_bits(regmap, 0x27004, BIT(0), BIT(0)); /* gcc_disp_ahb_clk */ + regmap_update_bits(regmap, 0x27018, BIT(0), BIT(0)); /* gcc_disp_xo_clk */ + regmap_update_bits(regmap, 0x71004, BIT(0), BIT(0)); /* gcc_gpu_cfg_ahb_clk */ + regmap_update_bits(regmap, 0x32004, BIT(0), BIT(0)); /* gcc_video_ahb_clk */ + regmap_update_bits(regmap, 0x32030, BIT(0), BIT(0)); /* gcc_video_xo_clk */ + + qcom_branch_set_force_mem_core(regmap, gcc_ufs_phy_ice_core_clk, true); + + /* Clear GDSC_SLEEP_ENA_VOTE to stop votes being auto-removed in sleep. */ + regmap_write(regmap, 0x52150, 0x0); + + return qcom_cc_really_probe(pdev, &gcc_sm8650_desc, regmap); +} + +static struct platform_driver gcc_sm8650_driver = { + .probe = gcc_sm8650_probe, + .driver = { + .name = "gcc-sm8650", + .of_match_table = gcc_sm8650_match_table, + }, +}; + +static int __init gcc_sm8650_init(void) +{ + return platform_driver_register(&gcc_sm8650_driver); +} +subsys_initcall(gcc_sm8650_init); + +static void __exit gcc_sm8650_exit(void) +{ + platform_driver_unregister(&gcc_sm8650_driver); +} +module_exit(gcc_sm8650_exit); + +MODULE_DESCRIPTION("QTI GCC SM8650 Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/qcom/gcc-x1e80100.c b/drivers/clk/qcom/gcc-x1e80100.c new file mode 100644 index 00000000000000..d7182d6e978372 --- /dev/null +++ b/drivers/clk/qcom/gcc-x1e80100.c @@ -0,0 +1,6808 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include + +#include + +#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 "gdsc.h" +#include "reset.h" + +enum { + DT_BI_TCXO, + DT_SLEEP_CLK, + DT_PCIE_3_PIPE, + DT_PCIE_4_PIPE, + DT_PCIE_5_PIPE, + DT_PCIE_6A_PIPE, + DT_PCIE_6B_PIPE, + DT_USB3_PHY_0_WRAPPER_GCC_USB30_PIPE, + DT_USB3_PHY_1_WRAPPER_GCC_USB30_PIPE, + DT_USB3_PHY_2_WRAPPER_GCC_USB30_PIPE, +}; + +enum { + P_BI_TCXO, + P_GCC_GPLL0_OUT_EVEN, + P_GCC_GPLL0_OUT_MAIN, + P_GCC_GPLL4_OUT_MAIN, + P_GCC_GPLL7_OUT_MAIN, + P_GCC_GPLL8_OUT_MAIN, + P_GCC_GPLL9_OUT_MAIN, + P_SLEEP_CLK, + P_USB3_PHY_0_WRAPPER_GCC_USB30_PIPE_CLK, + P_USB3_PHY_1_WRAPPER_GCC_USB30_PIPE_CLK, + P_USB3_PHY_2_WRAPPER_GCC_USB30_PIPE_CLK, +}; + +static struct clk_alpha_pll gcc_gpll0 = { + .offset = 0x0, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x52030, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll0", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_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_OLE], + .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_ole_ops, + }, +}; + +static struct clk_alpha_pll gcc_gpll4 = { + .offset = 0x4000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x52030, + .enable_mask = BIT(4), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll4", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll7 = { + .offset = 0x7000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x52030, + .enable_mask = BIT(7), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll7", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll8 = { + .offset = 0x8000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x52030, + .enable_mask = BIT(8), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll8", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_ops, + }, + }, +}; + +static struct clk_alpha_pll gcc_gpll9 = { + .offset = 0x9000, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE], + .clkr = { + .enable_reg = 0x52030, + .enable_mask = BIT(9), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpll9", + .parent_data = &(const struct clk_parent_data) { + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_fixed_lucid_ole_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_SLEEP_CLK, 5 }, +}; + +static const struct clk_parent_data gcc_parent_data_1[] = { + { .index = DT_BI_TCXO }, + { .index = DT_SLEEP_CLK }, +}; + +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 }, +}; + +static const struct clk_parent_data gcc_parent_data_3[] = { + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_4[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL8_OUT_MAIN, 2 }, + { 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_gpll8.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_5[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL7_OUT_MAIN, 2 }, + { P_SLEEP_CLK, 5 }, +}; + +static const struct clk_parent_data gcc_parent_data_5[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll7.clkr.hw }, + { .index = DT_SLEEP_CLK }, +}; + +static const struct parent_map gcc_parent_map_6[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL7_OUT_MAIN, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_6[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll7.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_7[] = { + { 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_7[] = { + { .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_8[] = { + { P_BI_TCXO, 0 }, + { P_GCC_GPLL0_OUT_MAIN, 1 }, + { P_GCC_GPLL7_OUT_MAIN, 2 }, + { P_GCC_GPLL0_OUT_EVEN, 6 }, +}; + +static const struct clk_parent_data gcc_parent_data_8[] = { + { .index = DT_BI_TCXO }, + { .hw = &gcc_gpll0.clkr.hw }, + { .hw = &gcc_gpll7.clkr.hw }, + { .hw = &gcc_gpll0_out_even.clkr.hw }, +}; + +static const struct parent_map gcc_parent_map_9[] = { + { 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_10[] = { + { .index = DT_USB3_PHY_0_WRAPPER_GCC_USB30_PIPE }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_10[] = { + { P_USB3_PHY_0_WRAPPER_GCC_USB30_PIPE_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_11[] = { + { .index = DT_USB3_PHY_1_WRAPPER_GCC_USB30_PIPE }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_11[] = { + { P_USB3_PHY_1_WRAPPER_GCC_USB30_PIPE_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_12[] = { + { .index = DT_USB3_PHY_2_WRAPPER_GCC_USB30_PIPE }, + { .index = DT_BI_TCXO }, +}; + +static const struct parent_map gcc_parent_map_12[] = { + { P_USB3_PHY_2_WRAPPER_GCC_USB30_PIPE_CLK, 0 }, + { P_BI_TCXO, 2 }, +}; + +static const struct clk_parent_data gcc_parent_data_9[] = { + { .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 freq_tbl ftbl_gcc_gp1_clk_src[] = { + F(50000000, P_GCC_GPLL0_OUT_EVEN, 6, 0, 0), + 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 = 0x64004, + .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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_gp2_clk_src = { + .cmd_rcgr = 0x65004, + .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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_gp3_clk_src = { + .cmd_rcgr = 0x66004, + .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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_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 = 0xa0180, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .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_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_pcie_0_phy_rchng_clk_src[] = { + F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_pcie_0_phy_rchng_clk_src = { + .cmd_rcgr = 0xa0054, + .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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_1_aux_clk_src = { + .cmd_rcgr = 0x2c180, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_aux_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_1_phy_rchng_clk_src = { + .cmd_rcgr = 0x2c054, + .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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_2_aux_clk_src = { + .cmd_rcgr = 0x13180, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_2_aux_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_2_phy_rchng_clk_src = { + .cmd_rcgr = 0x13054, + .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_2_phy_rchng_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_3_aux_clk_src = { + .cmd_rcgr = 0x5808c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3_aux_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_3_phy_rchng_clk_src = { + .cmd_rcgr = 0x58070, + .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_3_phy_rchng_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_4_aux_clk_src = { + .cmd_rcgr = 0x6b080, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_4_aux_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_4_phy_rchng_clk_src = { + .cmd_rcgr = 0x6b064, + .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_4_phy_rchng_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_5_aux_clk_src = { + .cmd_rcgr = 0x2f080, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_5_aux_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_5_phy_rchng_clk_src = { + .cmd_rcgr = 0x2f064, + .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_5_phy_rchng_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_6a_aux_clk_src = { + .cmd_rcgr = 0x3108c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6a_aux_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_6a_phy_rchng_clk_src = { + .cmd_rcgr = 0x31070, + .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_6a_phy_rchng_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_6b_aux_clk_src = { + .cmd_rcgr = 0x8d08c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6b_aux_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_6b_phy_rchng_clk_src = { + .cmd_rcgr = 0x8d070, + .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_6b_phy_rchng_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_pcie_rscc_xo_clk_src = { + .cmd_rcgr = 0xa400c, + .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_pcie_rscc_xo_clk_src", + .parent_data = gcc_parent_data_3, + .num_parents = ARRAY_SIZE(gcc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .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 = 0x33010, + .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), + .flags = CLK_SET_RATE_PARENT, + .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(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(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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s0_clk_src = { + .cmd_rcgr = 0x42010, + .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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s1_clk_src = { + .cmd_rcgr = 0x42148, + .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(150000000, P_GCC_GPLL0_OUT_EVEN, 2, 0, 0), + F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s2_clk_src = { + .cmd_rcgr = 0x42288, + .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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s3_clk_src = { + .cmd_rcgr = 0x423c8, + .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 const struct freq_tbl ftbl_gcc_qupv3_wrap0_s4_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), + { } +}; + +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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s4_clk_src = { + .cmd_rcgr = 0x42500, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s5_clk_src = { + .cmd_rcgr = 0x42638, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s6_clk_src = { + .cmd_rcgr = 0x42770, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap0_s7_clk_src = { + .cmd_rcgr = 0x428a8, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s0_clk_src = { + .cmd_rcgr = 0x18010, + .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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s1_clk_src = { + .cmd_rcgr = 0x18148, + .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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s2_clk_src = { + .cmd_rcgr = 0x18288, + .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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s3_clk_src = { + .cmd_rcgr = 0x183c8, + .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_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s4_clk_src = { + .cmd_rcgr = 0x18500, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s5_clk_src = { + .cmd_rcgr = 0x18638, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s6_clk_src = { + .cmd_rcgr = 0x18770, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap1_s7_clk_src = { + .cmd_rcgr = 0x188a8, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap1_s7_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_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s0_clk_src = { + .cmd_rcgr = 0x1e010, + .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_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_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s1_clk_src = { + .cmd_rcgr = 0x1e148, + .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_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_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s2_clk_src = { + .cmd_rcgr = 0x1e288, + .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_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_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s3_clk_src = { + .cmd_rcgr = 0x1e3c8, + .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_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_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s4_clk_src = { + .cmd_rcgr = 0x1e500, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_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_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s5_clk_src = { + .cmd_rcgr = 0x1e638, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_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_8, + .num_parents = ARRAY_SIZE(gcc_parent_data_8), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s6_clk_src = { + .cmd_rcgr = 0x1e770, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_8, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s6_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap2_s7_clk_src_init = { + .name = "gcc_qupv3_wrap2_s7_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, +}; + +static struct clk_rcg2 gcc_qupv3_wrap2_s7_clk_src = { + .cmd_rcgr = 0x1e8a8, + .mnd_width = 16, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_qupv3_wrap0_s4_clk_src, + .clkr.hw.init = &gcc_qupv3_wrap2_s7_clk_src_init, +}; + +static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = { + F(400000, P_BI_TCXO, 12, 1, 4), + 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(202000000, P_GCC_GPLL9_OUT_MAIN, 4, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { + .cmd_rcgr = 0x14018, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_9, + .freq_tbl = ftbl_gcc_sdcc2_apps_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc2_apps_clk_src", + .parent_data = gcc_parent_data_9, + .num_parents = ARRAY_SIZE(gcc_parent_data_9), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_floor_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_sdcc4_apps_clk_src[] = { + F(400000, P_BI_TCXO, 12, 1, 4), + F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0), + F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_sdcc4_apps_clk_src = { + .cmd_rcgr = 0x16018, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_sdcc4_apps_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc4_apps_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_floor_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_ufs_phy_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), + { } +}; + +static struct clk_rcg2 gcc_ufs_phy_axi_clk_src = { + .cmd_rcgr = 0x77030, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_ufs_phy_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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_ufs_phy_ice_core_clk_src[] = { + F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0), + F(201500000, P_GCC_GPLL4_OUT_MAIN, 4, 0, 0), + F(403000000, P_GCC_GPLL4_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_ufs_phy_ice_core_clk_src = { + .cmd_rcgr = 0x77080, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_7, + .freq_tbl = ftbl_gcc_ufs_phy_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_7, + .num_parents = ARRAY_SIZE(gcc_parent_data_7), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_ufs_phy_phy_aux_clk_src = { + .cmd_rcgr = 0x770b4, + .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_ufs_phy_phy_aux_clk_src", + .parent_data = gcc_parent_data_3, + .num_parents = ARRAY_SIZE(gcc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_ufs_phy_unipro_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), + { } +}; + +static struct clk_rcg2 gcc_ufs_phy_unipro_core_clk_src = { + .cmd_rcgr = 0x77098, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_ufs_phy_unipro_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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb20_master_clk_src[] = { + F(60000000, P_GCC_GPLL0_OUT_MAIN, 10, 0, 0), + F(120000000, P_GCC_GPLL0_OUT_MAIN, 5, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb20_master_clk_src = { + .cmd_rcgr = 0x2902c, + .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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb20_mock_utmi_clk_src = { + .cmd_rcgr = 0x29158, + .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_usb20_mock_utmi_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb30_mp_master_clk_src[] = { + F(66666667, P_GCC_GPLL0_OUT_EVEN, 4.5, 0, 0), + 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_mp_master_clk_src = { + .cmd_rcgr = 0x1702c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_usb30_mp_master_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_mp_master_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb30_mp_mock_utmi_clk_src = { + .cmd_rcgr = 0x17158, + .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_mp_mock_utmi_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb30_prim_master_clk_src = { + .cmd_rcgr = 0x3902c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_usb30_mp_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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb30_prim_mock_utmi_clk_src = { + .cmd_rcgr = 0x39044, + .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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb30_sec_master_clk_src = { + .cmd_rcgr = 0xa102c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_usb30_mp_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), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb30_sec_mock_utmi_clk_src = { + .cmd_rcgr = 0xa1044, + .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_sec_mock_utmi_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb30_tert_master_clk_src = { + .cmd_rcgr = 0xa202c, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_usb30_mp_master_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_tert_master_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb30_tert_mock_utmi_clk_src = { + .cmd_rcgr = 0xa2044, + .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_tert_mock_utmi_clk_src", + .parent_data = gcc_parent_data_0, + .num_parents = ARRAY_SIZE(gcc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb3_mp_phy_aux_clk_src = { + .cmd_rcgr = 0x172a0, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_mp_phy_aux_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb3_prim_phy_aux_clk_src = { + .cmd_rcgr = 0x39074, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .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_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb3_sec_phy_aux_clk_src = { + .cmd_rcgr = 0xa1074, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_sec_phy_aux_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb3_tert_phy_aux_clk_src = { + .cmd_rcgr = 0xa2074, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_1, + .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_tert_phy_aux_clk_src", + .parent_data = gcc_parent_data_1, + .num_parents = ARRAY_SIZE(gcc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb4_0_master_clk_src[] = { + F(85714286, P_GCC_GPLL0_OUT_EVEN, 3.5, 0, 0), + F(175000000, P_GCC_GPLL8_OUT_MAIN, 4, 0, 0), + F(350000000, P_GCC_GPLL8_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb4_0_master_clk_src = { + .cmd_rcgr = 0x9f024, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .freq_tbl = ftbl_gcc_usb4_0_master_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_master_clk_src", + .parent_data = gcc_parent_data_4, + .num_parents = ARRAY_SIZE(gcc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb4_0_phy_pcie_pipe_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + 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_usb4_0_phy_pcie_pipe_clk_src = { + .cmd_rcgr = 0x9f0e8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_5, + .freq_tbl = ftbl_gcc_usb4_0_phy_pcie_pipe_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_phy_pcie_pipe_clk_src", + .parent_data = gcc_parent_data_5, + .num_parents = ARRAY_SIZE(gcc_parent_data_5), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb4_0_sb_if_clk_src = { + .cmd_rcgr = 0x9f08c, + .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_usb4_0_sb_if_clk_src", + .parent_data = gcc_parent_data_3, + .num_parents = ARRAY_SIZE(gcc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gcc_usb4_0_tmu_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(250000000, P_GCC_GPLL7_OUT_MAIN, 4, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_usb4_0_tmu_clk_src = { + .cmd_rcgr = 0x9f070, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_6, + .freq_tbl = ftbl_gcc_usb4_0_tmu_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_tmu_clk_src", + .parent_data = gcc_parent_data_6, + .num_parents = ARRAY_SIZE(gcc_parent_data_6), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb4_1_master_clk_src = { + .cmd_rcgr = 0x2b024, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .freq_tbl = ftbl_gcc_usb4_0_master_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_master_clk_src", + .parent_data = gcc_parent_data_4, + .num_parents = ARRAY_SIZE(gcc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb4_1_phy_pcie_pipe_clk_src = { + .cmd_rcgr = 0x2b0e8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_5, + .freq_tbl = ftbl_gcc_usb4_0_phy_pcie_pipe_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_phy_pcie_pipe_clk_src", + .parent_data = gcc_parent_data_5, + .num_parents = ARRAY_SIZE(gcc_parent_data_5), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb4_1_sb_if_clk_src = { + .cmd_rcgr = 0x2b08c, + .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_usb4_1_sb_if_clk_src", + .parent_data = gcc_parent_data_3, + .num_parents = ARRAY_SIZE(gcc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb4_1_tmu_clk_src = { + .cmd_rcgr = 0x2b070, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_6, + .freq_tbl = ftbl_gcc_usb4_0_tmu_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_tmu_clk_src", + .parent_data = gcc_parent_data_6, + .num_parents = ARRAY_SIZE(gcc_parent_data_6), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb4_2_master_clk_src = { + .cmd_rcgr = 0x11024, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_4, + .freq_tbl = ftbl_gcc_usb4_0_master_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_master_clk_src", + .parent_data = gcc_parent_data_4, + .num_parents = ARRAY_SIZE(gcc_parent_data_4), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb4_2_phy_pcie_pipe_clk_src = { + .cmd_rcgr = 0x110e8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_5, + .freq_tbl = ftbl_gcc_usb4_0_phy_pcie_pipe_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_phy_pcie_pipe_clk_src", + .parent_data = gcc_parent_data_5, + .num_parents = ARRAY_SIZE(gcc_parent_data_5), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb4_2_sb_if_clk_src = { + .cmd_rcgr = 0x1108c, + .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_usb4_2_sb_if_clk_src", + .parent_data = gcc_parent_data_3, + .num_parents = ARRAY_SIZE(gcc_parent_data_3), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_rcg2 gcc_usb4_2_tmu_clk_src = { + .cmd_rcgr = 0x11070, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gcc_parent_map_6, + .freq_tbl = ftbl_gcc_usb4_0_tmu_clk_src, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_tmu_clk_src", + .parent_data = gcc_parent_data_6, + .num_parents = ARRAY_SIZE(gcc_parent_data_6), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_regmap_phy_mux gcc_pcie_3_pipe_clk_src = { + .reg = 0x58088, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_3_pipe_clk_src", + .parent_data = &(const struct clk_parent_data){ + .index = DT_PCIE_3_PIPE, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_regmap_div gcc_pcie_3_pipe_div_clk_src = { + .reg = 0x5806c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3_pipe_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_3_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_phy_mux gcc_pcie_4_pipe_clk_src = { + .reg = 0x6b07c, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_4_pipe_clk_src", + .parent_data = &(const struct clk_parent_data){ + .index = DT_PCIE_4_PIPE, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_regmap_div gcc_pcie_4_pipe_div_clk_src = { + .reg = 0x6b060, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_4_pipe_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_4_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_phy_mux gcc_pcie_5_pipe_clk_src = { + .reg = 0x2f07c, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_5_pipe_clk_src", + .parent_data = &(const struct clk_parent_data){ + .index = DT_PCIE_5_PIPE, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_regmap_div gcc_pcie_5_pipe_div_clk_src = { + .reg = 0x2f060, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_5_pipe_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_5_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_phy_mux gcc_pcie_6a_pipe_clk_src = { + .reg = 0x31088, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_6a_pipe_clk_src", + .parent_data = &(const struct clk_parent_data){ + .index = DT_PCIE_6A_PIPE, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_regmap_div gcc_pcie_6a_pipe_div_clk_src = { + .reg = 0x3106c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6a_pipe_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_6a_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_phy_mux gcc_pcie_6b_pipe_clk_src = { + .reg = 0x8d088, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gcc_pcie_6b_pipe_clk_src", + .parent_data = &(const struct clk_parent_data){ + .index = DT_PCIE_6B_PIPE, + }, + .num_parents = 1, + .ops = &clk_regmap_phy_mux_ops, + }, + }, +}; + +static struct clk_regmap_div gcc_pcie_6b_pipe_div_clk_src = { + .reg = 0x8d06c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6b_pipe_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_6b_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_regmap_div gcc_qupv3_wrap0_s2_div_clk_src = { + .reg = 0x42284, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_s2_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap0_s2_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_wrap0_s3_div_clk_src = { + .reg = 0x423c4, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_s3_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap0_s3_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_wrap1_s2_div_clk_src = { + .reg = 0x18284, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s2_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s2_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_wrap1_s3_div_clk_src = { + .reg = 0x183c4, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_s3_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap1_s3_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_wrap2_s2_div_clk_src = { + .reg = 0x1e284, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s2_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s2_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_wrap2_s3_div_clk_src = { + .reg = 0x1e3c4, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s3_div_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_s3_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 = 0x29284, + .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_mp_mock_utmi_postdiv_clk_src = { + .reg = 0x17284, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_mp_mock_utmi_postdiv_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_mp_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 = 0x3905c, + .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 = 0xa105c, + .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_regmap_div gcc_usb30_tert_mock_utmi_postdiv_clk_src = { + .reg = 0xa205c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_tert_mock_utmi_postdiv_clk_src", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_tert_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_usb_north_axi_clk = { + .halt_reg = 0x2d17c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2d17c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2d17c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_noc_usb_north_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_noc_usb_south_axi_clk = { + .halt_reg = 0x2d174, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2d174, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2d174, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_noc_usb_south_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_ufs_phy_axi_clk = { + .halt_reg = 0x770e4, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x770e4, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x770e4, + .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_usb2_prim_axi_clk = { + .halt_reg = 0x2928c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2928c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2928c, + .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_mp_axi_clk = { + .halt_reg = 0x173d0, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x173d0, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x173d0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_usb3_mp_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_mp_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 = 0x39090, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x39090, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x39090, + .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 = 0xa1090, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xa1090, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xa1090, + .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_aggre_usb3_tert_axi_clk = { + .halt_reg = 0xa2090, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xa2090, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xa2090, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_usb3_tert_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_tert_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_usb4_0_axi_clk = { + .halt_reg = 0x9f118, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x9f118, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x9f118, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_usb4_0_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_0_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_usb4_1_axi_clk = { + .halt_reg = 0x2b118, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2b118, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2b118, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_usb4_1_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_1_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_usb4_2_axi_clk = { + .halt_reg = 0x11118, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x11118, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x11118, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_usb4_2_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_2_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_aggre_usb_noc_axi_clk = { + .halt_reg = 0x2d034, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2d034, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2d034, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_aggre_usb_noc_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_av1e_ahb_clk = { + .halt_reg = 0x4a004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x4a004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x4a004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_av1e_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_av1e_axi_clk = { + .halt_reg = 0x4a008, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x4a008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x4a008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_av1e_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_av1e_xo_clk = { + .halt_reg = 0x4a014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4a014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_av1e_xo_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_boot_rom_ahb_clk = { + .halt_reg = 0x38004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x38004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52000, + .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 = 0x26010, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x26010, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x26010, + .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 = 0x2601c, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x2601c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2601c, + .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_cfg_noc_pcie_anoc_ahb_clk = { + .halt_reg = 0x10028, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x10028, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52028, + .enable_mask = BIT(20), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_pcie_anoc_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_pcie_anoc_north_ahb_clk = { + .halt_reg = 0x1002c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x1002c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52028, + .enable_mask = BIT(22), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_pcie_anoc_north_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_pcie_anoc_south_ahb_clk = { + .halt_reg = 0x10030, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x10030, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(20), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_pcie_anoc_south_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_usb2_prim_axi_clk = { + .halt_reg = 0x29288, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x29288, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x29288, + .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_mp_axi_clk = { + .halt_reg = 0x173cc, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x173cc, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x173cc, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_usb3_mp_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_mp_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 = 0x3908c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x3908c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x3908c, + .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 = 0xa108c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xa108c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xa108c, + .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_cfg_noc_usb3_tert_axi_clk = { + .halt_reg = 0xa208c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xa208c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xa208c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_usb3_tert_axi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_tert_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_usb_anoc_ahb_clk = { + .halt_reg = 0x2d024, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2d024, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52028, + .enable_mask = BIT(21), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_usb_anoc_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_usb_anoc_north_ahb_clk = { + .halt_reg = 0x2d028, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2d028, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52028, + .enable_mask = BIT(23), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_usb_anoc_north_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cfg_noc_usb_anoc_south_ahb_clk = { + .halt_reg = 0x2d02c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2d02c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(7), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cfg_noc_usb_anoc_south_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cnoc_pcie1_tunnel_clk = { + .halt_reg = 0x2c2b4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(30), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cnoc_pcie1_tunnel_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cnoc_pcie2_tunnel_clk = { + .halt_reg = 0x132b4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(31), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cnoc_pcie2_tunnel_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cnoc_pcie_north_sf_axi_clk = { + .halt_reg = 0x10014, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x10014, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(6), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cnoc_pcie_north_sf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cnoc_pcie_south_sf_axi_clk = { + .halt_reg = 0x10018, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x10018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52028, + .enable_mask = BIT(12), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cnoc_pcie_south_sf_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cnoc_pcie_tunnel_clk = { + .halt_reg = 0xa02b4, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xa02b4, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(29), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_cnoc_pcie_tunnel_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ddrss_gpu_axi_clk = { + .halt_reg = 0x7115c, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x7115c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x7115c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ddrss_gpu_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_disp_hf_axi_clk = { + .halt_reg = 0x2700c, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x2700c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2700c, + .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_disp_xo_clk = { + .halt_reg = 0x27018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x27018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_disp_xo_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gp1_clk = { + .halt_reg = 0x64000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x64000, + .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 = 0x65000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x65000, + .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 = 0x66000, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x66000, + .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_gpu_cfg_ahb_clk = { + .halt_reg = 0x71004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x71004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x71004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_gpll0_cph_clk_src = { + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(15), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_gpll0_cph_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_cph_clk_src = { + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(16), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_gpll0_div_cph_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 = 0x71010, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x71010, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x71010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_memnoc_gfx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gpu_snoc_dvm_gfx_clk = { + .halt_reg = 0x71018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x71018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_gpu_snoc_dvm_gfx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie0_phy_rchng_clk = { + .halt_reg = 0xa0050, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(26), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie0_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_pcie1_phy_rchng_clk = { + .halt_reg = 0x2c050, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(31), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie1_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_pcie2_phy_rchng_clk = { + .halt_reg = 0x13050, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(24), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie2_phy_rchng_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_2_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_aux_clk = { + .halt_reg = 0xa0038, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(24), + .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 = 0xa0034, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xa0034, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(23), + .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 = 0xa0028, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0xa0028, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(22), + .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_pipe_clk = { + .halt_reg = 0xa0044, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(25), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_0_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_0_slv_axi_clk = { + .halt_reg = 0xa001c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xa001c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(21), + .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 = 0xa0018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(20), + .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 = 0x2c038, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(29), + .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 = 0x2c034, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2c034, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(28), + .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 = 0x2c028, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x2c028, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(27), + .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_pipe_clk = { + .halt_reg = 0x2c044, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(30), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_1_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_1_slv_axi_clk = { + .halt_reg = 0x2c01c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2c01c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(26), + .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 = 0x2c018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(25), + .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_2_aux_clk = { + .halt_reg = 0x13038, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(22), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_2_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_2_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_2_cfg_ahb_clk = { + .halt_reg = 0x13034, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x13034, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(21), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_2_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_2_mstr_axi_clk = { + .halt_reg = 0x13028, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x13028, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(20), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_2_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_2_pipe_clk = { + .halt_reg = 0x13044, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(23), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_2_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_2_slv_axi_clk = { + .halt_reg = 0x1301c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x1301c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(19), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_2_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_2_slv_q2a_axi_clk = { + .halt_reg = 0x13018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(18), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_2_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_3_aux_clk = { + .halt_reg = 0x58038, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_3_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_3_cfg_ahb_clk = { + .halt_reg = 0x58034, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x58034, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_3_mstr_axi_clk = { + .halt_reg = 0x58028, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x58028, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(31), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_3_phy_aux_clk = { + .halt_reg = 0x58044, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(2), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3_phy_aux_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_3_phy_rchng_clk = { + .halt_reg = 0x5805c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(4), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3_phy_rchng_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_3_phy_rchng_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_3_pipe_clk = { + .halt_reg = 0x58050, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(3), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_3_pipediv2_clk = { + .halt_reg = 0x58060, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .enable_mask = BIT(5), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3_pipediv2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_3_pipe_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_3_slv_axi_clk = { + .halt_reg = 0x5801c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x5801c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(30), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_3_slv_q2a_axi_clk = { + .halt_reg = 0x58018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(29), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_3_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_4_aux_clk = { + .halt_reg = 0x6b038, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(3), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_4_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_4_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_4_cfg_ahb_clk = { + .halt_reg = 0x6b034, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x6b034, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(2), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_4_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_4_mstr_axi_clk = { + .halt_reg = 0x6b028, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x6b028, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_4_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_4_phy_rchng_clk = { + .halt_reg = 0x6b050, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(22), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_4_phy_rchng_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_4_phy_rchng_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_4_pipe_clk = { + .halt_reg = 0x6b044, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(4), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_4_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_4_pipediv2_clk = { + .halt_reg = 0x6b054, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(27), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_4_pipediv2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_4_pipe_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_4_slv_axi_clk = { + .halt_reg = 0x6b01c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x6b01c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_4_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_4_slv_q2a_axi_clk = { + .halt_reg = 0x6b018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .enable_mask = BIT(5), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_4_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_5_aux_clk = { + .halt_reg = 0x2f038, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(16), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_5_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_5_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_5_cfg_ahb_clk = { + .halt_reg = 0x2f034, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2f034, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(15), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_5_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_5_mstr_axi_clk = { + .halt_reg = 0x2f028, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x2f028, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(14), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_5_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_5_phy_rchng_clk = { + .halt_reg = 0x2f050, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(18), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_5_phy_rchng_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_5_phy_rchng_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_5_pipe_clk = { + .halt_reg = 0x2f044, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(17), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_5_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_5_pipediv2_clk = { + .halt_reg = 0x2f054, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(19), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_5_pipediv2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_5_pipe_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_5_slv_axi_clk = { + .halt_reg = 0x2f01c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2f01c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(13), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_5_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_5_slv_q2a_axi_clk = { + .halt_reg = 0x2f018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(12), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_5_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6a_aux_clk = { + .halt_reg = 0x31038, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(24), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6a_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_6a_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6a_cfg_ahb_clk = { + .halt_reg = 0x31034, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x31034, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(23), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6a_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6a_mstr_axi_clk = { + .halt_reg = 0x31028, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x31028, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(22), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6a_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6a_phy_aux_clk = { + .halt_reg = 0x31044, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(25), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6a_phy_aux_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6a_phy_rchng_clk = { + .halt_reg = 0x3105c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(27), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6a_phy_rchng_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_6a_phy_rchng_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6a_pipe_clk = { + .halt_reg = 0x31050, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(26), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6a_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6a_pipediv2_clk = { + .halt_reg = 0x31060, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(28), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6a_pipediv2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_6a_pipe_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6a_slv_axi_clk = { + .halt_reg = 0x3101c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x3101c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(21), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6a_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6a_slv_q2a_axi_clk = { + .halt_reg = 0x31018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52018, + .enable_mask = BIT(20), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6a_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6b_aux_clk = { + .halt_reg = 0x8d038, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(29), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6b_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_6b_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6b_cfg_ahb_clk = { + .halt_reg = 0x8d034, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x8d034, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(28), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6b_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6b_mstr_axi_clk = { + .halt_reg = 0x8d028, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x8d028, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(27), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6b_mstr_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6b_phy_aux_clk = { + .halt_reg = 0x8d044, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(24), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6b_phy_aux_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6b_phy_rchng_clk = { + .halt_reg = 0x8d05c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(23), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6b_phy_rchng_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_6b_phy_rchng_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6b_pipe_clk = { + .halt_reg = 0x8d050, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(30), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6b_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6b_pipediv2_clk = { + .halt_reg = 0x8d060, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(28), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6b_pipediv2_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_6b_pipe_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6b_slv_axi_clk = { + .halt_reg = 0x8d01c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x8d01c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(26), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6b_slv_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_6b_slv_q2a_axi_clk = { + .halt_reg = 0x8d018, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(25), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_6b_slv_q2a_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_rscc_ahb_clk = { + .halt_reg = 0xa4008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xa4008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52028, + .enable_mask = BIT(18), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_rscc_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pcie_rscc_xo_clk = { + .halt_reg = 0xa4004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52028, + .enable_mask = BIT(17), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_pcie_rscc_xo_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_pcie_rscc_xo_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_pdm2_clk = { + .halt_reg = 0x3300c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x3300c, + .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 = 0x33004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x33004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x33004, + .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 = 0x33008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x33008, + .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_av1e_ahb_clk = { + .halt_reg = 0x4a018, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x4a018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x4a018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_av1e_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_camera_nrt_ahb_clk = { + .halt_reg = 0x26008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x26008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x26008, + .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 = 0x2600c, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2600c, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2600c, + .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_disp_ahb_clk = { + .halt_reg = 0x27008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x27008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x27008, + .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_gpu_ahb_clk = { + .halt_reg = 0x71008, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x71008, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x71008, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_gpu_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_cv_cpu_ahb_clk = { + .halt_reg = 0x32014, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x32014, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x32014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_video_cv_cpu_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_cvp_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_video_cvp_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_v_cpu_ahb_clk = { + .halt_reg = 0x32010, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x32010, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x32010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qmip_video_v_cpu_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_qmip_video_vcodec_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_video_vcodec_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 = 0x52020, + .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 = 0x23008, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .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_qspi_s2_clk = { + .halt_reg = 0x42280, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52028, + .enable_mask = BIT(2), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_qspi_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_qspi_s3_clk = { + .halt_reg = 0x423c0, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52028, + .enable_mask = BIT(3), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap0_qspi_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_s0_clk = { + .halt_reg = 0x42004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .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 = 0x4213c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .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 = 0x42274, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .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_div_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 = 0x423b4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .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_div_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 = 0x424f4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .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 = 0x4262c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .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 = 0x42764, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .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 = 0x4289c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52020, + .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 = 0x23168, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .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 = 0x23158, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .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_qspi_s2_clk = { + .halt_reg = 0x18280, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52028, + .enable_mask = BIT(4), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_qspi_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_qspi_s3_clk = { + .halt_reg = 0x183c0, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52028, + .enable_mask = BIT(5), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap1_qspi_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_s0_clk = { + .halt_reg = 0x18004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .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 = 0x1813c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .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 = 0x18274, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .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_div_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 = 0x183b4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .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_div_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 = 0x184f4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .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 = 0x1862c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .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 = 0x18764, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52008, + .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 = 0x1889c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(16), + .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_wrap2_core_2x_clk = { + .halt_reg = 0x232b8, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .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 = 0x232a8, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .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_qspi_s2_clk = { + .halt_reg = 0x1e280, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52028, + .enable_mask = BIT(6), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_qspi_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_qspi_s3_clk = { + .halt_reg = 0x1e3c0, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52028, + .enable_mask = BIT(7), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_qspi_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_s0_clk = { + .halt_reg = 0x1e004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .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 = 0x1e13c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .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 = 0x1e274, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .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_div_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 = 0x1e3b4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .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_div_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 = 0x1e4f4, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .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 = 0x1e62c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .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 = 0x1e764, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(10), + .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_wrap2_s7_clk = { + .halt_reg = 0x1e89c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(17), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_qupv3_wrap2_s7_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_qupv3_wrap2_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 = 0x23000, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x23000, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52020, + .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 = 0x23004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x23004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52020, + .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 = 0x23150, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x23150, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .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 = 0x23154, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x23154, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52008, + .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 = 0x232a0, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x232a0, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .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 = 0x232a4, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x232a4, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52010, + .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_sdcc2_ahb_clk = { + .halt_reg = 0x14010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x14010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc2_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc2_apps_clk = { + .halt_reg = 0x14004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x14004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc2_apps_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_sdcc2_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc4_ahb_clk = { + .halt_reg = 0x16010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x16010, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc4_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc4_apps_clk = { + .halt_reg = 0x16004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x16004, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sdcc4_apps_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_sdcc4_apps_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sys_noc_usb_axi_clk = { + .halt_reg = 0x2d014, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2d014, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2d014, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_sys_noc_usb_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_ahb_clk = { + .halt_reg = 0x77024, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x77024, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77024, + .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 = 0x77018, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x77018, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77018, + .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_ice_core_clk = { + .halt_reg = 0x77074, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x77074, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77074, + .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_phy_aux_clk = { + .halt_reg = 0x770b0, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x770b0, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x770b0, + .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_rx_symbol_0_clk = { + .halt_reg = 0x7702c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x7702c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_rx_symbol_0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_rx_symbol_1_clk = { + .halt_reg = 0x770cc, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x770cc, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_rx_symbol_1_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_tx_symbol_0_clk = { + .halt_reg = 0x77028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x77028, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_ufs_phy_tx_symbol_0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ufs_phy_unipro_core_clk = { + .halt_reg = 0x77068, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x77068, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x77068, + .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_usb20_master_clk = { + .halt_reg = 0x29018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x29018, + .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 = 0x29028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x29028, + .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 = 0x29024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x29024, + .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_mp_master_clk = { + .halt_reg = 0x17018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x17018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_mp_master_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_mp_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_mp_mock_utmi_clk = { + .halt_reg = 0x17028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x17028, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_mp_mock_utmi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_mp_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_mp_sleep_clk = { + .halt_reg = 0x17024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x17024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_mp_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_prim_master_clk = { + .halt_reg = 0x39018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x39018, + .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 = 0x39028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x39028, + .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 = 0x39024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x39024, + .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 = 0xa1018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa1018, + .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 = 0xa1028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa1028, + .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 = 0xa1024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa1024, + .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_usb30_tert_master_clk = { + .halt_reg = 0xa2018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa2018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_tert_master_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_tert_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb30_tert_mock_utmi_clk = { + .halt_reg = 0xa2028, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa2028, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_tert_mock_utmi_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb30_tert_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_tert_sleep_clk = { + .halt_reg = 0xa2024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa2024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb30_tert_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_mp_phy_aux_clk = { + .halt_reg = 0x17288, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x17288, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_mp_phy_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_mp_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_mp_phy_com_aux_clk = { + .halt_reg = 0x1728c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1728c, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_mp_phy_com_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_mp_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_mp_phy_pipe_0_clk = { + .halt_reg = 0x17290, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x17290, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_mp_phy_pipe_0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_mp_phy_pipe_1_clk = { + .halt_reg = 0x17298, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x17298, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_mp_phy_pipe_1_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_prim_phy_aux_clk = { + .halt_reg = 0x39060, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x39060, + .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 = 0x39064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x39064, + .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_regmap_mux gcc_usb3_prim_phy_pipe_clk_src = { + .reg = 0x3906c, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_10, + .clkr = { + .hw.init = &(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 struct clk_branch gcc_usb3_prim_phy_pipe_clk = { + .halt_reg = 0x39068, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x39068, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x39068, + .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 = 0xa1060, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa1060, + .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 = 0xa1064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa1064, + .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_regmap_mux gcc_usb3_sec_phy_pipe_clk_src = { + .reg = 0xa106c, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_11, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_sec_phy_pipe_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_branch gcc_usb3_sec_phy_pipe_clk = { + .halt_reg = 0xa1068, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xa1068, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xa1068, + .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, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_tert_phy_aux_clk = { + .halt_reg = 0xa2060, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa2060, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_tert_phy_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_tert_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_tert_phy_com_aux_clk = { + .halt_reg = 0xa2064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa2064, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_tert_phy_com_aux_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_tert_phy_aux_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap_mux gcc_usb3_tert_phy_pipe_clk_src = { + .reg = 0xa206c, + .shift = 0, + .width = 2, + .parent_map = gcc_parent_map_12, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gcc_usb3_tert_phy_pipe_clk_src", + .parent_data = gcc_parent_data_12, + .num_parents = ARRAY_SIZE(gcc_parent_data_12), + .ops = &clk_regmap_mux_closest_ops, + }, + }, +}; + +static struct clk_branch gcc_usb3_tert_phy_pipe_clk = { + .halt_reg = 0xa2068, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0xa2068, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0xa2068, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb3_tert_phy_pipe_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb3_tert_phy_pipe_clk_src.clkr.hw, + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_cfg_ahb_clk = { + .halt_reg = 0x9f0a8, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x9f0a8, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x9f0a8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_dp0_clk = { + .halt_reg = 0x9f060, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9f060, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_dp0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_dp1_clk = { + .halt_reg = 0x9f108, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9f108, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_dp1_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_master_clk = { + .halt_reg = 0x9f018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9f018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_master_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_0_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_phy_p2rr2p_pipe_clk = { + .halt_reg = 0x9f0d8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9f0d8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_phy_p2rr2p_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_phy_pcie_pipe_clk = { + .halt_reg = 0x9f048, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52010, + .enable_mask = BIT(19), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_phy_pcie_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_phy_rx0_clk = { + .halt_reg = 0x9f0b0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9f0b0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_phy_rx0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_phy_rx1_clk = { + .halt_reg = 0x9f0c0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9f0c0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_phy_rx1_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_phy_usb_pipe_clk = { + .halt_reg = 0x9f0a4, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x9f0a4, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x9f0a4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_phy_usb_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_sb_if_clk = { + .halt_reg = 0x9f044, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9f044, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_sb_if_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_0_sb_if_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_sys_clk = { + .halt_reg = 0x9f054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9f054, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_sys_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_0_tmu_clk = { + .halt_reg = 0x9f088, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x9f088, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x9f088, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_0_tmu_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_0_tmu_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_cfg_ahb_clk = { + .halt_reg = 0x2b0a8, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2b0a8, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2b0a8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_dp0_clk = { + .halt_reg = 0x2b060, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2b060, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_dp0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_dp1_clk = { + .halt_reg = 0x2b108, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2b108, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_dp1_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_master_clk = { + .halt_reg = 0x2b018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2b018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_master_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_1_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_phy_p2rr2p_pipe_clk = { + .halt_reg = 0x2b0d8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2b0d8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_phy_p2rr2p_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_phy_pcie_pipe_clk = { + .halt_reg = 0x2b048, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52028, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_phy_pcie_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_phy_rx0_clk = { + .halt_reg = 0x2b0b0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2b0b0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_phy_rx0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_phy_rx1_clk = { + .halt_reg = 0x2b0c0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2b0c0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_phy_rx1_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_phy_usb_pipe_clk = { + .halt_reg = 0x2b0a4, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2b0a4, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2b0a4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_phy_usb_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_sb_if_clk = { + .halt_reg = 0x2b044, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2b044, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_sb_if_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_1_sb_if_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_sys_clk = { + .halt_reg = 0x2b054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2b054, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_sys_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_1_tmu_clk = { + .halt_reg = 0x2b088, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x2b088, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x2b088, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_1_tmu_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_1_tmu_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_cfg_ahb_clk = { + .halt_reg = 0x110a8, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x110a8, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x110a8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_cfg_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_dp0_clk = { + .halt_reg = 0x11060, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x11060, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_dp0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_dp1_clk = { + .halt_reg = 0x11108, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x11108, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_dp1_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_master_clk = { + .halt_reg = 0x11018, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x11018, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_master_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_2_master_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_phy_p2rr2p_pipe_clk = { + .halt_reg = 0x110d8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x110d8, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_phy_p2rr2p_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_phy_pcie_pipe_clk = { + .halt_reg = 0x11048, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x52028, + .enable_mask = BIT(1), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_phy_pcie_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_phy_rx0_clk = { + .halt_reg = 0x110b0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x110b0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_phy_rx0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_phy_rx1_clk = { + .halt_reg = 0x110c0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x110c0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_phy_rx1_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_phy_usb_pipe_clk = { + .halt_reg = 0x110a4, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x110a4, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x110a4, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_phy_usb_pipe_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_sb_if_clk = { + .halt_reg = 0x11044, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x11044, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_sb_if_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_2_sb_if_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_sys_clk = { + .halt_reg = 0x11054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x11054, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_sys_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_usb4_2_tmu_clk = { + .halt_reg = 0x11088, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x11088, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x11088, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_usb4_2_tmu_clk", + .parent_hws = (const struct clk_hw*[]) { + &gcc_usb4_2_tmu_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_video_axi0_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_video_axi0_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_video_axi1_clk = { + .halt_reg = 0x32024, + .halt_check = BRANCH_HALT_SKIP, + .hwcg_reg = 0x32024, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x32024, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data) { + .name = "gcc_video_axi1_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct gdsc gcc_pcie_0_tunnel_gdsc = { + .gdscr = 0xa0004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_pcie_0_tunnel_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_1_tunnel_gdsc = { + .gdscr = 0x2c004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_pcie_1_tunnel_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_2_tunnel_gdsc = { + .gdscr = 0x13004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_pcie_2_tunnel_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_3_gdsc = { + .gdscr = 0x58004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_pcie_3_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_3_phy_gdsc = { + .gdscr = 0x3e000, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x2, + .pd = { + .name = "gcc_pcie_3_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_4_gdsc = { + .gdscr = 0x6b004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_pcie_4_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_4_phy_gdsc = { + .gdscr = 0x6c000, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x2, + .pd = { + .name = "gcc_pcie_4_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_5_gdsc = { + .gdscr = 0x2f004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_pcie_5_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_5_phy_gdsc = { + .gdscr = 0x30000, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x2, + .pd = { + .name = "gcc_pcie_5_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_6_phy_gdsc = { + .gdscr = 0x8e000, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x2, + .pd = { + .name = "gcc_pcie_6_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_6a_gdsc = { + .gdscr = 0x31004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_pcie_6a_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_pcie_6b_gdsc = { + .gdscr = 0x8d004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_pcie_6b_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE, +}; + +static struct gdsc gcc_ufs_mem_phy_gdsc = { + .gdscr = 0x9e000, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x2, + .pd = { + .name = "gcc_ufs_mem_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_ufs_phy_gdsc = { + .gdscr = 0x77004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_ufs_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb20_prim_gdsc = { + .gdscr = 0x29004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_usb20_prim_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb30_mp_gdsc = { + .gdscr = 0x17004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_usb30_mp_gdsc", + }, + .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb30_prim_gdsc = { + .gdscr = 0x39004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_usb30_prim_gdsc", + }, + .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb30_sec_gdsc = { + .gdscr = 0xa1004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_usb30_sec_gdsc", + }, + .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb30_tert_gdsc = { + .gdscr = 0xa2004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_usb30_tert_gdsc", + }, + .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb3_mp_ss0_phy_gdsc = { + .gdscr = 0x1900c, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x2, + .pd = { + .name = "gcc_usb3_mp_ss0_phy_gdsc", + }, + .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb3_mp_ss1_phy_gdsc = { + .gdscr = 0x5400c, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x2, + .pd = { + .name = "gcc_usb3_mp_ss1_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb4_0_gdsc = { + .gdscr = 0x9f004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_usb4_0_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb4_1_gdsc = { + .gdscr = 0x2b004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_usb4_1_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb4_2_gdsc = { + .gdscr = 0x11004, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0xf, + .pd = { + .name = "gcc_usb4_2_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb_0_phy_gdsc = { + .gdscr = 0x50024, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x2, + .pd = { + .name = "gcc_usb_0_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb_1_phy_gdsc = { + .gdscr = 0x2a024, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x2, + .pd = { + .name = "gcc_usb_1_phy_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct gdsc gcc_usb_2_phy_gdsc = { + .gdscr = 0xa3024, + .en_rest_wait_val = 0x2, + .en_few_wait_val = 0x2, + .clk_dis_wait_val = 0x2, + .pd = { + .name = "gcc_usb_2_phy_gdsc", + }, + .pwrsts = PWRSTS_RET_ON, + .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE, +}; + +static struct clk_regmap *gcc_x1e80100_clocks[] = { + [GCC_AGGRE_NOC_USB_NORTH_AXI_CLK] = &gcc_aggre_noc_usb_north_axi_clk.clkr, + [GCC_AGGRE_NOC_USB_SOUTH_AXI_CLK] = &gcc_aggre_noc_usb_south_axi_clk.clkr, + [GCC_AGGRE_UFS_PHY_AXI_CLK] = &gcc_aggre_ufs_phy_axi_clk.clkr, + [GCC_AGGRE_USB2_PRIM_AXI_CLK] = &gcc_aggre_usb2_prim_axi_clk.clkr, + [GCC_AGGRE_USB3_MP_AXI_CLK] = &gcc_aggre_usb3_mp_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_AGGRE_USB3_TERT_AXI_CLK] = &gcc_aggre_usb3_tert_axi_clk.clkr, + [GCC_AGGRE_USB4_0_AXI_CLK] = &gcc_aggre_usb4_0_axi_clk.clkr, + [GCC_AGGRE_USB4_1_AXI_CLK] = &gcc_aggre_usb4_1_axi_clk.clkr, + [GCC_AGGRE_USB4_2_AXI_CLK] = &gcc_aggre_usb4_2_axi_clk.clkr, + [GCC_AGGRE_USB_NOC_AXI_CLK] = &gcc_aggre_usb_noc_axi_clk.clkr, + [GCC_AV1E_AHB_CLK] = &gcc_av1e_ahb_clk.clkr, + [GCC_AV1E_AXI_CLK] = &gcc_av1e_axi_clk.clkr, + [GCC_AV1E_XO_CLK] = &gcc_av1e_xo_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_CFG_NOC_PCIE_ANOC_AHB_CLK] = &gcc_cfg_noc_pcie_anoc_ahb_clk.clkr, + [GCC_CFG_NOC_PCIE_ANOC_NORTH_AHB_CLK] = &gcc_cfg_noc_pcie_anoc_north_ahb_clk.clkr, + [GCC_CFG_NOC_PCIE_ANOC_SOUTH_AHB_CLK] = &gcc_cfg_noc_pcie_anoc_south_ahb_clk.clkr, + [GCC_CFG_NOC_USB2_PRIM_AXI_CLK] = &gcc_cfg_noc_usb2_prim_axi_clk.clkr, + [GCC_CFG_NOC_USB3_MP_AXI_CLK] = &gcc_cfg_noc_usb3_mp_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_CFG_NOC_USB3_TERT_AXI_CLK] = &gcc_cfg_noc_usb3_tert_axi_clk.clkr, + [GCC_CFG_NOC_USB_ANOC_AHB_CLK] = &gcc_cfg_noc_usb_anoc_ahb_clk.clkr, + [GCC_CFG_NOC_USB_ANOC_NORTH_AHB_CLK] = &gcc_cfg_noc_usb_anoc_north_ahb_clk.clkr, + [GCC_CFG_NOC_USB_ANOC_SOUTH_AHB_CLK] = &gcc_cfg_noc_usb_anoc_south_ahb_clk.clkr, + [GCC_CNOC_PCIE1_TUNNEL_CLK] = &gcc_cnoc_pcie1_tunnel_clk.clkr, + [GCC_CNOC_PCIE2_TUNNEL_CLK] = &gcc_cnoc_pcie2_tunnel_clk.clkr, + [GCC_CNOC_PCIE_NORTH_SF_AXI_CLK] = &gcc_cnoc_pcie_north_sf_axi_clk.clkr, + [GCC_CNOC_PCIE_SOUTH_SF_AXI_CLK] = &gcc_cnoc_pcie_south_sf_axi_clk.clkr, + [GCC_CNOC_PCIE_TUNNEL_CLK] = &gcc_cnoc_pcie_tunnel_clk.clkr, + [GCC_DDRSS_GPU_AXI_CLK] = &gcc_ddrss_gpu_axi_clk.clkr, + [GCC_DISP_HF_AXI_CLK] = &gcc_disp_hf_axi_clk.clkr, + [GCC_DISP_XO_CLK] = &gcc_disp_xo_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_GPLL4] = &gcc_gpll4.clkr, + [GCC_GPLL7] = &gcc_gpll7.clkr, + [GCC_GPLL8] = &gcc_gpll8.clkr, + [GCC_GPLL9] = &gcc_gpll9.clkr, + [GCC_GPU_CFG_AHB_CLK] = &gcc_gpu_cfg_ahb_clk.clkr, + [GCC_GPU_GPLL0_CPH_CLK_SRC] = &gcc_gpu_gpll0_cph_clk_src.clkr, + [GCC_GPU_GPLL0_DIV_CPH_CLK_SRC] = &gcc_gpu_gpll0_div_cph_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_PCIE0_PHY_RCHNG_CLK] = &gcc_pcie0_phy_rchng_clk.clkr, + [GCC_PCIE1_PHY_RCHNG_CLK] = &gcc_pcie1_phy_rchng_clk.clkr, + [GCC_PCIE2_PHY_RCHNG_CLK] = &gcc_pcie2_phy_rchng_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_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_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_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_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_2_AUX_CLK] = &gcc_pcie_2_aux_clk.clkr, + [GCC_PCIE_2_AUX_CLK_SRC] = &gcc_pcie_2_aux_clk_src.clkr, + [GCC_PCIE_2_CFG_AHB_CLK] = &gcc_pcie_2_cfg_ahb_clk.clkr, + [GCC_PCIE_2_MSTR_AXI_CLK] = &gcc_pcie_2_mstr_axi_clk.clkr, + [GCC_PCIE_2_PHY_RCHNG_CLK_SRC] = &gcc_pcie_2_phy_rchng_clk_src.clkr, + [GCC_PCIE_2_PIPE_CLK] = &gcc_pcie_2_pipe_clk.clkr, + [GCC_PCIE_2_SLV_AXI_CLK] = &gcc_pcie_2_slv_axi_clk.clkr, + [GCC_PCIE_2_SLV_Q2A_AXI_CLK] = &gcc_pcie_2_slv_q2a_axi_clk.clkr, + [GCC_PCIE_3_AUX_CLK] = &gcc_pcie_3_aux_clk.clkr, + [GCC_PCIE_3_AUX_CLK_SRC] = &gcc_pcie_3_aux_clk_src.clkr, + [GCC_PCIE_3_CFG_AHB_CLK] = &gcc_pcie_3_cfg_ahb_clk.clkr, + [GCC_PCIE_3_MSTR_AXI_CLK] = &gcc_pcie_3_mstr_axi_clk.clkr, + [GCC_PCIE_3_PHY_AUX_CLK] = &gcc_pcie_3_phy_aux_clk.clkr, + [GCC_PCIE_3_PHY_RCHNG_CLK] = &gcc_pcie_3_phy_rchng_clk.clkr, + [GCC_PCIE_3_PHY_RCHNG_CLK_SRC] = &gcc_pcie_3_phy_rchng_clk_src.clkr, + [GCC_PCIE_3_PIPE_CLK] = &gcc_pcie_3_pipe_clk.clkr, + [GCC_PCIE_3_PIPE_CLK_SRC] = &gcc_pcie_3_pipe_clk_src.clkr, + [GCC_PCIE_3_PIPE_DIV_CLK_SRC] = &gcc_pcie_3_pipe_div_clk_src.clkr, + [GCC_PCIE_3_PIPEDIV2_CLK] = &gcc_pcie_3_pipediv2_clk.clkr, + [GCC_PCIE_3_SLV_AXI_CLK] = &gcc_pcie_3_slv_axi_clk.clkr, + [GCC_PCIE_3_SLV_Q2A_AXI_CLK] = &gcc_pcie_3_slv_q2a_axi_clk.clkr, + [GCC_PCIE_4_AUX_CLK] = &gcc_pcie_4_aux_clk.clkr, + [GCC_PCIE_4_AUX_CLK_SRC] = &gcc_pcie_4_aux_clk_src.clkr, + [GCC_PCIE_4_CFG_AHB_CLK] = &gcc_pcie_4_cfg_ahb_clk.clkr, + [GCC_PCIE_4_MSTR_AXI_CLK] = &gcc_pcie_4_mstr_axi_clk.clkr, + [GCC_PCIE_4_PHY_RCHNG_CLK] = &gcc_pcie_4_phy_rchng_clk.clkr, + [GCC_PCIE_4_PHY_RCHNG_CLK_SRC] = &gcc_pcie_4_phy_rchng_clk_src.clkr, + [GCC_PCIE_4_PIPE_CLK] = &gcc_pcie_4_pipe_clk.clkr, + [GCC_PCIE_4_PIPE_CLK_SRC] = &gcc_pcie_4_pipe_clk_src.clkr, + [GCC_PCIE_4_PIPE_DIV_CLK_SRC] = &gcc_pcie_4_pipe_div_clk_src.clkr, + [GCC_PCIE_4_PIPEDIV2_CLK] = &gcc_pcie_4_pipediv2_clk.clkr, + [GCC_PCIE_4_SLV_AXI_CLK] = &gcc_pcie_4_slv_axi_clk.clkr, + [GCC_PCIE_4_SLV_Q2A_AXI_CLK] = &gcc_pcie_4_slv_q2a_axi_clk.clkr, + [GCC_PCIE_5_AUX_CLK] = &gcc_pcie_5_aux_clk.clkr, + [GCC_PCIE_5_AUX_CLK_SRC] = &gcc_pcie_5_aux_clk_src.clkr, + [GCC_PCIE_5_CFG_AHB_CLK] = &gcc_pcie_5_cfg_ahb_clk.clkr, + [GCC_PCIE_5_MSTR_AXI_CLK] = &gcc_pcie_5_mstr_axi_clk.clkr, + [GCC_PCIE_5_PHY_RCHNG_CLK] = &gcc_pcie_5_phy_rchng_clk.clkr, + [GCC_PCIE_5_PHY_RCHNG_CLK_SRC] = &gcc_pcie_5_phy_rchng_clk_src.clkr, + [GCC_PCIE_5_PIPE_CLK] = &gcc_pcie_5_pipe_clk.clkr, + [GCC_PCIE_5_PIPE_CLK_SRC] = &gcc_pcie_5_pipe_clk_src.clkr, + [GCC_PCIE_5_PIPE_DIV_CLK_SRC] = &gcc_pcie_5_pipe_div_clk_src.clkr, + [GCC_PCIE_5_PIPEDIV2_CLK] = &gcc_pcie_5_pipediv2_clk.clkr, + [GCC_PCIE_5_SLV_AXI_CLK] = &gcc_pcie_5_slv_axi_clk.clkr, + [GCC_PCIE_5_SLV_Q2A_AXI_CLK] = &gcc_pcie_5_slv_q2a_axi_clk.clkr, + [GCC_PCIE_6A_AUX_CLK] = &gcc_pcie_6a_aux_clk.clkr, + [GCC_PCIE_6A_AUX_CLK_SRC] = &gcc_pcie_6a_aux_clk_src.clkr, + [GCC_PCIE_6A_CFG_AHB_CLK] = &gcc_pcie_6a_cfg_ahb_clk.clkr, + [GCC_PCIE_6A_MSTR_AXI_CLK] = &gcc_pcie_6a_mstr_axi_clk.clkr, + [GCC_PCIE_6A_PHY_AUX_CLK] = &gcc_pcie_6a_phy_aux_clk.clkr, + [GCC_PCIE_6A_PHY_RCHNG_CLK] = &gcc_pcie_6a_phy_rchng_clk.clkr, + [GCC_PCIE_6A_PHY_RCHNG_CLK_SRC] = &gcc_pcie_6a_phy_rchng_clk_src.clkr, + [GCC_PCIE_6A_PIPE_CLK] = &gcc_pcie_6a_pipe_clk.clkr, + [GCC_PCIE_6A_PIPE_CLK_SRC] = &gcc_pcie_6a_pipe_clk_src.clkr, + [GCC_PCIE_6A_PIPE_DIV_CLK_SRC] = &gcc_pcie_6a_pipe_div_clk_src.clkr, + [GCC_PCIE_6A_PIPEDIV2_CLK] = &gcc_pcie_6a_pipediv2_clk.clkr, + [GCC_PCIE_6A_SLV_AXI_CLK] = &gcc_pcie_6a_slv_axi_clk.clkr, + [GCC_PCIE_6A_SLV_Q2A_AXI_CLK] = &gcc_pcie_6a_slv_q2a_axi_clk.clkr, + [GCC_PCIE_6B_AUX_CLK] = &gcc_pcie_6b_aux_clk.clkr, + [GCC_PCIE_6B_AUX_CLK_SRC] = &gcc_pcie_6b_aux_clk_src.clkr, + [GCC_PCIE_6B_CFG_AHB_CLK] = &gcc_pcie_6b_cfg_ahb_clk.clkr, + [GCC_PCIE_6B_MSTR_AXI_CLK] = &gcc_pcie_6b_mstr_axi_clk.clkr, + [GCC_PCIE_6B_PHY_AUX_CLK] = &gcc_pcie_6b_phy_aux_clk.clkr, + [GCC_PCIE_6B_PHY_RCHNG_CLK] = &gcc_pcie_6b_phy_rchng_clk.clkr, + [GCC_PCIE_6B_PHY_RCHNG_CLK_SRC] = &gcc_pcie_6b_phy_rchng_clk_src.clkr, + [GCC_PCIE_6B_PIPE_CLK] = &gcc_pcie_6b_pipe_clk.clkr, + [GCC_PCIE_6B_PIPE_CLK_SRC] = &gcc_pcie_6b_pipe_clk_src.clkr, + [GCC_PCIE_6B_PIPE_DIV_CLK_SRC] = &gcc_pcie_6b_pipe_div_clk_src.clkr, + [GCC_PCIE_6B_PIPEDIV2_CLK] = &gcc_pcie_6b_pipediv2_clk.clkr, + [GCC_PCIE_6B_SLV_AXI_CLK] = &gcc_pcie_6b_slv_axi_clk.clkr, + [GCC_PCIE_6B_SLV_Q2A_AXI_CLK] = &gcc_pcie_6b_slv_q2a_axi_clk.clkr, + [GCC_PCIE_RSCC_AHB_CLK] = &gcc_pcie_rscc_ahb_clk.clkr, + [GCC_PCIE_RSCC_XO_CLK] = &gcc_pcie_rscc_xo_clk.clkr, + [GCC_PCIE_RSCC_XO_CLK_SRC] = &gcc_pcie_rscc_xo_clk_src.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_AV1E_AHB_CLK] = &gcc_qmip_av1e_ahb_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_DISP_AHB_CLK] = &gcc_qmip_disp_ahb_clk.clkr, + [GCC_QMIP_GPU_AHB_CLK] = &gcc_qmip_gpu_ahb_clk.clkr, + [GCC_QMIP_VIDEO_CV_CPU_AHB_CLK] = &gcc_qmip_video_cv_cpu_ahb_clk.clkr, + [GCC_QMIP_VIDEO_CVP_AHB_CLK] = &gcc_qmip_video_cvp_ahb_clk.clkr, + [GCC_QMIP_VIDEO_V_CPU_AHB_CLK] = &gcc_qmip_video_v_cpu_ahb_clk.clkr, + [GCC_QMIP_VIDEO_VCODEC_AHB_CLK] = &gcc_qmip_video_vcodec_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_QSPI_S2_CLK] = &gcc_qupv3_wrap0_qspi_s2_clk.clkr, + [GCC_QUPV3_WRAP0_QSPI_S3_CLK] = &gcc_qupv3_wrap0_qspi_s3_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_S2_DIV_CLK_SRC] = &gcc_qupv3_wrap0_s2_div_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_S3_DIV_CLK_SRC] = &gcc_qupv3_wrap0_s3_div_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_QSPI_S2_CLK] = &gcc_qupv3_wrap1_qspi_s2_clk.clkr, + [GCC_QUPV3_WRAP1_QSPI_S3_CLK] = &gcc_qupv3_wrap1_qspi_s3_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_S2_DIV_CLK_SRC] = &gcc_qupv3_wrap1_s2_div_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_S3_DIV_CLK_SRC] = &gcc_qupv3_wrap1_s3_div_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_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_QSPI_S2_CLK] = &gcc_qupv3_wrap2_qspi_s2_clk.clkr, + [GCC_QUPV3_WRAP2_QSPI_S3_CLK] = &gcc_qupv3_wrap2_qspi_s3_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_S2_DIV_CLK_SRC] = &gcc_qupv3_wrap2_s2_div_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_S3_DIV_CLK_SRC] = &gcc_qupv3_wrap2_s3_div_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_WRAP2_S7_CLK] = &gcc_qupv3_wrap2_s7_clk.clkr, + [GCC_QUPV3_WRAP2_S7_CLK_SRC] = &gcc_qupv3_wrap2_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_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_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.clkr, + [GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr, + [GCC_SDCC2_APPS_CLK_SRC] = &gcc_sdcc2_apps_clk_src.clkr, + [GCC_SDCC4_AHB_CLK] = &gcc_sdcc4_ahb_clk.clkr, + [GCC_SDCC4_APPS_CLK] = &gcc_sdcc4_apps_clk.clkr, + [GCC_SDCC4_APPS_CLK_SRC] = &gcc_sdcc4_apps_clk_src.clkr, + [GCC_SYS_NOC_USB_AXI_CLK] = &gcc_sys_noc_usb_axi_clk.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_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_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_RX_SYMBOL_0_CLK] = &gcc_ufs_phy_rx_symbol_0_clk.clkr, + [GCC_UFS_PHY_RX_SYMBOL_1_CLK] = &gcc_ufs_phy_rx_symbol_1_clk.clkr, + [GCC_UFS_PHY_TX_SYMBOL_0_CLK] = &gcc_ufs_phy_tx_symbol_0_clk.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_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_MP_MASTER_CLK] = &gcc_usb30_mp_master_clk.clkr, + [GCC_USB30_MP_MASTER_CLK_SRC] = &gcc_usb30_mp_master_clk_src.clkr, + [GCC_USB30_MP_MOCK_UTMI_CLK] = &gcc_usb30_mp_mock_utmi_clk.clkr, + [GCC_USB30_MP_MOCK_UTMI_CLK_SRC] = &gcc_usb30_mp_mock_utmi_clk_src.clkr, + [GCC_USB30_MP_MOCK_UTMI_POSTDIV_CLK_SRC] = &gcc_usb30_mp_mock_utmi_postdiv_clk_src.clkr, + [GCC_USB30_MP_SLEEP_CLK] = &gcc_usb30_mp_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_USB30_TERT_MASTER_CLK] = &gcc_usb30_tert_master_clk.clkr, + [GCC_USB30_TERT_MASTER_CLK_SRC] = &gcc_usb30_tert_master_clk_src.clkr, + [GCC_USB30_TERT_MOCK_UTMI_CLK] = &gcc_usb30_tert_mock_utmi_clk.clkr, + [GCC_USB30_TERT_MOCK_UTMI_CLK_SRC] = &gcc_usb30_tert_mock_utmi_clk_src.clkr, + [GCC_USB30_TERT_MOCK_UTMI_POSTDIV_CLK_SRC] = &gcc_usb30_tert_mock_utmi_postdiv_clk_src.clkr, + [GCC_USB30_TERT_SLEEP_CLK] = &gcc_usb30_tert_sleep_clk.clkr, + [GCC_USB3_MP_PHY_AUX_CLK] = &gcc_usb3_mp_phy_aux_clk.clkr, + [GCC_USB3_MP_PHY_AUX_CLK_SRC] = &gcc_usb3_mp_phy_aux_clk_src.clkr, + [GCC_USB3_MP_PHY_COM_AUX_CLK] = &gcc_usb3_mp_phy_com_aux_clk.clkr, + [GCC_USB3_MP_PHY_PIPE_0_CLK] = &gcc_usb3_mp_phy_pipe_0_clk.clkr, + [GCC_USB3_MP_PHY_PIPE_1_CLK] = &gcc_usb3_mp_phy_pipe_1_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_USB3_TERT_PHY_AUX_CLK] = &gcc_usb3_tert_phy_aux_clk.clkr, + [GCC_USB3_TERT_PHY_AUX_CLK_SRC] = &gcc_usb3_tert_phy_aux_clk_src.clkr, + [GCC_USB3_TERT_PHY_COM_AUX_CLK] = &gcc_usb3_tert_phy_com_aux_clk.clkr, + [GCC_USB3_TERT_PHY_PIPE_CLK] = &gcc_usb3_tert_phy_pipe_clk.clkr, + [GCC_USB3_TERT_PHY_PIPE_CLK_SRC] = &gcc_usb3_tert_phy_pipe_clk_src.clkr, + [GCC_USB4_0_CFG_AHB_CLK] = &gcc_usb4_0_cfg_ahb_clk.clkr, + [GCC_USB4_0_DP0_CLK] = &gcc_usb4_0_dp0_clk.clkr, + [GCC_USB4_0_DP1_CLK] = &gcc_usb4_0_dp1_clk.clkr, + [GCC_USB4_0_MASTER_CLK] = &gcc_usb4_0_master_clk.clkr, + [GCC_USB4_0_MASTER_CLK_SRC] = &gcc_usb4_0_master_clk_src.clkr, + [GCC_USB4_0_PHY_P2RR2P_PIPE_CLK] = &gcc_usb4_0_phy_p2rr2p_pipe_clk.clkr, + [GCC_USB4_0_PHY_PCIE_PIPE_CLK] = &gcc_usb4_0_phy_pcie_pipe_clk.clkr, + [GCC_USB4_0_PHY_PCIE_PIPE_CLK_SRC] = &gcc_usb4_0_phy_pcie_pipe_clk_src.clkr, + [GCC_USB4_0_PHY_RX0_CLK] = &gcc_usb4_0_phy_rx0_clk.clkr, + [GCC_USB4_0_PHY_RX1_CLK] = &gcc_usb4_0_phy_rx1_clk.clkr, + [GCC_USB4_0_PHY_USB_PIPE_CLK] = &gcc_usb4_0_phy_usb_pipe_clk.clkr, + [GCC_USB4_0_SB_IF_CLK] = &gcc_usb4_0_sb_if_clk.clkr, + [GCC_USB4_0_SB_IF_CLK_SRC] = &gcc_usb4_0_sb_if_clk_src.clkr, + [GCC_USB4_0_SYS_CLK] = &gcc_usb4_0_sys_clk.clkr, + [GCC_USB4_0_TMU_CLK] = &gcc_usb4_0_tmu_clk.clkr, + [GCC_USB4_0_TMU_CLK_SRC] = &gcc_usb4_0_tmu_clk_src.clkr, + [GCC_USB4_1_CFG_AHB_CLK] = &gcc_usb4_1_cfg_ahb_clk.clkr, + [GCC_USB4_1_DP0_CLK] = &gcc_usb4_1_dp0_clk.clkr, + [GCC_USB4_1_DP1_CLK] = &gcc_usb4_1_dp1_clk.clkr, + [GCC_USB4_1_MASTER_CLK] = &gcc_usb4_1_master_clk.clkr, + [GCC_USB4_1_MASTER_CLK_SRC] = &gcc_usb4_1_master_clk_src.clkr, + [GCC_USB4_1_PHY_P2RR2P_PIPE_CLK] = &gcc_usb4_1_phy_p2rr2p_pipe_clk.clkr, + [GCC_USB4_1_PHY_PCIE_PIPE_CLK] = &gcc_usb4_1_phy_pcie_pipe_clk.clkr, + [GCC_USB4_1_PHY_PCIE_PIPE_CLK_SRC] = &gcc_usb4_1_phy_pcie_pipe_clk_src.clkr, + [GCC_USB4_1_PHY_RX0_CLK] = &gcc_usb4_1_phy_rx0_clk.clkr, + [GCC_USB4_1_PHY_RX1_CLK] = &gcc_usb4_1_phy_rx1_clk.clkr, + [GCC_USB4_1_PHY_USB_PIPE_CLK] = &gcc_usb4_1_phy_usb_pipe_clk.clkr, + [GCC_USB4_1_SB_IF_CLK] = &gcc_usb4_1_sb_if_clk.clkr, + [GCC_USB4_1_SB_IF_CLK_SRC] = &gcc_usb4_1_sb_if_clk_src.clkr, + [GCC_USB4_1_SYS_CLK] = &gcc_usb4_1_sys_clk.clkr, + [GCC_USB4_1_TMU_CLK] = &gcc_usb4_1_tmu_clk.clkr, + [GCC_USB4_1_TMU_CLK_SRC] = &gcc_usb4_1_tmu_clk_src.clkr, + [GCC_USB4_2_CFG_AHB_CLK] = &gcc_usb4_2_cfg_ahb_clk.clkr, + [GCC_USB4_2_DP0_CLK] = &gcc_usb4_2_dp0_clk.clkr, + [GCC_USB4_2_DP1_CLK] = &gcc_usb4_2_dp1_clk.clkr, + [GCC_USB4_2_MASTER_CLK] = &gcc_usb4_2_master_clk.clkr, + [GCC_USB4_2_MASTER_CLK_SRC] = &gcc_usb4_2_master_clk_src.clkr, + [GCC_USB4_2_PHY_P2RR2P_PIPE_CLK] = &gcc_usb4_2_phy_p2rr2p_pipe_clk.clkr, + [GCC_USB4_2_PHY_PCIE_PIPE_CLK] = &gcc_usb4_2_phy_pcie_pipe_clk.clkr, + [GCC_USB4_2_PHY_PCIE_PIPE_CLK_SRC] = &gcc_usb4_2_phy_pcie_pipe_clk_src.clkr, + [GCC_USB4_2_PHY_RX0_CLK] = &gcc_usb4_2_phy_rx0_clk.clkr, + [GCC_USB4_2_PHY_RX1_CLK] = &gcc_usb4_2_phy_rx1_clk.clkr, + [GCC_USB4_2_PHY_USB_PIPE_CLK] = &gcc_usb4_2_phy_usb_pipe_clk.clkr, + [GCC_USB4_2_SB_IF_CLK] = &gcc_usb4_2_sb_if_clk.clkr, + [GCC_USB4_2_SB_IF_CLK_SRC] = &gcc_usb4_2_sb_if_clk_src.clkr, + [GCC_USB4_2_SYS_CLK] = &gcc_usb4_2_sys_clk.clkr, + [GCC_USB4_2_TMU_CLK] = &gcc_usb4_2_tmu_clk.clkr, + [GCC_USB4_2_TMU_CLK_SRC] = &gcc_usb4_2_tmu_clk_src.clkr, + [GCC_VIDEO_AXI0_CLK] = &gcc_video_axi0_clk.clkr, + [GCC_VIDEO_AXI1_CLK] = &gcc_video_axi1_clk.clkr, +}; + +static struct gdsc *gcc_x1e80100_gdscs[] = { + [GCC_PCIE_0_TUNNEL_GDSC] = &gcc_pcie_0_tunnel_gdsc, + [GCC_PCIE_1_TUNNEL_GDSC] = &gcc_pcie_1_tunnel_gdsc, + [GCC_PCIE_2_TUNNEL_GDSC] = &gcc_pcie_2_tunnel_gdsc, + [GCC_PCIE_3_GDSC] = &gcc_pcie_3_gdsc, + [GCC_PCIE_3_PHY_GDSC] = &gcc_pcie_3_phy_gdsc, + [GCC_PCIE_4_GDSC] = &gcc_pcie_4_gdsc, + [GCC_PCIE_4_PHY_GDSC] = &gcc_pcie_4_phy_gdsc, + [GCC_PCIE_5_GDSC] = &gcc_pcie_5_gdsc, + [GCC_PCIE_5_PHY_GDSC] = &gcc_pcie_5_phy_gdsc, + [GCC_PCIE_6_PHY_GDSC] = &gcc_pcie_6_phy_gdsc, + [GCC_PCIE_6A_GDSC] = &gcc_pcie_6a_gdsc, + [GCC_PCIE_6B_GDSC] = &gcc_pcie_6b_gdsc, + [GCC_UFS_MEM_PHY_GDSC] = &gcc_ufs_mem_phy_gdsc, + [GCC_UFS_PHY_GDSC] = &gcc_ufs_phy_gdsc, + [GCC_USB20_PRIM_GDSC] = &gcc_usb20_prim_gdsc, + [GCC_USB30_MP_GDSC] = &gcc_usb30_mp_gdsc, + [GCC_USB30_PRIM_GDSC] = &gcc_usb30_prim_gdsc, + [GCC_USB30_SEC_GDSC] = &gcc_usb30_sec_gdsc, + [GCC_USB30_TERT_GDSC] = &gcc_usb30_tert_gdsc, + [GCC_USB3_MP_SS0_PHY_GDSC] = &gcc_usb3_mp_ss0_phy_gdsc, + [GCC_USB3_MP_SS1_PHY_GDSC] = &gcc_usb3_mp_ss1_phy_gdsc, + [GCC_USB4_0_GDSC] = &gcc_usb4_0_gdsc, + [GCC_USB4_1_GDSC] = &gcc_usb4_1_gdsc, + [GCC_USB4_2_GDSC] = &gcc_usb4_2_gdsc, + [GCC_USB_0_PHY_GDSC] = &gcc_usb_0_phy_gdsc, + [GCC_USB_1_PHY_GDSC] = &gcc_usb_1_phy_gdsc, + [GCC_USB_2_PHY_GDSC] = &gcc_usb_2_phy_gdsc, +}; + +static const struct qcom_reset_map gcc_x1e80100_resets[] = { + [GCC_AV1E_BCR] = { 0x4a000 }, + [GCC_CAMERA_BCR] = { 0x26000 }, + [GCC_DISPLAY_BCR] = { 0x27000 }, + [GCC_GPU_BCR] = { 0x71000 }, + [GCC_PCIE_0_LINK_DOWN_BCR] = { 0x6c014 }, + [GCC_PCIE_0_NOCSR_COM_PHY_BCR] = { 0x6c020 }, + [GCC_PCIE_0_PHY_BCR] = { 0x6c01c }, + [GCC_PCIE_0_PHY_NOCSR_COM_PHY_BCR] = { 0x6c028 }, + [GCC_PCIE_0_TUNNEL_BCR] = { 0xa0000 }, + [GCC_PCIE_1_LINK_DOWN_BCR] = { 0x8e014 }, + [GCC_PCIE_1_NOCSR_COM_PHY_BCR] = { 0x8e020 }, + [GCC_PCIE_1_PHY_BCR] = { 0x8e01c }, + [GCC_PCIE_1_PHY_NOCSR_COM_PHY_BCR] = { 0x8e024 }, + [GCC_PCIE_1_TUNNEL_BCR] = { 0x2c000 }, + [GCC_PCIE_2_LINK_DOWN_BCR] = { 0xa5014 }, + [GCC_PCIE_2_NOCSR_COM_PHY_BCR] = { 0xa5020 }, + [GCC_PCIE_2_PHY_BCR] = { 0xa501c }, + [GCC_PCIE_2_PHY_NOCSR_COM_PHY_BCR] = { 0xa5028 }, + [GCC_PCIE_2_TUNNEL_BCR] = { 0x13000 }, + [GCC_PCIE_3_BCR] = { 0x58000 }, + [GCC_PCIE_3_LINK_DOWN_BCR] = { 0xab014 }, + [GCC_PCIE_3_NOCSR_COM_PHY_BCR] = { 0xab020 }, + [GCC_PCIE_3_PHY_BCR] = { 0xab01c }, + [GCC_PCIE_3_PHY_NOCSR_COM_PHY_BCR] = { 0xab024 }, + [GCC_PCIE_4_BCR] = { 0x6b000 }, + [GCC_PCIE_4_LINK_DOWN_BCR] = { 0xb3014 }, + [GCC_PCIE_4_NOCSR_COM_PHY_BCR] = { 0xb3020 }, + [GCC_PCIE_4_PHY_BCR] = { 0xb301c }, + [GCC_PCIE_4_PHY_NOCSR_COM_PHY_BCR] = { 0xb3028 }, + [GCC_PCIE_5_BCR] = { 0x2f000 }, + [GCC_PCIE_5_LINK_DOWN_BCR] = { 0xaa014 }, + [GCC_PCIE_5_NOCSR_COM_PHY_BCR] = { 0xaa020 }, + [GCC_PCIE_5_PHY_BCR] = { 0xaa01c }, + [GCC_PCIE_5_PHY_NOCSR_COM_PHY_BCR] = { 0xaa028 }, + [GCC_PCIE_6A_BCR] = { 0x31000 }, + [GCC_PCIE_6A_LINK_DOWN_BCR] = { 0xac014 }, + [GCC_PCIE_6A_NOCSR_COM_PHY_BCR] = { 0xac020 }, + [GCC_PCIE_6A_PHY_BCR] = { 0xac01c }, + [GCC_PCIE_6A_PHY_NOCSR_COM_PHY_BCR] = { 0xac024 }, + [GCC_PCIE_6B_BCR] = { 0x8d000 }, + [GCC_PCIE_6B_LINK_DOWN_BCR] = { 0xb5014 }, + [GCC_PCIE_6B_NOCSR_COM_PHY_BCR] = { 0xb5020 }, + [GCC_PCIE_6B_PHY_BCR] = { 0xb501c }, + [GCC_PCIE_6B_PHY_NOCSR_COM_PHY_BCR] = { 0xb5024 }, + [GCC_PCIE_PHY_BCR] = { 0x6f000 }, + [GCC_PCIE_PHY_CFG_AHB_BCR] = { 0x6f00c }, + [GCC_PCIE_PHY_COM_BCR] = { 0x6f010 }, + [GCC_PCIE_RSCC_BCR] = { 0xa4000 }, + [GCC_PDM_BCR] = { 0x33000 }, + [GCC_QUPV3_WRAPPER_0_BCR] = { 0x42000 }, + [GCC_QUPV3_WRAPPER_1_BCR] = { 0x18000 }, + [GCC_QUPV3_WRAPPER_2_BCR] = { 0x1e000 }, + [GCC_QUSB2PHY_HS0_MP_BCR] = { 0x1200c }, + [GCC_QUSB2PHY_HS1_MP_BCR] = { 0x12010 }, + [GCC_QUSB2PHY_PRIM_BCR] = { 0x12000 }, + [GCC_QUSB2PHY_SEC_BCR] = { 0x12004 }, + [GCC_QUSB2PHY_TERT_BCR] = { 0x12008 }, + [GCC_QUSB2PHY_USB20_HS_BCR] = { 0x12014 }, + [GCC_SDCC2_BCR] = { 0x14000 }, + [GCC_SDCC4_BCR] = { 0x16000 }, + [GCC_UFS_PHY_BCR] = { 0x77000 }, + [GCC_USB20_PRIM_BCR] = { 0x29000 }, + [GCC_USB30_MP_BCR] = { 0x17000 }, + [GCC_USB30_PRIM_BCR] = { 0x39000 }, + [GCC_USB30_SEC_BCR] = { 0xa1000 }, + [GCC_USB30_TERT_BCR] = { 0xa2000 }, + [GCC_USB3_MP_SS0_PHY_BCR] = { 0x19008 }, + [GCC_USB3_MP_SS1_PHY_BCR] = { 0x54008 }, + [GCC_USB3_PHY_PRIM_BCR] = { 0x50000 }, + [GCC_USB3_PHY_SEC_BCR] = { 0x2a000 }, + [GCC_USB3_PHY_TERT_BCR] = { 0xa3000 }, + [GCC_USB3_UNIPHY_MP0_BCR] = { 0x19000 }, + [GCC_USB3_UNIPHY_MP1_BCR] = { 0x54000 }, + [GCC_USB3PHY_PHY_PRIM_BCR] = { 0x50004 }, + [GCC_USB3PHY_PHY_SEC_BCR] = { 0x2a004 }, + [GCC_USB3PHY_PHY_TERT_BCR] = { 0xa3004 }, + [GCC_USB3UNIPHY_PHY_MP0_BCR] = { 0x19004 }, + [GCC_USB3UNIPHY_PHY_MP1_BCR] = { 0x54004 }, + [GCC_USB4_0_BCR] = { 0x9f000 }, + [GCC_USB4_0_DP0_PHY_PRIM_BCR] = { 0x50010 }, + [GCC_USB4_1_DP0_PHY_SEC_BCR] = { 0x2a010 }, + [GCC_USB4_2_DP0_PHY_TERT_BCR] = { 0xa3010 }, + [GCC_USB4_1_BCR] = { 0x2b000 }, + [GCC_USB4_2_BCR] = { 0x11000 }, + [GCC_USB_0_PHY_BCR] = { 0x50020 }, + [GCC_USB_1_PHY_BCR] = { 0x2a020 }, + [GCC_USB_2_PHY_BCR] = { 0xa3020 }, + [GCC_VIDEO_BCR] = { 0x32000 }, +}; + +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), + 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_wrap2_s7_clk_src), +}; + +static const struct regmap_config gcc_x1e80100_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x1f41f0, + .fast_io = true, +}; + +static const struct qcom_cc_desc gcc_x1e80100_desc = { + .config = &gcc_x1e80100_regmap_config, + .clks = gcc_x1e80100_clocks, + .num_clks = ARRAY_SIZE(gcc_x1e80100_clocks), + .resets = gcc_x1e80100_resets, + .num_resets = ARRAY_SIZE(gcc_x1e80100_resets), + .gdscs = gcc_x1e80100_gdscs, + .num_gdscs = ARRAY_SIZE(gcc_x1e80100_gdscs), +}; + +static const struct of_device_id gcc_x1e80100_match_table[] = { + { .compatible = "qcom,x1e80100-gcc" }, + { } +}; +MODULE_DEVICE_TABLE(of, gcc_x1e80100_match_table); + +static int gcc_x1e80100_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + int ret; + + regmap = qcom_cc_map(pdev, &gcc_x1e80100_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 critical clock always-On */ + regmap_update_bits(regmap, 0x26004, BIT(0), BIT(0)); /* gcc_camera_ahb_clk */ + regmap_update_bits(regmap, 0x26028, BIT(0), BIT(0)); /* gcc_camera_xo_clk */ + regmap_update_bits(regmap, 0x27004, BIT(0), BIT(0)); /* gcc_disp_ahb_clk */ + regmap_update_bits(regmap, 0x27018, BIT(0), BIT(0)); /* gcc_disp_xo_clk */ + regmap_update_bits(regmap, 0x32004, BIT(0), BIT(0)); /* gcc_video_ahb_clk */ + regmap_update_bits(regmap, 0x32030, BIT(0), BIT(0)); /* gcc_video_xo_clk */ + regmap_update_bits(regmap, 0x71004, BIT(0), BIT(0)); /* gcc_gpu_cfg_ahb_clk */ + + /* Clear GDSC_SLEEP_ENA_VOTE to stop votes being auto-removed in sleep. */ + regmap_write(regmap, 0x52224, 0x0); + + return qcom_cc_really_probe(pdev, &gcc_x1e80100_desc, regmap); +} + +static struct platform_driver gcc_x1e80100_driver = { + .probe = gcc_x1e80100_probe, + .driver = { + .name = "gcc-x1e80100", + .of_match_table = gcc_x1e80100_match_table, + }, +}; + +static int __init gcc_x1e80100_init(void) +{ + return platform_driver_register(&gcc_x1e80100_driver); +} +subsys_initcall(gcc_x1e80100_init); + +static void __exit gcc_x1e80100_exit(void) +{ + platform_driver_unregister(&gcc_x1e80100_driver); +} +module_exit(gcc_x1e80100_exit); + +MODULE_DESCRIPTION("QTI GCC X1E80100 Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/qcom/gpucc-sm8150.c b/drivers/clk/qcom/gpucc-sm8150.c index 8422fd0474932d..c89a5b59ddb7c2 100644 --- a/drivers/clk/qcom/gpucc-sm8150.c +++ b/drivers/clk/qcom/gpucc-sm8150.c @@ -37,8 +37,8 @@ static struct alpha_pll_config gpu_cc_pll1_config = { .config_ctl_hi_val = 0x00002267, .config_ctl_hi1_val = 0x00000024, .test_ctl_val = 0x00000000, - .test_ctl_hi_val = 0x00000002, - .test_ctl_hi1_val = 0x00000000, + .test_ctl_hi_val = 0x00000000, + .test_ctl_hi1_val = 0x00000020, .user_ctl_val = 0x00000000, .user_ctl_hi_val = 0x00000805, .user_ctl_hi1_val = 0x000000d0, diff --git a/drivers/clk/qcom/gpucc-sm8550.c b/drivers/clk/qcom/gpucc-sm8550.c index 420dcb27b47dde..2fa8673424d782 100644 --- a/drivers/clk/qcom/gpucc-sm8550.c +++ b/drivers/clk/qcom/gpucc-sm8550.c @@ -35,12 +35,12 @@ enum { }; static const struct pll_vco lucid_ole_vco[] = { - { 249600000, 2300000000, 0 }, + { 249600000, 2000000000, 0 }, }; static const struct alpha_pll_config gpu_cc_pll0_config = { - .l = 0x0d, - .alpha = 0x0, + .l = 0x1e, + .alpha = 0xbaaa, .config_ctl_val = 0x20485699, .config_ctl_hi_val = 0x00182261, .config_ctl_hi1_val = 0x82aa299c, diff --git a/drivers/clk/qcom/gpucc-sm8650.c b/drivers/clk/qcom/gpucc-sm8650.c new file mode 100644 index 00000000000000..03307e482acaa7 --- /dev/null +++ b/drivers/clk/qcom/gpucc-sm8650.c @@ -0,0 +1,663 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved + * Copyright (c) 2023, Linaro Limited + */ + +#include +#include +#include +#include +#include + +#include +#include + +#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 "gdsc.h" +#include "reset.h" + +enum { + DT_BI_TCXO, + DT_GPLL0_OUT_MAIN, + DT_GPLL0_OUT_MAIN_DIV, +}; + +enum { + P_BI_TCXO, + P_GPLL0_OUT_MAIN, + P_GPLL0_OUT_MAIN_DIV, + P_GPU_CC_PLL0_OUT_MAIN, + P_GPU_CC_PLL1_OUT_MAIN, +}; + +static struct pll_vco lucid_ole_vco[] = { + { 249600000, 2100000000, 0 }, +}; + +static const struct alpha_pll_config gpu_cc_pll0_config = { + .l = 0x20, + .alpha = 0x4aaa, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00000000, + .user_ctl_hi_val = 0x00000005, +}; + +static struct clk_alpha_pll gpu_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 = "gpu_cc_pll0", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_evo_ops, + }, + }, +}; + +static const struct alpha_pll_config gpu_cc_pll1_config = { + .l = 0x1b, + .alpha = 0x1555, + .config_ctl_val = 0x20485699, + .config_ctl_hi_val = 0x00182261, + .config_ctl_hi1_val = 0x82aa299c, + .test_ctl_val = 0x00000000, + .test_ctl_hi_val = 0x00000003, + .test_ctl_hi1_val = 0x00009000, + .test_ctl_hi2_val = 0x00000034, + .user_ctl_val = 0x00000000, + .user_ctl_hi_val = 0x00000005, +}; + +static struct clk_alpha_pll gpu_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 = "gpu_cc_pll1", + .parent_data = &(const struct clk_parent_data){ + .index = DT_BI_TCXO, + }, + .num_parents = 1, + .ops = &clk_alpha_pll_lucid_evo_ops, + }, + }, +}; + +static const struct parent_map gpu_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_GPLL0_OUT_MAIN_DIV, 6 }, +}; + +static const struct clk_parent_data gpu_cc_parent_data_0[] = { + { .index = DT_BI_TCXO }, + { .index = DT_GPLL0_OUT_MAIN }, + { .index = DT_GPLL0_OUT_MAIN_DIV }, +}; + +static const struct parent_map gpu_cc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_GPU_CC_PLL0_OUT_MAIN, 1 }, + { P_GPU_CC_PLL1_OUT_MAIN, 3 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_GPLL0_OUT_MAIN_DIV, 6 }, +}; + +static const struct clk_parent_data gpu_cc_parent_data_1[] = { + { .index = DT_BI_TCXO }, + { .hw = &gpu_cc_pll0.clkr.hw }, + { .hw = &gpu_cc_pll1.clkr.hw }, + { .index = DT_GPLL0_OUT_MAIN }, + { .index = DT_GPLL0_OUT_MAIN_DIV }, +}; + +static const struct parent_map gpu_cc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_GPU_CC_PLL1_OUT_MAIN, 3 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_GPLL0_OUT_MAIN_DIV, 6 }, +}; + +static const struct clk_parent_data gpu_cc_parent_data_2[] = { + { .index = DT_BI_TCXO }, + { .hw = &gpu_cc_pll1.clkr.hw }, + { .index = DT_GPLL0_OUT_MAIN }, + { .index = DT_GPLL0_OUT_MAIN_DIV }, +}; + +static const struct freq_tbl ftbl_gpu_cc_ff_clk_src[] = { + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 gpu_cc_ff_clk_src = { + .cmd_rcgr = 0x9474, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gpu_cc_parent_map_0, + .freq_tbl = ftbl_gpu_cc_ff_clk_src, + .hw_clk_ctrl = true, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpu_cc_ff_clk_src", + .parent_data = gpu_cc_parent_data_0, + .num_parents = ARRAY_SIZE(gpu_cc_parent_data_0), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(260000000, P_GPU_CC_PLL1_OUT_MAIN, 2, 0, 0), + F(625000000, P_GPU_CC_PLL1_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gpu_cc_gmu_clk_src = { + .cmd_rcgr = 0x9318, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gpu_cc_parent_map_1, + .freq_tbl = ftbl_gpu_cc_gmu_clk_src, + .hw_clk_ctrl = true, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gmu_clk_src", + .parent_data = gpu_cc_parent_data_1, + .num_parents = ARRAY_SIZE(gpu_cc_parent_data_1), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static const struct freq_tbl ftbl_gpu_cc_hub_clk_src[] = { + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gpu_cc_hub_clk_src = { + .cmd_rcgr = 0x93ec, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gpu_cc_parent_map_2, + .freq_tbl = ftbl_gpu_cc_hub_clk_src, + .hw_clk_ctrl = true, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpu_cc_hub_clk_src", + .parent_data = gpu_cc_parent_data_2, + .num_parents = ARRAY_SIZE(gpu_cc_parent_data_2), + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_shared_ops, + }, +}; + +static struct clk_regmap_div gpu_cc_hub_div_clk_src = { + .reg = 0x942c, + .shift = 0, + .width = 4, + .clkr.hw.init = &(const struct clk_init_data) { + .name = "gpu_cc_hub_div_clk_src", + .parent_hws = (const struct clk_hw*[]){ + &gpu_cc_hub_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_regmap_div_ro_ops, + }, +}; + +static struct clk_branch gpu_cc_ahb_clk = { + .halt_reg = 0x911c, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x911c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_ahb_clk", + .parent_hws = (const struct clk_hw*[]){ + &gpu_cc_hub_div_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_crc_ahb_clk = { + .halt_reg = 0x9120, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x9120, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_crc_ahb_clk", + .parent_hws = (const struct clk_hw*[]){ + &gpu_cc_hub_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_accu_shift_clk = { + .halt_reg = 0x9160, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x9160, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gpu_cc_cx_accu_shift_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_ff_clk = { + .halt_reg = 0x914c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x914c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_ff_clk", + .parent_hws = (const struct clk_hw*[]){ + &gpu_cc_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_gmu_clk = { + .halt_reg = 0x913c, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x913c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_gmu_clk", + .parent_hws = (const struct clk_hw*[]){ + &gpu_cc_gmu_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_aon_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cxo_aon_clk = { + .halt_reg = 0x9004, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x9004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cxo_aon_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cxo_clk = { + .halt_reg = 0x9144, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9144, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cxo_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_demet_clk = { + .halt_reg = 0x900c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x900c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_demet_clk", + .ops = &clk_branch2_aon_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_freq_measure_clk = { + .halt_reg = 0x9008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_freq_measure_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_gfx3d_clk = { + .halt_reg = 0x90a8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x90a8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gx_gfx3d_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_gfx3d_rdvm_clk = { + .halt_reg = 0x90c8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x90c8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gx_gfx3d_rdvm_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_gmu_clk = { + .halt_reg = 0x90bc, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x90bc, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gx_gmu_clk", + .parent_hws = (const struct clk_hw*[]){ + &gpu_cc_gmu_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_vsense_clk = { + .halt_reg = 0x90b0, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x90b0, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gx_vsense_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_accu_shift_clk = { + .halt_reg = 0x90d0, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x90d0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gpu_cc_gx_accu_shift_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_ff_clk = { + .halt_reg = 0x90c0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x90c0, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gpu_cc_gx_ff_clk", + .parent_hws = (const struct clk_hw*[]){ + &gpu_cc_ff_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_hlos1_vote_gpu_smmu_clk = { + .halt_reg = 0x7000, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x7000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_hlos1_vote_gpu_smmu_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_hub_aon_clk = { + .halt_reg = 0x93e8, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x93e8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_hub_aon_clk", + .parent_hws = (const struct clk_hw*[]){ + &gpu_cc_hub_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_aon_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_hub_cx_int_clk = { + .halt_reg = 0x9148, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x9148, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_hub_cx_int_clk", + .parent_hws = (const struct clk_hw*[]){ + &gpu_cc_hub_clk_src.clkr.hw, + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_aon_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_memnoc_gfx_clk = { + .halt_reg = 0x9150, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x9150, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_memnoc_gfx_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_sleep_clk = { + .halt_reg = 0x9134, + .halt_check = BRANCH_HALT_VOTED, + .clkr = { + .enable_reg = 0x9134, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_sleep_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_dpm_clk = { + .halt_reg = 0x9164, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9164, + .enable_mask = BIT(0), + .hw.init = &(const struct clk_init_data){ + .name = "gpu_cc_dpm_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct gdsc gpu_cx_gdsc = { + .gdscr = 0x9108, + .gds_hw_ctrl = 0x9168, + .clk_dis_wait_val = 8, + .pd = { + .name = "gpu_cx_gdsc", + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = VOTABLE | RETAIN_FF_ENABLE, +}; + +static struct gdsc gpu_gx_gdsc = { + .gdscr = 0x905c, + .clamp_io_ctrl = 0x9504, + .resets = (unsigned int []){ GPUCC_GPU_CC_GX_BCR, + GPUCC_GPU_CC_ACD_BCR, + GPUCC_GPU_CC_GX_ACD_IROOT_BCR }, + .reset_count = 3, + .pd = { + .name = "gpu_gx_gdsc", + .power_on = gdsc_gx_do_nothing_enable, + }, + .pwrsts = PWRSTS_OFF_ON, + .flags = CLAMP_IO | AON_RESET | SW_RESET | POLL_CFG_GDSCR, +}; + +static struct clk_regmap *gpu_cc_sm8650_clocks[] = { + [GPU_CC_AHB_CLK] = &gpu_cc_ahb_clk.clkr, + [GPU_CC_CRC_AHB_CLK] = &gpu_cc_crc_ahb_clk.clkr, + [GPU_CC_CX_ACCU_SHIFT_CLK] = &gpu_cc_cx_accu_shift_clk.clkr, + [GPU_CC_CX_FF_CLK] = &gpu_cc_cx_ff_clk.clkr, + [GPU_CC_CX_GMU_CLK] = &gpu_cc_cx_gmu_clk.clkr, + [GPU_CC_CXO_AON_CLK] = &gpu_cc_cxo_aon_clk.clkr, + [GPU_CC_CXO_CLK] = &gpu_cc_cxo_clk.clkr, + [GPU_CC_DEMET_CLK] = &gpu_cc_demet_clk.clkr, + [GPU_CC_DPM_CLK] = &gpu_cc_dpm_clk.clkr, + [GPU_CC_FF_CLK_SRC] = &gpu_cc_ff_clk_src.clkr, + [GPU_CC_FREQ_MEASURE_CLK] = &gpu_cc_freq_measure_clk.clkr, + [GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr, + [GPU_CC_GX_ACCU_SHIFT_CLK] = &gpu_cc_gx_accu_shift_clk.clkr, + [GPU_CC_GX_FF_CLK] = &gpu_cc_gx_ff_clk.clkr, + [GPU_CC_GX_GFX3D_CLK] = &gpu_cc_gx_gfx3d_clk.clkr, + [GPU_CC_GX_GFX3D_RDVM_CLK] = &gpu_cc_gx_gfx3d_rdvm_clk.clkr, + [GPU_CC_GX_GMU_CLK] = &gpu_cc_gx_gmu_clk.clkr, + [GPU_CC_GX_VSENSE_CLK] = &gpu_cc_gx_vsense_clk.clkr, + [GPU_CC_HLOS1_VOTE_GPU_SMMU_CLK] = &gpu_cc_hlos1_vote_gpu_smmu_clk.clkr, + [GPU_CC_HUB_AON_CLK] = &gpu_cc_hub_aon_clk.clkr, + [GPU_CC_HUB_CLK_SRC] = &gpu_cc_hub_clk_src.clkr, + [GPU_CC_HUB_CX_INT_CLK] = &gpu_cc_hub_cx_int_clk.clkr, + [GPU_CC_HUB_DIV_CLK_SRC] = &gpu_cc_hub_div_clk_src.clkr, + [GPU_CC_MEMNOC_GFX_CLK] = &gpu_cc_memnoc_gfx_clk.clkr, + [GPU_CC_PLL0] = &gpu_cc_pll0.clkr, + [GPU_CC_PLL1] = &gpu_cc_pll1.clkr, + [GPU_CC_SLEEP_CLK] = &gpu_cc_sleep_clk.clkr, +}; + +static const struct qcom_reset_map gpu_cc_sm8650_resets[] = { + [GPUCC_GPU_CC_XO_BCR] = { 0x9000 }, + [GPUCC_GPU_CC_GX_BCR] = { 0x9058 }, + [GPUCC_GPU_CC_CX_BCR] = { 0x9104 }, + [GPUCC_GPU_CC_GFX3D_AON_BCR] = { 0x9198 }, + [GPUCC_GPU_CC_ACD_BCR] = { 0x9358 }, + [GPUCC_GPU_CC_FAST_HUB_BCR] = { 0x93e4 }, + [GPUCC_GPU_CC_FF_BCR] = { 0x9470 }, + [GPUCC_GPU_CC_GMU_BCR] = { 0x9314 }, + [GPUCC_GPU_CC_GX_ACD_IROOT_BCR] = { 0x958c }, +}; + +static struct gdsc *gpu_cc_sm8650_gdscs[] = { + [GPU_CX_GDSC] = &gpu_cx_gdsc, + [GPU_GX_GDSC] = &gpu_gx_gdsc, +}; + +static const struct regmap_config gpu_cc_sm8650_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0xa000, + .fast_io = true, +}; + +static const struct qcom_cc_desc gpu_cc_sm8650_desc = { + .config = &gpu_cc_sm8650_regmap_config, + .clks = gpu_cc_sm8650_clocks, + .num_clks = ARRAY_SIZE(gpu_cc_sm8650_clocks), + .resets = gpu_cc_sm8650_resets, + .num_resets = ARRAY_SIZE(gpu_cc_sm8650_resets), + .gdscs = gpu_cc_sm8650_gdscs, + .num_gdscs = ARRAY_SIZE(gpu_cc_sm8650_gdscs), +}; + +static const struct of_device_id gpu_cc_sm8650_match_table[] = { + { .compatible = "qcom,sm8650-gpucc" }, + { } +}; +MODULE_DEVICE_TABLE(of, gpu_cc_sm8650_match_table); + +static int gpu_cc_sm8650_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + + regmap = qcom_cc_map(pdev, &gpu_cc_sm8650_desc); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + clk_lucid_ole_pll_configure(&gpu_cc_pll0, regmap, &gpu_cc_pll0_config); + clk_lucid_ole_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config); + + return qcom_cc_really_probe(pdev, &gpu_cc_sm8650_desc, regmap); +} + +static struct platform_driver gpu_cc_sm8650_driver = { + .probe = gpu_cc_sm8650_probe, + .driver = { + .name = "sm8650-gpucc", + .of_match_table = gpu_cc_sm8650_match_table, + }, +}; +module_platform_driver(gpu_cc_sm8650_driver); + +MODULE_DESCRIPTION("QTI GPU_CC SM8650 Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/qcom/tcsrcc-sm8650.c b/drivers/clk/qcom/tcsrcc-sm8650.c new file mode 100644 index 00000000000000..11c7d6df48c7b3 --- /dev/null +++ b/drivers/clk/qcom/tcsrcc-sm8650.c @@ -0,0 +1,182 @@ +// 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) 2023, Linaro Limited + */ + +#include +#include +#include +#include +#include + +#include + +#include "clk-branch.h" +#include "clk-regmap.h" +#include "common.h" +#include "reset.h" + +enum { + DT_BI_TCXO_PAD, +}; + +static struct clk_branch tcsr_pcie_0_clkref_en = { + .halt_reg = 0x31100, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x31100, + .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 = 0x31114, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x31114, + .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 = 0x31110, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x31110, + .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 = 0x31104, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x31104, + .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 = 0x31118, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x31118, + .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 = 0x31108, + .halt_check = BRANCH_HALT_DELAY, + .clkr = { + .enable_reg = 0x31108, + .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_sm8650_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_sm8650_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x3b000, + .fast_io = true, +}; + +static const struct qcom_cc_desc tcsr_cc_sm8650_desc = { + .config = &tcsr_cc_sm8650_regmap_config, + .clks = tcsr_cc_sm8650_clocks, + .num_clks = ARRAY_SIZE(tcsr_cc_sm8650_clocks), +}; + +static const struct of_device_id tcsr_cc_sm8650_match_table[] = { + { .compatible = "qcom,sm8650-tcsr" }, + { } +}; +MODULE_DEVICE_TABLE(of, tcsr_cc_sm8650_match_table); + +static int tcsr_cc_sm8650_probe(struct platform_device *pdev) +{ + return qcom_cc_probe(pdev, &tcsr_cc_sm8650_desc); +} + +static struct platform_driver tcsr_cc_sm8650_driver = { + .probe = tcsr_cc_sm8650_probe, + .driver = { + .name = "tcsr_cc-sm8650", + .of_match_table = tcsr_cc_sm8650_match_table, + }, +}; + +static int __init tcsr_cc_sm8650_init(void) +{ + return platform_driver_register(&tcsr_cc_sm8650_driver); +} +subsys_initcall(tcsr_cc_sm8650_init); + +static void __exit tcsr_cc_sm8650_exit(void) +{ + platform_driver_unregister(&tcsr_cc_sm8650_driver); +} +module_exit(tcsr_cc_sm8650_exit); + +MODULE_DESCRIPTION("QTI TCSRCC SM8650 Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/qcom/videocc-sm8150.c b/drivers/clk/qcom/videocc-sm8150.c index 1afdbe4a249d62..f1456eaa87c401 100644 --- a/drivers/clk/qcom/videocc-sm8150.c +++ b/drivers/clk/qcom/videocc-sm8150.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -33,6 +34,7 @@ static struct alpha_pll_config video_pll0_config = { .config_ctl_val = 0x20485699, .config_ctl_hi_val = 0x00002267, .config_ctl_hi1_val = 0x00000024, + .test_ctl_hi1_val = 0x00000020, .user_ctl_val = 0x00000000, .user_ctl_hi_val = 0x00000805, .user_ctl_hi1_val = 0x000000D0, @@ -214,6 +216,10 @@ static const struct regmap_config video_cc_sm8150_regmap_config = { static const struct qcom_reset_map video_cc_sm8150_resets[] = { [VIDEO_CC_MVSC_CORE_CLK_BCR] = { 0x850, 2 }, + [VIDEO_CC_INTERFACE_BCR] = { 0x8f0 }, + [VIDEO_CC_MVS0_BCR] = { 0x870 }, + [VIDEO_CC_MVS1_BCR] = { 0x8b0 }, + [VIDEO_CC_MVSC_BCR] = { 0x810 }, }; static const struct qcom_cc_desc video_cc_sm8150_desc = { @@ -235,17 +241,32 @@ MODULE_DEVICE_TABLE(of, video_cc_sm8150_match_table); static int video_cc_sm8150_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, &video_cc_sm8150_desc); - if (IS_ERR(regmap)) + if (IS_ERR(regmap)) { + pm_runtime_put_sync(&pdev->dev); return PTR_ERR(regmap); + } clk_trion_pll_configure(&video_pll0, regmap, &video_pll0_config); /* Keep VIDEO_CC_XO_CLK ALWAYS-ON */ regmap_update_bits(regmap, 0x984, 0x1, 0x1); - return qcom_cc_really_probe(pdev, &video_cc_sm8150_desc, regmap); + ret = qcom_cc_really_probe(pdev, &video_cc_sm8150_desc, regmap); + + pm_runtime_put_sync(&pdev->dev); + + return ret; } static struct platform_driver video_cc_sm8150_driver = { diff --git a/drivers/clk/renesas/r8a779g0-cpg-mssr.c b/drivers/clk/renesas/r8a779g0-cpg-mssr.c index 7cc580d6736261..5974adcef3eda1 100644 --- a/drivers/clk/renesas/r8a779g0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a779g0-cpg-mssr.c @@ -192,6 +192,8 @@ static const struct mssr_mod_clk r8a779g0_mod_clks[] __initconst = { DEF_MOD("msi3", 621, R8A779G0_CLK_MSO), DEF_MOD("msi4", 622, R8A779G0_CLK_MSO), DEF_MOD("msi5", 623, R8A779G0_CLK_MSO), + DEF_MOD("pciec0", 624, R8A779G0_CLK_S0D2_HSC), + DEF_MOD("pscie1", 625, R8A779G0_CLK_S0D2_HSC), DEF_MOD("pwm", 628, R8A779G0_CLK_SASYNCPERD4), DEF_MOD("rpc-if", 629, R8A779G0_CLK_RPCD2), DEF_MOD("scif0", 702, R8A779G0_CLK_SASYNCPERD4), @@ -235,6 +237,7 @@ static const struct mssr_mod_clk r8a779g0_mod_clks[] __initconst = { DEF_MOD("pfc2", 917, R8A779G0_CLK_CL16M), DEF_MOD("pfc3", 918, R8A779G0_CLK_CL16M), DEF_MOD("tsc", 919, R8A779G0_CLK_CL16M), + DEF_MOD("tsn", 2723, R8A779G0_CLK_S0D4_HSC), DEF_MOD("ssiu", 2926, R8A779G0_CLK_S0D6_PER), DEF_MOD("ssi", 2927, R8A779G0_CLK_S0D6_PER), }; diff --git a/drivers/clk/renesas/r9a08g045-cpg.c b/drivers/clk/renesas/r9a08g045-cpg.c index 4394cb241d9948..2582ba95256ead 100644 --- a/drivers/clk/renesas/r9a08g045-cpg.c +++ b/drivers/clk/renesas/r9a08g045-cpg.c @@ -181,13 +181,16 @@ static const struct cpg_core_clk r9a08g045_core_clks[] __initconst = { DEF_G3S_DIV("P3", R9A08G045_CLK_P3, CLK_PLL3_DIV2_4, DIVPL3C, G3S_DIVPL3C_STS, dtable_1_32, 0, 0, 0, NULL), DEF_FIXED("P3_DIV2", CLK_P3_DIV2, R9A08G045_CLK_P3, 1, 2), + DEF_FIXED("ZT", R9A08G045_CLK_ZT, CLK_PLL3_DIV2_8, 1, 1), DEF_FIXED("S0", R9A08G045_CLK_S0, CLK_SEL_PLL4, 1, 2), DEF_FIXED("OSC", R9A08G045_OSCCLK, CLK_EXTAL, 1, 1), DEF_FIXED("OSC2", R9A08G045_OSCCLK2, CLK_EXTAL, 1, 3), + DEF_FIXED("HP", R9A08G045_CLK_HP, CLK_PLL6, 1, 2), }; static const struct rzg2l_mod_clk r9a08g045_mod_clks[] = { DEF_MOD("gic_gicclk", R9A08G045_GIC600_GICCLK, R9A08G045_CLK_P1, 0x514, 0), + DEF_MOD("ia55_pclk", R9A08G045_IA55_PCLK, R9A08G045_CLK_P2, 0x518, 0), DEF_MOD("ia55_clk", R9A08G045_IA55_CLK, R9A08G045_CLK_P1, 0x518, 1), DEF_MOD("dmac_aclk", R9A08G045_DMAC_ACLK, R9A08G045_CLK_P3, 0x52c, 0), DEF_MOD("sdhi0_imclk", R9A08G045_SDHI0_IMCLK, CLK_SD0_DIV4, 0x554, 0), @@ -202,6 +205,12 @@ static const struct rzg2l_mod_clk r9a08g045_mod_clks[] = { DEF_MOD("sdhi2_imclk2", R9A08G045_SDHI2_IMCLK2, CLK_SD2_DIV4, 0x554, 9), DEF_MOD("sdhi2_clk_hs", R9A08G045_SDHI2_CLK_HS, R9A08G045_CLK_SD2, 0x554, 10), DEF_MOD("sdhi2_aclk", R9A08G045_SDHI2_ACLK, R9A08G045_CLK_P1, 0x554, 11), + DEF_COUPLED("eth0_axi", R9A08G045_ETH0_CLK_AXI, R9A08G045_CLK_M0, 0x57c, 0), + DEF_COUPLED("eth0_chi", R9A08G045_ETH0_CLK_CHI, R9A08G045_CLK_ZT, 0x57c, 0), + DEF_MOD("eth0_refclk", R9A08G045_ETH0_REFCLK, R9A08G045_CLK_HP, 0x57c, 8), + DEF_COUPLED("eth1_axi", R9A08G045_ETH1_CLK_AXI, R9A08G045_CLK_M0, 0x57c, 1), + DEF_COUPLED("eth1_chi", R9A08G045_ETH1_CLK_CHI, R9A08G045_CLK_ZT, 0x57c, 1), + DEF_MOD("eth1_refclk", R9A08G045_ETH1_REFCLK, R9A08G045_CLK_HP, 0x57c, 9), DEF_MOD("scif0_clk_pck", R9A08G045_SCIF0_CLK_PCK, R9A08G045_CLK_P0, 0x584, 0), DEF_MOD("gpio_hclk", R9A08G045_GPIO_HCLK, R9A08G045_OSCCLK, 0x598, 0), }; @@ -209,9 +218,12 @@ static const struct rzg2l_mod_clk r9a08g045_mod_clks[] = { static const struct rzg2l_reset r9a08g045_resets[] = { DEF_RST(R9A08G045_GIC600_GICRESET_N, 0x814, 0), DEF_RST(R9A08G045_GIC600_DBG_GICRESET_N, 0x814, 1), + DEF_RST(R9A08G045_IA55_RESETN, 0x818, 0), DEF_RST(R9A08G045_SDHI0_IXRST, 0x854, 0), DEF_RST(R9A08G045_SDHI1_IXRST, 0x854, 1), DEF_RST(R9A08G045_SDHI2_IXRST, 0x854, 2), + DEF_RST(R9A08G045_ETH0_RST_HW_N, 0x87c, 0), + DEF_RST(R9A08G045_ETH1_RST_HW_N, 0x87c, 1), DEF_RST(R9A08G045_SCIF0_RST_SYSTEM_N, 0x884, 0), DEF_RST(R9A08G045_GPIO_RSTN, 0x898, 0), DEF_RST(R9A08G045_GPIO_PORT_RESETN, 0x898, 1), @@ -220,6 +232,7 @@ static const struct rzg2l_reset r9a08g045_resets[] = { static const unsigned int r9a08g045_crit_mod_clks[] __initconst = { MOD_CLK_BASE + R9A08G045_GIC600_GICCLK, + MOD_CLK_BASE + R9A08G045_IA55_PCLK, MOD_CLK_BASE + R9A08G045_IA55_CLK, MOD_CLK_BASE + R9A08G045_DMAC_ACLK, }; diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index 764bd72cf05914..3d2daa4ba2a4bf 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -1410,41 +1410,33 @@ fail: #define rcdev_to_priv(x) container_of(x, struct rzg2l_cpg_priv, rcdev) -static int rzg2l_cpg_reset(struct reset_controller_dev *rcdev, - unsigned long id) -{ - struct rzg2l_cpg_priv *priv = rcdev_to_priv(rcdev); - const struct rzg2l_cpg_info *info = priv->info; - unsigned int reg = info->resets[id].off; - u32 dis = BIT(info->resets[id].bit); - u32 we = dis << 16; - - dev_dbg(rcdev->dev, "reset id:%ld offset:0x%x\n", id, CLK_RST_R(reg)); - - /* Reset module */ - writel(we, priv->base + CLK_RST_R(reg)); - - /* Wait for at least one cycle of the RCLK clock (@ ca. 32 kHz) */ - udelay(35); - - /* Release module from reset state */ - writel(we | dis, priv->base + CLK_RST_R(reg)); - - return 0; -} - static int rzg2l_cpg_assert(struct reset_controller_dev *rcdev, unsigned long id) { struct rzg2l_cpg_priv *priv = rcdev_to_priv(rcdev); const struct rzg2l_cpg_info *info = priv->info; unsigned int reg = info->resets[id].off; - u32 value = BIT(info->resets[id].bit) << 16; + u32 mask = BIT(info->resets[id].bit); + s8 monbit = info->resets[id].monbit; + u32 value = mask << 16; dev_dbg(rcdev->dev, "assert id:%ld offset:0x%x\n", id, CLK_RST_R(reg)); writel(value, priv->base + CLK_RST_R(reg)); - return 0; + + if (info->has_clk_mon_regs) { + reg = CLK_MRST_R(reg); + } else if (monbit >= 0) { + reg = CPG_RST_MON; + mask = BIT(monbit); + } else { + /* Wait for at least one cycle of the RCLK clock (@ ca. 32 kHz) */ + udelay(35); + return 0; + } + + return readl_poll_timeout_atomic(priv->base + reg, value, + value & mask, 10, 200); } static int rzg2l_cpg_deassert(struct reset_controller_dev *rcdev, @@ -1453,14 +1445,40 @@ static int rzg2l_cpg_deassert(struct reset_controller_dev *rcdev, struct rzg2l_cpg_priv *priv = rcdev_to_priv(rcdev); const struct rzg2l_cpg_info *info = priv->info; unsigned int reg = info->resets[id].off; - u32 dis = BIT(info->resets[id].bit); - u32 value = (dis << 16) | dis; + u32 mask = BIT(info->resets[id].bit); + s8 monbit = info->resets[id].monbit; + u32 value = (mask << 16) | mask; dev_dbg(rcdev->dev, "deassert id:%ld offset:0x%x\n", id, CLK_RST_R(reg)); writel(value, priv->base + CLK_RST_R(reg)); - return 0; + + if (info->has_clk_mon_regs) { + reg = CLK_MRST_R(reg); + } else if (monbit >= 0) { + reg = CPG_RST_MON; + mask = BIT(monbit); + } else { + /* Wait for at least one cycle of the RCLK clock (@ ca. 32 kHz) */ + udelay(35); + return 0; + } + + return readl_poll_timeout_atomic(priv->base + reg, value, + !(value & mask), 10, 200); +} + +static int rzg2l_cpg_reset(struct reset_controller_dev *rcdev, + unsigned long id) +{ + int ret; + + ret = rzg2l_cpg_assert(rcdev, id); + if (ret) + return ret; + + return rzg2l_cpg_deassert(rcdev, id); } static int rzg2l_cpg_status(struct reset_controller_dev *rcdev, @@ -1468,18 +1486,21 @@ static int rzg2l_cpg_status(struct reset_controller_dev *rcdev, { struct rzg2l_cpg_priv *priv = rcdev_to_priv(rcdev); const struct rzg2l_cpg_info *info = priv->info; - unsigned int reg = info->resets[id].off; - u32 bitmask = BIT(info->resets[id].bit); s8 monbit = info->resets[id].monbit; + unsigned int reg; + u32 bitmask; if (info->has_clk_mon_regs) { - return !!(readl(priv->base + CLK_MRST_R(reg)) & bitmask); + reg = CLK_MRST_R(info->resets[id].off); + bitmask = BIT(info->resets[id].bit); } else if (monbit >= 0) { - u32 monbitmask = BIT(monbit); - - return !!(readl(priv->base + CPG_RST_MON) & monbitmask); + reg = CPG_RST_MON; + bitmask = BIT(monbit); + } else { + return -ENOTSUPP; } - return -ENOTSUPP; + + return !!(readl(priv->base + reg) & bitmask); } static const struct reset_control_ops rzg2l_cpg_reset_ops = { diff --git a/drivers/clk/rockchip/clk-rk3568.c b/drivers/clk/rockchip/clk-rk3568.c index db713e1526cdc3..b786ddc9af2af6 100644 --- a/drivers/clk/rockchip/clk-rk3568.c +++ b/drivers/clk/rockchip/clk-rk3568.c @@ -78,7 +78,9 @@ static struct rockchip_pll_rate_table rk3568_pll_rates[] = { RK3036_PLL_RATE(200000000, 1, 100, 3, 4, 1, 0), RK3036_PLL_RATE(148500000, 1, 99, 4, 4, 1, 0), RK3036_PLL_RATE(135000000, 2, 45, 4, 1, 1, 0), + RK3036_PLL_RATE(126400000, 1, 79, 5, 3, 1, 0), RK3036_PLL_RATE(119000000, 3, 119, 4, 2, 1, 0), + RK3036_PLL_RATE(115200000, 1, 24, 5, 1, 1, 0), RK3036_PLL_RATE(108000000, 2, 45, 5, 1, 1, 0), RK3036_PLL_RATE(101000000, 1, 101, 6, 4, 1, 0), RK3036_PLL_RATE(100000000, 1, 150, 6, 6, 1, 0), @@ -1593,6 +1595,7 @@ static const char *const rk3568_cru_critical_clocks[] __initconst = { "hclk_php", "pclk_php", "hclk_usb", + "pclk_usb", "hclk_vo", }; diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile index ebbeacabe88f69..3056944a5a545c 100644 --- a/drivers/clk/samsung/Makefile +++ b/drivers/clk/samsung/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos7.o obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos7885.o obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos850.o obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynosautov9.o +obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-gs101.o obj-$(CONFIG_S3C64XX_COMMON_CLK) += clk-s3c64xx.o obj-$(CONFIG_S5PV210_COMMON_CLK) += clk-s5pv210.o clk-s5pv210-audss.o obj-$(CONFIG_TESLA_FSD_COMMON_CLK) += clk-fsd.o diff --git a/drivers/clk/samsung/clk-cpu.h b/drivers/clk/samsung/clk-cpu.h index fc9f67a3b22e8b..0164bd9ad021b9 100644 --- a/drivers/clk/samsung/clk-cpu.h +++ b/drivers/clk/samsung/clk-cpu.h @@ -11,10 +11,10 @@ #include "clk.h" /** - * struct exynos_cpuclk_data: config data to setup cpu clocks. - * @prate: frequency of the primary parent clock (in KHz). - * @div0: value to be programmed in the div_cpu0 register. - * @div1: value to be programmed in the div_cpu1 register. + * struct exynos_cpuclk_cfg_data - config data to setup cpu clocks + * @prate: frequency of the primary parent clock (in KHz) + * @div0: value to be programmed in the div_cpu0 register + * @div1: value to be programmed in the div_cpu1 register * * This structure holds the divider configuration data for dividers in the CPU * clock domain. The parent frequency at which these divider values are valid is @@ -29,17 +29,17 @@ struct exynos_cpuclk_cfg_data { }; /** - * struct exynos_cpuclk: information about clock supplied to a CPU core. - * @hw: handle between CCF and CPU clock. - * @alt_parent: alternate parent clock to use when switching the speed - * of the primary parent clock. - * @ctrl_base: base address of the clock controller. - * @lock: cpu clock domain register access lock. - * @cfg: cpu clock rate configuration data. - * @num_cfgs: number of array elements in @cfg array. - * @clk_nb: clock notifier registered for changes in clock speed of the - * primary parent clock. - * @flags: configuration flags for the CPU clock. + * struct exynos_cpuclk - information about clock supplied to a CPU core + * @hw: handle between CCF and CPU clock + * @alt_parent: alternate parent clock to use when switching the speed + * of the primary parent clock + * @ctrl_base: base address of the clock controller + * @lock: cpu clock domain register access lock + * @cfg: cpu clock rate configuration data + * @num_cfgs: number of array elements in @cfg array + * @clk_nb: clock notifier registered for changes in clock speed of the + * primary parent clock + * @flags: configuration flags for the CPU clock * * This structure holds information required for programming the CPU clock for * various clock speeds. diff --git a/drivers/clk/samsung/clk-gs101.c b/drivers/clk/samsung/clk-gs101.c new file mode 100644 index 00000000000000..0964bb11657f10 --- /dev/null +++ b/drivers/clk/samsung/clk-gs101.c @@ -0,0 +1,2518 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2023 Linaro Ltd. + * Author: Peter Griffin + * + * Common Clock Framework support for GS101. + */ + +#include +#include +#include +#include + +#include + +#include "clk.h" +#include "clk-exynos-arm64.h" + +/* NOTE: Must be equal to the last clock ID increased by one */ +#define CLKS_NR_TOP (CLK_GOUT_CMU_TPU_UART + 1) +#define CLKS_NR_APM (CLK_APM_PLL_DIV16_APM + 1) +#define CLKS_NR_MISC (CLK_GOUT_MISC_XIU_D_MISC_ACLK + 1) + +/* ---- CMU_TOP ------------------------------------------------------------- */ + +/* Register Offset definitions for CMU_TOP (0x1e080000) */ + +#define PLL_LOCKTIME_PLL_SHARED0 0x0000 +#define PLL_LOCKTIME_PLL_SHARED1 0x0004 +#define PLL_LOCKTIME_PLL_SHARED2 0x0008 +#define PLL_LOCKTIME_PLL_SHARED3 0x000c +#define PLL_LOCKTIME_PLL_SPARE 0x0010 +#define PLL_CON0_PLL_SHARED0 0x0100 +#define PLL_CON1_PLL_SHARED0 0x0104 +#define PLL_CON2_PLL_SHARED0 0x0108 +#define PLL_CON3_PLL_SHARED0 0x010c +#define PLL_CON4_PLL_SHARED0 0x0110 +#define PLL_CON0_PLL_SHARED1 0x0140 +#define PLL_CON1_PLL_SHARED1 0x0144 +#define PLL_CON2_PLL_SHARED1 0x0148 +#define PLL_CON3_PLL_SHARED1 0x014c +#define PLL_CON4_PLL_SHARED1 0x0150 +#define PLL_CON0_PLL_SHARED2 0x0180 +#define PLL_CON1_PLL_SHARED2 0x0184 +#define PLL_CON2_PLL_SHARED2 0x0188 +#define PLL_CON3_PLL_SHARED2 0x018c +#define PLL_CON4_PLL_SHARED2 0x0190 +#define PLL_CON0_PLL_SHARED3 0x01c0 +#define PLL_CON1_PLL_SHARED3 0x01c4 +#define PLL_CON2_PLL_SHARED3 0x01c8 +#define PLL_CON3_PLL_SHARED3 0x01cc +#define PLL_CON4_PLL_SHARED3 0x01d0 +#define PLL_CON0_PLL_SPARE 0x0200 +#define PLL_CON1_PLL_SPARE 0x0204 +#define PLL_CON2_PLL_SPARE 0x0208 +#define PLL_CON3_PLL_SPARE 0x020c +#define PLL_CON4_PLL_SPARE 0x0210 +#define CMU_CMU_TOP_CONTROLLER_OPTION 0x0800 +#define CLKOUT_CON_BLK_CMU_CMU_TOP_CLKOUT0 0x0810 +#define CMU_HCHGEN_CLKMUX_CMU_BOOST 0x0840 +#define CMU_HCHGEN_CLKMUX_TOP_BOOST 0x0844 +#define CMU_HCHGEN_CLKMUX 0x0850 +#define POWER_FAIL_DETECT_PLL 0x0864 +#define EARLY_WAKEUP_FORCED_0_ENABLE 0x0870 +#define EARLY_WAKEUP_FORCED_1_ENABLE 0x0874 +#define EARLY_WAKEUP_APM_CTRL 0x0878 +#define EARLY_WAKEUP_CLUSTER0_CTRL 0x087c +#define EARLY_WAKEUP_DPU_CTRL 0x0880 +#define EARLY_WAKEUP_CSIS_CTRL 0x0884 +#define EARLY_WAKEUP_APM_DEST 0x0890 +#define EARLY_WAKEUP_CLUSTER0_DEST 0x0894 +#define EARLY_WAKEUP_DPU_DEST 0x0898 +#define EARLY_WAKEUP_CSIS_DEST 0x089c +#define EARLY_WAKEUP_SW_TRIG_APM 0x08c0 +#define EARLY_WAKEUP_SW_TRIG_APM_SET 0x08c4 +#define EARLY_WAKEUP_SW_TRIG_APM_CLEAR 0x08c8 +#define EARLY_WAKEUP_SW_TRIG_CLUSTER0 0x08d0 +#define EARLY_WAKEUP_SW_TRIG_CLUSTER0_SET 0x08d4 +#define EARLY_WAKEUP_SW_TRIG_CLUSTER0_CLEAR 0x08d8 +#define EARLY_WAKEUP_SW_TRIG_DPU 0x08e0 +#define EARLY_WAKEUP_SW_TRIG_DPU_SET 0x08e4 +#define EARLY_WAKEUP_SW_TRIG_DPU_CLEAR 0x08e8 +#define EARLY_WAKEUP_SW_TRIG_CSIS 0x08f0 +#define EARLY_WAKEUP_SW_TRIG_CSIS_SET 0x08f4 +#define EARLY_WAKEUP_SW_TRIG_CSIS_CLEAR 0x08f8 +#define CLK_CON_MUX_MUX_CLKCMU_BO_BUS 0x1000 +#define CLK_CON_MUX_MUX_CLKCMU_BUS0_BUS 0x1004 +#define CLK_CON_MUX_MUX_CLKCMU_BUS1_BUS 0x1008 +#define CLK_CON_MUX_MUX_CLKCMU_BUS2_BUS 0x100c +#define CLK_CON_MUX_MUX_CLKCMU_CIS_CLK0 0x1010 +#define CLK_CON_MUX_MUX_CLKCMU_CIS_CLK1 0x1014 +#define CLK_CON_MUX_MUX_CLKCMU_CIS_CLK2 0x1018 +#define CLK_CON_MUX_MUX_CLKCMU_CIS_CLK3 0x101c +#define CLK_CON_MUX_MUX_CLKCMU_CIS_CLK4 0x1020 +#define CLK_CON_MUX_MUX_CLKCMU_CIS_CLK5 0x1024 +#define CLK_CON_MUX_MUX_CLKCMU_CIS_CLK6 0x1028 +#define CLK_CON_MUX_MUX_CLKCMU_CIS_CLK7 0x102c +#define CLK_CON_MUX_MUX_CLKCMU_CMU_BOOST 0x1030 +#define CLK_CON_MUX_MUX_CLKCMU_CMU_BOOST_OPTION1 0x1034 +#define CLK_CON_MUX_MUX_CLKCMU_CORE_BUS 0x1038 +#define CLK_CON_MUX_MUX_CLKCMU_CPUCL0_DBG 0x103c +#define CLK_CON_MUX_MUX_CLKCMU_CPUCL0_SWITCH 0x1040 +#define CLK_CON_MUX_MUX_CLKCMU_CPUCL1_SWITCH 0x1044 +#define CLK_CON_MUX_MUX_CLKCMU_CPUCL2_SWITCH 0x1048 +#define CLK_CON_MUX_MUX_CLKCMU_CSIS_BUS 0x104c +#define CLK_CON_MUX_MUX_CLKCMU_DISP_BUS 0x1050 +#define CLK_CON_MUX_MUX_CLKCMU_DNS_BUS 0x1054 +#define CLK_CON_MUX_MUX_CLKCMU_DPU_BUS 0x1058 +#define CLK_CON_MUX_MUX_CLKCMU_EH_BUS 0x105c +#define CLK_CON_MUX_MUX_CLKCMU_G2D_G2D 0x1060 +#define CLK_CON_MUX_MUX_CLKCMU_G2D_MSCL 0x1064 +#define CLK_CON_MUX_MUX_CLKCMU_G3AA_G3AA 0x1068 +#define CLK_CON_MUX_MUX_CLKCMU_G3D_BUSD 0x106c +#define CLK_CON_MUX_MUX_CLKCMU_G3D_GLB 0x1070 +#define CLK_CON_MUX_MUX_CLKCMU_G3D_SWITCH 0x1074 +#define CLK_CON_MUX_MUX_CLKCMU_GDC_GDC0 0x1078 +#define CLK_CON_MUX_MUX_CLKCMU_GDC_GDC1 0x107c +#define CLK_CON_MUX_MUX_CLKCMU_GDC_SCSC 0x1080 +#define CLK_CON_MUX_MUX_CLKCMU_HPM 0x1084 +#define CLK_CON_MUX_MUX_CLKCMU_HSI0_BUS 0x1088 +#define CLK_CON_MUX_MUX_CLKCMU_HSI0_DPGTC 0x108c +#define CLK_CON_MUX_MUX_CLKCMU_HSI0_USB31DRD 0x1090 +#define CLK_CON_MUX_MUX_CLKCMU_HSI0_USBDPDBG 0x1094 +#define CLK_CON_MUX_MUX_CLKCMU_HSI1_BUS 0x1098 +#define CLK_CON_MUX_MUX_CLKCMU_HSI1_PCIE 0x109c +#define CLK_CON_MUX_MUX_CLKCMU_HSI2_BUS 0x10a0 +#define CLK_CON_MUX_MUX_CLKCMU_HSI2_MMC_CARD 0x10a4 +#define CLK_CON_MUX_MUX_CLKCMU_HSI2_PCIE 0x10a8 +#define CLK_CON_MUX_MUX_CLKCMU_HSI2_UFS_EMBD 0x10ac +#define CLK_CON_MUX_MUX_CLKCMU_IPP_BUS 0x10b0 +#define CLK_CON_MUX_MUX_CLKCMU_ITP_BUS 0x10b4 +#define CLK_CON_MUX_MUX_CLKCMU_MCSC_ITSC 0x10b8 +#define CLK_CON_MUX_MUX_CLKCMU_MCSC_MCSC 0x10bc +#define CLK_CON_MUX_MUX_CLKCMU_MFC_MFC 0x10c0 +#define CLK_CON_MUX_MUX_CLKCMU_MIF_BUSP 0x10c4 +#define CLK_CON_MUX_MUX_CLKCMU_MIF_SWITCH 0x10c8 +#define CLK_CON_MUX_MUX_CLKCMU_MISC_BUS 0x10cc +#define CLK_CON_MUX_MUX_CLKCMU_MISC_SSS 0x10d0 +#define CLK_CON_MUX_MUX_CLKCMU_PDP_BUS 0x10d4 +#define CLK_CON_MUX_MUX_CLKCMU_PDP_VRA 0x10d8 +#define CLK_CON_MUX_MUX_CLKCMU_PERIC0_BUS 0x10dc +#define CLK_CON_MUX_MUX_CLKCMU_PERIC0_IP 0x10e0 +#define CLK_CON_MUX_MUX_CLKCMU_PERIC1_BUS 0x10e4 +#define CLK_CON_MUX_MUX_CLKCMU_PERIC1_IP 0x10e8 +#define CLK_CON_MUX_MUX_CLKCMU_TNR_BUS 0x10ec +#define CLK_CON_MUX_MUX_CLKCMU_TOP_BOOST_OPTION1 0x10f0 +#define CLK_CON_MUX_MUX_CLKCMU_TOP_CMUREF 0x10f4 +#define CLK_CON_MUX_MUX_CLKCMU_TPU_BUS 0x10f8 +#define CLK_CON_MUX_MUX_CLKCMU_TPU_TPU 0x10fc +#define CLK_CON_MUX_MUX_CLKCMU_TPU_TPUCTL 0x1100 +#define CLK_CON_MUX_MUX_CLKCMU_TPU_UART 0x1104 +#define CLK_CON_MUX_MUX_CMU_CMUREF 0x1108 +#define CLK_CON_DIV_CLKCMU_BO_BUS 0x1800 +#define CLK_CON_DIV_CLKCMU_BUS0_BUS 0x1804 +#define CLK_CON_DIV_CLKCMU_BUS1_BUS 0x1808 +#define CLK_CON_DIV_CLKCMU_BUS2_BUS 0x180c +#define CLK_CON_DIV_CLKCMU_CIS_CLK0 0x1810 +#define CLK_CON_DIV_CLKCMU_CIS_CLK1 0x1814 +#define CLK_CON_DIV_CLKCMU_CIS_CLK2 0x1818 +#define CLK_CON_DIV_CLKCMU_CIS_CLK3 0x181c +#define CLK_CON_DIV_CLKCMU_CIS_CLK4 0x1820 +#define CLK_CON_DIV_CLKCMU_CIS_CLK5 0x1824 +#define CLK_CON_DIV_CLKCMU_CIS_CLK6 0x1828 +#define CLK_CON_DIV_CLKCMU_CIS_CLK7 0x182c +#define CLK_CON_DIV_CLKCMU_CORE_BUS 0x1830 +#define CLK_CON_DIV_CLKCMU_CPUCL0_DBG 0x1834 +#define CLK_CON_DIV_CLKCMU_CPUCL0_SWITCH 0x1838 +#define CLK_CON_DIV_CLKCMU_CPUCL1_SWITCH 0x183c +#define CLK_CON_DIV_CLKCMU_CPUCL2_SWITCH 0x1840 +#define CLK_CON_DIV_CLKCMU_CSIS_BUS 0x1844 +#define CLK_CON_DIV_CLKCMU_DISP_BUS 0x1848 +#define CLK_CON_DIV_CLKCMU_DNS_BUS 0x184c +#define CLK_CON_DIV_CLKCMU_DPU_BUS 0x1850 +#define CLK_CON_DIV_CLKCMU_EH_BUS 0x1854 +#define CLK_CON_DIV_CLKCMU_G2D_G2D 0x1858 +#define CLK_CON_DIV_CLKCMU_G2D_MSCL 0x185c +#define CLK_CON_DIV_CLKCMU_G3AA_G3AA 0x1860 +#define CLK_CON_DIV_CLKCMU_G3D_BUSD 0x1864 +#define CLK_CON_DIV_CLKCMU_G3D_GLB 0x1868 +#define CLK_CON_DIV_CLKCMU_G3D_SWITCH 0x186c +#define CLK_CON_DIV_CLKCMU_GDC_GDC0 0x1870 +#define CLK_CON_DIV_CLKCMU_GDC_GDC1 0x1874 +#define CLK_CON_DIV_CLKCMU_GDC_SCSC 0x1878 +#define CLK_CON_DIV_CLKCMU_HPM 0x187c +#define CLK_CON_DIV_CLKCMU_HSI0_BUS 0x1880 +#define CLK_CON_DIV_CLKCMU_HSI0_DPGTC 0x1884 +#define CLK_CON_DIV_CLKCMU_HSI0_USB31DRD 0x1888 +#define CLK_CON_DIV_CLKCMU_HSI0_USBDPDBG 0x188c +#define CLK_CON_DIV_CLKCMU_HSI1_BUS 0x1890 +#define CLK_CON_DIV_CLKCMU_HSI1_PCIE 0x1894 +#define CLK_CON_DIV_CLKCMU_HSI2_BUS 0x1898 +#define CLK_CON_DIV_CLKCMU_HSI2_MMC_CARD 0x189c +#define CLK_CON_DIV_CLKCMU_HSI2_PCIE 0x18a0 +#define CLK_CON_DIV_CLKCMU_HSI2_UFS_EMBD 0x18a4 +#define CLK_CON_DIV_CLKCMU_IPP_BUS 0x18a8 +#define CLK_CON_DIV_CLKCMU_ITP_BUS 0x18ac +#define CLK_CON_DIV_CLKCMU_MCSC_ITSC 0x18b0 +#define CLK_CON_DIV_CLKCMU_MCSC_MCSC 0x18b4 +#define CLK_CON_DIV_CLKCMU_MFC_MFC 0x18b8 +#define CLK_CON_DIV_CLKCMU_MIF_BUSP 0x18bc +#define CLK_CON_DIV_CLKCMU_MISC_BUS 0x18c0 +#define CLK_CON_DIV_CLKCMU_MISC_SSS 0x18c4 +#define CLK_CON_DIV_CLKCMU_OTP 0x18c8 +#define CLK_CON_DIV_CLKCMU_PDP_BUS 0x18cc +#define CLK_CON_DIV_CLKCMU_PDP_VRA 0x18d0 +#define CLK_CON_DIV_CLKCMU_PERIC0_BUS 0x18d4 +#define CLK_CON_DIV_CLKCMU_PERIC0_IP 0x18d8 +#define CLK_CON_DIV_CLKCMU_PERIC1_BUS 0x18dc +#define CLK_CON_DIV_CLKCMU_PERIC1_IP 0x18e0 +#define CLK_CON_DIV_CLKCMU_TNR_BUS 0x18e4 +#define CLK_CON_DIV_CLKCMU_TPU_BUS 0x18e8 +#define CLK_CON_DIV_CLKCMU_TPU_TPU 0x18ec +#define CLK_CON_DIV_CLKCMU_TPU_TPUCTL 0x18f0 +#define CLK_CON_DIV_CLKCMU_TPU_UART 0x18f4 +#define CLK_CON_DIV_DIV_CLKCMU_CMU_BOOST 0x18f8 +#define CLK_CON_DIV_DIV_CLK_CMU_CMUREF 0x18fc +#define CLK_CON_DIV_PLL_SHARED0_DIV2 0x1900 +#define CLK_CON_DIV_PLL_SHARED0_DIV3 0x1904 +#define CLK_CON_DIV_PLL_SHARED0_DIV4 0x1908 +#define CLK_CON_DIV_PLL_SHARED0_DIV5 0x190c +#define CLK_CON_DIV_PLL_SHARED1_DIV2 0x1910 +#define CLK_CON_DIV_PLL_SHARED1_DIV3 0x1914 +#define CLK_CON_DIV_PLL_SHARED1_DIV4 0x1918 +#define CLK_CON_DIV_PLL_SHARED2_DIV2 0x191c +#define CLK_CON_DIV_PLL_SHARED3_DIV2 0x1920 +#define CLK_CON_GAT_CLKCMU_BUS0_BOOST 0x2000 +#define CLK_CON_GAT_CLKCMU_BUS1_BOOST 0x2004 +#define CLK_CON_GAT_CLKCMU_BUS2_BOOST 0x2008 +#define CLK_CON_GAT_CLKCMU_CORE_BOOST 0x200c +#define CLK_CON_GAT_CLKCMU_CPUCL0_BOOST 0x2010 +#define CLK_CON_GAT_CLKCMU_CPUCL1_BOOST 0x2014 +#define CLK_CON_GAT_CLKCMU_CPUCL2_BOOST 0x2018 +#define CLK_CON_GAT_CLKCMU_MIF_BOOST 0x201c +#define CLK_CON_GAT_CLKCMU_MIF_SWITCH 0x2020 +#define CLK_CON_GAT_GATE_CLKCMU_BO_BUS 0x2024 +#define CLK_CON_GAT_GATE_CLKCMU_BUS0_BUS 0x2028 +#define CLK_CON_GAT_GATE_CLKCMU_BUS1_BUS 0x202c +#define CLK_CON_GAT_GATE_CLKCMU_BUS2_BUS 0x2030 +#define CLK_CON_GAT_GATE_CLKCMU_CIS_CLK0 0x2034 +#define CLK_CON_GAT_GATE_CLKCMU_CIS_CLK1 0x2038 +#define CLK_CON_GAT_GATE_CLKCMU_CIS_CLK2 0x203c +#define CLK_CON_GAT_GATE_CLKCMU_CIS_CLK3 0x2040 +#define CLK_CON_GAT_GATE_CLKCMU_CIS_CLK4 0x2044 +#define CLK_CON_GAT_GATE_CLKCMU_CIS_CLK5 0x2048 +#define CLK_CON_GAT_GATE_CLKCMU_CIS_CLK6 0x204c +#define CLK_CON_GAT_GATE_CLKCMU_CIS_CLK7 0x2050 +#define CLK_CON_GAT_GATE_CLKCMU_CMU_BOOST 0x2054 +#define CLK_CON_GAT_GATE_CLKCMU_CORE_BUS 0x2058 +#define CLK_CON_GAT_GATE_CLKCMU_CPUCL0_DBG_BUS 0x205c +#define CLK_CON_GAT_GATE_CLKCMU_CPUCL0_SWITCH 0x2060 +#define CLK_CON_GAT_GATE_CLKCMU_CPUCL1_SWITCH 0x2064 +#define CLK_CON_GAT_GATE_CLKCMU_CPUCL2_SWITCH 0x2068 +#define CLK_CON_GAT_GATE_CLKCMU_CSIS_BUS 0x206c +#define CLK_CON_GAT_GATE_CLKCMU_DISP_BUS 0x2070 +#define CLK_CON_GAT_GATE_CLKCMU_DNS_BUS 0x2074 +#define CLK_CON_GAT_GATE_CLKCMU_DPU_BUS 0x2078 +#define CLK_CON_GAT_GATE_CLKCMU_EH_BUS 0x207c +#define CLK_CON_GAT_GATE_CLKCMU_G2D_G2D 0x2080 +#define CLK_CON_GAT_GATE_CLKCMU_G2D_MSCL 0x2084 +#define CLK_CON_GAT_GATE_CLKCMU_G3AA_G3AA 0x2088 +#define CLK_CON_GAT_GATE_CLKCMU_G3D_BUSD 0x208c +#define CLK_CON_GAT_GATE_CLKCMU_G3D_GLB 0x2090 +#define CLK_CON_GAT_GATE_CLKCMU_G3D_SWITCH 0x2094 +#define CLK_CON_GAT_GATE_CLKCMU_GDC_GDC0 0x2098 +#define CLK_CON_GAT_GATE_CLKCMU_GDC_GDC1 0x209c +#define CLK_CON_GAT_GATE_CLKCMU_GDC_SCSC 0x20a0 +#define CLK_CON_GAT_GATE_CLKCMU_HPM 0x20a4 +#define CLK_CON_GAT_GATE_CLKCMU_HSI0_BUS 0x20a8 +#define CLK_CON_GAT_GATE_CLKCMU_HSI0_DPGTC 0x20ac +#define CLK_CON_GAT_GATE_CLKCMU_HSI0_USB31DRD 0x20b0 +#define CLK_CON_GAT_GATE_CLKCMU_HSI0_USBDPDBG 0x20b4 +#define CLK_CON_GAT_GATE_CLKCMU_HSI1_BUS 0x20b8 +#define CLK_CON_GAT_GATE_CLKCMU_HSI1_PCIE 0x20bc +#define CLK_CON_GAT_GATE_CLKCMU_HSI2_BUS 0x20c0 +#define CLK_CON_GAT_GATE_CLKCMU_HSI2_MMCCARD 0x20c4 +#define CLK_CON_GAT_GATE_CLKCMU_HSI2_PCIE 0x20c8 +#define CLK_CON_GAT_GATE_CLKCMU_HSI2_UFS_EMBD 0x20cc +#define CLK_CON_GAT_GATE_CLKCMU_IPP_BUS 0x20d0 +#define CLK_CON_GAT_GATE_CLKCMU_ITP_BUS 0x20d4 +#define CLK_CON_GAT_GATE_CLKCMU_MCSC_ITSC 0x20d8 +#define CLK_CON_GAT_GATE_CLKCMU_MCSC_MCSC 0x20dc +#define CLK_CON_GAT_GATE_CLKCMU_MFC_MFC 0x20e0 +#define CLK_CON_GAT_GATE_CLKCMU_MIF_BUSP 0x20e4 +#define CLK_CON_GAT_GATE_CLKCMU_MISC_BUS 0x20e8 +#define CLK_CON_GAT_GATE_CLKCMU_MISC_SSS 0x20ec +#define CLK_CON_GAT_GATE_CLKCMU_PDP_BUS 0x20f0 +#define CLK_CON_GAT_GATE_CLKCMU_PDP_VRA 0x20f4 +#define CLK_CON_GAT_GATE_CLKCMU_PERIC0_BUS 0x20f8 +#define CLK_CON_GAT_GATE_CLKCMU_PERIC0_IP 0x20fc +#define CLK_CON_GAT_GATE_CLKCMU_PERIC1_BUS 0x2100 +#define CLK_CON_GAT_GATE_CLKCMU_PERIC1_IP 0x2104 +#define CLK_CON_GAT_GATE_CLKCMU_TNR_BUS 0x2108 +#define CLK_CON_GAT_GATE_CLKCMU_TOP_CMUREF 0x210c +#define CLK_CON_GAT_GATE_CLKCMU_TPU_BUS 0x2110 +#define CLK_CON_GAT_GATE_CLKCMU_TPU_TPU 0x2114 +#define CLK_CON_GAT_GATE_CLKCMU_TPU_TPUCTL 0x2118 +#define CLK_CON_GAT_GATE_CLKCMU_TPU_UART 0x211c +#define DMYQCH_CON_CMU_TOP_CMUREF_QCH 0x3000 +#define DMYQCH_CON_DFTMUX_CMU_QCH_CIS_CLK0 0x3004 +#define DMYQCH_CON_DFTMUX_CMU_QCH_CIS_CLK1 0x3008 +#define DMYQCH_CON_DFTMUX_CMU_QCH_CIS_CLK2 0x300c +#define DMYQCH_CON_DFTMUX_CMU_QCH_CIS_CLK3 0x3010 +#define DMYQCH_CON_DFTMUX_CMU_QCH_CIS_CLK4 0x3014 +#define DMYQCH_CON_DFTMUX_CMU_QCH_CIS_CLK5 0x3018 +#define DMYQCH_CON_DFTMUX_CMU_QCH_CIS_CLK6 0x301c +#define DMYQCH_CON_DFTMUX_CMU_QCH_CIS_CLK7 0x3020 +#define DMYQCH_CON_OTP_QCH 0x3024 +#define QUEUE_CTRL_REG_BLK_CMU_CMU_TOP 0x3c00 +#define QUEUE_ENTRY0_BLK_CMU_CMU_TOP 0x3c10 +#define QUEUE_ENTRY1_BLK_CMU_CMU_TOP 0x3c14 +#define QUEUE_ENTRY2_BLK_CMU_CMU_TOP 0x3c18 +#define QUEUE_ENTRY3_BLK_CMU_CMU_TOP 0x3c1c +#define QUEUE_ENTRY4_BLK_CMU_CMU_TOP 0x3c20 +#define QUEUE_ENTRY5_BLK_CMU_CMU_TOP 0x3c24 +#define QUEUE_ENTRY6_BLK_CMU_CMU_TOP 0x3c28 +#define QUEUE_ENTRY7_BLK_CMU_CMU_TOP 0x3c2c +#define MIFMIRROR_QUEUE_CTRL_REG 0x3e00 +#define MIFMIRROR_QUEUE_ENTRY0 0x3e10 +#define MIFMIRROR_QUEUE_ENTRY1 0x3e14 +#define MIFMIRROR_QUEUE_ENTRY2 0x3e18 +#define MIFMIRROR_QUEUE_ENTRY3 0x3e1c +#define MIFMIRROR_QUEUE_ENTRY4 0x3e20 +#define MIFMIRROR_QUEUE_ENTRY5 0x3e24 +#define MIFMIRROR_QUEUE_ENTRY6 0x3e28 +#define MIFMIRROR_QUEUE_ENTRY7 0x3e2c +#define MIFMIRROR_QUEUE_BUSY 0x3e30 +#define GENERALIO_ACD_CHANNEL_0 0x3f00 +#define GENERALIO_ACD_CHANNEL_1 0x3f04 +#define GENERALIO_ACD_CHANNEL_2 0x3f08 +#define GENERALIO_ACD_CHANNEL_3 0x3f0c +#define GENERALIO_ACD_MASK 0x3f14 + +static const unsigned long cmu_top_clk_regs[] __initconst = { + PLL_LOCKTIME_PLL_SHARED0, + PLL_LOCKTIME_PLL_SHARED1, + PLL_LOCKTIME_PLL_SHARED2, + PLL_LOCKTIME_PLL_SHARED3, + PLL_LOCKTIME_PLL_SPARE, + PLL_CON0_PLL_SHARED0, + PLL_CON1_PLL_SHARED0, + PLL_CON2_PLL_SHARED0, + PLL_CON3_PLL_SHARED0, + PLL_CON4_PLL_SHARED0, + PLL_CON0_PLL_SHARED1, + PLL_CON1_PLL_SHARED1, + PLL_CON2_PLL_SHARED1, + PLL_CON3_PLL_SHARED1, + PLL_CON4_PLL_SHARED1, + PLL_CON0_PLL_SHARED2, + PLL_CON1_PLL_SHARED2, + PLL_CON2_PLL_SHARED2, + PLL_CON3_PLL_SHARED2, + PLL_CON4_PLL_SHARED2, + PLL_CON0_PLL_SHARED3, + PLL_CON1_PLL_SHARED3, + PLL_CON2_PLL_SHARED3, + PLL_CON3_PLL_SHARED3, + PLL_CON4_PLL_SHARED3, + PLL_CON0_PLL_SPARE, + PLL_CON1_PLL_SPARE, + PLL_CON2_PLL_SPARE, + PLL_CON3_PLL_SPARE, + PLL_CON4_PLL_SPARE, + CMU_CMU_TOP_CONTROLLER_OPTION, + CLKOUT_CON_BLK_CMU_CMU_TOP_CLKOUT0, + CMU_HCHGEN_CLKMUX_CMU_BOOST, + CMU_HCHGEN_CLKMUX_TOP_BOOST, + CMU_HCHGEN_CLKMUX, + POWER_FAIL_DETECT_PLL, + EARLY_WAKEUP_FORCED_0_ENABLE, + EARLY_WAKEUP_FORCED_1_ENABLE, + EARLY_WAKEUP_APM_CTRL, + EARLY_WAKEUP_CLUSTER0_CTRL, + EARLY_WAKEUP_DPU_CTRL, + EARLY_WAKEUP_CSIS_CTRL, + EARLY_WAKEUP_APM_DEST, + EARLY_WAKEUP_CLUSTER0_DEST, + EARLY_WAKEUP_DPU_DEST, + EARLY_WAKEUP_CSIS_DEST, + EARLY_WAKEUP_SW_TRIG_APM, + EARLY_WAKEUP_SW_TRIG_APM_SET, + EARLY_WAKEUP_SW_TRIG_APM_CLEAR, + EARLY_WAKEUP_SW_TRIG_CLUSTER0, + EARLY_WAKEUP_SW_TRIG_CLUSTER0_SET, + EARLY_WAKEUP_SW_TRIG_CLUSTER0_CLEAR, + EARLY_WAKEUP_SW_TRIG_DPU, + EARLY_WAKEUP_SW_TRIG_DPU_SET, + EARLY_WAKEUP_SW_TRIG_DPU_CLEAR, + EARLY_WAKEUP_SW_TRIG_CSIS, + EARLY_WAKEUP_SW_TRIG_CSIS_SET, + EARLY_WAKEUP_SW_TRIG_CSIS_CLEAR, + CLK_CON_MUX_MUX_CLKCMU_BO_BUS, + CLK_CON_MUX_MUX_CLKCMU_BUS0_BUS, + CLK_CON_MUX_MUX_CLKCMU_BUS1_BUS, + CLK_CON_MUX_MUX_CLKCMU_BUS2_BUS, + CLK_CON_MUX_MUX_CLKCMU_CIS_CLK0, + CLK_CON_MUX_MUX_CLKCMU_CIS_CLK1, + CLK_CON_MUX_MUX_CLKCMU_CIS_CLK2, + CLK_CON_MUX_MUX_CLKCMU_CIS_CLK3, + CLK_CON_MUX_MUX_CLKCMU_CIS_CLK4, + CLK_CON_MUX_MUX_CLKCMU_CIS_CLK5, + CLK_CON_MUX_MUX_CLKCMU_CIS_CLK6, + CLK_CON_MUX_MUX_CLKCMU_CIS_CLK7, + CLK_CON_MUX_MUX_CLKCMU_CMU_BOOST, + CLK_CON_MUX_MUX_CLKCMU_CMU_BOOST_OPTION1, + CLK_CON_MUX_MUX_CLKCMU_CORE_BUS, + CLK_CON_MUX_MUX_CLKCMU_CPUCL0_DBG, + CLK_CON_MUX_MUX_CLKCMU_CPUCL0_SWITCH, + CLK_CON_MUX_MUX_CLKCMU_CPUCL1_SWITCH, + CLK_CON_MUX_MUX_CLKCMU_CPUCL2_SWITCH, + CLK_CON_MUX_MUX_CLKCMU_CSIS_BUS, + CLK_CON_MUX_MUX_CLKCMU_DISP_BUS, + CLK_CON_MUX_MUX_CLKCMU_DNS_BUS, + CLK_CON_MUX_MUX_CLKCMU_DPU_BUS, + CLK_CON_MUX_MUX_CLKCMU_EH_BUS, + CLK_CON_MUX_MUX_CLKCMU_G2D_G2D, + CLK_CON_MUX_MUX_CLKCMU_G2D_MSCL, + CLK_CON_MUX_MUX_CLKCMU_G3AA_G3AA, + CLK_CON_MUX_MUX_CLKCMU_G3D_BUSD, + CLK_CON_MUX_MUX_CLKCMU_G3D_GLB, + CLK_CON_MUX_MUX_CLKCMU_G3D_SWITCH, + CLK_CON_MUX_MUX_CLKCMU_GDC_GDC0, + CLK_CON_MUX_MUX_CLKCMU_GDC_GDC1, + CLK_CON_MUX_MUX_CLKCMU_GDC_SCSC, + CLK_CON_MUX_MUX_CLKCMU_HPM, + CLK_CON_MUX_MUX_CLKCMU_HSI0_BUS, + CLK_CON_MUX_MUX_CLKCMU_HSI0_DPGTC, + CLK_CON_MUX_MUX_CLKCMU_HSI0_USB31DRD, + CLK_CON_MUX_MUX_CLKCMU_HSI0_USBDPDBG, + CLK_CON_MUX_MUX_CLKCMU_HSI1_BUS, + CLK_CON_MUX_MUX_CLKCMU_HSI1_PCIE, + CLK_CON_MUX_MUX_CLKCMU_HSI2_BUS, + CLK_CON_MUX_MUX_CLKCMU_HSI2_MMC_CARD, + CLK_CON_MUX_MUX_CLKCMU_HSI2_PCIE, + CLK_CON_MUX_MUX_CLKCMU_HSI2_UFS_EMBD, + CLK_CON_MUX_MUX_CLKCMU_IPP_BUS, + CLK_CON_MUX_MUX_CLKCMU_ITP_BUS, + CLK_CON_MUX_MUX_CLKCMU_MCSC_ITSC, + CLK_CON_MUX_MUX_CLKCMU_MCSC_MCSC, + CLK_CON_MUX_MUX_CLKCMU_MFC_MFC, + CLK_CON_MUX_MUX_CLKCMU_MIF_BUSP, + CLK_CON_MUX_MUX_CLKCMU_MIF_SWITCH, + CLK_CON_MUX_MUX_CLKCMU_MISC_BUS, + CLK_CON_MUX_MUX_CLKCMU_MISC_SSS, + CLK_CON_MUX_MUX_CLKCMU_PDP_BUS, + CLK_CON_MUX_MUX_CLKCMU_PDP_VRA, + CLK_CON_MUX_MUX_CLKCMU_PERIC0_BUS, + CLK_CON_MUX_MUX_CLKCMU_PERIC0_IP, + CLK_CON_MUX_MUX_CLKCMU_PERIC1_BUS, + CLK_CON_MUX_MUX_CLKCMU_PERIC1_IP, + CLK_CON_MUX_MUX_CLKCMU_TNR_BUS, + CLK_CON_MUX_MUX_CLKCMU_TOP_BOOST_OPTION1, + CLK_CON_MUX_MUX_CLKCMU_TOP_CMUREF, + CLK_CON_MUX_MUX_CLKCMU_TPU_BUS, + CLK_CON_MUX_MUX_CLKCMU_TPU_TPU, + CLK_CON_MUX_MUX_CLKCMU_TPU_TPUCTL, + CLK_CON_MUX_MUX_CLKCMU_TPU_UART, + CLK_CON_MUX_MUX_CMU_CMUREF, + CLK_CON_DIV_CLKCMU_BO_BUS, + CLK_CON_DIV_CLKCMU_BUS0_BUS, + CLK_CON_DIV_CLKCMU_BUS1_BUS, + CLK_CON_DIV_CLKCMU_BUS2_BUS, + CLK_CON_DIV_CLKCMU_CIS_CLK0, + CLK_CON_DIV_CLKCMU_CIS_CLK1, + CLK_CON_DIV_CLKCMU_CIS_CLK2, + CLK_CON_DIV_CLKCMU_CIS_CLK3, + CLK_CON_DIV_CLKCMU_CIS_CLK4, + CLK_CON_DIV_CLKCMU_CIS_CLK5, + CLK_CON_DIV_CLKCMU_CIS_CLK6, + CLK_CON_DIV_CLKCMU_CIS_CLK7, + CLK_CON_DIV_CLKCMU_CORE_BUS, + CLK_CON_DIV_CLKCMU_CPUCL0_DBG, + CLK_CON_DIV_CLKCMU_CPUCL0_SWITCH, + CLK_CON_DIV_CLKCMU_CPUCL1_SWITCH, + CLK_CON_DIV_CLKCMU_CPUCL2_SWITCH, + CLK_CON_DIV_CLKCMU_CSIS_BUS, + CLK_CON_DIV_CLKCMU_DISP_BUS, + CLK_CON_DIV_CLKCMU_DNS_BUS, + CLK_CON_DIV_CLKCMU_DPU_BUS, + CLK_CON_DIV_CLKCMU_EH_BUS, + CLK_CON_DIV_CLKCMU_G2D_G2D, + CLK_CON_DIV_CLKCMU_G2D_MSCL, + CLK_CON_DIV_CLKCMU_G3AA_G3AA, + CLK_CON_DIV_CLKCMU_G3D_BUSD, + CLK_CON_DIV_CLKCMU_G3D_GLB, + CLK_CON_DIV_CLKCMU_G3D_SWITCH, + CLK_CON_DIV_CLKCMU_GDC_GDC0, + CLK_CON_DIV_CLKCMU_GDC_GDC1, + CLK_CON_DIV_CLKCMU_GDC_SCSC, + CLK_CON_DIV_CLKCMU_HPM, + CLK_CON_DIV_CLKCMU_HSI0_BUS, + CLK_CON_DIV_CLKCMU_HSI0_DPGTC, + CLK_CON_DIV_CLKCMU_HSI0_USB31DRD, + CLK_CON_DIV_CLKCMU_HSI0_USBDPDBG, + CLK_CON_DIV_CLKCMU_HSI1_BUS, + CLK_CON_DIV_CLKCMU_HSI1_PCIE, + CLK_CON_DIV_CLKCMU_HSI2_BUS, + CLK_CON_DIV_CLKCMU_HSI2_MMC_CARD, + CLK_CON_DIV_CLKCMU_HSI2_PCIE, + CLK_CON_DIV_CLKCMU_HSI2_UFS_EMBD, + CLK_CON_DIV_CLKCMU_IPP_BUS, + CLK_CON_DIV_CLKCMU_ITP_BUS, + CLK_CON_DIV_CLKCMU_MCSC_ITSC, + CLK_CON_DIV_CLKCMU_MCSC_MCSC, + CLK_CON_DIV_CLKCMU_MFC_MFC, + CLK_CON_DIV_CLKCMU_MIF_BUSP, + CLK_CON_DIV_CLKCMU_MISC_BUS, + CLK_CON_DIV_CLKCMU_MISC_SSS, + CLK_CON_DIV_CLKCMU_OTP, + CLK_CON_DIV_CLKCMU_PDP_BUS, + CLK_CON_DIV_CLKCMU_PDP_VRA, + CLK_CON_DIV_CLKCMU_PERIC0_BUS, + CLK_CON_DIV_CLKCMU_PERIC0_IP, + CLK_CON_DIV_CLKCMU_PERIC1_BUS, + CLK_CON_DIV_CLKCMU_PERIC1_IP, + CLK_CON_DIV_CLKCMU_TNR_BUS, + CLK_CON_DIV_CLKCMU_TPU_BUS, + CLK_CON_DIV_CLKCMU_TPU_TPU, + CLK_CON_DIV_CLKCMU_TPU_TPUCTL, + CLK_CON_DIV_CLKCMU_TPU_UART, + CLK_CON_DIV_DIV_CLKCMU_CMU_BOOST, + CLK_CON_DIV_DIV_CLK_CMU_CMUREF, + CLK_CON_DIV_PLL_SHARED0_DIV2, + CLK_CON_DIV_PLL_SHARED0_DIV3, + CLK_CON_DIV_PLL_SHARED0_DIV4, + CLK_CON_DIV_PLL_SHARED0_DIV5, + CLK_CON_DIV_PLL_SHARED1_DIV2, + CLK_CON_DIV_PLL_SHARED1_DIV3, + CLK_CON_DIV_PLL_SHARED1_DIV4, + CLK_CON_DIV_PLL_SHARED2_DIV2, + CLK_CON_DIV_PLL_SHARED3_DIV2, + CLK_CON_GAT_CLKCMU_BUS0_BOOST, + CLK_CON_GAT_CLKCMU_BUS1_BOOST, + CLK_CON_GAT_CLKCMU_BUS2_BOOST, + CLK_CON_GAT_CLKCMU_CORE_BOOST, + CLK_CON_GAT_CLKCMU_CPUCL0_BOOST, + CLK_CON_GAT_CLKCMU_CPUCL1_BOOST, + CLK_CON_GAT_CLKCMU_CPUCL2_BOOST, + CLK_CON_GAT_CLKCMU_MIF_BOOST, + CLK_CON_GAT_CLKCMU_MIF_SWITCH, + CLK_CON_GAT_GATE_CLKCMU_BO_BUS, + CLK_CON_GAT_GATE_CLKCMU_BUS0_BUS, + CLK_CON_GAT_GATE_CLKCMU_BUS1_BUS, + CLK_CON_GAT_GATE_CLKCMU_BUS2_BUS, + CLK_CON_GAT_GATE_CLKCMU_CIS_CLK0, + CLK_CON_GAT_GATE_CLKCMU_CIS_CLK1, + CLK_CON_GAT_GATE_CLKCMU_CIS_CLK2, + CLK_CON_GAT_GATE_CLKCMU_CIS_CLK3, + CLK_CON_GAT_GATE_CLKCMU_CIS_CLK4, + CLK_CON_GAT_GATE_CLKCMU_CIS_CLK5, + CLK_CON_GAT_GATE_CLKCMU_CIS_CLK6, + CLK_CON_GAT_GATE_CLKCMU_CIS_CLK7, + CLK_CON_GAT_GATE_CLKCMU_CMU_BOOST, + CLK_CON_GAT_GATE_CLKCMU_CORE_BUS, + CLK_CON_GAT_GATE_CLKCMU_CPUCL0_DBG_BUS, + CLK_CON_GAT_GATE_CLKCMU_CPUCL0_SWITCH, + CLK_CON_GAT_GATE_CLKCMU_CPUCL1_SWITCH, + CLK_CON_GAT_GATE_CLKCMU_CPUCL2_SWITCH, + CLK_CON_GAT_GATE_CLKCMU_CSIS_BUS, + CLK_CON_GAT_GATE_CLKCMU_DISP_BUS, + CLK_CON_GAT_GATE_CLKCMU_DNS_BUS, + CLK_CON_GAT_GATE_CLKCMU_DPU_BUS, + CLK_CON_GAT_GATE_CLKCMU_EH_BUS, + CLK_CON_GAT_GATE_CLKCMU_G2D_G2D, + CLK_CON_GAT_GATE_CLKCMU_G2D_MSCL, + CLK_CON_GAT_GATE_CLKCMU_G3AA_G3AA, + CLK_CON_GAT_GATE_CLKCMU_G3D_BUSD, + CLK_CON_GAT_GATE_CLKCMU_G3D_GLB, + CLK_CON_GAT_GATE_CLKCMU_G3D_SWITCH, + CLK_CON_GAT_GATE_CLKCMU_GDC_GDC0, + CLK_CON_GAT_GATE_CLKCMU_GDC_GDC1, + CLK_CON_GAT_GATE_CLKCMU_GDC_SCSC, + CLK_CON_GAT_GATE_CLKCMU_HPM, + CLK_CON_GAT_GATE_CLKCMU_HSI0_BUS, + CLK_CON_GAT_GATE_CLKCMU_HSI0_DPGTC, + CLK_CON_GAT_GATE_CLKCMU_HSI0_USB31DRD, + CLK_CON_GAT_GATE_CLKCMU_HSI0_USBDPDBG, + CLK_CON_GAT_GATE_CLKCMU_HSI1_BUS, + CLK_CON_GAT_GATE_CLKCMU_HSI1_PCIE, + CLK_CON_GAT_GATE_CLKCMU_HSI2_BUS, + CLK_CON_GAT_GATE_CLKCMU_HSI2_MMCCARD, + CLK_CON_GAT_GATE_CLKCMU_HSI2_PCIE, + CLK_CON_GAT_GATE_CLKCMU_HSI2_UFS_EMBD, + CLK_CON_GAT_GATE_CLKCMU_IPP_BUS, + CLK_CON_GAT_GATE_CLKCMU_ITP_BUS, + CLK_CON_GAT_GATE_CLKCMU_MCSC_ITSC, + CLK_CON_GAT_GATE_CLKCMU_MCSC_MCSC, + CLK_CON_GAT_GATE_CLKCMU_MFC_MFC, + CLK_CON_GAT_GATE_CLKCMU_MIF_BUSP, + CLK_CON_GAT_GATE_CLKCMU_MISC_BUS, + CLK_CON_GAT_GATE_CLKCMU_MISC_SSS, + CLK_CON_GAT_GATE_CLKCMU_PDP_BUS, + CLK_CON_GAT_GATE_CLKCMU_PDP_VRA, + CLK_CON_GAT_GATE_CLKCMU_PERIC0_BUS, + CLK_CON_GAT_GATE_CLKCMU_PERIC0_IP, + CLK_CON_GAT_GATE_CLKCMU_PERIC1_BUS, + CLK_CON_GAT_GATE_CLKCMU_PERIC1_IP, + CLK_CON_GAT_GATE_CLKCMU_TNR_BUS, + CLK_CON_GAT_GATE_CLKCMU_TOP_CMUREF, + CLK_CON_GAT_GATE_CLKCMU_TPU_BUS, + CLK_CON_GAT_GATE_CLKCMU_TPU_TPU, + CLK_CON_GAT_GATE_CLKCMU_TPU_TPUCTL, + CLK_CON_GAT_GATE_CLKCMU_TPU_UART, + DMYQCH_CON_CMU_TOP_CMUREF_QCH, + DMYQCH_CON_DFTMUX_CMU_QCH_CIS_CLK0, + DMYQCH_CON_DFTMUX_CMU_QCH_CIS_CLK1, + DMYQCH_CON_DFTMUX_CMU_QCH_CIS_CLK2, + DMYQCH_CON_DFTMUX_CMU_QCH_CIS_CLK3, + DMYQCH_CON_DFTMUX_CMU_QCH_CIS_CLK4, + DMYQCH_CON_DFTMUX_CMU_QCH_CIS_CLK5, + DMYQCH_CON_DFTMUX_CMU_QCH_CIS_CLK6, + DMYQCH_CON_DFTMUX_CMU_QCH_CIS_CLK7, + DMYQCH_CON_OTP_QCH, + QUEUE_CTRL_REG_BLK_CMU_CMU_TOP, + QUEUE_ENTRY0_BLK_CMU_CMU_TOP, + QUEUE_ENTRY1_BLK_CMU_CMU_TOP, + QUEUE_ENTRY2_BLK_CMU_CMU_TOP, + QUEUE_ENTRY3_BLK_CMU_CMU_TOP, + QUEUE_ENTRY4_BLK_CMU_CMU_TOP, + QUEUE_ENTRY5_BLK_CMU_CMU_TOP, + QUEUE_ENTRY6_BLK_CMU_CMU_TOP, + QUEUE_ENTRY7_BLK_CMU_CMU_TOP, + MIFMIRROR_QUEUE_CTRL_REG, + MIFMIRROR_QUEUE_ENTRY0, + MIFMIRROR_QUEUE_ENTRY1, + MIFMIRROR_QUEUE_ENTRY2, + MIFMIRROR_QUEUE_ENTRY3, + MIFMIRROR_QUEUE_ENTRY4, + MIFMIRROR_QUEUE_ENTRY5, + MIFMIRROR_QUEUE_ENTRY6, + MIFMIRROR_QUEUE_ENTRY7, + MIFMIRROR_QUEUE_BUSY, + GENERALIO_ACD_CHANNEL_0, + GENERALIO_ACD_CHANNEL_1, + GENERALIO_ACD_CHANNEL_2, + GENERALIO_ACD_CHANNEL_3, + GENERALIO_ACD_MASK, +}; + +static const struct samsung_pll_clock cmu_top_pll_clks[] __initconst = { + /* CMU_TOP_PURECLKCOMP */ + PLL(pll_0517x, CLK_FOUT_SHARED0_PLL, "fout_shared0_pll", "oscclk", + PLL_LOCKTIME_PLL_SHARED0, PLL_CON3_PLL_SHARED0, + NULL), + PLL(pll_0517x, CLK_FOUT_SHARED1_PLL, "fout_shared1_pll", "oscclk", + PLL_LOCKTIME_PLL_SHARED1, PLL_CON3_PLL_SHARED1, + NULL), + PLL(pll_0518x, CLK_FOUT_SHARED2_PLL, "fout_shared2_pll", "oscclk", + PLL_LOCKTIME_PLL_SHARED2, PLL_CON3_PLL_SHARED2, + NULL), + PLL(pll_0518x, CLK_FOUT_SHARED3_PLL, "fout_shared3_pll", "oscclk", + PLL_LOCKTIME_PLL_SHARED3, PLL_CON3_PLL_SHARED3, + NULL), + PLL(pll_0518x, CLK_FOUT_SPARE_PLL, "fout_spare_pll", "oscclk", + PLL_LOCKTIME_PLL_SPARE, PLL_CON3_PLL_SPARE, + NULL), +}; + +/* List of parent clocks for Muxes in CMU_TOP */ +PNAME(mout_pll_shared0_p) = { "oscclk", "fout_shared0_pll" }; +PNAME(mout_pll_shared1_p) = { "oscclk", "fout_shared1_pll" }; +PNAME(mout_pll_shared2_p) = { "oscclk", "fout_shared2_pll" }; +PNAME(mout_pll_shared3_p) = { "oscclk", "fout_shared3_pll" }; +PNAME(mout_pll_spare_p) = { "oscclk", "fout_spare_pll" }; +PNAME(mout_cmu_bo_bus_p) = { "fout_shared2_pll", "dout_cmu_shared0_div3", + "fout_shared3_pll", "dout_cmu_shared1_div3", + "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "fout_spare_pll", "oscclk" }; +PNAME(mout_cmu_bus0_bus_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared3_div2", + "fout_spare_pll", "oscclk", + "oscclk", "oscclk" }; +PNAME(mout_cmu_bus1_bus_p) = { "dout_cmu_shared0_div3", "fout_shared3_pll", + "dout_cmu_shared1_div3", + "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "fout_spare_pll", "oscclk" }; +PNAME(mout_cmu_bus2_bus_p) = { "dout_cmu_shared0_div2", + "dout_cmu_shared1_div2", + "fout_shared2_pll", "fout_shared3_pll", + "dout_cmu_shared0_div3", + "dout_cmu_shared1_div3", + "dout_cmu_shared0_div5", "fout_spare_pll" }; +PNAME(mout_cmu_cis_clk0_7_p) = { "oscclk", "dout_cmu_shared0_div3", + "dout_cmu_shared1_div3", + "dout_cmu_shared2_div2", + "dout_cmu_shared3_div2", "fout_spare_pll", + "oscclk", "oscclk" }; +PNAME(mout_cmu_cmu_boost_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared3_div2" }; +PNAME(mout_cmu_cmu_boost_option1_p) = { "dout_cmu_cmu_boost", + "gout_cmu_boost_option1" }; +PNAME(mout_cmu_core_bus_p) = { "dout_cmu_shared0_div2", + "dout_cmu_shared1_div2", + "fout_shared2_pll", "fout_shared3_pll", + "dout_cmu_shared0_div3", + "dout_cmu_shared1_div3", + "dout_cmu_shared0_div5", "fout_spare_pll" }; +PNAME(mout_cmu_cpucl0_dbg_p) = { "fout_shared2_pll", "fout_shared3_pll", + "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", "fout_spare_pll", + "oscclk", "oscclk" }; +PNAME(mout_cmu_cpucl0_switch_p) = { "fout_shared1_pll", "dout_cmu_shared0_div2", + "dout_cmu_shared1_div2", "fout_shared2_pll", + "fout_shared3_pll", "dout_cmu_shared0_div3", + "dout_cmu_shared1_div3", "fout_spare_pll" }; +PNAME(mout_cmu_cpucl1_switch_p) = { "fout_shared1_pll", "dout_cmu_shared0_div2", + "dout_cmu_shared1_div2", "fout_shared2_pll", + "fout_shared3_pll", "dout_cmu_shared0_div3", + "dout_cmu_shared1_div3", "fout_spare_pll" }; +PNAME(mout_cmu_cpucl2_switch_p) = { "fout_shared1_pll", "dout_cmu_shared0_div2", + "dout_cmu_shared1_div2", "fout_shared2_pll", + "fout_shared3_pll", "dout_cmu_shared0_div3", + "dout_cmu_shared1_div3", "fout_spare_pll" }; +PNAME(mout_cmu_csis_bus_p) = { "dout_cmu_shared0_div3", "fout_shared3_pll", + "dout_cmu_shared1_div3", + "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "fout_spare_pll", "oscclk" }; +PNAME(mout_cmu_disp_bus_p) = { "dout_cmu_shared0_div3", "fout_shared3_pll", + "dout_cmu_shared1_div3", + "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "fout_spare_pll", "oscclk" }; +PNAME(mout_cmu_dns_bus_p) = { "dout_cmu_shared0_div3", "fout_shared3_pll", + "dout_cmu_shared1_div3", + "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "fout_spare_pll", "oscclk" }; +PNAME(mout_cmu_dpu_p) = { "dout_cmu_shared0_div3", + "fout_shared3_pll", + "dout_cmu_shared1_div3", + "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "fout_spare_pll", "oscclk" }; +PNAME(mout_cmu_eh_bus_p) = { "dout_cmu_shared0_div2", + "dout_cmu_shared1_div2", + "fout_shared2_pll", "fout_shared3_pll", + "dout_cmu_shared0_div3", + "dout_cmu_shared1_div3", + "dout_cmu_shared0_div5", "fout_spare_pll" }; +PNAME(mout_cmu_g2d_g2d_p) = { "dout_cmu_shared0_div3", "fout_shared3_pll", + "dout_cmu_shared1_div3", + "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "fout_spare_pll", "oscclk" }; +PNAME(mout_cmu_g2d_mscl_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared3_div2", + "fout_spare_pll", "oscclk", + "oscclk", "oscclk" }; +PNAME(mout_cmu_g3aa_g3aa_p) = { "dout_cmu_shared0_div3", "fout_shared3_pll", + "dout_cmu_shared1_div3", + "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "fout_spare_pll", "oscclk" }; +PNAME(mout_cmu_g3d_busd_p) = { "dout_cmu_shared0_div2", + "dout_cmu_shared1_div2", + "fout_shared2_pll", "fout_shared3_pll", + "dout_cmu_shared0_div3", + "dout_cmu_shared1_div3", + "dout_cmu_shared0_div4", "fout_spare_pll" }; +PNAME(mout_cmu_g3d_glb_p) = { "dout_cmu_shared0_div2", + "dout_cmu_shared1_div2", + "fout_shared2_pll", "fout_shared3_pll", + "dout_cmu_shared0_div3", + "dout_cmu_shared1_div3", + "dout_cmu_shared0_div4", "fout_spare_pll" }; +PNAME(mout_cmu_g3d_switch_p) = { "fout_shared2_pll", "dout_cmu_shared0_div3", + "fout_shared3_pll", "dout_cmu_shared1_div3", + "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "fout_spare_pll", "fout_spare_pll"}; +PNAME(mout_cmu_gdc_gdc0_p) = { "dout_cmu_shared0_div3", "fout_shared3_pll", + "dout_cmu_shared1_div3", + "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "fout_spare_pll", "oscclk" }; +PNAME(mout_cmu_gdc_gdc1_p) = { "dout_cmu_shared0_div3", "fout_shared3_pll", + "dout_cmu_shared1_div3", + "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "fout_spare_pll", "oscclk" }; +PNAME(mout_cmu_gdc_scsc_p) = { "dout_cmu_shared0_div3", "fout_shared3_pll", + "dout_cmu_shared1_div3", + "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "fout_spare_pll", "oscclk" }; +PNAME(mout_cmu_hpm_p) = { "oscclk", "dout_cmu_shared1_div3", + "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2" }; +PNAME(mout_cmu_hsi0_bus_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared3_div2", + "fout_spare_pll", "oscclk", + "oscclk", "oscclk" }; +PNAME(mout_cmu_hsi0_dpgtc_p) = { "oscclk", "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2", "fout_spare_pll" }; +PNAME(mout_cmu_hsi0_usb31drd_p) = { "oscclk", "dout_cmu_shared2_div2" }; +PNAME(mout_cmu_hsi0_usbdpdbg_p) = { "oscclk", "dout_cmu_shared2_div2" }; +PNAME(mout_cmu_hsi1_bus_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared3_div2", + "fout_spare_pll" }; +PNAME(mout_cmu_hsi1_pcie_p) = { "oscclk", "dout_cmu_shared2_div2" }; +PNAME(mout_cmu_hsi2_bus_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared3_div2", + "fout_spare_pll", "oscclk", + "oscclk", "oscclk" }; +PNAME(mout_cmu_hsi2_mmc_card_p) = { "fout_shared2_pll", "fout_shared3_pll", + "dout_cmu_shared0_div4", "fout_spare_pll" }; +PNAME(mout_cmu_hsi2_pcie0_p) = { "oscclk", "dout_cmu_shared2_div2" }; +PNAME(mout_cmu_hsi2_ufs_embd_p) = { "oscclk", "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2", "fout_spare_pll" }; +PNAME(mout_cmu_ipp_bus_p) = { "dout_cmu_shared0_div3", "fout_shared3_pll", + "dout_cmu_shared1_div3", + "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "fout_spare_pll", "oscclk" }; +PNAME(mout_cmu_itp_bus_p) = { "dout_cmu_shared0_div3", "fout_shared3_pll", + "dout_cmu_shared1_div3", + "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "fout_spare_pll", "oscclk" }; +PNAME(mout_cmu_mcsc_itsc_p) = { "dout_cmu_shared0_div3", "fout_shared3_pll", + "dout_cmu_shared1_div3", + "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "fout_spare_pll", "oscclk" }; +PNAME(mout_cmu_mcsc_mcsc_p) = { "dout_cmu_shared0_div3", "fout_shared3_pll", + "dout_cmu_shared1_div3", + "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "fout_spare_pll", "oscclk" }; +PNAME(mout_cmu_mfc_mfc_p) = { "dout_cmu_shared0_div3", "fout_shared3_pll", + "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", "fout_spare_pll", + "oscclk", "oscclk" }; +PNAME(mout_cmu_mif_busp_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared0_div5", "fout_spare_pll" }; +PNAME(mout_cmu_mif_switch_p) = { "fout_shared0_pll", "fout_shared1_pll", + "dout_cmu_shared0_div2", + "dout_cmu_shared1_div2", + "fout_shared2_pll", "dout_cmu_shared0_div3", + "fout_shared3_pll", "fout_spare_pll" }; +PNAME(mout_cmu_misc_bus_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared3_div2", "fout_spare_pll" }; +PNAME(mout_cmu_misc_sss_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared3_div2", "fout_spare_pll" }; +PNAME(mout_cmu_pdp_bus_p) = { "dout_cmu_shared0_div3", "fout_shared3_pll", + "dout_cmu_shared1_div3", + "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "fout_spare_pll", "oscclk" }; +PNAME(mout_cmu_pdp_vra_p) = { "fout_shared2_pll", "dout_cmu_shared0_div3", + "fout_shared3_pll", "dout_cmu_shared1_div3", + "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "fout_spare_pll", "oscclk" }; +PNAME(mout_cmu_peric0_bus_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared3_div2", "fout_spare_pll" }; +PNAME(mout_cmu_peric0_ip_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared3_div2", "fout_spare_pll" }; +PNAME(mout_cmu_peric1_bus_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared3_div2", "fout_spare_pll" }; +PNAME(mout_cmu_peric1_ip_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared3_div2", "fout_spare_pll" }; +PNAME(mout_cmu_tnr_bus_p) = { "dout_cmu_shared0_div3", "fout_shared3_pll", + "dout_cmu_shared1_div3", + "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "fout_spare_pll", "oscclk" }; +PNAME(mout_cmu_top_boost_option1_p) = { "oscclk", + "gout_cmu_boost_option1" }; +PNAME(mout_cmu_top_cmuref_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared1_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared3_div2" }; +PNAME(mout_cmu_tpu_bus_p) = { "dout_cmu_shared0_div2", + "dout_cmu_shared1_div2", + "fout_shared2_pll", + "fout_shared3_pll", + "dout_cmu_shared0_div3", + "dout_cmu_shared1_div3", + "dout_cmu_shared0_div4", + "fout_spare_pll" }; +PNAME(mout_cmu_tpu_tpu_p) = { "dout_cmu_shared0_div2", + "dout_cmu_shared1_div2", + "fout_shared2_pll", + "fout_shared3_pll", + "dout_cmu_shared0_div3", + "dout_cmu_shared1_div3", + "dout_cmu_shared0_div4", "fout_spare_pll" }; +PNAME(mout_cmu_tpu_tpuctl_p) = { "dout_cmu_shared0_div2", + "dout_cmu_shared1_div2", + "fout_shared2_pll", "fout_shared3_pll", + "dout_cmu_shared0_div3", + "dout_cmu_shared1_div3", + "dout_cmu_shared0_div4", "fout_spare_pll" }; +PNAME(mout_cmu_tpu_uart_p) = { "dout_cmu_shared0_div4", + "dout_cmu_shared2_div2", + "dout_cmu_shared3_div2", "fout_spare_pll" }; +PNAME(mout_cmu_cmuref_p) = { "mout_cmu_top_boost_option1", + "dout_cmu_cmuref" }; + +/* + * Register name to clock name mangling strategy used in this file + * + * Replace PLL_CON0_PLL with CLK_MOUT_PLL and mout_pll + * Replace CLK_CON_MUX_MUX_CLKCMU with CLK_MOUT_CMU and mout_cmu + * Replace CLK_CON_DIV_CLKCMU with CLK_DOUT_CMU and dout_cmu + * Replace CLK_CON_DIV_DIV_CLKCMU with CLK_DOUT_CMU and dout_cmu + * Replace CLK_CON_GAT_CLKCMU with CLK_GOUT_CMU and gout_cmu + * Replace CLK_CON_GAT_GATE_CLKCMU with CLK_GOUT_CMU and gout_cmu + * + * For gates remove _UID _BLK _IPCLKPORT and _RSTNSYNC + */ + +static const struct samsung_mux_clock cmu_top_mux_clks[] __initconst = { + MUX(CLK_MOUT_PLL_SHARED0, "mout_pll_shared0", mout_pll_shared0_p, + PLL_CON0_PLL_SHARED0, 4, 1), + MUX(CLK_MOUT_PLL_SHARED1, "mout_pll_shared1", mout_pll_shared1_p, + PLL_CON0_PLL_SHARED1, 4, 1), + MUX(CLK_MOUT_PLL_SHARED2, "mout_pll_shared2", mout_pll_shared2_p, + PLL_CON0_PLL_SHARED2, 4, 1), + MUX(CLK_MOUT_PLL_SHARED3, "mout_pll_shared3", mout_pll_shared3_p, + PLL_CON0_PLL_SHARED3, 4, 1), + MUX(CLK_MOUT_PLL_SPARE, "mout_pll_spare", mout_pll_spare_p, + PLL_CON0_PLL_SPARE, 4, 1), + MUX(CLK_MOUT_CMU_BO_BUS, "mout_cmu_bo_bus", mout_cmu_bo_bus_p, + CLK_CON_MUX_MUX_CLKCMU_BO_BUS, 0, 3), + MUX(CLK_MOUT_CMU_BUS0_BUS, "mout_cmu_bus0_bus", mout_cmu_bus0_bus_p, + CLK_CON_MUX_MUX_CLKCMU_BUS0_BUS, 0, 3), + MUX(CLK_MOUT_CMU_BUS1_BUS, "mout_cmu_bus1_bus", mout_cmu_bus1_bus_p, + CLK_CON_MUX_MUX_CLKCMU_BUS1_BUS, 0, 3), + MUX(CLK_MOUT_CMU_BUS2_BUS, "mout_cmu_bus2_bus", mout_cmu_bus2_bus_p, + CLK_CON_MUX_MUX_CLKCMU_BUS2_BUS, 0, 3), + MUX(CLK_MOUT_CMU_CIS_CLK0, "mout_cmu_cis_clk0", mout_cmu_cis_clk0_7_p, + CLK_CON_MUX_MUX_CLKCMU_CIS_CLK0, 0, 3), + MUX(CLK_MOUT_CMU_CIS_CLK1, "mout_cmu_cis_clk1", mout_cmu_cis_clk0_7_p, + CLK_CON_MUX_MUX_CLKCMU_CIS_CLK1, 0, 3), + MUX(CLK_MOUT_CMU_CIS_CLK2, "mout_cmu_cis_clk2", mout_cmu_cis_clk0_7_p, + CLK_CON_MUX_MUX_CLKCMU_CIS_CLK2, 0, 3), + MUX(CLK_MOUT_CMU_CIS_CLK3, "mout_cmu_cis_clk3", mout_cmu_cis_clk0_7_p, + CLK_CON_MUX_MUX_CLKCMU_CIS_CLK3, 0, 3), + MUX(CLK_MOUT_CMU_CIS_CLK4, "mout_cmu_cis_clk4", mout_cmu_cis_clk0_7_p, + CLK_CON_MUX_MUX_CLKCMU_CIS_CLK4, 0, 3), + MUX(CLK_MOUT_CMU_CIS_CLK5, "mout_cmu_cis_clk5", mout_cmu_cis_clk0_7_p, + CLK_CON_MUX_MUX_CLKCMU_CIS_CLK5, 0, 3), + MUX(CLK_MOUT_CMU_CIS_CLK6, "mout_cmu_cis_clk6", mout_cmu_cis_clk0_7_p, + CLK_CON_MUX_MUX_CLKCMU_CIS_CLK6, 0, 3), + MUX(CLK_MOUT_CMU_CIS_CLK7, "mout_cmu_cis_clk7", mout_cmu_cis_clk0_7_p, + CLK_CON_MUX_MUX_CLKCMU_CIS_CLK7, 0, 3), + MUX(CLK_MOUT_CMU_CMU_BOOST, "mout_cmu_cmu_boost", mout_cmu_cmu_boost_p, + CLK_CON_MUX_MUX_CLKCMU_CMU_BOOST, 0, 2), + MUX(CLK_MOUT_CMU_BOOST_OPTION1, "mout_cmu_boost_option1", + mout_cmu_cmu_boost_option1_p, + CLK_CON_MUX_MUX_CLKCMU_CMU_BOOST_OPTION1, 0, 1), + MUX(CLK_MOUT_CMU_CORE_BUS, "mout_cmu_core_bus", mout_cmu_core_bus_p, + CLK_CON_MUX_MUX_CLKCMU_CORE_BUS, 0, 3), + MUX(CLK_MOUT_CMU_CPUCL0_DBG, "mout_cmu_cpucl0_dbg", + mout_cmu_cpucl0_dbg_p, CLK_CON_DIV_CLKCMU_CPUCL0_DBG, 0, 3), + MUX(CLK_MOUT_CMU_CPUCL0_SWITCH, "mout_cmu_cpucl0_switch", + mout_cmu_cpucl0_switch_p, CLK_CON_MUX_MUX_CLKCMU_CPUCL0_SWITCH, + 0, 3), + MUX(CLK_MOUT_CMU_CPUCL1_SWITCH, "mout_cmu_cpucl1_switch", + mout_cmu_cpucl1_switch_p, CLK_CON_MUX_MUX_CLKCMU_CPUCL1_SWITCH, + 0, 3), + MUX(CLK_MOUT_CMU_CPUCL2_SWITCH, "mout_cmu_cpucl2_switch", + mout_cmu_cpucl2_switch_p, CLK_CON_MUX_MUX_CLKCMU_CPUCL2_SWITCH, + 0, 3), + MUX(CLK_MOUT_CMU_CSIS_BUS, "mout_cmu_csis_bus", mout_cmu_csis_bus_p, + CLK_CON_MUX_MUX_CLKCMU_CSIS_BUS, 0, 3), + MUX(CLK_MOUT_CMU_DISP_BUS, "mout_cmu_disp_bus", mout_cmu_disp_bus_p, + CLK_CON_MUX_MUX_CLKCMU_DISP_BUS, 0, 3), + MUX(CLK_MOUT_CMU_DNS_BUS, "mout_cmu_dns_bus", mout_cmu_dns_bus_p, + CLK_CON_MUX_MUX_CLKCMU_DNS_BUS, 0, 3), + MUX(CLK_MOUT_CMU_DPU_BUS, "mout_cmu_dpu_bus", mout_cmu_dpu_p, + CLK_CON_MUX_MUX_CLKCMU_DPU_BUS, 0, 3), + MUX(CLK_MOUT_CMU_EH_BUS, "mout_cmu_eh_bus", mout_cmu_eh_bus_p, + CLK_CON_MUX_MUX_CLKCMU_EH_BUS, 0, 3), + MUX(CLK_MOUT_CMU_G2D_G2D, "mout_cmu_g2d_g2d", mout_cmu_g2d_g2d_p, + CLK_CON_MUX_MUX_CLKCMU_G2D_G2D, 0, 3), + MUX(CLK_MOUT_CMU_G2D_MSCL, "mout_cmu_g2d_mscl", mout_cmu_g2d_mscl_p, + CLK_CON_MUX_MUX_CLKCMU_G2D_MSCL, 0, 3), + MUX(CLK_MOUT_CMU_G3AA_G3AA, "mout_cmu_g3aa_g3aa", mout_cmu_g3aa_g3aa_p, + CLK_CON_MUX_MUX_CLKCMU_G3AA_G3AA, 0, 3), + MUX(CLK_MOUT_CMU_G3D_BUSD, "mout_cmu_g3d_busd", mout_cmu_g3d_busd_p, + CLK_CON_MUX_MUX_CLKCMU_G3D_BUSD, 0, 3), + MUX(CLK_MOUT_CMU_G3D_GLB, "mout_cmu_g3d_glb", mout_cmu_g3d_glb_p, + CLK_CON_MUX_MUX_CLKCMU_G3D_GLB, 0, 3), + MUX(CLK_MOUT_CMU_G3D_SWITCH, "mout_cmu_g3d_switch", + mout_cmu_g3d_switch_p, CLK_CON_MUX_MUX_CLKCMU_G3D_SWITCH, 0, 3), + MUX(CLK_MOUT_CMU_GDC_GDC0, "mout_cmu_gdc_gdc0", mout_cmu_gdc_gdc0_p, + CLK_CON_MUX_MUX_CLKCMU_GDC_GDC0, 0, 3), + MUX(CLK_MOUT_CMU_GDC_GDC1, "mout_cmu_gdc_gdc1", mout_cmu_gdc_gdc1_p, + CLK_CON_MUX_MUX_CLKCMU_GDC_GDC1, 0, 3), + MUX(CLK_MOUT_CMU_GDC_SCSC, "mout_cmu_gdc_scsc", mout_cmu_gdc_scsc_p, + CLK_CON_MUX_MUX_CLKCMU_GDC_SCSC, 0, 3), + MUX(CLK_MOUT_CMU_HPM, "mout_cmu_hpm", mout_cmu_hpm_p, + CLK_CON_MUX_MUX_CLKCMU_HPM, 0, 2), + MUX(CLK_MOUT_CMU_HSI0_BUS, "mout_cmu_hsi0_bus", mout_cmu_hsi0_bus_p, + CLK_CON_MUX_MUX_CLKCMU_HSI0_BUS, 0, 3), + MUX(CLK_MOUT_CMU_HSI0_DPGTC, "mout_cmu_hsi0_dpgtc", + mout_cmu_hsi0_dpgtc_p, CLK_CON_MUX_MUX_CLKCMU_HSI0_DPGTC, 0, 2), + MUX(CLK_MOUT_CMU_HSI0_USB31DRD, "mout_cmu_hsi0_usb31drd", + mout_cmu_hsi0_usb31drd_p, CLK_CON_MUX_MUX_CLKCMU_HSI0_USB31DRD, + 0, 1), + MUX(CLK_MOUT_CMU_HSI0_USBDPDBG, "mout_cmu_hsi0_usbdpdbg", + mout_cmu_hsi0_usbdpdbg_p, CLK_CON_MUX_MUX_CLKCMU_HSI0_USBDPDBG, + 0, 1), + MUX(CLK_MOUT_CMU_HSI1_BUS, "mout_cmu_hsi1_bus", mout_cmu_hsi1_bus_p, + CLK_CON_MUX_MUX_CLKCMU_HSI1_BUS, 0, 3), + MUX(CLK_MOUT_CMU_HSI1_PCIE, "mout_cmu_hsi1_pcie", mout_cmu_hsi1_pcie_p, + CLK_CON_MUX_MUX_CLKCMU_HSI1_PCIE, 0, 1), + MUX(CLK_MOUT_CMU_HSI2_BUS, "mout_cmu_hsi2_bus", mout_cmu_hsi2_bus_p, + CLK_CON_MUX_MUX_CLKCMU_HSI2_BUS, 0, 3), + MUX(CLK_MOUT_CMU_HSI2_MMC_CARD, "mout_cmu_hsi2_mmc_card", + mout_cmu_hsi2_mmc_card_p, CLK_CON_MUX_MUX_CLKCMU_HSI2_MMC_CARD, + 0, 2), + MUX(CLK_MOUT_CMU_HSI2_PCIE, "mout_cmu_hsi2_pcie", mout_cmu_hsi2_pcie0_p, + CLK_CON_MUX_MUX_CLKCMU_HSI2_PCIE, 0, 1), + MUX(CLK_MOUT_CMU_HSI2_UFS_EMBD, "mout_cmu_hsi2_ufs_embd", + mout_cmu_hsi2_ufs_embd_p, CLK_CON_MUX_MUX_CLKCMU_HSI2_UFS_EMBD, + 0, 2), + MUX(CLK_MOUT_CMU_IPP_BUS, "mout_cmu_ipp_bus", mout_cmu_ipp_bus_p, + CLK_CON_MUX_MUX_CLKCMU_IPP_BUS, 0, 3), + MUX(CLK_MOUT_CMU_ITP_BUS, "mout_cmu_itp_bus", mout_cmu_itp_bus_p, + CLK_CON_MUX_MUX_CLKCMU_ITP_BUS, 0, 3), + MUX(CLK_MOUT_CMU_MCSC_ITSC, "mout_cmu_mcsc_itsc", mout_cmu_mcsc_itsc_p, + CLK_CON_MUX_MUX_CLKCMU_MCSC_ITSC, 0, 3), + MUX(CLK_MOUT_CMU_MCSC_MCSC, "mout_cmu_mcsc_mcsc", mout_cmu_mcsc_mcsc_p, + CLK_CON_MUX_MUX_CLKCMU_MCSC_MCSC, 0, 3), + MUX(CLK_MOUT_CMU_MFC_MFC, "mout_cmu_mfc_mfc", mout_cmu_mfc_mfc_p, + CLK_CON_MUX_MUX_CLKCMU_MFC_MFC, 0, 3), + MUX(CLK_MOUT_CMU_MIF_BUSP, "mout_cmu_mif_busp", mout_cmu_mif_busp_p, + CLK_CON_MUX_MUX_CLKCMU_MIF_BUSP, 0, 2), + MUX(CLK_MOUT_CMU_MIF_SWITCH, "mout_cmu_mif_switch", + mout_cmu_mif_switch_p, CLK_CON_MUX_MUX_CLKCMU_MIF_SWITCH, 0, 3), + MUX(CLK_MOUT_CMU_MISC_BUS, "mout_cmu_misc_bus", mout_cmu_misc_bus_p, + CLK_CON_MUX_MUX_CLKCMU_MISC_BUS, 0, 2), + MUX(CLK_MOUT_CMU_MISC_SSS, "mout_cmu_misc_sss", mout_cmu_misc_sss_p, + CLK_CON_MUX_MUX_CLKCMU_MISC_SSS, 0, 2), + MUX(CLK_MOUT_CMU_PDP_BUS, "mout_cmu_pdp_bus", mout_cmu_pdp_bus_p, + CLK_CON_MUX_MUX_CLKCMU_PDP_BUS, 0, 3), + MUX(CLK_MOUT_CMU_PDP_VRA, "mout_cmu_pdp_vra", mout_cmu_pdp_vra_p, + CLK_CON_MUX_MUX_CLKCMU_PDP_VRA, 0, 3), + MUX(CLK_MOUT_CMU_PERIC0_BUS, "mout_cmu_peric0_bus", + mout_cmu_peric0_bus_p, CLK_CON_MUX_MUX_CLKCMU_PERIC0_BUS, 0, 2), + MUX(CLK_MOUT_CMU_PERIC0_IP, "mout_cmu_peric0_ip", mout_cmu_peric0_ip_p, + CLK_CON_MUX_MUX_CLKCMU_PERIC0_IP, 0, 2), + MUX(CLK_MOUT_CMU_PERIC1_BUS, "mout_cmu_peric1_bus", + mout_cmu_peric1_bus_p, CLK_CON_MUX_MUX_CLKCMU_PERIC1_BUS, 0, 2), + MUX(CLK_MOUT_CMU_PERIC1_IP, "mout_cmu_peric1_ip", mout_cmu_peric1_ip_p, + CLK_CON_MUX_MUX_CLKCMU_PERIC1_IP, 0, 2), + MUX(CLK_MOUT_CMU_TNR_BUS, "mout_cmu_tnr_bus", mout_cmu_tnr_bus_p, + CLK_CON_MUX_MUX_CLKCMU_TNR_BUS, 0, 3), + MUX(CLK_MOUT_CMU_TOP_BOOST_OPTION1, "mout_cmu_top_boost_option1", + mout_cmu_top_boost_option1_p, + CLK_CON_MUX_MUX_CLKCMU_TOP_BOOST_OPTION1, 0, 1), + MUX(CLK_MOUT_CMU_TOP_CMUREF, "mout_cmu_top_cmuref", + mout_cmu_top_cmuref_p, CLK_CON_MUX_MUX_CLKCMU_TOP_CMUREF, 0, 2), + MUX(CLK_MOUT_CMU_TPU_BUS, "mout_cmu_tpu_bus", mout_cmu_tpu_bus_p, + CLK_CON_MUX_MUX_CLKCMU_TPU_BUS, 0, 3), + MUX(CLK_MOUT_CMU_TPU_TPU, "mout_cmu_tpu_tpu", mout_cmu_tpu_tpu_p, + CLK_CON_MUX_MUX_CLKCMU_TPU_TPU, 0, 3), + MUX(CLK_MOUT_CMU_TPU_TPUCTL, "mout_cmu_tpu_tpuctl", + mout_cmu_tpu_tpuctl_p, CLK_CON_MUX_MUX_CLKCMU_TPU_TPUCTL, 0, 3), + MUX(CLK_MOUT_CMU_TPU_UART, "mout_cmu_tpu_uart", mout_cmu_tpu_uart_p, + CLK_CON_MUX_MUX_CLKCMU_TPU_UART, 0, 2), + MUX(CLK_MOUT_CMU_CMUREF, "mout_cmu_cmuref", mout_cmu_cmuref_p, + CLK_CON_MUX_MUX_CMU_CMUREF, 0, 1), +}; + +static const struct samsung_div_clock cmu_top_div_clks[] __initconst = { + DIV(CLK_DOUT_CMU_BO_BUS, "dout_cmu_bo_bus", "gout_cmu_bo_bus", + CLK_CON_DIV_CLKCMU_BO_BUS, 0, 4), + DIV(CLK_DOUT_CMU_BUS0_BUS, "dout_cmu_bus0_bus", "gout_cmu_bus0_bus", + CLK_CON_DIV_CLKCMU_BUS0_BUS, 0, 4), + DIV(CLK_DOUT_CMU_BUS1_BUS, "dout_cmu_bus1_bus", "gout_cmu_bus1_bus", + CLK_CON_DIV_CLKCMU_BUS1_BUS, 0, 4), + DIV(CLK_DOUT_CMU_BUS2_BUS, "dout_cmu_bus2_bus", "gout_cmu_bus2_bus", + CLK_CON_DIV_CLKCMU_BUS2_BUS, 0, 4), + DIV(CLK_DOUT_CMU_CIS_CLK0, "dout_cmu_cis_clk0", "gout_cmu_cis_clk0", + CLK_CON_DIV_CLKCMU_CIS_CLK0, 0, 5), + DIV(CLK_DOUT_CMU_CIS_CLK1, "dout_cmu_cis_clk1", "gout_cmu_cis_clk1", + CLK_CON_DIV_CLKCMU_CIS_CLK1, 0, 5), + DIV(CLK_DOUT_CMU_CIS_CLK2, "dout_cmu_cis_clk2", "gout_cmu_cis_clk2", + CLK_CON_DIV_CLKCMU_CIS_CLK2, 0, 5), + DIV(CLK_DOUT_CMU_CIS_CLK3, "dout_cmu_cis_clk3", "gout_cmu_cis_clk3", + CLK_CON_DIV_CLKCMU_CIS_CLK3, 0, 5), + DIV(CLK_DOUT_CMU_CIS_CLK4, "dout_cmu_cis_clk4", "gout_cmu_cis_clk4", + CLK_CON_DIV_CLKCMU_CIS_CLK4, 0, 5), + DIV(CLK_DOUT_CMU_CIS_CLK5, "dout_cmu_cis_clk5", "gout_cmu_cis_clk5", + CLK_CON_DIV_CLKCMU_CIS_CLK5, 0, 5), + DIV(CLK_DOUT_CMU_CIS_CLK6, "dout_cmu_cis_clk6", "gout_cmu_cis_clk6", + CLK_CON_DIV_CLKCMU_CIS_CLK6, 0, 5), + DIV(CLK_DOUT_CMU_CIS_CLK7, "dout_cmu_cis_clk7", "gout_cmu_cis_clk7", + CLK_CON_DIV_CLKCMU_CIS_CLK7, 0, 5), + DIV(CLK_DOUT_CMU_CORE_BUS, "dout_cmu_core_bus", "gout_cmu_core_bus", + CLK_CON_DIV_CLKCMU_CORE_BUS, 0, 4), + DIV(CLK_DOUT_CMU_CPUCL0_DBG, "dout_cmu_cpucl0_dbg", + "gout_cmu_cpucl0_dbg", CLK_CON_DIV_CLKCMU_CPUCL0_DBG, 0, 4), + DIV(CLK_DOUT_CMU_CPUCL0_SWITCH, "dout_cmu_cpucl0_switch", + "gout_cmu_cpucl0_switch", CLK_CON_DIV_CLKCMU_CPUCL0_SWITCH, 0, 3), + DIV(CLK_DOUT_CMU_CPUCL1_SWITCH, "dout_cmu_cpucl1_switch", + "gout_cmu_cpucl1_switch", CLK_CON_DIV_CLKCMU_CPUCL1_SWITCH, 0, 3), + DIV(CLK_DOUT_CMU_CPUCL2_SWITCH, "dout_cmu_cpucl2_switch", + "gout_cmu_cpucl2_switch", CLK_CON_DIV_CLKCMU_CPUCL2_SWITCH, 0, 3), + DIV(CLK_DOUT_CMU_CSIS_BUS, "dout_cmu_csis_bus", "gout_cmu_csis_bus", + CLK_CON_DIV_CLKCMU_CSIS_BUS, 0, 4), + DIV(CLK_DOUT_CMU_DISP_BUS, "dout_cmu_disp_bus", "gout_cmu_disp_bus", + CLK_CON_DIV_CLKCMU_DISP_BUS, 0, 4), + DIV(CLK_DOUT_CMU_DNS_BUS, "dout_cmu_dns_bus", "gout_cmu_dns_bus", + CLK_CON_DIV_CLKCMU_DNS_BUS, 0, 4), + DIV(CLK_DOUT_CMU_DPU_BUS, "dout_cmu_dpu_bus", "gout_cmu_dpu_bus", + CLK_CON_DIV_CLKCMU_DPU_BUS, 0, 4), + DIV(CLK_DOUT_CMU_EH_BUS, "dout_cmu_eh_bus", "gout_cmu_eh_bus", + CLK_CON_DIV_CLKCMU_EH_BUS, 0, 4), + DIV(CLK_DOUT_CMU_G2D_G2D, "dout_cmu_g2d_g2d", "gout_cmu_g2d_g2d", + CLK_CON_DIV_CLKCMU_G2D_G2D, 0, 4), + DIV(CLK_DOUT_CMU_G2D_MSCL, "dout_cmu_g2d_mscl", "gout_cmu_g2d_mscl", + CLK_CON_DIV_CLKCMU_G2D_MSCL, 0, 4), + DIV(CLK_DOUT_CMU_G3AA_G3AA, "dout_cmu_g3aa_g3aa", "gout_cmu_g3aa_g3aa", + CLK_CON_DIV_CLKCMU_G3AA_G3AA, 0, 4), + DIV(CLK_DOUT_CMU_G3D_SWITCH, "dout_cmu_g3d_busd", "gout_cmu_g3d_busd", + CLK_CON_DIV_CLKCMU_G3D_BUSD, 0, 4), + DIV(CLK_DOUT_CMU_G3D_GLB, "dout_cmu_g3d_glb", "gout_cmu_g3d_glb", + CLK_CON_DIV_CLKCMU_G3D_GLB, 0, 4), + DIV(CLK_DOUT_CMU_G3D_SWITCH, "dout_cmu_g3d_switch", + "gout_cmu_g3d_switch", CLK_CON_DIV_CLKCMU_G3D_SWITCH, 0, 3), + DIV(CLK_DOUT_CMU_GDC_GDC0, "dout_cmu_gdc_gdc0", "gout_cmu_gdc_gdc0", + CLK_CON_DIV_CLKCMU_GDC_GDC0, 0, 4), + DIV(CLK_DOUT_CMU_GDC_GDC1, "dout_cmu_gdc_gdc1", "gout_cmu_gdc_gdc1", + CLK_CON_DIV_CLKCMU_GDC_GDC1, 0, 4), + DIV(CLK_DOUT_CMU_GDC_SCSC, "dout_cmu_gdc_scsc", "gout_cmu_gdc_scsc", + CLK_CON_DIV_CLKCMU_GDC_SCSC, 0, 4), + DIV(CLK_DOUT_CMU_CMU_HPM, "dout_cmu_hpm", "gout_cmu_hpm", + CLK_CON_DIV_CLKCMU_HPM, 0, 2), + DIV(CLK_DOUT_CMU_HSI0_BUS, "dout_cmu_hsi0_bus", "gout_cmu_hsi0_bus", + CLK_CON_DIV_CLKCMU_HSI0_BUS, 0, 4), + DIV(CLK_DOUT_CMU_HSI0_DPGTC, "dout_cmu_hsi0_dpgtc", + "gout_cmu_hsi0_dpgtc", CLK_CON_DIV_CLKCMU_HSI0_DPGTC, 0, 4), + DIV(CLK_DOUT_CMU_HSI0_USB31DRD, "dout_cmu_hsi0_usb31drd", + "gout_cmu_hsi0_usb31drd", CLK_CON_DIV_CLKCMU_HSI0_USB31DRD, 0, 5), + DIV(CLK_DOUT_CMU_HSI1_BUS, "dout_cmu_hsi1_bus", "gout_cmu_hsi1_bus", + CLK_CON_DIV_CLKCMU_HSI1_BUS, 0, 4), + DIV(CLK_DOUT_CMU_HSI1_PCIE, "dout_cmu_hsi1_pcie", "gout_cmu_hsi1_pcie", + CLK_CON_DIV_CLKCMU_HSI1_PCIE, 0, 3), + DIV(CLK_DOUT_CMU_HSI2_BUS, "dout_cmu_hsi2_bus", "gout_cmu_hsi2_bus", + CLK_CON_DIV_CLKCMU_HSI2_BUS, 0, 4), + DIV(CLK_DOUT_CMU_HSI2_MMC_CARD, "dout_cmu_hsi2_mmc_card", + "gout_cmu_hsi2_mmc_card", CLK_CON_DIV_CLKCMU_HSI2_MMC_CARD, 0, 9), + DIV(CLK_DOUT_CMU_HSI2_PCIE, "dout_cmu_hsi2_pcie", "gout_cmu_hsi2_pcie", + CLK_CON_DIV_CLKCMU_HSI2_PCIE, 0, 3), + DIV(CLK_DOUT_CMU_HSI2_UFS_EMBD, "dout_cmu_hsi2_ufs_embd", + "gout_cmu_hsi2_ufs_embd", CLK_CON_DIV_CLKCMU_HSI2_UFS_EMBD, 0, 4), + DIV(CLK_DOUT_CMU_IPP_BUS, "dout_cmu_ipp_bus", "gout_cmu_ipp_bus", + CLK_CON_DIV_CLKCMU_IPP_BUS, 0, 4), + DIV(CLK_DOUT_CMU_ITP_BUS, "dout_cmu_itp_bus", "gout_cmu_itp_bus", + CLK_CON_DIV_CLKCMU_ITP_BUS, 0, 4), + DIV(CLK_DOUT_CMU_MCSC_ITSC, "dout_cmu_mcsc_itsc", "gout_cmu_mcsc_itsc", + CLK_CON_DIV_CLKCMU_MCSC_ITSC, 0, 4), + DIV(CLK_DOUT_CMU_MCSC_MCSC, "dout_cmu_mcsc_mcsc", "gout_cmu_mcsc_mcsc", + CLK_CON_DIV_CLKCMU_MCSC_MCSC, 0, 4), + DIV(CLK_DOUT_CMU_MFC_MFC, "dout_cmu_mfc_mfc", "gout_cmu_mfc_mfc", + CLK_CON_DIV_CLKCMU_MFC_MFC, 0, 4), + DIV(CLK_DOUT_CMU_MIF_BUSP, "dout_cmu_mif_busp", "gout_cmu_mif_busp", + CLK_CON_DIV_CLKCMU_MIF_BUSP, 0, 4), + DIV(CLK_DOUT_CMU_MISC_BUS, "dout_cmu_misc_bus", "gout_cmu_misc_bus", + CLK_CON_DIV_CLKCMU_MISC_BUS, 0, 4), + DIV(CLK_DOUT_CMU_MISC_SSS, "dout_cmu_misc_sss", "gout_cmu_misc_sss", + CLK_CON_DIV_CLKCMU_MISC_SSS, 0, 4), + DIV(CLK_DOUT_CMU_PDP_BUS, "dout_cmu_pdp_bus", "gout_cmu_pdp_bus", + CLK_CON_DIV_CLKCMU_PDP_BUS, 0, 4), + DIV(CLK_DOUT_CMU_PDP_VRA, "dout_cmu_pdp_vra", "gout_cmu_pdp_vra", + CLK_CON_DIV_CLKCMU_PDP_VRA, 0, 4), + DIV(CLK_DOUT_CMU_PERIC0_BUS, "dout_cmu_peric0_bus", + "gout_cmu_peric0_bus", CLK_CON_DIV_CLKCMU_PERIC0_BUS, 0, 4), + DIV(CLK_DOUT_CMU_PERIC0_IP, "dout_cmu_peric0_ip", "gout_cmu_peric0_ip", + CLK_CON_DIV_CLKCMU_PERIC0_IP, 0, 4), + DIV(CLK_DOUT_CMU_PERIC1_BUS, "dout_cmu_peric1_bus", + "gout_cmu_peric1_bus", CLK_CON_DIV_CLKCMU_PERIC1_BUS, 0, 4), + DIV(CLK_DOUT_CMU_PERIC1_IP, "dout_cmu_peric1_ip", "gout_cmu_peric1_ip", + CLK_CON_DIV_CLKCMU_PERIC1_IP, 0, 4), + DIV(CLK_DOUT_CMU_TNR_BUS, "dout_cmu_tnr_bus", "gout_cmu_tnr_bus", + CLK_CON_DIV_CLKCMU_TNR_BUS, 0, 4), + DIV(CLK_DOUT_CMU_TPU_BUS, "dout_cmu_tpu_bus", "gout_cmu_tpu_bus", + CLK_CON_DIV_CLKCMU_TPU_BUS, 0, 4), + DIV(CLK_DOUT_CMU_TPU_TPU, "dout_cmu_tpu_tpu", "gout_cmu_tpu_tpu", + CLK_CON_DIV_CLKCMU_TPU_TPU, 0, 4), + DIV(CLK_DOUT_CMU_TPU_TPUCTL, "dout_cmu_tpu_tpuctl", + "gout_cmu_tpu_tpuctl", CLK_CON_DIV_CLKCMU_TPU_TPUCTL, 0, 4), + DIV(CLK_DOUT_CMU_TPU_UART, "dout_cmu_tpu_uart", "gout_cmu_tpu_uart", + CLK_CON_DIV_CLKCMU_TPU_UART, 0, 4), + DIV(CLK_DOUT_CMU_CMU_BOOST, "dout_cmu_cmu_boost", "gout_cmu_cmu_boost", + CLK_CON_DIV_DIV_CLKCMU_CMU_BOOST, 0, 2), + DIV(CLK_DOUT_CMU_CMU_CMUREF, "dout_cmu_cmuref", "gout_cmu_cmuref", + CLK_CON_DIV_DIV_CLK_CMU_CMUREF, 0, 2), + DIV(CLK_DOUT_CMU_SHARED0_DIV2, "dout_cmu_shared0_div2", + "mout_pll_shared0", CLK_CON_DIV_PLL_SHARED0_DIV2, 0, 1), + DIV(CLK_DOUT_CMU_SHARED0_DIV3, "dout_cmu_shared0_div3", + "mout_pll_shared0", CLK_CON_DIV_PLL_SHARED0_DIV3, 0, 2), + DIV(CLK_DOUT_CMU_SHARED0_DIV4, "dout_cmu_shared0_div4", + "dout_cmu_shared0_div2", CLK_CON_DIV_PLL_SHARED0_DIV4, 0, 1), + DIV(CLK_DOUT_CMU_SHARED0_DIV5, "dout_cmu_shared0_div5", + "mout_pll_shared0", CLK_CON_DIV_PLL_SHARED0_DIV5, 0, 3), + DIV(CLK_DOUT_CMU_SHARED1_DIV2, "dout_cmu_shared1_div2", + "mout_pll_shared1", CLK_CON_DIV_PLL_SHARED1_DIV2, 0, 1), + DIV(CLK_DOUT_CMU_SHARED1_DIV3, "dout_cmu_shared1_div3", + "mout_pll_shared1", CLK_CON_DIV_PLL_SHARED1_DIV3, 0, 2), + DIV(CLK_DOUT_CMU_SHARED1_DIV4, "dout_cmu_shared1_div4", + "mout_pll_shared1", CLK_CON_DIV_PLL_SHARED1_DIV4, 0, 1), + DIV(CLK_DOUT_CMU_SHARED2_DIV2, "dout_cmu_shared2_div2", + "mout_pll_shared2", CLK_CON_DIV_PLL_SHARED2_DIV2, 0, 1), + DIV(CLK_DOUT_CMU_SHARED3_DIV2, "dout_cmu_shared3_div2", + "mout_pll_shared3", CLK_CON_DIV_PLL_SHARED3_DIV2, 0, 1), +}; + +static const struct samsung_fixed_factor_clock cmu_top_ffactor[] __initconst = { + FFACTOR(CLK_DOUT_CMU_HSI0_USBDPDBG, "dout_cmu_hsi0_usbdpdbg", + "gout_cmu_hsi0_usbdpdbg", 1, 4, 0), + FFACTOR(CLK_DOUT_CMU_OTP, "dout_cmu_otp", "oscclk", 1, 8, 0), +}; + +static const struct samsung_gate_clock cmu_top_gate_clks[] __initconst = { + GATE(CLK_GOUT_CMU_BUS0_BOOST, "gout_cmu_bus0_boost", + "mout_cmu_boost_option1", CLK_CON_GAT_CLKCMU_BUS0_BOOST, 21, 0, 0), + GATE(CLK_GOUT_CMU_BUS1_BOOST, "gout_cmu_bus1_boost", + "mout_cmu_boost_option1", CLK_CON_GAT_CLKCMU_BUS1_BOOST, 21, 0, 0), + GATE(CLK_GOUT_CMU_BUS2_BOOST, "gout_cmu_bus2_boost", + "mout_cmu_boost_option1", CLK_CON_GAT_CLKCMU_BUS2_BOOST, 21, 0, 0), + GATE(CLK_GOUT_CMU_CORE_BOOST, "gout_cmu_core_boost", + "mout_cmu_boost_option1", CLK_CON_GAT_CLKCMU_CORE_BOOST, 21, 0, 0), + GATE(CLK_GOUT_CMU_CPUCL0_BOOST, "gout_cmu_cpucl0_boost", + "mout_cmu_boost_option1", CLK_CON_GAT_CLKCMU_CPUCL0_BOOST, + 21, 0, 0), + GATE(CLK_GOUT_CMU_CPUCL1_BOOST, "gout_cmu_cpucl1_boost", + "mout_cmu_boost_option1", CLK_CON_GAT_CLKCMU_CPUCL1_BOOST, + 21, 0, 0), + GATE(CLK_GOUT_CMU_CPUCL2_BOOST, "gout_cmu_cpucl2_boost", + "mout_cmu_boost_option1", CLK_CON_GAT_CLKCMU_CPUCL2_BOOST, + 21, 0, 0), + GATE(CLK_GOUT_CMU_MIF_BOOST, "gout_cmu_mif_boost", + "mout_cmu_boost_option1", CLK_CON_GAT_CLKCMU_MIF_BOOST, + 21, 0, 0), + GATE(CLK_GOUT_CMU_MIF_SWITCH, "gout_cmu_mif_switch", + "mout_cmu_mif_switch", CLK_CON_GAT_CLKCMU_MIF_SWITCH, 21, 0, 0), + GATE(CLK_GOUT_CMU_BO_BUS, "gout_cmu_bo_bus", "mout_cmu_bo_bus", + CLK_CON_GAT_GATE_CLKCMU_BO_BUS, 21, 0, 0), + GATE(CLK_GOUT_CMU_BUS0_BUS, "gout_cmu_bus0_bus", "mout_cmu_bus0_bus", + CLK_CON_GAT_GATE_CLKCMU_BUS0_BUS, 21, 0, 0), + GATE(CLK_GOUT_CMU_BUS1_BUS, "gout_cmu_bus1_bus", "mout_cmu_bus1_bus", + CLK_CON_GAT_GATE_CLKCMU_BUS1_BUS, 21, 0, 0), + GATE(CLK_GOUT_CMU_BUS2_BUS, "gout_cmu_bus2_bus", "mout_cmu_bus2_bus", + CLK_CON_GAT_GATE_CLKCMU_BUS2_BUS, 21, 0, 0), + GATE(CLK_GOUT_CMU_CIS_CLK0, "gout_cmu_cis_clk0", "mout_cmu_cis_clk0", + CLK_CON_GAT_GATE_CLKCMU_CIS_CLK0, 21, 0, 0), + GATE(CLK_GOUT_CMU_CIS_CLK1, "gout_cmu_cis_clk1", "mout_cmu_cis_clk1", + CLK_CON_GAT_GATE_CLKCMU_CIS_CLK1, 21, 0, 0), + GATE(CLK_GOUT_CMU_CIS_CLK2, "gout_cmu_cis_clk2", "mout_cmu_cis_clk2", + CLK_CON_GAT_GATE_CLKCMU_CIS_CLK2, 21, 0, 0), + GATE(CLK_GOUT_CMU_CIS_CLK3, "gout_cmu_cis_clk3", "mout_cmu_cis_clk3", + CLK_CON_GAT_GATE_CLKCMU_CIS_CLK3, 21, 0, 0), + GATE(CLK_GOUT_CMU_CIS_CLK4, "gout_cmu_cis_clk4", "mout_cmu_cis_clk4", + CLK_CON_GAT_GATE_CLKCMU_CIS_CLK4, 21, 0, 0), + GATE(CLK_GOUT_CMU_CIS_CLK5, "gout_cmu_cis_clk5", "mout_cmu_cis_clk5", + CLK_CON_GAT_GATE_CLKCMU_CIS_CLK5, 21, 0, 0), + GATE(CLK_GOUT_CMU_CIS_CLK6, "gout_cmu_cis_clk6", "mout_cmu_cis_clk6", + CLK_CON_GAT_GATE_CLKCMU_CIS_CLK6, 21, 0, 0), + GATE(CLK_GOUT_CMU_CIS_CLK7, "gout_cmu_cis_clk7", "mout_cmu_cis_clk7", + CLK_CON_GAT_GATE_CLKCMU_CIS_CLK7, 21, 0, 0), + GATE(CLK_GOUT_CMU_CMU_BOOST, "gout_cmu_cmu_boost", "mout_cmu_cmu_boost", + CLK_CON_GAT_GATE_CLKCMU_CMU_BOOST, 21, 0, 0), + GATE(CLK_GOUT_CMU_CORE_BUS, "gout_cmu_core_bus", "mout_cmu_core_bus", + CLK_CON_GAT_GATE_CLKCMU_CORE_BUS, 21, 0, 0), + GATE(CLK_GOUT_CMU_CPUCL0_DBG, "gout_cmu_cpucl0_dbg", + "mout_cmu_cpucl0_dbg", CLK_CON_GAT_GATE_CLKCMU_CPUCL0_DBG_BUS, + 21, 0, 0), + GATE(CLK_GOUT_CMU_CPUCL0_SWITCH, "gout_cmu_cpucl0_switch", + "mout_cmu_cpucl0_switch", CLK_CON_GAT_GATE_CLKCMU_CPUCL0_SWITCH, + 21, 0, 0), + GATE(CLK_GOUT_CMU_CPUCL1_SWITCH, "gout_cmu_cpucl1_switch", + "mout_cmu_cpucl1_switch", CLK_CON_GAT_GATE_CLKCMU_CPUCL1_SWITCH, + 21, 0, 0), + GATE(CLK_GOUT_CMU_CPUCL2_SWITCH, "gout_cmu_cpucl2_switch", + "mout_cmu_cpucl2_switch", CLK_CON_GAT_GATE_CLKCMU_CPUCL2_SWITCH, + 21, 0, 0), + GATE(CLK_GOUT_CMU_CSIS_BUS, "gout_cmu_csis_bus", "mout_cmu_csis_bus", + CLK_CON_GAT_GATE_CLKCMU_CSIS_BUS, 21, 0, 0), + GATE(CLK_GOUT_CMU_DISP_BUS, "gout_cmu_disp_bus", "mout_cmu_disp_bus", + CLK_CON_GAT_GATE_CLKCMU_DISP_BUS, 21, 0, 0), + GATE(CLK_GOUT_CMU_DNS_BUS, "gout_cmu_dns_bus", "mout_cmu_dns_bus", + CLK_CON_GAT_GATE_CLKCMU_DNS_BUS, 21, 0, 0), + GATE(CLK_GOUT_CMU_DPU_BUS, "gout_cmu_dpu_bus", "mout_cmu_dpu_bus", + CLK_CON_GAT_GATE_CLKCMU_DPU_BUS, 21, 0, 0), + GATE(CLK_GOUT_CMU_EH_BUS, "gout_cmu_eh_bus", "mout_cmu_eh_bus", + CLK_CON_GAT_GATE_CLKCMU_EH_BUS, 21, 0, 0), + GATE(CLK_GOUT_CMU_G2D_G2D, "gout_cmu_g2d_g2d", "mout_cmu_g2d_g2d", + CLK_CON_GAT_GATE_CLKCMU_G2D_G2D, 21, 0, 0), + GATE(CLK_GOUT_CMU_G2D_MSCL, "gout_cmu_g2d_mscl", "mout_cmu_g2d_mscl", + CLK_CON_GAT_GATE_CLKCMU_G2D_MSCL, 21, 0, 0), + GATE(CLK_GOUT_CMU_G3AA_G3AA, "gout_cmu_g3aa_g3aa", "mout_cmu_g3aa_g3aa", + CLK_CON_MUX_MUX_CLKCMU_G3AA_G3AA, 21, 0, 0), + GATE(CLK_GOUT_CMU_G3D_BUSD, "gout_cmu_g3d_busd", "mout_cmu_g3d_busd", + CLK_CON_GAT_GATE_CLKCMU_G3D_BUSD, 21, 0, 0), + GATE(CLK_GOUT_CMU_G3D_GLB, "gout_cmu_g3d_glb", "mout_cmu_g3d_glb", + CLK_CON_GAT_GATE_CLKCMU_G3D_GLB, 21, 0, 0), + GATE(CLK_GOUT_CMU_G3D_SWITCH, "gout_cmu_g3d_switch", + "mout_cmu_g3d_switch", CLK_CON_GAT_GATE_CLKCMU_G3D_SWITCH, + 21, 0, 0), + GATE(CLK_GOUT_CMU_GDC_GDC0, "gout_cmu_gdc_gdc0", "mout_cmu_gdc_gdc0", + CLK_CON_GAT_GATE_CLKCMU_GDC_GDC0, 21, 0, 0), + GATE(CLK_GOUT_CMU_GDC_GDC1, "gout_cmu_gdc_gdc1", "mout_cmu_gdc_gdc1", + CLK_CON_GAT_GATE_CLKCMU_GDC_GDC1, 21, 0, 0), + GATE(CLK_GOUT_CMU_GDC_SCSC, "gout_cmu_gdc_scsc", "mout_cmu_gdc_scsc", + CLK_CON_GAT_GATE_CLKCMU_GDC_SCSC, 21, 0, 0), + GATE(CLK_GOUT_CMU_HPM, "gout_cmu_hpm", "mout_cmu_hpm", + CLK_CON_GAT_GATE_CLKCMU_HPM, 21, 0, 0), + GATE(CLK_GOUT_CMU_HSI0_BUS, "gout_cmu_hsi0_bus", "mout_cmu_hsi0_bus", + CLK_CON_GAT_GATE_CLKCMU_HSI0_BUS, 21, 0, 0), + GATE(CLK_GOUT_CMU_HSI0_DPGTC, "gout_cmu_hsi0_dpgtc", + "mout_cmu_hsi0_dpgtc", CLK_CON_GAT_GATE_CLKCMU_HSI0_DPGTC, + 21, 0, 0), + GATE(CLK_GOUT_CMU_HSI0_USB31DRD, "gout_cmu_hsi0_usb31drd", + "mout_cmu_hsi0_usb31drd", CLK_CON_GAT_GATE_CLKCMU_HSI0_USB31DRD, + 21, 0, 0), + GATE(CLK_GOUT_CMU_HSI0_USBDPDBG, "gout_cmu_hsi0_usbdpdbg", + "mout_cmu_hsi0_usbdpdbg", CLK_CON_GAT_GATE_CLKCMU_HSI0_USBDPDBG, + 21, 0, 0), + GATE(CLK_GOUT_CMU_HSI1_BUS, "gout_cmu_hsi1_bus", "mout_cmu_hsi1_bus", + CLK_CON_GAT_GATE_CLKCMU_HSI1_BUS, 21, 0, 0), + GATE(CLK_GOUT_CMU_HSI1_PCIE, "gout_cmu_hsi1_pcie", "mout_cmu_hsi1_pcie", + CLK_CON_GAT_GATE_CLKCMU_HSI1_PCIE, 21, 0, 0), + GATE(CLK_GOUT_CMU_HSI2_BUS, "gout_cmu_hsi2_bus", "mout_cmu_hsi2_bus", + CLK_CON_GAT_GATE_CLKCMU_HSI2_BUS, 21, 0, 0), + GATE(CLK_GOUT_CMU_HSI2_MMC_CARD, "gout_cmu_hsi2_mmc_card", + "mout_cmu_hsi2_mmc_card", CLK_CON_GAT_GATE_CLKCMU_HSI2_MMCCARD, + 21, 0, 0), + GATE(CLK_GOUT_CMU_HSI2_PCIE, "gout_cmu_hsi2_pcie", "mout_cmu_hsi2_pcie", + CLK_CON_GAT_GATE_CLKCMU_HSI2_PCIE, 21, 0, 0), + GATE(CLK_GOUT_CMU_HSI2_UFS_EMBD, "gout_cmu_hsi2_ufs_embd", + "mout_cmu_hsi2_ufs_embd", CLK_CON_GAT_GATE_CLKCMU_HSI2_UFS_EMBD, + 21, 0, 0), + GATE(CLK_GOUT_CMU_IPP_BUS, "gout_cmu_ipp_bus", "mout_cmu_ipp_bus", + CLK_CON_GAT_GATE_CLKCMU_IPP_BUS, 21, 0, 0), + GATE(CLK_GOUT_CMU_ITP_BUS, "gout_cmu_itp_bus", "mout_cmu_itp_bus", + CLK_CON_GAT_GATE_CLKCMU_ITP_BUS, 21, 0, 0), + GATE(CLK_GOUT_CMU_MCSC_ITSC, "gout_cmu_mcsc_itsc", "mout_cmu_mcsc_itsc", + CLK_CON_GAT_GATE_CLKCMU_MCSC_ITSC, 21, 0, 0), + GATE(CLK_GOUT_CMU_MCSC_MCSC, "gout_cmu_mcsc_mcsc", "mout_cmu_mcsc_mcsc", + CLK_CON_GAT_GATE_CLKCMU_MCSC_MCSC, 21, 0, 0), + GATE(CLK_GOUT_CMU_MFC_MFC, "gout_cmu_mfc_mfc", "mout_cmu_mfc_mfc", + CLK_CON_GAT_GATE_CLKCMU_MFC_MFC, 21, 0, 0), + GATE(CLK_GOUT_CMU_MIF_BUSP, "gout_cmu_mif_busp", "mout_cmu_mif_busp", + CLK_CON_GAT_GATE_CLKCMU_MIF_BUSP, 21, 0, 0), + GATE(CLK_GOUT_CMU_MISC_BUS, "gout_cmu_misc_bus", "mout_cmu_misc_bus", + CLK_CON_GAT_GATE_CLKCMU_MISC_BUS, 21, 0, 0), + GATE(CLK_GOUT_CMU_MISC_SSS, "gout_cmu_misc_sss", "mout_cmu_misc_sss", + CLK_CON_GAT_GATE_CLKCMU_MISC_SSS, 21, 0, 0), + GATE(CLK_GOUT_CMU_PDP_BUS, "gout_cmu_pdp_bus", "mout_cmu_pdp_bus", + CLK_CON_GAT_GATE_CLKCMU_PDP_BUS, 21, 0, 0), + GATE(CLK_GOUT_CMU_PDP_VRA, "gout_cmu_pdp_vra", "mout_cmu_pdp_vra", + CLK_CON_GAT_GATE_CLKCMU_PDP_BUS, 21, 0, 0), + GATE(CLK_GOUT_CMU_PERIC0_BUS, "gout_cmu_peric0_bus", + "mout_cmu_peric0_bus", CLK_CON_GAT_GATE_CLKCMU_PERIC0_BUS, + 21, 0, 0), + GATE(CLK_GOUT_CMU_PERIC0_IP, "gout_cmu_peric0_ip", "mout_cmu_peric0_ip", + CLK_CON_GAT_GATE_CLKCMU_PERIC0_IP, 21, 0, 0), + GATE(CLK_GOUT_CMU_PERIC1_BUS, "gout_cmu_peric1_bus", + "mout_cmu_peric1_bus", CLK_CON_GAT_GATE_CLKCMU_PERIC1_BUS, + 21, 0, 0), + GATE(CLK_GOUT_CMU_PERIC1_IP, "gout_cmu_peric1_ip", "mout_cmu_peric1_ip", + CLK_CON_GAT_GATE_CLKCMU_PERIC1_IP, 21, 0, 0), + GATE(CLK_GOUT_CMU_TNR_BUS, "gout_cmu_tnr_bus", "mout_cmu_tnr_bus", + CLK_CON_GAT_GATE_CLKCMU_TNR_BUS, 21, 0, 0), + GATE(CLK_GOUT_CMU_TOP_CMUREF, "gout_cmu_top_cmuref", + "mout_cmu_top_cmuref", CLK_CON_GAT_GATE_CLKCMU_TOP_CMUREF, + 21, 0, 0), + GATE(CLK_GOUT_CMU_TPU_BUS, "gout_cmu_tpu_bus", "mout_cmu_tpu_bus", + CLK_CON_GAT_GATE_CLKCMU_TPU_BUS, 21, 0, 0), + GATE(CLK_GOUT_CMU_TPU_TPU, "gout_cmu_tpu_tpu", "mout_cmu_tpu_tpu", + CLK_CON_GAT_GATE_CLKCMU_TPU_TPU, 21, 0, 0), + GATE(CLK_GOUT_CMU_TPU_TPUCTL, "gout_cmu_tpu_tpuctl", + "mout_cmu_tpu_tpuctl", CLK_CON_GAT_GATE_CLKCMU_TPU_TPUCTL, + 21, 0, 0), + GATE(CLK_GOUT_CMU_TPU_UART, "gout_cmu_tpu_uart", "mout_cmu_tpu_uart", + CLK_CON_GAT_GATE_CLKCMU_TPU_UART, 21, 0, 0), +}; + +static const struct samsung_cmu_info top_cmu_info __initconst = { + .pll_clks = cmu_top_pll_clks, + .nr_pll_clks = ARRAY_SIZE(cmu_top_pll_clks), + .mux_clks = cmu_top_mux_clks, + .nr_mux_clks = ARRAY_SIZE(cmu_top_mux_clks), + .div_clks = cmu_top_div_clks, + .nr_div_clks = ARRAY_SIZE(cmu_top_div_clks), + .fixed_factor_clks = cmu_top_ffactor, + .nr_fixed_factor_clks = ARRAY_SIZE(cmu_top_ffactor), + .gate_clks = cmu_top_gate_clks, + .nr_gate_clks = ARRAY_SIZE(cmu_top_gate_clks), + .nr_clk_ids = CLKS_NR_TOP, + .clk_regs = cmu_top_clk_regs, + .nr_clk_regs = ARRAY_SIZE(cmu_top_clk_regs), +}; + +static void __init gs101_cmu_top_init(struct device_node *np) +{ + exynos_arm64_register_cmu(NULL, np, &top_cmu_info); +} + +/* Register CMU_TOP early, as it's a dependency for other early domains */ +CLK_OF_DECLARE(gs101_cmu_top, "google,gs101-cmu-top", + gs101_cmu_top_init); + +/* ---- CMU_APM ------------------------------------------------------------- */ + +/* Register Offset definitions for CMU_APM (0x17400000) */ +#define APM_CMU_APM_CONTROLLER_OPTION 0x0800 +#define CLKOUT_CON_BLK_APM_CMU_APM_CLKOUT0 0x0810 +#define CLK_CON_MUX_MUX_CLKCMU_APM_FUNC 0x1000 +#define CLK_CON_MUX_MUX_CLKCMU_APM_FUNCSRC 0x1004 +#define CLK_CON_DIV_DIV_CLK_APM_BOOST 0x1800 +#define CLK_CON_DIV_DIV_CLK_APM_USI0_UART 0x1804 +#define CLK_CON_DIV_DIV_CLK_APM_USI0_USI 0x1808 +#define CLK_CON_DIV_DIV_CLK_APM_USI1_UART 0x180c +#define CLK_CON_GAT_CLK_BLK_APM_UID_APM_CMU_APM_IPCLKPORT_PCLK 0x2000 +#define CLK_CON_GAT_CLK_BUS0_BOOST_OPTION1 0x2004 +#define CLK_CON_GAT_CLK_CMU_BOOST_OPTION1 0x2008 +#define CLK_CON_GAT_CLK_CORE_BOOST_OPTION1 0x200c +#define CLK_CON_GAT_GATE_CLKCMU_APM_FUNC 0x2010 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_APBIF_GPIO_ALIVE_IPCLKPORT_PCLK 0x2014 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_APBIF_GPIO_FAR_ALIVE_IPCLKPORT_PCLK 0x2018 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_APBIF_PMU_ALIVE_IPCLKPORT_PCLK 0x201c +#define CLK_CON_GAT_GOUT_BLK_APM_UID_APBIF_RTC_IPCLKPORT_PCLK 0x2020 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_APBIF_TRTC_IPCLKPORT_PCLK 0x2024 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_APM_USI0_UART_IPCLKPORT_IPCLK 0x2028 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_APM_USI0_UART_IPCLKPORT_PCLK 0x202c +#define CLK_CON_GAT_GOUT_BLK_APM_UID_APM_USI0_USI_IPCLKPORT_IPCLK 0x2030 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_APM_USI0_USI_IPCLKPORT_PCLK 0x2034 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_APM_USI1_UART_IPCLKPORT_IPCLK 0x2038 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_APM_USI1_UART_IPCLKPORT_PCLK 0x203c +#define CLK_CON_GAT_GOUT_BLK_APM_UID_D_TZPC_APM_IPCLKPORT_PCLK 0x2040 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_GPC_APM_IPCLKPORT_PCLK 0x2044 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_GREBEINTEGRATION_IPCLKPORT_HCLK 0x2048 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_INTMEM_IPCLKPORT_ACLK 0x204c +#define CLK_CON_GAT_GOUT_BLK_APM_UID_INTMEM_IPCLKPORT_PCLK 0x2050 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_LHM_AXI_G_SWD_IPCLKPORT_I_CLK 0x2054 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_LHM_AXI_P_AOCAPM_IPCLKPORT_I_CLK 0x2058 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_LHM_AXI_P_APM_IPCLKPORT_I_CLK 0x205c +#define CLK_CON_GAT_GOUT_BLK_APM_UID_LHS_AXI_D_APM_IPCLKPORT_I_CLK 0x2060 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_LHS_AXI_G_DBGCORE_IPCLKPORT_I_CLK 0x2064 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_LHS_AXI_G_SCAN2DRAM_IPCLKPORT_I_CLK 0x2068 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_MAILBOX_APM_AOC_IPCLKPORT_PCLK 0x206c +#define CLK_CON_GAT_GOUT_BLK_APM_UID_MAILBOX_APM_AP_IPCLKPORT_PCLK 0x2070 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_MAILBOX_APM_GSA_IPCLKPORT_PCLK 0x2074 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_MAILBOX_APM_SWD_IPCLKPORT_PCLK 0x207c +#define CLK_CON_GAT_GOUT_BLK_APM_UID_MAILBOX_APM_TPU_IPCLKPORT_PCLK 0x2080 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_MAILBOX_AP_AOC_IPCLKPORT_PCLK 0x2084 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_MAILBOX_AP_DBGCORE_IPCLKPORT_PCLK 0x2088 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_PMU_INTR_GEN_IPCLKPORT_PCLK 0x208c +#define CLK_CON_GAT_GOUT_BLK_APM_UID_ROM_CRC32_HOST_IPCLKPORT_ACLK 0x2090 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_ROM_CRC32_HOST_IPCLKPORT_PCLK 0x2094 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_RSTNSYNC_CLK_APM_BUS_IPCLKPORT_CLK 0x2098 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_RSTNSYNC_CLK_APM_USI0_UART_IPCLKPORT_CLK 0x209c +#define CLK_CON_GAT_GOUT_BLK_APM_UID_RSTNSYNC_CLK_APM_USI0_USI_IPCLKPORT_CLK 0x20a0 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_RSTNSYNC_CLK_APM_USI1_UART_IPCLKPORT_CLK 0x20a4 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_SPEEDY_APM_IPCLKPORT_PCLK 0x20a8 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_SPEEDY_SUB_APM_IPCLKPORT_PCLK 0x20ac +#define CLK_CON_GAT_GOUT_BLK_APM_UID_SSMT_D_APM_IPCLKPORT_ACLK 0x20b0 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_SSMT_D_APM_IPCLKPORT_PCLK 0x20b4 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_SSMT_G_DBGCORE_IPCLKPORT_ACLK 0x20b8 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_SSMT_G_DBGCORE_IPCLKPORT_PCLK 0x20bc +#define CLK_CON_GAT_GOUT_BLK_APM_UID_SS_DBGCORE_IPCLKPORT_SS_DBGCORE_IPCLKPORT_HCLK 0x20c0 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_SYSMMU_D_APM_IPCLKPORT_CLK_S2 0x20c4 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_SYSREG_APM_IPCLKPORT_PCLK 0x20cc +#define CLK_CON_GAT_GOUT_BLK_APM_UID_UASC_APM_IPCLKPORT_ACLK 0x20d0 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_UASC_APM_IPCLKPORT_PCLK 0x20d4 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_UASC_DBGCORE_IPCLKPORT_ACLK 0x20d8 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_UASC_DBGCORE_IPCLKPORT_PCLK 0x20dc +#define CLK_CON_GAT_GOUT_BLK_APM_UID_UASC_G_SWD_IPCLKPORT_ACLK 0x20e0 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_UASC_G_SWD_IPCLKPORT_PCLK 0x20e4 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_UASC_P_AOCAPM_IPCLKPORT_ACLK 0x20e8 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_UASC_P_AOCAPM_IPCLKPORT_PCLK 0x20ec +#define CLK_CON_GAT_GOUT_BLK_APM_UID_UASC_P_APM_IPCLKPORT_ACLK 0x20f0 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_UASC_P_APM_IPCLKPORT_PCLK 0x20f4 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_WDT_APM_IPCLKPORT_PCLK 0x20f8 +#define CLK_CON_GAT_GOUT_BLK_APM_UID_XIU_DP_APM_IPCLKPORT_ACLK 0x20fc +#define PCH_CON_LHM_AXI_G_SWD_PCH 0x3000 +#define PCH_CON_LHM_AXI_P_AOCAPM_PCH 0x3004 +#define PCH_CON_LHM_AXI_P_APM_PCH 0x3008 +#define PCH_CON_LHS_AXI_D_APM_PCH 0x300c +#define PCH_CON_LHS_AXI_G_DBGCORE_PCH 0x3010 +#define PCH_CON_LHS_AXI_G_SCAN2DRAM_PCH 0x3014 +#define QCH_CON_APBIF_GPIO_ALIVE_QCH 0x3018 +#define QCH_CON_APBIF_GPIO_FAR_ALIVE_QCH 0x301c +#define QCH_CON_APBIF_PMU_ALIVE_QCH 0x3020 +#define QCH_CON_APBIF_RTC_QCH 0x3024 +#define QCH_CON_APBIF_TRTC_QCH 0x3028 +#define QCH_CON_APM_CMU_APM_QCH 0x302c +#define QCH_CON_APM_USI0_UART_QCH 0x3030 +#define QCH_CON_APM_USI0_USI_QCH 0x3034 +#define QCH_CON_APM_USI1_UART_QCH 0x3038 +#define QCH_CON_D_TZPC_APM_QCH 0x303c +#define QCH_CON_GPC_APM_QCH 0x3040 +#define QCH_CON_GREBEINTEGRATION_QCH_DBG 0x3044 +#define QCH_CON_GREBEINTEGRATION_QCH_GREBE 0x3048 +#define QCH_CON_INTMEM_QCH 0x304c +#define QCH_CON_LHM_AXI_G_SWD_QCH 0x3050 +#define QCH_CON_LHM_AXI_P_AOCAPM_QCH 0x3054 +#define QCH_CON_LHM_AXI_P_APM_QCH 0x3058 +#define QCH_CON_LHS_AXI_D_APM_QCH 0x305c +#define QCH_CON_LHS_AXI_G_DBGCORE_QCH 0x3060 +#define QCH_CON_LHS_AXI_G_SCAN2DRAM_QCH 0x3064 +#define QCH_CON_MAILBOX_APM_AOC_QCH 0x3068 +#define QCH_CON_MAILBOX_APM_AP_QCH 0x306c +#define QCH_CON_MAILBOX_APM_GSA_QCH 0x3070 +#define QCH_CON_MAILBOX_APM_SWD_QCH 0x3078 +#define QCH_CON_MAILBOX_APM_TPU_QCH 0x307c +#define QCH_CON_MAILBOX_AP_AOC_QCH 0x3080 +#define QCH_CON_MAILBOX_AP_DBGCORE_QCH 0x3084 +#define QCH_CON_PMU_INTR_GEN_QCH 0x3088 +#define QCH_CON_ROM_CRC32_HOST_QCH 0x308c +#define QCH_CON_RSTNSYNC_CLK_APM_BUS_QCH_GREBE 0x3090 +#define QCH_CON_RSTNSYNC_CLK_APM_BUS_QCH_GREBE_DBG 0x3094 +#define QCH_CON_SPEEDY_APM_QCH 0x3098 +#define QCH_CON_SPEEDY_SUB_APM_QCH 0x309c +#define QCH_CON_SSMT_D_APM_QCH 0x30a0 +#define QCH_CON_SSMT_G_DBGCORE_QCH 0x30a4 +#define QCH_CON_SS_DBGCORE_QCH_DBG 0x30a8 +#define QCH_CON_SS_DBGCORE_QCH_GREBE 0x30ac +#define QCH_CON_SYSMMU_D_APM_QCH 0x30b0 +#define QCH_CON_SYSREG_APM_QCH 0x30b8 +#define QCH_CON_UASC_APM_QCH 0x30bc +#define QCH_CON_UASC_DBGCORE_QCH 0x30c0 +#define QCH_CON_UASC_G_SWD_QCH 0x30c4 +#define QCH_CON_UASC_P_AOCAPM_QCH 0x30c8 +#define QCH_CON_UASC_P_APM_QCH 0x30cc +#define QCH_CON_WDT_APM_QCH 0x30d0 +#define QUEUE_CTRL_REG_BLK_APM_CMU_APM 0x3c00 + +static const unsigned long apm_clk_regs[] __initconst = { + APM_CMU_APM_CONTROLLER_OPTION, + CLKOUT_CON_BLK_APM_CMU_APM_CLKOUT0, + CLK_CON_MUX_MUX_CLKCMU_APM_FUNC, + CLK_CON_MUX_MUX_CLKCMU_APM_FUNCSRC, + CLK_CON_DIV_DIV_CLK_APM_BOOST, + CLK_CON_DIV_DIV_CLK_APM_USI0_UART, + CLK_CON_DIV_DIV_CLK_APM_USI0_USI, + CLK_CON_DIV_DIV_CLK_APM_USI1_UART, + CLK_CON_GAT_CLK_BLK_APM_UID_APM_CMU_APM_IPCLKPORT_PCLK, + CLK_CON_GAT_CLK_BUS0_BOOST_OPTION1, + CLK_CON_GAT_CLK_CMU_BOOST_OPTION1, + CLK_CON_GAT_CLK_CORE_BOOST_OPTION1, + CLK_CON_GAT_GATE_CLKCMU_APM_FUNC, + CLK_CON_GAT_GOUT_BLK_APM_UID_APBIF_GPIO_ALIVE_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_APBIF_GPIO_FAR_ALIVE_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_APBIF_PMU_ALIVE_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_APBIF_RTC_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_APBIF_TRTC_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_APM_USI0_UART_IPCLKPORT_IPCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_APM_USI0_UART_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_APM_USI0_USI_IPCLKPORT_IPCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_APM_USI0_USI_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_APM_USI1_UART_IPCLKPORT_IPCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_APM_USI1_UART_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_D_TZPC_APM_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_GPC_APM_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_GREBEINTEGRATION_IPCLKPORT_HCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_INTMEM_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_INTMEM_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_LHM_AXI_G_SWD_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_LHM_AXI_P_AOCAPM_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_LHM_AXI_P_APM_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_LHS_AXI_D_APM_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_LHS_AXI_G_DBGCORE_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_LHS_AXI_G_SCAN2DRAM_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_MAILBOX_APM_AOC_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_MAILBOX_APM_AP_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_MAILBOX_APM_GSA_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_MAILBOX_APM_SWD_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_MAILBOX_APM_TPU_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_MAILBOX_AP_AOC_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_MAILBOX_AP_DBGCORE_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_PMU_INTR_GEN_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_ROM_CRC32_HOST_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_ROM_CRC32_HOST_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_RSTNSYNC_CLK_APM_BUS_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_RSTNSYNC_CLK_APM_USI0_UART_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_RSTNSYNC_CLK_APM_USI0_USI_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_RSTNSYNC_CLK_APM_USI1_UART_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_SPEEDY_APM_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_SPEEDY_SUB_APM_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_SSMT_D_APM_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_SSMT_D_APM_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_SSMT_G_DBGCORE_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_SSMT_G_DBGCORE_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_SS_DBGCORE_IPCLKPORT_SS_DBGCORE_IPCLKPORT_HCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_SYSMMU_D_APM_IPCLKPORT_CLK_S2, + CLK_CON_GAT_GOUT_BLK_APM_UID_SYSREG_APM_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_UASC_APM_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_UASC_APM_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_UASC_DBGCORE_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_UASC_DBGCORE_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_UASC_G_SWD_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_UASC_G_SWD_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_UASC_P_AOCAPM_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_UASC_P_AOCAPM_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_UASC_P_APM_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_UASC_P_APM_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_WDT_APM_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_APM_UID_XIU_DP_APM_IPCLKPORT_ACLK, +}; + +PNAME(mout_apm_func_p) = { "oscclk", "mout_apm_funcsrc", + "pad_clk_apm", "oscclk" }; +PNAME(mout_apm_funcsrc_p) = { "pll_alv_div2_apm", "pll_alv_div4_apm", + "pll_alv_div16_apm" }; + +static const struct samsung_fixed_rate_clock apm_fixed_clks[] __initconst = { + FRATE(CLK_APM_PLL_DIV2_APM, "pll_alv_div2_apm", NULL, 0, 393216000), + FRATE(CLK_APM_PLL_DIV4_APM, "pll_alv_div4_apm", NULL, 0, 196608000), + FRATE(CLK_APM_PLL_DIV16_APM, "pll_alv_div16_apm", NULL, 0, 49152000), +}; + +static const struct samsung_mux_clock apm_mux_clks[] __initconst = { + MUX(CLK_MOUT_APM_FUNC, "mout_apm_func", mout_apm_func_p, + CLK_CON_MUX_MUX_CLKCMU_APM_FUNC, 4, 1), + MUX(CLK_MOUT_APM_FUNCSRC, "mout_apm_funcsrc", mout_apm_funcsrc_p, + CLK_CON_MUX_MUX_CLKCMU_APM_FUNCSRC, 3, 1), +}; + +static const struct samsung_div_clock apm_div_clks[] __initconst = { + DIV(CLK_DOUT_APM_BOOST, "dout_apm_boost", "gout_apm_func", + CLK_CON_DIV_DIV_CLK_APM_BOOST, 0, 1), + DIV(CLK_DOUT_APM_USI0_UART, "dout_apm_usi0_uart", "gout_apm_func", + CLK_CON_DIV_DIV_CLK_APM_USI0_UART, 0, 7), + DIV(CLK_DOUT_APM_USI0_USI, "dout_apm_usi0_usi", "gout_apm_func", + CLK_CON_DIV_DIV_CLK_APM_USI0_USI, 0, 7), + DIV(CLK_DOUT_APM_USI1_UART, "dout_apm_usi1_uart", "gout_apm_func", + CLK_CON_DIV_DIV_CLK_APM_USI1_UART, 0, 7), +}; + +static const struct samsung_gate_clock apm_gate_clks[] __initconst = { + GATE(CLK_GOUT_APM_APM_CMU_APM_PCLK, + "gout_apm_apm_cmu_apm_pclk", "mout_apm_func", + CLK_CON_GAT_CLK_BLK_APM_UID_APM_CMU_APM_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_BUS0_BOOST_OPTION1, "gout_bus0_boost_option1", + "dout_apm_boost", CLK_CON_GAT_CLK_BUS0_BOOST_OPTION1, 21, 0, 0), + GATE(CLK_GOUT_CMU_BOOST_OPTION1, "gout_cmu_boost_option1", + "dout_apm_boost", CLK_CON_GAT_CLK_CMU_BOOST_OPTION1, 21, 0, 0), + GATE(CLK_GOUT_CORE_BOOST_OPTION1, "gout_core_boost_option1", + "dout_apm_boost", CLK_CON_GAT_CLK_CORE_BOOST_OPTION1, 21, 0, 0), + GATE(CLK_GOUT_APM_FUNC, "gout_apm_func", "mout_apm_func", + CLK_CON_GAT_GATE_CLKCMU_APM_FUNC, 21, 0, 0), + GATE(CLK_GOUT_APM_APBIF_GPIO_ALIVE_PCLK, + "gout_apm_apbif_gpio_alive_pclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_APBIF_GPIO_ALIVE_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_APBIF_GPIO_FAR_ALIVE_PCLK, + "gout_apm_apbif_gpio_far_alive_pclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_APBIF_GPIO_FAR_ALIVE_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_APBIF_PMU_ALIVE_PCLK, + "gout_apm_apbif_pmu_alive_pclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_APBIF_PMU_ALIVE_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_APBIF_RTC_PCLK, + "gout_apm_apbif_rtc_pclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_APBIF_RTC_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_APM_APBIF_TRTC_PCLK, + "gout_apm_apbif_trtc_pclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_APBIF_TRTC_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_APM_APM_USI0_UART_IPCLK, + "gout_apm_apm_usi0_uart_ipclk", "dout_apm_usi0_uart", + CLK_CON_GAT_GOUT_BLK_APM_UID_APM_USI0_UART_IPCLKPORT_IPCLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_APM_USI0_UART_PCLK, + "gout_apm_apm_usi0_uart_pclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_APM_USI0_UART_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_APM_USI0_USI_IPCLK, + "gout_apm_apm_usi0_usi_ipclk", "dout_apm_usi0_usi", + CLK_CON_GAT_GOUT_BLK_APM_UID_APM_USI0_USI_IPCLKPORT_IPCLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_APM_USI0_USI_PCLK, + "gout_apm_apm_usi0_usi_pclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_APM_USI0_USI_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_APM_USI1_UART_IPCLK, + "gout_apm_apm_usi1_uart_ipclk", "dout_apm_usi1_uart", + CLK_CON_GAT_GOUT_BLK_APM_UID_APM_USI1_UART_IPCLKPORT_IPCLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_APM_USI1_UART_PCLK, + "gout_apm_apm_usi1_uart_pclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_APM_USI1_UART_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_D_TZPC_APM_PCLK, + "gout_apm_d_tzpc_apm_pclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_D_TZPC_APM_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_APM_GPC_APM_PCLK, + "gout_apm_gpc_apm_pclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_GPC_APM_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_APM_GREBEINTEGRATION_HCLK, + "gout_apm_grebeintegration_hclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_GREBEINTEGRATION_IPCLKPORT_HCLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_INTMEM_ACLK, + "gout_apm_intmem_aclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_INTMEM_IPCLKPORT_ACLK, 21, 0, 0), + GATE(CLK_GOUT_APM_INTMEM_PCLK, + "gout_apm_intmem_pclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_INTMEM_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_APM_LHM_AXI_G_SWD_I_CLK, + "gout_apm_lhm_axi_g_swd_i_clk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_LHM_AXI_G_SWD_IPCLKPORT_I_CLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_LHM_AXI_P_AOCAPM_I_CLK, + "gout_apm_lhm_axi_p_aocapm_i_clk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_LHM_AXI_P_AOCAPM_IPCLKPORT_I_CLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_LHM_AXI_P_APM_I_CLK, + "gout_apm_lhm_axi_p_apm_i_clk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_LHS_AXI_D_APM_IPCLKPORT_I_CLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_LHS_AXI_D_APM_I_CLK, + "gout_apm_lhs_axi_d_apm_i_clk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_LHS_AXI_D_APM_IPCLKPORT_I_CLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_LHS_AXI_G_DBGCORE_I_CLK, + "gout_apm_lhs_axi_g_dbgcore_i_clk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_LHS_AXI_G_DBGCORE_IPCLKPORT_I_CLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_LHS_AXI_G_SCAN2DRAM_I_CLK, + "gout_apm_lhs_axi_g_scan2dram_i_clk", + "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_LHS_AXI_G_SCAN2DRAM_IPCLKPORT_I_CLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_MAILBOX_APM_AOC_PCLK, + "gout_apm_mailbox_apm_aoc_pclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_MAILBOX_APM_AOC_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_MAILBOX_APM_AP_PCLK, + "gout_apm_mailbox_apm_ap_pclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_MAILBOX_APM_AP_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_MAILBOX_APM_GSA_PCLK, + "gout_apm_mailbox_apm_gsa_pclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_MAILBOX_APM_GSA_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_MAILBOX_APM_SWD_PCLK, + "gout_apm_mailbox_apm_swd_pclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_MAILBOX_APM_SWD_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_MAILBOX_APM_TPU_PCLK, + "gout_apm_mailbox_apm_tpu_pclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_MAILBOX_APM_TPU_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_MAILBOX_AP_AOC_PCLK, + "gout_apm_mailbox_ap_aoc_pclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_MAILBOX_AP_AOC_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_MAILBOX_AP_DBGCORE_PCLK, + "gout_apm_mailbox_ap_dbgcore_pclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_MAILBOX_AP_DBGCORE_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_PMU_INTR_GEN_PCLK, + "gout_apm_pmu_intr_gen_pclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_PMU_INTR_GEN_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_ROM_CRC32_HOST_ACLK, + "gout_apm_rom_crc32_host_aclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_ROM_CRC32_HOST_IPCLKPORT_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_ROM_CRC32_HOST_PCLK, + "gout_apm_rom_crc32_host_pclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_ROM_CRC32_HOST_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_CLK_APM_BUS_CLK, + "gout_apm_clk_apm_bus_clk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_RSTNSYNC_CLK_APM_BUS_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_CLK_APM_USI0_UART_CLK, + "gout_apm_clk_apm_usi0_uart_clk", + "dout_apm_usi0_uart", + CLK_CON_GAT_GOUT_BLK_APM_UID_RSTNSYNC_CLK_APM_USI0_UART_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_CLK_APM_USI0_USI_CLK, + "gout_apm_clk_apm_usi0_usi_clk", + "dout_apm_usi0_usi", + CLK_CON_GAT_GOUT_BLK_APM_UID_RSTNSYNC_CLK_APM_USI0_UART_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_CLK_APM_USI1_UART_CLK, + "gout_apm_clk_apm_usi1_uart_clk", + "dout_apm_usi1_uart", + CLK_CON_GAT_GOUT_BLK_APM_UID_RSTNSYNC_CLK_APM_USI1_UART_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_SPEEDY_APM_PCLK, + "gout_apm_speedy_apm_pclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_SPEEDY_APM_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_APM_SPEEDY_SUB_APM_PCLK, + "gout_apm_speedy_sub_apm_pclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_SPEEDY_SUB_APM_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_SSMT_D_APM_ACLK, + "gout_apm_ssmt_d_apm_aclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_SSMT_D_APM_IPCLKPORT_ACLK, 21, 0, 0), + GATE(CLK_GOUT_APM_SSMT_D_APM_PCLK, + "gout_apm_ssmt_d_apm_pclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_SSMT_D_APM_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_APM_SSMT_G_DBGCORE_ACLK, + "gout_apm_ssmt_g_dbgcore_aclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_SSMT_G_DBGCORE_IPCLKPORT_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_SSMT_G_DBGCORE_PCLK, + "gout_apm_ssmt_g_dbgcore_pclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_SSMT_G_DBGCORE_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_SS_DBGCORE_SS_DBGCORE_HCLK, + "gout_apm_ss_dbgcore_ss_dbgcore_hclk", + "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_SS_DBGCORE_IPCLKPORT_SS_DBGCORE_IPCLKPORT_HCLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_SYSMMU_D_APM_CLK_S2, + "gout_apm_sysmmu_d_dpm_clk_s2", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_SYSMMU_D_APM_IPCLKPORT_CLK_S2, + 21, 0, 0), + GATE(CLK_GOUT_APM_SYSREG_APM_PCLK, + "gout_apm_sysreg_apm_pclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_SYSREG_APM_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_APM_UASC_APM_ACLK, + "gout_apm_uasc_apm_aclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_UASC_APM_IPCLKPORT_ACLK, 21, 0, 0), + GATE(CLK_GOUT_APM_UASC_APM_PCLK, + "gout_apm_uasc_apm_pclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_UASC_APM_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_APM_UASC_DBGCORE_ACLK, + "gout_apm_uasc_dbgcore_aclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_UASC_DBGCORE_IPCLKPORT_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_UASC_DBGCORE_PCLK, + "gout_apm_uasc_dbgcore_pclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_UASC_DBGCORE_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_UASC_G_SWD_ACLK, + "gout_apm_uasc_g_swd_aclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_UASC_G_SWD_IPCLKPORT_ACLK, 21, 0, 0), + GATE(CLK_GOUT_APM_UASC_G_SWD_PCLK, + "gout_apm_uasc_g_swd_pclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_UASC_G_SWD_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_APM_UASC_P_AOCAPM_ACLK, + "gout_apm_uasc_p_aocapm_aclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_UASC_P_AOCAPM_IPCLKPORT_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_APM_UASC_P_AOCAPM_PCLK, + "gout_apm_uasc_p_aocapm_pclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_UASC_G_SWD_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_APM_UASC_P_APM_ACLK, + "gout_apm_uasc_p_apm_aclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_UASC_P_APM_IPCLKPORT_ACLK, 21, 0, 0), + GATE(CLK_GOUT_APM_UASC_P_APM_PCLK, + "gout_apm_uasc_p_apm_pclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_UASC_P_APM_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_APM_WDT_APM_PCLK, + "gout_apm_wdt_apm_pclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_WDT_APM_IPCLKPORT_PCLK, 21, 0, 0), + GATE(CLK_GOUT_APM_XIU_DP_APM_ACLK, + "gout_apm_xiu_dp_apm_aclk", "gout_apm_func", + CLK_CON_GAT_GOUT_BLK_APM_UID_XIU_DP_APM_IPCLKPORT_ACLK, 21, 0, 0), +}; + +static const struct samsung_cmu_info apm_cmu_info __initconst = { + .mux_clks = apm_mux_clks, + .nr_mux_clks = ARRAY_SIZE(apm_mux_clks), + .div_clks = apm_div_clks, + .nr_div_clks = ARRAY_SIZE(apm_div_clks), + .gate_clks = apm_gate_clks, + .nr_gate_clks = ARRAY_SIZE(apm_gate_clks), + .fixed_clks = apm_fixed_clks, + .nr_fixed_clks = ARRAY_SIZE(apm_fixed_clks), + .nr_clk_ids = CLKS_NR_APM, + .clk_regs = apm_clk_regs, + .nr_clk_regs = ARRAY_SIZE(apm_clk_regs), +}; + +/* ---- CMU_MISC ------------------------------------------------------------ */ + +/* Register Offset definitions for CMU_MISC (0x10010000) */ +#define PLL_CON0_MUX_CLKCMU_MISC_BUS_USER 0x0600 +#define PLL_CON1_MUX_CLKCMU_MISC_BUS_USER 0x0604 +#define PLL_CON0_MUX_CLKCMU_MISC_SSS_USER 0x0610 +#define PLL_CON1_MUX_CLKCMU_MISC_SSS_USER 0x0614 +#define MISC_CMU_MISC_CONTROLLER_OPTION 0x0800 +#define CLKOUT_CON_BLK_MISC_CMU_MISC_CLKOUT0 0x0810 +#define CLK_CON_MUX_MUX_CLK_MISC_GIC 0x1000 +#define CLK_CON_DIV_DIV_CLK_MISC_BUSP 0x1800 +#define CLK_CON_DIV_DIV_CLK_MISC_GIC 0x1804 +#define CLK_CON_GAT_CLK_BLK_MISC_UID_MISC_CMU_MISC_IPCLKPORT_PCLK 0x2000 +#define CLK_CON_GAT_CLK_BLK_MISC_UID_OTP_CON_BIRA_IPCLKPORT_I_OSCCLK 0x2004 +#define CLK_CON_GAT_CLK_BLK_MISC_UID_OTP_CON_BISR_IPCLKPORT_I_OSCCLK 0x2008 +#define CLK_CON_GAT_CLK_BLK_MISC_UID_OTP_CON_TOP_IPCLKPORT_I_OSCCLK 0x200c +#define CLK_CON_GAT_CLK_BLK_MISC_UID_RSTNSYNC_CLK_MISC_OSCCLK_IPCLKPORT_CLK 0x2010 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_ADM_AHB_SSS_IPCLKPORT_HCLKM 0x2014 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_AD_APB_DIT_IPCLKPORT_PCLKM 0x2018 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_AD_APB_PUF_IPCLKPORT_PCLKM 0x201c +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_DIT_IPCLKPORT_ICLKL2A 0x2020 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_D_TZPC_MISC_IPCLKPORT_PCLK 0x2024 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_GIC_IPCLKPORT_GICCLK 0x2028 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_GPC_MISC_IPCLKPORT_PCLK 0x202c +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_LHM_AST_ICC_CPUGIC_IPCLKPORT_I_CLK 0x2030 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_LHM_AXI_D_SSS_IPCLKPORT_I_CLK 0x2034 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_LHM_AXI_P_GIC_IPCLKPORT_I_CLK 0x2038 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_LHM_AXI_P_MISC_IPCLKPORT_I_CLK 0x203c +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_LHS_ACEL_D_MISC_IPCLKPORT_I_CLK 0x2040 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_LHS_AST_IRI_GICCPU_IPCLKPORT_I_CLK 0x2044 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_LHS_AXI_D_SSS_IPCLKPORT_I_CLK 0x2048 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_MCT_IPCLKPORT_PCLK 0x204c +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_OTP_CON_BIRA_IPCLKPORT_PCLK 0x2050 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_OTP_CON_BISR_IPCLKPORT_PCLK 0x2054 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_OTP_CON_TOP_IPCLKPORT_PCLK 0x2058 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_PDMA_IPCLKPORT_ACLK 0x205c +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_PPMU_DMA_IPCLKPORT_ACLK 0x2060 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_PPMU_MISC_IPCLKPORT_ACLK 0x2064 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_PPMU_MISC_IPCLKPORT_PCLK 0x2068 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_PUF_IPCLKPORT_I_CLK 0x206c +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_DIT_IPCLKPORT_ACLK 0x2070 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_DIT_IPCLKPORT_PCLK 0x2074 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_PDMA_IPCLKPORT_ACLK 0x2078 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_PDMA_IPCLKPORT_PCLK 0x207c +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_PPMU_DMA_IPCLKPORT_ACLK 0x2080 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_PPMU_DMA_IPCLKPORT_PCLK 0x2084 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_RTIC_IPCLKPORT_ACLK 0x2088 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_RTIC_IPCLKPORT_PCLK 0x208c +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_SPDMA_IPCLKPORT_ACLK 0x2090 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_SPDMA_IPCLKPORT_PCLK 0x2094 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_SSS_IPCLKPORT_ACLK 0x2098 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_SSS_IPCLKPORT_PCLK 0x209c +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_RSTNSYNC_CLK_MISC_BUSD_IPCLKPORT_CLK 0x20a0 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_RSTNSYNC_CLK_MISC_BUSP_IPCLKPORT_CLK 0x20a4 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_RSTNSYNC_CLK_MISC_GIC_IPCLKPORT_CLK 0x20a8 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_RSTNSYNC_CLK_MISC_SSS_IPCLKPORT_CLK 0x20ac +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_RTIC_IPCLKPORT_I_ACLK 0x20b0 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_RTIC_IPCLKPORT_I_PCLK 0x20b4 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_SPDMA_IPCLKPORT_ACLK 0x20b8 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_DIT_IPCLKPORT_ACLK 0x20bc +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_DIT_IPCLKPORT_PCLK 0x20c0 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_PDMA_IPCLKPORT_ACLK 0x20c4 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_PDMA_IPCLKPORT_PCLK 0x20c8 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_PPMU_DMA_IPCLKPORT_ACLK 0x20cc +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_PPMU_DMA_IPCLKPORT_PCLK 0x20d0 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_RTIC_IPCLKPORT_ACLK 0x20d4 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_RTIC_IPCLKPORT_PCLK 0x20d8 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_SPDMA_IPCLKPORT_ACLK 0x20dc +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_SPDMA_IPCLKPORT_PCLK 0x20e0 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_SSS_IPCLKPORT_ACLK 0x20e4 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_SSS_IPCLKPORT_PCLK 0x20e8 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_SSS_IPCLKPORT_I_ACLK 0x20ec +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_SSS_IPCLKPORT_I_PCLK 0x20f0 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_SYSMMU_MISC_IPCLKPORT_CLK_S2 0x20f4 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_SYSMMU_SSS_IPCLKPORT_CLK_S1 0x20f8 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_SYSREG_MISC_IPCLKPORT_PCLK 0x20fc +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_TMU_SUB_IPCLKPORT_PCLK 0x2100 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_TMU_TOP_IPCLKPORT_PCLK 0x2104 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_WDT_CLUSTER0_IPCLKPORT_PCLK 0x2108 +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_WDT_CLUSTER1_IPCLKPORT_PCLK 0x210c +#define CLK_CON_GAT_GOUT_BLK_MISC_UID_XIU_D_MISC_IPCLKPORT_ACLK 0x2110 +#define DMYQCH_CON_PPMU_DMA_QCH 0x3000 +#define DMYQCH_CON_PUF_QCH 0x3004 +#define PCH_CON_LHM_AXI_D_SSS_PCH 0x300c +#define PCH_CON_LHM_AXI_P_GIC_PCH 0x3010 +#define PCH_CON_LHM_AXI_P_MISC_PCH 0x3014 +#define PCH_CON_LHS_ACEL_D_MISC_PCH 0x3018 +#define PCH_CON_LHS_AST_IRI_GICCPU_PCH 0x301c +#define PCH_CON_LHS_AXI_D_SSS_PCH 0x3020 +#define QCH_CON_ADM_AHB_SSS_QCH 0x3024 +#define QCH_CON_DIT_QCH 0x3028 +#define QCH_CON_GIC_QCH 0x3030 +#define QCH_CON_LHM_AST_ICC_CPUGIC_QCH 0x3038 +#define QCH_CON_LHM_AXI_D_SSS_QCH 0x303c +#define QCH_CON_LHM_AXI_P_GIC_QCH 0x3040 +#define QCH_CON_LHM_AXI_P_MISC_QCH 0x3044 +#define QCH_CON_LHS_ACEL_D_MISC_QCH 0x3048 +#define QCH_CON_LHS_AST_IRI_GICCPU_QCH 0x304c +#define QCH_CON_LHS_AXI_D_SSS_QCH 0x3050 +#define QCH_CON_MCT_QCH 0x3054 +#define QCH_CON_MISC_CMU_MISC_QCH 0x3058 +#define QCH_CON_OTP_CON_BIRA_QCH 0x305c +#define QCH_CON_OTP_CON_BISR_QCH 0x3060 +#define QCH_CON_OTP_CON_TOP_QCH 0x3064 +#define QCH_CON_PDMA_QCH 0x3068 +#define QCH_CON_PPMU_MISC_QCH 0x306c +#define QCH_CON_QE_DIT_QCH 0x3070 +#define QCH_CON_QE_PDMA_QCH 0x3074 +#define QCH_CON_QE_PPMU_DMA_QCH 0x3078 +#define QCH_CON_QE_RTIC_QCH 0x307c +#define QCH_CON_QE_SPDMA_QCH 0x3080 +#define QCH_CON_QE_SSS_QCH 0x3084 +#define QCH_CON_RTIC_QCH 0x3088 +#define QCH_CON_SPDMA_QCH 0x308c +#define QCH_CON_SSMT_DIT_QCH 0x3090 +#define QCH_CON_SSMT_PDMA_QCH 0x3094 +#define QCH_CON_SSMT_PPMU_DMA_QCH 0x3098 +#define QCH_CON_SSMT_RTIC_QCH 0x309c +#define QCH_CON_SSMT_SPDMA_QCH 0x30a0 +#define QCH_CON_SSMT_SSS_QCH 0x30a4 +#define QCH_CON_SSS_QCH 0x30a8 +#define QCH_CON_SYSMMU_MISC_QCH 0x30ac +#define QCH_CON_SYSMMU_SSS_QCH 0x30b0 +#define QCH_CON_SYSREG_MISC_QCH 0x30b4 +#define QCH_CON_TMU_SUB_QCH 0x30b8 +#define QCH_CON_TMU_TOP_QCH 0x30bc +#define QCH_CON_WDT_CLUSTER0_QCH 0x30c0 +#define QCH_CON_WDT_CLUSTER1_QCH 0x30c4 +#define QUEUE_CTRL_REG_BLK_MISC_CMU_MISC 0x3c00 + +static const unsigned long misc_clk_regs[] __initconst = { + PLL_CON0_MUX_CLKCMU_MISC_BUS_USER, + PLL_CON1_MUX_CLKCMU_MISC_BUS_USER, + PLL_CON0_MUX_CLKCMU_MISC_SSS_USER, + PLL_CON1_MUX_CLKCMU_MISC_SSS_USER, + MISC_CMU_MISC_CONTROLLER_OPTION, + CLKOUT_CON_BLK_MISC_CMU_MISC_CLKOUT0, + CLK_CON_MUX_MUX_CLK_MISC_GIC, + CLK_CON_DIV_DIV_CLK_MISC_BUSP, + CLK_CON_DIV_DIV_CLK_MISC_GIC, + CLK_CON_GAT_CLK_BLK_MISC_UID_MISC_CMU_MISC_IPCLKPORT_PCLK, + CLK_CON_GAT_CLK_BLK_MISC_UID_OTP_CON_BIRA_IPCLKPORT_I_OSCCLK, + CLK_CON_GAT_CLK_BLK_MISC_UID_OTP_CON_BISR_IPCLKPORT_I_OSCCLK, + CLK_CON_GAT_CLK_BLK_MISC_UID_OTP_CON_TOP_IPCLKPORT_I_OSCCLK, + CLK_CON_GAT_CLK_BLK_MISC_UID_RSTNSYNC_CLK_MISC_OSCCLK_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_ADM_AHB_SSS_IPCLKPORT_HCLKM, + CLK_CON_GAT_GOUT_BLK_MISC_UID_AD_APB_DIT_IPCLKPORT_PCLKM, + CLK_CON_GAT_GOUT_BLK_MISC_UID_AD_APB_PUF_IPCLKPORT_PCLKM, + CLK_CON_GAT_GOUT_BLK_MISC_UID_DIT_IPCLKPORT_ICLKL2A, + CLK_CON_GAT_GOUT_BLK_MISC_UID_D_TZPC_MISC_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_GIC_IPCLKPORT_GICCLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_GPC_MISC_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_LHM_AST_ICC_CPUGIC_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_LHM_AXI_D_SSS_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_LHM_AXI_P_GIC_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_LHM_AXI_P_MISC_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_LHS_ACEL_D_MISC_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_LHS_AST_IRI_GICCPU_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_LHS_AXI_D_SSS_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_MCT_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_OTP_CON_BIRA_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_OTP_CON_BISR_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_OTP_CON_TOP_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_PDMA_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_PPMU_DMA_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_PPMU_MISC_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_PPMU_MISC_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_PUF_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_DIT_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_DIT_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_PDMA_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_PDMA_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_PPMU_DMA_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_PPMU_DMA_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_RTIC_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_RTIC_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_SPDMA_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_SPDMA_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_SSS_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_SSS_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_RSTNSYNC_CLK_MISC_BUSD_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_RSTNSYNC_CLK_MISC_BUSP_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_RSTNSYNC_CLK_MISC_GIC_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_RSTNSYNC_CLK_MISC_SSS_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_RTIC_IPCLKPORT_I_ACLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_RTIC_IPCLKPORT_I_PCLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_SPDMA_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_DIT_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_DIT_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_PDMA_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_PDMA_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_PPMU_DMA_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_PPMU_DMA_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_RTIC_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_RTIC_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_SPDMA_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_SPDMA_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_SSS_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_SSS_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_SSS_IPCLKPORT_I_ACLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_SSS_IPCLKPORT_I_PCLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_SYSMMU_MISC_IPCLKPORT_CLK_S2, + CLK_CON_GAT_GOUT_BLK_MISC_UID_SYSMMU_SSS_IPCLKPORT_CLK_S1, + CLK_CON_GAT_GOUT_BLK_MISC_UID_SYSREG_MISC_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_TMU_SUB_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_TMU_TOP_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_WDT_CLUSTER0_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_WDT_CLUSTER1_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_MISC_UID_XIU_D_MISC_IPCLKPORT_ACLK, + DMYQCH_CON_PPMU_DMA_QCH, + DMYQCH_CON_PUF_QCH, + PCH_CON_LHM_AXI_D_SSS_PCH, + PCH_CON_LHM_AXI_P_GIC_PCH, + PCH_CON_LHM_AXI_P_MISC_PCH, + PCH_CON_LHS_ACEL_D_MISC_PCH, + PCH_CON_LHS_AST_IRI_GICCPU_PCH, + PCH_CON_LHS_AXI_D_SSS_PCH, + QCH_CON_ADM_AHB_SSS_QCH, + QCH_CON_DIT_QCH, + QCH_CON_GIC_QCH, + QCH_CON_LHM_AST_ICC_CPUGIC_QCH, + QCH_CON_LHM_AXI_D_SSS_QCH, + QCH_CON_LHM_AXI_P_GIC_QCH, + QCH_CON_LHM_AXI_P_MISC_QCH, + QCH_CON_LHS_ACEL_D_MISC_QCH, + QCH_CON_LHS_AST_IRI_GICCPU_QCH, + QCH_CON_LHS_AXI_D_SSS_QCH, + QCH_CON_MCT_QCH, + QCH_CON_MISC_CMU_MISC_QCH, + QCH_CON_OTP_CON_BIRA_QCH, + QCH_CON_OTP_CON_BISR_QCH, + QCH_CON_OTP_CON_TOP_QCH, + QCH_CON_PDMA_QCH, + QCH_CON_PPMU_MISC_QCH, + QCH_CON_QE_DIT_QCH, + QCH_CON_QE_PDMA_QCH, + QCH_CON_QE_PPMU_DMA_QCH, + QCH_CON_QE_RTIC_QCH, + QCH_CON_QE_SPDMA_QCH, + QCH_CON_QE_SSS_QCH, + QCH_CON_RTIC_QCH, + QCH_CON_SPDMA_QCH, + QCH_CON_SSMT_DIT_QCH, + QCH_CON_SSMT_PDMA_QCH, + QCH_CON_SSMT_PPMU_DMA_QCH, + QCH_CON_SSMT_RTIC_QCH, + QCH_CON_SSMT_SPDMA_QCH, + QCH_CON_SSMT_SSS_QCH, + QCH_CON_SSS_QCH, + QCH_CON_SYSMMU_MISC_QCH, + QCH_CON_SYSMMU_SSS_QCH, + QCH_CON_SYSREG_MISC_QCH, + QCH_CON_TMU_SUB_QCH, + QCH_CON_TMU_TOP_QCH, + QCH_CON_WDT_CLUSTER0_QCH, + QCH_CON_WDT_CLUSTER1_QCH, + QUEUE_CTRL_REG_BLK_MISC_CMU_MISC, +}; + + /* List of parent clocks for Muxes in CMU_MISC */ +PNAME(mout_misc_bus_user_p) = { "oscclk", "dout_cmu_misc_bus" }; +PNAME(mout_misc_sss_user_p) = { "oscclk", "dout_cmu_misc_sss" }; +PNAME(mout_misc_gic_p) = { "dout_misc_gic", "oscclk" }; + +static const struct samsung_mux_clock misc_mux_clks[] __initconst = { + MUX(CLK_MOUT_MISC_BUS_USER, "mout_misc_bus_user", mout_misc_bus_user_p, + PLL_CON0_MUX_CLKCMU_MISC_BUS_USER, 4, 1), + MUX(CLK_MOUT_MISC_SSS_USER, "mout_misc_sss_user", mout_misc_sss_user_p, + PLL_CON0_MUX_CLKCMU_MISC_SSS_USER, 4, 1), + MUX(CLK_MOUT_MISC_GIC, "mout_misc_gic", mout_misc_gic_p, + CLK_CON_MUX_MUX_CLK_MISC_GIC, 0, 0), +}; + +static const struct samsung_div_clock misc_div_clks[] __initconst = { + DIV(CLK_DOUT_MISC_BUSP, "dout_misc_busp", "mout_misc_bus_user", + CLK_CON_DIV_DIV_CLK_MISC_BUSP, 0, 3), + DIV(CLK_DOUT_MISC_GIC, "dout_misc_gic", "mout_misc_bus_user", + CLK_CON_DIV_DIV_CLK_MISC_GIC, 0, 3), +}; + +static const struct samsung_gate_clock misc_gate_clks[] __initconst = { + GATE(CLK_GOUT_MISC_MISC_CMU_MISC_PCLK, + "gout_misc_misc_cmu_misc_pclk", "dout_misc_busp", + CLK_CON_GAT_CLK_BLK_MISC_UID_MISC_CMU_MISC_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_OTP_CON_BIRA_I_OSCCLK, + "gout_misc_otp_con_bira_i_oscclk", "oscclk", + CLK_CON_GAT_CLK_BLK_MISC_UID_OTP_CON_BIRA_IPCLKPORT_I_OSCCLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_OTP_CON_BISR_I_OSCCLK, + "gout_misc_otp_con_bisr_i_oscclk", "oscclk", + CLK_CON_GAT_CLK_BLK_MISC_UID_OTP_CON_BISR_IPCLKPORT_I_OSCCLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_OTP_CON_TOP_I_OSCCLK, + "gout_misc_otp_con_top_i_oscclk", "oscclk", + CLK_CON_GAT_CLK_BLK_MISC_UID_OTP_CON_TOP_IPCLKPORT_I_OSCCLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_CLK_MISC_OSCCLK_CLK, + "gout_misc_clk_misc_oscclk_clk", "oscclk", + CLK_CON_GAT_CLK_BLK_MISC_UID_RSTNSYNC_CLK_MISC_OSCCLK_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_ADM_AHB_SSS_HCLKM, + "gout_misc_adm_ahb_sss_hclkm", "mout_misc_sss_user", + CLK_CON_GAT_GOUT_BLK_MISC_UID_ADM_AHB_SSS_IPCLKPORT_HCLKM, + 21, 0, 0), + GATE(CLK_GOUT_MISC_AD_APB_DIT_PCLKM, + "gout_misc_ad_apb_dit_pclkm", "mout_misc_bus_user", + CLK_CON_GAT_GOUT_BLK_MISC_UID_AD_APB_DIT_IPCLKPORT_PCLKM, + 21, 0, 0), + GATE(CLK_GOUT_MISC_D_TZPC_MISC_PCLK, + "gout_misc_d_tzpc_misc_pclk", "dout_misc_busp", + CLK_CON_GAT_GOUT_BLK_MISC_UID_D_TZPC_MISC_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_GIC_GICCLK, + "gout_misc_gic_gicclk", "mout_misc_gic", + CLK_CON_GAT_GOUT_BLK_MISC_UID_GIC_IPCLKPORT_GICCLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_GPC_MISC_PCLK, + "gout_misc_gpc_misc_pclk", "dout_misc_busp", + CLK_CON_GAT_GOUT_BLK_MISC_UID_GPC_MISC_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_LHM_AST_ICC_CPUGIC_I_CLK, + "gout_misc_lhm_ast_icc_gpugic_i_clk", "mout_misc_gic", + CLK_CON_GAT_GOUT_BLK_MISC_UID_LHM_AST_ICC_CPUGIC_IPCLKPORT_I_CLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_LHM_AXI_D_SSS_I_CLK, + "gout_misc_lhm_axi_d_sss_i_clk", "mout_misc_bus_user", + CLK_CON_GAT_GOUT_BLK_MISC_UID_LHM_AXI_D_SSS_IPCLKPORT_I_CLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_LHM_AXI_P_GIC_I_CLK, + "gout_misc_lhm_axi_p_gic_i_clk", "mout_misc_gic", + CLK_CON_GAT_GOUT_BLK_MISC_UID_LHM_AXI_P_GIC_IPCLKPORT_I_CLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_LHM_AXI_P_MISC_I_CLK, + "gout_misc_lhm_axi_p_misc_i_clk", "dout_misc_busp", + CLK_CON_GAT_GOUT_BLK_MISC_UID_LHM_AXI_P_MISC_IPCLKPORT_I_CLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_LHS_ACEL_D_MISC_I_CLK, + "gout_misc_lhs_acel_d_misc_i_clk", "mout_misc_bus_user", + CLK_CON_GAT_GOUT_BLK_MISC_UID_LHS_ACEL_D_MISC_IPCLKPORT_I_CLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_LHS_AST_IRI_GICCPU_I_CLK, + "gout_misc_lhs_ast_iri_giccpu_i_clk", "mout_misc_gic", + CLK_CON_GAT_GOUT_BLK_MISC_UID_LHS_AST_IRI_GICCPU_IPCLKPORT_I_CLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_LHS_AXI_D_SSS_I_CLK, + "gout_misc_lhs_axi_d_sss_i_clk", "mout_misc_sss_user", + CLK_CON_GAT_GOUT_BLK_MISC_UID_LHS_AXI_D_SSS_IPCLKPORT_I_CLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_MCT_PCLK, "gout_misc_mct_pclk", + "dout_misc_busp", + CLK_CON_GAT_GOUT_BLK_MISC_UID_MCT_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_OTP_CON_BIRA_PCLK, + "gout_misc_otp_con_bira_pclk", "dout_misc_busp", + CLK_CON_GAT_GOUT_BLK_MISC_UID_OTP_CON_BIRA_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_OTP_CON_BISR_PCLK, + "gout_misc_otp_con_bisr_pclk", "dout_misc_busp", + CLK_CON_GAT_GOUT_BLK_MISC_UID_OTP_CON_BISR_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_OTP_CON_TOP_PCLK, + "gout_misc_otp_con_top_pclk", "dout_misc_busp", + CLK_CON_GAT_GOUT_BLK_MISC_UID_OTP_CON_TOP_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_PDMA_ACLK, "gout_misc_pdma_aclk", + "mout_misc_bus_user", + CLK_CON_GAT_GOUT_BLK_MISC_UID_PDMA_IPCLKPORT_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_PPMU_MISC_ACLK, + "gout_misc_ppmu_misc_aclk", "mout_misc_bus_user", + CLK_CON_GAT_GOUT_BLK_MISC_UID_PPMU_MISC_IPCLKPORT_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_PPMU_MISC_PCLK, + "gout_misc_ppmu_misc_pclk", "dout_misc_busp", + CLK_CON_GAT_GOUT_BLK_MISC_UID_PPMU_MISC_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_PUF_I_CLK, + "gout_misc_puf_i_clk", "mout_misc_sss_user", + CLK_CON_GAT_GOUT_BLK_MISC_UID_PUF_IPCLKPORT_I_CLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_QE_DIT_ACLK, + "gout_misc_qe_dit_aclk", "mout_misc_bus_user", + CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_DIT_IPCLKPORT_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_QE_DIT_PCLK, + "gout_misc_qe_dit_pclk", "dout_misc_busp", + CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_DIT_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_QE_PDMA_ACLK, + "gout_misc_qe_pdma_aclk", "mout_misc_bus_user", + CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_PDMA_IPCLKPORT_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_QE_PDMA_PCLK, + "gout_misc_qe_pdma_pclk", "dout_misc_busp", + CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_PDMA_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_QE_PPMU_DMA_ACLK, + "gout_misc_qe_ppmu_dma_aclk", "mout_misc_bus_user", + CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_PPMU_DMA_IPCLKPORT_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_QE_PPMU_DMA_PCLK, + "gout_misc_qe_ppmu_dma_pclk", "dout_misc_busp", + CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_PPMU_DMA_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_QE_RTIC_ACLK, + "gout_misc_qe_rtic_aclk", "mout_misc_bus_user", + CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_RTIC_IPCLKPORT_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_QE_RTIC_PCLK, + "gout_misc_qe_rtic_pclk", "dout_misc_busp", + CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_RTIC_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_QE_SPDMA_ACLK, + "gout_misc_qe_spdma_aclk", "mout_misc_bus_user", + CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_SPDMA_IPCLKPORT_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_QE_SPDMA_PCLK, + "gout_misc_qe_spdma_pclk", "dout_misc_busp", + CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_SPDMA_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_QE_SSS_ACLK, + "gout_misc_qe_sss_aclk", "mout_misc_sss_user", + CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_SSS_IPCLKPORT_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_QE_SSS_PCLK, + "gout_misc_qe_sss_pclk", "dout_misc_busp", + CLK_CON_GAT_GOUT_BLK_MISC_UID_QE_SSS_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_CLK_MISC_BUSD_CLK, + "gout_misc_clk_misc_busd_clk", "mout_misc_bus_user", + CLK_CON_GAT_GOUT_BLK_MISC_UID_RSTNSYNC_CLK_MISC_BUSD_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_CLK_MISC_BUSP_CLK, + "gout_misc_clk_misc_busp_clk", "dout_misc_busp", + CLK_CON_GAT_GOUT_BLK_MISC_UID_RSTNSYNC_CLK_MISC_BUSP_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_CLK_MISC_GIC_CLK, + "gout_misc_clk_misc_gic_clk", "mout_misc_gic", + CLK_CON_GAT_GOUT_BLK_MISC_UID_RSTNSYNC_CLK_MISC_GIC_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_CLK_MISC_SSS_CLK, + "gout_misc_clk_misc_sss_clk", "mout_misc_sss_user", + CLK_CON_GAT_GOUT_BLK_MISC_UID_RSTNSYNC_CLK_MISC_SSS_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_RTIC_I_ACLK, + "gout_misc_rtic_i_aclk", "mout_misc_bus_user", + CLK_CON_GAT_GOUT_BLK_MISC_UID_RTIC_IPCLKPORT_I_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_RTIC_I_PCLK, "gout_misc_rtic_i_pclk", + "dout_misc_busp", + CLK_CON_GAT_GOUT_BLK_MISC_UID_RTIC_IPCLKPORT_I_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_SPDMA_ACLK, + "gout_misc_spdma_ipclockport_aclk", "mout_misc_bus_user", + CLK_CON_GAT_GOUT_BLK_MISC_UID_SPDMA_IPCLKPORT_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_SSMT_DIT_ACLK, + "gout_misc_ssmt_dit_aclk", "mout_misc_bus_user", + CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_DIT_IPCLKPORT_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_SSMT_DIT_PCLK, + "gout_misc_ssmt_dit_pclk", "dout_misc_busp", + CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_DIT_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_SSMT_PDMA_ACLK, + "gout_misc_ssmt_pdma_aclk", "mout_misc_bus_user", + CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_PDMA_IPCLKPORT_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_SSMT_PDMA_PCLK, + "gout_misc_ssmt_pdma_pclk", "dout_misc_busp", + CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_PDMA_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_SSMT_PPMU_DMA_ACLK, + "gout_misc_ssmt_ppmu_dma_aclk", "mout_misc_bus_user", + CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_PPMU_DMA_IPCLKPORT_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_SSMT_PPMU_DMA_PCLK, + "gout_misc_ssmt_ppmu_dma_pclk", "dout_misc_busp", + CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_PPMU_DMA_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_SSMT_RTIC_ACLK, + "gout_misc_ssmt_rtic_aclk", "mout_misc_bus_user", + CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_RTIC_IPCLKPORT_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_SSMT_RTIC_PCLK, + "gout_misc_ssmt_rtic_pclk", "dout_misc_busp", + CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_RTIC_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_SSMT_SPDMA_ACLK, + "gout_misc_ssmt_spdma_aclk", "mout_misc_bus_user", + CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_SPDMA_IPCLKPORT_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_SSMT_SPDMA_PCLK, + "gout_misc_ssmt_spdma_pclk", "dout_misc_busp", + CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_SPDMA_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_SSMT_SSS_ACLK, + "gout_misc_ssmt_sss_aclk", "mout_misc_bus_user", + CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_SSS_IPCLKPORT_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_SSMT_SSS_PCLK, + "gout_misc_ssmt_sss_pclk", "dout_misc_busp", + CLK_CON_GAT_GOUT_BLK_MISC_UID_SSMT_SSS_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_SSS_I_ACLK, + "gout_misc_sss_i_aclk", "mout_misc_bus_user", + CLK_CON_GAT_GOUT_BLK_MISC_UID_SSS_IPCLKPORT_I_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_SSS_I_PCLK, + "gout_misc_sss_i_pclk", "dout_misc_busp", + CLK_CON_GAT_GOUT_BLK_MISC_UID_SSS_IPCLKPORT_I_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_SYSMMU_MISC_CLK_S2, + "gout_misc_sysmmu_misc_clk_s2", "mout_misc_bus_user", + CLK_CON_GAT_GOUT_BLK_MISC_UID_SYSMMU_MISC_IPCLKPORT_CLK_S2, + 21, 0, 0), + GATE(CLK_GOUT_MISC_SYSMMU_SSS_CLK_S1, + "gout_misc_sysmmu_sss_clk_s1", "mout_misc_sss_user", + CLK_CON_GAT_GOUT_BLK_MISC_UID_SYSMMU_SSS_IPCLKPORT_CLK_S1, + 21, 0, 0), + GATE(CLK_GOUT_MISC_SYSREG_MISC_PCLK, + "gout_misc_sysreg_misc_pclk", "dout_misc_busp", + CLK_CON_GAT_GOUT_BLK_MISC_UID_SYSREG_MISC_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_TMU_SUB_PCLK, + "gout_misc_tmu_sub_pclk", "dout_misc_busp", + CLK_CON_GAT_GOUT_BLK_MISC_UID_TMU_SUB_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_TMU_TOP_PCLK, + "gout_misc_tmu_top_pclk", "dout_misc_busp", + CLK_CON_GAT_GOUT_BLK_MISC_UID_TMU_TOP_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_WDT_CLUSTER0_PCLK, + "gout_misc_wdt_cluster0_pclk", "dout_misc_busp", + CLK_CON_GAT_GOUT_BLK_MISC_UID_WDT_CLUSTER0_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_WDT_CLUSTER1_PCLK, + "gout_misc_wdt_cluster1_pclk", "dout_misc_busp", + CLK_CON_GAT_GOUT_BLK_MISC_UID_WDT_CLUSTER1_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_MISC_XIU_D_MISC_ACLK, + "gout_misc_xiu_d_misc_aclk", "mout_misc_bus_user", + CLK_CON_GAT_GOUT_BLK_MISC_UID_XIU_D_MISC_IPCLKPORT_ACLK, + 21, 0, 0), +}; + +static const struct samsung_cmu_info misc_cmu_info __initconst = { + .mux_clks = misc_mux_clks, + .nr_mux_clks = ARRAY_SIZE(misc_mux_clks), + .div_clks = misc_div_clks, + .nr_div_clks = ARRAY_SIZE(misc_div_clks), + .gate_clks = misc_gate_clks, + .nr_gate_clks = ARRAY_SIZE(misc_gate_clks), + .nr_clk_ids = CLKS_NR_MISC, + .clk_regs = misc_clk_regs, + .nr_clk_regs = ARRAY_SIZE(misc_clk_regs), + .clk_name = "dout_cmu_misc_bus", +}; + +/* ---- platform_driver ----------------------------------------------------- */ + +static int __init gs101_cmu_probe(struct platform_device *pdev) +{ + const struct samsung_cmu_info *info; + struct device *dev = &pdev->dev; + + info = of_device_get_match_data(dev); + exynos_arm64_register_cmu(dev, dev->of_node, info); + + return 0; +} + +static const struct of_device_id gs101_cmu_of_match[] = { + { + .compatible = "google,gs101-cmu-apm", + .data = &apm_cmu_info, + }, { + .compatible = "google,gs101-cmu-misc", + .data = &misc_cmu_info, + }, { + }, +}; + +static struct platform_driver gs101_cmu_driver __refdata = { + .driver = { + .name = "gs101-cmu", + .of_match_table = gs101_cmu_of_match, + .suppress_bind_attrs = true, + }, + .probe = gs101_cmu_probe, +}; + +static int __init gs101_cmu_init(void) +{ + return platform_driver_register(&gs101_cmu_driver); +} +core_initcall(gs101_cmu_init); diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index 74934c6182cea9..4bbdf5e91650f3 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -443,6 +443,9 @@ static unsigned long samsung_pll0822x_recalc_rate(struct clk_hw *hw, sdiv = (pll_con3 >> PLL0822X_SDIV_SHIFT) & PLL0822X_SDIV_MASK; fvco *= mdiv; + if (pll->type == pll_0516x) + fvco *= 2; + do_div(fvco, (pdiv << sdiv)); return (unsigned long)fvco; @@ -1316,6 +1319,9 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx, case pll_1417x: case pll_0818x: case pll_0822x: + case pll_0516x: + case pll_0517x: + case pll_0518x: pll->enable_offs = PLL0822X_ENABLE_SHIFT; pll->lock_offs = PLL0822X_LOCK_STAT_SHIFT; if (!pll->rate_table) diff --git a/drivers/clk/samsung/clk-pll.h b/drivers/clk/samsung/clk-pll.h index 0725d485c6eecd..ffd3d52c0dec23 100644 --- a/drivers/clk/samsung/clk-pll.h +++ b/drivers/clk/samsung/clk-pll.h @@ -38,6 +38,9 @@ enum samsung_pll_type { pll_0822x, pll_0831x, pll_142xx, + pll_0516x, + pll_0517x, + pll_0518x, }; #define PLL_RATE(_fin, _m, _p, _s, _k, _ks) \ diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h index ab9c3d7a25b3d6..516b716407e550 100644 --- a/drivers/clk/samsung/clk.h +++ b/drivers/clk/samsung/clk.h @@ -14,11 +14,11 @@ #include "clk-pll.h" /** - * struct samsung_clk_provider: information about clock provider - * @reg_base: virtual address for the register base. - * @dev: clock provider device needed for runtime PM. - * @lock: maintains exclusion between callbacks for a given clock-provider. - * @clk_data: holds clock related data like clk_hw* and number of clocks. + * struct samsung_clk_provider - information about clock provider + * @reg_base: virtual address for the register base + * @dev: clock provider device needed for runtime PM + * @lock: maintains exclusion between callbacks for a given clock-provider + * @clk_data: holds clock related data like clk_hw* and number of clocks */ struct samsung_clk_provider { void __iomem *reg_base; @@ -29,10 +29,10 @@ struct samsung_clk_provider { }; /** - * struct samsung_clock_alias: information about mux clock - * @id: platform specific id of the clock. - * @dev_name: name of the device to which this clock belongs. - * @alias: optional clock alias name to be assigned to this clock. + * struct samsung_clock_alias - information about mux clock + * @id: platform specific id of the clock + * @dev_name: name of the device to which this clock belongs + * @alias: optional clock alias name to be assigned to this clock */ struct samsung_clock_alias { unsigned int id; @@ -50,12 +50,12 @@ struct samsung_clock_alias { #define MHZ (1000 * 1000) /** - * struct samsung_fixed_rate_clock: information about fixed-rate clock - * @id: platform specific id of the clock. - * @name: name of this fixed-rate clock. - * @parent_name: optional parent clock name. - * @flags: optional fixed-rate clock flags. - * @fixed-rate: fixed clock rate of this clock. + * struct samsung_fixed_rate_clock - information about fixed-rate clock + * @id: platform specific id of the clock + * @name: name of this fixed-rate clock + * @parent_name: optional parent clock name + * @flags: optional fixed-rate clock flags + * @fixed_rate: fixed clock rate of this clock */ struct samsung_fixed_rate_clock { unsigned int id; @@ -74,14 +74,14 @@ struct samsung_fixed_rate_clock { .fixed_rate = frate, \ } -/* - * struct samsung_fixed_factor_clock: information about fixed-factor clock - * @id: platform specific id of the clock. - * @name: name of this fixed-factor clock. - * @parent_name: parent clock name. - * @mult: fixed multiplication factor. - * @div: fixed division factor. - * @flags: optional fixed-factor clock flags. +/** + * struct samsung_fixed_factor_clock - information about fixed-factor clock + * @id: platform specific id of the clock + * @name: name of this fixed-factor clock + * @parent_name: parent clock name + * @mult: fixed multiplication factor + * @div: fixed division factor + * @flags: optional fixed-factor clock flags */ struct samsung_fixed_factor_clock { unsigned int id; @@ -103,16 +103,16 @@ struct samsung_fixed_factor_clock { } /** - * struct samsung_mux_clock: information about mux clock - * @id: platform specific id of the clock. - * @name: name of this mux clock. - * @parent_names: array of pointer to parent clock names. - * @num_parents: number of parents listed in @parent_names. - * @flags: optional flags for basic clock. - * @offset: offset of the register for configuring the mux. - * @shift: starting bit location of the mux control bit-field in @reg. - * @width: width of the mux control bit-field in @reg. - * @mux_flags: flags for mux-type clock. + * struct samsung_mux_clock - information about mux clock + * @id: platform specific id of the clock + * @name: name of this mux clock + * @parent_names: array of pointer to parent clock names + * @num_parents: number of parents listed in @parent_names + * @flags: optional flags for basic clock + * @offset: offset of the register for configuring the mux + * @shift: starting bit location of the mux control bit-field in @reg + * @width: width of the mux control bit-field in @reg + * @mux_flags: flags for mux-type clock */ struct samsung_mux_clock { unsigned int id; @@ -146,14 +146,16 @@ struct samsung_mux_clock { __MUX(_id, cname, pnames, o, s, w, f, mf) /** - * @id: platform specific id of the clock. - * struct samsung_div_clock: information about div clock - * @name: name of this div clock. - * @parent_name: name of the parent clock. - * @flags: optional flags for basic clock. - * @offset: offset of the register for configuring the div. - * @shift: starting bit location of the div control bit-field in @reg. - * @div_flags: flags for div-type clock. + * struct samsung_div_clock - information about div clock + * @id: platform specific id of the clock + * @name: name of this div clock + * @parent_name: name of the parent clock + * @flags: optional flags for basic clock + * @offset: offset of the register for configuring the div + * @shift: starting bit location of the div control bit-field in @reg + * @width: width of the bitfield + * @div_flags: flags for div-type clock + * @table: array of divider/value pairs ending with a div set to 0 */ struct samsung_div_clock { unsigned int id; @@ -190,14 +192,14 @@ struct samsung_div_clock { __DIV(_id, cname, pname, o, s, w, 0, 0, t) /** - * struct samsung_gate_clock: information about gate clock - * @id: platform specific id of the clock. - * @name: name of this gate clock. - * @parent_name: name of the parent clock. - * @flags: optional flags for basic clock. - * @offset: offset of the register for configuring the gate. - * @bit_idx: bit index of the gate control bit-field in @reg. - * @gate_flags: flags for gate-type clock. + * struct samsung_gate_clock - information about gate clock + * @id: platform specific id of the clock + * @name: name of this gate clock + * @parent_name: name of the parent clock + * @flags: optional flags for basic clock + * @offset: offset of the register for configuring the gate + * @bit_idx: bit index of the gate control bit-field in @reg + * @gate_flags: flags for gate-type clock */ struct samsung_gate_clock { unsigned int id; @@ -226,9 +228,9 @@ struct samsung_gate_clock { #define PNAME(x) static const char * const x[] __initconst /** - * struct samsung_clk_reg_dump: register dump of clock controller registers. - * @offset: clock register offset from the controller base address. - * @value: the value to be register at offset. + * struct samsung_clk_reg_dump - register dump of clock controller registers + * @offset: clock register offset from the controller base address + * @value: the value to be register at offset */ struct samsung_clk_reg_dump { u32 offset; @@ -236,14 +238,15 @@ struct samsung_clk_reg_dump { }; /** - * struct samsung_pll_clock: information about pll clock - * @id: platform specific id of the clock. - * @name: name of this pll clock. - * @parent_name: name of the parent clock. - * @flags: optional flags for basic clock. - * @con_offset: offset of the register for configuring the PLL. - * @lock_offset: offset of the register for locking the PLL. - * @type: Type of PLL to be registered. + * struct samsung_pll_clock - information about pll clock + * @id: platform specific id of the clock + * @name: name of this pll clock + * @parent_name: name of the parent clock + * @flags: optional flags for basic clock + * @con_offset: offset of the register for configuring the PLL + * @lock_offset: offset of the register for locking the PLL + * @type: type of PLL to be registered + * @rate_table: array of PLL settings for possible PLL rates */ struct samsung_pll_clock { unsigned int id; @@ -302,39 +305,51 @@ struct samsung_clock_reg_cache { unsigned int rsuspend_num; }; +/** + * struct samsung_cmu_info - all clocks information needed for CMU registration + * @pll_clks: list of PLL clocks + * @nr_pll_clks: count of clocks in @pll_clks + * @mux_clks: list of mux clocks + * @nr_mux_clks: count of clocks in @mux_clks + * @div_clks: list of div clocks + * @nr_div_clks: count of clocks in @div_clks + * @gate_clks: list of gate clocks + * @nr_gate_clks: count of clocks in @gate_clks + * @fixed_clks: list of fixed clocks + * @nr_fixed_clks: count clocks in @fixed_clks + * @fixed_factor_clks: list of fixed factor clocks + * @nr_fixed_factor_clks: count of clocks in @fixed_factor_clks + * @nr_clk_ids: total number of clocks with IDs assigned + * @cpu_clks: list of CPU clocks + * @nr_cpu_clks: count of clocks in @cpu_clks + * @clk_regs: list of clock registers + * @nr_clk_regs: count of clock registers in @clk_regs + * @suspend_regs: list of clock registers to set before suspend + * @nr_suspend_regs: count of clock registers in @suspend_regs + * @clk_name: name of the parent clock needed for CMU register access + */ struct samsung_cmu_info { - /* list of pll clocks and respective count */ const struct samsung_pll_clock *pll_clks; unsigned int nr_pll_clks; - /* list of mux clocks and respective count */ const struct samsung_mux_clock *mux_clks; unsigned int nr_mux_clks; - /* list of div clocks and respective count */ const struct samsung_div_clock *div_clks; unsigned int nr_div_clks; - /* list of gate clocks and respective count */ const struct samsung_gate_clock *gate_clks; unsigned int nr_gate_clks; - /* list of fixed clocks and respective count */ const struct samsung_fixed_rate_clock *fixed_clks; unsigned int nr_fixed_clks; - /* list of fixed factor clocks and respective count */ const struct samsung_fixed_factor_clock *fixed_factor_clks; unsigned int nr_fixed_factor_clks; - /* total number of clocks with IDs assigned*/ unsigned int nr_clk_ids; - /* list of cpu clocks and respective count */ const struct samsung_cpu_clock *cpu_clks; unsigned int nr_cpu_clks; - /* list and number of clocks registers */ const unsigned long *clk_regs; unsigned int nr_clk_regs; - /* list and number of clocks registers to set before suspend */ const struct samsung_clk_reg_dump *suspend_regs; unsigned int nr_suspend_regs; - /* name of the parent clock needed for CMU register access */ const char *clk_name; }; diff --git a/drivers/clk/starfive/clk-starfive-jh7100-audio.c b/drivers/clk/starfive/clk-starfive-jh7100-audio.c index ee4bda14a40e3f..1fcf4e62f347db 100644 --- a/drivers/clk/starfive/clk-starfive-jh7100-audio.c +++ b/drivers/clk/starfive/clk-starfive-jh7100-audio.c @@ -79,7 +79,7 @@ static const struct jh71x0_clk_data jh7100_audclk_data[] = { JH71X0_GDIV(JH7100_AUDCLK_USB_LPM, "usb_lpm", CLK_IGNORE_UNUSED, 4, JH7100_AUDCLK_USB_APB), JH71X0_GDIV(JH7100_AUDCLK_USB_STB, "usb_stb", CLK_IGNORE_UNUSED, 3, JH7100_AUDCLK_USB_APB), JH71X0__DIV(JH7100_AUDCLK_APB_EN, "apb_en", 8, JH7100_AUDCLK_DOM7AHB_BUS), - JH71X0__MUX(JH7100_AUDCLK_VAD_MEM, "vad_mem", 2, + JH71X0__MUX(JH7100_AUDCLK_VAD_MEM, "vad_mem", 0, 2, JH7100_AUDCLK_VAD_INTMEM, JH7100_AUDCLK_AUDIO_12288), }; diff --git a/drivers/clk/starfive/clk-starfive-jh7100.c b/drivers/clk/starfive/clk-starfive-jh7100.c index 69cc11ea7e3341..03f6f26a15d871 100644 --- a/drivers/clk/starfive/clk-starfive-jh7100.c +++ b/drivers/clk/starfive/clk-starfive-jh7100.c @@ -24,48 +24,48 @@ #define JH7100_CLK_GMAC_GR_MII_RX (JH7100_CLK_END + 3) static const struct jh71x0_clk_data jh7100_clk_data[] __initconst = { - JH71X0__MUX(JH7100_CLK_CPUNDBUS_ROOT, "cpundbus_root", 4, + JH71X0__MUX(JH7100_CLK_CPUNDBUS_ROOT, "cpundbus_root", 0, 4, JH7100_CLK_OSC_SYS, JH7100_CLK_PLL0_OUT, JH7100_CLK_PLL1_OUT, JH7100_CLK_PLL2_OUT), - JH71X0__MUX(JH7100_CLK_DLA_ROOT, "dla_root", 3, + JH71X0__MUX(JH7100_CLK_DLA_ROOT, "dla_root", 0, 3, JH7100_CLK_OSC_SYS, JH7100_CLK_PLL1_OUT, JH7100_CLK_PLL2_OUT), - JH71X0__MUX(JH7100_CLK_DSP_ROOT, "dsp_root", 4, + JH71X0__MUX(JH7100_CLK_DSP_ROOT, "dsp_root", 0, 4, JH7100_CLK_OSC_SYS, JH7100_CLK_PLL0_OUT, JH7100_CLK_PLL1_OUT, JH7100_CLK_PLL2_OUT), - JH71X0__MUX(JH7100_CLK_GMACUSB_ROOT, "gmacusb_root", 3, + JH71X0__MUX(JH7100_CLK_GMACUSB_ROOT, "gmacusb_root", 0, 3, JH7100_CLK_OSC_SYS, JH7100_CLK_PLL0_OUT, JH7100_CLK_PLL2_OUT), - JH71X0__MUX(JH7100_CLK_PERH0_ROOT, "perh0_root", 2, + JH71X0__MUX(JH7100_CLK_PERH0_ROOT, "perh0_root", 0, 2, JH7100_CLK_OSC_SYS, JH7100_CLK_PLL0_OUT), - JH71X0__MUX(JH7100_CLK_PERH1_ROOT, "perh1_root", 2, + JH71X0__MUX(JH7100_CLK_PERH1_ROOT, "perh1_root", 0, 2, JH7100_CLK_OSC_SYS, JH7100_CLK_PLL2_OUT), - JH71X0__MUX(JH7100_CLK_VIN_ROOT, "vin_root", 3, + JH71X0__MUX(JH7100_CLK_VIN_ROOT, "vin_root", 0, 3, JH7100_CLK_OSC_SYS, JH7100_CLK_PLL1_OUT, JH7100_CLK_PLL2_OUT), - JH71X0__MUX(JH7100_CLK_VOUT_ROOT, "vout_root", 3, + JH71X0__MUX(JH7100_CLK_VOUT_ROOT, "vout_root", 0, 3, JH7100_CLK_OSC_AUD, JH7100_CLK_PLL0_OUT, JH7100_CLK_PLL2_OUT), JH71X0_GDIV(JH7100_CLK_AUDIO_ROOT, "audio_root", 0, 8, JH7100_CLK_PLL0_OUT), - JH71X0__MUX(JH7100_CLK_CDECHIFI4_ROOT, "cdechifi4_root", 3, + JH71X0__MUX(JH7100_CLK_CDECHIFI4_ROOT, "cdechifi4_root", 0, 3, JH7100_CLK_OSC_SYS, JH7100_CLK_PLL1_OUT, JH7100_CLK_PLL2_OUT), - JH71X0__MUX(JH7100_CLK_CDEC_ROOT, "cdec_root", 3, + JH71X0__MUX(JH7100_CLK_CDEC_ROOT, "cdec_root", 0, 3, JH7100_CLK_OSC_SYS, JH7100_CLK_PLL0_OUT, JH7100_CLK_PLL1_OUT), - JH71X0__MUX(JH7100_CLK_VOUTBUS_ROOT, "voutbus_root", 3, + JH71X0__MUX(JH7100_CLK_VOUTBUS_ROOT, "voutbus_root", 0, 3, JH7100_CLK_OSC_AUD, JH7100_CLK_PLL0_OUT, JH7100_CLK_PLL2_OUT), @@ -76,7 +76,7 @@ static const struct jh71x0_clk_data jh7100_clk_data[] __initconst = { JH71X0_GDIV(JH7100_CLK_PLL0_TESTOUT, "pll0_testout", 0, 31, JH7100_CLK_PERH0_SRC), JH71X0_GDIV(JH7100_CLK_PLL1_TESTOUT, "pll1_testout", 0, 31, JH7100_CLK_DLA_ROOT), JH71X0_GDIV(JH7100_CLK_PLL2_TESTOUT, "pll2_testout", 0, 31, JH7100_CLK_PERH1_SRC), - JH71X0__MUX(JH7100_CLK_PLL2_REF, "pll2_refclk", 2, + JH71X0__MUX(JH7100_CLK_PLL2_REF, "pll2_refclk", 0, 2, JH7100_CLK_OSC_SYS, JH7100_CLK_OSC_AUD), JH71X0__DIV(JH7100_CLK_CPU_CORE, "cpu_core", 8, JH7100_CLK_CPUNBUS_ROOT_DIV), @@ -142,7 +142,7 @@ static const struct jh71x0_clk_data jh7100_clk_data[] __initconst = { JH71X0__DIV(JH7100_CLK_NOC_COG, "noc_cog", 8, JH7100_CLK_DLA_ROOT), JH71X0_GATE(JH7100_CLK_NNE_AHB, "nne_ahb", 0, JH7100_CLK_AHB_BUS), JH71X0__DIV(JH7100_CLK_NNEBUS_SRC1, "nnebus_src1", 4, JH7100_CLK_DSP_ROOT), - JH71X0__MUX(JH7100_CLK_NNE_BUS, "nne_bus", 2, + JH71X0__MUX(JH7100_CLK_NNE_BUS, "nne_bus", 0, 2, JH7100_CLK_CPU_AXI, JH7100_CLK_NNEBUS_SRC1), JH71X0_GATE(JH7100_CLK_NNE_AXI, "nne_axi", 0, JH7100_CLK_NNE_BUS), @@ -166,7 +166,7 @@ static const struct jh71x0_clk_data jh7100_clk_data[] __initconst = { JH71X0_GDIV(JH7100_CLK_USBPHY_125M, "usbphy_125m", 0, 8, JH7100_CLK_USBPHY_ROOTDIV), JH71X0_GDIV(JH7100_CLK_USBPHY_PLLDIV25M, "usbphy_plldiv25m", 0, 32, JH7100_CLK_USBPHY_ROOTDIV), - JH71X0__MUX(JH7100_CLK_USBPHY_25M, "usbphy_25m", 2, + JH71X0__MUX(JH7100_CLK_USBPHY_25M, "usbphy_25m", 0, 2, JH7100_CLK_OSC_SYS, JH7100_CLK_USBPHY_PLLDIV25M), JH71X0_FDIV(JH7100_CLK_AUDIO_DIV, "audio_div", JH7100_CLK_AUDIO_ROOT), @@ -200,12 +200,12 @@ static const struct jh71x0_clk_data jh7100_clk_data[] __initconst = { JH71X0_GDIV(JH7100_CLK_GMAC_GTX, "gmac_gtxclk", 0, 255, JH7100_CLK_GMAC_ROOT_DIV), JH71X0_GDIV(JH7100_CLK_GMAC_RMII_TX, "gmac_rmii_txclk", 0, 8, JH7100_CLK_GMAC_RMII_REF), JH71X0_GDIV(JH7100_CLK_GMAC_RMII_RX, "gmac_rmii_rxclk", 0, 8, JH7100_CLK_GMAC_RMII_REF), - JH71X0__MUX(JH7100_CLK_GMAC_TX, "gmac_tx", 3, + JH71X0__MUX(JH7100_CLK_GMAC_TX, "gmac_tx", CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, 3, JH7100_CLK_GMAC_GTX, JH7100_CLK_GMAC_TX_INV, JH7100_CLK_GMAC_RMII_TX), JH71X0__INV(JH7100_CLK_GMAC_TX_INV, "gmac_tx_inv", JH7100_CLK_GMAC_TX), - JH71X0__MUX(JH7100_CLK_GMAC_RX_PRE, "gmac_rx_pre", 2, + JH71X0__MUX(JH7100_CLK_GMAC_RX_PRE, "gmac_rx_pre", 0, 2, JH7100_CLK_GMAC_GR_MII_RX, JH7100_CLK_GMAC_RMII_RX), JH71X0__INV(JH7100_CLK_GMAC_RX_INV, "gmac_rx_inv", JH7100_CLK_GMAC_RX_PRE), diff --git a/drivers/clk/starfive/clk-starfive-jh7110-aon.c b/drivers/clk/starfive/clk-starfive-jh7110-aon.c index 62954eb7b50a39..418efdad719b87 100644 --- a/drivers/clk/starfive/clk-starfive-jh7110-aon.c +++ b/drivers/clk/starfive/clk-starfive-jh7110-aon.c @@ -26,7 +26,7 @@ static const struct jh71x0_clk_data jh7110_aonclk_data[] = { /* source */ JH71X0__DIV(JH7110_AONCLK_OSC_DIV4, "osc_div4", 4, JH7110_AONCLK_OSC), - JH71X0__MUX(JH7110_AONCLK_APB_FUNC, "apb_func", 2, + JH71X0__MUX(JH7110_AONCLK_APB_FUNC, "apb_func", 0, 2, JH7110_AONCLK_OSC_DIV4, JH7110_AONCLK_OSC), /* gmac0 */ @@ -39,7 +39,7 @@ static const struct jh71x0_clk_data jh7110_aonclk_data[] = { JH7110_AONCLK_GMAC0_GTXCLK, JH7110_AONCLK_GMAC0_RMII_RTX), JH71X0__INV(JH7110_AONCLK_GMAC0_TX_INV, "gmac0_tx_inv", JH7110_AONCLK_GMAC0_TX), - JH71X0__MUX(JH7110_AONCLK_GMAC0_RX, "gmac0_rx", 2, + JH71X0__MUX(JH7110_AONCLK_GMAC0_RX, "gmac0_rx", 0, 2, JH7110_AONCLK_GMAC0_RGMII_RXIN, JH7110_AONCLK_GMAC0_RMII_RTX), JH71X0__INV(JH7110_AONCLK_GMAC0_RX_INV, "gmac0_rx_inv", JH7110_AONCLK_GMAC0_RX), @@ -48,7 +48,7 @@ static const struct jh71x0_clk_data jh7110_aonclk_data[] = { /* rtc */ JH71X0_GATE(JH7110_AONCLK_RTC_APB, "rtc_apb", 0, JH7110_AONCLK_APB_BUS), JH71X0__DIV(JH7110_AONCLK_RTC_INTERNAL, "rtc_internal", 1022, JH7110_AONCLK_OSC), - JH71X0__MUX(JH7110_AONCLK_RTC_32K, "rtc_32k", 2, + JH71X0__MUX(JH7110_AONCLK_RTC_32K, "rtc_32k", 0, 2, JH7110_AONCLK_RTC_OSC, JH7110_AONCLK_RTC_INTERNAL), JH71X0_GATE(JH7110_AONCLK_RTC_CAL, "rtc_cal", 0, JH7110_AONCLK_OSC), diff --git a/drivers/clk/starfive/clk-starfive-jh7110-isp.c b/drivers/clk/starfive/clk-starfive-jh7110-isp.c index ce034ed2853211..929b8788279ea1 100644 --- a/drivers/clk/starfive/clk-starfive-jh7110-isp.c +++ b/drivers/clk/starfive/clk-starfive-jh7110-isp.c @@ -53,7 +53,7 @@ static const struct jh71x0_clk_data jh7110_ispclk_data[] = { JH7110_ISPCLK_MIPI_RX0_PXL), JH71X0_GATE(JH7110_ISPCLK_VIN_PIXEL_IF3, "vin_pixel_if3", 0, JH7110_ISPCLK_MIPI_RX0_PXL), - JH71X0__MUX(JH7110_ISPCLK_VIN_P_AXI_WR, "vin_p_axi_wr", 2, + JH71X0__MUX(JH7110_ISPCLK_VIN_P_AXI_WR, "vin_p_axi_wr", 0, 2, JH7110_ISPCLK_MIPI_RX0_PXL, JH7110_ISPCLK_DVP_INV), /* ispv2_top_wrapper */ diff --git a/drivers/clk/starfive/clk-starfive-jh7110-sys.c b/drivers/clk/starfive/clk-starfive-jh7110-sys.c index 3884eff9fe9315..8f5e5abfa178db 100644 --- a/drivers/clk/starfive/clk-starfive-jh7110-sys.c +++ b/drivers/clk/starfive/clk-starfive-jh7110-sys.c @@ -36,18 +36,18 @@ static const struct jh71x0_clk_data jh7110_sysclk_data[] __initconst = { /* root */ - JH71X0__MUX(JH7110_SYSCLK_CPU_ROOT, "cpu_root", 2, + JH71X0__MUX(JH7110_SYSCLK_CPU_ROOT, "cpu_root", 0, 2, JH7110_SYSCLK_OSC, JH7110_SYSCLK_PLL0_OUT), JH71X0__DIV(JH7110_SYSCLK_CPU_CORE, "cpu_core", 7, JH7110_SYSCLK_CPU_ROOT), JH71X0__DIV(JH7110_SYSCLK_CPU_BUS, "cpu_bus", 2, JH7110_SYSCLK_CPU_CORE), - JH71X0__MUX(JH7110_SYSCLK_GPU_ROOT, "gpu_root", 2, + JH71X0__MUX(JH7110_SYSCLK_GPU_ROOT, "gpu_root", 0, 2, JH7110_SYSCLK_PLL2_OUT, JH7110_SYSCLK_PLL1_OUT), JH71X0_MDIV(JH7110_SYSCLK_PERH_ROOT, "perh_root", 2, 2, JH7110_SYSCLK_PLL0_OUT, JH7110_SYSCLK_PLL2_OUT), - JH71X0__MUX(JH7110_SYSCLK_BUS_ROOT, "bus_root", 2, + JH71X0__MUX(JH7110_SYSCLK_BUS_ROOT, "bus_root", 0, 2, JH7110_SYSCLK_OSC, JH7110_SYSCLK_PLL2_OUT), JH71X0__DIV(JH7110_SYSCLK_NOCSTG_BUS, "nocstg_bus", 3, JH7110_SYSCLK_BUS_ROOT), @@ -62,7 +62,7 @@ static const struct jh71x0_clk_data jh7110_sysclk_data[] __initconst = { JH71X0__DIV(JH7110_SYSCLK_PLL2_DIV2, "pll2_div2", 2, JH7110_SYSCLK_PLL2_OUT), JH71X0__DIV(JH7110_SYSCLK_AUDIO_ROOT, "audio_root", 8, JH7110_SYSCLK_PLL2_OUT), JH71X0__DIV(JH7110_SYSCLK_MCLK_INNER, "mclk_inner", 64, JH7110_SYSCLK_AUDIO_ROOT), - JH71X0__MUX(JH7110_SYSCLK_MCLK, "mclk", 2, + JH71X0__MUX(JH7110_SYSCLK_MCLK, "mclk", 0, 2, JH7110_SYSCLK_MCLK_INNER, JH7110_SYSCLK_MCLK_EXT), JH71X0_GATE(JH7110_SYSCLK_MCLK_OUT, "mclk_out", 0, JH7110_SYSCLK_MCLK_INNER), @@ -96,7 +96,7 @@ static const struct jh71x0_clk_data jh7110_sysclk_data[] __initconst = { JH71X0__DIV(JH7110_SYSCLK_OSC_DIV2, "osc_div2", 2, JH7110_SYSCLK_OSC), JH71X0__DIV(JH7110_SYSCLK_PLL1_DIV4, "pll1_div4", 2, JH7110_SYSCLK_PLL1_DIV2), JH71X0__DIV(JH7110_SYSCLK_PLL1_DIV8, "pll1_div8", 2, JH7110_SYSCLK_PLL1_DIV4), - JH71X0__MUX(JH7110_SYSCLK_DDR_BUS, "ddr_bus", 4, + JH71X0__MUX(JH7110_SYSCLK_DDR_BUS, "ddr_bus", 0, 4, JH7110_SYSCLK_OSC_DIV2, JH7110_SYSCLK_PLL1_DIV2, JH7110_SYSCLK_PLL1_DIV4, @@ -186,7 +186,7 @@ static const struct jh71x0_clk_data jh7110_sysclk_data[] __initconst = { JH71X0__DIV(JH7110_SYSCLK_GMAC1_RMII_RTX, "gmac1_rmii_rtx", 30, JH7110_SYSCLK_GMAC1_RMII_REFIN), JH71X0_GDIV(JH7110_SYSCLK_GMAC1_PTP, "gmac1_ptp", 0, 31, JH7110_SYSCLK_GMAC_SRC), - JH71X0__MUX(JH7110_SYSCLK_GMAC1_RX, "gmac1_rx", 2, + JH71X0__MUX(JH7110_SYSCLK_GMAC1_RX, "gmac1_rx", 0, 2, JH7110_SYSCLK_GMAC1_RGMII_RXIN, JH7110_SYSCLK_GMAC1_RMII_RTX), JH71X0__INV(JH7110_SYSCLK_GMAC1_RX_INV, "gmac1_rx_inv", JH7110_SYSCLK_GMAC1_RX), @@ -270,11 +270,11 @@ static const struct jh71x0_clk_data jh7110_sysclk_data[] __initconst = { JH71X0_MDIV(JH7110_SYSCLK_I2STX0_LRCK_MST, "i2stx0_lrck_mst", 64, 2, JH7110_SYSCLK_I2STX0_BCLK_MST_INV, JH7110_SYSCLK_I2STX0_BCLK_MST), - JH71X0__MUX(JH7110_SYSCLK_I2STX0_BCLK, "i2stx0_bclk", 2, + JH71X0__MUX(JH7110_SYSCLK_I2STX0_BCLK, "i2stx0_bclk", 0, 2, JH7110_SYSCLK_I2STX0_BCLK_MST, JH7110_SYSCLK_I2STX_BCLK_EXT), JH71X0__INV(JH7110_SYSCLK_I2STX0_BCLK_INV, "i2stx0_bclk_inv", JH7110_SYSCLK_I2STX0_BCLK), - JH71X0__MUX(JH7110_SYSCLK_I2STX0_LRCK, "i2stx0_lrck", 2, + JH71X0__MUX(JH7110_SYSCLK_I2STX0_LRCK, "i2stx0_lrck", 0, 2, JH7110_SYSCLK_I2STX0_LRCK_MST, JH7110_SYSCLK_I2STX_LRCK_EXT), /* i2stx1 */ @@ -285,11 +285,11 @@ static const struct jh71x0_clk_data jh7110_sysclk_data[] __initconst = { JH71X0_MDIV(JH7110_SYSCLK_I2STX1_LRCK_MST, "i2stx1_lrck_mst", 64, 2, JH7110_SYSCLK_I2STX1_BCLK_MST_INV, JH7110_SYSCLK_I2STX1_BCLK_MST), - JH71X0__MUX(JH7110_SYSCLK_I2STX1_BCLK, "i2stx1_bclk", 2, + JH71X0__MUX(JH7110_SYSCLK_I2STX1_BCLK, "i2stx1_bclk", 0, 2, JH7110_SYSCLK_I2STX1_BCLK_MST, JH7110_SYSCLK_I2STX_BCLK_EXT), JH71X0__INV(JH7110_SYSCLK_I2STX1_BCLK_INV, "i2stx1_bclk_inv", JH7110_SYSCLK_I2STX1_BCLK), - JH71X0__MUX(JH7110_SYSCLK_I2STX1_LRCK, "i2stx1_lrck", 2, + JH71X0__MUX(JH7110_SYSCLK_I2STX1_LRCK, "i2stx1_lrck", 0, 2, JH7110_SYSCLK_I2STX1_LRCK_MST, JH7110_SYSCLK_I2STX_LRCK_EXT), /* i2srx */ @@ -300,11 +300,11 @@ static const struct jh71x0_clk_data jh7110_sysclk_data[] __initconst = { JH71X0_MDIV(JH7110_SYSCLK_I2SRX_LRCK_MST, "i2srx_lrck_mst", 64, 2, JH7110_SYSCLK_I2SRX_BCLK_MST_INV, JH7110_SYSCLK_I2SRX_BCLK_MST), - JH71X0__MUX(JH7110_SYSCLK_I2SRX_BCLK, "i2srx_bclk", 2, + JH71X0__MUX(JH7110_SYSCLK_I2SRX_BCLK, "i2srx_bclk", 0, 2, JH7110_SYSCLK_I2SRX_BCLK_MST, JH7110_SYSCLK_I2SRX_BCLK_EXT), JH71X0__INV(JH7110_SYSCLK_I2SRX_BCLK_INV, "i2srx_bclk_inv", JH7110_SYSCLK_I2SRX_BCLK), - JH71X0__MUX(JH7110_SYSCLK_I2SRX_LRCK, "i2srx_lrck", 2, + JH71X0__MUX(JH7110_SYSCLK_I2SRX_LRCK, "i2srx_lrck", 0, 2, JH7110_SYSCLK_I2SRX_LRCK_MST, JH7110_SYSCLK_I2SRX_LRCK_EXT), /* pdm */ @@ -314,7 +314,7 @@ static const struct jh71x0_clk_data jh7110_sysclk_data[] __initconst = { JH71X0_GATE(JH7110_SYSCLK_TDM_AHB, "tdm_ahb", 0, JH7110_SYSCLK_AHB0), JH71X0_GATE(JH7110_SYSCLK_TDM_APB, "tdm_apb", 0, JH7110_SYSCLK_APB0), JH71X0_GDIV(JH7110_SYSCLK_TDM_INTERNAL, "tdm_internal", 0, 64, JH7110_SYSCLK_MCLK), - JH71X0__MUX(JH7110_SYSCLK_TDM_TDM, "tdm_tdm", 2, + JH71X0__MUX(JH7110_SYSCLK_TDM_TDM, "tdm_tdm", 0, 2, JH7110_SYSCLK_TDM_INTERNAL, JH7110_SYSCLK_TDM_EXT), JH71X0__INV(JH7110_SYSCLK_TDM_TDM_INV, "tdm_tdm_inv", JH7110_SYSCLK_TDM_TDM), diff --git a/drivers/clk/starfive/clk-starfive-jh71x0.h b/drivers/clk/starfive/clk-starfive-jh71x0.h index 34bb11c72eb73b..23e052fc15495c 100644 --- a/drivers/clk/starfive/clk-starfive-jh71x0.h +++ b/drivers/clk/starfive/clk-starfive-jh71x0.h @@ -61,10 +61,10 @@ struct jh71x0_clk_data { .parents = { [0] = _parent }, \ } -#define JH71X0__MUX(_idx, _name, _nparents, ...) \ +#define JH71X0__MUX(_idx, _name, _flags, _nparents, ...) \ [_idx] = { \ .name = _name, \ - .flags = 0, \ + .flags = _flags, \ .max = ((_nparents) - 1) << JH71X0_CLK_MUX_SHIFT, \ .parents = { __VA_ARGS__ }, \ } diff --git a/drivers/clk/stm32/Kconfig b/drivers/clk/stm32/Kconfig new file mode 100644 index 00000000000000..3c8493a94a11b2 --- /dev/null +++ b/drivers/clk/stm32/Kconfig @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: GPL-2.0-only +# common clock support for STMicroelectronics SoC family. + +menuconfig COMMON_CLK_STM32MP + bool "Clock support for common STM32MP clocks" + depends on ARCH_STM32 || COMPILE_TEST + default y + select RESET_CONTROLLER + help + Support for STM32MP SoC family clocks. + +if COMMON_CLK_STM32MP + +config COMMON_CLK_STM32MP135 + bool "Clock driver for stm32mp13x clocks" + depends on ARM || COMPILE_TEST + default y + help + Support for stm32mp13x SoC family clocks. + +config COMMON_CLK_STM32MP157 + bool "Clock driver for stm32mp15x clocks" + depends on ARM || COMPILE_TEST + default y + help + Support for stm32mp15x SoC family clocks. + +endif + diff --git a/drivers/clk/stm32/Makefile b/drivers/clk/stm32/Makefile index 95bd2230bba073..5ced7fe3ddec66 100644 --- a/drivers/clk/stm32/Makefile +++ b/drivers/clk/stm32/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_COMMON_CLK_STM32MP135) += clk-stm32mp13.o clk-stm32-core.o reset-stm32.o +obj-$(CONFIG_COMMON_CLK_STM32MP157) += clk-stm32mp1.o reset-stm32.o diff --git a/drivers/clk/stm32/clk-stm32-core.c b/drivers/clk/stm32/clk-stm32-core.c index 067b918a889456..58705fcad334d8 100644 --- a/drivers/clk/stm32/clk-stm32-core.c +++ b/drivers/clk/stm32/clk-stm32-core.c @@ -70,6 +70,7 @@ static int stm32_rcc_clock_init(struct device *dev, int stm32_rcc_init(struct device *dev, const struct of_device_id *match_data, void __iomem *base) { + const struct stm32_rcc_match_data *rcc_match_data; const struct of_device_id *match; int err; @@ -79,8 +80,10 @@ int stm32_rcc_init(struct device *dev, const struct of_device_id *match_data, return -ENODEV; } + rcc_match_data = match->data; + /* RCC Reset Configuration */ - err = stm32_rcc_reset_init(dev, match, base); + err = stm32_rcc_reset_init(dev, rcc_match_data->reset_data, base); if (err) { pr_err("stm32 reset failed to initialize\n"); return err; diff --git a/drivers/clk/stm32/clk-stm32-core.h b/drivers/clk/stm32/clk-stm32-core.h index 76cffda0230848..bb5aa19a792d17 100644 --- a/drivers/clk/stm32/clk-stm32-core.h +++ b/drivers/clk/stm32/clk-stm32-core.h @@ -70,15 +70,12 @@ struct stm32_rcc_match_data { const struct clock_config *tab_clocks; unsigned int maxbinding; struct clk_stm32_clock_data *clock_data; - u32 clear_offset; + struct clk_stm32_reset_data *reset_data; int (*check_security)(void __iomem *base, const struct clock_config *cfg); int (*multi_mux)(void __iomem *base, const struct clock_config *cfg); }; -int stm32_rcc_reset_init(struct device *dev, const struct of_device_id *match, - void __iomem *base); - int stm32_rcc_init(struct device *dev, const struct of_device_id *match_data, void __iomem *base); diff --git a/drivers/clk/stm32/clk-stm32mp1.c b/drivers/clk/stm32/clk-stm32mp1.c new file mode 100644 index 00000000000000..7e2337297402a0 --- /dev/null +++ b/drivers/clk/stm32/clk-stm32mp1.c @@ -0,0 +1,2364 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved + * Author: Olivier Bideau for STMicroelectronics. + * Author: Gabriel Fernandez for STMicroelectronics. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "reset-stm32.h" + +#define STM32MP1_RESET_ID_MASK GENMASK(15, 0) + +static DEFINE_SPINLOCK(rlock); + +#define RCC_OCENSETR 0x0C +#define RCC_HSICFGR 0x18 +#define RCC_RDLSICR 0x144 +#define RCC_PLL1CR 0x80 +#define RCC_PLL1CFGR1 0x84 +#define RCC_PLL1CFGR2 0x88 +#define RCC_PLL2CR 0x94 +#define RCC_PLL2CFGR1 0x98 +#define RCC_PLL2CFGR2 0x9C +#define RCC_PLL3CR 0x880 +#define RCC_PLL3CFGR1 0x884 +#define RCC_PLL3CFGR2 0x888 +#define RCC_PLL4CR 0x894 +#define RCC_PLL4CFGR1 0x898 +#define RCC_PLL4CFGR2 0x89C +#define RCC_APB1ENSETR 0xA00 +#define RCC_APB2ENSETR 0xA08 +#define RCC_APB3ENSETR 0xA10 +#define RCC_APB4ENSETR 0x200 +#define RCC_APB5ENSETR 0x208 +#define RCC_AHB2ENSETR 0xA18 +#define RCC_AHB3ENSETR 0xA20 +#define RCC_AHB4ENSETR 0xA28 +#define RCC_AHB5ENSETR 0x210 +#define RCC_AHB6ENSETR 0x218 +#define RCC_AHB6LPENSETR 0x318 +#define RCC_RCK12SELR 0x28 +#define RCC_RCK3SELR 0x820 +#define RCC_RCK4SELR 0x824 +#define RCC_MPCKSELR 0x20 +#define RCC_ASSCKSELR 0x24 +#define RCC_MSSCKSELR 0x48 +#define RCC_SPI6CKSELR 0xC4 +#define RCC_SDMMC12CKSELR 0x8F4 +#define RCC_SDMMC3CKSELR 0x8F8 +#define RCC_FMCCKSELR 0x904 +#define RCC_I2C46CKSELR 0xC0 +#define RCC_I2C12CKSELR 0x8C0 +#define RCC_I2C35CKSELR 0x8C4 +#define RCC_UART1CKSELR 0xC8 +#define RCC_QSPICKSELR 0x900 +#define RCC_ETHCKSELR 0x8FC +#define RCC_RNG1CKSELR 0xCC +#define RCC_RNG2CKSELR 0x920 +#define RCC_GPUCKSELR 0x938 +#define RCC_USBCKSELR 0x91C +#define RCC_STGENCKSELR 0xD4 +#define RCC_SPDIFCKSELR 0x914 +#define RCC_SPI2S1CKSELR 0x8D8 +#define RCC_SPI2S23CKSELR 0x8DC +#define RCC_SPI2S45CKSELR 0x8E0 +#define RCC_CECCKSELR 0x918 +#define RCC_LPTIM1CKSELR 0x934 +#define RCC_LPTIM23CKSELR 0x930 +#define RCC_LPTIM45CKSELR 0x92C +#define RCC_UART24CKSELR 0x8E8 +#define RCC_UART35CKSELR 0x8EC +#define RCC_UART6CKSELR 0x8E4 +#define RCC_UART78CKSELR 0x8F0 +#define RCC_FDCANCKSELR 0x90C +#define RCC_SAI1CKSELR 0x8C8 +#define RCC_SAI2CKSELR 0x8CC +#define RCC_SAI3CKSELR 0x8D0 +#define RCC_SAI4CKSELR 0x8D4 +#define RCC_ADCCKSELR 0x928 +#define RCC_MPCKDIVR 0x2C +#define RCC_DSICKSELR 0x924 +#define RCC_CPERCKSELR 0xD0 +#define RCC_MCO1CFGR 0x800 +#define RCC_MCO2CFGR 0x804 +#define RCC_BDCR 0x140 +#define RCC_AXIDIVR 0x30 +#define RCC_MCUDIVR 0x830 +#define RCC_APB1DIVR 0x834 +#define RCC_APB2DIVR 0x838 +#define RCC_APB3DIVR 0x83C +#define RCC_APB4DIVR 0x3C +#define RCC_APB5DIVR 0x40 +#define RCC_TIMG1PRER 0x828 +#define RCC_TIMG2PRER 0x82C +#define RCC_RTCDIVR 0x44 +#define RCC_DBGCFGR 0x80C + +#define RCC_CLR 0x4 + +static const char * const ref12_parents[] = { + "ck_hsi", "ck_hse" +}; + +static const char * const ref3_parents[] = { + "ck_hsi", "ck_hse", "ck_csi" +}; + +static const char * const ref4_parents[] = { + "ck_hsi", "ck_hse", "ck_csi" +}; + +static const char * const cpu_src[] = { + "ck_hsi", "ck_hse", "pll1_p" +}; + +static const char * const axi_src[] = { + "ck_hsi", "ck_hse", "pll2_p" +}; + +static const char * const per_src[] = { + "ck_hsi", "ck_csi", "ck_hse" +}; + +static const char * const mcu_src[] = { + "ck_hsi", "ck_hse", "ck_csi", "pll3_p" +}; + +static const char * const sdmmc12_src[] = { + "ck_axi", "pll3_r", "pll4_p", "ck_hsi" +}; + +static const char * const sdmmc3_src[] = { + "ck_mcu", "pll3_r", "pll4_p", "ck_hsi" +}; + +static const char * const fmc_src[] = { + "ck_axi", "pll3_r", "pll4_p", "ck_per" +}; + +static const char * const qspi_src[] = { + "ck_axi", "pll3_r", "pll4_p", "ck_per" +}; + +static const char * const eth_src[] = { + "pll4_p", "pll3_q" +}; + +static const struct clk_parent_data ethrx_src[] = { + { .name = "ethck_k", .fw_name = "ETH_RX_CLK/ETH_REF_CLK" }, +}; + +static const char * const rng_src[] = { + "ck_csi", "pll4_r", "ck_lse", "ck_lsi" +}; + +static const char * const usbphy_src[] = { + "ck_hse", "pll4_r", "clk-hse-div2" +}; + +static const char * const usbo_src[] = { + "pll4_r", "ck_usbo_48m" +}; + +static const char * const stgen_src[] = { + "ck_hsi", "ck_hse" +}; + +static const char * const spdif_src[] = { + "pll4_p", "pll3_q", "ck_hsi" +}; + +static const char * const spi123_src[] = { + "pll4_p", "pll3_q", "i2s_ckin", "ck_per", "pll3_r" +}; + +static const char * const spi45_src[] = { + "pclk2", "pll4_q", "ck_hsi", "ck_csi", "ck_hse" +}; + +static const char * const spi6_src[] = { + "pclk5", "pll4_q", "ck_hsi", "ck_csi", "ck_hse", "pll3_q" +}; + +static const char * const cec_src[] = { + "ck_lse", "ck_lsi", "ck_csi" +}; + +static const char * const i2c12_src[] = { + "pclk1", "pll4_r", "ck_hsi", "ck_csi" +}; + +static const char * const i2c35_src[] = { + "pclk1", "pll4_r", "ck_hsi", "ck_csi" +}; + +static const char * const i2c46_src[] = { + "pclk5", "pll3_q", "ck_hsi", "ck_csi" +}; + +static const char * const lptim1_src[] = { + "pclk1", "pll4_p", "pll3_q", "ck_lse", "ck_lsi", "ck_per" +}; + +static const char * const lptim23_src[] = { + "pclk3", "pll4_q", "ck_per", "ck_lse", "ck_lsi" +}; + +static const char * const lptim45_src[] = { + "pclk3", "pll4_p", "pll3_q", "ck_lse", "ck_lsi", "ck_per" +}; + +static const char * const usart1_src[] = { + "pclk5", "pll3_q", "ck_hsi", "ck_csi", "pll4_q", "ck_hse" +}; + +static const char * const usart234578_src[] = { + "pclk1", "pll4_q", "ck_hsi", "ck_csi", "ck_hse" +}; + +static const char * const usart6_src[] = { + "pclk2", "pll4_q", "ck_hsi", "ck_csi", "ck_hse" +}; + +static const char * const fdcan_src[] = { + "ck_hse", "pll3_q", "pll4_q", "pll4_r" +}; + +static const char * const sai_src[] = { + "pll4_q", "pll3_q", "i2s_ckin", "ck_per", "pll3_r" +}; + +static const char * const sai2_src[] = { + "pll4_q", "pll3_q", "i2s_ckin", "ck_per", "spdif_ck_symb", "pll3_r" +}; + +static const char * const adc12_src[] = { + "pll4_r", "ck_per", "pll3_q" +}; + +static const char * const dsi_src[] = { + "ck_dsi_phy", "pll4_p" +}; + +static const char * const rtc_src[] = { + "off", "ck_lse", "ck_lsi", "ck_hse" +}; + +static const char * const mco1_src[] = { + "ck_hsi", "ck_hse", "ck_csi", "ck_lsi", "ck_lse" +}; + +static const char * const mco2_src[] = { + "ck_mpu", "ck_axi", "ck_mcu", "pll4_p", "ck_hse", "ck_hsi" +}; + +static const char * const ck_trace_src[] = { + "ck_axi" +}; + +static const struct clk_div_table axi_div_table[] = { + { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 }, + { 4, 4 }, { 5, 4 }, { 6, 4 }, { 7, 4 }, + { 0 }, +}; + +static const struct clk_div_table mcu_div_table[] = { + { 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 8 }, + { 4, 16 }, { 5, 32 }, { 6, 64 }, { 7, 128 }, + { 8, 256 }, { 9, 512 }, { 10, 512}, { 11, 512 }, + { 12, 512 }, { 13, 512 }, { 14, 512}, { 15, 512 }, + { 0 }, +}; + +static const struct clk_div_table apb_div_table[] = { + { 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 8 }, + { 4, 16 }, { 5, 16 }, { 6, 16 }, { 7, 16 }, + { 0 }, +}; + +static const struct clk_div_table ck_trace_div_table[] = { + { 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 8 }, + { 4, 16 }, { 5, 16 }, { 6, 16 }, { 7, 16 }, + { 0 }, +}; + +#define MAX_MUX_CLK 2 + +struct stm32_mmux { + u8 nbr_clk; + struct clk_hw *hws[MAX_MUX_CLK]; +}; + +struct stm32_clk_mmux { + struct clk_mux mux; + struct stm32_mmux *mmux; +}; + +struct stm32_mgate { + u8 nbr_clk; + u32 flag; +}; + +struct stm32_clk_mgate { + struct clk_gate gate; + struct stm32_mgate *mgate; + u32 mask; +}; + +struct clock_config { + u32 id; + const char *name; + const char *parent_name; + const char * const *parent_names; + const struct clk_parent_data *parent_data; + int num_parents; + unsigned long flags; + void *cfg; + struct clk_hw * (*func)(struct device *dev, + struct clk_hw_onecell_data *clk_data, + void __iomem *base, spinlock_t *lock, + const struct clock_config *cfg); +}; + +#define NO_ID ~0 + +struct gate_cfg { + u32 reg_off; + u8 bit_idx; + u8 gate_flags; +}; + +struct fixed_factor_cfg { + unsigned int mult; + unsigned int div; +}; + +struct div_cfg { + u32 reg_off; + u8 shift; + u8 width; + u8 div_flags; + const struct clk_div_table *table; +}; + +struct mux_cfg { + u32 reg_off; + u8 shift; + u8 width; + u8 mux_flags; + u32 *table; +}; + +struct stm32_gate_cfg { + struct gate_cfg *gate; + struct stm32_mgate *mgate; + const struct clk_ops *ops; +}; + +struct stm32_div_cfg { + struct div_cfg *div; + const struct clk_ops *ops; +}; + +struct stm32_mux_cfg { + struct mux_cfg *mux; + struct stm32_mmux *mmux; + const struct clk_ops *ops; +}; + +/* STM32 Composite clock */ +struct stm32_composite_cfg { + const struct stm32_gate_cfg *gate; + const struct stm32_div_cfg *div; + const struct stm32_mux_cfg *mux; +}; + +static struct clk_hw * +_clk_hw_register_gate(struct device *dev, + struct clk_hw_onecell_data *clk_data, + void __iomem *base, spinlock_t *lock, + const struct clock_config *cfg) +{ + struct gate_cfg *gate_cfg = cfg->cfg; + + return clk_hw_register_gate(dev, + cfg->name, + cfg->parent_name, + cfg->flags, + gate_cfg->reg_off + base, + gate_cfg->bit_idx, + gate_cfg->gate_flags, + lock); +} + +static struct clk_hw * +_clk_hw_register_fixed_factor(struct device *dev, + struct clk_hw_onecell_data *clk_data, + void __iomem *base, spinlock_t *lock, + const struct clock_config *cfg) +{ + struct fixed_factor_cfg *ff_cfg = cfg->cfg; + + return clk_hw_register_fixed_factor(dev, cfg->name, cfg->parent_name, + cfg->flags, ff_cfg->mult, + ff_cfg->div); +} + +static struct clk_hw * +_clk_hw_register_divider_table(struct device *dev, + struct clk_hw_onecell_data *clk_data, + void __iomem *base, spinlock_t *lock, + const struct clock_config *cfg) +{ + struct div_cfg *div_cfg = cfg->cfg; + + return clk_hw_register_divider_table(dev, + cfg->name, + cfg->parent_name, + cfg->flags, + div_cfg->reg_off + base, + div_cfg->shift, + div_cfg->width, + div_cfg->div_flags, + div_cfg->table, + lock); +} + +static struct clk_hw * +_clk_hw_register_mux(struct device *dev, + struct clk_hw_onecell_data *clk_data, + void __iomem *base, spinlock_t *lock, + const struct clock_config *cfg) +{ + struct mux_cfg *mux_cfg = cfg->cfg; + + return clk_hw_register_mux(dev, cfg->name, cfg->parent_names, + cfg->num_parents, cfg->flags, + mux_cfg->reg_off + base, mux_cfg->shift, + mux_cfg->width, mux_cfg->mux_flags, lock); +} + +/* MP1 Gate clock with set & clear registers */ + +static int mp1_gate_clk_enable(struct clk_hw *hw) +{ + if (!clk_gate_ops.is_enabled(hw)) + clk_gate_ops.enable(hw); + + return 0; +} + +static void mp1_gate_clk_disable(struct clk_hw *hw) +{ + struct clk_gate *gate = to_clk_gate(hw); + unsigned long flags = 0; + + if (clk_gate_ops.is_enabled(hw)) { + spin_lock_irqsave(gate->lock, flags); + writel_relaxed(BIT(gate->bit_idx), gate->reg + RCC_CLR); + spin_unlock_irqrestore(gate->lock, flags); + } +} + +static const struct clk_ops mp1_gate_clk_ops = { + .enable = mp1_gate_clk_enable, + .disable = mp1_gate_clk_disable, + .is_enabled = clk_gate_is_enabled, +}; + +static struct clk_hw *_get_stm32_mux(struct device *dev, void __iomem *base, + const struct stm32_mux_cfg *cfg, + spinlock_t *lock) +{ + struct stm32_clk_mmux *mmux; + struct clk_mux *mux; + struct clk_hw *mux_hw; + + if (cfg->mmux) { + mmux = devm_kzalloc(dev, sizeof(*mmux), GFP_KERNEL); + if (!mmux) + return ERR_PTR(-ENOMEM); + + mmux->mux.reg = cfg->mux->reg_off + base; + mmux->mux.shift = cfg->mux->shift; + mmux->mux.mask = (1 << cfg->mux->width) - 1; + mmux->mux.flags = cfg->mux->mux_flags; + mmux->mux.table = cfg->mux->table; + mmux->mux.lock = lock; + mmux->mmux = cfg->mmux; + mux_hw = &mmux->mux.hw; + cfg->mmux->hws[cfg->mmux->nbr_clk++] = mux_hw; + + } else { + mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); + if (!mux) + return ERR_PTR(-ENOMEM); + + mux->reg = cfg->mux->reg_off + base; + mux->shift = cfg->mux->shift; + mux->mask = (1 << cfg->mux->width) - 1; + mux->flags = cfg->mux->mux_flags; + mux->table = cfg->mux->table; + mux->lock = lock; + mux_hw = &mux->hw; + } + + return mux_hw; +} + +static struct clk_hw *_get_stm32_div(struct device *dev, void __iomem *base, + const struct stm32_div_cfg *cfg, + spinlock_t *lock) +{ + struct clk_divider *div; + + div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL); + + if (!div) + return ERR_PTR(-ENOMEM); + + div->reg = cfg->div->reg_off + base; + div->shift = cfg->div->shift; + div->width = cfg->div->width; + div->flags = cfg->div->div_flags; + div->table = cfg->div->table; + div->lock = lock; + + return &div->hw; +} + +static struct clk_hw *_get_stm32_gate(struct device *dev, void __iomem *base, + const struct stm32_gate_cfg *cfg, + spinlock_t *lock) +{ + struct stm32_clk_mgate *mgate; + struct clk_gate *gate; + struct clk_hw *gate_hw; + + if (cfg->mgate) { + mgate = devm_kzalloc(dev, sizeof(*mgate), GFP_KERNEL); + if (!mgate) + return ERR_PTR(-ENOMEM); + + mgate->gate.reg = cfg->gate->reg_off + base; + mgate->gate.bit_idx = cfg->gate->bit_idx; + mgate->gate.flags = cfg->gate->gate_flags; + mgate->gate.lock = lock; + mgate->mask = BIT(cfg->mgate->nbr_clk++); + + mgate->mgate = cfg->mgate; + + gate_hw = &mgate->gate.hw; + + } else { + gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL); + if (!gate) + return ERR_PTR(-ENOMEM); + + gate->reg = cfg->gate->reg_off + base; + gate->bit_idx = cfg->gate->bit_idx; + gate->flags = cfg->gate->gate_flags; + gate->lock = lock; + + gate_hw = &gate->hw; + } + + return gate_hw; +} + +static struct clk_hw * +clk_stm32_register_gate_ops(struct device *dev, + const char *name, + const char *parent_name, + const struct clk_parent_data *parent_data, + unsigned long flags, + void __iomem *base, + const struct stm32_gate_cfg *cfg, + spinlock_t *lock) +{ + struct clk_init_data init = { NULL }; + struct clk_hw *hw; + int ret; + + init.name = name; + if (parent_name) + init.parent_names = &parent_name; + if (parent_data) + init.parent_data = parent_data; + init.num_parents = 1; + init.flags = flags; + + init.ops = &clk_gate_ops; + + if (cfg->ops) + init.ops = cfg->ops; + + hw = _get_stm32_gate(dev, base, cfg, lock); + if (IS_ERR(hw)) + return ERR_PTR(-ENOMEM); + + hw->init = &init; + + ret = clk_hw_register(dev, hw); + if (ret) + hw = ERR_PTR(ret); + + return hw; +} + +static struct clk_hw * +clk_stm32_register_composite(struct device *dev, + const char *name, const char * const *parent_names, + const struct clk_parent_data *parent_data, + int num_parents, void __iomem *base, + const struct stm32_composite_cfg *cfg, + unsigned long flags, spinlock_t *lock) +{ + const struct clk_ops *mux_ops, *div_ops, *gate_ops; + struct clk_hw *mux_hw, *div_hw, *gate_hw; + + mux_hw = NULL; + div_hw = NULL; + gate_hw = NULL; + mux_ops = NULL; + div_ops = NULL; + gate_ops = NULL; + + if (cfg->mux) { + mux_hw = _get_stm32_mux(dev, base, cfg->mux, lock); + + if (!IS_ERR(mux_hw)) { + mux_ops = &clk_mux_ops; + + if (cfg->mux->ops) + mux_ops = cfg->mux->ops; + } + } + + if (cfg->div) { + div_hw = _get_stm32_div(dev, base, cfg->div, lock); + + if (!IS_ERR(div_hw)) { + div_ops = &clk_divider_ops; + + if (cfg->div->ops) + div_ops = cfg->div->ops; + } + } + + if (cfg->gate) { + gate_hw = _get_stm32_gate(dev, base, cfg->gate, lock); + + if (!IS_ERR(gate_hw)) { + gate_ops = &clk_gate_ops; + + if (cfg->gate->ops) + gate_ops = cfg->gate->ops; + } + } + + return clk_hw_register_composite(dev, name, parent_names, num_parents, + mux_hw, mux_ops, div_hw, div_ops, + gate_hw, gate_ops, flags); +} + +#define to_clk_mgate(_gate) container_of(_gate, struct stm32_clk_mgate, gate) + +static int mp1_mgate_clk_enable(struct clk_hw *hw) +{ + struct clk_gate *gate = to_clk_gate(hw); + struct stm32_clk_mgate *clk_mgate = to_clk_mgate(gate); + + clk_mgate->mgate->flag |= clk_mgate->mask; + + mp1_gate_clk_enable(hw); + + return 0; +} + +static void mp1_mgate_clk_disable(struct clk_hw *hw) +{ + struct clk_gate *gate = to_clk_gate(hw); + struct stm32_clk_mgate *clk_mgate = to_clk_mgate(gate); + + clk_mgate->mgate->flag &= ~clk_mgate->mask; + + if (clk_mgate->mgate->flag == 0) + mp1_gate_clk_disable(hw); +} + +static const struct clk_ops mp1_mgate_clk_ops = { + .enable = mp1_mgate_clk_enable, + .disable = mp1_mgate_clk_disable, + .is_enabled = clk_gate_is_enabled, + +}; + +#define to_clk_mmux(_mux) container_of(_mux, struct stm32_clk_mmux, mux) + +static u8 clk_mmux_get_parent(struct clk_hw *hw) +{ + return clk_mux_ops.get_parent(hw); +} + +static int clk_mmux_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_mux *mux = to_clk_mux(hw); + struct stm32_clk_mmux *clk_mmux = to_clk_mmux(mux); + struct clk_hw *hwp; + int ret, n; + + ret = clk_mux_ops.set_parent(hw, index); + if (ret) + return ret; + + hwp = clk_hw_get_parent(hw); + + for (n = 0; n < clk_mmux->mmux->nbr_clk; n++) + if (clk_mmux->mmux->hws[n] != hw) + clk_hw_reparent(clk_mmux->mmux->hws[n], hwp); + + return 0; +} + +static const struct clk_ops clk_mmux_ops = { + .get_parent = clk_mmux_get_parent, + .set_parent = clk_mmux_set_parent, + .determine_rate = __clk_mux_determine_rate, +}; + +/* STM32 PLL */ +struct stm32_pll_obj { + /* lock pll enable/disable registers */ + spinlock_t *lock; + void __iomem *reg; + struct clk_hw hw; + struct clk_mux mux; +}; + +#define to_pll(_hw) container_of(_hw, struct stm32_pll_obj, hw) + +#define PLL_ON BIT(0) +#define PLL_RDY BIT(1) +#define DIVN_MASK 0x1FF +#define DIVM_MASK 0x3F +#define DIVM_SHIFT 16 +#define DIVN_SHIFT 0 +#define FRAC_OFFSET 0xC +#define FRAC_MASK 0x1FFF +#define FRAC_SHIFT 3 +#define FRACLE BIT(16) +#define PLL_MUX_SHIFT 0 +#define PLL_MUX_MASK 3 + +static int __pll_is_enabled(struct clk_hw *hw) +{ + struct stm32_pll_obj *clk_elem = to_pll(hw); + + return readl_relaxed(clk_elem->reg) & PLL_ON; +} + +#define TIMEOUT 5 + +static int pll_enable(struct clk_hw *hw) +{ + struct stm32_pll_obj *clk_elem = to_pll(hw); + u32 reg; + unsigned long flags = 0; + unsigned int timeout = TIMEOUT; + int bit_status = 0; + + spin_lock_irqsave(clk_elem->lock, flags); + + if (__pll_is_enabled(hw)) + goto unlock; + + reg = readl_relaxed(clk_elem->reg); + reg |= PLL_ON; + writel_relaxed(reg, clk_elem->reg); + + /* We can't use readl_poll_timeout() because we can be blocked if + * someone enables this clock before clocksource changes. + * Only jiffies counter is available. Jiffies are incremented by + * interruptions and enable op does not allow to be interrupted. + */ + do { + bit_status = !(readl_relaxed(clk_elem->reg) & PLL_RDY); + + if (bit_status) + udelay(120); + + } while (bit_status && --timeout); + +unlock: + spin_unlock_irqrestore(clk_elem->lock, flags); + + return bit_status; +} + +static void pll_disable(struct clk_hw *hw) +{ + struct stm32_pll_obj *clk_elem = to_pll(hw); + u32 reg; + unsigned long flags = 0; + + spin_lock_irqsave(clk_elem->lock, flags); + + reg = readl_relaxed(clk_elem->reg); + reg &= ~PLL_ON; + writel_relaxed(reg, clk_elem->reg); + + spin_unlock_irqrestore(clk_elem->lock, flags); +} + +static u32 pll_frac_val(struct clk_hw *hw) +{ + struct stm32_pll_obj *clk_elem = to_pll(hw); + u32 reg, frac = 0; + + reg = readl_relaxed(clk_elem->reg + FRAC_OFFSET); + if (reg & FRACLE) + frac = (reg >> FRAC_SHIFT) & FRAC_MASK; + + return frac; +} + +static unsigned long pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct stm32_pll_obj *clk_elem = to_pll(hw); + u32 reg; + u32 frac, divm, divn; + u64 rate, rate_frac = 0; + + reg = readl_relaxed(clk_elem->reg + 4); + + divm = ((reg >> DIVM_SHIFT) & DIVM_MASK) + 1; + divn = ((reg >> DIVN_SHIFT) & DIVN_MASK) + 1; + rate = (u64)parent_rate * divn; + + do_div(rate, divm); + + frac = pll_frac_val(hw); + if (frac) { + rate_frac = (u64)parent_rate * (u64)frac; + do_div(rate_frac, (divm * 8192)); + } + + return rate + rate_frac; +} + +static int pll_is_enabled(struct clk_hw *hw) +{ + struct stm32_pll_obj *clk_elem = to_pll(hw); + unsigned long flags = 0; + int ret; + + spin_lock_irqsave(clk_elem->lock, flags); + ret = __pll_is_enabled(hw); + spin_unlock_irqrestore(clk_elem->lock, flags); + + return ret; +} + +static u8 pll_get_parent(struct clk_hw *hw) +{ + struct stm32_pll_obj *clk_elem = to_pll(hw); + struct clk_hw *mux_hw = &clk_elem->mux.hw; + + __clk_hw_set_clk(mux_hw, hw); + + return clk_mux_ops.get_parent(mux_hw); +} + +static const struct clk_ops pll_ops = { + .enable = pll_enable, + .disable = pll_disable, + .recalc_rate = pll_recalc_rate, + .is_enabled = pll_is_enabled, + .get_parent = pll_get_parent, +}; + +static struct clk_hw *clk_register_pll(struct device *dev, const char *name, + const char * const *parent_names, + int num_parents, + void __iomem *reg, + void __iomem *mux_reg, + unsigned long flags, + spinlock_t *lock) +{ + struct stm32_pll_obj *element; + struct clk_init_data init; + struct clk_hw *hw; + int err; + + element = devm_kzalloc(dev, sizeof(*element), GFP_KERNEL); + if (!element) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &pll_ops; + init.flags = flags; + init.parent_names = parent_names; + init.num_parents = num_parents; + + element->mux.lock = lock; + element->mux.reg = mux_reg; + element->mux.shift = PLL_MUX_SHIFT; + element->mux.mask = PLL_MUX_MASK; + element->mux.flags = CLK_MUX_READ_ONLY; + element->mux.reg = mux_reg; + + element->hw.init = &init; + element->reg = reg; + element->lock = lock; + + hw = &element->hw; + err = clk_hw_register(dev, hw); + + if (err) + return ERR_PTR(err); + + return hw; +} + +/* Kernel Timer */ +struct timer_cker { + /* lock the kernel output divider register */ + spinlock_t *lock; + void __iomem *apbdiv; + void __iomem *timpre; + struct clk_hw hw; +}; + +#define to_timer_cker(_hw) container_of(_hw, struct timer_cker, hw) + +#define APB_DIV_MASK 0x07 +#define TIM_PRE_MASK 0x01 + +static unsigned long __bestmult(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct timer_cker *tim_ker = to_timer_cker(hw); + u32 prescaler; + unsigned int mult = 0; + + prescaler = readl_relaxed(tim_ker->apbdiv) & APB_DIV_MASK; + if (prescaler < 2) + return 1; + + mult = 2; + + if (rate / parent_rate >= 4) + mult = 4; + + return mult; +} + +static long timer_ker_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + unsigned long factor = __bestmult(hw, rate, *parent_rate); + + return *parent_rate * factor; +} + +static int timer_ker_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct timer_cker *tim_ker = to_timer_cker(hw); + unsigned long flags = 0; + unsigned long factor = __bestmult(hw, rate, parent_rate); + int ret = 0; + + spin_lock_irqsave(tim_ker->lock, flags); + + switch (factor) { + case 1: + break; + case 2: + writel_relaxed(0, tim_ker->timpre); + break; + case 4: + writel_relaxed(1, tim_ker->timpre); + break; + default: + ret = -EINVAL; + } + spin_unlock_irqrestore(tim_ker->lock, flags); + + return ret; +} + +static unsigned long timer_ker_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct timer_cker *tim_ker = to_timer_cker(hw); + u32 prescaler, timpre; + u32 mul; + + prescaler = readl_relaxed(tim_ker->apbdiv) & APB_DIV_MASK; + + timpre = readl_relaxed(tim_ker->timpre) & TIM_PRE_MASK; + + if (!prescaler) + return parent_rate; + + mul = (timpre + 1) * 2; + + return parent_rate * mul; +} + +static const struct clk_ops timer_ker_ops = { + .recalc_rate = timer_ker_recalc_rate, + .round_rate = timer_ker_round_rate, + .set_rate = timer_ker_set_rate, + +}; + +static struct clk_hw *clk_register_cktim(struct device *dev, const char *name, + const char *parent_name, + unsigned long flags, + void __iomem *apbdiv, + void __iomem *timpre, + spinlock_t *lock) +{ + struct timer_cker *tim_ker; + struct clk_init_data init; + struct clk_hw *hw; + int err; + + tim_ker = devm_kzalloc(dev, sizeof(*tim_ker), GFP_KERNEL); + if (!tim_ker) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &timer_ker_ops; + init.flags = flags; + init.parent_names = &parent_name; + init.num_parents = 1; + + tim_ker->hw.init = &init; + tim_ker->lock = lock; + tim_ker->apbdiv = apbdiv; + tim_ker->timpre = timpre; + + hw = &tim_ker->hw; + err = clk_hw_register(dev, hw); + + if (err) + return ERR_PTR(err); + + return hw; +} + +/* The divider of RTC clock concerns only ck_hse clock */ +#define HSE_RTC 3 + +static unsigned long clk_divider_rtc_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + if (clk_hw_get_parent(hw) == clk_hw_get_parent_by_index(hw, HSE_RTC)) + return clk_divider_ops.recalc_rate(hw, parent_rate); + + return parent_rate; +} + +static int clk_divider_rtc_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + if (clk_hw_get_parent(hw) == clk_hw_get_parent_by_index(hw, HSE_RTC)) + return clk_divider_ops.set_rate(hw, rate, parent_rate); + + return parent_rate; +} + +static int clk_divider_rtc_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) +{ + if (req->best_parent_hw == clk_hw_get_parent_by_index(hw, HSE_RTC)) + return clk_divider_ops.determine_rate(hw, req); + + req->rate = req->best_parent_rate; + + return 0; +} + +static const struct clk_ops rtc_div_clk_ops = { + .recalc_rate = clk_divider_rtc_recalc_rate, + .set_rate = clk_divider_rtc_set_rate, + .determine_rate = clk_divider_rtc_determine_rate +}; + +struct stm32_pll_cfg { + u32 offset; + u32 muxoff; +}; + +static struct clk_hw *_clk_register_pll(struct device *dev, + struct clk_hw_onecell_data *clk_data, + void __iomem *base, spinlock_t *lock, + const struct clock_config *cfg) +{ + struct stm32_pll_cfg *stm_pll_cfg = cfg->cfg; + + return clk_register_pll(dev, cfg->name, cfg->parent_names, + cfg->num_parents, + base + stm_pll_cfg->offset, + base + stm_pll_cfg->muxoff, + cfg->flags, lock); +} + +struct stm32_cktim_cfg { + u32 offset_apbdiv; + u32 offset_timpre; +}; + +static struct clk_hw *_clk_register_cktim(struct device *dev, + struct clk_hw_onecell_data *clk_data, + void __iomem *base, spinlock_t *lock, + const struct clock_config *cfg) +{ + struct stm32_cktim_cfg *cktim_cfg = cfg->cfg; + + return clk_register_cktim(dev, cfg->name, cfg->parent_name, cfg->flags, + cktim_cfg->offset_apbdiv + base, + cktim_cfg->offset_timpre + base, lock); +} + +static struct clk_hw * +_clk_stm32_register_gate(struct device *dev, + struct clk_hw_onecell_data *clk_data, + void __iomem *base, spinlock_t *lock, + const struct clock_config *cfg) +{ + return clk_stm32_register_gate_ops(dev, + cfg->name, + cfg->parent_name, + cfg->parent_data, + cfg->flags, + base, + cfg->cfg, + lock); +} + +static struct clk_hw * +_clk_stm32_register_composite(struct device *dev, + struct clk_hw_onecell_data *clk_data, + void __iomem *base, spinlock_t *lock, + const struct clock_config *cfg) +{ + return clk_stm32_register_composite(dev, cfg->name, cfg->parent_names, + cfg->parent_data, cfg->num_parents, + base, cfg->cfg, cfg->flags, lock); +} + +#define GATE(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\ +{\ + .id = _id,\ + .name = _name,\ + .parent_name = _parent,\ + .flags = _flags,\ + .cfg = &(struct gate_cfg) {\ + .reg_off = _offset,\ + .bit_idx = _bit_idx,\ + .gate_flags = _gate_flags,\ + },\ + .func = _clk_hw_register_gate,\ +} + +#define FIXED_FACTOR(_id, _name, _parent, _flags, _mult, _div)\ +{\ + .id = _id,\ + .name = _name,\ + .parent_name = _parent,\ + .flags = _flags,\ + .cfg = &(struct fixed_factor_cfg) {\ + .mult = _mult,\ + .div = _div,\ + },\ + .func = _clk_hw_register_fixed_factor,\ +} + +#define DIV_TABLE(_id, _name, _parent, _flags, _offset, _shift, _width,\ + _div_flags, _div_table)\ +{\ + .id = _id,\ + .name = _name,\ + .parent_name = _parent,\ + .flags = _flags,\ + .cfg = &(struct div_cfg) {\ + .reg_off = _offset,\ + .shift = _shift,\ + .width = _width,\ + .div_flags = _div_flags,\ + .table = _div_table,\ + },\ + .func = _clk_hw_register_divider_table,\ +} + +#define DIV(_id, _name, _parent, _flags, _offset, _shift, _width, _div_flags)\ + DIV_TABLE(_id, _name, _parent, _flags, _offset, _shift, _width,\ + _div_flags, NULL) + +#define MUX(_id, _name, _parents, _flags, _offset, _shift, _width, _mux_flags)\ +{\ + .id = _id,\ + .name = _name,\ + .parent_names = _parents,\ + .num_parents = ARRAY_SIZE(_parents),\ + .flags = _flags,\ + .cfg = &(struct mux_cfg) {\ + .reg_off = _offset,\ + .shift = _shift,\ + .width = _width,\ + .mux_flags = _mux_flags,\ + },\ + .func = _clk_hw_register_mux,\ +} + +#define PLL(_id, _name, _parents, _flags, _offset_p, _offset_mux)\ +{\ + .id = _id,\ + .name = _name,\ + .parent_names = _parents,\ + .num_parents = ARRAY_SIZE(_parents),\ + .flags = CLK_IGNORE_UNUSED | (_flags),\ + .cfg = &(struct stm32_pll_cfg) {\ + .offset = _offset_p,\ + .muxoff = _offset_mux,\ + },\ + .func = _clk_register_pll,\ +} + +#define STM32_CKTIM(_name, _parent, _flags, _offset_apbdiv, _offset_timpre)\ +{\ + .id = NO_ID,\ + .name = _name,\ + .parent_name = _parent,\ + .flags = _flags,\ + .cfg = &(struct stm32_cktim_cfg) {\ + .offset_apbdiv = _offset_apbdiv,\ + .offset_timpre = _offset_timpre,\ + },\ + .func = _clk_register_cktim,\ +} + +#define STM32_TIM(_id, _name, _parent, _offset_set, _bit_idx)\ + GATE_MP1(_id, _name, _parent, CLK_SET_RATE_PARENT,\ + _offset_set, _bit_idx, 0) + +/* STM32 GATE */ +#define STM32_GATE(_id, _name, _parent, _flags, _gate)\ +{\ + .id = _id,\ + .name = _name,\ + .parent_name = _parent,\ + .flags = _flags,\ + .cfg = (struct stm32_gate_cfg *) {_gate},\ + .func = _clk_stm32_register_gate,\ +} + +#define STM32_GATE_PDATA(_id, _name, _parent, _flags, _gate)\ +{\ + .id = _id,\ + .name = _name,\ + .parent_data = _parent,\ + .flags = _flags,\ + .cfg = (struct stm32_gate_cfg *) {_gate},\ + .func = _clk_stm32_register_gate,\ +} + +#define _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags, _mgate, _ops)\ + (&(struct stm32_gate_cfg) {\ + &(struct gate_cfg) {\ + .reg_off = _gate_offset,\ + .bit_idx = _gate_bit_idx,\ + .gate_flags = _gate_flags,\ + },\ + .mgate = _mgate,\ + .ops = _ops,\ + }) + +#define _STM32_MGATE(_mgate)\ + (&per_gate_cfg[_mgate]) + +#define _GATE(_gate_offset, _gate_bit_idx, _gate_flags)\ + _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags,\ + NULL, NULL)\ + +#define _GATE_MP1(_gate_offset, _gate_bit_idx, _gate_flags)\ + _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags,\ + NULL, &mp1_gate_clk_ops)\ + +#define _MGATE_MP1(_mgate)\ + .gate = &per_gate_cfg[_mgate] + +#define GATE_MP1(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\ + STM32_GATE(_id, _name, _parent, _flags,\ + _GATE_MP1(_offset, _bit_idx, _gate_flags)) + +#define MGATE_MP1(_id, _name, _parent, _flags, _mgate)\ + STM32_GATE(_id, _name, _parent, _flags,\ + _STM32_MGATE(_mgate)) + +#define MGATE_MP1_PDATA(_id, _name, _parent, _flags, _mgate)\ + STM32_GATE_PDATA(_id, _name, _parent, _flags,\ + _STM32_MGATE(_mgate)) + +#define _STM32_DIV(_div_offset, _div_shift, _div_width,\ + _div_flags, _div_table, _ops)\ + .div = &(struct stm32_div_cfg) {\ + &(struct div_cfg) {\ + .reg_off = _div_offset,\ + .shift = _div_shift,\ + .width = _div_width,\ + .div_flags = _div_flags,\ + .table = _div_table,\ + },\ + .ops = _ops,\ + } + +#define _DIV(_div_offset, _div_shift, _div_width, _div_flags, _div_table)\ + _STM32_DIV(_div_offset, _div_shift, _div_width,\ + _div_flags, _div_table, NULL)\ + +#define _DIV_RTC(_div_offset, _div_shift, _div_width, _div_flags, _div_table)\ + _STM32_DIV(_div_offset, _div_shift, _div_width,\ + _div_flags, _div_table, &rtc_div_clk_ops) + +#define _STM32_MUX(_offset, _shift, _width, _mux_flags, _mmux, _ops)\ + .mux = &(struct stm32_mux_cfg) {\ + &(struct mux_cfg) {\ + .reg_off = _offset,\ + .shift = _shift,\ + .width = _width,\ + .mux_flags = _mux_flags,\ + .table = NULL,\ + },\ + .mmux = _mmux,\ + .ops = _ops,\ + } + +#define _MUX(_offset, _shift, _width, _mux_flags)\ + _STM32_MUX(_offset, _shift, _width, _mux_flags, NULL, NULL)\ + +#define _MMUX(_mmux) .mux = &ker_mux_cfg[_mmux] + +#define PARENT(_parent) ((const char *[]) { _parent}) + +#define _NO_MUX .mux = NULL +#define _NO_DIV .div = NULL +#define _NO_GATE .gate = NULL + +#define COMPOSITE(_id, _name, _parents, _flags, _gate, _mux, _div)\ +{\ + .id = _id,\ + .name = _name,\ + .parent_names = _parents,\ + .num_parents = ARRAY_SIZE(_parents),\ + .flags = _flags,\ + .cfg = &(struct stm32_composite_cfg) {\ + _gate,\ + _mux,\ + _div,\ + },\ + .func = _clk_stm32_register_composite,\ +} + +#define PCLK(_id, _name, _parent, _flags, _mgate)\ + MGATE_MP1(_id, _name, _parent, _flags, _mgate) + +#define PCLK_PDATA(_id, _name, _parent, _flags, _mgate)\ + MGATE_MP1_PDATA(_id, _name, _parent, _flags, _mgate) + +#define KCLK(_id, _name, _parents, _flags, _mgate, _mmux)\ + COMPOSITE(_id, _name, _parents, CLK_OPS_PARENT_ENABLE |\ + CLK_SET_RATE_NO_REPARENT | _flags,\ + _MGATE_MP1(_mgate),\ + _MMUX(_mmux),\ + _NO_DIV) + +enum { + G_SAI1, + G_SAI2, + G_SAI3, + G_SAI4, + G_SPI1, + G_SPI2, + G_SPI3, + G_SPI4, + G_SPI5, + G_SPI6, + G_SPDIF, + G_I2C1, + G_I2C2, + G_I2C3, + G_I2C4, + G_I2C5, + G_I2C6, + G_USART2, + G_UART4, + G_USART3, + G_UART5, + G_USART1, + G_USART6, + G_UART7, + G_UART8, + G_LPTIM1, + G_LPTIM2, + G_LPTIM3, + G_LPTIM4, + G_LPTIM5, + G_LTDC, + G_DSI, + G_QSPI, + G_FMC, + G_SDMMC1, + G_SDMMC2, + G_SDMMC3, + G_USBO, + G_USBPHY, + G_RNG1, + G_RNG2, + G_FDCAN, + G_DAC12, + G_CEC, + G_ADC12, + G_GPU, + G_STGEN, + G_DFSDM, + G_ADFSDM, + G_TIM2, + G_TIM3, + G_TIM4, + G_TIM5, + G_TIM6, + G_TIM7, + G_TIM12, + G_TIM13, + G_TIM14, + G_MDIO, + G_TIM1, + G_TIM8, + G_TIM15, + G_TIM16, + G_TIM17, + G_SYSCFG, + G_VREF, + G_TMPSENS, + G_PMBCTRL, + G_HDP, + G_IWDG2, + G_STGENRO, + G_DMA1, + G_DMA2, + G_DMAMUX, + G_DCMI, + G_CRYP2, + G_HASH2, + G_CRC2, + G_HSEM, + G_IPCC, + G_GPIOA, + G_GPIOB, + G_GPIOC, + G_GPIOD, + G_GPIOE, + G_GPIOF, + G_GPIOG, + G_GPIOH, + G_GPIOI, + G_GPIOJ, + G_GPIOK, + G_MDMA, + G_ETHCK, + G_ETHTX, + G_ETHRX, + G_ETHMAC, + G_CRC1, + G_USBH, + G_ETHSTP, + G_RTCAPB, + G_TZC1, + G_TZC2, + G_TZPC, + G_IWDG1, + G_BSEC, + G_GPIOZ, + G_CRYP1, + G_HASH1, + G_BKPSRAM, + G_DDRPERFM, + + G_LAST +}; + +static struct stm32_mgate mp1_mgate[G_LAST]; + +#define _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ + _mgate, _ops)\ + [_id] = {\ + &(struct gate_cfg) {\ + .reg_off = _gate_offset,\ + .bit_idx = _gate_bit_idx,\ + .gate_flags = _gate_flags,\ + },\ + .mgate = _mgate,\ + .ops = _ops,\ + } + +#define K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags)\ + _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ + NULL, &mp1_gate_clk_ops) + +#define K_MGATE(_id, _gate_offset, _gate_bit_idx, _gate_flags)\ + _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ + &mp1_mgate[_id], &mp1_mgate_clk_ops) + +/* Peripheral gates */ +static struct stm32_gate_cfg per_gate_cfg[G_LAST] = { + /* Multi gates */ + K_GATE(G_MDIO, RCC_APB1ENSETR, 31, 0), + K_MGATE(G_DAC12, RCC_APB1ENSETR, 29, 0), + K_MGATE(G_CEC, RCC_APB1ENSETR, 27, 0), + K_MGATE(G_SPDIF, RCC_APB1ENSETR, 26, 0), + K_MGATE(G_I2C5, RCC_APB1ENSETR, 24, 0), + K_MGATE(G_I2C3, RCC_APB1ENSETR, 23, 0), + K_MGATE(G_I2C2, RCC_APB1ENSETR, 22, 0), + K_MGATE(G_I2C1, RCC_APB1ENSETR, 21, 0), + K_MGATE(G_UART8, RCC_APB1ENSETR, 19, 0), + K_MGATE(G_UART7, RCC_APB1ENSETR, 18, 0), + K_MGATE(G_UART5, RCC_APB1ENSETR, 17, 0), + K_MGATE(G_UART4, RCC_APB1ENSETR, 16, 0), + K_MGATE(G_USART3, RCC_APB1ENSETR, 15, 0), + K_MGATE(G_USART2, RCC_APB1ENSETR, 14, 0), + K_MGATE(G_SPI3, RCC_APB1ENSETR, 12, 0), + K_MGATE(G_SPI2, RCC_APB1ENSETR, 11, 0), + K_MGATE(G_LPTIM1, RCC_APB1ENSETR, 9, 0), + K_GATE(G_TIM14, RCC_APB1ENSETR, 8, 0), + K_GATE(G_TIM13, RCC_APB1ENSETR, 7, 0), + K_GATE(G_TIM12, RCC_APB1ENSETR, 6, 0), + K_GATE(G_TIM7, RCC_APB1ENSETR, 5, 0), + K_GATE(G_TIM6, RCC_APB1ENSETR, 4, 0), + K_GATE(G_TIM5, RCC_APB1ENSETR, 3, 0), + K_GATE(G_TIM4, RCC_APB1ENSETR, 2, 0), + K_GATE(G_TIM3, RCC_APB1ENSETR, 1, 0), + K_GATE(G_TIM2, RCC_APB1ENSETR, 0, 0), + + K_MGATE(G_FDCAN, RCC_APB2ENSETR, 24, 0), + K_GATE(G_ADFSDM, RCC_APB2ENSETR, 21, 0), + K_GATE(G_DFSDM, RCC_APB2ENSETR, 20, 0), + K_MGATE(G_SAI3, RCC_APB2ENSETR, 18, 0), + K_MGATE(G_SAI2, RCC_APB2ENSETR, 17, 0), + K_MGATE(G_SAI1, RCC_APB2ENSETR, 16, 0), + K_MGATE(G_USART6, RCC_APB2ENSETR, 13, 0), + K_MGATE(G_SPI5, RCC_APB2ENSETR, 10, 0), + K_MGATE(G_SPI4, RCC_APB2ENSETR, 9, 0), + K_MGATE(G_SPI1, RCC_APB2ENSETR, 8, 0), + K_GATE(G_TIM17, RCC_APB2ENSETR, 4, 0), + K_GATE(G_TIM16, RCC_APB2ENSETR, 3, 0), + K_GATE(G_TIM15, RCC_APB2ENSETR, 2, 0), + K_GATE(G_TIM8, RCC_APB2ENSETR, 1, 0), + K_GATE(G_TIM1, RCC_APB2ENSETR, 0, 0), + + K_GATE(G_HDP, RCC_APB3ENSETR, 20, 0), + K_GATE(G_PMBCTRL, RCC_APB3ENSETR, 17, 0), + K_GATE(G_TMPSENS, RCC_APB3ENSETR, 16, 0), + K_GATE(G_VREF, RCC_APB3ENSETR, 13, 0), + K_GATE(G_SYSCFG, RCC_APB3ENSETR, 11, 0), + K_MGATE(G_SAI4, RCC_APB3ENSETR, 8, 0), + K_MGATE(G_LPTIM5, RCC_APB3ENSETR, 3, 0), + K_MGATE(G_LPTIM4, RCC_APB3ENSETR, 2, 0), + K_MGATE(G_LPTIM3, RCC_APB3ENSETR, 1, 0), + K_MGATE(G_LPTIM2, RCC_APB3ENSETR, 0, 0), + + K_GATE(G_STGENRO, RCC_APB4ENSETR, 20, 0), + K_MGATE(G_USBPHY, RCC_APB4ENSETR, 16, 0), + K_GATE(G_IWDG2, RCC_APB4ENSETR, 15, 0), + K_GATE(G_DDRPERFM, RCC_APB4ENSETR, 8, 0), + K_MGATE(G_DSI, RCC_APB4ENSETR, 4, 0), + K_MGATE(G_LTDC, RCC_APB4ENSETR, 0, 0), + + K_GATE(G_STGEN, RCC_APB5ENSETR, 20, 0), + K_GATE(G_BSEC, RCC_APB5ENSETR, 16, 0), + K_GATE(G_IWDG1, RCC_APB5ENSETR, 15, 0), + K_GATE(G_TZPC, RCC_APB5ENSETR, 13, 0), + K_GATE(G_TZC2, RCC_APB5ENSETR, 12, 0), + K_GATE(G_TZC1, RCC_APB5ENSETR, 11, 0), + K_GATE(G_RTCAPB, RCC_APB5ENSETR, 8, 0), + K_MGATE(G_USART1, RCC_APB5ENSETR, 4, 0), + K_MGATE(G_I2C6, RCC_APB5ENSETR, 3, 0), + K_MGATE(G_I2C4, RCC_APB5ENSETR, 2, 0), + K_MGATE(G_SPI6, RCC_APB5ENSETR, 0, 0), + + K_MGATE(G_SDMMC3, RCC_AHB2ENSETR, 16, 0), + K_MGATE(G_USBO, RCC_AHB2ENSETR, 8, 0), + K_MGATE(G_ADC12, RCC_AHB2ENSETR, 5, 0), + K_GATE(G_DMAMUX, RCC_AHB2ENSETR, 2, 0), + K_GATE(G_DMA2, RCC_AHB2ENSETR, 1, 0), + K_GATE(G_DMA1, RCC_AHB2ENSETR, 0, 0), + + K_GATE(G_IPCC, RCC_AHB3ENSETR, 12, 0), + K_GATE(G_HSEM, RCC_AHB3ENSETR, 11, 0), + K_GATE(G_CRC2, RCC_AHB3ENSETR, 7, 0), + K_MGATE(G_RNG2, RCC_AHB3ENSETR, 6, 0), + K_GATE(G_HASH2, RCC_AHB3ENSETR, 5, 0), + K_GATE(G_CRYP2, RCC_AHB3ENSETR, 4, 0), + K_GATE(G_DCMI, RCC_AHB3ENSETR, 0, 0), + + K_GATE(G_GPIOK, RCC_AHB4ENSETR, 10, 0), + K_GATE(G_GPIOJ, RCC_AHB4ENSETR, 9, 0), + K_GATE(G_GPIOI, RCC_AHB4ENSETR, 8, 0), + K_GATE(G_GPIOH, RCC_AHB4ENSETR, 7, 0), + K_GATE(G_GPIOG, RCC_AHB4ENSETR, 6, 0), + K_GATE(G_GPIOF, RCC_AHB4ENSETR, 5, 0), + K_GATE(G_GPIOE, RCC_AHB4ENSETR, 4, 0), + K_GATE(G_GPIOD, RCC_AHB4ENSETR, 3, 0), + K_GATE(G_GPIOC, RCC_AHB4ENSETR, 2, 0), + K_GATE(G_GPIOB, RCC_AHB4ENSETR, 1, 0), + K_GATE(G_GPIOA, RCC_AHB4ENSETR, 0, 0), + + K_GATE(G_BKPSRAM, RCC_AHB5ENSETR, 8, 0), + K_MGATE(G_RNG1, RCC_AHB5ENSETR, 6, 0), + K_GATE(G_HASH1, RCC_AHB5ENSETR, 5, 0), + K_GATE(G_CRYP1, RCC_AHB5ENSETR, 4, 0), + K_GATE(G_GPIOZ, RCC_AHB5ENSETR, 0, 0), + + K_GATE(G_USBH, RCC_AHB6ENSETR, 24, 0), + K_GATE(G_CRC1, RCC_AHB6ENSETR, 20, 0), + K_MGATE(G_SDMMC2, RCC_AHB6ENSETR, 17, 0), + K_MGATE(G_SDMMC1, RCC_AHB6ENSETR, 16, 0), + K_MGATE(G_QSPI, RCC_AHB6ENSETR, 14, 0), + K_MGATE(G_FMC, RCC_AHB6ENSETR, 12, 0), + K_GATE(G_ETHMAC, RCC_AHB6ENSETR, 10, 0), + K_GATE(G_ETHRX, RCC_AHB6ENSETR, 9, 0), + K_GATE(G_ETHTX, RCC_AHB6ENSETR, 8, 0), + K_GATE(G_ETHCK, RCC_AHB6ENSETR, 7, 0), + K_MGATE(G_GPU, RCC_AHB6ENSETR, 5, 0), + K_GATE(G_MDMA, RCC_AHB6ENSETR, 0, 0), + K_GATE(G_ETHSTP, RCC_AHB6LPENSETR, 11, 0), +}; + +enum { + M_SDMMC12, + M_SDMMC3, + M_FMC, + M_QSPI, + M_RNG1, + M_RNG2, + M_USBPHY, + M_USBO, + M_STGEN, + M_SPDIF, + M_SPI1, + M_SPI23, + M_SPI45, + M_SPI6, + M_CEC, + M_I2C12, + M_I2C35, + M_I2C46, + M_LPTIM1, + M_LPTIM23, + M_LPTIM45, + M_USART1, + M_UART24, + M_UART35, + M_USART6, + M_UART78, + M_SAI1, + M_SAI2, + M_SAI3, + M_SAI4, + M_DSI, + M_FDCAN, + M_ADC12, + M_ETHCK, + M_CKPER, + M_LAST +}; + +static struct stm32_mmux ker_mux[M_LAST]; + +#define _K_MUX(_id, _offset, _shift, _width, _mux_flags, _mmux, _ops)\ + [_id] = {\ + &(struct mux_cfg) {\ + .reg_off = _offset,\ + .shift = _shift,\ + .width = _width,\ + .mux_flags = _mux_flags,\ + .table = NULL,\ + },\ + .mmux = _mmux,\ + .ops = _ops,\ + } + +#define K_MUX(_id, _offset, _shift, _width, _mux_flags)\ + _K_MUX(_id, _offset, _shift, _width, _mux_flags,\ + NULL, NULL) + +#define K_MMUX(_id, _offset, _shift, _width, _mux_flags)\ + _K_MUX(_id, _offset, _shift, _width, _mux_flags,\ + &ker_mux[_id], &clk_mmux_ops) + +static const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = { + /* Kernel multi mux */ + K_MMUX(M_SDMMC12, RCC_SDMMC12CKSELR, 0, 3, 0), + K_MMUX(M_SPI23, RCC_SPI2S23CKSELR, 0, 3, 0), + K_MMUX(M_SPI45, RCC_SPI2S45CKSELR, 0, 3, 0), + K_MMUX(M_I2C12, RCC_I2C12CKSELR, 0, 3, 0), + K_MMUX(M_I2C35, RCC_I2C35CKSELR, 0, 3, 0), + K_MMUX(M_LPTIM23, RCC_LPTIM23CKSELR, 0, 3, 0), + K_MMUX(M_LPTIM45, RCC_LPTIM45CKSELR, 0, 3, 0), + K_MMUX(M_UART24, RCC_UART24CKSELR, 0, 3, 0), + K_MMUX(M_UART35, RCC_UART35CKSELR, 0, 3, 0), + K_MMUX(M_UART78, RCC_UART78CKSELR, 0, 3, 0), + K_MMUX(M_SAI1, RCC_SAI1CKSELR, 0, 3, 0), + K_MMUX(M_ETHCK, RCC_ETHCKSELR, 0, 2, 0), + K_MMUX(M_I2C46, RCC_I2C46CKSELR, 0, 3, 0), + + /* Kernel simple mux */ + K_MUX(M_RNG2, RCC_RNG2CKSELR, 0, 2, 0), + K_MUX(M_SDMMC3, RCC_SDMMC3CKSELR, 0, 3, 0), + K_MUX(M_FMC, RCC_FMCCKSELR, 0, 2, 0), + K_MUX(M_QSPI, RCC_QSPICKSELR, 0, 2, 0), + K_MUX(M_USBPHY, RCC_USBCKSELR, 0, 2, 0), + K_MUX(M_USBO, RCC_USBCKSELR, 4, 1, 0), + K_MUX(M_SPDIF, RCC_SPDIFCKSELR, 0, 2, 0), + K_MUX(M_SPI1, RCC_SPI2S1CKSELR, 0, 3, 0), + K_MUX(M_CEC, RCC_CECCKSELR, 0, 2, 0), + K_MUX(M_LPTIM1, RCC_LPTIM1CKSELR, 0, 3, 0), + K_MUX(M_USART6, RCC_UART6CKSELR, 0, 3, 0), + K_MUX(M_FDCAN, RCC_FDCANCKSELR, 0, 2, 0), + K_MUX(M_SAI2, RCC_SAI2CKSELR, 0, 3, 0), + K_MUX(M_SAI3, RCC_SAI3CKSELR, 0, 3, 0), + K_MUX(M_SAI4, RCC_SAI4CKSELR, 0, 3, 0), + K_MUX(M_ADC12, RCC_ADCCKSELR, 0, 2, 0), + K_MUX(M_DSI, RCC_DSICKSELR, 0, 1, 0), + K_MUX(M_CKPER, RCC_CPERCKSELR, 0, 2, 0), + K_MUX(M_RNG1, RCC_RNG1CKSELR, 0, 2, 0), + K_MUX(M_STGEN, RCC_STGENCKSELR, 0, 2, 0), + K_MUX(M_USART1, RCC_UART1CKSELR, 0, 3, 0), + K_MUX(M_SPI6, RCC_SPI6CKSELR, 0, 3, 0), +}; + +static const struct clock_config stm32mp1_clock_cfg[] = { + /* External / Internal Oscillators */ + GATE_MP1(CK_HSE, "ck_hse", "clk-hse", 0, RCC_OCENSETR, 8, 0), + /* ck_csi is used by IO compensation and should be critical */ + GATE_MP1(CK_CSI, "ck_csi", "clk-csi", CLK_IS_CRITICAL, + RCC_OCENSETR, 4, 0), + COMPOSITE(CK_HSI, "ck_hsi", PARENT("clk-hsi"), 0, + _GATE_MP1(RCC_OCENSETR, 0, 0), + _NO_MUX, + _DIV(RCC_HSICFGR, 0, 2, CLK_DIVIDER_POWER_OF_TWO | + CLK_DIVIDER_READ_ONLY, NULL)), + GATE(CK_LSI, "ck_lsi", "clk-lsi", 0, RCC_RDLSICR, 0, 0), + GATE(CK_LSE, "ck_lse", "clk-lse", 0, RCC_BDCR, 0, 0), + + FIXED_FACTOR(CK_HSE_DIV2, "clk-hse-div2", "ck_hse", 0, 1, 2), + + /* PLLs */ + PLL(PLL1, "pll1", ref12_parents, 0, RCC_PLL1CR, RCC_RCK12SELR), + PLL(PLL2, "pll2", ref12_parents, 0, RCC_PLL2CR, RCC_RCK12SELR), + PLL(PLL3, "pll3", ref3_parents, 0, RCC_PLL3CR, RCC_RCK3SELR), + PLL(PLL4, "pll4", ref4_parents, 0, RCC_PLL4CR, RCC_RCK4SELR), + + /* ODF */ + COMPOSITE(PLL1_P, "pll1_p", PARENT("pll1"), 0, + _GATE(RCC_PLL1CR, 4, 0), + _NO_MUX, + _DIV(RCC_PLL1CFGR2, 0, 7, 0, NULL)), + + COMPOSITE(PLL2_P, "pll2_p", PARENT("pll2"), 0, + _GATE(RCC_PLL2CR, 4, 0), + _NO_MUX, + _DIV(RCC_PLL2CFGR2, 0, 7, 0, NULL)), + + COMPOSITE(PLL2_Q, "pll2_q", PARENT("pll2"), 0, + _GATE(RCC_PLL2CR, 5, 0), + _NO_MUX, + _DIV(RCC_PLL2CFGR2, 8, 7, 0, NULL)), + + COMPOSITE(PLL2_R, "pll2_r", PARENT("pll2"), CLK_IS_CRITICAL, + _GATE(RCC_PLL2CR, 6, 0), + _NO_MUX, + _DIV(RCC_PLL2CFGR2, 16, 7, 0, NULL)), + + COMPOSITE(PLL3_P, "pll3_p", PARENT("pll3"), 0, + _GATE(RCC_PLL3CR, 4, 0), + _NO_MUX, + _DIV(RCC_PLL3CFGR2, 0, 7, 0, NULL)), + + COMPOSITE(PLL3_Q, "pll3_q", PARENT("pll3"), 0, + _GATE(RCC_PLL3CR, 5, 0), + _NO_MUX, + _DIV(RCC_PLL3CFGR2, 8, 7, 0, NULL)), + + COMPOSITE(PLL3_R, "pll3_r", PARENT("pll3"), 0, + _GATE(RCC_PLL3CR, 6, 0), + _NO_MUX, + _DIV(RCC_PLL3CFGR2, 16, 7, 0, NULL)), + + COMPOSITE(PLL4_P, "pll4_p", PARENT("pll4"), 0, + _GATE(RCC_PLL4CR, 4, 0), + _NO_MUX, + _DIV(RCC_PLL4CFGR2, 0, 7, 0, NULL)), + + COMPOSITE(PLL4_Q, "pll4_q", PARENT("pll4"), 0, + _GATE(RCC_PLL4CR, 5, 0), + _NO_MUX, + _DIV(RCC_PLL4CFGR2, 8, 7, 0, NULL)), + + COMPOSITE(PLL4_R, "pll4_r", PARENT("pll4"), 0, + _GATE(RCC_PLL4CR, 6, 0), + _NO_MUX, + _DIV(RCC_PLL4CFGR2, 16, 7, 0, NULL)), + + /* MUX system clocks */ + MUX(CK_PER, "ck_per", per_src, CLK_OPS_PARENT_ENABLE, + RCC_CPERCKSELR, 0, 2, 0), + + MUX(CK_MPU, "ck_mpu", cpu_src, CLK_OPS_PARENT_ENABLE | + CLK_IS_CRITICAL, RCC_MPCKSELR, 0, 2, 0), + + COMPOSITE(CK_AXI, "ck_axi", axi_src, CLK_IS_CRITICAL | + CLK_OPS_PARENT_ENABLE, + _NO_GATE, + _MUX(RCC_ASSCKSELR, 0, 2, 0), + _DIV(RCC_AXIDIVR, 0, 3, 0, axi_div_table)), + + COMPOSITE(CK_MCU, "ck_mcu", mcu_src, CLK_IS_CRITICAL | + CLK_OPS_PARENT_ENABLE, + _NO_GATE, + _MUX(RCC_MSSCKSELR, 0, 2, 0), + _DIV(RCC_MCUDIVR, 0, 4, 0, mcu_div_table)), + + DIV_TABLE(NO_ID, "pclk1", "ck_mcu", CLK_IGNORE_UNUSED, RCC_APB1DIVR, 0, + 3, CLK_DIVIDER_READ_ONLY, apb_div_table), + + DIV_TABLE(NO_ID, "pclk2", "ck_mcu", CLK_IGNORE_UNUSED, RCC_APB2DIVR, 0, + 3, CLK_DIVIDER_READ_ONLY, apb_div_table), + + DIV_TABLE(NO_ID, "pclk3", "ck_mcu", CLK_IGNORE_UNUSED, RCC_APB3DIVR, 0, + 3, CLK_DIVIDER_READ_ONLY, apb_div_table), + + DIV_TABLE(NO_ID, "pclk4", "ck_axi", CLK_IGNORE_UNUSED, RCC_APB4DIVR, 0, + 3, CLK_DIVIDER_READ_ONLY, apb_div_table), + + DIV_TABLE(NO_ID, "pclk5", "ck_axi", CLK_IGNORE_UNUSED, RCC_APB5DIVR, 0, + 3, CLK_DIVIDER_READ_ONLY, apb_div_table), + + /* Kernel Timers */ + STM32_CKTIM("ck1_tim", "pclk1", 0, RCC_APB1DIVR, RCC_TIMG1PRER), + STM32_CKTIM("ck2_tim", "pclk2", 0, RCC_APB2DIVR, RCC_TIMG2PRER), + + STM32_TIM(TIM2_K, "tim2_k", "ck1_tim", RCC_APB1ENSETR, 0), + STM32_TIM(TIM3_K, "tim3_k", "ck1_tim", RCC_APB1ENSETR, 1), + STM32_TIM(TIM4_K, "tim4_k", "ck1_tim", RCC_APB1ENSETR, 2), + STM32_TIM(TIM5_K, "tim5_k", "ck1_tim", RCC_APB1ENSETR, 3), + STM32_TIM(TIM6_K, "tim6_k", "ck1_tim", RCC_APB1ENSETR, 4), + STM32_TIM(TIM7_K, "tim7_k", "ck1_tim", RCC_APB1ENSETR, 5), + STM32_TIM(TIM12_K, "tim12_k", "ck1_tim", RCC_APB1ENSETR, 6), + STM32_TIM(TIM13_K, "tim13_k", "ck1_tim", RCC_APB1ENSETR, 7), + STM32_TIM(TIM14_K, "tim14_k", "ck1_tim", RCC_APB1ENSETR, 8), + STM32_TIM(TIM1_K, "tim1_k", "ck2_tim", RCC_APB2ENSETR, 0), + STM32_TIM(TIM8_K, "tim8_k", "ck2_tim", RCC_APB2ENSETR, 1), + STM32_TIM(TIM15_K, "tim15_k", "ck2_tim", RCC_APB2ENSETR, 2), + STM32_TIM(TIM16_K, "tim16_k", "ck2_tim", RCC_APB2ENSETR, 3), + STM32_TIM(TIM17_K, "tim17_k", "ck2_tim", RCC_APB2ENSETR, 4), + + /* Peripheral clocks */ + PCLK(TIM2, "tim2", "pclk1", CLK_IGNORE_UNUSED, G_TIM2), + PCLK(TIM3, "tim3", "pclk1", CLK_IGNORE_UNUSED, G_TIM3), + PCLK(TIM4, "tim4", "pclk1", CLK_IGNORE_UNUSED, G_TIM4), + PCLK(TIM5, "tim5", "pclk1", CLK_IGNORE_UNUSED, G_TIM5), + PCLK(TIM6, "tim6", "pclk1", CLK_IGNORE_UNUSED, G_TIM6), + PCLK(TIM7, "tim7", "pclk1", CLK_IGNORE_UNUSED, G_TIM7), + PCLK(TIM12, "tim12", "pclk1", CLK_IGNORE_UNUSED, G_TIM12), + PCLK(TIM13, "tim13", "pclk1", CLK_IGNORE_UNUSED, G_TIM13), + PCLK(TIM14, "tim14", "pclk1", CLK_IGNORE_UNUSED, G_TIM14), + PCLK(LPTIM1, "lptim1", "pclk1", 0, G_LPTIM1), + PCLK(SPI2, "spi2", "pclk1", 0, G_SPI2), + PCLK(SPI3, "spi3", "pclk1", 0, G_SPI3), + PCLK(USART2, "usart2", "pclk1", 0, G_USART2), + PCLK(USART3, "usart3", "pclk1", 0, G_USART3), + PCLK(UART4, "uart4", "pclk1", 0, G_UART4), + PCLK(UART5, "uart5", "pclk1", 0, G_UART5), + PCLK(UART7, "uart7", "pclk1", 0, G_UART7), + PCLK(UART8, "uart8", "pclk1", 0, G_UART8), + PCLK(I2C1, "i2c1", "pclk1", 0, G_I2C1), + PCLK(I2C2, "i2c2", "pclk1", 0, G_I2C2), + PCLK(I2C3, "i2c3", "pclk1", 0, G_I2C3), + PCLK(I2C5, "i2c5", "pclk1", 0, G_I2C5), + PCLK(SPDIF, "spdif", "pclk1", 0, G_SPDIF), + PCLK(CEC, "cec", "pclk1", 0, G_CEC), + PCLK(DAC12, "dac12", "pclk1", 0, G_DAC12), + PCLK(MDIO, "mdio", "pclk1", 0, G_MDIO), + PCLK(TIM1, "tim1", "pclk2", CLK_IGNORE_UNUSED, G_TIM1), + PCLK(TIM8, "tim8", "pclk2", CLK_IGNORE_UNUSED, G_TIM8), + PCLK(TIM15, "tim15", "pclk2", CLK_IGNORE_UNUSED, G_TIM15), + PCLK(TIM16, "tim16", "pclk2", CLK_IGNORE_UNUSED, G_TIM16), + PCLK(TIM17, "tim17", "pclk2", CLK_IGNORE_UNUSED, G_TIM17), + PCLK(SPI1, "spi1", "pclk2", 0, G_SPI1), + PCLK(SPI4, "spi4", "pclk2", 0, G_SPI4), + PCLK(SPI5, "spi5", "pclk2", 0, G_SPI5), + PCLK(USART6, "usart6", "pclk2", 0, G_USART6), + PCLK(SAI1, "sai1", "pclk2", 0, G_SAI1), + PCLK(SAI2, "sai2", "pclk2", 0, G_SAI2), + PCLK(SAI3, "sai3", "pclk2", 0, G_SAI3), + PCLK(DFSDM, "dfsdm", "pclk2", 0, G_DFSDM), + PCLK(FDCAN, "fdcan", "pclk2", 0, G_FDCAN), + PCLK(LPTIM2, "lptim2", "pclk3", 0, G_LPTIM2), + PCLK(LPTIM3, "lptim3", "pclk3", 0, G_LPTIM3), + PCLK(LPTIM4, "lptim4", "pclk3", 0, G_LPTIM4), + PCLK(LPTIM5, "lptim5", "pclk3", 0, G_LPTIM5), + PCLK(SAI4, "sai4", "pclk3", 0, G_SAI4), + PCLK(SYSCFG, "syscfg", "pclk3", 0, G_SYSCFG), + PCLK(VREF, "vref", "pclk3", 13, G_VREF), + PCLK(TMPSENS, "tmpsens", "pclk3", 0, G_TMPSENS), + PCLK(PMBCTRL, "pmbctrl", "pclk3", 0, G_PMBCTRL), + PCLK(HDP, "hdp", "pclk3", 0, G_HDP), + PCLK(LTDC, "ltdc", "pclk4", 0, G_LTDC), + PCLK(DSI, "dsi", "pclk4", 0, G_DSI), + PCLK(IWDG2, "iwdg2", "pclk4", 0, G_IWDG2), + PCLK(USBPHY, "usbphy", "pclk4", 0, G_USBPHY), + PCLK(STGENRO, "stgenro", "pclk4", 0, G_STGENRO), + PCLK(SPI6, "spi6", "pclk5", 0, G_SPI6), + PCLK(I2C4, "i2c4", "pclk5", 0, G_I2C4), + PCLK(I2C6, "i2c6", "pclk5", 0, G_I2C6), + PCLK(USART1, "usart1", "pclk5", 0, G_USART1), + PCLK(RTCAPB, "rtcapb", "pclk5", CLK_IGNORE_UNUSED | + CLK_IS_CRITICAL, G_RTCAPB), + PCLK(TZC1, "tzc1", "ck_axi", CLK_IGNORE_UNUSED, G_TZC1), + PCLK(TZC2, "tzc2", "ck_axi", CLK_IGNORE_UNUSED, G_TZC2), + PCLK(TZPC, "tzpc", "pclk5", CLK_IGNORE_UNUSED, G_TZPC), + PCLK(IWDG1, "iwdg1", "pclk5", 0, G_IWDG1), + PCLK(BSEC, "bsec", "pclk5", CLK_IGNORE_UNUSED, G_BSEC), + PCLK(STGEN, "stgen", "pclk5", CLK_IGNORE_UNUSED, G_STGEN), + PCLK(DMA1, "dma1", "ck_mcu", 0, G_DMA1), + PCLK(DMA2, "dma2", "ck_mcu", 0, G_DMA2), + PCLK(DMAMUX, "dmamux", "ck_mcu", 0, G_DMAMUX), + PCLK(ADC12, "adc12", "ck_mcu", 0, G_ADC12), + PCLK(USBO, "usbo", "ck_mcu", 0, G_USBO), + PCLK(SDMMC3, "sdmmc3", "ck_mcu", 0, G_SDMMC3), + PCLK(DCMI, "dcmi", "ck_mcu", 0, G_DCMI), + PCLK(CRYP2, "cryp2", "ck_mcu", 0, G_CRYP2), + PCLK(HASH2, "hash2", "ck_mcu", 0, G_HASH2), + PCLK(RNG2, "rng2", "ck_mcu", 0, G_RNG2), + PCLK(CRC2, "crc2", "ck_mcu", 0, G_CRC2), + PCLK(HSEM, "hsem", "ck_mcu", 0, G_HSEM), + PCLK(IPCC, "ipcc", "ck_mcu", 0, G_IPCC), + PCLK(GPIOA, "gpioa", "ck_mcu", 0, G_GPIOA), + PCLK(GPIOB, "gpiob", "ck_mcu", 0, G_GPIOB), + PCLK(GPIOC, "gpioc", "ck_mcu", 0, G_GPIOC), + PCLK(GPIOD, "gpiod", "ck_mcu", 0, G_GPIOD), + PCLK(GPIOE, "gpioe", "ck_mcu", 0, G_GPIOE), + PCLK(GPIOF, "gpiof", "ck_mcu", 0, G_GPIOF), + PCLK(GPIOG, "gpiog", "ck_mcu", 0, G_GPIOG), + PCLK(GPIOH, "gpioh", "ck_mcu", 0, G_GPIOH), + PCLK(GPIOI, "gpioi", "ck_mcu", 0, G_GPIOI), + PCLK(GPIOJ, "gpioj", "ck_mcu", 0, G_GPIOJ), + PCLK(GPIOK, "gpiok", "ck_mcu", 0, G_GPIOK), + PCLK(GPIOZ, "gpioz", "ck_axi", CLK_IGNORE_UNUSED, G_GPIOZ), + PCLK(CRYP1, "cryp1", "ck_axi", CLK_IGNORE_UNUSED, G_CRYP1), + PCLK(HASH1, "hash1", "ck_axi", CLK_IGNORE_UNUSED, G_HASH1), + PCLK(RNG1, "rng1", "ck_axi", 0, G_RNG1), + PCLK(BKPSRAM, "bkpsram", "ck_axi", CLK_IGNORE_UNUSED, G_BKPSRAM), + PCLK(MDMA, "mdma", "ck_axi", 0, G_MDMA), + PCLK(GPU, "gpu", "ck_axi", 0, G_GPU), + PCLK(ETHTX, "ethtx", "ck_axi", 0, G_ETHTX), + PCLK_PDATA(ETHRX, "ethrx", ethrx_src, 0, G_ETHRX), + PCLK(ETHMAC, "ethmac", "ck_axi", 0, G_ETHMAC), + PCLK(FMC, "fmc", "ck_axi", CLK_IGNORE_UNUSED, G_FMC), + PCLK(QSPI, "qspi", "ck_axi", CLK_IGNORE_UNUSED, G_QSPI), + PCLK(SDMMC1, "sdmmc1", "ck_axi", 0, G_SDMMC1), + PCLK(SDMMC2, "sdmmc2", "ck_axi", 0, G_SDMMC2), + PCLK(CRC1, "crc1", "ck_axi", 0, G_CRC1), + PCLK(USBH, "usbh", "ck_axi", 0, G_USBH), + PCLK(ETHSTP, "ethstp", "ck_axi", 0, G_ETHSTP), + PCLK(DDRPERFM, "ddrperfm", "pclk4", 0, G_DDRPERFM), + + /* Kernel clocks */ + KCLK(SDMMC1_K, "sdmmc1_k", sdmmc12_src, 0, G_SDMMC1, M_SDMMC12), + KCLK(SDMMC2_K, "sdmmc2_k", sdmmc12_src, 0, G_SDMMC2, M_SDMMC12), + KCLK(SDMMC3_K, "sdmmc3_k", sdmmc3_src, 0, G_SDMMC3, M_SDMMC3), + KCLK(FMC_K, "fmc_k", fmc_src, 0, G_FMC, M_FMC), + KCLK(QSPI_K, "qspi_k", qspi_src, 0, G_QSPI, M_QSPI), + KCLK(RNG1_K, "rng1_k", rng_src, 0, G_RNG1, M_RNG1), + KCLK(RNG2_K, "rng2_k", rng_src, 0, G_RNG2, M_RNG2), + KCLK(USBPHY_K, "usbphy_k", usbphy_src, 0, G_USBPHY, M_USBPHY), + KCLK(STGEN_K, "stgen_k", stgen_src, CLK_IS_CRITICAL, G_STGEN, M_STGEN), + KCLK(SPDIF_K, "spdif_k", spdif_src, 0, G_SPDIF, M_SPDIF), + KCLK(SPI1_K, "spi1_k", spi123_src, 0, G_SPI1, M_SPI1), + KCLK(SPI2_K, "spi2_k", spi123_src, 0, G_SPI2, M_SPI23), + KCLK(SPI3_K, "spi3_k", spi123_src, 0, G_SPI3, M_SPI23), + KCLK(SPI4_K, "spi4_k", spi45_src, 0, G_SPI4, M_SPI45), + KCLK(SPI5_K, "spi5_k", spi45_src, 0, G_SPI5, M_SPI45), + KCLK(SPI6_K, "spi6_k", spi6_src, 0, G_SPI6, M_SPI6), + KCLK(CEC_K, "cec_k", cec_src, 0, G_CEC, M_CEC), + KCLK(I2C1_K, "i2c1_k", i2c12_src, 0, G_I2C1, M_I2C12), + KCLK(I2C2_K, "i2c2_k", i2c12_src, 0, G_I2C2, M_I2C12), + KCLK(I2C3_K, "i2c3_k", i2c35_src, 0, G_I2C3, M_I2C35), + KCLK(I2C5_K, "i2c5_k", i2c35_src, 0, G_I2C5, M_I2C35), + KCLK(I2C4_K, "i2c4_k", i2c46_src, 0, G_I2C4, M_I2C46), + KCLK(I2C6_K, "i2c6_k", i2c46_src, 0, G_I2C6, M_I2C46), + KCLK(LPTIM1_K, "lptim1_k", lptim1_src, 0, G_LPTIM1, M_LPTIM1), + KCLK(LPTIM2_K, "lptim2_k", lptim23_src, 0, G_LPTIM2, M_LPTIM23), + KCLK(LPTIM3_K, "lptim3_k", lptim23_src, 0, G_LPTIM3, M_LPTIM23), + KCLK(LPTIM4_K, "lptim4_k", lptim45_src, 0, G_LPTIM4, M_LPTIM45), + KCLK(LPTIM5_K, "lptim5_k", lptim45_src, 0, G_LPTIM5, M_LPTIM45), + KCLK(USART1_K, "usart1_k", usart1_src, 0, G_USART1, M_USART1), + KCLK(USART2_K, "usart2_k", usart234578_src, 0, G_USART2, M_UART24), + KCLK(USART3_K, "usart3_k", usart234578_src, 0, G_USART3, M_UART35), + KCLK(UART4_K, "uart4_k", usart234578_src, 0, G_UART4, M_UART24), + KCLK(UART5_K, "uart5_k", usart234578_src, 0, G_UART5, M_UART35), + KCLK(USART6_K, "uart6_k", usart6_src, 0, G_USART6, M_USART6), + KCLK(UART7_K, "uart7_k", usart234578_src, 0, G_UART7, M_UART78), + KCLK(UART8_K, "uart8_k", usart234578_src, 0, G_UART8, M_UART78), + KCLK(FDCAN_K, "fdcan_k", fdcan_src, 0, G_FDCAN, M_FDCAN), + KCLK(SAI1_K, "sai1_k", sai_src, 0, G_SAI1, M_SAI1), + KCLK(SAI2_K, "sai2_k", sai2_src, 0, G_SAI2, M_SAI2), + KCLK(SAI3_K, "sai3_k", sai_src, 0, G_SAI3, M_SAI3), + KCLK(SAI4_K, "sai4_k", sai_src, 0, G_SAI4, M_SAI4), + KCLK(ADC12_K, "adc12_k", adc12_src, 0, G_ADC12, M_ADC12), + KCLK(DSI_K, "dsi_k", dsi_src, 0, G_DSI, M_DSI), + KCLK(ADFSDM_K, "adfsdm_k", sai_src, 0, G_ADFSDM, M_SAI1), + KCLK(USBO_K, "usbo_k", usbo_src, 0, G_USBO, M_USBO), + + /* Particulary Kernel Clocks (no mux or no gate) */ + MGATE_MP1(DFSDM_K, "dfsdm_k", "ck_mcu", 0, G_DFSDM), + MGATE_MP1(DSI_PX, "dsi_px", "pll4_q", CLK_SET_RATE_PARENT, G_DSI), + MGATE_MP1(LTDC_PX, "ltdc_px", "pll4_q", CLK_SET_RATE_PARENT, G_LTDC), + MGATE_MP1(GPU_K, "gpu_k", "pll2_q", 0, G_GPU), + MGATE_MP1(DAC12_K, "dac12_k", "ck_lsi", 0, G_DAC12), + + COMPOSITE(NO_ID, "ck_ker_eth", eth_src, CLK_OPS_PARENT_ENABLE | + CLK_SET_RATE_NO_REPARENT, + _NO_GATE, + _MMUX(M_ETHCK), + _NO_DIV), + + MGATE_MP1(ETHCK_K, "ethck_k", "ck_ker_eth", 0, G_ETHCK), + + DIV(ETHPTP_K, "ethptp_k", "ck_ker_eth", CLK_OPS_PARENT_ENABLE | + CLK_SET_RATE_NO_REPARENT, RCC_ETHCKSELR, 4, 4, 0), + + /* RTC clock */ + COMPOSITE(RTC, "ck_rtc", rtc_src, CLK_OPS_PARENT_ENABLE, + _GATE(RCC_BDCR, 20, 0), + _MUX(RCC_BDCR, 16, 2, 0), + _DIV_RTC(RCC_RTCDIVR, 0, 6, 0, NULL)), + + /* MCO clocks */ + COMPOSITE(CK_MCO1, "ck_mco1", mco1_src, CLK_OPS_PARENT_ENABLE | + CLK_SET_RATE_NO_REPARENT, + _GATE(RCC_MCO1CFGR, 12, 0), + _MUX(RCC_MCO1CFGR, 0, 3, 0), + _DIV(RCC_MCO1CFGR, 4, 4, 0, NULL)), + + COMPOSITE(CK_MCO2, "ck_mco2", mco2_src, CLK_OPS_PARENT_ENABLE | + CLK_SET_RATE_NO_REPARENT, + _GATE(RCC_MCO2CFGR, 12, 0), + _MUX(RCC_MCO2CFGR, 0, 3, 0), + _DIV(RCC_MCO2CFGR, 4, 4, 0, NULL)), + + /* Debug clocks */ + GATE(CK_DBG, "ck_sys_dbg", "ck_axi", CLK_IGNORE_UNUSED, + RCC_DBGCFGR, 8, 0), + + COMPOSITE(CK_TRACE, "ck_trace", ck_trace_src, CLK_OPS_PARENT_ENABLE, + _GATE(RCC_DBGCFGR, 9, 0), + _NO_MUX, + _DIV(RCC_DBGCFGR, 0, 3, 0, ck_trace_div_table)), +}; + +static const u32 stm32mp1_clock_secured[] = { + CK_HSE, + CK_HSI, + CK_CSI, + CK_LSI, + CK_LSE, + PLL1, + PLL2, + PLL1_P, + PLL2_P, + PLL2_Q, + PLL2_R, + CK_MPU, + CK_AXI, + SPI6, + I2C4, + I2C6, + USART1, + RTCAPB, + TZC1, + TZC2, + TZPC, + IWDG1, + BSEC, + STGEN, + GPIOZ, + CRYP1, + HASH1, + RNG1, + BKPSRAM, + RNG1_K, + STGEN_K, + SPI6_K, + I2C4_K, + I2C6_K, + USART1_K, + RTC, +}; + +static bool stm32_check_security(const struct clock_config *cfg) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(stm32mp1_clock_secured); i++) + if (cfg->id == stm32mp1_clock_secured[i]) + return true; + return false; +} + +struct stm32_rcc_match_data { + const struct clock_config *cfg; + unsigned int num; + unsigned int maxbinding; + struct clk_stm32_reset_data *reset_data; + bool (*check_security)(const struct clock_config *cfg); +}; + +static struct clk_stm32_reset_data stm32mp1_reset_data = { + .nr_lines = STM32MP1_RESET_ID_MASK, + .clear_offset = RCC_CLR, +}; + +static struct stm32_rcc_match_data stm32mp1_data = { + .cfg = stm32mp1_clock_cfg, + .num = ARRAY_SIZE(stm32mp1_clock_cfg), + .maxbinding = STM32MP1_LAST_CLK, + .reset_data = &stm32mp1_reset_data, +}; + +static struct stm32_rcc_match_data stm32mp1_data_secure = { + .cfg = stm32mp1_clock_cfg, + .num = ARRAY_SIZE(stm32mp1_clock_cfg), + .maxbinding = STM32MP1_LAST_CLK, + .reset_data = &stm32mp1_reset_data, + .check_security = &stm32_check_security +}; + +static const struct of_device_id stm32mp1_match_data[] = { + { + .compatible = "st,stm32mp1-rcc", + .data = &stm32mp1_data, + }, + { + .compatible = "st,stm32mp1-rcc-secure", + .data = &stm32mp1_data_secure, + }, + { } +}; +MODULE_DEVICE_TABLE(of, stm32mp1_match_data); + +static int stm32_register_hw_clk(struct device *dev, + struct clk_hw_onecell_data *clk_data, + void __iomem *base, spinlock_t *lock, + const struct clock_config *cfg) +{ + struct clk_hw **hws; + struct clk_hw *hw = ERR_PTR(-ENOENT); + + hws = clk_data->hws; + + if (cfg->func) + hw = (*cfg->func)(dev, clk_data, base, lock, cfg); + + if (IS_ERR(hw)) { + pr_err("Unable to register %s\n", cfg->name); + return PTR_ERR(hw); + } + + if (cfg->id != NO_ID) + hws[cfg->id] = hw; + + return 0; +} + +static int stm32_rcc_clock_init(struct device *dev, void __iomem *base, + const struct of_device_id *match) +{ + const struct stm32_rcc_match_data *data = match->data; + struct clk_hw_onecell_data *clk_data; + struct clk_hw **hws; + int err, n, max_binding; + + max_binding = data->maxbinding; + + clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, max_binding), + GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + + clk_data->num = max_binding; + + hws = clk_data->hws; + + for (n = 0; n < max_binding; n++) + hws[n] = ERR_PTR(-ENOENT); + + for (n = 0; n < data->num; n++) { + if (data->check_security && data->check_security(&data->cfg[n])) + continue; + + err = stm32_register_hw_clk(dev, clk_data, base, &rlock, + &data->cfg[n]); + if (err) { + dev_err(dev, "Can't register clk %s: %d\n", + data->cfg[n].name, err); + + return err; + } + } + + return of_clk_add_hw_provider(dev_of_node(dev), of_clk_hw_onecell_get, clk_data); +} + +static int stm32_rcc_init(struct device *dev, void __iomem *base, + const struct of_device_id *match_data) +{ + const struct stm32_rcc_match_data *rcc_match_data; + const struct of_device_id *match; + int err; + + match = of_match_node(match_data, dev_of_node(dev)); + if (!match) { + dev_err(dev, "match data not found\n"); + return -ENODEV; + } + + rcc_match_data = match->data; + + /* RCC Reset Configuration */ + err = stm32_rcc_reset_init(dev, rcc_match_data->reset_data, base); + if (err) { + pr_err("stm32mp1 reset failed to initialize\n"); + return err; + } + + /* RCC Clock Configuration */ + err = stm32_rcc_clock_init(dev, base, match); + if (err) { + pr_err("stm32mp1 clock failed to initialize\n"); + return err; + } + + return 0; +} + +static int stm32mp1_rcc_init(struct device *dev) +{ + void __iomem *base; + int ret; + + base = of_iomap(dev_of_node(dev), 0); + if (!base) { + pr_err("%pOFn: unable to map resource", dev_of_node(dev)); + ret = -ENOMEM; + goto out; + } + + ret = stm32_rcc_init(dev, base, stm32mp1_match_data); + +out: + if (ret) { + if (base) + iounmap(base); + + of_node_put(dev_of_node(dev)); + } + + return ret; +} + +static int get_clock_deps(struct device *dev) +{ + static const char * const clock_deps_name[] = { + "hsi", "hse", "csi", "lsi", "lse", + }; + size_t deps_size = sizeof(struct clk *) * ARRAY_SIZE(clock_deps_name); + struct clk **clk_deps; + int i; + + clk_deps = devm_kzalloc(dev, deps_size, GFP_KERNEL); + if (!clk_deps) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(clock_deps_name); i++) { + struct clk *clk = of_clk_get_by_name(dev_of_node(dev), + clock_deps_name[i]); + + if (IS_ERR(clk)) { + if (PTR_ERR(clk) != -EINVAL && PTR_ERR(clk) != -ENOENT) + return PTR_ERR(clk); + } else { + /* Device gets a reference count on the clock */ + clk_deps[i] = devm_clk_get(dev, __clk_get_name(clk)); + clk_put(clk); + } + } + + return 0; +} + +static int stm32mp1_rcc_clocks_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + int ret = get_clock_deps(dev); + + if (!ret) + ret = stm32mp1_rcc_init(dev); + + return ret; +} + +static void stm32mp1_rcc_clocks_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *child, *np = dev_of_node(dev); + + for_each_available_child_of_node(np, child) + of_clk_del_provider(child); +} + +static struct platform_driver stm32mp1_rcc_clocks_driver = { + .driver = { + .name = "stm32mp1_rcc", + .of_match_table = stm32mp1_match_data, + }, + .probe = stm32mp1_rcc_clocks_probe, + .remove_new = stm32mp1_rcc_clocks_remove, +}; + +static int __init stm32mp1_clocks_init(void) +{ + return platform_driver_register(&stm32mp1_rcc_clocks_driver); +} +core_initcall(stm32mp1_clocks_init); diff --git a/drivers/clk/stm32/clk-stm32mp13.c b/drivers/clk/stm32/clk-stm32mp13.c index c4a737482fe5f1..d4ecb3c34a1b26 100644 --- a/drivers/clk/stm32/clk-stm32mp13.c +++ b/drivers/clk/stm32/clk-stm32mp13.c @@ -10,8 +10,10 @@ #include #include #include "clk-stm32-core.h" +#include "reset-stm32.h" #include "stm32mp13_rcc.h" +#define STM32MP1_RESET_ID_MASK GENMASK(15, 0) #define RCC_CLR_OFFSET 0x4 /* STM32 Gates definition */ @@ -1511,13 +1513,18 @@ static struct clk_stm32_clock_data stm32mp13_clock_data = { .is_multi_mux = stm32mp13_is_multi_mux, }; +static struct clk_stm32_reset_data stm32mp13_reset_data = { + .nr_lines = STM32MP1_RESET_ID_MASK, + .clear_offset = RCC_CLR_OFFSET, +}; + static const struct stm32_rcc_match_data stm32mp13_data = { .tab_clocks = stm32mp13_clock_cfg, .num_clocks = ARRAY_SIZE(stm32mp13_clock_cfg), .clock_data = &stm32mp13_clock_data, .check_security = &stm32mp13_clock_is_provided_by_secure, .maxbinding = STM32MP1_LAST_CLK, - .clear_offset = RCC_CLR_OFFSET, + .reset_data = &stm32mp13_reset_data, }; static const struct of_device_id stm32mp13_match_data[] = { diff --git a/drivers/clk/stm32/reset-stm32.c b/drivers/clk/stm32/reset-stm32.c index e89381528af991..14c2ee1eebee0d 100644 --- a/drivers/clk/stm32/reset-stm32.c +++ b/drivers/clk/stm32/reset-stm32.c @@ -11,9 +11,7 @@ #include #include -#include "clk-stm32-core.h" - -#define STM32_RESET_ID_MASK GENMASK(15, 0) +#include "reset-stm32.h" struct stm32_reset_data { /* reset lock */ @@ -99,24 +97,22 @@ static const struct reset_control_ops stm32_reset_ops = { .status = stm32_reset_status, }; -int stm32_rcc_reset_init(struct device *dev, const struct of_device_id *match, +int stm32_rcc_reset_init(struct device *dev, struct clk_stm32_reset_data *data, void __iomem *base) { - const struct stm32_rcc_match_data *data = match->data; - struct stm32_reset_data *reset_data = NULL; - - data = match->data; + struct stm32_reset_data *reset_data; reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL); if (!reset_data) return -ENOMEM; spin_lock_init(&reset_data->lock); + reset_data->membase = base; reset_data->rcdev.owner = THIS_MODULE; reset_data->rcdev.ops = &stm32_reset_ops; reset_data->rcdev.of_node = dev_of_node(dev); - reset_data->rcdev.nr_resets = STM32_RESET_ID_MASK; + reset_data->rcdev.nr_resets = data->nr_lines; reset_data->clear_offset = data->clear_offset; return reset_controller_register(&reset_data->rcdev); diff --git a/drivers/clk/stm32/reset-stm32.h b/drivers/clk/stm32/reset-stm32.h index 6eb6ea4b55ab95..8cf1cc9be480b2 100644 --- a/drivers/clk/stm32/reset-stm32.h +++ b/drivers/clk/stm32/reset-stm32.h @@ -4,5 +4,11 @@ * Author: Gabriel Fernandez for STMicroelectronics. */ -int stm32_rcc_reset_init(struct device *dev, const struct of_device_id *match, +struct clk_stm32_reset_data { + const struct reset_control_ops *ops; + unsigned int nr_lines; + u32 clear_offset; +}; + +int stm32_rcc_reset_init(struct device *dev, struct clk_stm32_reset_data *data, void __iomem *base); diff --git a/drivers/clk/sunxi-ng/ccu_nkm.c b/drivers/clk/sunxi-ng/ccu_nkm.c index eed64547ad42ff..853f84398e2bdb 100644 --- a/drivers/clk/sunxi-ng/ccu_nkm.c +++ b/drivers/clk/sunxi-ng/ccu_nkm.c @@ -21,17 +21,16 @@ static unsigned long ccu_nkm_find_best_with_parent_adj(struct ccu_common *common unsigned long *parent, unsigned long rate, struct _ccu_nkm *nkm) { - unsigned long best_rate = 0, best_parent_rate = *parent, tmp_parent = *parent; + unsigned long best_rate = 0, best_parent_rate = *parent; unsigned long best_n = 0, best_k = 0, best_m = 0; unsigned long _n, _k, _m; for (_k = nkm->min_k; _k <= nkm->max_k; _k++) { for (_n = nkm->min_n; _n <= nkm->max_n; _n++) { for (_m = nkm->min_m; _m <= nkm->max_m; _m++) { - unsigned long tmp_rate; + unsigned long tmp_rate, tmp_parent; tmp_parent = clk_hw_round_rate(parent_hw, rate * _m / (_n * _k)); - tmp_rate = tmp_parent * _n * _k / _m; if (ccu_is_better_rate(common, rate, tmp_rate, best_rate) || diff --git a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c index d56822ce6126c1..6a6e5d9292e87a 100644 --- a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c +++ b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c @@ -23,15 +23,41 @@ #define WZRD_NUM_OUTPUTS 7 #define WZRD_ACLK_MAX_FREQ 250000000UL -#define WZRD_CLK_CFG_REG(n) (0x200 + 4 * (n)) +#define WZRD_CLK_CFG_REG(v, n) (0x200 + 0x130 * (v) + 4 * (n)) #define WZRD_CLKOUT0_FRAC_EN BIT(18) -#define WZRD_CLKFBOUT_FRAC_EN BIT(26) +#define WZRD_CLKFBOUT_1 0 +#define WZRD_CLKFBOUT_2 1 +#define WZRD_CLKOUT0_1 2 +#define WZRD_CLKOUT0_2 3 +#define WZRD_DESKEW_2 20 +#define WZRD_DIVCLK 21 +#define WZRD_CLKFBOUT_4 51 +#define WZRD_CLKFBOUT_3 48 +#define WZRD_DUTY_CYCLE 2 +#define WZRD_O_DIV 4 + +#define WZRD_CLKFBOUT_FRAC_EN BIT(1) +#define WZRD_CLKFBOUT_PREDIV2 (BIT(11) | BIT(12) | BIT(9)) +#define WZRD_MULT_PREDIV2 (BIT(10) | BIT(9) | BIT(12)) +#define WZRD_CLKFBOUT_EDGE BIT(8) +#define WZRD_P5EN BIT(13) +#define WZRD_P5EN_SHIFT 13 +#define WZRD_P5FEDGE BIT(15) +#define WZRD_DIVCLK_EDGE BIT(10) +#define WZRD_P5FEDGE_SHIFT 15 +#define WZRD_CLKOUT0_PREDIV2 BIT(11) +#define WZRD_EDGE_SHIFT 8 #define WZRD_CLKFBOUT_MULT_SHIFT 8 #define WZRD_CLKFBOUT_MULT_MASK (0xff << WZRD_CLKFBOUT_MULT_SHIFT) +#define WZRD_CLKFBOUT_L_SHIFT 0 +#define WZRD_CLKFBOUT_H_SHIFT 8 +#define WZRD_CLKFBOUT_L_MASK GENMASK(7, 0) +#define WZRD_CLKFBOUT_H_MASK GENMASK(15, 8) #define WZRD_CLKFBOUT_FRAC_SHIFT 16 #define WZRD_CLKFBOUT_FRAC_MASK (0x3ff << WZRD_CLKFBOUT_FRAC_SHIFT) +#define WZRD_VERSAL_FRAC_MASK GENMASK(5, 0) #define WZRD_DIVCLK_DIVIDE_SHIFT 0 #define WZRD_DIVCLK_DIVIDE_MASK (0xff << WZRD_DIVCLK_DIVIDE_SHIFT) #define WZRD_CLKOUT_DIVIDE_SHIFT 0 @@ -45,6 +71,7 @@ #define WZRD_DR_STATUS_REG_OFFSET 0x04 #define WZRD_DR_LOCK_BIT_MASK 0x00000001 #define WZRD_DR_INIT_REG_OFFSET 0x25C +#define WZRD_DR_INIT_VERSAL_OFFSET 0x14 #define WZRD_DR_DIV_TO_PHASE_OFFSET 4 #define WZRD_DR_BEGIN_DYNA_RECONF 0x03 #define WZRD_DR_BEGIN_DYNA_RECONF_5_2 0x07 @@ -52,6 +79,8 @@ #define WZRD_USEC_POLL 10 #define WZRD_TIMEOUT_POLL 1000 +#define WZRD_FRAC_GRADIENT 64 +#define PREDIV2_MULT 2 /* Divider limits, from UG572 Table 3-4 for Ultrascale+ */ #define DIV_O 0x01 @@ -65,6 +94,14 @@ #define WZRD_VCO_MAX 1600000000 #define WZRD_O_MIN 1 #define WZRD_O_MAX 128 +#define VER_WZRD_M_MIN 4 +#define VER_WZRD_M_MAX 432 +#define VER_WZRD_D_MIN 1 +#define VER_WZRD_D_MAX 123 +#define VER_WZRD_VCO_MIN 2160000000ULL +#define VER_WZRD_VCO_MAX 4320000000ULL +#define VER_WZRD_O_MIN 2 +#define VER_WZRD_O_MAX 511 #define WZRD_MIN_ERR 20000 #define WZRD_FRAC_POINTS 1000 @@ -135,6 +172,10 @@ struct clk_wzrd_divider { spinlock_t *lock; /* divider lock */ }; +struct versal_clk_data { + bool is_versal; +}; + #define to_clk_wzrd(_nb) container_of(_nb, struct clk_wzrd, nb) /* maximum frequencies for input/output clocks per speed grade */ @@ -147,6 +188,31 @@ static const unsigned long clk_wzrd_max_freq[] = { /* spin lock variable for clk_wzrd */ static DEFINE_SPINLOCK(clkwzrd_lock); +static unsigned long clk_wzrd_recalc_rate_ver(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); + void __iomem *div_addr = divider->base + divider->offset; + u32 div, p5en, edge, prediv2, all; + unsigned int vall, valh; + + edge = !!(readl(div_addr) & WZRD_CLKFBOUT_EDGE); + p5en = !!(readl(div_addr) & WZRD_P5EN); + prediv2 = !!(readl(div_addr) & WZRD_CLKOUT0_PREDIV2); + vall = readl(div_addr + 4) & WZRD_CLKFBOUT_L_MASK; + valh = readl(div_addr + 4) >> WZRD_CLKFBOUT_H_SHIFT; + all = valh + vall + edge; + if (!all) + all = 1; + + if (prediv2) + div = 2 * all + prediv2 * p5en; + else + div = all; + + return DIV_ROUND_UP_ULL((u64)parent_rate, div); +} + static unsigned long clk_wzrd_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { @@ -161,19 +227,64 @@ static unsigned long clk_wzrd_recalc_rate(struct clk_hw *hw, divider->flags, divider->width); } +static int clk_wzrd_ver_dynamic_reconfig(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); + void __iomem *div_addr = divider->base + divider->offset; + u32 value, regh, edged, p5en, p5fedge, regval, regval1; + unsigned long flags; + int err; + + spin_lock_irqsave(divider->lock, flags); + + value = DIV_ROUND_CLOSEST(parent_rate, rate); + + regh = (value / 4); + regval1 = readl(div_addr); + regval1 |= WZRD_CLKFBOUT_PREDIV2; + regval1 = regval1 & ~(WZRD_CLKFBOUT_EDGE | WZRD_P5EN | WZRD_P5FEDGE); + if (value % 4 > 1) { + edged = 1; + regval1 |= (edged << WZRD_EDGE_SHIFT); + } + p5fedge = value % 2; + p5en = value % 2; + regval1 = regval1 | p5en << WZRD_P5EN_SHIFT | p5fedge << WZRD_P5FEDGE_SHIFT; + writel(regval1, div_addr); + + regval = regh | regh << WZRD_CLKFBOUT_H_SHIFT; + writel(regval, div_addr + 4); + /* Check status register */ + err = readl_poll_timeout_atomic(divider->base + WZRD_DR_STATUS_REG_OFFSET, + value, value & WZRD_DR_LOCK_BIT_MASK, + WZRD_USEC_POLL, WZRD_TIMEOUT_POLL); + if (err) + goto err_reconfig; + + /* Initiate reconfiguration */ + writel(WZRD_DR_BEGIN_DYNA_RECONF, + divider->base + WZRD_DR_INIT_VERSAL_OFFSET); + + /* Check status register */ + err = readl_poll_timeout_atomic(divider->base + WZRD_DR_STATUS_REG_OFFSET, + value, value & WZRD_DR_LOCK_BIT_MASK, + WZRD_USEC_POLL, WZRD_TIMEOUT_POLL); +err_reconfig: + spin_unlock_irqrestore(divider->lock, flags); + return err; +} + static int clk_wzrd_dynamic_reconfig(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { - int err; - u32 value; - unsigned long flags = 0; struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); void __iomem *div_addr = divider->base + divider->offset; + unsigned long flags; + u32 value; + int err; - if (divider->lock) - spin_lock_irqsave(divider->lock, flags); - else - __acquire(divider->lock); + spin_lock_irqsave(divider->lock, flags); value = DIV_ROUND_CLOSEST(parent_rate, rate); @@ -185,9 +296,9 @@ static int clk_wzrd_dynamic_reconfig(struct clk_hw *hw, unsigned long rate, writel(0x00, div_addr + WZRD_DR_DIV_TO_PHASE_OFFSET); /* Check status register */ - err = readl_poll_timeout(divider->base + WZRD_DR_STATUS_REG_OFFSET, - value, value & WZRD_DR_LOCK_BIT_MASK, - WZRD_USEC_POLL, WZRD_TIMEOUT_POLL); + err = readl_poll_timeout_atomic(divider->base + WZRD_DR_STATUS_REG_OFFSET, + value, value & WZRD_DR_LOCK_BIT_MASK, + WZRD_USEC_POLL, WZRD_TIMEOUT_POLL); if (err) goto err_reconfig; @@ -198,14 +309,11 @@ static int clk_wzrd_dynamic_reconfig(struct clk_hw *hw, unsigned long rate, divider->base + WZRD_DR_INIT_REG_OFFSET); /* Check status register */ - err = readl_poll_timeout(divider->base + WZRD_DR_STATUS_REG_OFFSET, - value, value & WZRD_DR_LOCK_BIT_MASK, - WZRD_USEC_POLL, WZRD_TIMEOUT_POLL); + err = readl_poll_timeout_atomic(divider->base + WZRD_DR_STATUS_REG_OFFSET, + value, value & WZRD_DR_LOCK_BIT_MASK, + WZRD_USEC_POLL, WZRD_TIMEOUT_POLL); err_reconfig: - if (divider->lock) - spin_unlock_irqrestore(divider->lock, flags); - else - __release(divider->lock); + spin_unlock_irqrestore(divider->lock, flags); return err; } @@ -223,18 +331,66 @@ static long clk_wzrd_round_rate(struct clk_hw *hw, unsigned long rate, return *prate / div; } +static int clk_wzrd_get_divisors_ver(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); + u64 vco_freq, freq, diff, vcomin, vcomax; + u32 m, d, o; + u32 mmin, mmax, dmin, dmax, omin, omax; + + mmin = VER_WZRD_M_MIN; + mmax = VER_WZRD_M_MAX; + dmin = VER_WZRD_D_MIN; + dmax = VER_WZRD_D_MAX; + omin = VER_WZRD_O_MIN; + omax = VER_WZRD_O_MAX; + vcomin = VER_WZRD_VCO_MIN; + vcomax = VER_WZRD_VCO_MAX; + + for (m = mmin; m <= mmax; m++) { + for (d = dmin; d <= dmax; d++) { + vco_freq = DIV_ROUND_CLOSEST((parent_rate * m), d); + if (vco_freq >= vcomin && vco_freq <= vcomax) { + for (o = omin; o <= omax; o++) { + freq = DIV_ROUND_CLOSEST_ULL(vco_freq, o); + diff = abs(freq - rate); + + if (diff < WZRD_MIN_ERR) { + divider->m = m; + divider->d = d; + divider->o = o; + return 0; + } + } + } + } + } + return -EBUSY; +} + static int clk_wzrd_get_divisors(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); - unsigned long vco_freq, freq, diff; + u64 vco_freq, freq, diff, vcomin, vcomax; u32 m, d, o; - - for (m = WZRD_M_MIN; m <= WZRD_M_MAX; m++) { - for (d = WZRD_D_MIN; d <= WZRD_D_MAX; d++) { + u32 mmin, mmax, dmin, dmax, omin, omax; + + mmin = WZRD_M_MIN; + mmax = WZRD_M_MAX; + dmin = WZRD_D_MIN; + dmax = WZRD_D_MAX; + omin = WZRD_O_MIN; + omax = WZRD_O_MAX; + vcomin = WZRD_VCO_MIN; + vcomax = WZRD_VCO_MAX; + + for (m = mmin; m <= mmax; m++) { + for (d = dmin; d <= dmax; d++) { vco_freq = DIV_ROUND_CLOSEST((parent_rate * m), d); - if (vco_freq >= WZRD_VCO_MIN && vco_freq <= WZRD_VCO_MAX) { - for (o = WZRD_O_MIN; o <= WZRD_O_MAX; o++) { + if (vco_freq >= vcomin && vco_freq <= vcomax) { + for (o = omin; o <= omax; o++) { freq = DIV_ROUND_CLOSEST_ULL(vco_freq, o); diff = abs(freq - rate); @@ -251,12 +407,99 @@ static int clk_wzrd_get_divisors(struct clk_hw *hw, unsigned long rate, return -EBUSY; } +static int clk_wzrd_reconfig(struct clk_wzrd_divider *divider, void __iomem *div_addr) +{ + u32 value; + int err; + + /* Check status register */ + err = readl_poll_timeout_atomic(divider->base + WZRD_DR_STATUS_REG_OFFSET, value, + value & WZRD_DR_LOCK_BIT_MASK, + WZRD_USEC_POLL, WZRD_TIMEOUT_POLL); + if (err) + return -ETIMEDOUT; + + /* Initiate reconfiguration */ + writel(WZRD_DR_BEGIN_DYNA_RECONF, div_addr); + /* Check status register */ + return readl_poll_timeout_atomic(divider->base + WZRD_DR_STATUS_REG_OFFSET, value, + value & WZRD_DR_LOCK_BIT_MASK, + WZRD_USEC_POLL, WZRD_TIMEOUT_POLL); +} + +static int clk_wzrd_dynamic_ver_all_nolock(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + u32 regh, edged, p5en, p5fedge, value2, m, regval, regval1, value; + struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); + void __iomem *div_addr; + int err; + + err = clk_wzrd_get_divisors_ver(hw, rate, parent_rate); + if (err) + return err; + + writel(0, divider->base + WZRD_CLK_CFG_REG(1, WZRD_CLKFBOUT_4)); + + m = divider->m; + edged = m % WZRD_DUTY_CYCLE; + regh = m / WZRD_DUTY_CYCLE; + regval1 = readl(divider->base + WZRD_CLK_CFG_REG(1, + WZRD_CLKFBOUT_1)); + regval1 |= WZRD_MULT_PREDIV2; + if (edged) + regval1 = regval1 | WZRD_CLKFBOUT_EDGE; + else + regval1 = regval1 & ~WZRD_CLKFBOUT_EDGE; + + writel(regval1, divider->base + WZRD_CLK_CFG_REG(1, + WZRD_CLKFBOUT_1)); + regval1 = regh | regh << WZRD_CLKFBOUT_H_SHIFT; + writel(regval1, divider->base + WZRD_CLK_CFG_REG(1, + WZRD_CLKFBOUT_2)); + + value2 = divider->d; + edged = value2 % WZRD_DUTY_CYCLE; + regh = (value2 / WZRD_DUTY_CYCLE); + regval1 = FIELD_PREP(WZRD_DIVCLK_EDGE, edged); + writel(regval1, divider->base + WZRD_CLK_CFG_REG(1, + WZRD_DESKEW_2)); + regval1 = regh | regh << WZRD_CLKFBOUT_H_SHIFT; + writel(regval1, divider->base + WZRD_CLK_CFG_REG(1, WZRD_DIVCLK)); + + value = divider->o; + regh = value / WZRD_O_DIV; + regval1 = readl(divider->base + WZRD_CLK_CFG_REG(1, + WZRD_CLKOUT0_1)); + regval1 |= WZRD_CLKFBOUT_PREDIV2; + regval1 = regval1 & ~(WZRD_CLKFBOUT_EDGE | WZRD_P5EN | WZRD_P5FEDGE); + + if (value % WZRD_O_DIV > 1) { + edged = 1; + regval1 |= edged << WZRD_CLKFBOUT_H_SHIFT; + } + + p5fedge = value % WZRD_DUTY_CYCLE; + p5en = value % WZRD_DUTY_CYCLE; + + regval1 = regval1 | FIELD_PREP(WZRD_P5EN, p5en) | FIELD_PREP(WZRD_P5FEDGE, p5fedge); + writel(regval1, divider->base + WZRD_CLK_CFG_REG(1, + WZRD_CLKOUT0_1)); + regval = regh | regh << WZRD_CLKFBOUT_H_SHIFT; + writel(regval, divider->base + WZRD_CLK_CFG_REG(1, + WZRD_CLKOUT0_2)); + div_addr = divider->base + WZRD_DR_INIT_VERSAL_OFFSET; + + return clk_wzrd_reconfig(divider, div_addr); +} + static int clk_wzrd_dynamic_all_nolock(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); unsigned long vco_freq, rate_div, clockout0_div; - u32 reg, pre, value, f; + void __iomem *div_addr = divider->base; + u32 reg, pre, f; int err; err = clk_wzrd_get_divisors(hw, rate, parent_rate); @@ -275,35 +518,22 @@ static int clk_wzrd_dynamic_all_nolock(struct clk_hw *hw, unsigned long rate, reg = FIELD_PREP(WZRD_CLKOUT_DIVIDE_MASK, clockout0_div) | FIELD_PREP(WZRD_CLKOUT0_FRAC_MASK, f); - writel(reg, divider->base + WZRD_CLK_CFG_REG(2)); + writel(reg, divider->base + WZRD_CLK_CFG_REG(0, 2)); /* Set divisor and clear phase offset */ reg = FIELD_PREP(WZRD_CLKFBOUT_MULT_MASK, divider->m) | FIELD_PREP(WZRD_DIVCLK_DIVIDE_MASK, divider->d); - writel(reg, divider->base + WZRD_CLK_CFG_REG(0)); - writel(divider->o, divider->base + WZRD_CLK_CFG_REG(2)); - writel(0, divider->base + WZRD_CLK_CFG_REG(3)); - /* Check status register */ - err = readl_poll_timeout(divider->base + WZRD_DR_STATUS_REG_OFFSET, value, - value & WZRD_DR_LOCK_BIT_MASK, - WZRD_USEC_POLL, WZRD_TIMEOUT_POLL); - if (err) - return -ETIMEDOUT; - - /* Initiate reconfiguration */ - writel(WZRD_DR_BEGIN_DYNA_RECONF, - divider->base + WZRD_DR_INIT_REG_OFFSET); - - /* Check status register */ - return readl_poll_timeout(divider->base + WZRD_DR_STATUS_REG_OFFSET, value, - value & WZRD_DR_LOCK_BIT_MASK, - WZRD_USEC_POLL, WZRD_TIMEOUT_POLL); + writel(reg, divider->base + WZRD_CLK_CFG_REG(0, 0)); + writel(divider->o, divider->base + WZRD_CLK_CFG_REG(0, 2)); + writel(0, divider->base + WZRD_CLK_CFG_REG(0, 3)); + div_addr = divider->base + WZRD_DR_INIT_REG_OFFSET; + return clk_wzrd_reconfig(divider, div_addr); } static int clk_wzrd_dynamic_all(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); - unsigned long flags = 0; + unsigned long flags; int ret; spin_lock_irqsave(divider->lock, flags); @@ -315,21 +545,103 @@ static int clk_wzrd_dynamic_all(struct clk_hw *hw, unsigned long rate, return ret; } +static int clk_wzrd_dynamic_all_ver(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); + unsigned long flags; + int ret; + + spin_lock_irqsave(divider->lock, flags); + + ret = clk_wzrd_dynamic_ver_all_nolock(hw, rate, parent_rate); + + spin_unlock_irqrestore(divider->lock, flags); + + return ret; +} + static unsigned long clk_wzrd_recalc_rate_all(struct clk_hw *hw, unsigned long parent_rate) { struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); u32 m, d, o, div, reg, f; - reg = readl(divider->base + WZRD_CLK_CFG_REG(0)); + reg = readl(divider->base + WZRD_CLK_CFG_REG(0, 0)); d = FIELD_GET(WZRD_DIVCLK_DIVIDE_MASK, reg); m = FIELD_GET(WZRD_CLKFBOUT_MULT_MASK, reg); - reg = readl(divider->base + WZRD_CLK_CFG_REG(2)); + reg = readl(divider->base + WZRD_CLK_CFG_REG(0, 2)); o = FIELD_GET(WZRD_DIVCLK_DIVIDE_MASK, reg); f = FIELD_GET(WZRD_CLKOUT0_FRAC_MASK, reg); div = DIV_ROUND_CLOSEST(d * (WZRD_FRAC_POINTS * o + f), WZRD_FRAC_POINTS); return divider_recalc_rate(hw, parent_rate * m, div, divider->table, + divider->flags, divider->width); +} + +static unsigned long clk_wzrd_recalc_rate_all_ver(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); + u32 edged, div2, p5en, edge, prediv2, all, regl, regh, mult; + u32 div, reg; + + edge = !!(readl(divider->base + WZRD_CLK_CFG_REG(1, WZRD_CLKFBOUT_1)) & + WZRD_CLKFBOUT_EDGE); + + reg = readl(divider->base + WZRD_CLK_CFG_REG(1, WZRD_CLKFBOUT_2)); + regl = FIELD_GET(WZRD_CLKFBOUT_L_MASK, reg); + regh = FIELD_GET(WZRD_CLKFBOUT_H_MASK, reg); + + mult = regl + regh + edge; + if (!mult) + mult = 1; + + regl = readl(divider->base + WZRD_CLK_CFG_REG(1, WZRD_CLKFBOUT_4)) & + WZRD_CLKFBOUT_FRAC_EN; + if (regl) { + regl = readl(divider->base + WZRD_CLK_CFG_REG(1, WZRD_CLKFBOUT_3)) + & WZRD_VERSAL_FRAC_MASK; + mult = mult * WZRD_FRAC_GRADIENT + regl; + parent_rate = DIV_ROUND_CLOSEST((parent_rate * mult), WZRD_FRAC_GRADIENT); + } else { + parent_rate = parent_rate * mult; + } + + /* O Calculation */ + reg = readl(divider->base + WZRD_CLK_CFG_REG(1, WZRD_CLKOUT0_1)); + edged = FIELD_GET(WZRD_CLKFBOUT_EDGE, reg); + p5en = FIELD_GET(WZRD_P5EN, reg); + prediv2 = FIELD_GET(WZRD_CLKOUT0_PREDIV2, reg); + + reg = readl(divider->base + WZRD_CLK_CFG_REG(1, WZRD_CLKOUT0_2)); + /* Low time */ + regl = FIELD_GET(WZRD_CLKFBOUT_L_MASK, reg); + /* High time */ + regh = FIELD_GET(WZRD_CLKFBOUT_H_MASK, reg); + all = regh + regl + edged; + if (!all) + all = 1; + + if (prediv2) + div2 = PREDIV2_MULT * all + p5en; + else + div2 = all; + + /* D calculation */ + edged = !!(readl(divider->base + WZRD_CLK_CFG_REG(1, WZRD_DESKEW_2)) & + WZRD_DIVCLK_EDGE); + reg = readl(divider->base + WZRD_CLK_CFG_REG(1, WZRD_DIVCLK)); + /* Low time */ + regl = FIELD_GET(WZRD_CLKFBOUT_L_MASK, reg); + /* High time */ + regh = FIELD_GET(WZRD_CLKFBOUT_H_MASK, reg); + div = regl + regh + edged; + if (!div) + div = 1; + + div = div * div2; + return divider_recalc_rate(hw, parent_rate, div, divider->table, divider->flags, divider->width); } @@ -360,6 +672,18 @@ static long clk_wzrd_round_rate_all(struct clk_hw *hw, unsigned long rate, return rate; } +static const struct clk_ops clk_wzrd_ver_divider_ops = { + .round_rate = clk_wzrd_round_rate, + .set_rate = clk_wzrd_ver_dynamic_reconfig, + .recalc_rate = clk_wzrd_recalc_rate_ver, +}; + +static const struct clk_ops clk_wzrd_ver_div_all_ops = { + .round_rate = clk_wzrd_round_rate_all, + .set_rate = clk_wzrd_dynamic_all_ver, + .recalc_rate = clk_wzrd_recalc_rate_all_ver, +}; + static const struct clk_ops clk_wzrd_clk_divider_ops = { .round_rate = clk_wzrd_round_rate, .set_rate = clk_wzrd_dynamic_reconfig, @@ -484,6 +808,53 @@ static struct clk *clk_wzrd_register_divf(struct device *dev, return hw->clk; } +static struct clk *clk_wzrd_ver_register_divider(struct device *dev, + const char *name, + const char *parent_name, + unsigned long flags, + void __iomem *base, + u16 offset, + u8 shift, u8 width, + u8 clk_divider_flags, + u32 div_type, + spinlock_t *lock) +{ + struct clk_wzrd_divider *div; + struct clk_hw *hw; + struct clk_init_data init; + int ret; + + div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL); + if (!div) + return ERR_PTR(-ENOMEM); + + init.name = name; + if (clk_divider_flags & CLK_DIVIDER_READ_ONLY) + init.ops = &clk_divider_ro_ops; + else if (div_type == DIV_O) + init.ops = &clk_wzrd_ver_divider_ops; + else + init.ops = &clk_wzrd_ver_div_all_ops; + init.flags = flags; + init.parent_names = &parent_name; + init.num_parents = 1; + + div->base = base; + div->offset = offset; + div->shift = shift; + div->width = width; + div->flags = clk_divider_flags; + div->lock = lock; + div->hw.init = &init; + + hw = &div->hw; + ret = devm_clk_hw_register(dev, hw); + if (ret) + return ERR_PTR(ret); + + return hw->clk; +} + static struct clk *clk_wzrd_register_divider(struct device *dev, const char *name, const char *parent_name, @@ -588,18 +959,24 @@ static int __maybe_unused clk_wzrd_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(clk_wzrd_dev_pm_ops, clk_wzrd_suspend, clk_wzrd_resume); +static const struct versal_clk_data versal_data = { + .is_versal = true, +}; + static int clk_wzrd_probe(struct platform_device *pdev) { - int i, ret; + const char *clkout_name, *clk_name, *clk_mul_name; + u32 regl, regh, edge, regld, reghd, edged, div; + struct device_node *np = pdev->dev.of_node; + const struct versal_clk_data *data; + struct clk_wzrd *clk_wzrd; + unsigned long flags = 0; + void __iomem *ctrl_reg; u32 reg, reg_f, mult; + bool is_versal = false; unsigned long rate; - const char *clk_name; - void __iomem *ctrl_reg; - struct clk_wzrd *clk_wzrd; - const char *clkout_name; - struct device_node *np = pdev->dev.of_node; int nr_outputs; - unsigned long flags = 0; + int i, ret; clk_wzrd = devm_kzalloc(&pdev->dev, sizeof(*clk_wzrd), GFP_KERNEL); if (!clk_wzrd) @@ -641,6 +1018,10 @@ static int clk_wzrd_probe(struct platform_device *pdev) goto err_disable_clk; } + data = device_get_match_data(&pdev->dev); + if (data) + is_versal = data->is_versal; + ret = of_property_read_u32(np, "xlnx,nr-outputs", &nr_outputs); if (ret || nr_outputs > WZRD_NUM_OUTPUTS) { ret = -EINVAL; @@ -653,26 +1034,61 @@ static int clk_wzrd_probe(struct platform_device *pdev) goto err_disable_clk; } - if (nr_outputs == 1) { - clk_wzrd->clkout[0] = clk_wzrd_register_divider + if (is_versal) { + if (nr_outputs == 1) { + clk_wzrd->clkout[0] = clk_wzrd_ver_register_divider (&pdev->dev, clkout_name, __clk_get_name(clk_wzrd->clk_in1), 0, - clk_wzrd->base, WZRD_CLK_CFG_REG(3), + clk_wzrd->base, WZRD_CLK_CFG_REG(is_versal, 3), WZRD_CLKOUT_DIVIDE_SHIFT, WZRD_CLKOUT_DIVIDE_WIDTH, CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, DIV_ALL, &clkwzrd_lock); - goto out; - } - - reg = readl(clk_wzrd->base + WZRD_CLK_CFG_REG(0)); - reg_f = reg & WZRD_CLKFBOUT_FRAC_MASK; - reg_f = reg_f >> WZRD_CLKFBOUT_FRAC_SHIFT; + goto out; + } + /* register multiplier */ + edge = !!(readl(clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 0)) & + BIT(8)); + regl = (readl(clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 1)) & + WZRD_CLKFBOUT_L_MASK) >> WZRD_CLKFBOUT_L_SHIFT; + regh = (readl(clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 1)) & + WZRD_CLKFBOUT_H_MASK) >> WZRD_CLKFBOUT_H_SHIFT; + mult = regl + regh + edge; + if (!mult) + mult = 1; + mult = mult * WZRD_FRAC_GRADIENT; + + regl = readl(clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 51)) & + WZRD_CLKFBOUT_FRAC_EN; + if (regl) { + regl = readl(clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 48)) & + WZRD_VERSAL_FRAC_MASK; + mult = mult + regl; + } + div = 64; + } else { + if (nr_outputs == 1) { + clk_wzrd->clkout[0] = clk_wzrd_register_divider + (&pdev->dev, clkout_name, + __clk_get_name(clk_wzrd->clk_in1), 0, + clk_wzrd->base, WZRD_CLK_CFG_REG(is_versal, 3), + WZRD_CLKOUT_DIVIDE_SHIFT, + WZRD_CLKOUT_DIVIDE_WIDTH, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + DIV_ALL, &clkwzrd_lock); - reg = reg & WZRD_CLKFBOUT_MULT_MASK; - reg = reg >> WZRD_CLKFBOUT_MULT_SHIFT; - mult = (reg * 1000) + reg_f; + goto out; + } + reg = readl(clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 0)); + reg_f = reg & WZRD_CLKFBOUT_FRAC_MASK; + reg_f = reg_f >> WZRD_CLKFBOUT_FRAC_SHIFT; + + reg = reg & WZRD_CLKFBOUT_MULT_MASK; + reg = reg >> WZRD_CLKFBOUT_MULT_SHIFT; + mult = (reg * 1000) + reg_f; + div = 1000; + } clk_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_mul", dev_name(&pdev->dev)); if (!clk_name) { ret = -ENOMEM; @@ -681,7 +1097,7 @@ static int clk_wzrd_probe(struct platform_device *pdev) clk_wzrd->clks_internal[wzrd_clk_mul] = clk_register_fixed_factor (&pdev->dev, clk_name, __clk_get_name(clk_wzrd->clk_in1), - 0, mult, 1000); + 0, mult, div); if (IS_ERR(clk_wzrd->clks_internal[wzrd_clk_mul])) { dev_err(&pdev->dev, "unable to register fixed-factor clock\n"); ret = PTR_ERR(clk_wzrd->clks_internal[wzrd_clk_mul]); @@ -694,13 +1110,29 @@ static int clk_wzrd_probe(struct platform_device *pdev) goto err_rm_int_clk; } - ctrl_reg = clk_wzrd->base + WZRD_CLK_CFG_REG(0); - /* register div */ - clk_wzrd->clks_internal[wzrd_clk_mul_div] = clk_register_divider + if (is_versal) { + edged = !!(readl(clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 20)) & + BIT(10)); + regld = (readl(clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 21)) & + WZRD_CLKFBOUT_L_MASK) >> WZRD_CLKFBOUT_L_SHIFT; + reghd = (readl(clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 21)) & + WZRD_CLKFBOUT_H_MASK) >> WZRD_CLKFBOUT_H_SHIFT; + div = (regld + reghd + edged); + if (!div) + div = 1; + + clk_mul_name = __clk_get_name(clk_wzrd->clks_internal[wzrd_clk_mul]); + clk_wzrd->clks_internal[wzrd_clk_mul_div] = + clk_register_fixed_factor(&pdev->dev, clk_name, + clk_mul_name, 0, 1, div); + } else { + ctrl_reg = clk_wzrd->base + WZRD_CLK_CFG_REG(is_versal, 0); + clk_wzrd->clks_internal[wzrd_clk_mul_div] = clk_register_divider (&pdev->dev, clk_name, __clk_get_name(clk_wzrd->clks_internal[wzrd_clk_mul]), flags, ctrl_reg, 0, 8, CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, &clkwzrd_lock); + } if (IS_ERR(clk_wzrd->clks_internal[wzrd_clk_mul_div])) { dev_err(&pdev->dev, "unable to register divider clock\n"); ret = PTR_ERR(clk_wzrd->clks_internal[wzrd_clk_mul_div]); @@ -716,24 +1148,35 @@ static int clk_wzrd_probe(struct platform_device *pdev) goto err_rm_int_clk; } - if (!i) - clk_wzrd->clkout[i] = clk_wzrd_register_divf - (&pdev->dev, clkout_name, - clk_name, flags, - clk_wzrd->base, (WZRD_CLK_CFG_REG(2) + i * 12), - WZRD_CLKOUT_DIVIDE_SHIFT, - WZRD_CLKOUT_DIVIDE_WIDTH, - CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, - DIV_O, &clkwzrd_lock); - else - clk_wzrd->clkout[i] = clk_wzrd_register_divider - (&pdev->dev, clkout_name, - clk_name, 0, - clk_wzrd->base, (WZRD_CLK_CFG_REG(2) + i * 12), - WZRD_CLKOUT_DIVIDE_SHIFT, - WZRD_CLKOUT_DIVIDE_WIDTH, - CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, - DIV_O, &clkwzrd_lock); + if (is_versal) { + clk_wzrd->clkout[i] = clk_wzrd_ver_register_divider + (&pdev->dev, + clkout_name, clk_name, 0, + clk_wzrd->base, + (WZRD_CLK_CFG_REG(is_versal, 3) + i * 8), + WZRD_CLKOUT_DIVIDE_SHIFT, + WZRD_CLKOUT_DIVIDE_WIDTH, + CLK_DIVIDER_ONE_BASED | + CLK_DIVIDER_ALLOW_ZERO, + DIV_O, &clkwzrd_lock); + } else { + if (!i) + clk_wzrd->clkout[i] = clk_wzrd_register_divf + (&pdev->dev, clkout_name, clk_name, flags, clk_wzrd->base, + (WZRD_CLK_CFG_REG(is_versal, 2) + i * 12), + WZRD_CLKOUT_DIVIDE_SHIFT, + WZRD_CLKOUT_DIVIDE_WIDTH, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + DIV_O, &clkwzrd_lock); + else + clk_wzrd->clkout[i] = clk_wzrd_register_divider + (&pdev->dev, clkout_name, clk_name, 0, clk_wzrd->base, + (WZRD_CLK_CFG_REG(is_versal, 2) + i * 12), + WZRD_CLKOUT_DIVIDE_SHIFT, + WZRD_CLKOUT_DIVIDE_WIDTH, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + DIV_O, &clkwzrd_lock); + } if (IS_ERR(clk_wzrd->clkout[i])) { int j; @@ -799,9 +1242,10 @@ static void clk_wzrd_remove(struct platform_device *pdev) } static const struct of_device_id clk_wzrd_ids[] = { - { .compatible = "xlnx,clocking-wizard" }, - { .compatible = "xlnx,clocking-wizard-v5.2" }, - { .compatible = "xlnx,clocking-wizard-v6.0" }, + { .compatible = "xlnx,versal-clk-wizard", .data = &versal_data }, + { .compatible = "xlnx,clocking-wizard" }, + { .compatible = "xlnx,clocking-wizard-v5.2" }, + { .compatible = "xlnx,clocking-wizard-v6.0" }, { }, }; MODULE_DEVICE_TABLE(of, clk_wzrd_ids); diff --git a/drivers/clk/zynqmp/clk-mux-zynqmp.c b/drivers/clk/zynqmp/clk-mux-zynqmp.c index 60359333f26dbe..9b5d3050b74229 100644 --- a/drivers/clk/zynqmp/clk-mux-zynqmp.c +++ b/drivers/clk/zynqmp/clk-mux-zynqmp.c @@ -89,7 +89,7 @@ static int zynqmp_clk_mux_set_parent(struct clk_hw *hw, u8 index) static const struct clk_ops zynqmp_clk_mux_ops = { .get_parent = zynqmp_clk_mux_get_parent, .set_parent = zynqmp_clk_mux_set_parent, - .determine_rate = __clk_mux_determine_rate, + .determine_rate = __clk_mux_determine_rate_closest, }; static const struct clk_ops zynqmp_clk_mux_ro_ops = { diff --git a/drivers/clk/zynqmp/divider.c b/drivers/clk/zynqmp/divider.c index 33a3b2a226595d..5a00487ae408be 100644 --- a/drivers/clk/zynqmp/divider.c +++ b/drivers/clk/zynqmp/divider.c @@ -110,52 +110,6 @@ static unsigned long zynqmp_clk_divider_recalc_rate(struct clk_hw *hw, return DIV_ROUND_UP_ULL(parent_rate, value); } -static void zynqmp_get_divider2_val(struct clk_hw *hw, - unsigned long rate, - struct zynqmp_clk_divider *divider, - u32 *bestdiv) -{ - int div1; - int div2; - long error = LONG_MAX; - unsigned long div1_prate; - struct clk_hw *div1_parent_hw; - struct zynqmp_clk_divider *pdivider; - struct clk_hw *div2_parent_hw = clk_hw_get_parent(hw); - - if (!div2_parent_hw) - return; - - pdivider = to_zynqmp_clk_divider(div2_parent_hw); - if (!pdivider) - return; - - div1_parent_hw = clk_hw_get_parent(div2_parent_hw); - if (!div1_parent_hw) - return; - - div1_prate = clk_hw_get_rate(div1_parent_hw); - *bestdiv = 1; - for (div1 = 1; div1 <= pdivider->max_div;) { - for (div2 = 1; div2 <= divider->max_div;) { - long new_error = ((div1_prate / div1) / div2) - rate; - - if (abs(new_error) < abs(error)) { - *bestdiv = div2; - error = new_error; - } - if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) - div2 = div2 << 1; - else - div2++; - } - if (pdivider->flags & CLK_DIVIDER_POWER_OF_TWO) - div1 = div1 << 1; - else - div1++; - } -} - /** * zynqmp_clk_divider_round_rate() - Round rate of divider clock * @hw: handle between common and hardware-specific interfaces @@ -174,6 +128,7 @@ static long zynqmp_clk_divider_round_rate(struct clk_hw *hw, u32 div_type = divider->div_type; u32 bestdiv; int ret; + u8 width; /* if read only, just return current value */ if (divider->flags & CLK_DIVIDER_READ_ONLY) { @@ -193,23 +148,12 @@ static long zynqmp_clk_divider_round_rate(struct clk_hw *hw, return DIV_ROUND_UP_ULL((u64)*prate, bestdiv); } - bestdiv = zynqmp_divider_get_val(*prate, rate, divider->flags); - - /* - * In case of two divisors, compute best divider values and return - * divider2 value based on compute value. div1 will be automatically - * set to optimum based on required total divider value. - */ - if (div_type == TYPE_DIV2 && - (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) { - zynqmp_get_divider2_val(hw, rate, divider, &bestdiv); - } + width = fls(divider->max_div); - if ((clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) && divider->is_frac) - bestdiv = rate % *prate ? 1 : bestdiv; + rate = divider_round_rate(hw, rate, prate, NULL, width, divider->flags); - bestdiv = min_t(u32, bestdiv, divider->max_div); - *prate = rate * bestdiv; + if (divider->is_frac && (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) && (rate % *prate)) + *prate = rate; return rate; } diff --git a/drivers/clocksource/timer-cadence-ttc.c b/drivers/clocksource/timer-cadence-ttc.c index 32daaac9b13208..ca7a06489c405f 100644 --- a/drivers/clocksource/timer-cadence-ttc.c +++ b/drivers/clocksource/timer-cadence-ttc.c @@ -69,7 +69,7 @@ * @base_addr: Base address of timer * @freq: Timer input clock frequency * @clk: Associated clock source - * @clk_rate_change_nb Notifier block for clock rate changes + * @clk_rate_change_nb: Notifier block for clock rate changes */ struct ttc_timer { void __iomem *base_addr; @@ -134,7 +134,7 @@ static void ttc_set_interval(struct ttc_timer *timer, * @irq: IRQ number of the Timer * @dev_id: void pointer to the ttc_timer instance * - * returns: Always IRQ_HANDLED - success + * Returns: Always IRQ_HANDLED - success **/ static irqreturn_t ttc_clock_event_interrupt(int irq, void *dev_id) { @@ -151,8 +151,9 @@ static irqreturn_t ttc_clock_event_interrupt(int irq, void *dev_id) /** * __ttc_clocksource_read - Reads the timer counter register + * @cs: &clocksource to read from * - * returns: Current timer counter register value + * Returns: Current timer counter register value **/ static u64 __ttc_clocksource_read(struct clocksource *cs) { @@ -173,7 +174,7 @@ static u64 notrace ttc_sched_clock_read(void) * @cycles: Timer interval ticks * @evt: Address of clock event instance * - * returns: Always 0 - success + * Returns: Always %0 - success **/ static int ttc_set_next_event(unsigned long cycles, struct clock_event_device *evt) @@ -186,9 +187,12 @@ static int ttc_set_next_event(unsigned long cycles, } /** - * ttc_set_{shutdown|oneshot|periodic} - Sets the state of timer - * + * ttc_shutdown - Sets the state of timer * @evt: Address of clock event instance + * + * Used for shutdown or oneshot. + * + * Returns: Always %0 - success **/ static int ttc_shutdown(struct clock_event_device *evt) { @@ -202,6 +206,12 @@ static int ttc_shutdown(struct clock_event_device *evt) return 0; } +/** + * ttc_set_periodic - Sets the state of timer + * @evt: Address of clock event instance + * + * Returns: Always %0 - success + */ static int ttc_set_periodic(struct clock_event_device *evt) { struct ttc_timer_clockevent *ttce = to_ttc_timer_clkevent(evt); diff --git a/drivers/clocksource/timer-ep93xx.c b/drivers/clocksource/timer-ep93xx.c index bc0ca6e1233490..6981ff3ac8a940 100644 --- a/drivers/clocksource/timer-ep93xx.c +++ b/drivers/clocksource/timer-ep93xx.c @@ -155,9 +155,8 @@ static int __init ep93xx_timer_of_init(struct device_node *np) ep93xx_tcu = tcu; irq = irq_of_parse_and_map(np, 0); - if (irq == 0) - irq = -EINVAL; - if (irq < 0) { + if (!irq) { + ret = -EINVAL; pr_err("EP93XX Timer Can't parse IRQ %d", irq); goto out_free; } diff --git a/drivers/clocksource/timer-riscv.c b/drivers/clocksource/timer-riscv.c index 57857c0dfba97e..e66dcbd6656658 100644 --- a/drivers/clocksource/timer-riscv.c +++ b/drivers/clocksource/timer-riscv.c @@ -61,12 +61,19 @@ static int riscv_clock_next_event(unsigned long delta, return 0; } +static int riscv_clock_shutdown(struct clock_event_device *evt) +{ + riscv_clock_event_stop(); + return 0; +} + static unsigned int riscv_clock_event_irq; static DEFINE_PER_CPU(struct clock_event_device, riscv_clock_event) = { .name = "riscv_timer_clockevent", .features = CLOCK_EVT_FEAT_ONESHOT, .rating = 100, .set_next_event = riscv_clock_next_event, + .set_state_shutdown = riscv_clock_shutdown, }; /* diff --git a/drivers/clocksource/timer-ti-dm.c b/drivers/clocksource/timer-ti-dm.c index 5f60f6bd33866b..56acf26172621f 100644 --- a/drivers/clocksource/timer-ti-dm.c +++ b/drivers/clocksource/timer-ti-dm.c @@ -183,7 +183,7 @@ static inline u32 dmtimer_read(struct dmtimer *timer, u32 reg) * dmtimer_write - write timer registers in posted and non-posted mode * @timer: timer pointer over which write operation is to perform * @reg: lowest byte holds the register offset - * @value: data to write into the register + * @val: data to write into the register * * The posted mode bit is encoded in reg. Note that in posted mode, the write * pending bit must be checked. Otherwise a write on a register which has a @@ -949,7 +949,7 @@ static int omap_dm_timer_set_int_enable(struct omap_dm_timer *cookie, /** * omap_dm_timer_set_int_disable - disable timer interrupts - * @timer: pointer to timer handle + * @cookie: pointer to timer cookie * @mask: bit mask of interrupts to be disabled * * Disables the specified timer interrupts for a timer. diff --git a/drivers/comedi/comedi_fops.c b/drivers/comedi/comedi_fops.c index 1548dea15df140..1b481731df964e 100644 --- a/drivers/comedi/comedi_fops.c +++ b/drivers/comedi/comedi_fops.c @@ -1714,8 +1714,8 @@ static int __comedi_get_user_chanlist(struct comedi_device *dev, lockdep_assert_held(&dev->mutex); cmd->chanlist = NULL; - chanlist = memdup_user(user_chanlist, - cmd->chanlist_len * sizeof(unsigned int)); + chanlist = memdup_array_user(user_chanlist, + cmd->chanlist_len, sizeof(unsigned int)); if (IS_ERR(chanlist)) return PTR_ERR(chanlist); diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c index 7f7b94f616a66c..4028e8eeba821e 100644 --- a/drivers/connector/connector.c +++ b/drivers/connector/connector.c @@ -59,9 +59,8 @@ static int cn_already_initialized; * both, or if both are zero then the group is looked up and sent there. */ int cn_netlink_send_mult(struct cn_msg *msg, u16 len, u32 portid, u32 __group, - gfp_t gfp_mask, - int (*filter)(struct sock *dsk, struct sk_buff *skb, void *data), - void *filter_data) + gfp_t gfp_mask, netlink_filter_fn filter, + void *filter_data) { struct cn_callback_entry *__cbq; unsigned int size; diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c index 1f6186475715e0..1791d37fbc53c5 100644 --- a/drivers/cpufreq/amd-pstate.c +++ b/drivers/cpufreq/amd-pstate.c @@ -1232,14 +1232,13 @@ static void amd_pstate_epp_update_limit(struct cpufreq_policy *policy) max_limit_perf = div_u64(policy->max * cpudata->highest_perf, cpudata->max_freq); min_limit_perf = div_u64(policy->min * cpudata->highest_perf, cpudata->max_freq); + WRITE_ONCE(cpudata->max_limit_perf, max_limit_perf); + WRITE_ONCE(cpudata->min_limit_perf, min_limit_perf); + max_perf = clamp_t(unsigned long, max_perf, cpudata->min_limit_perf, cpudata->max_limit_perf); min_perf = clamp_t(unsigned long, min_perf, cpudata->min_limit_perf, cpudata->max_limit_perf); - - WRITE_ONCE(cpudata->max_limit_perf, max_limit_perf); - WRITE_ONCE(cpudata->min_limit_perf, min_limit_perf); - value = READ_ONCE(cpudata->cppc_req_cached); if (cpudata->policy == CPUFREQ_POLICY_PERFORMANCE) diff --git a/drivers/cpufreq/armada-8k-cpufreq.c b/drivers/cpufreq/armada-8k-cpufreq.c index 8afefdea4d80c9..ce5a5641b6dd0e 100644 --- a/drivers/cpufreq/armada-8k-cpufreq.c +++ b/drivers/cpufreq/armada-8k-cpufreq.c @@ -57,7 +57,7 @@ static void __init armada_8k_get_sharing_cpus(struct clk *cur_clk, continue; } - clk = clk_get(cpu_dev, 0); + clk = clk_get(cpu_dev, NULL); if (IS_ERR(clk)) { pr_warn("Cannot get clock for CPU %d\n", cpu); } else { @@ -165,7 +165,7 @@ static int __init armada_8k_cpufreq_init(void) continue; } - clk = clk_get(cpu_dev, 0); + clk = clk_get(cpu_dev, NULL); if (IS_ERR(clk)) { pr_err("Cannot get clock for CPU %d\n", cpu); diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c index fe08ca419b3dc3..64420d9cfd1ed3 100644 --- a/drivers/cpufreq/cppc_cpufreq.c +++ b/drivers/cpufreq/cppc_cpufreq.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -27,12 +26,6 @@ #include -/* Minimum struct length needed for the DMI processor entry we want */ -#define DMI_ENTRY_PROCESSOR_MIN_LENGTH 48 - -/* Offset in the DMI processor structure for the max frequency */ -#define DMI_PROCESSOR_MAX_SPEED 0x14 - /* * This list contains information parsed from per CPU ACPI _CPC and _PSD * structures: e.g. the highest and lowest supported performance, capabilities, @@ -291,97 +284,9 @@ static inline void cppc_freq_invariance_exit(void) } #endif /* CONFIG_ACPI_CPPC_CPUFREQ_FIE */ -/* Callback function used to retrieve the max frequency from DMI */ -static void cppc_find_dmi_mhz(const struct dmi_header *dm, void *private) -{ - const u8 *dmi_data = (const u8 *)dm; - u16 *mhz = (u16 *)private; - - if (dm->type == DMI_ENTRY_PROCESSOR && - dm->length >= DMI_ENTRY_PROCESSOR_MIN_LENGTH) { - u16 val = (u16)get_unaligned((const u16 *) - (dmi_data + DMI_PROCESSOR_MAX_SPEED)); - *mhz = val > *mhz ? val : *mhz; - } -} - -/* Look up the max frequency in DMI */ -static u64 cppc_get_dmi_max_khz(void) -{ - u16 mhz = 0; - - dmi_walk(cppc_find_dmi_mhz, &mhz); - - /* - * Real stupid fallback value, just in case there is no - * actual value set. - */ - mhz = mhz ? mhz : 1; - - return (1000 * mhz); -} - -/* - * If CPPC lowest_freq and nominal_freq registers are exposed then we can - * use them to convert perf to freq and vice versa. The conversion is - * extrapolated as an affine function passing by the 2 points: - * - (Low perf, Low freq) - * - (Nominal perf, Nominal perf) - */ -static unsigned int cppc_cpufreq_perf_to_khz(struct cppc_cpudata *cpu_data, - unsigned int perf) -{ - struct cppc_perf_caps *caps = &cpu_data->perf_caps; - s64 retval, offset = 0; - static u64 max_khz; - u64 mul, div; - - if (caps->lowest_freq && caps->nominal_freq) { - mul = caps->nominal_freq - caps->lowest_freq; - div = caps->nominal_perf - caps->lowest_perf; - offset = caps->nominal_freq - div64_u64(caps->nominal_perf * mul, div); - } else { - if (!max_khz) - max_khz = cppc_get_dmi_max_khz(); - mul = max_khz; - div = caps->highest_perf; - } - - retval = offset + div64_u64(perf * mul, div); - if (retval >= 0) - return retval; - return 0; -} - -static unsigned int cppc_cpufreq_khz_to_perf(struct cppc_cpudata *cpu_data, - unsigned int freq) -{ - struct cppc_perf_caps *caps = &cpu_data->perf_caps; - s64 retval, offset = 0; - static u64 max_khz; - u64 mul, div; - - if (caps->lowest_freq && caps->nominal_freq) { - mul = caps->nominal_perf - caps->lowest_perf; - div = caps->nominal_freq - caps->lowest_freq; - offset = caps->nominal_perf - div64_u64(caps->nominal_freq * mul, div); - } else { - if (!max_khz) - max_khz = cppc_get_dmi_max_khz(); - mul = caps->highest_perf; - div = max_khz; - } - - retval = offset + div64_u64(freq * mul, div); - if (retval >= 0) - return retval; - return 0; -} - static int cppc_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) - { struct cppc_cpudata *cpu_data = policy->driver_data; unsigned int cpu = policy->cpu; @@ -389,7 +294,7 @@ static int cppc_cpufreq_set_target(struct cpufreq_policy *policy, u32 desired_perf; int ret = 0; - desired_perf = cppc_cpufreq_khz_to_perf(cpu_data, target_freq); + desired_perf = cppc_khz_to_perf(&cpu_data->perf_caps, target_freq); /* Return if it is exactly the same perf */ if (desired_perf == cpu_data->perf_ctrls.desired_perf) return ret; @@ -417,7 +322,7 @@ static unsigned int cppc_cpufreq_fast_switch(struct cpufreq_policy *policy, u32 desired_perf; int ret; - desired_perf = cppc_cpufreq_khz_to_perf(cpu_data, target_freq); + desired_perf = cppc_khz_to_perf(&cpu_data->perf_caps, target_freq); cpu_data->perf_ctrls.desired_perf = desired_perf; ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls); @@ -530,7 +435,7 @@ static int cppc_get_cpu_power(struct device *cpu_dev, min_step = min_cap / CPPC_EM_CAP_STEP; max_step = max_cap / CPPC_EM_CAP_STEP; - perf_prev = cppc_cpufreq_khz_to_perf(cpu_data, *KHz); + perf_prev = cppc_khz_to_perf(perf_caps, *KHz); step = perf_prev / perf_step; if (step > max_step) @@ -550,8 +455,8 @@ static int cppc_get_cpu_power(struct device *cpu_dev, perf = step * perf_step; } - *KHz = cppc_cpufreq_perf_to_khz(cpu_data, perf); - perf_check = cppc_cpufreq_khz_to_perf(cpu_data, *KHz); + *KHz = cppc_perf_to_khz(perf_caps, perf); + perf_check = cppc_khz_to_perf(perf_caps, *KHz); step_check = perf_check / perf_step; /* @@ -561,8 +466,8 @@ static int cppc_get_cpu_power(struct device *cpu_dev, */ while ((*KHz == prev_freq) || (step_check != step)) { perf++; - *KHz = cppc_cpufreq_perf_to_khz(cpu_data, perf); - perf_check = cppc_cpufreq_khz_to_perf(cpu_data, *KHz); + *KHz = cppc_perf_to_khz(perf_caps, perf); + perf_check = cppc_khz_to_perf(perf_caps, *KHz); step_check = perf_check / perf_step; } @@ -591,7 +496,7 @@ static int cppc_get_cpu_cost(struct device *cpu_dev, unsigned long KHz, perf_caps = &cpu_data->perf_caps; max_cap = arch_scale_cpu_capacity(cpu_dev->id); - perf_prev = cppc_cpufreq_khz_to_perf(cpu_data, KHz); + perf_prev = cppc_khz_to_perf(perf_caps, KHz); perf_step = CPPC_EM_CAP_STEP * perf_caps->highest_perf / max_cap; step = perf_prev / perf_step; @@ -679,10 +584,6 @@ static struct cppc_cpudata *cppc_cpufreq_get_cpu_data(unsigned int cpu) goto free_mask; } - /* Convert the lowest and nominal freq from MHz to KHz */ - cpu_data->perf_caps.lowest_freq *= 1000; - cpu_data->perf_caps.nominal_freq *= 1000; - list_add(&cpu_data->node, &cpu_data_list); return cpu_data; @@ -724,20 +625,16 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) * Set min to lowest nonlinear perf to avoid any efficiency penalty (see * Section 8.4.7.1.1.5 of ACPI 6.1 spec) */ - policy->min = cppc_cpufreq_perf_to_khz(cpu_data, - caps->lowest_nonlinear_perf); - policy->max = cppc_cpufreq_perf_to_khz(cpu_data, - caps->nominal_perf); + policy->min = cppc_perf_to_khz(caps, caps->lowest_nonlinear_perf); + policy->max = cppc_perf_to_khz(caps, caps->nominal_perf); /* * Set cpuinfo.min_freq to Lowest to make the full range of performance * available if userspace wants to use any perf between lowest & lowest * nonlinear perf */ - policy->cpuinfo.min_freq = cppc_cpufreq_perf_to_khz(cpu_data, - caps->lowest_perf); - policy->cpuinfo.max_freq = cppc_cpufreq_perf_to_khz(cpu_data, - caps->nominal_perf); + policy->cpuinfo.min_freq = cppc_perf_to_khz(caps, caps->lowest_perf); + policy->cpuinfo.max_freq = cppc_perf_to_khz(caps, caps->nominal_perf); policy->transition_delay_us = cppc_cpufreq_get_transition_delay_us(cpu); policy->shared_type = cpu_data->shared_type; @@ -773,7 +670,7 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) boost_supported = true; /* Set policy->cur to max now. The governors will adjust later. */ - policy->cur = cppc_cpufreq_perf_to_khz(cpu_data, caps->highest_perf); + policy->cur = cppc_perf_to_khz(caps, caps->highest_perf); cpu_data->perf_ctrls.desired_perf = caps->highest_perf; ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls); @@ -863,7 +760,7 @@ static unsigned int cppc_cpufreq_get_rate(unsigned int cpu) delivered_perf = cppc_perf_from_fbctrs(cpu_data, &fb_ctrs_t0, &fb_ctrs_t1); - return cppc_cpufreq_perf_to_khz(cpu_data, delivered_perf); + return cppc_perf_to_khz(&cpu_data->perf_caps, delivered_perf); } static int cppc_cpufreq_set_boost(struct cpufreq_policy *policy, int state) @@ -878,11 +775,9 @@ static int cppc_cpufreq_set_boost(struct cpufreq_policy *policy, int state) } if (state) - policy->max = cppc_cpufreq_perf_to_khz(cpu_data, - caps->highest_perf); + policy->max = cppc_perf_to_khz(caps, caps->highest_perf); else - policy->max = cppc_cpufreq_perf_to_khz(cpu_data, - caps->nominal_perf); + policy->max = cppc_perf_to_khz(caps, caps->nominal_perf); policy->cpuinfo.max_freq = policy->max; ret = freq_qos_update_request(policy->max_freq_req, policy->max); @@ -937,7 +832,7 @@ static unsigned int hisi_cppc_cpufreq_get_rate(unsigned int cpu) if (ret < 0) return -EIO; - return cppc_cpufreq_perf_to_khz(cpu_data, desired_perf); + return cppc_perf_to_khz(&cpu_data->perf_caps, desired_perf); } static void cppc_check_hisi_workaround(void) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 934d35f570b7a0..44db4f59c4cc6c 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -454,7 +454,7 @@ void cpufreq_freq_transition_end(struct cpufreq_policy *policy, arch_set_freq_scale(policy->related_cpus, policy->cur, - policy->cpuinfo.max_freq); + arch_scale_freq_ref(policy->cpu)); spin_lock(&policy->transition_lock); policy->transition_ongoing = false; @@ -2174,7 +2174,7 @@ unsigned int cpufreq_driver_fast_switch(struct cpufreq_policy *policy, policy->cur = freq; arch_set_freq_scale(policy->related_cpus, freq, - policy->cpuinfo.max_freq); + arch_scale_freq_ref(policy->cpu)); cpufreq_stats_record_transition(policy, freq); if (trace_cpu_frequency_enabled()) { diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index a534a1f7f1ee73..ca94e60e705a1d 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -302,7 +302,10 @@ static bool hwp_forced __read_mostly; static struct cpufreq_driver *intel_pstate_driver __read_mostly; -#define HYBRID_SCALING_FACTOR 78741 +#define HYBRID_SCALING_FACTOR 78741 +#define HYBRID_SCALING_FACTOR_MTL 80000 + +static int hybrid_scaling_factor = HYBRID_SCALING_FACTOR; static inline int core_get_scaling(void) { @@ -422,7 +425,7 @@ static int intel_pstate_cppc_get_scaling(int cpu) */ if (!ret && cppc_perf.nominal_perf && cppc_perf.nominal_freq && cppc_perf.nominal_perf * 100 != cppc_perf.nominal_freq) - return HYBRID_SCALING_FACTOR; + return hybrid_scaling_factor; return core_get_scaling(); } @@ -526,6 +529,30 @@ static int intel_pstate_cppc_get_scaling(int cpu) } #endif /* CONFIG_ACPI_CPPC_LIB */ +static int intel_pstate_freq_to_hwp_rel(struct cpudata *cpu, int freq, + unsigned int relation) +{ + if (freq == cpu->pstate.turbo_freq) + return cpu->pstate.turbo_pstate; + + if (freq == cpu->pstate.max_freq) + return cpu->pstate.max_pstate; + + switch (relation) { + case CPUFREQ_RELATION_H: + return freq / cpu->pstate.scaling; + case CPUFREQ_RELATION_C: + return DIV_ROUND_CLOSEST(freq, cpu->pstate.scaling); + } + + return DIV_ROUND_UP(freq, cpu->pstate.scaling); +} + +static int intel_pstate_freq_to_hwp(struct cpudata *cpu, int freq) +{ + return intel_pstate_freq_to_hwp_rel(cpu, freq, CPUFREQ_RELATION_L); +} + /** * intel_pstate_hybrid_hwp_adjust - Calibrate HWP performance levels. * @cpu: Target CPU. @@ -543,6 +570,7 @@ static void intel_pstate_hybrid_hwp_adjust(struct cpudata *cpu) int perf_ctl_scaling = cpu->pstate.perf_ctl_scaling; int perf_ctl_turbo = pstate_funcs.get_turbo(cpu->cpu); int scaling = cpu->pstate.scaling; + int freq; pr_debug("CPU%d: perf_ctl_max_phys = %d\n", cpu->cpu, perf_ctl_max_phys); pr_debug("CPU%d: perf_ctl_turbo = %d\n", cpu->cpu, perf_ctl_turbo); @@ -556,16 +584,16 @@ static void intel_pstate_hybrid_hwp_adjust(struct cpudata *cpu) cpu->pstate.max_freq = rounddown(cpu->pstate.max_pstate * scaling, perf_ctl_scaling); - cpu->pstate.max_pstate_physical = - DIV_ROUND_UP(perf_ctl_max_phys * perf_ctl_scaling, - scaling); + freq = perf_ctl_max_phys * perf_ctl_scaling; + cpu->pstate.max_pstate_physical = intel_pstate_freq_to_hwp(cpu, freq); - cpu->pstate.min_freq = cpu->pstate.min_pstate * perf_ctl_scaling; + freq = cpu->pstate.min_pstate * perf_ctl_scaling; + cpu->pstate.min_freq = freq; /* * Cast the min P-state value retrieved via pstate_funcs.get_min() to * the effective range of HWP performance levels. */ - cpu->pstate.min_pstate = DIV_ROUND_UP(cpu->pstate.min_freq, scaling); + cpu->pstate.min_pstate = intel_pstate_freq_to_hwp(cpu, freq); } static inline void update_turbo_state(void) @@ -1691,13 +1719,6 @@ static void intel_pstate_update_epp_defaults(struct cpudata *cpudata) { cpudata->epp_default = intel_pstate_get_epp(cpudata, 0); - /* - * If this CPU gen doesn't call for change in balance_perf - * EPP return. - */ - if (epp_values[EPP_INDEX_BALANCE_PERFORMANCE] == HWP_EPP_BALANCE_PERFORMANCE) - return; - /* * If the EPP is set by firmware, which means that firmware enabled HWP * - Is equal or less than 0x80 (default balance_perf EPP) @@ -1710,6 +1731,13 @@ static void intel_pstate_update_epp_defaults(struct cpudata *cpudata) return; } + /* + * If this CPU gen doesn't call for change in balance_perf + * EPP return. + */ + if (epp_values[EPP_INDEX_BALANCE_PERFORMANCE] == HWP_EPP_BALANCE_PERFORMANCE) + return; + /* * Use hard coded value per gen to update the balance_perf * and default EPP. @@ -1968,7 +1996,7 @@ static int hwp_get_cpu_scaling(int cpu) smp_call_function_single(cpu, hybrid_get_type, &cpu_type, 1); /* P-cores have a smaller perf level-to-freqency scaling factor. */ if (cpu_type == 0x40) - return HYBRID_SCALING_FACTOR; + return hybrid_scaling_factor; /* Use default core scaling for E-cores */ if (cpu_type == 0x20) @@ -2406,6 +2434,7 @@ static const struct x86_cpu_id intel_pstate_cpu_ids[] = { X86_MATCH(ICELAKE_X, core_funcs), X86_MATCH(TIGERLAKE, core_funcs), X86_MATCH(SAPPHIRERAPIDS_X, core_funcs), + X86_MATCH(EMERALDRAPIDS_X, core_funcs), {} }; MODULE_DEVICE_TABLE(x86cpu, intel_pstate_cpu_ids); @@ -2524,13 +2553,12 @@ static void intel_pstate_update_perf_limits(struct cpudata *cpu, * abstract values to represent performance rather than pure ratios. */ if (hwp_active && cpu->pstate.scaling != perf_ctl_scaling) { - int scaling = cpu->pstate.scaling; int freq; freq = max_policy_perf * perf_ctl_scaling; - max_policy_perf = DIV_ROUND_UP(freq, scaling); + max_policy_perf = intel_pstate_freq_to_hwp(cpu, freq); freq = min_policy_perf * perf_ctl_scaling; - min_policy_perf = DIV_ROUND_UP(freq, scaling); + min_policy_perf = intel_pstate_freq_to_hwp(cpu, freq); } pr_debug("cpu:%d min_policy_perf:%d max_policy_perf:%d\n", @@ -2904,18 +2932,7 @@ static int intel_cpufreq_target(struct cpufreq_policy *policy, cpufreq_freq_transition_begin(policy, &freqs); - switch (relation) { - case CPUFREQ_RELATION_L: - target_pstate = DIV_ROUND_UP(freqs.new, cpu->pstate.scaling); - break; - case CPUFREQ_RELATION_H: - target_pstate = freqs.new / cpu->pstate.scaling; - break; - default: - target_pstate = DIV_ROUND_CLOSEST(freqs.new, cpu->pstate.scaling); - break; - } - + target_pstate = intel_pstate_freq_to_hwp_rel(cpu, freqs.new, relation); target_pstate = intel_cpufreq_update_pstate(policy, target_pstate, false); freqs.new = target_pstate * cpu->pstate.scaling; @@ -2933,7 +2950,7 @@ static unsigned int intel_cpufreq_fast_switch(struct cpufreq_policy *policy, update_turbo_state(); - target_pstate = DIV_ROUND_UP(target_freq, cpu->pstate.scaling); + target_pstate = intel_pstate_freq_to_hwp(cpu, target_freq); target_pstate = intel_cpufreq_update_pstate(policy, target_pstate, true); @@ -3398,6 +3415,11 @@ static const struct x86_cpu_id intel_epp_balance_perf[] = { {} }; +static const struct x86_cpu_id intel_hybrid_scaling_factor[] = { + X86_MATCH_INTEL_FAM6_MODEL(METEORLAKE_L, HYBRID_SCALING_FACTOR_MTL), + {} +}; + static int __init intel_pstate_init(void) { static struct cpudata **_all_cpu_data; @@ -3488,9 +3510,16 @@ hwp_cpu_matched: if (hwp_active) { const struct x86_cpu_id *id = x86_match_cpu(intel_epp_balance_perf); + const struct x86_cpu_id *hybrid_id = x86_match_cpu(intel_hybrid_scaling_factor); if (id) epp_values[EPP_INDEX_BALANCE_PERFORMANCE] = id->driver_data; + + if (hybrid_id) { + hybrid_scaling_factor = hybrid_id->driver_data; + pr_debug("hybrid scaling factor: %d\n", hybrid_scaling_factor); + } + } mutex_lock(&intel_pstate_driver_lock); diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c index c8a7ccc42c164f..4ee23f4ebf4a40 100644 --- a/drivers/cpufreq/scmi-cpufreq.c +++ b/drivers/cpufreq/scmi-cpufreq.c @@ -334,8 +334,11 @@ static int scmi_cpufreq_probe(struct scmi_device *sdev) #ifdef CONFIG_COMMON_CLK /* dummy clock provider as needed by OPP if clocks property is used */ - if (of_property_present(dev->of_node, "#clock-cells")) - devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, NULL); + if (of_property_present(dev->of_node, "#clock-cells")) { + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, NULL); + if (ret) + return dev_err_probe(dev, ret, "%s: registering clock provider failed\n", __func__); + } #endif ret = cpufreq_register_driver(&scmi_cpufreq_driver); diff --git a/drivers/cpuidle/cpuidle-haltpoll.c b/drivers/cpuidle/cpuidle-haltpoll.c index e66df22f96955f..d8515d5c0853dc 100644 --- a/drivers/cpuidle/cpuidle-haltpoll.c +++ b/drivers/cpuidle/cpuidle-haltpoll.c @@ -25,13 +25,12 @@ MODULE_PARM_DESC(force, "Load unconditionally"); static struct cpuidle_device __percpu *haltpoll_cpuidle_devices; static enum cpuhp_state haltpoll_hp_state; -static int default_enter_idle(struct cpuidle_device *dev, - struct cpuidle_driver *drv, int index) +static __cpuidle int default_enter_idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) { - if (current_clr_polling_and_test()) { - local_irq_enable(); + if (current_clr_polling_and_test()) return index; - } + arch_cpu_idle(); return index; } diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 79c3bb9c99c3bf..0991f026cb0703 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -306,6 +306,7 @@ config CRYPTO_DEV_SAHARA select CRYPTO_SKCIPHER select CRYPTO_AES select CRYPTO_ECB + select CRYPTO_ENGINE help This option enables support for the SAHARA HW crypto accelerator found in some Freescale i.MX chips. diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c index 8d4c42863a621e..1262a7773ef304 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-cipher.c @@ -431,8 +431,8 @@ int sun8i_ce_cipher_init(struct crypto_tfm *tfm) return PTR_ERR(op->fallback_tfm); } - sktfm->reqsize = sizeof(struct sun8i_cipher_req_ctx) + - crypto_skcipher_reqsize(op->fallback_tfm); + crypto_skcipher_set_reqsize(sktfm, sizeof(struct sun8i_cipher_req_ctx) + + crypto_skcipher_reqsize(op->fallback_tfm)); memcpy(algt->fbname, crypto_tfm_alg_driver_name(crypto_skcipher_tfm(op->fallback_tfm)), diff --git a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c index 7fa359725ec75f..9b9605ce8ee629 100644 --- a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c +++ b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-cipher.c @@ -405,9 +405,8 @@ int sun8i_ss_cipher_init(struct crypto_tfm *tfm) return PTR_ERR(op->fallback_tfm); } - sktfm->reqsize = sizeof(struct sun8i_cipher_req_ctx) + - crypto_skcipher_reqsize(op->fallback_tfm); - + crypto_skcipher_set_reqsize(sktfm, sizeof(struct sun8i_cipher_req_ctx) + + crypto_skcipher_reqsize(op->fallback_tfm)); memcpy(algt->fbname, crypto_tfm_alg_driver_name(crypto_skcipher_tfm(op->fallback_tfm)), diff --git a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c index d70b105dcfa1b3..753f67a36dc505 100644 --- a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c +++ b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c @@ -30,33 +30,16 @@ static int sun8i_ss_hashkey(struct sun8i_ss_hash_tfm_ctx *tfmctx, const u8 *key, unsigned int keylen) { struct crypto_shash *xtfm; - struct shash_desc *sdesc; - size_t len; - int ret = 0; + int ret; xtfm = crypto_alloc_shash("sha1", 0, CRYPTO_ALG_NEED_FALLBACK); if (IS_ERR(xtfm)) return PTR_ERR(xtfm); - len = sizeof(*sdesc) + crypto_shash_descsize(xtfm); - sdesc = kmalloc(len, GFP_KERNEL); - if (!sdesc) { - ret = -ENOMEM; - goto err_hashkey_sdesc; - } - sdesc->tfm = xtfm; - - ret = crypto_shash_init(sdesc); - if (ret) { - dev_err(tfmctx->ss->dev, "shash init error ret=%d\n", ret); - goto err_hashkey; - } - ret = crypto_shash_finup(sdesc, key, keylen, tfmctx->key); + ret = crypto_shash_tfm_digest(xtfm, key, keylen, tfmctx->key); if (ret) - dev_err(tfmctx->ss->dev, "shash finup error\n"); -err_hashkey: - kfree(sdesc); -err_hashkey_sdesc: + dev_err(tfmctx->ss->dev, "shash digest error ret=%d\n", ret); + crypto_free_shash(xtfm); return ret; } diff --git a/drivers/crypto/amcc/crypto4xx_alg.c b/drivers/crypto/amcc/crypto4xx_alg.c index ded73224273295..e0af611a95d88f 100644 --- a/drivers/crypto/amcc/crypto4xx_alg.c +++ b/drivers/crypto/amcc/crypto4xx_alg.c @@ -181,13 +181,6 @@ int crypto4xx_setkey_aes_cbc(struct crypto_skcipher *cipher, CRYPTO_FEEDBACK_MODE_NO_FB); } -int crypto4xx_setkey_aes_cfb(struct crypto_skcipher *cipher, - const u8 *key, unsigned int keylen) -{ - return crypto4xx_setkey_aes(cipher, key, keylen, CRYPTO_MODE_CFB, - CRYPTO_FEEDBACK_MODE_128BIT_CFB); -} - int crypto4xx_setkey_aes_ecb(struct crypto_skcipher *cipher, const u8 *key, unsigned int keylen) { @@ -195,13 +188,6 @@ int crypto4xx_setkey_aes_ecb(struct crypto_skcipher *cipher, CRYPTO_FEEDBACK_MODE_NO_FB); } -int crypto4xx_setkey_aes_ofb(struct crypto_skcipher *cipher, - const u8 *key, unsigned int keylen) -{ - return crypto4xx_setkey_aes(cipher, key, keylen, CRYPTO_MODE_OFB, - CRYPTO_FEEDBACK_MODE_64BIT_OFB); -} - int crypto4xx_setkey_rfc3686(struct crypto_skcipher *cipher, const u8 *key, unsigned int keylen) { diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c index 8d53372245ad6b..6006703fb6d767 100644 --- a/drivers/crypto/amcc/crypto4xx_core.c +++ b/drivers/crypto/amcc/crypto4xx_core.c @@ -1209,26 +1209,6 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = { .init = crypto4xx_sk_init, .exit = crypto4xx_sk_exit, } }, - { .type = CRYPTO_ALG_TYPE_SKCIPHER, .u.cipher = { - .base = { - .cra_name = "cfb(aes)", - .cra_driver_name = "cfb-aes-ppc4xx", - .cra_priority = CRYPTO4XX_CRYPTO_PRIORITY, - .cra_flags = CRYPTO_ALG_ASYNC | - CRYPTO_ALG_KERN_DRIVER_ONLY, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct crypto4xx_ctx), - .cra_module = THIS_MODULE, - }, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_IV_SIZE, - .setkey = crypto4xx_setkey_aes_cfb, - .encrypt = crypto4xx_encrypt_iv_stream, - .decrypt = crypto4xx_decrypt_iv_stream, - .init = crypto4xx_sk_init, - .exit = crypto4xx_sk_exit, - } }, { .type = CRYPTO_ALG_TYPE_SKCIPHER, .u.cipher = { .base = { .cra_name = "ctr(aes)", @@ -1289,26 +1269,6 @@ static struct crypto4xx_alg_common crypto4xx_alg[] = { .init = crypto4xx_sk_init, .exit = crypto4xx_sk_exit, } }, - { .type = CRYPTO_ALG_TYPE_SKCIPHER, .u.cipher = { - .base = { - .cra_name = "ofb(aes)", - .cra_driver_name = "ofb-aes-ppc4xx", - .cra_priority = CRYPTO4XX_CRYPTO_PRIORITY, - .cra_flags = CRYPTO_ALG_ASYNC | - CRYPTO_ALG_KERN_DRIVER_ONLY, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct crypto4xx_ctx), - .cra_module = THIS_MODULE, - }, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_IV_SIZE, - .setkey = crypto4xx_setkey_aes_ofb, - .encrypt = crypto4xx_encrypt_iv_stream, - .decrypt = crypto4xx_decrypt_iv_stream, - .init = crypto4xx_sk_init, - .exit = crypto4xx_sk_exit, - } }, /* AEAD */ { .type = CRYPTO_ALG_TYPE_AEAD, .u.aead = { diff --git a/drivers/crypto/amcc/crypto4xx_core.h b/drivers/crypto/amcc/crypto4xx_core.h index 56c10668c0ab0a..96355d463b04e6 100644 --- a/drivers/crypto/amcc/crypto4xx_core.h +++ b/drivers/crypto/amcc/crypto4xx_core.h @@ -162,14 +162,10 @@ int crypto4xx_build_pd(struct crypto_async_request *req, struct scatterlist *dst_tmp); int crypto4xx_setkey_aes_cbc(struct crypto_skcipher *cipher, const u8 *key, unsigned int keylen); -int crypto4xx_setkey_aes_cfb(struct crypto_skcipher *cipher, - const u8 *key, unsigned int keylen); int crypto4xx_setkey_aes_ctr(struct crypto_skcipher *cipher, const u8 *key, unsigned int keylen); int crypto4xx_setkey_aes_ecb(struct crypto_skcipher *cipher, const u8 *key, unsigned int keylen); -int crypto4xx_setkey_aes_ofb(struct crypto_skcipher *cipher, - const u8 *key, unsigned int keylen); int crypto4xx_setkey_rfc3686(struct crypto_skcipher *cipher, const u8 *key, unsigned int keylen); int crypto4xx_encrypt_ctr(struct skcipher_request *req); diff --git a/drivers/crypto/amlogic/amlogic-gxl-cipher.c b/drivers/crypto/amlogic/amlogic-gxl-cipher.c index 3308406612fcd2..29048da6f50a7f 100644 --- a/drivers/crypto/amlogic/amlogic-gxl-cipher.c +++ b/drivers/crypto/amlogic/amlogic-gxl-cipher.c @@ -327,8 +327,8 @@ int meson_cipher_init(struct crypto_tfm *tfm) return PTR_ERR(op->fallback_tfm); } - sktfm->reqsize = sizeof(struct meson_cipher_req_ctx) + - crypto_skcipher_reqsize(op->fallback_tfm); + crypto_skcipher_set_reqsize(sktfm, sizeof(struct meson_cipher_req_ctx) + + crypto_skcipher_reqsize(op->fallback_tfm)); return 0; } diff --git a/drivers/crypto/aspeed/Kconfig b/drivers/crypto/aspeed/Kconfig index db6c5b4cdc4092..e93f2f82b41819 100644 --- a/drivers/crypto/aspeed/Kconfig +++ b/drivers/crypto/aspeed/Kconfig @@ -38,14 +38,12 @@ config CRYPTO_DEV_ASPEED_HACE_CRYPTO select CRYPTO_DES select CRYPTO_ECB select CRYPTO_CBC - select CRYPTO_CFB - select CRYPTO_OFB select CRYPTO_CTR help Select here to enable Aspeed Hash & Crypto Engine (HACE) crypto driver. Supports AES/DES symmetric-key encryption and decryption - with ECB/CBC/CFB/OFB/CTR options. + with ECB/CBC/CTR options. config CRYPTO_DEV_ASPEED_ACRY bool "Enable Aspeed ACRY RSA Engine" diff --git a/drivers/crypto/aspeed/aspeed-hace-crypto.c b/drivers/crypto/aspeed/aspeed-hace-crypto.c index f0eddb7854e5d8..a72dfebc53ffc2 100644 --- a/drivers/crypto/aspeed/aspeed-hace-crypto.c +++ b/drivers/crypto/aspeed/aspeed-hace-crypto.c @@ -473,30 +473,6 @@ static int aspeed_tdes_ctr_encrypt(struct skcipher_request *req) HACE_CMD_TRIPLE_DES); } -static int aspeed_tdes_ofb_decrypt(struct skcipher_request *req) -{ - return aspeed_des_crypt(req, HACE_CMD_DECRYPT | HACE_CMD_OFB | - HACE_CMD_TRIPLE_DES); -} - -static int aspeed_tdes_ofb_encrypt(struct skcipher_request *req) -{ - return aspeed_des_crypt(req, HACE_CMD_ENCRYPT | HACE_CMD_OFB | - HACE_CMD_TRIPLE_DES); -} - -static int aspeed_tdes_cfb_decrypt(struct skcipher_request *req) -{ - return aspeed_des_crypt(req, HACE_CMD_DECRYPT | HACE_CMD_CFB | - HACE_CMD_TRIPLE_DES); -} - -static int aspeed_tdes_cfb_encrypt(struct skcipher_request *req) -{ - return aspeed_des_crypt(req, HACE_CMD_ENCRYPT | HACE_CMD_CFB | - HACE_CMD_TRIPLE_DES); -} - static int aspeed_tdes_cbc_decrypt(struct skcipher_request *req) { return aspeed_des_crypt(req, HACE_CMD_DECRYPT | HACE_CMD_CBC | @@ -533,30 +509,6 @@ static int aspeed_des_ctr_encrypt(struct skcipher_request *req) HACE_CMD_SINGLE_DES); } -static int aspeed_des_ofb_decrypt(struct skcipher_request *req) -{ - return aspeed_des_crypt(req, HACE_CMD_DECRYPT | HACE_CMD_OFB | - HACE_CMD_SINGLE_DES); -} - -static int aspeed_des_ofb_encrypt(struct skcipher_request *req) -{ - return aspeed_des_crypt(req, HACE_CMD_ENCRYPT | HACE_CMD_OFB | - HACE_CMD_SINGLE_DES); -} - -static int aspeed_des_cfb_decrypt(struct skcipher_request *req) -{ - return aspeed_des_crypt(req, HACE_CMD_DECRYPT | HACE_CMD_CFB | - HACE_CMD_SINGLE_DES); -} - -static int aspeed_des_cfb_encrypt(struct skcipher_request *req) -{ - return aspeed_des_crypt(req, HACE_CMD_ENCRYPT | HACE_CMD_CFB | - HACE_CMD_SINGLE_DES); -} - static int aspeed_des_cbc_decrypt(struct skcipher_request *req) { return aspeed_des_crypt(req, HACE_CMD_DECRYPT | HACE_CMD_CBC | @@ -659,26 +611,6 @@ static int aspeed_aes_ctr_encrypt(struct skcipher_request *req) return aspeed_aes_crypt(req, HACE_CMD_ENCRYPT | HACE_CMD_CTR); } -static int aspeed_aes_ofb_decrypt(struct skcipher_request *req) -{ - return aspeed_aes_crypt(req, HACE_CMD_DECRYPT | HACE_CMD_OFB); -} - -static int aspeed_aes_ofb_encrypt(struct skcipher_request *req) -{ - return aspeed_aes_crypt(req, HACE_CMD_ENCRYPT | HACE_CMD_OFB); -} - -static int aspeed_aes_cfb_decrypt(struct skcipher_request *req) -{ - return aspeed_aes_crypt(req, HACE_CMD_DECRYPT | HACE_CMD_CFB); -} - -static int aspeed_aes_cfb_encrypt(struct skcipher_request *req) -{ - return aspeed_aes_crypt(req, HACE_CMD_ENCRYPT | HACE_CMD_CFB); -} - static int aspeed_aes_cbc_decrypt(struct skcipher_request *req) { return aspeed_aes_crypt(req, HACE_CMD_DECRYPT | HACE_CMD_CBC); @@ -790,60 +722,6 @@ static struct aspeed_hace_alg aspeed_crypto_algs[] = { .do_one_request = aspeed_crypto_do_request, }, }, - { - .alg.skcipher.base = { - .ivsize = AES_BLOCK_SIZE, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .setkey = aspeed_aes_setkey, - .encrypt = aspeed_aes_cfb_encrypt, - .decrypt = aspeed_aes_cfb_decrypt, - .init = aspeed_crypto_cra_init, - .exit = aspeed_crypto_cra_exit, - .base = { - .cra_name = "cfb(aes)", - .cra_driver_name = "aspeed-cfb-aes", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_NEED_FALLBACK, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct aspeed_cipher_ctx), - .cra_alignmask = 0x0f, - .cra_module = THIS_MODULE, - } - }, - .alg.skcipher.op = { - .do_one_request = aspeed_crypto_do_request, - }, - }, - { - .alg.skcipher.base = { - .ivsize = AES_BLOCK_SIZE, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .setkey = aspeed_aes_setkey, - .encrypt = aspeed_aes_ofb_encrypt, - .decrypt = aspeed_aes_ofb_decrypt, - .init = aspeed_crypto_cra_init, - .exit = aspeed_crypto_cra_exit, - .base = { - .cra_name = "ofb(aes)", - .cra_driver_name = "aspeed-ofb-aes", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_NEED_FALLBACK, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct aspeed_cipher_ctx), - .cra_alignmask = 0x0f, - .cra_module = THIS_MODULE, - } - }, - .alg.skcipher.op = { - .do_one_request = aspeed_crypto_do_request, - }, - }, { .alg.skcipher.base = { .min_keysize = DES_KEY_SIZE, @@ -897,60 +775,6 @@ static struct aspeed_hace_alg aspeed_crypto_algs[] = { .do_one_request = aspeed_crypto_do_request, }, }, - { - .alg.skcipher.base = { - .ivsize = DES_BLOCK_SIZE, - .min_keysize = DES_KEY_SIZE, - .max_keysize = DES_KEY_SIZE, - .setkey = aspeed_des_setkey, - .encrypt = aspeed_des_cfb_encrypt, - .decrypt = aspeed_des_cfb_decrypt, - .init = aspeed_crypto_cra_init, - .exit = aspeed_crypto_cra_exit, - .base = { - .cra_name = "cfb(des)", - .cra_driver_name = "aspeed-cfb-des", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_NEED_FALLBACK, - .cra_blocksize = DES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct aspeed_cipher_ctx), - .cra_alignmask = 0x0f, - .cra_module = THIS_MODULE, - } - }, - .alg.skcipher.op = { - .do_one_request = aspeed_crypto_do_request, - }, - }, - { - .alg.skcipher.base = { - .ivsize = DES_BLOCK_SIZE, - .min_keysize = DES_KEY_SIZE, - .max_keysize = DES_KEY_SIZE, - .setkey = aspeed_des_setkey, - .encrypt = aspeed_des_ofb_encrypt, - .decrypt = aspeed_des_ofb_decrypt, - .init = aspeed_crypto_cra_init, - .exit = aspeed_crypto_cra_exit, - .base = { - .cra_name = "ofb(des)", - .cra_driver_name = "aspeed-ofb-des", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_NEED_FALLBACK, - .cra_blocksize = DES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct aspeed_cipher_ctx), - .cra_alignmask = 0x0f, - .cra_module = THIS_MODULE, - } - }, - .alg.skcipher.op = { - .do_one_request = aspeed_crypto_do_request, - }, - }, { .alg.skcipher.base = { .min_keysize = DES3_EDE_KEY_SIZE, @@ -1004,60 +828,6 @@ static struct aspeed_hace_alg aspeed_crypto_algs[] = { .do_one_request = aspeed_crypto_do_request, }, }, - { - .alg.skcipher.base = { - .ivsize = DES_BLOCK_SIZE, - .min_keysize = DES3_EDE_KEY_SIZE, - .max_keysize = DES3_EDE_KEY_SIZE, - .setkey = aspeed_des_setkey, - .encrypt = aspeed_tdes_cfb_encrypt, - .decrypt = aspeed_tdes_cfb_decrypt, - .init = aspeed_crypto_cra_init, - .exit = aspeed_crypto_cra_exit, - .base = { - .cra_name = "cfb(des3_ede)", - .cra_driver_name = "aspeed-cfb-tdes", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_NEED_FALLBACK, - .cra_blocksize = DES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct aspeed_cipher_ctx), - .cra_alignmask = 0x0f, - .cra_module = THIS_MODULE, - } - }, - .alg.skcipher.op = { - .do_one_request = aspeed_crypto_do_request, - }, - }, - { - .alg.skcipher.base = { - .ivsize = DES_BLOCK_SIZE, - .min_keysize = DES3_EDE_KEY_SIZE, - .max_keysize = DES3_EDE_KEY_SIZE, - .setkey = aspeed_des_setkey, - .encrypt = aspeed_tdes_ofb_encrypt, - .decrypt = aspeed_tdes_ofb_decrypt, - .init = aspeed_crypto_cra_init, - .exit = aspeed_crypto_cra_exit, - .base = { - .cra_name = "ofb(des3_ede)", - .cra_driver_name = "aspeed-ofb-tdes", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_NEED_FALLBACK, - .cra_blocksize = DES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct aspeed_cipher_ctx), - .cra_alignmask = 0x0f, - .cra_module = THIS_MODULE, - } - }, - .alg.skcipher.op = { - .do_one_request = aspeed_crypto_do_request, - }, - }, }; static struct aspeed_hace_alg aspeed_crypto_algs_g6[] = { diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c index d1d93e897892e2..8bd64fc37e7571 100644 --- a/drivers/crypto/atmel-aes.c +++ b/drivers/crypto/atmel-aes.c @@ -46,11 +46,6 @@ #define ATMEL_AES_BUFFER_ORDER 2 #define ATMEL_AES_BUFFER_SIZE (PAGE_SIZE << ATMEL_AES_BUFFER_ORDER) -#define CFB8_BLOCK_SIZE 1 -#define CFB16_BLOCK_SIZE 2 -#define CFB32_BLOCK_SIZE 4 -#define CFB64_BLOCK_SIZE 8 - #define SIZE_IN_WORDS(x) ((x) >> 2) /* AES flags */ @@ -60,12 +55,6 @@ #define AES_FLAGS_OPMODE_MASK (AES_MR_OPMOD_MASK | AES_MR_CFBS_MASK) #define AES_FLAGS_ECB AES_MR_OPMOD_ECB #define AES_FLAGS_CBC AES_MR_OPMOD_CBC -#define AES_FLAGS_OFB AES_MR_OPMOD_OFB -#define AES_FLAGS_CFB128 (AES_MR_OPMOD_CFB | AES_MR_CFBS_128b) -#define AES_FLAGS_CFB64 (AES_MR_OPMOD_CFB | AES_MR_CFBS_64b) -#define AES_FLAGS_CFB32 (AES_MR_OPMOD_CFB | AES_MR_CFBS_32b) -#define AES_FLAGS_CFB16 (AES_MR_OPMOD_CFB | AES_MR_CFBS_16b) -#define AES_FLAGS_CFB8 (AES_MR_OPMOD_CFB | AES_MR_CFBS_8b) #define AES_FLAGS_CTR AES_MR_OPMOD_CTR #define AES_FLAGS_GCM AES_MR_OPMOD_GCM #define AES_FLAGS_XTS AES_MR_OPMOD_XTS @@ -87,7 +76,6 @@ struct atmel_aes_caps { bool has_dualbuff; - bool has_cfb64; bool has_gcm; bool has_xts; bool has_authenc; @@ -860,22 +848,6 @@ static int atmel_aes_dma_start(struct atmel_aes_dev *dd, int err; switch (dd->ctx->block_size) { - case CFB8_BLOCK_SIZE: - addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; - maxburst = 1; - break; - - case CFB16_BLOCK_SIZE: - addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; - maxburst = 1; - break; - - case CFB32_BLOCK_SIZE: - case CFB64_BLOCK_SIZE: - addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - maxburst = 1; - break; - case AES_BLOCK_SIZE: addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; maxburst = dd->caps.max_burst_size; @@ -1103,7 +1075,7 @@ static int atmel_aes_crypt(struct skcipher_request *req, unsigned long mode) } /* - * ECB, CBC, CFB, OFB or CTR mode require the plaintext and ciphertext + * ECB, CBC or CTR mode require the plaintext and ciphertext * to have a positve integer length. */ if (!req->cryptlen && opmode != AES_FLAGS_XTS) @@ -1113,27 +1085,7 @@ static int atmel_aes_crypt(struct skcipher_request *req, unsigned long mode) !IS_ALIGNED(req->cryptlen, crypto_skcipher_blocksize(skcipher))) return -EINVAL; - switch (mode & AES_FLAGS_OPMODE_MASK) { - case AES_FLAGS_CFB8: - ctx->block_size = CFB8_BLOCK_SIZE; - break; - - case AES_FLAGS_CFB16: - ctx->block_size = CFB16_BLOCK_SIZE; - break; - - case AES_FLAGS_CFB32: - ctx->block_size = CFB32_BLOCK_SIZE; - break; - - case AES_FLAGS_CFB64: - ctx->block_size = CFB64_BLOCK_SIZE; - break; - - default: - ctx->block_size = AES_BLOCK_SIZE; - break; - } + ctx->block_size = AES_BLOCK_SIZE; ctx->is_aead = false; rctx = skcipher_request_ctx(req); @@ -1188,66 +1140,6 @@ static int atmel_aes_cbc_decrypt(struct skcipher_request *req) return atmel_aes_crypt(req, AES_FLAGS_CBC); } -static int atmel_aes_ofb_encrypt(struct skcipher_request *req) -{ - return atmel_aes_crypt(req, AES_FLAGS_OFB | AES_FLAGS_ENCRYPT); -} - -static int atmel_aes_ofb_decrypt(struct skcipher_request *req) -{ - return atmel_aes_crypt(req, AES_FLAGS_OFB); -} - -static int atmel_aes_cfb_encrypt(struct skcipher_request *req) -{ - return atmel_aes_crypt(req, AES_FLAGS_CFB128 | AES_FLAGS_ENCRYPT); -} - -static int atmel_aes_cfb_decrypt(struct skcipher_request *req) -{ - return atmel_aes_crypt(req, AES_FLAGS_CFB128); -} - -static int atmel_aes_cfb64_encrypt(struct skcipher_request *req) -{ - return atmel_aes_crypt(req, AES_FLAGS_CFB64 | AES_FLAGS_ENCRYPT); -} - -static int atmel_aes_cfb64_decrypt(struct skcipher_request *req) -{ - return atmel_aes_crypt(req, AES_FLAGS_CFB64); -} - -static int atmel_aes_cfb32_encrypt(struct skcipher_request *req) -{ - return atmel_aes_crypt(req, AES_FLAGS_CFB32 | AES_FLAGS_ENCRYPT); -} - -static int atmel_aes_cfb32_decrypt(struct skcipher_request *req) -{ - return atmel_aes_crypt(req, AES_FLAGS_CFB32); -} - -static int atmel_aes_cfb16_encrypt(struct skcipher_request *req) -{ - return atmel_aes_crypt(req, AES_FLAGS_CFB16 | AES_FLAGS_ENCRYPT); -} - -static int atmel_aes_cfb16_decrypt(struct skcipher_request *req) -{ - return atmel_aes_crypt(req, AES_FLAGS_CFB16); -} - -static int atmel_aes_cfb8_encrypt(struct skcipher_request *req) -{ - return atmel_aes_crypt(req, AES_FLAGS_CFB8 | AES_FLAGS_ENCRYPT); -} - -static int atmel_aes_cfb8_decrypt(struct skcipher_request *req) -{ - return atmel_aes_crypt(req, AES_FLAGS_CFB8); -} - static int atmel_aes_ctr_encrypt(struct skcipher_request *req) { return atmel_aes_crypt(req, AES_FLAGS_CTR | AES_FLAGS_ENCRYPT); @@ -1318,76 +1210,6 @@ static struct skcipher_alg aes_algs[] = { .decrypt = atmel_aes_cbc_decrypt, .ivsize = AES_BLOCK_SIZE, }, -{ - .base.cra_name = "ofb(aes)", - .base.cra_driver_name = "atmel-ofb-aes", - .base.cra_blocksize = 1, - .base.cra_ctxsize = sizeof(struct atmel_aes_ctx), - - .init = atmel_aes_init_tfm, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .setkey = atmel_aes_setkey, - .encrypt = atmel_aes_ofb_encrypt, - .decrypt = atmel_aes_ofb_decrypt, - .ivsize = AES_BLOCK_SIZE, -}, -{ - .base.cra_name = "cfb(aes)", - .base.cra_driver_name = "atmel-cfb-aes", - .base.cra_blocksize = 1, - .base.cra_ctxsize = sizeof(struct atmel_aes_ctx), - - .init = atmel_aes_init_tfm, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .setkey = atmel_aes_setkey, - .encrypt = atmel_aes_cfb_encrypt, - .decrypt = atmel_aes_cfb_decrypt, - .ivsize = AES_BLOCK_SIZE, -}, -{ - .base.cra_name = "cfb32(aes)", - .base.cra_driver_name = "atmel-cfb32-aes", - .base.cra_blocksize = CFB32_BLOCK_SIZE, - .base.cra_ctxsize = sizeof(struct atmel_aes_ctx), - - .init = atmel_aes_init_tfm, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .setkey = atmel_aes_setkey, - .encrypt = atmel_aes_cfb32_encrypt, - .decrypt = atmel_aes_cfb32_decrypt, - .ivsize = AES_BLOCK_SIZE, -}, -{ - .base.cra_name = "cfb16(aes)", - .base.cra_driver_name = "atmel-cfb16-aes", - .base.cra_blocksize = CFB16_BLOCK_SIZE, - .base.cra_ctxsize = sizeof(struct atmel_aes_ctx), - - .init = atmel_aes_init_tfm, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .setkey = atmel_aes_setkey, - .encrypt = atmel_aes_cfb16_encrypt, - .decrypt = atmel_aes_cfb16_decrypt, - .ivsize = AES_BLOCK_SIZE, -}, -{ - .base.cra_name = "cfb8(aes)", - .base.cra_driver_name = "atmel-cfb8-aes", - .base.cra_blocksize = CFB8_BLOCK_SIZE, - .base.cra_ctxsize = sizeof(struct atmel_aes_ctx), - - .init = atmel_aes_init_tfm, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .setkey = atmel_aes_setkey, - .encrypt = atmel_aes_cfb8_encrypt, - .decrypt = atmel_aes_cfb8_decrypt, - .ivsize = AES_BLOCK_SIZE, -}, { .base.cra_name = "ctr(aes)", .base.cra_driver_name = "atmel-ctr-aes", @@ -1404,21 +1226,6 @@ static struct skcipher_alg aes_algs[] = { }, }; -static struct skcipher_alg aes_cfb64_alg = { - .base.cra_name = "cfb64(aes)", - .base.cra_driver_name = "atmel-cfb64-aes", - .base.cra_blocksize = CFB64_BLOCK_SIZE, - .base.cra_ctxsize = sizeof(struct atmel_aes_ctx), - - .init = atmel_aes_init_tfm, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .setkey = atmel_aes_setkey, - .encrypt = atmel_aes_cfb64_encrypt, - .decrypt = atmel_aes_cfb64_decrypt, - .ivsize = AES_BLOCK_SIZE, -}; - /* gcm aead functions */ @@ -2407,9 +2214,6 @@ static void atmel_aes_unregister_algs(struct atmel_aes_dev *dd) if (dd->caps.has_gcm) crypto_unregister_aead(&aes_gcm_alg); - if (dd->caps.has_cfb64) - crypto_unregister_skcipher(&aes_cfb64_alg); - for (i = 0; i < ARRAY_SIZE(aes_algs); i++) crypto_unregister_skcipher(&aes_algs[i]); } @@ -2434,14 +2238,6 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd) goto err_aes_algs; } - if (dd->caps.has_cfb64) { - atmel_aes_crypto_alg_init(&aes_cfb64_alg.base); - - err = crypto_register_skcipher(&aes_cfb64_alg); - if (err) - goto err_aes_cfb64_alg; - } - if (dd->caps.has_gcm) { atmel_aes_crypto_alg_init(&aes_gcm_alg.base); @@ -2482,8 +2278,6 @@ err_aes_authenc_alg: err_aes_xts_alg: crypto_unregister_aead(&aes_gcm_alg); err_aes_gcm_alg: - crypto_unregister_skcipher(&aes_cfb64_alg); -err_aes_cfb64_alg: i = ARRAY_SIZE(aes_algs); err_aes_algs: for (j = 0; j < i; j++) @@ -2495,7 +2289,6 @@ err_aes_algs: static void atmel_aes_get_cap(struct atmel_aes_dev *dd) { dd->caps.has_dualbuff = 0; - dd->caps.has_cfb64 = 0; dd->caps.has_gcm = 0; dd->caps.has_xts = 0; dd->caps.has_authenc = 0; @@ -2507,7 +2300,6 @@ static void atmel_aes_get_cap(struct atmel_aes_dev *dd) case 0x600: case 0x500: dd->caps.has_dualbuff = 1; - dd->caps.has_cfb64 = 1; dd->caps.has_gcm = 1; dd->caps.has_xts = 1; dd->caps.has_authenc = 1; @@ -2515,13 +2307,11 @@ static void atmel_aes_get_cap(struct atmel_aes_dev *dd) break; case 0x200: dd->caps.has_dualbuff = 1; - dd->caps.has_cfb64 = 1; dd->caps.has_gcm = 1; dd->caps.max_burst_size = 4; break; case 0x130: dd->caps.has_dualbuff = 1; - dd->caps.has_cfb64 = 1; dd->caps.max_burst_size = 4; break; case 0x120: diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c index 27b7000e25bc72..dcc2380a5889f5 100644 --- a/drivers/crypto/atmel-tdes.c +++ b/drivers/crypto/atmel-tdes.c @@ -45,11 +45,6 @@ #define TDES_FLAGS_OPMODE_MASK (TDES_MR_OPMOD_MASK | TDES_MR_CFBS_MASK) #define TDES_FLAGS_ECB TDES_MR_OPMOD_ECB #define TDES_FLAGS_CBC TDES_MR_OPMOD_CBC -#define TDES_FLAGS_OFB TDES_MR_OPMOD_OFB -#define TDES_FLAGS_CFB64 (TDES_MR_OPMOD_CFB | TDES_MR_CFBS_64b) -#define TDES_FLAGS_CFB32 (TDES_MR_OPMOD_CFB | TDES_MR_CFBS_32b) -#define TDES_FLAGS_CFB16 (TDES_MR_OPMOD_CFB | TDES_MR_CFBS_16b) -#define TDES_FLAGS_CFB8 (TDES_MR_OPMOD_CFB | TDES_MR_CFBS_8b) #define TDES_FLAGS_MODE_MASK (TDES_FLAGS_OPMODE_MASK | TDES_FLAGS_ENCRYPT) @@ -60,13 +55,8 @@ #define ATMEL_TDES_QUEUE_LENGTH 50 -#define CFB8_BLOCK_SIZE 1 -#define CFB16_BLOCK_SIZE 2 -#define CFB32_BLOCK_SIZE 4 - struct atmel_tdes_caps { bool has_dma; - u32 has_cfb_3keys; }; struct atmel_tdes_dev; @@ -376,7 +366,6 @@ static int atmel_tdes_crypt_pdc(struct atmel_tdes_dev *dd, dma_addr_t dma_addr_in, dma_addr_t dma_addr_out, int length) { - struct atmel_tdes_reqctx *rctx = skcipher_request_ctx(dd->req); int len32; dd->dma_size = length; @@ -386,19 +375,7 @@ static int atmel_tdes_crypt_pdc(struct atmel_tdes_dev *dd, DMA_TO_DEVICE); } - switch (rctx->mode & TDES_FLAGS_OPMODE_MASK) { - case TDES_FLAGS_CFB8: - len32 = DIV_ROUND_UP(length, sizeof(u8)); - break; - - case TDES_FLAGS_CFB16: - len32 = DIV_ROUND_UP(length, sizeof(u16)); - break; - - default: - len32 = DIV_ROUND_UP(length, sizeof(u32)); - break; - } + len32 = DIV_ROUND_UP(length, sizeof(u32)); atmel_tdes_write(dd, TDES_PTCR, TDES_PTCR_TXTDIS|TDES_PTCR_RXTDIS); atmel_tdes_write(dd, TDES_TPR, dma_addr_in); @@ -419,7 +396,6 @@ static int atmel_tdes_crypt_dma(struct atmel_tdes_dev *dd, dma_addr_t dma_addr_in, dma_addr_t dma_addr_out, int length) { - struct atmel_tdes_reqctx *rctx = skcipher_request_ctx(dd->req); struct scatterlist sg[2]; struct dma_async_tx_descriptor *in_desc, *out_desc; enum dma_slave_buswidth addr_width; @@ -431,19 +407,7 @@ static int atmel_tdes_crypt_dma(struct atmel_tdes_dev *dd, DMA_TO_DEVICE); } - switch (rctx->mode & TDES_FLAGS_OPMODE_MASK) { - case TDES_FLAGS_CFB8: - addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; - break; - - case TDES_FLAGS_CFB16: - addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; - break; - - default: - addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - break; - } + addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; dd->dma_lch_in.dma_conf.dst_addr_width = addr_width; dd->dma_lch_out.dma_conf.src_addr_width = addr_width; @@ -680,39 +644,11 @@ static int atmel_tdes_crypt(struct skcipher_request *req, unsigned long mode) if (!req->cryptlen) return 0; - switch (mode & TDES_FLAGS_OPMODE_MASK) { - case TDES_FLAGS_CFB8: - if (!IS_ALIGNED(req->cryptlen, CFB8_BLOCK_SIZE)) { - dev_dbg(dev, "request size is not exact amount of CFB8 blocks\n"); - return -EINVAL; - } - ctx->block_size = CFB8_BLOCK_SIZE; - break; - - case TDES_FLAGS_CFB16: - if (!IS_ALIGNED(req->cryptlen, CFB16_BLOCK_SIZE)) { - dev_dbg(dev, "request size is not exact amount of CFB16 blocks\n"); - return -EINVAL; - } - ctx->block_size = CFB16_BLOCK_SIZE; - break; - - case TDES_FLAGS_CFB32: - if (!IS_ALIGNED(req->cryptlen, CFB32_BLOCK_SIZE)) { - dev_dbg(dev, "request size is not exact amount of CFB32 blocks\n"); - return -EINVAL; - } - ctx->block_size = CFB32_BLOCK_SIZE; - break; - - default: - if (!IS_ALIGNED(req->cryptlen, DES_BLOCK_SIZE)) { - dev_dbg(dev, "request size is not exact amount of DES blocks\n"); - return -EINVAL; - } - ctx->block_size = DES_BLOCK_SIZE; - break; + if (!IS_ALIGNED(req->cryptlen, DES_BLOCK_SIZE)) { + dev_dbg(dev, "request size is not exact amount of DES blocks\n"); + return -EINVAL; } + ctx->block_size = DES_BLOCK_SIZE; rctx->mode = mode; @@ -832,55 +768,6 @@ static int atmel_tdes_cbc_decrypt(struct skcipher_request *req) { return atmel_tdes_crypt(req, TDES_FLAGS_CBC); } -static int atmel_tdes_cfb_encrypt(struct skcipher_request *req) -{ - return atmel_tdes_crypt(req, TDES_FLAGS_CFB64 | TDES_FLAGS_ENCRYPT); -} - -static int atmel_tdes_cfb_decrypt(struct skcipher_request *req) -{ - return atmel_tdes_crypt(req, TDES_FLAGS_CFB64); -} - -static int atmel_tdes_cfb8_encrypt(struct skcipher_request *req) -{ - return atmel_tdes_crypt(req, TDES_FLAGS_CFB8 | TDES_FLAGS_ENCRYPT); -} - -static int atmel_tdes_cfb8_decrypt(struct skcipher_request *req) -{ - return atmel_tdes_crypt(req, TDES_FLAGS_CFB8); -} - -static int atmel_tdes_cfb16_encrypt(struct skcipher_request *req) -{ - return atmel_tdes_crypt(req, TDES_FLAGS_CFB16 | TDES_FLAGS_ENCRYPT); -} - -static int atmel_tdes_cfb16_decrypt(struct skcipher_request *req) -{ - return atmel_tdes_crypt(req, TDES_FLAGS_CFB16); -} - -static int atmel_tdes_cfb32_encrypt(struct skcipher_request *req) -{ - return atmel_tdes_crypt(req, TDES_FLAGS_CFB32 | TDES_FLAGS_ENCRYPT); -} - -static int atmel_tdes_cfb32_decrypt(struct skcipher_request *req) -{ - return atmel_tdes_crypt(req, TDES_FLAGS_CFB32); -} - -static int atmel_tdes_ofb_encrypt(struct skcipher_request *req) -{ - return atmel_tdes_crypt(req, TDES_FLAGS_OFB | TDES_FLAGS_ENCRYPT); -} - -static int atmel_tdes_ofb_decrypt(struct skcipher_request *req) -{ - return atmel_tdes_crypt(req, TDES_FLAGS_OFB); -} static int atmel_tdes_init_tfm(struct crypto_skcipher *tfm) { @@ -931,71 +818,6 @@ static struct skcipher_alg tdes_algs[] = { .encrypt = atmel_tdes_cbc_encrypt, .decrypt = atmel_tdes_cbc_decrypt, }, -{ - .base.cra_name = "cfb(des)", - .base.cra_driver_name = "atmel-cfb-des", - .base.cra_blocksize = DES_BLOCK_SIZE, - .base.cra_alignmask = 0x7, - - .min_keysize = DES_KEY_SIZE, - .max_keysize = DES_KEY_SIZE, - .ivsize = DES_BLOCK_SIZE, - .setkey = atmel_des_setkey, - .encrypt = atmel_tdes_cfb_encrypt, - .decrypt = atmel_tdes_cfb_decrypt, -}, -{ - .base.cra_name = "cfb8(des)", - .base.cra_driver_name = "atmel-cfb8-des", - .base.cra_blocksize = CFB8_BLOCK_SIZE, - .base.cra_alignmask = 0, - - .min_keysize = DES_KEY_SIZE, - .max_keysize = DES_KEY_SIZE, - .ivsize = DES_BLOCK_SIZE, - .setkey = atmel_des_setkey, - .encrypt = atmel_tdes_cfb8_encrypt, - .decrypt = atmel_tdes_cfb8_decrypt, -}, -{ - .base.cra_name = "cfb16(des)", - .base.cra_driver_name = "atmel-cfb16-des", - .base.cra_blocksize = CFB16_BLOCK_SIZE, - .base.cra_alignmask = 0x1, - - .min_keysize = DES_KEY_SIZE, - .max_keysize = DES_KEY_SIZE, - .ivsize = DES_BLOCK_SIZE, - .setkey = atmel_des_setkey, - .encrypt = atmel_tdes_cfb16_encrypt, - .decrypt = atmel_tdes_cfb16_decrypt, -}, -{ - .base.cra_name = "cfb32(des)", - .base.cra_driver_name = "atmel-cfb32-des", - .base.cra_blocksize = CFB32_BLOCK_SIZE, - .base.cra_alignmask = 0x3, - - .min_keysize = DES_KEY_SIZE, - .max_keysize = DES_KEY_SIZE, - .ivsize = DES_BLOCK_SIZE, - .setkey = atmel_des_setkey, - .encrypt = atmel_tdes_cfb32_encrypt, - .decrypt = atmel_tdes_cfb32_decrypt, -}, -{ - .base.cra_name = "ofb(des)", - .base.cra_driver_name = "atmel-ofb-des", - .base.cra_blocksize = 1, - .base.cra_alignmask = 0x7, - - .min_keysize = DES_KEY_SIZE, - .max_keysize = DES_KEY_SIZE, - .ivsize = DES_BLOCK_SIZE, - .setkey = atmel_des_setkey, - .encrypt = atmel_tdes_ofb_encrypt, - .decrypt = atmel_tdes_ofb_decrypt, -}, { .base.cra_name = "ecb(des3_ede)", .base.cra_driver_name = "atmel-ecb-tdes", @@ -1021,19 +843,6 @@ static struct skcipher_alg tdes_algs[] = { .decrypt = atmel_tdes_cbc_decrypt, .ivsize = DES_BLOCK_SIZE, }, -{ - .base.cra_name = "ofb(des3_ede)", - .base.cra_driver_name = "atmel-ofb-tdes", - .base.cra_blocksize = DES_BLOCK_SIZE, - .base.cra_alignmask = 0x7, - - .min_keysize = DES3_EDE_KEY_SIZE, - .max_keysize = DES3_EDE_KEY_SIZE, - .setkey = atmel_tdes_setkey, - .encrypt = atmel_tdes_ofb_encrypt, - .decrypt = atmel_tdes_ofb_decrypt, - .ivsize = DES_BLOCK_SIZE, -}, }; static void atmel_tdes_queue_task(unsigned long data) @@ -1121,14 +930,12 @@ static void atmel_tdes_get_cap(struct atmel_tdes_dev *dd) { dd->caps.has_dma = 0; - dd->caps.has_cfb_3keys = 0; /* keep only major version number */ switch (dd->hw_version & 0xf00) { case 0x800: case 0x700: dd->caps.has_dma = 1; - dd->caps.has_cfb_3keys = 1; break; case 0x600: break; diff --git a/drivers/crypto/axis/artpec6_crypto.c b/drivers/crypto/axis/artpec6_crypto.c index ef9fe13ffa593d..dbc1d483f2afa3 100644 --- a/drivers/crypto/axis/artpec6_crypto.c +++ b/drivers/crypto/axis/artpec6_crypto.c @@ -1535,7 +1535,8 @@ static int artpec6_crypto_aes_ecb_init(struct crypto_skcipher *tfm) { struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(tfm); - tfm->reqsize = sizeof(struct artpec6_crypto_request_context); + crypto_skcipher_set_reqsize(tfm, + sizeof(struct artpec6_crypto_request_context)); ctx->crypto_type = ARTPEC6_CRYPTO_CIPHER_AES_ECB; return 0; @@ -1551,7 +1552,8 @@ static int artpec6_crypto_aes_ctr_init(struct crypto_skcipher *tfm) if (IS_ERR(ctx->fallback)) return PTR_ERR(ctx->fallback); - tfm->reqsize = sizeof(struct artpec6_crypto_request_context); + crypto_skcipher_set_reqsize(tfm, + sizeof(struct artpec6_crypto_request_context)); ctx->crypto_type = ARTPEC6_CRYPTO_CIPHER_AES_CTR; return 0; @@ -1561,7 +1563,8 @@ static int artpec6_crypto_aes_cbc_init(struct crypto_skcipher *tfm) { struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(tfm); - tfm->reqsize = sizeof(struct artpec6_crypto_request_context); + crypto_skcipher_set_reqsize(tfm, + sizeof(struct artpec6_crypto_request_context)); ctx->crypto_type = ARTPEC6_CRYPTO_CIPHER_AES_CBC; return 0; @@ -1571,7 +1574,8 @@ static int artpec6_crypto_aes_xts_init(struct crypto_skcipher *tfm) { struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(tfm); - tfm->reqsize = sizeof(struct artpec6_crypto_request_context); + crypto_skcipher_set_reqsize(tfm, + sizeof(struct artpec6_crypto_request_context)); ctx->crypto_type = ARTPEC6_CRYPTO_CIPHER_AES_XTS; return 0; diff --git a/drivers/crypto/bcm/cipher.c b/drivers/crypto/bcm/cipher.c index 10968ddb146b15..1a3ecd44cbaf65 100644 --- a/drivers/crypto/bcm/cipher.c +++ b/drivers/crypto/bcm/cipher.c @@ -3514,25 +3514,6 @@ static struct iproc_alg_s driver_algs[] = { }, /* SKCIPHER algorithms. */ - { - .type = CRYPTO_ALG_TYPE_SKCIPHER, - .alg.skcipher = { - .base.cra_name = "ofb(des)", - .base.cra_driver_name = "ofb-des-iproc", - .base.cra_blocksize = DES_BLOCK_SIZE, - .min_keysize = DES_KEY_SIZE, - .max_keysize = DES_KEY_SIZE, - .ivsize = DES_BLOCK_SIZE, - }, - .cipher_info = { - .alg = CIPHER_ALG_DES, - .mode = CIPHER_MODE_OFB, - }, - .auth_info = { - .alg = HASH_ALG_NONE, - .mode = HASH_MODE_NONE, - }, - }, { .type = CRYPTO_ALG_TYPE_SKCIPHER, .alg.skcipher = { @@ -3571,25 +3552,6 @@ static struct iproc_alg_s driver_algs[] = { .mode = HASH_MODE_NONE, }, }, - { - .type = CRYPTO_ALG_TYPE_SKCIPHER, - .alg.skcipher = { - .base.cra_name = "ofb(des3_ede)", - .base.cra_driver_name = "ofb-des3-iproc", - .base.cra_blocksize = DES3_EDE_BLOCK_SIZE, - .min_keysize = DES3_EDE_KEY_SIZE, - .max_keysize = DES3_EDE_KEY_SIZE, - .ivsize = DES3_EDE_BLOCK_SIZE, - }, - .cipher_info = { - .alg = CIPHER_ALG_3DES, - .mode = CIPHER_MODE_OFB, - }, - .auth_info = { - .alg = HASH_ALG_NONE, - .mode = HASH_MODE_NONE, - }, - }, { .type = CRYPTO_ALG_TYPE_SKCIPHER, .alg.skcipher = { @@ -3628,25 +3590,6 @@ static struct iproc_alg_s driver_algs[] = { .mode = HASH_MODE_NONE, }, }, - { - .type = CRYPTO_ALG_TYPE_SKCIPHER, - .alg.skcipher = { - .base.cra_name = "ofb(aes)", - .base.cra_driver_name = "ofb-aes-iproc", - .base.cra_blocksize = AES_BLOCK_SIZE, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_BLOCK_SIZE, - }, - .cipher_info = { - .alg = CIPHER_ALG_AES, - .mode = CIPHER_MODE_OFB, - }, - .auth_info = { - .alg = HASH_ALG_NONE, - .mode = HASH_MODE_NONE, - }, - }, { .type = CRYPTO_ALG_TYPE_SKCIPHER, .alg.skcipher = { diff --git a/drivers/crypto/cavium/cpt/cptvf_algs.c b/drivers/crypto/cavium/cpt/cptvf_algs.c index ee476c6c7f8272..219fe9be760645 100644 --- a/drivers/crypto/cavium/cpt/cptvf_algs.c +++ b/drivers/crypto/cavium/cpt/cptvf_algs.c @@ -311,12 +311,6 @@ static int cvm_ecb_aes_setkey(struct crypto_skcipher *cipher, const u8 *key, return cvm_setkey(cipher, key, keylen, AES_ECB); } -static int cvm_cfb_aes_setkey(struct crypto_skcipher *cipher, const u8 *key, - u32 keylen) -{ - return cvm_setkey(cipher, key, keylen, AES_CFB); -} - static int cvm_cbc_des3_setkey(struct crypto_skcipher *cipher, const u8 *key, u32 keylen) { @@ -391,24 +385,6 @@ static struct skcipher_alg algs[] = { { .encrypt = cvm_encrypt, .decrypt = cvm_decrypt, .init = cvm_enc_dec_init, -}, { - .base.cra_flags = CRYPTO_ALG_ASYNC | - CRYPTO_ALG_ALLOCATES_MEMORY, - .base.cra_blocksize = AES_BLOCK_SIZE, - .base.cra_ctxsize = sizeof(struct cvm_enc_ctx), - .base.cra_alignmask = 7, - .base.cra_priority = 4001, - .base.cra_name = "cfb(aes)", - .base.cra_driver_name = "cavium-cfb-aes", - .base.cra_module = THIS_MODULE, - - .ivsize = AES_BLOCK_SIZE, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .setkey = cvm_cfb_aes_setkey, - .encrypt = cvm_encrypt, - .decrypt = cvm_decrypt, - .init = cvm_enc_dec_init, }, { .base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY, diff --git a/drivers/crypto/cavium/nitrox/nitrox_skcipher.c b/drivers/crypto/cavium/nitrox/nitrox_skcipher.c index 138261dcd032f3..6e5e667bab75b4 100644 --- a/drivers/crypto/cavium/nitrox/nitrox_skcipher.c +++ b/drivers/crypto/cavium/nitrox/nitrox_skcipher.c @@ -419,25 +419,6 @@ static struct skcipher_alg nitrox_skciphers[] = { { .decrypt = nitrox_aes_decrypt, .init = nitrox_skcipher_init, .exit = nitrox_skcipher_exit, -}, { - .base = { - .cra_name = "cfb(aes)", - .cra_driver_name = "n5_cfb(aes)", - .cra_priority = PRIO, - .cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY, - .cra_blocksize = AES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct nitrox_crypto_ctx), - .cra_alignmask = 0, - .cra_module = THIS_MODULE, - }, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_BLOCK_SIZE, - .setkey = nitrox_aes_setkey, - .encrypt = nitrox_aes_encrypt, - .decrypt = nitrox_aes_decrypt, - .init = nitrox_skcipher_init, - .exit = nitrox_skcipher_exit, }, { .base = { .cra_name = "xts(aes)", diff --git a/drivers/crypto/ccp/ccp-crypto-aes.c b/drivers/crypto/ccp/ccp-crypto-aes.c index 918e223f21b651..d11daaf47f068d 100644 --- a/drivers/crypto/ccp/ccp-crypto-aes.c +++ b/drivers/crypto/ccp/ccp-crypto-aes.c @@ -266,24 +266,6 @@ static struct ccp_aes_def aes_algs[] = { .ivsize = AES_BLOCK_SIZE, .alg_defaults = &ccp_aes_defaults, }, - { - .mode = CCP_AES_MODE_CFB, - .version = CCP_VERSION(3, 0), - .name = "cfb(aes)", - .driver_name = "cfb-aes-ccp", - .blocksize = 1, - .ivsize = AES_BLOCK_SIZE, - .alg_defaults = &ccp_aes_defaults, - }, - { - .mode = CCP_AES_MODE_OFB, - .version = CCP_VERSION(3, 0), - .name = "ofb(aes)", - .driver_name = "ofb-aes-ccp", - .blocksize = 1, - .ivsize = AES_BLOCK_SIZE, - .alg_defaults = &ccp_aes_defaults, - }, { .mode = CCP_AES_MODE_CTR, .version = CCP_VERSION(3, 0), diff --git a/drivers/crypto/ccp/ccp-ops.c b/drivers/crypto/ccp/ccp-ops.c index aa4e1a5006919d..cb8e99936abb72 100644 --- a/drivers/crypto/ccp/ccp-ops.c +++ b/drivers/crypto/ccp/ccp-ops.c @@ -179,8 +179,11 @@ static int ccp_init_dm_workarea(struct ccp_dm_workarea *wa, wa->dma.address = dma_map_single(wa->dev, wa->address, len, dir); - if (dma_mapping_error(wa->dev, wa->dma.address)) + if (dma_mapping_error(wa->dev, wa->dma.address)) { + kfree(wa->address); + wa->address = NULL; return -ENOMEM; + } wa->dma.length = len; } diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index fcaccd0b5a651e..e4d3f45242f632 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -906,7 +906,7 @@ static int sev_ioctl_do_get_id2(struct sev_issue_cmd *argp) /* * The length of the ID shouldn't be assumed by software since * it may change in the future. The allocation size is limited - * to 1 << (PAGE_SHIFT + MAX_ORDER) by the page allocator. + * to 1 << (PAGE_SHIFT + MAX_PAGE_ORDER) by the page allocator. * If the allocation fails, simply return ENOMEM rather than * warning in the kernel log. */ diff --git a/drivers/crypto/ccree/cc_aead.c b/drivers/crypto/ccree/cc_aead.c index 109ffb375fc695..5ef39d68238977 100644 --- a/drivers/crypto/ccree/cc_aead.c +++ b/drivers/crypto/ccree/cc_aead.c @@ -2569,9 +2569,13 @@ static struct cc_crypto_alg *cc_create_aead_alg(struct cc_alg_template *tmpl, alg = &tmpl->template_aead; - snprintf(alg->base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", tmpl->name); - snprintf(alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", - tmpl->driver_name); + if (snprintf(alg->base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", + tmpl->name) >= CRYPTO_MAX_ALG_NAME) + return ERR_PTR(-EINVAL); + if (snprintf(alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", + tmpl->driver_name) >= CRYPTO_MAX_ALG_NAME) + return ERR_PTR(-EINVAL); + alg->base.cra_module = THIS_MODULE; alg->base.cra_priority = CC_CRA_PRIO; diff --git a/drivers/crypto/ccree/cc_cipher.c b/drivers/crypto/ccree/cc_cipher.c index 2cd44d7457a457..cd66a580e8b642 100644 --- a/drivers/crypto/ccree/cc_cipher.c +++ b/drivers/crypto/ccree/cc_cipher.c @@ -1079,24 +1079,6 @@ static const struct cc_alg_template skcipher_algs[] = { .std_body = CC_STD_NIST, .sec_func = true, }, - { - .name = "ofb(paes)", - .driver_name = "ofb-paes-ccree", - .blocksize = AES_BLOCK_SIZE, - .template_skcipher = { - .setkey = cc_cipher_sethkey, - .encrypt = cc_cipher_encrypt, - .decrypt = cc_cipher_decrypt, - .min_keysize = CC_HW_KEY_SIZE, - .max_keysize = CC_HW_KEY_SIZE, - .ivsize = AES_BLOCK_SIZE, - }, - .cipher_mode = DRV_CIPHER_OFB, - .flow_mode = S_DIN_to_AES, - .min_hw_rev = CC_HW_REV_712, - .std_body = CC_STD_NIST, - .sec_func = true, - }, { .name = "cts(cbc(paes))", .driver_name = "cts-cbc-paes-ccree", @@ -1205,23 +1187,6 @@ static const struct cc_alg_template skcipher_algs[] = { .min_hw_rev = CC_HW_REV_630, .std_body = CC_STD_NIST, }, - { - .name = "ofb(aes)", - .driver_name = "ofb-aes-ccree", - .blocksize = 1, - .template_skcipher = { - .setkey = cc_cipher_setkey, - .encrypt = cc_cipher_encrypt, - .decrypt = cc_cipher_decrypt, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_BLOCK_SIZE, - }, - .cipher_mode = DRV_CIPHER_OFB, - .flow_mode = S_DIN_to_AES, - .min_hw_rev = CC_HW_REV_630, - .std_body = CC_STD_NIST, - }, { .name = "cts(cbc(aes))", .driver_name = "cts-cbc-aes-ccree", @@ -1427,9 +1392,13 @@ static struct cc_crypto_alg *cc_create_alg(const struct cc_alg_template *tmpl, memcpy(alg, &tmpl->template_skcipher, sizeof(*alg)); - snprintf(alg->base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", tmpl->name); - snprintf(alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", - tmpl->driver_name); + if (snprintf(alg->base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", + tmpl->name) >= CRYPTO_MAX_ALG_NAME) + return ERR_PTR(-EINVAL); + if (snprintf(alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", + tmpl->driver_name) >= CRYPTO_MAX_ALG_NAME) + return ERR_PTR(-EINVAL); + alg->base.cra_module = THIS_MODULE; alg->base.cra_priority = CC_CRA_PRIO; alg->base.cra_blocksize = tmpl->blocksize; diff --git a/drivers/crypto/gemini/sl3516-ce-cipher.c b/drivers/crypto/gemini/sl3516-ce-cipher.c index 49dce9e0a8343f..583010b2d00712 100644 --- a/drivers/crypto/gemini/sl3516-ce-cipher.c +++ b/drivers/crypto/gemini/sl3516-ce-cipher.c @@ -332,8 +332,8 @@ int sl3516_ce_cipher_init(struct crypto_tfm *tfm) return PTR_ERR(op->fallback_tfm); } - sktfm->reqsize = sizeof(struct sl3516_ce_cipher_req_ctx) + - crypto_skcipher_reqsize(op->fallback_tfm); + crypto_skcipher_set_reqsize(sktfm, sizeof(struct sl3516_ce_cipher_req_ctx) + + crypto_skcipher_reqsize(op->fallback_tfm)); dev_info(op->ce->dev, "Fallback for %s is %s\n", crypto_tfm_alg_driver_name(&sktfm->base), diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c index 7bddc3c786c1a7..b4a4ec35bce056 100644 --- a/drivers/crypto/hifn_795x.c +++ b/drivers/crypto/hifn_795x.c @@ -2096,16 +2096,6 @@ static inline int hifn_encrypt_aes_cbc(struct skcipher_request *req) return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CBC); } -static inline int hifn_encrypt_aes_cfb(struct skcipher_request *req) -{ - return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, - ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CFB); -} -static inline int hifn_encrypt_aes_ofb(struct skcipher_request *req) -{ - return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, - ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_OFB); -} /* * AES decryption functions. @@ -2120,16 +2110,6 @@ static inline int hifn_decrypt_aes_cbc(struct skcipher_request *req) return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CBC); } -static inline int hifn_decrypt_aes_cfb(struct skcipher_request *req) -{ - return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, - ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_CFB); -} -static inline int hifn_decrypt_aes_ofb(struct skcipher_request *req) -{ - return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, - ACRYPTO_TYPE_AES_128, ACRYPTO_MODE_OFB); -} /* * DES ecryption functions. @@ -2144,16 +2124,6 @@ static inline int hifn_encrypt_des_cbc(struct skcipher_request *req) return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, ACRYPTO_TYPE_DES, ACRYPTO_MODE_CBC); } -static inline int hifn_encrypt_des_cfb(struct skcipher_request *req) -{ - return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, - ACRYPTO_TYPE_DES, ACRYPTO_MODE_CFB); -} -static inline int hifn_encrypt_des_ofb(struct skcipher_request *req) -{ - return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, - ACRYPTO_TYPE_DES, ACRYPTO_MODE_OFB); -} /* * DES decryption functions. @@ -2168,16 +2138,6 @@ static inline int hifn_decrypt_des_cbc(struct skcipher_request *req) return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, ACRYPTO_TYPE_DES, ACRYPTO_MODE_CBC); } -static inline int hifn_decrypt_des_cfb(struct skcipher_request *req) -{ - return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, - ACRYPTO_TYPE_DES, ACRYPTO_MODE_CFB); -} -static inline int hifn_decrypt_des_ofb(struct skcipher_request *req) -{ - return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, - ACRYPTO_TYPE_DES, ACRYPTO_MODE_OFB); -} /* * 3DES ecryption functions. @@ -2192,16 +2152,6 @@ static inline int hifn_encrypt_3des_cbc(struct skcipher_request *req) return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CBC); } -static inline int hifn_encrypt_3des_cfb(struct skcipher_request *req) -{ - return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, - ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CFB); -} -static inline int hifn_encrypt_3des_ofb(struct skcipher_request *req) -{ - return hifn_setup_crypto(req, ACRYPTO_OP_ENCRYPT, - ACRYPTO_TYPE_3DES, ACRYPTO_MODE_OFB); -} /* 3DES decryption functions. */ static inline int hifn_decrypt_3des_ecb(struct skcipher_request *req) @@ -2214,16 +2164,6 @@ static inline int hifn_decrypt_3des_cbc(struct skcipher_request *req) return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CBC); } -static inline int hifn_decrypt_3des_cfb(struct skcipher_request *req) -{ - return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, - ACRYPTO_TYPE_3DES, ACRYPTO_MODE_CFB); -} -static inline int hifn_decrypt_3des_ofb(struct skcipher_request *req) -{ - return hifn_setup_crypto(req, ACRYPTO_OP_DECRYPT, - ACRYPTO_TYPE_3DES, ACRYPTO_MODE_OFB); -} struct hifn_alg_template { char name[CRYPTO_MAX_ALG_NAME]; @@ -2234,28 +2174,8 @@ struct hifn_alg_template { static const struct hifn_alg_template hifn_alg_templates[] = { /* - * 3DES ECB, CBC, CFB and OFB modes. + * 3DES ECB and CBC modes. */ - { - .name = "cfb(des3_ede)", .drv_name = "cfb-3des", .bsize = 8, - .skcipher = { - .min_keysize = HIFN_3DES_KEY_LENGTH, - .max_keysize = HIFN_3DES_KEY_LENGTH, - .setkey = hifn_des3_setkey, - .encrypt = hifn_encrypt_3des_cfb, - .decrypt = hifn_decrypt_3des_cfb, - }, - }, - { - .name = "ofb(des3_ede)", .drv_name = "ofb-3des", .bsize = 8, - .skcipher = { - .min_keysize = HIFN_3DES_KEY_LENGTH, - .max_keysize = HIFN_3DES_KEY_LENGTH, - .setkey = hifn_des3_setkey, - .encrypt = hifn_encrypt_3des_ofb, - .decrypt = hifn_decrypt_3des_ofb, - }, - }, { .name = "cbc(des3_ede)", .drv_name = "cbc-3des", .bsize = 8, .skcipher = { @@ -2279,28 +2199,8 @@ static const struct hifn_alg_template hifn_alg_templates[] = { }, /* - * DES ECB, CBC, CFB and OFB modes. + * DES ECB and CBC modes. */ - { - .name = "cfb(des)", .drv_name = "cfb-des", .bsize = 8, - .skcipher = { - .min_keysize = HIFN_DES_KEY_LENGTH, - .max_keysize = HIFN_DES_KEY_LENGTH, - .setkey = hifn_setkey, - .encrypt = hifn_encrypt_des_cfb, - .decrypt = hifn_decrypt_des_cfb, - }, - }, - { - .name = "ofb(des)", .drv_name = "ofb-des", .bsize = 8, - .skcipher = { - .min_keysize = HIFN_DES_KEY_LENGTH, - .max_keysize = HIFN_DES_KEY_LENGTH, - .setkey = hifn_setkey, - .encrypt = hifn_encrypt_des_ofb, - .decrypt = hifn_decrypt_des_ofb, - }, - }, { .name = "cbc(des)", .drv_name = "cbc-des", .bsize = 8, .skcipher = { @@ -2324,7 +2224,7 @@ static const struct hifn_alg_template hifn_alg_templates[] = { }, /* - * AES ECB, CBC, CFB and OFB modes. + * AES ECB and CBC modes. */ { .name = "ecb(aes)", .drv_name = "ecb-aes", .bsize = 16, @@ -2347,26 +2247,6 @@ static const struct hifn_alg_template hifn_alg_templates[] = { .decrypt = hifn_decrypt_aes_cbc, }, }, - { - .name = "cfb(aes)", .drv_name = "cfb-aes", .bsize = 16, - .skcipher = { - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .setkey = hifn_setkey, - .encrypt = hifn_encrypt_aes_cfb, - .decrypt = hifn_decrypt_aes_cfb, - }, - }, - { - .name = "ofb(aes)", .drv_name = "ofb-aes", .bsize = 16, - .skcipher = { - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .setkey = hifn_setkey, - .encrypt = hifn_encrypt_aes_ofb, - .decrypt = hifn_decrypt_aes_ofb, - }, - }, }; static int hifn_init_tfm(struct crypto_skcipher *tfm) diff --git a/drivers/crypto/hisilicon/debugfs.c b/drivers/crypto/hisilicon/debugfs.c index 7e8186fe051243..80ed4b2d209cac 100644 --- a/drivers/crypto/hisilicon/debugfs.c +++ b/drivers/crypto/hisilicon/debugfs.c @@ -31,6 +31,10 @@ static const char * const qm_debug_file_name[] = { [CLEAR_ENABLE] = "clear_enable", }; +static const char * const qm_s[] = { + "work", "stop", +}; + struct qm_dfx_item { const char *name; u32 offset; @@ -53,34 +57,34 @@ static struct qm_dfx_item qm_dfx_files[] = { #define CNT_CYC_REGS_NUM 10 static const struct debugfs_reg32 qm_dfx_regs[] = { /* XXX_CNT are reading clear register */ - {"QM_ECC_1BIT_CNT ", 0x104000ull}, - {"QM_ECC_MBIT_CNT ", 0x104008ull}, - {"QM_DFX_MB_CNT ", 0x104018ull}, - {"QM_DFX_DB_CNT ", 0x104028ull}, - {"QM_DFX_SQE_CNT ", 0x104038ull}, - {"QM_DFX_CQE_CNT ", 0x104048ull}, - {"QM_DFX_SEND_SQE_TO_ACC_CNT ", 0x104050ull}, - {"QM_DFX_WB_SQE_FROM_ACC_CNT ", 0x104058ull}, - {"QM_DFX_ACC_FINISH_CNT ", 0x104060ull}, - {"QM_DFX_CQE_ERR_CNT ", 0x1040b4ull}, - {"QM_DFX_FUNS_ACTIVE_ST ", 0x200ull}, - {"QM_ECC_1BIT_INF ", 0x104004ull}, - {"QM_ECC_MBIT_INF ", 0x10400cull}, - {"QM_DFX_ACC_RDY_VLD0 ", 0x1040a0ull}, - {"QM_DFX_ACC_RDY_VLD1 ", 0x1040a4ull}, - {"QM_DFX_AXI_RDY_VLD ", 0x1040a8ull}, - {"QM_DFX_FF_ST0 ", 0x1040c8ull}, - {"QM_DFX_FF_ST1 ", 0x1040ccull}, - {"QM_DFX_FF_ST2 ", 0x1040d0ull}, - {"QM_DFX_FF_ST3 ", 0x1040d4ull}, - {"QM_DFX_FF_ST4 ", 0x1040d8ull}, - {"QM_DFX_FF_ST5 ", 0x1040dcull}, - {"QM_DFX_FF_ST6 ", 0x1040e0ull}, - {"QM_IN_IDLE_ST ", 0x1040e4ull}, + {"QM_ECC_1BIT_CNT ", 0x104000}, + {"QM_ECC_MBIT_CNT ", 0x104008}, + {"QM_DFX_MB_CNT ", 0x104018}, + {"QM_DFX_DB_CNT ", 0x104028}, + {"QM_DFX_SQE_CNT ", 0x104038}, + {"QM_DFX_CQE_CNT ", 0x104048}, + {"QM_DFX_SEND_SQE_TO_ACC_CNT ", 0x104050}, + {"QM_DFX_WB_SQE_FROM_ACC_CNT ", 0x104058}, + {"QM_DFX_ACC_FINISH_CNT ", 0x104060}, + {"QM_DFX_CQE_ERR_CNT ", 0x1040b4}, + {"QM_DFX_FUNS_ACTIVE_ST ", 0x200}, + {"QM_ECC_1BIT_INF ", 0x104004}, + {"QM_ECC_MBIT_INF ", 0x10400c}, + {"QM_DFX_ACC_RDY_VLD0 ", 0x1040a0}, + {"QM_DFX_ACC_RDY_VLD1 ", 0x1040a4}, + {"QM_DFX_AXI_RDY_VLD ", 0x1040a8}, + {"QM_DFX_FF_ST0 ", 0x1040c8}, + {"QM_DFX_FF_ST1 ", 0x1040cc}, + {"QM_DFX_FF_ST2 ", 0x1040d0}, + {"QM_DFX_FF_ST3 ", 0x1040d4}, + {"QM_DFX_FF_ST4 ", 0x1040d8}, + {"QM_DFX_FF_ST5 ", 0x1040dc}, + {"QM_DFX_FF_ST6 ", 0x1040e0}, + {"QM_IN_IDLE_ST ", 0x1040e4}, }; static const struct debugfs_reg32 qm_vf_dfx_regs[] = { - {"QM_DFX_FUNS_ACTIVE_ST ", 0x200ull}, + {"QM_DFX_FUNS_ACTIVE_ST ", 0x200}, }; /* define the QM's dfx regs region and region length */ diff --git a/drivers/crypto/hisilicon/hpre/hpre_main.c b/drivers/crypto/hisilicon/hpre/hpre_main.c index 56777099ef6965..3255b2a070c785 100644 --- a/drivers/crypto/hisilicon/hpre/hpre_main.c +++ b/drivers/crypto/hisilicon/hpre/hpre_main.c @@ -118,8 +118,6 @@ #define HPRE_DFX_COMMON2_LEN 0xE #define HPRE_DFX_CORE_LEN 0x43 -#define HPRE_DEV_ALG_MAX_LEN 256 - static const char hpre_name[] = "hisi_hpre"; static struct dentry *hpre_debugfs_root; static const struct pci_device_id hpre_dev_ids[] = { @@ -135,12 +133,7 @@ struct hpre_hw_error { const char *msg; }; -struct hpre_dev_alg { - u32 alg_msk; - const char *alg; -}; - -static const struct hpre_dev_alg hpre_dev_algs[] = { +static const struct qm_dev_alg hpre_dev_algs[] = { { .alg_msk = BIT(0), .alg = "rsa\n" @@ -233,6 +226,20 @@ static const struct hisi_qm_cap_info hpre_basic_info[] = { {HPRE_CORE10_ALG_BITMAP_CAP, 0x3170, 0, GENMASK(31, 0), 0x0, 0x10, 0x10} }; +enum hpre_pre_store_cap_idx { + HPRE_CLUSTER_NUM_CAP_IDX = 0x0, + HPRE_CORE_ENABLE_BITMAP_CAP_IDX, + HPRE_DRV_ALG_BITMAP_CAP_IDX, + HPRE_DEV_ALG_BITMAP_CAP_IDX, +}; + +static const u32 hpre_pre_store_caps[] = { + HPRE_CLUSTER_NUM_CAP, + HPRE_CORE_ENABLE_BITMAP_CAP, + HPRE_DRV_ALG_BITMAP_CAP, + HPRE_DEV_ALG_BITMAP_CAP, +}; + static const struct hpre_hw_error hpre_hw_errors[] = { { .int_msk = BIT(0), @@ -355,42 +362,13 @@ bool hpre_check_alg_support(struct hisi_qm *qm, u32 alg) { u32 cap_val; - cap_val = hisi_qm_get_hw_info(qm, hpre_basic_info, HPRE_DRV_ALG_BITMAP_CAP, qm->cap_ver); + cap_val = qm->cap_tables.dev_cap_table[HPRE_DRV_ALG_BITMAP_CAP_IDX].cap_val; if (alg & cap_val) return true; return false; } -static int hpre_set_qm_algs(struct hisi_qm *qm) -{ - struct device *dev = &qm->pdev->dev; - char *algs, *ptr; - u32 alg_msk; - int i; - - if (!qm->use_sva) - return 0; - - algs = devm_kzalloc(dev, HPRE_DEV_ALG_MAX_LEN * sizeof(char), GFP_KERNEL); - if (!algs) - return -ENOMEM; - - alg_msk = hisi_qm_get_hw_info(qm, hpre_basic_info, HPRE_DEV_ALG_BITMAP_CAP, qm->cap_ver); - - for (i = 0; i < ARRAY_SIZE(hpre_dev_algs); i++) - if (alg_msk & hpre_dev_algs[i].alg_msk) - strcat(algs, hpre_dev_algs[i].alg); - - ptr = strrchr(algs, '\n'); - if (ptr) - *ptr = '\0'; - - qm->uacce->algs = algs; - - return 0; -} - static int hpre_diff_regs_show(struct seq_file *s, void *unused) { struct hisi_qm *qm = s->private; @@ -460,16 +438,6 @@ static u32 vfs_num; module_param_cb(vfs_num, &vfs_num_ops, &vfs_num, 0444); MODULE_PARM_DESC(vfs_num, "Number of VFs to enable(1-63), 0(default)"); -static inline int hpre_cluster_num(struct hisi_qm *qm) -{ - return hisi_qm_get_hw_info(qm, hpre_basic_info, HPRE_CLUSTER_NUM_CAP, qm->cap_ver); -} - -static inline int hpre_cluster_core_mask(struct hisi_qm *qm) -{ - return hisi_qm_get_hw_info(qm, hpre_basic_info, HPRE_CORE_ENABLE_BITMAP_CAP, qm->cap_ver); -} - struct hisi_qp *hpre_create_qp(u8 type) { int node = cpu_to_node(smp_processor_id()); @@ -536,13 +504,15 @@ static int hpre_cfg_by_dsm(struct hisi_qm *qm) static int hpre_set_cluster(struct hisi_qm *qm) { - u32 cluster_core_mask = hpre_cluster_core_mask(qm); - u8 clusters_num = hpre_cluster_num(qm); struct device *dev = &qm->pdev->dev; unsigned long offset; + u32 cluster_core_mask; + u8 clusters_num; u32 val = 0; int ret, i; + cluster_core_mask = qm->cap_tables.dev_cap_table[HPRE_CORE_ENABLE_BITMAP_CAP_IDX].cap_val; + clusters_num = qm->cap_tables.dev_cap_table[HPRE_CLUSTER_NUM_CAP_IDX].cap_val; for (i = 0; i < clusters_num; i++) { offset = i * HPRE_CLSTR_ADDR_INTRVL; @@ -737,11 +707,12 @@ static int hpre_set_user_domain_and_cache(struct hisi_qm *qm) static void hpre_cnt_regs_clear(struct hisi_qm *qm) { - u8 clusters_num = hpre_cluster_num(qm); unsigned long offset; + u8 clusters_num; int i; /* clear clusterX/cluster_ctrl */ + clusters_num = qm->cap_tables.dev_cap_table[HPRE_CLUSTER_NUM_CAP_IDX].cap_val; for (i = 0; i < clusters_num; i++) { offset = HPRE_CLSTR_BASE + i * HPRE_CLSTR_ADDR_INTRVL; writel(0x0, qm->io_base + offset + HPRE_CLUSTER_INQURY); @@ -1028,13 +999,14 @@ static int hpre_pf_comm_regs_debugfs_init(struct hisi_qm *qm) static int hpre_cluster_debugfs_init(struct hisi_qm *qm) { - u8 clusters_num = hpre_cluster_num(qm); struct device *dev = &qm->pdev->dev; char buf[HPRE_DBGFS_VAL_MAX_LEN]; struct debugfs_regset32 *regset; struct dentry *tmp_d; + u8 clusters_num; int i, ret; + clusters_num = qm->cap_tables.dev_cap_table[HPRE_CLUSTER_NUM_CAP_IDX].cap_val; for (i = 0; i < clusters_num; i++) { ret = snprintf(buf, HPRE_DBGFS_VAL_MAX_LEN, "cluster%d", i); if (ret >= HPRE_DBGFS_VAL_MAX_LEN) @@ -1139,8 +1111,37 @@ static void hpre_debugfs_exit(struct hisi_qm *qm) debugfs_remove_recursive(qm->debug.debug_root); } +static int hpre_pre_store_cap_reg(struct hisi_qm *qm) +{ + struct hisi_qm_cap_record *hpre_cap; + struct device *dev = &qm->pdev->dev; + size_t i, size; + + size = ARRAY_SIZE(hpre_pre_store_caps); + hpre_cap = devm_kzalloc(dev, sizeof(*hpre_cap) * size, GFP_KERNEL); + if (!hpre_cap) + return -ENOMEM; + + for (i = 0; i < size; i++) { + hpre_cap[i].type = hpre_pre_store_caps[i]; + hpre_cap[i].cap_val = hisi_qm_get_hw_info(qm, hpre_basic_info, + hpre_pre_store_caps[i], qm->cap_ver); + } + + if (hpre_cap[HPRE_CLUSTER_NUM_CAP_IDX].cap_val > HPRE_CLUSTERS_NUM_MAX) { + dev_err(dev, "Device cluster num %u is out of range for driver supports %d!\n", + hpre_cap[HPRE_CLUSTER_NUM_CAP_IDX].cap_val, HPRE_CLUSTERS_NUM_MAX); + return -EINVAL; + } + + qm->cap_tables.dev_cap_table = hpre_cap; + + return 0; +} + static int hpre_qm_init(struct hisi_qm *qm, struct pci_dev *pdev) { + u64 alg_msk; int ret; if (pdev->revision == QM_HW_V1) { @@ -1171,7 +1172,16 @@ static int hpre_qm_init(struct hisi_qm *qm, struct pci_dev *pdev) return ret; } - ret = hpre_set_qm_algs(qm); + /* Fetch and save the value of capability registers */ + ret = hpre_pre_store_cap_reg(qm); + if (ret) { + pci_err(pdev, "Failed to pre-store capability registers!\n"); + hisi_qm_uninit(qm); + return ret; + } + + alg_msk = qm->cap_tables.dev_cap_table[HPRE_DEV_ALG_BITMAP_CAP_IDX].cap_val; + ret = hisi_qm_set_algs(qm, alg_msk, hpre_dev_algs, ARRAY_SIZE(hpre_dev_algs)); if (ret) { pci_err(pdev, "Failed to set hpre algs!\n"); hisi_qm_uninit(qm); @@ -1184,11 +1194,12 @@ static int hpre_show_last_regs_init(struct hisi_qm *qm) { int cluster_dfx_regs_num = ARRAY_SIZE(hpre_cluster_dfx_regs); int com_dfx_regs_num = ARRAY_SIZE(hpre_com_dfx_regs); - u8 clusters_num = hpre_cluster_num(qm); struct qm_debug *debug = &qm->debug; void __iomem *io_base; + u8 clusters_num; int i, j, idx; + clusters_num = qm->cap_tables.dev_cap_table[HPRE_CLUSTER_NUM_CAP_IDX].cap_val; debug->last_words = kcalloc(cluster_dfx_regs_num * clusters_num + com_dfx_regs_num, sizeof(unsigned int), GFP_KERNEL); if (!debug->last_words) @@ -1225,10 +1236,10 @@ static void hpre_show_last_dfx_regs(struct hisi_qm *qm) { int cluster_dfx_regs_num = ARRAY_SIZE(hpre_cluster_dfx_regs); int com_dfx_regs_num = ARRAY_SIZE(hpre_com_dfx_regs); - u8 clusters_num = hpre_cluster_num(qm); struct qm_debug *debug = &qm->debug; struct pci_dev *pdev = qm->pdev; void __iomem *io_base; + u8 clusters_num; int i, j, idx; u32 val; @@ -1243,6 +1254,7 @@ static void hpre_show_last_dfx_regs(struct hisi_qm *qm) hpre_com_dfx_regs[i].name, debug->last_words[i], val); } + clusters_num = qm->cap_tables.dev_cap_table[HPRE_CLUSTER_NUM_CAP_IDX].cap_val; for (i = 0; i < clusters_num; i++) { io_base = qm->io_base + hpre_cluster_offsets[i]; for (j = 0; j < cluster_dfx_regs_num; j++) { diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index 18599f3634c3c1..4b20b94e6371ad 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -129,16 +129,21 @@ #define QM_FIFO_OVERFLOW_TYPE 0xc0 #define QM_FIFO_OVERFLOW_TYPE_SHIFT 6 #define QM_FIFO_OVERFLOW_VF 0x3f +#define QM_FIFO_OVERFLOW_QP_SHIFT 16 #define QM_ABNORMAL_INF01 0x100014 #define QM_DB_TIMEOUT_TYPE 0xc0 #define QM_DB_TIMEOUT_TYPE_SHIFT 6 #define QM_DB_TIMEOUT_VF 0x3f +#define QM_DB_TIMEOUT_QP_SHIFT 16 +#define QM_ABNORMAL_INF02 0x100018 +#define QM_AXI_POISON_ERR BIT(22) #define QM_RAS_CE_ENABLE 0x1000ec #define QM_RAS_FE_ENABLE 0x1000f0 #define QM_RAS_NFE_ENABLE 0x1000f4 #define QM_RAS_CE_THRESHOLD 0x1000f8 #define QM_RAS_CE_TIMES_PER_IRQ 1 #define QM_OOO_SHUTDOWN_SEL 0x1040f8 +#define QM_AXI_RRESP_ERR BIT(0) #define QM_ECC_MBIT BIT(2) #define QM_DB_TIMEOUT BIT(10) #define QM_OF_FIFO_OF BIT(11) @@ -229,6 +234,8 @@ #define QM_QOS_MAX_CIR_U 6 #define QM_AUTOSUSPEND_DELAY 3000 +#define QM_DEV_ALG_MAX_LEN 256 + #define QM_MK_CQC_DW3_V1(hop_num, pg_sz, buf_sz, cqe_sz) \ (((hop_num) << QM_CQ_HOP_NUM_SHIFT) | \ ((pg_sz) << QM_CQ_PAGE_SIZE_SHIFT) | \ @@ -294,6 +301,13 @@ enum qm_basic_type { QM_VF_IRQ_NUM_CAP, }; +enum qm_pre_store_cap_idx { + QM_EQ_IRQ_TYPE_CAP_IDX = 0x0, + QM_AEQ_IRQ_TYPE_CAP_IDX, + QM_ABN_IRQ_TYPE_CAP_IDX, + QM_PF2VF_IRQ_TYPE_CAP_IDX, +}; + static const struct hisi_qm_cap_info qm_cap_info_comm[] = { {QM_SUPPORT_DB_ISOLATION, 0x30, 0, BIT(0), 0x0, 0x0, 0x0}, {QM_SUPPORT_FUNC_QOS, 0x3100, 0, BIT(8), 0x0, 0x0, 0x1}, @@ -323,6 +337,13 @@ static const struct hisi_qm_cap_info qm_basic_info[] = { {QM_VF_IRQ_NUM_CAP, 0x311c, 0, GENMASK(15, 0), 0x1, 0x2, 0x3}, }; +static const u32 qm_pre_store_caps[] = { + QM_EQ_IRQ_TYPE_CAP, + QM_AEQ_IRQ_TYPE_CAP, + QM_ABN_IRQ_TYPE_CAP, + QM_PF2VF_IRQ_TYPE_CAP, +}; + struct qm_mailbox { __le16 w0; __le16 queue_num; @@ -386,7 +407,6 @@ static const struct hisi_qm_hw_error qm_hw_error[] = { { .int_msk = BIT(12), .msg = "qm_db_random_invalid" }, { .int_msk = BIT(13), .msg = "qm_mailbox_timeout" }, { .int_msk = BIT(14), .msg = "qm_flr_timeout" }, - { /* sentinel */ } }; static const char * const qm_db_timeout[] = { @@ -397,10 +417,6 @@ static const char * const qm_fifo_overflow[] = { "cq", "eq", "aeq", }; -static const char * const qp_s[] = { - "none", "init", "start", "stop", "close", -}; - struct qm_typical_qos_table { u32 start; u32 end; @@ -428,85 +444,6 @@ static struct qm_typical_qos_table shaper_cbs_s[] = { static void qm_irqs_unregister(struct hisi_qm *qm); -static bool qm_avail_state(struct hisi_qm *qm, enum qm_state new) -{ - enum qm_state curr = atomic_read(&qm->status.flags); - bool avail = false; - - switch (curr) { - case QM_INIT: - if (new == QM_START || new == QM_CLOSE) - avail = true; - break; - case QM_START: - if (new == QM_STOP) - avail = true; - break; - case QM_STOP: - if (new == QM_CLOSE || new == QM_START) - avail = true; - break; - default: - break; - } - - dev_dbg(&qm->pdev->dev, "change qm state from %s to %s\n", - qm_s[curr], qm_s[new]); - - if (!avail) - dev_warn(&qm->pdev->dev, "Can not change qm state from %s to %s\n", - qm_s[curr], qm_s[new]); - - return avail; -} - -static bool qm_qp_avail_state(struct hisi_qm *qm, struct hisi_qp *qp, - enum qp_state new) -{ - enum qm_state qm_curr = atomic_read(&qm->status.flags); - enum qp_state qp_curr = 0; - bool avail = false; - - if (qp) - qp_curr = atomic_read(&qp->qp_status.flags); - - switch (new) { - case QP_INIT: - if (qm_curr == QM_START || qm_curr == QM_INIT) - avail = true; - break; - case QP_START: - if ((qm_curr == QM_START && qp_curr == QP_INIT) || - (qm_curr == QM_START && qp_curr == QP_STOP)) - avail = true; - break; - case QP_STOP: - if ((qm_curr == QM_START && qp_curr == QP_START) || - (qp_curr == QP_INIT)) - avail = true; - break; - case QP_CLOSE: - if ((qm_curr == QM_START && qp_curr == QP_INIT) || - (qm_curr == QM_START && qp_curr == QP_STOP) || - (qm_curr == QM_STOP && qp_curr == QP_STOP) || - (qm_curr == QM_STOP && qp_curr == QP_INIT)) - avail = true; - break; - default: - break; - } - - dev_dbg(&qm->pdev->dev, "change qp state from %s to %s in QM %s\n", - qp_s[qp_curr], qp_s[new], qm_s[qm_curr]); - - if (!avail) - dev_warn(&qm->pdev->dev, - "Can not change qp state from %s to %s in QM %s\n", - qp_s[qp_curr], qp_s[new], qm_s[qm_curr]); - - return avail; -} - static u32 qm_get_hw_error_status(struct hisi_qm *qm) { return readl(qm->io_base + QM_ABNORMAL_INT_STATUS); @@ -660,9 +597,6 @@ int hisi_qm_mb(struct hisi_qm *qm, u8 cmd, dma_addr_t dma_addr, u16 queue, struct qm_mailbox mailbox; int ret; - dev_dbg(&qm->pdev->dev, "QM mailbox request to q%u: %u-%llx\n", - queue, cmd, (unsigned long long)dma_addr); - qm_mb_pre_init(&mailbox, cmd, dma_addr, queue, op); mutex_lock(&qm->mailbox_lock); @@ -828,6 +762,40 @@ static void qm_get_xqc_depth(struct hisi_qm *qm, u16 *low_bits, *high_bits = (depth >> QM_XQ_DEPTH_SHIFT) & QM_XQ_DEPTH_MASK; } +int hisi_qm_set_algs(struct hisi_qm *qm, u64 alg_msk, const struct qm_dev_alg *dev_algs, + u32 dev_algs_size) +{ + struct device *dev = &qm->pdev->dev; + char *algs, *ptr; + int i; + + if (!qm->uacce) + return 0; + + if (dev_algs_size >= QM_DEV_ALG_MAX_LEN) { + dev_err(dev, "algs size %u is equal or larger than %d.\n", + dev_algs_size, QM_DEV_ALG_MAX_LEN); + return -EINVAL; + } + + algs = devm_kzalloc(dev, QM_DEV_ALG_MAX_LEN * sizeof(char), GFP_KERNEL); + if (!algs) + return -ENOMEM; + + for (i = 0; i < dev_algs_size; i++) + if (alg_msk & dev_algs[i].alg_msk) + strcat(algs, dev_algs[i].alg); + + ptr = strrchr(algs, '\n'); + if (ptr) { + *ptr = '\0'; + qm->uacce->algs = algs; + } + + return 0; +} +EXPORT_SYMBOL_GPL(hisi_qm_set_algs); + static u32 qm_get_irq_num(struct hisi_qm *qm) { if (qm->fun_type == QM_HW_PF) @@ -1406,7 +1374,7 @@ static void qm_log_hw_error(struct hisi_qm *qm, u32 error_status) { const struct hisi_qm_hw_error *err; struct device *dev = &qm->pdev->dev; - u32 reg_val, type, vf_num; + u32 reg_val, type, vf_num, qp_id; int i; for (i = 0; i < ARRAY_SIZE(qm_hw_error); i++) { @@ -1422,19 +1390,24 @@ static void qm_log_hw_error(struct hisi_qm *qm, u32 error_status) type = (reg_val & QM_DB_TIMEOUT_TYPE) >> QM_DB_TIMEOUT_TYPE_SHIFT; vf_num = reg_val & QM_DB_TIMEOUT_VF; - dev_err(dev, "qm %s doorbell timeout in function %u\n", - qm_db_timeout[type], vf_num); + qp_id = reg_val >> QM_DB_TIMEOUT_QP_SHIFT; + dev_err(dev, "qm %s doorbell timeout in function %u qp %u\n", + qm_db_timeout[type], vf_num, qp_id); } else if (err->int_msk & QM_OF_FIFO_OF) { reg_val = readl(qm->io_base + QM_ABNORMAL_INF00); type = (reg_val & QM_FIFO_OVERFLOW_TYPE) >> QM_FIFO_OVERFLOW_TYPE_SHIFT; vf_num = reg_val & QM_FIFO_OVERFLOW_VF; - + qp_id = reg_val >> QM_FIFO_OVERFLOW_QP_SHIFT; if (type < ARRAY_SIZE(qm_fifo_overflow)) - dev_err(dev, "qm %s fifo overflow in function %u\n", - qm_fifo_overflow[type], vf_num); + dev_err(dev, "qm %s fifo overflow in function %u qp %u\n", + qm_fifo_overflow[type], vf_num, qp_id); else dev_err(dev, "unknown error type\n"); + } else if (err->int_msk & QM_AXI_RRESP_ERR) { + reg_val = readl(qm->io_base + QM_ABNORMAL_INF02); + if (reg_val & QM_AXI_POISON_ERR) + dev_err(dev, "qm axi poison error happened\n"); } } } @@ -1843,8 +1816,10 @@ static struct hisi_qp *qm_create_qp_nolock(struct hisi_qm *qm, u8 alg_type) struct hisi_qp *qp; int qp_id; - if (!qm_qp_avail_state(qm, NULL, QP_INIT)) + if (atomic_read(&qm->status.flags) == QM_STOP) { + dev_info_ratelimited(dev, "failed to create qp as qm is stop!\n"); return ERR_PTR(-EPERM); + } if (qm->qp_in_used == qm->qp_num) { dev_info_ratelimited(dev, "All %u queues of QM are busy!\n", @@ -1871,7 +1846,6 @@ static struct hisi_qp *qm_create_qp_nolock(struct hisi_qm *qm, u8 alg_type) qp->alg_type = alg_type; qp->is_in_kernel = true; qm->qp_in_used++; - atomic_set(&qp->qp_status.flags, QP_INIT); return qp; } @@ -1914,11 +1888,6 @@ static void hisi_qm_release_qp(struct hisi_qp *qp) down_write(&qm->qps_lock); - if (!qm_qp_avail_state(qm, qp, QP_CLOSE)) { - up_write(&qm->qps_lock); - return; - } - qm->qp_in_used--; idr_remove(&qm->qp_idr, qp->qp_id); @@ -1966,6 +1935,11 @@ static int qm_cq_ctx_cfg(struct hisi_qp *qp, int qp_id, u32 pasid) cqc.dw3 = cpu_to_le32(QM_MK_CQC_DW3_V2(QM_QC_CQE_SIZE, qp->cq_depth)); cqc.w8 = 0; /* rand_qc */ } + /* + * Enable request finishing interrupts defaultly. + * So, there will be some interrupts until disabling + * this. + */ cqc.dw6 = cpu_to_le32(1 << QM_CQ_PHASE_SHIFT | 1 << QM_CQ_FLAG_SHIFT); cqc.base_l = cpu_to_le32(lower_32_bits(qp->cqe_dma)); cqc.base_h = cpu_to_le32(upper_32_bits(qp->cqe_dma)); @@ -1998,8 +1972,10 @@ static int qm_start_qp_nolock(struct hisi_qp *qp, unsigned long arg) u32 pasid = arg; int ret; - if (!qm_qp_avail_state(qm, qp, QP_START)) + if (atomic_read(&qm->status.flags) == QM_STOP) { + dev_info_ratelimited(dev, "failed to start qp as qm is stop!\n"); return -EPERM; + } ret = qm_qp_ctx_cfg(qp, qp_id, pasid); if (ret) @@ -2121,21 +2097,17 @@ static int qm_stop_qp_nolock(struct hisi_qp *qp) * is_resetting flag should be set negative so that this qp will not * be restarted after reset. */ - if (atomic_read(&qp->qp_status.flags) == QP_STOP) { + if (atomic_read(&qp->qp_status.flags) != QP_START) { qp->is_resetting = false; return 0; } - if (!qm_qp_avail_state(qp->qm, qp, QP_STOP)) - return -EPERM; - atomic_set(&qp->qp_status.flags, QP_STOP); ret = qm_drain_qp(qp); if (ret) dev_err(dev, "Failed to drain out data for stopping!\n"); - flush_workqueue(qp->qm->wq); if (unlikely(qp->is_resetting && atomic_read(&qp->qp_status.used))) qp_stop_fail_cb(qp); @@ -2855,13 +2827,8 @@ void hisi_qm_uninit(struct hisi_qm *qm) { qm_cmd_uninit(qm); hisi_qm_unint_work(qm); - down_write(&qm->qps_lock); - - if (!qm_avail_state(qm, QM_CLOSE)) { - up_write(&qm->qps_lock); - return; - } + down_write(&qm->qps_lock); hisi_qm_memory_uninit(qm); hisi_qm_set_state(qm, QM_NOT_READY); up_write(&qm->qps_lock); @@ -3035,11 +3002,6 @@ int hisi_qm_start(struct hisi_qm *qm) down_write(&qm->qps_lock); - if (!qm_avail_state(qm, QM_START)) { - up_write(&qm->qps_lock); - return -EPERM; - } - dev_dbg(dev, "qm start with %u queue pairs\n", qm->qp_num); if (!qm->qp_num) { @@ -3049,10 +3011,12 @@ int hisi_qm_start(struct hisi_qm *qm) } ret = __hisi_qm_start(qm); - if (!ret) - atomic_set(&qm->status.flags, QM_START); + if (ret) + goto err_unlock; + atomic_set(&qm->status.flags, QM_WORK); hisi_qm_set_state(qm, QM_READY); + err_unlock: up_write(&qm->qps_lock); return ret; @@ -3149,10 +3113,11 @@ int hisi_qm_stop(struct hisi_qm *qm, enum qm_stop_reason r) down_write(&qm->qps_lock); qm->status.stop_reason = r; - if (!qm_avail_state(qm, QM_STOP)) { - ret = -EPERM; + if (atomic_read(&qm->status.flags) == QM_STOP) goto err_unlock; - } + + /* Stop all the request sending at first. */ + atomic_set(&qm->status.flags, QM_STOP); if (qm->status.stop_reason == QM_SOFT_RESET || qm->status.stop_reason == QM_DOWN) { @@ -3176,7 +3141,6 @@ int hisi_qm_stop(struct hisi_qm *qm, enum qm_stop_reason r) } qm_clear_queues(qm); - atomic_set(&qm->status.flags, QM_STOP); err_unlock: up_write(&qm->qps_lock); @@ -3966,6 +3930,11 @@ static int qm_set_vf_mse(struct hisi_qm *qm, bool set) int pos; int i; + /* + * Since function qm_set_vf_mse is called only after SRIOV is enabled, + * pci_find_ext_capability cannot return 0, pos does not need to be + * checked. + */ pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV); pci_read_config_word(pdev, pos + PCI_SRIOV_CTRL, &sriov_ctrl); if (set) @@ -4816,7 +4785,7 @@ static void qm_unregister_abnormal_irq(struct hisi_qm *qm) if (qm->fun_type == QM_HW_VF) return; - val = hisi_qm_get_hw_info(qm, qm_basic_info, QM_ABN_IRQ_TYPE_CAP, qm->cap_ver); + val = qm->cap_tables.qm_cap_table[QM_ABN_IRQ_TYPE_CAP_IDX].cap_val; if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_ABN_IRQ_TYPE_MASK)) return; @@ -4833,7 +4802,7 @@ static int qm_register_abnormal_irq(struct hisi_qm *qm) if (qm->fun_type == QM_HW_VF) return 0; - val = hisi_qm_get_hw_info(qm, qm_basic_info, QM_ABN_IRQ_TYPE_CAP, qm->cap_ver); + val = qm->cap_tables.qm_cap_table[QM_ABN_IRQ_TYPE_CAP_IDX].cap_val; if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_ABN_IRQ_TYPE_MASK)) return 0; @@ -4850,7 +4819,7 @@ static void qm_unregister_mb_cmd_irq(struct hisi_qm *qm) struct pci_dev *pdev = qm->pdev; u32 irq_vector, val; - val = hisi_qm_get_hw_info(qm, qm_basic_info, QM_PF2VF_IRQ_TYPE_CAP, qm->cap_ver); + val = qm->cap_tables.qm_cap_table[QM_PF2VF_IRQ_TYPE_CAP_IDX].cap_val; if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_IRQ_TYPE_MASK)) return; @@ -4864,7 +4833,7 @@ static int qm_register_mb_cmd_irq(struct hisi_qm *qm) u32 irq_vector, val; int ret; - val = hisi_qm_get_hw_info(qm, qm_basic_info, QM_PF2VF_IRQ_TYPE_CAP, qm->cap_ver); + val = qm->cap_tables.qm_cap_table[QM_PF2VF_IRQ_TYPE_CAP_IDX].cap_val; if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_IRQ_TYPE_MASK)) return 0; @@ -4881,7 +4850,7 @@ static void qm_unregister_aeq_irq(struct hisi_qm *qm) struct pci_dev *pdev = qm->pdev; u32 irq_vector, val; - val = hisi_qm_get_hw_info(qm, qm_basic_info, QM_AEQ_IRQ_TYPE_CAP, qm->cap_ver); + val = qm->cap_tables.qm_cap_table[QM_AEQ_IRQ_TYPE_CAP_IDX].cap_val; if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_IRQ_TYPE_MASK)) return; @@ -4895,7 +4864,7 @@ static int qm_register_aeq_irq(struct hisi_qm *qm) u32 irq_vector, val; int ret; - val = hisi_qm_get_hw_info(qm, qm_basic_info, QM_AEQ_IRQ_TYPE_CAP, qm->cap_ver); + val = qm->cap_tables.qm_cap_table[QM_AEQ_IRQ_TYPE_CAP_IDX].cap_val; if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_IRQ_TYPE_MASK)) return 0; @@ -4913,7 +4882,7 @@ static void qm_unregister_eq_irq(struct hisi_qm *qm) struct pci_dev *pdev = qm->pdev; u32 irq_vector, val; - val = hisi_qm_get_hw_info(qm, qm_basic_info, QM_EQ_IRQ_TYPE_CAP, qm->cap_ver); + val = qm->cap_tables.qm_cap_table[QM_EQ_IRQ_TYPE_CAP_IDX].cap_val; if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_IRQ_TYPE_MASK)) return; @@ -4927,7 +4896,7 @@ static int qm_register_eq_irq(struct hisi_qm *qm) u32 irq_vector, val; int ret; - val = hisi_qm_get_hw_info(qm, qm_basic_info, QM_EQ_IRQ_TYPE_CAP, qm->cap_ver); + val = qm->cap_tables.qm_cap_table[QM_EQ_IRQ_TYPE_CAP_IDX].cap_val; if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_IRQ_TYPE_MASK)) return 0; @@ -5015,7 +4984,29 @@ static int qm_get_qp_num(struct hisi_qm *qm) return 0; } -static void qm_get_hw_caps(struct hisi_qm *qm) +static int qm_pre_store_irq_type_caps(struct hisi_qm *qm) +{ + struct hisi_qm_cap_record *qm_cap; + struct pci_dev *pdev = qm->pdev; + size_t i, size; + + size = ARRAY_SIZE(qm_pre_store_caps); + qm_cap = devm_kzalloc(&pdev->dev, sizeof(*qm_cap) * size, GFP_KERNEL); + if (!qm_cap) + return -ENOMEM; + + for (i = 0; i < size; i++) { + qm_cap[i].type = qm_pre_store_caps[i]; + qm_cap[i].cap_val = hisi_qm_get_hw_info(qm, qm_basic_info, + qm_pre_store_caps[i], qm->cap_ver); + } + + qm->cap_tables.qm_cap_table = qm_cap; + + return 0; +} + +static int qm_get_hw_caps(struct hisi_qm *qm) { const struct hisi_qm_cap_info *cap_info = qm->fun_type == QM_HW_PF ? qm_cap_info_pf : qm_cap_info_vf; @@ -5046,6 +5037,9 @@ static void qm_get_hw_caps(struct hisi_qm *qm) if (val) set_bit(cap_info[i].type, &qm->caps); } + + /* Fetch and save the value of irq type related capability registers */ + return qm_pre_store_irq_type_caps(qm); } static int qm_get_pci_res(struct hisi_qm *qm) @@ -5067,7 +5061,10 @@ static int qm_get_pci_res(struct hisi_qm *qm) goto err_request_mem_regions; } - qm_get_hw_caps(qm); + ret = qm_get_hw_caps(qm); + if (ret) + goto err_ioremap; + if (test_bit(QM_SUPPORT_DB_ISOLATION, &qm->caps)) { qm->db_interval = QM_QP_DB_INTERVAL; qm->db_phys_base = pci_resource_start(pdev, PCI_BAR_4); @@ -5340,7 +5337,6 @@ int hisi_qm_init(struct hisi_qm *qm) goto err_free_qm_memory; qm_cmd_init(qm); - atomic_set(&qm->status.flags, QM_INIT); return 0; diff --git a/drivers/crypto/hisilicon/qm_common.h b/drivers/crypto/hisilicon/qm_common.h index 7b0b15c83ec120..0760bf55f13e8d 100644 --- a/drivers/crypto/hisilicon/qm_common.h +++ b/drivers/crypto/hisilicon/qm_common.h @@ -72,10 +72,6 @@ struct qm_aeqc { __le32 dw6; }; -static const char * const qm_s[] = { - "init", "start", "close", "stop", -}; - int qm_set_and_get_xqc(struct hisi_qm *qm, u8 cmd, void *xqc, u32 qp_id, bool op); void hisi_qm_show_last_dfx_regs(struct hisi_qm *qm); void hisi_qm_set_algqos_init(struct hisi_qm *qm); diff --git a/drivers/crypto/hisilicon/sec2/sec.h b/drivers/crypto/hisilicon/sec2/sec.h index 3e57fc04b37703..410c83712e2851 100644 --- a/drivers/crypto/hisilicon/sec2/sec.h +++ b/drivers/crypto/hisilicon/sec2/sec.h @@ -220,6 +220,13 @@ enum sec_cap_type { SEC_CORE4_ALG_BITMAP_HIGH, }; +enum sec_cap_reg_record_idx { + SEC_DRV_ALG_BITMAP_LOW_IDX = 0x0, + SEC_DRV_ALG_BITMAP_HIGH_IDX, + SEC_DEV_ALG_BITMAP_LOW_IDX, + SEC_DEV_ALG_BITMAP_HIGH_IDX, +}; + void sec_destroy_qps(struct hisi_qp **qps, int qp_num); struct hisi_qp **sec_create_qps(void); int sec_register_to_crypto(struct hisi_qm *qm); diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.c b/drivers/crypto/hisilicon/sec2/sec_crypto.c index 6fcabbc87860a6..f028dcfd0ead7e 100644 --- a/drivers/crypto/hisilicon/sec2/sec_crypto.c +++ b/drivers/crypto/hisilicon/sec2/sec_crypto.c @@ -850,6 +850,7 @@ static int sec_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, ret = sec_skcipher_aes_sm4_setkey(c_ctx, keylen, c_mode); break; default: + dev_err(dev, "sec c_alg err!\n"); return -EINVAL; } @@ -879,15 +880,11 @@ static int sec_setkey_##name(struct crypto_skcipher *tfm, const u8 *key,\ GEN_SEC_SETKEY_FUNC(aes_ecb, SEC_CALG_AES, SEC_CMODE_ECB) GEN_SEC_SETKEY_FUNC(aes_cbc, SEC_CALG_AES, SEC_CMODE_CBC) GEN_SEC_SETKEY_FUNC(aes_xts, SEC_CALG_AES, SEC_CMODE_XTS) -GEN_SEC_SETKEY_FUNC(aes_ofb, SEC_CALG_AES, SEC_CMODE_OFB) -GEN_SEC_SETKEY_FUNC(aes_cfb, SEC_CALG_AES, SEC_CMODE_CFB) GEN_SEC_SETKEY_FUNC(aes_ctr, SEC_CALG_AES, SEC_CMODE_CTR) GEN_SEC_SETKEY_FUNC(3des_ecb, SEC_CALG_3DES, SEC_CMODE_ECB) GEN_SEC_SETKEY_FUNC(3des_cbc, SEC_CALG_3DES, SEC_CMODE_CBC) GEN_SEC_SETKEY_FUNC(sm4_xts, SEC_CALG_SM4, SEC_CMODE_XTS) GEN_SEC_SETKEY_FUNC(sm4_cbc, SEC_CALG_SM4, SEC_CMODE_CBC) -GEN_SEC_SETKEY_FUNC(sm4_ofb, SEC_CALG_SM4, SEC_CMODE_OFB) -GEN_SEC_SETKEY_FUNC(sm4_cfb, SEC_CALG_SM4, SEC_CMODE_CFB) GEN_SEC_SETKEY_FUNC(sm4_ctr, SEC_CALG_SM4, SEC_CMODE_CTR) static int sec_cipher_pbuf_map(struct sec_ctx *ctx, struct sec_req *req, @@ -1176,7 +1173,8 @@ static int sec_aead_setkey(struct crypto_aead *tfm, const u8 *key, return 0; } - if (crypto_authenc_extractkeys(&keys, key, keylen)) + ret = crypto_authenc_extractkeys(&keys, key, keylen); + if (ret) goto bad_key; ret = sec_aead_aes_set_key(c_ctx, &keys); @@ -1193,6 +1191,7 @@ static int sec_aead_setkey(struct crypto_aead *tfm, const u8 *key, if ((ctx->a_ctx.mac_len & SEC_SQE_LEN_RATE_MASK) || (ctx->a_ctx.a_key_len & SEC_SQE_LEN_RATE_MASK)) { + ret = -EINVAL; dev_err(dev, "MAC or AUTH key length error!\n"); goto bad_key; } @@ -1201,7 +1200,7 @@ static int sec_aead_setkey(struct crypto_aead *tfm, const u8 *key, bad_key: memzero_explicit(&keys, sizeof(struct crypto_authenc_keys)); - return -EINVAL; + return ret; } @@ -2032,8 +2031,6 @@ static int sec_skcipher_cryptlen_check(struct sec_ctx *ctx, ret = -EINVAL; } break; - case SEC_CMODE_CFB: - case SEC_CMODE_OFB: case SEC_CMODE_CTR: if (unlikely(ctx->sec->qm.ver < QM_HW_V3)) { dev_err(dev, "skcipher HW version error!\n"); @@ -2197,16 +2194,6 @@ static struct sec_skcipher sec_skciphers[] = { .alg = SEC_SKCIPHER_ALG("xts(aes)", sec_setkey_aes_xts, SEC_XTS_MIN_KEY_SIZE, SEC_XTS_MAX_KEY_SIZE, AES_BLOCK_SIZE, AES_BLOCK_SIZE), }, - { - .alg_msk = BIT(4), - .alg = SEC_SKCIPHER_ALG("ofb(aes)", sec_setkey_aes_ofb, AES_MIN_KEY_SIZE, - AES_MAX_KEY_SIZE, SEC_MIN_BLOCK_SZ, AES_BLOCK_SIZE), - }, - { - .alg_msk = BIT(5), - .alg = SEC_SKCIPHER_ALG("cfb(aes)", sec_setkey_aes_cfb, AES_MIN_KEY_SIZE, - AES_MAX_KEY_SIZE, SEC_MIN_BLOCK_SZ, AES_BLOCK_SIZE), - }, { .alg_msk = BIT(12), .alg = SEC_SKCIPHER_ALG("cbc(sm4)", sec_setkey_sm4_cbc, AES_MIN_KEY_SIZE, @@ -2222,16 +2209,6 @@ static struct sec_skcipher sec_skciphers[] = { .alg = SEC_SKCIPHER_ALG("xts(sm4)", sec_setkey_sm4_xts, SEC_XTS_MIN_KEY_SIZE, SEC_XTS_MIN_KEY_SIZE, AES_BLOCK_SIZE, AES_BLOCK_SIZE), }, - { - .alg_msk = BIT(15), - .alg = SEC_SKCIPHER_ALG("ofb(sm4)", sec_setkey_sm4_ofb, AES_MIN_KEY_SIZE, - AES_MIN_KEY_SIZE, SEC_MIN_BLOCK_SZ, AES_BLOCK_SIZE), - }, - { - .alg_msk = BIT(16), - .alg = SEC_SKCIPHER_ALG("cfb(sm4)", sec_setkey_sm4_cfb, AES_MIN_KEY_SIZE, - AES_MIN_KEY_SIZE, SEC_MIN_BLOCK_SZ, AES_BLOCK_SIZE), - }, { .alg_msk = BIT(23), .alg = SEC_SKCIPHER_ALG("ecb(des3_ede)", sec_setkey_3des_ecb, SEC_DES3_3KEY_SIZE, @@ -2547,9 +2524,12 @@ err: int sec_register_to_crypto(struct hisi_qm *qm) { - u64 alg_mask = sec_get_alg_bitmap(qm, SEC_DRV_ALG_BITMAP_HIGH, SEC_DRV_ALG_BITMAP_LOW); + u64 alg_mask; int ret = 0; + alg_mask = sec_get_alg_bitmap(qm, SEC_DRV_ALG_BITMAP_HIGH_IDX, + SEC_DRV_ALG_BITMAP_LOW_IDX); + mutex_lock(&sec_algs_lock); if (sec_available_devs) { sec_available_devs++; @@ -2578,7 +2558,10 @@ unlock: void sec_unregister_from_crypto(struct hisi_qm *qm) { - u64 alg_mask = sec_get_alg_bitmap(qm, SEC_DRV_ALG_BITMAP_HIGH, SEC_DRV_ALG_BITMAP_LOW); + u64 alg_mask; + + alg_mask = sec_get_alg_bitmap(qm, SEC_DRV_ALG_BITMAP_HIGH_IDX, + SEC_DRV_ALG_BITMAP_LOW_IDX); mutex_lock(&sec_algs_lock); if (--sec_available_devs) diff --git a/drivers/crypto/hisilicon/sec2/sec_crypto.h b/drivers/crypto/hisilicon/sec2/sec_crypto.h index d033f63b583f85..27a0ee5ad9131c 100644 --- a/drivers/crypto/hisilicon/sec2/sec_crypto.h +++ b/drivers/crypto/hisilicon/sec2/sec_crypto.h @@ -37,8 +37,6 @@ enum sec_mac_len { enum sec_cmode { SEC_CMODE_ECB = 0x0, SEC_CMODE_CBC = 0x1, - SEC_CMODE_CFB = 0x2, - SEC_CMODE_OFB = 0x3, SEC_CMODE_CTR = 0x4, SEC_CMODE_CCM = 0x5, SEC_CMODE_GCM = 0x6, diff --git a/drivers/crypto/hisilicon/sec2/sec_main.c b/drivers/crypto/hisilicon/sec2/sec_main.c index 0e56a47eb86263..7bb99381bbdfbb 100644 --- a/drivers/crypto/hisilicon/sec2/sec_main.c +++ b/drivers/crypto/hisilicon/sec2/sec_main.c @@ -120,7 +120,6 @@ GENMASK_ULL(42, 25)) #define SEC_AEAD_BITMAP (GENMASK_ULL(7, 6) | GENMASK_ULL(18, 17) | \ GENMASK_ULL(45, 43)) -#define SEC_DEV_ALG_MAX_LEN 256 struct sec_hw_error { u32 int_msk; @@ -132,11 +131,6 @@ struct sec_dfx_item { u32 offset; }; -struct sec_dev_alg { - u64 alg_msk; - const char *algs; -}; - static const char sec_name[] = "hisi_sec2"; static struct dentry *sec_debugfs_root; @@ -159,7 +153,7 @@ static const struct hisi_qm_cap_info sec_basic_info[] = { {SEC_CORE_NUM_CAP, 0x313c, 8, GENMASK(7, 0), 0x4, 0x4, 0x4}, {SEC_CORES_PER_CLUSTER_NUM_CAP, 0x313c, 0, GENMASK(7, 0), 0x4, 0x4, 0x4}, {SEC_CORE_ENABLE_BITMAP, 0x3140, 32, GENMASK(31, 0), 0x17F, 0x17F, 0xF}, - {SEC_DRV_ALG_BITMAP_LOW, 0x3144, 0, GENMASK(31, 0), 0x18050CB, 0x18050CB, 0x187F0FF}, + {SEC_DRV_ALG_BITMAP_LOW, 0x3144, 0, GENMASK(31, 0), 0x18050CB, 0x18050CB, 0x18670CF}, {SEC_DRV_ALG_BITMAP_HIGH, 0x3148, 0, GENMASK(31, 0), 0x395C, 0x395C, 0x395C}, {SEC_DEV_ALG_BITMAP_LOW, 0x314c, 0, GENMASK(31, 0), 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, {SEC_DEV_ALG_BITMAP_HIGH, 0x3150, 0, GENMASK(31, 0), 0x3FFF, 0x3FFF, 0x3FFF}, @@ -173,15 +167,22 @@ static const struct hisi_qm_cap_info sec_basic_info[] = { {SEC_CORE4_ALG_BITMAP_HIGH, 0x3170, 0, GENMASK(31, 0), 0x3FFF, 0x3FFF, 0x3FFF}, }; -static const struct sec_dev_alg sec_dev_algs[] = { { +static const u32 sec_pre_store_caps[] = { + SEC_DRV_ALG_BITMAP_LOW, + SEC_DRV_ALG_BITMAP_HIGH, + SEC_DEV_ALG_BITMAP_LOW, + SEC_DEV_ALG_BITMAP_HIGH, +}; + +static const struct qm_dev_alg sec_dev_algs[] = { { .alg_msk = SEC_CIPHER_BITMAP, - .algs = "cipher\n", + .alg = "cipher\n", }, { .alg_msk = SEC_DIGEST_BITMAP, - .algs = "digest\n", + .alg = "digest\n", }, { .alg_msk = SEC_AEAD_BITMAP, - .algs = "aead\n", + .alg = "aead\n", }, }; @@ -394,8 +395,8 @@ u64 sec_get_alg_bitmap(struct hisi_qm *qm, u32 high, u32 low) { u32 cap_val_h, cap_val_l; - cap_val_h = hisi_qm_get_hw_info(qm, sec_basic_info, high, qm->cap_ver); - cap_val_l = hisi_qm_get_hw_info(qm, sec_basic_info, low, qm->cap_ver); + cap_val_h = qm->cap_tables.dev_cap_table[high].cap_val; + cap_val_l = qm->cap_tables.dev_cap_table[low].cap_val; return ((u64)cap_val_h << SEC_ALG_BITMAP_SHIFT) | (u64)cap_val_l; } @@ -1077,37 +1078,31 @@ static int sec_pf_probe_init(struct sec_dev *sec) return ret; } -static int sec_set_qm_algs(struct hisi_qm *qm) +static int sec_pre_store_cap_reg(struct hisi_qm *qm) { - struct device *dev = &qm->pdev->dev; - char *algs, *ptr; - u64 alg_mask; - int i; - - if (!qm->use_sva) - return 0; + struct hisi_qm_cap_record *sec_cap; + struct pci_dev *pdev = qm->pdev; + size_t i, size; - algs = devm_kzalloc(dev, SEC_DEV_ALG_MAX_LEN * sizeof(char), GFP_KERNEL); - if (!algs) + size = ARRAY_SIZE(sec_pre_store_caps); + sec_cap = devm_kzalloc(&pdev->dev, sizeof(*sec_cap) * size, GFP_KERNEL); + if (!sec_cap) return -ENOMEM; - alg_mask = sec_get_alg_bitmap(qm, SEC_DEV_ALG_BITMAP_HIGH, SEC_DEV_ALG_BITMAP_LOW); - - for (i = 0; i < ARRAY_SIZE(sec_dev_algs); i++) - if (alg_mask & sec_dev_algs[i].alg_msk) - strcat(algs, sec_dev_algs[i].algs); - - ptr = strrchr(algs, '\n'); - if (ptr) - *ptr = '\0'; + for (i = 0; i < size; i++) { + sec_cap[i].type = sec_pre_store_caps[i]; + sec_cap[i].cap_val = hisi_qm_get_hw_info(qm, sec_basic_info, + sec_pre_store_caps[i], qm->cap_ver); + } - qm->uacce->algs = algs; + qm->cap_tables.dev_cap_table = sec_cap; return 0; } static int sec_qm_init(struct hisi_qm *qm, struct pci_dev *pdev) { + u64 alg_msk; int ret; qm->pdev = pdev; @@ -1142,7 +1137,16 @@ static int sec_qm_init(struct hisi_qm *qm, struct pci_dev *pdev) return ret; } - ret = sec_set_qm_algs(qm); + /* Fetch and save the value of capability registers */ + ret = sec_pre_store_cap_reg(qm); + if (ret) { + pci_err(qm->pdev, "Failed to pre-store capability registers!\n"); + hisi_qm_uninit(qm); + return ret; + } + + alg_msk = sec_get_alg_bitmap(qm, SEC_DEV_ALG_BITMAP_HIGH_IDX, SEC_DEV_ALG_BITMAP_LOW_IDX); + ret = hisi_qm_set_algs(qm, alg_msk, sec_dev_algs, ARRAY_SIZE(sec_dev_algs)); if (ret) { pci_err(qm->pdev, "Failed to set sec algs!\n"); hisi_qm_uninit(qm); diff --git a/drivers/crypto/hisilicon/sgl.c b/drivers/crypto/hisilicon/sgl.c index 3df7a256e9197a..0beca257c20b21 100644 --- a/drivers/crypto/hisilicon/sgl.c +++ b/drivers/crypto/hisilicon/sgl.c @@ -70,11 +70,11 @@ struct hisi_acc_sgl_pool *hisi_acc_create_sgl_pool(struct device *dev, HISI_ACC_SGL_ALIGN_SIZE); /* - * the pool may allocate a block of memory of size PAGE_SIZE * 2^MAX_ORDER, + * the pool may allocate a block of memory of size PAGE_SIZE * 2^MAX_PAGE_ORDER, * block size may exceed 2^31 on ia64, so the max of block size is 2^31 */ - block_size = 1 << (PAGE_SHIFT + MAX_ORDER < 32 ? - PAGE_SHIFT + MAX_ORDER : 31); + block_size = 1 << (PAGE_SHIFT + MAX_PAGE_ORDER < 32 ? + PAGE_SHIFT + MAX_PAGE_ORDER : 31); sgl_num_per_block = block_size / sgl_size; block_num = count / sgl_num_per_block; remain_sgl = count % sgl_num_per_block; @@ -121,10 +121,10 @@ struct hisi_acc_sgl_pool *hisi_acc_create_sgl_pool(struct device *dev, return pool; err_free_mem: - for (j = 0; j < i; j++) { + for (j = 0; j < i; j++) dma_free_coherent(dev, block_size, block[j].sgl, block[j].sgl_dma); - } + kfree_sensitive(pool); return ERR_PTR(-ENOMEM); } @@ -140,7 +140,7 @@ EXPORT_SYMBOL_GPL(hisi_acc_create_sgl_pool); void hisi_acc_free_sgl_pool(struct device *dev, struct hisi_acc_sgl_pool *pool) { struct mem_block *block; - int i; + u32 i; if (!dev || !pool) return; @@ -196,9 +196,10 @@ static void update_hw_sgl_sum_sge(struct hisi_acc_hw_sgl *hw_sgl, u16 sum) static void clear_hw_sgl_sge(struct hisi_acc_hw_sgl *hw_sgl) { struct acc_hw_sge *hw_sge = hw_sgl->sge_entries; + u16 entry_sum = le16_to_cpu(hw_sgl->entry_sum_in_sgl); int i; - for (i = 0; i < le16_to_cpu(hw_sgl->entry_sum_in_sgl); i++) { + for (i = 0; i < entry_sum; i++) { hw_sge[i].page_ctrl = NULL; hw_sge[i].buf = 0; hw_sge[i].len = 0; @@ -223,10 +224,11 @@ hisi_acc_sg_buf_map_to_hw_sgl(struct device *dev, u32 index, dma_addr_t *hw_sgl_dma) { struct hisi_acc_hw_sgl *curr_hw_sgl; + unsigned int i, sg_n_mapped; dma_addr_t curr_sgl_dma = 0; struct acc_hw_sge *curr_hw_sge; struct scatterlist *sg; - int i, sg_n, sg_n_mapped; + int sg_n; if (!dev || !sgl || !pool || !hw_sgl_dma) return ERR_PTR(-EINVAL); diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c index db4c964cd64952..479ba8a1d6b5d9 100644 --- a/drivers/crypto/hisilicon/zip/zip_main.c +++ b/drivers/crypto/hisilicon/zip/zip_main.c @@ -74,7 +74,6 @@ #define HZIP_AXI_SHUTDOWN_ENABLE BIT(14) #define HZIP_WR_PORT BIT(11) -#define HZIP_DEV_ALG_MAX_LEN 256 #define HZIP_ALG_ZLIB_BIT GENMASK(1, 0) #define HZIP_ALG_GZIP_BIT GENMASK(3, 2) #define HZIP_ALG_DEFLATE_BIT GENMASK(5, 4) @@ -107,6 +106,14 @@ #define HZIP_CLOCK_GATED_EN (HZIP_CORE_GATED_EN | \ HZIP_CORE_GATED_OOO_EN) +/* zip comp high performance */ +#define HZIP_HIGH_PERF_OFFSET 0x301208 + +enum { + HZIP_HIGH_COMP_RATE, + HZIP_HIGH_COMP_PERF, +}; + static const char hisi_zip_name[] = "hisi_zip"; static struct dentry *hzip_debugfs_root; @@ -120,23 +127,18 @@ struct zip_dfx_item { u32 offset; }; -struct zip_dev_alg { - u32 alg_msk; - const char *algs; -}; - -static const struct zip_dev_alg zip_dev_algs[] = { { +static const struct qm_dev_alg zip_dev_algs[] = { { .alg_msk = HZIP_ALG_ZLIB_BIT, - .algs = "zlib\n", + .alg = "zlib\n", }, { .alg_msk = HZIP_ALG_GZIP_BIT, - .algs = "gzip\n", + .alg = "gzip\n", }, { .alg_msk = HZIP_ALG_DEFLATE_BIT, - .algs = "deflate\n", + .alg = "deflate\n", }, { .alg_msk = HZIP_ALG_LZ77_BIT, - .algs = "lz77_zstd\n", + .alg = "lz77_zstd\n", }, }; @@ -247,6 +249,26 @@ static struct hisi_qm_cap_info zip_basic_cap_info[] = { {ZIP_CAP_MAX, 0x317c, 0, GENMASK(0, 0), 0x0, 0x0, 0x0} }; +enum zip_pre_store_cap_idx { + ZIP_CORE_NUM_CAP_IDX = 0x0, + ZIP_CLUSTER_COMP_NUM_CAP_IDX, + ZIP_CLUSTER_DECOMP_NUM_CAP_IDX, + ZIP_DECOMP_ENABLE_BITMAP_IDX, + ZIP_COMP_ENABLE_BITMAP_IDX, + ZIP_DRV_ALG_BITMAP_IDX, + ZIP_DEV_ALG_BITMAP_IDX, +}; + +static const u32 zip_pre_store_caps[] = { + ZIP_CORE_NUM_CAP, + ZIP_CLUSTER_COMP_NUM_CAP, + ZIP_CLUSTER_DECOMP_NUM_CAP, + ZIP_DECOMP_ENABLE_BITMAP, + ZIP_COMP_ENABLE_BITMAP, + ZIP_DRV_ALG_BITMAP, + ZIP_DEV_ALG_BITMAP, +}; + enum { HZIP_COMP_CORE0, HZIP_COMP_CORE1, @@ -270,28 +292,28 @@ static const u64 core_offsets[] = { }; static const struct debugfs_reg32 hzip_dfx_regs[] = { - {"HZIP_GET_BD_NUM ", 0x00ull}, - {"HZIP_GET_RIGHT_BD ", 0x04ull}, - {"HZIP_GET_ERROR_BD ", 0x08ull}, - {"HZIP_DONE_BD_NUM ", 0x0cull}, - {"HZIP_WORK_CYCLE ", 0x10ull}, - {"HZIP_IDLE_CYCLE ", 0x18ull}, - {"HZIP_MAX_DELAY ", 0x20ull}, - {"HZIP_MIN_DELAY ", 0x24ull}, - {"HZIP_AVG_DELAY ", 0x28ull}, - {"HZIP_MEM_VISIBLE_DATA ", 0x30ull}, - {"HZIP_MEM_VISIBLE_ADDR ", 0x34ull}, - {"HZIP_CONSUMED_BYTE ", 0x38ull}, - {"HZIP_PRODUCED_BYTE ", 0x40ull}, - {"HZIP_COMP_INF ", 0x70ull}, - {"HZIP_PRE_OUT ", 0x78ull}, - {"HZIP_BD_RD ", 0x7cull}, - {"HZIP_BD_WR ", 0x80ull}, - {"HZIP_GET_BD_AXI_ERR_NUM ", 0x84ull}, - {"HZIP_GET_BD_PARSE_ERR_NUM ", 0x88ull}, - {"HZIP_ADD_BD_AXI_ERR_NUM ", 0x8cull}, - {"HZIP_DECOMP_STF_RELOAD_CURR_ST ", 0x94ull}, - {"HZIP_DECOMP_LZ77_CURR_ST ", 0x9cull}, + {"HZIP_GET_BD_NUM ", 0x00}, + {"HZIP_GET_RIGHT_BD ", 0x04}, + {"HZIP_GET_ERROR_BD ", 0x08}, + {"HZIP_DONE_BD_NUM ", 0x0c}, + {"HZIP_WORK_CYCLE ", 0x10}, + {"HZIP_IDLE_CYCLE ", 0x18}, + {"HZIP_MAX_DELAY ", 0x20}, + {"HZIP_MIN_DELAY ", 0x24}, + {"HZIP_AVG_DELAY ", 0x28}, + {"HZIP_MEM_VISIBLE_DATA ", 0x30}, + {"HZIP_MEM_VISIBLE_ADDR ", 0x34}, + {"HZIP_CONSUMED_BYTE ", 0x38}, + {"HZIP_PRODUCED_BYTE ", 0x40}, + {"HZIP_COMP_INF ", 0x70}, + {"HZIP_PRE_OUT ", 0x78}, + {"HZIP_BD_RD ", 0x7c}, + {"HZIP_BD_WR ", 0x80}, + {"HZIP_GET_BD_AXI_ERR_NUM ", 0x84}, + {"HZIP_GET_BD_PARSE_ERR_NUM ", 0x88}, + {"HZIP_ADD_BD_AXI_ERR_NUM ", 0x8c}, + {"HZIP_DECOMP_STF_RELOAD_CURR_ST ", 0x94}, + {"HZIP_DECOMP_LZ77_CURR_ST ", 0x9c}, }; static const struct debugfs_reg32 hzip_com_dfx_regs[] = { @@ -303,11 +325,11 @@ static const struct debugfs_reg32 hzip_com_dfx_regs[] = { }; static const struct debugfs_reg32 hzip_dump_dfx_regs[] = { - {"HZIP_GET_BD_NUM ", 0x00ull}, - {"HZIP_GET_RIGHT_BD ", 0x04ull}, - {"HZIP_GET_ERROR_BD ", 0x08ull}, - {"HZIP_DONE_BD_NUM ", 0x0cull}, - {"HZIP_MAX_DELAY ", 0x20ull}, + {"HZIP_GET_BD_NUM ", 0x00}, + {"HZIP_GET_RIGHT_BD ", 0x04}, + {"HZIP_GET_ERROR_BD ", 0x08}, + {"HZIP_DONE_BD_NUM ", 0x0c}, + {"HZIP_MAX_DELAY ", 0x20}, }; /* define the ZIP's dfx regs region and region length */ @@ -352,6 +374,37 @@ static int hzip_diff_regs_show(struct seq_file *s, void *unused) return 0; } DEFINE_SHOW_ATTRIBUTE(hzip_diff_regs); + +static int perf_mode_set(const char *val, const struct kernel_param *kp) +{ + int ret; + u32 n; + + if (!val) + return -EINVAL; + + ret = kstrtou32(val, 10, &n); + if (ret != 0 || (n != HZIP_HIGH_COMP_PERF && + n != HZIP_HIGH_COMP_RATE)) + return -EINVAL; + + return param_set_int(val, kp); +} + +static const struct kernel_param_ops zip_com_perf_ops = { + .set = perf_mode_set, + .get = param_get_int, +}; + +/* + * perf_mode = 0 means enable high compression rate mode, + * perf_mode = 1 means enable high compression performance mode. + * These two modes only apply to the compression direction. + */ +static u32 perf_mode = HZIP_HIGH_COMP_RATE; +module_param_cb(perf_mode, &zip_com_perf_ops, &perf_mode, 0444); +MODULE_PARM_DESC(perf_mode, "ZIP high perf mode 0(default), 1(enable)"); + static const struct kernel_param_ops zip_uacce_mode_ops = { .set = uacce_mode_set, .get = param_get_int, @@ -410,40 +463,33 @@ bool hisi_zip_alg_support(struct hisi_qm *qm, u32 alg) { u32 cap_val; - cap_val = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_DRV_ALG_BITMAP, qm->cap_ver); + cap_val = qm->cap_tables.dev_cap_table[ZIP_DRV_ALG_BITMAP_IDX].cap_val; if ((alg & cap_val) == alg) return true; return false; } -static int hisi_zip_set_qm_algs(struct hisi_qm *qm) +static int hisi_zip_set_high_perf(struct hisi_qm *qm) { - struct device *dev = &qm->pdev->dev; - char *algs, *ptr; - u32 alg_mask; - int i; - - if (!qm->use_sva) - return 0; - - algs = devm_kzalloc(dev, HZIP_DEV_ALG_MAX_LEN * sizeof(char), GFP_KERNEL); - if (!algs) - return -ENOMEM; - - alg_mask = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_DEV_ALG_BITMAP, qm->cap_ver); - - for (i = 0; i < ARRAY_SIZE(zip_dev_algs); i++) - if (alg_mask & zip_dev_algs[i].alg_msk) - strcat(algs, zip_dev_algs[i].algs); - - ptr = strrchr(algs, '\n'); - if (ptr) - *ptr = '\0'; + u32 val; + int ret; - qm->uacce->algs = algs; + val = readl_relaxed(qm->io_base + HZIP_HIGH_PERF_OFFSET); + if (perf_mode == HZIP_HIGH_COMP_PERF) + val |= HZIP_HIGH_COMP_PERF; + else + val &= ~HZIP_HIGH_COMP_PERF; + + /* Set perf mode */ + writel(val, qm->io_base + HZIP_HIGH_PERF_OFFSET); + ret = readl_relaxed_poll_timeout(qm->io_base + HZIP_HIGH_PERF_OFFSET, + val, val == perf_mode, HZIP_DELAY_1_US, + HZIP_POLL_TIMEOUT_US); + if (ret) + pci_err(qm->pdev, "failed to set perf mode\n"); - return 0; + return ret; } static void hisi_zip_open_sva_prefetch(struct hisi_qm *qm) @@ -542,10 +588,8 @@ static int hisi_zip_set_user_domain_and_cache(struct hisi_qm *qm) } /* let's open all compression/decompression cores */ - dcomp_bm = hisi_qm_get_hw_info(qm, zip_basic_cap_info, - ZIP_DECOMP_ENABLE_BITMAP, qm->cap_ver); - comp_bm = hisi_qm_get_hw_info(qm, zip_basic_cap_info, - ZIP_COMP_ENABLE_BITMAP, qm->cap_ver); + dcomp_bm = qm->cap_tables.dev_cap_table[ZIP_DECOMP_ENABLE_BITMAP_IDX].cap_val; + comp_bm = qm->cap_tables.dev_cap_table[ZIP_COMP_ENABLE_BITMAP_IDX].cap_val; writel(HZIP_DECOMP_CHECK_ENABLE | dcomp_bm | comp_bm, base + HZIP_CLOCK_GATE_CTRL); /* enable sqc,cqc writeback */ @@ -772,9 +816,8 @@ static int hisi_zip_core_debug_init(struct hisi_qm *qm) char buf[HZIP_BUF_SIZE]; int i; - zip_core_num = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_CORE_NUM_CAP, qm->cap_ver); - zip_comp_core_num = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_CLUSTER_COMP_NUM_CAP, - qm->cap_ver); + zip_core_num = qm->cap_tables.dev_cap_table[ZIP_CORE_NUM_CAP_IDX].cap_val; + zip_comp_core_num = qm->cap_tables.dev_cap_table[ZIP_CLUSTER_COMP_NUM_CAP_IDX].cap_val; for (i = 0; i < zip_core_num; i++) { if (i < zip_comp_core_num) @@ -916,7 +959,7 @@ static int hisi_zip_show_last_regs_init(struct hisi_qm *qm) u32 zip_core_num; int i, j, idx; - zip_core_num = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_CORE_NUM_CAP, qm->cap_ver); + zip_core_num = qm->cap_tables.dev_cap_table[ZIP_CORE_NUM_CAP_IDX].cap_val; debug->last_words = kcalloc(core_dfx_regs_num * zip_core_num + com_dfx_regs_num, sizeof(unsigned int), GFP_KERNEL); @@ -972,9 +1015,9 @@ static void hisi_zip_show_last_dfx_regs(struct hisi_qm *qm) hzip_com_dfx_regs[i].name, debug->last_words[i], val); } - zip_core_num = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_CORE_NUM_CAP, qm->cap_ver); - zip_comp_core_num = hisi_qm_get_hw_info(qm, zip_basic_cap_info, ZIP_CLUSTER_COMP_NUM_CAP, - qm->cap_ver); + zip_core_num = qm->cap_tables.dev_cap_table[ZIP_CORE_NUM_CAP_IDX].cap_val; + zip_comp_core_num = qm->cap_tables.dev_cap_table[ZIP_CLUSTER_COMP_NUM_CAP_IDX].cap_val; + for (i = 0; i < zip_core_num; i++) { if (i < zip_comp_core_num) scnprintf(buf, sizeof(buf), "Comp_core-%d", i); @@ -1115,6 +1158,10 @@ static int hisi_zip_pf_probe_init(struct hisi_zip *hisi_zip) if (ret) return ret; + ret = hisi_zip_set_high_perf(qm); + if (ret) + return ret; + hisi_zip_open_sva_prefetch(qm); hisi_qm_dev_err_init(qm); hisi_zip_debug_regs_clear(qm); @@ -1126,8 +1173,31 @@ static int hisi_zip_pf_probe_init(struct hisi_zip *hisi_zip) return ret; } +static int zip_pre_store_cap_reg(struct hisi_qm *qm) +{ + struct hisi_qm_cap_record *zip_cap; + struct pci_dev *pdev = qm->pdev; + size_t i, size; + + size = ARRAY_SIZE(zip_pre_store_caps); + zip_cap = devm_kzalloc(&pdev->dev, sizeof(*zip_cap) * size, GFP_KERNEL); + if (!zip_cap) + return -ENOMEM; + + for (i = 0; i < size; i++) { + zip_cap[i].type = zip_pre_store_caps[i]; + zip_cap[i].cap_val = hisi_qm_get_hw_info(qm, zip_basic_cap_info, + zip_pre_store_caps[i], qm->cap_ver); + } + + qm->cap_tables.dev_cap_table = zip_cap; + + return 0; +} + static int hisi_zip_qm_init(struct hisi_qm *qm, struct pci_dev *pdev) { + u64 alg_msk; int ret; qm->pdev = pdev; @@ -1163,7 +1233,16 @@ static int hisi_zip_qm_init(struct hisi_qm *qm, struct pci_dev *pdev) return ret; } - ret = hisi_zip_set_qm_algs(qm); + /* Fetch and save the value of capability registers */ + ret = zip_pre_store_cap_reg(qm); + if (ret) { + pci_err(qm->pdev, "Failed to pre-store capability registers!\n"); + hisi_qm_uninit(qm); + return ret; + } + + alg_msk = qm->cap_tables.dev_cap_table[ZIP_DEV_ALG_BITMAP_IDX].cap_val; + ret = hisi_qm_set_algs(qm, alg_msk, zip_dev_algs, ARRAY_SIZE(zip_dev_algs)); if (ret) { pci_err(qm->pdev, "Failed to set zip algs!\n"); hisi_qm_uninit(qm); diff --git a/drivers/crypto/inside-secure/safexcel.c b/drivers/crypto/inside-secure/safexcel.c index 76da14af74b592..f5c1912aa56436 100644 --- a/drivers/crypto/inside-secure/safexcel.c +++ b/drivers/crypto/inside-secure/safexcel.c @@ -1191,8 +1191,6 @@ static struct safexcel_alg_template *safexcel_algs[] = { &safexcel_alg_cbc_des3_ede, &safexcel_alg_ecb_aes, &safexcel_alg_cbc_aes, - &safexcel_alg_cfb_aes, - &safexcel_alg_ofb_aes, &safexcel_alg_ctr_aes, &safexcel_alg_md5, &safexcel_alg_sha1, @@ -1231,8 +1229,6 @@ static struct safexcel_alg_template *safexcel_algs[] = { &safexcel_alg_hmac_sm3, &safexcel_alg_ecb_sm4, &safexcel_alg_cbc_sm4, - &safexcel_alg_ofb_sm4, - &safexcel_alg_cfb_sm4, &safexcel_alg_ctr_sm4, &safexcel_alg_authenc_hmac_sha1_cbc_sm4, &safexcel_alg_authenc_hmac_sm3_cbc_sm4, diff --git a/drivers/crypto/inside-secure/safexcel.h b/drivers/crypto/inside-secure/safexcel.h index 47ef6c7cd02cb1..d0059ce954dd8c 100644 --- a/drivers/crypto/inside-secure/safexcel.h +++ b/drivers/crypto/inside-secure/safexcel.h @@ -933,8 +933,6 @@ extern struct safexcel_alg_template safexcel_alg_ecb_des3_ede; extern struct safexcel_alg_template safexcel_alg_cbc_des3_ede; extern struct safexcel_alg_template safexcel_alg_ecb_aes; extern struct safexcel_alg_template safexcel_alg_cbc_aes; -extern struct safexcel_alg_template safexcel_alg_cfb_aes; -extern struct safexcel_alg_template safexcel_alg_ofb_aes; extern struct safexcel_alg_template safexcel_alg_ctr_aes; extern struct safexcel_alg_template safexcel_alg_md5; extern struct safexcel_alg_template safexcel_alg_sha1; @@ -973,8 +971,6 @@ extern struct safexcel_alg_template safexcel_alg_sm3; extern struct safexcel_alg_template safexcel_alg_hmac_sm3; extern struct safexcel_alg_template safexcel_alg_ecb_sm4; extern struct safexcel_alg_template safexcel_alg_cbc_sm4; -extern struct safexcel_alg_template safexcel_alg_ofb_sm4; -extern struct safexcel_alg_template safexcel_alg_cfb_sm4; extern struct safexcel_alg_template safexcel_alg_ctr_sm4; extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sha1_cbc_sm4; extern struct safexcel_alg_template safexcel_alg_authenc_hmac_sm3_cbc_sm4; diff --git a/drivers/crypto/inside-secure/safexcel_cipher.c b/drivers/crypto/inside-secure/safexcel_cipher.c index 272c28b5a0883e..42677f7458b787 100644 --- a/drivers/crypto/inside-secure/safexcel_cipher.c +++ b/drivers/crypto/inside-secure/safexcel_cipher.c @@ -742,9 +742,9 @@ static int safexcel_send_req(struct crypto_async_request *base, int ring, max(totlen_src, totlen_dst)); return -EINVAL; } - if (sreq->nr_src > 0) - dma_map_sg(priv->dev, src, sreq->nr_src, - DMA_BIDIRECTIONAL); + if (sreq->nr_src > 0 && + !dma_map_sg(priv->dev, src, sreq->nr_src, DMA_BIDIRECTIONAL)) + return -EIO; } else { if (unlikely(totlen_src && (sreq->nr_src <= 0))) { dev_err(priv->dev, "Source buffer not large enough (need %d bytes)!", @@ -752,8 +752,9 @@ static int safexcel_send_req(struct crypto_async_request *base, int ring, return -EINVAL; } - if (sreq->nr_src > 0) - dma_map_sg(priv->dev, src, sreq->nr_src, DMA_TO_DEVICE); + if (sreq->nr_src > 0 && + !dma_map_sg(priv->dev, src, sreq->nr_src, DMA_TO_DEVICE)) + return -EIO; if (unlikely(totlen_dst && (sreq->nr_dst <= 0))) { dev_err(priv->dev, "Dest buffer not large enough (need %d bytes)!", @@ -762,9 +763,11 @@ static int safexcel_send_req(struct crypto_async_request *base, int ring, goto unmap; } - if (sreq->nr_dst > 0) - dma_map_sg(priv->dev, dst, sreq->nr_dst, - DMA_FROM_DEVICE); + if (sreq->nr_dst > 0 && + !dma_map_sg(priv->dev, dst, sreq->nr_dst, DMA_FROM_DEVICE)) { + ret = -EIO; + goto unmap; + } } memcpy(ctx->base.ctxr->data, ctx->key, ctx->key_len); @@ -1349,82 +1352,6 @@ struct safexcel_alg_template safexcel_alg_cbc_aes = { }, }; -static int safexcel_skcipher_aes_cfb_cra_init(struct crypto_tfm *tfm) -{ - struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); - - safexcel_skcipher_cra_init(tfm); - ctx->alg = SAFEXCEL_AES; - ctx->blocksz = AES_BLOCK_SIZE; - ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CFB; - return 0; -} - -struct safexcel_alg_template safexcel_alg_cfb_aes = { - .type = SAFEXCEL_ALG_TYPE_SKCIPHER, - .algo_mask = SAFEXCEL_ALG_AES | SAFEXCEL_ALG_AES_XFB, - .alg.skcipher = { - .setkey = safexcel_skcipher_aes_setkey, - .encrypt = safexcel_encrypt, - .decrypt = safexcel_decrypt, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_BLOCK_SIZE, - .base = { - .cra_name = "cfb(aes)", - .cra_driver_name = "safexcel-cfb-aes", - .cra_priority = SAFEXCEL_CRA_PRIORITY, - .cra_flags = CRYPTO_ALG_ASYNC | - CRYPTO_ALG_ALLOCATES_MEMORY | - CRYPTO_ALG_KERN_DRIVER_ONLY, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct safexcel_cipher_ctx), - .cra_alignmask = 0, - .cra_init = safexcel_skcipher_aes_cfb_cra_init, - .cra_exit = safexcel_skcipher_cra_exit, - .cra_module = THIS_MODULE, - }, - }, -}; - -static int safexcel_skcipher_aes_ofb_cra_init(struct crypto_tfm *tfm) -{ - struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); - - safexcel_skcipher_cra_init(tfm); - ctx->alg = SAFEXCEL_AES; - ctx->blocksz = AES_BLOCK_SIZE; - ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_OFB; - return 0; -} - -struct safexcel_alg_template safexcel_alg_ofb_aes = { - .type = SAFEXCEL_ALG_TYPE_SKCIPHER, - .algo_mask = SAFEXCEL_ALG_AES | SAFEXCEL_ALG_AES_XFB, - .alg.skcipher = { - .setkey = safexcel_skcipher_aes_setkey, - .encrypt = safexcel_encrypt, - .decrypt = safexcel_decrypt, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_BLOCK_SIZE, - .base = { - .cra_name = "ofb(aes)", - .cra_driver_name = "safexcel-ofb-aes", - .cra_priority = SAFEXCEL_CRA_PRIORITY, - .cra_flags = CRYPTO_ALG_ASYNC | - CRYPTO_ALG_ALLOCATES_MEMORY | - CRYPTO_ALG_KERN_DRIVER_ONLY, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct safexcel_cipher_ctx), - .cra_alignmask = 0, - .cra_init = safexcel_skcipher_aes_ofb_cra_init, - .cra_exit = safexcel_skcipher_cra_exit, - .cra_module = THIS_MODULE, - }, - }, -}; - static int safexcel_skcipher_aesctr_setkey(struct crypto_skcipher *ctfm, const u8 *key, unsigned int len) { @@ -3183,82 +3110,6 @@ struct safexcel_alg_template safexcel_alg_cbc_sm4 = { }, }; -static int safexcel_skcipher_sm4_ofb_cra_init(struct crypto_tfm *tfm) -{ - struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); - - safexcel_skcipher_cra_init(tfm); - ctx->alg = SAFEXCEL_SM4; - ctx->blocksz = SM4_BLOCK_SIZE; - ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_OFB; - return 0; -} - -struct safexcel_alg_template safexcel_alg_ofb_sm4 = { - .type = SAFEXCEL_ALG_TYPE_SKCIPHER, - .algo_mask = SAFEXCEL_ALG_SM4 | SAFEXCEL_ALG_AES_XFB, - .alg.skcipher = { - .setkey = safexcel_skcipher_sm4_setkey, - .encrypt = safexcel_encrypt, - .decrypt = safexcel_decrypt, - .min_keysize = SM4_KEY_SIZE, - .max_keysize = SM4_KEY_SIZE, - .ivsize = SM4_BLOCK_SIZE, - .base = { - .cra_name = "ofb(sm4)", - .cra_driver_name = "safexcel-ofb-sm4", - .cra_priority = SAFEXCEL_CRA_PRIORITY, - .cra_flags = CRYPTO_ALG_ASYNC | - CRYPTO_ALG_ALLOCATES_MEMORY | - CRYPTO_ALG_KERN_DRIVER_ONLY, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct safexcel_cipher_ctx), - .cra_alignmask = 0, - .cra_init = safexcel_skcipher_sm4_ofb_cra_init, - .cra_exit = safexcel_skcipher_cra_exit, - .cra_module = THIS_MODULE, - }, - }, -}; - -static int safexcel_skcipher_sm4_cfb_cra_init(struct crypto_tfm *tfm) -{ - struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm); - - safexcel_skcipher_cra_init(tfm); - ctx->alg = SAFEXCEL_SM4; - ctx->blocksz = SM4_BLOCK_SIZE; - ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CFB; - return 0; -} - -struct safexcel_alg_template safexcel_alg_cfb_sm4 = { - .type = SAFEXCEL_ALG_TYPE_SKCIPHER, - .algo_mask = SAFEXCEL_ALG_SM4 | SAFEXCEL_ALG_AES_XFB, - .alg.skcipher = { - .setkey = safexcel_skcipher_sm4_setkey, - .encrypt = safexcel_encrypt, - .decrypt = safexcel_decrypt, - .min_keysize = SM4_KEY_SIZE, - .max_keysize = SM4_KEY_SIZE, - .ivsize = SM4_BLOCK_SIZE, - .base = { - .cra_name = "cfb(sm4)", - .cra_driver_name = "safexcel-cfb-sm4", - .cra_priority = SAFEXCEL_CRA_PRIORITY, - .cra_flags = CRYPTO_ALG_ASYNC | - CRYPTO_ALG_ALLOCATES_MEMORY | - CRYPTO_ALG_KERN_DRIVER_ONLY, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct safexcel_cipher_ctx), - .cra_alignmask = 0, - .cra_init = safexcel_skcipher_sm4_cfb_cra_init, - .cra_exit = safexcel_skcipher_cra_exit, - .cra_module = THIS_MODULE, - }, - }, -}; - static int safexcel_skcipher_sm4ctr_setkey(struct crypto_skcipher *ctfm, const u8 *key, unsigned int len) { diff --git a/drivers/crypto/intel/Kconfig b/drivers/crypto/intel/Kconfig index 3d90c87d409454..f38cd62a3f67a9 100644 --- a/drivers/crypto/intel/Kconfig +++ b/drivers/crypto/intel/Kconfig @@ -3,3 +3,4 @@ source "drivers/crypto/intel/keembay/Kconfig" source "drivers/crypto/intel/ixp4xx/Kconfig" source "drivers/crypto/intel/qat/Kconfig" +source "drivers/crypto/intel/iaa/Kconfig" diff --git a/drivers/crypto/intel/Makefile b/drivers/crypto/intel/Makefile index b3d0352ae188da..2f56f6d34cf072 100644 --- a/drivers/crypto/intel/Makefile +++ b/drivers/crypto/intel/Makefile @@ -3,3 +3,4 @@ obj-y += keembay/ obj-y += ixp4xx/ obj-$(CONFIG_CRYPTO_DEV_QAT) += qat/ +obj-$(CONFIG_CRYPTO_DEV_IAA_CRYPTO) += iaa/ diff --git a/drivers/crypto/intel/iaa/Kconfig b/drivers/crypto/intel/iaa/Kconfig new file mode 100644 index 00000000000000..d53f4b1d494f98 --- /dev/null +++ b/drivers/crypto/intel/iaa/Kconfig @@ -0,0 +1,19 @@ +config CRYPTO_DEV_IAA_CRYPTO + tristate "Support for Intel(R) IAA Compression Accelerator" + depends on CRYPTO_DEFLATE + depends on INTEL_IDXD + default n + help + This driver supports acceleration for compression and + decompression with the Intel Analytics Accelerator (IAA) + hardware using the cryptographic API. If you choose 'M' + here, the module will be called iaa_crypto. + +config CRYPTO_DEV_IAA_CRYPTO_STATS + bool "Enable Intel(R) IAA Compression Accelerator Statistics" + depends on CRYPTO_DEV_IAA_CRYPTO + default n + help + Enable statistics for the IAA compression accelerator. + These include per-device and per-workqueue statistics in + addition to global driver statistics. diff --git a/drivers/crypto/intel/iaa/Makefile b/drivers/crypto/intel/iaa/Makefile new file mode 100644 index 00000000000000..b64b208d234408 --- /dev/null +++ b/drivers/crypto/intel/iaa/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for IAA crypto device drivers +# + +ccflags-y += -I $(srctree)/drivers/dma/idxd -DDEFAULT_SYMBOL_NAMESPACE=IDXD + +obj-$(CONFIG_CRYPTO_DEV_IAA_CRYPTO) := iaa_crypto.o + +iaa_crypto-y := iaa_crypto_main.o iaa_crypto_comp_fixed.o + +iaa_crypto-$(CONFIG_CRYPTO_DEV_IAA_CRYPTO_STATS) += iaa_crypto_stats.o diff --git a/drivers/crypto/intel/iaa/iaa_crypto.h b/drivers/crypto/intel/iaa/iaa_crypto.h new file mode 100644 index 00000000000000..014420f7beb032 --- /dev/null +++ b/drivers/crypto/intel/iaa/iaa_crypto.h @@ -0,0 +1,173 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright(c) 2021 Intel Corporation. All rights rsvd. */ + +#ifndef __IAA_CRYPTO_H__ +#define __IAA_CRYPTO_H__ + +#include +#include +#include + +#define IDXD_SUBDRIVER_NAME "crypto" + +#define IAA_DECOMP_ENABLE BIT(0) +#define IAA_DECOMP_FLUSH_OUTPUT BIT(1) +#define IAA_DECOMP_CHECK_FOR_EOB BIT(2) +#define IAA_DECOMP_STOP_ON_EOB BIT(3) +#define IAA_DECOMP_SUPPRESS_OUTPUT BIT(9) + +#define IAA_COMP_FLUSH_OUTPUT BIT(1) +#define IAA_COMP_APPEND_EOB BIT(2) + +#define IAA_COMPLETION_TIMEOUT 1000000 + +#define IAA_ANALYTICS_ERROR 0x0a +#define IAA_ERROR_DECOMP_BUF_OVERFLOW 0x0b +#define IAA_ERROR_COMP_BUF_OVERFLOW 0x19 +#define IAA_ERROR_WATCHDOG_EXPIRED 0x24 + +#define IAA_COMP_MODES_MAX 2 + +#define FIXED_HDR 0x2 +#define FIXED_HDR_SIZE 3 + +#define IAA_COMP_FLAGS (IAA_COMP_FLUSH_OUTPUT | \ + IAA_COMP_APPEND_EOB) + +#define IAA_DECOMP_FLAGS (IAA_DECOMP_ENABLE | \ + IAA_DECOMP_FLUSH_OUTPUT | \ + IAA_DECOMP_CHECK_FOR_EOB | \ + IAA_DECOMP_STOP_ON_EOB) + +/* Representation of IAA workqueue */ +struct iaa_wq { + struct list_head list; + + struct idxd_wq *wq; + int ref; + bool remove; + + struct iaa_device *iaa_device; + + u64 comp_calls; + u64 comp_bytes; + u64 decomp_calls; + u64 decomp_bytes; +}; + +struct iaa_device_compression_mode { + const char *name; + + struct aecs_comp_table_record *aecs_comp_table; + struct aecs_decomp_table_record *aecs_decomp_table; + + dma_addr_t aecs_comp_table_dma_addr; + dma_addr_t aecs_decomp_table_dma_addr; +}; + +/* Representation of IAA device with wqs, populated by probe */ +struct iaa_device { + struct list_head list; + struct idxd_device *idxd; + + struct iaa_device_compression_mode *compression_modes[IAA_COMP_MODES_MAX]; + + int n_wq; + struct list_head wqs; + + u64 comp_calls; + u64 comp_bytes; + u64 decomp_calls; + u64 decomp_bytes; +}; + +struct wq_table_entry { + struct idxd_wq **wqs; + int max_wqs; + int n_wqs; + int cur_wq; +}; + +#define IAA_AECS_ALIGN 32 + +/* + * Analytics Engine Configuration and State (AECS) contains parameters and + * internal state of the analytics engine. + */ +struct aecs_comp_table_record { + u32 crc; + u32 xor_checksum; + u32 reserved0[5]; + u32 num_output_accum_bits; + u8 output_accum[256]; + u32 ll_sym[286]; + u32 reserved1; + u32 reserved2; + u32 d_sym[30]; + u32 reserved_padding[2]; +} __packed; + +/* AECS for decompress */ +struct aecs_decomp_table_record { + u32 crc; + u32 xor_checksum; + u32 low_filter_param; + u32 high_filter_param; + u32 output_mod_idx; + u32 drop_init_decomp_out_bytes; + u32 reserved[36]; + u32 output_accum_data[2]; + u32 out_bits_valid; + u32 bit_off_indexing; + u32 input_accum_data[64]; + u8 size_qw[32]; + u32 decomp_state[1220]; +} __packed; + +int iaa_aecs_init_fixed(void); +void iaa_aecs_cleanup_fixed(void); + +typedef int (*iaa_dev_comp_init_fn_t) (struct iaa_device_compression_mode *mode); +typedef int (*iaa_dev_comp_free_fn_t) (struct iaa_device_compression_mode *mode); + +struct iaa_compression_mode { + const char *name; + u32 *ll_table; + int ll_table_size; + u32 *d_table; + int d_table_size; + u32 *header_table; + int header_table_size; + u16 gen_decomp_table_flags; + iaa_dev_comp_init_fn_t init; + iaa_dev_comp_free_fn_t free; +}; + +int add_iaa_compression_mode(const char *name, + const u32 *ll_table, + int ll_table_size, + const u32 *d_table, + int d_table_size, + const u8 *header_table, + int header_table_size, + u16 gen_decomp_table_flags, + iaa_dev_comp_init_fn_t init, + iaa_dev_comp_free_fn_t free); + +void remove_iaa_compression_mode(const char *name); + +enum iaa_mode { + IAA_MODE_FIXED, +}; + +struct iaa_compression_ctx { + enum iaa_mode mode; + bool verify_compress; + bool async_mode; + bool use_irq; +}; + +extern struct list_head iaa_devices; +extern struct mutex iaa_devices_lock; + +#endif diff --git a/drivers/crypto/intel/iaa/iaa_crypto_comp_fixed.c b/drivers/crypto/intel/iaa/iaa_crypto_comp_fixed.c new file mode 100644 index 00000000000000..45cf5d74f0fb94 --- /dev/null +++ b/drivers/crypto/intel/iaa/iaa_crypto_comp_fixed.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2021 Intel Corporation. All rights rsvd. */ + +#include "idxd.h" +#include "iaa_crypto.h" + +/* + * Fixed Huffman tables the IAA hardware requires to implement RFC-1951. + */ +static const u32 fixed_ll_sym[286] = { + 0x40030, 0x40031, 0x40032, 0x40033, 0x40034, 0x40035, 0x40036, 0x40037, + 0x40038, 0x40039, 0x4003A, 0x4003B, 0x4003C, 0x4003D, 0x4003E, 0x4003F, + 0x40040, 0x40041, 0x40042, 0x40043, 0x40044, 0x40045, 0x40046, 0x40047, + 0x40048, 0x40049, 0x4004A, 0x4004B, 0x4004C, 0x4004D, 0x4004E, 0x4004F, + 0x40050, 0x40051, 0x40052, 0x40053, 0x40054, 0x40055, 0x40056, 0x40057, + 0x40058, 0x40059, 0x4005A, 0x4005B, 0x4005C, 0x4005D, 0x4005E, 0x4005F, + 0x40060, 0x40061, 0x40062, 0x40063, 0x40064, 0x40065, 0x40066, 0x40067, + 0x40068, 0x40069, 0x4006A, 0x4006B, 0x4006C, 0x4006D, 0x4006E, 0x4006F, + 0x40070, 0x40071, 0x40072, 0x40073, 0x40074, 0x40075, 0x40076, 0x40077, + 0x40078, 0x40079, 0x4007A, 0x4007B, 0x4007C, 0x4007D, 0x4007E, 0x4007F, + 0x40080, 0x40081, 0x40082, 0x40083, 0x40084, 0x40085, 0x40086, 0x40087, + 0x40088, 0x40089, 0x4008A, 0x4008B, 0x4008C, 0x4008D, 0x4008E, 0x4008F, + 0x40090, 0x40091, 0x40092, 0x40093, 0x40094, 0x40095, 0x40096, 0x40097, + 0x40098, 0x40099, 0x4009A, 0x4009B, 0x4009C, 0x4009D, 0x4009E, 0x4009F, + 0x400A0, 0x400A1, 0x400A2, 0x400A3, 0x400A4, 0x400A5, 0x400A6, 0x400A7, + 0x400A8, 0x400A9, 0x400AA, 0x400AB, 0x400AC, 0x400AD, 0x400AE, 0x400AF, + 0x400B0, 0x400B1, 0x400B2, 0x400B3, 0x400B4, 0x400B5, 0x400B6, 0x400B7, + 0x400B8, 0x400B9, 0x400BA, 0x400BB, 0x400BC, 0x400BD, 0x400BE, 0x400BF, + 0x48190, 0x48191, 0x48192, 0x48193, 0x48194, 0x48195, 0x48196, 0x48197, + 0x48198, 0x48199, 0x4819A, 0x4819B, 0x4819C, 0x4819D, 0x4819E, 0x4819F, + 0x481A0, 0x481A1, 0x481A2, 0x481A3, 0x481A4, 0x481A5, 0x481A6, 0x481A7, + 0x481A8, 0x481A9, 0x481AA, 0x481AB, 0x481AC, 0x481AD, 0x481AE, 0x481AF, + 0x481B0, 0x481B1, 0x481B2, 0x481B3, 0x481B4, 0x481B5, 0x481B6, 0x481B7, + 0x481B8, 0x481B9, 0x481BA, 0x481BB, 0x481BC, 0x481BD, 0x481BE, 0x481BF, + 0x481C0, 0x481C1, 0x481C2, 0x481C3, 0x481C4, 0x481C5, 0x481C6, 0x481C7, + 0x481C8, 0x481C9, 0x481CA, 0x481CB, 0x481CC, 0x481CD, 0x481CE, 0x481CF, + 0x481D0, 0x481D1, 0x481D2, 0x481D3, 0x481D4, 0x481D5, 0x481D6, 0x481D7, + 0x481D8, 0x481D9, 0x481DA, 0x481DB, 0x481DC, 0x481DD, 0x481DE, 0x481DF, + 0x481E0, 0x481E1, 0x481E2, 0x481E3, 0x481E4, 0x481E5, 0x481E6, 0x481E7, + 0x481E8, 0x481E9, 0x481EA, 0x481EB, 0x481EC, 0x481ED, 0x481EE, 0x481EF, + 0x481F0, 0x481F1, 0x481F2, 0x481F3, 0x481F4, 0x481F5, 0x481F6, 0x481F7, + 0x481F8, 0x481F9, 0x481FA, 0x481FB, 0x481FC, 0x481FD, 0x481FE, 0x481FF, + 0x38000, 0x38001, 0x38002, 0x38003, 0x38004, 0x38005, 0x38006, 0x38007, + 0x38008, 0x38009, 0x3800A, 0x3800B, 0x3800C, 0x3800D, 0x3800E, 0x3800F, + 0x38010, 0x38011, 0x38012, 0x38013, 0x38014, 0x38015, 0x38016, 0x38017, + 0x400C0, 0x400C1, 0x400C2, 0x400C3, 0x400C4, 0x400C5 +}; + +static const u32 fixed_d_sym[30] = { + 0x28000, 0x28001, 0x28002, 0x28003, 0x28004, 0x28005, 0x28006, 0x28007, + 0x28008, 0x28009, 0x2800A, 0x2800B, 0x2800C, 0x2800D, 0x2800E, 0x2800F, + 0x28010, 0x28011, 0x28012, 0x28013, 0x28014, 0x28015, 0x28016, 0x28017, + 0x28018, 0x28019, 0x2801A, 0x2801B, 0x2801C, 0x2801D +}; + +static int init_fixed_mode(struct iaa_device_compression_mode *mode) +{ + struct aecs_comp_table_record *comp_table = mode->aecs_comp_table; + u32 bfinal = 1; + u32 offset; + + /* Configure aecs table using fixed Huffman table */ + comp_table->crc = 0; + comp_table->xor_checksum = 0; + offset = comp_table->num_output_accum_bits / 8; + comp_table->output_accum[offset] = FIXED_HDR | bfinal; + comp_table->num_output_accum_bits = FIXED_HDR_SIZE; + + return 0; +} + +int iaa_aecs_init_fixed(void) +{ + int ret; + + ret = add_iaa_compression_mode("fixed", + fixed_ll_sym, + sizeof(fixed_ll_sym), + fixed_d_sym, + sizeof(fixed_d_sym), + NULL, 0, 0, + init_fixed_mode, NULL); + if (!ret) + pr_debug("IAA fixed compression mode initialized\n"); + + return ret; +} + +void iaa_aecs_cleanup_fixed(void) +{ + remove_iaa_compression_mode("fixed"); +} diff --git a/drivers/crypto/intel/iaa/iaa_crypto_main.c b/drivers/crypto/intel/iaa/iaa_crypto_main.c new file mode 100644 index 00000000000000..dfd3baf0a8d873 --- /dev/null +++ b/drivers/crypto/intel/iaa/iaa_crypto_main.c @@ -0,0 +1,2193 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2021 Intel Corporation. All rights rsvd. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "idxd.h" +#include "iaa_crypto.h" +#include "iaa_crypto_stats.h" + +#ifdef pr_fmt +#undef pr_fmt +#endif + +#define pr_fmt(fmt) "idxd: " IDXD_SUBDRIVER_NAME ": " fmt + +#define IAA_ALG_PRIORITY 300 + +/* number of iaa instances probed */ +static unsigned int nr_iaa; +static unsigned int nr_cpus; +static unsigned int nr_nodes; +static unsigned int nr_cpus_per_node; + +/* Number of physical cpus sharing each iaa instance */ +static unsigned int cpus_per_iaa; + +static struct crypto_comp *deflate_generic_tfm; + +/* Per-cpu lookup table for balanced wqs */ +static struct wq_table_entry __percpu *wq_table; + +static struct idxd_wq *wq_table_next_wq(int cpu) +{ + struct wq_table_entry *entry = per_cpu_ptr(wq_table, cpu); + + if (++entry->cur_wq >= entry->n_wqs) + entry->cur_wq = 0; + + if (!entry->wqs[entry->cur_wq]) + return NULL; + + pr_debug("%s: returning wq at idx %d (iaa wq %d.%d) from cpu %d\n", __func__, + entry->cur_wq, entry->wqs[entry->cur_wq]->idxd->id, + entry->wqs[entry->cur_wq]->id, cpu); + + return entry->wqs[entry->cur_wq]; +} + +static void wq_table_add(int cpu, struct idxd_wq *wq) +{ + struct wq_table_entry *entry = per_cpu_ptr(wq_table, cpu); + + if (WARN_ON(entry->n_wqs == entry->max_wqs)) + return; + + entry->wqs[entry->n_wqs++] = wq; + + pr_debug("%s: added iaa wq %d.%d to idx %d of cpu %d\n", __func__, + entry->wqs[entry->n_wqs - 1]->idxd->id, + entry->wqs[entry->n_wqs - 1]->id, entry->n_wqs - 1, cpu); +} + +static void wq_table_free_entry(int cpu) +{ + struct wq_table_entry *entry = per_cpu_ptr(wq_table, cpu); + + kfree(entry->wqs); + memset(entry, 0, sizeof(*entry)); +} + +static void wq_table_clear_entry(int cpu) +{ + struct wq_table_entry *entry = per_cpu_ptr(wq_table, cpu); + + entry->n_wqs = 0; + entry->cur_wq = 0; + memset(entry->wqs, 0, entry->max_wqs * sizeof(struct idxd_wq *)); +} + +LIST_HEAD(iaa_devices); +DEFINE_MUTEX(iaa_devices_lock); + +/* If enabled, IAA hw crypto algos are registered, unavailable otherwise */ +static bool iaa_crypto_enabled; +static bool iaa_crypto_registered; + +/* Verify results of IAA compress or not */ +static bool iaa_verify_compress = true; + +static ssize_t verify_compress_show(struct device_driver *driver, char *buf) +{ + return sprintf(buf, "%d\n", iaa_verify_compress); +} + +static ssize_t verify_compress_store(struct device_driver *driver, + const char *buf, size_t count) +{ + int ret = -EBUSY; + + mutex_lock(&iaa_devices_lock); + + if (iaa_crypto_enabled) + goto out; + + ret = kstrtobool(buf, &iaa_verify_compress); + if (ret) + goto out; + + ret = count; +out: + mutex_unlock(&iaa_devices_lock); + + return ret; +} +static DRIVER_ATTR_RW(verify_compress); + +/* + * The iaa crypto driver supports three 'sync' methods determining how + * compressions and decompressions are performed: + * + * - sync: the compression or decompression completes before + * returning. This is the mode used by the async crypto + * interface when the sync mode is set to 'sync' and by + * the sync crypto interface regardless of setting. + * + * - async: the compression or decompression is submitted and returns + * immediately. Completion interrupts are not used so + * the caller is responsible for polling the descriptor + * for completion. This mode is applicable to only the + * async crypto interface and is ignored for anything + * else. + * + * - async_irq: the compression or decompression is submitted and + * returns immediately. Completion interrupts are + * enabled so the caller can wait for the completion and + * yield to other threads. When the compression or + * decompression completes, the completion is signaled + * and the caller awakened. This mode is applicable to + * only the async crypto interface and is ignored for + * anything else. + * + * These modes can be set using the iaa_crypto sync_mode driver + * attribute. + */ + +/* Use async mode */ +static bool async_mode; +/* Use interrupts */ +static bool use_irq; + +/** + * set_iaa_sync_mode - Set IAA sync mode + * @name: The name of the sync mode + * + * Make the IAA sync mode named @name the current sync mode used by + * compression/decompression. + */ + +static int set_iaa_sync_mode(const char *name) +{ + int ret = 0; + + if (sysfs_streq(name, "sync")) { + async_mode = false; + use_irq = false; + } else if (sysfs_streq(name, "async")) { + async_mode = true; + use_irq = false; + } else if (sysfs_streq(name, "async_irq")) { + async_mode = true; + use_irq = true; + } else { + ret = -EINVAL; + } + + return ret; +} + +static ssize_t sync_mode_show(struct device_driver *driver, char *buf) +{ + int ret = 0; + + if (!async_mode && !use_irq) + ret = sprintf(buf, "%s\n", "sync"); + else if (async_mode && !use_irq) + ret = sprintf(buf, "%s\n", "async"); + else if (async_mode && use_irq) + ret = sprintf(buf, "%s\n", "async_irq"); + + return ret; +} + +static ssize_t sync_mode_store(struct device_driver *driver, + const char *buf, size_t count) +{ + int ret = -EBUSY; + + mutex_lock(&iaa_devices_lock); + + if (iaa_crypto_enabled) + goto out; + + ret = set_iaa_sync_mode(buf); + if (ret == 0) + ret = count; +out: + mutex_unlock(&iaa_devices_lock); + + return ret; +} +static DRIVER_ATTR_RW(sync_mode); + +static struct iaa_compression_mode *iaa_compression_modes[IAA_COMP_MODES_MAX]; + +static int find_empty_iaa_compression_mode(void) +{ + int i = -EINVAL; + + for (i = 0; i < IAA_COMP_MODES_MAX; i++) { + if (iaa_compression_modes[i]) + continue; + break; + } + + return i; +} + +static struct iaa_compression_mode *find_iaa_compression_mode(const char *name, int *idx) +{ + struct iaa_compression_mode *mode; + int i; + + for (i = 0; i < IAA_COMP_MODES_MAX; i++) { + mode = iaa_compression_modes[i]; + if (!mode) + continue; + + if (!strcmp(mode->name, name)) { + *idx = i; + return iaa_compression_modes[i]; + } + } + + return NULL; +} + +static void free_iaa_compression_mode(struct iaa_compression_mode *mode) +{ + kfree(mode->name); + kfree(mode->ll_table); + kfree(mode->d_table); + kfree(mode->header_table); + + kfree(mode); +} + +/* + * IAA Compression modes are defined by an ll_table, a d_table, and an + * optional header_table. These tables are typically generated and + * captured using statistics collected from running actual + * compress/decompress workloads. + * + * A module or other kernel code can add and remove compression modes + * with a given name using the exported @add_iaa_compression_mode() + * and @remove_iaa_compression_mode functions. + * + * When a new compression mode is added, the tables are saved in a + * global compression mode list. When IAA devices are added, a + * per-IAA device dma mapping is created for each IAA device, for each + * compression mode. These are the tables used to do the actual + * compression/deccompression and are unmapped if/when the devices are + * removed. Currently, compression modes must be added before any + * device is added, and removed after all devices have been removed. + */ + +/** + * remove_iaa_compression_mode - Remove an IAA compression mode + * @name: The name the compression mode will be known as + * + * Remove the IAA compression mode named @name. + */ +void remove_iaa_compression_mode(const char *name) +{ + struct iaa_compression_mode *mode; + int idx; + + mutex_lock(&iaa_devices_lock); + + if (!list_empty(&iaa_devices)) + goto out; + + mode = find_iaa_compression_mode(name, &idx); + if (mode) { + free_iaa_compression_mode(mode); + iaa_compression_modes[idx] = NULL; + } +out: + mutex_unlock(&iaa_devices_lock); +} +EXPORT_SYMBOL_GPL(remove_iaa_compression_mode); + +/** + * add_iaa_compression_mode - Add an IAA compression mode + * @name: The name the compression mode will be known as + * @ll_table: The ll table + * @ll_table_size: The ll table size in bytes + * @d_table: The d table + * @d_table_size: The d table size in bytes + * @header_table: Optional header table + * @header_table_size: Optional header table size in bytes + * @gen_decomp_table_flags: Otional flags used to generate the decomp table + * @init: Optional callback function to init the compression mode data + * @free: Optional callback function to free the compression mode data + * + * Add a new IAA compression mode named @name. + * + * Returns 0 if successful, errcode otherwise. + */ +int add_iaa_compression_mode(const char *name, + const u32 *ll_table, + int ll_table_size, + const u32 *d_table, + int d_table_size, + const u8 *header_table, + int header_table_size, + u16 gen_decomp_table_flags, + iaa_dev_comp_init_fn_t init, + iaa_dev_comp_free_fn_t free) +{ + struct iaa_compression_mode *mode; + int idx, ret = -ENOMEM; + + mutex_lock(&iaa_devices_lock); + + if (!list_empty(&iaa_devices)) { + ret = -EBUSY; + goto out; + } + + mode = kzalloc(sizeof(*mode), GFP_KERNEL); + if (!mode) + goto out; + + mode->name = kstrdup(name, GFP_KERNEL); + if (!mode->name) + goto free; + + if (ll_table) { + mode->ll_table = kzalloc(ll_table_size, GFP_KERNEL); + if (!mode->ll_table) + goto free; + memcpy(mode->ll_table, ll_table, ll_table_size); + mode->ll_table_size = ll_table_size; + } + + if (d_table) { + mode->d_table = kzalloc(d_table_size, GFP_KERNEL); + if (!mode->d_table) + goto free; + memcpy(mode->d_table, d_table, d_table_size); + mode->d_table_size = d_table_size; + } + + if (header_table) { + mode->header_table = kzalloc(header_table_size, GFP_KERNEL); + if (!mode->header_table) + goto free; + memcpy(mode->header_table, header_table, header_table_size); + mode->header_table_size = header_table_size; + } + + mode->gen_decomp_table_flags = gen_decomp_table_flags; + + mode->init = init; + mode->free = free; + + idx = find_empty_iaa_compression_mode(); + if (idx < 0) + goto free; + + pr_debug("IAA compression mode %s added at idx %d\n", + mode->name, idx); + + iaa_compression_modes[idx] = mode; + + ret = 0; +out: + mutex_unlock(&iaa_devices_lock); + + return ret; +free: + free_iaa_compression_mode(mode); + goto out; +} +EXPORT_SYMBOL_GPL(add_iaa_compression_mode); + +static struct iaa_device_compression_mode * +get_iaa_device_compression_mode(struct iaa_device *iaa_device, int idx) +{ + return iaa_device->compression_modes[idx]; +} + +static void free_device_compression_mode(struct iaa_device *iaa_device, + struct iaa_device_compression_mode *device_mode) +{ + size_t size = sizeof(struct aecs_comp_table_record) + IAA_AECS_ALIGN; + struct device *dev = &iaa_device->idxd->pdev->dev; + + kfree(device_mode->name); + + if (device_mode->aecs_comp_table) + dma_free_coherent(dev, size, device_mode->aecs_comp_table, + device_mode->aecs_comp_table_dma_addr); + if (device_mode->aecs_decomp_table) + dma_free_coherent(dev, size, device_mode->aecs_decomp_table, + device_mode->aecs_decomp_table_dma_addr); + + kfree(device_mode); +} + +#define IDXD_OP_FLAG_AECS_RW_TGLS 0x400000 +#define IAX_AECS_DEFAULT_FLAG (IDXD_OP_FLAG_CRAV | IDXD_OP_FLAG_RCR | IDXD_OP_FLAG_CC) +#define IAX_AECS_COMPRESS_FLAG (IAX_AECS_DEFAULT_FLAG | IDXD_OP_FLAG_RD_SRC2_AECS) +#define IAX_AECS_DECOMPRESS_FLAG (IAX_AECS_DEFAULT_FLAG | IDXD_OP_FLAG_RD_SRC2_AECS) +#define IAX_AECS_GEN_FLAG (IAX_AECS_DEFAULT_FLAG | \ + IDXD_OP_FLAG_WR_SRC2_AECS_COMP | \ + IDXD_OP_FLAG_AECS_RW_TGLS) + +static int check_completion(struct device *dev, + struct iax_completion_record *comp, + bool compress, + bool only_once); + +static int decompress_header(struct iaa_device_compression_mode *device_mode, + struct iaa_compression_mode *mode, + struct idxd_wq *wq) +{ + dma_addr_t src_addr, src2_addr; + struct idxd_desc *idxd_desc; + struct iax_hw_desc *desc; + struct device *dev; + int ret = 0; + + idxd_desc = idxd_alloc_desc(wq, IDXD_OP_BLOCK); + if (IS_ERR(idxd_desc)) + return PTR_ERR(idxd_desc); + + desc = idxd_desc->iax_hw; + + dev = &wq->idxd->pdev->dev; + + src_addr = dma_map_single(dev, (void *)mode->header_table, + mode->header_table_size, DMA_TO_DEVICE); + dev_dbg(dev, "%s: mode->name %s, src_addr %llx, dev %p, src %p, slen %d\n", + __func__, mode->name, src_addr, dev, + mode->header_table, mode->header_table_size); + if (unlikely(dma_mapping_error(dev, src_addr))) { + dev_dbg(dev, "dma_map_single err, exiting\n"); + ret = -ENOMEM; + return ret; + } + + desc->flags = IAX_AECS_GEN_FLAG; + desc->opcode = IAX_OPCODE_DECOMPRESS; + + desc->src1_addr = (u64)src_addr; + desc->src1_size = mode->header_table_size; + + src2_addr = device_mode->aecs_decomp_table_dma_addr; + desc->src2_addr = (u64)src2_addr; + desc->src2_size = 1088; + dev_dbg(dev, "%s: mode->name %s, src2_addr %llx, dev %p, src2_size %d\n", + __func__, mode->name, desc->src2_addr, dev, desc->src2_size); + desc->max_dst_size = 0; // suppressed output + + desc->decompr_flags = mode->gen_decomp_table_flags; + + desc->priv = 0; + + desc->completion_addr = idxd_desc->compl_dma; + + ret = idxd_submit_desc(wq, idxd_desc); + if (ret) { + pr_err("%s: submit_desc failed ret=0x%x\n", __func__, ret); + goto out; + } + + ret = check_completion(dev, idxd_desc->iax_completion, false, false); + if (ret) + dev_dbg(dev, "%s: mode->name %s check_completion failed ret=%d\n", + __func__, mode->name, ret); + else + dev_dbg(dev, "%s: mode->name %s succeeded\n", __func__, + mode->name); +out: + dma_unmap_single(dev, src_addr, 1088, DMA_TO_DEVICE); + + return ret; +} + +static int init_device_compression_mode(struct iaa_device *iaa_device, + struct iaa_compression_mode *mode, + int idx, struct idxd_wq *wq) +{ + size_t size = sizeof(struct aecs_comp_table_record) + IAA_AECS_ALIGN; + struct device *dev = &iaa_device->idxd->pdev->dev; + struct iaa_device_compression_mode *device_mode; + int ret = -ENOMEM; + + device_mode = kzalloc(sizeof(*device_mode), GFP_KERNEL); + if (!device_mode) + return -ENOMEM; + + device_mode->name = kstrdup(mode->name, GFP_KERNEL); + if (!device_mode->name) + goto free; + + device_mode->aecs_comp_table = dma_alloc_coherent(dev, size, + &device_mode->aecs_comp_table_dma_addr, GFP_KERNEL); + if (!device_mode->aecs_comp_table) + goto free; + + device_mode->aecs_decomp_table = dma_alloc_coherent(dev, size, + &device_mode->aecs_decomp_table_dma_addr, GFP_KERNEL); + if (!device_mode->aecs_decomp_table) + goto free; + + /* Add Huffman table to aecs */ + memset(device_mode->aecs_comp_table, 0, sizeof(*device_mode->aecs_comp_table)); + memcpy(device_mode->aecs_comp_table->ll_sym, mode->ll_table, mode->ll_table_size); + memcpy(device_mode->aecs_comp_table->d_sym, mode->d_table, mode->d_table_size); + + if (mode->header_table) { + ret = decompress_header(device_mode, mode, wq); + if (ret) { + pr_debug("iaa header decompression failed: ret=%d\n", ret); + goto free; + } + } + + if (mode->init) { + ret = mode->init(device_mode); + if (ret) + goto free; + } + + /* mode index should match iaa_compression_modes idx */ + iaa_device->compression_modes[idx] = device_mode; + + pr_debug("IAA %s compression mode initialized for iaa device %d\n", + mode->name, iaa_device->idxd->id); + + ret = 0; +out: + return ret; +free: + pr_debug("IAA %s compression mode initialization failed for iaa device %d\n", + mode->name, iaa_device->idxd->id); + + free_device_compression_mode(iaa_device, device_mode); + goto out; +} + +static int init_device_compression_modes(struct iaa_device *iaa_device, + struct idxd_wq *wq) +{ + struct iaa_compression_mode *mode; + int i, ret = 0; + + for (i = 0; i < IAA_COMP_MODES_MAX; i++) { + mode = iaa_compression_modes[i]; + if (!mode) + continue; + + ret = init_device_compression_mode(iaa_device, mode, i, wq); + if (ret) + break; + } + + return ret; +} + +static void remove_device_compression_modes(struct iaa_device *iaa_device) +{ + struct iaa_device_compression_mode *device_mode; + int i; + + for (i = 0; i < IAA_COMP_MODES_MAX; i++) { + device_mode = iaa_device->compression_modes[i]; + if (!device_mode) + continue; + + free_device_compression_mode(iaa_device, device_mode); + iaa_device->compression_modes[i] = NULL; + if (iaa_compression_modes[i]->free) + iaa_compression_modes[i]->free(device_mode); + } +} + +static struct iaa_device *iaa_device_alloc(void) +{ + struct iaa_device *iaa_device; + + iaa_device = kzalloc(sizeof(*iaa_device), GFP_KERNEL); + if (!iaa_device) + return NULL; + + INIT_LIST_HEAD(&iaa_device->wqs); + + return iaa_device; +} + +static bool iaa_has_wq(struct iaa_device *iaa_device, struct idxd_wq *wq) +{ + struct iaa_wq *iaa_wq; + + list_for_each_entry(iaa_wq, &iaa_device->wqs, list) { + if (iaa_wq->wq == wq) + return true; + } + + return false; +} + +static struct iaa_device *add_iaa_device(struct idxd_device *idxd) +{ + struct iaa_device *iaa_device; + + iaa_device = iaa_device_alloc(); + if (!iaa_device) + return NULL; + + iaa_device->idxd = idxd; + + list_add_tail(&iaa_device->list, &iaa_devices); + + nr_iaa++; + + return iaa_device; +} + +static int init_iaa_device(struct iaa_device *iaa_device, struct iaa_wq *iaa_wq) +{ + int ret = 0; + + ret = init_device_compression_modes(iaa_device, iaa_wq->wq); + if (ret) + return ret; + + return ret; +} + +static void del_iaa_device(struct iaa_device *iaa_device) +{ + list_del(&iaa_device->list); + + nr_iaa--; +} + +static int add_iaa_wq(struct iaa_device *iaa_device, struct idxd_wq *wq, + struct iaa_wq **new_wq) +{ + struct idxd_device *idxd = iaa_device->idxd; + struct pci_dev *pdev = idxd->pdev; + struct device *dev = &pdev->dev; + struct iaa_wq *iaa_wq; + + iaa_wq = kzalloc(sizeof(*iaa_wq), GFP_KERNEL); + if (!iaa_wq) + return -ENOMEM; + + iaa_wq->wq = wq; + iaa_wq->iaa_device = iaa_device; + idxd_wq_set_private(wq, iaa_wq); + + list_add_tail(&iaa_wq->list, &iaa_device->wqs); + + iaa_device->n_wq++; + + if (new_wq) + *new_wq = iaa_wq; + + dev_dbg(dev, "added wq %d to iaa device %d, n_wq %d\n", + wq->id, iaa_device->idxd->id, iaa_device->n_wq); + + return 0; +} + +static void del_iaa_wq(struct iaa_device *iaa_device, struct idxd_wq *wq) +{ + struct idxd_device *idxd = iaa_device->idxd; + struct pci_dev *pdev = idxd->pdev; + struct device *dev = &pdev->dev; + struct iaa_wq *iaa_wq; + + list_for_each_entry(iaa_wq, &iaa_device->wqs, list) { + if (iaa_wq->wq == wq) { + list_del(&iaa_wq->list); + iaa_device->n_wq--; + + dev_dbg(dev, "removed wq %d from iaa_device %d, n_wq %d, nr_iaa %d\n", + wq->id, iaa_device->idxd->id, + iaa_device->n_wq, nr_iaa); + + if (iaa_device->n_wq == 0) + del_iaa_device(iaa_device); + break; + } + } +} + +static void clear_wq_table(void) +{ + int cpu; + + for (cpu = 0; cpu < nr_cpus; cpu++) + wq_table_clear_entry(cpu); + + pr_debug("cleared wq table\n"); +} + +static void free_iaa_device(struct iaa_device *iaa_device) +{ + if (!iaa_device) + return; + + remove_device_compression_modes(iaa_device); + kfree(iaa_device); +} + +static void __free_iaa_wq(struct iaa_wq *iaa_wq) +{ + struct iaa_device *iaa_device; + + if (!iaa_wq) + return; + + iaa_device = iaa_wq->iaa_device; + if (iaa_device->n_wq == 0) + free_iaa_device(iaa_wq->iaa_device); +} + +static void free_iaa_wq(struct iaa_wq *iaa_wq) +{ + struct idxd_wq *wq; + + __free_iaa_wq(iaa_wq); + + wq = iaa_wq->wq; + + kfree(iaa_wq); + idxd_wq_set_private(wq, NULL); +} + +static int iaa_wq_get(struct idxd_wq *wq) +{ + struct idxd_device *idxd = wq->idxd; + struct iaa_wq *iaa_wq; + int ret = 0; + + spin_lock(&idxd->dev_lock); + iaa_wq = idxd_wq_get_private(wq); + if (iaa_wq && !iaa_wq->remove) { + iaa_wq->ref++; + idxd_wq_get(wq); + } else { + ret = -ENODEV; + } + spin_unlock(&idxd->dev_lock); + + return ret; +} + +static int iaa_wq_put(struct idxd_wq *wq) +{ + struct idxd_device *idxd = wq->idxd; + struct iaa_wq *iaa_wq; + bool free = false; + int ret = 0; + + spin_lock(&idxd->dev_lock); + iaa_wq = idxd_wq_get_private(wq); + if (iaa_wq) { + iaa_wq->ref--; + if (iaa_wq->ref == 0 && iaa_wq->remove) { + idxd_wq_set_private(wq, NULL); + free = true; + } + idxd_wq_put(wq); + } else { + ret = -ENODEV; + } + spin_unlock(&idxd->dev_lock); + if (free) { + __free_iaa_wq(iaa_wq); + kfree(iaa_wq); + } + + return ret; +} + +static void free_wq_table(void) +{ + int cpu; + + for (cpu = 0; cpu < nr_cpus; cpu++) + wq_table_free_entry(cpu); + + free_percpu(wq_table); + + pr_debug("freed wq table\n"); +} + +static int alloc_wq_table(int max_wqs) +{ + struct wq_table_entry *entry; + int cpu; + + wq_table = alloc_percpu(struct wq_table_entry); + if (!wq_table) + return -ENOMEM; + + for (cpu = 0; cpu < nr_cpus; cpu++) { + entry = per_cpu_ptr(wq_table, cpu); + entry->wqs = kcalloc(max_wqs, sizeof(struct wq *), GFP_KERNEL); + if (!entry->wqs) { + free_wq_table(); + return -ENOMEM; + } + + entry->max_wqs = max_wqs; + } + + pr_debug("initialized wq table\n"); + + return 0; +} + +static int save_iaa_wq(struct idxd_wq *wq) +{ + struct iaa_device *iaa_device, *found = NULL; + struct idxd_device *idxd; + struct pci_dev *pdev; + struct device *dev; + int ret = 0; + + list_for_each_entry(iaa_device, &iaa_devices, list) { + if (iaa_device->idxd == wq->idxd) { + idxd = iaa_device->idxd; + pdev = idxd->pdev; + dev = &pdev->dev; + /* + * Check to see that we don't already have this wq. + * Shouldn't happen but we don't control probing. + */ + if (iaa_has_wq(iaa_device, wq)) { + dev_dbg(dev, "same wq probed multiple times for iaa_device %p\n", + iaa_device); + goto out; + } + + found = iaa_device; + + ret = add_iaa_wq(iaa_device, wq, NULL); + if (ret) + goto out; + + break; + } + } + + if (!found) { + struct iaa_device *new_device; + struct iaa_wq *new_wq; + + new_device = add_iaa_device(wq->idxd); + if (!new_device) { + ret = -ENOMEM; + goto out; + } + + ret = add_iaa_wq(new_device, wq, &new_wq); + if (ret) { + del_iaa_device(new_device); + free_iaa_device(new_device); + goto out; + } + + ret = init_iaa_device(new_device, new_wq); + if (ret) { + del_iaa_wq(new_device, new_wq->wq); + del_iaa_device(new_device); + free_iaa_wq(new_wq); + goto out; + } + } + + if (WARN_ON(nr_iaa == 0)) + return -EINVAL; + + cpus_per_iaa = (nr_nodes * nr_cpus_per_node) / nr_iaa; +out: + return 0; +} + +static void remove_iaa_wq(struct idxd_wq *wq) +{ + struct iaa_device *iaa_device; + + list_for_each_entry(iaa_device, &iaa_devices, list) { + if (iaa_has_wq(iaa_device, wq)) { + del_iaa_wq(iaa_device, wq); + break; + } + } + + if (nr_iaa) + cpus_per_iaa = (nr_nodes * nr_cpus_per_node) / nr_iaa; + else + cpus_per_iaa = 0; +} + +static int wq_table_add_wqs(int iaa, int cpu) +{ + struct iaa_device *iaa_device, *found_device = NULL; + int ret = 0, cur_iaa = 0, n_wqs_added = 0; + struct idxd_device *idxd; + struct iaa_wq *iaa_wq; + struct pci_dev *pdev; + struct device *dev; + + list_for_each_entry(iaa_device, &iaa_devices, list) { + idxd = iaa_device->idxd; + pdev = idxd->pdev; + dev = &pdev->dev; + + if (cur_iaa != iaa) { + cur_iaa++; + continue; + } + + found_device = iaa_device; + dev_dbg(dev, "getting wq from iaa_device %d, cur_iaa %d\n", + found_device->idxd->id, cur_iaa); + break; + } + + if (!found_device) { + found_device = list_first_entry_or_null(&iaa_devices, + struct iaa_device, list); + if (!found_device) { + pr_debug("couldn't find any iaa devices with wqs!\n"); + ret = -EINVAL; + goto out; + } + cur_iaa = 0; + + idxd = found_device->idxd; + pdev = idxd->pdev; + dev = &pdev->dev; + dev_dbg(dev, "getting wq from only iaa_device %d, cur_iaa %d\n", + found_device->idxd->id, cur_iaa); + } + + list_for_each_entry(iaa_wq, &found_device->wqs, list) { + wq_table_add(cpu, iaa_wq->wq); + pr_debug("rebalance: added wq for cpu=%d: iaa wq %d.%d\n", + cpu, iaa_wq->wq->idxd->id, iaa_wq->wq->id); + n_wqs_added++; + } + + if (!n_wqs_added) { + pr_debug("couldn't find any iaa wqs!\n"); + ret = -EINVAL; + goto out; + } +out: + return ret; +} + +/* + * Rebalance the wq table so that given a cpu, it's easy to find the + * closest IAA instance. The idea is to try to choose the most + * appropriate IAA instance for a caller and spread available + * workqueues around to clients. + */ +static void rebalance_wq_table(void) +{ + const struct cpumask *node_cpus; + int node, cpu, iaa = -1; + + if (nr_iaa == 0) + return; + + pr_debug("rebalance: nr_nodes=%d, nr_cpus %d, nr_iaa %d, cpus_per_iaa %d\n", + nr_nodes, nr_cpus, nr_iaa, cpus_per_iaa); + + clear_wq_table(); + + if (nr_iaa == 1) { + for (cpu = 0; cpu < nr_cpus; cpu++) { + if (WARN_ON(wq_table_add_wqs(0, cpu))) { + pr_debug("could not add any wqs for iaa 0 to cpu %d!\n", cpu); + return; + } + } + + return; + } + + for_each_node_with_cpus(node) { + node_cpus = cpumask_of_node(node); + + for (cpu = 0; cpu < nr_cpus_per_node; cpu++) { + int node_cpu = cpumask_nth(cpu, node_cpus); + + if (WARN_ON(node_cpu >= nr_cpu_ids)) { + pr_debug("node_cpu %d doesn't exist!\n", node_cpu); + return; + } + + if ((cpu % cpus_per_iaa) == 0) + iaa++; + + if (WARN_ON(wq_table_add_wqs(iaa, node_cpu))) { + pr_debug("could not add any wqs for iaa %d to cpu %d!\n", iaa, cpu); + return; + } + } + } +} + +static inline int check_completion(struct device *dev, + struct iax_completion_record *comp, + bool compress, + bool only_once) +{ + char *op_str = compress ? "compress" : "decompress"; + int ret = 0; + + while (!comp->status) { + if (only_once) + return -EAGAIN; + cpu_relax(); + } + + if (comp->status != IAX_COMP_SUCCESS) { + if (comp->status == IAA_ERROR_WATCHDOG_EXPIRED) { + ret = -ETIMEDOUT; + dev_dbg(dev, "%s timed out, size=0x%x\n", + op_str, comp->output_size); + update_completion_timeout_errs(); + goto out; + } + + if (comp->status == IAA_ANALYTICS_ERROR && + comp->error_code == IAA_ERROR_COMP_BUF_OVERFLOW && compress) { + ret = -E2BIG; + dev_dbg(dev, "compressed > uncompressed size," + " not compressing, size=0x%x\n", + comp->output_size); + update_completion_comp_buf_overflow_errs(); + goto out; + } + + if (comp->status == IAA_ERROR_DECOMP_BUF_OVERFLOW) { + ret = -EOVERFLOW; + goto out; + } + + ret = -EINVAL; + dev_dbg(dev, "iaa %s status=0x%x, error=0x%x, size=0x%x\n", + op_str, comp->status, comp->error_code, comp->output_size); + print_hex_dump(KERN_INFO, "cmp-rec: ", DUMP_PREFIX_OFFSET, 8, 1, comp, 64, 0); + update_completion_einval_errs(); + + goto out; + } +out: + return ret; +} + +static int deflate_generic_decompress(struct acomp_req *req) +{ + void *src, *dst; + int ret; + + src = kmap_local_page(sg_page(req->src)) + req->src->offset; + dst = kmap_local_page(sg_page(req->dst)) + req->dst->offset; + + ret = crypto_comp_decompress(deflate_generic_tfm, + src, req->slen, dst, &req->dlen); + + kunmap_local(src); + kunmap_local(dst); + + update_total_sw_decomp_calls(); + + return ret; +} + +static int iaa_remap_for_verify(struct device *dev, struct iaa_wq *iaa_wq, + struct acomp_req *req, + dma_addr_t *src_addr, dma_addr_t *dst_addr); + +static int iaa_compress_verify(struct crypto_tfm *tfm, struct acomp_req *req, + struct idxd_wq *wq, + dma_addr_t src_addr, unsigned int slen, + dma_addr_t dst_addr, unsigned int *dlen, + u32 compression_crc); + +static void iaa_desc_complete(struct idxd_desc *idxd_desc, + enum idxd_complete_type comp_type, + bool free_desc, void *__ctx, + u32 *status) +{ + struct iaa_device_compression_mode *active_compression_mode; + struct iaa_compression_ctx *compression_ctx; + struct crypto_ctx *ctx = __ctx; + struct iaa_device *iaa_device; + struct idxd_device *idxd; + struct iaa_wq *iaa_wq; + struct pci_dev *pdev; + struct device *dev; + int ret, err = 0; + + compression_ctx = crypto_tfm_ctx(ctx->tfm); + + iaa_wq = idxd_wq_get_private(idxd_desc->wq); + iaa_device = iaa_wq->iaa_device; + idxd = iaa_device->idxd; + pdev = idxd->pdev; + dev = &pdev->dev; + + active_compression_mode = get_iaa_device_compression_mode(iaa_device, + compression_ctx->mode); + dev_dbg(dev, "%s: compression mode %s," + " ctx->src_addr %llx, ctx->dst_addr %llx\n", __func__, + active_compression_mode->name, + ctx->src_addr, ctx->dst_addr); + + ret = check_completion(dev, idxd_desc->iax_completion, + ctx->compress, false); + if (ret) { + dev_dbg(dev, "%s: check_completion failed ret=%d\n", __func__, ret); + if (!ctx->compress && + idxd_desc->iax_completion->status == IAA_ANALYTICS_ERROR) { + pr_warn("%s: falling back to deflate-generic decompress, " + "analytics error code %x\n", __func__, + idxd_desc->iax_completion->error_code); + ret = deflate_generic_decompress(ctx->req); + if (ret) { + dev_dbg(dev, "%s: deflate-generic failed ret=%d\n", + __func__, ret); + err = -EIO; + goto err; + } + } else { + err = -EIO; + goto err; + } + } else { + ctx->req->dlen = idxd_desc->iax_completion->output_size; + } + + /* Update stats */ + if (ctx->compress) { + update_total_comp_bytes_out(ctx->req->dlen); + update_wq_comp_bytes(iaa_wq->wq, ctx->req->dlen); + } else { + update_total_decomp_bytes_in(ctx->req->dlen); + update_wq_decomp_bytes(iaa_wq->wq, ctx->req->dlen); + } + + if (ctx->compress && compression_ctx->verify_compress) { + dma_addr_t src_addr, dst_addr; + u32 compression_crc; + + compression_crc = idxd_desc->iax_completion->crc; + + ret = iaa_remap_for_verify(dev, iaa_wq, ctx->req, &src_addr, &dst_addr); + if (ret) { + dev_dbg(dev, "%s: compress verify remap failed ret=%d\n", __func__, ret); + err = -EIO; + goto out; + } + + ret = iaa_compress_verify(ctx->tfm, ctx->req, iaa_wq->wq, src_addr, + ctx->req->slen, dst_addr, &ctx->req->dlen, + compression_crc); + if (ret) { + dev_dbg(dev, "%s: compress verify failed ret=%d\n", __func__, ret); + err = -EIO; + } + + dma_unmap_sg(dev, ctx->req->dst, sg_nents(ctx->req->dst), DMA_TO_DEVICE); + dma_unmap_sg(dev, ctx->req->src, sg_nents(ctx->req->src), DMA_FROM_DEVICE); + + goto out; + } +err: + dma_unmap_sg(dev, ctx->req->dst, sg_nents(ctx->req->dst), DMA_FROM_DEVICE); + dma_unmap_sg(dev, ctx->req->src, sg_nents(ctx->req->src), DMA_TO_DEVICE); +out: + if (ret != 0) + dev_dbg(dev, "asynchronous compress failed ret=%d\n", ret); + + if (ctx->req->base.complete) + acomp_request_complete(ctx->req, err); + + if (free_desc) + idxd_free_desc(idxd_desc->wq, idxd_desc); + iaa_wq_put(idxd_desc->wq); +} + +static int iaa_compress(struct crypto_tfm *tfm, struct acomp_req *req, + struct idxd_wq *wq, + dma_addr_t src_addr, unsigned int slen, + dma_addr_t dst_addr, unsigned int *dlen, + u32 *compression_crc, + bool disable_async) +{ + struct iaa_device_compression_mode *active_compression_mode; + struct iaa_compression_ctx *ctx = crypto_tfm_ctx(tfm); + struct iaa_device *iaa_device; + struct idxd_desc *idxd_desc; + struct iax_hw_desc *desc; + struct idxd_device *idxd; + struct iaa_wq *iaa_wq; + struct pci_dev *pdev; + struct device *dev; + int ret = 0; + + iaa_wq = idxd_wq_get_private(wq); + iaa_device = iaa_wq->iaa_device; + idxd = iaa_device->idxd; + pdev = idxd->pdev; + dev = &pdev->dev; + + active_compression_mode = get_iaa_device_compression_mode(iaa_device, ctx->mode); + + idxd_desc = idxd_alloc_desc(wq, IDXD_OP_BLOCK); + if (IS_ERR(idxd_desc)) { + dev_dbg(dev, "idxd descriptor allocation failed\n"); + dev_dbg(dev, "iaa compress failed: ret=%ld\n", PTR_ERR(idxd_desc)); + return PTR_ERR(idxd_desc); + } + desc = idxd_desc->iax_hw; + + desc->flags = IDXD_OP_FLAG_CRAV | IDXD_OP_FLAG_RCR | + IDXD_OP_FLAG_RD_SRC2_AECS | IDXD_OP_FLAG_CC; + desc->opcode = IAX_OPCODE_COMPRESS; + desc->compr_flags = IAA_COMP_FLAGS; + desc->priv = 0; + + desc->src1_addr = (u64)src_addr; + desc->src1_size = slen; + desc->dst_addr = (u64)dst_addr; + desc->max_dst_size = *dlen; + desc->src2_addr = active_compression_mode->aecs_comp_table_dma_addr; + desc->src2_size = sizeof(struct aecs_comp_table_record); + desc->completion_addr = idxd_desc->compl_dma; + + if (ctx->use_irq && !disable_async) { + desc->flags |= IDXD_OP_FLAG_RCI; + + idxd_desc->crypto.req = req; + idxd_desc->crypto.tfm = tfm; + idxd_desc->crypto.src_addr = src_addr; + idxd_desc->crypto.dst_addr = dst_addr; + idxd_desc->crypto.compress = true; + + dev_dbg(dev, "%s use_async_irq: compression mode %s," + " src_addr %llx, dst_addr %llx\n", __func__, + active_compression_mode->name, + src_addr, dst_addr); + } else if (ctx->async_mode && !disable_async) + req->base.data = idxd_desc; + + dev_dbg(dev, "%s: compression mode %s," + " desc->src1_addr %llx, desc->src1_size %d," + " desc->dst_addr %llx, desc->max_dst_size %d," + " desc->src2_addr %llx, desc->src2_size %d\n", __func__, + active_compression_mode->name, + desc->src1_addr, desc->src1_size, desc->dst_addr, + desc->max_dst_size, desc->src2_addr, desc->src2_size); + + ret = idxd_submit_desc(wq, idxd_desc); + if (ret) { + dev_dbg(dev, "submit_desc failed ret=%d\n", ret); + goto err; + } + + /* Update stats */ + update_total_comp_calls(); + update_wq_comp_calls(wq); + + if (ctx->async_mode && !disable_async) { + ret = -EINPROGRESS; + dev_dbg(dev, "%s: returning -EINPROGRESS\n", __func__); + goto out; + } + + ret = check_completion(dev, idxd_desc->iax_completion, true, false); + if (ret) { + dev_dbg(dev, "check_completion failed ret=%d\n", ret); + goto err; + } + + *dlen = idxd_desc->iax_completion->output_size; + + /* Update stats */ + update_total_comp_bytes_out(*dlen); + update_wq_comp_bytes(wq, *dlen); + + *compression_crc = idxd_desc->iax_completion->crc; + + if (!ctx->async_mode) + idxd_free_desc(wq, idxd_desc); +out: + return ret; +err: + idxd_free_desc(wq, idxd_desc); + dev_dbg(dev, "iaa compress failed: ret=%d\n", ret); + + goto out; +} + +static int iaa_remap_for_verify(struct device *dev, struct iaa_wq *iaa_wq, + struct acomp_req *req, + dma_addr_t *src_addr, dma_addr_t *dst_addr) +{ + int ret = 0; + int nr_sgs; + + dma_unmap_sg(dev, req->dst, sg_nents(req->dst), DMA_FROM_DEVICE); + dma_unmap_sg(dev, req->src, sg_nents(req->src), DMA_TO_DEVICE); + + nr_sgs = dma_map_sg(dev, req->src, sg_nents(req->src), DMA_FROM_DEVICE); + if (nr_sgs <= 0 || nr_sgs > 1) { + dev_dbg(dev, "verify: couldn't map src sg for iaa device %d," + " wq %d: ret=%d\n", iaa_wq->iaa_device->idxd->id, + iaa_wq->wq->id, ret); + ret = -EIO; + goto out; + } + *src_addr = sg_dma_address(req->src); + dev_dbg(dev, "verify: dma_map_sg, src_addr %llx, nr_sgs %d, req->src %p," + " req->slen %d, sg_dma_len(sg) %d\n", *src_addr, nr_sgs, + req->src, req->slen, sg_dma_len(req->src)); + + nr_sgs = dma_map_sg(dev, req->dst, sg_nents(req->dst), DMA_TO_DEVICE); + if (nr_sgs <= 0 || nr_sgs > 1) { + dev_dbg(dev, "verify: couldn't map dst sg for iaa device %d," + " wq %d: ret=%d\n", iaa_wq->iaa_device->idxd->id, + iaa_wq->wq->id, ret); + ret = -EIO; + dma_unmap_sg(dev, req->src, sg_nents(req->src), DMA_FROM_DEVICE); + goto out; + } + *dst_addr = sg_dma_address(req->dst); + dev_dbg(dev, "verify: dma_map_sg, dst_addr %llx, nr_sgs %d, req->dst %p," + " req->dlen %d, sg_dma_len(sg) %d\n", *dst_addr, nr_sgs, + req->dst, req->dlen, sg_dma_len(req->dst)); +out: + return ret; +} + +static int iaa_compress_verify(struct crypto_tfm *tfm, struct acomp_req *req, + struct idxd_wq *wq, + dma_addr_t src_addr, unsigned int slen, + dma_addr_t dst_addr, unsigned int *dlen, + u32 compression_crc) +{ + struct iaa_device_compression_mode *active_compression_mode; + struct iaa_compression_ctx *ctx = crypto_tfm_ctx(tfm); + struct iaa_device *iaa_device; + struct idxd_desc *idxd_desc; + struct iax_hw_desc *desc; + struct idxd_device *idxd; + struct iaa_wq *iaa_wq; + struct pci_dev *pdev; + struct device *dev; + int ret = 0; + + iaa_wq = idxd_wq_get_private(wq); + iaa_device = iaa_wq->iaa_device; + idxd = iaa_device->idxd; + pdev = idxd->pdev; + dev = &pdev->dev; + + active_compression_mode = get_iaa_device_compression_mode(iaa_device, ctx->mode); + + idxd_desc = idxd_alloc_desc(wq, IDXD_OP_BLOCK); + if (IS_ERR(idxd_desc)) { + dev_dbg(dev, "idxd descriptor allocation failed\n"); + dev_dbg(dev, "iaa compress failed: ret=%ld\n", + PTR_ERR(idxd_desc)); + return PTR_ERR(idxd_desc); + } + desc = idxd_desc->iax_hw; + + /* Verify (optional) - decompress and check crc, suppress dest write */ + + desc->flags = IDXD_OP_FLAG_CRAV | IDXD_OP_FLAG_RCR | IDXD_OP_FLAG_CC; + desc->opcode = IAX_OPCODE_DECOMPRESS; + desc->decompr_flags = IAA_DECOMP_FLAGS | IAA_DECOMP_SUPPRESS_OUTPUT; + desc->priv = 0; + + desc->src1_addr = (u64)dst_addr; + desc->src1_size = *dlen; + desc->dst_addr = (u64)src_addr; + desc->max_dst_size = slen; + desc->completion_addr = idxd_desc->compl_dma; + + dev_dbg(dev, "(verify) compression mode %s," + " desc->src1_addr %llx, desc->src1_size %d," + " desc->dst_addr %llx, desc->max_dst_size %d," + " desc->src2_addr %llx, desc->src2_size %d\n", + active_compression_mode->name, + desc->src1_addr, desc->src1_size, desc->dst_addr, + desc->max_dst_size, desc->src2_addr, desc->src2_size); + + ret = idxd_submit_desc(wq, idxd_desc); + if (ret) { + dev_dbg(dev, "submit_desc (verify) failed ret=%d\n", ret); + goto err; + } + + ret = check_completion(dev, idxd_desc->iax_completion, false, false); + if (ret) { + dev_dbg(dev, "(verify) check_completion failed ret=%d\n", ret); + goto err; + } + + if (compression_crc != idxd_desc->iax_completion->crc) { + ret = -EINVAL; + dev_dbg(dev, "(verify) iaa comp/decomp crc mismatch:" + " comp=0x%x, decomp=0x%x\n", compression_crc, + idxd_desc->iax_completion->crc); + print_hex_dump(KERN_INFO, "cmp-rec: ", DUMP_PREFIX_OFFSET, + 8, 1, idxd_desc->iax_completion, 64, 0); + goto err; + } + + idxd_free_desc(wq, idxd_desc); +out: + return ret; +err: + idxd_free_desc(wq, idxd_desc); + dev_dbg(dev, "iaa compress failed: ret=%d\n", ret); + + goto out; +} + +static int iaa_decompress(struct crypto_tfm *tfm, struct acomp_req *req, + struct idxd_wq *wq, + dma_addr_t src_addr, unsigned int slen, + dma_addr_t dst_addr, unsigned int *dlen, + bool disable_async) +{ + struct iaa_device_compression_mode *active_compression_mode; + struct iaa_compression_ctx *ctx = crypto_tfm_ctx(tfm); + struct iaa_device *iaa_device; + struct idxd_desc *idxd_desc; + struct iax_hw_desc *desc; + struct idxd_device *idxd; + struct iaa_wq *iaa_wq; + struct pci_dev *pdev; + struct device *dev; + int ret = 0; + + iaa_wq = idxd_wq_get_private(wq); + iaa_device = iaa_wq->iaa_device; + idxd = iaa_device->idxd; + pdev = idxd->pdev; + dev = &pdev->dev; + + active_compression_mode = get_iaa_device_compression_mode(iaa_device, ctx->mode); + + idxd_desc = idxd_alloc_desc(wq, IDXD_OP_BLOCK); + if (IS_ERR(idxd_desc)) { + dev_dbg(dev, "idxd descriptor allocation failed\n"); + dev_dbg(dev, "iaa decompress failed: ret=%ld\n", + PTR_ERR(idxd_desc)); + return PTR_ERR(idxd_desc); + } + desc = idxd_desc->iax_hw; + + desc->flags = IDXD_OP_FLAG_CRAV | IDXD_OP_FLAG_RCR | IDXD_OP_FLAG_CC; + desc->opcode = IAX_OPCODE_DECOMPRESS; + desc->max_dst_size = PAGE_SIZE; + desc->decompr_flags = IAA_DECOMP_FLAGS; + desc->priv = 0; + + desc->src1_addr = (u64)src_addr; + desc->dst_addr = (u64)dst_addr; + desc->max_dst_size = *dlen; + desc->src1_size = slen; + desc->completion_addr = idxd_desc->compl_dma; + + if (ctx->use_irq && !disable_async) { + desc->flags |= IDXD_OP_FLAG_RCI; + + idxd_desc->crypto.req = req; + idxd_desc->crypto.tfm = tfm; + idxd_desc->crypto.src_addr = src_addr; + idxd_desc->crypto.dst_addr = dst_addr; + idxd_desc->crypto.compress = false; + + dev_dbg(dev, "%s: use_async_irq compression mode %s," + " src_addr %llx, dst_addr %llx\n", __func__, + active_compression_mode->name, + src_addr, dst_addr); + } else if (ctx->async_mode && !disable_async) + req->base.data = idxd_desc; + + dev_dbg(dev, "%s: decompression mode %s," + " desc->src1_addr %llx, desc->src1_size %d," + " desc->dst_addr %llx, desc->max_dst_size %d," + " desc->src2_addr %llx, desc->src2_size %d\n", __func__, + active_compression_mode->name, + desc->src1_addr, desc->src1_size, desc->dst_addr, + desc->max_dst_size, desc->src2_addr, desc->src2_size); + + ret = idxd_submit_desc(wq, idxd_desc); + if (ret) { + dev_dbg(dev, "submit_desc failed ret=%d\n", ret); + goto err; + } + + /* Update stats */ + update_total_decomp_calls(); + update_wq_decomp_calls(wq); + + if (ctx->async_mode && !disable_async) { + ret = -EINPROGRESS; + dev_dbg(dev, "%s: returning -EINPROGRESS\n", __func__); + goto out; + } + + ret = check_completion(dev, idxd_desc->iax_completion, false, false); + if (ret) { + dev_dbg(dev, "%s: check_completion failed ret=%d\n", __func__, ret); + if (idxd_desc->iax_completion->status == IAA_ANALYTICS_ERROR) { + pr_warn("%s: falling back to deflate-generic decompress, " + "analytics error code %x\n", __func__, + idxd_desc->iax_completion->error_code); + ret = deflate_generic_decompress(req); + if (ret) { + dev_dbg(dev, "%s: deflate-generic failed ret=%d\n", + __func__, ret); + goto err; + } + } else { + goto err; + } + } else { + req->dlen = idxd_desc->iax_completion->output_size; + } + + *dlen = req->dlen; + + if (!ctx->async_mode) + idxd_free_desc(wq, idxd_desc); + + /* Update stats */ + update_total_decomp_bytes_in(slen); + update_wq_decomp_bytes(wq, slen); +out: + return ret; +err: + idxd_free_desc(wq, idxd_desc); + dev_dbg(dev, "iaa decompress failed: ret=%d\n", ret); + + goto out; +} + +static int iaa_comp_acompress(struct acomp_req *req) +{ + struct iaa_compression_ctx *compression_ctx; + struct crypto_tfm *tfm = req->base.tfm; + dma_addr_t src_addr, dst_addr; + bool disable_async = false; + int nr_sgs, cpu, ret = 0; + struct iaa_wq *iaa_wq; + u32 compression_crc; + struct idxd_wq *wq; + struct device *dev; + int order = -1; + + compression_ctx = crypto_tfm_ctx(tfm); + + if (!iaa_crypto_enabled) { + pr_debug("iaa_crypto disabled, not compressing\n"); + return -ENODEV; + } + + if (!req->src || !req->slen) { + pr_debug("invalid src, not compressing\n"); + return -EINVAL; + } + + cpu = get_cpu(); + wq = wq_table_next_wq(cpu); + put_cpu(); + if (!wq) { + pr_debug("no wq configured for cpu=%d\n", cpu); + return -ENODEV; + } + + ret = iaa_wq_get(wq); + if (ret) { + pr_debug("no wq available for cpu=%d\n", cpu); + return -ENODEV; + } + + iaa_wq = idxd_wq_get_private(wq); + + if (!req->dst) { + gfp_t flags = req->flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL : GFP_ATOMIC; + + /* incompressible data will always be < 2 * slen */ + req->dlen = 2 * req->slen; + order = order_base_2(round_up(req->dlen, PAGE_SIZE) / PAGE_SIZE); + req->dst = sgl_alloc_order(req->dlen, order, false, flags, NULL); + if (!req->dst) { + ret = -ENOMEM; + order = -1; + goto out; + } + disable_async = true; + } + + dev = &wq->idxd->pdev->dev; + + nr_sgs = dma_map_sg(dev, req->src, sg_nents(req->src), DMA_TO_DEVICE); + if (nr_sgs <= 0 || nr_sgs > 1) { + dev_dbg(dev, "couldn't map src sg for iaa device %d," + " wq %d: ret=%d\n", iaa_wq->iaa_device->idxd->id, + iaa_wq->wq->id, ret); + ret = -EIO; + goto out; + } + src_addr = sg_dma_address(req->src); + dev_dbg(dev, "dma_map_sg, src_addr %llx, nr_sgs %d, req->src %p," + " req->slen %d, sg_dma_len(sg) %d\n", src_addr, nr_sgs, + req->src, req->slen, sg_dma_len(req->src)); + + nr_sgs = dma_map_sg(dev, req->dst, sg_nents(req->dst), DMA_FROM_DEVICE); + if (nr_sgs <= 0 || nr_sgs > 1) { + dev_dbg(dev, "couldn't map dst sg for iaa device %d," + " wq %d: ret=%d\n", iaa_wq->iaa_device->idxd->id, + iaa_wq->wq->id, ret); + ret = -EIO; + goto err_map_dst; + } + dst_addr = sg_dma_address(req->dst); + dev_dbg(dev, "dma_map_sg, dst_addr %llx, nr_sgs %d, req->dst %p," + " req->dlen %d, sg_dma_len(sg) %d\n", dst_addr, nr_sgs, + req->dst, req->dlen, sg_dma_len(req->dst)); + + ret = iaa_compress(tfm, req, wq, src_addr, req->slen, dst_addr, + &req->dlen, &compression_crc, disable_async); + if (ret == -EINPROGRESS) + return ret; + + if (!ret && compression_ctx->verify_compress) { + ret = iaa_remap_for_verify(dev, iaa_wq, req, &src_addr, &dst_addr); + if (ret) { + dev_dbg(dev, "%s: compress verify remap failed ret=%d\n", __func__, ret); + goto out; + } + + ret = iaa_compress_verify(tfm, req, wq, src_addr, req->slen, + dst_addr, &req->dlen, compression_crc); + if (ret) + dev_dbg(dev, "asynchronous compress verification failed ret=%d\n", ret); + + dma_unmap_sg(dev, req->dst, sg_nents(req->dst), DMA_TO_DEVICE); + dma_unmap_sg(dev, req->src, sg_nents(req->src), DMA_FROM_DEVICE); + + goto out; + } + + if (ret) + dev_dbg(dev, "asynchronous compress failed ret=%d\n", ret); + + dma_unmap_sg(dev, req->dst, sg_nents(req->dst), DMA_FROM_DEVICE); +err_map_dst: + dma_unmap_sg(dev, req->src, sg_nents(req->src), DMA_TO_DEVICE); +out: + iaa_wq_put(wq); + + if (order >= 0) + sgl_free_order(req->dst, order); + + return ret; +} + +static int iaa_comp_adecompress_alloc_dest(struct acomp_req *req) +{ + gfp_t flags = req->flags & CRYPTO_TFM_REQ_MAY_SLEEP ? + GFP_KERNEL : GFP_ATOMIC; + struct crypto_tfm *tfm = req->base.tfm; + dma_addr_t src_addr, dst_addr; + int nr_sgs, cpu, ret = 0; + struct iaa_wq *iaa_wq; + struct device *dev; + struct idxd_wq *wq; + int order = -1; + + cpu = get_cpu(); + wq = wq_table_next_wq(cpu); + put_cpu(); + if (!wq) { + pr_debug("no wq configured for cpu=%d\n", cpu); + return -ENODEV; + } + + ret = iaa_wq_get(wq); + if (ret) { + pr_debug("no wq available for cpu=%d\n", cpu); + return -ENODEV; + } + + iaa_wq = idxd_wq_get_private(wq); + + dev = &wq->idxd->pdev->dev; + + nr_sgs = dma_map_sg(dev, req->src, sg_nents(req->src), DMA_TO_DEVICE); + if (nr_sgs <= 0 || nr_sgs > 1) { + dev_dbg(dev, "couldn't map src sg for iaa device %d," + " wq %d: ret=%d\n", iaa_wq->iaa_device->idxd->id, + iaa_wq->wq->id, ret); + ret = -EIO; + goto out; + } + src_addr = sg_dma_address(req->src); + dev_dbg(dev, "dma_map_sg, src_addr %llx, nr_sgs %d, req->src %p," + " req->slen %d, sg_dma_len(sg) %d\n", src_addr, nr_sgs, + req->src, req->slen, sg_dma_len(req->src)); + + req->dlen = 4 * req->slen; /* start with ~avg comp rato */ +alloc_dest: + order = order_base_2(round_up(req->dlen, PAGE_SIZE) / PAGE_SIZE); + req->dst = sgl_alloc_order(req->dlen, order, false, flags, NULL); + if (!req->dst) { + ret = -ENOMEM; + order = -1; + goto out; + } + + nr_sgs = dma_map_sg(dev, req->dst, sg_nents(req->dst), DMA_FROM_DEVICE); + if (nr_sgs <= 0 || nr_sgs > 1) { + dev_dbg(dev, "couldn't map dst sg for iaa device %d," + " wq %d: ret=%d\n", iaa_wq->iaa_device->idxd->id, + iaa_wq->wq->id, ret); + ret = -EIO; + goto err_map_dst; + } + + dst_addr = sg_dma_address(req->dst); + dev_dbg(dev, "dma_map_sg, dst_addr %llx, nr_sgs %d, req->dst %p," + " req->dlen %d, sg_dma_len(sg) %d\n", dst_addr, nr_sgs, + req->dst, req->dlen, sg_dma_len(req->dst)); + ret = iaa_decompress(tfm, req, wq, src_addr, req->slen, + dst_addr, &req->dlen, true); + if (ret == -EOVERFLOW) { + dma_unmap_sg(dev, req->dst, sg_nents(req->dst), DMA_FROM_DEVICE); + req->dlen *= 2; + if (req->dlen > CRYPTO_ACOMP_DST_MAX) + goto err_map_dst; + goto alloc_dest; + } + + if (ret != 0) + dev_dbg(dev, "asynchronous decompress failed ret=%d\n", ret); + + dma_unmap_sg(dev, req->dst, sg_nents(req->dst), DMA_FROM_DEVICE); +err_map_dst: + dma_unmap_sg(dev, req->src, sg_nents(req->src), DMA_TO_DEVICE); +out: + iaa_wq_put(wq); + + if (order >= 0) + sgl_free_order(req->dst, order); + + return ret; +} + +static int iaa_comp_adecompress(struct acomp_req *req) +{ + struct crypto_tfm *tfm = req->base.tfm; + dma_addr_t src_addr, dst_addr; + int nr_sgs, cpu, ret = 0; + struct iaa_wq *iaa_wq; + struct device *dev; + struct idxd_wq *wq; + + if (!iaa_crypto_enabled) { + pr_debug("iaa_crypto disabled, not decompressing\n"); + return -ENODEV; + } + + if (!req->src || !req->slen) { + pr_debug("invalid src, not decompressing\n"); + return -EINVAL; + } + + if (!req->dst) + return iaa_comp_adecompress_alloc_dest(req); + + cpu = get_cpu(); + wq = wq_table_next_wq(cpu); + put_cpu(); + if (!wq) { + pr_debug("no wq configured for cpu=%d\n", cpu); + return -ENODEV; + } + + ret = iaa_wq_get(wq); + if (ret) { + pr_debug("no wq available for cpu=%d\n", cpu); + return -ENODEV; + } + + iaa_wq = idxd_wq_get_private(wq); + + dev = &wq->idxd->pdev->dev; + + nr_sgs = dma_map_sg(dev, req->src, sg_nents(req->src), DMA_TO_DEVICE); + if (nr_sgs <= 0 || nr_sgs > 1) { + dev_dbg(dev, "couldn't map src sg for iaa device %d," + " wq %d: ret=%d\n", iaa_wq->iaa_device->idxd->id, + iaa_wq->wq->id, ret); + ret = -EIO; + goto out; + } + src_addr = sg_dma_address(req->src); + dev_dbg(dev, "dma_map_sg, src_addr %llx, nr_sgs %d, req->src %p," + " req->slen %d, sg_dma_len(sg) %d\n", src_addr, nr_sgs, + req->src, req->slen, sg_dma_len(req->src)); + + nr_sgs = dma_map_sg(dev, req->dst, sg_nents(req->dst), DMA_FROM_DEVICE); + if (nr_sgs <= 0 || nr_sgs > 1) { + dev_dbg(dev, "couldn't map dst sg for iaa device %d," + " wq %d: ret=%d\n", iaa_wq->iaa_device->idxd->id, + iaa_wq->wq->id, ret); + ret = -EIO; + goto err_map_dst; + } + dst_addr = sg_dma_address(req->dst); + dev_dbg(dev, "dma_map_sg, dst_addr %llx, nr_sgs %d, req->dst %p," + " req->dlen %d, sg_dma_len(sg) %d\n", dst_addr, nr_sgs, + req->dst, req->dlen, sg_dma_len(req->dst)); + + ret = iaa_decompress(tfm, req, wq, src_addr, req->slen, + dst_addr, &req->dlen, false); + if (ret == -EINPROGRESS) + return ret; + + if (ret != 0) + dev_dbg(dev, "asynchronous decompress failed ret=%d\n", ret); + + dma_unmap_sg(dev, req->dst, sg_nents(req->dst), DMA_FROM_DEVICE); +err_map_dst: + dma_unmap_sg(dev, req->src, sg_nents(req->src), DMA_TO_DEVICE); +out: + iaa_wq_put(wq); + + return ret; +} + +static void compression_ctx_init(struct iaa_compression_ctx *ctx) +{ + ctx->verify_compress = iaa_verify_compress; + ctx->async_mode = async_mode; + ctx->use_irq = use_irq; +} + +static int iaa_comp_init_fixed(struct crypto_acomp *acomp_tfm) +{ + struct crypto_tfm *tfm = crypto_acomp_tfm(acomp_tfm); + struct iaa_compression_ctx *ctx = crypto_tfm_ctx(tfm); + + compression_ctx_init(ctx); + + ctx->mode = IAA_MODE_FIXED; + + return 0; +} + +static void dst_free(struct scatterlist *sgl) +{ + /* + * Called for req->dst = NULL cases but we free elsewhere + * using sgl_free_order(). + */ +} + +static struct acomp_alg iaa_acomp_fixed_deflate = { + .init = iaa_comp_init_fixed, + .compress = iaa_comp_acompress, + .decompress = iaa_comp_adecompress, + .dst_free = dst_free, + .base = { + .cra_name = "deflate", + .cra_driver_name = "deflate-iaa", + .cra_ctxsize = sizeof(struct iaa_compression_ctx), + .cra_module = THIS_MODULE, + .cra_priority = IAA_ALG_PRIORITY, + } +}; + +static int iaa_register_compression_device(void) +{ + int ret; + + ret = crypto_register_acomp(&iaa_acomp_fixed_deflate); + if (ret) { + pr_err("deflate algorithm acomp fixed registration failed (%d)\n", ret); + goto out; + } + + iaa_crypto_registered = true; +out: + return ret; +} + +static int iaa_unregister_compression_device(void) +{ + if (iaa_crypto_registered) + crypto_unregister_acomp(&iaa_acomp_fixed_deflate); + + return 0; +} + +static int iaa_crypto_probe(struct idxd_dev *idxd_dev) +{ + struct idxd_wq *wq = idxd_dev_to_wq(idxd_dev); + struct idxd_device *idxd = wq->idxd; + struct idxd_driver_data *data = idxd->data; + struct device *dev = &idxd_dev->conf_dev; + bool first_wq = false; + int ret = 0; + + if (idxd->state != IDXD_DEV_ENABLED) + return -ENXIO; + + if (data->type != IDXD_TYPE_IAX) + return -ENODEV; + + mutex_lock(&wq->wq_lock); + + if (idxd_wq_get_private(wq)) { + mutex_unlock(&wq->wq_lock); + return -EBUSY; + } + + if (!idxd_wq_driver_name_match(wq, dev)) { + dev_dbg(dev, "wq %d.%d driver_name match failed: wq driver_name %s, dev driver name %s\n", + idxd->id, wq->id, wq->driver_name, dev->driver->name); + idxd->cmd_status = IDXD_SCMD_WQ_NO_DRV_NAME; + ret = -ENODEV; + goto err; + } + + wq->type = IDXD_WQT_KERNEL; + + ret = idxd_drv_enable_wq(wq); + if (ret < 0) { + dev_dbg(dev, "enable wq %d.%d failed: %d\n", + idxd->id, wq->id, ret); + ret = -ENXIO; + goto err; + } + + mutex_lock(&iaa_devices_lock); + + if (list_empty(&iaa_devices)) { + ret = alloc_wq_table(wq->idxd->max_wqs); + if (ret) + goto err_alloc; + first_wq = true; + } + + ret = save_iaa_wq(wq); + if (ret) + goto err_save; + + rebalance_wq_table(); + + if (first_wq) { + iaa_crypto_enabled = true; + ret = iaa_register_compression_device(); + if (ret != 0) { + iaa_crypto_enabled = false; + dev_dbg(dev, "IAA compression device registration failed\n"); + goto err_register; + } + try_module_get(THIS_MODULE); + + pr_info("iaa_crypto now ENABLED\n"); + } + + mutex_unlock(&iaa_devices_lock); +out: + mutex_unlock(&wq->wq_lock); + + return ret; + +err_register: + remove_iaa_wq(wq); + free_iaa_wq(idxd_wq_get_private(wq)); +err_save: + if (first_wq) + free_wq_table(); +err_alloc: + mutex_unlock(&iaa_devices_lock); + idxd_drv_disable_wq(wq); +err: + wq->type = IDXD_WQT_NONE; + + goto out; +} + +static void iaa_crypto_remove(struct idxd_dev *idxd_dev) +{ + struct idxd_wq *wq = idxd_dev_to_wq(idxd_dev); + struct idxd_device *idxd = wq->idxd; + struct iaa_wq *iaa_wq; + bool free = false; + + idxd_wq_quiesce(wq); + + mutex_lock(&wq->wq_lock); + mutex_lock(&iaa_devices_lock); + + remove_iaa_wq(wq); + + spin_lock(&idxd->dev_lock); + iaa_wq = idxd_wq_get_private(wq); + if (!iaa_wq) { + spin_unlock(&idxd->dev_lock); + pr_err("%s: no iaa_wq available to remove\n", __func__); + goto out; + } + + if (iaa_wq->ref) { + iaa_wq->remove = true; + } else { + wq = iaa_wq->wq; + idxd_wq_set_private(wq, NULL); + free = true; + } + spin_unlock(&idxd->dev_lock); + if (free) { + __free_iaa_wq(iaa_wq); + kfree(iaa_wq); + } + + idxd_drv_disable_wq(wq); + rebalance_wq_table(); + + if (nr_iaa == 0) { + iaa_crypto_enabled = false; + free_wq_table(); + module_put(THIS_MODULE); + + pr_info("iaa_crypto now DISABLED\n"); + } +out: + mutex_unlock(&iaa_devices_lock); + mutex_unlock(&wq->wq_lock); +} + +static enum idxd_dev_type dev_types[] = { + IDXD_DEV_WQ, + IDXD_DEV_NONE, +}; + +static struct idxd_device_driver iaa_crypto_driver = { + .probe = iaa_crypto_probe, + .remove = iaa_crypto_remove, + .name = IDXD_SUBDRIVER_NAME, + .type = dev_types, + .desc_complete = iaa_desc_complete, +}; + +static int __init iaa_crypto_init_module(void) +{ + int ret = 0; + int node; + + nr_cpus = num_online_cpus(); + for_each_node_with_cpus(node) + nr_nodes++; + if (!nr_nodes) { + pr_err("IAA couldn't find any nodes with cpus\n"); + return -ENODEV; + } + nr_cpus_per_node = nr_cpus / nr_nodes; + + if (crypto_has_comp("deflate-generic", 0, 0)) + deflate_generic_tfm = crypto_alloc_comp("deflate-generic", 0, 0); + + if (IS_ERR_OR_NULL(deflate_generic_tfm)) { + pr_err("IAA could not alloc %s tfm: errcode = %ld\n", + "deflate-generic", PTR_ERR(deflate_generic_tfm)); + return -ENOMEM; + } + + ret = iaa_aecs_init_fixed(); + if (ret < 0) { + pr_debug("IAA fixed compression mode init failed\n"); + goto err_aecs_init; + } + + ret = idxd_driver_register(&iaa_crypto_driver); + if (ret) { + pr_debug("IAA wq sub-driver registration failed\n"); + goto err_driver_reg; + } + + ret = driver_create_file(&iaa_crypto_driver.drv, + &driver_attr_verify_compress); + if (ret) { + pr_debug("IAA verify_compress attr creation failed\n"); + goto err_verify_attr_create; + } + + ret = driver_create_file(&iaa_crypto_driver.drv, + &driver_attr_sync_mode); + if (ret) { + pr_debug("IAA sync mode attr creation failed\n"); + goto err_sync_attr_create; + } + + if (iaa_crypto_debugfs_init()) + pr_warn("debugfs init failed, stats not available\n"); + + pr_debug("initialized\n"); +out: + return ret; + +err_sync_attr_create: + driver_remove_file(&iaa_crypto_driver.drv, + &driver_attr_verify_compress); +err_verify_attr_create: + idxd_driver_unregister(&iaa_crypto_driver); +err_driver_reg: + iaa_aecs_cleanup_fixed(); +err_aecs_init: + crypto_free_comp(deflate_generic_tfm); + + goto out; +} + +static void __exit iaa_crypto_cleanup_module(void) +{ + if (iaa_unregister_compression_device()) + pr_debug("IAA compression device unregister failed\n"); + + iaa_crypto_debugfs_cleanup(); + driver_remove_file(&iaa_crypto_driver.drv, + &driver_attr_sync_mode); + driver_remove_file(&iaa_crypto_driver.drv, + &driver_attr_verify_compress); + idxd_driver_unregister(&iaa_crypto_driver); + iaa_aecs_cleanup_fixed(); + crypto_free_comp(deflate_generic_tfm); + + pr_debug("cleaned up\n"); +} + +MODULE_IMPORT_NS(IDXD); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_IDXD_DEVICE(0); +MODULE_AUTHOR("Intel Corporation"); +MODULE_DESCRIPTION("IAA Compression Accelerator Crypto Driver"); + +module_init(iaa_crypto_init_module); +module_exit(iaa_crypto_cleanup_module); diff --git a/drivers/crypto/intel/iaa/iaa_crypto_stats.c b/drivers/crypto/intel/iaa/iaa_crypto_stats.c new file mode 100644 index 00000000000000..2e3b7b73af2044 --- /dev/null +++ b/drivers/crypto/intel/iaa/iaa_crypto_stats.c @@ -0,0 +1,312 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2021 Intel Corporation. All rights rsvd. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../dma/idxd/idxd.h" +#include +#include +#include "iaa_crypto.h" +#include "iaa_crypto_stats.h" + +static u64 total_comp_calls; +static u64 total_decomp_calls; +static u64 total_sw_decomp_calls; +static u64 max_comp_delay_ns; +static u64 max_decomp_delay_ns; +static u64 max_acomp_delay_ns; +static u64 max_adecomp_delay_ns; +static u64 total_comp_bytes_out; +static u64 total_decomp_bytes_in; +static u64 total_completion_einval_errors; +static u64 total_completion_timeout_errors; +static u64 total_completion_comp_buf_overflow_errors; + +static struct dentry *iaa_crypto_debugfs_root; + +void update_total_comp_calls(void) +{ + total_comp_calls++; +} + +void update_total_comp_bytes_out(int n) +{ + total_comp_bytes_out += n; +} + +void update_total_decomp_calls(void) +{ + total_decomp_calls++; +} + +void update_total_sw_decomp_calls(void) +{ + total_sw_decomp_calls++; +} + +void update_total_decomp_bytes_in(int n) +{ + total_decomp_bytes_in += n; +} + +void update_completion_einval_errs(void) +{ + total_completion_einval_errors++; +} + +void update_completion_timeout_errs(void) +{ + total_completion_timeout_errors++; +} + +void update_completion_comp_buf_overflow_errs(void) +{ + total_completion_comp_buf_overflow_errors++; +} + +void update_max_comp_delay_ns(u64 start_time_ns) +{ + u64 time_diff; + + time_diff = ktime_get_ns() - start_time_ns; + + if (time_diff > max_comp_delay_ns) + max_comp_delay_ns = time_diff; +} + +void update_max_decomp_delay_ns(u64 start_time_ns) +{ + u64 time_diff; + + time_diff = ktime_get_ns() - start_time_ns; + + if (time_diff > max_decomp_delay_ns) + max_decomp_delay_ns = time_diff; +} + +void update_max_acomp_delay_ns(u64 start_time_ns) +{ + u64 time_diff; + + time_diff = ktime_get_ns() - start_time_ns; + + if (time_diff > max_acomp_delay_ns) + max_acomp_delay_ns = time_diff; +} + +void update_max_adecomp_delay_ns(u64 start_time_ns) +{ + u64 time_diff; + + time_diff = ktime_get_ns() - start_time_ns; + + if (time_diff > max_adecomp_delay_ns) + max_adecomp_delay_ns = time_diff; +} + +void update_wq_comp_calls(struct idxd_wq *idxd_wq) +{ + struct iaa_wq *wq = idxd_wq_get_private(idxd_wq); + + wq->comp_calls++; + wq->iaa_device->comp_calls++; +} + +void update_wq_comp_bytes(struct idxd_wq *idxd_wq, int n) +{ + struct iaa_wq *wq = idxd_wq_get_private(idxd_wq); + + wq->comp_bytes += n; + wq->iaa_device->comp_bytes += n; +} + +void update_wq_decomp_calls(struct idxd_wq *idxd_wq) +{ + struct iaa_wq *wq = idxd_wq_get_private(idxd_wq); + + wq->decomp_calls++; + wq->iaa_device->decomp_calls++; +} + +void update_wq_decomp_bytes(struct idxd_wq *idxd_wq, int n) +{ + struct iaa_wq *wq = idxd_wq_get_private(idxd_wq); + + wq->decomp_bytes += n; + wq->iaa_device->decomp_bytes += n; +} + +static void reset_iaa_crypto_stats(void) +{ + total_comp_calls = 0; + total_decomp_calls = 0; + total_sw_decomp_calls = 0; + max_comp_delay_ns = 0; + max_decomp_delay_ns = 0; + max_acomp_delay_ns = 0; + max_adecomp_delay_ns = 0; + total_comp_bytes_out = 0; + total_decomp_bytes_in = 0; + total_completion_einval_errors = 0; + total_completion_timeout_errors = 0; + total_completion_comp_buf_overflow_errors = 0; +} + +static void reset_wq_stats(struct iaa_wq *wq) +{ + wq->comp_calls = 0; + wq->comp_bytes = 0; + wq->decomp_calls = 0; + wq->decomp_bytes = 0; +} + +static void reset_device_stats(struct iaa_device *iaa_device) +{ + struct iaa_wq *iaa_wq; + + iaa_device->comp_calls = 0; + iaa_device->comp_bytes = 0; + iaa_device->decomp_calls = 0; + iaa_device->decomp_bytes = 0; + + list_for_each_entry(iaa_wq, &iaa_device->wqs, list) + reset_wq_stats(iaa_wq); +} + +static void wq_show(struct seq_file *m, struct iaa_wq *iaa_wq) +{ + seq_printf(m, " name: %s\n", iaa_wq->wq->name); + seq_printf(m, " comp_calls: %llu\n", iaa_wq->comp_calls); + seq_printf(m, " comp_bytes: %llu\n", iaa_wq->comp_bytes); + seq_printf(m, " decomp_calls: %llu\n", iaa_wq->decomp_calls); + seq_printf(m, " decomp_bytes: %llu\n\n", iaa_wq->decomp_bytes); +} + +static void device_stats_show(struct seq_file *m, struct iaa_device *iaa_device) +{ + struct iaa_wq *iaa_wq; + + seq_puts(m, "iaa device:\n"); + seq_printf(m, " id: %d\n", iaa_device->idxd->id); + seq_printf(m, " n_wqs: %d\n", iaa_device->n_wq); + seq_printf(m, " comp_calls: %llu\n", iaa_device->comp_calls); + seq_printf(m, " comp_bytes: %llu\n", iaa_device->comp_bytes); + seq_printf(m, " decomp_calls: %llu\n", iaa_device->decomp_calls); + seq_printf(m, " decomp_bytes: %llu\n", iaa_device->decomp_bytes); + seq_puts(m, " wqs:\n"); + + list_for_each_entry(iaa_wq, &iaa_device->wqs, list) + wq_show(m, iaa_wq); +} + +static void global_stats_show(struct seq_file *m) +{ + seq_puts(m, "global stats:\n"); + seq_printf(m, " total_comp_calls: %llu\n", total_comp_calls); + seq_printf(m, " total_decomp_calls: %llu\n", total_decomp_calls); + seq_printf(m, " total_sw_decomp_calls: %llu\n", total_sw_decomp_calls); + seq_printf(m, " total_comp_bytes_out: %llu\n", total_comp_bytes_out); + seq_printf(m, " total_decomp_bytes_in: %llu\n", total_decomp_bytes_in); + seq_printf(m, " total_completion_einval_errors: %llu\n", + total_completion_einval_errors); + seq_printf(m, " total_completion_timeout_errors: %llu\n", + total_completion_timeout_errors); + seq_printf(m, " total_completion_comp_buf_overflow_errors: %llu\n\n", + total_completion_comp_buf_overflow_errors); +} + +static int wq_stats_show(struct seq_file *m, void *v) +{ + struct iaa_device *iaa_device; + + mutex_lock(&iaa_devices_lock); + + global_stats_show(m); + + list_for_each_entry(iaa_device, &iaa_devices, list) + device_stats_show(m, iaa_device); + + mutex_unlock(&iaa_devices_lock); + + return 0; +} + +static int iaa_crypto_stats_reset(void *data, u64 value) +{ + struct iaa_device *iaa_device; + + reset_iaa_crypto_stats(); + + mutex_lock(&iaa_devices_lock); + + list_for_each_entry(iaa_device, &iaa_devices, list) + reset_device_stats(iaa_device); + + mutex_unlock(&iaa_devices_lock); + + return 0; +} + +static int wq_stats_open(struct inode *inode, struct file *file) +{ + return single_open(file, wq_stats_show, file); +} + +static const struct file_operations wq_stats_fops = { + .open = wq_stats_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +DEFINE_DEBUGFS_ATTRIBUTE(wq_stats_reset_fops, NULL, iaa_crypto_stats_reset, "%llu\n"); + +int __init iaa_crypto_debugfs_init(void) +{ + if (!debugfs_initialized()) + return -ENODEV; + + iaa_crypto_debugfs_root = debugfs_create_dir("iaa_crypto", NULL); + if (!iaa_crypto_debugfs_root) + return -ENOMEM; + + debugfs_create_u64("max_comp_delay_ns", 0644, + iaa_crypto_debugfs_root, &max_comp_delay_ns); + debugfs_create_u64("max_decomp_delay_ns", 0644, + iaa_crypto_debugfs_root, &max_decomp_delay_ns); + debugfs_create_u64("max_acomp_delay_ns", 0644, + iaa_crypto_debugfs_root, &max_comp_delay_ns); + debugfs_create_u64("max_adecomp_delay_ns", 0644, + iaa_crypto_debugfs_root, &max_decomp_delay_ns); + debugfs_create_u64("total_comp_calls", 0644, + iaa_crypto_debugfs_root, &total_comp_calls); + debugfs_create_u64("total_decomp_calls", 0644, + iaa_crypto_debugfs_root, &total_decomp_calls); + debugfs_create_u64("total_sw_decomp_calls", 0644, + iaa_crypto_debugfs_root, &total_sw_decomp_calls); + debugfs_create_u64("total_comp_bytes_out", 0644, + iaa_crypto_debugfs_root, &total_comp_bytes_out); + debugfs_create_u64("total_decomp_bytes_in", 0644, + iaa_crypto_debugfs_root, &total_decomp_bytes_in); + debugfs_create_file("wq_stats", 0644, iaa_crypto_debugfs_root, NULL, + &wq_stats_fops); + debugfs_create_file("stats_reset", 0644, iaa_crypto_debugfs_root, NULL, + &wq_stats_reset_fops); + + return 0; +} + +void __exit iaa_crypto_debugfs_cleanup(void) +{ + debugfs_remove_recursive(iaa_crypto_debugfs_root); +} + +MODULE_LICENSE("GPL"); diff --git a/drivers/crypto/intel/iaa/iaa_crypto_stats.h b/drivers/crypto/intel/iaa/iaa_crypto_stats.h new file mode 100644 index 00000000000000..c10b87b86fa456 --- /dev/null +++ b/drivers/crypto/intel/iaa/iaa_crypto_stats.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright(c) 2021 Intel Corporation. All rights rsvd. */ + +#ifndef __CRYPTO_DEV_IAA_CRYPTO_STATS_H__ +#define __CRYPTO_DEV_IAA_CRYPTO_STATS_H__ + +#if defined(CONFIG_CRYPTO_DEV_IAA_CRYPTO_STATS) +int iaa_crypto_debugfs_init(void); +void iaa_crypto_debugfs_cleanup(void); + +void update_total_comp_calls(void); +void update_total_comp_bytes_out(int n); +void update_total_decomp_calls(void); +void update_total_sw_decomp_calls(void); +void update_total_decomp_bytes_in(int n); +void update_max_comp_delay_ns(u64 start_time_ns); +void update_max_decomp_delay_ns(u64 start_time_ns); +void update_max_acomp_delay_ns(u64 start_time_ns); +void update_max_adecomp_delay_ns(u64 start_time_ns); +void update_completion_einval_errs(void); +void update_completion_timeout_errs(void); +void update_completion_comp_buf_overflow_errs(void); + +void update_wq_comp_calls(struct idxd_wq *idxd_wq); +void update_wq_comp_bytes(struct idxd_wq *idxd_wq, int n); +void update_wq_decomp_calls(struct idxd_wq *idxd_wq); +void update_wq_decomp_bytes(struct idxd_wq *idxd_wq, int n); + +#else +static inline int iaa_crypto_debugfs_init(void) { return 0; } +static inline void iaa_crypto_debugfs_cleanup(void) {} + +static inline void update_total_comp_calls(void) {} +static inline void update_total_comp_bytes_out(int n) {} +static inline void update_total_decomp_calls(void) {} +static inline void update_total_sw_decomp_calls(void) {} +static inline void update_total_decomp_bytes_in(int n) {} +static inline void update_max_comp_delay_ns(u64 start_time_ns) {} +static inline void update_max_decomp_delay_ns(u64 start_time_ns) {} +static inline void update_max_acomp_delay_ns(u64 start_time_ns) {} +static inline void update_max_adecomp_delay_ns(u64 start_time_ns) {} +static inline void update_completion_einval_errs(void) {} +static inline void update_completion_timeout_errs(void) {} +static inline void update_completion_comp_buf_overflow_errs(void) {} + +static inline void update_wq_comp_calls(struct idxd_wq *idxd_wq) {} +static inline void update_wq_comp_bytes(struct idxd_wq *idxd_wq, int n) {} +static inline void update_wq_decomp_calls(struct idxd_wq *idxd_wq) {} +static inline void update_wq_decomp_bytes(struct idxd_wq *idxd_wq, int n) {} + +#endif // CONFIG_CRYPTO_DEV_IAA_CRYPTO_STATS + +#endif diff --git a/drivers/crypto/intel/qat/Kconfig b/drivers/crypto/intel/qat/Kconfig index 1220cc86f9100a..c120f6715a09a6 100644 --- a/drivers/crypto/intel/qat/Kconfig +++ b/drivers/crypto/intel/qat/Kconfig @@ -59,6 +59,17 @@ config CRYPTO_DEV_QAT_4XXX To compile this as a module, choose M here: the module will be called qat_4xxx. +config CRYPTO_DEV_QAT_420XX + tristate "Support for Intel(R) QAT_420XX" + depends on PCI && (!CPU_BIG_ENDIAN || COMPILE_TEST) + select CRYPTO_DEV_QAT + help + Support for Intel(R) QuickAssist Technology QAT_420xx + for accelerating crypto and compression workloads. + + To compile this as a module, choose M here: the module + will be called qat_420xx. + config CRYPTO_DEV_QAT_DH895xCCVF tristate "Support for Intel(R) DH895xCC Virtual Function" depends on PCI && (!CPU_BIG_ENDIAN || COMPILE_TEST) diff --git a/drivers/crypto/intel/qat/Makefile b/drivers/crypto/intel/qat/Makefile index 258c8a626ce049..235b69f4f3f72a 100644 --- a/drivers/crypto/intel/qat/Makefile +++ b/drivers/crypto/intel/qat/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_CRYPTO_DEV_QAT_DH895xCC) += qat_dh895xcc/ obj-$(CONFIG_CRYPTO_DEV_QAT_C3XXX) += qat_c3xxx/ obj-$(CONFIG_CRYPTO_DEV_QAT_C62X) += qat_c62x/ obj-$(CONFIG_CRYPTO_DEV_QAT_4XXX) += qat_4xxx/ +obj-$(CONFIG_CRYPTO_DEV_QAT_420XX) += qat_420xx/ obj-$(CONFIG_CRYPTO_DEV_QAT_DH895xCCVF) += qat_dh895xccvf/ obj-$(CONFIG_CRYPTO_DEV_QAT_C3XXXVF) += qat_c3xxxvf/ obj-$(CONFIG_CRYPTO_DEV_QAT_C62XVF) += qat_c62xvf/ diff --git a/drivers/crypto/intel/qat/qat_420xx/Makefile b/drivers/crypto/intel/qat/qat_420xx/Makefile new file mode 100644 index 00000000000000..a90fbe00b3c88f --- /dev/null +++ b/drivers/crypto/intel/qat/qat_420xx/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only +ccflags-y := -I $(srctree)/$(src)/../qat_common +obj-$(CONFIG_CRYPTO_DEV_QAT_420XX) += qat_420xx.o +qat_420xx-objs := adf_drv.o adf_420xx_hw_data.o diff --git a/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c b/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c new file mode 100644 index 00000000000000..a87d29ae724fe4 --- /dev/null +++ b/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.c @@ -0,0 +1,528 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright(c) 2023 Intel Corporation */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "adf_420xx_hw_data.h" +#include "icp_qat_hw.h" + +#define ADF_AE_GROUP_0 GENMASK(3, 0) +#define ADF_AE_GROUP_1 GENMASK(7, 4) +#define ADF_AE_GROUP_2 GENMASK(11, 8) +#define ADF_AE_GROUP_3 GENMASK(15, 12) +#define ADF_AE_GROUP_4 BIT(16) + +#define ENA_THD_MASK_ASYM GENMASK(1, 0) +#define ENA_THD_MASK_SYM GENMASK(3, 0) +#define ENA_THD_MASK_DC GENMASK(1, 0) + +static const char * const adf_420xx_fw_objs[] = { + [ADF_FW_SYM_OBJ] = ADF_420XX_SYM_OBJ, + [ADF_FW_ASYM_OBJ] = ADF_420XX_ASYM_OBJ, + [ADF_FW_DC_OBJ] = ADF_420XX_DC_OBJ, + [ADF_FW_ADMIN_OBJ] = ADF_420XX_ADMIN_OBJ, +}; + +static const struct adf_fw_config adf_fw_cy_config[] = { + {ADF_AE_GROUP_3, ADF_FW_SYM_OBJ}, + {ADF_AE_GROUP_2, ADF_FW_ASYM_OBJ}, + {ADF_AE_GROUP_1, ADF_FW_SYM_OBJ}, + {ADF_AE_GROUP_0, ADF_FW_ASYM_OBJ}, + {ADF_AE_GROUP_4, ADF_FW_ADMIN_OBJ}, +}; + +static const struct adf_fw_config adf_fw_dc_config[] = { + {ADF_AE_GROUP_1, ADF_FW_DC_OBJ}, + {ADF_AE_GROUP_0, ADF_FW_DC_OBJ}, + {ADF_AE_GROUP_4, ADF_FW_ADMIN_OBJ}, +}; + +static const struct adf_fw_config adf_fw_sym_config[] = { + {ADF_AE_GROUP_3, ADF_FW_SYM_OBJ}, + {ADF_AE_GROUP_2, ADF_FW_SYM_OBJ}, + {ADF_AE_GROUP_1, ADF_FW_SYM_OBJ}, + {ADF_AE_GROUP_0, ADF_FW_SYM_OBJ}, + {ADF_AE_GROUP_4, ADF_FW_ADMIN_OBJ}, +}; + +static const struct adf_fw_config adf_fw_asym_config[] = { + {ADF_AE_GROUP_3, ADF_FW_ASYM_OBJ}, + {ADF_AE_GROUP_2, ADF_FW_ASYM_OBJ}, + {ADF_AE_GROUP_1, ADF_FW_ASYM_OBJ}, + {ADF_AE_GROUP_0, ADF_FW_ASYM_OBJ}, + {ADF_AE_GROUP_4, ADF_FW_ADMIN_OBJ}, +}; + +static const struct adf_fw_config adf_fw_asym_dc_config[] = { + {ADF_AE_GROUP_3, ADF_FW_ASYM_OBJ}, + {ADF_AE_GROUP_2, ADF_FW_ASYM_OBJ}, + {ADF_AE_GROUP_1, ADF_FW_ASYM_OBJ}, + {ADF_AE_GROUP_0, ADF_FW_DC_OBJ}, + {ADF_AE_GROUP_4, ADF_FW_ADMIN_OBJ}, +}; + +static const struct adf_fw_config adf_fw_sym_dc_config[] = { + {ADF_AE_GROUP_2, ADF_FW_SYM_OBJ}, + {ADF_AE_GROUP_1, ADF_FW_SYM_OBJ}, + {ADF_AE_GROUP_0, ADF_FW_DC_OBJ}, + {ADF_AE_GROUP_4, ADF_FW_ADMIN_OBJ}, +}; + +static const struct adf_fw_config adf_fw_dcc_config[] = { + {ADF_AE_GROUP_1, ADF_FW_DC_OBJ}, + {ADF_AE_GROUP_0, ADF_FW_SYM_OBJ}, + {ADF_AE_GROUP_4, ADF_FW_ADMIN_OBJ}, +}; + + +static struct adf_hw_device_class adf_420xx_class = { + .name = ADF_420XX_DEVICE_NAME, + .type = DEV_420XX, + .instances = 0, +}; + +static u32 get_ae_mask(struct adf_hw_device_data *self) +{ + u32 me_disable = self->fuses; + + return ~me_disable & ADF_420XX_ACCELENGINES_MASK; +} + +static u32 uof_get_num_objs(struct adf_accel_dev *accel_dev) +{ + switch (adf_get_service_enabled(accel_dev)) { + case SVC_CY: + case SVC_CY2: + return ARRAY_SIZE(adf_fw_cy_config); + case SVC_DC: + return ARRAY_SIZE(adf_fw_dc_config); + case SVC_DCC: + return ARRAY_SIZE(adf_fw_dcc_config); + case SVC_SYM: + return ARRAY_SIZE(adf_fw_sym_config); + case SVC_ASYM: + return ARRAY_SIZE(adf_fw_asym_config); + case SVC_ASYM_DC: + case SVC_DC_ASYM: + return ARRAY_SIZE(adf_fw_asym_dc_config); + case SVC_SYM_DC: + case SVC_DC_SYM: + return ARRAY_SIZE(adf_fw_sym_dc_config); + default: + return 0; + } +} + +static const struct adf_fw_config *get_fw_config(struct adf_accel_dev *accel_dev) +{ + switch (adf_get_service_enabled(accel_dev)) { + case SVC_CY: + case SVC_CY2: + return adf_fw_cy_config; + case SVC_DC: + return adf_fw_dc_config; + case SVC_DCC: + return adf_fw_dcc_config; + case SVC_SYM: + return adf_fw_sym_config; + case SVC_ASYM: + return adf_fw_asym_config; + case SVC_ASYM_DC: + case SVC_DC_ASYM: + return adf_fw_asym_dc_config; + case SVC_SYM_DC: + case SVC_DC_SYM: + return adf_fw_sym_dc_config; + default: + return NULL; + } +} + +static void update_ae_mask(struct adf_accel_dev *accel_dev) +{ + struct adf_hw_device_data *hw_data = GET_HW_DATA(accel_dev); + const struct adf_fw_config *fw_config; + u32 config_ae_mask = 0; + u32 ae_mask, num_objs; + int i; + + ae_mask = get_ae_mask(hw_data); + + /* Modify the AE mask based on the firmware configuration loaded */ + fw_config = get_fw_config(accel_dev); + num_objs = uof_get_num_objs(accel_dev); + + config_ae_mask |= ADF_420XX_ADMIN_AE_MASK; + for (i = 0; i < num_objs; i++) + config_ae_mask |= fw_config[i].ae_mask; + + hw_data->ae_mask = ae_mask & config_ae_mask; +} + +static u32 get_accel_cap(struct adf_accel_dev *accel_dev) +{ + u32 capabilities_sym, capabilities_asym, capabilities_dc; + struct pci_dev *pdev = accel_dev->accel_pci_dev.pci_dev; + u32 capabilities_dcc; + u32 fusectl1; + + /* As a side effect, update ae_mask based on configuration */ + update_ae_mask(accel_dev); + + /* Read accelerator capabilities mask */ + pci_read_config_dword(pdev, ADF_GEN4_FUSECTL1_OFFSET, &fusectl1); + + capabilities_sym = ICP_ACCEL_CAPABILITIES_CRYPTO_SYMMETRIC | + ICP_ACCEL_CAPABILITIES_CIPHER | + ICP_ACCEL_CAPABILITIES_AUTHENTICATION | + ICP_ACCEL_CAPABILITIES_SHA3 | + ICP_ACCEL_CAPABILITIES_SHA3_EXT | + ICP_ACCEL_CAPABILITIES_HKDF | + ICP_ACCEL_CAPABILITIES_CHACHA_POLY | + ICP_ACCEL_CAPABILITIES_AESGCM_SPC | + ICP_ACCEL_CAPABILITIES_SM3 | + ICP_ACCEL_CAPABILITIES_SM4 | + ICP_ACCEL_CAPABILITIES_AES_V2 | + ICP_ACCEL_CAPABILITIES_ZUC | + ICP_ACCEL_CAPABILITIES_ZUC_256 | + ICP_ACCEL_CAPABILITIES_WIRELESS_CRYPTO_EXT | + ICP_ACCEL_CAPABILITIES_EXT_ALGCHAIN; + + /* A set bit in fusectl1 means the feature is OFF in this SKU */ + if (fusectl1 & ICP_ACCEL_GEN4_MASK_CIPHER_SLICE) { + capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_CRYPTO_SYMMETRIC; + capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_HKDF; + capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_CIPHER; + } + + if (fusectl1 & ICP_ACCEL_GEN4_MASK_UCS_SLICE) { + capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_CHACHA_POLY; + capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_AESGCM_SPC; + capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_AES_V2; + capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_CIPHER; + } + + if (fusectl1 & ICP_ACCEL_GEN4_MASK_AUTH_SLICE) { + capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_AUTHENTICATION; + capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_SHA3; + capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_SHA3_EXT; + capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_CIPHER; + } + + if (fusectl1 & ICP_ACCEL_GEN4_MASK_SMX_SLICE) { + capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_SM3; + capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_SM4; + } + + if (fusectl1 & ICP_ACCEL_GEN4_MASK_WCP_WAT_SLICE) { + capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_ZUC; + capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_ZUC_256; + capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_WIRELESS_CRYPTO_EXT; + } + + if (fusectl1 & ICP_ACCEL_GEN4_MASK_EIA3_SLICE) { + capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_ZUC; + capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_ZUC_256; + } + + if (fusectl1 & ICP_ACCEL_GEN4_MASK_ZUC_256_SLICE) + capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_ZUC_256; + + capabilities_asym = ICP_ACCEL_CAPABILITIES_CRYPTO_ASYMMETRIC | + ICP_ACCEL_CAPABILITIES_SM2 | + ICP_ACCEL_CAPABILITIES_ECEDMONT; + + if (fusectl1 & ICP_ACCEL_GEN4_MASK_PKE_SLICE) { + capabilities_asym &= ~ICP_ACCEL_CAPABILITIES_CRYPTO_ASYMMETRIC; + capabilities_asym &= ~ICP_ACCEL_CAPABILITIES_SM2; + capabilities_asym &= ~ICP_ACCEL_CAPABILITIES_ECEDMONT; + } + + capabilities_dc = ICP_ACCEL_CAPABILITIES_COMPRESSION | + ICP_ACCEL_CAPABILITIES_LZ4_COMPRESSION | + ICP_ACCEL_CAPABILITIES_LZ4S_COMPRESSION | + ICP_ACCEL_CAPABILITIES_CNV_INTEGRITY64; + + if (fusectl1 & ICP_ACCEL_GEN4_MASK_COMPRESS_SLICE) { + capabilities_dc &= ~ICP_ACCEL_CAPABILITIES_COMPRESSION; + capabilities_dc &= ~ICP_ACCEL_CAPABILITIES_LZ4_COMPRESSION; + capabilities_dc &= ~ICP_ACCEL_CAPABILITIES_LZ4S_COMPRESSION; + capabilities_dc &= ~ICP_ACCEL_CAPABILITIES_CNV_INTEGRITY64; + } + + switch (adf_get_service_enabled(accel_dev)) { + case SVC_CY: + case SVC_CY2: + return capabilities_sym | capabilities_asym; + case SVC_DC: + return capabilities_dc; + case SVC_DCC: + /* + * Sym capabilities are available for chaining operations, + * but sym crypto instances cannot be supported + */ + capabilities_dcc = capabilities_dc | capabilities_sym; + capabilities_dcc &= ~ICP_ACCEL_CAPABILITIES_CRYPTO_SYMMETRIC; + return capabilities_dcc; + case SVC_SYM: + return capabilities_sym; + case SVC_ASYM: + return capabilities_asym; + case SVC_ASYM_DC: + case SVC_DC_ASYM: + return capabilities_asym | capabilities_dc; + case SVC_SYM_DC: + case SVC_DC_SYM: + return capabilities_sym | capabilities_dc; + default: + return 0; + } +} + +static const u32 *adf_get_arbiter_mapping(struct adf_accel_dev *accel_dev) +{ + if (adf_gen4_init_thd2arb_map(accel_dev)) + dev_warn(&GET_DEV(accel_dev), + "Generate of the thread to arbiter map failed"); + + return GET_HW_DATA(accel_dev)->thd_to_arb_map; +} + +static void adf_init_rl_data(struct adf_rl_hw_data *rl_data) +{ + rl_data->pciout_tb_offset = ADF_GEN4_RL_TOKEN_PCIEOUT_BUCKET_OFFSET; + rl_data->pciin_tb_offset = ADF_GEN4_RL_TOKEN_PCIEIN_BUCKET_OFFSET; + rl_data->r2l_offset = ADF_GEN4_RL_R2L_OFFSET; + rl_data->l2c_offset = ADF_GEN4_RL_L2C_OFFSET; + rl_data->c2s_offset = ADF_GEN4_RL_C2S_OFFSET; + + rl_data->pcie_scale_div = ADF_420XX_RL_PCIE_SCALE_FACTOR_DIV; + rl_data->pcie_scale_mul = ADF_420XX_RL_PCIE_SCALE_FACTOR_MUL; + rl_data->dcpr_correction = ADF_420XX_RL_DCPR_CORRECTION; + rl_data->max_tp[ADF_SVC_ASYM] = ADF_420XX_RL_MAX_TP_ASYM; + rl_data->max_tp[ADF_SVC_SYM] = ADF_420XX_RL_MAX_TP_SYM; + rl_data->max_tp[ADF_SVC_DC] = ADF_420XX_RL_MAX_TP_DC; + rl_data->scan_interval = ADF_420XX_RL_SCANS_PER_SEC; + rl_data->scale_ref = ADF_420XX_RL_SLICE_REF; +} + +static int get_rp_group(struct adf_accel_dev *accel_dev, u32 ae_mask) +{ + switch (ae_mask) { + case ADF_AE_GROUP_0: + return RP_GROUP_0; + case ADF_AE_GROUP_1: + case ADF_AE_GROUP_3: + return RP_GROUP_1; + case ADF_AE_GROUP_2: + if (get_fw_config(accel_dev) == adf_fw_cy_config) + return RP_GROUP_0; + else + return RP_GROUP_1; + default: + dev_dbg(&GET_DEV(accel_dev), "ae_mask not recognized"); + return -EINVAL; + } +} + +static u32 get_ena_thd_mask(struct adf_accel_dev *accel_dev, u32 obj_num) +{ + const struct adf_fw_config *fw_config; + + if (obj_num >= uof_get_num_objs(accel_dev)) + return ADF_GEN4_ENA_THD_MASK_ERROR; + + fw_config = get_fw_config(accel_dev); + if (!fw_config) + return ADF_GEN4_ENA_THD_MASK_ERROR; + + switch (fw_config[obj_num].obj) { + case ADF_FW_ASYM_OBJ: + return ENA_THD_MASK_ASYM; + case ADF_FW_SYM_OBJ: + return ENA_THD_MASK_SYM; + case ADF_FW_DC_OBJ: + return ENA_THD_MASK_DC; + default: + return ADF_GEN4_ENA_THD_MASK_ERROR; + } +} + +static u16 get_ring_to_svc_map(struct adf_accel_dev *accel_dev) +{ + enum adf_cfg_service_type rps[RP_GROUP_COUNT] = { }; + const struct adf_fw_config *fw_config; + u16 ring_to_svc_map; + int i, j; + + fw_config = get_fw_config(accel_dev); + if (!fw_config) + return 0; + + for (i = 0; i < RP_GROUP_COUNT; i++) { + switch (fw_config[i].ae_mask) { + case ADF_AE_GROUP_0: + j = RP_GROUP_0; + break; + case ADF_AE_GROUP_1: + j = RP_GROUP_1; + break; + default: + return 0; + } + + switch (fw_config[i].obj) { + case ADF_FW_SYM_OBJ: + rps[j] = SYM; + break; + case ADF_FW_ASYM_OBJ: + rps[j] = ASYM; + break; + case ADF_FW_DC_OBJ: + rps[j] = COMP; + break; + default: + rps[j] = 0; + break; + } + } + + ring_to_svc_map = rps[RP_GROUP_0] << ADF_CFG_SERV_RING_PAIR_0_SHIFT | + rps[RP_GROUP_1] << ADF_CFG_SERV_RING_PAIR_1_SHIFT | + rps[RP_GROUP_0] << ADF_CFG_SERV_RING_PAIR_2_SHIFT | + rps[RP_GROUP_1] << ADF_CFG_SERV_RING_PAIR_3_SHIFT; + + return ring_to_svc_map; +} + +static const char *uof_get_name(struct adf_accel_dev *accel_dev, u32 obj_num, + const char * const fw_objs[], int num_objs) +{ + const struct adf_fw_config *fw_config; + int id; + + fw_config = get_fw_config(accel_dev); + if (fw_config) + id = fw_config[obj_num].obj; + else + id = -EINVAL; + + if (id < 0 || id > num_objs) + return NULL; + + return fw_objs[id]; +} + +static const char *uof_get_name_420xx(struct adf_accel_dev *accel_dev, u32 obj_num) +{ + int num_fw_objs = ARRAY_SIZE(adf_420xx_fw_objs); + + return uof_get_name(accel_dev, obj_num, adf_420xx_fw_objs, num_fw_objs); +} + +static u32 uof_get_ae_mask(struct adf_accel_dev *accel_dev, u32 obj_num) +{ + const struct adf_fw_config *fw_config; + + fw_config = get_fw_config(accel_dev); + if (!fw_config) + return 0; + + return fw_config[obj_num].ae_mask; +} + +static void adf_gen4_set_err_mask(struct adf_dev_err_mask *dev_err_mask) +{ + dev_err_mask->cppagentcmdpar_mask = ADF_420XX_HICPPAGENTCMDPARERRLOG_MASK; + dev_err_mask->parerr_ath_cph_mask = ADF_420XX_PARITYERRORMASK_ATH_CPH_MASK; + dev_err_mask->parerr_cpr_xlt_mask = ADF_420XX_PARITYERRORMASK_CPR_XLT_MASK; + dev_err_mask->parerr_dcpr_ucs_mask = ADF_420XX_PARITYERRORMASK_DCPR_UCS_MASK; + dev_err_mask->parerr_pke_mask = ADF_420XX_PARITYERRORMASK_PKE_MASK; + dev_err_mask->ssmfeatren_mask = ADF_420XX_SSMFEATREN_MASK; +} + +void adf_init_hw_data_420xx(struct adf_hw_device_data *hw_data, u32 dev_id) +{ + hw_data->dev_class = &adf_420xx_class; + hw_data->instance_id = adf_420xx_class.instances++; + hw_data->num_banks = ADF_GEN4_ETR_MAX_BANKS; + hw_data->num_banks_per_vf = ADF_GEN4_NUM_BANKS_PER_VF; + hw_data->num_rings_per_bank = ADF_GEN4_NUM_RINGS_PER_BANK; + hw_data->num_accel = ADF_GEN4_MAX_ACCELERATORS; + hw_data->num_engines = ADF_420XX_MAX_ACCELENGINES; + hw_data->num_logical_accel = 1; + hw_data->tx_rx_gap = ADF_GEN4_RX_RINGS_OFFSET; + hw_data->tx_rings_mask = ADF_GEN4_TX_RINGS_MASK; + hw_data->ring_to_svc_map = ADF_GEN4_DEFAULT_RING_TO_SRV_MAP; + hw_data->alloc_irq = adf_isr_resource_alloc; + hw_data->free_irq = adf_isr_resource_free; + hw_data->enable_error_correction = adf_gen4_enable_error_correction; + hw_data->get_accel_mask = adf_gen4_get_accel_mask; + hw_data->get_ae_mask = get_ae_mask; + hw_data->get_num_accels = adf_gen4_get_num_accels; + hw_data->get_num_aes = adf_gen4_get_num_aes; + hw_data->get_sram_bar_id = adf_gen4_get_sram_bar_id; + hw_data->get_etr_bar_id = adf_gen4_get_etr_bar_id; + hw_data->get_misc_bar_id = adf_gen4_get_misc_bar_id; + hw_data->get_arb_info = adf_gen4_get_arb_info; + hw_data->get_admin_info = adf_gen4_get_admin_info; + hw_data->get_accel_cap = get_accel_cap; + hw_data->get_sku = adf_gen4_get_sku; + hw_data->init_admin_comms = adf_init_admin_comms; + hw_data->exit_admin_comms = adf_exit_admin_comms; + hw_data->send_admin_init = adf_send_admin_init; + hw_data->init_arb = adf_init_arb; + hw_data->exit_arb = adf_exit_arb; + hw_data->get_arb_mapping = adf_get_arbiter_mapping; + hw_data->enable_ints = adf_gen4_enable_ints; + hw_data->init_device = adf_gen4_init_device; + hw_data->reset_device = adf_reset_flr; + hw_data->admin_ae_mask = ADF_420XX_ADMIN_AE_MASK; + hw_data->num_rps = ADF_GEN4_MAX_RPS; + hw_data->fw_name = ADF_420XX_FW; + hw_data->fw_mmp_name = ADF_420XX_MMP; + hw_data->uof_get_name = uof_get_name_420xx; + hw_data->uof_get_num_objs = uof_get_num_objs; + hw_data->uof_get_ae_mask = uof_get_ae_mask; + hw_data->get_rp_group = get_rp_group; + hw_data->get_ena_thd_mask = get_ena_thd_mask; + hw_data->set_msix_rttable = adf_gen4_set_msix_default_rttable; + hw_data->set_ssm_wdtimer = adf_gen4_set_ssm_wdtimer; + hw_data->get_ring_to_svc_map = get_ring_to_svc_map; + hw_data->disable_iov = adf_disable_sriov; + hw_data->ring_pair_reset = adf_gen4_ring_pair_reset; + hw_data->enable_pm = adf_gen4_enable_pm; + hw_data->handle_pm_interrupt = adf_gen4_handle_pm_interrupt; + hw_data->dev_config = adf_gen4_dev_config; + hw_data->start_timer = adf_gen4_timer_start; + hw_data->stop_timer = adf_gen4_timer_stop; + hw_data->get_hb_clock = adf_gen4_get_heartbeat_clock; + hw_data->num_hb_ctrs = ADF_NUM_HB_CNT_PER_AE; + hw_data->clock_frequency = ADF_420XX_AE_FREQ; + + adf_gen4_set_err_mask(&hw_data->dev_err_mask); + adf_gen4_init_hw_csr_ops(&hw_data->csr_ops); + adf_gen4_init_pf_pfvf_ops(&hw_data->pfvf_ops); + adf_gen4_init_dc_ops(&hw_data->dc_ops); + adf_gen4_init_ras_ops(&hw_data->ras_ops); + adf_gen4_init_tl_data(&hw_data->tl_data); + adf_init_rl_data(&hw_data->rl_data); +} + +void adf_clean_hw_data_420xx(struct adf_hw_device_data *hw_data) +{ + hw_data->dev_class->instances--; +} diff --git a/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.h b/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.h new file mode 100644 index 00000000000000..99abbfc1482063 --- /dev/null +++ b/drivers/crypto/intel/qat/qat_420xx/adf_420xx_hw_data.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright(c) 2023 Intel Corporation */ +#ifndef ADF_420XX_HW_DATA_H_ +#define ADF_420XX_HW_DATA_H_ + +#include + +#define ADF_420XX_MAX_ACCELENGINES 17 + +#define ADF_420XX_ACCELENGINES_MASK 0x1FFFF +#define ADF_420XX_ADMIN_AE_MASK 0x10000 + +#define ADF_420XX_HICPPAGENTCMDPARERRLOG_MASK (0xFF) +#define ADF_420XX_PARITYERRORMASK_ATH_CPH_MASK (0xFF00FF) +#define ADF_420XX_PARITYERRORMASK_CPR_XLT_MASK (0x10001) +#define ADF_420XX_PARITYERRORMASK_DCPR_UCS_MASK (0xF0007) +#define ADF_420XX_PARITYERRORMASK_PKE_MASK (0xFFF) +#define ADF_420XX_PARITYERRORMASK_WAT_WCP_MASK (0x3FF03FF) + +/* + * SSMFEATREN bit mask + * BIT(4) - enables parity detection on CPP + * BIT(12) - enables the logging of push/pull data errors + * in pperr register + * BIT(16) - BIT(27) - enable parity detection on SPPs + */ +#define ADF_420XX_SSMFEATREN_MASK \ + (BIT(4) | BIT(12) | BIT(16) | BIT(17) | BIT(18) | BIT(19) | BIT(20) | \ + BIT(21) | BIT(22) | BIT(23) | BIT(24) | BIT(25) | BIT(26) | BIT(27)) + +/* Firmware Binaries */ +#define ADF_420XX_FW "qat_420xx.bin" +#define ADF_420XX_MMP "qat_420xx_mmp.bin" +#define ADF_420XX_SYM_OBJ "qat_420xx_sym.bin" +#define ADF_420XX_DC_OBJ "qat_420xx_dc.bin" +#define ADF_420XX_ASYM_OBJ "qat_420xx_asym.bin" +#define ADF_420XX_ADMIN_OBJ "qat_420xx_admin.bin" + +/* RL constants */ +#define ADF_420XX_RL_PCIE_SCALE_FACTOR_DIV 100 +#define ADF_420XX_RL_PCIE_SCALE_FACTOR_MUL 102 +#define ADF_420XX_RL_DCPR_CORRECTION 1 +#define ADF_420XX_RL_SCANS_PER_SEC 954 +#define ADF_420XX_RL_MAX_TP_ASYM 173750UL +#define ADF_420XX_RL_MAX_TP_SYM 95000UL +#define ADF_420XX_RL_MAX_TP_DC 40000UL +#define ADF_420XX_RL_SLICE_REF 1000UL + +/* Clocks frequency */ +#define ADF_420XX_AE_FREQ (1000 * HZ_PER_MHZ) + +void adf_init_hw_data_420xx(struct adf_hw_device_data *hw_data, u32 dev_id); +void adf_clean_hw_data_420xx(struct adf_hw_device_data *hw_data); + +#endif diff --git a/drivers/crypto/intel/qat/qat_420xx/adf_drv.c b/drivers/crypto/intel/qat/qat_420xx/adf_drv.c new file mode 100644 index 00000000000000..2a3598409eeb51 --- /dev/null +++ b/drivers/crypto/intel/qat/qat_420xx/adf_drv.c @@ -0,0 +1,202 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright(c) 2023 Intel Corporation */ +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "adf_420xx_hw_data.h" + +static const struct pci_device_id adf_pci_tbl[] = { + { PCI_VDEVICE(INTEL, ADF_420XX_PCI_DEVICE_ID), }, + { } +}; +MODULE_DEVICE_TABLE(pci, adf_pci_tbl); + +static void adf_cleanup_accel(struct adf_accel_dev *accel_dev) +{ + if (accel_dev->hw_device) { + adf_clean_hw_data_420xx(accel_dev->hw_device); + accel_dev->hw_device = NULL; + } + adf_dbgfs_exit(accel_dev); + adf_cfg_dev_remove(accel_dev); + adf_devmgr_rm_dev(accel_dev, NULL); +} + +static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + struct adf_accel_dev *accel_dev; + struct adf_accel_pci *accel_pci_dev; + struct adf_hw_device_data *hw_data; + unsigned int i, bar_nr; + unsigned long bar_mask; + struct adf_bar *bar; + int ret; + + if (num_possible_nodes() > 1 && dev_to_node(&pdev->dev) < 0) { + /* + * If the accelerator is connected to a node with no memory + * there is no point in using the accelerator since the remote + * memory transaction will be very slow. + */ + dev_err(&pdev->dev, "Invalid NUMA configuration.\n"); + return -EINVAL; + } + + accel_dev = devm_kzalloc(&pdev->dev, sizeof(*accel_dev), GFP_KERNEL); + if (!accel_dev) + return -ENOMEM; + + INIT_LIST_HEAD(&accel_dev->crypto_list); + accel_pci_dev = &accel_dev->accel_pci_dev; + accel_pci_dev->pci_dev = pdev; + + /* + * Add accel device to accel table + * This should be called before adf_cleanup_accel is called + */ + if (adf_devmgr_add_dev(accel_dev, NULL)) { + dev_err(&pdev->dev, "Failed to add new accelerator device.\n"); + return -EFAULT; + } + + accel_dev->owner = THIS_MODULE; + /* Allocate and initialise device hardware meta-data structure */ + hw_data = devm_kzalloc(&pdev->dev, sizeof(*hw_data), GFP_KERNEL); + if (!hw_data) { + ret = -ENOMEM; + goto out_err; + } + + accel_dev->hw_device = hw_data; + adf_init_hw_data_420xx(accel_dev->hw_device, ent->device); + + pci_read_config_byte(pdev, PCI_REVISION_ID, &accel_pci_dev->revid); + pci_read_config_dword(pdev, ADF_GEN4_FUSECTL4_OFFSET, &hw_data->fuses); + + /* Get Accelerators and Accelerators Engines masks */ + hw_data->accel_mask = hw_data->get_accel_mask(hw_data); + hw_data->ae_mask = hw_data->get_ae_mask(hw_data); + accel_pci_dev->sku = hw_data->get_sku(hw_data); + /* If the device has no acceleration engines then ignore it */ + if (!hw_data->accel_mask || !hw_data->ae_mask || + (~hw_data->ae_mask & 0x01)) { + dev_err(&pdev->dev, "No acceleration units found.\n"); + ret = -EFAULT; + goto out_err; + } + + /* Create device configuration table */ + ret = adf_cfg_dev_add(accel_dev); + if (ret) + goto out_err; + + /* Enable PCI device */ + ret = pcim_enable_device(pdev); + if (ret) { + dev_err(&pdev->dev, "Can't enable PCI device.\n"); + goto out_err; + } + + /* Set DMA identifier */ + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (ret) { + dev_err(&pdev->dev, "No usable DMA configuration.\n"); + goto out_err; + } + + ret = adf_gen4_cfg_dev_init(accel_dev); + if (ret) { + dev_err(&pdev->dev, "Failed to initialize configuration.\n"); + goto out_err; + } + + /* Get accelerator capabilities mask */ + hw_data->accel_capabilities_mask = hw_data->get_accel_cap(accel_dev); + if (!hw_data->accel_capabilities_mask) { + dev_err(&pdev->dev, "Failed to get capabilities mask.\n"); + ret = -EINVAL; + goto out_err; + } + + /* Find and map all the device's BARS */ + bar_mask = pci_select_bars(pdev, IORESOURCE_MEM) & ADF_GEN4_BAR_MASK; + + ret = pcim_iomap_regions_request_all(pdev, bar_mask, pci_name(pdev)); + if (ret) { + dev_err(&pdev->dev, "Failed to map pci regions.\n"); + goto out_err; + } + + i = 0; + for_each_set_bit(bar_nr, &bar_mask, PCI_STD_NUM_BARS) { + bar = &accel_pci_dev->pci_bars[i++]; + bar->virt_addr = pcim_iomap_table(pdev)[bar_nr]; + } + + pci_set_master(pdev); + + if (pci_save_state(pdev)) { + dev_err(&pdev->dev, "Failed to save pci state.\n"); + ret = -ENOMEM; + goto out_err; + } + + accel_dev->ras_errors.enabled = true; + adf_dbgfs_init(accel_dev); + + ret = adf_dev_up(accel_dev, true); + if (ret) + goto out_err_dev_stop; + + ret = adf_sysfs_init(accel_dev); + if (ret) + goto out_err_dev_stop; + + return ret; + +out_err_dev_stop: + adf_dev_down(accel_dev, false); +out_err: + adf_cleanup_accel(accel_dev); + return ret; +} + +static void adf_remove(struct pci_dev *pdev) +{ + struct adf_accel_dev *accel_dev = adf_devmgr_pci_to_accel_dev(pdev); + + if (!accel_dev) { + pr_err("QAT: Driver removal failed\n"); + return; + } + adf_dev_down(accel_dev, false); + adf_cleanup_accel(accel_dev); +} + +static struct pci_driver adf_driver = { + .id_table = adf_pci_tbl, + .name = ADF_420XX_DEVICE_NAME, + .probe = adf_probe, + .remove = adf_remove, + .sriov_configure = adf_sriov_configure, + .err_handler = &adf_err_handler, +}; + +module_pci_driver(adf_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Intel"); +MODULE_FIRMWARE(ADF_420XX_FW); +MODULE_FIRMWARE(ADF_420XX_MMP); +MODULE_DESCRIPTION("Intel(R) QuickAssist Technology"); +MODULE_VERSION(ADF_DRV_VERSION); +MODULE_SOFTDEP("pre: crypto-intel_qat"); +MODULE_IMPORT_NS(CRYPTO_QAT); diff --git a/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c b/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c index 0faedb5b2eb5a8..479062aa5e6b61 100644 --- a/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c +++ b/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.c @@ -7,12 +7,15 @@ #include #include #include +#include +#include #include #include #include #include #include "adf_gen4_ras.h" #include +#include #include "adf_4xxx_hw_data.h" #include "icp_qat_hw.h" @@ -20,12 +23,10 @@ #define ADF_AE_GROUP_1 GENMASK(7, 4) #define ADF_AE_GROUP_2 BIT(8) -enum adf_fw_objs { - ADF_FW_SYM_OBJ, - ADF_FW_ASYM_OBJ, - ADF_FW_DC_OBJ, - ADF_FW_ADMIN_OBJ, -}; +#define ENA_THD_MASK_ASYM GENMASK(1, 0) +#define ENA_THD_MASK_ASYM_401XX GENMASK(5, 0) +#define ENA_THD_MASK_SYM GENMASK(6, 0) +#define ENA_THD_MASK_DC GENMASK(1, 0) static const char * const adf_4xxx_fw_objs[] = { [ADF_FW_SYM_OBJ] = ADF_4XXX_SYM_OBJ, @@ -41,11 +42,6 @@ static const char * const adf_402xx_fw_objs[] = { [ADF_FW_ADMIN_OBJ] = ADF_402XX_ADMIN_OBJ, }; -struct adf_fw_config { - u32 ae_mask; - enum adf_fw_objs obj; -}; - static const struct adf_fw_config adf_fw_cy_config[] = { {ADF_AE_GROUP_1, ADF_FW_SYM_OBJ}, {ADF_AE_GROUP_0, ADF_FW_ASYM_OBJ}, @@ -95,59 +91,12 @@ static_assert(ARRAY_SIZE(adf_fw_cy_config) == ARRAY_SIZE(adf_fw_asym_dc_config)) static_assert(ARRAY_SIZE(adf_fw_cy_config) == ARRAY_SIZE(adf_fw_sym_dc_config)); static_assert(ARRAY_SIZE(adf_fw_cy_config) == ARRAY_SIZE(adf_fw_dcc_config)); -/* Worker thread to service arbiter mappings */ -static const u32 default_thrd_to_arb_map[ADF_4XXX_MAX_ACCELENGINES] = { - 0x5555555, 0x5555555, 0x5555555, 0x5555555, - 0xAAAAAAA, 0xAAAAAAA, 0xAAAAAAA, 0xAAAAAAA, - 0x0 -}; - -static const u32 thrd_to_arb_map_dc[ADF_4XXX_MAX_ACCELENGINES] = { - 0x000000FF, 0x000000FF, 0x000000FF, 0x000000FF, - 0x000000FF, 0x000000FF, 0x000000FF, 0x000000FF, - 0x0 -}; - -static const u32 thrd_to_arb_map_dcc[ADF_4XXX_MAX_ACCELENGINES] = { - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, - 0x0 -}; - static struct adf_hw_device_class adf_4xxx_class = { .name = ADF_4XXX_DEVICE_NAME, .type = DEV_4XXX, .instances = 0, }; -static int get_service_enabled(struct adf_accel_dev *accel_dev) -{ - char services[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = {0}; - int ret; - - ret = adf_cfg_get_param_value(accel_dev, ADF_GENERAL_SEC, - ADF_SERVICES_ENABLED, services); - if (ret) { - dev_err(&GET_DEV(accel_dev), - ADF_SERVICES_ENABLED " param not found\n"); - return ret; - } - - ret = match_string(adf_cfg_services, ARRAY_SIZE(adf_cfg_services), - services); - if (ret < 0) - dev_err(&GET_DEV(accel_dev), - "Invalid value of " ADF_SERVICES_ENABLED " param: %s\n", - services); - - return ret; -} - -static u32 get_accel_mask(struct adf_hw_device_data *self) -{ - return ADF_4XXX_ACCELERATORS_MASK; -} - static u32 get_ae_mask(struct adf_hw_device_data *self) { u32 me_disable = self->fuses; @@ -155,55 +104,6 @@ static u32 get_ae_mask(struct adf_hw_device_data *self) return ~me_disable & ADF_4XXX_ACCELENGINES_MASK; } -static u32 get_num_accels(struct adf_hw_device_data *self) -{ - return ADF_4XXX_MAX_ACCELERATORS; -} - -static u32 get_num_aes(struct adf_hw_device_data *self) -{ - if (!self || !self->ae_mask) - return 0; - - return hweight32(self->ae_mask); -} - -static u32 get_misc_bar_id(struct adf_hw_device_data *self) -{ - return ADF_4XXX_PMISC_BAR; -} - -static u32 get_etr_bar_id(struct adf_hw_device_data *self) -{ - return ADF_4XXX_ETR_BAR; -} - -static u32 get_sram_bar_id(struct adf_hw_device_data *self) -{ - return ADF_4XXX_SRAM_BAR; -} - -/* - * The vector routing table is used to select the MSI-X entry to use for each - * interrupt source. - * The first ADF_4XXX_ETR_MAX_BANKS entries correspond to ring interrupts. - * The final entry corresponds to VF2PF or error interrupts. - * This vector table could be used to configure one MSI-X entry to be shared - * between multiple interrupt sources. - * - * The default routing is set to have a one to one correspondence between the - * interrupt source and the MSI-X entry used. - */ -static void set_msix_default_rttable(struct adf_accel_dev *accel_dev) -{ - void __iomem *csr; - int i; - - csr = (&GET_BARS(accel_dev)[ADF_4XXX_PMISC_BAR])->virt_addr; - for (i = 0; i <= ADF_4XXX_ETR_MAX_BANKS; i++) - ADF_CSR_WR(csr, ADF_4XXX_MSIX_RTTABLE_OFFSET(i), i); -} - static u32 get_accel_cap(struct adf_accel_dev *accel_dev) { struct pci_dev *pdev = accel_dev->accel_pci_dev.pci_dev; @@ -212,7 +112,7 @@ static u32 get_accel_cap(struct adf_accel_dev *accel_dev) u32 fusectl1; /* Read accelerator capabilities mask */ - pci_read_config_dword(pdev, ADF_4XXX_FUSECTL1_OFFSET, &fusectl1); + pci_read_config_dword(pdev, ADF_GEN4_FUSECTL1_OFFSET, &fusectl1); capabilities_sym = ICP_ACCEL_CAPABILITIES_CRYPTO_SYMMETRIC | ICP_ACCEL_CAPABILITIES_CIPHER | @@ -227,27 +127,27 @@ static u32 get_accel_cap(struct adf_accel_dev *accel_dev) ICP_ACCEL_CAPABILITIES_AES_V2; /* A set bit in fusectl1 means the feature is OFF in this SKU */ - if (fusectl1 & ICP_ACCEL_4XXX_MASK_CIPHER_SLICE) { + if (fusectl1 & ICP_ACCEL_GEN4_MASK_CIPHER_SLICE) { capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_CRYPTO_SYMMETRIC; capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_HKDF; capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_CIPHER; } - if (fusectl1 & ICP_ACCEL_4XXX_MASK_UCS_SLICE) { + if (fusectl1 & ICP_ACCEL_GEN4_MASK_UCS_SLICE) { capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_CHACHA_POLY; capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_AESGCM_SPC; capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_AES_V2; capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_CIPHER; } - if (fusectl1 & ICP_ACCEL_4XXX_MASK_AUTH_SLICE) { + if (fusectl1 & ICP_ACCEL_GEN4_MASK_AUTH_SLICE) { capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_AUTHENTICATION; capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_SHA3; capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_SHA3_EXT; capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_CIPHER; } - if (fusectl1 & ICP_ACCEL_4XXX_MASK_SMX_SLICE) { + if (fusectl1 & ICP_ACCEL_GEN4_MASK_SMX_SLICE) { capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_SM3; capabilities_sym &= ~ICP_ACCEL_CAPABILITIES_SM4; } @@ -257,7 +157,7 @@ static u32 get_accel_cap(struct adf_accel_dev *accel_dev) ICP_ACCEL_CAPABILITIES_SM2 | ICP_ACCEL_CAPABILITIES_ECEDMONT; - if (fusectl1 & ICP_ACCEL_4XXX_MASK_PKE_SLICE) { + if (fusectl1 & ICP_ACCEL_GEN4_MASK_PKE_SLICE) { capabilities_asym &= ~ICP_ACCEL_CAPABILITIES_CRYPTO_ASYMMETRIC; capabilities_asym &= ~ICP_ACCEL_CAPABILITIES_SM2; capabilities_asym &= ~ICP_ACCEL_CAPABILITIES_ECEDMONT; @@ -268,14 +168,14 @@ static u32 get_accel_cap(struct adf_accel_dev *accel_dev) ICP_ACCEL_CAPABILITIES_LZ4S_COMPRESSION | ICP_ACCEL_CAPABILITIES_CNV_INTEGRITY64; - if (fusectl1 & ICP_ACCEL_4XXX_MASK_COMPRESS_SLICE) { + if (fusectl1 & ICP_ACCEL_GEN4_MASK_COMPRESS_SLICE) { capabilities_dc &= ~ICP_ACCEL_CAPABILITIES_COMPRESSION; capabilities_dc &= ~ICP_ACCEL_CAPABILITIES_LZ4_COMPRESSION; capabilities_dc &= ~ICP_ACCEL_CAPABILITIES_LZ4S_COMPRESSION; capabilities_dc &= ~ICP_ACCEL_CAPABILITIES_CNV_INTEGRITY64; } - switch (get_service_enabled(accel_dev)) { + switch (adf_get_service_enabled(accel_dev)) { case SVC_CY: case SVC_CY2: return capabilities_sym | capabilities_asym; @@ -304,43 +204,13 @@ static u32 get_accel_cap(struct adf_accel_dev *accel_dev) } } -static enum dev_sku_info get_sku(struct adf_hw_device_data *self) -{ - return DEV_SKU_1; -} - static const u32 *adf_get_arbiter_mapping(struct adf_accel_dev *accel_dev) { - switch (get_service_enabled(accel_dev)) { - case SVC_DC: - return thrd_to_arb_map_dc; - case SVC_DCC: - return thrd_to_arb_map_dcc; - default: - return default_thrd_to_arb_map; - } -} - -static void get_arb_info(struct arb_info *arb_info) -{ - arb_info->arb_cfg = ADF_4XXX_ARB_CONFIG; - arb_info->arb_offset = ADF_4XXX_ARB_OFFSET; - arb_info->wt2sam_offset = ADF_4XXX_ARB_WRK_2_SER_MAP_OFFSET; -} + if (adf_gen4_init_thd2arb_map(accel_dev)) + dev_warn(&GET_DEV(accel_dev), + "Generate of the thread to arbiter map failed"); -static void get_admin_info(struct admin_info *admin_csrs_info) -{ - admin_csrs_info->mailbox_offset = ADF_4XXX_MAILBOX_BASE_OFFSET; - admin_csrs_info->admin_msg_ur = ADF_4XXX_ADMINMSGUR_OFFSET; - admin_csrs_info->admin_msg_lr = ADF_4XXX_ADMINMSGLR_OFFSET; -} - -static u32 get_heartbeat_clock(struct adf_hw_device_data *self) -{ - /* - * 4XXX uses KPT counter for HB - */ - return ADF_4XXX_KPT_COUNTER_FREQ; + return GET_HW_DATA(accel_dev)->thd_to_arb_map; } static void adf_init_rl_data(struct adf_rl_hw_data *rl_data) @@ -361,66 +231,14 @@ static void adf_init_rl_data(struct adf_rl_hw_data *rl_data) rl_data->scale_ref = ADF_4XXX_RL_SLICE_REF; } -static void adf_enable_error_correction(struct adf_accel_dev *accel_dev) -{ - struct adf_bar *misc_bar = &GET_BARS(accel_dev)[ADF_4XXX_PMISC_BAR]; - void __iomem *csr = misc_bar->virt_addr; - - /* Enable all in errsou3 except VFLR notification on host */ - ADF_CSR_WR(csr, ADF_GEN4_ERRMSK3, ADF_GEN4_VFLNOTIFY); -} - -static void adf_enable_ints(struct adf_accel_dev *accel_dev) -{ - void __iomem *addr; - - addr = (&GET_BARS(accel_dev)[ADF_4XXX_PMISC_BAR])->virt_addr; - - /* Enable bundle interrupts */ - ADF_CSR_WR(addr, ADF_4XXX_SMIAPF_RP_X0_MASK_OFFSET, 0); - ADF_CSR_WR(addr, ADF_4XXX_SMIAPF_RP_X1_MASK_OFFSET, 0); - - /* Enable misc interrupts */ - ADF_CSR_WR(addr, ADF_4XXX_SMIAPF_MASK_OFFSET, 0); -} - -static int adf_init_device(struct adf_accel_dev *accel_dev) -{ - void __iomem *addr; - u32 status; - u32 csr; - int ret; - - addr = (&GET_BARS(accel_dev)[ADF_4XXX_PMISC_BAR])->virt_addr; - - /* Temporarily mask PM interrupt */ - csr = ADF_CSR_RD(addr, ADF_GEN4_ERRMSK2); - csr |= ADF_GEN4_PM_SOU; - ADF_CSR_WR(addr, ADF_GEN4_ERRMSK2, csr); - - /* Set DRV_ACTIVE bit to power up the device */ - ADF_CSR_WR(addr, ADF_GEN4_PM_INTERRUPT, ADF_GEN4_PM_DRV_ACTIVE); - - /* Poll status register to make sure the device is powered up */ - ret = read_poll_timeout(ADF_CSR_RD, status, - status & ADF_GEN4_PM_INIT_STATE, - ADF_GEN4_PM_POLL_DELAY_US, - ADF_GEN4_PM_POLL_TIMEOUT_US, true, addr, - ADF_GEN4_PM_STATUS); - if (ret) - dev_err(&GET_DEV(accel_dev), "Failed to power up the device\n"); - - return ret; -} - -static u32 uof_get_num_objs(void) +static u32 uof_get_num_objs(struct adf_accel_dev *accel_dev) { return ARRAY_SIZE(adf_fw_cy_config); } static const struct adf_fw_config *get_fw_config(struct adf_accel_dev *accel_dev) { - switch (get_service_enabled(accel_dev)) { + switch (adf_get_service_enabled(accel_dev)) { case SVC_CY: case SVC_CY2: return adf_fw_cy_config; @@ -443,11 +261,64 @@ static const struct adf_fw_config *get_fw_config(struct adf_accel_dev *accel_dev } } -enum adf_rp_groups { - RP_GROUP_0 = 0, - RP_GROUP_1, - RP_GROUP_COUNT -}; +static int get_rp_group(struct adf_accel_dev *accel_dev, u32 ae_mask) +{ + switch (ae_mask) { + case ADF_AE_GROUP_0: + return RP_GROUP_0; + case ADF_AE_GROUP_1: + return RP_GROUP_1; + default: + dev_dbg(&GET_DEV(accel_dev), "ae_mask not recognized"); + return -EINVAL; + } +} + +static u32 get_ena_thd_mask(struct adf_accel_dev *accel_dev, u32 obj_num) +{ + const struct adf_fw_config *fw_config; + + if (obj_num >= uof_get_num_objs(accel_dev)) + return ADF_GEN4_ENA_THD_MASK_ERROR; + + fw_config = get_fw_config(accel_dev); + if (!fw_config) + return ADF_GEN4_ENA_THD_MASK_ERROR; + + switch (fw_config[obj_num].obj) { + case ADF_FW_ASYM_OBJ: + return ENA_THD_MASK_ASYM; + case ADF_FW_SYM_OBJ: + return ENA_THD_MASK_SYM; + case ADF_FW_DC_OBJ: + return ENA_THD_MASK_DC; + default: + return ADF_GEN4_ENA_THD_MASK_ERROR; + } +} + +static u32 get_ena_thd_mask_401xx(struct adf_accel_dev *accel_dev, u32 obj_num) +{ + const struct adf_fw_config *fw_config; + + if (obj_num >= uof_get_num_objs(accel_dev)) + return ADF_GEN4_ENA_THD_MASK_ERROR; + + fw_config = get_fw_config(accel_dev); + if (!fw_config) + return ADF_GEN4_ENA_THD_MASK_ERROR; + + switch (fw_config[obj_num].obj) { + case ADF_FW_ASYM_OBJ: + return ENA_THD_MASK_ASYM_401XX; + case ADF_FW_SYM_OBJ: + return ENA_THD_MASK_SYM; + case ADF_FW_DC_OBJ: + return ENA_THD_MASK_DC; + default: + return ADF_GEN4_ENA_THD_MASK_ERROR; + } +} static u16 get_ring_to_svc_map(struct adf_accel_dev *accel_dev) { @@ -553,54 +424,63 @@ void adf_init_hw_data_4xxx(struct adf_hw_device_data *hw_data, u32 dev_id) { hw_data->dev_class = &adf_4xxx_class; hw_data->instance_id = adf_4xxx_class.instances++; - hw_data->num_banks = ADF_4XXX_ETR_MAX_BANKS; - hw_data->num_banks_per_vf = ADF_4XXX_NUM_BANKS_PER_VF; - hw_data->num_rings_per_bank = ADF_4XXX_NUM_RINGS_PER_BANK; - hw_data->num_accel = ADF_4XXX_MAX_ACCELERATORS; + hw_data->num_banks = ADF_GEN4_ETR_MAX_BANKS; + hw_data->num_banks_per_vf = ADF_GEN4_NUM_BANKS_PER_VF; + hw_data->num_rings_per_bank = ADF_GEN4_NUM_RINGS_PER_BANK; + hw_data->num_accel = ADF_GEN4_MAX_ACCELERATORS; hw_data->num_engines = ADF_4XXX_MAX_ACCELENGINES; hw_data->num_logical_accel = 1; - hw_data->tx_rx_gap = ADF_4XXX_RX_RINGS_OFFSET; - hw_data->tx_rings_mask = ADF_4XXX_TX_RINGS_MASK; + hw_data->tx_rx_gap = ADF_GEN4_RX_RINGS_OFFSET; + hw_data->tx_rings_mask = ADF_GEN4_TX_RINGS_MASK; hw_data->ring_to_svc_map = ADF_GEN4_DEFAULT_RING_TO_SRV_MAP; hw_data->alloc_irq = adf_isr_resource_alloc; hw_data->free_irq = adf_isr_resource_free; - hw_data->enable_error_correction = adf_enable_error_correction; - hw_data->get_accel_mask = get_accel_mask; + hw_data->enable_error_correction = adf_gen4_enable_error_correction; + hw_data->get_accel_mask = adf_gen4_get_accel_mask; hw_data->get_ae_mask = get_ae_mask; - hw_data->get_num_accels = get_num_accels; - hw_data->get_num_aes = get_num_aes; - hw_data->get_sram_bar_id = get_sram_bar_id; - hw_data->get_etr_bar_id = get_etr_bar_id; - hw_data->get_misc_bar_id = get_misc_bar_id; - hw_data->get_arb_info = get_arb_info; - hw_data->get_admin_info = get_admin_info; + hw_data->get_num_accels = adf_gen4_get_num_accels; + hw_data->get_num_aes = adf_gen4_get_num_aes; + hw_data->get_sram_bar_id = adf_gen4_get_sram_bar_id; + hw_data->get_etr_bar_id = adf_gen4_get_etr_bar_id; + hw_data->get_misc_bar_id = adf_gen4_get_misc_bar_id; + hw_data->get_arb_info = adf_gen4_get_arb_info; + hw_data->get_admin_info = adf_gen4_get_admin_info; hw_data->get_accel_cap = get_accel_cap; - hw_data->get_sku = get_sku; + hw_data->get_sku = adf_gen4_get_sku; hw_data->init_admin_comms = adf_init_admin_comms; hw_data->exit_admin_comms = adf_exit_admin_comms; hw_data->send_admin_init = adf_send_admin_init; hw_data->init_arb = adf_init_arb; hw_data->exit_arb = adf_exit_arb; hw_data->get_arb_mapping = adf_get_arbiter_mapping; - hw_data->enable_ints = adf_enable_ints; - hw_data->init_device = adf_init_device; + hw_data->enable_ints = adf_gen4_enable_ints; + hw_data->init_device = adf_gen4_init_device; hw_data->reset_device = adf_reset_flr; hw_data->admin_ae_mask = ADF_4XXX_ADMIN_AE_MASK; + hw_data->num_rps = ADF_GEN4_MAX_RPS; switch (dev_id) { case ADF_402XX_PCI_DEVICE_ID: hw_data->fw_name = ADF_402XX_FW; hw_data->fw_mmp_name = ADF_402XX_MMP; hw_data->uof_get_name = uof_get_name_402xx; break; - + case ADF_401XX_PCI_DEVICE_ID: + hw_data->fw_name = ADF_4XXX_FW; + hw_data->fw_mmp_name = ADF_4XXX_MMP; + hw_data->uof_get_name = uof_get_name_4xxx; + hw_data->get_ena_thd_mask = get_ena_thd_mask_401xx; + break; default: hw_data->fw_name = ADF_4XXX_FW; hw_data->fw_mmp_name = ADF_4XXX_MMP; hw_data->uof_get_name = uof_get_name_4xxx; + hw_data->get_ena_thd_mask = get_ena_thd_mask; + break; } hw_data->uof_get_num_objs = uof_get_num_objs; hw_data->uof_get_ae_mask = uof_get_ae_mask; - hw_data->set_msix_rttable = set_msix_default_rttable; + hw_data->get_rp_group = get_rp_group; + hw_data->set_msix_rttable = adf_gen4_set_msix_default_rttable; hw_data->set_ssm_wdtimer = adf_gen4_set_ssm_wdtimer; hw_data->get_ring_to_svc_map = get_ring_to_svc_map; hw_data->disable_iov = adf_disable_sriov; @@ -610,7 +490,7 @@ void adf_init_hw_data_4xxx(struct adf_hw_device_data *hw_data, u32 dev_id) hw_data->dev_config = adf_gen4_dev_config; hw_data->start_timer = adf_gen4_timer_start; hw_data->stop_timer = adf_gen4_timer_stop; - hw_data->get_hb_clock = get_heartbeat_clock; + hw_data->get_hb_clock = adf_gen4_get_heartbeat_clock; hw_data->num_hb_ctrs = ADF_NUM_HB_CNT_PER_AE; hw_data->clock_frequency = ADF_4XXX_AE_FREQ; @@ -619,6 +499,7 @@ void adf_init_hw_data_4xxx(struct adf_hw_device_data *hw_data, u32 dev_id) adf_gen4_init_pf_pfvf_ops(&hw_data->pfvf_ops); adf_gen4_init_dc_ops(&hw_data->dc_ops); adf_gen4_init_ras_ops(&hw_data->ras_ops); + adf_gen4_init_tl_data(&hw_data->tl_data); adf_init_rl_data(&hw_data->rl_data); } diff --git a/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.h b/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.h index 33423295e90fbf..76388363ea8776 100644 --- a/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.h +++ b/drivers/crypto/intel/qat/qat_4xxx/adf_4xxx_hw_data.h @@ -6,25 +6,8 @@ #include #include -/* PCIe configuration space */ -#define ADF_4XXX_SRAM_BAR 0 -#define ADF_4XXX_PMISC_BAR 1 -#define ADF_4XXX_ETR_BAR 2 -#define ADF_4XXX_RX_RINGS_OFFSET 1 -#define ADF_4XXX_TX_RINGS_MASK 0x1 -#define ADF_4XXX_MAX_ACCELERATORS 1 #define ADF_4XXX_MAX_ACCELENGINES 9 -#define ADF_4XXX_BAR_MASK (BIT(0) | BIT(2) | BIT(4)) -/* Physical function fuses */ -#define ADF_4XXX_FUSECTL0_OFFSET (0x2C8) -#define ADF_4XXX_FUSECTL1_OFFSET (0x2CC) -#define ADF_4XXX_FUSECTL2_OFFSET (0x2D0) -#define ADF_4XXX_FUSECTL3_OFFSET (0x2D4) -#define ADF_4XXX_FUSECTL4_OFFSET (0x2D8) -#define ADF_4XXX_FUSECTL5_OFFSET (0x2DC) - -#define ADF_4XXX_ACCELERATORS_MASK (0x1) #define ADF_4XXX_ACCELENGINES_MASK (0x1FF) #define ADF_4XXX_ADMIN_AE_MASK (0x100) @@ -45,28 +28,6 @@ (BIT(4) | BIT(12) | BIT(16) | BIT(17) | BIT(18) | \ BIT(19) | BIT(20) | BIT(21) | BIT(22) | BIT(23)) -#define ADF_4XXX_ETR_MAX_BANKS 64 - -/* MSIX interrupt */ -#define ADF_4XXX_SMIAPF_RP_X0_MASK_OFFSET (0x41A040) -#define ADF_4XXX_SMIAPF_RP_X1_MASK_OFFSET (0x41A044) -#define ADF_4XXX_SMIAPF_MASK_OFFSET (0x41A084) -#define ADF_4XXX_MSIX_RTTABLE_OFFSET(i) (0x409000 + ((i) * 0x04)) - -/* Bank and ring configuration */ -#define ADF_4XXX_NUM_RINGS_PER_BANK 2 -#define ADF_4XXX_NUM_BANKS_PER_VF 4 - -/* Arbiter configuration */ -#define ADF_4XXX_ARB_CONFIG (BIT(31) | BIT(6) | BIT(0)) -#define ADF_4XXX_ARB_OFFSET (0x0) -#define ADF_4XXX_ARB_WRK_2_SER_MAP_OFFSET (0x400) - -/* Admin Interface Reg Offset */ -#define ADF_4XXX_ADMINMSGUR_OFFSET (0x500574) -#define ADF_4XXX_ADMINMSGLR_OFFSET (0x500578) -#define ADF_4XXX_MAILBOX_BASE_OFFSET (0x600970) - /* Firmware Binaries */ #define ADF_4XXX_FW "qat_4xxx.bin" #define ADF_4XXX_MMP "qat_4xxx_mmp.bin" @@ -93,22 +54,9 @@ #define ADF_4XXX_RL_SLICE_REF 1000UL /* Clocks frequency */ -#define ADF_4XXX_KPT_COUNTER_FREQ (100 * HZ_PER_MHZ) #define ADF_4XXX_AE_FREQ (1000 * HZ_PER_MHZ) -/* qat_4xxx fuse bits are different from old GENs, redefine them */ -enum icp_qat_4xxx_slice_mask { - ICP_ACCEL_4XXX_MASK_CIPHER_SLICE = BIT(0), - ICP_ACCEL_4XXX_MASK_AUTH_SLICE = BIT(1), - ICP_ACCEL_4XXX_MASK_PKE_SLICE = BIT(2), - ICP_ACCEL_4XXX_MASK_COMPRESS_SLICE = BIT(3), - ICP_ACCEL_4XXX_MASK_UCS_SLICE = BIT(4), - ICP_ACCEL_4XXX_MASK_EIA3_SLICE = BIT(5), - ICP_ACCEL_4XXX_MASK_SMX_SLICE = BIT(7), -}; - void adf_init_hw_data_4xxx(struct adf_hw_device_data *hw_data, u32 dev_id); void adf_clean_hw_data_4xxx(struct adf_hw_device_data *hw_data); -int adf_gen4_dev_config(struct adf_accel_dev *accel_dev); #endif diff --git a/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c b/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c index 8f483d1197dda2..9762f2bf7727f1 100644 --- a/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c +++ b/drivers/crypto/intel/qat/qat_4xxx/adf_drv.c @@ -8,13 +8,10 @@ #include #include #include -#include +#include +#include #include "adf_4xxx_hw_data.h" -#include "adf_cfg_services.h" -#include "qat_compression.h" -#include "qat_crypto.h" -#include "adf_transport_access_macros.h" static const struct pci_device_id adf_pci_tbl[] = { { PCI_VDEVICE(INTEL, ADF_4XXX_PCI_DEVICE_ID), }, @@ -35,270 +32,6 @@ static void adf_cleanup_accel(struct adf_accel_dev *accel_dev) adf_devmgr_rm_dev(accel_dev, NULL); } -static int adf_cfg_dev_init(struct adf_accel_dev *accel_dev) -{ - const char *config; - int ret; - - config = accel_dev->accel_id % 2 ? ADF_CFG_DC : ADF_CFG_CY; - - ret = adf_cfg_section_add(accel_dev, ADF_GENERAL_SEC); - if (ret) - return ret; - - /* Default configuration is crypto only for even devices - * and compression for odd devices - */ - ret = adf_cfg_add_key_value_param(accel_dev, ADF_GENERAL_SEC, - ADF_SERVICES_ENABLED, config, - ADF_STR); - if (ret) - return ret; - - adf_heartbeat_save_cfg_param(accel_dev, ADF_CFG_HB_TIMER_MIN_MS); - - return 0; -} - -static int adf_crypto_dev_config(struct adf_accel_dev *accel_dev) -{ - char key[ADF_CFG_MAX_KEY_LEN_IN_BYTES]; - int banks = GET_MAX_BANKS(accel_dev); - int cpus = num_online_cpus(); - unsigned long bank, val; - int instances; - int ret; - int i; - - if (adf_hw_dev_has_crypto(accel_dev)) - instances = min(cpus, banks / 2); - else - instances = 0; - - for (i = 0; i < instances; i++) { - val = i; - bank = i * 2; - snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_ASYM_BANK_NUM, i); - ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, - key, &bank, ADF_DEC); - if (ret) - goto err; - - bank += 1; - snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_SYM_BANK_NUM, i); - ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, - key, &bank, ADF_DEC); - if (ret) - goto err; - - snprintf(key, sizeof(key), ADF_CY "%d" ADF_ETRMGR_CORE_AFFINITY, - i); - ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, - key, &val, ADF_DEC); - if (ret) - goto err; - - snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_ASYM_SIZE, i); - val = 128; - ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, - key, &val, ADF_DEC); - if (ret) - goto err; - - val = 512; - snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_SYM_SIZE, i); - ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, - key, &val, ADF_DEC); - if (ret) - goto err; - - val = 0; - snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_ASYM_TX, i); - ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, - key, &val, ADF_DEC); - if (ret) - goto err; - - val = 0; - snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_SYM_TX, i); - ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, - key, &val, ADF_DEC); - if (ret) - goto err; - - val = 1; - snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_ASYM_RX, i); - ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, - key, &val, ADF_DEC); - if (ret) - goto err; - - val = 1; - snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_SYM_RX, i); - ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, - key, &val, ADF_DEC); - if (ret) - goto err; - - val = ADF_COALESCING_DEF_TIME; - snprintf(key, sizeof(key), ADF_ETRMGR_COALESCE_TIMER_FORMAT, i); - ret = adf_cfg_add_key_value_param(accel_dev, "Accelerator0", - key, &val, ADF_DEC); - if (ret) - goto err; - } - - val = i; - ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, ADF_NUM_CY, - &val, ADF_DEC); - if (ret) - goto err; - - val = 0; - ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, ADF_NUM_DC, - &val, ADF_DEC); - if (ret) - goto err; - - return 0; -err: - dev_err(&GET_DEV(accel_dev), "Failed to add configuration for crypto\n"); - return ret; -} - -static int adf_comp_dev_config(struct adf_accel_dev *accel_dev) -{ - char key[ADF_CFG_MAX_KEY_LEN_IN_BYTES]; - int banks = GET_MAX_BANKS(accel_dev); - int cpus = num_online_cpus(); - unsigned long val; - int instances; - int ret; - int i; - - if (adf_hw_dev_has_compression(accel_dev)) - instances = min(cpus, banks); - else - instances = 0; - - for (i = 0; i < instances; i++) { - val = i; - snprintf(key, sizeof(key), ADF_DC "%d" ADF_RING_DC_BANK_NUM, i); - ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, - key, &val, ADF_DEC); - if (ret) - goto err; - - val = 512; - snprintf(key, sizeof(key), ADF_DC "%d" ADF_RING_DC_SIZE, i); - ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, - key, &val, ADF_DEC); - if (ret) - goto err; - - val = 0; - snprintf(key, sizeof(key), ADF_DC "%d" ADF_RING_DC_TX, i); - ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, - key, &val, ADF_DEC); - if (ret) - goto err; - - val = 1; - snprintf(key, sizeof(key), ADF_DC "%d" ADF_RING_DC_RX, i); - ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, - key, &val, ADF_DEC); - if (ret) - goto err; - - val = ADF_COALESCING_DEF_TIME; - snprintf(key, sizeof(key), ADF_ETRMGR_COALESCE_TIMER_FORMAT, i); - ret = adf_cfg_add_key_value_param(accel_dev, "Accelerator0", - key, &val, ADF_DEC); - if (ret) - goto err; - } - - val = i; - ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, ADF_NUM_DC, - &val, ADF_DEC); - if (ret) - goto err; - - val = 0; - ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, ADF_NUM_CY, - &val, ADF_DEC); - if (ret) - goto err; - - return 0; -err: - dev_err(&GET_DEV(accel_dev), "Failed to add configuration for compression\n"); - return ret; -} - -static int adf_no_dev_config(struct adf_accel_dev *accel_dev) -{ - unsigned long val; - int ret; - - val = 0; - ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, ADF_NUM_DC, - &val, ADF_DEC); - if (ret) - return ret; - - return adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, ADF_NUM_CY, - &val, ADF_DEC); -} - -int adf_gen4_dev_config(struct adf_accel_dev *accel_dev) -{ - char services[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = {0}; - int ret; - - ret = adf_cfg_section_add(accel_dev, ADF_KERNEL_SEC); - if (ret) - goto err; - - ret = adf_cfg_section_add(accel_dev, "Accelerator0"); - if (ret) - goto err; - - ret = adf_cfg_get_param_value(accel_dev, ADF_GENERAL_SEC, - ADF_SERVICES_ENABLED, services); - if (ret) - goto err; - - ret = sysfs_match_string(adf_cfg_services, services); - if (ret < 0) - goto err; - - switch (ret) { - case SVC_CY: - case SVC_CY2: - ret = adf_crypto_dev_config(accel_dev); - break; - case SVC_DC: - case SVC_DCC: - ret = adf_comp_dev_config(accel_dev); - break; - default: - ret = adf_no_dev_config(accel_dev); - break; - } - - if (ret) - goto err; - - set_bit(ADF_STATUS_CONFIGURED, &accel_dev->status); - - return ret; - -err: - dev_err(&GET_DEV(accel_dev), "Failed to configure QAT driver\n"); - return ret; -} - static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct adf_accel_dev *accel_dev; @@ -348,7 +81,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) adf_init_hw_data_4xxx(accel_dev->hw_device, ent->device); pci_read_config_byte(pdev, PCI_REVISION_ID, &accel_pci_dev->revid); - pci_read_config_dword(pdev, ADF_4XXX_FUSECTL4_OFFSET, &hw_data->fuses); + pci_read_config_dword(pdev, ADF_GEN4_FUSECTL4_OFFSET, &hw_data->fuses); /* Get Accelerators and Accelerators Engines masks */ hw_data->accel_mask = hw_data->get_accel_mask(hw_data); @@ -381,7 +114,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto out_err; } - ret = adf_cfg_dev_init(accel_dev); + ret = adf_gen4_cfg_dev_init(accel_dev); if (ret) { dev_err(&pdev->dev, "Failed to initialize configuration.\n"); goto out_err; @@ -396,7 +129,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } /* Find and map all the device's BARS */ - bar_mask = pci_select_bars(pdev, IORESOURCE_MEM) & ADF_4XXX_BAR_MASK; + bar_mask = pci_select_bars(pdev, IORESOURCE_MEM) & ADF_GEN4_BAR_MASK; ret = pcim_iomap_regions_request_all(pdev, bar_mask, pci_name(pdev)); if (ret) { diff --git a/drivers/crypto/intel/qat/qat_common/Makefile b/drivers/crypto/intel/qat/qat_common/Makefile index 779a8aa0b8d203..6908727bff3b85 100644 --- a/drivers/crypto/intel/qat/qat_common/Makefile +++ b/drivers/crypto/intel/qat/qat_common/Makefile @@ -16,6 +16,7 @@ intel_qat-objs := adf_cfg.o \ adf_sysfs_ras_counters.o \ adf_gen2_hw_data.o \ adf_gen2_config.o \ + adf_gen4_config.o \ adf_gen4_hw_data.o \ adf_gen4_pm.o \ adf_gen2_dc.o \ @@ -40,9 +41,12 @@ intel_qat-$(CONFIG_DEBUG_FS) += adf_transport_debug.o \ adf_fw_counters.o \ adf_cnv_dbgfs.o \ adf_gen4_pm_debugfs.o \ + adf_gen4_tl.o \ adf_heartbeat.o \ adf_heartbeat_dbgfs.o \ adf_pm_dbgfs.o \ + adf_telemetry.o \ + adf_tl_debugfs.o \ adf_dbgfs.o intel_qat-$(CONFIG_PCI_IOV) += adf_sriov.o adf_vf_isr.o adf_pfvf_utils.o \ diff --git a/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h b/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h index 4ff5729a34969b..a16c7e6edc65d4 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h +++ b/drivers/crypto/intel/qat/qat_common/adf_accel_devices.h @@ -6,11 +6,14 @@ #include #include #include +#include #include #include #include "adf_cfg_common.h" #include "adf_rl.h" +#include "adf_telemetry.h" #include "adf_pfvf_msg.h" +#include "icp_qat_hw.h" #define ADF_DH895XCC_DEVICE_NAME "dh895xcc" #define ADF_DH895XCCVF_DEVICE_NAME "dh895xccvf" @@ -19,12 +22,15 @@ #define ADF_C3XXX_DEVICE_NAME "c3xxx" #define ADF_C3XXXVF_DEVICE_NAME "c3xxxvf" #define ADF_4XXX_DEVICE_NAME "4xxx" +#define ADF_420XX_DEVICE_NAME "420xx" #define ADF_4XXX_PCI_DEVICE_ID 0x4940 #define ADF_4XXXIOV_PCI_DEVICE_ID 0x4941 #define ADF_401XX_PCI_DEVICE_ID 0x4942 #define ADF_401XXIOV_PCI_DEVICE_ID 0x4943 #define ADF_402XX_PCI_DEVICE_ID 0x4944 #define ADF_402XXIOV_PCI_DEVICE_ID 0x4945 +#define ADF_420XX_PCI_DEVICE_ID 0x4946 +#define ADF_420XXIOV_PCI_DEVICE_ID 0x4947 #define ADF_DEVICE_FUSECTL_OFFSET 0x40 #define ADF_DEVICE_LEGFUSE_OFFSET 0x4C #define ADF_DEVICE_FUSECTL_MASK 0x80000000 @@ -92,6 +98,7 @@ enum ras_errors { struct adf_error_counters { atomic_t counter[ADF_RAS_ERRORS]; + bool sysfs_added; bool enabled; }; @@ -240,8 +247,10 @@ struct adf_hw_device_data { void (*reset_device)(struct adf_accel_dev *accel_dev); void (*set_msix_rttable)(struct adf_accel_dev *accel_dev); const char *(*uof_get_name)(struct adf_accel_dev *accel_dev, u32 obj_num); - u32 (*uof_get_num_objs)(void); + u32 (*uof_get_num_objs)(struct adf_accel_dev *accel_dev); u32 (*uof_get_ae_mask)(struct adf_accel_dev *accel_dev, u32 obj_num); + int (*get_rp_group)(struct adf_accel_dev *accel_dev, u32 ae_mask); + u32 (*get_ena_thd_mask)(struct adf_accel_dev *accel_dev, u32 obj_num); int (*dev_config)(struct adf_accel_dev *accel_dev); struct adf_pfvf_ops pfvf_ops; struct adf_hw_csr_ops csr_ops; @@ -249,6 +258,7 @@ struct adf_hw_device_data { struct adf_ras_ops ras_ops; struct adf_dev_err_mask dev_err_mask; struct adf_rl_hw_data rl_data; + struct adf_tl_hw_data tl_data; const char *fw_name; const char *fw_mmp_name; u32 fuses; @@ -263,6 +273,7 @@ struct adf_hw_device_data { u32 admin_ae_mask; u16 tx_rings_mask; u16 ring_to_svc_map; + u32 thd_to_arb_map[ICP_QAT_HW_AE_DELIMITER]; u8 tx_rx_gap; u8 num_banks; u16 num_banks_per_vf; @@ -271,6 +282,7 @@ struct adf_hw_device_data { u8 num_logical_accel; u8 num_engines; u32 num_hb_ctrs; + u8 num_rps; }; /* CSR write macro */ @@ -303,6 +315,7 @@ struct adf_hw_device_data { #define GET_CSR_OPS(accel_dev) (&(accel_dev)->hw_device->csr_ops) #define GET_PFVF_OPS(accel_dev) (&(accel_dev)->hw_device->pfvf_ops) #define GET_DC_OPS(accel_dev) (&(accel_dev)->hw_device->dc_ops) +#define GET_TL_DATA(accel_dev) GET_HW_DATA(accel_dev)->tl_data #define accel_to_pci_dev(accel_ptr) accel_ptr->accel_pci_dev.pci_dev struct adf_admin_comms; @@ -351,6 +364,7 @@ struct adf_accel_dev { struct adf_cfg_device_data *cfg; struct adf_fw_loader_data *fw_loader; struct adf_admin_comms *admin; + struct adf_telemetry *telemetry; struct adf_dc_data *dc_data; struct adf_pm power_management; struct list_head crypto_list; diff --git a/drivers/crypto/intel/qat/qat_common/adf_accel_engine.c b/drivers/crypto/intel/qat/qat_common/adf_accel_engine.c index 6be064dc64c8e8..4b5d0350fc2ef1 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_accel_engine.c +++ b/drivers/crypto/intel/qat/qat_common/adf_accel_engine.c @@ -19,7 +19,7 @@ static int adf_ae_fw_load_images(struct adf_accel_dev *accel_dev, void *fw_addr, int i; loader = loader_data->fw_loader; - num_objs = hw_device->uof_get_num_objs(); + num_objs = hw_device->uof_get_num_objs(accel_dev); for (i = 0; i < num_objs; i++) { obj_name = hw_device->uof_get_name(accel_dev, i); diff --git a/drivers/crypto/intel/qat/qat_common/adf_admin.c b/drivers/crypto/intel/qat/qat_common/adf_admin.c index 54b673ec236223..acad526eb74168 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_admin.c +++ b/drivers/crypto/intel/qat/qat_common/adf_admin.c @@ -498,6 +498,43 @@ int adf_get_cnv_stats(struct adf_accel_dev *accel_dev, u16 ae, u16 *err_cnt, return ret; } +int adf_send_admin_tl_start(struct adf_accel_dev *accel_dev, + dma_addr_t tl_dma_addr, size_t layout_sz, u8 *rp_indexes, + struct icp_qat_fw_init_admin_slice_cnt *slice_count) +{ + u32 ae_mask = GET_HW_DATA(accel_dev)->admin_ae_mask; + struct icp_qat_fw_init_admin_resp resp = { }; + struct icp_qat_fw_init_admin_req req = { }; + int ret; + + req.cmd_id = ICP_QAT_FW_TL_START; + req.init_cfg_ptr = tl_dma_addr; + req.init_cfg_sz = layout_sz; + + if (rp_indexes) + memcpy(&req.rp_indexes, rp_indexes, sizeof(req.rp_indexes)); + + ret = adf_send_admin(accel_dev, &req, &resp, ae_mask); + if (ret) + return ret; + + memcpy(slice_count, &resp.slices, sizeof(*slice_count)); + + return 0; +} + +int adf_send_admin_tl_stop(struct adf_accel_dev *accel_dev) +{ + struct adf_hw_device_data *hw_data = GET_HW_DATA(accel_dev); + struct icp_qat_fw_init_admin_resp resp = { }; + struct icp_qat_fw_init_admin_req req = { }; + u32 ae_mask = hw_data->admin_ae_mask; + + req.cmd_id = ICP_QAT_FW_TL_STOP; + + return adf_send_admin(accel_dev, &req, &resp, ae_mask); +} + int adf_init_admin_comms(struct adf_accel_dev *accel_dev) { struct adf_admin_comms *admin; diff --git a/drivers/crypto/intel/qat/qat_common/adf_admin.h b/drivers/crypto/intel/qat/qat_common/adf_admin.h index 55cbcbc66c9f38..647c8e19675210 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_admin.h +++ b/drivers/crypto/intel/qat/qat_common/adf_admin.h @@ -23,5 +23,9 @@ int adf_send_admin_rl_delete(struct adf_accel_dev *accel_dev, u16 node_id, int adf_get_fw_timestamp(struct adf_accel_dev *accel_dev, u64 *timestamp); int adf_get_pm_info(struct adf_accel_dev *accel_dev, dma_addr_t p_state_addr, size_t buff_size); int adf_get_cnv_stats(struct adf_accel_dev *accel_dev, u16 ae, u16 *err_cnt, u16 *latest_err); +int adf_send_admin_tl_start(struct adf_accel_dev *accel_dev, + dma_addr_t tl_dma_addr, size_t layout_sz, u8 *rp_indexes, + struct icp_qat_fw_init_admin_slice_cnt *slice_count); +int adf_send_admin_tl_stop(struct adf_accel_dev *accel_dev); #endif diff --git a/drivers/crypto/intel/qat/qat_common/adf_cfg_common.h b/drivers/crypto/intel/qat/qat_common/adf_cfg_common.h index 6e5de1dab97b4f..89df3888d7eac7 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_cfg_common.h +++ b/drivers/crypto/intel/qat/qat_common/adf_cfg_common.h @@ -47,6 +47,7 @@ enum adf_device_type { DEV_C3XXX, DEV_C3XXXVF, DEV_4XXX, + DEV_420XX, }; struct adf_dev_status_info { diff --git a/drivers/crypto/intel/qat/qat_common/adf_cfg_services.c b/drivers/crypto/intel/qat/qat_common/adf_cfg_services.c index 8e13fe938959b4..26805229446843 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_cfg_services.c +++ b/drivers/crypto/intel/qat/qat_common/adf_cfg_services.c @@ -2,6 +2,9 @@ /* Copyright(c) 2023 Intel Corporation */ #include +#include +#include +#include "adf_cfg.h" #include "adf_cfg_services.h" #include "adf_cfg_strings.h" @@ -18,3 +21,27 @@ const char *const adf_cfg_services[] = { [SVC_SYM_DC] = ADF_CFG_SYM_DC, }; EXPORT_SYMBOL_GPL(adf_cfg_services); + +int adf_get_service_enabled(struct adf_accel_dev *accel_dev) +{ + char services[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = {0}; + int ret; + + ret = adf_cfg_get_param_value(accel_dev, ADF_GENERAL_SEC, + ADF_SERVICES_ENABLED, services); + if (ret) { + dev_err(&GET_DEV(accel_dev), + ADF_SERVICES_ENABLED " param not found\n"); + return ret; + } + + ret = match_string(adf_cfg_services, ARRAY_SIZE(adf_cfg_services), + services); + if (ret < 0) + dev_err(&GET_DEV(accel_dev), + "Invalid value of " ADF_SERVICES_ENABLED " param: %s\n", + services); + + return ret; +} +EXPORT_SYMBOL_GPL(adf_get_service_enabled); diff --git a/drivers/crypto/intel/qat/qat_common/adf_cfg_services.h b/drivers/crypto/intel/qat/qat_common/adf_cfg_services.h index f78fd697b4bee2..c6b0328b0f5b03 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_cfg_services.h +++ b/drivers/crypto/intel/qat/qat_common/adf_cfg_services.h @@ -5,6 +5,8 @@ #include "adf_cfg_strings.h" +struct adf_accel_dev; + enum adf_services { SVC_CY = 0, SVC_CY2, @@ -21,4 +23,6 @@ enum adf_services { extern const char *const adf_cfg_services[SVC_COUNT]; +int adf_get_service_enabled(struct adf_accel_dev *accel_dev); + #endif diff --git a/drivers/crypto/intel/qat/qat_common/adf_dbgfs.c b/drivers/crypto/intel/qat/qat_common/adf_dbgfs.c index 477efcc81a1637..c42f5c25aabdfa 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_dbgfs.c +++ b/drivers/crypto/intel/qat/qat_common/adf_dbgfs.c @@ -10,6 +10,7 @@ #include "adf_fw_counters.h" #include "adf_heartbeat_dbgfs.h" #include "adf_pm_dbgfs.h" +#include "adf_tl_debugfs.h" /** * adf_dbgfs_init() - add persistent debugfs entries @@ -66,6 +67,7 @@ void adf_dbgfs_add(struct adf_accel_dev *accel_dev) adf_heartbeat_dbgfs_add(accel_dev); adf_pm_dbgfs_add(accel_dev); adf_cnv_dbgfs_add(accel_dev); + adf_tl_dbgfs_add(accel_dev); } } @@ -79,6 +81,7 @@ void adf_dbgfs_rm(struct adf_accel_dev *accel_dev) return; if (!accel_dev->is_vf) { + adf_tl_dbgfs_rm(accel_dev); adf_cnv_dbgfs_rm(accel_dev); adf_pm_dbgfs_rm(accel_dev); adf_heartbeat_dbgfs_rm(accel_dev); diff --git a/drivers/crypto/intel/qat/qat_common/adf_fw_config.h b/drivers/crypto/intel/qat/qat_common/adf_fw_config.h new file mode 100644 index 00000000000000..4f86696800c97f --- /dev/null +++ b/drivers/crypto/intel/qat/qat_common/adf_fw_config.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright(c) 2023 Intel Corporation */ +#ifndef ADF_FW_CONFIG_H_ +#define ADF_FW_CONFIG_H_ + +enum adf_fw_objs { + ADF_FW_SYM_OBJ, + ADF_FW_ASYM_OBJ, + ADF_FW_DC_OBJ, + ADF_FW_ADMIN_OBJ, +}; + +struct adf_fw_config { + u32 ae_mask; + enum adf_fw_objs obj; +}; + +#endif diff --git a/drivers/crypto/intel/qat/qat_common/adf_gen4_config.c b/drivers/crypto/intel/qat/qat_common/adf_gen4_config.c new file mode 100644 index 00000000000000..fe1f3d727dc5a5 --- /dev/null +++ b/drivers/crypto/intel/qat/qat_common/adf_gen4_config.c @@ -0,0 +1,287 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright(c) 2023 Intel Corporation */ +#include "adf_accel_devices.h" +#include "adf_cfg.h" +#include "adf_cfg_services.h" +#include "adf_cfg_strings.h" +#include "adf_common_drv.h" +#include "adf_gen4_config.h" +#include "adf_heartbeat.h" +#include "adf_transport_access_macros.h" +#include "qat_compression.h" +#include "qat_crypto.h" + +static int adf_crypto_dev_config(struct adf_accel_dev *accel_dev) +{ + char key[ADF_CFG_MAX_KEY_LEN_IN_BYTES]; + int banks = GET_MAX_BANKS(accel_dev); + int cpus = num_online_cpus(); + unsigned long bank, val; + int instances; + int ret; + int i; + + if (adf_hw_dev_has_crypto(accel_dev)) + instances = min(cpus, banks / 2); + else + instances = 0; + + for (i = 0; i < instances; i++) { + val = i; + bank = i * 2; + snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_ASYM_BANK_NUM, i); + ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, + key, &bank, ADF_DEC); + if (ret) + goto err; + + bank += 1; + snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_SYM_BANK_NUM, i); + ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, + key, &bank, ADF_DEC); + if (ret) + goto err; + + snprintf(key, sizeof(key), ADF_CY "%d" ADF_ETRMGR_CORE_AFFINITY, + i); + ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, + key, &val, ADF_DEC); + if (ret) + goto err; + + snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_ASYM_SIZE, i); + val = 128; + ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, + key, &val, ADF_DEC); + if (ret) + goto err; + + val = 512; + snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_SYM_SIZE, i); + ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, + key, &val, ADF_DEC); + if (ret) + goto err; + + val = 0; + snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_ASYM_TX, i); + ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, + key, &val, ADF_DEC); + if (ret) + goto err; + + val = 0; + snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_SYM_TX, i); + ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, + key, &val, ADF_DEC); + if (ret) + goto err; + + val = 1; + snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_ASYM_RX, i); + ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, + key, &val, ADF_DEC); + if (ret) + goto err; + + val = 1; + snprintf(key, sizeof(key), ADF_CY "%d" ADF_RING_SYM_RX, i); + ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, + key, &val, ADF_DEC); + if (ret) + goto err; + + val = ADF_COALESCING_DEF_TIME; + snprintf(key, sizeof(key), ADF_ETRMGR_COALESCE_TIMER_FORMAT, i); + ret = adf_cfg_add_key_value_param(accel_dev, "Accelerator0", + key, &val, ADF_DEC); + if (ret) + goto err; + } + + val = i; + ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, ADF_NUM_CY, + &val, ADF_DEC); + if (ret) + goto err; + + val = 0; + ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, ADF_NUM_DC, + &val, ADF_DEC); + if (ret) + goto err; + + return 0; +err: + dev_err(&GET_DEV(accel_dev), "Failed to add configuration for crypto\n"); + return ret; +} + +static int adf_comp_dev_config(struct adf_accel_dev *accel_dev) +{ + char key[ADF_CFG_MAX_KEY_LEN_IN_BYTES]; + int banks = GET_MAX_BANKS(accel_dev); + int cpus = num_online_cpus(); + unsigned long val; + int instances; + int ret; + int i; + + if (adf_hw_dev_has_compression(accel_dev)) + instances = min(cpus, banks); + else + instances = 0; + + for (i = 0; i < instances; i++) { + val = i; + snprintf(key, sizeof(key), ADF_DC "%d" ADF_RING_DC_BANK_NUM, i); + ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, + key, &val, ADF_DEC); + if (ret) + goto err; + + val = 512; + snprintf(key, sizeof(key), ADF_DC "%d" ADF_RING_DC_SIZE, i); + ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, + key, &val, ADF_DEC); + if (ret) + goto err; + + val = 0; + snprintf(key, sizeof(key), ADF_DC "%d" ADF_RING_DC_TX, i); + ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, + key, &val, ADF_DEC); + if (ret) + goto err; + + val = 1; + snprintf(key, sizeof(key), ADF_DC "%d" ADF_RING_DC_RX, i); + ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, + key, &val, ADF_DEC); + if (ret) + goto err; + + val = ADF_COALESCING_DEF_TIME; + snprintf(key, sizeof(key), ADF_ETRMGR_COALESCE_TIMER_FORMAT, i); + ret = adf_cfg_add_key_value_param(accel_dev, "Accelerator0", + key, &val, ADF_DEC); + if (ret) + goto err; + } + + val = i; + ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, ADF_NUM_DC, + &val, ADF_DEC); + if (ret) + goto err; + + val = 0; + ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, ADF_NUM_CY, + &val, ADF_DEC); + if (ret) + goto err; + + return 0; +err: + dev_err(&GET_DEV(accel_dev), "Failed to add configuration for compression\n"); + return ret; +} + +static int adf_no_dev_config(struct adf_accel_dev *accel_dev) +{ + unsigned long val; + int ret; + + val = 0; + ret = adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, ADF_NUM_DC, + &val, ADF_DEC); + if (ret) + return ret; + + return adf_cfg_add_key_value_param(accel_dev, ADF_KERNEL_SEC, ADF_NUM_CY, + &val, ADF_DEC); +} + +/** + * adf_gen4_dev_config() - create dev config required to create instances + * + * @accel_dev: Pointer to acceleration device. + * + * Function creates device configuration required to create instances + * + * Return: 0 on success, error code otherwise. + */ +int adf_gen4_dev_config(struct adf_accel_dev *accel_dev) +{ + char services[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = {0}; + int ret; + + ret = adf_cfg_section_add(accel_dev, ADF_KERNEL_SEC); + if (ret) + goto err; + + ret = adf_cfg_section_add(accel_dev, "Accelerator0"); + if (ret) + goto err; + + ret = adf_cfg_get_param_value(accel_dev, ADF_GENERAL_SEC, + ADF_SERVICES_ENABLED, services); + if (ret) + goto err; + + ret = sysfs_match_string(adf_cfg_services, services); + if (ret < 0) + goto err; + + switch (ret) { + case SVC_CY: + case SVC_CY2: + ret = adf_crypto_dev_config(accel_dev); + break; + case SVC_DC: + case SVC_DCC: + ret = adf_comp_dev_config(accel_dev); + break; + default: + ret = adf_no_dev_config(accel_dev); + break; + } + + if (ret) + goto err; + + set_bit(ADF_STATUS_CONFIGURED, &accel_dev->status); + + return ret; + +err: + dev_err(&GET_DEV(accel_dev), "Failed to configure QAT driver\n"); + return ret; +} +EXPORT_SYMBOL_GPL(adf_gen4_dev_config); + +int adf_gen4_cfg_dev_init(struct adf_accel_dev *accel_dev) +{ + const char *config; + int ret; + + config = accel_dev->accel_id % 2 ? ADF_CFG_DC : ADF_CFG_CY; + + ret = adf_cfg_section_add(accel_dev, ADF_GENERAL_SEC); + if (ret) + return ret; + + /* Default configuration is crypto only for even devices + * and compression for odd devices + */ + ret = adf_cfg_add_key_value_param(accel_dev, ADF_GENERAL_SEC, + ADF_SERVICES_ENABLED, config, + ADF_STR); + if (ret) + return ret; + + adf_heartbeat_save_cfg_param(accel_dev, ADF_CFG_HB_TIMER_MIN_MS); + + return 0; +} +EXPORT_SYMBOL_GPL(adf_gen4_cfg_dev_init); diff --git a/drivers/crypto/intel/qat/qat_common/adf_gen4_config.h b/drivers/crypto/intel/qat/qat_common/adf_gen4_config.h new file mode 100644 index 00000000000000..bb87655f69a839 --- /dev/null +++ b/drivers/crypto/intel/qat/qat_common/adf_gen4_config.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright(c) 2023 Intel Corporation */ +#ifndef ADF_GEN4_CONFIG_H_ +#define ADF_GEN4_CONFIG_H_ + +#include "adf_accel_devices.h" + +int adf_gen4_dev_config(struct adf_accel_dev *accel_dev); +int adf_gen4_cfg_dev_init(struct adf_accel_dev *accel_dev); + +#endif diff --git a/drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.c b/drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.c index 3148a62938fdd2..9985683056d5ff 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.c +++ b/drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.c @@ -2,8 +2,10 @@ /* Copyright(c) 2020 Intel Corporation */ #include #include "adf_accel_devices.h" +#include "adf_cfg_services.h" #include "adf_common_drv.h" #include "adf_gen4_hw_data.h" +#include "adf_gen4_pm.h" static u64 build_csr_ring_base_addr(dma_addr_t addr, u32 size) { @@ -102,6 +104,131 @@ void adf_gen4_init_hw_csr_ops(struct adf_hw_csr_ops *csr_ops) } EXPORT_SYMBOL_GPL(adf_gen4_init_hw_csr_ops); +u32 adf_gen4_get_accel_mask(struct adf_hw_device_data *self) +{ + return ADF_GEN4_ACCELERATORS_MASK; +} +EXPORT_SYMBOL_GPL(adf_gen4_get_accel_mask); + +u32 adf_gen4_get_num_accels(struct adf_hw_device_data *self) +{ + return ADF_GEN4_MAX_ACCELERATORS; +} +EXPORT_SYMBOL_GPL(adf_gen4_get_num_accels); + +u32 adf_gen4_get_num_aes(struct adf_hw_device_data *self) +{ + if (!self || !self->ae_mask) + return 0; + + return hweight32(self->ae_mask); +} +EXPORT_SYMBOL_GPL(adf_gen4_get_num_aes); + +u32 adf_gen4_get_misc_bar_id(struct adf_hw_device_data *self) +{ + return ADF_GEN4_PMISC_BAR; +} +EXPORT_SYMBOL_GPL(adf_gen4_get_misc_bar_id); + +u32 adf_gen4_get_etr_bar_id(struct adf_hw_device_data *self) +{ + return ADF_GEN4_ETR_BAR; +} +EXPORT_SYMBOL_GPL(adf_gen4_get_etr_bar_id); + +u32 adf_gen4_get_sram_bar_id(struct adf_hw_device_data *self) +{ + return ADF_GEN4_SRAM_BAR; +} +EXPORT_SYMBOL_GPL(adf_gen4_get_sram_bar_id); + +enum dev_sku_info adf_gen4_get_sku(struct adf_hw_device_data *self) +{ + return DEV_SKU_1; +} +EXPORT_SYMBOL_GPL(adf_gen4_get_sku); + +void adf_gen4_get_arb_info(struct arb_info *arb_info) +{ + arb_info->arb_cfg = ADF_GEN4_ARB_CONFIG; + arb_info->arb_offset = ADF_GEN4_ARB_OFFSET; + arb_info->wt2sam_offset = ADF_GEN4_ARB_WRK_2_SER_MAP_OFFSET; +} +EXPORT_SYMBOL_GPL(adf_gen4_get_arb_info); + +void adf_gen4_get_admin_info(struct admin_info *admin_csrs_info) +{ + admin_csrs_info->mailbox_offset = ADF_GEN4_MAILBOX_BASE_OFFSET; + admin_csrs_info->admin_msg_ur = ADF_GEN4_ADMINMSGUR_OFFSET; + admin_csrs_info->admin_msg_lr = ADF_GEN4_ADMINMSGLR_OFFSET; +} +EXPORT_SYMBOL_GPL(adf_gen4_get_admin_info); + +u32 adf_gen4_get_heartbeat_clock(struct adf_hw_device_data *self) +{ + /* + * GEN4 uses KPT counter for HB + */ + return ADF_GEN4_KPT_COUNTER_FREQ; +} +EXPORT_SYMBOL_GPL(adf_gen4_get_heartbeat_clock); + +void adf_gen4_enable_error_correction(struct adf_accel_dev *accel_dev) +{ + struct adf_bar *misc_bar = &GET_BARS(accel_dev)[ADF_GEN4_PMISC_BAR]; + void __iomem *csr = misc_bar->virt_addr; + + /* Enable all in errsou3 except VFLR notification on host */ + ADF_CSR_WR(csr, ADF_GEN4_ERRMSK3, ADF_GEN4_VFLNOTIFY); +} +EXPORT_SYMBOL_GPL(adf_gen4_enable_error_correction); + +void adf_gen4_enable_ints(struct adf_accel_dev *accel_dev) +{ + void __iomem *addr; + + addr = (&GET_BARS(accel_dev)[ADF_GEN4_PMISC_BAR])->virt_addr; + + /* Enable bundle interrupts */ + ADF_CSR_WR(addr, ADF_GEN4_SMIAPF_RP_X0_MASK_OFFSET, 0); + ADF_CSR_WR(addr, ADF_GEN4_SMIAPF_RP_X1_MASK_OFFSET, 0); + + /* Enable misc interrupts */ + ADF_CSR_WR(addr, ADF_GEN4_SMIAPF_MASK_OFFSET, 0); +} +EXPORT_SYMBOL_GPL(adf_gen4_enable_ints); + +int adf_gen4_init_device(struct adf_accel_dev *accel_dev) +{ + void __iomem *addr; + u32 status; + u32 csr; + int ret; + + addr = (&GET_BARS(accel_dev)[ADF_GEN4_PMISC_BAR])->virt_addr; + + /* Temporarily mask PM interrupt */ + csr = ADF_CSR_RD(addr, ADF_GEN4_ERRMSK2); + csr |= ADF_GEN4_PM_SOU; + ADF_CSR_WR(addr, ADF_GEN4_ERRMSK2, csr); + + /* Set DRV_ACTIVE bit to power up the device */ + ADF_CSR_WR(addr, ADF_GEN4_PM_INTERRUPT, ADF_GEN4_PM_DRV_ACTIVE); + + /* Poll status register to make sure the device is powered up */ + ret = read_poll_timeout(ADF_CSR_RD, status, + status & ADF_GEN4_PM_INIT_STATE, + ADF_GEN4_PM_POLL_DELAY_US, + ADF_GEN4_PM_POLL_TIMEOUT_US, true, addr, + ADF_GEN4_PM_STATUS); + if (ret) + dev_err(&GET_DEV(accel_dev), "Failed to power up the device\n"); + + return ret; +} +EXPORT_SYMBOL_GPL(adf_gen4_init_device); + static inline void adf_gen4_unpack_ssm_wdtimer(u64 value, u32 *upper, u32 *lower) { @@ -135,6 +262,28 @@ void adf_gen4_set_ssm_wdtimer(struct adf_accel_dev *accel_dev) } EXPORT_SYMBOL_GPL(adf_gen4_set_ssm_wdtimer); +/* + * The vector routing table is used to select the MSI-X entry to use for each + * interrupt source. + * The first ADF_GEN4_ETR_MAX_BANKS entries correspond to ring interrupts. + * The final entry corresponds to VF2PF or error interrupts. + * This vector table could be used to configure one MSI-X entry to be shared + * between multiple interrupt sources. + * + * The default routing is set to have a one to one correspondence between the + * interrupt source and the MSI-X entry used. + */ +void adf_gen4_set_msix_default_rttable(struct adf_accel_dev *accel_dev) +{ + void __iomem *csr; + int i; + + csr = (&GET_BARS(accel_dev)[ADF_GEN4_PMISC_BAR])->virt_addr; + for (i = 0; i <= ADF_GEN4_ETR_MAX_BANKS; i++) + ADF_CSR_WR(csr, ADF_GEN4_MSIX_RTTABLE_OFFSET(i), i); +} +EXPORT_SYMBOL_GPL(adf_gen4_set_msix_default_rttable); + int adf_pfvf_comms_disabled(struct adf_accel_dev *accel_dev) { return 0; @@ -192,3 +341,92 @@ int adf_gen4_ring_pair_reset(struct adf_accel_dev *accel_dev, u32 bank_number) return ret; } EXPORT_SYMBOL_GPL(adf_gen4_ring_pair_reset); + +static const u32 thrd_to_arb_map_dcc[] = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0 +}; + +static const u16 rp_group_to_arb_mask[] = { + [RP_GROUP_0] = 0x5, + [RP_GROUP_1] = 0xA, +}; + +static bool is_single_service(int service_id) +{ + switch (service_id) { + case SVC_DC: + case SVC_SYM: + case SVC_ASYM: + return true; + case SVC_CY: + case SVC_CY2: + case SVC_DCC: + case SVC_ASYM_DC: + case SVC_DC_ASYM: + case SVC_SYM_DC: + case SVC_DC_SYM: + default: + return false; + } +} + +int adf_gen4_init_thd2arb_map(struct adf_accel_dev *accel_dev) +{ + struct adf_hw_device_data *hw_data = GET_HW_DATA(accel_dev); + u32 *thd2arb_map = hw_data->thd_to_arb_map; + unsigned int ae_cnt, worker_obj_cnt, i, j; + unsigned long ae_mask, thds_mask; + int srv_id, rp_group; + u32 thd2arb_map_base; + u16 arb_mask; + + if (!hw_data->get_rp_group || !hw_data->get_ena_thd_mask || + !hw_data->get_num_aes || !hw_data->uof_get_num_objs || + !hw_data->uof_get_ae_mask) + return -EFAULT; + + srv_id = adf_get_service_enabled(accel_dev); + if (srv_id < 0) + return srv_id; + + ae_cnt = hw_data->get_num_aes(hw_data); + worker_obj_cnt = hw_data->uof_get_num_objs(accel_dev) - + ADF_GEN4_ADMIN_ACCELENGINES; + + if (srv_id == SVC_DCC) { + memcpy(thd2arb_map, thrd_to_arb_map_dcc, + array_size(sizeof(*thd2arb_map), ae_cnt)); + return 0; + } + + for (i = 0; i < worker_obj_cnt; i++) { + ae_mask = hw_data->uof_get_ae_mask(accel_dev, i); + rp_group = hw_data->get_rp_group(accel_dev, ae_mask); + thds_mask = hw_data->get_ena_thd_mask(accel_dev, i); + thd2arb_map_base = 0; + + if (rp_group >= RP_GROUP_COUNT || rp_group < RP_GROUP_0) + return -EINVAL; + + if (thds_mask == ADF_GEN4_ENA_THD_MASK_ERROR) + return -EINVAL; + + if (is_single_service(srv_id)) + arb_mask = rp_group_to_arb_mask[RP_GROUP_0] | + rp_group_to_arb_mask[RP_GROUP_1]; + else + arb_mask = rp_group_to_arb_mask[rp_group]; + + for_each_set_bit(j, &thds_mask, ADF_NUM_THREADS_PER_AE) + thd2arb_map_base |= arb_mask << (j * 4); + + for_each_set_bit(j, &ae_mask, ae_cnt) + thd2arb_map[j] = thd2arb_map_base; + } + return 0; +} +EXPORT_SYMBOL_GPL(adf_gen4_init_thd2arb_map); diff --git a/drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.h b/drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.h index 1813fe1d5a06cc..7d8a774cadc882 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.h +++ b/drivers/crypto/intel/qat/qat_common/adf_gen4_hw_data.h @@ -3,9 +3,57 @@ #ifndef ADF_GEN4_HW_CSR_DATA_H_ #define ADF_GEN4_HW_CSR_DATA_H_ +#include + #include "adf_accel_devices.h" #include "adf_cfg_common.h" +/* PCIe configuration space */ +#define ADF_GEN4_BAR_MASK (BIT(0) | BIT(2) | BIT(4)) +#define ADF_GEN4_SRAM_BAR 0 +#define ADF_GEN4_PMISC_BAR 1 +#define ADF_GEN4_ETR_BAR 2 + +/* Clocks frequency */ +#define ADF_GEN4_KPT_COUNTER_FREQ (100 * HZ_PER_MHZ) + +/* Physical function fuses */ +#define ADF_GEN4_FUSECTL0_OFFSET 0x2C8 +#define ADF_GEN4_FUSECTL1_OFFSET 0x2CC +#define ADF_GEN4_FUSECTL2_OFFSET 0x2D0 +#define ADF_GEN4_FUSECTL3_OFFSET 0x2D4 +#define ADF_GEN4_FUSECTL4_OFFSET 0x2D8 +#define ADF_GEN4_FUSECTL5_OFFSET 0x2DC + +/* Accelerators */ +#define ADF_GEN4_ACCELERATORS_MASK 0x1 +#define ADF_GEN4_MAX_ACCELERATORS 1 +#define ADF_GEN4_ADMIN_ACCELENGINES 1 + +/* MSIX interrupt */ +#define ADF_GEN4_SMIAPF_RP_X0_MASK_OFFSET 0x41A040 +#define ADF_GEN4_SMIAPF_RP_X1_MASK_OFFSET 0x41A044 +#define ADF_GEN4_SMIAPF_MASK_OFFSET 0x41A084 +#define ADF_GEN4_MSIX_RTTABLE_OFFSET(i) (0x409000 + ((i) * 0x04)) + +/* Bank and ring configuration */ +#define ADF_GEN4_MAX_RPS 64 +#define ADF_GEN4_NUM_RINGS_PER_BANK 2 +#define ADF_GEN4_NUM_BANKS_PER_VF 4 +#define ADF_GEN4_ETR_MAX_BANKS 64 +#define ADF_GEN4_RX_RINGS_OFFSET 1 +#define ADF_GEN4_TX_RINGS_MASK 0x1 + +/* Arbiter configuration */ +#define ADF_GEN4_ARB_CONFIG (BIT(31) | BIT(6) | BIT(0)) +#define ADF_GEN4_ARB_OFFSET 0x0 +#define ADF_GEN4_ARB_WRK_2_SER_MAP_OFFSET 0x400 + +/* Admin Interface Reg Offset */ +#define ADF_GEN4_ADMINMSGUR_OFFSET 0x500574 +#define ADF_GEN4_ADMINMSGLR_OFFSET 0x500578 +#define ADF_GEN4_MAILBOX_BASE_OFFSET 0x600970 + /* Transport access */ #define ADF_BANK_INT_SRC_SEL_MASK 0x44UL #define ADF_RING_CSR_RING_CONFIG 0x1000 @@ -146,7 +194,46 @@ do { \ #define ADF_GEN4_RL_TOKEN_PCIEIN_BUCKET_OFFSET 0x508800 #define ADF_GEN4_RL_TOKEN_PCIEOUT_BUCKET_OFFSET 0x508804 +/* Arbiter threads mask with error value */ +#define ADF_GEN4_ENA_THD_MASK_ERROR GENMASK(ADF_NUM_THREADS_PER_AE, 0) + void adf_gen4_set_ssm_wdtimer(struct adf_accel_dev *accel_dev); + +enum icp_qat_gen4_slice_mask { + ICP_ACCEL_GEN4_MASK_CIPHER_SLICE = BIT(0), + ICP_ACCEL_GEN4_MASK_AUTH_SLICE = BIT(1), + ICP_ACCEL_GEN4_MASK_PKE_SLICE = BIT(2), + ICP_ACCEL_GEN4_MASK_COMPRESS_SLICE = BIT(3), + ICP_ACCEL_GEN4_MASK_UCS_SLICE = BIT(4), + ICP_ACCEL_GEN4_MASK_EIA3_SLICE = BIT(5), + ICP_ACCEL_GEN4_MASK_SMX_SLICE = BIT(7), + ICP_ACCEL_GEN4_MASK_WCP_WAT_SLICE = BIT(8), + ICP_ACCEL_GEN4_MASK_ZUC_256_SLICE = BIT(9), +}; + +enum adf_gen4_rp_groups { + RP_GROUP_0, + RP_GROUP_1, + RP_GROUP_COUNT +}; + +void adf_gen4_enable_error_correction(struct adf_accel_dev *accel_dev); +void adf_gen4_enable_ints(struct adf_accel_dev *accel_dev); +u32 adf_gen4_get_accel_mask(struct adf_hw_device_data *self); +void adf_gen4_get_admin_info(struct admin_info *admin_csrs_info); +void adf_gen4_get_arb_info(struct arb_info *arb_info); +u32 adf_gen4_get_etr_bar_id(struct adf_hw_device_data *self); +u32 adf_gen4_get_heartbeat_clock(struct adf_hw_device_data *self); +u32 adf_gen4_get_misc_bar_id(struct adf_hw_device_data *self); +u32 adf_gen4_get_num_accels(struct adf_hw_device_data *self); +u32 adf_gen4_get_num_aes(struct adf_hw_device_data *self); +enum dev_sku_info adf_gen4_get_sku(struct adf_hw_device_data *self); +u32 adf_gen4_get_sram_bar_id(struct adf_hw_device_data *self); +int adf_gen4_init_device(struct adf_accel_dev *accel_dev); void adf_gen4_init_hw_csr_ops(struct adf_hw_csr_ops *csr_ops); int adf_gen4_ring_pair_reset(struct adf_accel_dev *accel_dev, u32 bank_number); +void adf_gen4_set_msix_default_rttable(struct adf_accel_dev *accel_dev); +void adf_gen4_set_ssm_wdtimer(struct adf_accel_dev *accel_dev); +int adf_gen4_init_thd2arb_map(struct adf_accel_dev *accel_dev); + #endif diff --git a/drivers/crypto/intel/qat/qat_common/adf_gen4_tl.c b/drivers/crypto/intel/qat/qat_common/adf_gen4_tl.c new file mode 100644 index 00000000000000..7fc7a77f6aed93 --- /dev/null +++ b/drivers/crypto/intel/qat/qat_common/adf_gen4_tl.c @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2023 Intel Corporation. */ +#include +#include + +#include "adf_gen4_tl.h" +#include "adf_telemetry.h" +#include "adf_tl_debugfs.h" + +#define ADF_GEN4_TL_DEV_REG_OFF(reg) ADF_TL_DEV_REG_OFF(reg, gen4) + +#define ADF_GEN4_TL_RP_REG_OFF(reg) ADF_TL_RP_REG_OFF(reg, gen4) + +#define ADF_GEN4_TL_SL_UTIL_COUNTER(_name) \ + ADF_TL_COUNTER("util_" #_name, \ + ADF_TL_SIMPLE_COUNT, \ + ADF_TL_SLICE_REG_OFF(_name, reg_tm_slice_util, gen4)) + +#define ADF_GEN4_TL_SL_EXEC_COUNTER(_name) \ + ADF_TL_COUNTER("exec_" #_name, \ + ADF_TL_SIMPLE_COUNT, \ + ADF_TL_SLICE_REG_OFF(_name, reg_tm_slice_exec_cnt, gen4)) + +/* Device level counters. */ +static const struct adf_tl_dbg_counter dev_counters[] = { + /* PCIe partial transactions. */ + ADF_TL_COUNTER(PCI_TRANS_CNT_NAME, ADF_TL_SIMPLE_COUNT, + ADF_GEN4_TL_DEV_REG_OFF(reg_tl_pci_trans_cnt)), + /* Max read latency[ns]. */ + ADF_TL_COUNTER(MAX_RD_LAT_NAME, ADF_TL_COUNTER_NS, + ADF_GEN4_TL_DEV_REG_OFF(reg_tl_rd_lat_max)), + /* Read latency average[ns]. */ + ADF_TL_COUNTER_LATENCY(RD_LAT_ACC_NAME, ADF_TL_COUNTER_NS_AVG, + ADF_GEN4_TL_DEV_REG_OFF(reg_tl_rd_lat_acc), + ADF_GEN4_TL_DEV_REG_OFF(reg_tl_rd_cmpl_cnt)), + /* Max get to put latency[ns]. */ + ADF_TL_COUNTER(MAX_LAT_NAME, ADF_TL_COUNTER_NS, + ADF_GEN4_TL_DEV_REG_OFF(reg_tl_gp_lat_max)), + /* Get to put latency average[ns]. */ + ADF_TL_COUNTER_LATENCY(LAT_ACC_NAME, ADF_TL_COUNTER_NS_AVG, + ADF_GEN4_TL_DEV_REG_OFF(reg_tl_gp_lat_acc), + ADF_GEN4_TL_DEV_REG_OFF(reg_tl_ae_put_cnt)), + /* PCIe write bandwidth[Mbps]. */ + ADF_TL_COUNTER(BW_IN_NAME, ADF_TL_COUNTER_MBPS, + ADF_GEN4_TL_DEV_REG_OFF(reg_tl_bw_in)), + /* PCIe read bandwidth[Mbps]. */ + ADF_TL_COUNTER(BW_OUT_NAME, ADF_TL_COUNTER_MBPS, + ADF_GEN4_TL_DEV_REG_OFF(reg_tl_bw_out)), + /* Page request latency average[ns]. */ + ADF_TL_COUNTER_LATENCY(PAGE_REQ_LAT_NAME, ADF_TL_COUNTER_NS_AVG, + ADF_GEN4_TL_DEV_REG_OFF(reg_tl_at_page_req_lat_acc), + ADF_GEN4_TL_DEV_REG_OFF(reg_tl_at_page_req_cnt)), + /* Page translation latency average[ns]. */ + ADF_TL_COUNTER_LATENCY(AT_TRANS_LAT_NAME, ADF_TL_COUNTER_NS_AVG, + ADF_GEN4_TL_DEV_REG_OFF(reg_tl_at_trans_lat_acc), + ADF_GEN4_TL_DEV_REG_OFF(reg_tl_at_trans_lat_cnt)), + /* Maximum uTLB used. */ + ADF_TL_COUNTER(AT_MAX_UTLB_USED_NAME, ADF_TL_SIMPLE_COUNT, + ADF_GEN4_TL_DEV_REG_OFF(reg_tl_at_max_tlb_used)), +}; + +/* Slice utilization counters. */ +static const struct adf_tl_dbg_counter sl_util_counters[ADF_TL_SL_CNT_COUNT] = { + /* Compression slice utilization. */ + ADF_GEN4_TL_SL_UTIL_COUNTER(cpr), + /* Translator slice utilization. */ + ADF_GEN4_TL_SL_UTIL_COUNTER(xlt), + /* Decompression slice utilization. */ + ADF_GEN4_TL_SL_UTIL_COUNTER(dcpr), + /* PKE utilization. */ + ADF_GEN4_TL_SL_UTIL_COUNTER(pke), + /* Wireless Authentication slice utilization. */ + ADF_GEN4_TL_SL_UTIL_COUNTER(wat), + /* Wireless Cipher slice utilization. */ + ADF_GEN4_TL_SL_UTIL_COUNTER(wcp), + /* UCS slice utilization. */ + ADF_GEN4_TL_SL_UTIL_COUNTER(ucs), + /* Cipher slice utilization. */ + ADF_GEN4_TL_SL_UTIL_COUNTER(cph), + /* Authentication slice utilization. */ + ADF_GEN4_TL_SL_UTIL_COUNTER(ath), +}; + +/* Slice execution counters. */ +static const struct adf_tl_dbg_counter sl_exec_counters[ADF_TL_SL_CNT_COUNT] = { + /* Compression slice execution count. */ + ADF_GEN4_TL_SL_EXEC_COUNTER(cpr), + /* Translator slice execution count. */ + ADF_GEN4_TL_SL_EXEC_COUNTER(xlt), + /* Decompression slice execution count. */ + ADF_GEN4_TL_SL_EXEC_COUNTER(dcpr), + /* PKE execution count. */ + ADF_GEN4_TL_SL_EXEC_COUNTER(pke), + /* Wireless Authentication slice execution count. */ + ADF_GEN4_TL_SL_EXEC_COUNTER(wat), + /* Wireless Cipher slice execution count. */ + ADF_GEN4_TL_SL_EXEC_COUNTER(wcp), + /* UCS slice execution count. */ + ADF_GEN4_TL_SL_EXEC_COUNTER(ucs), + /* Cipher slice execution count. */ + ADF_GEN4_TL_SL_EXEC_COUNTER(cph), + /* Authentication slice execution count. */ + ADF_GEN4_TL_SL_EXEC_COUNTER(ath), +}; + +/* Ring pair counters. */ +static const struct adf_tl_dbg_counter rp_counters[] = { + /* PCIe partial transactions. */ + ADF_TL_COUNTER(PCI_TRANS_CNT_NAME, ADF_TL_SIMPLE_COUNT, + ADF_GEN4_TL_RP_REG_OFF(reg_tl_pci_trans_cnt)), + /* Get to put latency average[ns]. */ + ADF_TL_COUNTER_LATENCY(LAT_ACC_NAME, ADF_TL_COUNTER_NS_AVG, + ADF_GEN4_TL_RP_REG_OFF(reg_tl_gp_lat_acc), + ADF_GEN4_TL_RP_REG_OFF(reg_tl_ae_put_cnt)), + /* PCIe write bandwidth[Mbps]. */ + ADF_TL_COUNTER(BW_IN_NAME, ADF_TL_COUNTER_MBPS, + ADF_GEN4_TL_RP_REG_OFF(reg_tl_bw_in)), + /* PCIe read bandwidth[Mbps]. */ + ADF_TL_COUNTER(BW_OUT_NAME, ADF_TL_COUNTER_MBPS, + ADF_GEN4_TL_RP_REG_OFF(reg_tl_bw_out)), + /* Message descriptor DevTLB hit rate. */ + ADF_TL_COUNTER(AT_GLOB_DTLB_HIT_NAME, ADF_TL_SIMPLE_COUNT, + ADF_GEN4_TL_RP_REG_OFF(reg_tl_at_glob_devtlb_hit)), + /* Message descriptor DevTLB miss rate. */ + ADF_TL_COUNTER(AT_GLOB_DTLB_MISS_NAME, ADF_TL_SIMPLE_COUNT, + ADF_GEN4_TL_RP_REG_OFF(reg_tl_at_glob_devtlb_miss)), + /* Payload DevTLB hit rate. */ + ADF_TL_COUNTER(AT_PAYLD_DTLB_HIT_NAME, ADF_TL_SIMPLE_COUNT, + ADF_GEN4_TL_RP_REG_OFF(reg_tl_at_payld_devtlb_hit)), + /* Payload DevTLB miss rate. */ + ADF_TL_COUNTER(AT_PAYLD_DTLB_MISS_NAME, ADF_TL_SIMPLE_COUNT, + ADF_GEN4_TL_RP_REG_OFF(reg_tl_at_payld_devtlb_miss)), +}; + +void adf_gen4_init_tl_data(struct adf_tl_hw_data *tl_data) +{ + tl_data->layout_sz = ADF_GEN4_TL_LAYOUT_SZ; + tl_data->slice_reg_sz = ADF_GEN4_TL_SLICE_REG_SZ; + tl_data->rp_reg_sz = ADF_GEN4_TL_RP_REG_SZ; + tl_data->num_hbuff = ADF_GEN4_TL_NUM_HIST_BUFFS; + tl_data->max_rp = ADF_GEN4_TL_MAX_RP_NUM; + tl_data->msg_cnt_off = ADF_GEN4_TL_MSG_CNT_OFF; + tl_data->cpp_ns_per_cycle = ADF_GEN4_CPP_NS_PER_CYCLE; + tl_data->bw_units_to_bytes = ADF_GEN4_TL_BW_HW_UNITS_TO_BYTES; + + tl_data->dev_counters = dev_counters; + tl_data->num_dev_counters = ARRAY_SIZE(dev_counters); + tl_data->sl_util_counters = sl_util_counters; + tl_data->sl_exec_counters = sl_exec_counters; + tl_data->rp_counters = rp_counters; + tl_data->num_rp_counters = ARRAY_SIZE(rp_counters); +} +EXPORT_SYMBOL_GPL(adf_gen4_init_tl_data); diff --git a/drivers/crypto/intel/qat/qat_common/adf_gen4_tl.h b/drivers/crypto/intel/qat/qat_common/adf_gen4_tl.h new file mode 100644 index 00000000000000..32df4163beb9f0 --- /dev/null +++ b/drivers/crypto/intel/qat/qat_common/adf_gen4_tl.h @@ -0,0 +1,158 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2023 Intel Corporation. */ +#ifndef ADF_GEN4_TL_H +#define ADF_GEN4_TL_H + +#include +#include + +struct adf_tl_hw_data; + +/* Computation constants. */ +#define ADF_GEN4_CPP_NS_PER_CYCLE 2 +#define ADF_GEN4_TL_BW_HW_UNITS_TO_BYTES 64 + +/* Maximum aggregation time. Value in milliseconds. */ +#define ADF_GEN4_TL_MAX_AGGR_TIME_MS 4000 +/* Num of buffers to store historic values. */ +#define ADF_GEN4_TL_NUM_HIST_BUFFS \ + (ADF_GEN4_TL_MAX_AGGR_TIME_MS / ADF_TL_DATA_WR_INTERVAL_MS) + +/* Max number of HW resources of one type. */ +#define ADF_GEN4_TL_MAX_SLICES_PER_TYPE 24 + +/* Max number of simultaneously monitored ring pairs. */ +#define ADF_GEN4_TL_MAX_RP_NUM 4 + +/** + * struct adf_gen4_tl_slice_data_regs - HW slice data as populated by FW. + * @reg_tm_slice_exec_cnt: Slice execution count. + * @reg_tm_slice_util: Slice utilization. + */ +struct adf_gen4_tl_slice_data_regs { + __u32 reg_tm_slice_exec_cnt; + __u32 reg_tm_slice_util; +}; + +#define ADF_GEN4_TL_SLICE_REG_SZ sizeof(struct adf_gen4_tl_slice_data_regs) + +/** + * struct adf_gen4_tl_device_data_regs - This structure stores device telemetry + * counter values as are being populated periodically by device. + * @reg_tl_rd_lat_acc: read latency accumulator + * @reg_tl_gp_lat_acc: get-put latency accumulator + * @reg_tl_at_page_req_lat_acc: AT/DevTLB page request latency accumulator + * @reg_tl_at_trans_lat_acc: DevTLB transaction latency accumulator + * @reg_tl_re_acc: accumulated ring empty time + * @reg_tl_pci_trans_cnt: PCIe partial transactions + * @reg_tl_rd_lat_max: maximum logged read latency + * @reg_tl_rd_cmpl_cnt: read requests completed count + * @reg_tl_gp_lat_max: maximum logged get to put latency + * @reg_tl_ae_put_cnt: Accelerator Engine put counts across all rings + * @reg_tl_bw_in: PCIe write bandwidth + * @reg_tl_bw_out: PCIe read bandwidth + * @reg_tl_at_page_req_cnt: DevTLB page requests count + * @reg_tl_at_trans_lat_cnt: DevTLB transaction latency samples count + * @reg_tl_at_max_tlb_used: maximum uTLB used + * @reg_tl_re_cnt: ring empty time samples count + * @reserved: reserved + * @ath_slices: array of Authentication slices utilization registers + * @cph_slices: array of Cipher slices utilization registers + * @cpr_slices: array of Compression slices utilization registers + * @xlt_slices: array of Translator slices utilization registers + * @dcpr_slices: array of Decompression slices utilization registers + * @pke_slices: array of PKE slices utilization registers + * @ucs_slices: array of UCS slices utilization registers + * @wat_slices: array of Wireless Authentication slices utilization registers + * @wcp_slices: array of Wireless Cipher slices utilization registers + */ +struct adf_gen4_tl_device_data_regs { + __u64 reg_tl_rd_lat_acc; + __u64 reg_tl_gp_lat_acc; + __u64 reg_tl_at_page_req_lat_acc; + __u64 reg_tl_at_trans_lat_acc; + __u64 reg_tl_re_acc; + __u32 reg_tl_pci_trans_cnt; + __u32 reg_tl_rd_lat_max; + __u32 reg_tl_rd_cmpl_cnt; + __u32 reg_tl_gp_lat_max; + __u32 reg_tl_ae_put_cnt; + __u32 reg_tl_bw_in; + __u32 reg_tl_bw_out; + __u32 reg_tl_at_page_req_cnt; + __u32 reg_tl_at_trans_lat_cnt; + __u32 reg_tl_at_max_tlb_used; + __u32 reg_tl_re_cnt; + __u32 reserved; + struct adf_gen4_tl_slice_data_regs ath_slices[ADF_GEN4_TL_MAX_SLICES_PER_TYPE]; + struct adf_gen4_tl_slice_data_regs cph_slices[ADF_GEN4_TL_MAX_SLICES_PER_TYPE]; + struct adf_gen4_tl_slice_data_regs cpr_slices[ADF_GEN4_TL_MAX_SLICES_PER_TYPE]; + struct adf_gen4_tl_slice_data_regs xlt_slices[ADF_GEN4_TL_MAX_SLICES_PER_TYPE]; + struct adf_gen4_tl_slice_data_regs dcpr_slices[ADF_GEN4_TL_MAX_SLICES_PER_TYPE]; + struct adf_gen4_tl_slice_data_regs pke_slices[ADF_GEN4_TL_MAX_SLICES_PER_TYPE]; + struct adf_gen4_tl_slice_data_regs ucs_slices[ADF_GEN4_TL_MAX_SLICES_PER_TYPE]; + struct adf_gen4_tl_slice_data_regs wat_slices[ADF_GEN4_TL_MAX_SLICES_PER_TYPE]; + struct adf_gen4_tl_slice_data_regs wcp_slices[ADF_GEN4_TL_MAX_SLICES_PER_TYPE]; +}; + +/** + * struct adf_gen4_tl_ring_pair_data_regs - This structure stores Ring Pair + * telemetry counter values as are being populated periodically by device. + * @reg_tl_gp_lat_acc: get-put latency accumulator + * @reserved: reserved + * @reg_tl_pci_trans_cnt: PCIe partial transactions + * @reg_tl_ae_put_cnt: Accelerator Engine put counts across all rings + * @reg_tl_bw_in: PCIe write bandwidth + * @reg_tl_bw_out: PCIe read bandwidth + * @reg_tl_at_glob_devtlb_hit: Message descriptor DevTLB hit rate + * @reg_tl_at_glob_devtlb_miss: Message descriptor DevTLB miss rate + * @reg_tl_at_payld_devtlb_hit: Payload DevTLB hit rate + * @reg_tl_at_payld_devtlb_miss: Payload DevTLB miss rate + * @reg_tl_re_cnt: ring empty time samples count + * @reserved1: reserved + */ +struct adf_gen4_tl_ring_pair_data_regs { + __u64 reg_tl_gp_lat_acc; + __u64 reserved; + __u32 reg_tl_pci_trans_cnt; + __u32 reg_tl_ae_put_cnt; + __u32 reg_tl_bw_in; + __u32 reg_tl_bw_out; + __u32 reg_tl_at_glob_devtlb_hit; + __u32 reg_tl_at_glob_devtlb_miss; + __u32 reg_tl_at_payld_devtlb_hit; + __u32 reg_tl_at_payld_devtlb_miss; + __u32 reg_tl_re_cnt; + __u32 reserved1; +}; + +#define ADF_GEN4_TL_RP_REG_SZ sizeof(struct adf_gen4_tl_ring_pair_data_regs) + +/** + * struct adf_gen4_tl_layout - This structure represents entire telemetry + * counters data: Device + 4 Ring Pairs as are being populated periodically + * by device. + * @tl_device_data_regs: structure of device telemetry registers + * @tl_ring_pairs_data_regs: array of ring pairs telemetry registers + * @reg_tl_msg_cnt: telemetry messages counter + * @reserved: reserved + */ +struct adf_gen4_tl_layout { + struct adf_gen4_tl_device_data_regs tl_device_data_regs; + struct adf_gen4_tl_ring_pair_data_regs + tl_ring_pairs_data_regs[ADF_GEN4_TL_MAX_RP_NUM]; + __u32 reg_tl_msg_cnt; + __u32 reserved; +}; + +#define ADF_GEN4_TL_LAYOUT_SZ sizeof(struct adf_gen4_tl_layout) +#define ADF_GEN4_TL_MSG_CNT_OFF offsetof(struct adf_gen4_tl_layout, reg_tl_msg_cnt) + +#ifdef CONFIG_DEBUG_FS +void adf_gen4_init_tl_data(struct adf_tl_hw_data *tl_data); +#else +static inline void adf_gen4_init_tl_data(struct adf_tl_hw_data *tl_data) +{ +} +#endif /* CONFIG_DEBUG_FS */ +#endif /* ADF_GEN4_TL_H */ diff --git a/drivers/crypto/intel/qat/qat_common/adf_init.c b/drivers/crypto/intel/qat/qat_common/adf_init.c index 81c39f3d07e1c4..f43ae9111553f3 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_init.c +++ b/drivers/crypto/intel/qat/qat_common/adf_init.c @@ -11,6 +11,7 @@ #include "adf_heartbeat.h" #include "adf_rl.h" #include "adf_sysfs_ras_counters.h" +#include "adf_telemetry.h" static LIST_HEAD(service_table); static DEFINE_MUTEX(service_lock); @@ -142,6 +143,10 @@ static int adf_dev_init(struct adf_accel_dev *accel_dev) if (ret && ret != -EOPNOTSUPP) return ret; + ret = adf_tl_init(accel_dev); + if (ret && ret != -EOPNOTSUPP) + return ret; + /* * Subservice initialisation is divided into two stages: init and start. * This is to facilitate any ordering dependencies between services @@ -220,6 +225,10 @@ static int adf_dev_start(struct adf_accel_dev *accel_dev) if (ret && ret != -EOPNOTSUPP) return ret; + ret = adf_tl_start(accel_dev); + if (ret && ret != -EOPNOTSUPP) + return ret; + list_for_each_entry(service, &service_table, list) { if (service->event_hld(accel_dev, ADF_EVENT_START)) { dev_err(&GET_DEV(accel_dev), @@ -279,6 +288,7 @@ static void adf_dev_stop(struct adf_accel_dev *accel_dev) !test_bit(ADF_STATUS_STARTING, &accel_dev->status)) return; + adf_tl_stop(accel_dev); adf_rl_stop(accel_dev); adf_dbgfs_rm(accel_dev); adf_sysfs_stop_ras(accel_dev); @@ -374,6 +384,8 @@ static void adf_dev_shutdown(struct adf_accel_dev *accel_dev) adf_heartbeat_shutdown(accel_dev); + adf_tl_shutdown(accel_dev); + hw_data->disable_iov(accel_dev); if (test_bit(ADF_STATUS_IRQ_ALLOCATED, &accel_dev->status)) { diff --git a/drivers/crypto/intel/qat/qat_common/adf_rl.c b/drivers/crypto/intel/qat/qat_common/adf_rl.c index 86e3e2152b1b00..de1b214dba1f98 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_rl.c +++ b/drivers/crypto/intel/qat/qat_common/adf_rl.c @@ -812,17 +812,16 @@ static int add_update_sla(struct adf_accel_dev *accel_dev, if (!sla_in) { dev_warn(&GET_DEV(accel_dev), "SLA input data pointer is missing\n"); - ret = -EFAULT; - goto ret_err; + return -EFAULT; } + mutex_lock(&rl_data->rl_lock); + /* Input validation */ ret = validate_user_input(accel_dev, sla_in, is_update); if (ret) goto ret_err; - mutex_lock(&rl_data->rl_lock); - if (is_update) { ret = validate_sla_id(accel_dev, sla_in->sla_id); if (ret) diff --git a/drivers/crypto/intel/qat/qat_common/adf_rl.h b/drivers/crypto/intel/qat/qat_common/adf_rl.h index eb5a330f85437e..269c6656fb90ea 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_rl.h +++ b/drivers/crypto/intel/qat/qat_common/adf_rl.h @@ -79,6 +79,7 @@ struct adf_rl_interface_data { struct adf_rl_sla_input_data input; enum adf_base_services cap_rem_srv; struct rw_semaphore lock; + bool sysfs_added; }; struct adf_rl_hw_data { diff --git a/drivers/crypto/intel/qat/qat_common/adf_sysfs.c b/drivers/crypto/intel/qat/qat_common/adf_sysfs.c index ddffc98119c6b8..d450dad32c9e4e 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_sysfs.c +++ b/drivers/crypto/intel/qat/qat_common/adf_sysfs.c @@ -215,6 +215,9 @@ static ssize_t rp2srv_show(struct device *dev, struct device_attribute *attr, enum adf_cfg_service_type svc; accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev)); + if (!accel_dev) + return -EINVAL; + hw_data = GET_HW_DATA(accel_dev); if (accel_dev->sysfs.ring_num == UNSET_RING_NUM) @@ -242,7 +245,8 @@ static ssize_t rp2srv_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct adf_accel_dev *accel_dev; - int ring, num_rings, ret; + int num_rings, ret; + unsigned int ring; accel_dev = adf_devmgr_pci_to_accel_dev(to_pci_dev(dev)); if (!accel_dev) diff --git a/drivers/crypto/intel/qat/qat_common/adf_sysfs_ras_counters.c b/drivers/crypto/intel/qat/qat_common/adf_sysfs_ras_counters.c index cffe2d7229953d..e97c67c87b3cf1 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_sysfs_ras_counters.c +++ b/drivers/crypto/intel/qat/qat_common/adf_sysfs_ras_counters.c @@ -99,6 +99,8 @@ void adf_sysfs_start_ras(struct adf_accel_dev *accel_dev) if (device_add_group(&GET_DEV(accel_dev), &qat_ras_group)) dev_err(&GET_DEV(accel_dev), "Failed to create qat_ras attribute group.\n"); + + accel_dev->ras_errors.sysfs_added = true; } void adf_sysfs_stop_ras(struct adf_accel_dev *accel_dev) @@ -106,7 +108,10 @@ void adf_sysfs_stop_ras(struct adf_accel_dev *accel_dev) if (!accel_dev->ras_errors.enabled) return; - device_remove_group(&GET_DEV(accel_dev), &qat_ras_group); + if (accel_dev->ras_errors.sysfs_added) { + device_remove_group(&GET_DEV(accel_dev), &qat_ras_group); + accel_dev->ras_errors.sysfs_added = false; + } ADF_RAS_ERR_CTR_CLEAR(accel_dev->ras_errors); } diff --git a/drivers/crypto/intel/qat/qat_common/adf_sysfs_rl.c b/drivers/crypto/intel/qat/qat_common/adf_sysfs_rl.c index abf9c52474eca9..bedb514d4e3042 100644 --- a/drivers/crypto/intel/qat/qat_common/adf_sysfs_rl.c +++ b/drivers/crypto/intel/qat/qat_common/adf_sysfs_rl.c @@ -441,11 +441,19 @@ int adf_sysfs_rl_add(struct adf_accel_dev *accel_dev) data->cap_rem_srv = ADF_SVC_NONE; data->input.srv = ADF_SVC_NONE; + data->sysfs_added = true; return ret; } void adf_sysfs_rl_rm(struct adf_accel_dev *accel_dev) { + struct adf_rl_interface_data *data; + + data = &GET_RL_STRUCT(accel_dev); + if (!data->sysfs_added) + return; + device_remove_group(&GET_DEV(accel_dev), &qat_rl_group); + data->sysfs_added = false; } diff --git a/drivers/crypto/intel/qat/qat_common/adf_telemetry.c b/drivers/crypto/intel/qat/qat_common/adf_telemetry.c new file mode 100644 index 00000000000000..2ff714d11bd2f6 --- /dev/null +++ b/drivers/crypto/intel/qat/qat_common/adf_telemetry.c @@ -0,0 +1,288 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2023 Intel Corporation. */ +#define dev_fmt(fmt) "Telemetry: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "adf_admin.h" +#include "adf_accel_devices.h" +#include "adf_common_drv.h" +#include "adf_telemetry.h" + +#define TL_IS_ZERO(input) ((input) == 0) + +static bool is_tl_supported(struct adf_accel_dev *accel_dev) +{ + u16 fw_caps = GET_HW_DATA(accel_dev)->fw_capabilities; + + return fw_caps & TL_CAPABILITY_BIT; +} + +static int validate_tl_data(struct adf_tl_hw_data *tl_data) +{ + if (!tl_data->dev_counters || + TL_IS_ZERO(tl_data->num_dev_counters) || + !tl_data->sl_util_counters || + !tl_data->sl_exec_counters || + !tl_data->rp_counters || + TL_IS_ZERO(tl_data->num_rp_counters)) + return -EOPNOTSUPP; + + return 0; +} + +static int adf_tl_alloc_mem(struct adf_accel_dev *accel_dev) +{ + struct adf_tl_hw_data *tl_data = &GET_TL_DATA(accel_dev); + struct device *dev = &GET_DEV(accel_dev); + size_t regs_sz = tl_data->layout_sz; + struct adf_telemetry *telemetry; + int node = dev_to_node(dev); + void *tl_data_regs; + unsigned int i; + + telemetry = kzalloc_node(sizeof(*telemetry), GFP_KERNEL, node); + if (!telemetry) + return -ENOMEM; + + telemetry->rp_num_indexes = kmalloc_array(tl_data->max_rp, + sizeof(*telemetry->rp_num_indexes), + GFP_KERNEL); + if (!telemetry->rp_num_indexes) + goto err_free_tl; + + telemetry->regs_hist_buff = kmalloc_array(tl_data->num_hbuff, + sizeof(*telemetry->regs_hist_buff), + GFP_KERNEL); + if (!telemetry->regs_hist_buff) + goto err_free_rp_indexes; + + telemetry->regs_data = dma_alloc_coherent(dev, regs_sz, + &telemetry->regs_data_p, + GFP_KERNEL); + if (!telemetry->regs_data) + goto err_free_regs_hist_buff; + + for (i = 0; i < tl_data->num_hbuff; i++) { + tl_data_regs = kzalloc_node(regs_sz, GFP_KERNEL, node); + if (!tl_data_regs) + goto err_free_dma; + + telemetry->regs_hist_buff[i] = tl_data_regs; + } + + accel_dev->telemetry = telemetry; + + return 0; + +err_free_dma: + dma_free_coherent(dev, regs_sz, telemetry->regs_data, + telemetry->regs_data_p); + + while (i--) + kfree(telemetry->regs_hist_buff[i]); + +err_free_regs_hist_buff: + kfree(telemetry->regs_hist_buff); +err_free_rp_indexes: + kfree(telemetry->rp_num_indexes); +err_free_tl: + kfree(telemetry); + + return -ENOMEM; +} + +static void adf_tl_free_mem(struct adf_accel_dev *accel_dev) +{ + struct adf_tl_hw_data *tl_data = &GET_TL_DATA(accel_dev); + struct adf_telemetry *telemetry = accel_dev->telemetry; + struct device *dev = &GET_DEV(accel_dev); + size_t regs_sz = tl_data->layout_sz; + unsigned int i; + + for (i = 0; i < tl_data->num_hbuff; i++) + kfree(telemetry->regs_hist_buff[i]); + + dma_free_coherent(dev, regs_sz, telemetry->regs_data, + telemetry->regs_data_p); + + kfree(telemetry->regs_hist_buff); + kfree(telemetry->rp_num_indexes); + kfree(telemetry); + accel_dev->telemetry = NULL; +} + +static unsigned long get_next_timeout(void) +{ + return msecs_to_jiffies(ADF_TL_TIMER_INT_MS); +} + +static void snapshot_regs(struct adf_telemetry *telemetry, size_t size) +{ + void *dst = telemetry->regs_hist_buff[telemetry->hb_num]; + void *src = telemetry->regs_data; + + memcpy(dst, src, size); +} + +static void tl_work_handler(struct work_struct *work) +{ + struct delayed_work *delayed_work; + struct adf_telemetry *telemetry; + struct adf_tl_hw_data *tl_data; + u32 msg_cnt, old_msg_cnt; + size_t layout_sz; + u32 *regs_data; + size_t id; + + delayed_work = to_delayed_work(work); + telemetry = container_of(delayed_work, struct adf_telemetry, work_ctx); + tl_data = &GET_TL_DATA(telemetry->accel_dev); + regs_data = telemetry->regs_data; + + id = tl_data->msg_cnt_off / sizeof(*regs_data); + layout_sz = tl_data->layout_sz; + + if (!atomic_read(&telemetry->state)) { + cancel_delayed_work_sync(&telemetry->work_ctx); + return; + } + + msg_cnt = regs_data[id]; + old_msg_cnt = msg_cnt; + if (msg_cnt == telemetry->msg_cnt) + goto out; + + mutex_lock(&telemetry->regs_hist_lock); + + snapshot_regs(telemetry, layout_sz); + + /* Check if data changed while updating it */ + msg_cnt = regs_data[id]; + if (old_msg_cnt != msg_cnt) + snapshot_regs(telemetry, layout_sz); + + telemetry->msg_cnt = msg_cnt; + telemetry->hb_num++; + telemetry->hb_num %= telemetry->hbuffs; + + mutex_unlock(&telemetry->regs_hist_lock); + +out: + adf_misc_wq_queue_delayed_work(&telemetry->work_ctx, get_next_timeout()); +} + +int adf_tl_halt(struct adf_accel_dev *accel_dev) +{ + struct adf_telemetry *telemetry = accel_dev->telemetry; + struct device *dev = &GET_DEV(accel_dev); + int ret; + + cancel_delayed_work_sync(&telemetry->work_ctx); + atomic_set(&telemetry->state, 0); + + ret = adf_send_admin_tl_stop(accel_dev); + if (ret) + dev_err(dev, "failed to stop telemetry\n"); + + return ret; +} + +int adf_tl_run(struct adf_accel_dev *accel_dev, int state) +{ + struct adf_tl_hw_data *tl_data = &GET_TL_DATA(accel_dev); + struct adf_telemetry *telemetry = accel_dev->telemetry; + struct device *dev = &GET_DEV(accel_dev); + size_t layout_sz = tl_data->layout_sz; + int ret; + + ret = adf_send_admin_tl_start(accel_dev, telemetry->regs_data_p, + layout_sz, telemetry->rp_num_indexes, + &telemetry->slice_cnt); + if (ret) { + dev_err(dev, "failed to start telemetry\n"); + return ret; + } + + telemetry->hbuffs = state; + atomic_set(&telemetry->state, state); + + adf_misc_wq_queue_delayed_work(&telemetry->work_ctx, get_next_timeout()); + + return 0; +} + +int adf_tl_init(struct adf_accel_dev *accel_dev) +{ + struct adf_tl_hw_data *tl_data = &GET_TL_DATA(accel_dev); + u8 max_rp = GET_TL_DATA(accel_dev).max_rp; + struct device *dev = &GET_DEV(accel_dev); + struct adf_telemetry *telemetry; + unsigned int i; + int ret; + + ret = validate_tl_data(tl_data); + if (ret) + return ret; + + ret = adf_tl_alloc_mem(accel_dev); + if (ret) { + dev_err(dev, "failed to initialize: %d\n", ret); + return ret; + } + + telemetry = accel_dev->telemetry; + telemetry->accel_dev = accel_dev; + + mutex_init(&telemetry->wr_lock); + mutex_init(&telemetry->regs_hist_lock); + INIT_DELAYED_WORK(&telemetry->work_ctx, tl_work_handler); + + for (i = 0; i < max_rp; i++) + telemetry->rp_num_indexes[i] = ADF_TL_RP_REGS_DISABLED; + + return 0; +} + +int adf_tl_start(struct adf_accel_dev *accel_dev) +{ + struct device *dev = &GET_DEV(accel_dev); + + if (!accel_dev->telemetry) + return -EOPNOTSUPP; + + if (!is_tl_supported(accel_dev)) { + dev_info(dev, "feature not supported by FW\n"); + adf_tl_free_mem(accel_dev); + return -EOPNOTSUPP; + } + + return 0; +} + +void adf_tl_stop(struct adf_accel_dev *accel_dev) +{ + if (!accel_dev->telemetry) + return; + + if (atomic_read(&accel_dev->telemetry->state)) + adf_tl_halt(accel_dev); +} + +void adf_tl_shutdown(struct adf_accel_dev *accel_dev) +{ + if (!accel_dev->telemetry) + return; + + adf_tl_free_mem(accel_dev); +} diff --git a/drivers/crypto/intel/qat/qat_common/adf_telemetry.h b/drivers/crypto/intel/qat/qat_common/adf_telemetry.h new file mode 100644 index 00000000000000..9be81cd3b88606 --- /dev/null +++ b/drivers/crypto/intel/qat/qat_common/adf_telemetry.h @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2023 Intel Corporation. */ +#ifndef ADF_TELEMETRY_H +#define ADF_TELEMETRY_H + +#include +#include +#include +#include + +#include "icp_qat_fw_init_admin.h" + +struct adf_accel_dev; +struct adf_tl_dbg_counter; +struct dentry; + +#define ADF_TL_SL_CNT_COUNT \ + (sizeof(struct icp_qat_fw_init_admin_slice_cnt) / sizeof(__u8)) + +#define TL_CAPABILITY_BIT BIT(1) +/* Interval within device writes data to DMA region. Value in milliseconds. */ +#define ADF_TL_DATA_WR_INTERVAL_MS 1000 +/* Interval within timer interrupt should be handled. Value in milliseconds. */ +#define ADF_TL_TIMER_INT_MS (ADF_TL_DATA_WR_INTERVAL_MS / 2) + +#define ADF_TL_RP_REGS_DISABLED (0xff) + +struct adf_tl_hw_data { + size_t layout_sz; + size_t slice_reg_sz; + size_t rp_reg_sz; + size_t msg_cnt_off; + const struct adf_tl_dbg_counter *dev_counters; + const struct adf_tl_dbg_counter *sl_util_counters; + const struct adf_tl_dbg_counter *sl_exec_counters; + const struct adf_tl_dbg_counter *rp_counters; + u8 num_hbuff; + u8 cpp_ns_per_cycle; + u8 bw_units_to_bytes; + u8 num_dev_counters; + u8 num_rp_counters; + u8 max_rp; +}; + +struct adf_telemetry { + struct adf_accel_dev *accel_dev; + atomic_t state; + u32 hbuffs; + int hb_num; + u32 msg_cnt; + dma_addr_t regs_data_p; /* bus address for DMA mapping */ + void *regs_data; /* virtual address for DMA mapping */ + /** + * @regs_hist_buff: array of pointers to copies of the last @hbuffs + * values of @regs_data + */ + void **regs_hist_buff; + struct dentry *dbg_dir; + u8 *rp_num_indexes; + /** + * @regs_hist_lock: protects from race conditions between write and read + * to the copies referenced by @regs_hist_buff + */ + struct mutex regs_hist_lock; + /** + * @wr_lock: protects from concurrent writes to debugfs telemetry files + */ + struct mutex wr_lock; + struct delayed_work work_ctx; + struct icp_qat_fw_init_admin_slice_cnt slice_cnt; +}; + +#ifdef CONFIG_DEBUG_FS +int adf_tl_init(struct adf_accel_dev *accel_dev); +int adf_tl_start(struct adf_accel_dev *accel_dev); +void adf_tl_stop(struct adf_accel_dev *accel_dev); +void adf_tl_shutdown(struct adf_accel_dev *accel_dev); +int adf_tl_run(struct adf_accel_dev *accel_dev, int state); +int adf_tl_halt(struct adf_accel_dev *accel_dev); +#else +static inline int adf_tl_init(struct adf_accel_dev *accel_dev) +{ + return 0; +} + +static inline int adf_tl_start(struct adf_accel_dev *accel_dev) +{ + return 0; +} + +static inline void adf_tl_stop(struct adf_accel_dev *accel_dev) +{ +} + +static inline void adf_tl_shutdown(struct adf_accel_dev *accel_dev) +{ +} +#endif /* CONFIG_DEBUG_FS */ +#endif /* ADF_TELEMETRY_H */ diff --git a/drivers/crypto/intel/qat/qat_common/adf_tl_debugfs.c b/drivers/crypto/intel/qat/qat_common/adf_tl_debugfs.c new file mode 100644 index 00000000000000..c8241f5a0a26ee --- /dev/null +++ b/drivers/crypto/intel/qat/qat_common/adf_tl_debugfs.c @@ -0,0 +1,710 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2023 Intel Corporation. */ +#define dev_fmt(fmt) "Telemetry debugfs: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "adf_accel_devices.h" +#include "adf_cfg_strings.h" +#include "adf_telemetry.h" +#include "adf_tl_debugfs.h" + +#define TL_VALUE_MIN_PADDING 20 +#define TL_KEY_MIN_PADDING 23 +#define TL_RP_SRV_UNKNOWN "Unknown" + +static int tl_collect_values_u32(struct adf_telemetry *telemetry, + size_t counter_offset, u64 *arr) +{ + unsigned int samples, hb_idx, i; + u32 *regs_hist_buff; + u32 counter_val; + + samples = min(telemetry->msg_cnt, telemetry->hbuffs); + hb_idx = telemetry->hb_num + telemetry->hbuffs - samples; + + mutex_lock(&telemetry->regs_hist_lock); + + for (i = 0; i < samples; i++) { + regs_hist_buff = telemetry->regs_hist_buff[hb_idx % telemetry->hbuffs]; + counter_val = regs_hist_buff[counter_offset / sizeof(counter_val)]; + arr[i] = counter_val; + hb_idx++; + } + + mutex_unlock(&telemetry->regs_hist_lock); + + return samples; +} + +static int tl_collect_values_u64(struct adf_telemetry *telemetry, + size_t counter_offset, u64 *arr) +{ + unsigned int samples, hb_idx, i; + u64 *regs_hist_buff; + u64 counter_val; + + samples = min(telemetry->msg_cnt, telemetry->hbuffs); + hb_idx = telemetry->hb_num + telemetry->hbuffs - samples; + + mutex_lock(&telemetry->regs_hist_lock); + + for (i = 0; i < samples; i++) { + regs_hist_buff = telemetry->regs_hist_buff[hb_idx % telemetry->hbuffs]; + counter_val = regs_hist_buff[counter_offset / sizeof(counter_val)]; + arr[i] = counter_val; + hb_idx++; + } + + mutex_unlock(&telemetry->regs_hist_lock); + + return samples; +} + +/** + * avg_array() - Return average of values within an array. + * @array: Array of values. + * @len: Number of elements. + * + * This algorithm computes average of an array without running into overflow. + * + * Return: average of values. + */ +#define avg_array(array, len) ( \ +{ \ + typeof(&(array)[0]) _array = (array); \ + __unqual_scalar_typeof(_array[0]) _x = 0; \ + __unqual_scalar_typeof(_array[0]) _y = 0; \ + __unqual_scalar_typeof(_array[0]) _a, _b; \ + typeof(len) _len = (len); \ + size_t _i; \ + \ + for (_i = 0; _i < _len; _i++) { \ + _a = _array[_i]; \ + _b = do_div(_a, _len); \ + _x += _a; \ + if (_y >= _len - _b) { \ + _x++; \ + _y -= _len - _b; \ + } else { \ + _y += _b; \ + } \ + } \ + do_div(_y, _len); \ + (_x + _y); \ +}) + +/* Calculation function for simple counter. */ +static int tl_calc_count(struct adf_telemetry *telemetry, + const struct adf_tl_dbg_counter *ctr, + struct adf_tl_dbg_aggr_values *vals) +{ + struct adf_tl_hw_data *tl_data = &GET_TL_DATA(telemetry->accel_dev); + u64 *hist_vals; + int sample_cnt; + int ret = 0; + + hist_vals = kmalloc_array(tl_data->num_hbuff, sizeof(*hist_vals), + GFP_KERNEL); + if (!hist_vals) + return -ENOMEM; + + memset(vals, 0, sizeof(*vals)); + sample_cnt = tl_collect_values_u32(telemetry, ctr->offset1, hist_vals); + if (!sample_cnt) + goto out_free_hist_vals; + + vals->curr = hist_vals[sample_cnt - 1]; + vals->min = min_array(hist_vals, sample_cnt); + vals->max = max_array(hist_vals, sample_cnt); + vals->avg = avg_array(hist_vals, sample_cnt); + +out_free_hist_vals: + kfree(hist_vals); + return ret; +} + +/* Convert CPP bus cycles to ns. */ +static int tl_cycles_to_ns(struct adf_telemetry *telemetry, + const struct adf_tl_dbg_counter *ctr, + struct adf_tl_dbg_aggr_values *vals) +{ + struct adf_tl_hw_data *tl_data = &GET_TL_DATA(telemetry->accel_dev); + u8 cpp_ns_per_cycle = tl_data->cpp_ns_per_cycle; + int ret; + + ret = tl_calc_count(telemetry, ctr, vals); + if (ret) + return ret; + + vals->curr *= cpp_ns_per_cycle; + vals->min *= cpp_ns_per_cycle; + vals->max *= cpp_ns_per_cycle; + vals->avg *= cpp_ns_per_cycle; + + return 0; +} + +/* + * Compute latency cumulative average with division of accumulated value + * by sample count. Returned value is in ns. + */ +static int tl_lat_acc_avg(struct adf_telemetry *telemetry, + const struct adf_tl_dbg_counter *ctr, + struct adf_tl_dbg_aggr_values *vals) +{ + struct adf_tl_hw_data *tl_data = &GET_TL_DATA(telemetry->accel_dev); + u8 cpp_ns_per_cycle = tl_data->cpp_ns_per_cycle; + u8 num_hbuff = tl_data->num_hbuff; + int sample_cnt, i; + u64 *hist_vals; + u64 *hist_cnt; + int ret = 0; + + hist_vals = kmalloc_array(num_hbuff, sizeof(*hist_vals), GFP_KERNEL); + if (!hist_vals) + return -ENOMEM; + + hist_cnt = kmalloc_array(num_hbuff, sizeof(*hist_cnt), GFP_KERNEL); + if (!hist_cnt) { + ret = -ENOMEM; + goto out_free_hist_vals; + } + + memset(vals, 0, sizeof(*vals)); + sample_cnt = tl_collect_values_u64(telemetry, ctr->offset1, hist_vals); + if (!sample_cnt) + goto out_free_hist_cnt; + + tl_collect_values_u32(telemetry, ctr->offset2, hist_cnt); + + for (i = 0; i < sample_cnt; i++) { + /* Avoid division by 0 if count is 0. */ + if (hist_cnt[i]) + hist_vals[i] = div_u64(hist_vals[i] * cpp_ns_per_cycle, + hist_cnt[i]); + else + hist_vals[i] = 0; + } + + vals->curr = hist_vals[sample_cnt - 1]; + vals->min = min_array(hist_vals, sample_cnt); + vals->max = max_array(hist_vals, sample_cnt); + vals->avg = avg_array(hist_vals, sample_cnt); + +out_free_hist_cnt: + kfree(hist_cnt); +out_free_hist_vals: + kfree(hist_vals); + return ret; +} + +/* Convert HW raw bandwidth units to Mbps. */ +static int tl_bw_hw_units_to_mbps(struct adf_telemetry *telemetry, + const struct adf_tl_dbg_counter *ctr, + struct adf_tl_dbg_aggr_values *vals) +{ + struct adf_tl_hw_data *tl_data = &GET_TL_DATA(telemetry->accel_dev); + u16 bw_hw_2_bits = tl_data->bw_units_to_bytes * BITS_PER_BYTE; + u64 *hist_vals; + int sample_cnt; + int ret = 0; + + hist_vals = kmalloc_array(tl_data->num_hbuff, sizeof(*hist_vals), + GFP_KERNEL); + if (!hist_vals) + return -ENOMEM; + + memset(vals, 0, sizeof(*vals)); + sample_cnt = tl_collect_values_u32(telemetry, ctr->offset1, hist_vals); + if (!sample_cnt) + goto out_free_hist_vals; + + vals->curr = div_u64(hist_vals[sample_cnt - 1] * bw_hw_2_bits, MEGA); + vals->min = div_u64(min_array(hist_vals, sample_cnt) * bw_hw_2_bits, MEGA); + vals->max = div_u64(max_array(hist_vals, sample_cnt) * bw_hw_2_bits, MEGA); + vals->avg = div_u64(avg_array(hist_vals, sample_cnt) * bw_hw_2_bits, MEGA); + +out_free_hist_vals: + kfree(hist_vals); + return ret; +} + +static void tl_seq_printf_counter(struct adf_telemetry *telemetry, + struct seq_file *s, const char *name, + struct adf_tl_dbg_aggr_values *vals) +{ + seq_printf(s, "%-*s", TL_KEY_MIN_PADDING, name); + seq_printf(s, "%*llu", TL_VALUE_MIN_PADDING, vals->curr); + if (atomic_read(&telemetry->state) > 1) { + seq_printf(s, "%*llu", TL_VALUE_MIN_PADDING, vals->min); + seq_printf(s, "%*llu", TL_VALUE_MIN_PADDING, vals->max); + seq_printf(s, "%*llu", TL_VALUE_MIN_PADDING, vals->avg); + } + seq_puts(s, "\n"); +} + +static int tl_calc_and_print_counter(struct adf_telemetry *telemetry, + struct seq_file *s, + const struct adf_tl_dbg_counter *ctr, + const char *name) +{ + const char *counter_name = name ? name : ctr->name; + enum adf_tl_counter_type type = ctr->type; + struct adf_tl_dbg_aggr_values vals; + int ret; + + switch (type) { + case ADF_TL_SIMPLE_COUNT: + ret = tl_calc_count(telemetry, ctr, &vals); + break; + case ADF_TL_COUNTER_NS: + ret = tl_cycles_to_ns(telemetry, ctr, &vals); + break; + case ADF_TL_COUNTER_NS_AVG: + ret = tl_lat_acc_avg(telemetry, ctr, &vals); + break; + case ADF_TL_COUNTER_MBPS: + ret = tl_bw_hw_units_to_mbps(telemetry, ctr, &vals); + break; + default: + return -EINVAL; + } + + if (ret) + return ret; + + tl_seq_printf_counter(telemetry, s, counter_name, &vals); + + return 0; +} + +static int tl_print_sl_counter(struct adf_telemetry *telemetry, + const struct adf_tl_dbg_counter *ctr, + struct seq_file *s, u8 cnt_id) +{ + size_t sl_regs_sz = GET_TL_DATA(telemetry->accel_dev).slice_reg_sz; + struct adf_tl_dbg_counter slice_ctr; + size_t offset_inc = cnt_id * sl_regs_sz; + char cnt_name[MAX_COUNT_NAME_SIZE]; + + snprintf(cnt_name, MAX_COUNT_NAME_SIZE, "%s%d", ctr->name, cnt_id); + slice_ctr = *ctr; + slice_ctr.offset1 += offset_inc; + + return tl_calc_and_print_counter(telemetry, s, &slice_ctr, cnt_name); +} + +static int tl_calc_and_print_sl_counters(struct adf_accel_dev *accel_dev, + struct seq_file *s, u8 cnt_type, u8 cnt_id) +{ + struct adf_tl_hw_data *tl_data = &GET_TL_DATA(accel_dev); + struct adf_telemetry *telemetry = accel_dev->telemetry; + const struct adf_tl_dbg_counter *sl_tl_util_counters; + const struct adf_tl_dbg_counter *sl_tl_exec_counters; + const struct adf_tl_dbg_counter *ctr; + int ret; + + sl_tl_util_counters = tl_data->sl_util_counters; + sl_tl_exec_counters = tl_data->sl_exec_counters; + + ctr = &sl_tl_util_counters[cnt_type]; + + ret = tl_print_sl_counter(telemetry, ctr, s, cnt_id); + if (ret) { + dev_notice(&GET_DEV(accel_dev), + "invalid slice utilization counter type\n"); + return ret; + } + + ctr = &sl_tl_exec_counters[cnt_type]; + + ret = tl_print_sl_counter(telemetry, ctr, s, cnt_id); + if (ret) { + dev_notice(&GET_DEV(accel_dev), + "invalid slice execution counter type\n"); + return ret; + } + + return 0; +} + +static void tl_print_msg_cnt(struct seq_file *s, u32 msg_cnt) +{ + seq_printf(s, "%-*s", TL_KEY_MIN_PADDING, SNAPSHOT_CNT_MSG); + seq_printf(s, "%*u\n", TL_VALUE_MIN_PADDING, msg_cnt); +} + +static int tl_print_dev_data(struct adf_accel_dev *accel_dev, + struct seq_file *s) +{ + struct adf_tl_hw_data *tl_data = &GET_TL_DATA(accel_dev); + struct adf_telemetry *telemetry = accel_dev->telemetry; + const struct adf_tl_dbg_counter *dev_tl_counters; + u8 num_dev_counters = tl_data->num_dev_counters; + u8 *sl_cnt = (u8 *)&telemetry->slice_cnt; + const struct adf_tl_dbg_counter *ctr; + unsigned int i; + int ret; + u8 j; + + if (!atomic_read(&telemetry->state)) { + dev_info(&GET_DEV(accel_dev), "not enabled\n"); + return -EPERM; + } + + dev_tl_counters = tl_data->dev_counters; + + tl_print_msg_cnt(s, telemetry->msg_cnt); + + /* Print device level telemetry. */ + for (i = 0; i < num_dev_counters; i++) { + ctr = &dev_tl_counters[i]; + ret = tl_calc_and_print_counter(telemetry, s, ctr, NULL); + if (ret) { + dev_notice(&GET_DEV(accel_dev), + "invalid counter type\n"); + return ret; + } + } + + /* Print per slice telemetry. */ + for (i = 0; i < ADF_TL_SL_CNT_COUNT; i++) { + for (j = 0; j < sl_cnt[i]; j++) { + ret = tl_calc_and_print_sl_counters(accel_dev, s, i, j); + if (ret) + return ret; + } + } + + return 0; +} + +static int tl_dev_data_show(struct seq_file *s, void *unused) +{ + struct adf_accel_dev *accel_dev = s->private; + + if (!accel_dev) + return -EINVAL; + + return tl_print_dev_data(accel_dev, s); +} +DEFINE_SHOW_ATTRIBUTE(tl_dev_data); + +static int tl_control_show(struct seq_file *s, void *unused) +{ + struct adf_accel_dev *accel_dev = s->private; + + if (!accel_dev) + return -EINVAL; + + seq_printf(s, "%d\n", atomic_read(&accel_dev->telemetry->state)); + + return 0; +} + +static ssize_t tl_control_write(struct file *file, const char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct seq_file *seq_f = file->private_data; + struct adf_accel_dev *accel_dev; + struct adf_telemetry *telemetry; + struct adf_tl_hw_data *tl_data; + struct device *dev; + u32 input; + int ret; + + accel_dev = seq_f->private; + if (!accel_dev) + return -EINVAL; + + tl_data = &GET_TL_DATA(accel_dev); + telemetry = accel_dev->telemetry; + dev = &GET_DEV(accel_dev); + + mutex_lock(&telemetry->wr_lock); + + ret = kstrtou32_from_user(userbuf, count, 10, &input); + if (ret) + goto unlock_and_exit; + + if (input > tl_data->num_hbuff) { + dev_info(dev, "invalid control input\n"); + ret = -EINVAL; + goto unlock_and_exit; + } + + /* If input is 0, just stop telemetry. */ + if (!input) { + ret = adf_tl_halt(accel_dev); + if (!ret) + ret = count; + + goto unlock_and_exit; + } + + /* If TL is already enabled, stop it. */ + if (atomic_read(&telemetry->state)) { + dev_info(dev, "already enabled, restarting.\n"); + ret = adf_tl_halt(accel_dev); + if (ret) + goto unlock_and_exit; + } + + ret = adf_tl_run(accel_dev, input); + if (ret) + goto unlock_and_exit; + + ret = count; + +unlock_and_exit: + mutex_unlock(&telemetry->wr_lock); + return ret; +} +DEFINE_SHOW_STORE_ATTRIBUTE(tl_control); + +static int get_rp_index_from_file(const struct file *f, u8 *rp_id, u8 rp_num) +{ + char alpha; + u8 index; + int ret; + + ret = sscanf(f->f_path.dentry->d_name.name, ADF_TL_RP_REGS_FNAME, &alpha); + if (ret != 1) + return -EINVAL; + + index = ADF_TL_DBG_RP_INDEX_ALPHA(alpha); + *rp_id = index; + + return 0; +} + +static int adf_tl_dbg_change_rp_index(struct adf_accel_dev *accel_dev, + unsigned int new_rp_num, + unsigned int rp_regs_index) +{ + struct adf_hw_device_data *hw_data = GET_HW_DATA(accel_dev); + struct adf_telemetry *telemetry = accel_dev->telemetry; + struct device *dev = &GET_DEV(accel_dev); + unsigned int i; + u8 curr_state; + int ret; + + if (new_rp_num >= hw_data->num_rps) { + dev_info(dev, "invalid Ring Pair number selected\n"); + return -EINVAL; + } + + for (i = 0; i < hw_data->tl_data.max_rp; i++) { + if (telemetry->rp_num_indexes[i] == new_rp_num) { + dev_info(dev, "RP nr: %d is already selected in slot rp_%c_data\n", + new_rp_num, ADF_TL_DBG_RP_ALPHA_INDEX(i)); + return 0; + } + } + + dev_dbg(dev, "selecting RP nr %u into slot rp_%c_data\n", + new_rp_num, ADF_TL_DBG_RP_ALPHA_INDEX(rp_regs_index)); + + curr_state = atomic_read(&telemetry->state); + + if (curr_state) { + ret = adf_tl_halt(accel_dev); + if (ret) + return ret; + + telemetry->rp_num_indexes[rp_regs_index] = new_rp_num; + + ret = adf_tl_run(accel_dev, curr_state); + if (ret) + return ret; + } else { + telemetry->rp_num_indexes[rp_regs_index] = new_rp_num; + } + + return 0; +} + +static void tl_print_rp_srv(struct adf_accel_dev *accel_dev, struct seq_file *s, + u8 rp_idx) +{ + u32 banks_per_vf = GET_HW_DATA(accel_dev)->num_banks_per_vf; + enum adf_cfg_service_type svc; + + seq_printf(s, "%-*s", TL_KEY_MIN_PADDING, RP_SERVICE_TYPE); + + svc = GET_SRV_TYPE(accel_dev, rp_idx % banks_per_vf); + switch (svc) { + case COMP: + seq_printf(s, "%*s\n", TL_VALUE_MIN_PADDING, ADF_CFG_DC); + break; + case SYM: + seq_printf(s, "%*s\n", TL_VALUE_MIN_PADDING, ADF_CFG_SYM); + break; + case ASYM: + seq_printf(s, "%*s\n", TL_VALUE_MIN_PADDING, ADF_CFG_ASYM); + break; + default: + seq_printf(s, "%*s\n", TL_VALUE_MIN_PADDING, TL_RP_SRV_UNKNOWN); + break; + } +} + +static int tl_print_rp_data(struct adf_accel_dev *accel_dev, struct seq_file *s, + u8 rp_regs_index) +{ + struct adf_tl_hw_data *tl_data = &GET_TL_DATA(accel_dev); + struct adf_telemetry *telemetry = accel_dev->telemetry; + const struct adf_tl_dbg_counter *rp_tl_counters; + u8 num_rp_counters = tl_data->num_rp_counters; + size_t rp_regs_sz = tl_data->rp_reg_sz; + struct adf_tl_dbg_counter ctr; + unsigned int i; + u8 rp_idx; + int ret; + + if (!atomic_read(&telemetry->state)) { + dev_info(&GET_DEV(accel_dev), "not enabled\n"); + return -EPERM; + } + + rp_tl_counters = tl_data->rp_counters; + rp_idx = telemetry->rp_num_indexes[rp_regs_index]; + + if (rp_idx == ADF_TL_RP_REGS_DISABLED) { + dev_info(&GET_DEV(accel_dev), "no RP number selected in rp_%c_data\n", + ADF_TL_DBG_RP_ALPHA_INDEX(rp_regs_index)); + return -EPERM; + } + + tl_print_msg_cnt(s, telemetry->msg_cnt); + seq_printf(s, "%-*s", TL_KEY_MIN_PADDING, RP_NUM_INDEX); + seq_printf(s, "%*d\n", TL_VALUE_MIN_PADDING, rp_idx); + tl_print_rp_srv(accel_dev, s, rp_idx); + + for (i = 0; i < num_rp_counters; i++) { + ctr = rp_tl_counters[i]; + ctr.offset1 += rp_regs_sz * rp_regs_index; + ctr.offset2 += rp_regs_sz * rp_regs_index; + ret = tl_calc_and_print_counter(telemetry, s, &ctr, NULL); + if (ret) { + dev_dbg(&GET_DEV(accel_dev), + "invalid RP counter type\n"); + return ret; + } + } + + return 0; +} + +static int tl_rp_data_show(struct seq_file *s, void *unused) +{ + struct adf_accel_dev *accel_dev = s->private; + u8 rp_regs_index; + u8 max_rp; + int ret; + + if (!accel_dev) + return -EINVAL; + + max_rp = GET_TL_DATA(accel_dev).max_rp; + ret = get_rp_index_from_file(s->file, &rp_regs_index, max_rp); + if (ret) { + dev_dbg(&GET_DEV(accel_dev), "invalid RP data file name\n"); + return ret; + } + + return tl_print_rp_data(accel_dev, s, rp_regs_index); +} + +static ssize_t tl_rp_data_write(struct file *file, const char __user *userbuf, + size_t count, loff_t *ppos) +{ + struct seq_file *seq_f = file->private_data; + struct adf_accel_dev *accel_dev; + struct adf_telemetry *telemetry; + unsigned int new_rp_num; + u8 rp_regs_index; + u8 max_rp; + int ret; + + accel_dev = seq_f->private; + if (!accel_dev) + return -EINVAL; + + telemetry = accel_dev->telemetry; + max_rp = GET_TL_DATA(accel_dev).max_rp; + + mutex_lock(&telemetry->wr_lock); + + ret = get_rp_index_from_file(file, &rp_regs_index, max_rp); + if (ret) { + dev_dbg(&GET_DEV(accel_dev), "invalid RP data file name\n"); + goto unlock_and_exit; + } + + ret = kstrtou32_from_user(userbuf, count, 10, &new_rp_num); + if (ret) + goto unlock_and_exit; + + ret = adf_tl_dbg_change_rp_index(accel_dev, new_rp_num, rp_regs_index); + if (ret) + goto unlock_and_exit; + + ret = count; + +unlock_and_exit: + mutex_unlock(&telemetry->wr_lock); + return ret; +} +DEFINE_SHOW_STORE_ATTRIBUTE(tl_rp_data); + +void adf_tl_dbgfs_add(struct adf_accel_dev *accel_dev) +{ + struct adf_telemetry *telemetry = accel_dev->telemetry; + struct dentry *parent = accel_dev->debugfs_dir; + u8 max_rp = GET_TL_DATA(accel_dev).max_rp; + char name[ADF_TL_RP_REGS_FNAME_SIZE]; + struct dentry *dir; + unsigned int i; + + if (!telemetry) + return; + + dir = debugfs_create_dir("telemetry", parent); + accel_dev->telemetry->dbg_dir = dir; + debugfs_create_file("device_data", 0444, dir, accel_dev, &tl_dev_data_fops); + debugfs_create_file("control", 0644, dir, accel_dev, &tl_control_fops); + + for (i = 0; i < max_rp; i++) { + snprintf(name, sizeof(name), ADF_TL_RP_REGS_FNAME, + ADF_TL_DBG_RP_ALPHA_INDEX(i)); + debugfs_create_file(name, 0644, dir, accel_dev, &tl_rp_data_fops); + } +} + +void adf_tl_dbgfs_rm(struct adf_accel_dev *accel_dev) +{ + struct adf_telemetry *telemetry = accel_dev->telemetry; + struct dentry *dbg_dir; + + if (!telemetry) + return; + + dbg_dir = telemetry->dbg_dir; + + debugfs_remove_recursive(dbg_dir); + + if (atomic_read(&telemetry->state)) + adf_tl_halt(accel_dev); +} diff --git a/drivers/crypto/intel/qat/qat_common/adf_tl_debugfs.h b/drivers/crypto/intel/qat/qat_common/adf_tl_debugfs.h new file mode 100644 index 00000000000000..11cc9eae19b37a --- /dev/null +++ b/drivers/crypto/intel/qat/qat_common/adf_tl_debugfs.h @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2023 Intel Corporation. */ +#ifndef ADF_TL_DEBUGFS_H +#define ADF_TL_DEBUGFS_H + +#include + +struct adf_accel_dev; + +#define MAX_COUNT_NAME_SIZE 32 +#define SNAPSHOT_CNT_MSG "sample_cnt" +#define RP_NUM_INDEX "rp_num" +#define PCI_TRANS_CNT_NAME "pci_trans_cnt" +#define MAX_RD_LAT_NAME "max_rd_lat" +#define RD_LAT_ACC_NAME "rd_lat_acc_avg" +#define MAX_LAT_NAME "max_gp_lat" +#define LAT_ACC_NAME "gp_lat_acc_avg" +#define BW_IN_NAME "bw_in" +#define BW_OUT_NAME "bw_out" +#define PAGE_REQ_LAT_NAME "at_page_req_lat_avg" +#define AT_TRANS_LAT_NAME "at_trans_lat_avg" +#define AT_MAX_UTLB_USED_NAME "at_max_tlb_used" +#define AT_GLOB_DTLB_HIT_NAME "at_glob_devtlb_hit" +#define AT_GLOB_DTLB_MISS_NAME "at_glob_devtlb_miss" +#define AT_PAYLD_DTLB_HIT_NAME "tl_at_payld_devtlb_hit" +#define AT_PAYLD_DTLB_MISS_NAME "tl_at_payld_devtlb_miss" +#define RP_SERVICE_TYPE "service_type" + +#define ADF_TL_DBG_RP_ALPHA_INDEX(index) ((index) + 'A') +#define ADF_TL_DBG_RP_INDEX_ALPHA(alpha) ((alpha) - 'A') + +#define ADF_TL_RP_REGS_FNAME "rp_%c_data" +#define ADF_TL_RP_REGS_FNAME_SIZE 16 + +#define ADF_TL_DATA_REG_OFF(reg, qat_gen) \ + offsetof(struct adf_##qat_gen##_tl_layout, reg) + +#define ADF_TL_DEV_REG_OFF(reg, qat_gen) \ + (ADF_TL_DATA_REG_OFF(tl_device_data_regs, qat_gen) + \ + offsetof(struct adf_##qat_gen##_tl_device_data_regs, reg)) + +#define ADF_TL_SLICE_REG_OFF(slice, reg, qat_gen) \ + (ADF_TL_DEV_REG_OFF(slice##_slices[0], qat_gen) + \ + offsetof(struct adf_##qat_gen##_tl_slice_data_regs, reg)) + +#define ADF_TL_RP_REG_OFF(reg, qat_gen) \ + (ADF_TL_DATA_REG_OFF(tl_ring_pairs_data_regs[0], qat_gen) + \ + offsetof(struct adf_##qat_gen##_tl_ring_pair_data_regs, reg)) + +/** + * enum adf_tl_counter_type - telemetry counter types + * @ADF_TL_COUNTER_UNSUPPORTED: unsupported counter + * @ADF_TL_SIMPLE_COUNT: simple counter + * @ADF_TL_COUNTER_NS: latency counter, value in ns + * @ADF_TL_COUNTER_NS_AVG: accumulated average latency counter, value in ns + * @ADF_TL_COUNTER_MBPS: bandwidth, value in MBps + */ +enum adf_tl_counter_type { + ADF_TL_COUNTER_UNSUPPORTED, + ADF_TL_SIMPLE_COUNT, + ADF_TL_COUNTER_NS, + ADF_TL_COUNTER_NS_AVG, + ADF_TL_COUNTER_MBPS, +}; + +/** + * struct adf_tl_dbg_counter - telemetry counter definition + * @name: name of the counter as printed in the report + * @adf_tl_counter_type: type of the counter + * @offset1: offset of 1st register + * @offset2: offset of 2nd optional register + */ +struct adf_tl_dbg_counter { + const char *name; + enum adf_tl_counter_type type; + size_t offset1; + size_t offset2; +}; + +#define ADF_TL_COUNTER(_name, _type, _offset) \ +{ .name = _name, \ + .type = _type, \ + .offset1 = _offset \ +} + +#define ADF_TL_COUNTER_LATENCY(_name, _type, _offset1, _offset2) \ +{ .name = _name, \ + .type = _type, \ + .offset1 = _offset1, \ + .offset2 = _offset2 \ +} + +/* Telemetry counter aggregated values. */ +struct adf_tl_dbg_aggr_values { + u64 curr; + u64 min; + u64 max; + u64 avg; +}; + +/** + * adf_tl_dbgfs_add() - Add telemetry's debug fs entries. + * @accel_dev: Pointer to acceleration device. + * + * Creates telemetry's debug fs folder and attributes in QAT debug fs root. + */ +void adf_tl_dbgfs_add(struct adf_accel_dev *accel_dev); + +/** + * adf_tl_dbgfs_rm() - Remove telemetry's debug fs entries. + * @accel_dev: Pointer to acceleration device. + * + * Removes telemetry's debug fs folder and attributes from QAT debug fs root. + */ +void adf_tl_dbgfs_rm(struct adf_accel_dev *accel_dev); + +#endif /* ADF_TL_DEBUGFS_H */ diff --git a/drivers/crypto/intel/qat/qat_common/icp_qat_fw_init_admin.h b/drivers/crypto/intel/qat/qat_common/icp_qat_fw_init_admin.h index cd418b51d9f351..63cf18e2a4e57d 100644 --- a/drivers/crypto/intel/qat/qat_common/icp_qat_fw_init_admin.h +++ b/drivers/crypto/intel/qat/qat_common/icp_qat_fw_init_admin.h @@ -29,6 +29,8 @@ enum icp_qat_fw_init_admin_cmd_id { ICP_QAT_FW_RL_ADD = 134, ICP_QAT_FW_RL_UPDATE = 135, ICP_QAT_FW_RL_REMOVE = 136, + ICP_QAT_FW_TL_START = 137, + ICP_QAT_FW_TL_STOP = 138, }; enum icp_qat_fw_init_admin_resp_status { @@ -36,6 +38,13 @@ enum icp_qat_fw_init_admin_resp_status { ICP_QAT_FW_INIT_RESP_STATUS_FAIL }; +struct icp_qat_fw_init_admin_tl_rp_indexes { + __u8 rp_num_index_0; + __u8 rp_num_index_1; + __u8 rp_num_index_2; + __u8 rp_num_index_3; +}; + struct icp_qat_fw_init_admin_slice_cnt { __u8 cpr_cnt; __u8 xlt_cnt; @@ -87,6 +96,7 @@ struct icp_qat_fw_init_admin_req { __u8 rp_count; }; __u32 idle_filter; + struct icp_qat_fw_init_admin_tl_rp_indexes rp_indexes; }; __u32 resrvd4; diff --git a/drivers/crypto/intel/qat/qat_common/icp_qat_hw.h b/drivers/crypto/intel/qat/qat_common/icp_qat_hw.h index eb2ef225bcee16..b8f1c4ffb8b5a7 100644 --- a/drivers/crypto/intel/qat/qat_common/icp_qat_hw.h +++ b/drivers/crypto/intel/qat/qat_common/icp_qat_hw.h @@ -18,7 +18,12 @@ enum icp_qat_hw_ae_id { ICP_QAT_HW_AE_9 = 9, ICP_QAT_HW_AE_10 = 10, ICP_QAT_HW_AE_11 = 11, - ICP_QAT_HW_AE_DELIMITER = 12 + ICP_QAT_HW_AE_12 = 12, + ICP_QAT_HW_AE_13 = 13, + ICP_QAT_HW_AE_14 = 14, + ICP_QAT_HW_AE_15 = 15, + ICP_QAT_HW_AE_16 = 16, + ICP_QAT_HW_AE_DELIMITER = 17 }; enum icp_qat_hw_qat_id { @@ -95,7 +100,7 @@ enum icp_qat_capabilities_mask { /* Bits 10-11 are currently reserved */ ICP_ACCEL_CAPABILITIES_HKDF = BIT(12), ICP_ACCEL_CAPABILITIES_ECEDMONT = BIT(13), - /* Bit 14 is currently reserved */ + ICP_ACCEL_CAPABILITIES_EXT_ALGCHAIN = BIT(14), ICP_ACCEL_CAPABILITIES_SHA3_EXT = BIT(15), ICP_ACCEL_CAPABILITIES_AESGCM_SPC = BIT(16), ICP_ACCEL_CAPABILITIES_CHACHA_POLY = BIT(17), @@ -107,7 +112,10 @@ enum icp_qat_capabilities_mask { ICP_ACCEL_CAPABILITIES_CNV_INTEGRITY64 = BIT(23), ICP_ACCEL_CAPABILITIES_LZ4_COMPRESSION = BIT(24), ICP_ACCEL_CAPABILITIES_LZ4S_COMPRESSION = BIT(25), - ICP_ACCEL_CAPABILITIES_AES_V2 = BIT(26) + ICP_ACCEL_CAPABILITIES_AES_V2 = BIT(26), + /* Bits 27-28 are currently reserved */ + ICP_ACCEL_CAPABILITIES_ZUC_256 = BIT(29), + ICP_ACCEL_CAPABILITIES_WIRELESS_CRYPTO_EXT = BIT(30), }; #define QAT_AUTH_MODE_BITPOS 4 diff --git a/drivers/crypto/intel/qat/qat_common/icp_qat_uclo.h b/drivers/crypto/intel/qat/qat_common/icp_qat_uclo.h index 69482abdb8b936..e28241bdd0f4ef 100644 --- a/drivers/crypto/intel/qat/qat_common/icp_qat_uclo.h +++ b/drivers/crypto/intel/qat/qat_common/icp_qat_uclo.h @@ -7,7 +7,7 @@ #define ICP_QAT_AC_C62X_DEV_TYPE 0x01000000 #define ICP_QAT_AC_C3XXX_DEV_TYPE 0x02000000 #define ICP_QAT_AC_4XXX_A_DEV_TYPE 0x08000000 -#define ICP_QAT_UCLO_MAX_AE 12 +#define ICP_QAT_UCLO_MAX_AE 17 #define ICP_QAT_UCLO_MAX_CTX 8 #define ICP_QAT_UCLO_MAX_UIMAGE (ICP_QAT_UCLO_MAX_AE * ICP_QAT_UCLO_MAX_CTX) #define ICP_QAT_UCLO_MAX_USTORE 0x4000 diff --git a/drivers/crypto/intel/qat/qat_common/qat_hal.c b/drivers/crypto/intel/qat/qat_common/qat_hal.c index cbb946a800761d..317cafa9d11f9e 100644 --- a/drivers/crypto/intel/qat/qat_common/qat_hal.c +++ b/drivers/crypto/intel/qat/qat_common/qat_hal.c @@ -697,12 +697,16 @@ static int qat_hal_chip_init(struct icp_qat_fw_loader_handle *handle, case ADF_4XXX_PCI_DEVICE_ID: case ADF_401XX_PCI_DEVICE_ID: case ADF_402XX_PCI_DEVICE_ID: + case ADF_420XX_PCI_DEVICE_ID: handle->chip_info->mmp_sram_size = 0; handle->chip_info->nn = false; handle->chip_info->lm2lm3 = true; handle->chip_info->lm_size = ICP_QAT_UCLO_MAX_LMEM_REG_2X; handle->chip_info->icp_rst_csr = ICP_RESET_CPP0; - handle->chip_info->icp_rst_mask = 0x100015; + if (handle->pci_dev->device == ADF_420XX_PCI_DEVICE_ID) + handle->chip_info->icp_rst_mask = 0x100155; + else + handle->chip_info->icp_rst_mask = 0x100015; handle->chip_info->glb_clk_enable_csr = ICP_GLOBAL_CLK_ENABLE_CPP0; handle->chip_info->misc_ctl_csr = MISC_CONTROL_C4XXX; handle->chip_info->wakeup_event_val = 0x80000000; diff --git a/drivers/crypto/intel/qat/qat_common/qat_uclo.c b/drivers/crypto/intel/qat/qat_common/qat_uclo.c index e27ea7e28c51b0..ad2c64af7427ee 100644 --- a/drivers/crypto/intel/qat/qat_common/qat_uclo.c +++ b/drivers/crypto/intel/qat/qat_common/qat_uclo.c @@ -733,6 +733,7 @@ qat_uclo_get_dev_type(struct icp_qat_fw_loader_handle *handle) case ADF_4XXX_PCI_DEVICE_ID: case ADF_401XX_PCI_DEVICE_ID: case ADF_402XX_PCI_DEVICE_ID: + case ADF_420XX_PCI_DEVICE_ID: return ICP_QAT_AC_4XXX_A_DEV_TYPE; default: pr_err("QAT: unsupported device 0x%x\n", diff --git a/drivers/crypto/marvell/cesa/cesa.c b/drivers/crypto/marvell/cesa/cesa.c index 5744df30c83830..5fd31ba715c22a 100644 --- a/drivers/crypto/marvell/cesa/cesa.c +++ b/drivers/crypto/marvell/cesa/cesa.c @@ -488,7 +488,7 @@ static int mv_cesa_probe(struct platform_device *pdev) for (i = 0; i < caps->nengines; i++) { struct mv_cesa_engine *engine = &cesa->engines[i]; - char res_name[7]; + char res_name[16]; engine->id = i; spin_lock_init(&engine->lock); @@ -509,7 +509,7 @@ static int mv_cesa_probe(struct platform_device *pdev) * Not all platforms can gate the CESA clocks: do not complain * if the clock does not exist. */ - snprintf(res_name, sizeof(res_name), "cesa%d", i); + snprintf(res_name, sizeof(res_name), "cesa%u", i); engine->clk = devm_clk_get(dev, res_name); if (IS_ERR(engine->clk)) { engine->clk = devm_clk_get(dev, NULL); @@ -517,7 +517,7 @@ static int mv_cesa_probe(struct platform_device *pdev) engine->clk = NULL; } - snprintf(res_name, sizeof(res_name), "cesaz%d", i); + snprintf(res_name, sizeof(res_name), "cesaz%u", i); engine->zclk = devm_clk_get(dev, res_name); if (IS_ERR(engine->zclk)) engine->zclk = NULL; diff --git a/drivers/crypto/marvell/octeontx/otx_cptvf_algs.c b/drivers/crypto/marvell/octeontx/otx_cptvf_algs.c index 1c2c870e887aab..3c5d577d8f0d5e 100644 --- a/drivers/crypto/marvell/octeontx/otx_cptvf_algs.c +++ b/drivers/crypto/marvell/octeontx/otx_cptvf_algs.c @@ -473,12 +473,6 @@ static int otx_cpt_skcipher_ecb_aes_setkey(struct crypto_skcipher *tfm, return cpt_aes_setkey(tfm, key, keylen, OTX_CPT_AES_ECB); } -static int otx_cpt_skcipher_cfb_aes_setkey(struct crypto_skcipher *tfm, - const u8 *key, u32 keylen) -{ - return cpt_aes_setkey(tfm, key, keylen, OTX_CPT_AES_CFB); -} - static int otx_cpt_skcipher_cbc_des3_setkey(struct crypto_skcipher *tfm, const u8 *key, u32 keylen) { @@ -1351,23 +1345,6 @@ static struct skcipher_alg otx_cpt_skciphers[] = { { .setkey = otx_cpt_skcipher_ecb_aes_setkey, .encrypt = otx_cpt_skcipher_encrypt, .decrypt = otx_cpt_skcipher_decrypt, -}, { - .base.cra_name = "cfb(aes)", - .base.cra_driver_name = "cpt_cfb_aes", - .base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_ALLOCATES_MEMORY, - .base.cra_blocksize = AES_BLOCK_SIZE, - .base.cra_ctxsize = sizeof(struct otx_cpt_enc_ctx), - .base.cra_alignmask = 7, - .base.cra_priority = 4001, - .base.cra_module = THIS_MODULE, - - .init = otx_cpt_enc_dec_init, - .ivsize = AES_BLOCK_SIZE, - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .setkey = otx_cpt_skcipher_cfb_aes_setkey, - .encrypt = otx_cpt_skcipher_encrypt, - .decrypt = otx_cpt_skcipher_decrypt, }, { .base.cra_name = "cbc(des3_ede)", .base.cra_driver_name = "cpt_cbc_des3_ede", diff --git a/drivers/crypto/marvell/octeontx2/cn10k_cpt.c b/drivers/crypto/marvell/octeontx2/cn10k_cpt.c index 93d22b32899195..79b4e74804f6d0 100644 --- a/drivers/crypto/marvell/octeontx2/cn10k_cpt.c +++ b/drivers/crypto/marvell/octeontx2/cn10k_cpt.c @@ -14,12 +14,14 @@ static struct cpt_hw_ops otx2_hw_ops = { .send_cmd = otx2_cpt_send_cmd, .cpt_get_compcode = otx2_cpt_get_compcode, .cpt_get_uc_compcode = otx2_cpt_get_uc_compcode, + .cpt_sg_info_create = otx2_sg_info_create, }; static struct cpt_hw_ops cn10k_hw_ops = { .send_cmd = cn10k_cpt_send_cmd, .cpt_get_compcode = cn10k_cpt_get_compcode, .cpt_get_uc_compcode = cn10k_cpt_get_uc_compcode, + .cpt_sg_info_create = otx2_sg_info_create, }; static void cn10k_cpt_send_cmd(union otx2_cpt_inst_s *cptinst, u32 insts_num, @@ -78,12 +80,9 @@ int cn10k_cptvf_lmtst_init(struct otx2_cptvf_dev *cptvf) struct pci_dev *pdev = cptvf->pdev; resource_size_t offset, size; - if (!test_bit(CN10K_LMTST, &cptvf->cap_flag)) { - cptvf->lfs.ops = &otx2_hw_ops; + if (!test_bit(CN10K_LMTST, &cptvf->cap_flag)) return 0; - } - cptvf->lfs.ops = &cn10k_hw_ops; offset = pci_resource_start(pdev, PCI_MBOX_BAR_NUM); size = pci_resource_len(pdev, PCI_MBOX_BAR_NUM); /* Map VF LMILINE region */ @@ -96,3 +95,82 @@ int cn10k_cptvf_lmtst_init(struct otx2_cptvf_dev *cptvf) return 0; } EXPORT_SYMBOL_NS_GPL(cn10k_cptvf_lmtst_init, CRYPTO_DEV_OCTEONTX2_CPT); + +void cn10k_cpt_hw_ctx_clear(struct pci_dev *pdev, + struct cn10k_cpt_errata_ctx *er_ctx) +{ + u64 cptr_dma; + + if (!is_dev_cn10ka_ax(pdev)) + return; + + cptr_dma = er_ctx->cptr_dma & ~(BIT_ULL(60)); + cn10k_cpt_ctx_flush(pdev, cptr_dma, true); + dma_unmap_single(&pdev->dev, cptr_dma, CN10K_CPT_HW_CTX_SIZE, + DMA_BIDIRECTIONAL); + kfree(er_ctx->hw_ctx); +} +EXPORT_SYMBOL_NS_GPL(cn10k_cpt_hw_ctx_clear, CRYPTO_DEV_OCTEONTX2_CPT); + +void cn10k_cpt_hw_ctx_set(union cn10k_cpt_hw_ctx *hctx, u16 ctx_sz) +{ + hctx->w0.aop_valid = 1; + hctx->w0.ctx_hdr_sz = 0; + hctx->w0.ctx_sz = ctx_sz; + hctx->w0.ctx_push_sz = 1; +} +EXPORT_SYMBOL_NS_GPL(cn10k_cpt_hw_ctx_set, CRYPTO_DEV_OCTEONTX2_CPT); + +int cn10k_cpt_hw_ctx_init(struct pci_dev *pdev, + struct cn10k_cpt_errata_ctx *er_ctx) +{ + union cn10k_cpt_hw_ctx *hctx; + u64 cptr_dma; + + er_ctx->cptr_dma = 0; + er_ctx->hw_ctx = NULL; + + if (!is_dev_cn10ka_ax(pdev)) + return 0; + + hctx = kmalloc(CN10K_CPT_HW_CTX_SIZE, GFP_KERNEL); + if (unlikely(!hctx)) + return -ENOMEM; + cptr_dma = dma_map_single(&pdev->dev, hctx, CN10K_CPT_HW_CTX_SIZE, + DMA_BIDIRECTIONAL); + + cn10k_cpt_hw_ctx_set(hctx, 1); + er_ctx->hw_ctx = hctx; + er_ctx->cptr_dma = cptr_dma | BIT_ULL(60); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(cn10k_cpt_hw_ctx_init, CRYPTO_DEV_OCTEONTX2_CPT); + +void cn10k_cpt_ctx_flush(struct pci_dev *pdev, u64 cptr, bool inval) +{ + struct otx2_cptvf_dev *cptvf = pci_get_drvdata(pdev); + struct otx2_cptlfs_info *lfs = &cptvf->lfs; + u64 reg; + + reg = (uintptr_t)cptr >> 7; + if (inval) + reg = reg | BIT_ULL(46); + + otx2_cpt_write64(lfs->reg_base, lfs->blkaddr, lfs->lf[0].slot, + OTX2_CPT_LF_CTX_FLUSH, reg); + /* Make sure that the FLUSH operation is complete */ + wmb(); + otx2_cpt_read64(lfs->reg_base, lfs->blkaddr, lfs->lf[0].slot, + OTX2_CPT_LF_CTX_ERR); +} +EXPORT_SYMBOL_NS_GPL(cn10k_cpt_ctx_flush, CRYPTO_DEV_OCTEONTX2_CPT); + +void cptvf_hw_ops_get(struct otx2_cptvf_dev *cptvf) +{ + if (test_bit(CN10K_LMTST, &cptvf->cap_flag)) + cptvf->lfs.ops = &cn10k_hw_ops; + else + cptvf->lfs.ops = &otx2_hw_ops; +} +EXPORT_SYMBOL_NS_GPL(cptvf_hw_ops_get, CRYPTO_DEV_OCTEONTX2_CPT); diff --git a/drivers/crypto/marvell/octeontx2/cn10k_cpt.h b/drivers/crypto/marvell/octeontx2/cn10k_cpt.h index aaefc7e38e060b..92be3ecf570fc3 100644 --- a/drivers/crypto/marvell/octeontx2/cn10k_cpt.h +++ b/drivers/crypto/marvell/octeontx2/cn10k_cpt.h @@ -8,6 +8,26 @@ #include "otx2_cptpf.h" #include "otx2_cptvf.h" +#define CN10K_CPT_HW_CTX_SIZE 256 + +union cn10k_cpt_hw_ctx { + u64 u; + struct { + u64 reserved_0_47:48; + u64 ctx_push_sz:7; + u64 reserved_55:1; + u64 ctx_hdr_sz:2; + u64 aop_valid:1; + u64 reserved_59:1; + u64 ctx_sz:4; + } w0; +}; + +struct cn10k_cpt_errata_ctx { + union cn10k_cpt_hw_ctx *hw_ctx; + u64 cptr_dma; +}; + static inline u8 cn10k_cpt_get_compcode(union otx2_cpt_res_s *result) { return ((struct cn10k_cpt_res_s *)result)->compcode; @@ -30,5 +50,12 @@ static inline u8 otx2_cpt_get_uc_compcode(union otx2_cpt_res_s *result) int cn10k_cptpf_lmtst_init(struct otx2_cptpf_dev *cptpf); int cn10k_cptvf_lmtst_init(struct otx2_cptvf_dev *cptvf); +void cn10k_cpt_ctx_flush(struct pci_dev *pdev, u64 cptr, bool inval); +int cn10k_cpt_hw_ctx_init(struct pci_dev *pdev, + struct cn10k_cpt_errata_ctx *er_ctx); +void cn10k_cpt_hw_ctx_clear(struct pci_dev *pdev, + struct cn10k_cpt_errata_ctx *er_ctx); +void cn10k_cpt_hw_ctx_set(union cn10k_cpt_hw_ctx *hctx, u16 ctx_sz); +void cptvf_hw_ops_get(struct otx2_cptvf_dev *cptvf); #endif /* __CN10K_CPTLF_H */ diff --git a/drivers/crypto/marvell/octeontx2/otx2_cpt_common.h b/drivers/crypto/marvell/octeontx2/otx2_cpt_common.h index 46b778bbbee44c..c5b7c57574ef30 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cpt_common.h +++ b/drivers/crypto/marvell/octeontx2/otx2_cpt_common.h @@ -56,7 +56,11 @@ struct otx2_cpt_rx_inline_lf_cfg { u16 param2; u16 opcode; u32 credit; + u32 credit_th; + u16 bpid; u32 reserved; + u8 ctx_ilen_valid : 1; + u8 ctx_ilen : 7; }; /* @@ -102,7 +106,10 @@ union otx2_cpt_eng_caps { u64 kasumi:1; u64 des:1; u64 crc:1; - u64 reserved_14_63:50; + u64 mmul:1; + u64 reserved_15_33:19; + u64 pdcp_chain:1; + u64 reserved_35_63:29; }; }; @@ -145,6 +152,35 @@ static inline bool is_dev_otx2(struct pci_dev *pdev) return false; } +static inline bool is_dev_cn10ka(struct pci_dev *pdev) +{ + return pdev->subsystem_device == CPT_PCI_SUBSYS_DEVID_CN10K_A; +} + +static inline bool is_dev_cn10ka_ax(struct pci_dev *pdev) +{ + if (pdev->subsystem_device == CPT_PCI_SUBSYS_DEVID_CN10K_A && + ((pdev->revision & 0xFF) == 4 || (pdev->revision & 0xFF) == 0x50 || + (pdev->revision & 0xff) == 0x51)) + return true; + + return false; +} + +static inline bool is_dev_cn10kb(struct pci_dev *pdev) +{ + return pdev->subsystem_device == CPT_PCI_SUBSYS_DEVID_CN10K_B; +} + +static inline bool is_dev_cn10ka_b0(struct pci_dev *pdev) +{ + if (pdev->subsystem_device == CPT_PCI_SUBSYS_DEVID_CN10K_A && + (pdev->revision & 0xFF) == 0x54) + return true; + + return false; +} + static inline void otx2_cpt_set_hw_caps(struct pci_dev *pdev, unsigned long *cap_flag) { @@ -154,6 +190,21 @@ static inline void otx2_cpt_set_hw_caps(struct pci_dev *pdev, } } +static inline bool cpt_is_errata_38550_exists(struct pci_dev *pdev) +{ + if (is_dev_otx2(pdev) || is_dev_cn10ka_ax(pdev)) + return true; + + return false; +} + +static inline bool cpt_feature_sgv2(struct pci_dev *pdev) +{ + if (!is_dev_otx2(pdev) && !is_dev_cn10ka_ax(pdev)) + return true; + + return false; +} int otx2_cpt_send_ready_msg(struct otx2_mbox *mbox, struct pci_dev *pdev); int otx2_cpt_send_mbox_msg(struct otx2_mbox *mbox, struct pci_dev *pdev); @@ -171,5 +222,6 @@ int otx2_cpt_attach_rscrs_msg(struct otx2_cptlfs_info *lfs); int otx2_cpt_detach_rsrcs_msg(struct otx2_cptlfs_info *lfs); int otx2_cpt_msix_offset_msg(struct otx2_cptlfs_info *lfs); int otx2_cpt_sync_mbox_msg(struct otx2_mbox *mbox); +int otx2_cpt_lf_reset_msg(struct otx2_cptlfs_info *lfs, int slot); #endif /* __OTX2_CPT_COMMON_H */ diff --git a/drivers/crypto/marvell/octeontx2/otx2_cpt_devlink.c b/drivers/crypto/marvell/octeontx2/otx2_cpt_devlink.c index a2aba0b0d68a98..d2b8d26db968a6 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cpt_devlink.c +++ b/drivers/crypto/marvell/octeontx2/otx2_cpt_devlink.c @@ -23,11 +23,46 @@ static int otx2_cpt_dl_egrp_delete(struct devlink *dl, u32 id, static int otx2_cpt_dl_uc_info(struct devlink *dl, u32 id, struct devlink_param_gset_ctx *ctx) +{ + ctx->val.vstr[0] = '\0'; + + return 0; +} + +static int otx2_cpt_dl_t106_mode_get(struct devlink *dl, u32 id, + struct devlink_param_gset_ctx *ctx) { struct otx2_cpt_devlink *cpt_dl = devlink_priv(dl); struct otx2_cptpf_dev *cptpf = cpt_dl->cptpf; + struct pci_dev *pdev = cptpf->pdev; + u64 reg_val = 0; + + otx2_cpt_read_af_reg(&cptpf->afpf_mbox, pdev, CPT_AF_CTL, ®_val, + BLKADDR_CPT0); + ctx->val.vu8 = (reg_val >> 18) & 0x1; + + return 0; +} - otx2_cpt_print_uc_dbg_info(cptpf); +static int otx2_cpt_dl_t106_mode_set(struct devlink *dl, u32 id, + struct devlink_param_gset_ctx *ctx) +{ + struct otx2_cpt_devlink *cpt_dl = devlink_priv(dl); + struct otx2_cptpf_dev *cptpf = cpt_dl->cptpf; + struct pci_dev *pdev = cptpf->pdev; + u64 reg_val = 0; + + if (cptpf->enabled_vfs != 0 || cptpf->eng_grps.is_grps_created) + return -EPERM; + + if (cpt_feature_sgv2(pdev)) { + otx2_cpt_read_af_reg(&cptpf->afpf_mbox, pdev, CPT_AF_CTL, + ®_val, BLKADDR_CPT0); + reg_val &= ~(0x1ULL << 18); + reg_val |= ((u64)ctx->val.vu8 & 0x1) << 18; + return otx2_cpt_write_af_reg(&cptpf->afpf_mbox, pdev, + CPT_AF_CTL, reg_val, BLKADDR_CPT0); + } return 0; } @@ -36,6 +71,7 @@ enum otx2_cpt_dl_param_id { OTX2_CPT_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX, OTX2_CPT_DEVLINK_PARAM_ID_EGRP_CREATE, OTX2_CPT_DEVLINK_PARAM_ID_EGRP_DELETE, + OTX2_CPT_DEVLINK_PARAM_ID_T106_MODE, }; static const struct devlink_param otx2_cpt_dl_params[] = { @@ -49,6 +85,11 @@ static const struct devlink_param otx2_cpt_dl_params[] = { BIT(DEVLINK_PARAM_CMODE_RUNTIME), otx2_cpt_dl_uc_info, otx2_cpt_dl_egrp_delete, NULL), + DEVLINK_PARAM_DRIVER(OTX2_CPT_DEVLINK_PARAM_ID_T106_MODE, + "t106_mode", DEVLINK_PARAM_TYPE_U8, + BIT(DEVLINK_PARAM_CMODE_RUNTIME), + otx2_cpt_dl_t106_mode_get, otx2_cpt_dl_t106_mode_set, + NULL), }; static int otx2_cpt_dl_info_firmware_version_put(struct devlink_info_req *req, @@ -120,7 +161,6 @@ int otx2_cpt_register_dl(struct otx2_cptpf_dev *cptpf) devlink_free(dl); return ret; } - devlink_register(dl); return 0; diff --git a/drivers/crypto/marvell/octeontx2/otx2_cpt_hw_types.h b/drivers/crypto/marvell/octeontx2/otx2_cpt_hw_types.h index 6f947978e4e89c..7e746a4def8671 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cpt_hw_types.h +++ b/drivers/crypto/marvell/octeontx2/otx2_cpt_hw_types.h @@ -13,6 +13,9 @@ #define CN10K_CPT_PCI_PF_DEVICE_ID 0xA0F2 #define CN10K_CPT_PCI_VF_DEVICE_ID 0xA0F3 +#define CPT_PCI_SUBSYS_DEVID_CN10K_A 0xB900 +#define CPT_PCI_SUBSYS_DEVID_CN10K_B 0xBD00 + /* Mailbox interrupts offset */ #define OTX2_CPT_PF_MBOX_INT 6 #define OTX2_CPT_PF_INT_VEC_E_MBOXX(x, a) ((x) + (a)) @@ -99,6 +102,9 @@ #define OTX2_CPT_LF_Q_INST_PTR (0x110) #define OTX2_CPT_LF_Q_GRP_PTR (0x120) #define OTX2_CPT_LF_NQX(a) (0x400 | (a) << 3) +#define OTX2_CPT_LF_CTX_CTL (0x500) +#define OTX2_CPT_LF_CTX_FLUSH (0x510) +#define OTX2_CPT_LF_CTX_ERR (0x520) #define OTX2_CPT_RVU_FUNC_BLKADDR_SHIFT 20 /* LMT LF registers */ #define OTX2_CPT_LMT_LFBASE BIT_ULL(OTX2_CPT_RVU_FUNC_BLKADDR_SHIFT) @@ -467,7 +473,8 @@ union otx2_cptx_af_lf_ctrl { u64 cont_err:1; u64 reserved_11_15:5; u64 nixtx_en:1; - u64 reserved_17_47:31; + u64 ctx_ilen:3; + u64 reserved_17_47:28; u64 grp:8; u64 reserved_56_63:8; } s; diff --git a/drivers/crypto/marvell/octeontx2/otx2_cpt_mbox_common.c b/drivers/crypto/marvell/octeontx2/otx2_cpt_mbox_common.c index 273ee5352a50b4..5be0103c1fb817 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cpt_mbox_common.c +++ b/drivers/crypto/marvell/octeontx2/otx2_cpt_mbox_common.c @@ -229,3 +229,29 @@ int otx2_cpt_sync_mbox_msg(struct otx2_mbox *mbox) return otx2_mbox_check_rsp_msgs(mbox, 0); } EXPORT_SYMBOL_NS_GPL(otx2_cpt_sync_mbox_msg, CRYPTO_DEV_OCTEONTX2_CPT); + +int otx2_cpt_lf_reset_msg(struct otx2_cptlfs_info *lfs, int slot) +{ + struct otx2_mbox *mbox = lfs->mbox; + struct pci_dev *pdev = lfs->pdev; + struct cpt_lf_rst_req *req; + int ret; + + req = (struct cpt_lf_rst_req *)otx2_mbox_alloc_msg_rsp(mbox, 0, sizeof(*req), + sizeof(struct msg_rsp)); + if (!req) { + dev_err(&pdev->dev, "RVU MBOX failed to get message.\n"); + return -EFAULT; + } + + req->hdr.id = MBOX_MSG_CPT_LF_RESET; + req->hdr.sig = OTX2_MBOX_REQ_SIG; + req->hdr.pcifunc = 0; + req->slot = slot; + ret = otx2_cpt_send_mbox_msg(mbox, pdev); + if (ret) + return ret; + + return ret; +} +EXPORT_SYMBOL_NS_GPL(otx2_cpt_lf_reset_msg, CRYPTO_DEV_OCTEONTX2_CPT); diff --git a/drivers/crypto/marvell/octeontx2/otx2_cpt_reqmgr.h b/drivers/crypto/marvell/octeontx2/otx2_cpt_reqmgr.h index dbb1ee746f4cb0..e27e849b01dfc0 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cpt_reqmgr.h +++ b/drivers/crypto/marvell/octeontx2/otx2_cpt_reqmgr.h @@ -27,6 +27,13 @@ #define OTX2_CPT_MAX_REQ_SIZE 65535 +#define SG_COMPS_MAX 4 +#define SGV2_COMPS_MAX 3 + +#define SG_COMP_3 3 +#define SG_COMP_2 2 +#define SG_COMP_1 1 + union otx2_cpt_opcode { u16 flags; struct { @@ -40,6 +47,8 @@ struct otx2_cptvf_request { u32 param2; u16 dlen; union otx2_cpt_opcode opcode; + dma_addr_t cptr_dma; + void *cptr; }; /* @@ -143,6 +152,8 @@ struct otx2_cpt_inst_info { unsigned long time_in; u32 dlen; u32 dma_len; + u64 gthr_sz; + u64 sctr_sz; u8 extra_time; }; @@ -157,6 +168,16 @@ struct otx2_cpt_sglist_component { __be64 ptr3; }; +struct cn10kb_cpt_sglist_component { + u16 len0; + u16 len1; + u16 len2; + u16 valid_segs; + u64 ptr0; + u64 ptr1; + u64 ptr2; +}; + static inline void otx2_cpt_info_destroy(struct pci_dev *pdev, struct otx2_cpt_inst_info *info) { @@ -188,6 +209,283 @@ static inline void otx2_cpt_info_destroy(struct pci_dev *pdev, kfree(info); } +static inline int setup_sgio_components(struct pci_dev *pdev, + struct otx2_cpt_buf_ptr *list, + int buf_count, u8 *buffer) +{ + struct otx2_cpt_sglist_component *sg_ptr; + int components; + int i, j; + + if (unlikely(!list)) { + dev_err(&pdev->dev, "Input list pointer is NULL\n"); + return -EINVAL; + } + + for (i = 0; i < buf_count; i++) { + if (unlikely(!list[i].vptr)) + continue; + list[i].dma_addr = dma_map_single(&pdev->dev, list[i].vptr, + list[i].size, + DMA_BIDIRECTIONAL); + if (unlikely(dma_mapping_error(&pdev->dev, list[i].dma_addr))) { + dev_err(&pdev->dev, "Dma mapping failed\n"); + goto sg_cleanup; + } + } + components = buf_count / SG_COMPS_MAX; + sg_ptr = (struct otx2_cpt_sglist_component *)buffer; + for (i = 0; i < components; i++) { + sg_ptr->len0 = cpu_to_be16(list[i * SG_COMPS_MAX + 0].size); + sg_ptr->len1 = cpu_to_be16(list[i * SG_COMPS_MAX + 1].size); + sg_ptr->len2 = cpu_to_be16(list[i * SG_COMPS_MAX + 2].size); + sg_ptr->len3 = cpu_to_be16(list[i * SG_COMPS_MAX + 3].size); + sg_ptr->ptr0 = cpu_to_be64(list[i * SG_COMPS_MAX + 0].dma_addr); + sg_ptr->ptr1 = cpu_to_be64(list[i * SG_COMPS_MAX + 1].dma_addr); + sg_ptr->ptr2 = cpu_to_be64(list[i * SG_COMPS_MAX + 2].dma_addr); + sg_ptr->ptr3 = cpu_to_be64(list[i * SG_COMPS_MAX + 3].dma_addr); + sg_ptr++; + } + components = buf_count % SG_COMPS_MAX; + + switch (components) { + case SG_COMP_3: + sg_ptr->len2 = cpu_to_be16(list[i * SG_COMPS_MAX + 2].size); + sg_ptr->ptr2 = cpu_to_be64(list[i * SG_COMPS_MAX + 2].dma_addr); + fallthrough; + case SG_COMP_2: + sg_ptr->len1 = cpu_to_be16(list[i * SG_COMPS_MAX + 1].size); + sg_ptr->ptr1 = cpu_to_be64(list[i * SG_COMPS_MAX + 1].dma_addr); + fallthrough; + case SG_COMP_1: + sg_ptr->len0 = cpu_to_be16(list[i * SG_COMPS_MAX + 0].size); + sg_ptr->ptr0 = cpu_to_be64(list[i * SG_COMPS_MAX + 0].dma_addr); + break; + default: + break; + } + return 0; + +sg_cleanup: + for (j = 0; j < i; j++) { + if (list[j].dma_addr) { + dma_unmap_single(&pdev->dev, list[j].dma_addr, + list[j].size, DMA_BIDIRECTIONAL); + } + + list[j].dma_addr = 0; + } + return -EIO; +} + +static inline int sgv2io_components_setup(struct pci_dev *pdev, + struct otx2_cpt_buf_ptr *list, + int buf_count, u8 *buffer) +{ + struct cn10kb_cpt_sglist_component *sg_ptr; + int components; + int i, j; + + if (unlikely(!list)) { + dev_err(&pdev->dev, "Input list pointer is NULL\n"); + return -EFAULT; + } + + for (i = 0; i < buf_count; i++) { + if (unlikely(!list[i].vptr)) + continue; + list[i].dma_addr = dma_map_single(&pdev->dev, list[i].vptr, + list[i].size, + DMA_BIDIRECTIONAL); + if (unlikely(dma_mapping_error(&pdev->dev, list[i].dma_addr))) { + dev_err(&pdev->dev, "Dma mapping failed\n"); + goto sg_cleanup; + } + } + components = buf_count / SGV2_COMPS_MAX; + sg_ptr = (struct cn10kb_cpt_sglist_component *)buffer; + for (i = 0; i < components; i++) { + sg_ptr->len0 = list[i * SGV2_COMPS_MAX + 0].size; + sg_ptr->len1 = list[i * SGV2_COMPS_MAX + 1].size; + sg_ptr->len2 = list[i * SGV2_COMPS_MAX + 2].size; + sg_ptr->ptr0 = list[i * SGV2_COMPS_MAX + 0].dma_addr; + sg_ptr->ptr1 = list[i * SGV2_COMPS_MAX + 1].dma_addr; + sg_ptr->ptr2 = list[i * SGV2_COMPS_MAX + 2].dma_addr; + sg_ptr->valid_segs = SGV2_COMPS_MAX; + sg_ptr++; + } + components = buf_count % SGV2_COMPS_MAX; + + sg_ptr->valid_segs = components; + switch (components) { + case SG_COMP_2: + sg_ptr->len1 = list[i * SGV2_COMPS_MAX + 1].size; + sg_ptr->ptr1 = list[i * SGV2_COMPS_MAX + 1].dma_addr; + fallthrough; + case SG_COMP_1: + sg_ptr->len0 = list[i * SGV2_COMPS_MAX + 0].size; + sg_ptr->ptr0 = list[i * SGV2_COMPS_MAX + 0].dma_addr; + break; + default: + break; + } + return 0; + +sg_cleanup: + for (j = 0; j < i; j++) { + if (list[j].dma_addr) { + dma_unmap_single(&pdev->dev, list[j].dma_addr, + list[j].size, DMA_BIDIRECTIONAL); + } + + list[j].dma_addr = 0; + } + return -EIO; +} + +static inline struct otx2_cpt_inst_info * +cn10k_sgv2_info_create(struct pci_dev *pdev, struct otx2_cpt_req_info *req, + gfp_t gfp) +{ + u32 dlen = 0, g_len, sg_len, info_len; + int align = OTX2_CPT_DMA_MINALIGN; + struct otx2_cpt_inst_info *info; + u16 g_sz_bytes, s_sz_bytes; + u32 total_mem_len; + int i; + + g_sz_bytes = ((req->in_cnt + 2) / 3) * + sizeof(struct cn10kb_cpt_sglist_component); + s_sz_bytes = ((req->out_cnt + 2) / 3) * + sizeof(struct cn10kb_cpt_sglist_component); + + g_len = ALIGN(g_sz_bytes, align); + sg_len = ALIGN(g_len + s_sz_bytes, align); + info_len = ALIGN(sizeof(*info), align); + total_mem_len = sg_len + info_len + sizeof(union otx2_cpt_res_s); + + info = kzalloc(total_mem_len, gfp); + if (unlikely(!info)) + return NULL; + + for (i = 0; i < req->in_cnt; i++) + dlen += req->in[i].size; + + info->dlen = dlen; + info->in_buffer = (u8 *)info + info_len; + info->gthr_sz = req->in_cnt; + info->sctr_sz = req->out_cnt; + + /* Setup gather (input) components */ + if (sgv2io_components_setup(pdev, req->in, req->in_cnt, + info->in_buffer)) { + dev_err(&pdev->dev, "Failed to setup gather list\n"); + goto destroy_info; + } + + if (sgv2io_components_setup(pdev, req->out, req->out_cnt, + &info->in_buffer[g_len])) { + dev_err(&pdev->dev, "Failed to setup scatter list\n"); + goto destroy_info; + } + + info->dma_len = total_mem_len - info_len; + info->dptr_baddr = dma_map_single(&pdev->dev, info->in_buffer, + info->dma_len, DMA_BIDIRECTIONAL); + if (unlikely(dma_mapping_error(&pdev->dev, info->dptr_baddr))) { + dev_err(&pdev->dev, "DMA Mapping failed for cpt req\n"); + goto destroy_info; + } + info->rptr_baddr = info->dptr_baddr + g_len; + /* + * Get buffer for union otx2_cpt_res_s response + * structure and its physical address + */ + info->completion_addr = info->in_buffer + sg_len; + info->comp_baddr = info->dptr_baddr + sg_len; + + return info; + +destroy_info: + otx2_cpt_info_destroy(pdev, info); + return NULL; +} + +/* SG list header size in bytes */ +#define SG_LIST_HDR_SIZE 8 +static inline struct otx2_cpt_inst_info * +otx2_sg_info_create(struct pci_dev *pdev, struct otx2_cpt_req_info *req, + gfp_t gfp) +{ + int align = OTX2_CPT_DMA_MINALIGN; + struct otx2_cpt_inst_info *info; + u32 dlen, align_dlen, info_len; + u16 g_sz_bytes, s_sz_bytes; + u32 total_mem_len; + + if (unlikely(req->in_cnt > OTX2_CPT_MAX_SG_IN_CNT || + req->out_cnt > OTX2_CPT_MAX_SG_OUT_CNT)) { + dev_err(&pdev->dev, "Error too many sg components\n"); + return NULL; + } + + g_sz_bytes = ((req->in_cnt + 3) / 4) * + sizeof(struct otx2_cpt_sglist_component); + s_sz_bytes = ((req->out_cnt + 3) / 4) * + sizeof(struct otx2_cpt_sglist_component); + + dlen = g_sz_bytes + s_sz_bytes + SG_LIST_HDR_SIZE; + align_dlen = ALIGN(dlen, align); + info_len = ALIGN(sizeof(*info), align); + total_mem_len = align_dlen + info_len + sizeof(union otx2_cpt_res_s); + + info = kzalloc(total_mem_len, gfp); + if (unlikely(!info)) + return NULL; + + info->dlen = dlen; + info->in_buffer = (u8 *)info + info_len; + + ((u16 *)info->in_buffer)[0] = req->out_cnt; + ((u16 *)info->in_buffer)[1] = req->in_cnt; + ((u16 *)info->in_buffer)[2] = 0; + ((u16 *)info->in_buffer)[3] = 0; + cpu_to_be64s((u64 *)info->in_buffer); + + /* Setup gather (input) components */ + if (setup_sgio_components(pdev, req->in, req->in_cnt, + &info->in_buffer[8])) { + dev_err(&pdev->dev, "Failed to setup gather list\n"); + goto destroy_info; + } + + if (setup_sgio_components(pdev, req->out, req->out_cnt, + &info->in_buffer[8 + g_sz_bytes])) { + dev_err(&pdev->dev, "Failed to setup scatter list\n"); + goto destroy_info; + } + + info->dma_len = total_mem_len - info_len; + info->dptr_baddr = dma_map_single(&pdev->dev, info->in_buffer, + info->dma_len, DMA_BIDIRECTIONAL); + if (unlikely(dma_mapping_error(&pdev->dev, info->dptr_baddr))) { + dev_err(&pdev->dev, "DMA Mapping failed for cpt req\n"); + goto destroy_info; + } + /* + * Get buffer for union otx2_cpt_res_s response + * structure and its physical address + */ + info->completion_addr = info->in_buffer + align_dlen; + info->comp_baddr = info->dptr_baddr + align_dlen; + + return info; + +destroy_info: + otx2_cpt_info_destroy(pdev, info); + return NULL; +} + struct otx2_cptlf_wqe; int otx2_cpt_do_request(struct pci_dev *pdev, struct otx2_cpt_req_info *req, int cpu_num); diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptlf.c b/drivers/crypto/marvell/octeontx2/otx2_cptlf.c index 6edd27ff8c4e3c..b52728e3c0d13e 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cptlf.c +++ b/drivers/crypto/marvell/octeontx2/otx2_cptlf.c @@ -106,6 +106,32 @@ static int cptlf_set_grp_and_pri(struct otx2_cptlfs_info *lfs, return ret; } +static int cptlf_set_ctx_ilen(struct otx2_cptlfs_info *lfs, int ctx_ilen) +{ + union otx2_cptx_af_lf_ctrl lf_ctrl; + struct otx2_cptlf_info *lf; + int slot, ret = 0; + + for (slot = 0; slot < lfs->lfs_num; slot++) { + lf = &lfs->lf[slot]; + + ret = otx2_cpt_read_af_reg(lfs->mbox, lfs->pdev, + CPT_AF_LFX_CTL(lf->slot), + &lf_ctrl.u, lfs->blkaddr); + if (ret) + return ret; + + lf_ctrl.s.ctx_ilen = ctx_ilen; + + ret = otx2_cpt_write_af_reg(lfs->mbox, lfs->pdev, + CPT_AF_LFX_CTL(lf->slot), + lf_ctrl.u, lfs->blkaddr); + if (ret) + return ret; + } + return ret; +} + static void cptlf_hw_init(struct otx2_cptlfs_info *lfs) { /* Disable instruction queues */ @@ -151,26 +177,14 @@ static void cptlf_set_misc_intrs(struct otx2_cptlfs_info *lfs, u8 enable) irq_misc.u); } -static void cptlf_enable_intrs(struct otx2_cptlfs_info *lfs) -{ - int slot; - - /* Enable done interrupts */ - for (slot = 0; slot < lfs->lfs_num; slot++) - otx2_cpt_write64(lfs->reg_base, lfs->blkaddr, slot, - OTX2_CPT_LF_DONE_INT_ENA_W1S, 0x1); - /* Enable Misc interrupts */ - cptlf_set_misc_intrs(lfs, true); -} - -static void cptlf_disable_intrs(struct otx2_cptlfs_info *lfs) +static void cptlf_set_done_intrs(struct otx2_cptlfs_info *lfs, u8 enable) { + u64 reg = enable ? OTX2_CPT_LF_DONE_INT_ENA_W1S : + OTX2_CPT_LF_DONE_INT_ENA_W1C; int slot; for (slot = 0; slot < lfs->lfs_num; slot++) - otx2_cpt_write64(lfs->reg_base, lfs->blkaddr, slot, - OTX2_CPT_LF_DONE_INT_ENA_W1C, 0x1); - cptlf_set_misc_intrs(lfs, false); + otx2_cpt_write64(lfs->reg_base, lfs->blkaddr, slot, reg, 0x1); } static inline int cptlf_read_done_cnt(struct otx2_cptlf_info *lf) @@ -257,24 +271,44 @@ static irqreturn_t cptlf_done_intr_handler(int irq, void *arg) return IRQ_HANDLED; } -void otx2_cptlf_unregister_interrupts(struct otx2_cptlfs_info *lfs) +void otx2_cptlf_unregister_misc_interrupts(struct otx2_cptlfs_info *lfs) { - int i, offs, vector; + int i, irq_offs, vector; + irq_offs = OTX2_CPT_LF_INT_VEC_E_MISC; for (i = 0; i < lfs->lfs_num; i++) { - for (offs = 0; offs < OTX2_CPT_LF_MSIX_VECTORS; offs++) { - if (!lfs->lf[i].is_irq_reg[offs]) - continue; + if (!lfs->lf[i].is_irq_reg[irq_offs]) + continue; - vector = pci_irq_vector(lfs->pdev, - lfs->lf[i].msix_offset + offs); - free_irq(vector, &lfs->lf[i]); - lfs->lf[i].is_irq_reg[offs] = false; - } + vector = pci_irq_vector(lfs->pdev, + lfs->lf[i].msix_offset + irq_offs); + free_irq(vector, &lfs->lf[i]); + lfs->lf[i].is_irq_reg[irq_offs] = false; + } + + cptlf_set_misc_intrs(lfs, false); +} +EXPORT_SYMBOL_NS_GPL(otx2_cptlf_unregister_misc_interrupts, + CRYPTO_DEV_OCTEONTX2_CPT); + +void otx2_cptlf_unregister_done_interrupts(struct otx2_cptlfs_info *lfs) +{ + int i, irq_offs, vector; + + irq_offs = OTX2_CPT_LF_INT_VEC_E_DONE; + for (i = 0; i < lfs->lfs_num; i++) { + if (!lfs->lf[i].is_irq_reg[irq_offs]) + continue; + + vector = pci_irq_vector(lfs->pdev, + lfs->lf[i].msix_offset + irq_offs); + free_irq(vector, &lfs->lf[i]); + lfs->lf[i].is_irq_reg[irq_offs] = false; } - cptlf_disable_intrs(lfs); + + cptlf_set_done_intrs(lfs, false); } -EXPORT_SYMBOL_NS_GPL(otx2_cptlf_unregister_interrupts, +EXPORT_SYMBOL_NS_GPL(otx2_cptlf_unregister_done_interrupts, CRYPTO_DEV_OCTEONTX2_CPT); static int cptlf_do_register_interrrupts(struct otx2_cptlfs_info *lfs, @@ -296,34 +330,53 @@ static int cptlf_do_register_interrrupts(struct otx2_cptlfs_info *lfs, return ret; } -int otx2_cptlf_register_interrupts(struct otx2_cptlfs_info *lfs) +int otx2_cptlf_register_misc_interrupts(struct otx2_cptlfs_info *lfs) { + bool is_cpt1 = (lfs->blkaddr == BLKADDR_CPT1); int irq_offs, ret, i; + irq_offs = OTX2_CPT_LF_INT_VEC_E_MISC; for (i = 0; i < lfs->lfs_num; i++) { - irq_offs = OTX2_CPT_LF_INT_VEC_E_MISC; - snprintf(lfs->lf[i].irq_name[irq_offs], 32, "CPTLF Misc%d", i); + snprintf(lfs->lf[i].irq_name[irq_offs], 32, "CPT%dLF Misc%d", + is_cpt1, i); ret = cptlf_do_register_interrrupts(lfs, i, irq_offs, cptlf_misc_intr_handler); if (ret) goto free_irq; + } + cptlf_set_misc_intrs(lfs, true); + return 0; - irq_offs = OTX2_CPT_LF_INT_VEC_E_DONE; - snprintf(lfs->lf[i].irq_name[irq_offs], 32, "OTX2_CPTLF Done%d", - i); +free_irq: + otx2_cptlf_unregister_misc_interrupts(lfs); + return ret; +} +EXPORT_SYMBOL_NS_GPL(otx2_cptlf_register_misc_interrupts, + CRYPTO_DEV_OCTEONTX2_CPT); + +int otx2_cptlf_register_done_interrupts(struct otx2_cptlfs_info *lfs) +{ + bool is_cpt1 = (lfs->blkaddr == BLKADDR_CPT1); + int irq_offs, ret, i; + + irq_offs = OTX2_CPT_LF_INT_VEC_E_DONE; + for (i = 0; i < lfs->lfs_num; i++) { + snprintf(lfs->lf[i].irq_name[irq_offs], 32, + "OTX2_CPT%dLF Done%d", is_cpt1, i); ret = cptlf_do_register_interrrupts(lfs, i, irq_offs, cptlf_done_intr_handler); if (ret) goto free_irq; } - cptlf_enable_intrs(lfs); + cptlf_set_done_intrs(lfs, true); return 0; free_irq: - otx2_cptlf_unregister_interrupts(lfs); + otx2_cptlf_unregister_done_interrupts(lfs); return ret; } -EXPORT_SYMBOL_NS_GPL(otx2_cptlf_register_interrupts, CRYPTO_DEV_OCTEONTX2_CPT); +EXPORT_SYMBOL_NS_GPL(otx2_cptlf_register_done_interrupts, + CRYPTO_DEV_OCTEONTX2_CPT); void otx2_cptlf_free_irqs_affinity(struct otx2_cptlfs_info *lfs) { @@ -416,11 +469,17 @@ int otx2_cptlf_init(struct otx2_cptlfs_info *lfs, u8 eng_grp_mask, int pri, if (ret) goto free_iq; + if (lfs->ctx_ilen_ovrd) { + ret = cptlf_set_ctx_ilen(lfs, lfs->ctx_ilen); + if (ret) + goto free_iq; + } + return 0; free_iq: - otx2_cpt_free_instruction_queues(lfs); cptlf_hw_cleanup(lfs); + otx2_cpt_free_instruction_queues(lfs); detach_rsrcs: otx2_cpt_detach_rsrcs_msg(lfs); clear_lfs_num: @@ -431,11 +490,13 @@ EXPORT_SYMBOL_NS_GPL(otx2_cptlf_init, CRYPTO_DEV_OCTEONTX2_CPT); void otx2_cptlf_shutdown(struct otx2_cptlfs_info *lfs) { - lfs->lfs_num = 0; /* Cleanup LFs hardware side */ cptlf_hw_cleanup(lfs); + /* Free instruction queues */ + otx2_cpt_free_instruction_queues(lfs); /* Send request to detach LFs */ otx2_cpt_detach_rsrcs_msg(lfs); + lfs->lfs_num = 0; } EXPORT_SYMBOL_NS_GPL(otx2_cptlf_shutdown, CRYPTO_DEV_OCTEONTX2_CPT); diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptlf.h b/drivers/crypto/marvell/octeontx2/otx2_cptlf.h index 5302fe3d0e6f8b..bd8604be2952a9 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cptlf.h +++ b/drivers/crypto/marvell/octeontx2/otx2_cptlf.h @@ -5,6 +5,7 @@ #define __OTX2_CPTLF_H #include +#include #include #include #include "otx2_cpt_common.h" @@ -99,6 +100,9 @@ struct cpt_hw_ops { struct otx2_cptlf_info *lf); u8 (*cpt_get_compcode)(union otx2_cpt_res_s *result); u8 (*cpt_get_uc_compcode)(union otx2_cpt_res_s *result); + struct otx2_cpt_inst_info * + (*cpt_sg_info_create)(struct pci_dev *pdev, struct otx2_cpt_req_info *req, + gfp_t gfp); }; struct otx2_cptlfs_info { @@ -116,6 +120,9 @@ struct otx2_cptlfs_info { u8 kvf_limits; /* Kernel crypto limits */ atomic_t state; /* LF's state. started/reset */ int blkaddr; /* CPT blkaddr: BLKADDR_CPT0/BLKADDR_CPT1 */ + int global_slot; /* Global slot across the blocks */ + u8 ctx_ilen; + u8 ctx_ilen_ovrd; }; static inline void otx2_cpt_free_instruction_queues( @@ -203,48 +210,71 @@ static inline void otx2_cptlf_set_iqueues_size(struct otx2_cptlfs_info *lfs) otx2_cptlf_do_set_iqueue_size(&lfs->lf[slot]); } +#define INFLIGHT GENMASK_ULL(8, 0) +#define GRB_CNT GENMASK_ULL(39, 32) +#define GWB_CNT GENMASK_ULL(47, 40) +#define XQ_XOR GENMASK_ULL(63, 63) +#define DQPTR GENMASK_ULL(19, 0) +#define NQPTR GENMASK_ULL(51, 32) + static inline void otx2_cptlf_do_disable_iqueue(struct otx2_cptlf_info *lf) { - union otx2_cptx_lf_ctl lf_ctl = { .u = 0x0 }; - union otx2_cptx_lf_inprog lf_inprog; + void __iomem *reg_base = lf->lfs->reg_base; + struct pci_dev *pdev = lf->lfs->pdev; u8 blkaddr = lf->lfs->blkaddr; - int timeout = 20; + int timeout = 1000000; + u64 inprog, inst_ptr; + u64 slot = lf->slot; + u64 qsize, pending; + int i = 0; /* Disable instructions enqueuing */ - otx2_cpt_write64(lf->lfs->reg_base, blkaddr, lf->slot, - OTX2_CPT_LF_CTL, lf_ctl.u); + otx2_cpt_write64(reg_base, blkaddr, slot, OTX2_CPT_LF_CTL, 0x0); + + inprog = otx2_cpt_read64(reg_base, blkaddr, slot, OTX2_CPT_LF_INPROG); + inprog |= BIT_ULL(16); + otx2_cpt_write64(reg_base, blkaddr, slot, OTX2_CPT_LF_INPROG, inprog); - /* Wait for instruction queue to become empty */ + qsize = otx2_cpt_read64(reg_base, blkaddr, slot, OTX2_CPT_LF_Q_SIZE) & 0x7FFF; + do { + inst_ptr = otx2_cpt_read64(reg_base, blkaddr, slot, OTX2_CPT_LF_Q_INST_PTR); + pending = (FIELD_GET(XQ_XOR, inst_ptr) * qsize * 40) + + FIELD_GET(NQPTR, inst_ptr) - FIELD_GET(DQPTR, inst_ptr); + udelay(1); + timeout--; + } while ((pending != 0) && (timeout != 0)); + + if (timeout == 0) + dev_warn(&pdev->dev, "TIMEOUT: CPT poll on pending instructions\n"); + + timeout = 1000000; + /* Wait for CPT queue to become execution-quiescent */ do { - lf_inprog.u = otx2_cpt_read64(lf->lfs->reg_base, blkaddr, - lf->slot, OTX2_CPT_LF_INPROG); - if (!lf_inprog.s.inflight) - break; - - usleep_range(10000, 20000); - if (timeout-- < 0) { - dev_err(&lf->lfs->pdev->dev, - "Error LF %d is still busy.\n", lf->slot); - break; + inprog = otx2_cpt_read64(reg_base, blkaddr, slot, OTX2_CPT_LF_INPROG); + + if ((FIELD_GET(INFLIGHT, inprog) == 0) && + (FIELD_GET(GRB_CNT, inprog) == 0)) { + i++; + } else { + i = 0; + timeout--; } + } while ((timeout != 0) && (i < 10)); - } while (1); - - /* - * Disable executions in the LF's queue, - * the queue should be empty at this point - */ - lf_inprog.s.eena = 0x0; - otx2_cpt_write64(lf->lfs->reg_base, blkaddr, lf->slot, - OTX2_CPT_LF_INPROG, lf_inprog.u); + if (timeout == 0) + dev_warn(&pdev->dev, "TIMEOUT: CPT poll on inflight count\n"); + /* Wait for 2 us to flush all queue writes to memory */ + udelay(2); } static inline void otx2_cptlf_disable_iqueues(struct otx2_cptlfs_info *lfs) { int slot; - for (slot = 0; slot < lfs->lfs_num; slot++) + for (slot = 0; slot < lfs->lfs_num; slot++) { otx2_cptlf_do_disable_iqueue(&lfs->lf[slot]); + otx2_cpt_lf_reset_msg(lfs, lfs->global_slot + slot); + } } static inline void otx2_cptlf_set_iqueue_enq(struct otx2_cptlf_info *lf, @@ -282,6 +312,19 @@ static inline void otx2_cptlf_set_iqueue_exec(struct otx2_cptlf_info *lf, OTX2_CPT_LF_INPROG, lf_inprog.u); } +static inline void otx2_cptlf_set_ctx_flr_flush(struct otx2_cptlf_info *lf) +{ + u8 blkaddr = lf->lfs->blkaddr; + u64 val; + + val = otx2_cpt_read64(lf->lfs->reg_base, blkaddr, lf->slot, + OTX2_CPT_LF_CTX_CTL); + val |= BIT_ULL(0); + + otx2_cpt_write64(lf->lfs->reg_base, blkaddr, lf->slot, + OTX2_CPT_LF_CTX_CTL, val); +} + static inline void otx2_cptlf_enable_iqueue_exec(struct otx2_cptlf_info *lf) { otx2_cptlf_set_iqueue_exec(lf, true); @@ -297,6 +340,10 @@ static inline void otx2_cptlf_enable_iqueues(struct otx2_cptlfs_info *lfs) int slot; for (slot = 0; slot < lfs->lfs_num; slot++) { + /* Enable flush on FLR for Errata */ + if (is_dev_cn10kb(lfs->pdev)) + otx2_cptlf_set_ctx_flr_flush(&lfs->lf[slot]); + otx2_cptlf_enable_iqueue_exec(&lfs->lf[slot]); otx2_cptlf_enable_iqueue_enq(&lfs->lf[slot]); } @@ -382,8 +429,10 @@ static inline void otx2_cptlf_set_dev_info(struct otx2_cptlfs_info *lfs, int otx2_cptlf_init(struct otx2_cptlfs_info *lfs, u8 eng_grp_msk, int pri, int lfs_num); void otx2_cptlf_shutdown(struct otx2_cptlfs_info *lfs); -int otx2_cptlf_register_interrupts(struct otx2_cptlfs_info *lfs); -void otx2_cptlf_unregister_interrupts(struct otx2_cptlfs_info *lfs); +int otx2_cptlf_register_misc_interrupts(struct otx2_cptlfs_info *lfs); +int otx2_cptlf_register_done_interrupts(struct otx2_cptlfs_info *lfs); +void otx2_cptlf_unregister_misc_interrupts(struct otx2_cptlfs_info *lfs); +void otx2_cptlf_unregister_done_interrupts(struct otx2_cptlfs_info *lfs); void otx2_cptlf_free_irqs_affinity(struct otx2_cptlfs_info *lfs); int otx2_cptlf_set_irqs_affinity(struct otx2_cptlfs_info *lfs); diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptpf.h b/drivers/crypto/marvell/octeontx2/otx2_cptpf.h index a209ec5af381f1..e5859a1e1c6026 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cptpf.h +++ b/drivers/crypto/marvell/octeontx2/otx2_cptpf.h @@ -71,4 +71,8 @@ void otx2_cptpf_afpf_mbox_up_handler(struct work_struct *work); irqreturn_t otx2_cptpf_vfpf_mbox_intr(int irq, void *arg); void otx2_cptpf_vfpf_mbox_handler(struct work_struct *work); +int otx2_inline_cptlf_setup(struct otx2_cptpf_dev *cptpf, + struct otx2_cptlfs_info *lfs, u8 egrp, int num_lfs); +void otx2_inline_cptlf_cleanup(struct otx2_cptlfs_info *lfs); + #endif /* __OTX2_CPTPF_H */ diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c b/drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c index e34223daa327af..400e36d9908f43 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c +++ b/drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c @@ -14,6 +14,8 @@ #define OTX2_CPT_DRV_STRING "Marvell RVU CPT Physical Function Driver" #define CPT_UC_RID_CN9K_B0 1 +#define CPT_UC_RID_CN10K_A 4 +#define CPT_UC_RID_CN10K_B 5 static void cptpf_enable_vfpf_mbox_intr(struct otx2_cptpf_dev *cptpf, int num_vfs) @@ -587,43 +589,22 @@ static int cpt_is_pf_usable(struct otx2_cptpf_dev *cptpf) return 0; } -static int cptx_device_reset(struct otx2_cptpf_dev *cptpf, int blkaddr) +static void cptpf_get_rid(struct pci_dev *pdev, struct otx2_cptpf_dev *cptpf) { - int timeout = 10, ret; - u64 reg = 0; + struct otx2_cpt_eng_grps *eng_grps = &cptpf->eng_grps; + u64 reg_val = 0x0; - ret = otx2_cpt_write_af_reg(&cptpf->afpf_mbox, cptpf->pdev, - CPT_AF_BLK_RST, 0x1, blkaddr); - if (ret) - return ret; - - do { - ret = otx2_cpt_read_af_reg(&cptpf->afpf_mbox, cptpf->pdev, - CPT_AF_BLK_RST, ®, blkaddr); - if (ret) - return ret; - - if (!((reg >> 63) & 0x1)) - break; - - usleep_range(10000, 20000); - if (timeout-- < 0) - return -EBUSY; - } while (1); - - return ret; -} - -static int cptpf_device_reset(struct otx2_cptpf_dev *cptpf) -{ - int ret = 0; - - if (cptpf->has_cpt1) { - ret = cptx_device_reset(cptpf, BLKADDR_CPT1); - if (ret) - return ret; + if (is_dev_otx2(pdev)) { + eng_grps->rid = pdev->revision; + return; } - return cptx_device_reset(cptpf, BLKADDR_CPT0); + otx2_cpt_read_af_reg(&cptpf->afpf_mbox, pdev, CPT_AF_CTL, ®_val, + BLKADDR_CPT0); + if ((cpt_feature_sgv2(pdev) && (reg_val & BIT_ULL(18))) || + is_dev_cn10ka_ax(pdev)) + eng_grps->rid = CPT_UC_RID_CN10K_A; + else if (cpt_feature_sgv2(pdev)) + eng_grps->rid = CPT_UC_RID_CN10K_B; } static void cptpf_check_block_implemented(struct otx2_cptpf_dev *cptpf) @@ -643,10 +624,6 @@ static int cptpf_device_init(struct otx2_cptpf_dev *cptpf) /* check if 'implemented' bit is set for block BLKADDR_CPT1 */ cptpf_check_block_implemented(cptpf); - /* Reset the CPT PF device */ - ret = cptpf_device_reset(cptpf); - if (ret) - return ret; /* Get number of SE, IE and AE engines */ ret = otx2_cpt_read_af_reg(&cptpf->afpf_mbox, cptpf->pdev, @@ -701,6 +678,7 @@ static int cptpf_sriov_enable(struct pci_dev *pdev, int num_vfs) if (ret) goto destroy_flr; + cptpf_get_rid(pdev, cptpf); /* Get CPT HW capabilities using LOAD_FVC operation. */ ret = otx2_cpt_discover_eng_capabilities(cptpf); if (ret) @@ -744,7 +722,7 @@ static int otx2_cptpf_probe(struct pci_dev *pdev, { struct device *dev = &pdev->dev; struct otx2_cptpf_dev *cptpf; - int err; + int err, num_vec; cptpf = devm_kzalloc(dev, sizeof(*cptpf), GFP_KERNEL); if (!cptpf) @@ -779,8 +757,13 @@ static int otx2_cptpf_probe(struct pci_dev *pdev, if (err) goto clear_drvdata; - err = pci_alloc_irq_vectors(pdev, RVU_PF_INT_VEC_CNT, - RVU_PF_INT_VEC_CNT, PCI_IRQ_MSIX); + num_vec = pci_msix_vec_count(cptpf->pdev); + if (num_vec <= 0) { + err = -EINVAL; + goto clear_drvdata; + } + + err = pci_alloc_irq_vectors(pdev, num_vec, num_vec, PCI_IRQ_MSIX); if (err < 0) { dev_err(dev, "Request for %d msix vectors failed\n", RVU_PF_INT_VEC_CNT); @@ -797,6 +780,7 @@ static int otx2_cptpf_probe(struct pci_dev *pdev, goto destroy_afpf_mbox; cptpf->max_vfs = pci_sriov_get_totalvfs(pdev); + cptpf->kvf_limits = 1; err = cn10k_cptpf_lmtst_init(cptpf); if (err) @@ -844,6 +828,14 @@ static void otx2_cptpf_remove(struct pci_dev *pdev) cptpf_sriov_disable(pdev); otx2_cpt_unregister_dl(cptpf); + + /* Cleanup Inline CPT LF's if attached */ + if (cptpf->lfs.lfs_num) + otx2_inline_cptlf_cleanup(&cptpf->lfs); + + if (cptpf->cpt1_lfs.lfs_num) + otx2_inline_cptlf_cleanup(&cptpf->cpt1_lfs); + /* Delete sysfs entry created for kernel VF limits */ sysfs_remove_group(&pdev->dev.kobj, &cptpf_sysfs_group); /* Cleanup engine groups */ diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptpf_mbox.c b/drivers/crypto/marvell/octeontx2/otx2_cptpf_mbox.c index 480b3720f15ab4..ec1ac7e836a310 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cptpf_mbox.c +++ b/drivers/crypto/marvell/octeontx2/otx2_cptpf_mbox.c @@ -78,7 +78,7 @@ static int handle_msg_get_caps(struct otx2_cptpf_dev *cptpf, rsp->hdr.sig = OTX2_MBOX_RSP_SIG; rsp->hdr.pcifunc = req->pcifunc; rsp->cpt_pf_drv_version = OTX2_CPT_PF_DRV_VERSION; - rsp->cpt_revision = cptpf->pdev->revision; + rsp->cpt_revision = cptpf->eng_grps.rid; memcpy(&rsp->eng_caps, &cptpf->eng_caps, sizeof(rsp->eng_caps)); return 0; @@ -171,6 +171,8 @@ static int rx_inline_ipsec_lf_cfg(struct otx2_cptpf_dev *cptpf, u8 egrp, nix_req->hdr.id = MBOX_MSG_NIX_INLINE_IPSEC_CFG; nix_req->hdr.sig = OTX2_MBOX_REQ_SIG; nix_req->enable = 1; + nix_req->credit_th = req->credit_th; + nix_req->bpid = req->bpid; if (!req->credit || req->credit > OTX2_CPT_INST_QLEN_MSGS) nix_req->cpt_credit = OTX2_CPT_INST_QLEN_MSGS - 1; else @@ -197,12 +199,53 @@ static int rx_inline_ipsec_lf_cfg(struct otx2_cptpf_dev *cptpf, u8 egrp, return send_inline_ipsec_inbound_msg(cptpf, req->sso_pf_func, 0); } +int +otx2_inline_cptlf_setup(struct otx2_cptpf_dev *cptpf, + struct otx2_cptlfs_info *lfs, u8 egrp, int num_lfs) +{ + int ret; + + ret = otx2_cptlf_init(lfs, 1 << egrp, OTX2_CPT_QUEUE_HI_PRIO, 1); + if (ret) { + dev_err(&cptpf->pdev->dev, + "LF configuration failed for RX inline ipsec.\n"); + return ret; + } + + /* Get msix offsets for attached LFs */ + ret = otx2_cpt_msix_offset_msg(lfs); + if (ret) + goto cleanup_lf; + + /* Register for CPT LF Misc interrupts */ + ret = otx2_cptlf_register_misc_interrupts(lfs); + if (ret) + goto free_irq; + + return 0; +free_irq: + otx2_cptlf_unregister_misc_interrupts(lfs); +cleanup_lf: + otx2_cptlf_shutdown(lfs); + return ret; +} + +void +otx2_inline_cptlf_cleanup(struct otx2_cptlfs_info *lfs) +{ + /* Unregister misc interrupt */ + otx2_cptlf_unregister_misc_interrupts(lfs); + + /* Cleanup LFs */ + otx2_cptlf_shutdown(lfs); +} + static int handle_msg_rx_inline_ipsec_lf_cfg(struct otx2_cptpf_dev *cptpf, struct mbox_msghdr *req) { struct otx2_cpt_rx_inline_lf_cfg *cfg_req; + int num_lfs = 1, ret; u8 egrp; - int ret; cfg_req = (struct otx2_cpt_rx_inline_lf_cfg *)req; if (cptpf->lfs.lfs_num) { @@ -223,11 +266,13 @@ static int handle_msg_rx_inline_ipsec_lf_cfg(struct otx2_cptpf_dev *cptpf, otx2_cptlf_set_dev_info(&cptpf->lfs, cptpf->pdev, cptpf->reg_base, &cptpf->afpf_mbox, BLKADDR_CPT0); - ret = otx2_cptlf_init(&cptpf->lfs, 1 << egrp, OTX2_CPT_QUEUE_HI_PRIO, - 1); + cptpf->lfs.global_slot = 0; + cptpf->lfs.ctx_ilen_ovrd = cfg_req->ctx_ilen_valid; + cptpf->lfs.ctx_ilen = cfg_req->ctx_ilen; + + ret = otx2_inline_cptlf_setup(cptpf, &cptpf->lfs, egrp, num_lfs); if (ret) { - dev_err(&cptpf->pdev->dev, - "LF configuration failed for RX inline ipsec.\n"); + dev_err(&cptpf->pdev->dev, "Inline-Ipsec CPT0 LF setup failed.\n"); return ret; } @@ -236,11 +281,13 @@ static int handle_msg_rx_inline_ipsec_lf_cfg(struct otx2_cptpf_dev *cptpf, otx2_cptlf_set_dev_info(&cptpf->cpt1_lfs, cptpf->pdev, cptpf->reg_base, &cptpf->afpf_mbox, BLKADDR_CPT1); - ret = otx2_cptlf_init(&cptpf->cpt1_lfs, 1 << egrp, - OTX2_CPT_QUEUE_HI_PRIO, 1); + cptpf->cpt1_lfs.global_slot = num_lfs; + cptpf->cpt1_lfs.ctx_ilen_ovrd = cfg_req->ctx_ilen_valid; + cptpf->cpt1_lfs.ctx_ilen = cfg_req->ctx_ilen; + ret = otx2_inline_cptlf_setup(cptpf, &cptpf->cpt1_lfs, egrp, + num_lfs); if (ret) { - dev_err(&cptpf->pdev->dev, - "LF configuration failed for RX inline ipsec.\n"); + dev_err(&cptpf->pdev->dev, "Inline CPT1 LF setup failed.\n"); goto lf_cleanup; } cptpf->rsrc_req_blkaddr = 0; @@ -253,9 +300,9 @@ static int handle_msg_rx_inline_ipsec_lf_cfg(struct otx2_cptpf_dev *cptpf, return 0; lf1_cleanup: - otx2_cptlf_shutdown(&cptpf->cpt1_lfs); + otx2_inline_cptlf_cleanup(&cptpf->cpt1_lfs); lf_cleanup: - otx2_cptlf_shutdown(&cptpf->lfs); + otx2_inline_cptlf_cleanup(&cptpf->lfs); return ret; } @@ -410,6 +457,8 @@ static void process_afpf_mbox_msg(struct otx2_cptpf_dev *cptpf, struct otx2_cptlfs_info *lfs = &cptpf->lfs; struct device *dev = &cptpf->pdev->dev; struct cpt_rd_wr_reg_msg *rsp_rd_wr; + struct msix_offset_rsp *rsp_msix; + int i; if (msg->id >= MBOX_MSG_MAX) { dev_err(dev, "MBOX msg with unknown ID %d\n", msg->id); @@ -428,6 +477,14 @@ static void process_afpf_mbox_msg(struct otx2_cptpf_dev *cptpf, cptpf->pf_id = (msg->pcifunc >> RVU_PFVF_PF_SHIFT) & RVU_PFVF_PF_MASK; break; + case MBOX_MSG_MSIX_OFFSET: + rsp_msix = (struct msix_offset_rsp *) msg; + for (i = 0; i < rsp_msix->cptlfs; i++) + lfs->lf[i].msix_offset = rsp_msix->cptlf_msixoff[i]; + + for (i = 0; i < rsp_msix->cpt1_lfs; i++) + lfs->lf[i].msix_offset = rsp_msix->cpt1_lf_msixoff[i]; + break; case MBOX_MSG_CPT_RD_WR_REGISTER: rsp_rd_wr = (struct cpt_rd_wr_reg_msg *)msg; if (msg->rc) { @@ -449,6 +506,7 @@ static void process_afpf_mbox_msg(struct otx2_cptpf_dev *cptpf, break; case MBOX_MSG_CPT_INLINE_IPSEC_CFG: case MBOX_MSG_NIX_INLINE_IPSEC_CFG: + case MBOX_MSG_CPT_LF_RESET: break; default: diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.c b/drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.c index 1958b797a42100..5c94846461725d 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.c +++ b/drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.c @@ -16,7 +16,11 @@ #define LOADFVC_MAJOR_OP 0x01 #define LOADFVC_MINOR_OP 0x08 -#define CTX_FLUSH_TIMER_CNT 0xFFFFFF +/* + * Interval to flush dirty data for next CTX entry. The interval is measured + * in increments of 10ns(interval time = CTX_FLUSH_TIMER_COUNT * 10ns). + */ +#define CTX_FLUSH_TIMER_CNT 0x2FAF0 struct fw_info_t { struct list_head ucodes; @@ -117,12 +121,10 @@ static char *get_ucode_type_str(int ucode_type) static int get_ucode_type(struct device *dev, struct otx2_cpt_ucode_hdr *ucode_hdr, - int *ucode_type) + int *ucode_type, u16 rid) { - struct otx2_cptpf_dev *cptpf = dev_get_drvdata(dev); char ver_str_prefix[OTX2_CPT_UCODE_VER_STR_SZ]; char tmp_ver_str[OTX2_CPT_UCODE_VER_STR_SZ]; - struct pci_dev *pdev = cptpf->pdev; int i, val = 0; u8 nn; @@ -130,7 +132,7 @@ static int get_ucode_type(struct device *dev, for (i = 0; i < strlen(tmp_ver_str); i++) tmp_ver_str[i] = tolower(tmp_ver_str[i]); - sprintf(ver_str_prefix, "ocpt-%02d", pdev->revision); + sprintf(ver_str_prefix, "ocpt-%02d", rid); if (!strnstr(tmp_ver_str, ver_str_prefix, OTX2_CPT_UCODE_VER_STR_SZ)) return -EINVAL; @@ -359,7 +361,7 @@ static int cpt_attach_and_enable_cores(struct otx2_cpt_eng_grp_info *eng_grp, } static int load_fw(struct device *dev, struct fw_info_t *fw_info, - char *filename) + char *filename, u16 rid) { struct otx2_cpt_ucode_hdr *ucode_hdr; struct otx2_cpt_uc_info_t *uc_info; @@ -375,7 +377,7 @@ static int load_fw(struct device *dev, struct fw_info_t *fw_info, goto free_uc_info; ucode_hdr = (struct otx2_cpt_ucode_hdr *)uc_info->fw->data; - ret = get_ucode_type(dev, ucode_hdr, &ucode_type); + ret = get_ucode_type(dev, ucode_hdr, &ucode_type, rid); if (ret) goto release_fw; @@ -389,6 +391,7 @@ static int load_fw(struct device *dev, struct fw_info_t *fw_info, set_ucode_filename(&uc_info->ucode, filename); memcpy(uc_info->ucode.ver_str, ucode_hdr->ver_str, OTX2_CPT_UCODE_VER_STR_SZ); + uc_info->ucode.ver_str[OTX2_CPT_UCODE_VER_STR_SZ] = 0; uc_info->ucode.ver_num = ucode_hdr->ver_num; uc_info->ucode.type = ucode_type; uc_info->ucode.size = ucode_size; @@ -448,7 +451,8 @@ static void print_uc_info(struct fw_info_t *fw_info) } } -static int cpt_ucode_load_fw(struct pci_dev *pdev, struct fw_info_t *fw_info) +static int cpt_ucode_load_fw(struct pci_dev *pdev, struct fw_info_t *fw_info, + u16 rid) { char filename[OTX2_CPT_NAME_LENGTH]; char eng_type[8] = {0}; @@ -462,9 +466,9 @@ static int cpt_ucode_load_fw(struct pci_dev *pdev, struct fw_info_t *fw_info) eng_type[i] = tolower(eng_type[i]); snprintf(filename, sizeof(filename), "mrvl/cpt%02d/%s.out", - pdev->revision, eng_type); + rid, eng_type); /* Request firmware for each engine type */ - ret = load_fw(&pdev->dev, fw_info, filename); + ret = load_fw(&pdev->dev, fw_info, filename, rid); if (ret) goto release_fw; } @@ -1155,7 +1159,7 @@ int otx2_cpt_create_eng_grps(struct otx2_cptpf_dev *cptpf, if (eng_grps->is_grps_created) goto unlock; - ret = cpt_ucode_load_fw(pdev, &fw_info); + ret = cpt_ucode_load_fw(pdev, &fw_info, eng_grps->rid); if (ret) goto unlock; @@ -1230,14 +1234,16 @@ int otx2_cpt_create_eng_grps(struct otx2_cptpf_dev *cptpf, */ rnm_to_cpt_errata_fixup(&pdev->dev); + otx2_cpt_read_af_reg(&cptpf->afpf_mbox, pdev, CPT_AF_CTL, ®_val, + BLKADDR_CPT0); /* * Configure engine group mask to allow context prefetching * for the groups and enable random number request, to enable * CPT to request random numbers from RNM. */ + reg_val |= OTX2_CPT_ALL_ENG_GRPS_MASK << 3 | BIT_ULL(16); otx2_cpt_write_af_reg(&cptpf->afpf_mbox, pdev, CPT_AF_CTL, - OTX2_CPT_ALL_ENG_GRPS_MASK << 3 | BIT_ULL(16), - BLKADDR_CPT0); + reg_val, BLKADDR_CPT0); /* * Set interval to periodically flush dirty data for the next * CTX cache entry. Set the interval count to maximum supported @@ -1252,10 +1258,12 @@ int otx2_cpt_create_eng_grps(struct otx2_cptpf_dev *cptpf, * encounters a fault/poison, a rare case may result in * unpredictable data being delivered to a CPT engine. */ - otx2_cpt_read_af_reg(&cptpf->afpf_mbox, pdev, CPT_AF_DIAG, ®_val, - BLKADDR_CPT0); - otx2_cpt_write_af_reg(&cptpf->afpf_mbox, pdev, CPT_AF_DIAG, - reg_val | BIT_ULL(24), BLKADDR_CPT0); + if (cpt_is_errata_38550_exists(pdev)) { + otx2_cpt_read_af_reg(&cptpf->afpf_mbox, pdev, CPT_AF_DIAG, + ®_val, BLKADDR_CPT0); + otx2_cpt_write_af_reg(&cptpf->afpf_mbox, pdev, CPT_AF_DIAG, + reg_val | BIT_ULL(24), BLKADDR_CPT0); + } mutex_unlock(&eng_grps->lock); return 0; @@ -1412,7 +1420,7 @@ static int create_eng_caps_discovery_grps(struct pci_dev *pdev, int ret; mutex_lock(&eng_grps->lock); - ret = cpt_ucode_load_fw(pdev, &fw_info); + ret = cpt_ucode_load_fw(pdev, &fw_info, eng_grps->rid); if (ret) { mutex_unlock(&eng_grps->lock); return ret; @@ -1686,13 +1694,14 @@ int otx2_cpt_dl_custom_egrp_create(struct otx2_cptpf_dev *cptpf, goto err_unlock; } INIT_LIST_HEAD(&fw_info.ucodes); - ret = load_fw(dev, &fw_info, ucode_filename[0]); + + ret = load_fw(dev, &fw_info, ucode_filename[0], eng_grps->rid); if (ret) { dev_err(dev, "Unable to load firmware %s\n", ucode_filename[0]); goto err_unlock; } if (ucode_idx > 1) { - ret = load_fw(dev, &fw_info, ucode_filename[1]); + ret = load_fw(dev, &fw_info, ucode_filename[1], eng_grps->rid); if (ret) { dev_err(dev, "Unable to load firmware %s\n", ucode_filename[1]); diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.h b/drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.h index e69320a54b5d5f..365fe8943bd9ba 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.h +++ b/drivers/crypto/marvell/octeontx2/otx2_cptpf_ucode.h @@ -73,7 +73,7 @@ struct otx2_cpt_ucode_hdr { }; struct otx2_cpt_ucode { - u8 ver_str[OTX2_CPT_UCODE_VER_STR_SZ];/* + u8 ver_str[OTX2_CPT_UCODE_VER_STR_SZ + 1];/* * ucode version in readable * format */ @@ -150,6 +150,7 @@ struct otx2_cpt_eng_grps { int engs_num; /* total number of engines supported */ u8 eng_ref_cnt[OTX2_CPT_MAX_ENGINES];/* engines reference count */ bool is_grps_created; /* Is the engine groups are already created */ + u16 rid; }; struct otx2_cptpf_dev; int otx2_cpt_init_eng_grps(struct pci_dev *pdev, diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptvf.h b/drivers/crypto/marvell/octeontx2/otx2_cptvf.h index 994291e90da124..11ab9af1df15a8 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cptvf.h +++ b/drivers/crypto/marvell/octeontx2/otx2_cptvf.h @@ -22,6 +22,7 @@ struct otx2_cptvf_dev { int blkaddr; void *bbuf_base; unsigned long cap_flag; + u64 eng_caps[OTX2_CPT_MAX_ENG_TYPES]; }; irqreturn_t otx2_cptvf_pfvf_mbox_intr(int irq, void *arg); @@ -29,5 +30,6 @@ void otx2_cptvf_pfvf_mbox_handler(struct work_struct *work); int otx2_cptvf_send_eng_grp_num_msg(struct otx2_cptvf_dev *cptvf, int eng_type); int otx2_cptvf_send_kvf_limits_msg(struct otx2_cptvf_dev *cptvf); int otx2_cpt_mbox_bbuf_init(struct otx2_cptvf_dev *cptvf, struct pci_dev *pdev); +int otx2_cptvf_send_caps_msg(struct otx2_cptvf_dev *cptvf); #endif /* __OTX2_CPTVF_H */ diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c b/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c index e27ddd3c4e5581..1604fc58dc13ec 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c +++ b/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.c @@ -17,6 +17,7 @@ #include "otx2_cptvf.h" #include "otx2_cptvf_algs.h" #include "otx2_cpt_reqmgr.h" +#include "cn10k_cpt.h" /* Size of salt in AES GCM mode */ #define AES_GCM_SALT_SIZE 4 @@ -384,6 +385,9 @@ static inline int cpt_enc_dec(struct skcipher_request *req, u32 enc) req_info->is_trunc_hmac = false; req_info->ctrl.s.grp = otx2_cpt_get_kcrypto_eng_grp_num(pdev); + req_info->req.cptr = ctx->er_ctx.hw_ctx; + req_info->req.cptr_dma = ctx->er_ctx.cptr_dma; + /* * We perform an asynchronous send and once * the request is completed the driver would @@ -530,6 +534,8 @@ static int otx2_cpt_enc_dec_init(struct crypto_skcipher *stfm) struct otx2_cpt_enc_ctx *ctx = crypto_skcipher_ctx(stfm); struct crypto_tfm *tfm = crypto_skcipher_tfm(stfm); struct crypto_alg *alg = tfm->__crt_alg; + struct pci_dev *pdev; + int ret, cpu_num; memset(ctx, 0, sizeof(*ctx)); /* @@ -541,6 +547,15 @@ static int otx2_cpt_enc_dec_init(struct crypto_skcipher *stfm) stfm, sizeof(struct otx2_cpt_req_ctx) + sizeof(struct skcipher_request)); + ret = get_se_device(&pdev, &cpu_num); + if (ret) + return ret; + + ctx->pdev = pdev; + ret = cn10k_cpt_hw_ctx_init(pdev, &ctx->er_ctx); + if (ret) + return ret; + return cpt_skcipher_fallback_init(ctx, alg); } @@ -552,6 +567,7 @@ static void otx2_cpt_skcipher_exit(struct crypto_skcipher *tfm) crypto_free_skcipher(ctx->fbk_cipher); ctx->fbk_cipher = NULL; } + cn10k_cpt_hw_ctx_clear(ctx->pdev, &ctx->er_ctx); } static int cpt_aead_fallback_init(struct otx2_cpt_aead_ctx *ctx, @@ -576,6 +592,8 @@ static int cpt_aead_init(struct crypto_aead *atfm, u8 cipher_type, u8 mac_type) struct otx2_cpt_aead_ctx *ctx = crypto_aead_ctx_dma(atfm); struct crypto_tfm *tfm = crypto_aead_tfm(atfm); struct crypto_alg *alg = tfm->__crt_alg; + struct pci_dev *pdev; + int ret, cpu_num; ctx->cipher_type = cipher_type; ctx->mac_type = mac_type; @@ -632,6 +650,15 @@ static int cpt_aead_init(struct crypto_aead *atfm, u8 cipher_type, u8 mac_type) } crypto_aead_set_reqsize_dma(atfm, sizeof(struct otx2_cpt_req_ctx)); + ret = get_se_device(&pdev, &cpu_num); + if (ret) + return ret; + + ctx->pdev = pdev; + ret = cn10k_cpt_hw_ctx_init(pdev, &ctx->er_ctx); + if (ret) + return ret; + return cpt_aead_fallback_init(ctx, alg); } @@ -694,6 +721,7 @@ static void otx2_cpt_aead_exit(struct crypto_aead *tfm) crypto_free_aead(ctx->fbk_cipher); ctx->fbk_cipher = NULL; } + cn10k_cpt_hw_ctx_clear(ctx->pdev, &ctx->er_ctx); } static int otx2_cpt_aead_gcm_set_authsize(struct crypto_aead *tfm, @@ -1299,6 +1327,9 @@ static int cpt_aead_enc_dec(struct aead_request *req, u8 reg_type, u8 enc) req_info->is_enc = enc; req_info->is_trunc_hmac = false; + req_info->req.cptr = ctx->er_ctx.hw_ctx; + req_info->req.cptr_dma = ctx->er_ctx.cptr_dma; + switch (reg_type) { case OTX2_CPT_AEAD_ENC_DEC_REQ: status = create_aead_input_list(req, enc); diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.h b/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.h index f04184bd174470..d29f84f01ceeec 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.h +++ b/drivers/crypto/marvell/octeontx2/otx2_cptvf_algs.h @@ -9,6 +9,7 @@ #include #include #include "otx2_cpt_common.h" +#include "cn10k_cpt.h" #define OTX2_CPT_MAX_ENC_KEY_SIZE 32 #define OTX2_CPT_MAX_HASH_KEY_SIZE 64 @@ -123,6 +124,8 @@ struct otx2_cpt_enc_ctx { u8 key_type; u8 enc_align_len; struct crypto_skcipher *fbk_cipher; + struct pci_dev *pdev; + struct cn10k_cpt_errata_ctx er_ctx; }; union otx2_cpt_offset_ctrl { @@ -161,6 +164,8 @@ struct otx2_cpt_aead_ctx { struct crypto_shash *hashalg; struct otx2_cpt_sdesc *sdesc; struct crypto_aead *fbk_cipher; + struct cn10k_cpt_errata_ctx er_ctx; + struct pci_dev *pdev; u8 *ipad; u8 *opad; u32 enc_key_len; diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c b/drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c index bac729c885f960..527d34cc258b45 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c +++ b/drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c @@ -246,11 +246,15 @@ static void cptvf_lf_shutdown(struct otx2_cptlfs_info *lfs) /* Unregister crypto algorithms */ otx2_cpt_crypto_exit(lfs->pdev, THIS_MODULE); /* Unregister LFs interrupts */ - otx2_cptlf_unregister_interrupts(lfs); + otx2_cptlf_unregister_misc_interrupts(lfs); + otx2_cptlf_unregister_done_interrupts(lfs); /* Cleanup LFs software side */ lf_sw_cleanup(lfs); + /* Free instruction queues */ + otx2_cpt_free_instruction_queues(lfs); /* Send request to detach LFs */ otx2_cpt_detach_rsrcs_msg(lfs); + lfs->lfs_num = 0; } static int cptvf_lf_init(struct otx2_cptvf_dev *cptvf) @@ -277,8 +281,7 @@ static int cptvf_lf_init(struct otx2_cptvf_dev *cptvf) if (ret) return ret; - lfs_num = cptvf->lfs.kvf_limits ? cptvf->lfs.kvf_limits : - num_online_cpus(); + lfs_num = cptvf->lfs.kvf_limits; otx2_cptlf_set_dev_info(lfs, cptvf->pdev, cptvf->reg_base, &cptvf->pfvf_mbox, cptvf->blkaddr); @@ -298,7 +301,11 @@ static int cptvf_lf_init(struct otx2_cptvf_dev *cptvf) goto cleanup_lf; /* Register LFs interrupts */ - ret = otx2_cptlf_register_interrupts(lfs); + ret = otx2_cptlf_register_misc_interrupts(lfs); + if (ret) + goto cleanup_lf_sw; + + ret = otx2_cptlf_register_done_interrupts(lfs); if (ret) goto cleanup_lf_sw; @@ -319,7 +326,8 @@ static int cptvf_lf_init(struct otx2_cptvf_dev *cptvf) disable_irqs: otx2_cptlf_free_irqs_affinity(lfs); unregister_intr: - otx2_cptlf_unregister_interrupts(lfs); + otx2_cptlf_unregister_misc_interrupts(lfs); + otx2_cptlf_unregister_done_interrupts(lfs); cleanup_lf_sw: lf_sw_cleanup(lfs); cleanup_lf: @@ -380,6 +388,17 @@ static int otx2_cptvf_probe(struct pci_dev *pdev, goto destroy_pfvf_mbox; cptvf->blkaddr = BLKADDR_CPT0; + + cptvf_hw_ops_get(cptvf); + + ret = otx2_cptvf_send_caps_msg(cptvf); + if (ret) { + dev_err(&pdev->dev, "Couldn't get CPT engine capabilities.\n"); + goto unregister_interrupts; + } + if (cptvf->eng_caps[OTX2_CPT_SE_TYPES] & BIT_ULL(35)) + cptvf->lfs.ops->cpt_sg_info_create = cn10k_sgv2_info_create; + /* Initialize CPT LFs */ ret = cptvf_lf_init(cptvf); if (ret) diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptvf_mbox.c b/drivers/crypto/marvell/octeontx2/otx2_cptvf_mbox.c index 75c403f2b1d985..d9fa5f6e204d2e 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cptvf_mbox.c +++ b/drivers/crypto/marvell/octeontx2/otx2_cptvf_mbox.c @@ -72,6 +72,7 @@ static void process_pfvf_mbox_mbox_msg(struct otx2_cptvf_dev *cptvf, struct otx2_cptlfs_info *lfs = &cptvf->lfs; struct otx2_cpt_kvf_limits_rsp *rsp_limits; struct otx2_cpt_egrp_num_rsp *rsp_grp; + struct otx2_cpt_caps_rsp *eng_caps; struct cpt_rd_wr_reg_msg *rsp_reg; struct msix_offset_rsp *rsp_msix; int i; @@ -127,6 +128,13 @@ static void process_pfvf_mbox_mbox_msg(struct otx2_cptvf_dev *cptvf, rsp_limits = (struct otx2_cpt_kvf_limits_rsp *) msg; cptvf->lfs.kvf_limits = rsp_limits->kvf_limits; break; + case MBOX_MSG_GET_CAPS: + eng_caps = (struct otx2_cpt_caps_rsp *)msg; + memcpy(cptvf->eng_caps, eng_caps->eng_caps, + sizeof(cptvf->eng_caps)); + break; + case MBOX_MSG_CPT_LF_RESET: + break; default: dev_err(&cptvf->pdev->dev, "Unsupported msg %d received.\n", msg->id); @@ -205,3 +213,23 @@ int otx2_cptvf_send_kvf_limits_msg(struct otx2_cptvf_dev *cptvf) return otx2_cpt_send_mbox_msg(mbox, pdev); } + +int otx2_cptvf_send_caps_msg(struct otx2_cptvf_dev *cptvf) +{ + struct otx2_mbox *mbox = &cptvf->pfvf_mbox; + struct pci_dev *pdev = cptvf->pdev; + struct mbox_msghdr *req; + + req = (struct mbox_msghdr *) + otx2_mbox_alloc_msg_rsp(mbox, 0, sizeof(*req), + sizeof(struct otx2_cpt_caps_rsp)); + if (!req) { + dev_err(&pdev->dev, "RVU MBOX failed to get message.\n"); + return -EFAULT; + } + req->id = MBOX_MSG_GET_CAPS; + req->sig = OTX2_MBOX_REQ_SIG; + req->pcifunc = OTX2_CPT_RVU_PFFUNC(cptvf->vf_id, 0); + + return otx2_cpt_send_mbox_msg(mbox, pdev); +} diff --git a/drivers/crypto/marvell/octeontx2/otx2_cptvf_reqmgr.c b/drivers/crypto/marvell/octeontx2/otx2_cptvf_reqmgr.c index 811ded72ce5fbd..5387c68f3c9df1 100644 --- a/drivers/crypto/marvell/octeontx2/otx2_cptvf_reqmgr.c +++ b/drivers/crypto/marvell/octeontx2/otx2_cptvf_reqmgr.c @@ -4,9 +4,6 @@ #include "otx2_cptvf.h" #include "otx2_cpt_common.h" -/* SG list header size in bytes */ -#define SG_LIST_HDR_SIZE 8 - /* Default timeout when waiting for free pending entry in us */ #define CPT_PENTRY_TIMEOUT 1000 #define CPT_PENTRY_STEP 50 @@ -26,9 +23,9 @@ static void otx2_cpt_dump_sg_list(struct pci_dev *pdev, pr_debug("Gather list size %d\n", req->in_cnt); for (i = 0; i < req->in_cnt; i++) { - pr_debug("Buffer %d size %d, vptr 0x%p, dmaptr 0x%p\n", i, + pr_debug("Buffer %d size %d, vptr 0x%p, dmaptr 0x%llx\n", i, req->in[i].size, req->in[i].vptr, - (void *) req->in[i].dma_addr); + req->in[i].dma_addr); pr_debug("Buffer hexdump (%d bytes)\n", req->in[i].size); print_hex_dump_debug("", DUMP_PREFIX_NONE, 16, 1, @@ -36,9 +33,9 @@ static void otx2_cpt_dump_sg_list(struct pci_dev *pdev, } pr_debug("Scatter list size %d\n", req->out_cnt); for (i = 0; i < req->out_cnt; i++) { - pr_debug("Buffer %d size %d, vptr 0x%p, dmaptr 0x%p\n", i, + pr_debug("Buffer %d size %d, vptr 0x%p, dmaptr 0x%llx\n", i, req->out[i].size, req->out[i].vptr, - (void *) req->out[i].dma_addr); + req->out[i].dma_addr); pr_debug("Buffer hexdump (%d bytes)\n", req->out[i].size); print_hex_dump_debug("", DUMP_PREFIX_NONE, 16, 1, req->out[i].vptr, req->out[i].size, false); @@ -84,149 +81,6 @@ static inline void free_pentry(struct otx2_cpt_pending_entry *pentry) pentry->busy = false; } -static inline int setup_sgio_components(struct pci_dev *pdev, - struct otx2_cpt_buf_ptr *list, - int buf_count, u8 *buffer) -{ - struct otx2_cpt_sglist_component *sg_ptr = NULL; - int ret = 0, i, j; - int components; - - if (unlikely(!list)) { - dev_err(&pdev->dev, "Input list pointer is NULL\n"); - return -EFAULT; - } - - for (i = 0; i < buf_count; i++) { - if (unlikely(!list[i].vptr)) - continue; - list[i].dma_addr = dma_map_single(&pdev->dev, list[i].vptr, - list[i].size, - DMA_BIDIRECTIONAL); - if (unlikely(dma_mapping_error(&pdev->dev, list[i].dma_addr))) { - dev_err(&pdev->dev, "Dma mapping failed\n"); - ret = -EIO; - goto sg_cleanup; - } - } - components = buf_count / 4; - sg_ptr = (struct otx2_cpt_sglist_component *)buffer; - for (i = 0; i < components; i++) { - sg_ptr->len0 = cpu_to_be16(list[i * 4 + 0].size); - sg_ptr->len1 = cpu_to_be16(list[i * 4 + 1].size); - sg_ptr->len2 = cpu_to_be16(list[i * 4 + 2].size); - sg_ptr->len3 = cpu_to_be16(list[i * 4 + 3].size); - sg_ptr->ptr0 = cpu_to_be64(list[i * 4 + 0].dma_addr); - sg_ptr->ptr1 = cpu_to_be64(list[i * 4 + 1].dma_addr); - sg_ptr->ptr2 = cpu_to_be64(list[i * 4 + 2].dma_addr); - sg_ptr->ptr3 = cpu_to_be64(list[i * 4 + 3].dma_addr); - sg_ptr++; - } - components = buf_count % 4; - - switch (components) { - case 3: - sg_ptr->len2 = cpu_to_be16(list[i * 4 + 2].size); - sg_ptr->ptr2 = cpu_to_be64(list[i * 4 + 2].dma_addr); - fallthrough; - case 2: - sg_ptr->len1 = cpu_to_be16(list[i * 4 + 1].size); - sg_ptr->ptr1 = cpu_to_be64(list[i * 4 + 1].dma_addr); - fallthrough; - case 1: - sg_ptr->len0 = cpu_to_be16(list[i * 4 + 0].size); - sg_ptr->ptr0 = cpu_to_be64(list[i * 4 + 0].dma_addr); - break; - default: - break; - } - return ret; - -sg_cleanup: - for (j = 0; j < i; j++) { - if (list[j].dma_addr) { - dma_unmap_single(&pdev->dev, list[j].dma_addr, - list[j].size, DMA_BIDIRECTIONAL); - } - - list[j].dma_addr = 0; - } - return ret; -} - -static inline struct otx2_cpt_inst_info *info_create(struct pci_dev *pdev, - struct otx2_cpt_req_info *req, - gfp_t gfp) -{ - int align = OTX2_CPT_DMA_MINALIGN; - struct otx2_cpt_inst_info *info; - u32 dlen, align_dlen, info_len; - u16 g_sz_bytes, s_sz_bytes; - u32 total_mem_len; - - if (unlikely(req->in_cnt > OTX2_CPT_MAX_SG_IN_CNT || - req->out_cnt > OTX2_CPT_MAX_SG_OUT_CNT)) { - dev_err(&pdev->dev, "Error too many sg components\n"); - return NULL; - } - - g_sz_bytes = ((req->in_cnt + 3) / 4) * - sizeof(struct otx2_cpt_sglist_component); - s_sz_bytes = ((req->out_cnt + 3) / 4) * - sizeof(struct otx2_cpt_sglist_component); - - dlen = g_sz_bytes + s_sz_bytes + SG_LIST_HDR_SIZE; - align_dlen = ALIGN(dlen, align); - info_len = ALIGN(sizeof(*info), align); - total_mem_len = align_dlen + info_len + sizeof(union otx2_cpt_res_s); - - info = kzalloc(total_mem_len, gfp); - if (unlikely(!info)) - return NULL; - - info->dlen = dlen; - info->in_buffer = (u8 *)info + info_len; - - ((u16 *)info->in_buffer)[0] = req->out_cnt; - ((u16 *)info->in_buffer)[1] = req->in_cnt; - ((u16 *)info->in_buffer)[2] = 0; - ((u16 *)info->in_buffer)[3] = 0; - cpu_to_be64s((u64 *)info->in_buffer); - - /* Setup gather (input) components */ - if (setup_sgio_components(pdev, req->in, req->in_cnt, - &info->in_buffer[8])) { - dev_err(&pdev->dev, "Failed to setup gather list\n"); - goto destroy_info; - } - - if (setup_sgio_components(pdev, req->out, req->out_cnt, - &info->in_buffer[8 + g_sz_bytes])) { - dev_err(&pdev->dev, "Failed to setup scatter list\n"); - goto destroy_info; - } - - info->dma_len = total_mem_len - info_len; - info->dptr_baddr = dma_map_single(&pdev->dev, info->in_buffer, - info->dma_len, DMA_BIDIRECTIONAL); - if (unlikely(dma_mapping_error(&pdev->dev, info->dptr_baddr))) { - dev_err(&pdev->dev, "DMA Mapping failed for cpt req\n"); - goto destroy_info; - } - /* - * Get buffer for union otx2_cpt_res_s response - * structure and its physical address - */ - info->completion_addr = info->in_buffer + align_dlen; - info->comp_baddr = info->dptr_baddr + align_dlen; - - return info; - -destroy_info: - otx2_cpt_info_destroy(pdev, info); - return NULL; -} - static int process_request(struct pci_dev *pdev, struct otx2_cpt_req_info *req, struct otx2_cpt_pending_queue *pqueue, struct otx2_cptlf_info *lf) @@ -247,7 +101,7 @@ static int process_request(struct pci_dev *pdev, struct otx2_cpt_req_info *req, if (unlikely(!otx2_cptlf_started(lf->lfs))) return -ENODEV; - info = info_create(pdev, req, gfp); + info = lf->lfs->ops->cpt_sg_info_create(pdev, req, gfp); if (unlikely(!info)) { dev_err(&pdev->dev, "Setting up cpt inst info failed"); return -ENOMEM; @@ -303,9 +157,9 @@ static int process_request(struct pci_dev *pdev, struct otx2_cpt_req_info *req, /* 64-bit swap for microcode data reads, not needed for addresses*/ cpu_to_be64s(&iq_cmd.cmd.u); - iq_cmd.dptr = info->dptr_baddr; - iq_cmd.rptr = 0; - iq_cmd.cptr.u = 0; + iq_cmd.dptr = info->dptr_baddr | info->gthr_sz << 60; + iq_cmd.rptr = info->rptr_baddr | info->sctr_sz << 60; + iq_cmd.cptr.s.cptr = cpt_req->cptr_dma; iq_cmd.cptr.s.grp = ctrl->s.grp; /* Fill in the CPT_INST_S type command for HW interpretation */ diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c index caea98622c3362..7a3083debc2bb6 100644 --- a/drivers/crypto/n2_core.c +++ b/drivers/crypto/n2_core.c @@ -1121,19 +1121,6 @@ static const struct n2_skcipher_tmpl skcipher_tmpls[] = { .decrypt = n2_decrypt_chaining, }, }, - { .name = "cfb(des)", - .drv_name = "cfb-des", - .block_size = DES_BLOCK_SIZE, - .enc_type = (ENC_TYPE_ALG_DES | - ENC_TYPE_CHAINING_CFB), - .skcipher = { - .min_keysize = DES_KEY_SIZE, - .max_keysize = DES_KEY_SIZE, - .setkey = n2_des_setkey, - .encrypt = n2_encrypt_chaining, - .decrypt = n2_decrypt_chaining, - }, - }, /* 3DES: ECB CBC and CFB are supported */ { .name = "ecb(des3_ede)", @@ -1163,19 +1150,7 @@ static const struct n2_skcipher_tmpl skcipher_tmpls[] = { .decrypt = n2_decrypt_chaining, }, }, - { .name = "cfb(des3_ede)", - .drv_name = "cfb-3des", - .block_size = DES_BLOCK_SIZE, - .enc_type = (ENC_TYPE_ALG_3DES | - ENC_TYPE_CHAINING_CFB), - .skcipher = { - .min_keysize = 3 * DES_KEY_SIZE, - .max_keysize = 3 * DES_KEY_SIZE, - .setkey = n2_3des_setkey, - .encrypt = n2_encrypt_chaining, - .decrypt = n2_decrypt_chaining, - }, - }, + /* AES: ECB CBC and CTR are supported */ { .name = "ecb(aes)", .drv_name = "ecb-aes", @@ -1382,8 +1357,12 @@ static int __n2_register_one_hmac(struct n2_ahash_alg *n2ahash) ahash->setkey = n2_hmac_async_setkey; base = &ahash->halg.base; - snprintf(base->cra_name, CRYPTO_MAX_ALG_NAME, "hmac(%s)", p->child_alg); - snprintf(base->cra_driver_name, CRYPTO_MAX_ALG_NAME, "hmac-%s-n2", p->child_alg); + if (snprintf(base->cra_name, CRYPTO_MAX_ALG_NAME, "hmac(%s)", + p->child_alg) >= CRYPTO_MAX_ALG_NAME) + goto out_free_p; + if (snprintf(base->cra_driver_name, CRYPTO_MAX_ALG_NAME, "hmac-%s-n2", + p->child_alg) >= CRYPTO_MAX_ALG_NAME) + goto out_free_p; base->cra_ctxsize = sizeof(struct n2_hmac_ctx); base->cra_init = n2_hmac_cra_init; @@ -1394,6 +1373,7 @@ static int __n2_register_one_hmac(struct n2_ahash_alg *n2ahash) if (err) { pr_err("%s alg registration failed\n", base->cra_name); list_del(&p->derived.entry); +out_free_p: kfree(p); } else { pr_info("%s alg registered\n", base->cra_name); diff --git a/drivers/crypto/rockchip/rk3288_crypto_skcipher.c b/drivers/crypto/rockchip/rk3288_crypto_skcipher.c index da95747d973f0e..9393e10671c248 100644 --- a/drivers/crypto/rockchip/rk3288_crypto_skcipher.c +++ b/drivers/crypto/rockchip/rk3288_crypto_skcipher.c @@ -445,8 +445,8 @@ static int rk_cipher_tfm_init(struct crypto_skcipher *tfm) return PTR_ERR(ctx->fallback_tfm); } - tfm->reqsize = sizeof(struct rk_cipher_rctx) + - crypto_skcipher_reqsize(ctx->fallback_tfm); + crypto_skcipher_set_reqsize(tfm, sizeof(struct rk_cipher_rctx) + + crypto_skcipher_reqsize(ctx->fallback_tfm)); return 0; } diff --git a/drivers/crypto/sa2ul.c b/drivers/crypto/sa2ul.c index 6846a84295745e..78a4930c648090 100644 --- a/drivers/crypto/sa2ul.c +++ b/drivers/crypto/sa2ul.c @@ -1869,9 +1869,8 @@ static int sa_aead_setkey(struct crypto_aead *authenc, crypto_aead_set_flags(ctx->fallback.aead, crypto_aead_get_flags(authenc) & CRYPTO_TFM_REQ_MASK); - crypto_aead_setkey(ctx->fallback.aead, key, keylen); - return 0; + return crypto_aead_setkey(ctx->fallback.aead, key, keylen); } static int sa_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize) diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c index 02065131c3008c..3423b5cde1c7c3 100644 --- a/drivers/crypto/sahara.c +++ b/drivers/crypto/sahara.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -24,106 +25,101 @@ #include #include #include -#include #include #include #include #include -#define SHA_BUFFER_LEN PAGE_SIZE -#define SAHARA_MAX_SHA_BLOCK_SIZE SHA256_BLOCK_SIZE - -#define SAHARA_NAME "sahara" -#define SAHARA_VERSION_3 3 -#define SAHARA_VERSION_4 4 -#define SAHARA_TIMEOUT_MS 1000 -#define SAHARA_MAX_HW_DESC 2 -#define SAHARA_MAX_HW_LINK 20 - -#define FLAGS_MODE_MASK 0x000f -#define FLAGS_ENCRYPT BIT(0) -#define FLAGS_CBC BIT(1) -#define FLAGS_NEW_KEY BIT(3) - -#define SAHARA_HDR_BASE 0x00800000 -#define SAHARA_HDR_SKHA_ALG_AES 0 -#define SAHARA_HDR_SKHA_OP_ENC (1 << 2) -#define SAHARA_HDR_SKHA_MODE_ECB (0 << 3) -#define SAHARA_HDR_SKHA_MODE_CBC (1 << 3) -#define SAHARA_HDR_FORM_DATA (5 << 16) -#define SAHARA_HDR_FORM_KEY (8 << 16) -#define SAHARA_HDR_LLO (1 << 24) -#define SAHARA_HDR_CHA_SKHA (1 << 28) -#define SAHARA_HDR_CHA_MDHA (2 << 28) -#define SAHARA_HDR_PARITY_BIT (1 << 31) - -#define SAHARA_HDR_MDHA_SET_MODE_MD_KEY 0x20880000 -#define SAHARA_HDR_MDHA_SET_MODE_HASH 0x208D0000 -#define SAHARA_HDR_MDHA_HASH 0xA0850000 -#define SAHARA_HDR_MDHA_STORE_DIGEST 0x20820000 -#define SAHARA_HDR_MDHA_ALG_SHA1 0 -#define SAHARA_HDR_MDHA_ALG_MD5 1 -#define SAHARA_HDR_MDHA_ALG_SHA256 2 -#define SAHARA_HDR_MDHA_ALG_SHA224 3 -#define SAHARA_HDR_MDHA_PDATA (1 << 2) -#define SAHARA_HDR_MDHA_HMAC (1 << 3) -#define SAHARA_HDR_MDHA_INIT (1 << 5) -#define SAHARA_HDR_MDHA_IPAD (1 << 6) -#define SAHARA_HDR_MDHA_OPAD (1 << 7) -#define SAHARA_HDR_MDHA_SWAP (1 << 8) -#define SAHARA_HDR_MDHA_MAC_FULL (1 << 9) -#define SAHARA_HDR_MDHA_SSL (1 << 10) - -/* SAHARA can only process one request at a time */ -#define SAHARA_QUEUE_LENGTH 1 - -#define SAHARA_REG_VERSION 0x00 -#define SAHARA_REG_DAR 0x04 -#define SAHARA_REG_CONTROL 0x08 -#define SAHARA_CONTROL_SET_THROTTLE(x) (((x) & 0xff) << 24) -#define SAHARA_CONTROL_SET_MAXBURST(x) (((x) & 0xff) << 16) -#define SAHARA_CONTROL_RNG_AUTORSD (1 << 7) -#define SAHARA_CONTROL_ENABLE_INT (1 << 4) -#define SAHARA_REG_CMD 0x0C -#define SAHARA_CMD_RESET (1 << 0) -#define SAHARA_CMD_CLEAR_INT (1 << 8) -#define SAHARA_CMD_CLEAR_ERR (1 << 9) -#define SAHARA_CMD_SINGLE_STEP (1 << 10) -#define SAHARA_CMD_MODE_BATCH (1 << 16) -#define SAHARA_CMD_MODE_DEBUG (1 << 18) -#define SAHARA_REG_STATUS 0x10 -#define SAHARA_STATUS_GET_STATE(x) ((x) & 0x7) -#define SAHARA_STATE_IDLE 0 -#define SAHARA_STATE_BUSY 1 -#define SAHARA_STATE_ERR 2 -#define SAHARA_STATE_FAULT 3 -#define SAHARA_STATE_COMPLETE 4 -#define SAHARA_STATE_COMP_FLAG (1 << 2) -#define SAHARA_STATUS_DAR_FULL (1 << 3) -#define SAHARA_STATUS_ERROR (1 << 4) -#define SAHARA_STATUS_SECURE (1 << 5) -#define SAHARA_STATUS_FAIL (1 << 6) -#define SAHARA_STATUS_INIT (1 << 7) -#define SAHARA_STATUS_RNG_RESEED (1 << 8) -#define SAHARA_STATUS_ACTIVE_RNG (1 << 9) -#define SAHARA_STATUS_ACTIVE_MDHA (1 << 10) -#define SAHARA_STATUS_ACTIVE_SKHA (1 << 11) -#define SAHARA_STATUS_MODE_BATCH (1 << 16) -#define SAHARA_STATUS_MODE_DEDICATED (1 << 17) -#define SAHARA_STATUS_MODE_DEBUG (1 << 18) -#define SAHARA_STATUS_GET_ISTATE(x) (((x) >> 24) & 0xff) -#define SAHARA_REG_ERRSTATUS 0x14 -#define SAHARA_ERRSTATUS_GET_SOURCE(x) ((x) & 0xf) -#define SAHARA_ERRSOURCE_CHA 14 -#define SAHARA_ERRSOURCE_DMA 15 -#define SAHARA_ERRSTATUS_DMA_DIR (1 << 8) -#define SAHARA_ERRSTATUS_GET_DMASZ(x)(((x) >> 9) & 0x3) -#define SAHARA_ERRSTATUS_GET_DMASRC(x) (((x) >> 13) & 0x7) -#define SAHARA_ERRSTATUS_GET_CHASRC(x) (((x) >> 16) & 0xfff) -#define SAHARA_ERRSTATUS_GET_CHAERR(x) (((x) >> 28) & 0x3) -#define SAHARA_REG_FADDR 0x18 -#define SAHARA_REG_CDAR 0x1C -#define SAHARA_REG_IDAR 0x20 +#define SHA_BUFFER_LEN PAGE_SIZE +#define SAHARA_MAX_SHA_BLOCK_SIZE SHA256_BLOCK_SIZE + +#define SAHARA_NAME "sahara" +#define SAHARA_VERSION_3 3 +#define SAHARA_VERSION_4 4 +#define SAHARA_TIMEOUT_MS 1000 +#define SAHARA_MAX_HW_DESC 2 +#define SAHARA_MAX_HW_LINK 20 + +#define FLAGS_MODE_MASK 0x000f +#define FLAGS_ENCRYPT BIT(0) +#define FLAGS_CBC BIT(1) + +#define SAHARA_HDR_BASE 0x00800000 +#define SAHARA_HDR_SKHA_ALG_AES 0 +#define SAHARA_HDR_SKHA_MODE_ECB 0 +#define SAHARA_HDR_SKHA_OP_ENC BIT(2) +#define SAHARA_HDR_SKHA_MODE_CBC BIT(3) +#define SAHARA_HDR_FORM_DATA (5 << 16) +#define SAHARA_HDR_FORM_KEY BIT(19) +#define SAHARA_HDR_LLO BIT(24) +#define SAHARA_HDR_CHA_SKHA BIT(28) +#define SAHARA_HDR_CHA_MDHA BIT(29) +#define SAHARA_HDR_PARITY_BIT BIT(31) + +#define SAHARA_HDR_MDHA_SET_MODE_MD_KEY 0x20880000 +#define SAHARA_HDR_MDHA_SET_MODE_HASH 0x208D0000 +#define SAHARA_HDR_MDHA_HASH 0xA0850000 +#define SAHARA_HDR_MDHA_STORE_DIGEST 0x20820000 +#define SAHARA_HDR_MDHA_ALG_SHA1 0 +#define SAHARA_HDR_MDHA_ALG_MD5 1 +#define SAHARA_HDR_MDHA_ALG_SHA256 2 +#define SAHARA_HDR_MDHA_ALG_SHA224 3 +#define SAHARA_HDR_MDHA_PDATA BIT(2) +#define SAHARA_HDR_MDHA_HMAC BIT(3) +#define SAHARA_HDR_MDHA_INIT BIT(5) +#define SAHARA_HDR_MDHA_IPAD BIT(6) +#define SAHARA_HDR_MDHA_OPAD BIT(7) +#define SAHARA_HDR_MDHA_SWAP BIT(8) +#define SAHARA_HDR_MDHA_MAC_FULL BIT(9) +#define SAHARA_HDR_MDHA_SSL BIT(10) + +#define SAHARA_REG_VERSION 0x00 +#define SAHARA_REG_DAR 0x04 +#define SAHARA_REG_CONTROL 0x08 +#define SAHARA_CONTROL_SET_THROTTLE(x) (((x) & 0xff) << 24) +#define SAHARA_CONTROL_SET_MAXBURST(x) (((x) & 0xff) << 16) +#define SAHARA_CONTROL_RNG_AUTORSD BIT(7) +#define SAHARA_CONTROL_ENABLE_INT BIT(4) +#define SAHARA_REG_CMD 0x0C +#define SAHARA_CMD_RESET BIT(0) +#define SAHARA_CMD_CLEAR_INT BIT(8) +#define SAHARA_CMD_CLEAR_ERR BIT(9) +#define SAHARA_CMD_SINGLE_STEP BIT(10) +#define SAHARA_CMD_MODE_BATCH BIT(16) +#define SAHARA_CMD_MODE_DEBUG BIT(18) +#define SAHARA_REG_STATUS 0x10 +#define SAHARA_STATUS_GET_STATE(x) ((x) & 0x7) +#define SAHARA_STATE_IDLE 0 +#define SAHARA_STATE_BUSY 1 +#define SAHARA_STATE_ERR 2 +#define SAHARA_STATE_FAULT 3 +#define SAHARA_STATE_COMPLETE 4 +#define SAHARA_STATE_COMP_FLAG BIT(2) +#define SAHARA_STATUS_DAR_FULL BIT(3) +#define SAHARA_STATUS_ERROR BIT(4) +#define SAHARA_STATUS_SECURE BIT(5) +#define SAHARA_STATUS_FAIL BIT(6) +#define SAHARA_STATUS_INIT BIT(7) +#define SAHARA_STATUS_RNG_RESEED BIT(8) +#define SAHARA_STATUS_ACTIVE_RNG BIT(9) +#define SAHARA_STATUS_ACTIVE_MDHA BIT(10) +#define SAHARA_STATUS_ACTIVE_SKHA BIT(11) +#define SAHARA_STATUS_MODE_BATCH BIT(16) +#define SAHARA_STATUS_MODE_DEDICATED BIT(17) +#define SAHARA_STATUS_MODE_DEBUG BIT(18) +#define SAHARA_STATUS_GET_ISTATE(x) (((x) >> 24) & 0xff) +#define SAHARA_REG_ERRSTATUS 0x14 +#define SAHARA_ERRSTATUS_GET_SOURCE(x) ((x) & 0xf) +#define SAHARA_ERRSOURCE_CHA 14 +#define SAHARA_ERRSOURCE_DMA 15 +#define SAHARA_ERRSTATUS_DMA_DIR BIT(8) +#define SAHARA_ERRSTATUS_GET_DMASZ(x) (((x) >> 9) & 0x3) +#define SAHARA_ERRSTATUS_GET_DMASRC(x) (((x) >> 13) & 0x7) +#define SAHARA_ERRSTATUS_GET_CHASRC(x) (((x) >> 16) & 0xfff) +#define SAHARA_ERRSTATUS_GET_CHAERR(x) (((x) >> 28) & 0x3) +#define SAHARA_REG_FADDR 0x18 +#define SAHARA_REG_CDAR 0x1C +#define SAHARA_REG_IDAR 0x20 struct sahara_hw_desc { u32 hdr; @@ -141,8 +137,6 @@ struct sahara_hw_link { }; struct sahara_ctx { - unsigned long flags; - /* AES-specific context */ int keylen; u8 key[AES_KEYSIZE_128]; @@ -151,6 +145,7 @@ struct sahara_ctx { struct sahara_aes_reqctx { unsigned long mode; + u8 iv_out[AES_BLOCK_SIZE]; struct skcipher_request fallback_req; // keep at the end }; @@ -170,7 +165,6 @@ struct sahara_aes_reqctx { * @total: total number of bytes for transfer * @last: is this the last block * @first: is this the first block - * @active: inside a transfer */ struct sahara_sha_reqctx { u8 buf[SAHARA_MAX_SHA_BLOCK_SIZE]; @@ -186,7 +180,6 @@ struct sahara_sha_reqctx { size_t total; unsigned int last; unsigned int first; - unsigned int active; }; struct sahara_dev { @@ -195,12 +188,9 @@ struct sahara_dev { void __iomem *regs_base; struct clk *clk_ipg; struct clk *clk_ahb; - spinlock_t queue_spinlock; - struct task_struct *kthread; struct completion dma_completion; struct sahara_ctx *ctx; - struct crypto_queue queue; unsigned long flags; struct sahara_hw_desc *hw_desc[SAHARA_MAX_HW_DESC]; @@ -224,7 +214,7 @@ struct sahara_dev { struct scatterlist *out_sg; int nb_out_sg; - u32 error; + struct crypto_engine *engine; }; static struct sahara_dev *dev_ptr; @@ -446,27 +436,24 @@ static int sahara_hw_descriptor_create(struct sahara_dev *dev) int ret; int i, j; int idx = 0; + u32 len; - /* Copy new key if necessary */ - if (ctx->flags & FLAGS_NEW_KEY) { - memcpy(dev->key_base, ctx->key, ctx->keylen); - ctx->flags &= ~FLAGS_NEW_KEY; + memcpy(dev->key_base, ctx->key, ctx->keylen); - if (dev->flags & FLAGS_CBC) { - dev->hw_desc[idx]->len1 = AES_BLOCK_SIZE; - dev->hw_desc[idx]->p1 = dev->iv_phys_base; - } else { - dev->hw_desc[idx]->len1 = 0; - dev->hw_desc[idx]->p1 = 0; - } - dev->hw_desc[idx]->len2 = ctx->keylen; - dev->hw_desc[idx]->p2 = dev->key_phys_base; - dev->hw_desc[idx]->next = dev->hw_phys_desc[1]; + if (dev->flags & FLAGS_CBC) { + dev->hw_desc[idx]->len1 = AES_BLOCK_SIZE; + dev->hw_desc[idx]->p1 = dev->iv_phys_base; + } else { + dev->hw_desc[idx]->len1 = 0; + dev->hw_desc[idx]->p1 = 0; + } + dev->hw_desc[idx]->len2 = ctx->keylen; + dev->hw_desc[idx]->p2 = dev->key_phys_base; + dev->hw_desc[idx]->next = dev->hw_phys_desc[1]; + dev->hw_desc[idx]->hdr = sahara_aes_key_hdr(dev); - dev->hw_desc[idx]->hdr = sahara_aes_key_hdr(dev); + idx++; - idx++; - } dev->nb_in_sg = sg_nents_for_len(dev->in_sg, dev->total); if (dev->nb_in_sg < 0) { @@ -488,24 +475,27 @@ static int sahara_hw_descriptor_create(struct sahara_dev *dev) DMA_TO_DEVICE); if (!ret) { dev_err(dev->device, "couldn't map in sg\n"); - goto unmap_in; + return -EINVAL; } + ret = dma_map_sg(dev->device, dev->out_sg, dev->nb_out_sg, DMA_FROM_DEVICE); if (!ret) { dev_err(dev->device, "couldn't map out sg\n"); - goto unmap_out; + goto unmap_in; } /* Create input links */ dev->hw_desc[idx]->p1 = dev->hw_phys_link[0]; sg = dev->in_sg; + len = dev->total; for (i = 0; i < dev->nb_in_sg; i++) { - dev->hw_link[i]->len = sg->length; + dev->hw_link[i]->len = min(len, sg->length); dev->hw_link[i]->p = sg->dma_address; if (i == (dev->nb_in_sg - 1)) { dev->hw_link[i]->next = 0; } else { + len -= min(len, sg->length); dev->hw_link[i]->next = dev->hw_phys_link[i + 1]; sg = sg_next(sg); } @@ -514,12 +504,14 @@ static int sahara_hw_descriptor_create(struct sahara_dev *dev) /* Create output links */ dev->hw_desc[idx]->p2 = dev->hw_phys_link[i]; sg = dev->out_sg; + len = dev->total; for (j = i; j < dev->nb_out_sg + i; j++) { - dev->hw_link[j]->len = sg->length; + dev->hw_link[j]->len = min(len, sg->length); dev->hw_link[j]->p = sg->dma_address; if (j == (dev->nb_out_sg + i - 1)) { dev->hw_link[j]->next = 0; } else { + len -= min(len, sg->length); dev->hw_link[j]->next = dev->hw_phys_link[j + 1]; sg = sg_next(sg); } @@ -538,9 +530,6 @@ static int sahara_hw_descriptor_create(struct sahara_dev *dev) return 0; -unmap_out: - dma_unmap_sg(dev->device, dev->out_sg, dev->nb_out_sg, - DMA_FROM_DEVICE); unmap_in: dma_unmap_sg(dev->device, dev->in_sg, dev->nb_in_sg, DMA_TO_DEVICE); @@ -548,8 +537,24 @@ unmap_in: return -EINVAL; } +static void sahara_aes_cbc_update_iv(struct skcipher_request *req) +{ + struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); + struct sahara_aes_reqctx *rctx = skcipher_request_ctx(req); + unsigned int ivsize = crypto_skcipher_ivsize(skcipher); + + /* Update IV buffer to contain the last ciphertext block */ + if (rctx->mode & FLAGS_ENCRYPT) { + sg_pcopy_to_buffer(req->dst, sg_nents(req->dst), req->iv, + ivsize, req->cryptlen - ivsize); + } else { + memcpy(req->iv, rctx->iv_out, ivsize); + } +} + static int sahara_aes_process(struct skcipher_request *req) { + struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); struct sahara_dev *dev = dev_ptr; struct sahara_ctx *ctx; struct sahara_aes_reqctx *rctx; @@ -571,8 +576,17 @@ static int sahara_aes_process(struct skcipher_request *req) rctx->mode &= FLAGS_MODE_MASK; dev->flags = (dev->flags & ~FLAGS_MODE_MASK) | rctx->mode; - if ((dev->flags & FLAGS_CBC) && req->iv) - memcpy(dev->iv_base, req->iv, AES_KEYSIZE_128); + if ((dev->flags & FLAGS_CBC) && req->iv) { + unsigned int ivsize = crypto_skcipher_ivsize(skcipher); + + memcpy(dev->iv_base, req->iv, ivsize); + + if (!(dev->flags & FLAGS_ENCRYPT)) { + sg_pcopy_to_buffer(req->src, sg_nents(req->src), + rctx->iv_out, ivsize, + req->cryptlen - ivsize); + } + } /* assign new context to device */ dev->ctx = ctx; @@ -585,16 +599,20 @@ static int sahara_aes_process(struct skcipher_request *req) timeout = wait_for_completion_timeout(&dev->dma_completion, msecs_to_jiffies(SAHARA_TIMEOUT_MS)); - if (!timeout) { - dev_err(dev->device, "AES timeout\n"); - return -ETIMEDOUT; - } dma_unmap_sg(dev->device, dev->out_sg, dev->nb_out_sg, DMA_FROM_DEVICE); dma_unmap_sg(dev->device, dev->in_sg, dev->nb_in_sg, DMA_TO_DEVICE); + if (!timeout) { + dev_err(dev->device, "AES timeout\n"); + return -ETIMEDOUT; + } + + if ((dev->flags & FLAGS_CBC) && req->iv) + sahara_aes_cbc_update_iv(req); + return 0; } @@ -608,7 +626,6 @@ static int sahara_aes_setkey(struct crypto_skcipher *tfm, const u8 *key, /* SAHARA only supports 128bit keys */ if (keylen == AES_KEYSIZE_128) { memcpy(ctx->key, key, keylen); - ctx->flags |= FLAGS_NEW_KEY; return 0; } @@ -624,109 +641,67 @@ static int sahara_aes_setkey(struct crypto_skcipher *tfm, const u8 *key, return crypto_skcipher_setkey(ctx->fallback, key, keylen); } +static int sahara_aes_fallback(struct skcipher_request *req, unsigned long mode) +{ + struct sahara_aes_reqctx *rctx = skcipher_request_ctx(req); + struct sahara_ctx *ctx = crypto_skcipher_ctx( + crypto_skcipher_reqtfm(req)); + + skcipher_request_set_tfm(&rctx->fallback_req, ctx->fallback); + skcipher_request_set_callback(&rctx->fallback_req, + req->base.flags, + req->base.complete, + req->base.data); + skcipher_request_set_crypt(&rctx->fallback_req, req->src, + req->dst, req->cryptlen, req->iv); + + if (mode & FLAGS_ENCRYPT) + return crypto_skcipher_encrypt(&rctx->fallback_req); + + return crypto_skcipher_decrypt(&rctx->fallback_req); +} + static int sahara_aes_crypt(struct skcipher_request *req, unsigned long mode) { struct sahara_aes_reqctx *rctx = skcipher_request_ctx(req); + struct sahara_ctx *ctx = crypto_skcipher_ctx( + crypto_skcipher_reqtfm(req)); struct sahara_dev *dev = dev_ptr; - int err = 0; + + if (!req->cryptlen) + return 0; + + if (unlikely(ctx->keylen != AES_KEYSIZE_128)) + return sahara_aes_fallback(req, mode); dev_dbg(dev->device, "nbytes: %d, enc: %d, cbc: %d\n", req->cryptlen, !!(mode & FLAGS_ENCRYPT), !!(mode & FLAGS_CBC)); - if (!IS_ALIGNED(req->cryptlen, AES_BLOCK_SIZE)) { - dev_err(dev->device, - "request size is not exact amount of AES blocks\n"); + if (!IS_ALIGNED(req->cryptlen, AES_BLOCK_SIZE)) return -EINVAL; - } rctx->mode = mode; - spin_lock_bh(&dev->queue_spinlock); - err = crypto_enqueue_request(&dev->queue, &req->base); - spin_unlock_bh(&dev->queue_spinlock); - - wake_up_process(dev->kthread); - - return err; + return crypto_transfer_skcipher_request_to_engine(dev->engine, req); } static int sahara_aes_ecb_encrypt(struct skcipher_request *req) { - struct sahara_aes_reqctx *rctx = skcipher_request_ctx(req); - struct sahara_ctx *ctx = crypto_skcipher_ctx( - crypto_skcipher_reqtfm(req)); - - if (unlikely(ctx->keylen != AES_KEYSIZE_128)) { - skcipher_request_set_tfm(&rctx->fallback_req, ctx->fallback); - skcipher_request_set_callback(&rctx->fallback_req, - req->base.flags, - req->base.complete, - req->base.data); - skcipher_request_set_crypt(&rctx->fallback_req, req->src, - req->dst, req->cryptlen, req->iv); - return crypto_skcipher_encrypt(&rctx->fallback_req); - } - return sahara_aes_crypt(req, FLAGS_ENCRYPT); } static int sahara_aes_ecb_decrypt(struct skcipher_request *req) { - struct sahara_aes_reqctx *rctx = skcipher_request_ctx(req); - struct sahara_ctx *ctx = crypto_skcipher_ctx( - crypto_skcipher_reqtfm(req)); - - if (unlikely(ctx->keylen != AES_KEYSIZE_128)) { - skcipher_request_set_tfm(&rctx->fallback_req, ctx->fallback); - skcipher_request_set_callback(&rctx->fallback_req, - req->base.flags, - req->base.complete, - req->base.data); - skcipher_request_set_crypt(&rctx->fallback_req, req->src, - req->dst, req->cryptlen, req->iv); - return crypto_skcipher_decrypt(&rctx->fallback_req); - } - return sahara_aes_crypt(req, 0); } static int sahara_aes_cbc_encrypt(struct skcipher_request *req) { - struct sahara_aes_reqctx *rctx = skcipher_request_ctx(req); - struct sahara_ctx *ctx = crypto_skcipher_ctx( - crypto_skcipher_reqtfm(req)); - - if (unlikely(ctx->keylen != AES_KEYSIZE_128)) { - skcipher_request_set_tfm(&rctx->fallback_req, ctx->fallback); - skcipher_request_set_callback(&rctx->fallback_req, - req->base.flags, - req->base.complete, - req->base.data); - skcipher_request_set_crypt(&rctx->fallback_req, req->src, - req->dst, req->cryptlen, req->iv); - return crypto_skcipher_encrypt(&rctx->fallback_req); - } - return sahara_aes_crypt(req, FLAGS_ENCRYPT | FLAGS_CBC); } static int sahara_aes_cbc_decrypt(struct skcipher_request *req) { - struct sahara_aes_reqctx *rctx = skcipher_request_ctx(req); - struct sahara_ctx *ctx = crypto_skcipher_ctx( - crypto_skcipher_reqtfm(req)); - - if (unlikely(ctx->keylen != AES_KEYSIZE_128)) { - skcipher_request_set_tfm(&rctx->fallback_req, ctx->fallback); - skcipher_request_set_callback(&rctx->fallback_req, - req->base.flags, - req->base.complete, - req->base.data); - skcipher_request_set_crypt(&rctx->fallback_req, req->src, - req->dst, req->cryptlen, req->iv); - return crypto_skcipher_decrypt(&rctx->fallback_req); - } - return sahara_aes_crypt(req, FLAGS_CBC); } @@ -783,6 +758,7 @@ static int sahara_sha_hw_links_create(struct sahara_dev *dev, int start) { struct scatterlist *sg; + unsigned int len; unsigned int i; int ret; @@ -804,12 +780,14 @@ static int sahara_sha_hw_links_create(struct sahara_dev *dev, if (!ret) return -EFAULT; + len = rctx->total; for (i = start; i < dev->nb_in_sg + start; i++) { - dev->hw_link[i]->len = sg->length; + dev->hw_link[i]->len = min(len, sg->length); dev->hw_link[i]->p = sg->dma_address; if (i == (dev->nb_in_sg + start - 1)) { dev->hw_link[i]->next = 0; } else { + len -= min(len, sg->length); dev->hw_link[i]->next = dev->hw_phys_link[i + 1]; sg = sg_next(sg); } @@ -890,24 +868,6 @@ static int sahara_sha_hw_context_descriptor_create(struct sahara_dev *dev, return 0; } -static int sahara_walk_and_recalc(struct scatterlist *sg, unsigned int nbytes) -{ - if (!sg || !sg->length) - return nbytes; - - while (nbytes && sg) { - if (nbytes <= sg->length) { - sg->length = nbytes; - sg_mark_end(sg); - break; - } - nbytes -= sg->length; - sg = sg_next(sg); - } - - return nbytes; -} - static int sahara_sha_prepare_request(struct ahash_request *req) { struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); @@ -944,36 +904,20 @@ static int sahara_sha_prepare_request(struct ahash_request *req) hash_later, 0); } - /* nbytes should now be multiple of blocksize */ - req->nbytes = req->nbytes - hash_later; - - sahara_walk_and_recalc(req->src, req->nbytes); - + rctx->total = len - hash_later; /* have data from previous operation and current */ if (rctx->buf_cnt && req->nbytes) { sg_init_table(rctx->in_sg_chain, 2); sg_set_buf(rctx->in_sg_chain, rctx->rembuf, rctx->buf_cnt); - sg_chain(rctx->in_sg_chain, 2, req->src); - - rctx->total = req->nbytes + rctx->buf_cnt; rctx->in_sg = rctx->in_sg_chain; - - req->src = rctx->in_sg_chain; /* only data from previous operation */ } else if (rctx->buf_cnt) { - if (req->src) - rctx->in_sg = req->src; - else - rctx->in_sg = rctx->in_sg_chain; - /* buf was copied into rembuf above */ + rctx->in_sg = rctx->in_sg_chain; sg_init_one(rctx->in_sg, rctx->rembuf, rctx->buf_cnt); - rctx->total = rctx->buf_cnt; /* no data from previous operation */ } else { rctx->in_sg = req->src; - rctx->total = req->nbytes; - req->src = rctx->in_sg; } /* on next call, we only have the remaining data in the buffer */ @@ -994,7 +938,10 @@ static int sahara_sha_process(struct ahash_request *req) return ret; if (rctx->first) { - sahara_sha_hw_data_descriptor_create(dev, rctx, req, 0); + ret = sahara_sha_hw_data_descriptor_create(dev, rctx, req, 0); + if (ret) + return ret; + dev->hw_desc[0]->next = 0; rctx->first = 0; } else { @@ -1002,7 +949,10 @@ static int sahara_sha_process(struct ahash_request *req) sahara_sha_hw_context_descriptor_create(dev, rctx, req, 0); dev->hw_desc[0]->next = dev->hw_phys_desc[1]; - sahara_sha_hw_data_descriptor_create(dev, rctx, req, 1); + ret = sahara_sha_hw_data_descriptor_create(dev, rctx, req, 1); + if (ret) + return ret; + dev->hw_desc[1]->next = 0; } @@ -1015,62 +965,44 @@ static int sahara_sha_process(struct ahash_request *req) timeout = wait_for_completion_timeout(&dev->dma_completion, msecs_to_jiffies(SAHARA_TIMEOUT_MS)); - if (!timeout) { - dev_err(dev->device, "SHA timeout\n"); - return -ETIMEDOUT; - } if (rctx->sg_in_idx) dma_unmap_sg(dev->device, dev->in_sg, dev->nb_in_sg, DMA_TO_DEVICE); + if (!timeout) { + dev_err(dev->device, "SHA timeout\n"); + return -ETIMEDOUT; + } + memcpy(rctx->context, dev->context_base, rctx->context_size); - if (req->result) + if (req->result && rctx->last) memcpy(req->result, rctx->context, rctx->digest_size); return 0; } -static int sahara_queue_manage(void *data) +static int sahara_do_one_request(struct crypto_engine *engine, void *areq) { - struct sahara_dev *dev = data; - struct crypto_async_request *async_req; - struct crypto_async_request *backlog; - int ret = 0; - - do { - __set_current_state(TASK_INTERRUPTIBLE); - - spin_lock_bh(&dev->queue_spinlock); - backlog = crypto_get_backlog(&dev->queue); - async_req = crypto_dequeue_request(&dev->queue); - spin_unlock_bh(&dev->queue_spinlock); - - if (backlog) - crypto_request_complete(backlog, -EINPROGRESS); - - if (async_req) { - if (crypto_tfm_alg_type(async_req->tfm) == - CRYPTO_ALG_TYPE_AHASH) { - struct ahash_request *req = - ahash_request_cast(async_req); - - ret = sahara_sha_process(req); - } else { - struct skcipher_request *req = - skcipher_request_cast(async_req); - - ret = sahara_aes_process(req); - } + struct crypto_async_request *async_req = areq; + int err; - crypto_request_complete(async_req, ret); + if (crypto_tfm_alg_type(async_req->tfm) == CRYPTO_ALG_TYPE_AHASH) { + struct ahash_request *req = ahash_request_cast(async_req); - continue; - } + err = sahara_sha_process(req); + local_bh_disable(); + crypto_finalize_hash_request(engine, req, err); + local_bh_enable(); + } else { + struct skcipher_request *req = skcipher_request_cast(async_req); - schedule(); - } while (!kthread_should_stop()); + err = sahara_aes_process(skcipher_request_cast(async_req)); + local_bh_disable(); + crypto_finalize_skcipher_request(engine, req, err); + local_bh_enable(); + } return 0; } @@ -1079,25 +1011,13 @@ static int sahara_sha_enqueue(struct ahash_request *req, int last) { struct sahara_sha_reqctx *rctx = ahash_request_ctx(req); struct sahara_dev *dev = dev_ptr; - int ret; if (!req->nbytes && !last) return 0; rctx->last = last; - if (!rctx->active) { - rctx->active = 1; - rctx->first = 1; - } - - spin_lock_bh(&dev->queue_spinlock); - ret = crypto_enqueue_request(&dev->queue, &req->base); - spin_unlock_bh(&dev->queue_spinlock); - - wake_up_process(dev->kthread); - - return ret; + return crypto_transfer_hash_request_to_engine(dev->engine, req); } static int sahara_sha_init(struct ahash_request *req) @@ -1121,7 +1041,7 @@ static int sahara_sha_init(struct ahash_request *req) } rctx->context_size = rctx->digest_size + 4; - rctx->active = 0; + rctx->first = 1; return 0; } @@ -1170,100 +1090,119 @@ static int sahara_sha_import(struct ahash_request *req, const void *in) static int sahara_sha_cra_init(struct crypto_tfm *tfm) { crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), - sizeof(struct sahara_sha_reqctx) + - SHA_BUFFER_LEN + SHA256_BLOCK_SIZE); + sizeof(struct sahara_sha_reqctx)); return 0; } -static struct skcipher_alg aes_algs[] = { +static struct skcipher_engine_alg aes_algs[] = { { - .base.cra_name = "ecb(aes)", - .base.cra_driver_name = "sahara-ecb-aes", - .base.cra_priority = 300, - .base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, - .base.cra_blocksize = AES_BLOCK_SIZE, - .base.cra_ctxsize = sizeof(struct sahara_ctx), - .base.cra_alignmask = 0x0, - .base.cra_module = THIS_MODULE, - - .init = sahara_aes_init_tfm, - .exit = sahara_aes_exit_tfm, - .min_keysize = AES_MIN_KEY_SIZE , - .max_keysize = AES_MAX_KEY_SIZE, - .setkey = sahara_aes_setkey, - .encrypt = sahara_aes_ecb_encrypt, - .decrypt = sahara_aes_ecb_decrypt, + .base = { + .base.cra_name = "ecb(aes)", + .base.cra_driver_name = "sahara-ecb-aes", + .base.cra_priority = 300, + .base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, + .base.cra_blocksize = AES_BLOCK_SIZE, + .base.cra_ctxsize = sizeof(struct sahara_ctx), + .base.cra_alignmask = 0x0, + .base.cra_module = THIS_MODULE, + + .init = sahara_aes_init_tfm, + .exit = sahara_aes_exit_tfm, + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .setkey = sahara_aes_setkey, + .encrypt = sahara_aes_ecb_encrypt, + .decrypt = sahara_aes_ecb_decrypt, + }, + .op = { + .do_one_request = sahara_do_one_request, + }, }, { - .base.cra_name = "cbc(aes)", - .base.cra_driver_name = "sahara-cbc-aes", - .base.cra_priority = 300, - .base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, - .base.cra_blocksize = AES_BLOCK_SIZE, - .base.cra_ctxsize = sizeof(struct sahara_ctx), - .base.cra_alignmask = 0x0, - .base.cra_module = THIS_MODULE, - - .init = sahara_aes_init_tfm, - .exit = sahara_aes_exit_tfm, - .min_keysize = AES_MIN_KEY_SIZE , - .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_BLOCK_SIZE, - .setkey = sahara_aes_setkey, - .encrypt = sahara_aes_cbc_encrypt, - .decrypt = sahara_aes_cbc_decrypt, + .base = { + .base.cra_name = "cbc(aes)", + .base.cra_driver_name = "sahara-cbc-aes", + .base.cra_priority = 300, + .base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, + .base.cra_blocksize = AES_BLOCK_SIZE, + .base.cra_ctxsize = sizeof(struct sahara_ctx), + .base.cra_alignmask = 0x0, + .base.cra_module = THIS_MODULE, + + .init = sahara_aes_init_tfm, + .exit = sahara_aes_exit_tfm, + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = sahara_aes_setkey, + .encrypt = sahara_aes_cbc_encrypt, + .decrypt = sahara_aes_cbc_decrypt, + }, + .op = { + .do_one_request = sahara_do_one_request, + }, } }; -static struct ahash_alg sha_v3_algs[] = { +static struct ahash_engine_alg sha_v3_algs[] = { { - .init = sahara_sha_init, - .update = sahara_sha_update, - .final = sahara_sha_final, - .finup = sahara_sha_finup, - .digest = sahara_sha_digest, - .export = sahara_sha_export, - .import = sahara_sha_import, - .halg.digestsize = SHA1_DIGEST_SIZE, - .halg.statesize = sizeof(struct sahara_sha_reqctx), - .halg.base = { - .cra_name = "sha1", - .cra_driver_name = "sahara-sha1", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_ASYNC | - CRYPTO_ALG_NEED_FALLBACK, - .cra_blocksize = SHA1_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct sahara_ctx), - .cra_alignmask = 0, - .cra_module = THIS_MODULE, - .cra_init = sahara_sha_cra_init, - } + .base = { + .init = sahara_sha_init, + .update = sahara_sha_update, + .final = sahara_sha_final, + .finup = sahara_sha_finup, + .digest = sahara_sha_digest, + .export = sahara_sha_export, + .import = sahara_sha_import, + .halg.digestsize = SHA1_DIGEST_SIZE, + .halg.statesize = sizeof(struct sahara_sha_reqctx), + .halg.base = { + .cra_name = "sha1", + .cra_driver_name = "sahara-sha1", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_ASYNC | + CRYPTO_ALG_NEED_FALLBACK, + .cra_blocksize = SHA1_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct sahara_ctx), + .cra_alignmask = 0, + .cra_module = THIS_MODULE, + .cra_init = sahara_sha_cra_init, + } + }, + .op = { + .do_one_request = sahara_do_one_request, + }, }, }; -static struct ahash_alg sha_v4_algs[] = { +static struct ahash_engine_alg sha_v4_algs[] = { { - .init = sahara_sha_init, - .update = sahara_sha_update, - .final = sahara_sha_final, - .finup = sahara_sha_finup, - .digest = sahara_sha_digest, - .export = sahara_sha_export, - .import = sahara_sha_import, - .halg.digestsize = SHA256_DIGEST_SIZE, - .halg.statesize = sizeof(struct sahara_sha_reqctx), - .halg.base = { - .cra_name = "sha256", - .cra_driver_name = "sahara-sha256", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_ASYNC | - CRYPTO_ALG_NEED_FALLBACK, - .cra_blocksize = SHA256_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct sahara_ctx), - .cra_alignmask = 0, - .cra_module = THIS_MODULE, - .cra_init = sahara_sha_cra_init, - } + .base = { + .init = sahara_sha_init, + .update = sahara_sha_update, + .final = sahara_sha_final, + .finup = sahara_sha_finup, + .digest = sahara_sha_digest, + .export = sahara_sha_export, + .import = sahara_sha_import, + .halg.digestsize = SHA256_DIGEST_SIZE, + .halg.statesize = sizeof(struct sahara_sha_reqctx), + .halg.base = { + .cra_name = "sha256", + .cra_driver_name = "sahara-sha256", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_ASYNC | + CRYPTO_ALG_NEED_FALLBACK, + .cra_blocksize = SHA256_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct sahara_ctx), + .cra_alignmask = 0, + .cra_module = THIS_MODULE, + .cra_init = sahara_sha_cra_init, + } + }, + .op = { + .do_one_request = sahara_do_one_request, + }, }, }; @@ -1278,14 +1217,11 @@ static irqreturn_t sahara_irq_handler(int irq, void *data) sahara_decode_status(dev, stat); - if (SAHARA_STATUS_GET_STATE(stat) == SAHARA_STATE_BUSY) { + if (SAHARA_STATUS_GET_STATE(stat) == SAHARA_STATE_BUSY) return IRQ_NONE; - } else if (SAHARA_STATUS_GET_STATE(stat) == SAHARA_STATE_COMPLETE) { - dev->error = 0; - } else { + + if (SAHARA_STATUS_GET_STATE(stat) != SAHARA_STATE_COMPLETE) sahara_decode_error(dev, err); - dev->error = -EINVAL; - } complete(&dev->dma_completion); @@ -1296,57 +1232,42 @@ static irqreturn_t sahara_irq_handler(int irq, void *data) static int sahara_register_algs(struct sahara_dev *dev) { int err; - unsigned int i, j, k, l; - for (i = 0; i < ARRAY_SIZE(aes_algs); i++) { - err = crypto_register_skcipher(&aes_algs[i]); - if (err) - goto err_aes_algs; - } + err = crypto_engine_register_skciphers(aes_algs, ARRAY_SIZE(aes_algs)); + if (err) + return err; + + err = crypto_engine_register_ahashes(sha_v3_algs, + ARRAY_SIZE(sha_v3_algs)); + if (err) + goto err_aes_algs; - for (k = 0; k < ARRAY_SIZE(sha_v3_algs); k++) { - err = crypto_register_ahash(&sha_v3_algs[k]); + if (dev->version > SAHARA_VERSION_3) { + err = crypto_engine_register_ahashes(sha_v4_algs, + ARRAY_SIZE(sha_v4_algs)); if (err) goto err_sha_v3_algs; } - if (dev->version > SAHARA_VERSION_3) - for (l = 0; l < ARRAY_SIZE(sha_v4_algs); l++) { - err = crypto_register_ahash(&sha_v4_algs[l]); - if (err) - goto err_sha_v4_algs; - } - return 0; -err_sha_v4_algs: - for (j = 0; j < l; j++) - crypto_unregister_ahash(&sha_v4_algs[j]); - err_sha_v3_algs: - for (j = 0; j < k; j++) - crypto_unregister_ahash(&sha_v3_algs[j]); + crypto_engine_unregister_ahashes(sha_v3_algs, ARRAY_SIZE(sha_v3_algs)); err_aes_algs: - for (j = 0; j < i; j++) - crypto_unregister_skcipher(&aes_algs[j]); + crypto_engine_unregister_skciphers(aes_algs, ARRAY_SIZE(aes_algs)); return err; } static void sahara_unregister_algs(struct sahara_dev *dev) { - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(aes_algs); i++) - crypto_unregister_skcipher(&aes_algs[i]); - - for (i = 0; i < ARRAY_SIZE(sha_v3_algs); i++) - crypto_unregister_ahash(&sha_v3_algs[i]); + crypto_engine_unregister_skciphers(aes_algs, ARRAY_SIZE(aes_algs)); + crypto_engine_unregister_ahashes(sha_v3_algs, ARRAY_SIZE(sha_v3_algs)); if (dev->version > SAHARA_VERSION_3) - for (i = 0; i < ARRAY_SIZE(sha_v4_algs); i++) - crypto_unregister_ahash(&sha_v4_algs[i]); + crypto_engine_unregister_ahashes(sha_v4_algs, + ARRAY_SIZE(sha_v4_algs)); } static const struct of_device_id sahara_dt_ids[] = { @@ -1383,32 +1304,27 @@ static int sahara_probe(struct platform_device *pdev) err = devm_request_irq(&pdev->dev, irq, sahara_irq_handler, 0, dev_name(&pdev->dev), dev); - if (err) { - dev_err(&pdev->dev, "failed to request irq\n"); - return err; - } + if (err) + return dev_err_probe(&pdev->dev, err, + "failed to request irq\n"); /* clocks */ - dev->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); - if (IS_ERR(dev->clk_ipg)) { - dev_err(&pdev->dev, "Could not get ipg clock\n"); - return PTR_ERR(dev->clk_ipg); - } + dev->clk_ipg = devm_clk_get_enabled(&pdev->dev, "ipg"); + if (IS_ERR(dev->clk_ipg)) + return dev_err_probe(&pdev->dev, PTR_ERR(dev->clk_ipg), + "Could not get ipg clock\n"); - dev->clk_ahb = devm_clk_get(&pdev->dev, "ahb"); - if (IS_ERR(dev->clk_ahb)) { - dev_err(&pdev->dev, "Could not get ahb clock\n"); - return PTR_ERR(dev->clk_ahb); - } + dev->clk_ahb = devm_clk_get_enabled(&pdev->dev, "ahb"); + if (IS_ERR(dev->clk_ahb)) + return dev_err_probe(&pdev->dev, PTR_ERR(dev->clk_ahb), + "Could not get ahb clock\n"); /* Allocate HW descriptors */ dev->hw_desc[0] = dmam_alloc_coherent(&pdev->dev, SAHARA_MAX_HW_DESC * sizeof(struct sahara_hw_desc), &dev->hw_phys_desc[0], GFP_KERNEL); - if (!dev->hw_desc[0]) { - dev_err(&pdev->dev, "Could not allocate hw descriptors\n"); + if (!dev->hw_desc[0]) return -ENOMEM; - } dev->hw_desc[1] = dev->hw_desc[0] + 1; dev->hw_phys_desc[1] = dev->hw_phys_desc[0] + sizeof(struct sahara_hw_desc); @@ -1416,10 +1332,8 @@ static int sahara_probe(struct platform_device *pdev) /* Allocate space for iv and key */ dev->key_base = dmam_alloc_coherent(&pdev->dev, 2 * AES_KEYSIZE_128, &dev->key_phys_base, GFP_KERNEL); - if (!dev->key_base) { - dev_err(&pdev->dev, "Could not allocate memory for key\n"); + if (!dev->key_base) return -ENOMEM; - } dev->iv_base = dev->key_base + AES_KEYSIZE_128; dev->iv_phys_base = dev->key_phys_base + AES_KEYSIZE_128; @@ -1427,45 +1341,36 @@ static int sahara_probe(struct platform_device *pdev) dev->context_base = dmam_alloc_coherent(&pdev->dev, SHA256_DIGEST_SIZE + 4, &dev->context_phys_base, GFP_KERNEL); - if (!dev->context_base) { - dev_err(&pdev->dev, "Could not allocate memory for MDHA context\n"); + if (!dev->context_base) return -ENOMEM; - } /* Allocate space for HW links */ dev->hw_link[0] = dmam_alloc_coherent(&pdev->dev, SAHARA_MAX_HW_LINK * sizeof(struct sahara_hw_link), &dev->hw_phys_link[0], GFP_KERNEL); - if (!dev->hw_link[0]) { - dev_err(&pdev->dev, "Could not allocate hw links\n"); + if (!dev->hw_link[0]) return -ENOMEM; - } for (i = 1; i < SAHARA_MAX_HW_LINK; i++) { dev->hw_phys_link[i] = dev->hw_phys_link[i - 1] + sizeof(struct sahara_hw_link); dev->hw_link[i] = dev->hw_link[i - 1] + 1; } - crypto_init_queue(&dev->queue, SAHARA_QUEUE_LENGTH); - - spin_lock_init(&dev->queue_spinlock); - dev_ptr = dev; - dev->kthread = kthread_run(sahara_queue_manage, dev, "sahara_crypto"); - if (IS_ERR(dev->kthread)) { - return PTR_ERR(dev->kthread); + dev->engine = crypto_engine_alloc_init(&pdev->dev, true); + if (!dev->engine) + return -ENOMEM; + + err = crypto_engine_start(dev->engine); + if (err) { + crypto_engine_exit(dev->engine); + return dev_err_probe(&pdev->dev, err, + "Could not start crypto engine\n"); } init_completion(&dev->dma_completion); - err = clk_prepare_enable(dev->clk_ipg); - if (err) - return err; - err = clk_prepare_enable(dev->clk_ahb); - if (err) - goto clk_ipg_disable; - version = sahara_read(dev, SAHARA_REG_VERSION); if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx27-sahara")) { if (version != SAHARA_VERSION_3) @@ -1477,8 +1382,8 @@ static int sahara_probe(struct platform_device *pdev) version = (version >> 8) & 0xff; } if (err == -ENODEV) { - dev_err(&pdev->dev, "SAHARA version %d not supported\n", - version); + dev_err_probe(&pdev->dev, err, + "SAHARA version %d not supported\n", version); goto err_algs; } @@ -1501,11 +1406,7 @@ static int sahara_probe(struct platform_device *pdev) return 0; err_algs: - kthread_stop(dev->kthread); - dev_ptr = NULL; - clk_disable_unprepare(dev->clk_ahb); -clk_ipg_disable: - clk_disable_unprepare(dev->clk_ipg); + crypto_engine_exit(dev->engine); return err; } @@ -1514,14 +1415,8 @@ static void sahara_remove(struct platform_device *pdev) { struct sahara_dev *dev = platform_get_drvdata(pdev); - kthread_stop(dev->kthread); - + crypto_engine_exit(dev->engine); sahara_unregister_algs(dev); - - clk_disable_unprepare(dev->clk_ipg); - clk_disable_unprepare(dev->clk_ahb); - - dev_ptr = NULL; } static struct platform_driver sahara_driver = { diff --git a/drivers/crypto/starfive/Kconfig b/drivers/crypto/starfive/Kconfig index 2cb192502c1b7d..cb59357b58b242 100644 --- a/drivers/crypto/starfive/Kconfig +++ b/drivers/crypto/starfive/Kconfig @@ -4,7 +4,7 @@ config CRYPTO_DEV_JH7110 tristate "StarFive JH7110 cryptographic engine driver" - depends on SOC_STARFIVE || AMBA_PL08X || COMPILE_TEST + depends on (SOC_STARFIVE && AMBA_PL08X) || COMPILE_TEST depends on HAS_DMA select CRYPTO_ENGINE select CRYPTO_HMAC diff --git a/drivers/crypto/starfive/jh7110-aes.c b/drivers/crypto/starfive/jh7110-aes.c index 9378e6682f0e9c..1ac15cc4ef3c18 100644 --- a/drivers/crypto/starfive/jh7110-aes.c +++ b/drivers/crypto/starfive/jh7110-aes.c @@ -262,12 +262,7 @@ static int starfive_aes_hw_init(struct starfive_cryp_ctx *ctx) rctx->csr.aes.mode = hw_mode; rctx->csr.aes.cmode = !is_encrypt(cryp); rctx->csr.aes.ie = 1; - - if (hw_mode == STARFIVE_AES_MODE_CFB || - hw_mode == STARFIVE_AES_MODE_OFB) - rctx->csr.aes.stmode = STARFIVE_AES_MODE_XFB_128; - else - rctx->csr.aes.stmode = STARFIVE_AES_MODE_XFB_1; + rctx->csr.aes.stmode = STARFIVE_AES_MODE_XFB_1; if (cryp->side_chan) { rctx->csr.aes.delay_aes = 1; @@ -294,8 +289,6 @@ static int starfive_aes_hw_init(struct starfive_cryp_ctx *ctx) starfive_aes_ccm_init(ctx); starfive_aes_aead_hw_start(ctx, hw_mode); break; - case STARFIVE_AES_MODE_OFB: - case STARFIVE_AES_MODE_CFB: case STARFIVE_AES_MODE_CBC: case STARFIVE_AES_MODE_CTR: starfive_aes_write_iv(ctx, (void *)cryp->req.sreq->iv); @@ -500,7 +493,7 @@ static int starfive_aes_prepare_req(struct skcipher_request *req, scatterwalk_start(&cryp->out_walk, rctx->out_sg); if (cryp->assoclen) { - rctx->adata = kzalloc(ALIGN(cryp->assoclen, AES_BLOCK_SIZE), GFP_KERNEL); + rctx->adata = kzalloc(cryp->assoclen + AES_BLOCK_SIZE, GFP_KERNEL); if (!rctx->adata) return dev_err_probe(cryp->dev, -ENOMEM, "Failed to alloc memory for adata"); @@ -569,7 +562,7 @@ static int starfive_aes_aead_do_one_req(struct crypto_engine *engine, void *areq struct starfive_cryp_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req)); struct starfive_cryp_dev *cryp = ctx->cryp; - struct starfive_cryp_request_ctx *rctx = ctx->rctx; + struct starfive_cryp_request_ctx *rctx; u32 block[AES_BLOCK_32]; u32 stat; int err; @@ -579,6 +572,8 @@ static int starfive_aes_aead_do_one_req(struct crypto_engine *engine, void *areq if (err) return err; + rctx = ctx->rctx; + if (!cryp->assoclen) goto write_text; @@ -783,26 +778,6 @@ static int starfive_aes_cbc_decrypt(struct skcipher_request *req) return starfive_aes_crypt(req, STARFIVE_AES_MODE_CBC); } -static int starfive_aes_cfb_encrypt(struct skcipher_request *req) -{ - return starfive_aes_crypt(req, STARFIVE_AES_MODE_CFB | FLG_ENCRYPT); -} - -static int starfive_aes_cfb_decrypt(struct skcipher_request *req) -{ - return starfive_aes_crypt(req, STARFIVE_AES_MODE_CFB); -} - -static int starfive_aes_ofb_encrypt(struct skcipher_request *req) -{ - return starfive_aes_crypt(req, STARFIVE_AES_MODE_OFB | FLG_ENCRYPT); -} - -static int starfive_aes_ofb_decrypt(struct skcipher_request *req) -{ - return starfive_aes_crypt(req, STARFIVE_AES_MODE_OFB); -} - static int starfive_aes_ctr_encrypt(struct skcipher_request *req) { return starfive_aes_crypt(req, STARFIVE_AES_MODE_CTR | FLG_ENCRYPT); @@ -908,48 +883,6 @@ static struct skcipher_engine_alg skcipher_algs[] = { .op = { .do_one_request = starfive_aes_do_one_req, }, -}, { - .base.init = starfive_aes_init_tfm, - .base.setkey = starfive_aes_setkey, - .base.encrypt = starfive_aes_cfb_encrypt, - .base.decrypt = starfive_aes_cfb_decrypt, - .base.min_keysize = AES_MIN_KEY_SIZE, - .base.max_keysize = AES_MAX_KEY_SIZE, - .base.ivsize = AES_BLOCK_SIZE, - .base.base = { - .cra_name = "cfb(aes)", - .cra_driver_name = "starfive-cfb-aes", - .cra_priority = 200, - .cra_flags = CRYPTO_ALG_ASYNC, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct starfive_cryp_ctx), - .cra_alignmask = 0xf, - .cra_module = THIS_MODULE, - }, - .op = { - .do_one_request = starfive_aes_do_one_req, - }, -}, { - .base.init = starfive_aes_init_tfm, - .base.setkey = starfive_aes_setkey, - .base.encrypt = starfive_aes_ofb_encrypt, - .base.decrypt = starfive_aes_ofb_decrypt, - .base.min_keysize = AES_MIN_KEY_SIZE, - .base.max_keysize = AES_MAX_KEY_SIZE, - .base.ivsize = AES_BLOCK_SIZE, - .base.base = { - .cra_name = "ofb(aes)", - .cra_driver_name = "starfive-ofb-aes", - .cra_priority = 200, - .cra_flags = CRYPTO_ALG_ASYNC, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct starfive_cryp_ctx), - .cra_alignmask = 0xf, - .cra_module = THIS_MODULE, - }, - .op = { - .do_one_request = starfive_aes_do_one_req, - }, }, }; diff --git a/drivers/crypto/starfive/jh7110-cryp.c b/drivers/crypto/starfive/jh7110-cryp.c index 08e974e0dd1247..425fddf3a8abcb 100644 --- a/drivers/crypto/starfive/jh7110-cryp.c +++ b/drivers/crypto/starfive/jh7110-cryp.c @@ -109,12 +109,6 @@ static irqreturn_t starfive_cryp_irq(int irq, void *priv) tasklet_schedule(&cryp->hash_done); } - if (status & STARFIVE_IE_FLAG_PKA_DONE) { - mask |= STARFIVE_IE_MASK_PKA_DONE; - writel(mask, cryp->base + STARFIVE_IE_MASK_OFFSET); - complete(&cryp->pka_done); - } - return IRQ_HANDLED; } @@ -159,8 +153,6 @@ static int starfive_cryp_probe(struct platform_device *pdev) return dev_err_probe(&pdev->dev, PTR_ERR(cryp->rst), "Error getting hardware reset line\n"); - init_completion(&cryp->pka_done); - irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; @@ -168,7 +160,7 @@ static int starfive_cryp_probe(struct platform_device *pdev) ret = devm_request_irq(&pdev->dev, irq, starfive_cryp_irq, 0, pdev->name, (void *)cryp); if (ret) - return dev_err_probe(&pdev->dev, irq, + return dev_err_probe(&pdev->dev, ret, "Failed to register interrupt handler\n"); clk_prepare_enable(cryp->hclk); @@ -180,12 +172,8 @@ static int starfive_cryp_probe(struct platform_device *pdev) spin_unlock(&dev_list.lock); ret = starfive_dma_init(cryp); - if (ret) { - if (ret == -EPROBE_DEFER) - goto err_probe_defer; - else - goto err_dma_init; - } + if (ret) + goto err_dma_init; /* Initialize crypto engine */ cryp->engine = crypto_engine_alloc_init(&pdev->dev, 1); @@ -233,7 +221,7 @@ err_dma_init: tasklet_kill(&cryp->aes_done); tasklet_kill(&cryp->hash_done); -err_probe_defer: + return ret; } diff --git a/drivers/crypto/starfive/jh7110-cryp.h b/drivers/crypto/starfive/jh7110-cryp.h index fe011d50473d76..6cdf6db5d90486 100644 --- a/drivers/crypto/starfive/jh7110-cryp.h +++ b/drivers/crypto/starfive/jh7110-cryp.h @@ -50,8 +50,6 @@ union starfive_aes_csr { u32 ccm_start :1; #define STARFIVE_AES_MODE_ECB 0x0 #define STARFIVE_AES_MODE_CBC 0x1 -#define STARFIVE_AES_MODE_CFB 0x2 -#define STARFIVE_AES_MODE_OFB 0x3 #define STARFIVE_AES_MODE_CTR 0x4 #define STARFIVE_AES_MODE_CCM 0x5 #define STARFIVE_AES_MODE_GCM 0x6 @@ -125,6 +123,15 @@ union starfive_pka_cacr { }; }; +union starfive_pka_casr { + u32 v; + struct { +#define STARFIVE_PKA_DONE BIT(0) + u32 done :1; + u32 rsvd_0 :31; + }; +}; + struct starfive_rsa_key { u8 *n; u8 *e; @@ -183,7 +190,6 @@ struct starfive_cryp_dev { struct crypto_engine *engine; struct tasklet_struct aes_done; struct tasklet_struct hash_done; - struct completion pka_done; size_t assoclen; size_t total_in; size_t total_out; diff --git a/drivers/crypto/starfive/jh7110-rsa.c b/drivers/crypto/starfive/jh7110-rsa.c index f31bbd825f883f..cf8bda7f0855d9 100644 --- a/drivers/crypto/starfive/jh7110-rsa.c +++ b/drivers/crypto/starfive/jh7110-rsa.c @@ -6,13 +6,7 @@ */ #include -#include -#include -#include -#include #include -#include -#include #include #include #include @@ -28,13 +22,13 @@ #define STARFIVE_PKA_CAER_OFFSET (STARFIVE_PKA_REGS_OFFSET + 0x108) #define STARFIVE_PKA_CANR_OFFSET (STARFIVE_PKA_REGS_OFFSET + 0x208) -// R^2 mod N and N0' +/* R ^ 2 mod N and N0' */ #define CRYPTO_CMD_PRE 0x0 -// A * R mod N ==> A +/* A * R mod N ==> A */ #define CRYPTO_CMD_ARN 0x5 -// A * E * R mod N ==> A +/* A * E * R mod N ==> A */ #define CRYPTO_CMD_AERN 0x6 -// A * A * R mod N ==> A +/* A * A * R mod N ==> A */ #define CRYPTO_CMD_AARN 0x7 #define STARFIVE_RSA_MAX_KEYSZ 256 @@ -43,31 +37,17 @@ static inline int starfive_pka_wait_done(struct starfive_cryp_ctx *ctx) { struct starfive_cryp_dev *cryp = ctx->cryp; + u32 status; - return wait_for_completion_timeout(&cryp->pka_done, - usecs_to_jiffies(100000)); -} - -static inline void starfive_pka_irq_mask_clear(struct starfive_cryp_ctx *ctx) -{ - struct starfive_cryp_dev *cryp = ctx->cryp; - u32 stat; - - stat = readl(cryp->base + STARFIVE_IE_MASK_OFFSET); - stat &= ~STARFIVE_IE_MASK_PKA_DONE; - writel(stat, cryp->base + STARFIVE_IE_MASK_OFFSET); - - reinit_completion(&cryp->pka_done); + return readl_relaxed_poll_timeout(cryp->base + STARFIVE_PKA_CASR_OFFSET, status, + status & STARFIVE_PKA_DONE, 10, 100000); } static void starfive_rsa_free_key(struct starfive_rsa_key *key) { - if (key->d) - kfree_sensitive(key->d); - if (key->e) - kfree_sensitive(key->e); - if (key->n) - kfree_sensitive(key->n); + kfree_sensitive(key->d); + kfree_sensitive(key->e); + kfree_sensitive(key->n); memset(key, 0, sizeof(*key)); } @@ -114,10 +94,9 @@ static int starfive_rsa_montgomery_form(struct starfive_cryp_ctx *ctx, rctx->csr.pka.not_r2 = 1; rctx->csr.pka.ie = 1; - starfive_pka_irq_mask_clear(ctx); writel(rctx->csr.pka.v, cryp->base + STARFIVE_PKA_CACR_OFFSET); - if (!starfive_pka_wait_done(ctx)) + if (starfive_pka_wait_done(ctx)) return -ETIMEDOUT; for (loop = 0; loop <= opsize; loop++) @@ -136,10 +115,9 @@ static int starfive_rsa_montgomery_form(struct starfive_cryp_ctx *ctx, rctx->csr.pka.start = 1; rctx->csr.pka.ie = 1; - starfive_pka_irq_mask_clear(ctx); writel(rctx->csr.pka.v, cryp->base + STARFIVE_PKA_CACR_OFFSET); - if (!starfive_pka_wait_done(ctx)) + if (starfive_pka_wait_done(ctx)) return -ETIMEDOUT; } else { rctx->csr.pka.v = 0; @@ -151,10 +129,9 @@ static int starfive_rsa_montgomery_form(struct starfive_cryp_ctx *ctx, rctx->csr.pka.pre_expf = 1; rctx->csr.pka.ie = 1; - starfive_pka_irq_mask_clear(ctx); writel(rctx->csr.pka.v, cryp->base + STARFIVE_PKA_CACR_OFFSET); - if (!starfive_pka_wait_done(ctx)) + if (starfive_pka_wait_done(ctx)) return -ETIMEDOUT; for (loop = 0; loop <= count; loop++) @@ -172,10 +149,9 @@ static int starfive_rsa_montgomery_form(struct starfive_cryp_ctx *ctx, rctx->csr.pka.start = 1; rctx->csr.pka.ie = 1; - starfive_pka_irq_mask_clear(ctx); writel(rctx->csr.pka.v, cryp->base + STARFIVE_PKA_CACR_OFFSET); - if (!starfive_pka_wait_done(ctx)) + if (starfive_pka_wait_done(ctx)) return -ETIMEDOUT; } @@ -226,11 +202,10 @@ static int starfive_rsa_cpu_start(struct starfive_cryp_ctx *ctx, u32 *result, rctx->csr.pka.start = 1; rctx->csr.pka.ie = 1; - starfive_pka_irq_mask_clear(ctx); writel(rctx->csr.pka.v, cryp->base + STARFIVE_PKA_CACR_OFFSET); ret = -ETIMEDOUT; - if (!starfive_pka_wait_done(ctx)) + if (starfive_pka_wait_done(ctx)) goto rsa_err; if (mlen) { @@ -242,10 +217,9 @@ static int starfive_rsa_cpu_start(struct starfive_cryp_ctx *ctx, u32 *result, rctx->csr.pka.start = 1; rctx->csr.pka.ie = 1; - starfive_pka_irq_mask_clear(ctx); writel(rctx->csr.pka.v, cryp->base + STARFIVE_PKA_CACR_OFFSET); - if (!starfive_pka_wait_done(ctx)) + if (starfive_pka_wait_done(ctx)) goto rsa_err; } } diff --git a/drivers/crypto/stm32/stm32-crc32.c b/drivers/crypto/stm32/stm32-crc32.c index b2d5c8921ab36c..b0cf6d2fd352ff 100644 --- a/drivers/crypto/stm32/stm32-crc32.c +++ b/drivers/crypto/stm32/stm32-crc32.c @@ -104,7 +104,7 @@ static struct stm32_crc *stm32_crc_get_next_crc(void) struct stm32_crc *crc; spin_lock_bh(&crc_list.lock); - crc = list_first_entry(&crc_list.dev_list, struct stm32_crc, list); + crc = list_first_entry_or_null(&crc_list.dev_list, struct stm32_crc, list); if (crc) list_move_tail(&crc->list, &crc_list.dev_list); spin_unlock_bh(&crc_list.lock); diff --git a/drivers/crypto/stm32/stm32-cryp.c b/drivers/crypto/stm32/stm32-cryp.c index c3cbc2673338d2..11ad4ffdce0d49 100644 --- a/drivers/crypto/stm32/stm32-cryp.c +++ b/drivers/crypto/stm32/stm32-cryp.c @@ -838,7 +838,7 @@ static int stm32_cryp_aead_one_req(struct crypto_engine *engine, void *areq); static int stm32_cryp_aes_aead_init(struct crypto_aead *tfm) { - tfm->reqsize = sizeof(struct stm32_cryp_reqctx); + crypto_aead_set_reqsize(tfm, sizeof(struct stm32_cryp_reqctx)); return 0; } diff --git a/drivers/crypto/virtio/virtio_crypto_common.h b/drivers/crypto/virtio/virtio_crypto_common.h index 154590e1f7643d..7059bbe5a2ebaa 100644 --- a/drivers/crypto/virtio/virtio_crypto_common.h +++ b/drivers/crypto/virtio/virtio_crypto_common.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,7 @@ struct data_queue { char name[32]; struct crypto_engine *engine; + struct tasklet_struct done_task; }; struct virtio_crypto { diff --git a/drivers/crypto/virtio/virtio_crypto_core.c b/drivers/crypto/virtio/virtio_crypto_core.c index 43a0838d31ff01..b909c6a2bf1c34 100644 --- a/drivers/crypto/virtio/virtio_crypto_core.c +++ b/drivers/crypto/virtio/virtio_crypto_core.c @@ -72,27 +72,28 @@ int virtio_crypto_ctrl_vq_request(struct virtio_crypto *vcrypto, struct scatterl return 0; } -static void virtcrypto_dataq_callback(struct virtqueue *vq) +static void virtcrypto_done_task(unsigned long data) { - struct virtio_crypto *vcrypto = vq->vdev->priv; + struct data_queue *data_vq = (struct data_queue *)data; + struct virtqueue *vq = data_vq->vq; struct virtio_crypto_request *vc_req; - unsigned long flags; unsigned int len; - unsigned int qid = vq->index; - spin_lock_irqsave(&vcrypto->data_vq[qid].lock, flags); do { virtqueue_disable_cb(vq); while ((vc_req = virtqueue_get_buf(vq, &len)) != NULL) { - spin_unlock_irqrestore( - &vcrypto->data_vq[qid].lock, flags); if (vc_req->alg_cb) vc_req->alg_cb(vc_req, len); - spin_lock_irqsave( - &vcrypto->data_vq[qid].lock, flags); } } while (!virtqueue_enable_cb(vq)); - spin_unlock_irqrestore(&vcrypto->data_vq[qid].lock, flags); +} + +static void virtcrypto_dataq_callback(struct virtqueue *vq) +{ + struct virtio_crypto *vcrypto = vq->vdev->priv; + struct data_queue *dq = &vcrypto->data_vq[vq->index]; + + tasklet_schedule(&dq->done_task); } static int virtcrypto_find_vqs(struct virtio_crypto *vi) @@ -150,6 +151,8 @@ static int virtcrypto_find_vqs(struct virtio_crypto *vi) ret = -ENOMEM; goto err_engine; } + tasklet_init(&vi->data_vq[i].done_task, virtcrypto_done_task, + (unsigned long)&vi->data_vq[i]); } kfree(names); @@ -497,12 +500,15 @@ static void virtcrypto_free_unused_reqs(struct virtio_crypto *vcrypto) static void virtcrypto_remove(struct virtio_device *vdev) { struct virtio_crypto *vcrypto = vdev->priv; + int i; dev_info(&vdev->dev, "Start virtcrypto_remove.\n"); flush_work(&vcrypto->config_work); if (virtcrypto_dev_started(vcrypto)) virtcrypto_dev_stop(vcrypto); + for (i = 0; i < vcrypto->max_data_queues; i++) + tasklet_kill(&vcrypto->data_vq[i].done_task); virtio_reset_device(vdev); virtcrypto_free_unused_reqs(vcrypto); virtcrypto_clear_crypto_engines(vcrypto); diff --git a/drivers/cxl/Kconfig b/drivers/cxl/Kconfig index 8ea1d340e43850..67998dbd1d46b4 100644 --- a/drivers/cxl/Kconfig +++ b/drivers/cxl/Kconfig @@ -5,6 +5,7 @@ menuconfig CXL_BUS select FW_LOADER select FW_UPLOAD select PCI_DOE + select FIRMWARE_TABLE help CXL is a bus that is electrically compatible with PCI Express, but layers three protocols on that signalling (CXL.io, CXL.cache, and @@ -54,8 +55,10 @@ config CXL_MEM_RAW_COMMANDS config CXL_ACPI tristate "CXL ACPI: Platform Support" depends on ACPI + depends on ACPI_NUMA default CXL_BUS select ACPI_TABLE_LIB + select ACPI_HMAT help Enable support for host managed device memory (HDM) resources published by a platform's ACPI CXL memory layout description. See diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c index 2034eb4ce83fb7..dcf2b39e104882 100644 --- a/drivers/cxl/acpi.c +++ b/drivers/cxl/acpi.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include "cxlpci.h" #include "cxl.h" @@ -17,6 +18,10 @@ struct cxl_cxims_data { u64 xormaps[] __counted_by(nr_maps); }; +static const guid_t acpi_cxl_qtg_id_guid = + GUID_INIT(0xF365F9A6, 0xA7DE, 0x4071, + 0xA6, 0x6A, 0xB4, 0x0C, 0x0B, 0x4F, 0x8E, 0x52); + /* * Find a targets entry (n) in the host bridge interleave list. * CXL Specification 3.0 Table 9-22 @@ -194,6 +199,123 @@ struct cxl_cfmws_context { int id; }; +/** + * cxl_acpi_evaluate_qtg_dsm - Retrieve QTG ids via ACPI _DSM + * @handle: ACPI handle + * @coord: performance access coordinates + * @entries: number of QTG IDs to return + * @qos_class: int array provided by caller to return QTG IDs + * + * Return: number of QTG IDs returned, or -errno for errors + * + * Issue QTG _DSM with accompanied bandwidth and latency data in order to get + * the QTG IDs that are suitable for the performance point in order of most + * suitable to least suitable. Write back array of QTG IDs and return the + * actual number of QTG IDs written back. + */ +static int +cxl_acpi_evaluate_qtg_dsm(acpi_handle handle, struct access_coordinate *coord, + int entries, int *qos_class) +{ + union acpi_object *out_obj, *out_buf, *obj; + union acpi_object in_array[4] = { + [0].integer = { ACPI_TYPE_INTEGER, coord->read_latency }, + [1].integer = { ACPI_TYPE_INTEGER, coord->write_latency }, + [2].integer = { ACPI_TYPE_INTEGER, coord->read_bandwidth }, + [3].integer = { ACPI_TYPE_INTEGER, coord->write_bandwidth }, + }; + union acpi_object in_obj = { + .package = { + .type = ACPI_TYPE_PACKAGE, + .count = 4, + .elements = in_array, + }, + }; + int count, pkg_entries, i; + u16 max_qtg; + int rc; + + if (!entries) + return -EINVAL; + + out_obj = acpi_evaluate_dsm(handle, &acpi_cxl_qtg_id_guid, 1, 1, &in_obj); + if (!out_obj) + return -ENXIO; + + if (out_obj->type != ACPI_TYPE_PACKAGE) { + rc = -ENXIO; + goto out; + } + + /* Check Max QTG ID */ + obj = &out_obj->package.elements[0]; + if (obj->type != ACPI_TYPE_INTEGER) { + rc = -ENXIO; + goto out; + } + + max_qtg = obj->integer.value; + + /* It's legal to have 0 QTG entries */ + pkg_entries = out_obj->package.count; + if (pkg_entries <= 1) { + rc = 0; + goto out; + } + + /* Retrieve QTG IDs package */ + obj = &out_obj->package.elements[1]; + if (obj->type != ACPI_TYPE_PACKAGE) { + rc = -ENXIO; + goto out; + } + + pkg_entries = obj->package.count; + count = min(entries, pkg_entries); + for (i = 0; i < count; i++) { + u16 qtg_id; + + out_buf = &obj->package.elements[i]; + if (out_buf->type != ACPI_TYPE_INTEGER) { + rc = -ENXIO; + goto out; + } + + qtg_id = out_buf->integer.value; + if (qtg_id > max_qtg) + pr_warn("QTG ID %u greater than MAX %u\n", + qtg_id, max_qtg); + + qos_class[i] = qtg_id; + } + rc = count; + +out: + ACPI_FREE(out_obj); + return rc; +} + +static int cxl_acpi_qos_class(struct cxl_root *cxl_root, + struct access_coordinate *coord, int entries, + int *qos_class) +{ + struct device *dev = cxl_root->port.uport_dev; + acpi_handle handle; + + if (!dev_is_platform(dev)) + return -ENODEV; + + handle = ACPI_HANDLE(dev); + if (!handle) + return -ENODEV; + + return cxl_acpi_evaluate_qtg_dsm(handle, coord, entries, qos_class); +} + +static const struct cxl_root_ops acpi_root_ops = { + .qos_class = cxl_acpi_qos_class, +}; + static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg, const unsigned long end) { @@ -389,8 +511,29 @@ static int cxl_get_chbs(struct device *dev, struct acpi_device *hb, return 0; } +static int get_genport_coordinates(struct device *dev, struct cxl_dport *dport) +{ + struct acpi_device *hb = to_cxl_host_bridge(NULL, dev); + u32 uid; + int rc; + + if (kstrtou32(acpi_device_uid(hb), 0, &uid)) + return -EINVAL; + + rc = acpi_get_genport_coordinates(uid, &dport->hb_coord); + if (rc < 0) + return rc; + + /* Adjust back to picoseconds from nanoseconds */ + dport->hb_coord.read_latency *= 1000; + dport->hb_coord.write_latency *= 1000; + + return 0; +} + static int add_host_bridge_dport(struct device *match, void *arg) { + int ret; acpi_status rc; struct device *bridge; struct cxl_dport *dport; @@ -440,6 +583,10 @@ static int add_host_bridge_dport(struct device *match, void *arg) if (IS_ERR(dport)) return PTR_ERR(dport); + ret = get_genport_coordinates(match, dport); + if (ret) + dev_dbg(match, "Failed to get generic port perf coordinates.\n"); + return 0; } @@ -656,6 +803,7 @@ static int cxl_acpi_probe(struct platform_device *pdev) { int rc; struct resource *cxl_res; + struct cxl_root *cxl_root; struct cxl_port *root_port; struct device *host = &pdev->dev; struct acpi_device *adev = ACPI_COMPANION(host); @@ -675,9 +823,10 @@ static int cxl_acpi_probe(struct platform_device *pdev) cxl_res->end = -1; cxl_res->flags = IORESOURCE_MEM; - root_port = devm_cxl_add_port(host, host, CXL_RESOURCE_NONE, NULL); - if (IS_ERR(root_port)) - return PTR_ERR(root_port); + cxl_root = devm_cxl_add_root(host, &acpi_root_ops); + if (IS_ERR(cxl_root)) + return PTR_ERR(cxl_root); + root_port = &cxl_root->port; rc = bus_for_each_dev(adev->dev.bus, NULL, root_port, add_host_bridge_dport); diff --git a/drivers/cxl/core/Makefile b/drivers/cxl/core/Makefile index 1f66b5d4d93556..9259bcc6773c80 100644 --- a/drivers/cxl/core/Makefile +++ b/drivers/cxl/core/Makefile @@ -13,5 +13,6 @@ cxl_core-y += mbox.o cxl_core-y += pci.o cxl_core-y += hdm.o cxl_core-y += pmu.o +cxl_core-y += cdat.o cxl_core-$(CONFIG_TRACING) += trace.o cxl_core-$(CONFIG_CXL_REGION) += region.o diff --git a/drivers/cxl/core/cdat.c b/drivers/cxl/core/cdat.c new file mode 100644 index 00000000000000..6fe11546889fab --- /dev/null +++ b/drivers/cxl/core/cdat.c @@ -0,0 +1,521 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright(c) 2023 Intel Corporation. All rights reserved. */ +#include +#include +#include +#include +#include +#include "cxlpci.h" +#include "cxlmem.h" +#include "core.h" +#include "cxl.h" + +struct dsmas_entry { + struct range dpa_range; + u8 handle; + struct access_coordinate coord; + + int entries; + int qos_class; +}; + +static int cdat_dsmas_handler(union acpi_subtable_headers *header, void *arg, + const unsigned long end) +{ + struct acpi_cdat_header *hdr = &header->cdat; + struct acpi_cdat_dsmas *dsmas; + int size = sizeof(*hdr) + sizeof(*dsmas); + struct xarray *dsmas_xa = arg; + struct dsmas_entry *dent; + u16 len; + int rc; + + len = le16_to_cpu((__force __le16)hdr->length); + if (len != size || (unsigned long)hdr + len > end) { + pr_warn("Malformed DSMAS table length: (%u:%u)\n", size, len); + return -EINVAL; + } + + /* Skip common header */ + dsmas = (struct acpi_cdat_dsmas *)(hdr + 1); + + dent = kzalloc(sizeof(*dent), GFP_KERNEL); + if (!dent) + return -ENOMEM; + + dent->handle = dsmas->dsmad_handle; + dent->dpa_range.start = le64_to_cpu((__force __le64)dsmas->dpa_base_address); + dent->dpa_range.end = le64_to_cpu((__force __le64)dsmas->dpa_base_address) + + le64_to_cpu((__force __le64)dsmas->dpa_length) - 1; + + rc = xa_insert(dsmas_xa, dent->handle, dent, GFP_KERNEL); + if (rc) { + kfree(dent); + return rc; + } + + return 0; +} + +static void cxl_access_coordinate_set(struct access_coordinate *coord, + int access, unsigned int val) +{ + switch (access) { + case ACPI_HMAT_ACCESS_LATENCY: + coord->read_latency = val; + coord->write_latency = val; + break; + case ACPI_HMAT_READ_LATENCY: + coord->read_latency = val; + break; + case ACPI_HMAT_WRITE_LATENCY: + coord->write_latency = val; + break; + case ACPI_HMAT_ACCESS_BANDWIDTH: + coord->read_bandwidth = val; + coord->write_bandwidth = val; + break; + case ACPI_HMAT_READ_BANDWIDTH: + coord->read_bandwidth = val; + break; + case ACPI_HMAT_WRITE_BANDWIDTH: + coord->write_bandwidth = val; + break; + } +} + +static int cdat_dslbis_handler(union acpi_subtable_headers *header, void *arg, + const unsigned long end) +{ + struct acpi_cdat_header *hdr = &header->cdat; + struct acpi_cdat_dslbis *dslbis; + int size = sizeof(*hdr) + sizeof(*dslbis); + struct xarray *dsmas_xa = arg; + struct dsmas_entry *dent; + __le64 le_base; + __le16 le_val; + u64 val; + u16 len; + int rc; + + len = le16_to_cpu((__force __le16)hdr->length); + if (len != size || (unsigned long)hdr + len > end) { + pr_warn("Malformed DSLBIS table length: (%u:%u)\n", size, len); + return -EINVAL; + } + + /* Skip common header */ + dslbis = (struct acpi_cdat_dslbis *)(hdr + 1); + + /* Skip unrecognized data type */ + if (dslbis->data_type > ACPI_HMAT_WRITE_BANDWIDTH) + return 0; + + /* Not a memory type, skip */ + if ((dslbis->flags & ACPI_HMAT_MEMORY_HIERARCHY) != ACPI_HMAT_MEMORY) + return 0; + + dent = xa_load(dsmas_xa, dslbis->handle); + if (!dent) { + pr_warn("No matching DSMAS entry for DSLBIS entry.\n"); + return 0; + } + + le_base = (__force __le64)dslbis->entry_base_unit; + le_val = (__force __le16)dslbis->entry[0]; + rc = check_mul_overflow(le64_to_cpu(le_base), + le16_to_cpu(le_val), &val); + if (rc) + pr_warn("DSLBIS value overflowed.\n"); + + cxl_access_coordinate_set(&dent->coord, dslbis->data_type, val); + + return 0; +} + +static int cdat_table_parse_output(int rc) +{ + if (rc < 0) + return rc; + if (rc == 0) + return -ENOENT; + + return 0; +} + +static int cxl_cdat_endpoint_process(struct cxl_port *port, + struct xarray *dsmas_xa) +{ + int rc; + + rc = cdat_table_parse(ACPI_CDAT_TYPE_DSMAS, cdat_dsmas_handler, + dsmas_xa, port->cdat.table); + rc = cdat_table_parse_output(rc); + if (rc) + return rc; + + rc = cdat_table_parse(ACPI_CDAT_TYPE_DSLBIS, cdat_dslbis_handler, + dsmas_xa, port->cdat.table); + return cdat_table_parse_output(rc); +} + +static int cxl_port_perf_data_calculate(struct cxl_port *port, + struct xarray *dsmas_xa) +{ + struct access_coordinate c; + struct dsmas_entry *dent; + int valid_entries = 0; + unsigned long index; + int rc; + + rc = cxl_endpoint_get_perf_coordinates(port, &c); + if (rc) { + dev_dbg(&port->dev, "Failed to retrieve perf coordinates.\n"); + return rc; + } + + struct cxl_root *cxl_root __free(put_cxl_root) = find_cxl_root(port); + + if (!cxl_root) + return -ENODEV; + + if (!cxl_root->ops || !cxl_root->ops->qos_class) + return -EOPNOTSUPP; + + xa_for_each(dsmas_xa, index, dent) { + int qos_class; + + dent->coord.read_latency = dent->coord.read_latency + + c.read_latency; + dent->coord.write_latency = dent->coord.write_latency + + c.write_latency; + dent->coord.read_bandwidth = min_t(int, c.read_bandwidth, + dent->coord.read_bandwidth); + dent->coord.write_bandwidth = min_t(int, c.write_bandwidth, + dent->coord.write_bandwidth); + + dent->entries = 1; + rc = cxl_root->ops->qos_class(cxl_root, &dent->coord, 1, + &qos_class); + if (rc != 1) + continue; + + valid_entries++; + dent->qos_class = qos_class; + } + + if (!valid_entries) + return -ENOENT; + + return 0; +} + +static void add_perf_entry(struct device *dev, struct dsmas_entry *dent, + struct list_head *list) +{ + struct cxl_dpa_perf *dpa_perf; + + dpa_perf = kzalloc(sizeof(*dpa_perf), GFP_KERNEL); + if (!dpa_perf) + return; + + dpa_perf->dpa_range = dent->dpa_range; + dpa_perf->coord = dent->coord; + dpa_perf->qos_class = dent->qos_class; + list_add_tail(&dpa_perf->list, list); + dev_dbg(dev, + "DSMAS: dpa: %#llx qos: %d read_bw: %d write_bw %d read_lat: %d write_lat: %d\n", + dent->dpa_range.start, dpa_perf->qos_class, + dent->coord.read_bandwidth, dent->coord.write_bandwidth, + dent->coord.read_latency, dent->coord.write_latency); +} + +static void free_perf_ents(void *data) +{ + struct cxl_memdev_state *mds = data; + struct cxl_dpa_perf *dpa_perf, *n; + LIST_HEAD(discard); + + list_splice_tail_init(&mds->ram_perf_list, &discard); + list_splice_tail_init(&mds->pmem_perf_list, &discard); + list_for_each_entry_safe(dpa_perf, n, &discard, list) { + list_del(&dpa_perf->list); + kfree(dpa_perf); + } +} + +static void cxl_memdev_set_qos_class(struct cxl_dev_state *cxlds, + struct xarray *dsmas_xa) +{ + struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds); + struct device *dev = cxlds->dev; + struct range pmem_range = { + .start = cxlds->pmem_res.start, + .end = cxlds->pmem_res.end, + }; + struct range ram_range = { + .start = cxlds->ram_res.start, + .end = cxlds->ram_res.end, + }; + struct dsmas_entry *dent; + unsigned long index; + + xa_for_each(dsmas_xa, index, dent) { + if (resource_size(&cxlds->ram_res) && + range_contains(&ram_range, &dent->dpa_range)) + add_perf_entry(dev, dent, &mds->ram_perf_list); + else if (resource_size(&cxlds->pmem_res) && + range_contains(&pmem_range, &dent->dpa_range)) + add_perf_entry(dev, dent, &mds->pmem_perf_list); + else + dev_dbg(dev, "no partition for dsmas dpa: %#llx\n", + dent->dpa_range.start); + } + + devm_add_action_or_reset(&cxlds->cxlmd->dev, free_perf_ents, mds); +} + +static int match_cxlrd_qos_class(struct device *dev, void *data) +{ + int dev_qos_class = *(int *)data; + struct cxl_root_decoder *cxlrd; + + if (!is_root_decoder(dev)) + return 0; + + cxlrd = to_cxl_root_decoder(dev); + if (cxlrd->qos_class == CXL_QOS_CLASS_INVALID) + return 0; + + if (cxlrd->qos_class == dev_qos_class) + return 1; + + return 0; +} + +static void cxl_qos_match(struct cxl_port *root_port, + struct list_head *work_list, + struct list_head *discard_list) +{ + struct cxl_dpa_perf *dpa_perf, *n; + + list_for_each_entry_safe(dpa_perf, n, work_list, list) { + int rc; + + if (dpa_perf->qos_class == CXL_QOS_CLASS_INVALID) + return; + + rc = device_for_each_child(&root_port->dev, + (void *)&dpa_perf->qos_class, + match_cxlrd_qos_class); + if (!rc) + list_move_tail(&dpa_perf->list, discard_list); + } +} + +static int match_cxlrd_hb(struct device *dev, void *data) +{ + struct device *host_bridge = data; + struct cxl_switch_decoder *cxlsd; + struct cxl_root_decoder *cxlrd; + + if (!is_root_decoder(dev)) + return 0; + + cxlrd = to_cxl_root_decoder(dev); + cxlsd = &cxlrd->cxlsd; + + guard(rwsem_read)(&cxl_region_rwsem); + for (int i = 0; i < cxlsd->nr_targets; i++) { + if (host_bridge == cxlsd->target[i]->dport_dev) + return 1; + } + + return 0; +} + +static void discard_dpa_perf(struct list_head *list) +{ + struct cxl_dpa_perf *dpa_perf, *n; + + list_for_each_entry_safe(dpa_perf, n, list, list) { + list_del(&dpa_perf->list); + kfree(dpa_perf); + } +} +DEFINE_FREE(dpa_perf, struct list_head *, if (!list_empty(_T)) discard_dpa_perf(_T)) + +static int cxl_qos_class_verify(struct cxl_memdev *cxlmd) +{ + struct cxl_dev_state *cxlds = cxlmd->cxlds; + struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds); + LIST_HEAD(__discard); + struct list_head *discard __free(dpa_perf) = &__discard; + struct cxl_port *root_port; + int rc; + + struct cxl_root *cxl_root __free(put_cxl_root) = + find_cxl_root(cxlmd->endpoint); + + if (!cxl_root) + return -ENODEV; + + root_port = &cxl_root->port; + + /* Check that the QTG IDs are all sane between end device and root decoders */ + cxl_qos_match(root_port, &mds->ram_perf_list, discard); + cxl_qos_match(root_port, &mds->pmem_perf_list, discard); + + /* Check to make sure that the device's host bridge is under a root decoder */ + rc = device_for_each_child(&root_port->dev, + (void *)cxlmd->endpoint->host_bridge, + match_cxlrd_hb); + if (!rc) { + list_splice_tail_init(&mds->ram_perf_list, discard); + list_splice_tail_init(&mds->pmem_perf_list, discard); + } + + return rc; +} + +static void discard_dsmas(struct xarray *xa) +{ + unsigned long index; + void *ent; + + xa_for_each(xa, index, ent) { + xa_erase(xa, index); + kfree(ent); + } + xa_destroy(xa); +} +DEFINE_FREE(dsmas, struct xarray *, if (_T) discard_dsmas(_T)) + +void cxl_endpoint_parse_cdat(struct cxl_port *port) +{ + struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport_dev); + struct cxl_dev_state *cxlds = cxlmd->cxlds; + struct xarray __dsmas_xa; + struct xarray *dsmas_xa __free(dsmas) = &__dsmas_xa; + int rc; + + xa_init(&__dsmas_xa); + if (!port->cdat.table) + return; + + rc = cxl_cdat_endpoint_process(port, dsmas_xa); + if (rc < 0) { + dev_dbg(&port->dev, "Failed to parse CDAT: %d\n", rc); + return; + } + + rc = cxl_port_perf_data_calculate(port, dsmas_xa); + if (rc) { + dev_dbg(&port->dev, "Failed to do perf coord calculations.\n"); + return; + } + + cxl_memdev_set_qos_class(cxlds, dsmas_xa); + cxl_qos_class_verify(cxlmd); +} +EXPORT_SYMBOL_NS_GPL(cxl_endpoint_parse_cdat, CXL); + +static int cdat_sslbis_handler(union acpi_subtable_headers *header, void *arg, + const unsigned long end) +{ + struct acpi_cdat_sslbis *sslbis; + int size = sizeof(header->cdat) + sizeof(*sslbis); + struct cxl_port *port = arg; + struct device *dev = &port->dev; + struct acpi_cdat_sslbe *entry; + int remain, entries, i; + u16 len; + + len = le16_to_cpu((__force __le16)header->cdat.length); + remain = len - size; + if (!remain || remain % sizeof(*entry) || + (unsigned long)header + len > end) { + dev_warn(dev, "Malformed SSLBIS table length: (%u)\n", len); + return -EINVAL; + } + + /* Skip common header */ + sslbis = (struct acpi_cdat_sslbis *)((unsigned long)header + + sizeof(header->cdat)); + + /* Unrecognized data type, we can skip */ + if (sslbis->data_type > ACPI_HMAT_WRITE_BANDWIDTH) + return 0; + + entries = remain / sizeof(*entry); + entry = (struct acpi_cdat_sslbe *)((unsigned long)header + sizeof(*sslbis)); + + for (i = 0; i < entries; i++) { + u16 x = le16_to_cpu((__force __le16)entry->portx_id); + u16 y = le16_to_cpu((__force __le16)entry->porty_id); + __le64 le_base; + __le16 le_val; + struct cxl_dport *dport; + unsigned long index; + u16 dsp_id; + u64 val; + + switch (x) { + case ACPI_CDAT_SSLBIS_US_PORT: + dsp_id = y; + break; + case ACPI_CDAT_SSLBIS_ANY_PORT: + switch (y) { + case ACPI_CDAT_SSLBIS_US_PORT: + dsp_id = x; + break; + case ACPI_CDAT_SSLBIS_ANY_PORT: + dsp_id = ACPI_CDAT_SSLBIS_ANY_PORT; + break; + default: + dsp_id = y; + break; + } + break; + default: + dsp_id = x; + break; + } + + le_base = (__force __le64)sslbis->entry_base_unit; + le_val = (__force __le16)entry->latency_or_bandwidth; + + if (check_mul_overflow(le64_to_cpu(le_base), + le16_to_cpu(le_val), &val)) + dev_warn(dev, "SSLBIS value overflowed!\n"); + + xa_for_each(&port->dports, index, dport) { + if (dsp_id == ACPI_CDAT_SSLBIS_ANY_PORT || + dsp_id == dport->port_id) + cxl_access_coordinate_set(&dport->sw_coord, + sslbis->data_type, + val); + } + + entry++; + } + + return 0; +} + +void cxl_switch_parse_cdat(struct cxl_port *port) +{ + int rc; + + if (!port->cdat.table) + return; + + rc = cdat_table_parse(ACPI_CDAT_TYPE_SSLBIS, cdat_sslbis_handler, + port, port->cdat.table); + rc = cdat_table_parse_output(rc); + if (rc) + dev_dbg(&port->dev, "Failed to parse SSLBIS: %d\n", rc); +} +EXPORT_SYMBOL_NS_GPL(cxl_switch_parse_cdat, CXL); + +MODULE_IMPORT_NS(CXL); diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h index 86d7ba23235e3b..3b64fb1b9ed058 100644 --- a/drivers/cxl/core/core.h +++ b/drivers/cxl/core/core.h @@ -88,4 +88,6 @@ enum cxl_poison_trace_type { CXL_POISON_TRACE_CLEAR, }; +long cxl_pci_get_latency(struct pci_dev *pdev); + #endif /* __CXL_CORE_H__ */ diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c index 36270dcfb42ef2..27166a41170579 100644 --- a/drivers/cxl/core/mbox.c +++ b/drivers/cxl/core/mbox.c @@ -63,6 +63,7 @@ static struct cxl_mem_command cxl_mem_commands[CXL_MEM_COMMAND_ID_MAX] = { CXL_CMD(GET_SHUTDOWN_STATE, 0, 0x1, 0), CXL_CMD(SET_SHUTDOWN_STATE, 0x1, 0, 0), CXL_CMD(GET_SCAN_MEDIA_CAPS, 0x10, 0x4, 0), + CXL_CMD(GET_TIMESTAMP, 0, 0x8, 0), }; /* @@ -836,54 +837,37 @@ 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) +void cxl_event_trace_record(const struct cxl_memdev *cxlmd, + enum cxl_event_log_type type, + enum cxl_event_type event_type, + const uuid_t *uuid, union cxl_event *evt) { - 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; + if (event_type == CXL_CPER_EVENT_GEN_MEDIA) + trace_cxl_general_media(cxlmd, type, &evt->gen_media); + else if (event_type == CXL_CPER_EVENT_DRAM) + trace_cxl_dram(cxlmd, type, &evt->dram); + else if (event_type == CXL_CPER_EVENT_MEM_MODULE) + trace_cxl_memory_module(cxlmd, type, &evt->mem_module); + else + trace_cxl_generic_event(cxlmd, type, uuid, &evt->generic); +} +EXPORT_SYMBOL_NS_GPL(cxl_event_trace_record, CXL); - 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; +static void __cxl_event_trace_record(const struct cxl_memdev *cxlmd, + enum cxl_event_log_type type, + struct cxl_event_record_raw *record) +{ + enum cxl_event_type ev_type = CXL_CPER_EVENT_GENERIC; + const uuid_t *uuid = &record->id; - 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; + if (uuid_equal(uuid, &CXL_EVENT_GEN_MEDIA_UUID)) + ev_type = CXL_CPER_EVENT_GEN_MEDIA; + else if (uuid_equal(uuid, &CXL_EVENT_DRAM_UUID)) + ev_type = CXL_CPER_EVENT_DRAM; + else if (uuid_equal(uuid, &CXL_EVENT_MEM_MODULE_UUID)) + ev_type = CXL_CPER_EVENT_MEM_MODULE; - trace_cxl_memory_module(cxlmd, type, rec); - } else { - /* For unknown record types print just the header */ - trace_cxl_generic_event(cxlmd, type, record); - } + cxl_event_trace_record(cxlmd, type, ev_type, uuid, &record->event); } static int cxl_clear_event_record(struct cxl_memdev_state *mds, @@ -926,7 +910,10 @@ static int cxl_clear_event_record(struct cxl_memdev_state *mds, */ i = 0; for (cnt = 0; cnt < total; cnt++) { - payload->handles[i++] = get_pl->records[cnt].hdr.handle; + struct cxl_event_record_raw *raw = &get_pl->records[cnt]; + struct cxl_event_generic *gen = &raw->event.generic; + + payload->handles[i++] = gen->hdr.handle; dev_dbg(mds->cxlds.dev, "Event log '%d': Clearing %u\n", log, le16_to_cpu(payload->handles[i])); @@ -991,8 +978,8 @@ static void cxl_mem_get_records_log(struct cxl_memdev_state *mds, break; for (i = 0; i < nr_rec; i++) - cxl_event_trace_record(cxlmd, type, - &payload->records[i]); + __cxl_event_trace_record(cxlmd, type, + &payload->records[i]); if (payload->flags & CXL_GET_EVENT_FLAG_OVERFLOW) trace_cxl_overflow(cxlmd, type, payload); @@ -1404,6 +1391,8 @@ struct cxl_memdev_state *cxl_memdev_state_create(struct device *dev) mds->cxlds.reg_map.host = dev; mds->cxlds.reg_map.resource = CXL_RESOURCE_NONE; mds->cxlds.type = CXL_DEVTYPE_CLASSMEM; + INIT_LIST_HEAD(&mds->ram_perf_list); + INIT_LIST_HEAD(&mds->pmem_perf_list); return mds; } diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c index 2f43d368ba0730..dae8802ecdb01e 100644 --- a/drivers/cxl/core/memdev.c +++ b/drivers/cxl/core/memdev.c @@ -114,7 +114,7 @@ static DEVICE_ATTR_RO(serial); static ssize_t numa_node_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", dev_to_node(dev)); + return sysfs_emit(buf, "%d\n", dev_to_node(dev)); } static DEVICE_ATTR_RO(numa_node); diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c index 37e1652afbc7ea..6c9c8d92f8f714 100644 --- a/drivers/cxl/core/pci.c +++ b/drivers/cxl/core/pci.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright(c) 2021 Intel Corporation. All rights reserved. */ +#include #include #include #include @@ -979,3 +980,38 @@ pci_ers_result_t cxl_error_detected(struct pci_dev *pdev, return PCI_ERS_RESULT_NEED_RESET; } EXPORT_SYMBOL_NS_GPL(cxl_error_detected, CXL); + +static int cxl_flit_size(struct pci_dev *pdev) +{ + if (cxl_pci_flit_256(pdev)) + return 256; + + return 68; +} + +/** + * cxl_pci_get_latency - calculate the link latency for the PCIe link + * @pdev: PCI device + * + * return: calculated latency or 0 for no latency + * + * CXL Memory Device SW Guide v1.0 2.11.4 Link latency calculation + * Link latency = LinkPropagationLatency + FlitLatency + RetimerLatency + * LinkProgationLatency is negligible, so 0 will be used + * RetimerLatency is assumed to be negligible and 0 will be used + * FlitLatency = FlitSize / LinkBandwidth + * FlitSize is defined by spec. CXL rev3.0 4.2.1. + * 68B flit is used up to 32GT/s. >32GT/s, 256B flit size is used. + * The FlitLatency is converted to picoseconds. + */ +long cxl_pci_get_latency(struct pci_dev *pdev) +{ + long bw; + + bw = pcie_link_speed_mbps(pdev); + if (bw < 0) + return 0; + bw /= BITS_PER_BYTE; + + return cxl_flit_size(pdev) * MEGA / bw; +} diff --git a/drivers/cxl/core/pmem.c b/drivers/cxl/core/pmem.c index fc94f524032712..e69625a8d6a1d7 100644 --- a/drivers/cxl/core/pmem.c +++ b/drivers/cxl/core/pmem.c @@ -64,14 +64,14 @@ static int match_nvdimm_bridge(struct device *dev, void *data) struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_memdev *cxlmd) { - struct cxl_port *port = find_cxl_root(cxlmd->endpoint); + struct cxl_root *cxl_root __free(put_cxl_root) = + find_cxl_root(cxlmd->endpoint); struct device *dev; - if (!port) + if (!cxl_root) return NULL; - dev = device_find_child(&port->dev, NULL, match_nvdimm_bridge); - put_device(&port->dev); + dev = device_find_child(&cxl_root->port.dev, NULL, match_nvdimm_bridge); if (!dev) return NULL; diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index b7c93bb18f6e75..e59d9d37aa6500 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -172,14 +173,10 @@ static ssize_t target_list_show(struct device *dev, { struct cxl_switch_decoder *cxlsd = to_cxl_switch_decoder(dev); ssize_t offset; - unsigned int seq; int rc; - do { - seq = read_seqbegin(&cxlsd->target_lock); - rc = emit_target_list(cxlsd, buf); - } while (read_seqretry(&cxlsd->target_lock, seq)); - + guard(rwsem_read)(&cxl_region_rwsem); + rc = emit_target_list(cxlsd, buf); if (rc < 0) return rc; offset = rc; @@ -541,7 +538,10 @@ static void cxl_port_release(struct device *dev) xa_destroy(&port->dports); xa_destroy(&port->regions); ida_free(&cxl_port_ida, port->id); - kfree(port); + if (is_cxl_root(port)) + kfree(to_cxl_root(port)); + else + kfree(port); } static ssize_t decoders_committed_show(struct device *dev, @@ -669,17 +669,31 @@ static struct lock_class_key cxl_port_key; static struct cxl_port *cxl_port_alloc(struct device *uport_dev, struct cxl_dport *parent_dport) { - struct cxl_port *port; + struct cxl_root *cxl_root __free(kfree) = NULL; + struct cxl_port *port, *_port __free(kfree) = NULL; struct device *dev; int rc; - port = kzalloc(sizeof(*port), GFP_KERNEL); - if (!port) - return ERR_PTR(-ENOMEM); + /* No parent_dport, root cxl_port */ + if (!parent_dport) { + cxl_root = kzalloc(sizeof(*cxl_root), GFP_KERNEL); + if (!cxl_root) + return ERR_PTR(-ENOMEM); + } else { + _port = kzalloc(sizeof(*port), GFP_KERNEL); + if (!_port) + return ERR_PTR(-ENOMEM); + } rc = ida_alloc(&cxl_port_ida, GFP_KERNEL); if (rc < 0) - goto err; + return ERR_PTR(rc); + + if (cxl_root) + port = &no_free_ptr(cxl_root)->port; + else + port = no_free_ptr(_port); + port->id = rc; port->uport_dev = uport_dev; @@ -731,10 +745,6 @@ static struct cxl_port *cxl_port_alloc(struct device *uport_dev, dev->type = &cxl_port_type; return port; - -err: - kfree(port); - return ERR_PTR(rc); } static int cxl_setup_comp_regs(struct device *host, struct cxl_register_map *map, @@ -841,6 +851,9 @@ static struct cxl_port *__devm_cxl_add_port(struct device *host, if (rc) return ERR_PTR(rc); + if (parent_dport && dev_is_pci(uport_dev)) + port->pci_latency = cxl_pci_get_latency(to_pci_dev(uport_dev)); + return port; err: @@ -884,6 +897,22 @@ struct cxl_port *devm_cxl_add_port(struct device *host, } EXPORT_SYMBOL_NS_GPL(devm_cxl_add_port, CXL); +struct cxl_root *devm_cxl_add_root(struct device *host, + const struct cxl_root_ops *ops) +{ + struct cxl_root *cxl_root; + struct cxl_port *port; + + port = devm_cxl_add_port(host, host, CXL_RESOURCE_NONE, NULL); + if (IS_ERR(port)) + return (struct cxl_root *)port; + + cxl_root = to_cxl_root(port); + cxl_root->ops = ops; + return cxl_root; +} +EXPORT_SYMBOL_NS_GPL(devm_cxl_add_root, CXL); + struct pci_bus *cxl_port_to_pci_bus(struct cxl_port *port) { /* There is no pci_bus associated with a CXL platform-root port */ @@ -939,7 +968,7 @@ static bool dev_is_cxl_root_child(struct device *dev) return false; } -struct cxl_port *find_cxl_root(struct cxl_port *port) +struct cxl_root *find_cxl_root(struct cxl_port *port) { struct cxl_port *iter = port; @@ -949,10 +978,19 @@ struct cxl_port *find_cxl_root(struct cxl_port *port) if (!iter) return NULL; get_device(&iter->dev); - return iter; + return to_cxl_root(iter); } EXPORT_SYMBOL_NS_GPL(find_cxl_root, CXL); +void put_cxl_root(struct cxl_root *cxl_root) +{ + if (!cxl_root) + return; + + put_device(&cxl_root->port.dev); +} +EXPORT_SYMBOL_NS_GPL(put_cxl_root, CXL); + static struct cxl_dport *find_dport(struct cxl_port *port, int id) { struct cxl_dport *dport; @@ -1108,6 +1146,9 @@ __devm_cxl_add_dport(struct cxl_port *port, struct device *dport_dev, if (rc) return ERR_PTR(rc); + if (dev_is_pci(dport_dev)) + dport->link_latency = cxl_pci_get_latency(to_pci_dev(dport_dev)); + return dport; } @@ -1633,7 +1674,7 @@ EXPORT_SYMBOL_NS_GPL(cxl_mem_find_port, CXL); static int decoder_populate_targets(struct cxl_switch_decoder *cxlsd, struct cxl_port *port, int *target_map) { - int i, rc = 0; + int i; if (!target_map) return 0; @@ -1643,19 +1684,16 @@ static int decoder_populate_targets(struct cxl_switch_decoder *cxlsd, if (xa_empty(&port->dports)) return -EINVAL; - write_seqlock(&cxlsd->target_lock); - for (i = 0; i < cxlsd->nr_targets; i++) { + guard(rwsem_write)(&cxl_region_rwsem); + for (i = 0; i < cxlsd->cxld.interleave_ways; i++) { struct cxl_dport *dport = find_dport(port, target_map[i]); - if (!dport) { - rc = -ENXIO; - break; - } + if (!dport) + return -ENXIO; cxlsd->target[i] = dport; } - write_sequnlock(&cxlsd->target_lock); - return rc; + return 0; } struct cxl_dport *cxl_hb_modulo(struct cxl_root_decoder *cxlrd, int pos) @@ -1725,7 +1763,6 @@ static int cxl_switch_decoder_init(struct cxl_port *port, return -EINVAL; cxlsd->nr_targets = nr_targets; - seqlock_init(&cxlsd->target_lock); return cxl_decoder_init(port, &cxlsd->cxld); } @@ -2059,6 +2096,80 @@ bool schedule_cxl_memdev_detach(struct cxl_memdev *cxlmd) } EXPORT_SYMBOL_NS_GPL(schedule_cxl_memdev_detach, CXL); +static void combine_coordinates(struct access_coordinate *c1, + struct access_coordinate *c2) +{ + if (c2->write_bandwidth) + c1->write_bandwidth = min(c1->write_bandwidth, + c2->write_bandwidth); + c1->write_latency += c2->write_latency; + + if (c2->read_bandwidth) + c1->read_bandwidth = min(c1->read_bandwidth, + c2->read_bandwidth); + c1->read_latency += c2->read_latency; +} + +/** + * cxl_endpoint_get_perf_coordinates - Retrieve performance numbers stored in dports + * of CXL path + * @port: endpoint cxl_port + * @coord: output performance data + * + * Return: errno on failure, 0 on success. + */ +int cxl_endpoint_get_perf_coordinates(struct cxl_port *port, + struct access_coordinate *coord) +{ + struct access_coordinate c = { + .read_bandwidth = UINT_MAX, + .write_bandwidth = UINT_MAX, + }; + struct cxl_port *iter = port; + struct cxl_dport *dport; + struct pci_dev *pdev; + unsigned int bw; + + if (!is_cxl_endpoint(port)) + return -EINVAL; + + dport = iter->parent_dport; + + /* + * Exit the loop when the parent port of the current port is cxl root. + * The iterative loop starts at the endpoint and gathers the + * latency of the CXL link from the current iter to the next downstream + * port each iteration. If the parent is cxl root then there is + * nothing to gather. + */ + while (iter && !is_cxl_root(to_cxl_port(iter->dev.parent))) { + combine_coordinates(&c, &dport->sw_coord); + c.write_latency += dport->link_latency; + c.read_latency += dport->link_latency; + + iter = to_cxl_port(iter->dev.parent); + dport = iter->parent_dport; + } + + /* Augment with the generic port (host bridge) perf data */ + combine_coordinates(&c, &dport->hb_coord); + + /* Get the calculated PCI paths bandwidth */ + pdev = to_pci_dev(port->uport_dev->parent); + bw = pcie_bandwidth_available(pdev, NULL, NULL, NULL); + if (bw == 0) + return -ENXIO; + bw /= BITS_PER_BYTE; + + c.write_bandwidth = min(c.write_bandwidth, bw); + c.read_bandwidth = min(c.read_bandwidth, bw); + + *coord = c; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(cxl_endpoint_get_perf_coordinates, CXL); + /* for user tooling to ensure port disable work has completed */ static ssize_t flush_store(const struct bus_type *bus, const char *buf, size_t count) { diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index 3e817a6f94c6a4..ce0e2d82bb2b4c 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -397,7 +397,7 @@ static ssize_t interleave_ways_store(struct device *dev, return rc; /* - * Even for x3, x9, and x12 interleaves the region interleave must be a + * Even for x3, x6, and x12 interleaves the region interleave must be a * power of 2 multiple of the host bridge interleave. */ if (!is_power_of_2(val / cxld->interleave_ways) || @@ -525,7 +525,7 @@ static int alloc_hpa(struct cxl_region *cxlr, resource_size_t size) struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(cxlr->dev.parent); struct cxl_region_params *p = &cxlr->params; struct resource *res; - u32 remainder = 0; + u64 remainder = 0; lockdep_assert_held_write(&cxl_region_rwsem); @@ -545,15 +545,16 @@ static int alloc_hpa(struct cxl_region *cxlr, resource_size_t size) (cxlr->mode == CXL_DECODER_PMEM && uuid_is_null(&p->uuid))) return -ENXIO; - div_u64_rem(size, SZ_256M * p->interleave_ways, &remainder); + div64_u64_rem(size, (u64)SZ_256M * p->interleave_ways, &remainder); if (remainder) return -EINVAL; res = alloc_free_mem_region(cxlrd->res, size, SZ_256M, dev_name(&cxlr->dev)); if (IS_ERR(res)) { - dev_dbg(&cxlr->dev, "failed to allocate HPA: %ld\n", - PTR_ERR(res)); + dev_dbg(&cxlr->dev, + "HPA allocation error (%ld) for size:%pap in %s %pr\n", + PTR_ERR(res), &size, cxlrd->res->name, cxlrd->res); return PTR_ERR(res); } @@ -2083,13 +2084,13 @@ static struct cxl_region *to_cxl_region(struct device *dev) return container_of(dev, struct cxl_region, dev); } -static void unregister_region(void *dev) +static void unregister_region(void *_cxlr) { - struct cxl_region *cxlr = to_cxl_region(dev); + struct cxl_region *cxlr = _cxlr; struct cxl_region_params *p = &cxlr->params; int i; - device_del(dev); + device_del(&cxlr->dev); /* * Now that region sysfs is shutdown, the parameter block is now @@ -2100,7 +2101,7 @@ static void unregister_region(void *dev) detach_target(cxlr, i); cxl_region_iomem_release(cxlr); - put_device(dev); + put_device(&cxlr->dev); } static struct lock_class_key cxl_region_key; diff --git a/drivers/cxl/core/trace.h b/drivers/cxl/core/trace.h index a0b5819bc70b30..89445435303aac 100644 --- a/drivers/cxl/core/trace.h +++ b/drivers/cxl/core/trace.h @@ -181,6 +181,7 @@ TRACE_EVENT(cxl_overflow, * 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 + * NOTE: The uuid must be assigned by the specific trace event * 3) Use CXL_EVT_TP_printk() instead of TP_printk() * * See the generic_event tracepoint as an example. @@ -203,7 +204,6 @@ TRACE_EVENT(cxl_overflow, __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); \ @@ -225,9 +225,9 @@ TRACE_EVENT(cxl_overflow, TRACE_EVENT(cxl_generic_event, TP_PROTO(const struct cxl_memdev *cxlmd, enum cxl_event_log_type log, - struct cxl_event_record_raw *rec), + const uuid_t *uuid, struct cxl_event_generic *gen_rec), - TP_ARGS(cxlmd, log, rec), + TP_ARGS(cxlmd, log, uuid, gen_rec), TP_STRUCT__entry( CXL_EVT_TP_entry @@ -235,8 +235,9 @@ TRACE_EVENT(cxl_generic_event, ), 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_fast_assign(cxlmd, log, gen_rec->hdr); + memcpy(&__entry->hdr_uuid, uuid, sizeof(uuid_t)); + memcpy(__entry->data, gen_rec->data, CXL_EVENT_RECORD_DATA_LENGTH); ), CXL_EVT_TP_printk("%s", @@ -337,6 +338,7 @@ TRACE_EVENT(cxl_general_media, TP_fast_assign( CXL_EVT_TP_fast_assign(cxlmd, log, rec->hdr); + memcpy(&__entry->hdr_uuid, &CXL_EVENT_GEN_MEDIA_UUID, sizeof(uuid_t)); /* General Media */ __entry->dpa = le64_to_cpu(rec->phys_addr); @@ -423,6 +425,7 @@ TRACE_EVENT(cxl_dram, TP_fast_assign( CXL_EVT_TP_fast_assign(cxlmd, log, rec->hdr); + memcpy(&__entry->hdr_uuid, &CXL_EVENT_DRAM_UUID, sizeof(uuid_t)); /* DRAM */ __entry->dpa = le64_to_cpu(rec->phys_addr); @@ -570,6 +573,7 @@ TRACE_EVENT(cxl_memory_module, TP_fast_assign( CXL_EVT_TP_fast_assign(cxlmd, log, rec->hdr); + memcpy(&__entry->hdr_uuid, &CXL_EVENT_MEM_MODULE_UUID, sizeof(uuid_t)); /* Memory Module Event */ __entry->event_type = rec->event_type; diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index 687043ece1018c..b6017c0c57b4d5 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -8,6 +8,7 @@ #include #include #include +#include #include /** @@ -412,7 +413,6 @@ struct cxl_endpoint_decoder { /** * struct cxl_switch_decoder - Switch specific CXL HDM Decoder * @cxld: base cxl_decoder object - * @target_lock: coordinate coherent reads of the target list * @nr_targets: number of elements in @target * @target: active ordered target list in current decoder configuration * @@ -424,7 +424,6 @@ struct cxl_endpoint_decoder { */ struct cxl_switch_decoder { struct cxl_decoder cxld; - seqlock_t target_lock; int nr_targets; struct cxl_dport *target[]; }; @@ -590,6 +589,7 @@ struct cxl_dax_region { * @depth: How deep this port is relative to the root. depth 0 is the root. * @cdat: Cached CDAT data * @cdat_available: Should a CDAT attribute be available in sysfs + * @pci_latency: Upstream latency in picoseconds */ struct cxl_port { struct device dev; @@ -612,6 +612,30 @@ struct cxl_port { size_t length; } cdat; bool cdat_available; + long pci_latency; +}; + +/** + * struct cxl_root - logical collection of root cxl_port items + * + * @port: cxl_port member + * @ops: cxl root operations + */ +struct cxl_root { + struct cxl_port port; + const struct cxl_root_ops *ops; +}; + +static inline struct cxl_root * +to_cxl_root(const struct cxl_port *port) +{ + return container_of(port, struct cxl_root, port); +} + +struct cxl_root_ops { + int (*qos_class)(struct cxl_root *cxl_root, + struct access_coordinate *coord, int entries, + int *qos_class); }; static inline struct cxl_dport * @@ -634,6 +658,9 @@ struct cxl_rcrb_info { * @rch: Indicate whether this dport was enumerated in RCH or VH mode * @port: reference to cxl_port that contains this downstream port * @regs: Dport parsed register blocks + * @sw_coord: access coordinates (performance) for switch from CDAT + * @hb_coord: access coordinates (performance) from ACPI generic port (host bridge) + * @link_latency: calculated PCIe downstream latency */ struct cxl_dport { struct device *dport_dev; @@ -643,6 +670,9 @@ struct cxl_dport { bool rch; struct cxl_port *port; struct cxl_regs regs; + struct access_coordinate sw_coord; + struct access_coordinate hb_coord; + long link_latency; }; /** @@ -700,7 +730,12 @@ struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport_dev, resource_size_t component_reg_phys, struct cxl_dport *parent_dport); -struct cxl_port *find_cxl_root(struct cxl_port *port); +struct cxl_root *devm_cxl_add_root(struct device *host, + const struct cxl_root_ops *ops); +struct cxl_root *find_cxl_root(struct cxl_port *port); +void put_cxl_root(struct cxl_root *cxl_root); +DEFINE_FREE(put_cxl_root, struct cxl_root *, if (_T) put_cxl_root(_T)) + int devm_cxl_enumerate_ports(struct cxl_memdev *cxlmd); void cxl_bus_rescan(void); void cxl_bus_drain(void); @@ -839,6 +874,12 @@ static inline struct cxl_dax_region *to_cxl_dax_region(struct device *dev) } #endif +void cxl_endpoint_parse_cdat(struct cxl_port *port); +void cxl_switch_parse_cdat(struct cxl_port *port); + +int cxl_endpoint_get_perf_coordinates(struct cxl_port *port, + struct access_coordinate *coord); + /* * Unit test builds overrides this to __weak, find the 'strong' version * of these symbols in tools/testing/cxl/. diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h index a2fcbca253f398..5303d6942b880a 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include "cxl.h" /* CXL 2.0 8.2.8.5.1.1 Memory Device Status Register */ @@ -391,6 +393,20 @@ enum cxl_devtype { CXL_DEVTYPE_CLASSMEM, }; +/** + * struct cxl_dpa_perf - DPA performance property entry + * @list - list entry + * @dpa_range - range for DPA address + * @coord - QoS performance data (i.e. latency, bandwidth) + * @qos_class - QoS Class cookies + */ +struct cxl_dpa_perf { + struct list_head list; + struct range dpa_range; + struct access_coordinate coord; + int qos_class; +}; + /** * struct cxl_dev_state - The driver device state * @@ -455,6 +471,8 @@ struct cxl_dev_state { * @security: security driver state info * @fw: firmware upload / activation state * @mbox_send: @dev specific transport for transmitting mailbox commands + * @ram_perf_list: performance data entries matched to RAM + * @pmem_perf_list: performance data entries matched to PMEM * * See CXL 3.0 8.2.9.8.2 Capacity Configuration and Label Storage for * details on capacity parameters. @@ -475,6 +493,10 @@ struct cxl_memdev_state { u64 active_persistent_bytes; u64 next_volatile_bytes; u64 next_persistent_bytes; + + struct list_head ram_perf_list; + struct list_head pmem_perf_list; + struct cxl_event_state event; struct cxl_poison_state poison; struct cxl_security_state security; @@ -503,6 +525,7 @@ enum cxl_opcode { CXL_MBOX_OP_GET_FW_INFO = 0x0200, CXL_MBOX_OP_TRANSFER_FW = 0x0201, CXL_MBOX_OP_ACTIVATE_FW = 0x0202, + CXL_MBOX_OP_GET_TIMESTAMP = 0x0300, CXL_MBOX_OP_SET_TIMESTAMP = 0x0301, CXL_MBOX_OP_GET_SUPPORTED_LOGS = 0x0400, CXL_MBOX_OP_GET_LOG = 0x0401, @@ -580,25 +603,28 @@ struct cxl_mbox_identify { } __packed; /* - * Common Event Record Format - * CXL rev 3.0 section 8.2.9.2.1; Table 8-42 + * General Media Event Record UUID + * CXL rev 3.0 Section 8.2.9.2.1.1; Table 8-43 */ -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_GEN_MEDIA_UUID \ + UUID_INIT(0xfbcd0a77, 0xc260, 0x417f, 0x85, 0xa9, 0x08, 0x8b, 0x16, \ + 0x21, 0xeb, 0xa6) -#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; +/* + * DRAM Event Record UUID + * CXL rev 3.0 section 8.2.9.2.1.2; Table 8-44 + */ +#define CXL_EVENT_DRAM_UUID \ + UUID_INIT(0x601dcbb3, 0x9c06, 0x4eab, 0xb8, 0xaf, 0x4e, 0x9b, 0xfb, \ + 0x5c, 0x96, 0x24) + +/* + * Memory Module Event Record UUID + * CXL rev 3.0 section 8.2.9.2.1.3; Table 8-45 + */ +#define CXL_EVENT_MEM_MODULE_UUID \ + UUID_INIT(0xfe927475, 0xdd59, 0x4339, 0xa5, 0x86, 0x79, 0xba, 0xb1, \ + 0x13, 0xb7, 0x74) /* * Get Event Records output payload @@ -641,74 +667,6 @@ struct cxl_mbox_clear_event_payload { } __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; @@ -866,6 +824,10 @@ void set_exclusive_cxl_commands(struct cxl_memdev_state *mds, void clear_exclusive_cxl_commands(struct cxl_memdev_state *mds, unsigned long *cmds); void cxl_mem_get_event_records(struct cxl_memdev_state *mds, u32 status); +void cxl_event_trace_record(const struct cxl_memdev *cxlmd, + enum cxl_event_log_type type, + enum cxl_event_type event_type, + const uuid_t *uuid, union cxl_event *evt); int cxl_set_timestamp(struct cxl_memdev_state *mds); int cxl_poison_state_init(struct cxl_memdev_state *mds); int cxl_mem_get_poison(struct cxl_memdev *cxlmd, u64 offset, u64 len, diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h index 0fa4799ea316cd..711b05d9a370e9 100644 --- a/drivers/cxl/cxlpci.h +++ b/drivers/cxl/cxlpci.h @@ -85,6 +85,19 @@ struct cdat_entry_header { __le16 length; } __packed; +/* + * 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 inline 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; +} + 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, diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c index e087febf9af047..c5c9d8e0d88d69 100644 --- a/drivers/cxl/mem.c +++ b/drivers/cxl/mem.c @@ -215,23 +215,78 @@ static ssize_t trigger_poison_list_store(struct device *dev, } static DEVICE_ATTR_WO(trigger_poison_list); +static ssize_t ram_qos_class_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cxl_memdev *cxlmd = to_cxl_memdev(dev); + struct cxl_dev_state *cxlds = cxlmd->cxlds; + struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds); + struct cxl_dpa_perf *dpa_perf; + + if (!dev->driver) + return -ENOENT; + + if (list_empty(&mds->ram_perf_list)) + return -ENOENT; + + dpa_perf = list_first_entry(&mds->ram_perf_list, struct cxl_dpa_perf, + list); + + return sysfs_emit(buf, "%d\n", dpa_perf->qos_class); +} + +static struct device_attribute dev_attr_ram_qos_class = + __ATTR(qos_class, 0444, ram_qos_class_show, NULL); + +static ssize_t pmem_qos_class_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cxl_memdev *cxlmd = to_cxl_memdev(dev); + struct cxl_dev_state *cxlds = cxlmd->cxlds; + struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds); + struct cxl_dpa_perf *dpa_perf; + + if (!dev->driver) + return -ENOENT; + + if (list_empty(&mds->pmem_perf_list)) + return -ENOENT; + + dpa_perf = list_first_entry(&mds->pmem_perf_list, struct cxl_dpa_perf, + list); + + return sysfs_emit(buf, "%d\n", dpa_perf->qos_class); +} + +static struct device_attribute dev_attr_pmem_qos_class = + __ATTR(qos_class, 0444, pmem_qos_class_show, NULL); + static umode_t cxl_mem_visible(struct kobject *kobj, struct attribute *a, int n) { - if (a == &dev_attr_trigger_poison_list.attr) { - struct device *dev = kobj_to_dev(kobj); - struct cxl_memdev *cxlmd = to_cxl_memdev(dev); - struct cxl_memdev_state *mds = - to_cxl_memdev_state(cxlmd->cxlds); + struct device *dev = kobj_to_dev(kobj); + struct cxl_memdev *cxlmd = to_cxl_memdev(dev); + struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlmd->cxlds); + if (a == &dev_attr_trigger_poison_list.attr) if (!test_bit(CXL_POISON_ENABLED_LIST, mds->poison.enabled_cmds)) return 0; - } + + if (a == &dev_attr_pmem_qos_class.attr) + if (list_empty(&mds->pmem_perf_list)) + return 0; + + if (a == &dev_attr_ram_qos_class.attr) + if (list_empty(&mds->ram_perf_list)) + return 0; + return a->mode; } static struct attribute *cxl_mem_attrs[] = { &dev_attr_trigger_poison_list.attr, + &dev_attr_ram_qos_class.attr, + &dev_attr_pmem_qos_class.attr, NULL }; diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index 0155fb66b580d7..233e7c42c161d8 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright(c) 2020 Intel Corporation. All rights reserved. */ +#include #include #include #include @@ -381,7 +382,7 @@ static int cxl_pci_mbox_send(struct cxl_memdev_state *mds, return rc; } -static int cxl_pci_setup_mailbox(struct cxl_memdev_state *mds) +static int cxl_pci_setup_mailbox(struct cxl_memdev_state *mds, bool irq_avail) { struct cxl_dev_state *cxlds = &mds->cxlds; const int cap = readl(cxlds->regs.mbox + CXLDEV_MBOX_CAPS_OFFSET); @@ -440,7 +441,7 @@ static int cxl_pci_setup_mailbox(struct cxl_memdev_state *mds) INIT_DELAYED_WORK(&mds->security.poll_dwork, cxl_mbox_sanitize_work); /* background command interrupts are optional */ - if (!(cap & CXLDEV_MBOX_CAP_BG_CMD_IRQ)) + if (!(cap & CXLDEV_MBOX_CAP_BG_CMD_IRQ) || !irq_avail) return 0; msgnum = FIELD_GET(CXLDEV_MBOX_CAP_IRQ_MSGNUM_MASK, cap); @@ -587,7 +588,7 @@ static int cxl_mem_alloc_event_buf(struct cxl_memdev_state *mds) return devm_add_action_or_reset(mds->cxlds.dev, free_event_buf, buf); } -static int cxl_alloc_irq_vectors(struct pci_dev *pdev) +static bool cxl_alloc_irq_vectors(struct pci_dev *pdev) { int nvecs; @@ -604,9 +605,9 @@ static int cxl_alloc_irq_vectors(struct pci_dev *pdev) PCI_IRQ_MSIX | PCI_IRQ_MSI); if (nvecs < 1) { dev_dbg(&pdev->dev, "Failed to alloc irq vectors: %d\n", nvecs); - return -ENXIO; + return false; } - return 0; + return true; } static irqreturn_t cxl_event_thread(int irq, void *id) @@ -742,7 +743,7 @@ static bool cxl_event_int_is_fw(u8 setting) } static int cxl_event_config(struct pci_host_bridge *host_bridge, - struct cxl_memdev_state *mds) + struct cxl_memdev_state *mds, bool irq_avail) { struct cxl_event_interrupt_policy policy; int rc; @@ -754,6 +755,11 @@ static int cxl_event_config(struct pci_host_bridge *host_bridge, if (!host_bridge->native_cxl_error) return 0; + if (!irq_avail) { + dev_info(mds->cxlds.dev, "No interrupt support, disable event processing.\n"); + return 0; + } + rc = cxl_mem_alloc_event_buf(mds); if (rc) return rc; @@ -788,6 +794,7 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) struct cxl_register_map map; struct cxl_memdev *cxlmd; int i, rc, pmu_count; + bool irq_avail; /* * Double check the anonymous union trickery in struct cxl_regs @@ -845,11 +852,9 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) else dev_warn(&pdev->dev, "Media not active (%d)\n", rc); - rc = cxl_alloc_irq_vectors(pdev); - if (rc) - return rc; + irq_avail = cxl_alloc_irq_vectors(pdev); - rc = cxl_pci_setup_mailbox(mds); + rc = cxl_pci_setup_mailbox(mds, irq_avail); if (rc) return rc; @@ -908,7 +913,7 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) } } - rc = cxl_event_config(host_bridge, mds); + rc = cxl_event_config(host_bridge, mds, irq_avail); if (rc) return rc; @@ -969,6 +974,61 @@ static struct pci_driver cxl_pci_driver = { }, }; +#define CXL_EVENT_HDR_FLAGS_REC_SEVERITY GENMASK(1, 0) +static void cxl_cper_event_call(enum cxl_event_type ev_type, + struct cxl_cper_event_rec *rec) +{ + struct cper_cxl_event_devid *device_id = &rec->hdr.device_id; + struct pci_dev *pdev __free(pci_dev_put) = NULL; + enum cxl_event_log_type log_type; + struct cxl_dev_state *cxlds; + unsigned int devfn; + u32 hdr_flags; + + devfn = PCI_DEVFN(device_id->device_num, device_id->func_num); + pdev = pci_get_domain_bus_and_slot(device_id->segment_num, + device_id->bus_num, devfn); + if (!pdev) + return; + + guard(pci_dev)(pdev); + if (pdev->driver != &cxl_pci_driver) + return; + + cxlds = pci_get_drvdata(pdev); + if (!cxlds) + return; + + /* Fabricate a log type */ + hdr_flags = get_unaligned_le24(rec->event.generic.hdr.flags); + log_type = FIELD_GET(CXL_EVENT_HDR_FLAGS_REC_SEVERITY, hdr_flags); + + cxl_event_trace_record(cxlds->cxlmd, log_type, ev_type, + &uuid_null, &rec->event); +} + +static int __init cxl_pci_driver_init(void) +{ + int rc; + + rc = cxl_cper_register_callback(cxl_cper_event_call); + if (rc) + return rc; + + rc = pci_register_driver(&cxl_pci_driver); + if (rc) + cxl_cper_unregister_callback(cxl_cper_event_call); + + return rc; +} + +static void __exit cxl_pci_driver_exit(void) +{ + pci_unregister_driver(&cxl_pci_driver); + cxl_cper_unregister_callback(cxl_cper_event_call); +} + +module_init(cxl_pci_driver_init); +module_exit(cxl_pci_driver_exit); MODULE_LICENSE("GPL v2"); -module_pci_driver(cxl_pci_driver); MODULE_IMPORT_NS(CXL); diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c index 47bc8e0b859077..97c21566677aa3 100644 --- a/drivers/cxl/port.c +++ b/drivers/cxl/port.c @@ -69,6 +69,8 @@ static int cxl_switch_port_probe(struct cxl_port *port) if (rc < 0) return rc; + cxl_switch_parse_cdat(port); + cxlhdm = devm_cxl_setup_hdm(port, NULL); if (!IS_ERR(cxlhdm)) return devm_cxl_enumerate_decoders(cxlhdm, NULL); @@ -109,6 +111,7 @@ static int cxl_endpoint_port_probe(struct cxl_port *port) /* Cache the data early to ensure is_visible() works */ read_cdat_data(port); + cxl_endpoint_parse_cdat(port); get_device(&cxlmd->dev); rc = devm_add_action_or_reset(&port->dev, schedule_detach, cxlmd); @@ -127,14 +130,15 @@ static int cxl_endpoint_port_probe(struct cxl_port *port) * 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(port); + struct cxl_root *cxl_root __free(put_cxl_root) = find_cxl_root(port); + + root = &cxl_root->port; /* * 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; } diff --git a/drivers/dax/bus.c b/drivers/dax/bus.c index 1659b787b65f55..1ff1ab5fa105a6 100644 --- a/drivers/dax/bus.c +++ b/drivers/dax/bus.c @@ -367,6 +367,7 @@ static ssize_t create_store(struct device *dev, struct device_attribute *attr, .dax_region = dax_region, .size = 0, .id = -1, + .memmap_on_memory = false, }; struct dev_dax *dev_dax = devm_create_dev_dax(&data); @@ -1400,6 +1401,8 @@ struct dev_dax *devm_create_dev_dax(struct dev_dax_data *data) dev_dax->align = dax_region->align; ida_init(&dev_dax->ida); + dev_dax->memmap_on_memory = data->memmap_on_memory; + inode = dax_inode(dax_dev); dev->devt = inode->i_rdev; dev->bus = &dax_bus_type; diff --git a/drivers/dax/bus.h b/drivers/dax/bus.h index 1ccd2336012485..cbbf64443098c0 100644 --- a/drivers/dax/bus.h +++ b/drivers/dax/bus.h @@ -23,6 +23,7 @@ struct dev_dax_data { struct dev_pagemap *pgmap; resource_size_t size; int id; + bool memmap_on_memory; }; struct dev_dax *devm_create_dev_dax(struct dev_dax_data *data); diff --git a/drivers/dax/cxl.c b/drivers/dax/cxl.c index 8bc9d04034d65e..c696837ab23c95 100644 --- a/drivers/dax/cxl.c +++ b/drivers/dax/cxl.c @@ -26,6 +26,7 @@ static int cxl_dax_region_probe(struct device *dev) .dax_region = dax_region, .id = -1, .size = range_len(&cxlr_dax->hpa_range), + .memmap_on_memory = true, }; return PTR_ERR_OR_ZERO(devm_create_dev_dax(&data)); diff --git a/drivers/dax/dax-private.h b/drivers/dax/dax-private.h index 27cf2daaaa795a..446617b73aeab2 100644 --- a/drivers/dax/dax-private.h +++ b/drivers/dax/dax-private.h @@ -70,6 +70,7 @@ struct dev_dax { struct ida ida; struct device dev; struct dev_pagemap *pgmap; + bool memmap_on_memory; int nr_range; struct dev_dax_range { unsigned long pgoff; diff --git a/drivers/dax/hmem/hmem.c b/drivers/dax/hmem/hmem.c index 5d2ddef0f8f525..b9da69f926974f 100644 --- a/drivers/dax/hmem/hmem.c +++ b/drivers/dax/hmem/hmem.c @@ -36,6 +36,7 @@ static int dax_hmem_probe(struct platform_device *pdev) .dax_region = dax_region, .id = -1, .size = region_idle ? 0 : range_len(&mri->range), + .memmap_on_memory = false, }; return PTR_ERR_OR_ZERO(devm_create_dev_dax(&data)); diff --git a/drivers/dax/kmem.c b/drivers/dax/kmem.c index 369c698b7706fb..42ee360cf4e3db 100644 --- a/drivers/dax/kmem.c +++ b/drivers/dax/kmem.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "dax-private.h" #include "bus.h" @@ -93,6 +94,7 @@ static int dev_dax_kmem_probe(struct dev_dax *dev_dax) struct dax_kmem_data *data; struct memory_dev_type *mtype; int i, rc, mapped = 0; + mhp_t mhp_flags; int numa_node; int adist = MEMTIER_DEFAULT_DAX_ADISTANCE; @@ -179,12 +181,16 @@ static int dev_dax_kmem_probe(struct dev_dax *dev_dax) */ res->flags = IORESOURCE_SYSTEM_RAM; + mhp_flags = MHP_NID_IS_MGID; + if (dev_dax->memmap_on_memory) + mhp_flags |= MHP_MEMMAP_ON_MEMORY; + /* * Ensure that future kexec'd kernels will not treat * this as RAM automatically. */ rc = add_memory_driver_managed(data->mgid, range.start, - range_len(&range), kmem_name, MHP_NID_IS_MGID); + range_len(&range), kmem_name, mhp_flags); if (rc) { dev_warn(dev, "mapping%d: %#llx-%#llx memory add failed\n", diff --git a/drivers/dax/pmem.c b/drivers/dax/pmem.c index ae0cb113a5d32e..f3c6c67b84128c 100644 --- a/drivers/dax/pmem.c +++ b/drivers/dax/pmem.c @@ -63,6 +63,7 @@ static struct dev_dax *__dax_pmem_probe(struct device *dev) .id = id, .pgmap = &pgmap, .size = range_len(&range), + .memmap_on_memory = false, }; return devm_create_dev_dax(&data); diff --git a/drivers/dax/super.c b/drivers/dax/super.c index 0da9232ea1754b..f4b635526345ad 100644 --- a/drivers/dax/super.c +++ b/drivers/dax/super.c @@ -326,7 +326,8 @@ void kill_dax(struct dax_device *dax_dev) return; if (dax_dev->holder_data != NULL) - dax_holder_notify_failure(dax_dev, 0, U64_MAX, 0); + dax_holder_notify_failure(dax_dev, 0, U64_MAX, + MF_MEM_PRE_REMOVE); clear_bit(DAXDEV_ALIVE, &dax_dev->flags); synchronize_srcu(&dax_srcu); diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index b3a68d5833bd67..98657d3b9435c7 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -461,10 +461,14 @@ static void devfreq_monitor(struct work_struct *work) if (err) dev_err(&devfreq->dev, "dvfs failed with (%d) error\n", err); + if (devfreq->stop_polling) + goto out; + queue_delayed_work(devfreq_wq, &devfreq->work, msecs_to_jiffies(devfreq->profile->polling_ms)); - mutex_unlock(&devfreq->lock); +out: + mutex_unlock(&devfreq->lock); trace_devfreq_monitor(devfreq); } @@ -483,6 +487,10 @@ void devfreq_monitor_start(struct devfreq *devfreq) if (IS_SUPPORTED_FLAG(devfreq->governor->flags, IRQ_DRIVEN)) return; + mutex_lock(&devfreq->lock); + if (delayed_work_pending(&devfreq->work)) + goto out; + switch (devfreq->profile->timer) { case DEVFREQ_TIMER_DEFERRABLE: INIT_DEFERRABLE_WORK(&devfreq->work, devfreq_monitor); @@ -491,12 +499,16 @@ void devfreq_monitor_start(struct devfreq *devfreq) INIT_DELAYED_WORK(&devfreq->work, devfreq_monitor); break; default: - return; + goto out; } if (devfreq->profile->polling_ms) queue_delayed_work(devfreq_wq, &devfreq->work, msecs_to_jiffies(devfreq->profile->polling_ms)); + +out: + devfreq->stop_polling = false; + mutex_unlock(&devfreq->lock); } EXPORT_SYMBOL(devfreq_monitor_start); @@ -513,6 +525,14 @@ void devfreq_monitor_stop(struct devfreq *devfreq) if (IS_SUPPORTED_FLAG(devfreq->governor->flags, IRQ_DRIVEN)) return; + mutex_lock(&devfreq->lock); + if (devfreq->stop_polling) { + mutex_unlock(&devfreq->lock); + return; + } + + devfreq->stop_polling = true; + mutex_unlock(&devfreq->lock); cancel_delayed_work_sync(&devfreq->work); } EXPORT_SYMBOL(devfreq_monitor_stop); @@ -1688,7 +1708,7 @@ static ssize_t trans_stat_show(struct device *dev, struct device_attribute *attr, char *buf) { struct devfreq *df = to_devfreq(dev); - ssize_t len; + ssize_t len = 0; int i, j; unsigned int max_state; @@ -1697,7 +1717,7 @@ static ssize_t trans_stat_show(struct device *dev, max_state = df->max_state; if (max_state == 0) - return sprintf(buf, "Not Supported.\n"); + return sysfs_emit(buf, "Not Supported.\n"); mutex_lock(&df->lock); if (!df->stop_polling && @@ -1707,31 +1727,49 @@ static ssize_t trans_stat_show(struct device *dev, } mutex_unlock(&df->lock); - len = sprintf(buf, " From : To\n"); - len += sprintf(buf + len, " :"); - for (i = 0; i < max_state; i++) - len += sprintf(buf + len, "%10lu", - df->freq_table[i]); + len += sysfs_emit_at(buf, len, " From : To\n"); + len += sysfs_emit_at(buf, len, " :"); + for (i = 0; i < max_state; i++) { + if (len >= PAGE_SIZE - 1) + break; + len += sysfs_emit_at(buf, len, "%10lu", + df->freq_table[i]); + } - len += sprintf(buf + len, " time(ms)\n"); + if (len >= PAGE_SIZE - 1) + return PAGE_SIZE - 1; + len += sysfs_emit_at(buf, len, " time(ms)\n"); for (i = 0; i < max_state; i++) { - if (df->freq_table[i] == df->previous_freq) - len += sprintf(buf + len, "*"); + if (len >= PAGE_SIZE - 1) + break; + if (df->freq_table[2] == df->previous_freq) + len += sysfs_emit_at(buf, len, "*"); else - len += sprintf(buf + len, " "); - - len += sprintf(buf + len, "%10lu:", df->freq_table[i]); - for (j = 0; j < max_state; j++) - len += sprintf(buf + len, "%10u", + len += sysfs_emit_at(buf, len, " "); + if (len >= PAGE_SIZE - 1) + break; + len += sysfs_emit_at(buf, len, "%10lu:", df->freq_table[i]); + for (j = 0; j < max_state; j++) { + if (len >= PAGE_SIZE - 1) + break; + len += sysfs_emit_at(buf, len, "%10u", df->stats.trans_table[(i * max_state) + j]); + } + if (len >= PAGE_SIZE - 1) + break; + len += sysfs_emit_at(buf, len, "%10llu\n", (u64) + jiffies64_to_msecs(df->stats.time_in_state[i])); + } - len += sprintf(buf + len, "%10llu\n", (u64) - jiffies64_to_msecs(df->stats.time_in_state[i])); + if (len < PAGE_SIZE - 1) + len += sysfs_emit_at(buf, len, "Total transition : %u\n", + df->stats.total_trans); + if (len >= PAGE_SIZE - 1) { + pr_warn_once("devfreq transition table exceeds PAGE_SIZE. Disabling\n"); + return -EFBIG; } - len += sprintf(buf + len, "Total transition : %u\n", - df->stats.total_trans); return len; } diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 21916bba77d58b..8fe5aa67b16783 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -46,12 +46,12 @@ static char *dmabuffs_dname(struct dentry *dentry, char *buffer, int buflen) { struct dma_buf *dmabuf; char name[DMA_BUF_NAME_LEN]; - size_t ret = 0; + ssize_t ret = 0; dmabuf = dentry->d_fsdata; spin_lock(&dmabuf->name_lock); if (dmabuf->name) - ret = strlcpy(name, dmabuf->name, DMA_BUF_NAME_LEN); + ret = strscpy(name, dmabuf->name, sizeof(name)); spin_unlock(&dmabuf->name_lock); return dynamic_dname(buffer, buflen, "/%s:%s", diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c index 8aa8f8cb7071ef..e0fd99e61a2d4f 100644 --- a/drivers/dma-buf/dma-fence.c +++ b/drivers/dma-buf/dma-fence.c @@ -934,7 +934,8 @@ EXPORT_SYMBOL(dma_fence_wait_any_timeout); * the GPU's devfreq to reduce frequency, when in fact the opposite is what is * needed. * - * To this end, deadline hint(s) can be set on a &dma_fence via &dma_fence_set_deadline. + * To this end, deadline hint(s) can be set on a &dma_fence via &dma_fence_set_deadline + * (or indirectly via userspace facing ioctls like &sync_set_deadline). * The deadline hint provides a way for the waiting driver, or userspace, to * convey an appropriate sense of urgency to the signaling driver. * diff --git a/drivers/dma-buf/sw_sync.c b/drivers/dma-buf/sw_sync.c index f0a35277fd844c..c353029789cf1a 100644 --- a/drivers/dma-buf/sw_sync.c +++ b/drivers/dma-buf/sw_sync.c @@ -52,12 +52,33 @@ struct sw_sync_create_fence_data { __s32 fence; /* fd of new fence */ }; +/** + * struct sw_sync_get_deadline - get the deadline hint of a sw_sync fence + * @deadline_ns: absolute time of the deadline + * @pad: must be zero + * @fence_fd: the sw_sync fence fd (in) + * + * Return the earliest deadline set on the fence. The timebase for the + * deadline is CLOCK_MONOTONIC (same as vblank). If there is no deadline + * set on the fence, this ioctl will return -ENOENT. + */ +struct sw_sync_get_deadline { + __u64 deadline_ns; + __u32 pad; + __s32 fence_fd; +}; + #define SW_SYNC_IOC_MAGIC 'W' #define SW_SYNC_IOC_CREATE_FENCE _IOWR(SW_SYNC_IOC_MAGIC, 0,\ struct sw_sync_create_fence_data) #define SW_SYNC_IOC_INC _IOW(SW_SYNC_IOC_MAGIC, 1, __u32) +#define SW_SYNC_GET_DEADLINE _IOWR(SW_SYNC_IOC_MAGIC, 2, \ + struct sw_sync_get_deadline) + + +#define SW_SYNC_HAS_DEADLINE_BIT DMA_FENCE_FLAG_USER_BITS static const struct dma_fence_ops timeline_fence_ops; @@ -171,6 +192,22 @@ static void timeline_fence_timeline_value_str(struct dma_fence *fence, snprintf(str, size, "%d", parent->value); } +static void timeline_fence_set_deadline(struct dma_fence *fence, ktime_t deadline) +{ + struct sync_pt *pt = dma_fence_to_sync_pt(fence); + unsigned long flags; + + spin_lock_irqsave(fence->lock, flags); + if (test_bit(SW_SYNC_HAS_DEADLINE_BIT, &fence->flags)) { + if (ktime_before(deadline, pt->deadline)) + pt->deadline = deadline; + } else { + pt->deadline = deadline; + __set_bit(SW_SYNC_HAS_DEADLINE_BIT, &fence->flags); + } + spin_unlock_irqrestore(fence->lock, flags); +} + static const struct dma_fence_ops timeline_fence_ops = { .get_driver_name = timeline_fence_get_driver_name, .get_timeline_name = timeline_fence_get_timeline_name, @@ -179,6 +216,7 @@ static const struct dma_fence_ops timeline_fence_ops = { .release = timeline_fence_release, .fence_value_str = timeline_fence_value_str, .timeline_value_str = timeline_fence_timeline_value_str, + .set_deadline = timeline_fence_set_deadline, }; /** @@ -387,6 +425,47 @@ static long sw_sync_ioctl_inc(struct sync_timeline *obj, unsigned long arg) return 0; } +static int sw_sync_ioctl_get_deadline(struct sync_timeline *obj, unsigned long arg) +{ + struct sw_sync_get_deadline data; + struct dma_fence *fence; + unsigned long flags; + struct sync_pt *pt; + int ret = 0; + + if (copy_from_user(&data, (void __user *)arg, sizeof(data))) + return -EFAULT; + + if (data.deadline_ns || data.pad) + return -EINVAL; + + fence = sync_file_get_fence(data.fence_fd); + if (!fence) + return -EINVAL; + + pt = dma_fence_to_sync_pt(fence); + if (!pt) + return -EINVAL; + + spin_lock_irqsave(fence->lock, flags); + if (test_bit(SW_SYNC_HAS_DEADLINE_BIT, &fence->flags)) { + data.deadline_ns = ktime_to_ns(pt->deadline); + } else { + ret = -ENOENT; + } + spin_unlock_irqrestore(fence->lock, flags); + + dma_fence_put(fence); + + if (ret) + return ret; + + if (copy_to_user((void __user *)arg, &data, sizeof(data))) + return -EFAULT; + + return 0; +} + static long sw_sync_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -399,6 +478,9 @@ static long sw_sync_ioctl(struct file *file, unsigned int cmd, case SW_SYNC_IOC_INC: return sw_sync_ioctl_inc(obj, arg); + case SW_SYNC_GET_DEADLINE: + return sw_sync_ioctl_get_deadline(obj, arg); + default: return -ENOTTY; } diff --git a/drivers/dma-buf/sync_debug.h b/drivers/dma-buf/sync_debug.h index 6176e52ba2d748..a1bdd62efccd86 100644 --- a/drivers/dma-buf/sync_debug.h +++ b/drivers/dma-buf/sync_debug.h @@ -55,11 +55,13 @@ static inline struct sync_timeline *dma_fence_parent(struct dma_fence *fence) * @base: base fence object * @link: link on the sync timeline's list * @node: node in the sync timeline's tree + * @deadline: the earliest fence deadline hint */ struct sync_pt { struct dma_fence base; struct list_head link; struct rb_node node; + ktime_t deadline; }; extern const struct file_operations sw_sync_debugfs_fops; diff --git a/drivers/dma-buf/sync_file.c b/drivers/dma-buf/sync_file.c index 2e9a316c596a3b..d9b1c1b2a72b2c 100644 --- a/drivers/dma-buf/sync_file.c +++ b/drivers/dma-buf/sync_file.c @@ -347,6 +347,22 @@ out: return ret; } +static int sync_file_ioctl_set_deadline(struct sync_file *sync_file, + unsigned long arg) +{ + struct sync_set_deadline ts; + + if (copy_from_user(&ts, (void __user *)arg, sizeof(ts))) + return -EFAULT; + + if (ts.pad) + return -EINVAL; + + dma_fence_set_deadline(sync_file->fence, ns_to_ktime(ts.deadline_ns)); + + return 0; +} + static long sync_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -359,6 +375,9 @@ static long sync_file_ioctl(struct file *file, unsigned int cmd, case SYNC_IOC_FILE_INFO: return sync_file_ioctl_fence_info(sync_file, arg); + case SYNC_IOC_SET_DEADLINE: + return sync_file_ioctl_set_deadline(sync_file, arg); + default: return -ENOTTY; } diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 70ba506dabab5f..e928f2ca0f1e9a 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -378,6 +378,20 @@ config LPC18XX_DMAMUX Enable support for DMA on NXP LPC18xx/43xx platforms with PL080 and multiplexed DMA request lines. +config LS2X_APB_DMA + tristate "Loongson LS2X APB DMA support" + depends on LOONGARCH || COMPILE_TEST + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + help + Support for the Loongson LS2X APB DMA controller driver. The + DMA controller is having single DMA channel which can be + configured for different peripherals like audio, nand, sdio + etc which is in APB bus. + + This DMA controller transfers data from memory to peripheral fifo. + It does not support memory to memory data transfer. + config MCF_EDMA tristate "Freescale eDMA engine support, ColdFire mcf5441x SoCs" depends on M5441x || COMPILE_TEST diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index 83553a97a010e1..dfd40d14e4089d 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_INTEL_IOATDMA) += ioat/ obj-y += idxd/ obj-$(CONFIG_K3_DMA) += k3dma.o obj-$(CONFIG_LPC18XX_DMAMUX) += lpc18xx-dmamux.o +obj-$(CONFIG_LS2X_APB_DMA) += ls2x-apb-dma.o obj-$(CONFIG_MILBEAUT_HDMAC) += milbeaut-hdmac.o obj-$(CONFIG_MILBEAUT_XDMAC) += milbeaut-xdmac.o obj-$(CONFIG_MMP_PDMA) += mmp_pdma.o diff --git a/drivers/dma/apple-admac.c b/drivers/dma/apple-admac.c index 5b63996640d9d3..9588773dd2eb67 100644 --- a/drivers/dma/apple-admac.c +++ b/drivers/dma/apple-admac.c @@ -57,6 +57,8 @@ #define REG_BUS_WIDTH(ch) (0x8040 + (ch) * 0x200) +#define BUS_WIDTH_WORD_SIZE GENMASK(3, 0) +#define BUS_WIDTH_FRAME_SIZE GENMASK(7, 4) #define BUS_WIDTH_8BIT 0x00 #define BUS_WIDTH_16BIT 0x01 #define BUS_WIDTH_32BIT 0x02 @@ -740,7 +742,8 @@ static int admac_device_config(struct dma_chan *chan, struct admac_data *ad = adchan->host; bool is_tx = admac_chan_direction(adchan->no) == DMA_MEM_TO_DEV; int wordsize = 0; - u32 bus_width = 0; + u32 bus_width = readl_relaxed(ad->base + REG_BUS_WIDTH(adchan->no)) & + ~(BUS_WIDTH_WORD_SIZE | BUS_WIDTH_FRAME_SIZE); switch (is_tx ? config->dst_addr_width : config->src_addr_width) { case DMA_SLAVE_BUSWIDTH_1_BYTE: diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c index 2457a420c13d72..4e339c04fc1ea1 100644 --- a/drivers/dma/dma-axi-dmac.c +++ b/drivers/dma/dma-axi-dmac.c @@ -81,9 +81,13 @@ #define AXI_DMAC_REG_CURRENT_DEST_ADDR 0x438 #define AXI_DMAC_REG_PARTIAL_XFER_LEN 0x44c #define AXI_DMAC_REG_PARTIAL_XFER_ID 0x450 +#define AXI_DMAC_REG_CURRENT_SG_ID 0x454 +#define AXI_DMAC_REG_SG_ADDRESS 0x47c +#define AXI_DMAC_REG_SG_ADDRESS_HIGH 0x4bc #define AXI_DMAC_CTRL_ENABLE BIT(0) #define AXI_DMAC_CTRL_PAUSE BIT(1) +#define AXI_DMAC_CTRL_ENABLE_SG BIT(2) #define AXI_DMAC_IRQ_SOT BIT(0) #define AXI_DMAC_IRQ_EOT BIT(1) @@ -97,20 +101,35 @@ /* The maximum ID allocated by the hardware is 31 */ #define AXI_DMAC_SG_UNUSED 32U +/* Flags for axi_dmac_hw_desc.flags */ +#define AXI_DMAC_HW_FLAG_LAST BIT(0) +#define AXI_DMAC_HW_FLAG_IRQ BIT(1) + +struct axi_dmac_hw_desc { + u32 flags; + u32 id; + u64 dest_addr; + u64 src_addr; + u64 next_sg_addr; + u32 y_len; + u32 x_len; + u32 src_stride; + u32 dst_stride; + u64 __pad[2]; +}; + struct axi_dmac_sg { - dma_addr_t src_addr; - dma_addr_t dest_addr; - unsigned int x_len; - unsigned int y_len; - unsigned int dest_stride; - unsigned int src_stride; - unsigned int id; unsigned int partial_len; bool schedule_when_free; + + struct axi_dmac_hw_desc *hw; + dma_addr_t hw_phys; }; struct axi_dmac_desc { struct virt_dma_desc vdesc; + struct axi_dmac_chan *chan; + bool cyclic; bool have_partial_xfer; @@ -139,6 +158,7 @@ struct axi_dmac_chan { bool hw_partial_xfer; bool hw_cyclic; bool hw_2d; + bool hw_sg; }; struct axi_dmac { @@ -213,9 +233,11 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan) unsigned int flags = 0; unsigned int val; - val = axi_dmac_read(dmac, AXI_DMAC_REG_START_TRANSFER); - if (val) /* Queue is full, wait for the next SOT IRQ */ - return; + if (!chan->hw_sg) { + val = axi_dmac_read(dmac, AXI_DMAC_REG_START_TRANSFER); + if (val) /* Queue is full, wait for the next SOT IRQ */ + return; + } desc = chan->next_desc; @@ -229,14 +251,15 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan) sg = &desc->sg[desc->num_submitted]; /* Already queued in cyclic mode. Wait for it to finish */ - if (sg->id != AXI_DMAC_SG_UNUSED) { + if (sg->hw->id != AXI_DMAC_SG_UNUSED) { sg->schedule_when_free = true; return; } - desc->num_submitted++; - if (desc->num_submitted == desc->num_sgs || - desc->have_partial_xfer) { + if (chan->hw_sg) { + chan->next_desc = NULL; + } else if (++desc->num_submitted == desc->num_sgs || + desc->have_partial_xfer) { if (desc->cyclic) desc->num_submitted = 0; /* Start again */ else @@ -246,32 +269,42 @@ static void axi_dmac_start_transfer(struct axi_dmac_chan *chan) chan->next_desc = desc; } - sg->id = axi_dmac_read(dmac, AXI_DMAC_REG_TRANSFER_ID); + sg->hw->id = axi_dmac_read(dmac, AXI_DMAC_REG_TRANSFER_ID); - if (axi_dmac_dest_is_mem(chan)) { - axi_dmac_write(dmac, AXI_DMAC_REG_DEST_ADDRESS, sg->dest_addr); - axi_dmac_write(dmac, AXI_DMAC_REG_DEST_STRIDE, sg->dest_stride); - } + if (!chan->hw_sg) { + if (axi_dmac_dest_is_mem(chan)) { + axi_dmac_write(dmac, AXI_DMAC_REG_DEST_ADDRESS, sg->hw->dest_addr); + axi_dmac_write(dmac, AXI_DMAC_REG_DEST_STRIDE, sg->hw->dst_stride); + } - if (axi_dmac_src_is_mem(chan)) { - axi_dmac_write(dmac, AXI_DMAC_REG_SRC_ADDRESS, sg->src_addr); - axi_dmac_write(dmac, AXI_DMAC_REG_SRC_STRIDE, sg->src_stride); + if (axi_dmac_src_is_mem(chan)) { + axi_dmac_write(dmac, AXI_DMAC_REG_SRC_ADDRESS, sg->hw->src_addr); + axi_dmac_write(dmac, AXI_DMAC_REG_SRC_STRIDE, sg->hw->src_stride); + } } /* * If the hardware supports cyclic transfers and there is no callback to - * call and only a single segment, enable hw cyclic mode to avoid - * unnecessary interrupts. + * call, enable hw cyclic mode to avoid unnecessary interrupts. */ - if (chan->hw_cyclic && desc->cyclic && !desc->vdesc.tx.callback && - desc->num_sgs == 1) - flags |= AXI_DMAC_FLAG_CYCLIC; + if (chan->hw_cyclic && desc->cyclic && !desc->vdesc.tx.callback) { + if (chan->hw_sg) + desc->sg[desc->num_sgs - 1].hw->flags &= ~AXI_DMAC_HW_FLAG_IRQ; + else if (desc->num_sgs == 1) + flags |= AXI_DMAC_FLAG_CYCLIC; + } if (chan->hw_partial_xfer) flags |= AXI_DMAC_FLAG_PARTIAL_REPORT; - axi_dmac_write(dmac, AXI_DMAC_REG_X_LENGTH, sg->x_len - 1); - axi_dmac_write(dmac, AXI_DMAC_REG_Y_LENGTH, sg->y_len - 1); + if (chan->hw_sg) { + axi_dmac_write(dmac, AXI_DMAC_REG_SG_ADDRESS, (u32)sg->hw_phys); + axi_dmac_write(dmac, AXI_DMAC_REG_SG_ADDRESS_HIGH, + (u64)sg->hw_phys >> 32); + } else { + axi_dmac_write(dmac, AXI_DMAC_REG_X_LENGTH, sg->hw->x_len); + axi_dmac_write(dmac, AXI_DMAC_REG_Y_LENGTH, sg->hw->y_len); + } axi_dmac_write(dmac, AXI_DMAC_REG_FLAGS, flags); axi_dmac_write(dmac, AXI_DMAC_REG_START_TRANSFER, 1); } @@ -286,9 +319,9 @@ static inline unsigned int axi_dmac_total_sg_bytes(struct axi_dmac_chan *chan, struct axi_dmac_sg *sg) { if (chan->hw_2d) - return sg->x_len * sg->y_len; + return (sg->hw->x_len + 1) * (sg->hw->y_len + 1); else - return sg->x_len; + return (sg->hw->x_len + 1); } static void axi_dmac_dequeue_partial_xfers(struct axi_dmac_chan *chan) @@ -307,9 +340,9 @@ static void axi_dmac_dequeue_partial_xfers(struct axi_dmac_chan *chan) list_for_each_entry(desc, &chan->active_descs, vdesc.node) { for (i = 0; i < desc->num_sgs; i++) { sg = &desc->sg[i]; - if (sg->id == AXI_DMAC_SG_UNUSED) + if (sg->hw->id == AXI_DMAC_SG_UNUSED) continue; - if (sg->id == id) { + if (sg->hw->id == id) { desc->have_partial_xfer = true; sg->partial_len = len; found_sg = true; @@ -348,6 +381,9 @@ static void axi_dmac_compute_residue(struct axi_dmac_chan *chan, rslt->result = DMA_TRANS_NOERROR; rslt->residue = 0; + if (chan->hw_sg) + return; + /* * We get here if the last completed segment is partial, which * means we can compute the residue from that segment onwards @@ -374,36 +410,47 @@ static bool axi_dmac_transfer_done(struct axi_dmac_chan *chan, (completed_transfers & AXI_DMAC_FLAG_PARTIAL_XFER_DONE)) axi_dmac_dequeue_partial_xfers(chan); - do { - sg = &active->sg[active->num_completed]; - if (sg->id == AXI_DMAC_SG_UNUSED) /* Not yet submitted */ - break; - if (!(BIT(sg->id) & completed_transfers)) - break; - active->num_completed++; - sg->id = AXI_DMAC_SG_UNUSED; - if (sg->schedule_when_free) { - sg->schedule_when_free = false; - start_next = true; + if (chan->hw_sg) { + if (active->cyclic) { + vchan_cyclic_callback(&active->vdesc); + } else { + list_del(&active->vdesc.node); + vchan_cookie_complete(&active->vdesc); + active = axi_dmac_active_desc(chan); + start_next = !!active; } + } else { + do { + sg = &active->sg[active->num_completed]; + if (sg->hw->id == AXI_DMAC_SG_UNUSED) /* Not yet submitted */ + break; + if (!(BIT(sg->hw->id) & completed_transfers)) + break; + active->num_completed++; + sg->hw->id = AXI_DMAC_SG_UNUSED; + if (sg->schedule_when_free) { + sg->schedule_when_free = false; + start_next = true; + } - if (sg->partial_len) - axi_dmac_compute_residue(chan, active); + if (sg->partial_len) + axi_dmac_compute_residue(chan, active); - if (active->cyclic) - vchan_cyclic_callback(&active->vdesc); + if (active->cyclic) + vchan_cyclic_callback(&active->vdesc); - if (active->num_completed == active->num_sgs || - sg->partial_len) { - if (active->cyclic) { - active->num_completed = 0; /* wrap around */ - } else { - list_del(&active->vdesc.node); - vchan_cookie_complete(&active->vdesc); - active = axi_dmac_active_desc(chan); + if (active->num_completed == active->num_sgs || + sg->partial_len) { + if (active->cyclic) { + active->num_completed = 0; /* wrap around */ + } else { + list_del(&active->vdesc.node); + vchan_cookie_complete(&active->vdesc); + active = axi_dmac_active_desc(chan); + } } - } - } while (active); + } while (active); + } return start_next; } @@ -467,8 +514,12 @@ static void axi_dmac_issue_pending(struct dma_chan *c) struct axi_dmac_chan *chan = to_axi_dmac_chan(c); struct axi_dmac *dmac = chan_to_axi_dmac(chan); unsigned long flags; + u32 ctrl = AXI_DMAC_CTRL_ENABLE; - axi_dmac_write(dmac, AXI_DMAC_REG_CTRL, AXI_DMAC_CTRL_ENABLE); + if (chan->hw_sg) + ctrl |= AXI_DMAC_CTRL_ENABLE_SG; + + axi_dmac_write(dmac, AXI_DMAC_REG_CTRL, ctrl); spin_lock_irqsave(&chan->vchan.lock, flags); if (vchan_issue_pending(&chan->vchan)) @@ -476,22 +527,58 @@ static void axi_dmac_issue_pending(struct dma_chan *c) spin_unlock_irqrestore(&chan->vchan.lock, flags); } -static struct axi_dmac_desc *axi_dmac_alloc_desc(unsigned int num_sgs) +static struct axi_dmac_desc * +axi_dmac_alloc_desc(struct axi_dmac_chan *chan, unsigned int num_sgs) { + struct axi_dmac *dmac = chan_to_axi_dmac(chan); + struct device *dev = dmac->dma_dev.dev; + struct axi_dmac_hw_desc *hws; struct axi_dmac_desc *desc; + dma_addr_t hw_phys; unsigned int i; desc = kzalloc(struct_size(desc, sg, num_sgs), GFP_NOWAIT); if (!desc) return NULL; desc->num_sgs = num_sgs; + desc->chan = chan; + + hws = dma_alloc_coherent(dev, PAGE_ALIGN(num_sgs * sizeof(*hws)), + &hw_phys, GFP_ATOMIC); + if (!hws) { + kfree(desc); + return NULL; + } - for (i = 0; i < num_sgs; i++) - desc->sg[i].id = AXI_DMAC_SG_UNUSED; + for (i = 0; i < num_sgs; i++) { + desc->sg[i].hw = &hws[i]; + desc->sg[i].hw_phys = hw_phys + i * sizeof(*hws); + + hws[i].id = AXI_DMAC_SG_UNUSED; + hws[i].flags = 0; + + /* Link hardware descriptors */ + hws[i].next_sg_addr = hw_phys + (i + 1) * sizeof(*hws); + } + + /* The last hardware descriptor will trigger an interrupt */ + desc->sg[num_sgs - 1].hw->flags = AXI_DMAC_HW_FLAG_LAST | AXI_DMAC_HW_FLAG_IRQ; return desc; } +static void axi_dmac_free_desc(struct axi_dmac_desc *desc) +{ + struct axi_dmac *dmac = chan_to_axi_dmac(desc->chan); + struct device *dev = dmac->dma_dev.dev; + struct axi_dmac_hw_desc *hw = desc->sg[0].hw; + dma_addr_t hw_phys = desc->sg[0].hw_phys; + + dma_free_coherent(dev, PAGE_ALIGN(desc->num_sgs * sizeof(*hw)), + hw, hw_phys); + kfree(desc); +} + static struct axi_dmac_sg *axi_dmac_fill_linear_sg(struct axi_dmac_chan *chan, enum dma_transfer_direction direction, dma_addr_t addr, unsigned int num_periods, unsigned int period_len, @@ -508,26 +595,24 @@ static struct axi_dmac_sg *axi_dmac_fill_linear_sg(struct axi_dmac_chan *chan, segment_size = ((segment_size - 1) | chan->length_align_mask) + 1; for (i = 0; i < num_periods; i++) { - len = period_len; - - while (len > segment_size) { + for (len = period_len; len > segment_size; sg++) { if (direction == DMA_DEV_TO_MEM) - sg->dest_addr = addr; + sg->hw->dest_addr = addr; else - sg->src_addr = addr; - sg->x_len = segment_size; - sg->y_len = 1; - sg++; + sg->hw->src_addr = addr; + sg->hw->x_len = segment_size - 1; + sg->hw->y_len = 0; + sg->hw->flags = 0; addr += segment_size; len -= segment_size; } if (direction == DMA_DEV_TO_MEM) - sg->dest_addr = addr; + sg->hw->dest_addr = addr; else - sg->src_addr = addr; - sg->x_len = len; - sg->y_len = 1; + sg->hw->src_addr = addr; + sg->hw->x_len = len - 1; + sg->hw->y_len = 0; sg++; addr += len; } @@ -554,7 +639,7 @@ static struct dma_async_tx_descriptor *axi_dmac_prep_slave_sg( for_each_sg(sgl, sg, sg_len, i) num_sgs += DIV_ROUND_UP(sg_dma_len(sg), chan->max_length); - desc = axi_dmac_alloc_desc(num_sgs); + desc = axi_dmac_alloc_desc(chan, num_sgs); if (!desc) return NULL; @@ -563,7 +648,7 @@ static struct dma_async_tx_descriptor *axi_dmac_prep_slave_sg( for_each_sg(sgl, sg, sg_len, i) { if (!axi_dmac_check_addr(chan, sg_dma_address(sg)) || !axi_dmac_check_len(chan, sg_dma_len(sg))) { - kfree(desc); + axi_dmac_free_desc(desc); return NULL; } @@ -583,7 +668,7 @@ static struct dma_async_tx_descriptor *axi_dmac_prep_dma_cyclic( { struct axi_dmac_chan *chan = to_axi_dmac_chan(c); struct axi_dmac_desc *desc; - unsigned int num_periods, num_segments; + unsigned int num_periods, num_segments, num_sgs; if (direction != chan->direction) return NULL; @@ -597,11 +682,16 @@ static struct dma_async_tx_descriptor *axi_dmac_prep_dma_cyclic( num_periods = buf_len / period_len; num_segments = DIV_ROUND_UP(period_len, chan->max_length); + num_sgs = num_periods * num_segments; - desc = axi_dmac_alloc_desc(num_periods * num_segments); + desc = axi_dmac_alloc_desc(chan, num_sgs); if (!desc) return NULL; + /* Chain the last descriptor to the first, and remove its "last" flag */ + desc->sg[num_sgs - 1].hw->next_sg_addr = desc->sg[0].hw_phys; + desc->sg[num_sgs - 1].hw->flags &= ~AXI_DMAC_HW_FLAG_LAST; + axi_dmac_fill_linear_sg(chan, direction, buf_addr, num_periods, period_len, desc->sg); @@ -653,26 +743,26 @@ static struct dma_async_tx_descriptor *axi_dmac_prep_interleaved( return NULL; } - desc = axi_dmac_alloc_desc(1); + desc = axi_dmac_alloc_desc(chan, 1); if (!desc) return NULL; if (axi_dmac_src_is_mem(chan)) { - desc->sg[0].src_addr = xt->src_start; - desc->sg[0].src_stride = xt->sgl[0].size + src_icg; + desc->sg[0].hw->src_addr = xt->src_start; + desc->sg[0].hw->src_stride = xt->sgl[0].size + src_icg; } if (axi_dmac_dest_is_mem(chan)) { - desc->sg[0].dest_addr = xt->dst_start; - desc->sg[0].dest_stride = xt->sgl[0].size + dst_icg; + desc->sg[0].hw->dest_addr = xt->dst_start; + desc->sg[0].hw->dst_stride = xt->sgl[0].size + dst_icg; } if (chan->hw_2d) { - desc->sg[0].x_len = xt->sgl[0].size; - desc->sg[0].y_len = xt->numf; + desc->sg[0].hw->x_len = xt->sgl[0].size - 1; + desc->sg[0].hw->y_len = xt->numf - 1; } else { - desc->sg[0].x_len = xt->sgl[0].size * xt->numf; - desc->sg[0].y_len = 1; + desc->sg[0].hw->x_len = xt->sgl[0].size * xt->numf - 1; + desc->sg[0].hw->y_len = 0; } if (flags & DMA_CYCLIC) @@ -688,7 +778,7 @@ static void axi_dmac_free_chan_resources(struct dma_chan *c) static void axi_dmac_desc_free(struct virt_dma_desc *vdesc) { - kfree(container_of(vdesc, struct axi_dmac_desc, vdesc)); + axi_dmac_free_desc(to_axi_dmac_desc(vdesc)); } static bool axi_dmac_regmap_rdwr(struct device *dev, unsigned int reg) @@ -714,6 +804,9 @@ static bool axi_dmac_regmap_rdwr(struct device *dev, unsigned int reg) case AXI_DMAC_REG_CURRENT_DEST_ADDR: case AXI_DMAC_REG_PARTIAL_XFER_LEN: case AXI_DMAC_REG_PARTIAL_XFER_ID: + case AXI_DMAC_REG_CURRENT_SG_ID: + case AXI_DMAC_REG_SG_ADDRESS: + case AXI_DMAC_REG_SG_ADDRESS_HIGH: return true; default: return false; @@ -866,6 +959,10 @@ static int axi_dmac_detect_caps(struct axi_dmac *dmac, unsigned int version) if (axi_dmac_read(dmac, AXI_DMAC_REG_FLAGS) == AXI_DMAC_FLAG_CYCLIC) chan->hw_cyclic = true; + axi_dmac_write(dmac, AXI_DMAC_REG_SG_ADDRESS, 0xffffffff); + if (axi_dmac_read(dmac, AXI_DMAC_REG_SG_ADDRESS)) + chan->hw_sg = true; + axi_dmac_write(dmac, AXI_DMAC_REG_Y_LENGTH, 1); if (axi_dmac_read(dmac, AXI_DMAC_REG_Y_LENGTH) == 1) chan->hw_2d = true; @@ -911,6 +1008,7 @@ static int axi_dmac_probe(struct platform_device *pdev) struct axi_dmac *dmac; struct regmap *regmap; unsigned int version; + u32 irq_mask = 0; int ret; dmac = devm_kzalloc(&pdev->dev, sizeof(*dmac), GFP_KERNEL); @@ -966,6 +1064,7 @@ static int axi_dmac_probe(struct platform_device *pdev) dma_dev->dst_addr_widths = BIT(dmac->chan.dest_width); dma_dev->directions = BIT(dmac->chan.direction); dma_dev->residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR; + dma_dev->max_sg_burst = 31; /* 31 SGs maximum in one burst */ INIT_LIST_HEAD(&dma_dev->channels); dmac->chan.vchan.desc_free = axi_dmac_desc_free; @@ -977,7 +1076,10 @@ static int axi_dmac_probe(struct platform_device *pdev) dma_dev->copy_align = (dmac->chan.address_align_mask + 1); - axi_dmac_write(dmac, AXI_DMAC_REG_IRQ_MASK, 0x00); + if (dmac->chan.hw_sg) + irq_mask |= AXI_DMAC_IRQ_SOT; + + axi_dmac_write(dmac, AXI_DMAC_REG_IRQ_MASK, irq_mask); if (of_dma_is_coherent(pdev->dev.of_node)) { ret = axi_dmac_read(dmac, AXI_DMAC_REG_COHERENCY_DESC); diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index b7388ae62d7f1f..491b222402216a 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -1103,6 +1103,9 @@ EXPORT_SYMBOL_GPL(dma_async_device_channel_register); static void __dma_async_device_channel_unregister(struct dma_device *device, struct dma_chan *chan) { + if (chan->local == NULL) + return; + WARN_ONCE(!device->device_release && chan->client_count, "%s called while %d clients hold a reference\n", __func__, chan->client_count); diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index ffe621695e472b..a4f6088378492d 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -21,6 +21,10 @@ #include #include +static bool nobounce; +module_param(nobounce, bool, 0644); +MODULE_PARM_DESC(nobounce, "Prevent using swiotlb buffer (default: use swiotlb buffer)"); + static unsigned int test_buf_size = 16384; module_param(test_buf_size, uint, 0644); MODULE_PARM_DESC(test_buf_size, "Size of the memcpy test buffer"); @@ -90,6 +94,7 @@ MODULE_PARM_DESC(polled, "Use polling for completion instead of interrupts"); /** * struct dmatest_params - test parameters. + * @nobounce: prevent using swiotlb buffer * @buf_size: size of the memcpy test buffer * @channel: bus ID of the channel to test * @device: bus ID of the DMA Engine to test @@ -106,6 +111,7 @@ MODULE_PARM_DESC(polled, "Use polling for completion instead of interrupts"); * @polled: use polling for completion instead of interrupts */ struct dmatest_params { + bool nobounce; unsigned int buf_size; char channel[20]; char device[32]; @@ -215,6 +221,7 @@ struct dmatest_done { struct dmatest_data { u8 **raw; u8 **aligned; + gfp_t gfp_flags; unsigned int cnt; unsigned int off; }; @@ -533,7 +540,7 @@ static int dmatest_alloc_test_data(struct dmatest_data *d, goto err; for (i = 0; i < d->cnt; i++) { - d->raw[i] = kmalloc(buf_size + align, GFP_KERNEL); + d->raw[i] = kmalloc(buf_size + align, d->gfp_flags); if (!d->raw[i]) goto err; @@ -655,6 +662,13 @@ static int dmatest_func(void *data) goto err_free_coefs; } + src->gfp_flags = GFP_KERNEL; + dst->gfp_flags = GFP_KERNEL; + if (params->nobounce) { + src->gfp_flags = GFP_DMA; + dst->gfp_flags = GFP_DMA; + } + if (dmatest_alloc_test_data(src, buf_size, align) < 0) goto err_free_coefs; @@ -1093,6 +1107,7 @@ static void add_threaded_test(struct dmatest_info *info) struct dmatest_params *params = &info->params; /* Copy test parameters */ + params->nobounce = nobounce; params->buf_size = test_buf_size; strscpy(params->channel, strim(test_channel), sizeof(params->channel)); strscpy(params->device, strim(test_device), sizeof(params->device)); diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c index 0745d9e7d259b1..406f169b09a75a 100644 --- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c +++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c @@ -176,7 +176,7 @@ dw_edma_debugfs_regs_wr(struct dw_edma *dw, struct dentry *dent) }; struct dentry *regs_dent, *ch_dent; int nr_entries, i; - char name[16]; + char name[32]; regs_dent = debugfs_create_dir(WRITE_STR, dent); @@ -239,7 +239,7 @@ static noinline_for_stack void dw_edma_debugfs_regs_rd(struct dw_edma *dw, }; struct dentry *regs_dent, *ch_dent; int nr_entries, i; - char name[16]; + char name[32]; regs_dent = debugfs_create_dir(READ_STR, dent); diff --git a/drivers/dma/dw-edma/dw-hdma-v0-debugfs.c b/drivers/dma/dw-edma/dw-hdma-v0-debugfs.c index 520c81978b085f..dcdc57fe976c13 100644 --- a/drivers/dma/dw-edma/dw-hdma-v0-debugfs.c +++ b/drivers/dma/dw-edma/dw-hdma-v0-debugfs.c @@ -116,7 +116,7 @@ static void dw_hdma_debugfs_regs_ch(struct dw_edma *dw, enum dw_edma_dir dir, static void dw_hdma_debugfs_regs_wr(struct dw_edma *dw, struct dentry *dent) { struct dentry *regs_dent, *ch_dent; - char name[16]; + char name[32]; int i; regs_dent = debugfs_create_dir(WRITE_STR, dent); @@ -133,7 +133,7 @@ static void dw_hdma_debugfs_regs_wr(struct dw_edma *dw, struct dentry *dent) static void dw_hdma_debugfs_regs_rd(struct dw_edma *dw, struct dentry *dent) { struct dentry *regs_dent, *ch_dent; - char name[16]; + char name[32]; int i; regs_dent = debugfs_create_dir(READ_STR, dent); diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c index 238a69bd0d6f5d..45cc419b1b4acb 100644 --- a/drivers/dma/fsl-edma-main.c +++ b/drivers/dma/fsl-edma-main.c @@ -9,6 +9,7 @@ * Vybrid and Layerscape SoCs. */ +#include #include #include #include @@ -21,10 +22,6 @@ #include "fsl-edma-common.h" -#define ARGS_RX BIT(0) -#define ARGS_REMOTE BIT(1) -#define ARGS_MULTI_FIFO BIT(2) - static void fsl_edma_synchronize(struct dma_chan *chan) { struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan); @@ -153,9 +150,15 @@ static struct dma_chan *fsl_edma3_xlate(struct of_phandle_args *dma_spec, i = fsl_chan - fsl_edma->chans; fsl_chan->priority = dma_spec->args[1]; - fsl_chan->is_rxchan = dma_spec->args[2] & ARGS_RX; - fsl_chan->is_remote = dma_spec->args[2] & ARGS_REMOTE; - fsl_chan->is_multi_fifo = dma_spec->args[2] & ARGS_MULTI_FIFO; + fsl_chan->is_rxchan = dma_spec->args[2] & FSL_EDMA_RX; + fsl_chan->is_remote = dma_spec->args[2] & FSL_EDMA_REMOTE; + fsl_chan->is_multi_fifo = dma_spec->args[2] & FSL_EDMA_MULTI_FIFO; + + if ((dma_spec->args[2] & FSL_EDMA_EVEN_CH) && (i & 0x1)) + continue; + + if ((dma_spec->args[2] & FSL_EDMA_ODD_CH) && !(i & 0x1)) + continue; if (!b_chmux && i == dma_spec->args[0]) { chan = dma_get_slave_channel(chan); diff --git a/drivers/dma/fsl-qdma.c b/drivers/dma/fsl-qdma.c index 47cb284680494c..a1d0aa63142a98 100644 --- a/drivers/dma/fsl-qdma.c +++ b/drivers/dma/fsl-qdma.c @@ -805,7 +805,7 @@ fsl_qdma_irq_init(struct platform_device *pdev, int i; int cpu; int ret; - char irq_name[20]; + char irq_name[32]; fsl_qdma->error_irq = platform_get_irq_byname(pdev, "qdma-error"); diff --git a/drivers/dma/idxd/Makefile b/drivers/dma/idxd/Makefile index c5e679070e4633..2b4a0d406e1e71 100644 --- a/drivers/dma/idxd/Makefile +++ b/drivers/dma/idxd/Makefile @@ -4,7 +4,7 @@ obj-$(CONFIG_INTEL_IDXD_BUS) += idxd_bus.o idxd_bus-y := bus.o obj-$(CONFIG_INTEL_IDXD) += idxd.o -idxd-y := init.o irq.o device.o sysfs.o submit.o dma.o cdev.o debugfs.o +idxd-y := init.o irq.o device.o sysfs.o submit.o dma.o cdev.o debugfs.o defaults.o idxd-$(CONFIG_INTEL_IDXD_PERFMON) += perfmon.o diff --git a/drivers/dma/idxd/bus.c b/drivers/dma/idxd/bus.c index 6f84621053c678..0c9e689a2e77db 100644 --- a/drivers/dma/idxd/bus.c +++ b/drivers/dma/idxd/bus.c @@ -67,11 +67,17 @@ static void idxd_config_bus_remove(struct device *dev) idxd_drv->remove(idxd_dev); } +static int idxd_bus_uevent(const struct device *dev, struct kobj_uevent_env *env) +{ + return add_uevent_var(env, "MODALIAS=" IDXD_DEVICES_MODALIAS_FMT, 0); +} + struct bus_type dsa_bus_type = { .name = "dsa", .match = idxd_config_bus_match, .probe = idxd_config_bus_probe, .remove = idxd_config_bus_remove, + .uevent = idxd_bus_uevent, }; EXPORT_SYMBOL_GPL(dsa_bus_type); diff --git a/drivers/dma/idxd/cdev.c b/drivers/dma/idxd/cdev.c index 0423655f5a8804..77f8885cf4075a 100644 --- a/drivers/dma/idxd/cdev.c +++ b/drivers/dma/idxd/cdev.c @@ -165,7 +165,7 @@ static void idxd_cdev_dev_release(struct device *dev) struct idxd_wq *wq = idxd_cdev->wq; cdev_ctx = &ictx[wq->idxd->data->type]; - ida_simple_remove(&cdev_ctx->minor_ida, idxd_cdev->minor); + ida_free(&cdev_ctx->minor_ida, idxd_cdev->minor); kfree(idxd_cdev); } @@ -463,7 +463,7 @@ int idxd_wq_add_cdev(struct idxd_wq *wq) cdev = &idxd_cdev->cdev; dev = cdev_dev(idxd_cdev); cdev_ctx = &ictx[wq->idxd->data->type]; - minor = ida_simple_get(&cdev_ctx->minor_ida, 0, MINORMASK, GFP_KERNEL); + minor = ida_alloc_max(&cdev_ctx->minor_ida, MINORMASK, GFP_KERNEL); if (minor < 0) { kfree(idxd_cdev); return minor; @@ -550,7 +550,7 @@ static int idxd_user_drv_probe(struct idxd_dev *idxd_dev) } wq->type = IDXD_WQT_USER; - rc = drv_enable_wq(wq); + rc = idxd_drv_enable_wq(wq); if (rc < 0) goto err; @@ -565,7 +565,7 @@ static int idxd_user_drv_probe(struct idxd_dev *idxd_dev) return 0; err_cdev: - drv_disable_wq(wq); + idxd_drv_disable_wq(wq); err: destroy_workqueue(wq->wq); wq->type = IDXD_WQT_NONE; @@ -580,7 +580,7 @@ static void idxd_user_drv_remove(struct idxd_dev *idxd_dev) mutex_lock(&wq->wq_lock); idxd_wq_del_cdev(wq); - drv_disable_wq(wq); + idxd_drv_disable_wq(wq); wq->type = IDXD_WQT_NONE; destroy_workqueue(wq->wq); wq->wq = NULL; diff --git a/drivers/dma/idxd/defaults.c b/drivers/dma/idxd/defaults.c new file mode 100644 index 00000000000000..c607ae8dd12c61 --- /dev/null +++ b/drivers/dma/idxd/defaults.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2023 Intel Corporation. All rights rsvd. */ +#include +#include "idxd.h" + +int idxd_load_iaa_device_defaults(struct idxd_device *idxd) +{ + struct idxd_engine *engine; + struct idxd_group *group; + struct idxd_wq *wq; + + if (!test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) + return 0; + + wq = idxd->wqs[0]; + + if (wq->state != IDXD_WQ_DISABLED) + return -EPERM; + + /* set mode to "dedicated" */ + set_bit(WQ_FLAG_DEDICATED, &wq->flags); + wq->threshold = 0; + + /* only setting up 1 wq, so give it all the wq space */ + wq->size = idxd->max_wq_size; + + /* set priority to 10 */ + wq->priority = 10; + + /* set type to "kernel" */ + wq->type = IDXD_WQT_KERNEL; + + /* set wq group to 0 */ + group = idxd->groups[0]; + wq->group = group; + group->num_wqs++; + + /* set name to "iaa_crypto" */ + memset(wq->name, 0, WQ_NAME_SIZE + 1); + strscpy(wq->name, "iaa_crypto", WQ_NAME_SIZE + 1); + + /* set driver_name to "crypto" */ + memset(wq->driver_name, 0, DRIVER_NAME_SIZE + 1); + strscpy(wq->driver_name, "crypto", DRIVER_NAME_SIZE + 1); + + engine = idxd->engines[0]; + + /* set engine group to 0 */ + engine->group = idxd->groups[0]; + engine->group->num_engines++; + + return 0; +} diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c index 8f754f922217de..ecfdf4a8f1f838 100644 --- a/drivers/dma/idxd/device.c +++ b/drivers/dma/idxd/device.c @@ -161,6 +161,7 @@ int idxd_wq_alloc_resources(struct idxd_wq *wq) free_hw_descs(wq); return rc; } +EXPORT_SYMBOL_NS_GPL(idxd_wq_alloc_resources, IDXD); void idxd_wq_free_resources(struct idxd_wq *wq) { @@ -174,6 +175,7 @@ void idxd_wq_free_resources(struct idxd_wq *wq) dma_free_coherent(dev, wq->compls_size, wq->compls, wq->compls_addr); sbitmap_queue_free(&wq->sbq); } +EXPORT_SYMBOL_NS_GPL(idxd_wq_free_resources, IDXD); int idxd_wq_enable(struct idxd_wq *wq) { @@ -405,6 +407,7 @@ int idxd_wq_init_percpu_ref(struct idxd_wq *wq) reinit_completion(&wq->wq_resurrect); return 0; } +EXPORT_SYMBOL_NS_GPL(idxd_wq_init_percpu_ref, IDXD); void __idxd_wq_quiesce(struct idxd_wq *wq) { @@ -414,6 +417,7 @@ void __idxd_wq_quiesce(struct idxd_wq *wq) complete_all(&wq->wq_resurrect); wait_for_completion(&wq->wq_dead); } +EXPORT_SYMBOL_NS_GPL(__idxd_wq_quiesce, IDXD); void idxd_wq_quiesce(struct idxd_wq *wq) { @@ -421,6 +425,7 @@ void idxd_wq_quiesce(struct idxd_wq *wq) __idxd_wq_quiesce(wq); mutex_unlock(&wq->wq_lock); } +EXPORT_SYMBOL_NS_GPL(idxd_wq_quiesce, IDXD); /* Device control bits */ static inline bool idxd_is_enabled(struct idxd_device *idxd) @@ -802,6 +807,9 @@ err_bmap: static void idxd_device_evl_free(struct idxd_device *idxd) { + void *evl_log; + unsigned int evl_log_size; + dma_addr_t evl_dma; union gencfg_reg gencfg; union genctrl_reg genctrl; struct device *dev = &idxd->pdev->dev; @@ -822,11 +830,15 @@ static void idxd_device_evl_free(struct idxd_device *idxd) iowrite64(0, idxd->reg_base + IDXD_EVLCFG_OFFSET); iowrite64(0, idxd->reg_base + IDXD_EVLCFG_OFFSET + 8); - dma_free_coherent(dev, evl->log_size, evl->log, evl->dma); bitmap_free(evl->bmap); + evl_log = evl->log; + evl_log_size = evl->log_size; + evl_dma = evl->dma; evl->log = NULL; evl->size = IDXD_EVL_SIZE_MIN; spin_unlock(&evl->lock); + + dma_free_coherent(dev, evl_log_size, evl_log, evl_dma); } static void idxd_group_config_write(struct idxd_group *group) @@ -1266,7 +1278,7 @@ static void idxd_flush_pending_descs(struct idxd_irq_entry *ie) tx = &desc->txd; tx->callback = NULL; tx->callback_result = NULL; - idxd_dma_complete_txd(desc, ctype, true); + idxd_dma_complete_txd(desc, ctype, true, NULL, NULL); } } @@ -1350,7 +1362,7 @@ err_irq: return rc; } -int drv_enable_wq(struct idxd_wq *wq) +int idxd_drv_enable_wq(struct idxd_wq *wq) { struct idxd_device *idxd = wq->idxd; struct device *dev = &idxd->pdev->dev; @@ -1482,8 +1494,9 @@ err_map_portal: err: return rc; } +EXPORT_SYMBOL_NS_GPL(idxd_drv_enable_wq, IDXD); -void drv_disable_wq(struct idxd_wq *wq) +void idxd_drv_disable_wq(struct idxd_wq *wq) { struct idxd_device *idxd = wq->idxd; struct device *dev = &idxd->pdev->dev; @@ -1503,6 +1516,7 @@ void drv_disable_wq(struct idxd_wq *wq) wq->type = IDXD_WQT_NONE; wq->client_count = 0; } +EXPORT_SYMBOL_NS_GPL(idxd_drv_disable_wq, IDXD); int idxd_device_drv_probe(struct idxd_dev *idxd_dev) { diff --git a/drivers/dma/idxd/dma.c b/drivers/dma/idxd/dma.c index 47a01893cfdbf9..cd835eabd31b08 100644 --- a/drivers/dma/idxd/dma.c +++ b/drivers/dma/idxd/dma.c @@ -22,7 +22,7 @@ static inline struct idxd_wq *to_idxd_wq(struct dma_chan *c) void idxd_dma_complete_txd(struct idxd_desc *desc, enum idxd_complete_type comp_type, - bool free_desc) + bool free_desc, void *ctx, u32 *status) { struct idxd_device *idxd = desc->wq->idxd; struct dma_async_tx_descriptor *tx; @@ -314,7 +314,7 @@ static int idxd_dmaengine_drv_probe(struct idxd_dev *idxd_dev) wq->type = IDXD_WQT_KERNEL; - rc = drv_enable_wq(wq); + rc = idxd_drv_enable_wq(wq); if (rc < 0) { dev_dbg(dev, "Enable wq %d failed: %d\n", wq->id, rc); rc = -ENXIO; @@ -333,7 +333,7 @@ static int idxd_dmaengine_drv_probe(struct idxd_dev *idxd_dev) return 0; err_dma: - drv_disable_wq(wq); + idxd_drv_disable_wq(wq); err: wq->type = IDXD_WQT_NONE; mutex_unlock(&wq->wq_lock); @@ -347,7 +347,7 @@ static void idxd_dmaengine_drv_remove(struct idxd_dev *idxd_dev) mutex_lock(&wq->wq_lock); __idxd_wq_quiesce(wq); idxd_unregister_dma_channel(wq); - drv_disable_wq(wq); + idxd_drv_disable_wq(wq); mutex_unlock(&wq->wq_lock); } @@ -359,6 +359,7 @@ static enum idxd_dev_type dev_types[] = { struct idxd_device_driver idxd_dmaengine_drv = { .probe = idxd_dmaengine_drv_probe, .remove = idxd_dmaengine_drv_remove, + .desc_complete = idxd_dma_complete_txd, .name = "dmaengine", .type = dev_types, }; diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h index 1e89c80a07fc25..47de3f93ff1e9a 100644 --- a/drivers/dma/idxd/idxd.h +++ b/drivers/dma/idxd/idxd.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "registers.h" @@ -57,11 +58,23 @@ enum idxd_type { #define IDXD_ENQCMDS_RETRIES 32 #define IDXD_ENQCMDS_MAX_RETRIES 64 +enum idxd_complete_type { + IDXD_COMPLETE_NORMAL = 0, + IDXD_COMPLETE_ABORT, + IDXD_COMPLETE_DEV_FAIL, +}; + +struct idxd_desc; + struct idxd_device_driver { const char *name; enum idxd_dev_type *type; int (*probe)(struct idxd_dev *idxd_dev); void (*remove)(struct idxd_dev *idxd_dev); + void (*desc_complete)(struct idxd_desc *desc, + enum idxd_complete_type comp_type, + bool free_desc, + void *ctx, u32 *status); struct device_driver drv; }; @@ -174,12 +187,6 @@ enum idxd_op_type { IDXD_OP_NONBLOCK = 1, }; -enum idxd_complete_type { - IDXD_COMPLETE_NORMAL = 0, - IDXD_COMPLETE_ABORT, - IDXD_COMPLETE_DEV_FAIL, -}; - struct idxd_dma_chan { struct dma_chan chan; struct idxd_wq *wq; @@ -270,6 +277,8 @@ struct idxd_dma_dev { struct dma_device dma; }; +typedef int (*load_device_defaults_fn_t) (struct idxd_device *idxd); + struct idxd_driver_data { const char *name_prefix; enum idxd_type type; @@ -279,6 +288,7 @@ struct idxd_driver_data { int evl_cr_off; int cr_status_off; int cr_result_off; + load_device_defaults_fn_t load_device_defaults; }; struct idxd_evl { @@ -378,6 +388,14 @@ static inline unsigned int evl_size(struct idxd_device *idxd) return idxd->evl->size * evl_ent_size(idxd); } +struct crypto_ctx { + struct acomp_req *req; + struct crypto_tfm *tfm; + dma_addr_t src_addr; + dma_addr_t dst_addr; + bool compress; +}; + /* IDXD software descriptor */ struct idxd_desc { union { @@ -390,7 +408,10 @@ struct idxd_desc { struct iax_completion_record *iax_completion; }; dma_addr_t compl_dma; - struct dma_async_tx_descriptor txd; + union { + struct dma_async_tx_descriptor txd; + struct crypto_ctx crypto; + }; struct llist_node llnode; struct list_head list; int id; @@ -417,6 +438,15 @@ enum idxd_completion_status { #define idxd_dev_to_idxd(idxd_dev) container_of(idxd_dev, struct idxd_device, idxd_dev) #define idxd_dev_to_wq(idxd_dev) container_of(idxd_dev, struct idxd_wq, idxd_dev) +static inline struct idxd_device_driver *wq_to_idxd_drv(struct idxd_wq *wq) +{ + struct device *dev = wq_confdev(wq); + struct idxd_device_driver *idxd_drv = + container_of(dev->driver, struct idxd_device_driver, drv); + + return idxd_drv; +} + static inline struct idxd_device *confdev_to_idxd(struct device *dev) { struct idxd_dev *idxd_dev = confdev_to_idxd_dev(dev); @@ -618,6 +648,16 @@ static inline int idxd_wq_refcount(struct idxd_wq *wq) return wq->client_count; }; +static inline void idxd_wq_set_private(struct idxd_wq *wq, void *private) +{ + dev_set_drvdata(wq_confdev(wq), private); +} + +static inline void *idxd_wq_get_private(struct idxd_wq *wq) +{ + return dev_get_drvdata(wq_confdev(wq)); +} + /* * Intel IAA does not support batch processing. * The max batch size of device, max batch size of wq and @@ -655,6 +695,9 @@ static inline int idxd_wq_driver_name_match(struct idxd_wq *wq, struct device *d return (strncmp(wq->driver_name, dev->driver->name, strlen(dev->driver->name)) == 0); } +#define MODULE_ALIAS_IDXD_DEVICE(type) MODULE_ALIAS("idxd:t" __stringify(type) "*") +#define IDXD_DEVICES_MODALIAS_FMT "idxd:t%d" + int __must_check __idxd_driver_register(struct idxd_device_driver *idxd_drv, struct module *module, const char *mod_name); #define idxd_driver_register(driver) \ @@ -665,6 +708,24 @@ void idxd_driver_unregister(struct idxd_device_driver *idxd_drv); #define module_idxd_driver(__idxd_driver) \ module_driver(__idxd_driver, idxd_driver_register, idxd_driver_unregister) +void idxd_free_desc(struct idxd_wq *wq, struct idxd_desc *desc); +void idxd_dma_complete_txd(struct idxd_desc *desc, + enum idxd_complete_type comp_type, + bool free_desc, void *ctx, u32 *status); + +static inline void idxd_desc_complete(struct idxd_desc *desc, + enum idxd_complete_type comp_type, + bool free_desc) +{ + struct idxd_device_driver *drv; + u32 status; + + drv = wq_to_idxd_drv(desc->wq); + if (drv->desc_complete) + drv->desc_complete(desc, comp_type, free_desc, + &desc->txd, &status); +} + int idxd_register_bus_type(void); void idxd_unregister_bus_type(void); int idxd_register_devices(struct idxd_device *idxd); @@ -672,6 +733,7 @@ void idxd_unregister_devices(struct idxd_device *idxd); void idxd_wqs_quiesce(struct idxd_device *idxd); bool idxd_queue_int_handle_resubmit(struct idxd_desc *desc); void multi_u64_to_bmap(unsigned long *bmap, u64 *val, int count); +int idxd_load_iaa_device_defaults(struct idxd_device *idxd); /* device interrupt control */ irqreturn_t idxd_misc_thread(int vec, void *data); @@ -682,8 +744,8 @@ void idxd_unmask_error_interrupts(struct idxd_device *idxd); /* device control */ int idxd_device_drv_probe(struct idxd_dev *idxd_dev); void idxd_device_drv_remove(struct idxd_dev *idxd_dev); -int drv_enable_wq(struct idxd_wq *wq); -void drv_disable_wq(struct idxd_wq *wq); +int idxd_drv_enable_wq(struct idxd_wq *wq); +void idxd_drv_disable_wq(struct idxd_wq *wq); int idxd_device_init_reset(struct idxd_device *idxd); int idxd_device_enable(struct idxd_device *idxd); int idxd_device_disable(struct idxd_device *idxd); @@ -718,14 +780,11 @@ int idxd_wq_request_irq(struct idxd_wq *wq); /* submission */ int idxd_submit_desc(struct idxd_wq *wq, struct idxd_desc *desc); struct idxd_desc *idxd_alloc_desc(struct idxd_wq *wq, enum idxd_op_type optype); -void idxd_free_desc(struct idxd_wq *wq, struct idxd_desc *desc); int idxd_enqcmds(struct idxd_wq *wq, void __iomem *portal, const void *desc); /* dmaengine */ int idxd_register_dma_device(struct idxd_device *idxd); void idxd_unregister_dma_device(struct idxd_device *idxd); -void idxd_dma_complete_txd(struct idxd_desc *desc, - enum idxd_complete_type comp_type, bool free_desc); /* cdev */ int idxd_cdev_register(void); diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c index 0eb1c827a215f9..14df1f1347a8dd 100644 --- a/drivers/dma/idxd/init.c +++ b/drivers/dma/idxd/init.c @@ -59,6 +59,7 @@ static struct idxd_driver_data idxd_driver_data[] = { .evl_cr_off = offsetof(struct iax_evl_entry, cr), .cr_status_off = offsetof(struct iax_completion_record, status), .cr_result_off = offsetof(struct iax_completion_record, error_code), + .load_device_defaults = idxd_load_iaa_device_defaults, }, }; @@ -745,6 +746,12 @@ static int idxd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err; } + if (data->load_device_defaults) { + rc = data->load_device_defaults(idxd); + if (rc) + dev_warn(dev, "IDXD loading device defaults failed\n"); + } + rc = idxd_register_devices(idxd); if (rc) { dev_err(dev, "IDXD sysfs setup failed\n"); diff --git a/drivers/dma/idxd/irq.c b/drivers/dma/idxd/irq.c index 2183d7f9cdbdde..c8a0aa874b1153 100644 --- a/drivers/dma/idxd/irq.c +++ b/drivers/dma/idxd/irq.c @@ -123,7 +123,7 @@ static void idxd_abort_invalid_int_handle_descs(struct idxd_irq_entry *ie) list_for_each_entry_safe(d, t, &flist, list) { list_del(&d->list); - idxd_dma_complete_txd(d, IDXD_COMPLETE_ABORT, true); + idxd_desc_complete(d, IDXD_COMPLETE_ABORT, true); } } @@ -534,7 +534,7 @@ static void idxd_int_handle_resubmit_work(struct work_struct *work) */ if (rc != -EAGAIN) { desc->completion->status = IDXD_COMP_DESC_ABORT; - idxd_dma_complete_txd(desc, IDXD_COMPLETE_ABORT, false); + idxd_desc_complete(desc, IDXD_COMPLETE_ABORT, false); } idxd_free_desc(wq, desc); } @@ -575,11 +575,11 @@ static void irq_process_pending_llist(struct idxd_irq_entry *irq_entry) * and 0xff, which DSA_COMP_STATUS_MASK can mask out. */ if (unlikely(desc->completion->status == IDXD_COMP_DESC_ABORT)) { - idxd_dma_complete_txd(desc, IDXD_COMPLETE_ABORT, true); + idxd_desc_complete(desc, IDXD_COMPLETE_ABORT, true); continue; } - idxd_dma_complete_txd(desc, IDXD_COMPLETE_NORMAL, true); + idxd_desc_complete(desc, IDXD_COMPLETE_NORMAL, true); } else { spin_lock(&irq_entry->list_lock); list_add_tail(&desc->list, @@ -618,11 +618,11 @@ static void irq_process_work_list(struct idxd_irq_entry *irq_entry) * and 0xff, which DSA_COMP_STATUS_MASK can mask out. */ if (unlikely(desc->completion->status == IDXD_COMP_DESC_ABORT)) { - idxd_dma_complete_txd(desc, IDXD_COMPLETE_ABORT, true); + idxd_desc_complete(desc, IDXD_COMPLETE_ABORT, true); continue; } - idxd_dma_complete_txd(desc, IDXD_COMPLETE_NORMAL, true); + idxd_desc_complete(desc, IDXD_COMPLETE_NORMAL, true); } } diff --git a/drivers/dma/idxd/submit.c b/drivers/dma/idxd/submit.c index 3f922518e3a525..817a564413b08e 100644 --- a/drivers/dma/idxd/submit.c +++ b/drivers/dma/idxd/submit.c @@ -61,6 +61,7 @@ struct idxd_desc *idxd_alloc_desc(struct idxd_wq *wq, enum idxd_op_type optype) return __get_desc(wq, idx, cpu); } +EXPORT_SYMBOL_NS_GPL(idxd_alloc_desc, IDXD); void idxd_free_desc(struct idxd_wq *wq, struct idxd_desc *desc) { @@ -69,6 +70,7 @@ void idxd_free_desc(struct idxd_wq *wq, struct idxd_desc *desc) desc->cpu = -1; sbitmap_queue_clear(&wq->sbq, desc->id, cpu); } +EXPORT_SYMBOL_NS_GPL(idxd_free_desc, IDXD); static struct idxd_desc *list_abort_desc(struct idxd_wq *wq, struct idxd_irq_entry *ie, struct idxd_desc *desc) @@ -125,7 +127,8 @@ static void llist_abort_desc(struct idxd_wq *wq, struct idxd_irq_entry *ie, spin_unlock(&ie->list_lock); if (found) - idxd_dma_complete_txd(found, IDXD_COMPLETE_ABORT, false); + idxd_dma_complete_txd(found, IDXD_COMPLETE_ABORT, false, + NULL, NULL); /* * completing the descriptor will return desc to allocator and @@ -135,7 +138,8 @@ static void llist_abort_desc(struct idxd_wq *wq, struct idxd_irq_entry *ie, */ list_for_each_entry_safe(d, t, &flist, list) { list_del_init(&d->list); - idxd_dma_complete_txd(found, IDXD_COMPLETE_ABORT, true); + idxd_dma_complete_txd(found, IDXD_COMPLETE_ABORT, true, + NULL, NULL); } } @@ -215,3 +219,4 @@ int idxd_submit_desc(struct idxd_wq *wq, struct idxd_desc *desc) percpu_ref_put(&wq->wq_active); return 0; } +EXPORT_SYMBOL_NS_GPL(idxd_submit_desc, IDXD); diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index f81ecf5863e86e..9b42f5e96b1e0a 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -421,9 +421,7 @@ struct sdma_desc { * @shp_addr: value for gReg[6] * @per_addr: value for gReg[2] * @status: status of dma channel - * @context_loaded: ensure context is only loaded once * @data: specific sdma interface structure - * @bd_pool: dma_pool for bd * @terminate_worker: used to call back into terminate work function * @terminated: terminated list * @is_ram_script: flag for script in ram @@ -486,8 +484,6 @@ struct sdma_channel { * @num_script_addrs: Number of script addresses in this image * @ram_code_start: offset of SDMA ram image in this firmware image * @ram_code_size: size of SDMA ram image - * @script_addrs: Stores the start address of the SDMA scripts - * (in SDMA memory space) */ struct sdma_firmware_header { u32 magic; diff --git a/drivers/dma/ls2x-apb-dma.c b/drivers/dma/ls2x-apb-dma.c new file mode 100644 index 00000000000000..a49913f3ed3f7c --- /dev/null +++ b/drivers/dma/ls2x-apb-dma.c @@ -0,0 +1,705 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Driver for the Loongson LS2X APB DMA Controller + * + * Copyright (C) 2017-2023 Loongson Corporation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dmaengine.h" +#include "virt-dma.h" + +/* Global Configuration Register */ +#define LDMA_ORDER_ERG 0x0 + +/* Bitfield definitions */ + +/* Bitfields in Global Configuration Register */ +#define LDMA_64BIT_EN BIT(0) /* 1: 64 bit support */ +#define LDMA_UNCOHERENT_EN BIT(1) /* 0: cache, 1: uncache */ +#define LDMA_ASK_VALID BIT(2) +#define LDMA_START BIT(3) /* DMA start operation */ +#define LDMA_STOP BIT(4) /* DMA stop operation */ +#define LDMA_CONFIG_MASK GENMASK(4, 0) /* DMA controller config bits mask */ + +/* Bitfields in ndesc_addr field of HW decriptor */ +#define LDMA_DESC_EN BIT(0) /*1: The next descriptor is valid */ +#define LDMA_DESC_ADDR_LOW GENMASK(31, 1) + +/* Bitfields in cmd field of HW decriptor */ +#define LDMA_INT BIT(1) /* Enable DMA interrupts */ +#define LDMA_DATA_DIRECTION BIT(12) /* 1: write to device, 0: read from device */ + +#define LDMA_SLAVE_BUSWIDTHS (BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \ + BIT(DMA_SLAVE_BUSWIDTH_8_BYTES)) + +#define LDMA_MAX_TRANS_LEN U32_MAX + +/*-- descriptors -----------------------------------------------------*/ + +/* + * struct ls2x_dma_hw_desc - DMA HW descriptor + * @ndesc_addr: the next descriptor low address. + * @mem_addr: memory low address. + * @apb_addr: device buffer address. + * @len: length of a piece of carried content, in words. + * @step_len: length between two moved memory data blocks. + * @step_times: number of blocks to be carried in a single DMA operation. + * @cmd: descriptor command or state. + * @stats: DMA status. + * @high_ndesc_addr: the next descriptor high address. + * @high_mem_addr: memory high address. + * @reserved: reserved + */ +struct ls2x_dma_hw_desc { + u32 ndesc_addr; + u32 mem_addr; + u32 apb_addr; + u32 len; + u32 step_len; + u32 step_times; + u32 cmd; + u32 stats; + u32 high_ndesc_addr; + u32 high_mem_addr; + u32 reserved[2]; +} __packed; + +/* + * struct ls2x_dma_sg - ls2x dma scatter gather entry + * @hw: the pointer to DMA HW descriptor. + * @llp: physical address of the DMA HW descriptor. + * @phys: destination or source address(mem). + * @len: number of Bytes to read. + */ +struct ls2x_dma_sg { + struct ls2x_dma_hw_desc *hw; + dma_addr_t llp; + dma_addr_t phys; + u32 len; +}; + +/* + * struct ls2x_dma_desc - software descriptor + * @vdesc: pointer to the virtual dma descriptor. + * @cyclic: flag to dma cyclic + * @burst_size: burst size of transaction, in words. + * @desc_num: number of sg entries. + * @direction: transfer direction, to or from device. + * @status: dma controller status. + * @sg: array of sgs. + */ +struct ls2x_dma_desc { + struct virt_dma_desc vdesc; + bool cyclic; + size_t burst_size; + u32 desc_num; + enum dma_transfer_direction direction; + enum dma_status status; + struct ls2x_dma_sg sg[] __counted_by(desc_num); +}; + +/*-- Channels --------------------------------------------------------*/ + +/* + * struct ls2x_dma_chan - internal representation of an LS2X APB DMA channel + * @vchan: virtual dma channel entry. + * @desc: pointer to the ls2x sw dma descriptor. + * @pool: hw desc table + * @irq: irq line + * @sconfig: configuration for slave transfers, passed via .device_config + */ +struct ls2x_dma_chan { + struct virt_dma_chan vchan; + struct ls2x_dma_desc *desc; + void *pool; + int irq; + struct dma_slave_config sconfig; +}; + +/*-- Controller ------------------------------------------------------*/ + +/* + * struct ls2x_dma_priv - LS2X APB DMAC specific information + * @ddev: dmaengine dma_device object members + * @dma_clk: DMAC clock source + * @regs: memory mapped register base + * @lchan: channel to store ls2x_dma_chan structures + */ +struct ls2x_dma_priv { + struct dma_device ddev; + struct clk *dma_clk; + void __iomem *regs; + struct ls2x_dma_chan lchan; +}; + +/*-- Helper functions ------------------------------------------------*/ + +static inline struct ls2x_dma_desc *to_ldma_desc(struct virt_dma_desc *vdesc) +{ + return container_of(vdesc, struct ls2x_dma_desc, vdesc); +} + +static inline struct ls2x_dma_chan *to_ldma_chan(struct dma_chan *chan) +{ + return container_of(chan, struct ls2x_dma_chan, vchan.chan); +} + +static inline struct ls2x_dma_priv *to_ldma_priv(struct dma_device *ddev) +{ + return container_of(ddev, struct ls2x_dma_priv, ddev); +} + +static struct device *chan2dev(struct dma_chan *chan) +{ + return &chan->dev->device; +} + +static void ls2x_dma_desc_free(struct virt_dma_desc *vdesc) +{ + struct ls2x_dma_chan *lchan = to_ldma_chan(vdesc->tx.chan); + struct ls2x_dma_desc *desc = to_ldma_desc(vdesc); + int i; + + for (i = 0; i < desc->desc_num; i++) { + if (desc->sg[i].hw) + dma_pool_free(lchan->pool, desc->sg[i].hw, + desc->sg[i].llp); + } + + kfree(desc); +} + +static void ls2x_dma_write_cmd(struct ls2x_dma_chan *lchan, bool cmd) +{ + struct ls2x_dma_priv *priv = to_ldma_priv(lchan->vchan.chan.device); + u64 val; + + val = lo_hi_readq(priv->regs + LDMA_ORDER_ERG) & ~LDMA_CONFIG_MASK; + val |= LDMA_64BIT_EN | cmd; + lo_hi_writeq(val, priv->regs + LDMA_ORDER_ERG); +} + +static void ls2x_dma_start_transfer(struct ls2x_dma_chan *lchan) +{ + struct ls2x_dma_priv *priv = to_ldma_priv(lchan->vchan.chan.device); + struct ls2x_dma_sg *ldma_sg; + struct virt_dma_desc *vdesc; + u64 val; + + /* Get the next descriptor */ + vdesc = vchan_next_desc(&lchan->vchan); + if (!vdesc) { + lchan->desc = NULL; + return; + } + + list_del(&vdesc->node); + lchan->desc = to_ldma_desc(vdesc); + ldma_sg = &lchan->desc->sg[0]; + + /* Start DMA */ + lo_hi_writeq(0, priv->regs + LDMA_ORDER_ERG); + val = (ldma_sg->llp & ~LDMA_CONFIG_MASK) | LDMA_64BIT_EN | LDMA_START; + lo_hi_writeq(val, priv->regs + LDMA_ORDER_ERG); +} + +static size_t ls2x_dmac_detect_burst(struct ls2x_dma_chan *lchan) +{ + u32 maxburst, buswidth; + + /* Reject definitely invalid configurations */ + if ((lchan->sconfig.src_addr_width & LDMA_SLAVE_BUSWIDTHS) && + (lchan->sconfig.dst_addr_width & LDMA_SLAVE_BUSWIDTHS)) + return 0; + + if (lchan->sconfig.direction == DMA_MEM_TO_DEV) { + maxburst = lchan->sconfig.dst_maxburst; + buswidth = lchan->sconfig.dst_addr_width; + } else { + maxburst = lchan->sconfig.src_maxburst; + buswidth = lchan->sconfig.src_addr_width; + } + + /* If maxburst is zero, fallback to LDMA_MAX_TRANS_LEN */ + return maxburst ? (maxburst * buswidth) >> 2 : LDMA_MAX_TRANS_LEN; +} + +static void ls2x_dma_fill_desc(struct ls2x_dma_chan *lchan, u32 sg_index, + struct ls2x_dma_desc *desc) +{ + struct ls2x_dma_sg *ldma_sg = &desc->sg[sg_index]; + u32 num_segments, segment_size; + + if (desc->direction == DMA_MEM_TO_DEV) { + ldma_sg->hw->cmd = LDMA_INT | LDMA_DATA_DIRECTION; + ldma_sg->hw->apb_addr = lchan->sconfig.dst_addr; + } else { + ldma_sg->hw->cmd = LDMA_INT; + ldma_sg->hw->apb_addr = lchan->sconfig.src_addr; + } + + ldma_sg->hw->mem_addr = lower_32_bits(ldma_sg->phys); + ldma_sg->hw->high_mem_addr = upper_32_bits(ldma_sg->phys); + + /* Split into multiple equally sized segments if necessary */ + num_segments = DIV_ROUND_UP((ldma_sg->len + 3) >> 2, desc->burst_size); + segment_size = DIV_ROUND_UP((ldma_sg->len + 3) >> 2, num_segments); + + /* Word count register takes input in words */ + ldma_sg->hw->len = segment_size; + ldma_sg->hw->step_times = num_segments; + ldma_sg->hw->step_len = 0; + + /* lets make a link list */ + if (sg_index) { + desc->sg[sg_index - 1].hw->ndesc_addr = ldma_sg->llp | LDMA_DESC_EN; + desc->sg[sg_index - 1].hw->high_ndesc_addr = upper_32_bits(ldma_sg->llp); + } +} + +/*-- DMA Engine API --------------------------------------------------*/ + +/* + * ls2x_dma_alloc_chan_resources - allocate resources for DMA channel + * @chan: allocate descriptor resources for this channel + * + * return - the number of allocated descriptors + */ +static int ls2x_dma_alloc_chan_resources(struct dma_chan *chan) +{ + struct ls2x_dma_chan *lchan = to_ldma_chan(chan); + + /* Create a pool of consistent memory blocks for hardware descriptors */ + lchan->pool = dma_pool_create(dev_name(chan2dev(chan)), + chan->device->dev, PAGE_SIZE, + __alignof__(struct ls2x_dma_hw_desc), 0); + if (!lchan->pool) { + dev_err(chan2dev(chan), "No memory for descriptors\n"); + return -ENOMEM; + } + + return 1; +} + +/* + * ls2x_dma_free_chan_resources - free all channel resources + * @chan: DMA channel + */ +static void ls2x_dma_free_chan_resources(struct dma_chan *chan) +{ + struct ls2x_dma_chan *lchan = to_ldma_chan(chan); + + vchan_free_chan_resources(to_virt_chan(chan)); + dma_pool_destroy(lchan->pool); + lchan->pool = NULL; +} + +/* + * ls2x_dma_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction + * @chan: DMA channel + * @sgl: scatterlist to transfer to/from + * @sg_len: number of entries in @scatterlist + * @direction: DMA direction + * @flags: tx descriptor status flags + * @context: transaction context (ignored) + * + * Return: Async transaction descriptor on success and NULL on failure + */ +static struct dma_async_tx_descriptor * +ls2x_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, + u32 sg_len, enum dma_transfer_direction direction, + unsigned long flags, void *context) +{ + struct ls2x_dma_chan *lchan = to_ldma_chan(chan); + struct ls2x_dma_desc *desc; + struct scatterlist *sg; + size_t burst_size; + int i; + + if (unlikely(!sg_len || !is_slave_direction(direction))) + return NULL; + + burst_size = ls2x_dmac_detect_burst(lchan); + if (!burst_size) + return NULL; + + desc = kzalloc(struct_size(desc, sg, sg_len), GFP_NOWAIT); + if (!desc) + return NULL; + + desc->desc_num = sg_len; + desc->direction = direction; + desc->burst_size = burst_size; + + for_each_sg(sgl, sg, sg_len, i) { + struct ls2x_dma_sg *ldma_sg = &desc->sg[i]; + + /* Allocate DMA capable memory for hardware descriptor */ + ldma_sg->hw = dma_pool_alloc(lchan->pool, GFP_NOWAIT, &ldma_sg->llp); + if (!ldma_sg->hw) { + desc->desc_num = i; + ls2x_dma_desc_free(&desc->vdesc); + return NULL; + } + + ldma_sg->phys = sg_dma_address(sg); + ldma_sg->len = sg_dma_len(sg); + + ls2x_dma_fill_desc(lchan, i, desc); + } + + /* Setting the last descriptor enable bit */ + desc->sg[sg_len - 1].hw->ndesc_addr &= ~LDMA_DESC_EN; + desc->status = DMA_IN_PROGRESS; + + return vchan_tx_prep(&lchan->vchan, &desc->vdesc, flags); +} + +/* + * ls2x_dma_prep_dma_cyclic - prepare the cyclic DMA transfer + * @chan: the DMA channel to prepare + * @buf_addr: physical DMA address where the buffer starts + * @buf_len: total number of bytes for the entire buffer + * @period_len: number of bytes for each period + * @direction: transfer direction, to or from device + * @flags: tx descriptor status flags + * + * Return: Async transaction descriptor on success and NULL on failure + */ +static struct dma_async_tx_descriptor * +ls2x_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, + size_t period_len, enum dma_transfer_direction direction, + unsigned long flags) +{ + struct ls2x_dma_chan *lchan = to_ldma_chan(chan); + struct ls2x_dma_desc *desc; + size_t burst_size; + u32 num_periods; + int i; + + if (unlikely(!buf_len || !period_len)) + return NULL; + + if (unlikely(!is_slave_direction(direction))) + return NULL; + + burst_size = ls2x_dmac_detect_burst(lchan); + if (!burst_size) + return NULL; + + num_periods = buf_len / period_len; + desc = kzalloc(struct_size(desc, sg, num_periods), GFP_NOWAIT); + if (!desc) + return NULL; + + desc->desc_num = num_periods; + desc->direction = direction; + desc->burst_size = burst_size; + + /* Build cyclic linked list */ + for (i = 0; i < num_periods; i++) { + struct ls2x_dma_sg *ldma_sg = &desc->sg[i]; + + /* Allocate DMA capable memory for hardware descriptor */ + ldma_sg->hw = dma_pool_alloc(lchan->pool, GFP_NOWAIT, &ldma_sg->llp); + if (!ldma_sg->hw) { + desc->desc_num = i; + ls2x_dma_desc_free(&desc->vdesc); + return NULL; + } + + ldma_sg->phys = buf_addr + period_len * i; + ldma_sg->len = period_len; + + ls2x_dma_fill_desc(lchan, i, desc); + } + + /* Lets make a cyclic list */ + desc->sg[num_periods - 1].hw->ndesc_addr = desc->sg[0].llp | LDMA_DESC_EN; + desc->sg[num_periods - 1].hw->high_ndesc_addr = upper_32_bits(desc->sg[0].llp); + desc->cyclic = true; + desc->status = DMA_IN_PROGRESS; + + return vchan_tx_prep(&lchan->vchan, &desc->vdesc, flags); +} + +/* + * ls2x_slave_config - set slave configuration for channel + * @chan: dma channel + * @cfg: slave configuration + * + * Sets slave configuration for channel + */ +static int ls2x_dma_slave_config(struct dma_chan *chan, + struct dma_slave_config *config) +{ + struct ls2x_dma_chan *lchan = to_ldma_chan(chan); + + memcpy(&lchan->sconfig, config, sizeof(*config)); + return 0; +} + +/* + * ls2x_dma_issue_pending - push pending transactions to the hardware + * @chan: channel + * + * When this function is called, all pending transactions are pushed to the + * hardware and executed. + */ +static void ls2x_dma_issue_pending(struct dma_chan *chan) +{ + struct ls2x_dma_chan *lchan = to_ldma_chan(chan); + unsigned long flags; + + spin_lock_irqsave(&lchan->vchan.lock, flags); + if (vchan_issue_pending(&lchan->vchan) && !lchan->desc) + ls2x_dma_start_transfer(lchan); + spin_unlock_irqrestore(&lchan->vchan.lock, flags); +} + +/* + * ls2x_dma_terminate_all - terminate all transactions + * @chan: channel + * + * Stops all DMA transactions. + */ +static int ls2x_dma_terminate_all(struct dma_chan *chan) +{ + struct ls2x_dma_chan *lchan = to_ldma_chan(chan); + unsigned long flags; + LIST_HEAD(head); + + spin_lock_irqsave(&lchan->vchan.lock, flags); + /* Setting stop cmd */ + ls2x_dma_write_cmd(lchan, LDMA_STOP); + if (lchan->desc) { + vchan_terminate_vdesc(&lchan->desc->vdesc); + lchan->desc = NULL; + } + + vchan_get_all_descriptors(&lchan->vchan, &head); + spin_unlock_irqrestore(&lchan->vchan.lock, flags); + + vchan_dma_desc_free_list(&lchan->vchan, &head); + return 0; +} + +/* + * ls2x_dma_synchronize - Synchronizes the termination of transfers to the + * current context. + * @chan: channel + */ +static void ls2x_dma_synchronize(struct dma_chan *chan) +{ + struct ls2x_dma_chan *lchan = to_ldma_chan(chan); + + vchan_synchronize(&lchan->vchan); +} + +static int ls2x_dma_pause(struct dma_chan *chan) +{ + struct ls2x_dma_chan *lchan = to_ldma_chan(chan); + unsigned long flags; + + spin_lock_irqsave(&lchan->vchan.lock, flags); + if (lchan->desc && lchan->desc->status == DMA_IN_PROGRESS) { + ls2x_dma_write_cmd(lchan, LDMA_STOP); + lchan->desc->status = DMA_PAUSED; + } + spin_unlock_irqrestore(&lchan->vchan.lock, flags); + + return 0; +} + +static int ls2x_dma_resume(struct dma_chan *chan) +{ + struct ls2x_dma_chan *lchan = to_ldma_chan(chan); + unsigned long flags; + + spin_lock_irqsave(&lchan->vchan.lock, flags); + if (lchan->desc && lchan->desc->status == DMA_PAUSED) { + lchan->desc->status = DMA_IN_PROGRESS; + ls2x_dma_write_cmd(lchan, LDMA_START); + } + spin_unlock_irqrestore(&lchan->vchan.lock, flags); + + return 0; +} + +/* + * ls2x_dma_isr - LS2X DMA Interrupt handler + * @irq: IRQ number + * @dev_id: Pointer to ls2x_dma_chan + * + * Return: IRQ_HANDLED/IRQ_NONE + */ +static irqreturn_t ls2x_dma_isr(int irq, void *dev_id) +{ + struct ls2x_dma_chan *lchan = dev_id; + struct ls2x_dma_desc *desc; + + spin_lock(&lchan->vchan.lock); + desc = lchan->desc; + if (desc) { + if (desc->cyclic) { + vchan_cyclic_callback(&desc->vdesc); + } else { + desc->status = DMA_COMPLETE; + vchan_cookie_complete(&desc->vdesc); + ls2x_dma_start_transfer(lchan); + } + + /* ls2x_dma_start_transfer() updates lchan->desc */ + if (!lchan->desc) + ls2x_dma_write_cmd(lchan, LDMA_STOP); + } + spin_unlock(&lchan->vchan.lock); + + return IRQ_HANDLED; +} + +static int ls2x_dma_chan_init(struct platform_device *pdev, + struct ls2x_dma_priv *priv) +{ + struct ls2x_dma_chan *lchan = &priv->lchan; + struct device *dev = &pdev->dev; + int ret; + + lchan->irq = platform_get_irq(pdev, 0); + if (lchan->irq < 0) + return lchan->irq; + + ret = devm_request_irq(dev, lchan->irq, ls2x_dma_isr, IRQF_TRIGGER_RISING, + dev_name(&pdev->dev), lchan); + if (ret) + return ret; + + /* Initialize channels related values */ + INIT_LIST_HEAD(&priv->ddev.channels); + lchan->vchan.desc_free = ls2x_dma_desc_free; + vchan_init(&lchan->vchan, &priv->ddev); + + return 0; +} + +/* + * ls2x_dma_probe - Driver probe function + * @pdev: Pointer to the platform_device structure + * + * Return: '0' on success and failure value on error + */ +static int ls2x_dma_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ls2x_dma_priv *priv; + struct dma_device *ddev; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->regs)) + return dev_err_probe(dev, PTR_ERR(priv->regs), + "devm_platform_ioremap_resource failed.\n"); + + priv->dma_clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(priv->dma_clk)) + return dev_err_probe(dev, PTR_ERR(priv->dma_clk), "devm_clk_get failed.\n"); + + ret = clk_prepare_enable(priv->dma_clk); + if (ret) + return dev_err_probe(dev, ret, "clk_prepare_enable failed.\n"); + + ret = ls2x_dma_chan_init(pdev, priv); + if (ret) + goto disable_clk; + + ddev = &priv->ddev; + ddev->dev = dev; + dma_cap_zero(ddev->cap_mask); + dma_cap_set(DMA_SLAVE, ddev->cap_mask); + dma_cap_set(DMA_CYCLIC, ddev->cap_mask); + + ddev->device_alloc_chan_resources = ls2x_dma_alloc_chan_resources; + ddev->device_free_chan_resources = ls2x_dma_free_chan_resources; + ddev->device_tx_status = dma_cookie_status; + ddev->device_issue_pending = ls2x_dma_issue_pending; + ddev->device_prep_slave_sg = ls2x_dma_prep_slave_sg; + ddev->device_prep_dma_cyclic = ls2x_dma_prep_dma_cyclic; + ddev->device_config = ls2x_dma_slave_config; + ddev->device_terminate_all = ls2x_dma_terminate_all; + ddev->device_synchronize = ls2x_dma_synchronize; + ddev->device_pause = ls2x_dma_pause; + ddev->device_resume = ls2x_dma_resume; + + ddev->src_addr_widths = LDMA_SLAVE_BUSWIDTHS; + ddev->dst_addr_widths = LDMA_SLAVE_BUSWIDTHS; + ddev->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); + + ret = dma_async_device_register(&priv->ddev); + if (ret < 0) + goto disable_clk; + + ret = of_dma_controller_register(dev->of_node, of_dma_xlate_by_chan_id, priv); + if (ret < 0) + goto unregister_dmac; + + platform_set_drvdata(pdev, priv); + + dev_info(dev, "Loongson LS2X APB DMA driver registered successfully.\n"); + return 0; + +unregister_dmac: + dma_async_device_unregister(&priv->ddev); +disable_clk: + clk_disable_unprepare(priv->dma_clk); + + return ret; +} + +/* + * ls2x_dma_remove - Driver remove function + * @pdev: Pointer to the platform_device structure + */ +static void ls2x_dma_remove(struct platform_device *pdev) +{ + struct ls2x_dma_priv *priv = platform_get_drvdata(pdev); + + of_dma_controller_free(pdev->dev.of_node); + dma_async_device_unregister(&priv->ddev); + clk_disable_unprepare(priv->dma_clk); +} + +static const struct of_device_id ls2x_dma_of_match_table[] = { + { .compatible = "loongson,ls2k1000-apbdma" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ls2x_dma_of_match_table); + +static struct platform_driver ls2x_dmac_driver = { + .probe = ls2x_dma_probe, + .remove_new = ls2x_dma_remove, + .driver = { + .name = "ls2x-apbdma", + .of_match_table = ls2x_dma_of_match_table, + }, +}; +module_platform_driver(ls2x_dmac_driver); + +MODULE_DESCRIPTION("Loongson LS2X APB DMA Controller driver"); +MODULE_AUTHOR("Loongson Technology Corporation Limited"); +MODULE_LICENSE("GPL"); diff --git a/drivers/dma/milbeaut-hdmac.c b/drivers/dma/milbeaut-hdmac.c index 1b0a95892627d6..7b41c670970a65 100644 --- a/drivers/dma/milbeaut-hdmac.c +++ b/drivers/dma/milbeaut-hdmac.c @@ -531,7 +531,7 @@ disable_clk: return ret; } -static int milbeaut_hdmac_remove(struct platform_device *pdev) +static void milbeaut_hdmac_remove(struct platform_device *pdev) { struct milbeaut_hdmac_device *mdev = platform_get_drvdata(pdev); struct dma_chan *chan; @@ -546,16 +546,21 @@ static int milbeaut_hdmac_remove(struct platform_device *pdev) */ list_for_each_entry(chan, &mdev->ddev.channels, device_node) { ret = dmaengine_terminate_sync(chan); - if (ret) - return ret; + if (ret) { + /* + * This results in resource leakage and maybe also + * use-after-free errors as e.g. *mdev is kfreed. + */ + dev_alert(&pdev->dev, "Failed to terminate channel %d (%pe)\n", + chan->chan_id, ERR_PTR(ret)); + return; + } milbeaut_hdmac_free_chan_resources(chan); } of_dma_controller_free(pdev->dev.of_node); dma_async_device_unregister(&mdev->ddev); clk_disable_unprepare(mdev->clk); - - return 0; } static const struct of_device_id milbeaut_hdmac_match[] = { @@ -566,7 +571,7 @@ MODULE_DEVICE_TABLE(of, milbeaut_hdmac_match); static struct platform_driver milbeaut_hdmac_driver = { .probe = milbeaut_hdmac_probe, - .remove = milbeaut_hdmac_remove, + .remove_new = milbeaut_hdmac_remove, .driver = { .name = "milbeaut-m10v-hdmac", .of_match_table = milbeaut_hdmac_match, diff --git a/drivers/dma/milbeaut-xdmac.c b/drivers/dma/milbeaut-xdmac.c index d29d01e730aa09..2cce529b448eb7 100644 --- a/drivers/dma/milbeaut-xdmac.c +++ b/drivers/dma/milbeaut-xdmac.c @@ -368,7 +368,7 @@ disable_xdmac: return ret; } -static int milbeaut_xdmac_remove(struct platform_device *pdev) +static void milbeaut_xdmac_remove(struct platform_device *pdev) { struct milbeaut_xdmac_device *mdev = platform_get_drvdata(pdev); struct dma_chan *chan; @@ -383,8 +383,15 @@ static int milbeaut_xdmac_remove(struct platform_device *pdev) */ list_for_each_entry(chan, &mdev->ddev.channels, device_node) { ret = dmaengine_terminate_sync(chan); - if (ret) - return ret; + if (ret) { + /* + * This results in resource leakage and maybe also + * use-after-free errors as e.g. *mdev is kfreed. + */ + dev_alert(&pdev->dev, "Failed to terminate channel %d (%pe)\n", + chan->chan_id, ERR_PTR(ret)); + return; + } milbeaut_xdmac_free_chan_resources(chan); } @@ -392,8 +399,6 @@ static int milbeaut_xdmac_remove(struct platform_device *pdev) dma_async_device_unregister(&mdev->ddev); disable_xdmac(mdev); - - return 0; } static const struct of_device_id milbeaut_xdmac_match[] = { @@ -404,7 +409,7 @@ MODULE_DEVICE_TABLE(of, milbeaut_xdmac_match); static struct platform_driver milbeaut_xdmac_driver = { .probe = milbeaut_xdmac_probe, - .remove = milbeaut_xdmac_remove, + .remove_new = milbeaut_xdmac_remove, .driver = { .name = "milbeaut-m10v-xdmac", .of_match_table = milbeaut_xdmac_match, diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 3cf0b38387ae56..c29744bfdf2c2a 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -1053,6 +1053,9 @@ static bool _trigger(struct pl330_thread *thrd) thrd->req_running = idx; + if (desc->rqtype == DMA_MEM_TO_DEV || desc->rqtype == DMA_DEV_TO_MEM) + UNTIL(thrd, PL330_STATE_WFP); + return true; } diff --git a/drivers/dma/sf-pdma/sf-pdma.c b/drivers/dma/sf-pdma/sf-pdma.c index 3125a2f162b478..428473611115d1 100644 --- a/drivers/dma/sf-pdma/sf-pdma.c +++ b/drivers/dma/sf-pdma/sf-pdma.c @@ -20,10 +20,13 @@ #include #include #include +#include #include #include "sf-pdma.h" +#define PDMA_QUIRK_NO_STRICT_ORDERING BIT(0) + #ifndef readq static inline unsigned long long readq(void __iomem *addr) { @@ -65,7 +68,7 @@ static struct sf_pdma_desc *sf_pdma_alloc_desc(struct sf_pdma_chan *chan) static void sf_pdma_fill_desc(struct sf_pdma_desc *desc, u64 dst, u64 src, u64 size) { - desc->xfer_type = PDMA_FULL_SPEED; + desc->xfer_type = desc->chan->pdma->transfer_type; desc->xfer_size = size; desc->dst_addr = dst; desc->src_addr = src; @@ -492,6 +495,7 @@ static void sf_pdma_setup_chans(struct sf_pdma *pdma) static int sf_pdma_probe(struct platform_device *pdev) { + const struct sf_pdma_driver_platdata *ddata; struct sf_pdma *pdma; int ret, n_chans; const enum dma_slave_buswidth widths = @@ -517,6 +521,14 @@ static int sf_pdma_probe(struct platform_device *pdev) pdma->n_chans = n_chans; + pdma->transfer_type = PDMA_FULL_SPEED | PDMA_STRICT_ORDERING; + + ddata = device_get_match_data(&pdev->dev); + if (ddata) { + if (ddata->quirks & PDMA_QUIRK_NO_STRICT_ORDERING) + pdma->transfer_type &= ~PDMA_STRICT_ORDERING; + } + pdma->membase = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(pdma->membase)) return PTR_ERR(pdma->membase); @@ -563,7 +575,20 @@ static int sf_pdma_probe(struct platform_device *pdev) return ret; } + ret = of_dma_controller_register(pdev->dev.of_node, + of_dma_xlate_by_chan_id, pdma); + if (ret < 0) { + dev_err(&pdev->dev, + "Can't register SiFive Platform OF_DMA. (%d)\n", ret); + goto err_unregister; + } + return 0; + +err_unregister: + dma_async_device_unregister(&pdma->dma_dev); + + return ret; } static void sf_pdma_remove(struct platform_device *pdev) @@ -583,12 +608,25 @@ static void sf_pdma_remove(struct platform_device *pdev) tasklet_kill(&ch->err_tasklet); } + if (pdev->dev.of_node) + of_dma_controller_free(pdev->dev.of_node); + dma_async_device_unregister(&pdma->dma_dev); } +static const struct sf_pdma_driver_platdata mpfs_pdma = { + .quirks = PDMA_QUIRK_NO_STRICT_ORDERING, +}; + static const struct of_device_id sf_pdma_dt_ids[] = { - { .compatible = "sifive,fu540-c000-pdma" }, - { .compatible = "sifive,pdma0" }, + { + .compatible = "sifive,fu540-c000-pdma", + }, { + .compatible = "sifive,pdma0", + }, { + .compatible = "microchip,mpfs-pdma", + .data = &mpfs_pdma, + }, {}, }; MODULE_DEVICE_TABLE(of, sf_pdma_dt_ids); diff --git a/drivers/dma/sf-pdma/sf-pdma.h b/drivers/dma/sf-pdma/sf-pdma.h index d05772b5d8d3fd..215e07183d7e26 100644 --- a/drivers/dma/sf-pdma/sf-pdma.h +++ b/drivers/dma/sf-pdma/sf-pdma.h @@ -48,7 +48,8 @@ #define PDMA_ERR_STATUS_MASK GENMASK(31, 31) /* Transfer Type */ -#define PDMA_FULL_SPEED 0xFF000008 +#define PDMA_FULL_SPEED 0xFF000000 +#define PDMA_STRICT_ORDERING BIT(3) /* Error Recovery */ #define MAX_RETRY 1 @@ -112,8 +113,13 @@ struct sf_pdma { struct dma_device dma_dev; void __iomem *membase; void __iomem *mappedbase; + u32 transfer_type; u32 n_chans; struct sf_pdma_chan chans[] __counted_by(n_chans); }; +struct sf_pdma_driver_platdata { + u32 quirks; +}; + #endif /* _SF_PDMA_H */ diff --git a/drivers/dma/sh/rz-dmac.c b/drivers/dma/sh/rz-dmac.c index fea5bda34bc20f..1f1e86ba5c66aa 100644 --- a/drivers/dma/sh/rz-dmac.c +++ b/drivers/dma/sh/rz-dmac.c @@ -755,11 +755,11 @@ static struct dma_chan *rz_dmac_of_xlate(struct of_phandle_args *dma_spec, static int rz_dmac_chan_probe(struct rz_dmac *dmac, struct rz_dmac_chan *channel, - unsigned int index) + u8 index) { struct platform_device *pdev = to_platform_device(dmac->dev); struct rz_lmdesc *lmdesc; - char pdev_irqname[5]; + char pdev_irqname[6]; char *irqname; int ret; @@ -767,7 +767,7 @@ static int rz_dmac_chan_probe(struct rz_dmac *dmac, channel->mid_rid = -EINVAL; /* Request the channel interrupt. */ - sprintf(pdev_irqname, "ch%u", index); + scnprintf(pdev_irqname, sizeof(pdev_irqname), "ch%u", index); channel->irq = platform_get_irq_byname(pdev, pdev_irqname); if (channel->irq < 0) return channel->irq; @@ -845,9 +845,9 @@ static int rz_dmac_probe(struct platform_device *pdev) struct dma_device *engine; struct rz_dmac *dmac; int channel_num; - unsigned int i; int ret; int irq; + u8 i; dmac = devm_kzalloc(&pdev->dev, sizeof(*dmac), GFP_KERNEL); if (!dmac) diff --git a/drivers/dma/sh/shdma.h b/drivers/dma/sh/shdma.h index 9c121a4b33ad82..f97d80343aea42 100644 --- a/drivers/dma/sh/shdma.h +++ b/drivers/dma/sh/shdma.h @@ -25,7 +25,7 @@ struct sh_dmae_chan { const struct sh_dmae_slave_config *config; /* Slave DMA configuration */ int xmit_shift; /* log_2(bytes_per_xfer) */ void __iomem *base; - char dev_id[16]; /* unique name per DMAC of channel */ + char dev_id[32]; /* unique name per DMAC of channel */ int pm_error; dma_addr_t slave_addr; }; diff --git a/drivers/dma/sh/usb-dmac.c b/drivers/dma/sh/usb-dmac.c index a9b4302f605014..f7cd0cad056c16 100644 --- a/drivers/dma/sh/usb-dmac.c +++ b/drivers/dma/sh/usb-dmac.c @@ -706,10 +706,10 @@ static const struct dev_pm_ops usb_dmac_pm = { static int usb_dmac_chan_probe(struct usb_dmac *dmac, struct usb_dmac_chan *uchan, - unsigned int index) + u8 index) { struct platform_device *pdev = to_platform_device(dmac->dev); - char pdev_irqname[5]; + char pdev_irqname[6]; char *irqname; int ret; @@ -717,7 +717,7 @@ static int usb_dmac_chan_probe(struct usb_dmac *dmac, uchan->iomem = dmac->iomem + USB_DMAC_CHAN_OFFSET(index); /* Request the channel interrupt. */ - sprintf(pdev_irqname, "ch%u", index); + scnprintf(pdev_irqname, sizeof(pdev_irqname), "ch%u", index); uchan->irq = platform_get_irq_byname(pdev, pdev_irqname); if (uchan->irq < 0) return -ENODEV; @@ -768,8 +768,8 @@ 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; - unsigned int i; int ret; + u8 i; dmac = devm_kzalloc(&pdev->dev, sizeof(*dmac), GFP_KERNEL); if (!dmac) @@ -869,7 +869,7 @@ static void usb_dmac_chan_remove(struct usb_dmac *dmac, static void usb_dmac_remove(struct platform_device *pdev) { struct usb_dmac *dmac = platform_get_drvdata(pdev); - int i; + u8 i; for (i = 0; i < dmac->n_channels; ++i) usb_dmac_chan_remove(dmac, &dmac->channels[i]); diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 002833fb1fa04c..2c489299148eee 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -31,13 +31,11 @@ /** * struct stedma40_platform_data - Configuration struct for the dma device. * - * @dev_tx: mapping between destination event line and io address - * @dev_rx: mapping between source event line and io address * @disabled_channels: A vector, ending with -1, that marks physical channels * that are for different reasons not available for the driver. * @soft_lli_chans: A vector, that marks physical channels will use LLI by SW * which avoids HW bug that exists in some versions of the controller. - * SoftLLI introduces relink overhead that could impact performace for + * SoftLLI introduces relink overhead that could impact performance for * certain use cases. * @num_of_soft_lli_chans: The number of channels that needs to be configured * to use SoftLLI. @@ -184,7 +182,7 @@ static __maybe_unused u32 d40_backup_regs[] = { /* * since 9540 and 8540 has the same HW revision - * use v4a for 9540 or ealier + * use v4a for 9540 or earlier * use v4b for 8540 or later * HW revision: * DB8500ed has revision 0 @@ -411,7 +409,7 @@ struct d40_desc { * * @base: The virtual address of LCLA. 18 bit aligned. * @dma_addr: DMA address, if mapped - * @base_unaligned: The orignal kmalloc pointer, if kmalloc is used. + * @base_unaligned: The original kmalloc pointer, if kmalloc is used. * This pointer is only there for clean-up on error. * @pages: The number of pages needed for all physical channels. * Only used later for clean-up on error @@ -1655,7 +1653,7 @@ static void dma_tasklet(struct tasklet_struct *t) return; check_pending_tx: - /* Rescue manouver if receiving double interrupts */ + /* Rescue maneuver if receiving double interrupts */ if (d40c->pending_tx > 0) d40c->pending_tx--; spin_unlock_irqrestore(&d40c->lock, flags); @@ -3412,7 +3410,7 @@ static int __init d40_lcla_allocate(struct d40_base *base) base->lcla_pool.base = (void *)page_list[i]; } else { /* - * After many attempts and no succees with finding the correct + * After many attempts and no success with finding the correct * alignment, try with allocating a big buffer. */ dev_warn(base->dev, diff --git a/drivers/dma/tegra186-gpc-dma.c b/drivers/dma/tegra186-gpc-dma.c index fa4d4142a68a21..88547a23825b18 100644 --- a/drivers/dma/tegra186-gpc-dma.c +++ b/drivers/dma/tegra186-gpc-dma.c @@ -1348,8 +1348,8 @@ static int tegra_dma_program_sid(struct tegra_dma_channel *tdc, int stream_id) static int tegra_dma_probe(struct platform_device *pdev) { const struct tegra_dma_chip_data *cdata = NULL; - struct iommu_fwspec *iommu_spec; - unsigned int stream_id, i; + unsigned int i; + u32 stream_id; struct tegra_dma *tdma; int ret; @@ -1378,12 +1378,10 @@ static int tegra_dma_probe(struct platform_device *pdev) tdma->dma_dev.dev = &pdev->dev; - iommu_spec = dev_iommu_fwspec_get(&pdev->dev); - if (!iommu_spec) { + if (!tegra_dev_iommu_get_stream_id(&pdev->dev, &stream_id)) { dev_err(&pdev->dev, "Missing iommu stream-id\n"); return -EINVAL; } - stream_id = iommu_spec->ids[0] & 0xffff; ret = device_property_read_u32(&pdev->dev, "dma-channel-mask", &tdma->chan_mask); diff --git a/drivers/dma/tegra210-adma.c b/drivers/dma/tegra210-adma.c index 7a0586633bf326..24ad7077c53ba8 100644 --- a/drivers/dma/tegra210-adma.c +++ b/drivers/dma/tegra210-adma.c @@ -153,6 +153,7 @@ struct tegra_adma { void __iomem *base_addr; struct clk *ahub_clk; unsigned int nr_channels; + unsigned long *dma_chan_mask; unsigned long rx_requests_reserved; unsigned long tx_requests_reserved; @@ -741,6 +742,10 @@ static int __maybe_unused tegra_adma_runtime_suspend(struct device *dev) for (i = 0; i < tdma->nr_channels; i++) { tdc = &tdma->channels[i]; + /* skip for reserved channels */ + if (!tdc->tdma) + continue; + ch_reg = &tdc->ch_regs; ch_reg->cmd = tdma_ch_read(tdc, ADMA_CH_CMD); /* skip if channel is not active */ @@ -779,6 +784,9 @@ static int __maybe_unused tegra_adma_runtime_resume(struct device *dev) for (i = 0; i < tdma->nr_channels; i++) { tdc = &tdma->channels[i]; + /* skip for reserved channels */ + if (!tdc->tdma) + continue; ch_reg = &tdc->ch_regs; /* skip if channel was not active earlier */ if (!ch_reg->cmd) @@ -867,10 +875,31 @@ static int tegra_adma_probe(struct platform_device *pdev) return PTR_ERR(tdma->ahub_clk); } + tdma->dma_chan_mask = devm_kzalloc(&pdev->dev, + BITS_TO_LONGS(tdma->nr_channels) * sizeof(unsigned long), + GFP_KERNEL); + if (!tdma->dma_chan_mask) + return -ENOMEM; + + /* Enable all channels by default */ + bitmap_fill(tdma->dma_chan_mask, tdma->nr_channels); + + ret = of_property_read_u32_array(pdev->dev.of_node, "dma-channel-mask", + (u32 *)tdma->dma_chan_mask, + BITS_TO_U32(tdma->nr_channels)); + if (ret < 0 && (ret != -EINVAL)) { + dev_err(&pdev->dev, "dma-channel-mask is not complete.\n"); + return ret; + } + INIT_LIST_HEAD(&tdma->dma_dev.channels); for (i = 0; i < tdma->nr_channels; i++) { struct tegra_adma_chan *tdc = &tdma->channels[i]; + /* skip for reserved channels */ + if (!test_bit(i, tdma->dma_chan_mask)) + continue; + tdc->chan_addr = tdma->base_addr + cdata->ch_base_offset + (cdata->ch_reg_size * i); @@ -957,8 +986,10 @@ static void tegra_adma_remove(struct platform_device *pdev) of_dma_controller_free(pdev->dev.of_node); dma_async_device_unregister(&tdma->dma_dev); - for (i = 0; i < tdma->nr_channels; ++i) - irq_dispose_mapping(tdma->channels[i].irq); + for (i = 0; i < tdma->nr_channels; ++i) { + if (tdma->channels[i].irq) + irq_dispose_mapping(tdma->channels[i].irq); + } pm_runtime_disable(&pdev->dev); } diff --git a/drivers/dma/ti/Makefile b/drivers/dma/ti/Makefile index acc950bf609c36..d376c117cecf60 100644 --- a/drivers/dma/ti/Makefile +++ b/drivers/dma/ti/Makefile @@ -12,6 +12,7 @@ k3-psil-lib-objs := k3-psil.o \ k3-psil-j721s2.o \ k3-psil-am62.o \ k3-psil-am62a.o \ - k3-psil-j784s4.o + k3-psil-j784s4.o \ + k3-psil-am62p.o obj-$(CONFIG_TI_K3_PSIL) += k3-psil-lib.o obj-$(CONFIG_TI_DMA_CROSSBAR) += dma-crossbar.o diff --git a/drivers/dma/ti/k3-psil-am62p.c b/drivers/dma/ti/k3-psil-am62p.c new file mode 100644 index 00000000000000..0f338e16d9710f --- /dev/null +++ b/drivers/dma/ti/k3-psil-am62p.c @@ -0,0 +1,325 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com + */ + +#include + +#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 am62p_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-2 */ + PSIL_PDMA_XY_PKT(0x4300), + PSIL_PDMA_XY_PKT(0x4301), + 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), + /* 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), + 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), + /* CSIRX 1-3 (only for J722S) */ + PSIL_CSI2RX(0x5100), + PSIL_CSI2RX(0x5101), + PSIL_CSI2RX(0x5102), + PSIL_CSI2RX(0x5103), + PSIL_CSI2RX(0x5104), + PSIL_CSI2RX(0x5105), + PSIL_CSI2RX(0x5106), + PSIL_CSI2RX(0x5107), + PSIL_CSI2RX(0x5108), + PSIL_CSI2RX(0x5109), + PSIL_CSI2RX(0x510a), + PSIL_CSI2RX(0x510b), + PSIL_CSI2RX(0x510c), + PSIL_CSI2RX(0x510d), + PSIL_CSI2RX(0x510e), + PSIL_CSI2RX(0x510f), + PSIL_CSI2RX(0x5110), + PSIL_CSI2RX(0x5111), + PSIL_CSI2RX(0x5112), + PSIL_CSI2RX(0x5113), + PSIL_CSI2RX(0x5114), + PSIL_CSI2RX(0x5115), + PSIL_CSI2RX(0x5116), + PSIL_CSI2RX(0x5117), + PSIL_CSI2RX(0x5118), + PSIL_CSI2RX(0x5119), + PSIL_CSI2RX(0x511a), + PSIL_CSI2RX(0x511b), + PSIL_CSI2RX(0x511c), + PSIL_CSI2RX(0x511d), + PSIL_CSI2RX(0x511e), + PSIL_CSI2RX(0x511f), + PSIL_CSI2RX(0x5200), + PSIL_CSI2RX(0x5201), + PSIL_CSI2RX(0x5202), + PSIL_CSI2RX(0x5203), + PSIL_CSI2RX(0x5204), + PSIL_CSI2RX(0x5205), + PSIL_CSI2RX(0x5206), + PSIL_CSI2RX(0x5207), + PSIL_CSI2RX(0x5208), + PSIL_CSI2RX(0x5209), + PSIL_CSI2RX(0x520a), + PSIL_CSI2RX(0x520b), + PSIL_CSI2RX(0x520c), + PSIL_CSI2RX(0x520d), + PSIL_CSI2RX(0x520e), + PSIL_CSI2RX(0x520f), + PSIL_CSI2RX(0x5210), + PSIL_CSI2RX(0x5211), + PSIL_CSI2RX(0x5212), + PSIL_CSI2RX(0x5213), + PSIL_CSI2RX(0x5214), + PSIL_CSI2RX(0x5215), + PSIL_CSI2RX(0x5216), + PSIL_CSI2RX(0x5217), + PSIL_CSI2RX(0x5218), + PSIL_CSI2RX(0x5219), + PSIL_CSI2RX(0x521a), + PSIL_CSI2RX(0x521b), + PSIL_CSI2RX(0x521c), + PSIL_CSI2RX(0x521d), + PSIL_CSI2RX(0x521e), + PSIL_CSI2RX(0x521f), + PSIL_CSI2RX(0x5300), + PSIL_CSI2RX(0x5301), + PSIL_CSI2RX(0x5302), + PSIL_CSI2RX(0x5303), + PSIL_CSI2RX(0x5304), + PSIL_CSI2RX(0x5305), + PSIL_CSI2RX(0x5306), + PSIL_CSI2RX(0x5307), + PSIL_CSI2RX(0x5308), + PSIL_CSI2RX(0x5309), + PSIL_CSI2RX(0x530a), + PSIL_CSI2RX(0x530b), + PSIL_CSI2RX(0x530c), + PSIL_CSI2RX(0x530d), + PSIL_CSI2RX(0x530e), + PSIL_CSI2RX(0x530f), + PSIL_CSI2RX(0x5310), + PSIL_CSI2RX(0x5311), + PSIL_CSI2RX(0x5312), + PSIL_CSI2RX(0x5313), + PSIL_CSI2RX(0x5314), + PSIL_CSI2RX(0x5315), + PSIL_CSI2RX(0x5316), + PSIL_CSI2RX(0x5317), + PSIL_CSI2RX(0x5318), + PSIL_CSI2RX(0x5319), + PSIL_CSI2RX(0x531a), + PSIL_CSI2RX(0x531b), + PSIL_CSI2RX(0x531c), + PSIL_CSI2RX(0x531d), + PSIL_CSI2RX(0x531e), + PSIL_CSI2RX(0x531f), +}; + +/* PSI-L destination thread IDs, used for TX (DMA_MEM_TO_DEV) */ +static struct psil_ep am62p_dst_ep_map[] = { + /* SAUL */ + PSIL_SAUL(0xf500, 27, 83, 8, 83, 1), + PSIL_SAUL(0xf501, 28, 91, 8, 91, 1), + /* PDMA_MAIN0 - SPI0-2 */ + PSIL_PDMA_XY_PKT(0xc300), + PSIL_PDMA_XY_PKT(0xc301), + 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), + /* 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 am62p_ep_map = { + .name = "am62p", + .src = am62p_src_ep_map, + .src_count = ARRAY_SIZE(am62p_src_ep_map), + .dst = am62p_dst_ep_map, + .dst_count = ARRAY_SIZE(am62p_dst_ep_map), +}; diff --git a/drivers/dma/ti/k3-psil-priv.h b/drivers/dma/ti/k3-psil-priv.h index c383723d1c8f66..a577be97e34471 100644 --- a/drivers/dma/ti/k3-psil-priv.h +++ b/drivers/dma/ti/k3-psil-priv.h @@ -45,5 +45,6 @@ extern struct psil_ep_map j721s2_ep_map; extern struct psil_ep_map am62_ep_map; extern struct psil_ep_map am62a_ep_map; extern struct psil_ep_map j784s4_ep_map; +extern struct psil_ep_map am62p_ep_map; #endif /* K3_PSIL_PRIV_H_ */ diff --git a/drivers/dma/ti/k3-psil.c b/drivers/dma/ti/k3-psil.c index c11389d67a3f0f..25148d95247203 100644 --- a/drivers/dma/ti/k3-psil.c +++ b/drivers/dma/ti/k3-psil.c @@ -26,6 +26,8 @@ static const struct soc_device_attribute k3_soc_devices[] = { { .family = "AM62X", .data = &am62_ep_map }, { .family = "AM62AX", .data = &am62a_ep_map }, { .family = "J784S4", .data = &j784s4_ep_map }, + { .family = "AM62PX", .data = &am62p_ep_map }, + { .family = "J722S", .data = &am62p_ep_map }, { /* sentinel */ } }; diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c index 30fd2f386f36a1..2841a539c26489 100644 --- a/drivers/dma/ti/k3-udma.c +++ b/drivers/dma/ti/k3-udma.c @@ -4441,6 +4441,8 @@ static const struct soc_device_attribute k3_soc_devices[] = { { .family = "AM62X", .data = &am64_soc_data }, { .family = "AM62AX", .data = &am64_soc_data }, { .family = "J784S4", .data = &j721e_soc_data }, + { .family = "AM62PX", .data = &am64_soc_data }, + { .family = "J722S", .data = &am64_soc_data }, { /* sentinel */ } }; diff --git a/drivers/dma/uniphier-mdmac.c b/drivers/dma/uniphier-mdmac.c index 618839df074866..ad7125f6e2ca8e 100644 --- a/drivers/dma/uniphier-mdmac.c +++ b/drivers/dma/uniphier-mdmac.c @@ -453,7 +453,7 @@ disable_clk: return ret; } -static int uniphier_mdmac_remove(struct platform_device *pdev) +static void uniphier_mdmac_remove(struct platform_device *pdev) { struct uniphier_mdmac_device *mdev = platform_get_drvdata(pdev); struct dma_chan *chan; @@ -468,16 +468,21 @@ static int uniphier_mdmac_remove(struct platform_device *pdev) */ list_for_each_entry(chan, &mdev->ddev.channels, device_node) { ret = dmaengine_terminate_sync(chan); - if (ret) - return ret; + if (ret) { + /* + * This results in resource leakage and maybe also + * use-after-free errors as e.g. *mdev is kfreed. + */ + dev_alert(&pdev->dev, "Failed to terminate channel %d (%pe)\n", + chan->chan_id, ERR_PTR(ret)); + return; + } uniphier_mdmac_free_chan_resources(chan); } of_dma_controller_free(pdev->dev.of_node); dma_async_device_unregister(&mdev->ddev); clk_disable_unprepare(mdev->clk); - - return 0; } static const struct of_device_id uniphier_mdmac_match[] = { @@ -488,7 +493,7 @@ MODULE_DEVICE_TABLE(of, uniphier_mdmac_match); static struct platform_driver uniphier_mdmac_driver = { .probe = uniphier_mdmac_probe, - .remove = uniphier_mdmac_remove, + .remove_new = uniphier_mdmac_remove, .driver = { .name = "uniphier-mio-dmac", .of_match_table = uniphier_mdmac_match, diff --git a/drivers/dma/uniphier-xdmac.c b/drivers/dma/uniphier-xdmac.c index 3a8ee2b173b52e..3ce2dc2ad9de42 100644 --- a/drivers/dma/uniphier-xdmac.c +++ b/drivers/dma/uniphier-xdmac.c @@ -563,7 +563,7 @@ out_unregister_dmac: return ret; } -static int uniphier_xdmac_remove(struct platform_device *pdev) +static void uniphier_xdmac_remove(struct platform_device *pdev) { struct uniphier_xdmac_device *xdev = platform_get_drvdata(pdev); struct dma_device *ddev = &xdev->ddev; @@ -579,15 +579,20 @@ static int uniphier_xdmac_remove(struct platform_device *pdev) */ list_for_each_entry(chan, &ddev->channels, device_node) { ret = dmaengine_terminate_sync(chan); - if (ret) - return ret; + if (ret) { + /* + * This results in resource leakage and maybe also + * use-after-free errors as e.g. *xdev is kfreed. + */ + dev_alert(&pdev->dev, "Failed to terminate channel %d (%pe)\n", + chan->chan_id, ERR_PTR(ret)); + return; + } uniphier_xdmac_free_chan_resources(chan); } of_dma_controller_free(pdev->dev.of_node); dma_async_device_unregister(ddev); - - return 0; } static const struct of_device_id uniphier_xdmac_match[] = { @@ -598,7 +603,7 @@ MODULE_DEVICE_TABLE(of, uniphier_xdmac_match); static struct platform_driver uniphier_xdmac_driver = { .probe = uniphier_xdmac_probe, - .remove = uniphier_xdmac_remove, + .remove_new = uniphier_xdmac_remove, .driver = { .name = "uniphier-xdmac", .of_match_table = uniphier_xdmac_match, diff --git a/drivers/dma/xilinx/xdma-regs.h b/drivers/dma/xilinx/xdma-regs.h index e641a5083e14b0..98f5f6fb9ff9c7 100644 --- a/drivers/dma/xilinx/xdma-regs.h +++ b/drivers/dma/xilinx/xdma-regs.h @@ -64,9 +64,10 @@ struct xdma_hw_desc { __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 +#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 32 +#define XDMA_DESC_BLOCK_BOUNDARY 4096 /* * Channel registers @@ -76,6 +77,7 @@ struct xdma_hw_desc { #define XDMA_CHAN_CONTROL_W1S 0x8 #define XDMA_CHAN_CONTROL_W1C 0xc #define XDMA_CHAN_STATUS 0x40 +#define XDMA_CHAN_STATUS_RC 0x44 #define XDMA_CHAN_COMPLETED_DESC 0x48 #define XDMA_CHAN_ALIGNMENTS 0x4c #define XDMA_CHAN_INTR_ENABLE 0x90 @@ -101,6 +103,7 @@ struct xdma_hw_desc { #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_WRITE_ERROR GENMASK(18, 14) #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) @@ -111,8 +114,17 @@ struct xdma_hw_desc { CHAN_CTRL_IE_DESC_ALIGN_MISMATCH | \ CHAN_CTRL_IE_MAGIC_STOPPED | \ CHAN_CTRL_IE_READ_ERROR | \ + CHAN_CTRL_IE_WRITE_ERROR | \ CHAN_CTRL_IE_DESC_ERROR) +#define XDMA_CHAN_STATUS_MASK CHAN_CTRL_START + +#define XDMA_CHAN_ERROR_MASK (CHAN_CTRL_IE_DESC_ALIGN_MISMATCH | \ + CHAN_CTRL_IE_MAGIC_STOPPED | \ + CHAN_CTRL_IE_READ_ERROR | \ + CHAN_CTRL_IE_WRITE_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) @@ -134,18 +146,6 @@ struct xdma_hw_desc { #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 */ diff --git a/drivers/dma/xilinx/xdma.c b/drivers/dma/xilinx/xdma.c index 84a88029226fdc..170017ff2aad6e 100644 --- a/drivers/dma/xilinx/xdma.c +++ b/drivers/dma/xilinx/xdma.c @@ -78,27 +78,31 @@ struct xdma_chan { * @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 * @cyclic: Cyclic transfer vs. scatter-gather + * @interleaved_dma: Interleaved DMA transfer * @periods: Number of periods in the cyclic transfer * @period_size: Size of a period in bytes in cyclic transfers + * @frames_left: Number of frames left in interleaved DMA transfer + * @error: tx error flag */ 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; bool cyclic; + bool interleaved_dma; u32 periods; u32 period_size; + u32 frames_left; + bool error; }; #define XDMA_DEV_STATUS_REG_DMA BIT(0) @@ -276,6 +280,7 @@ xdma_alloc_desc(struct xdma_chan *chan, u32 desc_num, bool cyclic) sw_desc->chan = chan; sw_desc->desc_num = desc_num; sw_desc->cyclic = cyclic; + sw_desc->error = false; dblk_num = DIV_ROUND_UP(desc_num, XDMA_DESC_ADJACENT); sw_desc->desc_blocks = kcalloc(dblk_num, sizeof(*sw_desc->desc_blocks), GFP_NOWAIT); @@ -371,6 +376,31 @@ static int xdma_xfer_start(struct xdma_chan *xchan) return ret; xchan->busy = true; + + return 0; +} + +/** + * xdma_xfer_stop - Stop DMA transfer + * @xchan: DMA channel pointer + */ +static int xdma_xfer_stop(struct xdma_chan *xchan) +{ + int ret; + u32 val; + struct xdma_device *xdev = xchan->xdev_hdl; + + /* clear run stop bit to prevent any further auto-triggering */ + ret = regmap_write(xdev->rmap, xchan->base + XDMA_CHAN_CONTROL_W1C, + CHAN_CTRL_RUN_STOP); + if (ret) + return ret; + + /* Clear the channel status register */ + ret = regmap_read(xdev->rmap, xchan->base + XDMA_CHAN_STATUS_RC, &val); + if (ret) + return ret; + return 0; } @@ -475,6 +505,84 @@ static void xdma_issue_pending(struct dma_chan *chan) spin_unlock_irqrestore(&xdma_chan->vchan.lock, flags); } +/** + * xdma_terminate_all - Terminate all transactions + * @chan: DMA channel pointer + */ +static int xdma_terminate_all(struct dma_chan *chan) +{ + struct xdma_chan *xdma_chan = to_xdma_chan(chan); + struct virt_dma_desc *vd; + unsigned long flags; + LIST_HEAD(head); + + xdma_xfer_stop(xdma_chan); + + spin_lock_irqsave(&xdma_chan->vchan.lock, flags); + + xdma_chan->busy = false; + vd = vchan_next_desc(&xdma_chan->vchan); + if (vd) { + list_del(&vd->node); + dma_cookie_complete(&vd->tx); + vchan_terminate_vdesc(vd); + } + vchan_get_all_descriptors(&xdma_chan->vchan, &head); + list_splice_tail(&head, &xdma_chan->vchan.desc_terminated); + + spin_unlock_irqrestore(&xdma_chan->vchan.lock, flags); + + return 0; +} + +/** + * xdma_synchronize - Synchronize terminated transactions + * @chan: DMA channel pointer + */ +static void xdma_synchronize(struct dma_chan *chan) +{ + struct xdma_chan *xdma_chan = to_xdma_chan(chan); + + vchan_synchronize(&xdma_chan->vchan); +} + +/** + * xdma_fill_descs - Fill hardware descriptors with contiguous memory block addresses + * @sw_desc: tx descriptor state container + * @src_addr: Value for a ->src_addr field of a first descriptor + * @dst_addr: Value for a ->dst_addr field of a first descriptor + * @size: Total size of a contiguous memory block + * @filled_descs_num: Number of filled hardware descriptors for corresponding sw_desc + */ +static inline u32 xdma_fill_descs(struct xdma_desc *sw_desc, u64 src_addr, + u64 dst_addr, u32 size, u32 filled_descs_num) +{ + u32 left = size, len, desc_num = filled_descs_num; + struct xdma_desc_block *dblk; + struct xdma_hw_desc *desc; + + dblk = sw_desc->desc_blocks + (desc_num / XDMA_DESC_ADJACENT); + desc = dblk->virt_addr; + desc += desc_num & XDMA_DESC_ADJACENT_MASK; + do { + len = min_t(u32, left, XDMA_DESC_BLEN_MAX); + /* set hardware descriptor */ + desc->bytes = cpu_to_le32(len); + desc->src_addr = cpu_to_le64(src_addr); + desc->dst_addr = cpu_to_le64(dst_addr); + if (!(++desc_num & XDMA_DESC_ADJACENT_MASK)) + desc = (++dblk)->virt_addr; + else + desc++; + + src_addr += len; + dst_addr += len; + left -= len; + } while (left); + + return desc_num - filled_descs_num; +} + /** * xdma_prep_device_sg - prepare a descriptor for a DMA transaction * @chan: DMA channel pointer @@ -491,13 +599,10 @@ xdma_prep_device_sg(struct dma_chan *chan, struct scatterlist *sgl, { 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; + u32 desc_num = 0, i; + u64 addr, 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); @@ -506,6 +611,8 @@ xdma_prep_device_sg(struct dma_chan *chan, struct scatterlist *sgl, if (!sw_desc) return NULL; sw_desc->dir = dir; + sw_desc->cyclic = false; + sw_desc->interleaved_dma = false; if (dir == DMA_MEM_TO_DEV) { dev_addr = xdma_chan->cfg.dst_addr; @@ -517,32 +624,11 @@ xdma_prep_device_sg(struct dma_chan *chan, struct scatterlist *sgl, dst = &addr; } - dblk = sw_desc->desc_blocks; - desc = dblk->virt_addr; - desc_num = 1; + desc_num = 0; 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); + desc_num += xdma_fill_descs(sw_desc, *src, *dst, sg_dma_len(sg), desc_num); + dev_addr += sg_dma_len(sg); } tx_desc = vchan_tx_prep(&xdma_chan->vchan, &sw_desc->vdesc, flags); @@ -576,9 +662,9 @@ xdma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t address, struct xdma_device *xdev = xdma_chan->xdev_hdl; unsigned int periods = size / period_size; struct dma_async_tx_descriptor *tx_desc; - struct xdma_desc_block *dblk; - struct xdma_hw_desc *desc; struct xdma_desc *sw_desc; + u64 addr, dev_addr, *src, *dst; + u32 desc_num; unsigned int i; /* @@ -602,22 +688,23 @@ xdma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t address, sw_desc->periods = periods; sw_desc->period_size = period_size; sw_desc->dir = dir; + sw_desc->interleaved_dma = false; - dblk = sw_desc->desc_blocks; - desc = dblk->virt_addr; + addr = address; + 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; + } - /* fill hardware descriptor */ + desc_num = 0; for (i = 0; i < periods; i++) { - desc->bytes = cpu_to_le32(period_size); - if (dir == DMA_MEM_TO_DEV) { - desc->src_addr = cpu_to_le64(address + i * period_size); - desc->dst_addr = cpu_to_le64(xdma_chan->cfg.dst_addr); - } else { - desc->src_addr = cpu_to_le64(xdma_chan->cfg.src_addr); - desc->dst_addr = cpu_to_le64(address + i * period_size); - } - - desc++; + desc_num += xdma_fill_descs(sw_desc, *src, *dst, period_size, desc_num); + addr += i * period_size; } tx_desc = vchan_tx_prep(&xdma_chan->vchan, &sw_desc->vdesc, flags); @@ -632,6 +719,57 @@ failed: return NULL; } +/** + * xdma_prep_interleaved_dma - Prepare virtual descriptor for interleaved DMA transfers + * @chan: DMA channel + * @xt: DMA transfer template + * @flags: tx flags + */ +static struct dma_async_tx_descriptor * +xdma_prep_interleaved_dma(struct dma_chan *chan, + struct dma_interleaved_template *xt, + unsigned long flags) +{ + int i; + u32 desc_num = 0, period_size = 0; + struct dma_async_tx_descriptor *tx_desc; + struct xdma_chan *xchan = to_xdma_chan(chan); + struct xdma_desc *sw_desc; + u64 src_addr, dst_addr; + + for (i = 0; i < xt->frame_size; ++i) + desc_num += DIV_ROUND_UP(xt->sgl[i].size, XDMA_DESC_BLEN_MAX); + + sw_desc = xdma_alloc_desc(xchan, desc_num, false); + if (!sw_desc) + return NULL; + sw_desc->dir = xt->dir; + sw_desc->interleaved_dma = true; + sw_desc->cyclic = flags & DMA_PREP_REPEAT; + sw_desc->frames_left = xt->numf; + sw_desc->periods = xt->numf; + + desc_num = 0; + src_addr = xt->src_start; + dst_addr = xt->dst_start; + for (i = 0; i < xt->frame_size; ++i) { + desc_num += xdma_fill_descs(sw_desc, src_addr, dst_addr, xt->sgl[i].size, desc_num); + src_addr += dmaengine_get_src_icg(xt, &xt->sgl[i]) + (xt->src_inc ? + xt->sgl[i].size : 0); + dst_addr += dmaengine_get_dst_icg(xt, &xt->sgl[i]) + (xt->dst_inc ? + xt->sgl[i].size : 0); + period_size += xt->sgl[i].size; + } + sw_desc->period_size = period_size; + + tx_desc = vchan_tx_prep(&xchan->vchan, &sw_desc->vdesc, flags); + if (tx_desc) + return tx_desc; + + xdma_free_desc(&sw_desc->vdesc); + return NULL; +} + /** * xdma_device_config - Configure the DMA channel * @chan: DMA channel @@ -677,9 +815,8 @@ static int xdma_alloc_chan_resources(struct dma_chan *chan) return -EINVAL; } - xdma_chan->desc_pool = dma_pool_create(dma_chan_name(chan), - dev, XDMA_DESC_BLOCK_SIZE, - XDMA_DESC_BLOCK_ALIGN, 0); + xdma_chan->desc_pool = dma_pool_create(dma_chan_name(chan), dev, XDMA_DESC_BLOCK_SIZE, + XDMA_DESC_BLOCK_ALIGN, XDMA_DESC_BLOCK_BOUNDARY); if (!xdma_chan->desc_pool) { xdma_err(xdev, "unable to allocate descriptor pool"); return -ENOMEM; @@ -706,20 +843,20 @@ static enum dma_status xdma_tx_status(struct dma_chan *chan, dma_cookie_t cookie spin_lock_irqsave(&xdma_chan->vchan.lock, flags); vd = vchan_find_desc(&xdma_chan->vchan, cookie); - if (vd) - desc = to_xdma_desc(vd); - if (!desc || !desc->cyclic) { - spin_unlock_irqrestore(&xdma_chan->vchan.lock, flags); - return ret; - } - - period_idx = desc->completed_desc_num % desc->periods; - residue = (desc->periods - period_idx) * desc->period_size; + if (!vd) + goto out; + desc = to_xdma_desc(vd); + if (desc->error) { + ret = DMA_ERROR; + } else if (desc->cyclic) { + period_idx = desc->completed_desc_num % desc->periods; + residue = (desc->periods - period_idx) * desc->period_size; + dma_set_residue(state, residue); + } +out: spin_unlock_irqrestore(&xdma_chan->vchan.lock, flags); - dma_set_residue(state, residue); - return ret; } @@ -732,11 +869,12 @@ 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_device *xdev = xchan->xdev_hdl; + struct virt_dma_desc *vd, *next_vd; struct xdma_desc *desc; int ret; u32 st; + bool repeat_tx; spin_lock(&xchan->vchan.lock); @@ -745,45 +883,76 @@ static irqreturn_t xdma_channel_isr(int irq, void *dev_id) if (!vd) goto out; - xchan->busy = false; + /* Clear-on-read the status register */ + ret = regmap_read(xdev->rmap, xchan->base + XDMA_CHAN_STATUS_RC, &st); + if (ret) + goto out; + desc = to_xdma_desc(vd); - xdev = xchan->xdev_hdl; + + st &= XDMA_CHAN_STATUS_MASK; + if ((st & XDMA_CHAN_ERROR_MASK) || + !(st & (CHAN_CTRL_IE_DESC_COMPLETED | CHAN_CTRL_IE_DESC_STOPPED))) { + desc->error = true; + xdma_err(xdev, "channel error, status register value: 0x%x", st); + goto out; + } 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 (desc->interleaved_dma) { + xchan->busy = false; + desc->completed_desc_num += complete_desc_num; + if (complete_desc_num == XDMA_DESC_BLOCK_NUM * XDMA_DESC_ADJACENT) { + xdma_xfer_start(xchan); + goto out; + } - if (desc->cyclic) { - ret = regmap_read(xdev->rmap, xchan->base + XDMA_CHAN_STATUS, - &st); - if (ret) + /* last desc of any frame */ + desc->frames_left--; + if (desc->frames_left) + goto out; + + /* last desc of the last frame */ + repeat_tx = vd->tx.flags & DMA_PREP_REPEAT; + next_vd = list_first_entry_or_null(&vd->node, struct virt_dma_desc, node); + if (next_vd) + repeat_tx = repeat_tx && !(next_vd->tx.flags & DMA_PREP_LOAD_EOT); + if (repeat_tx) { + desc->frames_left = desc->periods; + desc->completed_desc_num = 0; + vchan_cyclic_callback(vd); + } else { + list_del(&vd->node); + vchan_cookie_complete(vd); + } + /* start (or continue) the tx of a first desc on the vc.desc_issued list, if any */ + xdma_xfer_start(xchan); + } else if (!desc->cyclic) { + xchan->busy = false; + 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; + } - regmap_write(xdev->rmap, xchan->base + XDMA_CHAN_STATUS, st); + 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); + } else { + desc->completed_desc_num = complete_desc_num; vchan_cyclic_callback(vd); - goto out; - } - - /* - * 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 (SG only) */ - xdma_xfer_start(xchan); - out: spin_unlock(&xchan->vchan.lock); return IRQ_HANDLED; @@ -1080,6 +1249,9 @@ static int xdma_probe(struct platform_device *pdev) dma_cap_set(DMA_SLAVE, xdev->dma_dev.cap_mask); dma_cap_set(DMA_PRIVATE, xdev->dma_dev.cap_mask); dma_cap_set(DMA_CYCLIC, xdev->dma_dev.cap_mask); + dma_cap_set(DMA_INTERLEAVE, xdev->dma_dev.cap_mask); + dma_cap_set(DMA_REPEAT, xdev->dma_dev.cap_mask); + dma_cap_set(DMA_LOAD_EOT, xdev->dma_dev.cap_mask); xdev->dma_dev.dev = &pdev->dev; xdev->dma_dev.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT; @@ -1089,10 +1261,13 @@ static int xdma_probe(struct platform_device *pdev) 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.device_terminate_all = xdma_terminate_all; + xdev->dma_dev.device_synchronize = xdma_synchronize; 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; xdev->dma_dev.device_prep_dma_cyclic = xdma_prep_dma_cyclic; + xdev->dma_dev.device_prep_interleaved_dma = xdma_prep_interleaved_dma; ret = dma_async_device_register(&xdev->dma_dev); if (ret) { diff --git a/drivers/dma/xilinx/xilinx_dpdma.c b/drivers/dma/xilinx/xilinx_dpdma.c index 69587d85a7cd20..b82815e64d24e8 100644 --- a/drivers/dma/xilinx/xilinx_dpdma.c +++ b/drivers/dma/xilinx/xilinx_dpdma.c @@ -309,7 +309,7 @@ static ssize_t xilinx_dpdma_debugfs_desc_done_irq_read(char *buf) out_str_len = strlen(XILINX_DPDMA_DEBUGFS_UINT16_MAX_STR); out_str_len = min_t(size_t, XILINX_DPDMA_DEBUGFS_READ_MAX_SIZE, - out_str_len); + out_str_len + 1); snprintf(buf, out_str_len, "%d", dpdma_debugfs.xilinx_dpdma_irq_done_count); diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c index 3568149b956200..5152bd1b0daf59 100644 --- a/drivers/dpll/dpll_core.c +++ b/drivers/dpll/dpll_core.c @@ -22,14 +22,13 @@ DEFINE_MUTEX(dpll_lock); DEFINE_XARRAY_FLAGS(dpll_device_xa, XA_FLAGS_ALLOC); DEFINE_XARRAY_FLAGS(dpll_pin_xa, XA_FLAGS_ALLOC); -static u32 dpll_xa_id; +static u32 dpll_device_xa_id; +static u32 dpll_pin_xa_id; #define ASSERT_DPLL_REGISTERED(d) \ WARN_ON_ONCE(!xa_get_mark(&dpll_device_xa, (d)->id, DPLL_REGISTERED)) #define ASSERT_DPLL_NOT_REGISTERED(d) \ WARN_ON_ONCE(xa_get_mark(&dpll_device_xa, (d)->id, DPLL_REGISTERED)) -#define ASSERT_PIN_REGISTERED(p) \ - WARN_ON_ONCE(!xa_get_mark(&dpll_pin_xa, (p)->id, DPLL_REGISTERED)) struct dpll_device_registration { struct list_head list; @@ -246,7 +245,7 @@ dpll_device_alloc(const u64 clock_id, u32 device_idx, struct module *module) dpll->clock_id = clock_id; dpll->module = module; ret = xa_alloc_cyclic(&dpll_device_xa, &dpll->id, dpll, xa_limit_32b, - &dpll_xa_id, GFP_KERNEL); + &dpll_device_xa_id, GFP_KERNEL); if (ret < 0) { kfree(dpll); return ERR_PTR(ret); @@ -424,6 +423,53 @@ void dpll_device_unregister(struct dpll_device *dpll, } EXPORT_SYMBOL_GPL(dpll_device_unregister); +static void dpll_pin_prop_free(struct dpll_pin_properties *prop) +{ + kfree(prop->package_label); + kfree(prop->panel_label); + kfree(prop->board_label); + kfree(prop->freq_supported); +} + +static int dpll_pin_prop_dup(const struct dpll_pin_properties *src, + struct dpll_pin_properties *dst) +{ + memcpy(dst, src, sizeof(*dst)); + if (src->freq_supported && src->freq_supported_num) { + size_t freq_size = src->freq_supported_num * + sizeof(*src->freq_supported); + dst->freq_supported = kmemdup(src->freq_supported, + freq_size, GFP_KERNEL); + if (!src->freq_supported) + return -ENOMEM; + } + if (src->board_label) { + dst->board_label = kstrdup(src->board_label, GFP_KERNEL); + if (!dst->board_label) + goto err_board_label; + } + if (src->panel_label) { + dst->panel_label = kstrdup(src->panel_label, GFP_KERNEL); + if (!dst->panel_label) + goto err_panel_label; + } + if (src->package_label) { + dst->package_label = kstrdup(src->package_label, GFP_KERNEL); + if (!dst->package_label) + goto err_package_label; + } + + return 0; + +err_package_label: + kfree(dst->panel_label); +err_panel_label: + kfree(dst->board_label); +err_board_label: + kfree(dst->freq_supported); + return -ENOMEM; +} + static struct dpll_pin * dpll_pin_alloc(u64 clock_id, u32 pin_idx, struct module *module, const struct dpll_pin_properties *prop) @@ -440,19 +486,24 @@ dpll_pin_alloc(u64 clock_id, u32 pin_idx, struct module *module, if (WARN_ON(prop->type < DPLL_PIN_TYPE_MUX || prop->type > DPLL_PIN_TYPE_MAX)) { ret = -EINVAL; - goto err; + goto err_pin_prop; } - pin->prop = prop; + ret = dpll_pin_prop_dup(prop, &pin->prop); + if (ret) + goto err_pin_prop; refcount_set(&pin->refcount, 1); xa_init_flags(&pin->dpll_refs, XA_FLAGS_ALLOC); xa_init_flags(&pin->parent_refs, XA_FLAGS_ALLOC); - ret = xa_alloc(&dpll_pin_xa, &pin->id, pin, xa_limit_16b, GFP_KERNEL); + ret = xa_alloc_cyclic(&dpll_pin_xa, &pin->id, pin, xa_limit_32b, + &dpll_pin_xa_id, GFP_KERNEL); if (ret) - goto err; + goto err_xa_alloc; return pin; -err: +err_xa_alloc: xa_destroy(&pin->dpll_refs); xa_destroy(&pin->parent_refs); + dpll_pin_prop_free(&pin->prop); +err_pin_prop: kfree(pin); return ERR_PTR(ret); } @@ -512,6 +563,7 @@ void dpll_pin_put(struct dpll_pin *pin) xa_destroy(&pin->dpll_refs); xa_destroy(&pin->parent_refs); xa_erase(&dpll_pin_xa, pin->id); + dpll_pin_prop_free(&pin->prop); kfree(pin); } mutex_unlock(&dpll_lock); @@ -562,8 +614,6 @@ dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin, WARN_ON(!ops->state_on_dpll_get) || WARN_ON(!ops->direction_get)) return -EINVAL; - if (ASSERT_DPLL_REGISTERED(dpll)) - return -EINVAL; mutex_lock(&dpll_lock); if (WARN_ON(!(dpll->module == pin->module && @@ -634,15 +684,13 @@ int dpll_pin_on_pin_register(struct dpll_pin *parent, struct dpll_pin *pin, unsigned long i, stop; int ret; - if (WARN_ON(parent->prop->type != DPLL_PIN_TYPE_MUX)) + if (WARN_ON(parent->prop.type != DPLL_PIN_TYPE_MUX)) return -EINVAL; if (WARN_ON(!ops) || WARN_ON(!ops->state_on_pin_get) || WARN_ON(!ops->direction_get)) return -EINVAL; - if (ASSERT_PIN_REGISTERED(parent)) - return -EINVAL; mutex_lock(&dpll_lock); ret = dpll_xa_ref_pin_add(&pin->parent_refs, parent, ops, priv); diff --git a/drivers/dpll/dpll_core.h b/drivers/dpll/dpll_core.h index 5585873c5c1b02..717f715015c742 100644 --- a/drivers/dpll/dpll_core.h +++ b/drivers/dpll/dpll_core.h @@ -44,7 +44,7 @@ struct dpll_device { * @module: module of creator * @dpll_refs: hold referencees to dplls pin was registered with * @parent_refs: hold references to parent pins pin was registered with - * @prop: pointer to pin properties given by registerer + * @prop: pin properties copied from the registerer * @rclk_dev_name: holds name of device when pin can recover clock from it * @refcount: refcount **/ @@ -55,7 +55,7 @@ struct dpll_pin { struct module *module; struct xarray dpll_refs; struct xarray parent_refs; - const struct dpll_pin_properties *prop; + struct dpll_pin_properties prop; refcount_t refcount; }; diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c index ce7cf736f02084..314bb377546519 100644 --- a/drivers/dpll/dpll_netlink.c +++ b/drivers/dpll/dpll_netlink.c @@ -101,13 +101,17 @@ dpll_msg_add_mode_supported(struct sk_buff *msg, struct dpll_device *dpll, { const struct dpll_device_ops *ops = dpll_device_ops(dpll); enum dpll_mode mode; + int ret; - if (!ops->mode_supported) - return 0; - for (mode = DPLL_MODE_MANUAL; mode <= DPLL_MODE_MAX; mode++) - if (ops->mode_supported(dpll, dpll_priv(dpll), mode, extack)) - if (nla_put_u32(msg, DPLL_A_MODE_SUPPORTED, mode)) - return -EMSGSIZE; + /* No mode change is supported now, so the only supported mode is the + * one obtained by mode_get(). + */ + + ret = ops->mode_get(dpll, dpll_priv(dpll), &mode, extack); + if (ret) + return ret; + if (nla_put_u32(msg, DPLL_A_MODE_SUPPORTED, mode)) + return -EMSGSIZE; return 0; } @@ -259,6 +263,27 @@ dpll_msg_add_phase_offset(struct sk_buff *msg, struct dpll_pin *pin, return 0; } +static int dpll_msg_add_ffo(struct sk_buff *msg, struct dpll_pin *pin, + struct dpll_pin_ref *ref, + struct netlink_ext_ack *extack) +{ + const struct dpll_pin_ops *ops = dpll_pin_ops(ref); + struct dpll_device *dpll = ref->dpll; + s64 ffo; + int ret; + + if (!ops->ffo_get) + return 0; + ret = ops->ffo_get(pin, dpll_pin_on_dpll_priv(dpll, pin), + dpll, dpll_priv(dpll), &ffo, extack); + if (ret) { + if (ret == -ENODATA) + return 0; + return ret; + } + return nla_put_sint(msg, DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET, ffo); +} + static int dpll_msg_add_pin_freq(struct sk_buff *msg, struct dpll_pin *pin, struct dpll_pin_ref *ref, struct netlink_ext_ack *extack) @@ -278,17 +303,17 @@ dpll_msg_add_pin_freq(struct sk_buff *msg, struct dpll_pin *pin, if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY, sizeof(freq), &freq, DPLL_A_PIN_PAD)) return -EMSGSIZE; - for (fs = 0; fs < pin->prop->freq_supported_num; fs++) { + for (fs = 0; fs < pin->prop.freq_supported_num; fs++) { nest = nla_nest_start(msg, DPLL_A_PIN_FREQUENCY_SUPPORTED); if (!nest) return -EMSGSIZE; - freq = pin->prop->freq_supported[fs].min; + freq = pin->prop.freq_supported[fs].min; if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY_MIN, sizeof(freq), &freq, DPLL_A_PIN_PAD)) { nla_nest_cancel(msg, nest); return -EMSGSIZE; } - freq = pin->prop->freq_supported[fs].max; + freq = pin->prop.freq_supported[fs].max; if (nla_put_64bit(msg, DPLL_A_PIN_FREQUENCY_MAX, sizeof(freq), &freq, DPLL_A_PIN_PAD)) { nla_nest_cancel(msg, nest); @@ -304,9 +329,9 @@ static bool dpll_pin_is_freq_supported(struct dpll_pin *pin, u32 freq) { int fs; - for (fs = 0; fs < pin->prop->freq_supported_num; fs++) - if (freq >= pin->prop->freq_supported[fs].min && - freq <= pin->prop->freq_supported[fs].max) + for (fs = 0; fs < pin->prop.freq_supported_num; fs++) + if (freq >= pin->prop.freq_supported[fs].min && + freq <= pin->prop.freq_supported[fs].max) return true; return false; } @@ -396,7 +421,7 @@ static int dpll_cmd_pin_get_one(struct sk_buff *msg, struct dpll_pin *pin, struct netlink_ext_ack *extack) { - const struct dpll_pin_properties *prop = pin->prop; + const struct dpll_pin_properties *prop = &pin->prop; struct dpll_pin_ref *ref; int ret; @@ -436,6 +461,9 @@ dpll_cmd_pin_get_one(struct sk_buff *msg, struct dpll_pin *pin, prop->phase_range.max)) return -EMSGSIZE; ret = dpll_msg_add_pin_phase_adjust(msg, pin, ref, extack); + if (ret) + return ret; + ret = dpll_msg_add_ffo(msg, pin, ref, extack); if (ret) return ret; if (xa_empty(&pin->parent_refs)) @@ -525,6 +553,24 @@ __dpll_device_change_ntf(struct dpll_device *dpll) return dpll_device_event_send(DPLL_CMD_DEVICE_CHANGE_NTF, dpll); } +static bool dpll_pin_available(struct dpll_pin *pin) +{ + struct dpll_pin_ref *par_ref; + unsigned long i; + + if (!xa_get_mark(&dpll_pin_xa, pin->id, DPLL_REGISTERED)) + return false; + xa_for_each(&pin->parent_refs, i, par_ref) + if (xa_get_mark(&dpll_pin_xa, par_ref->pin->id, + DPLL_REGISTERED)) + return true; + xa_for_each(&pin->dpll_refs, i, par_ref) + if (xa_get_mark(&dpll_device_xa, par_ref->dpll->id, + DPLL_REGISTERED)) + return true; + return false; +} + /** * dpll_device_change_ntf - notify that the dpll device has been changed * @dpll: registered dpll pointer @@ -551,7 +597,7 @@ dpll_pin_event_send(enum dpll_cmd event, struct dpll_pin *pin) int ret = -ENOMEM; void *hdr; - if (WARN_ON(!xa_get_mark(&dpll_pin_xa, pin->id, DPLL_REGISTERED))) + if (!dpll_pin_available(pin)) return -ENODEV; msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); @@ -689,7 +735,7 @@ dpll_pin_on_pin_state_set(struct dpll_pin *pin, u32 parent_idx, int ret; if (!(DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE & - pin->prop->capabilities)) { + pin->prop.capabilities)) { NL_SET_ERR_MSG(extack, "state changing is not allowed"); return -EOPNOTSUPP; } @@ -725,7 +771,7 @@ dpll_pin_state_set(struct dpll_device *dpll, struct dpll_pin *pin, int ret; if (!(DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE & - pin->prop->capabilities)) { + pin->prop.capabilities)) { NL_SET_ERR_MSG(extack, "state changing is not allowed"); return -EOPNOTSUPP; } @@ -752,7 +798,7 @@ dpll_pin_prio_set(struct dpll_device *dpll, struct dpll_pin *pin, int ret; if (!(DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE & - pin->prop->capabilities)) { + pin->prop.capabilities)) { NL_SET_ERR_MSG(extack, "prio changing is not allowed"); return -EOPNOTSUPP; } @@ -780,7 +826,7 @@ dpll_pin_direction_set(struct dpll_pin *pin, struct dpll_device *dpll, int ret; if (!(DPLL_PIN_CAPABILITIES_DIRECTION_CAN_CHANGE & - pin->prop->capabilities)) { + pin->prop.capabilities)) { NL_SET_ERR_MSG(extack, "direction changing is not allowed"); return -EOPNOTSUPP; } @@ -810,8 +856,8 @@ dpll_pin_phase_adj_set(struct dpll_pin *pin, struct nlattr *phase_adj_attr, int ret; phase_adj = nla_get_s32(phase_adj_attr); - if (phase_adj > pin->prop->phase_range.max || - phase_adj < pin->prop->phase_range.min) { + if (phase_adj > pin->prop.phase_range.max || + phase_adj < pin->prop.phase_range.min) { NL_SET_ERR_MSG_ATTR(extack, phase_adj_attr, "phase adjust value not supported"); return -EINVAL; @@ -995,7 +1041,7 @@ dpll_pin_find(u64 clock_id, struct nlattr *mod_name_attr, unsigned long i; xa_for_each_marked(&dpll_pin_xa, i, pin, DPLL_REGISTERED) { - prop = pin->prop; + prop = &pin->prop; cid_match = clock_id ? pin->clock_id == clock_id : true; mod_match = mod_name_attr && module_name(pin->module) ? !nla_strcmp(mod_name_attr, @@ -1102,6 +1148,10 @@ int dpll_nl_pin_id_get_doit(struct sk_buff *skb, struct genl_info *info) } pin = dpll_pin_find_from_nlattr(info); if (!IS_ERR(pin)) { + if (!dpll_pin_available(pin)) { + nlmsg_free(msg); + return -ENODEV; + } ret = dpll_msg_add_pin_handle(msg, pin); if (ret) { nlmsg_free(msg); @@ -1151,6 +1201,8 @@ int dpll_nl_pin_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) xa_for_each_marked_start(&dpll_pin_xa, i, pin, DPLL_REGISTERED, ctx->idx) { + if (!dpll_pin_available(pin)) + continue; hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, &dpll_nl_family, NLM_F_MULTI, @@ -1413,7 +1465,8 @@ int dpll_pin_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, } info->user_ptr[0] = xa_load(&dpll_pin_xa, nla_get_u32(info->attrs[DPLL_A_PIN_ID])); - if (!info->user_ptr[0]) { + if (!info->user_ptr[0] || + !dpll_pin_available(info->user_ptr[0])) { NL_SET_ERR_MSG(info->extack, "pin not found"); ret = -ENODEV; goto unlock_dev; diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index 8b31cd54bdb6de..ae17ce4d972267 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -279,7 +280,6 @@ release: static int altr_sdram_probe(struct platform_device *pdev) { - const struct of_device_id *id; struct edac_mc_layer layers[2]; struct mem_ctl_info *mci; struct altr_sdram_mc_data *drvdata; @@ -290,10 +290,6 @@ static int altr_sdram_probe(struct platform_device *pdev) int irq, irq2, res = 0; unsigned long mem_size, irqflags = 0; - id = of_match_device(altr_sdram_ctrl_of_match, &pdev->dev); - if (!id) - return -ENODEV; - /* Grab the register range from the sdr controller in device tree */ mc_vbase = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "altr,sdr-syscon"); @@ -304,8 +300,7 @@ static int altr_sdram_probe(struct platform_device *pdev) } /* Check specific dependencies for the module */ - priv = of_match_node(altr_sdram_ctrl_of_match, - pdev->dev.of_node)->data; + priv = device_get_match_data(&pdev->dev); /* Validate the SDRAM controller has ECC enabled */ if (regmap_read(mc_vbase, priv->ecc_ctrl_offset, &read_reg) || @@ -459,15 +454,13 @@ free: return res; } -static int altr_sdram_remove(struct platform_device *pdev) +static void altr_sdram_remove(struct platform_device *pdev) { struct mem_ctl_info *mci = platform_get_drvdata(pdev); edac_mc_del_mc(&pdev->dev); edac_mc_free(mci); platform_set_drvdata(pdev, NULL); - - return 0; } /* @@ -489,7 +482,7 @@ static const struct dev_pm_ops altr_sdram_pm_ops = { static struct platform_driver altr_sdram_edac_driver = { .probe = altr_sdram_probe, - .remove = altr_sdram_remove, + .remove_new = altr_sdram_remove, .driver = { .name = "altr_sdram_edac", #ifdef CONFIG_PM @@ -812,7 +805,7 @@ fail: return res; } -static int altr_edac_device_remove(struct platform_device *pdev) +static void altr_edac_device_remove(struct platform_device *pdev) { struct edac_device_ctl_info *dci = platform_get_drvdata(pdev); struct altr_edac_device_dev *drvdata = dci->pvt_info; @@ -820,13 +813,11 @@ static int altr_edac_device_remove(struct platform_device *pdev) debugfs_remove_recursive(drvdata->debugfs_dir); edac_device_del_device(&pdev->dev); edac_device_free_ctl_info(dci); - - return 0; } static struct platform_driver altr_edac_device_driver = { .probe = altr_edac_device_probe, - .remove = altr_edac_device_remove, + .remove_new = altr_edac_device_remove, .driver = { .name = "altr_edac_device", .of_match_table = altr_edac_device_of_match, diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 9b6642d0087130..537b9987a431c2 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -996,15 +996,23 @@ static struct local_node_map { #define LNTM_NODE_COUNT GENMASK(27, 16) #define LNTM_BASE_NODE_ID GENMASK(11, 0) -static int gpu_get_node_map(void) +static int gpu_get_node_map(struct amd64_pvt *pvt) { struct pci_dev *pdev; int ret; u32 tmp; /* - * Node ID 0 is reserved for CPUs. - * Therefore, a non-zero Node ID means we've already cached the values. + * Mapping of nodes from hardware-provided AMD Node ID to a + * Linux logical one is applicable for MI200 models. Therefore, + * return early for other heterogeneous systems. + */ + if (pvt->F3->device != PCI_DEVICE_ID_AMD_MI200_DF_F3) + return 0; + + /* + * Node ID 0 is reserved for CPUs. Therefore, a non-zero Node ID + * means the values have been already cached. */ if (gpu_node_map.base_node_id) return 0; @@ -3851,7 +3859,7 @@ static void gpu_init_csrows(struct mem_ctl_info *mci) dimm->nr_pages = gpu_get_csrow_nr_pages(pvt, umc, cs); dimm->edac_mode = EDAC_SECDED; - dimm->mtype = MEM_HBM2; + dimm->mtype = pvt->dram_type; dimm->dtype = DEV_X16; dimm->grain = 64; } @@ -3880,7 +3888,7 @@ static bool gpu_ecc_enabled(struct amd64_pvt *pvt) return true; } -static inline u32 gpu_get_umc_base(u8 umc, u8 channel) +static inline u32 gpu_get_umc_base(struct amd64_pvt *pvt, u8 umc, u8 channel) { /* * On CPUs, there is one channel per UMC, so UMC numbering equals @@ -3893,13 +3901,16 @@ static inline u32 gpu_get_umc_base(u8 umc, u8 channel) * On GPU nodes channels are selected in 3rd nibble * HBM chX[3:0]= [Y ]5X[3:0]000; * HBM chX[7:4]= [Y+1]5X[3:0]000 + * + * On MI300 APU nodes, same as GPU nodes but channels are selected + * in the base address of 0x90000 */ umc *= 2; if (channel >= 4) umc++; - return 0x50000 + (umc << 20) + ((channel % 4) << 12); + return pvt->gpu_umc_base + (umc << 20) + ((channel % 4) << 12); } static void gpu_read_mc_regs(struct amd64_pvt *pvt) @@ -3910,7 +3921,7 @@ static void gpu_read_mc_regs(struct amd64_pvt *pvt) /* Read registers from each UMC */ for_each_umc(i) { - umc_base = gpu_get_umc_base(i, 0); + umc_base = gpu_get_umc_base(pvt, i, 0); umc = &pvt->umc[i]; amd_smn_read(nid, umc_base + UMCCH_UMC_CFG, &umc->umc_cfg); @@ -3927,7 +3938,7 @@ static void gpu_read_base_mask(struct amd64_pvt *pvt) for_each_umc(umc) { for_each_chip_select(cs, umc, pvt) { - base_reg = gpu_get_umc_base(umc, cs) + UMCCH_BASE_ADDR; + base_reg = gpu_get_umc_base(pvt, umc, cs) + UMCCH_BASE_ADDR; base = &pvt->csels[umc].csbases[cs]; if (!amd_smn_read(pvt->mc_node_id, base_reg, base)) { @@ -3935,7 +3946,7 @@ static void gpu_read_base_mask(struct amd64_pvt *pvt) umc, cs, *base, base_reg); } - mask_reg = gpu_get_umc_base(umc, cs) + UMCCH_ADDR_MASK; + mask_reg = gpu_get_umc_base(pvt, umc, cs) + UMCCH_ADDR_MASK; mask = &pvt->csels[umc].csmasks[cs]; if (!amd_smn_read(pvt->mc_node_id, mask_reg, mask)) { @@ -3960,7 +3971,7 @@ static int gpu_hw_info_get(struct amd64_pvt *pvt) { int ret; - ret = gpu_get_node_map(); + ret = gpu_get_node_map(pvt); if (ret) return ret; @@ -4125,6 +4136,8 @@ static int per_family_init(struct amd64_pvt *pvt) if (pvt->F3->device == PCI_DEVICE_ID_AMD_MI200_DF_F3) { pvt->ctl_name = "MI200"; pvt->max_mcs = 4; + pvt->dram_type = MEM_HBM2; + pvt->gpu_umc_base = 0x50000; pvt->ops = &gpu_ops; } else { pvt->ctl_name = "F19h_M30h"; @@ -4142,6 +4155,13 @@ static int per_family_init(struct amd64_pvt *pvt) pvt->ctl_name = "F19h_M70h"; pvt->flags.zn_regs_v2 = 1; break; + case 0x90 ... 0x9f: + pvt->ctl_name = "F19h_M90h"; + pvt->max_mcs = 4; + pvt->dram_type = MEM_HBM3; + pvt->gpu_umc_base = 0x90000; + pvt->ops = &gpu_ops; + break; case 0xa0 ... 0xaf: pvt->ctl_name = "F19h_MA0h"; pvt->max_mcs = 12; @@ -4180,23 +4200,33 @@ static const struct attribute_group *amd64_edac_attr_groups[] = { NULL }; +/* + * For heterogeneous and APU models EDAC CHIP_SELECT and CHANNEL layers + * should be swapped to fit into the layers. + */ +static unsigned int get_layer_size(struct amd64_pvt *pvt, u8 layer) +{ + bool is_gpu = (pvt->ops == &gpu_ops); + + if (!layer) + return is_gpu ? pvt->max_mcs + : pvt->csels[0].b_cnt; + else + return is_gpu ? pvt->csels[0].b_cnt + : pvt->max_mcs; +} + static int init_one_instance(struct amd64_pvt *pvt) { struct mem_ctl_info *mci = NULL; struct edac_mc_layer layers[2]; int ret = -ENOMEM; - /* - * For Heterogeneous family EDAC CHIP_SELECT and CHANNEL layers should - * be swapped to fit into the layers. - */ layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; - layers[0].size = (pvt->F3->device == PCI_DEVICE_ID_AMD_MI200_DF_F3) ? - pvt->max_mcs : pvt->csels[0].b_cnt; + layers[0].size = get_layer_size(pvt, 0); layers[0].is_virt_csrow = true; layers[1].type = EDAC_MC_LAYER_CHANNEL; - layers[1].size = (pvt->F3->device == PCI_DEVICE_ID_AMD_MI200_DF_F3) ? - pvt->csels[0].b_cnt : pvt->max_mcs; + layers[1].size = get_layer_size(pvt, 1); layers[1].is_virt_csrow = false; mci = edac_mc_alloc(pvt->mc_node_id, ARRAY_SIZE(layers), layers, 0); diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index 5a4e4a59682b06..1665f7932bacbe 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -362,6 +362,7 @@ struct amd64_pvt { u32 dct_sel_lo; /* DRAM Controller Select Low */ u32 dct_sel_hi; /* DRAM Controller Select High */ u32 online_spare; /* On-Line spare Reg */ + u32 gpu_umc_base; /* Base address used for channel selection on GPUs */ /* x4, x8, or x16 syndromes in use */ u8 ecc_sym_sz; diff --git a/drivers/edac/armada_xp_edac.c b/drivers/edac/armada_xp_edac.c index c4bd2fb9c46ba2..25517c99b3eaca 100644 --- a/drivers/edac/armada_xp_edac.c +++ b/drivers/edac/armada_xp_edac.c @@ -5,7 +5,9 @@ #include #include -#include +#include +#include +#include #include #include @@ -351,20 +353,18 @@ static int axp_mc_probe(struct platform_device *pdev) return 0; } -static int axp_mc_remove(struct platform_device *pdev) +static void axp_mc_remove(struct platform_device *pdev) { struct mem_ctl_info *mci = platform_get_drvdata(pdev); edac_mc_del_mc(&pdev->dev); edac_mc_free(mci); platform_set_drvdata(pdev, NULL); - - return 0; } static struct platform_driver axp_mc_driver = { .probe = axp_mc_probe, - .remove = axp_mc_remove, + .remove_new = axp_mc_remove, .driver = { .name = "armada_xp_mc_edac", .of_match_table = of_match_ptr(axp_mc_of_match), @@ -564,7 +564,7 @@ static int aurora_l2_probe(struct platform_device *pdev) return 0; } -static int aurora_l2_remove(struct platform_device *pdev) +static void aurora_l2_remove(struct platform_device *pdev) { struct edac_device_ctl_info *dci = platform_get_drvdata(pdev); #ifdef CONFIG_EDAC_DEBUG @@ -575,13 +575,11 @@ static int aurora_l2_remove(struct platform_device *pdev) edac_device_del_device(&pdev->dev); edac_device_free_ctl_info(dci); platform_set_drvdata(pdev, NULL); - - return 0; } static struct platform_driver aurora_l2_driver = { .probe = aurora_l2_probe, - .remove = aurora_l2_remove, + .remove_new = aurora_l2_remove, .driver = { .name = "aurora_l2_edac", .of_match_table = of_match_ptr(aurora_l2_of_match), diff --git a/drivers/edac/aspeed_edac.c b/drivers/edac/aspeed_edac.c index 6bd5f881591932..157a480eb761b1 100644 --- a/drivers/edac/aspeed_edac.c +++ b/drivers/edac/aspeed_edac.c @@ -357,7 +357,7 @@ probe_exit02: } -static int aspeed_remove(struct platform_device *pdev) +static void aspeed_remove(struct platform_device *pdev) { struct mem_ctl_info *mci; @@ -369,8 +369,6 @@ static int aspeed_remove(struct platform_device *pdev) mci = edac_mc_del_mc(&pdev->dev); if (mci) edac_mc_free(mci); - - return 0; } @@ -389,7 +387,7 @@ static struct platform_driver aspeed_driver = { .of_match_table = aspeed_of_match }, .probe = aspeed_probe, - .remove = aspeed_remove + .remove_new = aspeed_remove }; module_platform_driver(aspeed_driver); diff --git a/drivers/edac/bluefield_edac.c b/drivers/edac/bluefield_edac.c index e4736eb37bfb33..5b3164560648ee 100644 --- a/drivers/edac/bluefield_edac.c +++ b/drivers/edac/bluefield_edac.c @@ -323,14 +323,12 @@ err: } -static int bluefield_edac_mc_remove(struct platform_device *pdev) +static void bluefield_edac_mc_remove(struct platform_device *pdev) { struct mem_ctl_info *mci = platform_get_drvdata(pdev); edac_mc_del_mc(&pdev->dev); edac_mc_free(mci); - - return 0; } static const struct acpi_device_id bluefield_mc_acpi_ids[] = { @@ -346,7 +344,7 @@ static struct platform_driver bluefield_edac_mc_driver = { .acpi_match_table = bluefield_mc_acpi_ids, }, .probe = bluefield_edac_mc_probe, - .remove = bluefield_edac_mc_remove, + .remove_new = bluefield_edac_mc_remove, }; module_platform_driver(bluefield_edac_mc_driver); diff --git a/drivers/edac/cell_edac.c b/drivers/edac/cell_edac.c index bc1f3416400e75..2000f66fbf5c46 100644 --- a/drivers/edac/cell_edac.c +++ b/drivers/edac/cell_edac.c @@ -234,12 +234,11 @@ static int cell_edac_probe(struct platform_device *pdev) return 0; } -static int cell_edac_remove(struct platform_device *pdev) +static void cell_edac_remove(struct platform_device *pdev) { struct mem_ctl_info *mci = edac_mc_del_mc(&pdev->dev); if (mci) edac_mc_free(mci); - return 0; } static struct platform_driver cell_edac_driver = { @@ -247,7 +246,7 @@ static struct platform_driver cell_edac_driver = { .name = "cbe-mic", }, .probe = cell_edac_probe, - .remove = cell_edac_remove, + .remove_new = cell_edac_remove, }; static int __init cell_edac_init(void) diff --git a/drivers/edac/cpc925_edac.c b/drivers/edac/cpc925_edac.c index 9797e6d60dde4d..5075dc7526e3f8 100644 --- a/drivers/edac/cpc925_edac.c +++ b/drivers/edac/cpc925_edac.c @@ -1010,7 +1010,7 @@ out: return res; } -static int cpc925_remove(struct platform_device *pdev) +static void cpc925_remove(struct platform_device *pdev) { struct mem_ctl_info *mci = platform_get_drvdata(pdev); @@ -1023,13 +1023,11 @@ static int cpc925_remove(struct platform_device *pdev) edac_mc_del_mc(&pdev->dev); edac_mc_free(mci); - - return 0; } static struct platform_driver cpc925_edac_driver = { .probe = cpc925_probe, - .remove = cpc925_remove, + .remove_new = cpc925_remove, .driver = { .name = "cpc925_edac", } diff --git a/drivers/edac/dmc520_edac.c b/drivers/edac/dmc520_edac.c index 1fa5ca57e9ec19..4e30b989a1a475 100644 --- a/drivers/edac/dmc520_edac.c +++ b/drivers/edac/dmc520_edac.c @@ -602,7 +602,7 @@ err: return ret; } -static int dmc520_edac_remove(struct platform_device *pdev) +static void dmc520_edac_remove(struct platform_device *pdev) { u32 reg_val, idx, irq_mask_all = 0; struct mem_ctl_info *mci; @@ -626,8 +626,6 @@ static int dmc520_edac_remove(struct platform_device *pdev) edac_mc_del_mc(&pdev->dev); edac_mc_free(mci); - - return 0; } static const struct of_device_id dmc520_edac_driver_id[] = { @@ -644,7 +642,7 @@ static struct platform_driver dmc520_edac_driver = { }, .probe = dmc520_edac_probe, - .remove = dmc520_edac_remove + .remove_new = dmc520_edac_remove }; module_platform_driver(dmc520_edac_driver); diff --git a/drivers/edac/edac_device.h b/drivers/edac/edac_device.h index 3f44e6b9d387f9..7db22a4c83ef3f 100644 --- a/drivers/edac/edac_device.h +++ b/drivers/edac/edac_device.h @@ -176,7 +176,7 @@ struct edac_device_ctl_info { struct edac_dev_sysfs_attribute *sysfs_attributes; /* pointer to main 'edac' subsys in sysfs */ - struct bus_type *edac_subsys; + const struct bus_type *edac_subsys; /* the internal state of this controller instance */ int op_state; diff --git a/drivers/edac/edac_device_sysfs.c b/drivers/edac/edac_device_sysfs.c index 010c26be58464d..237a542e045a3f 100644 --- a/drivers/edac/edac_device_sysfs.c +++ b/drivers/edac/edac_device_sysfs.c @@ -229,7 +229,7 @@ static struct kobj_type ktype_device_ctrl = { int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev) { struct device *dev_root; - struct bus_type *edac_subsys; + const struct bus_type *edac_subsys; int err = -ENODEV; edac_dbg(1, "\n"); diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 6faeb2ab39601b..d6eed727b0cd2e 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -166,6 +166,7 @@ const char * const edac_mem_types[] = { [MEM_NVDIMM] = "Non-volatile-RAM", [MEM_WIO2] = "Wide-IO-2", [MEM_HBM2] = "High-bandwidth-memory-Gen2", + [MEM_HBM3] = "High-bandwidth-memory-Gen3", }; EXPORT_SYMBOL_GPL(edac_mem_types); diff --git a/drivers/edac/edac_module.c b/drivers/edac/edac_module.c index 32a931d0cb71ff..1c9f623826665b 100644 --- a/drivers/edac/edac_module.c +++ b/drivers/edac/edac_module.c @@ -67,7 +67,7 @@ char *edac_op_state_to_string(int opstate) * sysfs object: /sys/devices/system/edac * need to export to other files */ -static struct bus_type edac_subsys = { +static const struct bus_type edac_subsys = { .name = "edac", .dev_name = "edac", }; @@ -90,7 +90,7 @@ static void edac_subsys_exit(void) } /* return pointer to the 'edac' node in sysfs */ -struct bus_type *edac_get_sysfs_subsys(void) +const struct bus_type *edac_get_sysfs_subsys(void) { return &edac_subsys; } diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c index 287cc51dbc868a..7b44afcf48db06 100644 --- a/drivers/edac/edac_pci_sysfs.c +++ b/drivers/edac/edac_pci_sysfs.c @@ -338,7 +338,7 @@ static struct kobj_type ktype_edac_pci_main_kobj = { static int edac_pci_main_kobj_setup(void) { int err = -ENODEV; - struct bus_type *edac_subsys; + const struct bus_type *edac_subsys; struct device *dev_root; edac_dbg(0, "\n"); @@ -521,7 +521,7 @@ static void edac_pci_dev_parity_clear(struct pci_dev *dev) /* read the device TYPE, looking for bridges */ pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type); - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) + if ((header_type & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_BRIDGE) get_pci_parity_status(dev, 1); } @@ -583,7 +583,7 @@ static void edac_pci_dev_parity_test(struct pci_dev *dev) edac_dbg(4, "PCI HEADER TYPE= 0x%02x %s\n", header_type, dev_name(&dev->dev)); - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + if ((header_type & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_BRIDGE) { /* On bridges, need to examine secondary status register */ status = get_pci_parity_status(dev, 1); diff --git a/drivers/edac/fsl_ddr_edac.c b/drivers/edac/fsl_ddr_edac.c index b81757555a8a96..d148d262d0d4de 100644 --- a/drivers/edac/fsl_ddr_edac.c +++ b/drivers/edac/fsl_ddr_edac.c @@ -612,7 +612,7 @@ err: return res; } -int fsl_mc_err_remove(struct platform_device *op) +void fsl_mc_err_remove(struct platform_device *op) { struct mem_ctl_info *mci = dev_get_drvdata(&op->dev); struct fsl_mc_pdata *pdata = mci->pvt_info; @@ -629,5 +629,4 @@ int fsl_mc_err_remove(struct platform_device *op) edac_mc_del_mc(&op->dev); edac_mc_free(mci); - return 0; } diff --git a/drivers/edac/fsl_ddr_edac.h b/drivers/edac/fsl_ddr_edac.h index 332439d7b2d97f..c0994a2a003c28 100644 --- a/drivers/edac/fsl_ddr_edac.h +++ b/drivers/edac/fsl_ddr_edac.h @@ -72,5 +72,5 @@ struct fsl_mc_pdata { int irq; }; int fsl_mc_err_probe(struct platform_device *op); -int fsl_mc_err_remove(struct platform_device *op); +void fsl_mc_err_remove(struct platform_device *op); #endif diff --git a/drivers/edac/highbank_l2_edac.c b/drivers/edac/highbank_l2_edac.c index 140d4431bd0d00..5646c049a93491 100644 --- a/drivers/edac/highbank_l2_edac.c +++ b/drivers/edac/highbank_l2_edac.c @@ -118,18 +118,17 @@ err: return res; } -static int highbank_l2_err_remove(struct platform_device *pdev) +static void highbank_l2_err_remove(struct platform_device *pdev) { struct edac_device_ctl_info *dci = platform_get_drvdata(pdev); edac_device_del_device(&pdev->dev); edac_device_free_ctl_info(dci); - return 0; } static struct platform_driver highbank_l2_edac_driver = { .probe = highbank_l2_err_probe, - .remove = highbank_l2_err_remove, + .remove_new = highbank_l2_err_remove, .driver = { .name = "hb_l2_edac", .of_match_table = hb_l2_err_of_match, diff --git a/drivers/edac/highbank_mc_edac.c b/drivers/edac/highbank_mc_edac.c index a0c04a7f95e91f..1c5b888ab11de3 100644 --- a/drivers/edac/highbank_mc_edac.c +++ b/drivers/edac/highbank_mc_edac.c @@ -251,18 +251,17 @@ free: return res; } -static int highbank_mc_remove(struct platform_device *pdev) +static void highbank_mc_remove(struct platform_device *pdev) { struct mem_ctl_info *mci = platform_get_drvdata(pdev); edac_mc_del_mc(&pdev->dev); edac_mc_free(mci); - return 0; } static struct platform_driver highbank_mc_edac_driver = { .probe = highbank_mc_probe, - .remove = highbank_mc_remove, + .remove_new = highbank_mc_remove, .driver = { .name = "hb_mc_edac", .of_match_table = hb_ddr_ctrl_of_match, diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 23d25724bae4c6..91e0a88ef90471 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -376,7 +376,7 @@ static const struct pci_id_table pci_dev_table[] = { PCI_ID_TABLE_ENTRY(pci_dev_descr_i7core_nehalem), PCI_ID_TABLE_ENTRY(pci_dev_descr_lynnfield), PCI_ID_TABLE_ENTRY(pci_dev_descr_i7core_westmere), - {0,} /* 0 terminated list. */ + { NULL, } }; /* @@ -385,7 +385,7 @@ static const struct pci_id_table pci_dev_table[] = { static const struct pci_device_id i7core_pci_tbl[] = { {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_X58_HUB_MGMT)}, {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNNFIELD_QPI_LINK0)}, - {0,} /* 0 terminated list. */ + { 0, } }; /**************************************************************************** diff --git a/drivers/edac/igen6_edac.c b/drivers/edac/igen6_edac.c index 1a18693294db48..2b0ecdeba5cdc9 100644 --- a/drivers/edac/igen6_edac.c +++ b/drivers/edac/igen6_edac.c @@ -58,6 +58,7 @@ /* Capability register E */ #define CAPID_E_OFFSET 0xf0 #define CAPID_E_IBECC BIT(12) +#define CAPID_E_IBECC_BIT18 BIT(18) /* Error Status */ #define ERRSTS_OFFSET 0xc8 @@ -80,6 +81,7 @@ #define ECC_ERROR_LOG_UE BIT_ULL(63) #define ECC_ERROR_LOG_ADDR_SHIFT 5 #define ECC_ERROR_LOG_ADDR(v) GET_BITFIELD(v, 5, 38) +#define ECC_ERROR_LOG_ADDR45(v) GET_BITFIELD(v, 5, 45) #define ECC_ERROR_LOG_SYND(v) GET_BITFIELD(v, 46, 61) /* Host MMIO base address */ @@ -133,6 +135,8 @@ static struct res_config { u32 ibecc_base; u32 ibecc_error_log_offset; bool (*ibecc_available)(struct pci_dev *pdev); + /* Extract error address logged in IBECC */ + u64 (*err_addr)(u64 ecclog); /* Convert error address logged in IBECC to system physical address */ u64 (*err_addr_to_sys_addr)(u64 eaddr, int mc); /* Convert error address logged in IBECC to integrated memory controller address */ @@ -222,6 +226,67 @@ static struct work_struct ecclog_work; #define DID_ADL_SKU3 0x4621 #define DID_ADL_SKU4 0x4641 +/* Compute die IDs for Alder Lake-N with IBECC */ +#define DID_ADL_N_SKU1 0x4614 +#define DID_ADL_N_SKU2 0x4617 +#define DID_ADL_N_SKU3 0x461b +#define DID_ADL_N_SKU4 0x461c +#define DID_ADL_N_SKU5 0x4673 +#define DID_ADL_N_SKU6 0x4674 +#define DID_ADL_N_SKU7 0x4675 +#define DID_ADL_N_SKU8 0x4677 +#define DID_ADL_N_SKU9 0x4678 +#define DID_ADL_N_SKU10 0x4679 +#define DID_ADL_N_SKU11 0x467c + +/* Compute die IDs for Raptor Lake-P with IBECC */ +#define DID_RPL_P_SKU1 0xa706 +#define DID_RPL_P_SKU2 0xa707 +#define DID_RPL_P_SKU3 0xa708 +#define DID_RPL_P_SKU4 0xa716 +#define DID_RPL_P_SKU5 0xa718 + +/* Compute die IDs for Meteor Lake-PS with IBECC */ +#define DID_MTL_PS_SKU1 0x7d21 +#define DID_MTL_PS_SKU2 0x7d22 +#define DID_MTL_PS_SKU3 0x7d23 +#define DID_MTL_PS_SKU4 0x7d24 + +/* Compute die IDs for Meteor Lake-P with IBECC */ +#define DID_MTL_P_SKU1 0x7d01 +#define DID_MTL_P_SKU2 0x7d02 +#define DID_MTL_P_SKU3 0x7d14 + +static int get_mchbar(struct pci_dev *pdev, u64 *mchbar) +{ + union { + u64 v; + struct { + u32 v_lo; + u32 v_hi; + }; + } u; + + if (pci_read_config_dword(pdev, MCHBAR_OFFSET, &u.v_lo)) { + igen6_printk(KERN_ERR, "Failed to read lower MCHBAR\n"); + return -ENODEV; + } + + if (pci_read_config_dword(pdev, MCHBAR_OFFSET + 4, &u.v_hi)) { + igen6_printk(KERN_ERR, "Failed to read upper MCHBAR\n"); + return -ENODEV; + } + + if (!(u.v & MCHBAR_EN)) { + igen6_printk(KERN_ERR, "MCHBAR is disabled\n"); + return -ENODEV; + } + + *mchbar = MCHBAR_BASE(u.v); + + return 0; +} + static bool ehl_ibecc_available(struct pci_dev *pdev) { u32 v; @@ -272,6 +337,39 @@ static bool tgl_ibecc_available(struct pci_dev *pdev) return !(CAPID_E_IBECC & v); } +static bool mtl_p_ibecc_available(struct pci_dev *pdev) +{ + u32 v; + + if (pci_read_config_dword(pdev, CAPID_E_OFFSET, &v)) + return false; + + return !(CAPID_E_IBECC_BIT18 & v); +} + +static bool mtl_ps_ibecc_available(struct pci_dev *pdev) +{ +#define MCHBAR_MEMSS_IBECCDIS 0x13c00 + void __iomem *window; + u64 mchbar; + u32 val; + + if (get_mchbar(pdev, &mchbar)) + return false; + + window = ioremap(mchbar, MCHBAR_SIZE * 2); + if (!window) { + igen6_printk(KERN_ERR, "Failed to ioremap 0x%llx\n", mchbar); + return false; + } + + val = readl(window + MCHBAR_MEMSS_IBECCDIS); + iounmap(window); + + /* Bit6: 1 - IBECC is disabled, 0 - IBECC isn't disabled */ + return !GET_BITFIELD(val, 6, 6); +} + static u64 mem_addr_to_sys_addr(u64 maddr) { if (maddr < igen6_tolud) @@ -358,6 +456,11 @@ static u64 adl_err_addr_to_imc_addr(u64 eaddr, int mc) return imc_addr; } +static u64 rpl_p_err_addr(u64 ecclog) +{ + return ECC_ERROR_LOG_ADDR45(ecclog); +} + static struct res_config ehl_cfg = { .num_imc = 1, .imc_base = 0x5000, @@ -403,6 +506,51 @@ static struct res_config adl_cfg = { .err_addr_to_imc_addr = adl_err_addr_to_imc_addr, }; +static struct res_config adl_n_cfg = { + .machine_check = true, + .num_imc = 1, + .imc_base = 0xd800, + .ibecc_base = 0xd400, + .ibecc_error_log_offset = 0x68, + .ibecc_available = tgl_ibecc_available, + .err_addr_to_sys_addr = adl_err_addr_to_sys_addr, + .err_addr_to_imc_addr = adl_err_addr_to_imc_addr, +}; + +static struct res_config rpl_p_cfg = { + .machine_check = true, + .num_imc = 2, + .imc_base = 0xd800, + .ibecc_base = 0xd400, + .ibecc_error_log_offset = 0x68, + .ibecc_available = tgl_ibecc_available, + .err_addr = rpl_p_err_addr, + .err_addr_to_sys_addr = adl_err_addr_to_sys_addr, + .err_addr_to_imc_addr = adl_err_addr_to_imc_addr, +}; + +static struct res_config mtl_ps_cfg = { + .machine_check = true, + .num_imc = 2, + .imc_base = 0xd800, + .ibecc_base = 0xd400, + .ibecc_error_log_offset = 0x170, + .ibecc_available = mtl_ps_ibecc_available, + .err_addr_to_sys_addr = adl_err_addr_to_sys_addr, + .err_addr_to_imc_addr = adl_err_addr_to_imc_addr, +}; + +static struct res_config mtl_p_cfg = { + .machine_check = true, + .num_imc = 2, + .imc_base = 0xd800, + .ibecc_base = 0xd400, + .ibecc_error_log_offset = 0x170, + .ibecc_available = mtl_p_ibecc_available, + .err_addr_to_sys_addr = adl_err_addr_to_sys_addr, + .err_addr_to_imc_addr = adl_err_addr_to_imc_addr, +}; + static const struct pci_device_id igen6_pci_tbl[] = { { PCI_VDEVICE(INTEL, DID_EHL_SKU5), (kernel_ulong_t)&ehl_cfg }, { PCI_VDEVICE(INTEL, DID_EHL_SKU6), (kernel_ulong_t)&ehl_cfg }, @@ -424,6 +572,29 @@ static const struct pci_device_id igen6_pci_tbl[] = { { PCI_VDEVICE(INTEL, DID_ADL_SKU2), (kernel_ulong_t)&adl_cfg }, { PCI_VDEVICE(INTEL, DID_ADL_SKU3), (kernel_ulong_t)&adl_cfg }, { PCI_VDEVICE(INTEL, DID_ADL_SKU4), (kernel_ulong_t)&adl_cfg }, + { PCI_VDEVICE(INTEL, DID_ADL_N_SKU1), (kernel_ulong_t)&adl_n_cfg }, + { PCI_VDEVICE(INTEL, DID_ADL_N_SKU2), (kernel_ulong_t)&adl_n_cfg }, + { PCI_VDEVICE(INTEL, DID_ADL_N_SKU3), (kernel_ulong_t)&adl_n_cfg }, + { PCI_VDEVICE(INTEL, DID_ADL_N_SKU4), (kernel_ulong_t)&adl_n_cfg }, + { PCI_VDEVICE(INTEL, DID_ADL_N_SKU5), (kernel_ulong_t)&adl_n_cfg }, + { PCI_VDEVICE(INTEL, DID_ADL_N_SKU6), (kernel_ulong_t)&adl_n_cfg }, + { PCI_VDEVICE(INTEL, DID_ADL_N_SKU7), (kernel_ulong_t)&adl_n_cfg }, + { PCI_VDEVICE(INTEL, DID_ADL_N_SKU8), (kernel_ulong_t)&adl_n_cfg }, + { PCI_VDEVICE(INTEL, DID_ADL_N_SKU9), (kernel_ulong_t)&adl_n_cfg }, + { PCI_VDEVICE(INTEL, DID_ADL_N_SKU10), (kernel_ulong_t)&adl_n_cfg }, + { PCI_VDEVICE(INTEL, DID_ADL_N_SKU11), (kernel_ulong_t)&adl_n_cfg }, + { PCI_VDEVICE(INTEL, DID_RPL_P_SKU1), (kernel_ulong_t)&rpl_p_cfg }, + { PCI_VDEVICE(INTEL, DID_RPL_P_SKU2), (kernel_ulong_t)&rpl_p_cfg }, + { PCI_VDEVICE(INTEL, DID_RPL_P_SKU3), (kernel_ulong_t)&rpl_p_cfg }, + { PCI_VDEVICE(INTEL, DID_RPL_P_SKU4), (kernel_ulong_t)&rpl_p_cfg }, + { PCI_VDEVICE(INTEL, DID_RPL_P_SKU5), (kernel_ulong_t)&rpl_p_cfg }, + { PCI_VDEVICE(INTEL, DID_MTL_PS_SKU1), (kernel_ulong_t)&mtl_ps_cfg }, + { PCI_VDEVICE(INTEL, DID_MTL_PS_SKU2), (kernel_ulong_t)&mtl_ps_cfg }, + { PCI_VDEVICE(INTEL, DID_MTL_PS_SKU3), (kernel_ulong_t)&mtl_ps_cfg }, + { PCI_VDEVICE(INTEL, DID_MTL_PS_SKU4), (kernel_ulong_t)&mtl_ps_cfg }, + { PCI_VDEVICE(INTEL, DID_MTL_P_SKU1), (kernel_ulong_t)&mtl_p_cfg }, + { PCI_VDEVICE(INTEL, DID_MTL_P_SKU2), (kernel_ulong_t)&mtl_p_cfg }, + { PCI_VDEVICE(INTEL, DID_MTL_P_SKU3), (kernel_ulong_t)&mtl_p_cfg }, { }, }; MODULE_DEVICE_TABLE(pci, igen6_pci_tbl); @@ -679,8 +850,11 @@ static void ecclog_work_cb(struct work_struct *work) llist_for_each_entry_safe(node, tmp, head, llnode) { memset(&res, 0, sizeof(res)); - eaddr = ECC_ERROR_LOG_ADDR(node->ecclog) << - ECC_ERROR_LOG_ADDR_SHIFT; + if (res_cfg->err_addr) + eaddr = res_cfg->err_addr(node->ecclog); + else + eaddr = ECC_ERROR_LOG_ADDR(node->ecclog) << + ECC_ERROR_LOG_ADDR_SHIFT; res.mc = node->mc; res.sys_addr = res_cfg->err_addr_to_sys_addr(eaddr, res.mc); res.imc_addr = res_cfg->err_addr_to_imc_addr(eaddr, res.mc); @@ -969,22 +1143,8 @@ static int igen6_pci_setup(struct pci_dev *pdev, u64 *mchbar) igen6_tom = u.v & GENMASK_ULL(38, 20); - if (pci_read_config_dword(pdev, MCHBAR_OFFSET, &u.v_lo)) { - igen6_printk(KERN_ERR, "Failed to read lower MCHBAR\n"); + if (get_mchbar(pdev, mchbar)) goto fail; - } - - if (pci_read_config_dword(pdev, MCHBAR_OFFSET + 4, &u.v_hi)) { - igen6_printk(KERN_ERR, "Failed to read upper MCHBAR\n"); - goto fail; - } - - if (!(u.v & MCHBAR_EN)) { - igen6_printk(KERN_ERR, "MCHBAR is disabled\n"); - goto fail; - } - - *mchbar = MCHBAR_BASE(u.v); #ifdef CONFIG_EDAC_DEBUG if (pci_read_config_dword(pdev, TOUUD_OFFSET, &u.v_lo)) diff --git a/drivers/edac/layerscape_edac.c b/drivers/edac/layerscape_edac.c index 7c5e2b3c0daa0c..d2f895033280f4 100644 --- a/drivers/edac/layerscape_edac.c +++ b/drivers/edac/layerscape_edac.c @@ -27,7 +27,7 @@ MODULE_DEVICE_TABLE(of, fsl_ddr_mc_err_of_match); static struct platform_driver fsl_ddr_mc_err_driver = { .probe = fsl_mc_err_probe, - .remove = fsl_mc_err_remove, + .remove_new = fsl_mc_err_remove, .driver = { .name = "fsl_ddr_mc_err", .of_match_table = fsl_ddr_mc_err_of_match, diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c index 9215c06783df5f..ec8b6c9fedfddf 100644 --- a/drivers/edac/mce_amd.c +++ b/drivers/edac/mce_amd.c @@ -143,482 +143,6 @@ static const char * const mc6_mce_desc[] = { "Status Register File", }; -/* Scalable MCA error strings */ -static const char * const smca_ls_mce_desc[] = { - "Load queue parity error", - "Store queue parity error", - "Miss address buffer payload parity error", - "Level 1 TLB parity error", - "DC Tag error type 5", - "DC Tag error type 6", - "DC Tag error type 1", - "Internal error type 1", - "Internal error type 2", - "System Read Data Error Thread 0", - "System Read Data Error Thread 1", - "DC Tag error type 2", - "DC Data error type 1 and poison consumption", - "DC Data error type 2", - "DC Data error type 3", - "DC Tag error type 4", - "Level 2 TLB parity error", - "PDC parity error", - "DC Tag error type 3", - "DC Tag error type 5", - "L2 Fill Data error", -}; - -static const char * const smca_ls2_mce_desc[] = { - "An ECC error was detected on a data cache read by a probe or victimization", - "An ECC error or L2 poison was detected on a data cache read by a load", - "An ECC error was detected on a data cache read-modify-write by a store", - "An ECC error or poison bit mismatch was detected on a tag read by a probe or victimization", - "An ECC error or poison bit mismatch was detected on a tag read by a load", - "An ECC error or poison bit mismatch was detected on a tag read by a store", - "An ECC error was detected on an EMEM read by a load", - "An ECC error was detected on an EMEM read-modify-write by a store", - "A parity error was detected in an L1 TLB entry by any access", - "A parity error was detected in an L2 TLB entry by any access", - "A parity error was detected in a PWC entry by any access", - "A parity error was detected in an STQ entry by any access", - "A parity error was detected in an LDQ entry by any access", - "A parity error was detected in a MAB entry by any access", - "A parity error was detected in an SCB entry state field by any access", - "A parity error was detected in an SCB entry address field by any access", - "A parity error was detected in an SCB entry data field by any access", - "A parity error was detected in a WCB entry by any access", - "A poisoned line was detected in an SCB entry by any access", - "A SystemReadDataError error was reported on read data returned from L2 for a load", - "A SystemReadDataError error was reported on read data returned from L2 for an SCB store", - "A SystemReadDataError error was reported on read data returned from L2 for a WCB store", - "A hardware assertion error was reported", - "A parity error was detected in an STLF, SCB EMEM entry or SRB store data by any access", -}; - -static const char * const smca_if_mce_desc[] = { - "Op Cache Microtag Probe Port Parity Error", - "IC Microtag or Full Tag Multi-hit Error", - "IC Full Tag Parity Error", - "IC Data Array Parity Error", - "Decoupling Queue PhysAddr Parity Error", - "L0 ITLB Parity Error", - "L1 ITLB Parity Error", - "L2 ITLB Parity Error", - "BPQ Thread 0 Snoop Parity Error", - "BPQ Thread 1 Snoop Parity Error", - "L1 BTB Multi-Match Error", - "L2 BTB Multi-Match Error", - "L2 Cache Response Poison Error", - "System Read Data Error", - "Hardware Assertion Error", - "L1-TLB Multi-Hit", - "L2-TLB Multi-Hit", - "BSR Parity Error", - "CT MCE", -}; - -static const char * const smca_l2_mce_desc[] = { - "L2M Tag Multiple-Way-Hit error", - "L2M Tag or State Array ECC Error", - "L2M Data Array ECC Error", - "Hardware Assert Error", -}; - -static const char * const smca_de_mce_desc[] = { - "Micro-op cache tag parity error", - "Micro-op cache data parity error", - "Instruction buffer parity error", - "Micro-op queue parity error", - "Instruction dispatch queue parity error", - "Fetch address FIFO parity error", - "Patch RAM data parity error", - "Patch RAM sequencer parity error", - "Micro-op buffer parity error", - "Hardware Assertion MCA Error", -}; - -static const char * const smca_ex_mce_desc[] = { - "Watchdog Timeout error", - "Physical register file parity error", - "Flag register file parity error", - "Immediate displacement register file parity error", - "Address generator payload parity error", - "EX payload parity error", - "Checkpoint queue parity error", - "Retire dispatch queue parity error", - "Retire status queue parity error", - "Scheduling queue parity error", - "Branch buffer queue parity error", - "Hardware Assertion error", - "Spec Map parity error", - "Retire Map parity error", -}; - -static const char * const smca_fp_mce_desc[] = { - "Physical register file (PRF) parity error", - "Freelist (FL) parity error", - "Schedule queue parity error", - "NSQ parity error", - "Retire queue (RQ) parity error", - "Status register file (SRF) parity error", - "Hardware assertion", -}; - -static const char * const smca_l3_mce_desc[] = { - "Shadow Tag Macro ECC Error", - "Shadow Tag Macro Multi-way-hit Error", - "L3M Tag ECC Error", - "L3M Tag Multi-way-hit Error", - "L3M Data ECC Error", - "SDP Parity Error or SystemReadDataError from XI", - "L3 Victim Queue Parity Error", - "L3 Hardware Assertion", -}; - -static const char * const smca_cs_mce_desc[] = { - "Illegal Request", - "Address Violation", - "Security Violation", - "Illegal Response", - "Unexpected Response", - "Request or Probe Parity Error", - "Read Response Parity Error", - "Atomic Request Parity Error", - "Probe Filter ECC Error", -}; - -static const char * const smca_cs2_mce_desc[] = { - "Illegal Request", - "Address Violation", - "Security Violation", - "Illegal Response", - "Unexpected Response", - "Request or Probe Parity Error", - "Read Response Parity Error", - "Atomic Request Parity Error", - "SDP read response had no match in the CS queue", - "Probe Filter Protocol Error", - "Probe Filter ECC Error", - "SDP read response had an unexpected RETRY error", - "Counter overflow error", - "Counter underflow error", -}; - -static const char * const smca_pie_mce_desc[] = { - "Hardware Assert", - "Register security violation", - "Link Error", - "Poison data consumption", - "A deferred error was detected in the DF" -}; - -static const char * const smca_umc_mce_desc[] = { - "DRAM ECC error", - "Data poison error", - "SDP parity error", - "Advanced peripheral bus error", - "Address/Command parity error", - "Write data CRC error", - "DCQ SRAM ECC error", - "AES SRAM ECC error", -}; - -static const char * const smca_umc2_mce_desc[] = { - "DRAM ECC error", - "Data poison error", - "SDP parity error", - "Reserved", - "Address/Command parity error", - "Write data parity error", - "DCQ SRAM ECC error", - "Reserved", - "Read data parity error", - "Rdb SRAM ECC error", - "RdRsp SRAM ECC error", - "LM32 MP errors", -}; - -static const char * const smca_pb_mce_desc[] = { - "An ECC error in the Parameter Block RAM array", -}; - -static const char * const smca_psp_mce_desc[] = { - "An ECC or parity error in a PSP RAM instance", -}; - -static const char * const smca_psp2_mce_desc[] = { - "High SRAM ECC or parity error", - "Low SRAM ECC or parity error", - "Instruction Cache Bank 0 ECC or parity error", - "Instruction Cache Bank 1 ECC or parity error", - "Instruction Tag Ram 0 parity error", - "Instruction Tag Ram 1 parity error", - "Data Cache Bank 0 ECC or parity error", - "Data Cache Bank 1 ECC or parity error", - "Data Cache Bank 2 ECC or parity error", - "Data Cache Bank 3 ECC or parity error", - "Data Tag Bank 0 parity error", - "Data Tag Bank 1 parity error", - "Data Tag Bank 2 parity error", - "Data Tag Bank 3 parity error", - "Dirty Data Ram parity error", - "TLB Bank 0 parity error", - "TLB Bank 1 parity error", - "System Hub Read Buffer ECC or parity error", -}; - -static const char * const smca_smu_mce_desc[] = { - "An ECC or parity error in an SMU RAM instance", -}; - -static const char * const smca_smu2_mce_desc[] = { - "High SRAM ECC or parity error", - "Low SRAM ECC or parity error", - "Data Cache Bank A ECC or parity error", - "Data Cache Bank B ECC or parity error", - "Data Tag Cache Bank A ECC or parity error", - "Data Tag Cache Bank B ECC or parity error", - "Instruction Cache Bank A ECC or parity error", - "Instruction Cache Bank B ECC or parity error", - "Instruction Tag Cache Bank A ECC or parity error", - "Instruction Tag Cache Bank B ECC or parity error", - "System Hub Read Buffer ECC or parity error", - "PHY RAM ECC error", -}; - -static const char * const smca_mp5_mce_desc[] = { - "High SRAM ECC or parity error", - "Low SRAM ECC or parity error", - "Data Cache Bank A ECC or parity error", - "Data Cache Bank B ECC or parity error", - "Data Tag Cache Bank A ECC or parity error", - "Data Tag Cache Bank B ECC or parity error", - "Instruction Cache Bank A ECC or parity error", - "Instruction Cache Bank B ECC or parity error", - "Instruction Tag Cache Bank A ECC or parity error", - "Instruction Tag Cache Bank B ECC or parity error", -}; - -static const char * const smca_mpdma_mce_desc[] = { - "Main SRAM [31:0] bank ECC or parity error", - "Main SRAM [63:32] bank ECC or parity error", - "Main SRAM [95:64] bank ECC or parity error", - "Main SRAM [127:96] bank ECC or parity error", - "Data Cache Bank A ECC or parity error", - "Data Cache Bank B ECC or parity error", - "Data Tag Cache Bank A ECC or parity error", - "Data Tag Cache Bank B ECC or parity error", - "Instruction Cache Bank A ECC or parity error", - "Instruction Cache Bank B ECC or parity error", - "Instruction Tag Cache Bank A ECC or parity error", - "Instruction Tag Cache Bank B ECC or parity error", - "Data Cache Bank A ECC or parity error", - "Data Cache Bank B ECC or parity error", - "Data Tag Cache Bank A ECC or parity error", - "Data Tag Cache Bank B ECC or parity error", - "Instruction Cache Bank A ECC or parity error", - "Instruction Cache Bank B ECC or parity error", - "Instruction Tag Cache Bank A ECC or parity error", - "Instruction Tag Cache Bank B ECC or parity error", - "Data Cache Bank A ECC or parity error", - "Data Cache Bank B ECC or parity error", - "Data Tag Cache Bank A ECC or parity error", - "Data Tag Cache Bank B ECC or parity error", - "Instruction Cache Bank A ECC or parity error", - "Instruction Cache Bank B ECC or parity error", - "Instruction Tag Cache Bank A ECC or parity error", - "Instruction Tag Cache Bank B ECC or parity error", - "System Hub Read Buffer ECC or parity error", - "MPDMA TVF DVSEC Memory ECC or parity error", - "MPDMA TVF MMIO Mailbox0 ECC or parity error", - "MPDMA TVF MMIO Mailbox1 ECC or parity error", - "MPDMA TVF Doorbell Memory ECC or parity error", - "MPDMA TVF SDP Slave Memory 0 ECC or parity error", - "MPDMA TVF SDP Slave Memory 1 ECC or parity error", - "MPDMA TVF SDP Slave Memory 2 ECC or parity error", - "MPDMA TVF SDP Master Memory 0 ECC or parity error", - "MPDMA TVF SDP Master Memory 1 ECC or parity error", - "MPDMA TVF SDP Master Memory 2 ECC or parity error", - "MPDMA TVF SDP Master Memory 3 ECC or parity error", - "MPDMA TVF SDP Master Memory 4 ECC or parity error", - "MPDMA TVF SDP Master Memory 5 ECC or parity error", - "MPDMA TVF SDP Master Memory 6 ECC or parity error", - "MPDMA PTE Command FIFO ECC or parity error", - "MPDMA PTE Hub Data FIFO ECC or parity error", - "MPDMA PTE Internal Data FIFO ECC or parity error", - "MPDMA PTE Command Memory DMA ECC or parity error", - "MPDMA PTE Command Memory Internal ECC or parity error", - "MPDMA PTE DMA Completion FIFO ECC or parity error", - "MPDMA PTE Tablewalk Completion FIFO ECC or parity error", - "MPDMA PTE Descriptor Completion FIFO ECC or parity error", - "MPDMA PTE ReadOnly Completion FIFO ECC or parity error", - "MPDMA PTE DirectWrite Completion FIFO ECC or parity error", - "SDP Watchdog Timer expired", -}; - -static const char * const smca_nbio_mce_desc[] = { - "ECC or Parity error", - "PCIE error", - "SDP ErrEvent error", - "SDP Egress Poison Error", - "IOHC Internal Poison Error", -}; - -static const char * const smca_pcie_mce_desc[] = { - "CCIX PER Message logging", - "CCIX Read Response with Status: Non-Data Error", - "CCIX Write Response with Status: Non-Data Error", - "CCIX Read Response with Status: Data Error", - "CCIX Non-okay write response with data error", -}; - -static const char * const smca_pcie2_mce_desc[] = { - "SDP Parity Error logging", -}; - -static const char * const smca_xgmipcs_mce_desc[] = { - "Data Loss Error", - "Training Error", - "Flow Control Acknowledge Error", - "Rx Fifo Underflow Error", - "Rx Fifo Overflow Error", - "CRC Error", - "BER Exceeded Error", - "Tx Vcid Data Error", - "Replay Buffer Parity Error", - "Data Parity Error", - "Replay Fifo Overflow Error", - "Replay Fifo Underflow Error", - "Elastic Fifo Overflow Error", - "Deskew Error", - "Flow Control CRC Error", - "Data Startup Limit Error", - "FC Init Timeout Error", - "Recovery Timeout Error", - "Ready Serial Timeout Error", - "Ready Serial Attempt Error", - "Recovery Attempt Error", - "Recovery Relock Attempt Error", - "Replay Attempt Error", - "Sync Header Error", - "Tx Replay Timeout Error", - "Rx Replay Timeout Error", - "LinkSub Tx Timeout Error", - "LinkSub Rx Timeout Error", - "Rx CMD Packet Error", -}; - -static const char * const smca_xgmiphy_mce_desc[] = { - "RAM ECC Error", - "ARC instruction buffer parity error", - "ARC data buffer parity error", - "PHY APB error", -}; - -static const char * const smca_nbif_mce_desc[] = { - "Timeout error from GMI", - "SRAM ECC error", - "NTB Error Event", - "SDP Parity error", -}; - -static const char * const smca_sata_mce_desc[] = { - "Parity error for port 0", - "Parity error for port 1", - "Parity error for port 2", - "Parity error for port 3", - "Parity error for port 4", - "Parity error for port 5", - "Parity error for port 6", - "Parity error for port 7", -}; - -static const char * const smca_usb_mce_desc[] = { - "Parity error or ECC error for S0 RAM0", - "Parity error or ECC error for S0 RAM1", - "Parity error or ECC error for S0 RAM2", - "Parity error for PHY RAM0", - "Parity error for PHY RAM1", - "AXI Slave Response error", -}; - -static const char * const smca_gmipcs_mce_desc[] = { - "Data Loss Error", - "Training Error", - "Replay Parity Error", - "Rx Fifo Underflow Error", - "Rx Fifo Overflow Error", - "CRC Error", - "BER Exceeded Error", - "Tx Fifo Underflow Error", - "Replay Buffer Parity Error", - "Tx Overflow Error", - "Replay Fifo Overflow Error", - "Replay Fifo Underflow Error", - "Elastic Fifo Overflow Error", - "Deskew Error", - "Offline Error", - "Data Startup Limit Error", - "FC Init Timeout Error", - "Recovery Timeout Error", - "Ready Serial Timeout Error", - "Ready Serial Attempt Error", - "Recovery Attempt Error", - "Recovery Relock Attempt Error", - "Deskew Abort Error", - "Rx Buffer Error", - "Rx LFDS Fifo Overflow Error", - "Rx LFDS Fifo Underflow Error", - "LinkSub Tx Timeout Error", - "LinkSub Rx Timeout Error", - "Rx CMD Packet Error", - "LFDS Training Timeout Error", - "LFDS FC Init Timeout Error", - "Data Loss Error", -}; - -struct smca_mce_desc { - const char * const *descs; - unsigned int num_descs; -}; - -static struct smca_mce_desc smca_mce_descs[] = { - [SMCA_LS] = { smca_ls_mce_desc, ARRAY_SIZE(smca_ls_mce_desc) }, - [SMCA_LS_V2] = { smca_ls2_mce_desc, ARRAY_SIZE(smca_ls2_mce_desc) }, - [SMCA_IF] = { smca_if_mce_desc, ARRAY_SIZE(smca_if_mce_desc) }, - [SMCA_L2_CACHE] = { smca_l2_mce_desc, ARRAY_SIZE(smca_l2_mce_desc) }, - [SMCA_DE] = { smca_de_mce_desc, ARRAY_SIZE(smca_de_mce_desc) }, - [SMCA_EX] = { smca_ex_mce_desc, ARRAY_SIZE(smca_ex_mce_desc) }, - [SMCA_FP] = { smca_fp_mce_desc, ARRAY_SIZE(smca_fp_mce_desc) }, - [SMCA_L3_CACHE] = { smca_l3_mce_desc, ARRAY_SIZE(smca_l3_mce_desc) }, - [SMCA_CS] = { smca_cs_mce_desc, ARRAY_SIZE(smca_cs_mce_desc) }, - [SMCA_CS_V2] = { smca_cs2_mce_desc, ARRAY_SIZE(smca_cs2_mce_desc) }, - [SMCA_PIE] = { smca_pie_mce_desc, ARRAY_SIZE(smca_pie_mce_desc) }, - [SMCA_UMC] = { smca_umc_mce_desc, ARRAY_SIZE(smca_umc_mce_desc) }, - [SMCA_UMC_V2] = { smca_umc2_mce_desc, ARRAY_SIZE(smca_umc2_mce_desc) }, - [SMCA_PB] = { smca_pb_mce_desc, ARRAY_SIZE(smca_pb_mce_desc) }, - [SMCA_PSP] = { smca_psp_mce_desc, ARRAY_SIZE(smca_psp_mce_desc) }, - [SMCA_PSP_V2] = { smca_psp2_mce_desc, ARRAY_SIZE(smca_psp2_mce_desc) }, - [SMCA_SMU] = { smca_smu_mce_desc, ARRAY_SIZE(smca_smu_mce_desc) }, - [SMCA_SMU_V2] = { smca_smu2_mce_desc, ARRAY_SIZE(smca_smu2_mce_desc) }, - [SMCA_MP5] = { smca_mp5_mce_desc, ARRAY_SIZE(smca_mp5_mce_desc) }, - [SMCA_MPDMA] = { smca_mpdma_mce_desc, ARRAY_SIZE(smca_mpdma_mce_desc) }, - [SMCA_NBIO] = { smca_nbio_mce_desc, ARRAY_SIZE(smca_nbio_mce_desc) }, - [SMCA_PCIE] = { smca_pcie_mce_desc, ARRAY_SIZE(smca_pcie_mce_desc) }, - [SMCA_PCIE_V2] = { smca_pcie2_mce_desc, ARRAY_SIZE(smca_pcie2_mce_desc) }, - [SMCA_XGMI_PCS] = { smca_xgmipcs_mce_desc, ARRAY_SIZE(smca_xgmipcs_mce_desc) }, - /* NBIF and SHUB have the same error descriptions, for now. */ - [SMCA_NBIF] = { smca_nbif_mce_desc, ARRAY_SIZE(smca_nbif_mce_desc) }, - [SMCA_SHUB] = { smca_nbif_mce_desc, ARRAY_SIZE(smca_nbif_mce_desc) }, - [SMCA_SATA] = { smca_sata_mce_desc, ARRAY_SIZE(smca_sata_mce_desc) }, - [SMCA_USB] = { smca_usb_mce_desc, ARRAY_SIZE(smca_usb_mce_desc) }, - [SMCA_GMI_PCS] = { smca_gmipcs_mce_desc, ARRAY_SIZE(smca_gmipcs_mce_desc) }, - /* All the PHY bank types have the same error descriptions, for now. */ - [SMCA_XGMI_PHY] = { smca_xgmiphy_mce_desc, ARRAY_SIZE(smca_xgmiphy_mce_desc) }, - [SMCA_WAFL_PHY] = { smca_xgmiphy_mce_desc, ARRAY_SIZE(smca_xgmiphy_mce_desc) }, - [SMCA_GMI_PHY] = { smca_xgmiphy_mce_desc, ARRAY_SIZE(smca_xgmiphy_mce_desc) }, -}; - static bool f12h_mc0_mce(u16 ec, u8 xec) { bool ret = false; @@ -1163,11 +687,51 @@ static void decode_mc6_mce(struct mce *m) pr_emerg(HW_ERR "Corrupted MC6 MCE info?\n"); } +static const char * const smca_long_names[] = { + [SMCA_LS ... SMCA_LS_V2] = "Load Store Unit", + [SMCA_IF] = "Instruction Fetch Unit", + [SMCA_L2_CACHE] = "L2 Cache", + [SMCA_DE] = "Decode Unit", + [SMCA_RESERVED] = "Reserved", + [SMCA_EX] = "Execution Unit", + [SMCA_FP] = "Floating Point Unit", + [SMCA_L3_CACHE] = "L3 Cache", + [SMCA_CS ... SMCA_CS_V2] = "Coherent Slave", + [SMCA_PIE] = "Power, Interrupts, etc.", + + /* UMC v2 is separate because both of them can exist in a single system. */ + [SMCA_UMC] = "Unified Memory Controller", + [SMCA_UMC_V2] = "Unified Memory Controller v2", + [SMCA_PB] = "Parameter Block", + [SMCA_PSP ... SMCA_PSP_V2] = "Platform Security Processor", + [SMCA_SMU ... SMCA_SMU_V2] = "System Management Unit", + [SMCA_MP5] = "Microprocessor 5 Unit", + [SMCA_MPDMA] = "MPDMA Unit", + [SMCA_NBIO] = "Northbridge IO Unit", + [SMCA_PCIE ... SMCA_PCIE_V2] = "PCI Express Unit", + [SMCA_XGMI_PCS] = "Ext Global Memory Interconnect PCS Unit", + [SMCA_NBIF] = "NBIF Unit", + [SMCA_SHUB] = "System Hub Unit", + [SMCA_SATA] = "SATA Unit", + [SMCA_USB] = "USB Unit", + [SMCA_GMI_PCS] = "Global Memory Interconnect PCS Unit", + [SMCA_XGMI_PHY] = "Ext Global Memory Interconnect PHY Unit", + [SMCA_WAFL_PHY] = "WAFL PHY Unit", + [SMCA_GMI_PHY] = "Global Memory Interconnect PHY Unit", +}; + +static const char *smca_get_long_name(enum smca_bank_types t) +{ + if (t >= N_SMCA_BANK_TYPES) + return NULL; + + return smca_long_names[t]; +} + /* Decode errors according to Scalable MCA specification */ static void decode_smca_error(struct mce *m) { enum smca_bank_types bank_type = smca_get_bank_type(m->extcpu, m->bank); - const char *ip_name; u8 xec = XEC(m->status, xec_mask); if (bank_type >= N_SMCA_BANK_TYPES) @@ -1178,13 +742,7 @@ static void decode_smca_error(struct mce *m) return; } - ip_name = smca_get_long_name(bank_type); - - pr_emerg(HW_ERR "%s Ext. Error Code: %d", ip_name, xec); - - /* Only print the decode of valid error codes */ - if (xec < smca_mce_descs[bank_type].num_descs) - pr_cont(", %s.\n", smca_mce_descs[bank_type].descs[xec]); + pr_emerg(HW_ERR "%s Ext. Error Code: %d", smca_get_long_name(bank_type), xec); if ((bank_type == SMCA_UMC || bank_type == SMCA_UMC_V2) && xec == 0 && decode_dram_ecc) diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c index 2b5703e5066e80..c1bc53f4e184c8 100644 --- a/drivers/edac/mpc85xx_edac.c +++ b/drivers/edac/mpc85xx_edac.c @@ -300,7 +300,7 @@ err: return res; } -static int mpc85xx_pci_err_remove(struct platform_device *op) +static void mpc85xx_pci_err_remove(struct platform_device *op) { struct edac_pci_ctl_info *pci = dev_get_drvdata(&op->dev); struct mpc85xx_pci_pdata *pdata = pci->pvt_info; @@ -312,8 +312,6 @@ static int mpc85xx_pci_err_remove(struct platform_device *op) edac_pci_del_device(&op->dev); edac_pci_free_ctl_info(pci); - - return 0; } static const struct platform_device_id mpc85xx_pci_err_match[] = { @@ -325,7 +323,7 @@ static const struct platform_device_id mpc85xx_pci_err_match[] = { static struct platform_driver mpc85xx_pci_err_driver = { .probe = mpc85xx_pci_err_probe, - .remove = mpc85xx_pci_err_remove, + .remove_new = mpc85xx_pci_err_remove, .id_table = mpc85xx_pci_err_match, .driver = { .name = "mpc85xx_pci_err", @@ -591,7 +589,7 @@ err: return res; } -static int mpc85xx_l2_err_remove(struct platform_device *op) +static void mpc85xx_l2_err_remove(struct platform_device *op) { struct edac_device_ctl_info *edac_dev = dev_get_drvdata(&op->dev); struct mpc85xx_l2_pdata *pdata = edac_dev->pvt_info; @@ -606,7 +604,6 @@ static int mpc85xx_l2_err_remove(struct platform_device *op) out_be32(pdata->l2_vbase + MPC85XX_L2_ERRDIS, orig_l2_err_disable); edac_device_del_device(&op->dev); edac_device_free_ctl_info(edac_dev); - return 0; } static const struct of_device_id mpc85xx_l2_err_of_match[] = { @@ -630,7 +627,7 @@ MODULE_DEVICE_TABLE(of, mpc85xx_l2_err_of_match); static struct platform_driver mpc85xx_l2_err_driver = { .probe = mpc85xx_l2_err_probe, - .remove = mpc85xx_l2_err_remove, + .remove_new = mpc85xx_l2_err_remove, .driver = { .name = "mpc85xx_l2_err", .of_match_table = mpc85xx_l2_err_of_match, @@ -659,7 +656,7 @@ MODULE_DEVICE_TABLE(of, mpc85xx_mc_err_of_match); static struct platform_driver mpc85xx_mc_err_driver = { .probe = fsl_mc_err_probe, - .remove = fsl_mc_err_remove, + .remove_new = fsl_mc_err_remove, .driver = { .name = "mpc85xx_mc_err", .of_match_table = mpc85xx_mc_err_of_match, diff --git a/drivers/edac/npcm_edac.c b/drivers/edac/npcm_edac.c index 6d15c1550263fa..2e2133b784e922 100644 --- a/drivers/edac/npcm_edac.c +++ b/drivers/edac/npcm_edac.c @@ -410,7 +410,7 @@ free_edac_mc: return rc; } -static int edac_remove(struct platform_device *pdev) +static void edac_remove(struct platform_device *pdev) { struct mem_ctl_info *mci = platform_get_drvdata(pdev); struct priv_data *priv = mci->pvt_info; @@ -426,8 +426,6 @@ static int edac_remove(struct platform_device *pdev) regmap_write(npcm_regmap, pdata->ctl_int_mask_master, pdata->int_mask_master_global_mask); regmap_update_bits(npcm_regmap, pdata->ctl_ecc_en, pdata->ecc_en_mask, 0); - - return 0; } static const struct npcm_platform_data npcm750_edac = { @@ -533,7 +531,7 @@ static struct platform_driver npcm_edac_driver = { .of_match_table = npcm_edac_of_match, }, .probe = edac_probe, - .remove = edac_remove, + .remove_new = edac_remove, }; module_platform_driver(npcm_edac_driver); diff --git a/drivers/edac/octeon_edac-l2c.c b/drivers/edac/octeon_edac-l2c.c index c33059e9b0be2c..4015eb9af6feb6 100644 --- a/drivers/edac/octeon_edac-l2c.c +++ b/drivers/edac/octeon_edac-l2c.c @@ -184,19 +184,17 @@ err: return -ENXIO; } -static int octeon_l2c_remove(struct platform_device *pdev) +static void octeon_l2c_remove(struct platform_device *pdev) { struct edac_device_ctl_info *l2c = platform_get_drvdata(pdev); edac_device_del_device(&pdev->dev); edac_device_free_ctl_info(l2c); - - return 0; } static struct platform_driver octeon_l2c_driver = { .probe = octeon_l2c_probe, - .remove = octeon_l2c_remove, + .remove_new = octeon_l2c_remove, .driver = { .name = "octeon_l2c_edac", } diff --git a/drivers/edac/octeon_edac-lmc.c b/drivers/edac/octeon_edac-lmc.c index aeb222ca3ed12c..18615cbcd9ea19 100644 --- a/drivers/edac/octeon_edac-lmc.c +++ b/drivers/edac/octeon_edac-lmc.c @@ -302,18 +302,17 @@ static int octeon_lmc_edac_probe(struct platform_device *pdev) return 0; } -static int octeon_lmc_edac_remove(struct platform_device *pdev) +static void octeon_lmc_edac_remove(struct platform_device *pdev) { struct mem_ctl_info *mci = platform_get_drvdata(pdev); edac_mc_del_mc(&pdev->dev); edac_mc_free(mci); - return 0; } static struct platform_driver octeon_lmc_edac_driver = { .probe = octeon_lmc_edac_probe, - .remove = octeon_lmc_edac_remove, + .remove_new = octeon_lmc_edac_remove, .driver = { .name = "octeon_lmc_edac", } diff --git a/drivers/edac/octeon_edac-pc.c b/drivers/edac/octeon_edac-pc.c index 754eced59c32b9..ea8a8e337b1e89 100644 --- a/drivers/edac/octeon_edac-pc.c +++ b/drivers/edac/octeon_edac-pc.c @@ -119,19 +119,18 @@ err: return -ENXIO; } -static int co_cache_error_remove(struct platform_device *pdev) +static void co_cache_error_remove(struct platform_device *pdev) { struct co_cache_error *p = platform_get_drvdata(pdev); unregister_co_cache_error_notifier(&p->notifier); edac_device_del_device(&pdev->dev); edac_device_free_ctl_info(p->ed); - return 0; } static struct platform_driver co_cache_error_driver = { .probe = co_cache_error_probe, - .remove = co_cache_error_remove, + .remove_new = co_cache_error_remove, .driver = { .name = "octeon_pc_edac", } diff --git a/drivers/edac/octeon_edac-pci.c b/drivers/edac/octeon_edac-pci.c index 28b238eecefcc9..108ad9493cfbe9 100644 --- a/drivers/edac/octeon_edac-pci.c +++ b/drivers/edac/octeon_edac-pci.c @@ -87,19 +87,17 @@ err: return res; } -static int octeon_pci_remove(struct platform_device *pdev) +static void octeon_pci_remove(struct platform_device *pdev) { struct edac_pci_ctl_info *pci = platform_get_drvdata(pdev); edac_pci_del_device(&pdev->dev); edac_pci_free_ctl_info(pci); - - return 0; } static struct platform_driver octeon_pci_driver = { .probe = octeon_pci_probe, - .remove = octeon_pci_remove, + .remove_new = octeon_pci_remove, .driver = { .name = "octeon_pci_edac", } diff --git a/drivers/edac/pnd2_edac.c b/drivers/edac/pnd2_edac.c index 2b306f2cc60585..2afcd148fcf880 100644 --- a/drivers/edac/pnd2_edac.c +++ b/drivers/edac/pnd2_edac.c @@ -16,18 +16,20 @@ * rank, bank, row and column using the appropriate "dunit_ops" functions/parameters. */ -#include +#include +#include +#include #include +#include +#include +#include +#include #include #include +#include #include -#include -#include -#include #include -#include -#include -#include + #include #include @@ -109,7 +111,6 @@ static struct mem_ctl_info *pnd2_mci; #define MOT_CHAN_INTLV_BIT_1SLC_2CH 12 #define MOT_CHAN_INTLV_BIT_2SLC_2CH 13 #define SELECTOR_DISABLED (-1) -#define _4GB (1ul << 32) #define PMI_ADDRESS_WIDTH 31 #define PND_MAX_PHYS_BIT 39 @@ -183,7 +184,7 @@ static int _apl_rd_reg(int port, int off, int op, u32 *data) } P2SB_READ(dword, P2SB_DATA_OFF, data); - ret = (status >> 1) & 0x3; + ret = (status >> 1) & GENMASK(1, 0); out: /* Hide the P2SB device, if it was hidden before */ if (hidden) @@ -307,7 +308,7 @@ static bool two_channels; /* Both PMI channels in one slice enabled */ static u8 sym_chan_mask; static u8 asym_chan_mask; -static u8 chan_mask; +static unsigned long chan_mask; static int slice_selector = -1; static int chan_selector = -1; @@ -329,7 +330,7 @@ static void mk_region_mask(char *name, struct region *rp, u64 base, u64 mask) return; } if (mask != GENMASK_ULL(PND_MAX_PHYS_BIT, __ffs(mask))) { - pr_info(FW_BUG "MOT mask not power of two\n"); + pr_info(FW_BUG "MOT mask is invalid\n"); return; } if (base & ~mask) { @@ -587,7 +588,7 @@ static int get_registers(void) /* Get a contiguous memory address (remove the MMIO gap) */ static u64 remove_mmio_gap(u64 sys) { - return (sys < _4GB) ? sys : sys - (_4GB - top_lm); + return (sys < SZ_4G) ? sys : sys - (SZ_4G - top_lm); } /* Squeeze out one address bit, shift upper part down to fill gap */ @@ -598,7 +599,7 @@ static void remove_addr_bit(u64 *addr, int bitidx) if (bitidx == -1) return; - mask = (1ull << bitidx) - 1; + mask = BIT_ULL(bitidx) - 1; *addr = ((*addr >> 1) & ~mask) | (*addr & mask); } @@ -642,8 +643,8 @@ static int sys2pmi(const u64 addr, u32 *pmiidx, u64 *pmiaddr, char *msg) int sym_chan_shift = sym_channels >> 1; /* Give up if address is out of range, or in MMIO gap */ - if (addr >= (1ul << PND_MAX_PHYS_BIT) || - (addr >= top_lm && addr < _4GB) || addr >= top_hm) { + if (addr >= BIT(PND_MAX_PHYS_BIT) || + (addr >= top_lm && addr < SZ_4G) || addr >= top_hm) { snprintf(msg, PND2_MSG_SIZE, "Error address 0x%llx is not DRAM", addr); return -EINVAL; } @@ -727,10 +728,10 @@ static int sys2pmi(const u64 addr, u32 *pmiidx, u64 *pmiaddr, char *msg) } /* Translate PMI address to memory (rank, row, bank, column) */ -#define C(n) (0x10 | (n)) /* column */ -#define B(n) (0x20 | (n)) /* bank */ -#define R(n) (0x40 | (n)) /* row */ -#define RS (0x80) /* rank */ +#define C(n) (BIT(4) | (n)) /* column */ +#define B(n) (BIT(5) | (n)) /* bank */ +#define R(n) (BIT(6) | (n)) /* row */ +#define RS (BIT(7)) /* rank */ /* addrdec values */ #define AMAP_1KB 0 @@ -1064,9 +1065,9 @@ static int apl_check_ecc_active(void) int i, ret = 0; /* Check dramtype and ECC mode for each present DIMM */ - for (i = 0; i < APL_NUM_CHANNELS; i++) - if (chan_mask & BIT(i)) - ret += check_channel(i); + for_each_set_bit(i, &chan_mask, APL_NUM_CHANNELS) + ret += check_channel(i); + return ret ? -EINVAL : 0; } @@ -1205,10 +1206,7 @@ static void apl_get_dimm_config(struct mem_ctl_info *mci) u64 capacity; int i, g; - for (i = 0; i < APL_NUM_CHANNELS; i++) { - if (!(chan_mask & BIT(i))) - continue; - + for_each_set_bit(i, &chan_mask, APL_NUM_CHANNELS) { dimm = edac_get_dimm(mci, i, 0, 0); if (!dimm) { edac_dbg(0, "No allocated DIMM for channel %d\n", i); @@ -1228,8 +1226,7 @@ static void apl_get_dimm_config(struct mem_ctl_info *mci) } pvt->dimm_geom[i] = g; - capacity = (d->rken0 + d->rken1) * 8 * (1ul << dimms[g].rowbits) * - (1ul << dimms[g].colbits); + capacity = (d->rken0 + d->rken1) * 8 * BIT(dimms[g].rowbits + dimms[g].colbits); edac_dbg(0, "Channel %d: %lld MByte DIMM\n", i, capacity >> (20 - 3)); dimm->nr_pages = MiB_TO_PAGES(capacity >> (20 - 3)); dimm->grain = 32; @@ -1295,7 +1292,7 @@ static void dnv_get_dimm_config(struct mem_ctl_info *mci) continue; } - capacity = ranks_of_dimm[j] * banks * (1ul << rowbits) * (1ul << colbits); + capacity = ranks_of_dimm[j] * banks * BIT(rowbits + colbits); edac_dbg(0, "Channel %d DIMM %d: %lld MByte DIMM\n", i, j, capacity >> (20 - 3)); dimm->nr_pages = MiB_TO_PAGES(capacity >> (20 - 3)); dimm->grain = 32; diff --git a/drivers/edac/ppc4xx_edac.c b/drivers/edac/ppc4xx_edac.c index 046969b4e82ef4..1eea3341a91682 100644 --- a/drivers/edac/ppc4xx_edac.c +++ b/drivers/edac/ppc4xx_edac.c @@ -1329,8 +1329,7 @@ static int ppc4xx_edac_probe(struct platform_device *op) * * Unconditionally returns 0. */ -static int -ppc4xx_edac_remove(struct platform_device *op) +static void ppc4xx_edac_remove(struct platform_device *op) { struct mem_ctl_info *mci = dev_get_drvdata(&op->dev); struct ppc4xx_edac_pdata *pdata = mci->pvt_info; @@ -1344,8 +1343,6 @@ ppc4xx_edac_remove(struct platform_device *op) edac_mc_del_mc(mci->pdev); edac_mc_free(mci); - - return 0; } /** @@ -1379,7 +1376,7 @@ ppc4xx_edac_opstate_init(void) static struct platform_driver ppc4xx_edac_driver = { .probe = ppc4xx_edac_probe, - .remove = ppc4xx_edac_remove, + .remove_new = ppc4xx_edac_remove, .driver = { .name = PPC4XX_EDAC_MODULE_NAME, .of_match_table = ppc4xx_edac_match, diff --git a/drivers/edac/qcom_edac.c b/drivers/edac/qcom_edac.c index b2db545c681031..5539917c01ddbe 100644 --- a/drivers/edac/qcom_edac.c +++ b/drivers/edac/qcom_edac.c @@ -390,14 +390,12 @@ irq_done: return rc; } -static int qcom_llcc_edac_remove(struct platform_device *pdev) +static void qcom_llcc_edac_remove(struct platform_device *pdev) { struct edac_device_ctl_info *edev_ctl = dev_get_drvdata(&pdev->dev); edac_device_del_device(edev_ctl->dev); edac_device_free_ctl_info(edev_ctl); - - return 0; } static const struct platform_device_id qcom_llcc_edac_id_table[] = { @@ -408,7 +406,7 @@ MODULE_DEVICE_TABLE(platform, qcom_llcc_edac_id_table); static struct platform_driver qcom_llcc_edac_driver = { .probe = qcom_llcc_edac_probe, - .remove = qcom_llcc_edac_remove, + .remove_new = qcom_llcc_edac_remove, .driver = { .name = "qcom_llcc_edac", }, diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index 0c779a0326b628..26cca5a9322da1 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -439,7 +439,7 @@ static const struct pci_id_descr pci_dev_descr_sbridge[] = { static const struct pci_id_table pci_dev_descr_sbridge_table[] = { PCI_ID_TABLE_ENTRY(pci_dev_descr_sbridge, ARRAY_SIZE(pci_dev_descr_sbridge), 1, SANDY_BRIDGE), - {0,} /* 0 terminated list. */ + { NULL, } }; /* This changes depending if 1HA or 2HA: @@ -505,7 +505,7 @@ static const struct pci_id_descr pci_dev_descr_ibridge[] = { static const struct pci_id_table pci_dev_descr_ibridge_table[] = { PCI_ID_TABLE_ENTRY(pci_dev_descr_ibridge, 12, 2, IVY_BRIDGE), - {0,} /* 0 terminated list. */ + { NULL, } }; /* Haswell support */ @@ -576,7 +576,7 @@ static const struct pci_id_descr pci_dev_descr_haswell[] = { static const struct pci_id_table pci_dev_descr_haswell_table[] = { PCI_ID_TABLE_ENTRY(pci_dev_descr_haswell, 13, 2, HASWELL), - {0,} /* 0 terminated list. */ + { NULL, } }; /* Knight's Landing Support */ @@ -620,7 +620,7 @@ static const struct pci_id_descr pci_dev_descr_knl[] = { static const struct pci_id_table pci_dev_descr_knl_table[] = { PCI_ID_TABLE_ENTRY(pci_dev_descr_knl, ARRAY_SIZE(pci_dev_descr_knl), 1, KNIGHTS_LANDING), - {0,} + { NULL, } }; /* @@ -686,7 +686,7 @@ static const struct pci_id_descr pci_dev_descr_broadwell[] = { static const struct pci_id_table pci_dev_descr_broadwell_table[] = { PCI_ID_TABLE_ENTRY(pci_dev_descr_broadwell, 10, 2, BROADWELL), - {0,} /* 0 terminated list. */ + { NULL, } }; diff --git a/drivers/edac/skx_common.c b/drivers/edac/skx_common.c index ce3e0069e028d0..9c5b6f8bd8bd59 100644 --- a/drivers/edac/skx_common.c +++ b/drivers/edac/skx_common.c @@ -648,6 +648,10 @@ int skx_mce_check_error(struct notifier_block *nb, unsigned long val, memset(&res, 0, sizeof(res)); res.mce = mce; res.addr = mce->addr & MCI_ADDR_PHYSADDR; + if (!pfn_to_online_page(res.addr >> PAGE_SHIFT)) { + pr_err("Invalid address 0x%llx in IA32_MC%d_ADDR\n", mce->addr, mce->bank); + return NOTIFY_DONE; + } /* Try driver decoder first */ if (!(driver_decode && driver_decode(&res))) { diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index c4fc64cbecd0e6..709babce43ba02 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -1410,7 +1410,7 @@ free_edac_mc: * * Return: Unconditionally 0 */ -static int mc_remove(struct platform_device *pdev) +static void mc_remove(struct platform_device *pdev) { struct mem_ctl_info *mci = platform_get_drvdata(pdev); struct synps_edac_priv *priv = mci->pvt_info; @@ -1425,8 +1425,6 @@ static int mc_remove(struct platform_device *pdev) edac_mc_del_mc(&pdev->dev); edac_mc_free(mci); - - return 0; } static struct platform_driver synps_edac_mc_driver = { @@ -1435,7 +1433,7 @@ static struct platform_driver synps_edac_mc_driver = { .of_match_table = synps_edac_match, }, .probe = mc_probe, - .remove = mc_remove, + .remove_new = mc_remove, }; module_platform_driver(synps_edac_mc_driver); diff --git a/drivers/edac/thunderx_edac.c b/drivers/edac/thunderx_edac.c index b9c5772da959cc..90d46e5c4ff069 100644 --- a/drivers/edac/thunderx_edac.c +++ b/drivers/edac/thunderx_edac.c @@ -1133,7 +1133,7 @@ static irqreturn_t thunderx_ocx_com_threaded_isr(int irq, void *irq_id) decode_register(other, OCX_OTHER_SIZE, ocx_com_errors, ctx->reg_com_int); - strncat(msg, other, OCX_MESSAGE_SIZE); + strlcat(msg, other, OCX_MESSAGE_SIZE); for (lane = 0; lane < OCX_RX_LANES; lane++) if (ctx->reg_com_int & BIT(lane)) { @@ -1142,12 +1142,12 @@ static irqreturn_t thunderx_ocx_com_threaded_isr(int irq, void *irq_id) lane, ctx->reg_lane_int[lane], lane, ctx->reg_lane_stat11[lane]); - strncat(msg, other, OCX_MESSAGE_SIZE); + strlcat(msg, other, OCX_MESSAGE_SIZE); decode_register(other, OCX_OTHER_SIZE, ocx_lane_errors, ctx->reg_lane_int[lane]); - strncat(msg, other, OCX_MESSAGE_SIZE); + strlcat(msg, other, OCX_MESSAGE_SIZE); } if (ctx->reg_com_int & OCX_COM_INT_CE) @@ -1217,7 +1217,7 @@ static irqreturn_t thunderx_ocx_lnk_threaded_isr(int irq, void *irq_id) decode_register(other, OCX_OTHER_SIZE, ocx_com_link_errors, ctx->reg_com_link_int); - strncat(msg, other, OCX_MESSAGE_SIZE); + strlcat(msg, other, OCX_MESSAGE_SIZE); if (ctx->reg_com_link_int & OCX_COM_LINK_INT_UE) edac_device_handle_ue(ocx->edac_dev, 0, 0, msg); @@ -1896,7 +1896,7 @@ static irqreturn_t thunderx_l2c_threaded_isr(int irq, void *irq_id) decode_register(other, L2C_OTHER_SIZE, l2_errors, ctx->reg_int); - strncat(msg, other, L2C_MESSAGE_SIZE); + strlcat(msg, other, L2C_MESSAGE_SIZE); if (ctx->reg_int & mask_ue) edac_device_handle_ue(l2c->edac_dev, 0, 0, msg); diff --git a/drivers/edac/ti_edac.c b/drivers/edac/ti_edac.c index 6971ded598de09..29723c9592f79e 100644 --- a/drivers/edac/ti_edac.c +++ b/drivers/edac/ti_edac.c @@ -312,19 +312,17 @@ err: return ret; } -static int ti_edac_remove(struct platform_device *pdev) +static void ti_edac_remove(struct platform_device *pdev) { struct mem_ctl_info *mci = platform_get_drvdata(pdev); edac_mc_del_mc(&pdev->dev); edac_mc_free(mci); - - return 0; } static struct platform_driver ti_edac_driver = { .probe = ti_edac_probe, - .remove = ti_edac_remove, + .remove_new = ti_edac_remove, .driver = { .name = EDAC_MOD_NAME, .of_match_table = ti_edac_of_match, diff --git a/drivers/edac/versal_edac.c b/drivers/edac/versal_edac.c index 8625de20fc7175..62caf454b56707 100644 --- a/drivers/edac/versal_edac.c +++ b/drivers/edac/versal_edac.c @@ -1005,7 +1005,7 @@ static int mc_probe(struct platform_device *pdev) goto free_edac_mc; } - rc = xlnx_register_event(PM_NOTIFY_CB, EVENT_ERROR_PMC_ERR1, + rc = xlnx_register_event(PM_NOTIFY_CB, VERSAL_EVENT_ERROR_PMC_ERR1, XPM_EVENT_ERROR_MASK_DDRMC_CR | XPM_EVENT_ERROR_MASK_DDRMC_NCR | XPM_EVENT_ERROR_MASK_NOC_CR | XPM_EVENT_ERROR_MASK_NOC_NCR, false, err_callback, mci); @@ -1042,7 +1042,7 @@ static int mc_remove(struct platform_device *pdev) debugfs_remove_recursive(priv->debugfs); #endif - xlnx_unregister_event(PM_NOTIFY_CB, EVENT_ERROR_PMC_ERR1, + xlnx_unregister_event(PM_NOTIFY_CB, VERSAL_EVENT_ERROR_PMC_ERR1, XPM_EVENT_ERROR_MASK_DDRMC_CR | XPM_EVENT_ERROR_MASK_NOC_CR | XPM_EVENT_ERROR_MASK_NOC_NCR | diff --git a/drivers/edac/xgene_edac.c b/drivers/edac/xgene_edac.c index c52b9dd9154c1d..1b50f816001393 100644 --- a/drivers/edac/xgene_edac.c +++ b/drivers/edac/xgene_edac.c @@ -1960,7 +1960,7 @@ out_err: return rc; } -static int xgene_edac_remove(struct platform_device *pdev) +static void xgene_edac_remove(struct platform_device *pdev) { struct xgene_edac *edac = dev_get_drvdata(&pdev->dev); struct xgene_edac_mc_ctx *mcu; @@ -1981,8 +1981,6 @@ static int xgene_edac_remove(struct platform_device *pdev) list_for_each_entry_safe(node, temp_node, &edac->socs, next) xgene_edac_soc_remove(node); - - return 0; } static const struct of_device_id xgene_edac_of_match[] = { @@ -1993,7 +1991,7 @@ MODULE_DEVICE_TABLE(of, xgene_edac_of_match); static struct platform_driver xgene_edac_driver = { .probe = xgene_edac_probe, - .remove = xgene_edac_remove, + .remove_new = xgene_edac_remove, .driver = { .name = "xgene-edac", .of_match_table = xgene_edac_of_match, diff --git a/drivers/edac/zynqmp_edac.c b/drivers/edac/zynqmp_edac.c index ac7d1e0b324c76..2d9a5cfd89317a 100644 --- a/drivers/edac/zynqmp_edac.c +++ b/drivers/edac/zynqmp_edac.c @@ -426,7 +426,7 @@ free_dev_ctl: return ret; } -static int edac_remove(struct platform_device *pdev) +static void edac_remove(struct platform_device *pdev) { struct edac_device_ctl_info *dci = platform_get_drvdata(pdev); struct edac_priv *priv = dci->pvt_info; @@ -440,8 +440,6 @@ static int edac_remove(struct platform_device *pdev) edac_device_del_device(&pdev->dev); edac_device_free_ctl_info(dci); - - return 0; } static const struct of_device_id zynqmp_ocm_edac_match[] = { @@ -457,7 +455,7 @@ static struct platform_driver zynqmp_ocm_edac_driver = { .of_match_table = zynqmp_ocm_edac_match, }, .probe = edac_probe, - .remove = edac_remove, + .remove_new = edac_remove, }; module_platform_driver(zynqmp_ocm_edac_driver); diff --git a/drivers/extcon/extcon-qcom-spmi-misc.c b/drivers/extcon/extcon-qcom-spmi-misc.c index f72e90ceca53d5..53de581a393a35 100644 --- a/drivers/extcon/extcon-qcom-spmi-misc.c +++ b/drivers/extcon/extcon-qcom-spmi-misc.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * extcon-qcom-spmi-misc.c - Qualcomm USB extcon driver to support USB ID * and VBUS detection based on extcon-usb-gpio.c. * diff --git a/drivers/extcon/extcon-usbc-tusb320.c b/drivers/extcon/extcon-usbc-tusb320.c index 4d08c2123e5980..2eab341de6b76f 100644 --- a/drivers/extcon/extcon-usbc-tusb320.c +++ b/drivers/extcon/extcon-usbc-tusb320.c @@ -17,6 +17,7 @@ #include #include #include +#include #define TUSB320_REG8 0x8 #define TUSB320_REG8_CURRENT_MODE_ADVERTISE GENMASK(7, 6) @@ -515,6 +516,8 @@ static int tusb320_probe(struct i2c_client *client) const void *match_data; unsigned int revision; int ret; + u32 irq_trigger_type = IRQF_TRIGGER_FALLING; + struct irq_data *irq_d; priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -568,9 +571,13 @@ static int tusb320_probe(struct i2c_client *client) */ tusb320_state_update_handler(priv, true); + irq_d = irq_get_irq_data(client->irq); + if (irq_d) + irq_trigger_type = irqd_get_trigger_type(irq_d); + ret = devm_request_threaded_irq(priv->dev, client->irq, NULL, tusb320_irq_handler, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + IRQF_ONESHOT | irq_trigger_type, client->name, priv); if (ret) tusb320_typec_remove(priv); diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 6f7a60d2ed9161..e7f55c021e562f 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -1280,8 +1280,6 @@ int extcon_dev_register(struct extcon_dev *edev) edev->id = ret; - dev_set_name(&edev->dev, "extcon%d", edev->id); - ret = extcon_alloc_cables(edev); if (ret < 0) goto err_alloc_cables; @@ -1310,6 +1308,7 @@ int extcon_dev_register(struct extcon_dev *edev) RAW_INIT_NOTIFIER_HEAD(&edev->nh_all); dev_set_drvdata(&edev->dev, edev); + dev_set_name(&edev->dev, "extcon%d", edev->id); edev->state = 0; ret = device_register(&edev->dev); diff --git a/drivers/firewire/.kunitconfig b/drivers/firewire/.kunitconfig index 1599e069395fc1..76444a2d5e1251 100644 --- a/drivers/firewire/.kunitconfig +++ b/drivers/firewire/.kunitconfig @@ -2,3 +2,4 @@ CONFIG_KUNIT=y CONFIG_PCI=y CONFIG_FIREWIRE=y CONFIG_FIREWIRE_KUNIT_UAPI_TEST=y +CONFIG_FIREWIRE_KUNIT_DEVICE_ATTRIBUTE_TEST=y diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig index 0a6596b027db9a..552a39df8cbddb 100644 --- a/drivers/firewire/Kconfig +++ b/drivers/firewire/Kconfig @@ -34,6 +34,22 @@ config FIREWIRE_KUNIT_UAPI_TEST For more information on KUnit and unit tests in general, refer to the KUnit documentation in Documentation/dev-tools/kunit/. +config FIREWIRE_KUNIT_DEVICE_ATTRIBUTE_TEST + tristate "KUnit tests for device attributes" if !KUNIT_ALL_TESTS + depends on FIREWIRE && KUNIT + default KUNIT_ALL_TESTS + help + This builds the KUnit tests for device attribute for node and + unit. + + KUnit tests run during boot and output the results to the debug + log in TAP format (https://testanything.org/). Only useful for + kernel devs running KUnit test harness and are not for inclusion + into a production build. + + For more information on KUnit and unit tests in general, refer + to the KUnit documentation in Documentation/dev-tools/kunit/. + config FIREWIRE_OHCI tristate "OHCI-1394 controllers" depends on PCI && FIREWIRE && MMU diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c index 2828e9573e90be..0547253d16fe5d 100644 --- a/drivers/firewire/core-device.c +++ b/drivers/firewire/core-device.c @@ -31,6 +31,8 @@ #include "core.h" +#define ROOT_DIR_OFFSET 5 + void fw_csr_iterator_init(struct fw_csr_iterator *ci, const u32 *p) { ci->p = p + 1; @@ -47,6 +49,22 @@ int fw_csr_iterator_next(struct fw_csr_iterator *ci, int *key, int *value) } EXPORT_SYMBOL(fw_csr_iterator_next); +static const u32 *search_directory(const u32 *directory, int search_key) +{ + struct fw_csr_iterator ci; + int key, value; + + search_key |= CSR_DIRECTORY; + + fw_csr_iterator_init(&ci, directory); + while (fw_csr_iterator_next(&ci, &key, &value)) { + if (key == search_key) + return ci.p - 1 + value; + } + + return NULL; +} + static const u32 *search_leaf(const u32 *directory, int search_key) { struct fw_csr_iterator ci; @@ -135,8 +153,25 @@ static void get_ids(const u32 *directory, 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); + const u32 *root_directory = &fw_parent_device(unit)->config_rom[ROOT_DIR_OFFSET]; + const u32 *directories[] = {NULL, NULL, NULL}; + const u32 *vendor_directory; + int i; + + directories[0] = root_directory; + + // Legacy layout of configuration ROM described in Annex 1 of 'Configuration ROM for AV/C + // Devices 1.0 (December 12, 2000, 1394 Trading Association, TA Document 1999027)'. + vendor_directory = search_directory(root_directory, CSR_VENDOR); + if (!vendor_directory) { + directories[1] = unit->directory; + } else { + directories[1] = vendor_directory; + directories[2] = unit->directory; + } + + for (i = 0; i < ARRAY_SIZE(directories) && !!directories[i]; ++i) + get_ids(directories[i], id); } static bool match_ids(const struct ieee1394_device_id *id_table, int *id) @@ -171,7 +206,7 @@ static const struct ieee1394_device_id *unit_match(struct device *dev, return NULL; } -static bool is_fw_unit(struct device *dev); +static bool is_fw_unit(const struct device *dev); static int fw_unit_match(struct device *dev, struct device_driver *drv) { @@ -219,7 +254,7 @@ static int fw_unit_uevent(const struct device *dev, struct kobj_uevent_env *env) return 0; } -struct bus_type fw_bus_type = { +const struct bus_type fw_bus_type = { .name = "firewire", .match = fw_unit_match, .probe = fw_unit_probe, @@ -251,27 +286,44 @@ static ssize_t show_immediate(struct device *dev, struct config_rom_attribute *attr = container_of(dattr, struct config_rom_attribute, attr); struct fw_csr_iterator ci; - const u32 *dir; - int key, value, ret = -ENOENT; + const u32 *directories[] = {NULL, NULL}; + int i, value = -1; down_read(&fw_device_rwsem); - if (is_fw_unit(dev)) - dir = fw_unit(dev)->directory; - else - dir = fw_device(dev)->config_rom + 5; + if (is_fw_unit(dev)) { + directories[0] = fw_unit(dev)->directory; + } else { + const u32 *root_directory = fw_device(dev)->config_rom + ROOT_DIR_OFFSET; + const u32 *vendor_directory = search_directory(root_directory, CSR_VENDOR); + + if (!vendor_directory) { + directories[0] = root_directory; + } else { + // Legacy layout of configuration ROM described in Annex 1 of + // 'Configuration ROM for AV/C Devices 1.0 (December 12, 2000, 1394 Trading + // Association, TA Document 1999027)'. + directories[0] = vendor_directory; + directories[1] = root_directory; + } + } - fw_csr_iterator_init(&ci, dir); - while (fw_csr_iterator_next(&ci, &key, &value)) - if (attr->key == key) { - ret = snprintf(buf, buf ? PAGE_SIZE : 0, - "0x%06x\n", value); - break; + for (i = 0; i < ARRAY_SIZE(directories) && !!directories[i]; ++i) { + int key, val; + + fw_csr_iterator_init(&ci, directories[i]); + while (fw_csr_iterator_next(&ci, &key, &val)) { + if (attr->key == key) + value = val; } + } up_read(&fw_device_rwsem); - return ret; + if (value < 0) + return -ENOENT; + + return snprintf(buf, buf ? PAGE_SIZE : 0, "0x%06x\n", value); } #define IMMEDIATE_ATTR(name, key) \ @@ -282,17 +334,29 @@ static ssize_t show_text_leaf(struct device *dev, { struct config_rom_attribute *attr = container_of(dattr, struct config_rom_attribute, attr); - const u32 *dir; + const u32 *directories[] = {NULL, NULL}; size_t bufsize; char dummy_buf[2]; - int ret; + int i, ret = -ENOENT; down_read(&fw_device_rwsem); - if (is_fw_unit(dev)) - dir = fw_unit(dev)->directory; - else - dir = fw_device(dev)->config_rom + 5; + if (is_fw_unit(dev)) { + directories[0] = fw_unit(dev)->directory; + } else { + const u32 *root_directory = fw_device(dev)->config_rom + ROOT_DIR_OFFSET; + const u32 *vendor_directory = search_directory(root_directory, CSR_VENDOR); + + if (!vendor_directory) { + directories[0] = root_directory; + } else { + // Legacy layout of configuration ROM described in Annex 1 of + // 'Configuration ROM for AV/C Devices 1.0 (December 12, 2000, 1394 + // Trading Association, TA Document 1999027)'. + directories[0] = root_directory; + directories[1] = vendor_directory; + } + } if (buf) { bufsize = PAGE_SIZE - 1; @@ -301,7 +365,12 @@ static ssize_t show_text_leaf(struct device *dev, bufsize = 1; } - ret = fw_csr_string(dir, attr->key, buf, bufsize); + for (i = 0; i < ARRAY_SIZE(directories) && !!directories[i]; ++i) { + int result = fw_csr_string(directories[i], attr->key, buf, bufsize); + // Detected. + if (result >= 0) + ret = result; + } if (ret >= 0) { /* Strip trailing whitespace and add newline. */ @@ -446,7 +515,7 @@ static ssize_t units_show(struct device *dev, int key, value, i = 0; down_read(&fw_device_rwsem); - fw_csr_iterator_init(&ci, &device->config_rom[5]); + fw_csr_iterator_init(&ci, &device->config_rom[ROOT_DIR_OFFSET]); while (fw_csr_iterator_next(&ci, &key, &value)) { if (key != (CSR_UNIT | CSR_DIRECTORY)) continue; @@ -679,7 +748,7 @@ static struct device_type fw_unit_type = { .release = fw_unit_release, }; -static bool is_fw_unit(struct device *dev) +static bool is_fw_unit(const struct device *dev) { return dev->type == &fw_unit_type; } @@ -691,7 +760,7 @@ static void create_units(struct fw_device *device) int key, value, i; i = 0; - fw_csr_iterator_init(&ci, &device->config_rom[5]); + fw_csr_iterator_init(&ci, &device->config_rom[ROOT_DIR_OFFSET]); while (fw_csr_iterator_next(&ci, &key, &value)) { if (key != (CSR_UNIT | CSR_DIRECTORY)) continue; @@ -835,7 +904,7 @@ static struct device_type fw_device_type = { .release = fw_device_release, }; -static bool is_fw_device(struct device *dev) +static bool is_fw_device(const struct device *dev) { return dev->type == &fw_device_type; } @@ -1308,3 +1377,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event) break; } } + +#ifdef CONFIG_FIREWIRE_KUNIT_DEVICE_ATTRIBUTE_TEST +#include "device-attribute-test.c" +#endif diff --git a/drivers/firewire/device-attribute-test.c b/drivers/firewire/device-attribute-test.c new file mode 100644 index 00000000000000..2f123c6b0a1659 --- /dev/null +++ b/drivers/firewire/device-attribute-test.c @@ -0,0 +1,251 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// device-attribute-test.c - An application of Kunit to test implementation for device attributes. +// +// Copyright (c) 2023 Takashi Sakamoto +// +// This file can not be built independently since it is intentionally included in core-device.c. + +#include + +// Configuration ROM for AV/C Devices 1.0 (Dec. 12, 2000, 1394 Trading Association) +// Annex C:Configuration ROM example(informative) +// C.1 Simple AV/C device +// +// Copied from the documentation. +static const u32 simple_avc_config_rom[] = { + 0x0404eabf, + 0x31333934, + 0xe0646102, + 0xffffffff, + 0xffffffff, + 0x00063287, // root directory. + 0x03ffffff, + 0x8100000a, + 0x17ffffff, + 0x8100000e, + 0x0c0083c0, + 0xd1000001, + 0x0004442d, // unit 0 directory. + 0x1200a02d, + 0x13010001, + 0x17ffffff, + 0x81000007, + 0x0005c915, // leaf for textual descriptor. + 0x00000000, + 0x00000000, + 0x56656e64, + 0x6f72204e, + 0x616d6500, + 0x00057f16, // leaf for textual descriptor. + 0x00000000, + 0x00000000, + 0x4d6f6465, + 0x6c204e61, + 0x6d650000, +}; + +// Ibid. +// Annex A:Consideration for configuration ROM reader design (informative) +// A.1 Vendor directory +// +// Written by hand. +static const u32 legacy_avc_config_rom[] = { + 0x04199fe7, + 0x31333934, + 0xe0644000, + 0x00112233, + 0x44556677, + 0x0005dace, // root directory. + 0x03012345, + 0x0c0083c0, + 0x8d000009, + 0xd1000002, + 0xc3000004, + 0x0002e107, // unit 0 directory. + 0x12abcdef, + 0x13543210, + 0x0002cb73, // vendor directory. + 0x17fedcba, + 0x81000004, + 0x00026dc1, // leaf for EUI-64. + 0x00112233, + 0x44556677, + 0x00050e84, // leaf for textual descriptor. + 0x00000000, + 0x00000000, + 0x41424344, + 0x45464748, + 0x494a0000, +}; + +static void device_attr_simple_avc(struct kunit *test) +{ + static const struct fw_device node = { + .device = { + .type = &fw_device_type, + }, + .config_rom = simple_avc_config_rom, + .config_rom_length = sizeof(simple_avc_config_rom), + }; + static const struct fw_unit unit0 = { + .device = { + .type = &fw_unit_type, + .parent = (struct device *)&node.device, + }, + .directory = &simple_avc_config_rom[12], + }; + struct device *node_dev = (struct device *)&node.device; + struct device *unit0_dev = (struct device *)&unit0.device; + static const int unit0_expected_ids[] = {0x00ffffff, 0x00ffffff, 0x0000a02d, 0x00010001}; + char *buf = kunit_kzalloc(test, PAGE_SIZE, GFP_KERNEL); + int ids[4] = {0, 0, 0, 0}; + + // Ensure associations for node and unit devices. + + KUNIT_ASSERT_TRUE(test, is_fw_device(node_dev)); + KUNIT_ASSERT_FALSE(test, is_fw_unit(node_dev)); + KUNIT_ASSERT_PTR_EQ(test, fw_device(node_dev), &node); + + KUNIT_ASSERT_FALSE(test, is_fw_device(unit0_dev)); + KUNIT_ASSERT_TRUE(test, is_fw_unit(unit0_dev)); + KUNIT_ASSERT_PTR_EQ(test, fw_parent_device((&unit0)), &node); + KUNIT_ASSERT_PTR_EQ(test, fw_unit(unit0_dev), &unit0); + + // For entries in root directory. + + // Vendor immediate entry is found. + KUNIT_EXPECT_GT(test, show_immediate(node_dev, &config_rom_attributes[0].attr, buf), 0); + KUNIT_EXPECT_STREQ(test, buf, "0xffffff\n"); + + // Model immediate entry is found. + KUNIT_EXPECT_GT(test, show_immediate(node_dev, &config_rom_attributes[4].attr, buf), 0); + KUNIT_EXPECT_STREQ(test, buf, "0xffffff\n"); + + // Descriptor leaf entry for vendor is found. + KUNIT_EXPECT_GT(test, show_text_leaf(node_dev, &config_rom_attributes[5].attr, buf), 0); + KUNIT_EXPECT_STREQ(test, buf, "Vendor Name\n"); + + // Descriptor leaf entry for model is found. + KUNIT_EXPECT_GT(test, show_text_leaf(node_dev, &config_rom_attributes[6].attr, buf), 0); + KUNIT_EXPECT_STREQ(test, buf, "Model Name\n"); + + // For entries in unit 0 directory. + + // Vendor immediate entry is not found. + KUNIT_EXPECT_LT(test, show_immediate(unit0_dev, &config_rom_attributes[0].attr, buf), 0); + + // Model immediate entry is found. + KUNIT_EXPECT_GT(test, show_immediate(unit0_dev, &config_rom_attributes[4].attr, buf), 0); + KUNIT_EXPECT_STREQ(test, buf, "0xffffff\n"); + + // Descriptor leaf entry for vendor is not found. + KUNIT_EXPECT_LT(test, show_text_leaf(unit0_dev, &config_rom_attributes[5].attr, buf), 0); + + // Descriptor leaf entry for model is found. + KUNIT_EXPECT_GT(test, show_text_leaf(unit0_dev, &config_rom_attributes[6].attr, buf), 0); + KUNIT_EXPECT_STREQ(test, buf, "Model Name\n"); + + // Specifier_ID immediate entry is found. + KUNIT_EXPECT_GT(test, show_immediate(unit0_dev, &config_rom_attributes[2].attr, buf), 0); + KUNIT_EXPECT_STREQ(test, buf, "0x00a02d\n"); + + // Version immediate entry is found. + KUNIT_EXPECT_GT(test, show_immediate(unit0_dev, &config_rom_attributes[3].attr, buf), 0); + KUNIT_EXPECT_STREQ(test, buf, "0x010001\n"); + + kunit_kfree(test, buf); + + get_modalias_ids(&unit0, ids); + KUNIT_EXPECT_MEMEQ(test, ids, unit0_expected_ids, sizeof(ids)); +} + +static void device_attr_legacy_avc(struct kunit *test) +{ + static const struct fw_device node = { + .device = { + .type = &fw_device_type, + }, + .config_rom = legacy_avc_config_rom, + .config_rom_length = sizeof(legacy_avc_config_rom), + }; + static const struct fw_unit unit0 = { + .device = { + .type = &fw_unit_type, + .parent = (struct device *)&node.device, + }, + .directory = &legacy_avc_config_rom[11], + }; + struct device *node_dev = (struct device *)&node.device; + struct device *unit0_dev = (struct device *)&unit0.device; + static const int unit0_expected_ids[] = {0x00012345, 0x00fedcba, 0x00abcdef, 0x00543210}; + char *buf = kunit_kzalloc(test, PAGE_SIZE, GFP_KERNEL); + int ids[4] = {0, 0, 0, 0}; + + // Ensure associations for node and unit devices. + + KUNIT_ASSERT_TRUE(test, is_fw_device(node_dev)); + KUNIT_ASSERT_FALSE(test, is_fw_unit(node_dev)); + KUNIT_ASSERT_PTR_EQ(test, fw_device((node_dev)), &node); + + KUNIT_ASSERT_FALSE(test, is_fw_device(unit0_dev)); + KUNIT_ASSERT_TRUE(test, is_fw_unit(unit0_dev)); + KUNIT_ASSERT_PTR_EQ(test, fw_parent_device((&unit0)), &node); + KUNIT_ASSERT_PTR_EQ(test, fw_unit(unit0_dev), &unit0); + + // For entries in root directory. + + // Vendor immediate entry is found. + KUNIT_EXPECT_GT(test, show_immediate(node_dev, &config_rom_attributes[0].attr, buf), 0); + KUNIT_EXPECT_STREQ(test, buf, "0x012345\n"); + + // Model immediate entry is found. + KUNIT_EXPECT_GT(test, show_immediate(node_dev, &config_rom_attributes[4].attr, buf), 0); + KUNIT_EXPECT_STREQ(test, buf, "0xfedcba\n"); + + // Descriptor leaf entry for vendor is not found. + KUNIT_EXPECT_LT(test, show_text_leaf(node_dev, &config_rom_attributes[5].attr, buf), 0); + + // Descriptor leaf entry for model is found. + KUNIT_EXPECT_GT(test, show_text_leaf(node_dev, &config_rom_attributes[6].attr, buf), 0); + KUNIT_EXPECT_STREQ(test, buf, "ABCDEFGHIJ\n"); + + // For entries in unit 0 directory. + + // Vendor immediate entry is not found. + KUNIT_EXPECT_LT(test, show_immediate(unit0_dev, &config_rom_attributes[0].attr, buf), 0); + + // Model immediate entry is not found. + KUNIT_EXPECT_LT(test, show_immediate(unit0_dev, &config_rom_attributes[4].attr, buf), 0); + + // Descriptor leaf entry for vendor is not found. + KUNIT_EXPECT_LT(test, show_text_leaf(unit0_dev, &config_rom_attributes[5].attr, buf), 0); + + // Descriptor leaf entry for model is not found. + KUNIT_EXPECT_LT(test, show_text_leaf(unit0_dev, &config_rom_attributes[6].attr, buf), 0); + + // Specifier_ID immediate entry is found. + KUNIT_EXPECT_GT(test, show_immediate(unit0_dev, &config_rom_attributes[2].attr, buf), 0); + KUNIT_EXPECT_STREQ(test, buf, "0xabcdef\n"); + + // Version immediate entry is found. + KUNIT_EXPECT_GT(test, show_immediate(unit0_dev, &config_rom_attributes[3].attr, buf), 0); + KUNIT_EXPECT_STREQ(test, buf, "0x543210\n"); + + kunit_kfree(test, buf); + + get_modalias_ids(&unit0, ids); + KUNIT_EXPECT_MEMEQ(test, ids, unit0_expected_ids, sizeof(ids)); +} + +static struct kunit_case device_attr_test_cases[] = { + KUNIT_CASE(device_attr_simple_avc), + KUNIT_CASE(device_attr_legacy_avc), + {} +}; + +static struct kunit_suite device_attr_test_suite = { + .name = "firewire-device-attribute", + .test_cases = device_attr_test_cases, +}; +kunit_test_suite(device_attr_test_suite); diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 4a98a859d44d34..afd38539b92e51 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -28,15 +28,6 @@ config ARM_SCPI_PROTOCOL This protocol library provides interface for all the client drivers making use of the features offered by the SCP. -config ARM_SCPI_POWER_DOMAIN - tristate "SCPI power domain driver" - depends on ARM_SCPI_PROTOCOL || (COMPILE_TEST && OF) - default y - select PM_GENERIC_DOMAINS if PM - help - This enables support for the SCPI power domains which can be - enabled or disabled via the SCP firmware - config ARM_SDE_INTERFACE bool "ARM Software Delegated Exception Interface (SDEI)" depends on ARM64 @@ -272,6 +263,7 @@ source "drivers/firmware/google/Kconfig" source "drivers/firmware/efi/Kconfig" source "drivers/firmware/imx/Kconfig" source "drivers/firmware/meson/Kconfig" +source "drivers/firmware/microchip/Kconfig" source "drivers/firmware/psci/Kconfig" source "drivers/firmware/qcom/Kconfig" source "drivers/firmware/smccc/Kconfig" diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 5f9dab82e1a0e9..7a8d486e718f86 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -3,7 +3,6 @@ # Makefile for the linux kernel. # obj-$(CONFIG_ARM_SCPI_PROTOCOL) += arm_scpi.o -obj-$(CONFIG_ARM_SCPI_POWER_DOMAIN) += scpi_pm_domain.o obj-$(CONFIG_ARM_SDE_INTERFACE) += arm_sdei.o obj-$(CONFIG_DMI) += dmi_scan.o obj-$(CONFIG_DMI_SYSFS) += dmi-sysfs.o @@ -28,6 +27,7 @@ obj-y += arm_scmi/ obj-y += broadcom/ obj-y += cirrus/ obj-y += meson/ +obj-y += microchip/ obj-$(CONFIG_GOOGLE_FIRMWARE) += google/ obj-y += efi/ obj-y += imx/ diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index 6146b2927d5c56..f2556a8e940156 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -107,12 +107,12 @@ struct ffa_drv_info { struct work_struct notif_pcpu_work; struct work_struct irq_work; struct xarray partition_info; - unsigned int partition_count; DECLARE_HASHTABLE(notifier_hash, ilog2(FFA_MAX_NOTIFICATIONS)); struct mutex notify_lock; /* lock to protect notifier hashtable */ }; static struct ffa_drv_info *drv_info; +static void ffa_partitions_cleanup(void); /* * The driver must be able to support all the versions from the earliest @@ -733,6 +733,11 @@ static void __do_sched_recv_cb(u16 part_id, u16 vcpu, bool is_per_vcpu) void *cb_data; partition = xa_load(&drv_info->partition_info, part_id); + if (!partition) { + pr_err("%s: Invalid partition ID 0x%x\n", __func__, part_id); + return; + } + read_lock(&partition->rw_lock); callback = partition->callback; cb_data = partition->cb_data; @@ -915,6 +920,11 @@ static int ffa_sched_recv_cb_update(u16 part_id, ffa_sched_recv_cb callback, return -EOPNOTSUPP; partition = xa_load(&drv_info->partition_info, part_id); + if (!partition) { + pr_err("%s: Invalid partition ID 0x%x\n", __func__, part_id); + return -EINVAL; + } + write_lock(&partition->rw_lock); cb_valid = !!partition->callback; @@ -1186,9 +1196,9 @@ void ffa_device_match_uuid(struct ffa_device *ffa_dev, const uuid_t *uuid) kfree(pbuf); } -static void ffa_setup_partitions(void) +static int ffa_setup_partitions(void) { - int count, idx; + int count, idx, ret; uuid_t uuid; struct ffa_device *ffa_dev; struct ffa_dev_part_info *info; @@ -1197,7 +1207,7 @@ static void ffa_setup_partitions(void) count = ffa_partition_probe(&uuid_null, &pbuf); if (count <= 0) { pr_info("%s: No partitions found, error %d\n", __func__, count); - return; + return -EINVAL; } xa_init(&drv_info->partition_info); @@ -1226,40 +1236,53 @@ static void ffa_setup_partitions(void) ffa_device_unregister(ffa_dev); continue; } - xa_store(&drv_info->partition_info, tpbuf->id, info, GFP_KERNEL); + rwlock_init(&info->rw_lock); + ret = xa_insert(&drv_info->partition_info, tpbuf->id, + info, GFP_KERNEL); + if (ret) { + pr_err("%s: failed to save partition ID 0x%x - ret:%d\n", + __func__, tpbuf->id, ret); + ffa_device_unregister(ffa_dev); + kfree(info); + } } - drv_info->partition_count = count; kfree(pbuf); /* Allocate for the host */ info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) - return; - xa_store(&drv_info->partition_info, drv_info->vm_id, info, GFP_KERNEL); - drv_info->partition_count++; + if (!info) { + pr_err("%s: failed to alloc Host partition ID 0x%x. Abort.\n", + __func__, drv_info->vm_id); + /* Already registered devices are freed on bus_exit */ + ffa_partitions_cleanup(); + return -ENOMEM; + } + + rwlock_init(&info->rw_lock); + ret = xa_insert(&drv_info->partition_info, drv_info->vm_id, + info, GFP_KERNEL); + if (ret) { + pr_err("%s: failed to save Host partition ID 0x%x - ret:%d. Abort.\n", + __func__, drv_info->vm_id, ret); + kfree(info); + /* Already registered devices are freed on bus_exit */ + ffa_partitions_cleanup(); + } + + return ret; } static void ffa_partitions_cleanup(void) { - struct ffa_dev_part_info **info; - int idx, count = drv_info->partition_count; - - if (!count) - return; - - info = kcalloc(count, sizeof(*info), GFP_KERNEL); - if (!info) - return; - - xa_extract(&drv_info->partition_info, (void **)info, 0, VM_ID_MASK, - count, XA_PRESENT); + struct ffa_dev_part_info *info; + unsigned long idx; - for (idx = 0; idx < count; idx++) - kfree(info[idx]); - kfree(info); + xa_for_each(&drv_info->partition_info, idx, info) { + xa_erase(&drv_info->partition_info, idx); + kfree(info); + } - drv_info->partition_count = 0; xa_destroy(&drv_info->partition_info); } @@ -1508,7 +1531,11 @@ static int __init ffa_init(void) ffa_notifications_setup(); - ffa_setup_partitions(); + ret = ffa_setup_partitions(); + if (ret) { + pr_err("failed to setup partitions\n"); + goto cleanup_notifs; + } ret = ffa_sched_recv_cb_update(drv_info->vm_id, ffa_self_notif_handle, drv_info, true); @@ -1516,6 +1543,9 @@ static int __init ffa_init(void) pr_info("Failed to register driver sched callback %d\n", ret); return 0; + +cleanup_notifs: + ffa_notifications_cleanup(); free_pages: if (drv_info->tx_buffer) free_pages_exact(drv_info->tx_buffer, RXTX_BUFFER_SIZE); @@ -1535,7 +1565,6 @@ static void __exit ffa_exit(void) ffa_rxtx_unmap(drv_info->vm_id); free_pages_exact(drv_info->tx_buffer, RXTX_BUFFER_SIZE); free_pages_exact(drv_info->rx_buffer, RXTX_BUFFER_SIZE); - xa_destroy(&drv_info->partition_info); kfree(drv_info); arm_ffa_bus_exit(); } diff --git a/drivers/firmware/arm_scmi/Kconfig b/drivers/firmware/arm_scmi/Kconfig index 706d1264d03896..aa5842be19b2d1 100644 --- a/drivers/firmware/arm_scmi/Kconfig +++ b/drivers/firmware/arm_scmi/Kconfig @@ -168,31 +168,6 @@ config ARM_SCMI_TRANSPORT_VIRTIO_ATOMIC_ENABLE endif #ARM_SCMI_PROTOCOL -config ARM_SCMI_POWER_DOMAIN - tristate "SCMI power domain driver" - depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF) - default y - select PM_GENERIC_DOMAINS if PM - help - This enables support for the SCMI power domains which can be - enabled or disabled via the SCP firmware - - This driver can also be built as a module. If so, the module - will be called scmi_pm_domain. Note this may needed early in boot - before rootfs may be available. - -config ARM_SCMI_PERF_DOMAIN - tristate "SCMI performance domain driver" - depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF) - default y - select PM_GENERIC_DOMAINS if PM - help - This enables support for the SCMI performance domains which can be - enabled or disabled via the SCP firmware. - - This driver can also be built as a module. If so, the module will be - called scmi_perf_domain. - config ARM_SCMI_POWER_CONTROL tristate "SCMI system power control driver" depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF) diff --git a/drivers/firmware/arm_scmi/base.c b/drivers/firmware/arm_scmi/base.c index a52f084a6a87bb..97254de35ab0d4 100644 --- a/drivers/firmware/arm_scmi/base.c +++ b/drivers/firmware/arm_scmi/base.c @@ -13,6 +13,9 @@ #include "common.h" #include "notify.h" +/* Updated only after ALL the mandatory features for that version are merged */ +#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20000 + #define SCMI_BASE_NUM_SOURCES 1 #define SCMI_BASE_MAX_CMD_ERR_COUNT 1024 @@ -385,7 +388,7 @@ static int scmi_base_protocol_init(const struct scmi_protocol_handle *ph) rev->major_ver = PROTOCOL_REV_MAJOR(version), rev->minor_ver = PROTOCOL_REV_MINOR(version); - ph->set_priv(ph, rev); + ph->set_priv(ph, rev, version); ret = scmi_base_attributes_get(ph); if (ret) @@ -423,6 +426,7 @@ static const struct scmi_protocol scmi_base = { .instance_init = &scmi_base_protocol_init, .ops = NULL, .events = &base_protocol_events, + .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION, }; DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(base, scmi_base) diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c index 42b81c181d687a..e2050adbf85c6a 100644 --- a/drivers/firmware/arm_scmi/clock.c +++ b/drivers/firmware/arm_scmi/clock.c @@ -12,6 +12,9 @@ #include "protocols.h" #include "notify.h" +/* Updated only after ALL the mandatory features for that version are merged */ +#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20000 + enum scmi_clock_protocol_cmd { CLOCK_ATTRIBUTES = 0x3, CLOCK_DESCRIBE_RATES = 0x4, @@ -318,7 +321,7 @@ static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph, if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x2) { if (SUPPORTS_EXTENDED_NAMES(attributes)) ph->hops->extended_name_get(ph, CLOCK_NAME_GET, clk_id, - clk->name, + NULL, clk->name, SCMI_MAX_STR_SIZE); if (SUPPORTS_RATE_CHANGED_NOTIF(attributes)) @@ -951,8 +954,7 @@ static int scmi_clock_protocol_init(const struct scmi_protocol_handle *ph) scmi_clock_describe_rates_get(ph, clkid, clk); } - if (PROTOCOL_REV_MAJOR(version) >= 0x2 && - PROTOCOL_REV_MINOR(version) >= 0x1) { + if (PROTOCOL_REV_MAJOR(version) >= 0x3) { cinfo->clock_config_set = scmi_clock_config_set_v2; cinfo->clock_config_get = scmi_clock_config_get_v2; } else { @@ -961,7 +963,7 @@ static int scmi_clock_protocol_init(const struct scmi_protocol_handle *ph) } cinfo->version = version; - return ph->set_priv(ph, cinfo); + return ph->set_priv(ph, cinfo, version); } static const struct scmi_protocol scmi_clock = { @@ -970,6 +972,7 @@ static const struct scmi_protocol scmi_clock = { .instance_init = &scmi_clock_protocol_init, .ops = &clk_proto_ops, .events = &clk_protocol_events, + .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION, }; DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(clock, scmi_clock) diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index c46dc5215af7a7..00b165d1f502df 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -314,6 +314,7 @@ void shmem_fetch_notification(struct scmi_shared_mem __iomem *shmem, void shmem_clear_channel(struct scmi_shared_mem __iomem *shmem); bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem, struct scmi_xfer *xfer); +bool shmem_channel_free(struct scmi_shared_mem __iomem *shmem); /* declarations for message passing transports */ struct scmi_msg_payld; diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 09371f40d61f48..3ea64b22cf0dfd 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -85,6 +85,7 @@ struct scmi_xfers_info { * @gid: A reference for per-protocol devres management. * @users: A refcount to track effective users of this protocol. * @priv: Reference for optional protocol private data. + * @version: Protocol version supported by the platform as detected at runtime. * @ph: An embedded protocol handle that will be passed down to protocol * initialization code to identify this instance. * @@ -97,6 +98,7 @@ struct scmi_protocol_instance { void *gid; refcount_t users; void *priv; + unsigned int version; struct scmi_protocol_handle ph; }; @@ -1392,15 +1394,17 @@ static int version_get(const struct scmi_protocol_handle *ph, u32 *version) * * @ph: A reference to the protocol handle. * @priv: The private data to set. + * @version: The detected protocol version for the core to register. * * Return: 0 on Success */ static int scmi_set_protocol_priv(const struct scmi_protocol_handle *ph, - void *priv) + void *priv, u32 version) { struct scmi_protocol_instance *pi = ph_to_pi(ph); pi->priv = priv; + pi->version = version; return 0; } @@ -1438,6 +1442,7 @@ struct scmi_msg_resp_domain_name_get { * @ph: A protocol handle reference. * @cmd_id: The specific command ID to use. * @res_id: The specific resource ID to use. + * @flags: A pointer to specific flags to use, if any. * @name: A pointer to the preallocated area where the retrieved name will be * stored as a NULL terminated string. * @len: The len in bytes of the @name char array. @@ -1445,19 +1450,22 @@ struct scmi_msg_resp_domain_name_get { * Return: 0 on Succcess */ static int scmi_common_extended_name_get(const struct scmi_protocol_handle *ph, - u8 cmd_id, u32 res_id, char *name, - size_t len) + u8 cmd_id, u32 res_id, u32 *flags, + char *name, size_t len) { int ret; + size_t txlen; struct scmi_xfer *t; struct scmi_msg_resp_domain_name_get *resp; - ret = ph->xops->xfer_get_init(ph, cmd_id, sizeof(res_id), - sizeof(*resp), &t); + txlen = !flags ? sizeof(res_id) : sizeof(res_id) + sizeof(*flags); + ret = ph->xops->xfer_get_init(ph, cmd_id, txlen, sizeof(*resp), &t); if (ret) goto out; put_unaligned_le32(res_id, t->tx.buf); + if (flags) + put_unaligned_le32(*flags, t->tx.buf + sizeof(res_id)); resp = t->rx.buf; ret = ph->xops->do_xfer(ph, t); @@ -1845,6 +1853,12 @@ scmi_alloc_init_protocol_instance(struct scmi_info *info, devres_close_group(handle->dev, pi->gid); dev_dbg(handle->dev, "Initialized protocol: 0x%X\n", pi->proto->id); + if (pi->version > proto->supported_version) + dev_warn(handle->dev, + "Detected UNSUPPORTED higher version 0x%X for protocol 0x%X." + "Backward compatibility is NOT assured.\n", + pi->version, pi->proto->id); + return pi; clean: @@ -2820,7 +2834,7 @@ clear_ida: return ret; } -static int scmi_remove(struct platform_device *pdev) +static void scmi_remove(struct platform_device *pdev) { int id; struct scmi_info *info = platform_get_drvdata(pdev); @@ -2854,8 +2868,6 @@ static int scmi_remove(struct platform_device *pdev) scmi_cleanup_txrx_channels(info); ida_free(&scmi_id, info->id); - - return 0; } static ssize_t protocol_version_show(struct device *dev, @@ -2933,7 +2945,7 @@ static struct platform_driver scmi_driver = { .dev_groups = versions_groups, }, .probe = scmi_probe, - .remove = scmi_remove, + .remove_new = scmi_remove, }; /** diff --git a/drivers/firmware/arm_scmi/mailbox.c b/drivers/firmware/arm_scmi/mailbox.c index 19246ed1f01ff7..b8d470417e8f99 100644 --- a/drivers/firmware/arm_scmi/mailbox.c +++ b/drivers/firmware/arm_scmi/mailbox.c @@ -45,6 +45,20 @@ static void rx_callback(struct mbox_client *cl, void *m) { struct scmi_mailbox *smbox = client_to_scmi_mailbox(cl); + /* + * An A2P IRQ is NOT valid when received while the platform still has + * the ownership of the channel, because the platform at first releases + * the SMT channel and then sends the completion interrupt. + * + * This addresses a possible race condition in which a spurious IRQ from + * a previous timed-out reply which arrived late could be wrongly + * associated with the next pending transaction. + */ + if (cl->knows_txdone && !shmem_channel_free(smbox->shmem)) { + dev_warn(smbox->cinfo->dev, "Ignoring spurious A2P IRQ !\n"); + return; + } + scmi_rx_callback(smbox->cinfo, shmem_read_header(smbox->shmem), NULL); } diff --git a/drivers/firmware/arm_scmi/optee.c b/drivers/firmware/arm_scmi/optee.c index e123de6e8c67a9..25bfb465484d08 100644 --- a/drivers/firmware/arm_scmi/optee.c +++ b/drivers/firmware/arm_scmi/optee.c @@ -440,6 +440,10 @@ static int scmi_optee_chan_setup(struct scmi_chan_info *cinfo, struct device *de if (ret) goto err_free_shm; + ret = tee_client_system_session(scmi_optee_private->tee_ctx, channel->tee_session); + if (ret) + dev_warn(dev, "Could not switch to system session, do best effort\n"); + ret = get_channel(channel); if (ret) goto err_close_sess; diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c index e11555de99ab86..211e8e0aef2c2b 100644 --- a/drivers/firmware/arm_scmi/perf.c +++ b/drivers/firmware/arm_scmi/perf.c @@ -24,7 +24,10 @@ #include "protocols.h" #include "notify.h" -#define MAX_OPPS 16 +/* Updated only after ALL the mandatory features for that version are merged */ +#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x40000 + +#define MAX_OPPS 32 enum scmi_performance_protocol_cmd { PERF_DOMAIN_ATTRIBUTES = 0x3, @@ -289,7 +292,7 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph, if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x3 && SUPPORTS_EXTENDED_NAMES(flags)) ph->hops->extended_name_get(ph, PERF_DOMAIN_NAME_GET, - dom_info->id, dom_info->info.name, + dom_info->id, NULL, dom_info->info.name, SCMI_MAX_STR_SIZE); if (dom_info->level_indexing_mode) { @@ -347,8 +350,8 @@ process_response_opp(struct scmi_opp *opp, unsigned int loop_idx, } static inline void -process_response_opp_v4(struct perf_dom_info *dom, struct scmi_opp *opp, - unsigned int loop_idx, +process_response_opp_v4(struct device *dev, struct perf_dom_info *dom, + struct scmi_opp *opp, unsigned int loop_idx, const struct scmi_msg_resp_perf_describe_levels_v4 *r) { opp->perf = le32_to_cpu(r->opp[loop_idx].perf_val); @@ -359,10 +362,23 @@ process_response_opp_v4(struct perf_dom_info *dom, struct scmi_opp *opp, /* Note that PERF v4 reports always five 32-bit words */ opp->indicative_freq = le32_to_cpu(r->opp[loop_idx].indicative_freq); if (dom->level_indexing_mode) { + int ret; + opp->level_index = le32_to_cpu(r->opp[loop_idx].level_index); - xa_store(&dom->opps_by_idx, opp->level_index, opp, GFP_KERNEL); - xa_store(&dom->opps_by_lvl, opp->perf, opp, GFP_KERNEL); + ret = xa_insert(&dom->opps_by_idx, opp->level_index, opp, + GFP_KERNEL); + if (ret) + dev_warn(dev, + "Failed to add opps_by_idx at %d - ret:%d\n", + opp->level_index, ret); + + ret = xa_insert(&dom->opps_by_lvl, opp->perf, opp, GFP_KERNEL); + if (ret) + dev_warn(dev, + "Failed to add opps_by_lvl at %d - ret:%d\n", + opp->perf, ret); + hash_add(dom->opps_by_freq, &opp->hash, opp->indicative_freq); } } @@ -379,7 +395,7 @@ iter_perf_levels_process_response(const struct scmi_protocol_handle *ph, if (PROTOCOL_REV_MAJOR(p->version) <= 0x3) process_response_opp(opp, st->loop_idx, response); else - process_response_opp_v4(p->perf_dom, opp, st->loop_idx, + process_response_opp_v4(ph->dev, p->perf_dom, opp, st->loop_idx, response); p->perf_dom->opp_count++; @@ -505,6 +521,9 @@ static int scmi_perf_limits_set(const struct scmi_protocol_handle *ph, if (IS_ERR(dom)) return PTR_ERR(dom); + if (!dom->set_limits) + return -EOPNOTSUPP; + if (PROTOCOL_REV_MAJOR(pi->version) >= 0x3 && !max_perf && !min_perf) return -EINVAL; @@ -655,6 +674,9 @@ static int scmi_perf_level_set(const struct scmi_protocol_handle *ph, if (IS_ERR(dom)) return PTR_ERR(dom); + if (!dom->info.set_perf) + return -EOPNOTSUPP; + if (dom->level_indexing_mode) { struct scmi_opp *opp; @@ -754,7 +776,7 @@ static int scmi_perf_level_limits_notify(const struct scmi_protocol_handle *ph, } static void scmi_perf_domain_init_fc(const struct scmi_protocol_handle *ph, - u32 domain, struct scmi_fc_info **p_fc) + struct perf_dom_info *dom) { struct scmi_fc_info *fc; @@ -763,24 +785,26 @@ static void scmi_perf_domain_init_fc(const struct scmi_protocol_handle *ph, return; ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL, - PERF_LEVEL_SET, 4, domain, - &fc[PERF_FC_LEVEL].set_addr, - &fc[PERF_FC_LEVEL].set_db); - - ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL, - PERF_LEVEL_GET, 4, domain, + PERF_LEVEL_GET, 4, dom->id, &fc[PERF_FC_LEVEL].get_addr, NULL); ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL, - PERF_LIMITS_SET, 8, domain, - &fc[PERF_FC_LIMIT].set_addr, - &fc[PERF_FC_LIMIT].set_db); - - ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL, - PERF_LIMITS_GET, 8, domain, + PERF_LIMITS_GET, 8, dom->id, &fc[PERF_FC_LIMIT].get_addr, NULL); - *p_fc = fc; + if (dom->info.set_perf) + ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL, + PERF_LEVEL_SET, 4, dom->id, + &fc[PERF_FC_LEVEL].set_addr, + &fc[PERF_FC_LEVEL].set_db); + + if (dom->set_limits) + ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL, + PERF_LIMITS_SET, 8, dom->id, + &fc[PERF_FC_LIMIT].set_addr, + &fc[PERF_FC_LIMIT].set_db); + + dom->fc_info = fc; } static int scmi_dvfs_device_opps_add(const struct scmi_protocol_handle *ph, @@ -1091,14 +1115,14 @@ static int scmi_perf_protocol_init(const struct scmi_protocol_handle *ph) scmi_perf_describe_levels_get(ph, dom, version); if (dom->perf_fastchannels) - scmi_perf_domain_init_fc(ph, dom->id, &dom->fc_info); + scmi_perf_domain_init_fc(ph, dom); } ret = devm_add_action_or_reset(ph->dev, scmi_perf_xa_destroy, pinfo); if (ret) return ret; - return ph->set_priv(ph, pinfo); + return ph->set_priv(ph, pinfo, version); } static const struct scmi_protocol scmi_perf = { @@ -1107,6 +1131,7 @@ static const struct scmi_protocol scmi_perf = { .instance_init = &scmi_perf_protocol_init, .ops = &perf_proto_ops, .events = &perf_protocol_events, + .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION, }; DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(perf, scmi_perf) diff --git a/drivers/firmware/arm_scmi/power.c b/drivers/firmware/arm_scmi/power.c index 356e83631664d9..c2e6b9b4d941cd 100644 --- a/drivers/firmware/arm_scmi/power.c +++ b/drivers/firmware/arm_scmi/power.c @@ -13,6 +13,9 @@ #include "protocols.h" #include "notify.h" +/* Updated only after ALL the mandatory features for that version are merged */ +#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30000 + enum scmi_power_protocol_cmd { POWER_DOMAIN_ATTRIBUTES = 0x3, POWER_STATE_SET = 0x4, @@ -133,7 +136,7 @@ scmi_power_domain_attributes_get(const struct scmi_protocol_handle *ph, if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x3 && SUPPORTS_EXTENDED_NAMES(flags)) { ph->hops->extended_name_get(ph, POWER_DOMAIN_NAME_GET, - domain, dom_info->name, + domain, NULL, dom_info->name, SCMI_MAX_STR_SIZE); } @@ -328,7 +331,7 @@ static int scmi_power_protocol_init(const struct scmi_protocol_handle *ph) pinfo->version = version; - return ph->set_priv(ph, pinfo); + return ph->set_priv(ph, pinfo, version); } static const struct scmi_protocol scmi_power = { @@ -337,6 +340,7 @@ static const struct scmi_protocol scmi_power = { .instance_init = &scmi_power_protocol_init, .ops = &power_proto_ops, .events = &power_protocol_events, + .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION, }; DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(power, scmi_power) diff --git a/drivers/firmware/arm_scmi/powercap.c b/drivers/firmware/arm_scmi/powercap.c index cb5617443a1448..a4c6cd4716fe44 100644 --- a/drivers/firmware/arm_scmi/powercap.c +++ b/drivers/firmware/arm_scmi/powercap.c @@ -17,6 +17,9 @@ #include "protocols.h" #include "notify.h" +/* Updated only after ALL the mandatory features for that version are merged */ +#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20000 + enum scmi_powercap_protocol_cmd { POWERCAP_DOMAIN_ATTRIBUTES = 0x3, POWERCAP_CAP_GET = 0x4, @@ -270,7 +273,7 @@ clean: */ if (!ret && SUPPORTS_EXTENDED_NAMES(flags)) ph->hops->extended_name_get(ph, POWERCAP_DOMAIN_NAME_GET, - domain, dom_info->name, + domain, NULL, dom_info->name, SCMI_MAX_STR_SIZE); return ret; @@ -975,7 +978,7 @@ scmi_powercap_protocol_init(const struct scmi_protocol_handle *ph) } pinfo->version = version; - return ph->set_priv(ph, pinfo); + return ph->set_priv(ph, pinfo, version); } static const struct scmi_protocol scmi_powercap = { @@ -984,6 +987,7 @@ static const struct scmi_protocol scmi_powercap = { .instance_init = &scmi_powercap_protocol_init, .ops = &powercap_proto_ops, .events = &powercap_protocol_events, + .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION, }; DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(powercap, scmi_powercap) diff --git a/drivers/firmware/arm_scmi/protocols.h b/drivers/firmware/arm_scmi/protocols.h index 78e1a01eb656e3..e683c26f24eb0c 100644 --- a/drivers/firmware/arm_scmi/protocols.h +++ b/drivers/firmware/arm_scmi/protocols.h @@ -174,7 +174,8 @@ struct scmi_protocol_handle { struct device *dev; const struct scmi_xfer_ops *xops; const struct scmi_proto_helpers_ops *hops; - int (*set_priv)(const struct scmi_protocol_handle *ph, void *priv); + int (*set_priv)(const struct scmi_protocol_handle *ph, void *priv, + u32 version); void *(*get_priv)(const struct scmi_protocol_handle *ph); }; @@ -256,7 +257,8 @@ struct scmi_fc_info { */ struct scmi_proto_helpers_ops { int (*extended_name_get)(const struct scmi_protocol_handle *ph, - u8 cmd_id, u32 res_id, char *name, size_t len); + u8 cmd_id, u32 res_id, u32 *flags, char *name, + size_t len); void *(*iter_response_init)(const struct scmi_protocol_handle *ph, struct scmi_iterator_ops *ops, unsigned int max_resources, u8 msg_id, @@ -310,6 +312,10 @@ typedef int (*scmi_prot_init_ph_fn_t)(const struct scmi_protocol_handle *); * @ops: Optional reference to the operations provided by the protocol and * exposed in scmi_protocol.h. * @events: An optional reference to the events supported by this protocol. + * @supported_version: The highest version currently supported for this + * protocol by the agent. Each protocol implementation + * in the agent is supposed to downgrade to match the + * protocol version supported by the platform. */ struct scmi_protocol { const u8 id; @@ -318,6 +324,7 @@ struct scmi_protocol { const scmi_prot_init_ph_fn_t instance_deinit; const void *ops; const struct scmi_protocol_events *events; + unsigned int supported_version; }; #define DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(name, proto) \ diff --git a/drivers/firmware/arm_scmi/raw_mode.c b/drivers/firmware/arm_scmi/raw_mode.c index 0493aa3c12bf53..35057351850335 100644 --- a/drivers/firmware/arm_scmi/raw_mode.c +++ b/drivers/firmware/arm_scmi/raw_mode.c @@ -1111,7 +1111,6 @@ static int scmi_raw_mode_setup(struct scmi_raw_mode_info *raw, int i; for (i = 0; i < num_chans; i++) { - void *xret; struct scmi_raw_queue *q; q = scmi_raw_queue_init(raw); @@ -1120,13 +1119,12 @@ static int scmi_raw_mode_setup(struct scmi_raw_mode_info *raw, goto err_xa; } - xret = xa_store(&raw->chans_q, channels[i], q, + ret = xa_insert(&raw->chans_q, channels[i], q, GFP_KERNEL); - if (xa_err(xret)) { + if (ret) { dev_err(dev, "Fail to allocate Raw queue 0x%02X\n", channels[i]); - ret = xa_err(xret); goto err_xa; } } @@ -1322,6 +1320,12 @@ void scmi_raw_message_report(void *r, struct scmi_xfer *xfer, dev = raw->handle->dev; q = scmi_raw_queue_select(raw, idx, SCMI_XFER_IS_CHAN_SET(xfer) ? chan_id : 0); + if (!q) { + dev_warn(dev, + "RAW[%d] - NO queue for chan 0x%X. Dropping report.\n", + idx, chan_id); + return; + } /* * Grab the msg_q_lock upfront to avoid a possible race between diff --git a/drivers/firmware/arm_scmi/reset.c b/drivers/firmware/arm_scmi/reset.c index e9afa8cab73094..19970d9f9e3677 100644 --- a/drivers/firmware/arm_scmi/reset.c +++ b/drivers/firmware/arm_scmi/reset.c @@ -13,6 +13,9 @@ #include "protocols.h" #include "notify.h" +/* Updated only after ALL the mandatory features for that version are merged */ +#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30000 + enum scmi_reset_protocol_cmd { RESET_DOMAIN_ATTRIBUTES = 0x3, RESET = 0x4, @@ -128,7 +131,8 @@ scmi_reset_domain_attributes_get(const struct scmi_protocol_handle *ph, if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x3 && SUPPORTS_EXTENDED_NAMES(attributes)) ph->hops->extended_name_get(ph, RESET_DOMAIN_NAME_GET, domain, - dom_info->name, SCMI_MAX_STR_SIZE); + NULL, dom_info->name, + SCMI_MAX_STR_SIZE); return ret; } @@ -342,7 +346,7 @@ static int scmi_reset_protocol_init(const struct scmi_protocol_handle *ph) } pinfo->version = version; - return ph->set_priv(ph, pinfo); + return ph->set_priv(ph, pinfo, version); } static const struct scmi_protocol scmi_reset = { @@ -351,6 +355,7 @@ static const struct scmi_protocol scmi_reset = { .instance_init = &scmi_reset_protocol_init, .ops = &reset_proto_ops, .events = &reset_protocol_events, + .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION, }; DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(reset, scmi_reset) diff --git a/drivers/firmware/arm_scmi/sensors.c b/drivers/firmware/arm_scmi/sensors.c index 0b5853fa9d874f..31114996537046 100644 --- a/drivers/firmware/arm_scmi/sensors.c +++ b/drivers/firmware/arm_scmi/sensors.c @@ -14,6 +14,9 @@ #include "protocols.h" #include "notify.h" +/* Updated only after ALL the mandatory features for that version are merged */ +#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30000 + #define SCMI_MAX_NUM_SENSOR_AXIS 63 #define SCMIv2_SENSOR_PROTOCOL 0x10000 @@ -644,7 +647,7 @@ iter_sens_descr_process_response(const struct scmi_protocol_handle *ph, if (PROTOCOL_REV_MAJOR(si->version) >= 0x3 && SUPPORTS_EXTENDED_NAMES(attrl)) ph->hops->extended_name_get(ph, SENSOR_NAME_GET, s->id, - s->name, SCMI_MAX_STR_SIZE); + NULL, s->name, SCMI_MAX_STR_SIZE); if (s->extended_scalar_attrs) { s->sensor_power = le32_to_cpu(sdesc->power); @@ -1138,7 +1141,7 @@ static int scmi_sensors_protocol_init(const struct scmi_protocol_handle *ph) if (ret) return ret; - return ph->set_priv(ph, sinfo); + return ph->set_priv(ph, sinfo, version); } static const struct scmi_protocol scmi_sensors = { @@ -1147,6 +1150,7 @@ static const struct scmi_protocol scmi_sensors = { .instance_init = &scmi_sensors_protocol_init, .ops = &sensor_proto_ops, .events = &sensor_protocol_events, + .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION, }; DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(sensors, scmi_sensors) diff --git a/drivers/firmware/arm_scmi/shmem.c b/drivers/firmware/arm_scmi/shmem.c index 87b4f4d35f0623..8bf495bcad09b7 100644 --- a/drivers/firmware/arm_scmi/shmem.c +++ b/drivers/firmware/arm_scmi/shmem.c @@ -10,7 +10,7 @@ #include #include -#include +#include #include "common.h" @@ -122,3 +122,9 @@ bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem, (SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR | SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE); } + +bool shmem_channel_free(struct scmi_shared_mem __iomem *shmem) +{ + return (ioread32(&shmem->channel_status) & + SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE); +} diff --git a/drivers/firmware/arm_scmi/system.c b/drivers/firmware/arm_scmi/system.c index 9383d75845393d..1621da97bcbb85 100644 --- a/drivers/firmware/arm_scmi/system.c +++ b/drivers/firmware/arm_scmi/system.c @@ -13,6 +13,9 @@ #include "protocols.h" #include "notify.h" +/* Updated only after ALL the mandatory features for that version are merged */ +#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20000 + #define SCMI_SYSTEM_NUM_SOURCES 1 enum scmi_system_protocol_cmd { @@ -144,7 +147,7 @@ static int scmi_system_protocol_init(const struct scmi_protocol_handle *ph) if (PROTOCOL_REV_MAJOR(pinfo->version) >= 0x2) pinfo->graceful_timeout_supported = true; - return ph->set_priv(ph, pinfo); + return ph->set_priv(ph, pinfo, version); } static const struct scmi_protocol scmi_system = { @@ -153,6 +156,7 @@ static const struct scmi_protocol scmi_system = { .instance_init = &scmi_system_protocol_init, .ops = NULL, .events = &system_protocol_events, + .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION, }; DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(system, scmi_system) diff --git a/drivers/firmware/arm_scmi/voltage.c b/drivers/firmware/arm_scmi/voltage.c index eaa8d944926a36..2175ffd6cef534 100644 --- a/drivers/firmware/arm_scmi/voltage.c +++ b/drivers/firmware/arm_scmi/voltage.c @@ -10,6 +10,9 @@ #include "protocols.h" +/* Updated only after ALL the mandatory features for that version are merged */ +#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20000 + #define VOLTAGE_DOMS_NUM_MASK GENMASK(15, 0) #define REMAINING_LEVELS_MASK GENMASK(31, 16) #define RETURNED_LEVELS_MASK GENMASK(11, 0) @@ -242,7 +245,7 @@ static int scmi_voltage_descriptors_get(const struct scmi_protocol_handle *ph, if (SUPPORTS_EXTENDED_NAMES(attributes)) ph->hops->extended_name_get(ph, VOLTAGE_DOMAIN_NAME_GET, - v->id, v->name, + v->id, NULL, v->name, SCMI_MAX_STR_SIZE); if (SUPPORTS_ASYNC_LEVEL_SET(attributes)) v->async_level_set = true; @@ -432,7 +435,7 @@ static int scmi_voltage_protocol_init(const struct scmi_protocol_handle *ph) dev_warn(ph->dev, "No Voltage domains found.\n"); } - return ph->set_priv(ph, vinfo); + return ph->set_priv(ph, vinfo, version); } static const struct scmi_protocol scmi_voltage = { @@ -440,6 +443,7 @@ static const struct scmi_protocol scmi_voltage = { .owner = THIS_MODULE, .instance_init = &scmi_voltage_protocol_init, .ops = &voltage_proto_ops, + .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION, }; DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(voltage, scmi_voltage) diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c index 3f123f592cb4c2..94a6b4e667de14 100644 --- a/drivers/firmware/arm_scpi.c +++ b/drivers/firmware/arm_scpi.c @@ -863,7 +863,7 @@ static void scpi_free_channels(void *data) mbox_free_channel(info->channels[i].chan); } -static int scpi_remove(struct platform_device *pdev) +static void scpi_remove(struct platform_device *pdev) { int i; struct scpi_drvinfo *info = platform_get_drvdata(pdev); @@ -874,8 +874,6 @@ static int scpi_remove(struct platform_device *pdev) kfree(info->dvfs[i]->opps); kfree(info->dvfs[i]); } - - return 0; } #define MAX_SCPI_XFERS 10 @@ -1048,7 +1046,7 @@ static struct platform_driver scpi_driver = { .dev_groups = versions_groups, }, .probe = scpi_probe, - .remove = scpi_remove, + .remove_new = scpi_remove, }; module_platform_driver(scpi_driver); diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig index cb374b2da9b78d..72f2537d90cafd 100644 --- a/drivers/firmware/efi/Kconfig +++ b/drivers/firmware/efi/Kconfig @@ -301,3 +301,18 @@ config UEFI_CPER_X86 bool depends on UEFI_CPER && X86 default y + +config TEE_STMM_EFI + tristate "TEE-based EFI runtime variable service driver" + depends on EFI && OPTEE + help + Select this config option if TEE is compiled to include StandAloneMM + as a separate secure partition. It has the ability to check and store + EFI variables on an RPMB or any other non-volatile medium used by + StandAloneMM. + + Enabling this will change the EFI runtime services from the firmware + provided functions to TEE calls. + + To compile this driver as a module, choose M here: the module + will be called tee_stmm_efi. diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile index e489fefd23dae0..a2d0009560d0f0 100644 --- a/drivers/firmware/efi/Makefile +++ b/drivers/firmware/efi/Makefile @@ -42,3 +42,4 @@ obj-$(CONFIG_EFI_EARLYCON) += earlycon.o obj-$(CONFIG_UEFI_CPER_ARM) += cper-arm.o obj-$(CONFIG_UEFI_CPER_X86) += cper-x86.o obj-$(CONFIG_UNACCEPTED_MEMORY) += unaccepted_memory.o +obj-$(CONFIG_TEE_STMM_EFI) += stmm/tee_stmm_efi.o diff --git a/drivers/firmware/efi/dev-path-parser.c b/drivers/firmware/efi/dev-path-parser.c index f80d87c199c3c3..937be269fee86d 100644 --- a/drivers/firmware/efi/dev-path-parser.c +++ b/drivers/firmware/efi/dev-path-parser.c @@ -18,8 +18,6 @@ static long __init parse_acpi_path(const struct efi_dev_path *node, struct acpi_device *adev; struct device *phys_dev; char hid[ACPI_ID_LEN]; - u64 uid; - int ret; if (node->header.length != 12) return -EINVAL; @@ -31,10 +29,9 @@ static long __init parse_acpi_path(const struct efi_dev_path *node, node->acpi.hid >> 16); for_each_acpi_dev_match(adev, hid, NULL, -1) { - ret = acpi_dev_uid_to_integer(adev, &uid); - if (ret == 0 && node->acpi.uid == uid) + if (acpi_dev_uid_match(adev, node->acpi.uid)) break; - if (ret == -ENODATA && node->acpi.uid == 0) + if (!acpi_device_uid(adev) && node->acpi.uid == 0) break; } if (!adev) diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 9d3910d1abe19e..4fcda50acfa4a8 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -32,6 +32,7 @@ #include #include #include +#include #include @@ -187,6 +188,9 @@ static const struct attribute_group efi_subsys_attr_group = { .is_visible = efi_attr_is_visible, }; +struct blocking_notifier_head efivar_ops_nh; +EXPORT_SYMBOL_GPL(efivar_ops_nh); + static struct efivars generic_efivars; static struct efivar_operations generic_ops; @@ -231,6 +235,18 @@ static void generic_ops_unregister(void) efivars_unregister(&generic_efivars); } +void efivars_generic_ops_register(void) +{ + generic_ops_register(); +} +EXPORT_SYMBOL_GPL(efivars_generic_ops_register); + +void efivars_generic_ops_unregister(void) +{ + generic_ops_unregister(); +} +EXPORT_SYMBOL_GPL(efivars_generic_ops_unregister); + #ifdef CONFIG_EFI_CUSTOM_SSDT_OVERLAYS #define EFIVAR_SSDT_NAME_MAX 16UL static char efivar_ssdt[EFIVAR_SSDT_NAME_MAX] __initdata; @@ -419,6 +435,8 @@ static int __init efisubsys_init(void) platform_device_register_simple("efivars", 0, NULL, 0); } + BLOCKING_INIT_NOTIFIER_HEAD(&efivar_ops_nh); + error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group); if (error) { pr_err("efi: Sysfs attribute export failed with error %d.\n", diff --git a/drivers/firmware/efi/libstub/Makefile.zboot b/drivers/firmware/efi/libstub/Makefile.zboot index 2c489627a80789..65ffd0b760b2fb 100644 --- a/drivers/firmware/efi/libstub/Makefile.zboot +++ b/drivers/firmware/efi/libstub/Makefile.zboot @@ -5,8 +5,8 @@ # EFI_ZBOOT_FORWARD_CFI quiet_cmd_copy_and_pad = PAD $@ - cmd_copy_and_pad = cp $< $@ && \ - truncate -s $(shell hexdump -s16 -n4 -e '"%u"' $<) $@ + cmd_copy_and_pad = cp $< $@; \ + truncate -s $$(hexdump -s16 -n4 -e '"%u"' $<) $@ # Pad the file to the size of the uncompressed image in memory, including BSS $(obj)/vmlinux.bin: $(obj)/$(EFI_ZBOOT_PAYLOAD) FORCE diff --git a/drivers/firmware/efi/libstub/loongarch-stub.c b/drivers/firmware/efi/libstub/loongarch-stub.c index d6ec5d4b8dbe08..736b6aae323d35 100644 --- a/drivers/firmware/efi/libstub/loongarch-stub.c +++ b/drivers/firmware/efi/libstub/loongarch-stub.c @@ -8,10 +8,10 @@ #include #include #include "efistub.h" +#include "loongarch-stub.h" extern int kernel_asize; extern int kernel_fsize; -extern int kernel_offset; extern int kernel_entry; efi_status_t handle_kernel_image(unsigned long *image_addr, @@ -24,7 +24,7 @@ efi_status_t handle_kernel_image(unsigned long *image_addr, efi_status_t status; unsigned long kernel_addr = 0; - kernel_addr = (unsigned long)&kernel_offset - kernel_offset; + kernel_addr = (unsigned long)image->image_base; status = efi_relocate_kernel(&kernel_addr, kernel_fsize, kernel_asize, EFI_KIMG_PREFERRED_ADDRESS, efi_get_kimg_min_align(), 0x0); @@ -35,9 +35,10 @@ efi_status_t handle_kernel_image(unsigned long *image_addr, return status; } -unsigned long kernel_entry_address(unsigned long kernel_addr) +unsigned long kernel_entry_address(unsigned long kernel_addr, + efi_loaded_image_t *image) { - unsigned long base = (unsigned long)&kernel_offset - kernel_offset; + unsigned long base = (unsigned long)image->image_base; return (unsigned long)&kernel_entry - base + kernel_addr; } diff --git a/drivers/firmware/efi/libstub/loongarch-stub.h b/drivers/firmware/efi/libstub/loongarch-stub.h new file mode 100644 index 00000000000000..cd015955a0152b --- /dev/null +++ b/drivers/firmware/efi/libstub/loongarch-stub.h @@ -0,0 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +unsigned long kernel_entry_address(unsigned long kernel_addr, + efi_loaded_image_t *image); diff --git a/drivers/firmware/efi/libstub/loongarch.c b/drivers/firmware/efi/libstub/loongarch.c index 0e0aa6cda73f7c..684c9354637c65 100644 --- a/drivers/firmware/efi/libstub/loongarch.c +++ b/drivers/firmware/efi/libstub/loongarch.c @@ -8,6 +8,7 @@ #include #include #include "efistub.h" +#include "loongarch-stub.h" typedef void __noreturn (*kernel_entry_t)(bool efi, unsigned long cmdline, unsigned long systab); @@ -37,7 +38,8 @@ static efi_status_t exit_boot_func(struct efi_boot_memmap *map, void *priv) return EFI_SUCCESS; } -unsigned long __weak kernel_entry_address(unsigned long kernel_addr) +unsigned long __weak kernel_entry_address(unsigned long kernel_addr, + efi_loaded_image_t *image) { return *(unsigned long *)(kernel_addr + 8) - VMLINUX_LOAD_ADDRESS + kernel_addr; } @@ -73,7 +75,7 @@ efi_status_t efi_boot_kernel(void *handle, efi_loaded_image_t *image, csr_write64(CSR_DMW0_INIT, LOONGARCH_CSR_DMWIN0); csr_write64(CSR_DMW1_INIT, LOONGARCH_CSR_DMWIN1); - real_kernel_entry = (void *)kernel_entry_address(kernel_addr); + real_kernel_entry = (void *)kernel_entry_address(kernel_addr, image); real_kernel_entry(true, (unsigned long)cmdline_ptr, (unsigned long)efi_system_table); diff --git a/drivers/firmware/efi/libstub/x86-5lvl.c b/drivers/firmware/efi/libstub/x86-5lvl.c index 479dd445acdcff..77359e802181fd 100644 --- a/drivers/firmware/efi/libstub/x86-5lvl.c +++ b/drivers/firmware/efi/libstub/x86-5lvl.c @@ -13,8 +13,8 @@ bool efi_no5lvl; static void (*la57_toggle)(void *cr3); static const struct desc_struct gdt[] = { - [GDT_ENTRY_KERNEL32_CS] = GDT_ENTRY_INIT(0xc09b, 0, 0xfffff), - [GDT_ENTRY_KERNEL_CS] = GDT_ENTRY_INIT(0xa09b, 0, 0xfffff), + [GDT_ENTRY_KERNEL32_CS] = GDT_ENTRY_INIT(DESC_CODE32, 0, 0xfffff), + [GDT_ENTRY_KERNEL_CS] = GDT_ENTRY_INIT(DESC_CODE64, 0, 0xfffff), }; /* diff --git a/drivers/firmware/efi/memmap.c b/drivers/firmware/efi/memmap.c index a1180461a445cf..3365944f796544 100644 --- a/drivers/firmware/efi/memmap.c +++ b/drivers/firmware/efi/memmap.c @@ -32,7 +32,7 @@ * space isn't setup. Once the kernel is fully booted we can fallback * to the more robust memremap*() API. * - * Returns zero on success, a negative error code on failure. + * Returns: zero on success, a negative error code on failure. */ int __init __efi_memmap_init(struct efi_memory_map_data *data) { @@ -77,6 +77,8 @@ int __init __efi_memmap_init(struct efi_memory_map_data *data) * * Use early_memremap() to map the passed in EFI memory map and assign * it to efi.memmap. + * + * Returns: zero on success, a negative error code on failure. */ int __init efi_memmap_init_early(struct efi_memory_map_data *data) { @@ -107,7 +109,7 @@ void __init efi_memmap_unmap(void) /** * efi_memmap_init_late - Map efi.memmap with memremap() - * @phys_addr: Physical address of the new EFI memory map + * @addr: Physical address of the new EFI memory map * @size: Size in bytes of the new EFI memory map * * Setup a mapping of the EFI memory map using ioremap_cache(). This @@ -126,7 +128,7 @@ void __init efi_memmap_unmap(void) * runtime so that things like efi_mem_desc_lookup() and * efi_mem_attributes() always work. * - * Returns zero on success, a negative error code on failure. + * Returns: zero on success, a negative error code on failure. */ int __init efi_memmap_init_late(phys_addr_t addr, unsigned long size) { diff --git a/drivers/firmware/efi/stmm/mm_communication.h b/drivers/firmware/efi/stmm/mm_communication.h new file mode 100644 index 00000000000000..52a1f32cd1eb8d --- /dev/null +++ b/drivers/firmware/efi/stmm/mm_communication.h @@ -0,0 +1,236 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Headers for EFI variable service via StandAloneMM, EDK2 application running + * in OP-TEE. Most of the structs and defines resemble the EDK2 naming. + * + * Copyright (c) 2017, Intel Corporation. All rights reserved. + * Copyright (C) 2020 Linaro Ltd. + */ + +#ifndef _MM_COMMUNICATION_H_ +#define _MM_COMMUNICATION_H_ + +/* + * Interface to the pseudo Trusted Application (TA), which provides a + * communication channel with the Standalone MM (Management Mode) + * Secure Partition running at Secure-EL0 + */ + +#define PTA_STMM_CMD_COMMUNICATE 0 + +/* + * Defined in OP-TEE, this UUID is used to identify the pseudo-TA. + * OP-TEE is using big endian GUIDs while UEFI uses little endian ones + */ +#define PTA_STMM_UUID \ + UUID_INIT(0xed32d533, 0x99e6, 0x4209, \ + 0x9c, 0xc0, 0x2d, 0x72, 0xcd, 0xd9, 0x98, 0xa7) + +#define EFI_MM_VARIABLE_GUID \ + EFI_GUID(0xed32d533, 0x99e6, 0x4209, \ + 0x9c, 0xc0, 0x2d, 0x72, 0xcd, 0xd9, 0x98, 0xa7) + +/** + * struct efi_mm_communicate_header - Header used for SMM variable communication + + * @header_guid: header use for disambiguation of content + * @message_len: length of the message. Does not include the size of the + * header + * @data: payload of the message + * + * Defined in the PI spec as EFI_MM_COMMUNICATE_HEADER. + * To avoid confusion in interpreting frames, the communication buffer should + * always begin with efi_mm_communicate_header. + */ +struct efi_mm_communicate_header { + efi_guid_t header_guid; + size_t message_len; + u8 data[]; +} __packed; + +#define MM_COMMUNICATE_HEADER_SIZE \ + (sizeof(struct efi_mm_communicate_header)) + +/* SPM return error codes */ +#define ARM_SVC_SPM_RET_SUCCESS 0 +#define ARM_SVC_SPM_RET_NOT_SUPPORTED -1 +#define ARM_SVC_SPM_RET_INVALID_PARAMS -2 +#define ARM_SVC_SPM_RET_DENIED -3 +#define ARM_SVC_SPM_RET_NO_MEMORY -5 + +#define SMM_VARIABLE_FUNCTION_GET_VARIABLE 1 +/* + * The payload for this function is + * SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME. + */ +#define SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME 2 +/* + * The payload for this function is SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE. + */ +#define SMM_VARIABLE_FUNCTION_SET_VARIABLE 3 +/* + * The payload for this function is + * SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO. + */ +#define SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO 4 +/* + * It is a notify event, no extra payload for this function. + */ +#define SMM_VARIABLE_FUNCTION_READY_TO_BOOT 5 +/* + * It is a notify event, no extra payload for this function. + */ +#define SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE 6 +/* + * The payload for this function is VARIABLE_INFO_ENTRY. + * The GUID in EFI_SMM_COMMUNICATE_HEADER is gEfiSmmVariableProtocolGuid. + */ +#define SMM_VARIABLE_FUNCTION_GET_STATISTICS 7 +/* + * The payload for this function is SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE + */ +#define SMM_VARIABLE_FUNCTION_LOCK_VARIABLE 8 + +#define SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET 9 + +#define SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET 10 + +#define SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE 11 +/* + * The payload for this function is + * SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT + */ +#define SMM_VARIABLE_FUNCTION_INIT_RUNTIME_VARIABLE_CACHE_CONTEXT 12 + +#define SMM_VARIABLE_FUNCTION_SYNC_RUNTIME_CACHE 13 +/* + * The payload for this function is + * SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO + */ +#define SMM_VARIABLE_FUNCTION_GET_RUNTIME_CACHE_INFO 14 + +/** + * struct smm_variable_communicate_header - Used for SMM variable communication + + * @function: function to call in Smm. + * @ret_status: return status + * @data: payload + */ +struct smm_variable_communicate_header { + size_t function; + efi_status_t ret_status; + u8 data[]; +}; + +#define MM_VARIABLE_COMMUNICATE_SIZE \ + (sizeof(struct smm_variable_communicate_header)) + +/** + * struct smm_variable_access - Used to communicate with StMM by + * SetVariable and GetVariable. + + * @guid: vendor GUID + * @data_size: size of EFI variable data + * @name_size: size of EFI name + * @attr: attributes + * @name: variable name + * + */ +struct smm_variable_access { + efi_guid_t guid; + size_t data_size; + size_t name_size; + u32 attr; + u16 name[]; +}; + +#define MM_VARIABLE_ACCESS_HEADER_SIZE \ + (sizeof(struct smm_variable_access)) +/** + * struct smm_variable_payload_size - Used to get the max allowed + * payload used in StMM. + * + * @size: size to fill in + * + */ +struct smm_variable_payload_size { + size_t size; +}; + +/** + * struct smm_variable_getnext - Used to communicate with StMM for + * GetNextVariableName. + * + * @guid: vendor GUID + * @name_size: size of the name of the variable + * @name: variable name + * + */ +struct smm_variable_getnext { + efi_guid_t guid; + size_t name_size; + u16 name[]; +}; + +#define MM_VARIABLE_GET_NEXT_HEADER_SIZE \ + (sizeof(struct smm_variable_getnext)) + +/** + * struct smm_variable_query_info - Used to communicate with StMM for + * QueryVariableInfo. + * + * @max_variable_storage: max available storage + * @remaining_variable_storage: remaining available storage + * @max_variable_size: max variable supported size + * @attr: attributes to query storage for + * + */ +struct smm_variable_query_info { + u64 max_variable_storage; + u64 remaining_variable_storage; + u64 max_variable_size; + u32 attr; +}; + +#define VAR_CHECK_VARIABLE_PROPERTY_REVISION 0x0001 +#define VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY BIT(0) +/** + * struct var_check_property - Used to store variable properties in StMM + * + * @revision: magic revision number for variable property checking + * @property: properties mask for the variable used in StMM. + * Currently RO flag is supported + * @attributes: variable attributes used in StMM checking when properties + * for a variable are enabled + * @minsize: minimum allowed size for variable payload checked against + * smm_variable_access->datasize in StMM + * @maxsize: maximum allowed size for variable payload checked against + * smm_variable_access->datasize in StMM + * + */ +struct var_check_property { + u16 revision; + u16 property; + u32 attributes; + size_t minsize; + size_t maxsize; +}; + +/** + * struct smm_variable_var_check_property - Used to communicate variable + * properties with StMM + * + * @guid: vendor GUID + * @name_size: size of EFI name + * @property: variable properties struct + * @name: variable name + * + */ +struct smm_variable_var_check_property { + efi_guid_t guid; + size_t name_size; + struct var_check_property property; + u16 name[]; +}; + +#endif /* _MM_COMMUNICATION_H_ */ diff --git a/drivers/firmware/efi/stmm/tee_stmm_efi.c b/drivers/firmware/efi/stmm/tee_stmm_efi.c new file mode 100644 index 00000000000000..f741ca279052bb --- /dev/null +++ b/drivers/firmware/efi/stmm/tee_stmm_efi.c @@ -0,0 +1,616 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * EFI variable service via TEE + * + * Copyright (C) 2022 Linaro + */ + +#include +#include +#include +#include +#include +#include +#include "mm_communication.h" + +static struct efivars tee_efivars; +static struct efivar_operations tee_efivar_ops; + +static size_t max_buffer_size; /* comm + var + func + data */ +static size_t max_payload_size; /* func + data */ + +struct tee_stmm_efi_private { + struct tee_context *ctx; + u32 session; + struct device *dev; +}; + +static struct tee_stmm_efi_private pvt_data; + +/* UUID of the stmm PTA */ +static const struct tee_client_device_id tee_stmm_efi_id_table[] = { + {PTA_STMM_UUID}, + {} +}; + +static int tee_ctx_match(struct tee_ioctl_version_data *ver, const void *data) +{ + /* currently only OP-TEE is supported as a communication path */ + if (ver->impl_id == TEE_IMPL_ID_OPTEE) + return 1; + else + return 0; +} + +/** + * tee_mm_communicate() - Pass a buffer to StandaloneMM running in TEE + * + * @comm_buf: locally allocated communication buffer + * @dsize: buffer size + * Return: status code + */ +static efi_status_t tee_mm_communicate(void *comm_buf, size_t dsize) +{ + size_t buf_size; + struct efi_mm_communicate_header *mm_hdr; + struct tee_ioctl_invoke_arg arg; + struct tee_param param[4]; + struct tee_shm *shm = NULL; + int rc; + + if (!comm_buf) + return EFI_INVALID_PARAMETER; + + mm_hdr = (struct efi_mm_communicate_header *)comm_buf; + buf_size = mm_hdr->message_len + sizeof(efi_guid_t) + sizeof(size_t); + + if (dsize != buf_size) + return EFI_INVALID_PARAMETER; + + shm = tee_shm_register_kernel_buf(pvt_data.ctx, comm_buf, buf_size); + if (IS_ERR(shm)) { + dev_err(pvt_data.dev, "Unable to register shared memory\n"); + return EFI_UNSUPPORTED; + } + + memset(&arg, 0, sizeof(arg)); + arg.func = PTA_STMM_CMD_COMMUNICATE; + arg.session = pvt_data.session; + arg.num_params = 4; + + memset(param, 0, sizeof(param)); + param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT; + param[0].u.memref.size = buf_size; + param[0].u.memref.shm = shm; + param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT; + param[2].attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE; + param[3].attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE; + + rc = tee_client_invoke_func(pvt_data.ctx, &arg, param); + tee_shm_free(shm); + + if (rc < 0 || arg.ret != 0) { + dev_err(pvt_data.dev, + "PTA_STMM_CMD_COMMUNICATE invoke error: 0x%x\n", arg.ret); + return EFI_DEVICE_ERROR; + } + + switch (param[1].u.value.a) { + case ARM_SVC_SPM_RET_SUCCESS: + return EFI_SUCCESS; + + case ARM_SVC_SPM_RET_INVALID_PARAMS: + return EFI_INVALID_PARAMETER; + + case ARM_SVC_SPM_RET_DENIED: + return EFI_ACCESS_DENIED; + + case ARM_SVC_SPM_RET_NO_MEMORY: + return EFI_OUT_OF_RESOURCES; + + default: + return EFI_ACCESS_DENIED; + } +} + +/** + * mm_communicate() - Adjust the communication buffer to StandAlonneMM and send + * it to TEE + * + * @comm_buf: locally allocated communication buffer, buffer should + * be enough big to have some headers and payload + * @payload_size: payload size + * Return: status code + */ +static efi_status_t mm_communicate(u8 *comm_buf, size_t payload_size) +{ + size_t dsize; + efi_status_t ret; + struct efi_mm_communicate_header *mm_hdr; + struct smm_variable_communicate_header *var_hdr; + + dsize = payload_size + MM_COMMUNICATE_HEADER_SIZE + + MM_VARIABLE_COMMUNICATE_SIZE; + mm_hdr = (struct efi_mm_communicate_header *)comm_buf; + var_hdr = (struct smm_variable_communicate_header *)mm_hdr->data; + + ret = tee_mm_communicate(comm_buf, dsize); + if (ret != EFI_SUCCESS) { + dev_err(pvt_data.dev, "%s failed!\n", __func__); + return ret; + } + + return var_hdr->ret_status; +} + +/** + * setup_mm_hdr() - Allocate a buffer for StandAloneMM and initialize the + * header data. + * + * @dptr: pointer address to store allocated buffer + * @payload_size: payload size + * @func: standAloneMM function number + * @ret: EFI return code + * Return: pointer to corresponding StandAloneMM function buffer or NULL + */ +static void *setup_mm_hdr(u8 **dptr, size_t payload_size, size_t func, + efi_status_t *ret) +{ + const efi_guid_t mm_var_guid = EFI_MM_VARIABLE_GUID; + struct efi_mm_communicate_header *mm_hdr; + struct smm_variable_communicate_header *var_hdr; + u8 *comm_buf; + + /* In the init function we initialize max_buffer_size with + * get_max_payload(). So skip the test if max_buffer_size is initialized + * StandAloneMM will perform similar checks and drop the buffer if it's + * too long + */ + if (max_buffer_size && + max_buffer_size < (MM_COMMUNICATE_HEADER_SIZE + + MM_VARIABLE_COMMUNICATE_SIZE + payload_size)) { + *ret = EFI_INVALID_PARAMETER; + return NULL; + } + + comm_buf = kzalloc(MM_COMMUNICATE_HEADER_SIZE + + MM_VARIABLE_COMMUNICATE_SIZE + payload_size, + GFP_KERNEL); + if (!comm_buf) { + *ret = EFI_OUT_OF_RESOURCES; + return NULL; + } + + mm_hdr = (struct efi_mm_communicate_header *)comm_buf; + memcpy(&mm_hdr->header_guid, &mm_var_guid, sizeof(mm_hdr->header_guid)); + mm_hdr->message_len = MM_VARIABLE_COMMUNICATE_SIZE + payload_size; + + var_hdr = (struct smm_variable_communicate_header *)mm_hdr->data; + var_hdr->function = func; + if (dptr) + *dptr = comm_buf; + *ret = EFI_SUCCESS; + + return var_hdr->data; +} + +/** + * get_max_payload() - Get variable payload size from StandAloneMM. + * + * @size: size of the variable in storage + * Return: status code + */ +static efi_status_t get_max_payload(size_t *size) +{ + struct smm_variable_payload_size *var_payload = NULL; + size_t payload_size; + u8 *comm_buf = NULL; + efi_status_t ret; + + if (!size) + return EFI_INVALID_PARAMETER; + + payload_size = sizeof(*var_payload); + var_payload = setup_mm_hdr(&comm_buf, payload_size, + SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE, + &ret); + if (!var_payload) + return EFI_OUT_OF_RESOURCES; + + ret = mm_communicate(comm_buf, payload_size); + if (ret != EFI_SUCCESS) + goto out; + + /* Make sure the buffer is big enough for storing variables */ + if (var_payload->size < MM_VARIABLE_ACCESS_HEADER_SIZE + 0x20) { + ret = EFI_DEVICE_ERROR; + goto out; + } + *size = var_payload->size; + /* + * There seems to be a bug in EDK2 miscalculating the boundaries and + * size checks, so deduct 2 more bytes to fulfill this requirement. Fix + * it up here to ensure backwards compatibility with older versions + * (cf. StandaloneMmPkg/Drivers/StandaloneMmCpu/AArch64/EventHandle.c. + * sizeof (EFI_MM_COMMUNICATE_HEADER) instead the size minus the + * flexible array member). + * + * size is guaranteed to be > 2 due to checks on the beginning. + */ + *size -= 2; +out: + kfree(comm_buf); + return ret; +} + +static efi_status_t get_property_int(u16 *name, size_t name_size, + const efi_guid_t *vendor, + struct var_check_property *var_property) +{ + struct smm_variable_var_check_property *smm_property; + size_t payload_size; + u8 *comm_buf = NULL; + efi_status_t ret; + + memset(var_property, 0, sizeof(*var_property)); + payload_size = sizeof(*smm_property) + name_size; + if (payload_size > max_payload_size) + return EFI_INVALID_PARAMETER; + + smm_property = setup_mm_hdr( + &comm_buf, payload_size, + SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET, &ret); + if (!smm_property) + return EFI_OUT_OF_RESOURCES; + + memcpy(&smm_property->guid, vendor, sizeof(smm_property->guid)); + smm_property->name_size = name_size; + memcpy(smm_property->name, name, name_size); + + ret = mm_communicate(comm_buf, payload_size); + /* + * Currently only R/O property is supported in StMM. + * Variables that are not set to R/O will not set the property in StMM + * and the call will return EFI_NOT_FOUND. We are setting the + * properties to 0x0 so checking against that is enough for the + * EFI_NOT_FOUND case. + */ + if (ret == EFI_NOT_FOUND) + ret = EFI_SUCCESS; + if (ret != EFI_SUCCESS) + goto out; + memcpy(var_property, &smm_property->property, sizeof(*var_property)); + +out: + kfree(comm_buf); + return ret; +} + +static efi_status_t tee_get_variable(u16 *name, efi_guid_t *vendor, + u32 *attributes, unsigned long *data_size, + void *data) +{ + struct var_check_property var_property; + struct smm_variable_access *var_acc; + size_t payload_size; + size_t name_size; + size_t tmp_dsize; + u8 *comm_buf = NULL; + efi_status_t ret; + + if (!name || !vendor || !data_size) + return EFI_INVALID_PARAMETER; + + name_size = (ucs2_strnlen(name, EFI_VAR_NAME_LEN) + 1) * sizeof(u16); + if (name_size > max_payload_size - MM_VARIABLE_ACCESS_HEADER_SIZE) + return EFI_INVALID_PARAMETER; + + /* Trim output buffer size */ + tmp_dsize = *data_size; + if (name_size + tmp_dsize > + max_payload_size - MM_VARIABLE_ACCESS_HEADER_SIZE) { + tmp_dsize = max_payload_size - MM_VARIABLE_ACCESS_HEADER_SIZE - + name_size; + } + + payload_size = MM_VARIABLE_ACCESS_HEADER_SIZE + name_size + tmp_dsize; + var_acc = setup_mm_hdr(&comm_buf, payload_size, + SMM_VARIABLE_FUNCTION_GET_VARIABLE, &ret); + if (!var_acc) + return EFI_OUT_OF_RESOURCES; + + /* Fill in contents */ + memcpy(&var_acc->guid, vendor, sizeof(var_acc->guid)); + var_acc->data_size = tmp_dsize; + var_acc->name_size = name_size; + var_acc->attr = attributes ? *attributes : 0; + memcpy(var_acc->name, name, name_size); + + ret = mm_communicate(comm_buf, payload_size); + if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL) + /* Update with reported data size for trimmed case */ + *data_size = var_acc->data_size; + if (ret != EFI_SUCCESS) + goto out; + + ret = get_property_int(name, name_size, vendor, &var_property); + if (ret != EFI_SUCCESS) + goto out; + + if (attributes) + *attributes = var_acc->attr; + + if (!data) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + memcpy(data, (u8 *)var_acc->name + var_acc->name_size, + var_acc->data_size); +out: + kfree(comm_buf); + return ret; +} + +static efi_status_t tee_get_next_variable(unsigned long *name_size, + efi_char16_t *name, efi_guid_t *guid) +{ + struct smm_variable_getnext *var_getnext; + size_t payload_size; + size_t out_name_size; + size_t in_name_size; + u8 *comm_buf = NULL; + efi_status_t ret; + + if (!name_size || !name || !guid) + return EFI_INVALID_PARAMETER; + + out_name_size = *name_size; + in_name_size = (ucs2_strnlen(name, EFI_VAR_NAME_LEN) + 1) * sizeof(u16); + + if (out_name_size < in_name_size) + return EFI_INVALID_PARAMETER; + + if (in_name_size > max_payload_size - MM_VARIABLE_GET_NEXT_HEADER_SIZE) + return EFI_INVALID_PARAMETER; + + /* Trim output buffer size */ + if (out_name_size > max_payload_size - MM_VARIABLE_GET_NEXT_HEADER_SIZE) + out_name_size = + max_payload_size - MM_VARIABLE_GET_NEXT_HEADER_SIZE; + + payload_size = MM_VARIABLE_GET_NEXT_HEADER_SIZE + out_name_size; + var_getnext = setup_mm_hdr(&comm_buf, payload_size, + SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME, + &ret); + if (!var_getnext) + return EFI_OUT_OF_RESOURCES; + + /* Fill in contents */ + memcpy(&var_getnext->guid, guid, sizeof(var_getnext->guid)); + var_getnext->name_size = out_name_size; + memcpy(var_getnext->name, name, in_name_size); + memset((u8 *)var_getnext->name + in_name_size, 0x0, + out_name_size - in_name_size); + + ret = mm_communicate(comm_buf, payload_size); + if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL) { + /* Update with reported data size for trimmed case */ + *name_size = var_getnext->name_size; + } + if (ret != EFI_SUCCESS) + goto out; + + memcpy(guid, &var_getnext->guid, sizeof(*guid)); + memcpy(name, var_getnext->name, var_getnext->name_size); + +out: + kfree(comm_buf); + return ret; +} + +static efi_status_t tee_set_variable(efi_char16_t *name, efi_guid_t *vendor, + u32 attributes, unsigned long data_size, + void *data) +{ + efi_status_t ret; + struct var_check_property var_property; + struct smm_variable_access *var_acc; + size_t payload_size; + size_t name_size; + u8 *comm_buf = NULL; + + if (!name || name[0] == 0 || !vendor) + return EFI_INVALID_PARAMETER; + + if (data_size > 0 && !data) + return EFI_INVALID_PARAMETER; + + /* Check payload size */ + name_size = (ucs2_strnlen(name, EFI_VAR_NAME_LEN) + 1) * sizeof(u16); + payload_size = MM_VARIABLE_ACCESS_HEADER_SIZE + name_size + data_size; + if (payload_size > max_payload_size) + return EFI_INVALID_PARAMETER; + + /* + * Allocate the buffer early, before switching to RW (if needed) + * so we won't need to account for any failures in reading/setting + * the properties, if the allocation fails + */ + var_acc = setup_mm_hdr(&comm_buf, payload_size, + SMM_VARIABLE_FUNCTION_SET_VARIABLE, &ret); + if (!var_acc) + return EFI_OUT_OF_RESOURCES; + + /* + * The API has the ability to override RO flags. If no RO check was + * requested switch the variable to RW for the duration of this call + */ + ret = get_property_int(name, name_size, vendor, &var_property); + if (ret != EFI_SUCCESS) { + dev_err(pvt_data.dev, "Getting variable property failed\n"); + goto out; + } + + if (var_property.property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY) { + ret = EFI_WRITE_PROTECTED; + goto out; + } + + /* Fill in contents */ + memcpy(&var_acc->guid, vendor, sizeof(var_acc->guid)); + var_acc->data_size = data_size; + var_acc->name_size = name_size; + var_acc->attr = attributes; + memcpy(var_acc->name, name, name_size); + memcpy((u8 *)var_acc->name + name_size, data, data_size); + + ret = mm_communicate(comm_buf, payload_size); + dev_dbg(pvt_data.dev, "Set Variable %s %d %lx\n", __FILE__, __LINE__, ret); +out: + kfree(comm_buf); + return ret; +} + +static efi_status_t tee_set_variable_nonblocking(efi_char16_t *name, + efi_guid_t *vendor, + u32 attributes, + unsigned long data_size, + void *data) +{ + return EFI_UNSUPPORTED; +} + +static efi_status_t tee_query_variable_info(u32 attributes, + u64 *max_variable_storage_size, + u64 *remain_variable_storage_size, + u64 *max_variable_size) +{ + struct smm_variable_query_info *mm_query_info; + size_t payload_size; + efi_status_t ret; + u8 *comm_buf; + + payload_size = sizeof(*mm_query_info); + mm_query_info = setup_mm_hdr(&comm_buf, payload_size, + SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO, + &ret); + if (!mm_query_info) + return EFI_OUT_OF_RESOURCES; + + mm_query_info->attr = attributes; + ret = mm_communicate(comm_buf, payload_size); + if (ret != EFI_SUCCESS) + goto out; + *max_variable_storage_size = mm_query_info->max_variable_storage; + *remain_variable_storage_size = + mm_query_info->remaining_variable_storage; + *max_variable_size = mm_query_info->max_variable_size; + +out: + kfree(comm_buf); + return ret; +} + +static void tee_stmm_efi_close_context(void *data) +{ + tee_client_close_context(pvt_data.ctx); +} + +static void tee_stmm_efi_close_session(void *data) +{ + tee_client_close_session(pvt_data.ctx, pvt_data.session); +} + +static void tee_stmm_restore_efivars_generic_ops(void) +{ + efivars_unregister(&tee_efivars); + efivars_generic_ops_register(); +} + +static int tee_stmm_efi_probe(struct device *dev) +{ + struct tee_ioctl_open_session_arg sess_arg; + efi_status_t ret; + int rc; + + pvt_data.ctx = tee_client_open_context(NULL, tee_ctx_match, NULL, NULL); + if (IS_ERR(pvt_data.ctx)) + return -ENODEV; + + rc = devm_add_action_or_reset(dev, tee_stmm_efi_close_context, NULL); + if (rc) + return rc; + + /* Open session with StMM PTA */ + memset(&sess_arg, 0, sizeof(sess_arg)); + export_uuid(sess_arg.uuid, &tee_stmm_efi_id_table[0].uuid); + rc = tee_client_open_session(pvt_data.ctx, &sess_arg, NULL); + if ((rc < 0) || (sess_arg.ret != 0)) { + dev_err(dev, "tee_client_open_session failed, err: %x\n", + sess_arg.ret); + return -EINVAL; + } + pvt_data.session = sess_arg.session; + pvt_data.dev = dev; + rc = devm_add_action_or_reset(dev, tee_stmm_efi_close_session, NULL); + if (rc) + return rc; + + ret = get_max_payload(&max_payload_size); + if (ret != EFI_SUCCESS) + return -EIO; + + max_buffer_size = MM_COMMUNICATE_HEADER_SIZE + + MM_VARIABLE_COMMUNICATE_SIZE + + max_payload_size; + + tee_efivar_ops.get_variable = tee_get_variable; + tee_efivar_ops.get_next_variable = tee_get_next_variable; + tee_efivar_ops.set_variable = tee_set_variable; + tee_efivar_ops.set_variable_nonblocking = tee_set_variable_nonblocking; + tee_efivar_ops.query_variable_store = efi_query_variable_store; + tee_efivar_ops.query_variable_info = tee_query_variable_info; + + efivars_generic_ops_unregister(); + pr_info("Using TEE-based EFI runtime variable services\n"); + efivars_register(&tee_efivars, &tee_efivar_ops); + + return 0; +} + +static int tee_stmm_efi_remove(struct device *dev) +{ + tee_stmm_restore_efivars_generic_ops(); + + return 0; +} + +MODULE_DEVICE_TABLE(tee, tee_stmm_efi_id_table); + +static struct tee_client_driver tee_stmm_efi_driver = { + .id_table = tee_stmm_efi_id_table, + .driver = { + .name = "tee-stmm-efi", + .bus = &tee_bus_type, + .probe = tee_stmm_efi_probe, + .remove = tee_stmm_efi_remove, + }, +}; + +static int __init tee_stmm_efi_mod_init(void) +{ + return driver_register(&tee_stmm_efi_driver.driver); +} + +static void __exit tee_stmm_efi_mod_exit(void) +{ + driver_unregister(&tee_stmm_efi_driver.driver); +} + +module_init(tee_stmm_efi_mod_init); +module_exit(tee_stmm_efi_mod_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Ilias Apalodimas "); +MODULE_AUTHOR("Masahisa Kojima "); +MODULE_DESCRIPTION("TEE based EFI runtime variable service driver"); diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c index e9dc7116daf133..f654e6f6af8738 100644 --- a/drivers/firmware/efi/vars.c +++ b/drivers/firmware/efi/vars.c @@ -63,6 +63,7 @@ int efivars_register(struct efivars *efivars, const struct efivar_operations *ops) { int rv; + int event; if (down_interruptible(&efivars_lock)) return -EINTR; @@ -77,6 +78,13 @@ int efivars_register(struct efivars *efivars, __efivars = efivars; + if (efivar_supports_writes()) + event = EFIVAR_OPS_RDWR; + else + event = EFIVAR_OPS_RDONLY; + + blocking_notifier_call_chain(&efivar_ops_nh, event, NULL); + pr_info("Registered efivars operations\n"); rv = 0; out: diff --git a/drivers/firmware/google/coreboot_table.c b/drivers/firmware/google/coreboot_table.c index 33ae94745aef97..2a4469bf1b81ce 100644 --- a/drivers/firmware/google/coreboot_table.c +++ b/drivers/firmware/google/coreboot_table.c @@ -176,10 +176,9 @@ static int __cb_dev_unregister(struct device *dev, void *dummy) return 0; } -static int coreboot_table_remove(struct platform_device *pdev) +static void coreboot_table_remove(struct platform_device *pdev) { bus_for_each_dev(&coreboot_bus_type, NULL, NULL, __cb_dev_unregister); - return 0; } #ifdef CONFIG_ACPI @@ -201,7 +200,7 @@ MODULE_DEVICE_TABLE(of, coreboot_of_match); static struct platform_driver coreboot_table_driver = { .probe = coreboot_table_probe, - .remove = coreboot_table_remove, + .remove_new = coreboot_table_remove, .driver = { .name = "coreboot_table", .acpi_match_table = ACPI_PTR(cros_coreboot_acpi_match), diff --git a/drivers/firmware/google/framebuffer-coreboot.c b/drivers/firmware/google/framebuffer-coreboot.c index c323a818805cc9..5c84bbebfef856 100644 --- a/drivers/firmware/google/framebuffer-coreboot.c +++ b/drivers/firmware/google/framebuffer-coreboot.c @@ -36,6 +36,9 @@ static int framebuffer_probe(struct coreboot_device *dev) .format = NULL, }; + if (!fb->physical_address) + return -ENODEV; + for (i = 0; i < ARRAY_SIZE(formats); ++i) { if (fb->bits_per_pixel == formats[i].bits_per_pixel && fb->red_mask_pos == formats[i].red.offset && diff --git a/drivers/firmware/imx/imx-dsp.c b/drivers/firmware/imx/imx-dsp.c index a48a58e0c61f8f..01c8ef14eaec3f 100644 --- a/drivers/firmware/imx/imx-dsp.c +++ b/drivers/firmware/imx/imx-dsp.c @@ -160,7 +160,7 @@ static int imx_dsp_probe(struct platform_device *pdev) return 0; } -static int imx_dsp_remove(struct platform_device *pdev) +static void imx_dsp_remove(struct platform_device *pdev) { struct imx_dsp_chan *dsp_chan; struct imx_dsp_ipc *dsp_ipc; @@ -173,8 +173,6 @@ static int imx_dsp_remove(struct platform_device *pdev) mbox_free_channel(dsp_chan->ch); kfree(dsp_chan->name); } - - return 0; } static struct platform_driver imx_dsp_driver = { @@ -182,7 +180,7 @@ static struct platform_driver imx_dsp_driver = { .name = "imx-dsp", }, .probe = imx_dsp_probe, - .remove = imx_dsp_remove, + .remove_new = imx_dsp_remove, }; builtin_platform_driver(imx_dsp_driver); diff --git a/drivers/firmware/meson/meson_sm.c b/drivers/firmware/meson/meson_sm.c index ed60f1103053e7..5d7f62fe1d5ff1 100644 --- a/drivers/firmware/meson/meson_sm.c +++ b/drivers/firmware/meson/meson_sm.c @@ -274,14 +274,11 @@ static ssize_t serial_show(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR_RO(serial); -static struct attribute *meson_sm_sysfs_attributes[] = { +static struct attribute *meson_sm_sysfs_attrs[] = { &dev_attr_serial.attr, NULL, }; - -static const struct attribute_group meson_sm_sysfs_attr_group = { - .attrs = meson_sm_sysfs_attributes, -}; +ATTRIBUTE_GROUPS(meson_sm_sysfs); static const struct of_device_id meson_sm_ids[] = { { .compatible = "amlogic,meson-gxbb-sm", .data = &gxbb_chip }, @@ -313,7 +310,7 @@ static int __init meson_sm_probe(struct platform_device *pdev) fw->sm_shmem_out_base = meson_sm_map_shmem(chip->cmd_shmem_out_base, chip->shmem_size); if (WARN_ON(!fw->sm_shmem_out_base)) - goto out_in_base; + goto unmap_in_base; } fw->chip = chip; @@ -321,16 +318,15 @@ static int __init meson_sm_probe(struct platform_device *pdev) platform_set_drvdata(pdev, fw); if (devm_of_platform_populate(dev)) - goto out_in_base; - - if (sysfs_create_group(&pdev->dev.kobj, &meson_sm_sysfs_attr_group)) - goto out_in_base; + goto unmap_out_base; pr_info("secure-monitor enabled\n"); return 0; -out_in_base: +unmap_out_base: + iounmap(fw->sm_shmem_out_base); +unmap_in_base: iounmap(fw->sm_shmem_in_base); out: return -EINVAL; @@ -340,6 +336,7 @@ static struct platform_driver meson_sm_driver = { .driver = { .name = "meson-sm", .of_match_table = of_match_ptr(meson_sm_ids), + .dev_groups = meson_sm_sysfs_groups, }, }; module_platform_driver_probe(meson_sm_driver, meson_sm_probe); diff --git a/drivers/firmware/microchip/Kconfig b/drivers/firmware/microchip/Kconfig new file mode 100644 index 00000000000000..434b923e08c240 --- /dev/null +++ b/drivers/firmware/microchip/Kconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config POLARFIRE_SOC_AUTO_UPDATE + tristate "Microchip PolarFire SoC AUTO UPDATE" + depends on POLARFIRE_SOC_SYS_CTRL + select FW_LOADER + select FW_UPLOAD + help + Support for reprogramming PolarFire SoC from within Linux, using the + Auto Upgrade feature of the system controller. + + If built as a module, it will be called mpfs-auto-update. diff --git a/drivers/firmware/microchip/Makefile b/drivers/firmware/microchip/Makefile new file mode 100644 index 00000000000000..38796fd82893c5 --- /dev/null +++ b/drivers/firmware/microchip/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_POLARFIRE_SOC_AUTO_UPDATE) += mpfs-auto-update.o diff --git a/drivers/firmware/microchip/mpfs-auto-update.c b/drivers/firmware/microchip/mpfs-auto-update.c new file mode 100644 index 00000000000000..81f5f62e34fce0 --- /dev/null +++ b/drivers/firmware/microchip/mpfs-auto-update.c @@ -0,0 +1,494 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Microchip Polarfire SoC "Auto Update" FPGA reprogramming. + * + * Documentation of this functionality is available in the "PolarFire® FPGA and + * PolarFire SoC FPGA Programming" User Guide. + * + * Copyright (c) 2022-2023 Microchip Corporation. All rights reserved. + * + * Author: Conor Dooley + */ +#include +#include +#include +#include +#include +#include +#include + +#include + +#define AUTO_UPDATE_DEFAULT_MBOX_OFFSET 0u +#define AUTO_UPDATE_DEFAULT_RESP_OFFSET 0u + +#define AUTO_UPDATE_FEATURE_CMD_OPCODE 0x05u +#define AUTO_UPDATE_FEATURE_CMD_DATA_SIZE 0u +#define AUTO_UPDATE_FEATURE_RESP_SIZE 33u +#define AUTO_UPDATE_FEATURE_CMD_DATA NULL +#define AUTO_UPDATE_FEATURE_ENABLED BIT(5) + +#define AUTO_UPDATE_AUTHENTICATE_CMD_OPCODE 0x22u +#define AUTO_UPDATE_AUTHENTICATE_CMD_DATA_SIZE 0u +#define AUTO_UPDATE_AUTHENTICATE_RESP_SIZE 1u +#define AUTO_UPDATE_AUTHENTICATE_CMD_DATA NULL + +#define AUTO_UPDATE_PROGRAM_CMD_OPCODE 0x46u +#define AUTO_UPDATE_PROGRAM_CMD_DATA_SIZE 0u +#define AUTO_UPDATE_PROGRAM_RESP_SIZE 1u +#define AUTO_UPDATE_PROGRAM_CMD_DATA NULL + +/* + * SPI Flash layout example: + * |------------------------------| 0x0000000 + * | 1 KiB | + * | SPI "directories" | + * |------------------------------| 0x0000400 + * | 1 MiB | + * | Reserved area | + * | Used for bitstream info | + * |------------------------------| 0x0100400 + * | 20 MiB | + * | Golden Image | + * |------------------------------| 0x1500400 + * | 20 MiB | + * | Auto Upgrade Image | + * |------------------------------| 0x2900400 + * | 20 MiB | + * | Reserved for multi-image IAP | + * | Unused for Auto Upgrade | + * |------------------------------| 0x3D00400 + * | ? B | + * | Unused | + * |------------------------------| 0x? + */ +#define AUTO_UPDATE_DIRECTORY_BASE 0u +#define AUTO_UPDATE_DIRECTORY_WIDTH 4u +#define AUTO_UPDATE_GOLDEN_INDEX 0u +#define AUTO_UPDATE_UPGRADE_INDEX 1u +#define AUTO_UPDATE_BLANK_INDEX 2u +#define AUTO_UPDATE_GOLDEN_DIRECTORY (AUTO_UPDATE_DIRECTORY_WIDTH * AUTO_UPDATE_GOLDEN_INDEX) +#define AUTO_UPDATE_UPGRADE_DIRECTORY (AUTO_UPDATE_DIRECTORY_WIDTH * AUTO_UPDATE_UPGRADE_INDEX) +#define AUTO_UPDATE_BLANK_DIRECTORY (AUTO_UPDATE_DIRECTORY_WIDTH * AUTO_UPDATE_BLANK_INDEX) +#define AUTO_UPDATE_DIRECTORY_SIZE SZ_1K +#define AUTO_UPDATE_RESERVED_SIZE SZ_1M +#define AUTO_UPDATE_BITSTREAM_BASE (AUTO_UPDATE_DIRECTORY_SIZE + AUTO_UPDATE_RESERVED_SIZE) + +#define AUTO_UPDATE_TIMEOUT_MS 60000 + +struct mpfs_auto_update_priv { + struct mpfs_sys_controller *sys_controller; + struct device *dev; + struct mtd_info *flash; + struct fw_upload *fw_uploader; + struct completion programming_complete; + size_t size_per_bitstream; + bool cancel_request; +}; + +static enum fw_upload_err mpfs_auto_update_prepare(struct fw_upload *fw_uploader, const u8 *data, + u32 size) +{ + struct mpfs_auto_update_priv *priv = fw_uploader->dd_handle; + size_t erase_size = AUTO_UPDATE_DIRECTORY_SIZE; + + /* + * Verifying the Golden Image is idealistic. It will be evaluated + * against the currently programmed image and thus may fail - due to + * either rollback protection (if its an older version than that in use) + * or if the version is the same as that of the in-use image. + * Extracting the information as to why a failure occurred is not + * currently possible due to limitations of the system controller + * driver. If those are fixed, verification of the Golden Image should + * be added here. + */ + + priv->flash = mpfs_sys_controller_get_flash(priv->sys_controller); + if (!priv->flash) + return FW_UPLOAD_ERR_HW_ERROR; + + erase_size = round_up(erase_size, (u64)priv->flash->erasesize); + + /* + * We need to calculate if we have enough space in the flash for the + * new image. + * First, chop off the first 1 KiB as it's reserved for the directory. + * The 1 MiB reserved for design info needs to be ignored also. + * All that remains is carved into 3 & rounded down to the erasesize. + * If this is smaller than the image size, we abort. + * There's also no need to consume more than 20 MiB per image. + */ + priv->size_per_bitstream = priv->flash->size - SZ_1K - SZ_1M; + priv->size_per_bitstream = round_down(priv->size_per_bitstream / 3, erase_size); + if (priv->size_per_bitstream > 20 * SZ_1M) + priv->size_per_bitstream = 20 * SZ_1M; + + if (priv->size_per_bitstream < size) { + dev_err(priv->dev, + "flash device has insufficient capacity to store this bitstream\n"); + return FW_UPLOAD_ERR_INVALID_SIZE; + } + + priv->cancel_request = false; + + return FW_UPLOAD_ERR_NONE; +} + +static void mpfs_auto_update_cancel(struct fw_upload *fw_uploader) +{ + struct mpfs_auto_update_priv *priv = fw_uploader->dd_handle; + + priv->cancel_request = true; +} + +static enum fw_upload_err mpfs_auto_update_poll_complete(struct fw_upload *fw_uploader) +{ + struct mpfs_auto_update_priv *priv = fw_uploader->dd_handle; + int ret; + + /* + * There is no meaningful way to get the status of the programming while + * it is in progress, so attempting anything other than waiting for it + * to complete would be misplaced. + */ + ret = wait_for_completion_timeout(&priv->programming_complete, + msecs_to_jiffies(AUTO_UPDATE_TIMEOUT_MS)); + if (ret) + return FW_UPLOAD_ERR_TIMEOUT; + + return FW_UPLOAD_ERR_NONE; +} + +static int mpfs_auto_update_verify_image(struct fw_upload *fw_uploader) +{ + struct mpfs_auto_update_priv *priv = fw_uploader->dd_handle; + struct mpfs_mss_response *response; + struct mpfs_mss_msg *message; + u32 *response_msg; + int ret; + + response_msg = devm_kzalloc(priv->dev, AUTO_UPDATE_FEATURE_RESP_SIZE * sizeof(response_msg), + GFP_KERNEL); + if (!response_msg) + return -ENOMEM; + + response = devm_kzalloc(priv->dev, sizeof(struct mpfs_mss_response), GFP_KERNEL); + if (!response) { + ret = -ENOMEM; + goto free_response_msg; + } + + message = devm_kzalloc(priv->dev, sizeof(struct mpfs_mss_msg), GFP_KERNEL); + if (!message) { + ret = -ENOMEM; + goto free_response; + } + + /* + * The system controller can verify that an image in the flash is valid. + * Rather than duplicate the check in this driver, call the relevant + * service from the system controller instead. + * This service has no command data and no response data. It overloads + * mbox_offset with the image index in the flash's SPI directory where + * the bitstream is located. + */ + response->resp_msg = response_msg; + response->resp_size = AUTO_UPDATE_AUTHENTICATE_RESP_SIZE; + message->cmd_opcode = AUTO_UPDATE_AUTHENTICATE_CMD_OPCODE; + message->cmd_data_size = AUTO_UPDATE_AUTHENTICATE_CMD_DATA_SIZE; + message->response = response; + message->cmd_data = AUTO_UPDATE_AUTHENTICATE_CMD_DATA; + message->mbox_offset = AUTO_UPDATE_UPGRADE_INDEX; + message->resp_offset = AUTO_UPDATE_DEFAULT_RESP_OFFSET; + + dev_info(priv->dev, "Running verification of Upgrade Image\n"); + ret = mpfs_blocking_transaction(priv->sys_controller, message); + if (ret | response->resp_status) { + dev_warn(priv->dev, "Verification of Upgrade Image failed!\n"); + ret = ret ? ret : -EBADMSG; + } + + dev_info(priv->dev, "Verification of Upgrade Image passed!\n"); + + devm_kfree(priv->dev, message); +free_response: + devm_kfree(priv->dev, response); +free_response_msg: + devm_kfree(priv->dev, response_msg); + + return ret; +} + +static int mpfs_auto_update_set_image_address(struct mpfs_auto_update_priv *priv, char *buffer, + u32 image_address, loff_t directory_address) +{ + struct erase_info erase; + size_t erase_size = AUTO_UPDATE_DIRECTORY_SIZE; + size_t bytes_written = 0, bytes_read = 0; + int ret; + + erase_size = round_up(erase_size, (u64)priv->flash->erasesize); + + erase.addr = AUTO_UPDATE_DIRECTORY_BASE; + erase.len = erase_size; + + /* + * We need to write the "SPI DIRECTORY" to the first 1 KiB, telling + * the system controller where to find the actual bitstream. Since + * this is spi-nor, we have to read the first eraseblock, erase that + * portion of the flash, modify the data and then write it back. + * There's no need to do this though if things are already the way they + * should be, so check and save the write in that case. + */ + ret = mtd_read(priv->flash, AUTO_UPDATE_DIRECTORY_BASE, erase_size, &bytes_read, + (u_char *)buffer); + if (ret) + return ret; + + if (bytes_read != erase_size) + return -EIO; + + if ((*(u32 *)(buffer + AUTO_UPDATE_UPGRADE_DIRECTORY) == image_address) && + !(*(u32 *)(buffer + AUTO_UPDATE_BLANK_DIRECTORY))) + return 0; + + ret = mtd_erase(priv->flash, &erase); + if (ret) + return ret; + + /* + * Populate the image address and then zero out the next directory so + * that the system controller doesn't complain if in "Single Image" + * mode. + */ + memcpy(buffer + AUTO_UPDATE_UPGRADE_DIRECTORY, &image_address, + AUTO_UPDATE_DIRECTORY_WIDTH); + memset(buffer + AUTO_UPDATE_BLANK_DIRECTORY, 0x0, AUTO_UPDATE_DIRECTORY_WIDTH); + + dev_info(priv->dev, "Writing the image address (%x) to the flash directory (%llx)\n", + image_address, directory_address); + + ret = mtd_write(priv->flash, 0x0, erase_size, &bytes_written, (u_char *)buffer); + if (ret) + return ret; + + if (bytes_written != erase_size) + return ret; + + return 0; +} + +static int mpfs_auto_update_write_bitstream(struct fw_upload *fw_uploader, const u8 *data, + u32 offset, u32 size, u32 *written) +{ + struct mpfs_auto_update_priv *priv = fw_uploader->dd_handle; + struct erase_info erase; + char *buffer; + loff_t directory_address = AUTO_UPDATE_UPGRADE_DIRECTORY; + size_t erase_size = AUTO_UPDATE_DIRECTORY_SIZE; + size_t bytes_written = 0; + u32 image_address; + int ret; + + erase_size = round_up(erase_size, (u64)priv->flash->erasesize); + + image_address = AUTO_UPDATE_BITSTREAM_BASE + + AUTO_UPDATE_UPGRADE_INDEX * priv->size_per_bitstream; + + buffer = devm_kzalloc(priv->dev, erase_size, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + ret = mpfs_auto_update_set_image_address(priv, buffer, image_address, directory_address); + if (ret) { + dev_err(priv->dev, "failed to set image address in the SPI directory: %d\n", ret); + goto out; + } + + /* + * Now the .spi image itself can be written to the flash. Preservation + * of contents here is not important here, unlike the spi "directory" + * which must be RMWed. + */ + erase.len = round_up(size, (size_t)priv->flash->erasesize); + erase.addr = image_address; + + dev_info(priv->dev, "Erasing the flash at address (%x)\n", image_address); + ret = mtd_erase(priv->flash, &erase); + if (ret) + goto out; + + /* + * No parsing etc of the bitstream is required. The system controller + * will do all of that itself - including verifying that the bitstream + * is valid. + */ + dev_info(priv->dev, "Writing the image to the flash at address (%x)\n", image_address); + ret = mtd_write(priv->flash, (loff_t)image_address, size, &bytes_written, data); + if (ret) + goto out; + + if (bytes_written != size) { + ret = -EIO; + goto out; + } + + *written = bytes_written; + +out: + devm_kfree(priv->dev, buffer); + return ret; +} + +static enum fw_upload_err mpfs_auto_update_write(struct fw_upload *fw_uploader, const u8 *data, + u32 offset, u32 size, u32 *written) +{ + struct mpfs_auto_update_priv *priv = fw_uploader->dd_handle; + enum fw_upload_err err = FW_UPLOAD_ERR_NONE; + int ret; + + reinit_completion(&priv->programming_complete); + + ret = mpfs_auto_update_write_bitstream(fw_uploader, data, offset, size, written); + if (ret) { + err = FW_UPLOAD_ERR_RW_ERROR; + goto out; + } + + if (priv->cancel_request) { + err = FW_UPLOAD_ERR_CANCELED; + goto out; + } + + ret = mpfs_auto_update_verify_image(fw_uploader); + if (ret) + err = FW_UPLOAD_ERR_FW_INVALID; + +out: + complete(&priv->programming_complete); + + return err; +} + +static const struct fw_upload_ops mpfs_auto_update_ops = { + .prepare = mpfs_auto_update_prepare, + .write = mpfs_auto_update_write, + .poll_complete = mpfs_auto_update_poll_complete, + .cancel = mpfs_auto_update_cancel, +}; + +static int mpfs_auto_update_available(struct mpfs_auto_update_priv *priv) +{ + struct mpfs_mss_response *response; + struct mpfs_mss_msg *message; + u32 *response_msg; + int ret; + + response_msg = devm_kzalloc(priv->dev, AUTO_UPDATE_FEATURE_RESP_SIZE * sizeof(response_msg), + GFP_KERNEL); + if (!response_msg) + return -ENOMEM; + + response = devm_kzalloc(priv->dev, sizeof(struct mpfs_mss_response), GFP_KERNEL); + if (!response) + return -ENOMEM; + + message = devm_kzalloc(priv->dev, sizeof(struct mpfs_mss_msg), GFP_KERNEL); + if (!message) + return -ENOMEM; + + /* + * To verify that Auto Update is possible, the "Query Security Service + * Request" is performed. + * This service has no command data & does not overload mbox_offset. + */ + response->resp_msg = response_msg; + response->resp_size = AUTO_UPDATE_FEATURE_RESP_SIZE; + message->cmd_opcode = AUTO_UPDATE_FEATURE_CMD_OPCODE; + message->cmd_data_size = AUTO_UPDATE_FEATURE_CMD_DATA_SIZE; + message->response = response; + message->cmd_data = AUTO_UPDATE_FEATURE_CMD_DATA; + message->mbox_offset = AUTO_UPDATE_DEFAULT_MBOX_OFFSET; + message->resp_offset = AUTO_UPDATE_DEFAULT_RESP_OFFSET; + + ret = mpfs_blocking_transaction(priv->sys_controller, message); + if (ret) + return ret; + + /* + * Currently, the system controller's firmware does not generate any + * interrupts for failed services, so mpfs_blocking_transaction() should + * time out & therefore return an error. + * Hitting this check is highly unlikely at present, but if the system + * controller's behaviour changes so that it does generate interrupts + * for failed services, it will be required. + */ + if (response->resp_status) + return -EIO; + + /* + * Bit 5 of byte 1 is "UL_Auto Update" & if it is set, Auto Update is + * not possible. + */ + if (response_msg[1] & AUTO_UPDATE_FEATURE_ENABLED) + return -EPERM; + + return 0; +} + +static int mpfs_auto_update_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mpfs_auto_update_priv *priv; + struct fw_upload *fw_uploader; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->sys_controller = mpfs_sys_controller_get(dev); + if (IS_ERR(priv->sys_controller)) + return dev_err_probe(dev, PTR_ERR(priv->sys_controller), + "Could not register as a sub device of the system controller\n"); + + priv->dev = dev; + platform_set_drvdata(pdev, priv); + + ret = mpfs_auto_update_available(priv); + if (ret) + return dev_err_probe(dev, ret, + "The current bitstream does not support auto-update\n"); + + init_completion(&priv->programming_complete); + + fw_uploader = firmware_upload_register(THIS_MODULE, dev, "mpfs-auto-update", + &mpfs_auto_update_ops, priv); + if (IS_ERR(fw_uploader)) + return dev_err_probe(dev, PTR_ERR(fw_uploader), + "Failed to register the bitstream uploader\n"); + + priv->fw_uploader = fw_uploader; + + return 0; +} + +static void mpfs_auto_update_remove(struct platform_device *pdev) +{ + struct mpfs_auto_update_priv *priv = platform_get_drvdata(pdev); + + firmware_upload_unregister(priv->fw_uploader); +} + +static struct platform_driver mpfs_auto_update_driver = { + .driver = { + .name = "mpfs-auto-update", + }, + .probe = mpfs_auto_update_probe, + .remove_new = mpfs_auto_update_remove, +}; +module_platform_driver(mpfs_auto_update_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Conor Dooley "); +MODULE_DESCRIPTION("PolarFire SoC Auto Update FPGA reprogramming"); diff --git a/drivers/firmware/mtk-adsp-ipc.c b/drivers/firmware/mtk-adsp-ipc.c index 85e94ddc7204d8..a762302978de0f 100644 --- a/drivers/firmware/mtk-adsp-ipc.c +++ b/drivers/firmware/mtk-adsp-ipc.c @@ -116,7 +116,7 @@ static int mtk_adsp_ipc_probe(struct platform_device *pdev) return 0; } -static int mtk_adsp_ipc_remove(struct platform_device *pdev) +static void mtk_adsp_ipc_remove(struct platform_device *pdev) { struct mtk_adsp_ipc *adsp_ipc = dev_get_drvdata(&pdev->dev); struct mtk_adsp_chan *adsp_chan; @@ -126,8 +126,6 @@ static int mtk_adsp_ipc_remove(struct platform_device *pdev) adsp_chan = &adsp_ipc->chans[i]; mbox_free_channel(adsp_chan->ch); } - - return 0; } static struct platform_driver mtk_adsp_ipc_driver = { @@ -135,7 +133,7 @@ static struct platform_driver mtk_adsp_ipc_driver = { .name = "mtk-adsp-ipc", }, .probe = mtk_adsp_ipc_probe, - .remove = mtk_adsp_ipc_remove, + .remove_new = mtk_adsp_ipc_remove, }; builtin_platform_driver(mtk_adsp_ipc_driver); diff --git a/drivers/firmware/qcom/qcom_qseecom_uefisecapp.c b/drivers/firmware/qcom/qcom_qseecom_uefisecapp.c index a33acdaf7b7817..32188f098ef349 100644 --- a/drivers/firmware/qcom/qcom_qseecom_uefisecapp.c +++ b/drivers/firmware/qcom/qcom_qseecom_uefisecapp.c @@ -325,8 +325,10 @@ static efi_status_t qsee_uefi_get_variable(struct qcuefi_client *qcuefi, const e req_data->length = req_size; status = ucs2_strscpy(((void *)req_data) + req_data->name_offset, name, name_length); - if (status < 0) - return EFI_INVALID_PARAMETER; + if (status < 0) { + efi_status = EFI_INVALID_PARAMETER; + goto out_free; + } memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size); @@ -471,8 +473,10 @@ static efi_status_t qsee_uefi_set_variable(struct qcuefi_client *qcuefi, const e req_data->length = req_size; status = ucs2_strscpy(((void *)req_data) + req_data->name_offset, name, name_length); - if (status < 0) - return EFI_INVALID_PARAMETER; + if (status < 0) { + efi_status = EFI_INVALID_PARAMETER; + goto out_free; + } memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size); @@ -563,8 +567,10 @@ static efi_status_t qsee_uefi_get_next_variable(struct qcuefi_client *qcuefi, memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size); status = ucs2_strscpy(((void *)req_data) + req_data->name_offset, name, *name_size / sizeof(*name)); - if (status < 0) - return EFI_INVALID_PARAMETER; + if (status < 0) { + efi_status = EFI_INVALID_PARAMETER; + goto out_free; + } status = qcom_qseecom_app_send(qcuefi->client, req_data, req_size, rsp_data, rsp_size); if (status) { @@ -635,7 +641,7 @@ static efi_status_t qsee_uefi_get_next_variable(struct qcuefi_client *qcuefi, * have already been validated above, causing this function to * bail with EFI_BUFFER_TOO_SMALL. */ - return EFI_DEVICE_ERROR; + efi_status = EFI_DEVICE_ERROR; } out_free: diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c index 1448f61173b357..03da9a4354f886 100644 --- a/drivers/firmware/qemu_fw_cfg.c +++ b/drivers/firmware/qemu_fw_cfg.c @@ -731,7 +731,7 @@ err_sel: return err; } -static int fw_cfg_sysfs_remove(struct platform_device *pdev) +static void fw_cfg_sysfs_remove(struct platform_device *pdev) { pr_debug("fw_cfg: unloading.\n"); fw_cfg_sysfs_cache_cleanup(); @@ -739,7 +739,6 @@ static int fw_cfg_sysfs_remove(struct platform_device *pdev) fw_cfg_io_cleanup(); fw_cfg_kset_unregister_recursive(fw_cfg_fname_kset); fw_cfg_kobj_cleanup(fw_cfg_sel_ko); - return 0; } static const struct of_device_id fw_cfg_sysfs_mmio_match[] = { @@ -758,7 +757,7 @@ MODULE_DEVICE_TABLE(acpi, fw_cfg_sysfs_acpi_match); static struct platform_driver fw_cfg_sysfs_driver = { .probe = fw_cfg_sysfs_probe, - .remove = fw_cfg_sysfs_remove, + .remove_new = fw_cfg_sysfs_remove, .driver = { .name = "fw_cfg", .of_match_table = fw_cfg_sysfs_mmio_match, diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c index 4cd290a60fbaaa..322aada20f7421 100644 --- a/drivers/firmware/raspberrypi.c +++ b/drivers/firmware/raspberrypi.c @@ -317,7 +317,7 @@ static void rpi_firmware_shutdown(struct platform_device *pdev) rpi_firmware_property(fw, RPI_FIRMWARE_NOTIFY_REBOOT, NULL, 0); } -static int rpi_firmware_remove(struct platform_device *pdev) +static void rpi_firmware_remove(struct platform_device *pdev) { struct rpi_firmware *fw = platform_get_drvdata(pdev); @@ -327,8 +327,6 @@ static int rpi_firmware_remove(struct platform_device *pdev) rpi_clk = NULL; rpi_firmware_put(fw); - - return 0; } static const struct of_device_id rpi_firmware_of_match[] = { @@ -406,7 +404,7 @@ static struct platform_driver rpi_firmware_driver = { }, .probe = rpi_firmware_probe, .shutdown = rpi_firmware_shutdown, - .remove = rpi_firmware_remove, + .remove_new = rpi_firmware_remove, }; module_platform_driver(rpi_firmware_driver); diff --git a/drivers/firmware/scpi_pm_domain.c b/drivers/firmware/scpi_pm_domain.c deleted file mode 100644 index 2231e6dd2070a2..00000000000000 --- a/drivers/firmware/scpi_pm_domain.c +++ /dev/null @@ -1,157 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * SCPI Generic power domain support. - * - * Copyright (C) 2016 ARM Ltd. - */ - -#include -#include -#include -#include -#include -#include -#include - -struct scpi_pm_domain { - struct generic_pm_domain genpd; - struct scpi_ops *ops; - u32 domain; -}; - -/* - * These device power state values are not well-defined in the specification. - * In case, different implementations use different values, we can make these - * specific to compatibles rather than getting these values from device tree. - */ -enum scpi_power_domain_state { - SCPI_PD_STATE_ON = 0, - SCPI_PD_STATE_OFF = 3, -}; - -#define to_scpi_pd(gpd) container_of(gpd, struct scpi_pm_domain, genpd) - -static int scpi_pd_power(struct scpi_pm_domain *pd, bool power_on) -{ - int ret; - enum scpi_power_domain_state state; - - if (power_on) - state = SCPI_PD_STATE_ON; - else - state = SCPI_PD_STATE_OFF; - - ret = pd->ops->device_set_power_state(pd->domain, state); - if (ret) - return ret; - - return !(state == pd->ops->device_get_power_state(pd->domain)); -} - -static int scpi_pd_power_on(struct generic_pm_domain *domain) -{ - struct scpi_pm_domain *pd = to_scpi_pd(domain); - - return scpi_pd_power(pd, true); -} - -static int scpi_pd_power_off(struct generic_pm_domain *domain) -{ - struct scpi_pm_domain *pd = to_scpi_pd(domain); - - return scpi_pd_power(pd, false); -} - -static int scpi_pm_domain_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; - struct scpi_pm_domain *scpi_pd; - struct genpd_onecell_data *scpi_pd_data; - struct generic_pm_domain **domains; - struct scpi_ops *scpi_ops; - int ret, num_domains, i; - - scpi_ops = get_scpi_ops(); - if (!scpi_ops) - return -EPROBE_DEFER; - - if (!np) { - dev_err(dev, "device tree node not found\n"); - return -ENODEV; - } - - if (!scpi_ops->device_set_power_state || - !scpi_ops->device_get_power_state) { - dev_err(dev, "power domains not supported in the firmware\n"); - return -ENODEV; - } - - ret = of_property_read_u32(np, "num-domains", &num_domains); - if (ret) { - dev_err(dev, "number of domains not found\n"); - return -EINVAL; - } - - scpi_pd = devm_kcalloc(dev, num_domains, sizeof(*scpi_pd), GFP_KERNEL); - if (!scpi_pd) - return -ENOMEM; - - scpi_pd_data = devm_kzalloc(dev, sizeof(*scpi_pd_data), GFP_KERNEL); - if (!scpi_pd_data) - return -ENOMEM; - - domains = devm_kcalloc(dev, num_domains, sizeof(*domains), GFP_KERNEL); - if (!domains) - return -ENOMEM; - - for (i = 0; i < num_domains; i++, scpi_pd++) { - domains[i] = &scpi_pd->genpd; - - scpi_pd->domain = i; - scpi_pd->ops = scpi_ops; - scpi_pd->genpd.name = devm_kasprintf(dev, GFP_KERNEL, - "%pOFn.%d", np, i); - if (!scpi_pd->genpd.name) { - dev_err(dev, "Failed to allocate genpd name:%pOFn.%d\n", - np, i); - continue; - } - scpi_pd->genpd.power_off = scpi_pd_power_off; - scpi_pd->genpd.power_on = scpi_pd_power_on; - - /* - * Treat all power domains as off at boot. - * - * The SCP firmware itself may have switched on some domains, - * but for reference counting purpose, keep it this way. - */ - pm_genpd_init(&scpi_pd->genpd, NULL, true); - } - - scpi_pd_data->domains = domains; - scpi_pd_data->num_domains = num_domains; - - of_genpd_add_provider_onecell(np, scpi_pd_data); - - return 0; -} - -static const struct of_device_id scpi_power_domain_ids[] = { - { .compatible = "arm,scpi-power-domains", }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, scpi_power_domain_ids); - -static struct platform_driver scpi_power_domain_driver = { - .driver = { - .name = "scpi_power_domain", - .of_match_table = scpi_power_domain_ids, - }, - .probe = scpi_pm_domain_probe, -}; -module_platform_driver(scpi_power_domain_driver); - -MODULE_AUTHOR("Sudeep Holla "); -MODULE_DESCRIPTION("ARM SCPI power domain driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/firmware/stratix10-rsu.c b/drivers/firmware/stratix10-rsu.c index 4f7a7abada48a6..e20cee9c2d320a 100644 --- a/drivers/firmware/stratix10-rsu.c +++ b/drivers/firmware/stratix10-rsu.c @@ -793,17 +793,16 @@ static int stratix10_rsu_probe(struct platform_device *pdev) return ret; } -static int stratix10_rsu_remove(struct platform_device *pdev) +static void stratix10_rsu_remove(struct platform_device *pdev) { struct stratix10_rsu_priv *priv = platform_get_drvdata(pdev); stratix10_svc_free_channel(priv->chan); - return 0; } static struct platform_driver stratix10_rsu_driver = { .probe = stratix10_rsu_probe, - .remove = stratix10_rsu_remove, + .remove_new = stratix10_rsu_remove, .driver = { .name = "stratix10-rsu", .dev_groups = rsu_groups, diff --git a/drivers/firmware/stratix10-svc.c b/drivers/firmware/stratix10-svc.c index c693da60e9a977..528f37417aea48 100644 --- a/drivers/firmware/stratix10-svc.c +++ b/drivers/firmware/stratix10-svc.c @@ -1251,7 +1251,7 @@ err_destroy_pool: return ret; } -static int stratix10_svc_drv_remove(struct platform_device *pdev) +static void stratix10_svc_drv_remove(struct platform_device *pdev) { struct stratix10_svc *svc = dev_get_drvdata(&pdev->dev); struct stratix10_svc_controller *ctrl = platform_get_drvdata(pdev); @@ -1267,13 +1267,11 @@ static int stratix10_svc_drv_remove(struct platform_device *pdev) if (ctrl->genpool) gen_pool_destroy(ctrl->genpool); list_del(&ctrl->node); - - return 0; } static struct platform_driver stratix10_svc_driver = { .probe = stratix10_svc_drv_probe, - .remove = stratix10_svc_drv_remove, + .remove_new = stratix10_svc_drv_remove, .driver = { .name = "stratix10-svc", .of_match_table = stratix10_svc_drv_match, diff --git a/drivers/firmware/sysfb.c b/drivers/firmware/sysfb.c index 82fcfd29bc4d29..3c197db42c9d93 100644 --- a/drivers/firmware/sysfb.c +++ b/drivers/firmware/sysfb.c @@ -128,4 +128,4 @@ unlock_mutex: } /* must execute after PCI subsystem for EFI quirks */ -subsys_initcall_sync(sysfb_init); +device_initcall(sysfb_init); diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c index 7041befc756a9f..8b9a2556de16dc 100644 --- a/drivers/firmware/ti_sci.c +++ b/drivers/firmware/ti_sci.c @@ -164,7 +164,7 @@ static int ti_sci_debugfs_create(struct platform_device *pdev, { struct device *dev = &pdev->dev; struct resource *res; - char debug_name[50] = "ti_sci_debug@"; + char debug_name[50]; /* Debug region is optional */ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, @@ -181,10 +181,10 @@ static int ti_sci_debugfs_create(struct platform_device *pdev, /* Setup NULL termination */ info->debug_buffer[info->debug_region_size] = 0; - info->d = debugfs_create_file(strncat(debug_name, dev_name(dev), - sizeof(debug_name) - - sizeof("ti_sci_debug@")), - 0444, NULL, info, &ti_sci_debug_fops); + snprintf(debug_name, sizeof(debug_name), "ti_sci_debug@%s", + dev_name(dev)); + info->d = debugfs_create_file(debug_name, 0444, NULL, info, + &ti_sci_debug_fops); if (IS_ERR(info->d)) return PTR_ERR(info->d); diff --git a/drivers/firmware/turris-mox-rwtm.c b/drivers/firmware/turris-mox-rwtm.c index 2de0fb139ce176..31d962cdd6eb2e 100644 --- a/drivers/firmware/turris-mox-rwtm.c +++ b/drivers/firmware/turris-mox-rwtm.c @@ -554,7 +554,7 @@ put_kobj: return ret; } -static int turris_mox_rwtm_remove(struct platform_device *pdev) +static void turris_mox_rwtm_remove(struct platform_device *pdev) { struct mox_rwtm *rwtm = platform_get_drvdata(pdev); @@ -562,8 +562,6 @@ static int turris_mox_rwtm_remove(struct platform_device *pdev) sysfs_remove_files(rwtm_to_kobj(rwtm), mox_rwtm_attrs); kobject_put(rwtm_to_kobj(rwtm)); mbox_free_channel(rwtm->mbox); - - return 0; } static const struct of_device_id turris_mox_rwtm_match[] = { @@ -576,7 +574,7 @@ MODULE_DEVICE_TABLE(of, turris_mox_rwtm_match); static struct platform_driver turris_mox_rwtm_driver = { .probe = turris_mox_rwtm_probe, - .remove = turris_mox_rwtm_remove, + .remove_new = turris_mox_rwtm_remove, .driver = { .name = DRIVER_NAME, .of_match_table = turris_mox_rwtm_match, diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c index b0d22d4455d950..79789f0563f6a3 100644 --- a/drivers/firmware/xilinx/zynqmp.c +++ b/drivers/firmware/xilinx/zynqmp.c @@ -92,6 +92,8 @@ static int zynqmp_pm_ret_code(u32 ret_status) return 0; case XST_PM_NO_FEATURE: return -ENOTSUPP; + case XST_PM_INVALID_VERSION: + return -EOPNOTSUPP; case XST_PM_NO_ACCESS: return -EACCES; case XST_PM_ABORT_SUSPEND: @@ -101,13 +103,13 @@ static int zynqmp_pm_ret_code(u32 ret_status) case XST_PM_INTERNAL: case XST_PM_CONFLICT: case XST_PM_INVALID_NODE: + case XST_PM_INVALID_CRC: default: return -EINVAL; } } -static noinline int do_fw_call_fail(u64 arg0, u64 arg1, u64 arg2, - u32 *ret_payload) +static noinline int do_fw_call_fail(u32 *ret_payload, u32 num_args, ...) { return -ENODEV; } @@ -116,25 +118,35 @@ static noinline int do_fw_call_fail(u64 arg0, u64 arg1, u64 arg2, * PM function call wrapper * Invoke do_fw_call_smc or do_fw_call_hvc, depending on the configuration */ -static int (*do_fw_call)(u64, u64, u64, u32 *ret_payload) = do_fw_call_fail; +static int (*do_fw_call)(u32 *ret_payload, u32, ...) = do_fw_call_fail; /** * do_fw_call_smc() - Call system-level platform management layer (SMC) - * @arg0: Argument 0 to SMC call - * @arg1: Argument 1 to SMC call - * @arg2: Argument 2 to SMC call + * @num_args: Number of variable arguments should be <= 8 * @ret_payload: Returned value array * * Invoke platform management function via SMC call (no hypervisor present). * * Return: Returns status, either success or error+reason */ -static noinline int do_fw_call_smc(u64 arg0, u64 arg1, u64 arg2, - u32 *ret_payload) +static noinline int do_fw_call_smc(u32 *ret_payload, u32 num_args, ...) { struct arm_smccc_res res; + u64 args[8] = {0}; + va_list arg_list; + u8 i; - arm_smccc_smc(arg0, arg1, arg2, 0, 0, 0, 0, 0, &res); + if (num_args > 8) + return -EINVAL; + + va_start(arg_list, num_args); + + for (i = 0; i < num_args; i++) + args[i] = va_arg(arg_list, u64); + + va_end(arg_list); + + arm_smccc_smc(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], &res); if (ret_payload) { ret_payload[0] = lower_32_bits(res.a0); @@ -148,9 +160,7 @@ static noinline int do_fw_call_smc(u64 arg0, u64 arg1, u64 arg2, /** * do_fw_call_hvc() - Call system-level platform management layer (HVC) - * @arg0: Argument 0 to HVC call - * @arg1: Argument 1 to HVC call - * @arg2: Argument 2 to HVC call + * @num_args: Number of variable arguments should be <= 8 * @ret_payload: Returned value array * * Invoke platform management function via HVC @@ -159,12 +169,24 @@ static noinline int do_fw_call_smc(u64 arg0, u64 arg1, u64 arg2, * * Return: Returns status, either success or error+reason */ -static noinline int do_fw_call_hvc(u64 arg0, u64 arg1, u64 arg2, - u32 *ret_payload) +static noinline int do_fw_call_hvc(u32 *ret_payload, u32 num_args, ...) { struct arm_smccc_res res; + u64 args[8] = {0}; + va_list arg_list; + u8 i; + + if (num_args > 8) + return -EINVAL; + + va_start(arg_list, num_args); + + for (i = 0; i < num_args; i++) + args[i] = va_arg(arg_list, u64); + + va_end(arg_list); - arm_smccc_hvc(arg0, arg1, arg2, 0, 0, 0, 0, 0, &res); + arm_smccc_hvc(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], &res); if (ret_payload) { ret_payload[0] = lower_32_bits(res.a0); @@ -180,11 +202,31 @@ static int __do_feature_check_call(const u32 api_id, u32 *ret_payload) { int ret; u64 smc_arg[2]; + u32 module_id; + u32 feature_check_api_id; - smc_arg[0] = PM_SIP_SVC | PM_FEATURE_CHECK; - smc_arg[1] = api_id; + module_id = FIELD_GET(MODULE_ID_MASK, api_id); - ret = do_fw_call(smc_arg[0], smc_arg[1], 0, ret_payload); + /* + * Feature check of APIs belonging to PM, XSEM, and TF-A are handled by calling + * PM_FEATURE_CHECK API. For other modules, call PM_API_FEATURES API. + */ + if (module_id == PM_MODULE_ID || module_id == XSEM_MODULE_ID || module_id == TF_A_MODULE_ID) + feature_check_api_id = PM_FEATURE_CHECK; + else + feature_check_api_id = PM_API_FEATURES; + + /* + * Feature check of TF-A APIs is done in the TF-A layer and it expects for + * MODULE_ID_MASK bits of SMC's arg[0] to be the same as PM_MODULE_ID. + */ + if (module_id == TF_A_MODULE_ID) + module_id = PM_MODULE_ID; + + smc_arg[0] = PM_SIP_SVC | FIELD_PREP(MODULE_ID_MASK, module_id) | feature_check_api_id; + smc_arg[1] = (api_id & API_ID_MASK); + + ret = do_fw_call(ret_payload, 2, smc_arg[0], smc_arg[1]); if (ret) ret = -EOPNOTSUPP; else @@ -295,11 +337,8 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_is_function_supported); * zynqmp_pm_invoke_fn() - Invoke the system-level platform management layer * caller function depending on the configuration * @pm_api_id: Requested PM-API call - * @arg0: Argument 0 to requested PM-API call - * @arg1: Argument 1 to requested PM-API call - * @arg2: Argument 2 to requested PM-API call - * @arg3: Argument 3 to requested PM-API call * @ret_payload: Returned value array + * @num_args: Number of arguments to requested PM-API call * * Invoke platform management function for SMC or HVC call, depending on * configuration. @@ -316,26 +355,38 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_is_function_supported); * * Return: Returns status, either success or error+reason */ -int zynqmp_pm_invoke_fn(u32 pm_api_id, u32 arg0, u32 arg1, - u32 arg2, u32 arg3, u32 *ret_payload) +int zynqmp_pm_invoke_fn(u32 pm_api_id, u32 *ret_payload, u32 num_args, ...) { /* * Added SIP service call Function Identifier * Make sure to stay in x0 register */ - u64 smc_arg[4]; - int ret; + u64 smc_arg[8]; + int ret, i; + va_list arg_list; + u32 args[14] = {0}; + + if (num_args > 14) + return -EINVAL; + + va_start(arg_list, num_args); /* Check if feature is supported or not */ ret = zynqmp_pm_feature(pm_api_id); if (ret < 0) return ret; + for (i = 0; i < num_args; i++) + args[i] = va_arg(arg_list, u32); + + va_end(arg_list); + smc_arg[0] = PM_SIP_SVC | pm_api_id; - smc_arg[1] = ((u64)arg1 << 32) | arg0; - smc_arg[2] = ((u64)arg3 << 32) | arg2; + for (i = 0; i < 7; i++) + smc_arg[i + 1] = ((u64)args[(i * 2) + 1] << 32) | args[i * 2]; - return do_fw_call(smc_arg[0], smc_arg[1], smc_arg[2], ret_payload); + return do_fw_call(ret_payload, 8, smc_arg[0], smc_arg[1], smc_arg[2], smc_arg[3], + smc_arg[4], smc_arg[5], smc_arg[6], smc_arg[7]); } static u32 pm_api_version; @@ -347,14 +398,12 @@ int zynqmp_pm_register_sgi(u32 sgi_num, u32 reset) { int ret; - ret = zynqmp_pm_invoke_fn(TF_A_PM_REGISTER_SGI, sgi_num, reset, 0, 0, - NULL); - if (!ret) + ret = zynqmp_pm_invoke_fn(TF_A_PM_REGISTER_SGI, NULL, 2, sgi_num, reset); + if (ret != -EOPNOTSUPP && !ret) return ret; /* try old implementation as fallback strategy if above fails */ - return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_REGISTER_SGI, sgi_num, - reset, NULL); + return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 3, IOCTL_REGISTER_SGI, sgi_num, reset); } /** @@ -376,7 +425,7 @@ int zynqmp_pm_get_api_version(u32 *version) *version = pm_api_version; return 0; } - ret = zynqmp_pm_invoke_fn(PM_GET_API_VERSION, 0, 0, 0, 0, ret_payload); + ret = zynqmp_pm_invoke_fn(PM_GET_API_VERSION, ret_payload, 0); *version = ret_payload[1]; return ret; @@ -399,7 +448,7 @@ int zynqmp_pm_get_chipid(u32 *idcode, u32 *version) if (!idcode || !version) return -EINVAL; - ret = zynqmp_pm_invoke_fn(PM_GET_CHIPID, 0, 0, 0, 0, ret_payload); + ret = zynqmp_pm_invoke_fn(PM_GET_CHIPID, ret_payload, 0); *idcode = ret_payload[1]; *version = ret_payload[2]; @@ -414,7 +463,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_get_chipid); * * Return: Returns status, either success or error+reason */ -static int zynqmp_pm_get_family_info(u32 *family, u32 *subfamily) +int zynqmp_pm_get_family_info(u32 *family, u32 *subfamily) { u32 ret_payload[PAYLOAD_ARG_CNT]; u32 idcode; @@ -427,7 +476,7 @@ static int zynqmp_pm_get_family_info(u32 *family, u32 *subfamily) return 0; } - ret = zynqmp_pm_invoke_fn(PM_GET_CHIPID, 0, 0, 0, 0, ret_payload); + ret = zynqmp_pm_invoke_fn(PM_GET_CHIPID, ret_payload, 0); if (ret < 0) return ret; @@ -439,6 +488,7 @@ static int zynqmp_pm_get_family_info(u32 *family, u32 *subfamily) return 0; } +EXPORT_SYMBOL_GPL(zynqmp_pm_get_family_info); /** * zynqmp_pm_get_trustzone_version() - Get secure trustzone firmware version @@ -459,8 +509,7 @@ static int zynqmp_pm_get_trustzone_version(u32 *version) *version = pm_tz_version; return 0; } - ret = zynqmp_pm_invoke_fn(PM_GET_TRUSTZONE_VERSION, 0, 0, - 0, 0, ret_payload); + ret = zynqmp_pm_invoke_fn(PM_GET_TRUSTZONE_VERSION, ret_payload, 0); *version = ret_payload[1]; return ret; @@ -507,8 +556,8 @@ int zynqmp_pm_query_data(struct zynqmp_pm_query_data qdata, u32 *out) { int ret; - ret = zynqmp_pm_invoke_fn(PM_QUERY_DATA, qdata.qid, qdata.arg1, - qdata.arg2, qdata.arg3, out); + ret = zynqmp_pm_invoke_fn(PM_QUERY_DATA, out, 4, qdata.qid, qdata.arg1, qdata.arg2, + qdata.arg3); /* * For clock name query, all bytes in SMC response are clock name @@ -530,7 +579,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_query_data); */ int zynqmp_pm_clock_enable(u32 clock_id) { - return zynqmp_pm_invoke_fn(PM_CLOCK_ENABLE, clock_id, 0, 0, 0, NULL); + return zynqmp_pm_invoke_fn(PM_CLOCK_ENABLE, NULL, 1, clock_id); } EXPORT_SYMBOL_GPL(zynqmp_pm_clock_enable); @@ -545,7 +594,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_clock_enable); */ int zynqmp_pm_clock_disable(u32 clock_id) { - return zynqmp_pm_invoke_fn(PM_CLOCK_DISABLE, clock_id, 0, 0, 0, NULL); + return zynqmp_pm_invoke_fn(PM_CLOCK_DISABLE, NULL, 1, clock_id); } EXPORT_SYMBOL_GPL(zynqmp_pm_clock_disable); @@ -564,8 +613,7 @@ int zynqmp_pm_clock_getstate(u32 clock_id, u32 *state) u32 ret_payload[PAYLOAD_ARG_CNT]; int ret; - ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETSTATE, clock_id, 0, - 0, 0, ret_payload); + ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETSTATE, ret_payload, 1, clock_id); *state = ret_payload[1]; return ret; @@ -584,8 +632,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_clock_getstate); */ int zynqmp_pm_clock_setdivider(u32 clock_id, u32 divider) { - return zynqmp_pm_invoke_fn(PM_CLOCK_SETDIVIDER, clock_id, divider, - 0, 0, NULL); + return zynqmp_pm_invoke_fn(PM_CLOCK_SETDIVIDER, NULL, 2, clock_id, divider); } EXPORT_SYMBOL_GPL(zynqmp_pm_clock_setdivider); @@ -604,55 +651,13 @@ int zynqmp_pm_clock_getdivider(u32 clock_id, u32 *divider) u32 ret_payload[PAYLOAD_ARG_CNT]; int ret; - ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETDIVIDER, clock_id, 0, - 0, 0, ret_payload); + ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETDIVIDER, ret_payload, 1, clock_id); *divider = ret_payload[1]; return ret; } EXPORT_SYMBOL_GPL(zynqmp_pm_clock_getdivider); -/** - * zynqmp_pm_clock_setrate() - Set the clock rate for given id - * @clock_id: ID of the clock - * @rate: rate value in hz - * - * This function is used by master to set rate for any clock. - * - * Return: Returns status, either success or error+reason - */ -int zynqmp_pm_clock_setrate(u32 clock_id, u64 rate) -{ - return zynqmp_pm_invoke_fn(PM_CLOCK_SETRATE, clock_id, - lower_32_bits(rate), - upper_32_bits(rate), - 0, NULL); -} -EXPORT_SYMBOL_GPL(zynqmp_pm_clock_setrate); - -/** - * zynqmp_pm_clock_getrate() - Get the clock rate for given id - * @clock_id: ID of the clock - * @rate: rate value in hz - * - * This function is used by master to get rate - * for any clock. - * - * Return: Returns status, either success or error+reason - */ -int zynqmp_pm_clock_getrate(u32 clock_id, u64 *rate) -{ - u32 ret_payload[PAYLOAD_ARG_CNT]; - int ret; - - ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETRATE, clock_id, 0, - 0, 0, ret_payload); - *rate = ((u64)ret_payload[2] << 32) | ret_payload[1]; - - return ret; -} -EXPORT_SYMBOL_GPL(zynqmp_pm_clock_getrate); - /** * zynqmp_pm_clock_setparent() - Set the clock parent for given id * @clock_id: ID of the clock @@ -664,8 +669,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_clock_getrate); */ int zynqmp_pm_clock_setparent(u32 clock_id, u32 parent_id) { - return zynqmp_pm_invoke_fn(PM_CLOCK_SETPARENT, clock_id, - parent_id, 0, 0, NULL); + return zynqmp_pm_invoke_fn(PM_CLOCK_SETPARENT, NULL, 2, clock_id, parent_id); } EXPORT_SYMBOL_GPL(zynqmp_pm_clock_setparent); @@ -684,8 +688,7 @@ int zynqmp_pm_clock_getparent(u32 clock_id, u32 *parent_id) u32 ret_payload[PAYLOAD_ARG_CNT]; int ret; - ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETPARENT, clock_id, 0, - 0, 0, ret_payload); + ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETPARENT, ret_payload, 1, clock_id); *parent_id = ret_payload[1]; return ret; @@ -704,8 +707,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_clock_getparent); */ int zynqmp_pm_set_pll_frac_mode(u32 clk_id, u32 mode) { - return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_SET_PLL_FRAC_MODE, - clk_id, mode, NULL); + return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, 0, IOCTL_SET_PLL_FRAC_MODE, clk_id, mode); } EXPORT_SYMBOL_GPL(zynqmp_pm_set_pll_frac_mode); @@ -721,8 +723,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_set_pll_frac_mode); */ int zynqmp_pm_get_pll_frac_mode(u32 clk_id, u32 *mode) { - return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_GET_PLL_FRAC_MODE, - clk_id, 0, mode); + return zynqmp_pm_invoke_fn(PM_IOCTL, mode, 3, 0, IOCTL_GET_PLL_FRAC_MODE, clk_id); } EXPORT_SYMBOL_GPL(zynqmp_pm_get_pll_frac_mode); @@ -739,8 +740,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_get_pll_frac_mode); */ int zynqmp_pm_set_pll_frac_data(u32 clk_id, u32 data) { - return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_SET_PLL_FRAC_DATA, - clk_id, data, NULL); + return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, 0, IOCTL_SET_PLL_FRAC_DATA, clk_id, data); } EXPORT_SYMBOL_GPL(zynqmp_pm_set_pll_frac_data); @@ -756,8 +756,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_set_pll_frac_data); */ int zynqmp_pm_get_pll_frac_data(u32 clk_id, u32 *data) { - return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_GET_PLL_FRAC_DATA, - clk_id, 0, data); + return zynqmp_pm_invoke_fn(PM_IOCTL, data, 3, 0, IOCTL_GET_PLL_FRAC_DATA, clk_id); } EXPORT_SYMBOL_GPL(zynqmp_pm_get_pll_frac_data); @@ -778,9 +777,8 @@ int zynqmp_pm_set_sd_tapdelay(u32 node_id, u32 type, u32 value) 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); + return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, node_id, IOCTL_SET_SD_TAPDELAY, type, + value); } /* @@ -798,7 +796,7 @@ int zynqmp_pm_set_sd_tapdelay(u32 node_id, u32 type, u32 value) * 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); + return zynqmp_pm_invoke_fn(PM_MMIO_WRITE, NULL, 2, reg, mask); } EXPORT_SYMBOL_GPL(zynqmp_pm_set_sd_tapdelay); @@ -814,8 +812,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_set_sd_tapdelay); */ int zynqmp_pm_sd_dll_reset(u32 node_id, u32 type) { - return zynqmp_pm_invoke_fn(PM_IOCTL, node_id, IOCTL_SD_DLL_RESET, - type, 0, NULL); + return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 3, node_id, IOCTL_SD_DLL_RESET, type); } EXPORT_SYMBOL_GPL(zynqmp_pm_sd_dll_reset); @@ -831,8 +828,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_sd_dll_reset); */ int zynqmp_pm_ospi_mux_select(u32 dev_id, u32 select) { - return zynqmp_pm_invoke_fn(PM_IOCTL, dev_id, IOCTL_OSPI_MUX_SELECT, - select, 0, NULL); + return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 3, dev_id, IOCTL_OSPI_MUX_SELECT, select); } EXPORT_SYMBOL_GPL(zynqmp_pm_ospi_mux_select); @@ -847,8 +843,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_ospi_mux_select); */ int zynqmp_pm_write_ggs(u32 index, u32 value) { - return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_WRITE_GGS, - index, value, NULL); + return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, 0, IOCTL_WRITE_GGS, index, value); } EXPORT_SYMBOL_GPL(zynqmp_pm_write_ggs); @@ -863,8 +858,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_write_ggs); */ int zynqmp_pm_read_ggs(u32 index, u32 *value) { - return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_READ_GGS, - index, 0, value); + return zynqmp_pm_invoke_fn(PM_IOCTL, value, 3, 0, IOCTL_READ_GGS, index); } EXPORT_SYMBOL_GPL(zynqmp_pm_read_ggs); @@ -880,8 +874,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_read_ggs); */ int zynqmp_pm_write_pggs(u32 index, u32 value) { - return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_WRITE_PGGS, index, value, - NULL); + return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, 0, IOCTL_WRITE_PGGS, index, value); } EXPORT_SYMBOL_GPL(zynqmp_pm_write_pggs); @@ -897,15 +890,13 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_write_pggs); */ int zynqmp_pm_read_pggs(u32 index, u32 *value) { - return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_READ_PGGS, index, 0, - value); + return zynqmp_pm_invoke_fn(PM_IOCTL, value, 3, 0, IOCTL_READ_PGGS, index); } EXPORT_SYMBOL_GPL(zynqmp_pm_read_pggs); int zynqmp_pm_set_tapdelay_bypass(u32 index, u32 value) { - return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_SET_TAPDELAY_BYPASS, - index, value, NULL); + return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, 0, IOCTL_SET_TAPDELAY_BYPASS, index, value); } EXPORT_SYMBOL_GPL(zynqmp_pm_set_tapdelay_bypass); @@ -920,8 +911,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_set_tapdelay_bypass); */ int zynqmp_pm_set_boot_health_status(u32 value) { - return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_SET_BOOT_HEALTH_STATUS, - value, 0, NULL); + return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 3, 0, IOCTL_SET_BOOT_HEALTH_STATUS, value); } /** @@ -935,8 +925,7 @@ int zynqmp_pm_set_boot_health_status(u32 value) int zynqmp_pm_reset_assert(const enum zynqmp_pm_reset reset, const enum zynqmp_pm_reset_action assert_flag) { - return zynqmp_pm_invoke_fn(PM_RESET_ASSERT, reset, assert_flag, - 0, 0, NULL); + return zynqmp_pm_invoke_fn(PM_RESET_ASSERT, NULL, 2, reset, assert_flag); } EXPORT_SYMBOL_GPL(zynqmp_pm_reset_assert); @@ -955,8 +944,7 @@ int zynqmp_pm_reset_get_status(const enum zynqmp_pm_reset reset, u32 *status) if (!status) return -EINVAL; - ret = zynqmp_pm_invoke_fn(PM_RESET_GET_STATUS, reset, 0, - 0, 0, ret_payload); + ret = zynqmp_pm_invoke_fn(PM_RESET_GET_STATUS, ret_payload, 1, reset); *status = ret_payload[1]; return ret; @@ -981,9 +969,8 @@ int zynqmp_pm_fpga_load(const u64 address, const u32 size, const u32 flags) u32 ret_payload[PAYLOAD_ARG_CNT]; int ret; - ret = zynqmp_pm_invoke_fn(PM_FPGA_LOAD, lower_32_bits(address), - upper_32_bits(address), size, flags, - ret_payload); + ret = zynqmp_pm_invoke_fn(PM_FPGA_LOAD, ret_payload, 4, lower_32_bits(address), + upper_32_bits(address), size, flags); if (ret_payload[0]) return -ret_payload[0]; @@ -1008,7 +995,7 @@ int zynqmp_pm_fpga_get_status(u32 *value) if (!value) return -EINVAL; - ret = zynqmp_pm_invoke_fn(PM_FPGA_GET_STATUS, 0, 0, 0, 0, ret_payload); + ret = zynqmp_pm_invoke_fn(PM_FPGA_GET_STATUS, ret_payload, 0); *value = ret_payload[1]; return ret; @@ -1036,11 +1023,9 @@ int zynqmp_pm_fpga_get_config_status(u32 *value) lower_addr = lower_32_bits((u64)&buf); upper_addr = upper_32_bits((u64)&buf); - ret = zynqmp_pm_invoke_fn(PM_FPGA_READ, - XILINX_ZYNQMP_PM_FPGA_CONFIG_STAT_OFFSET, - lower_addr, upper_addr, - XILINX_ZYNQMP_PM_FPGA_READ_CONFIG_REG, - ret_payload); + ret = zynqmp_pm_invoke_fn(PM_FPGA_READ, ret_payload, 4, + XILINX_ZYNQMP_PM_FPGA_CONFIG_STAT_OFFSET, lower_addr, upper_addr, + XILINX_ZYNQMP_PM_FPGA_READ_CONFIG_REG); *value = ret_payload[1]; @@ -1058,7 +1043,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_fpga_get_config_status); */ int zynqmp_pm_pinctrl_request(const u32 pin) { - return zynqmp_pm_invoke_fn(PM_PINCTRL_REQUEST, pin, 0, 0, 0, NULL); + return zynqmp_pm_invoke_fn(PM_PINCTRL_REQUEST, NULL, 1, pin); } EXPORT_SYMBOL_GPL(zynqmp_pm_pinctrl_request); @@ -1072,35 +1057,10 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_pinctrl_request); */ int zynqmp_pm_pinctrl_release(const u32 pin) { - return zynqmp_pm_invoke_fn(PM_PINCTRL_RELEASE, pin, 0, 0, 0, NULL); + return zynqmp_pm_invoke_fn(PM_PINCTRL_RELEASE, NULL, 1, pin); } EXPORT_SYMBOL_GPL(zynqmp_pm_pinctrl_release); -/** - * zynqmp_pm_pinctrl_get_function - Read function id set for the given pin - * @pin: Pin number - * @id: Buffer to store function ID - * - * This function provides the function currently set for the given pin. - * - * Return: Returns status, either success or error+reason - */ -int zynqmp_pm_pinctrl_get_function(const u32 pin, u32 *id) -{ - u32 ret_payload[PAYLOAD_ARG_CNT]; - int ret; - - if (!id) - return -EINVAL; - - ret = zynqmp_pm_invoke_fn(PM_PINCTRL_GET_FUNCTION, pin, 0, - 0, 0, ret_payload); - *id = ret_payload[1]; - - return ret; -} -EXPORT_SYMBOL_GPL(zynqmp_pm_pinctrl_get_function); - /** * zynqmp_pm_pinctrl_set_function - Set requested function for the pin * @pin: Pin number @@ -1112,8 +1072,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_pinctrl_get_function); */ int zynqmp_pm_pinctrl_set_function(const u32 pin, const u32 id) { - return zynqmp_pm_invoke_fn(PM_PINCTRL_SET_FUNCTION, pin, id, - 0, 0, NULL); + return zynqmp_pm_invoke_fn(PM_PINCTRL_SET_FUNCTION, NULL, 2, pin, id); } EXPORT_SYMBOL_GPL(zynqmp_pm_pinctrl_set_function); @@ -1136,8 +1095,7 @@ int zynqmp_pm_pinctrl_get_config(const u32 pin, const u32 param, if (!value) return -EINVAL; - ret = zynqmp_pm_invoke_fn(PM_PINCTRL_CONFIG_PARAM_GET, pin, param, - 0, 0, ret_payload); + ret = zynqmp_pm_invoke_fn(PM_PINCTRL_CONFIG_PARAM_GET, ret_payload, 2, pin, param); *value = ret_payload[1]; return ret; @@ -1166,8 +1124,7 @@ int zynqmp_pm_pinctrl_set_config(const u32 pin, const u32 param, return -EOPNOTSUPP; } - return zynqmp_pm_invoke_fn(PM_PINCTRL_CONFIG_PARAM_SET, pin, - param, value, 0, NULL); + return zynqmp_pm_invoke_fn(PM_PINCTRL_CONFIG_PARAM_SET, NULL, 3, pin, param, value); } EXPORT_SYMBOL_GPL(zynqmp_pm_pinctrl_set_config); @@ -1185,8 +1142,7 @@ unsigned int zynqmp_pm_bootmode_read(u32 *ps_mode) unsigned int ret; u32 ret_payload[PAYLOAD_ARG_CNT]; - ret = zynqmp_pm_invoke_fn(PM_MMIO_READ, CRL_APB_BOOT_PIN_CTRL, 0, - 0, 0, ret_payload); + ret = zynqmp_pm_invoke_fn(PM_MMIO_READ, ret_payload, 1, CRL_APB_BOOT_PIN_CTRL); *ps_mode = ret_payload[1]; @@ -1205,8 +1161,8 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_bootmode_read); */ int zynqmp_pm_bootmode_write(u32 ps_mode) { - return zynqmp_pm_invoke_fn(PM_MMIO_WRITE, CRL_APB_BOOT_PIN_CTRL, - CRL_APB_BOOTPIN_CTRL_MASK, ps_mode, 0, NULL); + return zynqmp_pm_invoke_fn(PM_MMIO_WRITE, NULL, 3, CRL_APB_BOOT_PIN_CTRL, + CRL_APB_BOOTPIN_CTRL_MASK, ps_mode); } EXPORT_SYMBOL_GPL(zynqmp_pm_bootmode_write); @@ -1221,7 +1177,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_bootmode_write); */ int zynqmp_pm_init_finalize(void) { - return zynqmp_pm_invoke_fn(PM_PM_INIT_FINALIZE, 0, 0, 0, 0, NULL); + return zynqmp_pm_invoke_fn(PM_PM_INIT_FINALIZE, NULL, 0); } EXPORT_SYMBOL_GPL(zynqmp_pm_init_finalize); @@ -1235,7 +1191,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_init_finalize); */ int zynqmp_pm_set_suspend_mode(u32 mode) { - return zynqmp_pm_invoke_fn(PM_SET_SUSPEND_MODE, mode, 0, 0, 0, NULL); + return zynqmp_pm_invoke_fn(PM_SET_SUSPEND_MODE, NULL, 1, mode); } EXPORT_SYMBOL_GPL(zynqmp_pm_set_suspend_mode); @@ -1254,8 +1210,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_set_suspend_mode); int zynqmp_pm_request_node(const u32 node, const u32 capabilities, const u32 qos, const enum zynqmp_pm_request_ack ack) { - return zynqmp_pm_invoke_fn(PM_REQUEST_NODE, node, capabilities, - qos, ack, NULL); + return zynqmp_pm_invoke_fn(PM_REQUEST_NODE, NULL, 4, node, capabilities, qos, ack); } EXPORT_SYMBOL_GPL(zynqmp_pm_request_node); @@ -1271,7 +1226,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_request_node); */ int zynqmp_pm_release_node(const u32 node) { - return zynqmp_pm_invoke_fn(PM_RELEASE_NODE, node, 0, 0, 0, NULL); + return zynqmp_pm_invoke_fn(PM_RELEASE_NODE, NULL, 1, node); } EXPORT_SYMBOL_GPL(zynqmp_pm_release_node); @@ -1290,8 +1245,7 @@ int zynqmp_pm_get_rpu_mode(u32 node_id, enum rpu_oper_mode *rpu_mode) u32 ret_payload[PAYLOAD_ARG_CNT]; int ret; - ret = zynqmp_pm_invoke_fn(PM_IOCTL, node_id, - IOCTL_GET_RPU_OPER_MODE, 0, 0, ret_payload); + ret = zynqmp_pm_invoke_fn(PM_IOCTL, ret_payload, 2, node_id, IOCTL_GET_RPU_OPER_MODE); /* only set rpu_mode if no error */ if (ret == XST_PM_SUCCESS) @@ -1313,9 +1267,8 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_get_rpu_mode); */ int zynqmp_pm_set_rpu_mode(u32 node_id, enum rpu_oper_mode rpu_mode) { - return zynqmp_pm_invoke_fn(PM_IOCTL, node_id, - IOCTL_SET_RPU_OPER_MODE, (u32)rpu_mode, - 0, NULL); + return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 3, node_id, IOCTL_SET_RPU_OPER_MODE, + (u32)rpu_mode); } EXPORT_SYMBOL_GPL(zynqmp_pm_set_rpu_mode); @@ -1331,9 +1284,8 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_set_rpu_mode); */ int zynqmp_pm_set_tcm_config(u32 node_id, enum rpu_tcm_comb tcm_mode) { - return zynqmp_pm_invoke_fn(PM_IOCTL, node_id, - IOCTL_TCM_COMB_CONFIG, (u32)tcm_mode, 0, - NULL); + return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 3, node_id, IOCTL_TCM_COMB_CONFIG, + (u32)tcm_mode); } EXPORT_SYMBOL_GPL(zynqmp_pm_set_tcm_config); @@ -1348,7 +1300,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_set_tcm_config); int zynqmp_pm_force_pwrdwn(const u32 node, const enum zynqmp_pm_request_ack ack) { - return zynqmp_pm_invoke_fn(PM_FORCE_POWERDOWN, node, ack, 0, 0, NULL); + return zynqmp_pm_invoke_fn(PM_FORCE_POWERDOWN, NULL, 2, node, ack); } EXPORT_SYMBOL_GPL(zynqmp_pm_force_pwrdwn); @@ -1367,8 +1319,8 @@ int zynqmp_pm_request_wake(const u32 node, const enum zynqmp_pm_request_ack ack) { /* set_addr flag is encoded into 1st bit of address */ - return zynqmp_pm_invoke_fn(PM_REQUEST_WAKEUP, node, address | set_addr, - address >> 32, ack, NULL); + return zynqmp_pm_invoke_fn(PM_REQUEST_WAKEUP, NULL, 4, node, address | set_addr, + address >> 32, ack); } EXPORT_SYMBOL_GPL(zynqmp_pm_request_wake); @@ -1388,15 +1340,14 @@ int zynqmp_pm_set_requirement(const u32 node, const u32 capabilities, const u32 qos, const enum zynqmp_pm_request_ack ack) { - return zynqmp_pm_invoke_fn(PM_SET_REQUIREMENT, node, capabilities, - qos, ack, NULL); + return zynqmp_pm_invoke_fn(PM_SET_REQUIREMENT, NULL, 4, node, capabilities, qos, ack); } EXPORT_SYMBOL_GPL(zynqmp_pm_set_requirement); /** * zynqmp_pm_load_pdi - Load and process PDI - * @src: Source device where PDI is located - * @address: PDI src address + * @src: Source device where PDI is located + * @address: PDI src address * * This function provides support to load PDI from linux * @@ -1404,9 +1355,8 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_set_requirement); */ int zynqmp_pm_load_pdi(const u32 src, const u64 address) { - return zynqmp_pm_invoke_fn(PM_LOAD_PDI, src, - lower_32_bits(address), - upper_32_bits(address), 0, NULL); + return zynqmp_pm_invoke_fn(PM_LOAD_PDI, NULL, 3, src, lower_32_bits(address), + upper_32_bits(address)); } EXPORT_SYMBOL_GPL(zynqmp_pm_load_pdi); @@ -1426,9 +1376,8 @@ int zynqmp_pm_aes_engine(const u64 address, u32 *out) if (!out) return -EINVAL; - ret = zynqmp_pm_invoke_fn(PM_SECURE_AES, upper_32_bits(address), - lower_32_bits(address), - 0, 0, ret_payload); + ret = zynqmp_pm_invoke_fn(PM_SECURE_AES, ret_payload, 2, upper_32_bits(address), + lower_32_bits(address)); *out = ret_payload[1]; return ret; @@ -1456,8 +1405,7 @@ int zynqmp_pm_sha_hash(const u64 address, const u32 size, const u32 flags) u32 lower_addr = lower_32_bits(address); u32 upper_addr = upper_32_bits(address); - return zynqmp_pm_invoke_fn(PM_SECURE_SHA, upper_addr, lower_addr, - size, flags, NULL); + return zynqmp_pm_invoke_fn(PM_SECURE_SHA, NULL, 4, upper_addr, lower_addr, size, flags); } EXPORT_SYMBOL_GPL(zynqmp_pm_sha_hash); @@ -1479,8 +1427,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_sha_hash); int zynqmp_pm_register_notifier(const u32 node, const u32 event, const u32 wake, const u32 enable) { - return zynqmp_pm_invoke_fn(PM_REGISTER_NOTIFIER, node, event, - wake, enable, NULL); + return zynqmp_pm_invoke_fn(PM_REGISTER_NOTIFIER, NULL, 4, node, event, wake, enable); } EXPORT_SYMBOL_GPL(zynqmp_pm_register_notifier); @@ -1493,8 +1440,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_register_notifier); */ int zynqmp_pm_system_shutdown(const u32 type, const u32 subtype) { - return zynqmp_pm_invoke_fn(PM_SYSTEM_SHUTDOWN, type, subtype, - 0, 0, NULL); + return zynqmp_pm_invoke_fn(PM_SYSTEM_SHUTDOWN, NULL, 2, type, subtype); } /** @@ -1506,8 +1452,7 @@ int zynqmp_pm_system_shutdown(const u32 type, const u32 subtype) */ int zynqmp_pm_set_feature_config(enum pm_feature_config_id id, u32 value) { - return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_SET_FEATURE_CONFIG, - id, value, NULL); + return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, 0, IOCTL_SET_FEATURE_CONFIG, id, value); } /** @@ -1520,8 +1465,7 @@ int zynqmp_pm_set_feature_config(enum pm_feature_config_id id, u32 value) int zynqmp_pm_get_feature_config(enum pm_feature_config_id id, u32 *payload) { - return zynqmp_pm_invoke_fn(PM_IOCTL, 0, IOCTL_GET_FEATURE_CONFIG, - id, 0, payload); + return zynqmp_pm_invoke_fn(PM_IOCTL, payload, 3, 0, IOCTL_GET_FEATURE_CONFIG, id); } /** @@ -1534,8 +1478,7 @@ int zynqmp_pm_get_feature_config(enum pm_feature_config_id id, */ int zynqmp_pm_set_sd_config(u32 node, enum pm_sd_config_type config, u32 value) { - return zynqmp_pm_invoke_fn(PM_IOCTL, node, IOCTL_SET_SD_CONFIG, - config, value, NULL); + return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, node, IOCTL_SET_SD_CONFIG, config, value); } EXPORT_SYMBOL_GPL(zynqmp_pm_set_sd_config); @@ -1550,8 +1493,7 @@ EXPORT_SYMBOL_GPL(zynqmp_pm_set_sd_config); int zynqmp_pm_set_gem_config(u32 node, enum pm_gem_config_type config, u32 value) { - return zynqmp_pm_invoke_fn(PM_IOCTL, node, IOCTL_SET_GEM_CONFIG, - config, value, NULL); + return zynqmp_pm_invoke_fn(PM_IOCTL, NULL, 4, node, IOCTL_SET_GEM_CONFIG, config, value); } EXPORT_SYMBOL_GPL(zynqmp_pm_set_gem_config); @@ -1916,7 +1858,6 @@ ATTRIBUTE_GROUPS(zynqmp_firmware); static int zynqmp_firmware_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *np; struct zynqmp_devinfo *devinfo; int ret; @@ -1924,22 +1865,9 @@ static int zynqmp_firmware_probe(struct platform_device *pdev) if (ret) return ret; - np = of_find_compatible_node(NULL, NULL, "xlnx,zynqmp"); - if (!np) { - np = of_find_compatible_node(NULL, NULL, "xlnx,versal"); - if (!np) - return 0; - + ret = do_feature_check_call(PM_FEATURE_CHECK); + if (ret >= 0 && ((ret & FIRMWARE_VERSION_MASK) >= PM_API_VERSION_1)) feature_check_enabled = true; - } - - if (!feature_check_enabled) { - ret = do_feature_check_call(PM_FEATURE_CHECK); - if (ret >= 0) - feature_check_enabled = true; - } - - of_node_put(np); devinfo = devm_kzalloc(dev, sizeof(*devinfo), GFP_KERNEL); if (!devinfo) @@ -1992,19 +1920,17 @@ static int zynqmp_firmware_probe(struct platform_device *pdev) zynqmp_pm_api_debugfs_init(); - np = of_find_compatible_node(NULL, NULL, "xlnx,versal"); - if (np) { + if (pm_family_code == VERSAL_FAMILY_CODE) { em_dev = platform_device_register_data(&pdev->dev, "xlnx_event_manager", -1, NULL, 0); if (IS_ERR(em_dev)) dev_err_probe(&pdev->dev, PTR_ERR(em_dev), "EM register fail with error\n"); } - of_node_put(np); return of_platform_populate(dev->of_node, NULL, NULL, dev); } -static int zynqmp_firmware_remove(struct platform_device *pdev) +static void zynqmp_firmware_remove(struct platform_device *pdev) { struct pm_api_feature_data *feature_data; struct hlist_node *tmp; @@ -2019,8 +1945,6 @@ static int zynqmp_firmware_remove(struct platform_device *pdev) } platform_device_unregister(em_dev); - - return 0; } static const struct of_device_id zynqmp_firmware_of_match[] = { @@ -2037,6 +1961,6 @@ static struct platform_driver zynqmp_firmware_driver = { .dev_groups = zynqmp_firmware_groups, }, .probe = zynqmp_firmware_probe, - .remove = zynqmp_firmware_remove, + .remove_new = zynqmp_firmware_remove, }; module_platform_driver(zynqmp_firmware_driver); diff --git a/drivers/fpga/altera-fpga2sdram.c b/drivers/fpga/altera-fpga2sdram.c index 1fa2ccc321abfc..6b60ca004345de 100644 --- a/drivers/fpga/altera-fpga2sdram.c +++ b/drivers/fpga/altera-fpga2sdram.c @@ -147,20 +147,18 @@ static int alt_fpga_bridge_probe(struct platform_device *pdev) return ret; } -static int alt_fpga_bridge_remove(struct platform_device *pdev) +static void alt_fpga_bridge_remove(struct platform_device *pdev) { struct fpga_bridge *br = platform_get_drvdata(pdev); fpga_bridge_unregister(br); - - return 0; } MODULE_DEVICE_TABLE(of, altera_fpga_of_match); static struct platform_driver altera_fpga_driver = { .probe = alt_fpga_bridge_probe, - .remove = alt_fpga_bridge_remove, + .remove_new = alt_fpga_bridge_remove, .driver = { .name = "altera_fpga2sdram_bridge", .of_match_table = of_match_ptr(altera_fpga_of_match), diff --git a/drivers/fpga/altera-freeze-bridge.c b/drivers/fpga/altera-freeze-bridge.c index 0c3fb822690890..44061cb16f8770 100644 --- a/drivers/fpga/altera-freeze-bridge.c +++ b/drivers/fpga/altera-freeze-bridge.c @@ -253,18 +253,16 @@ static int altera_freeze_br_probe(struct platform_device *pdev) return 0; } -static int altera_freeze_br_remove(struct platform_device *pdev) +static void altera_freeze_br_remove(struct platform_device *pdev) { struct fpga_bridge *br = platform_get_drvdata(pdev); fpga_bridge_unregister(br); - - return 0; } static struct platform_driver altera_freeze_br_driver = { .probe = altera_freeze_br_probe, - .remove = altera_freeze_br_remove, + .remove_new = altera_freeze_br_remove, .driver = { .name = "altera_freeze_br", .of_match_table = altera_freeze_br_of_match, diff --git a/drivers/fpga/altera-hps2fpga.c b/drivers/fpga/altera-hps2fpga.c index 5786635032972b..6f8e24be19c6df 100644 --- a/drivers/fpga/altera-hps2fpga.c +++ b/drivers/fpga/altera-hps2fpga.c @@ -191,7 +191,7 @@ err: return ret; } -static int alt_fpga_bridge_remove(struct platform_device *pdev) +static void alt_fpga_bridge_remove(struct platform_device *pdev) { struct fpga_bridge *bridge = platform_get_drvdata(pdev); struct altera_hps2fpga_data *priv = bridge->priv; @@ -199,15 +199,13 @@ static int alt_fpga_bridge_remove(struct platform_device *pdev) fpga_bridge_unregister(bridge); clk_disable_unprepare(priv->clk); - - return 0; } MODULE_DEVICE_TABLE(of, altera_fpga_of_match); static struct platform_driver alt_fpga_bridge_driver = { .probe = alt_fpga_bridge_probe, - .remove = alt_fpga_bridge_remove, + .remove_new = alt_fpga_bridge_remove, .driver = { .name = "altera_hps2fpga_bridge", .of_match_table = of_match_ptr(altera_fpga_of_match), diff --git a/drivers/fpga/dfl-afu-main.c b/drivers/fpga/dfl-afu-main.c index 7f621e96d3b8d8..c0a75ca360d697 100644 --- a/drivers/fpga/dfl-afu-main.c +++ b/drivers/fpga/dfl-afu-main.c @@ -932,15 +932,13 @@ exit: return ret; } -static int afu_remove(struct platform_device *pdev) +static void afu_remove(struct platform_device *pdev) { dev_dbg(&pdev->dev, "%s\n", __func__); dfl_fpga_dev_ops_unregister(pdev); dfl_fpga_dev_feature_uinit(pdev); afu_dev_destroy(pdev); - - return 0; } static const struct attribute_group *afu_dev_groups[] = { @@ -956,7 +954,7 @@ static struct platform_driver afu_driver = { .dev_groups = afu_dev_groups, }, .probe = afu_probe, - .remove = afu_remove, + .remove_new = afu_remove, }; static int __init afu_init(void) diff --git a/drivers/fpga/dfl-fme-br.c b/drivers/fpga/dfl-fme-br.c index 808d1f4d76df8f..0b01b389527760 100644 --- a/drivers/fpga/dfl-fme-br.c +++ b/drivers/fpga/dfl-fme-br.c @@ -78,7 +78,7 @@ static int fme_br_probe(struct platform_device *pdev) return 0; } -static int fme_br_remove(struct platform_device *pdev) +static void fme_br_remove(struct platform_device *pdev) { struct fpga_bridge *br = platform_get_drvdata(pdev); struct fme_br_priv *priv = br->priv; @@ -89,8 +89,6 @@ static int fme_br_remove(struct platform_device *pdev) put_device(&priv->port_pdev->dev); if (priv->port_ops) dfl_fpga_port_ops_put(priv->port_ops); - - return 0; } static struct platform_driver fme_br_driver = { @@ -98,7 +96,7 @@ static struct platform_driver fme_br_driver = { .name = DFL_FPGA_FME_BRIDGE, }, .probe = fme_br_probe, - .remove = fme_br_remove, + .remove_new = fme_br_remove, }; module_platform_driver(fme_br_driver); diff --git a/drivers/fpga/dfl-fme-main.c b/drivers/fpga/dfl-fme-main.c index 3dcf990bd261f8..a2b5da0093dac7 100644 --- a/drivers/fpga/dfl-fme-main.c +++ b/drivers/fpga/dfl-fme-main.c @@ -730,13 +730,11 @@ exit: return ret; } -static int fme_remove(struct platform_device *pdev) +static void fme_remove(struct platform_device *pdev) { dfl_fpga_dev_ops_unregister(pdev); dfl_fpga_dev_feature_uinit(pdev); fme_dev_destroy(pdev); - - return 0; } static const struct attribute_group *fme_dev_groups[] = { @@ -751,7 +749,7 @@ static struct platform_driver fme_driver = { .dev_groups = fme_dev_groups, }, .probe = fme_probe, - .remove = fme_remove, + .remove_new = fme_remove, }; module_platform_driver(fme_driver); diff --git a/drivers/fpga/dfl-fme-region.c b/drivers/fpga/dfl-fme-region.c index 4aebde0a7f1c35..71616f8b4982de 100644 --- a/drivers/fpga/dfl-fme-region.c +++ b/drivers/fpga/dfl-fme-region.c @@ -61,15 +61,13 @@ eprobe_mgr_put: return ret; } -static int fme_region_remove(struct platform_device *pdev) +static void fme_region_remove(struct platform_device *pdev) { struct fpga_region *region = platform_get_drvdata(pdev); struct fpga_manager *mgr = region->mgr; fpga_region_unregister(region); fpga_mgr_put(mgr); - - return 0; } static struct platform_driver fme_region_driver = { @@ -77,7 +75,7 @@ static struct platform_driver fme_region_driver = { .name = DFL_FPGA_FME_REGION, }, .probe = fme_region_probe, - .remove = fme_region_remove, + .remove_new = fme_region_remove, }; module_platform_driver(fme_region_driver); diff --git a/drivers/fpga/dfl.c b/drivers/fpga/dfl.c index dd7a783d53b5f4..e6d12fbab653fb 100644 --- a/drivers/fpga/dfl.c +++ b/drivers/fpga/dfl.c @@ -1872,7 +1872,7 @@ static irqreturn_t dfl_irq_handler(int irq, void *arg) { struct eventfd_ctx *trigger = arg; - eventfd_signal(trigger, 1); + eventfd_signal(trigger); return IRQ_HANDLED; } @@ -2008,8 +2008,8 @@ long dfl_feature_ioctl_set_irq(struct platform_device *pdev, (hdr.start + hdr.count < hdr.start)) return -EINVAL; - fds = memdup_user((void __user *)(arg + sizeof(hdr)), - array_size(hdr.count, sizeof(s32))); + fds = memdup_array_user((void __user *)(arg + sizeof(hdr)), + hdr.count, sizeof(s32)); if (IS_ERR(fds)) return PTR_ERR(fds); diff --git a/drivers/fpga/intel-m10-bmc-sec-update.c b/drivers/fpga/intel-m10-bmc-sec-update.c index 31af2e08c825fa..89851b1337097c 100644 --- a/drivers/fpga/intel-m10-bmc-sec-update.c +++ b/drivers/fpga/intel-m10-bmc-sec-update.c @@ -730,15 +730,13 @@ fw_name_fail: return ret; } -static int m10bmc_sec_remove(struct platform_device *pdev) +static void m10bmc_sec_remove(struct platform_device *pdev) { struct m10bmc_sec *sec = dev_get_drvdata(&pdev->dev); firmware_upload_unregister(sec->fwl); kfree(sec->fw_name); xa_erase(&fw_upload_xa, sec->fw_name_id); - - return 0; } static const struct platform_device_id intel_m10bmc_sec_ids[] = { @@ -760,7 +758,7 @@ MODULE_DEVICE_TABLE(platform, intel_m10bmc_sec_ids); static struct platform_driver intel_m10bmc_sec_driver = { .probe = m10bmc_sec_probe, - .remove = m10bmc_sec_remove, + .remove_new = m10bmc_sec_remove, .driver = { .name = "intel-m10bmc-sec-update", .dev_groups = m10bmc_sec_attr_groups, diff --git a/drivers/fpga/of-fpga-region.c b/drivers/fpga/of-fpga-region.c index a6affd83f27578..8526a5a86f0cbe 100644 --- a/drivers/fpga/of-fpga-region.c +++ b/drivers/fpga/of-fpga-region.c @@ -425,20 +425,18 @@ eprobe_mgr_put: return ret; } -static int of_fpga_region_remove(struct platform_device *pdev) +static void of_fpga_region_remove(struct platform_device *pdev) { struct fpga_region *region = platform_get_drvdata(pdev); struct fpga_manager *mgr = region->mgr; fpga_region_unregister(region); fpga_mgr_put(mgr); - - return 0; } static struct platform_driver of_fpga_region_driver = { .probe = of_fpga_region_probe, - .remove = of_fpga_region_remove, + .remove_new = of_fpga_region_remove, .driver = { .name = "of-fpga-region", .of_match_table = of_match_ptr(fpga_region_of_match), diff --git a/drivers/fpga/socfpga-a10.c b/drivers/fpga/socfpga-a10.c index cc4861e345c935..4c03513b8f03b5 100644 --- a/drivers/fpga/socfpga-a10.c +++ b/drivers/fpga/socfpga-a10.c @@ -517,15 +517,13 @@ static int socfpga_a10_fpga_probe(struct platform_device *pdev) return 0; } -static int socfpga_a10_fpga_remove(struct platform_device *pdev) +static void socfpga_a10_fpga_remove(struct platform_device *pdev) { struct fpga_manager *mgr = platform_get_drvdata(pdev); struct a10_fpga_priv *priv = mgr->priv; fpga_mgr_unregister(mgr); clk_disable_unprepare(priv->clk); - - return 0; } static const struct of_device_id socfpga_a10_fpga_of_match[] = { @@ -537,7 +535,7 @@ MODULE_DEVICE_TABLE(of, socfpga_a10_fpga_of_match); static struct platform_driver socfpga_a10_fpga_driver = { .probe = socfpga_a10_fpga_probe, - .remove = socfpga_a10_fpga_remove, + .remove_new = socfpga_a10_fpga_remove, .driver = { .name = "socfpga_a10_fpga_manager", .of_match_table = socfpga_a10_fpga_of_match, diff --git a/drivers/fpga/stratix10-soc.c b/drivers/fpga/stratix10-soc.c index cacb9cc5757e78..2c0def7d7cbb16 100644 --- a/drivers/fpga/stratix10-soc.c +++ b/drivers/fpga/stratix10-soc.c @@ -436,15 +436,13 @@ probe_err: return ret; } -static int s10_remove(struct platform_device *pdev) +static void s10_remove(struct platform_device *pdev) { struct fpga_manager *mgr = platform_get_drvdata(pdev); struct s10_priv *priv = mgr->priv; fpga_mgr_unregister(mgr); stratix10_svc_free_channel(priv->chan); - - return 0; } static const struct of_device_id s10_of_match[] = { @@ -457,7 +455,7 @@ MODULE_DEVICE_TABLE(of, s10_of_match); static struct platform_driver s10_driver = { .probe = s10_probe, - .remove = s10_remove, + .remove_new = s10_remove, .driver = { .name = "Stratix10 SoC FPGA manager", .of_match_table = of_match_ptr(s10_of_match), diff --git a/drivers/fpga/xilinx-pr-decoupler.c b/drivers/fpga/xilinx-pr-decoupler.c index 68835896f180ea..788dd2f63a652e 100644 --- a/drivers/fpga/xilinx-pr-decoupler.c +++ b/drivers/fpga/xilinx-pr-decoupler.c @@ -150,7 +150,7 @@ err_clk: return err; } -static int xlnx_pr_decoupler_remove(struct platform_device *pdev) +static void xlnx_pr_decoupler_remove(struct platform_device *pdev) { struct fpga_bridge *bridge = platform_get_drvdata(pdev); struct xlnx_pr_decoupler_data *p = bridge->priv; @@ -158,13 +158,11 @@ static int xlnx_pr_decoupler_remove(struct platform_device *pdev) fpga_bridge_unregister(bridge); clk_unprepare(p->clk); - - return 0; } static struct platform_driver xlnx_pr_decoupler_driver = { .probe = xlnx_pr_decoupler_probe, - .remove = xlnx_pr_decoupler_remove, + .remove_new = xlnx_pr_decoupler_remove, .driver = { .name = "xlnx_pr_decoupler", .of_match_table = xlnx_pr_decoupler_of_match, diff --git a/drivers/fpga/zynq-fpga.c b/drivers/fpga/zynq-fpga.c index 96611d424a104e..0ac93183d20165 100644 --- a/drivers/fpga/zynq-fpga.c +++ b/drivers/fpga/zynq-fpga.c @@ -618,7 +618,7 @@ static int zynq_fpga_probe(struct platform_device *pdev) return 0; } -static int zynq_fpga_remove(struct platform_device *pdev) +static void zynq_fpga_remove(struct platform_device *pdev) { struct zynq_fpga_priv *priv; struct fpga_manager *mgr; @@ -629,8 +629,6 @@ static int zynq_fpga_remove(struct platform_device *pdev) fpga_mgr_unregister(mgr); clk_unprepare(priv->clk); - - return 0; } #ifdef CONFIG_OF @@ -644,7 +642,7 @@ MODULE_DEVICE_TABLE(of, zynq_fpga_of_match); static struct platform_driver zynq_fpga_driver = { .probe = zynq_fpga_probe, - .remove = zynq_fpga_remove, + .remove_new = zynq_fpga_remove, .driver = { .name = "zynq_fpga_manager", .of_match_table = of_match_ptr(zynq_fpga_of_match), diff --git a/drivers/gnss/serial.c b/drivers/gnss/serial.c index 5d8e9bfb24d020..baa956494e79f0 100644 --- a/drivers/gnss/serial.c +++ b/drivers/gnss/serial.c @@ -80,8 +80,8 @@ static const struct gnss_operations gnss_serial_gnss_ops = { .write_raw = gnss_serial_write_raw, }; -static int gnss_serial_receive_buf(struct serdev_device *serdev, - const unsigned char *buf, size_t count) +static ssize_t gnss_serial_receive_buf(struct serdev_device *serdev, + const u8 *buf, size_t count) { struct gnss_serial *gserial = serdev_device_get_drvdata(serdev); struct gnss_device *gdev = gserial->gdev; diff --git a/drivers/gnss/sirf.c b/drivers/gnss/sirf.c index bcb53ccfee4d55..6801a8fb20401a 100644 --- a/drivers/gnss/sirf.c +++ b/drivers/gnss/sirf.c @@ -160,8 +160,8 @@ static const struct gnss_operations sirf_gnss_ops = { .write_raw = sirf_write_raw, }; -static int sirf_receive_buf(struct serdev_device *serdev, - const unsigned char *buf, size_t count) +static ssize_t sirf_receive_buf(struct serdev_device *serdev, + const u8 *buf, size_t count) { struct sirf_data *data = serdev_device_get_drvdata(serdev); struct gnss_device *gdev = data->gdev; diff --git a/drivers/gnss/ubx.c b/drivers/gnss/ubx.c index c951be202ca25a..92402f6082c415 100644 --- a/drivers/gnss/ubx.c +++ b/drivers/gnss/ubx.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -17,7 +18,6 @@ #include "serial.h" struct ubx_data { - struct regulator *v_bckp; struct regulator *vcc; }; @@ -66,6 +66,7 @@ static const struct gnss_serial_ops ubx_gserial_ops = { static int ubx_probe(struct serdev_device *serdev) { struct gnss_serial *gserial; + struct gpio_desc *reset; struct ubx_data *data; int ret; @@ -87,30 +88,23 @@ static int ubx_probe(struct serdev_device *serdev) goto err_free_gserial; } - data->v_bckp = devm_regulator_get_optional(&serdev->dev, "v-bckp"); - if (IS_ERR(data->v_bckp)) { - ret = PTR_ERR(data->v_bckp); - if (ret == -ENODEV) - data->v_bckp = NULL; - else - goto err_free_gserial; - } + ret = devm_regulator_get_enable_optional(&serdev->dev, "v-bckp"); + if (ret < 0 && ret != -ENODEV) + goto err_free_gserial; - if (data->v_bckp) { - ret = regulator_enable(data->v_bckp); - if (ret) - goto err_free_gserial; + /* Deassert reset */ + reset = devm_gpiod_get_optional(&serdev->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(reset)) { + ret = PTR_ERR(reset); + goto err_free_gserial; } ret = gnss_serial_register(gserial); if (ret) - goto err_disable_v_bckp; + goto err_free_gserial; return 0; -err_disable_v_bckp: - if (data->v_bckp) - regulator_disable(data->v_bckp); err_free_gserial: gnss_serial_free(gserial); @@ -120,11 +114,8 @@ err_free_gserial: static void ubx_remove(struct serdev_device *serdev) { struct gnss_serial *gserial = serdev_device_get_drvdata(serdev); - struct ubx_data *data = gnss_serial_get_drvdata(gserial); gnss_serial_deregister(gserial); - if (data->v_bckp) - regulator_disable(data->v_bckp); gnss_serial_free(gserial); } diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index b3a133ed31ee58..1301cec94f128a 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -478,6 +478,13 @@ config GPIO_MXS select GPIO_GENERIC select GENERIC_IRQ_CHIP +config GPIO_NPCM_SGPIO + bool "Nuvoton SGPIO support" + depends on ARCH_NPCM || COMPILE_TEST + select GPIOLIB_IRQCHIP + help + Say Y here to support Nuvoton NPCM7XX/NPCM8XX SGPIO functionality. + config GPIO_OCTEON tristate "Cavium OCTEON GPIO" depends on CAVIUM_OCTEON_SOC @@ -553,6 +560,19 @@ config GPIO_ROCKCHIP help Say yes here to support GPIO on Rockchip SoCs. +config GPIO_RTD + tristate "Realtek DHC GPIO support" + depends on ARCH_REALTEK + default y + select GPIOLIB_IRQCHIP + help + This option enables support for GPIOs found on Realtek DHC(Digital + Home Center) SoCs family, including RTD1295, RTD1315E, RTD1319, + RTD1319D, RTD1395, RTD1619 and RTD1619B. + + Say yes here to support GPIO functionality and GPIO interrupt on + Realtek DHC SoCs. + config GPIO_SAMA5D2_PIOBU tristate "SAMA5D2 PIOBU GPIO support" depends on MFD_SYSCON diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index eb73b5d633ebad..9e40af196aae67 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -116,6 +116,7 @@ obj-$(CONFIG_GPIO_MT7621) += gpio-mt7621.o obj-$(CONFIG_GPIO_MVEBU) += gpio-mvebu.o obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o obj-$(CONFIG_GPIO_MXS) += gpio-mxs.o +obj-$(CONFIG_GPIO_NPCM_SGPIO) += gpio-npcm-sgpio.o obj-$(CONFIG_GPIO_OCTEON) += gpio-octeon.o obj-$(CONFIG_GPIO_OMAP) += gpio-omap.o obj-$(CONFIG_GPIO_PALMAS) += gpio-palmas.o @@ -137,6 +138,7 @@ obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o obj-$(CONFIG_GPIO_REALTEK_OTTO) += gpio-realtek-otto.o obj-$(CONFIG_GPIO_REG) += gpio-reg.o obj-$(CONFIG_GPIO_ROCKCHIP) += gpio-rockchip.o +obj-$(CONFIG_GPIO_RTD) += gpio-rtd.o obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o obj-$(CONFIG_GPIO_SAMA5D2_PIOBU) += gpio-sama5d2-piobu.o obj-$(CONFIG_GPIO_SCH311X) += gpio-sch311x.o diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index 8c59332429c260..798235791f701f 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -416,11 +416,12 @@ static int dwapb_gpio_set_config(struct gpio_chip *gc, unsigned offset, { u32 debounce; - if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE) - return -ENOTSUPP; + if (pinconf_to_config_param(config) == PIN_CONFIG_INPUT_DEBOUNCE) { + debounce = pinconf_to_config_argument(config); + return dwapb_gpio_set_debounce(gc, offset, debounce); + } - debounce = pinconf_to_config_argument(config); - return dwapb_gpio_set_debounce(gc, offset, debounce); + return gpiochip_generic_config(gc, offset, config); } static int dwapb_convert_irqs(struct dwapb_gpio_port_irqchip *pirq, @@ -530,10 +531,14 @@ static int dwapb_gpio_add_port(struct dwapb_gpio *gpio, port->gc.fwnode = pp->fwnode; port->gc.ngpio = pp->ngpio; port->gc.base = pp->gpio_base; + port->gc.request = gpiochip_generic_request; + port->gc.free = gpiochip_generic_free; /* Only port A support debounce */ if (pp->idx == 0) port->gc.set_config = dwapb_gpio_set_config; + else + port->gc.set_config = gpiochip_generic_config; /* Only port A can provide interrupts in all configurations of the IP */ if (pp->idx == 0) diff --git a/drivers/gpio/gpio-eic-sprd.c b/drivers/gpio/gpio-eic-sprd.c index be7f2fa5aa7b60..806b88d8dfb7bd 100644 --- a/drivers/gpio/gpio-eic-sprd.c +++ b/drivers/gpio/gpio-eic-sprd.c @@ -330,20 +330,27 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type) switch (flow_type) { case IRQ_TYPE_LEVEL_HIGH: sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 1); + sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IC, 1); break; case IRQ_TYPE_LEVEL_LOW: sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 0); + sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IC, 1); break; case IRQ_TYPE_EDGE_RISING: case IRQ_TYPE_EDGE_FALLING: case IRQ_TYPE_EDGE_BOTH: state = sprd_eic_get(chip, offset); - if (state) + if (state) { sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 0); - else + sprd_eic_update(chip, offset, + SPRD_EIC_DBNC_IC, 1); + } else { sprd_eic_update(chip, offset, SPRD_EIC_DBNC_IEV, 1); + sprd_eic_update(chip, offset, + SPRD_EIC_DBNC_IC, 1); + } break; default: return -ENOTSUPP; @@ -355,20 +362,27 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type) switch (flow_type) { case IRQ_TYPE_LEVEL_HIGH: sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 0); + sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTCLR, 1); break; case IRQ_TYPE_LEVEL_LOW: sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 1); + sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTCLR, 1); break; case IRQ_TYPE_EDGE_RISING: case IRQ_TYPE_EDGE_FALLING: case IRQ_TYPE_EDGE_BOTH: state = sprd_eic_get(chip, offset); - if (state) + if (state) { sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 0); - else + sprd_eic_update(chip, offset, + SPRD_EIC_LATCH_INTCLR, 1); + } else { sprd_eic_update(chip, offset, SPRD_EIC_LATCH_INTPOL, 1); + sprd_eic_update(chip, offset, + SPRD_EIC_LATCH_INTCLR, 1); + } break; default: return -ENOTSUPP; @@ -382,29 +396,34 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type) sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0); sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 0); sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 1); + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1); irq_set_handler_locked(data, handle_edge_irq); break; case IRQ_TYPE_EDGE_FALLING: sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0); sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 0); sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 0); + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1); irq_set_handler_locked(data, handle_edge_irq); break; case IRQ_TYPE_EDGE_BOTH: sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 0); sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 1); + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1); irq_set_handler_locked(data, handle_edge_irq); break; case IRQ_TYPE_LEVEL_HIGH: sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0); sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 1); sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 1); + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1); irq_set_handler_locked(data, handle_level_irq); break; case IRQ_TYPE_LEVEL_LOW: sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTBOTH, 0); sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTMODE, 1); sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTPOL, 0); + sprd_eic_update(chip, offset, SPRD_EIC_ASYNC_INTCLR, 1); irq_set_handler_locked(data, handle_level_irq); break; default: @@ -417,29 +436,34 @@ static int sprd_eic_irq_set_type(struct irq_data *data, unsigned int flow_type) sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0); sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 0); sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 1); + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1); irq_set_handler_locked(data, handle_edge_irq); break; case IRQ_TYPE_EDGE_FALLING: sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0); sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 0); sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 0); + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1); irq_set_handler_locked(data, handle_edge_irq); break; case IRQ_TYPE_EDGE_BOTH: sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 0); sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 1); + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1); irq_set_handler_locked(data, handle_edge_irq); break; case IRQ_TYPE_LEVEL_HIGH: sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0); sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 1); sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 1); + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1); irq_set_handler_locked(data, handle_level_irq); break; case IRQ_TYPE_LEVEL_LOW: sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTBOTH, 0); sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTMODE, 1); sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTPOL, 0); + sprd_eic_update(chip, offset, SPRD_EIC_SYNC_INTCLR, 1); irq_set_handler_locked(data, handle_level_irq); break; default: diff --git a/drivers/gpio/gpio-elkhartlake.c b/drivers/gpio/gpio-elkhartlake.c index a9c8b16215be68..887c0fe99d3950 100644 --- a/drivers/gpio/gpio-elkhartlake.c +++ b/drivers/gpio/gpio-elkhartlake.c @@ -55,18 +55,6 @@ static int ehl_gpio_probe(struct platform_device *pdev) return 0; } -static int ehl_gpio_suspend(struct device *dev) -{ - return tng_gpio_suspend(dev); -} - -static int ehl_gpio_resume(struct device *dev) -{ - return tng_gpio_resume(dev); -} - -static DEFINE_SIMPLE_DEV_PM_OPS(ehl_gpio_pm_ops, ehl_gpio_suspend, ehl_gpio_resume); - static const struct platform_device_id ehl_gpio_ids[] = { { "gpio-elkhartlake" }, { } @@ -76,7 +64,7 @@ MODULE_DEVICE_TABLE(platform, ehl_gpio_ids); static struct platform_driver ehl_gpio_driver = { .driver = { .name = "gpio-elkhartlake", - .pm = pm_sleep_ptr(&ehl_gpio_pm_ops), + .pm = pm_sleep_ptr(&tng_gpio_pm_ops), }, .probe = ehl_gpio_probe, .id_table = ehl_gpio_ids, diff --git a/drivers/gpio/gpio-en7523.c b/drivers/gpio/gpio-en7523.c index f836a8db4c1d21..69834db2c1cf26 100644 --- a/drivers/gpio/gpio-en7523.c +++ b/drivers/gpio/gpio-en7523.c @@ -12,11 +12,11 @@ #define AIROHA_GPIO_MAX 32 /** - * airoha_gpio_ctrl - Airoha GPIO driver data + * struct airoha_gpio_ctrl - Airoha GPIO driver data * @gc: Associated gpio_chip instance. * @data: The data register. - * @dir0: The direction register for the lower 16 pins. - * @dir1: The direction register for the higher 16 pins. + * @dir: [0] The direction register for the lower 16 pins. + * [1]: The direction register for the higher 16 pins. * @output: The output enable register. */ struct airoha_gpio_ctrl { diff --git a/drivers/gpio/gpio-ixp4xx.c b/drivers/gpio/gpio-ixp4xx.c index dde6cf3a5779b6..c5a9fa64056648 100644 --- a/drivers/gpio/gpio-ixp4xx.c +++ b/drivers/gpio/gpio-ixp4xx.c @@ -38,6 +38,18 @@ #define IXP4XX_GPIO_STYLE_MASK GENMASK(2, 0) #define IXP4XX_GPIO_STYLE_SIZE 3 +/* + * Clock output control register defines. + */ +#define IXP4XX_GPCLK_CLK0DC_SHIFT 0 +#define IXP4XX_GPCLK_CLK0TC_SHIFT 4 +#define IXP4XX_GPCLK_CLK0_MASK GENMASK(7, 0) +#define IXP4XX_GPCLK_MUX14 BIT(8) +#define IXP4XX_GPCLK_CLK1DC_SHIFT 16 +#define IXP4XX_GPCLK_CLK1TC_SHIFT 20 +#define IXP4XX_GPCLK_CLK1_MASK GENMASK(23, 16) +#define IXP4XX_GPCLK_MUX15 BIT(24) + /** * struct ixp4xx_gpio - IXP4 GPIO state container * @dev: containing device for this instance @@ -202,6 +214,8 @@ static int ixp4xx_gpio_probe(struct platform_device *pdev) struct ixp4xx_gpio *g; struct gpio_irq_chip *girq; struct device_node *irq_parent; + bool clk_14, clk_15; + u32 val; int ret; g = devm_kzalloc(dev, sizeof(*g), GFP_KERNEL); @@ -225,13 +239,48 @@ static int ixp4xx_gpio_probe(struct platform_device *pdev) } g->fwnode = of_node_to_fwnode(np); + /* + * If either clock output is enabled explicitly in the device tree + * we take full control of the clock by masking off all bits for + * the clock control and selectively enabling them. Otherwise + * we leave the hardware default settings. + * + * Enable clock outputs with default timings of requested clock. + * If you need control over TC and DC, add these to the device + * tree bindings and use them here. + */ + clk_14 = of_property_read_bool(np, "intel,ixp4xx-gpio14-clkout"); + clk_15 = of_property_read_bool(np, "intel,ixp4xx-gpio15-clkout"); + /* * Make sure GPIO 14 and 15 are NOT used as clocks but GPIO on * specific machines. */ if (of_machine_is_compatible("dlink,dsm-g600-a") || of_machine_is_compatible("iom,nas-100d")) - __raw_writel(0x0, g->base + IXP4XX_REG_GPCLK); + val = 0; + else { + val = __raw_readl(g->base + IXP4XX_REG_GPCLK); + + if (clk_14 || clk_15) { + val &= ~(IXP4XX_GPCLK_MUX14 | IXP4XX_GPCLK_MUX15); + val &= ~IXP4XX_GPCLK_CLK0_MASK; + val &= ~IXP4XX_GPCLK_CLK1_MASK; + if (clk_14) { + /* IXP4XX_GPCLK_CLK0DC implicit low */ + val |= (1 << IXP4XX_GPCLK_CLK0TC_SHIFT); + val |= IXP4XX_GPCLK_MUX14; + } + + if (clk_15) { + /* IXP4XX_GPCLK_CLK1DC implicit low */ + val |= (1 << IXP4XX_GPCLK_CLK1TC_SHIFT); + val |= IXP4XX_GPCLK_MUX15; + } + } + } + + __raw_writel(val, g->base + IXP4XX_REG_GPCLK); /* * This is a very special big-endian ARM issue: when the IXP4xx is diff --git a/drivers/gpio/gpio-max730x.c b/drivers/gpio/gpio-max730x.c index bb5cf14ae4c876..701795b9d3290c 100644 --- a/drivers/gpio/gpio-max730x.c +++ b/drivers/gpio/gpio-max730x.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * Copyright (C) 2006 Juergen Beisert, Pengutronix * Copyright (C) 2008 Guennadi Liakhovetski, Pengutronix * Copyright (C) 2009 Wolfram Sang, Pengutronix diff --git a/drivers/gpio/gpio-mlxbf3.c b/drivers/gpio/gpio-mlxbf3.c index 7a3e1760fc5b7d..d5906d419b0ab9 100644 --- a/drivers/gpio/gpio-mlxbf3.c +++ b/drivers/gpio/gpio-mlxbf3.c @@ -215,6 +215,8 @@ static int mlxbf3_gpio_probe(struct platform_device *pdev) gs->gpio_clr_io + MLXBF_GPIO_FW_DATA_OUT_CLEAR, gs->gpio_set_io + MLXBF_GPIO_FW_OUTPUT_ENABLE_SET, gs->gpio_clr_io + MLXBF_GPIO_FW_OUTPUT_ENABLE_CLEAR, 0); + if (ret) + return dev_err_probe(dev, ret, "%s: bgpio_init() failed", __func__); gc->request = gpiochip_generic_request; gc->free = gpiochip_generic_free; diff --git a/drivers/gpio/gpio-mmio.c b/drivers/gpio/gpio-mmio.c index 3ff0ea1e351c1d..71e1af7c21847b 100644 --- a/drivers/gpio/gpio-mmio.c +++ b/drivers/gpio/gpio-mmio.c @@ -40,25 +40,22 @@ o ` ~~~~\___/~~~~ ` controller in FPGA is ,.` * `.......````.``` */ -#include +#include +#include #include -#include -#include +#include +#include +#include +#include +#include #include +#include +#include +#include #include -#include #include -#include -#include -#include -#include + #include -#include -#include -#include -#include -#include -#include #include "gpiolib.h" @@ -688,7 +685,6 @@ static void __iomem *bgpio_map(struct platform_device *pdev, return devm_ioremap_resource(&pdev->dev, r); } -#ifdef CONFIG_OF static const struct of_device_id bgpio_of_match[] = { { .compatible = "brcm,bcm6345-gpio" }, { .compatible = "wd,mbl-gpio" }, @@ -697,36 +693,27 @@ static const struct of_device_id bgpio_of_match[] = { }; MODULE_DEVICE_TABLE(of, bgpio_of_match); -static struct bgpio_pdata *bgpio_parse_dt(struct platform_device *pdev, - unsigned long *flags) +static struct bgpio_pdata *bgpio_parse_fw(struct device *dev, unsigned long *flags) { struct bgpio_pdata *pdata; - if (!pdev->dev.of_node) + if (!dev_fwnode(dev)) return NULL; - pdata = devm_kzalloc(&pdev->dev, sizeof(struct bgpio_pdata), - GFP_KERNEL); + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return ERR_PTR(-ENOMEM); pdata->base = -1; - if (of_device_is_big_endian(pdev->dev.of_node)) + if (device_is_big_endian(dev)) *flags |= BGPIOF_BIG_ENDIAN_BYTE_ORDER; - if (of_property_read_bool(pdev->dev.of_node, "no-output")) + if (device_property_read_bool(dev, "no-output")) *flags |= BGPIOF_NO_OUTPUT; return pdata; } -#else -static struct bgpio_pdata *bgpio_parse_dt(struct platform_device *pdev, - unsigned long *flags) -{ - return NULL; -} -#endif /* CONFIG_OF */ static int bgpio_pdev_probe(struct platform_device *pdev) { @@ -743,7 +730,7 @@ static int bgpio_pdev_probe(struct platform_device *pdev) struct gpio_chip *gc; struct bgpio_pdata *pdata; - pdata = bgpio_parse_dt(pdev, &flags); + pdata = bgpio_parse_fw(dev, &flags); if (IS_ERR(pdata)) return PTR_ERR(pdata); @@ -814,7 +801,7 @@ MODULE_DEVICE_TABLE(platform, bgpio_id_table); static struct platform_driver bgpio_driver = { .driver = { .name = "basic-mmio-gpio", - .of_match_table = of_match_ptr(bgpio_of_match), + .of_match_table = bgpio_of_match, }, .id_table = bgpio_id_table, .probe = bgpio_pdev_probe, diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c index 4870e267a402ac..455eecf6380e44 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c @@ -354,7 +354,6 @@ static const struct file_operations gpio_mockup_debugfs_ops = { static void gpio_mockup_debugfs_setup(struct device *dev, struct gpio_mockup_chip *chip) { - struct device *child __free(put_device) = NULL; struct gpio_mockup_dbgfs_private *priv; struct gpio_chip *gc; const char *devname; @@ -367,7 +366,7 @@ static void gpio_mockup_debugfs_setup(struct device *dev, * There can only be a single GPIO device per platform device in * gpio-mockup so using device_find_any_child() is OK. */ - child = device_find_any_child(dev); + struct device *child __free(put_device) = device_find_any_child(dev); if (!child) return; diff --git a/drivers/gpio/gpio-npcm-sgpio.c b/drivers/gpio/gpio-npcm-sgpio.c new file mode 100644 index 00000000000000..d31788b43abcc7 --- /dev/null +++ b/drivers/gpio/gpio-npcm-sgpio.c @@ -0,0 +1,619 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Nuvoton NPCM Serial GPIO Driver + * + * Copyright (C) 2021 Nuvoton Technologies + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_NR_HW_SGPIO 64 + +#define NPCM_IOXCFG1 0x2A +#define NPCM_IOXCFG1_SFT_CLK GENMASK(3, 0) +#define NPCM_IOXCFG1_SCLK_POL BIT(4) +#define NPCM_IOXCFG1_LDSH_POL BIT(5) + +#define NPCM_IOXCTS 0x28 +#define NPCM_IOXCTS_IOXIF_EN BIT(7) +#define NPCM_IOXCTS_RD_MODE GENMASK(2, 1) +#define NPCM_IOXCTS_RD_MODE_PERIODIC BIT(2) + +#define NPCM_IOXCFG2 0x2B +#define NPCM_IOXCFG2_PORT GENMASK(3, 0) + +#define NPCM_IXOEVCFG_MASK GENMASK(1, 0) +#define NPCM_IXOEVCFG_FALLING BIT(1) +#define NPCM_IXOEVCFG_RISING BIT(0) +#define NPCM_IXOEVCFG_BOTH (NPCM_IXOEVCFG_FALLING | NPCM_IXOEVCFG_RISING) + +#define NPCM_CLK_MHZ (8 * HZ_PER_MHZ) +#define NPCM_750_OPT 6 +#define NPCM_845_OPT 5 + +#define GPIO_BANK(x) ((x) / 8) +#define GPIO_BIT(x) ((x) % 8) + +/* + * Select the frequency of shift clock. + * The shift clock is a division of the APB clock. + */ +struct npcm_clk_cfg { + unsigned int *sft_clk; + unsigned int *clk_sel; + unsigned int cfg_opt; +}; + +struct npcm_sgpio { + struct gpio_chip chip; + struct clk *pclk; + struct irq_chip intc; + raw_spinlock_t lock; + + void __iomem *base; + int irq; + u8 nin_sgpio; + u8 nout_sgpio; + u8 in_port; + u8 out_port; + u8 int_type[MAX_NR_HW_SGPIO]; +}; + +struct npcm_sgpio_bank { + u8 rdata_reg; + u8 wdata_reg; + u8 event_config; + u8 event_status; +}; + +enum npcm_sgpio_reg { + READ_DATA, + WRITE_DATA, + EVENT_CFG, + EVENT_STS, +}; + +static const struct npcm_sgpio_bank npcm_sgpio_banks[] = { + { + .wdata_reg = 0x00, + .rdata_reg = 0x08, + .event_config = 0x10, + .event_status = 0x20, + }, + { + .wdata_reg = 0x01, + .rdata_reg = 0x09, + .event_config = 0x12, + .event_status = 0x21, + }, + { + .wdata_reg = 0x02, + .rdata_reg = 0x0a, + .event_config = 0x14, + .event_status = 0x22, + }, + { + .wdata_reg = 0x03, + .rdata_reg = 0x0b, + .event_config = 0x16, + .event_status = 0x23, + }, + { + .wdata_reg = 0x04, + .rdata_reg = 0x0c, + .event_config = 0x18, + .event_status = 0x24, + }, + { + .wdata_reg = 0x05, + .rdata_reg = 0x0d, + .event_config = 0x1a, + .event_status = 0x25, + }, + { + .wdata_reg = 0x06, + .rdata_reg = 0x0e, + .event_config = 0x1c, + .event_status = 0x26, + }, + { + .wdata_reg = 0x07, + .rdata_reg = 0x0f, + .event_config = 0x1e, + .event_status = 0x27, + }, +}; + +static void __iomem *bank_reg(struct npcm_sgpio *gpio, + const struct npcm_sgpio_bank *bank, + const enum npcm_sgpio_reg reg) +{ + switch (reg) { + case READ_DATA: + return gpio->base + bank->rdata_reg; + case WRITE_DATA: + return gpio->base + bank->wdata_reg; + case EVENT_CFG: + return gpio->base + bank->event_config; + case EVENT_STS: + return gpio->base + bank->event_status; + default: + /* actually if code runs to here, it's an error case */ + dev_WARN(gpio->chip.parent, "Getting here is an error condition"); + return NULL; + } +} + +static const struct npcm_sgpio_bank *offset_to_bank(unsigned int offset) +{ + unsigned int bank = GPIO_BANK(offset); + + return &npcm_sgpio_banks[bank]; +} + +static void npcm_sgpio_irqd_to_data(struct irq_data *d, + struct npcm_sgpio **gpio, + const struct npcm_sgpio_bank **bank, + u8 *bit, unsigned int *offset) +{ + struct npcm_sgpio *internal; + + *offset = irqd_to_hwirq(d); + internal = irq_data_get_irq_chip_data(d); + + *gpio = internal; + *offset -= internal->nout_sgpio; + *bank = offset_to_bank(*offset); + *bit = GPIO_BIT(*offset); +} + +static int npcm_sgpio_init_port(struct npcm_sgpio *gpio) +{ + u8 in_port, out_port, set_port, reg; + + in_port = GPIO_BANK(gpio->nin_sgpio); + if (GPIO_BIT(gpio->nin_sgpio) > 0) + in_port += 1; + + out_port = GPIO_BANK(gpio->nout_sgpio); + if (GPIO_BIT(gpio->nout_sgpio) > 0) + out_port += 1; + + gpio->in_port = in_port; + gpio->out_port = out_port; + set_port = (out_port & NPCM_IOXCFG2_PORT) << 4 | + (in_port & NPCM_IOXCFG2_PORT); + iowrite8(set_port, gpio->base + NPCM_IOXCFG2); + + reg = ioread8(gpio->base + NPCM_IOXCFG2); + + return reg == set_port ? 0 : -EINVAL; + +} + +static int npcm_sgpio_dir_in(struct gpio_chip *gc, unsigned int offset) +{ + struct npcm_sgpio *gpio = gpiochip_get_data(gc); + + return offset < gpio->nout_sgpio ? -EINVAL : 0; + +} + +static int npcm_sgpio_dir_out(struct gpio_chip *gc, unsigned int offset, int val) +{ + gc->set(gc, offset, val); + + return 0; +} + +static int npcm_sgpio_get_direction(struct gpio_chip *gc, unsigned int offset) +{ + struct npcm_sgpio *gpio = gpiochip_get_data(gc); + + if (offset < gpio->nout_sgpio) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; +} + +static void npcm_sgpio_set(struct gpio_chip *gc, unsigned int offset, int val) +{ + struct npcm_sgpio *gpio = gpiochip_get_data(gc); + const struct npcm_sgpio_bank *bank = offset_to_bank(offset); + void __iomem *addr; + u8 reg = 0; + + addr = bank_reg(gpio, bank, WRITE_DATA); + reg = ioread8(addr); + + if (val) + reg |= BIT(GPIO_BIT(offset)); + else + reg &= ~BIT(GPIO_BIT(offset)); + + iowrite8(reg, addr); +} + +static int npcm_sgpio_get(struct gpio_chip *gc, unsigned int offset) +{ + struct npcm_sgpio *gpio = gpiochip_get_data(gc); + const struct npcm_sgpio_bank *bank; + void __iomem *addr; + u8 reg; + + if (offset < gpio->nout_sgpio) { + bank = offset_to_bank(offset); + addr = bank_reg(gpio, bank, WRITE_DATA); + } else { + offset -= gpio->nout_sgpio; + bank = offset_to_bank(offset); + addr = bank_reg(gpio, bank, READ_DATA); + } + + reg = ioread8(addr); + + return !!(reg & BIT(GPIO_BIT(offset))); +} + +static void npcm_sgpio_setup_enable(struct npcm_sgpio *gpio, bool enable) +{ + u8 reg; + + reg = ioread8(gpio->base + NPCM_IOXCTS); + reg = (reg & ~NPCM_IOXCTS_RD_MODE) | NPCM_IOXCTS_RD_MODE_PERIODIC; + + if (enable) + reg |= NPCM_IOXCTS_IOXIF_EN; + else + reg &= ~NPCM_IOXCTS_IOXIF_EN; + + iowrite8(reg, gpio->base + NPCM_IOXCTS); +} + +static int npcm_sgpio_setup_clk(struct npcm_sgpio *gpio, + const struct npcm_clk_cfg *clk_cfg) +{ + unsigned long apb_freq; + u32 val; + u8 tmp; + int i; + + apb_freq = clk_get_rate(gpio->pclk); + tmp = ioread8(gpio->base + NPCM_IOXCFG1) & ~NPCM_IOXCFG1_SFT_CLK; + + for (i = clk_cfg->cfg_opt-1; i > 0; i--) { + val = apb_freq / clk_cfg->sft_clk[i]; + if (NPCM_CLK_MHZ > val) { + iowrite8(clk_cfg->clk_sel[i] | tmp, + gpio->base + NPCM_IOXCFG1); + return 0; + } + } + + return -EINVAL; +} + +static void npcm_sgpio_irq_init_valid_mask(struct gpio_chip *gc, + unsigned long *valid_mask, + unsigned int ngpios) +{ + struct npcm_sgpio *gpio = gpiochip_get_data(gc); + + /* input GPIOs in the high range */ + bitmap_set(valid_mask, gpio->nout_sgpio, gpio->nin_sgpio); + bitmap_clear(valid_mask, 0, gpio->nout_sgpio); +} + +static void npcm_sgpio_irq_set_mask(struct irq_data *d, bool set) +{ + const struct npcm_sgpio_bank *bank; + struct npcm_sgpio *gpio; + unsigned long flags; + void __iomem *addr; + unsigned int offset; + u16 reg, type; + u8 bit; + + npcm_sgpio_irqd_to_data(d, &gpio, &bank, &bit, &offset); + addr = bank_reg(gpio, bank, EVENT_CFG); + + reg = ioread16(addr); + if (set) { + reg &= ~(NPCM_IXOEVCFG_MASK << (bit * 2)); + } else { + type = gpio->int_type[offset]; + reg |= (type << (bit * 2)); + } + + raw_spin_lock_irqsave(&gpio->lock, flags); + + npcm_sgpio_setup_enable(gpio, false); + + iowrite16(reg, addr); + + npcm_sgpio_setup_enable(gpio, true); + + addr = bank_reg(gpio, bank, EVENT_STS); + reg = ioread8(addr); + reg |= BIT(bit); + iowrite8(reg, addr); + + raw_spin_unlock_irqrestore(&gpio->lock, flags); +} + +static void npcm_sgpio_irq_ack(struct irq_data *d) +{ + const struct npcm_sgpio_bank *bank; + struct npcm_sgpio *gpio; + unsigned long flags; + void __iomem *status_addr; + unsigned int offset; + u8 bit; + + npcm_sgpio_irqd_to_data(d, &gpio, &bank, &bit, &offset); + status_addr = bank_reg(gpio, bank, EVENT_STS); + raw_spin_lock_irqsave(&gpio->lock, flags); + iowrite8(BIT(bit), status_addr); + raw_spin_unlock_irqrestore(&gpio->lock, flags); +} + +static void npcm_sgpio_irq_mask(struct irq_data *d) +{ + npcm_sgpio_irq_set_mask(d, true); +} + +static void npcm_sgpio_irq_unmask(struct irq_data *d) +{ + npcm_sgpio_irq_set_mask(d, false); +} + +static int npcm_sgpio_set_type(struct irq_data *d, unsigned int type) +{ + const struct npcm_sgpio_bank *bank; + irq_flow_handler_t handler; + struct npcm_sgpio *gpio; + unsigned long flags; + void __iomem *addr; + unsigned int offset; + u16 reg, val; + u8 bit; + + npcm_sgpio_irqd_to_data(d, &gpio, &bank, &bit, &offset); + + switch (type & IRQ_TYPE_SENSE_MASK) { + case IRQ_TYPE_EDGE_BOTH: + val = NPCM_IXOEVCFG_BOTH; + break; + case IRQ_TYPE_EDGE_RISING: + case IRQ_TYPE_LEVEL_HIGH: + val = NPCM_IXOEVCFG_RISING; + break; + case IRQ_TYPE_EDGE_FALLING: + case IRQ_TYPE_LEVEL_LOW: + val = NPCM_IXOEVCFG_FALLING; + break; + default: + return -EINVAL; + } + + if (type & IRQ_TYPE_LEVEL_MASK) + handler = handle_level_irq; + else + handler = handle_edge_irq; + + gpio->int_type[offset] = val; + + raw_spin_lock_irqsave(&gpio->lock, flags); + npcm_sgpio_setup_enable(gpio, false); + addr = bank_reg(gpio, bank, EVENT_CFG); + reg = ioread16(addr); + + reg |= (val << (bit * 2)); + + iowrite16(reg, addr); + npcm_sgpio_setup_enable(gpio, true); + raw_spin_unlock_irqrestore(&gpio->lock, flags); + + irq_set_handler_locked(d, handler); + + return 0; +} + +static void npcm_sgpio_irq_handler(struct irq_desc *desc) +{ + struct gpio_chip *gc = irq_desc_get_handler_data(desc); + struct irq_chip *ic = irq_desc_get_chip(desc); + struct npcm_sgpio *gpio = gpiochip_get_data(gc); + unsigned int i, j, girq; + unsigned long reg; + + chained_irq_enter(ic, desc); + + for (i = 0; i < ARRAY_SIZE(npcm_sgpio_banks); i++) { + const struct npcm_sgpio_bank *bank = &npcm_sgpio_banks[i]; + + reg = ioread8(bank_reg(gpio, bank, EVENT_STS)); + for_each_set_bit(j, ®, 8) { + girq = irq_find_mapping(gc->irq.domain, + i * 8 + gpio->nout_sgpio + j); + generic_handle_domain_irq(gc->irq.domain, girq); + } + } + + chained_irq_exit(ic, desc); +} + +static const struct irq_chip sgpio_irq_chip = { + .name = "sgpio-irq", + .irq_ack = npcm_sgpio_irq_ack, + .irq_mask = npcm_sgpio_irq_mask, + .irq_unmask = npcm_sgpio_irq_unmask, + .irq_set_type = npcm_sgpio_set_type, + .flags = IRQCHIP_IMMUTABLE | IRQCHIP_MASK_ON_SUSPEND, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + +static int npcm_sgpio_setup_irqs(struct npcm_sgpio *gpio, + struct platform_device *pdev) +{ + int rc, i; + struct gpio_irq_chip *irq; + + rc = platform_get_irq(pdev, 0); + if (rc < 0) + return rc; + + gpio->irq = rc; + + npcm_sgpio_setup_enable(gpio, false); + + /* Disable IRQ and clear Interrupt status registers for all SGPIO Pins. */ + for (i = 0; i < ARRAY_SIZE(npcm_sgpio_banks); i++) { + const struct npcm_sgpio_bank *bank = &npcm_sgpio_banks[i]; + + iowrite16(0, bank_reg(gpio, bank, EVENT_CFG)); + iowrite8(0xff, bank_reg(gpio, bank, EVENT_STS)); + } + + irq = &gpio->chip.irq; + gpio_irq_chip_set_chip(irq, &sgpio_irq_chip); + irq->init_valid_mask = npcm_sgpio_irq_init_valid_mask; + irq->handler = handle_bad_irq; + irq->default_type = IRQ_TYPE_NONE; + irq->parent_handler = npcm_sgpio_irq_handler; + irq->parent_handler_data = gpio; + irq->parents = &gpio->irq; + irq->num_parents = 1; + + return 0; +} + +static int npcm_sgpio_probe(struct platform_device *pdev) +{ + struct npcm_sgpio *gpio; + const struct npcm_clk_cfg *clk_cfg; + int rc; + u32 nin_gpios, nout_gpios; + + gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); + if (!gpio) + return -ENOMEM; + + gpio->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(gpio->base)) + return PTR_ERR(gpio->base); + + clk_cfg = device_get_match_data(&pdev->dev); + if (!clk_cfg) + return -EINVAL; + + rc = device_property_read_u32(&pdev->dev, "nuvoton,input-ngpios", + &nin_gpios); + if (rc < 0) + return dev_err_probe(&pdev->dev, rc, "Could not read ngpios property\n"); + + rc = device_property_read_u32(&pdev->dev, "nuvoton,output-ngpios", + &nout_gpios); + if (rc < 0) + return dev_err_probe(&pdev->dev, rc, "Could not read ngpios property\n"); + + gpio->nin_sgpio = nin_gpios; + gpio->nout_sgpio = nout_gpios; + if (gpio->nin_sgpio > MAX_NR_HW_SGPIO || + gpio->nout_sgpio > MAX_NR_HW_SGPIO) + return dev_err_probe(&pdev->dev, -EINVAL, "Number of GPIOs exceeds the maximum of %d: input: %d output: %d\n", MAX_NR_HW_SGPIO, nin_gpios, nout_gpios); + + gpio->pclk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(gpio->pclk)) + return dev_err_probe(&pdev->dev, PTR_ERR(gpio->pclk), "Could not get pclk\n"); + + rc = npcm_sgpio_setup_clk(gpio, clk_cfg); + if (rc < 0) + return dev_err_probe(&pdev->dev, rc, "Failed to setup clock\n"); + + raw_spin_lock_init(&gpio->lock); + gpio->chip.parent = &pdev->dev; + gpio->chip.ngpio = gpio->nin_sgpio + gpio->nout_sgpio; + gpio->chip.direction_input = npcm_sgpio_dir_in; + gpio->chip.direction_output = npcm_sgpio_dir_out; + gpio->chip.get_direction = npcm_sgpio_get_direction; + gpio->chip.get = npcm_sgpio_get; + gpio->chip.set = npcm_sgpio_set; + gpio->chip.label = dev_name(&pdev->dev); + gpio->chip.base = -1; + + rc = npcm_sgpio_init_port(gpio); + if (rc < 0) + return rc; + + rc = npcm_sgpio_setup_irqs(gpio, pdev); + if (rc < 0) + return rc; + + rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); + if (rc) + return dev_err_probe(&pdev->dev, rc, "GPIO registering failed\n"); + + npcm_sgpio_setup_enable(gpio, true); + + return 0; +} + +static unsigned int npcm750_SFT_CLK[NPCM_750_OPT] = { + 1024, 32, 8, 4, 3, 2, +}; + +static unsigned int npcm750_CLK_SEL[NPCM_750_OPT] = { + 0x00, 0x05, 0x07, 0x0C, 0x0D, 0x0E, +}; + +static unsigned int npcm845_SFT_CLK[NPCM_845_OPT] = { + 1024, 32, 16, 8, 4, +}; + +static unsigned int npcm845_CLK_SEL[NPCM_845_OPT] = { + 0x00, 0x05, 0x06, 0x07, 0x0C, +}; + +static struct npcm_clk_cfg npcm750_sgpio_pdata = { + .sft_clk = npcm750_SFT_CLK, + .clk_sel = npcm750_CLK_SEL, + .cfg_opt = NPCM_750_OPT, +}; + +static const struct npcm_clk_cfg npcm845_sgpio_pdata = { + .sft_clk = npcm845_SFT_CLK, + .clk_sel = npcm845_CLK_SEL, + .cfg_opt = NPCM_845_OPT, +}; + +static const struct of_device_id npcm_sgpio_of_table[] = { + { .compatible = "nuvoton,npcm750-sgpio", .data = &npcm750_sgpio_pdata, }, + { .compatible = "nuvoton,npcm845-sgpio", .data = &npcm845_sgpio_pdata, }, + {} +}; +MODULE_DEVICE_TABLE(of, npcm_sgpio_of_table); + +static struct platform_driver npcm_sgpio_driver = { + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = npcm_sgpio_of_table, + }, + .probe = npcm_sgpio_probe, +}; +module_platform_driver(npcm_sgpio_driver); + +MODULE_AUTHOR("Jim Liu "); +MODULE_AUTHOR("Joseph Liu "); +MODULE_DESCRIPTION("Nuvoton NPCM Serial GPIO Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-pmic-eic-sprd.c b/drivers/gpio/gpio-pmic-eic-sprd.c index 01c0fd0a9d8c63..d9b228bea42eec 100644 --- a/drivers/gpio/gpio-pmic-eic-sprd.c +++ b/drivers/gpio/gpio-pmic-eic-sprd.c @@ -151,8 +151,8 @@ static void sprd_pmic_eic_irq_mask(struct irq_data *data) struct sprd_pmic_eic *pmic_eic = gpiochip_get_data(chip); u32 offset = irqd_to_hwirq(data); - pmic_eic->reg[REG_IE] = 0; - pmic_eic->reg[REG_TRIG] = 0; + pmic_eic->reg[REG_IE] &= ~BIT(offset); + pmic_eic->reg[REG_TRIG] &= ~BIT(offset); gpiochip_disable_irq(chip, offset); } @@ -165,8 +165,8 @@ static void sprd_pmic_eic_irq_unmask(struct irq_data *data) gpiochip_enable_irq(chip, offset); - pmic_eic->reg[REG_IE] = 1; - pmic_eic->reg[REG_TRIG] = 1; + pmic_eic->reg[REG_IE] |= BIT(offset); + pmic_eic->reg[REG_TRIG] |= BIT(offset); } static int sprd_pmic_eic_irq_set_type(struct irq_data *data, @@ -174,13 +174,14 @@ static int sprd_pmic_eic_irq_set_type(struct irq_data *data, { struct gpio_chip *chip = irq_data_get_irq_chip_data(data); struct sprd_pmic_eic *pmic_eic = gpiochip_get_data(chip); + u32 offset = irqd_to_hwirq(data); switch (flow_type) { case IRQ_TYPE_LEVEL_HIGH: - pmic_eic->reg[REG_IEV] = 1; + pmic_eic->reg[REG_IEV] |= BIT(offset); break; case IRQ_TYPE_LEVEL_LOW: - pmic_eic->reg[REG_IEV] = 0; + pmic_eic->reg[REG_IEV] &= ~BIT(offset); break; case IRQ_TYPE_EDGE_RISING: case IRQ_TYPE_EDGE_FALLING: @@ -222,15 +223,15 @@ static void sprd_pmic_eic_bus_sync_unlock(struct irq_data *data) sprd_pmic_eic_update(chip, offset, SPRD_PMIC_EIC_IEV, 1); } else { sprd_pmic_eic_update(chip, offset, SPRD_PMIC_EIC_IEV, - pmic_eic->reg[REG_IEV]); + !!(pmic_eic->reg[REG_IEV] & BIT(offset))); } /* Set irq unmask */ sprd_pmic_eic_update(chip, offset, SPRD_PMIC_EIC_IE, - pmic_eic->reg[REG_IE]); + !!(pmic_eic->reg[REG_IE] & BIT(offset))); /* Generate trigger start pulse for debounce EIC */ sprd_pmic_eic_update(chip, offset, SPRD_PMIC_EIC_TRIG, - pmic_eic->reg[REG_TRIG]); + !!(pmic_eic->reg[REG_TRIG] & BIT(offset))); mutex_unlock(&pmic_eic->buslock); } diff --git a/drivers/gpio/gpio-rtd.c b/drivers/gpio/gpio-rtd.c new file mode 100644 index 00000000000000..bf7f008f58d703 --- /dev/null +++ b/drivers/gpio/gpio-rtd.c @@ -0,0 +1,607 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Realtek DHC gpio driver + * + * Copyright (c) 2023 Realtek Semiconductor Corp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RTD_GPIO_DEBOUNCE_1US 0 +#define RTD_GPIO_DEBOUNCE_10US 1 +#define RTD_GPIO_DEBOUNCE_100US 2 +#define RTD_GPIO_DEBOUNCE_1MS 3 +#define RTD_GPIO_DEBOUNCE_10MS 4 +#define RTD_GPIO_DEBOUNCE_20MS 5 +#define RTD_GPIO_DEBOUNCE_30MS 6 + +/** + * struct rtd_gpio_info - Specific GPIO register information + * @name: GPIO device name + * @gpio_base: GPIO base number + * @num_gpios: The number of GPIOs + * @dir_offset: Offset for GPIO direction registers + * @dato_offset: Offset for GPIO data output registers + * @dati_offset: Offset for GPIO data input registers + * @ie_offset: Offset for GPIO interrupt enable registers + * @dp_offset: Offset for GPIO detection polarity registers + * @gpa_offset: Offset for GPIO assert interrupt status registers + * @gpda_offset: Offset for GPIO deassert interrupt status registers + * @deb_offset: Offset for GPIO debounce registers + * @deb_val: Register values representing the GPIO debounce time + * @get_deb_setval: Used to get the corresponding value for setting the debounce register + */ +struct rtd_gpio_info { + const char *name; + unsigned int gpio_base; + unsigned int num_gpios; + u8 *dir_offset; + u8 *dato_offset; + u8 *dati_offset; + u8 *ie_offset; + u8 *dp_offset; + u8 *gpa_offset; + u8 *gpda_offset; + u8 *deb_offset; + u8 *deb_val; + u8 (*get_deb_setval)(const struct rtd_gpio_info *info, + unsigned int offset, u8 deb_index, + u8 *reg_offset, u8 *shift); +}; + +struct rtd_gpio { + struct gpio_chip gpio_chip; + const struct rtd_gpio_info *info; + void __iomem *base; + void __iomem *irq_base; + unsigned int irqs[2]; + raw_spinlock_t lock; +}; + +static u8 rtd_gpio_get_deb_setval(const struct rtd_gpio_info *info, unsigned int offset, + u8 deb_index, u8 *reg_offset, u8 *shift) +{ + *reg_offset = info->deb_offset[offset / 8]; + *shift = (offset % 8) * 4; + return info->deb_val[deb_index]; +} + +static u8 rtd1295_misc_gpio_get_deb_setval(const struct rtd_gpio_info *info, unsigned int offset, + u8 deb_index, u8 *reg_offset, u8 *shift) +{ + *reg_offset = info->deb_offset[0]; + *shift = (offset % 8) * 4; + return info->deb_val[deb_index]; +} + +static u8 rtd1295_iso_gpio_get_deb_setval(const struct rtd_gpio_info *info, unsigned int offset, + u8 deb_index, u8 *reg_offset, u8 *shift) +{ + *reg_offset = info->deb_offset[0]; + *shift = 0; + return info->deb_val[deb_index]; +} + +static const struct rtd_gpio_info rtd_iso_gpio_info = { + .name = "rtd_iso_gpio", + .gpio_base = 0, + .num_gpios = 82, + .dir_offset = (u8 []){ 0x0, 0x18, 0x2c }, + .dato_offset = (u8 []){ 0x4, 0x1c, 0x30 }, + .dati_offset = (u8 []){ 0x8, 0x20, 0x34 }, + .ie_offset = (u8 []){ 0xc, 0x24, 0x38 }, + .dp_offset = (u8 []){ 0x10, 0x28, 0x3c }, + .gpa_offset = (u8 []){ 0x8, 0xe0, 0x90 }, + .gpda_offset = (u8 []){ 0xc, 0xe4, 0x94 }, + .deb_offset = (u8 []){ 0x44, 0x48, 0x4c, 0x50, 0x54, 0x58, 0x5c, + 0x60, 0x64, 0x68, 0x6c }, + .deb_val = (u8 []){ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6 }, + .get_deb_setval = rtd_gpio_get_deb_setval, +}; + +static const struct rtd_gpio_info rtd1619_iso_gpio_info = { + .name = "rtd1619_iso_gpio", + .gpio_base = 0, + .num_gpios = 86, + .dir_offset = (u8 []){ 0x0, 0x18, 0x2c }, + .dato_offset = (u8 []){ 0x4, 0x1c, 0x30 }, + .dati_offset = (u8 []){ 0x8, 0x20, 0x34 }, + .ie_offset = (u8 []){ 0xc, 0x24, 0x38 }, + .dp_offset = (u8 []){ 0x10, 0x28, 0x3c }, + .gpa_offset = (u8 []){ 0x8, 0xe0, 0x90 }, + .gpda_offset = (u8 []){ 0xc, 0xe4, 0x94 }, + .deb_offset = (u8 []){ 0x44, 0x48, 0x4c, 0x50, 0x54, 0x58, 0x5c, + 0x60, 0x64, 0x68, 0x6c }, + .deb_val = (u8 []){ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6 }, + .get_deb_setval = rtd_gpio_get_deb_setval, +}; + +static const struct rtd_gpio_info rtd1395_iso_gpio_info = { + .name = "rtd1395_iso_gpio", + .gpio_base = 0, + .num_gpios = 57, + .dir_offset = (u8 []){ 0x0, 0x18 }, + .dato_offset = (u8 []){ 0x4, 0x1c }, + .dati_offset = (u8 []){ 0x8, 0x20 }, + .ie_offset = (u8 []){ 0xc, 0x24 }, + .dp_offset = (u8 []){ 0x10, 0x28 }, + .gpa_offset = (u8 []){ 0x8, 0xe0 }, + .gpda_offset = (u8 []){ 0xc, 0xe4 }, + .deb_offset = (u8 []){ 0x30, 0x34, 0x38, 0x3c, 0x40, 0x44, 0x48, 0x4c }, + .deb_val = (u8 []){ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6 }, + .get_deb_setval = rtd_gpio_get_deb_setval, +}; + +static const struct rtd_gpio_info rtd1295_misc_gpio_info = { + .name = "rtd1295_misc_gpio", + .gpio_base = 0, + .num_gpios = 101, + .dir_offset = (u8 []){ 0x0, 0x4, 0x8, 0xc }, + .dato_offset = (u8 []){ 0x10, 0x14, 0x18, 0x1c }, + .dati_offset = (u8 []){ 0x20, 0x24, 0x28, 0x2c }, + .ie_offset = (u8 []){ 0x30, 0x34, 0x38, 0x3c }, + .dp_offset = (u8 []){ 0x40, 0x44, 0x48, 0x4c }, + .gpa_offset = (u8 []){ 0x40, 0x44, 0xa4, 0xb8 }, + .gpda_offset = (u8 []){ 0x54, 0x58, 0xa8, 0xbc}, + .deb_offset = (u8 []){ 0x50 }, + .deb_val = (u8 []){ 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 }, + .get_deb_setval = rtd1295_misc_gpio_get_deb_setval, +}; + +static const struct rtd_gpio_info rtd1295_iso_gpio_info = { + .name = "rtd1295_iso_gpio", + .gpio_base = 101, + .num_gpios = 35, + .dir_offset = (u8 []){ 0x0, 0x18 }, + .dato_offset = (u8 []){ 0x4, 0x1c }, + .dati_offset = (u8 []){ 0x8, 0x20 }, + .ie_offset = (u8 []){ 0xc, 0x24 }, + .dp_offset = (u8 []){ 0x10, 0x28 }, + .gpa_offset = (u8 []){ 0x8, 0xe0 }, + .gpda_offset = (u8 []){ 0xc, 0xe4 }, + .deb_offset = (u8 []){ 0x14 }, + .deb_val = (u8 []){ 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 }, + .get_deb_setval = rtd1295_iso_gpio_get_deb_setval, +}; + +static int rtd_gpio_dir_offset(struct rtd_gpio *data, unsigned int offset) +{ + return data->info->dir_offset[offset / 32]; +} + +static int rtd_gpio_dato_offset(struct rtd_gpio *data, unsigned int offset) +{ + return data->info->dato_offset[offset / 32]; +} + +static int rtd_gpio_dati_offset(struct rtd_gpio *data, unsigned int offset) +{ + return data->info->dati_offset[offset / 32]; +} + +static int rtd_gpio_ie_offset(struct rtd_gpio *data, unsigned int offset) +{ + return data->info->ie_offset[offset / 32]; +} + +static int rtd_gpio_dp_offset(struct rtd_gpio *data, unsigned int offset) +{ + return data->info->dp_offset[offset / 32]; +} + + +static int rtd_gpio_gpa_offset(struct rtd_gpio *data, unsigned int offset) +{ + /* Each GPIO assert interrupt status register contains 31 GPIOs. */ + return data->info->gpa_offset[offset / 31]; +} + +static int rtd_gpio_gpda_offset(struct rtd_gpio *data, unsigned int offset) +{ + /* Each GPIO deassert interrupt status register contains 31 GPIOs. */ + return data->info->gpda_offset[offset / 31]; +} + +static int rtd_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset, + unsigned int debounce) +{ + struct rtd_gpio *data = gpiochip_get_data(chip); + u8 deb_val, deb_index, reg_offset, shift; + unsigned int write_en; + u32 val; + + switch (debounce) { + case 1: + deb_index = RTD_GPIO_DEBOUNCE_1US; + break; + case 10: + deb_index = RTD_GPIO_DEBOUNCE_10US; + break; + case 100: + deb_index = RTD_GPIO_DEBOUNCE_100US; + break; + case 1000: + deb_index = RTD_GPIO_DEBOUNCE_1MS; + break; + case 10000: + deb_index = RTD_GPIO_DEBOUNCE_10MS; + break; + case 20000: + deb_index = RTD_GPIO_DEBOUNCE_20MS; + break; + case 30000: + deb_index = RTD_GPIO_DEBOUNCE_30MS; + break; + default: + return -ENOTSUPP; + } + + deb_val = data->info->get_deb_setval(data->info, offset, deb_index, ®_offset, &shift); + write_en = BIT(shift + 3); + val = (deb_val << shift) | write_en; + + guard(raw_spinlock_irqsave)(&data->lock); + writel_relaxed(val, data->base + reg_offset); + + return 0; +} + +static int rtd_gpio_set_config(struct gpio_chip *chip, unsigned int offset, + unsigned long config) +{ + int debounce; + + switch (pinconf_to_config_param(config)) { + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_UP: + case PIN_CONFIG_BIAS_PULL_DOWN: + return gpiochip_generic_config(chip, offset, config); + case PIN_CONFIG_INPUT_DEBOUNCE: + debounce = pinconf_to_config_argument(config); + return rtd_gpio_set_debounce(chip, offset, debounce); + default: + return -ENOTSUPP; + } +} + +static void rtd_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) +{ + struct rtd_gpio *data = gpiochip_get_data(chip); + u32 mask = BIT(offset % 32); + int dato_reg_offset; + u32 val; + + dato_reg_offset = rtd_gpio_dato_offset(data, offset); + + guard(raw_spinlock_irqsave)(&data->lock); + + val = readl_relaxed(data->base + dato_reg_offset); + if (value) + val |= mask; + else + val &= ~mask; + writel_relaxed(val, data->base + dato_reg_offset); +} + +static int rtd_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct rtd_gpio *data = gpiochip_get_data(chip); + int dato_reg_offset = rtd_gpio_dato_offset(data, offset); + int dati_reg_offset = rtd_gpio_dati_offset(data, offset); + int dir_reg_offset = rtd_gpio_dir_offset(data, offset); + int dat_reg_offset; + u32 val; + + guard(raw_spinlock_irqsave)(&data->lock); + + val = readl_relaxed(data->base + dir_reg_offset); + dat_reg_offset = (val & BIT(offset % 32)) ? dato_reg_offset : dati_reg_offset; + val = readl_relaxed(data->base + dat_reg_offset); + + return !!(val & BIT(offset % 32)); +} + +static int rtd_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) +{ + struct rtd_gpio *data = gpiochip_get_data(chip); + int reg_offset; + u32 val; + + reg_offset = rtd_gpio_dir_offset(data, offset); + val = readl_relaxed(data->base + reg_offset); + if (val & BIT(offset % 32)) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; +} + +static int rtd_gpio_set_direction(struct gpio_chip *chip, unsigned int offset, bool out) +{ + struct rtd_gpio *data = gpiochip_get_data(chip); + u32 mask = BIT(offset % 32); + int reg_offset; + u32 val; + + reg_offset = rtd_gpio_dir_offset(data, offset); + + guard(raw_spinlock_irqsave)(&data->lock); + + val = readl_relaxed(data->base + reg_offset); + if (out) + val |= mask; + else + val &= ~mask; + writel_relaxed(val, data->base + reg_offset); + + return 0; +} + +static int rtd_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) +{ + return rtd_gpio_set_direction(chip, offset, false); +} + +static int rtd_gpio_direction_output(struct gpio_chip *chip, unsigned int offset, int value) +{ + rtd_gpio_set(chip, offset, value); + + return rtd_gpio_set_direction(chip, offset, true); +} + +static bool rtd_gpio_check_ie(struct rtd_gpio *data, int irq) +{ + int mask = BIT(irq % 32); + int ie_reg_offset; + u32 enable; + + ie_reg_offset = rtd_gpio_ie_offset(data, irq); + enable = readl_relaxed(data->base + ie_reg_offset); + + return enable & mask; +} + +static void rtd_gpio_irq_handle(struct irq_desc *desc) +{ + int (*get_reg_offset)(struct rtd_gpio *gpio, unsigned int offset); + struct rtd_gpio *data = irq_desc_get_handler_data(desc); + struct irq_domain *domain = data->gpio_chip.irq.domain; + struct irq_chip *chip = irq_desc_get_chip(desc); + unsigned int irq = irq_desc_get_irq(desc); + unsigned long status; + int reg_offset, i, j; + unsigned int hwirq; + + if (irq == data->irqs[0]) + get_reg_offset = &rtd_gpio_gpa_offset; + else if (irq == data->irqs[1]) + get_reg_offset = &rtd_gpio_gpda_offset; + + chained_irq_enter(chip, desc); + + /* Each GPIO interrupt status register contains 31 GPIOs. */ + for (i = 0; i < data->info->num_gpios; i += 31) { + reg_offset = get_reg_offset(data, i); + + /* + * Bit 0 is the write_en bit, bit 0 to 31 corresponds to 31 GPIOs. + * When bit 0 is set to 0, write 1 to the other bits to clear the status. + * When bit 0 is set to 1, write 1 to the other bits to set the status. + */ + status = readl_relaxed(data->irq_base + reg_offset); + status &= ~BIT(0); + writel_relaxed(status, data->irq_base + reg_offset); + + for_each_set_bit(j, &status, 32) { + hwirq = i + j - 1; + if (rtd_gpio_check_ie(data, hwirq)) { + int girq = irq_find_mapping(domain, hwirq); + u32 irq_type = irq_get_trigger_type(girq); + + if ((irq == data->irqs[1]) && (irq_type != IRQ_TYPE_EDGE_BOTH)) + break; + generic_handle_domain_irq(domain, hwirq); + } + } + } + + chained_irq_exit(chip, desc); +} + +static void rtd_gpio_enable_irq(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct rtd_gpio *data = gpiochip_get_data(gc); + irq_hw_number_t hwirq = irqd_to_hwirq(d); + + /* Bit 0 is write_en and bit 1 to 31 is correspond to 31 GPIOs. */ + u32 clr_mask = BIT(hwirq % 31) << 1; + + u32 ie_mask = BIT(hwirq % 32); + int gpda_reg_offset; + int gpa_reg_offset; + int ie_reg_offset; + u32 val; + + ie_reg_offset = rtd_gpio_ie_offset(data, hwirq); + gpa_reg_offset = rtd_gpio_gpa_offset(data, hwirq); + gpda_reg_offset = rtd_gpio_gpda_offset(data, hwirq); + + gpiochip_enable_irq(gc, hwirq); + + guard(raw_spinlock_irqsave)(&data->lock); + + writel_relaxed(clr_mask, data->irq_base + gpa_reg_offset); + writel_relaxed(clr_mask, data->irq_base + gpda_reg_offset); + + val = readl_relaxed(data->base + ie_reg_offset); + val |= ie_mask; + writel_relaxed(val, data->base + ie_reg_offset); +} + +static void rtd_gpio_disable_irq(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct rtd_gpio *data = gpiochip_get_data(gc); + irq_hw_number_t hwirq = irqd_to_hwirq(d); + u32 ie_mask = BIT(hwirq % 32); + int ie_reg_offset; + u32 val; + + ie_reg_offset = rtd_gpio_ie_offset(data, hwirq); + + scoped_guard(raw_spinlock_irqsave, &data->lock) { + val = readl_relaxed(data->base + ie_reg_offset); + val &= ~ie_mask; + writel_relaxed(val, data->base + ie_reg_offset); + } + + gpiochip_disable_irq(gc, hwirq); +} + +static int rtd_gpio_irq_set_type(struct irq_data *d, unsigned int type) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct rtd_gpio *data = gpiochip_get_data(gc); + irq_hw_number_t hwirq = irqd_to_hwirq(d); + u32 mask = BIT(hwirq % 32); + int dp_reg_offset; + bool polarity; + u32 val; + + dp_reg_offset = rtd_gpio_dp_offset(data, hwirq); + + switch (type & IRQ_TYPE_SENSE_MASK) { + case IRQ_TYPE_EDGE_RISING: + polarity = 1; + break; + + case IRQ_TYPE_EDGE_FALLING: + polarity = 0; + break; + + case IRQ_TYPE_EDGE_BOTH: + polarity = 1; + break; + + default: + return -EINVAL; + } + + scoped_guard(raw_spinlock_irqsave, &data->lock) { + val = readl_relaxed(data->base + dp_reg_offset); + if (polarity) + val |= mask; + else + val &= ~mask; + writel_relaxed(val, data->base + dp_reg_offset); + } + + irq_set_handler_locked(d, handle_simple_irq); + + return 0; +} + +static const struct irq_chip rtd_gpio_irq_chip = { + .name = "rtd-gpio", + .irq_enable = rtd_gpio_enable_irq, + .irq_disable = rtd_gpio_disable_irq, + .irq_set_type = rtd_gpio_irq_set_type, + .flags = IRQCHIP_IMMUTABLE, +}; + +static int rtd_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct gpio_irq_chip *irq_chip; + struct rtd_gpio *data; + int ret; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + ret = platform_get_irq(pdev, 0); + if (ret < 0) + return ret; + data->irqs[0] = ret; + + ret = platform_get_irq(pdev, 1); + if (ret < 0) + return ret; + data->irqs[1] = ret; + + data->info = device_get_match_data(dev); + if (!data->info) + return -EINVAL; + + raw_spin_lock_init(&data->lock); + + data->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(data->base)) + return PTR_ERR(data->base); + + data->irq_base = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(data->irq_base)) + return PTR_ERR(data->irq_base); + + data->gpio_chip.label = dev_name(dev); + data->gpio_chip.base = -1; + data->gpio_chip.ngpio = data->info->num_gpios; + data->gpio_chip.request = gpiochip_generic_request; + data->gpio_chip.free = gpiochip_generic_free; + data->gpio_chip.get_direction = rtd_gpio_get_direction; + data->gpio_chip.direction_input = rtd_gpio_direction_input; + data->gpio_chip.direction_output = rtd_gpio_direction_output; + data->gpio_chip.set = rtd_gpio_set; + data->gpio_chip.get = rtd_gpio_get; + data->gpio_chip.set_config = rtd_gpio_set_config; + data->gpio_chip.parent = dev; + + irq_chip = &data->gpio_chip.irq; + irq_chip->handler = handle_bad_irq; + irq_chip->default_type = IRQ_TYPE_NONE; + irq_chip->parent_handler = rtd_gpio_irq_handle; + irq_chip->parent_handler_data = data; + irq_chip->num_parents = 2; + irq_chip->parents = data->irqs; + + gpio_irq_chip_set_chip(irq_chip, &rtd_gpio_irq_chip); + + return devm_gpiochip_add_data(dev, &data->gpio_chip, data); +} + +static const struct of_device_id rtd_gpio_of_matches[] = { + { .compatible = "realtek,rtd1295-misc-gpio", .data = &rtd1295_misc_gpio_info }, + { .compatible = "realtek,rtd1295-iso-gpio", .data = &rtd1295_iso_gpio_info }, + { .compatible = "realtek,rtd1395-iso-gpio", .data = &rtd1395_iso_gpio_info }, + { .compatible = "realtek,rtd1619-iso-gpio", .data = &rtd1619_iso_gpio_info }, + { .compatible = "realtek,rtd1319-iso-gpio", .data = &rtd_iso_gpio_info }, + { .compatible = "realtek,rtd1619b-iso-gpio", .data = &rtd_iso_gpio_info }, + { .compatible = "realtek,rtd1319d-iso-gpio", .data = &rtd_iso_gpio_info }, + { .compatible = "realtek,rtd1315e-iso-gpio", .data = &rtd_iso_gpio_info }, + { } +}; +MODULE_DEVICE_TABLE(of, rtd_gpio_of_matches); + +static struct platform_driver rtd_gpio_platform_driver = { + .driver = { + .name = "gpio-rtd", + .of_match_table = rtd_gpio_of_matches, + }, + .probe = rtd_gpio_probe, +}; +module_platform_driver(rtd_gpio_platform_driver); + +MODULE_DESCRIPTION("Realtek DHC SoC gpio driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-sifive.c b/drivers/gpio/gpio-sifive.c index 8decd9b5d22983..067c8edb62e205 100644 --- a/drivers/gpio/gpio-sifive.c +++ b/drivers/gpio/gpio-sifive.c @@ -250,7 +250,6 @@ static int sifive_gpio_probe(struct platform_device *pdev) girq->handler = handle_bad_irq; girq->default_type = IRQ_TYPE_NONE; - platform_set_drvdata(pdev, chip); return gpiochip_add_data(&chip->gc, chip); } diff --git a/drivers/gpio/gpio-sim.c b/drivers/gpio/gpio-sim.c index 1928209491e1ff..c4106e37e6dba1 100644 --- a/drivers/gpio/gpio-sim.c +++ b/drivers/gpio/gpio-sim.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -224,6 +226,25 @@ static void gpio_sim_free(struct gpio_chip *gc, unsigned int offset) } } +static void gpio_sim_dbg_show(struct seq_file *seq, struct gpio_chip *gc) +{ + struct gpio_sim_chip *chip = gpiochip_get_data(gc); + const char *label; + int i; + + guard(mutex)(&chip->lock); + + for_each_requested_gpio(gc, i, label) + seq_printf(seq, " gpio-%-3d (%s) %s,%s\n", + gc->base + i, + label, + test_bit(i, chip->direction_map) ? "input" : + test_bit(i, chip->value_map) ? "output-high" : + "output-low", + test_bit(i, chip->pull_map) ? "pull-up" : + "pull-down"); +} + static ssize_t gpio_sim_sysfs_val_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -460,6 +481,7 @@ static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev) gc->to_irq = gpio_sim_to_irq; gc->request = gpio_sim_request; gc->free = gpio_sim_free; + gc->dbg_show = PTR_IF(IS_ENABLED(CONFIG_DEBUG_FS), gpio_sim_dbg_show); gc->can_sleep = true; ret = devm_gpiochip_add_data(dev, gc, chip); @@ -1546,6 +1568,6 @@ static void __exit gpio_sim_exit(void) } module_exit(gpio_sim_exit); -MODULE_AUTHOR("Bartosz Golaszewski "); MODULE_DESCRIPTION("GPIO Simulator Module"); MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 27cc4da5356540..6c5ee81d71b3fb 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -5,6 +5,7 @@ * Author: Rabin Vincent for ST-Ericsson */ +#include #include #include #include @@ -255,7 +256,6 @@ static void stmpe_dbg_show_one(struct seq_file *s, { struct stmpe_gpio *stmpe_gpio = gpiochip_get_data(gc); struct stmpe *stmpe = stmpe_gpio->stmpe; - const char *label = gpiochip_is_requested(gc, offset); bool val = !!stmpe_gpio_get(gc, offset); u8 bank = offset / 8; u8 dir_reg = stmpe->regs[STMPE_IDX_GPDR_LSB + bank]; @@ -263,6 +263,10 @@ static void stmpe_dbg_show_one(struct seq_file *s, int ret; u8 dir; + char *label __free(kfree) = gpiochip_dup_line_label(gc, offset); + if (IS_ERR(label)) + return; + ret = stmpe_reg_read(stmpe, dir_reg); if (ret < 0) return; diff --git a/drivers/gpio/gpio-tangier.c b/drivers/gpio/gpio-tangier.c index 7ce3eddaed2572..b75e0b12087ac7 100644 --- a/drivers/gpio/gpio-tangier.c +++ b/drivers/gpio/gpio-tangier.c @@ -10,6 +10,7 @@ */ #include +#include #include #include #include @@ -19,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -91,37 +93,31 @@ static int tng_gpio_get(struct gpio_chip *chip, unsigned int offset) static void tng_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) { struct tng_gpio *priv = gpiochip_get_data(chip); - unsigned long flags; void __iomem *reg; u8 shift; reg = gpio_reg_and_bit(chip, offset, value ? GPSR : GPCR, &shift); - raw_spin_lock_irqsave(&priv->lock, flags); + guard(raw_spinlock_irqsave)(&priv->lock); writel(BIT(shift), reg); - - raw_spin_unlock_irqrestore(&priv->lock, flags); } static int tng_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) { struct tng_gpio *priv = gpiochip_get_data(chip); - unsigned long flags; void __iomem *gpdr; u32 value; u8 shift; gpdr = gpio_reg_and_bit(chip, offset, GPDR, &shift); - raw_spin_lock_irqsave(&priv->lock, flags); + guard(raw_spinlock_irqsave)(&priv->lock); value = readl(gpdr); value &= ~BIT(shift); writel(value, gpdr); - raw_spin_unlock_irqrestore(&priv->lock, flags); - return 0; } @@ -129,21 +125,18 @@ static int tng_gpio_direction_output(struct gpio_chip *chip, unsigned int offset int value) { struct tng_gpio *priv = gpiochip_get_data(chip); - unsigned long flags; void __iomem *gpdr; u8 shift; gpdr = gpio_reg_and_bit(chip, offset, GPDR, &shift); tng_gpio_set(chip, offset, value); - raw_spin_lock_irqsave(&priv->lock, flags); + guard(raw_spinlock_irqsave)(&priv->lock); value = readl(gpdr); value |= BIT(shift); writel(value, gpdr); - raw_spin_unlock_irqrestore(&priv->lock, flags); - return 0; } @@ -164,14 +157,13 @@ static int tng_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset, unsigned int debounce) { struct tng_gpio *priv = gpiochip_get_data(chip); - unsigned long flags; void __iomem *gfbr; u32 value; u8 shift; gfbr = gpio_reg_and_bit(chip, offset, GFBR, &shift); - raw_spin_lock_irqsave(&priv->lock, flags); + guard(raw_spinlock_irqsave)(&priv->lock); value = readl(gfbr); if (debounce) @@ -180,8 +172,6 @@ static int tng_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset, value |= BIT(shift); writel(value, gfbr); - raw_spin_unlock_irqrestore(&priv->lock, flags); - return 0; } @@ -207,27 +197,25 @@ static void tng_irq_ack(struct irq_data *d) { struct tng_gpio *priv = irq_data_get_irq_chip_data(d); irq_hw_number_t gpio = irqd_to_hwirq(d); - unsigned long flags; void __iomem *gisr; u8 shift; gisr = gpio_reg_and_bit(&priv->chip, gpio, GISR, &shift); - raw_spin_lock_irqsave(&priv->lock, flags); + guard(raw_spinlock_irqsave)(&priv->lock); + writel(BIT(shift), gisr); - raw_spin_unlock_irqrestore(&priv->lock, flags); } static void tng_irq_unmask_mask(struct tng_gpio *priv, u32 gpio, bool unmask) { - unsigned long flags; void __iomem *gimr; u32 value; u8 shift; gimr = gpio_reg_and_bit(&priv->chip, gpio, GIMR, &shift); - raw_spin_lock_irqsave(&priv->lock, flags); + guard(raw_spinlock_irqsave)(&priv->lock); value = readl(gimr); if (unmask) @@ -235,8 +223,6 @@ static void tng_irq_unmask_mask(struct tng_gpio *priv, u32 gpio, bool unmask) else value &= ~BIT(shift); writel(value, gimr); - - raw_spin_unlock_irqrestore(&priv->lock, flags); } static void tng_irq_mask(struct irq_data *d) @@ -267,10 +253,9 @@ static int tng_irq_set_type(struct irq_data *d, unsigned int type) void __iomem *gitr = gpio_reg(&priv->chip, gpio, GITR); void __iomem *glpr = gpio_reg(&priv->chip, gpio, GLPR); u8 shift = gpio % 32; - unsigned long flags; u32 value; - raw_spin_lock_irqsave(&priv->lock, flags); + guard(raw_spinlock_irqsave)(&priv->lock); value = readl(grer); if (type & IRQ_TYPE_EDGE_RISING) @@ -311,8 +296,6 @@ static int tng_irq_set_type(struct irq_data *d, unsigned int type) irq_set_handler_locked(d, handle_edge_irq); } - raw_spin_unlock_irqrestore(&priv->lock, flags); - return 0; } @@ -324,10 +307,11 @@ static int tng_irq_set_wake(struct irq_data *d, unsigned int on) void __iomem *gwmr = gpio_reg(&priv->chip, gpio, priv->wake_regs.gwmr); void __iomem *gwsr = gpio_reg(&priv->chip, gpio, priv->wake_regs.gwsr); u8 shift = gpio % 32; - unsigned long flags; u32 value; - raw_spin_lock_irqsave(&priv->lock, flags); + dev_dbg(priv->dev, "%s wake for gpio %lu\n", str_enable_disable(on), gpio); + + guard(raw_spinlock_irqsave)(&priv->lock); /* Clear the existing wake status */ writel(BIT(shift), gwsr); @@ -339,9 +323,6 @@ static int tng_irq_set_wake(struct irq_data *d, unsigned int on) value &= ~BIT(shift); writel(value, gwmr); - raw_spin_unlock_irqrestore(&priv->lock, flags); - - dev_dbg(priv->dev, "%s wake for gpio %lu\n", str_enable_disable(on), gpio); return 0; } @@ -477,14 +458,13 @@ int devm_tng_gpio_probe(struct device *dev, struct tng_gpio *gpio) } EXPORT_SYMBOL_NS_GPL(devm_tng_gpio_probe, GPIO_TANGIER); -int tng_gpio_suspend(struct device *dev) +static int tng_gpio_suspend(struct device *dev) { struct tng_gpio *priv = dev_get_drvdata(dev); struct tng_gpio_context *ctx = priv->ctx; - unsigned long flags; unsigned int base; - raw_spin_lock_irqsave(&priv->lock, flags); + guard(raw_spinlock_irqsave)(&priv->lock); for (base = 0; base < priv->chip.ngpio; base += 32, ctx++) { /* GPLR is RO, values read will be restored using GPSR */ @@ -498,20 +478,16 @@ int tng_gpio_suspend(struct device *dev) ctx->gwmr = readl(gpio_reg(&priv->chip, base, priv->wake_regs.gwmr)); } - raw_spin_unlock_irqrestore(&priv->lock, flags); - return 0; } -EXPORT_SYMBOL_NS_GPL(tng_gpio_suspend, GPIO_TANGIER); -int tng_gpio_resume(struct device *dev) +static int tng_gpio_resume(struct device *dev) { struct tng_gpio *priv = dev_get_drvdata(dev); struct tng_gpio_context *ctx = priv->ctx; - unsigned long flags; unsigned int base; - raw_spin_lock_irqsave(&priv->lock, flags); + guard(raw_spinlock_irqsave)(&priv->lock); for (base = 0; base < priv->chip.ngpio; base += 32, ctx++) { /* GPLR is RO, values read will be restored using GPSR */ @@ -525,11 +501,10 @@ int tng_gpio_resume(struct device *dev) writel(ctx->gwmr, gpio_reg(&priv->chip, base, priv->wake_regs.gwmr)); } - raw_spin_unlock_irqrestore(&priv->lock, flags); - return 0; } -EXPORT_SYMBOL_NS_GPL(tng_gpio_resume, GPIO_TANGIER); + +EXPORT_NS_GPL_SIMPLE_DEV_PM_OPS(tng_gpio_pm_ops, tng_gpio_suspend, tng_gpio_resume, GPIO_TANGIER); MODULE_AUTHOR("Andy Shevchenko "); MODULE_AUTHOR("Pandith N "); diff --git a/drivers/gpio/gpio-tangier.h b/drivers/gpio/gpio-tangier.h index 16c4f22908fb51..ca7ab6cf6fa53a 100644 --- a/drivers/gpio/gpio-tangier.h +++ b/drivers/gpio/gpio-tangier.h @@ -13,6 +13,7 @@ #define _GPIO_TANGIER_H_ #include +#include #include #include @@ -111,7 +112,6 @@ struct tng_gpio { int devm_tng_gpio_probe(struct device *dev, struct tng_gpio *gpio); -int tng_gpio_suspend(struct device *dev); -int tng_gpio_resume(struct device *dev); +extern const struct dev_pm_ops tng_gpio_pm_ops; #endif /* _GPIO_TANGIER_H_ */ diff --git a/drivers/gpio/gpio-tps65219.c b/drivers/gpio/gpio-tps65219.c index 7b38aa36011284..cd1f17041f8c04 100644 --- a/drivers/gpio/gpio-tps65219.c +++ b/drivers/gpio/gpio-tps65219.c @@ -96,16 +96,16 @@ static int tps65219_gpio_change_direction(struct gpio_chip *gc, unsigned int off * Below can be used for test purpose only. */ - if (IS_ENABLED(CONFIG_DEBUG_GPIO)) { - int ret = regmap_update_bits(gpio->tps->regmap, TPS65219_REG_MFP_1_CONFIG, - TPS65219_GPIO0_DIR_MASK, direction); - if (ret) { - dev_err(dev, - "GPIO DEBUG enabled: Fail to change direction to %u for GPIO%d.\n", - direction, offset); - return ret; - } +#if 0 + int ret = regmap_update_bits(gpio->tps->regmap, TPS65219_REG_MFP_1_CONFIG, + TPS65219_GPIO0_DIR_MASK, direction); + if (ret) { + dev_err(dev, + "GPIO DEBUG enabled: Fail to change direction to %u for GPIO%d.\n", + direction, offset); + return ret; } +#endif dev_err(dev, "GPIO%d direction set by NVM, change to %u failed, not allowed by specification\n", diff --git a/drivers/gpio/gpio-wm831x.c b/drivers/gpio/gpio-wm831x.c index 7eaf8a28638cf3..f7d5120ff8f13e 100644 --- a/drivers/gpio/gpio-wm831x.c +++ b/drivers/gpio/gpio-wm831x.c @@ -8,6 +8,7 @@ * */ +#include #include #include #include @@ -160,18 +161,21 @@ static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) for (i = 0; i < chip->ngpio; i++) { int gpio = i + chip->base; int reg; - const char *label, *pull, *powerdomain; + const char *pull, *powerdomain; /* We report the GPIO even if it's not requested since * we're also reporting things like alternate * functions which apply even when the GPIO is not in * use as a GPIO. */ - label = gpiochip_is_requested(chip, i); - if (!label) - label = "Unrequested"; + char *label __free(kfree) = gpiochip_dup_line_label(chip, i); + if (IS_ERR(label)) { + dev_err(wm831x->dev, "Failed to duplicate label\n"); + continue; + } - seq_printf(s, " gpio-%-3d (%-20.20s) ", gpio, label); + seq_printf(s, " gpio-%-3d (%-20.20s) ", + gpio, label ?: "Unrequested"); reg = wm831x_reg_read(wm831x, WM831X_GPIO1_CONTROL + i); if (reg < 0) { diff --git a/drivers/gpio/gpio-wm8994.c b/drivers/gpio/gpio-wm8994.c index f4a474cef32d87..bf05c9b5882b89 100644 --- a/drivers/gpio/gpio-wm8994.c +++ b/drivers/gpio/gpio-wm8994.c @@ -8,6 +8,7 @@ * */ +#include #include #include #include @@ -193,18 +194,20 @@ static void wm8994_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) for (i = 0; i < chip->ngpio; i++) { int gpio = i + chip->base; int reg; - const char *label; /* We report the GPIO even if it's not requested since * we're also reporting things like alternate * functions which apply even when the GPIO is not in * use as a GPIO. */ - label = gpiochip_is_requested(chip, i); - if (!label) - label = "Unrequested"; + char *label __free(kfree) = gpiochip_dup_line_label(chip, i); + if (IS_ERR(label)) { + dev_err(wm8994->dev, "Failed to duplicate label\n"); + continue; + } - seq_printf(s, " gpio-%-3d (%-20.20s) ", gpio, label); + seq_printf(s, " gpio-%-3d (%-20.20s) ", gpio, + label ?: "Unrequested"); reg = wm8994_reg_read(wm8994, WM8994_GPIO_1 + i); if (reg < 0) { diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index 82319836825042..7348df38519815 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -52,7 +52,6 @@ * @dir: GPIO direction shadow register * @gpio_lock: Lock used for synchronization * @irq: IRQ used by GPIO device - * @irqchip: IRQ chip * @enable: GPIO IRQ enable/disable bitfield * @rising_edge: GPIO IRQ rising edge enable/disable bitfield * @falling_edge: GPIO IRQ falling edge enable/disable bitfield diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index 88066826d8e5b6..cd3e9657cc36df 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -1651,6 +1651,20 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] __initconst = { .ignore_interrupt = "INT33FC:00@3", }, }, + { + /* + * Spurious wakeups from TP_ATTN# pin + * Found in BIOS 0.35 + * https://gitlab.freedesktop.org/drm/amd/-/issues/3073 + */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "GPD"), + DMI_MATCH(DMI_PRODUCT_NAME, "G1619-04"), + }, + .driver_data = &(struct acpi_gpiolib_dmi_quirk) { + .ignore_wake = "PNP0C50:00@8", + }, + }, {} /* Terminating entry */ }; diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c index f713d1ef7746e4..2a88736629ef3c 100644 --- a/drivers/gpio/gpiolib-cdev.c +++ b/drivers/gpio/gpiolib-cdev.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -19,8 +20,11 @@ #include #include #include +#include #include #include +#include +#include #include #include #include @@ -62,45 +66,6 @@ typedef long (*ioctl_fn)(struct file *, unsigned int, unsigned long); typedef ssize_t (*read_fn)(struct file *, char __user *, size_t count, loff_t *); -static __poll_t call_poll_locked(struct file *file, - struct poll_table_struct *wait, - struct gpio_device *gdev, poll_fn func) -{ - __poll_t ret; - - down_read(&gdev->sem); - ret = func(file, wait); - up_read(&gdev->sem); - - return ret; -} - -static long call_ioctl_locked(struct file *file, unsigned int cmd, - unsigned long arg, struct gpio_device *gdev, - ioctl_fn func) -{ - long ret; - - down_read(&gdev->sem); - ret = func(file, cmd, arg); - up_read(&gdev->sem); - - return ret; -} - -static ssize_t call_read_locked(struct file *file, char __user *buf, - size_t count, loff_t *f_ps, - struct gpio_device *gdev, read_fn func) -{ - ssize_t ret; - - down_read(&gdev->sem); - ret = func(file, buf, count, f_ps); - up_read(&gdev->sem); - - return ret; -} - /* * GPIO line handle management */ @@ -235,8 +200,8 @@ static long linehandle_set_config(struct linehandle_state *lh, return 0; } -static long linehandle_ioctl_unlocked(struct file *file, unsigned int cmd, - unsigned long arg) +static long linehandle_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) { struct linehandle_state *lh = file->private_data; void __user *ip = (void __user *)arg; @@ -245,6 +210,8 @@ static long linehandle_ioctl_unlocked(struct file *file, unsigned int cmd, unsigned int i; int ret; + guard(rwsem_read)(&lh->gdev->sem); + if (!lh->gdev->chip) return -ENODEV; @@ -294,15 +261,6 @@ static long linehandle_ioctl_unlocked(struct file *file, unsigned int cmd, } } -static long linehandle_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct linehandle_state *lh = file->private_data; - - return call_ioctl_locked(file, cmd, arg, lh->gdev, - linehandle_ioctl_unlocked); -} - #ifdef CONFIG_COMPAT static long linehandle_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) @@ -461,6 +419,7 @@ out_free_lh: /** * struct line - contains the state of a requested line + * @node: to store the object in supinfo_tree if supplemental * @desc: the GPIO descriptor for this line. * @req: the corresponding line request * @irq: the interrupt triggered in response to events on this GPIO @@ -473,6 +432,7 @@ out_free_lh: * @line_seqno: the seqno for the current edge event in the sequence of * events for this line. * @work: the worker that implements software debouncing + * @debounce_period_us: the debounce period in microseconds * @sw_debounced: flag indicating if the software debouncer is active * @level: the current debounced physical level of the line * @hdesc: the Hardware Timestamp Engine (HTE) descriptor @@ -481,6 +441,7 @@ out_free_lh: * @last_seqno: the last sequence number before debounce period expires */ struct line { + struct rb_node node; struct gpio_desc *desc; /* * -- edge detector specific fields -- @@ -514,6 +475,15 @@ struct line { * -- debouncer specific fields -- */ struct delayed_work work; + /* + * debounce_period_us is accessed by debounce_irq_handler() and + * process_hw_ts() which are disabled when modified by + * debounce_setup(), edge_detector_setup() or edge_detector_stop() + * or can live with a stale version when updated by + * edge_detector_update(). + * The modifying functions are themselves mutually exclusive. + */ + unsigned int debounce_period_us; /* * sw_debounce is accessed by linereq_set_config(), which is the * only setter, and linereq_get_values(), which can live with a @@ -546,6 +516,17 @@ struct line { #endif /* CONFIG_HTE */ }; +/* + * a rbtree of the struct lines containing supplemental info. + * Used to populate gpio_v2_line_info with cdev specific fields not contained + * in the struct gpio_desc. + * A line is determined to contain supplemental information by + * line_has_supinfo(). + */ +static struct rb_root supinfo_tree = RB_ROOT; +/* covers supinfo_tree */ +static DEFINE_SPINLOCK(supinfo_lock); + /** * struct linereq - contains the state of a userspace line request * @gdev: the GPIO device the line request pertains to @@ -559,7 +540,8 @@ struct line { * this line request. Note that this is not used when @num_lines is 1, as * the line_seqno is then the same and is cheaper to calculate. * @config_mutex: mutex for serializing ioctl() calls to ensure consistency - * of configuration, particularly multi-step accesses to desc flags. + * of configuration, particularly multi-step accesses to desc flags and + * changes to supinfo status. * @lines: the lines held by this line request, with @num_lines elements. */ struct linereq { @@ -575,6 +557,103 @@ struct linereq { struct line lines[] __counted_by(num_lines); }; +static void supinfo_insert(struct line *line) +{ + struct rb_node **new = &(supinfo_tree.rb_node), *parent = NULL; + struct line *entry; + + guard(spinlock)(&supinfo_lock); + + while (*new) { + entry = container_of(*new, struct line, node); + + parent = *new; + if (line->desc < entry->desc) { + new = &((*new)->rb_left); + } else if (line->desc > entry->desc) { + new = &((*new)->rb_right); + } else { + /* this should never happen */ + WARN(1, "duplicate line inserted"); + return; + } + } + + rb_link_node(&line->node, parent, new); + rb_insert_color(&line->node, &supinfo_tree); +} + +static void supinfo_erase(struct line *line) +{ + guard(spinlock)(&supinfo_lock); + + rb_erase(&line->node, &supinfo_tree); +} + +static struct line *supinfo_find(struct gpio_desc *desc) +{ + struct rb_node *node = supinfo_tree.rb_node; + struct line *line; + + while (node) { + line = container_of(node, struct line, node); + if (desc < line->desc) + node = node->rb_left; + else if (desc > line->desc) + node = node->rb_right; + else + return line; + } + return NULL; +} + +static void supinfo_to_lineinfo(struct gpio_desc *desc, + struct gpio_v2_line_info *info) +{ + struct gpio_v2_line_attribute *attr; + struct line *line; + + guard(spinlock)(&supinfo_lock); + + line = supinfo_find(desc); + if (!line) + return; + + attr = &info->attrs[info->num_attrs]; + attr->id = GPIO_V2_LINE_ATTR_ID_DEBOUNCE; + attr->debounce_period_us = READ_ONCE(line->debounce_period_us); + info->num_attrs++; +} + +static inline bool line_has_supinfo(struct line *line) +{ + return READ_ONCE(line->debounce_period_us); +} + +/* + * Checks line_has_supinfo() before and after the change to avoid unnecessary + * supinfo_tree access. + * Called indirectly by linereq_create() or linereq_set_config() so line + * is already protected from concurrent changes. + */ +static void line_set_debounce_period(struct line *line, + unsigned int debounce_period_us) +{ + bool was_suppl = line_has_supinfo(line); + + WRITE_ONCE(line->debounce_period_us, debounce_period_us); + + /* if supinfo status is unchanged then we're done */ + if (line_has_supinfo(line) == was_suppl) + return; + + /* supinfo status has changed, so update the tree */ + if (was_suppl) + supinfo_erase(line); + else + supinfo_insert(line); +} + #define GPIO_V2_LINE_BIAS_FLAGS \ (GPIO_V2_LINE_FLAG_BIAS_PULL_UP | \ GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN | \ @@ -625,13 +704,13 @@ static void linereq_put_event(struct linereq *lr, { bool overflow = false; - spin_lock(&lr->wait.lock); - if (kfifo_is_full(&lr->events)) { - overflow = true; - kfifo_skip(&lr->events); + scoped_guard(spinlock, &lr->wait.lock) { + if (kfifo_is_full(&lr->events)) { + overflow = true; + kfifo_skip(&lr->events); + } + kfifo_in(&lr->events, le, 1); } - kfifo_in(&lr->events, le, 1); - spin_unlock(&lr->wait.lock); if (!overflow) wake_up_poll(&lr->wait, EPOLLIN); else @@ -723,7 +802,7 @@ static enum hte_return process_hw_ts(struct hte_ts_data *ts, void *p) line->total_discard_seq++; line->last_seqno = ts->seq; mod_delayed_work(system_wq, &line->work, - usecs_to_jiffies(READ_ONCE(line->desc->debounce_period_us))); + usecs_to_jiffies(READ_ONCE(line->debounce_period_us))); } else { if (unlikely(ts->seq < line->line_seqno)) return HTE_CB_HANDLED; @@ -864,7 +943,7 @@ static irqreturn_t debounce_irq_handler(int irq, void *p) struct line *line = p; mod_delayed_work(system_wq, &line->work, - usecs_to_jiffies(READ_ONCE(line->desc->debounce_period_us))); + usecs_to_jiffies(READ_ONCE(line->debounce_period_us))); return IRQ_HANDLED; } @@ -946,7 +1025,7 @@ static int debounce_setup(struct line *line, unsigned int debounce_period_us) /* try hardware */ ret = gpiod_set_debounce(line->desc, debounce_period_us); if (!ret) { - WRITE_ONCE(line->desc->debounce_period_us, debounce_period_us); + line_set_debounce_period(line, debounce_period_us); return ret; } if (ret != -ENOTSUPP) @@ -1025,8 +1104,7 @@ static void edge_detector_stop(struct line *line) cancel_delayed_work_sync(&line->work); WRITE_ONCE(line->sw_debounced, 0); WRITE_ONCE(line->edflags, 0); - if (line->desc) - WRITE_ONCE(line->desc->debounce_period_us, 0); + line_set_debounce_period(line, 0); /* do not change line->level - see comment in debounced_value() */ } @@ -1051,7 +1129,7 @@ static int edge_detector_setup(struct line *line, ret = debounce_setup(line, debounce_period_us); if (ret) return ret; - WRITE_ONCE(line->desc->debounce_period_us, debounce_period_us); + line_set_debounce_period(line, debounce_period_us); } /* detection disabled or sw debouncer will provide edge detection */ @@ -1093,12 +1171,12 @@ static int edge_detector_update(struct line *line, gpio_v2_line_config_debounce_period(lc, line_idx); if ((active_edflags == edflags) && - (READ_ONCE(line->desc->debounce_period_us) == debounce_period_us)) + (READ_ONCE(line->debounce_period_us) == debounce_period_us)) return 0; /* sw debounced and still will be...*/ if (debounce_period_us && READ_ONCE(line->sw_debounced)) { - WRITE_ONCE(line->desc->debounce_period_us, debounce_period_us); + line_set_debounce_period(line, debounce_period_us); return 0; } @@ -1272,9 +1350,18 @@ static long linereq_get_values(struct linereq *lr, void __user *ip) if (copy_from_user(&lv, ip, sizeof(lv))) return -EFAULT; + /* + * gpiod_get_array_value_complex() requires compacted desc and val + * arrays, rather than the sparse ones in lv. + * Calculation of num_get and construction of the desc array is + * optimized to avoid allocation for the desc array for the common + * num_get == 1 case. + */ + /* scan requested lines to calculate the subset to get */ for (num_get = 0, i = 0; i < lr->num_lines; i++) { if (lv.mask & BIT_ULL(i)) { num_get++; + /* capture desc for the num_get == 1 case */ descs = &lr->lines[i].desc; } } @@ -1283,6 +1370,7 @@ static long linereq_get_values(struct linereq *lr, void __user *ip) return -EINVAL; if (num_get != 1) { + /* build compacted desc array */ descs = kmalloc_array(num_get, sizeof(*descs), GFP_KERNEL); if (!descs) return -ENOMEM; @@ -1303,6 +1391,7 @@ static long linereq_get_values(struct linereq *lr, void __user *ip) lv.bits = 0; for (didx = 0, i = 0; i < lr->num_lines; i++) { + /* unpack compacted vals for the response */ if (lv.mask & BIT_ULL(i)) { if (lr->lines[i].sw_debounced) val = debounced_value(&lr->lines[i]); @@ -1320,22 +1409,38 @@ static long linereq_get_values(struct linereq *lr, void __user *ip) return 0; } -static long linereq_set_values_unlocked(struct linereq *lr, - struct gpio_v2_line_values *lv) +static long linereq_set_values(struct linereq *lr, void __user *ip) { DECLARE_BITMAP(vals, GPIO_V2_LINES_MAX); + struct gpio_v2_line_values lv; struct gpio_desc **descs; unsigned int i, didx, num_set; int ret; + if (copy_from_user(&lv, ip, sizeof(lv))) + return -EFAULT; + + guard(mutex)(&lr->config_mutex); + + /* + * gpiod_set_array_value_complex() requires compacted desc and val + * arrays, rather than the sparse ones in lv. + * Calculation of num_set and construction of the descs and vals arrays + * is optimized to minimize scanning the lv->mask, and to avoid + * allocation for the desc array for the common num_set == 1 case. + */ bitmap_zero(vals, GPIO_V2_LINES_MAX); + /* scan requested lines to determine the subset to be set */ for (num_set = 0, i = 0; i < lr->num_lines; i++) { - if (lv->mask & BIT_ULL(i)) { + if (lv.mask & BIT_ULL(i)) { + /* setting inputs is not allowed */ if (!test_bit(FLAG_IS_OUT, &lr->lines[i].desc->flags)) return -EPERM; - if (lv->bits & BIT_ULL(i)) + /* add to compacted values */ + if (lv.bits & BIT_ULL(i)) __set_bit(num_set, vals); num_set++; + /* capture desc for the num_set == 1 case */ descs = &lr->lines[i].desc; } } @@ -1343,12 +1448,12 @@ static long linereq_set_values_unlocked(struct linereq *lr, return -EINVAL; if (num_set != 1) { - /* build compacted desc array and values */ + /* build compacted desc array */ descs = kmalloc_array(num_set, sizeof(*descs), GFP_KERNEL); if (!descs) return -ENOMEM; for (didx = 0, i = 0; i < lr->num_lines; i++) { - if (lv->mask & BIT_ULL(i)) { + if (lv.mask & BIT_ULL(i)) { descs[didx] = lr->lines[i].desc; didx++; } @@ -1362,36 +1467,28 @@ static long linereq_set_values_unlocked(struct linereq *lr, return ret; } -static long linereq_set_values(struct linereq *lr, void __user *ip) -{ - struct gpio_v2_line_values lv; - int ret; - - if (copy_from_user(&lv, ip, sizeof(lv))) - return -EFAULT; - - mutex_lock(&lr->config_mutex); - - ret = linereq_set_values_unlocked(lr, &lv); - - mutex_unlock(&lr->config_mutex); - - return ret; -} - -static long linereq_set_config_unlocked(struct linereq *lr, - struct gpio_v2_line_config *lc) +static long linereq_set_config(struct linereq *lr, void __user *ip) { + struct gpio_v2_line_config lc; struct gpio_desc *desc; struct line *line; unsigned int i; u64 flags, edflags; int ret; + if (copy_from_user(&lc, ip, sizeof(lc))) + return -EFAULT; + + ret = gpio_v2_line_config_validate(&lc, lr->num_lines); + if (ret) + return ret; + + guard(mutex)(&lr->config_mutex); + for (i = 0; i < lr->num_lines; i++) { line = &lr->lines[i]; desc = lr->lines[i].desc; - flags = gpio_v2_line_config_flags(lc, i); + flags = gpio_v2_line_config_flags(&lc, i); gpio_v2_line_config_flags_to_desc_flags(flags, &desc->flags); edflags = flags & GPIO_V2_LINE_EDGE_DETECTOR_FLAGS; /* @@ -1399,7 +1496,7 @@ static long linereq_set_config_unlocked(struct linereq *lr, * or output, else the line will be treated "as is". */ if (flags & GPIO_V2_LINE_FLAG_OUTPUT) { - int val = gpio_v2_line_config_output_value(lc, i); + int val = gpio_v2_line_config_output_value(&lc, i); edge_detector_stop(line); ret = gpiod_direction_output(desc, val); @@ -1410,7 +1507,7 @@ static long linereq_set_config_unlocked(struct linereq *lr, if (ret) return ret; - ret = edge_detector_update(line, lc, i, edflags); + ret = edge_detector_update(line, &lc, i, edflags); if (ret) return ret; } @@ -1422,33 +1519,14 @@ static long linereq_set_config_unlocked(struct linereq *lr, return 0; } -static long linereq_set_config(struct linereq *lr, void __user *ip) -{ - struct gpio_v2_line_config lc; - int ret; - - if (copy_from_user(&lc, ip, sizeof(lc))) - return -EFAULT; - - ret = gpio_v2_line_config_validate(&lc, lr->num_lines); - if (ret) - return ret; - - mutex_lock(&lr->config_mutex); - - ret = linereq_set_config_unlocked(lr, &lc); - - mutex_unlock(&lr->config_mutex); - - return ret; -} - -static long linereq_ioctl_unlocked(struct file *file, unsigned int cmd, - unsigned long arg) +static long linereq_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) { struct linereq *lr = file->private_data; void __user *ip = (void __user *)arg; + guard(rwsem_read)(&lr->gdev->sem); + if (!lr->gdev->chip) return -ENODEV; @@ -1464,15 +1542,6 @@ static long linereq_ioctl_unlocked(struct file *file, unsigned int cmd, } } -static long linereq_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct linereq *lr = file->private_data; - - return call_ioctl_locked(file, cmd, arg, lr->gdev, - linereq_ioctl_unlocked); -} - #ifdef CONFIG_COMPAT static long linereq_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) @@ -1481,12 +1550,14 @@ static long linereq_ioctl_compat(struct file *file, unsigned int cmd, } #endif -static __poll_t linereq_poll_unlocked(struct file *file, - struct poll_table_struct *wait) +static __poll_t linereq_poll(struct file *file, + struct poll_table_struct *wait) { struct linereq *lr = file->private_data; __poll_t events = 0; + guard(rwsem_read)(&lr->gdev->sem); + if (!lr->gdev->chip) return EPOLLHUP | EPOLLERR; @@ -1499,22 +1570,16 @@ static __poll_t linereq_poll_unlocked(struct file *file, return events; } -static __poll_t linereq_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct linereq *lr = file->private_data; - - return call_poll_locked(file, wait, lr->gdev, linereq_poll_unlocked); -} - -static ssize_t linereq_read_unlocked(struct file *file, char __user *buf, - size_t count, loff_t *f_ps) +static ssize_t linereq_read(struct file *file, char __user *buf, + size_t count, loff_t *f_ps) { struct linereq *lr = file->private_data; struct gpio_v2_line_event le; ssize_t bytes_read = 0; int ret; + guard(rwsem_read)(&lr->gdev->sem); + if (!lr->gdev->chip) return -ENODEV; @@ -1522,28 +1587,22 @@ static ssize_t linereq_read_unlocked(struct file *file, char __user *buf, return -EINVAL; do { - spin_lock(&lr->wait.lock); - if (kfifo_is_empty(&lr->events)) { - if (bytes_read) { - spin_unlock(&lr->wait.lock); - return bytes_read; + scoped_guard(spinlock, &lr->wait.lock) { + if (kfifo_is_empty(&lr->events)) { + if (bytes_read) + return bytes_read; + + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + + ret = wait_event_interruptible_locked(lr->wait, + !kfifo_is_empty(&lr->events)); + if (ret) + return ret; } - if (file->f_flags & O_NONBLOCK) { - spin_unlock(&lr->wait.lock); - return -EAGAIN; - } - - ret = wait_event_interruptible_locked(lr->wait, - !kfifo_is_empty(&lr->events)); - if (ret) { - spin_unlock(&lr->wait.lock); - return ret; - } + ret = kfifo_out(&lr->events, &le, 1); } - - ret = kfifo_out(&lr->events, &le, 1); - spin_unlock(&lr->wait.lock); if (ret != 1) { /* * This should never happen - we were holding the @@ -1562,17 +1621,9 @@ static ssize_t linereq_read_unlocked(struct file *file, char __user *buf, return bytes_read; } -static ssize_t linereq_read(struct file *file, char __user *buf, - size_t count, loff_t *f_ps) -{ - struct linereq *lr = file->private_data; - - return call_read_locked(file, buf, count, f_ps, lr->gdev, - linereq_read_unlocked); -} - static void linereq_free(struct linereq *lr) { + struct line *line; unsigned int i; if (lr->device_unregistered_nb.notifier_call) @@ -1580,15 +1631,19 @@ static void linereq_free(struct linereq *lr) &lr->device_unregistered_nb); for (i = 0; i < lr->num_lines; i++) { - if (lr->lines[i].desc) { - edge_detector_stop(&lr->lines[i]); - gpiod_free(lr->lines[i].desc); - } + line = &lr->lines[i]; + if (!line->desc) + continue; + + edge_detector_stop(line); + if (line_has_supinfo(line)) + supinfo_erase(line); + gpiod_free(line->desc); } kfifo_free(&lr->events); kfree(lr->label); gpio_device_put(lr->gdev); - kfree(lr); + kvfree(lr); } static int linereq_release(struct inode *inode, struct file *file) @@ -1653,7 +1708,7 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip) if (ret) return ret; - lr = kzalloc(struct_size(lr, lines, ulr.num_lines), GFP_KERNEL); + lr = kvzalloc(struct_size(lr, lines, ulr.num_lines), GFP_KERNEL); if (!lr) return -ENOMEM; lr->num_lines = ulr.num_lines; @@ -1818,12 +1873,14 @@ struct lineevent_state { (GPIOEVENT_REQUEST_RISING_EDGE | \ GPIOEVENT_REQUEST_FALLING_EDGE) -static __poll_t lineevent_poll_unlocked(struct file *file, - struct poll_table_struct *wait) +static __poll_t lineevent_poll(struct file *file, + struct poll_table_struct *wait) { struct lineevent_state *le = file->private_data; __poll_t events = 0; + guard(rwsem_read)(&le->gdev->sem); + if (!le->gdev->chip) return EPOLLHUP | EPOLLERR; @@ -1835,14 +1892,6 @@ static __poll_t lineevent_poll_unlocked(struct file *file, return events; } -static __poll_t lineevent_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct lineevent_state *le = file->private_data; - - return call_poll_locked(file, wait, le->gdev, lineevent_poll_unlocked); -} - static int lineevent_unregistered_notify(struct notifier_block *nb, unsigned long action, void *data) { @@ -1859,8 +1908,8 @@ struct compat_gpioeevent_data { u32 id; }; -static ssize_t lineevent_read_unlocked(struct file *file, char __user *buf, - size_t count, loff_t *f_ps) +static ssize_t lineevent_read(struct file *file, char __user *buf, + size_t count, loff_t *f_ps) { struct lineevent_state *le = file->private_data; struct gpioevent_data ge; @@ -1868,6 +1917,8 @@ static ssize_t lineevent_read_unlocked(struct file *file, char __user *buf, ssize_t ge_size; int ret; + guard(rwsem_read)(&le->gdev->sem); + if (!le->gdev->chip) return -ENODEV; @@ -1888,28 +1939,22 @@ static ssize_t lineevent_read_unlocked(struct file *file, char __user *buf, return -EINVAL; do { - spin_lock(&le->wait.lock); - if (kfifo_is_empty(&le->events)) { - if (bytes_read) { - spin_unlock(&le->wait.lock); - return bytes_read; + scoped_guard(spinlock, &le->wait.lock) { + if (kfifo_is_empty(&le->events)) { + if (bytes_read) + return bytes_read; + + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + + ret = wait_event_interruptible_locked(le->wait, + !kfifo_is_empty(&le->events)); + if (ret) + return ret; } - if (file->f_flags & O_NONBLOCK) { - spin_unlock(&le->wait.lock); - return -EAGAIN; - } - - ret = wait_event_interruptible_locked(le->wait, - !kfifo_is_empty(&le->events)); - if (ret) { - spin_unlock(&le->wait.lock); - return ret; - } + ret = kfifo_out(&le->events, &ge, 1); } - - ret = kfifo_out(&le->events, &ge, 1); - spin_unlock(&le->wait.lock); if (ret != 1) { /* * This should never happen - we were holding the lock @@ -1928,15 +1973,6 @@ static ssize_t lineevent_read_unlocked(struct file *file, char __user *buf, return bytes_read; } -static ssize_t lineevent_read(struct file *file, char __user *buf, - size_t count, loff_t *f_ps) -{ - struct lineevent_state *le = file->private_data; - - return call_read_locked(file, buf, count, f_ps, le->gdev, - lineevent_read_unlocked); -} - static void lineevent_free(struct lineevent_state *le) { if (le->device_unregistered_nb.notifier_call) @@ -1957,13 +1993,15 @@ static int lineevent_release(struct inode *inode, struct file *file) return 0; } -static long lineevent_ioctl_unlocked(struct file *file, unsigned int cmd, - unsigned long arg) +static long lineevent_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) { struct lineevent_state *le = file->private_data; void __user *ip = (void __user *)arg; struct gpiohandle_data ghd; + guard(rwsem_read)(&le->gdev->sem); + if (!le->gdev->chip) return -ENODEV; @@ -1989,15 +2027,6 @@ static long lineevent_ioctl_unlocked(struct file *file, unsigned int cmd, return -EINVAL; } -static long lineevent_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct lineevent_state *le = file->private_data; - - return call_ioctl_locked(file, cmd, arg, le->gdev, - lineevent_ioctl_unlocked); -} - #ifdef CONFIG_COMPAT static long lineevent_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) @@ -2272,84 +2301,72 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc, struct gpio_v2_line_info *info) { struct gpio_chip *gc = desc->gdev->chip; - bool ok_for_pinctrl; - unsigned long flags; - u32 debounce_period_us; - unsigned int num_attrs = 0; + unsigned long dflags; memset(info, 0, sizeof(*info)); info->offset = gpio_chip_hwgpio(desc); - /* - * This function takes a mutex so we must check this before taking - * the spinlock. - * - * FIXME: find a non-racy way to retrieve this information. Maybe a - * lock common to both frameworks? - */ - ok_for_pinctrl = pinctrl_gpio_can_use_line(gc, info->offset); - - spin_lock_irqsave(&gpio_lock, flags); + scoped_guard(spinlock_irqsave, &gpio_lock) { + if (desc->name) + strscpy(info->name, desc->name, sizeof(info->name)); - if (desc->name) - strscpy(info->name, desc->name, sizeof(info->name)); + if (desc->label) + strscpy(info->consumer, desc->label, + sizeof(info->consumer)); - if (desc->label) - strscpy(info->consumer, desc->label, sizeof(info->consumer)); + dflags = READ_ONCE(desc->flags); + } /* - * Userspace only need to know that the kernel is using this GPIO so - * it can't use it. + * Userspace only need know that the kernel is using this GPIO so it + * can't use it. + * The calculation of the used flag is slightly racy, as it may read + * desc, gc and pinctrl state without a lock covering all three at + * once. Worst case if the line is in transition and the calculation + * is inconsistent then it looks to the user like they performed the + * read on the other side of the transition - but that can always + * happen. + * The definitive test that a line is available to userspace is to + * request it. */ - info->flags = 0; - if (test_bit(FLAG_REQUESTED, &desc->flags) || - test_bit(FLAG_IS_HOGGED, &desc->flags) || - test_bit(FLAG_USED_AS_IRQ, &desc->flags) || - test_bit(FLAG_EXPORT, &desc->flags) || - test_bit(FLAG_SYSFS, &desc->flags) || + if (test_bit(FLAG_REQUESTED, &dflags) || + test_bit(FLAG_IS_HOGGED, &dflags) || + test_bit(FLAG_USED_AS_IRQ, &dflags) || + test_bit(FLAG_EXPORT, &dflags) || + test_bit(FLAG_SYSFS, &dflags) || !gpiochip_line_is_valid(gc, info->offset) || - !ok_for_pinctrl) + !pinctrl_gpio_can_use_line(gc, info->offset)) info->flags |= GPIO_V2_LINE_FLAG_USED; - if (test_bit(FLAG_IS_OUT, &desc->flags)) + if (test_bit(FLAG_IS_OUT, &dflags)) info->flags |= GPIO_V2_LINE_FLAG_OUTPUT; else info->flags |= GPIO_V2_LINE_FLAG_INPUT; - if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) + if (test_bit(FLAG_ACTIVE_LOW, &dflags)) info->flags |= GPIO_V2_LINE_FLAG_ACTIVE_LOW; - if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) + if (test_bit(FLAG_OPEN_DRAIN, &dflags)) info->flags |= GPIO_V2_LINE_FLAG_OPEN_DRAIN; - if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) + if (test_bit(FLAG_OPEN_SOURCE, &dflags)) info->flags |= GPIO_V2_LINE_FLAG_OPEN_SOURCE; - if (test_bit(FLAG_BIAS_DISABLE, &desc->flags)) + if (test_bit(FLAG_BIAS_DISABLE, &dflags)) info->flags |= GPIO_V2_LINE_FLAG_BIAS_DISABLED; - if (test_bit(FLAG_PULL_DOWN, &desc->flags)) + if (test_bit(FLAG_PULL_DOWN, &dflags)) info->flags |= GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN; - if (test_bit(FLAG_PULL_UP, &desc->flags)) + if (test_bit(FLAG_PULL_UP, &dflags)) info->flags |= GPIO_V2_LINE_FLAG_BIAS_PULL_UP; - if (test_bit(FLAG_EDGE_RISING, &desc->flags)) + if (test_bit(FLAG_EDGE_RISING, &dflags)) info->flags |= GPIO_V2_LINE_FLAG_EDGE_RISING; - if (test_bit(FLAG_EDGE_FALLING, &desc->flags)) + if (test_bit(FLAG_EDGE_FALLING, &dflags)) info->flags |= GPIO_V2_LINE_FLAG_EDGE_FALLING; - if (test_bit(FLAG_EVENT_CLOCK_REALTIME, &desc->flags)) + if (test_bit(FLAG_EVENT_CLOCK_REALTIME, &dflags)) info->flags |= GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME; - else if (test_bit(FLAG_EVENT_CLOCK_HTE, &desc->flags)) + else if (test_bit(FLAG_EVENT_CLOCK_HTE, &dflags)) info->flags |= GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE; - - debounce_period_us = READ_ONCE(desc->debounce_period_us); - if (debounce_period_us) { - info->attrs[num_attrs].id = GPIO_V2_LINE_ATTR_ID_DEBOUNCE; - info->attrs[num_attrs].debounce_period_us = debounce_period_us; - num_attrs++; - } - info->num_attrs = num_attrs; - - spin_unlock_irqrestore(&gpio_lock, flags); } struct gpio_chardev_data { @@ -2455,6 +2472,7 @@ static int lineinfo_get(struct gpio_chardev_data *cdev, void __user *ip, return -EBUSY; } gpio_desc_to_lineinfo(desc, &lineinfo); + supinfo_to_lineinfo(desc, &lineinfo); if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) { if (watch) @@ -2481,12 +2499,17 @@ static int lineinfo_unwatch(struct gpio_chardev_data *cdev, void __user *ip) return 0; } -static long gpio_ioctl_unlocked(struct file *file, unsigned int cmd, unsigned long arg) +/* + * gpio_ioctl() - ioctl handler for the GPIO chardev + */ +static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct gpio_chardev_data *cdev = file->private_data; struct gpio_device *gdev = cdev->gdev; void __user *ip = (void __user *)arg; + guard(rwsem_read)(&gdev->sem); + /* We fail any subsequent ioctl():s when the chip is gone */ if (!gdev->chip) return -ENODEV; @@ -2518,17 +2541,6 @@ static long gpio_ioctl_unlocked(struct file *file, unsigned int cmd, unsigned lo } } -/* - * gpio_ioctl() - ioctl handler for the GPIO chardev - */ -static long gpio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct gpio_chardev_data *cdev = file->private_data; - - return call_ioctl_locked(file, cmd, arg, cdev->gdev, - gpio_ioctl_unlocked); -} - #ifdef CONFIG_COMPAT static long gpio_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) @@ -2553,6 +2565,7 @@ static int lineinfo_changed_notify(struct notifier_block *nb, chg.event_type = action; chg.timestamp_ns = ktime_get_ns(); gpio_desc_to_lineinfo(desc, &chg.info); + supinfo_to_lineinfo(desc, &chg.info); ret = kfifo_in_spinlocked(&cdev->events, &chg, 1, &cdev->wait.lock); if (ret) @@ -2575,12 +2588,14 @@ static int gpio_device_unregistered_notify(struct notifier_block *nb, return NOTIFY_OK; } -static __poll_t lineinfo_watch_poll_unlocked(struct file *file, - struct poll_table_struct *pollt) +static __poll_t lineinfo_watch_poll(struct file *file, + struct poll_table_struct *pollt) { struct gpio_chardev_data *cdev = file->private_data; __poll_t events = 0; + guard(rwsem_read)(&cdev->gdev->sem); + if (!cdev->gdev->chip) return EPOLLHUP | EPOLLERR; @@ -2593,17 +2608,8 @@ static __poll_t lineinfo_watch_poll_unlocked(struct file *file, return events; } -static __poll_t lineinfo_watch_poll(struct file *file, - struct poll_table_struct *pollt) -{ - struct gpio_chardev_data *cdev = file->private_data; - - return call_poll_locked(file, pollt, cdev->gdev, - lineinfo_watch_poll_unlocked); -} - -static ssize_t lineinfo_watch_read_unlocked(struct file *file, char __user *buf, - size_t count, loff_t *off) +static ssize_t lineinfo_watch_read(struct file *file, char __user *buf, + size_t count, loff_t *off) { struct gpio_chardev_data *cdev = file->private_data; struct gpio_v2_line_info_changed event; @@ -2611,6 +2617,8 @@ static ssize_t lineinfo_watch_read_unlocked(struct file *file, char __user *buf, int ret; size_t event_size; + guard(rwsem_read)(&cdev->gdev->sem); + if (!cdev->gdev->chip) return -ENODEV; @@ -2621,38 +2629,30 @@ static ssize_t lineinfo_watch_read_unlocked(struct file *file, char __user *buf, #endif do { - spin_lock(&cdev->wait.lock); - if (kfifo_is_empty(&cdev->events)) { - if (bytes_read) { - spin_unlock(&cdev->wait.lock); - return bytes_read; + scoped_guard(spinlock, &cdev->wait.lock) { + if (kfifo_is_empty(&cdev->events)) { + if (bytes_read) + return bytes_read; + + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + + ret = wait_event_interruptible_locked(cdev->wait, + !kfifo_is_empty(&cdev->events)); + if (ret) + return ret; } - - if (file->f_flags & O_NONBLOCK) { - spin_unlock(&cdev->wait.lock); - return -EAGAIN; - } - - ret = wait_event_interruptible_locked(cdev->wait, - !kfifo_is_empty(&cdev->events)); - if (ret) { - spin_unlock(&cdev->wait.lock); - return ret; - } - } #ifdef CONFIG_GPIO_CDEV_V1 - /* must be after kfifo check so watch_abi_version is set */ - if (atomic_read(&cdev->watch_abi_version) == 2) - event_size = sizeof(struct gpio_v2_line_info_changed); - else - event_size = sizeof(struct gpioline_info_changed); - if (count < event_size) { - spin_unlock(&cdev->wait.lock); - return -EINVAL; - } + /* must be after kfifo check so watch_abi_version is set */ + if (atomic_read(&cdev->watch_abi_version) == 2) + event_size = sizeof(struct gpio_v2_line_info_changed); + else + event_size = sizeof(struct gpioline_info_changed); + if (count < event_size) + return -EINVAL; #endif - ret = kfifo_out(&cdev->events, &event, 1); - spin_unlock(&cdev->wait.lock); + ret = kfifo_out(&cdev->events, &event, 1); + } if (ret != 1) { ret = -EIO; break; @@ -2681,15 +2681,6 @@ static ssize_t lineinfo_watch_read_unlocked(struct file *file, char __user *buf, return bytes_read; } -static ssize_t lineinfo_watch_read(struct file *file, char __user *buf, - size_t count, loff_t *off) -{ - struct gpio_chardev_data *cdev = file->private_data; - - return call_read_locked(file, buf, count, off, cdev->gdev, - lineinfo_watch_read_unlocked); -} - /** * gpio_chrdev_open() - open the chardev for ioctl operations * @inode: inode for this chardev @@ -2703,17 +2694,15 @@ static int gpio_chrdev_open(struct inode *inode, struct file *file) struct gpio_chardev_data *cdev; int ret = -ENOMEM; - down_read(&gdev->sem); + guard(rwsem_read)(&gdev->sem); /* Fail on open if the backing gpiochip is gone */ - if (!gdev->chip) { - ret = -ENODEV; - goto out_unlock; - } + if (!gdev->chip) + return -ENODEV; cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); if (!cdev) - goto out_unlock; + return -ENODEV; cdev->watched_lines = bitmap_zalloc(gdev->chip->ngpio, GFP_KERNEL); if (!cdev->watched_lines) @@ -2742,8 +2731,6 @@ static int gpio_chrdev_open(struct inode *inode, struct file *file) if (ret) goto out_unregister_device_notifier; - up_read(&gdev->sem); - return ret; out_unregister_device_notifier: @@ -2757,8 +2744,6 @@ out_free_bitmap: bitmap_free(cdev->watched_lines); out_free_cdev: kfree(cdev); -out_unlock: - up_read(&gdev->sem); return ret; } diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 402f7d99b0c1e4..e7770eedd14693 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -184,7 +184,7 @@ static void of_gpio_try_fixup_polarity(const struct device_node *np, const char *propname; bool active_high; } gpios[] = { -#if !IS_ENABLED(CONFIG_LCD_HX8357) +#if IS_ENABLED(CONFIG_LCD_HX8357) /* * Himax LCD controllers used incorrectly named * "gpios-reset" property and also specified wrong @@ -478,7 +478,7 @@ static struct gpio_desc *of_find_gpio_rename(struct device_node *np, */ const char *compatible; } gpios[] = { -#if !IS_ENABLED(CONFIG_LCD_HX8357) +#if IS_ENABLED(CONFIG_LCD_HX8357) /* Himax LCD controllers used "gpios-reset" */ { "reset", "gpios-reset", "himax,hx8357" }, { "reset", "gpios-reset", "himax,hx8369" }, diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c index 12d853845bb803..6bf5332136e5a9 100644 --- a/drivers/gpio/gpiolib-sysfs.c +++ b/drivers/gpio/gpiolib-sysfs.c @@ -165,10 +165,10 @@ static irqreturn_t gpio_sysfs_irq(int irq, void *priv) /* Caller holds gpiod-data mutex. */ static int gpio_sysfs_request_irq(struct device *dev, unsigned char flags) { - struct gpiod_data *data = dev_get_drvdata(dev); - struct gpio_desc *desc = data->desc; - unsigned long irq_flags; - int ret; + struct gpiod_data *data = dev_get_drvdata(dev); + struct gpio_desc *desc = data->desc; + unsigned long irq_flags; + int ret; data->irq = gpiod_to_irq(desc); if (data->irq < 0) @@ -259,7 +259,7 @@ static ssize_t edge_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct gpiod_data *data = dev_get_drvdata(dev); - ssize_t status = size; + ssize_t status = size; int flags; flags = sysfs_match_string(trigger_names, buf); @@ -292,10 +292,11 @@ static DEVICE_ATTR_RW(edge); /* Caller holds gpiod-data mutex. */ static int gpio_sysfs_set_active_low(struct device *dev, int value) { - struct gpiod_data *data = dev_get_drvdata(dev); - struct gpio_desc *desc = data->desc; - int status = 0; - unsigned int flags = data->irq_flags; + struct gpiod_data *data = dev_get_drvdata(dev); + unsigned int flags = data->irq_flags; + struct gpio_desc *desc = data->desc; + int status = 0; + if (!!test_bit(FLAG_ACTIVE_LOW, &desc->flags) == !!value) return 0; @@ -331,9 +332,9 @@ static ssize_t active_low_show(struct device *dev, static ssize_t active_low_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { - struct gpiod_data *data = dev_get_drvdata(dev); - ssize_t status; - long value; + struct gpiod_data *data = dev_get_drvdata(dev); + ssize_t status; + long value; status = kstrtol(buf, 0, &value); if (status) @@ -399,7 +400,7 @@ static const struct attribute_group *gpio_groups[] = { static ssize_t base_show(struct device *dev, struct device_attribute *attr, char *buf) { - const struct gpio_chip *chip = dev_get_drvdata(dev); + const struct gpio_chip *chip = dev_get_drvdata(dev); return sysfs_emit(buf, "%d\n", chip->base); } @@ -408,7 +409,7 @@ static DEVICE_ATTR_RO(base); static ssize_t label_show(struct device *dev, struct device_attribute *attr, char *buf) { - const struct gpio_chip *chip = dev_get_drvdata(dev); + const struct gpio_chip *chip = dev_get_drvdata(dev); return sysfs_emit(buf, "%s\n", chip->label ?: ""); } @@ -417,7 +418,7 @@ static DEVICE_ATTR_RO(label); static ssize_t ngpio_show(struct device *dev, struct device_attribute *attr, char *buf) { - const struct gpio_chip *chip = dev_get_drvdata(dev); + const struct gpio_chip *chip = dev_get_drvdata(dev); return sysfs_emit(buf, "%u\n", chip->ngpio); } @@ -441,11 +442,10 @@ static ssize_t export_store(const struct class *class, const struct class_attribute *attr, const char *buf, size_t len) { - long gpio; - struct gpio_desc *desc; - int status; - struct gpio_chip *gc; - int offset; + struct gpio_desc *desc; + struct gpio_chip *gc; + int status, offset; + long gpio; status = kstrtol(buf, 0, &gpio); if (status < 0) @@ -496,9 +496,9 @@ static ssize_t unexport_store(const struct class *class, const struct class_attribute *attr, const char *buf, size_t len) { - long gpio; - struct gpio_desc *desc; - int status; + struct gpio_desc *desc; + int status; + long gpio; status = kstrtol(buf, 0, &gpio); if (status < 0) @@ -559,14 +559,13 @@ static struct class gpio_class = { */ int gpiod_export(struct gpio_desc *desc, bool direction_may_change) { - struct gpio_chip *chip; - struct gpio_device *gdev; - struct gpiod_data *data; - unsigned long flags; - int status; - const char *ioname = NULL; - struct device *dev; - int offset; + const char *ioname = NULL; + struct gpio_device *gdev; + struct gpiod_data *data; + struct gpio_chip *chip; + unsigned long flags; + struct device *dev; + int status, offset; /* can't export until sysfs is available ... */ if (!class_is_registered(&gpio_class)) { @@ -733,9 +732,9 @@ EXPORT_SYMBOL_GPL(gpiod_unexport); int gpiochip_sysfs_register(struct gpio_device *gdev) { - struct device *dev; - struct device *parent; struct gpio_chip *chip = gdev->chip; + struct device *parent; + struct device *dev; /* * Many systems add gpio chips for SOC support very early, diff --git a/drivers/gpio/gpiolib-sysfs.h b/drivers/gpio/gpiolib-sysfs.h index 0f213bdb473246..b794b396d6a525 100644 --- a/drivers/gpio/gpiolib-sysfs.h +++ b/drivers/gpio/gpiolib-sysfs.h @@ -3,10 +3,10 @@ #ifndef GPIOLIB_SYSFS_H #define GPIOLIB_SYSFS_H -#ifdef CONFIG_GPIO_SYSFS - struct gpio_device; +#ifdef CONFIG_GPIO_SYSFS + int gpiochip_sysfs_register(struct gpio_device *gdev); void gpiochip_sysfs_unregister(struct gpio_device *gdev); diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 95d2a7b2ea3e21..44c8f5743a2416 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -45,19 +45,6 @@ * GPIOs can sometimes cost only an instruction or two per bit. */ - -/* When debugging, extend minimal trust to callers and platform code. - * Also emit diagnostic messages that may help initial bringup, when - * board setup or driver bugs are most common. - * - * Otherwise, minimize overhead in what may be bitbanging codepaths. - */ -#ifdef DEBUG -#define extra_checks 1 -#else -#define extra_checks 0 -#endif - /* Device and char device-related information */ static DEFINE_IDA(gpio_ida); static dev_t gpio_devt; @@ -254,6 +241,20 @@ int gpio_device_get_base(struct gpio_device *gdev) } EXPORT_SYMBOL_GPL(gpio_device_get_base); +/** + * gpio_device_get_label() - Get the label of this GPIO device + * @gdev: GPIO device + * + * Returns: + * Pointer to the string containing the GPIO device label. The string's + * lifetime is tied to that of the underlying GPIO device. + */ +const char *gpio_device_get_label(struct gpio_device *gdev) +{ + return gdev->label; +} +EXPORT_SYMBOL(gpio_device_get_label); + /** * gpio_device_get_chip() - Get the gpio_chip implementation of this GPIO device * @gdev: GPIO device @@ -276,7 +277,7 @@ struct gpio_chip *gpio_device_get_chip(struct gpio_device *gdev) EXPORT_SYMBOL_GPL(gpio_device_get_chip); /* dynamic allocation of GPIOs, e.g. on a hotplugged device */ -static int gpiochip_find_base(int ngpio) +static int gpiochip_find_base_unlocked(int ngpio) { struct gpio_device *gdev; int base = GPIO_DYNAMIC_BASE; @@ -349,7 +350,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_direction); * Return -EBUSY if the new chip overlaps with some other chip's integer * space. */ -static int gpiodev_add_to_list(struct gpio_device *gdev) +static int gpiodev_add_to_list_unlocked(struct gpio_device *gdev) { struct gpio_device *prev, *next; @@ -655,11 +656,6 @@ EXPORT_SYMBOL_GPL(gpiochip_line_is_valid); static void gpiodev_release(struct device *dev) { struct gpio_device *gdev = to_gpio_device(dev); - unsigned long flags; - - spin_lock_irqsave(&gpio_lock, flags); - list_del(&gdev->list); - spin_unlock_irqrestore(&gpio_lock, flags); ida_free(&gpio_ida, gdev->id); kfree_const(gdev->label); @@ -893,7 +889,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, */ base = gc->base; if (base < 0) { - base = gpiochip_find_base(gc->ngpio); + base = gpiochip_find_base_unlocked(gc->ngpio); if (base < 0) { spin_unlock_irqrestore(&gpio_lock, flags); ret = base; @@ -913,7 +909,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, } gdev->base = base; - ret = gpiodev_add_to_list(gdev); + ret = gpiodev_add_to_list_unlocked(gdev); if (ret) { spin_unlock_irqrestore(&gpio_lock, flags); chip_err(gc, "GPIO integer space overlap, cannot add chip\n"); @@ -1048,8 +1044,8 @@ EXPORT_SYMBOL_GPL(gpiochip_add_data_with_key); void gpiochip_remove(struct gpio_chip *gc) { struct gpio_device *gdev = gc->gpiodev; - unsigned long flags; - unsigned int i; + unsigned long flags; + unsigned int i; down_write(&gdev->sem); @@ -1071,7 +1067,7 @@ void gpiochip_remove(struct gpio_chip *gc) spin_lock_irqsave(&gpio_lock, flags); for (i = 0; i < gdev->ngpio; i++) { - if (gpiochip_is_requested(gc, i)) + if (test_bit(FLAG_REQUESTED, &gdev->descs[i].flags)) break; } spin_unlock_irqrestore(&gpio_lock, flags); @@ -1080,6 +1076,9 @@ void gpiochip_remove(struct gpio_chip *gc) dev_crit(&gdev->dev, "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n"); + scoped_guard(spinlock_irqsave, &gpio_lock) + list_del(&gdev->list); + /* * The gpiochip side puts its use of the device to rest here: * if there are no userspace clients, the chardev and device will @@ -2185,10 +2184,10 @@ EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges); */ static int gpiod_request_commit(struct gpio_desc *desc, const char *label) { - struct gpio_chip *gc = desc->gdev->chip; - int ret; - unsigned long flags; - unsigned offset; + struct gpio_chip *gc = desc->gdev->chip; + unsigned long flags; + unsigned int offset; + int ret; if (label) { label = kstrdup_const(label, GFP_KERNEL); @@ -2300,9 +2299,9 @@ int gpiod_request(struct gpio_desc *desc, const char *label) static bool gpiod_free_commit(struct gpio_desc *desc) { - bool ret = false; - unsigned long flags; - struct gpio_chip *gc; + struct gpio_chip *gc; + unsigned long flags; + bool ret = false; might_sleep(); @@ -2330,9 +2329,6 @@ static bool gpiod_free_commit(struct gpio_desc *desc) clear_bit(FLAG_IS_HOGGED, &desc->flags); #ifdef CONFIG_OF_DYNAMIC desc->hog = NULL; -#endif -#ifdef CONFIG_GPIO_CDEV - WRITE_ONCE(desc->debounce_period_us, 0); #endif ret = true; } @@ -2353,38 +2349,53 @@ void gpiod_free(struct gpio_desc *desc) return; if (!gpiod_free_commit(desc)) - WARN_ON(extra_checks); + WARN_ON(1); module_put(desc->gdev->owner); gpio_device_put(desc->gdev); } /** - * gpiochip_is_requested - return string iff signal was requested - * @gc: controller managing the signal - * @offset: of signal within controller's 0..(ngpio - 1) range + * gpiochip_dup_line_label - Get a copy of the consumer label. + * @gc: GPIO chip controlling this line. + * @offset: Hardware offset of the line. * - * Returns NULL if the GPIO is not currently requested, else a string. - * The string returned is the label passed to gpio_request(); if none has been - * passed it is a meaningless, non-NULL constant. + * Returns: + * Pointer to a copy of the consumer label if the line is requested or NULL + * if it's not. If a valid pointer was returned, it must be freed using + * kfree(). In case of a memory allocation error, the function returns %ENOMEM. * - * This function is for use by GPIO controller drivers. The label can - * help with diagnostics, and knowing that the signal is used as a GPIO - * can help avoid accidentally multiplexing it to another controller. + * Must not be called from atomic context. */ -const char *gpiochip_is_requested(struct gpio_chip *gc, unsigned int offset) +char *gpiochip_dup_line_label(struct gpio_chip *gc, unsigned int offset) { struct gpio_desc *desc; + char *label; desc = gpiochip_get_desc(gc, offset); if (IS_ERR(desc)) return NULL; - if (test_bit(FLAG_REQUESTED, &desc->flags) == 0) + guard(spinlock_irqsave)(&gpio_lock); + + if (!test_bit(FLAG_REQUESTED, &desc->flags)) return NULL; - return desc->label; + + /* + * FIXME: Once we mark gpiod_direction_input/output() and + * gpiod_get_direction() with might_sleep(), we'll be able to protect + * the GPIO descriptors with mutex (while value setting operations will + * become lockless). + * + * Until this happens, this allocation needs to be atomic. + */ + label = kstrdup(desc->label, GFP_ATOMIC); + if (!label) + return ERR_PTR(-ENOMEM); + + return label; } -EXPORT_SYMBOL_GPL(gpiochip_is_requested); +EXPORT_SYMBOL_GPL(gpiochip_dup_line_label); /** * gpiochip_request_own_desc - Allow GPIO chip to request its own descriptor @@ -2564,8 +2575,8 @@ int gpio_set_debounce_timeout(struct gpio_desc *desc, unsigned int debounce) */ int gpiod_direction_input(struct gpio_desc *desc) { - struct gpio_chip *gc; - int ret = 0; + struct gpio_chip *gc; + int ret = 0; VALIDATE_DESC(desc); gc = desc->gdev->chip; @@ -2914,7 +2925,7 @@ static int gpio_chip_get_value(struct gpio_chip *gc, const struct gpio_desc *des static int gpiod_get_raw_value_commit(const struct gpio_desc *desc) { - struct gpio_chip *gc; + struct gpio_chip *gc; int value; gc = desc->gdev->chip; @@ -3209,7 +3220,7 @@ static void gpio_set_open_source_value_commit(struct gpio_desc *desc, bool value static void gpiod_set_raw_value_commit(struct gpio_desc *desc, bool value) { - struct gpio_chip *gc; + struct gpio_chip *gc; gc = desc->gdev->chip; trace_gpio_value(desc_to_gpio(desc), 0, value); @@ -3716,7 +3727,7 @@ EXPORT_SYMBOL_GPL(gpiochip_line_is_persistent); */ int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc) { - might_sleep_if(extra_checks); + might_sleep(); VALIDATE_DESC(desc); return gpiod_get_raw_value_commit(desc); } @@ -3735,7 +3746,7 @@ int gpiod_get_value_cansleep(const struct gpio_desc *desc) { int value; - might_sleep_if(extra_checks); + might_sleep(); VALIDATE_DESC(desc); value = gpiod_get_raw_value_commit(desc); if (value < 0) @@ -3766,7 +3777,7 @@ int gpiod_get_raw_array_value_cansleep(unsigned int array_size, struct gpio_array *array_info, unsigned long *value_bitmap) { - might_sleep_if(extra_checks); + might_sleep(); if (!desc_array) return -EINVAL; return gpiod_get_array_value_complex(true, true, array_size, @@ -3792,7 +3803,7 @@ int gpiod_get_array_value_cansleep(unsigned int array_size, struct gpio_array *array_info, unsigned long *value_bitmap) { - might_sleep_if(extra_checks); + might_sleep(); if (!desc_array) return -EINVAL; return gpiod_get_array_value_complex(false, true, array_size, @@ -3813,7 +3824,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_array_value_cansleep); */ void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value) { - might_sleep_if(extra_checks); + might_sleep(); VALIDATE_DESC_VOID(desc); gpiod_set_raw_value_commit(desc, value); } @@ -3831,7 +3842,7 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_value_cansleep); */ void gpiod_set_value_cansleep(struct gpio_desc *desc, int value) { - might_sleep_if(extra_checks); + might_sleep(); VALIDATE_DESC_VOID(desc); gpiod_set_value_nocheck(desc, value); } @@ -3854,7 +3865,7 @@ int gpiod_set_raw_array_value_cansleep(unsigned int array_size, struct gpio_array *array_info, unsigned long *value_bitmap) { - might_sleep_if(extra_checks); + might_sleep(); if (!desc_array) return -EINVAL; return gpiod_set_array_value_complex(true, true, array_size, desc_array, @@ -3896,7 +3907,7 @@ int gpiod_set_array_value_cansleep(unsigned int array_size, struct gpio_array *array_info, unsigned long *value_bitmap) { - might_sleep_if(extra_checks); + might_sleep(); if (!desc_array) return -EINVAL; return gpiod_set_array_value_complex(false, true, array_size, @@ -4696,13 +4707,11 @@ core_initcall(gpiolib_dev_init); static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev) { - struct gpio_chip *gc = gdev->chip; - struct gpio_desc *desc; - unsigned gpio = gdev->base; - int value; - bool is_out; - bool is_irq; - bool active_low; + struct gpio_chip *gc = gdev->chip; + bool active_low, is_irq, is_out; + unsigned int gpio = gdev->base; + struct gpio_desc *desc; + int value; for_each_gpio_desc(gc, desc) { if (test_bit(FLAG_REQUESTED, &desc->flags)) { diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index 3ccacf3c1288e7..a4a2520b5f31cc 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -147,7 +147,6 @@ void gpiod_line_state_notify(struct gpio_desc *desc, unsigned long action); * @label: Name of the consumer * @name: Line name * @hog: Pointer to the device node that hogs this line (if any) - * @debounce_period_us: Debounce period in microseconds * * These are obtained using gpiod_get() and are preferable to the old * integer-based handles. @@ -185,10 +184,6 @@ struct gpio_desc { #ifdef CONFIG_OF_DYNAMIC struct device_node *hog; #endif -#ifdef CONFIG_GPIO_CDEV - /* debounce period in microseconds */ - unsigned int debounce_period_us; -#endif }; #define gpiod_not_found(desc) (IS_ERR(desc) && PTR_ERR(desc) == -ENOENT) diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 3eee8636f847a1..2520db0b776e1b 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -74,16 +74,17 @@ config DRM_KUNIT_TEST_HELPERS config DRM_KUNIT_TEST tristate "KUnit tests for DRM" if !KUNIT_ALL_TESTS - depends on DRM && KUNIT - select PRIME_NUMBERS + depends on DRM && KUNIT && MMU + select DRM_BUDDY select DRM_DISPLAY_DP_HELPER select DRM_DISPLAY_HELPER - select DRM_LIB_RANDOM - select DRM_KMS_HELPER - select DRM_BUDDY + select DRM_EXEC select DRM_EXPORT_FOR_TESTS if m + select DRM_GEM_SHMEM_HELPER + select DRM_KMS_HELPER select DRM_KUNIT_TEST_HELPERS - select DRM_EXEC + select DRM_LIB_RANDOM + select PRIME_NUMBERS default KUNIT_ALL_TESTS help This builds unit tests for DRM. This option is not useful for @@ -275,6 +276,8 @@ source "drivers/gpu/drm/nouveau/Kconfig" source "drivers/gpu/drm/i915/Kconfig" +source "drivers/gpu/drm/xe/Kconfig" + source "drivers/gpu/drm/kmb/Kconfig" config DRM_VGEM @@ -394,6 +397,8 @@ source "drivers/gpu/drm/solomon/Kconfig" source "drivers/gpu/drm/sprd/Kconfig" +source "drivers/gpu/drm/imagination/Kconfig" + config DRM_HYPERV tristate "DRM Support for Hyper-V synthetic video device" depends on DRM && PCI && MMU && HYPERV @@ -407,27 +412,6 @@ config DRM_HYPERV If M is selected the module will be called hyperv_drm. -# Keep legacy drivers last - -menuconfig DRM_LEGACY - bool "Enable legacy drivers (DANGEROUS)" - depends on DRM && MMU - help - Enable legacy DRI1 drivers. Those drivers expose unsafe and dangerous - APIs to user-space, which can be used to circumvent access - restrictions and other security measures. For backwards compatibility - those drivers are still available, but their use is highly - inadvisable and might harm your system. - - You are recommended to use the safe modeset-only drivers instead, and - perform 3D emulation in user-space. - - Unless you have strong reasons to go rogue, say "N". - -if DRM_LEGACY -# leave here to list legacy drivers -endif # DRM_LEGACY - config DRM_EXPORT_FOR_TESTS bool diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 8e1bde059170ed..104b42df2e956b 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -22,6 +22,7 @@ drm-y := \ drm_drv.o \ drm_dumb_buffers.o \ drm_edid.o \ + drm_eld.o \ drm_encoder.o \ drm_file.o \ drm_fourcc.o \ @@ -46,18 +47,6 @@ drm-y := \ drm_vblank_work.o \ drm_vma_manager.o \ drm_writeback.o -drm-$(CONFIG_DRM_LEGACY) += \ - drm_agpsupport.o \ - drm_bufs.o \ - drm_context.o \ - drm_dma.o \ - drm_hashtab.o \ - drm_irq.o \ - drm_legacy_misc.o \ - drm_lock.o \ - drm_memory.o \ - drm_scatter.o \ - drm_vm.o drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o drm-$(CONFIG_COMPAT) += drm_ioc32.o drm-$(CONFIG_DRM_PANEL) += drm_panel.o @@ -145,6 +134,7 @@ obj-$(CONFIG_DRM_RADEON)+= radeon/ obj-$(CONFIG_DRM_AMDGPU)+= amd/amdgpu/ obj-$(CONFIG_DRM_AMDGPU)+= amd/amdxcp/ obj-$(CONFIG_DRM_I915) += i915/ +obj-$(CONFIG_DRM_XE) += xe/ obj-$(CONFIG_DRM_KMB_DISPLAY) += kmb/ obj-$(CONFIG_DRM_MGAG200) += mgag200/ obj-$(CONFIG_DRM_V3D) += v3d/ @@ -198,3 +188,4 @@ obj-$(CONFIG_DRM_HYPERV) += hyperv/ obj-y += solomon/ obj-$(CONFIG_DRM_SPRD) += sprd/ obj-$(CONFIG_DRM_LOONGSON) += loongson/ +obj-$(CONFIG_DRM_POWERVR) += imagination/ diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile index 2afecc55090f70..260e32ef7bae0f 100644 --- a/drivers/gpu/drm/amd/amdgpu/Makefile +++ b/drivers/gpu/drm/amd/amdgpu/Makefile @@ -80,7 +80,7 @@ amdgpu-y += amdgpu_device.o amdgpu_doorbell_mgr.o amdgpu_kms.o \ amdgpu_umc.o smu_v11_0_i2c.o amdgpu_fru_eeprom.o amdgpu_rap.o \ amdgpu_fw_attestation.o amdgpu_securedisplay.o \ amdgpu_eeprom.o amdgpu_mca.o amdgpu_psp_ta.o amdgpu_lsdma.o \ - amdgpu_ring_mux.o amdgpu_xcp.o + amdgpu_ring_mux.o amdgpu_xcp.o amdgpu_seq64.o amdgpu-$(CONFIG_PROC_FS) += amdgpu_fdinfo.o diff --git a/drivers/gpu/drm/amd/amdgpu/aldebaran.c b/drivers/gpu/drm/amd/amdgpu/aldebaran.c index 02f4c6f9d4f687..576067d66bb9af 100644 --- a/drivers/gpu/drm/amd/amdgpu/aldebaran.c +++ b/drivers/gpu/drm/amd/amdgpu/aldebaran.c @@ -330,6 +330,7 @@ aldebaran_mode2_restore_hwcontext(struct amdgpu_reset_control *reset_ctl, { struct list_head *reset_device_list = reset_context->reset_device_list; struct amdgpu_device *tmp_adev = NULL; + struct amdgpu_ras *con; int r; if (reset_device_list == NULL) @@ -355,7 +356,30 @@ aldebaran_mode2_restore_hwcontext(struct amdgpu_reset_control *reset_ctl, */ amdgpu_register_gpu_instance(tmp_adev); - /* Resume RAS */ + /* Resume RAS, ecc_irq */ + con = amdgpu_ras_get_context(tmp_adev); + if (!amdgpu_sriov_vf(tmp_adev) && con) { + if (tmp_adev->sdma.ras && + tmp_adev->sdma.ras->ras_block.ras_late_init) { + r = tmp_adev->sdma.ras->ras_block.ras_late_init(tmp_adev, + &tmp_adev->sdma.ras->ras_block.ras_comm); + if (r) { + dev_err(tmp_adev->dev, "SDMA failed to execute ras_late_init! ret:%d\n", r); + goto end; + } + } + + if (tmp_adev->gfx.ras && + tmp_adev->gfx.ras->ras_block.ras_late_init) { + r = tmp_adev->gfx.ras->ras_block.ras_late_init(tmp_adev, + &tmp_adev->gfx.ras->ras_block.ras_comm); + if (r) { + dev_err(tmp_adev->dev, "GFX failed to execute ras_late_init! ret:%d\n", r); + goto end; + } + } + } + amdgpu_ras_resume(tmp_adev); /* Update PSP FW topology after reset */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 9d92ca1576771b..3d8a48f46b0156 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -109,6 +109,8 @@ #include "amdgpu_mca.h" #include "amdgpu_ras.h" #include "amdgpu_xcp.h" +#include "amdgpu_seq64.h" +#include "amdgpu_reg_state.h" #define MAX_GPU_INSTANCE 64 @@ -250,6 +252,8 @@ extern int amdgpu_seamless; extern int amdgpu_user_partt_mode; extern int amdgpu_agp; +extern int amdgpu_wbrf; + #define AMDGPU_VM_MAX_NUM_CTX 4096 #define AMDGPU_SG_THRESHOLD (256*1024*1024) #define AMDGPU_WAIT_IDLE_TIMEOUT_IN_MS 3000 @@ -468,6 +472,7 @@ struct amdgpu_fpriv { struct amdgpu_vm vm; struct amdgpu_bo_va *prt_va; struct amdgpu_bo_va *csa_va; + struct amdgpu_bo_va *seq64_va; struct mutex bo_list_lock; struct idr bo_list_handles; struct amdgpu_ctx_mgr ctx_mgr; @@ -506,6 +511,31 @@ struct amdgpu_allowed_register_entry { bool grbm_indexed; }; +/** + * enum amd_reset_method - Methods for resetting AMD GPU devices + * + * @AMD_RESET_METHOD_NONE: The device will not be reset. + * @AMD_RESET_LEGACY: Method reserved for SI, CIK and VI ASICs. + * @AMD_RESET_MODE0: Reset the entire ASIC. Not currently available for the + * any device. + * @AMD_RESET_MODE1: Resets all IP blocks on the ASIC (SDMA, GFX, VCN, etc.) + * individually. Suitable only for some discrete GPU, not + * available for all ASICs. + * @AMD_RESET_MODE2: Resets a lesser level of IPs compared to MODE1. Which IPs + * are reset depends on the ASIC. Notably doesn't reset IPs + * shared with the CPU on APUs or the memory controllers (so + * VRAM is not lost). Not available on all ASICs. + * @AMD_RESET_BACO: BACO (Bus Alive, Chip Off) method powers off and on the card + * but without powering off the PCI bus. Suitable only for + * discrete GPUs. + * @AMD_RESET_PCI: Does a full bus reset using core Linux subsystem PCI reset + * and does a secondary bus reset or FLR, depending on what the + * underlying hardware supports. + * + * Methods available for AMD GPU driver for resetting the device. Not all + * methods are suitable for every device. User can override the method using + * module parameter `reset_method`. + */ enum amd_reset_method { AMD_RESET_METHOD_NONE = -1, AMD_RESET_METHOD_LEGACY = 0, @@ -585,6 +615,10 @@ struct amdgpu_asic_funcs { const struct amdgpu_video_codecs **codecs); /* encode "> 32bits" smn addressing */ u64 (*encode_ext_smn_addressing)(int ext_id); + + ssize_t (*get_reg_state)(struct amdgpu_device *adev, + enum amdgpu_reg_state reg_state, void *buf, + size_t max_size); }; /* @@ -757,6 +791,7 @@ struct amdgpu_mqd_prop { uint64_t eop_gpu_addr; uint32_t hqd_pipe_priority; uint32_t hqd_queue_priority; + bool allow_tunneling; bool hqd_active; }; @@ -986,6 +1021,9 @@ struct amdgpu_device { /* GDS */ struct amdgpu_gds gds; + /* for userq and VM fences */ + struct amdgpu_seq64 seq64; + /* KFD */ struct amdgpu_kfd_dev kfd; @@ -1106,6 +1144,7 @@ struct amdgpu_device { bool debug_vm; bool debug_largebar; bool debug_disable_soft_recovery; + bool debug_use_vram_fw_buf; }; static inline uint32_t amdgpu_ip_version(const struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 75dc58470393ff..77e26366028870 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -138,10 +138,14 @@ static void amdgpu_amdkfd_reset_work(struct work_struct *work) amdgpu_device_gpu_recover(adev, NULL, &reset_context); } +static const struct drm_client_funcs kfd_client_funcs = { + .unregister = drm_client_release, +}; void amdgpu_amdkfd_device_init(struct amdgpu_device *adev) { int i; int last_valid_bit; + int ret; amdgpu_amdkfd_gpuvm_init_mem_limits(); @@ -160,6 +164,12 @@ void amdgpu_amdkfd_device_init(struct amdgpu_device *adev) .enable_mes = adev->enable_mes, }; + ret = drm_client_init(&adev->ddev, &adev->kfd.client, "kfd", &kfd_client_funcs); + if (ret) { + dev_err(adev->dev, "Failed to init DRM client: %d\n", ret); + return; + } + /* this is going to have a few of the MSBs set that we need to * clear */ @@ -198,6 +208,10 @@ void amdgpu_amdkfd_device_init(struct amdgpu_device *adev) adev->kfd.init_complete = kgd2kfd_device_init(adev->kfd.dev, &gpu_resources); + if (adev->kfd.init_complete) + drm_client_register(&adev->kfd.client); + else + drm_client_release(&adev->kfd.client); amdgpu_amdkfd_total_mem_size += adev->gmc.real_vram_size; @@ -684,10 +698,8 @@ err: void amdgpu_amdkfd_set_compute_idle(struct amdgpu_device *adev, bool idle) { enum amd_powergating_state state = idle ? AMD_PG_STATE_GATE : AMD_PG_STATE_UNGATE; - /* Temporary workaround to fix issues observed in some - * compute applications when GFXOFF is enabled on GFX11. - */ - if (IP_VERSION_MAJ(amdgpu_ip_version(adev, GC_HWIP, 0)) == 11) { + if (IP_VERSION_MAJ(amdgpu_ip_version(adev, GC_HWIP, 0)) == 11 && + ((adev->mes.kiq_version & AMDGPU_MES_VERSION_MASK) <= 64)) { pr_debug("GFXOFF is %s\n", idle ? "enabled" : "disabled"); amdgpu_gfx_off_ctrl(adev, idle); } else if ((IP_VERSION_MAJ(amdgpu_ip_version(adev, GC_HWIP, 0)) == 9) && @@ -710,35 +722,6 @@ bool amdgpu_amdkfd_is_kfd_vmid(struct amdgpu_device *adev, u32 vmid) return false; } -int amdgpu_amdkfd_flush_gpu_tlb_vmid(struct amdgpu_device *adev, - uint16_t vmid) -{ - if (adev->family == AMDGPU_FAMILY_AI) { - int i; - - for_each_set_bit(i, adev->vmhubs_mask, AMDGPU_MAX_VMHUBS) - amdgpu_gmc_flush_gpu_tlb(adev, vmid, i, 0); - } else { - amdgpu_gmc_flush_gpu_tlb(adev, vmid, AMDGPU_GFXHUB(0), 0); - } - - return 0; -} - -int amdgpu_amdkfd_flush_gpu_tlb_pasid(struct amdgpu_device *adev, - uint16_t pasid, - enum TLB_FLUSH_TYPE flush_type, - uint32_t inst) -{ - bool all_hub = false; - - if (adev->family == AMDGPU_FAMILY_AI || - adev->family == AMDGPU_FAMILY_RV) - all_hub = true; - - return amdgpu_gmc_flush_gpu_tlb_pasid(adev, pasid, flush_type, all_hub, inst); -} - bool amdgpu_amdkfd_have_atomics_support(struct amdgpu_device *adev) { return adev->have_atomics_support; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h index dac983da961d6a..f262b9d89541a8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h @@ -33,6 +33,7 @@ #include #include #include +#include #include "amdgpu_sync.h" #include "amdgpu_vm.h" #include "amdgpu_xcp.h" @@ -83,6 +84,7 @@ struct kgd_mem { struct amdgpu_sync sync; + uint32_t gem_handle; bool aql_queue; bool is_imported; }; @@ -105,6 +107,9 @@ struct amdgpu_kfd_dev { /* HMM page migration MEMORY_DEVICE_PRIVATE mapping */ struct dev_pagemap pgmap; + + /* Client for KFD BO GEM handle allocations */ + struct drm_client_dev client; }; enum kgd_engine_type { @@ -162,11 +167,6 @@ int amdgpu_amdkfd_submit_ib(struct amdgpu_device *adev, uint32_t *ib_cmd, uint32_t ib_len); void amdgpu_amdkfd_set_compute_idle(struct amdgpu_device *adev, bool idle); bool amdgpu_amdkfd_have_atomics_support(struct amdgpu_device *adev); -int amdgpu_amdkfd_flush_gpu_tlb_vmid(struct amdgpu_device *adev, - uint16_t vmid); -int amdgpu_amdkfd_flush_gpu_tlb_pasid(struct amdgpu_device *adev, - uint16_t pasid, enum TLB_FLUSH_TYPE flush_type, - uint32_t inst); bool amdgpu_amdkfd_is_kfd_vmid(struct amdgpu_device *adev, u32 vmid); @@ -311,14 +311,13 @@ void amdgpu_amdkfd_gpuvm_unmap_gtt_bo_from_kernel(struct kgd_mem *mem); int amdgpu_amdkfd_map_gtt_bo_to_gart(struct amdgpu_device *adev, struct amdgpu_bo *bo); int amdgpu_amdkfd_gpuvm_restore_process_bos(void *process_info, - struct dma_fence **ef); + struct dma_fence __rcu **ef); int amdgpu_amdkfd_gpuvm_get_vm_fault_info(struct amdgpu_device *adev, struct kfd_vm_fault_info *info); -int amdgpu_amdkfd_gpuvm_import_dmabuf(struct amdgpu_device *adev, - struct dma_buf *dmabuf, - uint64_t va, void *drm_priv, - struct kgd_mem **mem, uint64_t *size, - uint64_t *mmap_offset); +int amdgpu_amdkfd_gpuvm_import_dmabuf_fd(struct amdgpu_device *adev, int fd, + uint64_t va, void *drm_priv, + struct kgd_mem **mem, uint64_t *size, + uint64_t *mmap_offset); int amdgpu_amdkfd_gpuvm_export_dmabuf(struct kgd_mem *mem, struct dma_buf **dmabuf); void amdgpu_amdkfd_debug_mem_fence(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_arcturus.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_arcturus.c index 625db444df1cb6..899e31e3a5e81d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_arcturus.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_arcturus.c @@ -200,7 +200,7 @@ int kgd_arcturus_hqd_sdma_dump(struct amdgpu_device *adev, #undef HQD_N_REGS #define HQD_N_REGS (19+6+7+10) - *dump = kmalloc_array(HQD_N_REGS * 2, sizeof(uint32_t), GFP_KERNEL); + *dump = kmalloc_array(HQD_N_REGS, sizeof(**dump), GFP_KERNEL); if (*dump == NULL) return -ENOMEM; @@ -290,7 +290,7 @@ static int suspend_resume_compute_scheduler(struct amdgpu_device *adev, bool sus for (i = 0; i < adev->gfx.num_compute_rings; i++) { struct amdgpu_ring *ring = &adev->gfx.compute_ring[i]; - if (!(ring && ring->sched.thread)) + if (!(ring && drm_sched_wqueue_ready(&ring->sched))) continue; /* stop secheduler and drain ring. */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c index 469785d337911a..1ef758ac5076ef 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_fence.c @@ -90,7 +90,7 @@ struct amdgpu_amdkfd_fence *to_amdgpu_amdkfd_fence(struct dma_fence *f) return NULL; fence = container_of(f, struct amdgpu_amdkfd_fence, base); - if (fence && f->ops == &amdkfd_fence_ops) + if (f->ops == &amdkfd_fence_ops) return fence; return NULL; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gc_9_4_3.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gc_9_4_3.c index f6598b9e4faa35..a5c7259cf2a3e8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gc_9_4_3.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gc_9_4_3.c @@ -141,7 +141,7 @@ static int kgd_gfx_v9_4_3_hqd_sdma_dump(struct amdgpu_device *adev, (*dump)[i++][1] = RREG32(addr); \ } while (0) - *dump = kmalloc_array(HQD_N_REGS * 2, sizeof(uint32_t), GFP_KERNEL); + *dump = kmalloc_array(HQD_N_REGS, sizeof(**dump), GFP_KERNEL); if (*dump == NULL) return -ENOMEM; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c index 6bf448ab3dffc1..ca4a6b82817f53 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c @@ -214,7 +214,7 @@ static int kgd_hqd_dump(struct amdgpu_device *adev, (*dump)[i++][1] = RREG32(addr); \ } while (0) - *dump = kmalloc_array(HQD_N_REGS * 2, sizeof(uint32_t), GFP_KERNEL); + *dump = kmalloc_array(HQD_N_REGS, sizeof(**dump), GFP_KERNEL); if (*dump == NULL) return -ENOMEM; @@ -301,7 +301,7 @@ static int kgd_hqd_sdma_dump(struct amdgpu_device *adev, #undef HQD_N_REGS #define HQD_N_REGS (19+4) - *dump = kmalloc_array(HQD_N_REGS * 2, sizeof(uint32_t), GFP_KERNEL); + *dump = kmalloc_array(HQD_N_REGS, sizeof(**dump), GFP_KERNEL); if (*dump == NULL) return -ENOMEM; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c index cd06e4a6d1da48..0f3e2944edd7e9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c @@ -238,7 +238,7 @@ static int kgd_hqd_dump(struct amdgpu_device *adev, (*dump)[i++][1] = RREG32(addr); \ } while (0) - *dump = kmalloc_array(HQD_N_REGS * 2, sizeof(uint32_t), GFP_KERNEL); + *dump = kmalloc_array(HQD_N_REGS, sizeof(**dump), GFP_KERNEL); if (*dump == NULL) return -ENOMEM; @@ -324,7 +324,7 @@ static int kgd_hqd_sdma_dump(struct amdgpu_device *adev, #undef HQD_N_REGS #define HQD_N_REGS (19+4+2+3+7) - *dump = kmalloc_array(HQD_N_REGS * 2, sizeof(uint32_t), GFP_KERNEL); + *dump = kmalloc_array(HQD_N_REGS, sizeof(**dump), GFP_KERNEL); if (*dump == NULL) return -ENOMEM; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c index 00fbc0f44c929b..5a35a8ca89222b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c @@ -363,7 +363,7 @@ int kgd_gfx_v9_hqd_dump(struct amdgpu_device *adev, (*dump)[i++][1] = RREG32(addr); \ } while (0) - *dump = kmalloc_array(HQD_N_REGS * 2, sizeof(uint32_t), GFP_KERNEL); + *dump = kmalloc_array(HQD_N_REGS, sizeof(**dump), GFP_KERNEL); if (*dump == NULL) return -ENOMEM; @@ -460,7 +460,7 @@ static int kgd_hqd_sdma_dump(struct amdgpu_device *adev, #undef HQD_N_REGS #define HQD_N_REGS (19+6+7+10) - *dump = kmalloc_array(HQD_N_REGS * 2, sizeof(uint32_t), GFP_KERNEL); + *dump = kmalloc_array(HQD_N_REGS, sizeof(**dump), GFP_KERNEL); if (*dump == NULL) return -ENOMEM; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index 41fbc4fd0fac30..f183d7faeeece1 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 #include #include +#include #include #include @@ -806,13 +807,22 @@ kfd_mem_dmaunmap_attachment(struct kgd_mem *mem, static int kfd_mem_export_dmabuf(struct kgd_mem *mem) { if (!mem->dmabuf) { - struct dma_buf *ret = amdgpu_gem_prime_export( - &mem->bo->tbo.base, + struct amdgpu_device *bo_adev; + struct dma_buf *dmabuf; + int r, fd; + + bo_adev = amdgpu_ttm_adev(mem->bo->tbo.bdev); + r = drm_gem_prime_handle_to_fd(&bo_adev->ddev, bo_adev->kfd.client.file, + mem->gem_handle, mem->alloc_flags & KFD_IOC_ALLOC_MEM_FLAGS_WRITABLE ? - DRM_RDWR : 0); - if (IS_ERR(ret)) - return PTR_ERR(ret); - mem->dmabuf = ret; + DRM_RDWR : 0, &fd); + if (r) + return r; + dmabuf = dma_buf_get(fd); + close_fd(fd); + if (WARN_ON_ONCE(IS_ERR(dmabuf))) + return PTR_ERR(dmabuf); + mem->dmabuf = dmabuf; } return 0; @@ -1137,7 +1147,7 @@ static int reserve_bo_and_vm(struct kgd_mem *mem, ctx->n_vms = 1; ctx->sync = &mem->sync; - drm_exec_init(&ctx->exec, DRM_EXEC_INTERRUPTIBLE_WAIT); + drm_exec_init(&ctx->exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0); drm_exec_until_all_locked(&ctx->exec) { ret = amdgpu_vm_lock_pd(vm, &ctx->exec, 2); drm_exec_retry_on_contention(&ctx->exec); @@ -1176,7 +1186,7 @@ static int reserve_bo_and_cond_vms(struct kgd_mem *mem, int ret; ctx->sync = &mem->sync; - drm_exec_init(&ctx->exec, DRM_EXEC_INTERRUPTIBLE_WAIT); + drm_exec_init(&ctx->exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0); drm_exec_until_all_locked(&ctx->exec) { ctx->n_vms = 0; list_for_each_entry(entry, &mem->attachments, list) { @@ -1384,7 +1394,6 @@ static int init_kfd_vm(struct amdgpu_vm *vm, void **process_info, amdgpu_amdkfd_restore_userptr_worker); *process_info = info; - *ef = dma_fence_get(&info->eviction_fence->base); } vm->process_info = *process_info; @@ -1415,6 +1424,8 @@ static int init_kfd_vm(struct amdgpu_vm *vm, void **process_info, list_add_tail(&vm->vm_list_node, &(vm->process_info->vm_list_head)); vm->process_info->n_vms++; + + *ef = dma_fence_get(&vm->process_info->eviction_fence->base); mutex_unlock(&vm->process_info->lock); return 0; @@ -1426,10 +1437,7 @@ validate_pd_fail: reserve_pd_fail: vm->process_info = NULL; if (info) { - /* Two fence references: one in info and one in *ef */ dma_fence_put(&info->eviction_fence->base); - dma_fence_put(*ef); - *ef = NULL; *process_info = NULL; put_pid(info->pid); create_evict_fence_fail: @@ -1623,7 +1631,8 @@ int amdgpu_amdkfd_criu_resume(void *p) goto out_unlock; } WRITE_ONCE(pinfo->block_mmu_notifications, false); - schedule_delayed_work(&pinfo->restore_userptr_work, 0); + queue_delayed_work(system_freezable_wq, + &pinfo->restore_userptr_work, 0); out_unlock: mutex_unlock(&pinfo->lock); @@ -1779,6 +1788,9 @@ int amdgpu_amdkfd_gpuvm_alloc_memory_of_gpu( pr_debug("Failed to allow vma node access. ret %d\n", ret); goto err_node_allow; } + ret = drm_gem_handle_create(adev->kfd.client.file, gobj, &(*mem)->gem_handle); + if (ret) + goto err_gem_handle_create; bo = gem_to_amdgpu_bo(gobj); if (bo_type == ttm_bo_type_sg) { bo->tbo.sg = sg; @@ -1830,6 +1842,8 @@ allocate_init_user_pages_failed: err_pin_bo: err_validate_bo: remove_kgd_mem_from_kfd_bo_list(*mem, avm->process_info); + drm_gem_handle_delete(adev->kfd.client.file, (*mem)->gem_handle); +err_gem_handle_create: drm_vma_node_revoke(&gobj->vma_node, drm_priv); err_node_allow: /* Don't unreserve system mem limit twice */ @@ -1942,8 +1956,11 @@ int amdgpu_amdkfd_gpuvm_free_memory_of_gpu( /* Free the BO*/ drm_vma_node_revoke(&mem->bo->tbo.base.vma_node, drm_priv); - if (mem->dmabuf) + drm_gem_handle_delete(adev->kfd.client.file, mem->gem_handle); + if (mem->dmabuf) { dma_buf_put(mem->dmabuf); + mem->dmabuf = NULL; + } mutex_destroy(&mem->lock); /* If this releases the last reference, it will end up calling @@ -2295,34 +2312,26 @@ int amdgpu_amdkfd_gpuvm_get_vm_fault_info(struct amdgpu_device *adev, return 0; } -int amdgpu_amdkfd_gpuvm_import_dmabuf(struct amdgpu_device *adev, - struct dma_buf *dma_buf, - uint64_t va, void *drm_priv, - struct kgd_mem **mem, uint64_t *size, - uint64_t *mmap_offset) +static int import_obj_create(struct amdgpu_device *adev, + struct dma_buf *dma_buf, + struct drm_gem_object *obj, + uint64_t va, void *drm_priv, + struct kgd_mem **mem, uint64_t *size, + uint64_t *mmap_offset) { struct amdgpu_vm *avm = drm_priv_to_vm(drm_priv); - struct drm_gem_object *obj; struct amdgpu_bo *bo; int ret; - obj = amdgpu_gem_prime_import(adev_to_drm(adev), dma_buf); - if (IS_ERR(obj)) - return PTR_ERR(obj); - bo = gem_to_amdgpu_bo(obj); if (!(bo->preferred_domains & (AMDGPU_GEM_DOMAIN_VRAM | - AMDGPU_GEM_DOMAIN_GTT))) { + AMDGPU_GEM_DOMAIN_GTT))) /* Only VRAM and GTT BOs are supported */ - ret = -EINVAL; - goto err_put_obj; - } + return -EINVAL; *mem = kzalloc(sizeof(struct kgd_mem), GFP_KERNEL); - if (!*mem) { - ret = -ENOMEM; - goto err_put_obj; - } + if (!*mem) + return -ENOMEM; ret = drm_vma_node_allow(&obj->vma_node, drm_priv); if (ret) @@ -2372,8 +2381,41 @@ err_remove_mem: drm_vma_node_revoke(&obj->vma_node, drm_priv); err_free_mem: kfree(*mem); + return ret; +} + +int amdgpu_amdkfd_gpuvm_import_dmabuf_fd(struct amdgpu_device *adev, int fd, + uint64_t va, void *drm_priv, + struct kgd_mem **mem, uint64_t *size, + uint64_t *mmap_offset) +{ + struct drm_gem_object *obj; + uint32_t handle; + int ret; + + ret = drm_gem_prime_fd_to_handle(&adev->ddev, adev->kfd.client.file, fd, + &handle); + if (ret) + return ret; + obj = drm_gem_object_lookup(adev->kfd.client.file, handle); + if (!obj) { + ret = -EINVAL; + goto err_release_handle; + } + + ret = import_obj_create(adev, obj->dma_buf, obj, va, drm_priv, mem, size, + mmap_offset); + if (ret) + goto err_put_obj; + + (*mem)->gem_handle = handle; + + return 0; + err_put_obj: drm_gem_object_put(obj); +err_release_handle: + drm_gem_handle_delete(adev->kfd.client.file, handle); return ret; } @@ -2426,7 +2468,8 @@ int amdgpu_amdkfd_evict_userptr(struct mmu_interval_notifier *mni, KFD_QUEUE_EVICTION_TRIGGER_USERPTR); if (r) pr_err("Failed to quiesce KFD\n"); - schedule_delayed_work(&process_info->restore_userptr_work, + queue_delayed_work(system_freezable_wq, + &process_info->restore_userptr_work, msecs_to_jiffies(AMDGPU_USERPTR_RESTORE_DELAY_MS)); } mutex_unlock(&process_info->notifier_lock); @@ -2552,7 +2595,7 @@ static int validate_invalid_user_pages(struct amdkfd_process_info *process_info) amdgpu_sync_create(&sync); - drm_exec_init(&exec, 0); + drm_exec_init(&exec, 0, 0); /* Reserve all BOs and page tables for validation */ drm_exec_until_all_locked(&exec) { /* Reserve all the page directories */ @@ -2749,7 +2792,8 @@ unlock_out: /* If validation failed, reschedule another attempt */ if (evicted_bos) { - schedule_delayed_work(&process_info->restore_userptr_work, + queue_delayed_work(system_freezable_wq, + &process_info->restore_userptr_work, msecs_to_jiffies(AMDGPU_USERPTR_RESTORE_DELAY_MS)); kfd_smi_event_queue_restore_rescheduled(mm); @@ -2758,6 +2802,23 @@ unlock_out: put_task_struct(usertask); } +static void replace_eviction_fence(struct dma_fence __rcu **ef, + struct dma_fence *new_ef) +{ + struct dma_fence *old_ef = rcu_replace_pointer(*ef, new_ef, true + /* protected by process_info->lock */); + + /* If we're replacing an unsignaled eviction fence, that fence will + * never be signaled, and if anyone is still waiting on that fence, + * they will hang forever. This should never happen. We should only + * replace the fence in restore_work that only gets scheduled after + * eviction work signaled the fence. + */ + WARN_ONCE(!dma_fence_is_signaled(old_ef), + "Replacing unsignaled eviction fence"); + dma_fence_put(old_ef); +} + /** amdgpu_amdkfd_gpuvm_restore_process_bos - Restore all BOs for the given * KFD process identified by process_info * @@ -2776,12 +2837,11 @@ unlock_out: * 7. Add fence to all PD and PT BOs. * 8. Unreserve all BOs */ -int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence **ef) +int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence __rcu **ef) { struct amdkfd_process_info *process_info = info; struct amdgpu_vm *peer_vm; struct kgd_mem *mem; - struct amdgpu_amdkfd_fence *new_fence; struct list_head duplicate_save; struct amdgpu_sync sync_obj; unsigned long failed_size = 0; @@ -2793,7 +2853,7 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence **ef) mutex_lock(&process_info->lock); - drm_exec_init(&exec, 0); + drm_exec_init(&exec, 0, 0); drm_exec_until_all_locked(&exec) { list_for_each_entry(peer_vm, &process_info->vm_list_head, vm_list_node) { @@ -2825,12 +2885,6 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence **ef) if (ret) goto validate_map_fail; - ret = process_sync_pds_resv(process_info, &sync_obj); - if (ret) { - pr_debug("Memory eviction: Failed to sync to PD BO moving fence. Try again\n"); - goto validate_map_fail; - } - /* Validate BOs and map them to GPUVM (update VM page tables). */ list_for_each_entry(mem, &process_info->kfd_bo_list, validate_list) { @@ -2881,6 +2935,19 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence **ef) if (failed_size) pr_debug("0x%lx/0x%lx in system\n", failed_size, total_size); + /* Update mappings not managed by KFD */ + list_for_each_entry(peer_vm, &process_info->vm_list_head, + vm_list_node) { + struct amdgpu_device *adev = amdgpu_ttm_adev( + peer_vm->root.bo->tbo.bdev); + + ret = amdgpu_vm_handle_moved(adev, peer_vm, &exec.ticket); + if (ret) { + pr_debug("Memory eviction: handle moved failed. Try again\n"); + goto validate_map_fail; + } + } + /* Update page directories */ ret = process_update_pds(process_info, &sync_obj); if (ret) { @@ -2888,25 +2955,47 @@ int amdgpu_amdkfd_gpuvm_restore_process_bos(void *info, struct dma_fence **ef) goto validate_map_fail; } + /* Sync with fences on all the page tables. They implicitly depend on any + * move fences from amdgpu_vm_handle_moved above. + */ + ret = process_sync_pds_resv(process_info, &sync_obj); + if (ret) { + pr_debug("Memory eviction: Failed to sync to PD BO moving fence. Try again\n"); + goto validate_map_fail; + } + /* Wait for validate and PT updates to finish */ amdgpu_sync_wait(&sync_obj, false); - /* Release old eviction fence and create new one, because fence only - * goes from unsignaled to signaled, fence cannot be reused. - * Use context and mm from the old fence. + /* The old eviction fence may be unsignaled if restore happens + * after a GPU reset or suspend/resume. Keep the old fence in that + * case. Otherwise release the old eviction fence and create new + * one, because fence only goes from unsignaled to signaled once + * and cannot be reused. Use context and mm from the old fence. + * + * If an old eviction fence signals after this check, that's OK. + * Anyone signaling an eviction fence must stop the queues first + * and schedule another restore worker. */ - new_fence = amdgpu_amdkfd_fence_create( + if (dma_fence_is_signaled(&process_info->eviction_fence->base)) { + struct amdgpu_amdkfd_fence *new_fence = + amdgpu_amdkfd_fence_create( process_info->eviction_fence->base.context, process_info->eviction_fence->mm, NULL); - if (!new_fence) { - pr_err("Failed to create eviction fence\n"); - ret = -ENOMEM; - goto validate_map_fail; + + if (!new_fence) { + pr_err("Failed to create eviction fence\n"); + ret = -ENOMEM; + goto validate_map_fail; + } + dma_fence_put(&process_info->eviction_fence->base); + process_info->eviction_fence = new_fence; + replace_eviction_fence(ef, dma_fence_get(&new_fence->base)); + } else { + WARN_ONCE(*ef != &process_info->eviction_fence->base, + "KFD eviction fence doesn't match KGD process_info"); } - dma_fence_put(&process_info->eviction_fence->base); - process_info->eviction_fence = new_fence; - *ef = dma_fence_get(&new_fence->base); /* Attach new eviction fence to all BOs except pinned ones */ list_for_each_entry(mem, &process_info->kfd_bo_list, validate_list) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c index 7473a42f7d454f..9caba10315a813 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c @@ -103,7 +103,7 @@ int amdgpu_connector_get_monitor_bpc(struct drm_connector *connector) struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); struct amdgpu_connector_atom_dig *dig_connector; int bpc = 8; - unsigned mode_clock, max_tmds_clock; + unsigned int mode_clock, max_tmds_clock; switch (connector->connector_type) { case DRM_MODE_CONNECTOR_DVII: @@ -255,6 +255,7 @@ struct edid *amdgpu_connector_edid(struct drm_connector *connector) return amdgpu_connector->edid; } else if (edid_blob) { struct edid *edid = kmemdup(edid_blob->data, edid_blob->length, GFP_KERNEL); + if (edid) amdgpu_connector->edid = edid; } @@ -581,6 +582,7 @@ static int amdgpu_connector_set_property(struct drm_connector *connector, amdgpu_encoder = to_amdgpu_encoder(connector->encoder); } else { const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; + amdgpu_encoder = to_amdgpu_encoder(connector_funcs->best_encoder(connector)); } @@ -797,6 +799,7 @@ static int amdgpu_connector_set_lcd_property(struct drm_connector *connector, amdgpu_encoder = to_amdgpu_encoder(connector->encoder); else { const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; + amdgpu_encoder = to_amdgpu_encoder(connector_funcs->best_encoder(connector)); } @@ -979,6 +982,41 @@ amdgpu_connector_check_hpd_status_unchanged(struct drm_connector *connector) return false; } +static void amdgpu_connector_shared_ddc(enum drm_connector_status *status, + struct drm_connector *connector, + struct amdgpu_connector *amdgpu_connector) +{ + struct drm_connector *list_connector; + struct drm_connector_list_iter iter; + struct amdgpu_connector *list_amdgpu_connector; + struct drm_device *dev = connector->dev; + struct amdgpu_device *adev = drm_to_adev(dev); + + if (amdgpu_connector->shared_ddc && *status == connector_status_connected) { + drm_connector_list_iter_begin(dev, &iter); + drm_for_each_connector_iter(list_connector, + &iter) { + if (connector == list_connector) + continue; + list_amdgpu_connector = to_amdgpu_connector(list_connector); + if (list_amdgpu_connector->shared_ddc && + list_amdgpu_connector->ddc_bus->rec.i2c_id == + amdgpu_connector->ddc_bus->rec.i2c_id) { + /* cases where both connectors are digital */ + if (list_connector->connector_type != DRM_MODE_CONNECTOR_VGA) { + /* hpd is our only option in this case */ + if (!amdgpu_display_hpd_sense(adev, + amdgpu_connector->hpd.hpd)) { + amdgpu_connector_free_edid(connector); + *status = connector_status_disconnected; + } + } + } + } + drm_connector_list_iter_end(&iter); + } +} + /* * DVI is complicated * Do a DDC probe, if DDC probe passes, get the full EDID so @@ -1065,32 +1103,7 @@ amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force) * DDC line. The latter is more complex because with DVI<->HDMI adapters * you don't really know what's connected to which port as both are digital. */ - if (amdgpu_connector->shared_ddc && (ret == connector_status_connected)) { - struct drm_connector *list_connector; - struct drm_connector_list_iter iter; - struct amdgpu_connector *list_amdgpu_connector; - - drm_connector_list_iter_begin(dev, &iter); - drm_for_each_connector_iter(list_connector, - &iter) { - if (connector == list_connector) - continue; - list_amdgpu_connector = to_amdgpu_connector(list_connector); - if (list_amdgpu_connector->shared_ddc && - (list_amdgpu_connector->ddc_bus->rec.i2c_id == - amdgpu_connector->ddc_bus->rec.i2c_id)) { - /* cases where both connectors are digital */ - if (list_connector->connector_type != DRM_MODE_CONNECTOR_VGA) { - /* hpd is our only option in this case */ - if (!amdgpu_display_hpd_sense(adev, amdgpu_connector->hpd.hpd)) { - amdgpu_connector_free_edid(connector); - ret = connector_status_disconnected; - } - } - } - } - drm_connector_list_iter_end(&iter); - } + amdgpu_connector_shared_ddc(&ret, connector, amdgpu_connector); } } @@ -1192,6 +1205,7 @@ amdgpu_connector_dvi_encoder(struct drm_connector *connector) static void amdgpu_connector_dvi_force(struct drm_connector *connector) { struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); + if (connector->force == DRM_FORCE_ON) amdgpu_connector->use_digital = false; if (connector->force == DRM_FORCE_ON_DIGITAL) @@ -1426,6 +1440,7 @@ amdgpu_connector_dp_detect(struct drm_connector *connector, bool force) ret = connector_status_connected; else if (amdgpu_connector->dac_load_detect) { /* try load detection */ const struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; + ret = encoder_funcs->detect(encoder, connector); } } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index e50be65000303a..6adeddfb3d5643 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -66,7 +66,7 @@ static int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, amdgpu_sync_create(&p->sync); drm_exec_init(&p->exec, DRM_EXEC_INTERRUPTIBLE_WAIT | - DRM_EXEC_IGNORE_DUPLICATES); + DRM_EXEC_IGNORE_DUPLICATES, 0); return 0; } @@ -870,9 +870,9 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, struct amdgpu_bo *bo = e->bo; int i; - e->user_pages = kvmalloc_array(bo->tbo.ttm->num_pages, - sizeof(struct page *), - GFP_KERNEL | __GFP_ZERO); + e->user_pages = kvcalloc(bo->tbo.ttm->num_pages, + sizeof(struct page *), + GFP_KERNEL); if (!e->user_pages) { DRM_ERROR("kvmalloc_array failure\n"); r = -ENOMEM; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.c index 7200110197415f..796fa6f1420b33 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.c @@ -70,7 +70,7 @@ int amdgpu_map_static_csa(struct amdgpu_device *adev, struct amdgpu_vm *vm, struct drm_exec exec; int r; - drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT); + drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0); drm_exec_until_all_locked(&exec) { r = amdgpu_vm_lock_pd(vm, &exec, 0); if (likely(!r)) @@ -110,7 +110,7 @@ int amdgpu_unmap_static_csa(struct amdgpu_device *adev, struct amdgpu_vm *vm, struct drm_exec exec; int r; - drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT); + drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0); drm_exec_until_all_locked(&exec) { r = amdgpu_vm_lock_pd(vm, &exec, 0); if (likely(!r)) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c index e2ae9ba147ba97..5cb33ac99f7089 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c @@ -73,10 +73,10 @@ amdgpu_ctx_to_drm_sched_prio(int32_t ctx_prio) return DRM_SCHED_PRIORITY_NORMAL; case AMDGPU_CTX_PRIORITY_VERY_LOW: - return DRM_SCHED_PRIORITY_MIN; + return DRM_SCHED_PRIORITY_LOW; case AMDGPU_CTX_PRIORITY_LOW: - return DRM_SCHED_PRIORITY_MIN; + return DRM_SCHED_PRIORITY_LOW; case AMDGPU_CTX_PRIORITY_NORMAL: return DRM_SCHED_PRIORITY_NORMAL; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c index 0e61ebdb3f3e59..e485dd3357c63f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c @@ -540,7 +540,11 @@ static ssize_t amdgpu_debugfs_regs_pcie_read(struct file *f, char __user *buf, while (size) { uint32_t value; - value = RREG32_PCIE(*pos); + if (upper_32_bits(*pos)) + value = RREG32_PCIE_EXT(*pos); + else + value = RREG32_PCIE(*pos); + r = put_user(value, (uint32_t *)buf); if (r) goto out; @@ -600,7 +604,10 @@ static ssize_t amdgpu_debugfs_regs_pcie_write(struct file *f, const char __user if (r) goto out; - WREG32_PCIE(*pos, value); + if (upper_32_bits(*pos)) + WREG32_PCIE_EXT(*pos, value); + else + WREG32_PCIE(*pos, value); result += 4; buf += 4; @@ -755,7 +762,7 @@ static ssize_t amdgpu_debugfs_regs_smc_read(struct file *f, char __user *buf, int r; if (!adev->smc_rreg) - return -EPERM; + return -EOPNOTSUPP; if (size & 0x3 || *pos & 0x3) return -EINVAL; @@ -814,7 +821,7 @@ static ssize_t amdgpu_debugfs_regs_smc_write(struct file *f, const char __user * int r; if (!adev->smc_wreg) - return -EPERM; + return -EOPNOTSUPP; if (size & 0x3 || *pos & 0x3) return -EINVAL; @@ -1671,9 +1678,9 @@ static int amdgpu_debugfs_test_ib_show(struct seq_file *m, void *unused) for (i = 0; i < AMDGPU_MAX_RINGS; i++) { struct amdgpu_ring *ring = adev->rings[i]; - if (!ring || !ring->sched.thread) + if (!ring || !drm_sched_wqueue_ready(&ring->sched)) continue; - kthread_park(ring->sched.thread); + drm_sched_wqueue_stop(&ring->sched); } seq_puts(m, "run ib test:\n"); @@ -1687,9 +1694,9 @@ static int amdgpu_debugfs_test_ib_show(struct seq_file *m, void *unused) for (i = 0; i < AMDGPU_MAX_RINGS; i++) { struct amdgpu_ring *ring = adev->rings[i]; - if (!ring || !ring->sched.thread) + if (!ring || !drm_sched_wqueue_ready(&ring->sched)) continue; - kthread_unpark(ring->sched.thread); + drm_sched_wqueue_start(&ring->sched); } up_write(&adev->reset_domain->sem); @@ -1909,7 +1916,8 @@ static int amdgpu_debugfs_ib_preempt(void *data, u64 val) ring = adev->rings[val]; - if (!ring || !ring->funcs->preempt_ib || !ring->sched.thread) + if (!ring || !ring->funcs->preempt_ib || + !drm_sched_wqueue_ready(&ring->sched)) return -EINVAL; /* the last preemption failed */ @@ -1927,7 +1935,7 @@ static int amdgpu_debugfs_ib_preempt(void *data, u64 val) goto pro_end; /* stop the scheduler */ - kthread_park(ring->sched.thread); + drm_sched_wqueue_stop(&ring->sched); /* preempt the IB */ r = amdgpu_ring_preempt_ib(ring); @@ -1961,7 +1969,7 @@ static int amdgpu_debugfs_ib_preempt(void *data, u64 val) failure: /* restart the scheduler */ - kthread_unpark(ring->sched.thread); + drm_sched_wqueue_start(&ring->sched); up_read(&adev->reset_domain->sem); @@ -2146,6 +2154,8 @@ int amdgpu_debugfs_init(struct amdgpu_device *adev) amdgpu_debugfs_firmware_init(adev); amdgpu_ta_if_debugfs_init(adev); + amdgpu_debugfs_mes_event_log_init(adev); + #if defined(CONFIG_DRM_AMD_DC) if (adev->dc_enabled) dtn_debugfs_init(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h index 371a6f0deb2998..0425432d8659ba 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.h @@ -32,3 +32,5 @@ void amdgpu_debugfs_fini(struct amdgpu_device *adev); void amdgpu_debugfs_fence_init(struct amdgpu_device *adev); void amdgpu_debugfs_firmware_init(struct amdgpu_device *adev); void amdgpu_debugfs_gem_init(struct amdgpu_device *adev); +void amdgpu_debugfs_mes_event_log_init(struct amdgpu_device *adev); + diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 93cf73d6fa118f..b158d27d0a71cb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -162,6 +162,65 @@ static ssize_t amdgpu_device_get_pcie_replay_count(struct device *dev, static DEVICE_ATTR(pcie_replay_count, 0444, amdgpu_device_get_pcie_replay_count, NULL); +static ssize_t amdgpu_sysfs_reg_state_get(struct file *f, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t ppos, size_t count) +{ + struct device *dev = kobj_to_dev(kobj); + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(ddev); + ssize_t bytes_read; + + switch (ppos) { + case AMDGPU_SYS_REG_STATE_XGMI: + bytes_read = amdgpu_asic_get_reg_state( + adev, AMDGPU_REG_STATE_TYPE_XGMI, buf, count); + break; + case AMDGPU_SYS_REG_STATE_WAFL: + bytes_read = amdgpu_asic_get_reg_state( + adev, AMDGPU_REG_STATE_TYPE_WAFL, buf, count); + break; + case AMDGPU_SYS_REG_STATE_PCIE: + bytes_read = amdgpu_asic_get_reg_state( + adev, AMDGPU_REG_STATE_TYPE_PCIE, buf, count); + break; + case AMDGPU_SYS_REG_STATE_USR: + bytes_read = amdgpu_asic_get_reg_state( + adev, AMDGPU_REG_STATE_TYPE_USR, buf, count); + break; + case AMDGPU_SYS_REG_STATE_USR_1: + bytes_read = amdgpu_asic_get_reg_state( + adev, AMDGPU_REG_STATE_TYPE_USR_1, buf, count); + break; + default: + return -EINVAL; + } + + return bytes_read; +} + +BIN_ATTR(reg_state, 0444, amdgpu_sysfs_reg_state_get, NULL, + AMDGPU_SYS_REG_STATE_END); + +int amdgpu_reg_state_sysfs_init(struct amdgpu_device *adev) +{ + int ret; + + if (!amdgpu_asic_get_reg_state_supported(adev)) + return 0; + + ret = sysfs_create_bin_file(&adev->dev->kobj, &bin_attr_reg_state); + + return ret; +} + +void amdgpu_reg_state_sysfs_fini(struct amdgpu_device *adev) +{ + if (!amdgpu_asic_get_reg_state_supported(adev)) + return; + sysfs_remove_bin_file(&adev->dev->kobj, &bin_attr_reg_state); +} + /** * DOC: board_info * @@ -1485,6 +1544,7 @@ bool amdgpu_device_need_post(struct amdgpu_device *adev) return true; fw_ver = *((uint32_t *)adev->pm.fw->data + 69); + release_firmware(adev->pm.fw); if (fw_ver < 0x00160e00) return true; } @@ -1540,7 +1600,7 @@ bool amdgpu_device_seamless_boot_supported(struct amdgpu_device *adev) if (adev->mman.keep_stolen_vga_memory) return false; - return adev->ip_versions[DCE_HWIP][0] >= IP_VERSION(3, 0, 0); + return amdgpu_ip_version(adev, DCE_HWIP, 0) >= IP_VERSION(3, 0, 0); } /* @@ -1551,11 +1611,15 @@ bool amdgpu_device_seamless_boot_supported(struct amdgpu_device *adev) * https://edc.intel.com/content/www/us/en/design/products/platforms/details/raptor-lake-s/13th-generation-core-processors-datasheet-volume-1-of-2/005/pci-express-support/ * https://gitlab.freedesktop.org/drm/amd/-/issues/2663 */ -static bool amdgpu_device_pcie_dynamic_switching_supported(void) +static bool amdgpu_device_pcie_dynamic_switching_supported(struct amdgpu_device *adev) { #if IS_ENABLED(CONFIG_X86) struct cpuinfo_x86 *c = &cpu_data(0); + /* eGPU change speeds based on USB4 fabric conditions */ + if (dev_is_removable(adev->dev)) + return true; + if (c->x86_vendor == X86_VENDOR_INTEL) return false; #endif @@ -2388,7 +2452,7 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev) adev->pm.pp_feature &= ~PP_GFXOFF_MASK; if (amdgpu_sriov_vf(adev) && adev->asic_type == CHIP_SIENNA_CICHLID) adev->pm.pp_feature &= ~PP_OVERDRIVE_MASK; - if (!amdgpu_device_pcie_dynamic_switching_supported()) + if (!amdgpu_device_pcie_dynamic_switching_supported(adev)) adev->pm.pp_feature &= ~PP_PCIE_DPM_MASK; total = true; @@ -2566,7 +2630,7 @@ static int amdgpu_device_init_schedulers(struct amdgpu_device *adev) break; } - r = drm_sched_init(&ring->sched, &amdgpu_sched_ops, + r = drm_sched_init(&ring->sched, &amdgpu_sched_ops, NULL, DRM_SCHED_PRIORITY_COUNT, ring->num_hw_submission, 0, timeout, adev->reset_domain->wq, @@ -2669,6 +2733,12 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev) goto init_failed; } } + + r = amdgpu_seq64_init(adev); + if (r) { + DRM_ERROR("allocate seq64 failed %d\n", r); + goto init_failed; + } } } @@ -3131,6 +3201,7 @@ static int amdgpu_device_ip_fini(struct amdgpu_device *adev) amdgpu_device_wb_fini(adev); amdgpu_device_mem_scratch_fini(adev); amdgpu_ib_pool_fini(adev); + amdgpu_seq64_fini(adev); } r = adev->ip_blocks[i].version->funcs->sw_fini((void *)adev); @@ -4211,6 +4282,7 @@ fence_driver_init: "Could not create amdgpu board attributes\n"); amdgpu_fru_sysfs_init(adev); + amdgpu_reg_state_sysfs_init(adev); if (IS_ENABLED(CONFIG_PERF_EVENTS)) r = amdgpu_pmu_init(adev); @@ -4333,6 +4405,8 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev) sysfs_remove_files(&adev->dev->kobj, amdgpu_dev_attributes); amdgpu_fru_sysfs_fini(adev); + amdgpu_reg_state_sysfs_fini(adev); + /* disable ras feature must before hw fini */ amdgpu_ras_pre_fini(adev); @@ -4957,7 +5031,7 @@ bool amdgpu_device_has_job_running(struct amdgpu_device *adev) for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { struct amdgpu_ring *ring = adev->rings[i]; - if (!ring || !ring->sched.thread) + if (!ring || !drm_sched_wqueue_ready(&ring->sched)) continue; spin_lock(&ring->sched.job_list_lock); @@ -5096,7 +5170,7 @@ int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev, for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { struct amdgpu_ring *ring = adev->rings[i]; - if (!ring || !ring->sched.thread) + if (!ring || !drm_sched_wqueue_ready(&ring->sched)) continue; /* Clear job fence from fence drv to avoid force_completion @@ -5172,7 +5246,6 @@ int amdgpu_do_asic_reset(struct list_head *device_list_handle, struct amdgpu_device *tmp_adev = NULL; bool need_full_reset, skip_hw_reset, vram_lost = false; int r = 0; - bool gpu_reset_for_dev_remove = 0; /* Try reset handler method first */ tmp_adev = list_first_entry(device_list_handle, struct amdgpu_device, @@ -5192,10 +5265,6 @@ int amdgpu_do_asic_reset(struct list_head *device_list_handle, test_bit(AMDGPU_NEED_FULL_RESET, &reset_context->flags); skip_hw_reset = test_bit(AMDGPU_SKIP_HW_RESET, &reset_context->flags); - gpu_reset_for_dev_remove = - test_bit(AMDGPU_RESET_FOR_DEVICE_REMOVE, &reset_context->flags) && - test_bit(AMDGPU_NEED_FULL_RESET, &reset_context->flags); - /* * ASIC reset has to be done on all XGMI hive nodes ASAP * to allow proper links negotiation in FW (within 1 sec) @@ -5238,18 +5307,6 @@ int amdgpu_do_asic_reset(struct list_head *device_list_handle, amdgpu_ras_intr_cleared(); } - /* Since the mode1 reset affects base ip blocks, the - * phase1 ip blocks need to be resumed. Otherwise there - * will be a BIOS signature error and the psp bootloader - * can't load kdb on the next amdgpu install. - */ - if (gpu_reset_for_dev_remove) { - list_for_each_entry(tmp_adev, device_list_handle, reset_list) - amdgpu_device_ip_resume_phase1(tmp_adev); - - goto end; - } - list_for_each_entry(tmp_adev, device_list_handle, reset_list) { if (need_full_reset) { /* post card */ @@ -5486,11 +5543,6 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, int i, r = 0; bool need_emergency_restart = false; bool audio_suspended = false; - bool gpu_reset_for_dev_remove = false; - - gpu_reset_for_dev_remove = - test_bit(AMDGPU_RESET_FOR_DEVICE_REMOVE, &reset_context->flags) && - test_bit(AMDGPU_NEED_FULL_RESET, &reset_context->flags); /* * Special case: RAS triggered and full reset isn't supported @@ -5528,7 +5580,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, if (!amdgpu_sriov_vf(adev) && (adev->gmc.xgmi.num_physical_nodes > 1)) { list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head) { list_add_tail(&tmp_adev->reset_list, &device_list); - if (gpu_reset_for_dev_remove && adev->shutdown) + if (adev->shutdown) tmp_adev->shutdown = true; } if (!list_is_first(&adev->reset_list, &device_list)) @@ -5585,7 +5637,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { struct amdgpu_ring *ring = tmp_adev->rings[i]; - if (!ring || !ring->sched.thread) + if (!ring || !drm_sched_wqueue_ready(&ring->sched)) continue; drm_sched_stop(&ring->sched, job ? &job->base : NULL); @@ -5613,10 +5665,6 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, retry: /* Rest of adevs pre asic reset from XGMI hive. */ list_for_each_entry(tmp_adev, device_list_handle, reset_list) { - if (gpu_reset_for_dev_remove) { - /* Workaroud for ASICs need to disable SMC first */ - amdgpu_device_smu_fini_early(tmp_adev); - } r = amdgpu_device_pre_asic_reset(tmp_adev, reset_context); /*TODO Should we stop ?*/ if (r) { @@ -5648,9 +5696,6 @@ retry: /* Rest of adevs pre asic reset from XGMI hive. */ r = amdgpu_do_asic_reset(device_list_handle, reset_context); if (r && r == -EAGAIN) goto retry; - - if (!r && gpu_reset_for_dev_remove) - goto recover_end; } skip_hw_reset: @@ -5661,7 +5706,7 @@ skip_hw_reset: for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { struct amdgpu_ring *ring = tmp_adev->rings[i]; - if (!ring || !ring->sched.thread) + if (!ring || !drm_sched_wqueue_ready(&ring->sched)) continue; drm_sched_start(&ring->sched, true); @@ -5706,7 +5751,6 @@ skip_sched_resume: amdgpu_ras_set_error_query_ready(tmp_adev, true); } -recover_end: tmp_adev = list_first_entry(device_list_handle, struct amdgpu_device, reset_list); amdgpu_device_unlock_reset_domain(tmp_adev->reset_domain); @@ -5723,6 +5767,39 @@ recover_end: return r; } +/** + * amdgpu_device_partner_bandwidth - find the bandwidth of appropriate partner + * + * @adev: amdgpu_device pointer + * @speed: pointer to the speed of the link + * @width: pointer to the width of the link + * + * Evaluate the hierarchy to find the speed and bandwidth capabilities of the + * first physical partner to an AMD dGPU. + * This will exclude any virtual switches and links. + */ +static void amdgpu_device_partner_bandwidth(struct amdgpu_device *adev, + enum pci_bus_speed *speed, + enum pcie_link_width *width) +{ + struct pci_dev *parent = adev->pdev; + + if (!speed || !width) + return; + + *speed = PCI_SPEED_UNKNOWN; + *width = PCIE_LNK_WIDTH_UNKNOWN; + + while ((parent = pci_upstream_bridge(parent))) { + /* skip upstream/downstream switches internal to dGPU*/ + if (parent->vendor == PCI_VENDOR_ID_ATI) + continue; + *speed = pcie_get_speed_cap(parent); + *width = pcie_get_width_cap(parent); + break; + } +} + /** * amdgpu_device_get_pcie_info - fence pcie info about the PCIE slot * @@ -5756,8 +5833,8 @@ static void amdgpu_device_get_pcie_info(struct amdgpu_device *adev) if (adev->pm.pcie_gen_mask && adev->pm.pcie_mlw_mask) return; - pcie_bandwidth_available(adev->pdev, NULL, - &platform_speed_cap, &platform_link_width); + amdgpu_device_partner_bandwidth(adev, &platform_speed_cap, + &platform_link_width); if (adev->pm.pcie_gen_mask == 0) { /* asic caps */ @@ -5984,7 +6061,7 @@ pci_ers_result_t amdgpu_pci_error_detected(struct pci_dev *pdev, pci_channel_sta for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { struct amdgpu_ring *ring = adev->rings[i]; - if (!ring || !ring->sched.thread) + if (!ring || !drm_sched_wqueue_ready(&ring->sched)) continue; drm_sched_stop(&ring->sched, NULL); @@ -6112,7 +6189,7 @@ void amdgpu_pci_resume(struct pci_dev *pdev) for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { struct amdgpu_ring *ring = adev->rings[i]; - if (!ring || !ring->sched.thread) + if (!ring || !drm_sched_wqueue_ready(&ring->sched)) continue; drm_sched_start(&ring->sched, true); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c index 0431eafa86b532..c7d60dd0fb975d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c @@ -1963,8 +1963,6 @@ static int amdgpu_discovery_set_gc_ip_blocks(struct amdgpu_device *adev) amdgpu_device_ip_block_add(adev, &gfx_v9_0_ip_block); break; case IP_VERSION(9, 4, 3): - if (!amdgpu_exp_hw_support) - return -EINVAL; amdgpu_device_ip_block_add(adev, &gfx_v9_4_3_ip_block); break; case IP_VERSION(10, 1, 10): diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c index e7e87a3b2601eb..decbbe3d4f06e9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c @@ -42,6 +42,7 @@ #include #include #include +#include "amdgpu_trace.h" /** * amdgpu_dma_buf_attach - &dma_buf_ops.attach implementation @@ -63,6 +64,7 @@ static int amdgpu_dma_buf_attach(struct dma_buf *dmabuf, attach->peer2peer = false; r = pm_runtime_get_sync(adev_to_drm(adev)->dev); + trace_amdgpu_runpm_reference_dumps(1, __func__); if (r < 0) goto out; @@ -70,6 +72,7 @@ static int amdgpu_dma_buf_attach(struct dma_buf *dmabuf, out: pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + trace_amdgpu_runpm_reference_dumps(0, __func__); return r; } @@ -90,6 +93,7 @@ static void amdgpu_dma_buf_detach(struct dma_buf *dmabuf, pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + trace_amdgpu_runpm_reference_dumps(0, __func__); } /** diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 8b33b130ea36e9..cc69005f5b46e7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -115,9 +115,10 @@ * 3.54.0 - Add AMDGPU_CTX_QUERY2_FLAGS_RESET_IN_PROGRESS support * - 3.55.0 - Add AMDGPU_INFO_GPUVM_FAULT query * - 3.56.0 - Update IB start address and size alignment for decode and encode + * - 3.57.0 - Compute tunneling on GFX10+ */ #define KMS_DRIVER_MAJOR 3 -#define KMS_DRIVER_MINOR 56 +#define KMS_DRIVER_MINOR 57 #define KMS_DRIVER_PATCHLEVEL 0 /* @@ -127,6 +128,7 @@ enum AMDGPU_DEBUG_MASK { AMDGPU_DEBUG_VM = BIT(0), AMDGPU_DEBUG_LARGEBAR = BIT(1), AMDGPU_DEBUG_DISABLE_GPU_SOFT_RECOVERY = BIT(2), + AMDGPU_DEBUG_USE_VRAM_FW_BUF = BIT(3), }; unsigned int amdgpu_vram_limit = UINT_MAX; @@ -208,6 +210,7 @@ int amdgpu_umsch_mm; int amdgpu_seamless = -1; /* auto */ uint amdgpu_debug_mask; int amdgpu_agp = -1; /* auto */ +int amdgpu_wbrf = -1; static void amdgpu_drv_delayed_reset_work_handler(struct work_struct *work); @@ -971,6 +974,22 @@ module_param_named(debug_mask, amdgpu_debug_mask, uint, 0444); MODULE_PARM_DESC(agp, "AGP (-1 = auto (default), 0 = disable, 1 = enable)"); module_param_named(agp, amdgpu_agp, int, 0444); +/** + * DOC: wbrf (int) + * Enable Wifi RFI interference mitigation feature. + * Due to electrical and mechanical constraints there may be likely interference of + * relatively high-powered harmonics of the (G-)DDR memory clocks with local radio + * module frequency bands used by Wifi 6/6e/7. To mitigate the possible RFI interference, + * with this feature enabled, PMFW will use either “shadowed P-State” or “P-State” based + * on active list of frequencies in-use (to be avoided) as part of initial setting or + * P-state transition. However, there may be potential performance impact with this + * feature enabled. + * (0 = disabled, 1 = enabled, -1 = auto (default setting, will be enabled if supported)) + */ +MODULE_PARM_DESC(wbrf, + "Enable Wifi RFI interference mitigation (0 = disabled, 1 = enabled, -1 = auto(default)"); +module_param_named(wbrf, amdgpu_wbrf, int, 0444); + /* These devices are not supported by amdgpu. * They are supported by the mach64, r128, radeon drivers */ @@ -2099,6 +2118,11 @@ static void amdgpu_init_debug_options(struct amdgpu_device *adev) pr_info("debug: soft reset for GPU recovery disabled\n"); adev->debug_disable_soft_recovery = true; } + + if (amdgpu_debug_mask & AMDGPU_DEBUG_USE_VRAM_FW_BUF) { + pr_info("debug: place fw in vram for frontdoor loading\n"); + adev->debug_use_vram_fw_buf = true; + } } static unsigned long amdgpu_fix_asic_type(struct pci_dev *pdev, unsigned long flags) @@ -2210,6 +2234,8 @@ static int amdgpu_pci_probe(struct pci_dev *pdev, pci_set_drvdata(pdev, ddev); + amdgpu_init_debug_options(adev); + ret = amdgpu_driver_load_kms(adev, flags); if (ret) goto err_pci; @@ -2290,8 +2316,6 @@ retry_init: amdgpu_get_secondary_funcs(adev); } - amdgpu_init_debug_options(adev); - return 0; err_pci: @@ -2313,38 +2337,6 @@ amdgpu_pci_remove(struct pci_dev *pdev) pm_runtime_forbid(dev->dev); } - if (amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 2) && - !amdgpu_sriov_vf(adev)) { - bool need_to_reset_gpu = false; - - if (adev->gmc.xgmi.num_physical_nodes > 1) { - struct amdgpu_hive_info *hive; - - hive = amdgpu_get_xgmi_hive(adev); - if (hive->device_remove_count == 0) - need_to_reset_gpu = true; - hive->device_remove_count++; - amdgpu_put_xgmi_hive(hive); - } else { - need_to_reset_gpu = true; - } - - /* Workaround for ASICs need to reset SMU. - * Called only when the first device is removed. - */ - if (need_to_reset_gpu) { - struct amdgpu_reset_context reset_context; - - adev->shutdown = true; - memset(&reset_context, 0, sizeof(reset_context)); - reset_context.method = AMD_RESET_METHOD_NONE; - reset_context.reset_req_dev = adev; - set_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags); - set_bit(AMDGPU_RESET_FOR_DEVICE_REMOVE, &reset_context.flags); - amdgpu_device_gpu_recover(adev, NULL, &reset_context); - } - } - amdgpu_driver_unload_kms(dev); /* diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c index dc230212746a29..70bff8cecfda7e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c @@ -183,6 +183,7 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, struct dma_fence **f, struct amd amdgpu_ring_emit_fence(ring, ring->fence_drv.gpu_addr, seq, flags | AMDGPU_FENCE_FLAG_INT); pm_runtime_get_noresume(adev_to_drm(adev)->dev); + trace_amdgpu_runpm_reference_dumps(1, __func__); ptr = &ring->fence_drv.fences[seq & ring->fence_drv.num_fences_mask]; if (unlikely(rcu_dereference_protected(*ptr, 1))) { struct dma_fence *old; @@ -310,6 +311,7 @@ bool amdgpu_fence_process(struct amdgpu_ring *ring) dma_fence_put(fence); pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + trace_amdgpu_runpm_reference_dumps(0, __func__); } while (last_seq != seq); return true; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c index 73b8cca35bab87..c623e23049d1d4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c @@ -121,6 +121,7 @@ int amdgpu_gart_table_ram_alloc(struct amdgpu_device *adev) struct amdgpu_bo_param bp; dma_addr_t dma_addr; struct page *p; + unsigned long x; int ret; if (adev->gart.bo != NULL) @@ -130,6 +131,10 @@ int amdgpu_gart_table_ram_alloc(struct amdgpu_device *adev) if (!p) return -ENOMEM; + /* assign pages to this device */ + for (x = 0; x < (1UL << order); x++) + p[x].mapping = adev->mman.bdev.dev_mapping; + /* If the hardware does not support UTCL2 snooping of the CPU caches * then set_memory_wc() could be used as a workaround to mark the pages * as write combine memory. @@ -223,6 +228,7 @@ void amdgpu_gart_table_ram_free(struct amdgpu_device *adev) unsigned int order = get_order(adev->gart.table_size); struct sg_table *sg = adev->gart.bo->tbo.sg; struct page *p; + unsigned long x; int ret; ret = amdgpu_bo_reserve(adev->gart.bo, false); @@ -234,6 +240,8 @@ void amdgpu_gart_table_ram_free(struct amdgpu_device *adev) sg_free_table(sg); kfree(sg); p = virt_to_page(adev->gart.ptr); + for (x = 0; x < (1UL << order); x++) + p[x].mapping = NULL; __free_pages(p, order); adev->gart.ptr = NULL; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index 84beeaa4d21ca7..49a5f1c73b3ecc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -203,7 +203,7 @@ static void amdgpu_gem_object_close(struct drm_gem_object *obj, struct drm_exec exec; long r; - drm_exec_init(&exec, DRM_EXEC_IGNORE_DUPLICATES); + drm_exec_init(&exec, DRM_EXEC_IGNORE_DUPLICATES, 0); drm_exec_until_all_locked(&exec) { r = drm_exec_prepare_obj(&exec, &bo->tbo.base, 1); drm_exec_retry_on_contention(&exec); @@ -739,7 +739,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, } drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT | - DRM_EXEC_IGNORE_DUPLICATES); + DRM_EXEC_IGNORE_DUPLICATES, 0); drm_exec_until_all_locked(&exec) { if (gobj) { r = drm_exec_lock_obj(&exec, gobj); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c index d2f273d77e5955..55784a9f26c4c8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c @@ -1045,21 +1045,28 @@ int amdgpu_gmc_vram_checking(struct amdgpu_device *adev) * seconds, so here, we just pick up three parts for emulation. */ ret = memcmp(vram_ptr, cptr, 10); - if (ret) - return ret; + if (ret) { + ret = -EIO; + goto release_buffer; + } ret = memcmp(vram_ptr + (size / 2), cptr, 10); - if (ret) - return ret; + if (ret) { + ret = -EIO; + goto release_buffer; + } ret = memcmp(vram_ptr + size - 10, cptr, 10); - if (ret) - return ret; + if (ret) { + ret = -EIO; + goto release_buffer; + } +release_buffer: amdgpu_bo_free_kernel(&vram_bo, &vram_gpu, &vram_ptr); - return 0; + return ret; } static ssize_t current_memory_partition_show( diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c index 081267161d4018..55b65fc04b651e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c @@ -190,8 +190,8 @@ int amdgpu_hmm_range_get_pages(struct mmu_interval_notifier *notifier, pr_debug("hmm range: start = 0x%lx, end = 0x%lx", hmm_range->start, hmm_range->end); - /* Assuming 128MB takes maximum 1 second to fault page address */ - timeout = max((hmm_range->end - hmm_range->start) >> 27, 1UL); + /* Assuming 64MB takes maximum 1 second to fault page address */ + timeout = max((hmm_range->end - hmm_range->start) >> 26, 1UL); timeout *= HMM_RANGE_DEFAULT_TIMEOUT; timeout = jiffies + msecs_to_jiffies(timeout); @@ -199,6 +199,7 @@ retry: hmm_range->notifier_seq = mmu_interval_read_begin(notifier); r = hmm_range_fault(hmm_range); if (unlikely(r)) { + schedule(); /* * FIXME: This timeout should encompass the retry from * mmu_interval_read_retry() as well. @@ -212,7 +213,6 @@ retry: break; hmm_range->hmm_pfns += MAX_WALK_BYTE >> PAGE_SHIFT; hmm_range->start = hmm_range->end; - schedule(); } while (hmm_range->end < end); hmm_range->start = start; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c index 82608df4339648..d79cb13e1aa835 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_i2c.c @@ -175,7 +175,6 @@ struct amdgpu_i2c_chan *amdgpu_i2c_create(struct drm_device *dev, i2c->rec = *rec; i2c->adapter.owner = THIS_MODULE; - i2c->adapter.class = I2C_CLASS_DDC; i2c->adapter.dev.parent = dev->dev; i2c->dev = dev; i2c_set_adapdata(&i2c->adapter, i2c); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c index 1f357198533f3e..71a5cf37b472d4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c @@ -115,7 +115,7 @@ int amdgpu_job_alloc(struct amdgpu_device *adev, struct amdgpu_vm *vm, if (!entity) return 0; - return drm_sched_job_init(&(*job)->base, entity, owner); + return drm_sched_job_init(&(*job)->base, entity, 1, owner); } int amdgpu_job_alloc_with_ib(struct amdgpu_device *adev, @@ -325,7 +325,7 @@ void amdgpu_job_stop_all_jobs_on_sched(struct drm_gpu_scheduler *sched) int i; /* Signal all jobs not yet scheduled */ - for (i = sched->num_rqs - 1; i >= DRM_SCHED_PRIORITY_MIN; i--) { + for (i = DRM_SCHED_PRIORITY_KERNEL; i < sched->num_rqs; i++) { struct drm_sched_rq *rq = sched->sched_rq[i]; spin_lock(&rq->lock); list_for_each_entry(s_entity, &rq->entities, list) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 583cf03950cd7f..bf4f48fe438d1b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -1105,7 +1105,12 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) if (amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_AVG_POWER, (void *)&ui32, &ui32_size)) { - return -EINVAL; + /* fall back to input power for backwards compat */ + if (amdgpu_dpm_read_sensor(adev, + AMDGPU_PP_SENSOR_GPU_INPUT_POWER, + (void *)&ui32, &ui32_size)) { + return -EINVAL; + } } ui32 >>= 8; break; @@ -1428,6 +1433,8 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev, fpriv->csa_va = NULL; } + amdgpu_seq64_unmap(adev, fpriv); + pasid = fpriv->vm.pasid; pd = amdgpu_bo_ref(fpriv->vm.root.bo); if (!WARN_ON(amdgpu_bo_reserve(pd, true))) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.c index cf33eb219e2574..59fafb8392e0ba 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.c @@ -218,6 +218,7 @@ static void amdgpu_mca_smu_mca_bank_dump(struct amdgpu_device *adev, int idx, st int amdgpu_mca_smu_log_ras_error(struct amdgpu_device *adev, enum amdgpu_ras_block blk, enum amdgpu_mca_error_type type, struct ras_err_data *err_data) { struct amdgpu_smuio_mcm_config_info mcm_info; + struct ras_err_addr err_addr = {0}; struct mca_bank_set mca_set; struct mca_bank_node *node; struct mca_bank_entry *entry; @@ -246,10 +247,18 @@ int amdgpu_mca_smu_log_ras_error(struct amdgpu_device *adev, enum amdgpu_ras_blo mcm_info.socket_id = entry->info.socket_id; mcm_info.die_id = entry->info.aid; + if (blk == AMDGPU_RAS_BLOCK__UMC) { + err_addr.err_status = entry->regs[MCA_REG_IDX_STATUS]; + err_addr.err_ipid = entry->regs[MCA_REG_IDX_IPID]; + err_addr.err_addr = entry->regs[MCA_REG_IDX_ADDR]; + } + if (type == AMDGPU_MCA_ERROR_TYPE_UE) - amdgpu_ras_error_statistic_ue_count(err_data, &mcm_info, (uint64_t)count); + amdgpu_ras_error_statistic_ue_count(err_data, + &mcm_info, &err_addr, (uint64_t)count); else - amdgpu_ras_error_statistic_ce_count(err_data, &mcm_info, (uint64_t)count); + amdgpu_ras_error_statistic_ce_count(err_data, + &mcm_info, &err_addr, (uint64_t)count); } out_mca_release: @@ -351,6 +360,9 @@ int amdgpu_mca_smu_get_mca_entry(struct amdgpu_device *adev, enum amdgpu_mca_err const struct amdgpu_mca_smu_funcs *mca_funcs = adev->mca.mca_funcs; int count; + if (!mca_funcs || !mca_funcs->mca_get_mca_entry) + return -EOPNOTSUPP; + switch (type) { case AMDGPU_MCA_ERROR_TYPE_UE: count = mca_funcs->max_ue_count; @@ -365,10 +377,7 @@ int amdgpu_mca_smu_get_mca_entry(struct amdgpu_device *adev, enum amdgpu_mca_err if (idx >= count) return -EINVAL; - if (mca_funcs && mca_funcs->mca_get_mca_entry) - return mca_funcs->mca_get_mca_entry(adev, type, idx, entry); - - return -EOPNOTSUPP; + return mca_funcs->mca_get_mca_entry(adev, type, idx, entry); } #if defined(CONFIG_DEBUG_FS) @@ -377,7 +386,7 @@ static int amdgpu_mca_smu_debug_mode_set(void *data, u64 val) struct amdgpu_device *adev = (struct amdgpu_device *)data; int ret; - ret = amdgpu_mca_smu_set_debug_mode(adev, val ? true : false); + ret = amdgpu_ras_set_mca_debug_mode(adev, val ? true : false); if (ret) return ret; @@ -485,7 +494,7 @@ DEFINE_DEBUGFS_ATTRIBUTE(mca_debug_mode_fops, NULL, amdgpu_mca_smu_debug_mode_se void amdgpu_mca_smu_debugfs_init(struct amdgpu_device *adev, struct dentry *root) { #if defined(CONFIG_DEBUG_FS) - if (!root || adev->ip_versions[MP1_HWIP][0] != IP_VERSION(13, 0, 6)) + if (!root || amdgpu_ip_version(adev, MP1_HWIP, 0) != IP_VERSION(13, 0, 6)) return; debugfs_create_file("mca_debug_mode", 0200, root, adev, &mca_debug_mode_fops); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.h index e51e8918e6671a..b399f1b62887a9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.h @@ -46,6 +46,8 @@ #define MCA_REG__STATUS__ERRORCODEEXT(x) MCA_REG_FIELD(x, 21, 16) #define MCA_REG__STATUS__ERRORCODE(x) MCA_REG_FIELD(x, 15, 0) +#define MCA_REG__MISC0__ERRCNT(x) MCA_REG_FIELD(x, 43, 32) + #define MCA_REG__SYND__ERRORINFORMATION(x) MCA_REG_FIELD(x, 17, 0) enum amdgpu_mca_ip { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index 9ddbf1494326a0..da48b6da010725 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -98,6 +98,26 @@ static int amdgpu_mes_doorbell_init(struct amdgpu_device *adev) return 0; } +static int amdgpu_mes_event_log_init(struct amdgpu_device *adev) +{ + int r; + + r = amdgpu_bo_create_kernel(adev, PAGE_SIZE, PAGE_SIZE, + AMDGPU_GEM_DOMAIN_GTT, + &adev->mes.event_log_gpu_obj, + &adev->mes.event_log_gpu_addr, + &adev->mes.event_log_cpu_addr); + if (r) { + dev_warn(adev->dev, "failed to create MES event log buffer (%d)", r); + return r; + } + + memset(adev->mes.event_log_cpu_addr, 0, PAGE_SIZE); + + return 0; + +} + static void amdgpu_mes_doorbell_free(struct amdgpu_device *adev) { bitmap_free(adev->mes.doorbell_bitmap); @@ -182,8 +202,14 @@ int amdgpu_mes_init(struct amdgpu_device *adev) if (r) goto error; + r = amdgpu_mes_event_log_init(adev); + if (r) + goto error_doorbell; + return 0; +error_doorbell: + amdgpu_mes_doorbell_free(adev); error: amdgpu_device_wb_free(adev, adev->mes.sch_ctx_offs); amdgpu_device_wb_free(adev, adev->mes.query_status_fence_offs); @@ -199,6 +225,10 @@ error_ids: void amdgpu_mes_fini(struct amdgpu_device *adev) { + amdgpu_bo_free_kernel(&adev->mes.event_log_gpu_obj, + &adev->mes.event_log_gpu_addr, + &adev->mes.event_log_cpu_addr); + amdgpu_device_wb_free(adev, adev->mes.sch_ctx_offs); amdgpu_device_wb_free(adev, adev->mes.query_status_fence_offs); amdgpu_device_wb_free(adev, adev->mes.read_val_offs); @@ -886,6 +916,11 @@ int amdgpu_mes_set_shader_debugger(struct amdgpu_device *adev, op_input.op = MES_MISC_OP_SET_SHADER_DEBUGGER; op_input.set_shader_debugger.process_context_addr = process_context_addr; op_input.set_shader_debugger.flags.u32all = flags; + + /* use amdgpu mes_flush_shader_debugger instead */ + if (op_input.set_shader_debugger.flags.process_ctx_flush) + return -EINVAL; + op_input.set_shader_debugger.spi_gdbg_per_vmid_cntl = spi_gdbg_per_vmid_cntl; memcpy(op_input.set_shader_debugger.tcp_watch_cntl, tcp_watch_cntl, sizeof(op_input.set_shader_debugger.tcp_watch_cntl)); @@ -905,6 +940,32 @@ int amdgpu_mes_set_shader_debugger(struct amdgpu_device *adev, return r; } +int amdgpu_mes_flush_shader_debugger(struct amdgpu_device *adev, + uint64_t process_context_addr) +{ + struct mes_misc_op_input op_input = {0}; + int r; + + if (!adev->mes.funcs->misc_op) { + DRM_ERROR("mes flush shader debugger is not supported!\n"); + return -EINVAL; + } + + op_input.op = MES_MISC_OP_SET_SHADER_DEBUGGER; + op_input.set_shader_debugger.process_context_addr = process_context_addr; + op_input.set_shader_debugger.flags.process_ctx_flush = true; + + amdgpu_mes_lock(&adev->mes); + + r = adev->mes.funcs->misc_op(&adev->mes, &op_input); + if (r) + DRM_ERROR("failed to set_shader_debugger\n"); + + amdgpu_mes_unlock(&adev->mes); + + return r; +} + static void amdgpu_mes_ring_to_queue_props(struct amdgpu_device *adev, struct amdgpu_ring *ring, @@ -1122,7 +1183,7 @@ int amdgpu_mes_ctx_map_meta_data(struct amdgpu_device *adev, amdgpu_sync_create(&sync); - drm_exec_init(&exec, 0); + drm_exec_init(&exec, 0, 0); drm_exec_until_all_locked(&exec) { r = drm_exec_lock_obj(&exec, &ctx_data->meta_data_obj->tbo.base); @@ -1193,7 +1254,7 @@ int amdgpu_mes_ctx_unmap_meta_data(struct amdgpu_device *adev, struct drm_exec exec; long r; - drm_exec_init(&exec, 0); + drm_exec_init(&exec, 0, 0); drm_exec_until_all_locked(&exec) { r = drm_exec_lock_obj(&exec, &ctx_data->meta_data_obj->tbo.base); @@ -1479,3 +1540,34 @@ out: amdgpu_ucode_release(&adev->mes.fw[pipe]); return r; } + +#if defined(CONFIG_DEBUG_FS) + +static int amdgpu_debugfs_mes_event_log_show(struct seq_file *m, void *unused) +{ + struct amdgpu_device *adev = m->private; + uint32_t *mem = (uint32_t *)(adev->mes.event_log_cpu_addr); + + seq_hex_dump(m, "", DUMP_PREFIX_OFFSET, 32, 4, + mem, PAGE_SIZE, false); + + return 0; +} + + +DEFINE_SHOW_ATTRIBUTE(amdgpu_debugfs_mes_event_log); + +#endif + +void amdgpu_debugfs_mes_event_log_init(struct amdgpu_device *adev) +{ + +#if defined(CONFIG_DEBUG_FS) + struct drm_minor *minor = adev_to_drm(adev)->primary; + struct dentry *root = minor->debugfs_root; + + debugfs_create_file("amdgpu_mes_event_log", 0444, root, + adev, &amdgpu_debugfs_mes_event_log_fops); + +#endif +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h index a27b424ffe0056..7d4f93fea937ae 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h @@ -133,6 +133,11 @@ struct amdgpu_mes { uint32_t num_mes_dbs; unsigned long *doorbell_bitmap; + /* MES event log buffer */ + struct amdgpu_bo *event_log_gpu_obj; + uint64_t event_log_gpu_addr; + void *event_log_cpu_addr; + /* ip specific functions */ const struct amdgpu_mes_funcs *funcs; }; @@ -291,9 +296,10 @@ struct mes_misc_op_input { uint64_t process_context_addr; union { struct { - uint64_t single_memop : 1; - uint64_t single_alu_op : 1; - uint64_t reserved: 30; + uint32_t single_memop : 1; + uint32_t single_alu_op : 1; + uint32_t reserved: 29; + uint32_t process_ctx_flush: 1; }; uint32_t u32all; } flags; @@ -369,7 +375,8 @@ int amdgpu_mes_set_shader_debugger(struct amdgpu_device *adev, const uint32_t *tcp_watch_cntl, uint32_t flags, bool trap_en); - +int amdgpu_mes_flush_shader_debugger(struct amdgpu_device *adev, + uint64_t process_context_addr); int amdgpu_mes_add_ring(struct amdgpu_device *adev, int gang_id, int queue_type, int idx, struct amdgpu_mes_ctx_data *ctx_data, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h index 32fe05c810c6fc..2e4911050cc5ec 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h @@ -32,7 +32,6 @@ #include #include -#include #include #include #include @@ -51,6 +50,7 @@ struct amdgpu_device; struct amdgpu_encoder; struct amdgpu_router; struct amdgpu_hpd; +struct edid; #define to_amdgpu_crtc(x) container_of(x, struct amdgpu_crtc, base) #define to_amdgpu_connector(x) container_of(x, struct amdgpu_connector, base) @@ -343,6 +343,97 @@ struct amdgpu_mode_info { int disp_priority; const struct amdgpu_display_funcs *funcs; const enum drm_plane_type *plane_type; + + /* Driver-private color mgmt props */ + + /* @plane_degamma_lut_property: Plane property to set a degamma LUT to + * convert encoded values to light linear values before sampling or + * blending. + */ + struct drm_property *plane_degamma_lut_property; + /* @plane_degamma_lut_size_property: Plane property to define the max + * size of degamma LUT as supported by the driver (read-only). + */ + struct drm_property *plane_degamma_lut_size_property; + /** + * @plane_degamma_tf_property: Plane pre-defined transfer function to + * to go from scanout/encoded values to linear values. + */ + struct drm_property *plane_degamma_tf_property; + /** + * @plane_hdr_mult_property: + */ + struct drm_property *plane_hdr_mult_property; + + struct drm_property *plane_ctm_property; + /** + * @shaper_lut_property: Plane property to set pre-blending shaper LUT + * that converts color content before 3D LUT. If + * plane_shaper_tf_property != Identity TF, AMD color module will + * combine the user LUT values with pre-defined TF into the LUT + * parameters to be programmed. + */ + struct drm_property *plane_shaper_lut_property; + /** + * @shaper_lut_size_property: Plane property for the size of + * pre-blending shaper LUT as supported by the driver (read-only). + */ + struct drm_property *plane_shaper_lut_size_property; + /** + * @plane_shaper_tf_property: Plane property to set a predefined + * transfer function for pre-blending shaper (before applying 3D LUT) + * with or without LUT. There is no shaper ROM, but we can use AMD + * color modules to program LUT parameters from predefined TF (or + * from a combination of pre-defined TF and the custom 1D LUT). + */ + struct drm_property *plane_shaper_tf_property; + /** + * @plane_lut3d_property: Plane property for color transformation using + * a 3D LUT (pre-blending), a three-dimensional array where each + * element is an RGB triplet. Each dimension has the size of + * lut3d_size. The array contains samples from the approximated + * function. On AMD, values between samples are estimated by + * tetrahedral interpolation. The array is accessed with three indices, + * one for each input dimension (color channel), blue being the + * outermost dimension, red the innermost. + */ + struct drm_property *plane_lut3d_property; + /** + * @plane_degamma_lut_size_property: Plane property to define the max + * size of 3D LUT as supported by the driver (read-only). The max size + * is the max size of one dimension and, therefore, the max number of + * entries for 3D LUT array is the 3D LUT size cubed; + */ + struct drm_property *plane_lut3d_size_property; + /** + * @plane_blend_lut_property: Plane property for output gamma before + * blending. Userspace set a blend LUT to convert colors after 3D LUT + * conversion. It works as a post-3DLUT 1D LUT. With shaper LUT, they + * are sandwiching 3D LUT with two 1D LUT. If plane_blend_tf_property + * != Identity TF, AMD color module will combine the user LUT values + * with pre-defined TF into the LUT parameters to be programmed. + */ + struct drm_property *plane_blend_lut_property; + /** + * @plane_blend_lut_size_property: Plane property to define the max + * size of blend LUT as supported by the driver (read-only). + */ + struct drm_property *plane_blend_lut_size_property; + /** + * @plane_blend_tf_property: Plane property to set a predefined + * transfer function for pre-blending blend/out_gamma (after applying + * 3D LUT) with or without LUT. There is no blend ROM, but we can use + * AMD color modules to program LUT parameters from predefined TF (or + * from a combination of pre-defined TF and the custom 1D LUT). + */ + struct drm_property *plane_blend_tf_property; + /* @regamma_tf_property: Transfer function for CRTC regamma + * (post-blending). Possible values are defined by `enum + * amdgpu_transfer_function`. There is no regamma ROM, but we can use + * AMD color modules to program LUT parameters from predefined TF (or + * from a combination of pre-defined TF and the custom 1D LUT). + */ + struct drm_property *regamma_tf_property; }; #define AMDGPU_MAX_BL_LEVEL 0xFF @@ -416,6 +507,10 @@ struct amdgpu_crtc { int otg_inst; struct drm_pending_vblank_event *event; + + bool wb_pending; + bool wb_enabled; + struct drm_writeback_connector *wb_conn; }; struct amdgpu_encoder_atom_dig { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 5ad03f2afdb45a..425cebcc5cbff7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -1245,19 +1245,15 @@ int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer, * amdgpu_bo_move_notify - notification about a memory move * @bo: pointer to a buffer object * @evict: if this move is evicting the buffer from the graphics address space - * @new_mem: new information of the bufer object * * Marks the corresponding &amdgpu_bo buffer object as invalid, also performs * bookkeeping. * TTM driver callback which is called when ttm moves a buffer. */ -void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, - bool evict, - struct ttm_resource *new_mem) +void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, bool evict) { struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev); struct amdgpu_bo *abo; - struct ttm_resource *old_mem = bo->resource; if (!amdgpu_bo_is_amdgpu_bo(bo)) return; @@ -1274,13 +1270,6 @@ void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, /* remember the eviction */ if (evict) atomic64_inc(&adev->num_evictions); - - /* update statistics */ - if (!new_mem) - return; - - /* move_notify is called before move happens */ - trace_amdgpu_bo_move(abo, new_mem->mem_type, old_mem->mem_type); } void amdgpu_bo_get_memory(struct amdgpu_bo *bo, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h index d28e21baef16ee..a3ea8a82db23ad 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h @@ -344,9 +344,7 @@ int amdgpu_bo_set_metadata (struct amdgpu_bo *bo, void *metadata, int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer, size_t buffer_size, uint32_t *metadata_size, uint64_t *flags); -void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, - bool evict, - struct ttm_resource *new_mem); +void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, bool evict); void amdgpu_bo_release_notify(struct ttm_buffer_object *bo); vm_fault_t amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo); void amdgpu_bo_fence(struct amdgpu_bo *bo, struct dma_fence *fence, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c index a21045d018f2b6..0328616473f80a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c @@ -466,7 +466,7 @@ static int psp_sw_init(void *handle) } ret = amdgpu_bo_create_kernel(adev, PSP_1_MEG, PSP_1_MEG, - amdgpu_sriov_vf(adev) ? + (amdgpu_sriov_vf(adev) || adev->debug_use_vram_fw_buf) ? AMDGPU_GEM_DOMAIN_VRAM : AMDGPU_GEM_DOMAIN_GTT, &psp->fw_pri_bo, &psp->fw_pri_mc_addr, @@ -1433,8 +1433,8 @@ int psp_xgmi_get_topology_info(struct psp_context *psp, get_extended_data) || amdgpu_ip_version(psp->adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 6); - bool ta_port_num_support = psp->xgmi_context.xgmi_ta_caps & - EXTEND_PEER_LINK_INFO_CMD_FLAG; + bool ta_port_num_support = amdgpu_sriov_vf(psp->adev) ? 0 : + psp->xgmi_context.xgmi_ta_caps & EXTEND_PEER_LINK_INFO_CMD_FLAG; /* popluate the shared output buffer rather than the cmd input buffer * with node_ids as the input for GET_PEER_LINKS command execution. diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index 63fb4cd85e53b7..31823a30dea217 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -305,11 +305,13 @@ static int amdgpu_ras_debugfs_ctrl_parse_data(struct file *f, return -EINVAL; data->head.block = block_id; - /* only ue and ce errors are supported */ + /* only ue, ce and poison errors are supported */ if (!memcmp("ue", err, 2)) data->head.type = AMDGPU_RAS_ERROR__MULTI_UNCORRECTABLE; else if (!memcmp("ce", err, 2)) data->head.type = AMDGPU_RAS_ERROR__SINGLE_CORRECTABLE; + else if (!memcmp("poison", err, 6)) + data->head.type = AMDGPU_RAS_ERROR__POISON; else return -EINVAL; @@ -431,9 +433,10 @@ static void amdgpu_ras_instance_mask_check(struct amdgpu_device *adev, * The block is one of: umc, sdma, gfx, etc. * see ras_block_string[] for details * - * The error type is one of: ue, ce, where, + * The error type is one of: ue, ce and poison where, * ue is multi-uncorrectable * ce is single-correctable + * poison is poison * * The sub-block is a the sub-block index, pass 0 if there is no sub-block. * The address and value are hexadecimal numbers, leading 0x is optional. @@ -1067,8 +1070,7 @@ static void amdgpu_ras_error_print_error_data(struct amdgpu_device *adev, mcm_info = &err_info->mcm_info; if (err_info->ce_count) { dev_info(adev->dev, "socket: %d, die: %d, " - "%lld new correctable hardware errors detected in %s block, " - "no user action is needed\n", + "%lld new correctable hardware errors detected in %s block\n", mcm_info->socket_id, mcm_info->die_id, err_info->ce_count, @@ -1080,8 +1082,7 @@ static void amdgpu_ras_error_print_error_data(struct amdgpu_device *adev, err_info = &err_node->err_info; mcm_info = &err_info->mcm_info; dev_info(adev->dev, "socket: %d, die: %d, " - "%lld correctable hardware errors detected in total in %s block, " - "no user action is needed\n", + "%lld correctable hardware errors detected in total in %s block\n", mcm_info->socket_id, mcm_info->die_id, err_info->ce_count, blk_name); } } @@ -1108,16 +1109,14 @@ static void amdgpu_ras_error_generate_report(struct amdgpu_device *adev, adev->smuio.funcs->get_die_id) { dev_info(adev->dev, "socket: %d, die: %d " "%ld correctable hardware errors " - "detected in %s block, no user " - "action is needed.\n", + "detected in %s block\n", adev->smuio.funcs->get_socket_id(adev), adev->smuio.funcs->get_die_id(adev), ras_mgr->err_data.ce_count, blk_name); } else { dev_info(adev->dev, "%ld correctable hardware errors " - "detected in %s block, no user " - "action is needed.\n", + "detected in %s block\n", ras_mgr->err_data.ce_count, blk_name); } @@ -1156,8 +1155,10 @@ static void amdgpu_rasmgr_error_data_statistic_update(struct ras_manager *obj, s for_each_ras_error(err_node, err_data) { err_info = &err_node->err_info; - amdgpu_ras_error_statistic_ce_count(&obj->err_data, &err_info->mcm_info, err_info->ce_count); - amdgpu_ras_error_statistic_ue_count(&obj->err_data, &err_info->mcm_info, err_info->ue_count); + amdgpu_ras_error_statistic_ce_count(&obj->err_data, + &err_info->mcm_info, NULL, err_info->ce_count); + amdgpu_ras_error_statistic_ue_count(&obj->err_data, + &err_info->mcm_info, NULL, err_info->ue_count); } } else { /* for legacy asic path which doesn't has error source info */ @@ -1174,6 +1175,9 @@ static int amdgpu_ras_query_error_status_helper(struct amdgpu_device *adev, enum amdgpu_ras_block blk = info ? info->head.block : AMDGPU_RAS_BLOCK_COUNT; struct amdgpu_ras_block_object *block_obj = NULL; + if (blk == AMDGPU_RAS_BLOCK_COUNT) + return -EINVAL; + if (error_query_mode == AMDGPU_RAS_INVALID_ERROR_QUERY) return -EINVAL; @@ -1915,7 +1919,7 @@ static void amdgpu_ras_interrupt_poison_creation_handler(struct ras_manager *obj struct amdgpu_iv_entry *entry) { dev_info(obj->adev->dev, - "Poison is created, no user action is needed.\n"); + "Poison is created\n"); } static void amdgpu_ras_interrupt_umc_handler(struct ras_manager *obj, @@ -2538,7 +2542,7 @@ int amdgpu_ras_recovery_init(struct amdgpu_device *adev) return 0; data = &con->eh_data; - *data = kmalloc(sizeof(**data), GFP_KERNEL | __GFP_ZERO); + *data = kzalloc(sizeof(**data), GFP_KERNEL); if (!*data) { ret = -ENOMEM; goto out; @@ -2825,10 +2829,10 @@ int amdgpu_ras_init(struct amdgpu_device *adev) if (con) return 0; - con = kmalloc(sizeof(struct amdgpu_ras) + + con = kzalloc(sizeof(*con) + sizeof(struct ras_manager) * AMDGPU_RAS_BLOCK_COUNT + sizeof(struct ras_manager) * AMDGPU_RAS_MCA_BLOCK_COUNT, - GFP_KERNEL|__GFP_ZERO); + GFP_KERNEL); if (!con) return -ENOMEM; @@ -2915,6 +2919,11 @@ int amdgpu_ras_init(struct amdgpu_device *adev) amdgpu_ras_query_poison_mode(adev); + /* Packed socket_id to ras feature mask bits[31:29] */ + if (adev->smuio.funcs && + adev->smuio.funcs->get_socket_id) + con->features |= ((adev->smuio.funcs->get_socket_id(adev)) << 29); + /* Get RAS schema for particular SOC */ con->schema = amdgpu_get_ras_schema(adev); @@ -3133,6 +3142,8 @@ int amdgpu_ras_late_init(struct amdgpu_device *adev) if (amdgpu_sriov_vf(adev)) return 0; + amdgpu_ras_set_mca_debug_mode(adev, false); + 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"); @@ -3406,12 +3417,18 @@ int amdgpu_ras_reset_gpu(struct amdgpu_device *adev) return 0; } -void amdgpu_ras_set_mca_debug_mode(struct amdgpu_device *adev, bool enable) +int amdgpu_ras_set_mca_debug_mode(struct amdgpu_device *adev, bool enable) { struct amdgpu_ras *con = amdgpu_ras_get_context(adev); + int ret = 0; - if (con) - con->is_mca_debug_mode = enable; + if (con) { + ret = amdgpu_mca_smu_set_debug_mode(adev, enable); + if (!ret) + con->is_mca_debug_mode = enable; + } + + return ret; } bool amdgpu_ras_get_mca_debug_mode(struct amdgpu_device *adev) @@ -3682,7 +3699,8 @@ static int ras_err_info_cmp(void *priv, const struct list_head *a, const struct } static struct ras_err_info *amdgpu_ras_error_get_info(struct ras_err_data *err_data, - struct amdgpu_smuio_mcm_config_info *mcm_info) + struct amdgpu_smuio_mcm_config_info *mcm_info, + struct ras_err_addr *err_addr) { struct ras_err_node *err_node; @@ -3696,6 +3714,9 @@ static struct ras_err_info *amdgpu_ras_error_get_info(struct ras_err_data *err_d memcpy(&err_node->err_info.mcm_info, mcm_info, sizeof(*mcm_info)); + if (err_addr) + memcpy(&err_node->err_info.err_addr, err_addr, sizeof(*err_addr)); + err_data->err_list_count++; list_add_tail(&err_node->node, &err_data->err_node_list); list_sort(NULL, &err_data->err_node_list, ras_err_info_cmp); @@ -3704,7 +3725,8 @@ static struct ras_err_info *amdgpu_ras_error_get_info(struct ras_err_data *err_d } int amdgpu_ras_error_statistic_ue_count(struct ras_err_data *err_data, - struct amdgpu_smuio_mcm_config_info *mcm_info, u64 count) + struct amdgpu_smuio_mcm_config_info *mcm_info, + struct ras_err_addr *err_addr, u64 count) { struct ras_err_info *err_info; @@ -3714,7 +3736,7 @@ int amdgpu_ras_error_statistic_ue_count(struct ras_err_data *err_data, if (!count) return 0; - err_info = amdgpu_ras_error_get_info(err_data, mcm_info); + err_info = amdgpu_ras_error_get_info(err_data, mcm_info, err_addr); if (!err_info) return -EINVAL; @@ -3725,7 +3747,8 @@ int amdgpu_ras_error_statistic_ue_count(struct ras_err_data *err_data, } int amdgpu_ras_error_statistic_ce_count(struct ras_err_data *err_data, - struct amdgpu_smuio_mcm_config_info *mcm_info, u64 count) + struct amdgpu_smuio_mcm_config_info *mcm_info, + struct ras_err_addr *err_addr, u64 count) { struct ras_err_info *err_info; @@ -3735,7 +3758,7 @@ int amdgpu_ras_error_statistic_ce_count(struct ras_err_data *err_data, if (!count) return 0; - err_info = amdgpu_ras_error_get_info(err_data, mcm_info); + err_info = amdgpu_ras_error_get_info(err_data, mcm_info, err_addr); if (!err_info) return -EINVAL; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h index 19161916ac46b9..76fb85628716f6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h @@ -452,10 +452,17 @@ struct ras_fs_data { char debugfs_name[32]; }; +struct ras_err_addr { + uint64_t err_status; + uint64_t err_ipid; + uint64_t err_addr; +}; + struct ras_err_info { struct amdgpu_smuio_mcm_config_info mcm_info; u64 ce_count; u64 ue_count; + struct ras_err_addr err_addr; }; struct ras_err_node { @@ -773,7 +780,7 @@ struct amdgpu_ras* amdgpu_ras_get_context(struct amdgpu_device *adev); int amdgpu_ras_set_context(struct amdgpu_device *adev, struct amdgpu_ras *ras_con); -void amdgpu_ras_set_mca_debug_mode(struct amdgpu_device *adev, bool enable); +int amdgpu_ras_set_mca_debug_mode(struct amdgpu_device *adev, bool enable); bool amdgpu_ras_get_mca_debug_mode(struct amdgpu_device *adev); bool amdgpu_ras_get_error_query_mode(struct amdgpu_device *adev, unsigned int *mode); @@ -806,8 +813,10 @@ void amdgpu_ras_inst_reset_ras_error_count(struct amdgpu_device *adev, int amdgpu_ras_error_data_init(struct ras_err_data *err_data); void amdgpu_ras_error_data_fini(struct ras_err_data *err_data); int amdgpu_ras_error_statistic_ce_count(struct ras_err_data *err_data, - struct amdgpu_smuio_mcm_config_info *mcm_info, u64 count); + struct amdgpu_smuio_mcm_config_info *mcm_info, + struct ras_err_addr *err_addr, u64 count); int amdgpu_ras_error_statistic_ue_count(struct ras_err_data *err_data, - struct amdgpu_smuio_mcm_config_info *mcm_info, u64 count); + struct amdgpu_smuio_mcm_config_info *mcm_info, + struct ras_err_addr *err_addr, u64 count); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h index b0335a1c5e90cb..19899f6b9b2b41 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_reset.h @@ -32,7 +32,6 @@ enum AMDGPU_RESET_FLAGS { AMDGPU_NEED_FULL_RESET = 0, AMDGPU_SKIP_HW_RESET = 1, - AMDGPU_RESET_FOR_DEVICE_REMOVE = 2, }; struct amdgpu_reset_context { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c index 6a80d3ec887e98..45424ebf968143 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c @@ -642,6 +642,10 @@ static void amdgpu_ring_to_mqd_prop(struct amdgpu_ring *ring, struct amdgpu_mqd_prop *prop) { struct amdgpu_device *adev = ring->adev; + bool is_high_prio_compute = ring->funcs->type == AMDGPU_RING_TYPE_COMPUTE && + amdgpu_gfx_is_high_priority_compute_queue(adev, ring); + bool is_high_prio_gfx = ring->funcs->type == AMDGPU_RING_TYPE_GFX && + amdgpu_gfx_is_high_priority_graphics_queue(adev, ring); memset(prop, 0, sizeof(*prop)); @@ -659,10 +663,8 @@ static void amdgpu_ring_to_mqd_prop(struct amdgpu_ring *ring, */ prop->hqd_active = ring->funcs->type == AMDGPU_RING_TYPE_KIQ; - if ((ring->funcs->type == AMDGPU_RING_TYPE_COMPUTE && - amdgpu_gfx_is_high_priority_compute_queue(adev, ring)) || - (ring->funcs->type == AMDGPU_RING_TYPE_GFX && - amdgpu_gfx_is_high_priority_graphics_queue(adev, ring))) { + prop->allow_tunneling = is_high_prio_compute; + if (is_high_prio_compute || is_high_prio_gfx) { prop->hqd_pipe_priority = AMDGPU_GFX_PIPE_PRIO_HIGH; prop->hqd_queue_priority = AMDGPU_GFX_QUEUE_PRIORITY_MAXIMUM; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c index 35e0ae9acadcd6..2c3675d91614f1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c @@ -531,13 +531,12 @@ int amdgpu_gfx_rlc_init_microcode(struct amdgpu_device *adev, if (version_major == 2 && version_minor == 1) adev->gfx.rlc.is_rlc_v2_1 = true; - if (version_minor >= 0) { - err = amdgpu_gfx_rlc_init_microcode_v2_0(adev); - if (err) { - dev_err(adev->dev, "fail to init rlc v2_0 microcode\n"); - return err; - } + err = amdgpu_gfx_rlc_init_microcode_v2_0(adev); + if (err) { + dev_err(adev->dev, "fail to init rlc v2_0 microcode\n"); + return err; } + if (version_minor >= 1) amdgpu_gfx_rlc_init_microcode_v2_1(adev); if (version_minor >= 2) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.c new file mode 100644 index 00000000000000..7a6a67275404c8 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.c @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: MIT +/* + * 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 "amdgpu_seq64.h" + +#include + +/** + * DOC: amdgpu_seq64 + * + * amdgpu_seq64 allocates a 64bit memory on each request in sequence order. + * seq64 driver is required for user queue fence memory allocation, TLB + * counters and VM updates. It has maximum count of 32768 64 bit slots. + */ + +/** + * amdgpu_seq64_map - Map the seq64 memory to VM + * + * @adev: amdgpu_device pointer + * @vm: vm pointer + * @bo_va: bo_va pointer + * @seq64_addr: seq64 vaddr start address + * @size: seq64 pool size + * + * Map the seq64 memory to the given VM. + * + * Returns: + * 0 on success or a negative error code on failure + */ +int amdgpu_seq64_map(struct amdgpu_device *adev, struct amdgpu_vm *vm, + struct amdgpu_bo_va **bo_va, u64 seq64_addr, + uint32_t size) +{ + struct amdgpu_bo *bo; + struct drm_exec exec; + int r; + + bo = adev->seq64.sbo; + if (!bo) + return -EINVAL; + + drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0); + drm_exec_until_all_locked(&exec) { + r = amdgpu_vm_lock_pd(vm, &exec, 0); + if (likely(!r)) + r = drm_exec_lock_obj(&exec, &bo->tbo.base); + drm_exec_retry_on_contention(&exec); + if (unlikely(r)) + goto error; + } + + *bo_va = amdgpu_vm_bo_add(adev, vm, bo); + if (!*bo_va) { + r = -ENOMEM; + goto error; + } + + r = amdgpu_vm_bo_map(adev, *bo_va, seq64_addr, 0, size, + AMDGPU_PTE_READABLE | AMDGPU_PTE_WRITEABLE | + AMDGPU_PTE_EXECUTABLE); + if (r) { + DRM_ERROR("failed to do bo_map on userq sem, err=%d\n", r); + amdgpu_vm_bo_del(adev, *bo_va); + goto error; + } + + r = amdgpu_vm_bo_update(adev, *bo_va, false); + if (r) { + DRM_ERROR("failed to do vm_bo_update on userq sem\n"); + amdgpu_vm_bo_del(adev, *bo_va); + goto error; + } + +error: + drm_exec_fini(&exec); + return r; +} + +/** + * amdgpu_seq64_unmap - Unmap the seq64 memory + * + * @adev: amdgpu_device pointer + * @fpriv: DRM file private + * + * Unmap the seq64 memory from the given VM. + */ +void amdgpu_seq64_unmap(struct amdgpu_device *adev, struct amdgpu_fpriv *fpriv) +{ + struct amdgpu_vm *vm; + struct amdgpu_bo *bo; + struct drm_exec exec; + int r; + + if (!fpriv->seq64_va) + return; + + bo = adev->seq64.sbo; + if (!bo) + return; + + vm = &fpriv->vm; + + drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0); + drm_exec_until_all_locked(&exec) { + r = amdgpu_vm_lock_pd(vm, &exec, 0); + if (likely(!r)) + r = drm_exec_lock_obj(&exec, &bo->tbo.base); + drm_exec_retry_on_contention(&exec); + if (unlikely(r)) + goto error; + } + + amdgpu_vm_bo_del(adev, fpriv->seq64_va); + + fpriv->seq64_va = NULL; + +error: + drm_exec_fini(&exec); +} + +/** + * amdgpu_seq64_alloc - Allocate a 64 bit memory + * + * @adev: amdgpu_device pointer + * @gpu_addr: allocated gpu VA start address + * @cpu_addr: allocated cpu VA start address + * + * Alloc a 64 bit memory from seq64 pool. + * + * Returns: + * 0 on success or a negative error code on failure + */ +int amdgpu_seq64_alloc(struct amdgpu_device *adev, u64 *gpu_addr, + u64 **cpu_addr) +{ + unsigned long bit_pos; + u32 offset; + + bit_pos = find_first_zero_bit(adev->seq64.used, adev->seq64.num_sem); + + if (bit_pos < adev->seq64.num_sem) { + __set_bit(bit_pos, adev->seq64.used); + offset = bit_pos << 6; /* convert to qw offset */ + } else { + return -EINVAL; + } + + *gpu_addr = offset + AMDGPU_SEQ64_VADDR_START; + *cpu_addr = offset + adev->seq64.cpu_base_addr; + + return 0; +} + +/** + * amdgpu_seq64_free - Free the given 64 bit memory + * + * @adev: amdgpu_device pointer + * @gpu_addr: gpu start address to be freed + * + * Free the given 64 bit memory from seq64 pool. + * + */ +void amdgpu_seq64_free(struct amdgpu_device *adev, u64 gpu_addr) +{ + u32 offset; + + offset = gpu_addr - AMDGPU_SEQ64_VADDR_START; + + offset >>= 6; + if (offset < adev->seq64.num_sem) + __clear_bit(offset, adev->seq64.used); +} + +/** + * amdgpu_seq64_fini - Cleanup seq64 driver + * + * @adev: amdgpu_device pointer + * + * Free the memory space allocated for seq64. + * + */ +void amdgpu_seq64_fini(struct amdgpu_device *adev) +{ + amdgpu_bo_free_kernel(&adev->seq64.sbo, + NULL, + (void **)&adev->seq64.cpu_base_addr); +} + +/** + * amdgpu_seq64_init - Initialize seq64 driver + * + * @adev: amdgpu_device pointer + * + * Allocate the required memory space for seq64. + * + * Returns: + * 0 on success or a negative error code on failure + */ +int amdgpu_seq64_init(struct amdgpu_device *adev) +{ + int r; + + if (adev->seq64.sbo) + return 0; + + /* + * AMDGPU_MAX_SEQ64_SLOTS * sizeof(u64) * 8 = AMDGPU_MAX_SEQ64_SLOTS + * 64bit slots + */ + r = amdgpu_bo_create_kernel(adev, AMDGPU_SEQ64_SIZE, + PAGE_SIZE, AMDGPU_GEM_DOMAIN_GTT, + &adev->seq64.sbo, NULL, + (void **)&adev->seq64.cpu_base_addr); + if (r) { + dev_warn(adev->dev, "(%d) create seq64 failed\n", r); + return r; + } + + memset(adev->seq64.cpu_base_addr, 0, AMDGPU_SEQ64_SIZE); + + adev->seq64.num_sem = AMDGPU_MAX_SEQ64_SLOTS; + memset(&adev->seq64.used, 0, sizeof(adev->seq64.used)); + + return 0; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.h new file mode 100644 index 00000000000000..2196e72be508ee --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_seq64.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: MIT */ +/* + * 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 __AMDGPU_SEQ64_H__ +#define __AMDGPU_SEQ64_H__ + +#define AMDGPU_SEQ64_SIZE (2ULL << 20) +#define AMDGPU_MAX_SEQ64_SLOTS (AMDGPU_SEQ64_SIZE / (sizeof(u64) * 8)) +#define AMDGPU_SEQ64_VADDR_OFFSET 0x50000 +#define AMDGPU_SEQ64_VADDR_START (AMDGPU_VA_RESERVED_SIZE + AMDGPU_SEQ64_VADDR_OFFSET) + +struct amdgpu_seq64 { + struct amdgpu_bo *sbo; + u32 num_sem; + u64 *cpu_base_addr; + DECLARE_BITMAP(used, AMDGPU_MAX_SEQ64_SLOTS); +}; + +void amdgpu_seq64_fini(struct amdgpu_device *adev); +int amdgpu_seq64_init(struct amdgpu_device *adev); +int amdgpu_seq64_alloc(struct amdgpu_device *adev, u64 *gpu_addr, u64 **cpu_addr); +void amdgpu_seq64_free(struct amdgpu_device *adev, u64 gpu_addr); +int amdgpu_seq64_map(struct amdgpu_device *adev, struct amdgpu_vm *vm, + struct amdgpu_bo_va **bo_va, u64 seq64_addr, uint32_t size); +void amdgpu_seq64_unmap(struct amdgpu_device *adev, struct amdgpu_fpriv *fpriv); + +#endif + diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c index dcd8c066bc1f50..1b013a44ca99af 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c @@ -191,7 +191,8 @@ static bool amdgpu_sync_test_fence(struct amdgpu_device *adev, /* Never sync to VM updates either. */ if (fence_owner == AMDGPU_FENCE_OWNER_VM && - owner != AMDGPU_FENCE_OWNER_UNDEFINED) + owner != AMDGPU_FENCE_OWNER_UNDEFINED && + owner != AMDGPU_FENCE_OWNER_KFD) return false; /* Ignore fences depending on the sync mode */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h index 2fd1bfb35916fe..f539b1d002343e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h @@ -554,6 +554,21 @@ TRACE_EVENT(amdgpu_reset_reg_dumps, __entry->value) ); +TRACE_EVENT(amdgpu_runpm_reference_dumps, + TP_PROTO(uint32_t index, const char *func), + TP_ARGS(index, func), + TP_STRUCT__entry( + __field(uint32_t, index) + __string(func, func) + ), + TP_fast_assign( + __entry->index = index; + __assign_str(func, func); + ), + TP_printk("amdgpu runpm reference dump 0x%x: 0x%s\n", + __entry->index, + __get_str(func)) +); #undef AMDGPU_JOB_GET_TIMELINE_NAME #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index ab4a762aed5bde..75c9fd2c6c2a1c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -545,10 +545,11 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict, return r; } + trace_amdgpu_bo_move(abo, new_mem->mem_type, old_mem->mem_type); out: /* update statistics */ atomic64_add(bo->base.size, &adev->num_bytes_moved); - amdgpu_bo_move_notify(bo, evict, new_mem); + amdgpu_bo_move_notify(bo, evict); return 0; } @@ -1553,7 +1554,7 @@ static int amdgpu_ttm_access_memory(struct ttm_buffer_object *bo, static void amdgpu_bo_delete_mem_notify(struct ttm_buffer_object *bo) { - amdgpu_bo_move_notify(bo, false, NULL); + amdgpu_bo_move_notify(bo, false); } static struct ttm_device_funcs amdgpu_bo_driver = { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c index b14127429f3036..3e12763e477aa4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.c @@ -1062,7 +1062,8 @@ int amdgpu_ucode_create_bo(struct amdgpu_device *adev) { if (adev->firmware.load_type != AMDGPU_FW_LOAD_DIRECT) { amdgpu_bo_create_kernel(adev, adev->firmware.fw_size, PAGE_SIZE, - amdgpu_sriov_vf(adev) ? AMDGPU_GEM_DOMAIN_VRAM : AMDGPU_GEM_DOMAIN_GTT, + (amdgpu_sriov_vf(adev) || adev->debug_use_vram_fw_buf) ? + AMDGPU_GEM_DOMAIN_VRAM : AMDGPU_GEM_DOMAIN_GTT, &adev->firmware.fw_buf, &adev->firmware.fw_buf_mc, &adev->firmware.fw_buf_ptr); @@ -1397,9 +1398,13 @@ int amdgpu_ucode_request(struct amdgpu_device *adev, const struct firmware **fw, if (err) return -ENODEV; + err = amdgpu_ucode_validate(*fw); - if (err) + if (err) { dev_dbg(adev->dev, "\"%s\" failed to validate\n", fw_name); + release_firmware(*fw); + *fw = NULL; + } return err; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.c index ca45ba8ac17158..bfbf59326ee12d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umsch_mm.c @@ -86,7 +86,7 @@ static int map_ring_data(struct amdgpu_device *adev, struct amdgpu_vm *vm, amdgpu_sync_create(&sync); - drm_exec_init(&exec, 0); + drm_exec_init(&exec, 0, 0); drm_exec_until_all_locked(&exec) { r = drm_exec_lock_obj(&exec, &bo->tbo.base); drm_exec_retry_on_contention(&exec); @@ -149,7 +149,7 @@ static int unmap_ring_data(struct amdgpu_device *adev, struct amdgpu_vm *vm, struct drm_exec exec; long r; - drm_exec_init(&exec, 0); + drm_exec_init(&exec, 0, 0); drm_exec_until_all_locked(&exec) { r = drm_exec_lock_obj(&exec, &bo->tbo.base); drm_exec_retry_on_contention(&exec); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c index 3a632c3b1a2cdc..0dcff2889e25d2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_virt.c @@ -1099,7 +1099,8 @@ bool amdgpu_sriov_xnack_support(struct amdgpu_device *adev) { bool xnack_mode = true; - if (amdgpu_sriov_vf(adev) && adev->ip_versions[GC_HWIP][0] == IP_VERSION(9, 4, 2)) + if (amdgpu_sriov_vf(adev) && + amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 2)) xnack_mode = false; return xnack_mode; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c index db6fc0cb18eb8c..453a4b786cfcc1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ #include +#include #include #include diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 5baefb548a2909..b8fcb6c5569893 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -1438,6 +1438,51 @@ int amdgpu_vm_handle_moved(struct amdgpu_device *adev, return 0; } +/** + * amdgpu_vm_flush_compute_tlb - Flush TLB on compute VM + * + * @adev: amdgpu_device pointer + * @vm: requested vm + * @flush_type: flush type + * @xcc_mask: mask of XCCs that belong to the compute partition in need of a TLB flush. + * + * Flush TLB if needed for a compute VM. + * + * Returns: + * 0 for success. + */ +int amdgpu_vm_flush_compute_tlb(struct amdgpu_device *adev, + struct amdgpu_vm *vm, + uint32_t flush_type, + uint32_t xcc_mask) +{ + uint64_t tlb_seq = amdgpu_vm_tlb_seq(vm); + bool all_hub = false; + int xcc = 0, r = 0; + + WARN_ON_ONCE(!vm->is_compute_context); + + /* + * It can be that we race and lose here, but that is extremely unlikely + * and the worst thing which could happen is that we flush the changes + * into the TLB once more which is harmless. + */ + if (atomic64_xchg(&vm->kfd_last_flushed_seq, tlb_seq) == tlb_seq) + return 0; + + if (adev->family == AMDGPU_FAMILY_AI || + adev->family == AMDGPU_FAMILY_RV) + all_hub = true; + + for_each_inst(xcc, xcc_mask) { + r = amdgpu_gmc_flush_gpu_tlb_pasid(adev, vm->pasid, flush_type, + all_hub, xcc); + if (r) + break; + } + return r; +} + /** * amdgpu_vm_bo_add - add a bo to a specific vm * diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h index 2cd86d2bf73f7a..4740dd65b99d6c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h @@ -116,7 +116,7 @@ struct amdgpu_mem_stats; #define AMDGPU_VM_FAULT_STOP_FIRST 1 #define AMDGPU_VM_FAULT_STOP_ALWAYS 2 -/* Reserve 4MB VRAM for page tables */ +/* How much VRAM be reserved for page tables */ #define AMDGPU_VM_RESERVED_VRAM (8ULL << 20) /* @@ -324,6 +324,7 @@ struct amdgpu_vm { /* Last finished delayed update */ atomic64_t tlb_seq; struct dma_fence *last_tlb_flush; + atomic64_t kfd_last_flushed_seq; /* How many times we had to re-generate the page tables */ uint64_t generation; @@ -445,6 +446,10 @@ int amdgpu_vm_clear_freed(struct amdgpu_device *adev, int amdgpu_vm_handle_moved(struct amdgpu_device *adev, struct amdgpu_vm *vm, struct ww_acquire_ctx *ticket); +int amdgpu_vm_flush_compute_tlb(struct amdgpu_device *adev, + struct amdgpu_vm *vm, + uint32_t flush_type, + uint32_t xcc_mask); void amdgpu_vm_bo_base_init(struct amdgpu_vm_bo_base *base, struct amdgpu_vm *vm, struct amdgpu_bo *bo); int amdgpu_vm_update_range(struct amdgpu_device *adev, struct amdgpu_vm *vm, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.c index e81579708e9662..b9a15d51eb5c30 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.c @@ -26,6 +26,7 @@ #include "amdgpu.h" #include "amdgpu_ucode.h" #include "amdgpu_vpe.h" +#include "amdgpu_smu.h" #include "soc15_common.h" #include "vpe_v6_1.h" @@ -33,8 +34,180 @@ /* VPE CSA resides in the 4th page of CSA */ #define AMDGPU_CSA_VPE_OFFSET (4096 * 3) +/* 1 second timeout */ +#define VPE_IDLE_TIMEOUT msecs_to_jiffies(1000) + +#define VPE_MAX_DPM_LEVEL 4 +#define FIXED1_8_BITS_PER_FRACTIONAL_PART 8 +#define GET_PRATIO_INTEGER_PART(x) ((x) >> FIXED1_8_BITS_PER_FRACTIONAL_PART) + static void vpe_set_ring_funcs(struct amdgpu_device *adev); +static inline uint16_t div16_u16_rem(uint16_t dividend, uint16_t divisor, uint16_t *remainder) +{ + *remainder = dividend % divisor; + return dividend / divisor; +} + +static inline uint16_t complete_integer_division_u16( + uint16_t dividend, + uint16_t divisor, + uint16_t *remainder) +{ + return div16_u16_rem(dividend, divisor, (uint16_t *)remainder); +} + +static uint16_t vpe_u1_8_from_fraction(uint16_t numerator, uint16_t denominator) +{ + u16 arg1_value = numerator; + u16 arg2_value = denominator; + + uint16_t remainder; + + /* determine integer part */ + uint16_t res_value = complete_integer_division_u16( + arg1_value, arg2_value, &remainder); + + if (res_value > 127 /* CHAR_MAX */) + return 0; + + /* determine fractional part */ + { + unsigned int i = FIXED1_8_BITS_PER_FRACTIONAL_PART; + + do { + remainder <<= 1; + + res_value <<= 1; + + if (remainder >= arg2_value) { + res_value |= 1; + remainder -= arg2_value; + } + } while (--i != 0); + } + + /* round up LSB */ + { + uint16_t summand = (remainder << 1) >= arg2_value; + + if ((res_value + summand) > 32767 /* SHRT_MAX */) + return 0; + + res_value += summand; + } + + return res_value; +} + +static uint16_t vpe_internal_get_pratio(uint16_t from_frequency, uint16_t to_frequency) +{ + uint16_t pratio = vpe_u1_8_from_fraction(from_frequency, to_frequency); + + if (GET_PRATIO_INTEGER_PART(pratio) > 1) + pratio = 0; + + return pratio; +} + +/* + * VPE has 4 DPM levels from level 0 (lowerest) to 3 (highest), + * VPE FW will dynamically decide which level should be used according to current loading. + * + * Get VPE and SOC clocks from PM, and select the appropriate four clock values, + * calculate the ratios of adjusting from one clock to another. + * The VPE FW can then request the appropriate frequency from the PMFW. + */ +int amdgpu_vpe_configure_dpm(struct amdgpu_vpe *vpe) +{ + struct amdgpu_device *adev = vpe->ring.adev; + uint32_t dpm_ctl; + + if (adev->pm.dpm_enabled) { + struct dpm_clocks clock_table = { 0 }; + struct dpm_clock *VPEClks; + struct dpm_clock *SOCClks; + uint32_t idx; + uint32_t pratio_vmax_vnorm = 0, pratio_vnorm_vmid = 0, pratio_vmid_vmin = 0; + uint16_t pratio_vmin_freq = 0, pratio_vmid_freq = 0, pratio_vnorm_freq = 0, pratio_vmax_freq = 0; + + dpm_ctl = RREG32(vpe_get_reg_offset(vpe, 0, vpe->regs.dpm_enable)); + dpm_ctl |= 1; /* DPM enablement */ + WREG32(vpe_get_reg_offset(vpe, 0, vpe->regs.dpm_enable), dpm_ctl); + + /* Get VPECLK and SOCCLK */ + if (amdgpu_dpm_get_dpm_clock_table(adev, &clock_table)) { + dev_dbg(adev->dev, "%s: get clock failed!\n", __func__); + goto disable_dpm; + } + + SOCClks = clock_table.SocClocks; + VPEClks = clock_table.VPEClocks; + + /* vpe dpm only cares 4 levels. */ + for (idx = 0; idx < VPE_MAX_DPM_LEVEL; idx++) { + uint32_t soc_dpm_level; + uint32_t min_freq; + + if (idx == 0) + soc_dpm_level = 0; + else + soc_dpm_level = (idx * 2) + 1; + + /* clamp the max level */ + if (soc_dpm_level > PP_SMU_NUM_VPECLK_DPM_LEVELS - 1) + soc_dpm_level = PP_SMU_NUM_VPECLK_DPM_LEVELS - 1; + + min_freq = (SOCClks[soc_dpm_level].Freq < VPEClks[soc_dpm_level].Freq) ? + SOCClks[soc_dpm_level].Freq : VPEClks[soc_dpm_level].Freq; + + switch (idx) { + case 0: + pratio_vmin_freq = min_freq; + break; + case 1: + pratio_vmid_freq = min_freq; + break; + case 2: + pratio_vnorm_freq = min_freq; + break; + case 3: + pratio_vmax_freq = min_freq; + break; + default: + break; + } + } + + if (pratio_vmin_freq && pratio_vmid_freq && pratio_vnorm_freq && pratio_vmax_freq) { + uint32_t pratio_ctl; + + pratio_vmax_vnorm = (uint32_t)vpe_internal_get_pratio(pratio_vmax_freq, pratio_vnorm_freq); + pratio_vnorm_vmid = (uint32_t)vpe_internal_get_pratio(pratio_vnorm_freq, pratio_vmid_freq); + pratio_vmid_vmin = (uint32_t)vpe_internal_get_pratio(pratio_vmid_freq, pratio_vmin_freq); + + pratio_ctl = pratio_vmax_vnorm | (pratio_vnorm_vmid << 9) | (pratio_vmid_vmin << 18); + WREG32(vpe_get_reg_offset(vpe, 0, vpe->regs.dpm_pratio), pratio_ctl); /* PRatio */ + WREG32(vpe_get_reg_offset(vpe, 0, vpe->regs.dpm_request_interval), 24000); /* 1ms, unit=1/24MHz */ + WREG32(vpe_get_reg_offset(vpe, 0, vpe->regs.dpm_decision_threshold), 1200000); /* 50ms */ + WREG32(vpe_get_reg_offset(vpe, 0, vpe->regs.dpm_busy_clamp_threshold), 1200000);/* 50ms */ + WREG32(vpe_get_reg_offset(vpe, 0, vpe->regs.dpm_idle_clamp_threshold), 1200000);/* 50ms */ + dev_dbg(adev->dev, "%s: configure vpe dpm pratio done!\n", __func__); + } else { + dev_dbg(adev->dev, "%s: invalid pratio parameters!\n", __func__); + goto disable_dpm; + } + } + return 0; + +disable_dpm: + dpm_ctl = RREG32(vpe_get_reg_offset(vpe, 0, vpe->regs.dpm_enable)); + dpm_ctl &= 0xfffffffe; /* Disable DPM */ + WREG32(vpe_get_reg_offset(vpe, 0, vpe->regs.dpm_enable), dpm_ctl); + dev_dbg(adev->dev, "%s: disable vpe dpm\n", __func__); + return 0; +} + int amdgpu_vpe_psp_update_sram(struct amdgpu_device *adev) { struct amdgpu_firmware_info ucode = { @@ -134,6 +307,19 @@ static int vpe_early_init(void *handle) return 0; } +static void vpe_idle_work_handler(struct work_struct *work) +{ + struct amdgpu_device *adev = + container_of(work, struct amdgpu_device, vpe.idle_work.work); + unsigned int fences = 0; + + fences += amdgpu_fence_count_emitted(&adev->vpe.ring); + + if (fences == 0) + amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VPE, AMD_PG_STATE_GATE); + else + schedule_delayed_work(&adev->vpe.idle_work, VPE_IDLE_TIMEOUT); +} static int vpe_common_init(struct amdgpu_vpe *vpe) { @@ -150,6 +336,9 @@ static int vpe_common_init(struct amdgpu_vpe *vpe) return r; } + vpe->context_started = false; + INIT_DELAYED_WORK(&adev->vpe.idle_work, vpe_idle_work_handler); + return 0; } @@ -219,6 +408,9 @@ static int vpe_hw_fini(void *handle) vpe_ring_stop(vpe); + /* Power off VPE */ + amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VPE, AMD_PG_STATE_GATE); + return 0; } @@ -226,6 +418,8 @@ static int vpe_suspend(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; + cancel_delayed_work_sync(&adev->vpe.idle_work); + return vpe_hw_fini(adev); } @@ -430,6 +624,21 @@ static int vpe_set_clockgating_state(void *handle, static int vpe_set_powergating_state(void *handle, enum amd_powergating_state state) { + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + struct amdgpu_vpe *vpe = &adev->vpe; + + if (!adev->pm.dpm_enabled) + dev_err(adev->dev, "Without PM, cannot support powergating\n"); + + dev_dbg(adev->dev, "%s: %s!\n", __func__, (state == AMD_PG_STATE_GATE) ? "GATE":"UNGATE"); + + if (state == AMD_PG_STATE_GATE) { + amdgpu_dpm_enable_vpe(adev, false); + vpe->context_started = false; + } else { + amdgpu_dpm_enable_vpe(adev, true); + } + return 0; } @@ -595,6 +804,38 @@ err0: return ret; } +static void vpe_ring_begin_use(struct amdgpu_ring *ring) +{ + struct amdgpu_device *adev = ring->adev; + struct amdgpu_vpe *vpe = &adev->vpe; + + cancel_delayed_work_sync(&adev->vpe.idle_work); + + /* Power on VPE and notify VPE of new context */ + if (!vpe->context_started) { + uint32_t context_notify; + + /* Power on VPE */ + amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_VPE, AMD_PG_STATE_UNGATE); + + /* Indicates that a job from a new context has been submitted. */ + context_notify = RREG32(vpe_get_reg_offset(vpe, 0, vpe->regs.context_indicator)); + if ((context_notify & 0x1) == 0) + context_notify |= 0x1; + else + context_notify &= ~(0x1); + WREG32(vpe_get_reg_offset(vpe, 0, vpe->regs.context_indicator), context_notify); + vpe->context_started = true; + } +} + +static void vpe_ring_end_use(struct amdgpu_ring *ring) +{ + struct amdgpu_device *adev = ring->adev; + + schedule_delayed_work(&adev->vpe.idle_work, VPE_IDLE_TIMEOUT); +} + static const struct amdgpu_ring_funcs vpe_ring_funcs = { .type = AMDGPU_RING_TYPE_VPE, .align_mask = 0xf, @@ -625,6 +866,8 @@ static const struct amdgpu_ring_funcs vpe_ring_funcs = { .init_cond_exec = vpe_ring_init_cond_exec, .patch_cond_exec = vpe_ring_patch_cond_exec, .preempt_ib = vpe_ring_preempt_ib, + .begin_use = vpe_ring_begin_use, + .end_use = vpe_ring_end_use, }; static void vpe_set_ring_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.h index 29d56f7ae4a9ec..1153ddaea64d67 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vpe.h @@ -47,6 +47,15 @@ struct vpe_regs { uint32_t queue0_rb_wptr_lo; uint32_t queue0_rb_wptr_hi; uint32_t queue0_preempt; + + uint32_t dpm_enable; + uint32_t dpm_pratio; + uint32_t dpm_request_interval; + uint32_t dpm_decision_threshold; + uint32_t dpm_busy_clamp_threshold; + uint32_t dpm_idle_clamp_threshold; + uint32_t dpm_request_lv; + uint32_t context_indicator; }; struct amdgpu_vpe { @@ -63,12 +72,15 @@ struct amdgpu_vpe { struct amdgpu_bo *cmdbuf_obj; uint64_t cmdbuf_gpu_addr; uint32_t *cmdbuf_cpu_addr; + struct delayed_work idle_work; + bool context_started; }; int amdgpu_vpe_psp_update_sram(struct amdgpu_device *adev); int amdgpu_vpe_init_microcode(struct amdgpu_vpe *vpe); int amdgpu_vpe_ring_init(struct amdgpu_vpe *vpe); int amdgpu_vpe_ring_fini(struct amdgpu_vpe *vpe); +int amdgpu_vpe_configure_dpm(struct amdgpu_vpe *vpe); #define vpe_ring_init(vpe) ((vpe)->funcs->ring_init ? (vpe)->funcs->ring_init((vpe)) : 0) #define vpe_ring_start(vpe) ((vpe)->funcs->ring_start ? (vpe)->funcs->ring_start((vpe)) : 0) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c index 08916538a615ff..8db880244324ff 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c @@ -221,8 +221,23 @@ static struct attribute *amdgpu_vram_mgr_attributes[] = { NULL }; +static umode_t amdgpu_vram_attrs_is_visible(struct kobject *kobj, + struct attribute *attr, int i) +{ + struct device *dev = kobj_to_dev(kobj); + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(ddev); + + if (attr == &dev_attr_mem_info_vram_vendor.attr && + !adev->gmc.vram_vendor) + return 0; + + return attr->mode; +} + const struct attribute_group amdgpu_vram_mgr_attr_group = { - .attrs = amdgpu_vram_mgr_attributes + .attrs = amdgpu_vram_mgr_attributes, + .is_visible = amdgpu_vram_attrs_is_visible }; /** diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c index bd20cb3b981984..a6c88f2fe6e575 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c @@ -413,6 +413,38 @@ static ssize_t amdgpu_xgmi_show_num_links(struct device *dev, return sysfs_emit(buf, "%s\n", buf); } +static ssize_t amdgpu_xgmi_show_connected_port_num(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(ddev); + struct psp_xgmi_topology_info *top = &adev->psp.xgmi_context.top_info; + int i, j, size = 0; + int current_node; + /* + * get the node id in the sysfs for the current socket and show + * it in the port num info output in the sysfs for easy reading. + * it is NOT the one retrieved from xgmi ta. + */ + for (i = 0; i < top->num_nodes; i++) { + if (top->nodes[i].node_id == adev->gmc.xgmi.node_id) { + current_node = i; + break; + } + } + + for (i = 0; i < top->num_nodes; i++) { + for (j = 0; j < top->nodes[i].num_links; j++) + /* node id in sysfs starts from 1 rather than 0 so +1 here */ + size += sysfs_emit_at(buf, size, "%02x:%02x -> %02x:%02x\n", current_node + 1, + top->nodes[i].port_num[j].src_xgmi_port_num, i + 1, + top->nodes[i].port_num[j].dst_xgmi_port_num); + } + + return size; +} + #define AMDGPU_XGMI_SET_FICAA(o) ((o) | 0x456801) static ssize_t amdgpu_xgmi_show_error(struct device *dev, struct device_attribute *attr, @@ -452,6 +484,7 @@ static DEVICE_ATTR(xgmi_physical_id, 0444, amdgpu_xgmi_show_physical_id, NULL); static DEVICE_ATTR(xgmi_error, S_IRUGO, amdgpu_xgmi_show_error, NULL); static DEVICE_ATTR(xgmi_num_hops, S_IRUGO, amdgpu_xgmi_show_num_hops, NULL); static DEVICE_ATTR(xgmi_num_links, S_IRUGO, amdgpu_xgmi_show_num_links, NULL); +static DEVICE_ATTR(xgmi_port_num, S_IRUGO, amdgpu_xgmi_show_connected_port_num, NULL); static int amdgpu_xgmi_sysfs_add_dev_info(struct amdgpu_device *adev, struct amdgpu_hive_info *hive) @@ -487,6 +520,13 @@ static int amdgpu_xgmi_sysfs_add_dev_info(struct amdgpu_device *adev, if (ret) pr_err("failed to create xgmi_num_links\n"); + /* Create xgmi port num file if supported */ + if (adev->psp.xgmi_context.xgmi_ta_caps & EXTEND_PEER_LINK_INFO_CMD_FLAG) { + ret = device_create_file(adev->dev, &dev_attr_xgmi_port_num); + if (ret) + dev_err(adev->dev, "failed to create xgmi_port_num\n"); + } + /* Create sysfs link to hive info folder on the first device */ if (hive->kobj.parent != (&adev->dev->kobj)) { ret = sysfs_create_link(&adev->dev->kobj, &hive->kobj, @@ -517,6 +557,8 @@ remove_file: device_remove_file(adev->dev, &dev_attr_xgmi_error); device_remove_file(adev->dev, &dev_attr_xgmi_num_hops); device_remove_file(adev->dev, &dev_attr_xgmi_num_links); + if (adev->psp.xgmi_context.xgmi_ta_caps & EXTEND_PEER_LINK_INFO_CMD_FLAG) + device_remove_file(adev->dev, &dev_attr_xgmi_port_num); success: return ret; @@ -533,6 +575,8 @@ static void amdgpu_xgmi_sysfs_rem_dev_info(struct amdgpu_device *adev, device_remove_file(adev->dev, &dev_attr_xgmi_error); device_remove_file(adev->dev, &dev_attr_xgmi_num_hops); device_remove_file(adev->dev, &dev_attr_xgmi_num_links); + if (adev->psp.xgmi_context.xgmi_ta_caps & EXTEND_PEER_LINK_INFO_CMD_FLAG) + device_remove_file(adev->dev, &dev_attr_xgmi_port_num); if (hive->kobj.parent != (&adev->dev->kobj)) sysfs_remove_link(&adev->dev->kobj,"xgmi_hive_info"); @@ -779,6 +823,28 @@ static int amdgpu_xgmi_initialize_hive_get_data_partition(struct amdgpu_hive_inf return 0; } +static void amdgpu_xgmi_fill_topology_info(struct amdgpu_device *adev, + struct amdgpu_device *peer_adev) +{ + struct psp_xgmi_topology_info *top_info = &adev->psp.xgmi_context.top_info; + struct psp_xgmi_topology_info *peer_info = &peer_adev->psp.xgmi_context.top_info; + + for (int i = 0; i < peer_info->num_nodes; i++) { + if (peer_info->nodes[i].node_id == adev->gmc.xgmi.node_id) { + for (int j = 0; j < top_info->num_nodes; j++) { + if (top_info->nodes[j].node_id == peer_adev->gmc.xgmi.node_id) { + peer_info->nodes[i].num_hops = top_info->nodes[j].num_hops; + peer_info->nodes[i].is_sharing_enabled = + top_info->nodes[j].is_sharing_enabled; + peer_info->nodes[i].num_links = + top_info->nodes[j].num_links; + return; + } + } + } + } +} + int amdgpu_xgmi_add_device(struct amdgpu_device *adev) { struct psp_xgmi_topology_info *top_info; @@ -853,18 +919,38 @@ int amdgpu_xgmi_add_device(struct amdgpu_device *adev) goto exit_unlock; } - /* get latest topology info for each device from psp */ - list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head) { - ret = psp_xgmi_get_topology_info(&tmp_adev->psp, count, - &tmp_adev->psp.xgmi_context.top_info, false); + if (amdgpu_sriov_vf(adev) && + adev->psp.xgmi_context.xgmi_ta_caps & EXTEND_PEER_LINK_INFO_CMD_FLAG) { + /* only get topology for VF being init if it can support full duplex */ + ret = psp_xgmi_get_topology_info(&adev->psp, count, + &adev->psp.xgmi_context.top_info, false); if (ret) { - dev_err(tmp_adev->dev, + dev_err(adev->dev, "XGMI: Get topology failure on device %llx, hive %llx, ret %d", - tmp_adev->gmc.xgmi.node_id, - tmp_adev->gmc.xgmi.hive_id, ret); - /* To do : continue with some node failed or disable the whole hive */ + adev->gmc.xgmi.node_id, + adev->gmc.xgmi.hive_id, ret); + /* To do: continue with some node failed or disable the whole hive*/ goto exit_unlock; } + + /* fill the topology info for peers instead of getting from PSP */ + list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head) { + amdgpu_xgmi_fill_topology_info(adev, tmp_adev); + } + } else { + /* get latest topology info for each device from psp */ + list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head) { + ret = psp_xgmi_get_topology_info(&tmp_adev->psp, count, + &tmp_adev->psp.xgmi_context.top_info, false); + if (ret) { + dev_err(tmp_adev->dev, + "XGMI: Get topology failure on device %llx, hive %llx, ret %d", + tmp_adev->gmc.xgmi.node_id, + tmp_adev->gmc.xgmi.hive_id, ret); + /* To do : continue with some node failed or disable the whole hive */ + goto exit_unlock; + } + } } /* get topology again for hives that support extended data */ @@ -1227,10 +1313,10 @@ static void __xgmi_v6_4_0_query_error_count(struct amdgpu_device *adev, struct a switch (xgmi_v6_4_0_pcs_mca_get_error_type(adev, status)) { case AMDGPU_MCA_ERROR_TYPE_UE: - amdgpu_ras_error_statistic_ue_count(err_data, mcm_info, 1ULL); + amdgpu_ras_error_statistic_ue_count(err_data, mcm_info, NULL, 1ULL); break; case AMDGPU_MCA_ERROR_TYPE_CE: - amdgpu_ras_error_statistic_ce_count(err_data, mcm_info, 1ULL); + amdgpu_ras_error_statistic_ce_count(err_data, mcm_info, NULL, 1ULL); break; default: break; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h index 6cab882e8061e8..1592c63b3099b9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.h @@ -43,7 +43,6 @@ struct amdgpu_hive_info { } pstate; struct amdgpu_reset_domain *reset_domain; - uint32_t device_remove_count; atomic_t ras_recovery; }; diff --git a/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c b/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c index 3f715e7fe1a959..d6f808acfb17b7 100644 --- a/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c +++ b/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c @@ -24,6 +24,7 @@ #include "soc15.h" #include "soc15_common.h" +#include "amdgpu_reg_state.h" #include "amdgpu_xcp.h" #include "gfx_v9_4_3.h" #include "gfxhub_v1_2.h" @@ -656,3 +657,416 @@ int aqua_vanjaram_init_soc_config(struct amdgpu_device *adev) return 0; } + +static void aqua_read_smn(struct amdgpu_device *adev, + struct amdgpu_smn_reg_data *regdata, + uint64_t smn_addr) +{ + regdata->addr = smn_addr; + regdata->value = RREG32_PCIE(smn_addr); +} + +struct aqua_reg_list { + uint64_t start_addr; + uint32_t num_regs; + uint32_t incrx; +}; + +#define DW_ADDR_INCR 4 + +static void aqua_read_smn_ext(struct amdgpu_device *adev, + struct amdgpu_smn_reg_data *regdata, + uint64_t smn_addr, int i) +{ + regdata->addr = + smn_addr + adev->asic_funcs->encode_ext_smn_addressing(i); + regdata->value = RREG32_PCIE_EXT(regdata->addr); +} + +#define smnreg_0x1A340218 0x1A340218 +#define smnreg_0x1A3402E4 0x1A3402E4 +#define smnreg_0x1A340294 0x1A340294 +#define smreg_0x1A380088 0x1A380088 + +#define NUM_PCIE_SMN_REGS 14 + +static struct aqua_reg_list pcie_reg_addrs[] = { + { smnreg_0x1A340218, 1, 0 }, + { smnreg_0x1A3402E4, 1, 0 }, + { smnreg_0x1A340294, 6, DW_ADDR_INCR }, + { smreg_0x1A380088, 6, DW_ADDR_INCR }, +}; + +static ssize_t aqua_vanjaram_read_pcie_state(struct amdgpu_device *adev, + void *buf, size_t max_size) +{ + struct amdgpu_reg_state_pcie_v1_0 *pcie_reg_state; + uint32_t start_addr, incrx, num_regs, szbuf; + struct amdgpu_regs_pcie_v1_0 *pcie_regs; + struct amdgpu_smn_reg_data *reg_data; + struct pci_dev *us_pdev, *ds_pdev; + int aer_cap, r, n; + + if (!buf || !max_size) + return -EINVAL; + + pcie_reg_state = (struct amdgpu_reg_state_pcie_v1_0 *)buf; + + szbuf = sizeof(*pcie_reg_state) + + amdgpu_reginst_size(1, sizeof(*pcie_regs), NUM_PCIE_SMN_REGS); + /* Only one instance of pcie regs */ + if (max_size < szbuf) + return -EOVERFLOW; + + pcie_regs = (struct amdgpu_regs_pcie_v1_0 *)((uint8_t *)buf + + sizeof(*pcie_reg_state)); + pcie_regs->inst_header.instance = 0; + pcie_regs->inst_header.state = AMDGPU_INST_S_OK; + pcie_regs->inst_header.num_smn_regs = NUM_PCIE_SMN_REGS; + + reg_data = pcie_regs->smn_reg_values; + + for (r = 0; r < ARRAY_SIZE(pcie_reg_addrs); r++) { + start_addr = pcie_reg_addrs[r].start_addr; + incrx = pcie_reg_addrs[r].incrx; + num_regs = pcie_reg_addrs[r].num_regs; + for (n = 0; n < num_regs; n++) { + aqua_read_smn(adev, reg_data, start_addr + n * incrx); + ++reg_data; + } + } + + ds_pdev = pci_upstream_bridge(adev->pdev); + us_pdev = pci_upstream_bridge(ds_pdev); + + pcie_capability_read_word(us_pdev, PCI_EXP_DEVSTA, + &pcie_regs->device_status); + pcie_capability_read_word(us_pdev, PCI_EXP_LNKSTA, + &pcie_regs->link_status); + + aer_cap = pci_find_ext_capability(us_pdev, PCI_EXT_CAP_ID_ERR); + if (aer_cap) { + pci_read_config_dword(us_pdev, aer_cap + PCI_ERR_COR_STATUS, + &pcie_regs->pcie_corr_err_status); + pci_read_config_dword(us_pdev, aer_cap + PCI_ERR_UNCOR_STATUS, + &pcie_regs->pcie_uncorr_err_status); + } + + pci_read_config_dword(us_pdev, PCI_PRIMARY_BUS, + &pcie_regs->sub_bus_number_latency); + + pcie_reg_state->common_header.structure_size = szbuf; + pcie_reg_state->common_header.format_revision = 1; + pcie_reg_state->common_header.content_revision = 0; + pcie_reg_state->common_header.state_type = AMDGPU_REG_STATE_TYPE_PCIE; + pcie_reg_state->common_header.num_instances = 1; + + return pcie_reg_state->common_header.structure_size; +} + +#define smnreg_0x11A00050 0x11A00050 +#define smnreg_0x11A00180 0x11A00180 +#define smnreg_0x11A00070 0x11A00070 +#define smnreg_0x11A00200 0x11A00200 +#define smnreg_0x11A0020C 0x11A0020C +#define smnreg_0x11A00210 0x11A00210 +#define smnreg_0x11A00108 0x11A00108 + +#define XGMI_LINK_REG(smnreg, l) ((smnreg) | (l << 20)) + +#define NUM_XGMI_SMN_REGS 25 + +static struct aqua_reg_list xgmi_reg_addrs[] = { + { smnreg_0x11A00050, 1, 0 }, + { smnreg_0x11A00180, 16, DW_ADDR_INCR }, + { smnreg_0x11A00070, 4, DW_ADDR_INCR }, + { smnreg_0x11A00200, 1, 0 }, + { smnreg_0x11A0020C, 1, 0 }, + { smnreg_0x11A00210, 1, 0 }, + { smnreg_0x11A00108, 1, 0 }, +}; + +static ssize_t aqua_vanjaram_read_xgmi_state(struct amdgpu_device *adev, + void *buf, size_t max_size) +{ + struct amdgpu_reg_state_xgmi_v1_0 *xgmi_reg_state; + uint32_t start_addr, incrx, num_regs, szbuf; + struct amdgpu_regs_xgmi_v1_0 *xgmi_regs; + struct amdgpu_smn_reg_data *reg_data; + const int max_xgmi_instances = 8; + int inst = 0, i, j, r, n; + const int xgmi_inst = 2; + void *p; + + if (!buf || !max_size) + return -EINVAL; + + xgmi_reg_state = (struct amdgpu_reg_state_xgmi_v1_0 *)buf; + + szbuf = sizeof(*xgmi_reg_state) + + amdgpu_reginst_size(max_xgmi_instances, sizeof(*xgmi_regs), + NUM_XGMI_SMN_REGS); + /* Only one instance of pcie regs */ + if (max_size < szbuf) + return -EOVERFLOW; + + p = &xgmi_reg_state->xgmi_state_regs[0]; + for_each_inst(i, adev->aid_mask) { + for (j = 0; j < xgmi_inst; ++j) { + xgmi_regs = (struct amdgpu_regs_xgmi_v1_0 *)p; + xgmi_regs->inst_header.instance = inst++; + + xgmi_regs->inst_header.state = AMDGPU_INST_S_OK; + xgmi_regs->inst_header.num_smn_regs = NUM_XGMI_SMN_REGS; + + reg_data = xgmi_regs->smn_reg_values; + + for (r = 0; r < ARRAY_SIZE(xgmi_reg_addrs); r++) { + start_addr = xgmi_reg_addrs[r].start_addr; + incrx = xgmi_reg_addrs[r].incrx; + num_regs = xgmi_reg_addrs[r].num_regs; + + for (n = 0; n < num_regs; n++) { + aqua_read_smn_ext( + adev, reg_data, + XGMI_LINK_REG(start_addr, j) + + n * incrx, + i); + ++reg_data; + } + } + p = reg_data; + } + } + + xgmi_reg_state->common_header.structure_size = szbuf; + xgmi_reg_state->common_header.format_revision = 1; + xgmi_reg_state->common_header.content_revision = 0; + xgmi_reg_state->common_header.state_type = AMDGPU_REG_STATE_TYPE_XGMI; + xgmi_reg_state->common_header.num_instances = max_xgmi_instances; + + return xgmi_reg_state->common_header.structure_size; +} + +#define smnreg_0x11C00070 0x11C00070 +#define smnreg_0x11C00210 0x11C00210 + +static struct aqua_reg_list wafl_reg_addrs[] = { + { smnreg_0x11C00070, 4, DW_ADDR_INCR }, + { smnreg_0x11C00210, 1, 0 }, +}; + +#define WAFL_LINK_REG(smnreg, l) ((smnreg) | (l << 20)) + +#define NUM_WAFL_SMN_REGS 5 + +static ssize_t aqua_vanjaram_read_wafl_state(struct amdgpu_device *adev, + void *buf, size_t max_size) +{ + struct amdgpu_reg_state_wafl_v1_0 *wafl_reg_state; + uint32_t start_addr, incrx, num_regs, szbuf; + struct amdgpu_regs_wafl_v1_0 *wafl_regs; + struct amdgpu_smn_reg_data *reg_data; + const int max_wafl_instances = 8; + int inst = 0, i, j, r, n; + const int wafl_inst = 2; + void *p; + + if (!buf || !max_size) + return -EINVAL; + + wafl_reg_state = (struct amdgpu_reg_state_wafl_v1_0 *)buf; + + szbuf = sizeof(*wafl_reg_state) + + amdgpu_reginst_size(max_wafl_instances, sizeof(*wafl_regs), + NUM_WAFL_SMN_REGS); + + if (max_size < szbuf) + return -EOVERFLOW; + + p = &wafl_reg_state->wafl_state_regs[0]; + for_each_inst(i, adev->aid_mask) { + for (j = 0; j < wafl_inst; ++j) { + wafl_regs = (struct amdgpu_regs_wafl_v1_0 *)p; + wafl_regs->inst_header.instance = inst++; + + wafl_regs->inst_header.state = AMDGPU_INST_S_OK; + wafl_regs->inst_header.num_smn_regs = NUM_WAFL_SMN_REGS; + + reg_data = wafl_regs->smn_reg_values; + + for (r = 0; r < ARRAY_SIZE(wafl_reg_addrs); r++) { + start_addr = wafl_reg_addrs[r].start_addr; + incrx = wafl_reg_addrs[r].incrx; + num_regs = wafl_reg_addrs[r].num_regs; + for (n = 0; n < num_regs; n++) { + aqua_read_smn_ext( + adev, reg_data, + WAFL_LINK_REG(start_addr, j) + + n * incrx, + i); + ++reg_data; + } + } + p = reg_data; + } + } + + wafl_reg_state->common_header.structure_size = szbuf; + wafl_reg_state->common_header.format_revision = 1; + wafl_reg_state->common_header.content_revision = 0; + wafl_reg_state->common_header.state_type = AMDGPU_REG_STATE_TYPE_WAFL; + wafl_reg_state->common_header.num_instances = max_wafl_instances; + + return wafl_reg_state->common_header.structure_size; +} + +#define smnreg_0x1B311060 0x1B311060 +#define smnreg_0x1B411060 0x1B411060 +#define smnreg_0x1B511060 0x1B511060 +#define smnreg_0x1B611060 0x1B611060 + +#define smnreg_0x1C307120 0x1C307120 +#define smnreg_0x1C317120 0x1C317120 + +#define smnreg_0x1C320830 0x1C320830 +#define smnreg_0x1C380830 0x1C380830 +#define smnreg_0x1C3D0830 0x1C3D0830 +#define smnreg_0x1C420830 0x1C420830 + +#define smnreg_0x1C320100 0x1C320100 +#define smnreg_0x1C380100 0x1C380100 +#define smnreg_0x1C3D0100 0x1C3D0100 +#define smnreg_0x1C420100 0x1C420100 + +#define smnreg_0x1B310500 0x1B310500 +#define smnreg_0x1C300400 0x1C300400 + +#define USR_CAKE_INCR 0x11000 +#define USR_LINK_INCR 0x100000 +#define USR_CP_INCR 0x10000 + +#define NUM_USR_SMN_REGS 20 + +struct aqua_reg_list usr_reg_addrs[] = { + { smnreg_0x1B311060, 4, DW_ADDR_INCR }, + { smnreg_0x1B411060, 4, DW_ADDR_INCR }, + { smnreg_0x1B511060, 4, DW_ADDR_INCR }, + { smnreg_0x1B611060, 4, DW_ADDR_INCR }, + { smnreg_0x1C307120, 2, DW_ADDR_INCR }, + { smnreg_0x1C317120, 2, DW_ADDR_INCR }, +}; + +#define NUM_USR1_SMN_REGS 46 +struct aqua_reg_list usr1_reg_addrs[] = { + { smnreg_0x1C320830, 6, USR_CAKE_INCR }, + { smnreg_0x1C380830, 5, USR_CAKE_INCR }, + { smnreg_0x1C3D0830, 5, USR_CAKE_INCR }, + { smnreg_0x1C420830, 4, USR_CAKE_INCR }, + { smnreg_0x1C320100, 6, USR_CAKE_INCR }, + { smnreg_0x1C380100, 5, USR_CAKE_INCR }, + { smnreg_0x1C3D0100, 5, USR_CAKE_INCR }, + { smnreg_0x1C420100, 4, USR_CAKE_INCR }, + { smnreg_0x1B310500, 4, USR_LINK_INCR }, + { smnreg_0x1C300400, 2, USR_CP_INCR }, +}; + +static ssize_t aqua_vanjaram_read_usr_state(struct amdgpu_device *adev, + void *buf, size_t max_size, + int reg_state) +{ + uint32_t start_addr, incrx, num_regs, szbuf, num_smn; + struct amdgpu_reg_state_usr_v1_0 *usr_reg_state; + struct amdgpu_regs_usr_v1_0 *usr_regs; + struct amdgpu_smn_reg_data *reg_data; + const int max_usr_instances = 4; + struct aqua_reg_list *reg_addrs; + int inst = 0, i, n, r, arr_size; + void *p; + + if (!buf || !max_size) + return -EINVAL; + + switch (reg_state) { + case AMDGPU_REG_STATE_TYPE_USR: + arr_size = ARRAY_SIZE(usr_reg_addrs); + reg_addrs = usr_reg_addrs; + num_smn = NUM_USR_SMN_REGS; + break; + case AMDGPU_REG_STATE_TYPE_USR_1: + arr_size = ARRAY_SIZE(usr1_reg_addrs); + reg_addrs = usr1_reg_addrs; + num_smn = NUM_USR1_SMN_REGS; + break; + default: + return -EINVAL; + } + + usr_reg_state = (struct amdgpu_reg_state_usr_v1_0 *)buf; + + szbuf = sizeof(*usr_reg_state) + amdgpu_reginst_size(max_usr_instances, + sizeof(*usr_regs), + num_smn); + if (max_size < szbuf) + return -EOVERFLOW; + + p = &usr_reg_state->usr_state_regs[0]; + for_each_inst(i, adev->aid_mask) { + usr_regs = (struct amdgpu_regs_usr_v1_0 *)p; + usr_regs->inst_header.instance = inst++; + usr_regs->inst_header.state = AMDGPU_INST_S_OK; + usr_regs->inst_header.num_smn_regs = num_smn; + reg_data = usr_regs->smn_reg_values; + + for (r = 0; r < arr_size; r++) { + start_addr = reg_addrs[r].start_addr; + incrx = reg_addrs[r].incrx; + num_regs = reg_addrs[r].num_regs; + for (n = 0; n < num_regs; n++) { + aqua_read_smn_ext(adev, reg_data, + start_addr + n * incrx, i); + reg_data++; + } + } + p = reg_data; + } + + usr_reg_state->common_header.structure_size = szbuf; + usr_reg_state->common_header.format_revision = 1; + usr_reg_state->common_header.content_revision = 0; + usr_reg_state->common_header.state_type = AMDGPU_REG_STATE_TYPE_USR; + usr_reg_state->common_header.num_instances = max_usr_instances; + + return usr_reg_state->common_header.structure_size; +} + +ssize_t aqua_vanjaram_get_reg_state(struct amdgpu_device *adev, + enum amdgpu_reg_state reg_state, void *buf, + size_t max_size) +{ + ssize_t size; + + switch (reg_state) { + case AMDGPU_REG_STATE_TYPE_PCIE: + size = aqua_vanjaram_read_pcie_state(adev, buf, max_size); + break; + case AMDGPU_REG_STATE_TYPE_XGMI: + size = aqua_vanjaram_read_xgmi_state(adev, buf, max_size); + break; + case AMDGPU_REG_STATE_TYPE_WAFL: + size = aqua_vanjaram_read_wafl_state(adev, buf, max_size); + break; + case AMDGPU_REG_STATE_TYPE_USR: + size = aqua_vanjaram_read_usr_state(adev, buf, max_size, + AMDGPU_REG_STATE_TYPE_USR); + break; + case AMDGPU_REG_STATE_TYPE_USR_1: + size = aqua_vanjaram_read_usr_state( + adev, buf, max_size, AMDGPU_REG_STATE_TYPE_USR_1); + break; + default: + return -EINVAL; + } + + return size; +} diff --git a/drivers/gpu/drm/amd/amdgpu/athub_v3_0.c b/drivers/gpu/drm/amd/amdgpu/athub_v3_0.c index f0737fb3a999e0..d1bba9c64e16d8 100644 --- a/drivers/gpu/drm/amd/amdgpu/athub_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/athub_v3_0.c @@ -30,6 +30,8 @@ #define regATHUB_MISC_CNTL_V3_0_1 0x00d7 #define regATHUB_MISC_CNTL_V3_0_1_BASE_IDX 0 +#define regATHUB_MISC_CNTL_V3_3_0 0x00d8 +#define regATHUB_MISC_CNTL_V3_3_0_BASE_IDX 0 static uint32_t athub_v3_0_get_cg_cntl(struct amdgpu_device *adev) @@ -40,6 +42,9 @@ static uint32_t athub_v3_0_get_cg_cntl(struct amdgpu_device *adev) case IP_VERSION(3, 0, 1): data = RREG32_SOC15(ATHUB, 0, regATHUB_MISC_CNTL_V3_0_1); break; + case IP_VERSION(3, 3, 0): + data = RREG32_SOC15(ATHUB, 0, regATHUB_MISC_CNTL_V3_3_0); + break; default: data = RREG32_SOC15(ATHUB, 0, regATHUB_MISC_CNTL); break; @@ -53,6 +58,9 @@ static void athub_v3_0_set_cg_cntl(struct amdgpu_device *adev, uint32_t data) case IP_VERSION(3, 0, 1): WREG32_SOC15(ATHUB, 0, regATHUB_MISC_CNTL_V3_0_1, data); break; + case IP_VERSION(3, 3, 0): + WREG32_SOC15(ATHUB, 0, regATHUB_MISC_CNTL_V3_3_0, data); + break; default: WREG32_SOC15(ATHUB, 0, regATHUB_MISC_CNTL, data); break; diff --git a/drivers/gpu/drm/amd/amdgpu/atom.c b/drivers/gpu/drm/amd/amdgpu/atom.c index 2c221000782cdf..a33e890c70d904 100644 --- a/drivers/gpu/drm/amd/amdgpu/atom.c +++ b/drivers/gpu/drm/amd/amdgpu/atom.c @@ -395,7 +395,6 @@ static void atom_skip_src_int(atom_exec_context *ctx, uint8_t attr, int *ptr) (*ptr)++; return; } - return; } } diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c b/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c index 3ee219aa289188..7672abe6c140c0 100644 --- a/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c +++ b/drivers/gpu/drm/amd/amdgpu/atombios_encoders.c @@ -28,6 +28,7 @@ #include +#include #include #include "amdgpu.h" #include "amdgpu_connectors.h" diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c index bb666cb7522e35..587ee632a3b8fd 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c @@ -21,6 +21,7 @@ * */ +#include #include #include #include diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c index 7af277f61ccadc..f22ec27365bd25 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c @@ -21,6 +21,7 @@ * */ +#include #include #include #include diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c index 143efc37a17fe9..4dbe9b3259b50d 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c @@ -23,6 +23,7 @@ #include +#include #include #include #include diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c index adeddfb7ff1273..05bcce23385ec0 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c @@ -21,6 +21,7 @@ * */ +#include #include #include #include diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c index c8a3bf01743f63..ecb622b7f9709c 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c @@ -3996,16 +3996,13 @@ static int gfx_v10_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 = 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 - */ - if (err == -ENODEV) - goto out; + err = request_firmware(&adev->gfx.rlc_fw, fw_name, adev->dev); if (err) - dev_dbg(adev->dev, - "gfx10: amdgpu_ucode_request() failed \"%s\"\n", - fw_name); + goto out; + + /* don't validate this firmware. There are apparently firmwares + * in the wild with incorrect size in the header + */ 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); version_minor = le16_to_cpu(rlc_hdr->header.header_version_minor); @@ -6592,8 +6589,9 @@ static int gfx_v10_0_compute_mqd_init(struct amdgpu_device *adev, void *m, #ifdef __BIG_ENDIAN tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, ENDIAN_SWAP, 1); #endif - tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, UNORD_DISPATCH, 0); - tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, TUNNEL_DISPATCH, 0); + tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, UNORD_DISPATCH, 1); + tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, TUNNEL_DISPATCH, + prop->allow_tunneling); tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, PRIV_STATE, 1); tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, KMD_QUEUE, 1); mqd->cp_hqd_pq_control = tmp; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c index 8ed4a6fb147a2a..d9cf9fd03d3001 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c @@ -67,6 +67,7 @@ MODULE_FIRMWARE("amdgpu/gc_11_0_0_pfp.bin"); MODULE_FIRMWARE("amdgpu/gc_11_0_0_me.bin"); MODULE_FIRMWARE("amdgpu/gc_11_0_0_mec.bin"); MODULE_FIRMWARE("amdgpu/gc_11_0_0_rlc.bin"); +MODULE_FIRMWARE("amdgpu/gc_11_0_0_rlc_1.bin"); MODULE_FIRMWARE("amdgpu/gc_11_0_0_toc.bin"); MODULE_FIRMWARE("amdgpu/gc_11_0_1_pfp.bin"); MODULE_FIRMWARE("amdgpu/gc_11_0_1_me.bin"); @@ -114,7 +115,7 @@ static const struct soc15_reg_golden golden_settings_gc_11_5_0[] = { SOC15_REG_GOLDEN_VALUE(GC, 0, regGL2C_ADDR_MATCH_MASK, 0xffffffff, 0xfffffff3), SOC15_REG_GOLDEN_VALUE(GC, 0, regGL2C_CTRL, 0xffffffff, 0xf37fff3f), SOC15_REG_GOLDEN_VALUE(GC, 0, regGL2C_CTRL3, 0xfffffffb, 0x00f40188), - SOC15_REG_GOLDEN_VALUE(GC, 0, regGL2C_CTRL4, 0xf0ffffff, 0x8000b007), + SOC15_REG_GOLDEN_VALUE(GC, 0, regGL2C_CTRL4, 0xf0ffffff, 0x80009007), SOC15_REG_GOLDEN_VALUE(GC, 0, regPA_CL_ENHANCE, 0xf1ffffff, 0x00880007), SOC15_REG_GOLDEN_VALUE(GC, 0, regPC_CONFIG_CNTL_1, 0xffffffff, 0x00010000), SOC15_REG_GOLDEN_VALUE(GC, 0, regTA_CNTL_AUX, 0xf7f7ffff, 0x01030000), @@ -293,6 +294,9 @@ static void gfx_v11_0_set_kiq_pm4_funcs(struct amdgpu_device *adev) static void gfx_v11_0_init_golden_registers(struct amdgpu_device *adev) { + if (amdgpu_sriov_vf(adev)) + return; + switch (amdgpu_ip_version(adev, GC_HWIP, 0)) { case IP_VERSION(11, 0, 1): case IP_VERSION(11, 0, 4): @@ -564,7 +568,11 @@ 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); + if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(11, 0, 0) && + adev->pdev->revision == 0xCE) + snprintf(fw_name, sizeof(fw_name), "amdgpu/gc_11_0_0_rlc_1.bin"); + else + snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_rlc.bin", ucode_prefix); err = amdgpu_ucode_request(adev, &adev->gfx.rlc_fw, fw_name); if (err) goto out; @@ -3838,8 +3846,9 @@ static int gfx_v11_0_compute_mqd_init(struct amdgpu_device *adev, void *m, (order_base_2(prop->queue_size / 4) - 1)); tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, RPTR_BLOCK_SIZE, (order_base_2(AMDGPU_GPU_PAGE_SIZE / 4) - 1)); - tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, UNORD_DISPATCH, 0); - tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, TUNNEL_DISPATCH, 0); + tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, UNORD_DISPATCH, 1); + tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, TUNNEL_DISPATCH, + prop->allow_tunneling); tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, PRIV_STATE, 1); tmp = REG_SET_FIELD(tmp, CP_HQD_PQ_CONTROL, KMD_QUEUE, 1); mqd->cp_hqd_pq_control = tmp; @@ -4465,11 +4474,43 @@ static int gfx_v11_0_wait_for_idle(void *handle) return -ETIMEDOUT; } +static int gfx_v11_0_request_gfx_index_mutex(struct amdgpu_device *adev, + int req) +{ + u32 i, tmp, val; + + for (i = 0; i < adev->usec_timeout; i++) { + /* Request with MeId=2, PipeId=0 */ + tmp = REG_SET_FIELD(0, CP_GFX_INDEX_MUTEX, REQUEST, req); + tmp = REG_SET_FIELD(tmp, CP_GFX_INDEX_MUTEX, CLIENTID, 4); + WREG32_SOC15(GC, 0, regCP_GFX_INDEX_MUTEX, tmp); + + val = RREG32_SOC15(GC, 0, regCP_GFX_INDEX_MUTEX); + if (req) { + if (val == tmp) + break; + } else { + tmp = REG_SET_FIELD(tmp, CP_GFX_INDEX_MUTEX, + REQUEST, 1); + + /* unlocked or locked by firmware */ + if (val != tmp) + break; + } + udelay(1); + } + + if (i >= adev->usec_timeout) + return -EINVAL; + + return 0; +} + static int gfx_v11_0_soft_reset(void *handle) { u32 grbm_soft_reset = 0; u32 tmp; - int i, j, k; + int r, i, j, k; struct amdgpu_device *adev = (struct amdgpu_device *)handle; tmp = RREG32_SOC15(GC, 0, regCP_INT_CNTL); @@ -4509,6 +4550,13 @@ static int gfx_v11_0_soft_reset(void *handle) } } + /* Try to acquire the gfx mutex before access to CP_VMID_RESET */ + r = gfx_v11_0_request_gfx_index_mutex(adev, 1); + if (r) { + DRM_ERROR("Failed to acquire the gfx mutex during soft reset\n"); + return r; + } + WREG32_SOC15(GC, 0, regCP_VMID_RESET, 0xfffffffe); // Read CP_VMID_RESET register three times. @@ -4517,6 +4565,13 @@ static int gfx_v11_0_soft_reset(void *handle) RREG32_SOC15(GC, 0, regCP_VMID_RESET); RREG32_SOC15(GC, 0, regCP_VMID_RESET); + /* release the gfx mutex */ + r = gfx_v11_0_request_gfx_index_mutex(adev, 0); + if (r) { + DRM_ERROR("Failed to release the gfx mutex during soft reset\n"); + return r; + } + for (i = 0; i < adev->usec_timeout; i++) { if (!RREG32_SOC15(GC, 0, regCP_HQD_ACTIVE) && !RREG32_SOC15(GC, 0, regCP_GFX_HQD_ACTIVE)) @@ -6328,6 +6383,9 @@ static int gfx_v11_0_get_cu_info(struct amdgpu_device *adev, 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++) { + bitmap = i * adev->gfx.config.max_sh_per_se + j; + if (!((gfx_v11_0_get_sa_active_bitmap(adev) >> bitmap) & 1)) + continue; mask = 1; counter = 0; gfx_v11_0_select_se_sh(adev, i, j, 0xffffffff, 0); diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c index 4a09cc0d8ce07f..131cddbdda0dc1 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c @@ -3828,8 +3828,8 @@ static void gfx_v9_4_3_inst_query_ras_err_count(struct amdgpu_device *adev, /* the caller should make sure initialize value of * err_data->ue_count and err_data->ce_count */ - amdgpu_ras_error_statistic_ue_count(err_data, &mcm_info, ue_count); - amdgpu_ras_error_statistic_ce_count(err_data, &mcm_info, ce_count); + amdgpu_ras_error_statistic_ue_count(err_data, &mcm_info, NULL, ue_count); + amdgpu_ras_error_statistic_ce_count(err_data, &mcm_info, NULL, ce_count); } static void gfx_v9_4_3_inst_reset_ras_err_count(struct amdgpu_device *adev, @@ -3882,150 +3882,6 @@ static void gfx_v9_4_3_inst_reset_ras_err_count(struct amdgpu_device *adev, mutex_unlock(&adev->grbm_idx_mutex); } -static void gfx_v9_4_3_inst_query_utc_err_status(struct amdgpu_device *adev, - int xcc_id) -{ - uint32_t data; - - data = RREG32_SOC15(GC, GET_INST(GC, xcc_id), regUTCL2_MEM_ECC_STATUS); - if (data) { - dev_warn(adev->dev, "GFX UTCL2 Mem Ecc Status: 0x%x!\n", data); - WREG32_SOC15(GC, GET_INST(GC, xcc_id), regUTCL2_MEM_ECC_STATUS, 0x3); - } - - data = RREG32_SOC15(GC, GET_INST(GC, xcc_id), regVML2_MEM_ECC_STATUS); - if (data) { - dev_warn(adev->dev, "GFX VML2 Mem Ecc Status: 0x%x!\n", data); - WREG32_SOC15(GC, GET_INST(GC, xcc_id), regVML2_MEM_ECC_STATUS, 0x3); - } - - data = RREG32_SOC15(GC, GET_INST(GC, xcc_id), - regVML2_WALKER_MEM_ECC_STATUS); - if (data) { - dev_warn(adev->dev, "GFX VML2 Walker Mem Ecc Status: 0x%x!\n", data); - WREG32_SOC15(GC, GET_INST(GC, xcc_id), regVML2_WALKER_MEM_ECC_STATUS, - 0x3); - } -} - -static void gfx_v9_4_3_log_cu_timeout_status(struct amdgpu_device *adev, - uint32_t status, int xcc_id) -{ - struct amdgpu_cu_info *cu_info = &adev->gfx.cu_info; - uint32_t i, simd, wave; - uint32_t wave_status; - uint32_t wave_pc_lo, wave_pc_hi; - uint32_t wave_exec_lo, wave_exec_hi; - uint32_t wave_inst_dw0, wave_inst_dw1; - uint32_t wave_ib_sts; - - for (i = 0; i < 32; i++) { - if (!((i << 1) & status)) - continue; - - simd = i / cu_info->max_waves_per_simd; - wave = i % cu_info->max_waves_per_simd; - - wave_status = wave_read_ind(adev, xcc_id, simd, wave, ixSQ_WAVE_STATUS); - wave_pc_lo = wave_read_ind(adev, xcc_id, simd, wave, ixSQ_WAVE_PC_LO); - wave_pc_hi = wave_read_ind(adev, xcc_id, simd, wave, ixSQ_WAVE_PC_HI); - wave_exec_lo = - wave_read_ind(adev, xcc_id, simd, wave, ixSQ_WAVE_EXEC_LO); - wave_exec_hi = - wave_read_ind(adev, xcc_id, simd, wave, ixSQ_WAVE_EXEC_HI); - wave_inst_dw0 = - wave_read_ind(adev, xcc_id, simd, wave, ixSQ_WAVE_INST_DW0); - wave_inst_dw1 = - wave_read_ind(adev, xcc_id, simd, wave, ixSQ_WAVE_INST_DW1); - wave_ib_sts = wave_read_ind(adev, xcc_id, simd, wave, ixSQ_WAVE_IB_STS); - - dev_info( - adev->dev, - "\t SIMD %d, Wave %d: status 0x%x, pc 0x%llx, exec 0x%llx, inst 0x%llx, ib_sts 0x%x\n", - simd, wave, wave_status, - ((uint64_t)wave_pc_hi << 32 | wave_pc_lo), - ((uint64_t)wave_exec_hi << 32 | wave_exec_lo), - ((uint64_t)wave_inst_dw1 << 32 | wave_inst_dw0), - wave_ib_sts); - } -} - -static void gfx_v9_4_3_inst_query_sq_timeout_status(struct amdgpu_device *adev, - int xcc_id) -{ - uint32_t se_idx, sh_idx, cu_idx; - uint32_t status; - - mutex_lock(&adev->grbm_idx_mutex); - for (se_idx = 0; se_idx < adev->gfx.config.max_shader_engines; se_idx++) { - for (sh_idx = 0; sh_idx < adev->gfx.config.max_sh_per_se; sh_idx++) { - for (cu_idx = 0; cu_idx < adev->gfx.config.max_cu_per_sh; cu_idx++) { - gfx_v9_4_3_xcc_select_se_sh(adev, se_idx, sh_idx, - cu_idx, xcc_id); - status = RREG32_SOC15(GC, GET_INST(GC, xcc_id), - regSQ_TIMEOUT_STATUS); - if (status != 0) { - dev_info( - adev->dev, - "GFX Watchdog Timeout: SE %d, SH %d, CU %d\n", - se_idx, sh_idx, cu_idx); - gfx_v9_4_3_log_cu_timeout_status( - adev, status, xcc_id); - } - /* clear old status */ - WREG32_SOC15(GC, GET_INST(GC, xcc_id), - regSQ_TIMEOUT_STATUS, 0); - } - } - } - gfx_v9_4_3_xcc_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff, - xcc_id); - mutex_unlock(&adev->grbm_idx_mutex); -} - -static void gfx_v9_4_3_inst_query_ras_err_status(struct amdgpu_device *adev, - void *ras_error_status, int xcc_id) -{ - gfx_v9_4_3_inst_query_utc_err_status(adev, xcc_id); - gfx_v9_4_3_inst_query_sq_timeout_status(adev, xcc_id); -} - -static void gfx_v9_4_3_inst_reset_utc_err_status(struct amdgpu_device *adev, - int xcc_id) -{ - WREG32_SOC15(GC, GET_INST(GC, xcc_id), regUTCL2_MEM_ECC_STATUS, 0x3); - WREG32_SOC15(GC, GET_INST(GC, xcc_id), regVML2_MEM_ECC_STATUS, 0x3); - WREG32_SOC15(GC, GET_INST(GC, xcc_id), regVML2_WALKER_MEM_ECC_STATUS, 0x3); -} - -static void gfx_v9_4_3_inst_reset_sq_timeout_status(struct amdgpu_device *adev, - int xcc_id) -{ - uint32_t se_idx, sh_idx, cu_idx; - - mutex_lock(&adev->grbm_idx_mutex); - for (se_idx = 0; se_idx < adev->gfx.config.max_shader_engines; se_idx++) { - for (sh_idx = 0; sh_idx < adev->gfx.config.max_sh_per_se; sh_idx++) { - for (cu_idx = 0; cu_idx < adev->gfx.config.max_cu_per_sh; cu_idx++) { - gfx_v9_4_3_xcc_select_se_sh(adev, se_idx, sh_idx, - cu_idx, xcc_id); - WREG32_SOC15(GC, GET_INST(GC, xcc_id), - regSQ_TIMEOUT_STATUS, 0); - } - } - } - gfx_v9_4_3_xcc_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff, - xcc_id); - mutex_unlock(&adev->grbm_idx_mutex); -} - -static void gfx_v9_4_3_inst_reset_ras_err_status(struct amdgpu_device *adev, - void *ras_error_status, int xcc_id) -{ - gfx_v9_4_3_inst_reset_utc_err_status(adev, xcc_id); - gfx_v9_4_3_inst_reset_sq_timeout_status(adev, xcc_id); -} - static void gfx_v9_4_3_inst_enable_watchdog_timer(struct amdgpu_device *adev, void *ras_error_status, int xcc_id) { @@ -4067,16 +3923,6 @@ static void gfx_v9_4_3_reset_ras_error_count(struct amdgpu_device *adev) amdgpu_gfx_ras_error_func(adev, NULL, gfx_v9_4_3_inst_reset_ras_err_count); } -static void gfx_v9_4_3_query_ras_error_status(struct amdgpu_device *adev) -{ - amdgpu_gfx_ras_error_func(adev, NULL, gfx_v9_4_3_inst_query_ras_err_status); -} - -static void gfx_v9_4_3_reset_ras_error_status(struct amdgpu_device *adev) -{ - amdgpu_gfx_ras_error_func(adev, NULL, gfx_v9_4_3_inst_reset_ras_err_status); -} - static void gfx_v9_4_3_enable_watchdog_timer(struct amdgpu_device *adev) { amdgpu_gfx_ras_error_func(adev, NULL, gfx_v9_4_3_inst_enable_watchdog_timer); @@ -4394,8 +4240,6 @@ struct amdgpu_xcp_ip_funcs gfx_v9_4_3_xcp_funcs = { struct amdgpu_ras_block_hw_ops gfx_v9_4_3_ras_ops = { .query_ras_error_count = &gfx_v9_4_3_query_ras_error_count, .reset_ras_error_count = &gfx_v9_4_3_reset_ras_error_count, - .query_ras_error_status = &gfx_v9_4_3_query_ras_error_status, - .reset_ras_error_status = &gfx_v9_4_3_reset_ras_error_status, }; struct amdgpu_gfx_ras gfx_v9_4_3_ras = { diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c index 53a2ba5fcf4ba3..22175da0e16afe 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_0.c @@ -102,7 +102,9 @@ static void gfxhub_v1_0_init_system_aperture_regs(struct amdgpu_device *adev) WREG32_SOC15_RLC(GC, 0, mmMC_VM_SYSTEM_APERTURE_LOW_ADDR, min(adev->gmc.fb_start, adev->gmc.agp_start) >> 18); - if (adev->apu_flags & AMD_APU_IS_RAVEN2) + if (adev->apu_flags & (AMD_APU_IS_RAVEN2 | + AMD_APU_IS_RENOIR | + AMD_APU_IS_GREEN_SARDINE)) /* * Raven2 has a HW issue that it is unable to use the * vram which is out of MC_VM_SYSTEM_APERTURE_HIGH_ADDR. diff --git a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_2.c b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_2.c index 55423ff1bb4926..49aecdcee00695 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_2.c +++ b/drivers/gpu/drm/amd/amdgpu/gfxhub_v1_2.c @@ -139,7 +139,9 @@ gfxhub_v1_2_xcc_init_system_aperture_regs(struct amdgpu_device *adev, WREG32_SOC15_RLC(GC, GET_INST(GC, i), regMC_VM_SYSTEM_APERTURE_LOW_ADDR, min(adev->gmc.fb_start, adev->gmc.agp_start) >> 18); - if (adev->apu_flags & AMD_APU_IS_RAVEN2) + if (adev->apu_flags & (AMD_APU_IS_RAVEN2 | + AMD_APU_IS_RENOIR | + AMD_APU_IS_GREEN_SARDINE)) /* * Raven2 has a HW issue that it is unable to use the * vram which is out of MC_VM_SYSTEM_APERTURE_HIGH_ADDR. @@ -454,10 +456,12 @@ static void gfxhub_v1_2_xcc_gart_disable(struct amdgpu_device *adev, WREG32_SOC15_RLC(GC, GET_INST(GC, j), regMC_VM_MX_L1_TLB_CNTL, tmp); /* Setup L2 cache */ - tmp = RREG32_SOC15(GC, GET_INST(GC, j), regVM_L2_CNTL); - tmp = REG_SET_FIELD(tmp, VM_L2_CNTL, ENABLE_L2_CACHE, 0); - WREG32_SOC15(GC, GET_INST(GC, j), regVM_L2_CNTL, tmp); - WREG32_SOC15(GC, GET_INST(GC, j), regVM_L2_CNTL3, 0); + if (!amdgpu_sriov_vf(adev)) { + tmp = RREG32_SOC15(GC, GET_INST(GC, j), regVM_L2_CNTL); + tmp = REG_SET_FIELD(tmp, VM_L2_CNTL, ENABLE_L2_CACHE, 0); + WREG32_SOC15(GC, GET_INST(GC, j), regVM_L2_CNTL, tmp); + WREG32_SOC15(GC, GET_INST(GC, j), regVM_L2_CNTL3, 0); + } } } diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c index a5a05c16c10d7b..6c51856088546f 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c @@ -1041,6 +1041,10 @@ static int gmc_v10_0_hw_fini(void *handle) amdgpu_irq_put(adev, &adev->gmc.vm_fault, 0); + if (adev->gmc.ecc_irq.funcs && + amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__UMC)) + amdgpu_irq_put(adev, &adev->gmc.ecc_irq, 0); + return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c index 23d7b548d13f44..c9c653cfc765b8 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c @@ -941,6 +941,11 @@ static int gmc_v11_0_hw_fini(void *handle) } amdgpu_irq_put(adev, &adev->gmc.vm_fault, 0); + + if (adev->gmc.ecc_irq.funcs && + amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__UMC)) + amdgpu_irq_put(adev, &adev->gmc.ecc_irq, 0); + gmc_v11_0_gart_disable(adev); 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 2ac5820e9c9241..17b7a25121b00e 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -883,7 +883,7 @@ static void gmc_v9_0_flush_gpu_tlb(struct amdgpu_device *adev, uint32_t vmid, * GRBM interface. */ if ((vmhub == AMDGPU_GFXHUB(0)) && - (adev->ip_versions[GC_HWIP][0] < IP_VERSION(9, 4, 2))) + (amdgpu_ip_version(adev, GC_HWIP, 0) < IP_VERSION(9, 4, 2))) RREG32_NO_KIQ(req); for (j = 0; j < adev->usec_timeout; j++) { @@ -1950,7 +1950,8 @@ static void gmc_v9_4_3_init_vram_info(struct amdgpu_device *adev) static const u32 regBIF_BIOS_SCRATCH_4 = 0x50; u32 vram_info; - if (!amdgpu_sriov_vf(adev)) { + /* Only for dGPU, vendor informaton is reliable */ + if (!amdgpu_sriov_vf(adev) && !(adev->flags & AMD_IS_APU)) { vram_info = RREG32(regBIF_BIOS_SCRATCH_4); adev->gmc.vram_vendor = vram_info & 0xF; } @@ -2380,6 +2381,10 @@ static int gmc_v9_0_hw_fini(void *handle) amdgpu_irq_put(adev, &adev->gmc.vm_fault, 0); + if (adev->gmc.ecc_irq.funcs && + amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__UMC)) + amdgpu_irq_put(adev, &adev->gmc.ecc_irq, 0); + return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c index 4dfec56e1b7fc3..26d71a22395d29 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c @@ -408,6 +408,8 @@ static int mes_v11_0_set_hw_resources(struct amdgpu_mes *mes) mes_set_hw_res_pkt.enable_reg_active_poll = 1; mes_set_hw_res_pkt.enable_level_process_quantum_check = 1; mes_set_hw_res_pkt.oversubscription_timer = 50; + mes_set_hw_res_pkt.enable_mes_event_int_logging = 1; + mes_set_hw_res_pkt.event_intr_history_gpu_mc_ptr = mes->event_log_gpu_addr; return mes_v11_0_submit_pkt_and_poll_completion(mes, &mes_set_hw_res_pkt, sizeof(mes_set_hw_res_pkt), diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c index 843219a9173609..e3ddd22aa1728e 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_0.c @@ -96,7 +96,9 @@ static void mmhub_v1_0_init_system_aperture_regs(struct amdgpu_device *adev) WREG32_SOC15(MMHUB, 0, mmMC_VM_SYSTEM_APERTURE_LOW_ADDR, min(adev->gmc.fb_start, adev->gmc.agp_start) >> 18); - if (adev->apu_flags & AMD_APU_IS_RAVEN2) + if (adev->apu_flags & (AMD_APU_IS_RAVEN2 | + AMD_APU_IS_RENOIR | + AMD_APU_IS_GREEN_SARDINE)) /* * Raven2 has a HW issue that it is unable to use the vram which * is out of MC_VM_SYSTEM_APERTURE_HIGH_ADDR. So here is the diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c index 9b0146732e13ce..fb53aacdcba20f 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c @@ -652,8 +652,8 @@ static void mmhub_v1_8_inst_query_ras_error_count(struct amdgpu_device *adev, AMDGPU_RAS_ERROR__MULTI_UNCORRECTABLE, &ue_count); - amdgpu_ras_error_statistic_ce_count(err_data, &mcm_info, ce_count); - amdgpu_ras_error_statistic_ue_count(err_data, &mcm_info, ue_count); + amdgpu_ras_error_statistic_ce_count(err_data, &mcm_info, NULL, ce_count); + amdgpu_ras_error_statistic_ue_count(err_data, &mcm_info, NULL, ue_count); } static void mmhub_v1_8_query_ras_error_count(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c b/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c index 6d24c84924cb5d..19986ff6a48d7e 100644 --- a/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c +++ b/drivers/gpu/drm/amd/amdgpu/nbio_v7_4.c @@ -401,8 +401,7 @@ static void nbio_v7_4_handle_ras_controller_intr_no_bifring(struct amdgpu_device if (err_data.ce_count) dev_info(adev->dev, "%ld correctable hardware " - "errors detected in %s block, " - "no user action is needed.\n", + "errors detected in %s block\n", obj->err_data.ce_count, get_ras_block_str(adev->nbio.ras_if)); diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c b/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c index 25a3da83e0fb97..e90f3378080345 100644 --- a/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c +++ b/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c @@ -597,8 +597,7 @@ static void nbio_v7_9_handle_ras_controller_intr_no_bifring(struct amdgpu_device if (err_data.ce_count) dev_info(adev->dev, "%ld correctable hardware " - "errors detected in %s block, " - "no user action is needed.\n", + "errors detected in %s block\n", obj->err_data.ce_count, get_ras_block_str(adev->nbio.ras_if)); diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c index 0f24af6f28102b..2d688dca26bedb 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c @@ -2156,7 +2156,7 @@ static void sdma_v4_4_2_inst_query_ras_error_count(struct amdgpu_device *adev, AMDGPU_RAS_ERROR__MULTI_UNCORRECTABLE, &ue_count); - amdgpu_ras_error_statistic_ue_count(err_data, &mcm_info, ue_count); + amdgpu_ras_error_statistic_ue_count(err_data, &mcm_info, NULL, ue_count); } static void sdma_v4_4_2_query_ras_error_count(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c index 51342809af0347..15033efec2bac0 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc15.c +++ b/drivers/gpu/drm/amd/amdgpu/soc15.c @@ -902,6 +902,7 @@ static const struct amdgpu_asic_funcs aqua_vanjaram_asic_funcs = .pre_asic_init = &soc15_pre_asic_init, .query_video_codecs = &soc15_query_video_codecs, .encode_ext_smn_addressing = &aqua_vanjaram_encode_ext_smn_addressing, + .get_reg_state = &aqua_vanjaram_get_reg_state, }; static int soc15_common_early_init(void *handle) diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.h b/drivers/gpu/drm/amd/amdgpu/soc15.h index eac54042c6c0e4..1444b7765e4bea 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc15.h +++ b/drivers/gpu/drm/amd/amdgpu/soc15.h @@ -27,6 +27,7 @@ #include "nbio_v6_1.h" #include "nbio_v7_0.h" #include "nbio_v7_4.h" +#include "amdgpu_reg_state.h" extern const struct amdgpu_ip_block_version vega10_common_ip_block; @@ -114,6 +115,9 @@ int aldebaran_reg_base_init(struct amdgpu_device *adev); void aqua_vanjaram_ip_map_init(struct amdgpu_device *adev); u64 aqua_vanjaram_encode_ext_smn_addressing(int ext_id); int aqua_vanjaram_init_soc_config(struct amdgpu_device *adev); +ssize_t aqua_vanjaram_get_reg_state(struct amdgpu_device *adev, + enum amdgpu_reg_state reg_state, void *buf, + size_t max_size); void vega10_doorbell_index_init(struct amdgpu_device *adev); void vega20_doorbell_index_init(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/umc_v12_0.c b/drivers/gpu/drm/amd/amdgpu/umc_v12_0.c index e9c2ff74f0bc1d..7458a218e89db1 100644 --- a/drivers/gpu/drm/amd/amdgpu/umc_v12_0.c +++ b/drivers/gpu/drm/amd/amdgpu/umc_v12_0.c @@ -26,6 +26,7 @@ #include "amdgpu.h" #include "umc/umc_12_0_0_offset.h" #include "umc/umc_12_0_0_sh_mask.h" +#include "mp/mp_13_0_6_sh_mask.h" const uint32_t umc_v12_0_channel_idx_tbl[] @@ -88,16 +89,26 @@ static void umc_v12_0_reset_error_count(struct amdgpu_device *adev) umc_v12_0_reset_error_count_per_channel, NULL); } -bool umc_v12_0_is_uncorrectable_error(uint64_t mc_umc_status) +bool umc_v12_0_is_uncorrectable_error(struct amdgpu_device *adev, uint64_t mc_umc_status) { + if (amdgpu_ras_is_poison_mode_supported(adev) && + (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)) + return true; + return ((REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, Val) == 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)); } -bool umc_v12_0_is_correctable_error(uint64_t mc_umc_status) +bool umc_v12_0_is_correctable_error(struct amdgpu_device *adev, uint64_t mc_umc_status) { + if (amdgpu_ras_is_poison_mode_supported(adev) && + (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)) + return false; + return (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 || (REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, UECC) == 1 && @@ -105,7 +116,7 @@ bool umc_v12_0_is_correctable_error(uint64_t mc_umc_status) /* Identify data parity error in replay mode */ ((REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, ErrorCodeExt) == 0x5 || REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, ErrorCodeExt) == 0xb) && - !(umc_v12_0_is_uncorrectable_error(mc_umc_status))))); + !(umc_v12_0_is_uncorrectable_error(adev, mc_umc_status))))); } static void umc_v12_0_query_correctable_error_count(struct amdgpu_device *adev, @@ -124,7 +135,7 @@ static void umc_v12_0_query_correctable_error_count(struct amdgpu_device *adev, mc_umc_status = RREG64_PCIE_EXT((mc_umc_status_addr + umc_reg_offset) * 4); - if (umc_v12_0_is_correctable_error(mc_umc_status)) + if (umc_v12_0_is_correctable_error(adev, mc_umc_status)) *error_count += 1; } @@ -142,7 +153,7 @@ static void umc_v12_0_query_uncorrectable_error_count(struct amdgpu_device *adev mc_umc_status = RREG64_PCIE_EXT((mc_umc_status_addr + umc_reg_offset) * 4); - if (umc_v12_0_is_uncorrectable_error(mc_umc_status)) + if (umc_v12_0_is_uncorrectable_error(adev, mc_umc_status)) *error_count += 1; } @@ -166,8 +177,8 @@ static int umc_v12_0_query_error_count(struct amdgpu_device *adev, umc_v12_0_query_correctable_error_count(adev, umc_reg_offset, &ce_count); umc_v12_0_query_uncorrectable_error_count(adev, umc_reg_offset, &ue_count); - amdgpu_ras_error_statistic_ue_count(err_data, &mcm_info, ue_count); - amdgpu_ras_error_statistic_ce_count(err_data, &mcm_info, ce_count); + amdgpu_ras_error_statistic_ue_count(err_data, &mcm_info, NULL, ue_count); + amdgpu_ras_error_statistic_ce_count(err_data, &mcm_info, NULL, ce_count); return 0; } @@ -360,6 +371,59 @@ static int umc_v12_0_err_cnt_init_per_channel(struct amdgpu_device *adev, return 0; } +static void umc_v12_0_ecc_info_query_ras_error_count(struct amdgpu_device *adev, + void *ras_error_status) +{ + amdgpu_mca_smu_log_ras_error(adev, + AMDGPU_RAS_BLOCK__UMC, AMDGPU_MCA_ERROR_TYPE_CE, ras_error_status); + amdgpu_mca_smu_log_ras_error(adev, + AMDGPU_RAS_BLOCK__UMC, AMDGPU_MCA_ERROR_TYPE_UE, ras_error_status); +} + +static void umc_v12_0_ecc_info_query_ras_error_address(struct amdgpu_device *adev, + void *ras_error_status) +{ + struct ras_err_node *err_node; + uint64_t mc_umc_status; + struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status; + + for_each_ras_error(err_node, err_data) { + mc_umc_status = err_node->err_info.err_addr.err_status; + if (!mc_umc_status) + continue; + + if (umc_v12_0_is_uncorrectable_error(adev, mc_umc_status)) { + uint64_t mca_addr, err_addr, mca_ipid; + uint32_t InstanceIdLo; + struct amdgpu_smuio_mcm_config_info *mcm_info; + + mcm_info = &err_node->err_info.mcm_info; + mca_addr = err_node->err_info.err_addr.err_addr; + mca_ipid = err_node->err_info.err_addr.err_ipid; + + err_addr = REG_GET_FIELD(mca_addr, MCA_UMC_UMC0_MCUMC_ADDRT0, ErrorAddr); + InstanceIdLo = REG_GET_FIELD(mca_ipid, MCMP1_IPIDT0, InstanceIdLo); + + dev_info(adev->dev, "UMC:IPID:0x%llx, aid:%d, inst:%d, ch:%d, err_addr:0x%llx\n", + mca_ipid, + mcm_info->die_id, + MCA_IPID_LO_2_UMC_INST(InstanceIdLo), + MCA_IPID_LO_2_UMC_CH(InstanceIdLo), + err_addr); + + umc_v12_0_convert_error_address(adev, + err_data, err_addr, + MCA_IPID_LO_2_UMC_CH(InstanceIdLo), + MCA_IPID_LO_2_UMC_INST(InstanceIdLo), + mcm_info->die_id); + + /* Clear umc error address content */ + memset(&err_node->err_info.err_addr, + 0, sizeof(err_node->err_info.err_addr)); + } + } +} + static void umc_v12_0_err_cnt_init(struct amdgpu_device *adev) { amdgpu_umc_loop_channels(adev, @@ -386,4 +450,6 @@ struct amdgpu_umc_ras umc_v12_0_ras = { }, .err_cnt_init = umc_v12_0_err_cnt_init, .query_ras_poison_mode = umc_v12_0_query_ras_poison_mode, + .ecc_info_query_ras_error_count = umc_v12_0_ecc_info_query_ras_error_count, + .ecc_info_query_ras_error_address = umc_v12_0_ecc_info_query_ras_error_address, }; diff --git a/drivers/gpu/drm/amd/amdgpu/umc_v12_0.h b/drivers/gpu/drm/amd/amdgpu/umc_v12_0.h index b34b1e358f8b82..e8de3a92251a2c 100644 --- a/drivers/gpu/drm/amd/amdgpu/umc_v12_0.h +++ b/drivers/gpu/drm/amd/amdgpu/umc_v12_0.h @@ -117,8 +117,12 @@ (pa) |= (UMC_V12_0_CHANNEL_HASH_CH6(channel_idx, pa) << UMC_V12_0_PA_CH6_BIT); \ } while (0) -bool umc_v12_0_is_uncorrectable_error(uint64_t mc_umc_status); -bool umc_v12_0_is_correctable_error(uint64_t mc_umc_status); +#define MCA_IPID_LO_2_UMC_CH(_ipid_lo) (((((_ipid_lo) >> 20) & 0x1) * 4) + \ + (((_ipid_lo) >> 12) & 0xF)) +#define MCA_IPID_LO_2_UMC_INST(_ipid_lo) (((_ipid_lo) >> 21) & 0x7) + +bool umc_v12_0_is_uncorrectable_error(struct amdgpu_device *adev, uint64_t mc_umc_status); +bool umc_v12_0_is_correctable_error(struct amdgpu_device *adev, uint64_t mc_umc_status); extern const uint32_t umc_v12_0_channel_idx_tbl[] diff --git a/drivers/gpu/drm/amd/amdgpu/umc_v6_7.c b/drivers/gpu/drm/amd/amdgpu/umc_v6_7.c index 530549314ce46c..a3ee3c4c650feb 100644 --- a/drivers/gpu/drm/amd/amdgpu/umc_v6_7.c +++ b/drivers/gpu/drm/amd/amdgpu/umc_v6_7.c @@ -64,7 +64,7 @@ static void umc_v6_7_query_error_status_helper(struct amdgpu_device *adev, uint64_t reg_value; if (REG_GET_FIELD(mc_umc_status, MCA_UMC_UMC0_MCUMC_STATUST0, Deferred) == 1) - dev_info(adev->dev, "Deferred error, no user action is needed.\n"); + dev_info(adev->dev, "Deferred error\n"); if (mc_umc_status) dev_info(adev->dev, "MCA STATUS 0x%llx, umc_reg_offset 0x%x\n", mc_umc_status, umc_reg_offset); diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c index 48bfcd0d558b73..169ed400ee7b74 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c @@ -100,6 +100,31 @@ static int vcn_v4_0_early_init(void *handle) return amdgpu_vcn_early_init(adev); } +static int vcn_v4_0_fw_shared_init(struct amdgpu_device *adev, int inst_idx) +{ + volatile struct amdgpu_vcn4_fw_shared *fw_shared; + + fw_shared = adev->vcn.inst[inst_idx].fw_shared.cpu_addr; + fw_shared->present_flag_0 = cpu_to_le32(AMDGPU_FW_SHARED_FLAG_0_UNIFIED_QUEUE); + fw_shared->sq.is_enabled = 1; + + fw_shared->present_flag_0 |= cpu_to_le32(AMDGPU_VCN_SMU_DPM_INTERFACE_FLAG); + fw_shared->smu_dpm_interface.smu_interface_type = (adev->flags & AMD_IS_APU) ? + AMDGPU_VCN_SMU_DPM_INTERFACE_APU : AMDGPU_VCN_SMU_DPM_INTERFACE_DGPU; + + if (amdgpu_ip_version(adev, VCN_HWIP, 0) == + IP_VERSION(4, 0, 2)) { + fw_shared->present_flag_0 |= AMDGPU_FW_SHARED_FLAG_0_DRM_KEY_INJECT; + fw_shared->drm_key_wa.method = + AMDGPU_DRM_KEY_INJECT_WORKAROUND_VCNFW_ASD_HANDSHAKING; + } + + if (amdgpu_vcnfw_log) + amdgpu_vcn_fwlog_init(&adev->vcn.inst[inst_idx]); + + return 0; +} + /** * vcn_v4_0_sw_init - sw init for VCN block * @@ -124,8 +149,6 @@ static int vcn_v4_0_sw_init(void *handle) return r; for (i = 0; i < adev->vcn.num_vcn_inst; i++) { - volatile struct amdgpu_vcn4_fw_shared *fw_shared; - if (adev->vcn.harvest_config & (1 << i)) continue; @@ -161,23 +184,7 @@ static int vcn_v4_0_sw_init(void *handle) if (r) return r; - fw_shared = adev->vcn.inst[i].fw_shared.cpu_addr; - fw_shared->present_flag_0 = cpu_to_le32(AMDGPU_FW_SHARED_FLAG_0_UNIFIED_QUEUE); - fw_shared->sq.is_enabled = 1; - - fw_shared->present_flag_0 |= cpu_to_le32(AMDGPU_VCN_SMU_DPM_INTERFACE_FLAG); - fw_shared->smu_dpm_interface.smu_interface_type = (adev->flags & AMD_IS_APU) ? - AMDGPU_VCN_SMU_DPM_INTERFACE_APU : AMDGPU_VCN_SMU_DPM_INTERFACE_DGPU; - - if (amdgpu_ip_version(adev, VCN_HWIP, 0) == - IP_VERSION(4, 0, 2)) { - fw_shared->present_flag_0 |= AMDGPU_FW_SHARED_FLAG_0_DRM_KEY_INJECT; - fw_shared->drm_key_wa.method = - AMDGPU_DRM_KEY_INJECT_WORKAROUND_VCNFW_ASD_HANDSHAKING; - } - - if (amdgpu_vcnfw_log) - amdgpu_vcn_fwlog_init(&adev->vcn.inst[i]); + vcn_v4_0_fw_shared_init(adev, i); } if (amdgpu_sriov_vf(adev)) { @@ -1273,6 +1280,9 @@ static int vcn_v4_0_start_sriov(struct amdgpu_device *adev) if (adev->vcn.harvest_config & (1 << i)) continue; + // Must re/init fw_shared at beginning + vcn_v4_0_fw_shared_init(adev, i); + table_size = 0; MMSCH_V4_0_INSERT_DIRECT_RD_MOD_WT(SOC15_REG_OFFSET(VCN, i, diff --git a/drivers/gpu/drm/amd/amdgpu/vpe_v6_1.c b/drivers/gpu/drm/amd/amdgpu/vpe_v6_1.c index 174f13eff57549..d20060a51e0525 100644 --- a/drivers/gpu/drm/amd/amdgpu/vpe_v6_1.c +++ b/drivers/gpu/drm/amd/amdgpu/vpe_v6_1.c @@ -96,6 +96,10 @@ static int vpe_v6_1_load_microcode(struct amdgpu_vpe *vpe) adev->vpe.cmdbuf_cpu_addr[1] = f32_cntl; amdgpu_vpe_psp_update_sram(adev); + + /* Config DPM */ + amdgpu_vpe_configure_dpm(vpe); + return 0; } @@ -128,6 +132,8 @@ static int vpe_v6_1_load_microcode(struct amdgpu_vpe *vpe) } vpe_v6_1_halt(vpe, false); + /* Config DPM */ + amdgpu_vpe_configure_dpm(vpe); return 0; } @@ -264,6 +270,15 @@ static int vpe_v6_1_set_regs(struct amdgpu_vpe *vpe) vpe->regs.queue0_rb_wptr_hi = regVPEC_QUEUE0_RB_WPTR_HI; vpe->regs.queue0_preempt = regVPEC_QUEUE0_PREEMPT; + vpe->regs.dpm_enable = regVPEC_PUB_DUMMY2; + vpe->regs.dpm_pratio = regVPEC_QUEUE6_DUMMY4; + vpe->regs.dpm_request_interval = regVPEC_QUEUE5_DUMMY3; + vpe->regs.dpm_decision_threshold = regVPEC_QUEUE5_DUMMY4; + vpe->regs.dpm_busy_clamp_threshold = regVPEC_QUEUE7_DUMMY2; + vpe->regs.dpm_idle_clamp_threshold = regVPEC_QUEUE7_DUMMY3; + vpe->regs.dpm_request_lv = regVPEC_QUEUE7_DUMMY1; + vpe->regs.context_indicator = regVPEC_QUEUE6_DUMMY3; + return 0; } diff --git a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h index d7cd5fa313ff88..df75863393fcb8 100644 --- a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h +++ b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler.h @@ -2069,7 +2069,7 @@ static const uint32_t cwsr_trap_aldebaran_hex[] = { }; static const uint32_t cwsr_trap_gfx10_hex[] = { - 0xbf820001, 0xbf820220, + 0xbf820001, 0xbf820221, 0xb0804004, 0xb978f802, 0x8a78ff78, 0x00020006, 0xb97bf803, 0x876eff78, @@ -2118,391 +2118,391 @@ static const uint32_t cwsr_trap_gfx10_hex[] = { 0xbf900004, 0xbf8cc07f, 0x877aff7f, 0x04000000, 0x8f7a857a, 0x886d7a6d, - 0xbefa037e, 0x877bff7f, - 0x0000ffff, 0xbefe03c1, - 0xbeff03c1, 0xdc5f8000, - 0x007a0000, 0x7e000280, - 0xbefe037a, 0xbeff037b, - 0xb97b02dc, 0x8f7b997b, - 0xb97a3a05, 0x807a817a, - 0xbf0d997b, 0xbf850002, - 0x8f7a897a, 0xbf820001, - 0x8f7a8a7a, 0xb97b1e06, - 0x8f7b8a7b, 0x807a7b7a, + 0x7e008200, 0xbefa037e, 0x877bff7f, 0x0000ffff, - 0x807aff7a, 0x00000200, - 0x807a7e7a, 0x827b807b, - 0xd7610000, 0x00010870, - 0xd7610000, 0x00010a71, - 0xd7610000, 0x00010c72, - 0xd7610000, 0x00010e73, - 0xd7610000, 0x00011074, - 0xd7610000, 0x00011275, - 0xd7610000, 0x00011476, - 0xd7610000, 0x00011677, - 0xd7610000, 0x00011a79, - 0xd7610000, 0x00011c7e, - 0xd7610000, 0x00011e7f, - 0xbefe03ff, 0x00003fff, - 0xbeff0380, 0xdc5f8040, - 0x007a0000, 0xd760007a, - 0x00011d00, 0xd760007b, - 0x00011f00, 0xbefe037a, - 0xbeff037b, 0xbef4037e, - 0x8775ff7f, 0x0000ffff, - 0x8875ff75, 0x00040000, - 0xbef60380, 0xbef703ff, - 0x10807fac, 0xbef1037c, - 0xbef00380, 0xb97302dc, - 0x8f739973, 0xbefe03c1, - 0x907c9973, 0x877c817c, - 0xbf06817c, 0xbf850002, - 0xbeff0380, 0xbf820002, - 0xbeff03c1, 0xbf820009, + 0xbefe03c1, 0xbeff03c1, + 0xdc5f8000, 0x007a0000, + 0x7e000280, 0xbefe037a, + 0xbeff037b, 0xb97b02dc, + 0x8f7b997b, 0xb97a3a05, + 0x807a817a, 0xbf0d997b, + 0xbf850002, 0x8f7a897a, + 0xbf820001, 0x8f7a8a7a, + 0xb97b1e06, 0x8f7b8a7b, + 0x807a7b7a, 0x877bff7f, + 0x0000ffff, 0x807aff7a, + 0x00000200, 0x807a7e7a, + 0x827b807b, 0xd7610000, + 0x00010870, 0xd7610000, + 0x00010a71, 0xd7610000, + 0x00010c72, 0xd7610000, + 0x00010e73, 0xd7610000, + 0x00011074, 0xd7610000, + 0x00011275, 0xd7610000, + 0x00011476, 0xd7610000, + 0x00011677, 0xd7610000, + 0x00011a79, 0xd7610000, + 0x00011c7e, 0xd7610000, + 0x00011e7f, 0xbefe03ff, + 0x00003fff, 0xbeff0380, + 0xdc5f8040, 0x007a0000, + 0xd760007a, 0x00011d00, + 0xd760007b, 0x00011f00, + 0xbefe037a, 0xbeff037b, + 0xbef4037e, 0x8775ff7f, + 0x0000ffff, 0x8875ff75, + 0x00040000, 0xbef60380, + 0xbef703ff, 0x10807fac, + 0xbef1037c, 0xbef00380, + 0xb97302dc, 0x8f739973, + 0xbefe03c1, 0x907c9973, + 0x877c817c, 0xbf06817c, + 0xbf850002, 0xbeff0380, + 0xbf820002, 0xbeff03c1, + 0xbf820009, 0xbef603ff, + 0x01000000, 0xe0704080, + 0x705d0100, 0xe0704100, + 0x705d0200, 0xe0704180, + 0x705d0300, 0xbf820008, 0xbef603ff, 0x01000000, - 0xe0704080, 0x705d0100, - 0xe0704100, 0x705d0200, - 0xe0704180, 0x705d0300, - 0xbf820008, 0xbef603ff, - 0x01000000, 0xe0704100, - 0x705d0100, 0xe0704200, - 0x705d0200, 0xe0704300, - 0x705d0300, 0xb9703a05, - 0x80708170, 0xbf0d9973, - 0xbf850002, 0x8f708970, - 0xbf820001, 0x8f708a70, - 0xb97a1e06, 0x8f7a8a7a, - 0x80707a70, 0x8070ff70, - 0x00000200, 0xbef603ff, - 0x01000000, 0x7e000280, - 0x7e020280, 0x7e040280, - 0xbefc0380, 0xd7610002, - 0x0000f871, 0x807c817c, - 0xd7610002, 0x0000f86c, - 0x807c817c, 0x8a7aff6d, - 0x80000000, 0xd7610002, - 0x0000f87a, 0x807c817c, - 0xd7610002, 0x0000f86e, - 0x807c817c, 0xd7610002, - 0x0000f86f, 0x807c817c, - 0xd7610002, 0x0000f878, - 0x807c817c, 0xb97af803, - 0xd7610002, 0x0000f87a, - 0x807c817c, 0xd7610002, - 0x0000f87b, 0x807c817c, - 0xb971f801, 0xd7610002, - 0x0000f871, 0x807c817c, - 0xb971f814, 0xd7610002, - 0x0000f871, 0x807c817c, - 0xb971f815, 0xd7610002, - 0x0000f871, 0x807c817c, - 0xbefe03ff, 0x0000ffff, - 0xbeff0380, 0xe0704000, - 0x705d0200, 0xbefe03c1, + 0xe0704100, 0x705d0100, + 0xe0704200, 0x705d0200, + 0xe0704300, 0x705d0300, 0xb9703a05, 0x80708170, 0xbf0d9973, 0xbf850002, 0x8f708970, 0xbf820001, 0x8f708a70, 0xb97a1e06, 0x8f7a8a7a, 0x80707a70, + 0x8070ff70, 0x00000200, 0xbef603ff, 0x01000000, - 0xbef90380, 0xbefc0380, - 0xbf800000, 0xbe802f00, - 0xbe822f02, 0xbe842f04, - 0xbe862f06, 0xbe882f08, - 0xbe8a2f0a, 0xbe8c2f0c, - 0xbe8e2f0e, 0xd7610002, - 0x0000f200, 0x80798179, - 0xd7610002, 0x0000f201, + 0x7e000280, 0x7e020280, + 0x7e040280, 0xbefc0380, + 0xd7610002, 0x0000f871, + 0x807c817c, 0xd7610002, + 0x0000f86c, 0x807c817c, + 0x8a7aff6d, 0x80000000, + 0xd7610002, 0x0000f87a, + 0x807c817c, 0xd7610002, + 0x0000f86e, 0x807c817c, + 0xd7610002, 0x0000f86f, + 0x807c817c, 0xd7610002, + 0x0000f878, 0x807c817c, + 0xb97af803, 0xd7610002, + 0x0000f87a, 0x807c817c, + 0xd7610002, 0x0000f87b, + 0x807c817c, 0xb971f801, + 0xd7610002, 0x0000f871, + 0x807c817c, 0xb971f814, + 0xd7610002, 0x0000f871, + 0x807c817c, 0xb971f815, + 0xd7610002, 0x0000f871, + 0x807c817c, 0xbefe03ff, + 0x0000ffff, 0xbeff0380, + 0xe0704000, 0x705d0200, + 0xbefe03c1, 0xb9703a05, + 0x80708170, 0xbf0d9973, + 0xbf850002, 0x8f708970, + 0xbf820001, 0x8f708a70, + 0xb97a1e06, 0x8f7a8a7a, + 0x80707a70, 0xbef603ff, + 0x01000000, 0xbef90380, + 0xbefc0380, 0xbf800000, + 0xbe802f00, 0xbe822f02, + 0xbe842f04, 0xbe862f06, + 0xbe882f08, 0xbe8a2f0a, + 0xbe8c2f0c, 0xbe8e2f0e, + 0xd7610002, 0x0000f200, 0x80798179, 0xd7610002, - 0x0000f202, 0x80798179, - 0xd7610002, 0x0000f203, + 0x0000f201, 0x80798179, + 0xd7610002, 0x0000f202, 0x80798179, 0xd7610002, - 0x0000f204, 0x80798179, - 0xd7610002, 0x0000f205, + 0x0000f203, 0x80798179, + 0xd7610002, 0x0000f204, 0x80798179, 0xd7610002, - 0x0000f206, 0x80798179, - 0xd7610002, 0x0000f207, + 0x0000f205, 0x80798179, + 0xd7610002, 0x0000f206, 0x80798179, 0xd7610002, - 0x0000f208, 0x80798179, - 0xd7610002, 0x0000f209, + 0x0000f207, 0x80798179, + 0xd7610002, 0x0000f208, 0x80798179, 0xd7610002, - 0x0000f20a, 0x80798179, - 0xd7610002, 0x0000f20b, + 0x0000f209, 0x80798179, + 0xd7610002, 0x0000f20a, 0x80798179, 0xd7610002, - 0x0000f20c, 0x80798179, - 0xd7610002, 0x0000f20d, + 0x0000f20b, 0x80798179, + 0xd7610002, 0x0000f20c, 0x80798179, 0xd7610002, - 0x0000f20e, 0x80798179, - 0xd7610002, 0x0000f20f, - 0x80798179, 0xbf06a079, - 0xbf840006, 0xe0704000, - 0x705d0200, 0x8070ff70, - 0x00000080, 0xbef90380, - 0x7e040280, 0x807c907c, - 0xbf0aff7c, 0x00000060, - 0xbf85ffbc, 0xbe802f00, - 0xbe822f02, 0xbe842f04, - 0xbe862f06, 0xbe882f08, - 0xbe8a2f0a, 0xd7610002, - 0x0000f200, 0x80798179, - 0xd7610002, 0x0000f201, + 0x0000f20d, 0x80798179, + 0xd7610002, 0x0000f20e, 0x80798179, 0xd7610002, - 0x0000f202, 0x80798179, - 0xd7610002, 0x0000f203, + 0x0000f20f, 0x80798179, + 0xbf06a079, 0xbf840006, + 0xe0704000, 0x705d0200, + 0x8070ff70, 0x00000080, + 0xbef90380, 0x7e040280, + 0x807c907c, 0xbf0aff7c, + 0x00000060, 0xbf85ffbc, + 0xbe802f00, 0xbe822f02, + 0xbe842f04, 0xbe862f06, + 0xbe882f08, 0xbe8a2f0a, + 0xd7610002, 0x0000f200, 0x80798179, 0xd7610002, - 0x0000f204, 0x80798179, - 0xd7610002, 0x0000f205, + 0x0000f201, 0x80798179, + 0xd7610002, 0x0000f202, 0x80798179, 0xd7610002, - 0x0000f206, 0x80798179, - 0xd7610002, 0x0000f207, + 0x0000f203, 0x80798179, + 0xd7610002, 0x0000f204, 0x80798179, 0xd7610002, - 0x0000f208, 0x80798179, - 0xd7610002, 0x0000f209, + 0x0000f205, 0x80798179, + 0xd7610002, 0x0000f206, 0x80798179, 0xd7610002, - 0x0000f20a, 0x80798179, - 0xd7610002, 0x0000f20b, - 0x80798179, 0xe0704000, - 0x705d0200, 0xbefe03c1, - 0x907c9973, 0x877c817c, - 0xbf06817c, 0xbf850002, - 0xbeff0380, 0xbf820001, - 0xbeff03c1, 0xb97b4306, - 0x877bc17b, 0xbf840044, - 0xbf8a0000, 0x877aff6d, - 0x80000000, 0xbf840040, - 0x8f7b867b, 0x8f7b827b, - 0xbef6037b, 0xb9703a05, - 0x80708170, 0xbf0d9973, - 0xbf850002, 0x8f708970, - 0xbf820001, 0x8f708a70, - 0xb97a1e06, 0x8f7a8a7a, - 0x80707a70, 0x8070ff70, - 0x00000200, 0x8070ff70, - 0x00000080, 0xbef603ff, - 0x01000000, 0xd7650000, - 0x000100c1, 0xd7660000, - 0x000200c1, 0x16000084, - 0x907c9973, 0x877c817c, - 0xbf06817c, 0xbefc0380, - 0xbf850012, 0xbe8303ff, - 0x00000080, 0xbf800000, - 0xbf800000, 0xbf800000, - 0xd8d80000, 0x01000000, - 0xbf8c0000, 0xe0704000, - 0x705d0100, 0x807c037c, - 0x80700370, 0xd5250000, - 0x0001ff00, 0x00000080, - 0xbf0a7b7c, 0xbf85fff4, - 0xbf820011, 0xbe8303ff, - 0x00000100, 0xbf800000, - 0xbf800000, 0xbf800000, - 0xd8d80000, 0x01000000, - 0xbf8c0000, 0xe0704000, - 0x705d0100, 0x807c037c, - 0x80700370, 0xd5250000, - 0x0001ff00, 0x00000100, - 0xbf0a7b7c, 0xbf85fff4, + 0x0000f207, 0x80798179, + 0xd7610002, 0x0000f208, + 0x80798179, 0xd7610002, + 0x0000f209, 0x80798179, + 0xd7610002, 0x0000f20a, + 0x80798179, 0xd7610002, + 0x0000f20b, 0x80798179, + 0xe0704000, 0x705d0200, 0xbefe03c1, 0x907c9973, 0x877c817c, 0xbf06817c, - 0xbf850004, 0xbef003ff, - 0x00000200, 0xbeff0380, - 0xbf820003, 0xbef003ff, - 0x00000400, 0xbeff03c1, - 0xb97b3a05, 0x807b817b, - 0x8f7b827b, 0x907c9973, + 0xbf850002, 0xbeff0380, + 0xbf820001, 0xbeff03c1, + 0xb97b4306, 0x877bc17b, + 0xbf840044, 0xbf8a0000, + 0x877aff6d, 0x80000000, + 0xbf840040, 0x8f7b867b, + 0x8f7b827b, 0xbef6037b, + 0xb9703a05, 0x80708170, + 0xbf0d9973, 0xbf850002, + 0x8f708970, 0xbf820001, + 0x8f708a70, 0xb97a1e06, + 0x8f7a8a7a, 0x80707a70, + 0x8070ff70, 0x00000200, + 0x8070ff70, 0x00000080, + 0xbef603ff, 0x01000000, + 0xd7650000, 0x000100c1, + 0xd7660000, 0x000200c1, + 0x16000084, 0x907c9973, 0x877c817c, 0xbf06817c, - 0xbf850017, 0xbef603ff, - 0x01000000, 0xbefc0384, - 0xbf0a7b7c, 0xbf840037, - 0x7e008700, 0x7e028701, - 0x7e048702, 0x7e068703, - 0xe0704000, 0x705d0000, - 0xe0704080, 0x705d0100, - 0xe0704100, 0x705d0200, - 0xe0704180, 0x705d0300, - 0x807c847c, 0x8070ff70, - 0x00000200, 0xbf0a7b7c, - 0xbf85ffef, 0xbf820025, + 0xbefc0380, 0xbf850012, + 0xbe8303ff, 0x00000080, + 0xbf800000, 0xbf800000, + 0xbf800000, 0xd8d80000, + 0x01000000, 0xbf8c0000, + 0xe0704000, 0x705d0100, + 0x807c037c, 0x80700370, + 0xd5250000, 0x0001ff00, + 0x00000080, 0xbf0a7b7c, + 0xbf85fff4, 0xbf820011, + 0xbe8303ff, 0x00000100, + 0xbf800000, 0xbf800000, + 0xbf800000, 0xd8d80000, + 0x01000000, 0xbf8c0000, + 0xe0704000, 0x705d0100, + 0x807c037c, 0x80700370, + 0xd5250000, 0x0001ff00, + 0x00000100, 0xbf0a7b7c, + 0xbf85fff4, 0xbefe03c1, + 0x907c9973, 0x877c817c, + 0xbf06817c, 0xbf850004, + 0xbef003ff, 0x00000200, + 0xbeff0380, 0xbf820003, + 0xbef003ff, 0x00000400, + 0xbeff03c1, 0xb97b3a05, + 0x807b817b, 0x8f7b827b, + 0x907c9973, 0x877c817c, + 0xbf06817c, 0xbf850017, 0xbef603ff, 0x01000000, 0xbefc0384, 0xbf0a7b7c, - 0xbf840011, 0x7e008700, + 0xbf840037, 0x7e008700, 0x7e028701, 0x7e048702, 0x7e068703, 0xe0704000, - 0x705d0000, 0xe0704100, - 0x705d0100, 0xe0704200, - 0x705d0200, 0xe0704300, + 0x705d0000, 0xe0704080, + 0x705d0100, 0xe0704100, + 0x705d0200, 0xe0704180, 0x705d0300, 0x807c847c, - 0x8070ff70, 0x00000400, + 0x8070ff70, 0x00000200, 0xbf0a7b7c, 0xbf85ffef, - 0xb97b1e06, 0x877bc17b, - 0xbf84000c, 0x8f7b837b, - 0x807b7c7b, 0xbefe03c1, - 0xbeff0380, 0x7e008700, + 0xbf820025, 0xbef603ff, + 0x01000000, 0xbefc0384, + 0xbf0a7b7c, 0xbf840011, + 0x7e008700, 0x7e028701, + 0x7e048702, 0x7e068703, 0xe0704000, 0x705d0000, - 0x807c817c, 0x8070ff70, - 0x00000080, 0xbf0a7b7c, - 0xbf85fff8, 0xbf82013b, - 0xbef4037e, 0x8775ff7f, - 0x0000ffff, 0x8875ff75, - 0x00040000, 0xbef60380, - 0xbef703ff, 0x10807fac, - 0xb97202dc, 0x8f729972, - 0x876eff7f, 0x04000000, - 0xbf840034, 0xbefe03c1, - 0x907c9972, 0x877c817c, - 0xbf06817c, 0xbf850002, - 0xbeff0380, 0xbf820001, - 0xbeff03c1, 0xb96f4306, - 0x876fc16f, 0xbf840029, - 0x8f6f866f, 0x8f6f826f, - 0xbef6036f, 0xb9783a05, - 0x80788178, 0xbf0d9972, - 0xbf850002, 0x8f788978, - 0xbf820001, 0x8f788a78, - 0xb96e1e06, 0x8f6e8a6e, - 0x80786e78, 0x8078ff78, - 0x00000200, 0x8078ff78, - 0x00000080, 0xbef603ff, - 0x01000000, 0x907c9972, - 0x877c817c, 0xbf06817c, - 0xbefc0380, 0xbf850009, - 0xe0310000, 0x781d0000, - 0x807cff7c, 0x00000080, - 0x8078ff78, 0x00000080, - 0xbf0a6f7c, 0xbf85fff8, - 0xbf820008, 0xe0310000, - 0x781d0000, 0x807cff7c, - 0x00000100, 0x8078ff78, - 0x00000100, 0xbf0a6f7c, - 0xbf85fff8, 0xbef80380, + 0xe0704100, 0x705d0100, + 0xe0704200, 0x705d0200, + 0xe0704300, 0x705d0300, + 0x807c847c, 0x8070ff70, + 0x00000400, 0xbf0a7b7c, + 0xbf85ffef, 0xb97b1e06, + 0x877bc17b, 0xbf84000c, + 0x8f7b837b, 0x807b7c7b, + 0xbefe03c1, 0xbeff0380, + 0x7e008700, 0xe0704000, + 0x705d0000, 0x807c817c, + 0x8070ff70, 0x00000080, + 0xbf0a7b7c, 0xbf85fff8, + 0xbf82013b, 0xbef4037e, + 0x8775ff7f, 0x0000ffff, + 0x8875ff75, 0x00040000, + 0xbef60380, 0xbef703ff, + 0x10807fac, 0xb97202dc, + 0x8f729972, 0x876eff7f, + 0x04000000, 0xbf840034, 0xbefe03c1, 0x907c9972, 0x877c817c, 0xbf06817c, 0xbf850002, 0xbeff0380, 0xbf820001, 0xbeff03c1, - 0xb96f3a05, 0x806f816f, - 0x8f6f826f, 0x907c9972, - 0x877c817c, 0xbf06817c, - 0xbf850024, 0xbef603ff, - 0x01000000, 0xbeee0378, + 0xb96f4306, 0x876fc16f, + 0xbf840029, 0x8f6f866f, + 0x8f6f826f, 0xbef6036f, + 0xb9783a05, 0x80788178, + 0xbf0d9972, 0xbf850002, + 0x8f788978, 0xbf820001, + 0x8f788a78, 0xb96e1e06, + 0x8f6e8a6e, 0x80786e78, 0x8078ff78, 0x00000200, - 0xbefc0384, 0xbf0a6f7c, - 0xbf840050, 0xe0304000, - 0x785d0000, 0xe0304080, - 0x785d0100, 0xe0304100, - 0x785d0200, 0xe0304180, - 0x785d0300, 0xbf8c3f70, - 0x7e008500, 0x7e028501, - 0x7e048502, 0x7e068503, - 0x807c847c, 0x8078ff78, - 0x00000200, 0xbf0a6f7c, - 0xbf85ffee, 0xe0304000, - 0x6e5d0000, 0xe0304080, - 0x6e5d0100, 0xe0304100, - 0x6e5d0200, 0xe0304180, - 0x6e5d0300, 0xbf8c3f70, - 0xbf820034, 0xbef603ff, - 0x01000000, 0xbeee0378, - 0x8078ff78, 0x00000400, - 0xbefc0384, 0xbf0a6f7c, - 0xbf840012, 0xe0304000, - 0x785d0000, 0xe0304100, - 0x785d0100, 0xe0304200, - 0x785d0200, 0xe0304300, - 0x785d0300, 0xbf8c3f70, - 0x7e008500, 0x7e028501, - 0x7e048502, 0x7e068503, - 0x807c847c, 0x8078ff78, - 0x00000400, 0xbf0a6f7c, - 0xbf85ffee, 0xb96f1e06, - 0x876fc16f, 0xbf84000e, - 0x8f6f836f, 0x806f7c6f, - 0xbefe03c1, 0xbeff0380, + 0x8078ff78, 0x00000080, + 0xbef603ff, 0x01000000, + 0x907c9972, 0x877c817c, + 0xbf06817c, 0xbefc0380, + 0xbf850009, 0xe0310000, + 0x781d0000, 0x807cff7c, + 0x00000080, 0x8078ff78, + 0x00000080, 0xbf0a6f7c, + 0xbf85fff8, 0xbf820008, + 0xe0310000, 0x781d0000, + 0x807cff7c, 0x00000100, + 0x8078ff78, 0x00000100, + 0xbf0a6f7c, 0xbf85fff8, + 0xbef80380, 0xbefe03c1, + 0x907c9972, 0x877c817c, + 0xbf06817c, 0xbf850002, + 0xbeff0380, 0xbf820001, + 0xbeff03c1, 0xb96f3a05, + 0x806f816f, 0x8f6f826f, + 0x907c9972, 0x877c817c, + 0xbf06817c, 0xbf850024, + 0xbef603ff, 0x01000000, + 0xbeee0378, 0x8078ff78, + 0x00000200, 0xbefc0384, + 0xbf0a6f7c, 0xbf840050, 0xe0304000, 0x785d0000, + 0xe0304080, 0x785d0100, + 0xe0304100, 0x785d0200, + 0xe0304180, 0x785d0300, 0xbf8c3f70, 0x7e008500, - 0x807c817c, 0x8078ff78, - 0x00000080, 0xbf0a6f7c, - 0xbf85fff7, 0xbeff03c1, + 0x7e028501, 0x7e048502, + 0x7e068503, 0x807c847c, + 0x8078ff78, 0x00000200, + 0xbf0a6f7c, 0xbf85ffee, 0xe0304000, 0x6e5d0000, - 0xe0304100, 0x6e5d0100, - 0xe0304200, 0x6e5d0200, - 0xe0304300, 0x6e5d0300, - 0xbf8c3f70, 0xb9783a05, - 0x80788178, 0xbf0d9972, - 0xbf850002, 0x8f788978, - 0xbf820001, 0x8f788a78, - 0xb96e1e06, 0x8f6e8a6e, - 0x80786e78, 0x8078ff78, - 0x00000200, 0x80f8ff78, - 0x00000050, 0xbef603ff, - 0x01000000, 0xbefc03ff, - 0x0000006c, 0x80f89078, - 0xf429003a, 0xf0000000, - 0xbf8cc07f, 0x80fc847c, - 0xbf800000, 0xbe803100, - 0xbe823102, 0x80f8a078, - 0xf42d003a, 0xf0000000, - 0xbf8cc07f, 0x80fc887c, - 0xbf800000, 0xbe803100, - 0xbe823102, 0xbe843104, - 0xbe863106, 0x80f8c078, - 0xf431003a, 0xf0000000, - 0xbf8cc07f, 0x80fc907c, - 0xbf800000, 0xbe803100, - 0xbe823102, 0xbe843104, - 0xbe863106, 0xbe883108, - 0xbe8a310a, 0xbe8c310c, - 0xbe8e310e, 0xbf06807c, - 0xbf84fff0, 0xba80f801, - 0x00000000, 0xbf8a0000, + 0xe0304080, 0x6e5d0100, + 0xe0304100, 0x6e5d0200, + 0xe0304180, 0x6e5d0300, + 0xbf8c3f70, 0xbf820034, + 0xbef603ff, 0x01000000, + 0xbeee0378, 0x8078ff78, + 0x00000400, 0xbefc0384, + 0xbf0a6f7c, 0xbf840012, + 0xe0304000, 0x785d0000, + 0xe0304100, 0x785d0100, + 0xe0304200, 0x785d0200, + 0xe0304300, 0x785d0300, + 0xbf8c3f70, 0x7e008500, + 0x7e028501, 0x7e048502, + 0x7e068503, 0x807c847c, + 0x8078ff78, 0x00000400, + 0xbf0a6f7c, 0xbf85ffee, + 0xb96f1e06, 0x876fc16f, + 0xbf84000e, 0x8f6f836f, + 0x806f7c6f, 0xbefe03c1, + 0xbeff0380, 0xe0304000, + 0x785d0000, 0xbf8c3f70, + 0x7e008500, 0x807c817c, + 0x8078ff78, 0x00000080, + 0xbf0a6f7c, 0xbf85fff7, + 0xbeff03c1, 0xe0304000, + 0x6e5d0000, 0xe0304100, + 0x6e5d0100, 0xe0304200, + 0x6e5d0200, 0xe0304300, + 0x6e5d0300, 0xbf8c3f70, 0xb9783a05, 0x80788178, 0xbf0d9972, 0xbf850002, 0x8f788978, 0xbf820001, 0x8f788a78, 0xb96e1e06, 0x8f6e8a6e, 0x80786e78, 0x8078ff78, 0x00000200, + 0x80f8ff78, 0x00000050, 0xbef603ff, 0x01000000, - 0xf4211bfa, 0xf0000000, - 0x80788478, 0xf4211b3a, + 0xbefc03ff, 0x0000006c, + 0x80f89078, 0xf429003a, + 0xf0000000, 0xbf8cc07f, + 0x80fc847c, 0xbf800000, + 0xbe803100, 0xbe823102, + 0x80f8a078, 0xf42d003a, + 0xf0000000, 0xbf8cc07f, + 0x80fc887c, 0xbf800000, + 0xbe803100, 0xbe823102, + 0xbe843104, 0xbe863106, + 0x80f8c078, 0xf431003a, + 0xf0000000, 0xbf8cc07f, + 0x80fc907c, 0xbf800000, + 0xbe803100, 0xbe823102, + 0xbe843104, 0xbe863106, + 0xbe883108, 0xbe8a310a, + 0xbe8c310c, 0xbe8e310e, + 0xbf06807c, 0xbf84fff0, + 0xba80f801, 0x00000000, + 0xbf8a0000, 0xb9783a05, + 0x80788178, 0xbf0d9972, + 0xbf850002, 0x8f788978, + 0xbf820001, 0x8f788a78, + 0xb96e1e06, 0x8f6e8a6e, + 0x80786e78, 0x8078ff78, + 0x00000200, 0xbef603ff, + 0x01000000, 0xf4211bfa, 0xf0000000, 0x80788478, - 0xf4211b7a, 0xf0000000, - 0x80788478, 0xf4211c3a, + 0xf4211b3a, 0xf0000000, + 0x80788478, 0xf4211b7a, 0xf0000000, 0x80788478, - 0xf4211c7a, 0xf0000000, - 0x80788478, 0xf4211eba, + 0xf4211c3a, 0xf0000000, + 0x80788478, 0xf4211c7a, 0xf0000000, 0x80788478, - 0xf4211efa, 0xf0000000, - 0x80788478, 0xf4211e7a, + 0xf4211eba, 0xf0000000, + 0x80788478, 0xf4211efa, 0xf0000000, 0x80788478, - 0xf4211cfa, 0xf0000000, - 0x80788478, 0xf4211bba, + 0xf4211e7a, 0xf0000000, + 0x80788478, 0xf4211cfa, 0xf0000000, 0x80788478, - 0xbf8cc07f, 0xb9eef814, 0xf4211bba, 0xf0000000, 0x80788478, 0xbf8cc07f, - 0xb9eef815, 0xbefc036f, - 0xbefe0370, 0xbeff0371, - 0x876f7bff, 0x000003ff, - 0xb9ef4803, 0x876f7bff, - 0xfffff800, 0x906f8b6f, - 0xb9efa2c3, 0xb9f3f801, - 0xb96e3a05, 0x806e816e, - 0xbf0d9972, 0xbf850002, - 0x8f6e896e, 0xbf820001, - 0x8f6e8a6e, 0xb96f1e06, - 0x8f6f8a6f, 0x806e6f6e, - 0x806eff6e, 0x00000200, - 0x806e746e, 0x826f8075, - 0x876fff6f, 0x0000ffff, - 0xf4091c37, 0xfa000050, - 0xf4091d37, 0xfa000060, - 0xf4011e77, 0xfa000074, - 0xbf8cc07f, 0x876dff6d, - 0x0000ffff, 0x87fe7e7e, - 0x87ea6a6a, 0xb9faf802, - 0xbe80226c, 0xbf810000, + 0xb9eef814, 0xf4211bba, + 0xf0000000, 0x80788478, + 0xbf8cc07f, 0xb9eef815, + 0xbefc036f, 0xbefe0370, + 0xbeff0371, 0x876f7bff, + 0x000003ff, 0xb9ef4803, + 0x876f7bff, 0xfffff800, + 0x906f8b6f, 0xb9efa2c3, + 0xb9f3f801, 0xb96e3a05, + 0x806e816e, 0xbf0d9972, + 0xbf850002, 0x8f6e896e, + 0xbf820001, 0x8f6e8a6e, + 0xb96f1e06, 0x8f6f8a6f, + 0x806e6f6e, 0x806eff6e, + 0x00000200, 0x806e746e, + 0x826f8075, 0x876fff6f, + 0x0000ffff, 0xf4091c37, + 0xfa000050, 0xf4091d37, + 0xfa000060, 0xf4011e77, + 0xfa000074, 0xbf8cc07f, + 0x876dff6d, 0x0000ffff, + 0x87fe7e7e, 0x87ea6a6a, + 0xb9faf802, 0xbe80226c, + 0xbf810000, 0xbf9f0000, 0xbf9f0000, 0xbf9f0000, 0xbf9f0000, 0xbf9f0000, - 0xbf9f0000, 0x00000000, }; static const uint32_t cwsr_trap_gfx11_hex[] = { diff --git a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx10.asm b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx10.asm index fdab6462442253..e0140df0b0ec80 100644 --- a/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx10.asm +++ b/drivers/gpu/drm/amd/amdkfd/cwsr_trap_handler_gfx10.asm @@ -369,6 +369,12 @@ L_SLEEP: s_or_b32 s_save_pc_hi, s_save_pc_hi, s_save_tmp #if NO_SQC_STORE +#if ASIC_FAMILY <= CHIP_SIENNA_CICHLID + // gfx10: If there was a VALU exception, the exception state must be + // cleared before executing the VALU instructions below. + v_clrexcp +#endif + // Trap temporaries must be saved via VGPR but all VGPRs are in use. // There is no ttmp space to hold the resource constant for VGPR save. // Save v0 by itself since it requires only two SGPRs. diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index f6d4748c1980a5..ce4c52ec34d80e 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -1564,16 +1564,11 @@ static int kfd_ioctl_import_dmabuf(struct file *filep, { struct kfd_ioctl_import_dmabuf_args *args = data; struct kfd_process_device *pdd; - struct dma_buf *dmabuf; int idr_handle; uint64_t size; void *mem; int r; - dmabuf = dma_buf_get(args->dmabuf_fd); - if (IS_ERR(dmabuf)) - return PTR_ERR(dmabuf); - mutex_lock(&p->mutex); pdd = kfd_process_device_data_by_id(p, args->gpu_id); if (!pdd) { @@ -1587,10 +1582,10 @@ static int kfd_ioctl_import_dmabuf(struct file *filep, goto err_unlock; } - r = amdgpu_amdkfd_gpuvm_import_dmabuf(pdd->dev->adev, dmabuf, - args->va_addr, pdd->drm_priv, - (struct kgd_mem **)&mem, &size, - NULL); + r = amdgpu_amdkfd_gpuvm_import_dmabuf_fd(pdd->dev->adev, args->dmabuf_fd, + args->va_addr, pdd->drm_priv, + (struct kgd_mem **)&mem, &size, + NULL); if (r) goto err_unlock; @@ -1601,7 +1596,6 @@ static int kfd_ioctl_import_dmabuf(struct file *filep, } mutex_unlock(&p->mutex); - dma_buf_put(dmabuf); args->handle = MAKE_HANDLE(args->gpu_id, idr_handle); @@ -1612,7 +1606,6 @@ err_free: pdd->drm_priv, NULL); err_unlock: mutex_unlock(&p->mutex); - dma_buf_put(dmabuf); return r; } @@ -1855,8 +1848,8 @@ static uint32_t get_process_num_bos(struct kfd_process *p) return num_of_bos; } -static int criu_get_prime_handle(struct kgd_mem *mem, int flags, - u32 *shared_fd) +static int criu_get_prime_handle(struct kgd_mem *mem, + int flags, u32 *shared_fd) { struct dma_buf *dmabuf; int ret; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_events.c index 0f58be65132fc0..739721254a5dff 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_events.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.c @@ -880,6 +880,10 @@ static int copy_signaled_event_data(uint32_t num_events, dst = &data[i].memory_exception_data; src = &event->memory_exception_data; size = sizeof(struct kfd_hsa_memory_exception_data); + } else if (event->type == KFD_EVENT_TYPE_HW_EXCEPTION) { + dst = &data[i].memory_exception_data; + src = &event->hw_exception_data; + size = sizeof(struct kfd_hsa_hw_exception_data); } else if (event->type == KFD_EVENT_TYPE_SIGNAL && waiter->event_age_enabled) { dst = &data[i].signal_event_data.last_event_age; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c b/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c index 62b205dac63a05..6604a3f99c5ecf 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c @@ -330,12 +330,6 @@ static void kfd_init_apertures_vi(struct kfd_process_device *pdd, uint8_t id) pdd->gpuvm_limit = pdd->dev->kfd->shared_resources.gpuvm_size - 1; - /* dGPUs: the reserved space for kernel - * before SVM - */ - pdd->qpd.cwsr_base = SVM_CWSR_BASE; - pdd->qpd.ib_base = SVM_IB_BASE; - pdd->scratch_base = MAKE_SCRATCH_APP_BASE_VI(); pdd->scratch_limit = MAKE_SCRATCH_APP_LIMIT(pdd->scratch_base); } @@ -345,18 +339,18 @@ static void kfd_init_apertures_v9(struct kfd_process_device *pdd, uint8_t id) pdd->lds_base = MAKE_LDS_APP_BASE_V9(); pdd->lds_limit = MAKE_LDS_APP_LIMIT(pdd->lds_base); - pdd->gpuvm_base = PAGE_SIZE; + /* Raven needs SVM to support graphic handle, etc. Leave the small + * reserved space before SVM on Raven as well, even though we don't + * have to. + * Set gpuvm_base and gpuvm_limit to CANONICAL addresses so that they + * are used in Thunk to reserve SVM. + */ + pdd->gpuvm_base = SVM_USER_BASE; pdd->gpuvm_limit = pdd->dev->kfd->shared_resources.gpuvm_size - 1; pdd->scratch_base = MAKE_SCRATCH_APP_BASE_V9(); pdd->scratch_limit = MAKE_SCRATCH_APP_LIMIT(pdd->scratch_base); - - /* - * Place TBA/TMA on opposite side of VM hole to prevent - * stray faults from triggering SVM on these pages. - */ - pdd->qpd.cwsr_base = pdd->dev->kfd->shared_resources.gpuvm_size; } int kfd_init_apertures(struct kfd_process *process) @@ -413,6 +407,12 @@ int kfd_init_apertures(struct kfd_process *process) return -EINVAL; } } + + /* dGPUs: the reserved space for kernel + * before SVM + */ + pdd->qpd.cwsr_base = SVM_CWSR_BASE; + pdd->qpd.ib_base = SVM_IB_BASE; } dev_dbg(kfd_device, "node id %u\n", id); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index 6c25dab051d5c4..f856901055d34e 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -260,19 +260,6 @@ static void svm_migrate_put_sys_page(unsigned long addr) put_page(page); } -static unsigned long svm_migrate_successful_pages(struct migrate_vma *migrate) -{ - unsigned long cpages = 0; - unsigned long i; - - for (i = 0; i < migrate->npages; i++) { - if (migrate->src[i] & MIGRATE_PFN_VALID && - migrate->src[i] & MIGRATE_PFN_MIGRATE) - cpages++; - } - return cpages; -} - static unsigned long svm_migrate_unsuccessful_pages(struct migrate_vma *migrate) { unsigned long upages = 0; @@ -402,6 +389,7 @@ svm_migrate_vma_to_vram(struct kfd_node *node, struct svm_range *prange, struct dma_fence *mfence = NULL; struct migrate_vma migrate = { 0 }; unsigned long cpages = 0; + unsigned long mpages = 0; dma_addr_t *scratch; void *buf; int r = -ENOMEM; @@ -442,20 +430,21 @@ svm_migrate_vma_to_vram(struct kfd_node *node, struct svm_range *prange, goto out_free; } if (cpages != npages) - pr_debug("partial migration, 0x%lx/0x%llx pages migrated\n", + pr_debug("partial migration, 0x%lx/0x%llx pages collected\n", cpages, npages); else - pr_debug("0x%lx pages migrated\n", cpages); + pr_debug("0x%lx pages collected\n", cpages); r = svm_migrate_copy_to_vram(node, prange, &migrate, &mfence, scratch, ttm_res_offset); migrate_vma_pages(&migrate); - pr_debug("successful/cpages/npages 0x%lx/0x%lx/0x%lx\n", - svm_migrate_successful_pages(&migrate), cpages, migrate.npages); - svm_migrate_copy_done(adev, mfence); migrate_vma_finalize(&migrate); + mpages = cpages - svm_migrate_unsuccessful_pages(&migrate); + pr_debug("successful/cpages/npages 0x%lx/0x%lx/0x%lx\n", + mpages, cpages, migrate.npages); + kfd_smi_event_migration_end(node, p->lead_thread->pid, start >> PAGE_SHIFT, end >> PAGE_SHIFT, 0, node->id, trigger); @@ -465,12 +454,12 @@ svm_migrate_vma_to_vram(struct kfd_node *node, struct svm_range *prange, out_free: kvfree(buf); out: - if (!r && cpages) { + if (!r && mpages) { pdd = svm_range_get_pdd_by_node(prange, node); if (pdd) - WRITE_ONCE(pdd->page_in, pdd->page_in + cpages); + WRITE_ONCE(pdd->page_in, pdd->page_in + mpages); - return cpages; + return mpages; } return r; } @@ -479,6 +468,8 @@ out: * svm_migrate_ram_to_vram - migrate svm range from system to device * @prange: range structure * @best_loc: the device to migrate to + * @start_mgr: start page to migrate + * @last_mgr: last page to migrate * @mm: the process mm structure * @trigger: reason of migration * @@ -489,19 +480,20 @@ out: */ static int svm_migrate_ram_to_vram(struct svm_range *prange, uint32_t best_loc, + unsigned long start_mgr, unsigned long last_mgr, struct mm_struct *mm, uint32_t trigger) { unsigned long addr, start, end; struct vm_area_struct *vma; uint64_t ttm_res_offset; struct kfd_node *node; - unsigned long cpages = 0; + unsigned long mpages = 0; long r = 0; - if (prange->actual_loc == best_loc) { - pr_debug("svms 0x%p [0x%lx 0x%lx] already on best_loc 0x%x\n", - prange->svms, prange->start, prange->last, best_loc); - return 0; + if (start_mgr < prange->start || last_mgr > prange->last) { + pr_debug("range [0x%lx 0x%lx] out prange [0x%lx 0x%lx]\n", + start_mgr, last_mgr, prange->start, prange->last); + return -EFAULT; } node = svm_range_get_node_by_id(prange, best_loc); @@ -510,18 +502,19 @@ svm_migrate_ram_to_vram(struct svm_range *prange, uint32_t best_loc, return -ENODEV; } - pr_debug("svms 0x%p [0x%lx 0x%lx] to gpu 0x%x\n", prange->svms, - prange->start, prange->last, best_loc); + pr_debug("svms 0x%p [0x%lx 0x%lx] in [0x%lx 0x%lx] to gpu 0x%x\n", + prange->svms, start_mgr, last_mgr, prange->start, prange->last, + best_loc); - start = prange->start << PAGE_SHIFT; - end = (prange->last + 1) << PAGE_SHIFT; + start = start_mgr << PAGE_SHIFT; + end = (last_mgr + 1) << PAGE_SHIFT; r = svm_range_vram_node_new(node, prange, true); if (r) { dev_dbg(node->adev->dev, "fail %ld to alloc vram\n", r); return r; } - ttm_res_offset = prange->offset << PAGE_SHIFT; + ttm_res_offset = (start_mgr - prange->start + prange->offset) << PAGE_SHIFT; for (addr = start; addr < end;) { unsigned long next; @@ -536,16 +529,19 @@ svm_migrate_ram_to_vram(struct svm_range *prange, uint32_t best_loc, pr_debug("failed %ld to migrate\n", r); break; } else { - cpages += r; + mpages += r; } ttm_res_offset += next - addr; addr = next; } - if (cpages) { + if (mpages) { prange->actual_loc = best_loc; - svm_range_dma_unmap(prange); - } else { + prange->vram_pages += mpages; + } else if (!prange->actual_loc) { + /* if no page migrated and all pages from prange are at + * sys ram drop svm_bo got from svm_range_vram_node_new + */ svm_range_vram_node_free(prange); } @@ -663,9 +659,8 @@ out_oom: * Context: Process context, caller hold mmap read lock, prange->migrate_mutex * * Return: - * 0 - success with all pages migrated * negative values - indicate error - * positive values - partial migration, number of pages not migrated + * positive values or zero - number of pages got migrated */ static long svm_migrate_vma_to_ram(struct kfd_node *node, struct svm_range *prange, @@ -676,6 +671,7 @@ svm_migrate_vma_to_ram(struct kfd_node *node, struct svm_range *prange, uint64_t npages = (end - start) >> PAGE_SHIFT; unsigned long upages = npages; unsigned long cpages = 0; + unsigned long mpages = 0; struct amdgpu_device *adev = node->adev; struct kfd_process_device *pdd; struct dma_fence *mfence = NULL; @@ -725,10 +721,10 @@ svm_migrate_vma_to_ram(struct kfd_node *node, struct svm_range *prange, goto out_free; } if (cpages != npages) - pr_debug("partial migration, 0x%lx/0x%llx pages migrated\n", + pr_debug("partial migration, 0x%lx/0x%llx pages collected\n", cpages, npages); else - pr_debug("0x%lx pages migrated\n", cpages); + pr_debug("0x%lx pages collected\n", cpages); r = svm_migrate_copy_to_ram(adev, prange, &migrate, &mfence, scratch, npages); @@ -751,17 +747,21 @@ out_free: kvfree(buf); out: if (!r && cpages) { + mpages = cpages - upages; pdd = svm_range_get_pdd_by_node(prange, node); if (pdd) - WRITE_ONCE(pdd->page_out, pdd->page_out + cpages); + WRITE_ONCE(pdd->page_out, pdd->page_out + mpages); } - return r ? r : upages; + + return r ? r : mpages; } /** * svm_migrate_vram_to_ram - migrate svm range from device to system * @prange: range structure * @mm: process mm, use current->mm if NULL + * @start_mgr: start page need be migrated to sys ram + * @last_mgr: last page need be migrated to sys ram * @trigger: reason of migration * @fault_page: is from vmf->page, svm_migrate_to_ram(), this is CPU page fault callback * @@ -771,6 +771,7 @@ out: * 0 - OK, otherwise error code */ int svm_migrate_vram_to_ram(struct svm_range *prange, struct mm_struct *mm, + unsigned long start_mgr, unsigned long last_mgr, uint32_t trigger, struct page *fault_page) { struct kfd_node *node; @@ -778,26 +779,33 @@ int svm_migrate_vram_to_ram(struct svm_range *prange, struct mm_struct *mm, unsigned long addr; unsigned long start; unsigned long end; - unsigned long upages = 0; + unsigned long mpages = 0; long r = 0; + /* this pragne has no any vram page to migrate to sys ram */ if (!prange->actual_loc) { pr_debug("[0x%lx 0x%lx] already migrated to ram\n", prange->start, prange->last); return 0; } + if (start_mgr < prange->start || last_mgr > prange->last) { + pr_debug("range [0x%lx 0x%lx] out prange [0x%lx 0x%lx]\n", + start_mgr, last_mgr, prange->start, prange->last); + return -EFAULT; + } + node = svm_range_get_node_by_id(prange, prange->actual_loc); if (!node) { pr_debug("failed to get kfd node by id 0x%x\n", prange->actual_loc); return -ENODEV; } pr_debug("svms 0x%p prange 0x%p [0x%lx 0x%lx] from gpu 0x%x to ram\n", - prange->svms, prange, prange->start, prange->last, + prange->svms, prange, start_mgr, last_mgr, prange->actual_loc); - start = prange->start << PAGE_SHIFT; - end = (prange->last + 1) << PAGE_SHIFT; + start = start_mgr << PAGE_SHIFT; + end = (last_mgr + 1) << PAGE_SHIFT; for (addr = start; addr < end;) { unsigned long next; @@ -816,14 +824,21 @@ int svm_migrate_vram_to_ram(struct svm_range *prange, struct mm_struct *mm, pr_debug("failed %ld to migrate prange %p\n", r, prange); break; } else { - upages += r; + mpages += r; } addr = next; } - if (r >= 0 && !upages) { - svm_range_vram_node_free(prange); - prange->actual_loc = 0; + if (r >= 0) { + prange->vram_pages -= mpages; + + /* prange does not have vram page set its actual_loc to system + * and drop its svm_bo ref + */ + if (prange->vram_pages == 0 && prange->ttm_res) { + prange->actual_loc = 0; + svm_range_vram_node_free(prange); + } } return r < 0 ? r : 0; @@ -833,17 +848,23 @@ int svm_migrate_vram_to_ram(struct svm_range *prange, struct mm_struct *mm, * svm_migrate_vram_to_vram - migrate svm range from device to device * @prange: range structure * @best_loc: the device to migrate to + * @start: start page need be migrated to sys ram + * @last: last page need be migrated to sys ram * @mm: process mm, use current->mm if NULL * @trigger: reason of migration * * Context: Process context, caller hold mmap read lock, svms lock, prange lock * + * migrate all vram pages in prange to sys ram, then migrate + * [start, last] pages from sys ram to gpu node best_loc. + * * Return: * 0 - OK, otherwise error code */ static int svm_migrate_vram_to_vram(struct svm_range *prange, uint32_t best_loc, - struct mm_struct *mm, uint32_t trigger) + unsigned long start, unsigned long last, + struct mm_struct *mm, uint32_t trigger) { int r, retries = 3; @@ -855,7 +876,8 @@ svm_migrate_vram_to_vram(struct svm_range *prange, uint32_t best_loc, pr_debug("from gpu 0x%x to gpu 0x%x\n", prange->actual_loc, best_loc); do { - r = svm_migrate_vram_to_ram(prange, mm, trigger, NULL); + r = svm_migrate_vram_to_ram(prange, mm, prange->start, prange->last, + trigger, NULL); if (r) return r; } while (prange->actual_loc && --retries); @@ -863,17 +885,21 @@ svm_migrate_vram_to_vram(struct svm_range *prange, uint32_t best_loc, if (prange->actual_loc) return -EDEADLK; - return svm_migrate_ram_to_vram(prange, best_loc, mm, trigger); + return svm_migrate_ram_to_vram(prange, best_loc, start, last, mm, trigger); } int svm_migrate_to_vram(struct svm_range *prange, uint32_t best_loc, + unsigned long start, unsigned long last, struct mm_struct *mm, uint32_t trigger) { - if (!prange->actual_loc) - return svm_migrate_ram_to_vram(prange, best_loc, mm, trigger); + if (!prange->actual_loc || prange->actual_loc == best_loc) + return svm_migrate_ram_to_vram(prange, best_loc, start, last, + mm, trigger); + else - return svm_migrate_vram_to_vram(prange, best_loc, mm, trigger); + return svm_migrate_vram_to_vram(prange, best_loc, start, last, + mm, trigger); } @@ -889,10 +915,9 @@ svm_migrate_to_vram(struct svm_range *prange, uint32_t best_loc, */ static vm_fault_t svm_migrate_to_ram(struct vm_fault *vmf) { + unsigned long start, last, size; unsigned long addr = vmf->address; struct svm_range_bo *svm_bo; - enum svm_work_list_ops op; - struct svm_range *parent; struct svm_range *prange; struct kfd_process *p; struct mm_struct *mm; @@ -929,51 +954,31 @@ static vm_fault_t svm_migrate_to_ram(struct vm_fault *vmf) mutex_lock(&p->svms.lock); - prange = svm_range_from_addr(&p->svms, addr, &parent); + prange = svm_range_from_addr(&p->svms, addr, NULL); if (!prange) { pr_debug("failed get range svms 0x%p addr 0x%lx\n", &p->svms, addr); r = -EFAULT; goto out_unlock_svms; } - mutex_lock(&parent->migrate_mutex); - if (prange != parent) - mutex_lock_nested(&prange->migrate_mutex, 1); + mutex_lock(&prange->migrate_mutex); if (!prange->actual_loc) goto out_unlock_prange; - svm_range_lock(parent); - if (prange != parent) - mutex_lock_nested(&prange->lock, 1); - r = svm_range_split_by_granularity(p, mm, addr, parent, prange); - if (prange != parent) - mutex_unlock(&prange->lock); - svm_range_unlock(parent); - if (r) { - pr_debug("failed %d to split range by granularity\n", r); - goto out_unlock_prange; - } + /* Align migration range start and size to granularity size */ + size = 1UL << prange->granularity; + start = max(ALIGN_DOWN(addr, size), prange->start); + last = min(ALIGN(addr + 1, size) - 1, prange->last); - r = svm_migrate_vram_to_ram(prange, vmf->vma->vm_mm, - KFD_MIGRATE_TRIGGER_PAGEFAULT_CPU, - vmf->page); + r = svm_migrate_vram_to_ram(prange, vmf->vma->vm_mm, start, last, + KFD_MIGRATE_TRIGGER_PAGEFAULT_CPU, vmf->page); if (r) pr_debug("failed %d migrate svms 0x%p range 0x%p [0x%lx 0x%lx]\n", - r, prange->svms, prange, prange->start, prange->last); - - /* xnack on, update mapping on GPUs with ACCESS_IN_PLACE */ - if (p->xnack_enabled && parent == prange) - op = SVM_OP_UPDATE_RANGE_NOTIFIER_AND_MAP; - else - op = SVM_OP_UPDATE_RANGE_NOTIFIER; - svm_range_add_list_work(&p->svms, parent, mm, op); - schedule_deferred_list_work(&p->svms); + r, prange->svms, prange, start, last); out_unlock_prange: - if (prange != parent) - mutex_unlock(&prange->migrate_mutex); - mutex_unlock(&parent->migrate_mutex); + mutex_unlock(&prange->migrate_mutex); out_unlock_svms: mutex_unlock(&p->svms.lock); out_unref_process: @@ -1021,7 +1026,7 @@ int kgd2kfd_init_zone_device(struct amdgpu_device *adev) } else { res = devm_request_free_mem_region(adev->dev, &iomem_resource, size); if (IS_ERR(res)) - return -ENOMEM; + return PTR_ERR(res); pgmap->range.start = res->start; pgmap->range.end = res->end; pgmap->type = MEMORY_DEVICE_PRIVATE; @@ -1037,10 +1042,10 @@ int kgd2kfd_init_zone_device(struct amdgpu_device *adev) r = devm_memremap_pages(adev->dev, pgmap); if (IS_ERR(r)) { pr_err("failed to register HMM device memory\n"); - /* Disable SVM support capability */ - pgmap->type = 0; if (pgmap->type == MEMORY_DEVICE_PRIVATE) devm_release_mem_region(adev->dev, res->start, resource_size(res)); + /* Disable SVM support capability */ + pgmap->type = 0; return PTR_ERR(r); } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.h b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.h index 487f2636816483..2eebf67f9c2ce2 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.h @@ -41,9 +41,13 @@ enum MIGRATION_COPY_DIR { }; int svm_migrate_to_vram(struct svm_range *prange, uint32_t best_loc, + unsigned long start, unsigned long last, struct mm_struct *mm, uint32_t trigger); + int svm_migrate_vram_to_ram(struct svm_range *prange, struct mm_struct *mm, + unsigned long start, unsigned long last, uint32_t trigger, struct page *fault_page); + unsigned long svm_migrate_addr_to_pfn(struct amdgpu_device *adev, unsigned long addr); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c index 8b7fed91352696..22cbfa1bdaddb9 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c @@ -170,6 +170,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd, m->cp_hqd_pq_control = 5 << CP_HQD_PQ_CONTROL__RPTR_BLOCK_SIZE__SHIFT; m->cp_hqd_pq_control |= ffs(q->queue_size / sizeof(unsigned int)) - 1 - 1; + m->cp_hqd_pq_control |= CP_HQD_PQ_CONTROL__UNORD_DISPATCH_MASK; pr_debug("cp_hqd_pq_control 0x%x\n", m->cp_hqd_pq_control); m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8); 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 15277f1d5cf0a9..d722cbd317834a 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c @@ -224,6 +224,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd, m->cp_hqd_pq_control = 5 << CP_HQD_PQ_CONTROL__RPTR_BLOCK_SIZE__SHIFT; m->cp_hqd_pq_control |= ffs(q->queue_size / sizeof(unsigned int)) - 1 - 1; + m->cp_hqd_pq_control |= CP_HQD_PQ_CONTROL__UNORD_DISPATCH_MASK; pr_debug("cp_hqd_pq_control 0x%x\n", m->cp_hqd_pq_control); m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index 4c8e278a0d0cc4..17fbedbf365138 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -748,7 +748,6 @@ struct kfd_process_device { /* VM context for GPUVM allocations */ struct file *drm_file; void *drm_priv; - atomic64_t tlb_seq; /* GPUVM allocations storage */ struct idr alloc_idr; @@ -918,7 +917,7 @@ struct kfd_process { * fence will be triggered during eviction and new one will be created * during restore */ - struct dma_fence *ef; + struct dma_fence __rcu *ef; /* Work items for evicting and restoring BOs */ struct delayed_work eviction_work; @@ -971,7 +970,7 @@ struct kfd_process { struct work_struct debug_event_workarea; /* Tracks debug per-vmid request for debug flags */ - bool dbg_flags; + u32 dbg_flags; atomic_t poison; /* Queues are in paused stated because we are in the process of doing a CRIU checkpoint */ @@ -1462,7 +1461,14 @@ void kfd_signal_reset_event(struct kfd_node *dev); void kfd_signal_poison_consumed_event(struct kfd_node *dev, u32 pasid); -void kfd_flush_tlb(struct kfd_process_device *pdd, enum TLB_FLUSH_TYPE type); +static inline void kfd_flush_tlb(struct kfd_process_device *pdd, + enum TLB_FLUSH_TYPE type) +{ + struct amdgpu_device *adev = pdd->dev->adev; + struct amdgpu_vm *vm = drm_priv_to_vm(pdd->drm_priv); + + amdgpu_vm_flush_compute_tlb(adev, vm, type, pdd->dev->xcc_mask); +} static inline bool kfd_flush_tlb_after_unmap(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 7a33e06f5c9009..717a60d7a4ea95 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -664,7 +664,8 @@ int kfd_process_create_wq(void) if (!kfd_process_wq) kfd_process_wq = alloc_workqueue("kfd_process_wq", 0, 0); if (!kfd_restore_wq) - kfd_restore_wq = alloc_ordered_workqueue("kfd_restore_wq", 0); + kfd_restore_wq = alloc_ordered_workqueue("kfd_restore_wq", + WQ_FREEZABLE); if (!kfd_process_wq || !kfd_restore_wq) { kfd_process_destroy_wq(); @@ -1109,6 +1110,7 @@ static void kfd_process_wq_release(struct work_struct *work) { struct kfd_process *p = container_of(work, struct kfd_process, release_work); + struct dma_fence *ef; kfd_process_dequeue_from_all_devices(p); pqm_uninit(&p->pqm); @@ -1117,7 +1119,9 @@ static void kfd_process_wq_release(struct work_struct *work) * destroyed. This allows any BOs to be freed without * triggering pointless evictions or waiting for fences. */ - dma_fence_signal(p->ef); + synchronize_rcu(); + ef = rcu_access_pointer(p->ef); + dma_fence_signal(ef); kfd_process_remove_sysfs(p); @@ -1126,7 +1130,7 @@ static void kfd_process_wq_release(struct work_struct *work) svm_range_list_fini(p); kfd_process_destroy_pdds(p); - dma_fence_put(p->ef); + dma_fence_put(ef); kfd_event_free_process(p); @@ -1642,6 +1646,7 @@ int kfd_process_device_init_vm(struct kfd_process_device *pdd, struct amdgpu_fpriv *drv_priv; struct amdgpu_vm *avm; struct kfd_process *p; + struct dma_fence *ef; struct kfd_node *dev; int ret; @@ -1661,13 +1666,13 @@ int kfd_process_device_init_vm(struct kfd_process_device *pdd, ret = amdgpu_amdkfd_gpuvm_acquire_process_vm(dev->adev, avm, &p->kgd_process_info, - &p->ef); + &ef); if (ret) { pr_err("Failed to create process VM object\n"); return ret; } + RCU_INIT_POINTER(p->ef, ef); pdd->drm_priv = drm_file->private_data; - atomic64_set(&pdd->tlb_seq, 0); ret = kfd_process_device_reserve_ib_mem(pdd); if (ret) @@ -1909,6 +1914,21 @@ kfd_process_gpuid_from_node(struct kfd_process *p, struct kfd_node *node, return -EINVAL; } +static int signal_eviction_fence(struct kfd_process *p) +{ + struct dma_fence *ef; + int ret; + + rcu_read_lock(); + ef = dma_fence_get_rcu_safe(&p->ef); + rcu_read_unlock(); + + ret = dma_fence_signal(ef); + dma_fence_put(ef); + + return ret; +} + static void evict_process_worker(struct work_struct *work) { int ret; @@ -1921,31 +1941,46 @@ static void evict_process_worker(struct work_struct *work) * lifetime of this thread, kfd_process p will be valid */ p = container_of(dwork, struct kfd_process, eviction_work); - WARN_ONCE(p->last_eviction_seqno != p->ef->seqno, - "Eviction fence mismatch\n"); - - /* Narrow window of overlap between restore and evict work - * item is possible. Once amdgpu_amdkfd_gpuvm_restore_process_bos - * unreserves KFD BOs, it is possible to evicted again. But - * restore has few more steps of finish. So lets wait for any - * previous restore work to complete - */ - flush_delayed_work(&p->restore_work); pr_debug("Started evicting pasid 0x%x\n", p->pasid); ret = kfd_process_evict_queues(p, KFD_QUEUE_EVICTION_TRIGGER_TTM); if (!ret) { - dma_fence_signal(p->ef); - dma_fence_put(p->ef); - p->ef = NULL; - queue_delayed_work(kfd_restore_wq, &p->restore_work, + /* If another thread already signaled the eviction fence, + * they are responsible stopping the queues and scheduling + * the restore work. + */ + if (!signal_eviction_fence(p)) + queue_delayed_work(kfd_restore_wq, &p->restore_work, msecs_to_jiffies(PROCESS_RESTORE_TIME_MS)); + else + kfd_process_restore_queues(p); pr_debug("Finished evicting pasid 0x%x\n", p->pasid); } else pr_err("Failed to evict queues of pasid 0x%x\n", p->pasid); } +static int restore_process_helper(struct kfd_process *p) +{ + int ret = 0; + + /* VMs may not have been acquired yet during debugging. */ + if (p->kgd_process_info) { + ret = amdgpu_amdkfd_gpuvm_restore_process_bos( + p->kgd_process_info, &p->ef); + if (ret) + return ret; + } + + ret = kfd_process_restore_queues(p); + if (!ret) + pr_debug("Finished restoring pasid 0x%x\n", p->pasid); + else + pr_err("Failed to restore queues of pasid 0x%x\n", p->pasid); + + return ret; +} + static void restore_process_worker(struct work_struct *work) { struct delayed_work *dwork; @@ -1971,24 +2006,15 @@ static void restore_process_worker(struct work_struct *work) */ p->last_restore_timestamp = get_jiffies_64(); - /* VMs may not have been acquired yet during debugging. */ - if (p->kgd_process_info) - ret = amdgpu_amdkfd_gpuvm_restore_process_bos(p->kgd_process_info, - &p->ef); + + ret = restore_process_helper(p); if (ret) { pr_debug("Failed to restore BOs of pasid 0x%x, retry after %d ms\n", p->pasid, PROCESS_BACK_OFF_TIME_MS); ret = queue_delayed_work(kfd_restore_wq, &p->restore_work, msecs_to_jiffies(PROCESS_BACK_OFF_TIME_MS)); WARN(!ret, "reschedule restore work failed\n"); - return; } - - ret = kfd_process_restore_queues(p); - if (!ret) - pr_debug("Finished restoring pasid 0x%x\n", p->pasid); - else - pr_err("Failed to restore queues of pasid 0x%x\n", p->pasid); } void kfd_suspend_all_processes(void) @@ -1999,14 +2025,9 @@ void kfd_suspend_all_processes(void) WARN(debug_evictions, "Evicting all processes"); hash_for_each_rcu(kfd_processes_table, temp, p, kfd_processes) { - cancel_delayed_work_sync(&p->eviction_work); - flush_delayed_work(&p->restore_work); - if (kfd_process_evict_queues(p, KFD_QUEUE_EVICTION_TRIGGER_SUSPEND)) pr_err("Failed to suspend process 0x%x\n", p->pasid); - dma_fence_signal(p->ef); - dma_fence_put(p->ef); - p->ef = NULL; + signal_eviction_fence(p); } srcu_read_unlock(&kfd_processes_srcu, idx); } @@ -2018,7 +2039,7 @@ int kfd_resume_all_processes(void) int ret = 0, idx = srcu_read_lock(&kfd_processes_srcu); hash_for_each_rcu(kfd_processes_table, temp, p, kfd_processes) { - if (!queue_delayed_work(kfd_restore_wq, &p->restore_work, 0)) { + if (restore_process_helper(p)) { pr_err("Restore process %d failed during resume\n", p->pasid); ret = -EFAULT; @@ -2059,36 +2080,6 @@ int kfd_reserved_mem_mmap(struct kfd_node *dev, struct kfd_process *process, KFD_CWSR_TBA_TMA_SIZE, vma->vm_page_prot); } -void kfd_flush_tlb(struct kfd_process_device *pdd, enum TLB_FLUSH_TYPE type) -{ - struct amdgpu_vm *vm = drm_priv_to_vm(pdd->drm_priv); - uint64_t tlb_seq = amdgpu_vm_tlb_seq(vm); - struct kfd_node *dev = pdd->dev; - uint32_t xcc_mask = dev->xcc_mask; - int xcc = 0; - - /* - * It can be that we race and lose here, but that is extremely unlikely - * and the worst thing which could happen is that we flush the changes - * into the TLB once more which is harmless. - */ - if (atomic64_xchg(&pdd->tlb_seq, tlb_seq) == tlb_seq) - return; - - if (dev->dqm->sched_policy == KFD_SCHED_POLICY_NO_HWS) { - /* Nothing to flush until a VMID is assigned, which - * only happens when the first queue is created. - */ - if (pdd->qpd.vmid) - amdgpu_amdkfd_flush_gpu_tlb_vmid(dev->adev, - pdd->qpd.vmid); - } else { - for_each_inst(xcc, xcc_mask) - amdgpu_amdkfd_flush_gpu_tlb_pasid( - dev->adev, pdd->process->pasid, type, xcc); - } -} - /* assumes caller holds process lock. */ int kfd_process_drain_interrupts(struct kfd_process_device *pdd) { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c index 77f493262e0584..43eff221eae58c 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c @@ -87,6 +87,8 @@ void kfd_process_dequeue_from_device(struct kfd_process_device *pdd) return; dev->dqm->ops.process_termination(dev->dqm, &pdd->qpd); + if (dev->kfd->shared_resources.enable_mes) + amdgpu_mes_flush_shader_debugger(dev->adev, pdd->proc_ctx_gpu_addr); pdd->already_dequeued = true; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index a15bfb5223e8fe..c50a0dc9c9c072 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -198,6 +198,7 @@ svm_range_dma_map_dev(struct amdgpu_device *adev, struct svm_range *prange, pr_debug_ratelimited("dma mapping 0x%llx for page addr 0x%lx\n", addr[i] >> PAGE_SHIFT, page_to_pfn(page)); } + return 0; } @@ -349,6 +350,7 @@ svm_range *svm_range_new(struct svm_range_list *svms, uint64_t start, INIT_LIST_HEAD(&prange->child_list); atomic_set(&prange->invalid, 0); prange->validate_timestamp = 0; + prange->vram_pages = 0; mutex_init(&prange->migrate_mutex); mutex_init(&prange->lock); @@ -395,19 +397,16 @@ static void svm_range_bo_release(struct kref *kref) prange->start, prange->last); mutex_lock(&prange->lock); prange->svm_bo = NULL; + /* prange should not hold vram page now */ + WARN_ONCE(prange->actual_loc, "prange should not hold vram page"); mutex_unlock(&prange->lock); spin_lock(&svm_bo->list_lock); } spin_unlock(&svm_bo->list_lock); - if (!dma_fence_is_signaled(&svm_bo->eviction_fence->base)) { - /* We're not in the eviction worker. - * Signal the fence and synchronize with any - * pending eviction work. - */ + if (!dma_fence_is_signaled(&svm_bo->eviction_fence->base)) + /* We're not in the eviction worker. Signal the fence. */ dma_fence_signal(&svm_bo->eviction_fence->base); - cancel_work_sync(&svm_bo->eviction_work); - } dma_fence_put(&svm_bo->eviction_fence->base); amdgpu_bo_unref(&svm_bo->bo); kfree(svm_bo); @@ -878,14 +877,29 @@ static void svm_range_debug_dump(struct svm_range_list *svms) static void * svm_range_copy_array(void *psrc, size_t size, uint64_t num_elements, - uint64_t offset) + uint64_t offset, uint64_t *vram_pages) { + unsigned char *src = (unsigned char *)psrc + offset; unsigned char *dst; + uint64_t i; dst = kvmalloc_array(num_elements, size, GFP_KERNEL); if (!dst) return NULL; - memcpy(dst, (unsigned char *)psrc + offset, num_elements * size); + + if (!vram_pages) { + memcpy(dst, src, num_elements * size); + return (void *)dst; + } + + *vram_pages = 0; + for (i = 0; i < num_elements; i++) { + dma_addr_t *temp; + temp = (dma_addr_t *)dst + i; + *temp = *((dma_addr_t *)src + i); + if (*temp&SVM_RANGE_VRAM_DOMAIN) + (*vram_pages)++; + } return (void *)dst; } @@ -899,7 +913,7 @@ svm_range_copy_dma_addrs(struct svm_range *dst, struct svm_range *src) if (!src->dma_addr[i]) continue; dst->dma_addr[i] = svm_range_copy_array(src->dma_addr[i], - sizeof(*src->dma_addr[i]), src->npages, 0); + sizeof(*src->dma_addr[i]), src->npages, 0, NULL); if (!dst->dma_addr[i]) return -ENOMEM; } @@ -910,7 +924,7 @@ svm_range_copy_dma_addrs(struct svm_range *dst, struct svm_range *src) static int svm_range_split_array(void *ppnew, void *ppold, size_t size, uint64_t old_start, uint64_t old_n, - uint64_t new_start, uint64_t new_n) + uint64_t new_start, uint64_t new_n, uint64_t *new_vram_pages) { unsigned char *new, *old, *pold; uint64_t d; @@ -922,11 +936,12 @@ svm_range_split_array(void *ppnew, void *ppold, size_t size, return 0; d = (new_start - old_start) * size; - new = svm_range_copy_array(pold, size, new_n, d); + /* get dma addr array for new range and calculte its vram page number */ + new = svm_range_copy_array(pold, size, new_n, d, new_vram_pages); if (!new) return -ENOMEM; d = (new_start == old_start) ? new_n * size : 0; - old = svm_range_copy_array(pold, size, old_n, d); + old = svm_range_copy_array(pold, size, old_n, d, NULL); if (!old) { kvfree(new); return -ENOMEM; @@ -948,10 +963,13 @@ svm_range_split_pages(struct svm_range *new, struct svm_range *old, for (i = 0; i < MAX_GPU_INSTANCE; i++) { r = svm_range_split_array(&new->dma_addr[i], &old->dma_addr[i], sizeof(*old->dma_addr[i]), old->start, - npages, new->start, new->npages); + npages, new->start, new->npages, + old->actual_loc ? &new->vram_pages : NULL); if (r) return r; } + if (old->actual_loc) + old->vram_pages -= new->vram_pages; return 0; } @@ -1097,7 +1115,7 @@ static int svm_range_split_tail(struct svm_range *prange, uint64_t new_last, struct list_head *insert_list, struct list_head *remap_list) { - struct svm_range *tail; + struct svm_range *tail = NULL; int r = svm_range_split(prange, prange->start, new_last, &tail); if (!r) { @@ -1112,7 +1130,7 @@ static int svm_range_split_head(struct svm_range *prange, uint64_t new_start, struct list_head *insert_list, struct list_head *remap_list) { - struct svm_range *head; + struct svm_range *head = NULL; int r = svm_range_split(prange, new_start, prange->last, &head); if (!r) { @@ -1135,66 +1153,6 @@ svm_range_add_child(struct svm_range *prange, struct mm_struct *mm, list_add_tail(&pchild->child_list, &prange->child_list); } -/** - * svm_range_split_by_granularity - collect ranges within granularity boundary - * - * @p: the process with svms list - * @mm: mm structure - * @addr: the vm fault address in pages, to split the prange - * @parent: parent range if prange is from child list - * @prange: prange to split - * - * Trims @prange to be a single aligned block of prange->granularity if - * possible. The head and tail are added to the child_list in @parent. - * - * Context: caller must hold mmap_read_lock and prange->lock - * - * Return: - * 0 - OK, otherwise error code - */ -int -svm_range_split_by_granularity(struct kfd_process *p, struct mm_struct *mm, - unsigned long addr, struct svm_range *parent, - struct svm_range *prange) -{ - struct svm_range *head, *tail; - unsigned long start, last, size; - int r; - - /* Align splited range start and size to granularity size, then a single - * PTE will be used for whole range, this reduces the number of PTE - * updated and the L1 TLB space used for translation. - */ - size = 1UL << prange->granularity; - start = ALIGN_DOWN(addr, size); - last = ALIGN(addr + 1, size) - 1; - - pr_debug("svms 0x%p split [0x%lx 0x%lx] to [0x%lx 0x%lx] size 0x%lx\n", - prange->svms, prange->start, prange->last, start, last, size); - - if (start > prange->start) { - r = svm_range_split(prange, start, prange->last, &head); - if (r) - return r; - svm_range_add_child(parent, mm, head, SVM_OP_ADD_RANGE); - } - - if (last < prange->last) { - r = svm_range_split(prange, prange->start, last, &tail); - if (r) - return r; - svm_range_add_child(parent, mm, tail, SVM_OP_ADD_RANGE); - } - - /* xnack on, update mapping on GPUs with ACCESS_IN_PLACE */ - if (p->xnack_enabled && prange->work_item.op == SVM_OP_ADD_RANGE) { - prange->work_item.op = SVM_OP_ADD_RANGE_AND_MAP; - pr_debug("change prange 0x%p [0x%lx 0x%lx] op %d\n", - prange, prange->start, prange->last, - SVM_OP_ADD_RANGE_AND_MAP); - } - return 0; -} static bool svm_nodes_in_same_hive(struct kfd_node *node_a, struct kfd_node *node_b) { @@ -1529,7 +1487,7 @@ static int svm_range_reserve_bos(struct svm_validate_context *ctx, bool intr) uint32_t gpuidx; int r; - drm_exec_init(&ctx->exec, intr ? DRM_EXEC_INTERRUPTIBLE_WAIT: 0); + drm_exec_init(&ctx->exec, intr ? DRM_EXEC_INTERRUPTIBLE_WAIT: 0, 0); drm_exec_until_all_locked(&ctx->exec) { for_each_set_bit(gpuidx, ctx->bitmap, MAX_GPU_INSTANCE) { pdd = kfd_process_device_from_gpuidx(ctx->process, gpuidx); @@ -1614,6 +1572,7 @@ static void *kfd_svm_page_owner(struct kfd_process *p, int32_t gpuidx) * 5. Release page table (and SVM BO) reservation */ static int svm_range_validate_and_map(struct mm_struct *mm, + unsigned long map_start, unsigned long map_last, struct svm_range *prange, int32_t gpuidx, bool intr, bool wait, bool flush_tlb) { @@ -1694,10 +1653,12 @@ static int svm_range_validate_and_map(struct mm_struct *mm, } } - start = prange->start << PAGE_SHIFT; - end = (prange->last + 1) << PAGE_SHIFT; + start = map_start << PAGE_SHIFT; + end = (map_last + 1) << PAGE_SHIFT; for (addr = start; !r && addr < end; ) { struct hmm_range *hmm_range; + unsigned long map_start_vma; + unsigned long map_last_vma; struct vm_area_struct *vma; unsigned long next = 0; unsigned long offset; @@ -1725,7 +1686,7 @@ static int svm_range_validate_and_map(struct mm_struct *mm, } if (!r) { - offset = (addr - start) >> PAGE_SHIFT; + offset = (addr >> PAGE_SHIFT) - prange->start; r = svm_range_dma_map(prange, ctx->bitmap, offset, npages, hmm_range->hmm_pfns); if (r) @@ -1743,9 +1704,16 @@ static int svm_range_validate_and_map(struct mm_struct *mm, r = -EAGAIN; } - if (!r) - r = svm_range_map_to_gpus(prange, offset, npages, readonly, - ctx->bitmap, wait, flush_tlb); + if (!r) { + map_start_vma = max(map_start, prange->start + offset); + map_last_vma = min(map_last, prange->start + offset + npages - 1); + if (map_start_vma <= map_last_vma) { + offset = map_start_vma - prange->start; + npages = map_last_vma - map_start_vma + 1; + r = svm_range_map_to_gpus(prange, offset, npages, readonly, + ctx->bitmap, wait, flush_tlb); + } + } if (!r && next == end) prange->mapped_to_gpu = true; @@ -1838,8 +1806,8 @@ static void svm_range_restore_work(struct work_struct *work) */ mutex_lock(&prange->migrate_mutex); - r = svm_range_validate_and_map(mm, prange, MAX_GPU_INSTANCE, - false, true, false); + r = svm_range_validate_and_map(mm, prange->start, prange->last, prange, + MAX_GPU_INSTANCE, false, true, false); if (r) pr_debug("failed %d to map 0x%lx to gpus\n", r, prange->start); @@ -1876,7 +1844,7 @@ out_reschedule: /* If validation failed, reschedule another attempt */ if (evicted_ranges) { pr_debug("reschedule to restore svm range\n"); - schedule_delayed_work(&svms->restore_work, + queue_delayed_work(system_freezable_wq, &svms->restore_work, msecs_to_jiffies(AMDGPU_SVM_RANGE_RESTORE_DELAY_MS)); kfd_smi_event_queue_restore_rescheduled(mm); @@ -1952,7 +1920,7 @@ svm_range_evict(struct svm_range *prange, struct mm_struct *mm, pr_debug("failed to quiesce KFD\n"); pr_debug("schedule to restore svm %p ranges\n", svms); - schedule_delayed_work(&svms->restore_work, + queue_delayed_work(system_freezable_wq, &svms->restore_work, msecs_to_jiffies(AMDGPU_SVM_RANGE_RESTORE_DELAY_MS)); } else { unsigned long s, l; @@ -2007,6 +1975,7 @@ static struct svm_range *svm_range_clone(struct svm_range *old) new->actual_loc = old->actual_loc; new->granularity = old->granularity; new->mapped_to_gpu = old->mapped_to_gpu; + new->vram_pages = old->vram_pages; bitmap_copy(new->bitmap_access, old->bitmap_access, MAX_GPU_INSTANCE); bitmap_copy(new->bitmap_aip, old->bitmap_aip, MAX_GPU_INSTANCE); @@ -2371,8 +2340,10 @@ retry: mutex_unlock(&svms->lock); mmap_write_unlock(mm); - /* Pairs with mmget in svm_range_add_list_work */ - mmput(mm); + /* Pairs with mmget in svm_range_add_list_work. If dropping the + * last mm refcount, schedule release work to avoid circular locking + */ + mmput_async(mm); spin_lock(&svms->deferred_list_lock); } @@ -2683,6 +2654,7 @@ svm_range_get_range_boundaries(struct kfd_process *p, int64_t addr, { struct vm_area_struct *vma; struct interval_tree_node *node; + struct rb_node *rb_node; unsigned long start_limit, end_limit; vma = vma_lookup(p->mm, addr << PAGE_SHIFT); @@ -2702,16 +2674,15 @@ svm_range_get_range_boundaries(struct kfd_process *p, int64_t addr, if (node) { end_limit = min(end_limit, node->start); /* Last range that ends before the fault address */ - node = container_of(rb_prev(&node->rb), - struct interval_tree_node, rb); + rb_node = rb_prev(&node->rb); } else { /* Last range must end before addr because * there was no range after addr */ - node = container_of(rb_last(&p->svms.objects.rb_root), - struct interval_tree_node, rb); + rb_node = rb_last(&p->svms.objects.rb_root); } - if (node) { + if (rb_node) { + node = container_of(rb_node, struct interval_tree_node, rb); if (node->last >= addr) { WARN(1, "Overlap with prev node and page fault addr\n"); return -EFAULT; @@ -2914,6 +2885,7 @@ svm_range_restore_pages(struct amdgpu_device *adev, unsigned int pasid, uint32_t vmid, uint32_t node_id, uint64_t addr, bool write_fault) { + unsigned long start, last, size; struct mm_struct *mm = NULL; struct svm_range_list *svms; struct svm_range *prange; @@ -3049,40 +3021,44 @@ retry_write_locked: kfd_smi_event_page_fault_start(node, p->lead_thread->pid, addr, write_fault, timestamp); - if (prange->actual_loc != best_loc) { + /* Align migration range start and size to granularity size */ + size = 1UL << prange->granularity; + start = max_t(unsigned long, ALIGN_DOWN(addr, size), prange->start); + last = min_t(unsigned long, ALIGN(addr + 1, size) - 1, prange->last); + if (prange->actual_loc != 0 || best_loc != 0) { migration = true; + if (best_loc) { - r = svm_migrate_to_vram(prange, best_loc, mm, - KFD_MIGRATE_TRIGGER_PAGEFAULT_GPU); + r = svm_migrate_to_vram(prange, best_loc, start, last, + mm, KFD_MIGRATE_TRIGGER_PAGEFAULT_GPU); if (r) { pr_debug("svm_migrate_to_vram failed (%d) at %llx, falling back to system memory\n", r, addr); /* Fallback to system memory if migration to * VRAM failed */ - if (prange->actual_loc) - r = svm_migrate_vram_to_ram(prange, mm, - KFD_MIGRATE_TRIGGER_PAGEFAULT_GPU, - NULL); + if (prange->actual_loc && prange->actual_loc != best_loc) + r = svm_migrate_vram_to_ram(prange, mm, start, last, + KFD_MIGRATE_TRIGGER_PAGEFAULT_GPU, NULL); else r = 0; } } else { - r = svm_migrate_vram_to_ram(prange, mm, - KFD_MIGRATE_TRIGGER_PAGEFAULT_GPU, - NULL); + r = svm_migrate_vram_to_ram(prange, mm, start, last, + KFD_MIGRATE_TRIGGER_PAGEFAULT_GPU, NULL); } if (r) { pr_debug("failed %d to migrate svms %p [0x%lx 0x%lx]\n", - r, svms, prange->start, prange->last); + r, svms, start, last); goto out_unlock_range; } } - r = svm_range_validate_and_map(mm, prange, gpuidx, false, false, false); + r = svm_range_validate_and_map(mm, start, last, prange, gpuidx, false, + false, false); if (r) pr_debug("failed %d to map svms 0x%p [0x%lx 0x%lx] to gpus\n", - r, svms, prange->start, prange->last); + r, svms, start, last); kfd_smi_event_page_fault_end(node, p->lead_thread->pid, addr, migration); @@ -3428,18 +3404,24 @@ svm_range_trigger_migration(struct mm_struct *mm, struct svm_range *prange, *migrated = false; best_loc = svm_range_best_prefetch_location(prange); - if (best_loc == KFD_IOCTL_SVM_LOCATION_UNDEFINED || - best_loc == prange->actual_loc) + /* when best_loc is a gpu node and same as prange->actual_loc + * we still need do migration as prange->actual_loc !=0 does + * not mean all pages in prange are vram. hmm migrate will pick + * up right pages during migration. + */ + if ((best_loc == KFD_IOCTL_SVM_LOCATION_UNDEFINED) || + (best_loc == 0 && prange->actual_loc == 0)) return 0; if (!best_loc) { - r = svm_migrate_vram_to_ram(prange, mm, + r = svm_migrate_vram_to_ram(prange, mm, prange->start, prange->last, KFD_MIGRATE_TRIGGER_PREFETCH, NULL); *migrated = !r; return r; } - r = svm_migrate_to_vram(prange, best_loc, mm, KFD_MIGRATE_TRIGGER_PREFETCH); + r = svm_migrate_to_vram(prange, best_loc, prange->start, prange->last, + mm, KFD_MIGRATE_TRIGGER_PREFETCH); *migrated = !r; return r; @@ -3447,13 +3429,14 @@ svm_range_trigger_migration(struct mm_struct *mm, struct svm_range *prange, int svm_range_schedule_evict_svm_bo(struct amdgpu_amdkfd_fence *fence) { - if (!fence) - return -EINVAL; - - if (dma_fence_is_signaled(&fence->base)) - return 0; - - if (fence->svm_bo) { + /* Dereferencing fence->svm_bo is safe here because the fence hasn't + * signaled yet and we're under the protection of the fence->lock. + * After the fence is signaled in svm_range_bo_release, we cannot get + * here any more. + * + * Reference is dropped in svm_range_evict_svm_bo_worker. + */ + if (svm_bo_ref_unless_zero(fence->svm_bo)) { WRITE_ONCE(fence->svm_bo->evicting, 1); schedule_work(&fence->svm_bo->eviction_work); } @@ -3468,8 +3451,6 @@ static void svm_range_evict_svm_bo_worker(struct work_struct *work) int r = 0; svm_bo = container_of(work, struct svm_range_bo, eviction_work); - if (!svm_bo_ref_unless_zero(svm_bo)) - return; /* svm_bo was freed while eviction was pending */ if (mmget_not_zero(svm_bo->eviction_fence->mm)) { mm = svm_bo->eviction_fence->mm; @@ -3494,7 +3475,11 @@ static void svm_range_evict_svm_bo_worker(struct work_struct *work) mutex_lock(&prange->migrate_mutex); do { + /* migrate all vram pages in this prange to sys ram + * after that prange->actual_loc should be zero + */ r = svm_migrate_vram_to_ram(prange, mm, + prange->start, prange->last, KFD_MIGRATE_TRIGGER_TTM_EVICTION, NULL); } while (!r && prange->actual_loc && --retries); @@ -3618,8 +3603,8 @@ svm_range_set_attr(struct kfd_process *p, struct mm_struct *mm, flush_tlb = !migrated && update_mapping && prange->mapped_to_gpu; - r = svm_range_validate_and_map(mm, prange, MAX_GPU_INSTANCE, - true, true, flush_tlb); + r = svm_range_validate_and_map(mm, prange->start, prange->last, prange, + MAX_GPU_INSTANCE, true, true, flush_tlb); if (r) pr_debug("failed %d to map svm range\n", r); @@ -3633,8 +3618,8 @@ out_unlock_range: pr_debug("Remapping prange 0x%p [0x%lx 0x%lx]\n", prange, prange->start, prange->last); mutex_lock(&prange->migrate_mutex); - r = svm_range_validate_and_map(mm, prange, MAX_GPU_INSTANCE, - true, true, prange->mapped_to_gpu); + r = svm_range_validate_and_map(mm, prange->start, prange->last, prange, + MAX_GPU_INSTANCE, true, true, prange->mapped_to_gpu); if (r) pr_debug("failed %d on remap svm range\n", r); mutex_unlock(&prange->migrate_mutex); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h index c528df1d0ba2c6..026863a0abcd3e 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.h @@ -78,6 +78,7 @@ struct svm_work_list_item { * @update_list:link list node used to add to update_list * @mapping: bo_va mapping structure to create and update GPU page table * @npages: number of pages + * @vram_pages: vram pages number in this svm_range * @dma_addr: dma mapping address on each GPU for system memory physical page * @ttm_res: vram ttm resource map * @offset: range start offset within mm_nodes @@ -88,7 +89,9 @@ struct svm_work_list_item { * @flags: flags defined as KFD_IOCTL_SVM_FLAG_* * @perferred_loc: perferred location, 0 for CPU, or GPU id * @perfetch_loc: last prefetch location, 0 for CPU, or GPU id - * @actual_loc: the actual location, 0 for CPU, or GPU id + * @actual_loc: this svm_range location. 0: all pages are from sys ram; + * GPU id: this svm_range may include vram pages from GPU with + * id actual_loc. * @granularity:migration granularity, log2 num pages * @invalid: not 0 means cpu page table is invalidated * @validate_timestamp: system timestamp when range is validated @@ -112,6 +115,7 @@ struct svm_range { struct list_head list; struct list_head update_list; uint64_t npages; + uint64_t vram_pages; dma_addr_t *dma_addr[MAX_GPU_INSTANCE]; struct ttm_resource *ttm_res; uint64_t offset; @@ -168,9 +172,6 @@ struct kfd_node *svm_range_get_node_by_id(struct svm_range *prange, int svm_range_vram_node_new(struct kfd_node *node, struct svm_range *prange, bool clear); void svm_range_vram_node_free(struct svm_range *prange); -int svm_range_split_by_granularity(struct kfd_process *p, struct mm_struct *mm, - unsigned long addr, struct svm_range *parent, - struct svm_range *prange); int svm_range_restore_pages(struct amdgpu_device *adev, unsigned int pasid, uint32_t vmid, uint32_t node_id, uint64_t addr, bool write_fault); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index 057284bf50bbea..e5f7c92eebcbbf 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -1342,10 +1342,11 @@ static int kfd_create_indirect_link_prop(struct kfd_topology_device *kdev, int g num_cpu++; } + if (list_empty(&kdev->io_link_props)) + return -ENODATA; + gpu_link = list_first_entry(&kdev->io_link_props, - struct kfd_iolink_properties, list); - if (!gpu_link) - return -ENOMEM; + struct kfd_iolink_properties, list); for (i = 0; i < num_cpu; i++) { /* CPU <--> GPU */ @@ -1423,15 +1424,17 @@ static int kfd_add_peer_prop(struct kfd_topology_device *kdev, peer->gpu->adev)) return ret; + if (list_empty(&kdev->io_link_props)) + return -ENODATA; + iolink1 = list_first_entry(&kdev->io_link_props, - struct kfd_iolink_properties, list); - if (!iolink1) - return -ENOMEM; + struct kfd_iolink_properties, list); + + if (list_empty(&peer->io_link_props)) + return -ENODATA; iolink2 = list_first_entry(&peer->io_link_props, - struct kfd_iolink_properties, list); - if (!iolink2) - return -ENOMEM; + struct kfd_iolink_properties, list); props = kfd_alloc_struct(props); if (!props) @@ -1449,17 +1452,19 @@ static int kfd_add_peer_prop(struct kfd_topology_device *kdev, /* CPU->CPU link*/ cpu_dev = kfd_topology_device_by_proximity_domain(iolink1->node_to); if (cpu_dev) { - list_for_each_entry(iolink3, &cpu_dev->io_link_props, list) - if (iolink3->node_to == iolink2->node_to) - break; - - props->weight += iolink3->weight; - props->min_latency += iolink3->min_latency; - props->max_latency += iolink3->max_latency; - props->min_bandwidth = min(props->min_bandwidth, - iolink3->min_bandwidth); - props->max_bandwidth = min(props->max_bandwidth, - iolink3->max_bandwidth); + list_for_each_entry(iolink3, &cpu_dev->io_link_props, list) { + if (iolink3->node_to != iolink2->node_to) + continue; + + props->weight += iolink3->weight; + props->min_latency += iolink3->min_latency; + props->max_latency += iolink3->max_latency; + props->min_bandwidth = min(props->min_bandwidth, + iolink3->min_bandwidth); + props->max_bandwidth = min(props->max_bandwidth, + iolink3->max_bandwidth); + break; + } } else { WARN(1, "CPU node not found"); } diff --git a/drivers/gpu/drm/amd/display/Makefile b/drivers/gpu/drm/amd/display/Makefile index af17ab8027dfda..92a5c5efcf9262 100644 --- a/drivers/gpu/drm/amd/display/Makefile +++ b/drivers/gpu/drm/amd/display/Makefile @@ -30,6 +30,9 @@ subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/inc/ subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/inc/hw subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/clk_mgr subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/hwss +subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/resource +subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/dsc +subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/optc subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/inc subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/freesync subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/color diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile index 8bf94920d23ea3..ab2a97e354da1f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile @@ -25,22 +25,25 @@ +ifneq ($(CONFIG_DRM_AMD_DC),) AMDGPUDM = \ amdgpu_dm.o \ amdgpu_dm_plane.o \ amdgpu_dm_crtc.o \ amdgpu_dm_irq.o \ amdgpu_dm_mst_types.o \ - amdgpu_dm_color.o + amdgpu_dm_color.o \ + amdgpu_dm_services.o \ + amdgpu_dm_helpers.o \ + amdgpu_dm_pp_smu.o \ + amdgpu_dm_psr.o \ + amdgpu_dm_replay.o \ + amdgpu_dm_wb.o ifdef CONFIG_DRM_AMD_DC_FP AMDGPUDM += dc_fpu.o endif -ifneq ($(CONFIG_DRM_AMD_DC),) -AMDGPUDM += amdgpu_dm_services.o amdgpu_dm_helpers.o amdgpu_dm_pp_smu.o amdgpu_dm_psr.o amdgpu_dm_replay.o -endif - AMDGPUDM += amdgpu_dm_hdcp.o ifneq ($(CONFIG_DEBUG_FS),) @@ -52,3 +55,4 @@ subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc AMDGPU_DM = $(addprefix $(AMDDALPATH)/amdgpu_dm/,$(AMDGPUDM)) AMD_DISPLAY_FILES += $(AMDGPU_DM) +endif 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 4e82ee4d74aca2..6cda5b53636265 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -37,6 +37,7 @@ #include "dc/dc_dmub_srv.h" #include "dc/dc_edid_parser.h" #include "dc/dc_stat.h" +#include "dc/dc_state.h" #include "amdgpu_dm_trace.h" #include "dpcd_defs.h" #include "link/protocols/link_dpcd.h" @@ -54,6 +55,7 @@ #include "amdgpu_dm_crtc.h" #include "amdgpu_dm_hdcp.h" #include +#include "amdgpu_dm_wb.h" #include "amdgpu_pm.h" #include "amdgpu_atombios.h" @@ -65,7 +67,6 @@ #include "amdgpu_dm_debugfs.h" #endif #include "amdgpu_dm_psr.h" -#include "amdgpu_dm_replay.h" #include "ivsrcid/ivsrcid_vislands30.h" @@ -85,12 +86,13 @@ #include #include #include +#include #include #include +#include #include #include #include -#include #include @@ -270,6 +272,7 @@ static int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc, { u32 v_blank_start, v_blank_end, h_position, v_position; struct amdgpu_crtc *acrtc = NULL; + struct dc *dc = adev->dm.dc; if ((crtc < 0) || (crtc >= adev->mode_info.num_crtc)) return -EINVAL; @@ -282,6 +285,9 @@ static int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc, return 0; } + if (dc && dc->caps.ips_support && dc->idle_optimizations_allowed) + dc_allow_idle_optimizations(dc, false); + /* * TODO rework base driver to use values directly. * for now parse it back into reg-format @@ -575,6 +581,7 @@ static void dm_crtc_high_irq(void *interrupt_params) { struct common_irq_params *irq_params = interrupt_params; struct amdgpu_device *adev = irq_params->adev; + struct drm_writeback_job *job; struct amdgpu_crtc *acrtc; unsigned long flags; int vrr_active; @@ -583,6 +590,33 @@ static void dm_crtc_high_irq(void *interrupt_params) if (!acrtc) return; + if (acrtc->wb_pending) { + if (acrtc->wb_conn) { + spin_lock_irqsave(&acrtc->wb_conn->job_lock, flags); + job = list_first_entry_or_null(&acrtc->wb_conn->job_queue, + struct drm_writeback_job, + list_entry); + spin_unlock_irqrestore(&acrtc->wb_conn->job_lock, flags); + + if (job) { + unsigned int v_total, refresh_hz; + struct dc_stream_state *stream = acrtc->dm_irq_params.stream; + + v_total = stream->adjust.v_total_max ? + stream->adjust.v_total_max : stream->timing.v_total; + refresh_hz = div_u64((uint64_t) stream->timing.pix_clk_100hz * + 100LL, (v_total * stream->timing.h_total)); + mdelay(1000 / refresh_hz); + + drm_writeback_signal_completion(acrtc->wb_conn, 0); + dc_stream_fc_disable_writeback(adev->dm.dc, + acrtc->dm_irq_params.stream, 0); + } + } else + DRM_ERROR("%s: no amdgpu_crtc wb_conn\n", __func__); + acrtc->wb_pending = false; + } + vrr_active = amdgpu_dm_crtc_vrr_active_irq(acrtc); drm_dbg_vbl(adev_to_drm(adev), @@ -725,6 +759,10 @@ static void dmub_hpd_callback(struct amdgpu_device *adev, drm_connector_list_iter_begin(dev, &iter); drm_for_each_connector_iter(connector, &iter) { + + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + aconnector = to_amdgpu_dm_connector(connector); if (link && aconnector->dc_link == link) { if (notify->type == DMUB_NOTIFICATION_HPD) @@ -894,8 +932,7 @@ static int dm_early_init(void *handle); /* Allocate memory for FBC compressed data */ static void amdgpu_dm_fbc_init(struct drm_connector *connector) { - struct drm_device *dev = connector->dev; - struct amdgpu_device *adev = drm_to_adev(dev); + struct amdgpu_device *adev = drm_to_adev(connector->dev); struct dm_compressor_info *compressor = &adev->dm.compressor; struct amdgpu_dm_connector *aconn = to_amdgpu_dm_connector(connector); struct drm_display_mode *mode; @@ -949,6 +986,10 @@ static int amdgpu_dm_audio_component_get_eld(struct device *kdev, int port, drm_connector_list_iter_begin(dev, &conn_iter); drm_for_each_connector_iter(connector, &conn_iter) { + + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + aconnector = to_amdgpu_dm_connector(connector); if (aconnector->audio_inst != port) continue; @@ -989,8 +1030,7 @@ static int amdgpu_dm_audio_component_bind(struct device *kdev, static void amdgpu_dm_audio_component_unbind(struct device *kdev, struct device *hda_kdev, void *data) { - struct drm_device *dev = dev_get_drvdata(kdev); - struct amdgpu_device *adev = drm_to_adev(dev); + struct amdgpu_device *adev = drm_to_adev(dev_get_drvdata(kdev)); struct drm_audio_component *acomp = data; acomp->ops = NULL; @@ -1258,7 +1298,9 @@ 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.fb_start >> 18; - if (adev->apu_flags & AMD_APU_IS_RAVEN2) + if (adev->apu_flags & (AMD_APU_IS_RAVEN2 | + AMD_APU_IS_RENOIR | + AMD_APU_IS_GREEN_SARDINE)) /* * Raven2 has a HW issue that it is unable to use the vram which * is out of MC_VM_SYSTEM_APERTURE_HIGH_ADDR. So here is the @@ -1270,7 +1312,9 @@ static void mmhub_read_system_context(struct amdgpu_device *adev, struct dc_phy_ logical_addr_high = adev->gmc.fb_end >> 18; } else { logical_addr_low = min(adev->gmc.fb_start, adev->gmc.agp_start) >> 18; - if (adev->apu_flags & AMD_APU_IS_RAVEN2) + if (adev->apu_flags & (AMD_APU_IS_RAVEN2 | + AMD_APU_IS_RENOIR | + AMD_APU_IS_GREEN_SARDINE)) /* * Raven2 has a HW issue that it is unable to use the vram which * is out of MC_VM_SYSTEM_APERTURE_HIGH_ADDR. So here is the @@ -1675,6 +1719,15 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) init_data.nbio_reg_offsets = adev->reg_offset[NBIO_HWIP][0]; init_data.clk_reg_offsets = adev->reg_offset[CLK_HWIP][0]; + if (amdgpu_dc_debug_mask & DC_DISABLE_IPS) + init_data.flags.disable_ips = DMUB_IPS_DISABLE_ALL; + + init_data.flags.disable_ips_in_vpb = 1; + + /* Enable DWB for tested platforms only */ + if (amdgpu_ip_version(adev, DCE_HWIP, 0) >= IP_VERSION(3, 0, 0)) + init_data.num_virtual_links = 1; + INIT_LIST_HEAD(&adev->dm.da_list); retrieve_dmi_info(&adev->dm); @@ -1717,23 +1770,6 @@ 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"); @@ -2269,6 +2305,10 @@ static int detect_mst_link_for_all_connectors(struct drm_device *dev) drm_connector_list_iter_begin(dev, &iter); drm_for_each_connector_iter(connector, &iter) { + + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + aconnector = to_amdgpu_dm_connector(connector); if (aconnector->dc_link->type == dc_connection_mst_branch && aconnector->mst_mgr.aux) { @@ -2397,6 +2437,10 @@ static void s3_handle_mst(struct drm_device *dev, bool suspend) drm_connector_list_iter_begin(dev, &iter); drm_for_each_connector_iter(connector, &iter) { + + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + aconnector = to_amdgpu_dm_connector(connector); if (aconnector->dc_link->type != dc_connection_mst_branch || aconnector->mst_root) @@ -2576,12 +2620,10 @@ static enum dc_status amdgpu_dm_commit_zero_streams(struct dc *dc) memset(del_streams, 0, sizeof(del_streams)); - context = dc_create_state(dc); + context = dc_state_create_current_copy(dc); if (context == NULL) goto context_alloc_fail; - dc_resource_state_copy_construct_current(dc, context); - /* First remove from context all streams */ for (i = 0; i < context->stream_count; i++) { struct dc_stream_state *stream = context->streams[i]; @@ -2591,12 +2633,12 @@ static enum dc_status amdgpu_dm_commit_zero_streams(struct dc *dc) /* Remove all planes for removed streams and then remove the streams */ for (i = 0; i < del_streams_count; i++) { - if (!dc_rem_all_planes_for_stream(dc, del_streams[i], context)) { + if (!dc_state_rem_all_planes_for_stream(dc, del_streams[i], context)) { res = DC_FAIL_DETACH_SURFACES; goto fail; } - res = dc_remove_stream_from_ctx(dc, context, del_streams[i]); + res = dc_state_remove_stream(dc, context, del_streams[i]); if (res != DC_OK) goto fail; } @@ -2604,7 +2646,7 @@ static enum dc_status amdgpu_dm_commit_zero_streams(struct dc *dc) res = dc_commit_streams(dc, context->streams, context->stream_count); fail: - dc_release_state(context); + dc_state_release(context); context_alloc_fail: return res; @@ -2631,7 +2673,7 @@ static int dm_suspend(void *handle) dc_allow_idle_optimizations(adev->dm.dc, false); - dm->cached_dc_state = dc_copy_state(dm->dc->current_state); + dm->cached_dc_state = dc_state_create_copy(dm->dc->current_state); dm_gpureset_toggle_interrupts(adev, dm->cached_dc_state, false); @@ -2656,11 +2698,12 @@ static int dm_suspend(void *handle) hpd_rx_irq_work_suspend(dm); dc_set_power_state(dm->dc, DC_ACPI_CM_POWER_STATE_D3); + dc_dmub_srv_set_power_state(dm->dc->ctx->dmub_srv, DC_ACPI_CM_POWER_STATE_D3); return 0; } -struct amdgpu_dm_connector * +struct drm_connector * amdgpu_dm_find_first_crtc_matching_connector(struct drm_atomic_state *state, struct drm_crtc *crtc) { @@ -2673,7 +2716,7 @@ amdgpu_dm_find_first_crtc_matching_connector(struct drm_atomic_state *state, crtc_from_state = new_con_state->crtc; if (crtc_from_state == crtc) - return to_amdgpu_dm_connector(connector); + return connector; } return NULL; @@ -2824,7 +2867,7 @@ static int dm_resume(void *handle) bool need_hotplug = false; if (dm->dc->caps.ips_support) { - dc_dmub_srv_exit_low_power_state(dm->dc); + dc_dmub_srv_apply_idle_power_optimizations(dm->dc, false); } if (amdgpu_in_reset(adev)) { @@ -2851,6 +2894,7 @@ static int dm_resume(void *handle) if (r) DRM_ERROR("DMUB interface failed to initialize: status=%d\n", r); + dc_dmub_srv_set_power_state(dm->dc->ctx->dmub_srv, DC_ACPI_CM_POWER_STATE_D0); dc_set_power_state(dm->dc, DC_ACPI_CM_POWER_STATE_D0); dc_resume(dm->dc); @@ -2876,7 +2920,7 @@ static int dm_resume(void *handle) dm_gpureset_toggle_interrupts(adev, dm->cached_dc_state, true); - dc_release_state(dm->cached_dc_state); + dc_state_release(dm->cached_dc_state); dm->cached_dc_state = NULL; amdgpu_dm_irq_resume_late(adev); @@ -2886,10 +2930,9 @@ static int dm_resume(void *handle) return 0; } /* Recreate dc_state - DC invalidates it when setting power state to S3. */ - dc_release_state(dm_state->context); - dm_state->context = dc_create_state(dm->dc); + dc_state_release(dm_state->context); + dm_state->context = dc_state_create(dm->dc); /* TODO: Remove dc_state->dccg, use dc->dccg directly. */ - dc_resource_state_construct(dm->dc, dm_state->context); /* Before powering on DC we need to re-initialize DMUB. */ dm_dmub_hw_resume(adev); @@ -2901,6 +2944,7 @@ static int dm_resume(void *handle) } /* power on hardware */ + dc_dmub_srv_set_power_state(dm->dc->ctx->dmub_srv, DC_ACPI_CM_POWER_STATE_D0); dc_set_power_state(dm->dc, DC_ACPI_CM_POWER_STATE_D0); /* program HPD filter */ @@ -2918,6 +2962,10 @@ static int dm_resume(void *handle) /* Do detection*/ drm_connector_list_iter_begin(ddev, &iter); drm_for_each_connector_iter(connector, &iter) { + + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + aconnector = to_amdgpu_dm_connector(connector); if (!aconnector->dc_link) @@ -3491,6 +3539,9 @@ static void register_hpd_handlers(struct amdgpu_device *adev) list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + aconnector = to_amdgpu_dm_connector(connector); dc_link = aconnector->dc_link; @@ -3957,7 +4008,7 @@ dm_atomic_duplicate_state(struct drm_private_obj *obj) old_state = to_dm_atomic_state(obj->state); if (old_state && old_state->context) - new_state->context = dc_copy_state(old_state->context); + new_state->context = dc_state_create_copy(old_state->context); if (!new_state->context) { kfree(new_state); @@ -3973,7 +4024,7 @@ static void dm_atomic_destroy_state(struct drm_private_obj *obj, struct dm_atomic_state *dm_state = to_dm_atomic_state(state); if (dm_state && dm_state->context) - dc_release_state(dm_state->context); + dc_state_release(dm_state->context); kfree(dm_state); } @@ -4009,14 +4060,12 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev) if (!state) return -ENOMEM; - state->context = dc_create_state(adev->dm.dc); + state->context = dc_state_create_current_copy(adev->dm.dc); if (!state->context) { kfree(state); return -ENOMEM; } - dc_resource_state_copy_construct_current(adev->dm.dc, state->context); - drm_atomic_private_obj_init(adev_to_drm(adev), &adev->dm.atomic_obj, &state->base, @@ -4024,14 +4073,19 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev) r = amdgpu_display_modeset_create_props(adev); if (r) { - dc_release_state(state->context); + dc_state_release(state->context); kfree(state); return r; } +#ifdef AMD_PRIVATE_COLOR + if (amdgpu_dm_create_color_properties(adev)) + return -ENOMEM; +#endif + r = amdgpu_dm_audio_init(adev); if (r) { - dc_release_state(state->context); + dc_state_release(state->context); kfree(state); return r; } @@ -4345,7 +4399,6 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) enum dc_connection_type new_connection_type = dc_connection_none; const struct dc_plane_cap *plane; bool psr_feature_enabled = false; - bool replay_feature_enabled = false; int max_overlay = dm->dc->caps.max_slave_planes; dm->display_indexes_num = dm->dc->caps.max_streams; @@ -4457,20 +4510,6 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) } } - if (!(amdgpu_dc_debug_mask & DC_DISABLE_REPLAY)) { - switch (adev->ip_versions[DCE_HWIP][0]) { - case IP_VERSION(3, 1, 4): - case IP_VERSION(3, 1, 5): - case IP_VERSION(3, 1, 6): - case IP_VERSION(3, 2, 0): - case IP_VERSION(3, 2, 1): - replay_feature_enabled = true; - break; - default: - replay_feature_enabled = amdgpu_dc_feature_mask & DC_REPLAY_MASK; - break; - } - } /* loops over all connectors on the board */ for (i = 0; i < link_cnt; i++) { struct dc_link *link = NULL; @@ -4482,6 +4521,28 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) continue; } + link = dc_get_link_at_index(dm->dc, i); + + if (link->connector_signal == SIGNAL_TYPE_VIRTUAL) { + struct amdgpu_dm_wb_connector *wbcon = kzalloc(sizeof(*wbcon), GFP_KERNEL); + + if (!wbcon) { + DRM_ERROR("KMS: Failed to allocate writeback connector\n"); + continue; + } + + if (amdgpu_dm_wb_connector_init(dm, wbcon, i)) { + DRM_ERROR("KMS: Failed to initialize writeback connector\n"); + kfree(wbcon); + continue; + } + + link->psr_settings.psr_feature_enabled = false; + link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED; + + continue; + } + aconnector = kzalloc(sizeof(*aconnector), GFP_KERNEL); if (!aconnector) goto fail; @@ -4500,8 +4561,6 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) goto fail; } - link = dc_get_link_at_index(dm->dc, i); - if (!dc_link_detect_connection_type(link, &new_connection_type)) DRM_ERROR("KMS: Failed to detect connector\n"); @@ -4519,12 +4578,6 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) amdgpu_dm_update_connector_after_detect(aconnector); setup_backlight_device(dm, aconnector); - /* - * Disable psr if replay can be enabled - */ - if (replay_feature_enabled && amdgpu_dm_setup_replay(link, aconnector)) - psr_feature_enabled = false; - if (psr_feature_enabled) amdgpu_dm_set_psr_caps(link); @@ -5106,7 +5159,9 @@ static int fill_dc_plane_attributes(struct amdgpu_device *adev, * Always set input transfer function, since plane state is refreshed * every time. */ - ret = amdgpu_dm_update_plane_color_mgmt(dm_crtc_state, dc_plane_state); + ret = amdgpu_dm_update_plane_color_mgmt(dm_crtc_state, + plane_state, + dc_plane_state); if (ret) return ret; @@ -5511,10 +5566,13 @@ static void fill_stream_properties_from_drm_display_mode( { struct dc_crtc_timing *timing_out = &stream->timing; const struct drm_display_info *info = &connector->display_info; - struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); + struct amdgpu_dm_connector *aconnector = NULL; struct hdmi_vendor_infoframe hv_frame; struct hdmi_avi_infoframe avi_frame; + if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) + aconnector = to_amdgpu_dm_connector(connector); + memset(&hv_frame, 0, sizeof(hv_frame)); memset(&avi_frame, 0, sizeof(avi_frame)); @@ -5527,6 +5585,7 @@ static void fill_stream_properties_from_drm_display_mode( && stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420; else if (drm_mode_is_420_also(info, mode_in) + && aconnector && aconnector->force_yuv420_output) timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420; else if ((connector->display_info.color_formats & DRM_COLOR_FORMAT_YCBCR444) @@ -5562,7 +5621,7 @@ static void fill_stream_properties_from_drm_display_mode( timing_out->hdmi_vic = hv_frame.vic; } - if (is_freesync_video_mode(mode_in, aconnector)) { + if (aconnector && is_freesync_video_mode(mode_in, aconnector)) { timing_out->h_addressable = mode_in->hdisplay; timing_out->h_total = mode_in->htotal; timing_out->h_sync_width = mode_in->hsync_end - mode_in->hsync_start; @@ -5683,13 +5742,13 @@ decide_crtc_timing_for_drm_display_mode(struct drm_display_mode *drm_mode, } static struct dc_sink * -create_fake_sink(struct amdgpu_dm_connector *aconnector) +create_fake_sink(struct dc_link *link) { struct dc_sink_init_data sink_init_data = { 0 }; struct dc_sink *sink = NULL; - sink_init_data.link = aconnector->dc_link; - sink_init_data.sink_signal = aconnector->dc_link->connector_signal; + sink_init_data.link = link; + sink_init_data.sink_signal = link->connector_signal; sink = dc_sink_create(&sink_init_data); if (!sink) { @@ -6039,14 +6098,14 @@ static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector, } static struct dc_stream_state * -create_stream_for_sink(struct amdgpu_dm_connector *aconnector, +create_stream_for_sink(struct drm_connector *connector, const struct drm_display_mode *drm_mode, const struct dm_connector_state *dm_state, const struct dc_stream_state *old_stream, int requested_bpc) { + struct amdgpu_dm_connector *aconnector = NULL; struct drm_display_mode *preferred_mode = NULL; - struct drm_connector *drm_connector; const struct drm_connector_state *con_state = &dm_state->base; struct dc_stream_state *stream = NULL; struct drm_display_mode mode; @@ -6060,22 +6119,35 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, enum color_transfer_func tf = TRANSFER_FUNC_UNKNOWN; struct dsc_dec_dpcd_caps dsc_caps; + struct dc_link *link = NULL; struct dc_sink *sink = NULL; drm_mode_init(&mode, drm_mode); memset(&saved_mode, 0, sizeof(saved_mode)); - if (aconnector == NULL) { - DRM_ERROR("aconnector is NULL!\n"); + if (connector == NULL) { + DRM_ERROR("connector is NULL!\n"); return stream; } - drm_connector = &aconnector->base; + if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) { + aconnector = NULL; + aconnector = to_amdgpu_dm_connector(connector); + link = aconnector->dc_link; + } else { + struct drm_writeback_connector *wbcon = NULL; + struct amdgpu_dm_wb_connector *dm_wbcon = NULL; + + wbcon = drm_connector_to_writeback(connector); + dm_wbcon = to_amdgpu_dm_wb_connector(wbcon); + link = dm_wbcon->link; + } - if (!aconnector->dc_sink) { - sink = create_fake_sink(aconnector); + if (!aconnector || !aconnector->dc_sink) { + sink = create_fake_sink(link); if (!sink) return stream; + } else { sink = aconnector->dc_sink; dc_sink_retain(sink); @@ -6088,12 +6160,13 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, goto finish; } + /* We leave this NULL for writeback connectors */ stream->dm_stream_context = aconnector; stream->timing.flags.LTE_340MCSC_SCRAMBLE = - drm_connector->display_info.hdmi.scdc.scrambling.low_rates; + connector->display_info.hdmi.scdc.scrambling.low_rates; - list_for_each_entry(preferred_mode, &aconnector->base.modes, head) { + list_for_each_entry(preferred_mode, &connector->modes, head) { /* Search for preferred mode */ if (preferred_mode->type & DRM_MODE_TYPE_PREFERRED) { native_mode_found = true; @@ -6102,7 +6175,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, } if (!native_mode_found) preferred_mode = list_first_entry_or_null( - &aconnector->base.modes, + &connector->modes, struct drm_display_mode, head); @@ -6116,7 +6189,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, * and the modelist may not be filled in time. */ DRM_DEBUG_DRIVER("No preferred mode found\n"); - } else { + } else if (aconnector) { recalculate_timing = is_freesync_video_mode(&mode, aconnector); if (recalculate_timing) { freesync_mode = get_highest_refresh_rate_mode(aconnector, false); @@ -6139,13 +6212,17 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, */ if (!scale || mode_refresh != preferred_refresh) fill_stream_properties_from_drm_display_mode( - stream, &mode, &aconnector->base, con_state, NULL, + stream, &mode, connector, con_state, NULL, requested_bpc); else fill_stream_properties_from_drm_display_mode( - stream, &mode, &aconnector->base, con_state, old_stream, + stream, &mode, connector, con_state, old_stream, requested_bpc); + /* The rest isn't needed for writeback connectors */ + if (!aconnector) + goto finish; + if (aconnector->timing_changed) { drm_dbg(aconnector->base.dev, "overriding timing for automated test, bpc %d, changing to %d\n", @@ -6163,7 +6240,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, fill_audio_info( &stream->audio_info, - drm_connector, + connector, sink); update_stream_signal(stream, sink); @@ -6570,7 +6647,7 @@ static enum dc_status dm_validate_stream_and_context(struct dc *dc, if (!dc_plane_state) goto cleanup; - dc_state = dc_create_state(dc); + dc_state = dc_state_create(dc); if (!dc_state) goto cleanup; @@ -6597,9 +6674,9 @@ static enum dc_status dm_validate_stream_and_context(struct dc *dc, dc_result = dc_validate_plane(dc, dc_plane_state); if (dc_result == DC_OK) - dc_result = dc_add_stream_to_ctx(dc, dc_state, stream); + dc_result = dc_state_add_stream(dc, dc_state, stream); - if (dc_result == DC_OK && !dc_add_plane_to_context( + if (dc_result == DC_OK && !dc_state_add_plane( dc, stream, dc_plane_state, @@ -6611,7 +6688,7 @@ static enum dc_status dm_validate_stream_and_context(struct dc *dc, cleanup: if (dc_state) - dc_release_state(dc_state); + dc_state_release(dc_state); if (dc_plane_state) dc_plane_state_release(dc_plane_state); @@ -6633,7 +6710,7 @@ create_validate_stream_for_sink(struct amdgpu_dm_connector *aconnector, enum dc_status dc_result = DC_OK; do { - stream = create_stream_for_sink(aconnector, drm_mode, + stream = create_stream_for_sink(connector, drm_mode, dm_state, old_stream, requested_bpc); if (stream == NULL) { @@ -6641,6 +6718,9 @@ create_validate_stream_for_sink(struct amdgpu_dm_connector *aconnector, break; } + if (aconnector->base.connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + return stream; + dc_result = dc_validate_stream(adev->dm.dc, stream); if (dc_result == DC_OK && stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) dc_result = dm_dp_mst_is_port_support_mode(aconnector, stream); @@ -6916,7 +6996,7 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder, if (IS_ERR(mst_state)) return PTR_ERR(mst_state); - mst_state->pbn_div = dm_mst_get_pbn_divider(aconnector->mst_root->dc_link); + mst_state->pbn_div.full = dfixed_const(dm_mst_get_pbn_divider(aconnector->mst_root->dc_link)); if (!state->duplicated) { int max_bpc = conn_state->max_requested_bpc; @@ -6928,7 +7008,7 @@ static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder, max_bpc); bpp = convert_dc_color_depth_into_bpc(color_depth) * 3; clock = adjusted_mode->clock; - dm_new_connector_state->pbn = drm_dp_calc_pbn_mode(clock, bpp, false); + dm_new_connector_state->pbn = drm_dp_calc_pbn_mode(clock, bpp << 4); } dm_new_connector_state->vcpi_slots = @@ -6960,6 +7040,9 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_state *state, for_each_new_connector_in_state(state, connector, new_con_state, i) { + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + aconnector = to_amdgpu_dm_connector(connector); if (!aconnector->mst_output_port) @@ -7539,7 +7622,6 @@ create_i2c(struct ddc_service *ddc_service, if (!i2c) return NULL; i2c->base.owner = THIS_MODULE; - i2c->base.class = I2C_CLASS_DDC; i2c->base.dev.parent = &adev->pdev->dev; i2c->base.algo = &amdgpu_dm_i2c_algo; snprintf(i2c->base.name, sizeof(i2c->base.name), "AMDGPU DM i2c hw bus %d", link_index); @@ -7565,6 +7647,7 @@ static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm, struct dc_link *link = dc_get_link_at_index(dc, link_index); struct amdgpu_i2c_adapter *i2c; + /* Not needed for writeback connector */ link->priv = aconnector; @@ -8175,6 +8258,10 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, bundle->surface_updates[planes_count].gamma = dc_plane->gamma_correction; bundle->surface_updates[planes_count].in_transfer_func = dc_plane->in_transfer_func; bundle->surface_updates[planes_count].gamut_remap_matrix = &dc_plane->gamut_remap_matrix; + bundle->surface_updates[planes_count].hdr_mult = dc_plane->hdr_mult; + bundle->surface_updates[planes_count].func_shaper = dc_plane->in_shaper_func; + bundle->surface_updates[planes_count].lut3d_func = dc_plane->lut3d_func; + bundle->surface_updates[planes_count].blend_tf = dc_plane->blend_tf; } amdgpu_dm_plane_fill_dc_scaling_info(dm->adev, new_plane_state, @@ -8386,6 +8473,10 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, &acrtc_state->stream->csc_color_matrix; bundle->stream_update.out_transfer_func = acrtc_state->stream->out_transfer_func; + bundle->stream_update.lut3d_func = + (struct dc_3dlut *) acrtc_state->stream->lut3d_func; + bundle->stream_update.func_shaper = + (struct dc_transfer_func *) acrtc_state->stream->func_shaper; } acrtc_state->stream->abm_level = acrtc_state->abm_level; @@ -8519,6 +8610,9 @@ static void amdgpu_dm_commit_audio(struct drm_device *dev, if (!drm_atomic_crtc_needs_modeset(new_crtc_state)) continue; + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + notify: aconnector = to_amdgpu_dm_connector(connector); @@ -8552,6 +8646,9 @@ notify: if (!status) continue; + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + aconnector = to_amdgpu_dm_connector(connector); mutex_lock(&adev->dm.audio_lock); @@ -8577,6 +8674,12 @@ static void amdgpu_dm_crtc_copy_transient_flags(struct drm_crtc_state *crtc_stat stream_state->mode_changed = drm_atomic_crtc_needs_modeset(crtc_state); } +static void dm_clear_writeback(struct amdgpu_display_manager *dm, + struct dm_crtc_state *crtc_state) +{ + dc_stream_remove_writeback(dm->dc, crtc_state->stream, 0); +} + static void amdgpu_dm_commit_streams(struct drm_atomic_state *state, struct dc_state *dc_state) { @@ -8586,9 +8689,38 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state, struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state, *new_crtc_state; struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state; + struct drm_connector_state *old_con_state; + struct drm_connector *connector; bool mode_set_reset_required = false; u32 i; + /* Disable writeback */ + for_each_old_connector_in_state(state, connector, old_con_state, i) { + struct dm_connector_state *dm_old_con_state; + struct amdgpu_crtc *acrtc; + + if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) + continue; + + old_crtc_state = NULL; + + dm_old_con_state = to_dm_connector_state(old_con_state); + if (!dm_old_con_state->base.crtc) + continue; + + acrtc = to_amdgpu_crtc(dm_old_con_state->base.crtc); + if (acrtc) + old_crtc_state = drm_atomic_get_old_crtc_state(state, &acrtc->base); + + if (!acrtc->wb_enabled) + continue; + + dm_old_crtc_state = to_dm_crtc_state(old_crtc_state); + + dm_clear_writeback(dm, dm_old_crtc_state); + acrtc->wb_enabled = false; + } + for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); @@ -8713,7 +8845,7 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state, dc_stream_get_status(dm_new_crtc_state->stream); if (!status) - status = dc_stream_get_status_from_state(dc_state, + status = dc_state_get_stream_status(dc_state, dm_new_crtc_state->stream); if (!status) drm_err(dev, @@ -8725,6 +8857,105 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_state *state, } } +static void dm_set_writeback(struct amdgpu_display_manager *dm, + struct dm_crtc_state *crtc_state, + struct drm_connector *connector, + struct drm_connector_state *new_con_state) +{ + struct drm_writeback_connector *wb_conn = drm_connector_to_writeback(connector); + struct amdgpu_device *adev = dm->adev; + struct amdgpu_crtc *acrtc; + struct dc_writeback_info *wb_info; + struct pipe_ctx *pipe = NULL; + struct amdgpu_framebuffer *afb; + int i = 0; + + wb_info = kzalloc(sizeof(*wb_info), GFP_KERNEL); + if (!wb_info) { + DRM_ERROR("Failed to allocate wb_info\n"); + return; + } + + acrtc = to_amdgpu_crtc(wb_conn->encoder.crtc); + if (!acrtc) { + DRM_ERROR("no amdgpu_crtc found\n"); + kfree(wb_info); + return; + } + + afb = to_amdgpu_framebuffer(new_con_state->writeback_job->fb); + if (!afb) { + DRM_ERROR("No amdgpu_framebuffer found\n"); + kfree(wb_info); + return; + } + + for (i = 0; i < MAX_PIPES; i++) { + if (dm->dc->current_state->res_ctx.pipe_ctx[i].stream == crtc_state->stream) { + pipe = &dm->dc->current_state->res_ctx.pipe_ctx[i]; + break; + } + } + + /* fill in wb_info */ + wb_info->wb_enabled = true; + + wb_info->dwb_pipe_inst = 0; + wb_info->dwb_params.dwbscl_black_color = 0; + wb_info->dwb_params.hdr_mult = 0x1F000; + wb_info->dwb_params.csc_params.gamut_adjust_type = CM_GAMUT_ADJUST_TYPE_BYPASS; + wb_info->dwb_params.csc_params.gamut_coef_format = CM_GAMUT_REMAP_COEF_FORMAT_S2_13; + wb_info->dwb_params.output_depth = DWB_OUTPUT_PIXEL_DEPTH_10BPC; + wb_info->dwb_params.cnv_params.cnv_out_bpc = DWB_CNV_OUT_BPC_10BPC; + + /* width & height from crtc */ + wb_info->dwb_params.cnv_params.src_width = acrtc->base.mode.crtc_hdisplay; + wb_info->dwb_params.cnv_params.src_height = acrtc->base.mode.crtc_vdisplay; + wb_info->dwb_params.dest_width = acrtc->base.mode.crtc_hdisplay; + wb_info->dwb_params.dest_height = acrtc->base.mode.crtc_vdisplay; + + wb_info->dwb_params.cnv_params.crop_en = false; + wb_info->dwb_params.stereo_params.stereo_enabled = false; + + wb_info->dwb_params.cnv_params.out_max_pix_val = 0x3ff; // 10 bits + wb_info->dwb_params.cnv_params.out_min_pix_val = 0; + wb_info->dwb_params.cnv_params.fc_out_format = DWB_OUT_FORMAT_32BPP_ARGB; + wb_info->dwb_params.cnv_params.out_denorm_mode = DWB_OUT_DENORM_BYPASS; + + wb_info->dwb_params.out_format = dwb_scaler_mode_bypass444; + + wb_info->dwb_params.capture_rate = dwb_capture_rate_0; + + wb_info->dwb_params.scaler_taps.h_taps = 4; + wb_info->dwb_params.scaler_taps.v_taps = 4; + wb_info->dwb_params.scaler_taps.h_taps_c = 2; + wb_info->dwb_params.scaler_taps.v_taps_c = 2; + wb_info->dwb_params.subsample_position = DWB_INTERSTITIAL_SUBSAMPLING; + + wb_info->mcif_buf_params.luma_pitch = afb->base.pitches[0]; + wb_info->mcif_buf_params.chroma_pitch = afb->base.pitches[1]; + + for (i = 0; i < DWB_MCIF_BUF_COUNT; i++) { + wb_info->mcif_buf_params.luma_address[i] = afb->address; + wb_info->mcif_buf_params.chroma_address[i] = 0; + } + + wb_info->mcif_buf_params.p_vmid = 1; + if (amdgpu_ip_version(adev, DCE_HWIP, 0) >= IP_VERSION(3, 0, 0)) { + wb_info->mcif_warmup_params.start_address.quad_part = afb->address; + wb_info->mcif_warmup_params.region_size = + wb_info->mcif_buf_params.luma_pitch * wb_info->dwb_params.dest_height; + } + wb_info->mcif_warmup_params.p_vmid = 1; + wb_info->writeback_source_plane = pipe->plane_state; + + dc_stream_add_writeback(dm->dc, crtc_state->stream, wb_info); + + acrtc->wb_pending = true; + acrtc->wb_conn = wb_conn; + drm_writeback_queue_job(wb_conn, new_con_state); +} + /** * amdgpu_dm_atomic_commit_tail() - AMDgpu DM's commit tail implementation. * @state: The atomic state to commit @@ -8752,16 +8983,8 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) trace_amdgpu_dm_atomic_commit_tail_begin(state); - if (dm->dc->caps.ips_support) { - for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) { - if (new_con_state->crtc && - new_con_state->crtc->state->active && - drm_atomic_crtc_needs_modeset(new_con_state->crtc->state)) { - dc_dmub_srv_exit_low_power_state(dm->dc); - break; - } - } - } + if (dm->dc->caps.ips_support && dm->dc->idle_optimizations_allowed) + dc_allow_idle_optimizations(dm->dc, false); drm_atomic_helper_update_legacy_modeset_state(dev, state); drm_dp_mst_atomic_wait_for_dependencies(state); @@ -8775,7 +8998,12 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) 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); + struct amdgpu_dm_connector *aconnector; + + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + + aconnector = to_amdgpu_dm_connector(connector); if (!adev->dm.hdcp_workqueue) continue; @@ -9052,6 +9280,31 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) amdgpu_dm_commit_planes(state, dev, dm, crtc, wait_for_vblank); } + /* Enable writeback */ + for_each_new_connector_in_state(state, connector, 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); + + if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) + continue; + + if (!new_con_state->writeback_job) + continue; + + new_crtc_state = drm_atomic_get_new_crtc_state(state, &acrtc->base); + + if (!new_crtc_state) + continue; + + if (acrtc->wb_enabled) + continue; + + dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); + + dm_set_writeback(dm, dm_new_crtc_state, connector, new_con_state); + acrtc->wb_enabled = true; + } + /* Update audio instances for each connector. */ amdgpu_dm_commit_audio(dev, state); @@ -9169,10 +9422,15 @@ out: void dm_restore_drm_connector_state(struct drm_device *dev, struct drm_connector *connector) { - struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); + struct amdgpu_dm_connector *aconnector; struct amdgpu_crtc *disconnected_acrtc; struct dm_crtc_state *acrtc_state; + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + return; + + aconnector = to_amdgpu_dm_connector(connector); + if (!aconnector->dc_sink || !connector->state || !connector->encoder) return; @@ -9249,12 +9507,16 @@ static void get_freesync_config_for_crtc( struct dm_connector_state *new_con_state) { struct mod_freesync_config config = {0}; - struct amdgpu_dm_connector *aconnector = - to_amdgpu_dm_connector(new_con_state->base.connector); + struct amdgpu_dm_connector *aconnector; struct drm_display_mode *mode = &new_crtc_state->base.mode; int vrefresh = drm_mode_vrefresh(mode); bool fs_vid_mode = false; + if (new_con_state->base.connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + return; + + aconnector = to_amdgpu_dm_connector(new_con_state->base.connector); + new_crtc_state->vrr_supported = new_con_state->freesync_capable && vrefresh >= aconnector->min_vfreq && vrefresh <= aconnector->max_vfreq; @@ -9354,6 +9616,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm, * update changed items */ struct amdgpu_crtc *acrtc = NULL; + struct drm_connector *connector = NULL; struct amdgpu_dm_connector *aconnector = NULL; struct drm_connector_state *drm_new_conn_state = NULL, *drm_old_conn_state = NULL; struct dm_connector_state *dm_new_conn_state = NULL, *dm_old_conn_state = NULL; @@ -9363,15 +9626,17 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm, dm_old_crtc_state = to_dm_crtc_state(old_crtc_state); dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); acrtc = to_amdgpu_crtc(crtc); - aconnector = amdgpu_dm_find_first_crtc_matching_connector(state, crtc); + connector = amdgpu_dm_find_first_crtc_matching_connector(state, crtc); + if (connector) + aconnector = to_amdgpu_dm_connector(connector); /* TODO This hack should go away */ - if (aconnector && enable) { + if (connector && enable) { /* Make sure fake sink is created in plug-in scenario */ drm_new_conn_state = drm_atomic_get_new_connector_state(state, - &aconnector->base); + connector); drm_old_conn_state = drm_atomic_get_old_connector_state(state, - &aconnector->base); + connector); if (IS_ERR(drm_new_conn_state)) { ret = PTR_ERR_OR_ZERO(drm_new_conn_state); @@ -9497,7 +9762,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm, crtc->base.id); /* i.e. reset mode */ - if (dc_remove_stream_from_ctx( + if (dc_state_remove_stream( dm->dc, dm_state->context, dm_old_crtc_state->stream) != DC_OK) { @@ -9518,7 +9783,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm, * added MST connectors not found in existing crtc_state in the chained mode * TODO: need to dig out the root cause of that */ - if (!aconnector) + if (!connector) goto skip_modeset; if (modereset_required(new_crtc_state)) @@ -9540,7 +9805,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm, DRM_DEBUG_ATOMIC("Enabling DRM crtc: %d\n", crtc->base.id); - if (dc_add_stream_to_ctx( + if (dc_state_add_stream( dm->dc, dm_state->context, dm_new_crtc_state->stream) != DC_OK) { @@ -9561,7 +9826,7 @@ skip_modeset: * We want to do dc stream updates that do not require a * full modeset below. */ - if (!(enable && aconnector && new_crtc_state->active)) + if (!(enable && connector && new_crtc_state->active)) return 0; /* * Given above conditions, the dc state cannot be NULL because: @@ -9587,6 +9852,7 @@ skip_modeset: * when a modeset is needed, to ensure it gets reprogrammed. */ if (dm_new_crtc_state->base.color_mgmt_changed || + dm_old_crtc_state->regamma_tf != dm_new_crtc_state->regamma_tf || drm_atomic_crtc_needs_modeset(new_crtc_state)) { ret = amdgpu_dm_update_crtc_color_mgmt(dm_new_crtc_state); if (ret) @@ -9620,7 +9886,8 @@ static bool should_reset_plane(struct drm_atomic_state *state, * TODO: Remove this hack for all asics once it proves that the * fast updates works fine on DCN3.2+. */ - if (adev->ip_versions[DCE_HWIP][0] < IP_VERSION(3, 2, 0) && state->allow_modeset) + if (amdgpu_ip_version(adev, DCE_HWIP, 0) < IP_VERSION(3, 2, 0) && + state->allow_modeset) return true; /* Exit early if we know that we're adding or removing the plane. */ @@ -9654,6 +9921,10 @@ static bool should_reset_plane(struct drm_atomic_state *state, */ for_each_oldnew_plane_in_state(state, other, old_other_state, new_other_state, i) { struct amdgpu_framebuffer *old_afb, *new_afb; + struct dm_plane_state *dm_new_other_state, *dm_old_other_state; + + dm_new_other_state = to_dm_plane_state(new_other_state); + dm_old_other_state = to_dm_plane_state(old_other_state); if (other->type == DRM_PLANE_TYPE_CURSOR) continue; @@ -9690,6 +9961,18 @@ static bool should_reset_plane(struct drm_atomic_state *state, old_other_state->color_encoding != new_other_state->color_encoding) return true; + /* HDR/Transfer Function changes. */ + if (dm_old_other_state->degamma_tf != dm_new_other_state->degamma_tf || + dm_old_other_state->degamma_lut != dm_new_other_state->degamma_lut || + dm_old_other_state->hdr_mult != dm_new_other_state->hdr_mult || + dm_old_other_state->ctm != dm_new_other_state->ctm || + dm_old_other_state->shaper_lut != dm_new_other_state->shaper_lut || + dm_old_other_state->shaper_tf != dm_new_other_state->shaper_tf || + dm_old_other_state->lut3d != dm_new_other_state->lut3d || + dm_old_other_state->blend_lut != dm_new_other_state->blend_lut || + dm_old_other_state->blend_tf != dm_new_other_state->blend_tf) + return true; + /* Framebuffer checks fall at the end. */ if (!old_other_state->fb || !new_other_state->fb) continue; @@ -9844,7 +10127,7 @@ static int dm_update_plane_state(struct dc *dc, if (ret) return ret; - if (!dc_remove_plane_from_context( + if (!dc_state_remove_plane( dc, dm_old_crtc_state->stream, dm_old_plane_state->dc_state, @@ -9922,7 +10205,7 @@ static int dm_update_plane_state(struct dc *dc, * state. It'll be released when the atomic state is * cleaned. */ - if (!dc_add_plane_to_context( + if (!dc_state_add_plane( dc, dm_new_crtc_state->stream, dc_new_plane_state, @@ -10084,6 +10367,9 @@ static int add_affected_mst_dsc_crtcs(struct drm_atomic_state *state, struct drm if (conn_state->crtc != crtc) continue; + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + aconnector = to_amdgpu_dm_connector(connector); if (!aconnector->mst_output_port || !aconnector->mst_root) aconnector = NULL; @@ -10603,7 +10889,7 @@ static bool dm_edid_parser_send_cea(struct amdgpu_display_manager *dm, input->cea_total_length = total_length; memcpy(input->payload, data, length); - res = dm_execute_dmub_cmd(dm->dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY); + res = dc_wake_and_execute_dmub_cmd(dm->dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY); if (!res) { DRM_ERROR("EDID CEA parser failed\n"); return false; @@ -10794,8 +11080,7 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, struct dm_connector_state *dm_con_state = NULL; struct dc_sink *sink; - struct drm_device *dev = connector->dev; - struct amdgpu_device *adev = drm_to_adev(dev); + struct amdgpu_device *adev = drm_to_adev(connector->dev); struct amdgpu_hdmi_vsdb_info vsdb_info = {0}; bool freesync_capable = false; enum adaptive_sync_type as_type = ADAPTIVE_SYNC_TYPE_NONE; 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 3d480be802cb5e..9c1871b866cc97 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -32,6 +32,7 @@ #include #include #include "link_service_types.h" +#include /* * This file contains the definition for amdgpu_display_manager @@ -54,6 +55,9 @@ #define HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_IEEE_REGISTRATION_ID 0x00001A #define AMD_VSDB_VERSION_3_FEATURECAP_REPLAYMODE 0x40 #define HDMI_AMD_VENDOR_SPECIFIC_DATA_BLOCK_VERSION_3 0x3 + +#define AMDGPU_HDR_MULT_DEFAULT (0x100000000LL) + /* #include "include/amdgpu_dal_power_if.h" #include "amdgpu_dm_irq.h" @@ -714,11 +718,107 @@ static inline void amdgpu_dm_set_mst_status(uint8_t *status, #define to_amdgpu_dm_connector(x) container_of(x, struct amdgpu_dm_connector, base) +struct amdgpu_dm_wb_connector { + struct drm_writeback_connector base; + struct dc_link *link; +}; + +#define to_amdgpu_dm_wb_connector(x) container_of(x, struct amdgpu_dm_wb_connector, base) + extern const struct amdgpu_ip_block_version dm_ip_block; +/* enum amdgpu_transfer_function: pre-defined transfer function supported by AMD. + * + * It includes standardized transfer functions and pure power functions. The + * transfer function coefficients are available at modules/color/color_gamma.c + */ +enum amdgpu_transfer_function { + AMDGPU_TRANSFER_FUNCTION_DEFAULT, + AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF, + AMDGPU_TRANSFER_FUNCTION_BT709_INV_OETF, + AMDGPU_TRANSFER_FUNCTION_PQ_EOTF, + AMDGPU_TRANSFER_FUNCTION_IDENTITY, + AMDGPU_TRANSFER_FUNCTION_GAMMA22_EOTF, + AMDGPU_TRANSFER_FUNCTION_GAMMA24_EOTF, + AMDGPU_TRANSFER_FUNCTION_GAMMA26_EOTF, + AMDGPU_TRANSFER_FUNCTION_SRGB_INV_EOTF, + AMDGPU_TRANSFER_FUNCTION_BT709_OETF, + AMDGPU_TRANSFER_FUNCTION_PQ_INV_EOTF, + AMDGPU_TRANSFER_FUNCTION_GAMMA22_INV_EOTF, + AMDGPU_TRANSFER_FUNCTION_GAMMA24_INV_EOTF, + AMDGPU_TRANSFER_FUNCTION_GAMMA26_INV_EOTF, + AMDGPU_TRANSFER_FUNCTION_COUNT +}; + struct dm_plane_state { struct drm_plane_state base; struct dc_plane_state *dc_state; + + /* Plane color mgmt */ + /** + * @degamma_lut: + * + * 1D LUT for mapping framebuffer/plane pixel data before sampling or + * blending operations. It's usually applied to linearize input space. + * The blob (if not NULL) is an array of &struct drm_color_lut. + */ + struct drm_property_blob *degamma_lut; + /** + * @degamma_tf: + * + * Predefined transfer function to tell DC driver the input space to + * linearize. + */ + enum amdgpu_transfer_function degamma_tf; + /** + * @hdr_mult: + * + * Multiplier to 'gain' the plane. When PQ is decoded using the fixed + * func transfer function to the internal FP16 fb, 1.0 -> 80 nits (on + * AMD at least). When sRGB is decoded, 1.0 -> 1.0, obviously. + * Therefore, 1.0 multiplier = 80 nits for SDR content. So if you + * want, 203 nits for SDR content, pass in (203.0 / 80.0). Format is + * S31.32 sign-magnitude. + * + * HDR multiplier can wide range beyond [0.0, 1.0]. This means that PQ + * TF is needed for any subsequent linear-to-non-linear transforms. + */ + __u64 hdr_mult; + /** + * @ctm: + * + * Color transformation matrix. The blob (if not NULL) is a &struct + * drm_color_ctm_3x4. + */ + struct drm_property_blob *ctm; + /** + * @shaper_lut: shaper lookup table blob. The blob (if not NULL) is an + * array of &struct drm_color_lut. + */ + struct drm_property_blob *shaper_lut; + /** + * @shaper_tf: + * + * Predefined transfer function to delinearize color space. + */ + enum amdgpu_transfer_function shaper_tf; + /** + * @lut3d: 3D lookup table blob. The blob (if not NULL) is an array of + * &struct drm_color_lut. + */ + struct drm_property_blob *lut3d; + /** + * @blend_lut: blend lut lookup table blob. The blob (if not NULL) is an + * array of &struct drm_color_lut. + */ + struct drm_property_blob *blend_lut; + /** + * @blend_tf: + * + * Pre-defined transfer function for converting plane pixel data before + * applying blend LUT. + */ + enum amdgpu_transfer_function blend_tf; }; struct dm_crtc_state { @@ -743,6 +843,14 @@ struct dm_crtc_state { struct dc_info_packet vrr_infopacket; int abm_level; + + /** + * @regamma_tf: + * + * Pre-defined transfer function for converting internal FB -> wire + * encoding. + */ + enum amdgpu_transfer_function regamma_tf; }; #define to_dm_crtc_state(x) container_of(x, struct dm_crtc_state, base) @@ -804,14 +912,22 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, void amdgpu_dm_trigger_timing_sync(struct drm_device *dev); +/* 3D LUT max size is 17x17x17 (4913 entries) */ +#define MAX_COLOR_3DLUT_SIZE 17 +#define MAX_COLOR_3DLUT_BITDEPTH 12 +int amdgpu_dm_verify_lut3d_size(struct amdgpu_device *adev, + struct drm_plane_state *plane_state); +/* 1D LUT size */ #define MAX_COLOR_LUT_ENTRIES 4096 /* Legacy gamm LUT users such as X doesn't like large LUT sizes */ #define MAX_COLOR_LEGACY_LUT_ENTRIES 256 void amdgpu_dm_init_color_mod(void); +int amdgpu_dm_create_color_properties(struct amdgpu_device *adev); int amdgpu_dm_verify_lut_sizes(const struct drm_crtc_state *crtc_state); int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc); int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, + struct drm_plane_state *plane_state, struct dc_plane_state *dc_plane_state); void amdgpu_dm_update_connector_after_detect( @@ -834,7 +950,7 @@ struct dc_stream_state * int dm_atomic_get_state(struct drm_atomic_state *state, struct dm_atomic_state **dm_state); -struct amdgpu_dm_connector * +struct drm_connector * amdgpu_dm_find_first_crtc_matching_connector(struct drm_atomic_state *state, struct drm_crtc *crtc); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index a4cb23d059bd6a..c87b64e464ed5c 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -72,6 +72,7 @@ */ #define MAX_DRM_LUT_VALUE 0xFFFF +#define SDR_WHITE_LEVEL_INIT_VALUE 80 /** * amdgpu_dm_init_color_mod - Initialize the color module. @@ -84,6 +85,247 @@ void amdgpu_dm_init_color_mod(void) setup_x_points_distribution(); } +static inline struct fixed31_32 amdgpu_dm_fixpt_from_s3132(__u64 x) +{ + struct fixed31_32 val; + + /* If negative, convert to 2's complement. */ + if (x & (1ULL << 63)) + x = -(x & ~(1ULL << 63)); + + val.value = x; + return val; +} + +#ifdef AMD_PRIVATE_COLOR +/* Pre-defined Transfer Functions (TF) + * + * AMD driver supports pre-defined mathematical functions for transferring + * between encoded values and optical/linear space. Depending on HW color caps, + * ROMs and curves built by the AMD color module support these transforms. + * + * The driver-specific color implementation exposes properties for pre-blending + * degamma TF, shaper TF (before 3D LUT), and blend(dpp.ogam) TF and + * post-blending regamma (mpc.ogam) TF. However, only pre-blending degamma + * supports ROM curves. AMD color module uses pre-defined coefficients to build + * curves for the other blocks. What can be done by each color block is + * described by struct dpp_color_capsand struct mpc_color_caps. + * + * AMD driver-specific color API exposes the following pre-defined transfer + * functions: + * + * - Identity: linear/identity relationship between pixel value and + * luminance value; + * - Gamma 2.2, Gamma 2.4, Gamma 2.6: pure power functions; + * - sRGB: 2.4: The piece-wise transfer function from IEC 61966-2-1:1999; + * - BT.709: has a linear segment in the bottom part and then a power function + * with a 0.45 (~1/2.22) gamma for the rest of the range; standardized by + * ITU-R BT.709-6; + * - PQ (Perceptual Quantizer): used for HDR display, allows luminance range + * capability of 0 to 10,000 nits; standardized by SMPTE ST 2084. + * + * The AMD color model is designed with an assumption that SDR (sRGB, BT.709, + * Gamma 2.2, etc.) peak white maps (normalized to 1.0 FP) to 80 nits in the PQ + * system. This has the implication that PQ EOTF (non-linear to linear) maps to + * [0.0..125.0] where 125.0 = 10,000 nits / 80 nits. + * + * Non-linear and linear forms are described in the table below: + * + * ┌───────────┬─────────────────────┬──────────────────────┐ + * │ │ Non-linear │ Linear │ + * ├───────────┼─────────────────────┼──────────────────────┤ + * │ sRGB │ UNORM or [0.0, 1.0] │ [0.0, 1.0] │ + * ├───────────┼─────────────────────┼──────────────────────┤ + * │ BT709 │ UNORM or [0.0, 1.0] │ [0.0, 1.0] │ + * ├───────────┼─────────────────────┼──────────────────────┤ + * │ Gamma 2.x │ UNORM or [0.0, 1.0] │ [0.0, 1.0] │ + * ├───────────┼─────────────────────┼──────────────────────┤ + * │ PQ │ UNORM or FP16 CCCS* │ [0.0, 125.0] │ + * ├───────────┼─────────────────────┼──────────────────────┤ + * │ Identity │ UNORM or FP16 CCCS* │ [0.0, 1.0] or CCCS** │ + * └───────────┴─────────────────────┴──────────────────────┘ + * * CCCS: Windows canonical composition color space + * ** Respectively + * + * In the driver-specific API, color block names attached to TF properties + * suggest the intention regarding non-linear encoding pixel's luminance + * values. As some newer encodings don't use gamma curve, we make encoding and + * decoding explicit by defining an enum list of transfer functions supported + * in terms of EOTF and inverse EOTF, where: + * + * - EOTF (electro-optical transfer function): is the transfer function to go + * from the encoded value to an optical (linear) value. De-gamma functions + * traditionally do this. + * - Inverse EOTF (simply the inverse of the EOTF): is usually intended to go + * from an optical/linear space (which might have been used for blending) + * back to the encoded values. Gamma functions traditionally do this. + */ +static const char * const +amdgpu_transfer_function_names[] = { + [AMDGPU_TRANSFER_FUNCTION_DEFAULT] = "Default", + [AMDGPU_TRANSFER_FUNCTION_IDENTITY] = "Identity", + [AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF] = "sRGB EOTF", + [AMDGPU_TRANSFER_FUNCTION_BT709_INV_OETF] = "BT.709 inv_OETF", + [AMDGPU_TRANSFER_FUNCTION_PQ_EOTF] = "PQ EOTF", + [AMDGPU_TRANSFER_FUNCTION_GAMMA22_EOTF] = "Gamma 2.2 EOTF", + [AMDGPU_TRANSFER_FUNCTION_GAMMA24_EOTF] = "Gamma 2.4 EOTF", + [AMDGPU_TRANSFER_FUNCTION_GAMMA26_EOTF] = "Gamma 2.6 EOTF", + [AMDGPU_TRANSFER_FUNCTION_SRGB_INV_EOTF] = "sRGB inv_EOTF", + [AMDGPU_TRANSFER_FUNCTION_BT709_OETF] = "BT.709 OETF", + [AMDGPU_TRANSFER_FUNCTION_PQ_INV_EOTF] = "PQ inv_EOTF", + [AMDGPU_TRANSFER_FUNCTION_GAMMA22_INV_EOTF] = "Gamma 2.2 inv_EOTF", + [AMDGPU_TRANSFER_FUNCTION_GAMMA24_INV_EOTF] = "Gamma 2.4 inv_EOTF", + [AMDGPU_TRANSFER_FUNCTION_GAMMA26_INV_EOTF] = "Gamma 2.6 inv_EOTF", +}; + +static const u32 amdgpu_eotf = + BIT(AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF) | + BIT(AMDGPU_TRANSFER_FUNCTION_BT709_INV_OETF) | + BIT(AMDGPU_TRANSFER_FUNCTION_PQ_EOTF) | + BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA22_EOTF) | + BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA24_EOTF) | + BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA26_EOTF); + +static const u32 amdgpu_inv_eotf = + BIT(AMDGPU_TRANSFER_FUNCTION_SRGB_INV_EOTF) | + BIT(AMDGPU_TRANSFER_FUNCTION_BT709_OETF) | + BIT(AMDGPU_TRANSFER_FUNCTION_PQ_INV_EOTF) | + BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA22_INV_EOTF) | + BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA24_INV_EOTF) | + BIT(AMDGPU_TRANSFER_FUNCTION_GAMMA26_INV_EOTF); + +static struct drm_property * +amdgpu_create_tf_property(struct drm_device *dev, + const char *name, + u32 supported_tf) +{ + u32 transfer_functions = supported_tf | + BIT(AMDGPU_TRANSFER_FUNCTION_DEFAULT) | + BIT(AMDGPU_TRANSFER_FUNCTION_IDENTITY); + struct drm_prop_enum_list enum_list[AMDGPU_TRANSFER_FUNCTION_COUNT]; + int i, len; + + len = 0; + for (i = 0; i < AMDGPU_TRANSFER_FUNCTION_COUNT; i++) { + if ((transfer_functions & BIT(i)) == 0) + continue; + + enum_list[len].type = i; + enum_list[len].name = amdgpu_transfer_function_names[i]; + len++; + } + + return drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, + name, enum_list, len); +} + +int +amdgpu_dm_create_color_properties(struct amdgpu_device *adev) +{ + struct drm_property *prop; + + prop = drm_property_create(adev_to_drm(adev), + DRM_MODE_PROP_BLOB, + "AMD_PLANE_DEGAMMA_LUT", 0); + if (!prop) + return -ENOMEM; + adev->mode_info.plane_degamma_lut_property = prop; + + prop = drm_property_create_range(adev_to_drm(adev), + DRM_MODE_PROP_IMMUTABLE, + "AMD_PLANE_DEGAMMA_LUT_SIZE", + 0, UINT_MAX); + if (!prop) + return -ENOMEM; + adev->mode_info.plane_degamma_lut_size_property = prop; + + prop = amdgpu_create_tf_property(adev_to_drm(adev), + "AMD_PLANE_DEGAMMA_TF", + amdgpu_eotf); + if (!prop) + return -ENOMEM; + adev->mode_info.plane_degamma_tf_property = prop; + + prop = drm_property_create_range(adev_to_drm(adev), + 0, "AMD_PLANE_HDR_MULT", 0, U64_MAX); + if (!prop) + return -ENOMEM; + adev->mode_info.plane_hdr_mult_property = prop; + + prop = drm_property_create(adev_to_drm(adev), + DRM_MODE_PROP_BLOB, + "AMD_PLANE_CTM", 0); + if (!prop) + return -ENOMEM; + adev->mode_info.plane_ctm_property = prop; + + prop = drm_property_create(adev_to_drm(adev), + DRM_MODE_PROP_BLOB, + "AMD_PLANE_SHAPER_LUT", 0); + if (!prop) + return -ENOMEM; + adev->mode_info.plane_shaper_lut_property = prop; + + prop = drm_property_create_range(adev_to_drm(adev), + DRM_MODE_PROP_IMMUTABLE, + "AMD_PLANE_SHAPER_LUT_SIZE", 0, UINT_MAX); + if (!prop) + return -ENOMEM; + adev->mode_info.plane_shaper_lut_size_property = prop; + + prop = amdgpu_create_tf_property(adev_to_drm(adev), + "AMD_PLANE_SHAPER_TF", + amdgpu_inv_eotf); + if (!prop) + return -ENOMEM; + adev->mode_info.plane_shaper_tf_property = prop; + + prop = drm_property_create(adev_to_drm(adev), + DRM_MODE_PROP_BLOB, + "AMD_PLANE_LUT3D", 0); + if (!prop) + return -ENOMEM; + adev->mode_info.plane_lut3d_property = prop; + + prop = drm_property_create_range(adev_to_drm(adev), + DRM_MODE_PROP_IMMUTABLE, + "AMD_PLANE_LUT3D_SIZE", 0, UINT_MAX); + if (!prop) + return -ENOMEM; + adev->mode_info.plane_lut3d_size_property = prop; + + prop = drm_property_create(adev_to_drm(adev), + DRM_MODE_PROP_BLOB, + "AMD_PLANE_BLEND_LUT", 0); + if (!prop) + return -ENOMEM; + adev->mode_info.plane_blend_lut_property = prop; + + prop = drm_property_create_range(adev_to_drm(adev), + DRM_MODE_PROP_IMMUTABLE, + "AMD_PLANE_BLEND_LUT_SIZE", 0, UINT_MAX); + if (!prop) + return -ENOMEM; + adev->mode_info.plane_blend_lut_size_property = prop; + + prop = amdgpu_create_tf_property(adev_to_drm(adev), + "AMD_PLANE_BLEND_TF", + amdgpu_eotf); + if (!prop) + return -ENOMEM; + adev->mode_info.plane_blend_tf_property = prop; + + prop = amdgpu_create_tf_property(adev_to_drm(adev), + "AMD_CRTC_REGAMMA_TF", + amdgpu_inv_eotf); + if (!prop) + return -ENOMEM; + adev->mode_info.regamma_tf_property = prop; + + return 0; +} +#endif + /** * __extract_blob_lut - Extracts the DRM lut and lut size from a blob. * @blob: DRM color mgmt property blob @@ -182,7 +424,6 @@ static void __drm_lut_to_dc_gamma(const struct drm_color_lut *lut, static void __drm_ctm_to_dc_matrix(const struct drm_color_ctm *ctm, struct fixed31_32 *matrix) { - int64_t val; int i; /* @@ -201,12 +442,29 @@ static void __drm_ctm_to_dc_matrix(const struct drm_color_ctm *ctm, } /* gamut_remap_matrix[i] = ctm[i - floor(i/4)] */ - val = ctm->matrix[i - (i / 4)]; - /* If negative, convert to 2's complement. */ - if (val & (1ULL << 63)) - val = -(val & ~(1ULL << 63)); + matrix[i] = amdgpu_dm_fixpt_from_s3132(ctm->matrix[i - (i / 4)]); + } +} - matrix[i].value = val; +/** + * __drm_ctm_3x4_to_dc_matrix - converts a DRM CTM 3x4 to a DC CSC float matrix + * @ctm: DRM color transformation matrix with 3x4 dimensions + * @matrix: DC CSC float matrix + * + * The matrix needs to be a 3x4 (12 entry) matrix. + */ +static void __drm_ctm_3x4_to_dc_matrix(const struct drm_color_ctm_3x4 *ctm, + struct fixed31_32 *matrix) +{ + int i; + + /* The format provided is S31.32, using signed-magnitude representation. + * Our fixed31_32 is also S31.32, but is using 2's complement. We have + * to convert from signed-magnitude to 2's complement. + */ + for (i = 0; i < 12; i++) { + /* gamut_remap_matrix[i] = ctm[i - floor(i/4)] */ + matrix[i] = amdgpu_dm_fixpt_from_s3132(ctm->matrix[i]); } } @@ -268,16 +526,18 @@ static int __set_output_tf(struct dc_transfer_func *func, struct calculate_buffer cal_buffer = {0}; bool res; - ASSERT(lut && lut_size == MAX_COLOR_LUT_ENTRIES); - cal_buffer.buffer_index = -1; - gamma = dc_create_gamma(); - if (!gamma) - return -ENOMEM; + if (lut_size) { + ASSERT(lut && lut_size == MAX_COLOR_LUT_ENTRIES); - gamma->num_entries = lut_size; - __drm_lut_to_dc_gamma(lut, gamma, false); + gamma = dc_create_gamma(); + if (!gamma) + return -ENOMEM; + + gamma->num_entries = lut_size; + __drm_lut_to_dc_gamma(lut, gamma, false); + } if (func->tf == TRANSFER_FUNCTION_LINEAR) { /* @@ -285,27 +545,68 @@ static int __set_output_tf(struct dc_transfer_func *func, * on top of a linear input. But degamma params can be used * instead to simulate this. */ - gamma->type = GAMMA_CUSTOM; + if (gamma) + gamma->type = GAMMA_CUSTOM; res = mod_color_calculate_degamma_params(NULL, func, - gamma, true); + gamma, gamma != NULL); } else { /* * Assume sRGB. The actual mapping will depend on whether the * input was legacy or not. */ - gamma->type = GAMMA_CS_TFM_1D; - res = mod_color_calculate_regamma_params(func, gamma, false, + if (gamma) + gamma->type = GAMMA_CS_TFM_1D; + res = mod_color_calculate_regamma_params(func, gamma, gamma != NULL, has_rom, NULL, &cal_buffer); } - dc_gamma_release(&gamma); + if (gamma) + dc_gamma_release(&gamma); return res ? 0 : -ENOMEM; } +static int amdgpu_dm_set_atomic_regamma(struct dc_stream_state *stream, + const struct drm_color_lut *regamma_lut, + uint32_t regamma_size, bool has_rom, + enum dc_transfer_func_predefined tf) +{ + struct dc_transfer_func *out_tf = stream->out_transfer_func; + int ret = 0; + + if (regamma_size || tf != TRANSFER_FUNCTION_LINEAR) { + /* + * CRTC RGM goes into RGM LUT. + * + * Note: there is no implicit sRGB regamma here. We are using + * degamma calculation from color module to calculate the curve + * from a linear base if gamma TF is not set. However, if gamma + * TF (!= Linear) and LUT are set at the same time, we will use + * regamma calculation, and the color module will combine the + * pre-defined TF and the custom LUT values into the LUT that's + * actually programmed. + */ + out_tf->type = TF_TYPE_DISTRIBUTED_POINTS; + out_tf->tf = tf; + out_tf->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE; + + ret = __set_output_tf(out_tf, regamma_lut, regamma_size, has_rom); + } else { + /* + * No CRTC RGM means we can just put the block into bypass + * since we don't have any plane level adjustments using it. + */ + out_tf->type = TF_TYPE_BYPASS; + out_tf->tf = TRANSFER_FUNCTION_LINEAR; + } + + return ret; +} + /** * __set_input_tf - calculates the input transfer function based on expected * input space. + * @caps: dc color capabilities * @func: transfer function * @lut: lookup table that defines the color space * @lut_size: size of respective lut. @@ -313,27 +614,240 @@ static int __set_output_tf(struct dc_transfer_func *func, * Returns: * 0 in case of success. -ENOMEM if fails. */ -static int __set_input_tf(struct dc_transfer_func *func, +static int __set_input_tf(struct dc_color_caps *caps, struct dc_transfer_func *func, const struct drm_color_lut *lut, uint32_t lut_size) { struct dc_gamma *gamma = NULL; bool res; - gamma = dc_create_gamma(); - if (!gamma) - return -ENOMEM; + if (lut_size) { + gamma = dc_create_gamma(); + if (!gamma) + return -ENOMEM; - gamma->type = GAMMA_CUSTOM; - gamma->num_entries = lut_size; + gamma->type = GAMMA_CUSTOM; + gamma->num_entries = lut_size; + + __drm_lut_to_dc_gamma(lut, gamma, false); + } - __drm_lut_to_dc_gamma(lut, gamma, false); + res = mod_color_calculate_degamma_params(caps, func, gamma, gamma != NULL); - res = mod_color_calculate_degamma_params(NULL, func, gamma, true); - dc_gamma_release(&gamma); + if (gamma) + dc_gamma_release(&gamma); return res ? 0 : -ENOMEM; } +static enum dc_transfer_func_predefined +amdgpu_tf_to_dc_tf(enum amdgpu_transfer_function tf) +{ + switch (tf) { + default: + case AMDGPU_TRANSFER_FUNCTION_DEFAULT: + case AMDGPU_TRANSFER_FUNCTION_IDENTITY: + return TRANSFER_FUNCTION_LINEAR; + case AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF: + case AMDGPU_TRANSFER_FUNCTION_SRGB_INV_EOTF: + return TRANSFER_FUNCTION_SRGB; + case AMDGPU_TRANSFER_FUNCTION_BT709_OETF: + case AMDGPU_TRANSFER_FUNCTION_BT709_INV_OETF: + return TRANSFER_FUNCTION_BT709; + case AMDGPU_TRANSFER_FUNCTION_PQ_EOTF: + case AMDGPU_TRANSFER_FUNCTION_PQ_INV_EOTF: + return TRANSFER_FUNCTION_PQ; + case AMDGPU_TRANSFER_FUNCTION_GAMMA22_EOTF: + case AMDGPU_TRANSFER_FUNCTION_GAMMA22_INV_EOTF: + return TRANSFER_FUNCTION_GAMMA22; + case AMDGPU_TRANSFER_FUNCTION_GAMMA24_EOTF: + case AMDGPU_TRANSFER_FUNCTION_GAMMA24_INV_EOTF: + return TRANSFER_FUNCTION_GAMMA24; + case AMDGPU_TRANSFER_FUNCTION_GAMMA26_EOTF: + case AMDGPU_TRANSFER_FUNCTION_GAMMA26_INV_EOTF: + return TRANSFER_FUNCTION_GAMMA26; + } +} + +static void __to_dc_lut3d_color(struct dc_rgb *rgb, + const struct drm_color_lut lut, + int bit_precision) +{ + rgb->red = drm_color_lut_extract(lut.red, bit_precision); + rgb->green = drm_color_lut_extract(lut.green, bit_precision); + rgb->blue = drm_color_lut_extract(lut.blue, bit_precision); +} + +static void __drm_3dlut_to_dc_3dlut(const struct drm_color_lut *lut, + uint32_t lut3d_size, + struct tetrahedral_params *params, + bool use_tetrahedral_9, + int bit_depth) +{ + struct dc_rgb *lut0; + struct dc_rgb *lut1; + struct dc_rgb *lut2; + struct dc_rgb *lut3; + int lut_i, i; + + + if (use_tetrahedral_9) { + lut0 = params->tetrahedral_9.lut0; + lut1 = params->tetrahedral_9.lut1; + lut2 = params->tetrahedral_9.lut2; + lut3 = params->tetrahedral_9.lut3; + } else { + lut0 = params->tetrahedral_17.lut0; + lut1 = params->tetrahedral_17.lut1; + lut2 = params->tetrahedral_17.lut2; + lut3 = params->tetrahedral_17.lut3; + } + + for (lut_i = 0, i = 0; i < lut3d_size - 4; lut_i++, i += 4) { + /* + * We should consider the 3D LUT RGB values are distributed + * along four arrays lut0-3 where the first sizes 1229 and the + * other 1228. The bit depth supported for 3dlut channel is + * 12-bit, but DC also supports 10-bit. + * + * TODO: improve color pipeline API to enable the userspace set + * bit depth and 3D LUT size/stride, as specified by VA-API. + */ + __to_dc_lut3d_color(&lut0[lut_i], lut[i], bit_depth); + __to_dc_lut3d_color(&lut1[lut_i], lut[i + 1], bit_depth); + __to_dc_lut3d_color(&lut2[lut_i], lut[i + 2], bit_depth); + __to_dc_lut3d_color(&lut3[lut_i], lut[i + 3], bit_depth); + } + /* lut0 has 1229 points (lut_size/4 + 1) */ + __to_dc_lut3d_color(&lut0[lut_i], lut[i], bit_depth); +} + +/* amdgpu_dm_atomic_lut3d - set DRM 3D LUT to DC stream + * @drm_lut3d: user 3D LUT + * @drm_lut3d_size: size of 3D LUT + * @lut3d: DC 3D LUT + * + * Map user 3D LUT data to DC 3D LUT and all necessary bits to program it + * on DCN accordingly. + */ +static void amdgpu_dm_atomic_lut3d(const struct drm_color_lut *drm_lut3d, + uint32_t drm_lut3d_size, + struct dc_3dlut *lut) +{ + if (!drm_lut3d_size) { + lut->state.bits.initialized = 0; + } else { + /* Stride and bit depth are not programmable by API yet. + * Therefore, only supports 17x17x17 3D LUT (12-bit). + */ + lut->lut_3d.use_tetrahedral_9 = false; + lut->lut_3d.use_12bits = true; + lut->state.bits.initialized = 1; + __drm_3dlut_to_dc_3dlut(drm_lut3d, drm_lut3d_size, &lut->lut_3d, + lut->lut_3d.use_tetrahedral_9, + MAX_COLOR_3DLUT_BITDEPTH); + } +} + +static int amdgpu_dm_atomic_shaper_lut(const struct drm_color_lut *shaper_lut, + bool has_rom, + enum dc_transfer_func_predefined tf, + uint32_t shaper_size, + struct dc_transfer_func *func_shaper) +{ + int ret = 0; + + if (shaper_size || tf != TRANSFER_FUNCTION_LINEAR) { + /* + * If user shaper LUT is set, we assume a linear color space + * (linearized by degamma 1D LUT or not). + */ + func_shaper->type = TF_TYPE_DISTRIBUTED_POINTS; + func_shaper->tf = tf; + func_shaper->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE; + + ret = __set_output_tf(func_shaper, shaper_lut, shaper_size, has_rom); + } else { + func_shaper->type = TF_TYPE_BYPASS; + func_shaper->tf = TRANSFER_FUNCTION_LINEAR; + } + + return ret; +} + +static int amdgpu_dm_atomic_blend_lut(const struct drm_color_lut *blend_lut, + bool has_rom, + enum dc_transfer_func_predefined tf, + uint32_t blend_size, + struct dc_transfer_func *func_blend) +{ + int ret = 0; + + if (blend_size || tf != TRANSFER_FUNCTION_LINEAR) { + /* + * DRM plane gamma LUT or TF means we are linearizing color + * space before blending (similar to degamma programming). As + * we don't have hardcoded curve support, or we use AMD color + * module to fill the parameters that will be translated to HW + * points. + */ + func_blend->type = TF_TYPE_DISTRIBUTED_POINTS; + func_blend->tf = tf; + func_blend->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE; + + ret = __set_input_tf(NULL, func_blend, blend_lut, blend_size); + } else { + func_blend->type = TF_TYPE_BYPASS; + func_blend->tf = TRANSFER_FUNCTION_LINEAR; + } + + return ret; +} + +/** + * amdgpu_dm_verify_lut3d_size - verifies if 3D LUT is supported and if user + * shaper and 3D LUTs match the hw supported size + * @adev: amdgpu device + * @plane_state: the DRM plane state + * + * Verifies if pre-blending (DPP) 3D LUT is supported by the HW (DCN 2.0 or + * newer) and if the user shaper and 3D LUTs match the supported size. + * + * Returns: + * 0 on success. -EINVAL if lut size are invalid. + */ +int amdgpu_dm_verify_lut3d_size(struct amdgpu_device *adev, + struct drm_plane_state *plane_state) +{ + struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state); + const struct drm_color_lut *shaper = NULL, *lut3d = NULL; + uint32_t exp_size, size, dim_size = MAX_COLOR_3DLUT_SIZE; + bool has_3dlut = adev->dm.dc->caps.color.dpp.hw_3d_lut; + + /* shaper LUT is only available if 3D LUT color caps */ + exp_size = has_3dlut ? MAX_COLOR_LUT_ENTRIES : 0; + shaper = __extract_blob_lut(dm_plane_state->shaper_lut, &size); + + if (shaper && size != exp_size) { + drm_dbg(&adev->ddev, + "Invalid Shaper LUT size. Should be %u but got %u.\n", + exp_size, size); + return -EINVAL; + } + + /* The number of 3D LUT entries is the dimension size cubed */ + exp_size = has_3dlut ? dim_size * dim_size * dim_size : 0; + lut3d = __extract_blob_lut(dm_plane_state->lut3d, &size); + + if (lut3d && size != exp_size) { + drm_dbg(&adev->ddev, + "Invalid 3D LUT size. Should be %u but got %u.\n", + exp_size, size); + return -EINVAL; + } + + return 0; +} + /** * amdgpu_dm_verify_lut_sizes - verifies if DRM luts match the hw supported sizes * @crtc_state: the DRM CRTC state @@ -401,9 +915,12 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc) const struct drm_color_lut *degamma_lut, *regamma_lut; uint32_t degamma_size, regamma_size; bool has_regamma, has_degamma; + enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_LINEAR; bool is_legacy; int r; + tf = amdgpu_tf_to_dc_tf(crtc->regamma_tf); + r = amdgpu_dm_verify_lut_sizes(&crtc->base); if (r) return r; @@ -439,27 +956,23 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc) crtc->cm_is_degamma_srgb = true; stream->out_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS; stream->out_transfer_func->tf = TRANSFER_FUNCTION_SRGB; - + /* + * Note: although we pass has_rom as parameter here, we never + * actually use ROM because the color module only takes the ROM + * path if transfer_func->type == PREDEFINED. + * + * See more in mod_color_calculate_regamma_params() + */ r = __set_legacy_tf(stream->out_transfer_func, regamma_lut, regamma_size, has_rom); if (r) return r; - } else if (has_regamma) { - /* If atomic regamma, CRTC RGM goes into RGM LUT. */ - stream->out_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS; - stream->out_transfer_func->tf = TRANSFER_FUNCTION_LINEAR; - - r = __set_output_tf(stream->out_transfer_func, regamma_lut, - regamma_size, has_rom); + } else { + regamma_size = has_regamma ? regamma_size : 0; + r = amdgpu_dm_set_atomic_regamma(stream, regamma_lut, + regamma_size, has_rom, tf); if (r) return r; - } else { - /* - * No CRTC RGM means we can just put the block into bypass - * since we don't have any plane level adjustments using it. - */ - stream->out_transfer_func->type = TF_TYPE_BYPASS; - stream->out_transfer_func->tf = TRANSFER_FUNCTION_LINEAR; } /* @@ -495,20 +1008,10 @@ int amdgpu_dm_update_crtc_color_mgmt(struct dm_crtc_state *crtc) return 0; } -/** - * amdgpu_dm_update_plane_color_mgmt: Maps DRM color management to DC plane. - * @crtc: amdgpu_dm crtc state - * @dc_plane_state: target DC surface - * - * Update the underlying dc_stream_state's input transfer function (ITF) in - * preparation for hardware commit. The transfer function used depends on - * the preparation done on the stream for color management. - * - * Returns: - * 0 on success. -ENOMEM if mem allocation fails. - */ -int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, - struct dc_plane_state *dc_plane_state) +static int +map_crtc_degamma_to_dc_plane(struct dm_crtc_state *crtc, + struct dc_plane_state *dc_plane_state, + struct dc_color_caps *caps) { const struct drm_color_lut *degamma_lut; enum dc_transfer_func_predefined tf = TRANSFER_FUNCTION_SRGB; @@ -531,8 +1034,7 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, °amma_size); ASSERT(degamma_size == MAX_COLOR_LUT_ENTRIES); - dc_plane_state->in_transfer_func->type = - TF_TYPE_DISTRIBUTED_POINTS; + dc_plane_state->in_transfer_func->type = TF_TYPE_DISTRIBUTED_POINTS; /* * This case isn't fully correct, but also fairly @@ -564,11 +1066,11 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, dc_plane_state->in_transfer_func->tf = TRANSFER_FUNCTION_LINEAR; - r = __set_input_tf(dc_plane_state->in_transfer_func, + r = __set_input_tf(caps, dc_plane_state->in_transfer_func, degamma_lut, degamma_size); if (r) return r; - } else if (crtc->cm_is_degamma_srgb) { + } else { /* * For legacy gamma support we need the regamma input * in linear space. Assume that the input is sRGB. @@ -577,14 +1079,209 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, dc_plane_state->in_transfer_func->tf = tf; if (tf != TRANSFER_FUNCTION_SRGB && - !mod_color_calculate_degamma_params(NULL, - dc_plane_state->in_transfer_func, NULL, false)) + !mod_color_calculate_degamma_params(caps, + dc_plane_state->in_transfer_func, + NULL, false)) + return -ENOMEM; + } + + return 0; +} + +static int +__set_dm_plane_degamma(struct drm_plane_state *plane_state, + struct dc_plane_state *dc_plane_state, + struct dc_color_caps *color_caps) +{ + struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state); + const struct drm_color_lut *degamma_lut; + enum amdgpu_transfer_function tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT; + uint32_t degamma_size; + bool has_degamma_lut; + int ret; + + degamma_lut = __extract_blob_lut(dm_plane_state->degamma_lut, + °amma_size); + + has_degamma_lut = degamma_lut && + !__is_lut_linear(degamma_lut, degamma_size); + + tf = dm_plane_state->degamma_tf; + + /* If we don't have plane degamma LUT nor TF to set on DC, we have + * nothing to do here, return. + */ + if (!has_degamma_lut && tf == AMDGPU_TRANSFER_FUNCTION_DEFAULT) + return -EINVAL; + + dc_plane_state->in_transfer_func->tf = amdgpu_tf_to_dc_tf(tf); + + if (has_degamma_lut) { + ASSERT(degamma_size == MAX_COLOR_LUT_ENTRIES); + + dc_plane_state->in_transfer_func->type = + TF_TYPE_DISTRIBUTED_POINTS; + + ret = __set_input_tf(color_caps, dc_plane_state->in_transfer_func, + degamma_lut, degamma_size); + if (ret) + return ret; + } else { + dc_plane_state->in_transfer_func->type = + TF_TYPE_PREDEFINED; + + if (!mod_color_calculate_degamma_params(color_caps, + dc_plane_state->in_transfer_func, NULL, false)) return -ENOMEM; - } else { - /* ...Otherwise we can just bypass the DGM block. */ - dc_plane_state->in_transfer_func->type = TF_TYPE_BYPASS; - dc_plane_state->in_transfer_func->tf = TRANSFER_FUNCTION_LINEAR; + } + return 0; +} + +static int +amdgpu_dm_plane_set_color_properties(struct drm_plane_state *plane_state, + struct dc_plane_state *dc_plane_state) +{ + struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state); + enum amdgpu_transfer_function shaper_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT; + enum amdgpu_transfer_function blend_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT; + const struct drm_color_lut *shaper_lut, *lut3d, *blend_lut; + uint32_t shaper_size, lut3d_size, blend_size; + int ret; + + dc_plane_state->hdr_mult = amdgpu_dm_fixpt_from_s3132(dm_plane_state->hdr_mult); + + shaper_lut = __extract_blob_lut(dm_plane_state->shaper_lut, &shaper_size); + shaper_size = shaper_lut != NULL ? shaper_size : 0; + shaper_tf = dm_plane_state->shaper_tf; + lut3d = __extract_blob_lut(dm_plane_state->lut3d, &lut3d_size); + lut3d_size = lut3d != NULL ? lut3d_size : 0; + + amdgpu_dm_atomic_lut3d(lut3d, lut3d_size, dc_plane_state->lut3d_func); + ret = amdgpu_dm_atomic_shaper_lut(shaper_lut, false, + amdgpu_tf_to_dc_tf(shaper_tf), + shaper_size, + dc_plane_state->in_shaper_func); + if (ret) { + drm_dbg_kms(plane_state->plane->dev, + "setting plane %d shaper LUT failed.\n", + plane_state->plane->index); + + return ret; + } + + blend_tf = dm_plane_state->blend_tf; + blend_lut = __extract_blob_lut(dm_plane_state->blend_lut, &blend_size); + blend_size = blend_lut != NULL ? blend_size : 0; + + ret = amdgpu_dm_atomic_blend_lut(blend_lut, false, + amdgpu_tf_to_dc_tf(blend_tf), + blend_size, dc_plane_state->blend_tf); + if (ret) { + drm_dbg_kms(plane_state->plane->dev, + "setting plane %d gamma lut failed.\n", + plane_state->plane->index); + + return ret; } return 0; } + +/** + * amdgpu_dm_update_plane_color_mgmt: Maps DRM color management to DC plane. + * @crtc: amdgpu_dm crtc state + * @plane_state: DRM plane state + * @dc_plane_state: target DC surface + * + * Update the underlying dc_stream_state's input transfer function (ITF) in + * preparation for hardware commit. The transfer function used depends on + * the preparation done on the stream for color management. + * + * Returns: + * 0 on success. -ENOMEM if mem allocation fails. + */ +int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, + struct drm_plane_state *plane_state, + struct dc_plane_state *dc_plane_state) +{ + struct amdgpu_device *adev = drm_to_adev(crtc->base.state->dev); + struct dm_plane_state *dm_plane_state = to_dm_plane_state(plane_state); + struct drm_color_ctm_3x4 *ctm = NULL; + struct dc_color_caps *color_caps = NULL; + bool has_crtc_cm_degamma; + int ret; + + ret = amdgpu_dm_verify_lut3d_size(adev, plane_state); + if (ret) { + drm_dbg_driver(&adev->ddev, "amdgpu_dm_verify_lut3d_size() failed\n"); + return ret; + } + + if (dc_plane_state->ctx && dc_plane_state->ctx->dc) + color_caps = &dc_plane_state->ctx->dc->caps.color; + + /* Initially, we can just bypass the DGM block. */ + dc_plane_state->in_transfer_func->type = TF_TYPE_BYPASS; + dc_plane_state->in_transfer_func->tf = TRANSFER_FUNCTION_LINEAR; + + /* After, we start to update values according to color props */ + has_crtc_cm_degamma = (crtc->cm_has_degamma || crtc->cm_is_degamma_srgb); + + ret = __set_dm_plane_degamma(plane_state, dc_plane_state, color_caps); + if (ret == -ENOMEM) + return ret; + + /* We only have one degamma block available (pre-blending) for the + * whole color correction pipeline, so that we can't actually perform + * plane and CRTC degamma at the same time. Explicitly reject atomic + * updates when userspace sets both plane and CRTC degamma properties. + */ + if (has_crtc_cm_degamma && ret != -EINVAL) { + drm_dbg_kms(crtc->base.crtc->dev, + "doesn't support plane and CRTC degamma at the same time\n"); + return -EINVAL; + } + + /* If we are here, it means we don't have plane degamma settings, check + * if we have CRTC degamma waiting for mapping to pre-blending degamma + * block + */ + if (has_crtc_cm_degamma) { + /* + * AMD HW doesn't have post-blending degamma caps. When DRM + * CRTC atomic degamma is set, we maps it to DPP degamma block + * (pre-blending) or, on legacy gamma, we use DPP degamma to + * linearize (implicit degamma) from sRGB/BT709 according to + * the input space. + */ + ret = map_crtc_degamma_to_dc_plane(crtc, dc_plane_state, color_caps); + if (ret) + return ret; + } + + /* Setup CRTC CTM. */ + if (dm_plane_state->ctm) { + ctm = (struct drm_color_ctm_3x4 *)dm_plane_state->ctm->data; + /* + * DCN2 and older don't support both pre-blending and + * post-blending gamut remap. For this HW family, if we have + * the plane and CRTC CTMs simultaneously, CRTC CTM takes + * priority, and we discard plane CTM, as implemented in + * dcn10_program_gamut_remap(). However, DCN3+ has DPP + * (pre-blending) and MPC (post-blending) `gamut remap` blocks; + * therefore, we can program plane and CRTC CTMs together by + * mapping CRTC CTM to MPC and keeping plane CTM setup at DPP, + * as it's done by dcn30_program_gamut_remap(). + */ + __drm_ctm_3x4_to_dc_matrix(ctm, dc_plane_state->gamut_remap_matrix.matrix); + + dc_plane_state->gamut_remap_matrix.enable_remap = true; + dc_plane_state->input_csc_color_matrix.enable_adjustment = false; + } else { + /* Bypass CTM. */ + dc_plane_state->gamut_remap_matrix.enable_remap = false; + dc_plane_state->input_csc_color_matrix.enable_adjustment = false; + } + + return amdgpu_dm_plane_set_color_properties(plane_state, dc_plane_state); +} 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 52ecfa746b54dd..f936a35fa9ebb7 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 @@ -326,6 +326,9 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name) if (!connector->state || connector->state->crtc != crtc) continue; + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + aconn = to_amdgpu_dm_connector(connector); break; } 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 cb0b48bb2a7dca..6e715ef3a5566e 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 @@ -29,7 +29,6 @@ #include "dc.h" #include "amdgpu.h" #include "amdgpu_dm_psr.h" -#include "amdgpu_dm_replay.h" #include "amdgpu_dm_crtc.h" #include "amdgpu_dm_plane.h" #include "amdgpu_dm_trace.h" @@ -124,12 +123,7 @@ static void amdgpu_dm_crtc_vblank_control_worker(struct work_struct *work) * fill_dc_dirty_rects(). */ if (vblank_work->stream && vblank_work->stream->link) { - /* - * Prioritize replay, instead of psr - */ - if (vblank_work->stream->link->replay_settings.replay_feature_enabled) - amdgpu_dm_replay_enable(vblank_work->stream, false); - else if (vblank_work->enable) { + if (vblank_work->enable) { if (vblank_work->stream->link->psr_settings.psr_version < DC_PSR_VERSION_SU_1 && vblank_work->stream->link->psr_settings.psr_allow_active) amdgpu_dm_psr_disable(vblank_work->stream); @@ -138,7 +132,6 @@ static void amdgpu_dm_crtc_vblank_control_worker(struct work_struct *work) #ifdef CONFIG_DRM_AMD_SECURE_DISPLAY !amdgpu_dm_crc_window_is_activated(&vblank_work->acrtc->base) && #endif - vblank_work->stream->link->panel_config.psr.disallow_replay && vblank_work->acrtc->dm_irq_params.allow_psr_entry) { amdgpu_dm_psr_enable(vblank_work->stream); } @@ -260,6 +253,7 @@ static struct drm_crtc_state *amdgpu_dm_crtc_duplicate_state(struct drm_crtc *cr state->freesync_config = cur->freesync_config; state->cm_has_degamma = cur->cm_has_degamma; state->cm_is_degamma_srgb = cur->cm_is_degamma_srgb; + state->regamma_tf = cur->regamma_tf; state->crc_skip_count = cur->crc_skip_count; state->mpo_requested = cur->mpo_requested; /* TODO Duplicate dc_stream after objects are stream object is flattened */ @@ -296,6 +290,70 @@ static int amdgpu_dm_crtc_late_register(struct drm_crtc *crtc) } #endif +#ifdef AMD_PRIVATE_COLOR +/** + * dm_crtc_additional_color_mgmt - enable additional color properties + * @crtc: DRM CRTC + * + * This function lets the driver enable post-blending CRTC regamma transfer + * function property in addition to DRM CRTC gamma LUT. Default value means + * linear transfer function, which is the default CRTC gamma LUT behaviour + * without this property. + */ +static void +dm_crtc_additional_color_mgmt(struct drm_crtc *crtc) +{ + struct amdgpu_device *adev = drm_to_adev(crtc->dev); + + if (adev->dm.dc->caps.color.mpc.ogam_ram) + drm_object_attach_property(&crtc->base, + adev->mode_info.regamma_tf_property, + AMDGPU_TRANSFER_FUNCTION_DEFAULT); +} + +static int +amdgpu_dm_atomic_crtc_set_property(struct drm_crtc *crtc, + struct drm_crtc_state *state, + struct drm_property *property, + uint64_t val) +{ + struct amdgpu_device *adev = drm_to_adev(crtc->dev); + struct dm_crtc_state *acrtc_state = to_dm_crtc_state(state); + + if (property == adev->mode_info.regamma_tf_property) { + if (acrtc_state->regamma_tf != val) { + acrtc_state->regamma_tf = val; + acrtc_state->base.color_mgmt_changed |= 1; + } + } else { + drm_dbg_atomic(crtc->dev, + "[CRTC:%d:%s] unknown property [PROP:%d:%s]]\n", + crtc->base.id, crtc->name, + property->base.id, property->name); + return -EINVAL; + } + + return 0; +} + +static int +amdgpu_dm_atomic_crtc_get_property(struct drm_crtc *crtc, + const struct drm_crtc_state *state, + struct drm_property *property, + uint64_t *val) +{ + struct amdgpu_device *adev = drm_to_adev(crtc->dev); + struct dm_crtc_state *acrtc_state = to_dm_crtc_state(state); + + if (property == adev->mode_info.regamma_tf_property) + *val = acrtc_state->regamma_tf; + else + return -EINVAL; + + return 0; +} +#endif + /* Implemented only the options currently available for the driver */ static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = { .reset = amdgpu_dm_crtc_reset_state, @@ -314,6 +372,10 @@ static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = { #if defined(CONFIG_DEBUG_FS) .late_register = amdgpu_dm_crtc_late_register, #endif +#ifdef AMD_PRIVATE_COLOR + .atomic_set_property = amdgpu_dm_atomic_crtc_set_property, + .atomic_get_property = amdgpu_dm_atomic_crtc_get_property, +#endif }; static void amdgpu_dm_crtc_helper_disable(struct drm_crtc *crtc) @@ -489,6 +551,9 @@ int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm, drm_mode_crtc_set_gamma_size(&acrtc->base, MAX_COLOR_LEGACY_LUT_ENTRIES); +#ifdef AMD_PRIVATE_COLOR + dm_crtc_additional_color_mgmt(&acrtc->base); +#endif return 0; fail: 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 13a177d3437625..68a84632391276 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 @@ -2971,6 +2971,85 @@ static int allow_edp_hotplug_detection_set(void *data, u64 val) return 0; } +static int dmub_trace_mask_set(void *data, u64 val) +{ + struct amdgpu_device *adev = data; + struct dmub_srv *srv = adev->dm.dc->ctx->dmub_srv->dmub; + enum dmub_gpint_command cmd; + u64 mask = 0xffff; + u8 shift = 0; + u32 res; + int i; + + if (!srv->fw_version) + return -EINVAL; + + for (i = 0; i < 4; i++) { + res = (val & mask) >> shift; + + switch (i) { + case 0: + cmd = DMUB_GPINT__SET_TRACE_BUFFER_MASK_WORD0; + break; + case 1: + cmd = DMUB_GPINT__SET_TRACE_BUFFER_MASK_WORD1; + break; + case 2: + cmd = DMUB_GPINT__SET_TRACE_BUFFER_MASK_WORD2; + break; + case 3: + cmd = DMUB_GPINT__SET_TRACE_BUFFER_MASK_WORD3; + break; + } + + if (!dc_wake_and_execute_gpint(adev->dm.dc->ctx, cmd, res, NULL, DM_DMUB_WAIT_TYPE_WAIT)) + return -EIO; + + usleep_range(100, 1000); + + mask <<= 16; + shift += 16; + } + + return 0; +} + +static int dmub_trace_mask_show(void *data, u64 *val) +{ + enum dmub_gpint_command cmd = DMUB_GPINT__GET_TRACE_BUFFER_MASK_WORD0; + struct amdgpu_device *adev = data; + struct dmub_srv *srv = adev->dm.dc->ctx->dmub_srv->dmub; + u8 shift = 0; + u64 raw = 0; + u64 res = 0; + int i = 0; + + if (!srv->fw_version) + return -EINVAL; + + while (i < 4) { + uint32_t response; + + if (!dc_wake_and_execute_gpint(adev->dm.dc->ctx, cmd, 0, &response, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) + return -EIO; + + raw = response; + usleep_range(100, 1000); + + cmd++; + res |= (raw << shift); + shift += 16; + i++; + } + + *val = res; + + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(dmub_trace_mask_fops, dmub_trace_mask_show, + dmub_trace_mask_set, "0x%llx\n"); + /* * Set dmcub trace event IRQ enable or disable. * Usage to enable dmcub trace event IRQ: echo 1 > /sys/kernel/debug/dri/0/amdgpu_dm_dmcub_trace_event_en @@ -3647,12 +3726,16 @@ static int capabilities_show(struct seq_file *m, void *unused) bool mall_supported = dc->caps.mall_size_total; bool subvp_supported = dc->caps.subvp_fw_processing_delay_us; unsigned int mall_in_use = false; - unsigned int subvp_in_use = dc->cap_funcs.get_subvp_en(dc, dc->current_state); + unsigned int subvp_in_use = false; + struct hubbub *hubbub = dc->res_pool->hubbub; if (hubbub->funcs->get_mall_en) hubbub->funcs->get_mall_en(hubbub, &mall_in_use); + if (dc->cap_funcs.get_subvp_en) + subvp_in_use = dc->cap_funcs.get_subvp_en(dc, dc->current_state); + seq_printf(m, "mall supported: %s, enabled: %s\n", mall_supported ? "yes" : "no", mall_in_use ? "yes" : "no"); seq_printf(m, "sub-viewport supported: %s, enabled: %s\n", @@ -3880,6 +3963,9 @@ void dtn_debugfs_init(struct amdgpu_device *adev) debugfs_create_file_unsafe("amdgpu_dm_force_timing_sync", 0644, root, adev, &force_timing_sync_ops); + debugfs_create_file_unsafe("amdgpu_dm_dmub_trace_mask", 0644, root, + adev, &dmub_trace_mask_fops); + debugfs_create_file_unsafe("amdgpu_dm_dmcub_trace_event_en", 0644, root, adev, &dmcub_trace_event_state_fops); 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 aac98f93545a22..85b7f58a7f35a4 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 @@ -31,6 +31,7 @@ #include #include #include +#include #include "dm_services.h" #include "amdgpu.h" @@ -216,7 +217,7 @@ static void dm_helpers_construct_old_payload( struct drm_dp_mst_atomic_payload *old_payload) { struct drm_dp_mst_atomic_payload *pos; - int pbn_per_slot = mst_state->pbn_div; + int pbn_per_slot = dfixed_trunc(mst_state->pbn_div); u8 next_payload_vc_start = mgr->next_start_slot; u8 payload_vc_start = new_payload->vc_start_slot; u8 allocated_time_slots; @@ -339,15 +340,14 @@ enum act_return_status dm_helpers_dp_mst_poll_for_allocation_change_trigger( return ACT_SUCCESS; } -bool dm_helpers_dp_mst_send_payload_allocation( +void dm_helpers_dp_mst_send_payload_allocation( struct dc_context *ctx, - const struct dc_stream_state *stream, - bool enable) + const struct dc_stream_state *stream) { struct amdgpu_dm_connector *aconnector; struct drm_dp_mst_topology_state *mst_state; struct drm_dp_mst_topology_mgr *mst_mgr; - struct drm_dp_mst_atomic_payload *new_payload, old_payload; + struct drm_dp_mst_atomic_payload *new_payload; enum mst_progress_status set_flag = MST_ALLOCATE_NEW_PAYLOAD; enum mst_progress_status clr_flag = MST_CLEAR_ALLOCATED_PAYLOAD; int ret = 0; @@ -355,25 +355,13 @@ bool dm_helpers_dp_mst_send_payload_allocation( aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context; if (!aconnector || !aconnector->mst_root) - return false; + return; mst_mgr = &aconnector->mst_root->mst_mgr; mst_state = to_drm_dp_mst_topology_state(mst_mgr->base.state); - new_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) { - ret = drm_dp_add_payload_part2(mst_mgr, mst_state->base.state, new_payload); - } else { - dm_helpers_construct_old_payload(mst_mgr, mst_state, - new_payload, &old_payload); - drm_dp_remove_payload_part2(mst_mgr, mst_state, &old_payload, new_payload); - } + ret = drm_dp_add_payload_part2(mst_mgr, mst_state->base.state, new_payload); if (ret) { amdgpu_dm_set_mst_status(&aconnector->mst_status, @@ -384,10 +372,36 @@ bool dm_helpers_dp_mst_send_payload_allocation( amdgpu_dm_set_mst_status(&aconnector->mst_status, clr_flag, false); } - - return true; } +void dm_helpers_dp_mst_update_mst_mgr_for_deallocation( + struct dc_context *ctx, + const struct dc_stream_state *stream) +{ + struct amdgpu_dm_connector *aconnector; + struct drm_dp_mst_topology_state *mst_state; + struct drm_dp_mst_topology_mgr *mst_mgr; + struct drm_dp_mst_atomic_payload *new_payload, old_payload; + enum mst_progress_status set_flag = MST_CLEAR_ALLOCATED_PAYLOAD; + enum mst_progress_status clr_flag = MST_ALLOCATE_NEW_PAYLOAD; + + aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context; + + if (!aconnector || !aconnector->mst_root) + return; + + mst_mgr = &aconnector->mst_root->mst_mgr; + mst_state = to_drm_dp_mst_topology_state(mst_mgr->base.state); + new_payload = drm_atomic_get_mst_payload_state(mst_state, aconnector->mst_output_port); + dm_helpers_construct_old_payload(mst_mgr, mst_state, + new_payload, &old_payload); + + drm_dp_remove_payload_part2(mst_mgr, mst_state, &old_payload, new_payload); + + amdgpu_dm_set_mst_status(&aconnector->mst_status, set_flag, true); + amdgpu_dm_set_mst_status(&aconnector->mst_status, clr_flag, false); + } + void dm_dtn_log_begin(struct dc_context *ctx, struct dc_log_buffer_ctx *log_ctx) { @@ -965,6 +979,11 @@ int dm_helper_dmub_aux_transfer_sync( struct aux_payload *payload, enum aux_return_code_type *operation_result) { + if (!link->hpd_status) { + *operation_result = AUX_RET_ERROR_HPD_DISCON; + return -1; + } + return amdgpu_dm_process_dmub_aux_transfer_sync(ctx, link->link_index, payload, operation_result); } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c index 51467f132c2604..3390f0d8420a05 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c @@ -711,7 +711,7 @@ static inline int dm_irq_state(struct amdgpu_device *adev, { bool st; enum dc_irq_source irq_source; - + struct dc *dc = adev->dm.dc; struct amdgpu_crtc *acrtc = adev->mode_info.crtcs[crtc_id]; if (!acrtc) { @@ -729,6 +729,9 @@ static inline int dm_irq_state(struct amdgpu_device *adev, st = (state == AMDGPU_IRQ_STATE_ENABLE); + if (dc && dc->caps.ips_support && dc->idle_optimizations_allowed) + dc_allow_idle_optimizations(dc, false); + dc_interrupt_set(adev->dm.dc, irq_source, st); return 0; } @@ -894,10 +897,15 @@ void amdgpu_dm_hpd_init(struct amdgpu_device *adev) drm_connector_list_iter_begin(dev, &iter); drm_for_each_connector_iter(connector, &iter) { - struct amdgpu_dm_connector *amdgpu_dm_connector = - to_amdgpu_dm_connector(connector); + struct amdgpu_dm_connector *amdgpu_dm_connector; + const struct dc_link *dc_link; + + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; - const struct dc_link *dc_link = amdgpu_dm_connector->dc_link; + amdgpu_dm_connector = to_amdgpu_dm_connector(connector); + + dc_link = amdgpu_dm_connector->dc_link; if (dc_link->irq_source_hpd != DC_IRQ_SOURCE_INVALID) { dc_interrupt_set(adev->dm.dc, @@ -930,9 +938,14 @@ void amdgpu_dm_hpd_fini(struct amdgpu_device *adev) drm_connector_list_iter_begin(dev, &iter); drm_for_each_connector_iter(connector, &iter) { - struct amdgpu_dm_connector *amdgpu_dm_connector = - to_amdgpu_dm_connector(connector); - const struct dc_link *dc_link = amdgpu_dm_connector->dc_link; + struct amdgpu_dm_connector *amdgpu_dm_connector; + const struct dc_link *dc_link; + + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + + amdgpu_dm_connector = to_amdgpu_dm_connector(connector); + dc_link = amdgpu_dm_connector->dc_link; if (dc_link->irq_source_hpd != DC_IRQ_SOURCE_INVALID) { dc_interrupt_set(adev->dm.dc, 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 11da0eebee6c4b..941e96f100f4e5 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 @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include "dm_services.h" #include "amdgpu.h" #include "amdgpu_dm.h" @@ -44,7 +46,7 @@ #include "amdgpu_dm_debugfs.h" #endif -#include "dc/dcn20/dcn20_resource.h" +#include "dc/resource/dcn20/dcn20_resource.h" #define PEAK_FACTOR_X1000 1006 @@ -424,8 +426,7 @@ dm_mst_atomic_best_encoder(struct drm_connector *connector, { struct drm_connector_state *connector_state = drm_atomic_get_new_connector_state(state, connector); - struct drm_device *dev = connector->dev; - struct amdgpu_device *adev = drm_to_adev(dev); + struct amdgpu_device *adev = drm_to_adev(connector->dev); struct amdgpu_crtc *acrtc = to_amdgpu_crtc(connector_state->crtc); return &adev->dm.mst_encoders[acrtc->crtc_id].base; @@ -941,10 +942,10 @@ static int increase_dsc_bpp(struct drm_atomic_state *state, link_timeslots_used = 0; for (i = 0; i < count; i++) - link_timeslots_used += DIV_ROUND_UP(vars[i + k].pbn, mst_state->pbn_div); + link_timeslots_used += DIV_ROUND_UP(vars[i + k].pbn, dfixed_trunc(mst_state->pbn_div)); fair_pbn_alloc = - (63 - link_timeslots_used) / remaining_to_increase * mst_state->pbn_div; + (63 - link_timeslots_used) / remaining_to_increase * dfixed_trunc(mst_state->pbn_div); if (initial_slack[next_index] > fair_pbn_alloc) { vars[next_index].pbn += fair_pbn_alloc; @@ -1500,14 +1501,16 @@ int pre_validate_dsc(struct drm_atomic_state *state, int ind = find_crtc_index_in_state_by_stream(state, stream); if (ind >= 0) { + struct drm_connector *connector; struct amdgpu_dm_connector *aconnector; struct drm_connector_state *drm_new_conn_state; struct dm_connector_state *dm_new_conn_state; struct dm_crtc_state *dm_old_crtc_state; - aconnector = + connector = amdgpu_dm_find_first_crtc_matching_connector(state, state->crtcs[ind].ptr); + aconnector = to_amdgpu_dm_connector(connector); drm_new_conn_state = drm_atomic_get_new_connector_state(state, &aconnector->base); @@ -1602,9 +1605,8 @@ enum dc_status dm_dp_mst_is_port_support_mode( struct dc_link_settings cur_link_settings; unsigned int end_to_end_bw_in_kbps = 0; unsigned int upper_link_bw_in_kbps = 0, down_link_bw_in_kbps = 0; - unsigned int max_compressed_bw_in_kbps = 0; struct dc_dsc_bw_range bw_range = {0}; - uint16_t full_pbn = aconnector->mst_output_port->full_pbn; + struct dc_dsc_config_options dsc_options = {0}; /* * Consider the case with the depth of the mst topology tree is equal or less than 2 @@ -1620,30 +1622,39 @@ enum dc_status dm_dp_mst_is_port_support_mode( (aconnector->mst_output_port->passthrough_aux || aconnector->dsc_aux == &aconnector->mst_output_port->aux)) { cur_link_settings = stream->link->verified_link_cap; + upper_link_bw_in_kbps = dc_link_bandwidth_kbps(aconnector->dc_link, &cur_link_settings); + down_link_bw_in_kbps = kbps_from_pbn(aconnector->mst_output_port->full_pbn); - upper_link_bw_in_kbps = dc_link_bandwidth_kbps(aconnector->dc_link, - &cur_link_settings); - down_link_bw_in_kbps = kbps_from_pbn(full_pbn); - - /* pick the bottleneck */ - end_to_end_bw_in_kbps = min(upper_link_bw_in_kbps, - down_link_bw_in_kbps); - - /* - * use the maximum dsc compression bandwidth as the required - * bandwidth for the mode - */ - max_compressed_bw_in_kbps = bw_range.min_kbps; + /* pick the end to end bw bottleneck */ + end_to_end_bw_in_kbps = min(upper_link_bw_in_kbps, down_link_bw_in_kbps); - if (end_to_end_bw_in_kbps < max_compressed_bw_in_kbps) { - DRM_DEBUG_DRIVER("Mode does not fit into DSC pass-through bandwidth validation\n"); + if (end_to_end_bw_in_kbps < bw_range.min_kbps) { + DRM_DEBUG_DRIVER("maximum dsc compression cannot fit into end-to-end bandwidth\n"); return DC_FAIL_BANDWIDTH_VALIDATE; } + + if (end_to_end_bw_in_kbps < bw_range.stream_kbps) { + dc_dsc_get_default_config_option(stream->link->dc, &dsc_options); + dsc_options.max_target_bpp_limit_override_x16 = aconnector->base.display_info.max_dsc_bpp * 16; + if (dc_dsc_compute_config(stream->sink->ctx->dc->res_pool->dscs[0], + &stream->sink->dsc_caps.dsc_dec_caps, + &dsc_options, + end_to_end_bw_in_kbps, + &stream->timing, + dc_link_get_highest_encoding_format(stream->link), + &stream->timing.dsc_cfg)) { + stream->timing.flags.DSC = 1; + DRM_DEBUG_DRIVER("end-to-end bandwidth require dsc and dsc config found\n"); + } else { + DRM_DEBUG_DRIVER("end-to-end bandwidth require dsc but dsc config not found\n"); + return DC_FAIL_BANDWIDTH_VALIDATE; + } + } } else { /* check if mode could be supported within full_pbn */ 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 > full_pbn) + pbn = drm_dp_calc_pbn_mode(stream->timing.pix_clk_100hz / 10, bpp << 4); + if (pbn > aconnector->mst_output_port->full_pbn) return DC_FAIL_BANDWIDTH_VALIDATE; } 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 116121e647ca12..8a4c40b4c27e4f 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 @@ -1337,8 +1337,14 @@ static void amdgpu_dm_plane_drm_plane_reset(struct drm_plane *plane) amdgpu_state = kzalloc(sizeof(*amdgpu_state), GFP_KERNEL); WARN_ON(amdgpu_state == NULL); - if (amdgpu_state) - __drm_atomic_helper_plane_reset(plane, &amdgpu_state->base); + if (!amdgpu_state) + return; + + __drm_atomic_helper_plane_reset(plane, &amdgpu_state->base); + amdgpu_state->degamma_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT; + amdgpu_state->hdr_mult = AMDGPU_HDR_MULT_DEFAULT; + amdgpu_state->shaper_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT; + amdgpu_state->blend_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT; } static struct drm_plane_state *amdgpu_dm_plane_drm_plane_duplicate_state(struct drm_plane *plane) @@ -1357,6 +1363,27 @@ static struct drm_plane_state *amdgpu_dm_plane_drm_plane_duplicate_state(struct dc_plane_state_retain(dm_plane_state->dc_state); } + if (old_dm_plane_state->degamma_lut) + dm_plane_state->degamma_lut = + drm_property_blob_get(old_dm_plane_state->degamma_lut); + if (old_dm_plane_state->ctm) + dm_plane_state->ctm = + drm_property_blob_get(old_dm_plane_state->ctm); + if (old_dm_plane_state->shaper_lut) + dm_plane_state->shaper_lut = + drm_property_blob_get(old_dm_plane_state->shaper_lut); + if (old_dm_plane_state->lut3d) + dm_plane_state->lut3d = + drm_property_blob_get(old_dm_plane_state->lut3d); + if (old_dm_plane_state->blend_lut) + dm_plane_state->blend_lut = + drm_property_blob_get(old_dm_plane_state->blend_lut); + + dm_plane_state->degamma_tf = old_dm_plane_state->degamma_tf; + dm_plane_state->hdr_mult = old_dm_plane_state->hdr_mult; + dm_plane_state->shaper_tf = old_dm_plane_state->shaper_tf; + dm_plane_state->blend_tf = old_dm_plane_state->blend_tf; + return &dm_plane_state->base; } @@ -1424,12 +1451,206 @@ static void amdgpu_dm_plane_drm_plane_destroy_state(struct drm_plane *plane, { struct dm_plane_state *dm_plane_state = to_dm_plane_state(state); + if (dm_plane_state->degamma_lut) + drm_property_blob_put(dm_plane_state->degamma_lut); + if (dm_plane_state->ctm) + drm_property_blob_put(dm_plane_state->ctm); + if (dm_plane_state->lut3d) + drm_property_blob_put(dm_plane_state->lut3d); + if (dm_plane_state->shaper_lut) + drm_property_blob_put(dm_plane_state->shaper_lut); + if (dm_plane_state->blend_lut) + drm_property_blob_put(dm_plane_state->blend_lut); + if (dm_plane_state->dc_state) dc_plane_state_release(dm_plane_state->dc_state); drm_atomic_helper_plane_destroy_state(plane, state); } +#ifdef AMD_PRIVATE_COLOR +static void +dm_atomic_plane_attach_color_mgmt_properties(struct amdgpu_display_manager *dm, + struct drm_plane *plane) +{ + struct amdgpu_mode_info mode_info = dm->adev->mode_info; + struct dpp_color_caps dpp_color_caps = dm->dc->caps.color.dpp; + + /* Check HW color pipeline capabilities on DPP block (pre-blending) + * before exposing related properties. + */ + if (dpp_color_caps.dgam_ram || dpp_color_caps.gamma_corr) { + drm_object_attach_property(&plane->base, + mode_info.plane_degamma_lut_property, + 0); + drm_object_attach_property(&plane->base, + mode_info.plane_degamma_lut_size_property, + MAX_COLOR_LUT_ENTRIES); + drm_object_attach_property(&plane->base, + dm->adev->mode_info.plane_degamma_tf_property, + AMDGPU_TRANSFER_FUNCTION_DEFAULT); + } + /* HDR MULT is always available */ + drm_object_attach_property(&plane->base, + dm->adev->mode_info.plane_hdr_mult_property, + AMDGPU_HDR_MULT_DEFAULT); + + /* Only enable plane CTM if both DPP and MPC gamut remap is available. */ + if (dm->dc->caps.color.mpc.gamut_remap) + drm_object_attach_property(&plane->base, + dm->adev->mode_info.plane_ctm_property, 0); + + if (dpp_color_caps.hw_3d_lut) { + drm_object_attach_property(&plane->base, + mode_info.plane_shaper_lut_property, 0); + drm_object_attach_property(&plane->base, + mode_info.plane_shaper_lut_size_property, + MAX_COLOR_LUT_ENTRIES); + drm_object_attach_property(&plane->base, + mode_info.plane_shaper_tf_property, + AMDGPU_TRANSFER_FUNCTION_DEFAULT); + drm_object_attach_property(&plane->base, + mode_info.plane_lut3d_property, 0); + drm_object_attach_property(&plane->base, + mode_info.plane_lut3d_size_property, + MAX_COLOR_3DLUT_SIZE); + } + + if (dpp_color_caps.ogam_ram) { + drm_object_attach_property(&plane->base, + mode_info.plane_blend_lut_property, 0); + drm_object_attach_property(&plane->base, + mode_info.plane_blend_lut_size_property, + MAX_COLOR_LUT_ENTRIES); + drm_object_attach_property(&plane->base, + mode_info.plane_blend_tf_property, + AMDGPU_TRANSFER_FUNCTION_DEFAULT); + } +} + +static int +dm_atomic_plane_set_property(struct drm_plane *plane, + struct drm_plane_state *state, + struct drm_property *property, + uint64_t val) +{ + struct dm_plane_state *dm_plane_state = to_dm_plane_state(state); + struct amdgpu_device *adev = drm_to_adev(plane->dev); + bool replaced = false; + int ret; + + if (property == adev->mode_info.plane_degamma_lut_property) { + ret = drm_property_replace_blob_from_id(plane->dev, + &dm_plane_state->degamma_lut, + val, -1, + sizeof(struct drm_color_lut), + &replaced); + dm_plane_state->base.color_mgmt_changed |= replaced; + return ret; + } else if (property == adev->mode_info.plane_degamma_tf_property) { + if (dm_plane_state->degamma_tf != val) { + dm_plane_state->degamma_tf = val; + dm_plane_state->base.color_mgmt_changed = 1; + } + } else if (property == adev->mode_info.plane_hdr_mult_property) { + if (dm_plane_state->hdr_mult != val) { + dm_plane_state->hdr_mult = val; + dm_plane_state->base.color_mgmt_changed = 1; + } + } else if (property == adev->mode_info.plane_ctm_property) { + ret = drm_property_replace_blob_from_id(plane->dev, + &dm_plane_state->ctm, + val, + sizeof(struct drm_color_ctm_3x4), -1, + &replaced); + dm_plane_state->base.color_mgmt_changed |= replaced; + return ret; + } else if (property == adev->mode_info.plane_shaper_lut_property) { + ret = drm_property_replace_blob_from_id(plane->dev, + &dm_plane_state->shaper_lut, + val, -1, + sizeof(struct drm_color_lut), + &replaced); + dm_plane_state->base.color_mgmt_changed |= replaced; + return ret; + } else if (property == adev->mode_info.plane_shaper_tf_property) { + if (dm_plane_state->shaper_tf != val) { + dm_plane_state->shaper_tf = val; + dm_plane_state->base.color_mgmt_changed = 1; + } + } else if (property == adev->mode_info.plane_lut3d_property) { + ret = drm_property_replace_blob_from_id(plane->dev, + &dm_plane_state->lut3d, + val, -1, + sizeof(struct drm_color_lut), + &replaced); + dm_plane_state->base.color_mgmt_changed |= replaced; + return ret; + } else if (property == adev->mode_info.plane_blend_lut_property) { + ret = drm_property_replace_blob_from_id(plane->dev, + &dm_plane_state->blend_lut, + val, -1, + sizeof(struct drm_color_lut), + &replaced); + dm_plane_state->base.color_mgmt_changed |= replaced; + return ret; + } else if (property == adev->mode_info.plane_blend_tf_property) { + if (dm_plane_state->blend_tf != val) { + dm_plane_state->blend_tf = val; + dm_plane_state->base.color_mgmt_changed = 1; + } + } else { + drm_dbg_atomic(plane->dev, + "[PLANE:%d:%s] unknown property [PROP:%d:%s]]\n", + plane->base.id, plane->name, + property->base.id, property->name); + return -EINVAL; + } + + return 0; +} + +static int +dm_atomic_plane_get_property(struct drm_plane *plane, + const struct drm_plane_state *state, + struct drm_property *property, + uint64_t *val) +{ + struct dm_plane_state *dm_plane_state = to_dm_plane_state(state); + struct amdgpu_device *adev = drm_to_adev(plane->dev); + + if (property == adev->mode_info.plane_degamma_lut_property) { + *val = (dm_plane_state->degamma_lut) ? + dm_plane_state->degamma_lut->base.id : 0; + } else if (property == adev->mode_info.plane_degamma_tf_property) { + *val = dm_plane_state->degamma_tf; + } else if (property == adev->mode_info.plane_hdr_mult_property) { + *val = dm_plane_state->hdr_mult; + } else if (property == adev->mode_info.plane_ctm_property) { + *val = (dm_plane_state->ctm) ? + dm_plane_state->ctm->base.id : 0; + } else if (property == adev->mode_info.plane_shaper_lut_property) { + *val = (dm_plane_state->shaper_lut) ? + dm_plane_state->shaper_lut->base.id : 0; + } else if (property == adev->mode_info.plane_shaper_tf_property) { + *val = dm_plane_state->shaper_tf; + } else if (property == adev->mode_info.plane_lut3d_property) { + *val = (dm_plane_state->lut3d) ? + dm_plane_state->lut3d->base.id : 0; + } else if (property == adev->mode_info.plane_blend_lut_property) { + *val = (dm_plane_state->blend_lut) ? + dm_plane_state->blend_lut->base.id : 0; + } else if (property == adev->mode_info.plane_blend_tf_property) { + *val = dm_plane_state->blend_tf; + + } else { + return -EINVAL; + } + + return 0; +} +#endif + static const struct drm_plane_funcs dm_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, @@ -1438,6 +1659,10 @@ static const struct drm_plane_funcs dm_plane_funcs = { .atomic_duplicate_state = amdgpu_dm_plane_drm_plane_duplicate_state, .atomic_destroy_state = amdgpu_dm_plane_drm_plane_destroy_state, .format_mod_supported = amdgpu_dm_plane_format_mod_supported, +#ifdef AMD_PRIVATE_COLOR + .atomic_set_property = dm_atomic_plane_set_property, + .atomic_get_property = dm_atomic_plane_get_property, +#endif }; int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm, @@ -1517,6 +1742,9 @@ int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm, drm_plane_helper_add(plane, &dm_plane_helper_funcs); +#ifdef AMD_PRIVATE_COLOR + dm_atomic_plane_attach_color_mgmt_properties(dm, plane); +#endif /* Create (reset) the plane state */ if (plane->funcs->reset) plane->funcs->reset(plane); 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 08ce3bb8f640d9..1f08c6564c3bfe 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 @@ -51,6 +51,9 @@ static bool link_supports_psrsu(struct dc_link *link) !link->dpcd_caps.psr_info.psr2_su_y_granularity_cap) return false; + if (amdgpu_dc_debug_mask & DC_DISABLE_PSR_SU) + return false; + return dc_dmub_check_min_version(dc->ctx->dmub_srv->dmub); } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.c new file mode 100644 index 00000000000000..16e72d623630ca --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.c @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: MIT +/* + * 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 "dm_services_types.h" + +#include "amdgpu.h" +#include "amdgpu_dm.h" +#include "amdgpu_dm_wb.h" +#include "amdgpu_display.h" +#include "dc.h" + +#include +#include +#include + +static const u32 amdgpu_dm_wb_formats[] = { + DRM_FORMAT_XRGB2101010, +}; + +static int amdgpu_dm_wb_encoder_atomic_check(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct drm_framebuffer *fb; + const struct drm_display_mode *mode = &crtc_state->mode; + bool found = false; + uint8_t i; + + if (!conn_state->writeback_job || !conn_state->writeback_job->fb) + return 0; + + fb = conn_state->writeback_job->fb; + if (fb->width != mode->hdisplay || fb->height != mode->vdisplay) { + DRM_DEBUG_KMS("Invalid framebuffer size %ux%u\n", + fb->width, fb->height); + return -EINVAL; + } + + for (i = 0; i < sizeof(amdgpu_dm_wb_formats) / sizeof(u32); i++) { + if (fb->format->format == amdgpu_dm_wb_formats[i]) + found = true; + } + + if (!found) { + DRM_DEBUG_KMS("Invalid pixel format %p4cc\n", + &fb->format->format); + return -EINVAL; + } + + return 0; +} + + +static int amdgpu_dm_wb_connector_get_modes(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + + return drm_add_modes_noedid(connector, dev->mode_config.max_width, + dev->mode_config.max_height); +} + +static int amdgpu_dm_wb_prepare_job(struct drm_writeback_connector *wb_connector, + struct drm_writeback_job *job) +{ + struct amdgpu_framebuffer *afb; + struct drm_gem_object *obj; + struct amdgpu_device *adev; + struct amdgpu_bo *rbo; + uint32_t domain; + int r; + + if (!job->fb) { + DRM_DEBUG_KMS("No FB bound\n"); + return 0; + } + + afb = to_amdgpu_framebuffer(job->fb); + obj = job->fb->obj[0]; + rbo = gem_to_amdgpu_bo(obj); + adev = amdgpu_ttm_adev(rbo->tbo.bdev); + + r = amdgpu_bo_reserve(rbo, true); + if (r) { + dev_err(adev->dev, "fail to reserve bo (%d)\n", r); + return r; + } + + r = dma_resv_reserve_fences(rbo->tbo.base.resv, 1); + if (r) { + dev_err(adev->dev, "reserving fence slot failed (%d)\n", r); + goto error_unlock; + } + + domain = amdgpu_display_supported_domains(adev, rbo->flags); + + r = amdgpu_bo_pin(rbo, domain); + if (unlikely(r != 0)) { + if (r != -ERESTARTSYS) + DRM_ERROR("Failed to pin framebuffer with error %d\n", r); + goto error_unlock; + } + + r = amdgpu_ttm_alloc_gart(&rbo->tbo); + if (unlikely(r != 0)) { + DRM_ERROR("%p bind failed\n", rbo); + goto error_unpin; + } + + amdgpu_bo_unreserve(rbo); + + afb->address = amdgpu_bo_gpu_offset(rbo); + + amdgpu_bo_ref(rbo); + + return 0; + +error_unpin: + amdgpu_bo_unpin(rbo); + +error_unlock: + amdgpu_bo_unreserve(rbo); + return r; +} + +static void amdgpu_dm_wb_cleanup_job(struct drm_writeback_connector *connector, + struct drm_writeback_job *job) +{ + struct amdgpu_bo *rbo; + int r; + + if (!job->fb) + return; + + rbo = gem_to_amdgpu_bo(job->fb->obj[0]); + r = amdgpu_bo_reserve(rbo, false); + if (unlikely(r)) { + DRM_ERROR("failed to reserve rbo before unpin\n"); + return; + } + + amdgpu_bo_unpin(rbo); + amdgpu_bo_unreserve(rbo); + amdgpu_bo_unref(&rbo); +} + +static const struct drm_encoder_helper_funcs amdgpu_dm_wb_encoder_helper_funcs = { + .atomic_check = amdgpu_dm_wb_encoder_atomic_check, +}; + +static const struct drm_connector_funcs amdgpu_dm_wb_connector_funcs = { + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = drm_connector_cleanup, + .reset = amdgpu_dm_connector_funcs_reset, + .atomic_duplicate_state = amdgpu_dm_connector_atomic_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +static const struct drm_connector_helper_funcs amdgpu_dm_wb_conn_helper_funcs = { + .get_modes = amdgpu_dm_wb_connector_get_modes, + .prepare_writeback_job = amdgpu_dm_wb_prepare_job, + .cleanup_writeback_job = amdgpu_dm_wb_cleanup_job, +}; + +int amdgpu_dm_wb_connector_init(struct amdgpu_display_manager *dm, + struct amdgpu_dm_wb_connector *wbcon, + uint32_t link_index) +{ + struct dc *dc = dm->dc; + struct dc_link *link = dc_get_link_at_index(dc, link_index); + int res = 0; + + wbcon->link = link; + + drm_connector_helper_add(&wbcon->base.base, &amdgpu_dm_wb_conn_helper_funcs); + + res = drm_writeback_connector_init(&dm->adev->ddev, &wbcon->base, + &amdgpu_dm_wb_connector_funcs, + &amdgpu_dm_wb_encoder_helper_funcs, + amdgpu_dm_wb_formats, + ARRAY_SIZE(amdgpu_dm_wb_formats), + amdgpu_dm_get_encoder_crtc_mask(dm->adev)); + + if (res) + return res; + /* + * Some of the properties below require access to state, like bpc. + * Allocate some default initial connector state with our reset helper. + */ + if (wbcon->base.base.funcs->reset) + wbcon->base.base.funcs->reset(&wbcon->base.base); + + return 0; +} diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.h new file mode 100644 index 00000000000000..13d31c857dee49 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: MIT */ +/* + * 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 __AMDGPU_DM_WB_H__ +#define __AMDGPU_DM_WB_H__ + +#include + +int amdgpu_dm_wb_connector_init(struct amdgpu_display_manager *dm, + struct amdgpu_dm_wb_connector *dm_wbcon, + uint32_t link_index); + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/Makefile b/drivers/gpu/drm/amd/display/dc/Makefile index 3a169b78e7e432..7991ae468f752c 100644 --- a/drivers/gpu/drm/amd/display/dc/Makefile +++ b/drivers/gpu/drm/amd/display/dc/Makefile @@ -22,7 +22,7 @@ # # Makefile for Display Core (dc) component. -DC_LIBS = basics bios dml clk_mgr dce gpio hwss irq link virtual dsc +DC_LIBS = basics bios dml clk_mgr dce gpio hwss irq link virtual dsc resource optc ifdef CONFIG_DRM_AMD_DC_FP @@ -34,12 +34,8 @@ DC_LIBS += dcn21 DC_LIBS += dcn201 DC_LIBS += dcn30 DC_LIBS += dcn301 -DC_LIBS += dcn302 -DC_LIBS += dcn303 DC_LIBS += dcn31 DC_LIBS += dcn314 -DC_LIBS += dcn315 -DC_LIBS += dcn316 DC_LIBS += dcn32 DC_LIBS += dcn321 DC_LIBS += dcn35 @@ -51,7 +47,6 @@ DC_LIBS += dce120 DC_LIBS += dce112 DC_LIBS += dce110 -DC_LIBS += dce100 DC_LIBS += dce80 ifdef CONFIG_DRM_AMD_DC_SI @@ -65,7 +60,7 @@ AMD_DC = $(addsuffix /Makefile, $(addprefix $(FULL_AMD_DISPLAY_PATH)/dc/,$(DC_LI include $(AMD_DC) 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 +dc_surface.o dc_debug.o dc_stream.o dc_link_enc_cfg.o dc_link_exports.o dc_state.o DISPLAY_CORE += dc_vm_helper.o diff --git a/drivers/gpu/drm/amd/display/dc/basics/conversion.c b/drivers/gpu/drm/amd/display/dc/basics/conversion.c index e295a839ab4761..1090d235086aca 100644 --- a/drivers/gpu/drm/amd/display/dc/basics/conversion.c +++ b/drivers/gpu/drm/amd/display/dc/basics/conversion.c @@ -103,7 +103,8 @@ void convert_float_matrix( static uint32_t find_gcd(uint32_t a, uint32_t b) { - uint32_t remainder = 0; + uint32_t remainder; + while (b != 0) { remainder = a % b; a = b; 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 2d1f5efa9091a4..960c4b4f6ddf36 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c @@ -1698,7 +1698,7 @@ 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 pwrseq_instance, uint8_t bypass_panel_control_wait) { struct bios_parser *bp = BP_FROM_DCB(dcb); @@ -1706,7 +1706,7 @@ static enum bp_result bios_parser_enable_lvtma_control( if (!bp->cmd_tbl.enable_lvtma_control) return BP_RESULT_FAILURE; - return bp->cmd_tbl.enable_lvtma_control(bp, uc_pwr_on, panel_instance, bypass_panel_control_wait); + return bp->cmd_tbl.enable_lvtma_control(bp, uc_pwr_on, pwrseq_instance, bypass_panel_control_wait); } static bool bios_parser_is_accelerated_mode( @@ -2221,22 +2221,22 @@ static enum bp_result bios_parser_get_disp_connector_caps_info( switch (bp->object_info_tbl.revision.minor) { case 4: - default: - object = get_bios_object(bp, object_id); - - if (!object) - return BP_RESULT_BADINPUT; - - record = get_disp_connector_caps_record(bp, object); - if (!record) - return BP_RESULT_NORECORD; - - info->INTERNAL_DISPLAY = - (record->connectcaps & ATOM_CONNECTOR_CAP_INTERNAL_DISPLAY) ? 1 : 0; - info->INTERNAL_DISPLAY_BL = - (record->connectcaps & ATOM_CONNECTOR_CAP_INTERNAL_DISPLAY_BL) ? 1 : 0; - break; - case 5: + default: + object = get_bios_object(bp, object_id); + + if (!object) + return BP_RESULT_BADINPUT; + + record = get_disp_connector_caps_record(bp, object); + if (!record) + return BP_RESULT_NORECORD; + + info->INTERNAL_DISPLAY = + (record->connectcaps & ATOM_CONNECTOR_CAP_INTERNAL_DISPLAY) ? 1 : 0; + info->INTERNAL_DISPLAY_BL = + (record->connectcaps & ATOM_CONNECTOR_CAP_INTERNAL_DISPLAY_BL) ? 1 : 0; + break; + case 5: object_path_v3 = get_bios_object_from_path_v3(bp, object_id); if (!object_path_v3) @@ -2398,7 +2398,6 @@ static enum bp_result get_vram_info_v30( return result; } - /* * get_integrated_info_v11 * @@ -3332,27 +3331,28 @@ static enum bp_result get_bracket_layout_record( DC_LOG_DETECTION_EDID_PARSER("Invalid slot_layout_info\n"); return BP_RESULT_BADINPUT; } + tbl = &bp->object_info_tbl; v1_4 = tbl->v1_4; v1_5 = tbl->v1_5; result = BP_RESULT_NORECORD; switch (bp->object_info_tbl.revision.minor) { - case 4: - default: - for (i = 0; i < v1_4->number_of_path; ++i) { - if (bracket_layout_id == - v1_4->display_path[i].display_objid) { - result = update_slot_layout_info(dcb, i, slot_layout_info); - break; - } + case 4: + default: + for (i = 0; i < v1_4->number_of_path; ++i) { + if (bracket_layout_id == v1_4->display_path[i].display_objid) { + result = update_slot_layout_info(dcb, i, slot_layout_info); + break; } - break; - case 5: - for (i = 0; i < v1_5->number_of_path; ++i) - result = update_slot_layout_info_v2(dcb, i, slot_layout_info); - break; + } + break; + case 5: + for (i = 0; i < v1_5->number_of_path; ++i) + result = update_slot_layout_info_v2(dcb, i, slot_layout_info); + break; } + return result; } @@ -3361,9 +3361,7 @@ static enum bp_result bios_get_board_layout_info( struct board_layout_info *board_layout_info) { unsigned int i; - struct bios_parser *bp; - static enum bp_result record_result; unsigned int max_slots; @@ -3373,7 +3371,6 @@ static enum bp_result bios_get_board_layout_info( 0, 0 }; - bp = BP_FROM_DCB(dcb); if (board_layout_info == NULL) { @@ -3554,7 +3551,6 @@ static const struct dc_vbios_funcs vbios_funcs = { .bios_parser_destroy = firmware_parser_destroy, .get_board_layout_info = bios_get_board_layout_info, - /* TODO: use this fn in hw init?*/ .pack_data_tables = bios_parser_pack_data_tables, .get_atom_dc_golden_table = bios_get_atom_dc_golden_table, 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 90a02d7bd3da3f..293a919d605d16 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c @@ -123,7 +123,7 @@ static void encoder_control_dmcub( sizeof(cmd.digx_encoder_control.header); cmd.digx_encoder_control.encoder_control.dig.stream_param = *dig; - dm_execute_dmub_cmd(dmcub->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dmcub->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); } static enum bp_result encoder_control_digx_v1_5( @@ -259,7 +259,7 @@ static void transmitter_control_dmcub( sizeof(cmd.dig1_transmitter_control.header); cmd.dig1_transmitter_control.transmitter_control.dig = *dig; - dm_execute_dmub_cmd(dmcub->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dmcub->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); } static enum bp_result transmitter_control_v1_6( @@ -321,7 +321,7 @@ static void transmitter_control_dmcub_v1_7( sizeof(cmd.dig1_transmitter_control.header); cmd.dig1_transmitter_control.transmitter_control.dig_v1_7 = *dig; - dm_execute_dmub_cmd(dmcub->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dmcub->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); } static enum bp_result transmitter_control_v1_7( @@ -429,7 +429,7 @@ static void set_pixel_clock_dmcub( sizeof(cmd.set_pixel_clock.header); cmd.set_pixel_clock.pixel_clock.clk = *clk; - dm_execute_dmub_cmd(dmcub->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dmcub->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); } static enum bp_result set_pixel_clock_v7( @@ -796,7 +796,7 @@ static void enable_disp_power_gating_dmcub( sizeof(cmd.enable_disp_power_gating.header); cmd.enable_disp_power_gating.power_gating.pwr = *pwr; - dm_execute_dmub_cmd(dmcub->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dmcub->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); } static enum bp_result enable_disp_power_gating_v2_1( @@ -976,7 +976,7 @@ 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 pwrseq_instance, uint8_t bypass_panel_control_wait); static void init_enable_lvtma_control(struct bios_parser *bp) @@ -989,7 +989,7 @@ 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 pwrseq_instance, uint8_t bypass_panel_control_wait) { @@ -1002,17 +1002,17 @@ static void enable_lvtma_control_dmcub( DMUB_CMD__VBIOS_LVTMA_CONTROL; cmd.lvtma_control.data.uc_pwr_action = uc_pwr_on; - cmd.lvtma_control.data.panel_inst = - panel_instance; + cmd.lvtma_control.data.pwrseq_inst = + pwrseq_instance; cmd.lvtma_control.data.bypass_panel_control_wait = bypass_panel_control_wait; - dm_execute_dmub_cmd(dmcub->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dmcub->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); } static enum bp_result enable_lvtma_control( struct bios_parser *bp, uint8_t uc_pwr_on, - uint8_t panel_instance, + uint8_t pwrseq_instance, uint8_t bypass_panel_control_wait) { enum bp_result result = BP_RESULT_FAILURE; @@ -1021,7 +1021,7 @@ 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, + pwrseq_instance, bypass_panel_control_wait); return BP_RESULT_OK; } 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 b6d09bf6cf72b6..41c8c014397f29 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,7 @@ 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 pwrseq_instance, uint8_t bypass_panel_control_wait); }; 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 3e73c4e59d4083..28a2a837d2f0a7 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 "dc_state_priv.h" #include "link.h" #include "dce100/dce_clk_mgr.h" @@ -63,7 +64,7 @@ int clk_mgr_helper_get_active_display_cnt( /* Don't count SubVP phantom pipes as part of active * display count */ - if (stream->mall_stream_config.type == SUBVP_PHANTOM) + if (dc_state_get_stream_subvp_type(context, stream) == SUBVP_PHANTOM) continue; /* @@ -368,7 +369,7 @@ struct clk_mgr *dc_clk_mgr_create(struct dc_context *ctx, struct pp_smu_funcs *p } break; -#endif /* CONFIG_DRM_AMD_DC_FP - Family RV */ +#endif /* CONFIG_DRM_AMD_DC_FP */ default: ASSERT(0); /* Unknown Asic */ break; 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 3db4ef564b997a..ce1386e22576ec 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 @@ -253,7 +253,7 @@ void dcn31_update_clocks(struct clk_mgr *clk_mgr_base, cmd.notify_clocks.clocks.dispclk_khz = clk_mgr_base->clks.dispclk_khz; cmd.notify_clocks.clocks.dppclk_khz = clk_mgr_base->clks.dppclk_khz; - dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); } static int get_vco_frequency_from_reg(struct clk_mgr_internal *clk_mgr) 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 7326b756584610..a84f1e376dee45 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 @@ -87,6 +87,20 @@ static const struct IP_BASE CLK_BASE = { { { { 0x00016C00, 0x02401800, 0, 0, 0, #define CLK1_CLK_PLL_REQ__PllSpineDiv_MASK 0x0000F000L #define CLK1_CLK_PLL_REQ__FbMult_frac_MASK 0xFFFF0000L +#define regCLK1_CLK2_BYPASS_CNTL 0x029c +#define regCLK1_CLK2_BYPASS_CNTL_BASE_IDX 0 + +#define CLK1_CLK2_BYPASS_CNTL__CLK2_BYPASS_SEL__SHIFT 0x0 +#define CLK1_CLK2_BYPASS_CNTL__CLK2_BYPASS_DIV__SHIFT 0x10 +#define CLK1_CLK2_BYPASS_CNTL__CLK2_BYPASS_SEL_MASK 0x00000007L +#define CLK1_CLK2_BYPASS_CNTL__CLK2_BYPASS_DIV_MASK 0x000F0000L + +#define regCLK6_0_CLK6_spll_field_8 0x464b +#define regCLK6_0_CLK6_spll_field_8_BASE_IDX 0 + +#define CLK6_0_CLK6_spll_field_8__spll_ssc_en__SHIFT 0xd +#define CLK6_0_CLK6_spll_field_8__spll_ssc_en_MASK 0x00002000L + #define REG(reg_name) \ (CLK_BASE.instance[0].segment[reg ## reg_name ## _BASE_IDX] + reg ## reg_name) @@ -131,35 +145,63 @@ static int dcn314_get_active_display_cnt_wa( return display_count; } -static void dcn314_disable_otg_wa(struct clk_mgr *clk_mgr_base, struct dc_state *context, bool disable) +static void dcn314_disable_otg_wa(struct clk_mgr *clk_mgr_base, struct dc_state *context, + bool safe_to_lower, bool disable) { struct dc *dc = clk_mgr_base->ctx->dc; int i; 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 = safe_to_lower + ? &context->res_ctx.pipe_ctx[i] + : &dc->current_state->res_ctx.pipe_ctx[i]; if (pipe->top_pipe || pipe->prev_odm_pipe) continue; if (pipe->stream && (pipe->stream->dpms_off || dc_is_virtual_signal(pipe->stream->signal))) { - struct stream_encoder *stream_enc = pipe->stream_res.stream_enc; - if (disable) { - if (stream_enc && stream_enc->funcs->disable_fifo) - pipe->stream_res.stream_enc->funcs->disable_fifo(stream_enc); + if (pipe->stream_res.tg && pipe->stream_res.tg->funcs->immediate_disable_crtc) + pipe->stream_res.tg->funcs->immediate_disable_crtc(pipe->stream_res.tg); - 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); - - if (stream_enc && stream_enc->funcs->enable_fifo) - pipe->stream_res.stream_enc->funcs->enable_fifo(stream_enc); } } } } +bool dcn314_is_spll_ssc_enabled(struct clk_mgr *clk_mgr_base) +{ + struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); + uint32_t ssc_enable; + + REG_GET(CLK6_0_CLK6_spll_field_8, spll_ssc_en, &ssc_enable); + + return ssc_enable == 1; +} + +void dcn314_init_clocks(struct clk_mgr *clk_mgr) +{ + struct clk_mgr_internal *clk_mgr_int = TO_CLK_MGR_INTERNAL(clk_mgr); + uint32_t ref_dtbclk = clk_mgr->clks.ref_dtbclk_khz; + + memset(&(clk_mgr->clks), 0, sizeof(struct dc_clocks)); + // Assumption is that boot state always supports pstate + clk_mgr->clks.ref_dtbclk_khz = ref_dtbclk; // restore ref_dtbclk + clk_mgr->clks.p_state_change_support = true; + clk_mgr->clks.prev_p_state_change_support = true; + clk_mgr->clks.pwr_state = DCN_PWR_STATE_UNKNOWN; + clk_mgr->clks.zstate_support = DCN_ZSTATE_SUPPORT_UNKNOWN; + + // to adjust dp_dto reference clock if ssc is enable otherwise to apply dprefclk + if (dcn314_is_spll_ssc_enabled(clk_mgr)) + clk_mgr->dp_dto_source_clock_in_khz = + dce_adjust_dp_ref_freq_for_ss(clk_mgr_int, clk_mgr->dprefclk_khz); + else + clk_mgr->dp_dto_source_clock_in_khz = clk_mgr->dprefclk_khz; +} + void dcn314_update_clocks(struct clk_mgr *clk_mgr_base, struct dc_state *context, bool safe_to_lower) @@ -252,11 +294,11 @@ void dcn314_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)) { - dcn314_disable_otg_wa(clk_mgr_base, context, true); + dcn314_disable_otg_wa(clk_mgr_base, context, safe_to_lower, true); clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz; dcn314_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz); - dcn314_disable_otg_wa(clk_mgr_base, context, false); + dcn314_disable_otg_wa(clk_mgr_base, context, safe_to_lower, false); update_dispclk = true; } @@ -284,7 +326,7 @@ void dcn314_update_clocks(struct clk_mgr *clk_mgr_base, cmd.notify_clocks.clocks.dispclk_khz = clk_mgr_base->clks.dispclk_khz; cmd.notify_clocks.clocks.dppclk_khz = clk_mgr_base->clks.dppclk_khz; - dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); } static int get_vco_frequency_from_reg(struct clk_mgr_internal *clk_mgr) @@ -436,6 +478,11 @@ static DpmClocks314_t dummy_clocks; static struct dcn314_watermarks dummy_wms = { 0 }; +static struct dcn314_ss_info_table ss_info_table = { + .ss_divider = 1000, + .ss_percentage = {0, 0, 375, 375, 375} +}; + static void dcn314_build_watermark_ranges(struct clk_bw_params *bw_params, struct dcn314_watermarks *table) { int i, num_valid_sets; @@ -708,13 +755,31 @@ static struct clk_mgr_funcs dcn314_funcs = { .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, .get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz, .update_clocks = dcn314_update_clocks, - .init_clocks = dcn31_init_clocks, + .init_clocks = dcn314_init_clocks, .enable_pme_wa = dcn314_enable_pme_wa, .are_clock_states_equal = dcn314_are_clock_states_equal, .notify_wm_ranges = dcn314_notify_wm_ranges }; extern struct clk_mgr_funcs dcn3_fpga_funcs; +static void dcn314_read_ss_info_from_lut(struct clk_mgr_internal *clk_mgr) +{ + uint32_t clock_source; + //uint32_t ssc_enable; + + REG_GET(CLK1_CLK2_BYPASS_CNTL, CLK2_BYPASS_SEL, &clock_source); + //REG_GET(CLK6_0_CLK6_spll_field_8, spll_ssc_en, &ssc_enable); + + if (dcn314_is_spll_ssc_enabled(&clk_mgr->base) && (clock_source < ARRAY_SIZE(ss_info_table.ss_percentage))) { + clk_mgr->dprefclk_ss_percentage = ss_info_table.ss_percentage[clock_source]; + + if (clk_mgr->dprefclk_ss_percentage != 0) { + clk_mgr->ss_on_dprefclk = true; + clk_mgr->dprefclk_ss_divider = ss_info_table.ss_divider; + } + } +} + void dcn314_clk_mgr_construct( struct dc_context *ctx, struct clk_mgr_dcn314 *clk_mgr, @@ -782,6 +847,7 @@ void dcn314_clk_mgr_construct( clk_mgr->base.base.dprefclk_khz = 600000; clk_mgr->base.base.clks.ref_dtbclk_khz = 600000; dce_clock_read_ss_info(&clk_mgr->base); + dcn314_read_ss_info_from_lut(&clk_mgr->base); /*if bios enabled SS, driver needs to adjust dtb clock, only enable with correct bios*/ clk_mgr->base.base.bw_params = &dcn314_bw_params; diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.h index 171f84340eb2fb..002c28e807208e 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.h +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.h @@ -28,6 +28,8 @@ #define __DCN314_CLK_MGR_H__ #include "clk_mgr_internal.h" +#define DCN314_NUM_CLOCK_SOURCES 5 + struct dcn314_watermarks; struct dcn314_smu_watermark_set { @@ -40,9 +42,18 @@ struct clk_mgr_dcn314 { struct dcn314_smu_watermark_set smu_wm_set; }; +struct dcn314_ss_info_table { + uint32_t ss_divider; + uint32_t ss_percentage[DCN314_NUM_CLOCK_SOURCES]; +}; + bool dcn314_are_clock_states_equal(struct dc_clocks *a, struct dc_clocks *b); +bool dcn314_is_spll_ssc_enabled(struct clk_mgr *clk_mgr_base); + +void dcn314_init_clocks(struct clk_mgr *clk_mgr); + void dcn314_update_clocks(struct clk_mgr *clk_mgr_base, struct dc_state *context, bool safe_to_lower); 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 8776055bbeaaea..644da463732093 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 @@ -232,7 +232,7 @@ static void dcn315_update_clocks(struct clk_mgr *clk_mgr_base, cmd.notify_clocks.clocks.dispclk_khz = clk_mgr_base->clks.dispclk_khz; cmd.notify_clocks.clocks.dppclk_khz = clk_mgr_base->clks.dppclk_khz; - dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); } static void dcn315_dump_clk_registers(struct clk_state_registers_and_bypass *regs_and_bypass, 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 09151cc56ce4f2..12f3e8aa46d8df 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 @@ -239,7 +239,7 @@ static void dcn316_update_clocks(struct clk_mgr *clk_mgr_base, cmd.notify_clocks.clocks.dispclk_khz = clk_mgr_base->clks.dispclk_khz; cmd.notify_clocks.clocks.dppclk_khz = clk_mgr_base->clks.dppclk_khz; - dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); } static void dcn316_dump_clk_registers(struct clk_state_registers_and_bypass *regs_and_bypass, 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 a496930b1f9c03..aadd07bc68c5db 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 @@ -25,7 +25,6 @@ #include "dccg.h" #include "clk_mgr_internal.h" - #include "dcn32/dcn32_clk_mgr_smu_msg.h" #include "dcn20/dcn20_clk_mgr.h" #include "dce100/dce_clk_mgr.h" @@ -34,7 +33,7 @@ #include "core_types.h" #include "dm_helpers.h" #include "link.h" - +#include "dc_state_priv.h" #include "atomfirmware.h" #include "smu13_driver_if.h" @@ -458,20 +457,56 @@ static int dcn32_get_dispclk_from_dentist(struct clk_mgr *clk_mgr_base) return 0; } -static void dcn32_auto_dpm_test_log(struct dc_clocks *new_clocks, struct clk_mgr_internal *clk_mgr) +static bool dcn32_check_native_scaling(struct pipe_ctx *pipe) { - unsigned int dispclk_khz_reg = REG_READ(CLK1_CLK0_CURRENT_CNT); // DISPCLK - unsigned int dppclk_khz_reg = REG_READ(CLK1_CLK1_CURRENT_CNT); // DPPCLK - unsigned int dprefclk_khz_reg = REG_READ(CLK1_CLK2_CURRENT_CNT); // DPREFCLK - unsigned int dcfclk_khz_reg = REG_READ(CLK1_CLK3_CURRENT_CNT); // DCFCLK - unsigned int dtbclk_khz_reg = REG_READ(CLK1_CLK4_CURRENT_CNT); // DTBCLK - unsigned int fclk_khz_reg = REG_READ(CLK4_CLK0_CURRENT_CNT); // FCLK + bool is_native_scaling = false; + int width = pipe->plane_state->src_rect.width; + int height = pipe->plane_state->src_rect.height; + + if (pipe->stream->timing.h_addressable == width && + pipe->stream->timing.v_addressable == height && + pipe->plane_state->dst_rect.width == width && + pipe->plane_state->dst_rect.height == height) + is_native_scaling = true; + + return is_native_scaling; +} + +static void dcn32_auto_dpm_test_log( + struct dc_clocks *new_clocks, + struct clk_mgr_internal *clk_mgr, + struct dc_state *context) +{ + unsigned int dispclk_khz_reg, dppclk_khz_reg, dprefclk_khz_reg, dcfclk_khz_reg, dtbclk_khz_reg, + fclk_khz_reg, mall_ss_size_bytes; + int dramclk_khz_override, fclk_khz_override, num_fclk_levels; + + struct pipe_ctx *pipe_ctx_list[MAX_PIPES]; + int active_pipe_count = 0; + + for (int i = 0; i < MAX_PIPES; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + if (pipe_ctx->stream && dc_state_get_pipe_subvp_type(context, pipe_ctx) != SUBVP_PHANTOM) { + pipe_ctx_list[active_pipe_count] = pipe_ctx; + active_pipe_count++; + } + } + + mall_ss_size_bytes = context->bw_ctx.bw.dcn.mall_ss_size_bytes; + + dispclk_khz_reg = REG_READ(CLK1_CLK0_CURRENT_CNT); // DISPCLK + dppclk_khz_reg = REG_READ(CLK1_CLK1_CURRENT_CNT); // DPPCLK + dprefclk_khz_reg = REG_READ(CLK1_CLK2_CURRENT_CNT); // DPREFCLK + dcfclk_khz_reg = REG_READ(CLK1_CLK3_CURRENT_CNT); // DCFCLK + dtbclk_khz_reg = REG_READ(CLK1_CLK4_CURRENT_CNT); // DTBCLK + fclk_khz_reg = REG_READ(CLK4_CLK0_CURRENT_CNT); // FCLK // Overrides for these clocks in case there is no p_state change support - int dramclk_khz_override = new_clocks->dramclk_khz; - int fclk_khz_override = new_clocks->fclk_khz; + dramclk_khz_override = new_clocks->dramclk_khz; + fclk_khz_override = new_clocks->fclk_khz; - int num_fclk_levels = clk_mgr->base.bw_params->clk_table.num_entries_per_clk.num_fclk_levels - 1; + num_fclk_levels = clk_mgr->base.bw_params->clk_table.num_entries_per_clk.num_fclk_levels - 1; if (!new_clocks->p_state_change_support) { dramclk_khz_override = clk_mgr->base.bw_params->max_memclk_mhz * 1000; @@ -488,16 +523,49 @@ static void dcn32_auto_dpm_test_log(struct dc_clocks *new_clocks, struct clk_mgr // // AutoDPMTest: clk1:%d - clk2:%d - clk3:%d - clk4:%d\n" //////////////////////////////////////////////////////////////////////////// - if (new_clocks && + if (new_clocks && active_pipe_count > 0 && new_clocks->dramclk_khz > 0 && new_clocks->fclk_khz > 0 && new_clocks->dcfclk_khz > 0 && new_clocks->dppclk_khz > 0) { + uint32_t pix_clk_list[MAX_PIPES] = {0}; + int p_state_list[MAX_PIPES] = {0}; + int disp_src_width_list[MAX_PIPES] = {0}; + int disp_src_height_list[MAX_PIPES] = {0}; + uint64_t disp_src_refresh_list[MAX_PIPES] = {0}; + bool is_scaled_list[MAX_PIPES] = {0}; + + for (int i = 0; i < active_pipe_count; i++) { + struct pipe_ctx *curr_pipe_ctx = pipe_ctx_list[i]; + uint64_t refresh_rate; + + pix_clk_list[i] = curr_pipe_ctx->stream->timing.pix_clk_100hz; + p_state_list[i] = curr_pipe_ctx->p_state_type; + + refresh_rate = (curr_pipe_ctx->stream->timing.pix_clk_100hz * (uint64_t)100 + + curr_pipe_ctx->stream->timing.v_total * curr_pipe_ctx->stream->timing.h_total - (uint64_t)1); + refresh_rate = div_u64(refresh_rate, curr_pipe_ctx->stream->timing.v_total); + refresh_rate = div_u64(refresh_rate, curr_pipe_ctx->stream->timing.h_total); + disp_src_refresh_list[i] = refresh_rate; + + if (curr_pipe_ctx->plane_state) { + is_scaled_list[i] = !(dcn32_check_native_scaling(curr_pipe_ctx)); + disp_src_width_list[i] = curr_pipe_ctx->plane_state->src_rect.width; + disp_src_height_list[i] = curr_pipe_ctx->plane_state->src_rect.height; + } + } + DC_LOG_AUTO_DPM_TEST("AutoDPMTest: dramclk:%d - fclk:%d - " "dcfclk:%d - dppclk:%d - dispclk_hw:%d - " "dppclk_hw:%d - dprefclk_hw:%d - dcfclk_hw:%d - " - "dtbclk_hw:%d - fclk_hw:%d\n", + "dtbclk_hw:%d - fclk_hw:%d - pix_clk_0:%d - pix_clk_1:%d - " + "pix_clk_2:%d - pix_clk_3:%d - mall_ss_size:%d - p_state_type_0:%d - " + "p_state_type_1:%d - p_state_type_2:%d - p_state_type_3:%d - " + "pix_width_0:%d - pix_height_0:%d - refresh_rate_0:%lld - is_scaled_0:%d - " + "pix_width_1:%d - pix_height_1:%d - refresh_rate_1:%lld - is_scaled_1:%d - " + "pix_width_2:%d - pix_height_2:%d - refresh_rate_2:%lld - is_scaled_2:%d - " + "pix_width_3:%d - pix_height_3:%d - refresh_rate_3:%lld - is_scaled_3:%d - LOG_END\n", dramclk_khz_override, fclk_khz_override, new_clocks->dcfclk_khz, @@ -507,7 +575,14 @@ static void dcn32_auto_dpm_test_log(struct dc_clocks *new_clocks, struct clk_mgr dprefclk_khz_reg, dcfclk_khz_reg, dtbclk_khz_reg, - fclk_khz_reg); + fclk_khz_reg, + pix_clk_list[0], pix_clk_list[1], pix_clk_list[3], pix_clk_list[2], + mall_ss_size_bytes, + p_state_list[0], p_state_list[1], p_state_list[2], p_state_list[3], + disp_src_width_list[0], disp_src_height_list[0], disp_src_refresh_list[0], is_scaled_list[0], + disp_src_width_list[1], disp_src_height_list[1], disp_src_refresh_list[1], is_scaled_list[1], + disp_src_width_list[2], disp_src_height_list[2], disp_src_refresh_list[2], is_scaled_list[2], + disp_src_width_list[3], disp_src_height_list[3], disp_src_refresh_list[3], is_scaled_list[3]); } } @@ -680,6 +755,7 @@ static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base, /* DCCG requires KHz precision for DTBCLK */ clk_mgr_base->clks.ref_dtbclk_khz = dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DTBCLK, khz_to_mhz_ceil(new_clocks->ref_dtbclk_khz)); + dcn32_update_clocks_update_dtb_dto(clk_mgr, context, clk_mgr_base->clks.ref_dtbclk_khz); } @@ -708,7 +784,7 @@ static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base, clk_mgr_base->clks.dispclk_khz / 1000 / 7); if (dc->config.enable_auto_dpm_test_logs) { - dcn32_auto_dpm_test_log(new_clocks, clk_mgr); + dcn32_auto_dpm_test_log(new_clocks, clk_mgr, context); } } diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c index d5fde7d23fbf8e..9c660d1facc769 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c @@ -50,6 +50,7 @@ #include "dc_dmub_srv.h" #include "link.h" #include "logger_types.h" + #undef DC_LOGGER #define DC_LOGGER \ clk_mgr->base.base.ctx->logger @@ -80,12 +81,12 @@ static int dcn35_get_active_display_cnt_wa( struct dc *dc, - struct dc_state *context) + struct dc_state *context, + int *all_active_disps) { - int i, display_count; + int i, display_count = 0; bool tmds_present = false; - display_count = 0; for (i = 0; i < context->stream_count; i++) { const struct dc_stream_state *stream = context->streams[i]; @@ -103,7 +104,8 @@ static int dcn35_get_active_display_cnt_wa( link->link_enc->funcs->is_dig_enabled(link->link_enc)) display_count++; } - + if (all_active_disps != NULL) + *all_active_disps = display_count; /* WA for hang on HDMI after display off back on*/ if (display_count == 0 && tmds_present) display_count = 1; @@ -126,21 +128,13 @@ static void dcn35_disable_otg_wa(struct clk_mgr *clk_mgr_base, struct dc_state * continue; if (pipe->stream && (pipe->stream->dpms_off || dc_is_virtual_signal(pipe->stream->signal) || !pipe->stream->link_enc)) { - struct stream_encoder *stream_enc = pipe->stream_res.stream_enc; - if (disable) { - if (stream_enc && stream_enc->funcs->disable_fifo) - pipe->stream_res.stream_enc->funcs->disable_fifo(stream_enc); - if (pipe->stream_res.tg && pipe->stream_res.tg->funcs->immediate_disable_crtc) 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); - - if (stream_enc && stream_enc->funcs->enable_fifo) - pipe->stream_res.stream_enc->funcs->enable_fifo(stream_enc); } } } @@ -224,15 +218,16 @@ void dcn35_update_clocks(struct clk_mgr *clk_mgr_base, struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk; struct dc *dc = clk_mgr_base->ctx->dc; - int display_count; + int display_count = 0; bool update_dppclk = false; bool update_dispclk = false; bool dpp_clock_lowered = false; + int all_active_disps = 0; if (dc->work_arounds.skip_clock_update) return; - /* DTBCLK is fixed, so set a default if unspecified. */ + display_count = dcn35_get_active_display_cnt_wa(dc, context, &all_active_disps); if (new_clocks->dtbclk_en && !new_clocks->ref_dtbclk_khz) new_clocks->ref_dtbclk_khz = 600000; @@ -254,7 +249,6 @@ void dcn35_update_clocks(struct clk_mgr *clk_mgr_base, } /* check that we're not already in lower */ if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_LOW_POWER) { - display_count = dcn35_get_active_display_cnt_wa(dc, context); /* if we can go lower, go lower */ if (display_count == 0) clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER; @@ -349,7 +343,7 @@ void dcn35_update_clocks(struct clk_mgr *clk_mgr_base, cmd.notify_clocks.clocks.dispclk_khz = clk_mgr_base->clks.dispclk_khz; cmd.notify_clocks.clocks.dppclk_khz = clk_mgr_base->clks.dppclk_khz; - dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); } static int get_vco_frequency_from_reg(struct clk_mgr_internal *clk_mgr) @@ -424,9 +418,8 @@ bool dcn35_are_clock_states_equal(struct dc_clocks *a, } static void dcn35_dump_clk_registers(struct clk_state_registers_and_bypass *regs_and_bypass, - struct clk_mgr *clk_mgr_base, struct clk_log_info *log_info) + struct clk_mgr_dcn35 *clk_mgr) { - } static struct clk_bw_params dcn35_bw_params = { @@ -826,7 +819,7 @@ static void dcn35_set_low_power_state(struct clk_mgr *clk_mgr_base) struct dc_state *context = dc->current_state; if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_LOW_POWER) { - display_count = dcn35_get_active_display_cnt_wa(dc, context); + display_count = dcn35_get_active_display_cnt_wa(dc, context, NULL); /* if we can go lower, go lower */ if (display_count == 0) clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER; @@ -993,7 +986,6 @@ void dcn35_clk_mgr_construct( struct dccg *dccg) { struct dcn35_smu_dpm_clks smu_dpm_clks = { 0 }; - struct clk_log_info log_info = {0}; clk_mgr->base.base.ctx = ctx; clk_mgr->base.base.funcs = &dcn35_funcs; @@ -1046,7 +1038,7 @@ void dcn35_clk_mgr_construct( dcn35_bw_params.wm_table = ddr5_wm_table; } /* Saved clocks configured at boot for debug purposes */ - dcn35_dump_clk_registers(&clk_mgr->base.base.boot_snapshot, &clk_mgr->base.base, &log_info); + dcn35_dump_clk_registers(&clk_mgr->base.base.boot_snapshot, clk_mgr); clk_mgr->base.base.dprefclk_khz = dcn35_smu_get_dprefclk(&clk_mgr->base); clk_mgr->base.base.clks.ref_dtbclk_khz = 600000; diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_smu.c index b6b8c3ca1572cc..6d4a1ffab5ed9d 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_smu.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_smu.c @@ -116,6 +116,9 @@ static uint32_t dcn35_smu_wait_for_response(struct clk_mgr_internal *clk_mgr, un msleep(delay_us/1000); else if (delay_us > 0) udelay(delay_us); + + if (clk_mgr->base.ctx->dc->debug.disable_timeout) + max_retries++; } while (max_retries--); return res_val; @@ -276,7 +279,7 @@ void dcn35_smu_set_display_idle_optimization(struct clk_mgr_internal *clk_mgr, u clk_mgr, VBIOSSMC_MSG_SetDisplayIdleOptimizations, idle_info); - smu_print("VBIOSSMC_MSG_SetDisplayIdleOptimizations idle_info = %d\n", idle_info); + smu_print("%s: VBIOSSMC_MSG_SetDisplayIdleOptimizations idle_info = %x\n", __func__, idle_info); } void dcn35_smu_enable_phy_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr, bool enable) @@ -295,7 +298,7 @@ void dcn35_smu_enable_phy_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr, bool e clk_mgr, VBIOSSMC_MSG_SetDisplayIdleOptimizations, idle_info.data); - smu_print("dcn35_smu_enable_phy_refclk_pwrdwn = %d\n", enable ? 1 : 0); + smu_print("%s smu_enable_phy_refclk_pwrdwn = %d\n", __func__, enable ? 1 : 0); } void dcn35_smu_enable_pme_wa(struct clk_mgr_internal *clk_mgr) @@ -307,6 +310,7 @@ void dcn35_smu_enable_pme_wa(struct clk_mgr_internal *clk_mgr) clk_mgr, VBIOSSMC_MSG_UpdatePmeRestore, 0); + smu_print("%s: SMC_MSG_UpdatePmeRestore\n", __func__); } void dcn35_smu_set_dram_addr_high(struct clk_mgr_internal *clk_mgr, uint32_t addr_high) @@ -347,7 +351,7 @@ void dcn35_smu_transfer_wm_table_dram_2_smu(struct clk_mgr_internal *clk_mgr) void dcn35_smu_set_zstate_support(struct clk_mgr_internal *clk_mgr, enum dcn_zstate_support_state support) { - unsigned int msg_id, param; + unsigned int msg_id, param, retv; if (!clk_mgr->smu_present) return; @@ -357,27 +361,32 @@ void dcn35_smu_set_zstate_support(struct clk_mgr_internal *clk_mgr, enum dcn_zst case DCN_ZSTATE_SUPPORT_ALLOW: msg_id = VBIOSSMC_MSG_AllowZstatesEntry; param = (1 << 10) | (1 << 9) | (1 << 8); + smu_print("%s: SMC_MSG_AllowZstatesEntry msg = ALLOW, param = %d\n", __func__, param); break; case DCN_ZSTATE_SUPPORT_DISALLOW: msg_id = VBIOSSMC_MSG_AllowZstatesEntry; param = 0; + smu_print("%s: SMC_MSG_AllowZstatesEntry msg_id = DISALLOW, param = %d\n", __func__, param); break; case DCN_ZSTATE_SUPPORT_ALLOW_Z10_ONLY: msg_id = VBIOSSMC_MSG_AllowZstatesEntry; param = (1 << 10); + smu_print("%s: SMC_MSG_AllowZstatesEntry msg = ALLOW_Z10_ONLY, param = %d\n", __func__, param); break; case DCN_ZSTATE_SUPPORT_ALLOW_Z8_Z10_ONLY: msg_id = VBIOSSMC_MSG_AllowZstatesEntry; param = (1 << 10) | (1 << 8); + smu_print("%s: SMC_MSG_AllowZstatesEntry msg = ALLOW_Z8_Z10_ONLY, param = %d\n", __func__, param); break; case DCN_ZSTATE_SUPPORT_ALLOW_Z8_ONLY: msg_id = VBIOSSMC_MSG_AllowZstatesEntry; param = (1 << 8); + smu_print("%s: SMC_MSG_AllowZstatesEntry msg = ALLOW_Z8_ONLY, param = %d\n", __func__, param); break; default: //DCN_ZSTATE_SUPPORT_UNKNOWN @@ -387,11 +396,11 @@ void dcn35_smu_set_zstate_support(struct clk_mgr_internal *clk_mgr, enum dcn_zst } - dcn35_smu_send_msg_with_param( + retv = dcn35_smu_send_msg_with_param( clk_mgr, msg_id, param); - smu_print("dcn35_smu_set_zstate_support msg_id = %d, param = %d\n", msg_id, param); + smu_print("%s: msg_id = %d, param = 0x%x, return = %d\n", __func__, msg_id, param, retv); } int dcn35_smu_get_dprefclk(struct clk_mgr_internal *clk_mgr) @@ -405,7 +414,7 @@ int dcn35_smu_get_dprefclk(struct clk_mgr_internal *clk_mgr) VBIOSSMC_MSG_GetDprefclkFreq, 0); - smu_print("dcn35_smu_get_DPREF clk = %d mhz\n", dprefclk); + smu_print("%s: SMU DPREF clk = %d mhz\n", __func__, dprefclk); return dprefclk * 1000; } @@ -420,7 +429,7 @@ int dcn35_smu_get_dtbclk(struct clk_mgr_internal *clk_mgr) VBIOSSMC_MSG_GetDtbclkFreq, 0); - smu_print("dcn35_smu_get_dtbclk = %d mhz\n", dtbclk); + smu_print("%s: get_dtbclk = %dmhz\n", __func__, dtbclk); return dtbclk * 1000; } /* Arg = 1: Turn DTB on; 0: Turn DTB CLK OFF. when it is on, it is 600MHZ */ @@ -433,7 +442,7 @@ void dcn35_smu_set_dtbclk(struct clk_mgr_internal *clk_mgr, bool enable) clk_mgr, VBIOSSMC_MSG_SetDtbClk, enable); - smu_print("dcn35_smu_set_dtbclk = %d \n", enable ? 1 : 0); + smu_print("%s: smu_set_dtbclk = %d\n", __func__, enable ? 1 : 0); } void dcn35_vbios_smu_enable_48mhz_tmdp_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr, bool enable) @@ -442,30 +451,45 @@ void dcn35_vbios_smu_enable_48mhz_tmdp_refclk_pwrdwn(struct clk_mgr_internal *cl clk_mgr, VBIOSSMC_MSG_EnableTmdp48MHzRefclkPwrDown, enable); + smu_print("%s: smu_enable_48mhz_tmdp_refclk_pwrdwn = %d\n", __func__, enable ? 1 : 0); } int dcn35_smu_exit_low_power_state(struct clk_mgr_internal *clk_mgr) { - return dcn35_smu_send_msg_with_param( + int retv; + + retv = dcn35_smu_send_msg_with_param( clk_mgr, VBIOSSMC_MSG_DispPsrExit, 0); + smu_print("%s: smu_exit_low_power_state return = %d\n", __func__, retv); + return retv; } int dcn35_smu_get_ips_supported(struct clk_mgr_internal *clk_mgr) { - return dcn35_smu_send_msg_with_param( + int retv; + + retv = dcn35_smu_send_msg_with_param( clk_mgr, VBIOSSMC_MSG_QueryIPS2Support, 0); + + //smu_print("%s: VBIOSSMC_MSG_QueryIPS2Support return = %x\n", __func__, retv); + return retv; } void dcn35_smu_write_ips_scratch(struct clk_mgr_internal *clk_mgr, uint32_t param) { REG_WRITE(MP1_SMN_C2PMSG_71, param); + //smu_print("%s: write_ips_scratch = %x\n", __func__, param); } uint32_t dcn35_smu_read_ips_scratch(struct clk_mgr_internal *clk_mgr) { - return REG_READ(MP1_SMN_C2PMSG_71); + uint32_t retv; + + retv = REG_READ(MP1_SMN_C2PMSG_71); + //smu_print("%s: dcn35_smu_read_ips_scratch = %x\n", __func__, retv); + return retv; } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 5c118520664595..aa7c02ba948e9c 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -34,6 +34,8 @@ #include "dce/dce_hwseq.h" #include "resource.h" +#include "dc_state.h" +#include "dc_state_priv.h" #include "gpio_service_interface.h" #include "clk_mgr.h" @@ -519,7 +521,7 @@ dc_stream_forward_dmub_crc_window(struct dc_dmub_srv *dmub_srv, cmd.secure_display.roi_info.y_end = rect->y + rect->height; } - dm_execute_dmub_cmd(dmub_srv->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT); + dc_wake_and_execute_dmub_cmd(dmub_srv->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT); } static inline void @@ -808,7 +810,7 @@ static void dc_destruct(struct dc *dc) link_enc_cfg_init(dc, dc->current_state); if (dc->current_state) { - dc_release_state(dc->current_state); + dc_state_release(dc->current_state); dc->current_state = NULL; } @@ -1020,29 +1022,27 @@ static bool dc_construct(struct dc *dc, } #endif + if (!create_links(dc, init_params->num_virtual_links)) + goto fail; + + /* Create additional DIG link encoder objects if fewer than the platform + * supports were created during link construction. + */ + if (!create_link_encoders(dc)) + goto fail; + /* Creation of current_state must occur after dc->dml * is initialized in dc_create_resource_pool because * on creation it copies the contents of dc->dml */ - dc->current_state = dc_create_state(dc); + dc->current_state = dc_state_create(dc); if (!dc->current_state) { dm_error("%s: failed to create validate ctx\n", __func__); goto fail; } - if (!create_links(dc, init_params->num_virtual_links)) - goto fail; - - /* Create additional DIG link encoder objects if fewer than the platform - * supports were created during link construction. - */ - if (!create_link_encoders(dc)) - goto fail; - - dc_resource_state_construct(dc, dc->current_state); - return true; fail: @@ -1085,7 +1085,7 @@ static void apply_ctx_interdependent_lock(struct dc *dc, } } -static void dc_update_viusal_confirm_color(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx) +static void dc_update_visual_confirm_color(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx) { if (dc->ctx->dce_version >= DCN_VERSION_1_0) { memset(&pipe_ctx->visual_confirm_color, 0, sizeof(struct tg_color)); @@ -1105,9 +1105,9 @@ static void dc_update_viusal_confirm_color(struct dc *dc, struct dc_state *conte if (dc->debug.visual_confirm == VISUAL_CONFIRM_MPCTREE) get_mpctree_visual_confirm_color(pipe_ctx, &(pipe_ctx->visual_confirm_color)); else if (dc->debug.visual_confirm == VISUAL_CONFIRM_SUBVP) - get_subvp_visual_confirm_color(dc, context, pipe_ctx, &(pipe_ctx->visual_confirm_color)); + get_subvp_visual_confirm_color(pipe_ctx, &(pipe_ctx->visual_confirm_color)); else if (dc->debug.visual_confirm == VISUAL_CONFIRM_MCLK_SWITCH) - get_mclk_switch_visual_confirm_color(dc, context, pipe_ctx, &(pipe_ctx->visual_confirm_color)); + get_mclk_switch_visual_confirm_color(pipe_ctx, &(pipe_ctx->visual_confirm_color)); } } } @@ -1115,7 +1115,7 @@ static void dc_update_viusal_confirm_color(struct dc *dc, struct dc_state *conte static void disable_dangling_plane(struct dc *dc, struct dc_state *context) { int i, j; - struct dc_state *dangling_context = dc_create_state(dc); + struct dc_state *dangling_context = dc_state_create_current_copy(dc); struct dc_state *current_ctx; struct pipe_ctx *pipe; struct timing_generator *tg; @@ -1123,8 +1123,6 @@ static void disable_dangling_plane(struct dc *dc, struct dc_state *context) if (dangling_context == NULL) return; - dc_resource_state_copy_construct(dc->current_state, dangling_context); - for (i = 0; i < dc->res_pool->pipe_count; i++) { struct dc_stream_state *old_stream = dc->current_state->res_ctx.pipe_ctx[i].stream; @@ -1161,6 +1159,7 @@ static void disable_dangling_plane(struct dc *dc, struct dc_state *context) } if (should_disable && old_stream) { + bool is_phantom = dc_state_get_stream_subvp_type(dc->current_state, old_stream) == SUBVP_PHANTOM; pipe = &dc->current_state->res_ctx.pipe_ctx[i]; tg = pipe->stream_res.tg; /* When disabling plane for a phantom pipe, we must turn on the @@ -1169,22 +1168,29 @@ static void disable_dangling_plane(struct dc *dc, struct dc_state *context) * state that can result in underflow or hang when enabling it * again for different use. */ - if (old_stream->mall_stream_config.type == SUBVP_PHANTOM) { + if (is_phantom) { if (tg->funcs->enable_crtc) { int main_pipe_width, main_pipe_height; + struct dc_stream_state *old_paired_stream = dc_state_get_paired_subvp_stream(dc->current_state, old_stream); - main_pipe_width = old_stream->mall_stream_config.paired_stream->dst.width; - main_pipe_height = old_stream->mall_stream_config.paired_stream->dst.height; + main_pipe_width = old_paired_stream->dst.width; + main_pipe_height = old_paired_stream->dst.height; if (dc->hwss.blank_phantom) dc->hwss.blank_phantom(dc, tg, main_pipe_width, main_pipe_height); tg->funcs->enable_crtc(tg); } } - dc_rem_all_planes_for_stream(dc, old_stream, dangling_context); + + if (is_phantom) + dc_state_rem_all_phantom_planes_for_stream(dc, old_stream, dangling_context, true); + else + dc_state_rem_all_planes_for_stream(dc, old_stream, dangling_context); disable_all_writeback_pipes_for_stream(dc, old_stream, dangling_context); - if (pipe->stream && pipe->plane_state) - dc_update_viusal_confirm_color(dc, context, pipe); + if (pipe->stream && pipe->plane_state) { + set_p_state_switch_method(dc, context, pipe); + dc_update_visual_confirm_color(dc, context, pipe); + } if (dc->hwss.apply_ctx_for_surface) { apply_ctx_interdependent_lock(dc, dc->current_state, old_stream, true); @@ -1203,7 +1209,7 @@ static void disable_dangling_plane(struct dc *dc, struct dc_state *context) * The OTG is set to disable on falling edge of VUPDATE so the plane disable * will still get it's double buffer update. */ - if (old_stream->mall_stream_config.type == SUBVP_PHANTOM) { + if (is_phantom) { if (tg->funcs->disable_phantom_crtc) tg->funcs->disable_phantom_crtc(tg); } @@ -1212,7 +1218,7 @@ static void disable_dangling_plane(struct dc *dc, struct dc_state *context) current_ctx = dc->current_state; dc->current_state = dangling_context; - dc_release_state(current_ctx); + dc_state_release(current_ctx); } static void disable_vbios_mode_if_required( @@ -1284,7 +1290,7 @@ static void wait_for_no_pipes_pending(struct dc *dc, struct dc_state *context) int count = 0; struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - if (!pipe->plane_state || pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) + if (!pipe->plane_state || dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) continue; /* Timeout 100 ms */ @@ -1510,7 +1516,7 @@ static void program_timing_sync( } for (k = 0; k < group_size; k++) { - struct dc_stream_status *status = dc_stream_get_status_from_state(ctx, pipe_set[k]->stream); + struct dc_stream_status *status = dc_state_get_stream_status(ctx, pipe_set[k]->stream); status->timing_sync_info.group_id = num_group; status->timing_sync_info.group_size = group_size; @@ -1521,7 +1527,7 @@ static void program_timing_sync( } - /* remove any other pipes that are already been synced */ + /* remove any other unblanked pipes as they have already been synced */ if (dc->config.use_pipe_ctx_sync_logic) { /* check pipe's syncd to decide which pipe to be removed */ for (j = 1; j < group_size; j++) { @@ -1534,6 +1540,7 @@ static void program_timing_sync( pipe_set[j]->pipe_idx_syncd = pipe_set[0]->pipe_idx_syncd; } } else { + /* remove any other pipes by checking valid plane */ for (j = j + 1; j < group_size; j++) { bool is_blanked; @@ -1554,7 +1561,7 @@ static void program_timing_sync( if (group_size > 1) { if (sync_type == TIMING_SYNCHRONIZABLE) { dc->hwss.enable_timing_synchronization( - dc, group_index, group_size, pipe_set); + dc, ctx, group_index, group_size, pipe_set); } else if (sync_type == VBLANK_SYNCHRONIZABLE) { dc->hwss.enable_vblanks_synchronization( @@ -1836,7 +1843,7 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i]; /* Check old context for SubVP */ - subvp_prev_use |= (old_pipe->stream && old_pipe->stream->mall_stream_config.type == SUBVP_PHANTOM); + subvp_prev_use |= (dc_state_get_pipe_subvp_type(dc->current_state, old_pipe) == SUBVP_PHANTOM); if (subvp_prev_use) break; } @@ -1964,6 +1971,10 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c wait_for_no_pipes_pending(dc, context); /* pplib is notified if disp_num changed */ dc->hwss.optimize_bandwidth(dc, context); + /* Need to do otg sync again as otg could be out of sync due to otg + * workaround applied during clock update + */ + dc_trigger_sync(dc, context); } if (dc->hwss.update_dsc_pg) @@ -1990,9 +2001,9 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c old_state = dc->current_state; dc->current_state = context; - dc_release_state(old_state); + dc_state_release(old_state); - dc_retain_state(dc->current_state); + dc_state_retain(dc->current_state); return result; } @@ -2063,12 +2074,10 @@ enum dc_status dc_commit_streams(struct dc *dc, if (handle_exit_odm2to1) res = commit_minimal_transition_state(dc, dc->current_state); - context = dc_create_state(dc); + context = dc_state_create_current_copy(dc); if (!context) goto context_alloc_fail; - dc_resource_state_copy_construct_current(dc, context); - res = dc_validate_with_context(dc, set, stream_count, context, false); if (res != DC_OK) { BREAK_TO_DEBUGGER(); @@ -2083,7 +2092,7 @@ enum dc_status dc_commit_streams(struct dc *dc, streams[i]->out.otg_offset = context->stream_status[j].primary_otg_inst; if (dc_is_embedded_signal(streams[i]->signal)) { - struct dc_stream_status *status = dc_stream_get_status_from_state(context, streams[i]); + struct dc_stream_status *status = dc_state_get_stream_status(context, streams[i]); if (dc->hwss.is_abm_supported) status->is_abm_supported = dc->hwss.is_abm_supported(dc, context, streams[i]); @@ -2094,7 +2103,7 @@ enum dc_status dc_commit_streams(struct dc *dc, } fail: - dc_release_state(context); + dc_state_release(context); context_alloc_fail: @@ -2148,7 +2157,7 @@ static bool is_flip_pending_in_pipes(struct dc *dc, struct dc_state *context) pipe = &context->res_ctx.pipe_ctx[i]; // Don't check flip pending on phantom pipes - if (!pipe->plane_state || (pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_PHANTOM)) + if (!pipe->plane_state || (dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM)) continue; /* Must set to false to start with, due to OR in update function */ @@ -2206,7 +2215,7 @@ void dc_post_update_surfaces_to_stream(struct dc *dc) if (context->res_ctx.pipe_ctx[i].stream == NULL || context->res_ctx.pipe_ctx[i].plane_state == NULL) { context->res_ctx.pipe_ctx[i].pipe_idx = i; - dc->hwss.disable_plane(dc, &context->res_ctx.pipe_ctx[i]); + dc->hwss.disable_plane(dc, context, &context->res_ctx.pipe_ctx[i]); } process_deferred_updates(dc); @@ -2221,110 +2230,6 @@ void dc_post_update_surfaces_to_stream(struct dc *dc) dc->wm_optimized_required = false; } -static void init_state(struct dc *dc, struct dc_state *context) -{ - /* Each context must have their 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 - */ - memcpy(&context->bw_ctx.dml, &dc->dml, sizeof(struct display_mode_lib)); -} - -struct dc_state *dc_create_state(struct dc *dc) -{ - struct dc_state *context = kvzalloc(sizeof(struct dc_state), - GFP_KERNEL); - - if (!context) - return NULL; - - init_state(dc, context); - -#ifdef CONFIG_DRM_AMD_DC_FP - if (dc->debug.using_dml2) { - dml2_create(dc, &dc->dml2_options, &context->bw_ctx.dml2); - } -#endif - kref_init(&context->refcount); - - return context; -} - -struct dc_state *dc_copy_state(struct dc_state *src_ctx) -{ - int i, j; - struct dc_state *new_ctx = kvmalloc(sizeof(struct dc_state), GFP_KERNEL); -#ifdef CONFIG_DRM_AMD_DC_FP - struct dml2_context *dml2 = NULL; -#endif - - if (!new_ctx) - return NULL; - memcpy(new_ctx, src_ctx, sizeof(struct dc_state)); - -#ifdef CONFIG_DRM_AMD_DC_FP - if (new_ctx->bw_ctx.dml2) { - dml2 = kzalloc(sizeof(struct dml2_context), GFP_KERNEL); - if (!dml2) - return NULL; - - memcpy(dml2, src_ctx->bw_ctx.dml2, sizeof(struct dml2_context)); - new_ctx->bw_ctx.dml2 = dml2; - } -#endif - - for (i = 0; i < MAX_PIPES; i++) { - struct pipe_ctx *cur_pipe = &new_ctx->res_ctx.pipe_ctx[i]; - - if (cur_pipe->top_pipe) - cur_pipe->top_pipe = &new_ctx->res_ctx.pipe_ctx[cur_pipe->top_pipe->pipe_idx]; - - if (cur_pipe->bottom_pipe) - cur_pipe->bottom_pipe = &new_ctx->res_ctx.pipe_ctx[cur_pipe->bottom_pipe->pipe_idx]; - - if (cur_pipe->prev_odm_pipe) - cur_pipe->prev_odm_pipe = &new_ctx->res_ctx.pipe_ctx[cur_pipe->prev_odm_pipe->pipe_idx]; - - if (cur_pipe->next_odm_pipe) - cur_pipe->next_odm_pipe = &new_ctx->res_ctx.pipe_ctx[cur_pipe->next_odm_pipe->pipe_idx]; - - } - - for (i = 0; i < new_ctx->stream_count; i++) { - dc_stream_retain(new_ctx->streams[i]); - for (j = 0; j < new_ctx->stream_status[i].plane_count; j++) - dc_plane_state_retain( - new_ctx->stream_status[i].plane_states[j]); - } - - kref_init(&new_ctx->refcount); - - return new_ctx; -} - -void dc_retain_state(struct dc_state *context) -{ - kref_get(&context->refcount); -} - -static void dc_state_free(struct kref *kref) -{ - struct dc_state *context = container_of(kref, struct dc_state, refcount); - dc_resource_state_destruct(context); - -#ifdef CONFIG_DRM_AMD_DC_FP - dml2_destroy(context->bw_ctx.dml2); - context->bw_ctx.dml2 = 0; -#endif - - kvfree(context); -} - -void dc_release_state(struct dc_state *context) -{ - kref_put(&context->refcount, dc_state_free); -} - bool dc_set_generic_gpio_for_stereo(bool enable, struct gpio_service *gpio_service) { @@ -2997,11 +2902,9 @@ static void copy_stream_update_to_stream(struct dc *dc, update->dsc_config->num_slices_v != 0); /* Use temporarry context for validating new DSC config */ - struct dc_state *dsc_validate_context = dc_create_state(dc); + struct dc_state *dsc_validate_context = dc_state_create_copy(dc->current_state); if (dsc_validate_context) { - dc_resource_state_copy_construct(dc->current_state, dsc_validate_context); - stream->timing.dsc_cfg = *update->dsc_config; stream->timing.flags.DSC = enable_dsc; if (!dc->res_pool->funcs->validate_bandwidth(dc, dsc_validate_context, true)) { @@ -3010,7 +2913,7 @@ static void copy_stream_update_to_stream(struct dc *dc, update->dsc_config = NULL; } - dc_release_state(dsc_validate_context); + dc_state_release(dsc_validate_context); } else { DC_ERROR("Failed to allocate new validate context for DSC change\n"); update->dsc_config = NULL; @@ -3109,30 +3012,27 @@ static bool update_planes_and_stream_state(struct dc *dc, new_planes[i] = srf_updates[i].surface; /* initialize scratch memory for building context */ - context = dc_create_state(dc); + context = dc_state_create_copy(dc->current_state); if (context == NULL) { DC_ERROR("Failed to allocate new validate context!\n"); return false; } - dc_resource_state_copy_construct( - dc->current_state, context); - /* For each full update, remove all existing phantom pipes first. * Ensures that we have enough pipes for newly added MPO planes */ - if (dc->res_pool->funcs->remove_phantom_pipes) - dc->res_pool->funcs->remove_phantom_pipes(dc, context, false); + dc_state_remove_phantom_streams_and_planes(dc, context); + dc_state_release_phantom_streams_and_planes(dc, context); /*remove old surfaces from context */ - if (!dc_rem_all_planes_for_stream(dc, stream, context)) { + if (!dc_state_rem_all_planes_for_stream(dc, stream, context)) { BREAK_TO_DEBUGGER(); goto fail; } /* add surface to context */ - if (!dc_add_all_planes_for_stream(dc, stream, new_planes, surface_count, context)) { + if (!dc_state_add_all_planes_for_stream(dc, stream, new_planes, surface_count, context)) { BREAK_TO_DEBUGGER(); goto fail; @@ -3157,19 +3057,6 @@ static bool update_planes_and_stream_state(struct dc *dc, if (update_type == UPDATE_TYPE_FULL) { if (!dc->res_pool->funcs->validate_bandwidth(dc, context, false)) { - /* For phantom pipes we remove and create a new set of phantom pipes - * for each full update (because we don't know if we'll need phantom - * pipes until after the first round of validation). However, if validation - * fails we need to keep the existing phantom pipes (because we don't update - * the dc->current_state). - * - * The phantom stream/plane refcount is decremented for validation because - * we assume it'll be removed (the free comes when the dc_state is freed), - * but if validation fails we have to increment back the refcount so it's - * consistent. - */ - if (dc->res_pool->funcs->retain_phantom_pipes) - dc->res_pool->funcs->retain_phantom_pipes(dc, dc->current_state); BREAK_TO_DEBUGGER(); goto fail; } @@ -3190,7 +3077,7 @@ static bool update_planes_and_stream_state(struct dc *dc, return true; fail: - dc_release_state(context); + dc_state_release(context); return false; @@ -3386,7 +3273,7 @@ void dc_dmub_update_dirty_rect(struct dc *dc, update_dirty_rect->panel_inst = panel_inst; update_dirty_rect->pipe_idx = j; - dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT); + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT); } } } @@ -3488,18 +3375,24 @@ static void commit_planes_for_stream_fast(struct dc *dc, { int i, j; struct pipe_ctx *top_pipe_to_program = NULL; + struct dc_stream_status *stream_status = NULL; dc_z10_restore(dc); top_pipe_to_program = resource_get_otg_master_for_stream( &context->res_ctx, stream); - if (dc->debug.visual_confirm) { - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + if (!top_pipe_to_program) + return; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + + if (pipe->stream && pipe->plane_state) { + set_p_state_switch_method(dc, context, pipe); - if (pipe->stream && pipe->plane_state) - dc_update_viusal_confirm_color(dc, context, pipe); + if (dc->debug.visual_confirm) + dc_update_visual_confirm_color(dc, context, pipe); } } @@ -3523,6 +3416,8 @@ static void commit_planes_for_stream_fast(struct dc *dc, } } + stream_status = dc_state_get_stream_status(context, stream); + build_dmub_cmd_list(dc, srf_updates, surface_count, @@ -3535,7 +3430,8 @@ static void commit_planes_for_stream_fast(struct dc *dc, context->dmub_cmd_count, context->block_sequence, &(context->block_sequence_steps), - top_pipe_to_program); + top_pipe_to_program, + stream_status); hwss_execute_sequence(dc, context->block_sequence, context->block_sequence_steps); @@ -3626,12 +3522,12 @@ static void commit_planes_for_stream(struct dc *dc, top_pipe_to_program = resource_get_otg_master_for_stream( &context->res_ctx, stream); - + ASSERT(top_pipe_to_program != NULL); for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i]; // Check old context for SubVP - subvp_prev_use |= (old_pipe->stream && old_pipe->stream->mall_stream_config.type == SUBVP_PHANTOM); + subvp_prev_use |= (dc_state_get_pipe_subvp_type(dc->current_state, old_pipe) == SUBVP_PHANTOM); if (subvp_prev_use) break; } @@ -3639,19 +3535,22 @@ static void commit_planes_for_stream(struct dc *dc, 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) { + if (dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) { subvp_curr_use = true; break; } } - if (dc->debug.visual_confirm) - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + + if (pipe->stream && pipe->plane_state) { + set_p_state_switch_method(dc, context, pipe); - if (pipe->stream && pipe->plane_state) - dc_update_viusal_confirm_color(dc, context, pipe); + if (dc->debug.visual_confirm) + dc_update_visual_confirm_color(dc, context, pipe); } + } if (stream->test_pattern.type != DP_TEST_PATTERN_VIDEO_MODE) { struct pipe_ctx *mpcc_pipe; @@ -4024,7 +3923,7 @@ static bool could_mpcc_tree_change_for_active_pipes(struct dc *dc, for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe->stream && pipe->stream->mall_stream_config.type != SUBVP_NONE) { + if (dc_state_get_pipe_subvp_type(dc->current_state, pipe) != SUBVP_NONE) { subvp_active = true; break; } @@ -4061,7 +3960,7 @@ struct pipe_split_policy_backup { static void release_minimal_transition_state(struct dc *dc, struct dc_state *context, struct pipe_split_policy_backup *policy) { - dc_release_state(context); + dc_state_release(context); /* restore previous pipe split and odm policy */ if (!dc->config.is_vmin_only_asic) dc->debug.pipe_split_policy = policy->mpc_policy; @@ -4072,7 +3971,7 @@ static void release_minimal_transition_state(struct dc *dc, static struct dc_state *create_minimal_transition_state(struct dc *dc, struct dc_state *base_context, struct pipe_split_policy_backup *policy) { - struct dc_state *minimal_transition_context = dc_create_state(dc); + struct dc_state *minimal_transition_context = NULL; unsigned int i, j; if (!dc->config.is_vmin_only_asic) { @@ -4084,7 +3983,9 @@ static struct dc_state *create_minimal_transition_state(struct dc *dc, policy->subvp_policy = dc->debug.force_disable_subvp; dc->debug.force_disable_subvp = true; - dc_resource_state_copy_construct(base_context, minimal_transition_context); + minimal_transition_context = dc_state_create_copy(base_context); + if (!minimal_transition_context) + return NULL; /* commit minimal state */ if (dc->res_pool->funcs->validate_bandwidth(dc, minimal_transition_context, false)) { @@ -4116,7 +4017,6 @@ static bool commit_minimal_transition_state_for_windowed_mpo_odm(struct dc *dc, bool success = false; struct dc_state *minimal_transition_context; struct pipe_split_policy_backup policy; - struct mall_temp_config mall_temp_config; /* commit based on new context */ /* Since all phantom pipes are removed in full validation, @@ -4125,8 +4025,6 @@ static bool commit_minimal_transition_state_for_windowed_mpo_odm(struct dc *dc, * pipe as subvp/phantom will be cleared (dc copy constructor * creates a shallow copy). */ - if (dc->res_pool->funcs->save_mall_state) - dc->res_pool->funcs->save_mall_state(dc, context, &mall_temp_config); minimal_transition_context = create_minimal_transition_state(dc, context, &policy); if (minimal_transition_context) { @@ -4139,16 +4037,6 @@ static bool commit_minimal_transition_state_for_windowed_mpo_odm(struct dc *dc, success = dc_commit_state_no_check(dc, minimal_transition_context) == DC_OK; } release_minimal_transition_state(dc, minimal_transition_context, &policy); - if (dc->res_pool->funcs->restore_mall_state) - dc->res_pool->funcs->restore_mall_state(dc, context, &mall_temp_config); - /* If we do a minimal transition with plane removal and the context - * has subvp we also have to retain back the phantom stream / planes - * since the refcount is decremented as part of the min transition - * (we commit a state with no subvp, so the phantom streams / planes - * had to be removed). - */ - if (dc->res_pool->funcs->retain_phantom_pipes) - dc->res_pool->funcs->retain_phantom_pipes(dc, context); } if (!success) { @@ -4216,7 +4104,7 @@ static bool commit_minimal_transition_state(struct dc *dc, for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i]; - if (pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) { + if (pipe->stream && dc_state_get_pipe_subvp_type(dc->current_state, pipe) == SUBVP_PHANTOM) { subvp_in_use = true; break; } @@ -4457,6 +4345,8 @@ static bool should_commit_minimal_transition_for_windowed_mpo_odm(struct dc *dc, cur_pipe = resource_get_otg_master_for_stream(&dc->current_state->res_ctx, stream); new_pipe = resource_get_otg_master_for_stream(&context->res_ctx, stream); + if (!cur_pipe || !new_pipe) + return false; cur_is_odm_in_use = resource_get_odm_slice_count(cur_pipe) > 1; new_is_odm_in_use = resource_get_odm_slice_count(new_pipe) > 1; if (cur_is_odm_in_use == new_is_odm_in_use) @@ -4482,7 +4372,6 @@ bool dc_update_planes_and_stream(struct dc *dc, struct dc_state *context; enum surface_update_type update_type; int i; - struct mall_temp_config mall_temp_config; struct dc_fast_update fast_update[MAX_SURFACES] = {0}; /* In cases where MPO and split or ODM are used transitions can @@ -4526,23 +4415,10 @@ bool dc_update_planes_and_stream(struct dc *dc, * pipe as subvp/phantom will be cleared (dc copy constructor * creates a shallow copy). */ - if (dc->res_pool->funcs->save_mall_state) - dc->res_pool->funcs->save_mall_state(dc, context, &mall_temp_config); if (!commit_minimal_transition_state(dc, context)) { - dc_release_state(context); + dc_state_release(context); return false; } - if (dc->res_pool->funcs->restore_mall_state) - dc->res_pool->funcs->restore_mall_state(dc, context, &mall_temp_config); - - /* If we do a minimal transition with plane removal and the context - * has subvp we also have to retain back the phantom stream / planes - * since the refcount is decremented as part of the min transition - * (we commit a state with no subvp, so the phantom streams / planes - * had to be removed). - */ - if (dc->res_pool->funcs->retain_phantom_pipes) - dc->res_pool->funcs->retain_phantom_pipes(dc, context); update_type = UPDATE_TYPE_FULL; } @@ -4599,7 +4475,7 @@ bool dc_update_planes_and_stream(struct dc *dc, struct dc_state *old = dc->current_state; dc->current_state = context; - dc_release_state(old); + dc_state_release(old); // clear any forced full updates for (i = 0; i < dc->res_pool->pipe_count; i++) { @@ -4658,14 +4534,12 @@ void dc_commit_updates_for_stream(struct dc *dc, if (update_type >= UPDATE_TYPE_FULL) { /* initialize scratch memory for building context */ - context = dc_create_state(dc); + context = dc_state_create_copy(state); if (context == NULL) { DC_ERROR("Failed to allocate new validate context!\n"); return; } - dc_resource_state_copy_construct(state, context); - for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *new_pipe = &context->res_ctx.pipe_ctx[i]; struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i]; @@ -4704,7 +4578,7 @@ void dc_commit_updates_for_stream(struct dc *dc, if (update_type >= UPDATE_TYPE_FULL) { if (!dc->res_pool->funcs->validate_bandwidth(dc, context, false)) { DC_ERROR("Mode validation failed for stream update!\n"); - dc_release_state(context); + dc_state_release(context); return; } } @@ -4737,7 +4611,7 @@ void dc_commit_updates_for_stream(struct dc *dc, struct dc_state *old = dc->current_state; dc->current_state = context; - dc_release_state(old); + dc_state_release(old); for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; @@ -4810,7 +4684,7 @@ void dc_set_power_state( switch (power_state) { case DC_ACPI_CM_POWER_STATE_D0: - dc_resource_state_construct(dc, dc->current_state); + dc_state_construct(dc, dc->current_state); dc_z10_restore(dc); @@ -4825,7 +4699,7 @@ void dc_set_power_state( default: ASSERT(dc->current_state->stream_count == 0); - dc_resource_state_destruct(dc->current_state); + dc_state_destruct(dc->current_state); break; } @@ -4902,6 +4776,38 @@ bool dc_set_psr_allow_active(struct dc *dc, bool enable) return true; } +/* enable/disable eDP Replay without specify stream for eDP */ +bool dc_set_replay_allow_active(struct dc *dc, bool active) +{ + int i; + bool allow_active; + + for (i = 0; i < dc->current_state->stream_count; i++) { + struct dc_link *link; + struct dc_stream_state *stream = dc->current_state->streams[i]; + + link = stream->link; + if (!link) + continue; + + if (link->replay_settings.replay_feature_enabled) { + if (active && !link->replay_settings.replay_allow_active) { + allow_active = true; + if (!dc_link_set_replay_allow_active(link, &allow_active, + false, false, NULL)) + return false; + } else if (!active && link->replay_settings.replay_allow_active) { + allow_active = false; + if (!dc_link_set_replay_allow_active(link, &allow_active, + true, false, NULL)) + return false; + } + } + } + + return true; +} + void dc_allow_idle_optimizations(struct dc *dc, bool allow) { if (dc->debug.disable_idle_power_optimizations) @@ -5213,7 +5119,7 @@ bool dc_process_dmub_aux_transfer_async(struct dc *dc, ); } - dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); return true; } @@ -5267,7 +5173,7 @@ bool dc_process_dmub_set_config_async(struct dc *dc, cmd.set_config_access.set_config_control.cmd_pkt.msg_type = payload->msg_type; cmd.set_config_access.set_config_control.cmd_pkt.msg_data = payload->msg_data; - if (!dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) { + if (!dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) { /* command is not processed by dmub */ notify->sc_status = SET_CONFIG_UNKNOWN_ERROR; return is_cmd_complete; @@ -5310,7 +5216,7 @@ enum dc_status dc_process_dmub_set_mst_slots(const struct dc *dc, cmd.set_mst_alloc_slots.mst_slots_control.instance = dc->links[link_index]->ddc_hw_inst; cmd.set_mst_alloc_slots.mst_slots_control.mst_alloc_slots = mst_alloc_slots; - if (!dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) + if (!dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) /* command is not processed by dmub */ return DC_ERROR_UNEXPECTED; @@ -5348,7 +5254,7 @@ void dc_process_dmub_dpia_hpd_int_enable(const struct dc *dc, cmd.dpia_hpd_int_enable.header.type = DMUB_CMD__DPIA_HPD_INT_ENABLE; cmd.dpia_hpd_int_enable.enable = hpd_int_enable; - dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); DC_LOG_DEBUG("%s: hpd_int_enable(%d)\n", __func__, hpd_int_enable); } @@ -5447,6 +5353,8 @@ bool dc_abm_save_restore( struct dc_link *link = stream->sink->link; struct dc_link *edp_links[MAX_NUM_EDP]; + if (link->replay_settings.replay_feature_enabled) + return false; /*find primary pipe associated with stream*/ for (i = 0; i < MAX_PIPES; i++) { diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c index fe07160932d696..9c05b1a07142fe 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c @@ -31,6 +31,7 @@ #include "basics/dc_common.h" #include "resource.h" #include "dc_dmub_srv.h" +#include "dc_state_priv.h" #define NUM_ELEMENTS(a) (sizeof(a) / sizeof((a)[0])) @@ -425,45 +426,130 @@ void get_hdr_visual_confirm_color( } void get_subvp_visual_confirm_color( - struct dc *dc, - struct dc_state *context, struct pipe_ctx *pipe_ctx, struct tg_color *color) { uint32_t color_value = MAX_TG_COLOR_VALUE; - bool enable_subvp = false; - int i; - - if (!dc->ctx || !dc->ctx->dmub_srv || !pipe_ctx || !context) - return; + if (pipe_ctx) { + switch (pipe_ctx->p_state_type) { + case P_STATE_SUB_VP: + color->color_r_cr = color_value; + color->color_g_y = 0; + color->color_b_cb = 0; + break; + case P_STATE_DRR_SUB_VP: + color->color_r_cr = 0; + color->color_g_y = color_value; + color->color_b_cb = 0; + break; + case P_STATE_V_BLANK_SUB_VP: + color->color_r_cr = 0; + color->color_g_y = 0; + color->color_b_cb = color_value; + break; + default: + break; + } + } +} - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; +void get_mclk_switch_visual_confirm_color( + struct pipe_ctx *pipe_ctx, + struct tg_color *color) +{ + uint32_t color_value = MAX_TG_COLOR_VALUE; - if (pipe->stream && pipe->stream->mall_stream_config.paired_stream && - pipe->stream->mall_stream_config.type == SUBVP_MAIN) { - /* SubVP enable - red */ - color->color_g_y = 0; + if (pipe_ctx) { + switch (pipe_ctx->p_state_type) { + case P_STATE_V_BLANK: + color->color_r_cr = color_value; + color->color_g_y = color_value; color->color_b_cb = 0; + break; + case P_STATE_FPO: + color->color_r_cr = 0; + color->color_g_y = color_value; + color->color_b_cb = color_value; + break; + case P_STATE_V_ACTIVE: color->color_r_cr = color_value; - enable_subvp = true; - - if (pipe_ctx->stream == pipe->stream) - return; + color->color_g_y = 0; + color->color_b_cb = color_value; + break; + case P_STATE_SUB_VP: + color->color_r_cr = color_value; + color->color_g_y = 0; + color->color_b_cb = 0; + break; + case P_STATE_DRR_SUB_VP: + color->color_r_cr = 0; + color->color_g_y = color_value; + color->color_b_cb = 0; + break; + case P_STATE_V_BLANK_SUB_VP: + color->color_r_cr = 0; + color->color_g_y = 0; + color->color_b_cb = color_value; + break; + default: break; } } +} - if (enable_subvp && pipe_ctx->stream->mall_stream_config.type == SUBVP_NONE) { - color->color_r_cr = 0; - if (pipe_ctx->stream->allow_freesync == 1) { - /* SubVP enable and DRR on - green */ - color->color_b_cb = 0; - color->color_g_y = color_value; +void set_p_state_switch_method( + struct dc *dc, + struct dc_state *context, + struct pipe_ctx *pipe_ctx) +{ + struct vba_vars_st *vba = &context->bw_ctx.dml.vba; + bool enable_subvp; + + if (!dc->ctx || !dc->ctx->dmub_srv || !pipe_ctx || !vba || !context) + return; + + if (vba->DRAMClockChangeSupport[vba->VoltageLevel][vba->maxMpcComb] != + dm_dram_clock_change_unsupported) { + /* MCLK switching is supported */ + if (!pipe_ctx->has_vactive_margin) { + /* In Vblank - yellow */ + pipe_ctx->p_state_type = P_STATE_V_BLANK; + + if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching) { + /* FPO + Vblank - cyan */ + pipe_ctx->p_state_type = P_STATE_FPO; + } } else { - /* SubVP enable and No DRR - blue */ - color->color_g_y = 0; - color->color_b_cb = color_value; + /* In Vactive - pink */ + pipe_ctx->p_state_type = P_STATE_V_ACTIVE; + } + + /* SubVP */ + enable_subvp = false; + + for (int i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + + if (pipe->stream && dc_state_get_paired_subvp_stream(context, pipe->stream) && + dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_MAIN) { + /* SubVP enable - red */ + pipe_ctx->p_state_type = P_STATE_SUB_VP; + enable_subvp = true; + + if (pipe_ctx->stream == pipe->stream) + return; + break; + } + } + + if (enable_subvp && dc_state_get_pipe_subvp_type(context, pipe_ctx) == SUBVP_NONE) { + if (pipe_ctx->stream->allow_freesync == 1) { + /* SubVP enable and DRR on - green */ + pipe_ctx->p_state_type = P_STATE_DRR_SUB_VP; + } else { + /* SubVP enable and No DRR - blue */ + pipe_ctx->p_state_type = P_STATE_V_BLANK_SUB_VP; + } } } } @@ -473,7 +559,8 @@ void hwss_build_fast_sequence(struct dc *dc, unsigned int dmub_cmd_count, struct block_sequence block_sequence[], int *num_steps, - struct pipe_ctx *pipe_ctx) + struct pipe_ctx *pipe_ctx, + struct dc_stream_status *stream_status) { struct dc_plane_state *plane = pipe_ctx->plane_state; struct dc_stream_state *stream = pipe_ctx->stream; @@ -490,7 +577,8 @@ void hwss_build_fast_sequence(struct dc *dc, if (dc->hwss.subvp_pipe_control_lock_fast) { block_sequence[*num_steps].params.subvp_pipe_control_lock_fast_params.dc = dc; block_sequence[*num_steps].params.subvp_pipe_control_lock_fast_params.lock = true; - block_sequence[*num_steps].params.subvp_pipe_control_lock_fast_params.pipe_ctx = pipe_ctx; + block_sequence[*num_steps].params.subvp_pipe_control_lock_fast_params.subvp_immediate_flip = + plane->flip_immediate && stream_status->mall_stream_config.type == SUBVP_MAIN; block_sequence[*num_steps].func = DMUB_SUBVP_PIPE_CONTROL_LOCK_FAST; (*num_steps)++; } @@ -529,7 +617,7 @@ void hwss_build_fast_sequence(struct dc *dc, } if (dc->hwss.update_plane_addr && current_mpc_pipe->plane_state->update_flags.bits.addr_update) { if (resource_is_pipe_type(current_mpc_pipe, OTG_MASTER) && - current_mpc_pipe->stream->mall_stream_config.type == SUBVP_MAIN) { + stream_status->mall_stream_config.type == SUBVP_MAIN) { block_sequence[*num_steps].params.subvp_save_surf_addr.dc_dmub_srv = dc->ctx->dmub_srv; block_sequence[*num_steps].params.subvp_save_surf_addr.addr = ¤t_mpc_pipe->plane_state->address; block_sequence[*num_steps].params.subvp_save_surf_addr.subvp_index = current_mpc_pipe->subvp_index; @@ -612,7 +700,8 @@ void hwss_build_fast_sequence(struct dc *dc, if (dc->hwss.subvp_pipe_control_lock_fast) { block_sequence[*num_steps].params.subvp_pipe_control_lock_fast_params.dc = dc; block_sequence[*num_steps].params.subvp_pipe_control_lock_fast_params.lock = false; - block_sequence[*num_steps].params.subvp_pipe_control_lock_fast_params.pipe_ctx = pipe_ctx; + block_sequence[*num_steps].params.subvp_pipe_control_lock_fast_params.subvp_immediate_flip = + plane->flip_immediate && stream_status->mall_stream_config.type == SUBVP_MAIN; block_sequence[*num_steps].func = DMUB_SUBVP_PIPE_CONTROL_LOCK_FAST; (*num_steps)++; } @@ -724,7 +813,7 @@ void hwss_send_dmcub_cmd(union block_sequence_params *params) union dmub_rb_cmd *cmd = params->send_dmcub_cmd_params.cmd; enum dm_dmub_wait_type wait_type = params->send_dmcub_cmd_params.wait_type; - dm_execute_dmub_cmd(ctx, cmd, wait_type); + dc_wake_and_execute_dmub_cmd(ctx, cmd, wait_type); } void hwss_program_manual_trigger(union block_sequence_params *params) @@ -812,42 +901,6 @@ void hwss_subvp_save_surf_addr(union block_sequence_params *params) dc_dmub_srv_subvp_save_surf_addr(dc_dmub_srv, addr, subvp_index); } -void get_mclk_switch_visual_confirm_color( - struct dc *dc, - struct dc_state *context, - struct pipe_ctx *pipe_ctx, - struct tg_color *color) -{ - uint32_t color_value = MAX_TG_COLOR_VALUE; - struct vba_vars_st *vba = &context->bw_ctx.dml.vba; - - if (!dc->ctx || !dc->ctx->dmub_srv || !pipe_ctx || !vba || !context) - return; - - if (vba->DRAMClockChangeSupport[vba->VoltageLevel][vba->maxMpcComb] != - dm_dram_clock_change_unsupported) { - /* MCLK switching is supported */ - if (!pipe_ctx->has_vactive_margin) { - /* In Vblank - yellow */ - color->color_r_cr = color_value; - color->color_g_y = color_value; - - if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching) { - /* FPO + Vblank - cyan */ - color->color_r_cr = 0; - color->color_g_y = color_value; - color->color_b_cb = color_value; - } - } else { - /* In Vactive - pink */ - color->color_r_cr = color_value; - color->color_b_cb = color_value; - } - /* SubVP */ - get_subvp_visual_confirm_color(dc, context, pipe_ctx, color); - } -} - void get_surface_tile_visual_confirm_color( struct pipe_ctx *pipe_ctx, struct tg_color *color) 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 index ed94187c2afa2d..c6c35037bdb8b7 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_exports.c @@ -467,6 +467,13 @@ bool dc_link_setup_psr(struct dc_link *link, return link->dc->link_srv->edp_setup_psr(link, stream, psr_config, psr_context); } +bool dc_link_set_replay_allow_active(struct dc_link *link, const bool *allow_active, + bool wait, bool force_static, const unsigned int *power_opts) +{ + return link->dc->link_srv->edp_set_replay_allow_active(link, allow_active, wait, + force_static, power_opts); +} + bool dc_link_get_replay_state(const struct dc_link *link, uint64_t *state) { return link->dc->link_srv->edp_get_replay_state(link, state); @@ -497,7 +504,7 @@ void dc_link_enable_hpd_filter(struct dc_link *link, bool enable) link->dc->link_srv->enable_hpd_filter(link, enable); } -bool dc_link_validate(struct dc *dc, const struct dc_stream_state *streams, const unsigned int count) +bool dc_link_dp_dpia_validate(struct dc *dc, const struct dc_stream_state *streams, const unsigned int count) { return dc->link_srv->validate_dpia_bandwidth(streams, count); } 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 a1f1d100399275..9fbdb09697fd5e 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -42,6 +42,7 @@ #include "link_enc_cfg.h" #include "link.h" #include "clk_mgr.h" +#include "dc_state_priv.h" #include "virtual/virtual_link_hwss.h" #include "link/hwss/link_hwss_dio.h" #include "link/hwss/link_hwss_dpia.h" @@ -69,8 +70,8 @@ #include "dcn314/dcn314_resource.h" #include "dcn315/dcn315_resource.h" #include "dcn316/dcn316_resource.h" -#include "../dcn32/dcn32_resource.h" -#include "../dcn321/dcn321_resource.h" +#include "dcn32/dcn32_resource.h" +#include "dcn321/dcn321_resource.h" #include "dcn35/dcn35_resource.h" #define VISUAL_CONFIRM_BASE_DEFAULT 3 @@ -1764,6 +1765,29 @@ int recource_find_free_pipe_not_used_in_cur_res_ctx( return free_pipe_idx; } +int recource_find_free_pipe_used_as_otg_master_in_cur_res_ctx( + const struct resource_context *cur_res_ctx, + struct resource_context *new_res_ctx, + const struct resource_pool *pool) +{ + int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND; + const struct pipe_ctx *new_pipe, *cur_pipe; + int i; + + for (i = 0; i < pool->pipe_count; i++) { + cur_pipe = &cur_res_ctx->pipe_ctx[i]; + new_pipe = &new_res_ctx->pipe_ctx[i]; + + if (resource_is_pipe_type(cur_pipe, OTG_MASTER) && + resource_is_pipe_type(new_pipe, FREE_PIPE)) { + free_pipe_idx = i; + break; + } + } + + return free_pipe_idx; +} + int resource_find_free_pipe_used_as_cur_sec_dpp_in_mpcc_combine( const struct resource_context *cur_res_ctx, struct resource_context *new_res_ctx, @@ -2170,6 +2194,10 @@ void resource_log_pipe_topology_update(struct dc *dc, struct dc_state *state) for (stream_idx = 0; stream_idx < state->stream_count; stream_idx++) { otg_master = resource_get_otg_master_for_stream( &state->res_ctx, state->streams[stream_idx]); + if (!otg_master || otg_master->stream_res.tg == NULL) { + DC_LOG_DC("topology update: otg_master NULL stream_idx %d!\n", stream_idx); + return; + } slice_count = resource_get_opp_heads_for_otg_master(otg_master, &state->res_ctx, opp_heads); for (slice_idx = 0; slice_idx < slice_count; slice_idx++) { @@ -2233,7 +2261,7 @@ static struct pipe_ctx *get_last_dpp_pipe_in_mpcc_combine( } static bool update_pipe_params_after_odm_slice_count_change( - const struct dc_stream_state *stream, + struct pipe_ctx *otg_master, struct dc_state *context, const struct resource_pool *pool) { @@ -2243,9 +2271,12 @@ static bool update_pipe_params_after_odm_slice_count_change( for (i = 0; i < pool->pipe_count && result; i++) { pipe = &context->res_ctx.pipe_ctx[i]; - if (pipe->stream == stream && pipe->plane_state) + if (pipe->stream == otg_master->stream && pipe->plane_state) result = resource_build_scaling_params(pipe); } + + if (pool->funcs->build_pipe_pix_clk_params) + pool->funcs->build_pipe_pix_clk_params(otg_master); return result; } @@ -2433,6 +2464,9 @@ void resource_remove_otg_master_for_stream_output(struct dc_state *context, struct pipe_ctx *otg_master = resource_get_otg_master_for_stream( &context->res_ctx, stream); + if (!otg_master) + return; + ASSERT(resource_get_odm_slice_count(otg_master) == 1); ASSERT(otg_master->plane_state == NULL); ASSERT(otg_master->stream_res.stream_enc); @@ -2928,7 +2962,7 @@ bool resource_update_pipes_for_stream_with_slice_count( otg_master, new_ctx, pool); if (result) result = update_pipe_params_after_odm_slice_count_change( - otg_master->stream, new_ctx, pool); + otg_master, new_ctx, pool); return result; } @@ -2967,189 +3001,6 @@ bool resource_update_pipes_for_plane_with_slice_count( return result; } -bool dc_add_plane_to_context( - const struct dc *dc, - struct dc_stream_state *stream, - struct dc_plane_state *plane_state, - struct dc_state *context) -{ - struct resource_pool *pool = dc->res_pool; - struct pipe_ctx *otg_master_pipe; - struct dc_stream_status *stream_status = NULL; - bool added = false; - - stream_status = dc_stream_get_status_from_state(context, stream); - if (stream_status == NULL) { - dm_error("Existing stream not found; failed to attach surface!\n"); - goto out; - } else if (stream_status->plane_count == MAX_SURFACE_NUM) { - dm_error("Surface: can not attach plane_state %p! Maximum is: %d\n", - plane_state, MAX_SURFACE_NUM); - goto out; - } - - otg_master_pipe = resource_get_otg_master_for_stream( - &context->res_ctx, stream); - added = resource_append_dpp_pipes_for_plane_composition(context, - dc->current_state, pool, otg_master_pipe, plane_state); - - if (added) { - stream_status->plane_states[stream_status->plane_count] = - plane_state; - stream_status->plane_count++; - dc_plane_state_retain(plane_state); - } - -out: - return added; -} - -bool dc_remove_plane_from_context( - const struct dc *dc, - struct dc_stream_state *stream, - struct dc_plane_state *plane_state, - struct dc_state *context) -{ - int i; - struct dc_stream_status *stream_status = NULL; - struct resource_pool *pool = dc->res_pool; - - if (!plane_state) - return true; - - for (i = 0; i < context->stream_count; i++) - if (context->streams[i] == stream) { - stream_status = &context->stream_status[i]; - break; - } - - if (stream_status == NULL) { - dm_error("Existing stream not found; failed to remove plane.\n"); - return false; - } - - resource_remove_dpp_pipes_for_plane_composition( - context, pool, plane_state); - - for (i = 0; i < stream_status->plane_count; i++) { - if (stream_status->plane_states[i] == plane_state) { - dc_plane_state_release(stream_status->plane_states[i]); - break; - } - } - - if (i == stream_status->plane_count) { - dm_error("Existing plane_state not found; failed to detach it!\n"); - return false; - } - - stream_status->plane_count--; - - /* Start at the plane we've just released, and move all the planes one index forward to "trim" the array */ - for (; i < stream_status->plane_count; i++) - stream_status->plane_states[i] = stream_status->plane_states[i + 1]; - - stream_status->plane_states[stream_status->plane_count] = NULL; - - if (stream_status->plane_count == 0 && dc->config.enable_windowed_mpo_odm) - /* ODM combine could prevent us from supporting more planes - * we will reset ODM slice count back to 1 when all planes have - * been removed to maximize the amount of planes supported when - * new planes are added. - */ - resource_update_pipes_for_stream_with_slice_count( - context, dc->current_state, dc->res_pool, stream, 1); - - return true; -} - -/** - * dc_rem_all_planes_for_stream - Remove planes attached to the target stream. - * - * @dc: Current dc state. - * @stream: Target stream, which we want to remove the attached plans. - * @context: New context. - * - * Return: - * Return true if DC was able to remove all planes from the target - * stream, otherwise, return false. - */ -bool dc_rem_all_planes_for_stream( - const struct dc *dc, - struct dc_stream_state *stream, - struct dc_state *context) -{ - int i, old_plane_count; - struct dc_stream_status *stream_status = NULL; - struct dc_plane_state *del_planes[MAX_SURFACE_NUM] = { 0 }; - - for (i = 0; i < context->stream_count; i++) - if (context->streams[i] == stream) { - stream_status = &context->stream_status[i]; - break; - } - - if (stream_status == NULL) { - dm_error("Existing stream %p not found!\n", stream); - return false; - } - - old_plane_count = stream_status->plane_count; - - for (i = 0; i < old_plane_count; i++) - del_planes[i] = stream_status->plane_states[i]; - - for (i = 0; i < old_plane_count; i++) - if (!dc_remove_plane_from_context(dc, stream, del_planes[i], context)) - return false; - - return true; -} - -static bool add_all_planes_for_stream( - const struct dc *dc, - struct dc_stream_state *stream, - const struct dc_validation_set set[], - int set_count, - struct dc_state *context) -{ - int i, j; - - for (i = 0; i < set_count; i++) - if (set[i].stream == stream) - break; - - if (i == set_count) { - dm_error("Stream %p not found in set!\n", stream); - return false; - } - - for (j = 0; j < set[i].plane_count; j++) - if (!dc_add_plane_to_context(dc, stream, set[i].plane_states[j], context)) - return false; - - return true; -} - -bool dc_add_all_planes_for_stream( - const struct dc *dc, - struct dc_stream_state *stream, - struct dc_plane_state * const *plane_states, - int plane_count, - struct dc_state *context) -{ - struct dc_validation_set set; - int i; - - set.stream = stream; - set.plane_count = plane_count; - - for (i = 0; i < plane_count; i++) - set.plane_states[i] = plane_states[i]; - - return add_all_planes_for_stream(dc, stream, &set, 1, context); -} - bool dc_is_timing_changed(struct dc_stream_state *cur_stream, struct dc_stream_state *new_stream) { @@ -3301,84 +3152,6 @@ static struct audio *find_first_free_audio( return NULL; } -/* - * dc_add_stream_to_ctx() - Add a new dc_stream_state to a dc_state. - */ -enum dc_status dc_add_stream_to_ctx( - struct dc *dc, - struct dc_state *new_ctx, - struct dc_stream_state *stream) -{ - enum dc_status res; - DC_LOGGER_INIT(dc->ctx->logger); - - if (new_ctx->stream_count >= dc->res_pool->timing_generator_count) { - DC_LOG_WARNING("Max streams reached, can't add stream %p !\n", stream); - return DC_ERROR_UNEXPECTED; - } - - new_ctx->streams[new_ctx->stream_count] = stream; - dc_stream_retain(stream); - new_ctx->stream_count++; - - res = resource_add_otg_master_for_stream_output( - new_ctx, dc->res_pool, stream); - if (res != DC_OK) - DC_LOG_WARNING("Adding stream %p to context failed with err %d!\n", stream, res); - - return res; -} - -/* - * dc_remove_stream_from_ctx() - Remove a stream from a dc_state. - */ -enum dc_status dc_remove_stream_from_ctx( - struct dc *dc, - struct dc_state *new_ctx, - struct dc_stream_state *stream) -{ - int i; - struct dc_context *dc_ctx = dc->ctx; - struct pipe_ctx *del_pipe = resource_get_otg_master_for_stream( - &new_ctx->res_ctx, stream); - - if (!del_pipe) { - DC_ERROR("Pipe not found for stream %p !\n", stream); - return DC_ERROR_UNEXPECTED; - } - - resource_update_pipes_for_stream_with_slice_count(new_ctx, - dc->current_state, dc->res_pool, stream, 1); - resource_remove_otg_master_for_stream_output( - new_ctx, dc->res_pool, stream); - - for (i = 0; i < new_ctx->stream_count; i++) - if (new_ctx->streams[i] == stream) - break; - - if (new_ctx->streams[i] != stream) { - DC_ERROR("Context doesn't have stream %p !\n", stream); - return DC_ERROR_UNEXPECTED; - } - - dc_stream_release(new_ctx->streams[i]); - new_ctx->stream_count--; - - /* Trim back arrays */ - for (; i < new_ctx->stream_count; i++) { - new_ctx->streams[i] = new_ctx->streams[i + 1]; - new_ctx->stream_status[i] = new_ctx->stream_status[i + 1]; - } - - new_ctx->streams[new_ctx->stream_count] = NULL; - memset( - &new_ctx->stream_status[new_ctx->stream_count], - 0, - sizeof(new_ctx->stream_status[0])); - - return DC_OK; -} - static struct dc_stream_state *find_pll_sharable_stream( struct dc_stream_state *stream_needs_pll, struct dc_state *context) @@ -3586,6 +3359,7 @@ static void mark_seamless_boot_stream( * |________|_______________|___________|_____________| */ static bool acquire_otg_master_pipe_for_stream( + const struct dc_state *cur_ctx, struct dc_state *new_ctx, const struct resource_pool *pool, struct dc_stream_state *stream) @@ -3599,7 +3373,22 @@ static bool acquire_otg_master_pipe_for_stream( int pipe_idx; struct pipe_ctx *pipe_ctx = NULL; - pipe_idx = resource_find_any_free_pipe(&new_ctx->res_ctx, pool); + /* + * Upper level code is responsible to optimize unnecessary addition and + * removal for unchanged streams. So unchanged stream will keep the same + * OTG master instance allocated. When current stream is removed and a + * new stream is added, we want to reuse the OTG instance made available + * by the removed stream first. If not found, we try to avoid of using + * any free pipes already used in current context as this could tear + * down exiting ODM/MPC/MPO configuration unnecessarily. + */ + pipe_idx = recource_find_free_pipe_used_as_otg_master_in_cur_res_ctx( + &cur_ctx->res_ctx, &new_ctx->res_ctx, pool); + if (pipe_idx == FREE_PIPE_INDEX_NOT_FOUND) + pipe_idx = recource_find_free_pipe_not_used_in_cur_res_ctx( + &cur_ctx->res_ctx, &new_ctx->res_ctx, pool); + if (pipe_idx == FREE_PIPE_INDEX_NOT_FOUND) + pipe_idx = resource_find_any_free_pipe(&new_ctx->res_ctx, pool); if (pipe_idx != FREE_PIPE_INDEX_NOT_FOUND) { pipe_ctx = &new_ctx->res_ctx.pipe_ctx[pipe_idx]; memset(pipe_ctx, 0, sizeof(*pipe_ctx)); @@ -3659,7 +3448,7 @@ enum dc_status resource_map_pool_resources( if (!acquired) /* acquire new resources */ - acquired = acquire_otg_master_pipe_for_stream( + acquired = acquire_otg_master_pipe_for_stream(dc->current_state, context, pool, stream); pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream); @@ -3742,34 +3531,6 @@ enum dc_status resource_map_pool_resources( return DC_ERROR_UNEXPECTED; } -/** - * dc_resource_state_copy_construct_current() - Creates a new dc_state from existing state - * - * @dc: copy out of dc->current_state - * @dst_ctx: copy into this - * - * This function makes a shallow copy of the current DC state and increments - * refcounts on existing streams and planes. - */ -void dc_resource_state_copy_construct_current( - const struct dc *dc, - struct dc_state *dst_ctx) -{ - dc_resource_state_copy_construct(dc->current_state, dst_ctx); -} - - -void dc_resource_state_construct( - const struct dc *dc, - struct dc_state *dst_ctx) -{ - dst_ctx->clk_mgr = dc->clk_mgr; - - /* Initialise DIG link encoder resource tracking variables. */ - link_enc_cfg_init(dc, dst_ctx); -} - - bool dc_resource_is_dsc_encoding_supported(const struct dc *dc) { if (dc->res_pool == NULL) @@ -3813,6 +3574,31 @@ static bool planes_changed_for_existing_stream(struct dc_state *context, return false; } +static bool add_all_planes_for_stream( + const struct dc *dc, + struct dc_stream_state *stream, + const struct dc_validation_set set[], + int set_count, + struct dc_state *state) +{ + int i, j; + + for (i = 0; i < set_count; i++) + if (set[i].stream == stream) + break; + + if (i == set_count) { + dm_error("Stream %p not found in set!\n", stream); + return false; + } + + for (j = 0; j < set[i].plane_count; j++) + if (!dc_state_add_plane(dc, stream, set[i].plane_states[j], state)) + return false; + + return true; +} + /** * dc_validate_with_context - Validate and update the potential new stream in the context object * @@ -3918,7 +3704,8 @@ enum dc_status dc_validate_with_context(struct dc *dc, unchanged_streams[i], set, set_count)) { - if (!dc_rem_all_planes_for_stream(dc, + + if (!dc_state_rem_all_planes_for_stream(dc, unchanged_streams[i], context)) { res = DC_FAIL_DETACH_SURFACES; @@ -3940,12 +3727,24 @@ enum dc_status dc_validate_with_context(struct dc *dc, } } - if (!dc_rem_all_planes_for_stream(dc, del_streams[i], context)) { - res = DC_FAIL_DETACH_SURFACES; - goto fail; + if (dc_state_get_stream_subvp_type(context, del_streams[i]) == SUBVP_PHANTOM) { + /* remove phantoms specifically */ + if (!dc_state_rem_all_phantom_planes_for_stream(dc, del_streams[i], context, true)) { + res = DC_FAIL_DETACH_SURFACES; + goto fail; + } + + res = dc_state_remove_phantom_stream(dc, context, del_streams[i]); + dc_state_release_phantom_stream(dc, context, del_streams[i]); + } else { + if (!dc_state_rem_all_planes_for_stream(dc, del_streams[i], context)) { + res = DC_FAIL_DETACH_SURFACES; + goto fail; + } + + res = dc_state_remove_stream(dc, context, del_streams[i]); } - res = dc_remove_stream_from_ctx(dc, context, del_streams[i]); if (res != DC_OK) goto fail; } @@ -3968,7 +3767,7 @@ enum dc_status dc_validate_with_context(struct dc *dc, /* Add new streams and then add all planes for the new stream */ for (i = 0; i < add_streams_count; i++) { calculate_phy_pix_clks(add_streams[i]); - res = dc_add_stream_to_ctx(dc, context, add_streams[i]); + res = dc_state_add_stream(dc, context, add_streams[i]); if (res != DC_OK) goto fail; @@ -4474,84 +4273,6 @@ static void set_vtem_info_packet( *info_packet = stream->vtem_infopacket; } -void dc_resource_state_destruct(struct dc_state *context) -{ - int i, j; - - for (i = 0; i < context->stream_count; i++) { - for (j = 0; j < context->stream_status[i].plane_count; j++) - dc_plane_state_release( - context->stream_status[i].plane_states[j]); - - context->stream_status[i].plane_count = 0; - dc_stream_release(context->streams[i]); - context->streams[i] = NULL; - } - context->stream_count = 0; - context->stream_mask = 0; - memset(&context->res_ctx, 0, sizeof(context->res_ctx)); - memset(&context->pp_display_cfg, 0, sizeof(context->pp_display_cfg)); - memset(&context->dcn_bw_vars, 0, sizeof(context->dcn_bw_vars)); - context->clk_mgr = NULL; - memset(&context->bw_ctx.bw, 0, sizeof(context->bw_ctx.bw)); - memset(context->block_sequence, 0, sizeof(context->block_sequence)); - context->block_sequence_steps = 0; - memset(context->dc_dmub_cmd, 0, sizeof(context->dc_dmub_cmd)); - context->dmub_cmd_count = 0; - memset(&context->perf_params, 0, sizeof(context->perf_params)); - memset(&context->scratch, 0, sizeof(context->scratch)); -} - -void dc_resource_state_copy_construct( - const struct dc_state *src_ctx, - struct dc_state *dst_ctx) -{ - int i, j; - struct kref refcount = dst_ctx->refcount; -#ifdef CONFIG_DRM_AMD_DC_FP - struct dml2_context *dml2 = NULL; - - // Need to preserve allocated dml2 context - if (src_ctx->clk_mgr->ctx->dc->debug.using_dml2) - dml2 = dst_ctx->bw_ctx.dml2; -#endif - - *dst_ctx = *src_ctx; - -#ifdef CONFIG_DRM_AMD_DC_FP - // Preserve allocated dml2 context - if (src_ctx->clk_mgr->ctx->dc->debug.using_dml2) - dst_ctx->bw_ctx.dml2 = dml2; -#endif - - for (i = 0; i < MAX_PIPES; i++) { - struct pipe_ctx *cur_pipe = &dst_ctx->res_ctx.pipe_ctx[i]; - - if (cur_pipe->top_pipe) - cur_pipe->top_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->top_pipe->pipe_idx]; - - if (cur_pipe->bottom_pipe) - cur_pipe->bottom_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->bottom_pipe->pipe_idx]; - - if (cur_pipe->next_odm_pipe) - cur_pipe->next_odm_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->next_odm_pipe->pipe_idx]; - - if (cur_pipe->prev_odm_pipe) - cur_pipe->prev_odm_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->prev_odm_pipe->pipe_idx]; - } - - for (i = 0; i < dst_ctx->stream_count; i++) { - dc_stream_retain(dst_ctx->streams[i]); - for (j = 0; j < dst_ctx->stream_status[i].plane_count; j++) - dc_plane_state_retain( - dst_ctx->stream_status[i].plane_states[j]); - } - - /* context refcount should not be overridden */ - dst_ctx->refcount = refcount; - -} - struct clock_source *dc_resource_find_first_free_pll( struct resource_context *res_ctx, const struct resource_pool *pool) @@ -4731,7 +4452,7 @@ void resource_build_bit_depth_reduction_params(struct dc_stream_state *stream, option = DITHER_OPTION_SPATIAL8; break; case COLOR_DEPTH_101010: - option = DITHER_OPTION_SPATIAL10; + option = DITHER_OPTION_TRUN10; break; default: option = DITHER_OPTION_DISABLE; @@ -4757,6 +4478,8 @@ void resource_build_bit_depth_reduction_params(struct dc_stream_state *stream, option == DITHER_OPTION_TRUN10_SPATIAL8_FM6) { fmt_bit_depth->flags.TRUNCATE_ENABLED = 1; fmt_bit_depth->flags.TRUNCATE_DEPTH = 2; + if (option == DITHER_OPTION_TRUN10) + fmt_bit_depth->flags.TRUNCATE_MODE = 1; } /* special case - Formatter can only reduce by 4 bits at most. @@ -5274,7 +4997,7 @@ bool check_subvp_sw_cursor_fallback_req(const struct dc *dc, struct dc_stream_st if (dc->current_state->stream_count == 1 && stream->timing.v_addressable >= 2880 && ((stream->timing.pix_clk_100hz * 100) / stream->timing.v_total / stream->timing.h_total) < 120) return true; - else if (dc->current_state->stream_count > 1 && stream->timing.v_addressable >= 2160 && + else if (dc->current_state->stream_count > 1 && stream->timing.v_addressable >= 1080 && ((stream->timing.pix_clk_100hz * 100) / stream->timing.v_total / stream->timing.h_total) < 120) return true; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_state.c b/drivers/gpu/drm/amd/display/dc/core/dc_state.c new file mode 100644 index 00000000000000..88c6436b28b69c --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/core/dc_state.c @@ -0,0 +1,867 @@ +/* + * 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 "core_types.h" +#include "core_status.h" +#include "dc_state.h" +#include "dc_state_priv.h" +#include "dc_stream_priv.h" +#include "dc_plane_priv.h" + +#include "dm_services.h" +#include "resource.h" +#include "link_enc_cfg.h" + +#include "dml2/dml2_wrapper.h" +#include "dml2/dml2_internal_types.h" + +#define DC_LOGGER \ + dc->ctx->logger +#define DC_LOGGER_INIT(logger) + +/* Private dc_state helper functions */ +static bool dc_state_track_phantom_stream(struct dc_state *state, + struct dc_stream_state *phantom_stream) +{ + if (state->phantom_stream_count >= MAX_PHANTOM_PIPES) + return false; + + state->phantom_streams[state->phantom_stream_count++] = phantom_stream; + + return true; +} + +static bool dc_state_untrack_phantom_stream(struct dc_state *state, struct dc_stream_state *phantom_stream) +{ + bool res = false; + int i; + + /* first find phantom stream in the dc_state */ + for (i = 0; i < state->phantom_stream_count; i++) { + if (state->phantom_streams[i] == phantom_stream) { + state->phantom_streams[i] = NULL; + res = true; + break; + } + } + + /* failed to find stream in state */ + if (!res) + return res; + + /* trim back phantom streams */ + state->phantom_stream_count--; + for (; i < state->phantom_stream_count; i++) + state->phantom_streams[i] = state->phantom_streams[i + 1]; + + return res; +} + +static bool dc_state_is_phantom_stream_tracked(struct dc_state *state, struct dc_stream_state *phantom_stream) +{ + int i; + + for (i = 0; i < state->phantom_stream_count; i++) { + if (state->phantom_streams[i] == phantom_stream) + return true; + } + + return false; +} + +static bool dc_state_track_phantom_plane(struct dc_state *state, + struct dc_plane_state *phantom_plane) +{ + if (state->phantom_plane_count >= MAX_PHANTOM_PIPES) + return false; + + state->phantom_planes[state->phantom_plane_count++] = phantom_plane; + + return true; +} + +static bool dc_state_untrack_phantom_plane(struct dc_state *state, struct dc_plane_state *phantom_plane) +{ + bool res = false; + int i; + + /* first find phantom plane in the dc_state */ + for (i = 0; i < state->phantom_plane_count; i++) { + if (state->phantom_planes[i] == phantom_plane) { + state->phantom_planes[i] = NULL; + res = true; + break; + } + } + + /* failed to find plane in state */ + if (!res) + return res; + + /* trim back phantom planes */ + state->phantom_plane_count--; + for (; i < state->phantom_plane_count; i++) + state->phantom_planes[i] = state->phantom_planes[i + 1]; + + return res; +} + +static bool dc_state_is_phantom_plane_tracked(struct dc_state *state, struct dc_plane_state *phantom_plane) +{ + int i; + + for (i = 0; i < state->phantom_plane_count; i++) { + if (state->phantom_planes[i] == phantom_plane) + return true; + } + + return false; +} + +static void dc_state_copy_internal(struct dc_state *dst_state, struct dc_state *src_state) +{ + int i, j; + + memcpy(dst_state, src_state, sizeof(struct dc_state)); + + for (i = 0; i < MAX_PIPES; i++) { + struct pipe_ctx *cur_pipe = &dst_state->res_ctx.pipe_ctx[i]; + + if (cur_pipe->top_pipe) + cur_pipe->top_pipe = &dst_state->res_ctx.pipe_ctx[cur_pipe->top_pipe->pipe_idx]; + + if (cur_pipe->bottom_pipe) + cur_pipe->bottom_pipe = &dst_state->res_ctx.pipe_ctx[cur_pipe->bottom_pipe->pipe_idx]; + + if (cur_pipe->prev_odm_pipe) + cur_pipe->prev_odm_pipe = &dst_state->res_ctx.pipe_ctx[cur_pipe->prev_odm_pipe->pipe_idx]; + + if (cur_pipe->next_odm_pipe) + cur_pipe->next_odm_pipe = &dst_state->res_ctx.pipe_ctx[cur_pipe->next_odm_pipe->pipe_idx]; + } + + /* retain phantoms */ + for (i = 0; i < dst_state->phantom_stream_count; i++) + dc_stream_retain(dst_state->phantom_streams[i]); + + for (i = 0; i < dst_state->phantom_plane_count; i++) + dc_plane_state_retain(dst_state->phantom_planes[i]); + + /* retain streams and planes */ + for (i = 0; i < dst_state->stream_count; i++) { + dc_stream_retain(dst_state->streams[i]); + for (j = 0; j < dst_state->stream_status[i].plane_count; j++) + dc_plane_state_retain( + dst_state->stream_status[i].plane_states[j]); + } + +} + +static void init_state(struct dc *dc, struct dc_state *state) +{ + /* Each context must have their 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 + */ + memcpy(&state->bw_ctx.dml, &dc->dml, sizeof(struct display_mode_lib)); +} + +/* Public dc_state functions */ +struct dc_state *dc_state_create(struct dc *dc) +{ + struct dc_state *state = kvzalloc(sizeof(struct dc_state), + GFP_KERNEL); + + if (!state) + return NULL; + + init_state(dc, state); + dc_state_construct(dc, state); + +#ifdef CONFIG_DRM_AMD_DC_FP + if (dc->debug.using_dml2) + dml2_create(dc, &dc->dml2_options, &state->bw_ctx.dml2); +#endif + + kref_init(&state->refcount); + + return state; +} + +void dc_state_copy(struct dc_state *dst_state, struct dc_state *src_state) +{ + struct kref refcount = dst_state->refcount; +#ifdef CONFIG_DRM_AMD_DC_FP + struct dml2_context *dst_dml2 = dst_state->bw_ctx.dml2; +#endif + + dc_state_copy_internal(dst_state, src_state); + +#ifdef CONFIG_DRM_AMD_DC_FP + dst_state->bw_ctx.dml2 = dst_dml2; + if (src_state->bw_ctx.dml2) + dml2_copy(dst_state->bw_ctx.dml2, src_state->bw_ctx.dml2); +#endif + + /* context refcount should not be overridden */ + dst_state->refcount = refcount; +} + +struct dc_state *dc_state_create_copy(struct dc_state *src_state) +{ + struct dc_state *new_state; + + new_state = kvmalloc(sizeof(struct dc_state), + GFP_KERNEL); + if (!new_state) + return NULL; + + dc_state_copy_internal(new_state, src_state); + +#ifdef CONFIG_DRM_AMD_DC_FP + if (src_state->bw_ctx.dml2 && + !dml2_create_copy(&new_state->bw_ctx.dml2, src_state->bw_ctx.dml2)) { + dc_state_release(new_state); + return NULL; + } +#endif + + kref_init(&new_state->refcount); + + return new_state; +} + +void dc_state_copy_current(struct dc *dc, struct dc_state *dst_state) +{ + dc_state_copy(dst_state, dc->current_state); +} + +struct dc_state *dc_state_create_current_copy(struct dc *dc) +{ + return dc_state_create_copy(dc->current_state); +} + +void dc_state_construct(struct dc *dc, struct dc_state *state) +{ + state->clk_mgr = dc->clk_mgr; + + /* Initialise DIG link encoder resource tracking variables. */ + if (dc->res_pool) + link_enc_cfg_init(dc, state); +} + +void dc_state_destruct(struct dc_state *state) +{ + int i, j; + + for (i = 0; i < state->stream_count; i++) { + for (j = 0; j < state->stream_status[i].plane_count; j++) + dc_plane_state_release( + state->stream_status[i].plane_states[j]); + + state->stream_status[i].plane_count = 0; + dc_stream_release(state->streams[i]); + state->streams[i] = NULL; + } + state->stream_count = 0; + + /* release tracked phantoms */ + for (i = 0; i < state->phantom_stream_count; i++) { + dc_stream_release(state->phantom_streams[i]); + state->phantom_streams[i] = NULL; + } + + for (i = 0; i < state->phantom_plane_count; i++) { + dc_plane_state_release(state->phantom_planes[i]); + state->phantom_planes[i] = NULL; + } + state->stream_mask = 0; + memset(&state->res_ctx, 0, sizeof(state->res_ctx)); + memset(&state->pp_display_cfg, 0, sizeof(state->pp_display_cfg)); + memset(&state->dcn_bw_vars, 0, sizeof(state->dcn_bw_vars)); + state->clk_mgr = NULL; + memset(&state->bw_ctx.bw, 0, sizeof(state->bw_ctx.bw)); + memset(state->block_sequence, 0, sizeof(state->block_sequence)); + state->block_sequence_steps = 0; + memset(state->dc_dmub_cmd, 0, sizeof(state->dc_dmub_cmd)); + state->dmub_cmd_count = 0; + memset(&state->perf_params, 0, sizeof(state->perf_params)); + memset(&state->scratch, 0, sizeof(state->scratch)); +} + +void dc_state_retain(struct dc_state *state) +{ + kref_get(&state->refcount); +} + +static void dc_state_free(struct kref *kref) +{ + struct dc_state *state = container_of(kref, struct dc_state, refcount); + + dc_state_destruct(state); + +#ifdef CONFIG_DRM_AMD_DC_FP + dml2_destroy(state->bw_ctx.dml2); + state->bw_ctx.dml2 = 0; +#endif + + kvfree(state); +} + +void dc_state_release(struct dc_state *state) +{ + kref_put(&state->refcount, dc_state_free); +} +/* + * dc_state_add_stream() - Add a new dc_stream_state to a dc_state. + */ +enum dc_status dc_state_add_stream( + struct dc *dc, + struct dc_state *state, + struct dc_stream_state *stream) +{ + enum dc_status res; + + DC_LOGGER_INIT(dc->ctx->logger); + + if (state->stream_count >= dc->res_pool->timing_generator_count) { + DC_LOG_WARNING("Max streams reached, can't add stream %p !\n", stream); + return DC_ERROR_UNEXPECTED; + } + + state->streams[state->stream_count] = stream; + dc_stream_retain(stream); + state->stream_count++; + + res = resource_add_otg_master_for_stream_output( + state, dc->res_pool, stream); + if (res != DC_OK) + DC_LOG_WARNING("Adding stream %p to context failed with err %d!\n", stream, res); + + return res; +} + +/* + * dc_state_remove_stream() - Remove a stream from a dc_state. + */ +enum dc_status dc_state_remove_stream( + struct dc *dc, + struct dc_state *state, + struct dc_stream_state *stream) +{ + int i; + struct pipe_ctx *del_pipe = resource_get_otg_master_for_stream( + &state->res_ctx, stream); + + if (!del_pipe) { + dm_error("Pipe not found for stream %p !\n", stream); + return DC_ERROR_UNEXPECTED; + } + + resource_update_pipes_for_stream_with_slice_count(state, + dc->current_state, dc->res_pool, stream, 1); + resource_remove_otg_master_for_stream_output( + state, dc->res_pool, stream); + + for (i = 0; i < state->stream_count; i++) + if (state->streams[i] == stream) + break; + + if (state->streams[i] != stream) { + dm_error("Context doesn't have stream %p !\n", stream); + return DC_ERROR_UNEXPECTED; + } + + dc_stream_release(state->streams[i]); + state->stream_count--; + + /* Trim back arrays */ + for (; i < state->stream_count; i++) { + state->streams[i] = state->streams[i + 1]; + state->stream_status[i] = state->stream_status[i + 1]; + } + + state->streams[state->stream_count] = NULL; + memset( + &state->stream_status[state->stream_count], + 0, + sizeof(state->stream_status[0])); + + return DC_OK; +} + +bool dc_state_add_plane( + const struct dc *dc, + struct dc_stream_state *stream, + struct dc_plane_state *plane_state, + struct dc_state *state) +{ + struct resource_pool *pool = dc->res_pool; + struct pipe_ctx *otg_master_pipe; + struct dc_stream_status *stream_status = NULL; + bool added = false; + + stream_status = dc_state_get_stream_status(state, stream); + if (stream_status == NULL) { + dm_error("Existing stream not found; failed to attach surface!\n"); + goto out; + } else if (stream_status->plane_count == MAX_SURFACE_NUM) { + dm_error("Surface: can not attach plane_state %p! Maximum is: %d\n", + plane_state, MAX_SURFACE_NUM); + goto out; + } + + otg_master_pipe = resource_get_otg_master_for_stream( + &state->res_ctx, stream); + if (otg_master_pipe) + added = resource_append_dpp_pipes_for_plane_composition(state, + dc->current_state, pool, otg_master_pipe, plane_state); + + if (added) { + stream_status->plane_states[stream_status->plane_count] = + plane_state; + stream_status->plane_count++; + dc_plane_state_retain(plane_state); + } + +out: + return added; +} + +bool dc_state_remove_plane( + const struct dc *dc, + struct dc_stream_state *stream, + struct dc_plane_state *plane_state, + struct dc_state *state) +{ + int i; + struct dc_stream_status *stream_status = NULL; + struct resource_pool *pool = dc->res_pool; + + if (!plane_state) + return true; + + for (i = 0; i < state->stream_count; i++) + if (state->streams[i] == stream) { + stream_status = &state->stream_status[i]; + break; + } + + if (stream_status == NULL) { + dm_error("Existing stream not found; failed to remove plane.\n"); + return false; + } + + resource_remove_dpp_pipes_for_plane_composition( + state, pool, plane_state); + + for (i = 0; i < stream_status->plane_count; i++) { + if (stream_status->plane_states[i] == plane_state) { + dc_plane_state_release(stream_status->plane_states[i]); + break; + } + } + + if (i == stream_status->plane_count) { + dm_error("Existing plane_state not found; failed to detach it!\n"); + return false; + } + + stream_status->plane_count--; + + /* Start at the plane we've just released, and move all the planes one index forward to "trim" the array */ + for (; i < stream_status->plane_count; i++) + stream_status->plane_states[i] = stream_status->plane_states[i + 1]; + + stream_status->plane_states[stream_status->plane_count] = NULL; + + if (stream_status->plane_count == 0 && dc->config.enable_windowed_mpo_odm) + /* ODM combine could prevent us from supporting more planes + * we will reset ODM slice count back to 1 when all planes have + * been removed to maximize the amount of planes supported when + * new planes are added. + */ + resource_update_pipes_for_stream_with_slice_count( + state, dc->current_state, dc->res_pool, stream, 1); + + return true; +} + +/** + * dc_state_rem_all_planes_for_stream - Remove planes attached to the target stream. + * + * @dc: Current dc state. + * @stream: Target stream, which we want to remove the attached plans. + * @state: context from which the planes are to be removed. + * + * Return: + * Return true if DC was able to remove all planes from the target + * stream, otherwise, return false. + */ +bool dc_state_rem_all_planes_for_stream( + const struct dc *dc, + struct dc_stream_state *stream, + struct dc_state *state) +{ + int i, old_plane_count; + struct dc_stream_status *stream_status = NULL; + struct dc_plane_state *del_planes[MAX_SURFACE_NUM] = { 0 }; + + for (i = 0; i < state->stream_count; i++) + if (state->streams[i] == stream) { + stream_status = &state->stream_status[i]; + break; + } + + if (stream_status == NULL) { + dm_error("Existing stream %p not found!\n", stream); + return false; + } + + old_plane_count = stream_status->plane_count; + + for (i = 0; i < old_plane_count; i++) + del_planes[i] = stream_status->plane_states[i]; + + for (i = 0; i < old_plane_count; i++) + if (!dc_state_remove_plane(dc, stream, del_planes[i], state)) + return false; + + return true; +} + +bool dc_state_add_all_planes_for_stream( + const struct dc *dc, + struct dc_stream_state *stream, + struct dc_plane_state * const *plane_states, + int plane_count, + struct dc_state *state) +{ + int i; + bool result = true; + + for (i = 0; i < plane_count; i++) + if (!dc_state_add_plane(dc, stream, plane_states[i], state)) { + result = false; + break; + } + + return result; +} + +/* Private dc_state functions */ + +/** + * dc_state_get_stream_status - Get stream status from given dc state + * @state: DC state to find the stream status in + * @stream: The stream to get the stream status for + * + * The given stream is expected to exist in the given dc state. Otherwise, NULL + * will be returned. + */ +struct dc_stream_status *dc_state_get_stream_status( + struct dc_state *state, + struct dc_stream_state *stream) +{ + uint8_t i; + + if (state == NULL) + return NULL; + + for (i = 0; i < state->stream_count; i++) { + if (stream == state->streams[i]) + return &state->stream_status[i]; + } + + return NULL; +} + +enum mall_stream_type dc_state_get_pipe_subvp_type(const struct dc_state *state, + const struct pipe_ctx *pipe_ctx) +{ + return dc_state_get_stream_subvp_type(state, pipe_ctx->stream); +} + +enum mall_stream_type dc_state_get_stream_subvp_type(const struct dc_state *state, + const struct dc_stream_state *stream) +{ + int i; + + enum mall_stream_type type = SUBVP_NONE; + + for (i = 0; i < state->stream_count; i++) { + if (state->streams[i] == stream) { + type = state->stream_status[i].mall_stream_config.type; + break; + } + } + + return type; +} + +struct dc_stream_state *dc_state_get_paired_subvp_stream(const struct dc_state *state, + const struct dc_stream_state *stream) +{ + int i; + + struct dc_stream_state *paired_stream = NULL; + + for (i = 0; i < state->stream_count; i++) { + if (state->streams[i] == stream) { + paired_stream = state->stream_status[i].mall_stream_config.paired_stream; + break; + } + } + + return paired_stream; +} + +struct dc_stream_state *dc_state_create_phantom_stream(const struct dc *dc, + struct dc_state *state, + struct dc_stream_state *main_stream) +{ + struct dc_stream_state *phantom_stream; + + DC_LOGGER_INIT(dc->ctx->logger); + + phantom_stream = dc_create_stream_for_sink(main_stream->sink); + + if (!phantom_stream) { + DC_LOG_ERROR("Failed to allocate phantom stream.\n"); + return NULL; + } + + /* track phantom stream in dc_state */ + dc_state_track_phantom_stream(state, phantom_stream); + + phantom_stream->is_phantom = true; + phantom_stream->signal = SIGNAL_TYPE_VIRTUAL; + phantom_stream->dpms_off = true; + + return phantom_stream; +} + +void dc_state_release_phantom_stream(const struct dc *dc, + struct dc_state *state, + struct dc_stream_state *phantom_stream) +{ + DC_LOGGER_INIT(dc->ctx->logger); + + if (!dc_state_untrack_phantom_stream(state, phantom_stream)) { + DC_LOG_ERROR("Failed to free phantom stream %p in dc state %p.\n", phantom_stream, state); + return; + } + + dc_stream_release(phantom_stream); +} + +struct dc_plane_state *dc_state_create_phantom_plane(struct dc *dc, + struct dc_state *state, + struct dc_plane_state *main_plane) +{ + struct dc_plane_state *phantom_plane = dc_create_plane_state(dc); + + DC_LOGGER_INIT(dc->ctx->logger); + + if (!phantom_plane) { + DC_LOG_ERROR("Failed to allocate phantom plane.\n"); + return NULL; + } + + /* track phantom inside dc_state */ + dc_state_track_phantom_plane(state, phantom_plane); + + phantom_plane->is_phantom = true; + + return phantom_plane; +} + +void dc_state_release_phantom_plane(const struct dc *dc, + struct dc_state *state, + struct dc_plane_state *phantom_plane) +{ + DC_LOGGER_INIT(dc->ctx->logger); + + if (!dc_state_untrack_phantom_plane(state, phantom_plane)) { + DC_LOG_ERROR("Failed to free phantom plane %p in dc state %p.\n", phantom_plane, state); + return; + } + + dc_plane_state_release(phantom_plane); +} + +/* add phantom streams to context and generate correct meta inside dc_state */ +enum dc_status dc_state_add_phantom_stream(struct dc *dc, + struct dc_state *state, + struct dc_stream_state *phantom_stream, + struct dc_stream_state *main_stream) +{ + struct dc_stream_status *main_stream_status; + struct dc_stream_status *phantom_stream_status; + enum dc_status res = dc_state_add_stream(dc, state, phantom_stream); + + /* check if stream is tracked */ + if (res == DC_OK && !dc_state_is_phantom_stream_tracked(state, phantom_stream)) { + /* stream must be tracked if added to state */ + dc_state_track_phantom_stream(state, phantom_stream); + } + + /* setup subvp meta */ + main_stream_status = dc_state_get_stream_status(state, main_stream); + phantom_stream_status = dc_state_get_stream_status(state, phantom_stream); + phantom_stream_status->mall_stream_config.type = SUBVP_PHANTOM; + phantom_stream_status->mall_stream_config.paired_stream = main_stream; + main_stream_status->mall_stream_config.type = SUBVP_MAIN; + main_stream_status->mall_stream_config.paired_stream = phantom_stream; + + return res; +} + +enum dc_status dc_state_remove_phantom_stream(struct dc *dc, + struct dc_state *state, + struct dc_stream_state *phantom_stream) +{ + struct dc_stream_status *main_stream_status; + struct dc_stream_status *phantom_stream_status; + + /* reset subvp meta */ + phantom_stream_status = dc_state_get_stream_status(state, phantom_stream); + main_stream_status = dc_state_get_stream_status(state, phantom_stream_status->mall_stream_config.paired_stream); + phantom_stream_status->mall_stream_config.type = SUBVP_NONE; + phantom_stream_status->mall_stream_config.paired_stream = NULL; + if (main_stream_status) { + main_stream_status->mall_stream_config.type = SUBVP_NONE; + main_stream_status->mall_stream_config.paired_stream = NULL; + } + + /* remove stream from state */ + return dc_state_remove_stream(dc, state, phantom_stream); +} + +bool dc_state_add_phantom_plane( + const struct dc *dc, + struct dc_stream_state *phantom_stream, + struct dc_plane_state *phantom_plane, + struct dc_state *state) +{ + bool res = dc_state_add_plane(dc, phantom_stream, phantom_plane, state); + + /* check if stream is tracked */ + if (res && !dc_state_is_phantom_plane_tracked(state, phantom_plane)) { + /* stream must be tracked if added to state */ + dc_state_track_phantom_plane(state, phantom_plane); + } + + return res; +} + +bool dc_state_remove_phantom_plane( + const struct dc *dc, + struct dc_stream_state *phantom_stream, + struct dc_plane_state *phantom_plane, + struct dc_state *state) +{ + return dc_state_remove_plane(dc, phantom_stream, phantom_plane, state); +} + +bool dc_state_rem_all_phantom_planes_for_stream( + const struct dc *dc, + struct dc_stream_state *phantom_stream, + struct dc_state *state, + bool should_release_planes) +{ + int i, old_plane_count; + struct dc_stream_status *stream_status = NULL; + struct dc_plane_state *del_planes[MAX_SURFACE_NUM] = { 0 }; + + for (i = 0; i < state->stream_count; i++) + if (state->streams[i] == phantom_stream) { + stream_status = &state->stream_status[i]; + break; + } + + if (stream_status == NULL) { + dm_error("Existing stream %p not found!\n", phantom_stream); + return false; + } + + old_plane_count = stream_status->plane_count; + + for (i = 0; i < old_plane_count; i++) + del_planes[i] = stream_status->plane_states[i]; + + for (i = 0; i < old_plane_count; i++) { + if (!dc_state_remove_plane(dc, phantom_stream, del_planes[i], state)) + return false; + if (should_release_planes) + dc_state_release_phantom_plane(dc, state, del_planes[i]); + } + + return true; +} + +bool dc_state_add_all_phantom_planes_for_stream( + const struct dc *dc, + struct dc_stream_state *phantom_stream, + struct dc_plane_state * const *phantom_planes, + int plane_count, + struct dc_state *state) +{ + return dc_state_add_all_planes_for_stream(dc, phantom_stream, phantom_planes, plane_count, state); +} + +bool dc_state_remove_phantom_streams_and_planes( + struct dc *dc, + struct dc_state *state) +{ + int i; + bool removed_phantom = false; + struct dc_stream_state *phantom_stream = NULL; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &state->res_ctx.pipe_ctx[i]; + + if (pipe->plane_state && pipe->stream && dc_state_get_pipe_subvp_type(state, pipe) == SUBVP_PHANTOM) { + phantom_stream = pipe->stream; + + dc_state_rem_all_phantom_planes_for_stream(dc, phantom_stream, state, false); + dc_state_remove_phantom_stream(dc, state, phantom_stream); + removed_phantom = true; + } + } + return removed_phantom; +} + +void dc_state_release_phantom_streams_and_planes( + struct dc *dc, + struct dc_state *state) +{ + int i; + + for (i = 0; i < state->phantom_stream_count; i++) + dc_state_release_phantom_stream(dc, state, state->phantom_streams[i]); + + for (i = 0; i < state->phantom_plane_count; i++) + dc_state_release_phantom_plane(dc, state, state->phantom_planes[i]); +} 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 4bdf105d1d7150..54670e0b151895 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c @@ -31,6 +31,8 @@ #include "ipp.h" #include "timing_generator.h" #include "dc_dmub_srv.h" +#include "dc_state_priv.h" +#include "dc_stream_priv.h" #define DC_LOGGER dc->ctx->logger @@ -54,7 +56,7 @@ void update_stream_signal(struct dc_stream_state *stream, struct dc_sink *sink) } } -static bool dc_stream_construct(struct dc_stream_state *stream, +bool dc_stream_construct(struct dc_stream_state *stream, struct dc_sink *dc_sink_data) { uint32_t i = 0; @@ -121,13 +123,12 @@ static bool dc_stream_construct(struct dc_stream_state *stream, } stream->out_transfer_func->type = TF_TYPE_BYPASS; - stream->stream_id = stream->ctx->dc_stream_id_count; - stream->ctx->dc_stream_id_count++; + dc_stream_assign_stream_id(stream); return true; } -static void dc_stream_destruct(struct dc_stream_state *stream) +void dc_stream_destruct(struct dc_stream_state *stream) { dc_sink_release(stream->sink); if (stream->out_transfer_func != NULL) { @@ -136,6 +137,13 @@ static void dc_stream_destruct(struct dc_stream_state *stream) } } +void dc_stream_assign_stream_id(struct dc_stream_state *stream) +{ + /* MSB is reserved to indicate phantoms */ + stream->stream_id = stream->ctx->dc_stream_id_count; + stream->ctx->dc_stream_id_count++; +} + void dc_stream_retain(struct dc_stream_state *stream) { kref_get(&stream->refcount); @@ -196,8 +204,7 @@ struct dc_stream_state *dc_copy_stream(const struct dc_stream_state *stream) if (new_stream->out_transfer_func) dc_transfer_func_retain(new_stream->out_transfer_func); - new_stream->stream_id = new_stream->ctx->dc_stream_id_count; - new_stream->ctx->dc_stream_id_count++; + dc_stream_assign_stream_id(new_stream); /* If using dynamic encoder assignment, wait till stream committed to assign encoder. */ if (new_stream->ctx->dc->res_pool->funcs->link_encs_assign) @@ -208,31 +215,6 @@ struct dc_stream_state *dc_copy_stream(const struct dc_stream_state *stream) return new_stream; } -/** - * dc_stream_get_status_from_state - Get stream status from given dc state - * @state: DC state to find the stream status in - * @stream: The stream to get the stream status for - * - * The given stream is expected to exist in the given dc state. Otherwise, NULL - * will be returned. - */ -struct dc_stream_status *dc_stream_get_status_from_state( - struct dc_state *state, - struct dc_stream_state *stream) -{ - uint8_t i; - - if (state == NULL) - return NULL; - - for (i = 0; i < state->stream_count; i++) { - if (stream == state->streams[i]) - return &state->stream_status[i]; - } - - return NULL; -} - /** * dc_stream_get_status() - Get current stream status of the given stream state * @stream: The stream to get the stream status for. @@ -244,7 +226,7 @@ struct dc_stream_status *dc_stream_get_status( struct dc_stream_state *stream) { struct dc *dc = stream->ctx->dc; - return dc_stream_get_status_from_state(dc->current_state, stream); + return dc_state_get_stream_status(dc->current_state, stream); } static void program_cursor_attributes( @@ -465,16 +447,37 @@ bool dc_stream_add_writeback(struct dc *dc, if (dc->hwss.enable_writeback) { struct dc_stream_status *stream_status = dc_stream_get_status(stream); struct dwbc *dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst]; - dwb->otg_inst = stream_status->primary_otg_inst; + if (stream_status) + dwb->otg_inst = stream_status->primary_otg_inst; } + + if (!dc->hwss.update_bandwidth(dc, dc->current_state)) { + dm_error("DC: update_bandwidth failed!\n"); + return false; + } + + /* enable writeback */ + if (dc->hwss.enable_writeback) { + struct dwbc *dwb = dc->res_pool->dwbc[wb_info->dwb_pipe_inst]; + + if (dwb->funcs->is_enabled(dwb)) { + /* writeback pipe already enabled, only need to update */ + dc->hwss.update_writeback(dc, wb_info, dc->current_state); + } else { + /* Enable writeback pipe from scratch*/ + dc->hwss.enable_writeback(dc, wb_info, dc->current_state); + } + } + return true; } -bool dc_stream_remove_writeback(struct dc *dc, +bool dc_stream_fc_disable_writeback(struct dc *dc, struct dc_stream_state *stream, uint32_t dwb_pipe_inst) { - int i = 0, j = 0; + struct dwbc *dwb = dc->res_pool->dwbc[dwb_pipe_inst]; + if (stream == NULL) { dm_error("DC: dc_stream is NULL!\n"); return false; @@ -490,27 +493,63 @@ bool dc_stream_remove_writeback(struct dc *dc, return false; } -// stream->writeback_info[dwb_pipe_inst].wb_enabled = false; - for (i = 0; i < stream->num_wb_info; i++) { - /*dynamic update*/ - if (stream->writeback_info[i].wb_enabled && - stream->writeback_info[i].dwb_pipe_inst == dwb_pipe_inst) { - stream->writeback_info[i].wb_enabled = false; - } + if (dwb->funcs->set_fc_enable) + dwb->funcs->set_fc_enable(dwb, DWB_FRAME_CAPTURE_DISABLE); + + return true; +} + +bool dc_stream_remove_writeback(struct dc *dc, + struct dc_stream_state *stream, + uint32_t dwb_pipe_inst) +{ + int i = 0, j = 0; + if (stream == NULL) { + dm_error("DC: dc_stream is NULL!\n"); + return false; + } + + if (dwb_pipe_inst >= MAX_DWB_PIPES) { + dm_error("DC: writeback pipe is invalid!\n"); + return false; + } + + if (stream->num_wb_info > MAX_DWB_PIPES) { + dm_error("DC: num_wb_info is invalid!\n"); + return false; } /* remove writeback info for disabled writeback pipes from stream */ for (i = 0, j = 0; i < stream->num_wb_info; i++) { if (stream->writeback_info[i].wb_enabled) { - if (j < i) - /* trim the array */ + + if (stream->writeback_info[i].dwb_pipe_inst == dwb_pipe_inst) + stream->writeback_info[i].wb_enabled = false; + + /* trim the array */ + if (j < i) { memcpy(&stream->writeback_info[j], &stream->writeback_info[i], sizeof(struct dc_writeback_info)); - j++; + j++; + } } } stream->num_wb_info = j; + /* recalculate and apply DML parameters */ + if (!dc->hwss.update_bandwidth(dc, dc->current_state)) { + dm_error("DC: update_bandwidth failed!\n"); + return false; + } + + /* disable writeback */ + if (dc->hwss.disable_writeback) { + struct dwbc *dwb = dc->res_pool->dwbc[dwb_pipe_inst]; + + if (dwb->funcs->is_enabled(dwb)) + dc->hwss.disable_writeback(dc, dwb_pipe_inst); + } + return true; } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c index a80e45300783c0..19a2c7140ae843 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c @@ -32,10 +32,12 @@ #include "transform.h" #include "dpp.h" +#include "dc_plane_priv.h" + /******************************************************************************* * Private functions ******************************************************************************/ -static void dc_plane_construct(struct dc_context *ctx, struct dc_plane_state *plane_state) +void dc_plane_construct(struct dc_context *ctx, struct dc_plane_state *plane_state) { plane_state->ctx = ctx; @@ -63,7 +65,7 @@ static void dc_plane_construct(struct dc_context *ctx, struct dc_plane_state *pl } -static void dc_plane_destruct(struct dc_plane_state *plane_state) +void dc_plane_destruct(struct dc_plane_state *plane_state) { if (plane_state->gamma_correction != NULL) { dc_gamma_release(&plane_state->gamma_correction); diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 2cafd644baff83..c9317ea0258ea1 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -27,6 +27,8 @@ #define DC_INTERFACE_H_ #include "dc_types.h" +#include "dc_state.h" +#include "dc_plane.h" #include "grph_object_defs.h" #include "logger_types.h" #include "hdcp_msg_types.h" @@ -49,7 +51,7 @@ struct aux_payload; struct set_config_cmd_payload; struct dmub_notification; -#define DC_VER "3.2.259" +#define DC_VER "3.2.266" #define MAX_SURFACES 3 #define MAX_PLANES 6 @@ -432,6 +434,7 @@ struct dc_config { bool EnableMinDispClkODM; bool enable_auto_dpm_test_logs; unsigned int disable_ips; + unsigned int disable_ips_in_vpb; }; enum visual_confirm { @@ -461,6 +464,12 @@ enum dml_hostvm_override_opts { DML_HOSTVM_OVERRIDE_TRUE = 0x2, }; +enum dc_replay_power_opts { + replay_power_opt_invalid = 0x0, + replay_power_opt_smu_opt_static_screen = 0x1, + replay_power_opt_z10_static_screen = 0x10, +}; + enum dcc_option { DCC_ENABLE = 0, DCC_DISABLE = 1, @@ -956,7 +965,6 @@ struct dc_debug_options { unsigned int min_prefetch_in_strobe_ns; bool disable_unbounded_requesting; bool dig_fifo_off_in_blank; - bool temp_mst_deallocation_sequence; bool override_dispclk_programming; bool otg_crc_db; bool disallow_dispclk_dppclk_ds; @@ -979,6 +987,9 @@ struct dc_debug_options { bool psp_disabled_wa; unsigned int ips2_eval_delay_us; unsigned int ips2_entry_delay_us; + bool disable_timeout; + bool disable_extblankadj; + unsigned int static_screen_wait_frames; }; struct gpu_info_soc_bounding_box_v1_0; @@ -1389,13 +1400,6 @@ struct dc_surface_update { /* * Create a new surface with default parameters; */ -struct dc_plane_state *dc_create_plane_state(struct dc *dc); -const struct dc_plane_status *dc_plane_get_status( - const struct dc_plane_state *plane_state); - -void dc_plane_state_retain(struct dc_plane_state *plane_state); -void dc_plane_state_release(struct dc_plane_state *plane_state); - void dc_gamma_retain(struct dc_gamma *dc_gamma); void dc_gamma_release(struct dc_gamma **dc_gamma); struct dc_gamma *dc_create_gamma(void); @@ -1459,37 +1463,20 @@ enum dc_status dc_validate_global_state( struct dc_state *new_ctx, bool fast_validate); - -void dc_resource_state_construct( - const struct dc *dc, - struct dc_state *dst_ctx); - bool dc_acquire_release_mpc_3dlut( struct dc *dc, bool acquire, struct dc_stream_state *stream, struct dc_3dlut **lut, struct dc_transfer_func **shaper); -void dc_resource_state_copy_construct( - const struct dc_state *src_ctx, - struct dc_state *dst_ctx); - -void dc_resource_state_copy_construct_current( - const struct dc *dc, - struct dc_state *dst_ctx); - -void dc_resource_state_destruct(struct dc_state *context); - bool dc_resource_is_dsc_encoding_supported(const struct dc *dc); +void get_audio_check(struct audio_info *aud_modes, + struct audio_check *aud_chk); enum dc_status dc_commit_streams(struct dc *dc, struct dc_stream_state *streams[], uint8_t stream_count); -struct dc_state *dc_create_state(struct dc *dc); -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, @@ -1541,7 +1528,13 @@ struct dc_link { bool is_dig_mapping_flexible; bool hpd_status; /* HPD status of link without physical HPD pin. */ bool is_hpd_pending; /* Indicates a new received hpd */ - bool is_automated; /* Indicates automated testing */ + + /* USB4 DPIA links skip verifying link cap, instead performing the fallback method + * for every link training. This is incompatible with DP LL compliance automation, + * which expects the same link settings to be used every retry on a link loss. + * This flag is used to skip the fallback when link loss occurs during automation. + */ + bool skip_fallback_on_link_loss; bool edp_sink_present; @@ -2092,6 +2085,20 @@ 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); +/* + * Communicate with DMUB to allow or disallow Panel Replay on the specified link: + * + * @link: pointer to the dc_link struct instance + * @enable: enable(active) or disable(inactive) replay + * @wait: state transition need to wait the active set completed. + * @force_static: force disable(inactive) the replay + * @power_opts: set power optimazation parameters to DMUB. + * + * return: allow Replay active will return true, else will return false. + */ +bool dc_link_set_replay_allow_active(struct dc_link *dc_link, const bool *enable, + bool wait, bool force_static, const unsigned int *power_opts); + bool dc_link_get_replay_state(const struct dc_link *dc_link, uint64_t *state); /* On eDP links this function call will stall until T12 has elapsed. @@ -2187,11 +2194,11 @@ int dc_link_dp_dpia_handle_usb4_bandwidth_allocation_for_link( * * @dc: pointer to dc struct * @stream: pointer to all possible streams - * @num_streams: number of valid DPIA streams + * @count: number of valid DPIA streams * * return: TRUE if bw used by DPIAs doesn't exceed available BW else return FALSE */ -bool dc_link_validate(struct dc *dc, const struct dc_stream_state *streams, +bool dc_link_dp_dpia_validate(struct dc *dc, const struct dc_stream_state *streams, const unsigned int count); /* Sink Interfaces - A sink corresponds to a display output device */ @@ -2336,6 +2343,9 @@ void dc_hardware_release(struct dc *dc); void dc_mclk_switch_using_fw_based_vblank_stretch_shut_down(struct dc *dc); bool dc_set_psr_allow_active(struct dc *dc, bool enable); + +bool dc_set_replay_allow_active(struct dc *dc, bool active); + void dc_z10_restore(const struct dc *dc); void dc_z10_save_init(struct dc *dc); 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 be9aa1a71847d7..26940d94d8fb40 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,7 @@ 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 pwrseq_instance, uint8_t bypass_panel_control_wait); enum bp_result (*get_soc_bb_info)( 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 0e07699c1e8352..2b79a0e5638e1b 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c @@ -33,6 +33,7 @@ #include "cursor_reg_cache.h" #include "resource.h" #include "clk_mgr.h" +#include "dc_state_priv.h" #define CTX dc_dmub_srv->ctx #define DC_LOGGER CTX->logger @@ -140,7 +141,10 @@ bool dc_dmub_srv_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_srv, if (status == DMUB_STATUS_QUEUE_FULL) { /* Execute and wait for queue to become empty again. */ - dmub_srv_cmd_execute(dmub); + status = dmub_srv_cmd_execute(dmub); + if (status == DMUB_STATUS_POWER_STATE_D3) + return false; + dmub_srv_wait_for_idle(dmub, 100000); /* Requeue the command. */ @@ -148,16 +152,20 @@ bool dc_dmub_srv_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_srv, } if (status != DMUB_STATUS_OK) { - DC_ERROR("Error queueing DMUB command: status=%d\n", status); - dc_dmub_srv_log_diagnostic_data(dc_dmub_srv); + if (status != DMUB_STATUS_POWER_STATE_D3) { + DC_ERROR("Error queueing DMUB command: status=%d\n", status); + dc_dmub_srv_log_diagnostic_data(dc_dmub_srv); + } return false; } } status = dmub_srv_cmd_execute(dmub); if (status != DMUB_STATUS_OK) { - DC_ERROR("Error starting DMUB execution: status=%d\n", status); - dc_dmub_srv_log_diagnostic_data(dc_dmub_srv); + if (status != DMUB_STATUS_POWER_STATE_D3) { + DC_ERROR("Error starting DMUB execution: status=%d\n", status); + dc_dmub_srv_log_diagnostic_data(dc_dmub_srv); + } return false; } @@ -218,7 +226,10 @@ bool dc_dmub_srv_cmd_run_list(struct dc_dmub_srv *dc_dmub_srv, unsigned int coun if (status == DMUB_STATUS_QUEUE_FULL) { /* Execute and wait for queue to become empty again. */ - dmub_srv_cmd_execute(dmub); + status = dmub_srv_cmd_execute(dmub); + if (status == DMUB_STATUS_POWER_STATE_D3) + return false; + dmub_srv_wait_for_idle(dmub, 100000); /* Requeue the command. */ @@ -226,22 +237,31 @@ bool dc_dmub_srv_cmd_run_list(struct dc_dmub_srv *dc_dmub_srv, unsigned int coun } if (status != DMUB_STATUS_OK) { - DC_ERROR("Error queueing DMUB command: status=%d\n", status); - dc_dmub_srv_log_diagnostic_data(dc_dmub_srv); + if (status != DMUB_STATUS_POWER_STATE_D3) { + DC_ERROR("Error queueing DMUB command: status=%d\n", status); + dc_dmub_srv_log_diagnostic_data(dc_dmub_srv); + } return false; } } status = dmub_srv_cmd_execute(dmub); if (status != DMUB_STATUS_OK) { - DC_ERROR("Error starting DMUB execution: status=%d\n", status); - dc_dmub_srv_log_diagnostic_data(dc_dmub_srv); + if (status != DMUB_STATUS_POWER_STATE_D3) { + DC_ERROR("Error starting DMUB execution: status=%d\n", status); + dc_dmub_srv_log_diagnostic_data(dc_dmub_srv); + } return false; } // Wait for DMUB to process command if (wait_type != DM_DMUB_WAIT_TYPE_NO_WAIT) { - status = dmub_srv_wait_for_idle(dmub, 100000); + if (dc_dmub_srv->ctx->dc->debug.disable_timeout) { + do { + status = dmub_srv_wait_for_idle(dmub, 100000); + } while (status != DMUB_STATUS_OK); + } else + status = dmub_srv_wait_for_idle(dmub, 100000); if (status != DMUB_STATUS_OK) { DC_LOG_DEBUG("No reply for DMUB command: status=%d\n", status); @@ -282,17 +302,11 @@ bool dc_dmub_srv_optimized_init_done(struct dc_dmub_srv *dc_dmub_srv) bool dc_dmub_srv_notify_stream_mask(struct dc_dmub_srv *dc_dmub_srv, unsigned int stream_mask) { - struct dmub_srv *dmub; - const uint32_t timeout = 30; - if (!dc_dmub_srv || !dc_dmub_srv->dmub) return false; - dmub = dc_dmub_srv->dmub; - - return dmub_srv_send_gpint_command( - dmub, DMUB_GPINT__IDLE_OPT_NOTIFY_STREAM_MASK, - stream_mask, timeout) == DMUB_STATUS_OK; + return dc_wake_and_execute_gpint(dc_dmub_srv->ctx, DMUB_GPINT__IDLE_OPT_NOTIFY_STREAM_MASK, + stream_mask, NULL, DM_DMUB_WAIT_TYPE_WAIT); } bool dc_dmub_srv_is_restore_required(struct dc_dmub_srv *dc_dmub_srv) @@ -341,7 +355,7 @@ void dc_dmub_srv_drr_update_cmd(struct dc *dc, uint32_t tg_inst, uint32_t vtotal cmd.drr_update.header.payload_bytes = sizeof(cmd.drr_update) - sizeof(cmd.drr_update.header); // Send the command to the DMCUB. - dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); } void dc_dmub_srv_set_drr_manual_trigger_cmd(struct dc *dc, uint32_t tg_inst) @@ -355,7 +369,7 @@ void dc_dmub_srv_set_drr_manual_trigger_cmd(struct dc *dc, uint32_t tg_inst) cmd.drr_update.header.payload_bytes = sizeof(cmd.drr_update) - sizeof(cmd.drr_update.header); // Send the command to the DMCUB. - dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); } static uint8_t dc_dmub_srv_get_pipes_for_stream(struct dc *dc, struct dc_stream_state *stream) @@ -448,7 +462,7 @@ bool dc_dmub_srv_p_state_delegate(struct dc *dc, bool should_manage_pstate, stru sizeof(cmd.fw_assisted_mclk_switch) - sizeof(cmd.fw_assisted_mclk_switch.header); // Send the command to the DMCUB. - dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); return true; } @@ -469,7 +483,7 @@ void dc_dmub_srv_query_caps_cmd(struct dc_dmub_srv *dc_dmub_srv) cmd.query_feature_caps.header.payload_bytes = sizeof(struct dmub_cmd_query_feature_caps_data); /* If command was processed, copy feature caps to dmub srv */ - if (dm_execute_dmub_cmd(dc_dmub_srv->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY) && + if (dc_wake_and_execute_dmub_cmd(dc_dmub_srv->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY) && cmd.query_feature_caps.header.ret_status == 0) { memcpy(&dc_dmub_srv->dmub->feature_caps, &cmd.query_feature_caps.query_feature_caps_data, @@ -494,7 +508,7 @@ void dc_dmub_srv_get_visual_confirm_color_cmd(struct dc *dc, struct pipe_ctx *pi cmd.visual_confirm_color.visual_confirm_color_data.visual_confirm_color.panel_inst = panel_inst; // If command was processed, copy feature caps to dmub srv - if (dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY) && + if (dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY) && cmd.visual_confirm_color.header.ret_status == 0) { memcpy(&dc->ctx->dmub_srv->dmub->visual_confirm_color, &cmd.visual_confirm_color.visual_confirm_color_data, @@ -505,10 +519,11 @@ void dc_dmub_srv_get_visual_confirm_color_cmd(struct dc *dc, struct pipe_ctx *pi /** * populate_subvp_cmd_drr_info - Helper to populate DRR pipe info for the DMCUB subvp command * - * @dc: [in] current dc state + * @dc: [in] pointer to dc object * @subvp_pipe: [in] pipe_ctx for the SubVP pipe * @vblank_pipe: [in] pipe_ctx for the DRR pipe * @pipe_data: [in] Pipe data which stores the VBLANK/DRR info + * @context: [in] DC state for access to phantom stream * * Populate the DMCUB SubVP command with DRR pipe info. All the information * required for calculating the SubVP + DRR microschedule is populated here. @@ -519,12 +534,14 @@ void dc_dmub_srv_get_visual_confirm_color_cmd(struct dc *dc, struct pipe_ctx *pi * 3. Populate the drr_info with the min and max supported vtotal values */ static void populate_subvp_cmd_drr_info(struct dc *dc, + struct dc_state *context, struct pipe_ctx *subvp_pipe, struct pipe_ctx *vblank_pipe, struct dmub_cmd_fw_assisted_mclk_switch_pipe_data_v2 *pipe_data) { + struct dc_stream_state *phantom_stream = dc_state_get_paired_subvp_stream(context, subvp_pipe->stream); struct dc_crtc_timing *main_timing = &subvp_pipe->stream->timing; - struct dc_crtc_timing *phantom_timing = &subvp_pipe->stream->mall_stream_config.paired_stream->timing; + struct dc_crtc_timing *phantom_timing = &phantom_stream->timing; struct dc_crtc_timing *drr_timing = &vblank_pipe->stream->timing; uint16_t drr_frame_us = 0; uint16_t min_drr_supported_us = 0; @@ -612,7 +629,7 @@ static void populate_subvp_cmd_vblank_pipe_info(struct dc *dc, continue; // Find the SubVP pipe - if (pipe->stream->mall_stream_config.type == SUBVP_MAIN) + if (dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_MAIN) break; } @@ -629,7 +646,7 @@ static void populate_subvp_cmd_vblank_pipe_info(struct dc *dc, if (vblank_pipe->stream->ignore_msa_timing_param && (vblank_pipe->stream->allow_freesync || vblank_pipe->stream->vrr_active_variable || vblank_pipe->stream->vrr_active_fixed)) - populate_subvp_cmd_drr_info(dc, pipe, vblank_pipe, pipe_data); + populate_subvp_cmd_drr_info(dc, context, pipe, vblank_pipe, pipe_data); } /** @@ -654,10 +671,17 @@ static void update_subvp_prefetch_end_to_mall_start(struct dc *dc, uint32_t subvp0_prefetch_us = 0; uint32_t subvp1_prefetch_us = 0; uint32_t prefetch_delta_us = 0; - struct dc_crtc_timing *phantom_timing0 = &subvp_pipes[0]->stream->mall_stream_config.paired_stream->timing; - struct dc_crtc_timing *phantom_timing1 = &subvp_pipes[1]->stream->mall_stream_config.paired_stream->timing; + struct dc_stream_state *phantom_stream0 = NULL; + struct dc_stream_state *phantom_stream1 = NULL; + struct dc_crtc_timing *phantom_timing0 = NULL; + struct dc_crtc_timing *phantom_timing1 = NULL; struct dmub_cmd_fw_assisted_mclk_switch_pipe_data_v2 *pipe_data = NULL; + phantom_stream0 = dc_state_get_paired_subvp_stream(context, subvp_pipes[0]->stream); + phantom_stream1 = dc_state_get_paired_subvp_stream(context, subvp_pipes[1]->stream); + phantom_timing0 = &phantom_stream0->timing; + phantom_timing1 = &phantom_stream1->timing; + subvp0_prefetch_us = div64_u64(((uint64_t)(phantom_timing0->v_total - phantom_timing0->v_front_porch) * (uint64_t)phantom_timing0->h_total * 1000000), (((uint64_t)phantom_timing0->pix_clk_100hz * 100) + dc->caps.subvp_prefetch_end_to_mall_start_us)); @@ -707,8 +731,9 @@ static void populate_subvp_cmd_pipe_info(struct dc *dc, uint32_t j; struct dmub_cmd_fw_assisted_mclk_switch_pipe_data_v2 *pipe_data = &cmd->fw_assisted_mclk_switch_v2.config_data.pipe_data[cmd_pipe_index]; + struct dc_stream_state *phantom_stream = dc_state_get_paired_subvp_stream(context, subvp_pipe->stream); struct dc_crtc_timing *main_timing = &subvp_pipe->stream->timing; - struct dc_crtc_timing *phantom_timing = &subvp_pipe->stream->mall_stream_config.paired_stream->timing; + struct dc_crtc_timing *phantom_timing = &phantom_stream->timing; uint32_t out_num_stream, out_den_stream, out_num_plane, out_den_plane, out_num, out_den; pipe_data->mode = SUBVP; @@ -762,7 +787,7 @@ static void populate_subvp_cmd_pipe_info(struct dc *dc, for (j = 0; j < dc->res_pool->pipe_count; j++) { struct pipe_ctx *phantom_pipe = &context->res_ctx.pipe_ctx[j]; - if (phantom_pipe->stream == subvp_pipe->stream->mall_stream_config.paired_stream) { + if (phantom_pipe->stream == dc_state_get_paired_subvp_stream(context, subvp_pipe->stream)) { pipe_data->pipe_config.subvp_data.phantom_pipe_index = phantom_pipe->stream_res.tg->inst; if (phantom_pipe->bottom_pipe) { pipe_data->pipe_config.subvp_data.phantom_split_pipe_index = phantom_pipe->bottom_pipe->plane_res.hubp->inst; @@ -796,6 +821,7 @@ void dc_dmub_setup_subvp_dmub_command(struct dc *dc, union dmub_rb_cmd cmd; struct pipe_ctx *subvp_pipes[2]; uint32_t wm_val_refclk = 0; + enum mall_stream_type pipe_mall_type; memset(&cmd, 0, sizeof(cmd)); // FW command for SUBVP @@ -811,7 +837,7 @@ void dc_dmub_setup_subvp_dmub_command(struct dc *dc, */ if (resource_is_pipe_type(pipe, OTG_MASTER) && resource_is_pipe_type(pipe, DPP_PIPE) && - pipe->stream->mall_stream_config.type == SUBVP_MAIN) + dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_MAIN) subvp_pipes[subvp_count++] = pipe; } @@ -819,6 +845,7 @@ void dc_dmub_setup_subvp_dmub_command(struct dc *dc, // For each pipe that is a "main" SUBVP pipe, fill in pipe data for DMUB SUBVP cmd for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + pipe_mall_type = dc_state_get_pipe_subvp_type(context, pipe); if (!pipe->stream) continue; @@ -829,12 +856,11 @@ void dc_dmub_setup_subvp_dmub_command(struct dc *dc, */ if (resource_is_pipe_type(pipe, OTG_MASTER) && resource_is_pipe_type(pipe, DPP_PIPE) && - pipe->stream->mall_stream_config.paired_stream && - pipe->stream->mall_stream_config.type == SUBVP_MAIN) { + pipe_mall_type == SUBVP_MAIN) { populate_subvp_cmd_pipe_info(dc, context, &cmd, pipe, cmd_pipe_index++); } else if (resource_is_pipe_type(pipe, OTG_MASTER) && resource_is_pipe_type(pipe, DPP_PIPE) && - pipe->stream->mall_stream_config.type == SUBVP_NONE) { + pipe_mall_type == SUBVP_NONE) { // Don't need to check for ActiveDRAMClockChangeMargin < 0, not valid in cases where // we run through DML without calculating "natural" P-state support populate_subvp_cmd_vblank_pipe_info(dc, context, &cmd, pipe, cmd_pipe_index++); @@ -856,7 +882,7 @@ void dc_dmub_setup_subvp_dmub_command(struct dc *dc, cmd.fw_assisted_mclk_switch_v2.config_data.watermark_a_cache = wm_val_refclk < 0xFFFF ? wm_val_refclk : 0xFFFF; } - dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); } bool dc_dmub_srv_get_diagnostic_data(struct dc_dmub_srv *dc_dmub_srv, struct dmub_diagnostic_data *diag_data) @@ -1093,7 +1119,7 @@ void dc_send_update_cursor_info_to_dmu( pipe_idx, pCtx->plane_res.hubp, pCtx->plane_res.dpp); /* Combine 2nd cmds update_curosr_info to DMU */ - dm_execute_dmub_cmd_list(pCtx->stream->ctx, 2, cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd_list(pCtx->stream->ctx, 2, cmd, DM_DMUB_WAIT_TYPE_WAIT); } } @@ -1107,25 +1133,20 @@ bool dc_dmub_check_min_version(struct dmub_srv *srv) void dc_dmub_srv_enable_dpia_trace(const struct dc *dc) { struct dc_dmub_srv *dc_dmub_srv = dc->ctx->dmub_srv; - struct dmub_srv *dmub; - enum dmub_status status; - static const uint32_t timeout_us = 30; if (!dc_dmub_srv || !dc_dmub_srv->dmub) { DC_LOG_ERROR("%s: invalid parameters.", __func__); return; } - dmub = dc_dmub_srv->dmub; - - status = dmub_srv_send_gpint_command(dmub, DMUB_GPINT__SET_TRACE_BUFFER_MASK_WORD1, 0x0010, timeout_us); - if (status != DMUB_STATUS_OK) { + if (!dc_wake_and_execute_gpint(dc->ctx, DMUB_GPINT__SET_TRACE_BUFFER_MASK_WORD1, + 0x0010, NULL, DM_DMUB_WAIT_TYPE_WAIT)) { DC_LOG_ERROR("timeout updating trace buffer mask word\n"); return; } - status = dmub_srv_send_gpint_command(dmub, DMUB_GPINT__UPDATE_TRACE_BUFFER_MASK, 0x0000, timeout_us); - if (status != DMUB_STATUS_OK) { + if (!dc_wake_and_execute_gpint(dc->ctx, DMUB_GPINT__UPDATE_TRACE_BUFFER_MASK, + 0x0000, NULL, DM_DMUB_WAIT_TYPE_WAIT)) { DC_LOG_ERROR("timeout updating trace buffer mask word\n"); return; } @@ -1143,14 +1164,23 @@ bool dc_dmub_srv_is_hw_pwr_up(struct dc_dmub_srv *dc_dmub_srv, bool wait) struct dc_context *dc_ctx = dc_dmub_srv->ctx; enum dmub_status status; + if (!dc_dmub_srv || !dc_dmub_srv->dmub) + return true; + if (dc_dmub_srv->ctx->dc->debug.dmcub_emulation) return true; if (wait) { - status = dmub_srv_wait_for_hw_pwr_up(dc_dmub_srv->dmub, 500000); - if (status != DMUB_STATUS_OK) { - DC_ERROR("Error querying DMUB hw power up status: error=%d\n", status); - return false; + if (dc_dmub_srv->ctx->dc->debug.disable_timeout) { + do { + status = dmub_srv_wait_for_hw_pwr_up(dc_dmub_srv->dmub, 500000); + } while (status != DMUB_STATUS_OK); + } else { + status = dmub_srv_wait_for_hw_pwr_up(dc_dmub_srv->dmub, 500000); + if (status != DMUB_STATUS_OK) { + DC_ERROR("Error querying DMUB hw power up status: error=%d\n", status); + return false; + } } } else return dmub_srv_is_hw_pwr_up(dc_dmub_srv->dmub); @@ -1158,7 +1188,7 @@ bool dc_dmub_srv_is_hw_pwr_up(struct dc_dmub_srv *dc_dmub_srv, bool wait) return true; } -void dc_dmub_srv_notify_idle(const struct dc *dc, bool allow_idle) +static void dc_dmub_srv_notify_idle(const struct dc *dc, bool allow_idle) { union dmub_rb_cmd cmd = {0}; @@ -1179,20 +1209,20 @@ void dc_dmub_srv_notify_idle(const struct dc *dc, bool allow_idle) dc->hwss.set_idle_state(dc, true); } - dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + /* NOTE: This does not use the "wake" interface since this is part of the wake path. */ + /* We also do not perform a wait since DMCUB could enter idle after the notification. */ + dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT); } -void dc_dmub_srv_exit_low_power_state(const struct dc *dc) +static void dc_dmub_srv_exit_low_power_state(const struct dc *dc) { - const uint32_t max_num_polls = 10000; uint32_t allow_state = 0; uint32_t commit_state = 0; - uint32_t i; if (dc->debug.dmcub_emulation) return; - if (!dc->idle_optimizations_allowed) + if (!dc->ctx->dmub_srv || !dc->ctx->dmub_srv->dmub) return; if (dc->hwss.get_idle_state && @@ -1204,8 +1234,16 @@ void dc_dmub_srv_exit_low_power_state(const struct dc *dc) if (!(allow_state & DMUB_IPS2_ALLOW_MASK)) { // Wait for evaluation time - udelay(dc->debug.ips2_eval_delay_us); - commit_state = dc->hwss.get_idle_state(dc); + for (;;) { + udelay(dc->debug.ips2_eval_delay_us); + commit_state = dc->hwss.get_idle_state(dc); + if (commit_state & DMUB_IPS2_ALLOW_MASK) + break; + + /* allow was still set, retry eval delay */ + dc->hwss.set_idle_state(dc, false); + } + if (!(commit_state & DMUB_IPS2_COMMIT_MASK)) { // Tell PMFW to exit low power state dc->clk_mgr->funcs->exit_low_power_state(dc->clk_mgr); @@ -1214,14 +1252,13 @@ void dc_dmub_srv_exit_low_power_state(const struct dc *dc) udelay(dc->debug.ips2_entry_delay_us); dc->clk_mgr->funcs->exit_low_power_state(dc->clk_mgr); - for (i = 0; i < max_num_polls; ++i) { + for (;;) { commit_state = dc->hwss.get_idle_state(dc); if (commit_state & DMUB_IPS2_COMMIT_MASK) break; udelay(1); } - ASSERT(i < max_num_polls); if (!dc_dmub_srv_is_hw_pwr_up(dc->ctx->dmub_srv, true)) ASSERT(0); @@ -1236,14 +1273,13 @@ void dc_dmub_srv_exit_low_power_state(const struct dc *dc) dc_dmub_srv_notify_idle(dc, false); if (!(allow_state & DMUB_IPS1_ALLOW_MASK)) { - for (i = 0; i < max_num_polls; ++i) { + for (;;) { commit_state = dc->hwss.get_idle_state(dc); if (commit_state & DMUB_IPS1_COMMIT_MASK) break; udelay(1); } - ASSERT(i < max_num_polls); } } @@ -1251,3 +1287,131 @@ void dc_dmub_srv_exit_low_power_state(const struct dc *dc) ASSERT(0); } +void dc_dmub_srv_set_power_state(struct dc_dmub_srv *dc_dmub_srv, enum dc_acpi_cm_power_state powerState) +{ + struct dmub_srv *dmub; + + if (!dc_dmub_srv) + return; + + dmub = dc_dmub_srv->dmub; + + if (powerState == DC_ACPI_CM_POWER_STATE_D0) + dmub_srv_set_power_state(dmub, DMUB_POWER_STATE_D0); + else + dmub_srv_set_power_state(dmub, DMUB_POWER_STATE_D3); +} + +void dc_dmub_srv_apply_idle_power_optimizations(const struct dc *dc, bool allow_idle) +{ + struct dc_dmub_srv *dc_dmub_srv = dc->ctx->dmub_srv; + + if (!dc_dmub_srv || !dc_dmub_srv->dmub) + return; + + if (dc_dmub_srv->idle_allowed == allow_idle) + return; + + /* + * Entering a low power state requires a driver notification. + * Powering up the hardware requires notifying PMFW and DMCUB. + * Clearing the driver idle allow requires a DMCUB command. + * DMCUB commands requires the DMCUB to be powered up and restored. + * + * Exit out early to prevent an infinite loop of DMCUB commands + * triggering exit low power - use software state to track this. + */ + dc_dmub_srv->idle_allowed = allow_idle; + + if (!allow_idle) + dc_dmub_srv_exit_low_power_state(dc); + else + dc_dmub_srv_notify_idle(dc, allow_idle); +} + +bool dc_wake_and_execute_dmub_cmd(const struct dc_context *ctx, union dmub_rb_cmd *cmd, + enum dm_dmub_wait_type wait_type) +{ + return dc_wake_and_execute_dmub_cmd_list(ctx, 1, cmd, wait_type); +} + +bool dc_wake_and_execute_dmub_cmd_list(const struct dc_context *ctx, unsigned int count, + union dmub_rb_cmd *cmd, enum dm_dmub_wait_type wait_type) +{ + struct dc_dmub_srv *dc_dmub_srv = ctx->dmub_srv; + bool result = false, reallow_idle = false; + + if (!dc_dmub_srv || !dc_dmub_srv->dmub) + return false; + + if (count == 0) + return true; + + if (dc_dmub_srv->idle_allowed) { + dc_dmub_srv_apply_idle_power_optimizations(ctx->dc, false); + reallow_idle = true; + } + + /* + * These may have different implementations in DM, so ensure + * that we guide it to the expected helper. + */ + if (count > 1) + result = dm_execute_dmub_cmd_list(ctx, count, cmd, wait_type); + else + result = dm_execute_dmub_cmd(ctx, cmd, wait_type); + + if (result && reallow_idle) + dc_dmub_srv_apply_idle_power_optimizations(ctx->dc, true); + + return result; +} + +static bool dc_dmub_execute_gpint(const struct dc_context *ctx, enum dmub_gpint_command command_code, + uint16_t param, uint32_t *response, enum dm_dmub_wait_type wait_type) +{ + struct dc_dmub_srv *dc_dmub_srv = ctx->dmub_srv; + const uint32_t wait_us = wait_type == DM_DMUB_WAIT_TYPE_NO_WAIT ? 0 : 30; + enum dmub_status status; + + if (response) + *response = 0; + + if (!dc_dmub_srv || !dc_dmub_srv->dmub) + return false; + + status = dmub_srv_send_gpint_command(dc_dmub_srv->dmub, command_code, param, wait_us); + if (status != DMUB_STATUS_OK) { + if (status == DMUB_STATUS_TIMEOUT && wait_type == DM_DMUB_WAIT_TYPE_NO_WAIT) + return true; + + return false; + } + + if (response && wait_type == DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY) + dmub_srv_get_gpint_response(dc_dmub_srv->dmub, response); + + return true; +} + +bool dc_wake_and_execute_gpint(const struct dc_context *ctx, enum dmub_gpint_command command_code, + uint16_t param, uint32_t *response, enum dm_dmub_wait_type wait_type) +{ + struct dc_dmub_srv *dc_dmub_srv = ctx->dmub_srv; + bool result = false, reallow_idle = false; + + if (!dc_dmub_srv || !dc_dmub_srv->dmub) + return false; + + if (dc_dmub_srv->idle_allowed) { + dc_dmub_srv_apply_idle_power_optimizations(ctx->dc, false); + reallow_idle = true; + } + + result = dc_dmub_execute_gpint(ctx, command_code, param, response, wait_type); + + if (result && reallow_idle) + dc_dmub_srv_apply_idle_power_optimizations(ctx->dc, true); + + return result; +} diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h index d4a60f53faab12..952bfb368886e3 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h @@ -50,6 +50,8 @@ struct dc_dmub_srv { struct dc_context *ctx; void *dm; + + bool idle_allowed; }; void dc_dmub_srv_wait_idle(struct dc_dmub_srv *dc_dmub_srv); @@ -100,6 +102,59 @@ void dc_dmub_srv_enable_dpia_trace(const struct dc *dc); void dc_dmub_srv_subvp_save_surf_addr(const struct dc_dmub_srv *dc_dmub_srv, const struct dc_plane_address *addr, uint8_t subvp_index); bool dc_dmub_srv_is_hw_pwr_up(struct dc_dmub_srv *dc_dmub_srv, bool wait); -void dc_dmub_srv_notify_idle(const struct dc *dc, bool allow_idle); -void dc_dmub_srv_exit_low_power_state(const struct dc *dc); + +void dc_dmub_srv_apply_idle_power_optimizations(const struct dc *dc, bool allow_idle); + +void dc_dmub_srv_set_power_state(struct dc_dmub_srv *dc_dmub_srv, enum dc_acpi_cm_power_state powerState); + +/** + * dc_wake_and_execute_dmub_cmd() - Wrapper for DMUB command execution. + * + * Refer to dc_wake_and_execute_dmub_cmd_list() for usage and limitations, + * This function is a convenience wrapper for a single command execution. + * + * @ctx: DC context + * @cmd: The command to send/receive + * @wait_type: The wait behavior for the execution + * + * Return: true on command submission success, false otherwise + */ +bool dc_wake_and_execute_dmub_cmd(const struct dc_context *ctx, union dmub_rb_cmd *cmd, + enum dm_dmub_wait_type wait_type); + +/** + * dc_wake_and_execute_dmub_cmd_list() - Wrapper for DMUB command list execution. + * + * If the DMCUB hardware was asleep then it wakes the DMUB before + * executing the command and attempts to re-enter if the command + * submission was successful. + * + * This should be the preferred command submission interface provided + * the DC lock is acquired. + * + * Entry/exit out of idle power optimizations would need to be + * manually performed otherwise through dc_allow_idle_optimizations(). + * + * @ctx: DC context + * @count: Number of commands to send/receive + * @cmd: Array of commands to send + * @wait_type: The wait behavior for the execution + * + * Return: true on command submission success, false otherwise + */ +bool dc_wake_and_execute_dmub_cmd_list(const struct dc_context *ctx, unsigned int count, + union dmub_rb_cmd *cmd, enum dm_dmub_wait_type wait_type); + +/** + * dc_wake_and_execute_gpint() + * + * @ctx: DC context + * @command_code: The command ID to send to DMCUB + * @param: The parameter to message DMCUB + * @response: Optional response out value - may be NULL. + * @wait_type: The wait behavior for the execution + */ +bool dc_wake_and_execute_gpint(const struct dc_context *ctx, enum dmub_gpint_command command_code, + uint16_t param, uint32_t *response, enum dm_dmub_wait_type wait_type); + #endif /* _DMUB_DC_SRV_H_ */ 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 eeeeeef4d71734..1cb7765f593aa6 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h @@ -1377,6 +1377,12 @@ struct dp_trace { #ifndef DP_TUNNELING_STATUS #define DP_TUNNELING_STATUS 0xE0025 /* 1.4a */ #endif +#ifndef DP_TUNNELING_MAX_LINK_RATE +#define DP_TUNNELING_MAX_LINK_RATE 0xE0028 /* 1.4a */ +#endif +#ifndef DP_TUNNELING_MAX_LANE_COUNT +#define DP_TUNNELING_MAX_LANE_COUNT 0xE0029 /* 1.4a */ +#endif #ifndef DPTX_BW_ALLOCATION_MODE_CONTROL #define DPTX_BW_ALLOCATION_MODE_CONTROL 0xE0030 /* 1.4a */ #endif diff --git a/drivers/gpu/drm/amd/display/dc/dc_helper.c b/drivers/gpu/drm/amd/display/dc/dc_helper.c index cb6eaddab72056..8f9a678256150b 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_helper.c +++ b/drivers/gpu/drm/amd/display/dc/dc_helper.c @@ -50,7 +50,7 @@ static inline void submit_dmub_read_modify_write( cmd_buf->header.payload_bytes = sizeof(struct dmub_cmd_read_modify_write_sequence) * offload->reg_seq_count; - dm_execute_dmub_cmd(ctx, &offload->cmd_data, DM_DMUB_WAIT_TYPE_NO_WAIT); + dc_wake_and_execute_dmub_cmd(ctx, &offload->cmd_data, DM_DMUB_WAIT_TYPE_NO_WAIT); memset(cmd_buf, 0, sizeof(*cmd_buf)); @@ -67,7 +67,7 @@ static inline void submit_dmub_burst_write( cmd_buf->header.payload_bytes = sizeof(uint32_t) * offload->reg_seq_count; - dm_execute_dmub_cmd(ctx, &offload->cmd_data, DM_DMUB_WAIT_TYPE_NO_WAIT); + dc_wake_and_execute_dmub_cmd(ctx, &offload->cmd_data, DM_DMUB_WAIT_TYPE_NO_WAIT); memset(cmd_buf, 0, sizeof(*cmd_buf)); @@ -80,7 +80,7 @@ static inline void submit_dmub_reg_wait( { struct dmub_rb_cmd_reg_wait *cmd_buf = &offload->cmd_data.reg_wait; - dm_execute_dmub_cmd(ctx, &offload->cmd_data, DM_DMUB_WAIT_TYPE_NO_WAIT); + dc_wake_and_execute_dmub_cmd(ctx, &offload->cmd_data, DM_DMUB_WAIT_TYPE_NO_WAIT); memset(cmd_buf, 0, sizeof(*cmd_buf)); offload->reg_seq_count = 0; 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 e2a3aa8812df49..811474f4419bd2 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h @@ -244,7 +244,7 @@ enum pixel_format { #define DC_MAX_DIRTY_RECTS 3 struct dc_flip_addrs { struct dc_plane_address address; - unsigned int flip_timestamp_in_us; + unsigned long long flip_timestamp_in_us; bool flip_immediate; /* TODO: add flip duration for FreeSync */ bool triplebuffer_flips; diff --git a/drivers/gpu/drm/amd/display/dc/dc_plane.h b/drivers/gpu/drm/amd/display/dc/dc_plane.h new file mode 100644 index 00000000000000..ef380cae816a31 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dc_plane.h @@ -0,0 +1,38 @@ +/* + * 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_PLANE_H_ +#define _DC_PLANE_H_ + +#include "dc.h" +#include "dc_hw_types.h" + +struct dc_plane_state *dc_create_plane_state(struct dc *dc); +const struct dc_plane_status *dc_plane_get_status( + const struct dc_plane_state *plane_state); +void dc_plane_state_retain(struct dc_plane_state *plane_state); +void dc_plane_state_release(struct dc_plane_state *plane_state); + +#endif /* _DC_PLANE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dc_plane_priv.h b/drivers/gpu/drm/amd/display/dc/dc_plane_priv.h new file mode 100644 index 00000000000000..9ee184c1df0070 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dc_plane_priv.h @@ -0,0 +1,34 @@ +/* + * 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_PLANE_PRIV_H_ +#define _DC_PLANE_PRIV_H_ + +#include "dc_plane.h" + +void dc_plane_construct(struct dc_context *ctx, struct dc_plane_state *plane_state); +void dc_plane_destruct(struct dc_plane_state *plane_state); + +#endif /* _DC_PLANE_PRIV_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dc_state.h b/drivers/gpu/drm/amd/display/dc/dc_state.h new file mode 100644 index 00000000000000..d167fdbfa8a970 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dc_state.h @@ -0,0 +1,78 @@ +/* + * 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_STATE_H_ +#define _DC_STATE_H_ + +#include "dc.h" +#include "inc/core_status.h" + +struct dc_state *dc_state_create(struct dc *dc); +void dc_state_copy(struct dc_state *dst_state, struct dc_state *src_state); +struct dc_state *dc_state_create_copy(struct dc_state *src_state); +void dc_state_copy_current(struct dc *dc, struct dc_state *dst_state); +struct dc_state *dc_state_create_current_copy(struct dc *dc); +void dc_state_construct(struct dc *dc, struct dc_state *state); +void dc_state_destruct(struct dc_state *state); +void dc_state_retain(struct dc_state *state); +void dc_state_release(struct dc_state *state); + +enum dc_status dc_state_add_stream(struct dc *dc, + struct dc_state *state, + struct dc_stream_state *stream); + +enum dc_status dc_state_remove_stream( + struct dc *dc, + struct dc_state *state, + struct dc_stream_state *stream); + +bool dc_state_add_plane( + const struct dc *dc, + struct dc_stream_state *stream, + struct dc_plane_state *plane_state, + struct dc_state *state); + +bool dc_state_remove_plane( + const struct dc *dc, + struct dc_stream_state *stream, + struct dc_plane_state *plane_state, + struct dc_state *state); + +bool dc_state_rem_all_planes_for_stream( + const struct dc *dc, + struct dc_stream_state *stream, + struct dc_state *state); + +bool dc_state_add_all_planes_for_stream( + const struct dc *dc, + struct dc_stream_state *stream, + struct dc_plane_state * const *plane_states, + int plane_count, + struct dc_state *state); + +struct dc_stream_status *dc_state_get_stream_status( + struct dc_state *state, + struct dc_stream_state *stream); +#endif /* _DC_STATE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dc_state_priv.h b/drivers/gpu/drm/amd/display/dc/dc_state_priv.h new file mode 100644 index 00000000000000..c1f44e09a6c1bf --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dc_state_priv.h @@ -0,0 +1,102 @@ +/* + * 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_STATE_PRIV_H_ +#define _DC_STATE_PRIV_H_ + +#include "dc_state.h" +#include "dc_stream.h" + +/* Get the type of the provided resource (none, phantom, main) based on the provided + * context. If the context is unavailable, determine only if phantom or not. + */ +enum mall_stream_type dc_state_get_pipe_subvp_type(const struct dc_state *state, + const struct pipe_ctx *pipe_ctx); +enum mall_stream_type dc_state_get_stream_subvp_type(const struct dc_state *state, + const struct dc_stream_state *stream); + +/* Gets the phantom stream if main is provided, gets the main if phantom is provided.*/ +struct dc_stream_state *dc_state_get_paired_subvp_stream(const struct dc_state *state, + const struct dc_stream_state *stream); + +/* allocate's phantom stream or plane and returns pointer to the object */ +struct dc_stream_state *dc_state_create_phantom_stream(const struct dc *dc, + struct dc_state *state, + struct dc_stream_state *main_stream); +struct dc_plane_state *dc_state_create_phantom_plane(struct dc *dc, + struct dc_state *state, + struct dc_plane_state *main_plane); + +/* deallocate's phantom stream or plane */ +void dc_state_release_phantom_stream(const struct dc *dc, + struct dc_state *state, + struct dc_stream_state *phantom_stream); +void dc_state_release_phantom_plane(const struct dc *dc, + struct dc_state *state, + struct dc_plane_state *phantom_plane); + +/* add/remove phantom stream to context and generate subvp meta data */ +enum dc_status dc_state_add_phantom_stream(struct dc *dc, + struct dc_state *state, + struct dc_stream_state *phantom_stream, + struct dc_stream_state *main_stream); +enum dc_status dc_state_remove_phantom_stream(struct dc *dc, + struct dc_state *state, + struct dc_stream_state *phantom_stream); + +bool dc_state_add_phantom_plane( + const struct dc *dc, + struct dc_stream_state *phantom_stream, + struct dc_plane_state *phantom_plane, + struct dc_state *state); + +bool dc_state_remove_phantom_plane( + const struct dc *dc, + struct dc_stream_state *phantom_stream, + struct dc_plane_state *phantom_plane, + struct dc_state *state); + +bool dc_state_rem_all_phantom_planes_for_stream( + const struct dc *dc, + struct dc_stream_state *phantom_stream, + struct dc_state *state, + bool should_release_planes); + +bool dc_state_add_all_phantom_planes_for_stream( + const struct dc *dc, + struct dc_stream_state *phantom_stream, + struct dc_plane_state * const *phantom_planes, + int plane_count, + struct dc_state *state); + +bool dc_state_remove_phantom_streams_and_planes( + struct dc *dc, + struct dc_state *state); + +void dc_state_release_phantom_streams_and_planes( + struct dc *dc, + struct dc_state *state); + +#endif /* _DC_STATE_PRIV_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index e61eea6db29cd5..ee10941caa5980 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -38,6 +38,14 @@ struct timing_sync_info { bool master; }; +struct mall_stream_config { + /* MALL stream config to indicate if the stream is phantom or not. + * We will use a phantom stream to indicate that the pipe is phantom. + */ + enum mall_stream_type type; + struct dc_stream_state *paired_stream; // master / slave stream +}; + struct dc_stream_status { int primary_otg_inst; int stream_enc_inst; @@ -50,6 +58,7 @@ struct dc_stream_status { struct timing_sync_info timing_sync_info; struct dc_plane_state *plane_states[MAX_SURFACE_NUM]; bool is_abm_supported; + struct mall_stream_config mall_stream_config; }; enum hubp_dmdata_mode { @@ -147,31 +156,6 @@ struct test_pattern { #define SUBVP_DRR_MARGIN_US 100 // 100us for DRR margin (SubVP + DRR) -enum mall_stream_type { - SUBVP_NONE, // subvp not in use - SUBVP_MAIN, // subvp in use, this stream is main stream - SUBVP_PHANTOM, // subvp in use, this stream is a phantom stream -}; - -struct mall_stream_config { - /* MALL stream config to indicate if the stream is phantom or not. - * We will use a phantom stream to indicate that the pipe is phantom. - */ - enum mall_stream_type type; - struct dc_stream_state *paired_stream; // master / slave stream -}; - -/* Temp struct used to save and restore MALL config - * during validation. - * - * TODO: Move MALL config into dc_state instead of stream struct - * to avoid needing to save/restore. - */ -struct mall_temp_config { - struct mall_stream_config mall_stream_config[MAX_PIPES]; - bool is_phantom_plane[MAX_PIPES]; -}; - struct dc_stream_debug_options { char force_odm_combine_segments; }; @@ -301,7 +285,7 @@ struct dc_stream_state { bool has_non_synchronizable_pclk; bool vblank_synchronized; bool fpo_in_use; - struct mall_stream_config mall_stream_config; + bool is_phantom; }; #define ABM_LEVEL_IMMEDIATE_DISABLE 255 @@ -415,45 +399,14 @@ bool dc_stream_get_scanoutpos(const struct dc_stream_state *stream, uint32_t *h_position, uint32_t *v_position); -enum dc_status dc_add_stream_to_ctx( - struct dc *dc, - struct dc_state *new_ctx, - struct dc_stream_state *stream); - -enum dc_status dc_remove_stream_from_ctx( - struct dc *dc, - struct dc_state *new_ctx, - struct dc_stream_state *stream); - - -bool dc_add_plane_to_context( - const struct dc *dc, - struct dc_stream_state *stream, - struct dc_plane_state *plane_state, - struct dc_state *context); - -bool dc_remove_plane_from_context( - const struct dc *dc, - struct dc_stream_state *stream, - struct dc_plane_state *plane_state, - struct dc_state *context); - -bool dc_rem_all_planes_for_stream( - const struct dc *dc, - struct dc_stream_state *stream, - struct dc_state *context); - -bool dc_add_all_planes_for_stream( - const struct dc *dc, - struct dc_stream_state *stream, - struct dc_plane_state * const *plane_states, - int plane_count, - struct dc_state *context); - bool dc_stream_add_writeback(struct dc *dc, struct dc_stream_state *stream, struct dc_writeback_info *wb_info); +bool dc_stream_fc_disable_writeback(struct dc *dc, + struct dc_stream_state *stream, + uint32_t dwb_pipe_inst); + bool dc_stream_remove_writeback(struct dc *dc, struct dc_stream_state *stream, uint32_t dwb_pipe_inst); @@ -514,9 +467,6 @@ void update_stream_signal(struct dc_stream_state *stream, struct dc_sink *sink); void dc_stream_retain(struct dc_stream_state *dc_stream); void dc_stream_release(struct dc_stream_state *dc_stream); -struct dc_stream_status *dc_stream_get_status_from_state( - struct dc_state *state, - struct dc_stream_state *stream); struct dc_stream_status *dc_stream_get_status( struct dc_stream_state *dc_stream); diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream_priv.h b/drivers/gpu/drm/amd/display/dc/dc_stream_priv.h new file mode 100644 index 00000000000000..7476fd52ce2b55 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dc_stream_priv.h @@ -0,0 +1,37 @@ +/* + * 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_STREAM_PRIV_H_ +#define _DC_STREAM_PRIV_H_ + +#include "dc_stream.h" + +bool dc_stream_construct(struct dc_stream_state *stream, + struct dc_sink *dc_sink_data); +void dc_stream_destruct(struct dc_stream_state *stream); + +void dc_stream_assign_stream_id(struct dc_stream_state *stream); + +#endif // _DC_STREAM_PRIV_H_ diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index 35d146217aef0f..9900dda2eef5cd 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -1018,6 +1018,25 @@ enum replay_coasting_vtotal_type { PR_COASTING_TYPE_NUM, }; +enum replay_link_off_frame_count_level { + PR_LINK_OFF_FRAME_COUNT_FAIL = 0x0, + PR_LINK_OFF_FRAME_COUNT_GOOD = 0x2, + PR_LINK_OFF_FRAME_COUNT_BEST = 0x6, +}; + +/* + * This is general Interface for Replay to + * set an 32 bit variable to dmub + * The Message_type indicates which variable + * passed to DMUB. + */ +enum replay_FW_Message_type { + Replay_Msg_Not_Support = -1, + Replay_Set_Timing_Sync_Supported, + Replay_Set_Residency_Frameupdate_Timer, + Replay_Set_Pseudo_VTotal, +}; + union replay_error_status { struct { unsigned char STATE_TRANSITION_ERROR :1; @@ -1029,26 +1048,52 @@ union replay_error_status { }; struct replay_config { - bool replay_supported; // Replay feature is supported - unsigned int replay_power_opt_supported; // Power opt flags that are supported - bool replay_smu_opt_supported; // SMU optimization is supported - unsigned int replay_enable_option; // Replay enablement option - uint32_t debug_flags; // Replay debug flags - bool replay_timing_sync_supported; // Replay desync is supported - bool force_disable_desync_error_check; // Replay desync is supported - bool received_desync_error_hpd; //Replay Received Desync Error HPD. - union replay_error_status replay_error_status; // Replay error status -}; - -/* Replay feature flags */ + /* Replay feature is supported */ + bool replay_supported; + /* Power opt flags that are supported */ + unsigned int replay_power_opt_supported; + /* SMU optimization is supported */ + bool replay_smu_opt_supported; + /* Replay enablement option */ + unsigned int replay_enable_option; + /* Replay debug flags */ + uint32_t debug_flags; + /* Replay sync is supported */ + bool replay_timing_sync_supported; + /* Replay Disable desync error check. */ + bool force_disable_desync_error_check; + /* Replay Received Desync Error HPD. */ + bool received_desync_error_hpd; + /* Replay feature is supported long vblank */ + bool replay_support_fast_resync_in_ultra_sleep_mode; + /* Replay error status */ + union replay_error_status replay_error_status; +}; + +/* Replay feature flags*/ struct replay_settings { - struct replay_config config; // Replay configuration - bool replay_feature_enabled; // Replay feature is ready for activating - bool replay_allow_active; // Replay is currently active - unsigned int replay_power_opt_active; // Power opt flags that are activated currently - bool replay_smu_opt_enable; // SMU optimization is enabled - uint16_t coasting_vtotal; // Current Coasting vtotal - uint16_t coasting_vtotal_table[PR_COASTING_TYPE_NUM]; // Coasting vtotal table + /* Replay configuration */ + struct replay_config config; + /* Replay feature is ready for activating */ + bool replay_feature_enabled; + /* Replay is currently active */ + bool replay_allow_active; + /* Replay is currently active */ + bool replay_allow_long_vblank; + /* Power opt flags that are activated currently */ + unsigned int replay_power_opt_active; + /* SMU optimization is enabled */ + bool replay_smu_opt_enable; + /* Current Coasting vtotal */ + uint16_t coasting_vtotal; + /* Coasting vtotal table */ + uint16_t coasting_vtotal_table[PR_COASTING_TYPE_NUM]; + /* Maximum link off frame count */ + enum replay_link_off_frame_count_level link_off_frame_count_level; + /* Replay pseudo vtotal for abm + ips on full screen video which can improve ips residency */ + uint16_t abm_with_ips_on_full_screen_video_pseudo_vtotal; + /* Replay last pseudo vtotal set to DMUB */ + uint16_t last_pseudo_vtotal; }; /* To split out "global" and "per-panel" config settings. @@ -1100,25 +1145,34 @@ struct dc_panel_config { } ilr; }; +#define MAX_SINKS_PER_LINK 4 + /* * USB4 DPIA BW ALLOCATION STRUCTS */ 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 sink_max_bw; // The Max BW that sink can require/support + int remote_sink_req_bw[MAX_SINKS_PER_LINK]; // BW requested by remote sinks + int link_verified_bw; // The Verified BW that link can allocated and use that has been verified already + int link_max_bw; // The Max BW that link can require/support + int allocated_bw; // The Actual Allocated BW for this DPIA int estimated_bw; // The estimated available BW for this DPIA int bw_granularity; // BW Granularity + int dp_overhead; // DP overhead in dp tunneling 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 + uint8_t nrd_max_lane_count; // Non-reduced max lane count + uint8_t nrd_max_link_rate; // Non-reduced max link rate }; -#define MAX_SINKS_PER_LINK 4 - enum dc_hpd_enable_select { HPD_EN_FOR_ALL_EDP = 0, HPD_EN_FOR_PRIMARY_EDP_ONLY, HPD_EN_FOR_SECONDARY_EDP_ONLY, }; +enum mall_stream_type { + SUBVP_NONE, // subvp not in use + SUBVP_MAIN, // subvp in use, this stream is main stream + SUBVP_PHANTOM, // subvp in use, this stream is a phantom stream +}; #endif /* DC_TYPES_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c b/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c index 874b132fe1d782..a6006776333d12 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_abm.c @@ -135,7 +135,7 @@ static void dmcu_set_backlight_level( 0, 1, 80000); } -static void dce_abm_init(struct abm *abm, uint32_t backlight) +static void dce_abm_init(struct abm *abm, uint32_t backlight, uint32_t user_level) { struct dce_abm *abm_dce = TO_DCE_ABM(abm); @@ -162,7 +162,7 @@ static void dce_abm_init(struct abm *abm, uint32_t backlight) BL1_PWM_TARGET_ABM_LEVEL, backlight); REG_UPDATE(BL1_PWM_USER_LEVEL, - BL1_PWM_USER_LEVEL, backlight); + BL1_PWM_USER_LEVEL, user_level); REG_UPDATE_2(DC_ABM1_LS_MIN_MAX_PIXEL_VALUE_THRES, ABM1_LS_MIN_PIXEL_VALUE_THRES, 0, diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c b/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c index 140598f18bbdd4..f0458b8f00af84 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_audio.c @@ -782,7 +782,7 @@ static void get_azalia_clock_info_dp( /*audio_dto_module = dpDtoSourceClockInkhz * 10,000; * [khz] ->[100Hz] */ azalia_clock_info->audio_dto_module = - pll_info->dp_dto_source_clock_in_khz * 10; + pll_info->audio_dto_source_clock_in_khz * 10; } void dce_aud_wall_dto_setup( diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c index 5d3f6fa1011e8e..970644b695cd4f 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c @@ -975,6 +975,9 @@ static bool dcn31_program_pix_clk( look_up_in_video_optimized_rate_tlb(pix_clk_params->requested_pix_clk_100hz / 10); struct bp_pixel_clock_parameters bp_pc_params = {0}; enum transmitter_color_depth bp_pc_colour_depth = TRANSMITTER_COLOR_DEPTH_24; + + if (clock_source->ctx->dc->clk_mgr->dp_dto_source_clock_in_khz != 0) + dp_dto_ref_khz = clock_source->ctx->dc->clk_mgr->dp_dto_source_clock_in_khz; // For these signal types Driver to program DP_DTO without calling VBIOS Command table if (dc_is_dp_signal(pix_clk_params->signal_type) || dc_is_virtual_signal(pix_clk_params->signal_type)) { if (e) { @@ -1088,6 +1091,10 @@ static bool get_pixel_clk_frequency_100hz( struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source); unsigned int clock_hz = 0; unsigned int modulo_hz = 0; + unsigned int dp_dto_ref_khz = clock_source->ctx->dc->clk_mgr->dprefclk_khz; + + if (clock_source->ctx->dc->clk_mgr->dp_dto_source_clock_in_khz != 0) + dp_dto_ref_khz = clock_source->ctx->dc->clk_mgr->dp_dto_source_clock_in_khz; if (clock_source->id == CLOCK_SOURCE_ID_DP_DTO) { clock_hz = REG_READ(PHASE[inst]); @@ -1100,7 +1107,7 @@ static bool get_pixel_clk_frequency_100hz( modulo_hz = REG_READ(MODULO[inst]); if (modulo_hz) *pixel_clk_khz = div_u64((uint64_t)clock_hz* - clock_source->ctx->dc->clk_mgr->dprefclk_khz*10, + dp_dto_ref_khz*10, modulo_hz); else *pixel_clk_khz = 0; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c index d3e6544022b787..ccc154b0281c2c 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm.c @@ -57,18 +57,22 @@ static unsigned int abm_feature_support(struct abm *abm, unsigned int panel_inst return ret; } -static void dmub_abm_init_ex(struct abm *abm, uint32_t backlight) +static void dmub_abm_init_ex(struct abm *abm, uint32_t backlight, uint32_t user_level) { - dmub_abm_init(abm, backlight); + dmub_abm_init(abm, backlight, user_level); } static unsigned int dmub_abm_get_current_backlight_ex(struct abm *abm) { + dc_allow_idle_optimizations(abm->ctx->dc, false); + return dmub_abm_get_current_backlight(abm); } static unsigned int dmub_abm_get_target_backlight_ex(struct abm *abm) { + dc_allow_idle_optimizations(abm->ctx->dc, false); + return dmub_abm_get_target_backlight(abm); } @@ -145,7 +149,11 @@ static bool dmub_abm_save_restore_ex( return ret; } -static bool dmub_abm_set_pipe_ex(struct abm *abm, uint32_t otg_inst, uint32_t option, uint32_t panel_inst) +static bool dmub_abm_set_pipe_ex(struct abm *abm, + uint32_t otg_inst, + uint32_t option, + uint32_t panel_inst, + uint32_t pwrseq_inst) { bool ret = false; unsigned int feature_support; @@ -153,7 +161,7 @@ static bool dmub_abm_set_pipe_ex(struct abm *abm, uint32_t otg_inst, uint32_t op feature_support = abm_feature_support(abm, panel_inst); if (feature_support == ABM_LCD_SUPPORT) - ret = dmub_abm_set_pipe(abm, otg_inst, option, panel_inst); + ret = dmub_abm_set_pipe(abm, otg_inst, option, panel_inst, pwrseq_inst); return ret; } diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.c index 592a8f7a1c6d00..f9d6a181164aac 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.c @@ -76,10 +76,10 @@ static void dmub_abm_enable_fractional_pwm(struct dc_context *dc) cmd.abm_set_pwm_frac.abm_set_pwm_frac_data.panel_mask = panel_mask; cmd.abm_set_pwm_frac.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_pwm_frac_data); - dm_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); } -void dmub_abm_init(struct abm *abm, uint32_t backlight) +void dmub_abm_init(struct abm *abm, uint32_t backlight, uint32_t user_level) { struct dce_abm *dce_abm = TO_DMUB_ABM(abm); @@ -106,7 +106,7 @@ void dmub_abm_init(struct abm *abm, uint32_t backlight) BL1_PWM_TARGET_ABM_LEVEL, backlight); REG_UPDATE(BL1_PWM_USER_LEVEL, - BL1_PWM_USER_LEVEL, backlight); + BL1_PWM_USER_LEVEL, user_level); REG_UPDATE_2(DC_ABM1_LS_MIN_MAX_PIXEL_VALUE_THRES, ABM1_LS_MIN_PIXEL_VALUE_THRES, 0, @@ -155,7 +155,7 @@ bool dmub_abm_set_level(struct abm *abm, uint32_t level, uint8_t panel_mask) cmd.abm_set_level.abm_set_level_data.panel_mask = panel_mask; cmd.abm_set_level.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_level_data); - dm_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); return true; } @@ -186,7 +186,7 @@ void dmub_abm_init_config(struct abm *abm, cmd.abm_init_config.header.payload_bytes = sizeof(struct dmub_cmd_abm_init_config_data); - dm_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); } @@ -203,7 +203,7 @@ bool dmub_abm_set_pause(struct abm *abm, bool pause, unsigned int panel_inst, un cmd.abm_pause.abm_pause_data.panel_mask = panel_mask; cmd.abm_set_level.header.payload_bytes = sizeof(struct dmub_cmd_abm_pause_data); - dm_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); return true; } @@ -246,7 +246,7 @@ bool dmub_abm_save_restore( cmd.abm_save_restore.header.payload_bytes = sizeof(struct dmub_rb_cmd_abm_save_restore); - dm_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); // Copy iramtable data into local structure memcpy((void *)pData, dc->dmub_srv->dmub->scratch_mem_fb.cpu_addr, bytes); @@ -254,7 +254,11 @@ bool dmub_abm_save_restore( return true; } -bool dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, uint32_t option, uint32_t panel_inst) +bool dmub_abm_set_pipe(struct abm *abm, + uint32_t otg_inst, + uint32_t option, + uint32_t panel_inst, + uint32_t pwrseq_inst) { union dmub_rb_cmd cmd; struct dc_context *dc = abm->ctx; @@ -264,12 +268,13 @@ bool dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, uint32_t option, uint cmd.abm_set_pipe.header.type = DMUB_CMD__ABM; cmd.abm_set_pipe.header.sub_type = DMUB_CMD__ABM_SET_PIPE; cmd.abm_set_pipe.abm_set_pipe_data.otg_inst = otg_inst; + cmd.abm_set_pipe.abm_set_pipe_data.pwrseq_inst = pwrseq_inst; cmd.abm_set_pipe.abm_set_pipe_data.set_pipe_option = option; cmd.abm_set_pipe.abm_set_pipe_data.panel_inst = panel_inst; cmd.abm_set_pipe.abm_set_pipe_data.ramping_boundary = ramping_boundary; cmd.abm_set_pipe.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_pipe_data); - dm_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); return true; } @@ -291,7 +296,7 @@ bool dmub_abm_set_backlight_level(struct abm *abm, cmd.abm_set_backlight.abm_set_backlight_data.panel_mask = (0x01 << panel_inst); cmd.abm_set_backlight.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_backlight_data); - dm_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); return true; } diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.h b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.h index 853564d7f4714c..761685e5b8c91e 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_abm_lcd.h @@ -30,7 +30,7 @@ struct abm_save_restore; -void dmub_abm_init(struct abm *abm, uint32_t backlight); +void dmub_abm_init(struct abm *abm, uint32_t backlight, uint32_t user_level); bool dmub_abm_set_level(struct abm *abm, uint32_t level, uint8_t panel_mask); unsigned int dmub_abm_get_current_backlight(struct abm *abm); unsigned int dmub_abm_get_target_backlight(struct abm *abm); @@ -44,7 +44,7 @@ bool dmub_abm_save_restore( struct dc_context *dc, unsigned int panel_inst, struct abm_save_restore *pData); -bool dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, uint32_t option, uint32_t panel_inst); +bool dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, uint32_t option, uint32_t panel_inst, uint32_t pwrseq_inst); bool dmub_abm_set_backlight_level(struct abm *abm, unsigned int backlight_pwm_u16_16, unsigned int frame_ramp, diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.c index 2aa0e01a6891b0..ba1fec3016d5ba 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_hw_lock_mgr.c @@ -47,7 +47,7 @@ void dmub_hw_lock_mgr_cmd(struct dc_dmub_srv *dmub_srv, if (!lock) cmd.lock_hw.lock_hw_data.should_release = 1; - dm_execute_dmub_cmd(dmub_srv->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dmub_srv->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); } void dmub_hw_lock_mgr_inbox0_cmd(struct dc_dmub_srv *dmub_srv, diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_outbox.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_outbox.c index d8009b2dc56a06..98a778996e1a91 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_outbox.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_outbox.c @@ -48,5 +48,5 @@ void dmub_enable_outbox_notification(struct dc_dmub_srv *dmub_srv) sizeof(cmd.outbox1_enable.header); cmd.outbox1_enable.enable = true; - dm_execute_dmub_cmd(dmub_srv->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dmub_srv->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); } 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 9d4170a356a207..3e243e407bb87e 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c @@ -105,23 +105,18 @@ static enum dc_psr_state convert_psr_state(uint32_t raw_state) */ static void dmub_psr_get_state(struct dmub_psr *dmub, enum dc_psr_state *state, uint8_t panel_inst) { - struct dmub_srv *srv = dmub->ctx->dmub_srv->dmub; uint32_t raw_state = 0; uint32_t retry_count = 0; - enum dmub_status status; do { // Send gpint command and wait for ack - status = dmub_srv_send_gpint_command(srv, DMUB_GPINT__GET_PSR_STATE, panel_inst, 30); - - if (status == DMUB_STATUS_OK) { - // GPINT was executed, get response - dmub_srv_get_gpint_response(srv, &raw_state); + if (dc_wake_and_execute_gpint(dmub->ctx, DMUB_GPINT__GET_PSR_STATE, panel_inst, &raw_state, + DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) { *state = convert_psr_state(raw_state); - } else + } else { // Return invalid state when GPINT times out *state = PSR_STATE_INVALID; - + } } while (++retry_count <= 1000 && *state == PSR_STATE_INVALID); // Assert if max retry hit @@ -171,7 +166,7 @@ static bool dmub_psr_set_version(struct dmub_psr *dmub, struct dc_stream_state * cmd.psr_set_version.psr_set_version_data.panel_inst = panel_inst; cmd.psr_set_version.header.payload_bytes = sizeof(struct dmub_cmd_psr_set_version_data); - dm_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); return true; } @@ -199,7 +194,7 @@ static void dmub_psr_enable(struct dmub_psr *dmub, bool enable, bool wait, uint8 cmd.psr_enable.header.payload_bytes = 0; // Send header only - dm_execute_dmub_cmd(dc->dmub_srv->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dc->dmub_srv->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); /* Below loops 1000 x 500us = 500 ms. * Exit PSR may need to wait 1-2 frames to power up. Timeout after at @@ -248,7 +243,7 @@ static void dmub_psr_set_level(struct dmub_psr *dmub, uint16_t psr_level, uint8_ cmd.psr_set_level.psr_set_level_data.psr_level = psr_level; cmd.psr_set_level.psr_set_level_data.cmd_version = DMUB_CMD_PSR_CONTROL_VERSION_1; cmd.psr_set_level.psr_set_level_data.panel_inst = panel_inst; - dm_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); } /* @@ -267,7 +262,7 @@ static void dmub_psr_set_sink_vtotal_in_psr_active(struct dmub_psr *dmub, cmd.psr_set_vtotal.psr_set_vtotal_data.psr_vtotal_idle = psr_vtotal_idle; cmd.psr_set_vtotal.psr_set_vtotal_data.psr_vtotal_su = psr_vtotal_su; - dm_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); } /* @@ -286,7 +281,7 @@ static void dmub_psr_set_power_opt(struct dmub_psr *dmub, unsigned int power_opt cmd.psr_set_power_opt.psr_set_power_opt_data.power_opt = power_opt; cmd.psr_set_power_opt.psr_set_power_opt_data.panel_inst = panel_inst; - dm_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); } /* @@ -423,7 +418,7 @@ static bool dmub_psr_copy_settings(struct dmub_psr *dmub, copy_settings_data->relock_delay_frame_cnt = 2; copy_settings_data->dsc_slice_height = psr_context->dsc_slice_height; - dm_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); return true; } @@ -444,7 +439,7 @@ static void dmub_psr_force_static(struct dmub_psr *dmub, uint8_t panel_inst) cmd.psr_force_static.header.sub_type = DMUB_CMD__PSR_FORCE_STATIC; cmd.psr_enable.header.payload_bytes = 0; - dm_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); } /* @@ -452,13 +447,11 @@ static void dmub_psr_force_static(struct dmub_psr *dmub, uint8_t panel_inst) */ static void dmub_psr_get_residency(struct dmub_psr *dmub, uint32_t *residency, uint8_t panel_inst) { - struct dmub_srv *srv = dmub->ctx->dmub_srv->dmub; uint16_t param = (uint16_t)(panel_inst << 8); /* Send gpint command and wait for ack */ - dmub_srv_send_gpint_command(srv, DMUB_GPINT__PSR_RESIDENCY, param, 30); - - dmub_srv_get_gpint_response(srv, residency); + dc_wake_and_execute_gpint(dmub->ctx, DMUB_GPINT__PSR_RESIDENCY, param, residency, + DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY); } static const struct dmub_psr_funcs psr_funcs = { diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c index 28149e53c2a68f..38e4797e9476ca 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.c @@ -258,13 +258,97 @@ static void dmub_replay_residency(struct dmub_replay *dmub, uint8_t panel_inst, *residency = 0; } +/** + * Set REPLAY power optimization flags and coasting vtotal. + */ +static void dmub_replay_set_power_opt_and_coasting_vtotal(struct dmub_replay *dmub, + unsigned int power_opt, uint8_t panel_inst, uint16_t coasting_vtotal) +{ + union dmub_rb_cmd cmd; + struct dc_context *dc = dmub->ctx; + + memset(&cmd, 0, sizeof(cmd)); + cmd.replay_set_power_opt_and_coasting_vtotal.header.type = DMUB_CMD__REPLAY; + cmd.replay_set_power_opt_and_coasting_vtotal.header.sub_type = + DMUB_CMD__REPLAY_SET_POWER_OPT_AND_COASTING_VTOTAL; + cmd.replay_set_power_opt_and_coasting_vtotal.header.payload_bytes = + sizeof(struct dmub_rb_cmd_replay_set_power_opt_and_coasting_vtotal); + cmd.replay_set_power_opt_and_coasting_vtotal.replay_set_power_opt_data.power_opt = power_opt; + cmd.replay_set_power_opt_and_coasting_vtotal.replay_set_power_opt_data.panel_inst = panel_inst; + cmd.replay_set_power_opt_and_coasting_vtotal.replay_set_coasting_vtotal_data.coasting_vtotal = coasting_vtotal; + + dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); +} + +/** + * send Replay general cmd to DMUB. + */ +static void dmub_replay_send_cmd(struct dmub_replay *dmub, + enum replay_FW_Message_type msg, union dmub_replay_cmd_set *cmd_element) +{ + union dmub_rb_cmd cmd; + struct dc_context *ctx = NULL; + + if (dmub == NULL || cmd_element == NULL) + return; + + ctx = dmub->ctx; + if (ctx != NULL) { + + if (msg != Replay_Msg_Not_Support) { + memset(&cmd, 0, sizeof(cmd)); + //Header + cmd.replay_set_timing_sync.header.type = DMUB_CMD__REPLAY; + } else + return; + } else + return; + + switch (msg) { + case Replay_Set_Timing_Sync_Supported: + //Header + cmd.replay_set_timing_sync.header.sub_type = + DMUB_CMD__REPLAY_SET_TIMING_SYNC_SUPPORTED; + cmd.replay_set_timing_sync.header.payload_bytes = + sizeof(struct dmub_rb_cmd_replay_set_timing_sync); + //Cmd Body + cmd.replay_set_timing_sync.replay_set_timing_sync_data.panel_inst = + cmd_element->sync_data.panel_inst; + cmd.replay_set_timing_sync.replay_set_timing_sync_data.timing_sync_supported = + cmd_element->sync_data.timing_sync_supported; + break; + case Replay_Set_Residency_Frameupdate_Timer: + //Header + cmd.replay_set_frameupdate_timer.header.sub_type = + DMUB_CMD__REPLAY_SET_RESIDENCY_FRAMEUPDATE_TIMER; + cmd.replay_set_frameupdate_timer.header.payload_bytes = + sizeof(struct dmub_rb_cmd_replay_set_frameupdate_timer); + //Cmd Body + cmd.replay_set_frameupdate_timer.data.panel_inst = + cmd_element->panel_inst; + cmd.replay_set_frameupdate_timer.data.enable = + cmd_element->timer_data.enable; + cmd.replay_set_frameupdate_timer.data.frameupdate_count = + cmd_element->timer_data.frameupdate_count; + break; + case Replay_Msg_Not_Support: + default: + return; + break; + } + + dc_wake_and_execute_dmub_cmd(ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); +} + static const struct dmub_replay_funcs replay_funcs = { - .replay_copy_settings = dmub_replay_copy_settings, - .replay_enable = dmub_replay_enable, - .replay_get_state = dmub_replay_get_state, - .replay_set_power_opt = dmub_replay_set_power_opt, - .replay_set_coasting_vtotal = dmub_replay_set_coasting_vtotal, - .replay_residency = dmub_replay_residency, + .replay_copy_settings = dmub_replay_copy_settings, + .replay_enable = dmub_replay_enable, + .replay_get_state = dmub_replay_get_state, + .replay_set_power_opt = dmub_replay_set_power_opt, + .replay_set_coasting_vtotal = dmub_replay_set_coasting_vtotal, + .replay_residency = dmub_replay_residency, + .replay_set_power_opt_and_coasting_vtotal = dmub_replay_set_power_opt_and_coasting_vtotal, + .replay_send_cmd = dmub_replay_send_cmd, }; /* diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h index e8385bbf51fc2a..3613aff994d725 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_replay.h @@ -45,10 +45,14 @@ struct dmub_replay_funcs { struct replay_context *replay_context, uint8_t panel_inst); void (*replay_set_power_opt)(struct dmub_replay *dmub, unsigned int power_opt, uint8_t panel_inst); + void (*replay_send_cmd)(struct dmub_replay *dmub, + enum replay_FW_Message_type msg, union dmub_replay_cmd_set *cmd_element); void (*replay_set_coasting_vtotal)(struct dmub_replay *dmub, uint16_t coasting_vtotal, uint8_t panel_inst); void (*replay_residency)(struct dmub_replay *dmub, uint8_t panel_inst, uint32_t *residency, const bool is_start, const bool is_alpm); + void (*replay_set_power_opt_and_coasting_vtotal)(struct dmub_replay *dmub, + unsigned int power_opt, uint8_t panel_inst, uint16_t coasting_vtotal); }; struct dmub_replay *dmub_replay_create(struct dc_context *ctx); diff --git a/drivers/gpu/drm/amd/display/dc/dce100/Makefile b/drivers/gpu/drm/amd/display/dc/dce100/Makefile deleted file mode 100644 index 0d2f6bbf75585b..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dce100/Makefile +++ /dev/null @@ -1,46 +0,0 @@ -# -# Copyright 2017 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. -# -# -# Makefile for the 'controller' sub-component of DAL. -# It provides the control and status of HW CRTC block. - -CFLAGS_$(AMDDALPATH)/dc/dce100/dce100_resource.o = $(call cc-disable-warning, override-init) - -DCE100 = dce100_resource.o - -AMD_DAL_DCE100 = $(addprefix $(AMDDALPATH)/dc/dce100/,$(DCE100)) - -AMD_DISPLAY_FILES += $(AMD_DAL_DCE100) - - -############################################################################### -# DCE 10x -############################################################################### -ifdef 0#CONFIG_DRM_AMD_DC_DCE11_0 -TG_DCE100 = dce100_resource.o - -AMD_DAL_TG_DCE100 = $(addprefix \ - $(AMDDALPATH)/dc/dce100/,$(TG_DCE100)) - -AMD_DISPLAY_FILES += $(AMD_DAL_TG_DCE100) -endif - diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c deleted file mode 100644 index 53a5f4cb648cbd..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c +++ /dev/null @@ -1,1179 +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 - * - */ - -#include "dm_services.h" - -#include "link_encoder.h" -#include "stream_encoder.h" - -#include "resource.h" -#include "include/irq_service_interface.h" -#include "virtual/virtual_stream_encoder.h" -#include "dce110/dce110_resource.h" -#include "dce110/dce110_timing_generator.h" -#include "irq/dce110/irq_service_dce110.h" -#include "dce/dce_link_encoder.h" -#include "dce/dce_stream_encoder.h" -#include "dce/dce_mem_input.h" -#include "dce/dce_ipp.h" -#include "dce/dce_transform.h" -#include "dce/dce_opp.h" -#include "dce/dce_clock_source.h" -#include "dce/dce_audio.h" -#include "dce/dce_hwseq.h" -#include "dce100/dce100_hwseq.h" -#include "dce/dce_panel_cntl.h" - -#include "reg_helper.h" - -#include "dce/dce_10_0_d.h" -#include "dce/dce_10_0_sh_mask.h" - -#include "dce/dce_dmcu.h" -#include "dce/dce_aux.h" -#include "dce/dce_abm.h" -#include "dce/dce_i2c.h" - -#include "dce100_resource.h" - -#ifndef mmMC_HUB_RDREQ_DMIF_LIMIT -#include "gmc/gmc_8_2_d.h" -#include "gmc/gmc_8_2_sh_mask.h" -#endif - -#ifndef mmDP_DPHY_INTERNAL_CTRL - #define mmDP_DPHY_INTERNAL_CTRL 0x4aa7 - #define mmDP0_DP_DPHY_INTERNAL_CTRL 0x4aa7 - #define mmDP1_DP_DPHY_INTERNAL_CTRL 0x4ba7 - #define mmDP2_DP_DPHY_INTERNAL_CTRL 0x4ca7 - #define mmDP3_DP_DPHY_INTERNAL_CTRL 0x4da7 - #define mmDP4_DP_DPHY_INTERNAL_CTRL 0x4ea7 - #define mmDP5_DP_DPHY_INTERNAL_CTRL 0x4fa7 - #define mmDP6_DP_DPHY_INTERNAL_CTRL 0x54a7 - #define mmDP7_DP_DPHY_INTERNAL_CTRL 0x56a7 - #define mmDP8_DP_DPHY_INTERNAL_CTRL 0x57a7 -#endif - -#ifndef mmBIOS_SCRATCH_2 - #define mmBIOS_SCRATCH_2 0x05CB - #define mmBIOS_SCRATCH_3 0x05CC - #define mmBIOS_SCRATCH_6 0x05CF -#endif - -#ifndef mmDP_DPHY_BS_SR_SWAP_CNTL - #define mmDP_DPHY_BS_SR_SWAP_CNTL 0x4ADC - #define mmDP0_DP_DPHY_BS_SR_SWAP_CNTL 0x4ADC - #define mmDP1_DP_DPHY_BS_SR_SWAP_CNTL 0x4BDC - #define mmDP2_DP_DPHY_BS_SR_SWAP_CNTL 0x4CDC - #define mmDP3_DP_DPHY_BS_SR_SWAP_CNTL 0x4DDC - #define mmDP4_DP_DPHY_BS_SR_SWAP_CNTL 0x4EDC - #define mmDP5_DP_DPHY_BS_SR_SWAP_CNTL 0x4FDC - #define mmDP6_DP_DPHY_BS_SR_SWAP_CNTL 0x54DC -#endif - -#ifndef mmDP_DPHY_FAST_TRAINING - #define mmDP_DPHY_FAST_TRAINING 0x4ABC - #define mmDP0_DP_DPHY_FAST_TRAINING 0x4ABC - #define mmDP1_DP_DPHY_FAST_TRAINING 0x4BBC - #define mmDP2_DP_DPHY_FAST_TRAINING 0x4CBC - #define mmDP3_DP_DPHY_FAST_TRAINING 0x4DBC - #define mmDP4_DP_DPHY_FAST_TRAINING 0x4EBC - #define mmDP5_DP_DPHY_FAST_TRAINING 0x4FBC - #define mmDP6_DP_DPHY_FAST_TRAINING 0x54BC -#endif - -static const struct dce110_timing_generator_offsets dce100_tg_offsets[] = { - { - .crtc = (mmCRTC0_CRTC_CONTROL - mmCRTC_CONTROL), - .dcp = (mmDCP0_GRPH_CONTROL - mmGRPH_CONTROL), - }, - { - .crtc = (mmCRTC1_CRTC_CONTROL - mmCRTC_CONTROL), - .dcp = (mmDCP1_GRPH_CONTROL - mmGRPH_CONTROL), - }, - { - .crtc = (mmCRTC2_CRTC_CONTROL - mmCRTC_CONTROL), - .dcp = (mmDCP2_GRPH_CONTROL - mmGRPH_CONTROL), - }, - { - .crtc = (mmCRTC3_CRTC_CONTROL - mmCRTC_CONTROL), - .dcp = (mmDCP3_GRPH_CONTROL - mmGRPH_CONTROL), - }, - { - .crtc = (mmCRTC4_CRTC_CONTROL - mmCRTC_CONTROL), - .dcp = (mmDCP4_GRPH_CONTROL - mmGRPH_CONTROL), - }, - { - .crtc = (mmCRTC5_CRTC_CONTROL - mmCRTC_CONTROL), - .dcp = (mmDCP5_GRPH_CONTROL - mmGRPH_CONTROL), - } -}; - -/* set register offset */ -#define SR(reg_name)\ - .reg_name = mm ## reg_name - -/* set register offset with instance */ -#define SRI(reg_name, block, id)\ - .reg_name = mm ## block ## id ## _ ## reg_name - -#define ipp_regs(id)\ -[id] = {\ - IPP_DCE100_REG_LIST_DCE_BASE(id)\ -} - -static const struct dce_ipp_registers ipp_regs[] = { - ipp_regs(0), - ipp_regs(1), - ipp_regs(2), - ipp_regs(3), - ipp_regs(4), - ipp_regs(5) -}; - -static const struct dce_ipp_shift ipp_shift = { - IPP_DCE100_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) -}; - -static const struct dce_ipp_mask ipp_mask = { - IPP_DCE100_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) -}; - -#define transform_regs(id)\ -[id] = {\ - XFM_COMMON_REG_LIST_DCE100(id)\ -} - -static const struct dce_transform_registers xfm_regs[] = { - transform_regs(0), - transform_regs(1), - transform_regs(2), - transform_regs(3), - transform_regs(4), - transform_regs(5) -}; - -static const struct dce_transform_shift xfm_shift = { - XFM_COMMON_MASK_SH_LIST_DCE110(__SHIFT) -}; - -static const struct dce_transform_mask xfm_mask = { - XFM_COMMON_MASK_SH_LIST_DCE110(_MASK) -}; - -#define aux_regs(id)\ -[id] = {\ - AUX_REG_LIST(id)\ -} - -static const struct dce110_link_enc_aux_registers link_enc_aux_regs[] = { - aux_regs(0), - aux_regs(1), - aux_regs(2), - aux_regs(3), - aux_regs(4), - aux_regs(5) -}; - -#define hpd_regs(id)\ -[id] = {\ - HPD_REG_LIST(id)\ -} - -static const struct dce110_link_enc_hpd_registers link_enc_hpd_regs[] = { - hpd_regs(0), - hpd_regs(1), - hpd_regs(2), - hpd_regs(3), - hpd_regs(4), - hpd_regs(5) -}; - -#define link_regs(id)\ -[id] = {\ - LE_DCE100_REG_LIST(id)\ -} - -static const struct dce110_link_enc_registers link_enc_regs[] = { - link_regs(0), - link_regs(1), - link_regs(2), - link_regs(3), - link_regs(4), - link_regs(5), - link_regs(6), -}; - -#define stream_enc_regs(id)\ -[id] = {\ - SE_COMMON_REG_LIST_DCE_BASE(id),\ - .AFMT_CNTL = 0,\ -} - -static const struct dce110_stream_enc_registers stream_enc_regs[] = { - stream_enc_regs(0), - stream_enc_regs(1), - stream_enc_regs(2), - stream_enc_regs(3), - stream_enc_regs(4), - stream_enc_regs(5), - stream_enc_regs(6) -}; - -static const struct dce_stream_encoder_shift se_shift = { - SE_COMMON_MASK_SH_LIST_DCE80_100(__SHIFT) -}; - -static const struct dce_stream_encoder_mask se_mask = { - SE_COMMON_MASK_SH_LIST_DCE80_100(_MASK) -}; - -static const struct dce_panel_cntl_registers panel_cntl_regs[] = { - { DCE_PANEL_CNTL_REG_LIST() } -}; - -static const struct dce_panel_cntl_shift panel_cntl_shift = { - DCE_PANEL_CNTL_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_panel_cntl_mask panel_cntl_mask = { - DCE_PANEL_CNTL_MASK_SH_LIST(_MASK) -}; - -#define opp_regs(id)\ -[id] = {\ - OPP_DCE_100_REG_LIST(id),\ -} - -static const struct dce_opp_registers opp_regs[] = { - opp_regs(0), - opp_regs(1), - opp_regs(2), - opp_regs(3), - opp_regs(4), - opp_regs(5) -}; - -static const struct dce_opp_shift opp_shift = { - OPP_COMMON_MASK_SH_LIST_DCE_100(__SHIFT) -}; - -static const struct dce_opp_mask opp_mask = { - OPP_COMMON_MASK_SH_LIST_DCE_100(_MASK) -}; -#define aux_engine_regs(id)\ -[id] = {\ - AUX_COMMON_REG_LIST(id), \ - .AUX_RESET_MASK = 0 \ -} - -static const struct dce110_aux_registers aux_engine_regs[] = { - aux_engine_regs(0), - aux_engine_regs(1), - aux_engine_regs(2), - aux_engine_regs(3), - aux_engine_regs(4), - aux_engine_regs(5) -}; - -#define audio_regs(id)\ -[id] = {\ - AUD_COMMON_REG_LIST(id)\ -} - -static const struct dce_audio_registers audio_regs[] = { - audio_regs(0), - audio_regs(1), - audio_regs(2), - audio_regs(3), - audio_regs(4), - audio_regs(5), - audio_regs(6), -}; - -static const struct dce_audio_shift audio_shift = { - AUD_COMMON_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_audio_mask audio_mask = { - AUD_COMMON_MASK_SH_LIST(_MASK) -}; - -#define clk_src_regs(id)\ -[id] = {\ - CS_COMMON_REG_LIST_DCE_100_110(id),\ -} - -static const struct dce110_clk_src_regs clk_src_regs[] = { - clk_src_regs(0), - clk_src_regs(1), - clk_src_regs(2) -}; - -static const struct dce110_clk_src_shift cs_shift = { - CS_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) -}; - -static const struct dce110_clk_src_mask cs_mask = { - CS_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) -}; - -static const struct dce_dmcu_registers dmcu_regs = { - DMCU_DCE110_COMMON_REG_LIST() -}; - -static const struct dce_dmcu_shift dmcu_shift = { - DMCU_MASK_SH_LIST_DCE110(__SHIFT) -}; - -static const struct dce_dmcu_mask dmcu_mask = { - DMCU_MASK_SH_LIST_DCE110(_MASK) -}; - -static const struct dce_abm_registers abm_regs = { - ABM_DCE110_COMMON_REG_LIST() -}; - -static const struct dce_abm_shift abm_shift = { - ABM_MASK_SH_LIST_DCE110(__SHIFT) -}; - -static const struct dce_abm_mask abm_mask = { - ABM_MASK_SH_LIST_DCE110(_MASK) -}; - -#define DCFE_MEM_PWR_CTRL_REG_BASE 0x1b03 - -static const struct bios_registers bios_regs = { - .BIOS_SCRATCH_3 = mmBIOS_SCRATCH_3, - .BIOS_SCRATCH_6 = mmBIOS_SCRATCH_6 -}; - -static const struct resource_caps res_cap = { - .num_timing_generator = 6, - .num_audio = 6, - .num_stream_encoder = 6, - .num_pll = 3, - .num_ddc = 6, -}; - -static const struct dc_plane_cap plane_cap = { - .type = DC_PLANE_TYPE_DCE_RGB, - - .pixel_format_support = { - .argb8888 = true, - .nv12 = false, - .fp16 = true - }, - - .max_upscale_factor = { - .argb8888 = 16000, - .nv12 = 1, - .fp16 = 1 - }, - - .max_downscale_factor = { - .argb8888 = 250, - .nv12 = 1, - .fp16 = 1 - } -}; - -static const struct dc_debug_options debug_defaults = { - .enable_legacy_fast_update = true, -}; - -#define CTX ctx -#define REG(reg) mm ## reg - -#ifndef mmCC_DC_HDMI_STRAPS -#define mmCC_DC_HDMI_STRAPS 0x1918 -#define CC_DC_HDMI_STRAPS__HDMI_DISABLE_MASK 0x40 -#define CC_DC_HDMI_STRAPS__HDMI_DISABLE__SHIFT 0x6 -#define CC_DC_HDMI_STRAPS__AUDIO_STREAM_NUMBER_MASK 0x700 -#define CC_DC_HDMI_STRAPS__AUDIO_STREAM_NUMBER__SHIFT 0x8 -#endif - -static int map_transmitter_id_to_phy_instance( - enum transmitter transmitter) -{ - switch (transmitter) { - case TRANSMITTER_UNIPHY_A: - return 0; - case TRANSMITTER_UNIPHY_B: - return 1; - case TRANSMITTER_UNIPHY_C: - return 2; - case TRANSMITTER_UNIPHY_D: - return 3; - case TRANSMITTER_UNIPHY_E: - return 4; - case TRANSMITTER_UNIPHY_F: - return 5; - case TRANSMITTER_UNIPHY_G: - return 6; - default: - ASSERT(0); - return 0; - } -} - -static void read_dce_straps( - struct dc_context *ctx, - struct resource_straps *straps) -{ - REG_GET_2(CC_DC_HDMI_STRAPS, - HDMI_DISABLE, &straps->hdmi_disable, - AUDIO_STREAM_NUMBER, &straps->audio_stream_number); - - REG_GET(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO, &straps->dc_pinstraps_audio); -} - -static struct audio *create_audio( - struct dc_context *ctx, unsigned int inst) -{ - return dce_audio_create(ctx, inst, - &audio_regs[inst], &audio_shift, &audio_mask); -} - -static struct timing_generator *dce100_timing_generator_create( - struct dc_context *ctx, - uint32_t instance, - const struct dce110_timing_generator_offsets *offsets) -{ - struct dce110_timing_generator *tg110 = - kzalloc(sizeof(struct dce110_timing_generator), GFP_KERNEL); - - if (!tg110) - return NULL; - - dce110_timing_generator_construct(tg110, ctx, instance, offsets); - return &tg110->base; -} - -static struct stream_encoder *dce100_stream_encoder_create( - enum engine_id eng_id, - struct dc_context *ctx) -{ - struct dce110_stream_encoder *enc110 = - kzalloc(sizeof(struct dce110_stream_encoder), GFP_KERNEL); - - if (!enc110) - return NULL; - - dce110_stream_encoder_construct(enc110, ctx, ctx->dc_bios, eng_id, - &stream_enc_regs[eng_id], &se_shift, &se_mask); - return &enc110->base; -} - -#define SRII(reg_name, block, id)\ - .reg_name[id] = mm ## block ## id ## _ ## reg_name - -static const struct dce_hwseq_registers hwseq_reg = { - HWSEQ_DCE10_REG_LIST() -}; - -static const struct dce_hwseq_shift hwseq_shift = { - HWSEQ_DCE10_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_hwseq_mask hwseq_mask = { - HWSEQ_DCE10_MASK_SH_LIST(_MASK) -}; - -static struct dce_hwseq *dce100_hwseq_create( - struct dc_context *ctx) -{ - struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); - - if (hws) { - hws->ctx = ctx; - hws->regs = &hwseq_reg; - hws->shifts = &hwseq_shift; - hws->masks = &hwseq_mask; - } - return hws; -} - -static const struct resource_create_funcs res_create_funcs = { - .read_dce_straps = read_dce_straps, - .create_audio = create_audio, - .create_stream_encoder = dce100_stream_encoder_create, - .create_hwseq = dce100_hwseq_create, -}; - -#define mi_inst_regs(id) { \ - MI_DCE8_REG_LIST(id), \ - .MC_HUB_RDREQ_DMIF_LIMIT = mmMC_HUB_RDREQ_DMIF_LIMIT \ -} -static const struct dce_mem_input_registers mi_regs[] = { - mi_inst_regs(0), - mi_inst_regs(1), - mi_inst_regs(2), - mi_inst_regs(3), - mi_inst_regs(4), - mi_inst_regs(5), -}; - -static const struct dce_mem_input_shift mi_shifts = { - MI_DCE8_MASK_SH_LIST(__SHIFT), - .ENABLE = MC_HUB_RDREQ_DMIF_LIMIT__ENABLE__SHIFT -}; - -static const struct dce_mem_input_mask mi_masks = { - MI_DCE8_MASK_SH_LIST(_MASK), - .ENABLE = MC_HUB_RDREQ_DMIF_LIMIT__ENABLE_MASK -}; - -static const struct dce110_aux_registers_shift aux_shift = { - DCE10_AUX_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce110_aux_registers_mask aux_mask = { - DCE10_AUX_MASK_SH_LIST(_MASK) -}; - -static struct mem_input *dce100_mem_input_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dce_mem_input *dce_mi = kzalloc(sizeof(struct dce_mem_input), - GFP_KERNEL); - - if (!dce_mi) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dce_mem_input_construct(dce_mi, ctx, inst, &mi_regs[inst], &mi_shifts, &mi_masks); - dce_mi->wa.single_head_rdreq_dmif_limit = 2; - return &dce_mi->base; -} - -static void dce100_transform_destroy(struct transform **xfm) -{ - kfree(TO_DCE_TRANSFORM(*xfm)); - *xfm = NULL; -} - -static struct transform *dce100_transform_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dce_transform *transform = - kzalloc(sizeof(struct dce_transform), GFP_KERNEL); - - if (!transform) - return NULL; - - dce_transform_construct(transform, ctx, inst, - &xfm_regs[inst], &xfm_shift, &xfm_mask); - return &transform->base; -} - -static struct input_pixel_processor *dce100_ipp_create( - struct dc_context *ctx, uint32_t inst) -{ - struct dce_ipp *ipp = kzalloc(sizeof(struct dce_ipp), GFP_KERNEL); - - if (!ipp) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dce_ipp_construct(ipp, ctx, inst, - &ipp_regs[inst], &ipp_shift, &ipp_mask); - return &ipp->base; -} - -static const struct encoder_feature_support link_enc_feature = { - .max_hdmi_deep_color = COLOR_DEPTH_121212, - .max_hdmi_pixel_clock = 300000, - .flags.bits.IS_HBR2_CAPABLE = true, - .flags.bits.IS_TPS3_CAPABLE = true -}; - -static struct link_encoder *dce100_link_encoder_create( - struct dc_context *ctx, - const struct encoder_init_data *enc_init_data) -{ - struct dce110_link_encoder *enc110 = - kzalloc(sizeof(struct dce110_link_encoder), GFP_KERNEL); - int link_regs_id; - - if (!enc110) - return NULL; - - link_regs_id = - map_transmitter_id_to_phy_instance(enc_init_data->transmitter); - - dce110_link_encoder_construct(enc110, - enc_init_data, - &link_enc_feature, - &link_enc_regs[link_regs_id], - &link_enc_aux_regs[enc_init_data->channel - 1], - &link_enc_hpd_regs[enc_init_data->hpd_source]); - return &enc110->base; -} - -static struct panel_cntl *dce100_panel_cntl_create(const struct panel_cntl_init_data *init_data) -{ - struct dce_panel_cntl *panel_cntl = - kzalloc(sizeof(struct dce_panel_cntl), GFP_KERNEL); - - if (!panel_cntl) - return NULL; - - dce_panel_cntl_construct(panel_cntl, - init_data, - &panel_cntl_regs[init_data->inst], - &panel_cntl_shift, - &panel_cntl_mask); - - return &panel_cntl->base; -} - -static struct output_pixel_processor *dce100_opp_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dce110_opp *opp = - kzalloc(sizeof(struct dce110_opp), GFP_KERNEL); - - if (!opp) - return NULL; - - dce110_opp_construct(opp, - ctx, inst, &opp_regs[inst], &opp_shift, &opp_mask); - return &opp->base; -} - -static struct dce_aux *dce100_aux_engine_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct aux_engine_dce110 *aux_engine = - kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); - - if (!aux_engine) - return NULL; - - dce110_aux_engine_construct(aux_engine, ctx, inst, - SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, - &aux_engine_regs[inst], - &aux_mask, - &aux_shift, - ctx->dc->caps.extended_aux_timeout_support); - - return &aux_engine->base; -} -#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST(id) } - -static const struct dce_i2c_registers i2c_hw_regs[] = { - i2c_inst_regs(1), - i2c_inst_regs(2), - i2c_inst_regs(3), - i2c_inst_regs(4), - i2c_inst_regs(5), - i2c_inst_regs(6), -}; - -static const struct dce_i2c_shift i2c_shifts = { - I2C_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) -}; - -static const struct dce_i2c_mask i2c_masks = { - I2C_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) -}; - -static struct dce_i2c_hw *dce100_i2c_hw_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dce_i2c_hw *dce_i2c_hw = - kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); - - if (!dce_i2c_hw) - return NULL; - - dce100_i2c_hw_construct(dce_i2c_hw, ctx, inst, - &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); - - return dce_i2c_hw; -} -static struct clock_source *dce100_clock_source_create( - struct dc_context *ctx, - struct dc_bios *bios, - enum clock_source_id id, - const struct dce110_clk_src_regs *regs, - bool dp_clk_src) -{ - struct dce110_clk_src *clk_src = - kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); - - if (!clk_src) - return NULL; - - if (dce110_clk_src_construct(clk_src, ctx, bios, id, - regs, &cs_shift, &cs_mask)) { - clk_src->base.dp_clk_src = dp_clk_src; - return &clk_src->base; - } - - kfree(clk_src); - BREAK_TO_DEBUGGER(); - return NULL; -} - -static void dce100_clock_source_destroy(struct clock_source **clk_src) -{ - kfree(TO_DCE110_CLK_SRC(*clk_src)); - *clk_src = NULL; -} - -static void dce100_resource_destruct(struct dce110_resource_pool *pool) -{ - unsigned int i; - - for (i = 0; i < pool->base.pipe_count; i++) { - if (pool->base.opps[i] != NULL) - dce110_opp_destroy(&pool->base.opps[i]); - - if (pool->base.transforms[i] != NULL) - dce100_transform_destroy(&pool->base.transforms[i]); - - if (pool->base.ipps[i] != NULL) - dce_ipp_destroy(&pool->base.ipps[i]); - - if (pool->base.mis[i] != NULL) { - kfree(TO_DCE_MEM_INPUT(pool->base.mis[i])); - pool->base.mis[i] = NULL; - } - - if (pool->base.timing_generators[i] != NULL) { - kfree(DCE110TG_FROM_TG(pool->base.timing_generators[i])); - pool->base.timing_generators[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - if (pool->base.engines[i] != NULL) - dce110_engine_destroy(&pool->base.engines[i]); - if (pool->base.hw_i2cs[i] != NULL) { - kfree(pool->base.hw_i2cs[i]); - pool->base.hw_i2cs[i] = NULL; - } - if (pool->base.sw_i2cs[i] != NULL) { - kfree(pool->base.sw_i2cs[i]); - pool->base.sw_i2cs[i] = NULL; - } - } - - for (i = 0; i < pool->base.stream_enc_count; i++) { - if (pool->base.stream_enc[i] != NULL) - kfree(DCE110STRENC_FROM_STRENC(pool->base.stream_enc[i])); - } - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] != NULL) - dce100_clock_source_destroy(&pool->base.clock_sources[i]); - } - - if (pool->base.dp_clock_source != NULL) - dce100_clock_source_destroy(&pool->base.dp_clock_source); - - for (i = 0; i < pool->base.audio_count; i++) { - if (pool->base.audios[i] != NULL) - dce_aud_destroy(&pool->base.audios[i]); - } - - if (pool->base.abm != NULL) - dce_abm_destroy(&pool->base.abm); - - if (pool->base.dmcu != NULL) - dce_dmcu_destroy(&pool->base.dmcu); - - if (pool->base.irqs != NULL) - dal_irq_service_destroy(&pool->base.irqs); -} - -static enum dc_status build_mapped_resource( - const struct dc *dc, - struct dc_state *context, - struct dc_stream_state *stream) -{ - struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream); - - if (!pipe_ctx) - return DC_ERROR_UNEXPECTED; - - dce110_resource_build_pipe_hw_param(pipe_ctx); - - resource_build_info_frame(pipe_ctx); - - return DC_OK; -} - -static bool dce100_validate_bandwidth( - struct dc *dc, - struct dc_state *context, - bool fast_validate) -{ - int i; - bool at_least_one_pipe = false; - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - if (context->res_ctx.pipe_ctx[i].stream) - at_least_one_pipe = true; - } - - if (at_least_one_pipe) { - /* TODO implement when needed but for now hardcode max value*/ - context->bw_ctx.bw.dce.dispclk_khz = 681000; - context->bw_ctx.bw.dce.yclk_khz = 250000 * MEMORY_TYPE_MULTIPLIER_CZ; - } else { - context->bw_ctx.bw.dce.dispclk_khz = 0; - context->bw_ctx.bw.dce.yclk_khz = 0; - } - - return true; -} - -static bool dce100_validate_surface_sets( - struct dc_state *context) -{ - int i; - - for (i = 0; i < context->stream_count; i++) { - if (context->stream_status[i].plane_count == 0) - continue; - - if (context->stream_status[i].plane_count > 1) - return false; - - if (context->stream_status[i].plane_states[0]->format - >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) - return false; - } - - return true; -} - -static enum dc_status dce100_validate_global( - struct dc *dc, - struct dc_state *context) -{ - if (!dce100_validate_surface_sets(context)) - return DC_FAIL_SURFACE_VALIDATE; - - return DC_OK; -} - -enum dc_status dce100_add_stream_to_ctx( - struct dc *dc, - struct dc_state *new_ctx, - struct dc_stream_state *dc_stream) -{ - enum dc_status result = DC_ERROR_UNEXPECTED; - - result = resource_map_pool_resources(dc, new_ctx, dc_stream); - - if (result == DC_OK) - result = resource_map_clock_resources(dc, new_ctx, dc_stream); - - if (result == DC_OK) - result = build_mapped_resource(dc, new_ctx, dc_stream); - - return result; -} - -static void dce100_destroy_resource_pool(struct resource_pool **pool) -{ - struct dce110_resource_pool *dce110_pool = TO_DCE110_RES_POOL(*pool); - - dce100_resource_destruct(dce110_pool); - kfree(dce110_pool); - *pool = NULL; -} - -enum dc_status dce100_validate_plane(const struct dc_plane_state *plane_state, struct dc_caps *caps) -{ - - if (plane_state->format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) - return DC_OK; - - return DC_FAIL_SURFACE_VALIDATE; -} - -struct stream_encoder *dce100_find_first_free_match_stream_enc_for_link( - struct resource_context *res_ctx, - const struct resource_pool *pool, - struct dc_stream_state *stream) -{ - int i; - int j = -1; - struct dc_link *link = stream->link; - - for (i = 0; i < pool->stream_enc_count; i++) { - if (!res_ctx->is_stream_enc_acquired[i] && - pool->stream_enc[i]) { - /* Store first available for MST second display - * in daisy chain use case - */ - j = i; - if (pool->stream_enc[i]->id == - link->link_enc->preferred_engine) - return pool->stream_enc[i]; - } - } - - /* - * below can happen in cases when stream encoder is acquired: - * 1) for second MST display in chain, so preferred engine already - * acquired; - * 2) for another link, which preferred engine already acquired by any - * MST configuration. - * - * If signal is of DP type and preferred engine not found, return last available - * - * TODO - This is just a patch up and a generic solution is - * required for non DP connectors. - */ - - if (j >= 0 && link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT) - return pool->stream_enc[j]; - - return NULL; -} - -static const struct resource_funcs dce100_res_pool_funcs = { - .destroy = dce100_destroy_resource_pool, - .link_enc_create = dce100_link_encoder_create, - .panel_cntl_create = dce100_panel_cntl_create, - .validate_bandwidth = dce100_validate_bandwidth, - .validate_plane = dce100_validate_plane, - .add_stream_to_ctx = dce100_add_stream_to_ctx, - .validate_global = dce100_validate_global, - .find_first_free_match_stream_enc_for_link = dce100_find_first_free_match_stream_enc_for_link -}; - -static bool dce100_resource_construct( - uint8_t num_virtual_links, - struct dc *dc, - struct dce110_resource_pool *pool) -{ - unsigned int i; - struct dc_context *ctx = dc->ctx; - struct dc_bios *bp; - - ctx->dc_bios->regs = &bios_regs; - - pool->base.res_cap = &res_cap; - pool->base.funcs = &dce100_res_pool_funcs; - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; - - bp = ctx->dc_bios; - - if (bp->fw_info_valid && bp->fw_info.external_clock_source_frequency_for_dp != 0) { - pool->base.dp_clock_source = - dce100_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_EXTERNAL, NULL, true); - - pool->base.clock_sources[0] = - dce100_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL0, &clk_src_regs[0], false); - pool->base.clock_sources[1] = - dce100_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL1, &clk_src_regs[1], false); - pool->base.clock_sources[2] = - dce100_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL2, &clk_src_regs[2], false); - pool->base.clk_src_count = 3; - - } else { - pool->base.dp_clock_source = - dce100_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL0, &clk_src_regs[0], true); - - pool->base.clock_sources[0] = - dce100_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL1, &clk_src_regs[1], false); - pool->base.clock_sources[1] = - dce100_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL2, &clk_src_regs[2], false); - pool->base.clk_src_count = 2; - } - - if (pool->base.dp_clock_source == NULL) { - dm_error("DC: failed to create dp clock source!\n"); - BREAK_TO_DEBUGGER(); - goto res_create_fail; - } - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] == NULL) { - dm_error("DC: failed to create clock sources!\n"); - BREAK_TO_DEBUGGER(); - goto res_create_fail; - } - } - - pool->base.dmcu = dce_dmcu_create(ctx, - &dmcu_regs, - &dmcu_shift, - &dmcu_mask); - if (pool->base.dmcu == NULL) { - dm_error("DC: failed to create dmcu!\n"); - BREAK_TO_DEBUGGER(); - goto res_create_fail; - } - - pool->base.abm = dce_abm_create(ctx, - &abm_regs, - &abm_shift, - &abm_mask); - if (pool->base.abm == NULL) { - dm_error("DC: failed to create abm!\n"); - BREAK_TO_DEBUGGER(); - goto res_create_fail; - } - - { - struct irq_service_init_data init_data; - init_data.ctx = dc->ctx; - pool->base.irqs = dal_irq_service_dce110_create(&init_data); - if (!pool->base.irqs) - goto res_create_fail; - } - - /************************************************* - * Resource + asic cap harcoding * - *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; - pool->base.pipe_count = res_cap.num_timing_generator; - pool->base.timing_generator_count = pool->base.res_cap->num_timing_generator; - dc->caps.max_downscale_ratio = 200; - dc->caps.i2c_speed_in_khz = 40; - dc->caps.i2c_speed_in_khz = 40; - dc->caps.max_cursor_size = 128; - dc->caps.min_horizontal_blanking_period = 80; - dc->caps.dual_link_dvi = true; - dc->caps.disable_dp_clk_share = true; - dc->caps.extended_aux_timeout_support = false; - dc->debug = debug_defaults; - - for (i = 0; i < pool->base.pipe_count; i++) { - pool->base.timing_generators[i] = - dce100_timing_generator_create( - ctx, - i, - &dce100_tg_offsets[i]); - if (pool->base.timing_generators[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create tg!\n"); - goto res_create_fail; - } - - pool->base.mis[i] = dce100_mem_input_create(ctx, i); - if (pool->base.mis[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create memory input!\n"); - goto res_create_fail; - } - - pool->base.ipps[i] = dce100_ipp_create(ctx, i); - if (pool->base.ipps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create input pixel processor!\n"); - goto res_create_fail; - } - - pool->base.transforms[i] = dce100_transform_create(ctx, i); - if (pool->base.transforms[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create transform!\n"); - goto res_create_fail; - } - - pool->base.opps[i] = dce100_opp_create(ctx, i); - if (pool->base.opps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create output pixel processor!\n"); - goto res_create_fail; - } - } - - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - pool->base.engines[i] = dce100_aux_engine_create(ctx, i); - if (pool->base.engines[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create aux engine!!\n"); - goto res_create_fail; - } - pool->base.hw_i2cs[i] = dce100_i2c_hw_create(ctx, i); - if (pool->base.hw_i2cs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create i2c engine!!\n"); - goto res_create_fail; - } - pool->base.sw_i2cs[i] = NULL; - } - - dc->caps.max_planes = pool->base.pipe_count; - - for (i = 0; i < dc->caps.max_planes; ++i) - dc->caps.planes[i] = plane_cap; - - if (!resource_construct(num_virtual_links, dc, &pool->base, - &res_create_funcs)) - goto res_create_fail; - - /* Create hardware sequencer */ - dce100_hw_sequencer_construct(dc); - return true; - -res_create_fail: - dce100_resource_destruct(pool); - - return false; -} - -struct resource_pool *dce100_create_resource_pool( - uint8_t num_virtual_links, - struct dc *dc) -{ - struct dce110_resource_pool *pool = - kzalloc(sizeof(struct dce110_resource_pool), GFP_KERNEL); - - if (!pool) - return NULL; - - if (dce100_resource_construct(num_virtual_links, dc, pool)) - return &pool->base; - - kfree(pool); - BREAK_TO_DEBUGGER(); - return NULL; -} - diff --git a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.h b/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.h deleted file mode 100644 index fecab7c560f5ba..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2017 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. - * - * - */ -/* - * dce100_resource.h - * - * Created on: 2016-01-20 - * Author: qyang - */ - -#ifndef DCE100_RESOURCE_H_ -#define DCE100_RESOURCE_H_ - -struct dc; -struct resource_pool; -struct dc_validation_set; - -struct resource_pool *dce100_create_resource_pool( - uint8_t num_virtual_links, - struct dc *dc); - -enum dc_status dce100_validate_plane(const struct dc_plane_state *plane_state, struct dc_caps *caps); - -enum dc_status dce100_add_stream_to_ctx( - struct dc *dc, - struct dc_state *new_ctx, - struct dc_stream_state *dc_stream); - -struct stream_encoder *dce100_find_first_free_match_stream_enc_for_link( - struct resource_context *res_ctx, - const struct resource_pool *pool, - struct dc_stream_state *stream); - -#endif /* DCE100_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dce110/Makefile b/drivers/gpu/drm/amd/display/dc/dce110/Makefile index 695a50ed5ad268..f0777d61c2cbb6 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dce110/Makefile @@ -26,8 +26,8 @@ CFLAGS_$(AMDDALPATH)/dc/dce110/dce110_resource.o = $(call cc-disable-warning, override-init) DCE110 = dce110_timing_generator.o \ -dce110_compressor.o dce110_resource.o \ -dce110_opp_regamma_v.o dce110_opp_csc_v.o dce110_timing_generator_v.o \ +dce110_compressor.o dce110_opp_regamma_v.o \ +dce110_opp_csc_v.o dce110_timing_generator_v.o \ dce110_mem_input_v.o dce110_opp_v.o dce110_transform_v.o AMD_DAL_DCE110 = $(addprefix $(AMDDALPATH)/dc/dce110/,$(DCE110)) diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c deleted file mode 100644 index fe518fd27b083d..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c +++ /dev/null @@ -1,1551 +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 - * - */ - -#include "dm_services.h" - -#include "link_encoder.h" -#include "stream_encoder.h" - -#include "resource.h" -#include "dce110/dce110_resource.h" -#include "include/irq_service_interface.h" -#include "dce/dce_audio.h" -#include "dce110/dce110_timing_generator.h" -#include "irq/dce110/irq_service_dce110.h" -#include "dce110/dce110_timing_generator_v.h" -#include "dce/dce_link_encoder.h" -#include "dce/dce_stream_encoder.h" -#include "dce/dce_mem_input.h" -#include "dce110/dce110_mem_input_v.h" -#include "dce/dce_ipp.h" -#include "dce/dce_transform.h" -#include "dce110/dce110_transform_v.h" -#include "dce/dce_opp.h" -#include "dce110/dce110_opp_v.h" -#include "dce/dce_clock_source.h" -#include "dce/dce_hwseq.h" -#include "dce110/dce110_hwseq.h" -#include "dce/dce_aux.h" -#include "dce/dce_abm.h" -#include "dce/dce_dmcu.h" -#include "dce/dce_i2c.h" -#include "dce/dce_panel_cntl.h" - -#define DC_LOGGER \ - dc->ctx->logger - -#include "dce110/dce110_compressor.h" - -#include "reg_helper.h" - -#include "dce/dce_11_0_d.h" -#include "dce/dce_11_0_sh_mask.h" - -#ifndef mmMC_HUB_RDREQ_DMIF_LIMIT -#include "gmc/gmc_8_2_d.h" -#include "gmc/gmc_8_2_sh_mask.h" -#endif - -#ifndef mmDP_DPHY_INTERNAL_CTRL - #define mmDP_DPHY_INTERNAL_CTRL 0x4aa7 - #define mmDP0_DP_DPHY_INTERNAL_CTRL 0x4aa7 - #define mmDP1_DP_DPHY_INTERNAL_CTRL 0x4ba7 - #define mmDP2_DP_DPHY_INTERNAL_CTRL 0x4ca7 - #define mmDP3_DP_DPHY_INTERNAL_CTRL 0x4da7 - #define mmDP4_DP_DPHY_INTERNAL_CTRL 0x4ea7 - #define mmDP5_DP_DPHY_INTERNAL_CTRL 0x4fa7 - #define mmDP6_DP_DPHY_INTERNAL_CTRL 0x54a7 - #define mmDP7_DP_DPHY_INTERNAL_CTRL 0x56a7 - #define mmDP8_DP_DPHY_INTERNAL_CTRL 0x57a7 -#endif - -#ifndef mmBIOS_SCRATCH_2 - #define mmBIOS_SCRATCH_2 0x05CB - #define mmBIOS_SCRATCH_3 0x05CC - #define mmBIOS_SCRATCH_6 0x05CF -#endif - -#ifndef mmDP_DPHY_BS_SR_SWAP_CNTL - #define mmDP_DPHY_BS_SR_SWAP_CNTL 0x4ADC - #define mmDP0_DP_DPHY_BS_SR_SWAP_CNTL 0x4ADC - #define mmDP1_DP_DPHY_BS_SR_SWAP_CNTL 0x4BDC - #define mmDP2_DP_DPHY_BS_SR_SWAP_CNTL 0x4CDC - #define mmDP3_DP_DPHY_BS_SR_SWAP_CNTL 0x4DDC - #define mmDP4_DP_DPHY_BS_SR_SWAP_CNTL 0x4EDC - #define mmDP5_DP_DPHY_BS_SR_SWAP_CNTL 0x4FDC - #define mmDP6_DP_DPHY_BS_SR_SWAP_CNTL 0x54DC -#endif - -#ifndef mmDP_DPHY_FAST_TRAINING - #define mmDP_DPHY_FAST_TRAINING 0x4ABC - #define mmDP0_DP_DPHY_FAST_TRAINING 0x4ABC - #define mmDP1_DP_DPHY_FAST_TRAINING 0x4BBC - #define mmDP2_DP_DPHY_FAST_TRAINING 0x4CBC - #define mmDP3_DP_DPHY_FAST_TRAINING 0x4DBC - #define mmDP4_DP_DPHY_FAST_TRAINING 0x4EBC - #define mmDP5_DP_DPHY_FAST_TRAINING 0x4FBC - #define mmDP6_DP_DPHY_FAST_TRAINING 0x54BC -#endif - -#ifndef DPHY_RX_FAST_TRAINING_CAPABLE - #define DPHY_RX_FAST_TRAINING_CAPABLE 0x1 -#endif - -static const struct dce110_timing_generator_offsets dce110_tg_offsets[] = { - { - .crtc = (mmCRTC0_CRTC_CONTROL - mmCRTC_CONTROL), - .dcp = (mmDCP0_GRPH_CONTROL - mmGRPH_CONTROL), - }, - { - .crtc = (mmCRTC1_CRTC_CONTROL - mmCRTC_CONTROL), - .dcp = (mmDCP1_GRPH_CONTROL - mmGRPH_CONTROL), - }, - { - .crtc = (mmCRTC2_CRTC_CONTROL - mmCRTC_CONTROL), - .dcp = (mmDCP2_GRPH_CONTROL - mmGRPH_CONTROL), - }, - { - .crtc = (mmCRTC3_CRTC_CONTROL - mmCRTC_CONTROL), - .dcp = (mmDCP3_GRPH_CONTROL - mmGRPH_CONTROL), - }, - { - .crtc = (mmCRTC4_CRTC_CONTROL - mmCRTC_CONTROL), - .dcp = (mmDCP4_GRPH_CONTROL - mmGRPH_CONTROL), - }, - { - .crtc = (mmCRTC5_CRTC_CONTROL - mmCRTC_CONTROL), - .dcp = (mmDCP5_GRPH_CONTROL - mmGRPH_CONTROL), - } -}; - -/* set register offset */ -#define SR(reg_name)\ - .reg_name = mm ## reg_name - -/* set register offset with instance */ -#define SRI(reg_name, block, id)\ - .reg_name = mm ## block ## id ## _ ## reg_name - -static const struct dce_dmcu_registers dmcu_regs = { - DMCU_DCE110_COMMON_REG_LIST() -}; - -static const struct dce_dmcu_shift dmcu_shift = { - DMCU_MASK_SH_LIST_DCE110(__SHIFT) -}; - -static const struct dce_dmcu_mask dmcu_mask = { - DMCU_MASK_SH_LIST_DCE110(_MASK) -}; - -static const struct dce_abm_registers abm_regs = { - ABM_DCE110_COMMON_REG_LIST() -}; - -static const struct dce_abm_shift abm_shift = { - ABM_MASK_SH_LIST_DCE110(__SHIFT) -}; - -static const struct dce_abm_mask abm_mask = { - ABM_MASK_SH_LIST_DCE110(_MASK) -}; - -#define ipp_regs(id)\ -[id] = {\ - IPP_DCE110_REG_LIST_DCE_BASE(id)\ -} - -static const struct dce_ipp_registers ipp_regs[] = { - ipp_regs(0), - ipp_regs(1), - ipp_regs(2) -}; - -static const struct dce_ipp_shift ipp_shift = { - IPP_DCE100_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) -}; - -static const struct dce_ipp_mask ipp_mask = { - IPP_DCE100_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) -}; - -#define transform_regs(id)\ -[id] = {\ - XFM_COMMON_REG_LIST_DCE110(id)\ -} - -static const struct dce_transform_registers xfm_regs[] = { - transform_regs(0), - transform_regs(1), - transform_regs(2) -}; - -static const struct dce_transform_shift xfm_shift = { - XFM_COMMON_MASK_SH_LIST_DCE110(__SHIFT) -}; - -static const struct dce_transform_mask xfm_mask = { - XFM_COMMON_MASK_SH_LIST_DCE110(_MASK) -}; - -#define aux_regs(id)\ -[id] = {\ - AUX_REG_LIST(id)\ -} - -static const struct dce110_link_enc_aux_registers link_enc_aux_regs[] = { - aux_regs(0), - aux_regs(1), - aux_regs(2), - aux_regs(3), - aux_regs(4), - aux_regs(5) -}; - -#define hpd_regs(id)\ -[id] = {\ - HPD_REG_LIST(id)\ -} - -static const struct dce110_link_enc_hpd_registers link_enc_hpd_regs[] = { - hpd_regs(0), - hpd_regs(1), - hpd_regs(2), - hpd_regs(3), - hpd_regs(4), - hpd_regs(5) -}; - - -#define link_regs(id)\ -[id] = {\ - LE_DCE110_REG_LIST(id)\ -} - -static const struct dce110_link_enc_registers link_enc_regs[] = { - link_regs(0), - link_regs(1), - link_regs(2), - link_regs(3), - link_regs(4), - link_regs(5), - link_regs(6), -}; - -#define stream_enc_regs(id)\ -[id] = {\ - SE_COMMON_REG_LIST(id),\ - .TMDS_CNTL = 0,\ -} - -static const struct dce110_stream_enc_registers stream_enc_regs[] = { - stream_enc_regs(0), - stream_enc_regs(1), - stream_enc_regs(2) -}; - -static const struct dce_stream_encoder_shift se_shift = { - SE_COMMON_MASK_SH_LIST_DCE110(__SHIFT) -}; - -static const struct dce_stream_encoder_mask se_mask = { - SE_COMMON_MASK_SH_LIST_DCE110(_MASK) -}; - -static const struct dce_panel_cntl_registers panel_cntl_regs[] = { - { DCE_PANEL_CNTL_REG_LIST() } -}; - -static const struct dce_panel_cntl_shift panel_cntl_shift = { - DCE_PANEL_CNTL_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_panel_cntl_mask panel_cntl_mask = { - DCE_PANEL_CNTL_MASK_SH_LIST(_MASK) -}; - -static const struct dce110_aux_registers_shift aux_shift = { - DCE_AUX_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce110_aux_registers_mask aux_mask = { - DCE_AUX_MASK_SH_LIST(_MASK) -}; - -#define opp_regs(id)\ -[id] = {\ - OPP_DCE_110_REG_LIST(id),\ -} - -static const struct dce_opp_registers opp_regs[] = { - opp_regs(0), - opp_regs(1), - opp_regs(2), - opp_regs(3), - opp_regs(4), - opp_regs(5) -}; - -static const struct dce_opp_shift opp_shift = { - OPP_COMMON_MASK_SH_LIST_DCE_110(__SHIFT) -}; - -static const struct dce_opp_mask opp_mask = { - OPP_COMMON_MASK_SH_LIST_DCE_110(_MASK) -}; - -#define aux_engine_regs(id)\ -[id] = {\ - AUX_COMMON_REG_LIST(id), \ - .AUX_RESET_MASK = 0 \ -} - -static const struct dce110_aux_registers aux_engine_regs[] = { - aux_engine_regs(0), - aux_engine_regs(1), - aux_engine_regs(2), - aux_engine_regs(3), - aux_engine_regs(4), - aux_engine_regs(5) -}; - -#define audio_regs(id)\ -[id] = {\ - AUD_COMMON_REG_LIST(id)\ -} - -static const struct dce_audio_registers audio_regs[] = { - audio_regs(0), - audio_regs(1), - audio_regs(2), - audio_regs(3), - audio_regs(4), - audio_regs(5), - audio_regs(6), -}; - -static const struct dce_audio_shift audio_shift = { - AUD_COMMON_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_audio_mask audio_mask = { - AUD_COMMON_MASK_SH_LIST(_MASK) -}; - -/* AG TBD Needs to be reduced back to 3 pipes once dce10 hw sequencer implemented. */ - - -#define clk_src_regs(id)\ -[id] = {\ - CS_COMMON_REG_LIST_DCE_100_110(id),\ -} - -static const struct dce110_clk_src_regs clk_src_regs[] = { - clk_src_regs(0), - clk_src_regs(1), - clk_src_regs(2) -}; - -static const struct dce110_clk_src_shift cs_shift = { - CS_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) -}; - -static const struct dce110_clk_src_mask cs_mask = { - CS_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) -}; - -static const struct bios_registers bios_regs = { - .BIOS_SCRATCH_3 = mmBIOS_SCRATCH_3, - .BIOS_SCRATCH_6 = mmBIOS_SCRATCH_6 -}; - -static const struct resource_caps carrizo_resource_cap = { - .num_timing_generator = 3, - .num_video_plane = 1, - .num_audio = 3, - .num_stream_encoder = 3, - .num_pll = 2, - .num_ddc = 3, -}; - -static const struct resource_caps stoney_resource_cap = { - .num_timing_generator = 2, - .num_video_plane = 1, - .num_audio = 3, - .num_stream_encoder = 3, - .num_pll = 2, - .num_ddc = 3, -}; - -static const struct dc_plane_cap plane_cap = { - .type = DC_PLANE_TYPE_DCE_RGB, - .per_pixel_alpha = 1, - - .pixel_format_support = { - .argb8888 = true, - .nv12 = false, - .fp16 = true - }, - - .max_upscale_factor = { - .argb8888 = 16000, - .nv12 = 1, - .fp16 = 1 - }, - - .max_downscale_factor = { - .argb8888 = 250, - .nv12 = 1, - .fp16 = 1 - }, - 64, - 64 -}; - -static const struct dc_debug_options debug_defaults = { - .enable_legacy_fast_update = true, -}; - -static const struct dc_plane_cap underlay_plane_cap = { - .type = DC_PLANE_TYPE_DCE_UNDERLAY, - .per_pixel_alpha = 1, - - .pixel_format_support = { - .argb8888 = false, - .nv12 = true, - .fp16 = false - }, - - .max_upscale_factor = { - .argb8888 = 1, - .nv12 = 16000, - .fp16 = 1 - }, - - .max_downscale_factor = { - .argb8888 = 1, - .nv12 = 250, - .fp16 = 1 - }, - 64, - 64 -}; - -#define CTX ctx -#define REG(reg) mm ## reg - -#ifndef mmCC_DC_HDMI_STRAPS -#define mmCC_DC_HDMI_STRAPS 0x4819 -#define CC_DC_HDMI_STRAPS__HDMI_DISABLE_MASK 0x40 -#define CC_DC_HDMI_STRAPS__HDMI_DISABLE__SHIFT 0x6 -#define CC_DC_HDMI_STRAPS__AUDIO_STREAM_NUMBER_MASK 0x700 -#define CC_DC_HDMI_STRAPS__AUDIO_STREAM_NUMBER__SHIFT 0x8 -#endif - -static int map_transmitter_id_to_phy_instance( - enum transmitter transmitter) -{ - switch (transmitter) { - case TRANSMITTER_UNIPHY_A: - return 0; - case TRANSMITTER_UNIPHY_B: - return 1; - case TRANSMITTER_UNIPHY_C: - return 2; - case TRANSMITTER_UNIPHY_D: - return 3; - case TRANSMITTER_UNIPHY_E: - return 4; - case TRANSMITTER_UNIPHY_F: - return 5; - case TRANSMITTER_UNIPHY_G: - return 6; - default: - ASSERT(0); - return 0; - } -} - -static void read_dce_straps( - struct dc_context *ctx, - struct resource_straps *straps) -{ - REG_GET_2(CC_DC_HDMI_STRAPS, - HDMI_DISABLE, &straps->hdmi_disable, - AUDIO_STREAM_NUMBER, &straps->audio_stream_number); - - REG_GET(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO, &straps->dc_pinstraps_audio); -} - -static struct audio *create_audio( - struct dc_context *ctx, unsigned int inst) -{ - return dce_audio_create(ctx, inst, - &audio_regs[inst], &audio_shift, &audio_mask); -} - -static struct timing_generator *dce110_timing_generator_create( - struct dc_context *ctx, - uint32_t instance, - const struct dce110_timing_generator_offsets *offsets) -{ - struct dce110_timing_generator *tg110 = - kzalloc(sizeof(struct dce110_timing_generator), GFP_KERNEL); - - if (!tg110) - return NULL; - - dce110_timing_generator_construct(tg110, ctx, instance, offsets); - return &tg110->base; -} - -static struct stream_encoder *dce110_stream_encoder_create( - enum engine_id eng_id, - struct dc_context *ctx) -{ - struct dce110_stream_encoder *enc110 = - kzalloc(sizeof(struct dce110_stream_encoder), GFP_KERNEL); - - if (!enc110) - return NULL; - - dce110_stream_encoder_construct(enc110, ctx, ctx->dc_bios, eng_id, - &stream_enc_regs[eng_id], - &se_shift, &se_mask); - return &enc110->base; -} - -#define SRII(reg_name, block, id)\ - .reg_name[id] = mm ## block ## id ## _ ## reg_name - -static const struct dce_hwseq_registers hwseq_stoney_reg = { - HWSEQ_ST_REG_LIST() -}; - -static const struct dce_hwseq_registers hwseq_cz_reg = { - HWSEQ_CZ_REG_LIST() -}; - -static const struct dce_hwseq_shift hwseq_shift = { - HWSEQ_DCE11_MASK_SH_LIST(__SHIFT), -}; - -static const struct dce_hwseq_mask hwseq_mask = { - HWSEQ_DCE11_MASK_SH_LIST(_MASK), -}; - -static struct dce_hwseq *dce110_hwseq_create( - struct dc_context *ctx) -{ - struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); - - if (hws) { - hws->ctx = ctx; - hws->regs = ASIC_REV_IS_STONEY(ctx->asic_id.hw_internal_rev) ? - &hwseq_stoney_reg : &hwseq_cz_reg; - hws->shifts = &hwseq_shift; - hws->masks = &hwseq_mask; - hws->wa.blnd_crtc_trigger = true; - } - return hws; -} - -static const struct resource_create_funcs res_create_funcs = { - .read_dce_straps = read_dce_straps, - .create_audio = create_audio, - .create_stream_encoder = dce110_stream_encoder_create, - .create_hwseq = dce110_hwseq_create, -}; - -#define mi_inst_regs(id) { \ - MI_DCE11_REG_LIST(id), \ - .MC_HUB_RDREQ_DMIF_LIMIT = mmMC_HUB_RDREQ_DMIF_LIMIT \ -} -static const struct dce_mem_input_registers mi_regs[] = { - mi_inst_regs(0), - mi_inst_regs(1), - mi_inst_regs(2), -}; - -static const struct dce_mem_input_shift mi_shifts = { - MI_DCE11_MASK_SH_LIST(__SHIFT), - .ENABLE = MC_HUB_RDREQ_DMIF_LIMIT__ENABLE__SHIFT -}; - -static const struct dce_mem_input_mask mi_masks = { - MI_DCE11_MASK_SH_LIST(_MASK), - .ENABLE = MC_HUB_RDREQ_DMIF_LIMIT__ENABLE_MASK -}; - - -static struct mem_input *dce110_mem_input_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dce_mem_input *dce_mi = kzalloc(sizeof(struct dce_mem_input), - GFP_KERNEL); - - if (!dce_mi) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dce_mem_input_construct(dce_mi, ctx, inst, &mi_regs[inst], &mi_shifts, &mi_masks); - dce_mi->wa.single_head_rdreq_dmif_limit = 3; - return &dce_mi->base; -} - -static void dce110_transform_destroy(struct transform **xfm) -{ - kfree(TO_DCE_TRANSFORM(*xfm)); - *xfm = NULL; -} - -static struct transform *dce110_transform_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dce_transform *transform = - kzalloc(sizeof(struct dce_transform), GFP_KERNEL); - - if (!transform) - return NULL; - - dce_transform_construct(transform, ctx, inst, - &xfm_regs[inst], &xfm_shift, &xfm_mask); - return &transform->base; -} - -static struct input_pixel_processor *dce110_ipp_create( - struct dc_context *ctx, uint32_t inst) -{ - struct dce_ipp *ipp = kzalloc(sizeof(struct dce_ipp), GFP_KERNEL); - - if (!ipp) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dce_ipp_construct(ipp, ctx, inst, - &ipp_regs[inst], &ipp_shift, &ipp_mask); - return &ipp->base; -} - -static const struct encoder_feature_support link_enc_feature = { - .max_hdmi_deep_color = COLOR_DEPTH_121212, - .max_hdmi_pixel_clock = 300000, - .flags.bits.IS_HBR2_CAPABLE = true, - .flags.bits.IS_TPS3_CAPABLE = true -}; - -static struct link_encoder *dce110_link_encoder_create( - struct dc_context *ctx, - const struct encoder_init_data *enc_init_data) -{ - struct dce110_link_encoder *enc110 = - kzalloc(sizeof(struct dce110_link_encoder), GFP_KERNEL); - int link_regs_id; - - if (!enc110) - return NULL; - - link_regs_id = - map_transmitter_id_to_phy_instance(enc_init_data->transmitter); - - dce110_link_encoder_construct(enc110, - enc_init_data, - &link_enc_feature, - &link_enc_regs[link_regs_id], - &link_enc_aux_regs[enc_init_data->channel - 1], - &link_enc_hpd_regs[enc_init_data->hpd_source]); - return &enc110->base; -} - -static struct panel_cntl *dce110_panel_cntl_create(const struct panel_cntl_init_data *init_data) -{ - struct dce_panel_cntl *panel_cntl = - kzalloc(sizeof(struct dce_panel_cntl), GFP_KERNEL); - - if (!panel_cntl) - return NULL; - - dce_panel_cntl_construct(panel_cntl, - init_data, - &panel_cntl_regs[init_data->inst], - &panel_cntl_shift, - &panel_cntl_mask); - - return &panel_cntl->base; -} - -static struct output_pixel_processor *dce110_opp_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dce110_opp *opp = - kzalloc(sizeof(struct dce110_opp), GFP_KERNEL); - - if (!opp) - return NULL; - - dce110_opp_construct(opp, - ctx, inst, &opp_regs[inst], &opp_shift, &opp_mask); - return &opp->base; -} - -static struct dce_aux *dce110_aux_engine_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct aux_engine_dce110 *aux_engine = - kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); - - if (!aux_engine) - return NULL; - - dce110_aux_engine_construct(aux_engine, ctx, inst, - SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, - &aux_engine_regs[inst], - &aux_mask, - &aux_shift, - ctx->dc->caps.extended_aux_timeout_support); - - return &aux_engine->base; -} -#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST(id) } - -static const struct dce_i2c_registers i2c_hw_regs[] = { - i2c_inst_regs(1), - i2c_inst_regs(2), - i2c_inst_regs(3), - i2c_inst_regs(4), - i2c_inst_regs(5), - i2c_inst_regs(6), -}; - -static const struct dce_i2c_shift i2c_shifts = { - I2C_COMMON_MASK_SH_LIST_DCE110(__SHIFT) -}; - -static const struct dce_i2c_mask i2c_masks = { - I2C_COMMON_MASK_SH_LIST_DCE110(_MASK) -}; - -static struct dce_i2c_hw *dce110_i2c_hw_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dce_i2c_hw *dce_i2c_hw = - kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); - - if (!dce_i2c_hw) - return NULL; - - dce100_i2c_hw_construct(dce_i2c_hw, ctx, inst, - &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); - - return dce_i2c_hw; -} -static struct clock_source *dce110_clock_source_create( - struct dc_context *ctx, - struct dc_bios *bios, - enum clock_source_id id, - const struct dce110_clk_src_regs *regs, - bool dp_clk_src) -{ - struct dce110_clk_src *clk_src = - kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); - - if (!clk_src) - return NULL; - - if (dce110_clk_src_construct(clk_src, ctx, bios, id, - regs, &cs_shift, &cs_mask)) { - clk_src->base.dp_clk_src = dp_clk_src; - return &clk_src->base; - } - - kfree(clk_src); - BREAK_TO_DEBUGGER(); - return NULL; -} - -static void dce110_clock_source_destroy(struct clock_source **clk_src) -{ - struct dce110_clk_src *dce110_clk_src; - - if (!clk_src) - return; - - dce110_clk_src = TO_DCE110_CLK_SRC(*clk_src); - - kfree(dce110_clk_src->dp_ss_params); - kfree(dce110_clk_src->hdmi_ss_params); - kfree(dce110_clk_src->dvi_ss_params); - - kfree(dce110_clk_src); - *clk_src = NULL; -} - -static void dce110_resource_destruct(struct dce110_resource_pool *pool) -{ - unsigned int i; - - for (i = 0; i < pool->base.pipe_count; i++) { - if (pool->base.opps[i] != NULL) - dce110_opp_destroy(&pool->base.opps[i]); - - if (pool->base.transforms[i] != NULL) - dce110_transform_destroy(&pool->base.transforms[i]); - - if (pool->base.ipps[i] != NULL) - dce_ipp_destroy(&pool->base.ipps[i]); - - if (pool->base.mis[i] != NULL) { - kfree(TO_DCE_MEM_INPUT(pool->base.mis[i])); - pool->base.mis[i] = NULL; - } - - if (pool->base.timing_generators[i] != NULL) { - kfree(DCE110TG_FROM_TG(pool->base.timing_generators[i])); - pool->base.timing_generators[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - if (pool->base.engines[i] != NULL) - dce110_engine_destroy(&pool->base.engines[i]); - if (pool->base.hw_i2cs[i] != NULL) { - kfree(pool->base.hw_i2cs[i]); - pool->base.hw_i2cs[i] = NULL; - } - if (pool->base.sw_i2cs[i] != NULL) { - kfree(pool->base.sw_i2cs[i]); - pool->base.sw_i2cs[i] = NULL; - } - } - - for (i = 0; i < pool->base.stream_enc_count; i++) { - if (pool->base.stream_enc[i] != NULL) - kfree(DCE110STRENC_FROM_STRENC(pool->base.stream_enc[i])); - } - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] != NULL) { - dce110_clock_source_destroy(&pool->base.clock_sources[i]); - } - } - - if (pool->base.dp_clock_source != NULL) - dce110_clock_source_destroy(&pool->base.dp_clock_source); - - for (i = 0; i < pool->base.audio_count; i++) { - if (pool->base.audios[i] != NULL) { - dce_aud_destroy(&pool->base.audios[i]); - } - } - - if (pool->base.abm != NULL) - dce_abm_destroy(&pool->base.abm); - - if (pool->base.dmcu != NULL) - dce_dmcu_destroy(&pool->base.dmcu); - - if (pool->base.irqs != NULL) { - dal_irq_service_destroy(&pool->base.irqs); - } -} - - -static void get_pixel_clock_parameters( - const struct pipe_ctx *pipe_ctx, - struct pixel_clk_params *pixel_clk_params) -{ - const struct dc_stream_state *stream = pipe_ctx->stream; - - /*TODO: is this halved for YCbCr 420? in that case we might want to move - * the pixel clock normalization for hdmi up to here instead of doing it - * in pll_adjust_pix_clk - */ - pixel_clk_params->requested_pix_clk_100hz = stream->timing.pix_clk_100hz; - pixel_clk_params->encoder_object_id = stream->link->link_enc->id; - pixel_clk_params->signal_type = pipe_ctx->stream->signal; - pixel_clk_params->controller_id = pipe_ctx->stream_res.tg->inst + 1; - /* TODO: un-hardcode*/ - pixel_clk_params->requested_sym_clk = LINK_RATE_LOW * - LINK_RATE_REF_FREQ_IN_KHZ; - pixel_clk_params->flags.ENABLE_SS = 0; - pixel_clk_params->color_depth = - stream->timing.display_color_depth; - pixel_clk_params->flags.DISPLAY_BLANKED = 1; - pixel_clk_params->flags.SUPPORT_YCBCR420 = (stream->timing.pixel_encoding == - PIXEL_ENCODING_YCBCR420); - pixel_clk_params->pixel_encoding = stream->timing.pixel_encoding; - if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR422) { - pixel_clk_params->color_depth = COLOR_DEPTH_888; - } - if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) { - pixel_clk_params->requested_pix_clk_100hz = pixel_clk_params->requested_pix_clk_100hz / 2; - } - if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING) - pixel_clk_params->requested_pix_clk_100hz *= 2; - -} - -void dce110_resource_build_pipe_hw_param(struct pipe_ctx *pipe_ctx) -{ - get_pixel_clock_parameters(pipe_ctx, &pipe_ctx->stream_res.pix_clk_params); - pipe_ctx->clock_source->funcs->get_pix_clk_dividers( - pipe_ctx->clock_source, - &pipe_ctx->stream_res.pix_clk_params, - &pipe_ctx->pll_settings); - resource_build_bit_depth_reduction_params(pipe_ctx->stream, - &pipe_ctx->stream->bit_depth_params); - pipe_ctx->stream->clamping.pixel_encoding = pipe_ctx->stream->timing.pixel_encoding; -} - -static bool is_surface_pixel_format_supported(struct pipe_ctx *pipe_ctx, unsigned int underlay_idx) -{ - if (pipe_ctx->pipe_idx != underlay_idx) - return true; - if (!pipe_ctx->plane_state) - return false; - if (pipe_ctx->plane_state->format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) - return false; - return true; -} - -static enum dc_status build_mapped_resource( - const struct dc *dc, - struct dc_state *context, - struct dc_stream_state *stream) -{ - struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream); - - if (!pipe_ctx) - return DC_ERROR_UNEXPECTED; - - if (!is_surface_pixel_format_supported(pipe_ctx, - dc->res_pool->underlay_pipe_index)) - return DC_SURFACE_PIXEL_FORMAT_UNSUPPORTED; - - dce110_resource_build_pipe_hw_param(pipe_ctx); - - /* TODO: validate audio ASIC caps, encoder */ - - resource_build_info_frame(pipe_ctx); - - return DC_OK; -} - -static bool dce110_validate_bandwidth( - struct dc *dc, - struct dc_state *context, - bool fast_validate) -{ - bool result = false; - - DC_LOG_BANDWIDTH_CALCS( - "%s: start", - __func__); - - if (bw_calcs( - dc->ctx, - dc->bw_dceip, - dc->bw_vbios, - context->res_ctx.pipe_ctx, - dc->res_pool->pipe_count, - &context->bw_ctx.bw.dce)) - result = true; - - if (!result) - DC_LOG_BANDWIDTH_VALIDATION("%s: %dx%d@%d Bandwidth validation failed!\n", - __func__, - context->streams[0]->timing.h_addressable, - context->streams[0]->timing.v_addressable, - context->streams[0]->timing.pix_clk_100hz / 10); - - if (memcmp(&dc->current_state->bw_ctx.bw.dce, - &context->bw_ctx.bw.dce, sizeof(context->bw_ctx.bw.dce))) { - - DC_LOG_BANDWIDTH_CALCS( - "%s: finish,\n" - "nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n" - "stutMark_b: %d stutMark_a: %d\n" - "nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n" - "stutMark_b: %d stutMark_a: %d\n" - "nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n" - "stutMark_b: %d stutMark_a: %d stutter_mode_enable: %d\n" - "cstate: %d pstate: %d nbpstate: %d sync: %d dispclk: %d\n" - "sclk: %d sclk_sleep: %d yclk: %d blackout_recovery_time_us: %d\n" - , - __func__, - context->bw_ctx.bw.dce.nbp_state_change_wm_ns[0].b_mark, - context->bw_ctx.bw.dce.nbp_state_change_wm_ns[0].a_mark, - context->bw_ctx.bw.dce.urgent_wm_ns[0].b_mark, - context->bw_ctx.bw.dce.urgent_wm_ns[0].a_mark, - context->bw_ctx.bw.dce.stutter_exit_wm_ns[0].b_mark, - context->bw_ctx.bw.dce.stutter_exit_wm_ns[0].a_mark, - context->bw_ctx.bw.dce.nbp_state_change_wm_ns[1].b_mark, - context->bw_ctx.bw.dce.nbp_state_change_wm_ns[1].a_mark, - context->bw_ctx.bw.dce.urgent_wm_ns[1].b_mark, - context->bw_ctx.bw.dce.urgent_wm_ns[1].a_mark, - context->bw_ctx.bw.dce.stutter_exit_wm_ns[1].b_mark, - context->bw_ctx.bw.dce.stutter_exit_wm_ns[1].a_mark, - context->bw_ctx.bw.dce.nbp_state_change_wm_ns[2].b_mark, - context->bw_ctx.bw.dce.nbp_state_change_wm_ns[2].a_mark, - context->bw_ctx.bw.dce.urgent_wm_ns[2].b_mark, - context->bw_ctx.bw.dce.urgent_wm_ns[2].a_mark, - context->bw_ctx.bw.dce.stutter_exit_wm_ns[2].b_mark, - context->bw_ctx.bw.dce.stutter_exit_wm_ns[2].a_mark, - context->bw_ctx.bw.dce.stutter_mode_enable, - context->bw_ctx.bw.dce.cpuc_state_change_enable, - context->bw_ctx.bw.dce.cpup_state_change_enable, - context->bw_ctx.bw.dce.nbp_state_change_enable, - context->bw_ctx.bw.dce.all_displays_in_sync, - context->bw_ctx.bw.dce.dispclk_khz, - context->bw_ctx.bw.dce.sclk_khz, - context->bw_ctx.bw.dce.sclk_deep_sleep_khz, - context->bw_ctx.bw.dce.yclk_khz, - context->bw_ctx.bw.dce.blackout_recovery_time_us); - } - return result; -} - -static enum dc_status dce110_validate_plane(const struct dc_plane_state *plane_state, - struct dc_caps *caps) -{ - if (((plane_state->dst_rect.width * 2) < plane_state->src_rect.width) || - ((plane_state->dst_rect.height * 2) < plane_state->src_rect.height)) - return DC_FAIL_SURFACE_VALIDATE; - - return DC_OK; -} - -static bool dce110_validate_surface_sets( - struct dc_state *context) -{ - int i, j; - - for (i = 0; i < context->stream_count; i++) { - if (context->stream_status[i].plane_count == 0) - continue; - - if (context->stream_status[i].plane_count > 2) - return false; - - for (j = 0; j < context->stream_status[i].plane_count; j++) { - struct dc_plane_state *plane = - context->stream_status[i].plane_states[j]; - - /* underlay validation */ - if (plane->format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) { - - if ((plane->src_rect.width > 1920 || - plane->src_rect.height > 1080)) - return false; - - /* we don't have the logic to support underlay - * only yet so block the use case where we get - * NV12 plane as top layer - */ - if (j == 0) - return false; - - /* irrespective of plane format, - * stream should be RGB encoded - */ - if (context->streams[i]->timing.pixel_encoding - != PIXEL_ENCODING_RGB) - return false; - - } - - } - } - - return true; -} - -static enum dc_status dce110_validate_global( - struct dc *dc, - struct dc_state *context) -{ - if (!dce110_validate_surface_sets(context)) - return DC_FAIL_SURFACE_VALIDATE; - - return DC_OK; -} - -static enum dc_status dce110_add_stream_to_ctx( - struct dc *dc, - struct dc_state *new_ctx, - struct dc_stream_state *dc_stream) -{ - enum dc_status result = DC_ERROR_UNEXPECTED; - - result = resource_map_pool_resources(dc, new_ctx, dc_stream); - - if (result == DC_OK) - result = resource_map_clock_resources(dc, new_ctx, dc_stream); - - - if (result == DC_OK) - result = build_mapped_resource(dc, new_ctx, dc_stream); - - return result; -} - -static struct pipe_ctx *dce110_acquire_underlay( - const struct dc_state *cur_ctx, - struct dc_state *new_ctx, - const struct resource_pool *pool, - const struct pipe_ctx *opp_head_pipe) -{ - struct dc_stream_state *stream = opp_head_pipe->stream; - struct dc *dc = stream->ctx->dc; - struct dce_hwseq *hws = dc->hwseq; - struct resource_context *res_ctx = &new_ctx->res_ctx; - unsigned int underlay_idx = pool->underlay_pipe_index; - struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[underlay_idx]; - - if (res_ctx->pipe_ctx[underlay_idx].stream) - return NULL; - - pipe_ctx->stream_res.tg = pool->timing_generators[underlay_idx]; - pipe_ctx->plane_res.mi = pool->mis[underlay_idx]; - /*pipe_ctx->plane_res.ipp = res_ctx->pool->ipps[underlay_idx];*/ - pipe_ctx->plane_res.xfm = pool->transforms[underlay_idx]; - pipe_ctx->stream_res.opp = pool->opps[underlay_idx]; - pipe_ctx->pipe_idx = underlay_idx; - - pipe_ctx->stream = stream; - - if (!dc->current_state->res_ctx.pipe_ctx[underlay_idx].stream) { - struct tg_color black_color = {0}; - struct dc_bios *dcb = dc->ctx->dc_bios; - - hws->funcs.enable_display_power_gating( - dc, - pipe_ctx->stream_res.tg->inst, - dcb, PIPE_GATING_CONTROL_DISABLE); - - /* - * This is for powering on underlay, so crtc does not - * need to be enabled - */ - - pipe_ctx->stream_res.tg->funcs->program_timing(pipe_ctx->stream_res.tg, - &stream->timing, - 0, - 0, - 0, - 0, - pipe_ctx->stream->signal, - false); - - pipe_ctx->stream_res.tg->funcs->enable_advanced_request( - pipe_ctx->stream_res.tg, - true, - &stream->timing); - - pipe_ctx->plane_res.mi->funcs->allocate_mem_input(pipe_ctx->plane_res.mi, - stream->timing.h_total, - stream->timing.v_total, - stream->timing.pix_clk_100hz / 10, - new_ctx->stream_count); - - color_space_to_black_color(dc, - COLOR_SPACE_YCBCR601, &black_color); - pipe_ctx->stream_res.tg->funcs->set_blank_color( - pipe_ctx->stream_res.tg, - &black_color); - } - - return pipe_ctx; -} - -static void dce110_destroy_resource_pool(struct resource_pool **pool) -{ - struct dce110_resource_pool *dce110_pool = TO_DCE110_RES_POOL(*pool); - - dce110_resource_destruct(dce110_pool); - kfree(dce110_pool); - *pool = NULL; -} - -struct stream_encoder *dce110_find_first_free_match_stream_enc_for_link( - struct resource_context *res_ctx, - const struct resource_pool *pool, - struct dc_stream_state *stream) -{ - int i; - int j = -1; - struct dc_link *link = stream->link; - - for (i = 0; i < pool->stream_enc_count; i++) { - if (!res_ctx->is_stream_enc_acquired[i] && - pool->stream_enc[i]) { - /* Store first available for MST second display - * in daisy chain use case - */ - j = i; - if (pool->stream_enc[i]->id == - link->link_enc->preferred_engine) - return pool->stream_enc[i]; - } - } - - /* - * For CZ and later, we can allow DIG FE and BE to differ for all display types - */ - - if (j >= 0) - return pool->stream_enc[j]; - - return NULL; -} - - -static const struct resource_funcs dce110_res_pool_funcs = { - .destroy = dce110_destroy_resource_pool, - .link_enc_create = dce110_link_encoder_create, - .panel_cntl_create = dce110_panel_cntl_create, - .validate_bandwidth = dce110_validate_bandwidth, - .validate_plane = dce110_validate_plane, - .acquire_free_pipe_as_secondary_dpp_pipe = dce110_acquire_underlay, - .add_stream_to_ctx = dce110_add_stream_to_ctx, - .validate_global = dce110_validate_global, - .find_first_free_match_stream_enc_for_link = dce110_find_first_free_match_stream_enc_for_link -}; - -static bool underlay_create(struct dc_context *ctx, struct resource_pool *pool) -{ - struct dce110_timing_generator *dce110_tgv = kzalloc(sizeof(*dce110_tgv), - GFP_KERNEL); - struct dce_transform *dce110_xfmv = kzalloc(sizeof(*dce110_xfmv), - GFP_KERNEL); - struct dce_mem_input *dce110_miv = kzalloc(sizeof(*dce110_miv), - GFP_KERNEL); - struct dce110_opp *dce110_oppv = kzalloc(sizeof(*dce110_oppv), - GFP_KERNEL); - - if (!dce110_tgv || !dce110_xfmv || !dce110_miv || !dce110_oppv) { - kfree(dce110_tgv); - kfree(dce110_xfmv); - kfree(dce110_miv); - kfree(dce110_oppv); - return false; - } - - dce110_opp_v_construct(dce110_oppv, ctx); - - dce110_timing_generator_v_construct(dce110_tgv, ctx); - dce110_mem_input_v_construct(dce110_miv, ctx); - dce110_transform_v_construct(dce110_xfmv, ctx); - - pool->opps[pool->pipe_count] = &dce110_oppv->base; - pool->timing_generators[pool->pipe_count] = &dce110_tgv->base; - pool->mis[pool->pipe_count] = &dce110_miv->base; - pool->transforms[pool->pipe_count] = &dce110_xfmv->base; - pool->pipe_count++; - - /* update the public caps to indicate an underlay is available */ - ctx->dc->caps.max_slave_planes = 1; - ctx->dc->caps.max_slave_yuv_planes = 1; - ctx->dc->caps.max_slave_rgb_planes = 0; - - return true; -} - -static void bw_calcs_data_update_from_pplib(struct dc *dc) -{ - struct dm_pp_clock_levels clks = {0}; - - /*do system clock*/ - dm_pp_get_clock_levels_by_type( - dc->ctx, - DM_PP_CLOCK_TYPE_ENGINE_CLK, - &clks); - /* convert all the clock fro kHz to fix point mHz */ - dc->bw_vbios->high_sclk = bw_frc_to_fixed( - clks.clocks_in_khz[clks.num_levels-1], 1000); - dc->bw_vbios->mid1_sclk = bw_frc_to_fixed( - clks.clocks_in_khz[clks.num_levels/8], 1000); - dc->bw_vbios->mid2_sclk = bw_frc_to_fixed( - clks.clocks_in_khz[clks.num_levels*2/8], 1000); - dc->bw_vbios->mid3_sclk = bw_frc_to_fixed( - clks.clocks_in_khz[clks.num_levels*3/8], 1000); - dc->bw_vbios->mid4_sclk = bw_frc_to_fixed( - clks.clocks_in_khz[clks.num_levels*4/8], 1000); - dc->bw_vbios->mid5_sclk = bw_frc_to_fixed( - clks.clocks_in_khz[clks.num_levels*5/8], 1000); - dc->bw_vbios->mid6_sclk = bw_frc_to_fixed( - clks.clocks_in_khz[clks.num_levels*6/8], 1000); - dc->bw_vbios->low_sclk = bw_frc_to_fixed( - clks.clocks_in_khz[0], 1000); - dc->sclk_lvls = clks; - - /*do display clock*/ - dm_pp_get_clock_levels_by_type( - dc->ctx, - DM_PP_CLOCK_TYPE_DISPLAY_CLK, - &clks); - dc->bw_vbios->high_voltage_max_dispclk = bw_frc_to_fixed( - clks.clocks_in_khz[clks.num_levels-1], 1000); - dc->bw_vbios->mid_voltage_max_dispclk = bw_frc_to_fixed( - clks.clocks_in_khz[clks.num_levels>>1], 1000); - dc->bw_vbios->low_voltage_max_dispclk = bw_frc_to_fixed( - clks.clocks_in_khz[0], 1000); - - /*do memory clock*/ - dm_pp_get_clock_levels_by_type( - dc->ctx, - DM_PP_CLOCK_TYPE_MEMORY_CLK, - &clks); - - dc->bw_vbios->low_yclk = bw_frc_to_fixed( - clks.clocks_in_khz[0] * MEMORY_TYPE_MULTIPLIER_CZ, 1000); - dc->bw_vbios->mid_yclk = bw_frc_to_fixed( - clks.clocks_in_khz[clks.num_levels>>1] * MEMORY_TYPE_MULTIPLIER_CZ, - 1000); - dc->bw_vbios->high_yclk = bw_frc_to_fixed( - clks.clocks_in_khz[clks.num_levels-1] * MEMORY_TYPE_MULTIPLIER_CZ, - 1000); -} - -static const struct resource_caps *dce110_resource_cap( - struct hw_asic_id *asic_id) -{ - if (ASIC_REV_IS_STONEY(asic_id->hw_internal_rev)) - return &stoney_resource_cap; - else - return &carrizo_resource_cap; -} - -static bool dce110_resource_construct( - uint8_t num_virtual_links, - struct dc *dc, - struct dce110_resource_pool *pool, - struct hw_asic_id asic_id) -{ - unsigned int i; - struct dc_context *ctx = dc->ctx; - struct dc_bios *bp; - - ctx->dc_bios->regs = &bios_regs; - - pool->base.res_cap = dce110_resource_cap(&ctx->asic_id); - pool->base.funcs = &dce110_res_pool_funcs; - - /************************************************* - * Resource + asic cap harcoding * - *************************************************/ - - pool->base.pipe_count = pool->base.res_cap->num_timing_generator; - pool->base.underlay_pipe_index = pool->base.pipe_count; - pool->base.timing_generator_count = pool->base.res_cap->num_timing_generator; - dc->caps.max_downscale_ratio = 150; - dc->caps.i2c_speed_in_khz = 40; - dc->caps.i2c_speed_in_khz_hdcp = 40; - dc->caps.max_cursor_size = 128; - dc->caps.min_horizontal_blanking_period = 80; - dc->caps.is_apu = true; - dc->caps.extended_aux_timeout_support = false; - dc->debug = debug_defaults; - - /************************************************* - * Create resources * - *************************************************/ - - bp = ctx->dc_bios; - - if (bp->fw_info_valid && bp->fw_info.external_clock_source_frequency_for_dp != 0) { - pool->base.dp_clock_source = - dce110_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_EXTERNAL, NULL, true); - - pool->base.clock_sources[0] = - dce110_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL0, - &clk_src_regs[0], false); - pool->base.clock_sources[1] = - dce110_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL1, - &clk_src_regs[1], false); - - pool->base.clk_src_count = 2; - - /* TODO: find out if CZ support 3 PLLs */ - } - - if (pool->base.dp_clock_source == NULL) { - dm_error("DC: failed to create dp clock source!\n"); - BREAK_TO_DEBUGGER(); - goto res_create_fail; - } - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] == NULL) { - dm_error("DC: failed to create clock sources!\n"); - BREAK_TO_DEBUGGER(); - goto res_create_fail; - } - } - - pool->base.dmcu = dce_dmcu_create(ctx, - &dmcu_regs, - &dmcu_shift, - &dmcu_mask); - if (pool->base.dmcu == NULL) { - dm_error("DC: failed to create dmcu!\n"); - BREAK_TO_DEBUGGER(); - goto res_create_fail; - } - - pool->base.abm = dce_abm_create(ctx, - &abm_regs, - &abm_shift, - &abm_mask); - if (pool->base.abm == NULL) { - dm_error("DC: failed to create abm!\n"); - BREAK_TO_DEBUGGER(); - goto res_create_fail; - } - - { - struct irq_service_init_data init_data; - init_data.ctx = dc->ctx; - pool->base.irqs = dal_irq_service_dce110_create(&init_data); - if (!pool->base.irqs) - goto res_create_fail; - } - - for (i = 0; i < pool->base.pipe_count; i++) { - pool->base.timing_generators[i] = dce110_timing_generator_create( - ctx, i, &dce110_tg_offsets[i]); - if (pool->base.timing_generators[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create tg!\n"); - goto res_create_fail; - } - - pool->base.mis[i] = dce110_mem_input_create(ctx, i); - if (pool->base.mis[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create memory input!\n"); - goto res_create_fail; - } - - pool->base.ipps[i] = dce110_ipp_create(ctx, i); - if (pool->base.ipps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create input pixel processor!\n"); - goto res_create_fail; - } - - pool->base.transforms[i] = dce110_transform_create(ctx, i); - if (pool->base.transforms[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create transform!\n"); - goto res_create_fail; - } - - pool->base.opps[i] = dce110_opp_create(ctx, i); - if (pool->base.opps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create output pixel processor!\n"); - goto res_create_fail; - } - } - - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - pool->base.engines[i] = dce110_aux_engine_create(ctx, i); - if (pool->base.engines[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create aux engine!!\n"); - goto res_create_fail; - } - pool->base.hw_i2cs[i] = dce110_i2c_hw_create(ctx, i); - if (pool->base.hw_i2cs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create i2c engine!!\n"); - goto res_create_fail; - } - pool->base.sw_i2cs[i] = NULL; - } - - if (dc->config.fbc_support) - dc->fbc_compressor = dce110_compressor_create(ctx); - - if (!underlay_create(ctx, &pool->base)) - goto res_create_fail; - - if (!resource_construct(num_virtual_links, dc, &pool->base, - &res_create_funcs)) - goto res_create_fail; - - /* Create hardware sequencer */ - dce110_hw_sequencer_construct(dc); - - dc->caps.max_planes = pool->base.pipe_count; - - for (i = 0; i < pool->base.underlay_pipe_index; ++i) - dc->caps.planes[i] = plane_cap; - - dc->caps.planes[pool->base.underlay_pipe_index] = underlay_plane_cap; - - bw_calcs_init(dc->bw_dceip, dc->bw_vbios, dc->ctx->asic_id); - - bw_calcs_data_update_from_pplib(dc); - - return true; - -res_create_fail: - dce110_resource_destruct(pool); - return false; -} - -struct resource_pool *dce110_create_resource_pool( - uint8_t num_virtual_links, - struct dc *dc, - struct hw_asic_id asic_id) -{ - struct dce110_resource_pool *pool = - kzalloc(sizeof(struct dce110_resource_pool), GFP_KERNEL); - - if (!pool) - return NULL; - - if (dce110_resource_construct(num_virtual_links, dc, pool, asic_id)) - return &pool->base; - - kfree(pool); - BREAK_TO_DEBUGGER(); - return NULL; -} diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.h b/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.h deleted file mode 100644 index aa4531e0800e69..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.h +++ /dev/null @@ -1,54 +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 __DC_RESOURCE_DCE110_H__ -#define __DC_RESOURCE_DCE110_H__ - -#include "core_types.h" - -struct dc; -struct resource_pool; - -#define TO_DCE110_RES_POOL(pool)\ - container_of(pool, struct dce110_resource_pool, base) - -struct dce110_resource_pool { - struct resource_pool base; -}; - -void dce110_resource_build_pipe_hw_param(struct pipe_ctx *pipe_ctx); - -struct resource_pool *dce110_create_resource_pool( - uint8_t num_virtual_links, - struct dc *dc, - struct hw_asic_id asic_id); - -struct stream_encoder *dce110_find_first_free_match_stream_enc_for_link( - struct resource_context *res_ctx, - const struct resource_pool *pool, - struct dc_stream_state *stream); - -#endif /* __DC_RESOURCE_DCE110_H__ */ - diff --git a/drivers/gpu/drm/amd/display/dc/dce112/Makefile b/drivers/gpu/drm/amd/display/dc/dce112/Makefile index e846ef58cab3f2..7e92effec89447 100644 --- a/drivers/gpu/drm/amd/display/dc/dce112/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dce112/Makefile @@ -25,8 +25,7 @@ CFLAGS_$(AMDDALPATH)/dc/dce112/dce112_resource.o = $(call cc-disable-warning, override-init) -DCE112 = dce112_compressor.o \ -dce112_resource.o +DCE112 = dce112_compressor.o AMD_DAL_DCE112 = $(addprefix $(AMDDALPATH)/dc/dce112/,$(DCE112)) diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c deleted file mode 100644 index d1edac46c9a089..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c +++ /dev/null @@ -1,1431 +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 - * - */ - -#include "dm_services.h" - -#include "link_encoder.h" -#include "stream_encoder.h" - -#include "resource.h" -#include "include/irq_service_interface.h" -#include "dce110/dce110_resource.h" -#include "dce110/dce110_timing_generator.h" - -#include "irq/dce110/irq_service_dce110.h" -#include "dce/dce_mem_input.h" -#include "dce/dce_transform.h" -#include "dce/dce_link_encoder.h" -#include "dce/dce_stream_encoder.h" -#include "dce/dce_audio.h" -#include "dce/dce_opp.h" -#include "dce/dce_ipp.h" -#include "dce/dce_clock_source.h" - -#include "dce/dce_hwseq.h" -#include "dce112/dce112_hwseq.h" -#include "dce/dce_abm.h" -#include "dce/dce_dmcu.h" -#include "dce/dce_aux.h" -#include "dce/dce_i2c.h" -#include "dce/dce_panel_cntl.h" - -#include "reg_helper.h" - -#include "dce/dce_11_2_d.h" -#include "dce/dce_11_2_sh_mask.h" - -#include "dce100/dce100_resource.h" -#include "dce112_resource.h" - -#define DC_LOGGER \ - dc->ctx->logger - -#ifndef mmDP_DPHY_INTERNAL_CTRL - #define mmDP_DPHY_INTERNAL_CTRL 0x4aa7 - #define mmDP0_DP_DPHY_INTERNAL_CTRL 0x4aa7 - #define mmDP1_DP_DPHY_INTERNAL_CTRL 0x4ba7 - #define mmDP2_DP_DPHY_INTERNAL_CTRL 0x4ca7 - #define mmDP3_DP_DPHY_INTERNAL_CTRL 0x4da7 - #define mmDP4_DP_DPHY_INTERNAL_CTRL 0x4ea7 - #define mmDP5_DP_DPHY_INTERNAL_CTRL 0x4fa7 - #define mmDP6_DP_DPHY_INTERNAL_CTRL 0x54a7 - #define mmDP7_DP_DPHY_INTERNAL_CTRL 0x56a7 - #define mmDP8_DP_DPHY_INTERNAL_CTRL 0x57a7 -#endif - -#ifndef mmBIOS_SCRATCH_2 - #define mmBIOS_SCRATCH_2 0x05CB - #define mmBIOS_SCRATCH_3 0x05CC - #define mmBIOS_SCRATCH_6 0x05CF -#endif - -#ifndef mmDP_DPHY_BS_SR_SWAP_CNTL - #define mmDP_DPHY_BS_SR_SWAP_CNTL 0x4ADC - #define mmDP0_DP_DPHY_BS_SR_SWAP_CNTL 0x4ADC - #define mmDP1_DP_DPHY_BS_SR_SWAP_CNTL 0x4BDC - #define mmDP2_DP_DPHY_BS_SR_SWAP_CNTL 0x4CDC - #define mmDP3_DP_DPHY_BS_SR_SWAP_CNTL 0x4DDC - #define mmDP4_DP_DPHY_BS_SR_SWAP_CNTL 0x4EDC - #define mmDP5_DP_DPHY_BS_SR_SWAP_CNTL 0x4FDC - #define mmDP6_DP_DPHY_BS_SR_SWAP_CNTL 0x54DC -#endif - -#ifndef mmDP_DPHY_FAST_TRAINING - #define mmDP_DPHY_FAST_TRAINING 0x4ABC - #define mmDP0_DP_DPHY_FAST_TRAINING 0x4ABC - #define mmDP1_DP_DPHY_FAST_TRAINING 0x4BBC - #define mmDP2_DP_DPHY_FAST_TRAINING 0x4CBC - #define mmDP3_DP_DPHY_FAST_TRAINING 0x4DBC - #define mmDP4_DP_DPHY_FAST_TRAINING 0x4EBC - #define mmDP5_DP_DPHY_FAST_TRAINING 0x4FBC - #define mmDP6_DP_DPHY_FAST_TRAINING 0x54BC -#endif - -enum dce112_clk_src_array_id { - DCE112_CLK_SRC_PLL0, - DCE112_CLK_SRC_PLL1, - DCE112_CLK_SRC_PLL2, - DCE112_CLK_SRC_PLL3, - DCE112_CLK_SRC_PLL4, - DCE112_CLK_SRC_PLL5, - - DCE112_CLK_SRC_TOTAL -}; - -static const struct dce110_timing_generator_offsets dce112_tg_offsets[] = { - { - .crtc = (mmCRTC0_CRTC_CONTROL - mmCRTC_CONTROL), - .dcp = (mmDCP0_GRPH_CONTROL - mmGRPH_CONTROL), - }, - { - .crtc = (mmCRTC1_CRTC_CONTROL - mmCRTC_CONTROL), - .dcp = (mmDCP1_GRPH_CONTROL - mmGRPH_CONTROL), - }, - { - .crtc = (mmCRTC2_CRTC_CONTROL - mmCRTC_CONTROL), - .dcp = (mmDCP2_GRPH_CONTROL - mmGRPH_CONTROL), - }, - { - .crtc = (mmCRTC3_CRTC_CONTROL - mmCRTC_CONTROL), - .dcp = (mmDCP3_GRPH_CONTROL - mmGRPH_CONTROL), - }, - { - .crtc = (mmCRTC4_CRTC_CONTROL - mmCRTC_CONTROL), - .dcp = (mmDCP4_GRPH_CONTROL - mmGRPH_CONTROL), - }, - { - .crtc = (mmCRTC5_CRTC_CONTROL - mmCRTC_CONTROL), - .dcp = (mmDCP5_GRPH_CONTROL - mmGRPH_CONTROL), - } -}; - -/* set register offset */ -#define SR(reg_name)\ - .reg_name = mm ## reg_name - -/* set register offset with instance */ -#define SRI(reg_name, block, id)\ - .reg_name = mm ## block ## id ## _ ## reg_name - -static const struct dce_dmcu_registers dmcu_regs = { - DMCU_DCE110_COMMON_REG_LIST() -}; - -static const struct dce_dmcu_shift dmcu_shift = { - DMCU_MASK_SH_LIST_DCE110(__SHIFT) -}; - -static const struct dce_dmcu_mask dmcu_mask = { - DMCU_MASK_SH_LIST_DCE110(_MASK) -}; - -static const struct dce_abm_registers abm_regs = { - ABM_DCE110_COMMON_REG_LIST() -}; - -static const struct dce_abm_shift abm_shift = { - ABM_MASK_SH_LIST_DCE110(__SHIFT) -}; - -static const struct dce_abm_mask abm_mask = { - ABM_MASK_SH_LIST_DCE110(_MASK) -}; - -static const struct dce110_aux_registers_shift aux_shift = { - DCE_AUX_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce110_aux_registers_mask aux_mask = { - DCE_AUX_MASK_SH_LIST(_MASK) -}; - -#define ipp_regs(id)\ -[id] = {\ - IPP_DCE110_REG_LIST_DCE_BASE(id)\ -} - -static const struct dce_ipp_registers ipp_regs[] = { - ipp_regs(0), - ipp_regs(1), - ipp_regs(2), - ipp_regs(3), - ipp_regs(4), - ipp_regs(5) -}; - -static const struct dce_ipp_shift ipp_shift = { - IPP_DCE100_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) -}; - -static const struct dce_ipp_mask ipp_mask = { - IPP_DCE100_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) -}; - -#define transform_regs(id)\ -[id] = {\ - XFM_COMMON_REG_LIST_DCE110(id)\ -} - -static const struct dce_transform_registers xfm_regs[] = { - transform_regs(0), - transform_regs(1), - transform_regs(2), - transform_regs(3), - transform_regs(4), - transform_regs(5) -}; - -static const struct dce_transform_shift xfm_shift = { - XFM_COMMON_MASK_SH_LIST_DCE110(__SHIFT) -}; - -static const struct dce_transform_mask xfm_mask = { - XFM_COMMON_MASK_SH_LIST_DCE110(_MASK) -}; - -#define aux_regs(id)\ -[id] = {\ - AUX_REG_LIST(id)\ -} - -static const struct dce110_link_enc_aux_registers link_enc_aux_regs[] = { - aux_regs(0), - aux_regs(1), - aux_regs(2), - aux_regs(3), - aux_regs(4), - aux_regs(5) -}; - -static const struct dce_panel_cntl_registers panel_cntl_regs[] = { - { DCE_PANEL_CNTL_REG_LIST() } -}; - -static const struct dce_panel_cntl_shift panel_cntl_shift = { - DCE_PANEL_CNTL_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_panel_cntl_mask panel_cntl_mask = { - DCE_PANEL_CNTL_MASK_SH_LIST(_MASK) -}; - -#define hpd_regs(id)\ -[id] = {\ - HPD_REG_LIST(id)\ -} - -static const struct dce110_link_enc_hpd_registers link_enc_hpd_regs[] = { - hpd_regs(0), - hpd_regs(1), - hpd_regs(2), - hpd_regs(3), - hpd_regs(4), - hpd_regs(5) -}; - -#define link_regs(id)\ -[id] = {\ - LE_DCE110_REG_LIST(id)\ -} - -static const struct dce110_link_enc_registers link_enc_regs[] = { - link_regs(0), - link_regs(1), - link_regs(2), - link_regs(3), - link_regs(4), - link_regs(5), - link_regs(6), -}; - -#define stream_enc_regs(id)\ -[id] = {\ - SE_COMMON_REG_LIST(id),\ - .TMDS_CNTL = 0,\ -} - -static const struct dce110_stream_enc_registers stream_enc_regs[] = { - stream_enc_regs(0), - stream_enc_regs(1), - stream_enc_regs(2), - stream_enc_regs(3), - stream_enc_regs(4), - stream_enc_regs(5) -}; - -static const struct dce_stream_encoder_shift se_shift = { - SE_COMMON_MASK_SH_LIST_DCE112(__SHIFT) -}; - -static const struct dce_stream_encoder_mask se_mask = { - SE_COMMON_MASK_SH_LIST_DCE112(_MASK) -}; - -#define opp_regs(id)\ -[id] = {\ - OPP_DCE_112_REG_LIST(id),\ -} - -static const struct dce_opp_registers opp_regs[] = { - opp_regs(0), - opp_regs(1), - opp_regs(2), - opp_regs(3), - opp_regs(4), - opp_regs(5) -}; - -static const struct dce_opp_shift opp_shift = { - OPP_COMMON_MASK_SH_LIST_DCE_112(__SHIFT) -}; - -static const struct dce_opp_mask opp_mask = { - OPP_COMMON_MASK_SH_LIST_DCE_112(_MASK) -}; - -#define aux_engine_regs(id)\ -[id] = {\ - AUX_COMMON_REG_LIST(id), \ - .AUX_RESET_MASK = 0 \ -} - -static const struct dce110_aux_registers aux_engine_regs[] = { - aux_engine_regs(0), - aux_engine_regs(1), - aux_engine_regs(2), - aux_engine_regs(3), - aux_engine_regs(4), - aux_engine_regs(5) -}; - -#define audio_regs(id)\ -[id] = {\ - AUD_COMMON_REG_LIST(id)\ -} - -static const struct dce_audio_registers audio_regs[] = { - audio_regs(0), - audio_regs(1), - audio_regs(2), - audio_regs(3), - audio_regs(4), - audio_regs(5) -}; - -static const struct dce_audio_shift audio_shift = { - AUD_COMMON_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_audio_mask audio_mask = { - AUD_COMMON_MASK_SH_LIST(_MASK) -}; - -#define clk_src_regs(index, id)\ -[index] = {\ - CS_COMMON_REG_LIST_DCE_112(id),\ -} - -static const struct dce110_clk_src_regs clk_src_regs[] = { - clk_src_regs(0, A), - clk_src_regs(1, B), - clk_src_regs(2, C), - clk_src_regs(3, D), - clk_src_regs(4, E), - clk_src_regs(5, F) -}; - -static const struct dce110_clk_src_shift cs_shift = { - CS_COMMON_MASK_SH_LIST_DCE_112(__SHIFT) -}; - -static const struct dce110_clk_src_mask cs_mask = { - CS_COMMON_MASK_SH_LIST_DCE_112(_MASK) -}; - -static const struct bios_registers bios_regs = { - .BIOS_SCRATCH_3 = mmBIOS_SCRATCH_3, - .BIOS_SCRATCH_6 = mmBIOS_SCRATCH_6 -}; - -static const struct resource_caps polaris_10_resource_cap = { - .num_timing_generator = 6, - .num_audio = 6, - .num_stream_encoder = 6, - .num_pll = 8, /* why 8? 6 combo PHY PLL + 2 regular PLLs? */ - .num_ddc = 6, -}; - -static const struct resource_caps polaris_11_resource_cap = { - .num_timing_generator = 5, - .num_audio = 5, - .num_stream_encoder = 5, - .num_pll = 8, /* why 8? 6 combo PHY PLL + 2 regular PLLs? */ - .num_ddc = 5, -}; - -static const struct dc_plane_cap plane_cap = { - .type = DC_PLANE_TYPE_DCE_RGB, - - .pixel_format_support = { - .argb8888 = true, - .nv12 = false, - .fp16 = true - }, - - .max_upscale_factor = { - .argb8888 = 16000, - .nv12 = 1, - .fp16 = 1 - }, - - .max_downscale_factor = { - .argb8888 = 250, - .nv12 = 1, - .fp16 = 1 - }, - 64, - 64 -}; - -static const struct dc_debug_options debug_defaults = { - .enable_legacy_fast_update = true, -}; - -#define CTX ctx -#define REG(reg) mm ## reg - -#ifndef mmCC_DC_HDMI_STRAPS -#define mmCC_DC_HDMI_STRAPS 0x4819 -#define CC_DC_HDMI_STRAPS__HDMI_DISABLE_MASK 0x40 -#define CC_DC_HDMI_STRAPS__HDMI_DISABLE__SHIFT 0x6 -#define CC_DC_HDMI_STRAPS__AUDIO_STREAM_NUMBER_MASK 0x700 -#define CC_DC_HDMI_STRAPS__AUDIO_STREAM_NUMBER__SHIFT 0x8 -#endif - -static int map_transmitter_id_to_phy_instance( - enum transmitter transmitter) -{ - switch (transmitter) { - case TRANSMITTER_UNIPHY_A: - return 0; - case TRANSMITTER_UNIPHY_B: - return 1; - case TRANSMITTER_UNIPHY_C: - return 2; - case TRANSMITTER_UNIPHY_D: - return 3; - case TRANSMITTER_UNIPHY_E: - return 4; - case TRANSMITTER_UNIPHY_F: - return 5; - case TRANSMITTER_UNIPHY_G: - return 6; - default: - ASSERT(0); - return 0; - } -} - -static void read_dce_straps( - struct dc_context *ctx, - struct resource_straps *straps) -{ - REG_GET_2(CC_DC_HDMI_STRAPS, - HDMI_DISABLE, &straps->hdmi_disable, - AUDIO_STREAM_NUMBER, &straps->audio_stream_number); - - REG_GET(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO, &straps->dc_pinstraps_audio); -} - -static struct audio *create_audio( - struct dc_context *ctx, unsigned int inst) -{ - return dce_audio_create(ctx, inst, - &audio_regs[inst], &audio_shift, &audio_mask); -} - - -static struct timing_generator *dce112_timing_generator_create( - struct dc_context *ctx, - uint32_t instance, - const struct dce110_timing_generator_offsets *offsets) -{ - struct dce110_timing_generator *tg110 = - kzalloc(sizeof(struct dce110_timing_generator), GFP_KERNEL); - - if (!tg110) - return NULL; - - dce110_timing_generator_construct(tg110, ctx, instance, offsets); - return &tg110->base; -} - -static struct stream_encoder *dce112_stream_encoder_create( - enum engine_id eng_id, - struct dc_context *ctx) -{ - struct dce110_stream_encoder *enc110 = - kzalloc(sizeof(struct dce110_stream_encoder), GFP_KERNEL); - - if (!enc110) - return NULL; - - dce110_stream_encoder_construct(enc110, ctx, ctx->dc_bios, eng_id, - &stream_enc_regs[eng_id], - &se_shift, &se_mask); - return &enc110->base; -} - -#define SRII(reg_name, block, id)\ - .reg_name[id] = mm ## block ## id ## _ ## reg_name - -static const struct dce_hwseq_registers hwseq_reg = { - HWSEQ_DCE112_REG_LIST() -}; - -static const struct dce_hwseq_shift hwseq_shift = { - HWSEQ_DCE112_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_hwseq_mask hwseq_mask = { - HWSEQ_DCE112_MASK_SH_LIST(_MASK) -}; - -static struct dce_hwseq *dce112_hwseq_create( - struct dc_context *ctx) -{ - struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); - - if (hws) { - hws->ctx = ctx; - hws->regs = &hwseq_reg; - hws->shifts = &hwseq_shift; - hws->masks = &hwseq_mask; - } - return hws; -} - -static const struct resource_create_funcs res_create_funcs = { - .read_dce_straps = read_dce_straps, - .create_audio = create_audio, - .create_stream_encoder = dce112_stream_encoder_create, - .create_hwseq = dce112_hwseq_create, -}; - -#define mi_inst_regs(id) { MI_DCE11_2_REG_LIST(id) } -static const struct dce_mem_input_registers mi_regs[] = { - mi_inst_regs(0), - mi_inst_regs(1), - mi_inst_regs(2), - mi_inst_regs(3), - mi_inst_regs(4), - mi_inst_regs(5), -}; - -static const struct dce_mem_input_shift mi_shifts = { - MI_DCE11_2_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_mem_input_mask mi_masks = { - MI_DCE11_2_MASK_SH_LIST(_MASK) -}; - -static struct mem_input *dce112_mem_input_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dce_mem_input *dce_mi = kzalloc(sizeof(struct dce_mem_input), - GFP_KERNEL); - - if (!dce_mi) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dce112_mem_input_construct(dce_mi, ctx, inst, &mi_regs[inst], &mi_shifts, &mi_masks); - return &dce_mi->base; -} - -static void dce112_transform_destroy(struct transform **xfm) -{ - kfree(TO_DCE_TRANSFORM(*xfm)); - *xfm = NULL; -} - -static struct transform *dce112_transform_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dce_transform *transform = - kzalloc(sizeof(struct dce_transform), GFP_KERNEL); - - if (!transform) - return NULL; - - dce_transform_construct(transform, ctx, inst, - &xfm_regs[inst], &xfm_shift, &xfm_mask); - transform->lb_memory_size = 0x1404; /*5124*/ - return &transform->base; -} - -static const struct encoder_feature_support link_enc_feature = { - .max_hdmi_deep_color = COLOR_DEPTH_121212, - .max_hdmi_pixel_clock = 600000, - .hdmi_ycbcr420_supported = true, - .dp_ycbcr420_supported = false, - .flags.bits.IS_HBR2_CAPABLE = true, - .flags.bits.IS_HBR3_CAPABLE = true, - .flags.bits.IS_TPS3_CAPABLE = true, - .flags.bits.IS_TPS4_CAPABLE = true -}; - -static struct link_encoder *dce112_link_encoder_create( - struct dc_context *ctx, - const struct encoder_init_data *enc_init_data) -{ - struct dce110_link_encoder *enc110 = - kzalloc(sizeof(struct dce110_link_encoder), GFP_KERNEL); - int link_regs_id; - - if (!enc110) - return NULL; - - link_regs_id = - map_transmitter_id_to_phy_instance(enc_init_data->transmitter); - - dce110_link_encoder_construct(enc110, - enc_init_data, - &link_enc_feature, - &link_enc_regs[link_regs_id], - &link_enc_aux_regs[enc_init_data->channel - 1], - &link_enc_hpd_regs[enc_init_data->hpd_source]); - return &enc110->base; -} - -static struct panel_cntl *dce112_panel_cntl_create(const struct panel_cntl_init_data *init_data) -{ - struct dce_panel_cntl *panel_cntl = - kzalloc(sizeof(struct dce_panel_cntl), GFP_KERNEL); - - if (!panel_cntl) - return NULL; - - dce_panel_cntl_construct(panel_cntl, - init_data, - &panel_cntl_regs[init_data->inst], - &panel_cntl_shift, - &panel_cntl_mask); - - return &panel_cntl->base; -} - -static struct input_pixel_processor *dce112_ipp_create( - struct dc_context *ctx, uint32_t inst) -{ - struct dce_ipp *ipp = kzalloc(sizeof(struct dce_ipp), GFP_KERNEL); - - if (!ipp) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dce_ipp_construct(ipp, ctx, inst, - &ipp_regs[inst], &ipp_shift, &ipp_mask); - return &ipp->base; -} - -static struct output_pixel_processor *dce112_opp_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dce110_opp *opp = - kzalloc(sizeof(struct dce110_opp), GFP_KERNEL); - - if (!opp) - return NULL; - - dce110_opp_construct(opp, - ctx, inst, &opp_regs[inst], &opp_shift, &opp_mask); - return &opp->base; -} - -static struct dce_aux *dce112_aux_engine_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct aux_engine_dce110 *aux_engine = - kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); - - if (!aux_engine) - return NULL; - - dce110_aux_engine_construct(aux_engine, ctx, inst, - SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, - &aux_engine_regs[inst], - &aux_mask, - &aux_shift, - ctx->dc->caps.extended_aux_timeout_support); - - return &aux_engine->base; -} -#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST(id) } - -static const struct dce_i2c_registers i2c_hw_regs[] = { - i2c_inst_regs(1), - i2c_inst_regs(2), - i2c_inst_regs(3), - i2c_inst_regs(4), - i2c_inst_regs(5), - i2c_inst_regs(6), -}; - -static const struct dce_i2c_shift i2c_shifts = { - I2C_COMMON_MASK_SH_LIST_DCE110(__SHIFT) -}; - -static const struct dce_i2c_mask i2c_masks = { - I2C_COMMON_MASK_SH_LIST_DCE110(_MASK) -}; - -static struct dce_i2c_hw *dce112_i2c_hw_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dce_i2c_hw *dce_i2c_hw = - kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); - - if (!dce_i2c_hw) - return NULL; - - dce112_i2c_hw_construct(dce_i2c_hw, ctx, inst, - &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); - - return dce_i2c_hw; -} -static struct clock_source *dce112_clock_source_create( - struct dc_context *ctx, - struct dc_bios *bios, - enum clock_source_id id, - const struct dce110_clk_src_regs *regs, - bool dp_clk_src) -{ - struct dce110_clk_src *clk_src = - kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); - - if (!clk_src) - return NULL; - - if (dce112_clk_src_construct(clk_src, ctx, bios, id, - regs, &cs_shift, &cs_mask)) { - clk_src->base.dp_clk_src = dp_clk_src; - return &clk_src->base; - } - - kfree(clk_src); - BREAK_TO_DEBUGGER(); - return NULL; -} - -static void dce112_clock_source_destroy(struct clock_source **clk_src) -{ - kfree(TO_DCE110_CLK_SRC(*clk_src)); - *clk_src = NULL; -} - -static void dce112_resource_destruct(struct dce110_resource_pool *pool) -{ - unsigned int i; - - for (i = 0; i < pool->base.pipe_count; i++) { - if (pool->base.opps[i] != NULL) - dce110_opp_destroy(&pool->base.opps[i]); - - if (pool->base.transforms[i] != NULL) - dce112_transform_destroy(&pool->base.transforms[i]); - - if (pool->base.ipps[i] != NULL) - dce_ipp_destroy(&pool->base.ipps[i]); - - if (pool->base.mis[i] != NULL) { - kfree(TO_DCE_MEM_INPUT(pool->base.mis[i])); - pool->base.mis[i] = NULL; - } - - if (pool->base.timing_generators[i] != NULL) { - kfree(DCE110TG_FROM_TG(pool->base.timing_generators[i])); - pool->base.timing_generators[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - if (pool->base.engines[i] != NULL) - dce110_engine_destroy(&pool->base.engines[i]); - if (pool->base.hw_i2cs[i] != NULL) { - kfree(pool->base.hw_i2cs[i]); - pool->base.hw_i2cs[i] = NULL; - } - if (pool->base.sw_i2cs[i] != NULL) { - kfree(pool->base.sw_i2cs[i]); - pool->base.sw_i2cs[i] = NULL; - } - } - - for (i = 0; i < pool->base.stream_enc_count; i++) { - if (pool->base.stream_enc[i] != NULL) - kfree(DCE110STRENC_FROM_STRENC(pool->base.stream_enc[i])); - } - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] != NULL) { - dce112_clock_source_destroy(&pool->base.clock_sources[i]); - } - } - - if (pool->base.dp_clock_source != NULL) - dce112_clock_source_destroy(&pool->base.dp_clock_source); - - for (i = 0; i < pool->base.audio_count; i++) { - if (pool->base.audios[i] != NULL) { - dce_aud_destroy(&pool->base.audios[i]); - } - } - - if (pool->base.abm != NULL) - dce_abm_destroy(&pool->base.abm); - - if (pool->base.dmcu != NULL) - dce_dmcu_destroy(&pool->base.dmcu); - - if (pool->base.irqs != NULL) { - dal_irq_service_destroy(&pool->base.irqs); - } -} - -static struct clock_source *find_matching_pll( - struct resource_context *res_ctx, - const struct resource_pool *pool, - const struct dc_stream_state *const stream) -{ - switch (stream->link->link_enc->transmitter) { - case TRANSMITTER_UNIPHY_A: - return pool->clock_sources[DCE112_CLK_SRC_PLL0]; - case TRANSMITTER_UNIPHY_B: - return pool->clock_sources[DCE112_CLK_SRC_PLL1]; - case TRANSMITTER_UNIPHY_C: - return pool->clock_sources[DCE112_CLK_SRC_PLL2]; - case TRANSMITTER_UNIPHY_D: - return pool->clock_sources[DCE112_CLK_SRC_PLL3]; - case TRANSMITTER_UNIPHY_E: - return pool->clock_sources[DCE112_CLK_SRC_PLL4]; - case TRANSMITTER_UNIPHY_F: - return pool->clock_sources[DCE112_CLK_SRC_PLL5]; - default: - return NULL; - } - - return NULL; -} - -static enum dc_status build_mapped_resource( - const struct dc *dc, - struct dc_state *context, - struct dc_stream_state *stream) -{ - struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream); - - if (!pipe_ctx) - return DC_ERROR_UNEXPECTED; - - dce110_resource_build_pipe_hw_param(pipe_ctx); - - resource_build_info_frame(pipe_ctx); - - return DC_OK; -} - -bool dce112_validate_bandwidth( - struct dc *dc, - struct dc_state *context, - bool fast_validate) -{ - bool result = false; - - DC_LOG_BANDWIDTH_CALCS( - "%s: start", - __func__); - - if (bw_calcs( - dc->ctx, - dc->bw_dceip, - dc->bw_vbios, - context->res_ctx.pipe_ctx, - dc->res_pool->pipe_count, - &context->bw_ctx.bw.dce)) - result = true; - - if (!result) - DC_LOG_BANDWIDTH_VALIDATION( - "%s: Bandwidth validation failed!", - __func__); - - if (memcmp(&dc->current_state->bw_ctx.bw.dce, - &context->bw_ctx.bw.dce, sizeof(context->bw_ctx.bw.dce))) { - - DC_LOG_BANDWIDTH_CALCS( - "%s: finish,\n" - "nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n" - "stutMark_b: %d stutMark_a: %d\n" - "nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n" - "stutMark_b: %d stutMark_a: %d\n" - "nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n" - "stutMark_b: %d stutMark_a: %d stutter_mode_enable: %d\n" - "cstate: %d pstate: %d nbpstate: %d sync: %d dispclk: %d\n" - "sclk: %d sclk_sleep: %d yclk: %d blackout_recovery_time_us: %d\n" - , - __func__, - context->bw_ctx.bw.dce.nbp_state_change_wm_ns[0].b_mark, - context->bw_ctx.bw.dce.nbp_state_change_wm_ns[0].a_mark, - context->bw_ctx.bw.dce.urgent_wm_ns[0].b_mark, - context->bw_ctx.bw.dce.urgent_wm_ns[0].a_mark, - context->bw_ctx.bw.dce.stutter_exit_wm_ns[0].b_mark, - context->bw_ctx.bw.dce.stutter_exit_wm_ns[0].a_mark, - context->bw_ctx.bw.dce.nbp_state_change_wm_ns[1].b_mark, - context->bw_ctx.bw.dce.nbp_state_change_wm_ns[1].a_mark, - context->bw_ctx.bw.dce.urgent_wm_ns[1].b_mark, - context->bw_ctx.bw.dce.urgent_wm_ns[1].a_mark, - context->bw_ctx.bw.dce.stutter_exit_wm_ns[1].b_mark, - context->bw_ctx.bw.dce.stutter_exit_wm_ns[1].a_mark, - context->bw_ctx.bw.dce.nbp_state_change_wm_ns[2].b_mark, - context->bw_ctx.bw.dce.nbp_state_change_wm_ns[2].a_mark, - context->bw_ctx.bw.dce.urgent_wm_ns[2].b_mark, - context->bw_ctx.bw.dce.urgent_wm_ns[2].a_mark, - context->bw_ctx.bw.dce.stutter_exit_wm_ns[2].b_mark, - context->bw_ctx.bw.dce.stutter_exit_wm_ns[2].a_mark, - context->bw_ctx.bw.dce.stutter_mode_enable, - context->bw_ctx.bw.dce.cpuc_state_change_enable, - context->bw_ctx.bw.dce.cpup_state_change_enable, - context->bw_ctx.bw.dce.nbp_state_change_enable, - context->bw_ctx.bw.dce.all_displays_in_sync, - context->bw_ctx.bw.dce.dispclk_khz, - context->bw_ctx.bw.dce.sclk_khz, - context->bw_ctx.bw.dce.sclk_deep_sleep_khz, - context->bw_ctx.bw.dce.yclk_khz, - context->bw_ctx.bw.dce.blackout_recovery_time_us); - } - return result; -} - -enum dc_status resource_map_phy_clock_resources( - const struct dc *dc, - struct dc_state *context, - struct dc_stream_state *stream) -{ - - /* acquire new resources */ - struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream( - &context->res_ctx, stream); - - if (!pipe_ctx) - return DC_ERROR_UNEXPECTED; - - if (dc_is_dp_signal(pipe_ctx->stream->signal) - || dc_is_virtual_signal(pipe_ctx->stream->signal)) - pipe_ctx->clock_source = - dc->res_pool->dp_clock_source; - else { - if (stream && stream->link && stream->link->link_enc) - pipe_ctx->clock_source = find_matching_pll( - &context->res_ctx, dc->res_pool, - stream); - } - - if (pipe_ctx->clock_source == NULL) - return DC_NO_CLOCK_SOURCE_RESOURCE; - - resource_reference_clock_source( - &context->res_ctx, - dc->res_pool, - pipe_ctx->clock_source); - - return DC_OK; -} - -static bool dce112_validate_surface_sets( - struct dc_state *context) -{ - int i; - - for (i = 0; i < context->stream_count; i++) { - if (context->stream_status[i].plane_count == 0) - continue; - - if (context->stream_status[i].plane_count > 1) - return false; - - if (context->stream_status[i].plane_states[0]->format - >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) - return false; - } - - return true; -} - -enum dc_status dce112_add_stream_to_ctx( - struct dc *dc, - struct dc_state *new_ctx, - struct dc_stream_state *dc_stream) -{ - enum dc_status result; - - result = resource_map_pool_resources(dc, new_ctx, dc_stream); - - if (result == DC_OK) - result = resource_map_phy_clock_resources(dc, new_ctx, dc_stream); - - - if (result == DC_OK) - result = build_mapped_resource(dc, new_ctx, dc_stream); - - return result; -} - -static enum dc_status dce112_validate_global( - struct dc *dc, - struct dc_state *context) -{ - if (!dce112_validate_surface_sets(context)) - return DC_FAIL_SURFACE_VALIDATE; - - return DC_OK; -} - -static void dce112_destroy_resource_pool(struct resource_pool **pool) -{ - struct dce110_resource_pool *dce110_pool = TO_DCE110_RES_POOL(*pool); - - dce112_resource_destruct(dce110_pool); - kfree(dce110_pool); - *pool = NULL; -} - -static const struct resource_funcs dce112_res_pool_funcs = { - .destroy = dce112_destroy_resource_pool, - .link_enc_create = dce112_link_encoder_create, - .panel_cntl_create = dce112_panel_cntl_create, - .validate_bandwidth = dce112_validate_bandwidth, - .validate_plane = dce100_validate_plane, - .add_stream_to_ctx = dce112_add_stream_to_ctx, - .validate_global = dce112_validate_global, - .find_first_free_match_stream_enc_for_link = dce110_find_first_free_match_stream_enc_for_link -}; - -static void bw_calcs_data_update_from_pplib(struct dc *dc) -{ - struct dm_pp_clock_levels_with_latency eng_clks = {0}; - struct dm_pp_clock_levels_with_latency mem_clks = {0}; - struct dm_pp_wm_sets_with_clock_ranges clk_ranges = {0}; - struct dm_pp_clock_levels clks = {0}; - int memory_type_multiplier = MEMORY_TYPE_MULTIPLIER_CZ; - - if (dc->bw_vbios && dc->bw_vbios->memory_type == bw_def_hbm) - memory_type_multiplier = MEMORY_TYPE_HBM; - - /*do system clock TODO PPLIB: after PPLIB implement, - * then remove old way - */ - if (!dm_pp_get_clock_levels_by_type_with_latency( - dc->ctx, - DM_PP_CLOCK_TYPE_ENGINE_CLK, - &eng_clks)) { - - /* This is only for temporary */ - dm_pp_get_clock_levels_by_type( - dc->ctx, - DM_PP_CLOCK_TYPE_ENGINE_CLK, - &clks); - /* convert all the clock fro kHz to fix point mHz */ - dc->bw_vbios->high_sclk = bw_frc_to_fixed( - clks.clocks_in_khz[clks.num_levels-1], 1000); - dc->bw_vbios->mid1_sclk = bw_frc_to_fixed( - clks.clocks_in_khz[clks.num_levels/8], 1000); - dc->bw_vbios->mid2_sclk = bw_frc_to_fixed( - clks.clocks_in_khz[clks.num_levels*2/8], 1000); - dc->bw_vbios->mid3_sclk = bw_frc_to_fixed( - clks.clocks_in_khz[clks.num_levels*3/8], 1000); - dc->bw_vbios->mid4_sclk = bw_frc_to_fixed( - clks.clocks_in_khz[clks.num_levels*4/8], 1000); - dc->bw_vbios->mid5_sclk = bw_frc_to_fixed( - clks.clocks_in_khz[clks.num_levels*5/8], 1000); - dc->bw_vbios->mid6_sclk = bw_frc_to_fixed( - clks.clocks_in_khz[clks.num_levels*6/8], 1000); - dc->bw_vbios->low_sclk = bw_frc_to_fixed( - clks.clocks_in_khz[0], 1000); - - /*do memory clock*/ - dm_pp_get_clock_levels_by_type( - dc->ctx, - DM_PP_CLOCK_TYPE_MEMORY_CLK, - &clks); - - dc->bw_vbios->low_yclk = bw_frc_to_fixed( - clks.clocks_in_khz[0] * memory_type_multiplier, 1000); - dc->bw_vbios->mid_yclk = bw_frc_to_fixed( - clks.clocks_in_khz[clks.num_levels>>1] * memory_type_multiplier, - 1000); - dc->bw_vbios->high_yclk = bw_frc_to_fixed( - clks.clocks_in_khz[clks.num_levels-1] * memory_type_multiplier, - 1000); - - return; - } - - /* convert all the clock fro kHz to fix point mHz TODO: wloop data */ - dc->bw_vbios->high_sclk = bw_frc_to_fixed( - eng_clks.data[eng_clks.num_levels-1].clocks_in_khz, 1000); - dc->bw_vbios->mid1_sclk = bw_frc_to_fixed( - eng_clks.data[eng_clks.num_levels/8].clocks_in_khz, 1000); - dc->bw_vbios->mid2_sclk = bw_frc_to_fixed( - eng_clks.data[eng_clks.num_levels*2/8].clocks_in_khz, 1000); - dc->bw_vbios->mid3_sclk = bw_frc_to_fixed( - eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz, 1000); - dc->bw_vbios->mid4_sclk = bw_frc_to_fixed( - eng_clks.data[eng_clks.num_levels*4/8].clocks_in_khz, 1000); - dc->bw_vbios->mid5_sclk = bw_frc_to_fixed( - eng_clks.data[eng_clks.num_levels*5/8].clocks_in_khz, 1000); - dc->bw_vbios->mid6_sclk = bw_frc_to_fixed( - eng_clks.data[eng_clks.num_levels*6/8].clocks_in_khz, 1000); - dc->bw_vbios->low_sclk = bw_frc_to_fixed( - eng_clks.data[0].clocks_in_khz, 1000); - - /*do memory clock*/ - dm_pp_get_clock_levels_by_type_with_latency( - dc->ctx, - DM_PP_CLOCK_TYPE_MEMORY_CLK, - &mem_clks); - - /* we don't need to call PPLIB for validation clock since they - * also give us the highest sclk and highest mclk (UMA clock). - * ALSO always convert UMA clock (from PPLIB) to YCLK (HW formula): - * YCLK = UMACLK*m_memoryTypeMultiplier - */ - dc->bw_vbios->low_yclk = bw_frc_to_fixed( - mem_clks.data[0].clocks_in_khz * memory_type_multiplier, 1000); - dc->bw_vbios->mid_yclk = bw_frc_to_fixed( - mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz * memory_type_multiplier, - 1000); - dc->bw_vbios->high_yclk = bw_frc_to_fixed( - mem_clks.data[mem_clks.num_levels-1].clocks_in_khz * memory_type_multiplier, - 1000); - - /* Now notify PPLib/SMU about which Watermarks sets they should select - * depending on DPM state they are in. And update BW MGR GFX Engine and - * Memory clock member variables for Watermarks calculations for each - * Watermark Set - */ - clk_ranges.num_wm_sets = 4; - clk_ranges.wm_clk_ranges[0].wm_set_id = WM_SET_A; - clk_ranges.wm_clk_ranges[0].wm_min_eng_clk_in_khz = - eng_clks.data[0].clocks_in_khz; - clk_ranges.wm_clk_ranges[0].wm_max_eng_clk_in_khz = - eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz - 1; - clk_ranges.wm_clk_ranges[0].wm_min_mem_clk_in_khz = - mem_clks.data[0].clocks_in_khz; - clk_ranges.wm_clk_ranges[0].wm_max_mem_clk_in_khz = - mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz - 1; - - clk_ranges.wm_clk_ranges[1].wm_set_id = WM_SET_B; - clk_ranges.wm_clk_ranges[1].wm_min_eng_clk_in_khz = - eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz; - /* 5 GHz instead of data[7].clockInKHz to cover Overdrive */ - clk_ranges.wm_clk_ranges[1].wm_max_eng_clk_in_khz = 5000000; - clk_ranges.wm_clk_ranges[1].wm_min_mem_clk_in_khz = - mem_clks.data[0].clocks_in_khz; - clk_ranges.wm_clk_ranges[1].wm_max_mem_clk_in_khz = - mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz - 1; - - clk_ranges.wm_clk_ranges[2].wm_set_id = WM_SET_C; - clk_ranges.wm_clk_ranges[2].wm_min_eng_clk_in_khz = - eng_clks.data[0].clocks_in_khz; - clk_ranges.wm_clk_ranges[2].wm_max_eng_clk_in_khz = - eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz - 1; - clk_ranges.wm_clk_ranges[2].wm_min_mem_clk_in_khz = - mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz; - /* 5 GHz instead of data[2].clockInKHz to cover Overdrive */ - clk_ranges.wm_clk_ranges[2].wm_max_mem_clk_in_khz = 5000000; - - clk_ranges.wm_clk_ranges[3].wm_set_id = WM_SET_D; - clk_ranges.wm_clk_ranges[3].wm_min_eng_clk_in_khz = - eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz; - /* 5 GHz instead of data[7].clockInKHz to cover Overdrive */ - clk_ranges.wm_clk_ranges[3].wm_max_eng_clk_in_khz = 5000000; - clk_ranges.wm_clk_ranges[3].wm_min_mem_clk_in_khz = - mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz; - /* 5 GHz instead of data[2].clockInKHz to cover Overdrive */ - clk_ranges.wm_clk_ranges[3].wm_max_mem_clk_in_khz = 5000000; - - /* Notify PP Lib/SMU which Watermarks to use for which clock ranges */ - dm_pp_notify_wm_clock_changes(dc->ctx, &clk_ranges); -} - -static const struct resource_caps *dce112_resource_cap( - struct hw_asic_id *asic_id) -{ - if (ASIC_REV_IS_POLARIS11_M(asic_id->hw_internal_rev) || - ASIC_REV_IS_POLARIS12_V(asic_id->hw_internal_rev)) - return &polaris_11_resource_cap; - else - return &polaris_10_resource_cap; -} - -static bool dce112_resource_construct( - uint8_t num_virtual_links, - struct dc *dc, - struct dce110_resource_pool *pool) -{ - unsigned int i; - struct dc_context *ctx = dc->ctx; - - ctx->dc_bios->regs = &bios_regs; - - pool->base.res_cap = dce112_resource_cap(&ctx->asic_id); - pool->base.funcs = &dce112_res_pool_funcs; - - /************************************************* - * Resource + asic cap harcoding * - *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; - pool->base.pipe_count = pool->base.res_cap->num_timing_generator; - pool->base.timing_generator_count = pool->base.res_cap->num_timing_generator; - dc->caps.max_downscale_ratio = 200; - dc->caps.i2c_speed_in_khz = 100; - dc->caps.i2c_speed_in_khz_hdcp = 100; /*1.4 w/a not applied by default*/ - dc->caps.max_cursor_size = 128; - dc->caps.min_horizontal_blanking_period = 80; - dc->caps.dual_link_dvi = true; - dc->caps.extended_aux_timeout_support = false; - dc->debug = debug_defaults; - - /************************************************* - * Create resources * - *************************************************/ - - pool->base.clock_sources[DCE112_CLK_SRC_PLL0] = - dce112_clock_source_create( - ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL0, - &clk_src_regs[0], false); - pool->base.clock_sources[DCE112_CLK_SRC_PLL1] = - dce112_clock_source_create( - ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL1, - &clk_src_regs[1], false); - pool->base.clock_sources[DCE112_CLK_SRC_PLL2] = - dce112_clock_source_create( - ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL2, - &clk_src_regs[2], false); - pool->base.clock_sources[DCE112_CLK_SRC_PLL3] = - dce112_clock_source_create( - ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL3, - &clk_src_regs[3], false); - pool->base.clock_sources[DCE112_CLK_SRC_PLL4] = - dce112_clock_source_create( - ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL4, - &clk_src_regs[4], false); - pool->base.clock_sources[DCE112_CLK_SRC_PLL5] = - dce112_clock_source_create( - ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL5, - &clk_src_regs[5], false); - pool->base.clk_src_count = DCE112_CLK_SRC_TOTAL; - - pool->base.dp_clock_source = dce112_clock_source_create( - ctx, ctx->dc_bios, - CLOCK_SOURCE_ID_DP_DTO, &clk_src_regs[0], true); - - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] == NULL) { - dm_error("DC: failed to create clock sources!\n"); - BREAK_TO_DEBUGGER(); - goto res_create_fail; - } - } - - pool->base.dmcu = dce_dmcu_create(ctx, - &dmcu_regs, - &dmcu_shift, - &dmcu_mask); - if (pool->base.dmcu == NULL) { - dm_error("DC: failed to create dmcu!\n"); - BREAK_TO_DEBUGGER(); - goto res_create_fail; - } - - pool->base.abm = dce_abm_create(ctx, - &abm_regs, - &abm_shift, - &abm_mask); - if (pool->base.abm == NULL) { - dm_error("DC: failed to create abm!\n"); - BREAK_TO_DEBUGGER(); - goto res_create_fail; - } - - { - struct irq_service_init_data init_data; - init_data.ctx = dc->ctx; - pool->base.irqs = dal_irq_service_dce110_create(&init_data); - if (!pool->base.irqs) - goto res_create_fail; - } - - for (i = 0; i < pool->base.pipe_count; i++) { - pool->base.timing_generators[i] = - dce112_timing_generator_create( - ctx, - i, - &dce112_tg_offsets[i]); - if (pool->base.timing_generators[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create tg!\n"); - goto res_create_fail; - } - - pool->base.mis[i] = dce112_mem_input_create(ctx, i); - if (pool->base.mis[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create memory input!\n"); - goto res_create_fail; - } - - pool->base.ipps[i] = dce112_ipp_create(ctx, i); - if (pool->base.ipps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create input pixel processor!\n"); - goto res_create_fail; - } - - pool->base.transforms[i] = dce112_transform_create(ctx, i); - if (pool->base.transforms[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create transform!\n"); - goto res_create_fail; - } - - pool->base.opps[i] = dce112_opp_create( - ctx, - i); - if (pool->base.opps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create output pixel processor!\n"); - goto res_create_fail; - } - } - - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - pool->base.engines[i] = dce112_aux_engine_create(ctx, i); - if (pool->base.engines[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create aux engine!!\n"); - goto res_create_fail; - } - pool->base.hw_i2cs[i] = dce112_i2c_hw_create(ctx, i); - if (pool->base.hw_i2cs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create i2c engine!!\n"); - goto res_create_fail; - } - pool->base.sw_i2cs[i] = NULL; - } - - if (!resource_construct(num_virtual_links, dc, &pool->base, - &res_create_funcs)) - goto res_create_fail; - - dc->caps.max_planes = pool->base.pipe_count; - - for (i = 0; i < dc->caps.max_planes; ++i) - dc->caps.planes[i] = plane_cap; - - /* Create hardware sequencer */ - dce112_hw_sequencer_construct(dc); - - bw_calcs_init(dc->bw_dceip, dc->bw_vbios, dc->ctx->asic_id); - - bw_calcs_data_update_from_pplib(dc); - - return true; - -res_create_fail: - dce112_resource_destruct(pool); - return false; -} - -struct resource_pool *dce112_create_resource_pool( - uint8_t num_virtual_links, - struct dc *dc) -{ - struct dce110_resource_pool *pool = - kzalloc(sizeof(struct dce110_resource_pool), GFP_KERNEL); - - if (!pool) - return NULL; - - if (dce112_resource_construct(num_virtual_links, dc, pool)) - return &pool->base; - - kfree(pool); - BREAK_TO_DEBUGGER(); - return NULL; -} diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.h b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.h deleted file mode 100644 index 1f57ebc6f9b440..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.h +++ /dev/null @@ -1,57 +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 __DC_RESOURCE_DCE112_H__ -#define __DC_RESOURCE_DCE112_H__ - -#include "core_types.h" - -struct dc; -struct resource_pool; - -struct resource_pool *dce112_create_resource_pool( - uint8_t num_virtual_links, - struct dc *dc); - -enum dc_status dce112_validate_with_context( - struct dc *dc, - const struct dc_validation_set set[], - int set_count, - struct dc_state *context, - struct dc_state *old_context); - -bool dce112_validate_bandwidth( - struct dc *dc, - struct dc_state *context, - bool fast_validate); - -enum dc_status dce112_add_stream_to_ctx( - struct dc *dc, - struct dc_state *new_ctx, - struct dc_stream_state *dc_stream); - - -#endif /* __DC_RESOURCE_DCE112_H__ */ - diff --git a/drivers/gpu/drm/amd/display/dc/dce120/Makefile b/drivers/gpu/drm/amd/display/dc/dce120/Makefile index 097cf407a15d18..1e3ef68a452a56 100644 --- a/drivers/gpu/drm/amd/display/dc/dce120/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dce120/Makefile @@ -26,7 +26,7 @@ CFLAGS_$(AMDDALPATH)/dc/dce120/dce120_resource.o = $(call cc-disable-warning, override-init) -DCE120 = dce120_resource.o dce120_timing_generator.o \ +DCE120 = dce120_timing_generator.o AMD_DAL_DCE120 = $(addprefix $(AMDDALPATH)/dc/dce120/,$(DCE120)) diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c deleted file mode 100644 index 962de79be169a4..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c +++ /dev/null @@ -1,1288 +0,0 @@ -/* -* Copyright 2012-15 Advanced Micro Devices, Inc.cls -* - * - * 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 "stream_encoder.h" -#include "resource.h" -#include "include/irq_service_interface.h" -#include "dce120_resource.h" - -#include "dce112/dce112_resource.h" - -#include "dce110/dce110_resource.h" -#include "virtual/virtual_stream_encoder.h" -#include "dce120_timing_generator.h" -#include "irq/dce120/irq_service_dce120.h" -#include "dce/dce_opp.h" -#include "dce/dce_clock_source.h" -#include "dce/dce_ipp.h" -#include "dce/dce_mem_input.h" -#include "dce/dce_panel_cntl.h" - -#include "dce110/dce110_hwseq.h" -#include "dce120/dce120_hwseq.h" -#include "dce/dce_transform.h" -#include "clk_mgr.h" -#include "dce/dce_audio.h" -#include "dce/dce_link_encoder.h" -#include "dce/dce_stream_encoder.h" -#include "dce/dce_hwseq.h" -#include "dce/dce_abm.h" -#include "dce/dce_dmcu.h" -#include "dce/dce_aux.h" -#include "dce/dce_i2c.h" - -#include "dce/dce_12_0_offset.h" -#include "dce/dce_12_0_sh_mask.h" -#include "soc15_hw_ip.h" -#include "vega10_ip_offset.h" -#include "nbio/nbio_6_1_offset.h" -#include "mmhub/mmhub_1_0_offset.h" -#include "mmhub/mmhub_1_0_sh_mask.h" -#include "reg_helper.h" - -#include "dce100/dce100_resource.h" - -#ifndef mmDP0_DP_DPHY_INTERNAL_CTRL - #define mmDP0_DP_DPHY_INTERNAL_CTRL 0x210f - #define mmDP0_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 - #define mmDP1_DP_DPHY_INTERNAL_CTRL 0x220f - #define mmDP1_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 - #define mmDP2_DP_DPHY_INTERNAL_CTRL 0x230f - #define mmDP2_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 - #define mmDP3_DP_DPHY_INTERNAL_CTRL 0x240f - #define mmDP3_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 - #define mmDP4_DP_DPHY_INTERNAL_CTRL 0x250f - #define mmDP4_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 - #define mmDP5_DP_DPHY_INTERNAL_CTRL 0x260f - #define mmDP5_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 - #define mmDP6_DP_DPHY_INTERNAL_CTRL 0x270f - #define mmDP6_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 -#endif - -enum dce120_clk_src_array_id { - DCE120_CLK_SRC_PLL0, - DCE120_CLK_SRC_PLL1, - DCE120_CLK_SRC_PLL2, - DCE120_CLK_SRC_PLL3, - DCE120_CLK_SRC_PLL4, - DCE120_CLK_SRC_PLL5, - - DCE120_CLK_SRC_TOTAL -}; - -static const struct dce110_timing_generator_offsets dce120_tg_offsets[] = { - { - .crtc = (mmCRTC0_CRTC_CONTROL - mmCRTC0_CRTC_CONTROL), - }, - { - .crtc = (mmCRTC1_CRTC_CONTROL - mmCRTC0_CRTC_CONTROL), - }, - { - .crtc = (mmCRTC2_CRTC_CONTROL - mmCRTC0_CRTC_CONTROL), - }, - { - .crtc = (mmCRTC3_CRTC_CONTROL - mmCRTC0_CRTC_CONTROL), - }, - { - .crtc = (mmCRTC4_CRTC_CONTROL - mmCRTC0_CRTC_CONTROL), - }, - { - .crtc = (mmCRTC5_CRTC_CONTROL - mmCRTC0_CRTC_CONTROL), - } -}; - -/* begin ********************* - * macros to expend register list macro defined in HW object header file */ - -#define BASE_INNER(seg) \ - DCE_BASE__INST0_SEG ## seg - -#define NBIO_BASE_INNER(seg) \ - NBIF_BASE__INST0_SEG ## seg - -#define NBIO_BASE(seg) \ - NBIO_BASE_INNER(seg) - -/* compile time expand base address. */ -#define BASE(seg) \ - BASE_INNER(seg) - -#define SR(reg_name)\ - .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + \ - mm ## reg_name - -#define SRI(reg_name, block, id)\ - .reg_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name - -/* MMHUB */ -#define MMHUB_BASE_INNER(seg) \ - MMHUB_BASE__INST0_SEG ## seg - -#define MMHUB_BASE(seg) \ - MMHUB_BASE_INNER(seg) - -#define MMHUB_SR(reg_name)\ - .reg_name = MMHUB_BASE(mm ## reg_name ## _BASE_IDX) + \ - mm ## reg_name - -/* macros to expend register list macro defined in HW object header file - * end *********************/ - - -static const struct dce_dmcu_registers dmcu_regs = { - DMCU_DCE110_COMMON_REG_LIST() -}; - -static const struct dce_dmcu_shift dmcu_shift = { - DMCU_MASK_SH_LIST_DCE110(__SHIFT) -}; - -static const struct dce_dmcu_mask dmcu_mask = { - DMCU_MASK_SH_LIST_DCE110(_MASK) -}; - -static const struct dce_abm_registers abm_regs = { - ABM_DCE110_COMMON_REG_LIST() -}; - -static const struct dce_abm_shift abm_shift = { - ABM_MASK_SH_LIST_DCE110(__SHIFT) -}; - -static const struct dce_abm_mask abm_mask = { - ABM_MASK_SH_LIST_DCE110(_MASK) -}; - -#define ipp_regs(id)\ -[id] = {\ - IPP_DCE110_REG_LIST_DCE_BASE(id)\ -} - -static const struct dce_ipp_registers ipp_regs[] = { - ipp_regs(0), - ipp_regs(1), - ipp_regs(2), - ipp_regs(3), - ipp_regs(4), - ipp_regs(5) -}; - -static const struct dce_ipp_shift ipp_shift = { - IPP_DCE120_MASK_SH_LIST_SOC_BASE(__SHIFT) -}; - -static const struct dce_ipp_mask ipp_mask = { - IPP_DCE120_MASK_SH_LIST_SOC_BASE(_MASK) -}; - -#define transform_regs(id)\ -[id] = {\ - XFM_COMMON_REG_LIST_DCE110(id)\ -} - -static const struct dce_transform_registers xfm_regs[] = { - transform_regs(0), - transform_regs(1), - transform_regs(2), - transform_regs(3), - transform_regs(4), - transform_regs(5) -}; - -static const struct dce_transform_shift xfm_shift = { - XFM_COMMON_MASK_SH_LIST_SOC_BASE(__SHIFT) -}; - -static const struct dce_transform_mask xfm_mask = { - XFM_COMMON_MASK_SH_LIST_SOC_BASE(_MASK) -}; - -#define aux_regs(id)\ -[id] = {\ - AUX_REG_LIST(id)\ -} - -static const struct dce110_link_enc_aux_registers link_enc_aux_regs[] = { - aux_regs(0), - aux_regs(1), - aux_regs(2), - aux_regs(3), - aux_regs(4), - aux_regs(5) -}; - -#define hpd_regs(id)\ -[id] = {\ - HPD_REG_LIST(id)\ -} - -static const struct dce110_link_enc_hpd_registers link_enc_hpd_regs[] = { - hpd_regs(0), - hpd_regs(1), - hpd_regs(2), - hpd_regs(3), - hpd_regs(4), - hpd_regs(5) -}; - -#define link_regs(id)\ -[id] = {\ - LE_DCE120_REG_LIST(id), \ - SRI(DP_DPHY_INTERNAL_CTRL, DP, id) \ -} - -static const struct dce110_link_enc_registers link_enc_regs[] = { - link_regs(0), - link_regs(1), - link_regs(2), - link_regs(3), - link_regs(4), - link_regs(5), - link_regs(6), -}; - - -#define stream_enc_regs(id)\ -[id] = {\ - SE_COMMON_REG_LIST(id),\ - .TMDS_CNTL = 0,\ -} - -static const struct dce110_stream_enc_registers stream_enc_regs[] = { - stream_enc_regs(0), - stream_enc_regs(1), - stream_enc_regs(2), - stream_enc_regs(3), - stream_enc_regs(4), - stream_enc_regs(5) -}; - -static const struct dce_stream_encoder_shift se_shift = { - SE_COMMON_MASK_SH_LIST_DCE120(__SHIFT) -}; - -static const struct dce_stream_encoder_mask se_mask = { - SE_COMMON_MASK_SH_LIST_DCE120(_MASK) -}; - -static const struct dce_panel_cntl_registers panel_cntl_regs[] = { - { DCE_PANEL_CNTL_REG_LIST() } -}; - -static const struct dce_panel_cntl_shift panel_cntl_shift = { - DCE_PANEL_CNTL_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_panel_cntl_mask panel_cntl_mask = { - DCE_PANEL_CNTL_MASK_SH_LIST(_MASK) -}; - -static const struct dce110_aux_registers_shift aux_shift = { - DCE12_AUX_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce110_aux_registers_mask aux_mask = { - DCE12_AUX_MASK_SH_LIST(_MASK) -}; - -#define opp_regs(id)\ -[id] = {\ - OPP_DCE_120_REG_LIST(id),\ -} - -static const struct dce_opp_registers opp_regs[] = { - opp_regs(0), - opp_regs(1), - opp_regs(2), - opp_regs(3), - opp_regs(4), - opp_regs(5) -}; - -static const struct dce_opp_shift opp_shift = { - OPP_COMMON_MASK_SH_LIST_DCE_120(__SHIFT) -}; - -static const struct dce_opp_mask opp_mask = { - OPP_COMMON_MASK_SH_LIST_DCE_120(_MASK) -}; - #define aux_engine_regs(id)\ -[id] = {\ - AUX_COMMON_REG_LIST(id), \ - .AUX_RESET_MASK = 0 \ -} - -static const struct dce110_aux_registers aux_engine_regs[] = { - aux_engine_regs(0), - aux_engine_regs(1), - aux_engine_regs(2), - aux_engine_regs(3), - aux_engine_regs(4), - aux_engine_regs(5) -}; - -#define audio_regs(id)\ -[id] = {\ - AUD_COMMON_REG_LIST(id)\ -} - -static const struct dce_audio_registers audio_regs[] = { - audio_regs(0), - audio_regs(1), - audio_regs(2), - audio_regs(3), - audio_regs(4), - audio_regs(5), - audio_regs(6), -}; - -#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ - SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ - SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ - AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) - -static const struct dce_audio_shift audio_shift = { - DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_audio_mask audio_mask = { - DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) -}; - -static int map_transmitter_id_to_phy_instance( - enum transmitter transmitter) -{ - switch (transmitter) { - case TRANSMITTER_UNIPHY_A: - return 0; - case TRANSMITTER_UNIPHY_B: - return 1; - case TRANSMITTER_UNIPHY_C: - return 2; - case TRANSMITTER_UNIPHY_D: - return 3; - case TRANSMITTER_UNIPHY_E: - return 4; - case TRANSMITTER_UNIPHY_F: - return 5; - case TRANSMITTER_UNIPHY_G: - return 6; - default: - ASSERT(0); - return 0; - } -} - -#define clk_src_regs(index, id)\ -[index] = {\ - CS_COMMON_REG_LIST_DCE_112(id),\ -} - -static const struct dce110_clk_src_regs clk_src_regs[] = { - clk_src_regs(0, A), - clk_src_regs(1, B), - clk_src_regs(2, C), - clk_src_regs(3, D), - clk_src_regs(4, E), - clk_src_regs(5, F) -}; - -static const struct dce110_clk_src_shift cs_shift = { - CS_COMMON_MASK_SH_LIST_DCE_112(__SHIFT) -}; - -static const struct dce110_clk_src_mask cs_mask = { - CS_COMMON_MASK_SH_LIST_DCE_112(_MASK) -}; - -static struct output_pixel_processor *dce120_opp_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dce110_opp *opp = - kzalloc(sizeof(struct dce110_opp), GFP_KERNEL); - - if (!opp) - return NULL; - - dce110_opp_construct(opp, - ctx, inst, &opp_regs[inst], &opp_shift, &opp_mask); - return &opp->base; -} -static struct dce_aux *dce120_aux_engine_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct aux_engine_dce110 *aux_engine = - kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); - - if (!aux_engine) - return NULL; - - dce110_aux_engine_construct(aux_engine, ctx, inst, - SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, - &aux_engine_regs[inst], - &aux_mask, - &aux_shift, - ctx->dc->caps.extended_aux_timeout_support); - - return &aux_engine->base; -} -#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST(id) } - -static const struct dce_i2c_registers i2c_hw_regs[] = { - i2c_inst_regs(1), - i2c_inst_regs(2), - i2c_inst_regs(3), - i2c_inst_regs(4), - i2c_inst_regs(5), - i2c_inst_regs(6), -}; - -static const struct dce_i2c_shift i2c_shifts = { - I2C_COMMON_MASK_SH_LIST_DCE110(__SHIFT) -}; - -static const struct dce_i2c_mask i2c_masks = { - I2C_COMMON_MASK_SH_LIST_DCE110(_MASK) -}; - -static struct dce_i2c_hw *dce120_i2c_hw_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dce_i2c_hw *dce_i2c_hw = - kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); - - if (!dce_i2c_hw) - return NULL; - - dce112_i2c_hw_construct(dce_i2c_hw, ctx, inst, - &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); - - return dce_i2c_hw; -} -static const struct bios_registers bios_regs = { - .BIOS_SCRATCH_3 = mmBIOS_SCRATCH_3 + NBIO_BASE(mmBIOS_SCRATCH_3_BASE_IDX), - .BIOS_SCRATCH_6 = mmBIOS_SCRATCH_6 + NBIO_BASE(mmBIOS_SCRATCH_6_BASE_IDX) -}; - -static const struct resource_caps res_cap = { - .num_timing_generator = 6, - .num_audio = 7, - .num_stream_encoder = 6, - .num_pll = 6, - .num_ddc = 6, -}; - -static const struct dc_plane_cap plane_cap = { - .type = DC_PLANE_TYPE_DCE_RGB, - - .pixel_format_support = { - .argb8888 = true, - .nv12 = false, - .fp16 = true - }, - - .max_upscale_factor = { - .argb8888 = 16000, - .nv12 = 1, - .fp16 = 1 - }, - - .max_downscale_factor = { - .argb8888 = 250, - .nv12 = 1, - .fp16 = 1 - } -}; - -static const struct dc_debug_options debug_defaults = { - .disable_clock_gate = true, - .enable_legacy_fast_update = true, -}; - -static struct clock_source *dce120_clock_source_create( - struct dc_context *ctx, - struct dc_bios *bios, - enum clock_source_id id, - const struct dce110_clk_src_regs *regs, - bool dp_clk_src) -{ - struct dce110_clk_src *clk_src = - kzalloc(sizeof(*clk_src), GFP_KERNEL); - - if (!clk_src) - return NULL; - - if (dce112_clk_src_construct(clk_src, ctx, bios, id, - regs, &cs_shift, &cs_mask)) { - clk_src->base.dp_clk_src = dp_clk_src; - return &clk_src->base; - } - - kfree(clk_src); - BREAK_TO_DEBUGGER(); - return NULL; -} - -static void dce120_clock_source_destroy(struct clock_source **clk_src) -{ - kfree(TO_DCE110_CLK_SRC(*clk_src)); - *clk_src = NULL; -} - - -static bool dce120_hw_sequencer_create(struct dc *dc) -{ - /* All registers used by dce11.2 match those in dce11 in offset and - * structure - */ - dce120_hw_sequencer_construct(dc); - - /*TODO Move to separate file and Override what is needed */ - - return true; -} - -static struct timing_generator *dce120_timing_generator_create( - struct dc_context *ctx, - uint32_t instance, - const struct dce110_timing_generator_offsets *offsets) -{ - struct dce110_timing_generator *tg110 = - kzalloc(sizeof(struct dce110_timing_generator), GFP_KERNEL); - - if (!tg110) - return NULL; - - dce120_timing_generator_construct(tg110, ctx, instance, offsets); - return &tg110->base; -} - -static void dce120_transform_destroy(struct transform **xfm) -{ - kfree(TO_DCE_TRANSFORM(*xfm)); - *xfm = NULL; -} - -static void dce120_resource_destruct(struct dce110_resource_pool *pool) -{ - unsigned int i; - - for (i = 0; i < pool->base.pipe_count; i++) { - if (pool->base.opps[i] != NULL) - dce110_opp_destroy(&pool->base.opps[i]); - - if (pool->base.transforms[i] != NULL) - dce120_transform_destroy(&pool->base.transforms[i]); - - if (pool->base.ipps[i] != NULL) - dce_ipp_destroy(&pool->base.ipps[i]); - - if (pool->base.mis[i] != NULL) { - kfree(TO_DCE_MEM_INPUT(pool->base.mis[i])); - pool->base.mis[i] = NULL; - } - - if (pool->base.irqs != NULL) { - dal_irq_service_destroy(&pool->base.irqs); - } - - if (pool->base.timing_generators[i] != NULL) { - kfree(DCE110TG_FROM_TG(pool->base.timing_generators[i])); - pool->base.timing_generators[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - if (pool->base.engines[i] != NULL) - dce110_engine_destroy(&pool->base.engines[i]); - if (pool->base.hw_i2cs[i] != NULL) { - kfree(pool->base.hw_i2cs[i]); - pool->base.hw_i2cs[i] = NULL; - } - if (pool->base.sw_i2cs[i] != NULL) { - kfree(pool->base.sw_i2cs[i]); - pool->base.sw_i2cs[i] = NULL; - } - } - - for (i = 0; i < pool->base.audio_count; i++) { - if (pool->base.audios[i]) - dce_aud_destroy(&pool->base.audios[i]); - } - - for (i = 0; i < pool->base.stream_enc_count; i++) { - if (pool->base.stream_enc[i] != NULL) - kfree(DCE110STRENC_FROM_STRENC(pool->base.stream_enc[i])); - } - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] != NULL) - dce120_clock_source_destroy( - &pool->base.clock_sources[i]); - } - - if (pool->base.dp_clock_source != NULL) - dce120_clock_source_destroy(&pool->base.dp_clock_source); - - if (pool->base.abm != NULL) - dce_abm_destroy(&pool->base.abm); - - if (pool->base.dmcu != NULL) - dce_dmcu_destroy(&pool->base.dmcu); -} - -static void read_dce_straps( - struct dc_context *ctx, - struct resource_straps *straps) -{ - uint32_t reg_val = dm_read_reg_soc15(ctx, mmCC_DC_MISC_STRAPS, 0); - - straps->audio_stream_number = get_reg_field_value(reg_val, - CC_DC_MISC_STRAPS, - AUDIO_STREAM_NUMBER); - straps->hdmi_disable = get_reg_field_value(reg_val, - CC_DC_MISC_STRAPS, - HDMI_DISABLE); - - reg_val = dm_read_reg_soc15(ctx, mmDC_PINSTRAPS, 0); - straps->dc_pinstraps_audio = get_reg_field_value(reg_val, - DC_PINSTRAPS, - DC_PINSTRAPS_AUDIO); -} - -static struct audio *create_audio( - struct dc_context *ctx, unsigned int inst) -{ - return dce_audio_create(ctx, inst, - &audio_regs[inst], &audio_shift, &audio_mask); -} - -static const struct encoder_feature_support link_enc_feature = { - .max_hdmi_deep_color = COLOR_DEPTH_121212, - .max_hdmi_pixel_clock = 600000, - .hdmi_ycbcr420_supported = true, - .dp_ycbcr420_supported = false, - .flags.bits.IS_HBR2_CAPABLE = true, - .flags.bits.IS_HBR3_CAPABLE = true, - .flags.bits.IS_TPS3_CAPABLE = true, - .flags.bits.IS_TPS4_CAPABLE = true, -}; - -static struct link_encoder *dce120_link_encoder_create( - struct dc_context *ctx, - const struct encoder_init_data *enc_init_data) -{ - struct dce110_link_encoder *enc110 = - kzalloc(sizeof(struct dce110_link_encoder), GFP_KERNEL); - int link_regs_id; - - if (!enc110) - return NULL; - - link_regs_id = - map_transmitter_id_to_phy_instance(enc_init_data->transmitter); - - dce110_link_encoder_construct(enc110, - enc_init_data, - &link_enc_feature, - &link_enc_regs[link_regs_id], - &link_enc_aux_regs[enc_init_data->channel - 1], - &link_enc_hpd_regs[enc_init_data->hpd_source]); - - return &enc110->base; -} - -static struct panel_cntl *dce120_panel_cntl_create(const struct panel_cntl_init_data *init_data) -{ - struct dce_panel_cntl *panel_cntl = - kzalloc(sizeof(struct dce_panel_cntl), GFP_KERNEL); - - if (!panel_cntl) - return NULL; - - dce_panel_cntl_construct(panel_cntl, - init_data, - &panel_cntl_regs[init_data->inst], - &panel_cntl_shift, - &panel_cntl_mask); - - return &panel_cntl->base; -} - -static struct input_pixel_processor *dce120_ipp_create( - struct dc_context *ctx, uint32_t inst) -{ - struct dce_ipp *ipp = kzalloc(sizeof(struct dce_ipp), GFP_KERNEL); - - if (!ipp) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dce_ipp_construct(ipp, ctx, inst, - &ipp_regs[inst], &ipp_shift, &ipp_mask); - return &ipp->base; -} - -static struct stream_encoder *dce120_stream_encoder_create( - enum engine_id eng_id, - struct dc_context *ctx) -{ - struct dce110_stream_encoder *enc110 = - kzalloc(sizeof(struct dce110_stream_encoder), GFP_KERNEL); - - if (!enc110) - return NULL; - - dce110_stream_encoder_construct(enc110, ctx, ctx->dc_bios, eng_id, - &stream_enc_regs[eng_id], - &se_shift, &se_mask); - return &enc110->base; -} - -#define SRII(reg_name, block, id)\ - .reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name - -static const struct dce_hwseq_registers hwseq_reg = { - HWSEQ_DCE120_REG_LIST() -}; - -static const struct dce_hwseq_shift hwseq_shift = { - HWSEQ_DCE12_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_hwseq_mask hwseq_mask = { - HWSEQ_DCE12_MASK_SH_LIST(_MASK) -}; - -/* HWSEQ regs for VG20 */ -static const struct dce_hwseq_registers dce121_hwseq_reg = { - HWSEQ_VG20_REG_LIST() -}; - -static const struct dce_hwseq_shift dce121_hwseq_shift = { - HWSEQ_VG20_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_hwseq_mask dce121_hwseq_mask = { - HWSEQ_VG20_MASK_SH_LIST(_MASK) -}; - -static struct dce_hwseq *dce120_hwseq_create( - struct dc_context *ctx) -{ - struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); - - if (hws) { - hws->ctx = ctx; - hws->regs = &hwseq_reg; - hws->shifts = &hwseq_shift; - hws->masks = &hwseq_mask; - } - return hws; -} - -static struct dce_hwseq *dce121_hwseq_create( - struct dc_context *ctx) -{ - struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); - - if (hws) { - hws->ctx = ctx; - hws->regs = &dce121_hwseq_reg; - hws->shifts = &dce121_hwseq_shift; - hws->masks = &dce121_hwseq_mask; - } - return hws; -} - -static const struct resource_create_funcs res_create_funcs = { - .read_dce_straps = read_dce_straps, - .create_audio = create_audio, - .create_stream_encoder = dce120_stream_encoder_create, - .create_hwseq = dce120_hwseq_create, -}; - -static const struct resource_create_funcs dce121_res_create_funcs = { - .read_dce_straps = read_dce_straps, - .create_audio = create_audio, - .create_stream_encoder = dce120_stream_encoder_create, - .create_hwseq = dce121_hwseq_create, -}; - - -#define mi_inst_regs(id) { MI_DCE12_REG_LIST(id) } -static const struct dce_mem_input_registers mi_regs[] = { - mi_inst_regs(0), - mi_inst_regs(1), - mi_inst_regs(2), - mi_inst_regs(3), - mi_inst_regs(4), - mi_inst_regs(5), -}; - -static const struct dce_mem_input_shift mi_shifts = { - MI_DCE12_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_mem_input_mask mi_masks = { - MI_DCE12_MASK_SH_LIST(_MASK) -}; - -static struct mem_input *dce120_mem_input_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dce_mem_input *dce_mi = kzalloc(sizeof(struct dce_mem_input), - GFP_KERNEL); - - if (!dce_mi) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dce120_mem_input_construct(dce_mi, ctx, inst, &mi_regs[inst], &mi_shifts, &mi_masks); - return &dce_mi->base; -} - -static struct transform *dce120_transform_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dce_transform *transform = - kzalloc(sizeof(struct dce_transform), GFP_KERNEL); - - if (!transform) - return NULL; - - dce_transform_construct(transform, ctx, inst, - &xfm_regs[inst], &xfm_shift, &xfm_mask); - transform->lb_memory_size = 0x1404; /*5124*/ - return &transform->base; -} - -static void dce120_destroy_resource_pool(struct resource_pool **pool) -{ - struct dce110_resource_pool *dce110_pool = TO_DCE110_RES_POOL(*pool); - - dce120_resource_destruct(dce110_pool); - kfree(dce110_pool); - *pool = NULL; -} - -static const struct resource_funcs dce120_res_pool_funcs = { - .destroy = dce120_destroy_resource_pool, - .link_enc_create = dce120_link_encoder_create, - .panel_cntl_create = dce120_panel_cntl_create, - .validate_bandwidth = dce112_validate_bandwidth, - .validate_plane = dce100_validate_plane, - .add_stream_to_ctx = dce112_add_stream_to_ctx, - .find_first_free_match_stream_enc_for_link = dce110_find_first_free_match_stream_enc_for_link -}; - -static void bw_calcs_data_update_from_pplib(struct dc *dc) -{ - struct dm_pp_clock_levels_with_latency eng_clks = {0}; - struct dm_pp_clock_levels_with_latency mem_clks = {0}; - struct dm_pp_wm_sets_with_clock_ranges clk_ranges = {0}; - int i; - unsigned int clk; - unsigned int latency; - /*original logic in dal3*/ - int memory_type_multiplier = MEMORY_TYPE_MULTIPLIER_CZ; - - /*do system clock*/ - if (!dm_pp_get_clock_levels_by_type_with_latency( - dc->ctx, - DM_PP_CLOCK_TYPE_ENGINE_CLK, - &eng_clks) || eng_clks.num_levels == 0) { - - eng_clks.num_levels = 8; - clk = 300000; - - for (i = 0; i < eng_clks.num_levels; i++) { - eng_clks.data[i].clocks_in_khz = clk; - clk += 100000; - } - } - - /* convert all the clock fro kHz to fix point mHz TODO: wloop data */ - dc->bw_vbios->high_sclk = bw_frc_to_fixed( - eng_clks.data[eng_clks.num_levels-1].clocks_in_khz, 1000); - dc->bw_vbios->mid1_sclk = bw_frc_to_fixed( - eng_clks.data[eng_clks.num_levels/8].clocks_in_khz, 1000); - dc->bw_vbios->mid2_sclk = bw_frc_to_fixed( - eng_clks.data[eng_clks.num_levels*2/8].clocks_in_khz, 1000); - dc->bw_vbios->mid3_sclk = bw_frc_to_fixed( - eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz, 1000); - dc->bw_vbios->mid4_sclk = bw_frc_to_fixed( - eng_clks.data[eng_clks.num_levels*4/8].clocks_in_khz, 1000); - dc->bw_vbios->mid5_sclk = bw_frc_to_fixed( - eng_clks.data[eng_clks.num_levels*5/8].clocks_in_khz, 1000); - dc->bw_vbios->mid6_sclk = bw_frc_to_fixed( - eng_clks.data[eng_clks.num_levels*6/8].clocks_in_khz, 1000); - dc->bw_vbios->low_sclk = bw_frc_to_fixed( - eng_clks.data[0].clocks_in_khz, 1000); - - /*do memory clock*/ - if (!dm_pp_get_clock_levels_by_type_with_latency( - dc->ctx, - DM_PP_CLOCK_TYPE_MEMORY_CLK, - &mem_clks) || mem_clks.num_levels == 0) { - - mem_clks.num_levels = 3; - clk = 250000; - latency = 45; - - for (i = 0; i < eng_clks.num_levels; i++) { - mem_clks.data[i].clocks_in_khz = clk; - mem_clks.data[i].latency_in_us = latency; - clk += 500000; - latency -= 5; - } - - } - - /* we don't need to call PPLIB for validation clock since they - * also give us the highest sclk and highest mclk (UMA clock). - * ALSO always convert UMA clock (from PPLIB) to YCLK (HW formula): - * YCLK = UMACLK*m_memoryTypeMultiplier - */ - if (dc->bw_vbios->memory_type == bw_def_hbm) - memory_type_multiplier = MEMORY_TYPE_HBM; - - dc->bw_vbios->low_yclk = bw_frc_to_fixed( - mem_clks.data[0].clocks_in_khz * memory_type_multiplier, 1000); - dc->bw_vbios->mid_yclk = bw_frc_to_fixed( - mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz * memory_type_multiplier, - 1000); - dc->bw_vbios->high_yclk = bw_frc_to_fixed( - mem_clks.data[mem_clks.num_levels-1].clocks_in_khz * memory_type_multiplier, - 1000); - - /* Now notify PPLib/SMU about which Watermarks sets they should select - * depending on DPM state they are in. And update BW MGR GFX Engine and - * Memory clock member variables for Watermarks calculations for each - * Watermark Set - */ - clk_ranges.num_wm_sets = 4; - clk_ranges.wm_clk_ranges[0].wm_set_id = WM_SET_A; - clk_ranges.wm_clk_ranges[0].wm_min_eng_clk_in_khz = - eng_clks.data[0].clocks_in_khz; - clk_ranges.wm_clk_ranges[0].wm_max_eng_clk_in_khz = - eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz - 1; - clk_ranges.wm_clk_ranges[0].wm_min_mem_clk_in_khz = - mem_clks.data[0].clocks_in_khz; - clk_ranges.wm_clk_ranges[0].wm_max_mem_clk_in_khz = - mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz - 1; - - clk_ranges.wm_clk_ranges[1].wm_set_id = WM_SET_B; - clk_ranges.wm_clk_ranges[1].wm_min_eng_clk_in_khz = - eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz; - /* 5 GHz instead of data[7].clockInKHz to cover Overdrive */ - clk_ranges.wm_clk_ranges[1].wm_max_eng_clk_in_khz = 5000000; - clk_ranges.wm_clk_ranges[1].wm_min_mem_clk_in_khz = - mem_clks.data[0].clocks_in_khz; - clk_ranges.wm_clk_ranges[1].wm_max_mem_clk_in_khz = - mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz - 1; - - clk_ranges.wm_clk_ranges[2].wm_set_id = WM_SET_C; - clk_ranges.wm_clk_ranges[2].wm_min_eng_clk_in_khz = - eng_clks.data[0].clocks_in_khz; - clk_ranges.wm_clk_ranges[2].wm_max_eng_clk_in_khz = - eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz - 1; - clk_ranges.wm_clk_ranges[2].wm_min_mem_clk_in_khz = - mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz; - /* 5 GHz instead of data[2].clockInKHz to cover Overdrive */ - clk_ranges.wm_clk_ranges[2].wm_max_mem_clk_in_khz = 5000000; - - clk_ranges.wm_clk_ranges[3].wm_set_id = WM_SET_D; - clk_ranges.wm_clk_ranges[3].wm_min_eng_clk_in_khz = - eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz; - /* 5 GHz instead of data[7].clockInKHz to cover Overdrive */ - clk_ranges.wm_clk_ranges[3].wm_max_eng_clk_in_khz = 5000000; - clk_ranges.wm_clk_ranges[3].wm_min_mem_clk_in_khz = - mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz; - /* 5 GHz instead of data[2].clockInKHz to cover Overdrive */ - clk_ranges.wm_clk_ranges[3].wm_max_mem_clk_in_khz = 5000000; - - /* Notify PP Lib/SMU which Watermarks to use for which clock ranges */ - dm_pp_notify_wm_clock_changes(dc->ctx, &clk_ranges); -} - -static uint32_t read_pipe_fuses(struct dc_context *ctx) -{ - uint32_t value = dm_read_reg_soc15(ctx, mmCC_DC_PIPE_DIS, 0); - /* VG20 support max 6 pipes */ - value = value & 0x3f; - return value; -} - -static bool dce120_resource_construct( - uint8_t num_virtual_links, - struct dc *dc, - struct dce110_resource_pool *pool) -{ - unsigned int i; - int j; - struct dc_context *ctx = dc->ctx; - struct irq_service_init_data irq_init_data; - static const struct resource_create_funcs *res_funcs; - bool is_vg20 = ASICREV_IS_VEGA20_P(ctx->asic_id.hw_internal_rev); - uint32_t pipe_fuses; - - ctx->dc_bios->regs = &bios_regs; - - pool->base.res_cap = &res_cap; - pool->base.funcs = &dce120_res_pool_funcs; - - /* TODO: Fill more data from GreenlandAsicCapability.cpp */ - pool->base.pipe_count = res_cap.num_timing_generator; - pool->base.timing_generator_count = pool->base.res_cap->num_timing_generator; - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; - - dc->caps.max_downscale_ratio = 200; - dc->caps.i2c_speed_in_khz = 100; - dc->caps.i2c_speed_in_khz_hdcp = 100; /*1.4 w/a not applied by default*/ - dc->caps.max_cursor_size = 128; - dc->caps.min_horizontal_blanking_period = 80; - dc->caps.dual_link_dvi = true; - dc->caps.psp_setup_panel_mode = true; - dc->caps.extended_aux_timeout_support = false; - dc->debug = debug_defaults; - - /************************************************* - * Create resources * - *************************************************/ - - pool->base.clock_sources[DCE120_CLK_SRC_PLL0] = - dce120_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL0, - &clk_src_regs[0], false); - pool->base.clock_sources[DCE120_CLK_SRC_PLL1] = - dce120_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL1, - &clk_src_regs[1], false); - pool->base.clock_sources[DCE120_CLK_SRC_PLL2] = - dce120_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL2, - &clk_src_regs[2], false); - pool->base.clock_sources[DCE120_CLK_SRC_PLL3] = - dce120_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL3, - &clk_src_regs[3], false); - pool->base.clock_sources[DCE120_CLK_SRC_PLL4] = - dce120_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL4, - &clk_src_regs[4], false); - pool->base.clock_sources[DCE120_CLK_SRC_PLL5] = - dce120_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL5, - &clk_src_regs[5], false); - pool->base.clk_src_count = DCE120_CLK_SRC_TOTAL; - - pool->base.dp_clock_source = - dce120_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_ID_DP_DTO, - &clk_src_regs[0], true); - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] == NULL) { - dm_error("DC: failed to create clock sources!\n"); - BREAK_TO_DEBUGGER(); - goto clk_src_create_fail; - } - } - - pool->base.dmcu = dce_dmcu_create(ctx, - &dmcu_regs, - &dmcu_shift, - &dmcu_mask); - if (pool->base.dmcu == NULL) { - dm_error("DC: failed to create dmcu!\n"); - BREAK_TO_DEBUGGER(); - goto res_create_fail; - } - - pool->base.abm = dce_abm_create(ctx, - &abm_regs, - &abm_shift, - &abm_mask); - if (pool->base.abm == NULL) { - dm_error("DC: failed to create abm!\n"); - BREAK_TO_DEBUGGER(); - goto res_create_fail; - } - - - irq_init_data.ctx = dc->ctx; - pool->base.irqs = dal_irq_service_dce120_create(&irq_init_data); - if (!pool->base.irqs) - goto irqs_create_fail; - - /* VG20: Pipe harvesting enabled, retrieve valid pipe fuses */ - if (is_vg20) - pipe_fuses = read_pipe_fuses(ctx); - - /* index to valid pipe resource */ - j = 0; - for (i = 0; i < pool->base.pipe_count; i++) { - if (is_vg20) { - if ((pipe_fuses & (1 << i)) != 0) { - dm_error("DC: skip invalid pipe %d!\n", i); - continue; - } - } - - pool->base.timing_generators[j] = - dce120_timing_generator_create( - ctx, - i, - &dce120_tg_offsets[i]); - if (pool->base.timing_generators[j] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create tg!\n"); - goto controller_create_fail; - } - - pool->base.mis[j] = dce120_mem_input_create(ctx, i); - - if (pool->base.mis[j] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create memory input!\n"); - goto controller_create_fail; - } - - pool->base.ipps[j] = dce120_ipp_create(ctx, i); - if (pool->base.ipps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create input pixel processor!\n"); - goto controller_create_fail; - } - - pool->base.transforms[j] = dce120_transform_create(ctx, i); - if (pool->base.transforms[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create transform!\n"); - goto res_create_fail; - } - - pool->base.opps[j] = dce120_opp_create( - ctx, - i); - if (pool->base.opps[j] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create output pixel processor!\n"); - } - - /* check next valid pipe */ - j++; - } - - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - pool->base.engines[i] = dce120_aux_engine_create(ctx, i); - if (pool->base.engines[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create aux engine!!\n"); - goto res_create_fail; - } - pool->base.hw_i2cs[i] = dce120_i2c_hw_create(ctx, i); - if (pool->base.hw_i2cs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create i2c engine!!\n"); - goto res_create_fail; - } - pool->base.sw_i2cs[i] = NULL; - } - - /* valid pipe num */ - pool->base.pipe_count = j; - pool->base.timing_generator_count = j; - - if (is_vg20) - res_funcs = &dce121_res_create_funcs; - else - res_funcs = &res_create_funcs; - - if (!resource_construct(num_virtual_links, dc, &pool->base, res_funcs)) - goto res_create_fail; - - /* Create hardware sequencer */ - if (!dce120_hw_sequencer_create(dc)) - goto controller_create_fail; - - dc->caps.max_planes = pool->base.pipe_count; - - for (i = 0; i < dc->caps.max_planes; ++i) - dc->caps.planes[i] = plane_cap; - - bw_calcs_init(dc->bw_dceip, dc->bw_vbios, dc->ctx->asic_id); - - bw_calcs_data_update_from_pplib(dc); - - return true; - -irqs_create_fail: -controller_create_fail: -clk_src_create_fail: -res_create_fail: - - dce120_resource_destruct(pool); - - return false; -} - -struct resource_pool *dce120_create_resource_pool( - uint8_t num_virtual_links, - struct dc *dc) -{ - struct dce110_resource_pool *pool = - kzalloc(sizeof(struct dce110_resource_pool), GFP_KERNEL); - - if (!pool) - return NULL; - - if (dce120_resource_construct(num_virtual_links, dc, pool)) - return &pool->base; - - kfree(pool); - BREAK_TO_DEBUGGER(); - return NULL; -} diff --git a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.h b/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.h deleted file mode 100644 index 3d1f3cf012f4a6..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.h +++ /dev/null @@ -1,39 +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 __DC_RESOURCE_DCE120_H__ -#define __DC_RESOURCE_DCE120_H__ - -#include "core_types.h" - -struct dc; -struct resource_pool; - -struct resource_pool *dce120_create_resource_pool( - uint8_t num_virtual_links, - struct dc *dc); - -#endif /* __DC_RESOURCE_DCE120_H__ */ - diff --git a/drivers/gpu/drm/amd/display/dc/dce80/Makefile b/drivers/gpu/drm/amd/display/dc/dce80/Makefile index 93dd68c31275be..7eefffbdc9253f 100644 --- a/drivers/gpu/drm/amd/display/dc/dce80/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dce80/Makefile @@ -25,8 +25,7 @@ CFLAGS_$(AMDDALPATH)/dc/dce80/dce80_resource.o = $(call cc-disable-warning, override-init) -DCE80 = dce80_timing_generator.o \ - dce80_resource.o +DCE80 = dce80_timing_generator.o AMD_DAL_DCE80 = $(addprefix $(AMDDALPATH)/dc/dce80/,$(DCE80)) diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c deleted file mode 100644 index 35a2cce0c2b8e6..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c +++ /dev/null @@ -1,1544 +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 - * - */ - -#include "dce/dce_8_0_d.h" -#include "dce/dce_8_0_sh_mask.h" - -#include "dm_services.h" - -#include "link_encoder.h" -#include "stream_encoder.h" - -#include "resource.h" -#include "include/irq_service_interface.h" -#include "irq/dce80/irq_service_dce80.h" -#include "dce110/dce110_timing_generator.h" -#include "dce110/dce110_resource.h" -#include "dce80/dce80_timing_generator.h" -#include "dce/dce_mem_input.h" -#include "dce/dce_link_encoder.h" -#include "dce/dce_stream_encoder.h" -#include "dce/dce_ipp.h" -#include "dce/dce_transform.h" -#include "dce/dce_opp.h" -#include "dce/dce_clock_source.h" -#include "dce/dce_audio.h" -#include "dce/dce_hwseq.h" -#include "dce80/dce80_hwseq.h" -#include "dce100/dce100_resource.h" -#include "dce/dce_panel_cntl.h" - -#include "reg_helper.h" - -#include "dce/dce_dmcu.h" -#include "dce/dce_aux.h" -#include "dce/dce_abm.h" -#include "dce/dce_i2c.h" -/* TODO remove this include */ - -#ifndef mmMC_HUB_RDREQ_DMIF_LIMIT -#include "gmc/gmc_7_1_d.h" -#include "gmc/gmc_7_1_sh_mask.h" -#endif - -#include "dce80/dce80_resource.h" - -#ifndef mmDP_DPHY_INTERNAL_CTRL -#define mmDP_DPHY_INTERNAL_CTRL 0x1CDE -#define mmDP0_DP_DPHY_INTERNAL_CTRL 0x1CDE -#define mmDP1_DP_DPHY_INTERNAL_CTRL 0x1FDE -#define mmDP2_DP_DPHY_INTERNAL_CTRL 0x42DE -#define mmDP3_DP_DPHY_INTERNAL_CTRL 0x45DE -#define mmDP4_DP_DPHY_INTERNAL_CTRL 0x48DE -#define mmDP5_DP_DPHY_INTERNAL_CTRL 0x4BDE -#define mmDP6_DP_DPHY_INTERNAL_CTRL 0x4EDE -#endif - - -#ifndef mmBIOS_SCRATCH_2 - #define mmBIOS_SCRATCH_2 0x05CB - #define mmBIOS_SCRATCH_3 0x05CC - #define mmBIOS_SCRATCH_6 0x05CF -#endif - -#ifndef mmDP_DPHY_FAST_TRAINING - #define mmDP_DPHY_FAST_TRAINING 0x1CCE - #define mmDP0_DP_DPHY_FAST_TRAINING 0x1CCE - #define mmDP1_DP_DPHY_FAST_TRAINING 0x1FCE - #define mmDP2_DP_DPHY_FAST_TRAINING 0x42CE - #define mmDP3_DP_DPHY_FAST_TRAINING 0x45CE - #define mmDP4_DP_DPHY_FAST_TRAINING 0x48CE - #define mmDP5_DP_DPHY_FAST_TRAINING 0x4BCE - #define mmDP6_DP_DPHY_FAST_TRAINING 0x4ECE -#endif - - -#ifndef mmHPD_DC_HPD_CONTROL - #define mmHPD_DC_HPD_CONTROL 0x189A - #define mmHPD0_DC_HPD_CONTROL 0x189A - #define mmHPD1_DC_HPD_CONTROL 0x18A2 - #define mmHPD2_DC_HPD_CONTROL 0x18AA - #define mmHPD3_DC_HPD_CONTROL 0x18B2 - #define mmHPD4_DC_HPD_CONTROL 0x18BA - #define mmHPD5_DC_HPD_CONTROL 0x18C2 -#endif - -#define DCE11_DIG_FE_CNTL 0x4a00 -#define DCE11_DIG_BE_CNTL 0x4a47 -#define DCE11_DP_SEC 0x4ac3 - -static const struct dce110_timing_generator_offsets dce80_tg_offsets[] = { - { - .crtc = (mmCRTC0_CRTC_CONTROL - mmCRTC_CONTROL), - .dcp = (mmGRPH_CONTROL - mmGRPH_CONTROL), - .dmif = (mmDMIF_PG0_DPG_WATERMARK_MASK_CONTROL - - mmDPG_WATERMARK_MASK_CONTROL), - }, - { - .crtc = (mmCRTC1_CRTC_CONTROL - mmCRTC_CONTROL), - .dcp = (mmDCP1_GRPH_CONTROL - mmGRPH_CONTROL), - .dmif = (mmDMIF_PG1_DPG_WATERMARK_MASK_CONTROL - - mmDPG_WATERMARK_MASK_CONTROL), - }, - { - .crtc = (mmCRTC2_CRTC_CONTROL - mmCRTC_CONTROL), - .dcp = (mmDCP2_GRPH_CONTROL - mmGRPH_CONTROL), - .dmif = (mmDMIF_PG2_DPG_WATERMARK_MASK_CONTROL - - mmDPG_WATERMARK_MASK_CONTROL), - }, - { - .crtc = (mmCRTC3_CRTC_CONTROL - mmCRTC_CONTROL), - .dcp = (mmDCP3_GRPH_CONTROL - mmGRPH_CONTROL), - .dmif = (mmDMIF_PG3_DPG_WATERMARK_MASK_CONTROL - - mmDPG_WATERMARK_MASK_CONTROL), - }, - { - .crtc = (mmCRTC4_CRTC_CONTROL - mmCRTC_CONTROL), - .dcp = (mmDCP4_GRPH_CONTROL - mmGRPH_CONTROL), - .dmif = (mmDMIF_PG4_DPG_WATERMARK_MASK_CONTROL - - mmDPG_WATERMARK_MASK_CONTROL), - }, - { - .crtc = (mmCRTC5_CRTC_CONTROL - mmCRTC_CONTROL), - .dcp = (mmDCP5_GRPH_CONTROL - mmGRPH_CONTROL), - .dmif = (mmDMIF_PG5_DPG_WATERMARK_MASK_CONTROL - - mmDPG_WATERMARK_MASK_CONTROL), - } -}; - -/* set register offset */ -#define SR(reg_name)\ - .reg_name = mm ## reg_name - -/* set register offset with instance */ -#define SRI(reg_name, block, id)\ - .reg_name = mm ## block ## id ## _ ## reg_name - -#define ipp_regs(id)\ -[id] = {\ - IPP_COMMON_REG_LIST_DCE_BASE(id)\ -} - -static const struct dce_ipp_registers ipp_regs[] = { - ipp_regs(0), - ipp_regs(1), - ipp_regs(2), - ipp_regs(3), - ipp_regs(4), - ipp_regs(5) -}; - -static const struct dce_ipp_shift ipp_shift = { - IPP_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) -}; - -static const struct dce_ipp_mask ipp_mask = { - IPP_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) -}; - -#define transform_regs(id)\ -[id] = {\ - XFM_COMMON_REG_LIST_DCE80(id)\ -} - -static const struct dce_transform_registers xfm_regs[] = { - transform_regs(0), - transform_regs(1), - transform_regs(2), - transform_regs(3), - transform_regs(4), - transform_regs(5) -}; - -static const struct dce_transform_shift xfm_shift = { - XFM_COMMON_MASK_SH_LIST_DCE80(__SHIFT) -}; - -static const struct dce_transform_mask xfm_mask = { - XFM_COMMON_MASK_SH_LIST_DCE80(_MASK) -}; - -#define aux_regs(id)\ -[id] = {\ - AUX_REG_LIST(id)\ -} - -static const struct dce110_link_enc_aux_registers link_enc_aux_regs[] = { - aux_regs(0), - aux_regs(1), - aux_regs(2), - aux_regs(3), - aux_regs(4), - aux_regs(5) -}; - -#define hpd_regs(id)\ -[id] = {\ - HPD_REG_LIST(id)\ -} - -static const struct dce110_link_enc_hpd_registers link_enc_hpd_regs[] = { - hpd_regs(0), - hpd_regs(1), - hpd_regs(2), - hpd_regs(3), - hpd_regs(4), - hpd_regs(5) -}; - -#define link_regs(id)\ -[id] = {\ - LE_DCE80_REG_LIST(id)\ -} - -static const struct dce110_link_enc_registers link_enc_regs[] = { - link_regs(0), - link_regs(1), - link_regs(2), - link_regs(3), - link_regs(4), - link_regs(5), - link_regs(6), -}; - -#define stream_enc_regs(id)\ -[id] = {\ - SE_COMMON_REG_LIST_DCE_BASE(id),\ - .AFMT_CNTL = 0,\ -} - -static const struct dce110_stream_enc_registers stream_enc_regs[] = { - stream_enc_regs(0), - stream_enc_regs(1), - stream_enc_regs(2), - stream_enc_regs(3), - stream_enc_regs(4), - stream_enc_regs(5), - stream_enc_regs(6) -}; - -static const struct dce_stream_encoder_shift se_shift = { - SE_COMMON_MASK_SH_LIST_DCE80_100(__SHIFT) -}; - -static const struct dce_stream_encoder_mask se_mask = { - SE_COMMON_MASK_SH_LIST_DCE80_100(_MASK) -}; - -static const struct dce_panel_cntl_registers panel_cntl_regs[] = { - { DCE_PANEL_CNTL_REG_LIST() } -}; - -static const struct dce_panel_cntl_shift panel_cntl_shift = { - DCE_PANEL_CNTL_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_panel_cntl_mask panel_cntl_mask = { - DCE_PANEL_CNTL_MASK_SH_LIST(_MASK) -}; - -#define opp_regs(id)\ -[id] = {\ - OPP_DCE_80_REG_LIST(id),\ -} - -static const struct dce_opp_registers opp_regs[] = { - opp_regs(0), - opp_regs(1), - opp_regs(2), - opp_regs(3), - opp_regs(4), - opp_regs(5) -}; - -static const struct dce_opp_shift opp_shift = { - OPP_COMMON_MASK_SH_LIST_DCE_80(__SHIFT) -}; - -static const struct dce_opp_mask opp_mask = { - OPP_COMMON_MASK_SH_LIST_DCE_80(_MASK) -}; - -static const struct dce110_aux_registers_shift aux_shift = { - DCE10_AUX_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce110_aux_registers_mask aux_mask = { - DCE10_AUX_MASK_SH_LIST(_MASK) -}; - -#define aux_engine_regs(id)\ -[id] = {\ - AUX_COMMON_REG_LIST(id), \ - .AUX_RESET_MASK = 0 \ -} - -static const struct dce110_aux_registers aux_engine_regs[] = { - aux_engine_regs(0), - aux_engine_regs(1), - aux_engine_regs(2), - aux_engine_regs(3), - aux_engine_regs(4), - aux_engine_regs(5) -}; - -#define audio_regs(id)\ -[id] = {\ - AUD_COMMON_REG_LIST(id)\ -} - -static const struct dce_audio_registers audio_regs[] = { - audio_regs(0), - audio_regs(1), - audio_regs(2), - audio_regs(3), - audio_regs(4), - audio_regs(5), - audio_regs(6), -}; - -static const struct dce_audio_shift audio_shift = { - AUD_COMMON_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_audio_mask audio_mask = { - AUD_COMMON_MASK_SH_LIST(_MASK) -}; - -#define clk_src_regs(id)\ -[id] = {\ - CS_COMMON_REG_LIST_DCE_80(id),\ -} - - -static const struct dce110_clk_src_regs clk_src_regs[] = { - clk_src_regs(0), - clk_src_regs(1), - clk_src_regs(2) -}; - -static const struct dce110_clk_src_shift cs_shift = { - CS_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) -}; - -static const struct dce110_clk_src_mask cs_mask = { - CS_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) -}; - -static const struct bios_registers bios_regs = { - .BIOS_SCRATCH_3 = mmBIOS_SCRATCH_3, - .BIOS_SCRATCH_6 = mmBIOS_SCRATCH_6 -}; - -static const struct resource_caps res_cap = { - .num_timing_generator = 6, - .num_audio = 6, - .num_stream_encoder = 6, - .num_pll = 3, - .num_ddc = 6, -}; - -static const struct resource_caps res_cap_81 = { - .num_timing_generator = 4, - .num_audio = 7, - .num_stream_encoder = 7, - .num_pll = 3, - .num_ddc = 6, -}; - -static const struct resource_caps res_cap_83 = { - .num_timing_generator = 2, - .num_audio = 6, - .num_stream_encoder = 6, - .num_pll = 2, - .num_ddc = 2, -}; - -static const struct dc_plane_cap plane_cap = { - .type = DC_PLANE_TYPE_DCE_RGB, - - .pixel_format_support = { - .argb8888 = true, - .nv12 = false, - .fp16 = true - }, - - .max_upscale_factor = { - .argb8888 = 16000, - .nv12 = 1, - .fp16 = 1 - }, - - .max_downscale_factor = { - .argb8888 = 250, - .nv12 = 1, - .fp16 = 1 - } -}; - -static const struct dc_debug_options debug_defaults = { - .enable_legacy_fast_update = true, -}; - -static const struct dce_dmcu_registers dmcu_regs = { - DMCU_DCE80_REG_LIST() -}; - -static const struct dce_dmcu_shift dmcu_shift = { - DMCU_MASK_SH_LIST_DCE80(__SHIFT) -}; - -static const struct dce_dmcu_mask dmcu_mask = { - DMCU_MASK_SH_LIST_DCE80(_MASK) -}; -static const struct dce_abm_registers abm_regs = { - ABM_DCE110_COMMON_REG_LIST() -}; - -static const struct dce_abm_shift abm_shift = { - ABM_MASK_SH_LIST_DCE110(__SHIFT) -}; - -static const struct dce_abm_mask abm_mask = { - ABM_MASK_SH_LIST_DCE110(_MASK) -}; - -#define CTX ctx -#define REG(reg) mm ## reg - -#ifndef mmCC_DC_HDMI_STRAPS -#define mmCC_DC_HDMI_STRAPS 0x1918 -#define CC_DC_HDMI_STRAPS__HDMI_DISABLE_MASK 0x40 -#define CC_DC_HDMI_STRAPS__HDMI_DISABLE__SHIFT 0x6 -#define CC_DC_HDMI_STRAPS__AUDIO_STREAM_NUMBER_MASK 0x700 -#define CC_DC_HDMI_STRAPS__AUDIO_STREAM_NUMBER__SHIFT 0x8 -#endif - -static int map_transmitter_id_to_phy_instance( - enum transmitter transmitter) -{ - switch (transmitter) { - case TRANSMITTER_UNIPHY_A: - return 0; - case TRANSMITTER_UNIPHY_B: - return 1; - case TRANSMITTER_UNIPHY_C: - return 2; - case TRANSMITTER_UNIPHY_D: - return 3; - case TRANSMITTER_UNIPHY_E: - return 4; - case TRANSMITTER_UNIPHY_F: - return 5; - case TRANSMITTER_UNIPHY_G: - return 6; - default: - ASSERT(0); - return 0; - } -} - -static void read_dce_straps( - struct dc_context *ctx, - struct resource_straps *straps) -{ - REG_GET_2(CC_DC_HDMI_STRAPS, - HDMI_DISABLE, &straps->hdmi_disable, - AUDIO_STREAM_NUMBER, &straps->audio_stream_number); - - REG_GET(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO, &straps->dc_pinstraps_audio); -} - -static struct audio *create_audio( - struct dc_context *ctx, unsigned int inst) -{ - return dce_audio_create(ctx, inst, - &audio_regs[inst], &audio_shift, &audio_mask); -} - -static struct timing_generator *dce80_timing_generator_create( - struct dc_context *ctx, - uint32_t instance, - const struct dce110_timing_generator_offsets *offsets) -{ - struct dce110_timing_generator *tg110 = - kzalloc(sizeof(struct dce110_timing_generator), GFP_KERNEL); - - if (!tg110) - return NULL; - - dce80_timing_generator_construct(tg110, ctx, instance, offsets); - return &tg110->base; -} - -static struct output_pixel_processor *dce80_opp_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dce110_opp *opp = - kzalloc(sizeof(struct dce110_opp), GFP_KERNEL); - - if (!opp) - return NULL; - - dce110_opp_construct(opp, - ctx, inst, &opp_regs[inst], &opp_shift, &opp_mask); - return &opp->base; -} - -static struct dce_aux *dce80_aux_engine_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct aux_engine_dce110 *aux_engine = - kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); - - if (!aux_engine) - return NULL; - - dce110_aux_engine_construct(aux_engine, ctx, inst, - SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, - &aux_engine_regs[inst], - &aux_mask, - &aux_shift, - ctx->dc->caps.extended_aux_timeout_support); - - return &aux_engine->base; -} -#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST(id) } - -static const struct dce_i2c_registers i2c_hw_regs[] = { - i2c_inst_regs(1), - i2c_inst_regs(2), - i2c_inst_regs(3), - i2c_inst_regs(4), - i2c_inst_regs(5), - i2c_inst_regs(6), -}; - -static const struct dce_i2c_shift i2c_shifts = { - I2C_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) -}; - -static const struct dce_i2c_mask i2c_masks = { - I2C_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) -}; - -static struct dce_i2c_hw *dce80_i2c_hw_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dce_i2c_hw *dce_i2c_hw = - kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); - - if (!dce_i2c_hw) - return NULL; - - dce_i2c_hw_construct(dce_i2c_hw, ctx, inst, - &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); - - return dce_i2c_hw; -} - -static struct dce_i2c_sw *dce80_i2c_sw_create( - struct dc_context *ctx) -{ - struct dce_i2c_sw *dce_i2c_sw = - kzalloc(sizeof(struct dce_i2c_sw), GFP_KERNEL); - - if (!dce_i2c_sw) - return NULL; - - dce_i2c_sw_construct(dce_i2c_sw, ctx); - - return dce_i2c_sw; -} -static struct stream_encoder *dce80_stream_encoder_create( - enum engine_id eng_id, - struct dc_context *ctx) -{ - struct dce110_stream_encoder *enc110 = - kzalloc(sizeof(struct dce110_stream_encoder), GFP_KERNEL); - - if (!enc110) - return NULL; - - dce110_stream_encoder_construct(enc110, ctx, ctx->dc_bios, eng_id, - &stream_enc_regs[eng_id], - &se_shift, &se_mask); - return &enc110->base; -} - -#define SRII(reg_name, block, id)\ - .reg_name[id] = mm ## block ## id ## _ ## reg_name - -static const struct dce_hwseq_registers hwseq_reg = { - HWSEQ_DCE8_REG_LIST() -}; - -static const struct dce_hwseq_shift hwseq_shift = { - HWSEQ_DCE8_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_hwseq_mask hwseq_mask = { - HWSEQ_DCE8_MASK_SH_LIST(_MASK) -}; - -static struct dce_hwseq *dce80_hwseq_create( - struct dc_context *ctx) -{ - struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); - - if (hws) { - hws->ctx = ctx; - hws->regs = &hwseq_reg; - hws->shifts = &hwseq_shift; - hws->masks = &hwseq_mask; - } - return hws; -} - -static const struct resource_create_funcs res_create_funcs = { - .read_dce_straps = read_dce_straps, - .create_audio = create_audio, - .create_stream_encoder = dce80_stream_encoder_create, - .create_hwseq = dce80_hwseq_create, -}; - -#define mi_inst_regs(id) { \ - MI_DCE8_REG_LIST(id), \ - .MC_HUB_RDREQ_DMIF_LIMIT = mmMC_HUB_RDREQ_DMIF_LIMIT \ -} -static const struct dce_mem_input_registers mi_regs[] = { - mi_inst_regs(0), - mi_inst_regs(1), - mi_inst_regs(2), - mi_inst_regs(3), - mi_inst_regs(4), - mi_inst_regs(5), -}; - -static const struct dce_mem_input_shift mi_shifts = { - MI_DCE8_MASK_SH_LIST(__SHIFT), - .ENABLE = MC_HUB_RDREQ_DMIF_LIMIT__ENABLE__SHIFT -}; - -static const struct dce_mem_input_mask mi_masks = { - MI_DCE8_MASK_SH_LIST(_MASK), - .ENABLE = MC_HUB_RDREQ_DMIF_LIMIT__ENABLE_MASK -}; - -static struct mem_input *dce80_mem_input_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dce_mem_input *dce_mi = kzalloc(sizeof(struct dce_mem_input), - GFP_KERNEL); - - if (!dce_mi) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dce_mem_input_construct(dce_mi, ctx, inst, &mi_regs[inst], &mi_shifts, &mi_masks); - dce_mi->wa.single_head_rdreq_dmif_limit = 2; - return &dce_mi->base; -} - -static void dce80_transform_destroy(struct transform **xfm) -{ - kfree(TO_DCE_TRANSFORM(*xfm)); - *xfm = NULL; -} - -static struct transform *dce80_transform_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dce_transform *transform = - kzalloc(sizeof(struct dce_transform), GFP_KERNEL); - - if (!transform) - return NULL; - - dce_transform_construct(transform, ctx, inst, - &xfm_regs[inst], &xfm_shift, &xfm_mask); - transform->prescaler_on = false; - return &transform->base; -} - -static const struct encoder_feature_support link_enc_feature = { - .max_hdmi_deep_color = COLOR_DEPTH_121212, - .max_hdmi_pixel_clock = 297000, - .flags.bits.IS_HBR2_CAPABLE = true, - .flags.bits.IS_TPS3_CAPABLE = true -}; - -static struct link_encoder *dce80_link_encoder_create( - struct dc_context *ctx, - const struct encoder_init_data *enc_init_data) -{ - struct dce110_link_encoder *enc110 = - kzalloc(sizeof(struct dce110_link_encoder), GFP_KERNEL); - int link_regs_id; - - if (!enc110) - return NULL; - - link_regs_id = - map_transmitter_id_to_phy_instance(enc_init_data->transmitter); - - dce110_link_encoder_construct(enc110, - enc_init_data, - &link_enc_feature, - &link_enc_regs[link_regs_id], - &link_enc_aux_regs[enc_init_data->channel - 1], - &link_enc_hpd_regs[enc_init_data->hpd_source]); - return &enc110->base; -} - -static struct panel_cntl *dce80_panel_cntl_create(const struct panel_cntl_init_data *init_data) -{ - struct dce_panel_cntl *panel_cntl = - kzalloc(sizeof(struct dce_panel_cntl), GFP_KERNEL); - - if (!panel_cntl) - return NULL; - - dce_panel_cntl_construct(panel_cntl, - init_data, - &panel_cntl_regs[init_data->inst], - &panel_cntl_shift, - &panel_cntl_mask); - - return &panel_cntl->base; -} - -static struct clock_source *dce80_clock_source_create( - struct dc_context *ctx, - struct dc_bios *bios, - enum clock_source_id id, - const struct dce110_clk_src_regs *regs, - bool dp_clk_src) -{ - struct dce110_clk_src *clk_src = - kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); - - if (!clk_src) - return NULL; - - if (dce110_clk_src_construct(clk_src, ctx, bios, id, - regs, &cs_shift, &cs_mask)) { - clk_src->base.dp_clk_src = dp_clk_src; - return &clk_src->base; - } - - kfree(clk_src); - BREAK_TO_DEBUGGER(); - return NULL; -} - -static void dce80_clock_source_destroy(struct clock_source **clk_src) -{ - kfree(TO_DCE110_CLK_SRC(*clk_src)); - *clk_src = NULL; -} - -static struct input_pixel_processor *dce80_ipp_create( - struct dc_context *ctx, uint32_t inst) -{ - struct dce_ipp *ipp = kzalloc(sizeof(struct dce_ipp), GFP_KERNEL); - - if (!ipp) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dce_ipp_construct(ipp, ctx, inst, - &ipp_regs[inst], &ipp_shift, &ipp_mask); - return &ipp->base; -} - -static void dce80_resource_destruct(struct dce110_resource_pool *pool) -{ - unsigned int i; - - for (i = 0; i < pool->base.pipe_count; i++) { - if (pool->base.opps[i] != NULL) - dce110_opp_destroy(&pool->base.opps[i]); - - if (pool->base.transforms[i] != NULL) - dce80_transform_destroy(&pool->base.transforms[i]); - - if (pool->base.ipps[i] != NULL) - dce_ipp_destroy(&pool->base.ipps[i]); - - if (pool->base.mis[i] != NULL) { - kfree(TO_DCE_MEM_INPUT(pool->base.mis[i])); - pool->base.mis[i] = NULL; - } - - if (pool->base.timing_generators[i] != NULL) { - kfree(DCE110TG_FROM_TG(pool->base.timing_generators[i])); - pool->base.timing_generators[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - if (pool->base.engines[i] != NULL) - dce110_engine_destroy(&pool->base.engines[i]); - if (pool->base.hw_i2cs[i] != NULL) { - kfree(pool->base.hw_i2cs[i]); - pool->base.hw_i2cs[i] = NULL; - } - if (pool->base.sw_i2cs[i] != NULL) { - kfree(pool->base.sw_i2cs[i]); - pool->base.sw_i2cs[i] = NULL; - } - } - - for (i = 0; i < pool->base.stream_enc_count; i++) { - if (pool->base.stream_enc[i] != NULL) - kfree(DCE110STRENC_FROM_STRENC(pool->base.stream_enc[i])); - } - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] != NULL) { - dce80_clock_source_destroy(&pool->base.clock_sources[i]); - } - } - - if (pool->base.abm != NULL) - dce_abm_destroy(&pool->base.abm); - - if (pool->base.dmcu != NULL) - dce_dmcu_destroy(&pool->base.dmcu); - - if (pool->base.dp_clock_source != NULL) - dce80_clock_source_destroy(&pool->base.dp_clock_source); - - for (i = 0; i < pool->base.audio_count; i++) { - if (pool->base.audios[i] != NULL) { - dce_aud_destroy(&pool->base.audios[i]); - } - } - - if (pool->base.irqs != NULL) { - dal_irq_service_destroy(&pool->base.irqs); - } -} - -static bool dce80_validate_bandwidth( - struct dc *dc, - struct dc_state *context, - bool fast_validate) -{ - int i; - bool at_least_one_pipe = false; - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - if (context->res_ctx.pipe_ctx[i].stream) - at_least_one_pipe = true; - } - - if (at_least_one_pipe) { - /* TODO implement when needed but for now hardcode max value*/ - context->bw_ctx.bw.dce.dispclk_khz = 681000; - context->bw_ctx.bw.dce.yclk_khz = 250000 * MEMORY_TYPE_MULTIPLIER_CZ; - } else { - context->bw_ctx.bw.dce.dispclk_khz = 0; - context->bw_ctx.bw.dce.yclk_khz = 0; - } - - return true; -} - -static bool dce80_validate_surface_sets( - struct dc_state *context) -{ - int i; - - for (i = 0; i < context->stream_count; i++) { - if (context->stream_status[i].plane_count == 0) - continue; - - if (context->stream_status[i].plane_count > 1) - return false; - - if (context->stream_status[i].plane_states[0]->format - >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) - return false; - } - - return true; -} - -static enum dc_status dce80_validate_global( - struct dc *dc, - struct dc_state *context) -{ - if (!dce80_validate_surface_sets(context)) - return DC_FAIL_SURFACE_VALIDATE; - - return DC_OK; -} - -static void dce80_destroy_resource_pool(struct resource_pool **pool) -{ - struct dce110_resource_pool *dce110_pool = TO_DCE110_RES_POOL(*pool); - - dce80_resource_destruct(dce110_pool); - kfree(dce110_pool); - *pool = NULL; -} - -static const struct resource_funcs dce80_res_pool_funcs = { - .destroy = dce80_destroy_resource_pool, - .link_enc_create = dce80_link_encoder_create, - .panel_cntl_create = dce80_panel_cntl_create, - .validate_bandwidth = dce80_validate_bandwidth, - .validate_plane = dce100_validate_plane, - .add_stream_to_ctx = dce100_add_stream_to_ctx, - .validate_global = dce80_validate_global, - .find_first_free_match_stream_enc_for_link = dce100_find_first_free_match_stream_enc_for_link -}; - -static bool dce80_construct( - uint8_t num_virtual_links, - struct dc *dc, - struct dce110_resource_pool *pool) -{ - unsigned int i; - struct dc_context *ctx = dc->ctx; - struct dc_bios *bp; - - ctx->dc_bios->regs = &bios_regs; - - pool->base.res_cap = &res_cap; - pool->base.funcs = &dce80_res_pool_funcs; - - - /************************************************* - * Resource + asic cap harcoding * - *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; - pool->base.pipe_count = res_cap.num_timing_generator; - pool->base.timing_generator_count = res_cap.num_timing_generator; - dc->caps.max_downscale_ratio = 200; - dc->caps.i2c_speed_in_khz = 40; - dc->caps.i2c_speed_in_khz_hdcp = 40; - dc->caps.max_cursor_size = 128; - dc->caps.min_horizontal_blanking_period = 80; - dc->caps.dual_link_dvi = true; - dc->caps.extended_aux_timeout_support = false; - dc->debug = debug_defaults; - - /************************************************* - * Create resources * - *************************************************/ - - bp = ctx->dc_bios; - - if (bp->fw_info_valid && bp->fw_info.external_clock_source_frequency_for_dp != 0) { - pool->base.dp_clock_source = - dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_EXTERNAL, NULL, true); - - pool->base.clock_sources[0] = - dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL0, &clk_src_regs[0], false); - pool->base.clock_sources[1] = - dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL1, &clk_src_regs[1], false); - pool->base.clock_sources[2] = - dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL2, &clk_src_regs[2], false); - pool->base.clk_src_count = 3; - - } else { - pool->base.dp_clock_source = - dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL0, &clk_src_regs[0], true); - - pool->base.clock_sources[0] = - dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL1, &clk_src_regs[1], false); - pool->base.clock_sources[1] = - dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL2, &clk_src_regs[2], false); - pool->base.clk_src_count = 2; - } - - if (pool->base.dp_clock_source == NULL) { - dm_error("DC: failed to create dp clock source!\n"); - BREAK_TO_DEBUGGER(); - goto res_create_fail; - } - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] == NULL) { - dm_error("DC: failed to create clock sources!\n"); - BREAK_TO_DEBUGGER(); - goto res_create_fail; - } - } - - pool->base.dmcu = dce_dmcu_create(ctx, - &dmcu_regs, - &dmcu_shift, - &dmcu_mask); - if (pool->base.dmcu == NULL) { - dm_error("DC: failed to create dmcu!\n"); - BREAK_TO_DEBUGGER(); - goto res_create_fail; - } - - pool->base.abm = dce_abm_create(ctx, - &abm_regs, - &abm_shift, - &abm_mask); - if (pool->base.abm == NULL) { - dm_error("DC: failed to create abm!\n"); - BREAK_TO_DEBUGGER(); - goto res_create_fail; - } - - { - struct irq_service_init_data init_data; - init_data.ctx = dc->ctx; - pool->base.irqs = dal_irq_service_dce80_create(&init_data); - if (!pool->base.irqs) - goto res_create_fail; - } - - for (i = 0; i < pool->base.pipe_count; i++) { - pool->base.timing_generators[i] = dce80_timing_generator_create( - ctx, i, &dce80_tg_offsets[i]); - if (pool->base.timing_generators[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create tg!\n"); - goto res_create_fail; - } - - pool->base.mis[i] = dce80_mem_input_create(ctx, i); - if (pool->base.mis[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create memory input!\n"); - goto res_create_fail; - } - - pool->base.ipps[i] = dce80_ipp_create(ctx, i); - if (pool->base.ipps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create input pixel processor!\n"); - goto res_create_fail; - } - - pool->base.transforms[i] = dce80_transform_create(ctx, i); - if (pool->base.transforms[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create transform!\n"); - goto res_create_fail; - } - - pool->base.opps[i] = dce80_opp_create(ctx, i); - if (pool->base.opps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create output pixel processor!\n"); - goto res_create_fail; - } - } - - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - pool->base.engines[i] = dce80_aux_engine_create(ctx, i); - if (pool->base.engines[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create aux engine!!\n"); - goto res_create_fail; - } - pool->base.hw_i2cs[i] = dce80_i2c_hw_create(ctx, i); - if (pool->base.hw_i2cs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create i2c engine!!\n"); - goto res_create_fail; - } - pool->base.sw_i2cs[i] = dce80_i2c_sw_create(ctx); - if (pool->base.sw_i2cs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create sw i2c!!\n"); - goto res_create_fail; - } - } - - dc->caps.max_planes = pool->base.pipe_count; - - for (i = 0; i < dc->caps.max_planes; ++i) - dc->caps.planes[i] = plane_cap; - - dc->caps.disable_dp_clk_share = true; - - if (!resource_construct(num_virtual_links, dc, &pool->base, - &res_create_funcs)) - goto res_create_fail; - - /* Create hardware sequencer */ - dce80_hw_sequencer_construct(dc); - - return true; - -res_create_fail: - dce80_resource_destruct(pool); - return false; -} - -struct resource_pool *dce80_create_resource_pool( - uint8_t num_virtual_links, - struct dc *dc) -{ - struct dce110_resource_pool *pool = - kzalloc(sizeof(struct dce110_resource_pool), GFP_KERNEL); - - if (!pool) - return NULL; - - if (dce80_construct(num_virtual_links, dc, pool)) - return &pool->base; - - kfree(pool); - BREAK_TO_DEBUGGER(); - return NULL; -} - -static bool dce81_construct( - uint8_t num_virtual_links, - struct dc *dc, - struct dce110_resource_pool *pool) -{ - unsigned int i; - struct dc_context *ctx = dc->ctx; - struct dc_bios *bp; - - ctx->dc_bios->regs = &bios_regs; - - pool->base.res_cap = &res_cap_81; - pool->base.funcs = &dce80_res_pool_funcs; - - - /************************************************* - * Resource + asic cap harcoding * - *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; - pool->base.pipe_count = res_cap_81.num_timing_generator; - pool->base.timing_generator_count = res_cap_81.num_timing_generator; - dc->caps.max_downscale_ratio = 200; - dc->caps.i2c_speed_in_khz = 40; - dc->caps.i2c_speed_in_khz_hdcp = 40; - dc->caps.max_cursor_size = 128; - dc->caps.min_horizontal_blanking_period = 80; - dc->caps.is_apu = true; - - /************************************************* - * Create resources * - *************************************************/ - - bp = ctx->dc_bios; - - if (bp->fw_info_valid && bp->fw_info.external_clock_source_frequency_for_dp != 0) { - pool->base.dp_clock_source = - dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_EXTERNAL, NULL, true); - - pool->base.clock_sources[0] = - dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL0, &clk_src_regs[0], false); - pool->base.clock_sources[1] = - dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL1, &clk_src_regs[1], false); - pool->base.clock_sources[2] = - dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL2, &clk_src_regs[2], false); - pool->base.clk_src_count = 3; - - } else { - pool->base.dp_clock_source = - dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL0, &clk_src_regs[0], true); - - pool->base.clock_sources[0] = - dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL1, &clk_src_regs[1], false); - pool->base.clock_sources[1] = - dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL2, &clk_src_regs[2], false); - pool->base.clk_src_count = 2; - } - - if (pool->base.dp_clock_source == NULL) { - dm_error("DC: failed to create dp clock source!\n"); - BREAK_TO_DEBUGGER(); - goto res_create_fail; - } - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] == NULL) { - dm_error("DC: failed to create clock sources!\n"); - BREAK_TO_DEBUGGER(); - goto res_create_fail; - } - } - - pool->base.dmcu = dce_dmcu_create(ctx, - &dmcu_regs, - &dmcu_shift, - &dmcu_mask); - if (pool->base.dmcu == NULL) { - dm_error("DC: failed to create dmcu!\n"); - BREAK_TO_DEBUGGER(); - goto res_create_fail; - } - - pool->base.abm = dce_abm_create(ctx, - &abm_regs, - &abm_shift, - &abm_mask); - if (pool->base.abm == NULL) { - dm_error("DC: failed to create abm!\n"); - BREAK_TO_DEBUGGER(); - goto res_create_fail; - } - - { - struct irq_service_init_data init_data; - init_data.ctx = dc->ctx; - pool->base.irqs = dal_irq_service_dce80_create(&init_data); - if (!pool->base.irqs) - goto res_create_fail; - } - - for (i = 0; i < pool->base.pipe_count; i++) { - pool->base.timing_generators[i] = dce80_timing_generator_create( - ctx, i, &dce80_tg_offsets[i]); - if (pool->base.timing_generators[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create tg!\n"); - goto res_create_fail; - } - - pool->base.mis[i] = dce80_mem_input_create(ctx, i); - if (pool->base.mis[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create memory input!\n"); - goto res_create_fail; - } - - pool->base.ipps[i] = dce80_ipp_create(ctx, i); - if (pool->base.ipps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create input pixel processor!\n"); - goto res_create_fail; - } - - pool->base.transforms[i] = dce80_transform_create(ctx, i); - if (pool->base.transforms[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create transform!\n"); - goto res_create_fail; - } - - pool->base.opps[i] = dce80_opp_create(ctx, i); - if (pool->base.opps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create output pixel processor!\n"); - goto res_create_fail; - } - } - - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - pool->base.engines[i] = dce80_aux_engine_create(ctx, i); - if (pool->base.engines[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create aux engine!!\n"); - goto res_create_fail; - } - pool->base.hw_i2cs[i] = dce80_i2c_hw_create(ctx, i); - if (pool->base.hw_i2cs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create i2c engine!!\n"); - goto res_create_fail; - } - pool->base.sw_i2cs[i] = dce80_i2c_sw_create(ctx); - if (pool->base.sw_i2cs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create sw i2c!!\n"); - goto res_create_fail; - } - } - - dc->caps.max_planes = pool->base.pipe_count; - - for (i = 0; i < dc->caps.max_planes; ++i) - dc->caps.planes[i] = plane_cap; - - dc->caps.disable_dp_clk_share = true; - - if (!resource_construct(num_virtual_links, dc, &pool->base, - &res_create_funcs)) - goto res_create_fail; - - /* Create hardware sequencer */ - dce80_hw_sequencer_construct(dc); - - return true; - -res_create_fail: - dce80_resource_destruct(pool); - return false; -} - -struct resource_pool *dce81_create_resource_pool( - uint8_t num_virtual_links, - struct dc *dc) -{ - struct dce110_resource_pool *pool = - kzalloc(sizeof(struct dce110_resource_pool), GFP_KERNEL); - - if (!pool) - return NULL; - - if (dce81_construct(num_virtual_links, dc, pool)) - return &pool->base; - - kfree(pool); - BREAK_TO_DEBUGGER(); - return NULL; -} - -static bool dce83_construct( - uint8_t num_virtual_links, - struct dc *dc, - struct dce110_resource_pool *pool) -{ - unsigned int i; - struct dc_context *ctx = dc->ctx; - struct dc_bios *bp; - - ctx->dc_bios->regs = &bios_regs; - - pool->base.res_cap = &res_cap_83; - pool->base.funcs = &dce80_res_pool_funcs; - - - /************************************************* - * Resource + asic cap harcoding * - *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; - pool->base.pipe_count = res_cap_83.num_timing_generator; - pool->base.timing_generator_count = res_cap_83.num_timing_generator; - dc->caps.max_downscale_ratio = 200; - dc->caps.i2c_speed_in_khz = 40; - dc->caps.i2c_speed_in_khz_hdcp = 40; - dc->caps.max_cursor_size = 128; - dc->caps.min_horizontal_blanking_period = 80; - dc->caps.is_apu = true; - dc->debug = debug_defaults; - - /************************************************* - * Create resources * - *************************************************/ - - bp = ctx->dc_bios; - - if (bp->fw_info_valid && bp->fw_info.external_clock_source_frequency_for_dp != 0) { - pool->base.dp_clock_source = - dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_EXTERNAL, NULL, true); - - pool->base.clock_sources[0] = - dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL1, &clk_src_regs[0], false); - pool->base.clock_sources[1] = - dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL2, &clk_src_regs[1], false); - pool->base.clk_src_count = 2; - - } else { - pool->base.dp_clock_source = - dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL1, &clk_src_regs[0], true); - - pool->base.clock_sources[0] = - dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL2, &clk_src_regs[1], false); - pool->base.clk_src_count = 1; - } - - if (pool->base.dp_clock_source == NULL) { - dm_error("DC: failed to create dp clock source!\n"); - BREAK_TO_DEBUGGER(); - goto res_create_fail; - } - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] == NULL) { - dm_error("DC: failed to create clock sources!\n"); - BREAK_TO_DEBUGGER(); - goto res_create_fail; - } - } - - pool->base.dmcu = dce_dmcu_create(ctx, - &dmcu_regs, - &dmcu_shift, - &dmcu_mask); - if (pool->base.dmcu == NULL) { - dm_error("DC: failed to create dmcu!\n"); - BREAK_TO_DEBUGGER(); - goto res_create_fail; - } - - pool->base.abm = dce_abm_create(ctx, - &abm_regs, - &abm_shift, - &abm_mask); - if (pool->base.abm == NULL) { - dm_error("DC: failed to create abm!\n"); - BREAK_TO_DEBUGGER(); - goto res_create_fail; - } - - { - struct irq_service_init_data init_data; - init_data.ctx = dc->ctx; - pool->base.irqs = dal_irq_service_dce80_create(&init_data); - if (!pool->base.irqs) - goto res_create_fail; - } - - for (i = 0; i < pool->base.pipe_count; i++) { - pool->base.timing_generators[i] = dce80_timing_generator_create( - ctx, i, &dce80_tg_offsets[i]); - if (pool->base.timing_generators[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create tg!\n"); - goto res_create_fail; - } - - pool->base.mis[i] = dce80_mem_input_create(ctx, i); - if (pool->base.mis[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create memory input!\n"); - goto res_create_fail; - } - - pool->base.ipps[i] = dce80_ipp_create(ctx, i); - if (pool->base.ipps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create input pixel processor!\n"); - goto res_create_fail; - } - - pool->base.transforms[i] = dce80_transform_create(ctx, i); - if (pool->base.transforms[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create transform!\n"); - goto res_create_fail; - } - - pool->base.opps[i] = dce80_opp_create(ctx, i); - if (pool->base.opps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create output pixel processor!\n"); - goto res_create_fail; - } - } - - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - pool->base.engines[i] = dce80_aux_engine_create(ctx, i); - if (pool->base.engines[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create aux engine!!\n"); - goto res_create_fail; - } - pool->base.hw_i2cs[i] = dce80_i2c_hw_create(ctx, i); - if (pool->base.hw_i2cs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create i2c engine!!\n"); - goto res_create_fail; - } - pool->base.sw_i2cs[i] = dce80_i2c_sw_create(ctx); - if (pool->base.sw_i2cs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create sw i2c!!\n"); - goto res_create_fail; - } - } - - dc->caps.max_planes = pool->base.pipe_count; - - for (i = 0; i < dc->caps.max_planes; ++i) - dc->caps.planes[i] = plane_cap; - - dc->caps.disable_dp_clk_share = true; - - if (!resource_construct(num_virtual_links, dc, &pool->base, - &res_create_funcs)) - goto res_create_fail; - - /* Create hardware sequencer */ - dce80_hw_sequencer_construct(dc); - - return true; - -res_create_fail: - dce80_resource_destruct(pool); - return false; -} - -struct resource_pool *dce83_create_resource_pool( - uint8_t num_virtual_links, - struct dc *dc) -{ - struct dce110_resource_pool *pool = - kzalloc(sizeof(struct dce110_resource_pool), GFP_KERNEL); - - if (!pool) - return NULL; - - if (dce83_construct(num_virtual_links, dc, pool)) - return &pool->base; - - BREAK_TO_DEBUGGER(); - return NULL; -} diff --git a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.h b/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.h deleted file mode 100644 index eff31ab83a39f9..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.h +++ /dev/null @@ -1,47 +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 __DC_RESOURCE_DCE80_H__ -#define __DC_RESOURCE_DCE80_H__ - -#include "core_types.h" - -struct dc; -struct resource_pool; - -struct resource_pool *dce80_create_resource_pool( - uint8_t num_virtual_links, - struct dc *dc); - -struct resource_pool *dce81_create_resource_pool( - uint8_t num_virtual_links, - struct dc *dc); - -struct resource_pool *dce83_create_resource_pool( - uint8_t num_virtual_links, - struct dc *dc); - -#endif /* __DC_RESOURCE_DCE80_H__ */ - diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/Makefile b/drivers/gpu/drm/amd/display/dc/dcn10/Makefile index 2d2007c3e2b614..ae6a131be71b6b 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn10/Makefile @@ -22,9 +22,9 @@ # # Makefile for DCN. -DCN10 = dcn10_init.o dcn10_resource.o dcn10_ipp.o \ +DCN10 = dcn10_ipp.o \ dcn10_hw_sequencer_debug.o \ - dcn10_dpp.o dcn10_opp.o dcn10_optc.o \ + dcn10_dpp.o dcn10_opp.o \ dcn10_hubp.o dcn10_mpc.o \ dcn10_dpp_dscl.o dcn10_dpp_cm.o dcn10_cm_common.o \ dcn10_hubbub.o dcn10_stream_encoder.o dcn10_link_encoder.o diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c index 92fdab731f4ac9..9033b39e0e0c83 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer_debug.c @@ -32,7 +32,7 @@ #include "dce/dce_hwseq.h" #include "abm.h" #include "dmcu.h" -#include "dcn10_optc.h" +#include "dcn10/dcn10_optc.h" #include "dcn10/dcn10_dpp.h" #include "dcn10/dcn10_mpc.h" #include "timing_generator.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c deleted file mode 100644 index a5bdac79a744eb..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.c +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2016-2020 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 "hw_sequencer_private.h" -#include "dce110/dce110_hwseq.h" -#include "dcn10/dcn10_hwseq.h" -#include "dcn20/dcn20_hwseq.h" - -static const struct hw_sequencer_funcs dcn10_funcs = { - .program_gamut_remap = dcn10_program_gamut_remap, - .init_hw = dcn10_init_hw, - .power_down_on_boot = dcn10_power_down_on_boot, - .apply_ctx_to_hw = dce110_apply_ctx_to_hw, - .apply_ctx_for_surface = NULL, - .program_front_end_for_ctx = dcn20_program_front_end_for_ctx, - .post_unlock_program_front_end = dcn10_post_unlock_program_front_end, - .wait_for_pending_cleared = dcn10_wait_for_pending_cleared, - .update_plane_addr = dcn10_update_plane_addr, - .update_dchub = dcn10_update_dchub, - .update_pending_status = dcn10_update_pending_status, - .program_output_csc = dcn10_program_output_csc, - .enable_accelerated_mode = dce110_enable_accelerated_mode, - .enable_timing_synchronization = dcn10_enable_timing_synchronization, - .enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset, - .update_info_frame = dce110_update_info_frame, - .send_immediate_sdp_message = dcn10_send_immediate_sdp_message, - .enable_stream = dce110_enable_stream, - .disable_stream = dce110_disable_stream, - .unblank_stream = dcn10_unblank_stream, - .blank_stream = dce110_blank_stream, - .enable_audio_stream = dce110_enable_audio_stream, - .disable_audio_stream = dce110_disable_audio_stream, - .disable_plane = dcn10_disable_plane, - .pipe_control_lock = dcn10_pipe_control_lock, - .cursor_lock = dcn10_cursor_lock, - .interdependent_update_lock = dcn10_lock_all_pipes, - .prepare_bandwidth = dcn10_prepare_bandwidth, - .optimize_bandwidth = dcn10_optimize_bandwidth, - .set_drr = dcn10_set_drr, - .get_position = dcn10_get_position, - .set_static_screen_control = dcn10_set_static_screen_control, - .setup_stereo = dcn10_setup_stereo, - .set_avmute = dce110_set_avmute, - .log_hw_state = dcn10_log_hw_state, - .get_hw_state = dcn10_get_hw_state, - .clear_status_bits = dcn10_clear_status_bits, - .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, - .edp_backlight_control = dce110_edp_backlight_control, - .edp_power_control = dce110_edp_power_control, - .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, - .set_cursor_position = dcn10_set_cursor_position, - .set_cursor_attribute = dcn10_set_cursor_attribute, - .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level, - .setup_periodic_interrupt = dcn10_setup_periodic_interrupt, - .set_clock = dcn10_set_clock, - .get_clock = dcn10_get_clock, - .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync, - .calc_vupdate_position = dcn10_calc_vupdate_position, - .power_down = dce110_power_down, - .set_backlight_level = dce110_set_backlight_level, - .set_abm_immediate_disable = dce110_set_abm_immediate_disable, - .set_pipe = dce110_set_pipe, - .enable_lvds_link_output = dce110_enable_lvds_link_output, - .enable_tmds_link_output = dce110_enable_tmds_link_output, - .enable_dp_link_output = dce110_enable_dp_link_output, - .disable_link_output = dce110_disable_link_output, - .get_dcc_en_bits = dcn10_get_dcc_en_bits, - .update_visual_confirm_color = dcn10_update_visual_confirm_color, -}; - -static const struct hwseq_private_funcs dcn10_private_funcs = { - .init_pipes = dcn10_init_pipes, - .update_plane_addr = dcn10_update_plane_addr, - .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, - .program_pipe = dcn10_program_pipe, - .update_mpcc = dcn10_update_mpcc, - .set_input_transfer_func = dcn10_set_input_transfer_func, - .set_output_transfer_func = dcn10_set_output_transfer_func, - .power_down = dce110_power_down, - .enable_display_power_gating = dcn10_dummy_display_power_gating, - .blank_pixel_data = dcn10_blank_pixel_data, - .reset_hw_ctx_wrap = dcn10_reset_hw_ctx_wrap, - .enable_stream_timing = dcn10_enable_stream_timing, - .edp_backlight_control = dce110_edp_backlight_control, - .disable_stream_gating = NULL, - .enable_stream_gating = NULL, - .setup_vupdate_interrupt = dcn10_setup_vupdate_interrupt, - .did_underflow_occur = dcn10_did_underflow_occur, - .init_blank = NULL, - .disable_vga = dcn10_disable_vga, - .bios_golden_init = dcn10_bios_golden_init, - .plane_atomic_disable = dcn10_plane_atomic_disable, - .plane_atomic_power_down = dcn10_plane_atomic_power_down, - .enable_power_gating_plane = dcn10_enable_power_gating_plane, - .dpp_pg_control = dcn10_dpp_pg_control, - .hubp_pg_control = dcn10_hubp_pg_control, - .dsc_pg_control = NULL, - .set_hdr_multiplier = dcn10_set_hdr_multiplier, - .verify_allow_pstate_change_high = dcn10_verify_allow_pstate_change_high, -}; - -void dcn10_hw_sequencer_construct(struct dc *dc) -{ - dc->hwss = dcn10_funcs; - dc->hwseq->funcs = dcn10_private_funcs; -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.h deleted file mode 100644 index 8c6fd7b844a4d7..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_init.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2016 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_DCN10_INIT_H__ -#define __DC_DCN10_INIT_H__ - -struct dc; - -void dcn10_hw_sequencer_construct(struct dc *dc); - -#endif /* __DC_DCN10_INIT_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c deleted file mode 100644 index 0e8f4f36c87c51..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c +++ /dev/null @@ -1,1621 +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 - * - */ - - -#include "reg_helper.h" -#include "dcn10_optc.h" -#include "dc.h" -#include "dc_trace.h" - -#define REG(reg)\ - optc1->tg_regs->reg - -#define CTX \ - optc1->base.ctx - -#undef FN -#define FN(reg_name, field_name) \ - optc1->tg_shift->field_name, optc1->tg_mask->field_name - -#define STATIC_SCREEN_EVENT_MASK_RANGETIMING_DOUBLE_BUFFER_UPDATE_EN 0x100 - -/** - * apply_front_porch_workaround() - This is a workaround for a bug that has - * existed since R5xx and has not been fixed - * keep Front porch at minimum 2 for Interlaced - * mode or 1 for progressive. - * - * @timing: Timing parameters used to configure DCN blocks. - */ -static void apply_front_porch_workaround(struct dc_crtc_timing *timing) -{ - if (timing->flags.INTERLACE == 1) { - if (timing->v_front_porch < 2) - timing->v_front_porch = 2; - } else { - if (timing->v_front_porch < 1) - timing->v_front_porch = 1; - } -} - -void optc1_program_global_sync( - struct timing_generator *optc, - int vready_offset, - int vstartup_start, - int vupdate_offset, - int vupdate_width) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - optc1->vready_offset = vready_offset; - optc1->vstartup_start = vstartup_start; - optc1->vupdate_offset = vupdate_offset; - optc1->vupdate_width = vupdate_width; - - if (optc1->vstartup_start == 0) { - BREAK_TO_DEBUGGER(); - return; - } - - REG_SET(OTG_VSTARTUP_PARAM, 0, - VSTARTUP_START, optc1->vstartup_start); - - REG_SET_2(OTG_VUPDATE_PARAM, 0, - VUPDATE_OFFSET, optc1->vupdate_offset, - VUPDATE_WIDTH, optc1->vupdate_width); - - REG_SET(OTG_VREADY_PARAM, 0, - VREADY_OFFSET, optc1->vready_offset); -} - -static void optc1_disable_stereo(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_SET(OTG_STEREO_CONTROL, 0, - OTG_STEREO_EN, 0); - - REG_SET_2(OTG_3D_STRUCTURE_CONTROL, 0, - OTG_3D_STRUCTURE_EN, 0, - OTG_3D_STRUCTURE_STEREO_SEL_OVR, 0); -} - -void optc1_setup_vertical_interrupt0( - struct timing_generator *optc, - uint32_t start_line, - uint32_t end_line) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_SET_2(OTG_VERTICAL_INTERRUPT0_POSITION, 0, - OTG_VERTICAL_INTERRUPT0_LINE_START, start_line, - OTG_VERTICAL_INTERRUPT0_LINE_END, end_line); -} - -void optc1_setup_vertical_interrupt1( - struct timing_generator *optc, - uint32_t start_line) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_SET(OTG_VERTICAL_INTERRUPT1_POSITION, 0, - OTG_VERTICAL_INTERRUPT1_LINE_START, start_line); -} - -void optc1_setup_vertical_interrupt2( - struct timing_generator *optc, - uint32_t start_line) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_SET(OTG_VERTICAL_INTERRUPT2_POSITION, 0, - OTG_VERTICAL_INTERRUPT2_LINE_START, start_line); -} - -/** - * optc1_program_timing() - used by mode timing set Program - * CRTC Timing Registers - OTG_H_*, - * OTG_V_*, Pixel repetition. - * Including SYNC. Call BIOS command table to program Timings. - * - * @optc: timing_generator instance. - * @dc_crtc_timing: Timing parameters used to configure DCN blocks. - * @vready_offset: Vready's starting position. - * @vstartup_start: Vstartup period. - * @vupdate_offset: Vupdate starting position. - * @vupdate_width: Vupdate duration. - * @signal: DC signal types. - * @use_vbios: to program timings from BIOS command table. - * - */ -void optc1_program_timing( - struct timing_generator *optc, - const struct dc_crtc_timing *dc_crtc_timing, - int vready_offset, - int vstartup_start, - int vupdate_offset, - int vupdate_width, - const enum signal_type signal, - bool use_vbios) -{ - struct dc_crtc_timing patched_crtc_timing; - uint32_t asic_blank_end; - uint32_t asic_blank_start; - uint32_t v_total; - uint32_t v_sync_end; - uint32_t h_sync_polarity, v_sync_polarity; - uint32_t start_point = 0; - uint32_t field_num = 0; - enum h_timing_div_mode h_div = H_TIMING_NO_DIV; - - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - optc1->signal = signal; - optc1->vready_offset = vready_offset; - optc1->vstartup_start = vstartup_start; - optc1->vupdate_offset = vupdate_offset; - optc1->vupdate_width = vupdate_width; - patched_crtc_timing = *dc_crtc_timing; - apply_front_porch_workaround(&patched_crtc_timing); - optc1->orginal_patched_timing = patched_crtc_timing; - - /* Load horizontal timing */ - - /* CRTC_H_TOTAL = vesa.h_total - 1 */ - REG_SET(OTG_H_TOTAL, 0, - OTG_H_TOTAL, patched_crtc_timing.h_total - 1); - - /* h_sync_start = 0, h_sync_end = vesa.h_sync_width */ - REG_UPDATE_2(OTG_H_SYNC_A, - OTG_H_SYNC_A_START, 0, - OTG_H_SYNC_A_END, patched_crtc_timing.h_sync_width); - - /* blank_start = line end - front porch */ - asic_blank_start = patched_crtc_timing.h_total - - patched_crtc_timing.h_front_porch; - - /* blank_end = blank_start - active */ - asic_blank_end = asic_blank_start - - patched_crtc_timing.h_border_right - - patched_crtc_timing.h_addressable - - patched_crtc_timing.h_border_left; - - REG_UPDATE_2(OTG_H_BLANK_START_END, - OTG_H_BLANK_START, asic_blank_start, - OTG_H_BLANK_END, asic_blank_end); - - /* h_sync polarity */ - h_sync_polarity = patched_crtc_timing.flags.HSYNC_POSITIVE_POLARITY ? - 0 : 1; - - REG_UPDATE(OTG_H_SYNC_A_CNTL, - OTG_H_SYNC_A_POL, h_sync_polarity); - - v_total = patched_crtc_timing.v_total - 1; - - REG_SET(OTG_V_TOTAL, 0, - OTG_V_TOTAL, v_total); - - /* In case of V_TOTAL_CONTROL is on, make sure OTG_V_TOTAL_MAX and - * OTG_V_TOTAL_MIN are equal to V_TOTAL. - */ - optc->funcs->set_vtotal_min_max(optc, v_total, v_total); - - /* v_sync_start = 0, v_sync_end = v_sync_width */ - v_sync_end = patched_crtc_timing.v_sync_width; - - REG_UPDATE_2(OTG_V_SYNC_A, - OTG_V_SYNC_A_START, 0, - OTG_V_SYNC_A_END, v_sync_end); - - /* 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; - - REG_UPDATE_2(OTG_V_BLANK_START_END, - OTG_V_BLANK_START, asic_blank_start, - OTG_V_BLANK_END, asic_blank_end); - - /* v_sync polarity */ - v_sync_polarity = patched_crtc_timing.flags.VSYNC_POSITIVE_POLARITY ? - 0 : 1; - - REG_UPDATE(OTG_V_SYNC_A_CNTL, - OTG_V_SYNC_A_POL, v_sync_polarity); - - if (optc1->signal == SIGNAL_TYPE_DISPLAY_PORT || - optc1->signal == SIGNAL_TYPE_DISPLAY_PORT_MST || - optc1->signal == SIGNAL_TYPE_EDP) { - start_point = 1; - if (patched_crtc_timing.flags.INTERLACE == 1) - field_num = 1; - } - - /* Interlace */ - if (REG(OTG_INTERLACE_CONTROL)) { - if (patched_crtc_timing.flags.INTERLACE == 1) - REG_UPDATE(OTG_INTERLACE_CONTROL, - OTG_INTERLACE_ENABLE, 1); - else - REG_UPDATE(OTG_INTERLACE_CONTROL, - OTG_INTERLACE_ENABLE, 0); - } - - /* VTG enable set to 0 first VInit */ - REG_UPDATE(CONTROL, - VTG0_ENABLE, 0); - - /* original code is using VTG offset to address OTG reg, seems wrong */ - REG_UPDATE_2(OTG_CONTROL, - OTG_START_POINT_CNTL, start_point, - OTG_FIELD_NUMBER_CNTL, field_num); - - optc->funcs->program_global_sync(optc, - vready_offset, - vstartup_start, - vupdate_offset, - vupdate_width); - - optc->funcs->set_vtg_params(optc, dc_crtc_timing, true); - - /* TODO - * patched_crtc_timing.flags.HORZ_COUNT_BY_TWO == 1 - * program_horz_count_by_2 - * for DVI 30bpp mode, 0 otherwise - * program_horz_count_by_2(optc, &patched_crtc_timing); - */ - - /* Enable stereo - only when we need to pack 3D frame. Other types - * of stereo handled in explicit call - */ - - if (optc1_is_two_pixels_per_containter(&patched_crtc_timing) || optc1->opp_count == 2) - h_div = H_TIMING_DIV_BY2; - - if (REG(OPTC_DATA_FORMAT_CONTROL) && optc1->tg_mask->OPTC_DATA_FORMAT != 0) { - uint32_t data_fmt = 0; - - if (patched_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR422) - data_fmt = 1; - else if (patched_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) - data_fmt = 2; - - REG_UPDATE(OPTC_DATA_FORMAT_CONTROL, OPTC_DATA_FORMAT, data_fmt); - } - - if (optc1->tg_mask->OTG_H_TIMING_DIV_MODE != 0) { - if (optc1->opp_count == 4) - h_div = H_TIMING_DIV_BY4; - - REG_UPDATE(OTG_H_TIMING_CNTL, - OTG_H_TIMING_DIV_MODE, h_div); - } else { - REG_UPDATE(OTG_H_TIMING_CNTL, - OTG_H_TIMING_DIV_BY2, h_div); - } -} - -/** - * optc1_set_vtg_params - Set Vertical Timing Generator (VTG) parameters - * - * @optc: timing_generator struct used to extract the optc parameters - * @dc_crtc_timing: Timing parameters configured - * @program_fp2: Boolean value indicating if FP2 will be programmed or not - * - * OTG is responsible for generating the global sync signals, including - * vertical timing information for each HUBP in the dcfclk domain. Each VTG is - * associated with one OTG that provides HUBP with vertical timing information - * (i.e., there is 1:1 correspondence between OTG and VTG). This function is - * responsible for setting the OTG parameters to the VTG during the pipe - * programming. - */ -void optc1_set_vtg_params(struct timing_generator *optc, - const struct dc_crtc_timing *dc_crtc_timing, bool program_fp2) -{ - struct dc_crtc_timing patched_crtc_timing; - uint32_t asic_blank_end; - uint32_t v_init; - uint32_t v_fp2 = 0; - int32_t vertical_line_start; - - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - patched_crtc_timing = *dc_crtc_timing; - apply_front_porch_workaround(&patched_crtc_timing); - - /* VCOUNT_INIT is the start of blank */ - v_init = patched_crtc_timing.v_total - patched_crtc_timing.v_front_porch; - - /* end of blank = v_init - active */ - asic_blank_end = v_init - - patched_crtc_timing.v_border_bottom - - patched_crtc_timing.v_addressable - - patched_crtc_timing.v_border_top; - - /* if VSTARTUP is before VSYNC, FP2 is the offset, otherwise 0 */ - vertical_line_start = asic_blank_end - optc1->vstartup_start + 1; - if (vertical_line_start < 0) - v_fp2 = -vertical_line_start; - - /* Interlace */ - if (REG(OTG_INTERLACE_CONTROL)) { - if (patched_crtc_timing.flags.INTERLACE == 1) { - v_init = v_init / 2; - if ((optc1->vstartup_start/2)*2 > asic_blank_end) - v_fp2 = v_fp2 / 2; - } - } - - if (program_fp2) - REG_UPDATE_2(CONTROL, - VTG0_FP2, v_fp2, - VTG0_VCOUNT_INIT, v_init); - else - REG_UPDATE(CONTROL, VTG0_VCOUNT_INIT, v_init); -} - -void optc1_set_blank_data_double_buffer(struct timing_generator *optc, bool enable) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - uint32_t blank_data_double_buffer_enable = enable ? 1 : 0; - - REG_UPDATE(OTG_DOUBLE_BUFFER_CONTROL, - OTG_BLANK_DATA_DOUBLE_BUFFER_EN, blank_data_double_buffer_enable); -} - -/** - * optc1_set_timing_double_buffer() - DRR double buffering control - * - * Sets double buffer point for V_TOTAL, H_TOTAL, VTOTAL_MIN, - * VTOTAL_MAX, VTOTAL_MIN_SEL and VTOTAL_MAX_SEL registers. - * - * @optc: timing_generator instance. - * @enable: Enable DRR double buffering control if true, disable otherwise. - * - * Options: any time, start of frame, dp start of frame (range timing) - */ -void optc1_set_timing_double_buffer(struct timing_generator *optc, bool enable) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - uint32_t mode = enable ? 2 : 0; - - REG_UPDATE(OTG_DOUBLE_BUFFER_CONTROL, - OTG_RANGE_TIMING_DBUF_UPDATE_MODE, mode); -} - -/** - * optc1_unblank_crtc() - Call ASIC Control Object to UnBlank CRTC. - * - * @optc: timing_generator instance. - */ -static void optc1_unblank_crtc(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_UPDATE_2(OTG_BLANK_CONTROL, - OTG_BLANK_DATA_EN, 0, - OTG_BLANK_DE_MODE, 0); - - /* W/A for automated testing - * Automated testing will fail underflow test as there - * sporadic underflows which occur during the optc blank - * sequence. As a w/a, clear underflow on unblank. - * This prevents the failure, but will not mask actual - * underflow that affect real use cases. - */ - optc1_clear_optc_underflow(optc); -} - -/** - * optc1_blank_crtc() - Call ASIC Control Object to Blank CRTC. - * - * @optc: timing_generator instance. - */ - -static void optc1_blank_crtc(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_UPDATE_2(OTG_BLANK_CONTROL, - OTG_BLANK_DATA_EN, 1, - OTG_BLANK_DE_MODE, 0); - - optc1_set_blank_data_double_buffer(optc, false); -} - -void optc1_set_blank(struct timing_generator *optc, - bool enable_blanking) -{ - if (enable_blanking) - optc1_blank_crtc(optc); - else - optc1_unblank_crtc(optc); -} - -bool optc1_is_blanked(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - uint32_t blank_en; - uint32_t blank_state; - - REG_GET_2(OTG_BLANK_CONTROL, - OTG_BLANK_DATA_EN, &blank_en, - OTG_CURRENT_BLANK_STATE, &blank_state); - - return blank_en && blank_state; -} - -void optc1_enable_optc_clock(struct timing_generator *optc, bool enable) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - if (enable) { - REG_UPDATE_2(OPTC_INPUT_CLOCK_CONTROL, - OPTC_INPUT_CLK_EN, 1, - OPTC_INPUT_CLK_GATE_DIS, 1); - - REG_WAIT(OPTC_INPUT_CLOCK_CONTROL, - OPTC_INPUT_CLK_ON, 1, - 1, 1000); - - /* Enable clock */ - REG_UPDATE_2(OTG_CLOCK_CONTROL, - OTG_CLOCK_EN, 1, - OTG_CLOCK_GATE_DIS, 1); - REG_WAIT(OTG_CLOCK_CONTROL, - OTG_CLOCK_ON, 1, - 1, 1000); - } else { - - //last chance to clear underflow, otherwise, it will always there due to clock is off. - if (optc->funcs->is_optc_underflow_occurred(optc) == true) - optc->funcs->clear_optc_underflow(optc); - - REG_UPDATE_2(OTG_CLOCK_CONTROL, - OTG_CLOCK_GATE_DIS, 0, - OTG_CLOCK_EN, 0); - - REG_UPDATE_2(OPTC_INPUT_CLOCK_CONTROL, - OPTC_INPUT_CLK_GATE_DIS, 0, - OPTC_INPUT_CLK_EN, 0); - } -} - -/** - * optc1_enable_crtc() - Enable CRTC - call ASIC Control Object to enable Timing generator. - * - * @optc: timing_generator instance. - */ -static bool optc1_enable_crtc(struct timing_generator *optc) -{ - /* TODO FPGA wait for answer - * OTG_MASTER_UPDATE_MODE != CRTC_MASTER_UPDATE_MODE - * OTG_MASTER_UPDATE_LOCK != CRTC_MASTER_UPDATE_LOCK - */ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - /* opp instance for OTG. For DCN1.0, ODM is remoed. - * OPP and OPTC should 1:1 mapping - */ - REG_UPDATE(OPTC_DATA_SOURCE_SELECT, - OPTC_SRC_SEL, optc->inst); - - /* VTG enable first is for HW workaround */ - REG_UPDATE(CONTROL, - VTG0_ENABLE, 1); - - REG_SEQ_START(); - - /* Enable CRTC */ - REG_UPDATE_2(OTG_CONTROL, - OTG_DISABLE_POINT_CNTL, 3, - OTG_MASTER_EN, 1); - - REG_SEQ_SUBMIT(); - REG_SEQ_WAIT_DONE(); - - return true; -} - -/* disable_crtc - call ASIC Control Object to disable Timing generator. */ -bool optc1_disable_crtc(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - /* disable otg request until end of the first line - * in the vertical blank region - */ - REG_UPDATE_2(OTG_CONTROL, - OTG_DISABLE_POINT_CNTL, 3, - OTG_MASTER_EN, 0); - - REG_UPDATE(CONTROL, - VTG0_ENABLE, 0); - - /* CRTC disabled, so disable clock. */ - REG_WAIT(OTG_CLOCK_CONTROL, - OTG_BUSY, 0, - 1, 100000); - - return true; -} - - -void optc1_program_blank_color( - struct timing_generator *optc, - const struct tg_color *black_color) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_SET_3(OTG_BLACK_COLOR, 0, - OTG_BLACK_COLOR_B_CB, black_color->color_b_cb, - OTG_BLACK_COLOR_G_Y, black_color->color_g_y, - OTG_BLACK_COLOR_R_CR, black_color->color_r_cr); -} - -bool optc1_validate_timing( - struct timing_generator *optc, - const struct dc_crtc_timing *timing) -{ - uint32_t v_blank; - uint32_t h_blank; - uint32_t min_v_blank; - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - ASSERT(timing != NULL); - - v_blank = (timing->v_total - timing->v_addressable - - timing->v_border_top - timing->v_border_bottom); - - h_blank = (timing->h_total - timing->h_addressable - - timing->h_border_right - - timing->h_border_left); - - if (timing->timing_3d_format != TIMING_3D_FORMAT_NONE && - timing->timing_3d_format != TIMING_3D_FORMAT_HW_FRAME_PACKING && - timing->timing_3d_format != TIMING_3D_FORMAT_TOP_AND_BOTTOM && - timing->timing_3d_format != TIMING_3D_FORMAT_SIDE_BY_SIDE && - timing->timing_3d_format != TIMING_3D_FORMAT_FRAME_ALTERNATE && - timing->timing_3d_format != TIMING_3D_FORMAT_INBAND_FA) - return false; - - /* Temporarily blocking interlacing mode until it's supported */ - if (timing->flags.INTERLACE == 1) - return false; - - /* Check maximum number of pixels supported by Timing Generator - * (Currently will never fail, in order to fail needs display which - * needs more than 8192 horizontal and - * more than 8192 vertical total pixels) - */ - if (timing->h_total > optc1->max_h_total || - timing->v_total > optc1->max_v_total) - return false; - - - if (h_blank < optc1->min_h_blank) - return false; - - if (timing->h_sync_width < optc1->min_h_sync_width || - timing->v_sync_width < optc1->min_v_sync_width) - return false; - - min_v_blank = timing->flags.INTERLACE?optc1->min_v_blank_interlace:optc1->min_v_blank; - - if (v_blank < min_v_blank) - return false; - - return true; - -} - -/* - * get_vblank_counter - * - * @brief - * Get counter for vertical blanks. use register CRTC_STATUS_FRAME_COUNT which - * holds the counter of frames. - * - * @param - * struct timing_generator *optc - [in] timing generator which controls the - * desired CRTC - * - * @return - * Counter of frames, which should equal to number of vblanks. - */ -uint32_t optc1_get_vblank_counter(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - uint32_t frame_count; - - REG_GET(OTG_STATUS_FRAME_COUNT, - OTG_FRAME_COUNT, &frame_count); - - return frame_count; -} - -void optc1_lock(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_SET(OTG_GLOBAL_CONTROL0, 0, - OTG_MASTER_UPDATE_LOCK_SEL, optc->inst); - REG_SET(OTG_MASTER_UPDATE_LOCK, 0, - OTG_MASTER_UPDATE_LOCK, 1); - - REG_WAIT(OTG_MASTER_UPDATE_LOCK, - UPDATE_LOCK_STATUS, 1, - 1, 10); - - TRACE_OPTC_LOCK_UNLOCK_STATE(optc1, optc->inst, true); -} - -void optc1_unlock(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_SET(OTG_MASTER_UPDATE_LOCK, 0, - OTG_MASTER_UPDATE_LOCK, 0); - - TRACE_OPTC_LOCK_UNLOCK_STATE(optc1, optc->inst, false); -} - -void optc1_get_position(struct timing_generator *optc, - struct crtc_position *position) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_GET_2(OTG_STATUS_POSITION, - OTG_HORZ_COUNT, &position->horizontal_count, - OTG_VERT_COUNT, &position->vertical_count); - - REG_GET(OTG_NOM_VERT_POSITION, - OTG_VERT_COUNT_NOM, &position->nominal_vcount); -} - -bool optc1_is_counter_moving(struct timing_generator *optc) -{ - struct crtc_position position1, position2; - - optc->funcs->get_position(optc, &position1); - optc->funcs->get_position(optc, &position2); - - if (position1.horizontal_count == position2.horizontal_count && - position1.vertical_count == position2.vertical_count) - return false; - else - return true; -} - -bool optc1_did_triggered_reset_occur( - struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - uint32_t occurred_force, occurred_vsync; - - REG_GET(OTG_FORCE_COUNT_NOW_CNTL, - OTG_FORCE_COUNT_NOW_OCCURRED, &occurred_force); - - REG_GET(OTG_VERT_SYNC_CONTROL, - OTG_FORCE_VSYNC_NEXT_LINE_OCCURRED, &occurred_vsync); - - return occurred_vsync != 0 || occurred_force != 0; -} - -void optc1_disable_reset_trigger(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_WRITE(OTG_TRIGA_CNTL, 0); - - REG_SET(OTG_FORCE_COUNT_NOW_CNTL, 0, - OTG_FORCE_COUNT_NOW_CLEAR, 1); - - REG_SET(OTG_VERT_SYNC_CONTROL, 0, - OTG_FORCE_VSYNC_NEXT_LINE_CLEAR, 1); -} - -void optc1_enable_reset_trigger(struct timing_generator *optc, int source_tg_inst) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - uint32_t falling_edge; - - REG_GET(OTG_V_SYNC_A_CNTL, - OTG_V_SYNC_A_POL, &falling_edge); - - if (falling_edge) - REG_SET_3(OTG_TRIGA_CNTL, 0, - /* vsync signal from selected OTG pipe based - * on OTG_TRIG_SOURCE_PIPE_SELECT setting - */ - OTG_TRIGA_SOURCE_SELECT, 20, - OTG_TRIGA_SOURCE_PIPE_SELECT, source_tg_inst, - /* always detect falling edge */ - OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, 1); - else - REG_SET_3(OTG_TRIGA_CNTL, 0, - /* vsync signal from selected OTG pipe based - * on OTG_TRIG_SOURCE_PIPE_SELECT setting - */ - OTG_TRIGA_SOURCE_SELECT, 20, - OTG_TRIGA_SOURCE_PIPE_SELECT, source_tg_inst, - /* always detect rising edge */ - OTG_TRIGA_RISING_EDGE_DETECT_CNTL, 1); - - REG_SET(OTG_FORCE_COUNT_NOW_CNTL, 0, - /* force H count to H_TOTAL and V count to V_TOTAL in - * progressive mode and V_TOTAL-1 in interlaced mode - */ - OTG_FORCE_COUNT_NOW_MODE, 2); -} - -void optc1_enable_crtc_reset( - struct timing_generator *optc, - int source_tg_inst, - struct crtc_trigger_info *crtc_tp) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - uint32_t falling_edge = 0; - uint32_t rising_edge = 0; - - switch (crtc_tp->event) { - - case CRTC_EVENT_VSYNC_RISING: - rising_edge = 1; - break; - - case CRTC_EVENT_VSYNC_FALLING: - falling_edge = 1; - break; - } - - REG_SET_4(OTG_TRIGA_CNTL, 0, - /* vsync signal from selected OTG pipe based - * on OTG_TRIG_SOURCE_PIPE_SELECT setting - */ - OTG_TRIGA_SOURCE_SELECT, 20, - OTG_TRIGA_SOURCE_PIPE_SELECT, source_tg_inst, - /* always detect falling edge */ - OTG_TRIGA_RISING_EDGE_DETECT_CNTL, rising_edge, - OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, falling_edge); - - switch (crtc_tp->delay) { - case TRIGGER_DELAY_NEXT_LINE: - REG_SET(OTG_VERT_SYNC_CONTROL, 0, - OTG_AUTO_FORCE_VSYNC_MODE, 1); - break; - case TRIGGER_DELAY_NEXT_PIXEL: - REG_SET(OTG_FORCE_COUNT_NOW_CNTL, 0, - /* force H count to H_TOTAL and V count to V_TOTAL in - * progressive mode and V_TOTAL-1 in interlaced mode - */ - OTG_FORCE_COUNT_NOW_MODE, 2); - break; - } -} - -void optc1_wait_for_state(struct timing_generator *optc, - enum crtc_state state) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - switch (state) { - case CRTC_STATE_VBLANK: - REG_WAIT(OTG_STATUS, - OTG_V_BLANK, 1, - 1, 100000); /* 1 vupdate at 10hz */ - break; - - case CRTC_STATE_VACTIVE: - REG_WAIT(OTG_STATUS, - OTG_V_ACTIVE_DISP, 1, - 1, 100000); /* 1 vupdate at 10hz */ - break; - - default: - break; - } -} - -void optc1_set_early_control( - struct timing_generator *optc, - uint32_t early_cntl) -{ - /* asic design change, do not need this control - * empty for share caller logic - */ -} - - -void optc1_set_static_screen_control( - struct timing_generator *optc, - uint32_t event_triggers, - uint32_t num_frames) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - // By register spec, it only takes 8 bit value - if (num_frames > 0xFF) - num_frames = 0xFF; - - /* Bit 8 is no longer applicable in RV for PSR case, - * set bit 8 to 0 if given - */ - if ((event_triggers & STATIC_SCREEN_EVENT_MASK_RANGETIMING_DOUBLE_BUFFER_UPDATE_EN) - != 0) - event_triggers = event_triggers & - ~STATIC_SCREEN_EVENT_MASK_RANGETIMING_DOUBLE_BUFFER_UPDATE_EN; - - REG_SET_2(OTG_STATIC_SCREEN_CONTROL, 0, - OTG_STATIC_SCREEN_EVENT_MASK, event_triggers, - OTG_STATIC_SCREEN_FRAME_COUNT, num_frames); -} - -static void optc1_setup_manual_trigger(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_SET(OTG_GLOBAL_CONTROL2, 0, - MANUAL_FLOW_CONTROL_SEL, optc->inst); - - REG_SET_8(OTG_TRIGA_CNTL, 0, - OTG_TRIGA_SOURCE_SELECT, 22, - OTG_TRIGA_SOURCE_PIPE_SELECT, optc->inst, - OTG_TRIGA_RISING_EDGE_DETECT_CNTL, 1, - OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, 0, - OTG_TRIGA_POLARITY_SELECT, 0, - OTG_TRIGA_FREQUENCY_SELECT, 0, - OTG_TRIGA_DELAY, 0, - OTG_TRIGA_CLEAR, 1); -} - -static void optc1_program_manual_trigger(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_SET(OTG_MANUAL_FLOW_CONTROL, 0, - MANUAL_FLOW_CONTROL, 1); - - REG_SET(OTG_MANUAL_FLOW_CONTROL, 0, - MANUAL_FLOW_CONTROL, 0); -} - -/** - * optc1_set_drr() - Program dynamic refresh rate registers m_OTGx_OTG_V_TOTAL_*. - * - * @optc: timing_generator instance. - * @params: parameters used for Dynamic Refresh Rate. - */ -void optc1_set_drr( - struct timing_generator *optc, - const struct drr_params *params) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - if (params != NULL && - params->vertical_total_max > 0 && - params->vertical_total_min > 0) { - - if (params->vertical_total_mid != 0) { - - REG_SET(OTG_V_TOTAL_MID, 0, - OTG_V_TOTAL_MID, params->vertical_total_mid - 1); - - REG_UPDATE_2(OTG_V_TOTAL_CONTROL, - OTG_VTOTAL_MID_REPLACING_MAX_EN, 1, - OTG_VTOTAL_MID_FRAME_NUM, - (uint8_t)params->vertical_total_mid_frame_num); - - } - - optc->funcs->set_vtotal_min_max(optc, params->vertical_total_min - 1, params->vertical_total_max - 1); - - REG_UPDATE_5(OTG_V_TOTAL_CONTROL, - OTG_V_TOTAL_MIN_SEL, 1, - OTG_V_TOTAL_MAX_SEL, 1, - OTG_FORCE_LOCK_ON_EVENT, 0, - OTG_SET_V_TOTAL_MIN_MASK_EN, 0, - OTG_SET_V_TOTAL_MIN_MASK, 0); - } - - // Setup manual flow control for EOF via TRIG_A - optc->funcs->setup_manual_trigger(optc); -} - -void optc1_set_vtotal_min_max(struct timing_generator *optc, int vtotal_min, int vtotal_max) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_SET(OTG_V_TOTAL_MAX, 0, - OTG_V_TOTAL_MAX, vtotal_max); - - REG_SET(OTG_V_TOTAL_MIN, 0, - OTG_V_TOTAL_MIN, vtotal_min); -} - -static void optc1_set_test_pattern( - struct timing_generator *optc, - /* TODO: replace 'controller_dp_test_pattern' by 'test_pattern_mode' - * because this is not DP-specific (which is probably somewhere in DP - * encoder) */ - enum controller_dp_test_pattern test_pattern, - enum dc_color_depth color_depth) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - enum test_pattern_color_format bit_depth; - enum test_pattern_dyn_range dyn_range; - enum test_pattern_mode mode; - uint32_t pattern_mask; - uint32_t pattern_data; - /* color ramp generator mixes 16-bits color */ - uint32_t src_bpc = 16; - /* requested bpc */ - uint32_t dst_bpc; - uint32_t index; - /* RGB values of the color bars. - * Produce two RGB colors: RGB0 - white (all Fs) - * and RGB1 - black (all 0s) - * (three RGB components for two colors) - */ - uint16_t src_color[6] = {0xFFFF, 0xFFFF, 0xFFFF, 0x0000, - 0x0000, 0x0000}; - /* dest color (converted to the specified color format) */ - uint16_t dst_color[6]; - uint32_t inc_base; - - /* translate to bit depth */ - switch (color_depth) { - case COLOR_DEPTH_666: - bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_6; - break; - case COLOR_DEPTH_888: - bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_8; - break; - case COLOR_DEPTH_101010: - bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_10; - break; - case COLOR_DEPTH_121212: - bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_12; - break; - default: - bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_8; - break; - } - - switch (test_pattern) { - case CONTROLLER_DP_TEST_PATTERN_COLORSQUARES: - case CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA: - { - dyn_range = (test_pattern == - CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA ? - TEST_PATTERN_DYN_RANGE_CEA : - TEST_PATTERN_DYN_RANGE_VESA); - mode = TEST_PATTERN_MODE_COLORSQUARES_RGB; - - REG_UPDATE_2(OTG_TEST_PATTERN_PARAMETERS, - OTG_TEST_PATTERN_VRES, 6, - OTG_TEST_PATTERN_HRES, 6); - - REG_UPDATE_4(OTG_TEST_PATTERN_CONTROL, - OTG_TEST_PATTERN_EN, 1, - OTG_TEST_PATTERN_MODE, mode, - OTG_TEST_PATTERN_DYNAMIC_RANGE, dyn_range, - OTG_TEST_PATTERN_COLOR_FORMAT, bit_depth); - } - break; - - case CONTROLLER_DP_TEST_PATTERN_VERTICALBARS: - case CONTROLLER_DP_TEST_PATTERN_HORIZONTALBARS: - { - mode = (test_pattern == - CONTROLLER_DP_TEST_PATTERN_VERTICALBARS ? - TEST_PATTERN_MODE_VERTICALBARS : - TEST_PATTERN_MODE_HORIZONTALBARS); - - switch (bit_depth) { - case TEST_PATTERN_COLOR_FORMAT_BPC_6: - dst_bpc = 6; - break; - case TEST_PATTERN_COLOR_FORMAT_BPC_8: - dst_bpc = 8; - break; - case TEST_PATTERN_COLOR_FORMAT_BPC_10: - dst_bpc = 10; - break; - default: - dst_bpc = 8; - break; - } - - /* adjust color to the required colorFormat */ - for (index = 0; index < 6; index++) { - /* dst = 2^dstBpc * src / 2^srcBpc = src >> - * (srcBpc - dstBpc); - */ - dst_color[index] = - src_color[index] >> (src_bpc - dst_bpc); - /* CRTC_TEST_PATTERN_DATA has 16 bits, - * lowest 6 are hardwired to ZERO - * color bits should be left aligned to MSB - * XXXXXXXXXX000000 for 10 bit, - * XXXXXXXX00000000 for 8 bit and XXXXXX0000000000 for 6 - */ - dst_color[index] <<= (16 - dst_bpc); - } - - REG_WRITE(OTG_TEST_PATTERN_PARAMETERS, 0); - - /* We have to write the mask before data, similar to pipeline. - * For example, for 8 bpc, if we want RGB0 to be magenta, - * and RGB1 to be cyan, - * we need to make 7 writes: - * MASK DATA - * 000001 00000000 00000000 set mask to R0 - * 000010 11111111 00000000 R0 255, 0xFF00, set mask to G0 - * 000100 00000000 00000000 G0 0, 0x0000, set mask to B0 - * 001000 11111111 00000000 B0 255, 0xFF00, set mask to R1 - * 010000 00000000 00000000 R1 0, 0x0000, set mask to G1 - * 100000 11111111 00000000 G1 255, 0xFF00, set mask to B1 - * 100000 11111111 00000000 B1 255, 0xFF00 - * - * we will make a loop of 6 in which we prepare the mask, - * then write, then prepare the color for next write. - * first iteration will write mask only, - * but each next iteration color prepared in - * previous iteration will be written within new mask, - * the last component will written separately, - * mask is not changing between 6th and 7th write - * and color will be prepared by last iteration - */ - - /* write color, color values mask in CRTC_TEST_PATTERN_MASK - * is B1, G1, R1, B0, G0, R0 - */ - pattern_data = 0; - for (index = 0; index < 6; index++) { - /* prepare color mask, first write PATTERN_DATA - * will have all zeros - */ - pattern_mask = (1 << index); - - /* write color component */ - REG_SET_2(OTG_TEST_PATTERN_COLOR, 0, - OTG_TEST_PATTERN_MASK, pattern_mask, - OTG_TEST_PATTERN_DATA, pattern_data); - - /* prepare next color component, - * will be written in the next iteration - */ - pattern_data = dst_color[index]; - } - /* write last color component, - * it's been already prepared in the loop - */ - REG_SET_2(OTG_TEST_PATTERN_COLOR, 0, - OTG_TEST_PATTERN_MASK, pattern_mask, - OTG_TEST_PATTERN_DATA, pattern_data); - - /* enable test pattern */ - REG_UPDATE_4(OTG_TEST_PATTERN_CONTROL, - OTG_TEST_PATTERN_EN, 1, - OTG_TEST_PATTERN_MODE, mode, - OTG_TEST_PATTERN_DYNAMIC_RANGE, 0, - OTG_TEST_PATTERN_COLOR_FORMAT, bit_depth); - } - break; - - case CONTROLLER_DP_TEST_PATTERN_COLORRAMP: - { - mode = (bit_depth == - TEST_PATTERN_COLOR_FORMAT_BPC_10 ? - TEST_PATTERN_MODE_DUALRAMP_RGB : - TEST_PATTERN_MODE_SINGLERAMP_RGB); - - switch (bit_depth) { - case TEST_PATTERN_COLOR_FORMAT_BPC_6: - dst_bpc = 6; - break; - case TEST_PATTERN_COLOR_FORMAT_BPC_8: - dst_bpc = 8; - break; - case TEST_PATTERN_COLOR_FORMAT_BPC_10: - dst_bpc = 10; - break; - default: - dst_bpc = 8; - break; - } - - /* increment for the first ramp for one color gradation - * 1 gradation for 6-bit color is 2^10 - * gradations in 16-bit color - */ - inc_base = (src_bpc - dst_bpc); - - switch (bit_depth) { - case TEST_PATTERN_COLOR_FORMAT_BPC_6: - { - REG_UPDATE_5(OTG_TEST_PATTERN_PARAMETERS, - OTG_TEST_PATTERN_INC0, inc_base, - OTG_TEST_PATTERN_INC1, 0, - OTG_TEST_PATTERN_HRES, 6, - OTG_TEST_PATTERN_VRES, 6, - OTG_TEST_PATTERN_RAMP0_OFFSET, 0); - } - break; - case TEST_PATTERN_COLOR_FORMAT_BPC_8: - { - REG_UPDATE_5(OTG_TEST_PATTERN_PARAMETERS, - OTG_TEST_PATTERN_INC0, inc_base, - OTG_TEST_PATTERN_INC1, 0, - OTG_TEST_PATTERN_HRES, 8, - OTG_TEST_PATTERN_VRES, 6, - OTG_TEST_PATTERN_RAMP0_OFFSET, 0); - } - break; - case TEST_PATTERN_COLOR_FORMAT_BPC_10: - { - REG_UPDATE_5(OTG_TEST_PATTERN_PARAMETERS, - OTG_TEST_PATTERN_INC0, inc_base, - OTG_TEST_PATTERN_INC1, inc_base + 2, - OTG_TEST_PATTERN_HRES, 8, - OTG_TEST_PATTERN_VRES, 5, - OTG_TEST_PATTERN_RAMP0_OFFSET, 384 << 6); - } - break; - default: - break; - } - - REG_WRITE(OTG_TEST_PATTERN_COLOR, 0); - - /* enable test pattern */ - REG_WRITE(OTG_TEST_PATTERN_CONTROL, 0); - - REG_SET_4(OTG_TEST_PATTERN_CONTROL, 0, - OTG_TEST_PATTERN_EN, 1, - OTG_TEST_PATTERN_MODE, mode, - OTG_TEST_PATTERN_DYNAMIC_RANGE, 0, - OTG_TEST_PATTERN_COLOR_FORMAT, bit_depth); - } - break; - case CONTROLLER_DP_TEST_PATTERN_VIDEOMODE: - { - REG_WRITE(OTG_TEST_PATTERN_CONTROL, 0); - REG_WRITE(OTG_TEST_PATTERN_COLOR, 0); - REG_WRITE(OTG_TEST_PATTERN_PARAMETERS, 0); - } - break; - default: - break; - - } -} - -void optc1_get_crtc_scanoutpos( - struct timing_generator *optc, - uint32_t *v_blank_start, - uint32_t *v_blank_end, - uint32_t *h_position, - uint32_t *v_position) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - struct crtc_position position; - - REG_GET_2(OTG_V_BLANK_START_END, - OTG_V_BLANK_START, v_blank_start, - OTG_V_BLANK_END, v_blank_end); - - optc1_get_position(optc, &position); - - *h_position = position.horizontal_count; - *v_position = position.vertical_count; -} - -static void optc1_enable_stereo(struct timing_generator *optc, - const struct dc_crtc_timing *timing, struct crtc_stereo_flags *flags) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - if (flags) { - uint32_t stereo_en; - stereo_en = flags->FRAME_PACKED == 0 ? 1 : 0; - - if (flags->PROGRAM_STEREO) - REG_UPDATE_3(OTG_STEREO_CONTROL, - OTG_STEREO_EN, stereo_en, - OTG_STEREO_SYNC_OUTPUT_LINE_NUM, 0, - OTG_STEREO_SYNC_OUTPUT_POLARITY, flags->RIGHT_EYE_POLARITY == 0 ? 0 : 1); - - if (flags->PROGRAM_POLARITY) - REG_UPDATE(OTG_STEREO_CONTROL, - OTG_STEREO_EYE_FLAG_POLARITY, - flags->RIGHT_EYE_POLARITY == 0 ? 0 : 1); - - if (flags->DISABLE_STEREO_DP_SYNC) - REG_UPDATE(OTG_STEREO_CONTROL, - OTG_DISABLE_STEREOSYNC_OUTPUT_FOR_DP, 1); - - if (flags->PROGRAM_STEREO) - REG_UPDATE_2(OTG_3D_STRUCTURE_CONTROL, - OTG_3D_STRUCTURE_EN, flags->FRAME_PACKED, - OTG_3D_STRUCTURE_STEREO_SEL_OVR, flags->FRAME_PACKED); - - } -} - -void optc1_program_stereo(struct timing_generator *optc, - const struct dc_crtc_timing *timing, struct crtc_stereo_flags *flags) -{ - if (flags->PROGRAM_STEREO) - optc1_enable_stereo(optc, timing, flags); - else - optc1_disable_stereo(optc); -} - - -bool optc1_is_stereo_left_eye(struct timing_generator *optc) -{ - bool ret = false; - uint32_t left_eye = 0; - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_GET(OTG_STEREO_STATUS, - OTG_STEREO_CURRENT_EYE, &left_eye); - if (left_eye == 1) - ret = true; - else - ret = false; - - return ret; -} - -bool optc1_get_hw_timing(struct timing_generator *tg, - struct dc_crtc_timing *hw_crtc_timing) -{ - struct dcn_otg_state s = {0}; - - if (tg == NULL || hw_crtc_timing == NULL) - return false; - - optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s); - - hw_crtc_timing->h_total = s.h_total + 1; - hw_crtc_timing->h_addressable = s.h_total - ((s.h_total - s.h_blank_start) + s.h_blank_end); - hw_crtc_timing->h_front_porch = s.h_total + 1 - s.h_blank_start; - hw_crtc_timing->h_sync_width = s.h_sync_a_end - s.h_sync_a_start; - - hw_crtc_timing->v_total = s.v_total + 1; - hw_crtc_timing->v_addressable = s.v_total - ((s.v_total - s.v_blank_start) + s.v_blank_end); - hw_crtc_timing->v_front_porch = s.v_total + 1 - s.v_blank_start; - hw_crtc_timing->v_sync_width = s.v_sync_a_end - s.v_sync_a_start; - - return true; -} - - -void optc1_read_otg_state(struct optc *optc1, - struct dcn_otg_state *s) -{ - REG_GET(OTG_CONTROL, - OTG_MASTER_EN, &s->otg_enabled); - - REG_GET_2(OTG_V_BLANK_START_END, - OTG_V_BLANK_START, &s->v_blank_start, - OTG_V_BLANK_END, &s->v_blank_end); - - REG_GET(OTG_V_SYNC_A_CNTL, - OTG_V_SYNC_A_POL, &s->v_sync_a_pol); - - REG_GET(OTG_V_TOTAL, - OTG_V_TOTAL, &s->v_total); - - REG_GET(OTG_V_TOTAL_MAX, - OTG_V_TOTAL_MAX, &s->v_total_max); - - REG_GET(OTG_V_TOTAL_MIN, - OTG_V_TOTAL_MIN, &s->v_total_min); - - REG_GET(OTG_V_TOTAL_CONTROL, - OTG_V_TOTAL_MAX_SEL, &s->v_total_max_sel); - - REG_GET(OTG_V_TOTAL_CONTROL, - OTG_V_TOTAL_MIN_SEL, &s->v_total_min_sel); - - REG_GET_2(OTG_V_SYNC_A, - OTG_V_SYNC_A_START, &s->v_sync_a_start, - OTG_V_SYNC_A_END, &s->v_sync_a_end); - - REG_GET_2(OTG_H_BLANK_START_END, - OTG_H_BLANK_START, &s->h_blank_start, - OTG_H_BLANK_END, &s->h_blank_end); - - REG_GET_2(OTG_H_SYNC_A, - OTG_H_SYNC_A_START, &s->h_sync_a_start, - OTG_H_SYNC_A_END, &s->h_sync_a_end); - - REG_GET(OTG_H_SYNC_A_CNTL, - OTG_H_SYNC_A_POL, &s->h_sync_a_pol); - - REG_GET(OTG_H_TOTAL, - OTG_H_TOTAL, &s->h_total); - - REG_GET(OPTC_INPUT_GLOBAL_CONTROL, - OPTC_UNDERFLOW_OCCURRED_STATUS, &s->underflow_occurred_status); - - REG_GET(OTG_VERTICAL_INTERRUPT1_CONTROL, - OTG_VERTICAL_INTERRUPT1_INT_ENABLE, &s->vertical_interrupt1_en); - - REG_GET(OTG_VERTICAL_INTERRUPT1_POSITION, - OTG_VERTICAL_INTERRUPT1_LINE_START, &s->vertical_interrupt1_line); - - REG_GET(OTG_VERTICAL_INTERRUPT2_CONTROL, - OTG_VERTICAL_INTERRUPT2_INT_ENABLE, &s->vertical_interrupt2_en); - - REG_GET(OTG_VERTICAL_INTERRUPT2_POSITION, - OTG_VERTICAL_INTERRUPT2_LINE_START, &s->vertical_interrupt2_line); -} - -bool optc1_get_otg_active_size(struct timing_generator *optc, - uint32_t *otg_active_width, - uint32_t *otg_active_height) -{ - uint32_t otg_enabled; - uint32_t v_blank_start; - uint32_t v_blank_end; - uint32_t h_blank_start; - uint32_t h_blank_end; - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - - REG_GET(OTG_CONTROL, - OTG_MASTER_EN, &otg_enabled); - - if (otg_enabled == 0) - return false; - - REG_GET_2(OTG_V_BLANK_START_END, - OTG_V_BLANK_START, &v_blank_start, - OTG_V_BLANK_END, &v_blank_end); - - REG_GET_2(OTG_H_BLANK_START_END, - OTG_H_BLANK_START, &h_blank_start, - OTG_H_BLANK_END, &h_blank_end); - - *otg_active_width = v_blank_start - v_blank_end; - *otg_active_height = h_blank_start - h_blank_end; - return true; -} - -void optc1_clear_optc_underflow(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_UPDATE(OPTC_INPUT_GLOBAL_CONTROL, OPTC_UNDERFLOW_CLEAR, 1); -} - -void optc1_tg_init(struct timing_generator *optc) -{ - optc1_set_blank_data_double_buffer(optc, true); - optc1_set_timing_double_buffer(optc, true); - optc1_clear_optc_underflow(optc); -} - -bool optc1_is_tg_enabled(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - uint32_t otg_enabled = 0; - - REG_GET(OTG_CONTROL, OTG_MASTER_EN, &otg_enabled); - - return (otg_enabled != 0); - -} - -bool optc1_is_optc_underflow_occurred(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - uint32_t underflow_occurred = 0; - - REG_GET(OPTC_INPUT_GLOBAL_CONTROL, - OPTC_UNDERFLOW_OCCURRED_STATUS, - &underflow_occurred); - - return (underflow_occurred == 1); -} - -bool optc1_configure_crc(struct timing_generator *optc, - const struct crc_params *params) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - /* Cannot configure crc on a CRTC that is disabled */ - if (!optc1_is_tg_enabled(optc)) - return false; - - REG_WRITE(OTG_CRC_CNTL, 0); - - if (!params->enable) - return true; - - /* Program frame boundaries */ - /* Window A x axis start and end. */ - REG_UPDATE_2(OTG_CRC0_WINDOWA_X_CONTROL, - OTG_CRC0_WINDOWA_X_START, params->windowa_x_start, - OTG_CRC0_WINDOWA_X_END, params->windowa_x_end); - - /* Window A y axis start and end. */ - REG_UPDATE_2(OTG_CRC0_WINDOWA_Y_CONTROL, - OTG_CRC0_WINDOWA_Y_START, params->windowa_y_start, - OTG_CRC0_WINDOWA_Y_END, params->windowa_y_end); - - /* Window B x axis start and end. */ - REG_UPDATE_2(OTG_CRC0_WINDOWB_X_CONTROL, - OTG_CRC0_WINDOWB_X_START, params->windowb_x_start, - OTG_CRC0_WINDOWB_X_END, params->windowb_x_end); - - /* Window B y axis start and end. */ - REG_UPDATE_2(OTG_CRC0_WINDOWB_Y_CONTROL, - OTG_CRC0_WINDOWB_Y_START, params->windowb_y_start, - OTG_CRC0_WINDOWB_Y_END, params->windowb_y_end); - - /* Set crc mode and selection, and enable. Only using CRC0*/ - REG_UPDATE_3(OTG_CRC_CNTL, - OTG_CRC_CONT_EN, params->continuous_mode ? 1 : 0, - OTG_CRC0_SELECT, params->selection, - OTG_CRC_EN, 1); - - return true; -} - -/** - * optc1_get_crc - Capture CRC result per component - * - * @optc: timing_generator instance. - * @r_cr: 16-bit primary CRC signature for red data. - * @g_y: 16-bit primary CRC signature for green data. - * @b_cb: 16-bit primary CRC signature for blue data. - * - * This function reads the CRC signature from the OPTC registers. Notice that - * we have three registers to keep the CRC result per color component (RGB). - * - * Returns: - * If CRC is disabled, return false; otherwise, return true, and the CRC - * results in the parameters. - */ -bool optc1_get_crc(struct timing_generator *optc, - uint32_t *r_cr, uint32_t *g_y, uint32_t *b_cb) -{ - uint32_t field = 0; - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_GET(OTG_CRC_CNTL, OTG_CRC_EN, &field); - - /* Early return if CRC is not enabled for this CRTC */ - if (!field) - return false; - - /* OTG_CRC0_DATA_RG has the CRC16 results for the red and green component */ - REG_GET_2(OTG_CRC0_DATA_RG, - CRC0_R_CR, r_cr, - CRC0_G_Y, g_y); - - /* OTG_CRC0_DATA_B has the CRC16 results for the blue component */ - REG_GET(OTG_CRC0_DATA_B, - CRC0_B_CB, b_cb); - - return true; -} - -static const struct timing_generator_funcs dcn10_tg_funcs = { - .validate_timing = optc1_validate_timing, - .program_timing = optc1_program_timing, - .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0, - .setup_vertical_interrupt1 = optc1_setup_vertical_interrupt1, - .setup_vertical_interrupt2 = optc1_setup_vertical_interrupt2, - .program_global_sync = optc1_program_global_sync, - .enable_crtc = optc1_enable_crtc, - .disable_crtc = optc1_disable_crtc, - /* used by enable_timing_synchronization. Not need for FPGA */ - .is_counter_moving = optc1_is_counter_moving, - .get_position = optc1_get_position, - .get_frame_count = optc1_get_vblank_counter, - .get_scanoutpos = optc1_get_crtc_scanoutpos, - .get_otg_active_size = optc1_get_otg_active_size, - .set_early_control = optc1_set_early_control, - /* used by enable_timing_synchronization. Not need for FPGA */ - .wait_for_state = optc1_wait_for_state, - .set_blank = optc1_set_blank, - .is_blanked = optc1_is_blanked, - .set_blank_color = optc1_program_blank_color, - .did_triggered_reset_occur = optc1_did_triggered_reset_occur, - .enable_reset_trigger = optc1_enable_reset_trigger, - .enable_crtc_reset = optc1_enable_crtc_reset, - .disable_reset_trigger = optc1_disable_reset_trigger, - .lock = optc1_lock, - .unlock = optc1_unlock, - .enable_optc_clock = optc1_enable_optc_clock, - .set_drr = optc1_set_drr, - .get_last_used_drr_vtotal = NULL, - .set_vtotal_min_max = optc1_set_vtotal_min_max, - .set_static_screen_control = optc1_set_static_screen_control, - .set_test_pattern = optc1_set_test_pattern, - .program_stereo = optc1_program_stereo, - .is_stereo_left_eye = optc1_is_stereo_left_eye, - .set_blank_data_double_buffer = optc1_set_blank_data_double_buffer, - .tg_init = optc1_tg_init, - .is_tg_enabled = optc1_is_tg_enabled, - .is_optc_underflow_occurred = optc1_is_optc_underflow_occurred, - .clear_optc_underflow = optc1_clear_optc_underflow, - .get_crc = optc1_get_crc, - .configure_crc = optc1_configure_crc, - .set_vtg_params = optc1_set_vtg_params, - .program_manual_trigger = optc1_program_manual_trigger, - .setup_manual_trigger = optc1_setup_manual_trigger, - .get_hw_timing = optc1_get_hw_timing, -}; - -void dcn10_timing_generator_init(struct optc *optc1) -{ - optc1->base.funcs = &dcn10_tg_funcs; - - optc1->max_h_total = optc1->tg_mask->OTG_H_TOTAL + 1; - optc1->max_v_total = optc1->tg_mask->OTG_V_TOTAL + 1; - - optc1->min_h_blank = 32; - optc1->min_v_blank = 3; - optc1->min_v_blank_interlace = 5; - optc1->min_h_sync_width = 4; - optc1->min_v_sync_width = 1; -} - -/* "Containter" vs. "pixel" is a concept within HW blocks, mostly those closer to the back-end. It works like this: - * - * - In most of the formats (RGB or YCbCr 4:4:4, 4:2:2 uncompressed and DSC 4:2:2 Simple) pixel rate is the same as - * containter rate. - * - * - In 4:2:0 (DSC or uncompressed) there are two pixels per container, hence the target container rate has to be - * halved to maintain the correct pixel rate. - * - * - Unlike 4:2:2 uncompressed, DSC 4:2:2 Native also has two pixels per container (this happens when DSC is applied - * to it) and has to be treated the same as 4:2:0, i.e. target containter rate has to be halved in this case as well. - * - */ -bool optc1_is_two_pixels_per_containter(const struct dc_crtc_timing *timing) -{ - bool two_pix = timing->pixel_encoding == PIXEL_ENCODING_YCBCR420; - - two_pix = two_pix || (timing->flags.DSC && timing->pixel_encoding == PIXEL_ENCODING_YCBCR422 - && !timing->dsc_cfg.ycbcr422_simple); - return two_pix; -} - diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h deleted file mode 100644 index ab81594a7fadcc..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h +++ /dev/null @@ -1,599 +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 __DC_TIMING_GENERATOR_DCN10_H__ -#define __DC_TIMING_GENERATOR_DCN10_H__ - -#include "optc.h" - -#define DCN10TG_FROM_TG(tg)\ - container_of(tg, struct optc, base) - -#define TG_COMMON_REG_LIST_DCN(inst) \ - SRI(OTG_VSTARTUP_PARAM, OTG, inst),\ - SRI(OTG_VUPDATE_PARAM, OTG, inst),\ - SRI(OTG_VREADY_PARAM, OTG, inst),\ - SRI(OTG_BLANK_CONTROL, OTG, inst),\ - SRI(OTG_MASTER_UPDATE_LOCK, OTG, inst),\ - SRI(OTG_GLOBAL_CONTROL0, OTG, inst),\ - SRI(OTG_DOUBLE_BUFFER_CONTROL, OTG, inst),\ - SRI(OTG_H_TOTAL, OTG, inst),\ - SRI(OTG_H_BLANK_START_END, OTG, inst),\ - SRI(OTG_H_SYNC_A, OTG, inst),\ - SRI(OTG_H_SYNC_A_CNTL, OTG, inst),\ - SRI(OTG_H_TIMING_CNTL, OTG, inst),\ - SRI(OTG_V_TOTAL, OTG, inst),\ - SRI(OTG_V_BLANK_START_END, OTG, inst),\ - SRI(OTG_V_SYNC_A, OTG, inst),\ - SRI(OTG_V_SYNC_A_CNTL, OTG, inst),\ - SRI(OTG_INTERLACE_CONTROL, OTG, inst),\ - SRI(OTG_CONTROL, OTG, inst),\ - SRI(OTG_STEREO_CONTROL, OTG, inst),\ - SRI(OTG_3D_STRUCTURE_CONTROL, OTG, inst),\ - SRI(OTG_STEREO_STATUS, OTG, inst),\ - SRI(OTG_V_TOTAL_MAX, OTG, inst),\ - SRI(OTG_V_TOTAL_MID, OTG, inst),\ - SRI(OTG_V_TOTAL_MIN, OTG, inst),\ - SRI(OTG_V_TOTAL_CONTROL, OTG, inst),\ - SRI(OTG_TRIGA_CNTL, OTG, inst),\ - SRI(OTG_FORCE_COUNT_NOW_CNTL, OTG, inst),\ - SRI(OTG_STATIC_SCREEN_CONTROL, OTG, inst),\ - SRI(OTG_STATUS_FRAME_COUNT, OTG, inst),\ - SRI(OTG_STATUS, OTG, inst),\ - SRI(OTG_STATUS_POSITION, OTG, inst),\ - SRI(OTG_NOM_VERT_POSITION, OTG, inst),\ - SRI(OTG_BLACK_COLOR, OTG, inst),\ - SRI(OTG_CLOCK_CONTROL, OTG, inst),\ - SRI(OTG_VERTICAL_INTERRUPT0_CONTROL, OTG, inst),\ - SRI(OTG_VERTICAL_INTERRUPT0_POSITION, OTG, inst),\ - SRI(OTG_VERTICAL_INTERRUPT1_CONTROL, OTG, inst),\ - SRI(OTG_VERTICAL_INTERRUPT1_POSITION, OTG, inst),\ - SRI(OTG_VERTICAL_INTERRUPT2_CONTROL, OTG, inst),\ - SRI(OTG_VERTICAL_INTERRUPT2_POSITION, OTG, inst),\ - SRI(OPTC_INPUT_CLOCK_CONTROL, ODM, inst),\ - SRI(OPTC_DATA_SOURCE_SELECT, ODM, inst),\ - SRI(OPTC_INPUT_GLOBAL_CONTROL, ODM, inst),\ - SRI(CONTROL, VTG, inst),\ - SRI(OTG_VERT_SYNC_CONTROL, OTG, inst),\ - SRI(OTG_MASTER_UPDATE_MODE, OTG, inst),\ - SRI(OTG_GSL_CONTROL, OTG, inst),\ - SRI(OTG_CRC_CNTL, OTG, inst),\ - SRI(OTG_CRC0_DATA_RG, OTG, inst),\ - SRI(OTG_CRC0_DATA_B, OTG, inst),\ - SRI(OTG_CRC0_WINDOWA_X_CONTROL, OTG, inst),\ - SRI(OTG_CRC0_WINDOWA_Y_CONTROL, OTG, inst),\ - SRI(OTG_CRC0_WINDOWB_X_CONTROL, OTG, inst),\ - SRI(OTG_CRC0_WINDOWB_Y_CONTROL, OTG, inst),\ - SR(GSL_SOURCE_SELECT),\ - SRI(OTG_GLOBAL_CONTROL2, OTG, inst),\ - SRI(OTG_TRIGA_MANUAL_TRIG, OTG, inst) - -#define TG_COMMON_REG_LIST_DCN1_0(inst) \ - TG_COMMON_REG_LIST_DCN(inst),\ - SRI(OTG_TEST_PATTERN_PARAMETERS, OTG, inst),\ - SRI(OTG_TEST_PATTERN_CONTROL, OTG, inst),\ - SRI(OTG_TEST_PATTERN_COLOR, OTG, inst),\ - SRI(OTG_MANUAL_FLOW_CONTROL, OTG, inst) - - -struct dcn_optc_registers { - uint32_t OTG_GLOBAL_CONTROL1; - uint32_t OTG_GLOBAL_CONTROL2; - uint32_t OTG_VERT_SYNC_CONTROL; - uint32_t OTG_MASTER_UPDATE_MODE; - uint32_t OTG_GSL_CONTROL; - uint32_t OTG_VSTARTUP_PARAM; - uint32_t OTG_VUPDATE_PARAM; - uint32_t OTG_VREADY_PARAM; - uint32_t OTG_BLANK_CONTROL; - uint32_t OTG_MASTER_UPDATE_LOCK; - uint32_t OTG_GLOBAL_CONTROL0; - uint32_t OTG_DOUBLE_BUFFER_CONTROL; - uint32_t OTG_H_TOTAL; - uint32_t OTG_H_BLANK_START_END; - uint32_t OTG_H_SYNC_A; - uint32_t OTG_H_SYNC_A_CNTL; - uint32_t OTG_H_TIMING_CNTL; - uint32_t OTG_V_TOTAL; - uint32_t OTG_V_BLANK_START_END; - uint32_t OTG_V_SYNC_A; - uint32_t OTG_V_SYNC_A_CNTL; - uint32_t OTG_INTERLACE_CONTROL; - uint32_t OTG_CONTROL; - uint32_t OTG_STEREO_CONTROL; - uint32_t OTG_3D_STRUCTURE_CONTROL; - uint32_t OTG_STEREO_STATUS; - uint32_t OTG_V_TOTAL_MAX; - uint32_t OTG_V_TOTAL_MID; - uint32_t OTG_V_TOTAL_MIN; - uint32_t OTG_V_TOTAL_CONTROL; - uint32_t OTG_TRIGA_CNTL; - uint32_t OTG_TRIGA_MANUAL_TRIG; - uint32_t OTG_MANUAL_FLOW_CONTROL; - uint32_t OTG_FORCE_COUNT_NOW_CNTL; - uint32_t OTG_STATIC_SCREEN_CONTROL; - uint32_t OTG_STATUS_FRAME_COUNT; - uint32_t OTG_STATUS; - uint32_t OTG_STATUS_POSITION; - uint32_t OTG_NOM_VERT_POSITION; - uint32_t OTG_BLACK_COLOR; - uint32_t OTG_TEST_PATTERN_PARAMETERS; - uint32_t OTG_TEST_PATTERN_CONTROL; - uint32_t OTG_TEST_PATTERN_COLOR; - uint32_t OTG_CLOCK_CONTROL; - uint32_t OTG_VERTICAL_INTERRUPT0_CONTROL; - uint32_t OTG_VERTICAL_INTERRUPT0_POSITION; - uint32_t OTG_VERTICAL_INTERRUPT1_CONTROL; - uint32_t OTG_VERTICAL_INTERRUPT1_POSITION; - uint32_t OTG_VERTICAL_INTERRUPT2_CONTROL; - uint32_t OTG_VERTICAL_INTERRUPT2_POSITION; - uint32_t OPTC_INPUT_CLOCK_CONTROL; - uint32_t OPTC_DATA_SOURCE_SELECT; - uint32_t OPTC_MEMORY_CONFIG; - uint32_t OPTC_INPUT_GLOBAL_CONTROL; - uint32_t CONTROL; - uint32_t OTG_GSL_WINDOW_X; - uint32_t OTG_GSL_WINDOW_Y; - uint32_t OTG_VUPDATE_KEEPOUT; - uint32_t OTG_CRC_CNTL; - uint32_t OTG_CRC_CNTL2; - uint32_t OTG_CRC0_DATA_RG; - uint32_t OTG_CRC0_DATA_B; - uint32_t OTG_CRC1_DATA_B; - uint32_t OTG_CRC2_DATA_B; - uint32_t OTG_CRC3_DATA_B; - uint32_t OTG_CRC1_DATA_RG; - uint32_t OTG_CRC2_DATA_RG; - uint32_t OTG_CRC3_DATA_RG; - uint32_t OTG_CRC0_WINDOWA_X_CONTROL; - uint32_t OTG_CRC0_WINDOWA_Y_CONTROL; - uint32_t OTG_CRC0_WINDOWB_X_CONTROL; - uint32_t OTG_CRC0_WINDOWB_Y_CONTROL; - uint32_t OTG_CRC1_WINDOWA_X_CONTROL; - uint32_t OTG_CRC1_WINDOWA_Y_CONTROL; - uint32_t OTG_CRC1_WINDOWB_X_CONTROL; - uint32_t OTG_CRC1_WINDOWB_Y_CONTROL; - uint32_t GSL_SOURCE_SELECT; - uint32_t DWB_SOURCE_SELECT; - uint32_t OTG_DSC_START_POSITION; - uint32_t OPTC_DATA_FORMAT_CONTROL; - uint32_t OPTC_BYTES_PER_PIXEL; - uint32_t OPTC_WIDTH_CONTROL; - uint32_t OTG_DRR_CONTROL; - uint32_t OTG_BLANK_DATA_COLOR; - uint32_t OTG_BLANK_DATA_COLOR_EXT; - uint32_t OTG_DRR_TRIGGER_WINDOW; - uint32_t OTG_M_CONST_DTO0; - uint32_t OTG_M_CONST_DTO1; - uint32_t OTG_DRR_V_TOTAL_CHANGE; - uint32_t OTG_GLOBAL_CONTROL4; - uint32_t OTG_CRC0_WINDOWA_X_CONTROL_READBACK; - uint32_t OTG_CRC0_WINDOWA_Y_CONTROL_READBACK; - uint32_t OTG_CRC0_WINDOWB_X_CONTROL_READBACK; - uint32_t OTG_CRC0_WINDOWB_Y_CONTROL_READBACK; - uint32_t OTG_CRC1_WINDOWA_X_CONTROL_READBACK; - uint32_t OTG_CRC1_WINDOWA_Y_CONTROL_READBACK; - uint32_t OTG_CRC1_WINDOWB_X_CONTROL_READBACK; - uint32_t OTG_CRC1_WINDOWB_Y_CONTROL_READBACK; - uint32_t OPTC_CLOCK_CONTROL; -}; - -#define TG_COMMON_MASK_SH_LIST_DCN(mask_sh)\ - SF(OTG0_OTG_VSTARTUP_PARAM, VSTARTUP_START, mask_sh),\ - SF(OTG0_OTG_VUPDATE_PARAM, VUPDATE_OFFSET, mask_sh),\ - SF(OTG0_OTG_VUPDATE_PARAM, VUPDATE_WIDTH, mask_sh),\ - SF(OTG0_OTG_VREADY_PARAM, VREADY_OFFSET, mask_sh),\ - SF(OTG0_OTG_BLANK_CONTROL, OTG_BLANK_DATA_EN, mask_sh),\ - SF(OTG0_OTG_BLANK_CONTROL, OTG_BLANK_DE_MODE, mask_sh),\ - SF(OTG0_OTG_BLANK_CONTROL, OTG_CURRENT_BLANK_STATE, mask_sh),\ - SF(OTG0_OTG_MASTER_UPDATE_LOCK, OTG_MASTER_UPDATE_LOCK, mask_sh),\ - SF(OTG0_OTG_MASTER_UPDATE_LOCK, UPDATE_LOCK_STATUS, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL0, OTG_MASTER_UPDATE_LOCK_SEL, mask_sh),\ - SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_UPDATE_PENDING, mask_sh),\ - SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_BLANK_DATA_DOUBLE_BUFFER_EN, mask_sh),\ - SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_RANGE_TIMING_DBUF_UPDATE_MODE, mask_sh),\ - SF(OTG0_OTG_VUPDATE_KEEPOUT, OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, mask_sh), \ - SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET, mask_sh), \ - SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET, mask_sh), \ - SF(OTG0_OTG_H_TOTAL, OTG_H_TOTAL, mask_sh),\ - SF(OTG0_OTG_H_BLANK_START_END, OTG_H_BLANK_START, mask_sh),\ - SF(OTG0_OTG_H_BLANK_START_END, OTG_H_BLANK_END, mask_sh),\ - SF(OTG0_OTG_H_SYNC_A, OTG_H_SYNC_A_START, mask_sh),\ - SF(OTG0_OTG_H_SYNC_A, OTG_H_SYNC_A_END, mask_sh),\ - SF(OTG0_OTG_H_SYNC_A_CNTL, OTG_H_SYNC_A_POL, mask_sh),\ - SF(OTG0_OTG_H_TIMING_CNTL, OTG_H_TIMING_DIV_BY2, mask_sh),\ - SF(OTG0_OTG_V_TOTAL, OTG_V_TOTAL, mask_sh),\ - SF(OTG0_OTG_V_BLANK_START_END, OTG_V_BLANK_START, mask_sh),\ - SF(OTG0_OTG_V_BLANK_START_END, OTG_V_BLANK_END, mask_sh),\ - SF(OTG0_OTG_V_SYNC_A, OTG_V_SYNC_A_START, mask_sh),\ - SF(OTG0_OTG_V_SYNC_A, OTG_V_SYNC_A_END, mask_sh),\ - SF(OTG0_OTG_V_SYNC_A_CNTL, OTG_V_SYNC_A_POL, mask_sh),\ - SF(OTG0_OTG_INTERLACE_CONTROL, OTG_INTERLACE_ENABLE, mask_sh),\ - SF(OTG0_OTG_CONTROL, OTG_MASTER_EN, mask_sh),\ - SF(OTG0_OTG_CONTROL, OTG_START_POINT_CNTL, mask_sh),\ - SF(OTG0_OTG_CONTROL, OTG_DISABLE_POINT_CNTL, mask_sh),\ - SF(OTG0_OTG_CONTROL, OTG_FIELD_NUMBER_CNTL, mask_sh),\ - SF(OTG0_OTG_CONTROL, OTG_CURRENT_MASTER_EN_STATE, mask_sh),\ - SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_EN, mask_sh),\ - SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_SYNC_OUTPUT_LINE_NUM, mask_sh),\ - SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_SYNC_OUTPUT_POLARITY, mask_sh),\ - SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_EYE_FLAG_POLARITY, mask_sh),\ - SF(OTG0_OTG_STEREO_CONTROL, OTG_DISABLE_STEREOSYNC_OUTPUT_FOR_DP, mask_sh),\ - SF(OTG0_OTG_STEREO_CONTROL, OTG_DISABLE_STEREOSYNC_OUTPUT_FOR_DP, mask_sh),\ - SF(OTG0_OTG_STEREO_STATUS, OTG_STEREO_CURRENT_EYE, mask_sh),\ - SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_EN, mask_sh),\ - SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_V_UPDATE_MODE, mask_sh),\ - SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_STEREO_SEL_OVR, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_MAX, OTG_V_TOTAL_MAX, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_MID, OTG_V_TOTAL_MID, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_MIN, OTG_V_TOTAL_MIN, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_V_TOTAL_MIN_SEL, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_V_TOTAL_MAX_SEL, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_FORCE_LOCK_ON_EVENT, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_SET_V_TOTAL_MIN_MASK_EN, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_SET_V_TOTAL_MIN_MASK, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_VTOTAL_MID_REPLACING_MAX_EN, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_VTOTAL_MID_FRAME_NUM, mask_sh),\ - SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_CLEAR, mask_sh),\ - SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_MODE, mask_sh),\ - SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_OCCURRED, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_SOURCE_SELECT, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_SOURCE_PIPE_SELECT, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_RISING_EDGE_DETECT_CNTL, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_POLARITY_SELECT, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_FREQUENCY_SELECT, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_DELAY, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_CLEAR, mask_sh),\ - SF(OTG0_OTG_TRIGA_MANUAL_TRIG, OTG_TRIGA_MANUAL_TRIG, mask_sh),\ - SF(OTG0_OTG_STATIC_SCREEN_CONTROL, OTG_STATIC_SCREEN_EVENT_MASK, mask_sh),\ - SF(OTG0_OTG_STATIC_SCREEN_CONTROL, OTG_STATIC_SCREEN_FRAME_COUNT, mask_sh),\ - SF(OTG0_OTG_STATUS_FRAME_COUNT, OTG_FRAME_COUNT, mask_sh),\ - SF(OTG0_OTG_STATUS, OTG_V_BLANK, mask_sh),\ - SF(OTG0_OTG_STATUS, OTG_V_ACTIVE_DISP, mask_sh),\ - SF(OTG0_OTG_STATUS_POSITION, OTG_HORZ_COUNT, mask_sh),\ - SF(OTG0_OTG_STATUS_POSITION, OTG_VERT_COUNT, mask_sh),\ - SF(OTG0_OTG_NOM_VERT_POSITION, OTG_VERT_COUNT_NOM, mask_sh),\ - SF(OTG0_OTG_BLACK_COLOR, OTG_BLACK_COLOR_B_CB, mask_sh),\ - SF(OTG0_OTG_BLACK_COLOR, OTG_BLACK_COLOR_G_Y, mask_sh),\ - SF(OTG0_OTG_BLACK_COLOR, OTG_BLACK_COLOR_R_CR, mask_sh),\ - SF(OTG0_OTG_CLOCK_CONTROL, OTG_BUSY, mask_sh),\ - SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_EN, mask_sh),\ - SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_ON, mask_sh),\ - SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_GATE_DIS, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_INT_ENABLE, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT0_POSITION, OTG_VERTICAL_INTERRUPT0_LINE_START, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT0_POSITION, OTG_VERTICAL_INTERRUPT0_LINE_END, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT1_CONTROL, OTG_VERTICAL_INTERRUPT1_INT_ENABLE, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT1_POSITION, OTG_VERTICAL_INTERRUPT1_LINE_START, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT2_POSITION, OTG_VERTICAL_INTERRUPT2_LINE_START, mask_sh),\ - SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_EN, mask_sh),\ - SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_ON, mask_sh),\ - SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_GATE_DIS, mask_sh),\ - SF(ODM0_OPTC_INPUT_GLOBAL_CONTROL, OPTC_UNDERFLOW_OCCURRED_STATUS, mask_sh),\ - SF(ODM0_OPTC_INPUT_GLOBAL_CONTROL, OPTC_UNDERFLOW_CLEAR, mask_sh),\ - SF(VTG0_CONTROL, VTG0_ENABLE, mask_sh),\ - SF(VTG0_CONTROL, VTG0_FP2, mask_sh),\ - SF(VTG0_CONTROL, VTG0_VCOUNT_INIT, mask_sh),\ - SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_FORCE_VSYNC_NEXT_LINE_OCCURRED, mask_sh),\ - SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_FORCE_VSYNC_NEXT_LINE_CLEAR, mask_sh),\ - SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_AUTO_FORCE_VSYNC_MODE, mask_sh),\ - SF(OTG0_OTG_MASTER_UPDATE_MODE, MASTER_UPDATE_INTERLACED_MODE, mask_sh),\ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL0_EN, mask_sh),\ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL1_EN, mask_sh),\ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL2_EN, mask_sh),\ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_MASTER_EN, mask_sh),\ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_FORCE_DELAY, mask_sh),\ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_CHECK_ALL_FIELDS, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL, OTG_CRC_CONT_EN, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL, OTG_CRC0_SELECT, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL, OTG_CRC_EN, mask_sh),\ - SF(OTG0_OTG_CRC0_DATA_RG, CRC0_R_CR, mask_sh),\ - SF(OTG0_OTG_CRC0_DATA_RG, CRC0_G_Y, mask_sh),\ - SF(OTG0_OTG_CRC0_DATA_B, CRC0_B_CB, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWA_X_CONTROL, OTG_CRC0_WINDOWA_X_START, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWA_X_CONTROL, OTG_CRC0_WINDOWA_X_END, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWA_Y_CONTROL, OTG_CRC0_WINDOWA_Y_START, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWA_Y_CONTROL, OTG_CRC0_WINDOWA_Y_END, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWB_X_CONTROL, OTG_CRC0_WINDOWB_X_START, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWB_X_CONTROL, OTG_CRC0_WINDOWB_X_END, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL, OTG_CRC0_WINDOWB_Y_START, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL, OTG_CRC0_WINDOWB_Y_END, mask_sh),\ - SF(GSL_SOURCE_SELECT, GSL0_READY_SOURCE_SEL, mask_sh),\ - SF(GSL_SOURCE_SELECT, GSL1_READY_SOURCE_SEL, mask_sh),\ - SF(GSL_SOURCE_SELECT, GSL2_READY_SOURCE_SEL, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL2, MANUAL_FLOW_CONTROL_SEL, mask_sh) - - - -#define TG_COMMON_MASK_SH_LIST_DCN1_0(mask_sh)\ - TG_COMMON_MASK_SH_LIST_DCN(mask_sh),\ - SF(OTG0_OTG_TEST_PATTERN_PARAMETERS, OTG_TEST_PATTERN_INC0, mask_sh),\ - SF(OTG0_OTG_TEST_PATTERN_PARAMETERS, OTG_TEST_PATTERN_INC1, mask_sh),\ - SF(OTG0_OTG_TEST_PATTERN_PARAMETERS, OTG_TEST_PATTERN_VRES, mask_sh),\ - SF(OTG0_OTG_TEST_PATTERN_PARAMETERS, OTG_TEST_PATTERN_HRES, mask_sh),\ - SF(OTG0_OTG_TEST_PATTERN_PARAMETERS, OTG_TEST_PATTERN_RAMP0_OFFSET, mask_sh),\ - SF(OTG0_OTG_TEST_PATTERN_CONTROL, OTG_TEST_PATTERN_EN, mask_sh),\ - SF(OTG0_OTG_TEST_PATTERN_CONTROL, OTG_TEST_PATTERN_MODE, mask_sh),\ - SF(OTG0_OTG_TEST_PATTERN_CONTROL, OTG_TEST_PATTERN_DYNAMIC_RANGE, mask_sh),\ - SF(OTG0_OTG_TEST_PATTERN_CONTROL, OTG_TEST_PATTERN_COLOR_FORMAT, mask_sh),\ - SF(OTG0_OTG_TEST_PATTERN_COLOR, OTG_TEST_PATTERN_MASK, mask_sh),\ - SF(OTG0_OTG_TEST_PATTERN_COLOR, OTG_TEST_PATTERN_DATA, mask_sh),\ - SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SRC_SEL, mask_sh),\ - SF(OTG0_OTG_MANUAL_FLOW_CONTROL, MANUAL_FLOW_CONTROL, mask_sh),\ - -#define TG_REG_FIELD_LIST_DCN1_0(type) \ - type VSTARTUP_START;\ - type VUPDATE_OFFSET;\ - type VUPDATE_WIDTH;\ - type VREADY_OFFSET;\ - type OTG_BLANK_DATA_EN;\ - type OTG_BLANK_DE_MODE;\ - type OTG_CURRENT_BLANK_STATE;\ - type OTG_MASTER_UPDATE_LOCK;\ - type UPDATE_LOCK_STATUS;\ - type OTG_UPDATE_PENDING;\ - type OTG_MASTER_UPDATE_LOCK_SEL;\ - type OTG_BLANK_DATA_DOUBLE_BUFFER_EN;\ - type OTG_H_TOTAL;\ - type OTG_H_BLANK_START;\ - type OTG_H_BLANK_END;\ - type OTG_H_SYNC_A_START;\ - type OTG_H_SYNC_A_END;\ - type OTG_H_SYNC_A_POL;\ - type OTG_H_TIMING_DIV_BY2;\ - type OTG_V_TOTAL;\ - type OTG_V_BLANK_START;\ - type OTG_V_BLANK_END;\ - type OTG_V_SYNC_A_START;\ - type OTG_V_SYNC_A_END;\ - type OTG_V_SYNC_A_POL;\ - type OTG_INTERLACE_ENABLE;\ - type OTG_MASTER_EN;\ - type OTG_START_POINT_CNTL;\ - type OTG_DISABLE_POINT_CNTL;\ - type OTG_FIELD_NUMBER_CNTL;\ - type OTG_CURRENT_MASTER_EN_STATE;\ - type OTG_STEREO_EN;\ - type OTG_STEREO_SYNC_OUTPUT_LINE_NUM;\ - type OTG_STEREO_SYNC_OUTPUT_POLARITY;\ - type OTG_STEREO_EYE_FLAG_POLARITY;\ - type OTG_STEREO_CURRENT_EYE;\ - type OTG_DISABLE_STEREOSYNC_OUTPUT_FOR_DP;\ - type OTG_3D_STRUCTURE_EN;\ - type OTG_3D_STRUCTURE_V_UPDATE_MODE;\ - type OTG_3D_STRUCTURE_STEREO_SEL_OVR;\ - type OTG_V_TOTAL_MAX;\ - type OTG_V_TOTAL_MID;\ - type OTG_V_TOTAL_MIN;\ - type OTG_V_TOTAL_MIN_SEL;\ - type OTG_V_TOTAL_MAX_SEL;\ - type OTG_VTOTAL_MID_REPLACING_MAX_EN;\ - type OTG_VTOTAL_MID_FRAME_NUM;\ - type OTG_FORCE_LOCK_ON_EVENT;\ - type OTG_SET_V_TOTAL_MIN_MASK_EN;\ - type OTG_SET_V_TOTAL_MIN_MASK;\ - type OTG_FORCE_COUNT_NOW_CLEAR;\ - type OTG_FORCE_COUNT_NOW_MODE;\ - type OTG_FORCE_COUNT_NOW_OCCURRED;\ - type OTG_TRIGA_SOURCE_SELECT;\ - type OTG_TRIGA_SOURCE_PIPE_SELECT;\ - type OTG_TRIGA_RISING_EDGE_DETECT_CNTL;\ - type OTG_TRIGA_FALLING_EDGE_DETECT_CNTL;\ - type OTG_TRIGA_POLARITY_SELECT;\ - type OTG_TRIGA_FREQUENCY_SELECT;\ - type OTG_TRIGA_DELAY;\ - type OTG_TRIGA_CLEAR;\ - type OTG_TRIGA_MANUAL_TRIG;\ - type OTG_STATIC_SCREEN_EVENT_MASK;\ - type OTG_STATIC_SCREEN_FRAME_COUNT;\ - type OTG_FRAME_COUNT;\ - type OTG_V_BLANK;\ - type OTG_V_ACTIVE_DISP;\ - type OTG_HORZ_COUNT;\ - type OTG_VERT_COUNT;\ - type OTG_VERT_COUNT_NOM;\ - type OTG_BLACK_COLOR_B_CB;\ - type OTG_BLACK_COLOR_G_Y;\ - type OTG_BLACK_COLOR_R_CR;\ - type OTG_BLANK_DATA_COLOR_BLUE_CB;\ - type OTG_BLANK_DATA_COLOR_GREEN_Y;\ - type OTG_BLANK_DATA_COLOR_RED_CR;\ - type OTG_BLANK_DATA_COLOR_BLUE_CB_EXT;\ - type OTG_BLANK_DATA_COLOR_GREEN_Y_EXT;\ - type OTG_BLANK_DATA_COLOR_RED_CR_EXT;\ - type OTG_VTOTAL_MID_REPLACING_MIN_EN;\ - type OTG_TEST_PATTERN_INC0;\ - type OTG_TEST_PATTERN_INC1;\ - type OTG_TEST_PATTERN_VRES;\ - type OTG_TEST_PATTERN_HRES;\ - type OTG_TEST_PATTERN_RAMP0_OFFSET;\ - type OTG_TEST_PATTERN_EN;\ - type OTG_TEST_PATTERN_MODE;\ - type OTG_TEST_PATTERN_DYNAMIC_RANGE;\ - type OTG_TEST_PATTERN_COLOR_FORMAT;\ - type OTG_TEST_PATTERN_MASK;\ - type OTG_TEST_PATTERN_DATA;\ - type OTG_BUSY;\ - type OTG_CLOCK_EN;\ - type OTG_CLOCK_ON;\ - type OTG_CLOCK_GATE_DIS;\ - type OTG_VERTICAL_INTERRUPT0_INT_ENABLE;\ - type OTG_VERTICAL_INTERRUPT0_LINE_START;\ - type OTG_VERTICAL_INTERRUPT0_LINE_END;\ - type OTG_VERTICAL_INTERRUPT1_INT_ENABLE;\ - type OTG_VERTICAL_INTERRUPT1_LINE_START;\ - type OTG_VERTICAL_INTERRUPT2_INT_ENABLE;\ - type OTG_VERTICAL_INTERRUPT2_LINE_START;\ - type OPTC_INPUT_CLK_EN;\ - type OPTC_INPUT_CLK_ON;\ - type OPTC_INPUT_CLK_GATE_DIS;\ - type OPTC_UNDERFLOW_OCCURRED_STATUS;\ - type OPTC_UNDERFLOW_CLEAR;\ - type OPTC_SRC_SEL;\ - type VTG0_ENABLE;\ - type VTG0_FP2;\ - type VTG0_VCOUNT_INIT;\ - type OTG_FORCE_VSYNC_NEXT_LINE_OCCURRED;\ - type OTG_FORCE_VSYNC_NEXT_LINE_CLEAR;\ - type OTG_AUTO_FORCE_VSYNC_MODE;\ - type MASTER_UPDATE_INTERLACED_MODE;\ - type OTG_GSL0_EN;\ - type OTG_GSL1_EN;\ - type OTG_GSL2_EN;\ - type OTG_GSL_MASTER_EN;\ - type OTG_GSL_FORCE_DELAY;\ - type OTG_GSL_CHECK_ALL_FIELDS;\ - type OTG_GSL_WINDOW_START_X;\ - type OTG_GSL_WINDOW_END_X;\ - type OTG_GSL_WINDOW_START_Y;\ - type OTG_GSL_WINDOW_END_Y;\ - type OTG_RANGE_TIMING_DBUF_UPDATE_MODE;\ - type OTG_GSL_MASTER_MODE;\ - type OTG_MASTER_UPDATE_LOCK_GSL_EN;\ - type MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET;\ - type MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET;\ - type OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN;\ - type OTG_CRC_CONT_EN;\ - type OTG_CRC0_SELECT;\ - type OTG_CRC_EN;\ - type CRC0_R_CR;\ - type CRC0_G_Y;\ - type CRC0_B_CB;\ - type CRC1_R_CR;\ - type CRC1_G_Y;\ - type CRC1_B_CB;\ - type CRC2_R_CR;\ - type CRC2_G_Y;\ - type CRC2_B_CB;\ - type CRC3_R_CR;\ - type CRC3_G_Y;\ - type CRC3_B_CB;\ - type OTG_CRC0_WINDOWA_X_START;\ - type OTG_CRC0_WINDOWA_X_END;\ - type OTG_CRC0_WINDOWA_Y_START;\ - type OTG_CRC0_WINDOWA_Y_END;\ - type OTG_CRC0_WINDOWB_X_START;\ - type OTG_CRC0_WINDOWB_X_END;\ - type OTG_CRC0_WINDOWB_Y_START;\ - type OTG_CRC0_WINDOWB_Y_END;\ - type OTG_CRC_WINDOW_DB_EN;\ - type OTG_CRC1_WINDOWA_X_START;\ - type OTG_CRC1_WINDOWA_X_END;\ - type OTG_CRC1_WINDOWA_Y_START;\ - type OTG_CRC1_WINDOWA_Y_END;\ - type OTG_CRC1_WINDOWB_X_START;\ - type OTG_CRC1_WINDOWB_X_END;\ - type OTG_CRC1_WINDOWB_Y_START;\ - type OTG_CRC1_WINDOWB_Y_END;\ - type GSL0_READY_SOURCE_SEL;\ - type GSL1_READY_SOURCE_SEL;\ - type GSL2_READY_SOURCE_SEL;\ - type MANUAL_FLOW_CONTROL;\ - type MANUAL_FLOW_CONTROL_SEL; - -#define TG_REG_FIELD_LIST(type) \ - TG_REG_FIELD_LIST_DCN1_0(type)\ - type OTG_V_SYNC_MODE;\ - type OTG_DRR_TRIGGER_WINDOW_START_X;\ - type OTG_DRR_TRIGGER_WINDOW_END_X;\ - type OTG_DRR_V_TOTAL_CHANGE_LIMIT;\ - type OTG_OUT_MUX;\ - type OTG_M_CONST_DTO_PHASE;\ - type OTG_M_CONST_DTO_MODULO;\ - type MASTER_UPDATE_LOCK_DB_X;\ - type MASTER_UPDATE_LOCK_DB_Y;\ - type MASTER_UPDATE_LOCK_DB_EN;\ - type GLOBAL_UPDATE_LOCK_EN;\ - type DIG_UPDATE_LOCATION;\ - type OTG_DSC_START_POSITION_X;\ - type OTG_DSC_START_POSITION_LINE_NUM;\ - type OPTC_NUM_OF_INPUT_SEGMENT;\ - type OPTC_SEG0_SRC_SEL;\ - type OPTC_SEG1_SRC_SEL;\ - type OPTC_SEG2_SRC_SEL;\ - type OPTC_SEG3_SRC_SEL;\ - type OPTC_MEM_SEL;\ - type OPTC_DATA_FORMAT;\ - type OPTC_DSC_MODE;\ - type OPTC_DSC_BYTES_PER_PIXEL;\ - type OPTC_DSC_SLICE_WIDTH;\ - type OPTC_SEGMENT_WIDTH;\ - type OPTC_DWB0_SOURCE_SELECT;\ - type OPTC_DWB1_SOURCE_SELECT;\ - type MASTER_UPDATE_LOCK_DB_START_X;\ - type MASTER_UPDATE_LOCK_DB_END_X;\ - type MASTER_UPDATE_LOCK_DB_START_Y;\ - type MASTER_UPDATE_LOCK_DB_END_Y;\ - type DIG_UPDATE_POSITION_X;\ - type DIG_UPDATE_POSITION_Y;\ - type OTG_H_TIMING_DIV_MODE;\ - type OTG_DRR_TIMING_DBUF_UPDATE_MODE;\ - type OTG_CRC_DSC_MODE;\ - 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_DRR_TIMING_DBUF_UPDATE_PENDING; - -#define TG_REG_FIELD_LIST_DCN3_2(type) \ - type OTG_H_TIMING_DIV_MODE_MANUAL; - - -#define TG_REG_FIELD_LIST_DCN3_5(type) \ - type OTG_CRC0_WINDOWA_X_START_READBACK;\ - type OTG_CRC0_WINDOWA_X_END_READBACK;\ - type OTG_CRC0_WINDOWA_Y_START_READBACK;\ - type OTG_CRC0_WINDOWA_Y_END_READBACK;\ - type OTG_CRC0_WINDOWB_X_START_READBACK;\ - type OTG_CRC0_WINDOWB_X_END_READBACK;\ - type OTG_CRC0_WINDOWB_Y_START_READBACK;\ - type OTG_CRC0_WINDOWB_Y_END_READBACK; \ - type OTG_CRC1_WINDOWA_X_START_READBACK;\ - type OTG_CRC1_WINDOWA_X_END_READBACK;\ - type OTG_CRC1_WINDOWA_Y_START_READBACK;\ - type OTG_CRC1_WINDOWA_Y_END_READBACK;\ - type OTG_CRC1_WINDOWB_X_START_READBACK;\ - type OTG_CRC1_WINDOWB_X_END_READBACK;\ - type OTG_CRC1_WINDOWB_Y_START_READBACK;\ - type OTG_CRC1_WINDOWB_Y_END_READBACK;\ - type OPTC_FGCG_REP_DIS; - -struct dcn_optc_shift { - TG_REG_FIELD_LIST(uint8_t) - TG_REG_FIELD_LIST_DCN3_2(uint8_t) - TG_REG_FIELD_LIST_DCN3_5(uint8_t) -}; - -struct dcn_optc_mask { - TG_REG_FIELD_LIST(uint32_t) - TG_REG_FIELD_LIST_DCN3_2(uint32_t) - TG_REG_FIELD_LIST_DCN3_5(uint32_t) -}; - -void dcn10_timing_generator_init(struct optc *optc); - -#endif /* __DC_TIMING_GENERATOR_DCN10_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c deleted file mode 100644 index b94c5c97eee777..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c +++ /dev/null @@ -1,1686 +0,0 @@ -/* -* Copyright 2016 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 "dcn10_init.h" - -#include "resource.h" -#include "include/irq_service_interface.h" -#include "dcn10_resource.h" -#include "dcn10_ipp.h" -#include "dcn10_mpc.h" -#include "irq/dcn10/irq_service_dcn10.h" -#include "dcn10_dpp.h" -#include "dcn10_optc.h" -#include "dcn10/dcn10_hwseq.h" -#include "dce110/dce110_hwseq.h" -#include "dcn10_opp.h" -#include "dcn10_link_encoder.h" -#include "dcn10_stream_encoder.h" -#include "dce/dce_clock_source.h" -#include "dce/dce_audio.h" -#include "dce/dce_hwseq.h" -#include "virtual/virtual_stream_encoder.h" -#include "dce110/dce110_resource.h" -#include "dce112/dce112_resource.h" -#include "dcn10_hubp.h" -#include "dcn10_hubbub.h" -#include "dce/dce_panel_cntl.h" - -#include "soc15_hw_ip.h" -#include "vega10_ip_offset.h" - -#include "dcn/dcn_1_0_offset.h" -#include "dcn/dcn_1_0_sh_mask.h" - -#include "nbio/nbio_7_0_offset.h" - -#include "mmhub/mmhub_9_1_offset.h" -#include "mmhub/mmhub_9_1_sh_mask.h" - -#include "reg_helper.h" -#include "dce/dce_abm.h" -#include "dce/dce_dmcu.h" -#include "dce/dce_aux.h" -#include "dce/dce_i2c.h" - -#ifndef mmDP0_DP_DPHY_INTERNAL_CTRL - #define mmDP0_DP_DPHY_INTERNAL_CTRL 0x210f - #define mmDP0_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 - #define mmDP1_DP_DPHY_INTERNAL_CTRL 0x220f - #define mmDP1_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 - #define mmDP2_DP_DPHY_INTERNAL_CTRL 0x230f - #define mmDP2_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 - #define mmDP3_DP_DPHY_INTERNAL_CTRL 0x240f - #define mmDP3_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 - #define mmDP4_DP_DPHY_INTERNAL_CTRL 0x250f - #define mmDP4_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 - #define mmDP5_DP_DPHY_INTERNAL_CTRL 0x260f - #define mmDP5_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 - #define mmDP6_DP_DPHY_INTERNAL_CTRL 0x270f - #define mmDP6_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 -#endif - - -enum dcn10_clk_src_array_id { - DCN10_CLK_SRC_PLL0, - DCN10_CLK_SRC_PLL1, - DCN10_CLK_SRC_PLL2, - DCN10_CLK_SRC_PLL3, - DCN10_CLK_SRC_TOTAL, - DCN101_CLK_SRC_TOTAL = DCN10_CLK_SRC_PLL3 -}; - -/* begin ********************* - * macros to expend register list macro defined in HW object header file */ - -/* DCN */ -#define BASE_INNER(seg) \ - DCE_BASE__INST0_SEG ## seg - -#define BASE(seg) \ - BASE_INNER(seg) - -#define SR(reg_name)\ - .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + \ - mm ## reg_name - -#define SRI(reg_name, block, id)\ - .reg_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name - - -#define SRII(reg_name, block, id)\ - .reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name - -#define VUPDATE_SRII(reg_name, block, id)\ - .reg_name[id] = BASE(mm ## reg_name ## 0 ## _ ## block ## id ## _BASE_IDX) + \ - mm ## reg_name ## 0 ## _ ## block ## id - -/* set field/register/bitfield name */ -#define SFRB(field_name, reg_name, bitfield, post_fix)\ - .field_name = reg_name ## __ ## bitfield ## post_fix - -/* NBIO */ -#define NBIO_BASE_INNER(seg) \ - NBIF_BASE__INST0_SEG ## seg - -#define NBIO_BASE(seg) \ - NBIO_BASE_INNER(seg) - -#define NBIO_SR(reg_name)\ - .reg_name = NBIO_BASE(mm ## reg_name ## _BASE_IDX) + \ - mm ## reg_name - -/* MMHUB */ -#define MMHUB_BASE_INNER(seg) \ - MMHUB_BASE__INST0_SEG ## seg - -#define MMHUB_BASE(seg) \ - MMHUB_BASE_INNER(seg) - -#define MMHUB_SR(reg_name)\ - .reg_name = MMHUB_BASE(mm ## reg_name ## _BASE_IDX) + \ - mm ## reg_name - -/* macros to expend register list macro defined in HW object header file - * end *********************/ - - -static const struct dce_dmcu_registers dmcu_regs = { - DMCU_DCN10_REG_LIST() -}; - -static const struct dce_dmcu_shift dmcu_shift = { - DMCU_MASK_SH_LIST_DCN10(__SHIFT) -}; - -static const struct dce_dmcu_mask dmcu_mask = { - DMCU_MASK_SH_LIST_DCN10(_MASK) -}; - -static const struct dce_abm_registers abm_regs = { - ABM_DCN10_REG_LIST(0) -}; - -static const struct dce_abm_shift abm_shift = { - ABM_MASK_SH_LIST_DCN10(__SHIFT) -}; - -static const struct dce_abm_mask abm_mask = { - ABM_MASK_SH_LIST_DCN10(_MASK) -}; - -#define stream_enc_regs(id)\ -[id] = {\ - SE_DCN_REG_LIST(id)\ -} - -static const struct dcn10_stream_enc_registers stream_enc_regs[] = { - stream_enc_regs(0), - stream_enc_regs(1), - stream_enc_regs(2), - stream_enc_regs(3), -}; - -static const struct dcn10_stream_encoder_shift se_shift = { - SE_COMMON_MASK_SH_LIST_DCN10(__SHIFT) -}; - -static const struct dcn10_stream_encoder_mask se_mask = { - SE_COMMON_MASK_SH_LIST_DCN10(_MASK) -}; - -#define audio_regs(id)\ -[id] = {\ - AUD_COMMON_REG_LIST(id)\ -} - -static const struct dce_audio_registers audio_regs[] = { - audio_regs(0), - audio_regs(1), - audio_regs(2), - audio_regs(3), -}; - -#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ - SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ - SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ - AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) - -static const struct dce_audio_shift audio_shift = { - DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_audio_mask audio_mask = { - DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) -}; - -#define aux_regs(id)\ -[id] = {\ - AUX_REG_LIST(id)\ -} - -static const struct dcn10_link_enc_aux_registers link_enc_aux_regs[] = { - aux_regs(0), - aux_regs(1), - aux_regs(2), - aux_regs(3) -}; - -#define hpd_regs(id)\ -[id] = {\ - HPD_REG_LIST(id)\ -} - -static const struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[] = { - hpd_regs(0), - hpd_regs(1), - hpd_regs(2), - hpd_regs(3) -}; - -#define link_regs(id)\ -[id] = {\ - LE_DCN10_REG_LIST(id), \ - SRI(DP_DPHY_INTERNAL_CTRL, DP, id) \ -} - -static const struct dcn10_link_enc_registers link_enc_regs[] = { - link_regs(0), - link_regs(1), - link_regs(2), - link_regs(3) -}; - -static const struct dcn10_link_enc_shift le_shift = { - LINK_ENCODER_MASK_SH_LIST_DCN10(__SHIFT) -}; - -static const struct dcn10_link_enc_mask le_mask = { - LINK_ENCODER_MASK_SH_LIST_DCN10(_MASK) -}; - -static const struct dce_panel_cntl_registers panel_cntl_regs[] = { - { DCN_PANEL_CNTL_REG_LIST() } -}; - -static const struct dce_panel_cntl_shift panel_cntl_shift = { - DCE_PANEL_CNTL_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_panel_cntl_mask panel_cntl_mask = { - DCE_PANEL_CNTL_MASK_SH_LIST(_MASK) -}; - -static const struct dce110_aux_registers_shift aux_shift = { - DCN10_AUX_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce110_aux_registers_mask aux_mask = { - DCN10_AUX_MASK_SH_LIST(_MASK) -}; - -#define ipp_regs(id)\ -[id] = {\ - IPP_REG_LIST_DCN10(id),\ -} - -static const struct dcn10_ipp_registers ipp_regs[] = { - ipp_regs(0), - ipp_regs(1), - ipp_regs(2), - ipp_regs(3), -}; - -static const struct dcn10_ipp_shift ipp_shift = { - IPP_MASK_SH_LIST_DCN10(__SHIFT) -}; - -static const struct dcn10_ipp_mask ipp_mask = { - IPP_MASK_SH_LIST_DCN10(_MASK), -}; - -#define opp_regs(id)\ -[id] = {\ - OPP_REG_LIST_DCN10(id),\ -} - -static const struct dcn10_opp_registers opp_regs[] = { - opp_regs(0), - opp_regs(1), - opp_regs(2), - opp_regs(3), -}; - -static const struct dcn10_opp_shift opp_shift = { - OPP_MASK_SH_LIST_DCN10(__SHIFT) -}; - -static const struct dcn10_opp_mask opp_mask = { - OPP_MASK_SH_LIST_DCN10(_MASK), -}; - -#define aux_engine_regs(id)\ -[id] = {\ - AUX_COMMON_REG_LIST(id), \ - .AUX_RESET_MASK = 0 \ -} - -static const struct dce110_aux_registers aux_engine_regs[] = { - aux_engine_regs(0), - aux_engine_regs(1), - aux_engine_regs(2), - aux_engine_regs(3), - aux_engine_regs(4), - aux_engine_regs(5) -}; - -#define tf_regs(id)\ -[id] = {\ - TF_REG_LIST_DCN10(id),\ -} - -static const struct dcn_dpp_registers tf_regs[] = { - tf_regs(0), - tf_regs(1), - tf_regs(2), - tf_regs(3), -}; - -static const struct dcn_dpp_shift tf_shift = { - TF_REG_LIST_SH_MASK_DCN10(__SHIFT), - TF_DEBUG_REG_LIST_SH_DCN10 - -}; - -static const struct dcn_dpp_mask tf_mask = { - TF_REG_LIST_SH_MASK_DCN10(_MASK), - TF_DEBUG_REG_LIST_MASK_DCN10 -}; - -static const struct dcn_mpc_registers mpc_regs = { - MPC_COMMON_REG_LIST_DCN1_0(0), - MPC_COMMON_REG_LIST_DCN1_0(1), - MPC_COMMON_REG_LIST_DCN1_0(2), - MPC_COMMON_REG_LIST_DCN1_0(3), - MPC_OUT_MUX_COMMON_REG_LIST_DCN1_0(0), - MPC_OUT_MUX_COMMON_REG_LIST_DCN1_0(1), - MPC_OUT_MUX_COMMON_REG_LIST_DCN1_0(2), - MPC_OUT_MUX_COMMON_REG_LIST_DCN1_0(3) -}; - -static const struct dcn_mpc_shift mpc_shift = { - MPC_COMMON_MASK_SH_LIST_DCN1_0(__SHIFT),\ - SFRB(CUR_VUPDATE_LOCK_SET, CUR0_VUPDATE_LOCK_SET0, CUR0_VUPDATE_LOCK_SET, __SHIFT) -}; - -static const struct dcn_mpc_mask mpc_mask = { - MPC_COMMON_MASK_SH_LIST_DCN1_0(_MASK),\ - SFRB(CUR_VUPDATE_LOCK_SET, CUR0_VUPDATE_LOCK_SET0, CUR0_VUPDATE_LOCK_SET, _MASK) -}; - -#define tg_regs(id)\ -[id] = {TG_COMMON_REG_LIST_DCN1_0(id)} - -static const struct dcn_optc_registers tg_regs[] = { - tg_regs(0), - tg_regs(1), - tg_regs(2), - tg_regs(3), -}; - -static const struct dcn_optc_shift tg_shift = { - TG_COMMON_MASK_SH_LIST_DCN1_0(__SHIFT) -}; - -static const struct dcn_optc_mask tg_mask = { - TG_COMMON_MASK_SH_LIST_DCN1_0(_MASK) -}; - -static const struct bios_registers bios_regs = { - NBIO_SR(BIOS_SCRATCH_3), - NBIO_SR(BIOS_SCRATCH_6) -}; - -#define hubp_regs(id)\ -[id] = {\ - HUBP_REG_LIST_DCN10(id)\ -} - -static const struct dcn_mi_registers hubp_regs[] = { - hubp_regs(0), - hubp_regs(1), - hubp_regs(2), - hubp_regs(3), -}; - -static const struct dcn_mi_shift hubp_shift = { - HUBP_MASK_SH_LIST_DCN10(__SHIFT) -}; - -static const struct dcn_mi_mask hubp_mask = { - HUBP_MASK_SH_LIST_DCN10(_MASK) -}; - -static const struct dcn_hubbub_registers hubbub_reg = { - HUBBUB_REG_LIST_DCN10(0) -}; - -static const struct dcn_hubbub_shift hubbub_shift = { - HUBBUB_MASK_SH_LIST_DCN10(__SHIFT) -}; - -static const struct dcn_hubbub_mask hubbub_mask = { - HUBBUB_MASK_SH_LIST_DCN10(_MASK) -}; - -static int map_transmitter_id_to_phy_instance( - enum transmitter transmitter) -{ - switch (transmitter) { - case TRANSMITTER_UNIPHY_A: - return 0; - break; - case TRANSMITTER_UNIPHY_B: - return 1; - break; - case TRANSMITTER_UNIPHY_C: - return 2; - break; - case TRANSMITTER_UNIPHY_D: - return 3; - break; - default: - ASSERT(0); - return 0; - } -} - -#define clk_src_regs(index, pllid)\ -[index] = {\ - CS_COMMON_REG_LIST_DCN1_0(index, pllid),\ -} - -static const struct dce110_clk_src_regs clk_src_regs[] = { - clk_src_regs(0, A), - clk_src_regs(1, B), - clk_src_regs(2, C), - clk_src_regs(3, D) -}; - -static const struct dce110_clk_src_shift cs_shift = { - CS_COMMON_MASK_SH_LIST_DCN1_0(__SHIFT) -}; - -static const struct dce110_clk_src_mask cs_mask = { - CS_COMMON_MASK_SH_LIST_DCN1_0(_MASK) -}; - -static const struct resource_caps res_cap = { - .num_timing_generator = 4, - .num_opp = 4, - .num_video_plane = 4, - .num_audio = 4, - .num_stream_encoder = 4, - .num_pll = 4, - .num_ddc = 4, -}; - -static const struct resource_caps rv2_res_cap = { - .num_timing_generator = 3, - .num_opp = 3, - .num_video_plane = 3, - .num_audio = 3, - .num_stream_encoder = 3, - .num_pll = 3, - .num_ddc = 4, -}; - -static const struct dc_plane_cap plane_cap = { - .type = DC_PLANE_TYPE_DCN_UNIVERSAL, - .per_pixel_alpha = true, - - .pixel_format_support = { - .argb8888 = true, - .nv12 = true, - .fp16 = true, - .p010 = true - }, - - .max_upscale_factor = { - .argb8888 = 16000, - .nv12 = 16000, - .fp16 = 1 - }, - - .max_downscale_factor = { - .argb8888 = 250, - .nv12 = 250, - .fp16 = 1 - } -}; - -static const struct dc_debug_options debug_defaults_drv = { - .sanity_checks = true, - .disable_dmcu = false, - .force_abm_enable = false, - .timing_trace = false, - .clock_trace = true, - - /* raven smu dones't allow 0 disp clk, - * smu min disp clk limit is 50Mhz - * keep min disp clk 100Mhz avoid smu hang - */ - .min_disp_clk_khz = 100000, - - .disable_pplib_clock_request = false, - .disable_pplib_wm_range = false, - .pplib_wm_report_mode = WM_REPORT_DEFAULT, - .pipe_split_policy = MPC_SPLIT_DYNAMIC, - .force_single_disp_pipe_split = true, - .disable_dcc = DCC_ENABLE, - .voltage_align_fclk = true, - .disable_stereo_support = true, - .vsr_support = true, - .performance_trace = false, - .az_endpoint_mute_only = true, - .recovery_enabled = false, /*enable this by default after testing.*/ - .max_downscale_src_width = 3840, - .underflow_assert_delay_us = 0xFFFFFFFF, - .enable_legacy_fast_update = true, - .using_dml2 = false, -}; - -static const struct dc_debug_options debug_defaults_diags = { - .disable_dmcu = false, - .force_abm_enable = false, - .timing_trace = true, - .clock_trace = true, - .disable_stutter = true, - .disable_pplib_clock_request = true, - .disable_pplib_wm_range = true, - .underflow_assert_delay_us = 0xFFFFFFFF, -}; - -static void dcn10_dpp_destroy(struct dpp **dpp) -{ - kfree(TO_DCN10_DPP(*dpp)); - *dpp = NULL; -} - -static struct dpp *dcn10_dpp_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn10_dpp *dpp = - kzalloc(sizeof(struct dcn10_dpp), GFP_KERNEL); - - if (!dpp) - return NULL; - - dpp1_construct(dpp, ctx, inst, - &tf_regs[inst], &tf_shift, &tf_mask); - return &dpp->base; -} - -static struct input_pixel_processor *dcn10_ipp_create( - struct dc_context *ctx, uint32_t inst) -{ - struct dcn10_ipp *ipp = - kzalloc(sizeof(struct dcn10_ipp), GFP_KERNEL); - - if (!ipp) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dcn10_ipp_construct(ipp, ctx, inst, - &ipp_regs[inst], &ipp_shift, &ipp_mask); - return &ipp->base; -} - - -static struct output_pixel_processor *dcn10_opp_create( - struct dc_context *ctx, uint32_t inst) -{ - struct dcn10_opp *opp = - kzalloc(sizeof(struct dcn10_opp), GFP_KERNEL); - - if (!opp) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dcn10_opp_construct(opp, ctx, inst, - &opp_regs[inst], &opp_shift, &opp_mask); - return &opp->base; -} - -static struct dce_aux *dcn10_aux_engine_create(struct dc_context *ctx, - uint32_t inst) -{ - struct aux_engine_dce110 *aux_engine = - kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); - - if (!aux_engine) - return NULL; - - dce110_aux_engine_construct(aux_engine, ctx, inst, - SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, - &aux_engine_regs[inst], - &aux_mask, - &aux_shift, - ctx->dc->caps.extended_aux_timeout_support); - - return &aux_engine->base; -} -#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST(id) } - -static const struct dce_i2c_registers i2c_hw_regs[] = { - i2c_inst_regs(1), - i2c_inst_regs(2), - i2c_inst_regs(3), - i2c_inst_regs(4), - i2c_inst_regs(5), - i2c_inst_regs(6), -}; - -static const struct dce_i2c_shift i2c_shifts = { - I2C_COMMON_MASK_SH_LIST_DCE110(__SHIFT) -}; - -static const struct dce_i2c_mask i2c_masks = { - I2C_COMMON_MASK_SH_LIST_DCE110(_MASK) -}; - -static struct dce_i2c_hw *dcn10_i2c_hw_create(struct dc_context *ctx, - uint32_t inst) -{ - struct dce_i2c_hw *dce_i2c_hw = - kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); - - if (!dce_i2c_hw) - return NULL; - - dcn1_i2c_hw_construct(dce_i2c_hw, ctx, inst, - &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); - - return dce_i2c_hw; -} -static struct mpc *dcn10_mpc_create(struct dc_context *ctx) -{ - struct dcn10_mpc *mpc10 = kzalloc(sizeof(struct dcn10_mpc), - GFP_KERNEL); - - if (!mpc10) - return NULL; - - dcn10_mpc_construct(mpc10, ctx, - &mpc_regs, - &mpc_shift, - &mpc_mask, - 4); - - return &mpc10->base; -} - -static struct hubbub *dcn10_hubbub_create(struct dc_context *ctx) -{ - struct dcn10_hubbub *dcn10_hubbub = kzalloc(sizeof(struct dcn10_hubbub), - GFP_KERNEL); - - if (!dcn10_hubbub) - return NULL; - - hubbub1_construct(&dcn10_hubbub->base, ctx, - &hubbub_reg, - &hubbub_shift, - &hubbub_mask); - - return &dcn10_hubbub->base; -} - -static struct timing_generator *dcn10_timing_generator_create( - struct dc_context *ctx, - uint32_t instance) -{ - struct optc *tgn10 = - kzalloc(sizeof(struct optc), GFP_KERNEL); - - if (!tgn10) - return NULL; - - tgn10->base.inst = instance; - tgn10->base.ctx = ctx; - - tgn10->tg_regs = &tg_regs[instance]; - tgn10->tg_shift = &tg_shift; - tgn10->tg_mask = &tg_mask; - - dcn10_timing_generator_init(tgn10); - - return &tgn10->base; -} - -static const struct encoder_feature_support link_enc_feature = { - .max_hdmi_deep_color = COLOR_DEPTH_121212, - .max_hdmi_pixel_clock = 600000, - .hdmi_ycbcr420_supported = true, - .dp_ycbcr420_supported = true, - .flags.bits.IS_HBR2_CAPABLE = true, - .flags.bits.IS_HBR3_CAPABLE = true, - .flags.bits.IS_TPS3_CAPABLE = true, - .flags.bits.IS_TPS4_CAPABLE = true -}; - -static struct link_encoder *dcn10_link_encoder_create( - struct dc_context *ctx, - const struct encoder_init_data *enc_init_data) -{ - struct dcn10_link_encoder *enc10 = - kzalloc(sizeof(struct dcn10_link_encoder), GFP_KERNEL); - int link_regs_id; - - if (!enc10) - return NULL; - - link_regs_id = - map_transmitter_id_to_phy_instance(enc_init_data->transmitter); - - dcn10_link_encoder_construct(enc10, - enc_init_data, - &link_enc_feature, - &link_enc_regs[link_regs_id], - &link_enc_aux_regs[enc_init_data->channel - 1], - &link_enc_hpd_regs[enc_init_data->hpd_source], - &le_shift, - &le_mask); - - return &enc10->base; -} - -static struct panel_cntl *dcn10_panel_cntl_create(const struct panel_cntl_init_data *init_data) -{ - struct dce_panel_cntl *panel_cntl = - kzalloc(sizeof(struct dce_panel_cntl), GFP_KERNEL); - - if (!panel_cntl) - return NULL; - - dce_panel_cntl_construct(panel_cntl, - init_data, - &panel_cntl_regs[init_data->inst], - &panel_cntl_shift, - &panel_cntl_mask); - - return &panel_cntl->base; -} - -static struct clock_source *dcn10_clock_source_create( - struct dc_context *ctx, - struct dc_bios *bios, - enum clock_source_id id, - const struct dce110_clk_src_regs *regs, - bool dp_clk_src) -{ - struct dce110_clk_src *clk_src = - kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); - - if (!clk_src) - return NULL; - - if (dce112_clk_src_construct(clk_src, ctx, bios, id, - regs, &cs_shift, &cs_mask)) { - clk_src->base.dp_clk_src = dp_clk_src; - return &clk_src->base; - } - - kfree(clk_src); - BREAK_TO_DEBUGGER(); - return NULL; -} - -static void read_dce_straps( - struct dc_context *ctx, - struct resource_straps *straps) -{ - generic_reg_get(ctx, mmDC_PINSTRAPS + BASE(mmDC_PINSTRAPS_BASE_IDX), - FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio); -} - -static struct audio *create_audio( - struct dc_context *ctx, unsigned int inst) -{ - return dce_audio_create(ctx, inst, - &audio_regs[inst], &audio_shift, &audio_mask); -} - -static struct stream_encoder *dcn10_stream_encoder_create( - enum engine_id eng_id, - struct dc_context *ctx) -{ - struct dcn10_stream_encoder *enc1 = - kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL); - - if (!enc1) - return NULL; - - dcn10_stream_encoder_construct(enc1, ctx, ctx->dc_bios, eng_id, - &stream_enc_regs[eng_id], - &se_shift, &se_mask); - return &enc1->base; -} - -static const struct dce_hwseq_registers hwseq_reg = { - HWSEQ_DCN1_REG_LIST() -}; - -static const struct dce_hwseq_shift hwseq_shift = { - HWSEQ_DCN1_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_hwseq_mask hwseq_mask = { - HWSEQ_DCN1_MASK_SH_LIST(_MASK) -}; - -static struct dce_hwseq *dcn10_hwseq_create( - struct dc_context *ctx) -{ - struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); - - if (hws) { - hws->ctx = ctx; - hws->regs = &hwseq_reg; - hws->shifts = &hwseq_shift; - hws->masks = &hwseq_mask; - hws->wa.DEGVIDCN10_253 = true; - hws->wa.false_optc_underflow = true; - hws->wa.DEGVIDCN10_254 = true; - - if ((ctx->asic_id.chip_family == FAMILY_RV) && - ASICREV_IS_RAVEN2(ctx->asic_id.hw_internal_rev)) - switch (ctx->asic_id.pci_revision_id) { - case PRID_POLLOCK_94: - case PRID_POLLOCK_95: - case PRID_POLLOCK_E9: - case PRID_POLLOCK_EA: - case PRID_POLLOCK_EB: - hws->wa.wait_hubpret_read_start_during_mpo_transition = true; - break; - default: - hws->wa.wait_hubpret_read_start_during_mpo_transition = false; - break; - } - } - return hws; -} - -static const struct resource_create_funcs res_create_funcs = { - .read_dce_straps = read_dce_straps, - .create_audio = create_audio, - .create_stream_encoder = dcn10_stream_encoder_create, - .create_hwseq = dcn10_hwseq_create, -}; - -static void dcn10_clock_source_destroy(struct clock_source **clk_src) -{ - kfree(TO_DCE110_CLK_SRC(*clk_src)); - *clk_src = NULL; -} - -static struct pp_smu_funcs *dcn10_pp_smu_create(struct dc_context *ctx) -{ - struct pp_smu_funcs *pp_smu = kzalloc(sizeof(*pp_smu), GFP_KERNEL); - - if (!pp_smu) - return pp_smu; - - dm_pp_get_funcs(ctx, pp_smu); - return pp_smu; -} - -static void dcn10_resource_destruct(struct dcn10_resource_pool *pool) -{ - unsigned int i; - - for (i = 0; i < pool->base.stream_enc_count; i++) { - if (pool->base.stream_enc[i] != NULL) { - kfree(DCN10STRENC_FROM_STRENC(pool->base.stream_enc[i])); - pool->base.stream_enc[i] = NULL; - } - } - - if (pool->base.mpc != NULL) { - kfree(TO_DCN10_MPC(pool->base.mpc)); - pool->base.mpc = NULL; - } - - kfree(pool->base.hubbub); - pool->base.hubbub = NULL; - - for (i = 0; i < pool->base.pipe_count; i++) { - if (pool->base.opps[i] != NULL) - pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]); - - if (pool->base.dpps[i] != NULL) - dcn10_dpp_destroy(&pool->base.dpps[i]); - - if (pool->base.ipps[i] != NULL) - pool->base.ipps[i]->funcs->ipp_destroy(&pool->base.ipps[i]); - - if (pool->base.hubps[i] != NULL) { - kfree(TO_DCN10_HUBP(pool->base.hubps[i])); - pool->base.hubps[i] = NULL; - } - - if (pool->base.irqs != NULL) { - dal_irq_service_destroy(&pool->base.irqs); - } - - if (pool->base.timing_generators[i] != NULL) { - kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i])); - pool->base.timing_generators[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - if (pool->base.engines[i] != NULL) - dce110_engine_destroy(&pool->base.engines[i]); - kfree(pool->base.hw_i2cs[i]); - pool->base.hw_i2cs[i] = NULL; - kfree(pool->base.sw_i2cs[i]); - pool->base.sw_i2cs[i] = NULL; - } - - for (i = 0; i < pool->base.audio_count; i++) { - if (pool->base.audios[i]) - dce_aud_destroy(&pool->base.audios[i]); - } - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] != NULL) { - dcn10_clock_source_destroy(&pool->base.clock_sources[i]); - pool->base.clock_sources[i] = NULL; - } - } - - if (pool->base.dp_clock_source != NULL) { - dcn10_clock_source_destroy(&pool->base.dp_clock_source); - pool->base.dp_clock_source = NULL; - } - - if (pool->base.abm != NULL) - dce_abm_destroy(&pool->base.abm); - - if (pool->base.dmcu != NULL) - dce_dmcu_destroy(&pool->base.dmcu); - - kfree(pool->base.pp_smu); -} - -static struct hubp *dcn10_hubp_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn10_hubp *hubp1 = - kzalloc(sizeof(struct dcn10_hubp), GFP_KERNEL); - - if (!hubp1) - return NULL; - - dcn10_hubp_construct(hubp1, ctx, inst, - &hubp_regs[inst], &hubp_shift, &hubp_mask); - return &hubp1->base; -} - -static void get_pixel_clock_parameters( - const struct pipe_ctx *pipe_ctx, - struct pixel_clk_params *pixel_clk_params) -{ - const struct dc_stream_state *stream = pipe_ctx->stream; - pixel_clk_params->requested_pix_clk_100hz = stream->timing.pix_clk_100hz; - pixel_clk_params->encoder_object_id = stream->link->link_enc->id; - pixel_clk_params->signal_type = pipe_ctx->stream->signal; - pixel_clk_params->controller_id = pipe_ctx->stream_res.tg->inst + 1; - /* TODO: un-hardcode*/ - pixel_clk_params->requested_sym_clk = LINK_RATE_LOW * - LINK_RATE_REF_FREQ_IN_KHZ; - pixel_clk_params->flags.ENABLE_SS = 0; - pixel_clk_params->color_depth = - stream->timing.display_color_depth; - pixel_clk_params->flags.DISPLAY_BLANKED = 1; - pixel_clk_params->pixel_encoding = stream->timing.pixel_encoding; - - if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR422) - pixel_clk_params->color_depth = COLOR_DEPTH_888; - - if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) - pixel_clk_params->requested_pix_clk_100hz /= 2; - if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING) - pixel_clk_params->requested_pix_clk_100hz *= 2; - -} - -static void build_clamping_params(struct dc_stream_state *stream) -{ - stream->clamping.clamping_level = CLAMPING_FULL_RANGE; - stream->clamping.c_depth = stream->timing.display_color_depth; - stream->clamping.pixel_encoding = stream->timing.pixel_encoding; -} - -static void build_pipe_hw_param(struct pipe_ctx *pipe_ctx) -{ - - get_pixel_clock_parameters(pipe_ctx, &pipe_ctx->stream_res.pix_clk_params); - - pipe_ctx->clock_source->funcs->get_pix_clk_dividers( - pipe_ctx->clock_source, - &pipe_ctx->stream_res.pix_clk_params, - &pipe_ctx->pll_settings); - - pipe_ctx->stream->clamping.pixel_encoding = pipe_ctx->stream->timing.pixel_encoding; - - resource_build_bit_depth_reduction_params(pipe_ctx->stream, - &pipe_ctx->stream->bit_depth_params); - build_clamping_params(pipe_ctx->stream); -} - -static enum dc_status build_mapped_resource( - const struct dc *dc, - struct dc_state *context, - struct dc_stream_state *stream) -{ - struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream); - - if (!pipe_ctx) - return DC_ERROR_UNEXPECTED; - - build_pipe_hw_param(pipe_ctx); - return DC_OK; -} - -static enum dc_status dcn10_add_stream_to_ctx( - struct dc *dc, - struct dc_state *new_ctx, - struct dc_stream_state *dc_stream) -{ - enum dc_status result = DC_ERROR_UNEXPECTED; - - result = resource_map_pool_resources(dc, new_ctx, dc_stream); - - if (result == DC_OK) - result = resource_map_phy_clock_resources(dc, new_ctx, dc_stream); - - - if (result == DC_OK) - result = build_mapped_resource(dc, new_ctx, dc_stream); - - return result; -} - -static struct pipe_ctx *dcn10_acquire_free_pipe_for_layer( - const struct dc_state *cur_ctx, - struct dc_state *new_ctx, - const struct resource_pool *pool, - const struct pipe_ctx *opp_head_pipe) -{ - struct resource_context *res_ctx = &new_ctx->res_ctx; - struct pipe_ctx *head_pipe = resource_get_otg_master_for_stream(res_ctx, opp_head_pipe->stream); - struct pipe_ctx *idle_pipe = resource_find_free_secondary_pipe_legacy(res_ctx, pool, head_pipe); - - if (!head_pipe) { - ASSERT(0); - return NULL; - } - - if (!idle_pipe) - return NULL; - - idle_pipe->stream = head_pipe->stream; - idle_pipe->stream_res.tg = head_pipe->stream_res.tg; - idle_pipe->stream_res.abm = head_pipe->stream_res.abm; - idle_pipe->stream_res.opp = head_pipe->stream_res.opp; - - idle_pipe->plane_res.hubp = pool->hubps[idle_pipe->pipe_idx]; - idle_pipe->plane_res.ipp = pool->ipps[idle_pipe->pipe_idx]; - idle_pipe->plane_res.dpp = pool->dpps[idle_pipe->pipe_idx]; - idle_pipe->plane_res.mpcc_inst = pool->dpps[idle_pipe->pipe_idx]->inst; - - return idle_pipe; -} - -static bool dcn10_get_dcc_compression_cap(const struct dc *dc, - const struct dc_dcc_surface_param *input, - struct dc_surface_dcc_cap *output) -{ - return dc->res_pool->hubbub->funcs->get_dcc_compression_cap( - dc->res_pool->hubbub, - input, - output); -} - -static void dcn10_destroy_resource_pool(struct resource_pool **pool) -{ - struct dcn10_resource_pool *dcn10_pool = TO_DCN10_RES_POOL(*pool); - - dcn10_resource_destruct(dcn10_pool); - kfree(dcn10_pool); - *pool = NULL; -} - -static bool dcn10_validate_bandwidth( - struct dc *dc, - struct dc_state *context, - bool fast_validate) -{ - bool voltage_supported; - - DC_FP_START(); - voltage_supported = dcn_validate_bandwidth(dc, context, fast_validate); - DC_FP_END(); - - return voltage_supported; -} - -static enum dc_status dcn10_validate_plane(const struct dc_plane_state *plane_state, struct dc_caps *caps) -{ - if (plane_state->format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN - && caps->max_video_width != 0 - && plane_state->src_rect.width > caps->max_video_width) - return DC_FAIL_SURFACE_VALIDATE; - - return DC_OK; -} - -static enum dc_status dcn10_validate_global(struct dc *dc, struct dc_state *context) -{ - int i, j; - bool video_down_scaled = false; - bool video_large = false; - bool desktop_large = false; - bool dcc_disabled = false; - bool mpo_enabled = false; - - for (i = 0; i < context->stream_count; i++) { - if (context->stream_status[i].plane_count == 0) - continue; - - if (context->stream_status[i].plane_count > 2) - return DC_FAIL_UNSUPPORTED_1; - - if (context->stream_status[i].plane_count > 1) - mpo_enabled = true; - - for (j = 0; j < context->stream_status[i].plane_count; j++) { - struct dc_plane_state *plane = - context->stream_status[i].plane_states[j]; - - - if (plane->format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) { - - if (plane->src_rect.width > plane->dst_rect.width || - plane->src_rect.height > plane->dst_rect.height) - video_down_scaled = true; - - if (plane->src_rect.width >= 3840) - video_large = true; - - } else { - if (plane->src_rect.width >= 3840) - desktop_large = true; - if (!plane->dcc.enable) - dcc_disabled = true; - } - } - } - - /* Disable MPO in multi-display configurations. */ - if (context->stream_count > 1 && mpo_enabled) - return DC_FAIL_UNSUPPORTED_1; - - /* - * Workaround: On DCN10 there is UMC issue that causes underflow when - * playing 4k video on 4k desktop with video downscaled and single channel - * memory - */ - if (video_large && desktop_large && video_down_scaled && dcc_disabled && - dc->dcn_soc->number_of_channels == 1) - return DC_FAIL_SURFACE_VALIDATE; - - return DC_OK; -} - -static enum dc_status dcn10_patch_unknown_plane_state(struct dc_plane_state *plane_state) -{ - 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; - - if (bpp == 64) - swizzle = DC_SW_64KB_D; - else - swizzle = DC_SW_64KB_S; - - plane_state->tiling_info.gfx9.swizzle = swizzle; - return DC_OK; -} - -struct stream_encoder *dcn10_find_first_free_match_stream_enc_for_link( - struct resource_context *res_ctx, - const struct resource_pool *pool, - struct dc_stream_state *stream) -{ - int i; - int j = -1; - struct dc_link *link = stream->link; - - for (i = 0; i < pool->stream_enc_count; i++) { - if (!res_ctx->is_stream_enc_acquired[i] && - pool->stream_enc[i]) { - /* Store first available for MST second display - * in daisy chain use case - */ - j = i; - if (link->ep_type == DISPLAY_ENDPOINT_PHY && pool->stream_enc[i]->id == - link->link_enc->preferred_engine) - return pool->stream_enc[i]; - } - } - - /* - * For CZ and later, we can allow DIG FE and BE to differ for all display types - */ - - if (j >= 0) - return pool->stream_enc[j]; - - return NULL; -} - -static const struct dc_cap_funcs cap_funcs = { - .get_dcc_compression_cap = dcn10_get_dcc_compression_cap -}; - -static const struct resource_funcs dcn10_res_pool_funcs = { - .destroy = dcn10_destroy_resource_pool, - .link_enc_create = dcn10_link_encoder_create, - .panel_cntl_create = dcn10_panel_cntl_create, - .validate_bandwidth = dcn10_validate_bandwidth, - .acquire_free_pipe_as_secondary_dpp_pipe = dcn10_acquire_free_pipe_for_layer, - .validate_plane = dcn10_validate_plane, - .validate_global = dcn10_validate_global, - .add_stream_to_ctx = dcn10_add_stream_to_ctx, - .patch_unknown_plane_state = dcn10_patch_unknown_plane_state, - .find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link -}; - -static uint32_t read_pipe_fuses(struct dc_context *ctx) -{ - uint32_t value = dm_read_reg_soc15(ctx, mmCC_DC_PIPE_DIS, 0); - /* RV1 support max 4 pipes */ - value = value & 0xf; - return value; -} - -static bool verify_clock_values(struct dm_pp_clock_levels_with_voltage *clks) -{ - int i; - - if (clks->num_levels == 0) - return false; - - for (i = 0; i < clks->num_levels; i++) - /* Ensure that the result is sane */ - if (clks->data[i].clocks_in_khz == 0) - return false; - - return true; -} - -static bool dcn10_resource_construct( - uint8_t num_virtual_links, - struct dc *dc, - struct dcn10_resource_pool *pool) -{ - int i; - int j; - struct dc_context *ctx = dc->ctx; - uint32_t pipe_fuses = read_pipe_fuses(ctx); - struct dm_pp_clock_levels_with_voltage fclks = {0}, dcfclks = {0}; - int min_fclk_khz, min_dcfclk_khz, socclk_khz; - bool res; - - ctx->dc_bios->regs = &bios_regs; - - if (ctx->dce_version == DCN_VERSION_1_01) - pool->base.res_cap = &rv2_res_cap; - else - pool->base.res_cap = &res_cap; - pool->base.funcs = &dcn10_res_pool_funcs; - - /* - * TODO fill in from actual raven resource when we create - * more than virtual encoder - */ - - /************************************************* - * Resource + asic cap harcoding * - *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; - - /* max pipe num for ASIC before check pipe fuses */ - pool->base.pipe_count = pool->base.res_cap->num_timing_generator; - - if (dc->ctx->dce_version == DCN_VERSION_1_01) - pool->base.pipe_count = 3; - dc->caps.max_video_width = 3840; - dc->caps.max_downscale_ratio = 200; - dc->caps.i2c_speed_in_khz = 100; - dc->caps.i2c_speed_in_khz_hdcp = 100; /*1.4 w/a not applied by default*/ - dc->caps.max_cursor_size = 256; - dc->caps.min_horizontal_blanking_period = 80; - dc->caps.max_slave_planes = 1; - dc->caps.max_slave_yuv_planes = 1; - dc->caps.max_slave_rgb_planes = 0; - dc->caps.is_apu = true; - dc->caps.post_blend_color_processing = false; - dc->caps.extended_aux_timeout_support = false; - - /* Raven DP PHY HBR2 eye diagram pattern is not stable. Use TP4 */ - dc->caps.force_dp_tps4_for_cp2520 = true; - - /* Color pipeline capabilities */ - dc->caps.color.dpp.dcn_arch = 1; - dc->caps.color.dpp.input_lut_shared = 1; - dc->caps.color.dpp.icsc = 1; - dc->caps.color.dpp.dgam_ram = 1; - dc->caps.color.dpp.dgam_rom_caps.srgb = 1; - dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1; - dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 0; - dc->caps.color.dpp.dgam_rom_caps.pq = 0; - dc->caps.color.dpp.dgam_rom_caps.hlg = 0; - dc->caps.color.dpp.post_csc = 0; - dc->caps.color.dpp.gamma_corr = 0; - dc->caps.color.dpp.dgam_rom_for_yuv = 1; - - dc->caps.color.dpp.hw_3d_lut = 0; - dc->caps.color.dpp.ogam_ram = 1; // RGAM on DCN1 - dc->caps.color.dpp.ogam_rom_caps.srgb = 1; - dc->caps.color.dpp.ogam_rom_caps.bt2020 = 1; - dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0; - dc->caps.color.dpp.ogam_rom_caps.pq = 0; - dc->caps.color.dpp.ogam_rom_caps.hlg = 0; - dc->caps.color.dpp.ocsc = 1; - - /* no post-blend color operations */ - dc->caps.color.mpc.gamut_remap = 0; - dc->caps.color.mpc.num_3dluts = 0; - dc->caps.color.mpc.shared_3d_lut = 0; - dc->caps.color.mpc.ogam_ram = 0; - dc->caps.color.mpc.ogam_rom_caps.srgb = 0; - dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0; - dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0; - dc->caps.color.mpc.ogam_rom_caps.pq = 0; - dc->caps.color.mpc.ogam_rom_caps.hlg = 0; - dc->caps.color.mpc.ocsc = 0; - - if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) - dc->debug = debug_defaults_drv; - else - dc->debug = debug_defaults_diags; - - /************************************************* - * Create resources * - *************************************************/ - - pool->base.clock_sources[DCN10_CLK_SRC_PLL0] = - dcn10_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL0, - &clk_src_regs[0], false); - pool->base.clock_sources[DCN10_CLK_SRC_PLL1] = - dcn10_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL1, - &clk_src_regs[1], false); - pool->base.clock_sources[DCN10_CLK_SRC_PLL2] = - dcn10_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL2, - &clk_src_regs[2], false); - - if (dc->ctx->dce_version == DCN_VERSION_1_0) { - pool->base.clock_sources[DCN10_CLK_SRC_PLL3] = - dcn10_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL3, - &clk_src_regs[3], false); - } - - pool->base.clk_src_count = DCN10_CLK_SRC_TOTAL; - - if (dc->ctx->dce_version == DCN_VERSION_1_01) - pool->base.clk_src_count = DCN101_CLK_SRC_TOTAL; - - pool->base.dp_clock_source = - dcn10_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_ID_DP_DTO, - /* todo: not reuse phy_pll registers */ - &clk_src_regs[0], true); - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] == NULL) { - dm_error("DC: failed to create clock sources!\n"); - BREAK_TO_DEBUGGER(); - goto fail; - } - } - - pool->base.dmcu = dcn10_dmcu_create(ctx, - &dmcu_regs, - &dmcu_shift, - &dmcu_mask); - if (pool->base.dmcu == NULL) { - dm_error("DC: failed to create dmcu!\n"); - BREAK_TO_DEBUGGER(); - goto fail; - } - - pool->base.abm = dce_abm_create(ctx, - &abm_regs, - &abm_shift, - &abm_mask); - if (pool->base.abm == NULL) { - dm_error("DC: failed to create abm!\n"); - BREAK_TO_DEBUGGER(); - goto fail; - } - - dml_init_instance(&dc->dml, &dcn1_0_soc, &dcn1_0_ip, DML_PROJECT_RAVEN1); - memcpy(dc->dcn_ip, &dcn10_ip_defaults, sizeof(dcn10_ip_defaults)); - memcpy(dc->dcn_soc, &dcn10_soc_defaults, sizeof(dcn10_soc_defaults)); - - DC_FP_START(); - dcn10_resource_construct_fp(dc); - DC_FP_END(); - - if (!dc->config.is_vmin_only_asic) - if (ASICREV_IS_RAVEN2(dc->ctx->asic_id.hw_internal_rev)) - switch (dc->ctx->asic_id.pci_revision_id) { - case PRID_DALI_DE: - case PRID_DALI_DF: - case PRID_DALI_E3: - case PRID_DALI_E4: - case PRID_POLLOCK_94: - case PRID_POLLOCK_95: - case PRID_POLLOCK_E9: - case PRID_POLLOCK_EA: - case PRID_POLLOCK_EB: - dc->config.is_vmin_only_asic = true; - break; - default: - break; - } - - pool->base.pp_smu = dcn10_pp_smu_create(ctx); - - /* - * Right now SMU/PPLIB and DAL all have the AZ D3 force PME notification * - * implemented. So AZ D3 should work.For issue 197007. * - */ - if (pool->base.pp_smu != NULL - && pool->base.pp_smu->rv_funcs.set_pme_wa_enable != NULL) - dc->debug.az_endpoint_mute_only = false; - - - if (!dc->debug.disable_pplib_clock_request) { - /* - * TODO: This is not the proper way to obtain - * fabric_and_dram_bandwidth, should be min(fclk, memclk). - */ - res = dm_pp_get_clock_levels_by_type_with_voltage( - ctx, DM_PP_CLOCK_TYPE_FCLK, &fclks); - - DC_FP_START(); - - if (res) - res = verify_clock_values(&fclks); - - if (res) - dcn_bw_update_from_pplib_fclks(dc, &fclks); - else - BREAK_TO_DEBUGGER(); - - DC_FP_END(); - - res = dm_pp_get_clock_levels_by_type_with_voltage( - ctx, DM_PP_CLOCK_TYPE_DCFCLK, &dcfclks); - - DC_FP_START(); - - if (res) - res = verify_clock_values(&dcfclks); - - if (res) - dcn_bw_update_from_pplib_dcfclks(dc, &dcfclks); - else - BREAK_TO_DEBUGGER(); - - DC_FP_END(); - } - - dcn_bw_sync_calcs_and_dml(dc); - if (!dc->debug.disable_pplib_wm_range) { - dc->res_pool = &pool->base; - DC_FP_START(); - dcn_get_soc_clks( - dc, &min_fclk_khz, &min_dcfclk_khz, &socclk_khz); - DC_FP_END(); - dcn_bw_notify_pplib_of_wm_ranges( - dc, min_fclk_khz, min_dcfclk_khz, socclk_khz); - } - - { - struct irq_service_init_data init_data; - init_data.ctx = dc->ctx; - pool->base.irqs = dal_irq_service_dcn10_create(&init_data); - if (!pool->base.irqs) - goto fail; - } - - /* index to valid pipe resource */ - j = 0; - /* mem input -> ipp -> dpp -> opp -> TG */ - for (i = 0; i < pool->base.pipe_count; i++) { - /* if pipe is disabled, skip instance of HW pipe, - * i.e, skip ASIC register instance - */ - if ((pipe_fuses & (1 << i)) != 0) - continue; - - pool->base.hubps[j] = dcn10_hubp_create(ctx, i); - if (pool->base.hubps[j] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create memory input!\n"); - goto fail; - } - - pool->base.ipps[j] = dcn10_ipp_create(ctx, i); - if (pool->base.ipps[j] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create input pixel processor!\n"); - goto fail; - } - - pool->base.dpps[j] = dcn10_dpp_create(ctx, i); - if (pool->base.dpps[j] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create dpp!\n"); - goto fail; - } - - pool->base.opps[j] = dcn10_opp_create(ctx, i); - if (pool->base.opps[j] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create output pixel processor!\n"); - goto fail; - } - - pool->base.timing_generators[j] = dcn10_timing_generator_create( - ctx, i); - if (pool->base.timing_generators[j] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create tg!\n"); - goto fail; - } - /* check next valid pipe */ - j++; - } - - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - pool->base.engines[i] = dcn10_aux_engine_create(ctx, i); - if (pool->base.engines[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create aux engine!!\n"); - goto fail; - } - pool->base.hw_i2cs[i] = dcn10_i2c_hw_create(ctx, i); - if (pool->base.hw_i2cs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create hw i2c!!\n"); - goto fail; - } - pool->base.sw_i2cs[i] = NULL; - } - - /* valid pipe num */ - pool->base.pipe_count = j; - pool->base.timing_generator_count = j; - - /* within dml lib, it is hard code to 4. If ASIC pipe is fused, - * the value may be changed - */ - dc->dml.ip.max_num_dpp = pool->base.pipe_count; - dc->dcn_ip->max_num_dpp = pool->base.pipe_count; - - pool->base.mpc = dcn10_mpc_create(ctx); - if (pool->base.mpc == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create mpc!\n"); - goto fail; - } - - pool->base.hubbub = dcn10_hubbub_create(ctx); - if (pool->base.hubbub == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create hubbub!\n"); - goto fail; - } - - if (!resource_construct(num_virtual_links, dc, &pool->base, - &res_create_funcs)) - goto fail; - - dcn10_hw_sequencer_construct(dc); - dc->caps.max_planes = pool->base.pipe_count; - - for (i = 0; i < dc->caps.max_planes; ++i) - dc->caps.planes[i] = plane_cap; - - dc->cap_funcs = cap_funcs; - - return true; - -fail: - - dcn10_resource_destruct(pool); - - return false; -} - -struct resource_pool *dcn10_create_resource_pool( - const struct dc_init_data *init_data, - struct dc *dc) -{ - struct dcn10_resource_pool *pool = - kzalloc(sizeof(struct dcn10_resource_pool), GFP_KERNEL); - - if (!pool) - return NULL; - - if (dcn10_resource_construct(init_data->num_virtual_links, dc, pool)) - return &pool->base; - - kfree(pool); - BREAK_TO_DEBUGGER(); - return NULL; -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.h deleted file mode 100644 index bf8e33cd8147c8..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -* Copyright 2016 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_RESOURCE_DCN10_H__ -#define __DC_RESOURCE_DCN10_H__ - -#include "core_types.h" -#include "dml/dcn10/dcn10_fpu.h" - -#define TO_DCN10_RES_POOL(pool)\ - container_of(pool, struct dcn10_resource_pool, base) - -struct dc; -struct resource_pool; -struct _vcs_dpi_display_pipe_params_st; - -extern struct _vcs_dpi_ip_params_st dcn1_0_ip; -extern struct _vcs_dpi_soc_bounding_box_st dcn1_0_soc; - -struct dcn10_resource_pool { - struct resource_pool base; -}; -struct resource_pool *dcn10_create_resource_pool( - const struct dc_init_data *init_data, - struct dc *dc); - -struct stream_encoder *dcn10_find_first_free_match_stream_enc_for_link( - struct resource_context *res_ctx, - const struct resource_pool *pool, - struct dc_stream_state *stream); - - -#endif /* __DC_RESOURCE_DCN10_H__ */ - diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/Makefile b/drivers/gpu/drm/amd/display/dc/dcn20/Makefile index d7dc9696a8c826..3dae3943b056c4 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn20/Makefile @@ -2,13 +2,11 @@ # # Makefile for DCN. -DCN20 = dcn20_resource.o dcn20_init.o dcn20_dpp.o dcn20_dpp_cm.o dcn20_hubp.o \ - dcn20_mpc.o dcn20_opp.o dcn20_hubbub.o dcn20_optc.o dcn20_mmhubbub.o \ +DCN20 = dcn20_dpp.o dcn20_dpp_cm.o dcn20_hubp.o \ + dcn20_mpc.o dcn20_opp.o dcn20_hubbub.o dcn20_mmhubbub.o \ dcn20_stream_encoder.o dcn20_link_encoder.o dcn20_dccg.o \ dcn20_vmid.o dcn20_dwb.o dcn20_dwb_scl.o -DCN20 += dcn20_dsc.o - AMD_DAL_DCN20 = $(addprefix $(AMDDALPATH)/dc/dcn20/,$(DCN20)) AMD_DISPLAY_FILES += $(AMD_DAL_DCN20) diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h index ab6d09c6fe348c..ef5c22f41563d3 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h @@ -291,7 +291,43 @@ type SYMCLKB_FE_SRC_SEL;\ type SYMCLKC_FE_SRC_SEL;\ type SYMCLKD_FE_SRC_SEL;\ - type SYMCLKE_FE_SRC_SEL; + type SYMCLKE_FE_SRC_SEL;\ + type DTBCLK_P0_GATE_DISABLE;\ + type DTBCLK_P1_GATE_DISABLE;\ + type DTBCLK_P2_GATE_DISABLE;\ + type DTBCLK_P3_GATE_DISABLE;\ + type DSCCLK0_ROOT_GATE_DISABLE;\ + type DSCCLK1_ROOT_GATE_DISABLE;\ + type DSCCLK2_ROOT_GATE_DISABLE;\ + type DSCCLK3_ROOT_GATE_DISABLE;\ + type SYMCLKA_FE_ROOT_GATE_DISABLE;\ + type SYMCLKB_FE_ROOT_GATE_DISABLE;\ + type SYMCLKC_FE_ROOT_GATE_DISABLE;\ + type SYMCLKD_FE_ROOT_GATE_DISABLE;\ + type SYMCLKE_FE_ROOT_GATE_DISABLE;\ + type DPPCLK0_ROOT_GATE_DISABLE;\ + type DPPCLK1_ROOT_GATE_DISABLE;\ + type DPPCLK2_ROOT_GATE_DISABLE;\ + type DPPCLK3_ROOT_GATE_DISABLE;\ + type HDMISTREAMCLK0_ROOT_GATE_DISABLE;\ + type SYMCLKA_ROOT_GATE_DISABLE;\ + type SYMCLKB_ROOT_GATE_DISABLE;\ + type SYMCLKC_ROOT_GATE_DISABLE;\ + type SYMCLKD_ROOT_GATE_DISABLE;\ + type SYMCLKE_ROOT_GATE_DISABLE;\ + type PHYA_REFCLK_ROOT_GATE_DISABLE;\ + type PHYB_REFCLK_ROOT_GATE_DISABLE;\ + type PHYC_REFCLK_ROOT_GATE_DISABLE;\ + type PHYD_REFCLK_ROOT_GATE_DISABLE;\ + type PHYE_REFCLK_ROOT_GATE_DISABLE;\ + type DPSTREAMCLK0_ROOT_GATE_DISABLE;\ + type DPSTREAMCLK1_ROOT_GATE_DISABLE;\ + type DPSTREAMCLK2_ROOT_GATE_DISABLE;\ + type DPSTREAMCLK3_ROOT_GATE_DISABLE;\ + type DPSTREAMCLK0_GATE_DISABLE;\ + type DPSTREAMCLK1_GATE_DISABLE;\ + type DPSTREAMCLK2_GATE_DISABLE;\ + type DPSTREAMCLK3_GATE_DISABLE;\ struct dccg_shift { DCCG_REG_FIELD_LIST(uint8_t) diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c deleted file mode 100644 index c9ae2d8f0096fa..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c +++ /dev/null @@ -1,780 +0,0 @@ -/* - * Copyright 2017 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 - -#include "reg_helper.h" -#include "dcn20_dsc.h" -#include "dsc/dscc_types.h" -#include "dsc/rc_calc.h" - -static void dsc_write_to_registers(struct display_stream_compressor *dsc, const struct dsc_reg_values *reg_vals); - -/* Object I/F functions */ -static void dsc2_read_state(struct display_stream_compressor *dsc, struct dcn_dsc_state *s); -static bool dsc2_validate_stream(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg); -static void dsc2_set_config(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg, - struct dsc_optc_config *dsc_optc_cfg); -static void dsc2_enable(struct display_stream_compressor *dsc, int opp_pipe); -static void dsc2_disable(struct display_stream_compressor *dsc); -static void dsc2_disconnect(struct display_stream_compressor *dsc); - -static const struct dsc_funcs dcn20_dsc_funcs = { - .dsc_get_enc_caps = dsc2_get_enc_caps, - .dsc_read_state = dsc2_read_state, - .dsc_validate_stream = dsc2_validate_stream, - .dsc_set_config = dsc2_set_config, - .dsc_get_packed_pps = dsc2_get_packed_pps, - .dsc_enable = dsc2_enable, - .dsc_disable = dsc2_disable, - .dsc_disconnect = dsc2_disconnect, -}; - -/* Macro definitios for REG_SET macros*/ -#define CTX \ - dsc20->base.ctx - -#define REG(reg)\ - dsc20->dsc_regs->reg - -#undef FN -#define FN(reg_name, field_name) \ - dsc20->dsc_shift->field_name, dsc20->dsc_mask->field_name -#define DC_LOGGER \ - dsc->ctx->logger - -enum dsc_bits_per_comp { - DSC_BPC_8 = 8, - DSC_BPC_10 = 10, - DSC_BPC_12 = 12, - DSC_BPC_UNKNOWN -}; - -/* API functions (external or via structure->function_pointer) */ - -void dsc2_construct(struct dcn20_dsc *dsc, - struct dc_context *ctx, - int inst, - const struct dcn20_dsc_registers *dsc_regs, - const struct dcn20_dsc_shift *dsc_shift, - const struct dcn20_dsc_mask *dsc_mask) -{ - dsc->base.ctx = ctx; - dsc->base.inst = inst; - dsc->base.funcs = &dcn20_dsc_funcs; - - dsc->dsc_regs = dsc_regs; - dsc->dsc_shift = dsc_shift; - dsc->dsc_mask = dsc_mask; - - dsc->max_image_width = 5184; -} - - -#define DCN20_MAX_PIXEL_CLOCK_Mhz 1188 -#define DCN20_MAX_DISPLAY_CLOCK_Mhz 1200 - -/* This returns the capabilities for a single DSC encoder engine. Number of slices and total throughput - * can be doubled, tripled etc. by using additional DSC engines. - */ -void dsc2_get_enc_caps(struct dsc_enc_caps *dsc_enc_caps, int pixel_clock_100Hz) -{ - dsc_enc_caps->dsc_version = 0x21; /* v1.2 - DP spec defined it in reverse order and we kept it */ - - dsc_enc_caps->slice_caps.bits.NUM_SLICES_1 = 1; - dsc_enc_caps->slice_caps.bits.NUM_SLICES_2 = 1; - dsc_enc_caps->slice_caps.bits.NUM_SLICES_3 = 1; - dsc_enc_caps->slice_caps.bits.NUM_SLICES_4 = 1; - - dsc_enc_caps->lb_bit_depth = 13; - dsc_enc_caps->is_block_pred_supported = true; - - dsc_enc_caps->color_formats.bits.RGB = 1; - dsc_enc_caps->color_formats.bits.YCBCR_444 = 1; - dsc_enc_caps->color_formats.bits.YCBCR_SIMPLE_422 = 1; - dsc_enc_caps->color_formats.bits.YCBCR_NATIVE_422 = 0; - dsc_enc_caps->color_formats.bits.YCBCR_NATIVE_420 = 1; - - dsc_enc_caps->color_depth.bits.COLOR_DEPTH_8_BPC = 1; - dsc_enc_caps->color_depth.bits.COLOR_DEPTH_10_BPC = 1; - dsc_enc_caps->color_depth.bits.COLOR_DEPTH_12_BPC = 1; - - /* Maximum total throughput with all the slices combined. This is different from how DP spec specifies it. - * Our decoder's total throughput in Pix/s is equal to DISPCLK. This is then shared between slices. - * The value below is the absolute maximum value. The actual throughput may be lower, but it'll always - * be sufficient to process the input pixel rate fed into a single DSC engine. - */ - dsc_enc_caps->max_total_throughput_mps = DCN20_MAX_DISPLAY_CLOCK_Mhz; - - /* For pixel clock bigger than a single-pipe limit we'll need two engines, which then doubles our - * throughput and number of slices, but also introduces a lower limit of 2 slices - */ - if (pixel_clock_100Hz >= DCN20_MAX_PIXEL_CLOCK_Mhz*10000) { - dsc_enc_caps->slice_caps.bits.NUM_SLICES_1 = 0; - dsc_enc_caps->slice_caps.bits.NUM_SLICES_8 = 1; - dsc_enc_caps->max_total_throughput_mps = DCN20_MAX_DISPLAY_CLOCK_Mhz * 2; - } - - /* For pixel clock bigger than a single-pipe limit needing four engines ODM 4:1, which then quardruples our - * throughput and number of slices - */ - if (pixel_clock_100Hz > DCN20_MAX_PIXEL_CLOCK_Mhz*10000*2) { - dsc_enc_caps->slice_caps.bits.NUM_SLICES_12 = 1; - dsc_enc_caps->slice_caps.bits.NUM_SLICES_16 = 1; - dsc_enc_caps->max_total_throughput_mps = DCN20_MAX_DISPLAY_CLOCK_Mhz * 4; - } - - dsc_enc_caps->max_slice_width = 5184; /* (including 64 overlap pixels for eDP MSO mode) */ - dsc_enc_caps->bpp_increment_div = 16; /* 1/16th of a bit */ -} - - -/* this function read dsc related register fields to be logged later in dcn10_log_hw_state - * into a dcn_dsc_state struct. - */ -static void dsc2_read_state(struct display_stream_compressor *dsc, struct dcn_dsc_state *s) -{ - struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc); - - REG_GET(DSC_TOP_CONTROL, DSC_CLOCK_EN, &s->dsc_clock_en); - REG_GET(DSCC_PPS_CONFIG3, SLICE_WIDTH, &s->dsc_slice_width); - REG_GET(DSCC_PPS_CONFIG1, BITS_PER_PIXEL, &s->dsc_bits_per_pixel); - REG_GET(DSCC_PPS_CONFIG3, SLICE_HEIGHT, &s->dsc_slice_height); - REG_GET(DSCC_PPS_CONFIG1, CHUNK_SIZE, &s->dsc_chunk_size); - REG_GET(DSCC_PPS_CONFIG2, PIC_WIDTH, &s->dsc_pic_width); - REG_GET(DSCC_PPS_CONFIG2, PIC_HEIGHT, &s->dsc_pic_height); - REG_GET(DSCC_PPS_CONFIG7, SLICE_BPG_OFFSET, &s->dsc_slice_bpg_offset); - REG_GET_2(DSCRM_DSC_FORWARD_CONFIG, DSCRM_DSC_FORWARD_EN, &s->dsc_fw_en, - DSCRM_DSC_OPP_PIPE_SOURCE, &s->dsc_opp_source); -} - - -static bool dsc2_validate_stream(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg) -{ - struct dsc_optc_config dsc_optc_cfg; - struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc); - - if (dsc_cfg->pic_width > dsc20->max_image_width) - return false; - - return dsc_prepare_config(dsc_cfg, &dsc20->reg_vals, &dsc_optc_cfg); -} - - -void dsc_config_log(struct display_stream_compressor *dsc, const struct dsc_config *config) -{ - DC_LOG_DSC("\tnum_slices_h %d", config->dc_dsc_cfg.num_slices_h); - DC_LOG_DSC("\tnum_slices_v %d", config->dc_dsc_cfg.num_slices_v); - DC_LOG_DSC("\tbits_per_pixel %d (%d.%04d)", - config->dc_dsc_cfg.bits_per_pixel, - config->dc_dsc_cfg.bits_per_pixel / 16, - ((config->dc_dsc_cfg.bits_per_pixel % 16) * 10000) / 16); - DC_LOG_DSC("\tcolor_depth %d", config->color_depth); -} - -static void dsc2_set_config(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg, - struct dsc_optc_config *dsc_optc_cfg) -{ - bool is_config_ok; - struct dcn20_dsc *dsc20 = TO_DCN20_DSC(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); - ASSERT(is_config_ok); - DC_LOG_DSC("programming DSC Picture Parameter Set (PPS):"); - dsc_log_pps(dsc, &dsc20->reg_vals.pps); - dsc_write_to_registers(dsc, &dsc20->reg_vals); -} - - -bool dsc2_get_packed_pps(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg, uint8_t *dsc_packed_pps) -{ - bool is_config_ok; - struct dsc_reg_values dsc_reg_vals; - struct dsc_optc_config dsc_optc_cfg; - - memset(&dsc_reg_vals, 0, sizeof(dsc_reg_vals)); - memset(&dsc_optc_cfg, 0, sizeof(dsc_optc_cfg)); - - DC_LOG_DSC("Getting packed DSC PPS for DSC Config:"); - dsc_config_log(dsc, dsc_cfg); - DC_LOG_DSC("DSC Picture Parameter Set (PPS):"); - is_config_ok = dsc_prepare_config(dsc_cfg, &dsc_reg_vals, &dsc_optc_cfg); - ASSERT(is_config_ok); - drm_dsc_pps_payload_pack((struct drm_dsc_picture_parameter_set *)dsc_packed_pps, &dsc_reg_vals.pps); - dsc_log_pps(dsc, &dsc_reg_vals.pps); - - return is_config_ok; -} - - -static void dsc2_enable(struct display_stream_compressor *dsc, int opp_pipe) -{ - struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc); - int dsc_clock_en; - int dsc_fw_config; - int enabled_opp_pipe; - - DC_LOG_DSC("enable DSC %d at opp pipe %d", dsc->inst, opp_pipe); - - REG_GET(DSC_TOP_CONTROL, DSC_CLOCK_EN, &dsc_clock_en); - REG_GET_2(DSCRM_DSC_FORWARD_CONFIG, DSCRM_DSC_FORWARD_EN, &dsc_fw_config, DSCRM_DSC_OPP_PIPE_SOURCE, &enabled_opp_pipe); - if ((dsc_clock_en || dsc_fw_config) && enabled_opp_pipe != opp_pipe) { - DC_LOG_DSC("ERROR: DSC %d at opp pipe %d already enabled!", dsc->inst, enabled_opp_pipe); - ASSERT(0); - } - - REG_UPDATE(DSC_TOP_CONTROL, - DSC_CLOCK_EN, 1); - - REG_UPDATE_2(DSCRM_DSC_FORWARD_CONFIG, - DSCRM_DSC_FORWARD_EN, 1, - DSCRM_DSC_OPP_PIPE_SOURCE, opp_pipe); -} - - -static void dsc2_disable(struct display_stream_compressor *dsc) -{ - struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc); - int dsc_clock_en; - int dsc_fw_config; - int enabled_opp_pipe; - - DC_LOG_DSC("disable DSC %d", dsc->inst); - - REG_GET(DSC_TOP_CONTROL, DSC_CLOCK_EN, &dsc_clock_en); - REG_GET_2(DSCRM_DSC_FORWARD_CONFIG, DSCRM_DSC_FORWARD_EN, &dsc_fw_config, DSCRM_DSC_OPP_PIPE_SOURCE, &enabled_opp_pipe); - if (!dsc_clock_en || !dsc_fw_config) { - DC_LOG_DSC("ERROR: DSC %d at opp pipe %d already disabled!", dsc->inst, enabled_opp_pipe); - ASSERT(0); - } - - REG_UPDATE(DSCRM_DSC_FORWARD_CONFIG, - DSCRM_DSC_FORWARD_EN, 0); - - REG_UPDATE(DSC_TOP_CONTROL, - DSC_CLOCK_EN, 0); -} - -static void dsc2_disconnect(struct display_stream_compressor *dsc) -{ - struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc); - - DC_LOG_DSC("disconnect DSC %d", dsc->inst); - - REG_UPDATE(DSCRM_DSC_FORWARD_CONFIG, - DSCRM_DSC_FORWARD_EN, 0); -} - -/* This module's internal functions */ -void dsc_log_pps(struct display_stream_compressor *dsc, struct drm_dsc_config *pps) -{ - int i; - int bits_per_pixel = pps->bits_per_pixel; - - DC_LOG_DSC("\tdsc_version_major %d", pps->dsc_version_major); - DC_LOG_DSC("\tdsc_version_minor %d", pps->dsc_version_minor); - DC_LOG_DSC("\tbits_per_component %d", pps->bits_per_component); - DC_LOG_DSC("\tline_buf_depth %d", pps->line_buf_depth); - DC_LOG_DSC("\tblock_pred_enable %d", pps->block_pred_enable); - DC_LOG_DSC("\tconvert_rgb %d", pps->convert_rgb); - DC_LOG_DSC("\tsimple_422 %d", pps->simple_422); - DC_LOG_DSC("\tvbr_enable %d", pps->vbr_enable); - DC_LOG_DSC("\tbits_per_pixel %d (%d.%04d)", bits_per_pixel, bits_per_pixel / 16, ((bits_per_pixel % 16) * 10000) / 16); - DC_LOG_DSC("\tpic_height %d", pps->pic_height); - DC_LOG_DSC("\tpic_width %d", pps->pic_width); - DC_LOG_DSC("\tslice_height %d", pps->slice_height); - DC_LOG_DSC("\tslice_width %d", pps->slice_width); - DC_LOG_DSC("\tslice_chunk_size %d", pps->slice_chunk_size); - DC_LOG_DSC("\tinitial_xmit_delay %d", pps->initial_xmit_delay); - DC_LOG_DSC("\tinitial_dec_delay %d", pps->initial_dec_delay); - DC_LOG_DSC("\tinitial_scale_value %d", pps->initial_scale_value); - DC_LOG_DSC("\tscale_increment_interval %d", pps->scale_increment_interval); - DC_LOG_DSC("\tscale_decrement_interval %d", pps->scale_decrement_interval); - DC_LOG_DSC("\tfirst_line_bpg_offset %d", pps->first_line_bpg_offset); - DC_LOG_DSC("\tnfl_bpg_offset %d", pps->nfl_bpg_offset); - DC_LOG_DSC("\tslice_bpg_offset %d", pps->slice_bpg_offset); - DC_LOG_DSC("\tinitial_offset %d", pps->initial_offset); - DC_LOG_DSC("\tfinal_offset %d", pps->final_offset); - DC_LOG_DSC("\tflatness_min_qp %d", pps->flatness_min_qp); - DC_LOG_DSC("\tflatness_max_qp %d", pps->flatness_max_qp); - /* DC_LOG_DSC("\trc_parameter_set %d", pps->rc_parameter_set); */ - DC_LOG_DSC("\tnative_420 %d", pps->native_420); - DC_LOG_DSC("\tnative_422 %d", pps->native_422); - DC_LOG_DSC("\tsecond_line_bpg_offset %d", pps->second_line_bpg_offset); - DC_LOG_DSC("\tnsl_bpg_offset %d", pps->nsl_bpg_offset); - DC_LOG_DSC("\tsecond_line_offset_adj %d", pps->second_line_offset_adj); - DC_LOG_DSC("\trc_model_size %d", pps->rc_model_size); - DC_LOG_DSC("\trc_edge_factor %d", pps->rc_edge_factor); - DC_LOG_DSC("\trc_quant_incr_limit0 %d", pps->rc_quant_incr_limit0); - DC_LOG_DSC("\trc_quant_incr_limit1 %d", pps->rc_quant_incr_limit1); - DC_LOG_DSC("\trc_tgt_offset_high %d", pps->rc_tgt_offset_high); - DC_LOG_DSC("\trc_tgt_offset_low %d", pps->rc_tgt_offset_low); - - for (i = 0; i < NUM_BUF_RANGES - 1; i++) - DC_LOG_DSC("\trc_buf_thresh[%d] %d", i, pps->rc_buf_thresh[i]); - - for (i = 0; i < NUM_BUF_RANGES; i++) { - DC_LOG_DSC("\trc_range_parameters[%d].range_min_qp %d", i, pps->rc_range_params[i].range_min_qp); - DC_LOG_DSC("\trc_range_parameters[%d].range_max_qp %d", i, pps->rc_range_params[i].range_max_qp); - DC_LOG_DSC("\trc_range_parameters[%d].range_bpg_offset %d", i, pps->rc_range_params[i].range_bpg_offset); - } -} - -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; -} - -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); - ASSERT(dsc_cfg->dc_dsc_cfg.num_slices_v); - ASSERT(dsc_cfg->dc_dsc_cfg.version_minor == 1 || dsc_cfg->dc_dsc_cfg.version_minor == 2); - ASSERT(dsc_cfg->pic_width); - ASSERT(dsc_cfg->pic_height); - ASSERT((dsc_cfg->dc_dsc_cfg.version_minor == 1 && - (8 <= dsc_cfg->dc_dsc_cfg.linebuf_depth && dsc_cfg->dc_dsc_cfg.linebuf_depth <= 13)) || - (dsc_cfg->dc_dsc_cfg.version_minor == 2 && - ((8 <= dsc_cfg->dc_dsc_cfg.linebuf_depth && dsc_cfg->dc_dsc_cfg.linebuf_depth <= 15) || - dsc_cfg->dc_dsc_cfg.linebuf_depth == 0))); - ASSERT(96 <= dsc_cfg->dc_dsc_cfg.bits_per_pixel && dsc_cfg->dc_dsc_cfg.bits_per_pixel <= 0x3ff); // 6.0 <= bits_per_pixel <= 63.9375 - - if (!dsc_cfg->dc_dsc_cfg.num_slices_v || !dsc_cfg->dc_dsc_cfg.num_slices_h || - !(dsc_cfg->dc_dsc_cfg.version_minor == 1 || dsc_cfg->dc_dsc_cfg.version_minor == 2) || - !dsc_cfg->pic_width || !dsc_cfg->pic_height || - !((dsc_cfg->dc_dsc_cfg.version_minor == 1 && // v1.1 line buffer depth range: - 8 <= dsc_cfg->dc_dsc_cfg.linebuf_depth && dsc_cfg->dc_dsc_cfg.linebuf_depth <= 13) || - (dsc_cfg->dc_dsc_cfg.version_minor == 2 && // v1.2 line buffer depth range: - ((8 <= dsc_cfg->dc_dsc_cfg.linebuf_depth && dsc_cfg->dc_dsc_cfg.linebuf_depth <= 15) || - dsc_cfg->dc_dsc_cfg.linebuf_depth == 0))) || - !(96 <= dsc_cfg->dc_dsc_cfg.bits_per_pixel && dsc_cfg->dc_dsc_cfg.bits_per_pixel <= 0x3ff)) { - dm_output_to_console("%s: Invalid parameters\n", __func__); - return false; - } - - dsc_init_reg_values(dsc_reg_vals); - - /* Copy input config */ - dsc_reg_vals->pixel_format = dsc_dc_pixel_encoding_to_dsc_pixel_format(dsc_cfg->pixel_encoding, dsc_cfg->dc_dsc_cfg.ycbcr422_simple); - dsc_reg_vals->num_slices_h = dsc_cfg->dc_dsc_cfg.num_slices_h; - dsc_reg_vals->num_slices_v = dsc_cfg->dc_dsc_cfg.num_slices_v; - dsc_reg_vals->pps.dsc_version_minor = dsc_cfg->dc_dsc_cfg.version_minor; - dsc_reg_vals->pps.pic_width = dsc_cfg->pic_width; - dsc_reg_vals->pps.pic_height = dsc_cfg->pic_height; - dsc_reg_vals->pps.bits_per_component = dsc_dc_color_depth_to_dsc_bits_per_comp(dsc_cfg->color_depth); - dsc_reg_vals->pps.block_pred_enable = dsc_cfg->dc_dsc_cfg.block_pred_enable; - dsc_reg_vals->pps.line_buf_depth = dsc_cfg->dc_dsc_cfg.linebuf_depth; - dsc_reg_vals->alternate_ich_encoding_en = dsc_reg_vals->pps.dsc_version_minor == 1 ? 0 : 1; - dsc_reg_vals->ich_reset_at_eol = (dsc_cfg->is_odm || dsc_reg_vals->num_slices_h > 1) ? 0xF : 0; - - // TODO: in addition to validating slice height (pic height must be divisible by slice height), - // see what happens when the same condition doesn't apply for slice_width/pic_width. - dsc_reg_vals->pps.slice_width = dsc_cfg->pic_width / dsc_cfg->dc_dsc_cfg.num_slices_h; - dsc_reg_vals->pps.slice_height = dsc_cfg->pic_height / dsc_cfg->dc_dsc_cfg.num_slices_v; - - ASSERT(dsc_reg_vals->pps.slice_height * dsc_cfg->dc_dsc_cfg.num_slices_v == dsc_cfg->pic_height); - if (!(dsc_reg_vals->pps.slice_height * dsc_cfg->dc_dsc_cfg.num_slices_v == dsc_cfg->pic_height)) { - dm_output_to_console("%s: pix height %d not divisible by num_slices_v %d\n\n", __func__, dsc_cfg->pic_height, dsc_cfg->dc_dsc_cfg.num_slices_v); - return false; - } - - dsc_reg_vals->bpp_x32 = dsc_cfg->dc_dsc_cfg.bits_per_pixel << 1; - if (dsc_reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR420 || dsc_reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR422) - dsc_reg_vals->pps.bits_per_pixel = dsc_reg_vals->bpp_x32; - else - dsc_reg_vals->pps.bits_per_pixel = dsc_reg_vals->bpp_x32 >> 1; - - dsc_reg_vals->pps.convert_rgb = dsc_reg_vals->pixel_format == DSC_PIXFMT_RGB ? 1 : 0; - dsc_reg_vals->pps.native_422 = (dsc_reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR422); - 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); - - 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; - } - - dsc_update_from_dsc_parameters(dsc_reg_vals, &dsc_params); - - dsc_optc_cfg->bytes_per_pixel = dsc_params.bytes_per_pixel; - dsc_optc_cfg->slice_width = dsc_reg_vals->pps.slice_width; - dsc_optc_cfg->is_pixel_format_444 = dsc_reg_vals->pixel_format == DSC_PIXFMT_RGB || - dsc_reg_vals->pixel_format == DSC_PIXFMT_YCBCR444 || - dsc_reg_vals->pixel_format == DSC_PIXFMT_SIMPLE_YCBCR422; - - return true; -} - - -enum dsc_pixel_format dsc_dc_pixel_encoding_to_dsc_pixel_format(enum dc_pixel_encoding dc_pix_enc, bool is_ycbcr422_simple) -{ - enum dsc_pixel_format dsc_pix_fmt = DSC_PIXFMT_UNKNOWN; - - /* NOTE: We don't support DSC_PIXFMT_SIMPLE_YCBCR422 */ - - switch (dc_pix_enc) { - case PIXEL_ENCODING_RGB: - dsc_pix_fmt = DSC_PIXFMT_RGB; - break; - case PIXEL_ENCODING_YCBCR422: - if (is_ycbcr422_simple) - dsc_pix_fmt = DSC_PIXFMT_SIMPLE_YCBCR422; - else - dsc_pix_fmt = DSC_PIXFMT_NATIVE_YCBCR422; - break; - case PIXEL_ENCODING_YCBCR444: - dsc_pix_fmt = DSC_PIXFMT_YCBCR444; - break; - case PIXEL_ENCODING_YCBCR420: - dsc_pix_fmt = DSC_PIXFMT_NATIVE_YCBCR420; - break; - default: - dsc_pix_fmt = DSC_PIXFMT_UNKNOWN; - break; - } - - ASSERT(dsc_pix_fmt != DSC_PIXFMT_UNKNOWN); - return dsc_pix_fmt; -} - - -enum dsc_bits_per_comp dsc_dc_color_depth_to_dsc_bits_per_comp(enum dc_color_depth dc_color_depth) -{ - enum dsc_bits_per_comp bpc = DSC_BPC_UNKNOWN; - - switch (dc_color_depth) { - case COLOR_DEPTH_888: - bpc = DSC_BPC_8; - break; - case COLOR_DEPTH_101010: - bpc = DSC_BPC_10; - break; - case COLOR_DEPTH_121212: - bpc = DSC_BPC_12; - break; - default: - bpc = DSC_BPC_UNKNOWN; - break; - } - - return bpc; -} - - -void dsc_init_reg_values(struct dsc_reg_values *reg_vals) -{ - int i; - - memset(reg_vals, 0, sizeof(struct dsc_reg_values)); - - /* Non-PPS values */ - reg_vals->dsc_clock_enable = 1; - reg_vals->dsc_clock_gating_disable = 0; - reg_vals->underflow_recovery_en = 0; - reg_vals->underflow_occurred_int_en = 0; - reg_vals->underflow_occurred_status = 0; - reg_vals->ich_reset_at_eol = 0; - reg_vals->alternate_ich_encoding_en = 0; - reg_vals->rc_buffer_model_size = 0; - /*reg_vals->disable_ich = 0;*/ - reg_vals->dsc_dbg_en = 0; - - for (i = 0; i < 4; i++) - reg_vals->rc_buffer_model_overflow_int_en[i] = 0; - - /* PPS values */ - reg_vals->pps.dsc_version_minor = 2; - reg_vals->pps.dsc_version_major = 1; - reg_vals->pps.line_buf_depth = 9; - reg_vals->pps.bits_per_component = 8; - reg_vals->pps.block_pred_enable = 1; - reg_vals->pps.slice_chunk_size = 0; - reg_vals->pps.pic_width = 0; - reg_vals->pps.pic_height = 0; - reg_vals->pps.slice_width = 0; - reg_vals->pps.slice_height = 0; - reg_vals->pps.initial_xmit_delay = 170; - reg_vals->pps.initial_dec_delay = 0; - reg_vals->pps.initial_scale_value = 0; - reg_vals->pps.scale_increment_interval = 0; - reg_vals->pps.scale_decrement_interval = 0; - reg_vals->pps.nfl_bpg_offset = 0; - reg_vals->pps.slice_bpg_offset = 0; - reg_vals->pps.nsl_bpg_offset = 0; - reg_vals->pps.initial_offset = 6144; - reg_vals->pps.final_offset = 0; - reg_vals->pps.flatness_min_qp = 3; - reg_vals->pps.flatness_max_qp = 12; - reg_vals->pps.rc_model_size = 8192; - reg_vals->pps.rc_edge_factor = 6; - reg_vals->pps.rc_quant_incr_limit0 = 11; - reg_vals->pps.rc_quant_incr_limit1 = 11; - reg_vals->pps.rc_tgt_offset_low = 3; - reg_vals->pps.rc_tgt_offset_high = 3; -} - -/* Updates dsc_reg_values::reg_vals::xxx fields based on the values from computed params. - * This is required because dscc_compute_dsc_parameters returns a modified PPS, which in turn - * affects non-PPS register values. - */ -void dsc_update_from_dsc_parameters(struct dsc_reg_values *reg_vals, const struct dsc_parameters *dsc_params) -{ - int i; - - reg_vals->pps = dsc_params->pps; - - // pps_computed will have the "expanded" values; need to shift them to make them fit for regs. - for (i = 0; i < NUM_BUF_RANGES - 1; i++) - reg_vals->pps.rc_buf_thresh[i] = reg_vals->pps.rc_buf_thresh[i] >> 6; - - reg_vals->rc_buffer_model_size = dsc_params->rc_buffer_model_size; -} - -static void dsc_write_to_registers(struct display_stream_compressor *dsc, const struct dsc_reg_values *reg_vals) -{ - uint32_t temp_int; - struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc); - - REG_SET(DSC_DEBUG_CONTROL, 0, - DSC_DBG_EN, reg_vals->dsc_dbg_en); - - // dsccif registers - REG_SET_5(DSCCIF_CONFIG0, 0, - INPUT_INTERFACE_UNDERFLOW_RECOVERY_EN, reg_vals->underflow_recovery_en, - INPUT_INTERFACE_UNDERFLOW_OCCURRED_INT_EN, reg_vals->underflow_occurred_int_en, - INPUT_INTERFACE_UNDERFLOW_OCCURRED_STATUS, reg_vals->underflow_occurred_status, - INPUT_PIXEL_FORMAT, reg_vals->pixel_format, - DSCCIF_CONFIG0__BITS_PER_COMPONENT, reg_vals->pps.bits_per_component); - - REG_SET_2(DSCCIF_CONFIG1, 0, - PIC_WIDTH, reg_vals->pps.pic_width, - PIC_HEIGHT, reg_vals->pps.pic_height); - - // dscc registers - if (dsc20->dsc_mask->ICH_RESET_AT_END_OF_LINE == 0) { - REG_SET_3(DSCC_CONFIG0, 0, - NUMBER_OF_SLICES_PER_LINE, reg_vals->num_slices_h - 1, - ALTERNATE_ICH_ENCODING_EN, reg_vals->alternate_ich_encoding_en, - NUMBER_OF_SLICES_IN_VERTICAL_DIRECTION, reg_vals->num_slices_v - 1); - } else { - REG_SET_4(DSCC_CONFIG0, 0, ICH_RESET_AT_END_OF_LINE, - reg_vals->ich_reset_at_eol, NUMBER_OF_SLICES_PER_LINE, - reg_vals->num_slices_h - 1, ALTERNATE_ICH_ENCODING_EN, - reg_vals->alternate_ich_encoding_en, NUMBER_OF_SLICES_IN_VERTICAL_DIRECTION, - reg_vals->num_slices_v - 1); - } - - REG_SET(DSCC_CONFIG1, 0, - DSCC_RATE_CONTROL_BUFFER_MODEL_SIZE, reg_vals->rc_buffer_model_size); - /*REG_SET_2(DSCC_CONFIG1, 0, - DSCC_RATE_CONTROL_BUFFER_MODEL_SIZE, reg_vals->rc_buffer_model_size, - DSCC_DISABLE_ICH, reg_vals->disable_ich);*/ - - REG_SET_4(DSCC_INTERRUPT_CONTROL_STATUS, 0, - DSCC_RATE_CONTROL_BUFFER_MODEL0_OVERFLOW_OCCURRED_INT_EN, reg_vals->rc_buffer_model_overflow_int_en[0], - DSCC_RATE_CONTROL_BUFFER_MODEL1_OVERFLOW_OCCURRED_INT_EN, reg_vals->rc_buffer_model_overflow_int_en[1], - DSCC_RATE_CONTROL_BUFFER_MODEL2_OVERFLOW_OCCURRED_INT_EN, reg_vals->rc_buffer_model_overflow_int_en[2], - DSCC_RATE_CONTROL_BUFFER_MODEL3_OVERFLOW_OCCURRED_INT_EN, reg_vals->rc_buffer_model_overflow_int_en[3]); - - REG_SET_3(DSCC_PPS_CONFIG0, 0, - DSC_VERSION_MINOR, reg_vals->pps.dsc_version_minor, - LINEBUF_DEPTH, reg_vals->pps.line_buf_depth, - DSCC_PPS_CONFIG0__BITS_PER_COMPONENT, reg_vals->pps.bits_per_component); - - if (reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR420 || reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR422) - temp_int = reg_vals->bpp_x32; - else - temp_int = reg_vals->bpp_x32 >> 1; - - REG_SET_7(DSCC_PPS_CONFIG1, 0, - BITS_PER_PIXEL, temp_int, - SIMPLE_422, reg_vals->pixel_format == DSC_PIXFMT_SIMPLE_YCBCR422, - CONVERT_RGB, reg_vals->pixel_format == DSC_PIXFMT_RGB, - BLOCK_PRED_ENABLE, reg_vals->pps.block_pred_enable, - NATIVE_422, reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR422, - NATIVE_420, reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR420, - CHUNK_SIZE, reg_vals->pps.slice_chunk_size); - - REG_SET_2(DSCC_PPS_CONFIG2, 0, - PIC_WIDTH, reg_vals->pps.pic_width, - PIC_HEIGHT, reg_vals->pps.pic_height); - - REG_SET_2(DSCC_PPS_CONFIG3, 0, - SLICE_WIDTH, reg_vals->pps.slice_width, - SLICE_HEIGHT, reg_vals->pps.slice_height); - - REG_SET(DSCC_PPS_CONFIG4, 0, - INITIAL_XMIT_DELAY, reg_vals->pps.initial_xmit_delay); - - REG_SET_2(DSCC_PPS_CONFIG5, 0, - INITIAL_SCALE_VALUE, reg_vals->pps.initial_scale_value, - SCALE_INCREMENT_INTERVAL, reg_vals->pps.scale_increment_interval); - - REG_SET_3(DSCC_PPS_CONFIG6, 0, - SCALE_DECREMENT_INTERVAL, reg_vals->pps.scale_decrement_interval, - FIRST_LINE_BPG_OFFSET, reg_vals->pps.first_line_bpg_offset, - SECOND_LINE_BPG_OFFSET, reg_vals->pps.second_line_bpg_offset); - - REG_SET_2(DSCC_PPS_CONFIG7, 0, - NFL_BPG_OFFSET, reg_vals->pps.nfl_bpg_offset, - SLICE_BPG_OFFSET, reg_vals->pps.slice_bpg_offset); - - REG_SET_2(DSCC_PPS_CONFIG8, 0, - NSL_BPG_OFFSET, reg_vals->pps.nsl_bpg_offset, - SECOND_LINE_OFFSET_ADJ, reg_vals->pps.second_line_offset_adj); - - REG_SET_2(DSCC_PPS_CONFIG9, 0, - INITIAL_OFFSET, reg_vals->pps.initial_offset, - FINAL_OFFSET, reg_vals->pps.final_offset); - - REG_SET_3(DSCC_PPS_CONFIG10, 0, - FLATNESS_MIN_QP, reg_vals->pps.flatness_min_qp, - FLATNESS_MAX_QP, reg_vals->pps.flatness_max_qp, - RC_MODEL_SIZE, reg_vals->pps.rc_model_size); - - REG_SET_5(DSCC_PPS_CONFIG11, 0, - RC_EDGE_FACTOR, reg_vals->pps.rc_edge_factor, - RC_QUANT_INCR_LIMIT0, reg_vals->pps.rc_quant_incr_limit0, - RC_QUANT_INCR_LIMIT1, reg_vals->pps.rc_quant_incr_limit1, - RC_TGT_OFFSET_LO, reg_vals->pps.rc_tgt_offset_low, - RC_TGT_OFFSET_HI, reg_vals->pps.rc_tgt_offset_high); - - REG_SET_4(DSCC_PPS_CONFIG12, 0, - RC_BUF_THRESH0, reg_vals->pps.rc_buf_thresh[0], - RC_BUF_THRESH1, reg_vals->pps.rc_buf_thresh[1], - RC_BUF_THRESH2, reg_vals->pps.rc_buf_thresh[2], - RC_BUF_THRESH3, reg_vals->pps.rc_buf_thresh[3]); - - REG_SET_4(DSCC_PPS_CONFIG13, 0, - RC_BUF_THRESH4, reg_vals->pps.rc_buf_thresh[4], - RC_BUF_THRESH5, reg_vals->pps.rc_buf_thresh[5], - RC_BUF_THRESH6, reg_vals->pps.rc_buf_thresh[6], - RC_BUF_THRESH7, reg_vals->pps.rc_buf_thresh[7]); - - REG_SET_4(DSCC_PPS_CONFIG14, 0, - RC_BUF_THRESH8, reg_vals->pps.rc_buf_thresh[8], - RC_BUF_THRESH9, reg_vals->pps.rc_buf_thresh[9], - RC_BUF_THRESH10, reg_vals->pps.rc_buf_thresh[10], - RC_BUF_THRESH11, reg_vals->pps.rc_buf_thresh[11]); - - REG_SET_5(DSCC_PPS_CONFIG15, 0, - RC_BUF_THRESH12, reg_vals->pps.rc_buf_thresh[12], - RC_BUF_THRESH13, reg_vals->pps.rc_buf_thresh[13], - RANGE_MIN_QP0, reg_vals->pps.rc_range_params[0].range_min_qp, - RANGE_MAX_QP0, reg_vals->pps.rc_range_params[0].range_max_qp, - RANGE_BPG_OFFSET0, reg_vals->pps.rc_range_params[0].range_bpg_offset); - - REG_SET_6(DSCC_PPS_CONFIG16, 0, - RANGE_MIN_QP1, reg_vals->pps.rc_range_params[1].range_min_qp, - RANGE_MAX_QP1, reg_vals->pps.rc_range_params[1].range_max_qp, - RANGE_BPG_OFFSET1, reg_vals->pps.rc_range_params[1].range_bpg_offset, - RANGE_MIN_QP2, reg_vals->pps.rc_range_params[2].range_min_qp, - RANGE_MAX_QP2, reg_vals->pps.rc_range_params[2].range_max_qp, - RANGE_BPG_OFFSET2, reg_vals->pps.rc_range_params[2].range_bpg_offset); - - REG_SET_6(DSCC_PPS_CONFIG17, 0, - RANGE_MIN_QP3, reg_vals->pps.rc_range_params[3].range_min_qp, - RANGE_MAX_QP3, reg_vals->pps.rc_range_params[3].range_max_qp, - RANGE_BPG_OFFSET3, reg_vals->pps.rc_range_params[3].range_bpg_offset, - RANGE_MIN_QP4, reg_vals->pps.rc_range_params[4].range_min_qp, - RANGE_MAX_QP4, reg_vals->pps.rc_range_params[4].range_max_qp, - RANGE_BPG_OFFSET4, reg_vals->pps.rc_range_params[4].range_bpg_offset); - - REG_SET_6(DSCC_PPS_CONFIG18, 0, - RANGE_MIN_QP5, reg_vals->pps.rc_range_params[5].range_min_qp, - RANGE_MAX_QP5, reg_vals->pps.rc_range_params[5].range_max_qp, - RANGE_BPG_OFFSET5, reg_vals->pps.rc_range_params[5].range_bpg_offset, - RANGE_MIN_QP6, reg_vals->pps.rc_range_params[6].range_min_qp, - RANGE_MAX_QP6, reg_vals->pps.rc_range_params[6].range_max_qp, - RANGE_BPG_OFFSET6, reg_vals->pps.rc_range_params[6].range_bpg_offset); - - REG_SET_6(DSCC_PPS_CONFIG19, 0, - RANGE_MIN_QP7, reg_vals->pps.rc_range_params[7].range_min_qp, - RANGE_MAX_QP7, reg_vals->pps.rc_range_params[7].range_max_qp, - RANGE_BPG_OFFSET7, reg_vals->pps.rc_range_params[7].range_bpg_offset, - RANGE_MIN_QP8, reg_vals->pps.rc_range_params[8].range_min_qp, - RANGE_MAX_QP8, reg_vals->pps.rc_range_params[8].range_max_qp, - RANGE_BPG_OFFSET8, reg_vals->pps.rc_range_params[8].range_bpg_offset); - - REG_SET_6(DSCC_PPS_CONFIG20, 0, - RANGE_MIN_QP9, reg_vals->pps.rc_range_params[9].range_min_qp, - RANGE_MAX_QP9, reg_vals->pps.rc_range_params[9].range_max_qp, - RANGE_BPG_OFFSET9, reg_vals->pps.rc_range_params[9].range_bpg_offset, - RANGE_MIN_QP10, reg_vals->pps.rc_range_params[10].range_min_qp, - RANGE_MAX_QP10, reg_vals->pps.rc_range_params[10].range_max_qp, - RANGE_BPG_OFFSET10, reg_vals->pps.rc_range_params[10].range_bpg_offset); - - REG_SET_6(DSCC_PPS_CONFIG21, 0, - RANGE_MIN_QP11, reg_vals->pps.rc_range_params[11].range_min_qp, - RANGE_MAX_QP11, reg_vals->pps.rc_range_params[11].range_max_qp, - RANGE_BPG_OFFSET11, reg_vals->pps.rc_range_params[11].range_bpg_offset, - RANGE_MIN_QP12, reg_vals->pps.rc_range_params[12].range_min_qp, - RANGE_MAX_QP12, reg_vals->pps.rc_range_params[12].range_max_qp, - RANGE_BPG_OFFSET12, reg_vals->pps.rc_range_params[12].range_bpg_offset); - - REG_SET_6(DSCC_PPS_CONFIG22, 0, - RANGE_MIN_QP13, reg_vals->pps.rc_range_params[13].range_min_qp, - RANGE_MAX_QP13, reg_vals->pps.rc_range_params[13].range_max_qp, - RANGE_BPG_OFFSET13, reg_vals->pps.rc_range_params[13].range_bpg_offset, - RANGE_MIN_QP14, reg_vals->pps.rc_range_params[14].range_min_qp, - RANGE_MAX_QP14, reg_vals->pps.rc_range_params[14].range_max_qp, - RANGE_BPG_OFFSET14, reg_vals->pps.rc_range_params[14].range_bpg_offset); - -} - diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h deleted file mode 100644 index ba869387c3c583..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h +++ /dev/null @@ -1,589 +0,0 @@ -/* Copyright 2017 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 __DCN20_DSC_H__ -#define __DCN20_DSC_H__ - -#include "dsc.h" -#include "dsc/dscc_types.h" -#include - -#define TO_DCN20_DSC(dsc)\ - container_of(dsc, struct dcn20_dsc, base) - -#define DSC_REG_LIST_DCN20(id) \ - SRI(DSC_TOP_CONTROL, DSC_TOP, id),\ - SRI(DSC_DEBUG_CONTROL, DSC_TOP, id),\ - SRI(DSCC_CONFIG0, DSCC, id),\ - SRI(DSCC_CONFIG1, DSCC, id),\ - SRI(DSCC_STATUS, DSCC, id),\ - SRI(DSCC_INTERRUPT_CONTROL_STATUS, DSCC, id),\ - SRI(DSCC_PPS_CONFIG0, DSCC, id),\ - SRI(DSCC_PPS_CONFIG1, DSCC, id),\ - SRI(DSCC_PPS_CONFIG2, DSCC, id),\ - SRI(DSCC_PPS_CONFIG3, DSCC, id),\ - SRI(DSCC_PPS_CONFIG4, DSCC, id),\ - SRI(DSCC_PPS_CONFIG5, DSCC, id),\ - SRI(DSCC_PPS_CONFIG6, DSCC, id),\ - SRI(DSCC_PPS_CONFIG7, DSCC, id),\ - SRI(DSCC_PPS_CONFIG8, DSCC, id),\ - SRI(DSCC_PPS_CONFIG9, DSCC, id),\ - SRI(DSCC_PPS_CONFIG10, DSCC, id),\ - SRI(DSCC_PPS_CONFIG11, DSCC, id),\ - SRI(DSCC_PPS_CONFIG12, DSCC, id),\ - SRI(DSCC_PPS_CONFIG13, DSCC, id),\ - SRI(DSCC_PPS_CONFIG14, DSCC, id),\ - SRI(DSCC_PPS_CONFIG15, DSCC, id),\ - SRI(DSCC_PPS_CONFIG16, DSCC, id),\ - SRI(DSCC_PPS_CONFIG17, DSCC, id),\ - SRI(DSCC_PPS_CONFIG18, DSCC, id),\ - SRI(DSCC_PPS_CONFIG19, DSCC, id),\ - SRI(DSCC_PPS_CONFIG20, DSCC, id),\ - SRI(DSCC_PPS_CONFIG21, DSCC, id),\ - SRI(DSCC_PPS_CONFIG22, DSCC, id),\ - SRI(DSCC_MEM_POWER_CONTROL, DSCC, id),\ - SRI(DSCC_R_Y_SQUARED_ERROR_LOWER, DSCC, id),\ - SRI(DSCC_R_Y_SQUARED_ERROR_UPPER, DSCC, id),\ - SRI(DSCC_G_CB_SQUARED_ERROR_LOWER, DSCC, id),\ - SRI(DSCC_G_CB_SQUARED_ERROR_UPPER, DSCC, id),\ - SRI(DSCC_B_CR_SQUARED_ERROR_LOWER, DSCC, id),\ - SRI(DSCC_B_CR_SQUARED_ERROR_UPPER, DSCC, id),\ - SRI(DSCC_MAX_ABS_ERROR0, DSCC, id),\ - SRI(DSCC_MAX_ABS_ERROR1, DSCC, id),\ - SRI(DSCC_RATE_BUFFER0_MAX_FULLNESS_LEVEL, DSCC, id),\ - SRI(DSCC_RATE_BUFFER1_MAX_FULLNESS_LEVEL, DSCC, id),\ - SRI(DSCC_RATE_BUFFER2_MAX_FULLNESS_LEVEL, DSCC, id),\ - SRI(DSCC_RATE_BUFFER3_MAX_FULLNESS_LEVEL, DSCC, id),\ - SRI(DSCC_RATE_CONTROL_BUFFER0_MAX_FULLNESS_LEVEL, DSCC, id),\ - SRI(DSCC_RATE_CONTROL_BUFFER1_MAX_FULLNESS_LEVEL, DSCC, id),\ - SRI(DSCC_RATE_CONTROL_BUFFER2_MAX_FULLNESS_LEVEL, DSCC, id),\ - SRI(DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL, DSCC, id),\ - SRI(DSCCIF_CONFIG0, DSCCIF, id),\ - SRI(DSCCIF_CONFIG1, DSCCIF, id),\ - SRI(DSCRM_DSC_FORWARD_CONFIG, DSCRM, id) - - -#define DSC_SF(reg_name, field_name, post_fix)\ - .field_name = reg_name ## __ ## field_name ## post_fix - -//Used in resolving the corner case with duplicate field name -#define DSC2_SF(reg_name, field_name, post_fix)\ - .field_name = reg_name ## _ ## field_name ## post_fix - -#define DSC_REG_LIST_SH_MASK_DCN20(mask_sh)\ - DSC_SF(DSC_TOP0_DSC_TOP_CONTROL, DSC_CLOCK_EN, mask_sh), \ - DSC_SF(DSC_TOP0_DSC_TOP_CONTROL, DSC_DISPCLK_R_GATE_DIS, mask_sh), \ - DSC_SF(DSC_TOP0_DSC_TOP_CONTROL, DSC_DSCCLK_R_GATE_DIS, mask_sh), \ - DSC_SF(DSC_TOP0_DSC_DEBUG_CONTROL, DSC_DBG_EN, mask_sh), \ - DSC_SF(DSCC0_DSCC_CONFIG0, ICH_RESET_AT_END_OF_LINE, mask_sh), \ - DSC_SF(DSCC0_DSCC_CONFIG0, NUMBER_OF_SLICES_PER_LINE, mask_sh), \ - DSC_SF(DSCC0_DSCC_CONFIG0, ALTERNATE_ICH_ENCODING_EN, mask_sh), \ - DSC_SF(DSCC0_DSCC_CONFIG0, NUMBER_OF_SLICES_IN_VERTICAL_DIRECTION, mask_sh), \ - DSC_SF(DSCC0_DSCC_CONFIG1, DSCC_RATE_CONTROL_BUFFER_MODEL_SIZE, mask_sh), \ - /*DSC_SF(DSCC0_DSCC_CONFIG1, DSCC_DISABLE_ICH, mask_sh),*/ \ - DSC_SF(DSCC0_DSCC_STATUS, DSCC_DOUBLE_BUFFER_REG_UPDATE_PENDING, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER0_OVERFLOW_OCCURRED, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER1_OVERFLOW_OCCURRED, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER2_OVERFLOW_OCCURRED, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER3_OVERFLOW_OCCURRED, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER0_UNDERFLOW_OCCURRED, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER1_UNDERFLOW_OCCURRED, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER2_UNDERFLOW_OCCURRED, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER3_UNDERFLOW_OCCURRED, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL0_OVERFLOW_OCCURRED, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL1_OVERFLOW_OCCURRED, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL2_OVERFLOW_OCCURRED, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL3_OVERFLOW_OCCURRED, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER0_OVERFLOW_OCCURRED_INT_EN, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER1_OVERFLOW_OCCURRED_INT_EN, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER2_OVERFLOW_OCCURRED_INT_EN, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER3_OVERFLOW_OCCURRED_INT_EN, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER0_UNDERFLOW_OCCURRED_INT_EN, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER1_UNDERFLOW_OCCURRED_INT_EN, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER2_UNDERFLOW_OCCURRED_INT_EN, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER3_UNDERFLOW_OCCURRED_INT_EN, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL0_OVERFLOW_OCCURRED_INT_EN, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL1_OVERFLOW_OCCURRED_INT_EN, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL2_OVERFLOW_OCCURRED_INT_EN, mask_sh), \ - DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL3_OVERFLOW_OCCURRED_INT_EN, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG0, DSC_VERSION_MINOR, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG0, DSC_VERSION_MAJOR, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG0, PPS_IDENTIFIER, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG0, LINEBUF_DEPTH, mask_sh), \ - DSC2_SF(DSCC0, DSCC_PPS_CONFIG0__BITS_PER_COMPONENT, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG1, BITS_PER_PIXEL, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG1, VBR_ENABLE, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG1, SIMPLE_422, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG1, CONVERT_RGB, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG1, BLOCK_PRED_ENABLE, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG1, NATIVE_422, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG1, NATIVE_420, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG1, CHUNK_SIZE, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG2, PIC_WIDTH, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG2, PIC_HEIGHT, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG3, SLICE_WIDTH, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG3, SLICE_HEIGHT, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG4, INITIAL_XMIT_DELAY, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG4, INITIAL_DEC_DELAY, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG5, INITIAL_SCALE_VALUE, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG5, SCALE_INCREMENT_INTERVAL, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG6, SCALE_DECREMENT_INTERVAL, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG6, FIRST_LINE_BPG_OFFSET, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG6, SECOND_LINE_BPG_OFFSET, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG7, NFL_BPG_OFFSET, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG7, SLICE_BPG_OFFSET, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG8, NSL_BPG_OFFSET, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG8, SECOND_LINE_OFFSET_ADJ, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG9, INITIAL_OFFSET, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG9, FINAL_OFFSET, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG10, FLATNESS_MIN_QP, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG10, FLATNESS_MAX_QP, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG10, RC_MODEL_SIZE, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG11, RC_EDGE_FACTOR, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG11, RC_QUANT_INCR_LIMIT0, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG11, RC_QUANT_INCR_LIMIT1, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG11, RC_TGT_OFFSET_LO, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG11, RC_TGT_OFFSET_HI, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG12, RC_BUF_THRESH0, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG12, RC_BUF_THRESH1, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG12, RC_BUF_THRESH2, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG12, RC_BUF_THRESH3, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG13, RC_BUF_THRESH4, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG13, RC_BUF_THRESH5, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG13, RC_BUF_THRESH6, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG13, RC_BUF_THRESH7, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG14, RC_BUF_THRESH8, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG14, RC_BUF_THRESH9, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG14, RC_BUF_THRESH10, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG14, RC_BUF_THRESH11, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG15, RC_BUF_THRESH12, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG15, RC_BUF_THRESH13, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG15, RANGE_MIN_QP0, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG15, RANGE_MAX_QP0, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG15, RANGE_BPG_OFFSET0, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_MIN_QP1, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_MAX_QP1, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_BPG_OFFSET1, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_MIN_QP2, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_MAX_QP2, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_BPG_OFFSET2, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_MIN_QP3, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_MAX_QP3, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_BPG_OFFSET3, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_MIN_QP4, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_MAX_QP4, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_BPG_OFFSET4, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_MIN_QP5, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_MAX_QP5, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_BPG_OFFSET5, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_MIN_QP6, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_MAX_QP6, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_BPG_OFFSET6, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_MIN_QP7, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_MAX_QP7, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_BPG_OFFSET7, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_MIN_QP8, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_MAX_QP8, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_BPG_OFFSET8, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_MIN_QP9, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_MAX_QP9, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_BPG_OFFSET9, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_MIN_QP10, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_MAX_QP10, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_BPG_OFFSET10, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_MIN_QP11, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_MAX_QP11, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_BPG_OFFSET11, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_MIN_QP12, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_MAX_QP12, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_BPG_OFFSET12, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_MIN_QP13, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_MAX_QP13, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_BPG_OFFSET13, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_MIN_QP14, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_MAX_QP14, mask_sh), \ - DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_BPG_OFFSET14, mask_sh), \ - DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_DEFAULT_MEM_LOW_POWER_STATE, mask_sh), \ - DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_MEM_PWR_FORCE, mask_sh), \ - DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_MEM_PWR_DIS, mask_sh), \ - DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_MEM_PWR_STATE, mask_sh), \ - DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_NATIVE_422_MEM_PWR_FORCE, mask_sh), \ - DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_NATIVE_422_MEM_PWR_DIS, mask_sh), \ - DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_NATIVE_422_MEM_PWR_STATE, mask_sh), \ - DSC_SF(DSCC0_DSCC_R_Y_SQUARED_ERROR_LOWER, DSCC_R_Y_SQUARED_ERROR_LOWER, mask_sh), \ - DSC_SF(DSCC0_DSCC_R_Y_SQUARED_ERROR_UPPER, DSCC_R_Y_SQUARED_ERROR_UPPER, mask_sh), \ - DSC_SF(DSCC0_DSCC_G_CB_SQUARED_ERROR_LOWER, DSCC_G_CB_SQUARED_ERROR_LOWER, mask_sh), \ - DSC_SF(DSCC0_DSCC_G_CB_SQUARED_ERROR_UPPER, DSCC_G_CB_SQUARED_ERROR_UPPER, mask_sh), \ - DSC_SF(DSCC0_DSCC_B_CR_SQUARED_ERROR_LOWER, DSCC_B_CR_SQUARED_ERROR_LOWER, mask_sh), \ - DSC_SF(DSCC0_DSCC_B_CR_SQUARED_ERROR_UPPER, DSCC_B_CR_SQUARED_ERROR_UPPER, mask_sh), \ - DSC_SF(DSCC0_DSCC_MAX_ABS_ERROR0, DSCC_R_Y_MAX_ABS_ERROR, mask_sh), \ - DSC_SF(DSCC0_DSCC_MAX_ABS_ERROR0, DSCC_G_CB_MAX_ABS_ERROR, mask_sh), \ - DSC_SF(DSCC0_DSCC_MAX_ABS_ERROR1, DSCC_B_CR_MAX_ABS_ERROR, mask_sh), \ - DSC_SF(DSCC0_DSCC_RATE_BUFFER0_MAX_FULLNESS_LEVEL, DSCC_RATE_BUFFER0_MAX_FULLNESS_LEVEL, mask_sh), \ - DSC_SF(DSCC0_DSCC_RATE_BUFFER1_MAX_FULLNESS_LEVEL, DSCC_RATE_BUFFER1_MAX_FULLNESS_LEVEL, mask_sh), \ - DSC_SF(DSCC0_DSCC_RATE_BUFFER2_MAX_FULLNESS_LEVEL, DSCC_RATE_BUFFER2_MAX_FULLNESS_LEVEL, mask_sh), \ - DSC_SF(DSCC0_DSCC_RATE_BUFFER3_MAX_FULLNESS_LEVEL, DSCC_RATE_BUFFER3_MAX_FULLNESS_LEVEL, mask_sh), \ - DSC_SF(DSCC0_DSCC_RATE_CONTROL_BUFFER0_MAX_FULLNESS_LEVEL, DSCC_RATE_CONTROL_BUFFER0_MAX_FULLNESS_LEVEL, mask_sh), \ - DSC_SF(DSCC0_DSCC_RATE_CONTROL_BUFFER1_MAX_FULLNESS_LEVEL, DSCC_RATE_CONTROL_BUFFER1_MAX_FULLNESS_LEVEL, mask_sh), \ - DSC_SF(DSCC0_DSCC_RATE_CONTROL_BUFFER2_MAX_FULLNESS_LEVEL, DSCC_RATE_CONTROL_BUFFER2_MAX_FULLNESS_LEVEL, mask_sh), \ - DSC_SF(DSCC0_DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL, DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL, mask_sh), \ - DSC_SF(DSCCIF0_DSCCIF_CONFIG0, INPUT_INTERFACE_UNDERFLOW_RECOVERY_EN, mask_sh), \ - DSC_SF(DSCCIF0_DSCCIF_CONFIG0, INPUT_INTERFACE_UNDERFLOW_OCCURRED_INT_EN, mask_sh), \ - DSC_SF(DSCCIF0_DSCCIF_CONFIG0, INPUT_INTERFACE_UNDERFLOW_OCCURRED_STATUS, mask_sh), \ - DSC_SF(DSCCIF0_DSCCIF_CONFIG0, INPUT_PIXEL_FORMAT, mask_sh), \ - DSC2_SF(DSCCIF0, DSCCIF_CONFIG0__BITS_PER_COMPONENT, mask_sh), \ - DSC_SF(DSCCIF0_DSCCIF_CONFIG0, DOUBLE_BUFFER_REG_UPDATE_PENDING, mask_sh), \ - DSC_SF(DSCCIF0_DSCCIF_CONFIG1, PIC_WIDTH, mask_sh), \ - DSC_SF(DSCCIF0_DSCCIF_CONFIG1, PIC_HEIGHT, mask_sh), \ - DSC_SF(DSCRM0_DSCRM_DSC_FORWARD_CONFIG, DSCRM_DSC_FORWARD_EN, mask_sh), \ - DSC_SF(DSCRM0_DSCRM_DSC_FORWARD_CONFIG, DSCRM_DSC_OPP_PIPE_SOURCE, mask_sh) - - - -#define DSC_FIELD_LIST_DCN20(type)\ - type DSC_CLOCK_EN; \ - type DSC_DISPCLK_R_GATE_DIS; \ - type DSC_DSCCLK_R_GATE_DIS; \ - type DSC_DBG_EN; \ - type DSC_TEST_CLOCK_MUX_SEL; \ - type ICH_RESET_AT_END_OF_LINE; \ - type NUMBER_OF_SLICES_PER_LINE; \ - type ALTERNATE_ICH_ENCODING_EN; \ - type NUMBER_OF_SLICES_IN_VERTICAL_DIRECTION; \ - type DSCC_RATE_CONTROL_BUFFER_MODEL_SIZE; \ - /*type DSCC_DISABLE_ICH;*/ \ - type DSCC_DOUBLE_BUFFER_REG_UPDATE_PENDING; \ - type DSCC_RATE_BUFFER0_OVERFLOW_OCCURRED; \ - type DSCC_RATE_BUFFER1_OVERFLOW_OCCURRED; \ - type DSCC_RATE_BUFFER2_OVERFLOW_OCCURRED; \ - type DSCC_RATE_BUFFER3_OVERFLOW_OCCURRED; \ - type DSCC_RATE_BUFFER0_UNDERFLOW_OCCURRED; \ - type DSCC_RATE_BUFFER1_UNDERFLOW_OCCURRED; \ - type DSCC_RATE_BUFFER2_UNDERFLOW_OCCURRED; \ - type DSCC_RATE_BUFFER3_UNDERFLOW_OCCURRED; \ - type DSCC_RATE_CONTROL_BUFFER_MODEL0_OVERFLOW_OCCURRED; \ - type DSCC_RATE_CONTROL_BUFFER_MODEL1_OVERFLOW_OCCURRED; \ - type DSCC_RATE_CONTROL_BUFFER_MODEL2_OVERFLOW_OCCURRED; \ - type DSCC_RATE_CONTROL_BUFFER_MODEL3_OVERFLOW_OCCURRED; \ - type DSCC_RATE_BUFFER0_OVERFLOW_OCCURRED_INT_EN; \ - type DSCC_RATE_BUFFER1_OVERFLOW_OCCURRED_INT_EN; \ - type DSCC_RATE_BUFFER2_OVERFLOW_OCCURRED_INT_EN; \ - type DSCC_RATE_BUFFER3_OVERFLOW_OCCURRED_INT_EN; \ - type DSCC_RATE_BUFFER0_UNDERFLOW_OCCURRED_INT_EN; \ - type DSCC_RATE_BUFFER1_UNDERFLOW_OCCURRED_INT_EN; \ - type DSCC_RATE_BUFFER2_UNDERFLOW_OCCURRED_INT_EN; \ - type DSCC_RATE_BUFFER3_UNDERFLOW_OCCURRED_INT_EN; \ - type DSCC_RATE_CONTROL_BUFFER_MODEL0_OVERFLOW_OCCURRED_INT_EN; \ - type DSCC_RATE_CONTROL_BUFFER_MODEL1_OVERFLOW_OCCURRED_INT_EN; \ - type DSCC_RATE_CONTROL_BUFFER_MODEL2_OVERFLOW_OCCURRED_INT_EN; \ - type DSCC_RATE_CONTROL_BUFFER_MODEL3_OVERFLOW_OCCURRED_INT_EN; \ - type DSC_VERSION_MINOR; \ - type DSC_VERSION_MAJOR; \ - type PPS_IDENTIFIER; \ - type LINEBUF_DEPTH; \ - type DSCC_PPS_CONFIG0__BITS_PER_COMPONENT; \ - type BITS_PER_PIXEL; \ - type VBR_ENABLE; \ - type SIMPLE_422; \ - type CONVERT_RGB; \ - type BLOCK_PRED_ENABLE; \ - type NATIVE_422; \ - type NATIVE_420; \ - type CHUNK_SIZE; \ - type PIC_WIDTH; \ - type PIC_HEIGHT; \ - type SLICE_WIDTH; \ - type SLICE_HEIGHT; \ - type INITIAL_XMIT_DELAY; \ - type INITIAL_DEC_DELAY; \ - type INITIAL_SCALE_VALUE; \ - type SCALE_INCREMENT_INTERVAL; \ - type SCALE_DECREMENT_INTERVAL; \ - type FIRST_LINE_BPG_OFFSET; \ - type SECOND_LINE_BPG_OFFSET; \ - type NFL_BPG_OFFSET; \ - type SLICE_BPG_OFFSET; \ - type NSL_BPG_OFFSET; \ - type SECOND_LINE_OFFSET_ADJ; \ - type INITIAL_OFFSET; \ - type FINAL_OFFSET; \ - type FLATNESS_MIN_QP; \ - type FLATNESS_MAX_QP; \ - type RC_MODEL_SIZE; \ - type RC_EDGE_FACTOR; \ - type RC_QUANT_INCR_LIMIT0; \ - type RC_QUANT_INCR_LIMIT1; \ - type RC_TGT_OFFSET_LO; \ - type RC_TGT_OFFSET_HI; \ - type RC_BUF_THRESH0; \ - type RC_BUF_THRESH1; \ - type RC_BUF_THRESH2; \ - type RC_BUF_THRESH3; \ - type RC_BUF_THRESH4; \ - type RC_BUF_THRESH5; \ - type RC_BUF_THRESH6; \ - type RC_BUF_THRESH7; \ - type RC_BUF_THRESH8; \ - type RC_BUF_THRESH9; \ - type RC_BUF_THRESH10; \ - type RC_BUF_THRESH11; \ - type RC_BUF_THRESH12; \ - type RC_BUF_THRESH13; \ - type RANGE_MIN_QP0; \ - type RANGE_MAX_QP0; \ - type RANGE_BPG_OFFSET0; \ - type RANGE_MIN_QP1; \ - type RANGE_MAX_QP1; \ - type RANGE_BPG_OFFSET1; \ - type RANGE_MIN_QP2; \ - type RANGE_MAX_QP2; \ - type RANGE_BPG_OFFSET2; \ - type RANGE_MIN_QP3; \ - type RANGE_MAX_QP3; \ - type RANGE_BPG_OFFSET3; \ - type RANGE_MIN_QP4; \ - type RANGE_MAX_QP4; \ - type RANGE_BPG_OFFSET4; \ - type RANGE_MIN_QP5; \ - type RANGE_MAX_QP5; \ - type RANGE_BPG_OFFSET5; \ - type RANGE_MIN_QP6; \ - type RANGE_MAX_QP6; \ - type RANGE_BPG_OFFSET6; \ - type RANGE_MIN_QP7; \ - type RANGE_MAX_QP7; \ - type RANGE_BPG_OFFSET7; \ - type RANGE_MIN_QP8; \ - type RANGE_MAX_QP8; \ - type RANGE_BPG_OFFSET8; \ - type RANGE_MIN_QP9; \ - type RANGE_MAX_QP9; \ - type RANGE_BPG_OFFSET9; \ - type RANGE_MIN_QP10; \ - type RANGE_MAX_QP10; \ - type RANGE_BPG_OFFSET10; \ - type RANGE_MIN_QP11; \ - type RANGE_MAX_QP11; \ - type RANGE_BPG_OFFSET11; \ - type RANGE_MIN_QP12; \ - type RANGE_MAX_QP12; \ - type RANGE_BPG_OFFSET12; \ - type RANGE_MIN_QP13; \ - type RANGE_MAX_QP13; \ - type RANGE_BPG_OFFSET13; \ - type RANGE_MIN_QP14; \ - type RANGE_MAX_QP14; \ - type RANGE_BPG_OFFSET14; \ - type DSCC_DEFAULT_MEM_LOW_POWER_STATE; \ - type DSCC_MEM_PWR_FORCE; \ - type DSCC_MEM_PWR_DIS; \ - type DSCC_MEM_PWR_STATE; \ - type DSCC_NATIVE_422_MEM_PWR_FORCE; \ - type DSCC_NATIVE_422_MEM_PWR_DIS; \ - type DSCC_NATIVE_422_MEM_PWR_STATE; \ - type DSCC_R_Y_SQUARED_ERROR_LOWER; \ - type DSCC_R_Y_SQUARED_ERROR_UPPER; \ - type DSCC_G_CB_SQUARED_ERROR_LOWER; \ - type DSCC_G_CB_SQUARED_ERROR_UPPER; \ - type DSCC_B_CR_SQUARED_ERROR_LOWER; \ - type DSCC_B_CR_SQUARED_ERROR_UPPER; \ - type DSCC_R_Y_MAX_ABS_ERROR; \ - type DSCC_G_CB_MAX_ABS_ERROR; \ - type DSCC_B_CR_MAX_ABS_ERROR; \ - type DSCC_RATE_BUFFER0_MAX_FULLNESS_LEVEL; \ - type DSCC_RATE_BUFFER1_MAX_FULLNESS_LEVEL; \ - type DSCC_RATE_BUFFER2_MAX_FULLNESS_LEVEL; \ - type DSCC_RATE_BUFFER3_MAX_FULLNESS_LEVEL; \ - type DSCC_RATE_CONTROL_BUFFER0_MAX_FULLNESS_LEVEL; \ - type DSCC_RATE_CONTROL_BUFFER1_MAX_FULLNESS_LEVEL; \ - type DSCC_RATE_CONTROL_BUFFER2_MAX_FULLNESS_LEVEL; \ - type DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL; \ - type DSCC_UPDATE_PENDING_STATUS; \ - type DSCC_UPDATE_TAKEN_STATUS; \ - type DSCC_UPDATE_TAKEN_ACK; \ - type DSCC_RATE_BUFFER0_FULLNESS_LEVEL; \ - type DSCC_RATE_BUFFER1_FULLNESS_LEVEL; \ - type DSCC_RATE_BUFFER2_FULLNESS_LEVEL; \ - type DSCC_RATE_BUFFER3_FULLNESS_LEVEL; \ - type DSCC_RATE_CONTROL_BUFFER0_FULLNESS_LEVEL; \ - type DSCC_RATE_CONTROL_BUFFER1_FULLNESS_LEVEL; \ - type DSCC_RATE_CONTROL_BUFFER2_FULLNESS_LEVEL; \ - type DSCC_RATE_CONTROL_BUFFER3_FULLNESS_LEVEL; \ - type DSCC_RATE_BUFFER0_INITIAL_XMIT_DELAY_REACHED; \ - type DSCC_RATE_BUFFER1_INITIAL_XMIT_DELAY_REACHED; \ - type DSCC_RATE_BUFFER2_INITIAL_XMIT_DELAY_REACHED; \ - type DSCC_RATE_BUFFER3_INITIAL_XMIT_DELAY_REACHED; \ - type INPUT_INTERFACE_UNDERFLOW_RECOVERY_EN; \ - type INPUT_INTERFACE_UNDERFLOW_OCCURRED_INT_EN; \ - type INPUT_INTERFACE_UNDERFLOW_OCCURRED_STATUS; \ - type INPUT_PIXEL_FORMAT; \ - type DSCCIF_CONFIG0__BITS_PER_COMPONENT; \ - type DOUBLE_BUFFER_REG_UPDATE_PENDING; \ - type DSCCIF_UPDATE_PENDING_STATUS; \ - type DSCCIF_UPDATE_TAKEN_STATUS; \ - type DSCCIF_UPDATE_TAKEN_ACK; \ - type DSCRM_DSC_FORWARD_EN; \ - type DSCRM_DSC_OPP_PIPE_SOURCE - -struct dcn20_dsc_registers { - uint32_t DSC_TOP_CONTROL; - uint32_t DSC_DEBUG_CONTROL; - uint32_t DSCC_CONFIG0; - uint32_t DSCC_CONFIG1; - uint32_t DSCC_STATUS; - uint32_t DSCC_INTERRUPT_CONTROL_STATUS; - uint32_t DSCC_PPS_CONFIG0; - uint32_t DSCC_PPS_CONFIG1; - uint32_t DSCC_PPS_CONFIG2; - uint32_t DSCC_PPS_CONFIG3; - uint32_t DSCC_PPS_CONFIG4; - uint32_t DSCC_PPS_CONFIG5; - uint32_t DSCC_PPS_CONFIG6; - uint32_t DSCC_PPS_CONFIG7; - uint32_t DSCC_PPS_CONFIG8; - uint32_t DSCC_PPS_CONFIG9; - uint32_t DSCC_PPS_CONFIG10; - uint32_t DSCC_PPS_CONFIG11; - uint32_t DSCC_PPS_CONFIG12; - uint32_t DSCC_PPS_CONFIG13; - uint32_t DSCC_PPS_CONFIG14; - uint32_t DSCC_PPS_CONFIG15; - uint32_t DSCC_PPS_CONFIG16; - uint32_t DSCC_PPS_CONFIG17; - uint32_t DSCC_PPS_CONFIG18; - uint32_t DSCC_PPS_CONFIG19; - uint32_t DSCC_PPS_CONFIG20; - uint32_t DSCC_PPS_CONFIG21; - uint32_t DSCC_PPS_CONFIG22; - uint32_t DSCC_MEM_POWER_CONTROL; - uint32_t DSCC_R_Y_SQUARED_ERROR_LOWER; - uint32_t DSCC_R_Y_SQUARED_ERROR_UPPER; - uint32_t DSCC_G_CB_SQUARED_ERROR_LOWER; - uint32_t DSCC_G_CB_SQUARED_ERROR_UPPER; - uint32_t DSCC_B_CR_SQUARED_ERROR_LOWER; - uint32_t DSCC_B_CR_SQUARED_ERROR_UPPER; - uint32_t DSCC_MAX_ABS_ERROR0; - uint32_t DSCC_MAX_ABS_ERROR1; - uint32_t DSCC_RATE_BUFFER0_MAX_FULLNESS_LEVEL; - uint32_t DSCC_RATE_BUFFER1_MAX_FULLNESS_LEVEL; - uint32_t DSCC_RATE_BUFFER2_MAX_FULLNESS_LEVEL; - uint32_t DSCC_RATE_BUFFER3_MAX_FULLNESS_LEVEL; - uint32_t DSCC_RATE_CONTROL_BUFFER0_MAX_FULLNESS_LEVEL; - uint32_t DSCC_RATE_CONTROL_BUFFER1_MAX_FULLNESS_LEVEL; - uint32_t DSCC_RATE_CONTROL_BUFFER2_MAX_FULLNESS_LEVEL; - uint32_t DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL; - uint32_t DSCCIF_CONFIG0; - uint32_t DSCCIF_CONFIG1; - uint32_t DSCRM_DSC_FORWARD_CONFIG; -}; - - -struct dcn20_dsc_shift { - DSC_FIELD_LIST_DCN20(uint8_t); -}; - -struct dcn20_dsc_mask { - DSC_FIELD_LIST_DCN20(uint32_t); -}; - -/* DSCCIF_CONFIG.INPUT_PIXEL_FORMAT values */ -enum dsc_pixel_format { - DSC_PIXFMT_RGB, - DSC_PIXFMT_YCBCR444, - DSC_PIXFMT_SIMPLE_YCBCR422, - DSC_PIXFMT_NATIVE_YCBCR422, - DSC_PIXFMT_NATIVE_YCBCR420, - DSC_PIXFMT_UNKNOWN -}; - -struct dsc_reg_values { - /* PPS registers */ - struct drm_dsc_config pps; - - /* Additional registers */ - uint32_t dsc_clock_enable; - uint32_t dsc_clock_gating_disable; - uint32_t underflow_recovery_en; - uint32_t underflow_occurred_int_en; - uint32_t underflow_occurred_status; - enum dsc_pixel_format pixel_format; - uint32_t ich_reset_at_eol; - uint32_t alternate_ich_encoding_en; - uint32_t num_slices_h; - uint32_t num_slices_v; - uint32_t rc_buffer_model_size; - uint32_t disable_ich; - uint32_t bpp_x32; - uint32_t dsc_dbg_en; - uint32_t rc_buffer_model_overflow_int_en[4]; -}; - -struct dcn20_dsc { - struct display_stream_compressor base; - const struct dcn20_dsc_registers *dsc_regs; - const struct dcn20_dsc_shift *dsc_shift; - const struct dcn20_dsc_mask *dsc_mask; - - struct dsc_reg_values reg_vals; - - int max_image_width; -}; - -void dsc_config_log(struct display_stream_compressor *dsc, - const struct dsc_config *config); - -void dsc_log_pps(struct display_stream_compressor *dsc, - struct drm_dsc_config *pps); - -void dsc_override_rc_params(struct rc_params *rc, - const struct dc_dsc_rc_params_override *override); - -bool dsc_prepare_config(const struct dsc_config *dsc_cfg, - struct dsc_reg_values *dsc_reg_vals, - struct dsc_optc_config *dsc_optc_cfg); - -enum dsc_pixel_format dsc_dc_pixel_encoding_to_dsc_pixel_format(enum dc_pixel_encoding dc_pix_enc, - bool is_ycbcr422_simple); - -enum dsc_bits_per_comp dsc_dc_color_depth_to_dsc_bits_per_comp(enum dc_color_depth dc_color_depth); - -void dsc_init_reg_values(struct dsc_reg_values *reg_vals); - -void dsc_update_from_dsc_parameters(struct dsc_reg_values *reg_vals, const struct dsc_parameters *dsc_params); - -void dsc2_construct(struct dcn20_dsc *dsc, - struct dc_context *ctx, - int inst, - const struct dcn20_dsc_registers *dsc_regs, - const struct dcn20_dsc_shift *dsc_shift, - const struct dcn20_dsc_mask *dsc_mask); - -void dsc2_get_enc_caps(struct dsc_enc_caps *dsc_enc_caps, - int pixel_clock_100Hz); - -bool dsc2_get_packed_pps(struct display_stream_compressor *dsc, - const struct dsc_config *dsc_cfg, - uint8_t *dsc_packed_pps); - -#endif - diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c deleted file mode 100644 index 884e3e32333808..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2016 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 "dce110/dce110_hwseq.h" -#include "dcn10/dcn10_hwseq.h" -#include "dcn20/dcn20_hwseq.h" - -#include "dcn20_init.h" - -static const struct hw_sequencer_funcs dcn20_funcs = { - .program_gamut_remap = dcn10_program_gamut_remap, - .init_hw = dcn10_init_hw, - .power_down_on_boot = dcn10_power_down_on_boot, - .apply_ctx_to_hw = dce110_apply_ctx_to_hw, - .apply_ctx_for_surface = NULL, - .program_front_end_for_ctx = dcn20_program_front_end_for_ctx, - .wait_for_pending_cleared = dcn10_wait_for_pending_cleared, - .post_unlock_program_front_end = dcn20_post_unlock_program_front_end, - .update_plane_addr = dcn20_update_plane_addr, - .update_dchub = dcn10_update_dchub, - .update_pending_status = dcn10_update_pending_status, - .program_output_csc = dcn20_program_output_csc, - .enable_accelerated_mode = dce110_enable_accelerated_mode, - .enable_timing_synchronization = dcn10_enable_timing_synchronization, - .enable_vblanks_synchronization = dcn10_enable_vblanks_synchronization, - .enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset, - .update_info_frame = dce110_update_info_frame, - .send_immediate_sdp_message = dcn10_send_immediate_sdp_message, - .enable_stream = dcn20_enable_stream, - .disable_stream = dce110_disable_stream, - .unblank_stream = dcn20_unblank_stream, - .blank_stream = dce110_blank_stream, - .enable_audio_stream = dce110_enable_audio_stream, - .disable_audio_stream = dce110_disable_audio_stream, - .disable_plane = dcn20_disable_plane, - .pipe_control_lock = dcn20_pipe_control_lock, - .interdependent_update_lock = dcn10_lock_all_pipes, - .cursor_lock = dcn10_cursor_lock, - .prepare_bandwidth = dcn20_prepare_bandwidth, - .optimize_bandwidth = dcn20_optimize_bandwidth, - .update_bandwidth = dcn20_update_bandwidth, - .set_drr = dcn10_set_drr, - .get_position = dcn10_get_position, - .set_static_screen_control = dcn10_set_static_screen_control, - .setup_stereo = dcn10_setup_stereo, - .set_avmute = dce110_set_avmute, - .log_hw_state = dcn10_log_hw_state, - .get_hw_state = dcn10_get_hw_state, - .clear_status_bits = dcn10_clear_status_bits, - .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, - .edp_backlight_control = dce110_edp_backlight_control, - .edp_power_control = dce110_edp_power_control, - .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, - .set_cursor_position = dcn10_set_cursor_position, - .set_cursor_attribute = dcn10_set_cursor_attribute, - .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level, - .setup_periodic_interrupt = dcn10_setup_periodic_interrupt, - .set_clock = dcn10_set_clock, - .get_clock = dcn10_get_clock, - .program_triplebuffer = dcn20_program_triple_buffer, - .enable_writeback = dcn20_enable_writeback, - .disable_writeback = dcn20_disable_writeback, - .dmdata_status_done = dcn20_dmdata_status_done, - .program_dmdata_engine = dcn20_program_dmdata_engine, - .set_dmdata_attributes = dcn20_set_dmdata_attributes, - .init_sys_ctx = dcn20_init_sys_ctx, - .init_vm_ctx = dcn20_init_vm_ctx, - .set_flip_control_gsl = dcn20_set_flip_control_gsl, - .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync, - .calc_vupdate_position = dcn10_calc_vupdate_position, - .set_backlight_level = dce110_set_backlight_level, - .set_abm_immediate_disable = dce110_set_abm_immediate_disable, - .set_pipe = dce110_set_pipe, - .enable_lvds_link_output = dce110_enable_lvds_link_output, - .enable_tmds_link_output = dce110_enable_tmds_link_output, - .enable_dp_link_output = dce110_enable_dp_link_output, - .disable_link_output = dce110_disable_link_output, - .set_disp_pattern_generator = dcn20_set_disp_pattern_generator, - .get_dcc_en_bits = dcn10_get_dcc_en_bits, - .update_visual_confirm_color = dcn10_update_visual_confirm_color, -}; - -static const struct hwseq_private_funcs dcn20_private_funcs = { - .init_pipes = dcn10_init_pipes, - .update_plane_addr = dcn20_update_plane_addr, - .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, - .update_mpcc = dcn20_update_mpcc, - .set_input_transfer_func = dcn20_set_input_transfer_func, - .set_output_transfer_func = dcn20_set_output_transfer_func, - .power_down = dce110_power_down, - .enable_display_power_gating = dcn10_dummy_display_power_gating, - .blank_pixel_data = dcn20_blank_pixel_data, - .reset_hw_ctx_wrap = dcn20_reset_hw_ctx_wrap, - .enable_stream_timing = dcn20_enable_stream_timing, - .edp_backlight_control = dce110_edp_backlight_control, - .disable_stream_gating = dcn20_disable_stream_gating, - .enable_stream_gating = dcn20_enable_stream_gating, - .setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt, - .did_underflow_occur = dcn10_did_underflow_occur, - .init_blank = dcn20_init_blank, - .disable_vga = dcn20_disable_vga, - .bios_golden_init = dcn10_bios_golden_init, - .plane_atomic_disable = dcn20_plane_atomic_disable, - .plane_atomic_power_down = dcn10_plane_atomic_power_down, - .enable_power_gating_plane = dcn20_enable_power_gating_plane, - .dpp_pg_control = dcn20_dpp_pg_control, - .hubp_pg_control = dcn20_hubp_pg_control, - .update_odm = dcn20_update_odm, - .dsc_pg_control = dcn20_dsc_pg_control, - .set_hdr_multiplier = dcn10_set_hdr_multiplier, - .verify_allow_pstate_change_high = dcn10_verify_allow_pstate_change_high, - .wait_for_blank_complete = dcn20_wait_for_blank_complete, - .dccg_init = dcn20_dccg_init, - .set_blend_lut = dcn20_set_blend_lut, - .set_shaper_3dlut = dcn20_set_shaper_3dlut, -}; - -void dcn20_hw_sequencer_construct(struct dc *dc) -{ - dc->hwss = dcn20_funcs; - dc->hwseq->funcs = dcn20_private_funcs; - -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.h deleted file mode 100644 index 12277797cd7106..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_init.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2016 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_DCN20_INIT_H__ -#define __DC_DCN20_INIT_H__ - -struct dc; - -void dcn20_hw_sequencer_construct(struct dc *dc); - -#endif /* __DC_DCN20_INIT_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c deleted file mode 100644 index 58bdbd859bf9b0..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c +++ /dev/null @@ -1,587 +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 - * - */ - -#include "reg_helper.h" -#include "dcn20_optc.h" -#include "dc.h" - -#define REG(reg)\ - optc1->tg_regs->reg - -#define CTX \ - optc1->base.ctx - -#undef FN -#define FN(reg_name, field_name) \ - optc1->tg_shift->field_name, optc1->tg_mask->field_name - -/** - * optc2_enable_crtc() - Enable CRTC - call ASIC Control Object to enable Timing generator. - * - * @optc: timing_generator instance. - * - * Return: If CRTC is enabled, return true. - * - */ -bool optc2_enable_crtc(struct timing_generator *optc) -{ - /* TODO FPGA wait for answer - * OTG_MASTER_UPDATE_MODE != CRTC_MASTER_UPDATE_MODE - * OTG_MASTER_UPDATE_LOCK != CRTC_MASTER_UPDATE_LOCK - */ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - /* opp instance for OTG. For DCN1.0, ODM is remoed. - * OPP and OPTC should 1:1 mapping - */ - REG_UPDATE(OPTC_DATA_SOURCE_SELECT, - OPTC_SEG0_SRC_SEL, optc->inst); - - /* VTG enable first is for HW workaround */ - REG_UPDATE(CONTROL, - VTG0_ENABLE, 1); - - REG_SEQ_START(); - - /* Enable CRTC */ - REG_UPDATE_2(OTG_CONTROL, - OTG_DISABLE_POINT_CNTL, 3, - OTG_MASTER_EN, 1); - - REG_SEQ_SUBMIT(); - REG_SEQ_WAIT_DONE(); - - return true; -} - -/** - * optc2_set_gsl() - Assign OTG to GSL groups, - * set one of the OTGs to be master & rest are slaves - * - * @optc: timing_generator instance. - * @params: pointer to gsl_params - */ -void optc2_set_gsl(struct timing_generator *optc, - const struct gsl_params *params) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - -/* - * There are (MAX_OPTC+1)/2 gsl groups available for use. - * In each group (assign an OTG to a group by setting OTG_GSLX_EN = 1, - * set one of the OTGs to be the master (OTG_GSL_MASTER_EN = 1) and the rest are slaves. - */ - REG_UPDATE_5(OTG_GSL_CONTROL, - OTG_GSL0_EN, params->gsl0_en, - OTG_GSL1_EN, params->gsl1_en, - OTG_GSL2_EN, params->gsl2_en, - OTG_GSL_MASTER_EN, params->gsl_master_en, - OTG_GSL_MASTER_MODE, params->gsl_master_mode); -} - - -void optc2_set_gsl_source_select( - struct timing_generator *optc, - int group_idx, - uint32_t gsl_ready_signal) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - switch (group_idx) { - case 1: - REG_UPDATE(GSL_SOURCE_SELECT, GSL0_READY_SOURCE_SEL, gsl_ready_signal); - break; - case 2: - REG_UPDATE(GSL_SOURCE_SELECT, GSL1_READY_SOURCE_SEL, gsl_ready_signal); - break; - case 3: - REG_UPDATE(GSL_SOURCE_SELECT, GSL2_READY_SOURCE_SEL, gsl_ready_signal); - break; - default: - break; - } -} - -/* Set DSC-related configuration. - * dsc_mode: 0 disables DSC, other values enable DSC in specified format - * sc_bytes_per_pixel: Bytes per pixel in u3.28 format - * dsc_slice_width: Slice width in pixels - */ -void optc2_set_dsc_config(struct timing_generator *optc, - enum optc_dsc_mode dsc_mode, - uint32_t dsc_bytes_per_pixel, - uint32_t dsc_slice_width) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_UPDATE(OPTC_DATA_FORMAT_CONTROL, - OPTC_DSC_MODE, dsc_mode); - - REG_SET(OPTC_BYTES_PER_PIXEL, 0, - OPTC_DSC_BYTES_PER_PIXEL, dsc_bytes_per_pixel); - - REG_UPDATE(OPTC_WIDTH_CONTROL, - OPTC_DSC_SLICE_WIDTH, dsc_slice_width); -} - -/* Get DSC-related configuration. - * dsc_mode: 0 disables DSC, other values enable DSC in specified format - */ -void optc2_get_dsc_status(struct timing_generator *optc, - uint32_t *dsc_mode) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_GET(OPTC_DATA_FORMAT_CONTROL, - OPTC_DSC_MODE, dsc_mode); -} - - -/*TEMP: Need to figure out inheritance model here.*/ -bool optc2_is_two_pixels_per_containter(const struct dc_crtc_timing *timing) -{ - return optc1_is_two_pixels_per_containter(timing); -} - -void optc2_set_odm_bypass(struct timing_generator *optc, - const struct dc_crtc_timing *dc_crtc_timing) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - uint32_t h_div_2 = 0; - - REG_SET_3(OPTC_DATA_SOURCE_SELECT, 0, - OPTC_NUM_OF_INPUT_SEGMENT, 0, - OPTC_SEG0_SRC_SEL, optc->inst, - OPTC_SEG1_SRC_SEL, 0xf); - REG_WRITE(OTG_H_TIMING_CNTL, 0); - - h_div_2 = optc2_is_two_pixels_per_containter(dc_crtc_timing); - REG_UPDATE(OTG_H_TIMING_CNTL, - OTG_H_TIMING_DIV_BY2, h_div_2); - REG_SET(OPTC_MEMORY_CONFIG, 0, - OPTC_MEM_SEL, 0); - optc1->opp_count = 1; -} - -void optc2_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, - struct dc_crtc_timing *timing) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - int mpcc_hactive = (timing->h_addressable + timing->h_border_left + timing->h_border_right) - / opp_cnt; - uint32_t memory_mask; - - ASSERT(opp_cnt == 2); - - /* TODO: In pseudocode but does not affect maximus, delete comment if we dont need on asic - * REG_SET(OTG_GLOBAL_CONTROL2, 0, GLOBAL_UPDATE_LOCK_EN, 1); - * Program OTG register MASTER_UPDATE_LOCK_DB_X/Y to the position before DP frame start - * REG_SET_2(OTG_GLOBAL_CONTROL1, 0, - * MASTER_UPDATE_LOCK_DB_X, 160, - * MASTER_UPDATE_LOCK_DB_Y, 240); - */ - - /* 2 pieces of memory required for up to 5120 displays, 4 for up to 8192, - * however, for ODM combine we can simplify by always using 4. - * To make sure there's no overlap, each instance "reserves" 2 memories and - * they are uniquely combined here. - */ - memory_mask = 0x3 << (opp_id[0] * 2) | 0x3 << (opp_id[1] * 2); - - if (REG(OPTC_MEMORY_CONFIG)) - REG_SET(OPTC_MEMORY_CONFIG, 0, - OPTC_MEM_SEL, memory_mask); - - REG_SET_3(OPTC_DATA_SOURCE_SELECT, 0, - OPTC_NUM_OF_INPUT_SEGMENT, 1, - OPTC_SEG0_SRC_SEL, opp_id[0], - OPTC_SEG1_SRC_SEL, opp_id[1]); - - REG_UPDATE(OPTC_WIDTH_CONTROL, - OPTC_SEGMENT_WIDTH, mpcc_hactive); - - REG_SET(OTG_H_TIMING_CNTL, 0, OTG_H_TIMING_DIV_BY2, 1); - optc1->opp_count = opp_cnt; -} - -void optc2_get_optc_source(struct timing_generator *optc, - uint32_t *num_of_src_opp, - uint32_t *src_opp_id_0, - uint32_t *src_opp_id_1) -{ - uint32_t num_of_input_segments; - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_GET_3(OPTC_DATA_SOURCE_SELECT, - OPTC_NUM_OF_INPUT_SEGMENT, &num_of_input_segments, - OPTC_SEG0_SRC_SEL, src_opp_id_0, - OPTC_SEG1_SRC_SEL, src_opp_id_1); - - if (num_of_input_segments == 1) - *num_of_src_opp = 2; - else - *num_of_src_opp = 1; - - /* Work around VBIOS not updating OPTC_NUM_OF_INPUT_SEGMENT */ - if (*src_opp_id_1 == 0xf) - *num_of_src_opp = 1; -} - -static void optc2_set_dwb_source(struct timing_generator *optc, - uint32_t dwb_pipe_inst) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - if (dwb_pipe_inst == 0) - REG_UPDATE(DWB_SOURCE_SELECT, - OPTC_DWB0_SOURCE_SELECT, optc->inst); - else if (dwb_pipe_inst == 1) - REG_UPDATE(DWB_SOURCE_SELECT, - OPTC_DWB1_SOURCE_SELECT, optc->inst); -} - -static void optc2_align_vblanks( - struct timing_generator *optc_master, - struct timing_generator *optc_slave, - uint32_t master_pixel_clock_100Hz, - uint32_t slave_pixel_clock_100Hz, - uint8_t master_clock_divider, - uint8_t slave_clock_divider) -{ - /* accessing slave OTG registers */ - struct optc *optc1 = DCN10TG_FROM_TG(optc_slave); - - uint32_t master_v_active = 0; - uint32_t master_h_total = 0; - uint32_t slave_h_total = 0; - uint64_t L, XY; - uint32_t X, Y, p = 10000; - uint32_t master_update_lock; - - /* disable slave OTG */ - REG_UPDATE(OTG_CONTROL, OTG_MASTER_EN, 0); - /* wait until disabled */ - REG_WAIT(OTG_CONTROL, - OTG_CURRENT_MASTER_EN_STATE, - 0, 10, 5000); - - REG_GET(OTG_H_TOTAL, OTG_H_TOTAL, &slave_h_total); - - /* assign slave OTG to be controlled by master update lock */ - REG_SET(OTG_GLOBAL_CONTROL0, 0, - OTG_MASTER_UPDATE_LOCK_SEL, optc_master->inst); - - /* accessing master OTG registers */ - optc1 = DCN10TG_FROM_TG(optc_master); - - /* saving update lock state, not sure if it's needed */ - REG_GET(OTG_MASTER_UPDATE_LOCK, - OTG_MASTER_UPDATE_LOCK, &master_update_lock); - /* unlocking master OTG */ - REG_SET(OTG_MASTER_UPDATE_LOCK, 0, - OTG_MASTER_UPDATE_LOCK, 0); - - REG_GET(OTG_V_BLANK_START_END, - OTG_V_BLANK_START, &master_v_active); - REG_GET(OTG_H_TOTAL, OTG_H_TOTAL, &master_h_total); - - /* calculate when to enable slave OTG */ - L = (uint64_t)p * slave_h_total * master_pixel_clock_100Hz; - L = div_u64(L, master_h_total); - L = div_u64(L, slave_pixel_clock_100Hz); - XY = div_u64(L, p); - Y = master_v_active - XY - 1; - X = div_u64(((XY + 1) * p - L) * master_h_total, p * master_clock_divider); - - /* - * set master OTG to unlock when V/H - * counters reach calculated values - */ - REG_UPDATE(OTG_GLOBAL_CONTROL1, - MASTER_UPDATE_LOCK_DB_EN, 1); - REG_UPDATE_2(OTG_GLOBAL_CONTROL1, - MASTER_UPDATE_LOCK_DB_X, - X, - MASTER_UPDATE_LOCK_DB_Y, - Y); - - /* lock master OTG */ - REG_SET(OTG_MASTER_UPDATE_LOCK, 0, - OTG_MASTER_UPDATE_LOCK, 1); - REG_WAIT(OTG_MASTER_UPDATE_LOCK, - UPDATE_LOCK_STATUS, 1, 1, 10); - - /* accessing slave OTG registers */ - optc1 = DCN10TG_FROM_TG(optc_slave); - - /* - * enable slave OTG, the OTG is locked with - * master's update lock, so it will not run - */ - REG_UPDATE(OTG_CONTROL, - OTG_MASTER_EN, 1); - - /* accessing master OTG registers */ - optc1 = DCN10TG_FROM_TG(optc_master); - - /* - * unlock master OTG. When master H/V counters reach - * DB_XY point, slave OTG will start - */ - REG_SET(OTG_MASTER_UPDATE_LOCK, 0, - OTG_MASTER_UPDATE_LOCK, 0); - - /* accessing slave OTG registers */ - optc1 = DCN10TG_FROM_TG(optc_slave); - - /* wait for slave OTG to start running*/ - REG_WAIT(OTG_CONTROL, - OTG_CURRENT_MASTER_EN_STATE, - 1, 10, 5000); - - /* accessing master OTG registers */ - optc1 = DCN10TG_FROM_TG(optc_master); - - /* disable the XY point*/ - REG_UPDATE(OTG_GLOBAL_CONTROL1, - MASTER_UPDATE_LOCK_DB_EN, 0); - REG_UPDATE_2(OTG_GLOBAL_CONTROL1, - MASTER_UPDATE_LOCK_DB_X, - 0, - MASTER_UPDATE_LOCK_DB_Y, - 0); - - /*restore master update lock*/ - REG_SET(OTG_MASTER_UPDATE_LOCK, 0, - OTG_MASTER_UPDATE_LOCK, master_update_lock); - - /* accessing slave OTG registers */ - optc1 = DCN10TG_FROM_TG(optc_slave); - /* restore slave to be controlled by it's own */ - REG_SET(OTG_GLOBAL_CONTROL0, 0, - OTG_MASTER_UPDATE_LOCK_SEL, optc_slave->inst); - -} - -void optc2_triplebuffer_lock(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_SET(OTG_GLOBAL_CONTROL0, 0, - OTG_MASTER_UPDATE_LOCK_SEL, optc->inst); - - REG_SET(OTG_VUPDATE_KEEPOUT, 0, - OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, 1); - - REG_SET(OTG_MASTER_UPDATE_LOCK, 0, - OTG_MASTER_UPDATE_LOCK, 1); - - REG_WAIT(OTG_MASTER_UPDATE_LOCK, - UPDATE_LOCK_STATUS, 1, - 1, 10); -} - -void optc2_triplebuffer_unlock(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_SET(OTG_MASTER_UPDATE_LOCK, 0, - OTG_MASTER_UPDATE_LOCK, 0); - - REG_SET(OTG_VUPDATE_KEEPOUT, 0, - OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, 0); - -} - -void optc2_lock_doublebuffer_enable(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - uint32_t v_blank_start = 0; - uint32_t h_blank_start = 0; - - REG_UPDATE(OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_EN, 1); - - REG_UPDATE_2(OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, 1, - DIG_UPDATE_LOCATION, 20); - - REG_GET(OTG_V_BLANK_START_END, OTG_V_BLANK_START, &v_blank_start); - - REG_GET(OTG_H_BLANK_START_END, OTG_H_BLANK_START, &h_blank_start); - - REG_UPDATE_2(OTG_GLOBAL_CONTROL1, - MASTER_UPDATE_LOCK_DB_X, - (h_blank_start - 200 - 1) / optc1->opp_count, - MASTER_UPDATE_LOCK_DB_Y, - v_blank_start - 1); - - REG_SET_3(OTG_VUPDATE_KEEPOUT, 0, - MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET, 0, - MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET, 100, - OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, 1); -} - -void optc2_lock_doublebuffer_disable(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_UPDATE_2(OTG_GLOBAL_CONTROL1, - MASTER_UPDATE_LOCK_DB_X, - 0, - MASTER_UPDATE_LOCK_DB_Y, - 0); - - REG_UPDATE_2(OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, 0, - DIG_UPDATE_LOCATION, 0); - - REG_UPDATE(OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_EN, 0); -} - -void optc2_setup_manual_trigger(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - /* Set the min/max selectors unconditionally so that - * DMCUB fw may change OTG timings when necessary - * TODO: Remove the w/a after fixing the issue in DMCUB firmware - */ - REG_UPDATE_4(OTG_V_TOTAL_CONTROL, - OTG_V_TOTAL_MIN_SEL, 1, - OTG_V_TOTAL_MAX_SEL, 1, - OTG_FORCE_LOCK_ON_EVENT, 0, - OTG_SET_V_TOTAL_MIN_MASK, (1 << 1)); /* TRIGA */ - - REG_SET_8(OTG_TRIGA_CNTL, 0, - OTG_TRIGA_SOURCE_SELECT, 21, - OTG_TRIGA_SOURCE_PIPE_SELECT, optc->inst, - OTG_TRIGA_RISING_EDGE_DETECT_CNTL, 1, - OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, 0, - OTG_TRIGA_POLARITY_SELECT, 0, - OTG_TRIGA_FREQUENCY_SELECT, 0, - OTG_TRIGA_DELAY, 0, - OTG_TRIGA_CLEAR, 1); -} - -void optc2_program_manual_trigger(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_SET(OTG_TRIGA_MANUAL_TRIG, 0, - OTG_TRIGA_MANUAL_TRIG, 1); -} - -bool optc2_configure_crc(struct timing_generator *optc, - const struct crc_params *params) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_SET_2(OTG_CRC_CNTL2, 0, - OTG_CRC_DSC_MODE, params->dsc_mode, - OTG_CRC_DATA_STREAM_COMBINE_MODE, params->odm_mode); - - return optc1_configure_crc(optc, params); -} - - -void optc2_get_last_used_drr_vtotal(struct timing_generator *optc, uint32_t *refresh_rate) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_GET(OTG_DRR_CONTROL, OTG_V_TOTAL_LAST_USED_BY_DRR, refresh_rate); -} - -static struct timing_generator_funcs dcn20_tg_funcs = { - .validate_timing = optc1_validate_timing, - .program_timing = optc1_program_timing, - .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0, - .setup_vertical_interrupt1 = optc1_setup_vertical_interrupt1, - .setup_vertical_interrupt2 = optc1_setup_vertical_interrupt2, - .program_global_sync = optc1_program_global_sync, - .enable_crtc = optc2_enable_crtc, - .disable_crtc = optc1_disable_crtc, - /* used by enable_timing_synchronization. Not need for FPGA */ - .is_counter_moving = optc1_is_counter_moving, - .get_position = optc1_get_position, - .get_frame_count = optc1_get_vblank_counter, - .get_scanoutpos = optc1_get_crtc_scanoutpos, - .get_otg_active_size = optc1_get_otg_active_size, - .set_early_control = optc1_set_early_control, - /* used by enable_timing_synchronization. Not need for FPGA */ - .wait_for_state = optc1_wait_for_state, - .set_blank = optc1_set_blank, - .is_blanked = optc1_is_blanked, - .set_blank_color = optc1_program_blank_color, - .enable_reset_trigger = optc1_enable_reset_trigger, - .enable_crtc_reset = optc1_enable_crtc_reset, - .did_triggered_reset_occur = optc1_did_triggered_reset_occur, - .triplebuffer_lock = optc2_triplebuffer_lock, - .triplebuffer_unlock = optc2_triplebuffer_unlock, - .disable_reset_trigger = optc1_disable_reset_trigger, - .lock = optc1_lock, - .unlock = optc1_unlock, - .lock_doublebuffer_enable = optc2_lock_doublebuffer_enable, - .lock_doublebuffer_disable = optc2_lock_doublebuffer_disable, - .enable_optc_clock = optc1_enable_optc_clock, - .set_drr = optc1_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 = optc1_set_static_screen_control, - .program_stereo = optc1_program_stereo, - .is_stereo_left_eye = optc1_is_stereo_left_eye, - .set_blank_data_double_buffer = optc1_set_blank_data_double_buffer, - .tg_init = optc1_tg_init, - .is_tg_enabled = optc1_is_tg_enabled, - .is_optc_underflow_occurred = optc1_is_optc_underflow_occurred, - .clear_optc_underflow = optc1_clear_optc_underflow, - .setup_global_swap_lock = NULL, - .get_crc = optc1_get_crc, - .configure_crc = optc2_configure_crc, - .set_dsc_config = optc2_set_dsc_config, - .get_dsc_status = optc2_get_dsc_status, - .set_dwb_source = optc2_set_dwb_source, - .set_odm_bypass = optc2_set_odm_bypass, - .set_odm_combine = optc2_set_odm_combine, - .get_optc_source = optc2_get_optc_source, - .set_gsl = optc2_set_gsl, - .set_gsl_source_select = optc2_set_gsl_source_select, - .set_vtg_params = optc1_set_vtg_params, - .program_manual_trigger = optc2_program_manual_trigger, - .setup_manual_trigger = optc2_setup_manual_trigger, - .get_hw_timing = optc1_get_hw_timing, - .align_vblanks = optc2_align_vblanks, -}; - -void dcn20_timing_generator_init(struct optc *optc1) -{ - optc1->base.funcs = &dcn20_tg_funcs; - - optc1->max_h_total = optc1->tg_mask->OTG_H_TOTAL + 1; - optc1->max_v_total = optc1->tg_mask->OTG_V_TOTAL + 1; - - optc1->min_h_blank = 32; - optc1->min_v_blank = 3; - optc1->min_v_blank_interlace = 5; - optc1->min_h_sync_width = 4;// Minimum HSYNC = 8 pixels asked By HW in the first place for no actual reason. Oculus Rift S will not light up with 8 as it's hsyncWidth is 6. Changing it to 4 to fix that issue. - optc1->min_v_sync_width = 1; -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h deleted file mode 100644 index f7968b9ca16eb4..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h +++ /dev/null @@ -1,124 +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 __DC_OPTC_DCN20_H__ -#define __DC_OPTC_DCN20_H__ - -#include "../dcn10/dcn10_optc.h" - -#define TG_COMMON_REG_LIST_DCN2_0(inst) \ - TG_COMMON_REG_LIST_DCN(inst),\ - SRI(OTG_GLOBAL_CONTROL1, OTG, inst),\ - SRI(OTG_GLOBAL_CONTROL2, OTG, inst),\ - SRI(OTG_GSL_WINDOW_X, OTG, inst),\ - SRI(OTG_GSL_WINDOW_Y, OTG, inst),\ - SRI(OTG_VUPDATE_KEEPOUT, OTG, inst),\ - SRI(OTG_DSC_START_POSITION, OTG, inst),\ - SRI(OTG_CRC_CNTL2, OTG, inst),\ - SRI(OPTC_DATA_FORMAT_CONTROL, ODM, inst),\ - SRI(OPTC_BYTES_PER_PIXEL, ODM, inst),\ - SRI(OPTC_WIDTH_CONTROL, ODM, inst),\ - SRI(OPTC_MEMORY_CONFIG, ODM, inst),\ - SR(DWB_SOURCE_SELECT),\ - SRI(OTG_MANUAL_FLOW_CONTROL, OTG, inst), \ - SRI(OTG_DRR_CONTROL, OTG, inst) - -#define TG_COMMON_MASK_SH_LIST_DCN2_0(mask_sh)\ - TG_COMMON_MASK_SH_LIST_DCN(mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_X, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_Y, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_EN, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL2, DIG_UPDATE_LOCATION, mask_sh),\ - SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_RANGE_TIMING_DBUF_UPDATE_MODE, mask_sh),\ - SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_START_X, mask_sh),\ - SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_END_X, mask_sh), \ - SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_START_Y, mask_sh),\ - SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_END_Y, mask_sh),\ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_MASTER_MODE, mask_sh), \ - SF(OTG0_OTG_GSL_CONTROL, OTG_MASTER_UPDATE_LOCK_GSL_EN, mask_sh), \ - SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_X, mask_sh), \ - SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_LINE_NUM, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DSC_MODE, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_STREAM_COMBINE_MODE, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_STREAM_SPLIT_MODE, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_FORMAT, mask_sh),\ - SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG0_SRC_SEL, mask_sh),\ - SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG1_SRC_SEL, mask_sh),\ - SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_NUM_OF_INPUT_SEGMENT, mask_sh),\ - SF(ODM0_OPTC_MEMORY_CONFIG, OPTC_MEM_SEL, mask_sh),\ - SF(ODM0_OPTC_DATA_FORMAT_CONTROL, OPTC_DATA_FORMAT, mask_sh),\ - SF(ODM0_OPTC_DATA_FORMAT_CONTROL, OPTC_DSC_MODE, mask_sh),\ - SF(ODM0_OPTC_BYTES_PER_PIXEL, OPTC_DSC_BYTES_PER_PIXEL, mask_sh),\ - SF(ODM0_OPTC_WIDTH_CONTROL, OPTC_DSC_SLICE_WIDTH, mask_sh),\ - SF(ODM0_OPTC_WIDTH_CONTROL, OPTC_SEGMENT_WIDTH, mask_sh),\ - SF(DWB_SOURCE_SELECT, OPTC_DWB0_SOURCE_SELECT, mask_sh),\ - SF(DWB_SOURCE_SELECT, OPTC_DWB1_SOURCE_SELECT, mask_sh),\ - SF(OTG0_OTG_MANUAL_FLOW_CONTROL, MANUAL_FLOW_CONTROL, mask_sh), \ - SF(OTG0_OTG_DRR_CONTROL, OTG_V_TOTAL_LAST_USED_BY_DRR, mask_sh) - -void dcn20_timing_generator_init(struct optc *optc); - -void optc2_get_last_used_drr_vtotal(struct timing_generator *optc, - uint32_t *refresh_rate); - -bool optc2_enable_crtc(struct timing_generator *optc); - -void optc2_set_gsl(struct timing_generator *optc, - const struct gsl_params *params); - -void optc2_set_gsl_source_select(struct timing_generator *optc, - int group_idx, - uint32_t gsl_ready_signal); - -void optc2_set_dsc_config(struct timing_generator *optc, - enum optc_dsc_mode dsc_mode, - uint32_t dsc_bytes_per_pixel, - uint32_t dsc_slice_width); - -void optc2_get_dsc_status(struct timing_generator *optc, - uint32_t *dsc_mode); - -void optc2_set_odm_bypass(struct timing_generator *optc, - const struct dc_crtc_timing *dc_crtc_timing); - -void optc2_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, - struct dc_crtc_timing *timing); - -void optc2_get_optc_source(struct timing_generator *optc, - uint32_t *num_of_src_opp, - uint32_t *src_opp_id_0, - uint32_t *src_opp_id_1); - -void optc2_triplebuffer_lock(struct timing_generator *optc); -void optc2_triplebuffer_unlock(struct timing_generator *optc); -void optc2_lock_doublebuffer_disable(struct timing_generator *optc); -void optc2_lock_doublebuffer_enable(struct timing_generator *optc); -void optc2_setup_manual_trigger(struct timing_generator *optc); -void optc2_program_manual_trigger(struct timing_generator *optc); -bool optc2_is_two_pixels_per_containter(const struct dc_crtc_timing *timing); -bool optc2_configure_crc(struct timing_generator *optc, - const struct crc_params *params); -#endif /* __DC_OPTC_DCN20_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 deleted file mode 100644 index 0a422fbb14bc84..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c +++ /dev/null @@ -1,2789 +0,0 @@ -/* -* Copyright 2016 Advanced Micro Devices, Inc. - * Copyright 2019 Raptor Engineering, LLC - * - * 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 - -#include "dm_services.h" -#include "dc.h" - -#include "dcn20_init.h" - -#include "resource.h" -#include "include/irq_service_interface.h" -#include "dcn20/dcn20_resource.h" - -#include "dml/dcn20/dcn20_fpu.h" - -#include "dcn10/dcn10_hubp.h" -#include "dcn10/dcn10_ipp.h" -#include "dcn20_hubbub.h" -#include "dcn20_mpc.h" -#include "dcn20_hubp.h" -#include "irq/dcn20/irq_service_dcn20.h" -#include "dcn20_dpp.h" -#include "dcn20_optc.h" -#include "dcn20/dcn20_hwseq.h" -#include "dce110/dce110_hwseq.h" -#include "dcn10/dcn10_resource.h" -#include "dcn20_opp.h" - -#include "dcn20_dsc.h" - -#include "dcn20_link_encoder.h" -#include "dcn20_stream_encoder.h" -#include "dce/dce_clock_source.h" -#include "dce/dce_audio.h" -#include "dce/dce_hwseq.h" -#include "virtual/virtual_stream_encoder.h" -#include "dce110/dce110_resource.h" -#include "dml/display_mode_vba.h" -#include "dcn20_dccg.h" -#include "dcn20_vmid.h" -#include "dce/dce_panel_cntl.h" - -#include "navi10_ip_offset.h" - -#include "dcn/dcn_2_0_0_offset.h" -#include "dcn/dcn_2_0_0_sh_mask.h" -#include "dpcs/dpcs_2_0_0_offset.h" -#include "dpcs/dpcs_2_0_0_sh_mask.h" - -#include "nbio/nbio_2_3_offset.h" - -#include "dcn20/dcn20_dwb.h" -#include "dcn20/dcn20_mmhubbub.h" - -#include "mmhub/mmhub_2_0_0_offset.h" -#include "mmhub/mmhub_2_0_0_sh_mask.h" - -#include "reg_helper.h" -#include "dce/dce_abm.h" -#include "dce/dce_dmcu.h" -#include "dce/dce_aux.h" -#include "dce/dce_i2c.h" -#include "vm_helper.h" -#include "link_enc_cfg.h" - -#include "amdgpu_socbb.h" - -#include "link.h" -#define DC_LOGGER_INIT(logger) - -#ifndef mmDP0_DP_DPHY_INTERNAL_CTRL - #define mmDP0_DP_DPHY_INTERNAL_CTRL 0x210f - #define mmDP0_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 - #define mmDP1_DP_DPHY_INTERNAL_CTRL 0x220f - #define mmDP1_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 - #define mmDP2_DP_DPHY_INTERNAL_CTRL 0x230f - #define mmDP2_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 - #define mmDP3_DP_DPHY_INTERNAL_CTRL 0x240f - #define mmDP3_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 - #define mmDP4_DP_DPHY_INTERNAL_CTRL 0x250f - #define mmDP4_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 - #define mmDP5_DP_DPHY_INTERNAL_CTRL 0x260f - #define mmDP5_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 - #define mmDP6_DP_DPHY_INTERNAL_CTRL 0x270f - #define mmDP6_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 -#endif - - -enum dcn20_clk_src_array_id { - DCN20_CLK_SRC_PLL0, - DCN20_CLK_SRC_PLL1, - DCN20_CLK_SRC_PLL2, - DCN20_CLK_SRC_PLL3, - DCN20_CLK_SRC_PLL4, - DCN20_CLK_SRC_PLL5, - DCN20_CLK_SRC_TOTAL -}; - -/* begin ********************* - * macros to expend register list macro defined in HW object header file */ - -/* DCN */ -#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg - -#define BASE(seg) BASE_INNER(seg) - -#define SR(reg_name)\ - .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + \ - mm ## reg_name - -#define SRI(reg_name, block, id)\ - .reg_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name - -#define SRI2_DWB(reg_name, block, id)\ - .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + \ - mm ## reg_name -#define SF_DWB(reg_name, field_name, post_fix)\ - .field_name = reg_name ## __ ## field_name ## post_fix - -#define SF_DWB2(reg_name, block, id, field_name, post_fix) \ - .field_name = reg_name ## __ ## field_name ## post_fix - -#define SRIR(var_name, reg_name, block, id)\ - .var_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name - -#define SRII(reg_name, block, id)\ - .reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name - -#define DCCG_SRII(reg_name, block, id)\ - .block ## _ ## reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name - -#define VUPDATE_SRII(reg_name, block, id)\ - .reg_name[id] = BASE(mm ## reg_name ## _ ## block ## id ## _BASE_IDX) + \ - mm ## reg_name ## _ ## block ## id - -/* NBIO */ -#define NBIO_BASE_INNER(seg) \ - NBIO_BASE__INST0_SEG ## seg - -#define NBIO_BASE(seg) \ - NBIO_BASE_INNER(seg) - -#define NBIO_SR(reg_name)\ - .reg_name = NBIO_BASE(mm ## reg_name ## _BASE_IDX) + \ - mm ## reg_name - -/* MMHUB */ -#define MMHUB_BASE_INNER(seg) \ - MMHUB_BASE__INST0_SEG ## seg - -#define MMHUB_BASE(seg) \ - MMHUB_BASE_INNER(seg) - -#define MMHUB_SR(reg_name)\ - .reg_name = MMHUB_BASE(mmMM ## reg_name ## _BASE_IDX) + \ - mmMM ## reg_name - -static const struct bios_registers bios_regs = { - NBIO_SR(BIOS_SCRATCH_3), - NBIO_SR(BIOS_SCRATCH_6) -}; - -#define clk_src_regs(index, pllid)\ -[index] = {\ - CS_COMMON_REG_LIST_DCN2_0(index, pllid),\ -} - -static const struct dce110_clk_src_regs clk_src_regs[] = { - clk_src_regs(0, A), - clk_src_regs(1, B), - clk_src_regs(2, C), - clk_src_regs(3, D), - clk_src_regs(4, E), - clk_src_regs(5, F) -}; - -static const struct dce110_clk_src_shift cs_shift = { - CS_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) -}; - -static const struct dce110_clk_src_mask cs_mask = { - CS_COMMON_MASK_SH_LIST_DCN2_0(_MASK) -}; - -static const struct dce_dmcu_registers dmcu_regs = { - DMCU_DCN10_REG_LIST() -}; - -static const struct dce_dmcu_shift dmcu_shift = { - DMCU_MASK_SH_LIST_DCN10(__SHIFT) -}; - -static const struct dce_dmcu_mask dmcu_mask = { - DMCU_MASK_SH_LIST_DCN10(_MASK) -}; - -static const struct dce_abm_registers abm_regs = { - ABM_DCN20_REG_LIST() -}; - -static const struct dce_abm_shift abm_shift = { - ABM_MASK_SH_LIST_DCN20(__SHIFT) -}; - -static const struct dce_abm_mask abm_mask = { - ABM_MASK_SH_LIST_DCN20(_MASK) -}; - -#define audio_regs(id)\ -[id] = {\ - AUD_COMMON_REG_LIST(id)\ -} - -static const struct dce_audio_registers audio_regs[] = { - audio_regs(0), - audio_regs(1), - audio_regs(2), - audio_regs(3), - audio_regs(4), - audio_regs(5), - audio_regs(6), -}; - -#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ - SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ - SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ - AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) - -static const struct dce_audio_shift audio_shift = { - DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_audio_mask audio_mask = { - DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) -}; - -#define stream_enc_regs(id)\ -[id] = {\ - SE_DCN2_REG_LIST(id)\ -} - -static const struct dcn10_stream_enc_registers stream_enc_regs[] = { - stream_enc_regs(0), - stream_enc_regs(1), - stream_enc_regs(2), - stream_enc_regs(3), - stream_enc_regs(4), - stream_enc_regs(5), -}; - -static const struct dcn10_stream_encoder_shift se_shift = { - SE_COMMON_MASK_SH_LIST_DCN20(__SHIFT) -}; - -static const struct dcn10_stream_encoder_mask se_mask = { - SE_COMMON_MASK_SH_LIST_DCN20(_MASK) -}; - - -#define aux_regs(id)\ -[id] = {\ - DCN2_AUX_REG_LIST(id)\ -} - -static const struct dcn10_link_enc_aux_registers link_enc_aux_regs[] = { - aux_regs(0), - aux_regs(1), - aux_regs(2), - aux_regs(3), - aux_regs(4), - aux_regs(5) -}; - -#define hpd_regs(id)\ -[id] = {\ - HPD_REG_LIST(id)\ -} - -static const struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[] = { - hpd_regs(0), - hpd_regs(1), - hpd_regs(2), - hpd_regs(3), - hpd_regs(4), - hpd_regs(5) -}; - -#define link_regs(id, phyid)\ -[id] = {\ - LE_DCN10_REG_LIST(id), \ - UNIPHY_DCN2_REG_LIST(phyid), \ - DPCS_DCN2_REG_LIST(id), \ - SRI(DP_DPHY_INTERNAL_CTRL, DP, id) \ -} - -static const struct dcn10_link_enc_registers link_enc_regs[] = { - link_regs(0, A), - link_regs(1, B), - link_regs(2, C), - link_regs(3, D), - link_regs(4, E), - link_regs(5, F) -}; - -static const struct dcn10_link_enc_shift le_shift = { - LINK_ENCODER_MASK_SH_LIST_DCN20(__SHIFT),\ - DPCS_DCN2_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn10_link_enc_mask le_mask = { - LINK_ENCODER_MASK_SH_LIST_DCN20(_MASK),\ - DPCS_DCN2_MASK_SH_LIST(_MASK) -}; - -static const struct dce_panel_cntl_registers panel_cntl_regs[] = { - { DCN_PANEL_CNTL_REG_LIST() } -}; - -static const struct dce_panel_cntl_shift panel_cntl_shift = { - DCE_PANEL_CNTL_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_panel_cntl_mask panel_cntl_mask = { - DCE_PANEL_CNTL_MASK_SH_LIST(_MASK) -}; - -#define ipp_regs(id)\ -[id] = {\ - IPP_REG_LIST_DCN20(id),\ -} - -static const struct dcn10_ipp_registers ipp_regs[] = { - ipp_regs(0), - ipp_regs(1), - ipp_regs(2), - ipp_regs(3), - ipp_regs(4), - ipp_regs(5), -}; - -static const struct dcn10_ipp_shift ipp_shift = { - IPP_MASK_SH_LIST_DCN20(__SHIFT) -}; - -static const struct dcn10_ipp_mask ipp_mask = { - IPP_MASK_SH_LIST_DCN20(_MASK), -}; - -#define opp_regs(id)\ -[id] = {\ - OPP_REG_LIST_DCN20(id),\ -} - -static const struct dcn20_opp_registers opp_regs[] = { - opp_regs(0), - opp_regs(1), - opp_regs(2), - opp_regs(3), - opp_regs(4), - opp_regs(5), -}; - -static const struct dcn20_opp_shift opp_shift = { - OPP_MASK_SH_LIST_DCN20(__SHIFT) -}; - -static const struct dcn20_opp_mask opp_mask = { - OPP_MASK_SH_LIST_DCN20(_MASK) -}; - -#define aux_engine_regs(id)\ -[id] = {\ - AUX_COMMON_REG_LIST0(id), \ - .AUXN_IMPCAL = 0, \ - .AUXP_IMPCAL = 0, \ - .AUX_RESET_MASK = DP_AUX0_AUX_CONTROL__AUX_RESET_MASK, \ -} - -static const struct dce110_aux_registers aux_engine_regs[] = { - aux_engine_regs(0), - aux_engine_regs(1), - aux_engine_regs(2), - aux_engine_regs(3), - aux_engine_regs(4), - aux_engine_regs(5) -}; - -#define tf_regs(id)\ -[id] = {\ - TF_REG_LIST_DCN20(id),\ - TF_REG_LIST_DCN20_COMMON_APPEND(id),\ -} - -static const struct dcn2_dpp_registers tf_regs[] = { - tf_regs(0), - tf_regs(1), - tf_regs(2), - tf_regs(3), - tf_regs(4), - tf_regs(5), -}; - -static const struct dcn2_dpp_shift tf_shift = { - TF_REG_LIST_SH_MASK_DCN20(__SHIFT), - TF_DEBUG_REG_LIST_SH_DCN20 -}; - -static const struct dcn2_dpp_mask tf_mask = { - TF_REG_LIST_SH_MASK_DCN20(_MASK), - TF_DEBUG_REG_LIST_MASK_DCN20 -}; - -#define dwbc_regs_dcn2(id)\ -[id] = {\ - DWBC_COMMON_REG_LIST_DCN2_0(id),\ - } - -static const struct dcn20_dwbc_registers dwbc20_regs[] = { - dwbc_regs_dcn2(0), -}; - -static const struct dcn20_dwbc_shift dwbc20_shift = { - DWBC_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) -}; - -static const struct dcn20_dwbc_mask dwbc20_mask = { - DWBC_COMMON_MASK_SH_LIST_DCN2_0(_MASK) -}; - -#define mcif_wb_regs_dcn2(id)\ -[id] = {\ - MCIF_WB_COMMON_REG_LIST_DCN2_0(id),\ - } - -static const struct dcn20_mmhubbub_registers mcif_wb20_regs[] = { - mcif_wb_regs_dcn2(0), -}; - -static const struct dcn20_mmhubbub_shift mcif_wb20_shift = { - MCIF_WB_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) -}; - -static const struct dcn20_mmhubbub_mask mcif_wb20_mask = { - MCIF_WB_COMMON_MASK_SH_LIST_DCN2_0(_MASK) -}; - -static const struct dcn20_mpc_registers mpc_regs = { - MPC_REG_LIST_DCN2_0(0), - MPC_REG_LIST_DCN2_0(1), - MPC_REG_LIST_DCN2_0(2), - MPC_REG_LIST_DCN2_0(3), - MPC_REG_LIST_DCN2_0(4), - MPC_REG_LIST_DCN2_0(5), - MPC_OUT_MUX_REG_LIST_DCN2_0(0), - MPC_OUT_MUX_REG_LIST_DCN2_0(1), - MPC_OUT_MUX_REG_LIST_DCN2_0(2), - MPC_OUT_MUX_REG_LIST_DCN2_0(3), - MPC_OUT_MUX_REG_LIST_DCN2_0(4), - MPC_OUT_MUX_REG_LIST_DCN2_0(5), - MPC_DBG_REG_LIST_DCN2_0() -}; - -static const struct dcn20_mpc_shift mpc_shift = { - MPC_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT), - MPC_DEBUG_REG_LIST_SH_DCN20 -}; - -static const struct dcn20_mpc_mask mpc_mask = { - MPC_COMMON_MASK_SH_LIST_DCN2_0(_MASK), - MPC_DEBUG_REG_LIST_MASK_DCN20 -}; - -#define tg_regs(id)\ -[id] = {TG_COMMON_REG_LIST_DCN2_0(id)} - - -static const struct dcn_optc_registers tg_regs[] = { - tg_regs(0), - tg_regs(1), - tg_regs(2), - tg_regs(3), - tg_regs(4), - tg_regs(5) -}; - -static const struct dcn_optc_shift tg_shift = { - TG_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) -}; - -static const struct dcn_optc_mask tg_mask = { - TG_COMMON_MASK_SH_LIST_DCN2_0(_MASK) -}; - -#define hubp_regs(id)\ -[id] = {\ - HUBP_REG_LIST_DCN20(id)\ -} - -static const struct dcn_hubp2_registers hubp_regs[] = { - hubp_regs(0), - hubp_regs(1), - hubp_regs(2), - hubp_regs(3), - hubp_regs(4), - hubp_regs(5) -}; - -static const struct dcn_hubp2_shift hubp_shift = { - HUBP_MASK_SH_LIST_DCN20(__SHIFT) -}; - -static const struct dcn_hubp2_mask hubp_mask = { - HUBP_MASK_SH_LIST_DCN20(_MASK) -}; - -static const struct dcn_hubbub_registers hubbub_reg = { - HUBBUB_REG_LIST_DCN20(0) -}; - -static const struct dcn_hubbub_shift hubbub_shift = { - HUBBUB_MASK_SH_LIST_DCN20(__SHIFT) -}; - -static const struct dcn_hubbub_mask hubbub_mask = { - HUBBUB_MASK_SH_LIST_DCN20(_MASK) -}; - -#define vmid_regs(id)\ -[id] = {\ - DCN20_VMID_REG_LIST(id)\ -} - -static const struct dcn_vmid_registers vmid_regs[] = { - vmid_regs(0), - vmid_regs(1), - vmid_regs(2), - vmid_regs(3), - vmid_regs(4), - vmid_regs(5), - vmid_regs(6), - vmid_regs(7), - vmid_regs(8), - vmid_regs(9), - vmid_regs(10), - vmid_regs(11), - vmid_regs(12), - vmid_regs(13), - vmid_regs(14), - vmid_regs(15) -}; - -static const struct dcn20_vmid_shift vmid_shifts = { - DCN20_VMID_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn20_vmid_mask vmid_masks = { - DCN20_VMID_MASK_SH_LIST(_MASK) -}; - -static const struct dce110_aux_registers_shift aux_shift = { - DCN_AUX_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce110_aux_registers_mask aux_mask = { - DCN_AUX_MASK_SH_LIST(_MASK) -}; - -static int map_transmitter_id_to_phy_instance( - enum transmitter transmitter) -{ - switch (transmitter) { - case TRANSMITTER_UNIPHY_A: - return 0; - break; - case TRANSMITTER_UNIPHY_B: - return 1; - break; - case TRANSMITTER_UNIPHY_C: - return 2; - break; - case TRANSMITTER_UNIPHY_D: - return 3; - break; - case TRANSMITTER_UNIPHY_E: - return 4; - break; - case TRANSMITTER_UNIPHY_F: - return 5; - break; - default: - ASSERT(0); - return 0; - } -} - -#define dsc_regsDCN20(id)\ -[id] = {\ - DSC_REG_LIST_DCN20(id)\ -} - -static const struct dcn20_dsc_registers dsc_regs[] = { - dsc_regsDCN20(0), - dsc_regsDCN20(1), - dsc_regsDCN20(2), - dsc_regsDCN20(3), - dsc_regsDCN20(4), - dsc_regsDCN20(5) -}; - -static const struct dcn20_dsc_shift dsc_shift = { - DSC_REG_LIST_SH_MASK_DCN20(__SHIFT) -}; - -static const struct dcn20_dsc_mask dsc_mask = { - DSC_REG_LIST_SH_MASK_DCN20(_MASK) -}; - -static const struct dccg_registers dccg_regs = { - DCCG_REG_LIST_DCN2() -}; - -static const struct dccg_shift dccg_shift = { - DCCG_MASK_SH_LIST_DCN2(__SHIFT) -}; - -static const struct dccg_mask dccg_mask = { - DCCG_MASK_SH_LIST_DCN2(_MASK) -}; - -static const struct resource_caps res_cap_nv10 = { - .num_timing_generator = 6, - .num_opp = 6, - .num_video_plane = 6, - .num_audio = 7, - .num_stream_encoder = 6, - .num_pll = 6, - .num_dwb = 1, - .num_ddc = 6, - .num_vmid = 16, - .num_dsc = 6, -}; - -static const struct dc_plane_cap plane_cap = { - .type = DC_PLANE_TYPE_DCN_UNIVERSAL, - .per_pixel_alpha = true, - - .pixel_format_support = { - .argb8888 = true, - .nv12 = true, - .fp16 = true, - .p010 = true - }, - - .max_upscale_factor = { - .argb8888 = 16000, - .nv12 = 16000, - .fp16 = 1 - }, - - .max_downscale_factor = { - .argb8888 = 250, - .nv12 = 250, - .fp16 = 1 - }, - 16, - 16 -}; -static const struct resource_caps res_cap_nv14 = { - .num_timing_generator = 5, - .num_opp = 5, - .num_video_plane = 5, - .num_audio = 6, - .num_stream_encoder = 5, - .num_pll = 5, - .num_dwb = 1, - .num_ddc = 5, - .num_vmid = 16, - .num_dsc = 5, -}; - -static const struct dc_debug_options debug_defaults_drv = { - .disable_dmcu = false, - .force_abm_enable = false, - .timing_trace = false, - .clock_trace = true, - .disable_pplib_clock_request = true, - .pipe_split_policy = MPC_SPLIT_AVOID_MULT_DISP, - .force_single_disp_pipe_split = false, - .disable_dcc = DCC_ENABLE, - .vsr_support = true, - .performance_trace = false, - .max_downscale_src_width = 5120,/*upto 5K*/ - .disable_pplib_wm_range = false, - .scl_reset_length10 = true, - .sanity_checks = false, - .underflow_assert_delay_us = 0xFFFFFFFF, - .enable_legacy_fast_update = true, - .using_dml2 = false, -}; - -void dcn20_dpp_destroy(struct dpp **dpp) -{ - kfree(TO_DCN20_DPP(*dpp)); - *dpp = NULL; -} - -struct dpp *dcn20_dpp_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn20_dpp *dpp = - kzalloc(sizeof(struct dcn20_dpp), GFP_ATOMIC); - - if (!dpp) - return NULL; - - if (dpp2_construct(dpp, ctx, inst, - &tf_regs[inst], &tf_shift, &tf_mask)) - return &dpp->base; - - BREAK_TO_DEBUGGER(); - kfree(dpp); - return NULL; -} - -struct input_pixel_processor *dcn20_ipp_create( - struct dc_context *ctx, uint32_t inst) -{ - struct dcn10_ipp *ipp = - kzalloc(sizeof(struct dcn10_ipp), GFP_ATOMIC); - - if (!ipp) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dcn20_ipp_construct(ipp, ctx, inst, - &ipp_regs[inst], &ipp_shift, &ipp_mask); - return &ipp->base; -} - - -struct output_pixel_processor *dcn20_opp_create( - struct dc_context *ctx, uint32_t inst) -{ - struct dcn20_opp *opp = - kzalloc(sizeof(struct dcn20_opp), GFP_ATOMIC); - - if (!opp) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dcn20_opp_construct(opp, ctx, inst, - &opp_regs[inst], &opp_shift, &opp_mask); - return &opp->base; -} - -struct dce_aux *dcn20_aux_engine_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct aux_engine_dce110 *aux_engine = - kzalloc(sizeof(struct aux_engine_dce110), GFP_ATOMIC); - - if (!aux_engine) - return NULL; - - dce110_aux_engine_construct(aux_engine, ctx, inst, - SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, - &aux_engine_regs[inst], - &aux_mask, - &aux_shift, - ctx->dc->caps.extended_aux_timeout_support); - - return &aux_engine->base; -} -#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST(id) } - -static const struct dce_i2c_registers i2c_hw_regs[] = { - i2c_inst_regs(1), - i2c_inst_regs(2), - i2c_inst_regs(3), - i2c_inst_regs(4), - i2c_inst_regs(5), - i2c_inst_regs(6), -}; - -static const struct dce_i2c_shift i2c_shifts = { - I2C_COMMON_MASK_SH_LIST_DCN2(__SHIFT) -}; - -static const struct dce_i2c_mask i2c_masks = { - I2C_COMMON_MASK_SH_LIST_DCN2(_MASK) -}; - -struct dce_i2c_hw *dcn20_i2c_hw_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dce_i2c_hw *dce_i2c_hw = - kzalloc(sizeof(struct dce_i2c_hw), GFP_ATOMIC); - - if (!dce_i2c_hw) - return NULL; - - dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst, - &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); - - return dce_i2c_hw; -} -struct mpc *dcn20_mpc_create(struct dc_context *ctx) -{ - struct dcn20_mpc *mpc20 = kzalloc(sizeof(struct dcn20_mpc), - GFP_ATOMIC); - - if (!mpc20) - return NULL; - - dcn20_mpc_construct(mpc20, ctx, - &mpc_regs, - &mpc_shift, - &mpc_mask, - 6); - - return &mpc20->base; -} - -struct hubbub *dcn20_hubbub_create(struct dc_context *ctx) -{ - int i; - struct dcn20_hubbub *hubbub = kzalloc(sizeof(struct dcn20_hubbub), - GFP_ATOMIC); - - if (!hubbub) - return NULL; - - hubbub2_construct(hubbub, ctx, - &hubbub_reg, - &hubbub_shift, - &hubbub_mask); - - for (i = 0; i < res_cap_nv10.num_vmid; i++) { - struct dcn20_vmid *vmid = &hubbub->vmid[i]; - - vmid->ctx = ctx; - - vmid->regs = &vmid_regs[i]; - vmid->shifts = &vmid_shifts; - vmid->masks = &vmid_masks; - } - - return &hubbub->base; -} - -struct timing_generator *dcn20_timing_generator_create( - struct dc_context *ctx, - uint32_t instance) -{ - struct optc *tgn10 = - kzalloc(sizeof(struct optc), GFP_ATOMIC); - - if (!tgn10) - return NULL; - - tgn10->base.inst = instance; - tgn10->base.ctx = ctx; - - tgn10->tg_regs = &tg_regs[instance]; - tgn10->tg_shift = &tg_shift; - tgn10->tg_mask = &tg_mask; - - dcn20_timing_generator_init(tgn10); - - return &tgn10->base; -} - -static const struct encoder_feature_support link_enc_feature = { - .max_hdmi_deep_color = COLOR_DEPTH_121212, - .max_hdmi_pixel_clock = 600000, - .hdmi_ycbcr420_supported = true, - .dp_ycbcr420_supported = true, - .fec_supported = true, - .flags.bits.IS_HBR2_CAPABLE = true, - .flags.bits.IS_HBR3_CAPABLE = true, - .flags.bits.IS_TPS3_CAPABLE = true, - .flags.bits.IS_TPS4_CAPABLE = true -}; - -struct link_encoder *dcn20_link_encoder_create( - struct dc_context *ctx, - const struct encoder_init_data *enc_init_data) -{ - struct dcn20_link_encoder *enc20 = - kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); - int link_regs_id; - - if (!enc20) - return NULL; - - link_regs_id = - map_transmitter_id_to_phy_instance(enc_init_data->transmitter); - - dcn20_link_encoder_construct(enc20, - enc_init_data, - &link_enc_feature, - &link_enc_regs[link_regs_id], - &link_enc_aux_regs[enc_init_data->channel - 1], - &link_enc_hpd_regs[enc_init_data->hpd_source], - &le_shift, - &le_mask); - - return &enc20->enc10.base; -} - -static struct panel_cntl *dcn20_panel_cntl_create(const struct panel_cntl_init_data *init_data) -{ - struct dce_panel_cntl *panel_cntl = - kzalloc(sizeof(struct dce_panel_cntl), GFP_KERNEL); - - if (!panel_cntl) - return NULL; - - dce_panel_cntl_construct(panel_cntl, - init_data, - &panel_cntl_regs[init_data->inst], - &panel_cntl_shift, - &panel_cntl_mask); - - return &panel_cntl->base; -} - -static struct clock_source *dcn20_clock_source_create( - struct dc_context *ctx, - struct dc_bios *bios, - enum clock_source_id id, - const struct dce110_clk_src_regs *regs, - bool dp_clk_src) -{ - struct dce110_clk_src *clk_src = - kzalloc(sizeof(struct dce110_clk_src), GFP_ATOMIC); - - if (!clk_src) - return NULL; - - if (dcn20_clk_src_construct(clk_src, ctx, bios, id, - regs, &cs_shift, &cs_mask)) { - clk_src->base.dp_clk_src = dp_clk_src; - return &clk_src->base; - } - - kfree(clk_src); - BREAK_TO_DEBUGGER(); - return NULL; -} - -static void read_dce_straps( - struct dc_context *ctx, - struct resource_straps *straps) -{ - generic_reg_get(ctx, mmDC_PINSTRAPS + BASE(mmDC_PINSTRAPS_BASE_IDX), - FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio); -} - -static struct audio *dcn20_create_audio( - struct dc_context *ctx, unsigned int inst) -{ - return dce_audio_create(ctx, inst, - &audio_regs[inst], &audio_shift, &audio_mask); -} - -struct stream_encoder *dcn20_stream_encoder_create( - enum engine_id eng_id, - struct dc_context *ctx) -{ - struct dcn10_stream_encoder *enc1 = - kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL); - - if (!enc1) - return NULL; - - if (ASICREV_IS_NAVI14_M(ctx->asic_id.hw_internal_rev)) { - if (eng_id >= ENGINE_ID_DIGD) - eng_id++; - } - - dcn20_stream_encoder_construct(enc1, ctx, ctx->dc_bios, eng_id, - &stream_enc_regs[eng_id], - &se_shift, &se_mask); - - return &enc1->base; -} - -static const struct dce_hwseq_registers hwseq_reg = { - HWSEQ_DCN2_REG_LIST() -}; - -static const struct dce_hwseq_shift hwseq_shift = { - HWSEQ_DCN2_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_hwseq_mask hwseq_mask = { - HWSEQ_DCN2_MASK_SH_LIST(_MASK) -}; - -struct dce_hwseq *dcn20_hwseq_create( - struct dc_context *ctx) -{ - struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); - - if (hws) { - hws->ctx = ctx; - hws->regs = &hwseq_reg; - hws->shifts = &hwseq_shift; - hws->masks = &hwseq_mask; - } - return hws; -} - -static const struct resource_create_funcs res_create_funcs = { - .read_dce_straps = read_dce_straps, - .create_audio = dcn20_create_audio, - .create_stream_encoder = dcn20_stream_encoder_create, - .create_hwseq = dcn20_hwseq_create, -}; - -static void dcn20_pp_smu_destroy(struct pp_smu_funcs **pp_smu); - -void dcn20_clock_source_destroy(struct clock_source **clk_src) -{ - kfree(TO_DCE110_CLK_SRC(*clk_src)); - *clk_src = NULL; -} - - -struct display_stream_compressor *dcn20_dsc_create( - struct dc_context *ctx, uint32_t inst) -{ - struct dcn20_dsc *dsc = - kzalloc(sizeof(struct dcn20_dsc), GFP_ATOMIC); - - if (!dsc) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dsc2_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask); - return &dsc->base; -} - -void dcn20_dsc_destroy(struct display_stream_compressor **dsc) -{ - kfree(container_of(*dsc, struct dcn20_dsc, base)); - *dsc = NULL; -} - - -static void dcn20_resource_destruct(struct dcn20_resource_pool *pool) -{ - unsigned int i; - - for (i = 0; i < pool->base.stream_enc_count; i++) { - if (pool->base.stream_enc[i] != NULL) { - kfree(DCN10STRENC_FROM_STRENC(pool->base.stream_enc[i])); - pool->base.stream_enc[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_dsc; i++) { - if (pool->base.dscs[i] != NULL) - dcn20_dsc_destroy(&pool->base.dscs[i]); - } - - if (pool->base.mpc != NULL) { - kfree(TO_DCN20_MPC(pool->base.mpc)); - pool->base.mpc = NULL; - } - if (pool->base.hubbub != NULL) { - kfree(pool->base.hubbub); - pool->base.hubbub = NULL; - } - for (i = 0; i < pool->base.pipe_count; i++) { - if (pool->base.dpps[i] != NULL) - dcn20_dpp_destroy(&pool->base.dpps[i]); - - if (pool->base.ipps[i] != NULL) - pool->base.ipps[i]->funcs->ipp_destroy(&pool->base.ipps[i]); - - if (pool->base.hubps[i] != NULL) { - kfree(TO_DCN20_HUBP(pool->base.hubps[i])); - pool->base.hubps[i] = NULL; - } - - if (pool->base.irqs != NULL) { - dal_irq_service_destroy(&pool->base.irqs); - } - } - - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - if (pool->base.engines[i] != NULL) - dce110_engine_destroy(&pool->base.engines[i]); - if (pool->base.hw_i2cs[i] != NULL) { - kfree(pool->base.hw_i2cs[i]); - pool->base.hw_i2cs[i] = NULL; - } - if (pool->base.sw_i2cs[i] != NULL) { - kfree(pool->base.sw_i2cs[i]); - pool->base.sw_i2cs[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_opp; i++) { - if (pool->base.opps[i] != NULL) - pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]); - } - - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - if (pool->base.timing_generators[i] != NULL) { - kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i])); - pool->base.timing_generators[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_dwb; i++) { - if (pool->base.dwbc[i] != NULL) { - kfree(TO_DCN20_DWBC(pool->base.dwbc[i])); - pool->base.dwbc[i] = NULL; - } - if (pool->base.mcif_wb[i] != NULL) { - kfree(TO_DCN20_MMHUBBUB(pool->base.mcif_wb[i])); - pool->base.mcif_wb[i] = NULL; - } - } - - for (i = 0; i < pool->base.audio_count; i++) { - if (pool->base.audios[i]) - dce_aud_destroy(&pool->base.audios[i]); - } - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] != NULL) { - dcn20_clock_source_destroy(&pool->base.clock_sources[i]); - pool->base.clock_sources[i] = NULL; - } - } - - if (pool->base.dp_clock_source != NULL) { - dcn20_clock_source_destroy(&pool->base.dp_clock_source); - pool->base.dp_clock_source = NULL; - } - - - if (pool->base.abm != NULL) - dce_abm_destroy(&pool->base.abm); - - if (pool->base.dmcu != NULL) - dce_dmcu_destroy(&pool->base.dmcu); - - if (pool->base.dccg != NULL) - dcn_dccg_destroy(&pool->base.dccg); - - if (pool->base.pp_smu != NULL) - dcn20_pp_smu_destroy(&pool->base.pp_smu); - - if (pool->base.oem_device != NULL) { - struct dc *dc = pool->base.oem_device->ctx->dc; - - dc->link_srv->destroy_ddc_service(&pool->base.oem_device); - } -} - -struct hubp *dcn20_hubp_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn20_hubp *hubp2 = - kzalloc(sizeof(struct dcn20_hubp), GFP_ATOMIC); - - if (!hubp2) - return NULL; - - if (hubp2_construct(hubp2, ctx, inst, - &hubp_regs[inst], &hubp_shift, &hubp_mask)) - return &hubp2->base; - - BREAK_TO_DEBUGGER(); - kfree(hubp2); - return NULL; -} - -static void get_pixel_clock_parameters( - struct pipe_ctx *pipe_ctx, - struct pixel_clk_params *pixel_clk_params) -{ - const struct dc_stream_state *stream = pipe_ctx->stream; - struct pipe_ctx *odm_pipe; - int opp_cnt = 1; - struct dc_link *link = stream->link; - struct link_encoder *link_enc = NULL; - struct dc *dc = pipe_ctx->stream->ctx->dc; - struct dce_hwseq *hws = dc->hwseq; - - for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) - opp_cnt++; - - pixel_clk_params->requested_pix_clk_100hz = stream->timing.pix_clk_100hz; - - link_enc = link_enc_cfg_get_link_enc(link); - if (link_enc) - pixel_clk_params->encoder_object_id = link_enc->id; - - pixel_clk_params->signal_type = pipe_ctx->stream->signal; - pixel_clk_params->controller_id = pipe_ctx->stream_res.tg->inst + 1; - /* TODO: un-hardcode*/ - /* TODO - DP2.0 HW: calculate requested_sym_clk for UHBR rates */ - pixel_clk_params->requested_sym_clk = LINK_RATE_LOW * - LINK_RATE_REF_FREQ_IN_KHZ; - pixel_clk_params->flags.ENABLE_SS = 0; - pixel_clk_params->color_depth = - stream->timing.display_color_depth; - pixel_clk_params->flags.DISPLAY_BLANKED = 1; - pixel_clk_params->pixel_encoding = stream->timing.pixel_encoding; - - if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR422) - pixel_clk_params->color_depth = COLOR_DEPTH_888; - - if (opp_cnt == 4) - pixel_clk_params->requested_pix_clk_100hz /= 4; - else if (optc2_is_two_pixels_per_containter(&stream->timing) || opp_cnt == 2) - pixel_clk_params->requested_pix_clk_100hz /= 2; - else if (hws->funcs.is_dp_dig_pixel_rate_div_policy) { - if (hws->funcs.is_dp_dig_pixel_rate_div_policy(pipe_ctx)) - pixel_clk_params->requested_pix_clk_100hz /= 2; - } - - if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING) - pixel_clk_params->requested_pix_clk_100hz *= 2; - -} - -static void build_clamping_params(struct dc_stream_state *stream) -{ - stream->clamping.clamping_level = CLAMPING_FULL_RANGE; - stream->clamping.c_depth = stream->timing.display_color_depth; - stream->clamping.pixel_encoding = stream->timing.pixel_encoding; -} - -static enum dc_status build_pipe_hw_param(struct pipe_ctx *pipe_ctx) -{ - - get_pixel_clock_parameters(pipe_ctx, &pipe_ctx->stream_res.pix_clk_params); - - pipe_ctx->clock_source->funcs->get_pix_clk_dividers( - pipe_ctx->clock_source, - &pipe_ctx->stream_res.pix_clk_params, - &pipe_ctx->pll_settings); - - pipe_ctx->stream->clamping.pixel_encoding = pipe_ctx->stream->timing.pixel_encoding; - - resource_build_bit_depth_reduction_params(pipe_ctx->stream, - &pipe_ctx->stream->bit_depth_params); - build_clamping_params(pipe_ctx->stream); - - return DC_OK; -} - -enum dc_status dcn20_build_mapped_resource(const struct dc *dc, struct dc_state *context, struct dc_stream_state *stream) -{ - enum dc_status status = DC_OK; - struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream); - - if (!pipe_ctx) - return DC_ERROR_UNEXPECTED; - - - status = build_pipe_hw_param(pipe_ctx); - - return status; -} - - -void dcn20_acquire_dsc(const struct dc *dc, - struct resource_context *res_ctx, - struct display_stream_compressor **dsc, - int pipe_idx) -{ - int i; - const struct resource_pool *pool = dc->res_pool; - struct display_stream_compressor *dsc_old = dc->current_state->res_ctx.pipe_ctx[pipe_idx].stream_res.dsc; - - ASSERT(*dsc == NULL); /* If this ASSERT fails, dsc was not released properly */ - *dsc = NULL; - - /* Always do 1-to-1 mapping when number of DSCs is same as number of pipes */ - if (pool->res_cap->num_dsc == pool->res_cap->num_opp) { - *dsc = pool->dscs[pipe_idx]; - res_ctx->is_dsc_acquired[pipe_idx] = true; - return; - } - - /* Return old DSC to avoid the need for re-programming */ - if (dsc_old && !res_ctx->is_dsc_acquired[dsc_old->inst]) { - *dsc = dsc_old; - res_ctx->is_dsc_acquired[dsc_old->inst] = true; - return ; - } - - /* Find first free DSC */ - for (i = 0; i < pool->res_cap->num_dsc; i++) - if (!res_ctx->is_dsc_acquired[i]) { - *dsc = pool->dscs[i]; - res_ctx->is_dsc_acquired[i] = true; - break; - } -} - -void dcn20_release_dsc(struct resource_context *res_ctx, - const struct resource_pool *pool, - struct display_stream_compressor **dsc) -{ - int i; - - for (i = 0; i < pool->res_cap->num_dsc; i++) - if (pool->dscs[i] == *dsc) { - res_ctx->is_dsc_acquired[i] = false; - *dsc = NULL; - break; - } -} - - - -enum dc_status dcn20_add_dsc_to_stream_resource(struct dc *dc, - struct dc_state *dc_ctx, - struct dc_stream_state *dc_stream) -{ - enum dc_status result = DC_OK; - int i; - - /* Get a DSC if required and available */ - 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; - - if (pipe_ctx->stream_res.dsc) - continue; - - dcn20_acquire_dsc(dc, &dc_ctx->res_ctx, &pipe_ctx->stream_res.dsc, i); - - /* The number of DSCs can be less than the number of pipes */ - if (!pipe_ctx->stream_res.dsc) { - result = DC_NO_DSC_RESOURCE; - } - - break; - } - - return result; -} - - -static enum dc_status remove_dsc_from_stream_resource(struct dc *dc, - struct dc_state *new_ctx, - struct dc_stream_state *dc_stream) -{ - struct pipe_ctx *pipe_ctx = NULL; - int i; - - for (i = 0; i < MAX_PIPES; i++) { - if (new_ctx->res_ctx.pipe_ctx[i].stream == dc_stream && !new_ctx->res_ctx.pipe_ctx[i].top_pipe) { - pipe_ctx = &new_ctx->res_ctx.pipe_ctx[i]; - - if (pipe_ctx->stream_res.dsc) - dcn20_release_dsc(&new_ctx->res_ctx, dc->res_pool, &pipe_ctx->stream_res.dsc); - } - } - - if (!pipe_ctx) - return DC_ERROR_UNEXPECTED; - else - return DC_OK; -} - - -enum dc_status dcn20_add_stream_to_ctx(struct dc *dc, struct dc_state *new_ctx, struct dc_stream_state *dc_stream) -{ - enum dc_status result = DC_ERROR_UNEXPECTED; - - result = resource_map_pool_resources(dc, new_ctx, dc_stream); - - if (result == DC_OK) - result = resource_map_phy_clock_resources(dc, new_ctx, dc_stream); - - /* Get a DSC if required and available */ - if (result == DC_OK && dc_stream->timing.flags.DSC) - result = dcn20_add_dsc_to_stream_resource(dc, new_ctx, dc_stream); - - if (result == DC_OK) - result = dcn20_build_mapped_resource(dc, new_ctx, dc_stream); - - return result; -} - - -enum dc_status dcn20_remove_stream_from_ctx(struct dc *dc, struct dc_state *new_ctx, struct dc_stream_state *dc_stream) -{ - enum dc_status result = DC_OK; - - result = remove_dsc_from_stream_resource(dc, new_ctx, dc_stream); - - return result; -} - -/** - * dcn20_split_stream_for_odm - Check if stream can be splited for ODM - * - * @dc: DC object with resource pool info required for pipe split - * @res_ctx: Persistent state of resources - * @prev_odm_pipe: Reference to the previous ODM pipe - * @next_odm_pipe: Reference to the next ODM pipe - * - * This function takes a logically active pipe and a logically free pipe and - * halves all the scaling parameters that need to be halved while populating - * the free pipe with the required resources and configuring the next/previous - * ODM pipe pointers. - * - * Return: - * Return true if split stream for ODM is possible, otherwise, return false. - */ -bool dcn20_split_stream_for_odm( - const struct dc *dc, - struct resource_context *res_ctx, - struct pipe_ctx *prev_odm_pipe, - struct pipe_ctx *next_odm_pipe) -{ - int pipe_idx = next_odm_pipe->pipe_idx; - const struct resource_pool *pool = dc->res_pool; - - *next_odm_pipe = *prev_odm_pipe; - - next_odm_pipe->pipe_idx = pipe_idx; - next_odm_pipe->plane_res.mi = pool->mis[next_odm_pipe->pipe_idx]; - next_odm_pipe->plane_res.hubp = pool->hubps[next_odm_pipe->pipe_idx]; - next_odm_pipe->plane_res.ipp = pool->ipps[next_odm_pipe->pipe_idx]; - next_odm_pipe->plane_res.xfm = pool->transforms[next_odm_pipe->pipe_idx]; - next_odm_pipe->plane_res.dpp = pool->dpps[next_odm_pipe->pipe_idx]; - next_odm_pipe->plane_res.mpcc_inst = pool->dpps[next_odm_pipe->pipe_idx]->inst; - next_odm_pipe->stream_res.dsc = NULL; - if (prev_odm_pipe->next_odm_pipe && prev_odm_pipe->next_odm_pipe != next_odm_pipe) { - next_odm_pipe->next_odm_pipe = prev_odm_pipe->next_odm_pipe; - next_odm_pipe->next_odm_pipe->prev_odm_pipe = next_odm_pipe; - } - if (prev_odm_pipe->top_pipe && prev_odm_pipe->top_pipe->next_odm_pipe) { - prev_odm_pipe->top_pipe->next_odm_pipe->bottom_pipe = next_odm_pipe; - next_odm_pipe->top_pipe = prev_odm_pipe->top_pipe->next_odm_pipe; - } - if (prev_odm_pipe->bottom_pipe && prev_odm_pipe->bottom_pipe->next_odm_pipe) { - prev_odm_pipe->bottom_pipe->next_odm_pipe->top_pipe = next_odm_pipe; - next_odm_pipe->bottom_pipe = prev_odm_pipe->bottom_pipe->next_odm_pipe; - } - prev_odm_pipe->next_odm_pipe = next_odm_pipe; - next_odm_pipe->prev_odm_pipe = prev_odm_pipe; - - if (prev_odm_pipe->plane_state) { - struct scaler_data *sd = &prev_odm_pipe->plane_res.scl_data; - int new_width; - - /* HACTIVE halved for odm combine */ - sd->h_active /= 2; - /* Calculate new vp and recout for left pipe */ - /* Need at least 16 pixels width per side */ - if (sd->recout.x + 16 >= sd->h_active) - return false; - new_width = sd->h_active - sd->recout.x; - sd->viewport.width -= dc_fixpt_floor(dc_fixpt_mul_int( - sd->ratios.horz, sd->recout.width - new_width)); - sd->viewport_c.width -= dc_fixpt_floor(dc_fixpt_mul_int( - sd->ratios.horz_c, sd->recout.width - new_width)); - sd->recout.width = new_width; - - /* Calculate new vp and recout for right pipe */ - sd = &next_odm_pipe->plane_res.scl_data; - /* HACTIVE halved for odm combine */ - sd->h_active /= 2; - /* Need at least 16 pixels width per side */ - if (new_width <= 16) - return false; - new_width = sd->recout.width + sd->recout.x - sd->h_active; - sd->viewport.width -= dc_fixpt_floor(dc_fixpt_mul_int( - sd->ratios.horz, sd->recout.width - new_width)); - sd->viewport_c.width -= dc_fixpt_floor(dc_fixpt_mul_int( - sd->ratios.horz_c, sd->recout.width - new_width)); - sd->recout.width = new_width; - sd->viewport.x += dc_fixpt_floor(dc_fixpt_mul_int( - sd->ratios.horz, sd->h_active - sd->recout.x)); - sd->viewport_c.x += dc_fixpt_floor(dc_fixpt_mul_int( - sd->ratios.horz_c, sd->h_active - sd->recout.x)); - sd->recout.x = 0; - } - if (!next_odm_pipe->top_pipe) - next_odm_pipe->stream_res.opp = pool->opps[next_odm_pipe->pipe_idx]; - else - next_odm_pipe->stream_res.opp = next_odm_pipe->top_pipe->stream_res.opp; - if (next_odm_pipe->stream->timing.flags.DSC == 1 && !next_odm_pipe->top_pipe) { - dcn20_acquire_dsc(dc, res_ctx, &next_odm_pipe->stream_res.dsc, next_odm_pipe->pipe_idx); - ASSERT(next_odm_pipe->stream_res.dsc); - if (next_odm_pipe->stream_res.dsc == NULL) - return false; - } - - return true; -} - -void dcn20_split_stream_for_mpc( - struct resource_context *res_ctx, - const struct resource_pool *pool, - struct pipe_ctx *primary_pipe, - struct pipe_ctx *secondary_pipe) -{ - int pipe_idx = secondary_pipe->pipe_idx; - struct pipe_ctx *sec_bot_pipe = secondary_pipe->bottom_pipe; - - *secondary_pipe = *primary_pipe; - secondary_pipe->bottom_pipe = sec_bot_pipe; - - secondary_pipe->pipe_idx = pipe_idx; - secondary_pipe->plane_res.mi = pool->mis[secondary_pipe->pipe_idx]; - secondary_pipe->plane_res.hubp = pool->hubps[secondary_pipe->pipe_idx]; - secondary_pipe->plane_res.ipp = pool->ipps[secondary_pipe->pipe_idx]; - secondary_pipe->plane_res.xfm = pool->transforms[secondary_pipe->pipe_idx]; - secondary_pipe->plane_res.dpp = pool->dpps[secondary_pipe->pipe_idx]; - secondary_pipe->plane_res.mpcc_inst = pool->dpps[secondary_pipe->pipe_idx]->inst; - secondary_pipe->stream_res.dsc = NULL; - if (primary_pipe->bottom_pipe && primary_pipe->bottom_pipe != secondary_pipe) { - ASSERT(!secondary_pipe->bottom_pipe); - secondary_pipe->bottom_pipe = primary_pipe->bottom_pipe; - secondary_pipe->bottom_pipe->top_pipe = secondary_pipe; - } - primary_pipe->bottom_pipe = secondary_pipe; - secondary_pipe->top_pipe = primary_pipe; - - ASSERT(primary_pipe->plane_state); -} - -unsigned int dcn20_calc_max_scaled_time( - unsigned int time_per_pixel, - enum mmhubbub_wbif_mode mode, - unsigned int urgent_watermark) -{ - unsigned int time_per_byte = 0; - unsigned int total_y_free_entry = 0x200; /* two memory piece for luma */ - unsigned int total_c_free_entry = 0x140; /* two memory piece for chroma */ - unsigned int small_free_entry, max_free_entry; - unsigned int buf_lh_capability; - unsigned int max_scaled_time; - - if (mode == PACKED_444) /* packed mode */ - time_per_byte = time_per_pixel/4; - else if (mode == PLANAR_420_8BPC) - time_per_byte = time_per_pixel; - else if (mode == PLANAR_420_10BPC) /* p010 */ - time_per_byte = time_per_pixel * 819/1024; - - if (time_per_byte == 0) - time_per_byte = 1; - - small_free_entry = (total_y_free_entry > total_c_free_entry) ? total_c_free_entry : total_y_free_entry; - max_free_entry = (mode == PACKED_444) ? total_y_free_entry + total_c_free_entry : small_free_entry; - buf_lh_capability = max_free_entry*time_per_byte*32/16; /* there is 4bit fraction */ - max_scaled_time = buf_lh_capability - urgent_watermark; - return max_scaled_time; -} - -void dcn20_set_mcif_arb_params( - struct dc *dc, - struct dc_state *context, - display_e2e_pipe_params_st *pipes, - int pipe_cnt) -{ - enum mmhubbub_wbif_mode wbif_mode; - struct mcif_arb_params *wb_arb_params; - int i, j, dwb_pipe; - - /* Writeback MCIF_WB arbitration parameters */ - dwb_pipe = 0; - for (i = 0; i < dc->res_pool->pipe_count; i++) { - - if (!context->res_ctx.pipe_ctx[i].stream) - continue; - - for (j = 0; j < MAX_DWB_PIPES; j++) { - if (context->res_ctx.pipe_ctx[i].stream->writeback_info[j].wb_enabled == false) - continue; - - //wb_arb_params = &context->res_ctx.pipe_ctx[i].stream->writeback_info[j].mcif_arb_params; - wb_arb_params = &context->bw_ctx.bw.dcn.bw_writeback.mcif_wb_arb[dwb_pipe]; - - if (context->res_ctx.pipe_ctx[i].stream->writeback_info[j].dwb_params.out_format == dwb_scaler_mode_yuv420) { - if (context->res_ctx.pipe_ctx[i].stream->writeback_info[j].dwb_params.output_depth == DWB_OUTPUT_PIXEL_DEPTH_8BPC) - wbif_mode = PLANAR_420_8BPC; - else - wbif_mode = PLANAR_420_10BPC; - } else - wbif_mode = PACKED_444; - - DC_FP_START(); - dcn20_fpu_set_wb_arb_params(wb_arb_params, context, pipes, pipe_cnt, i); - DC_FP_END(); - - wb_arb_params->slice_lines = 32; - wb_arb_params->arbitration_slice = 2; - wb_arb_params->max_scaled_time = dcn20_calc_max_scaled_time(wb_arb_params->time_per_pixel, - wbif_mode, - wb_arb_params->cli_watermark[0]); /* assume 4 watermark sets have the same value */ - - dwb_pipe++; - - if (dwb_pipe >= MAX_DWB_PIPES) - return; - } - if (dwb_pipe >= MAX_DWB_PIPES) - return; - } -} - -bool dcn20_validate_dsc(struct dc *dc, struct dc_state *new_ctx) -{ - int i; - - /* Validate DSC config, dsc count validation is already done */ - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe_ctx = &new_ctx->res_ctx.pipe_ctx[i]; - struct dc_stream_state *stream = pipe_ctx->stream; - struct dsc_config dsc_cfg; - 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++; - - /* Only need to validate top pipe */ - if (pipe_ctx->top_pipe || pipe_ctx->prev_odm_pipe || !stream || !stream->timing.flags.DSC) - continue; - - 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; - dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt; - - if (!pipe_ctx->stream_res.dsc->funcs->dsc_validate_stream(pipe_ctx->stream_res.dsc, &dsc_cfg)) - return false; - } - return true; -} - -struct pipe_ctx *dcn20_find_secondary_pipe(struct dc *dc, - struct resource_context *res_ctx, - const struct resource_pool *pool, - const struct pipe_ctx *primary_pipe) -{ - struct pipe_ctx *secondary_pipe = NULL; - - if (dc && primary_pipe) { - int j; - int preferred_pipe_idx = 0; - - /* first check the prev dc state: - * if this primary pipe has a bottom pipe in prev. state - * and if the bottom pipe is still available (which it should be), - * pick that pipe as secondary - * Same logic applies for ODM pipes - */ - if (dc->current_state->res_ctx.pipe_ctx[primary_pipe->pipe_idx].next_odm_pipe) { - preferred_pipe_idx = dc->current_state->res_ctx.pipe_ctx[primary_pipe->pipe_idx].next_odm_pipe->pipe_idx; - if (res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) { - secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx]; - secondary_pipe->pipe_idx = preferred_pipe_idx; - } - } - if (secondary_pipe == NULL && - dc->current_state->res_ctx.pipe_ctx[primary_pipe->pipe_idx].bottom_pipe) { - preferred_pipe_idx = dc->current_state->res_ctx.pipe_ctx[primary_pipe->pipe_idx].bottom_pipe->pipe_idx; - if (res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) { - secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx]; - secondary_pipe->pipe_idx = preferred_pipe_idx; - } - } - - /* - * if this primary pipe does not have a bottom pipe in prev. state - * start backward and find a pipe that did not used to be a bottom pipe in - * prev. dc state. This way we make sure we keep the same assignment as - * last state and will not have to reprogram every pipe - */ - if (secondary_pipe == NULL) { - for (j = dc->res_pool->pipe_count - 1; j >= 0; j--) { - if (dc->current_state->res_ctx.pipe_ctx[j].top_pipe == NULL - && dc->current_state->res_ctx.pipe_ctx[j].prev_odm_pipe == NULL) { - preferred_pipe_idx = j; - - if (res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) { - secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx]; - secondary_pipe->pipe_idx = preferred_pipe_idx; - break; - } - } - } - } - /* - * We should never hit this assert unless assignments are shuffled around - * if this happens we will prob. hit a vsync tdr - */ - ASSERT(secondary_pipe); - /* - * search backwards for the second pipe to keep pipe - * assignment more consistent - */ - if (secondary_pipe == NULL) { - for (j = dc->res_pool->pipe_count - 1; j >= 0; j--) { - preferred_pipe_idx = j; - - if (res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) { - secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx]; - secondary_pipe->pipe_idx = preferred_pipe_idx; - break; - } - } - } - } - - return secondary_pipe; -} - -void dcn20_merge_pipes_for_validate( - struct dc *dc, - struct dc_state *context) -{ - int i; - - /* merge previously split odm pipes since mode support needs to make the decision */ - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - struct pipe_ctx *odm_pipe = pipe->next_odm_pipe; - - if (pipe->prev_odm_pipe) - continue; - - pipe->next_odm_pipe = NULL; - while (odm_pipe) { - struct pipe_ctx *next_odm_pipe = odm_pipe->next_odm_pipe; - - odm_pipe->plane_state = NULL; - odm_pipe->stream = NULL; - odm_pipe->top_pipe = NULL; - odm_pipe->bottom_pipe = NULL; - odm_pipe->prev_odm_pipe = NULL; - odm_pipe->next_odm_pipe = NULL; - if (odm_pipe->stream_res.dsc) - dcn20_release_dsc(&context->res_ctx, dc->res_pool, &odm_pipe->stream_res.dsc); - /* Clear plane_res and stream_res */ - memset(&odm_pipe->plane_res, 0, sizeof(odm_pipe->plane_res)); - memset(&odm_pipe->stream_res, 0, sizeof(odm_pipe->stream_res)); - odm_pipe = next_odm_pipe; - } - if (pipe->plane_state) - resource_build_scaling_params(pipe); - } - - /* merge previously mpc split pipes since mode support needs to make the decision */ - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - struct pipe_ctx *hsplit_pipe = pipe->bottom_pipe; - - if (!hsplit_pipe || hsplit_pipe->plane_state != pipe->plane_state) - continue; - - pipe->bottom_pipe = hsplit_pipe->bottom_pipe; - if (hsplit_pipe->bottom_pipe) - hsplit_pipe->bottom_pipe->top_pipe = pipe; - hsplit_pipe->plane_state = NULL; - hsplit_pipe->stream = NULL; - hsplit_pipe->top_pipe = NULL; - hsplit_pipe->bottom_pipe = NULL; - - /* Clear plane_res and stream_res */ - memset(&hsplit_pipe->plane_res, 0, sizeof(hsplit_pipe->plane_res)); - memset(&hsplit_pipe->stream_res, 0, sizeof(hsplit_pipe->stream_res)); - if (pipe->plane_state) - resource_build_scaling_params(pipe); - } -} - -int dcn20_validate_apply_pipe_split_flags( - struct dc *dc, - struct dc_state *context, - int vlevel, - int *split, - bool *merge) -{ - int i, pipe_idx, vlevel_split; - int plane_count = 0; - bool force_split = false; - bool avoid_split = dc->debug.pipe_split_policy == MPC_SPLIT_AVOID; - struct vba_vars_st *v = &context->bw_ctx.dml.vba; - int max_mpc_comb = v->maxMpcComb; - - if (context->stream_count > 1) { - if (dc->debug.pipe_split_policy == MPC_SPLIT_AVOID_MULT_DISP) - avoid_split = true; - } else if (dc->debug.force_single_disp_pipe_split) - force_split = true; - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - - /** - * Workaround for avoiding pipe-split in cases where we'd split - * planes that are too small, resulting in splits that aren't - * valid for the scaler. - */ - if (pipe->plane_state && - (pipe->plane_state->dst_rect.width <= 16 || - pipe->plane_state->dst_rect.height <= 16 || - pipe->plane_state->src_rect.width <= 16 || - pipe->plane_state->src_rect.height <= 16)) - avoid_split = true; - - /* TODO: fix dc bugs and remove this split threshold thing */ - if (pipe->stream && !pipe->prev_odm_pipe && - (!pipe->top_pipe || pipe->top_pipe->plane_state != pipe->plane_state)) - ++plane_count; - } - if (plane_count > dc->res_pool->pipe_count / 2) - avoid_split = true; - - /* W/A: Mode timing with borders may not work well with pipe split, avoid for this corner case */ - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - struct dc_crtc_timing timing; - - if (!pipe->stream) - continue; - else { - timing = pipe->stream->timing; - if (timing.h_border_left + timing.h_border_right - + timing.v_border_top + timing.v_border_bottom > 0) { - avoid_split = true; - break; - } - } - } - - /* Avoid split loop looks for lowest voltage level that allows most unsplit pipes possible */ - if (avoid_split) { - for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { - if (!context->res_ctx.pipe_ctx[i].stream) - continue; - - for (vlevel_split = vlevel; vlevel <= context->bw_ctx.dml.soc.num_states; vlevel++) - if (v->NoOfDPP[vlevel][0][pipe_idx] == 1 && - v->ModeSupport[vlevel][0]) - break; - /* Impossible to not split this pipe */ - if (vlevel > context->bw_ctx.dml.soc.num_states) - vlevel = vlevel_split; - else - max_mpc_comb = 0; - pipe_idx++; - } - v->maxMpcComb = max_mpc_comb; - } - - /* Split loop sets which pipe should be split based on dml outputs and dc flags */ - for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - int pipe_plane = v->pipe_plane[pipe_idx]; - bool split4mpc = context->stream_count == 1 && plane_count == 1 - && dc->config.enable_4to1MPC && dc->res_pool->pipe_count >= 4; - - if (!context->res_ctx.pipe_ctx[i].stream) - continue; - - if (split4mpc || v->NoOfDPP[vlevel][max_mpc_comb][pipe_plane] == 4) - split[i] = 4; - else if (force_split || v->NoOfDPP[vlevel][max_mpc_comb][pipe_plane] == 2) - split[i] = 2; - - if ((pipe->stream->view_format == - VIEW_3D_FORMAT_SIDE_BY_SIDE || - pipe->stream->view_format == - VIEW_3D_FORMAT_TOP_AND_BOTTOM) && - (pipe->stream->timing.timing_3d_format == - TIMING_3D_FORMAT_TOP_AND_BOTTOM || - pipe->stream->timing.timing_3d_format == - TIMING_3D_FORMAT_SIDE_BY_SIDE)) - split[i] = 2; - if (dc->debug.force_odm_combine & (1 << pipe->stream_res.tg->inst)) { - split[i] = 2; - v->ODMCombineEnablePerState[vlevel][pipe_plane] = dm_odm_combine_mode_2to1; - } - if (dc->debug.force_odm_combine_4to1 & (1 << pipe->stream_res.tg->inst)) { - split[i] = 4; - v->ODMCombineEnablePerState[vlevel][pipe_plane] = dm_odm_combine_mode_4to1; - } - /*420 format workaround*/ - if (pipe->stream->timing.h_addressable > 7680 && - pipe->stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) { - split[i] = 4; - } - v->ODMCombineEnabled[pipe_plane] = - v->ODMCombineEnablePerState[vlevel][pipe_plane]; - - if (v->ODMCombineEnabled[pipe_plane] == dm_odm_combine_mode_disabled) { - if (resource_get_mpc_slice_count(pipe) == 2) { - /*If need split for mpc but 2 way split already*/ - if (split[i] == 4) - split[i] = 2; /* 2 -> 4 MPC */ - else if (split[i] == 2) - split[i] = 0; /* 2 -> 2 MPC */ - else if (pipe->top_pipe && pipe->top_pipe->plane_state == pipe->plane_state) - merge[i] = true; /* 2 -> 1 MPC */ - } else if (resource_get_mpc_slice_count(pipe) == 4) { - /*If need split for mpc but 4 way split already*/ - if (split[i] == 2 && ((pipe->top_pipe && !pipe->top_pipe->top_pipe) - || !pipe->bottom_pipe)) { - merge[i] = true; /* 4 -> 2 MPC */ - } else if (split[i] == 0 && pipe->top_pipe && - pipe->top_pipe->plane_state == pipe->plane_state) - merge[i] = true; /* 4 -> 1 MPC */ - split[i] = 0; - } else if (resource_get_odm_slice_count(pipe) > 1) { - /* ODM -> MPC transition */ - if (pipe->prev_odm_pipe) { - split[i] = 0; - merge[i] = true; - } - } - } else { - if (resource_get_odm_slice_count(pipe) == 2) { - /*If need split for odm but 2 way split already*/ - if (split[i] == 4) - split[i] = 2; /* 2 -> 4 ODM */ - else if (split[i] == 2) - split[i] = 0; /* 2 -> 2 ODM */ - else if (pipe->prev_odm_pipe) { - ASSERT(0); /* NOT expected yet */ - merge[i] = true; /* exit ODM */ - } - } else if (resource_get_odm_slice_count(pipe) == 4) { - /*If need split for odm but 4 way split already*/ - if (split[i] == 2 && ((pipe->prev_odm_pipe && !pipe->prev_odm_pipe->prev_odm_pipe) - || !pipe->next_odm_pipe)) { - merge[i] = true; /* 4 -> 2 ODM */ - } else if (split[i] == 0 && pipe->prev_odm_pipe) { - ASSERT(0); /* NOT expected yet */ - merge[i] = true; /* exit ODM */ - } - split[i] = 0; - } else if (resource_get_mpc_slice_count(pipe) > 1) { - /* MPC -> ODM transition */ - ASSERT(0); /* NOT expected yet */ - if (pipe->top_pipe && pipe->top_pipe->plane_state == pipe->plane_state) { - split[i] = 0; - merge[i] = true; - } - } - } - - /* Adjust dppclk when split is forced, do not bother with dispclk */ - if (split[i] != 0 && v->NoOfDPP[vlevel][max_mpc_comb][pipe_idx] == 1) { - DC_FP_START(); - dcn20_fpu_adjust_dppclk(v, vlevel, max_mpc_comb, pipe_idx, false); - DC_FP_END(); - } - pipe_idx++; - } - - return vlevel; -} - -bool dcn20_fast_validate_bw( - struct dc *dc, - struct dc_state *context, - display_e2e_pipe_params_st *pipes, - int *pipe_cnt_out, - int *pipe_split_from, - int *vlevel_out, - bool fast_validate) -{ - bool out = false; - int split[MAX_PIPES] = { 0 }; - int pipe_cnt, i, pipe_idx, vlevel; - - ASSERT(pipes); - if (!pipes) - return false; - - dcn20_merge_pipes_for_validate(dc, context); - - DC_FP_START(); - pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, context, pipes, fast_validate); - DC_FP_END(); - - *pipe_cnt_out = pipe_cnt; - - if (!pipe_cnt) { - out = true; - goto validate_out; - } - - vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt); - - if (vlevel > context->bw_ctx.dml.soc.num_states) - goto validate_fail; - - vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, vlevel, split, NULL); - - /*initialize pipe_just_split_from to invalid idx*/ - for (i = 0; i < MAX_PIPES; i++) - pipe_split_from[i] = -1; - - for (i = 0, pipe_idx = -1; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - struct pipe_ctx *hsplit_pipe = pipe->bottom_pipe; - - if (!pipe->stream || pipe_split_from[i] >= 0) - continue; - - pipe_idx++; - - if (!pipe->top_pipe && !pipe->plane_state && context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_idx]) { - hsplit_pipe = dcn20_find_secondary_pipe(dc, &context->res_ctx, dc->res_pool, pipe); - ASSERT(hsplit_pipe); - if (!dcn20_split_stream_for_odm( - dc, &context->res_ctx, - pipe, hsplit_pipe)) - goto validate_fail; - pipe_split_from[hsplit_pipe->pipe_idx] = pipe_idx; - dcn20_build_mapped_resource(dc, context, pipe->stream); - } - - if (!pipe->plane_state) - continue; - /* Skip 2nd half of already split pipe */ - if (pipe->top_pipe && pipe->plane_state == pipe->top_pipe->plane_state) - continue; - - /* We do not support mpo + odm at the moment */ - if (hsplit_pipe && hsplit_pipe->plane_state != pipe->plane_state - && context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_idx]) - goto validate_fail; - - if (split[i] == 2) { - if (!hsplit_pipe || hsplit_pipe->plane_state != pipe->plane_state) { - /* pipe not split previously needs split */ - hsplit_pipe = dcn20_find_secondary_pipe(dc, &context->res_ctx, dc->res_pool, pipe); - ASSERT(hsplit_pipe); - if (!hsplit_pipe) { - DC_FP_START(); - dcn20_fpu_adjust_dppclk(&context->bw_ctx.dml.vba, vlevel, context->bw_ctx.dml.vba.maxMpcComb, pipe_idx, true); - DC_FP_END(); - continue; - } - if (context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_idx]) { - if (!dcn20_split_stream_for_odm( - dc, &context->res_ctx, - pipe, hsplit_pipe)) - goto validate_fail; - dcn20_build_mapped_resource(dc, context, pipe->stream); - } else { - dcn20_split_stream_for_mpc( - &context->res_ctx, dc->res_pool, - pipe, hsplit_pipe); - resource_build_scaling_params(pipe); - resource_build_scaling_params(hsplit_pipe); - } - pipe_split_from[hsplit_pipe->pipe_idx] = pipe_idx; - } - } else if (hsplit_pipe && hsplit_pipe->plane_state == pipe->plane_state) { - /* merge should already have been done */ - ASSERT(0); - } - } - /* Actual dsc count per stream dsc validation*/ - if (!dcn20_validate_dsc(dc, context)) { - context->bw_ctx.dml.vba.ValidationStatus[context->bw_ctx.dml.vba.soc.num_states] = - DML_FAIL_DSC_VALIDATION_FAILURE; - goto validate_fail; - } - - *vlevel_out = vlevel; - - out = true; - goto validate_out; - -validate_fail: - out = false; - -validate_out: - return out; -} - -bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, - bool fast_validate) -{ - bool voltage_supported; - display_e2e_pipe_params_st *pipes; - - pipes = kcalloc(dc->res_pool->pipe_count, sizeof(display_e2e_pipe_params_st), GFP_KERNEL); - if (!pipes) - return false; - - DC_FP_START(); - voltage_supported = dcn20_validate_bandwidth_fp(dc, context, fast_validate, pipes); - DC_FP_END(); - - kfree(pipes); - return voltage_supported; -} - -struct pipe_ctx *dcn20_acquire_free_pipe_for_layer( - const struct dc_state *cur_ctx, - struct dc_state *new_ctx, - const struct resource_pool *pool, - const struct pipe_ctx *opp_head) -{ - struct resource_context *res_ctx = &new_ctx->res_ctx; - struct pipe_ctx *otg_master = resource_get_otg_master_for_stream(res_ctx, opp_head->stream); - struct pipe_ctx *sec_dpp_pipe = resource_find_free_secondary_pipe_legacy(res_ctx, pool, otg_master); - - ASSERT(otg_master); - - if (!sec_dpp_pipe) - return NULL; - - sec_dpp_pipe->stream = opp_head->stream; - sec_dpp_pipe->stream_res.tg = opp_head->stream_res.tg; - sec_dpp_pipe->stream_res.opp = opp_head->stream_res.opp; - - sec_dpp_pipe->plane_res.hubp = pool->hubps[sec_dpp_pipe->pipe_idx]; - sec_dpp_pipe->plane_res.ipp = pool->ipps[sec_dpp_pipe->pipe_idx]; - sec_dpp_pipe->plane_res.dpp = pool->dpps[sec_dpp_pipe->pipe_idx]; - sec_dpp_pipe->plane_res.mpcc_inst = pool->dpps[sec_dpp_pipe->pipe_idx]->inst; - - return sec_dpp_pipe; -} - -bool dcn20_get_dcc_compression_cap(const struct dc *dc, - const struct dc_dcc_surface_param *input, - struct dc_surface_dcc_cap *output) -{ - return dc->res_pool->hubbub->funcs->get_dcc_compression_cap( - dc->res_pool->hubbub, - input, - output); -} - -static void dcn20_destroy_resource_pool(struct resource_pool **pool) -{ - struct dcn20_resource_pool *dcn20_pool = TO_DCN20_RES_POOL(*pool); - - dcn20_resource_destruct(dcn20_pool); - kfree(dcn20_pool); - *pool = NULL; -} - - -static struct dc_cap_funcs cap_funcs = { - .get_dcc_compression_cap = dcn20_get_dcc_compression_cap -}; - - -enum dc_status dcn20_patch_unknown_plane_state(struct dc_plane_state *plane_state) -{ - enum surface_pixel_format surf_pix_format = plane_state->format; - unsigned int bpp = resource_pixel_format_to_bpp(surf_pix_format); - - plane_state->tiling_info.gfx9.swizzle = DC_SW_64KB_S; - if (bpp == 64) - plane_state->tiling_info.gfx9.swizzle = DC_SW_64KB_D; - - return DC_OK; -} - -void dcn20_release_pipe(struct dc_state *context, - struct pipe_ctx *pipe, - const struct resource_pool *pool) -{ - if (resource_is_pipe_type(pipe, OPP_HEAD) && pipe->stream_res.dsc) - dcn20_release_dsc(&context->res_ctx, pool, &pipe->stream_res.dsc); - memset(pipe, 0, sizeof(*pipe)); -} - -static const struct resource_funcs dcn20_res_pool_funcs = { - .destroy = dcn20_destroy_resource_pool, - .link_enc_create = dcn20_link_encoder_create, - .panel_cntl_create = dcn20_panel_cntl_create, - .validate_bandwidth = dcn20_validate_bandwidth, - .acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer, - .release_pipe = dcn20_release_pipe, - .add_stream_to_ctx = dcn20_add_stream_to_ctx, - .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource, - .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, - .populate_dml_writeback_from_context = dcn20_populate_dml_writeback_from_context, - .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, - .set_mcif_arb_params = dcn20_set_mcif_arb_params, - .populate_dml_pipes = dcn20_populate_dml_pipes_from_context, - .find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link -}; - -bool dcn20_dwbc_create(struct dc_context *ctx, struct resource_pool *pool) -{ - int i; - uint32_t pipe_count = pool->res_cap->num_dwb; - - for (i = 0; i < pipe_count; i++) { - struct dcn20_dwbc *dwbc20 = kzalloc(sizeof(struct dcn20_dwbc), - GFP_KERNEL); - - if (!dwbc20) { - dm_error("DC: failed to create dwbc20!\n"); - return false; - } - dcn20_dwbc_construct(dwbc20, ctx, - &dwbc20_regs[i], - &dwbc20_shift, - &dwbc20_mask, - i); - pool->dwbc[i] = &dwbc20->base; - } - return true; -} - -bool dcn20_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool) -{ - int i; - uint32_t pipe_count = pool->res_cap->num_dwb; - - ASSERT(pipe_count > 0); - - for (i = 0; i < pipe_count; i++) { - struct dcn20_mmhubbub *mcif_wb20 = kzalloc(sizeof(struct dcn20_mmhubbub), - GFP_KERNEL); - - if (!mcif_wb20) { - dm_error("DC: failed to create mcif_wb20!\n"); - return false; - } - - dcn20_mmhubbub_construct(mcif_wb20, ctx, - &mcif_wb20_regs[i], - &mcif_wb20_shift, - &mcif_wb20_mask, - i); - - pool->mcif_wb[i] = &mcif_wb20->base; - } - return true; -} - -static struct pp_smu_funcs *dcn20_pp_smu_create(struct dc_context *ctx) -{ - struct pp_smu_funcs *pp_smu = kzalloc(sizeof(*pp_smu), GFP_ATOMIC); - - if (!pp_smu) - return pp_smu; - - dm_pp_get_funcs(ctx, pp_smu); - - if (pp_smu->ctx.ver != PP_SMU_VER_NV) - pp_smu = memset(pp_smu, 0, sizeof(struct pp_smu_funcs)); - - return pp_smu; -} - -static void dcn20_pp_smu_destroy(struct pp_smu_funcs **pp_smu) -{ - if (pp_smu && *pp_smu) { - kfree(*pp_smu); - *pp_smu = NULL; - } -} - -static struct _vcs_dpi_soc_bounding_box_st *get_asic_rev_soc_bb( - uint32_t hw_internal_rev) -{ - if (ASICREV_IS_NAVI14_M(hw_internal_rev)) - return &dcn2_0_nv14_soc; - - if (ASICREV_IS_NAVI12_P(hw_internal_rev)) - return &dcn2_0_nv12_soc; - - return &dcn2_0_soc; -} - -static struct _vcs_dpi_ip_params_st *get_asic_rev_ip_params( - uint32_t hw_internal_rev) -{ - /* NV14 */ - if (ASICREV_IS_NAVI14_M(hw_internal_rev)) - return &dcn2_0_nv14_ip; - - /* NV12 and NV10 */ - return &dcn2_0_ip; -} - -static enum dml_project get_dml_project_version(uint32_t hw_internal_rev) -{ - return DML_PROJECT_NAVI10v2; -} - -static bool init_soc_bounding_box(struct dc *dc, - struct dcn20_resource_pool *pool) -{ - struct _vcs_dpi_soc_bounding_box_st *loaded_bb = - get_asic_rev_soc_bb(dc->ctx->asic_id.hw_internal_rev); - struct _vcs_dpi_ip_params_st *loaded_ip = - get_asic_rev_ip_params(dc->ctx->asic_id.hw_internal_rev); - - DC_LOGGER_INIT(dc->ctx->logger); - - if (pool->base.pp_smu) { - struct pp_smu_nv_clock_table max_clocks = {0}; - unsigned int uclk_states[8] = {0}; - unsigned int num_states = 0; - enum pp_smu_status status; - bool clock_limits_available = false; - bool uclk_states_available = false; - - if (pool->base.pp_smu->nv_funcs.get_uclk_dpm_states) { - status = (pool->base.pp_smu->nv_funcs.get_uclk_dpm_states) - (&pool->base.pp_smu->nv_funcs.pp_smu, uclk_states, &num_states); - - uclk_states_available = (status == PP_SMU_RESULT_OK); - } - - if (pool->base.pp_smu->nv_funcs.get_maximum_sustainable_clocks) { - status = (*pool->base.pp_smu->nv_funcs.get_maximum_sustainable_clocks) - (&pool->base.pp_smu->nv_funcs.pp_smu, &max_clocks); - /* SMU cannot set DCF clock to anything equal to or higher than SOC clock - */ - if (max_clocks.dcfClockInKhz >= max_clocks.socClockInKhz) - max_clocks.dcfClockInKhz = max_clocks.socClockInKhz - 1000; - clock_limits_available = (status == PP_SMU_RESULT_OK); - } - - if (clock_limits_available && uclk_states_available && num_states) { - DC_FP_START(); - dcn20_update_bounding_box(dc, loaded_bb, &max_clocks, uclk_states, num_states); - DC_FP_END(); - } else if (clock_limits_available) { - DC_FP_START(); - dcn20_cap_soc_clocks(loaded_bb, max_clocks); - DC_FP_END(); - } - } - - loaded_ip->max_num_otg = pool->base.res_cap->num_timing_generator; - loaded_ip->max_num_dpp = pool->base.pipe_count; - DC_FP_START(); - dcn20_patch_bounding_box(dc, loaded_bb); - DC_FP_END(); - return true; -} - -static bool dcn20_resource_construct( - uint8_t num_virtual_links, - struct dc *dc, - struct dcn20_resource_pool *pool) -{ - int i; - struct dc_context *ctx = dc->ctx; - struct irq_service_init_data init_data; - struct ddc_service_init_data ddc_init_data = {0}; - struct _vcs_dpi_soc_bounding_box_st *loaded_bb = - get_asic_rev_soc_bb(ctx->asic_id.hw_internal_rev); - struct _vcs_dpi_ip_params_st *loaded_ip = - get_asic_rev_ip_params(ctx->asic_id.hw_internal_rev); - enum dml_project dml_project_version = - get_dml_project_version(ctx->asic_id.hw_internal_rev); - - ctx->dc_bios->regs = &bios_regs; - pool->base.funcs = &dcn20_res_pool_funcs; - - if (ASICREV_IS_NAVI14_M(ctx->asic_id.hw_internal_rev)) { - pool->base.res_cap = &res_cap_nv14; - pool->base.pipe_count = 5; - pool->base.mpcc_count = 5; - } else { - pool->base.res_cap = &res_cap_nv10; - pool->base.pipe_count = 6; - pool->base.mpcc_count = 6; - } - /************************************************* - * Resource + asic cap harcoding * - *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; - - dc->caps.max_downscale_ratio = 200; - dc->caps.i2c_speed_in_khz = 100; - dc->caps.i2c_speed_in_khz_hdcp = 100; /*1.4 w/a not applied by default*/ - dc->caps.max_cursor_size = 256; - dc->caps.min_horizontal_blanking_period = 80; - dc->caps.dmdata_alloc_size = 2048; - - dc->caps.max_slave_planes = 1; - dc->caps.max_slave_yuv_planes = 1; - dc->caps.max_slave_rgb_planes = 1; - dc->caps.post_blend_color_processing = true; - dc->caps.force_dp_tps4_for_cp2520 = true; - dc->caps.extended_aux_timeout_support = true; - - /* Color pipeline capabilities */ - dc->caps.color.dpp.dcn_arch = 1; - dc->caps.color.dpp.input_lut_shared = 0; - dc->caps.color.dpp.icsc = 1; - dc->caps.color.dpp.dgam_ram = 1; - dc->caps.color.dpp.dgam_rom_caps.srgb = 1; - dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1; - dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 0; - dc->caps.color.dpp.dgam_rom_caps.pq = 0; - dc->caps.color.dpp.dgam_rom_caps.hlg = 0; - dc->caps.color.dpp.post_csc = 0; - dc->caps.color.dpp.gamma_corr = 0; - dc->caps.color.dpp.dgam_rom_for_yuv = 1; - - dc->caps.color.dpp.hw_3d_lut = 1; - dc->caps.color.dpp.ogam_ram = 1; - // no OGAM ROM on DCN2, only MPC ROM - dc->caps.color.dpp.ogam_rom_caps.srgb = 0; - dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0; - dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0; - dc->caps.color.dpp.ogam_rom_caps.pq = 0; - dc->caps.color.dpp.ogam_rom_caps.hlg = 0; - dc->caps.color.dpp.ocsc = 0; - - dc->caps.color.mpc.gamut_remap = 0; - dc->caps.color.mpc.num_3dluts = 0; - dc->caps.color.mpc.shared_3d_lut = 0; - dc->caps.color.mpc.ogam_ram = 1; - dc->caps.color.mpc.ogam_rom_caps.srgb = 0; - dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0; - dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0; - dc->caps.color.mpc.ogam_rom_caps.pq = 0; - dc->caps.color.mpc.ogam_rom_caps.hlg = 0; - dc->caps.color.mpc.ocsc = 1; - - dc->caps.dp_hdmi21_pcon_support = true; - - if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) - dc->debug = debug_defaults_drv; - - //dcn2.0x - dc->work_arounds.dedcn20_305_wa = true; - - // Init the vm_helper - if (dc->vm_helper) - vm_helper_init(dc->vm_helper, 16); - - /************************************************* - * Create resources * - *************************************************/ - - pool->base.clock_sources[DCN20_CLK_SRC_PLL0] = - dcn20_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL0, - &clk_src_regs[0], false); - pool->base.clock_sources[DCN20_CLK_SRC_PLL1] = - dcn20_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL1, - &clk_src_regs[1], false); - pool->base.clock_sources[DCN20_CLK_SRC_PLL2] = - dcn20_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL2, - &clk_src_regs[2], false); - pool->base.clock_sources[DCN20_CLK_SRC_PLL3] = - dcn20_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL3, - &clk_src_regs[3], false); - pool->base.clock_sources[DCN20_CLK_SRC_PLL4] = - dcn20_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL4, - &clk_src_regs[4], false); - pool->base.clock_sources[DCN20_CLK_SRC_PLL5] = - dcn20_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL5, - &clk_src_regs[5], false); - pool->base.clk_src_count = DCN20_CLK_SRC_TOTAL; - /* todo: not reuse phy_pll registers */ - pool->base.dp_clock_source = - dcn20_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_ID_DP_DTO, - &clk_src_regs[0], true); - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] == NULL) { - dm_error("DC: failed to create clock sources!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - } - - pool->base.dccg = dccg2_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask); - if (pool->base.dccg == NULL) { - dm_error("DC: failed to create dccg!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - - pool->base.dmcu = dcn20_dmcu_create(ctx, - &dmcu_regs, - &dmcu_shift, - &dmcu_mask); - if (pool->base.dmcu == NULL) { - dm_error("DC: failed to create dmcu!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - - pool->base.abm = dce_abm_create(ctx, - &abm_regs, - &abm_shift, - &abm_mask); - if (pool->base.abm == NULL) { - dm_error("DC: failed to create abm!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - - pool->base.pp_smu = dcn20_pp_smu_create(ctx); - - - if (!init_soc_bounding_box(dc, pool)) { - dm_error("DC: failed to initialize soc bounding box!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - - dml_init_instance(&dc->dml, loaded_bb, loaded_ip, dml_project_version); - - if (!dc->debug.disable_pplib_wm_range) { - struct pp_smu_wm_range_sets ranges = {0}; - int i = 0; - - ranges.num_reader_wm_sets = 0; - - if (loaded_bb->num_states == 1) { - ranges.reader_wm_sets[0].wm_inst = i; - ranges.reader_wm_sets[0].min_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; - ranges.reader_wm_sets[0].max_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; - ranges.reader_wm_sets[0].min_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; - ranges.reader_wm_sets[0].max_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; - - ranges.num_reader_wm_sets = 1; - } else if (loaded_bb->num_states > 1) { - for (i = 0; i < 4 && i < loaded_bb->num_states; i++) { - ranges.reader_wm_sets[i].wm_inst = i; - ranges.reader_wm_sets[i].min_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; - ranges.reader_wm_sets[i].max_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; - DC_FP_START(); - dcn20_fpu_set_wm_ranges(i, &ranges, loaded_bb); - DC_FP_END(); - - ranges.num_reader_wm_sets = i + 1; - } - - ranges.reader_wm_sets[0].min_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; - ranges.reader_wm_sets[ranges.num_reader_wm_sets - 1].max_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; - } - - ranges.num_writer_wm_sets = 1; - - ranges.writer_wm_sets[0].wm_inst = 0; - ranges.writer_wm_sets[0].min_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; - ranges.writer_wm_sets[0].max_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; - ranges.writer_wm_sets[0].min_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; - ranges.writer_wm_sets[0].max_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; - - /* Notify PP Lib/SMU which Watermarks to use for which clock ranges */ - if (pool->base.pp_smu->nv_funcs.set_wm_ranges) - pool->base.pp_smu->nv_funcs.set_wm_ranges(&pool->base.pp_smu->nv_funcs.pp_smu, &ranges); - } - - init_data.ctx = dc->ctx; - pool->base.irqs = dal_irq_service_dcn20_create(&init_data); - if (!pool->base.irqs) - goto create_fail; - - /* mem input -> ipp -> dpp -> opp -> TG */ - for (i = 0; i < pool->base.pipe_count; i++) { - pool->base.hubps[i] = dcn20_hubp_create(ctx, i); - if (pool->base.hubps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create memory input!\n"); - goto create_fail; - } - - pool->base.ipps[i] = dcn20_ipp_create(ctx, i); - if (pool->base.ipps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create input pixel processor!\n"); - goto create_fail; - } - - pool->base.dpps[i] = dcn20_dpp_create(ctx, i); - if (pool->base.dpps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create dpps!\n"); - goto create_fail; - } - } - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - pool->base.engines[i] = dcn20_aux_engine_create(ctx, i); - if (pool->base.engines[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create aux engine!!\n"); - goto create_fail; - } - pool->base.hw_i2cs[i] = dcn20_i2c_hw_create(ctx, i); - if (pool->base.hw_i2cs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create hw i2c!!\n"); - goto create_fail; - } - pool->base.sw_i2cs[i] = NULL; - } - - for (i = 0; i < pool->base.res_cap->num_opp; i++) { - pool->base.opps[i] = dcn20_opp_create(ctx, i); - if (pool->base.opps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create output pixel processor!\n"); - goto create_fail; - } - } - - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - pool->base.timing_generators[i] = dcn20_timing_generator_create( - ctx, i); - if (pool->base.timing_generators[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create tg!\n"); - goto create_fail; - } - } - - pool->base.timing_generator_count = i; - - pool->base.mpc = dcn20_mpc_create(ctx); - if (pool->base.mpc == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create mpc!\n"); - goto create_fail; - } - - pool->base.hubbub = dcn20_hubbub_create(ctx); - if (pool->base.hubbub == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create hubbub!\n"); - goto create_fail; - } - - for (i = 0; i < pool->base.res_cap->num_dsc; i++) { - pool->base.dscs[i] = dcn20_dsc_create(ctx, i); - if (pool->base.dscs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create display stream compressor %d!\n", i); - goto create_fail; - } - } - - if (!dcn20_dwbc_create(ctx, &pool->base)) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create dwbc!\n"); - goto create_fail; - } - if (!dcn20_mmhubbub_create(ctx, &pool->base)) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create mcif_wb!\n"); - goto create_fail; - } - - if (!resource_construct(num_virtual_links, dc, &pool->base, - &res_create_funcs)) - goto create_fail; - - dcn20_hw_sequencer_construct(dc); - - // IF NV12, set PG function pointer to NULL. It's not that - // PG isn't supported for NV12, it's that we don't want to - // program the registers because that will cause more power - // to be consumed. We could have created dcn20_init_hw to get - // the same effect by checking ASIC rev, but there was a - // request at some point to not check ASIC rev on hw sequencer. - if (ASICREV_IS_NAVI12_P(dc->ctx->asic_id.hw_internal_rev)) { - dc->hwseq->funcs.enable_power_gating_plane = NULL; - dc->debug.disable_dpp_power_gate = true; - dc->debug.disable_hubp_power_gate = true; - } - - - dc->caps.max_planes = pool->base.pipe_count; - - for (i = 0; i < dc->caps.max_planes; ++i) - dc->caps.planes[i] = plane_cap; - - 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->base.oem_device = dc->link_srv->create_ddc_service(&ddc_init_data); - } else { - pool->base.oem_device = NULL; - } - - return true; - -create_fail: - - dcn20_resource_destruct(pool); - - return false; -} - -struct resource_pool *dcn20_create_resource_pool( - const struct dc_init_data *init_data, - struct dc *dc) -{ - struct dcn20_resource_pool *pool = - kzalloc(sizeof(struct dcn20_resource_pool), GFP_ATOMIC); - - if (!pool) - return NULL; - - if (dcn20_resource_construct(init_data->num_virtual_links, dc, pool)) - return &pool->base; - - BREAK_TO_DEBUGGER(); - kfree(pool); - return NULL; -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h deleted file mode 100644 index 37ecaccc5d1281..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h +++ /dev/null @@ -1,170 +0,0 @@ -/* -* Copyright 2017 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_RESOURCE_DCN20_H__ -#define __DC_RESOURCE_DCN20_H__ - -#include "core_types.h" -#include "dml/dcn20/dcn20_fpu.h" - -#define TO_DCN20_RES_POOL(pool)\ - container_of(pool, struct dcn20_resource_pool, base) - -struct dc; -struct resource_pool; -struct _vcs_dpi_display_pipe_params_st; - -extern struct _vcs_dpi_ip_params_st dcn2_0_ip; -extern struct _vcs_dpi_ip_params_st dcn2_0_nv14_ip; -extern struct _vcs_dpi_soc_bounding_box_st dcn2_0_soc; -extern struct _vcs_dpi_soc_bounding_box_st dcn2_0_nv14_soc; -extern struct _vcs_dpi_soc_bounding_box_st dcn2_0_nv12_soc; - -struct dcn20_resource_pool { - struct resource_pool base; -}; -struct resource_pool *dcn20_create_resource_pool( - const struct dc_init_data *init_data, - struct dc *dc); - -struct link_encoder *dcn20_link_encoder_create( - struct dc_context *ctx, - const struct encoder_init_data *enc_init_data); - -unsigned int dcn20_calc_max_scaled_time( - unsigned int time_per_pixel, - enum mmhubbub_wbif_mode mode, - unsigned int urgent_watermark); - -struct pipe_ctx *dcn20_acquire_free_pipe_for_layer( - const struct dc_state *cur_ctx, - struct dc_state *new_ctx, - const struct resource_pool *pool, - const struct pipe_ctx *opp_head_pipe); -void dcn20_release_pipe(struct dc_state *context, - struct pipe_ctx *pipe, - const struct resource_pool *pool); -struct stream_encoder *dcn20_stream_encoder_create( - enum engine_id eng_id, - struct dc_context *ctx); - -struct dce_hwseq *dcn20_hwseq_create( - struct dc_context *ctx); - -bool dcn20_get_dcc_compression_cap(const struct dc *dc, - const struct dc_dcc_surface_param *input, - struct dc_surface_dcc_cap *output); - -void dcn20_dpp_destroy(struct dpp **dpp); - -struct dpp *dcn20_dpp_create( - struct dc_context *ctx, - uint32_t inst); - -struct input_pixel_processor *dcn20_ipp_create( - struct dc_context *ctx, uint32_t inst); - -struct output_pixel_processor *dcn20_opp_create( - struct dc_context *ctx, uint32_t inst); - -struct dce_aux *dcn20_aux_engine_create( - struct dc_context *ctx, uint32_t inst); - -struct dce_i2c_hw *dcn20_i2c_hw_create( - struct dc_context *ctx, - uint32_t inst); - -void dcn20_clock_source_destroy(struct clock_source **clk_src); - -struct display_stream_compressor *dcn20_dsc_create( - struct dc_context *ctx, uint32_t inst); -void dcn20_dsc_destroy(struct display_stream_compressor **dsc); - -struct hubp *dcn20_hubp_create( - struct dc_context *ctx, - uint32_t inst); -struct timing_generator *dcn20_timing_generator_create( - struct dc_context *ctx, - uint32_t instance); -struct mpc *dcn20_mpc_create(struct dc_context *ctx); -struct hubbub *dcn20_hubbub_create(struct dc_context *ctx); - -bool dcn20_dwbc_create(struct dc_context *ctx, struct resource_pool *pool); -bool dcn20_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool); - -void dcn20_set_mcif_arb_params( - struct dc *dc, - struct dc_state *context, - display_e2e_pipe_params_st *pipes, - int pipe_cnt); -bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, bool fast_validate); -void dcn20_merge_pipes_for_validate( - struct dc *dc, - struct dc_state *context); -int dcn20_validate_apply_pipe_split_flags( - struct dc *dc, - struct dc_state *context, - int vlevel, - int *split, - bool *merge); -void dcn20_release_dsc(struct resource_context *res_ctx, - const struct resource_pool *pool, - struct display_stream_compressor **dsc); -bool dcn20_validate_dsc(struct dc *dc, struct dc_state *new_ctx); -void dcn20_split_stream_for_mpc( - struct resource_context *res_ctx, - const struct resource_pool *pool, - struct pipe_ctx *primary_pipe, - struct pipe_ctx *secondary_pipe); -bool dcn20_split_stream_for_odm( - const struct dc *dc, - struct resource_context *res_ctx, - struct pipe_ctx *prev_odm_pipe, - struct pipe_ctx *next_odm_pipe); -void dcn20_acquire_dsc(const struct dc *dc, - struct resource_context *res_ctx, - struct display_stream_compressor **dsc, - int pipe_idx); -struct pipe_ctx *dcn20_find_secondary_pipe(struct dc *dc, - struct resource_context *res_ctx, - const struct resource_pool *pool, - const struct pipe_ctx *primary_pipe); -bool dcn20_fast_validate_bw( - struct dc *dc, - struct dc_state *context, - display_e2e_pipe_params_st *pipes, - int *pipe_cnt_out, - int *pipe_split_from, - int *vlevel_out, - bool fast_validate); - -enum dc_status dcn20_build_mapped_resource(const struct dc *dc, struct dc_state *context, struct dc_stream_state *stream); -enum dc_status dcn20_add_stream_to_ctx(struct dc *dc, struct dc_state *new_ctx, struct dc_stream_state *dc_stream); -enum dc_status dcn20_add_dsc_to_stream_resource(struct dc *dc, struct dc_state *dc_ctx, struct dc_stream_state *dc_stream); -enum dc_status dcn20_remove_stream_from_ctx(struct dc *dc, struct dc_state *new_ctx, struct dc_stream_state *dc_stream); -enum dc_status dcn20_patch_unknown_plane_state(struct dc_plane_state *plane_state); - -#endif /* __DC_RESOURCE_DCN20_H__ */ - diff --git a/drivers/gpu/drm/amd/display/dc/dcn201/Makefile b/drivers/gpu/drm/amd/display/dc/dcn201/Makefile index 3a41a97b0729ca..2b0b4f32e13bf8 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn201/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn201/Makefile @@ -1,9 +1,8 @@ # SPDX-License-Identifier: MIT # # Makefile for DCN. -DCN201 = dcn201_init.o dcn201_resource.o \ - dcn201_hubbub.o\ - dcn201_mpc.o dcn201_hubp.o dcn201_opp.o dcn201_optc.o dcn201_dpp.o \ +DCN201 = dcn201_hubbub.o\ + dcn201_mpc.o dcn201_hubp.o dcn201_opp.o dcn201_dpp.o \ dcn201_dccg.o dcn201_link_encoder.o AMD_DAL_DCN201 = $(addprefix $(AMDDALPATH)/dc/dcn201/,$(DCN201)) diff --git a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_init.c b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_init.c deleted file mode 100644 index a13bf6c9386e0a..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_init.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright 2016 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 "dce110/dce110_hwseq.h" -#include "dcn10/dcn10_hwseq.h" -#include "dcn20/dcn20_hwseq.h" -#include "dcn201/dcn201_hwseq.h" -#include "dcn201_init.h" - -static const struct hw_sequencer_funcs dcn201_funcs = { - .program_gamut_remap = dcn10_program_gamut_remap, - .init_hw = dcn201_init_hw, - .power_down_on_boot = NULL, - .apply_ctx_to_hw = dce110_apply_ctx_to_hw, - .apply_ctx_for_surface = NULL, - .program_front_end_for_ctx = dcn20_program_front_end_for_ctx, - .wait_for_pending_cleared = dcn10_wait_for_pending_cleared, - .post_unlock_program_front_end = dcn10_post_unlock_program_front_end, - .update_plane_addr = dcn201_update_plane_addr, - .update_dchub = dcn10_update_dchub, - .update_pending_status = dcn10_update_pending_status, - .program_output_csc = dcn20_program_output_csc, - .enable_accelerated_mode = dce110_enable_accelerated_mode, - .enable_timing_synchronization = dcn10_enable_timing_synchronization, - .enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset, - .update_info_frame = dce110_update_info_frame, - .send_immediate_sdp_message = dcn10_send_immediate_sdp_message, - .enable_stream = dce110_enable_stream, - .disable_stream = dce110_disable_stream, - .unblank_stream = dcn201_unblank_stream, - .blank_stream = dce110_blank_stream, - .enable_audio_stream = dce110_enable_audio_stream, - .disable_audio_stream = dce110_disable_audio_stream, - .disable_plane = dcn10_disable_plane, - .pipe_control_lock = dcn201_pipe_control_lock, - .interdependent_update_lock = dcn10_lock_all_pipes, - .cursor_lock = dcn10_cursor_lock, - .prepare_bandwidth = dcn20_prepare_bandwidth, - .optimize_bandwidth = dcn20_optimize_bandwidth, - .update_bandwidth = dcn20_update_bandwidth, - .set_drr = dcn10_set_drr, - .get_position = dcn10_get_position, - .set_static_screen_control = dcn10_set_static_screen_control, - .setup_stereo = dcn10_setup_stereo, - .set_avmute = dce110_set_avmute, - .log_hw_state = dcn10_log_hw_state, - .get_hw_state = dcn10_get_hw_state, - .clear_status_bits = dcn10_clear_status_bits, - .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, - .edp_backlight_control = dce110_edp_backlight_control, - .edp_power_control = dce110_edp_power_control, - .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, - .setup_periodic_interrupt = dcn10_setup_periodic_interrupt, - .set_clock = dcn10_set_clock, - .get_clock = dcn10_get_clock, - .program_triplebuffer = dcn20_program_triple_buffer, - .dmdata_status_done = dcn20_dmdata_status_done, - .set_dmdata_attributes = dcn201_set_dmdata_attributes, - .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync, - .calc_vupdate_position = dcn10_calc_vupdate_position, - .set_cursor_position = dcn10_set_cursor_position, - .set_cursor_attribute = dcn201_set_cursor_attribute, - .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level, - .set_backlight_level = dce110_set_backlight_level, - .set_abm_immediate_disable = dce110_set_abm_immediate_disable, - .set_pipe = dce110_set_pipe, - .enable_lvds_link_output = dce110_enable_lvds_link_output, - .enable_tmds_link_output = dce110_enable_tmds_link_output, - .enable_dp_link_output = dce110_enable_dp_link_output, - .disable_link_output = dce110_disable_link_output, - .set_disp_pattern_generator = dcn20_set_disp_pattern_generator, - .update_visual_confirm_color = dcn10_update_visual_confirm_color, -}; - -static const struct hwseq_private_funcs dcn201_private_funcs = { - .init_pipes = NULL, - .update_plane_addr = dcn201_update_plane_addr, - .plane_atomic_disconnect = dcn201_plane_atomic_disconnect, - .program_pipe = dcn10_program_pipe, - .update_mpcc = dcn201_update_mpcc, - .set_input_transfer_func = dcn20_set_input_transfer_func, - .set_output_transfer_func = dcn20_set_output_transfer_func, - .power_down = dce110_power_down, - .enable_display_power_gating = dcn10_dummy_display_power_gating, - .blank_pixel_data = dcn20_blank_pixel_data, - .reset_hw_ctx_wrap = dcn10_reset_hw_ctx_wrap, - .enable_stream_timing = dcn20_enable_stream_timing, - .edp_backlight_control = dce110_edp_backlight_control, - .disable_stream_gating = NULL, - .enable_stream_gating = NULL, - .setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt, - .did_underflow_occur = dcn10_did_underflow_occur, - .init_blank = dcn201_init_blank, - .disable_vga = dcn10_disable_vga, - .bios_golden_init = dcn10_bios_golden_init, - .plane_atomic_disable = dcn10_plane_atomic_disable, - .plane_atomic_power_down = dcn10_plane_atomic_power_down, - .enable_power_gating_plane = dcn10_enable_power_gating_plane, - .dpp_pg_control = dcn10_dpp_pg_control, - .hubp_pg_control = dcn10_hubp_pg_control, - .dsc_pg_control = NULL, - .set_hdr_multiplier = dcn10_set_hdr_multiplier, - .verify_allow_pstate_change_high = dcn10_verify_allow_pstate_change_high, - .wait_for_blank_complete = dcn20_wait_for_blank_complete, - .dccg_init = dcn20_dccg_init, - .set_blend_lut = dcn20_set_blend_lut, - .set_shaper_3dlut = dcn20_set_shaper_3dlut, -}; - -void dcn201_hw_sequencer_construct(struct dc *dc) -{ - dc->hwss = dcn201_funcs; - dc->hwseq->funcs = dcn201_private_funcs; -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_init.h b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_init.h deleted file mode 100644 index 1168887b033dee..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_init.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2016 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_DCN201_INIT_H__ -#define __DC_DCN201_INIT_H__ - -struct dc; - -void dcn201_hw_sequencer_construct(struct dc *dc); - -#endif /* __DC_DCN201_INIT_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_optc.c b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_optc.c deleted file mode 100644 index 70fcbec03fb6b7..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_optc.c +++ /dev/null @@ -1,202 +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 - * - */ - -#include "reg_helper.h" -#include "dcn201_optc.h" -#include "dcn10/dcn10_optc.h" -#include "dc.h" - -#define REG(reg)\ - optc1->tg_regs->reg - -#define CTX \ - optc1->base.ctx - -#undef FN -#define FN(reg_name, field_name) \ - optc1->tg_shift->field_name, optc1->tg_mask->field_name - -/*TEMP: Need to figure out inheritance model here.*/ -bool optc201_is_two_pixels_per_containter(const struct dc_crtc_timing *timing) -{ - return optc1_is_two_pixels_per_containter(timing); -} - -static void optc201_triplebuffer_lock(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_SET(OTG_GLOBAL_CONTROL0, 0, - OTG_MASTER_UPDATE_LOCK_SEL, optc->inst); - REG_SET(OTG_VUPDATE_KEEPOUT, 0, - OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, 1); - REG_SET(OTG_MASTER_UPDATE_LOCK, 0, - OTG_MASTER_UPDATE_LOCK, 1); - - REG_WAIT(OTG_MASTER_UPDATE_LOCK, - UPDATE_LOCK_STATUS, 1, - 1, 10); -} - -static void optc201_triplebuffer_unlock(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_SET(OTG_MASTER_UPDATE_LOCK, 0, - OTG_MASTER_UPDATE_LOCK, 0); - REG_SET(OTG_VUPDATE_KEEPOUT, 0, - OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, 0); - -} - -static bool optc201_validate_timing( - struct timing_generator *optc, - const struct dc_crtc_timing *timing) -{ - uint32_t v_blank; - uint32_t h_blank; - uint32_t min_v_blank; - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - ASSERT(timing != NULL); - - v_blank = (timing->v_total - timing->v_addressable - - timing->v_border_top - timing->v_border_bottom); - - h_blank = (timing->h_total - timing->h_addressable - - timing->h_border_right - - timing->h_border_left); - - if (timing->timing_3d_format != TIMING_3D_FORMAT_NONE && - timing->timing_3d_format != TIMING_3D_FORMAT_HW_FRAME_PACKING && - timing->timing_3d_format != TIMING_3D_FORMAT_TOP_AND_BOTTOM && - timing->timing_3d_format != TIMING_3D_FORMAT_SIDE_BY_SIDE && - timing->timing_3d_format != TIMING_3D_FORMAT_FRAME_ALTERNATE && - timing->timing_3d_format != TIMING_3D_FORMAT_INBAND_FA) - return false; - - /* Check maximum number of pixels supported by Timing Generator - * (Currently will never fail, in order to fail needs display which - * needs more than 8192 horizontal and - * more than 8192 vertical total pixels) - */ - if (timing->h_total > optc1->max_h_total || - timing->v_total > optc1->max_v_total) - return false; - - if (h_blank < optc1->min_h_blank) - return false; - - if (timing->h_sync_width < optc1->min_h_sync_width || - timing->v_sync_width < optc1->min_v_sync_width) - return false; - - min_v_blank = timing->flags.INTERLACE?optc1->min_v_blank_interlace:optc1->min_v_blank; - - if (v_blank < min_v_blank) - return false; - - return true; - -} - -static void optc201_get_optc_source(struct timing_generator *optc, - uint32_t *num_of_src_opp, - uint32_t *src_opp_id_0, - uint32_t *src_opp_id_1) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_GET(OPTC_DATA_SOURCE_SELECT, - OPTC_SEG0_SRC_SEL, src_opp_id_0); - - *num_of_src_opp = 1; -} - -static struct timing_generator_funcs dcn201_tg_funcs = { - .validate_timing = optc201_validate_timing, - .program_timing = optc1_program_timing, - .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0, - .setup_vertical_interrupt1 = optc1_setup_vertical_interrupt1, - .setup_vertical_interrupt2 = optc1_setup_vertical_interrupt2, - .program_global_sync = optc1_program_global_sync, - .enable_crtc = optc2_enable_crtc, - .disable_crtc = optc1_disable_crtc, - /* used by enable_timing_synchronization. Not need for FPGA */ - .is_counter_moving = optc1_is_counter_moving, - .get_position = optc1_get_position, - .get_frame_count = optc1_get_vblank_counter, - .get_scanoutpos = optc1_get_crtc_scanoutpos, - .get_otg_active_size = optc1_get_otg_active_size, - .set_early_control = optc1_set_early_control, - /* used by enable_timing_synchronization. Not need for FPGA */ - .wait_for_state = optc1_wait_for_state, - .set_blank = optc1_set_blank, - .is_blanked = optc1_is_blanked, - .set_blank_color = optc1_program_blank_color, - .did_triggered_reset_occur = optc1_did_triggered_reset_occur, - .enable_reset_trigger = optc1_enable_reset_trigger, - .enable_crtc_reset = optc1_enable_crtc_reset, - .disable_reset_trigger = optc1_disable_reset_trigger, - .triplebuffer_lock = optc201_triplebuffer_lock, - .triplebuffer_unlock = optc201_triplebuffer_unlock, - .lock = optc1_lock, - .unlock = optc1_unlock, - .enable_optc_clock = optc1_enable_optc_clock, - .set_drr = optc1_set_drr, - .get_last_used_drr_vtotal = NULL, - .set_vtotal_min_max = optc1_set_vtotal_min_max, - .set_static_screen_control = optc1_set_static_screen_control, - .program_stereo = optc1_program_stereo, - .is_stereo_left_eye = optc1_is_stereo_left_eye, - .set_blank_data_double_buffer = optc1_set_blank_data_double_buffer, - .tg_init = optc1_tg_init, - .is_tg_enabled = optc1_is_tg_enabled, - .is_optc_underflow_occurred = optc1_is_optc_underflow_occurred, - .clear_optc_underflow = optc1_clear_optc_underflow, - .get_crc = optc1_get_crc, - .configure_crc = optc2_configure_crc, - .set_dsc_config = optc2_set_dsc_config, - .set_dwb_source = NULL, - .get_optc_source = optc201_get_optc_source, - .set_vtg_params = optc1_set_vtg_params, - .program_manual_trigger = optc2_program_manual_trigger, - .setup_manual_trigger = optc2_setup_manual_trigger, - .get_hw_timing = optc1_get_hw_timing, -}; - -void dcn201_timing_generator_init(struct optc *optc1) -{ - optc1->base.funcs = &dcn201_tg_funcs; - - optc1->max_h_total = optc1->tg_mask->OTG_H_TOTAL + 1; - optc1->max_v_total = optc1->tg_mask->OTG_V_TOTAL + 1; - - optc1->min_h_blank = 32; - optc1->min_v_blank = 3; - optc1->min_v_blank_interlace = 5; - optc1->min_h_sync_width = 8; - optc1->min_v_sync_width = 1; -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_optc.h b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_optc.h deleted file mode 100644 index e9545b73513abe..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_optc.h +++ /dev/null @@ -1,74 +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 __DC_OPTC_DCN201_H__ -#define __DC_OPTC_DCN201_H__ - -#include "dcn20/dcn20_optc.h" - -#define TG_COMMON_REG_LIST_DCN201(inst) \ - TG_COMMON_REG_LIST_DCN(inst),\ - SRI(OTG_GLOBAL_CONTROL1, OTG, inst),\ - SRI(OTG_GLOBAL_CONTROL2, OTG, inst),\ - SRI(OTG_GSL_WINDOW_X, OTG, inst),\ - SRI(OTG_GSL_WINDOW_Y, OTG, inst),\ - SRI(OTG_VUPDATE_KEEPOUT, OTG, inst),\ - SRI(OTG_DSC_START_POSITION, OTG, inst),\ - SRI(OPTC_DATA_FORMAT_CONTROL, ODM, inst),\ - SRI(OPTC_BYTES_PER_PIXEL, ODM, inst),\ - SRI(OPTC_WIDTH_CONTROL, ODM, inst),\ - SR(DWB_SOURCE_SELECT) - -#define TG_COMMON_MASK_SH_LIST_DCN201(mask_sh)\ - TG_COMMON_MASK_SH_LIST_DCN(mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_X, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_Y, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_EN, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, mask_sh),\ - SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_RANGE_TIMING_DBUF_UPDATE_MODE, mask_sh),\ - SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_START_X, mask_sh),\ - SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_END_X, mask_sh), \ - SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_START_Y, mask_sh),\ - SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_END_Y, mask_sh),\ - SF(OTG0_OTG_VUPDATE_KEEPOUT, OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, mask_sh), \ - SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET, mask_sh), \ - SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET, mask_sh), \ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_MASTER_MODE, mask_sh), \ - SF(OTG0_OTG_GSL_CONTROL, OTG_MASTER_UPDATE_LOCK_GSL_EN, mask_sh), \ - SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_X, mask_sh), \ - SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_LINE_NUM, mask_sh),\ - SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG0_SRC_SEL, mask_sh),\ - SF(ODM0_OPTC_DATA_FORMAT_CONTROL, OPTC_DSC_MODE, mask_sh),\ - SF(ODM0_OPTC_BYTES_PER_PIXEL, OPTC_DSC_BYTES_PER_PIXEL, mask_sh),\ - SF(ODM0_OPTC_WIDTH_CONTROL, OPTC_DSC_SLICE_WIDTH, mask_sh),\ - SF(DWB_SOURCE_SELECT, OPTC_DWB0_SOURCE_SELECT, mask_sh),\ - SF(DWB_SOURCE_SELECT, OPTC_DWB1_SOURCE_SELECT, mask_sh),\ - SF(DWB_SOURCE_SELECT, OPTC_DWB1_SOURCE_SELECT, mask_sh) - -void dcn201_timing_generator_init(struct optc *optc); - -bool optc201_is_two_pixels_per_containter(const struct dc_crtc_timing *timing); - -#endif diff --git a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.c b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.c deleted file mode 100644 index bca22d86769693..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.c +++ /dev/null @@ -1,1308 +0,0 @@ -/* -* Copyright 2016 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 "dcn201_init.h" -#include "dml/dcn20/dcn20_fpu.h" -#include "resource.h" -#include "include/irq_service_interface.h" -#include "dcn201_resource.h" - -#include "dcn20/dcn20_resource.h" - -#include "dcn10/dcn10_hubp.h" -#include "dcn10/dcn10_ipp.h" -#include "dcn201_mpc.h" -#include "dcn201_hubp.h" -#include "irq/dcn201/irq_service_dcn201.h" -#include "dcn201/dcn201_dpp.h" -#include "dcn201/dcn201_hubbub.h" -#include "dcn201_dccg.h" -#include "dcn201_optc.h" -#include "dcn201/dcn201_hwseq.h" -#include "dce110/dce110_hwseq.h" -#include "dcn201_opp.h" -#include "dcn201/dcn201_link_encoder.h" -#include "dcn20/dcn20_stream_encoder.h" -#include "dce/dce_clock_source.h" -#include "dce/dce_audio.h" -#include "dce/dce_hwseq.h" -#include "virtual/virtual_stream_encoder.h" -#include "dce110/dce110_resource.h" -#include "dce/dce_aux.h" -#include "dce/dce_i2c.h" -#include "dcn201_hubbub.h" -#include "dcn10/dcn10_resource.h" - -#include "cyan_skillfish_ip_offset.h" - -#include "dcn/dcn_2_0_3_offset.h" -#include "dcn/dcn_2_0_3_sh_mask.h" -#include "dpcs/dpcs_2_0_3_offset.h" -#include "dpcs/dpcs_2_0_3_sh_mask.h" - -#include "mmhub/mmhub_2_0_0_offset.h" -#include "mmhub/mmhub_2_0_0_sh_mask.h" -#include "nbio/nbio_7_4_offset.h" - -#include "reg_helper.h" - -#define MIN_DISP_CLK_KHZ 100000 -#define MIN_DPP_CLK_KHZ 100000 - -static struct _vcs_dpi_ip_params_st dcn201_ip = { - .gpuvm_enable = 0, - .hostvm_enable = 0, - .gpuvm_max_page_table_levels = 4, - .hostvm_max_page_table_levels = 4, - .hostvm_cached_page_table_levels = 0, - .pte_group_size_bytes = 2048, - .rob_buffer_size_kbytes = 168, - .det_buffer_size_kbytes = 164, - .dpte_buffer_size_in_pte_reqs_luma = 84, - .pde_proc_buffer_size_64k_reqs = 48, - .dpp_output_buffer_pixels = 2560, - .opp_output_buffer_lines = 1, - .pixel_chunk_size_kbytes = 8, - .pte_chunk_size_kbytes = 2, - .meta_chunk_size_kbytes = 2, - .writeback_chunk_size_kbytes = 2, - .line_buffer_size_bits = 789504, - .is_line_buffer_bpp_fixed = 0, - .line_buffer_fixed_bpp = 0, - .dcc_supported = true, - .max_line_buffer_lines = 12, - .writeback_luma_buffer_size_kbytes = 12, - .writeback_chroma_buffer_size_kbytes = 8, - .writeback_chroma_line_buffer_width_pixels = 4, - .writeback_max_hscl_ratio = 1, - .writeback_max_vscl_ratio = 1, - .writeback_min_hscl_ratio = 1, - .writeback_min_vscl_ratio = 1, - .writeback_max_hscl_taps = 12, - .writeback_max_vscl_taps = 12, - .writeback_line_buffer_luma_buffer_size = 0, - .writeback_line_buffer_chroma_buffer_size = 9600, - .cursor_buffer_size = 8, - .cursor_chunk_size = 2, - .max_num_otg = 2, - .max_num_dpp = 4, - .max_num_wb = 0, - .max_dchub_pscl_bw_pix_per_clk = 4, - .max_pscl_lb_bw_pix_per_clk = 2, - .max_lb_vscl_bw_pix_per_clk = 4, - .max_vscl_hscl_bw_pix_per_clk = 4, - .max_hscl_ratio = 8, - .max_vscl_ratio = 8, - .hscl_mults = 4, - .vscl_mults = 4, - .max_hscl_taps = 8, - .max_vscl_taps = 8, - .dispclk_ramp_margin_percent = 1, - .underscan_factor = 1.10, - .min_vblank_lines = 30, - .dppclk_delay_subtotal = 77, - .dppclk_delay_scl_lb_only = 16, - .dppclk_delay_scl = 50, - .dppclk_delay_cnvc_formatter = 8, - .dppclk_delay_cnvc_cursor = 6, - .dispclk_delay_subtotal = 87, - .dcfclk_cstate_latency = 10, - .max_inter_dcn_tile_repeaters = 8, - .number_of_cursors = 1, -}; - -static struct _vcs_dpi_soc_bounding_box_st dcn201_soc = { - .clock_limits = { - { - .state = 0, - .dscclk_mhz = 400.0, - .dcfclk_mhz = 1000.0, - .fabricclk_mhz = 200.0, - .dispclk_mhz = 300.0, - .dppclk_mhz = 300.0, - .phyclk_mhz = 810.0, - .socclk_mhz = 1254.0, - .dram_speed_mts = 2000.0, - }, - { - .state = 1, - .dscclk_mhz = 400.0, - .dcfclk_mhz = 1000.0, - .fabricclk_mhz = 250.0, - .dispclk_mhz = 1200.0, - .dppclk_mhz = 1200.0, - .phyclk_mhz = 810.0, - .socclk_mhz = 1254.0, - .dram_speed_mts = 3600.0, - }, - { - .state = 2, - .dscclk_mhz = 400.0, - .dcfclk_mhz = 1000.0, - .fabricclk_mhz = 750.0, - .dispclk_mhz = 1200.0, - .dppclk_mhz = 1200.0, - .phyclk_mhz = 810.0, - .socclk_mhz = 1254.0, - .dram_speed_mts = 6800.0, - }, - { - .state = 3, - .dscclk_mhz = 400.0, - .dcfclk_mhz = 1000.0, - .fabricclk_mhz = 250.0, - .dispclk_mhz = 1200.0, - .dppclk_mhz = 1200.0, - .phyclk_mhz = 810.0, - .socclk_mhz = 1254.0, - .dram_speed_mts = 14000.0, - }, - { - .state = 4, - .dscclk_mhz = 400.0, - .dcfclk_mhz = 1000.0, - .fabricclk_mhz = 750.0, - .dispclk_mhz = 1200.0, - .dppclk_mhz = 1200.0, - .phyclk_mhz = 810.0, - .socclk_mhz = 1254.0, - .dram_speed_mts = 14000.0, - } - }, - .num_states = 4, - .sr_exit_time_us = 9.0, - .sr_enter_plus_exit_time_us = 11.0, - .urgent_latency_us = 4.0, - .urgent_latency_pixel_data_only_us = 4.0, - .urgent_latency_pixel_mixed_with_vm_data_us = 4.0, - .urgent_latency_vm_data_only_us = 4.0, - .urgent_out_of_order_return_per_channel_pixel_only_bytes = 256, - .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 256, - .urgent_out_of_order_return_per_channel_vm_only_bytes = 256, - .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 80.0, - .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 80.0, - .pct_ideal_dram_sdp_bw_after_urgent_vm_only = 80.0, - .max_avg_sdp_bw_use_normal_percent = 80.0, - .max_avg_dram_bw_use_normal_percent = 69.0, - .writeback_latency_us = 12.0, - .ideal_dram_bw_after_urgent_percent = 80.0, - .max_request_size_bytes = 256, - .dram_channel_width_bytes = 2, - .fabric_datapath_to_dcn_data_return_bytes = 64, - .dcn_downspread_percent = 0.3, - .downspread_percent = 0.3, - .dram_page_open_time_ns = 50.0, - .dram_rw_turnaround_time_ns = 17.5, - .dram_return_buffer_per_channel_bytes = 8192, - .round_trip_ping_latency_dcfclk_cycles = 128, - .urgent_out_of_order_return_per_channel_bytes = 256, - .channel_interleave_bytes = 256, - .num_banks = 8, - .num_chans = 16, - .vmm_page_size_bytes = 4096, - .dram_clock_change_latency_us = 250.0, - .writeback_dram_clock_change_latency_us = 23.0, - .return_bus_width_bytes = 64, - .dispclk_dppclk_vco_speed_mhz = 3000, - .use_urgent_burst_bw = 0, -}; - -enum dcn20_clk_src_array_id { - DCN20_CLK_SRC_PLL0, - DCN20_CLK_SRC_PLL1, - DCN20_CLK_SRC_TOTAL_DCN201 -}; - -/* begin ********************* - * macros to expend register list macro defined in HW object header file */ - -/* DCN */ - -#undef BASE_INNER -#define BASE_INNER(seg) DMU_BASE__INST0_SEG ## seg - -#define BASE(seg) BASE_INNER(seg) - -#define SR(reg_name)\ - .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + \ - mm ## reg_name - -#define SRI(reg_name, block, id)\ - .reg_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name - -#define SRIR(var_name, reg_name, block, id)\ - .var_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name - -#define SRII(reg_name, block, id)\ - .reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name - -#define SRI_IX(reg_name, block, id)\ - .reg_name = ix ## block ## id ## _ ## reg_name - -#define DCCG_SRII(reg_name, block, id)\ - .block ## _ ## reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name - -#define VUPDATE_SRII(reg_name, block, id)\ - .reg_name[id] = BASE(mm ## reg_name ## _ ## block ## id ## _BASE_IDX) + \ - mm ## reg_name ## _ ## block ## id - -/* NBIO */ -#define NBIO_BASE_INNER(seg) \ - NBIO_BASE__INST0_SEG ## seg - -#define NBIO_BASE(seg) \ - NBIO_BASE_INNER(seg) - -#define NBIO_SR(reg_name)\ - .reg_name = NBIO_BASE(mm ## reg_name ## _BASE_IDX) + \ - mm ## reg_name - -/* MMHUB */ -#define MMHUB_BASE_INNER(seg) \ - MMHUB_BASE__INST0_SEG ## seg - -#define MMHUB_BASE(seg) \ - MMHUB_BASE_INNER(seg) - -#define MMHUB_SR(reg_name)\ - .reg_name = MMHUB_BASE(mmMM ## reg_name ## _BASE_IDX) + \ - mmMM ## reg_name - -static const struct bios_registers bios_regs = { - NBIO_SR(BIOS_SCRATCH_3), - NBIO_SR(BIOS_SCRATCH_6) -}; - -#define clk_src_regs(index, pllid)\ -[index] = {\ - CS_COMMON_REG_LIST_DCN201(index, pllid),\ -} - -static const struct dce110_clk_src_regs clk_src_regs[] = { - clk_src_regs(0, A), - clk_src_regs(1, B) -}; - -static const struct dce110_clk_src_shift cs_shift = { - CS_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) -}; - -static const struct dce110_clk_src_mask cs_mask = { - CS_COMMON_MASK_SH_LIST_DCN2_0(_MASK) -}; - -#define audio_regs(id)\ -[id] = {\ - AUD_COMMON_REG_LIST(id)\ -} - -static const struct dce_audio_registers audio_regs[] = { - audio_regs(0), - audio_regs(1), -}; - -#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ - SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ - SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ - AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) - -static const struct dce_audio_shift audio_shift = { - DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_audio_mask audio_mask = { - DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) -}; - -#define stream_enc_regs(id)\ -[id] = {\ - SE_DCN2_REG_LIST(id)\ -} - -static const struct dcn10_stream_enc_registers stream_enc_regs[] = { - stream_enc_regs(0), - stream_enc_regs(1) -}; - -static const struct dcn10_stream_encoder_shift se_shift = { - SE_COMMON_MASK_SH_LIST_DCN20(__SHIFT) -}; - -static const struct dcn10_stream_encoder_mask se_mask = { - SE_COMMON_MASK_SH_LIST_DCN20(_MASK) -}; - -static const struct dce110_aux_registers_shift aux_shift = { - DCN_AUX_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce110_aux_registers_mask aux_mask = { - DCN_AUX_MASK_SH_LIST(_MASK) -}; - -#define aux_regs(id)\ -[id] = {\ - DCN2_AUX_REG_LIST(id)\ -} - -static const struct dcn10_link_enc_aux_registers link_enc_aux_regs[] = { - aux_regs(0), - aux_regs(1), -}; - -#define hpd_regs(id)\ -[id] = {\ - HPD_REG_LIST(id)\ -} - -static const struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[] = { - hpd_regs(0), - hpd_regs(1), -}; - -#define link_regs(id, phyid)\ -[id] = {\ - LE_DCN_COMMON_REG_LIST(id), \ - UNIPHY_DCN2_REG_LIST(phyid) \ -} - -static const struct dcn10_link_enc_registers link_enc_regs[] = { - link_regs(0, A), - link_regs(1, B), -}; - -#define LINK_ENCODER_MASK_SH_LIST_DCN201(mask_sh)\ - LINK_ENCODER_MASK_SH_LIST_DCN20(mask_sh) - -static const struct dcn10_link_enc_shift le_shift = { - LINK_ENCODER_MASK_SH_LIST_DCN201(__SHIFT) -}; - -static const struct dcn10_link_enc_mask le_mask = { - LINK_ENCODER_MASK_SH_LIST_DCN201(_MASK) -}; - -#define ipp_regs(id)\ -[id] = {\ - IPP_REG_LIST_DCN201(id),\ -} - -static const struct dcn10_ipp_registers ipp_regs[] = { - ipp_regs(0), - ipp_regs(1), - ipp_regs(2), - ipp_regs(3), -}; - -static const struct dcn10_ipp_shift ipp_shift = { - IPP_MASK_SH_LIST_DCN201(__SHIFT) -}; - -static const struct dcn10_ipp_mask ipp_mask = { - IPP_MASK_SH_LIST_DCN201(_MASK) -}; - -#define opp_regs(id)\ -[id] = {\ - OPP_REG_LIST_DCN201(id),\ -} - -static const struct dcn201_opp_registers opp_regs[] = { - opp_regs(0), - opp_regs(1), -}; - -static const struct dcn201_opp_shift opp_shift = { - OPP_MASK_SH_LIST_DCN201(__SHIFT) -}; - -static const struct dcn201_opp_mask opp_mask = { - OPP_MASK_SH_LIST_DCN201(_MASK) -}; - -#define aux_engine_regs(id)\ -[id] = {\ - AUX_COMMON_REG_LIST0(id), \ - .AUX_RESET_MASK = 0 \ -} - -static const struct dce110_aux_registers aux_engine_regs[] = { - aux_engine_regs(0), - aux_engine_regs(1) -}; - -#define tf_regs(id)\ -[id] = {\ - TF_REG_LIST_DCN201(id),\ -} - -static const struct dcn201_dpp_registers tf_regs[] = { - tf_regs(0), - tf_regs(1), - tf_regs(2), - tf_regs(3), -}; - -static const struct dcn201_dpp_shift tf_shift = { - TF_REG_LIST_SH_MASK_DCN201(__SHIFT) -}; - -static const struct dcn201_dpp_mask tf_mask = { - TF_REG_LIST_SH_MASK_DCN201(_MASK) -}; - -static const struct dcn201_mpc_registers mpc_regs = { - MPC_REG_LIST_DCN201(0), - MPC_REG_LIST_DCN201(1), - MPC_REG_LIST_DCN201(2), - MPC_REG_LIST_DCN201(3), - MPC_REG_LIST_DCN201(4), - MPC_OUT_MUX_REG_LIST_DCN201(0), - MPC_OUT_MUX_REG_LIST_DCN201(1), -}; - -static const struct dcn201_mpc_shift mpc_shift = { - MPC_COMMON_MASK_SH_LIST_DCN201(__SHIFT) -}; - -static const struct dcn201_mpc_mask mpc_mask = { - MPC_COMMON_MASK_SH_LIST_DCN201(_MASK) -}; - -#define tg_regs_dcn201(id)\ -[id] = {TG_COMMON_REG_LIST_DCN201(id)} - -static const struct dcn_optc_registers tg_regs[] = { - tg_regs_dcn201(0), - tg_regs_dcn201(1) -}; - -static const struct dcn_optc_shift tg_shift = { - TG_COMMON_MASK_SH_LIST_DCN201(__SHIFT) -}; - -static const struct dcn_optc_mask tg_mask = { - TG_COMMON_MASK_SH_LIST_DCN201(_MASK) -}; - -#define hubp_regsDCN201(id)\ -[id] = {\ - HUBP_REG_LIST_DCN201(id)\ -} - -static const struct dcn201_hubp_registers hubp_regs[] = { - hubp_regsDCN201(0), - hubp_regsDCN201(1), - hubp_regsDCN201(2), - hubp_regsDCN201(3) -}; - -static const struct dcn201_hubp_shift hubp_shift = { - HUBP_MASK_SH_LIST_DCN201(__SHIFT) -}; - -static const struct dcn201_hubp_mask hubp_mask = { - HUBP_MASK_SH_LIST_DCN201(_MASK) -}; - -static const struct dcn_hubbub_registers hubbub_reg = { - HUBBUB_REG_LIST_DCN201(0) -}; - -static const struct dcn_hubbub_shift hubbub_shift = { - HUBBUB_MASK_SH_LIST_DCN201(__SHIFT) -}; - -static const struct dcn_hubbub_mask hubbub_mask = { - HUBBUB_MASK_SH_LIST_DCN201(_MASK) -}; - - -static const struct dccg_registers dccg_regs = { - DCCG_COMMON_REG_LIST_DCN_BASE() -}; - -static const struct dccg_shift dccg_shift = { - DCCG_COMMON_MASK_SH_LIST_DCN_COMMON_BASE(__SHIFT) -}; - -static const struct dccg_mask dccg_mask = { - DCCG_COMMON_MASK_SH_LIST_DCN_COMMON_BASE(_MASK) -}; - -static const struct resource_caps res_cap_dnc201 = { - .num_timing_generator = 2, - .num_opp = 2, - .num_video_plane = 4, - .num_audio = 2, - .num_stream_encoder = 2, - .num_pll = 2, - .num_ddc = 2, -}; - -static const struct dc_plane_cap plane_cap = { - .type = DC_PLANE_TYPE_DCN_UNIVERSAL, - .per_pixel_alpha = true, - - .pixel_format_support = { - .argb8888 = true, - .nv12 = false, - .fp16 = true, - .p010 = false, - }, - - .max_upscale_factor = { - .argb8888 = 16000, - .nv12 = 16000, - .fp16 = 1 - }, - - .max_downscale_factor = { - .argb8888 = 250, - .nv12 = 250, - .fp16 = 250 - }, - 64, - 64 -}; - -static const struct dc_debug_options debug_defaults_drv = { - .disable_dmcu = true, - .force_abm_enable = false, - .timing_trace = false, - .clock_trace = true, - .disable_pplib_clock_request = true, - .pipe_split_policy = MPC_SPLIT_DYNAMIC, - .force_single_disp_pipe_split = false, - .disable_dcc = DCC_ENABLE, - .vsr_support = true, - .performance_trace = false, - .az_endpoint_mute_only = true, - .max_downscale_src_width = 3840, - .disable_pplib_wm_range = true, - .scl_reset_length10 = true, - .sanity_checks = false, - .underflow_assert_delay_us = 0xFFFFFFFF, - .enable_tri_buf = false, - .enable_legacy_fast_update = true, - .using_dml2 = false, -}; - -static void dcn201_dpp_destroy(struct dpp **dpp) -{ - kfree(TO_DCN201_DPP(*dpp)); - *dpp = NULL; -} - -static struct dpp *dcn201_dpp_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn201_dpp *dpp = - kzalloc(sizeof(struct dcn201_dpp), GFP_ATOMIC); - - if (!dpp) - return NULL; - - if (dpp201_construct(dpp, ctx, inst, - &tf_regs[inst], &tf_shift, &tf_mask)) - return &dpp->base; - - kfree(dpp); - return NULL; -} - -static struct input_pixel_processor *dcn201_ipp_create( - struct dc_context *ctx, uint32_t inst) -{ - struct dcn10_ipp *ipp = - kzalloc(sizeof(struct dcn10_ipp), GFP_ATOMIC); - - if (!ipp) { - return NULL; - } - - dcn20_ipp_construct(ipp, ctx, inst, - &ipp_regs[inst], &ipp_shift, &ipp_mask); - return &ipp->base; -} - - -static struct output_pixel_processor *dcn201_opp_create( - struct dc_context *ctx, uint32_t inst) -{ - struct dcn201_opp *opp = - kzalloc(sizeof(struct dcn201_opp), GFP_ATOMIC); - - if (!opp) { - return NULL; - } - - dcn201_opp_construct(opp, ctx, inst, - &opp_regs[inst], &opp_shift, &opp_mask); - return &opp->base; -} - -static struct dce_aux *dcn201_aux_engine_create(struct dc_context *ctx, - uint32_t inst) -{ - struct aux_engine_dce110 *aux_engine = - kzalloc(sizeof(struct aux_engine_dce110), GFP_ATOMIC); - - if (!aux_engine) - return NULL; - - dce110_aux_engine_construct(aux_engine, ctx, inst, - SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, - &aux_engine_regs[inst], - &aux_mask, - &aux_shift, - ctx->dc->caps.extended_aux_timeout_support); - - return &aux_engine->base; -} -#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST(id) } - -static const struct dce_i2c_registers i2c_hw_regs[] = { - i2c_inst_regs(1), - i2c_inst_regs(2), -}; - -static const struct dce_i2c_shift i2c_shifts = { - I2C_COMMON_MASK_SH_LIST_DCN2(__SHIFT) -}; - -static const struct dce_i2c_mask i2c_masks = { - I2C_COMMON_MASK_SH_LIST_DCN2(_MASK) -}; - -static struct dce_i2c_hw *dcn201_i2c_hw_create(struct dc_context *ctx, - uint32_t inst) -{ - struct dce_i2c_hw *dce_i2c_hw = - kzalloc(sizeof(struct dce_i2c_hw), GFP_ATOMIC); - - if (!dce_i2c_hw) - return NULL; - - dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst, - &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); - - return dce_i2c_hw; -} - -static struct mpc *dcn201_mpc_create(struct dc_context *ctx, uint32_t num_mpcc) -{ - struct dcn201_mpc *mpc201 = kzalloc(sizeof(struct dcn201_mpc), - GFP_ATOMIC); - - if (!mpc201) - return NULL; - - dcn201_mpc_construct(mpc201, ctx, - &mpc_regs, - &mpc_shift, - &mpc_mask, - num_mpcc); - - return &mpc201->base; -} - -static struct hubbub *dcn201_hubbub_create(struct dc_context *ctx) -{ - struct dcn20_hubbub *hubbub = kzalloc(sizeof(struct dcn20_hubbub), - GFP_ATOMIC); - - if (!hubbub) - return NULL; - - hubbub201_construct(hubbub, ctx, - &hubbub_reg, - &hubbub_shift, - &hubbub_mask); - - return &hubbub->base; -} - -static struct timing_generator *dcn201_timing_generator_create( - struct dc_context *ctx, - uint32_t instance) -{ - struct optc *tgn10 = - kzalloc(sizeof(struct optc), GFP_ATOMIC); - - if (!tgn10) - return NULL; - - tgn10->base.inst = instance; - tgn10->base.ctx = ctx; - - tgn10->tg_regs = &tg_regs[instance]; - tgn10->tg_shift = &tg_shift; - tgn10->tg_mask = &tg_mask; - - dcn201_timing_generator_init(tgn10); - - return &tgn10->base; -} - -static const struct encoder_feature_support link_enc_feature = { - .max_hdmi_deep_color = COLOR_DEPTH_121212, - .max_hdmi_pixel_clock = 600000, - .hdmi_ycbcr420_supported = true, - .dp_ycbcr420_supported = true, - .fec_supported = true, - .flags.bits.IS_HBR2_CAPABLE = true, - .flags.bits.IS_HBR3_CAPABLE = true, - .flags.bits.IS_TPS3_CAPABLE = true, - .flags.bits.IS_TPS4_CAPABLE = true -}; - -static struct link_encoder *dcn201_link_encoder_create( - struct dc_context *ctx, - const struct encoder_init_data *enc_init_data) -{ - struct dcn20_link_encoder *enc20 = - kzalloc(sizeof(struct dcn20_link_encoder), GFP_ATOMIC); - struct dcn10_link_encoder *enc10 = &enc20->enc10; - - if (!enc20) - return NULL; - - dcn201_link_encoder_construct(enc20, - enc_init_data, - &link_enc_feature, - &link_enc_regs[enc_init_data->transmitter], - &link_enc_aux_regs[enc_init_data->channel - 1], - &link_enc_hpd_regs[enc_init_data->hpd_source], - &le_shift, - &le_mask); - - return &enc10->base; -} - -static struct clock_source *dcn201_clock_source_create( - struct dc_context *ctx, - struct dc_bios *bios, - enum clock_source_id id, - const struct dce110_clk_src_regs *regs, - bool dp_clk_src) -{ - struct dce110_clk_src *clk_src = - kzalloc(sizeof(struct dce110_clk_src), GFP_ATOMIC); - - if (!clk_src) - return NULL; - - if (dce112_clk_src_construct(clk_src, ctx, bios, id, - regs, &cs_shift, &cs_mask)) { - clk_src->base.dp_clk_src = dp_clk_src; - return &clk_src->base; - } - kfree(clk_src); - return NULL; -} - -static void read_dce_straps( - struct dc_context *ctx, - struct resource_straps *straps) -{ - generic_reg_get(ctx, mmDC_PINSTRAPS + BASE(mmDC_PINSTRAPS_BASE_IDX), - - FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio); -} - -static struct audio *dcn201_create_audio( - struct dc_context *ctx, unsigned int inst) -{ - return dce_audio_create(ctx, inst, - &audio_regs[inst], &audio_shift, &audio_mask); -} - -static struct stream_encoder *dcn201_stream_encoder_create( - enum engine_id eng_id, - struct dc_context *ctx) -{ - struct dcn10_stream_encoder *enc1 = - kzalloc(sizeof(struct dcn10_stream_encoder), GFP_ATOMIC); - - if (!enc1) - return NULL; - - dcn20_stream_encoder_construct(enc1, ctx, ctx->dc_bios, eng_id, - &stream_enc_regs[eng_id], - &se_shift, &se_mask); - - return &enc1->base; -} - -static const struct dce_hwseq_registers hwseq_reg = { - HWSEQ_DCN201_REG_LIST() -}; - -static const struct dce_hwseq_shift hwseq_shift = { - HWSEQ_DCN201_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_hwseq_mask hwseq_mask = { - HWSEQ_DCN201_MASK_SH_LIST(_MASK) -}; - -static struct dce_hwseq *dcn201_hwseq_create( - struct dc_context *ctx) -{ - struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_ATOMIC); - - if (hws) { - hws->ctx = ctx; - hws->regs = &hwseq_reg; - hws->shifts = &hwseq_shift; - hws->masks = &hwseq_mask; - } - return hws; -} - -static const struct resource_create_funcs res_create_funcs = { - .read_dce_straps = read_dce_straps, - .create_audio = dcn201_create_audio, - .create_stream_encoder = dcn201_stream_encoder_create, - .create_hwseq = dcn201_hwseq_create, -}; - -static void dcn201_clock_source_destroy(struct clock_source **clk_src) -{ - kfree(TO_DCE110_CLK_SRC(*clk_src)); - *clk_src = NULL; -} - -static void dcn201_resource_destruct(struct dcn201_resource_pool *pool) -{ - unsigned int i; - - for (i = 0; i < pool->base.stream_enc_count; i++) { - if (pool->base.stream_enc[i] != NULL) { - kfree(DCN10STRENC_FROM_STRENC(pool->base.stream_enc[i])); - pool->base.stream_enc[i] = NULL; - } - } - - - if (pool->base.mpc != NULL) { - kfree(TO_DCN201_MPC(pool->base.mpc)); - pool->base.mpc = NULL; - } - - if (pool->base.hubbub != NULL) { - kfree(pool->base.hubbub); - pool->base.hubbub = NULL; - } - - for (i = 0; i < pool->base.pipe_count; i++) { - if (pool->base.dpps[i] != NULL) - dcn201_dpp_destroy(&pool->base.dpps[i]); - - if (pool->base.ipps[i] != NULL) - pool->base.ipps[i]->funcs->ipp_destroy(&pool->base.ipps[i]); - - if (pool->base.hubps[i] != NULL) { - kfree(TO_DCN10_HUBP(pool->base.hubps[i])); - pool->base.hubps[i] = NULL; - } - - if (pool->base.irqs != NULL) { - dal_irq_service_destroy(&pool->base.irqs); - } - } - - for (i = 0; i < pool->base.res_cap->num_opp; i++) { - if (pool->base.opps[i] != NULL) - pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]); - } - - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - if (pool->base.timing_generators[i] != NULL) { - kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i])); - pool->base.timing_generators[i] = NULL; - } - } - for (i = 0; i < pool->base.audio_count; i++) { - if (pool->base.audios[i]) - dce_aud_destroy(&pool->base.audios[i]); - } - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] != NULL) { - dcn201_clock_source_destroy(&pool->base.clock_sources[i]); - pool->base.clock_sources[i] = NULL; - } - } - - if (pool->base.dp_clock_source != NULL) { - dcn201_clock_source_destroy(&pool->base.dp_clock_source); - pool->base.dp_clock_source = NULL; - } - - if (pool->base.dccg != NULL) - dcn_dccg_destroy(&pool->base.dccg); -} - -static struct hubp *dcn201_hubp_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn201_hubp *hubp201 = - kzalloc(sizeof(struct dcn201_hubp), GFP_ATOMIC); - - if (!hubp201) - return NULL; - - if (dcn201_hubp_construct(hubp201, ctx, inst, - &hubp_regs[inst], &hubp_shift, &hubp_mask)) - return &hubp201->base; - - kfree(hubp201); - return NULL; -} - -static struct pipe_ctx *dcn201_acquire_free_pipe_for_layer( - const struct dc_state *cur_ctx, - struct dc_state *new_ctx, - const struct resource_pool *pool, - const struct pipe_ctx *opp_head_pipe) -{ - struct resource_context *res_ctx = &new_ctx->res_ctx; - struct pipe_ctx *head_pipe = resource_get_otg_master_for_stream(res_ctx, opp_head_pipe->stream); - struct pipe_ctx *idle_pipe = resource_find_free_secondary_pipe_legacy(res_ctx, pool, head_pipe); - - if (!head_pipe) - ASSERT(0); - - if (!idle_pipe) - return NULL; - - idle_pipe->stream = head_pipe->stream; - idle_pipe->stream_res.tg = head_pipe->stream_res.tg; - idle_pipe->stream_res.opp = head_pipe->stream_res.opp; - - idle_pipe->plane_res.hubp = pool->hubps[idle_pipe->pipe_idx]; - idle_pipe->plane_res.ipp = pool->ipps[idle_pipe->pipe_idx]; - idle_pipe->plane_res.dpp = pool->dpps[idle_pipe->pipe_idx]; - idle_pipe->plane_res.mpcc_inst = pool->dpps[idle_pipe->pipe_idx]->inst; - - return idle_pipe; -} - -static bool dcn201_get_dcc_compression_cap(const struct dc *dc, - const struct dc_dcc_surface_param *input, - struct dc_surface_dcc_cap *output) -{ - return dc->res_pool->hubbub->funcs->get_dcc_compression_cap( - dc->res_pool->hubbub, - input, - output); -} - -static void dcn201_populate_dml_writeback_from_context(struct dc *dc, - struct resource_context *res_ctx, - display_e2e_pipe_params_st *pipes) -{ - DC_FP_START(); - dcn201_populate_dml_writeback_from_context_fpu(dc, res_ctx, pipes); - DC_FP_END(); -} - -static void dcn201_destroy_resource_pool(struct resource_pool **pool) -{ - struct dcn201_resource_pool *dcn201_pool = TO_DCN201_RES_POOL(*pool); - - dcn201_resource_destruct(dcn201_pool); - kfree(dcn201_pool); - *pool = NULL; -} - -static void dcn201_link_init(struct dc_link *link) -{ - if (link->ctx->dc_bios->integrated_info) - link->dp_ss_off = !link->ctx->dc_bios->integrated_info->dp_ss_control; -} - -static struct dc_cap_funcs cap_funcs = { - .get_dcc_compression_cap = dcn201_get_dcc_compression_cap, -}; - -static struct resource_funcs dcn201_res_pool_funcs = { - .link_init = dcn201_link_init, - .destroy = dcn201_destroy_resource_pool, - .link_enc_create = dcn201_link_encoder_create, - .panel_cntl_create = NULL, - .validate_bandwidth = dcn20_validate_bandwidth, - .populate_dml_pipes = dcn20_populate_dml_pipes_from_context, - .add_stream_to_ctx = dcn20_add_stream_to_ctx, - .add_dsc_to_stream_resource = NULL, - .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, - .acquire_free_pipe_as_secondary_dpp_pipe = dcn201_acquire_free_pipe_for_layer, - .release_pipe = dcn20_release_pipe, - .populate_dml_writeback_from_context = dcn201_populate_dml_writeback_from_context, - .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, - .set_mcif_arb_params = dcn20_set_mcif_arb_params, - .find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link -}; - -static bool dcn201_resource_construct( - uint8_t num_virtual_links, - struct dc *dc, - struct dcn201_resource_pool *pool) -{ - int i; - struct dc_context *ctx = dc->ctx; - - ctx->dc_bios->regs = &bios_regs; - - pool->base.res_cap = &res_cap_dnc201; - pool->base.funcs = &dcn201_res_pool_funcs; - - /************************************************* - * Resource + asic cap harcoding * - *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; - - pool->base.pipe_count = 4; - pool->base.mpcc_count = 5; - dc->caps.max_downscale_ratio = 200; - dc->caps.i2c_speed_in_khz = 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; - - dc->caps.max_slave_planes = 1; - dc->caps.max_slave_yuv_planes = 1; - dc->caps.max_slave_rgb_planes = 1; - dc->caps.post_blend_color_processing = true; - dc->caps.force_dp_tps4_for_cp2520 = true; - dc->caps.extended_aux_timeout_support = true; - - /* Color pipeline capabilities */ - dc->caps.color.dpp.dcn_arch = 1; - dc->caps.color.dpp.input_lut_shared = 0; - dc->caps.color.dpp.icsc = 1; - dc->caps.color.dpp.dgam_ram = 1; - dc->caps.color.dpp.dgam_rom_caps.srgb = 1; - dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1; - dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 0; - dc->caps.color.dpp.dgam_rom_caps.pq = 0; - dc->caps.color.dpp.dgam_rom_caps.hlg = 0; - dc->caps.color.dpp.post_csc = 0; - dc->caps.color.dpp.gamma_corr = 0; - dc->caps.color.dpp.dgam_rom_for_yuv = 1; - - dc->caps.color.dpp.hw_3d_lut = 1; - dc->caps.color.dpp.ogam_ram = 1; - // no OGAM ROM on DCN2 - dc->caps.color.dpp.ogam_rom_caps.srgb = 0; - dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0; - dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0; - dc->caps.color.dpp.ogam_rom_caps.pq = 0; - dc->caps.color.dpp.ogam_rom_caps.hlg = 0; - dc->caps.color.dpp.ocsc = 0; - - dc->caps.color.mpc.gamut_remap = 0; - dc->caps.color.mpc.num_3dluts = 0; - dc->caps.color.mpc.shared_3d_lut = 0; - dc->caps.color.mpc.ogam_ram = 1; - dc->caps.color.mpc.ogam_rom_caps.srgb = 0; - dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0; - dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0; - dc->caps.color.mpc.ogam_rom_caps.pq = 0; - dc->caps.color.mpc.ogam_rom_caps.hlg = 0; - dc->caps.color.mpc.ocsc = 1; - - dc->debug = debug_defaults_drv; - - /*a0 only, remove later*/ - dc->work_arounds.no_connect_phy_config = true; - dc->work_arounds.dedcn20_305_wa = true; - /************************************************* - * Create resources * - *************************************************/ - - pool->base.clock_sources[DCN20_CLK_SRC_PLL0] = - dcn201_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL0, - &clk_src_regs[0], false); - pool->base.clock_sources[DCN20_CLK_SRC_PLL1] = - dcn201_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL1, - &clk_src_regs[1], false); - - pool->base.clk_src_count = DCN20_CLK_SRC_TOTAL_DCN201; - - /* todo: not reuse phy_pll registers */ - pool->base.dp_clock_source = - dcn201_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_ID_DP_DTO, - &clk_src_regs[0], true); - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] == NULL) { - dm_error("DC: failed to create clock sources!\n"); - goto create_fail; - } - } - - pool->base.dccg = dccg201_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask); - if (pool->base.dccg == NULL) { - dm_error("DC: failed to create dccg!\n"); - goto create_fail; - } - - dcn201_ip.max_num_otg = pool->base.res_cap->num_timing_generator; - dcn201_ip.max_num_dpp = pool->base.pipe_count; - dml_init_instance(&dc->dml, &dcn201_soc, &dcn201_ip, DML_PROJECT_DCN201); - { - struct irq_service_init_data init_data; - init_data.ctx = dc->ctx; - pool->base.irqs = dal_irq_service_dcn201_create(&init_data); - if (!pool->base.irqs) - goto create_fail; - } - - /* mem input -> ipp -> dpp -> opp -> TG */ - for (i = 0; i < pool->base.pipe_count; i++) { - pool->base.hubps[i] = dcn201_hubp_create(ctx, i); - if (pool->base.hubps[i] == NULL) { - dm_error( - "DC: failed to create memory input!\n"); - goto create_fail; - } - - pool->base.ipps[i] = dcn201_ipp_create(ctx, i); - if (pool->base.ipps[i] == NULL) { - dm_error( - "DC: failed to create input pixel processor!\n"); - goto create_fail; - } - - pool->base.dpps[i] = dcn201_dpp_create(ctx, i); - if (pool->base.dpps[i] == NULL) { - dm_error( - "DC: failed to create dpps!\n"); - goto create_fail; - } - } - - for (i = 0; i < pool->base.res_cap->num_opp; i++) { - pool->base.opps[i] = dcn201_opp_create(ctx, i); - if (pool->base.opps[i] == NULL) { - dm_error( - "DC: failed to create output pixel processor!\n"); - goto create_fail; - } - } - - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - pool->base.engines[i] = dcn201_aux_engine_create(ctx, i); - if (pool->base.engines[i] == NULL) { - dm_error( - "DC:failed to create aux engine!!\n"); - goto create_fail; - } - pool->base.hw_i2cs[i] = dcn201_i2c_hw_create(ctx, i); - if (pool->base.hw_i2cs[i] == NULL) { - dm_error( - "DC:failed to create hw i2c!!\n"); - goto create_fail; - } - pool->base.sw_i2cs[i] = NULL; - } - - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - pool->base.timing_generators[i] = dcn201_timing_generator_create( - ctx, i); - if (pool->base.timing_generators[i] == NULL) { - dm_error("DC: failed to create tg!\n"); - goto create_fail; - } - } - - pool->base.timing_generator_count = i; - - pool->base.mpc = dcn201_mpc_create(ctx, pool->base.mpcc_count); - if (pool->base.mpc == NULL) { - dm_error("DC: failed to create mpc!\n"); - goto create_fail; - } - - pool->base.hubbub = dcn201_hubbub_create(ctx); - if (pool->base.hubbub == NULL) { - dm_error("DC: failed to create hubbub!\n"); - goto create_fail; - } - - if (!resource_construct(num_virtual_links, dc, &pool->base, - &res_create_funcs)) - goto create_fail; - - dcn201_hw_sequencer_construct(dc); - - dc->caps.max_planes = pool->base.pipe_count; - - for (i = 0; i < dc->caps.max_planes; ++i) - dc->caps.planes[i] = plane_cap; - - dc->cap_funcs = cap_funcs; - - return true; - -create_fail: - - dcn201_resource_destruct(pool); - - return false; -} - -struct resource_pool *dcn201_create_resource_pool( - const struct dc_init_data *init_data, - struct dc *dc) -{ - struct dcn201_resource_pool *pool = - kzalloc(sizeof(struct dcn201_resource_pool), GFP_ATOMIC); - - if (!pool) - return NULL; - - if (dcn201_resource_construct(init_data->num_virtual_links, dc, pool)) - return &pool->base; - - kfree(pool); - return NULL; -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.h b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.h deleted file mode 100644 index e0467d17d4ae8d..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.h +++ /dev/null @@ -1,50 +0,0 @@ -/* -* Copyright 2017 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_RESOURCE_DCN201_H__ -#define __DC_RESOURCE_DCN201_H__ - -#include "core_types.h" - -#define RRDPCS_PHY_DP_TX_PSTATE_POWER_UP 0x00000000 -#define RRDPCS_PHY_DP_TX_PSTATE_HOLD 0x00000001 -#define RRDPCS_PHY_DP_TX_PSTATE_HOLD_OFF 0x00000002 -#define RRDPCS_PHY_DP_TX_PSTATE_POWER_DOWN 0x00000003 - -#define TO_DCN201_RES_POOL(pool)\ - container_of(pool, struct dcn201_resource_pool, base) - -struct dc; -struct resource_pool; -struct _vcs_dpi_display_pipe_params_st; - -struct dcn201_resource_pool { - struct resource_pool base; -}; -struct resource_pool *dcn201_create_resource_pool( - const struct dc_init_data *init_data, - struct dc *dc); - -#endif /* __DC_RESOURCE_DCN201_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/Makefile b/drivers/gpu/drm/amd/display/dc/dcn21/Makefile index ce1be0afae4a91..ca92f5c8e7fb70 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn21/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn21/Makefile @@ -2,7 +2,7 @@ # # Makefile for DCN21. -DCN21 = dcn21_init.o dcn21_hubp.o dcn21_hubbub.o dcn21_resource.o \ +DCN21 = dcn21_hubp.o dcn21_hubbub.o \ dcn21_link_encoder.o dcn21_dccg.o AMD_DAL_DCN21 = $(addprefix $(AMDDALPATH)/dc/dcn21/,$(DCN21)) diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hubp.c index 68cad55c72ab8c..e13d69a22c1c7f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_hubp.c @@ -691,7 +691,7 @@ static void dmcub_PLAT_54186_wa(struct hubp *hubp, cmd.PLAT_54186_wa.flip.flip_params.vmid = flip_regs->vmid; PERF_TRACE(); // TODO: remove after performance is stable. - dm_execute_dmub_cmd(hubp->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(hubp->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); PERF_TRACE(); // TODO: remove after performance is stable. } diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.c deleted file mode 100644 index 18249c6b6d81c5..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 2016-2020 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 "dce110/dce110_hwseq.h" -#include "dcn10/dcn10_hwseq.h" -#include "dcn20/dcn20_hwseq.h" -#include "dcn21/dcn21_hwseq.h" - -#include "dcn21_init.h" - -static const struct hw_sequencer_funcs dcn21_funcs = { - .program_gamut_remap = dcn10_program_gamut_remap, - .init_hw = dcn10_init_hw, - .power_down_on_boot = dcn10_power_down_on_boot, - .apply_ctx_to_hw = dce110_apply_ctx_to_hw, - .apply_ctx_for_surface = NULL, - .program_front_end_for_ctx = dcn20_program_front_end_for_ctx, - .wait_for_pending_cleared = dcn10_wait_for_pending_cleared, - .post_unlock_program_front_end = dcn20_post_unlock_program_front_end, - .update_plane_addr = dcn20_update_plane_addr, - .update_dchub = dcn10_update_dchub, - .update_pending_status = dcn10_update_pending_status, - .program_output_csc = dcn20_program_output_csc, - .enable_accelerated_mode = dce110_enable_accelerated_mode, - .enable_timing_synchronization = dcn10_enable_timing_synchronization, - .enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset, - .update_info_frame = dce110_update_info_frame, - .send_immediate_sdp_message = dcn10_send_immediate_sdp_message, - .enable_stream = dcn20_enable_stream, - .disable_stream = dce110_disable_stream, - .unblank_stream = dcn20_unblank_stream, - .blank_stream = dce110_blank_stream, - .enable_audio_stream = dce110_enable_audio_stream, - .disable_audio_stream = dce110_disable_audio_stream, - .disable_plane = dcn20_disable_plane, - .pipe_control_lock = dcn20_pipe_control_lock, - .interdependent_update_lock = dcn10_lock_all_pipes, - .cursor_lock = dcn10_cursor_lock, - .prepare_bandwidth = dcn20_prepare_bandwidth, - .optimize_bandwidth = dcn20_optimize_bandwidth, - .update_bandwidth = dcn20_update_bandwidth, - .set_drr = dcn10_set_drr, - .get_position = dcn10_get_position, - .set_static_screen_control = dcn10_set_static_screen_control, - .setup_stereo = dcn10_setup_stereo, - .set_avmute = dce110_set_avmute, - .log_hw_state = dcn10_log_hw_state, - .get_hw_state = dcn10_get_hw_state, - .clear_status_bits = dcn10_clear_status_bits, - .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, - .edp_backlight_control = dce110_edp_backlight_control, - .edp_power_control = dce110_edp_power_control, - .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, - .set_cursor_position = dcn10_set_cursor_position, - .set_cursor_attribute = dcn10_set_cursor_attribute, - .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level, - .setup_periodic_interrupt = dcn10_setup_periodic_interrupt, - .set_clock = dcn10_set_clock, - .get_clock = dcn10_get_clock, - .program_triplebuffer = dcn20_program_triple_buffer, - .enable_writeback = dcn20_enable_writeback, - .disable_writeback = dcn20_disable_writeback, - .dmdata_status_done = dcn20_dmdata_status_done, - .program_dmdata_engine = dcn20_program_dmdata_engine, - .set_dmdata_attributes = dcn20_set_dmdata_attributes, - .init_sys_ctx = dcn21_init_sys_ctx, - .init_vm_ctx = dcn20_init_vm_ctx, - .set_flip_control_gsl = dcn20_set_flip_control_gsl, - .optimize_pwr_state = dcn21_optimize_pwr_state, - .exit_optimized_pwr_state = dcn21_exit_optimized_pwr_state, - .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync, - .calc_vupdate_position = dcn10_calc_vupdate_position, - .power_down = dce110_power_down, - .set_backlight_level = dcn21_set_backlight_level, - .set_abm_immediate_disable = dcn21_set_abm_immediate_disable, - .set_pipe = dcn21_set_pipe, - .enable_lvds_link_output = dce110_enable_lvds_link_output, - .enable_tmds_link_output = dce110_enable_tmds_link_output, - .enable_dp_link_output = dce110_enable_dp_link_output, - .disable_link_output = dce110_disable_link_output, - .is_abm_supported = dcn21_is_abm_supported, - .set_disp_pattern_generator = dcn20_set_disp_pattern_generator, - .get_dcc_en_bits = dcn10_get_dcc_en_bits, - .update_visual_confirm_color = dcn10_update_visual_confirm_color, -}; - -static const struct hwseq_private_funcs dcn21_private_funcs = { - .init_pipes = dcn10_init_pipes, - .update_plane_addr = dcn20_update_plane_addr, - .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, - .update_mpcc = dcn20_update_mpcc, - .set_input_transfer_func = dcn20_set_input_transfer_func, - .set_output_transfer_func = dcn20_set_output_transfer_func, - .power_down = dce110_power_down, - .enable_display_power_gating = dcn10_dummy_display_power_gating, - .blank_pixel_data = dcn20_blank_pixel_data, - .reset_hw_ctx_wrap = dcn20_reset_hw_ctx_wrap, - .enable_stream_timing = dcn20_enable_stream_timing, - .edp_backlight_control = dce110_edp_backlight_control, - .disable_stream_gating = dcn20_disable_stream_gating, - .enable_stream_gating = dcn20_enable_stream_gating, - .setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt, - .did_underflow_occur = dcn10_did_underflow_occur, - .init_blank = dcn20_init_blank, - .disable_vga = dcn20_disable_vga, - .bios_golden_init = dcn10_bios_golden_init, - .plane_atomic_disable = dcn20_plane_atomic_disable, - .plane_atomic_power_down = dcn10_plane_atomic_power_down, - .enable_power_gating_plane = dcn20_enable_power_gating_plane, - .dpp_pg_control = dcn20_dpp_pg_control, - .hubp_pg_control = dcn20_hubp_pg_control, - .update_odm = dcn20_update_odm, - .dsc_pg_control = dcn20_dsc_pg_control, - .set_hdr_multiplier = dcn10_set_hdr_multiplier, - .verify_allow_pstate_change_high = dcn10_verify_allow_pstate_change_high, - .s0i3_golden_init_wa = dcn21_s0i3_golden_init_wa, - .wait_for_blank_complete = dcn20_wait_for_blank_complete, - .dccg_init = dcn20_dccg_init, - .set_blend_lut = dcn20_set_blend_lut, - .set_shaper_3dlut = dcn20_set_shaper_3dlut, - .PLAT_58856_wa = dcn21_PLAT_58856_wa, -}; - -void dcn21_hw_sequencer_construct(struct dc *dc) -{ - dc->hwss = dcn21_funcs; - dc->hwseq->funcs = dcn21_private_funcs; - -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.h b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.h deleted file mode 100644 index 3ed24292648a4f..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_init.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2016 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_DCN21_INIT_H__ -#define __DC_DCN21_INIT_H__ - -struct dc; - -void dcn21_hw_sequencer_construct(struct dc *dc); - -#endif /* __DC_DCN20_INIT_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 deleted file mode 100644 index 42277b280586e5..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c +++ /dev/null @@ -1,1745 +0,0 @@ -/* -* Copyright 2018 Advanced Micro Devices, Inc. - * Copyright 2019 Raptor Engineering, LLC - * - * 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 - -#include "dm_services.h" -#include "dc.h" - -#include "dcn21_init.h" - -#include "resource.h" -#include "include/irq_service_interface.h" -#include "dcn20/dcn20_resource.h" -#include "dcn21/dcn21_resource.h" - -#include "dml/dcn20/dcn20_fpu.h" - -#include "clk_mgr.h" -#include "dcn10/dcn10_hubp.h" -#include "dcn10/dcn10_ipp.h" -#include "dcn20/dcn20_hubbub.h" -#include "dcn20/dcn20_mpc.h" -#include "dcn20/dcn20_hubp.h" -#include "dcn21_hubp.h" -#include "irq/dcn21/irq_service_dcn21.h" -#include "dcn20/dcn20_dpp.h" -#include "dcn20/dcn20_optc.h" -#include "dcn21/dcn21_hwseq.h" -#include "dce110/dce110_hwseq.h" -#include "dcn20/dcn20_opp.h" -#include "dcn20/dcn20_dsc.h" -#include "dcn21/dcn21_link_encoder.h" -#include "dcn20/dcn20_stream_encoder.h" -#include "dce/dce_clock_source.h" -#include "dce/dce_audio.h" -#include "dce/dce_hwseq.h" -#include "virtual/virtual_stream_encoder.h" -#include "dml/display_mode_vba.h" -#include "dcn20/dcn20_dccg.h" -#include "dcn21/dcn21_dccg.h" -#include "dcn21_hubbub.h" -#include "dcn10/dcn10_resource.h" -#include "dce/dce_panel_cntl.h" - -#include "dcn20/dcn20_dwb.h" -#include "dcn20/dcn20_mmhubbub.h" -#include "dpcs/dpcs_2_1_0_offset.h" -#include "dpcs/dpcs_2_1_0_sh_mask.h" - -#include "renoir_ip_offset.h" -#include "dcn/dcn_2_1_0_offset.h" -#include "dcn/dcn_2_1_0_sh_mask.h" - -#include "nbio/nbio_7_0_offset.h" - -#include "mmhub/mmhub_2_0_0_offset.h" -#include "mmhub/mmhub_2_0_0_sh_mask.h" - -#include "reg_helper.h" -#include "dce/dce_abm.h" -#include "dce/dce_dmcu.h" -#include "dce/dce_aux.h" -#include "dce/dce_i2c.h" -#include "dcn21_resource.h" -#include "vm_helper.h" -#include "dcn20/dcn20_vmid.h" -#include "dce/dmub_psr.h" -#include "dce/dmub_abm.h" - -/* begin ********************* - * macros to expend register list macro defined in HW object header file */ - -/* DCN */ -#define BASE_INNER(seg) DMU_BASE__INST0_SEG ## seg - -#define BASE(seg) BASE_INNER(seg) - -#define SR(reg_name)\ - .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + \ - mm ## reg_name - -#define SRI(reg_name, block, id)\ - .reg_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name - -#define SRIR(var_name, reg_name, block, id)\ - .var_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name - -#define SRII(reg_name, block, id)\ - .reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name - -#define DCCG_SRII(reg_name, block, id)\ - .block ## _ ## reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name - -#define VUPDATE_SRII(reg_name, block, id)\ - .reg_name[id] = BASE(mm ## reg_name ## _ ## block ## id ## _BASE_IDX) + \ - mm ## reg_name ## _ ## block ## id - -/* NBIO */ -#define NBIO_BASE_INNER(seg) \ - NBIF0_BASE__INST0_SEG ## seg - -#define NBIO_BASE(seg) \ - NBIO_BASE_INNER(seg) - -#define NBIO_SR(reg_name)\ - .reg_name = NBIO_BASE(mm ## reg_name ## _BASE_IDX) + \ - mm ## reg_name - -/* MMHUB */ -#define MMHUB_BASE_INNER(seg) \ - MMHUB_BASE__INST0_SEG ## seg - -#define MMHUB_BASE(seg) \ - MMHUB_BASE_INNER(seg) - -#define MMHUB_SR(reg_name)\ - .reg_name = MMHUB_BASE(mmMM ## reg_name ## _BASE_IDX) + \ - mmMM ## reg_name - -#define clk_src_regs(index, pllid)\ -[index] = {\ - CS_COMMON_REG_LIST_DCN2_1(index, pllid),\ -} - -static const struct dce110_clk_src_regs clk_src_regs[] = { - clk_src_regs(0, A), - clk_src_regs(1, B), - clk_src_regs(2, C), - clk_src_regs(3, D), - clk_src_regs(4, E), -}; - -static const struct dce110_clk_src_shift cs_shift = { - CS_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) -}; - -static const struct dce110_clk_src_mask cs_mask = { - CS_COMMON_MASK_SH_LIST_DCN2_0(_MASK) -}; - -static const struct bios_registers bios_regs = { - NBIO_SR(BIOS_SCRATCH_3), - NBIO_SR(BIOS_SCRATCH_6) -}; - -static const struct dce_dmcu_registers dmcu_regs = { - DMCU_DCN20_REG_LIST() -}; - -static const struct dce_dmcu_shift dmcu_shift = { - DMCU_MASK_SH_LIST_DCN10(__SHIFT) -}; - -static const struct dce_dmcu_mask dmcu_mask = { - DMCU_MASK_SH_LIST_DCN10(_MASK) -}; - -static const struct dce_abm_registers abm_regs = { - ABM_DCN20_REG_LIST() -}; - -static const struct dce_abm_shift abm_shift = { - ABM_MASK_SH_LIST_DCN20(__SHIFT) -}; - -static const struct dce_abm_mask abm_mask = { - ABM_MASK_SH_LIST_DCN20(_MASK) -}; - -#define audio_regs(id)\ -[id] = {\ - AUD_COMMON_REG_LIST(id)\ -} - -static const struct dce_audio_registers audio_regs[] = { - audio_regs(0), - audio_regs(1), - audio_regs(2), - audio_regs(3), - audio_regs(4), - audio_regs(5), -}; - -#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ - SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ - SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ - AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) - -static const struct dce_audio_shift audio_shift = { - DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_audio_mask audio_mask = { - DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) -}; - -static const struct dccg_registers dccg_regs = { - DCCG_COMMON_REG_LIST_DCN_BASE() -}; - -static const struct dccg_shift dccg_shift = { - DCCG_MASK_SH_LIST_DCN2_1(__SHIFT) -}; - -static const struct dccg_mask dccg_mask = { - DCCG_MASK_SH_LIST_DCN2_1(_MASK) -}; - -#define opp_regs(id)\ -[id] = {\ - OPP_REG_LIST_DCN20(id),\ -} - -static const struct dcn20_opp_registers opp_regs[] = { - opp_regs(0), - opp_regs(1), - opp_regs(2), - opp_regs(3), - opp_regs(4), - opp_regs(5), -}; - -static const struct dcn20_opp_shift opp_shift = { - OPP_MASK_SH_LIST_DCN20(__SHIFT) -}; - -static const struct dcn20_opp_mask opp_mask = { - OPP_MASK_SH_LIST_DCN20(_MASK) -}; - -#define tg_regs(id)\ -[id] = {TG_COMMON_REG_LIST_DCN2_0(id)} - -static const struct dcn_optc_registers tg_regs[] = { - tg_regs(0), - tg_regs(1), - tg_regs(2), - tg_regs(3) -}; - -static const struct dcn_optc_shift tg_shift = { - TG_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) -}; - -static const struct dcn_optc_mask tg_mask = { - TG_COMMON_MASK_SH_LIST_DCN2_0(_MASK) -}; - -static const struct dcn20_mpc_registers mpc_regs = { - MPC_REG_LIST_DCN2_0(0), - MPC_REG_LIST_DCN2_0(1), - MPC_REG_LIST_DCN2_0(2), - MPC_REG_LIST_DCN2_0(3), - MPC_REG_LIST_DCN2_0(4), - MPC_REG_LIST_DCN2_0(5), - MPC_OUT_MUX_REG_LIST_DCN2_0(0), - MPC_OUT_MUX_REG_LIST_DCN2_0(1), - MPC_OUT_MUX_REG_LIST_DCN2_0(2), - MPC_OUT_MUX_REG_LIST_DCN2_0(3), - MPC_DBG_REG_LIST_DCN2_0() -}; - -static const struct dcn20_mpc_shift mpc_shift = { - MPC_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT), - MPC_DEBUG_REG_LIST_SH_DCN20 -}; - -static const struct dcn20_mpc_mask mpc_mask = { - MPC_COMMON_MASK_SH_LIST_DCN2_0(_MASK), - MPC_DEBUG_REG_LIST_MASK_DCN20 -}; - -#define hubp_regs(id)\ -[id] = {\ - HUBP_REG_LIST_DCN21(id)\ -} - -static const struct dcn_hubp2_registers hubp_regs[] = { - hubp_regs(0), - hubp_regs(1), - hubp_regs(2), - hubp_regs(3) -}; - -static const struct dcn_hubp2_shift hubp_shift = { - HUBP_MASK_SH_LIST_DCN21(__SHIFT) -}; - -static const struct dcn_hubp2_mask hubp_mask = { - HUBP_MASK_SH_LIST_DCN21(_MASK) -}; - -static const struct dcn_hubbub_registers hubbub_reg = { - HUBBUB_REG_LIST_DCN21() -}; - -static const struct dcn_hubbub_shift hubbub_shift = { - HUBBUB_MASK_SH_LIST_DCN21(__SHIFT) -}; - -static const struct dcn_hubbub_mask hubbub_mask = { - HUBBUB_MASK_SH_LIST_DCN21(_MASK) -}; - - -#define vmid_regs(id)\ -[id] = {\ - DCN20_VMID_REG_LIST(id)\ -} - -static const struct dcn_vmid_registers vmid_regs[] = { - vmid_regs(0), - vmid_regs(1), - vmid_regs(2), - vmid_regs(3), - vmid_regs(4), - vmid_regs(5), - vmid_regs(6), - vmid_regs(7), - vmid_regs(8), - vmid_regs(9), - vmid_regs(10), - vmid_regs(11), - vmid_regs(12), - vmid_regs(13), - vmid_regs(14), - vmid_regs(15) -}; - -static const struct dcn20_vmid_shift vmid_shifts = { - DCN20_VMID_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn20_vmid_mask vmid_masks = { - DCN20_VMID_MASK_SH_LIST(_MASK) -}; - -#define dsc_regsDCN20(id)\ -[id] = {\ - DSC_REG_LIST_DCN20(id)\ -} - -static const struct dcn20_dsc_registers dsc_regs[] = { - dsc_regsDCN20(0), - dsc_regsDCN20(1), - dsc_regsDCN20(2), - dsc_regsDCN20(3), - dsc_regsDCN20(4), - dsc_regsDCN20(5) -}; - -static const struct dcn20_dsc_shift dsc_shift = { - DSC_REG_LIST_SH_MASK_DCN20(__SHIFT) -}; - -static const struct dcn20_dsc_mask dsc_mask = { - DSC_REG_LIST_SH_MASK_DCN20(_MASK) -}; - -#define ipp_regs(id)\ -[id] = {\ - IPP_REG_LIST_DCN20(id),\ -} - -static const struct dcn10_ipp_registers ipp_regs[] = { - ipp_regs(0), - ipp_regs(1), - ipp_regs(2), - ipp_regs(3), -}; - -static const struct dcn10_ipp_shift ipp_shift = { - IPP_MASK_SH_LIST_DCN20(__SHIFT) -}; - -static const struct dcn10_ipp_mask ipp_mask = { - IPP_MASK_SH_LIST_DCN20(_MASK), -}; - -#define opp_regs(id)\ -[id] = {\ - OPP_REG_LIST_DCN20(id),\ -} - - -#define aux_engine_regs(id)\ -[id] = {\ - AUX_COMMON_REG_LIST0(id), \ - .AUXN_IMPCAL = 0, \ - .AUXP_IMPCAL = 0, \ - .AUX_RESET_MASK = DP_AUX0_AUX_CONTROL__AUX_RESET_MASK, \ -} - -static const struct dce110_aux_registers aux_engine_regs[] = { - aux_engine_regs(0), - aux_engine_regs(1), - aux_engine_regs(2), - aux_engine_regs(3), - aux_engine_regs(4), -}; - -#define tf_regs(id)\ -[id] = {\ - TF_REG_LIST_DCN20(id),\ - TF_REG_LIST_DCN20_COMMON_APPEND(id),\ -} - -static const struct dcn2_dpp_registers tf_regs[] = { - tf_regs(0), - tf_regs(1), - tf_regs(2), - tf_regs(3), -}; - -static const struct dcn2_dpp_shift tf_shift = { - TF_REG_LIST_SH_MASK_DCN20(__SHIFT), - TF_DEBUG_REG_LIST_SH_DCN20 -}; - -static const struct dcn2_dpp_mask tf_mask = { - TF_REG_LIST_SH_MASK_DCN20(_MASK), - TF_DEBUG_REG_LIST_MASK_DCN20 -}; - -#define stream_enc_regs(id)\ -[id] = {\ - SE_DCN2_REG_LIST(id)\ -} - -static const struct dcn10_stream_enc_registers stream_enc_regs[] = { - stream_enc_regs(0), - stream_enc_regs(1), - stream_enc_regs(2), - stream_enc_regs(3), - stream_enc_regs(4), -}; - -static const struct dce110_aux_registers_shift aux_shift = { - DCN_AUX_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce110_aux_registers_mask aux_mask = { - DCN_AUX_MASK_SH_LIST(_MASK) -}; - -static const struct dcn10_stream_encoder_shift se_shift = { - SE_COMMON_MASK_SH_LIST_DCN20(__SHIFT) -}; - -static const struct dcn10_stream_encoder_mask se_mask = { - SE_COMMON_MASK_SH_LIST_DCN20(_MASK) -}; - -static void dcn21_pp_smu_destroy(struct pp_smu_funcs **pp_smu); - -static struct input_pixel_processor *dcn21_ipp_create( - struct dc_context *ctx, uint32_t inst) -{ - struct dcn10_ipp *ipp = - kzalloc(sizeof(struct dcn10_ipp), GFP_KERNEL); - - if (!ipp) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dcn20_ipp_construct(ipp, ctx, inst, - &ipp_regs[inst], &ipp_shift, &ipp_mask); - return &ipp->base; -} - -static struct dpp *dcn21_dpp_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn20_dpp *dpp = - kzalloc(sizeof(struct dcn20_dpp), GFP_KERNEL); - - if (!dpp) - return NULL; - - if (dpp2_construct(dpp, ctx, inst, - &tf_regs[inst], &tf_shift, &tf_mask)) - return &dpp->base; - - BREAK_TO_DEBUGGER(); - kfree(dpp); - return NULL; -} - -static struct dce_aux *dcn21_aux_engine_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct aux_engine_dce110 *aux_engine = - kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); - - if (!aux_engine) - return NULL; - - dce110_aux_engine_construct(aux_engine, ctx, inst, - SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, - &aux_engine_regs[inst], - &aux_mask, - &aux_shift, - ctx->dc->caps.extended_aux_timeout_support); - - return &aux_engine->base; -} - -#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST(id) } - -static const struct dce_i2c_registers i2c_hw_regs[] = { - i2c_inst_regs(1), - i2c_inst_regs(2), - i2c_inst_regs(3), - i2c_inst_regs(4), - i2c_inst_regs(5), -}; - -static const struct dce_i2c_shift i2c_shifts = { - I2C_COMMON_MASK_SH_LIST_DCN2(__SHIFT) -}; - -static const struct dce_i2c_mask i2c_masks = { - I2C_COMMON_MASK_SH_LIST_DCN2(_MASK) -}; - -static struct dce_i2c_hw *dcn21_i2c_hw_create(struct dc_context *ctx, - uint32_t inst) -{ - struct dce_i2c_hw *dce_i2c_hw = - kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); - - if (!dce_i2c_hw) - return NULL; - - dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst, - &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); - - return dce_i2c_hw; -} - -static const struct resource_caps res_cap_rn = { - .num_timing_generator = 4, - .num_opp = 4, - .num_video_plane = 4, - .num_audio = 4, // 4 audio endpoints. 4 audio streams - .num_stream_encoder = 5, - .num_pll = 5, // maybe 3 because the last two used for USB-c - .num_dwb = 1, - .num_ddc = 5, - .num_vmid = 16, - .num_dsc = 3, -}; - -#ifdef DIAGS_BUILD -static const struct resource_caps res_cap_rn_FPGA_4pipe = { - .num_timing_generator = 4, - .num_opp = 4, - .num_video_plane = 4, - .num_audio = 7, - .num_stream_encoder = 4, - .num_pll = 4, - .num_dwb = 1, - .num_ddc = 4, - .num_dsc = 0, -}; - -static const struct resource_caps res_cap_rn_FPGA_2pipe_dsc = { - .num_timing_generator = 2, - .num_opp = 2, - .num_video_plane = 2, - .num_audio = 7, - .num_stream_encoder = 2, - .num_pll = 4, - .num_dwb = 1, - .num_ddc = 4, - .num_dsc = 2, -}; -#endif - -static const struct dc_plane_cap plane_cap = { - .type = DC_PLANE_TYPE_DCN_UNIVERSAL, - .per_pixel_alpha = true, - - .pixel_format_support = { - .argb8888 = true, - .nv12 = true, - .fp16 = true, - .p010 = true - }, - - .max_upscale_factor = { - .argb8888 = 16000, - .nv12 = 16000, - .fp16 = 16000 - }, - - .max_downscale_factor = { - .argb8888 = 250, - .nv12 = 250, - .fp16 = 250 - }, - 64, - 64 -}; - -static const struct dc_debug_options debug_defaults_drv = { - .disable_dmcu = false, - .force_abm_enable = false, - .timing_trace = false, - .clock_trace = true, - .disable_pplib_clock_request = true, - .min_disp_clk_khz = 100000, - .pipe_split_policy = MPC_SPLIT_DYNAMIC, - .force_single_disp_pipe_split = false, - .disable_dcc = DCC_ENABLE, - .vsr_support = true, - .performance_trace = false, - .max_downscale_src_width = 4096, - .disable_pplib_wm_range = false, - .scl_reset_length10 = true, - .sanity_checks = true, - .disable_48mhz_pwrdwn = false, - .usbc_combo_phy_reset_wa = true, - .dmub_command_table = true, - .use_max_lb = true, - .enable_legacy_fast_update = true, - .using_dml2 = false, -}; - -static const struct dc_panel_config panel_config_defaults = { - .psr = { - .disable_psr = false, - .disallow_psrsu = false, - .disallow_replay = false, - }, - .ilr = { - .optimize_edp_link_rate = true, - }, -}; - -enum dcn20_clk_src_array_id { - DCN20_CLK_SRC_PLL0, - DCN20_CLK_SRC_PLL1, - DCN20_CLK_SRC_PLL2, - DCN20_CLK_SRC_PLL3, - DCN20_CLK_SRC_PLL4, - DCN20_CLK_SRC_TOTAL_DCN21 -}; - -static void dcn21_resource_destruct(struct dcn21_resource_pool *pool) -{ - unsigned int i; - - for (i = 0; i < pool->base.stream_enc_count; i++) { - if (pool->base.stream_enc[i] != NULL) { - kfree(DCN10STRENC_FROM_STRENC(pool->base.stream_enc[i])); - pool->base.stream_enc[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_dsc; i++) { - if (pool->base.dscs[i] != NULL) - dcn20_dsc_destroy(&pool->base.dscs[i]); - } - - if (pool->base.mpc != NULL) { - kfree(TO_DCN20_MPC(pool->base.mpc)); - pool->base.mpc = NULL; - } - if (pool->base.hubbub != NULL) { - kfree(pool->base.hubbub); - pool->base.hubbub = NULL; - } - for (i = 0; i < pool->base.pipe_count; i++) { - if (pool->base.dpps[i] != NULL) - dcn20_dpp_destroy(&pool->base.dpps[i]); - - if (pool->base.ipps[i] != NULL) - pool->base.ipps[i]->funcs->ipp_destroy(&pool->base.ipps[i]); - - if (pool->base.hubps[i] != NULL) { - kfree(TO_DCN20_HUBP(pool->base.hubps[i])); - pool->base.hubps[i] = NULL; - } - - if (pool->base.irqs != NULL) { - dal_irq_service_destroy(&pool->base.irqs); - } - } - - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - if (pool->base.engines[i] != NULL) - dce110_engine_destroy(&pool->base.engines[i]); - if (pool->base.hw_i2cs[i] != NULL) { - kfree(pool->base.hw_i2cs[i]); - pool->base.hw_i2cs[i] = NULL; - } - if (pool->base.sw_i2cs[i] != NULL) { - kfree(pool->base.sw_i2cs[i]); - pool->base.sw_i2cs[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_opp; i++) { - if (pool->base.opps[i] != NULL) - pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]); - } - - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - if (pool->base.timing_generators[i] != NULL) { - kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i])); - pool->base.timing_generators[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_dwb; i++) { - if (pool->base.dwbc[i] != NULL) { - kfree(TO_DCN20_DWBC(pool->base.dwbc[i])); - pool->base.dwbc[i] = NULL; - } - if (pool->base.mcif_wb[i] != NULL) { - kfree(TO_DCN20_MMHUBBUB(pool->base.mcif_wb[i])); - pool->base.mcif_wb[i] = NULL; - } - } - - for (i = 0; i < pool->base.audio_count; i++) { - if (pool->base.audios[i]) - dce_aud_destroy(&pool->base.audios[i]); - } - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] != NULL) { - dcn20_clock_source_destroy(&pool->base.clock_sources[i]); - pool->base.clock_sources[i] = NULL; - } - } - - if (pool->base.dp_clock_source != NULL) { - dcn20_clock_source_destroy(&pool->base.dp_clock_source); - pool->base.dp_clock_source = NULL; - } - - if (pool->base.abm != NULL) { - if (pool->base.abm->ctx->dc->config.disable_dmcu) - dmub_abm_destroy(&pool->base.abm); - else - dce_abm_destroy(&pool->base.abm); - } - - if (pool->base.dmcu != NULL) - dce_dmcu_destroy(&pool->base.dmcu); - - if (pool->base.psr != NULL) - dmub_psr_destroy(&pool->base.psr); - - if (pool->base.dccg != NULL) - dcn_dccg_destroy(&pool->base.dccg); - - if (pool->base.pp_smu != NULL) - dcn21_pp_smu_destroy(&pool->base.pp_smu); -} - -bool dcn21_fast_validate_bw(struct dc *dc, - struct dc_state *context, - display_e2e_pipe_params_st *pipes, - int *pipe_cnt_out, - int *pipe_split_from, - int *vlevel_out, - bool fast_validate) -{ - bool out = false; - int split[MAX_PIPES] = { 0 }; - int pipe_cnt, i, pipe_idx, vlevel; - - ASSERT(pipes); - if (!pipes) - return false; - - dcn20_merge_pipes_for_validate(dc, context); - - DC_FP_START(); - pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, context, pipes, fast_validate); - DC_FP_END(); - - *pipe_cnt_out = pipe_cnt; - - if (!pipe_cnt) { - out = true; - goto validate_out; - } - /* - * DML favors voltage over p-state, but we're more interested in - * supporting p-state over voltage. We can't support p-state in - * prefetch mode > 0 so try capping the prefetch mode to start. - */ - context->bw_ctx.dml.soc.allow_dram_self_refresh_or_dram_clock_change_in_vblank = - dm_allow_self_refresh_and_mclk_switch; - vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt); - - if (vlevel > context->bw_ctx.dml.soc.num_states) { - /* - * 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. - */ - context->bw_ctx.dml.soc.allow_dram_self_refresh_or_dram_clock_change_in_vblank = - dm_allow_self_refresh; - vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt); - if (vlevel > context->bw_ctx.dml.soc.num_states) - goto validate_fail; - } - - vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, vlevel, split, NULL); - - for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - struct pipe_ctx *mpo_pipe = pipe->bottom_pipe; - struct vba_vars_st *vba = &context->bw_ctx.dml.vba; - - if (!pipe->stream) - continue; - - /* We only support full screen mpo with ODM */ - if (vba->ODMCombineEnabled[vba->pipe_plane[pipe_idx]] != dm_odm_combine_mode_disabled - && pipe->plane_state && mpo_pipe - && memcmp(&mpo_pipe->plane_state->clip_rect, - &pipe->stream->src, - sizeof(struct rect)) != 0) { - ASSERT(mpo_pipe->plane_state != pipe->plane_state); - goto validate_fail; - } - pipe_idx++; - } - - /*initialize pipe_just_split_from to invalid idx*/ - for (i = 0; i < MAX_PIPES; i++) - pipe_split_from[i] = -1; - - for (i = 0, pipe_idx = -1; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - struct pipe_ctx *hsplit_pipe = pipe->bottom_pipe; - - if (!pipe->stream || pipe_split_from[i] >= 0) - continue; - - pipe_idx++; - - if (!pipe->top_pipe && !pipe->plane_state && context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_idx]) { - hsplit_pipe = dcn20_find_secondary_pipe(dc, &context->res_ctx, dc->res_pool, pipe); - ASSERT(hsplit_pipe); - if (!dcn20_split_stream_for_odm( - dc, &context->res_ctx, - pipe, hsplit_pipe)) - goto validate_fail; - pipe_split_from[hsplit_pipe->pipe_idx] = pipe_idx; - dcn20_build_mapped_resource(dc, context, pipe->stream); - } - - if (!pipe->plane_state) - continue; - /* Skip 2nd half of already split pipe */ - if (pipe->top_pipe && pipe->plane_state == pipe->top_pipe->plane_state) - continue; - - if (split[i] == 2) { - if (!hsplit_pipe || hsplit_pipe->plane_state != pipe->plane_state) { - /* pipe not split previously needs split */ - hsplit_pipe = dcn20_find_secondary_pipe(dc, &context->res_ctx, dc->res_pool, pipe); - ASSERT(hsplit_pipe); - if (!hsplit_pipe) { - DC_FP_START(); - dcn20_fpu_adjust_dppclk(&context->bw_ctx.dml.vba, vlevel, context->bw_ctx.dml.vba.maxMpcComb, pipe_idx, true); - DC_FP_END(); - continue; - } - if (context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_idx]) { - if (!dcn20_split_stream_for_odm( - dc, &context->res_ctx, - pipe, hsplit_pipe)) - goto validate_fail; - dcn20_build_mapped_resource(dc, context, pipe->stream); - } else { - dcn20_split_stream_for_mpc( - &context->res_ctx, dc->res_pool, - pipe, hsplit_pipe); - resource_build_scaling_params(pipe); - resource_build_scaling_params(hsplit_pipe); - } - pipe_split_from[hsplit_pipe->pipe_idx] = pipe_idx; - } - } else if (hsplit_pipe && hsplit_pipe->plane_state == pipe->plane_state) { - /* merge should already have been done */ - ASSERT(0); - } - } - /* Actual dsc count per stream dsc validation*/ - if (!dcn20_validate_dsc(dc, context)) { - context->bw_ctx.dml.vba.ValidationStatus[context->bw_ctx.dml.vba.soc.num_states] = - DML_FAIL_DSC_VALIDATION_FAILURE; - goto validate_fail; - } - - *vlevel_out = vlevel; - - out = true; - goto validate_out; - -validate_fail: - out = false; - -validate_out: - return out; -} - -/* - * Some of the functions further below use the FPU, so we need to wrap this - * with DC_FP_START()/DC_FP_END(). Use the same approach as for - * dcn20_validate_bandwidth in dcn20_resource.c. - */ -static bool dcn21_validate_bandwidth(struct dc *dc, struct dc_state *context, - bool fast_validate) -{ - bool voltage_supported; - display_e2e_pipe_params_st *pipes; - - pipes = kcalloc(dc->res_pool->pipe_count, sizeof(display_e2e_pipe_params_st), GFP_KERNEL); - if (!pipes) - return false; - - DC_FP_START(); - voltage_supported = dcn21_validate_bandwidth_fp(dc, context, fast_validate, pipes); - DC_FP_END(); - - kfree(pipes); - return voltage_supported; -} - -static void dcn21_destroy_resource_pool(struct resource_pool **pool) -{ - struct dcn21_resource_pool *dcn21_pool = TO_DCN21_RES_POOL(*pool); - - dcn21_resource_destruct(dcn21_pool); - kfree(dcn21_pool); - *pool = NULL; -} - -static struct clock_source *dcn21_clock_source_create( - struct dc_context *ctx, - struct dc_bios *bios, - enum clock_source_id id, - const struct dce110_clk_src_regs *regs, - bool dp_clk_src) -{ - struct dce110_clk_src *clk_src = - kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); - - if (!clk_src) - return NULL; - - if (dcn20_clk_src_construct(clk_src, ctx, bios, id, - regs, &cs_shift, &cs_mask)) { - clk_src->base.dp_clk_src = dp_clk_src; - return &clk_src->base; - } - - kfree(clk_src); - BREAK_TO_DEBUGGER(); - return NULL; -} - -static struct hubp *dcn21_hubp_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn21_hubp *hubp21 = - kzalloc(sizeof(struct dcn21_hubp), GFP_KERNEL); - - if (!hubp21) - return NULL; - - if (hubp21_construct(hubp21, ctx, inst, - &hubp_regs[inst], &hubp_shift, &hubp_mask)) - return &hubp21->base; - - BREAK_TO_DEBUGGER(); - kfree(hubp21); - return NULL; -} - -static struct hubbub *dcn21_hubbub_create(struct dc_context *ctx) -{ - int i; - - struct dcn20_hubbub *hubbub = kzalloc(sizeof(struct dcn20_hubbub), - GFP_KERNEL); - - if (!hubbub) - return NULL; - - hubbub21_construct(hubbub, ctx, - &hubbub_reg, - &hubbub_shift, - &hubbub_mask); - - for (i = 0; i < res_cap_rn.num_vmid; i++) { - struct dcn20_vmid *vmid = &hubbub->vmid[i]; - - vmid->ctx = ctx; - - vmid->regs = &vmid_regs[i]; - vmid->shifts = &vmid_shifts; - vmid->masks = &vmid_masks; - } - hubbub->num_vmid = res_cap_rn.num_vmid; - - return &hubbub->base; -} - -static struct output_pixel_processor *dcn21_opp_create(struct dc_context *ctx, - uint32_t inst) -{ - struct dcn20_opp *opp = - kzalloc(sizeof(struct dcn20_opp), GFP_KERNEL); - - if (!opp) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dcn20_opp_construct(opp, ctx, inst, - &opp_regs[inst], &opp_shift, &opp_mask); - return &opp->base; -} - -static struct timing_generator *dcn21_timing_generator_create(struct dc_context *ctx, - uint32_t instance) -{ - struct optc *tgn10 = - kzalloc(sizeof(struct optc), GFP_KERNEL); - - if (!tgn10) - return NULL; - - tgn10->base.inst = instance; - tgn10->base.ctx = ctx; - - tgn10->tg_regs = &tg_regs[instance]; - tgn10->tg_shift = &tg_shift; - tgn10->tg_mask = &tg_mask; - - dcn20_timing_generator_init(tgn10); - - return &tgn10->base; -} - -static struct mpc *dcn21_mpc_create(struct dc_context *ctx) -{ - struct dcn20_mpc *mpc20 = kzalloc(sizeof(struct dcn20_mpc), - GFP_KERNEL); - - if (!mpc20) - return NULL; - - dcn20_mpc_construct(mpc20, ctx, - &mpc_regs, - &mpc_shift, - &mpc_mask, - 6); - - return &mpc20->base; -} - -static void read_dce_straps( - struct dc_context *ctx, - struct resource_straps *straps) -{ - generic_reg_get(ctx, mmDC_PINSTRAPS + BASE(mmDC_PINSTRAPS_BASE_IDX), - FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio); - -} - - -static struct display_stream_compressor *dcn21_dsc_create(struct dc_context *ctx, - uint32_t inst) -{ - struct dcn20_dsc *dsc = - kzalloc(sizeof(struct dcn20_dsc), GFP_KERNEL); - - if (!dsc) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dsc2_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask); - return &dsc->base; -} - -static struct pp_smu_funcs *dcn21_pp_smu_create(struct dc_context *ctx) -{ - struct pp_smu_funcs *pp_smu = kzalloc(sizeof(*pp_smu), GFP_KERNEL); - - if (!pp_smu) - return pp_smu; - - dm_pp_get_funcs(ctx, pp_smu); - - if (pp_smu->ctx.ver != PP_SMU_VER_RN) - pp_smu = memset(pp_smu, 0, sizeof(struct pp_smu_funcs)); - - - return pp_smu; -} - -static void dcn21_pp_smu_destroy(struct pp_smu_funcs **pp_smu) -{ - if (pp_smu && *pp_smu) { - kfree(*pp_smu); - *pp_smu = NULL; - } -} - -static struct audio *dcn21_create_audio( - struct dc_context *ctx, unsigned int inst) -{ - return dce_audio_create(ctx, inst, - &audio_regs[inst], &audio_shift, &audio_mask); -} - -static struct dc_cap_funcs cap_funcs = { - .get_dcc_compression_cap = dcn20_get_dcc_compression_cap -}; - -static struct stream_encoder *dcn21_stream_encoder_create(enum engine_id eng_id, - struct dc_context *ctx) -{ - struct dcn10_stream_encoder *enc1 = - kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL); - - if (!enc1) - return NULL; - - dcn20_stream_encoder_construct(enc1, ctx, ctx->dc_bios, eng_id, - &stream_enc_regs[eng_id], - &se_shift, &se_mask); - - return &enc1->base; -} - -static const struct dce_hwseq_registers hwseq_reg = { - HWSEQ_DCN21_REG_LIST() -}; - -static const struct dce_hwseq_shift hwseq_shift = { - HWSEQ_DCN21_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_hwseq_mask hwseq_mask = { - HWSEQ_DCN21_MASK_SH_LIST(_MASK) -}; - -static struct dce_hwseq *dcn21_hwseq_create( - struct dc_context *ctx) -{ - struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); - - if (hws) { - hws->ctx = ctx; - hws->regs = &hwseq_reg; - hws->shifts = &hwseq_shift; - hws->masks = &hwseq_mask; - hws->wa.DEGVIDCN21 = true; - hws->wa.disallow_self_refresh_during_multi_plane_transition = true; - } - return hws; -} - -static const struct resource_create_funcs res_create_funcs = { - .read_dce_straps = read_dce_straps, - .create_audio = dcn21_create_audio, - .create_stream_encoder = dcn21_stream_encoder_create, - .create_hwseq = dcn21_hwseq_create, -}; - -static const struct encoder_feature_support link_enc_feature = { - .max_hdmi_deep_color = COLOR_DEPTH_121212, - .max_hdmi_pixel_clock = 600000, - .hdmi_ycbcr420_supported = true, - .dp_ycbcr420_supported = true, - .fec_supported = true, - .flags.bits.IS_HBR2_CAPABLE = true, - .flags.bits.IS_HBR3_CAPABLE = true, - .flags.bits.IS_TPS3_CAPABLE = true, - .flags.bits.IS_TPS4_CAPABLE = true -}; - - -#define link_regs(id, phyid)\ -[id] = {\ - LE_DCN2_REG_LIST(id), \ - UNIPHY_DCN2_REG_LIST(phyid), \ - DPCS_DCN21_REG_LIST(id), \ - SRI(DP_DPHY_INTERNAL_CTRL, DP, id) \ -} - -static const struct dcn10_link_enc_registers link_enc_regs[] = { - link_regs(0, A), - link_regs(1, B), - link_regs(2, C), - link_regs(3, D), - link_regs(4, E), -}; - -static const struct dce_panel_cntl_registers panel_cntl_regs[] = { - { DCN_PANEL_CNTL_REG_LIST() } -}; - -static const struct dce_panel_cntl_shift panel_cntl_shift = { - DCE_PANEL_CNTL_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_panel_cntl_mask panel_cntl_mask = { - DCE_PANEL_CNTL_MASK_SH_LIST(_MASK) -}; - -#define aux_regs(id)\ -[id] = {\ - DCN2_AUX_REG_LIST(id)\ -} - -static const struct dcn10_link_enc_aux_registers link_enc_aux_regs[] = { - aux_regs(0), - aux_regs(1), - aux_regs(2), - aux_regs(3), - aux_regs(4) -}; - -#define hpd_regs(id)\ -[id] = {\ - HPD_REG_LIST(id)\ -} - -static const struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[] = { - hpd_regs(0), - hpd_regs(1), - hpd_regs(2), - hpd_regs(3), - hpd_regs(4) -}; - -static const struct dcn10_link_enc_shift le_shift = { - LINK_ENCODER_MASK_SH_LIST_DCN20(__SHIFT),\ - DPCS_DCN21_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn10_link_enc_mask le_mask = { - LINK_ENCODER_MASK_SH_LIST_DCN20(_MASK),\ - DPCS_DCN21_MASK_SH_LIST(_MASK) -}; - -static int map_transmitter_id_to_phy_instance( - enum transmitter transmitter) -{ - switch (transmitter) { - case TRANSMITTER_UNIPHY_A: - return 0; - break; - case TRANSMITTER_UNIPHY_B: - return 1; - break; - case TRANSMITTER_UNIPHY_C: - return 2; - break; - case TRANSMITTER_UNIPHY_D: - return 3; - break; - case TRANSMITTER_UNIPHY_E: - return 4; - break; - default: - ASSERT(0); - return 0; - } -} - -static struct link_encoder *dcn21_link_encoder_create( - struct dc_context *ctx, - const struct encoder_init_data *enc_init_data) -{ - struct dcn21_link_encoder *enc21 = - kzalloc(sizeof(struct dcn21_link_encoder), GFP_KERNEL); - int link_regs_id; - - if (!enc21) - return NULL; - - link_regs_id = - map_transmitter_id_to_phy_instance(enc_init_data->transmitter); - - dcn21_link_encoder_construct(enc21, - enc_init_data, - &link_enc_feature, - &link_enc_regs[link_regs_id], - &link_enc_aux_regs[enc_init_data->channel - 1], - &link_enc_hpd_regs[enc_init_data->hpd_source], - &le_shift, - &le_mask); - - return &enc21->enc10.base; -} - -static struct panel_cntl *dcn21_panel_cntl_create(const struct panel_cntl_init_data *init_data) -{ - struct dce_panel_cntl *panel_cntl = - kzalloc(sizeof(struct dce_panel_cntl), GFP_KERNEL); - - if (!panel_cntl) - return NULL; - - dce_panel_cntl_construct(panel_cntl, - init_data, - &panel_cntl_regs[init_data->inst], - &panel_cntl_shift, - &panel_cntl_mask); - - return &panel_cntl->base; -} - -static void dcn21_get_panel_config_defaults(struct dc_panel_config *panel_config) -{ - *panel_config = panel_config_defaults; -} - -#define CTX ctx - -#define REG(reg_name) \ - (DCN_BASE.instance[0].segment[mm ## reg_name ## _BASE_IDX] + mm ## reg_name) - -static uint32_t read_pipe_fuses(struct dc_context *ctx) -{ - uint32_t value = REG_READ(CC_DC_PIPE_DIS); - /* RV1 support max 4 pipes */ - value = value & 0xf; - return value; -} - -static enum dc_status dcn21_patch_unknown_plane_state(struct dc_plane_state *plane_state) -{ - 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; - } - - return dcn20_patch_unknown_plane_state(plane_state); -} - -static const struct resource_funcs dcn21_res_pool_funcs = { - .destroy = dcn21_destroy_resource_pool, - .link_enc_create = dcn21_link_encoder_create, - .panel_cntl_create = dcn21_panel_cntl_create, - .validate_bandwidth = dcn21_validate_bandwidth, - .populate_dml_pipes = dcn21_populate_dml_pipes_from_context, - .add_stream_to_ctx = dcn20_add_stream_to_ctx, - .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource, - .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, - .acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer, - .release_pipe = dcn20_release_pipe, - .populate_dml_writeback_from_context = dcn20_populate_dml_writeback_from_context, - .patch_unknown_plane_state = dcn21_patch_unknown_plane_state, - .set_mcif_arb_params = dcn20_set_mcif_arb_params, - .find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link, - .update_bw_bounding_box = dcn21_update_bw_bounding_box, - .get_panel_config_defaults = dcn21_get_panel_config_defaults, -}; - -static bool dcn21_resource_construct( - uint8_t num_virtual_links, - struct dc *dc, - struct dcn21_resource_pool *pool) -{ - int i, j; - struct dc_context *ctx = dc->ctx; - struct irq_service_init_data init_data; - uint32_t pipe_fuses = read_pipe_fuses(ctx); - uint32_t num_pipes; - - ctx->dc_bios->regs = &bios_regs; - - pool->base.res_cap = &res_cap_rn; -#ifdef DIAGS_BUILD - if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) - //pool->base.res_cap = &res_cap_nv10_FPGA_2pipe_dsc; - pool->base.res_cap = &res_cap_rn_FPGA_4pipe; -#endif - - pool->base.funcs = &dcn21_res_pool_funcs; - - /************************************************* - * Resource + asic cap harcoding * - *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; - - /* max pipe num for ASIC before check pipe fuses */ - pool->base.pipe_count = pool->base.res_cap->num_timing_generator; - - dc->caps.max_downscale_ratio = 200; - dc->caps.i2c_speed_in_khz = 100; - dc->caps.i2c_speed_in_khz_hdcp = 5; /*1.4 w/a applied by default*/ - dc->caps.max_cursor_size = 256; - dc->caps.min_horizontal_blanking_period = 80; - dc->caps.dmdata_alloc_size = 2048; - - dc->caps.max_slave_planes = 1; - dc->caps.max_slave_yuv_planes = 1; - dc->caps.max_slave_rgb_planes = 1; - dc->caps.post_blend_color_processing = true; - dc->caps.force_dp_tps4_for_cp2520 = true; - dc->caps.extended_aux_timeout_support = true; - dc->caps.dmcub_support = true; - dc->caps.is_apu = true; - - /* Color pipeline capabilities */ - dc->caps.color.dpp.dcn_arch = 1; - dc->caps.color.dpp.input_lut_shared = 0; - dc->caps.color.dpp.icsc = 1; - dc->caps.color.dpp.dgam_ram = 1; - dc->caps.color.dpp.dgam_rom_caps.srgb = 1; - dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1; - dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 0; - dc->caps.color.dpp.dgam_rom_caps.pq = 0; - dc->caps.color.dpp.dgam_rom_caps.hlg = 0; - dc->caps.color.dpp.post_csc = 0; - dc->caps.color.dpp.gamma_corr = 0; - dc->caps.color.dpp.dgam_rom_for_yuv = 1; - - dc->caps.color.dpp.hw_3d_lut = 1; - dc->caps.color.dpp.ogam_ram = 1; - // no OGAM ROM on DCN2 - dc->caps.color.dpp.ogam_rom_caps.srgb = 0; - dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0; - dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0; - dc->caps.color.dpp.ogam_rom_caps.pq = 0; - dc->caps.color.dpp.ogam_rom_caps.hlg = 0; - dc->caps.color.dpp.ocsc = 0; - - dc->caps.color.mpc.gamut_remap = 0; - dc->caps.color.mpc.num_3dluts = 0; - dc->caps.color.mpc.shared_3d_lut = 0; - dc->caps.color.mpc.ogam_ram = 1; - dc->caps.color.mpc.ogam_rom_caps.srgb = 0; - dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0; - dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0; - dc->caps.color.mpc.ogam_rom_caps.pq = 0; - dc->caps.color.mpc.ogam_rom_caps.hlg = 0; - dc->caps.color.mpc.ocsc = 1; - - dc->caps.dp_hdmi21_pcon_support = true; - - if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) - dc->debug = debug_defaults_drv; - - // Init the vm_helper - if (dc->vm_helper) - vm_helper_init(dc->vm_helper, 16); - - /************************************************* - * Create resources * - *************************************************/ - - pool->base.clock_sources[DCN20_CLK_SRC_PLL0] = - dcn21_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL0, - &clk_src_regs[0], false); - pool->base.clock_sources[DCN20_CLK_SRC_PLL1] = - dcn21_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL1, - &clk_src_regs[1], false); - pool->base.clock_sources[DCN20_CLK_SRC_PLL2] = - dcn21_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL2, - &clk_src_regs[2], false); - pool->base.clock_sources[DCN20_CLK_SRC_PLL3] = - dcn21_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL3, - &clk_src_regs[3], false); - pool->base.clock_sources[DCN20_CLK_SRC_PLL4] = - dcn21_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL4, - &clk_src_regs[4], false); - - pool->base.clk_src_count = DCN20_CLK_SRC_TOTAL_DCN21; - - /* todo: not reuse phy_pll registers */ - pool->base.dp_clock_source = - dcn21_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_ID_DP_DTO, - &clk_src_regs[0], true); - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] == NULL) { - dm_error("DC: failed to create clock sources!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - } - - pool->base.dccg = dccg21_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask); - if (pool->base.dccg == NULL) { - dm_error("DC: failed to create dccg!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - - if (!dc->config.disable_dmcu) { - pool->base.dmcu = dcn21_dmcu_create(ctx, - &dmcu_regs, - &dmcu_shift, - &dmcu_mask); - if (pool->base.dmcu == NULL) { - dm_error("DC: failed to create dmcu!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - - dc->debug.dmub_command_table = false; - } - - if (dc->config.disable_dmcu) { - pool->base.psr = dmub_psr_create(ctx); - - if (pool->base.psr == NULL) { - dm_error("DC: failed to create psr obj!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - } - - if (dc->config.disable_dmcu) - pool->base.abm = dmub_abm_create(ctx, - &abm_regs, - &abm_shift, - &abm_mask); - else - pool->base.abm = dce_abm_create(ctx, - &abm_regs, - &abm_shift, - &abm_mask); - - pool->base.pp_smu = dcn21_pp_smu_create(ctx); - - num_pipes = dcn2_1_ip.max_num_dpp; - - for (i = 0; i < dcn2_1_ip.max_num_dpp; i++) - if (pipe_fuses & 1 << i) - num_pipes--; - dcn2_1_ip.max_num_dpp = num_pipes; - dcn2_1_ip.max_num_otg = num_pipes; - - dml_init_instance(&dc->dml, &dcn2_1_soc, &dcn2_1_ip, DML_PROJECT_DCN21); - - init_data.ctx = dc->ctx; - pool->base.irqs = dal_irq_service_dcn21_create(&init_data); - if (!pool->base.irqs) - goto create_fail; - - j = 0; - /* mem input -> ipp -> dpp -> opp -> TG */ - for (i = 0; i < pool->base.pipe_count; i++) { - /* if pipe is disabled, skip instance of HW pipe, - * i.e, skip ASIC register instance - */ - if ((pipe_fuses & (1 << i)) != 0) - continue; - - pool->base.hubps[j] = dcn21_hubp_create(ctx, i); - if (pool->base.hubps[j] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create memory input!\n"); - goto create_fail; - } - - pool->base.ipps[j] = dcn21_ipp_create(ctx, i); - if (pool->base.ipps[j] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create input pixel processor!\n"); - goto create_fail; - } - - pool->base.dpps[j] = dcn21_dpp_create(ctx, i); - if (pool->base.dpps[j] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create dpps!\n"); - goto create_fail; - } - - pool->base.opps[j] = dcn21_opp_create(ctx, i); - if (pool->base.opps[j] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create output pixel processor!\n"); - goto create_fail; - } - - pool->base.timing_generators[j] = dcn21_timing_generator_create( - ctx, i); - if (pool->base.timing_generators[j] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create tg!\n"); - goto create_fail; - } - j++; - } - - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - pool->base.engines[i] = dcn21_aux_engine_create(ctx, i); - if (pool->base.engines[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create aux engine!!\n"); - goto create_fail; - } - pool->base.hw_i2cs[i] = dcn21_i2c_hw_create(ctx, i); - if (pool->base.hw_i2cs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create hw i2c!!\n"); - goto create_fail; - } - pool->base.sw_i2cs[i] = NULL; - } - - pool->base.timing_generator_count = j; - pool->base.pipe_count = j; - pool->base.mpcc_count = j; - - pool->base.mpc = dcn21_mpc_create(ctx); - if (pool->base.mpc == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create mpc!\n"); - goto create_fail; - } - - pool->base.hubbub = dcn21_hubbub_create(ctx); - if (pool->base.hubbub == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create hubbub!\n"); - goto create_fail; - } - - for (i = 0; i < pool->base.res_cap->num_dsc; i++) { - pool->base.dscs[i] = dcn21_dsc_create(ctx, i); - if (pool->base.dscs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create display stream compressor %d!\n", i); - goto create_fail; - } - } - - if (!dcn20_dwbc_create(ctx, &pool->base)) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create dwbc!\n"); - goto create_fail; - } - if (!dcn20_mmhubbub_create(ctx, &pool->base)) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create mcif_wb!\n"); - goto create_fail; - } - - if (!resource_construct(num_virtual_links, dc, &pool->base, - &res_create_funcs)) - goto create_fail; - - dcn21_hw_sequencer_construct(dc); - - dc->caps.max_planes = pool->base.pipe_count; - - for (i = 0; i < dc->caps.max_planes; ++i) - dc->caps.planes[i] = plane_cap; - - dc->cap_funcs = cap_funcs; - - return true; - -create_fail: - - dcn21_resource_destruct(pool); - - return false; -} - -struct resource_pool *dcn21_create_resource_pool( - const struct dc_init_data *init_data, - struct dc *dc) -{ - struct dcn21_resource_pool *pool = - kzalloc(sizeof(struct dcn21_resource_pool), GFP_KERNEL); - - if (!pool) - return NULL; - - if (dcn21_resource_construct(init_data->num_virtual_links, dc, pool)) - return &pool->base; - - BREAK_TO_DEBUGGER(); - kfree(pool); - return NULL; -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.h b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.h deleted file mode 100644 index f7ecc002c2f7f6..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2018 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 _DCN21_RESOURCE_H_ -#define _DCN21_RESOURCE_H_ - -#include "core_types.h" - -#define TO_DCN21_RES_POOL(pool)\ - container_of(pool, struct dcn21_resource_pool, base) - -struct dc; -struct resource_pool; -struct _vcs_dpi_display_pipe_params_st; - -extern struct _vcs_dpi_ip_params_st dcn2_1_ip; -extern struct _vcs_dpi_soc_bounding_box_st dcn2_1_soc; - -struct dcn21_resource_pool { - struct resource_pool base; -}; -struct resource_pool *dcn21_create_resource_pool( - const struct dc_init_data *init_data, - struct dc *dc); -bool dcn21_fast_validate_bw( - struct dc *dc, - struct dc_state *context, - display_e2e_pipe_params_st *pipes, - int *pipe_cnt_out, - int *pipe_split_from, - int *vlevel_out, - bool fast_validate); - -#endif /* _DCN21_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/Makefile b/drivers/gpu/drm/amd/display/dc/dcn30/Makefile index af4d2065d2c13f..b5b2aa3b378397 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn30/Makefile @@ -23,12 +23,9 @@ # # -DCN30 := \ - dcn30_init.o \ - dcn30_hubbub.o \ +DCN30 := dcn30_hubbub.o \ dcn30_hubp.o \ dcn30_dpp.o \ - dcn30_optc.o \ dcn30_dccg.o \ dcn30_mpc.o dcn30_vpg.o \ dcn30_afmt.o \ @@ -38,7 +35,6 @@ DCN30 := \ dcn30_dwb_cm.o \ dcn30_cm_common.o \ dcn30_mmhubbub.o \ - dcn30_resource.o \ dcn30_dio_link_encoder.o diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dwb.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dwb.c index 0d98918bf0fc41..1b9d9495f76de9 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dwb.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dwb.c @@ -130,6 +130,28 @@ bool dwb3_disable(struct dwbc *dwbc) return true; } +void dwb3_set_fc_enable(struct dwbc *dwbc, enum dwb_frame_capture_enable enable) +{ + struct dcn30_dwbc *dwbc30 = TO_DCN30_DWBC(dwbc); + unsigned int pre_locked; + + REG_GET(DWB_UPDATE_CTRL, DWB_UPDATE_LOCK, &pre_locked); + + /* Lock DWB registers */ + if (pre_locked == 0) + REG_UPDATE(DWB_UPDATE_CTRL, DWB_UPDATE_LOCK, 1); + + /* Disable FC */ + REG_UPDATE(FC_MODE_CTRL, FC_FRAME_CAPTURE_EN, enable); + + /* Unlock DWB registers */ + if (pre_locked == 0) + REG_UPDATE(DWB_UPDATE_CTRL, DWB_UPDATE_LOCK, 0); + + DC_LOG_DWB("%s dwb3_fc_disabled at inst = %d", __func__, dwbc->inst); +} + + bool dwb3_update(struct dwbc *dwbc, struct dc_dwb_params *params) { struct dcn30_dwbc *dwbc30 = TO_DCN30_DWBC(dwbc); @@ -226,6 +248,7 @@ static const struct dwbc_funcs dcn30_dwbc_funcs = { .disable = dwb3_disable, .update = dwb3_update, .is_enabled = dwb3_is_enabled, + .set_fc_enable = dwb3_set_fc_enable, .set_stereo = dwb3_set_stereo, .set_new_content = dwb3_set_new_content, .dwb_program_output_csc = NULL, diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dwb.h b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dwb.h index a5d1b81e768dd8..332634b76aacda 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dwb.h +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dwb.h @@ -877,6 +877,8 @@ bool dwb3_update(struct dwbc *dwbc, struct dc_dwb_params *params); bool dwb3_is_enabled(struct dwbc *dwbc); +void dwb3_set_fc_enable(struct dwbc *dwbc, enum dwb_frame_capture_enable enable); + void dwb3_set_stereo(struct dwbc *dwbc, struct dwb_stereo_params *stereo_params); diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dwb_cm.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dwb_cm.c index 701c7d8bc038ae..03a50c32fcfe1f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dwb_cm.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dwb_cm.c @@ -243,6 +243,9 @@ static bool dwb3_program_ogam_lut( return false; } + if (params->hw_points_num == 0) + return false; + REG_SET(DWB_OGAM_CONTROL, 0, DWB_OGAM_MODE, 2); current_mode = dwb3_get_ogam_current(dwbc30); diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_init.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_init.c deleted file mode 100644 index 9894caedffed73..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_init.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2016-2020 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 "dce110/dce110_hwseq.h" -#include "dcn10/dcn10_hwseq.h" -#include "dcn20/dcn20_hwseq.h" -#include "dcn21/dcn21_hwseq.h" -#include "dcn30/dcn30_hwseq.h" - -#include "dcn30_init.h" - -static const struct hw_sequencer_funcs dcn30_funcs = { - .program_gamut_remap = dcn30_program_gamut_remap, - .init_hw = dcn30_init_hw, - .apply_ctx_to_hw = dce110_apply_ctx_to_hw, - .apply_ctx_for_surface = NULL, - .program_front_end_for_ctx = dcn20_program_front_end_for_ctx, - .wait_for_pending_cleared = dcn10_wait_for_pending_cleared, - .post_unlock_program_front_end = dcn20_post_unlock_program_front_end, - .update_plane_addr = dcn20_update_plane_addr, - .update_dchub = dcn10_update_dchub, - .update_pending_status = dcn10_update_pending_status, - .program_output_csc = dcn20_program_output_csc, - .enable_accelerated_mode = dce110_enable_accelerated_mode, - .enable_timing_synchronization = dcn10_enable_timing_synchronization, - .enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset, - .update_info_frame = dcn30_update_info_frame, - .send_immediate_sdp_message = dcn10_send_immediate_sdp_message, - .enable_stream = dcn20_enable_stream, - .disable_stream = dce110_disable_stream, - .unblank_stream = dcn20_unblank_stream, - .blank_stream = dce110_blank_stream, - .enable_audio_stream = dce110_enable_audio_stream, - .disable_audio_stream = dce110_disable_audio_stream, - .disable_plane = dcn20_disable_plane, - .disable_pixel_data = dcn20_disable_pixel_data, - .pipe_control_lock = dcn20_pipe_control_lock, - .interdependent_update_lock = dcn10_lock_all_pipes, - .cursor_lock = dcn10_cursor_lock, - .prepare_bandwidth = dcn30_prepare_bandwidth, - .optimize_bandwidth = dcn20_optimize_bandwidth, - .update_bandwidth = dcn20_update_bandwidth, - .set_drr = dcn10_set_drr, - .get_position = dcn10_get_position, - .set_static_screen_control = dcn30_set_static_screen_control, - .setup_stereo = dcn10_setup_stereo, - .set_avmute = dcn30_set_avmute, - .log_hw_state = dcn10_log_hw_state, - .get_hw_state = dcn10_get_hw_state, - .clear_status_bits = dcn10_clear_status_bits, - .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, - .edp_backlight_control = dce110_edp_backlight_control, - .edp_power_control = dce110_edp_power_control, - .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, - .edp_wait_for_T12 = dce110_edp_wait_for_T12, - .set_cursor_position = dcn10_set_cursor_position, - .set_cursor_attribute = dcn10_set_cursor_attribute, - .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level, - .setup_periodic_interrupt = dcn10_setup_periodic_interrupt, - .set_clock = dcn10_set_clock, - .get_clock = dcn10_get_clock, - .program_triplebuffer = dcn20_program_triple_buffer, - .enable_writeback = dcn30_enable_writeback, - .disable_writeback = dcn30_disable_writeback, - .update_writeback = dcn30_update_writeback, - .mmhubbub_warmup = dcn30_mmhubbub_warmup, - .dmdata_status_done = dcn20_dmdata_status_done, - .program_dmdata_engine = dcn30_program_dmdata_engine, - .set_dmdata_attributes = dcn20_set_dmdata_attributes, - .init_sys_ctx = dcn20_init_sys_ctx, - .init_vm_ctx = dcn20_init_vm_ctx, - .set_flip_control_gsl = dcn20_set_flip_control_gsl, - .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync, - .calc_vupdate_position = dcn10_calc_vupdate_position, - .apply_idle_power_optimizations = dcn30_apply_idle_power_optimizations, - .does_plane_fit_in_mall = dcn30_does_plane_fit_in_mall, - .set_backlight_level = dcn21_set_backlight_level, - .set_abm_immediate_disable = dcn21_set_abm_immediate_disable, - .hardware_release = dcn30_hardware_release, - .set_pipe = dcn21_set_pipe, - .enable_lvds_link_output = dce110_enable_lvds_link_output, - .enable_tmds_link_output = dce110_enable_tmds_link_output, - .enable_dp_link_output = dce110_enable_dp_link_output, - .disable_link_output = dce110_disable_link_output, - .set_disp_pattern_generator = dcn30_set_disp_pattern_generator, - .get_dcc_en_bits = dcn10_get_dcc_en_bits, - .update_visual_confirm_color = dcn10_update_visual_confirm_color, - .is_abm_supported = dcn21_is_abm_supported -}; - -static const struct hwseq_private_funcs dcn30_private_funcs = { - .init_pipes = dcn10_init_pipes, - .update_plane_addr = dcn20_update_plane_addr, - .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, - .update_mpcc = dcn20_update_mpcc, - .set_input_transfer_func = dcn30_set_input_transfer_func, - .set_output_transfer_func = dcn30_set_output_transfer_func, - .power_down = dce110_power_down, - .enable_display_power_gating = dcn10_dummy_display_power_gating, - .blank_pixel_data = dcn20_blank_pixel_data, - .reset_hw_ctx_wrap = dcn20_reset_hw_ctx_wrap, - .enable_stream_timing = dcn20_enable_stream_timing, - .edp_backlight_control = dce110_edp_backlight_control, - .disable_stream_gating = dcn20_disable_stream_gating, - .enable_stream_gating = dcn20_enable_stream_gating, - .setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt, - .did_underflow_occur = dcn10_did_underflow_occur, - .init_blank = dcn20_init_blank, - .disable_vga = dcn20_disable_vga, - .bios_golden_init = dcn10_bios_golden_init, - .plane_atomic_disable = dcn20_plane_atomic_disable, - .plane_atomic_power_down = dcn10_plane_atomic_power_down, - .enable_power_gating_plane = dcn20_enable_power_gating_plane, - .dpp_pg_control = dcn20_dpp_pg_control, - .hubp_pg_control = dcn20_hubp_pg_control, - .program_all_writeback_pipes_in_tree = dcn30_program_all_writeback_pipes_in_tree, - .update_odm = dcn20_update_odm, - .dsc_pg_control = dcn20_dsc_pg_control, - .set_hdr_multiplier = dcn10_set_hdr_multiplier, - .verify_allow_pstate_change_high = dcn10_verify_allow_pstate_change_high, - .wait_for_blank_complete = dcn20_wait_for_blank_complete, - .dccg_init = dcn20_dccg_init, - .set_blend_lut = dcn30_set_blend_lut, - .set_shaper_3dlut = dcn20_set_shaper_3dlut, -}; - -void dcn30_hw_sequencer_construct(struct dc *dc) -{ - dc->hwss = dcn30_funcs; - dc->hwseq->funcs = dcn30_private_funcs; - -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_init.h b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_init.h deleted file mode 100644 index c280ff90bfa3b6..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_init.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2020 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_DCN30_INIT_H__ -#define __DC_DCN30_INIT_H__ - -struct dc; - -void dcn30_hw_sequencer_construct(struct dc *dc); - -#endif /* __DC_DCN30_INIT_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c deleted file mode 100644 index b97bdb868a0e7f..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c +++ /dev/null @@ -1,393 +0,0 @@ -/* - * Copyright 2020 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 "reg_helper.h" -#include "dcn30_optc.h" -#include "dc.h" -#include "dcn_calc_math.h" -#include "dc_dmub_srv.h" - -#include "dml/dcn30/dcn30_fpu.h" -#include "dc_trace.h" - -#define REG(reg)\ - optc1->tg_regs->reg - -#define CTX \ - optc1->base.ctx - -#undef FN -#define FN(reg_name, field_name) \ - optc1->tg_shift->field_name, optc1->tg_mask->field_name - -void optc3_triplebuffer_lock(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_UPDATE(OTG_GLOBAL_CONTROL2, - OTG_MASTER_UPDATE_LOCK_SEL, optc->inst); - - REG_SET(OTG_VUPDATE_KEEPOUT, 0, - OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, 1); - - REG_SET(OTG_MASTER_UPDATE_LOCK, 0, - OTG_MASTER_UPDATE_LOCK, 1); - - REG_WAIT(OTG_MASTER_UPDATE_LOCK, - UPDATE_LOCK_STATUS, 1, - 1, 10); - - TRACE_OPTC_LOCK_UNLOCK_STATE(optc1, optc->inst, true); -} - -void optc3_lock_doublebuffer_enable(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - uint32_t v_blank_start = 0; - uint32_t v_blank_end = 0; - uint32_t h_blank_start = 0; - uint32_t h_blank_end = 0; - - REG_GET_2(OTG_V_BLANK_START_END, - OTG_V_BLANK_START, &v_blank_start, - OTG_V_BLANK_END, &v_blank_end); - REG_GET_2(OTG_H_BLANK_START_END, - OTG_H_BLANK_START, &h_blank_start, - OTG_H_BLANK_END, &h_blank_end); - - REG_UPDATE_2(OTG_GLOBAL_CONTROL1, - MASTER_UPDATE_LOCK_DB_START_Y, v_blank_start - 1, - MASTER_UPDATE_LOCK_DB_END_Y, v_blank_start); - REG_UPDATE_2(OTG_GLOBAL_CONTROL4, - DIG_UPDATE_POSITION_X, h_blank_start - 180 - 1, - DIG_UPDATE_POSITION_Y, v_blank_start - 1); - // there is a DIG_UPDATE_VCOUNT_MODE and it is 0. - - REG_UPDATE_3(OTG_GLOBAL_CONTROL0, - MASTER_UPDATE_LOCK_DB_START_X, h_blank_start - 200 - 1, - MASTER_UPDATE_LOCK_DB_END_X, h_blank_start - 180, - MASTER_UPDATE_LOCK_DB_EN, 1); - REG_UPDATE(OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, 1); - - REG_SET_3(OTG_VUPDATE_KEEPOUT, 0, - MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET, 0, - MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET, 100, - OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, 1); - - TRACE_OPTC_LOCK_UNLOCK_STATE(optc1, optc->inst, true); -} - -void optc3_lock_doublebuffer_disable(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_UPDATE_2(OTG_GLOBAL_CONTROL0, - MASTER_UPDATE_LOCK_DB_START_X, 0, - MASTER_UPDATE_LOCK_DB_END_X, 0); - REG_UPDATE_2(OTG_GLOBAL_CONTROL1, - MASTER_UPDATE_LOCK_DB_START_Y, 0, - MASTER_UPDATE_LOCK_DB_END_Y, 0); - - REG_UPDATE(OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, 0); - REG_UPDATE(OTG_GLOBAL_CONTROL0, MASTER_UPDATE_LOCK_DB_EN, 0); - - TRACE_OPTC_LOCK_UNLOCK_STATE(optc1, optc->inst, true); -} - -void optc3_lock(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_UPDATE(OTG_GLOBAL_CONTROL2, - OTG_MASTER_UPDATE_LOCK_SEL, optc->inst); - REG_SET(OTG_MASTER_UPDATE_LOCK, 0, - OTG_MASTER_UPDATE_LOCK, 1); - - REG_WAIT(OTG_MASTER_UPDATE_LOCK, - UPDATE_LOCK_STATUS, 1, - 1, 10); - - TRACE_OPTC_LOCK_UNLOCK_STATE(optc1, optc->inst, true); -} - -void optc3_set_out_mux(struct timing_generator *optc, enum otg_out_mux_dest dest) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_UPDATE(OTG_CONTROL, OTG_OUT_MUX, dest); -} - -void optc3_program_blank_color(struct timing_generator *optc, - const struct tg_color *blank_color) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_SET_3(OTG_BLANK_DATA_COLOR, 0, - OTG_BLANK_DATA_COLOR_BLUE_CB, blank_color->color_b_cb, - OTG_BLANK_DATA_COLOR_GREEN_Y, blank_color->color_g_y, - OTG_BLANK_DATA_COLOR_RED_CR, blank_color->color_r_cr); - - REG_SET_3(OTG_BLANK_DATA_COLOR_EXT, 0, - OTG_BLANK_DATA_COLOR_BLUE_CB_EXT, blank_color->color_b_cb >> 10, - OTG_BLANK_DATA_COLOR_GREEN_Y_EXT, blank_color->color_g_y >> 10, - OTG_BLANK_DATA_COLOR_RED_CR_EXT, blank_color->color_r_cr >> 10); -} - -void optc3_set_drr_trigger_window(struct timing_generator *optc, - uint32_t window_start, uint32_t window_end) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_SET_2(OTG_DRR_TRIGGER_WINDOW, 0, - OTG_DRR_TRIGGER_WINDOW_START_X, window_start, - OTG_DRR_TRIGGER_WINDOW_END_X, window_end); -} - -void optc3_set_vtotal_change_limit(struct timing_generator *optc, - uint32_t limit) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - - REG_SET(OTG_DRR_V_TOTAL_CHANGE, 0, - OTG_DRR_V_TOTAL_CHANGE_LIMIT, limit); -} - - -/* Set DSC-related configuration. - * dsc_mode: 0 disables DSC, other values enable DSC in specified format - * sc_bytes_per_pixel: Bytes per pixel in u3.28 format - * dsc_slice_width: Slice width in pixels - */ -void optc3_set_dsc_config(struct timing_generator *optc, - enum optc_dsc_mode dsc_mode, - uint32_t dsc_bytes_per_pixel, - uint32_t dsc_slice_width) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - optc2_set_dsc_config(optc, dsc_mode, dsc_bytes_per_pixel, dsc_slice_width); - REG_UPDATE(OTG_V_SYNC_A_CNTL, OTG_V_SYNC_MODE, 0); -} - -void optc3_set_odm_bypass(struct timing_generator *optc, - const struct dc_crtc_timing *dc_crtc_timing) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - enum h_timing_div_mode h_div = H_TIMING_NO_DIV; - - REG_SET_5(OPTC_DATA_SOURCE_SELECT, 0, - OPTC_NUM_OF_INPUT_SEGMENT, 0, - OPTC_SEG0_SRC_SEL, optc->inst, - OPTC_SEG1_SRC_SEL, 0xf, - OPTC_SEG2_SRC_SEL, 0xf, - OPTC_SEG3_SRC_SEL, 0xf - ); - - h_div = optc1_is_two_pixels_per_containter(dc_crtc_timing); - REG_UPDATE(OTG_H_TIMING_CNTL, - OTG_H_TIMING_DIV_MODE, h_div); - - REG_SET(OPTC_MEMORY_CONFIG, 0, - OPTC_MEM_SEL, 0); - optc1->opp_count = 1; -} - -void optc3_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, - struct dc_crtc_timing *timing) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - int mpcc_hactive = (timing->h_addressable + timing->h_border_left + timing->h_border_right) - / opp_cnt; - uint32_t memory_mask = 0; - - /* TODO: In pseudocode but does not affect maximus, delete comment if we dont need on asic - * REG_SET(OTG_GLOBAL_CONTROL2, 0, GLOBAL_UPDATE_LOCK_EN, 1); - * Program OTG register MASTER_UPDATE_LOCK_DB_X/Y to the position before DP frame start - * REG_SET_2(OTG_GLOBAL_CONTROL1, 0, - * MASTER_UPDATE_LOCK_DB_X, 160, - * MASTER_UPDATE_LOCK_DB_Y, 240); - */ - - ASSERT(opp_cnt == 2 || opp_cnt == 4); - - /* 2 pieces of memory required for up to 5120 displays, 4 for up to 8192, - * however, for ODM combine we can simplify by always using 4. - */ - if (opp_cnt == 2) { - /* To make sure there's no memory overlap, each instance "reserves" 2 - * memories and they are uniquely combined here. - */ - memory_mask = 0x3 << (opp_id[0] * 2) | 0x3 << (opp_id[1] * 2); - } else if (opp_cnt == 4) { - /* To make sure there's no memory overlap, each instance "reserves" 1 - * memory and they are uniquely combined here. - */ - memory_mask = 0x1 << (opp_id[0] * 2) | 0x1 << (opp_id[1] * 2) | 0x1 << (opp_id[2] * 2) | 0x1 << (opp_id[3] * 2); - } - - if (REG(OPTC_MEMORY_CONFIG)) - REG_SET(OPTC_MEMORY_CONFIG, 0, - OPTC_MEM_SEL, memory_mask); - - if (opp_cnt == 2) { - REG_SET_3(OPTC_DATA_SOURCE_SELECT, 0, - OPTC_NUM_OF_INPUT_SEGMENT, 1, - OPTC_SEG0_SRC_SEL, opp_id[0], - OPTC_SEG1_SRC_SEL, opp_id[1]); - } else if (opp_cnt == 4) { - REG_SET_5(OPTC_DATA_SOURCE_SELECT, 0, - OPTC_NUM_OF_INPUT_SEGMENT, 3, - OPTC_SEG0_SRC_SEL, opp_id[0], - OPTC_SEG1_SRC_SEL, opp_id[1], - OPTC_SEG2_SRC_SEL, opp_id[2], - OPTC_SEG3_SRC_SEL, opp_id[3]); - } - - REG_UPDATE(OPTC_WIDTH_CONTROL, - OPTC_SEGMENT_WIDTH, mpcc_hactive); - - REG_SET(OTG_H_TIMING_CNTL, 0, OTG_H_TIMING_DIV_MODE, opp_cnt - 1); - optc1->opp_count = opp_cnt; -} - -/** - * optc3_set_timing_double_buffer() - DRR double buffering control - * - * Sets double buffer point for V_TOTAL, H_TOTAL, VTOTAL_MIN, - * VTOTAL_MAX, VTOTAL_MIN_SEL and VTOTAL_MAX_SEL registers. - * - * @optc: timing_generator instance. - * @enable: Enable DRR double buffering control if true, disable otherwise. - * - * Options: any time, start of frame, dp start of frame (range timing) - */ -static void optc3_set_timing_double_buffer(struct timing_generator *optc, bool enable) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - uint32_t mode = enable ? 2 : 0; - - REG_UPDATE(OTG_DOUBLE_BUFFER_CONTROL, - 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) -{ - struct dc *dc = optc->ctx->dc; - - if (dc->caps.dmub_caps.mclk_sw && !dc->debug.disable_fams) - dc_dmub_srv_drr_update_cmd(dc, optc->inst, vtotal_min, vtotal_max); - else - optc1_set_vtotal_min_max(optc, vtotal_min, vtotal_max); -} - -void optc3_tg_init(struct timing_generator *optc) -{ - optc3_set_timing_double_buffer(optc, true); - optc1_clear_optc_underflow(optc); -} - -static struct timing_generator_funcs dcn30_tg_funcs = { - .validate_timing = optc1_validate_timing, - .program_timing = optc1_program_timing, - .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0, - .setup_vertical_interrupt1 = optc1_setup_vertical_interrupt1, - .setup_vertical_interrupt2 = optc1_setup_vertical_interrupt2, - .program_global_sync = optc1_program_global_sync, - .enable_crtc = optc2_enable_crtc, - .disable_crtc = optc1_disable_crtc, - /* used by enable_timing_synchronization. Not need for FPGA */ - .is_counter_moving = optc1_is_counter_moving, - .get_position = optc1_get_position, - .get_frame_count = optc1_get_vblank_counter, - .get_scanoutpos = optc1_get_crtc_scanoutpos, - .get_otg_active_size = optc1_get_otg_active_size, - .set_early_control = optc1_set_early_control, - /* used by enable_timing_synchronization. Not need for FPGA */ - .wait_for_state = optc1_wait_for_state, - .set_blank_color = optc3_program_blank_color, - .did_triggered_reset_occur = optc1_did_triggered_reset_occur, - .triplebuffer_lock = optc3_triplebuffer_lock, - .triplebuffer_unlock = optc2_triplebuffer_unlock, - .enable_reset_trigger = optc1_enable_reset_trigger, - .enable_crtc_reset = optc1_enable_crtc_reset, - .disable_reset_trigger = optc1_disable_reset_trigger, - .lock = optc3_lock, - .unlock = optc1_unlock, - .lock_doublebuffer_enable = optc3_lock_doublebuffer_enable, - .lock_doublebuffer_disable = optc3_lock_doublebuffer_disable, - .enable_optc_clock = optc1_enable_optc_clock, - .set_drr = optc1_set_drr, - .get_last_used_drr_vtotal = optc2_get_last_used_drr_vtotal, - .set_vtotal_min_max = optc3_set_vtotal_min_max, - .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, - .is_tg_enabled = optc1_is_tg_enabled, - .is_optc_underflow_occurred = optc1_is_optc_underflow_occurred, - .clear_optc_underflow = optc1_clear_optc_underflow, - .setup_global_swap_lock = NULL, - .get_crc = optc1_get_crc, - .configure_crc = optc2_configure_crc, - .set_dsc_config = optc3_set_dsc_config, - .get_dsc_status = optc2_get_dsc_status, - .set_dwb_source = NULL, - .set_odm_bypass = optc3_set_odm_bypass, - .set_odm_combine = optc3_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, - .set_vtotal_change_limit = optc3_set_vtotal_change_limit, - .set_gsl = optc2_set_gsl, - .set_gsl_source_select = optc2_set_gsl_source_select, - .set_vtg_params = optc1_set_vtg_params, - .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) -{ - optc1->base.funcs = &dcn30_tg_funcs; - - optc1->max_h_total = optc1->tg_mask->OTG_H_TOTAL + 1; - optc1->max_v_total = optc1->tg_mask->OTG_V_TOTAL + 1; - - optc1->min_h_blank = 32; - optc1->min_v_blank = 3; - optc1->min_v_blank_interlace = 5; - optc1->min_h_sync_width = 4; - optc1->min_v_sync_width = 1; -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.h b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.h deleted file mode 100644 index d3a056c12b0dc7..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.h +++ /dev/null @@ -1,359 +0,0 @@ -/* - * Copyright 2020 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_OPTC_DCN30_H__ -#define __DC_OPTC_DCN30_H__ - -#include "dcn20/dcn20_optc.h" - -#define V_TOTAL_REGS_DCN30_SRI(inst) - -#define OPTC_COMMON_REG_LIST_DCN3_BASE(inst) \ - SRI(OTG_VSTARTUP_PARAM, OTG, inst),\ - SRI(OTG_VUPDATE_PARAM, OTG, inst),\ - SRI(OTG_VREADY_PARAM, OTG, inst),\ - SRI(OTG_MASTER_UPDATE_LOCK, OTG, inst),\ - SRI(OTG_GLOBAL_CONTROL0, OTG, inst),\ - SRI(OTG_GLOBAL_CONTROL1, OTG, inst),\ - SRI(OTG_GLOBAL_CONTROL2, OTG, inst),\ - SRI(OTG_GLOBAL_CONTROL4, OTG, inst),\ - SRI(OTG_DOUBLE_BUFFER_CONTROL, OTG, inst),\ - SRI(OTG_H_TOTAL, OTG, inst),\ - SRI(OTG_H_BLANK_START_END, OTG, inst),\ - SRI(OTG_H_SYNC_A, OTG, inst),\ - SRI(OTG_H_SYNC_A_CNTL, OTG, inst),\ - SRI(OTG_H_TIMING_CNTL, OTG, inst),\ - SRI(OTG_V_TOTAL, OTG, inst),\ - SRI(OTG_V_BLANK_START_END, OTG, inst),\ - SRI(OTG_V_SYNC_A, OTG, inst),\ - SRI(OTG_V_SYNC_A_CNTL, OTG, inst),\ - SRI(OTG_CONTROL, OTG, inst),\ - SRI(OTG_STEREO_CONTROL, OTG, inst),\ - SRI(OTG_3D_STRUCTURE_CONTROL, OTG, inst),\ - SRI(OTG_STEREO_STATUS, OTG, inst),\ - SRI(OTG_V_TOTAL_MAX, OTG, inst),\ - SRI(OTG_V_TOTAL_MIN, OTG, inst),\ - SRI(OTG_V_TOTAL_CONTROL, OTG, inst),\ - V_TOTAL_REGS_DCN30_SRI(inst)\ - SRI(OTG_TRIGA_CNTL, OTG, inst),\ - SRI(OTG_FORCE_COUNT_NOW_CNTL, OTG, inst),\ - SRI(OTG_STATIC_SCREEN_CONTROL, OTG, inst),\ - SRI(OTG_STATUS_FRAME_COUNT, OTG, inst),\ - SRI(OTG_STATUS, OTG, inst),\ - SRI(OTG_STATUS_POSITION, OTG, inst),\ - SRI(OTG_NOM_VERT_POSITION, OTG, inst),\ - SRI(OTG_BLANK_DATA_COLOR, OTG, inst),\ - SRI(OTG_BLANK_DATA_COLOR_EXT, OTG, inst),\ - SRI(OTG_M_CONST_DTO0, OTG, inst),\ - SRI(OTG_M_CONST_DTO1, OTG, inst),\ - SRI(OTG_CLOCK_CONTROL, OTG, inst),\ - SRI(OTG_VERTICAL_INTERRUPT0_CONTROL, OTG, inst),\ - SRI(OTG_VERTICAL_INTERRUPT0_POSITION, OTG, inst),\ - SRI(OTG_VERTICAL_INTERRUPT1_CONTROL, OTG, inst),\ - SRI(OTG_VERTICAL_INTERRUPT1_POSITION, OTG, inst),\ - SRI(OTG_VERTICAL_INTERRUPT2_CONTROL, OTG, inst),\ - SRI(OTG_VERTICAL_INTERRUPT2_POSITION, OTG, inst),\ - SRI(OPTC_INPUT_CLOCK_CONTROL, ODM, inst),\ - SRI(OPTC_DATA_SOURCE_SELECT, ODM, inst),\ - SRI(OPTC_INPUT_GLOBAL_CONTROL, ODM, inst),\ - SRI(CONTROL, VTG, inst),\ - SRI(OTG_VERT_SYNC_CONTROL, OTG, inst),\ - SRI(OTG_GSL_CONTROL, OTG, inst),\ - SRI(OTG_CRC_CNTL, OTG, inst),\ - SRI(OTG_CRC_CNTL2, OTG, inst),\ - SRI(OTG_CRC0_DATA_RG, OTG, inst),\ - SRI(OTG_CRC0_DATA_B, OTG, inst),\ - SRI(OTG_CRC0_WINDOWA_X_CONTROL, OTG, inst),\ - SRI(OTG_CRC0_WINDOWA_Y_CONTROL, OTG, inst),\ - SRI(OTG_CRC0_WINDOWB_X_CONTROL, OTG, inst),\ - SRI(OTG_CRC0_WINDOWB_Y_CONTROL, OTG, inst),\ - SR(GSL_SOURCE_SELECT),\ - SRI(OTG_TRIGA_MANUAL_TRIG, OTG, inst),\ - SRI(OTG_DRR_CONTROL, OTG, inst) - - -#define OPTC_COMMON_REG_LIST_DCN3_0(inst) \ - OPTC_COMMON_REG_LIST_DCN3_BASE(inst),\ - SRI(OTG_GLOBAL_CONTROL1, OTG, inst),\ - SRI(OTG_GLOBAL_CONTROL2, OTG, inst),\ - SRI(OTG_GSL_WINDOW_X, OTG, inst),\ - SRI(OTG_GSL_WINDOW_Y, OTG, inst),\ - SRI(OTG_VUPDATE_KEEPOUT, OTG, inst),\ - SRI(OTG_DSC_START_POSITION, OTG, inst),\ - SRI(OTG_CRC_CNTL2, OTG, inst),\ - SRI(OTG_DRR_TRIGGER_WINDOW, OTG, inst),\ - SRI(OTG_DRR_V_TOTAL_CHANGE, OTG, inst),\ - SRI(OPTC_DATA_FORMAT_CONTROL, ODM, inst),\ - SRI(OPTC_BYTES_PER_PIXEL, ODM, inst),\ - SRI(OPTC_WIDTH_CONTROL, ODM, inst),\ - SRI(OPTC_MEMORY_CONFIG, ODM, inst),\ - SR(DWB_SOURCE_SELECT) - -#define DCN30_VTOTAL_REGS_SF(mask_sh) - -#define OPTC_COMMON_MASK_SH_LIST_DCN3_BASE(mask_sh)\ - SF(OTG0_OTG_VSTARTUP_PARAM, VSTARTUP_START, mask_sh),\ - SF(OTG0_OTG_VUPDATE_PARAM, VUPDATE_OFFSET, mask_sh),\ - SF(OTG0_OTG_VUPDATE_PARAM, VUPDATE_WIDTH, mask_sh),\ - SF(OTG0_OTG_VREADY_PARAM, VREADY_OFFSET, mask_sh),\ - SF(OTG0_OTG_MASTER_UPDATE_LOCK, OTG_MASTER_UPDATE_LOCK, mask_sh),\ - SF(OTG0_OTG_MASTER_UPDATE_LOCK, UPDATE_LOCK_STATUS, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL0, MASTER_UPDATE_LOCK_DB_START_X, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL0, MASTER_UPDATE_LOCK_DB_END_X, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL0, MASTER_UPDATE_LOCK_DB_EN, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_START_Y, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_END_Y, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL2, OTG_MASTER_UPDATE_LOCK_SEL, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL4, DIG_UPDATE_POSITION_X, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL4, DIG_UPDATE_POSITION_Y, mask_sh),\ - SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_UPDATE_PENDING, mask_sh),\ - SF(OTG0_OTG_H_TOTAL, OTG_H_TOTAL, mask_sh),\ - SF(OTG0_OTG_H_BLANK_START_END, OTG_H_BLANK_START, mask_sh),\ - SF(OTG0_OTG_H_BLANK_START_END, OTG_H_BLANK_END, mask_sh),\ - SF(OTG0_OTG_H_SYNC_A, OTG_H_SYNC_A_START, mask_sh),\ - SF(OTG0_OTG_H_SYNC_A, OTG_H_SYNC_A_END, mask_sh),\ - SF(OTG0_OTG_H_SYNC_A_CNTL, OTG_H_SYNC_A_POL, mask_sh),\ - SF(OTG0_OTG_V_TOTAL, OTG_V_TOTAL, mask_sh),\ - SF(OTG0_OTG_V_BLANK_START_END, OTG_V_BLANK_START, mask_sh),\ - SF(OTG0_OTG_V_BLANK_START_END, OTG_V_BLANK_END, mask_sh),\ - SF(OTG0_OTG_V_SYNC_A, OTG_V_SYNC_A_START, mask_sh),\ - SF(OTG0_OTG_V_SYNC_A, OTG_V_SYNC_A_END, mask_sh),\ - SF(OTG0_OTG_V_SYNC_A_CNTL, OTG_V_SYNC_A_POL, mask_sh),\ - SF(OTG0_OTG_V_SYNC_A_CNTL, OTG_V_SYNC_MODE, mask_sh),\ - SF(OTG0_OTG_CONTROL, OTG_MASTER_EN, mask_sh),\ - SF(OTG0_OTG_CONTROL, OTG_START_POINT_CNTL, mask_sh),\ - SF(OTG0_OTG_CONTROL, OTG_DISABLE_POINT_CNTL, mask_sh),\ - SF(OTG0_OTG_CONTROL, OTG_FIELD_NUMBER_CNTL, mask_sh),\ - SF(OTG0_OTG_CONTROL, OTG_OUT_MUX, mask_sh),\ - SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_EN, mask_sh),\ - SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_SYNC_OUTPUT_LINE_NUM, mask_sh),\ - SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_SYNC_OUTPUT_POLARITY, mask_sh),\ - SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_EYE_FLAG_POLARITY, mask_sh),\ - SF(OTG0_OTG_STEREO_CONTROL, OTG_DISABLE_STEREOSYNC_OUTPUT_FOR_DP, mask_sh),\ - SF(OTG0_OTG_STEREO_STATUS, OTG_STEREO_CURRENT_EYE, mask_sh),\ - SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_EN, mask_sh),\ - SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_V_UPDATE_MODE, mask_sh),\ - SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_STEREO_SEL_OVR, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_MAX, OTG_V_TOTAL_MAX, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_MIN, OTG_V_TOTAL_MIN, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_V_TOTAL_MIN_SEL, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_V_TOTAL_MAX_SEL, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_FORCE_LOCK_ON_EVENT, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_SET_V_TOTAL_MIN_MASK_EN, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_SET_V_TOTAL_MIN_MASK, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_VTOTAL_MID_REPLACING_MIN_EN, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_VTOTAL_MID_REPLACING_MAX_EN, mask_sh),\ - DCN30_VTOTAL_REGS_SF(mask_sh)\ - SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_CLEAR, mask_sh),\ - SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_MODE, mask_sh),\ - SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_OCCURRED, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_SOURCE_SELECT, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_SOURCE_PIPE_SELECT, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_RISING_EDGE_DETECT_CNTL, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_POLARITY_SELECT, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_FREQUENCY_SELECT, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_DELAY, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_CLEAR, mask_sh),\ - SF(OTG0_OTG_STATIC_SCREEN_CONTROL, OTG_STATIC_SCREEN_EVENT_MASK, mask_sh),\ - SF(OTG0_OTG_STATIC_SCREEN_CONTROL, OTG_STATIC_SCREEN_FRAME_COUNT, mask_sh),\ - SF(OTG0_OTG_STATUS_FRAME_COUNT, OTG_FRAME_COUNT, mask_sh),\ - SF(OTG0_OTG_STATUS, OTG_V_BLANK, mask_sh),\ - SF(OTG0_OTG_STATUS, OTG_V_ACTIVE_DISP, mask_sh),\ - SF(OTG0_OTG_STATUS_POSITION, OTG_HORZ_COUNT, mask_sh),\ - SF(OTG0_OTG_STATUS_POSITION, OTG_VERT_COUNT, mask_sh),\ - SF(OTG0_OTG_NOM_VERT_POSITION, OTG_VERT_COUNT_NOM, mask_sh),\ - SF(OTG0_OTG_BLANK_DATA_COLOR, OTG_BLANK_DATA_COLOR_BLUE_CB, mask_sh),\ - SF(OTG0_OTG_BLANK_DATA_COLOR, OTG_BLANK_DATA_COLOR_GREEN_Y, mask_sh),\ - SF(OTG0_OTG_BLANK_DATA_COLOR, OTG_BLANK_DATA_COLOR_RED_CR, mask_sh),\ - SF(OTG0_OTG_BLANK_DATA_COLOR_EXT, OTG_BLANK_DATA_COLOR_BLUE_CB_EXT, mask_sh),\ - SF(OTG0_OTG_BLANK_DATA_COLOR_EXT, OTG_BLANK_DATA_COLOR_GREEN_Y_EXT, mask_sh),\ - SF(OTG0_OTG_BLANK_DATA_COLOR_EXT, OTG_BLANK_DATA_COLOR_RED_CR_EXT, mask_sh),\ - SF(OTG0_OTG_M_CONST_DTO0, OTG_M_CONST_DTO_PHASE, mask_sh),\ - SF(OTG0_OTG_M_CONST_DTO1, OTG_M_CONST_DTO_MODULO, mask_sh),\ - SF(OTG0_OTG_CLOCK_CONTROL, OTG_BUSY, mask_sh),\ - SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_EN, mask_sh),\ - SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_ON, mask_sh),\ - SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_GATE_DIS, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_INT_ENABLE, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT0_POSITION, OTG_VERTICAL_INTERRUPT0_LINE_START, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT0_POSITION, OTG_VERTICAL_INTERRUPT0_LINE_END, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT1_CONTROL, OTG_VERTICAL_INTERRUPT1_INT_ENABLE, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT1_POSITION, OTG_VERTICAL_INTERRUPT1_LINE_START, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT2_POSITION, OTG_VERTICAL_INTERRUPT2_LINE_START, mask_sh),\ - SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_EN, mask_sh),\ - SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_ON, mask_sh),\ - SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_GATE_DIS, mask_sh),\ - SF(ODM0_OPTC_INPUT_GLOBAL_CONTROL, OPTC_UNDERFLOW_OCCURRED_STATUS, mask_sh),\ - SF(ODM0_OPTC_INPUT_GLOBAL_CONTROL, OPTC_UNDERFLOW_CLEAR, mask_sh),\ - SF(VTG0_CONTROL, VTG0_ENABLE, mask_sh),\ - SF(VTG0_CONTROL, VTG0_FP2, mask_sh),\ - SF(VTG0_CONTROL, VTG0_VCOUNT_INIT, mask_sh),\ - SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_FORCE_VSYNC_NEXT_LINE_OCCURRED, mask_sh),\ - SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_FORCE_VSYNC_NEXT_LINE_CLEAR, mask_sh),\ - SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_AUTO_FORCE_VSYNC_MODE, mask_sh),\ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL0_EN, mask_sh),\ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL1_EN, mask_sh),\ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL2_EN, mask_sh),\ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_MASTER_EN, mask_sh),\ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_FORCE_DELAY, mask_sh),\ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_CHECK_ALL_FIELDS, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL, OTG_CRC_CONT_EN, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL, OTG_CRC0_SELECT, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL, OTG_CRC_EN, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DSC_MODE, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_STREAM_COMBINE_MODE, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_STREAM_SPLIT_MODE, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_FORMAT, mask_sh),\ - SF(OTG0_OTG_CRC0_DATA_RG, CRC0_R_CR, mask_sh),\ - SF(OTG0_OTG_CRC0_DATA_RG, CRC0_G_Y, mask_sh),\ - SF(OTG0_OTG_CRC0_DATA_B, CRC0_B_CB, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWA_X_CONTROL, OTG_CRC0_WINDOWA_X_START, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWA_X_CONTROL, OTG_CRC0_WINDOWA_X_END, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWA_Y_CONTROL, OTG_CRC0_WINDOWA_Y_START, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWA_Y_CONTROL, OTG_CRC0_WINDOWA_Y_END, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWB_X_CONTROL, OTG_CRC0_WINDOWB_X_START, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWB_X_CONTROL, OTG_CRC0_WINDOWB_X_END, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL, OTG_CRC0_WINDOWB_Y_START, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL, OTG_CRC0_WINDOWB_Y_END, mask_sh),\ - SF(OTG0_OTG_TRIGA_MANUAL_TRIG, OTG_TRIGA_MANUAL_TRIG, mask_sh),\ - SF(GSL_SOURCE_SELECT, GSL0_READY_SOURCE_SEL, mask_sh),\ - SF(GSL_SOURCE_SELECT, GSL1_READY_SOURCE_SEL, mask_sh),\ - SF(GSL_SOURCE_SELECT, GSL2_READY_SOURCE_SEL, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL2, MANUAL_FLOW_CONTROL_SEL, mask_sh),\ - SF(OTG0_OTG_DRR_CONTROL, OTG_V_TOTAL_LAST_USED_BY_DRR, mask_sh) - -#define OPTC_COMMON_MASK_SH_LIST_DCN3_0(mask_sh)\ - OPTC_COMMON_MASK_SH_LIST_DCN3_BASE(mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, mask_sh),\ - SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_START_X, mask_sh),\ - SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_END_X, mask_sh), \ - SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_START_Y, mask_sh),\ - SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_END_Y, mask_sh),\ - SF(OTG0_OTG_VUPDATE_KEEPOUT, OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, mask_sh), \ - SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET, mask_sh), \ - SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET, mask_sh), \ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_MASTER_MODE, mask_sh), \ - SF(OTG0_OTG_GSL_CONTROL, OTG_MASTER_UPDATE_LOCK_GSL_EN, mask_sh), \ - SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_X, mask_sh), \ - SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_LINE_NUM, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DSC_MODE, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_STREAM_COMBINE_MODE, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_STREAM_SPLIT_MODE, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_FORMAT, mask_sh),\ - SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG0_SRC_SEL, mask_sh),\ - SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG1_SRC_SEL, mask_sh),\ - SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_NUM_OF_INPUT_SEGMENT, mask_sh),\ - SF(ODM0_OPTC_MEMORY_CONFIG, OPTC_MEM_SEL, mask_sh),\ - SF(ODM0_OPTC_DATA_FORMAT_CONTROL, OPTC_DATA_FORMAT, mask_sh),\ - SF(ODM0_OPTC_DATA_FORMAT_CONTROL, OPTC_DSC_MODE, mask_sh),\ - SF(ODM0_OPTC_BYTES_PER_PIXEL, OPTC_DSC_BYTES_PER_PIXEL, mask_sh),\ - SF(ODM0_OPTC_WIDTH_CONTROL, OPTC_DSC_SLICE_WIDTH, mask_sh),\ - SF(ODM0_OPTC_WIDTH_CONTROL, OPTC_SEGMENT_WIDTH, mask_sh),\ - SF(DWB_SOURCE_SELECT, OPTC_DWB0_SOURCE_SELECT, mask_sh),\ - SF(DWB_SOURCE_SELECT, OPTC_DWB1_SOURCE_SELECT, mask_sh),\ - SF(OTG0_OTG_DRR_TRIGGER_WINDOW, OTG_DRR_TRIGGER_WINDOW_START_X, mask_sh),\ - 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) - -#define OPTC_COMMON_MASK_SH_LIST_DCN30(mask_sh)\ - OPTC_COMMON_MASK_SH_LIST_DCN3_BASE(mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, mask_sh),\ - SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_START_X, mask_sh),\ - SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_END_X, mask_sh), \ - SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_START_Y, mask_sh),\ - SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_END_Y, mask_sh),\ - SF(OTG0_OTG_VUPDATE_KEEPOUT, OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, mask_sh), \ - SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET, mask_sh), \ - SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET, mask_sh), \ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_MASTER_MODE, mask_sh), \ - SF(OTG0_OTG_GSL_CONTROL, OTG_MASTER_UPDATE_LOCK_GSL_EN, mask_sh), \ - SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_X, mask_sh), \ - SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_LINE_NUM, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DSC_MODE, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_STREAM_COMBINE_MODE, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_STREAM_SPLIT_MODE, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_FORMAT, mask_sh),\ - SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG0_SRC_SEL, mask_sh),\ - SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG1_SRC_SEL, mask_sh),\ - SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG2_SRC_SEL, mask_sh),\ - SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG3_SRC_SEL, mask_sh),\ - SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_NUM_OF_INPUT_SEGMENT, mask_sh),\ - SF(ODM0_OPTC_MEMORY_CONFIG, OPTC_MEM_SEL, mask_sh),\ - SF(ODM0_OPTC_DATA_FORMAT_CONTROL, OPTC_DATA_FORMAT, mask_sh),\ - SF(ODM0_OPTC_DATA_FORMAT_CONTROL, OPTC_DSC_MODE, mask_sh),\ - SF(ODM0_OPTC_BYTES_PER_PIXEL, OPTC_DSC_BYTES_PER_PIXEL, mask_sh),\ - SF(ODM0_OPTC_WIDTH_CONTROL, OPTC_DSC_SLICE_WIDTH, mask_sh),\ - SF(ODM0_OPTC_WIDTH_CONTROL, OPTC_SEGMENT_WIDTH, mask_sh),\ - SF(DWB_SOURCE_SELECT, OPTC_DWB0_SOURCE_SELECT, mask_sh),\ - SF(DWB_SOURCE_SELECT, OPTC_DWB1_SOURCE_SELECT, mask_sh),\ - SF(OTG0_OTG_DRR_TRIGGER_WINDOW, OTG_DRR_TRIGGER_WINDOW_START_X, mask_sh),\ - 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); - -void optc3_set_out_mux(struct timing_generator *optc, enum otg_out_mux_dest dest); - -void optc3_lock(struct timing_generator *optc); - -void optc3_lock_doublebuffer_enable(struct timing_generator *optc); - -void optc3_lock_doublebuffer_disable(struct timing_generator *optc); - -void optc3_set_drr_trigger_window(struct timing_generator *optc, - uint32_t window_start, uint32_t window_end); - -void optc3_triplebuffer_lock(struct timing_generator *optc); - -void optc3_program_blank_color(struct timing_generator *optc, - const struct tg_color *blank_color); - -void optc3_set_vtotal_change_limit(struct timing_generator *optc, - uint32_t limit); - -void optc3_set_dsc_config(struct timing_generator *optc, - enum optc_dsc_mode dsc_mode, - uint32_t dsc_bytes_per_pixel, - uint32_t dsc_slice_width); - -void optc3_set_timing_db_mode(struct timing_generator *optc, bool enable); - -void optc3_set_odm_bypass(struct timing_generator *optc, - const struct dc_crtc_timing *dc_crtc_timing); -void optc3_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, - struct dc_crtc_timing *timing); -void optc3_wait_drr_doublebuffer_pending_clear(struct timing_generator *optc); -void optc3_tg_init(struct timing_generator *optc); -void optc3_set_vtotal_min_max(struct timing_generator *optc, int vtotal_min, int vtotal_max); -#endif /* __DC_OPTC_DCN30_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c deleted file mode 100644 index 7b259cb5f41878..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c +++ /dev/null @@ -1,2611 +0,0 @@ -/* - * Copyright 2020 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 "dcn30_init.h" - -#include "resource.h" -#include "include/irq_service_interface.h" -#include "dcn20/dcn20_resource.h" - -#include "dcn30_resource.h" - -#include "dcn10/dcn10_ipp.h" -#include "dcn30/dcn30_hubbub.h" -#include "dcn30/dcn30_mpc.h" -#include "dcn30/dcn30_hubp.h" -#include "irq/dcn30/irq_service_dcn30.h" -#include "dcn30/dcn30_dpp.h" -#include "dcn30/dcn30_optc.h" -#include "dcn20/dcn20_hwseq.h" -#include "dcn30/dcn30_hwseq.h" -#include "dce110/dce110_hwseq.h" -#include "dcn30/dcn30_opp.h" -#include "dcn20/dcn20_dsc.h" -#include "dcn30/dcn30_vpg.h" -#include "dcn30/dcn30_afmt.h" -#include "dcn30/dcn30_dio_stream_encoder.h" -#include "dcn30/dcn30_dio_link_encoder.h" -#include "dce/dce_clock_source.h" -#include "dce/dce_audio.h" -#include "dce/dce_hwseq.h" -#include "clk_mgr.h" -#include "virtual/virtual_stream_encoder.h" -#include "dce110/dce110_resource.h" -#include "dml/display_mode_vba.h" -#include "dcn30/dcn30_dccg.h" -#include "dcn10/dcn10_resource.h" -#include "link.h" -#include "dce/dce_panel_cntl.h" - -#include "dcn30/dcn30_dwb.h" -#include "dcn30/dcn30_mmhubbub.h" - -#include "sienna_cichlid_ip_offset.h" -#include "dcn/dcn_3_0_0_offset.h" -#include "dcn/dcn_3_0_0_sh_mask.h" - -#include "nbio/nbio_7_4_offset.h" - -#include "dpcs/dpcs_3_0_0_offset.h" -#include "dpcs/dpcs_3_0_0_sh_mask.h" - -#include "mmhub/mmhub_2_0_0_offset.h" -#include "mmhub/mmhub_2_0_0_sh_mask.h" - -#include "reg_helper.h" -#include "dce/dmub_abm.h" -#include "dce/dmub_psr.h" -#include "dce/dce_aux.h" -#include "dce/dce_i2c.h" - -#include "dml/dcn30/dcn30_fpu.h" -#include "dml/dcn30/display_mode_vba_30.h" -#include "vm_helper.h" -#include "dcn20/dcn20_vmid.h" -#include "amdgpu_socbb.h" -#include "dc_dmub_srv.h" - -#define DC_LOGGER \ - dc->ctx->logger -#define DC_LOGGER_INIT(logger) - -enum dcn30_clk_src_array_id { - DCN30_CLK_SRC_PLL0, - DCN30_CLK_SRC_PLL1, - DCN30_CLK_SRC_PLL2, - DCN30_CLK_SRC_PLL3, - DCN30_CLK_SRC_PLL4, - DCN30_CLK_SRC_PLL5, - DCN30_CLK_SRC_TOTAL -}; - -/* begin ********************* - * macros to expend register list macro defined in HW object header file - */ - -/* DCN */ -#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg - -#define BASE(seg) BASE_INNER(seg) - -#define SR(reg_name)\ - .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + \ - mm ## reg_name - -#define SRI(reg_name, block, id)\ - .reg_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name - -#define SRI2(reg_name, block, id)\ - .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + \ - mm ## reg_name - -#define SRIR(var_name, reg_name, block, id)\ - .var_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name - -#define SRII(reg_name, block, id)\ - .reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name - -#define SRII_MPC_RMU(reg_name, block, id)\ - .RMU##_##reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name - -#define SRII_DWB(reg_name, temp_name, block, id)\ - .reg_name[id] = BASE(mm ## block ## id ## _ ## temp_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## temp_name - -#define SF_DWB2(reg_name, block, id, field_name, post_fix) \ - .field_name = reg_name ## __ ## field_name ## post_fix - -#define DCCG_SRII(reg_name, block, id)\ - .block ## _ ## reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name - -#define VUPDATE_SRII(reg_name, block, id)\ - .reg_name[id] = BASE(mm ## reg_name ## _ ## block ## id ## _BASE_IDX) + \ - mm ## reg_name ## _ ## block ## id - -/* NBIO */ -#define NBIO_BASE_INNER(seg) \ - NBIO_BASE__INST0_SEG ## seg - -#define NBIO_BASE(seg) \ - NBIO_BASE_INNER(seg) - -#define NBIO_SR(reg_name)\ - .reg_name = NBIO_BASE(mm ## reg_name ## _BASE_IDX) + \ - mm ## reg_name - -/* MMHUB */ -#define MMHUB_BASE_INNER(seg) \ - MMHUB_BASE__INST0_SEG ## seg - -#define MMHUB_BASE(seg) \ - MMHUB_BASE_INNER(seg) - -#define MMHUB_SR(reg_name)\ - .reg_name = MMHUB_BASE(mmMM ## reg_name ## _BASE_IDX) + \ - mmMM ## reg_name - -/* CLOCK */ -#define CLK_BASE_INNER(seg) \ - CLK_BASE__INST0_SEG ## seg - -#define CLK_BASE(seg) \ - CLK_BASE_INNER(seg) - -#define CLK_SRI(reg_name, block, inst)\ - .reg_name = CLK_BASE(mm ## block ## _ ## inst ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## _ ## inst ## _ ## reg_name - - -static const struct bios_registers bios_regs = { - NBIO_SR(BIOS_SCRATCH_3), - NBIO_SR(BIOS_SCRATCH_6) -}; - -#define clk_src_regs(index, pllid)\ -[index] = {\ - CS_COMMON_REG_LIST_DCN2_0(index, pllid),\ -} - -static const struct dce110_clk_src_regs clk_src_regs[] = { - clk_src_regs(0, A), - clk_src_regs(1, B), - clk_src_regs(2, C), - clk_src_regs(3, D), - clk_src_regs(4, E), - clk_src_regs(5, F) -}; - -static const struct dce110_clk_src_shift cs_shift = { - CS_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) -}; - -static const struct dce110_clk_src_mask cs_mask = { - CS_COMMON_MASK_SH_LIST_DCN2_0(_MASK) -}; - -#define abm_regs(id)\ -[id] = {\ - ABM_DCN30_REG_LIST(id)\ -} - -static const struct dce_abm_registers abm_regs[] = { - abm_regs(0), - abm_regs(1), - abm_regs(2), - abm_regs(3), - abm_regs(4), - abm_regs(5), -}; - -static const struct dce_abm_shift abm_shift = { - ABM_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dce_abm_mask abm_mask = { - ABM_MASK_SH_LIST_DCN30(_MASK) -}; - - - -#define audio_regs(id)\ -[id] = {\ - AUD_COMMON_REG_LIST(id)\ -} - -static const struct dce_audio_registers audio_regs[] = { - audio_regs(0), - audio_regs(1), - audio_regs(2), - audio_regs(3), - audio_regs(4), - audio_regs(5), - audio_regs(6) -}; - -#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ - SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ - SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ - AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) - -static const struct dce_audio_shift audio_shift = { - DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_audio_mask audio_mask = { - DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) -}; - -#define vpg_regs(id)\ -[id] = {\ - VPG_DCN3_REG_LIST(id)\ -} - -static const struct dcn30_vpg_registers vpg_regs[] = { - vpg_regs(0), - vpg_regs(1), - vpg_regs(2), - vpg_regs(3), - vpg_regs(4), - vpg_regs(5), - vpg_regs(6), -}; - -static const struct dcn30_vpg_shift vpg_shift = { - DCN3_VPG_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn30_vpg_mask vpg_mask = { - DCN3_VPG_MASK_SH_LIST(_MASK) -}; - -#define afmt_regs(id)\ -[id] = {\ - AFMT_DCN3_REG_LIST(id)\ -} - -static const struct dcn30_afmt_registers afmt_regs[] = { - afmt_regs(0), - afmt_regs(1), - afmt_regs(2), - afmt_regs(3), - afmt_regs(4), - afmt_regs(5), - afmt_regs(6), -}; - -static const struct dcn30_afmt_shift afmt_shift = { - DCN3_AFMT_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn30_afmt_mask afmt_mask = { - DCN3_AFMT_MASK_SH_LIST(_MASK) -}; - -#define stream_enc_regs(id)\ -[id] = {\ - SE_DCN3_REG_LIST(id)\ -} - -static const struct dcn10_stream_enc_registers stream_enc_regs[] = { - stream_enc_regs(0), - stream_enc_regs(1), - stream_enc_regs(2), - stream_enc_regs(3), - stream_enc_regs(4), - stream_enc_regs(5) -}; - -static const struct dcn10_stream_encoder_shift se_shift = { - SE_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn10_stream_encoder_mask se_mask = { - SE_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - - -#define aux_regs(id)\ -[id] = {\ - DCN2_AUX_REG_LIST(id)\ -} - -static const struct dcn10_link_enc_aux_registers link_enc_aux_regs[] = { - aux_regs(0), - aux_regs(1), - aux_regs(2), - aux_regs(3), - aux_regs(4), - aux_regs(5) -}; - -#define hpd_regs(id)\ -[id] = {\ - HPD_REG_LIST(id)\ -} - -static const struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[] = { - hpd_regs(0), - hpd_regs(1), - hpd_regs(2), - hpd_regs(3), - hpd_regs(4), - hpd_regs(5) -}; - -#define link_regs(id, phyid)\ -[id] = {\ - LE_DCN3_REG_LIST(id), \ - UNIPHY_DCN2_REG_LIST(phyid), \ - DPCS_DCN2_REG_LIST(id), \ - SRI(DP_DPHY_INTERNAL_CTRL, DP, id) \ -} - -static const struct dce110_aux_registers_shift aux_shift = { - DCN_AUX_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce110_aux_registers_mask aux_mask = { - DCN_AUX_MASK_SH_LIST(_MASK) -}; - -static const struct dcn10_link_enc_registers link_enc_regs[] = { - link_regs(0, A), - link_regs(1, B), - link_regs(2, C), - link_regs(3, D), - link_regs(4, E), - link_regs(5, F) -}; - -static const struct dcn10_link_enc_shift le_shift = { - LINK_ENCODER_MASK_SH_LIST_DCN30(__SHIFT),\ - DPCS_DCN2_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn10_link_enc_mask le_mask = { - LINK_ENCODER_MASK_SH_LIST_DCN30(_MASK),\ - DPCS_DCN2_MASK_SH_LIST(_MASK) -}; - - -static const struct dce_panel_cntl_registers panel_cntl_regs[] = { - { DCN_PANEL_CNTL_REG_LIST() } -}; - -static const struct dce_panel_cntl_shift panel_cntl_shift = { - DCE_PANEL_CNTL_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_panel_cntl_mask panel_cntl_mask = { - DCE_PANEL_CNTL_MASK_SH_LIST(_MASK) -}; - -#define dpp_regs(id)\ -[id] = {\ - DPP_REG_LIST_DCN30(id),\ -} - -static const struct dcn3_dpp_registers dpp_regs[] = { - dpp_regs(0), - dpp_regs(1), - dpp_regs(2), - dpp_regs(3), - dpp_regs(4), - dpp_regs(5), -}; - -static const struct dcn3_dpp_shift tf_shift = { - DPP_REG_LIST_SH_MASK_DCN30(__SHIFT) -}; - -static const struct dcn3_dpp_mask tf_mask = { - DPP_REG_LIST_SH_MASK_DCN30(_MASK) -}; - -#define opp_regs(id)\ -[id] = {\ - OPP_REG_LIST_DCN30(id),\ -} - -static const struct dcn20_opp_registers opp_regs[] = { - opp_regs(0), - opp_regs(1), - opp_regs(2), - opp_regs(3), - opp_regs(4), - opp_regs(5) -}; - -static const struct dcn20_opp_shift opp_shift = { - OPP_MASK_SH_LIST_DCN20(__SHIFT) -}; - -static const struct dcn20_opp_mask opp_mask = { - OPP_MASK_SH_LIST_DCN20(_MASK) -}; - -#define aux_engine_regs(id)\ -[id] = {\ - AUX_COMMON_REG_LIST0(id), \ - .AUXN_IMPCAL = 0, \ - .AUXP_IMPCAL = 0, \ - .AUX_RESET_MASK = DP_AUX0_AUX_CONTROL__AUX_RESET_MASK, \ -} - -static const struct dce110_aux_registers aux_engine_regs[] = { - aux_engine_regs(0), - aux_engine_regs(1), - aux_engine_regs(2), - aux_engine_regs(3), - aux_engine_regs(4), - aux_engine_regs(5) -}; - -#define dwbc_regs_dcn3(id)\ -[id] = {\ - DWBC_COMMON_REG_LIST_DCN30(id),\ -} - -static const struct dcn30_dwbc_registers dwbc30_regs[] = { - dwbc_regs_dcn3(0), -}; - -static const struct dcn30_dwbc_shift dwbc30_shift = { - DWBC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn30_dwbc_mask dwbc30_mask = { - DWBC_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -#define mcif_wb_regs_dcn3(id)\ -[id] = {\ - MCIF_WB_COMMON_REG_LIST_DCN30(id),\ -} - -static const struct dcn30_mmhubbub_registers mcif_wb30_regs[] = { - mcif_wb_regs_dcn3(0) -}; - -static const struct dcn30_mmhubbub_shift mcif_wb30_shift = { - MCIF_WB_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn30_mmhubbub_mask mcif_wb30_mask = { - MCIF_WB_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -#define dsc_regsDCN20(id)\ -[id] = {\ - DSC_REG_LIST_DCN20(id)\ -} - -static const struct dcn20_dsc_registers dsc_regs[] = { - dsc_regsDCN20(0), - dsc_regsDCN20(1), - dsc_regsDCN20(2), - dsc_regsDCN20(3), - dsc_regsDCN20(4), - dsc_regsDCN20(5) -}; - -static const struct dcn20_dsc_shift dsc_shift = { - DSC_REG_LIST_SH_MASK_DCN20(__SHIFT) -}; - -static const struct dcn20_dsc_mask dsc_mask = { - DSC_REG_LIST_SH_MASK_DCN20(_MASK) -}; - -static const struct dcn30_mpc_registers mpc_regs = { - MPC_REG_LIST_DCN3_0(0), - MPC_REG_LIST_DCN3_0(1), - MPC_REG_LIST_DCN3_0(2), - MPC_REG_LIST_DCN3_0(3), - MPC_REG_LIST_DCN3_0(4), - MPC_REG_LIST_DCN3_0(5), - MPC_OUT_MUX_REG_LIST_DCN3_0(0), - MPC_OUT_MUX_REG_LIST_DCN3_0(1), - MPC_OUT_MUX_REG_LIST_DCN3_0(2), - MPC_OUT_MUX_REG_LIST_DCN3_0(3), - MPC_OUT_MUX_REG_LIST_DCN3_0(4), - MPC_OUT_MUX_REG_LIST_DCN3_0(5), - MPC_RMU_GLOBAL_REG_LIST_DCN3AG, - MPC_RMU_REG_LIST_DCN3AG(0), - MPC_RMU_REG_LIST_DCN3AG(1), - MPC_RMU_REG_LIST_DCN3AG(2), - MPC_DWB_MUX_REG_LIST_DCN3_0(0), -}; - -static const struct dcn30_mpc_shift mpc_shift = { - MPC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn30_mpc_mask mpc_mask = { - MPC_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -#define optc_regs(id)\ -[id] = {OPTC_COMMON_REG_LIST_DCN3_0(id)} - - -static const struct dcn_optc_registers optc_regs[] = { - optc_regs(0), - optc_regs(1), - optc_regs(2), - optc_regs(3), - optc_regs(4), - optc_regs(5) -}; - -static const struct dcn_optc_shift optc_shift = { - OPTC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn_optc_mask optc_mask = { - OPTC_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -#define hubp_regs(id)\ -[id] = {\ - HUBP_REG_LIST_DCN30(id)\ -} - -static const struct dcn_hubp2_registers hubp_regs[] = { - hubp_regs(0), - hubp_regs(1), - hubp_regs(2), - hubp_regs(3), - hubp_regs(4), - hubp_regs(5) -}; - -static const struct dcn_hubp2_shift hubp_shift = { - HUBP_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn_hubp2_mask hubp_mask = { - HUBP_MASK_SH_LIST_DCN30(_MASK) -}; - -static const struct dcn_hubbub_registers hubbub_reg = { - HUBBUB_REG_LIST_DCN30(0) -}; - -static const struct dcn_hubbub_shift hubbub_shift = { - HUBBUB_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn_hubbub_mask hubbub_mask = { - HUBBUB_MASK_SH_LIST_DCN30(_MASK) -}; - -static const struct dccg_registers dccg_regs = { - DCCG_REG_LIST_DCN30() -}; - -static const struct dccg_shift dccg_shift = { - DCCG_MASK_SH_LIST_DCN3(__SHIFT) -}; - -static const struct dccg_mask dccg_mask = { - DCCG_MASK_SH_LIST_DCN3(_MASK) -}; - -static const struct dce_hwseq_registers hwseq_reg = { - HWSEQ_DCN30_REG_LIST() -}; - -static const struct dce_hwseq_shift hwseq_shift = { - HWSEQ_DCN30_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_hwseq_mask hwseq_mask = { - HWSEQ_DCN30_MASK_SH_LIST(_MASK) -}; -#define vmid_regs(id)\ -[id] = {\ - DCN20_VMID_REG_LIST(id)\ -} - -static const struct dcn_vmid_registers vmid_regs[] = { - vmid_regs(0), - vmid_regs(1), - vmid_regs(2), - vmid_regs(3), - vmid_regs(4), - vmid_regs(5), - vmid_regs(6), - vmid_regs(7), - vmid_regs(8), - vmid_regs(9), - vmid_regs(10), - vmid_regs(11), - vmid_regs(12), - vmid_regs(13), - vmid_regs(14), - vmid_regs(15) -}; - -static const struct dcn20_vmid_shift vmid_shifts = { - DCN20_VMID_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn20_vmid_mask vmid_masks = { - DCN20_VMID_MASK_SH_LIST(_MASK) -}; - -static const struct resource_caps res_cap_dcn3 = { - .num_timing_generator = 6, - .num_opp = 6, - .num_video_plane = 6, - .num_audio = 6, - .num_stream_encoder = 6, - .num_pll = 6, - .num_dwb = 1, - .num_ddc = 6, - .num_vmid = 16, - .num_mpc_3dlut = 3, - .num_dsc = 6, -}; - -static const struct dc_plane_cap plane_cap = { - .type = DC_PLANE_TYPE_DCN_UNIVERSAL, - .per_pixel_alpha = true, - - .pixel_format_support = { - .argb8888 = true, - .nv12 = true, - .fp16 = true, - .p010 = true, - .ayuv = false, - }, - - .max_upscale_factor = { - .argb8888 = 16000, - .nv12 = 16000, - .fp16 = 16000 - }, - - /* 6:1 downscaling ratio: 1000/6 = 166.666 */ - .max_downscale_factor = { - .argb8888 = 167, - .nv12 = 167, - .fp16 = 167 - }, - 16, - 16 -}; - -static const struct dc_debug_options debug_defaults_drv = { - .disable_dmcu = true, //No DMCU on DCN30 - .force_abm_enable = false, - .timing_trace = false, - .clock_trace = true, - .disable_pplib_clock_request = true, - .pipe_split_policy = MPC_SPLIT_DYNAMIC, - .force_single_disp_pipe_split = false, - .disable_dcc = DCC_ENABLE, - .vsr_support = true, - .performance_trace = false, - .max_downscale_src_width = 7680,/*upto 8K*/ - .disable_pplib_wm_range = false, - .scl_reset_length10 = true, - .sanity_checks = false, - .underflow_assert_delay_us = 0xFFFFFFFF, - .dwb_fi_phase = -1, // -1 = disable, - .dmub_command_table = true, - .use_max_lb = true, - .exit_idle_opt_for_cursor_updates = true, - .enable_legacy_fast_update = false, - .using_dml2 = false, -}; - -static const struct dc_panel_config panel_config_defaults = { - .psr = { - .disable_psr = false, - .disallow_psrsu = false, - .disallow_replay = false, - }, -}; - -static void dcn30_dpp_destroy(struct dpp **dpp) -{ - kfree(TO_DCN20_DPP(*dpp)); - *dpp = NULL; -} - -static struct dpp *dcn30_dpp_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn3_dpp *dpp = - kzalloc(sizeof(struct dcn3_dpp), GFP_KERNEL); - - if (!dpp) - return NULL; - - if (dpp3_construct(dpp, ctx, inst, - &dpp_regs[inst], &tf_shift, &tf_mask)) - return &dpp->base; - - BREAK_TO_DEBUGGER(); - kfree(dpp); - return NULL; -} - -static struct output_pixel_processor *dcn30_opp_create( - struct dc_context *ctx, uint32_t inst) -{ - struct dcn20_opp *opp = - kzalloc(sizeof(struct dcn20_opp), GFP_KERNEL); - - if (!opp) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dcn20_opp_construct(opp, ctx, inst, - &opp_regs[inst], &opp_shift, &opp_mask); - return &opp->base; -} - -static struct dce_aux *dcn30_aux_engine_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct aux_engine_dce110 *aux_engine = - kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); - - if (!aux_engine) - return NULL; - - dce110_aux_engine_construct(aux_engine, ctx, inst, - SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, - &aux_engine_regs[inst], - &aux_mask, - &aux_shift, - ctx->dc->caps.extended_aux_timeout_support); - - return &aux_engine->base; -} - -#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST_DCN30(id) } - -static const struct dce_i2c_registers i2c_hw_regs[] = { - i2c_inst_regs(1), - i2c_inst_regs(2), - i2c_inst_regs(3), - i2c_inst_regs(4), - i2c_inst_regs(5), - i2c_inst_regs(6), -}; - -static const struct dce_i2c_shift i2c_shifts = { - I2C_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dce_i2c_mask i2c_masks = { - I2C_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -static struct dce_i2c_hw *dcn30_i2c_hw_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dce_i2c_hw *dce_i2c_hw = - kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); - - if (!dce_i2c_hw) - return NULL; - - dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst, - &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); - - return dce_i2c_hw; -} - -static struct mpc *dcn30_mpc_create( - struct dc_context *ctx, - int num_mpcc, - int num_rmu) -{ - struct dcn30_mpc *mpc30 = kzalloc(sizeof(struct dcn30_mpc), - GFP_KERNEL); - - if (!mpc30) - return NULL; - - dcn30_mpc_construct(mpc30, ctx, - &mpc_regs, - &mpc_shift, - &mpc_mask, - num_mpcc, - num_rmu); - - return &mpc30->base; -} - -static struct hubbub *dcn30_hubbub_create(struct dc_context *ctx) -{ - int i; - - struct dcn20_hubbub *hubbub3 = kzalloc(sizeof(struct dcn20_hubbub), - GFP_KERNEL); - - if (!hubbub3) - return NULL; - - hubbub3_construct(hubbub3, ctx, - &hubbub_reg, - &hubbub_shift, - &hubbub_mask); - - - for (i = 0; i < res_cap_dcn3.num_vmid; i++) { - struct dcn20_vmid *vmid = &hubbub3->vmid[i]; - - vmid->ctx = ctx; - - vmid->regs = &vmid_regs[i]; - vmid->shifts = &vmid_shifts; - vmid->masks = &vmid_masks; - } - - return &hubbub3->base; -} - -static struct timing_generator *dcn30_timing_generator_create( - struct dc_context *ctx, - uint32_t instance) -{ - struct optc *tgn10 = - kzalloc(sizeof(struct optc), GFP_KERNEL); - - if (!tgn10) - return NULL; - - tgn10->base.inst = instance; - tgn10->base.ctx = ctx; - - tgn10->tg_regs = &optc_regs[instance]; - tgn10->tg_shift = &optc_shift; - tgn10->tg_mask = &optc_mask; - - dcn30_timing_generator_init(tgn10); - - return &tgn10->base; -} - -static const struct encoder_feature_support link_enc_feature = { - .max_hdmi_deep_color = COLOR_DEPTH_121212, - .max_hdmi_pixel_clock = 600000, - .hdmi_ycbcr420_supported = true, - .dp_ycbcr420_supported = true, - .fec_supported = true, - .flags.bits.IS_HBR2_CAPABLE = true, - .flags.bits.IS_HBR3_CAPABLE = true, - .flags.bits.IS_TPS3_CAPABLE = true, - .flags.bits.IS_TPS4_CAPABLE = true -}; - -static struct link_encoder *dcn30_link_encoder_create( - struct dc_context *ctx, - const struct encoder_init_data *enc_init_data) -{ - struct dcn20_link_encoder *enc20 = - kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); - - if (!enc20) - return NULL; - - dcn30_link_encoder_construct(enc20, - enc_init_data, - &link_enc_feature, - &link_enc_regs[enc_init_data->transmitter], - &link_enc_aux_regs[enc_init_data->channel - 1], - &link_enc_hpd_regs[enc_init_data->hpd_source], - &le_shift, - &le_mask); - - return &enc20->enc10.base; -} - -static struct panel_cntl *dcn30_panel_cntl_create(const struct panel_cntl_init_data *init_data) -{ - struct dce_panel_cntl *panel_cntl = - kzalloc(sizeof(struct dce_panel_cntl), GFP_KERNEL); - - if (!panel_cntl) - return NULL; - - dce_panel_cntl_construct(panel_cntl, - init_data, - &panel_cntl_regs[init_data->inst], - &panel_cntl_shift, - &panel_cntl_mask); - - return &panel_cntl->base; -} - -static void read_dce_straps( - struct dc_context *ctx, - struct resource_straps *straps) -{ - generic_reg_get(ctx, mmDC_PINSTRAPS + BASE(mmDC_PINSTRAPS_BASE_IDX), - FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio); - -} - -static struct audio *dcn30_create_audio( - struct dc_context *ctx, unsigned int inst) -{ - return dce_audio_create(ctx, inst, - &audio_regs[inst], &audio_shift, &audio_mask); -} - -static struct vpg *dcn30_vpg_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn30_vpg *vpg3 = kzalloc(sizeof(struct dcn30_vpg), GFP_KERNEL); - - if (!vpg3) - return NULL; - - vpg3_construct(vpg3, ctx, inst, - &vpg_regs[inst], - &vpg_shift, - &vpg_mask); - - return &vpg3->base; -} - -static struct afmt *dcn30_afmt_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn30_afmt *afmt3 = kzalloc(sizeof(struct dcn30_afmt), GFP_KERNEL); - - if (!afmt3) - return NULL; - - afmt3_construct(afmt3, ctx, inst, - &afmt_regs[inst], - &afmt_shift, - &afmt_mask); - - return &afmt3->base; -} - -static struct stream_encoder *dcn30_stream_encoder_create(enum engine_id eng_id, - struct dc_context *ctx) -{ - struct dcn10_stream_encoder *enc1; - struct vpg *vpg; - struct afmt *afmt; - int vpg_inst; - int afmt_inst; - - /* Mapping of VPG, AFMT, DME register blocks to DIO block instance */ - if (eng_id <= ENGINE_ID_DIGF) { - vpg_inst = eng_id; - afmt_inst = eng_id; - } else - return NULL; - - enc1 = kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL); - vpg = dcn30_vpg_create(ctx, vpg_inst); - afmt = dcn30_afmt_create(ctx, afmt_inst); - - if (!enc1 || !vpg || !afmt) { - kfree(enc1); - kfree(vpg); - kfree(afmt); - return NULL; - } - - dcn30_dio_stream_encoder_construct(enc1, ctx, ctx->dc_bios, - eng_id, vpg, afmt, - &stream_enc_regs[eng_id], - &se_shift, &se_mask); - - return &enc1->base; -} - -static struct dce_hwseq *dcn30_hwseq_create(struct dc_context *ctx) -{ - struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); - - if (hws) { - hws->ctx = ctx; - hws->regs = &hwseq_reg; - hws->shifts = &hwseq_shift; - hws->masks = &hwseq_mask; - } - return hws; -} -static const struct resource_create_funcs res_create_funcs = { - .read_dce_straps = read_dce_straps, - .create_audio = dcn30_create_audio, - .create_stream_encoder = dcn30_stream_encoder_create, - .create_hwseq = dcn30_hwseq_create, -}; - -static void dcn30_resource_destruct(struct dcn30_resource_pool *pool) -{ - unsigned int i; - - for (i = 0; i < pool->base.stream_enc_count; i++) { - if (pool->base.stream_enc[i] != NULL) { - if (pool->base.stream_enc[i]->vpg != NULL) { - kfree(DCN30_VPG_FROM_VPG(pool->base.stream_enc[i]->vpg)); - pool->base.stream_enc[i]->vpg = NULL; - } - if (pool->base.stream_enc[i]->afmt != NULL) { - kfree(DCN30_AFMT_FROM_AFMT(pool->base.stream_enc[i]->afmt)); - pool->base.stream_enc[i]->afmt = NULL; - } - kfree(DCN10STRENC_FROM_STRENC(pool->base.stream_enc[i])); - pool->base.stream_enc[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_dsc; i++) { - if (pool->base.dscs[i] != NULL) - dcn20_dsc_destroy(&pool->base.dscs[i]); - } - - if (pool->base.mpc != NULL) { - kfree(TO_DCN20_MPC(pool->base.mpc)); - pool->base.mpc = NULL; - } - if (pool->base.hubbub != NULL) { - kfree(pool->base.hubbub); - pool->base.hubbub = NULL; - } - for (i = 0; i < pool->base.pipe_count; i++) { - if (pool->base.dpps[i] != NULL) - dcn30_dpp_destroy(&pool->base.dpps[i]); - - if (pool->base.ipps[i] != NULL) - pool->base.ipps[i]->funcs->ipp_destroy(&pool->base.ipps[i]); - - if (pool->base.hubps[i] != NULL) { - kfree(TO_DCN20_HUBP(pool->base.hubps[i])); - pool->base.hubps[i] = NULL; - } - - if (pool->base.irqs != NULL) { - dal_irq_service_destroy(&pool->base.irqs); - } - } - - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - if (pool->base.engines[i] != NULL) - dce110_engine_destroy(&pool->base.engines[i]); - if (pool->base.hw_i2cs[i] != NULL) { - kfree(pool->base.hw_i2cs[i]); - pool->base.hw_i2cs[i] = NULL; - } - if (pool->base.sw_i2cs[i] != NULL) { - kfree(pool->base.sw_i2cs[i]); - pool->base.sw_i2cs[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_opp; i++) { - if (pool->base.opps[i] != NULL) - pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]); - } - - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - if (pool->base.timing_generators[i] != NULL) { - kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i])); - pool->base.timing_generators[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_dwb; i++) { - if (pool->base.dwbc[i] != NULL) { - kfree(TO_DCN30_DWBC(pool->base.dwbc[i])); - pool->base.dwbc[i] = NULL; - } - if (pool->base.mcif_wb[i] != NULL) { - kfree(TO_DCN30_MMHUBBUB(pool->base.mcif_wb[i])); - pool->base.mcif_wb[i] = NULL; - } - } - - for (i = 0; i < pool->base.audio_count; i++) { - if (pool->base.audios[i]) - dce_aud_destroy(&pool->base.audios[i]); - } - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] != NULL) { - dcn20_clock_source_destroy(&pool->base.clock_sources[i]); - pool->base.clock_sources[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_mpc_3dlut; i++) { - if (pool->base.mpc_lut[i] != NULL) { - dc_3dlut_func_release(pool->base.mpc_lut[i]); - pool->base.mpc_lut[i] = NULL; - } - if (pool->base.mpc_shaper[i] != NULL) { - dc_transfer_func_release(pool->base.mpc_shaper[i]); - pool->base.mpc_shaper[i] = NULL; - } - } - - if (pool->base.dp_clock_source != NULL) { - dcn20_clock_source_destroy(&pool->base.dp_clock_source); - pool->base.dp_clock_source = NULL; - } - - for (i = 0; i < pool->base.pipe_count; i++) { - if (pool->base.multiple_abms[i] != NULL) - dce_abm_destroy(&pool->base.multiple_abms[i]); - } - - if (pool->base.psr != NULL) - dmub_psr_destroy(&pool->base.psr); - - if (pool->base.dccg != NULL) - dcn_dccg_destroy(&pool->base.dccg); - - if (pool->base.oem_device != NULL) { - struct dc *dc = pool->base.oem_device->ctx->dc; - - dc->link_srv->destroy_ddc_service(&pool->base.oem_device); - } -} - -static struct hubp *dcn30_hubp_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn20_hubp *hubp2 = - kzalloc(sizeof(struct dcn20_hubp), GFP_KERNEL); - - if (!hubp2) - return NULL; - - if (hubp3_construct(hubp2, ctx, inst, - &hubp_regs[inst], &hubp_shift, &hubp_mask)) - return &hubp2->base; - - BREAK_TO_DEBUGGER(); - kfree(hubp2); - return NULL; -} - -static bool dcn30_dwbc_create(struct dc_context *ctx, struct resource_pool *pool) -{ - int i; - uint32_t pipe_count = pool->res_cap->num_dwb; - - for (i = 0; i < pipe_count; i++) { - struct dcn30_dwbc *dwbc30 = kzalloc(sizeof(struct dcn30_dwbc), - GFP_KERNEL); - - if (!dwbc30) { - dm_error("DC: failed to create dwbc30!\n"); - return false; - } - - dcn30_dwbc_construct(dwbc30, ctx, - &dwbc30_regs[i], - &dwbc30_shift, - &dwbc30_mask, - i); - - pool->dwbc[i] = &dwbc30->base; - } - return true; -} - -static bool dcn30_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool) -{ - int i; - uint32_t pipe_count = pool->res_cap->num_dwb; - - for (i = 0; i < pipe_count; i++) { - struct dcn30_mmhubbub *mcif_wb30 = kzalloc(sizeof(struct dcn30_mmhubbub), - GFP_KERNEL); - - if (!mcif_wb30) { - dm_error("DC: failed to create mcif_wb30!\n"); - return false; - } - - dcn30_mmhubbub_construct(mcif_wb30, ctx, - &mcif_wb30_regs[i], - &mcif_wb30_shift, - &mcif_wb30_mask, - i); - - pool->mcif_wb[i] = &mcif_wb30->base; - } - return true; -} - -static struct display_stream_compressor *dcn30_dsc_create( - struct dc_context *ctx, uint32_t inst) -{ - struct dcn20_dsc *dsc = - kzalloc(sizeof(struct dcn20_dsc), GFP_KERNEL); - - if (!dsc) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dsc2_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask); - return &dsc->base; -} - -enum dc_status dcn30_add_stream_to_ctx(struct dc *dc, struct dc_state *new_ctx, struct dc_stream_state *dc_stream) -{ - - return dcn20_add_stream_to_ctx(dc, new_ctx, dc_stream); -} - -static void dcn30_destroy_resource_pool(struct resource_pool **pool) -{ - struct dcn30_resource_pool *dcn30_pool = TO_DCN30_RES_POOL(*pool); - - dcn30_resource_destruct(dcn30_pool); - kfree(dcn30_pool); - *pool = NULL; -} - -static struct clock_source *dcn30_clock_source_create( - struct dc_context *ctx, - struct dc_bios *bios, - enum clock_source_id id, - const struct dce110_clk_src_regs *regs, - bool dp_clk_src) -{ - struct dce110_clk_src *clk_src = - kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); - - if (!clk_src) - return NULL; - - if (dcn3_clk_src_construct(clk_src, ctx, bios, id, - regs, &cs_shift, &cs_mask)) { - clk_src->base.dp_clk_src = dp_clk_src; - return &clk_src->base; - } - - kfree(clk_src); - BREAK_TO_DEBUGGER(); - return NULL; -} - -int dcn30_populate_dml_pipes_from_context( - struct dc *dc, struct dc_state *context, - display_e2e_pipe_params_st *pipes, - bool fast_validate) -{ - int i, pipe_cnt; - struct resource_context *res_ctx = &context->res_ctx; - - DC_FP_START(); - dcn20_populate_dml_pipes_from_context(dc, context, pipes, fast_validate); - DC_FP_END(); - - for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) { - if (!res_ctx->pipe_ctx[i].stream) - continue; - - pipes[pipe_cnt++].pipe.scale_ratio_depth.lb_depth = - dm_lb_16; - } - - return pipe_cnt; -} - -void dcn30_populate_dml_writeback_from_context( - struct dc *dc, struct resource_context *res_ctx, display_e2e_pipe_params_st *pipes) -{ - DC_FP_START(); - dcn30_fpu_populate_dml_writeback_from_context(dc, res_ctx, pipes); - DC_FP_END(); -} - -unsigned int dcn30_calc_max_scaled_time( - unsigned int time_per_pixel, - enum mmhubbub_wbif_mode mode, - unsigned int urgent_watermark) -{ - unsigned int time_per_byte = 0; - unsigned int total_free_entry = 0xb40; - unsigned int buf_lh_capability; - unsigned int max_scaled_time; - - if (mode == PACKED_444) /* packed mode 32 bpp */ - time_per_byte = time_per_pixel/4; - else if (mode == PACKED_444_FP16) /* packed mode 64 bpp */ - time_per_byte = time_per_pixel/8; - - if (time_per_byte == 0) - time_per_byte = 1; - - buf_lh_capability = (total_free_entry*time_per_byte*32) >> 6; /* time_per_byte is in u6.6*/ - max_scaled_time = buf_lh_capability - urgent_watermark; - return max_scaled_time; -} - -void dcn30_set_mcif_arb_params( - struct dc *dc, - struct dc_state *context, - display_e2e_pipe_params_st *pipes, - int pipe_cnt) -{ - enum mmhubbub_wbif_mode wbif_mode; - struct display_mode_lib *dml = &context->bw_ctx.dml; - struct mcif_arb_params *wb_arb_params; - int i, j, dwb_pipe; - - /* Writeback MCIF_WB arbitration parameters */ - dwb_pipe = 0; - for (i = 0; i < dc->res_pool->pipe_count; i++) { - - if (!context->res_ctx.pipe_ctx[i].stream) - continue; - - for (j = 0; j < MAX_DWB_PIPES; j++) { - struct dc_writeback_info *writeback_info = &context->res_ctx.pipe_ctx[i].stream->writeback_info[j]; - - if (writeback_info->wb_enabled == false) - continue; - - //wb_arb_params = &context->res_ctx.pipe_ctx[i].stream->writeback_info[j].mcif_arb_params; - wb_arb_params = &context->bw_ctx.bw.dcn.bw_writeback.mcif_wb_arb[dwb_pipe]; - - if (writeback_info->dwb_params.cnv_params.fc_out_format == DWB_OUT_FORMAT_64BPP_ARGB || - writeback_info->dwb_params.cnv_params.fc_out_format == DWB_OUT_FORMAT_64BPP_RGBA) - wbif_mode = PACKED_444_FP16; - else - wbif_mode = PACKED_444; - - DC_FP_START(); - dcn30_fpu_set_mcif_arb_params(wb_arb_params, dml, pipes, pipe_cnt, j); - DC_FP_END(); - wb_arb_params->time_per_pixel = (1000000 << 6) / context->res_ctx.pipe_ctx[i].stream->phy_pix_clk; /* time_per_pixel should be in u6.6 format */ - wb_arb_params->slice_lines = 32; - wb_arb_params->arbitration_slice = 2; /* irrelevant since there is no YUV output */ - wb_arb_params->max_scaled_time = dcn30_calc_max_scaled_time(wb_arb_params->time_per_pixel, - wbif_mode, - wb_arb_params->cli_watermark[0]); /* assume 4 watermark sets have the same value */ - - dwb_pipe++; - - if (dwb_pipe >= MAX_DWB_PIPES) - return; - } - if (dwb_pipe >= MAX_DWB_PIPES) - return; - } - -} - -static struct dc_cap_funcs cap_funcs = { - .get_dcc_compression_cap = dcn20_get_dcc_compression_cap -}; - -bool dcn30_acquire_post_bldn_3dlut( - struct resource_context *res_ctx, - const struct resource_pool *pool, - int mpcc_id, - struct dc_3dlut **lut, - struct dc_transfer_func **shaper) -{ - int i; - bool ret = false; - union dc_3dlut_state *state; - - ASSERT(*lut == NULL && *shaper == NULL); - *lut = NULL; - *shaper = NULL; - - for (i = 0; i < pool->res_cap->num_mpc_3dlut; i++) { - if (!res_ctx->is_mpc_3dlut_acquired[i]) { - *lut = pool->mpc_lut[i]; - *shaper = pool->mpc_shaper[i]; - state = &pool->mpc_lut[i]->state; - res_ctx->is_mpc_3dlut_acquired[i] = true; - state->bits.rmu_idx_valid = 1; - state->bits.rmu_mux_num = i; - if (state->bits.rmu_mux_num == 0) - state->bits.mpc_rmu0_mux = mpcc_id; - else if (state->bits.rmu_mux_num == 1) - state->bits.mpc_rmu1_mux = mpcc_id; - else if (state->bits.rmu_mux_num == 2) - state->bits.mpc_rmu2_mux = mpcc_id; - ret = true; - break; - } - } - return ret; -} - -bool dcn30_release_post_bldn_3dlut( - struct resource_context *res_ctx, - const struct resource_pool *pool, - struct dc_3dlut **lut, - struct dc_transfer_func **shaper) -{ - int i; - bool ret = false; - - for (i = 0; i < pool->res_cap->num_mpc_3dlut; i++) { - if (pool->mpc_lut[i] == *lut && pool->mpc_shaper[i] == *shaper) { - res_ctx->is_mpc_3dlut_acquired[i] = false; - pool->mpc_lut[i]->state.raw = 0; - *lut = NULL; - *shaper = NULL; - ret = true; - break; - } - } - return ret; -} - -static bool is_soc_bounding_box_valid(struct dc *dc) -{ - uint32_t hw_internal_rev = dc->ctx->asic_id.hw_internal_rev; - - if (ASICREV_IS_SIENNA_CICHLID_P(hw_internal_rev)) - return true; - - return false; -} - -static bool init_soc_bounding_box(struct dc *dc, - struct dcn30_resource_pool *pool) -{ - struct _vcs_dpi_soc_bounding_box_st *loaded_bb = &dcn3_0_soc; - struct _vcs_dpi_ip_params_st *loaded_ip = &dcn3_0_ip; - - DC_LOGGER_INIT(dc->ctx->logger); - - if (!is_soc_bounding_box_valid(dc)) { - DC_LOG_ERROR("%s: not valid soc bounding box\n", __func__); - return false; - } - - loaded_ip->max_num_otg = pool->base.res_cap->num_timing_generator; - loaded_ip->max_num_dpp = pool->base.pipe_count; - loaded_ip->clamp_min_dcfclk = dc->config.clamp_min_dcfclk; - dcn20_patch_bounding_box(dc, loaded_bb); - DC_FP_START(); - patch_dcn30_soc_bounding_box(dc, &dcn3_0_soc); - DC_FP_END(); - - return true; -} - -static bool dcn30_split_stream_for_mpc_or_odm( - const struct dc *dc, - struct resource_context *res_ctx, - struct pipe_ctx *pri_pipe, - struct pipe_ctx *sec_pipe, - bool odm) -{ - int pipe_idx = sec_pipe->pipe_idx; - const struct resource_pool *pool = dc->res_pool; - - *sec_pipe = *pri_pipe; - - sec_pipe->pipe_idx = pipe_idx; - sec_pipe->plane_res.mi = pool->mis[pipe_idx]; - sec_pipe->plane_res.hubp = pool->hubps[pipe_idx]; - sec_pipe->plane_res.ipp = pool->ipps[pipe_idx]; - sec_pipe->plane_res.xfm = pool->transforms[pipe_idx]; - sec_pipe->plane_res.dpp = pool->dpps[pipe_idx]; - sec_pipe->plane_res.mpcc_inst = pool->dpps[pipe_idx]->inst; - sec_pipe->stream_res.dsc = NULL; - if (odm) { - if (pri_pipe->next_odm_pipe) { - ASSERT(pri_pipe->next_odm_pipe != sec_pipe); - sec_pipe->next_odm_pipe = pri_pipe->next_odm_pipe; - sec_pipe->next_odm_pipe->prev_odm_pipe = sec_pipe; - } - if (pri_pipe->top_pipe && pri_pipe->top_pipe->next_odm_pipe) { - pri_pipe->top_pipe->next_odm_pipe->bottom_pipe = sec_pipe; - sec_pipe->top_pipe = pri_pipe->top_pipe->next_odm_pipe; - } - if (pri_pipe->bottom_pipe && pri_pipe->bottom_pipe->next_odm_pipe) { - pri_pipe->bottom_pipe->next_odm_pipe->top_pipe = sec_pipe; - sec_pipe->bottom_pipe = pri_pipe->bottom_pipe->next_odm_pipe; - } - pri_pipe->next_odm_pipe = sec_pipe; - sec_pipe->prev_odm_pipe = pri_pipe; - - if (!sec_pipe->top_pipe) - sec_pipe->stream_res.opp = pool->opps[pipe_idx]; - else - sec_pipe->stream_res.opp = sec_pipe->top_pipe->stream_res.opp; - if (sec_pipe->stream->timing.flags.DSC == 1) { - dcn20_acquire_dsc(dc, res_ctx, &sec_pipe->stream_res.dsc, pipe_idx); - ASSERT(sec_pipe->stream_res.dsc); - if (sec_pipe->stream_res.dsc == NULL) - return false; - } - } else { - if (pri_pipe->bottom_pipe) { - ASSERT(pri_pipe->bottom_pipe != sec_pipe); - sec_pipe->bottom_pipe = pri_pipe->bottom_pipe; - sec_pipe->bottom_pipe->top_pipe = sec_pipe; - } - pri_pipe->bottom_pipe = sec_pipe; - sec_pipe->top_pipe = pri_pipe; - - ASSERT(pri_pipe->plane_state); - } - - return true; -} - -static struct pipe_ctx *dcn30_find_split_pipe( - struct dc *dc, - struct dc_state *context, - int old_index) -{ - struct pipe_ctx *pipe = NULL; - int i; - - if (old_index >= 0 && context->res_ctx.pipe_ctx[old_index].stream == NULL) { - pipe = &context->res_ctx.pipe_ctx[old_index]; - pipe->pipe_idx = old_index; - } - - if (!pipe) - for (i = dc->res_pool->pipe_count - 1; i >= 0; i--) { - if (dc->current_state->res_ctx.pipe_ctx[i].top_pipe == NULL - && dc->current_state->res_ctx.pipe_ctx[i].prev_odm_pipe == NULL) { - if (context->res_ctx.pipe_ctx[i].stream == NULL) { - pipe = &context->res_ctx.pipe_ctx[i]; - pipe->pipe_idx = i; - break; - } - } - } - - /* - * May need to fix pipes getting tossed from 1 opp to another on flip - * Add for debugging transient underflow during topology updates: - * ASSERT(pipe); - */ - if (!pipe) - for (i = dc->res_pool->pipe_count - 1; i >= 0; i--) { - if (context->res_ctx.pipe_ctx[i].stream == NULL) { - pipe = &context->res_ctx.pipe_ctx[i]; - pipe->pipe_idx = i; - break; - } - } - - return pipe; -} - -noinline bool dcn30_internal_validate_bw( - struct dc *dc, - struct dc_state *context, - display_e2e_pipe_params_st *pipes, - int *pipe_cnt_out, - int *vlevel_out, - bool fast_validate, - bool allow_self_refresh_only) -{ - bool out = false; - bool repopulate_pipes = false; - int split[MAX_PIPES] = { 0 }; - bool merge[MAX_PIPES] = { false }; - bool newly_split[MAX_PIPES] = { false }; - int pipe_cnt, i, pipe_idx, vlevel; - struct vba_vars_st *vba = &context->bw_ctx.dml.vba; - - ASSERT(pipes); - if (!pipes) - return false; - - context->bw_ctx.dml.vba.maxMpcComb = 0; - context->bw_ctx.dml.vba.VoltageLevel = 0; - context->bw_ctx.dml.vba.DRAMClockChangeSupport[0][0] = dm_dram_clock_change_vactive; - dc->res_pool->funcs->update_soc_for_wm_a(dc, context); - pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, context, pipes, fast_validate); - - if (!pipe_cnt) { - out = true; - goto validate_out; - } - - dml_log_pipe_params(&context->bw_ctx.dml, pipes, pipe_cnt); - - 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 - * prefetch mode > 0 so try capping the prefetch mode to start. - */ - context->bw_ctx.dml.soc.allow_dram_self_refresh_or_dram_clock_change_in_vblank = - dm_allow_self_refresh_and_mclk_switch; - vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt); - /* This may adjust vlevel and maxMpcComb */ - if (vlevel < context->bw_ctx.dml.soc.num_states) - vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, vlevel, split, merge); - } - 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. - * - * We don't actually support prefetch mode 2, so require that we - * at least support prefetch mode 1. - */ - context->bw_ctx.dml.soc.allow_dram_self_refresh_or_dram_clock_change_in_vblank = - dm_allow_self_refresh; - - vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt); - if (vlevel < context->bw_ctx.dml.soc.num_states) { - memset(split, 0, sizeof(split)); - memset(merge, 0, sizeof(merge)); - vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, vlevel, split, merge); - } - } - - dml_log_mode_support_params(&context->bw_ctx.dml); - - if (vlevel == context->bw_ctx.dml.soc.num_states) - goto validate_fail; - - if (!dc->config.enable_windowed_mpo_odm) { - for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - struct pipe_ctx *mpo_pipe = pipe->bottom_pipe; - - if (!pipe->stream) - continue; - - /* We only support full screen mpo with ODM */ - if (vba->ODMCombineEnabled[vba->pipe_plane[pipe_idx]] != dm_odm_combine_mode_disabled - && pipe->plane_state && mpo_pipe - && memcmp(&mpo_pipe->plane_state->clip_rect, - &pipe->stream->src, - sizeof(struct rect)) != 0) { - ASSERT(mpo_pipe->plane_state != pipe->plane_state); - goto validate_fail; - } - pipe_idx++; - } - } - - /* merge pipes if necessary */ - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - - /*skip pipes that don't need merging*/ - if (!merge[i]) - continue; - - /* if ODM merge we ignore mpc tree, mpo pipes will have their own flags */ - if (pipe->prev_odm_pipe) { - /*split off odm pipe*/ - pipe->prev_odm_pipe->next_odm_pipe = pipe->next_odm_pipe; - if (pipe->next_odm_pipe) - pipe->next_odm_pipe->prev_odm_pipe = pipe->prev_odm_pipe; - - pipe->bottom_pipe = NULL; - pipe->next_odm_pipe = NULL; - pipe->plane_state = NULL; - pipe->stream = NULL; - pipe->top_pipe = NULL; - pipe->prev_odm_pipe = NULL; - if (pipe->stream_res.dsc) - 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)); - repopulate_pipes = true; - } else if (pipe->top_pipe && pipe->top_pipe->plane_state == pipe->plane_state) { - struct pipe_ctx *top_pipe = pipe->top_pipe; - struct pipe_ctx *bottom_pipe = pipe->bottom_pipe; - - top_pipe->bottom_pipe = bottom_pipe; - if (bottom_pipe) - bottom_pipe->top_pipe = top_pipe; - - pipe->top_pipe = NULL; - pipe->bottom_pipe = NULL; - pipe->plane_state = NULL; - pipe->stream = NULL; - memset(&pipe->plane_res, 0, sizeof(pipe->plane_res)); - memset(&pipe->stream_res, 0, sizeof(pipe->stream_res)); - repopulate_pipes = true; - } else - ASSERT(0); /* Should never try to merge master pipe */ - - } - - for (i = 0, pipe_idx = -1; 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]; - struct pipe_ctx *hsplit_pipe = NULL; - bool odm; - int old_index = -1; - - if (!pipe->stream || newly_split[i]) - continue; - - pipe_idx++; - odm = vba->ODMCombineEnabled[vba->pipe_plane[pipe_idx]] != dm_odm_combine_mode_disabled; - - if (!pipe->plane_state && !odm) - continue; - - if (split[i]) { - if (odm) { - if (split[i] == 4 && old_pipe->next_odm_pipe && old_pipe->next_odm_pipe->next_odm_pipe) - old_index = old_pipe->next_odm_pipe->next_odm_pipe->pipe_idx; - else if (old_pipe->next_odm_pipe) - old_index = old_pipe->next_odm_pipe->pipe_idx; - } else { - if (split[i] == 4 && old_pipe->bottom_pipe && old_pipe->bottom_pipe->bottom_pipe && - old_pipe->bottom_pipe->bottom_pipe->plane_state == old_pipe->plane_state) - old_index = old_pipe->bottom_pipe->bottom_pipe->pipe_idx; - else if (old_pipe->bottom_pipe && - old_pipe->bottom_pipe->plane_state == old_pipe->plane_state) - old_index = old_pipe->bottom_pipe->pipe_idx; - } - hsplit_pipe = dcn30_find_split_pipe(dc, context, old_index); - ASSERT(hsplit_pipe); - if (!hsplit_pipe) - goto validate_fail; - - if (!dcn30_split_stream_for_mpc_or_odm( - dc, &context->res_ctx, - pipe, hsplit_pipe, odm)) - goto validate_fail; - - newly_split[hsplit_pipe->pipe_idx] = true; - repopulate_pipes = true; - } - if (split[i] == 4) { - struct pipe_ctx *pipe_4to1; - - if (odm && old_pipe->next_odm_pipe) - old_index = old_pipe->next_odm_pipe->pipe_idx; - else if (!odm && old_pipe->bottom_pipe && - old_pipe->bottom_pipe->plane_state == old_pipe->plane_state) - old_index = old_pipe->bottom_pipe->pipe_idx; - else - old_index = -1; - pipe_4to1 = dcn30_find_split_pipe(dc, context, old_index); - ASSERT(pipe_4to1); - if (!pipe_4to1) - goto validate_fail; - if (!dcn30_split_stream_for_mpc_or_odm( - dc, &context->res_ctx, - pipe, pipe_4to1, odm)) - goto validate_fail; - newly_split[pipe_4to1->pipe_idx] = true; - - if (odm && old_pipe->next_odm_pipe && old_pipe->next_odm_pipe->next_odm_pipe - && old_pipe->next_odm_pipe->next_odm_pipe->next_odm_pipe) - old_index = old_pipe->next_odm_pipe->next_odm_pipe->next_odm_pipe->pipe_idx; - else if (!odm && old_pipe->bottom_pipe && old_pipe->bottom_pipe->bottom_pipe && - old_pipe->bottom_pipe->bottom_pipe->bottom_pipe && - old_pipe->bottom_pipe->bottom_pipe->bottom_pipe->plane_state == old_pipe->plane_state) - old_index = old_pipe->bottom_pipe->bottom_pipe->bottom_pipe->pipe_idx; - else - old_index = -1; - pipe_4to1 = dcn30_find_split_pipe(dc, context, old_index); - ASSERT(pipe_4to1); - if (!pipe_4to1) - goto validate_fail; - if (!dcn30_split_stream_for_mpc_or_odm( - dc, &context->res_ctx, - hsplit_pipe, pipe_4to1, odm)) - goto validate_fail; - newly_split[pipe_4to1->pipe_idx] = true; - } - if (odm) - dcn20_build_mapped_resource(dc, context, pipe->stream); - } - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - - if (pipe->plane_state) { - if (!resource_build_scaling_params(pipe)) - goto validate_fail; - } - } - - /* Actual dsc count per stream dsc validation*/ - if (!dcn20_validate_dsc(dc, context)) { - vba->ValidationStatus[vba->soc.num_states] = DML_FAIL_DSC_VALIDATION_FAILURE; - goto validate_fail; - } - - if (repopulate_pipes) - pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, context, pipes, fast_validate); - context->bw_ctx.dml.vba.VoltageLevel = vlevel; - *vlevel_out = vlevel; - *pipe_cnt_out = pipe_cnt; - - out = true; - goto validate_out; - -validate_fail: - out = false; - -validate_out: - return out; -} - -static int get_refresh_rate(struct dc_state *context) -{ - int refresh_rate = 0; - int h_v_total = 0; - struct dc_crtc_timing *timing = NULL; - - if (context == NULL || context->streams[0] == NULL) - return 0; - - /* check if refresh rate at least 120hz */ - timing = &context->streams[0]->timing; - if (timing == NULL) - return 0; - - h_v_total = timing->h_total * timing->v_total; - if (h_v_total == 0) - return 0; - - refresh_rate = ((timing->pix_clk_100hz * 100) / (h_v_total)) + 1; - return refresh_rate; -} - -#define MAX_STRETCHED_V_BLANK 500 // in micro-seconds -/* - * Scaling factor for v_blank stretch calculations considering timing in - * micro-seconds and pixel clock in 100hz. - * Note: the parenthesis are necessary to ensure the correct order of - * operation where V_SCALE is used. - */ -#define V_SCALE (10000 / MAX_STRETCHED_V_BLANK) - -static int get_frame_rate_at_max_stretch_100hz(struct dc_state *context) -{ - struct dc_crtc_timing *timing = NULL; - uint32_t sec_per_100_lines; - uint32_t max_v_blank; - uint32_t curr_v_blank; - uint32_t v_stretch_max; - uint32_t stretched_frame_pix_cnt; - uint32_t scaled_stretched_frame_pix_cnt; - uint32_t scaled_refresh_rate; - - if (context == NULL || context->streams[0] == NULL) - return 0; - - /* check if refresh rate at least 120hz */ - timing = &context->streams[0]->timing; - if (timing == NULL) - return 0; - - sec_per_100_lines = timing->pix_clk_100hz / timing->h_total + 1; - max_v_blank = sec_per_100_lines / V_SCALE + 1; - curr_v_blank = timing->v_total - timing->v_addressable; - v_stretch_max = (max_v_blank > curr_v_blank) ? (max_v_blank - curr_v_blank) : (0); - stretched_frame_pix_cnt = (v_stretch_max + timing->v_total) * timing->h_total; - scaled_stretched_frame_pix_cnt = stretched_frame_pix_cnt / 10000; - scaled_refresh_rate = (timing->pix_clk_100hz) / scaled_stretched_frame_pix_cnt + 1; - - return scaled_refresh_rate; -} - -static bool is_refresh_rate_support_mclk_switch_using_fw_based_vblank_stretch(struct dc_state *context) -{ - int refresh_rate_max_stretch_100hz; - int min_refresh_100hz; - - if (context == NULL || context->streams[0] == NULL) - return false; - - refresh_rate_max_stretch_100hz = get_frame_rate_at_max_stretch_100hz(context); - min_refresh_100hz = context->streams[0]->timing.min_refresh_in_uhz / 10000; - - if (refresh_rate_max_stretch_100hz < min_refresh_100hz) - return false; - - return true; -} - -bool dcn30_can_support_mclk_switch_using_fw_based_vblank_stretch(struct dc *dc, struct dc_state *context) -{ - int refresh_rate = 0; - const int minimum_refreshrate_supported = 120; - - if (context == NULL || context->streams[0] == NULL) - return false; - - if (context->streams[0]->sink->edid_caps.panel_patch.disable_fams) - return false; - - if (dc->debug.disable_fams) - return false; - - if (!dc->caps.dmub_caps.mclk_sw) - return false; - - if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching_shut_down) - return false; - - /* more then 1 monitor connected */ - if (context->stream_count != 1) - return false; - - refresh_rate = get_refresh_rate(context); - if (refresh_rate < minimum_refreshrate_supported) - return false; - - if (!is_refresh_rate_support_mclk_switch_using_fw_based_vblank_stretch(context)) - return false; - - if (!context->streams[0]->allow_freesync) - return false; - - if (context->streams[0]->vrr_active_variable && dc->debug.disable_fams_gaming) - return false; - - context->streams[0]->fpo_in_use = true; - - return true; -} - -/* - * set up FPO watermarks, pstate, dram latency - */ -void dcn30_setup_mclk_switch_using_fw_based_vblank_stretch(struct dc *dc, struct dc_state *context) -{ - ASSERT(dc != NULL && context != NULL); - if (dc == NULL || context == NULL) - return; - - /* Set wm_a.pstate so high natural MCLK switches are impossible: 4 seconds */ - context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = 4U * 1000U * 1000U * 1000U; -} - -void dcn30_update_soc_for_wm_a(struct dc *dc, struct dc_state *context) -{ - DC_FP_START(); - dcn30_fpu_update_soc_for_wm_a(dc, context); - DC_FP_END(); -} - -void dcn30_calculate_wm_and_dlg( - struct dc *dc, struct dc_state *context, - display_e2e_pipe_params_st *pipes, - int pipe_cnt, - int vlevel) -{ - DC_FP_START(); - dcn30_fpu_calculate_wm_and_dlg(dc, context, pipes, pipe_cnt, vlevel); - DC_FP_END(); -} - -bool dcn30_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(); - out = dcn30_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, fast_validate, true); - DC_FP_END(); - - if (pipe_cnt == 0) - goto validate_out; - - if (!out) - goto validate_fail; - - BW_VAL_TRACE_END_VOLTAGE_LEVEL(); - - if (fast_validate) { - BW_VAL_TRACE_SKIP(fast); - goto validate_out; - } - - DC_FP_START(); - if (dc->res_pool->funcs->calculate_wm_and_dlg) - dc->res_pool->funcs->calculate_wm_and_dlg(dc, context, pipes, pipe_cnt, vlevel); - DC_FP_END(); - - 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; -} - -void dcn30_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) -{ - unsigned int i, j; - unsigned int num_states = 0; - - unsigned int dcfclk_mhz[DC__VOLTAGE_STATES] = {0}; - unsigned int dram_speed_mts[DC__VOLTAGE_STATES] = {0}; - unsigned int optimal_uclk_for_dcfclk_sta_targets[DC__VOLTAGE_STATES] = {0}; - unsigned int optimal_dcfclk_for_uclk[DC__VOLTAGE_STATES] = {0}; - - unsigned int dcfclk_sta_targets[DC__VOLTAGE_STATES] = {694, 875, 1000, 1200}; - unsigned int num_dcfclk_sta_targets = 4; - unsigned int num_uclk_states; - - struct dc_bounding_box_max_clk dcn30_bb_max_clk; - - memset(&dcn30_bb_max_clk, 0, sizeof(dcn30_bb_max_clk)); - - if (dc->ctx->dc_bios->vram_info.num_chans) - dcn3_0_soc.num_chans = dc->ctx->dc_bios->vram_info.num_chans; - - DC_FP_START(); - dcn30_fpu_update_dram_channel_width_bytes(dc); - DC_FP_END(); - - if (bw_params->clk_table.entries[0].memclk_mhz) { - - for (i = 0; i < MAX_NUM_DPM_LVL; i++) { - if (bw_params->clk_table.entries[i].dcfclk_mhz > dcn30_bb_max_clk.max_dcfclk_mhz) - dcn30_bb_max_clk.max_dcfclk_mhz = bw_params->clk_table.entries[i].dcfclk_mhz; - if (bw_params->clk_table.entries[i].dispclk_mhz > dcn30_bb_max_clk.max_dispclk_mhz) - dcn30_bb_max_clk.max_dispclk_mhz = bw_params->clk_table.entries[i].dispclk_mhz; - if (bw_params->clk_table.entries[i].dppclk_mhz > dcn30_bb_max_clk.max_dppclk_mhz) - dcn30_bb_max_clk.max_dppclk_mhz = bw_params->clk_table.entries[i].dppclk_mhz; - if (bw_params->clk_table.entries[i].phyclk_mhz > dcn30_bb_max_clk.max_phyclk_mhz) - dcn30_bb_max_clk.max_phyclk_mhz = bw_params->clk_table.entries[i].phyclk_mhz; - } - - DC_FP_START(); - dcn30_fpu_update_max_clk(&dcn30_bb_max_clk); - DC_FP_END(); - - if (dcn30_bb_max_clk.max_dcfclk_mhz > dcfclk_sta_targets[num_dcfclk_sta_targets-1]) { - // If max DCFCLK is greater than the max DCFCLK STA target, insert into the DCFCLK STA target array - dcfclk_sta_targets[num_dcfclk_sta_targets] = dcn30_bb_max_clk.max_dcfclk_mhz; - num_dcfclk_sta_targets++; - } else if (dcn30_bb_max_clk.max_dcfclk_mhz < dcfclk_sta_targets[num_dcfclk_sta_targets-1]) { - // If max DCFCLK is less than the max DCFCLK STA target, cap values and remove duplicates - for (i = 0; i < num_dcfclk_sta_targets; i++) { - if (dcfclk_sta_targets[i] > dcn30_bb_max_clk.max_dcfclk_mhz) { - dcfclk_sta_targets[i] = dcn30_bb_max_clk.max_dcfclk_mhz; - break; - } - } - // Update size of array since we "removed" duplicates - num_dcfclk_sta_targets = i + 1; - } - - num_uclk_states = bw_params->clk_table.num_entries; - - // Calculate optimal dcfclk for each uclk - for (i = 0; i < num_uclk_states; i++) { - DC_FP_START(); - dcn30_fpu_get_optimal_dcfclk_fclk_for_uclk(bw_params->clk_table.entries[i].memclk_mhz * 16, - &optimal_dcfclk_for_uclk[i], NULL); - DC_FP_END(); - if (optimal_dcfclk_for_uclk[i] < bw_params->clk_table.entries[0].dcfclk_mhz) { - optimal_dcfclk_for_uclk[i] = bw_params->clk_table.entries[0].dcfclk_mhz; - } - } - - // Calculate optimal uclk for each dcfclk sta target - for (i = 0; i < num_dcfclk_sta_targets; i++) { - for (j = 0; j < num_uclk_states; j++) { - if (dcfclk_sta_targets[i] < optimal_dcfclk_for_uclk[j]) { - optimal_uclk_for_dcfclk_sta_targets[i] = - bw_params->clk_table.entries[j].memclk_mhz * 16; - break; - } - } - } - - i = 0; - j = 0; - // create the final dcfclk and uclk table - while (i < num_dcfclk_sta_targets && j < num_uclk_states && num_states < DC__VOLTAGE_STATES) { - if (dcfclk_sta_targets[i] < optimal_dcfclk_for_uclk[j] && i < num_dcfclk_sta_targets) { - dcfclk_mhz[num_states] = dcfclk_sta_targets[i]; - dram_speed_mts[num_states++] = optimal_uclk_for_dcfclk_sta_targets[i++]; - } else { - if (j < num_uclk_states && optimal_dcfclk_for_uclk[j] <= dcn30_bb_max_clk.max_dcfclk_mhz) { - dcfclk_mhz[num_states] = optimal_dcfclk_for_uclk[j]; - dram_speed_mts[num_states++] = bw_params->clk_table.entries[j++].memclk_mhz * 16; - } else { - j = num_uclk_states; - } - } - } - - while (i < num_dcfclk_sta_targets && num_states < DC__VOLTAGE_STATES) { - dcfclk_mhz[num_states] = dcfclk_sta_targets[i]; - dram_speed_mts[num_states++] = optimal_uclk_for_dcfclk_sta_targets[i++]; - } - - while (j < num_uclk_states && num_states < DC__VOLTAGE_STATES && - optimal_dcfclk_for_uclk[j] <= dcn30_bb_max_clk.max_dcfclk_mhz) { - dcfclk_mhz[num_states] = optimal_dcfclk_for_uclk[j]; - dram_speed_mts[num_states++] = bw_params->clk_table.entries[j++].memclk_mhz * 16; - } - - dcn3_0_soc.num_states = num_states; - DC_FP_START(); - dcn30_fpu_update_bw_bounding_box(dc, bw_params, &dcn30_bb_max_clk, dcfclk_mhz, dram_speed_mts); - DC_FP_END(); - } -} - -static void dcn30_get_panel_config_defaults(struct dc_panel_config *panel_config) -{ - *panel_config = panel_config_defaults; -} - -static const struct resource_funcs dcn30_res_pool_funcs = { - .destroy = dcn30_destroy_resource_pool, - .link_enc_create = dcn30_link_encoder_create, - .panel_cntl_create = dcn30_panel_cntl_create, - .validate_bandwidth = dcn30_validate_bandwidth, - .calculate_wm_and_dlg = dcn30_calculate_wm_and_dlg, - .update_soc_for_wm_a = dcn30_update_soc_for_wm_a, - .populate_dml_pipes = dcn30_populate_dml_pipes_from_context, - .acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer, - .release_pipe = dcn20_release_pipe, - .add_stream_to_ctx = dcn30_add_stream_to_ctx, - .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource, - .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, - .populate_dml_writeback_from_context = dcn30_populate_dml_writeback_from_context, - .set_mcif_arb_params = dcn30_set_mcif_arb_params, - .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 = dcn30_update_bw_bounding_box, - .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, - .get_panel_config_defaults = dcn30_get_panel_config_defaults, -}; - -#define CTX ctx - -#define REG(reg_name) \ - (DCN_BASE.instance[0].segment[mm ## reg_name ## _BASE_IDX] + mm ## reg_name) - -static uint32_t read_pipe_fuses(struct dc_context *ctx) -{ - uint32_t value = REG_READ(CC_DC_PIPE_DIS); - /* Support for max 6 pipes */ - value = value & 0x3f; - return value; -} - -static bool dcn30_resource_construct( - uint8_t num_virtual_links, - struct dc *dc, - struct dcn30_resource_pool *pool) -{ - int i; - struct dc_context *ctx = dc->ctx; - struct irq_service_init_data init_data; - struct ddc_service_init_data ddc_init_data = {0}; - uint32_t pipe_fuses = read_pipe_fuses(ctx); - uint32_t num_pipes = 0; - - if (!(pipe_fuses == 0 || pipe_fuses == 0x3e)) { - BREAK_TO_DEBUGGER(); - dm_error("DC: Unexpected fuse recipe for navi2x !\n"); - /* fault to single pipe */ - pipe_fuses = 0x3e; - } - - DC_FP_START(); - - ctx->dc_bios->regs = &bios_regs; - - pool->base.res_cap = &res_cap_dcn3; - - pool->base.funcs = &dcn30_res_pool_funcs; - - /************************************************* - * Resource + asic cap harcoding * - *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; - pool->base.pipe_count = pool->base.res_cap->num_timing_generator; - 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; /*1.4 w/a not applied by default*/ - dc->caps.max_cursor_size = 256; - dc->caps.min_horizontal_blanking_period = 80; - dc->caps.dmdata_alloc_size = 2048; - dc->caps.mall_size_per_mem_channel = 8; - /* total size = mall per channel * num channels * 1024 * 1024 */ - dc->caps.mall_size_total = dc->caps.mall_size_per_mem_channel * dc->ctx->dc_bios->vram_info.num_chans * 1048576; - dc->caps.cursor_cache_size = dc->caps.max_cursor_size * dc->caps.max_cursor_size * 8; - - dc->caps.max_slave_planes = 2; - dc->caps.max_slave_yuv_planes = 2; - dc->caps.max_slave_rgb_planes = 2; - dc->caps.post_blend_color_processing = true; - dc->caps.force_dp_tps4_for_cp2520 = true; - dc->caps.extended_aux_timeout_support = true; - dc->caps.dmcub_support = true; - - /* Color pipeline capabilities */ - dc->caps.color.dpp.dcn_arch = 1; - dc->caps.color.dpp.input_lut_shared = 0; - dc->caps.color.dpp.icsc = 1; - dc->caps.color.dpp.dgam_ram = 0; // must use gamma_corr - dc->caps.color.dpp.dgam_rom_caps.srgb = 1; - dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1; - dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 1; - dc->caps.color.dpp.dgam_rom_caps.pq = 1; - dc->caps.color.dpp.dgam_rom_caps.hlg = 1; - dc->caps.color.dpp.post_csc = 1; - dc->caps.color.dpp.gamma_corr = 1; - dc->caps.color.dpp.dgam_rom_for_yuv = 0; - - dc->caps.color.dpp.hw_3d_lut = 1; - dc->caps.color.dpp.ogam_ram = 1; - // no OGAM ROM on DCN3 - dc->caps.color.dpp.ogam_rom_caps.srgb = 0; - dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0; - dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0; - dc->caps.color.dpp.ogam_rom_caps.pq = 0; - dc->caps.color.dpp.ogam_rom_caps.hlg = 0; - dc->caps.color.dpp.ocsc = 0; - - dc->caps.color.mpc.gamut_remap = 1; - dc->caps.color.mpc.num_3dluts = pool->base.res_cap->num_mpc_3dlut; //3 - dc->caps.color.mpc.ogam_ram = 1; - dc->caps.color.mpc.ogam_rom_caps.srgb = 0; - dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0; - dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0; - dc->caps.color.mpc.ogam_rom_caps.pq = 0; - dc->caps.color.mpc.ogam_rom_caps.hlg = 0; - dc->caps.color.mpc.ocsc = 1; - - dc->caps.dp_hdmi21_pcon_support = true; - dc->caps.max_v_total = (1 << 15) - 1; - - /* read VBIOS LTTPR caps */ - { - if (ctx->dc_bios->funcs->get_lttpr_caps) { - enum bp_result bp_query_result; - uint8_t is_vbios_lttpr_enable = 0; - - bp_query_result = ctx->dc_bios->funcs->get_lttpr_caps(ctx->dc_bios, &is_vbios_lttpr_enable); - dc->caps.vbios_lttpr_enable = (bp_query_result == BP_RESULT_OK) && !!is_vbios_lttpr_enable; - } - - if (ctx->dc_bios->funcs->get_lttpr_interop) { - enum bp_result bp_query_result; - uint8_t is_vbios_interop_enabled = 0; - - bp_query_result = ctx->dc_bios->funcs->get_lttpr_interop(ctx->dc_bios, - &is_vbios_interop_enabled); - dc->caps.vbios_lttpr_aware = (bp_query_result == BP_RESULT_OK) && !!is_vbios_interop_enabled; - } - } - - if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) - dc->debug = debug_defaults_drv; - - // Init the vm_helper - if (dc->vm_helper) - vm_helper_init(dc->vm_helper, 16); - - /************************************************* - * Create resources * - *************************************************/ - - /* Clock Sources for Pixel Clock*/ - pool->base.clock_sources[DCN30_CLK_SRC_PLL0] = - dcn30_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL0, - &clk_src_regs[0], false); - pool->base.clock_sources[DCN30_CLK_SRC_PLL1] = - dcn30_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL1, - &clk_src_regs[1], false); - pool->base.clock_sources[DCN30_CLK_SRC_PLL2] = - dcn30_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL2, - &clk_src_regs[2], false); - pool->base.clock_sources[DCN30_CLK_SRC_PLL3] = - dcn30_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL3, - &clk_src_regs[3], false); - pool->base.clock_sources[DCN30_CLK_SRC_PLL4] = - dcn30_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL4, - &clk_src_regs[4], false); - pool->base.clock_sources[DCN30_CLK_SRC_PLL5] = - dcn30_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL5, - &clk_src_regs[5], false); - - pool->base.clk_src_count = DCN30_CLK_SRC_TOTAL; - - /* todo: not reuse phy_pll registers */ - pool->base.dp_clock_source = - dcn30_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_ID_DP_DTO, - &clk_src_regs[0], true); - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] == NULL) { - dm_error("DC: failed to create clock sources!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - } - - /* DCCG */ - pool->base.dccg = dccg30_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask); - if (pool->base.dccg == NULL) { - dm_error("DC: failed to create dccg!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - - /* PP Lib and SMU interfaces */ - init_soc_bounding_box(dc, pool); - - num_pipes = dcn3_0_ip.max_num_dpp; - - for (i = 0; i < dcn3_0_ip.max_num_dpp; i++) - if (pipe_fuses & 1 << i) - num_pipes--; - - dcn3_0_ip.max_num_dpp = num_pipes; - dcn3_0_ip.max_num_otg = num_pipes; - - dml_init_instance(&dc->dml, &dcn3_0_soc, &dcn3_0_ip, DML_PROJECT_DCN30); - - /* IRQ */ - init_data.ctx = dc->ctx; - pool->base.irqs = dal_irq_service_dcn30_create(&init_data); - if (!pool->base.irqs) - goto create_fail; - - /* HUBBUB */ - pool->base.hubbub = dcn30_hubbub_create(ctx); - if (pool->base.hubbub == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create hubbub!\n"); - goto create_fail; - } - - /* HUBPs, DPPs, OPPs and TGs */ - for (i = 0; i < pool->base.pipe_count; i++) { - pool->base.hubps[i] = dcn30_hubp_create(ctx, i); - if (pool->base.hubps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create hubps!\n"); - goto create_fail; - } - - pool->base.dpps[i] = dcn30_dpp_create(ctx, i); - if (pool->base.dpps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create dpps!\n"); - goto create_fail; - } - } - - for (i = 0; i < pool->base.res_cap->num_opp; i++) { - pool->base.opps[i] = dcn30_opp_create(ctx, i); - if (pool->base.opps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create output pixel processor!\n"); - goto create_fail; - } - } - - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - pool->base.timing_generators[i] = dcn30_timing_generator_create( - ctx, i); - if (pool->base.timing_generators[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create tg!\n"); - goto create_fail; - } - } - pool->base.timing_generator_count = i; - /* PSR */ - pool->base.psr = dmub_psr_create(ctx); - - if (pool->base.psr == NULL) { - dm_error("DC: failed to create PSR obj!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - - /* ABM */ - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - pool->base.multiple_abms[i] = dmub_abm_create(ctx, - &abm_regs[i], - &abm_shift, - &abm_mask); - if (pool->base.multiple_abms[i] == NULL) { - dm_error("DC: failed to create abm for pipe %d!\n", i); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - } - /* MPC and DSC */ - pool->base.mpc = dcn30_mpc_create(ctx, pool->base.mpcc_count, pool->base.res_cap->num_mpc_3dlut); - if (pool->base.mpc == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create mpc!\n"); - goto create_fail; - } - - for (i = 0; i < pool->base.res_cap->num_dsc; i++) { - pool->base.dscs[i] = dcn30_dsc_create(ctx, i); - if (pool->base.dscs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create display stream compressor %d!\n", i); - goto create_fail; - } - } - - /* DWB and MMHUBBUB */ - if (!dcn30_dwbc_create(ctx, &pool->base)) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create dwbc!\n"); - goto create_fail; - } - - if (!dcn30_mmhubbub_create(ctx, &pool->base)) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create mcif_wb!\n"); - goto create_fail; - } - - /* AUX and I2C */ - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - pool->base.engines[i] = dcn30_aux_engine_create(ctx, i); - if (pool->base.engines[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create aux engine!!\n"); - goto create_fail; - } - pool->base.hw_i2cs[i] = dcn30_i2c_hw_create(ctx, i); - if (pool->base.hw_i2cs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create hw i2c!!\n"); - goto create_fail; - } - pool->base.sw_i2cs[i] = NULL; - } - - /* Audio, Stream Encoders including DIG and virtual, MPC 3D LUTs */ - if (!resource_construct(num_virtual_links, dc, &pool->base, - &res_create_funcs)) - goto create_fail; - - /* HW Sequencer and Plane caps */ - dcn30_hw_sequencer_construct(dc); - - dc->caps.max_planes = pool->base.pipe_count; - - for (i = 0; i < dc->caps.max_planes; ++i) - dc->caps.planes[i] = plane_cap; - - 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->base.oem_device = dc->link_srv->create_ddc_service(&ddc_init_data); - } else { - pool->base.oem_device = NULL; - } - - DC_FP_END(); - - return true; - -create_fail: - - DC_FP_END(); - dcn30_resource_destruct(pool); - - return false; -} - -struct resource_pool *dcn30_create_resource_pool( - const struct dc_init_data *init_data, - struct dc *dc) -{ - struct dcn30_resource_pool *pool = - kzalloc(sizeof(struct dcn30_resource_pool), GFP_KERNEL); - - if (!pool) - return NULL; - - if (dcn30_resource_construct(init_data->num_virtual_links, dc, pool)) - return &pool->base; - - BREAK_TO_DEBUGGER(); - kfree(pool); - return 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 deleted file mode 100644 index 8e6b8b7368fdb3..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2020 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 _DCN30_RESOURCE_H_ -#define _DCN30_RESOURCE_H_ - -#include "core_types.h" - -#define TO_DCN30_RES_POOL(pool)\ - container_of(pool, struct dcn30_resource_pool, base) - -struct dc; -struct resource_pool; -struct _vcs_dpi_display_pipe_params_st; - -extern struct _vcs_dpi_ip_params_st dcn3_0_ip; -extern struct _vcs_dpi_soc_bounding_box_st dcn3_0_soc; - -struct dcn30_resource_pool { - struct resource_pool base; -}; -struct resource_pool *dcn30_create_resource_pool( - const struct dc_init_data *init_data, - struct dc *dc); - -void dcn30_set_mcif_arb_params( - struct dc *dc, - struct dc_state *context, - display_e2e_pipe_params_st *pipes, - int pipe_cnt); - -unsigned int dcn30_calc_max_scaled_time( - unsigned int time_per_pixel, - enum mmhubbub_wbif_mode mode, - unsigned int urgent_watermark); - -bool dcn30_validate_bandwidth(struct dc *dc, struct dc_state *context, - bool fast_validate); -bool dcn30_internal_validate_bw( - struct dc *dc, - struct dc_state *context, - display_e2e_pipe_params_st *pipes, - int *pipe_cnt_out, - int *vlevel_out, - 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, - int pipe_cnt, - int vlevel); -void dcn30_update_soc_for_wm_a(struct dc *dc, struct dc_state *context); -void dcn30_populate_dml_writeback_from_context( - struct dc *dc, struct resource_context *res_ctx, display_e2e_pipe_params_st *pipes); - -int dcn30_populate_dml_pipes_from_context( - struct dc *dc, struct dc_state *context, - display_e2e_pipe_params_st *pipes, - bool fast_validate); - -bool dcn30_acquire_post_bldn_3dlut( - struct resource_context *res_ctx, - const struct resource_pool *pool, - int mpcc_id, - struct dc_3dlut **lut, - struct dc_transfer_func **shaper); - -bool dcn30_release_post_bldn_3dlut( - struct resource_context *res_ctx, - const struct resource_pool *pool, - struct dc_3dlut **lut, - struct dc_transfer_func **shaper); - -enum dc_status dcn30_add_stream_to_ctx( - struct dc *dc, - struct dc_state *new_ctx, - struct dc_stream_state *dc_stream); - -void dcn30_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params); - -bool dcn30_can_support_mclk_switch_using_fw_based_vblank_stretch(struct dc *dc, struct dc_state *context); -void dcn30_setup_mclk_switch_using_fw_based_vblank_stretch(struct dc *dc, struct dc_state *context); -int dcn30_find_dummy_latency_index_for_fw_based_mclk_switch(struct dc *dc, struct dc_state *context, - display_e2e_pipe_params_st *pipes, int pipe_cnt, int vlevel); - -#endif /* _DCN30_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/Makefile b/drivers/gpu/drm/amd/display/dc/dcn301/Makefile index 30fbc5e06dcaaa..d241f665e40ac4 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn301/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn301/Makefile @@ -10,9 +10,8 @@ # # Makefile for dcn30. -DCN301 = dcn301_init.o dcn301_resource.o dcn301_dccg.o \ - dcn301_dio_link_encoder.o dcn301_panel_cntl.o dcn301_hubbub.o \ - dcn301_optc.o +DCN301 = dcn301_dccg.o \ + dcn301_dio_link_encoder.o dcn301_panel_cntl.o dcn301_hubbub.o AMD_DAL_DCN301 = $(addprefix $(AMDDALPATH)/dc/dcn301/,$(DCN301)) diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_init.c b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_init.c deleted file mode 100644 index 6477009ce0654d..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_init.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2016-2020 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 "dce110/dce110_hwseq.h" -#include "dcn10/dcn10_hwseq.h" -#include "dcn20/dcn20_hwseq.h" -#include "dcn21/dcn21_hwseq.h" -#include "dcn30/dcn30_hwseq.h" -#include "dcn301/dcn301_hwseq.h" - -#include "dcn301_init.h" - -static const struct hw_sequencer_funcs dcn301_funcs = { - .program_gamut_remap = dcn30_program_gamut_remap, - .init_hw = dcn10_init_hw, - .power_down_on_boot = dcn10_power_down_on_boot, - .apply_ctx_to_hw = dce110_apply_ctx_to_hw, - .apply_ctx_for_surface = NULL, - .program_front_end_for_ctx = dcn20_program_front_end_for_ctx, - .wait_for_pending_cleared = dcn10_wait_for_pending_cleared, - .post_unlock_program_front_end = dcn20_post_unlock_program_front_end, - .update_plane_addr = dcn20_update_plane_addr, - .update_dchub = dcn10_update_dchub, - .update_pending_status = dcn10_update_pending_status, - .program_output_csc = dcn20_program_output_csc, - .enable_accelerated_mode = dce110_enable_accelerated_mode, - .enable_timing_synchronization = dcn10_enable_timing_synchronization, - .enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset, - .update_info_frame = dcn30_update_info_frame, - .send_immediate_sdp_message = dcn10_send_immediate_sdp_message, - .enable_stream = dcn20_enable_stream, - .disable_stream = dce110_disable_stream, - .unblank_stream = dcn20_unblank_stream, -#ifdef FREESYNC_POWER_OPTIMIZE - .are_streams_coarse_grain_aligned = dcn20_are_streams_coarse_grain_aligned, -#endif - .blank_stream = dce110_blank_stream, - .enable_audio_stream = dce110_enable_audio_stream, - .disable_audio_stream = dce110_disable_audio_stream, - .disable_plane = dcn20_disable_plane, - .pipe_control_lock = dcn20_pipe_control_lock, - .interdependent_update_lock = dcn10_lock_all_pipes, - .cursor_lock = dcn10_cursor_lock, - .prepare_bandwidth = dcn20_prepare_bandwidth, - .optimize_bandwidth = dcn20_optimize_bandwidth, - .update_bandwidth = dcn20_update_bandwidth, - .set_drr = dcn10_set_drr, - .get_position = dcn10_get_position, - .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, - .get_hw_state = dcn10_get_hw_state, - .clear_status_bits = dcn10_clear_status_bits, - .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, - .edp_backlight_control = dce110_edp_backlight_control, - .edp_power_control = dce110_edp_power_control, - .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, - .set_cursor_position = dcn10_set_cursor_position, - .set_cursor_attribute = dcn10_set_cursor_attribute, - .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level, - .setup_periodic_interrupt = dcn10_setup_periodic_interrupt, - .set_clock = dcn10_set_clock, - .get_clock = dcn10_get_clock, - .program_triplebuffer = dcn20_program_triple_buffer, - .enable_writeback = dcn30_enable_writeback, - .disable_writeback = dcn30_disable_writeback, - .update_writeback = dcn30_update_writeback, - .mmhubbub_warmup = dcn30_mmhubbub_warmup, - .dmdata_status_done = dcn20_dmdata_status_done, - .program_dmdata_engine = dcn30_program_dmdata_engine, - .set_dmdata_attributes = dcn20_set_dmdata_attributes, - .init_sys_ctx = dcn20_init_sys_ctx, - .init_vm_ctx = dcn20_init_vm_ctx, - .set_flip_control_gsl = dcn20_set_flip_control_gsl, - .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync, - .calc_vupdate_position = dcn10_calc_vupdate_position, - .set_backlight_level = dcn21_set_backlight_level, - .set_abm_immediate_disable = dcn21_set_abm_immediate_disable, - .set_pipe = dcn21_set_pipe, - .enable_lvds_link_output = dce110_enable_lvds_link_output, - .enable_tmds_link_output = dce110_enable_tmds_link_output, - .enable_dp_link_output = dce110_enable_dp_link_output, - .disable_link_output = dce110_disable_link_output, - .set_disp_pattern_generator = dcn30_set_disp_pattern_generator, - .get_dcc_en_bits = dcn10_get_dcc_en_bits, - .optimize_pwr_state = dcn21_optimize_pwr_state, - .exit_optimized_pwr_state = dcn21_exit_optimized_pwr_state, - .update_visual_confirm_color = dcn10_update_visual_confirm_color, -}; - -static const struct hwseq_private_funcs dcn301_private_funcs = { - .init_pipes = dcn10_init_pipes, - .update_plane_addr = dcn20_update_plane_addr, - .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, - .update_mpcc = dcn20_update_mpcc, - .set_input_transfer_func = dcn30_set_input_transfer_func, - .set_output_transfer_func = dcn30_set_output_transfer_func, - .power_down = dce110_power_down, - .enable_display_power_gating = dcn10_dummy_display_power_gating, - .blank_pixel_data = dcn20_blank_pixel_data, - .reset_hw_ctx_wrap = dcn20_reset_hw_ctx_wrap, - .enable_stream_timing = dcn20_enable_stream_timing, - .edp_backlight_control = dce110_edp_backlight_control, - .disable_stream_gating = dcn20_disable_stream_gating, - .enable_stream_gating = dcn20_enable_stream_gating, - .setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt, - .did_underflow_occur = dcn10_did_underflow_occur, - .init_blank = dcn20_init_blank, - .disable_vga = dcn20_disable_vga, - .bios_golden_init = dcn10_bios_golden_init, - .plane_atomic_disable = dcn20_plane_atomic_disable, - .plane_atomic_power_down = dcn10_plane_atomic_power_down, - .enable_power_gating_plane = dcn20_enable_power_gating_plane, - .dpp_pg_control = dcn20_dpp_pg_control, - .hubp_pg_control = dcn20_hubp_pg_control, - .program_all_writeback_pipes_in_tree = dcn30_program_all_writeback_pipes_in_tree, - .update_odm = dcn20_update_odm, - .dsc_pg_control = dcn20_dsc_pg_control, - .set_hdr_multiplier = dcn10_set_hdr_multiplier, - .verify_allow_pstate_change_high = dcn10_verify_allow_pstate_change_high, - .wait_for_blank_complete = dcn20_wait_for_blank_complete, - .dccg_init = dcn20_dccg_init, - .set_blend_lut = dcn30_set_blend_lut, - .set_shaper_3dlut = dcn20_set_shaper_3dlut, -}; - -void dcn301_hw_sequencer_construct(struct dc *dc) -{ - dc->hwss = dcn301_funcs; - dc->hwseq->funcs = dcn301_private_funcs; -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_init.h b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_init.h deleted file mode 100644 index 0bca48ccbfa200..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_init.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2020 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_DCN30_INIT_H__ -#define __DC_DCN30_INIT_H__ - -struct dc; - -void dcn301_hw_sequencer_construct(struct dc *dc); - -#endif /* __DC_DCN30_INIT_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_optc.c b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_optc.c deleted file mode 100644 index b3cfcb8879050a..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_optc.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright 2020 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 "reg_helper.h" -#include "dcn301_optc.h" -#include "dc.h" -#include "dcn_calc_math.h" -#include "dc_dmub_srv.h" - -#include "dml/dcn30/dcn30_fpu.h" -#include "dc_trace.h" - -#define REG(reg)\ - optc1->tg_regs->reg - -#define CTX \ - optc1->base.ctx - -#undef FN -#define FN(reg_name, field_name) \ - optc1->tg_shift->field_name, optc1->tg_mask->field_name - - -/** - * optc301_set_drr() - Program dynamic refresh rate registers m_OTGx_OTG_V_TOTAL_*. - * - * @optc: timing_generator instance. - * @params: parameters used for Dynamic Refresh Rate. - */ -void optc301_set_drr( - struct timing_generator *optc, - const struct drr_params *params) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - if (params != NULL && - params->vertical_total_max > 0 && - params->vertical_total_min > 0) { - - if (params->vertical_total_mid != 0) { - - REG_SET(OTG_V_TOTAL_MID, 0, - OTG_V_TOTAL_MID, params->vertical_total_mid - 1); - - REG_UPDATE_2(OTG_V_TOTAL_CONTROL, - OTG_VTOTAL_MID_REPLACING_MAX_EN, 1, - OTG_VTOTAL_MID_FRAME_NUM, - (uint8_t)params->vertical_total_mid_frame_num); - - } - - optc->funcs->set_vtotal_min_max(optc, params->vertical_total_min - 1, params->vertical_total_max - 1); - - REG_UPDATE_5(OTG_V_TOTAL_CONTROL, - OTG_V_TOTAL_MIN_SEL, 1, - OTG_V_TOTAL_MAX_SEL, 1, - OTG_FORCE_LOCK_ON_EVENT, 0, - OTG_SET_V_TOTAL_MIN_MASK_EN, 0, - OTG_SET_V_TOTAL_MIN_MASK, 0); - // Setup manual flow control for EOF via TRIG_A - optc->funcs->setup_manual_trigger(optc); - - } else { - REG_UPDATE_4(OTG_V_TOTAL_CONTROL, - OTG_SET_V_TOTAL_MIN_MASK, 0, - OTG_V_TOTAL_MIN_SEL, 0, - OTG_V_TOTAL_MAX_SEL, 0, - OTG_FORCE_LOCK_ON_EVENT, 0); - - optc->funcs->set_vtotal_min_max(optc, 0, 0); - } -} - - -void optc301_setup_manual_trigger(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_SET_8(OTG_TRIGA_CNTL, 0, - OTG_TRIGA_SOURCE_SELECT, 21, - OTG_TRIGA_SOURCE_PIPE_SELECT, optc->inst, - OTG_TRIGA_RISING_EDGE_DETECT_CNTL, 1, - OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, 0, - OTG_TRIGA_POLARITY_SELECT, 0, - OTG_TRIGA_FREQUENCY_SELECT, 0, - OTG_TRIGA_DELAY, 0, - OTG_TRIGA_CLEAR, 1); -} - -static struct timing_generator_funcs dcn30_tg_funcs = { - .validate_timing = optc1_validate_timing, - .program_timing = optc1_program_timing, - .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0, - .setup_vertical_interrupt1 = optc1_setup_vertical_interrupt1, - .setup_vertical_interrupt2 = optc1_setup_vertical_interrupt2, - .program_global_sync = optc1_program_global_sync, - .enable_crtc = optc2_enable_crtc, - .disable_crtc = optc1_disable_crtc, - /* used by enable_timing_synchronization. Not need for FPGA */ - .is_counter_moving = optc1_is_counter_moving, - .get_position = optc1_get_position, - .get_frame_count = optc1_get_vblank_counter, - .get_scanoutpos = optc1_get_crtc_scanoutpos, - .get_otg_active_size = optc1_get_otg_active_size, - .set_early_control = optc1_set_early_control, - /* used by enable_timing_synchronization. Not need for FPGA */ - .wait_for_state = optc1_wait_for_state, - .set_blank_color = optc3_program_blank_color, - .did_triggered_reset_occur = optc1_did_triggered_reset_occur, - .triplebuffer_lock = optc3_triplebuffer_lock, - .triplebuffer_unlock = optc2_triplebuffer_unlock, - .enable_reset_trigger = optc1_enable_reset_trigger, - .enable_crtc_reset = optc1_enable_crtc_reset, - .disable_reset_trigger = optc1_disable_reset_trigger, - .lock = optc3_lock, - .unlock = optc1_unlock, - .lock_doublebuffer_enable = optc3_lock_doublebuffer_enable, - .lock_doublebuffer_disable = optc3_lock_doublebuffer_disable, - .enable_optc_clock = optc1_enable_optc_clock, - .set_drr = optc301_set_drr, - .get_last_used_drr_vtotal = optc2_get_last_used_drr_vtotal, - .set_vtotal_min_max = optc3_set_vtotal_min_max, - .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, - .is_tg_enabled = optc1_is_tg_enabled, - .is_optc_underflow_occurred = optc1_is_optc_underflow_occurred, - .clear_optc_underflow = optc1_clear_optc_underflow, - .setup_global_swap_lock = NULL, - .get_crc = optc1_get_crc, - .configure_crc = optc2_configure_crc, - .set_dsc_config = optc3_set_dsc_config, - .get_dsc_status = optc2_get_dsc_status, - .set_dwb_source = NULL, - .set_odm_bypass = optc3_set_odm_bypass, - .set_odm_combine = optc3_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, - .set_vtotal_change_limit = optc3_set_vtotal_change_limit, - .set_gsl = optc2_set_gsl, - .set_gsl_source_select = optc2_set_gsl_source_select, - .set_vtg_params = optc1_set_vtg_params, - .program_manual_trigger = optc2_program_manual_trigger, - .setup_manual_trigger = optc301_setup_manual_trigger, - .get_hw_timing = optc1_get_hw_timing, - .wait_drr_doublebuffer_pending_clear = optc3_wait_drr_doublebuffer_pending_clear, -}; - -void dcn301_timing_generator_init(struct optc *optc1) -{ - optc1->base.funcs = &dcn30_tg_funcs; - - optc1->max_h_total = optc1->tg_mask->OTG_H_TOTAL + 1; - optc1->max_v_total = optc1->tg_mask->OTG_V_TOTAL + 1; - - optc1->min_h_blank = 32; - optc1->min_v_blank = 3; - optc1->min_v_blank_interlace = 5; - optc1->min_h_sync_width = 4; - optc1->min_v_sync_width = 1; -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_optc.h b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_optc.h deleted file mode 100644 index b49585682a1599..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_optc.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2020 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_OPTC_DCN301_H__ -#define __DC_OPTC_DCN301_H__ - -#include "dcn20/dcn20_optc.h" -#include "dcn30/dcn30_optc.h" - -void dcn301_timing_generator_init(struct optc *optc1); -void optc301_setup_manual_trigger(struct timing_generator *optc); -void optc301_set_drr(struct timing_generator *optc, const struct drr_params *params); - -#endif /* __DC_OPTC_DCN301_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 deleted file mode 100644 index f3b75f283aa257..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c +++ /dev/null @@ -1,1728 +0,0 @@ -/* - * Copyright 2019-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 "dm_services.h" -#include "dc.h" - -#include "dcn301_init.h" - -#include "resource.h" -#include "include/irq_service_interface.h" -#include "dcn30/dcn30_resource.h" -#include "dcn301_resource.h" - -#include "dcn20/dcn20_resource.h" - -#include "dcn10/dcn10_ipp.h" -#include "dcn301/dcn301_hubbub.h" -#include "dcn30/dcn30_mpc.h" -#include "dcn30/dcn30_hubp.h" -#include "irq/dcn30/irq_service_dcn30.h" -#include "dcn30/dcn30_dpp.h" -#include "dcn301/dcn301_optc.h" -#include "dcn20/dcn20_hwseq.h" -#include "dcn30/dcn30_hwseq.h" -#include "dce110/dce110_hwseq.h" -#include "dcn30/dcn30_opp.h" -#include "dcn20/dcn20_dsc.h" -#include "dcn30/dcn30_vpg.h" -#include "dcn30/dcn30_afmt.h" -#include "dce/dce_clock_source.h" -#include "dce/dce_audio.h" -#include "dce/dce_hwseq.h" -#include "clk_mgr.h" -#include "virtual/virtual_stream_encoder.h" -#include "dce110/dce110_resource.h" -#include "dml/display_mode_vba.h" -#include "dcn301/dcn301_dccg.h" -#include "dcn10/dcn10_resource.h" -#include "dcn30/dcn30_dio_stream_encoder.h" -#include "dcn301/dcn301_dio_link_encoder.h" -#include "dcn301_panel_cntl.h" - -#include "vangogh_ip_offset.h" - -#include "dcn30/dcn30_dwb.h" -#include "dcn30/dcn30_mmhubbub.h" - -#include "dcn/dcn_3_0_1_offset.h" -#include "dcn/dcn_3_0_1_sh_mask.h" - -#include "nbio/nbio_7_2_0_offset.h" - -#include "dpcs/dpcs_3_0_0_offset.h" -#include "dpcs/dpcs_3_0_0_sh_mask.h" - -#include "reg_helper.h" -#include "dce/dmub_abm.h" -#include "dce/dce_aux.h" -#include "dce/dce_i2c.h" - -#include "dml/dcn30/dcn30_fpu.h" - -#include "dml/dcn30/display_mode_vba_30.h" -#include "dml/dcn301/dcn301_fpu.h" -#include "vm_helper.h" -#include "dcn20/dcn20_vmid.h" -#include "amdgpu_socbb.h" - -#define TO_DCN301_RES_POOL(pool)\ - container_of(pool, struct dcn301_resource_pool, base) - -#define DC_LOGGER \ - dc->ctx->logger -#define DC_LOGGER_INIT(logger) - -enum dcn301_clk_src_array_id { - DCN301_CLK_SRC_PLL0, - DCN301_CLK_SRC_PLL1, - DCN301_CLK_SRC_PLL2, - DCN301_CLK_SRC_PLL3, - DCN301_CLK_SRC_TOTAL -}; - -/* begin ********************* - * macros to expend register list macro defined in HW object header file - */ - -/* DCN */ -#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg - -#define BASE(seg) BASE_INNER(seg) - -#define SR(reg_name)\ - .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + \ - mm ## reg_name - -#define SRI(reg_name, block, id)\ - .reg_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name - -#define SRI2(reg_name, block, id)\ - .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + \ - mm ## reg_name - -#define SRIR(var_name, reg_name, block, id)\ - .var_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name - -#define SRII(reg_name, block, id)\ - .reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name - -#define SRII2(reg_name_pre, reg_name_post, id)\ - .reg_name_pre ## _ ## reg_name_post[id] = BASE(mm ## reg_name_pre \ - ## id ## _ ## reg_name_post ## _BASE_IDX) + \ - mm ## reg_name_pre ## id ## _ ## reg_name_post - -#define SRII_MPC_RMU(reg_name, block, id)\ - .RMU##_##reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name - -#define SRII_DWB(reg_name, temp_name, block, id)\ - .reg_name[id] = BASE(mm ## block ## id ## _ ## temp_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## temp_name - -#define SF_DWB2(reg_name, block, id, field_name, post_fix) \ - .field_name = reg_name ## __ ## field_name ## post_fix - -#define DCCG_SRII(reg_name, block, id)\ - .block ## _ ## reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name - -#define VUPDATE_SRII(reg_name, block, id)\ - .reg_name[id] = BASE(mm ## reg_name ## _ ## block ## id ## _BASE_IDX) + \ - mm ## reg_name ## _ ## block ## id - -/* NBIO */ -#define NBIO_BASE_INNER(seg) \ - NBIO_BASE__INST0_SEG ## seg - -#define NBIO_BASE(seg) \ - NBIO_BASE_INNER(seg) - -#define NBIO_SR(reg_name)\ - .reg_name = NBIO_BASE(regBIF_BX0_ ## reg_name ## _BASE_IDX) + \ - regBIF_BX0_ ## reg_name - -/* MMHUB */ -#define MMHUB_BASE_INNER(seg) \ - MMHUB_BASE__INST0_SEG ## seg - -#define MMHUB_BASE(seg) \ - MMHUB_BASE_INNER(seg) - -#define MMHUB_SR(reg_name)\ - .reg_name = MMHUB_BASE(regMM ## reg_name ## _BASE_IDX) + \ - regMM ## reg_name - -/* CLOCK */ -#define CLK_BASE_INNER(seg) \ - CLK_BASE__INST0_SEG ## seg - -#define CLK_BASE(seg) \ - CLK_BASE_INNER(seg) - -#define CLK_SRI(reg_name, block, inst)\ - .reg_name = CLK_BASE(mm ## block ## _ ## inst ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## _ ## inst ## _ ## reg_name - -static const struct bios_registers bios_regs = { - NBIO_SR(BIOS_SCRATCH_3), - NBIO_SR(BIOS_SCRATCH_6) -}; - -#define clk_src_regs(index, pllid)\ -[index] = {\ - CS_COMMON_REG_LIST_DCN3_01(index, pllid),\ -} - -static const struct dce110_clk_src_regs clk_src_regs[] = { - clk_src_regs(0, A), - clk_src_regs(1, B), - clk_src_regs(2, C), - clk_src_regs(3, D) -}; - -static const struct dce110_clk_src_shift cs_shift = { - CS_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) -}; - -static const struct dce110_clk_src_mask cs_mask = { - CS_COMMON_MASK_SH_LIST_DCN2_0(_MASK) -}; - -#define abm_regs(id)\ -[id] = {\ - ABM_DCN301_REG_LIST(id)\ -} - -static const struct dce_abm_registers abm_regs[] = { - abm_regs(0), - abm_regs(1), - abm_regs(2), - abm_regs(3), -}; - -static const struct dce_abm_shift abm_shift = { - ABM_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dce_abm_mask abm_mask = { - ABM_MASK_SH_LIST_DCN30(_MASK) -}; - -#define audio_regs(id)\ -[id] = {\ - AUD_COMMON_REG_LIST(id)\ -} - -static const struct dce_audio_registers audio_regs[] = { - audio_regs(0), - audio_regs(1), - audio_regs(2), - audio_regs(3), - audio_regs(4), - audio_regs(5), - audio_regs(6) -}; - -#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ - SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ - SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ - AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) - -static const struct dce_audio_shift audio_shift = { - DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_audio_mask audio_mask = { - DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) -}; - -#define vpg_regs(id)\ -[id] = {\ - VPG_DCN3_REG_LIST(id)\ -} - -static const struct dcn30_vpg_registers vpg_regs[] = { - vpg_regs(0), - vpg_regs(1), - vpg_regs(2), - vpg_regs(3), -}; - -static const struct dcn30_vpg_shift vpg_shift = { - DCN3_VPG_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn30_vpg_mask vpg_mask = { - DCN3_VPG_MASK_SH_LIST(_MASK) -}; - -#define afmt_regs(id)\ -[id] = {\ - AFMT_DCN3_REG_LIST(id)\ -} - -static const struct dcn30_afmt_registers afmt_regs[] = { - afmt_regs(0), - afmt_regs(1), - afmt_regs(2), - afmt_regs(3), -}; - -static const struct dcn30_afmt_shift afmt_shift = { - DCN3_AFMT_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn30_afmt_mask afmt_mask = { - DCN3_AFMT_MASK_SH_LIST(_MASK) -}; - -#define stream_enc_regs(id)\ -[id] = {\ - SE_DCN3_REG_LIST(id)\ -} - -static const struct dcn10_stream_enc_registers stream_enc_regs[] = { - stream_enc_regs(0), - stream_enc_regs(1), - stream_enc_regs(2), - stream_enc_regs(3), -}; - -static const struct dcn10_stream_encoder_shift se_shift = { - SE_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn10_stream_encoder_mask se_mask = { - SE_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - - -#define aux_regs(id)\ -[id] = {\ - DCN2_AUX_REG_LIST(id)\ -} - -static const struct dcn10_link_enc_aux_registers link_enc_aux_regs[] = { - aux_regs(0), - aux_regs(1), - aux_regs(2), - aux_regs(3), -}; - -#define hpd_regs(id)\ -[id] = {\ - HPD_REG_LIST(id)\ -} - -static const struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[] = { - hpd_regs(0), - hpd_regs(1), - hpd_regs(2), - hpd_regs(3), -}; - - -#define link_regs(id, phyid)\ -[id] = {\ - LE_DCN301_REG_LIST(id), \ - UNIPHY_DCN2_REG_LIST(phyid), \ - DPCS_DCN2_REG_LIST(id), \ - SRI(DP_DPHY_INTERNAL_CTRL, DP, id) \ -} - -static const struct dce110_aux_registers_shift aux_shift = { - DCN_AUX_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce110_aux_registers_mask aux_mask = { - DCN_AUX_MASK_SH_LIST(_MASK) -}; - -static const struct dcn10_link_enc_registers link_enc_regs[] = { - link_regs(0, A), - link_regs(1, B), - link_regs(2, C), - link_regs(3, D), -}; - -static const struct dcn10_link_enc_shift le_shift = { - LINK_ENCODER_MASK_SH_LIST_DCN301(__SHIFT),\ - DPCS_DCN2_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn10_link_enc_mask le_mask = { - LINK_ENCODER_MASK_SH_LIST_DCN301(_MASK),\ - DPCS_DCN2_MASK_SH_LIST(_MASK) -}; - -#define panel_cntl_regs(id)\ -[id] = {\ - DCN301_PANEL_CNTL_REG_LIST(id),\ -} - -static const struct dce_panel_cntl_registers panel_cntl_regs[] = { - panel_cntl_regs(0), - panel_cntl_regs(1), -}; - -static const struct dcn301_panel_cntl_shift panel_cntl_shift = { - DCN301_PANEL_CNTL_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn301_panel_cntl_mask panel_cntl_mask = { - DCN301_PANEL_CNTL_MASK_SH_LIST(_MASK) -}; - -#define dpp_regs(id)\ -[id] = {\ - DPP_REG_LIST_DCN30(id),\ -} - -static const struct dcn3_dpp_registers dpp_regs[] = { - dpp_regs(0), - dpp_regs(1), - dpp_regs(2), - dpp_regs(3), -}; - -static const struct dcn3_dpp_shift tf_shift = { - DPP_REG_LIST_SH_MASK_DCN30(__SHIFT) -}; - -static const struct dcn3_dpp_mask tf_mask = { - DPP_REG_LIST_SH_MASK_DCN30(_MASK) -}; - -#define opp_regs(id)\ -[id] = {\ - OPP_REG_LIST_DCN30(id),\ -} - -static const struct dcn20_opp_registers opp_regs[] = { - opp_regs(0), - opp_regs(1), - opp_regs(2), - opp_regs(3), -}; - -static const struct dcn20_opp_shift opp_shift = { - OPP_MASK_SH_LIST_DCN20(__SHIFT) -}; - -static const struct dcn20_opp_mask opp_mask = { - OPP_MASK_SH_LIST_DCN20(_MASK) -}; - -#define aux_engine_regs(id)\ -[id] = {\ - AUX_COMMON_REG_LIST0(id), \ - .AUXN_IMPCAL = 0, \ - .AUXP_IMPCAL = 0, \ - .AUX_RESET_MASK = DP_AUX0_AUX_CONTROL__AUX_RESET_MASK, \ -} - -static const struct dce110_aux_registers aux_engine_regs[] = { - aux_engine_regs(0), - aux_engine_regs(1), - aux_engine_regs(2), - aux_engine_regs(3), -}; - -#define dwbc_regs_dcn3(id)\ -[id] = {\ - DWBC_COMMON_REG_LIST_DCN30(id),\ -} - -static const struct dcn30_dwbc_registers dwbc30_regs[] = { - dwbc_regs_dcn3(0), -}; - -static const struct dcn30_dwbc_shift dwbc30_shift = { - DWBC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn30_dwbc_mask dwbc30_mask = { - DWBC_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -#define mcif_wb_regs_dcn3(id)\ -[id] = {\ - MCIF_WB_COMMON_REG_LIST_DCN30(id),\ -} - -static const struct dcn30_mmhubbub_registers mcif_wb30_regs[] = { - mcif_wb_regs_dcn3(0) -}; - -static const struct dcn30_mmhubbub_shift mcif_wb30_shift = { - MCIF_WB_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn30_mmhubbub_mask mcif_wb30_mask = { - MCIF_WB_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -#define dsc_regsDCN20(id)\ -[id] = {\ - DSC_REG_LIST_DCN20(id)\ -} - -static const struct dcn20_dsc_registers dsc_regs[] = { - dsc_regsDCN20(0), - dsc_regsDCN20(1), - dsc_regsDCN20(2), -}; - -static const struct dcn20_dsc_shift dsc_shift = { - DSC_REG_LIST_SH_MASK_DCN20(__SHIFT) -}; - -static const struct dcn20_dsc_mask dsc_mask = { - DSC_REG_LIST_SH_MASK_DCN20(_MASK) -}; - -static const struct dcn30_mpc_registers mpc_regs = { - MPC_REG_LIST_DCN3_0(0), - MPC_REG_LIST_DCN3_0(1), - MPC_REG_LIST_DCN3_0(2), - MPC_REG_LIST_DCN3_0(3), - MPC_OUT_MUX_REG_LIST_DCN3_0(0), - MPC_OUT_MUX_REG_LIST_DCN3_0(1), - MPC_OUT_MUX_REG_LIST_DCN3_0(2), - MPC_OUT_MUX_REG_LIST_DCN3_0(3), - MPC_RMU_GLOBAL_REG_LIST_DCN3AG, - MPC_RMU_REG_LIST_DCN3AG(0), - MPC_RMU_REG_LIST_DCN3AG(1), - MPC_DWB_MUX_REG_LIST_DCN3_0(0), -}; - -static const struct dcn30_mpc_shift mpc_shift = { - MPC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn30_mpc_mask mpc_mask = { - MPC_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -#define optc_regs(id)\ -[id] = {OPTC_COMMON_REG_LIST_DCN3_0(id)} - - -static const struct dcn_optc_registers optc_regs[] = { - optc_regs(0), - optc_regs(1), - optc_regs(2), - optc_regs(3), -}; - -static const struct dcn_optc_shift optc_shift = { - OPTC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn_optc_mask optc_mask = { - OPTC_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -#define hubp_regs(id)\ -[id] = {\ - HUBP_REG_LIST_DCN30(id)\ -} - -static const struct dcn_hubp2_registers hubp_regs[] = { - hubp_regs(0), - hubp_regs(1), - hubp_regs(2), - hubp_regs(3), -}; - -static const struct dcn_hubp2_shift hubp_shift = { - HUBP_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn_hubp2_mask hubp_mask = { - HUBP_MASK_SH_LIST_DCN30(_MASK) -}; - -static const struct dcn_hubbub_registers hubbub_reg = { - HUBBUB_REG_LIST_DCN301(0) -}; - -static const struct dcn_hubbub_shift hubbub_shift = { - HUBBUB_MASK_SH_LIST_DCN301(__SHIFT) -}; - -static const struct dcn_hubbub_mask hubbub_mask = { - HUBBUB_MASK_SH_LIST_DCN301(_MASK) -}; - -static const struct dccg_registers dccg_regs = { - DCCG_REG_LIST_DCN301() -}; - -static const struct dccg_shift dccg_shift = { - DCCG_MASK_SH_LIST_DCN301(__SHIFT) -}; - -static const struct dccg_mask dccg_mask = { - DCCG_MASK_SH_LIST_DCN301(_MASK) -}; - -static const struct dce_hwseq_registers hwseq_reg = { - HWSEQ_DCN301_REG_LIST() -}; - -static const struct dce_hwseq_shift hwseq_shift = { - HWSEQ_DCN301_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_hwseq_mask hwseq_mask = { - HWSEQ_DCN301_MASK_SH_LIST(_MASK) -}; -#define vmid_regs(id)\ -[id] = {\ - DCN20_VMID_REG_LIST(id)\ -} - -static const struct dcn_vmid_registers vmid_regs[] = { - vmid_regs(0), - vmid_regs(1), - vmid_regs(2), - vmid_regs(3), - vmid_regs(4), - vmid_regs(5), - vmid_regs(6), - vmid_regs(7), - vmid_regs(8), - vmid_regs(9), - vmid_regs(10), - vmid_regs(11), - vmid_regs(12), - vmid_regs(13), - vmid_regs(14), - vmid_regs(15) -}; - -static const struct dcn20_vmid_shift vmid_shifts = { - DCN20_VMID_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn20_vmid_mask vmid_masks = { - DCN20_VMID_MASK_SH_LIST(_MASK) -}; - -static struct resource_caps res_cap_dcn301 = { - .num_timing_generator = 4, - .num_opp = 4, - .num_video_plane = 4, - .num_audio = 4, - .num_stream_encoder = 4, - .num_pll = 4, - .num_dwb = 1, - .num_ddc = 4, - .num_vmid = 16, - .num_mpc_3dlut = 2, - .num_dsc = 3, -}; - -static const struct dc_plane_cap plane_cap = { - .type = DC_PLANE_TYPE_DCN_UNIVERSAL, - .per_pixel_alpha = true, - - .pixel_format_support = { - .argb8888 = true, - .nv12 = true, - .fp16 = true, - .p010 = true, - .ayuv = false, - }, - - .max_upscale_factor = { - .argb8888 = 16000, - .nv12 = 16000, - .fp16 = 16000 - }, - - /* 6:1 downscaling ratio: 1000/6 = 166.666 */ - .max_downscale_factor = { - .argb8888 = 167, - .nv12 = 167, - .fp16 = 167 - }, - 64, - 64 -}; - -static const struct dc_debug_options debug_defaults_drv = { - .disable_dmcu = true, - .force_abm_enable = false, - .timing_trace = false, - .clock_trace = true, - .disable_dpp_power_gate = false, - .disable_hubp_power_gate = false, - .disable_clock_gate = true, - .disable_pplib_clock_request = true, - .disable_pplib_wm_range = true, - .pipe_split_policy = MPC_SPLIT_DYNAMIC, - .force_single_disp_pipe_split = false, - .disable_dcc = DCC_ENABLE, - .vsr_support = true, - .performance_trace = false, - .max_downscale_src_width = 7680,/*upto 8K*/ - .scl_reset_length10 = true, - .sanity_checks = false, - .underflow_assert_delay_us = 0xFFFFFFFF, - .dwb_fi_phase = -1, // -1 = disable - .dmub_command_table = true, - .use_max_lb = false, - .exit_idle_opt_for_cursor_updates = true, - .using_dml2 = false, -}; - -static void dcn301_dpp_destroy(struct dpp **dpp) -{ - kfree(TO_DCN20_DPP(*dpp)); - *dpp = NULL; -} - -static struct dpp *dcn301_dpp_create(struct dc_context *ctx, uint32_t inst) -{ - struct dcn3_dpp *dpp = - kzalloc(sizeof(struct dcn3_dpp), GFP_KERNEL); - - if (!dpp) - return NULL; - - if (dpp3_construct(dpp, ctx, inst, - &dpp_regs[inst], &tf_shift, &tf_mask)) - return &dpp->base; - - BREAK_TO_DEBUGGER(); - kfree(dpp); - return NULL; -} -static struct output_pixel_processor *dcn301_opp_create(struct dc_context *ctx, - uint32_t inst) -{ - struct dcn20_opp *opp = - kzalloc(sizeof(struct dcn20_opp), GFP_KERNEL); - - if (!opp) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dcn20_opp_construct(opp, ctx, inst, - &opp_regs[inst], &opp_shift, &opp_mask); - return &opp->base; -} - -static struct dce_aux *dcn301_aux_engine_create(struct dc_context *ctx, uint32_t inst) -{ - struct aux_engine_dce110 *aux_engine = - kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); - - if (!aux_engine) - return NULL; - - dce110_aux_engine_construct(aux_engine, ctx, inst, - SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, - &aux_engine_regs[inst], - &aux_mask, - &aux_shift, - ctx->dc->caps.extended_aux_timeout_support); - - return &aux_engine->base; -} -#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST(id) } - -static const struct dce_i2c_registers i2c_hw_regs[] = { - i2c_inst_regs(1), - i2c_inst_regs(2), - i2c_inst_regs(3), - i2c_inst_regs(4), -}; - -static const struct dce_i2c_shift i2c_shifts = { - I2C_COMMON_MASK_SH_LIST_DCN2(__SHIFT) -}; - -static const struct dce_i2c_mask i2c_masks = { - I2C_COMMON_MASK_SH_LIST_DCN2(_MASK) -}; - -static struct dce_i2c_hw *dcn301_i2c_hw_create(struct dc_context *ctx, uint32_t inst) -{ - struct dce_i2c_hw *dce_i2c_hw = - kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); - - if (!dce_i2c_hw) - return NULL; - - dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst, - &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); - - return dce_i2c_hw; -} -static struct mpc *dcn301_mpc_create( - struct dc_context *ctx, - int num_mpcc, - int num_rmu) -{ - struct dcn30_mpc *mpc30 = kzalloc(sizeof(struct dcn30_mpc), - GFP_KERNEL); - - if (!mpc30) - return NULL; - - dcn30_mpc_construct(mpc30, ctx, - &mpc_regs, - &mpc_shift, - &mpc_mask, - num_mpcc, - num_rmu); - - return &mpc30->base; -} - -static struct hubbub *dcn301_hubbub_create(struct dc_context *ctx) -{ - int i; - - struct dcn20_hubbub *hubbub3 = kzalloc(sizeof(struct dcn20_hubbub), - GFP_KERNEL); - - if (!hubbub3) - return NULL; - - hubbub301_construct(hubbub3, ctx, - &hubbub_reg, - &hubbub_shift, - &hubbub_mask); - - - for (i = 0; i < res_cap_dcn301.num_vmid; i++) { - struct dcn20_vmid *vmid = &hubbub3->vmid[i]; - - vmid->ctx = ctx; - - vmid->regs = &vmid_regs[i]; - vmid->shifts = &vmid_shifts; - vmid->masks = &vmid_masks; - } - - hubbub3->num_vmid = res_cap_dcn301.num_vmid; - - return &hubbub3->base; -} - -static struct timing_generator *dcn301_timing_generator_create( - struct dc_context *ctx, uint32_t instance) -{ - struct optc *tgn10 = - kzalloc(sizeof(struct optc), GFP_KERNEL); - - if (!tgn10) - return NULL; - - tgn10->base.inst = instance; - tgn10->base.ctx = ctx; - - tgn10->tg_regs = &optc_regs[instance]; - tgn10->tg_shift = &optc_shift; - tgn10->tg_mask = &optc_mask; - - dcn301_timing_generator_init(tgn10); - - return &tgn10->base; -} - -static const struct encoder_feature_support link_enc_feature = { - .max_hdmi_deep_color = COLOR_DEPTH_121212, - .max_hdmi_pixel_clock = 600000, - .hdmi_ycbcr420_supported = true, - .dp_ycbcr420_supported = true, - .fec_supported = true, - .flags.bits.IS_HBR2_CAPABLE = true, - .flags.bits.IS_HBR3_CAPABLE = true, - .flags.bits.IS_TPS3_CAPABLE = true, - .flags.bits.IS_TPS4_CAPABLE = true -}; - -static struct link_encoder *dcn301_link_encoder_create( - struct dc_context *ctx, - const struct encoder_init_data *enc_init_data) -{ - struct dcn20_link_encoder *enc20 = - kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); - - if (!enc20) - return NULL; - - dcn301_link_encoder_construct(enc20, - enc_init_data, - &link_enc_feature, - &link_enc_regs[enc_init_data->transmitter], - &link_enc_aux_regs[enc_init_data->channel - 1], - &link_enc_hpd_regs[enc_init_data->hpd_source], - &le_shift, - &le_mask); - - return &enc20->enc10.base; -} - -static struct panel_cntl *dcn301_panel_cntl_create(const struct panel_cntl_init_data *init_data) -{ - struct dcn301_panel_cntl *panel_cntl = - kzalloc(sizeof(struct dcn301_panel_cntl), GFP_KERNEL); - - if (!panel_cntl) - return NULL; - - dcn301_panel_cntl_construct(panel_cntl, - init_data, - &panel_cntl_regs[init_data->inst], - &panel_cntl_shift, - &panel_cntl_mask); - - return &panel_cntl->base; -} - - -#define CTX ctx - -#define REG(reg_name) \ - (DCN_BASE.instance[0].segment[mm ## reg_name ## _BASE_IDX] + mm ## reg_name) - -static uint32_t read_pipe_fuses(struct dc_context *ctx) -{ - uint32_t value = REG_READ(CC_DC_PIPE_DIS); - /* RV1 support max 4 pipes */ - value = value & 0xf; - return value; -} - - -static void read_dce_straps( - struct dc_context *ctx, - struct resource_straps *straps) -{ - generic_reg_get(ctx, mmDC_PINSTRAPS + BASE(mmDC_PINSTRAPS_BASE_IDX), - FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio); - -} - -static struct audio *dcn301_create_audio( - struct dc_context *ctx, unsigned int inst) -{ - return dce_audio_create(ctx, inst, - &audio_regs[inst], &audio_shift, &audio_mask); -} - -static struct vpg *dcn301_vpg_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn30_vpg *vpg3 = kzalloc(sizeof(struct dcn30_vpg), GFP_KERNEL); - - if (!vpg3) - return NULL; - - vpg3_construct(vpg3, ctx, inst, - &vpg_regs[inst], - &vpg_shift, - &vpg_mask); - - return &vpg3->base; -} - -static struct afmt *dcn301_afmt_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn30_afmt *afmt3 = kzalloc(sizeof(struct dcn30_afmt), GFP_KERNEL); - - if (!afmt3) - return NULL; - - afmt3_construct(afmt3, ctx, inst, - &afmt_regs[inst], - &afmt_shift, - &afmt_mask); - - return &afmt3->base; -} - -static struct stream_encoder *dcn301_stream_encoder_create(enum engine_id eng_id, - struct dc_context *ctx) -{ - struct dcn10_stream_encoder *enc1; - struct vpg *vpg; - struct afmt *afmt; - int vpg_inst; - int afmt_inst; - - /* Mapping of VPG, AFMT, DME register blocks to DIO block instance */ - if (eng_id <= ENGINE_ID_DIGF) { - vpg_inst = eng_id; - afmt_inst = eng_id; - } else - return NULL; - - enc1 = kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL); - vpg = dcn301_vpg_create(ctx, vpg_inst); - afmt = dcn301_afmt_create(ctx, afmt_inst); - - if (!enc1 || !vpg || !afmt) { - kfree(enc1); - kfree(vpg); - kfree(afmt); - return NULL; - } - - dcn30_dio_stream_encoder_construct(enc1, ctx, ctx->dc_bios, - eng_id, vpg, afmt, - &stream_enc_regs[eng_id], - &se_shift, &se_mask); - - return &enc1->base; -} - -static struct dce_hwseq *dcn301_hwseq_create(struct dc_context *ctx) -{ - struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); - - if (hws) { - hws->ctx = ctx; - hws->regs = &hwseq_reg; - hws->shifts = &hwseq_shift; - hws->masks = &hwseq_mask; - } - return hws; -} -static const struct resource_create_funcs res_create_funcs = { - .read_dce_straps = read_dce_straps, - .create_audio = dcn301_create_audio, - .create_stream_encoder = dcn301_stream_encoder_create, - .create_hwseq = dcn301_hwseq_create, -}; - -static void dcn301_destruct(struct dcn301_resource_pool *pool) -{ - unsigned int i; - - for (i = 0; i < pool->base.stream_enc_count; i++) { - if (pool->base.stream_enc[i] != NULL) { - if (pool->base.stream_enc[i]->vpg != NULL) { - kfree(DCN30_VPG_FROM_VPG(pool->base.stream_enc[i]->vpg)); - pool->base.stream_enc[i]->vpg = NULL; - } - if (pool->base.stream_enc[i]->afmt != NULL) { - kfree(DCN30_AFMT_FROM_AFMT(pool->base.stream_enc[i]->afmt)); - pool->base.stream_enc[i]->afmt = NULL; - } - kfree(DCN10STRENC_FROM_STRENC(pool->base.stream_enc[i])); - pool->base.stream_enc[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_dsc; i++) { - if (pool->base.dscs[i] != NULL) - dcn20_dsc_destroy(&pool->base.dscs[i]); - } - - if (pool->base.mpc != NULL) { - kfree(TO_DCN20_MPC(pool->base.mpc)); - pool->base.mpc = NULL; - } - if (pool->base.hubbub != NULL) { - kfree(pool->base.hubbub); - pool->base.hubbub = NULL; - } - for (i = 0; i < pool->base.pipe_count; i++) { - if (pool->base.dpps[i] != NULL) - dcn301_dpp_destroy(&pool->base.dpps[i]); - - if (pool->base.ipps[i] != NULL) - pool->base.ipps[i]->funcs->ipp_destroy(&pool->base.ipps[i]); - - if (pool->base.hubps[i] != NULL) { - kfree(TO_DCN20_HUBP(pool->base.hubps[i])); - pool->base.hubps[i] = NULL; - } - - if (pool->base.irqs != NULL) { - dal_irq_service_destroy(&pool->base.irqs); - } - } - - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - if (pool->base.engines[i] != NULL) - dce110_engine_destroy(&pool->base.engines[i]); - if (pool->base.hw_i2cs[i] != NULL) { - kfree(pool->base.hw_i2cs[i]); - pool->base.hw_i2cs[i] = NULL; - } - if (pool->base.sw_i2cs[i] != NULL) { - kfree(pool->base.sw_i2cs[i]); - pool->base.sw_i2cs[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_opp; i++) { - if (pool->base.opps[i] != NULL) - pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]); - } - - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - if (pool->base.timing_generators[i] != NULL) { - kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i])); - pool->base.timing_generators[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_dwb; i++) { - if (pool->base.dwbc[i] != NULL) { - kfree(TO_DCN30_DWBC(pool->base.dwbc[i])); - pool->base.dwbc[i] = NULL; - } - if (pool->base.mcif_wb[i] != NULL) { - kfree(TO_DCN30_MMHUBBUB(pool->base.mcif_wb[i])); - pool->base.mcif_wb[i] = NULL; - } - } - - for (i = 0; i < pool->base.audio_count; i++) { - if (pool->base.audios[i]) - dce_aud_destroy(&pool->base.audios[i]); - } - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] != NULL) { - dcn20_clock_source_destroy(&pool->base.clock_sources[i]); - pool->base.clock_sources[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_mpc_3dlut; i++) { - if (pool->base.mpc_lut[i] != NULL) { - dc_3dlut_func_release(pool->base.mpc_lut[i]); - pool->base.mpc_lut[i] = NULL; - } - if (pool->base.mpc_shaper[i] != NULL) { - dc_transfer_func_release(pool->base.mpc_shaper[i]); - pool->base.mpc_shaper[i] = NULL; - } - } - - if (pool->base.dp_clock_source != NULL) { - dcn20_clock_source_destroy(&pool->base.dp_clock_source); - pool->base.dp_clock_source = NULL; - } - - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - if (pool->base.multiple_abms[i] != NULL) - dce_abm_destroy(&pool->base.multiple_abms[i]); - } - - if (pool->base.dccg != NULL) - dcn_dccg_destroy(&pool->base.dccg); -} - -static struct hubp *dcn301_hubp_create(struct dc_context *ctx, uint32_t inst) -{ - struct dcn20_hubp *hubp2 = - kzalloc(sizeof(struct dcn20_hubp), GFP_KERNEL); - - if (!hubp2) - return NULL; - - if (hubp3_construct(hubp2, ctx, inst, - &hubp_regs[inst], &hubp_shift, &hubp_mask)) - return &hubp2->base; - - BREAK_TO_DEBUGGER(); - kfree(hubp2); - return NULL; -} - -static bool dcn301_dwbc_create(struct dc_context *ctx, struct resource_pool *pool) -{ - int i; - uint32_t pipe_count = pool->res_cap->num_dwb; - - for (i = 0; i < pipe_count; i++) { - struct dcn30_dwbc *dwbc30 = kzalloc(sizeof(struct dcn30_dwbc), - GFP_KERNEL); - - if (!dwbc30) { - dm_error("DC: failed to create dwbc30!\n"); - return false; - } - - dcn30_dwbc_construct(dwbc30, ctx, - &dwbc30_regs[i], - &dwbc30_shift, - &dwbc30_mask, - i); - - pool->dwbc[i] = &dwbc30->base; - } - return true; -} - -static bool dcn301_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool) -{ - int i; - uint32_t pipe_count = pool->res_cap->num_dwb; - - for (i = 0; i < pipe_count; i++) { - struct dcn30_mmhubbub *mcif_wb30 = kzalloc(sizeof(struct dcn30_mmhubbub), - GFP_KERNEL); - - if (!mcif_wb30) { - dm_error("DC: failed to create mcif_wb30!\n"); - return false; - } - - dcn30_mmhubbub_construct(mcif_wb30, ctx, - &mcif_wb30_regs[i], - &mcif_wb30_shift, - &mcif_wb30_mask, - i); - - pool->mcif_wb[i] = &mcif_wb30->base; - } - return true; -} - -static struct display_stream_compressor *dcn301_dsc_create( - struct dc_context *ctx, uint32_t inst) -{ - struct dcn20_dsc *dsc = - kzalloc(sizeof(struct dcn20_dsc), GFP_KERNEL); - - if (!dsc) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dsc2_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask); - return &dsc->base; -} - - -static void dcn301_destroy_resource_pool(struct resource_pool **pool) -{ - struct dcn301_resource_pool *dcn301_pool = TO_DCN301_RES_POOL(*pool); - - dcn301_destruct(dcn301_pool); - kfree(dcn301_pool); - *pool = NULL; -} - -static struct clock_source *dcn301_clock_source_create( - struct dc_context *ctx, - struct dc_bios *bios, - enum clock_source_id id, - const struct dce110_clk_src_regs *regs, - bool dp_clk_src) -{ - struct dce110_clk_src *clk_src = - kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); - - if (!clk_src) - return NULL; - - if (dcn301_clk_src_construct(clk_src, ctx, bios, id, - regs, &cs_shift, &cs_mask)) { - clk_src->base.dp_clk_src = dp_clk_src; - return &clk_src->base; - } - - kfree(clk_src); - BREAK_TO_DEBUGGER(); - return NULL; -} - -static struct dc_cap_funcs cap_funcs = { - .get_dcc_compression_cap = dcn20_get_dcc_compression_cap -}; - - -static bool is_soc_bounding_box_valid(struct dc *dc) -{ - uint32_t hw_internal_rev = dc->ctx->asic_id.hw_internal_rev; - - if (ASICREV_IS_VANGOGH(hw_internal_rev)) - return true; - - return false; -} - -static bool init_soc_bounding_box(struct dc *dc, - struct dcn301_resource_pool *pool) -{ - struct _vcs_dpi_soc_bounding_box_st *loaded_bb = &dcn3_01_soc; - struct _vcs_dpi_ip_params_st *loaded_ip = &dcn3_01_ip; - - DC_LOGGER_INIT(dc->ctx->logger); - - if (!is_soc_bounding_box_valid(dc)) { - DC_LOG_ERROR("%s: not valid soc bounding box\n", __func__); - return false; - } - - loaded_ip->max_num_otg = pool->base.res_cap->num_timing_generator; - loaded_ip->max_num_dpp = pool->base.pipe_count; - DC_FP_START(); - dcn20_patch_bounding_box(dc, loaded_bb); - DC_FP_END(); - - if (dc->ctx->dc_bios->funcs->get_soc_bb_info) { - struct bp_soc_bb_info bb_info = {0}; - - if (dc->ctx->dc_bios->funcs->get_soc_bb_info(dc->ctx->dc_bios, &bb_info) == BP_RESULT_OK) { - DC_FP_START(); - dcn301_fpu_init_soc_bounding_box(bb_info); - DC_FP_END(); - } - } - - return true; -} - - -static void set_wm_ranges( - struct pp_smu_funcs *pp_smu, - struct _vcs_dpi_soc_bounding_box_st *loaded_bb) -{ - struct pp_smu_wm_range_sets ranges = {0}; - int i; - - ranges.num_reader_wm_sets = 0; - - if (loaded_bb->num_states == 1) { - ranges.reader_wm_sets[0].wm_inst = 0; - ranges.reader_wm_sets[0].min_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; - ranges.reader_wm_sets[0].max_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; - ranges.reader_wm_sets[0].min_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; - ranges.reader_wm_sets[0].max_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; - - ranges.num_reader_wm_sets = 1; - } else if (loaded_bb->num_states > 1) { - for (i = 0; i < 4 && i < loaded_bb->num_states; i++) { - ranges.reader_wm_sets[i].wm_inst = i; - ranges.reader_wm_sets[i].min_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; - ranges.reader_wm_sets[i].max_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; - DC_FP_START(); - dcn301_fpu_set_wm_ranges(i, &ranges, loaded_bb); - DC_FP_END(); - ranges.num_reader_wm_sets = i + 1; - } - - ranges.reader_wm_sets[0].min_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; - ranges.reader_wm_sets[ranges.num_reader_wm_sets - 1].max_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; - } - - ranges.num_writer_wm_sets = 1; - - ranges.writer_wm_sets[0].wm_inst = 0; - ranges.writer_wm_sets[0].min_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; - ranges.writer_wm_sets[0].max_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; - ranges.writer_wm_sets[0].min_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; - ranges.writer_wm_sets[0].max_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; - - /* Notify PP Lib/SMU which Watermarks to use for which clock ranges */ - pp_smu->nv_funcs.set_wm_ranges(&pp_smu->nv_funcs.pp_smu, &ranges); -} - -static void dcn301_calculate_wm_and_dlg( - struct dc *dc, struct dc_state *context, - display_e2e_pipe_params_st *pipes, - int pipe_cnt, - int vlevel) -{ - DC_FP_START(); - dcn301_calculate_wm_and_dlg_fp(dc, context, pipes, pipe_cnt, vlevel); - DC_FP_END(); -} - -static struct resource_funcs dcn301_res_pool_funcs = { - .destroy = dcn301_destroy_resource_pool, - .link_enc_create = dcn301_link_encoder_create, - .panel_cntl_create = dcn301_panel_cntl_create, - .validate_bandwidth = dcn30_validate_bandwidth, - .calculate_wm_and_dlg = dcn301_calculate_wm_and_dlg, - .update_soc_for_wm_a = dcn30_update_soc_for_wm_a, - .populate_dml_pipes = dcn30_populate_dml_pipes_from_context, - .acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer, - .release_pipe = dcn20_release_pipe, - .add_stream_to_ctx = dcn30_add_stream_to_ctx, - .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource, - .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, - .populate_dml_writeback_from_context = dcn30_populate_dml_writeback_from_context, - .set_mcif_arb_params = dcn30_set_mcif_arb_params, - .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, - .patch_unknown_plane_state = dcn20_patch_unknown_plane_state -}; - -static bool dcn301_resource_construct( - uint8_t num_virtual_links, - struct dc *dc, - struct dcn301_resource_pool *pool) -{ - int i, j; - struct dc_context *ctx = dc->ctx; - struct irq_service_init_data init_data; - uint32_t pipe_fuses = read_pipe_fuses(ctx); - uint32_t num_pipes = 0; - - DC_LOGGER_INIT(dc->ctx->logger); - - ctx->dc_bios->regs = &bios_regs; - - if (dc->ctx->asic_id.chip_id == DEVICE_ID_VGH_1435) - res_cap_dcn301.num_pll = 2; - pool->base.res_cap = &res_cap_dcn301; - - pool->base.funcs = &dcn301_res_pool_funcs; - - /************************************************* - * Resource + asic cap harcoding * - *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; - pool->base.pipe_count = pool->base.res_cap->num_timing_generator; - 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 = 5; /*1.4 w/a enabled by default*/ - dc->caps.max_cursor_size = 256; - dc->caps.min_horizontal_blanking_period = 80; - dc->caps.dmdata_alloc_size = 2048; - dc->caps.max_slave_planes = 2; - dc->caps.max_slave_yuv_planes = 2; - dc->caps.max_slave_rgb_planes = 2; - dc->caps.is_apu = true; - dc->caps.post_blend_color_processing = true; - dc->caps.force_dp_tps4_for_cp2520 = true; - dc->caps.extended_aux_timeout_support = true; - dc->caps.dmcub_support = true; - - /* Color pipeline capabilities */ - dc->caps.color.dpp.dcn_arch = 1; - dc->caps.color.dpp.input_lut_shared = 0; - dc->caps.color.dpp.icsc = 1; - dc->caps.color.dpp.dgam_ram = 0; // must use gamma_corr - dc->caps.color.dpp.dgam_rom_caps.srgb = 1; - dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1; - dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 1; - dc->caps.color.dpp.dgam_rom_caps.pq = 1; - dc->caps.color.dpp.dgam_rom_caps.hlg = 1; - dc->caps.color.dpp.post_csc = 1; - dc->caps.color.dpp.gamma_corr = 1; - dc->caps.color.dpp.dgam_rom_for_yuv = 0; - - dc->caps.color.dpp.hw_3d_lut = 1; - dc->caps.color.dpp.ogam_ram = 1; - // no OGAM ROM on DCN301 - dc->caps.color.dpp.ogam_rom_caps.srgb = 0; - dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0; - dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0; - dc->caps.color.dpp.ogam_rom_caps.pq = 0; - dc->caps.color.dpp.ogam_rom_caps.hlg = 0; - dc->caps.color.dpp.ocsc = 0; - - dc->caps.color.mpc.gamut_remap = 1; - dc->caps.color.mpc.num_3dluts = pool->base.res_cap->num_mpc_3dlut; //2 - dc->caps.color.mpc.ogam_ram = 1; - dc->caps.color.mpc.ogam_rom_caps.srgb = 0; - dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0; - dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0; - dc->caps.color.mpc.ogam_rom_caps.pq = 0; - dc->caps.color.mpc.ogam_rom_caps.hlg = 0; - dc->caps.color.mpc.ocsc = 1; - - dc->caps.dp_hdmi21_pcon_support = true; - - /* read VBIOS LTTPR caps */ - if (ctx->dc_bios->funcs->get_lttpr_caps) { - enum bp_result bp_query_result; - uint8_t is_vbios_lttpr_enable = 0; - - bp_query_result = ctx->dc_bios->funcs->get_lttpr_caps(ctx->dc_bios, &is_vbios_lttpr_enable); - dc->caps.vbios_lttpr_enable = (bp_query_result == BP_RESULT_OK) && !!is_vbios_lttpr_enable; - } - - if (ctx->dc_bios->funcs->get_lttpr_interop) { - enum bp_result bp_query_result; - uint8_t is_vbios_interop_enabled = 0; - - bp_query_result = ctx->dc_bios->funcs->get_lttpr_interop(ctx->dc_bios, &is_vbios_interop_enabled); - dc->caps.vbios_lttpr_aware = (bp_query_result == BP_RESULT_OK) && !!is_vbios_interop_enabled; - } - - if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) - dc->debug = debug_defaults_drv; - - // Init the vm_helper - if (dc->vm_helper) - vm_helper_init(dc->vm_helper, 16); - - /************************************************* - * Create resources * - *************************************************/ - - /* Clock Sources for Pixel Clock*/ - pool->base.clock_sources[DCN301_CLK_SRC_PLL0] = - dcn301_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL0, - &clk_src_regs[0], false); - pool->base.clock_sources[DCN301_CLK_SRC_PLL1] = - dcn301_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL1, - &clk_src_regs[1], false); - pool->base.clock_sources[DCN301_CLK_SRC_PLL2] = - dcn301_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL2, - &clk_src_regs[2], false); - pool->base.clock_sources[DCN301_CLK_SRC_PLL3] = - dcn301_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL3, - &clk_src_regs[3], false); - - pool->base.clk_src_count = DCN301_CLK_SRC_TOTAL; - - /* todo: not reuse phy_pll registers */ - pool->base.dp_clock_source = - dcn301_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_ID_DP_DTO, - &clk_src_regs[0], true); - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] == NULL) { - dm_error("DC: failed to create clock sources!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - } - - /* DCCG */ - pool->base.dccg = dccg301_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask); - if (pool->base.dccg == NULL) { - dm_error("DC: failed to create dccg!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - - init_soc_bounding_box(dc, pool); - - if (!dc->debug.disable_pplib_wm_range && pool->base.pp_smu->nv_funcs.set_wm_ranges) - set_wm_ranges(pool->base.pp_smu, &dcn3_01_soc); - - num_pipes = dcn3_01_ip.max_num_dpp; - - for (i = 0; i < dcn3_01_ip.max_num_dpp; i++) - if (pipe_fuses & 1 << i) - num_pipes--; - dcn3_01_ip.max_num_dpp = num_pipes; - dcn3_01_ip.max_num_otg = num_pipes; - - - dml_init_instance(&dc->dml, &dcn3_01_soc, &dcn3_01_ip, DML_PROJECT_DCN30); - - /* IRQ */ - init_data.ctx = dc->ctx; - pool->base.irqs = dal_irq_service_dcn30_create(&init_data); - if (!pool->base.irqs) - goto create_fail; - - /* HUBBUB */ - pool->base.hubbub = dcn301_hubbub_create(ctx); - if (pool->base.hubbub == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create hubbub!\n"); - goto create_fail; - } - - j = 0; - /* HUBPs, DPPs, OPPs and TGs */ - for (i = 0; i < pool->base.pipe_count; i++) { - - /* if pipe is disabled, skip instance of HW pipe, - * i.e, skip ASIC register instance - */ - if ((pipe_fuses & (1 << i)) != 0) { - DC_LOG_DEBUG("%s: fusing pipe %d\n", __func__, i); - continue; - } - - pool->base.hubps[j] = dcn301_hubp_create(ctx, i); - if (pool->base.hubps[j] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create hubps!\n"); - goto create_fail; - } - - pool->base.dpps[j] = dcn301_dpp_create(ctx, i); - if (pool->base.dpps[j] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create dpps!\n"); - goto create_fail; - } - - pool->base.opps[j] = dcn301_opp_create(ctx, i); - if (pool->base.opps[j] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create output pixel processor!\n"); - goto create_fail; - } - - pool->base.timing_generators[j] = dcn301_timing_generator_create(ctx, i); - if (pool->base.timing_generators[j] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create tg!\n"); - goto create_fail; - } - j++; - } - pool->base.timing_generator_count = j; - pool->base.pipe_count = j; - pool->base.mpcc_count = j; - - /* ABM (or ABMs for NV2x) */ - /* TODO: */ - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - pool->base.multiple_abms[i] = dmub_abm_create(ctx, - &abm_regs[i], - &abm_shift, - &abm_mask); - if (pool->base.multiple_abms[i] == NULL) { - dm_error("DC: failed to create abm for pipe %d!\n", i); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - } - - /* MPC and DSC */ - pool->base.mpc = dcn301_mpc_create(ctx, pool->base.mpcc_count, pool->base.res_cap->num_mpc_3dlut); - if (pool->base.mpc == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create mpc!\n"); - goto create_fail; - } - - for (i = 0; i < pool->base.res_cap->num_dsc; i++) { - pool->base.dscs[i] = dcn301_dsc_create(ctx, i); - if (pool->base.dscs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create display stream compressor %d!\n", i); - goto create_fail; - } - } - - /* DWB and MMHUBBUB */ - if (!dcn301_dwbc_create(ctx, &pool->base)) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create dwbc!\n"); - goto create_fail; - } - - if (!dcn301_mmhubbub_create(ctx, &pool->base)) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create mcif_wb!\n"); - goto create_fail; - } - - /* AUX and I2C */ - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - pool->base.engines[i] = dcn301_aux_engine_create(ctx, i); - if (pool->base.engines[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create aux engine!!\n"); - goto create_fail; - } - pool->base.hw_i2cs[i] = dcn301_i2c_hw_create(ctx, i); - if (pool->base.hw_i2cs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create hw i2c!!\n"); - goto create_fail; - } - pool->base.sw_i2cs[i] = NULL; - } - - /* Audio, Stream Encoders including HPO and virtual, MPC 3D LUTs */ - if (!resource_construct(num_virtual_links, dc, &pool->base, - &res_create_funcs)) - goto create_fail; - - /* HW Sequencer and Plane caps */ - dcn301_hw_sequencer_construct(dc); - - dc->caps.max_planes = pool->base.pipe_count; - - for (i = 0; i < dc->caps.max_planes; ++i) - dc->caps.planes[i] = plane_cap; - - dc->cap_funcs = cap_funcs; - - return true; - -create_fail: - - dcn301_destruct(pool); - - return false; -} - -struct resource_pool *dcn301_create_resource_pool( - const struct dc_init_data *init_data, - struct dc *dc) -{ - struct dcn301_resource_pool *pool = - kzalloc(sizeof(struct dcn301_resource_pool), GFP_KERNEL); - - if (!pool) - return NULL; - - if (dcn301_resource_construct(init_data->num_virtual_links, dc, pool)) - return &pool->base; - - BREAK_TO_DEBUGGER(); - kfree(pool); - return NULL; -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.h b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.h deleted file mode 100644 index ae8672680cdd13..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2020 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 _DCN301_RESOURCE_H_ -#define _DCN301_RESOURCE_H_ - -#include "core_types.h" - -struct dc; -struct resource_pool; -struct _vcs_dpi_display_pipe_params_st; - -extern struct _vcs_dpi_ip_params_st dcn3_01_ip; -extern struct _vcs_dpi_soc_bounding_box_st dcn3_01_soc; - -struct dcn301_resource_pool { - struct resource_pool base; -}; -struct resource_pool *dcn301_create_resource_pool( - const struct dc_init_data *init_data, - struct dc *dc); - -#endif /* _DCN301_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn302/Makefile b/drivers/gpu/drm/amd/display/dc/dcn302/Makefile deleted file mode 100644 index 95b66baf39e911..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn302/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# -# (c) Copyright 2020 Advanced Micro Devices, Inc. All the rights reserved -# -# Authors: AMD -# -# Makefile for dcn302. - -DCN3_02 = dcn302_init.o dcn302_resource.o - -AMD_DAL_DCN3_02 = $(addprefix $(AMDDALPATH)/dc/dcn302/,$(DCN3_02)) - -AMD_DISPLAY_FILES += $(AMD_DAL_DCN3_02) diff --git a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_init.c b/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_init.c deleted file mode 100644 index 637f9514d37b2d..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_init.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2020 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 "dcn302/dcn302_hwseq.h" - -#include "dcn30/dcn30_init.h" - -#include "dc.h" - -#include "dcn302_init.h" - -void dcn302_hw_sequencer_construct(struct dc *dc) -{ - dcn30_hw_sequencer_construct(dc); - - dc->hwseq->funcs.dpp_pg_control = dcn302_dpp_pg_control; - dc->hwseq->funcs.hubp_pg_control = dcn302_hubp_pg_control; - dc->hwseq->funcs.dsc_pg_control = dcn302_dsc_pg_control; -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_init.h b/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_init.h deleted file mode 100644 index 899587b93aa1c2..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_init.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2020 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_DCN302_INIT_H__ -#define __DC_DCN302_INIT_H__ - -struct dc; - -void dcn302_hw_sequencer_construct(struct dc *dc); - -#endif /* __DC_DCN302_INIT_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c b/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c deleted file mode 100644 index 63ac984a04f7ed..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c +++ /dev/null @@ -1,1518 +0,0 @@ -/* - * Copyright 2020 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 "dcn302_init.h" -#include "dcn302_resource.h" -#include "dcn302_dccg.h" -#include "irq/dcn302/irq_service_dcn302.h" - -#include "dcn30/dcn30_dio_link_encoder.h" -#include "dcn30/dcn30_dio_stream_encoder.h" -#include "dcn30/dcn30_dwb.h" -#include "dcn30/dcn30_dpp.h" -#include "dcn30/dcn30_hubbub.h" -#include "dcn30/dcn30_hubp.h" -#include "dcn30/dcn30_mmhubbub.h" -#include "dcn30/dcn30_mpc.h" -#include "dcn30/dcn30_opp.h" -#include "dcn30/dcn30_optc.h" -#include "dcn30/dcn30_resource.h" - -#include "dcn20/dcn20_dsc.h" -#include "dcn20/dcn20_resource.h" - -#include "dml/dcn30/dcn30_fpu.h" - -#include "dcn10/dcn10_resource.h" - -#include "link.h" -#include "dce/dce_abm.h" -#include "dce/dce_audio.h" -#include "dce/dce_aux.h" -#include "dce/dce_clock_source.h" -#include "dce/dce_hwseq.h" -#include "dce/dce_i2c_hw.h" -#include "dce/dce_panel_cntl.h" -#include "dce/dmub_abm.h" -#include "dce/dmub_psr.h" -#include "clk_mgr.h" - -#include "hw_sequencer_private.h" -#include "reg_helper.h" -#include "resource.h" -#include "vm_helper.h" - -#include "dml/dcn302/dcn302_fpu.h" - -#include "dimgrey_cavefish_ip_offset.h" -#include "dcn/dcn_3_0_2_offset.h" -#include "dcn/dcn_3_0_2_sh_mask.h" -#include "dpcs/dpcs_3_0_0_offset.h" -#include "dpcs/dpcs_3_0_0_sh_mask.h" -#include "nbio/nbio_7_4_offset.h" -#include "amdgpu_socbb.h" - -#define DC_LOGGER \ - dc->ctx->logger -#define DC_LOGGER_INIT(logger) - -static const struct dc_debug_options debug_defaults_drv = { - .disable_dmcu = true, - .force_abm_enable = false, - .timing_trace = false, - .clock_trace = true, - .disable_pplib_clock_request = true, - .pipe_split_policy = MPC_SPLIT_DYNAMIC, - .force_single_disp_pipe_split = false, - .disable_dcc = DCC_ENABLE, - .vsr_support = true, - .performance_trace = false, - .max_downscale_src_width = 7680,/*upto 8K*/ - .disable_pplib_wm_range = false, - .scl_reset_length10 = true, - .sanity_checks = false, - .underflow_assert_delay_us = 0xFFFFFFFF, - .dwb_fi_phase = -1, // -1 = disable, - .dmub_command_table = true, - .use_max_lb = true, - .exit_idle_opt_for_cursor_updates = true, - .enable_legacy_fast_update = false, - .using_dml2 = false, -}; - -static const struct dc_panel_config panel_config_defaults = { - .psr = { - .disable_psr = false, - .disallow_psrsu = false, - .disallow_replay = false, - }, -}; - -enum dcn302_clk_src_array_id { - DCN302_CLK_SRC_PLL0, - DCN302_CLK_SRC_PLL1, - DCN302_CLK_SRC_PLL2, - DCN302_CLK_SRC_PLL3, - DCN302_CLK_SRC_PLL4, - DCN302_CLK_SRC_TOTAL -}; - -static const struct resource_caps res_cap_dcn302 = { - .num_timing_generator = 5, - .num_opp = 5, - .num_video_plane = 5, - .num_audio = 5, - .num_stream_encoder = 5, - .num_dwb = 1, - .num_ddc = 5, - .num_vmid = 16, - .num_mpc_3dlut = 2, - .num_dsc = 5, -}; - -static const struct dc_plane_cap plane_cap = { - .type = DC_PLANE_TYPE_DCN_UNIVERSAL, - .per_pixel_alpha = true, - .pixel_format_support = { - .argb8888 = true, - .nv12 = true, - .fp16 = true, - .p010 = true, - .ayuv = false, - }, - .max_upscale_factor = { - .argb8888 = 16000, - .nv12 = 16000, - .fp16 = 16000 - }, - /* 6:1 downscaling ratio: 1000/6 = 166.666 */ - .max_downscale_factor = { - .argb8888 = 167, - .nv12 = 167, - .fp16 = 167 - }, - 16, - 16 -}; - -/* NBIO */ -#define NBIO_BASE_INNER(seg) \ - NBIO_BASE__INST0_SEG ## seg - -#define NBIO_BASE(seg) \ - NBIO_BASE_INNER(seg) - -#define NBIO_SR(reg_name)\ - .reg_name = NBIO_BASE(mm ## reg_name ## _BASE_IDX) + \ - mm ## reg_name - -/* DCN */ -#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg - -#define BASE(seg) BASE_INNER(seg) - -#define SR(reg_name)\ - .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + mm ## reg_name - -#define SF(reg_name, field_name, post_fix)\ - .field_name = reg_name ## __ ## field_name ## post_fix - -#define SRI(reg_name, block, id)\ - .reg_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + mm ## block ## id ## _ ## reg_name - -#define SRI2(reg_name, block, id)\ - .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + mm ## reg_name - -#define SRII(reg_name, block, id)\ - .reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name - -#define DCCG_SRII(reg_name, block, id)\ - .block ## _ ## reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name - -#define VUPDATE_SRII(reg_name, block, id)\ - .reg_name[id] = BASE(mm ## reg_name ## _ ## block ## id ## _BASE_IDX) + \ - mm ## reg_name ## _ ## block ## id - -#define SRII_DWB(reg_name, temp_name, block, id)\ - .reg_name[id] = BASE(mm ## block ## id ## _ ## temp_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## temp_name - -#define SF_DWB2(reg_name, block, id, field_name, post_fix) \ - .field_name = reg_name ## __ ## field_name ## post_fix - -#define SRII_MPC_RMU(reg_name, block, id)\ - .RMU##_##reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name - -static const struct dcn_hubbub_registers hubbub_reg = { - HUBBUB_REG_LIST_DCN30(0) -}; - -static const struct dcn_hubbub_shift hubbub_shift = { - HUBBUB_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn_hubbub_mask hubbub_mask = { - HUBBUB_MASK_SH_LIST_DCN30(_MASK) -}; - -#define vmid_regs(id)\ - [id] = { DCN20_VMID_REG_LIST(id) } - -static const struct dcn_vmid_registers vmid_regs[] = { - vmid_regs(0), - vmid_regs(1), - vmid_regs(2), - vmid_regs(3), - vmid_regs(4), - vmid_regs(5), - vmid_regs(6), - vmid_regs(7), - vmid_regs(8), - vmid_regs(9), - vmid_regs(10), - vmid_regs(11), - vmid_regs(12), - vmid_regs(13), - vmid_regs(14), - vmid_regs(15) -}; - -static const struct dcn20_vmid_shift vmid_shifts = { - DCN20_VMID_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn20_vmid_mask vmid_masks = { - DCN20_VMID_MASK_SH_LIST(_MASK) -}; - -static struct hubbub *dcn302_hubbub_create(struct dc_context *ctx) -{ - int i; - - struct dcn20_hubbub *hubbub3 = kzalloc(sizeof(struct dcn20_hubbub), GFP_KERNEL); - - if (!hubbub3) - return NULL; - - hubbub3_construct(hubbub3, ctx, &hubbub_reg, &hubbub_shift, &hubbub_mask); - - for (i = 0; i < res_cap_dcn302.num_vmid; i++) { - struct dcn20_vmid *vmid = &hubbub3->vmid[i]; - - vmid->ctx = ctx; - - vmid->regs = &vmid_regs[i]; - vmid->shifts = &vmid_shifts; - vmid->masks = &vmid_masks; - } - - return &hubbub3->base; -} - -#define vpg_regs(id)\ - [id] = { VPG_DCN3_REG_LIST(id) } - -static const struct dcn30_vpg_registers vpg_regs[] = { - vpg_regs(0), - vpg_regs(1), - vpg_regs(2), - vpg_regs(3), - vpg_regs(4), - vpg_regs(5) -}; - -static const struct dcn30_vpg_shift vpg_shift = { - DCN3_VPG_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn30_vpg_mask vpg_mask = { - DCN3_VPG_MASK_SH_LIST(_MASK) -}; - -static struct vpg *dcn302_vpg_create(struct dc_context *ctx, uint32_t inst) -{ - struct dcn30_vpg *vpg3 = kzalloc(sizeof(struct dcn30_vpg), GFP_KERNEL); - - if (!vpg3) - return NULL; - - vpg3_construct(vpg3, ctx, inst, &vpg_regs[inst], &vpg_shift, &vpg_mask); - - return &vpg3->base; -} - -#define afmt_regs(id)\ - [id] = { AFMT_DCN3_REG_LIST(id) } - -static const struct dcn30_afmt_registers afmt_regs[] = { - afmt_regs(0), - afmt_regs(1), - afmt_regs(2), - afmt_regs(3), - afmt_regs(4), - afmt_regs(5) -}; - -static const struct dcn30_afmt_shift afmt_shift = { - DCN3_AFMT_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn30_afmt_mask afmt_mask = { - DCN3_AFMT_MASK_SH_LIST(_MASK) -}; - -static struct afmt *dcn302_afmt_create(struct dc_context *ctx, uint32_t inst) -{ - struct dcn30_afmt *afmt3 = kzalloc(sizeof(struct dcn30_afmt), GFP_KERNEL); - - if (!afmt3) - return NULL; - - afmt3_construct(afmt3, ctx, inst, &afmt_regs[inst], &afmt_shift, &afmt_mask); - - return &afmt3->base; -} - -#define audio_regs(id)\ - [id] = { AUD_COMMON_REG_LIST(id) } - -static const struct dce_audio_registers audio_regs[] = { - audio_regs(0), - audio_regs(1), - audio_regs(2), - audio_regs(3), - audio_regs(4), - audio_regs(5), - audio_regs(6) -}; - -#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ - SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ - SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ - AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) - -static const struct dce_audio_shift audio_shift = { - DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_audio_mask audio_mask = { - DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) -}; - -static struct audio *dcn302_create_audio(struct dc_context *ctx, unsigned int inst) -{ - return dce_audio_create(ctx, inst, &audio_regs[inst], &audio_shift, &audio_mask); -} - -#define stream_enc_regs(id)\ - [id] = { SE_DCN3_REG_LIST(id) } - -static const struct dcn10_stream_enc_registers stream_enc_regs[] = { - stream_enc_regs(0), - stream_enc_regs(1), - stream_enc_regs(2), - stream_enc_regs(3), - stream_enc_regs(4) -}; - -static const struct dcn10_stream_encoder_shift se_shift = { - SE_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn10_stream_encoder_mask se_mask = { - SE_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -static struct stream_encoder *dcn302_stream_encoder_create(enum engine_id eng_id, struct dc_context *ctx) -{ - struct dcn10_stream_encoder *enc1; - struct vpg *vpg; - struct afmt *afmt; - int vpg_inst; - int afmt_inst; - - /* Mapping of VPG, AFMT, DME register blocks to DIO block instance */ - if (eng_id <= ENGINE_ID_DIGE) { - vpg_inst = eng_id; - afmt_inst = eng_id; - } else - return NULL; - - enc1 = kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL); - vpg = dcn302_vpg_create(ctx, vpg_inst); - afmt = dcn302_afmt_create(ctx, afmt_inst); - - if (!enc1 || !vpg || !afmt) { - kfree(enc1); - kfree(vpg); - kfree(afmt); - return NULL; - } - - dcn30_dio_stream_encoder_construct(enc1, ctx, ctx->dc_bios, eng_id, vpg, afmt, &stream_enc_regs[eng_id], - &se_shift, &se_mask); - - return &enc1->base; -} - -#define clk_src_regs(index, pllid)\ - [index] = { CS_COMMON_REG_LIST_DCN3_02(index, pllid) } - -static const struct dce110_clk_src_regs clk_src_regs[] = { - clk_src_regs(0, A), - clk_src_regs(1, B), - clk_src_regs(2, C), - clk_src_regs(3, D), - clk_src_regs(4, E) -}; - -static const struct dce110_clk_src_shift cs_shift = { - CS_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) -}; - -static const struct dce110_clk_src_mask cs_mask = { - CS_COMMON_MASK_SH_LIST_DCN2_0(_MASK) -}; - -static struct clock_source *dcn302_clock_source_create(struct dc_context *ctx, struct dc_bios *bios, - enum clock_source_id id, const struct dce110_clk_src_regs *regs, bool dp_clk_src) -{ - struct dce110_clk_src *clk_src = kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); - - if (!clk_src) - return NULL; - - if (dcn3_clk_src_construct(clk_src, ctx, bios, id, regs, &cs_shift, &cs_mask)) { - clk_src->base.dp_clk_src = dp_clk_src; - return &clk_src->base; - } - - kfree(clk_src); - BREAK_TO_DEBUGGER(); - return NULL; -} - -static const struct dce_hwseq_registers hwseq_reg = { - HWSEQ_DCN302_REG_LIST() -}; - -static const struct dce_hwseq_shift hwseq_shift = { - HWSEQ_DCN302_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_hwseq_mask hwseq_mask = { - HWSEQ_DCN302_MASK_SH_LIST(_MASK) -}; - -static struct dce_hwseq *dcn302_hwseq_create(struct dc_context *ctx) -{ - struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); - - if (hws) { - hws->ctx = ctx; - hws->regs = &hwseq_reg; - hws->shifts = &hwseq_shift; - hws->masks = &hwseq_mask; - } - return hws; -} - -#define hubp_regs(id)\ - [id] = { HUBP_REG_LIST_DCN30(id) } - -static const struct dcn_hubp2_registers hubp_regs[] = { - hubp_regs(0), - hubp_regs(1), - hubp_regs(2), - hubp_regs(3), - hubp_regs(4) -}; - -static const struct dcn_hubp2_shift hubp_shift = { - HUBP_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn_hubp2_mask hubp_mask = { - HUBP_MASK_SH_LIST_DCN30(_MASK) -}; - -static struct hubp *dcn302_hubp_create(struct dc_context *ctx, uint32_t inst) -{ - struct dcn20_hubp *hubp2 = kzalloc(sizeof(struct dcn20_hubp), GFP_KERNEL); - - if (!hubp2) - return NULL; - - if (hubp3_construct(hubp2, ctx, inst, &hubp_regs[inst], &hubp_shift, &hubp_mask)) - return &hubp2->base; - - BREAK_TO_DEBUGGER(); - kfree(hubp2); - return NULL; -} - -#define dpp_regs(id)\ - [id] = { DPP_REG_LIST_DCN30(id) } - -static const struct dcn3_dpp_registers dpp_regs[] = { - dpp_regs(0), - dpp_regs(1), - dpp_regs(2), - dpp_regs(3), - dpp_regs(4) -}; - -static const struct dcn3_dpp_shift tf_shift = { - DPP_REG_LIST_SH_MASK_DCN30(__SHIFT) -}; - -static const struct dcn3_dpp_mask tf_mask = { - DPP_REG_LIST_SH_MASK_DCN30(_MASK) -}; - -static struct dpp *dcn302_dpp_create(struct dc_context *ctx, uint32_t inst) -{ - struct dcn3_dpp *dpp = kzalloc(sizeof(struct dcn3_dpp), GFP_KERNEL); - - if (!dpp) - return NULL; - - if (dpp3_construct(dpp, ctx, inst, &dpp_regs[inst], &tf_shift, &tf_mask)) - return &dpp->base; - - BREAK_TO_DEBUGGER(); - kfree(dpp); - return NULL; -} - -#define opp_regs(id)\ - [id] = { OPP_REG_LIST_DCN30(id) } - -static const struct dcn20_opp_registers opp_regs[] = { - opp_regs(0), - opp_regs(1), - opp_regs(2), - opp_regs(3), - opp_regs(4) -}; - -static const struct dcn20_opp_shift opp_shift = { - OPP_MASK_SH_LIST_DCN20(__SHIFT) -}; - -static const struct dcn20_opp_mask opp_mask = { - OPP_MASK_SH_LIST_DCN20(_MASK) -}; - -static struct output_pixel_processor *dcn302_opp_create(struct dc_context *ctx, uint32_t inst) -{ - struct dcn20_opp *opp = kzalloc(sizeof(struct dcn20_opp), GFP_KERNEL); - - if (!opp) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dcn20_opp_construct(opp, ctx, inst, &opp_regs[inst], &opp_shift, &opp_mask); - return &opp->base; -} - -#define optc_regs(id)\ - [id] = { OPTC_COMMON_REG_LIST_DCN3_0(id) } - -static const struct dcn_optc_registers optc_regs[] = { - optc_regs(0), - optc_regs(1), - optc_regs(2), - optc_regs(3), - optc_regs(4) -}; - -static const struct dcn_optc_shift optc_shift = { - OPTC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn_optc_mask optc_mask = { - OPTC_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -static struct timing_generator *dcn302_timing_generator_create(struct dc_context *ctx, uint32_t instance) -{ - struct optc *tgn10 = kzalloc(sizeof(struct optc), GFP_KERNEL); - - if (!tgn10) - return NULL; - - tgn10->base.inst = instance; - tgn10->base.ctx = ctx; - - tgn10->tg_regs = &optc_regs[instance]; - tgn10->tg_shift = &optc_shift; - tgn10->tg_mask = &optc_mask; - - dcn30_timing_generator_init(tgn10); - - return &tgn10->base; -} - -static const struct dcn30_mpc_registers mpc_regs = { - MPC_REG_LIST_DCN3_0(0), - MPC_REG_LIST_DCN3_0(1), - MPC_REG_LIST_DCN3_0(2), - MPC_REG_LIST_DCN3_0(3), - MPC_REG_LIST_DCN3_0(4), - MPC_OUT_MUX_REG_LIST_DCN3_0(0), - MPC_OUT_MUX_REG_LIST_DCN3_0(1), - MPC_OUT_MUX_REG_LIST_DCN3_0(2), - MPC_OUT_MUX_REG_LIST_DCN3_0(3), - MPC_OUT_MUX_REG_LIST_DCN3_0(4), - MPC_RMU_GLOBAL_REG_LIST_DCN3AG, - MPC_RMU_REG_LIST_DCN3AG(0), - MPC_RMU_REG_LIST_DCN3AG(1), - MPC_RMU_REG_LIST_DCN3AG(2), - MPC_DWB_MUX_REG_LIST_DCN3_0(0), -}; - -static const struct dcn30_mpc_shift mpc_shift = { - MPC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn30_mpc_mask mpc_mask = { - MPC_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -static struct mpc *dcn302_mpc_create(struct dc_context *ctx, int num_mpcc, int num_rmu) -{ - struct dcn30_mpc *mpc30 = kzalloc(sizeof(struct dcn30_mpc), GFP_KERNEL); - - if (!mpc30) - return NULL; - - dcn30_mpc_construct(mpc30, ctx, &mpc_regs, &mpc_shift, &mpc_mask, num_mpcc, num_rmu); - - return &mpc30->base; -} - -#define dsc_regsDCN20(id)\ -[id] = { DSC_REG_LIST_DCN20(id) } - -static const struct dcn20_dsc_registers dsc_regs[] = { - dsc_regsDCN20(0), - dsc_regsDCN20(1), - dsc_regsDCN20(2), - dsc_regsDCN20(3), - dsc_regsDCN20(4) -}; - -static const struct dcn20_dsc_shift dsc_shift = { - DSC_REG_LIST_SH_MASK_DCN20(__SHIFT) -}; - -static const struct dcn20_dsc_mask dsc_mask = { - DSC_REG_LIST_SH_MASK_DCN20(_MASK) -}; - -static struct display_stream_compressor *dcn302_dsc_create(struct dc_context *ctx, uint32_t inst) -{ - struct dcn20_dsc *dsc = kzalloc(sizeof(struct dcn20_dsc), GFP_KERNEL); - - if (!dsc) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dsc2_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask); - return &dsc->base; -} - -#define dwbc_regs_dcn3(id)\ -[id] = { DWBC_COMMON_REG_LIST_DCN30(id) } - -static const struct dcn30_dwbc_registers dwbc30_regs[] = { - dwbc_regs_dcn3(0) -}; - -static const struct dcn30_dwbc_shift dwbc30_shift = { - DWBC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn30_dwbc_mask dwbc30_mask = { - DWBC_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -static bool dcn302_dwbc_create(struct dc_context *ctx, struct resource_pool *pool) -{ - int i; - uint32_t pipe_count = pool->res_cap->num_dwb; - - for (i = 0; i < pipe_count; i++) { - struct dcn30_dwbc *dwbc30 = kzalloc(sizeof(struct dcn30_dwbc), GFP_KERNEL); - - if (!dwbc30) { - dm_error("DC: failed to create dwbc30!\n"); - return false; - } - - dcn30_dwbc_construct(dwbc30, ctx, &dwbc30_regs[i], &dwbc30_shift, &dwbc30_mask, i); - - pool->dwbc[i] = &dwbc30->base; - } - return true; -} - -#define mcif_wb_regs_dcn3(id)\ -[id] = { MCIF_WB_COMMON_REG_LIST_DCN30(id) } - -static const struct dcn30_mmhubbub_registers mcif_wb30_regs[] = { - mcif_wb_regs_dcn3(0) -}; - -static const struct dcn30_mmhubbub_shift mcif_wb30_shift = { - MCIF_WB_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn30_mmhubbub_mask mcif_wb30_mask = { - MCIF_WB_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -static bool dcn302_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool) -{ - int i; - uint32_t pipe_count = pool->res_cap->num_dwb; - - for (i = 0; i < pipe_count; i++) { - struct dcn30_mmhubbub *mcif_wb30 = kzalloc(sizeof(struct dcn30_mmhubbub), GFP_KERNEL); - - if (!mcif_wb30) { - dm_error("DC: failed to create mcif_wb30!\n"); - return false; - } - - dcn30_mmhubbub_construct(mcif_wb30, ctx, &mcif_wb30_regs[i], &mcif_wb30_shift, &mcif_wb30_mask, i); - - pool->mcif_wb[i] = &mcif_wb30->base; - } - return true; -} - -#define aux_engine_regs(id)\ -[id] = {\ - AUX_COMMON_REG_LIST0(id), \ - .AUXN_IMPCAL = 0, \ - .AUXP_IMPCAL = 0, \ - .AUX_RESET_MASK = DP_AUX0_AUX_CONTROL__AUX_RESET_MASK, \ -} - -static const struct dce110_aux_registers aux_engine_regs[] = { - aux_engine_regs(0), - aux_engine_regs(1), - aux_engine_regs(2), - aux_engine_regs(3), - aux_engine_regs(4) -}; - -static const struct dce110_aux_registers_shift aux_shift = { - DCN_AUX_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce110_aux_registers_mask aux_mask = { - DCN_AUX_MASK_SH_LIST(_MASK) -}; - -static struct dce_aux *dcn302_aux_engine_create(struct dc_context *ctx, uint32_t inst) -{ - struct aux_engine_dce110 *aux_engine = kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); - - if (!aux_engine) - return NULL; - - dce110_aux_engine_construct(aux_engine, ctx, inst, SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, - &aux_engine_regs[inst], &aux_mask, &aux_shift, ctx->dc->caps.extended_aux_timeout_support); - - return &aux_engine->base; -} - -#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST(id) } - -static const struct dce_i2c_registers i2c_hw_regs[] = { - i2c_inst_regs(1), - i2c_inst_regs(2), - i2c_inst_regs(3), - i2c_inst_regs(4), - i2c_inst_regs(5) -}; - -static const struct dce_i2c_shift i2c_shifts = { - I2C_COMMON_MASK_SH_LIST_DCN2(__SHIFT) -}; - -static const struct dce_i2c_mask i2c_masks = { - I2C_COMMON_MASK_SH_LIST_DCN2(_MASK) -}; - -static struct dce_i2c_hw *dcn302_i2c_hw_create(struct dc_context *ctx, uint32_t inst) -{ - struct dce_i2c_hw *dce_i2c_hw = kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); - - if (!dce_i2c_hw) - return NULL; - - dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst, &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); - - return dce_i2c_hw; -} - -static const struct encoder_feature_support link_enc_feature = { - .max_hdmi_deep_color = COLOR_DEPTH_121212, - .max_hdmi_pixel_clock = 600000, - .hdmi_ycbcr420_supported = true, - .dp_ycbcr420_supported = true, - .fec_supported = true, - .flags.bits.IS_HBR2_CAPABLE = true, - .flags.bits.IS_HBR3_CAPABLE = true, - .flags.bits.IS_TPS3_CAPABLE = true, - .flags.bits.IS_TPS4_CAPABLE = true -}; - -#define link_regs(id, phyid)\ - [id] = {\ - LE_DCN3_REG_LIST(id), \ - UNIPHY_DCN2_REG_LIST(phyid), \ - DPCS_DCN2_REG_LIST(id), \ - SRI(DP_DPHY_INTERNAL_CTRL, DP, id) \ - } - -static const struct dcn10_link_enc_registers link_enc_regs[] = { - link_regs(0, A), - link_regs(1, B), - link_regs(2, C), - link_regs(3, D), - link_regs(4, E) -}; - -static const struct dcn10_link_enc_shift le_shift = { - LINK_ENCODER_MASK_SH_LIST_DCN30(__SHIFT), - DPCS_DCN2_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn10_link_enc_mask le_mask = { - LINK_ENCODER_MASK_SH_LIST_DCN30(_MASK), - DPCS_DCN2_MASK_SH_LIST(_MASK) -}; - -#define aux_regs(id)\ - [id] = { DCN2_AUX_REG_LIST(id) } - -static const struct dcn10_link_enc_aux_registers link_enc_aux_regs[] = { - aux_regs(0), - aux_regs(1), - aux_regs(2), - aux_regs(3), - aux_regs(4) -}; - -#define hpd_regs(id)\ - [id] = { HPD_REG_LIST(id) } - -static const struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[] = { - hpd_regs(0), - hpd_regs(1), - hpd_regs(2), - hpd_regs(3), - hpd_regs(4) -}; - -static struct link_encoder *dcn302_link_encoder_create( - struct dc_context *ctx, - const struct encoder_init_data *enc_init_data) -{ - struct dcn20_link_encoder *enc20 = kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); - - if (!enc20) - return NULL; - - dcn30_link_encoder_construct(enc20, enc_init_data, &link_enc_feature, - &link_enc_regs[enc_init_data->transmitter], &link_enc_aux_regs[enc_init_data->channel - 1], - &link_enc_hpd_regs[enc_init_data->hpd_source], &le_shift, &le_mask); - - return &enc20->enc10.base; -} - -static const struct dce_panel_cntl_registers panel_cntl_regs[] = { - { DCN_PANEL_CNTL_REG_LIST() } -}; - -static const struct dce_panel_cntl_shift panel_cntl_shift = { - DCE_PANEL_CNTL_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_panel_cntl_mask panel_cntl_mask = { - DCE_PANEL_CNTL_MASK_SH_LIST(_MASK) -}; - -static struct panel_cntl *dcn302_panel_cntl_create(const struct panel_cntl_init_data *init_data) -{ - struct dce_panel_cntl *panel_cntl = kzalloc(sizeof(struct dce_panel_cntl), GFP_KERNEL); - - if (!panel_cntl) - return NULL; - - dce_panel_cntl_construct(panel_cntl, init_data, &panel_cntl_regs[init_data->inst], - &panel_cntl_shift, &panel_cntl_mask); - - return &panel_cntl->base; -} - -static void read_dce_straps(struct dc_context *ctx, struct resource_straps *straps) -{ - generic_reg_get(ctx, mmDC_PINSTRAPS + BASE(mmDC_PINSTRAPS_BASE_IDX), - FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio); -} - -static const struct resource_create_funcs res_create_funcs = { - .read_dce_straps = read_dce_straps, - .create_audio = dcn302_create_audio, - .create_stream_encoder = dcn302_stream_encoder_create, - .create_hwseq = dcn302_hwseq_create, -}; - -static bool is_soc_bounding_box_valid(struct dc *dc) -{ - uint32_t hw_internal_rev = dc->ctx->asic_id.hw_internal_rev; - - if (ASICREV_IS_DIMGREY_CAVEFISH_P(hw_internal_rev)) - return true; - - return false; -} - -static bool init_soc_bounding_box(struct dc *dc, struct resource_pool *pool) -{ - struct _vcs_dpi_soc_bounding_box_st *loaded_bb = &dcn3_02_soc; - struct _vcs_dpi_ip_params_st *loaded_ip = &dcn3_02_ip; - - DC_LOGGER_INIT(dc->ctx->logger); - - if (!is_soc_bounding_box_valid(dc)) { - DC_LOG_ERROR("%s: not valid soc bounding box\n", __func__); - return false; - } - - loaded_ip->max_num_otg = pool->pipe_count; - loaded_ip->max_num_dpp = pool->pipe_count; - loaded_ip->clamp_min_dcfclk = dc->config.clamp_min_dcfclk; - DC_FP_START(); - dcn20_patch_bounding_box(dc, loaded_bb); - DC_FP_END(); - - if (dc->ctx->dc_bios->funcs->get_soc_bb_info) { - struct bp_soc_bb_info bb_info = { 0 }; - - if (dc->ctx->dc_bios->funcs->get_soc_bb_info( - dc->ctx->dc_bios, &bb_info) == BP_RESULT_OK) { - - DC_FP_START(); - dcn302_fpu_init_soc_bounding_box(bb_info); - DC_FP_END(); - } - } - - return true; -} - -static void dcn302_resource_destruct(struct resource_pool *pool) -{ - unsigned int i; - - for (i = 0; i < pool->stream_enc_count; i++) { - if (pool->stream_enc[i] != NULL) { - if (pool->stream_enc[i]->vpg != NULL) { - kfree(DCN30_VPG_FROM_VPG(pool->stream_enc[i]->vpg)); - pool->stream_enc[i]->vpg = NULL; - } - if (pool->stream_enc[i]->afmt != NULL) { - kfree(DCN30_AFMT_FROM_AFMT(pool->stream_enc[i]->afmt)); - pool->stream_enc[i]->afmt = NULL; - } - kfree(DCN10STRENC_FROM_STRENC(pool->stream_enc[i])); - pool->stream_enc[i] = NULL; - } - } - - for (i = 0; i < pool->res_cap->num_dsc; i++) { - if (pool->dscs[i] != NULL) - dcn20_dsc_destroy(&pool->dscs[i]); - } - - if (pool->mpc != NULL) { - kfree(TO_DCN20_MPC(pool->mpc)); - pool->mpc = NULL; - } - - if (pool->hubbub != NULL) { - kfree(pool->hubbub); - pool->hubbub = NULL; - } - - for (i = 0; i < pool->pipe_count; i++) { - if (pool->dpps[i] != NULL) { - kfree(TO_DCN20_DPP(pool->dpps[i])); - pool->dpps[i] = NULL; - } - - if (pool->hubps[i] != NULL) { - kfree(TO_DCN20_HUBP(pool->hubps[i])); - pool->hubps[i] = NULL; - } - - if (pool->irqs != NULL) - dal_irq_service_destroy(&pool->irqs); - } - - for (i = 0; i < pool->res_cap->num_ddc; i++) { - if (pool->engines[i] != NULL) - dce110_engine_destroy(&pool->engines[i]); - if (pool->hw_i2cs[i] != NULL) { - kfree(pool->hw_i2cs[i]); - pool->hw_i2cs[i] = NULL; - } - if (pool->sw_i2cs[i] != NULL) { - kfree(pool->sw_i2cs[i]); - pool->sw_i2cs[i] = NULL; - } - } - - for (i = 0; i < pool->res_cap->num_opp; i++) { - if (pool->opps[i] != NULL) - pool->opps[i]->funcs->opp_destroy(&pool->opps[i]); - } - - for (i = 0; i < pool->res_cap->num_timing_generator; i++) { - if (pool->timing_generators[i] != NULL) { - kfree(DCN10TG_FROM_TG(pool->timing_generators[i])); - pool->timing_generators[i] = NULL; - } - } - - for (i = 0; i < pool->res_cap->num_dwb; i++) { - if (pool->dwbc[i] != NULL) { - kfree(TO_DCN30_DWBC(pool->dwbc[i])); - pool->dwbc[i] = NULL; - } - if (pool->mcif_wb[i] != NULL) { - kfree(TO_DCN30_MMHUBBUB(pool->mcif_wb[i])); - pool->mcif_wb[i] = NULL; - } - } - - for (i = 0; i < pool->audio_count; i++) { - if (pool->audios[i]) - dce_aud_destroy(&pool->audios[i]); - } - - for (i = 0; i < pool->clk_src_count; i++) { - if (pool->clock_sources[i] != NULL) - dcn20_clock_source_destroy(&pool->clock_sources[i]); - } - - if (pool->dp_clock_source != NULL) - dcn20_clock_source_destroy(&pool->dp_clock_source); - - for (i = 0; i < pool->res_cap->num_mpc_3dlut; i++) { - if (pool->mpc_lut[i] != NULL) { - dc_3dlut_func_release(pool->mpc_lut[i]); - pool->mpc_lut[i] = NULL; - } - if (pool->mpc_shaper[i] != NULL) { - dc_transfer_func_release(pool->mpc_shaper[i]); - pool->mpc_shaper[i] = NULL; - } - } - - for (i = 0; i < pool->pipe_count; i++) { - if (pool->multiple_abms[i] != NULL) - dce_abm_destroy(&pool->multiple_abms[i]); - } - - if (pool->psr != NULL) - dmub_psr_destroy(&pool->psr); - - if (pool->dccg != NULL) - dcn_dccg_destroy(&pool->dccg); - - if (pool->oem_device != NULL) { - struct dc *dc = pool->oem_device->ctx->dc; - - dc->link_srv->destroy_ddc_service(&pool->oem_device); - } -} - -static void dcn302_destroy_resource_pool(struct resource_pool **pool) -{ - dcn302_resource_destruct(*pool); - kfree(*pool); - *pool = NULL; -} - -void dcn302_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) -{ - DC_FP_START(); - dcn302_fpu_update_bw_bounding_box(dc, bw_params); - DC_FP_END(); -} - -static void dcn302_get_panel_config_defaults(struct dc_panel_config *panel_config) -{ - *panel_config = panel_config_defaults; -} - -static struct resource_funcs dcn302_res_pool_funcs = { - .destroy = dcn302_destroy_resource_pool, - .link_enc_create = dcn302_link_encoder_create, - .panel_cntl_create = dcn302_panel_cntl_create, - .validate_bandwidth = dcn30_validate_bandwidth, - .calculate_wm_and_dlg = dcn30_calculate_wm_and_dlg, - .update_soc_for_wm_a = dcn30_update_soc_for_wm_a, - .populate_dml_pipes = dcn30_populate_dml_pipes_from_context, - .acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer, - .release_pipe = dcn20_release_pipe, - .add_stream_to_ctx = dcn30_add_stream_to_ctx, - .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource, - .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, - .populate_dml_writeback_from_context = dcn30_populate_dml_writeback_from_context, - .set_mcif_arb_params = dcn30_set_mcif_arb_params, - .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 = dcn302_update_bw_bounding_box, - .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, - .get_panel_config_defaults = dcn302_get_panel_config_defaults, -}; - -static struct dc_cap_funcs cap_funcs = { - .get_dcc_compression_cap = dcn20_get_dcc_compression_cap -}; - -static const struct bios_registers bios_regs = { - NBIO_SR(BIOS_SCRATCH_3), - NBIO_SR(BIOS_SCRATCH_6) -}; - -static const struct dccg_registers dccg_regs = { - DCCG_REG_LIST_DCN3_02() -}; - -static const struct dccg_shift dccg_shift = { - DCCG_MASK_SH_LIST_DCN3_02(__SHIFT) -}; - -static const struct dccg_mask dccg_mask = { - DCCG_MASK_SH_LIST_DCN3_02(_MASK) -}; - -#define abm_regs(id)\ - [id] = { ABM_DCN302_REG_LIST(id) } - -static const struct dce_abm_registers abm_regs[] = { - abm_regs(0), - abm_regs(1), - abm_regs(2), - abm_regs(3), - abm_regs(4) -}; - -static const struct dce_abm_shift abm_shift = { - ABM_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dce_abm_mask abm_mask = { - ABM_MASK_SH_LIST_DCN30(_MASK) -}; - -static bool dcn302_resource_construct( - uint8_t num_virtual_links, - struct dc *dc, - struct resource_pool *pool) -{ - 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; - - pool->res_cap = &res_cap_dcn302; - - pool->funcs = &dcn302_res_pool_funcs; - - /************************************************* - * Resource + asic cap harcoding * - *************************************************/ - pool->underlay_pipe_index = NO_UNDERLAY_PIPE; - pool->pipe_count = pool->res_cap->num_timing_generator; - pool->mpcc_count = pool->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 = 5; /*1.4 w/a applied by derfault*/ - dc->caps.max_cursor_size = 256; - dc->caps.min_horizontal_blanking_period = 80; - dc->caps.dmdata_alloc_size = 2048; - dc->caps.mall_size_per_mem_channel = 4; - /* total size = mall per channel * num channels * 1024 * 1024 */ - dc->caps.mall_size_total = dc->caps.mall_size_per_mem_channel * dc->ctx->dc_bios->vram_info.num_chans * 1048576; - dc->caps.cursor_cache_size = dc->caps.max_cursor_size * dc->caps.max_cursor_size * 8; - dc->caps.max_slave_planes = 2; - dc->caps.max_slave_yuv_planes = 2; - dc->caps.max_slave_rgb_planes = 2; - dc->caps.post_blend_color_processing = true; - dc->caps.force_dp_tps4_for_cp2520 = true; - dc->caps.extended_aux_timeout_support = true; - dc->caps.dmcub_support = true; - dc->caps.max_v_total = (1 << 15) - 1; - - /* Color pipeline capabilities */ - dc->caps.color.dpp.dcn_arch = 1; - dc->caps.color.dpp.input_lut_shared = 0; - dc->caps.color.dpp.icsc = 1; - dc->caps.color.dpp.dgam_ram = 0; // must use gamma_corr - dc->caps.color.dpp.dgam_rom_caps.srgb = 1; - dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1; - dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 1; - dc->caps.color.dpp.dgam_rom_caps.pq = 1; - dc->caps.color.dpp.dgam_rom_caps.hlg = 1; - dc->caps.color.dpp.post_csc = 1; - dc->caps.color.dpp.gamma_corr = 1; - dc->caps.color.dpp.dgam_rom_for_yuv = 0; - - dc->caps.color.dpp.hw_3d_lut = 1; - dc->caps.color.dpp.ogam_ram = 1; - // no OGAM ROM on DCN3 - dc->caps.color.dpp.ogam_rom_caps.srgb = 0; - dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0; - dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0; - dc->caps.color.dpp.ogam_rom_caps.pq = 0; - dc->caps.color.dpp.ogam_rom_caps.hlg = 0; - dc->caps.color.dpp.ocsc = 0; - - dc->caps.color.mpc.gamut_remap = 1; - dc->caps.color.mpc.num_3dluts = pool->res_cap->num_mpc_3dlut; //3 - dc->caps.color.mpc.ogam_ram = 1; - dc->caps.color.mpc.ogam_rom_caps.srgb = 0; - dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0; - dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0; - dc->caps.color.mpc.ogam_rom_caps.pq = 0; - dc->caps.color.mpc.ogam_rom_caps.hlg = 0; - dc->caps.color.mpc.ocsc = 1; - - dc->caps.dp_hdmi21_pcon_support = true; - - /* read VBIOS LTTPR caps */ - if (ctx->dc_bios->funcs->get_lttpr_caps) { - enum bp_result bp_query_result; - uint8_t is_vbios_lttpr_enable = 0; - - bp_query_result = ctx->dc_bios->funcs->get_lttpr_caps(ctx->dc_bios, &is_vbios_lttpr_enable); - dc->caps.vbios_lttpr_enable = (bp_query_result == BP_RESULT_OK) && !!is_vbios_lttpr_enable; - } - - if (ctx->dc_bios->funcs->get_lttpr_interop) { - enum bp_result bp_query_result; - uint8_t is_vbios_interop_enabled = 0; - - bp_query_result = ctx->dc_bios->funcs->get_lttpr_interop(ctx->dc_bios, - &is_vbios_interop_enabled); - dc->caps.vbios_lttpr_aware = (bp_query_result == BP_RESULT_OK) && !!is_vbios_interop_enabled; - } - - if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) - dc->debug = debug_defaults_drv; - - // Init the vm_helper - if (dc->vm_helper) - vm_helper_init(dc->vm_helper, 16); - - /************************************************* - * Create resources * - *************************************************/ - - /* Clock Sources for Pixel Clock*/ - pool->clock_sources[DCN302_CLK_SRC_PLL0] = - dcn302_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL0, - &clk_src_regs[0], false); - pool->clock_sources[DCN302_CLK_SRC_PLL1] = - dcn302_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL1, - &clk_src_regs[1], false); - pool->clock_sources[DCN302_CLK_SRC_PLL2] = - dcn302_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL2, - &clk_src_regs[2], false); - pool->clock_sources[DCN302_CLK_SRC_PLL3] = - dcn302_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL3, - &clk_src_regs[3], false); - pool->clock_sources[DCN302_CLK_SRC_PLL4] = - dcn302_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL4, - &clk_src_regs[4], false); - - pool->clk_src_count = DCN302_CLK_SRC_TOTAL; - - /* todo: not reuse phy_pll registers */ - pool->dp_clock_source = - dcn302_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_ID_DP_DTO, - &clk_src_regs[0], true); - - for (i = 0; i < pool->clk_src_count; i++) { - if (pool->clock_sources[i] == NULL) { - dm_error("DC: failed to create clock sources!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - } - - /* DCCG */ - pool->dccg = dccg30_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask); - if (pool->dccg == NULL) { - dm_error("DC: failed to create dccg!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - - /* PP Lib and SMU interfaces */ - init_soc_bounding_box(dc, pool); - - /* DML */ - dml_init_instance(&dc->dml, &dcn3_02_soc, &dcn3_02_ip, DML_PROJECT_DCN30); - - /* IRQ */ - init_data.ctx = dc->ctx; - pool->irqs = dal_irq_service_dcn302_create(&init_data); - if (!pool->irqs) - goto create_fail; - - /* HUBBUB */ - pool->hubbub = dcn302_hubbub_create(ctx); - if (pool->hubbub == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create hubbub!\n"); - goto create_fail; - } - - /* HUBPs, DPPs, OPPs and TGs */ - for (i = 0; i < pool->pipe_count; i++) { - pool->hubps[i] = dcn302_hubp_create(ctx, i); - if (pool->hubps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create hubps!\n"); - goto create_fail; - } - - pool->dpps[i] = dcn302_dpp_create(ctx, i); - if (pool->dpps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create dpps!\n"); - goto create_fail; - } - } - - for (i = 0; i < pool->res_cap->num_opp; i++) { - pool->opps[i] = dcn302_opp_create(ctx, i); - if (pool->opps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create output pixel processor!\n"); - goto create_fail; - } - } - - for (i = 0; i < pool->res_cap->num_timing_generator; i++) { - pool->timing_generators[i] = dcn302_timing_generator_create(ctx, i); - if (pool->timing_generators[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create tg!\n"); - goto create_fail; - } - } - pool->timing_generator_count = i; - - /* PSR */ - pool->psr = dmub_psr_create(ctx); - if (pool->psr == NULL) { - dm_error("DC: failed to create psr!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - - /* ABMs */ - for (i = 0; i < pool->res_cap->num_timing_generator; i++) { - pool->multiple_abms[i] = dmub_abm_create(ctx, &abm_regs[i], &abm_shift, &abm_mask); - if (pool->multiple_abms[i] == NULL) { - dm_error("DC: failed to create abm for pipe %d!\n", i); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - } - - /* MPC and DSC */ - pool->mpc = dcn302_mpc_create(ctx, pool->mpcc_count, pool->res_cap->num_mpc_3dlut); - if (pool->mpc == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create mpc!\n"); - goto create_fail; - } - - for (i = 0; i < pool->res_cap->num_dsc; i++) { - pool->dscs[i] = dcn302_dsc_create(ctx, i); - if (pool->dscs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create display stream compressor %d!\n", i); - goto create_fail; - } - } - - /* DWB and MMHUBBUB */ - if (!dcn302_dwbc_create(ctx, pool)) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create dwbc!\n"); - goto create_fail; - } - - if (!dcn302_mmhubbub_create(ctx, pool)) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create mcif_wb!\n"); - goto create_fail; - } - - /* AUX and I2C */ - for (i = 0; i < pool->res_cap->num_ddc; i++) { - pool->engines[i] = dcn302_aux_engine_create(ctx, i); - if (pool->engines[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC:failed to create aux engine!!\n"); - goto create_fail; - } - pool->hw_i2cs[i] = dcn302_i2c_hw_create(ctx, i); - if (pool->hw_i2cs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC:failed to create hw i2c!!\n"); - goto create_fail; - } - pool->sw_i2cs[i] = NULL; - } - - /* Audio, Stream Encoders including HPO and virtual, MPC 3D LUTs */ - if (!resource_construct(num_virtual_links, dc, pool, - &res_create_funcs)) - goto create_fail; - - /* HW Sequencer and Plane caps */ - dcn302_hw_sequencer_construct(dc); - - dc->caps.max_planes = pool->pipe_count; - - for (i = 0; i < dc->caps.max_planes; ++i) - dc->caps.planes[i] = plane_cap; - - 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 = dc->link_srv->create_ddc_service(&ddc_init_data); - } else { - pool->oem_device = NULL; - } - - return true; - -create_fail: - - dcn302_resource_destruct(pool); - - return false; -} - -struct resource_pool *dcn302_create_resource_pool(const struct dc_init_data *init_data, struct dc *dc) -{ - struct resource_pool *pool = kzalloc(sizeof(struct resource_pool), GFP_KERNEL); - - if (!pool) - return NULL; - - if (dcn302_resource_construct(init_data->num_virtual_links, dc, pool)) - return pool; - - BREAK_TO_DEBUGGER(); - kfree(pool); - return NULL; -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.h b/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.h deleted file mode 100644 index 9f24e73b92b314..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2020 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 _DCN302_RESOURCE_H_ -#define _DCN302_RESOURCE_H_ - -#include "core_types.h" - -extern struct _vcs_dpi_ip_params_st dcn3_02_ip; -extern struct _vcs_dpi_soc_bounding_box_st dcn3_02_soc; - -struct resource_pool *dcn302_create_resource_pool(const struct dc_init_data *init_data, struct dc *dc); - -void dcn302_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params); - -#endif /* _DCN302_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn303/Makefile b/drivers/gpu/drm/amd/display/dc/dcn303/Makefile index d7b3ad780e5db8..a954e316aca254 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn303/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn303/Makefile @@ -6,7 +6,7 @@ # # Makefile for dcn303. -DCN3_03 = dcn303_init.o dcn303_resource.o +DCN3_03 = dcn303_init.o AMD_DAL_DCN3_03 = $(addprefix $(AMDDALPATH)/dc/dcn303/,$(DCN3_03)) diff --git a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_init.c b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_init.c deleted file mode 100644 index edb4d68b81871c..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_init.c +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - * Copyright (C) 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 "dcn303/dcn303_hwseq.h" -#include "dcn30/dcn30_init.h" -#include "dc.h" - -#include "dcn303_init.h" - -void dcn303_hw_sequencer_construct(struct dc *dc) -{ - dcn30_hw_sequencer_construct(dc); - - dc->hwseq->funcs.dpp_pg_control = dcn303_dpp_pg_control; - dc->hwseq->funcs.hubp_pg_control = dcn303_hubp_pg_control; - dc->hwseq->funcs.dsc_pg_control = dcn303_dsc_pg_control; - dc->hwseq->funcs.enable_power_gating_plane = dcn303_enable_power_gating_plane; -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_init.h b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_init.h deleted file mode 100644 index 4949981126d762..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_init.h +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - * Copyright (C) 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_DCN303_INIT_H__ -#define __DC_DCN303_INIT_H__ - -struct dc; - -void dcn303_hw_sequencer_construct(struct dc *dc); - -#endif /* __DC_DCN303_INIT_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c deleted file mode 100644 index 49cb7fde416a4d..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c +++ /dev/null @@ -1,1448 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - * Copyright (C) 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 "dcn303_init.h" -#include "dcn303_resource.h" -#include "dcn303_dccg.h" -#include "irq/dcn303/irq_service_dcn303.h" - -#include "dcn30/dcn30_dio_link_encoder.h" -#include "dcn30/dcn30_dio_stream_encoder.h" -#include "dcn30/dcn30_dpp.h" -#include "dcn30/dcn30_dwb.h" -#include "dcn30/dcn30_hubbub.h" -#include "dcn30/dcn30_hubp.h" -#include "dcn30/dcn30_mmhubbub.h" -#include "dcn30/dcn30_mpc.h" -#include "dcn30/dcn30_opp.h" -#include "dcn30/dcn30_optc.h" -#include "dcn30/dcn30_resource.h" - -#include "dcn20/dcn20_dsc.h" -#include "dcn20/dcn20_resource.h" - -#include "dml/dcn30/dcn30_fpu.h" - -#include "dcn10/dcn10_resource.h" - -#include "link.h" - -#include "dce/dce_abm.h" -#include "dce/dce_audio.h" -#include "dce/dce_aux.h" -#include "dce/dce_clock_source.h" -#include "dce/dce_hwseq.h" -#include "dce/dce_i2c_hw.h" -#include "dce/dce_panel_cntl.h" -#include "dce/dmub_abm.h" -#include "dce/dmub_psr.h" -#include "clk_mgr.h" - -#include "hw_sequencer_private.h" -#include "reg_helper.h" -#include "resource.h" -#include "vm_helper.h" - -#include "sienna_cichlid_ip_offset.h" -#include "dcn/dcn_3_0_3_offset.h" -#include "dcn/dcn_3_0_3_sh_mask.h" -#include "dpcs/dpcs_3_0_3_offset.h" -#include "dpcs/dpcs_3_0_3_sh_mask.h" -#include "nbio/nbio_2_3_offset.h" - -#include "dml/dcn303/dcn303_fpu.h" - -#define DC_LOGGER \ - dc->ctx->logger -#define DC_LOGGER_INIT(logger) - - -static const struct dc_debug_options debug_defaults_drv = { - .disable_dmcu = true, - .force_abm_enable = false, - .timing_trace = false, - .clock_trace = true, - .disable_pplib_clock_request = true, - .pipe_split_policy = MPC_SPLIT_AVOID, - .force_single_disp_pipe_split = false, - .disable_dcc = DCC_ENABLE, - .vsr_support = true, - .performance_trace = false, - .max_downscale_src_width = 7680,/*upto 8K*/ - .disable_pplib_wm_range = false, - .scl_reset_length10 = true, - .sanity_checks = false, - .underflow_assert_delay_us = 0xFFFFFFFF, - .dwb_fi_phase = -1, // -1 = disable, - .dmub_command_table = true, - .exit_idle_opt_for_cursor_updates = true, - .disable_idle_power_optimizations = false, - .using_dml2 = false, -}; - -static const struct dc_panel_config panel_config_defaults = { - .psr = { - .disable_psr = false, - .disallow_psrsu = false, - .disallow_replay = false, - }, -}; - -enum dcn303_clk_src_array_id { - DCN303_CLK_SRC_PLL0, - DCN303_CLK_SRC_PLL1, - DCN303_CLK_SRC_TOTAL -}; - -static const struct resource_caps res_cap_dcn303 = { - .num_timing_generator = 2, - .num_opp = 2, - .num_video_plane = 2, - .num_audio = 2, - .num_stream_encoder = 2, - .num_dwb = 1, - .num_ddc = 2, - .num_vmid = 16, - .num_mpc_3dlut = 1, - .num_dsc = 2, -}; - -static const struct dc_plane_cap plane_cap = { - .type = DC_PLANE_TYPE_DCN_UNIVERSAL, - .per_pixel_alpha = true, - .pixel_format_support = { - .argb8888 = true, - .nv12 = true, - .fp16 = true, - .p010 = true, - .ayuv = false, - }, - .max_upscale_factor = { - .argb8888 = 16000, - .nv12 = 16000, - .fp16 = 16000 - }, - .max_downscale_factor = { - .argb8888 = 600, - .nv12 = 600, - .fp16 = 600 - }, - 16, - 16 -}; - -/* NBIO */ -#define NBIO_BASE_INNER(seg) \ - NBIO_BASE__INST0_SEG ## seg - -#define NBIO_BASE(seg) \ - NBIO_BASE_INNER(seg) - -#define NBIO_SR(reg_name)\ - .reg_name = NBIO_BASE(mm ## reg_name ## _BASE_IDX) + \ - mm ## reg_name - -/* DCN */ -#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg - -#define BASE(seg) BASE_INNER(seg) - -#define SR(reg_name)\ - .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + mm ## reg_name - -#define SF(reg_name, field_name, post_fix)\ - .field_name = reg_name ## __ ## field_name ## post_fix - -#define SRI(reg_name, block, id)\ - .reg_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + mm ## block ## id ## _ ## reg_name - -#define SRI2(reg_name, block, id)\ - .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + mm ## reg_name - -#define SRII(reg_name, block, id)\ - .reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name - -#define DCCG_SRII(reg_name, block, id)\ - .block ## _ ## reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name - -#define VUPDATE_SRII(reg_name, block, id)\ - .reg_name[id] = BASE(mm ## reg_name ## _ ## block ## id ## _BASE_IDX) + \ - mm ## reg_name ## _ ## block ## id - -#define SRII_DWB(reg_name, temp_name, block, id)\ - .reg_name[id] = BASE(mm ## block ## id ## _ ## temp_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## temp_name - -#define SF_DWB2(reg_name, block, id, field_name, post_fix) \ - .field_name = reg_name ## __ ## field_name ## post_fix - -#define SRII_MPC_RMU(reg_name, block, id)\ - .RMU##_##reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - mm ## block ## id ## _ ## reg_name - -static const struct dcn_hubbub_registers hubbub_reg = { - HUBBUB_REG_LIST_DCN30(0) -}; - -static const struct dcn_hubbub_shift hubbub_shift = { - HUBBUB_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn_hubbub_mask hubbub_mask = { - HUBBUB_MASK_SH_LIST_DCN30(_MASK) -}; - -#define vmid_regs(id)\ - [id] = { DCN20_VMID_REG_LIST(id) } - -static const struct dcn_vmid_registers vmid_regs[] = { - vmid_regs(0), - vmid_regs(1), - vmid_regs(2), - vmid_regs(3), - vmid_regs(4), - vmid_regs(5), - vmid_regs(6), - vmid_regs(7), - vmid_regs(8), - vmid_regs(9), - vmid_regs(10), - vmid_regs(11), - vmid_regs(12), - vmid_regs(13), - vmid_regs(14), - vmid_regs(15) -}; - -static const struct dcn20_vmid_shift vmid_shifts = { - DCN20_VMID_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn20_vmid_mask vmid_masks = { - DCN20_VMID_MASK_SH_LIST(_MASK) -}; - -static struct hubbub *dcn303_hubbub_create(struct dc_context *ctx) -{ - int i; - - struct dcn20_hubbub *hubbub3 = kzalloc(sizeof(struct dcn20_hubbub), GFP_KERNEL); - - if (!hubbub3) - return NULL; - - hubbub3_construct(hubbub3, ctx, &hubbub_reg, &hubbub_shift, &hubbub_mask); - - for (i = 0; i < res_cap_dcn303.num_vmid; i++) { - struct dcn20_vmid *vmid = &hubbub3->vmid[i]; - - vmid->ctx = ctx; - - vmid->regs = &vmid_regs[i]; - vmid->shifts = &vmid_shifts; - vmid->masks = &vmid_masks; - } - - return &hubbub3->base; -} - -#define vpg_regs(id)\ - [id] = { VPG_DCN3_REG_LIST(id) } - -static const struct dcn30_vpg_registers vpg_regs[] = { - vpg_regs(0), - vpg_regs(1), - vpg_regs(2) -}; - -static const struct dcn30_vpg_shift vpg_shift = { - DCN3_VPG_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn30_vpg_mask vpg_mask = { - DCN3_VPG_MASK_SH_LIST(_MASK) -}; - -static struct vpg *dcn303_vpg_create(struct dc_context *ctx, uint32_t inst) -{ - struct dcn30_vpg *vpg3 = kzalloc(sizeof(struct dcn30_vpg), GFP_KERNEL); - - if (!vpg3) - return NULL; - - vpg3_construct(vpg3, ctx, inst, &vpg_regs[inst], &vpg_shift, &vpg_mask); - - return &vpg3->base; -} - -#define afmt_regs(id)\ - [id] = { AFMT_DCN3_REG_LIST(id) } - -static const struct dcn30_afmt_registers afmt_regs[] = { - afmt_regs(0), - afmt_regs(1), - afmt_regs(2) -}; - -static const struct dcn30_afmt_shift afmt_shift = { - DCN3_AFMT_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn30_afmt_mask afmt_mask = { - DCN3_AFMT_MASK_SH_LIST(_MASK) -}; - -static struct afmt *dcn303_afmt_create(struct dc_context *ctx, uint32_t inst) -{ - struct dcn30_afmt *afmt3 = kzalloc(sizeof(struct dcn30_afmt), GFP_KERNEL); - - if (!afmt3) - return NULL; - - afmt3_construct(afmt3, ctx, inst, &afmt_regs[inst], &afmt_shift, &afmt_mask); - - return &afmt3->base; -} - -#define audio_regs(id)\ - [id] = { AUD_COMMON_REG_LIST(id) } - -static const struct dce_audio_registers audio_regs[] = { - audio_regs(0), - audio_regs(1), - audio_regs(2), - audio_regs(3), - audio_regs(4), - audio_regs(5), - audio_regs(6) -}; - -#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ - SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ - SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ - AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) - -static const struct dce_audio_shift audio_shift = { - DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_audio_mask audio_mask = { - DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) -}; - -static struct audio *dcn303_create_audio(struct dc_context *ctx, unsigned int inst) -{ - return dce_audio_create(ctx, inst, &audio_regs[inst], &audio_shift, &audio_mask); -} - -#define stream_enc_regs(id)\ - [id] = { SE_DCN3_REG_LIST(id) } - -static const struct dcn10_stream_enc_registers stream_enc_regs[] = { - stream_enc_regs(0), - stream_enc_regs(1) -}; - -static const struct dcn10_stream_encoder_shift se_shift = { - SE_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn10_stream_encoder_mask se_mask = { - SE_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -static struct stream_encoder *dcn303_stream_encoder_create(enum engine_id eng_id, struct dc_context *ctx) -{ - struct dcn10_stream_encoder *enc1; - struct vpg *vpg; - struct afmt *afmt; - int vpg_inst; - int afmt_inst; - - /* Mapping of VPG, AFMT, DME register blocks to DIO block instance */ - if (eng_id <= ENGINE_ID_DIGB) { - vpg_inst = eng_id; - afmt_inst = eng_id; - } else - return NULL; - - enc1 = kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL); - vpg = dcn303_vpg_create(ctx, vpg_inst); - afmt = dcn303_afmt_create(ctx, afmt_inst); - - if (!enc1 || !vpg || !afmt) { - kfree(enc1); - kfree(vpg); - kfree(afmt); - return NULL; - } - - dcn30_dio_stream_encoder_construct(enc1, ctx, ctx->dc_bios, eng_id, vpg, afmt, &stream_enc_regs[eng_id], - &se_shift, &se_mask); - - return &enc1->base; -} - -#define clk_src_regs(index, pllid)\ - [index] = { CS_COMMON_REG_LIST_DCN3_03(index, pllid) } - -static const struct dce110_clk_src_regs clk_src_regs[] = { - clk_src_regs(0, A), - clk_src_regs(1, B) -}; - -static const struct dce110_clk_src_shift cs_shift = { - CS_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) -}; - -static const struct dce110_clk_src_mask cs_mask = { - CS_COMMON_MASK_SH_LIST_DCN2_0(_MASK) -}; - -static struct clock_source *dcn303_clock_source_create(struct dc_context *ctx, struct dc_bios *bios, - enum clock_source_id id, const struct dce110_clk_src_regs *regs, bool dp_clk_src) -{ - struct dce110_clk_src *clk_src = kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); - - if (!clk_src) - return NULL; - - if (dcn3_clk_src_construct(clk_src, ctx, bios, id, regs, &cs_shift, &cs_mask)) { - clk_src->base.dp_clk_src = dp_clk_src; - return &clk_src->base; - } - - kfree(clk_src); - BREAK_TO_DEBUGGER(); - return NULL; -} - -static const struct dce_hwseq_registers hwseq_reg = { - HWSEQ_DCN303_REG_LIST() -}; - -static const struct dce_hwseq_shift hwseq_shift = { - HWSEQ_DCN303_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_hwseq_mask hwseq_mask = { - HWSEQ_DCN303_MASK_SH_LIST(_MASK) -}; - -static struct dce_hwseq *dcn303_hwseq_create(struct dc_context *ctx) -{ - struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); - - if (hws) { - hws->ctx = ctx; - hws->regs = &hwseq_reg; - hws->shifts = &hwseq_shift; - hws->masks = &hwseq_mask; - } - return hws; -} - -#define hubp_regs(id)\ - [id] = { HUBP_REG_LIST_DCN30(id) } - -static const struct dcn_hubp2_registers hubp_regs[] = { - hubp_regs(0), - hubp_regs(1) -}; - -static const struct dcn_hubp2_shift hubp_shift = { - HUBP_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn_hubp2_mask hubp_mask = { - HUBP_MASK_SH_LIST_DCN30(_MASK) -}; - -static struct hubp *dcn303_hubp_create(struct dc_context *ctx, uint32_t inst) -{ - struct dcn20_hubp *hubp2 = kzalloc(sizeof(struct dcn20_hubp), GFP_KERNEL); - - if (!hubp2) - return NULL; - - if (hubp3_construct(hubp2, ctx, inst, &hubp_regs[inst], &hubp_shift, &hubp_mask)) - return &hubp2->base; - - BREAK_TO_DEBUGGER(); - kfree(hubp2); - return NULL; -} - -#define dpp_regs(id)\ - [id] = { DPP_REG_LIST_DCN30(id) } - -static const struct dcn3_dpp_registers dpp_regs[] = { - dpp_regs(0), - dpp_regs(1) -}; - -static const struct dcn3_dpp_shift tf_shift = { - DPP_REG_LIST_SH_MASK_DCN30(__SHIFT) -}; - -static const struct dcn3_dpp_mask tf_mask = { - DPP_REG_LIST_SH_MASK_DCN30(_MASK) -}; - -static struct dpp *dcn303_dpp_create(struct dc_context *ctx, uint32_t inst) -{ - struct dcn3_dpp *dpp = kzalloc(sizeof(struct dcn3_dpp), GFP_KERNEL); - - if (!dpp) - return NULL; - - if (dpp3_construct(dpp, ctx, inst, &dpp_regs[inst], &tf_shift, &tf_mask)) - return &dpp->base; - - BREAK_TO_DEBUGGER(); - kfree(dpp); - return NULL; -} - -#define opp_regs(id)\ - [id] = { OPP_REG_LIST_DCN30(id) } - -static const struct dcn20_opp_registers opp_regs[] = { - opp_regs(0), - opp_regs(1) -}; - -static const struct dcn20_opp_shift opp_shift = { - OPP_MASK_SH_LIST_DCN20(__SHIFT) -}; - -static const struct dcn20_opp_mask opp_mask = { - OPP_MASK_SH_LIST_DCN20(_MASK) -}; - -static struct output_pixel_processor *dcn303_opp_create(struct dc_context *ctx, uint32_t inst) -{ - struct dcn20_opp *opp = kzalloc(sizeof(struct dcn20_opp), GFP_KERNEL); - - if (!opp) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dcn20_opp_construct(opp, ctx, inst, &opp_regs[inst], &opp_shift, &opp_mask); - return &opp->base; -} - -#define optc_regs(id)\ - [id] = { OPTC_COMMON_REG_LIST_DCN3_0(id) } - -static const struct dcn_optc_registers optc_regs[] = { - optc_regs(0), - optc_regs(1) -}; - -static const struct dcn_optc_shift optc_shift = { - OPTC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn_optc_mask optc_mask = { - OPTC_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -static struct timing_generator *dcn303_timing_generator_create(struct dc_context *ctx, uint32_t instance) -{ - struct optc *tgn10 = kzalloc(sizeof(struct optc), GFP_KERNEL); - - if (!tgn10) - return NULL; - - tgn10->base.inst = instance; - tgn10->base.ctx = ctx; - - tgn10->tg_regs = &optc_regs[instance]; - tgn10->tg_shift = &optc_shift; - tgn10->tg_mask = &optc_mask; - - dcn30_timing_generator_init(tgn10); - - return &tgn10->base; -} - -static const struct dcn30_mpc_registers mpc_regs = { - MPC_REG_LIST_DCN3_0(0), - MPC_REG_LIST_DCN3_0(1), - MPC_OUT_MUX_REG_LIST_DCN3_0(0), - MPC_OUT_MUX_REG_LIST_DCN3_0(1), - MPC_RMU_GLOBAL_REG_LIST_DCN3AG, - MPC_RMU_REG_LIST_DCN3AG(0), - MPC_DWB_MUX_REG_LIST_DCN3_0(0), -}; - -static const struct dcn30_mpc_shift mpc_shift = { - MPC_COMMON_MASK_SH_LIST_DCN303(__SHIFT) -}; - -static const struct dcn30_mpc_mask mpc_mask = { - MPC_COMMON_MASK_SH_LIST_DCN303(_MASK) -}; - -static struct mpc *dcn303_mpc_create(struct dc_context *ctx, int num_mpcc, int num_rmu) -{ - struct dcn30_mpc *mpc30 = kzalloc(sizeof(struct dcn30_mpc), GFP_KERNEL); - - if (!mpc30) - return NULL; - - dcn30_mpc_construct(mpc30, ctx, &mpc_regs, &mpc_shift, &mpc_mask, num_mpcc, num_rmu); - - return &mpc30->base; -} - -#define dsc_regsDCN20(id)\ -[id] = { DSC_REG_LIST_DCN20(id) } - -static const struct dcn20_dsc_registers dsc_regs[] = { - dsc_regsDCN20(0), - dsc_regsDCN20(1) -}; - -static const struct dcn20_dsc_shift dsc_shift = { - DSC_REG_LIST_SH_MASK_DCN20(__SHIFT) -}; - -static const struct dcn20_dsc_mask dsc_mask = { - DSC_REG_LIST_SH_MASK_DCN20(_MASK) -}; - -static struct display_stream_compressor *dcn303_dsc_create(struct dc_context *ctx, uint32_t inst) -{ - struct dcn20_dsc *dsc = kzalloc(sizeof(struct dcn20_dsc), GFP_KERNEL); - - if (!dsc) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dsc2_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask); - return &dsc->base; -} - -#define dwbc_regs_dcn3(id)\ -[id] = { DWBC_COMMON_REG_LIST_DCN30(id) } - -static const struct dcn30_dwbc_registers dwbc30_regs[] = { - dwbc_regs_dcn3(0) -}; - -static const struct dcn30_dwbc_shift dwbc30_shift = { - DWBC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn30_dwbc_mask dwbc30_mask = { - DWBC_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -static bool dcn303_dwbc_create(struct dc_context *ctx, struct resource_pool *pool) -{ - int i; - uint32_t pipe_count = pool->res_cap->num_dwb; - - for (i = 0; i < pipe_count; i++) { - struct dcn30_dwbc *dwbc30 = kzalloc(sizeof(struct dcn30_dwbc), GFP_KERNEL); - - if (!dwbc30) { - dm_error("DC: failed to create dwbc30!\n"); - return false; - } - - dcn30_dwbc_construct(dwbc30, ctx, &dwbc30_regs[i], &dwbc30_shift, &dwbc30_mask, i); - - pool->dwbc[i] = &dwbc30->base; - } - return true; -} - -#define mcif_wb_regs_dcn3(id)\ -[id] = { MCIF_WB_COMMON_REG_LIST_DCN30(id) } - -static const struct dcn30_mmhubbub_registers mcif_wb30_regs[] = { - mcif_wb_regs_dcn3(0) -}; - -static const struct dcn30_mmhubbub_shift mcif_wb30_shift = { - MCIF_WB_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn30_mmhubbub_mask mcif_wb30_mask = { - MCIF_WB_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -static bool dcn303_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool) -{ - int i; - uint32_t pipe_count = pool->res_cap->num_dwb; - - for (i = 0; i < pipe_count; i++) { - struct dcn30_mmhubbub *mcif_wb30 = kzalloc(sizeof(struct dcn30_mmhubbub), GFP_KERNEL); - - if (!mcif_wb30) { - dm_error("DC: failed to create mcif_wb30!\n"); - return false; - } - - dcn30_mmhubbub_construct(mcif_wb30, ctx, &mcif_wb30_regs[i], &mcif_wb30_shift, &mcif_wb30_mask, i); - - pool->mcif_wb[i] = &mcif_wb30->base; - } - return true; -} - -#define aux_engine_regs(id)\ -[id] = {\ - AUX_COMMON_REG_LIST0(id), \ - .AUXN_IMPCAL = 0, \ - .AUXP_IMPCAL = 0, \ - .AUX_RESET_MASK = DP_AUX0_AUX_CONTROL__AUX_RESET_MASK, \ -} - -static const struct dce110_aux_registers aux_engine_regs[] = { - aux_engine_regs(0), - aux_engine_regs(1) -}; - -static const struct dce110_aux_registers_shift aux_shift = { - DCN_AUX_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce110_aux_registers_mask aux_mask = { - DCN_AUX_MASK_SH_LIST(_MASK) -}; - -static struct dce_aux *dcn303_aux_engine_create(struct dc_context *ctx, uint32_t inst) -{ - struct aux_engine_dce110 *aux_engine = kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); - - if (!aux_engine) - return NULL; - - dce110_aux_engine_construct(aux_engine, ctx, inst, SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, - &aux_engine_regs[inst], &aux_mask, &aux_shift, ctx->dc->caps.extended_aux_timeout_support); - - return &aux_engine->base; -} - -#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST(id) } - -static const struct dce_i2c_registers i2c_hw_regs[] = { - i2c_inst_regs(1), - i2c_inst_regs(2) -}; - -static const struct dce_i2c_shift i2c_shifts = { - I2C_COMMON_MASK_SH_LIST_DCN2(__SHIFT) -}; - -static const struct dce_i2c_mask i2c_masks = { - I2C_COMMON_MASK_SH_LIST_DCN2(_MASK) -}; - -static struct dce_i2c_hw *dcn303_i2c_hw_create(struct dc_context *ctx, uint32_t inst) -{ - struct dce_i2c_hw *dce_i2c_hw = kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); - - if (!dce_i2c_hw) - return NULL; - - dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst, &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); - - return dce_i2c_hw; -} - -static const struct encoder_feature_support link_enc_feature = { - .max_hdmi_deep_color = COLOR_DEPTH_121212, - .max_hdmi_pixel_clock = 600000, - .hdmi_ycbcr420_supported = true, - .dp_ycbcr420_supported = true, - .fec_supported = true, - .flags.bits.IS_HBR2_CAPABLE = true, - .flags.bits.IS_HBR3_CAPABLE = true, - .flags.bits.IS_TPS3_CAPABLE = true, - .flags.bits.IS_TPS4_CAPABLE = true -}; - -#define link_regs(id, phyid)\ - [id] = {\ - LE_DCN3_REG_LIST(id), \ - UNIPHY_DCN2_REG_LIST(phyid), \ - SRI(DP_DPHY_INTERNAL_CTRL, DP, id) \ - } - -static const struct dcn10_link_enc_registers link_enc_regs[] = { - link_regs(0, A), - link_regs(1, B) -}; - -static const struct dcn10_link_enc_shift le_shift = { - LINK_ENCODER_MASK_SH_LIST_DCN30(__SHIFT), - DPCS_DCN2_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn10_link_enc_mask le_mask = { - LINK_ENCODER_MASK_SH_LIST_DCN30(_MASK), - DPCS_DCN2_MASK_SH_LIST(_MASK) -}; - -#define aux_regs(id)\ - [id] = { DCN2_AUX_REG_LIST(id) } - -static const struct dcn10_link_enc_aux_registers link_enc_aux_regs[] = { - aux_regs(0), - aux_regs(1) -}; - -#define hpd_regs(id)\ - [id] = { HPD_REG_LIST(id) } - -static const struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[] = { - hpd_regs(0), - hpd_regs(1) -}; - -static struct link_encoder *dcn303_link_encoder_create( - struct dc_context *ctx, - const struct encoder_init_data *enc_init_data) -{ - struct dcn20_link_encoder *enc20 = kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); - - if (!enc20) - return NULL; - - dcn30_link_encoder_construct(enc20, enc_init_data, &link_enc_feature, - &link_enc_regs[enc_init_data->transmitter], &link_enc_aux_regs[enc_init_data->channel - 1], - &link_enc_hpd_regs[enc_init_data->hpd_source], &le_shift, &le_mask); - - return &enc20->enc10.base; -} - -static const struct dce_panel_cntl_registers panel_cntl_regs[] = { - { DCN_PANEL_CNTL_REG_LIST() } -}; - -static const struct dce_panel_cntl_shift panel_cntl_shift = { - DCE_PANEL_CNTL_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_panel_cntl_mask panel_cntl_mask = { - DCE_PANEL_CNTL_MASK_SH_LIST(_MASK) -}; - -static struct panel_cntl *dcn303_panel_cntl_create(const struct panel_cntl_init_data *init_data) -{ - struct dce_panel_cntl *panel_cntl = kzalloc(sizeof(struct dce_panel_cntl), GFP_KERNEL); - - if (!panel_cntl) - return NULL; - - dce_panel_cntl_construct(panel_cntl, init_data, &panel_cntl_regs[init_data->inst], - &panel_cntl_shift, &panel_cntl_mask); - - return &panel_cntl->base; -} - -static void read_dce_straps(struct dc_context *ctx, struct resource_straps *straps) -{ - generic_reg_get(ctx, mmDC_PINSTRAPS + BASE(mmDC_PINSTRAPS_BASE_IDX), - FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio); -} - -static const struct resource_create_funcs res_create_funcs = { - .read_dce_straps = read_dce_straps, - .create_audio = dcn303_create_audio, - .create_stream_encoder = dcn303_stream_encoder_create, - .create_hwseq = dcn303_hwseq_create, -}; - -static bool is_soc_bounding_box_valid(struct dc *dc) -{ - uint32_t hw_internal_rev = dc->ctx->asic_id.hw_internal_rev; - - if (ASICREV_IS_BEIGE_GOBY_P(hw_internal_rev)) - return true; - - return false; -} - -static bool init_soc_bounding_box(struct dc *dc, struct resource_pool *pool) -{ - struct _vcs_dpi_soc_bounding_box_st *loaded_bb = &dcn3_03_soc; - struct _vcs_dpi_ip_params_st *loaded_ip = &dcn3_03_ip; - - DC_LOGGER_INIT(dc->ctx->logger); - - if (!is_soc_bounding_box_valid(dc)) { - DC_LOG_ERROR("%s: not valid soc bounding box/n", __func__); - return false; - } - - loaded_ip->max_num_otg = pool->pipe_count; - loaded_ip->max_num_dpp = pool->pipe_count; - loaded_ip->clamp_min_dcfclk = dc->config.clamp_min_dcfclk; - DC_FP_START(); - dcn20_patch_bounding_box(dc, loaded_bb); - DC_FP_END(); - - if (dc->ctx->dc_bios->funcs->get_soc_bb_info) { - struct bp_soc_bb_info bb_info = { 0 }; - - if (dc->ctx->dc_bios->funcs->get_soc_bb_info( - dc->ctx->dc_bios, &bb_info) == BP_RESULT_OK) { - DC_FP_START(); - dcn303_fpu_init_soc_bounding_box(bb_info); - DC_FP_END(); - } - } - - return true; -} - -static void dcn303_resource_destruct(struct resource_pool *pool) -{ - unsigned int i; - - for (i = 0; i < pool->stream_enc_count; i++) { - if (pool->stream_enc[i] != NULL) { - if (pool->stream_enc[i]->vpg != NULL) { - kfree(DCN30_VPG_FROM_VPG(pool->stream_enc[i]->vpg)); - pool->stream_enc[i]->vpg = NULL; - } - if (pool->stream_enc[i]->afmt != NULL) { - kfree(DCN30_AFMT_FROM_AFMT(pool->stream_enc[i]->afmt)); - pool->stream_enc[i]->afmt = NULL; - } - kfree(DCN10STRENC_FROM_STRENC(pool->stream_enc[i])); - pool->stream_enc[i] = NULL; - } - } - - for (i = 0; i < pool->res_cap->num_dsc; i++) { - if (pool->dscs[i] != NULL) - dcn20_dsc_destroy(&pool->dscs[i]); - } - - if (pool->mpc != NULL) { - kfree(TO_DCN20_MPC(pool->mpc)); - pool->mpc = NULL; - } - - if (pool->hubbub != NULL) { - kfree(pool->hubbub); - pool->hubbub = NULL; - } - - for (i = 0; i < pool->pipe_count; i++) { - if (pool->dpps[i] != NULL) { - kfree(TO_DCN20_DPP(pool->dpps[i])); - pool->dpps[i] = NULL; - } - - if (pool->hubps[i] != NULL) { - kfree(TO_DCN20_HUBP(pool->hubps[i])); - pool->hubps[i] = NULL; - } - - if (pool->irqs != NULL) - dal_irq_service_destroy(&pool->irqs); - } - - for (i = 0; i < pool->res_cap->num_ddc; i++) { - if (pool->engines[i] != NULL) - dce110_engine_destroy(&pool->engines[i]); - if (pool->hw_i2cs[i] != NULL) { - kfree(pool->hw_i2cs[i]); - pool->hw_i2cs[i] = NULL; - } - if (pool->sw_i2cs[i] != NULL) { - kfree(pool->sw_i2cs[i]); - pool->sw_i2cs[i] = NULL; - } - } - - for (i = 0; i < pool->res_cap->num_opp; i++) { - if (pool->opps[i] != NULL) - pool->opps[i]->funcs->opp_destroy(&pool->opps[i]); - } - - for (i = 0; i < pool->res_cap->num_timing_generator; i++) { - if (pool->timing_generators[i] != NULL) { - kfree(DCN10TG_FROM_TG(pool->timing_generators[i])); - pool->timing_generators[i] = NULL; - } - } - - for (i = 0; i < pool->res_cap->num_dwb; i++) { - if (pool->dwbc[i] != NULL) { - kfree(TO_DCN30_DWBC(pool->dwbc[i])); - pool->dwbc[i] = NULL; - } - if (pool->mcif_wb[i] != NULL) { - kfree(TO_DCN30_MMHUBBUB(pool->mcif_wb[i])); - pool->mcif_wb[i] = NULL; - } - } - - for (i = 0; i < pool->audio_count; i++) { - if (pool->audios[i]) - dce_aud_destroy(&pool->audios[i]); - } - - for (i = 0; i < pool->clk_src_count; i++) { - if (pool->clock_sources[i] != NULL) - dcn20_clock_source_destroy(&pool->clock_sources[i]); - } - - if (pool->dp_clock_source != NULL) - dcn20_clock_source_destroy(&pool->dp_clock_source); - - for (i = 0; i < pool->res_cap->num_mpc_3dlut; i++) { - if (pool->mpc_lut[i] != NULL) { - dc_3dlut_func_release(pool->mpc_lut[i]); - pool->mpc_lut[i] = NULL; - } - if (pool->mpc_shaper[i] != NULL) { - dc_transfer_func_release(pool->mpc_shaper[i]); - pool->mpc_shaper[i] = NULL; - } - } - - for (i = 0; i < pool->pipe_count; i++) { - if (pool->multiple_abms[i] != NULL) - dce_abm_destroy(&pool->multiple_abms[i]); - } - - if (pool->psr != NULL) - dmub_psr_destroy(&pool->psr); - - if (pool->dccg != NULL) - dcn_dccg_destroy(&pool->dccg); - - if (pool->oem_device != NULL) { - struct dc *dc = pool->oem_device->ctx->dc; - - dc->link_srv->destroy_ddc_service(&pool->oem_device); - } -} - -static void dcn303_destroy_resource_pool(struct resource_pool **pool) -{ - dcn303_resource_destruct(*pool); - kfree(*pool); - *pool = NULL; -} - -static void dcn303_get_panel_config_defaults(struct dc_panel_config *panel_config) -{ - *panel_config = panel_config_defaults; -} - -void dcn303_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) -{ - DC_FP_START(); - dcn303_fpu_update_bw_bounding_box(dc, bw_params); - DC_FP_END(); -} - -static struct resource_funcs dcn303_res_pool_funcs = { - .destroy = dcn303_destroy_resource_pool, - .link_enc_create = dcn303_link_encoder_create, - .panel_cntl_create = dcn303_panel_cntl_create, - .validate_bandwidth = dcn30_validate_bandwidth, - .calculate_wm_and_dlg = dcn30_calculate_wm_and_dlg, - .update_soc_for_wm_a = dcn30_update_soc_for_wm_a, - .populate_dml_pipes = dcn30_populate_dml_pipes_from_context, - .acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer, - .release_pipe = dcn20_release_pipe, - .add_stream_to_ctx = dcn30_add_stream_to_ctx, - .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource, - .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, - .populate_dml_writeback_from_context = dcn30_populate_dml_writeback_from_context, - .set_mcif_arb_params = dcn30_set_mcif_arb_params, - .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 = dcn303_update_bw_bounding_box, - .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, - .get_panel_config_defaults = dcn303_get_panel_config_defaults, -}; - -static struct dc_cap_funcs cap_funcs = { - .get_dcc_compression_cap = dcn20_get_dcc_compression_cap -}; - -static const struct bios_registers bios_regs = { - NBIO_SR(BIOS_SCRATCH_3), - NBIO_SR(BIOS_SCRATCH_6) -}; - -static const struct dccg_registers dccg_regs = { - DCCG_REG_LIST_DCN3_03() -}; - -static const struct dccg_shift dccg_shift = { - DCCG_MASK_SH_LIST_DCN3_03(__SHIFT) -}; - -static const struct dccg_mask dccg_mask = { - DCCG_MASK_SH_LIST_DCN3_03(_MASK) -}; - -#define abm_regs(id)\ - [id] = { ABM_DCN302_REG_LIST(id) } - -static const struct dce_abm_registers abm_regs[] = { - abm_regs(0), - abm_regs(1) -}; - -static const struct dce_abm_shift abm_shift = { - ABM_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dce_abm_mask abm_mask = { - ABM_MASK_SH_LIST_DCN30(_MASK) -}; - -static bool dcn303_resource_construct( - uint8_t num_virtual_links, - struct dc *dc, - struct resource_pool *pool) -{ - int i; - struct dc_context *ctx = dc->ctx; - struct irq_service_init_data init_data; - struct ddc_service_init_data ddc_init_data; - - ctx->dc_bios->regs = &bios_regs; - - pool->res_cap = &res_cap_dcn303; - - pool->funcs = &dcn303_res_pool_funcs; - - /************************************************* - * Resource + asic cap harcoding * - *************************************************/ - pool->underlay_pipe_index = NO_UNDERLAY_PIPE; - pool->pipe_count = pool->res_cap->num_timing_generator; - pool->mpcc_count = pool->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 = 5; /*1.4 w/a applied by derfault*/ - dc->caps.max_cursor_size = 256; - dc->caps.min_horizontal_blanking_period = 80; - dc->caps.dmdata_alloc_size = 2048; - dc->caps.mall_size_per_mem_channel = 4; - /* total size = mall per channel * num channels * 1024 * 1024 */ - dc->caps.mall_size_total = dc->caps.mall_size_per_mem_channel * - dc->ctx->dc_bios->vram_info.num_chans * - 1024 * 1024; - dc->caps.cursor_cache_size = - dc->caps.max_cursor_size * dc->caps.max_cursor_size * 8; - dc->caps.max_slave_planes = 1; - dc->caps.post_blend_color_processing = true; - dc->caps.force_dp_tps4_for_cp2520 = true; - dc->caps.extended_aux_timeout_support = true; - dc->caps.dmcub_support = true; - dc->caps.max_v_total = (1 << 15) - 1; - - /* Color pipeline capabilities */ - dc->caps.color.dpp.dcn_arch = 1; - dc->caps.color.dpp.input_lut_shared = 0; - dc->caps.color.dpp.icsc = 1; - dc->caps.color.dpp.dgam_ram = 0; // must use gamma_corr - dc->caps.color.dpp.dgam_rom_caps.srgb = 1; - dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1; - dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 1; - dc->caps.color.dpp.dgam_rom_caps.pq = 1; - dc->caps.color.dpp.dgam_rom_caps.hlg = 1; - dc->caps.color.dpp.post_csc = 1; - dc->caps.color.dpp.gamma_corr = 1; - dc->caps.color.dpp.dgam_rom_for_yuv = 0; - - dc->caps.color.dpp.hw_3d_lut = 1; - dc->caps.color.dpp.ogam_ram = 1; - // no OGAM ROM on DCN3 - dc->caps.color.dpp.ogam_rom_caps.srgb = 0; - dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0; - dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0; - dc->caps.color.dpp.ogam_rom_caps.pq = 0; - dc->caps.color.dpp.ogam_rom_caps.hlg = 0; - dc->caps.color.dpp.ocsc = 0; - - dc->caps.color.mpc.gamut_remap = 1; - dc->caps.color.mpc.num_3dluts = pool->res_cap->num_mpc_3dlut; //3 - dc->caps.color.mpc.ogam_ram = 1; - dc->caps.color.mpc.ogam_rom_caps.srgb = 0; - dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0; - dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0; - dc->caps.color.mpc.ogam_rom_caps.pq = 0; - dc->caps.color.mpc.ogam_rom_caps.hlg = 0; - dc->caps.color.mpc.ocsc = 1; - - dc->caps.dp_hdmi21_pcon_support = true; - - dc->config.dc_mode_clk_limit_support = true; - /* read VBIOS LTTPR caps */ - if (ctx->dc_bios->funcs->get_lttpr_caps) { - enum bp_result bp_query_result; - uint8_t is_vbios_lttpr_enable = 0; - - bp_query_result = ctx->dc_bios->funcs->get_lttpr_caps(ctx->dc_bios, &is_vbios_lttpr_enable); - dc->caps.vbios_lttpr_enable = (bp_query_result == BP_RESULT_OK) && !!is_vbios_lttpr_enable; - } - - if (ctx->dc_bios->funcs->get_lttpr_interop) { - enum bp_result bp_query_result; - uint8_t is_vbios_interop_enabled = 0; - - bp_query_result = ctx->dc_bios->funcs->get_lttpr_interop(ctx->dc_bios, &is_vbios_interop_enabled); - dc->caps.vbios_lttpr_aware = (bp_query_result == BP_RESULT_OK) && !!is_vbios_interop_enabled; - } - - if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) - dc->debug = debug_defaults_drv; - - // Init the vm_helper - if (dc->vm_helper) - vm_helper_init(dc->vm_helper, 16); - - /************************************************* - * Create resources * - *************************************************/ - - /* Clock Sources for Pixel Clock*/ - pool->clock_sources[DCN303_CLK_SRC_PLL0] = - dcn303_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL0, - &clk_src_regs[0], false); - pool->clock_sources[DCN303_CLK_SRC_PLL1] = - dcn303_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL1, - &clk_src_regs[1], false); - - pool->clk_src_count = DCN303_CLK_SRC_TOTAL; - - /* todo: not reuse phy_pll registers */ - pool->dp_clock_source = - dcn303_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_ID_DP_DTO, - &clk_src_regs[0], true); - - for (i = 0; i < pool->clk_src_count; i++) { - if (pool->clock_sources[i] == NULL) { - dm_error("DC: failed to create clock sources!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - } - - /* DCCG */ - pool->dccg = dccg30_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask); - if (pool->dccg == NULL) { - dm_error("DC: failed to create dccg!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - - /* PP Lib and SMU interfaces */ - init_soc_bounding_box(dc, pool); - - /* DML */ - dml_init_instance(&dc->dml, &dcn3_03_soc, &dcn3_03_ip, DML_PROJECT_DCN30); - - /* IRQ */ - init_data.ctx = dc->ctx; - pool->irqs = dal_irq_service_dcn303_create(&init_data); - if (!pool->irqs) - goto create_fail; - - /* HUBBUB */ - pool->hubbub = dcn303_hubbub_create(ctx); - if (pool->hubbub == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create hubbub!\n"); - goto create_fail; - } - - /* HUBPs, DPPs, OPPs and TGs */ - for (i = 0; i < pool->pipe_count; i++) { - pool->hubps[i] = dcn303_hubp_create(ctx, i); - if (pool->hubps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create hubps!\n"); - goto create_fail; - } - - pool->dpps[i] = dcn303_dpp_create(ctx, i); - if (pool->dpps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create dpps!\n"); - goto create_fail; - } - } - - for (i = 0; i < pool->res_cap->num_opp; i++) { - pool->opps[i] = dcn303_opp_create(ctx, i); - if (pool->opps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create output pixel processor!\n"); - goto create_fail; - } - } - - for (i = 0; i < pool->res_cap->num_timing_generator; i++) { - pool->timing_generators[i] = dcn303_timing_generator_create(ctx, i); - if (pool->timing_generators[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create tg!\n"); - goto create_fail; - } - } - pool->timing_generator_count = i; - - /* PSR */ - pool->psr = dmub_psr_create(ctx); - if (pool->psr == NULL) { - dm_error("DC: failed to create psr!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - - /* ABM */ - for (i = 0; i < pool->res_cap->num_timing_generator; i++) { - pool->multiple_abms[i] = dmub_abm_create(ctx, &abm_regs[i], &abm_shift, &abm_mask); - if (pool->multiple_abms[i] == NULL) { - dm_error("DC: failed to create abm for pipe %d!\n", i); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - } - - /* MPC and DSC */ - pool->mpc = dcn303_mpc_create(ctx, pool->mpcc_count, pool->res_cap->num_mpc_3dlut); - if (pool->mpc == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create mpc!\n"); - goto create_fail; - } - - for (i = 0; i < pool->res_cap->num_dsc; i++) { - pool->dscs[i] = dcn303_dsc_create(ctx, i); - if (pool->dscs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create display stream compressor %d!\n", i); - goto create_fail; - } - } - - /* DWB and MMHUBBUB */ - if (!dcn303_dwbc_create(ctx, pool)) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create dwbc!\n"); - goto create_fail; - } - - if (!dcn303_mmhubbub_create(ctx, pool)) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create mcif_wb!\n"); - goto create_fail; - } - - /* AUX and I2C */ - for (i = 0; i < pool->res_cap->num_ddc; i++) { - pool->engines[i] = dcn303_aux_engine_create(ctx, i); - if (pool->engines[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC:failed to create aux engine!!\n"); - goto create_fail; - } - pool->hw_i2cs[i] = dcn303_i2c_hw_create(ctx, i); - if (pool->hw_i2cs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC:failed to create hw i2c!!\n"); - goto create_fail; - } - pool->sw_i2cs[i] = NULL; - } - - /* Audio, Stream Encoders including HPO and virtual, MPC 3D LUTs */ - if (!resource_construct(num_virtual_links, dc, pool, - &res_create_funcs)) - goto create_fail; - - /* HW Sequencer and Plane caps */ - dcn303_hw_sequencer_construct(dc); - - dc->caps.max_planes = pool->pipe_count; - - for (i = 0; i < dc->caps.max_planes; ++i) - dc->caps.planes[i] = plane_cap; - - 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 = dc->link_srv->create_ddc_service(&ddc_init_data); - } else { - pool->oem_device = NULL; - } - - return true; - -create_fail: - - dcn303_resource_destruct(pool); - - return false; -} - -struct resource_pool *dcn303_create_resource_pool(const struct dc_init_data *init_data, struct dc *dc) -{ - struct resource_pool *pool = kzalloc(sizeof(struct resource_pool), GFP_KERNEL); - - if (!pool) - return NULL; - - if (dcn303_resource_construct(init_data->num_virtual_links, dc, pool)) - return pool; - - BREAK_TO_DEBUGGER(); - kfree(pool); - return NULL; -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.h b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.h deleted file mode 100644 index 37cf1525820bbc..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.h +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - * Copyright (C) 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 _DCN303_RESOURCE_H_ -#define _DCN303_RESOURCE_H_ - -#include "core_types.h" - -extern struct _vcs_dpi_ip_params_st dcn3_03_ip; -extern struct _vcs_dpi_soc_bounding_box_st dcn3_03_soc; - -struct resource_pool *dcn303_create_resource_pool(const struct dc_init_data *init_data, struct dc *dc); - -void dcn303_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params); - -#endif /* _DCN303_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/Makefile b/drivers/gpu/drm/amd/display/dc/dcn31/Makefile index 96e45c9efb461c..5d93ac16c03a94 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn31/Makefile @@ -10,8 +10,8 @@ # # Makefile for dcn31. -DCN31 = dcn31_resource.o dcn31_hubbub.o dcn31_init.o dcn31_hubp.o \ - dcn31_dccg.o dcn31_optc.o dcn31_dio_link_encoder.o dcn31_panel_cntl.o \ +DCN31 = dcn31_hubbub.o dcn31_hubp.o \ + dcn31_dccg.o dcn31_dio_link_encoder.o dcn31_panel_cntl.o \ dcn31_apg.o dcn31_hpo_dp_stream_encoder.o dcn31_hpo_dp_link_encoder.o \ dcn31_afmt.o dcn31_vpg.o 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 4596f3bac1b4c7..26be5fee7411d9 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 @@ -125,7 +125,7 @@ static bool query_dp_alt_from_dmub(struct link_encoder *enc, cmd->query_dp_alt.header.payload_bytes = sizeof(cmd->query_dp_alt.data); cmd->query_dp_alt.data.phy_id = phy_id_from_transmitter(enc10->base.transmitter); - if (!dm_execute_dmub_cmd(enc->ctx, cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) + if (!dc_wake_and_execute_dmub_cmd(enc->ctx, cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) return false; return true; @@ -436,7 +436,7 @@ static bool link_dpia_control(struct dc_context *dc_ctx, cmd.dig1_dpia_control.dpia_control = *dpia_control; - dm_execute_dmub_cmd(dc_ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dc_ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); return true; } diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c deleted file mode 100644 index 669f524bd064d5..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright 2016 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 "dce110/dce110_hwseq.h" -#include "dcn10/dcn10_hwseq.h" -#include "dcn20/dcn20_hwseq.h" -#include "dcn21/dcn21_hwseq.h" -#include "dcn30/dcn30_hwseq.h" -#include "dcn301/dcn301_hwseq.h" -#include "dcn31/dcn31_hwseq.h" - -#include "dcn31_init.h" - -static const struct hw_sequencer_funcs dcn31_funcs = { - .program_gamut_remap = dcn30_program_gamut_remap, - .init_hw = dcn31_init_hw, - .power_down_on_boot = dcn10_power_down_on_boot, - .apply_ctx_to_hw = dce110_apply_ctx_to_hw, - .apply_ctx_for_surface = NULL, - .program_front_end_for_ctx = dcn20_program_front_end_for_ctx, - .wait_for_pending_cleared = dcn10_wait_for_pending_cleared, - .post_unlock_program_front_end = dcn20_post_unlock_program_front_end, - .update_plane_addr = dcn20_update_plane_addr, - .update_dchub = dcn10_update_dchub, - .update_pending_status = dcn10_update_pending_status, - .program_output_csc = dcn20_program_output_csc, - .enable_accelerated_mode = dce110_enable_accelerated_mode, - .enable_timing_synchronization = dcn10_enable_timing_synchronization, - .enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset, - .update_info_frame = dcn31_update_info_frame, - .send_immediate_sdp_message = dcn10_send_immediate_sdp_message, - .enable_stream = dcn20_enable_stream, - .disable_stream = dce110_disable_stream, - .unblank_stream = dcn20_unblank_stream, - .blank_stream = dce110_blank_stream, - .enable_audio_stream = dce110_enable_audio_stream, - .disable_audio_stream = dce110_disable_audio_stream, - .disable_plane = dcn20_disable_plane, - .disable_pixel_data = dcn20_disable_pixel_data, - .pipe_control_lock = dcn20_pipe_control_lock, - .interdependent_update_lock = dcn10_lock_all_pipes, - .cursor_lock = dcn10_cursor_lock, - .prepare_bandwidth = dcn20_prepare_bandwidth, - .optimize_bandwidth = dcn20_optimize_bandwidth, - .update_bandwidth = dcn20_update_bandwidth, - .set_drr = dcn10_set_drr, - .get_position = dcn10_get_position, - .set_static_screen_control = dcn30_set_static_screen_control, - .setup_stereo = dcn10_setup_stereo, - .set_avmute = dcn30_set_avmute, - .log_hw_state = dcn10_log_hw_state, - .get_hw_state = dcn10_get_hw_state, - .clear_status_bits = dcn10_clear_status_bits, - .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, - .edp_backlight_control = dce110_edp_backlight_control, - .edp_power_control = dce110_edp_power_control, - .edp_wait_for_T12 = dce110_edp_wait_for_T12, - .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, - .set_cursor_position = dcn10_set_cursor_position, - .set_cursor_attribute = dcn10_set_cursor_attribute, - .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level, - .setup_periodic_interrupt = dcn10_setup_periodic_interrupt, - .set_clock = dcn10_set_clock, - .get_clock = dcn10_get_clock, - .program_triplebuffer = dcn20_program_triple_buffer, - .enable_writeback = dcn30_enable_writeback, - .disable_writeback = dcn30_disable_writeback, - .update_writeback = dcn30_update_writeback, - .mmhubbub_warmup = dcn30_mmhubbub_warmup, - .dmdata_status_done = dcn20_dmdata_status_done, - .program_dmdata_engine = dcn30_program_dmdata_engine, - .set_dmdata_attributes = dcn20_set_dmdata_attributes, - .init_sys_ctx = dcn31_init_sys_ctx, - .init_vm_ctx = dcn20_init_vm_ctx, - .set_flip_control_gsl = dcn20_set_flip_control_gsl, - .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync, - .calc_vupdate_position = dcn10_calc_vupdate_position, - .power_down = dce110_power_down, - .set_backlight_level = dcn21_set_backlight_level, - .set_abm_immediate_disable = dcn21_set_abm_immediate_disable, - .set_pipe = dcn21_set_pipe, - .enable_lvds_link_output = dce110_enable_lvds_link_output, - .enable_tmds_link_output = dce110_enable_tmds_link_output, - .enable_dp_link_output = dce110_enable_dp_link_output, - .disable_link_output = dce110_disable_link_output, - .z10_restore = dcn31_z10_restore, - .z10_save_init = dcn31_z10_save_init, - .set_disp_pattern_generator = dcn30_set_disp_pattern_generator, - .optimize_pwr_state = dcn21_optimize_pwr_state, - .exit_optimized_pwr_state = dcn21_exit_optimized_pwr_state, - .update_visual_confirm_color = dcn10_update_visual_confirm_color, -}; - -static const struct hwseq_private_funcs dcn31_private_funcs = { - .init_pipes = dcn10_init_pipes, - .update_plane_addr = dcn20_update_plane_addr, - .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, - .update_mpcc = dcn20_update_mpcc, - .set_input_transfer_func = dcn30_set_input_transfer_func, - .set_output_transfer_func = dcn30_set_output_transfer_func, - .power_down = dce110_power_down, - .enable_display_power_gating = dcn10_dummy_display_power_gating, - .blank_pixel_data = dcn20_blank_pixel_data, - .reset_hw_ctx_wrap = dcn31_reset_hw_ctx_wrap, - .enable_stream_timing = dcn20_enable_stream_timing, - .edp_backlight_control = dce110_edp_backlight_control, - .disable_stream_gating = dcn20_disable_stream_gating, - .enable_stream_gating = dcn20_enable_stream_gating, - .setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt, - .did_underflow_occur = dcn10_did_underflow_occur, - .init_blank = dcn20_init_blank, - .disable_vga = dcn20_disable_vga, - .bios_golden_init = dcn10_bios_golden_init, - .plane_atomic_disable = dcn20_plane_atomic_disable, - .plane_atomic_power_down = dcn10_plane_atomic_power_down, - .enable_power_gating_plane = dcn31_enable_power_gating_plane, - .hubp_pg_control = dcn31_hubp_pg_control, - .program_all_writeback_pipes_in_tree = dcn30_program_all_writeback_pipes_in_tree, - .update_odm = dcn20_update_odm, - .dsc_pg_control = dcn31_dsc_pg_control, - .set_hdr_multiplier = dcn10_set_hdr_multiplier, - .verify_allow_pstate_change_high = dcn10_verify_allow_pstate_change_high, - .wait_for_blank_complete = dcn20_wait_for_blank_complete, - .dccg_init = dcn20_dccg_init, - .set_blend_lut = dcn30_set_blend_lut, - .set_shaper_3dlut = dcn20_set_shaper_3dlut, - .setup_hpo_hw_control = dcn31_setup_hpo_hw_control, -}; - -void dcn31_hw_sequencer_construct(struct dc *dc) -{ - dc->hwss = dcn31_funcs; - dc->hwseq->funcs = dcn31_private_funcs; - -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.h deleted file mode 100644 index a3db08c8bd35bd..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2016 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_DCN31_INIT_H__ -#define __DC_DCN31_INIT_H__ - -struct dc; - -void dcn31_hw_sequencer_construct(struct dc *dc); - -#endif /* __DC_DCN31_INIT_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.c deleted file mode 100644 index 63a677c8ee2726..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.c +++ /dev/null @@ -1,310 +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 - * - */ - -#include "dcn31_optc.h" - -#include "dcn30/dcn30_optc.h" -#include "reg_helper.h" -#include "dc.h" -#include "dcn_calc_math.h" - -#define REG(reg)\ - optc1->tg_regs->reg - -#define CTX \ - optc1->base.ctx - -#undef FN -#define FN(reg_name, field_name) \ - optc1->tg_shift->field_name, optc1->tg_mask->field_name - -static void optc31_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, - struct dc_crtc_timing *timing) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - int mpcc_hactive = (timing->h_addressable + timing->h_border_left + timing->h_border_right) - / opp_cnt; - uint32_t memory_mask = 0; - int mem_count_per_opp = (mpcc_hactive + 2559) / 2560; - - /* Assume less than 6 pipes */ - if (opp_cnt == 4) { - if (mem_count_per_opp == 1) - memory_mask = 0xf; - else { - ASSERT(mem_count_per_opp == 2); - memory_mask = 0xff; - } - } else if (mem_count_per_opp == 1) - memory_mask = 0x1 << (opp_id[0] * 2) | 0x1 << (opp_id[1] * 2); - else if (mem_count_per_opp == 2) - memory_mask = 0x3 << (opp_id[0] * 2) | 0x3 << (opp_id[1] * 2); - else if (mem_count_per_opp == 3) - memory_mask = 0x77; - else if (mem_count_per_opp == 4) - memory_mask = 0xff; - - if (REG(OPTC_MEMORY_CONFIG)) - REG_SET(OPTC_MEMORY_CONFIG, 0, - OPTC_MEM_SEL, memory_mask); - - if (opp_cnt == 2) { - REG_SET_3(OPTC_DATA_SOURCE_SELECT, 0, - OPTC_NUM_OF_INPUT_SEGMENT, 1, - OPTC_SEG0_SRC_SEL, opp_id[0], - OPTC_SEG1_SRC_SEL, opp_id[1]); - } else if (opp_cnt == 4) { - REG_SET_5(OPTC_DATA_SOURCE_SELECT, 0, - OPTC_NUM_OF_INPUT_SEGMENT, 3, - OPTC_SEG0_SRC_SEL, opp_id[0], - OPTC_SEG1_SRC_SEL, opp_id[1], - OPTC_SEG2_SRC_SEL, opp_id[2], - OPTC_SEG3_SRC_SEL, opp_id[3]); - } - - REG_UPDATE(OPTC_WIDTH_CONTROL, - OPTC_SEGMENT_WIDTH, mpcc_hactive); - - REG_SET(OTG_H_TIMING_CNTL, 0, OTG_H_TIMING_DIV_MODE, opp_cnt - 1); - optc1->opp_count = opp_cnt; -} - -/* - * Enable CRTC - call ASIC Control Object to enable Timing generator. - */ -static bool optc31_enable_crtc(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - /* opp instance for OTG, 1 to 1 mapping and odm will adjust */ - REG_UPDATE(OPTC_DATA_SOURCE_SELECT, - OPTC_SEG0_SRC_SEL, optc->inst); - - /* VTG enable first is for HW workaround */ - REG_UPDATE(CONTROL, - VTG0_ENABLE, 1); - - REG_SEQ_START(); - - /* Enable CRTC */ - REG_UPDATE_2(OTG_CONTROL, - OTG_DISABLE_POINT_CNTL, 2, - OTG_MASTER_EN, 1); - - REG_SEQ_SUBMIT(); - REG_SEQ_WAIT_DONE(); - - return true; -} - -/* disable_crtc - call ASIC Control Object to disable Timing generator. */ -static bool optc31_disable_crtc(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - /* disable otg request until end of the first line - * in the vertical blank region - */ - REG_UPDATE(OTG_CONTROL, - OTG_MASTER_EN, 0); - - REG_UPDATE(CONTROL, - VTG0_ENABLE, 0); - - /* CRTC disabled, so disable clock. */ - REG_WAIT(OTG_CLOCK_CONTROL, - OTG_BUSY, 0, - 1, 100000); - optc1_clear_optc_underflow(optc); - - return true; -} - -bool optc31_immediate_disable_crtc(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_UPDATE_2(OTG_CONTROL, - OTG_DISABLE_POINT_CNTL, 0, - OTG_MASTER_EN, 0); - - REG_UPDATE(CONTROL, - VTG0_ENABLE, 0); - - /* CRTC disabled, so disable clock. */ - REG_WAIT(OTG_CLOCK_CONTROL, - OTG_BUSY, 0, - 1, 100000); - - /* clear the false state */ - optc1_clear_optc_underflow(optc); - - return true; -} - -void optc31_set_drr( - struct timing_generator *optc, - const struct drr_params *params) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - if (params != NULL && - params->vertical_total_max > 0 && - params->vertical_total_min > 0) { - - if (params->vertical_total_mid != 0) { - - REG_SET(OTG_V_TOTAL_MID, 0, - OTG_V_TOTAL_MID, params->vertical_total_mid - 1); - - REG_UPDATE_2(OTG_V_TOTAL_CONTROL, - OTG_VTOTAL_MID_REPLACING_MAX_EN, 1, - OTG_VTOTAL_MID_FRAME_NUM, - (uint8_t)params->vertical_total_mid_frame_num); - - } - - optc->funcs->set_vtotal_min_max(optc, params->vertical_total_min - 1, params->vertical_total_max - 1); - - /* - * MIN_MASK_EN is gone and MASK is now always enabled. - * - * To get it to it work with manual trigger we need to make sure - * we program the correct bit. - */ - REG_UPDATE_4(OTG_V_TOTAL_CONTROL, - OTG_V_TOTAL_MIN_SEL, 1, - OTG_V_TOTAL_MAX_SEL, 1, - OTG_FORCE_LOCK_ON_EVENT, 0, - OTG_SET_V_TOTAL_MIN_MASK, (1 << 1)); /* TRIGA */ - - // Setup manual flow control for EOF via TRIG_A - optc->funcs->setup_manual_trigger(optc); - } else { - REG_UPDATE_4(OTG_V_TOTAL_CONTROL, - OTG_SET_V_TOTAL_MIN_MASK, 0, - OTG_V_TOTAL_MIN_SEL, 0, - OTG_V_TOTAL_MAX_SEL, 0, - OTG_FORCE_LOCK_ON_EVENT, 0); - - optc->funcs->set_vtotal_min_max(optc, 0, 0); - } -} - -void optc3_init_odm(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_SET_5(OPTC_DATA_SOURCE_SELECT, 0, - OPTC_NUM_OF_INPUT_SEGMENT, 0, - OPTC_SEG0_SRC_SEL, optc->inst, - OPTC_SEG1_SRC_SEL, 0xf, - OPTC_SEG2_SRC_SEL, 0xf, - OPTC_SEG3_SRC_SEL, 0xf - ); - - REG_SET(OTG_H_TIMING_CNTL, 0, - OTG_H_TIMING_DIV_MODE, 0); - - REG_SET(OPTC_MEMORY_CONFIG, 0, - OPTC_MEM_SEL, 0); - optc1->opp_count = 1; -} - -static struct timing_generator_funcs dcn31_tg_funcs = { - .validate_timing = optc1_validate_timing, - .program_timing = optc1_program_timing, - .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0, - .setup_vertical_interrupt1 = optc1_setup_vertical_interrupt1, - .setup_vertical_interrupt2 = optc1_setup_vertical_interrupt2, - .program_global_sync = optc1_program_global_sync, - .enable_crtc = optc31_enable_crtc, - .disable_crtc = optc31_disable_crtc, - .immediate_disable_crtc = optc31_immediate_disable_crtc, - /* used by enable_timing_synchronization. Not need for FPGA */ - .is_counter_moving = optc1_is_counter_moving, - .get_position = optc1_get_position, - .get_frame_count = optc1_get_vblank_counter, - .get_scanoutpos = optc1_get_crtc_scanoutpos, - .get_otg_active_size = optc1_get_otg_active_size, - .set_early_control = optc1_set_early_control, - /* used by enable_timing_synchronization. Not need for FPGA */ - .wait_for_state = optc1_wait_for_state, - .set_blank_color = optc3_program_blank_color, - .did_triggered_reset_occur = optc1_did_triggered_reset_occur, - .triplebuffer_lock = optc3_triplebuffer_lock, - .triplebuffer_unlock = optc2_triplebuffer_unlock, - .enable_reset_trigger = optc1_enable_reset_trigger, - .enable_crtc_reset = optc1_enable_crtc_reset, - .disable_reset_trigger = optc1_disable_reset_trigger, - .lock = optc3_lock, - .unlock = optc1_unlock, - .lock_doublebuffer_enable = optc3_lock_doublebuffer_enable, - .lock_doublebuffer_disable = optc3_lock_doublebuffer_disable, - .enable_optc_clock = optc1_enable_optc_clock, - .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 = optc1_set_static_screen_control, - .program_stereo = optc1_program_stereo, - .is_stereo_left_eye = optc1_is_stereo_left_eye, - .tg_init = optc3_tg_init, - .is_tg_enabled = optc1_is_tg_enabled, - .is_optc_underflow_occurred = optc1_is_optc_underflow_occurred, - .clear_optc_underflow = optc1_clear_optc_underflow, - .setup_global_swap_lock = NULL, - .get_crc = optc1_get_crc, - .configure_crc = optc2_configure_crc, - .set_dsc_config = optc3_set_dsc_config, - .get_dsc_status = optc2_get_dsc_status, - .set_dwb_source = NULL, - .set_odm_bypass = optc3_set_odm_bypass, - .set_odm_combine = optc31_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, - .set_vtotal_change_limit = optc3_set_vtotal_change_limit, - .set_gsl = optc2_set_gsl, - .set_gsl_source_select = optc2_set_gsl_source_select, - .set_vtg_params = optc1_set_vtg_params, - .program_manual_trigger = optc2_program_manual_trigger, - .setup_manual_trigger = optc2_setup_manual_trigger, - .get_hw_timing = optc1_get_hw_timing, - .init_odm = optc3_init_odm, -}; - -void dcn31_timing_generator_init(struct optc *optc1) -{ - optc1->base.funcs = &dcn31_tg_funcs; - - optc1->max_h_total = optc1->tg_mask->OTG_H_TOTAL + 1; - optc1->max_v_total = optc1->tg_mask->OTG_V_TOTAL + 1; - - optc1->min_h_blank = 32; - optc1->min_v_blank = 3; - optc1->min_v_blank_interlace = 5; - optc1->min_h_sync_width = 4; - optc1->min_v_sync_width = 1; -} - diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.h deleted file mode 100644 index 30b81a448ce2d1..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.h +++ /dev/null @@ -1,267 +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 __DC_OPTC_DCN31_H__ -#define __DC_OPTC_DCN31_H__ - -#include "dcn10/dcn10_optc.h" - -#define OPTC_COMMON_REG_LIST_DCN3_1(inst) \ - SRI(OTG_VSTARTUP_PARAM, OTG, inst),\ - SRI(OTG_VUPDATE_PARAM, OTG, inst),\ - SRI(OTG_VREADY_PARAM, OTG, inst),\ - SRI(OTG_MASTER_UPDATE_LOCK, OTG, inst),\ - SRI(OTG_GLOBAL_CONTROL0, OTG, inst),\ - SRI(OTG_GLOBAL_CONTROL1, OTG, inst),\ - SRI(OTG_GLOBAL_CONTROL2, OTG, inst),\ - SRI(OTG_GLOBAL_CONTROL4, OTG, inst),\ - SRI(OTG_DOUBLE_BUFFER_CONTROL, OTG, inst),\ - SRI(OTG_H_TOTAL, OTG, inst),\ - SRI(OTG_H_BLANK_START_END, OTG, inst),\ - SRI(OTG_H_SYNC_A, OTG, inst),\ - SRI(OTG_H_SYNC_A_CNTL, OTG, inst),\ - SRI(OTG_H_TIMING_CNTL, OTG, inst),\ - SRI(OTG_V_TOTAL, OTG, inst),\ - SRI(OTG_V_BLANK_START_END, OTG, inst),\ - SRI(OTG_V_SYNC_A, OTG, inst),\ - SRI(OTG_V_SYNC_A_CNTL, OTG, inst),\ - SRI(OTG_CONTROL, OTG, inst),\ - SRI(OTG_STEREO_CONTROL, OTG, inst),\ - SRI(OTG_3D_STRUCTURE_CONTROL, OTG, inst),\ - SRI(OTG_STEREO_STATUS, OTG, inst),\ - SRI(OTG_V_TOTAL_MAX, OTG, inst),\ - SRI(OTG_V_TOTAL_MIN, OTG, inst),\ - SRI(OTG_V_TOTAL_CONTROL, OTG, inst),\ - SRI(OTG_TRIGA_CNTL, OTG, inst),\ - SRI(OTG_FORCE_COUNT_NOW_CNTL, OTG, inst),\ - SRI(OTG_STATIC_SCREEN_CONTROL, OTG, inst),\ - SRI(OTG_STATUS_FRAME_COUNT, OTG, inst),\ - SRI(OTG_STATUS, OTG, inst),\ - SRI(OTG_STATUS_POSITION, OTG, inst),\ - SRI(OTG_NOM_VERT_POSITION, OTG, inst),\ - SRI(OTG_M_CONST_DTO0, OTG, inst),\ - SRI(OTG_M_CONST_DTO1, OTG, inst),\ - SRI(OTG_CLOCK_CONTROL, OTG, inst),\ - SRI(OTG_VERTICAL_INTERRUPT0_CONTROL, OTG, inst),\ - SRI(OTG_VERTICAL_INTERRUPT0_POSITION, OTG, inst),\ - SRI(OTG_VERTICAL_INTERRUPT1_CONTROL, OTG, inst),\ - SRI(OTG_VERTICAL_INTERRUPT1_POSITION, OTG, inst),\ - SRI(OTG_VERTICAL_INTERRUPT2_CONTROL, OTG, inst),\ - SRI(OTG_VERTICAL_INTERRUPT2_POSITION, OTG, inst),\ - SRI(OPTC_INPUT_CLOCK_CONTROL, ODM, inst),\ - SRI(OPTC_DATA_SOURCE_SELECT, ODM, inst),\ - SRI(OPTC_INPUT_GLOBAL_CONTROL, ODM, inst),\ - SRI(CONTROL, VTG, inst),\ - SRI(OTG_VERT_SYNC_CONTROL, OTG, inst),\ - SRI(OTG_GSL_CONTROL, OTG, inst),\ - SRI(OTG_CRC_CNTL, OTG, inst),\ - SRI(OTG_CRC0_DATA_RG, OTG, inst),\ - SRI(OTG_CRC0_DATA_B, OTG, inst),\ - SRI(OTG_CRC0_WINDOWA_X_CONTROL, OTG, inst),\ - SRI(OTG_CRC0_WINDOWA_Y_CONTROL, OTG, inst),\ - SRI(OTG_CRC0_WINDOWB_X_CONTROL, OTG, inst),\ - SRI(OTG_CRC0_WINDOWB_Y_CONTROL, OTG, inst),\ - SR(GSL_SOURCE_SELECT),\ - SRI(OTG_TRIGA_MANUAL_TRIG, OTG, inst),\ - SRI(OTG_GLOBAL_CONTROL1, OTG, inst),\ - SRI(OTG_GLOBAL_CONTROL2, OTG, inst),\ - SRI(OTG_GSL_WINDOW_X, OTG, inst),\ - SRI(OTG_GSL_WINDOW_Y, OTG, inst),\ - SRI(OTG_VUPDATE_KEEPOUT, OTG, inst),\ - SRI(OTG_DSC_START_POSITION, OTG, inst),\ - SRI(OTG_DRR_TRIGGER_WINDOW, OTG, inst),\ - SRI(OTG_DRR_V_TOTAL_CHANGE, OTG, inst),\ - SRI(OPTC_DATA_FORMAT_CONTROL, ODM, inst),\ - SRI(OPTC_BYTES_PER_PIXEL, ODM, inst),\ - SRI(OPTC_WIDTH_CONTROL, ODM, inst),\ - SRI(OPTC_MEMORY_CONFIG, ODM, inst),\ - SRI(OTG_CRC_CNTL2, OTG, inst),\ - SR(DWB_SOURCE_SELECT),\ - SRI(OTG_DRR_CONTROL, OTG, inst) - -#define OPTC_COMMON_MASK_SH_LIST_DCN3_1(mask_sh)\ - SF(OTG0_OTG_VSTARTUP_PARAM, VSTARTUP_START, mask_sh),\ - SF(OTG0_OTG_VUPDATE_PARAM, VUPDATE_OFFSET, mask_sh),\ - SF(OTG0_OTG_VUPDATE_PARAM, VUPDATE_WIDTH, mask_sh),\ - SF(OTG0_OTG_VREADY_PARAM, VREADY_OFFSET, mask_sh),\ - SF(OTG0_OTG_MASTER_UPDATE_LOCK, OTG_MASTER_UPDATE_LOCK, mask_sh),\ - SF(OTG0_OTG_MASTER_UPDATE_LOCK, UPDATE_LOCK_STATUS, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL0, MASTER_UPDATE_LOCK_DB_START_X, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL0, MASTER_UPDATE_LOCK_DB_END_X, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL0, MASTER_UPDATE_LOCK_DB_EN, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_START_Y, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_END_Y, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL2, OTG_MASTER_UPDATE_LOCK_SEL, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL4, DIG_UPDATE_POSITION_X, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL4, DIG_UPDATE_POSITION_Y, mask_sh),\ - SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_UPDATE_PENDING, mask_sh),\ - SF(OTG0_OTG_H_TOTAL, OTG_H_TOTAL, mask_sh),\ - SF(OTG0_OTG_H_BLANK_START_END, OTG_H_BLANK_START, mask_sh),\ - SF(OTG0_OTG_H_BLANK_START_END, OTG_H_BLANK_END, mask_sh),\ - SF(OTG0_OTG_H_SYNC_A, OTG_H_SYNC_A_START, mask_sh),\ - SF(OTG0_OTG_H_SYNC_A, OTG_H_SYNC_A_END, mask_sh),\ - SF(OTG0_OTG_H_SYNC_A_CNTL, OTG_H_SYNC_A_POL, mask_sh),\ - SF(OTG0_OTG_V_TOTAL, OTG_V_TOTAL, mask_sh),\ - SF(OTG0_OTG_V_BLANK_START_END, OTG_V_BLANK_START, mask_sh),\ - SF(OTG0_OTG_V_BLANK_START_END, OTG_V_BLANK_END, mask_sh),\ - SF(OTG0_OTG_V_SYNC_A, OTG_V_SYNC_A_START, mask_sh),\ - SF(OTG0_OTG_V_SYNC_A, OTG_V_SYNC_A_END, mask_sh),\ - SF(OTG0_OTG_V_SYNC_A_CNTL, OTG_V_SYNC_A_POL, mask_sh),\ - SF(OTG0_OTG_V_SYNC_A_CNTL, OTG_V_SYNC_MODE, mask_sh),\ - SF(OTG0_OTG_CONTROL, OTG_MASTER_EN, mask_sh),\ - SF(OTG0_OTG_CONTROL, OTG_START_POINT_CNTL, mask_sh),\ - SF(OTG0_OTG_CONTROL, OTG_DISABLE_POINT_CNTL, mask_sh),\ - SF(OTG0_OTG_CONTROL, OTG_FIELD_NUMBER_CNTL, mask_sh),\ - SF(OTG0_OTG_CONTROL, OTG_OUT_MUX, mask_sh),\ - SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_EN, mask_sh),\ - SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_SYNC_OUTPUT_LINE_NUM, mask_sh),\ - SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_SYNC_OUTPUT_POLARITY, mask_sh),\ - SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_EYE_FLAG_POLARITY, mask_sh),\ - SF(OTG0_OTG_STEREO_CONTROL, OTG_DISABLE_STEREOSYNC_OUTPUT_FOR_DP, mask_sh),\ - SF(OTG0_OTG_STEREO_STATUS, OTG_STEREO_CURRENT_EYE, mask_sh),\ - SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_EN, mask_sh),\ - SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_V_UPDATE_MODE, mask_sh),\ - SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_STEREO_SEL_OVR, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_MAX, OTG_V_TOTAL_MAX, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_MIN, OTG_V_TOTAL_MIN, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_V_TOTAL_MIN_SEL, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_V_TOTAL_MAX_SEL, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_FORCE_LOCK_ON_EVENT, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_SET_V_TOTAL_MIN_MASK, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_VTOTAL_MID_REPLACING_MIN_EN, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_VTOTAL_MID_REPLACING_MAX_EN, mask_sh),\ - SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_CLEAR, mask_sh),\ - SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_MODE, mask_sh),\ - SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_OCCURRED, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_SOURCE_SELECT, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_SOURCE_PIPE_SELECT, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_RISING_EDGE_DETECT_CNTL, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_POLARITY_SELECT, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_FREQUENCY_SELECT, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_DELAY, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_CLEAR, mask_sh),\ - SF(OTG0_OTG_STATIC_SCREEN_CONTROL, OTG_STATIC_SCREEN_EVENT_MASK, mask_sh),\ - SF(OTG0_OTG_STATIC_SCREEN_CONTROL, OTG_STATIC_SCREEN_FRAME_COUNT, mask_sh),\ - SF(OTG0_OTG_STATUS_FRAME_COUNT, OTG_FRAME_COUNT, mask_sh),\ - SF(OTG0_OTG_STATUS, OTG_V_BLANK, mask_sh),\ - SF(OTG0_OTG_STATUS, OTG_V_ACTIVE_DISP, mask_sh),\ - SF(OTG0_OTG_STATUS_POSITION, OTG_HORZ_COUNT, mask_sh),\ - SF(OTG0_OTG_STATUS_POSITION, OTG_VERT_COUNT, mask_sh),\ - SF(OTG0_OTG_NOM_VERT_POSITION, OTG_VERT_COUNT_NOM, mask_sh),\ - SF(OTG0_OTG_M_CONST_DTO0, OTG_M_CONST_DTO_PHASE, mask_sh),\ - SF(OTG0_OTG_M_CONST_DTO1, OTG_M_CONST_DTO_MODULO, mask_sh),\ - SF(OTG0_OTG_CLOCK_CONTROL, OTG_BUSY, mask_sh),\ - SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_EN, mask_sh),\ - SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_ON, mask_sh),\ - SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_GATE_DIS, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_INT_ENABLE, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT0_POSITION, OTG_VERTICAL_INTERRUPT0_LINE_START, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT0_POSITION, OTG_VERTICAL_INTERRUPT0_LINE_END, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT1_CONTROL, OTG_VERTICAL_INTERRUPT1_INT_ENABLE, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT1_POSITION, OTG_VERTICAL_INTERRUPT1_LINE_START, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT2_POSITION, OTG_VERTICAL_INTERRUPT2_LINE_START, mask_sh),\ - SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_EN, mask_sh),\ - SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_ON, mask_sh),\ - SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_GATE_DIS, mask_sh),\ - SF(ODM0_OPTC_INPUT_GLOBAL_CONTROL, OPTC_UNDERFLOW_OCCURRED_STATUS, mask_sh),\ - SF(ODM0_OPTC_INPUT_GLOBAL_CONTROL, OPTC_UNDERFLOW_CLEAR, mask_sh),\ - SF(VTG0_CONTROL, VTG0_ENABLE, mask_sh),\ - SF(VTG0_CONTROL, VTG0_FP2, mask_sh),\ - SF(VTG0_CONTROL, VTG0_VCOUNT_INIT, mask_sh),\ - SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_FORCE_VSYNC_NEXT_LINE_OCCURRED, mask_sh),\ - SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_FORCE_VSYNC_NEXT_LINE_CLEAR, mask_sh),\ - SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_AUTO_FORCE_VSYNC_MODE, mask_sh),\ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL0_EN, mask_sh),\ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL1_EN, mask_sh),\ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL2_EN, mask_sh),\ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_MASTER_EN, mask_sh),\ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_FORCE_DELAY, mask_sh),\ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_CHECK_ALL_FIELDS, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL, OTG_CRC_CONT_EN, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL, OTG_CRC0_SELECT, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL, OTG_CRC_EN, mask_sh),\ - SF(OTG0_OTG_CRC0_DATA_RG, CRC0_R_CR, mask_sh),\ - SF(OTG0_OTG_CRC0_DATA_RG, CRC0_G_Y, mask_sh),\ - SF(OTG0_OTG_CRC0_DATA_B, CRC0_B_CB, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWA_X_CONTROL, OTG_CRC0_WINDOWA_X_START, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWA_X_CONTROL, OTG_CRC0_WINDOWA_X_END, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWA_Y_CONTROL, OTG_CRC0_WINDOWA_Y_START, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWA_Y_CONTROL, OTG_CRC0_WINDOWA_Y_END, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWB_X_CONTROL, OTG_CRC0_WINDOWB_X_START, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWB_X_CONTROL, OTG_CRC0_WINDOWB_X_END, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL, OTG_CRC0_WINDOWB_Y_START, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL, OTG_CRC0_WINDOWB_Y_END, mask_sh),\ - SF(OTG0_OTG_TRIGA_MANUAL_TRIG, OTG_TRIGA_MANUAL_TRIG, mask_sh),\ - SF(GSL_SOURCE_SELECT, GSL0_READY_SOURCE_SEL, mask_sh),\ - SF(GSL_SOURCE_SELECT, GSL1_READY_SOURCE_SEL, mask_sh),\ - SF(GSL_SOURCE_SELECT, GSL2_READY_SOURCE_SEL, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL2, MANUAL_FLOW_CONTROL_SEL, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, mask_sh),\ - SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_START_X, mask_sh),\ - SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_END_X, mask_sh), \ - SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_START_Y, mask_sh),\ - SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_END_Y, mask_sh),\ - SF(OTG0_OTG_VUPDATE_KEEPOUT, OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, mask_sh), \ - SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET, mask_sh), \ - SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET, mask_sh), \ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_MASTER_MODE, mask_sh), \ - SF(OTG0_OTG_GSL_CONTROL, OTG_MASTER_UPDATE_LOCK_GSL_EN, mask_sh), \ - SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_X, mask_sh), \ - SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_LINE_NUM, mask_sh),\ - SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG0_SRC_SEL, mask_sh),\ - SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG1_SRC_SEL, mask_sh),\ - SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG2_SRC_SEL, mask_sh),\ - SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG3_SRC_SEL, mask_sh),\ - SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_NUM_OF_INPUT_SEGMENT, mask_sh),\ - SF(ODM0_OPTC_MEMORY_CONFIG, OPTC_MEM_SEL, mask_sh),\ - SF(ODM0_OPTC_DATA_FORMAT_CONTROL, OPTC_DATA_FORMAT, mask_sh),\ - SF(ODM0_OPTC_DATA_FORMAT_CONTROL, OPTC_DSC_MODE, mask_sh),\ - SF(ODM0_OPTC_BYTES_PER_PIXEL, OPTC_DSC_BYTES_PER_PIXEL, mask_sh),\ - SF(ODM0_OPTC_WIDTH_CONTROL, OPTC_DSC_SLICE_WIDTH, mask_sh),\ - SF(ODM0_OPTC_WIDTH_CONTROL, OPTC_SEGMENT_WIDTH, mask_sh),\ - SF(DWB_SOURCE_SELECT, OPTC_DWB0_SOURCE_SELECT, mask_sh),\ - SF(DWB_SOURCE_SELECT, OPTC_DWB1_SOURCE_SELECT, mask_sh),\ - SF(OTG0_OTG_DRR_TRIGGER_WINDOW, OTG_DRR_TRIGGER_WINDOW_START_X, mask_sh),\ - 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_MODE, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DSC_MODE, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_STREAM_COMBINE_MODE, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_STREAM_SPLIT_MODE, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_FORMAT, mask_sh),\ - SF(OTG0_OTG_DRR_CONTROL, OTG_V_TOTAL_LAST_USED_BY_DRR, mask_sh) - -void dcn31_timing_generator_init(struct optc *optc1); - -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); - -#endif /* __DC_OPTC_DCN31_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_panel_cntl.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_panel_cntl.c index 217acd4e292a30..03248422d6ffde 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_panel_cntl.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_panel_cntl.c @@ -50,9 +50,9 @@ static bool dcn31_query_backlight_info(struct panel_cntl *panel_cntl, union dmub cmd->panel_cntl.header.type = DMUB_CMD__PANEL_CNTL; cmd->panel_cntl.header.sub_type = DMUB_CMD__PANEL_CNTL_QUERY_BACKLIGHT_INFO; cmd->panel_cntl.header.payload_bytes = sizeof(cmd->panel_cntl.data); - cmd->panel_cntl.data.inst = dcn31_panel_cntl->base.inst; + cmd->panel_cntl.data.pwrseq_inst = dcn31_panel_cntl->base.pwrseq_inst; - return dm_execute_dmub_cmd(dc_dmub_srv->ctx, cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY); + return dc_wake_and_execute_dmub_cmd(dc_dmub_srv->ctx, cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY); } static uint32_t dcn31_get_16_bit_backlight_from_pwm(struct panel_cntl *panel_cntl) @@ -78,14 +78,14 @@ static uint32_t dcn31_panel_cntl_hw_init(struct panel_cntl *panel_cntl) cmd.panel_cntl.header.type = DMUB_CMD__PANEL_CNTL; cmd.panel_cntl.header.sub_type = DMUB_CMD__PANEL_CNTL_HW_INIT; cmd.panel_cntl.header.payload_bytes = sizeof(cmd.panel_cntl.data); - cmd.panel_cntl.data.inst = dcn31_panel_cntl->base.inst; + cmd.panel_cntl.data.pwrseq_inst = dcn31_panel_cntl->base.pwrseq_inst; cmd.panel_cntl.data.bl_pwm_cntl = panel_cntl->stored_backlight_registers.BL_PWM_CNTL; cmd.panel_cntl.data.bl_pwm_period_cntl = panel_cntl->stored_backlight_registers.BL_PWM_PERIOD_CNTL; cmd.panel_cntl.data.bl_pwm_ref_div1 = panel_cntl->stored_backlight_registers.LVTMA_PWRSEQ_REF_DIV_BL_PWM_REF_DIV; cmd.panel_cntl.data.bl_pwm_ref_div2 = panel_cntl->stored_backlight_registers.PANEL_PWRSEQ_REF_DIV2; - if (!dm_execute_dmub_cmd(dc_dmub_srv->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) + if (!dc_wake_and_execute_dmub_cmd(dc_dmub_srv->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) return 0; panel_cntl->stored_backlight_registers.BL_PWM_CNTL = cmd.panel_cntl.data.bl_pwm_cntl; @@ -157,4 +157,5 @@ void dcn31_panel_cntl_construct( dcn31_panel_cntl->base.funcs = &dcn31_link_panel_cntl_funcs; dcn31_panel_cntl->base.ctx = init_data->ctx; dcn31_panel_cntl->base.inst = init_data->inst; + dcn31_panel_cntl->base.pwrseq_inst = init_data->pwrseq_inst; } diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c deleted file mode 100644 index 79416cfb22f09d..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c +++ /dev/null @@ -1,2218 +0,0 @@ -/* - * Copyright 2019 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 "dcn31/dcn31_init.h" - -#include "resource.h" -#include "include/irq_service_interface.h" -#include "dcn31_resource.h" - -#include "dcn20/dcn20_resource.h" -#include "dcn30/dcn30_resource.h" - -#include "dml/dcn30/dcn30_fpu.h" - -#include "dcn10/dcn10_ipp.h" -#include "dcn30/dcn30_hubbub.h" -#include "dcn31/dcn31_hubbub.h" -#include "dcn30/dcn30_mpc.h" -#include "dcn31/dcn31_hubp.h" -#include "irq/dcn31/irq_service_dcn31.h" -#include "dcn30/dcn30_dpp.h" -#include "dcn31/dcn31_optc.h" -#include "dcn20/dcn20_hwseq.h" -#include "dcn30/dcn30_hwseq.h" -#include "dce110/dce110_hwseq.h" -#include "dcn30/dcn30_opp.h" -#include "dcn20/dcn20_dsc.h" -#include "dcn30/dcn30_vpg.h" -#include "dcn30/dcn30_afmt.h" -#include "dcn30/dcn30_dio_stream_encoder.h" -#include "dcn31/dcn31_hpo_dp_stream_encoder.h" -#include "dcn31/dcn31_hpo_dp_link_encoder.h" -#include "dcn31/dcn31_apg.h" -#include "dcn31/dcn31_dio_link_encoder.h" -#include "dcn31/dcn31_vpg.h" -#include "dcn31/dcn31_afmt.h" -#include "dce/dce_clock_source.h" -#include "dce/dce_audio.h" -#include "dce/dce_hwseq.h" -#include "clk_mgr.h" -#include "virtual/virtual_stream_encoder.h" -#include "dce110/dce110_resource.h" -#include "dml/display_mode_vba.h" -#include "dml/dcn31/dcn31_fpu.h" -#include "dcn31/dcn31_dccg.h" -#include "dcn10/dcn10_resource.h" -#include "dcn31_panel_cntl.h" - -#include "dcn30/dcn30_dwb.h" -#include "dcn30/dcn30_mmhubbub.h" - -// TODO: change include headers /amd/include/asic_reg after upstream -#include "yellow_carp_offset.h" -#include "dcn/dcn_3_1_2_offset.h" -#include "dcn/dcn_3_1_2_sh_mask.h" -#include "nbio/nbio_7_2_0_offset.h" -#include "dpcs/dpcs_4_2_0_offset.h" -#include "dpcs/dpcs_4_2_0_sh_mask.h" -#include "mmhub/mmhub_2_3_0_offset.h" -#include "mmhub/mmhub_2_3_0_sh_mask.h" - - -#define regDCHUBBUB_DEBUG_CTRL_0 0x04d6 -#define regDCHUBBUB_DEBUG_CTRL_0_BASE_IDX 2 -#define DCHUBBUB_DEBUG_CTRL_0__DET_DEPTH__SHIFT 0x10 -#define DCHUBBUB_DEBUG_CTRL_0__DET_DEPTH_MASK 0x01FF0000L - -#include "reg_helper.h" -#include "dce/dmub_abm.h" -#include "dce/dmub_psr.h" -#include "dce/dce_aux.h" -#include "dce/dce_i2c.h" -#include "dce/dmub_replay.h" - -#include "dml/dcn30/display_mode_vba_30.h" -#include "vm_helper.h" -#include "dcn20/dcn20_vmid.h" - -#include "link_enc_cfg.h" - -#define DC_LOGGER \ - dc->ctx->logger -#define DC_LOGGER_INIT(logger) - -enum dcn31_clk_src_array_id { - DCN31_CLK_SRC_PLL0, - DCN31_CLK_SRC_PLL1, - DCN31_CLK_SRC_PLL2, - DCN31_CLK_SRC_PLL3, - DCN31_CLK_SRC_PLL4, - DCN30_CLK_SRC_TOTAL -}; - -/* begin ********************* - * macros to expend register list macro defined in HW object header file - */ - -/* DCN */ -#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg - -#define BASE(seg) BASE_INNER(seg) - -#define SR(reg_name)\ - .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ - reg ## reg_name - -#define SRI(reg_name, block, id)\ - .reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRI2(reg_name, block, id)\ - .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ - reg ## reg_name - -#define SRIR(var_name, reg_name, block, id)\ - .var_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRII(reg_name, block, id)\ - .reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRII_MPC_RMU(reg_name, block, id)\ - .RMU##_##reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRII_DWB(reg_name, temp_name, block, id)\ - .reg_name[id] = BASE(reg ## block ## id ## _ ## temp_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## temp_name - -#define SF_DWB2(reg_name, block, id, field_name, post_fix) \ - .field_name = reg_name ## __ ## field_name ## post_fix - -#define DCCG_SRII(reg_name, block, id)\ - .block ## _ ## reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define VUPDATE_SRII(reg_name, block, id)\ - .reg_name[id] = BASE(reg ## reg_name ## _ ## block ## id ## _BASE_IDX) + \ - reg ## reg_name ## _ ## block ## id - -/* NBIO */ -#define NBIO_BASE_INNER(seg) \ - NBIO_BASE__INST0_SEG ## seg - -#define NBIO_BASE(seg) \ - NBIO_BASE_INNER(seg) - -#define NBIO_SR(reg_name)\ - .reg_name = NBIO_BASE(regBIF_BX1_ ## reg_name ## _BASE_IDX) + \ - regBIF_BX1_ ## reg_name - -/* MMHUB */ -#define MMHUB_BASE_INNER(seg) \ - MMHUB_BASE__INST0_SEG ## seg - -#define MMHUB_BASE(seg) \ - MMHUB_BASE_INNER(seg) - -#define MMHUB_SR(reg_name)\ - .reg_name = MMHUB_BASE(mm ## reg_name ## _BASE_IDX) + \ - mm ## reg_name - -/* CLOCK */ -#define CLK_BASE_INNER(seg) \ - CLK_BASE__INST0_SEG ## seg - -#define CLK_BASE(seg) \ - CLK_BASE_INNER(seg) - -#define CLK_SRI(reg_name, block, inst)\ - .reg_name = CLK_BASE(reg ## block ## _ ## inst ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## _ ## inst ## _ ## reg_name - - -static const struct bios_registers bios_regs = { - NBIO_SR(BIOS_SCRATCH_3), - NBIO_SR(BIOS_SCRATCH_6) -}; - -#define clk_src_regs(index, pllid)\ -[index] = {\ - CS_COMMON_REG_LIST_DCN3_0(index, pllid),\ -} - -static const struct dce110_clk_src_regs clk_src_regs[] = { - clk_src_regs(0, A), - clk_src_regs(1, B), - clk_src_regs(2, C), - clk_src_regs(3, D), - clk_src_regs(4, E) -}; -/*pll_id being rempped in dmub, in driver it is logical instance*/ -static const struct dce110_clk_src_regs clk_src_regs_b0[] = { - clk_src_regs(0, A), - clk_src_regs(1, B), - clk_src_regs(2, F), - clk_src_regs(3, G), - clk_src_regs(4, E) -}; - -static const struct dce110_clk_src_shift cs_shift = { - CS_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) -}; - -static const struct dce110_clk_src_mask cs_mask = { - CS_COMMON_MASK_SH_LIST_DCN2_0(_MASK) -}; - -#define abm_regs(id)\ -[id] = {\ - ABM_DCN302_REG_LIST(id)\ -} - -static const struct dce_abm_registers abm_regs[] = { - abm_regs(0), - abm_regs(1), - abm_regs(2), - abm_regs(3), -}; - -static const struct dce_abm_shift abm_shift = { - ABM_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dce_abm_mask abm_mask = { - ABM_MASK_SH_LIST_DCN30(_MASK) -}; - -#define audio_regs(id)\ -[id] = {\ - AUD_COMMON_REG_LIST(id)\ -} - -static const struct dce_audio_registers audio_regs[] = { - audio_regs(0), - audio_regs(1), - audio_regs(2), - audio_regs(3), - audio_regs(4), - audio_regs(5), - audio_regs(6) -}; - -#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ - SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ - SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ - AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) - -static const struct dce_audio_shift audio_shift = { - DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_audio_mask audio_mask = { - DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) -}; - -#define vpg_regs(id)\ -[id] = {\ - VPG_DCN31_REG_LIST(id)\ -} - -static const struct dcn31_vpg_registers vpg_regs[] = { - vpg_regs(0), - vpg_regs(1), - vpg_regs(2), - vpg_regs(3), - vpg_regs(4), - vpg_regs(5), - vpg_regs(6), - vpg_regs(7), - vpg_regs(8), - vpg_regs(9), -}; - -static const struct dcn31_vpg_shift vpg_shift = { - DCN31_VPG_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn31_vpg_mask vpg_mask = { - DCN31_VPG_MASK_SH_LIST(_MASK) -}; - -#define afmt_regs(id)\ -[id] = {\ - AFMT_DCN31_REG_LIST(id)\ -} - -static const struct dcn31_afmt_registers afmt_regs[] = { - afmt_regs(0), - afmt_regs(1), - afmt_regs(2), - afmt_regs(3), - afmt_regs(4), - afmt_regs(5) -}; - -static const struct dcn31_afmt_shift afmt_shift = { - DCN31_AFMT_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn31_afmt_mask afmt_mask = { - DCN31_AFMT_MASK_SH_LIST(_MASK) -}; - -#define apg_regs(id)\ -[id] = {\ - APG_DCN31_REG_LIST(id)\ -} - -static const struct dcn31_apg_registers apg_regs[] = { - apg_regs(0), - apg_regs(1), - apg_regs(2), - apg_regs(3) -}; - -static const struct dcn31_apg_shift apg_shift = { - DCN31_APG_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn31_apg_mask apg_mask = { - DCN31_APG_MASK_SH_LIST(_MASK) -}; - -#define stream_enc_regs(id)\ -[id] = {\ - SE_DCN3_REG_LIST(id)\ -} - -/* Some encoders won't be initialized here - but they're logical, not physical. */ -static const struct dcn10_stream_enc_registers stream_enc_regs[ENGINE_ID_COUNT] = { - stream_enc_regs(0), - stream_enc_regs(1), - stream_enc_regs(2), - stream_enc_regs(3), - stream_enc_regs(4) -}; - -static const struct dcn10_stream_encoder_shift se_shift = { - SE_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn10_stream_encoder_mask se_mask = { - SE_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - - -#define aux_regs(id)\ -[id] = {\ - DCN2_AUX_REG_LIST(id)\ -} - -static const struct dcn10_link_enc_aux_registers link_enc_aux_regs[] = { - aux_regs(0), - aux_regs(1), - aux_regs(2), - aux_regs(3), - aux_regs(4) -}; - -#define hpd_regs(id)\ -[id] = {\ - HPD_REG_LIST(id)\ -} - -static const struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[] = { - hpd_regs(0), - hpd_regs(1), - hpd_regs(2), - hpd_regs(3), - hpd_regs(4) -}; - -#define link_regs(id, phyid)\ -[id] = {\ - LE_DCN31_REG_LIST(id), \ - UNIPHY_DCN2_REG_LIST(phyid), \ - DPCS_DCN31_REG_LIST(id), \ -} - -static const struct dce110_aux_registers_shift aux_shift = { - DCN_AUX_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce110_aux_registers_mask aux_mask = { - DCN_AUX_MASK_SH_LIST(_MASK) -}; - -static const struct dcn10_link_enc_registers link_enc_regs[] = { - link_regs(0, A), - link_regs(1, B), - link_regs(2, C), - link_regs(3, D), - link_regs(4, E) -}; - -static const struct dcn10_link_enc_shift le_shift = { - LINK_ENCODER_MASK_SH_LIST_DCN31(__SHIFT), \ - DPCS_DCN31_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn10_link_enc_mask le_mask = { - LINK_ENCODER_MASK_SH_LIST_DCN31(_MASK), \ - DPCS_DCN31_MASK_SH_LIST(_MASK) -}; - -#define hpo_dp_stream_encoder_reg_list(id)\ -[id] = {\ - DCN3_1_HPO_DP_STREAM_ENC_REG_LIST(id)\ -} - -static const struct dcn31_hpo_dp_stream_encoder_registers hpo_dp_stream_enc_regs[] = { - hpo_dp_stream_encoder_reg_list(0), - hpo_dp_stream_encoder_reg_list(1), - hpo_dp_stream_encoder_reg_list(2), - hpo_dp_stream_encoder_reg_list(3), -}; - -static const struct dcn31_hpo_dp_stream_encoder_shift hpo_dp_se_shift = { - DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn31_hpo_dp_stream_encoder_mask hpo_dp_se_mask = { - DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(_MASK) -}; - -#define hpo_dp_link_encoder_reg_list(id)\ -[id] = {\ - DCN3_1_HPO_DP_LINK_ENC_REG_LIST(id),\ - DCN3_1_RDPCSTX_REG_LIST(0),\ - DCN3_1_RDPCSTX_REG_LIST(1),\ - DCN3_1_RDPCSTX_REG_LIST(2),\ - DCN3_1_RDPCSTX_REG_LIST(3),\ - DCN3_1_RDPCSTX_REG_LIST(4)\ -} - -static const struct dcn31_hpo_dp_link_encoder_registers hpo_dp_link_enc_regs[] = { - hpo_dp_link_encoder_reg_list(0), - hpo_dp_link_encoder_reg_list(1), -}; - -static const struct dcn31_hpo_dp_link_encoder_shift hpo_dp_le_shift = { - DCN3_1_HPO_DP_LINK_ENC_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn31_hpo_dp_link_encoder_mask hpo_dp_le_mask = { - DCN3_1_HPO_DP_LINK_ENC_MASK_SH_LIST(_MASK) -}; - -#define dpp_regs(id)\ -[id] = {\ - DPP_REG_LIST_DCN30(id),\ -} - -static const struct dcn3_dpp_registers dpp_regs[] = { - dpp_regs(0), - dpp_regs(1), - dpp_regs(2), - dpp_regs(3) -}; - -static const struct dcn3_dpp_shift tf_shift = { - DPP_REG_LIST_SH_MASK_DCN30(__SHIFT) -}; - -static const struct dcn3_dpp_mask tf_mask = { - DPP_REG_LIST_SH_MASK_DCN30(_MASK) -}; - -#define opp_regs(id)\ -[id] = {\ - OPP_REG_LIST_DCN30(id),\ -} - -static const struct dcn20_opp_registers opp_regs[] = { - opp_regs(0), - opp_regs(1), - opp_regs(2), - opp_regs(3) -}; - -static const struct dcn20_opp_shift opp_shift = { - OPP_MASK_SH_LIST_DCN20(__SHIFT) -}; - -static const struct dcn20_opp_mask opp_mask = { - OPP_MASK_SH_LIST_DCN20(_MASK) -}; - -#define aux_engine_regs(id)\ -[id] = {\ - AUX_COMMON_REG_LIST0(id), \ - .AUXN_IMPCAL = 0, \ - .AUXP_IMPCAL = 0, \ - .AUX_RESET_MASK = DP_AUX0_AUX_CONTROL__AUX_RESET_MASK, \ -} - -static const struct dce110_aux_registers aux_engine_regs[] = { - aux_engine_regs(0), - aux_engine_regs(1), - aux_engine_regs(2), - aux_engine_regs(3), - aux_engine_regs(4) -}; - -#define dwbc_regs_dcn3(id)\ -[id] = {\ - DWBC_COMMON_REG_LIST_DCN30(id),\ -} - -static const struct dcn30_dwbc_registers dwbc30_regs[] = { - dwbc_regs_dcn3(0), -}; - -static const struct dcn30_dwbc_shift dwbc30_shift = { - DWBC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn30_dwbc_mask dwbc30_mask = { - DWBC_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -#define mcif_wb_regs_dcn3(id)\ -[id] = {\ - MCIF_WB_COMMON_REG_LIST_DCN30(id),\ -} - -static const struct dcn30_mmhubbub_registers mcif_wb30_regs[] = { - mcif_wb_regs_dcn3(0) -}; - -static const struct dcn30_mmhubbub_shift mcif_wb30_shift = { - MCIF_WB_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn30_mmhubbub_mask mcif_wb30_mask = { - MCIF_WB_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -#define dsc_regsDCN20(id)\ -[id] = {\ - DSC_REG_LIST_DCN20(id)\ -} - -static const struct dcn20_dsc_registers dsc_regs[] = { - dsc_regsDCN20(0), - dsc_regsDCN20(1), - dsc_regsDCN20(2) -}; - -static const struct dcn20_dsc_shift dsc_shift = { - DSC_REG_LIST_SH_MASK_DCN20(__SHIFT) -}; - -static const struct dcn20_dsc_mask dsc_mask = { - DSC_REG_LIST_SH_MASK_DCN20(_MASK) -}; - -static const struct dcn30_mpc_registers mpc_regs = { - MPC_REG_LIST_DCN3_0(0), - MPC_REG_LIST_DCN3_0(1), - MPC_REG_LIST_DCN3_0(2), - MPC_REG_LIST_DCN3_0(3), - MPC_OUT_MUX_REG_LIST_DCN3_0(0), - MPC_OUT_MUX_REG_LIST_DCN3_0(1), - MPC_OUT_MUX_REG_LIST_DCN3_0(2), - MPC_OUT_MUX_REG_LIST_DCN3_0(3), - MPC_RMU_GLOBAL_REG_LIST_DCN3AG, - MPC_RMU_REG_LIST_DCN3AG(0), - MPC_RMU_REG_LIST_DCN3AG(1), - //MPC_RMU_REG_LIST_DCN3AG(2), - MPC_DWB_MUX_REG_LIST_DCN3_0(0), -}; - -static const struct dcn30_mpc_shift mpc_shift = { - MPC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn30_mpc_mask mpc_mask = { - MPC_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -#define optc_regs(id)\ -[id] = {OPTC_COMMON_REG_LIST_DCN3_1(id)} - -static const struct dcn_optc_registers optc_regs[] = { - optc_regs(0), - optc_regs(1), - optc_regs(2), - optc_regs(3) -}; - -static const struct dcn_optc_shift optc_shift = { - OPTC_COMMON_MASK_SH_LIST_DCN3_1(__SHIFT) -}; - -static const struct dcn_optc_mask optc_mask = { - OPTC_COMMON_MASK_SH_LIST_DCN3_1(_MASK) -}; - -#define hubp_regs(id)\ -[id] = {\ - HUBP_REG_LIST_DCN30(id)\ -} - -static const struct dcn_hubp2_registers hubp_regs[] = { - hubp_regs(0), - hubp_regs(1), - hubp_regs(2), - hubp_regs(3) -}; - - -static const struct dcn_hubp2_shift hubp_shift = { - HUBP_MASK_SH_LIST_DCN31(__SHIFT) -}; - -static const struct dcn_hubp2_mask hubp_mask = { - HUBP_MASK_SH_LIST_DCN31(_MASK) -}; -static const struct dcn_hubbub_registers hubbub_reg = { - HUBBUB_REG_LIST_DCN31(0) -}; - -static const struct dcn_hubbub_shift hubbub_shift = { - HUBBUB_MASK_SH_LIST_DCN31(__SHIFT) -}; - -static const struct dcn_hubbub_mask hubbub_mask = { - HUBBUB_MASK_SH_LIST_DCN31(_MASK) -}; - -static const struct dccg_registers dccg_regs = { - DCCG_REG_LIST_DCN31() -}; - -static const struct dccg_shift dccg_shift = { - DCCG_MASK_SH_LIST_DCN31(__SHIFT) -}; - -static const struct dccg_mask dccg_mask = { - DCCG_MASK_SH_LIST_DCN31(_MASK) -}; - - -#define SRII2(reg_name_pre, reg_name_post, id)\ - .reg_name_pre ## _ ## reg_name_post[id] = BASE(reg ## reg_name_pre \ - ## id ## _ ## reg_name_post ## _BASE_IDX) + \ - reg ## reg_name_pre ## id ## _ ## reg_name_post - - -#define HWSEQ_DCN31_REG_LIST()\ - SR(DCHUBBUB_GLOBAL_TIMER_CNTL), \ - SR(DCHUBBUB_ARB_HOSTVM_CNTL), \ - SR(DIO_MEM_PWR_CTRL), \ - SR(ODM_MEM_PWR_CTRL3), \ - SR(DMU_MEM_PWR_CNTL), \ - SR(MMHUBBUB_MEM_PWR_CNTL), \ - SR(DCCG_GATE_DISABLE_CNTL), \ - SR(DCCG_GATE_DISABLE_CNTL2), \ - SR(DCFCLK_CNTL),\ - SR(DC_MEM_GLOBAL_PWR_REQ_CNTL), \ - SRII(PIXEL_RATE_CNTL, OTG, 0), \ - SRII(PIXEL_RATE_CNTL, OTG, 1),\ - SRII(PIXEL_RATE_CNTL, OTG, 2),\ - SRII(PIXEL_RATE_CNTL, OTG, 3),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 0),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 1),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 2),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 3),\ - SR(MICROSECOND_TIME_BASE_DIV), \ - SR(MILLISECOND_TIME_BASE_DIV), \ - SR(DISPCLK_FREQ_CHANGE_CNTL), \ - SR(RBBMIF_TIMEOUT_DIS), \ - SR(RBBMIF_TIMEOUT_DIS_2), \ - SR(DCHUBBUB_CRC_CTRL), \ - SR(DPP_TOP0_DPP_CRC_CTRL), \ - SR(DPP_TOP0_DPP_CRC_VAL_B_A), \ - SR(DPP_TOP0_DPP_CRC_VAL_R_G), \ - SR(MPC_CRC_CTRL), \ - SR(MPC_CRC_RESULT_GB), \ - SR(MPC_CRC_RESULT_C), \ - SR(MPC_CRC_RESULT_AR), \ - SR(DOMAIN0_PG_CONFIG), \ - SR(DOMAIN1_PG_CONFIG), \ - SR(DOMAIN2_PG_CONFIG), \ - SR(DOMAIN3_PG_CONFIG), \ - SR(DOMAIN16_PG_CONFIG), \ - SR(DOMAIN17_PG_CONFIG), \ - SR(DOMAIN18_PG_CONFIG), \ - SR(DOMAIN0_PG_STATUS), \ - SR(DOMAIN1_PG_STATUS), \ - SR(DOMAIN2_PG_STATUS), \ - SR(DOMAIN3_PG_STATUS), \ - SR(DOMAIN16_PG_STATUS), \ - SR(DOMAIN17_PG_STATUS), \ - SR(DOMAIN18_PG_STATUS), \ - SR(D1VGA_CONTROL), \ - SR(D2VGA_CONTROL), \ - SR(D3VGA_CONTROL), \ - SR(D4VGA_CONTROL), \ - SR(D5VGA_CONTROL), \ - SR(D6VGA_CONTROL), \ - SR(DC_IP_REQUEST_CNTL), \ - SR(AZALIA_AUDIO_DTO), \ - SR(AZALIA_CONTROLLER_CLOCK_GATING), \ - SR(HPO_TOP_HW_CONTROL) - -static const struct dce_hwseq_registers hwseq_reg = { - HWSEQ_DCN31_REG_LIST() -}; - -#define HWSEQ_DCN31_MASK_SH_LIST(mask_sh)\ - HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ - HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \ - HWS_SF(, DCHUBBUB_ARB_HOSTVM_CNTL, DISABLE_HOSTVM_FORCE_ALLOW_PSTATE, mask_sh), \ - HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN16_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN17_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN18_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \ - HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh), \ - HWS_SF(, HPO_TOP_CLOCK_CONTROL, HPO_HDMISTREAMCLK_G_GATE_DIS, mask_sh), \ - HWS_SF(, DMU_MEM_PWR_CNTL, DMCU_ERAM_MEM_PWR_FORCE, mask_sh), \ - HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_UNASSIGNED_PWR_MODE, mask_sh), \ - HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_VBLANK_PWR_MODE, mask_sh), \ - HWS_SF(, MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, mask_sh), \ - HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh), \ - HWS_SF(, HPO_TOP_HW_CONTROL, HPO_IO_EN, mask_sh) - -static const struct dce_hwseq_shift hwseq_shift = { - HWSEQ_DCN31_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_hwseq_mask hwseq_mask = { - HWSEQ_DCN31_MASK_SH_LIST(_MASK) -}; -#define vmid_regs(id)\ -[id] = {\ - DCN20_VMID_REG_LIST(id)\ -} - -static const struct dcn_vmid_registers vmid_regs[] = { - vmid_regs(0), - vmid_regs(1), - vmid_regs(2), - vmid_regs(3), - vmid_regs(4), - vmid_regs(5), - vmid_regs(6), - vmid_regs(7), - vmid_regs(8), - vmid_regs(9), - vmid_regs(10), - vmid_regs(11), - vmid_regs(12), - vmid_regs(13), - vmid_regs(14), - vmid_regs(15) -}; - -static const struct dcn20_vmid_shift vmid_shifts = { - DCN20_VMID_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn20_vmid_mask vmid_masks = { - DCN20_VMID_MASK_SH_LIST(_MASK) -}; - -static const struct resource_caps res_cap_dcn31 = { - .num_timing_generator = 4, - .num_opp = 4, - .num_video_plane = 4, - .num_audio = 5, - .num_stream_encoder = 5, - .num_dig_link_enc = 5, - .num_hpo_dp_stream_encoder = 4, - .num_hpo_dp_link_encoder = 2, - .num_pll = 5, - .num_dwb = 1, - .num_ddc = 5, - .num_vmid = 16, - .num_mpc_3dlut = 2, - .num_dsc = 3, -}; - -static const struct dc_plane_cap plane_cap = { - .type = DC_PLANE_TYPE_DCN_UNIVERSAL, - .per_pixel_alpha = true, - - .pixel_format_support = { - .argb8888 = true, - .nv12 = true, - .fp16 = true, - .p010 = true, - .ayuv = false, - }, - - .max_upscale_factor = { - .argb8888 = 16000, - .nv12 = 16000, - .fp16 = 16000 - }, - - // 6:1 downscaling ratio: 1000/6 = 166.666 - .max_downscale_factor = { - .argb8888 = 167, - .nv12 = 167, - .fp16 = 167 - }, - 64, - 64 -}; - -static const struct dc_debug_options debug_defaults_drv = { - .disable_dmcu = true, - .force_abm_enable = false, - .timing_trace = false, - .clock_trace = true, - .disable_pplib_clock_request = false, - .pipe_split_policy = MPC_SPLIT_DYNAMIC, - .force_single_disp_pipe_split = false, - .disable_dcc = DCC_ENABLE, - .vsr_support = true, - .performance_trace = false, - .max_downscale_src_width = 4096,/*upto true 4K*/ - .disable_pplib_wm_range = false, - .scl_reset_length10 = true, - .sanity_checks = true, - .underflow_assert_delay_us = 0xFFFFFFFF, - .dwb_fi_phase = -1, // -1 = disable, - .dmub_command_table = true, - .pstate_enabled = true, - .use_max_lb = true, - .enable_mem_low_power = { - .bits = { - .vga = true, - .i2c = true, - .dmcu = false, // This is previously known to cause hang on S3 cycles if enabled - .dscl = true, - .cm = true, - .mpc = true, - .optc = true, - .vpg = true, - .afmt = true, - } - }, - .disable_z10 = true, - .enable_legacy_fast_update = true, - .enable_z9_disable_interface = true, /* Allow support for the PMFW interface for disable Z9*/ - .dml_hostvm_override = DML_HOSTVM_OVERRIDE_FALSE, - .using_dml2 = false, -}; - -static const struct dc_panel_config panel_config_defaults = { - .psr = { - .disable_psr = false, - .disallow_psrsu = false, - .disallow_replay = false, - }, - .ilr = { - .optimize_edp_link_rate = true, - }, -}; - -static void dcn31_dpp_destroy(struct dpp **dpp) -{ - kfree(TO_DCN20_DPP(*dpp)); - *dpp = NULL; -} - -static struct dpp *dcn31_dpp_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn3_dpp *dpp = - kzalloc(sizeof(struct dcn3_dpp), GFP_KERNEL); - - if (!dpp) - return NULL; - - if (dpp3_construct(dpp, ctx, inst, - &dpp_regs[inst], &tf_shift, &tf_mask)) - return &dpp->base; - - BREAK_TO_DEBUGGER(); - kfree(dpp); - return NULL; -} - -static struct output_pixel_processor *dcn31_opp_create( - struct dc_context *ctx, uint32_t inst) -{ - struct dcn20_opp *opp = - kzalloc(sizeof(struct dcn20_opp), GFP_KERNEL); - - if (!opp) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dcn20_opp_construct(opp, ctx, inst, - &opp_regs[inst], &opp_shift, &opp_mask); - return &opp->base; -} - -static struct dce_aux *dcn31_aux_engine_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct aux_engine_dce110 *aux_engine = - kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); - - if (!aux_engine) - return NULL; - - dce110_aux_engine_construct(aux_engine, ctx, inst, - SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, - &aux_engine_regs[inst], - &aux_mask, - &aux_shift, - ctx->dc->caps.extended_aux_timeout_support); - - return &aux_engine->base; -} -#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST_DCN30(id) } - -static const struct dce_i2c_registers i2c_hw_regs[] = { - i2c_inst_regs(1), - i2c_inst_regs(2), - i2c_inst_regs(3), - i2c_inst_regs(4), - i2c_inst_regs(5), -}; - -static const struct dce_i2c_shift i2c_shifts = { - I2C_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dce_i2c_mask i2c_masks = { - I2C_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -static struct dce_i2c_hw *dcn31_i2c_hw_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dce_i2c_hw *dce_i2c_hw = - kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); - - if (!dce_i2c_hw) - return NULL; - - dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst, - &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); - - return dce_i2c_hw; -} -static struct mpc *dcn31_mpc_create( - struct dc_context *ctx, - int num_mpcc, - int num_rmu) -{ - struct dcn30_mpc *mpc30 = kzalloc(sizeof(struct dcn30_mpc), - GFP_KERNEL); - - if (!mpc30) - return NULL; - - dcn30_mpc_construct(mpc30, ctx, - &mpc_regs, - &mpc_shift, - &mpc_mask, - num_mpcc, - num_rmu); - - return &mpc30->base; -} - -static struct hubbub *dcn31_hubbub_create(struct dc_context *ctx) -{ - int i; - - struct dcn20_hubbub *hubbub3 = kzalloc(sizeof(struct dcn20_hubbub), - GFP_KERNEL); - - if (!hubbub3) - return NULL; - - hubbub31_construct(hubbub3, ctx, - &hubbub_reg, - &hubbub_shift, - &hubbub_mask, - dcn3_1_ip.det_buffer_size_kbytes, - dcn3_1_ip.pixel_chunk_size_kbytes, - dcn3_1_ip.config_return_buffer_size_in_kbytes); - - - for (i = 0; i < res_cap_dcn31.num_vmid; i++) { - struct dcn20_vmid *vmid = &hubbub3->vmid[i]; - - vmid->ctx = ctx; - - vmid->regs = &vmid_regs[i]; - vmid->shifts = &vmid_shifts; - vmid->masks = &vmid_masks; - } - - return &hubbub3->base; -} - -static struct timing_generator *dcn31_timing_generator_create( - struct dc_context *ctx, - uint32_t instance) -{ - struct optc *tgn10 = - kzalloc(sizeof(struct optc), GFP_KERNEL); - - if (!tgn10) - return NULL; - - tgn10->base.inst = instance; - tgn10->base.ctx = ctx; - - tgn10->tg_regs = &optc_regs[instance]; - tgn10->tg_shift = &optc_shift; - tgn10->tg_mask = &optc_mask; - - dcn31_timing_generator_init(tgn10); - - return &tgn10->base; -} - -static const struct encoder_feature_support link_enc_feature = { - .max_hdmi_deep_color = COLOR_DEPTH_121212, - .max_hdmi_pixel_clock = 600000, - .hdmi_ycbcr420_supported = true, - .dp_ycbcr420_supported = true, - .fec_supported = true, - .flags.bits.IS_HBR2_CAPABLE = true, - .flags.bits.IS_HBR3_CAPABLE = true, - .flags.bits.IS_TPS3_CAPABLE = true, - .flags.bits.IS_TPS4_CAPABLE = true -}; - -static struct link_encoder *dcn31_link_encoder_create( - struct dc_context *ctx, - const struct encoder_init_data *enc_init_data) -{ - struct dcn20_link_encoder *enc20 = - kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); - - if (!enc20) - return NULL; - - dcn31_link_encoder_construct(enc20, - enc_init_data, - &link_enc_feature, - &link_enc_regs[enc_init_data->transmitter], - &link_enc_aux_regs[enc_init_data->channel - 1], - &link_enc_hpd_regs[enc_init_data->hpd_source], - &le_shift, - &le_mask); - - return &enc20->enc10.base; -} - -/* Create a minimal link encoder object not associated with a particular - * physical connector. - * resource_funcs.link_enc_create_minimal - */ -static struct link_encoder *dcn31_link_enc_create_minimal( - struct dc_context *ctx, enum engine_id eng_id) -{ - struct dcn20_link_encoder *enc20; - - if ((eng_id - ENGINE_ID_DIGA) > ctx->dc->res_pool->res_cap->num_dig_link_enc) - return NULL; - - enc20 = kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); - if (!enc20) - return NULL; - - dcn31_link_encoder_construct_minimal( - enc20, - ctx, - &link_enc_feature, - &link_enc_regs[eng_id - ENGINE_ID_DIGA], - eng_id); - - return &enc20->enc10.base; -} - -static struct panel_cntl *dcn31_panel_cntl_create(const struct panel_cntl_init_data *init_data) -{ - struct dcn31_panel_cntl *panel_cntl = - kzalloc(sizeof(struct dcn31_panel_cntl), GFP_KERNEL); - - if (!panel_cntl) - return NULL; - - dcn31_panel_cntl_construct(panel_cntl, init_data); - - return &panel_cntl->base; -} - -static void read_dce_straps( - struct dc_context *ctx, - struct resource_straps *straps) -{ - generic_reg_get(ctx, regDC_PINSTRAPS + BASE(regDC_PINSTRAPS_BASE_IDX), - FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio); - -} - -static struct audio *dcn31_create_audio( - struct dc_context *ctx, unsigned int inst) -{ - return dce_audio_create(ctx, inst, - &audio_regs[inst], &audio_shift, &audio_mask); -} - -static struct vpg *dcn31_vpg_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn31_vpg *vpg31 = kzalloc(sizeof(struct dcn31_vpg), GFP_KERNEL); - - if (!vpg31) - return NULL; - - vpg31_construct(vpg31, ctx, inst, - &vpg_regs[inst], - &vpg_shift, - &vpg_mask); - - return &vpg31->base; -} - -static struct afmt *dcn31_afmt_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn31_afmt *afmt31 = kzalloc(sizeof(struct dcn31_afmt), GFP_KERNEL); - - if (!afmt31) - return NULL; - - afmt31_construct(afmt31, ctx, inst, - &afmt_regs[inst], - &afmt_shift, - &afmt_mask); - - // Light sleep by default, no need to power down here - - return &afmt31->base; -} - -static struct apg *dcn31_apg_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn31_apg *apg31 = kzalloc(sizeof(struct dcn31_apg), GFP_KERNEL); - - if (!apg31) - return NULL; - - apg31_construct(apg31, ctx, inst, - &apg_regs[inst], - &apg_shift, - &apg_mask); - - return &apg31->base; -} - -static struct stream_encoder *dcn31_stream_encoder_create( - enum engine_id eng_id, - struct dc_context *ctx) -{ - struct dcn10_stream_encoder *enc1; - struct vpg *vpg; - struct afmt *afmt; - int vpg_inst; - int afmt_inst; - - /* Mapping of VPG, AFMT, DME register blocks to DIO block instance */ - if (eng_id <= ENGINE_ID_DIGF) { - vpg_inst = eng_id; - afmt_inst = eng_id; - } else - return NULL; - - enc1 = kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL); - vpg = dcn31_vpg_create(ctx, vpg_inst); - afmt = dcn31_afmt_create(ctx, afmt_inst); - - if (!enc1 || !vpg || !afmt) { - kfree(enc1); - kfree(vpg); - kfree(afmt); - return NULL; - } - - dcn30_dio_stream_encoder_construct(enc1, ctx, ctx->dc_bios, - eng_id, vpg, afmt, - &stream_enc_regs[eng_id], - &se_shift, &se_mask); - - return &enc1->base; -} - -static struct hpo_dp_stream_encoder *dcn31_hpo_dp_stream_encoder_create( - enum engine_id eng_id, - struct dc_context *ctx) -{ - struct dcn31_hpo_dp_stream_encoder *hpo_dp_enc31; - struct vpg *vpg; - struct apg *apg; - uint32_t hpo_dp_inst; - uint32_t vpg_inst; - uint32_t apg_inst; - - ASSERT((eng_id >= ENGINE_ID_HPO_DP_0) && (eng_id <= ENGINE_ID_HPO_DP_3)); - hpo_dp_inst = eng_id - ENGINE_ID_HPO_DP_0; - - /* Mapping of VPG register blocks to HPO DP block instance: - * VPG[6] -> HPO_DP[0] - * VPG[7] -> HPO_DP[1] - * VPG[8] -> HPO_DP[2] - * VPG[9] -> HPO_DP[3] - */ - vpg_inst = hpo_dp_inst + 6; - - /* Mapping of APG register blocks to HPO DP block instance: - * APG[0] -> HPO_DP[0] - * APG[1] -> HPO_DP[1] - * APG[2] -> HPO_DP[2] - * APG[3] -> HPO_DP[3] - */ - apg_inst = hpo_dp_inst; - - /* allocate HPO stream encoder and create VPG sub-block */ - hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_stream_encoder), GFP_KERNEL); - vpg = dcn31_vpg_create(ctx, vpg_inst); - apg = dcn31_apg_create(ctx, apg_inst); - - if (!hpo_dp_enc31 || !vpg || !apg) { - kfree(hpo_dp_enc31); - kfree(vpg); - kfree(apg); - return NULL; - } - - dcn31_hpo_dp_stream_encoder_construct(hpo_dp_enc31, ctx, ctx->dc_bios, - hpo_dp_inst, eng_id, vpg, apg, - &hpo_dp_stream_enc_regs[hpo_dp_inst], - &hpo_dp_se_shift, &hpo_dp_se_mask); - - return &hpo_dp_enc31->base; -} - -static struct hpo_dp_link_encoder *dcn31_hpo_dp_link_encoder_create( - uint8_t inst, - struct dc_context *ctx) -{ - struct dcn31_hpo_dp_link_encoder *hpo_dp_enc31; - - /* allocate HPO link encoder */ - hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_link_encoder), GFP_KERNEL); - - hpo_dp_link_encoder31_construct(hpo_dp_enc31, ctx, inst, - &hpo_dp_link_enc_regs[inst], - &hpo_dp_le_shift, &hpo_dp_le_mask); - - return &hpo_dp_enc31->base; -} - -static struct dce_hwseq *dcn31_hwseq_create( - struct dc_context *ctx) -{ - struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); - - if (hws) { - hws->ctx = ctx; - hws->regs = &hwseq_reg; - hws->shifts = &hwseq_shift; - hws->masks = &hwseq_mask; - } - return hws; -} -static const struct resource_create_funcs res_create_funcs = { - .read_dce_straps = read_dce_straps, - .create_audio = dcn31_create_audio, - .create_stream_encoder = dcn31_stream_encoder_create, - .create_hpo_dp_stream_encoder = dcn31_hpo_dp_stream_encoder_create, - .create_hpo_dp_link_encoder = dcn31_hpo_dp_link_encoder_create, - .create_hwseq = dcn31_hwseq_create, -}; - -static void dcn31_resource_destruct(struct dcn31_resource_pool *pool) -{ - unsigned int i; - - for (i = 0; i < pool->base.stream_enc_count; i++) { - if (pool->base.stream_enc[i] != NULL) { - if (pool->base.stream_enc[i]->vpg != NULL) { - kfree(DCN30_VPG_FROM_VPG(pool->base.stream_enc[i]->vpg)); - pool->base.stream_enc[i]->vpg = NULL; - } - if (pool->base.stream_enc[i]->afmt != NULL) { - kfree(DCN30_AFMT_FROM_AFMT(pool->base.stream_enc[i]->afmt)); - pool->base.stream_enc[i]->afmt = NULL; - } - kfree(DCN10STRENC_FROM_STRENC(pool->base.stream_enc[i])); - pool->base.stream_enc[i] = NULL; - } - } - - for (i = 0; i < pool->base.hpo_dp_stream_enc_count; i++) { - if (pool->base.hpo_dp_stream_enc[i] != NULL) { - if (pool->base.hpo_dp_stream_enc[i]->vpg != NULL) { - kfree(DCN30_VPG_FROM_VPG(pool->base.hpo_dp_stream_enc[i]->vpg)); - pool->base.hpo_dp_stream_enc[i]->vpg = NULL; - } - if (pool->base.hpo_dp_stream_enc[i]->apg != NULL) { - kfree(DCN31_APG_FROM_APG(pool->base.hpo_dp_stream_enc[i]->apg)); - pool->base.hpo_dp_stream_enc[i]->apg = NULL; - } - kfree(DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(pool->base.hpo_dp_stream_enc[i])); - pool->base.hpo_dp_stream_enc[i] = NULL; - } - } - - for (i = 0; i < pool->base.hpo_dp_link_enc_count; i++) { - if (pool->base.hpo_dp_link_enc[i] != NULL) { - kfree(DCN3_1_HPO_DP_LINK_ENC_FROM_HPO_LINK_ENC(pool->base.hpo_dp_link_enc[i])); - pool->base.hpo_dp_link_enc[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_dsc; i++) { - if (pool->base.dscs[i] != NULL) - dcn20_dsc_destroy(&pool->base.dscs[i]); - } - - if (pool->base.mpc != NULL) { - kfree(TO_DCN20_MPC(pool->base.mpc)); - pool->base.mpc = NULL; - } - if (pool->base.hubbub != NULL) { - kfree(pool->base.hubbub); - pool->base.hubbub = NULL; - } - for (i = 0; i < pool->base.pipe_count; i++) { - if (pool->base.dpps[i] != NULL) - dcn31_dpp_destroy(&pool->base.dpps[i]); - - if (pool->base.ipps[i] != NULL) - pool->base.ipps[i]->funcs->ipp_destroy(&pool->base.ipps[i]); - - if (pool->base.hubps[i] != NULL) { - kfree(TO_DCN20_HUBP(pool->base.hubps[i])); - pool->base.hubps[i] = NULL; - } - - if (pool->base.irqs != NULL) { - dal_irq_service_destroy(&pool->base.irqs); - } - } - - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - if (pool->base.engines[i] != NULL) - dce110_engine_destroy(&pool->base.engines[i]); - if (pool->base.hw_i2cs[i] != NULL) { - kfree(pool->base.hw_i2cs[i]); - pool->base.hw_i2cs[i] = NULL; - } - if (pool->base.sw_i2cs[i] != NULL) { - kfree(pool->base.sw_i2cs[i]); - pool->base.sw_i2cs[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_opp; i++) { - if (pool->base.opps[i] != NULL) - pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]); - } - - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - if (pool->base.timing_generators[i] != NULL) { - kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i])); - pool->base.timing_generators[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_dwb; i++) { - if (pool->base.dwbc[i] != NULL) { - kfree(TO_DCN30_DWBC(pool->base.dwbc[i])); - pool->base.dwbc[i] = NULL; - } - if (pool->base.mcif_wb[i] != NULL) { - kfree(TO_DCN30_MMHUBBUB(pool->base.mcif_wb[i])); - pool->base.mcif_wb[i] = NULL; - } - } - - for (i = 0; i < pool->base.audio_count; i++) { - if (pool->base.audios[i]) - dce_aud_destroy(&pool->base.audios[i]); - } - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] != NULL) { - dcn20_clock_source_destroy(&pool->base.clock_sources[i]); - pool->base.clock_sources[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_mpc_3dlut; i++) { - if (pool->base.mpc_lut[i] != NULL) { - dc_3dlut_func_release(pool->base.mpc_lut[i]); - pool->base.mpc_lut[i] = NULL; - } - if (pool->base.mpc_shaper[i] != NULL) { - dc_transfer_func_release(pool->base.mpc_shaper[i]); - pool->base.mpc_shaper[i] = NULL; - } - } - - if (pool->base.dp_clock_source != NULL) { - dcn20_clock_source_destroy(&pool->base.dp_clock_source); - pool->base.dp_clock_source = NULL; - } - - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - if (pool->base.multiple_abms[i] != NULL) - dce_abm_destroy(&pool->base.multiple_abms[i]); - } - - if (pool->base.psr != NULL) - dmub_psr_destroy(&pool->base.psr); - - if (pool->base.replay != NULL) - dmub_replay_destroy(&pool->base.replay); - - if (pool->base.dccg != NULL) - dcn_dccg_destroy(&pool->base.dccg); -} - -static struct hubp *dcn31_hubp_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn20_hubp *hubp2 = - kzalloc(sizeof(struct dcn20_hubp), GFP_KERNEL); - - if (!hubp2) - return NULL; - - if (hubp31_construct(hubp2, ctx, inst, - &hubp_regs[inst], &hubp_shift, &hubp_mask)) - return &hubp2->base; - - BREAK_TO_DEBUGGER(); - kfree(hubp2); - return NULL; -} - -static bool dcn31_dwbc_create(struct dc_context *ctx, struct resource_pool *pool) -{ - int i; - uint32_t pipe_count = pool->res_cap->num_dwb; - - for (i = 0; i < pipe_count; i++) { - struct dcn30_dwbc *dwbc30 = kzalloc(sizeof(struct dcn30_dwbc), - GFP_KERNEL); - - if (!dwbc30) { - dm_error("DC: failed to create dwbc30!\n"); - return false; - } - - dcn30_dwbc_construct(dwbc30, ctx, - &dwbc30_regs[i], - &dwbc30_shift, - &dwbc30_mask, - i); - - pool->dwbc[i] = &dwbc30->base; - } - return true; -} - -static bool dcn31_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool) -{ - int i; - uint32_t pipe_count = pool->res_cap->num_dwb; - - for (i = 0; i < pipe_count; i++) { - struct dcn30_mmhubbub *mcif_wb30 = kzalloc(sizeof(struct dcn30_mmhubbub), - GFP_KERNEL); - - if (!mcif_wb30) { - dm_error("DC: failed to create mcif_wb30!\n"); - return false; - } - - dcn30_mmhubbub_construct(mcif_wb30, ctx, - &mcif_wb30_regs[i], - &mcif_wb30_shift, - &mcif_wb30_mask, - i); - - pool->mcif_wb[i] = &mcif_wb30->base; - } - return true; -} - -static struct display_stream_compressor *dcn31_dsc_create( - struct dc_context *ctx, uint32_t inst) -{ - struct dcn20_dsc *dsc = - kzalloc(sizeof(struct dcn20_dsc), GFP_KERNEL); - - if (!dsc) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dsc2_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask); - return &dsc->base; -} - -static void dcn31_destroy_resource_pool(struct resource_pool **pool) -{ - struct dcn31_resource_pool *dcn31_pool = TO_DCN31_RES_POOL(*pool); - - dcn31_resource_destruct(dcn31_pool); - kfree(dcn31_pool); - *pool = NULL; -} - -static struct clock_source *dcn31_clock_source_create( - struct dc_context *ctx, - struct dc_bios *bios, - enum clock_source_id id, - const struct dce110_clk_src_regs *regs, - bool dp_clk_src) -{ - struct dce110_clk_src *clk_src = - kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); - - if (!clk_src) - return NULL; - - if (dcn3_clk_src_construct(clk_src, ctx, bios, id, - regs, &cs_shift, &cs_mask)) { - clk_src->base.dp_clk_src = dp_clk_src; - return &clk_src->base; - } - - kfree(clk_src); - BREAK_TO_DEBUGGER(); - return NULL; -} - -static bool is_dual_plane(enum surface_pixel_format format) -{ - return format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN || format == SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA; -} - -int dcn31x_populate_dml_pipes_from_context(struct dc *dc, - struct dc_state *context, - display_e2e_pipe_params_st *pipes, - bool fast_validate) -{ - uint32_t pipe_cnt; - int i; - - dc_assert_fp_enabled(); - - pipe_cnt = dcn20_populate_dml_pipes_from_context(dc, context, pipes, fast_validate); - - for (i = 0; i < pipe_cnt; i++) { - pipes[i].pipe.src.gpuvm = 1; - if (dc->debug.dml_hostvm_override == DML_HOSTVM_NO_OVERRIDE) { - //pipes[pipe_cnt].pipe.src.hostvm = dc->res_pool->hubbub->riommu_active; - pipes[i].pipe.src.hostvm = dc->vm_pa_config.is_hvm_enabled; - } else if (dc->debug.dml_hostvm_override == DML_HOSTVM_OVERRIDE_FALSE) - pipes[i].pipe.src.hostvm = false; - else if (dc->debug.dml_hostvm_override == DML_HOSTVM_OVERRIDE_TRUE) - pipes[i].pipe.src.hostvm = true; - } - return pipe_cnt; -} - -int dcn31_populate_dml_pipes_from_context( - struct dc *dc, struct dc_state *context, - display_e2e_pipe_params_st *pipes, - bool fast_validate) -{ - int i, pipe_cnt; - struct resource_context *res_ctx = &context->res_ctx; - struct pipe_ctx *pipe; - bool upscaled = false; - - DC_FP_START(); - dcn31x_populate_dml_pipes_from_context(dc, context, pipes, fast_validate); - DC_FP_END(); - - for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) { - struct dc_crtc_timing *timing; - - if (!res_ctx->pipe_ctx[i].stream) - continue; - pipe = &res_ctx->pipe_ctx[i]; - timing = &pipe->stream->timing; - if (pipe->plane_state && - (pipe->plane_state->src_rect.height < pipe->plane_state->dst_rect.height || - pipe->plane_state->src_rect.width < pipe->plane_state->dst_rect.width)) - upscaled = true; - - /* - * Immediate flip can be set dynamically after enabling the plane. - * We need to require support for immediate flip or underflow can be - * intermittently experienced depending on peak b/w requirements. - */ - pipes[pipe_cnt].pipe.src.immediate_flip = true; - pipes[pipe_cnt].pipe.src.unbounded_req_mode = false; - pipes[pipe_cnt].pipe.src.gpuvm = true; - pipes[pipe_cnt].pipe.dest.vfront_porch = timing->v_front_porch; - pipes[pipe_cnt].pipe.src.dcc_rate = 3; - pipes[pipe_cnt].dout.dsc_input_bpc = 0; - DC_FP_START(); - dcn31_zero_pipe_dcc_fraction(pipes, pipe_cnt); - DC_FP_END(); - - - if (pipes[pipe_cnt].dout.dsc_enable) { - switch (timing->display_color_depth) { - case COLOR_DEPTH_888: - pipes[pipe_cnt].dout.dsc_input_bpc = 8; - break; - case COLOR_DEPTH_101010: - pipes[pipe_cnt].dout.dsc_input_bpc = 10; - break; - case COLOR_DEPTH_121212: - pipes[pipe_cnt].dout.dsc_input_bpc = 12; - break; - default: - ASSERT(0); - break; - } - } - - pipe_cnt++; - } - context->bw_ctx.dml.ip.det_buffer_size_kbytes = DCN3_1_DEFAULT_DET_SIZE; - dc->config.enable_4to1MPC = false; - if (pipe_cnt == 1 && pipe->plane_state && !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; - } else if (!is_dual_plane(pipe->plane_state->format) && pipe->plane_state->src_rect.width <= 5120) { - /* Limit to 5k max to avoid forced pipe split when there is not enough detile for swath */ - context->bw_ctx.dml.ip.det_buffer_size_kbytes = 192; - pipes[0].pipe.src.unbounded_req_mode = true; - } - } else if (context->stream_count >= dc->debug.crb_alloc_policy_min_disp_count - && dc->debug.crb_alloc_policy > DET_SIZE_DEFAULT) { - context->bw_ctx.dml.ip.det_buffer_size_kbytes = dc->debug.crb_alloc_policy * 64; - } else if (context->stream_count >= 3 && upscaled) { - context->bw_ctx.dml.ip.det_buffer_size_kbytes = 192; - } - - return pipe_cnt; -} - -void dcn31_calculate_wm_and_dlg( - struct dc *dc, struct dc_state *context, - display_e2e_pipe_params_st *pipes, - int pipe_cnt, - int vlevel) -{ - DC_FP_START(); - dcn31_calculate_wm_and_dlg_fp(dc, context, pipes, pipe_cnt, vlevel); - DC_FP_END(); -} - -void -dcn31_populate_dml_writeback_from_context(struct dc *dc, - struct resource_context *res_ctx, - display_e2e_pipe_params_st *pipes) -{ - DC_FP_START(); - dcn30_populate_dml_writeback_from_context(dc, res_ctx, pipes); - DC_FP_END(); -} - -void -dcn31_set_mcif_arb_params(struct dc *dc, - struct dc_state *context, - display_e2e_pipe_params_st *pipes, - int pipe_cnt) -{ - DC_FP_START(); - dcn30_set_mcif_arb_params(dc, context, pipes, pipe_cnt); - DC_FP_END(); -} - -bool dcn31_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(); - 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 - 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; - } - if (dc->res_pool->funcs->calculate_wm_and_dlg) - 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 void dcn31_get_panel_config_defaults(struct dc_panel_config *panel_config) -{ - *panel_config = panel_config_defaults; -} - -static struct dc_cap_funcs cap_funcs = { - .get_dcc_compression_cap = dcn20_get_dcc_compression_cap -}; - -static struct resource_funcs dcn31_res_pool_funcs = { - .destroy = dcn31_destroy_resource_pool, - .link_enc_create = dcn31_link_encoder_create, - .link_enc_create_minimal = dcn31_link_enc_create_minimal, - .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, - .calculate_wm_and_dlg = dcn31_calculate_wm_and_dlg, - .update_soc_for_wm_a = dcn31_update_soc_for_wm_a, - .populate_dml_pipes = dcn31_populate_dml_pipes_from_context, - .acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer, - .release_pipe = dcn20_release_pipe, - .add_stream_to_ctx = dcn30_add_stream_to_ctx, - .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource, - .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, - .populate_dml_writeback_from_context = dcn31_populate_dml_writeback_from_context, - .set_mcif_arb_params = dcn31_set_mcif_arb_params, - .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 = dcn31_update_bw_bounding_box, - .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, - .get_panel_config_defaults = dcn31_get_panel_config_defaults, -}; - -static struct clock_source *dcn30_clock_source_create( - struct dc_context *ctx, - struct dc_bios *bios, - enum clock_source_id id, - const struct dce110_clk_src_regs *regs, - bool dp_clk_src) -{ - struct dce110_clk_src *clk_src = - kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); - - if (!clk_src) - return NULL; - - if (dcn31_clk_src_construct(clk_src, ctx, bios, id, - regs, &cs_shift, &cs_mask)) { - clk_src->base.dp_clk_src = dp_clk_src; - return &clk_src->base; - } - - BREAK_TO_DEBUGGER(); - return NULL; -} - -static bool dcn31_resource_construct( - uint8_t num_virtual_links, - struct dc *dc, - struct dcn31_resource_pool *pool) -{ - int i; - struct dc_context *ctx = dc->ctx; - struct irq_service_init_data init_data; - - ctx->dc_bios->regs = &bios_regs; - - pool->base.res_cap = &res_cap_dcn31; - - pool->base.funcs = &dcn31_res_pool_funcs; - - /************************************************* - * Resource + asic cap harcoding * - *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; - pool->base.pipe_count = pool->base.res_cap->num_timing_generator; - 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 = 5; /*1.4 w/a applied by default*/ - dc->caps.max_cursor_size = 256; - dc->caps.min_horizontal_blanking_period = 80; - dc->caps.dmdata_alloc_size = 2048; - - dc->caps.max_slave_planes = 2; - dc->caps.max_slave_yuv_planes = 2; - dc->caps.max_slave_rgb_planes = 2; - dc->caps.post_blend_color_processing = true; - dc->caps.force_dp_tps4_for_cp2520 = true; - if (dc->config.forceHBR2CP2520) - dc->caps.force_dp_tps4_for_cp2520 = false; - dc->caps.dp_hpo = true; - dc->caps.dp_hdmi21_pcon_support = true; - dc->caps.edp_dsc_support = true; - dc->caps.extended_aux_timeout_support = true; - dc->caps.dmcub_support = true; - dc->caps.is_apu = true; - dc->caps.zstate_support = true; - - /* Color pipeline capabilities */ - dc->caps.color.dpp.dcn_arch = 1; - dc->caps.color.dpp.input_lut_shared = 0; - dc->caps.color.dpp.icsc = 1; - dc->caps.color.dpp.dgam_ram = 0; // must use gamma_corr - dc->caps.color.dpp.dgam_rom_caps.srgb = 1; - dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1; - dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 1; - dc->caps.color.dpp.dgam_rom_caps.pq = 1; - dc->caps.color.dpp.dgam_rom_caps.hlg = 1; - dc->caps.color.dpp.post_csc = 1; - dc->caps.color.dpp.gamma_corr = 1; - dc->caps.color.dpp.dgam_rom_for_yuv = 0; - - dc->caps.color.dpp.hw_3d_lut = 1; - dc->caps.color.dpp.ogam_ram = 1; - // no OGAM ROM on DCN301 - dc->caps.color.dpp.ogam_rom_caps.srgb = 0; - dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0; - dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0; - dc->caps.color.dpp.ogam_rom_caps.pq = 0; - dc->caps.color.dpp.ogam_rom_caps.hlg = 0; - dc->caps.color.dpp.ocsc = 0; - - dc->caps.color.mpc.gamut_remap = 1; - dc->caps.color.mpc.num_3dluts = pool->base.res_cap->num_mpc_3dlut; //2 - dc->caps.color.mpc.ogam_ram = 1; - dc->caps.color.mpc.ogam_rom_caps.srgb = 0; - dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0; - dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0; - dc->caps.color.mpc.ogam_rom_caps.pq = 0; - dc->caps.color.mpc.ogam_rom_caps.hlg = 0; - dc->caps.color.mpc.ocsc = 1; - - dc->config.use_old_fixed_vs_sequence = true; - - /* Use pipe context based otg sync logic */ - dc->config.use_pipe_ctx_sync_logic = true; - - /* read VBIOS LTTPR caps */ - { - if (ctx->dc_bios->funcs->get_lttpr_caps) { - enum bp_result bp_query_result; - uint8_t is_vbios_lttpr_enable = 0; - - bp_query_result = ctx->dc_bios->funcs->get_lttpr_caps(ctx->dc_bios, &is_vbios_lttpr_enable); - dc->caps.vbios_lttpr_enable = (bp_query_result == BP_RESULT_OK) && !!is_vbios_lttpr_enable; - } - - /* interop bit is implicit */ - { - dc->caps.vbios_lttpr_aware = true; - } - } - - if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) - dc->debug = debug_defaults_drv; - - // Init the vm_helper - if (dc->vm_helper) - vm_helper_init(dc->vm_helper, 16); - - /************************************************* - * Create resources * - *************************************************/ - - /* Clock Sources for Pixel Clock*/ - pool->base.clock_sources[DCN31_CLK_SRC_PLL0] = - dcn30_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL0, - &clk_src_regs[0], false); - pool->base.clock_sources[DCN31_CLK_SRC_PLL1] = - dcn30_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL1, - &clk_src_regs[1], false); - /*move phypllx_pixclk_resync to dmub next*/ - if (dc->ctx->asic_id.hw_internal_rev == YELLOW_CARP_B0) { - pool->base.clock_sources[DCN31_CLK_SRC_PLL2] = - dcn30_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL2, - &clk_src_regs_b0[2], false); - pool->base.clock_sources[DCN31_CLK_SRC_PLL3] = - dcn30_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL3, - &clk_src_regs_b0[3], false); - } else { - pool->base.clock_sources[DCN31_CLK_SRC_PLL2] = - dcn30_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL2, - &clk_src_regs[2], false); - pool->base.clock_sources[DCN31_CLK_SRC_PLL3] = - dcn30_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL3, - &clk_src_regs[3], false); - } - - pool->base.clock_sources[DCN31_CLK_SRC_PLL4] = - dcn30_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL4, - &clk_src_regs[4], false); - - pool->base.clk_src_count = DCN30_CLK_SRC_TOTAL; - - /* todo: not reuse phy_pll registers */ - pool->base.dp_clock_source = - dcn31_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_ID_DP_DTO, - &clk_src_regs[0], true); - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] == NULL) { - dm_error("DC: failed to create clock sources!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - } - - /* TODO: DCCG */ - pool->base.dccg = dccg31_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask); - if (pool->base.dccg == NULL) { - dm_error("DC: failed to create dccg!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - - /* TODO: IRQ */ - init_data.ctx = dc->ctx; - pool->base.irqs = dal_irq_service_dcn31_create(&init_data); - if (!pool->base.irqs) - goto create_fail; - - /* HUBBUB */ - pool->base.hubbub = dcn31_hubbub_create(ctx); - if (pool->base.hubbub == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create hubbub!\n"); - goto create_fail; - } - - /* HUBPs, DPPs, OPPs and TGs */ - for (i = 0; i < pool->base.pipe_count; i++) { - pool->base.hubps[i] = dcn31_hubp_create(ctx, i); - if (pool->base.hubps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create hubps!\n"); - goto create_fail; - } - - pool->base.dpps[i] = dcn31_dpp_create(ctx, i); - if (pool->base.dpps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create dpps!\n"); - goto create_fail; - } - } - - for (i = 0; i < pool->base.res_cap->num_opp; i++) { - pool->base.opps[i] = dcn31_opp_create(ctx, i); - if (pool->base.opps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create output pixel processor!\n"); - goto create_fail; - } - } - - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - pool->base.timing_generators[i] = dcn31_timing_generator_create( - ctx, i); - if (pool->base.timing_generators[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create tg!\n"); - goto create_fail; - } - } - pool->base.timing_generator_count = i; - - /* PSR */ - pool->base.psr = dmub_psr_create(ctx); - if (pool->base.psr == NULL) { - dm_error("DC: failed to create psr obj!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - - /* Replay */ - pool->base.replay = dmub_replay_create(ctx); - if (pool->base.replay == NULL) { - dm_error("DC: failed to create replay obj!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - - /* ABM */ - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - pool->base.multiple_abms[i] = dmub_abm_create(ctx, - &abm_regs[i], - &abm_shift, - &abm_mask); - if (pool->base.multiple_abms[i] == NULL) { - dm_error("DC: failed to create abm for pipe %d!\n", i); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - } - - /* MPC and DSC */ - pool->base.mpc = dcn31_mpc_create(ctx, pool->base.mpcc_count, pool->base.res_cap->num_mpc_3dlut); - if (pool->base.mpc == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create mpc!\n"); - goto create_fail; - } - - for (i = 0; i < pool->base.res_cap->num_dsc; i++) { - pool->base.dscs[i] = dcn31_dsc_create(ctx, i); - if (pool->base.dscs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create display stream compressor %d!\n", i); - goto create_fail; - } - } - - /* DWB and MMHUBBUB */ - if (!dcn31_dwbc_create(ctx, &pool->base)) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create dwbc!\n"); - goto create_fail; - } - - if (!dcn31_mmhubbub_create(ctx, &pool->base)) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create mcif_wb!\n"); - goto create_fail; - } - - /* AUX and I2C */ - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - pool->base.engines[i] = dcn31_aux_engine_create(ctx, i); - if (pool->base.engines[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create aux engine!!\n"); - goto create_fail; - } - pool->base.hw_i2cs[i] = dcn31_i2c_hw_create(ctx, i); - if (pool->base.hw_i2cs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create hw i2c!!\n"); - goto create_fail; - } - pool->base.sw_i2cs[i] = NULL; - } - - if (dc->ctx->asic_id.chip_family == FAMILY_YELLOW_CARP && - dc->ctx->asic_id.hw_internal_rev == YELLOW_CARP_B0 && - !dc->debug.dpia_debug.bits.disable_dpia) { - /* YELLOW CARP B0 has 4 DPIA's */ - pool->base.usb4_dpia_count = 4; - } - - if (dc->ctx->asic_id.chip_family == AMDGPU_FAMILY_GC_11_0_1) - pool->base.usb4_dpia_count = 4; - - /* Audio, Stream Encoders including HPO and virtual, MPC 3D LUTs */ - if (!resource_construct(num_virtual_links, dc, &pool->base, - &res_create_funcs)) - goto create_fail; - - /* HW Sequencer and Plane caps */ - dcn31_hw_sequencer_construct(dc); - - dc->caps.max_planes = pool->base.pipe_count; - - for (i = 0; i < dc->caps.max_planes; ++i) - dc->caps.planes[i] = plane_cap; - - dc->cap_funcs = cap_funcs; - - dc->dcn_ip->max_num_dpp = dcn3_1_ip.max_num_dpp; - - return true; - -create_fail: - dcn31_resource_destruct(pool); - - return false; -} - -struct resource_pool *dcn31_create_resource_pool( - const struct dc_init_data *init_data, - struct dc *dc) -{ - struct dcn31_resource_pool *pool = - kzalloc(sizeof(struct dcn31_resource_pool), GFP_KERNEL); - - if (!pool) - return NULL; - - if (dcn31_resource_construct(init_data->num_virtual_links, dc, pool)) - return &pool->base; - - BREAK_TO_DEBUGGER(); - kfree(pool); - return NULL; -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.h deleted file mode 100644 index 901436591ed45c..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2020 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 _DCN31_RESOURCE_H_ -#define _DCN31_RESOURCE_H_ - -#include "core_types.h" - -#define TO_DCN31_RES_POOL(pool)\ - container_of(pool, struct dcn31_resource_pool, base) - -extern struct _vcs_dpi_ip_params_st dcn3_1_ip; - -struct dcn31_resource_pool { - struct resource_pool base; -}; - -bool dcn31_validate_bandwidth(struct dc *dc, - struct dc_state *context, - bool fast_validate); -void dcn31_calculate_wm_and_dlg( - struct dc *dc, struct dc_state *context, - display_e2e_pipe_params_st *pipes, - int pipe_cnt, - int vlevel); -int dcn31_populate_dml_pipes_from_context( - struct dc *dc, struct dc_state *context, - display_e2e_pipe_params_st *pipes, - bool fast_validate); -void -dcn31_populate_dml_writeback_from_context(struct dc *dc, - struct resource_context *res_ctx, - display_e2e_pipe_params_st *pipes); -void -dcn31_set_mcif_arb_params(struct dc *dc, - struct dc_state *context, - display_e2e_pipe_params_st *pipes, - int pipe_cnt); - -struct resource_pool *dcn31_create_resource_pool( - const struct dc_init_data *init_data, - struct dc *dc); - -/*temp: B0 specific before switch to dcn313 headers*/ -#ifndef regPHYPLLF_PIXCLK_RESYNC_CNTL -#define regPHYPLLF_PIXCLK_RESYNC_CNTL 0x007e -#define regPHYPLLF_PIXCLK_RESYNC_CNTL_BASE_IDX 1 -#define regPHYPLLG_PIXCLK_RESYNC_CNTL 0x005f -#define regPHYPLLG_PIXCLK_RESYNC_CNTL_BASE_IDX 1 - -//PHYPLLF_PIXCLK_RESYNC_CNTL -#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_PIXCLK_RESYNC_ENABLE__SHIFT 0x0 -#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_DEEP_COLOR_DTO_ENABLE_STATUS__SHIFT 0x1 -#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_DCCG_DEEP_COLOR_CNTL__SHIFT 0x4 -#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_PIXCLK_ENABLE__SHIFT 0x8 -#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_PIXCLK_DOUBLE_RATE_ENABLE__SHIFT 0x9 -#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_PIXCLK_RESYNC_ENABLE_MASK 0x00000001L -#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_DEEP_COLOR_DTO_ENABLE_STATUS_MASK 0x00000002L -#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_DCCG_DEEP_COLOR_CNTL_MASK 0x00000030L -#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_PIXCLK_ENABLE_MASK 0x00000100L -#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_PIXCLK_DOUBLE_RATE_ENABLE_MASK 0x00000200L - -//PHYPLLG_PIXCLK_RESYNC_CNTL -#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_PIXCLK_RESYNC_ENABLE__SHIFT 0x0 -#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_DEEP_COLOR_DTO_ENABLE_STATUS__SHIFT 0x1 -#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_DCCG_DEEP_COLOR_CNTL__SHIFT 0x4 -#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_PIXCLK_ENABLE__SHIFT 0x8 -#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_PIXCLK_DOUBLE_RATE_ENABLE__SHIFT 0x9 -#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_PIXCLK_RESYNC_ENABLE_MASK 0x00000001L -#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_DEEP_COLOR_DTO_ENABLE_STATUS_MASK 0x00000002L -#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_DCCG_DEEP_COLOR_CNTL_MASK 0x00000030L -#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_PIXCLK_ENABLE_MASK 0x00000100L -#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_PIXCLK_DOUBLE_RATE_ENABLE_MASK 0x00000200L -#endif -#endif /* _DCN31_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/Makefile b/drivers/gpu/drm/amd/display/dc/dcn314/Makefile index 72456debb99f97..b134ab05aa7126 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn314/Makefile @@ -10,8 +10,7 @@ # # Makefile for dcn314. -DCN314 = dcn314_resource.o dcn314_init.o \ - dcn314_dio_stream_encoder.o dcn314_dccg.o dcn314_optc.o +DCN314 = dcn314_dio_stream_encoder.o dcn314_dccg.o AMD_DAL_DCN314 = $(addprefix $(AMDDALPATH)/dc/dcn314/,$(DCN314)) diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c deleted file mode 100644 index ccb7e317e86af1..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c +++ /dev/null @@ -1,163 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - * 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 "dce110/dce110_hwseq.h" -#include "dcn10/dcn10_hwseq.h" -#include "dcn20/dcn20_hwseq.h" -#include "dcn21/dcn21_hwseq.h" -#include "dcn30/dcn30_hwseq.h" -#include "dcn301/dcn301_hwseq.h" -#include "dcn31/dcn31_hwseq.h" -#include "dcn314/dcn314_hwseq.h" - -#include "dcn314_init.h" - -static const struct hw_sequencer_funcs dcn314_funcs = { - .program_gamut_remap = dcn30_program_gamut_remap, - .init_hw = dcn31_init_hw, - .power_down_on_boot = dcn10_power_down_on_boot, - .apply_ctx_to_hw = dce110_apply_ctx_to_hw, - .apply_ctx_for_surface = NULL, - .program_front_end_for_ctx = dcn20_program_front_end_for_ctx, - .wait_for_pending_cleared = dcn10_wait_for_pending_cleared, - .post_unlock_program_front_end = dcn20_post_unlock_program_front_end, - .update_plane_addr = dcn20_update_plane_addr, - .update_dchub = dcn10_update_dchub, - .update_pending_status = dcn10_update_pending_status, - .program_output_csc = dcn20_program_output_csc, - .enable_accelerated_mode = dce110_enable_accelerated_mode, - .enable_timing_synchronization = dcn10_enable_timing_synchronization, - .enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset, - .update_info_frame = dcn31_update_info_frame, - .send_immediate_sdp_message = dcn10_send_immediate_sdp_message, - .enable_stream = dcn20_enable_stream, - .disable_stream = dce110_disable_stream, - .unblank_stream = dcn20_unblank_stream, - .blank_stream = dce110_blank_stream, - .enable_audio_stream = dce110_enable_audio_stream, - .disable_audio_stream = dce110_disable_audio_stream, - .disable_plane = dcn20_disable_plane, - .disable_pixel_data = dcn20_disable_pixel_data, - .pipe_control_lock = dcn20_pipe_control_lock, - .interdependent_update_lock = dcn10_lock_all_pipes, - .cursor_lock = dcn10_cursor_lock, - .prepare_bandwidth = dcn20_prepare_bandwidth, - .optimize_bandwidth = dcn20_optimize_bandwidth, - .update_bandwidth = dcn20_update_bandwidth, - .set_drr = dcn10_set_drr, - .get_position = dcn10_get_position, - .set_static_screen_control = dcn30_set_static_screen_control, - .setup_stereo = dcn10_setup_stereo, - .set_avmute = dcn30_set_avmute, - .log_hw_state = dcn10_log_hw_state, - .get_hw_state = dcn10_get_hw_state, - .clear_status_bits = dcn10_clear_status_bits, - .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, - .edp_backlight_control = dce110_edp_backlight_control, - .edp_power_control = dce110_edp_power_control, - .edp_wait_for_T12 = dce110_edp_wait_for_T12, - .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, - .set_cursor_position = dcn10_set_cursor_position, - .set_cursor_attribute = dcn10_set_cursor_attribute, - .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level, - .setup_periodic_interrupt = dcn10_setup_periodic_interrupt, - .set_clock = dcn10_set_clock, - .get_clock = dcn10_get_clock, - .program_triplebuffer = dcn20_program_triple_buffer, - .enable_writeback = dcn30_enable_writeback, - .disable_writeback = dcn30_disable_writeback, - .update_writeback = dcn30_update_writeback, - .mmhubbub_warmup = dcn30_mmhubbub_warmup, - .dmdata_status_done = dcn20_dmdata_status_done, - .program_dmdata_engine = dcn30_program_dmdata_engine, - .set_dmdata_attributes = dcn20_set_dmdata_attributes, - .init_sys_ctx = dcn31_init_sys_ctx, - .init_vm_ctx = dcn20_init_vm_ctx, - .set_flip_control_gsl = dcn20_set_flip_control_gsl, - .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync, - .calc_vupdate_position = dcn10_calc_vupdate_position, - .power_down = dce110_power_down, - .set_backlight_level = dcn21_set_backlight_level, - .set_abm_immediate_disable = dcn21_set_abm_immediate_disable, - .set_pipe = dcn21_set_pipe, - .enable_lvds_link_output = dce110_enable_lvds_link_output, - .enable_tmds_link_output = dce110_enable_tmds_link_output, - .enable_dp_link_output = dce110_enable_dp_link_output, - .disable_link_output = dcn314_disable_link_output, - .z10_restore = dcn31_z10_restore, - .z10_save_init = dcn31_z10_save_init, - .set_disp_pattern_generator = dcn30_set_disp_pattern_generator, - .optimize_pwr_state = dcn21_optimize_pwr_state, - .exit_optimized_pwr_state = dcn21_exit_optimized_pwr_state, - .update_visual_confirm_color = dcn10_update_visual_confirm_color, -}; - -static const struct hwseq_private_funcs dcn314_private_funcs = { - .init_pipes = dcn10_init_pipes, - .update_plane_addr = dcn20_update_plane_addr, - .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, - .update_mpcc = dcn20_update_mpcc, - .set_input_transfer_func = dcn30_set_input_transfer_func, - .set_output_transfer_func = dcn30_set_output_transfer_func, - .power_down = dce110_power_down, - .enable_display_power_gating = dcn10_dummy_display_power_gating, - .blank_pixel_data = dcn20_blank_pixel_data, - .reset_hw_ctx_wrap = dcn31_reset_hw_ctx_wrap, - .enable_stream_timing = dcn20_enable_stream_timing, - .edp_backlight_control = dce110_edp_backlight_control, - .disable_stream_gating = dcn20_disable_stream_gating, - .enable_stream_gating = dcn20_enable_stream_gating, - .setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt, - .did_underflow_occur = dcn10_did_underflow_occur, - .init_blank = dcn20_init_blank, - .disable_vga = dcn20_disable_vga, - .bios_golden_init = dcn10_bios_golden_init, - .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, - .dpp_root_clock_control = dcn314_dpp_root_clock_control, - .hubp_pg_control = dcn31_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, - .set_hdr_multiplier = dcn10_set_hdr_multiplier, - .verify_allow_pstate_change_high = dcn10_verify_allow_pstate_change_high, - .wait_for_blank_complete = dcn20_wait_for_blank_complete, - .dccg_init = dcn20_dccg_init, - .set_blend_lut = dcn30_set_blend_lut, - .set_shaper_3dlut = dcn20_set_shaper_3dlut, - .setup_hpo_hw_control = dcn31_setup_hpo_hw_control, - .calculate_dccg_k1_k2_values = dcn314_calculate_dccg_k1_k2_values, - .set_pixels_per_cycle = dcn314_set_pixels_per_cycle, - .resync_fifo_dccg_dio = dcn314_resync_fifo_dccg_dio, -}; - -void dcn314_hw_sequencer_construct(struct dc *dc) -{ - dc->hwss = dcn314_funcs; - dc->hwseq->funcs = dcn314_private_funcs; - -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.h b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.h deleted file mode 100644 index 8f92e66577cf17..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.h +++ /dev/null @@ -1,34 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * 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_DCN314_INIT_H__ -#define __DC_DCN314_INIT_H__ - -struct dc; - -void dcn314_hw_sequencer_construct(struct dc *dc); - -#endif /* __DC_DCN314_INIT_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_optc.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_optc.c deleted file mode 100644 index 0086cafb0f7a82..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_optc.c +++ /dev/null @@ -1,273 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - * 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 "dcn314_optc.h" - -#include "dcn30/dcn30_optc.h" -#include "dcn31/dcn31_optc.h" -#include "reg_helper.h" -#include "dc.h" -#include "dcn_calc_math.h" - -#define REG(reg)\ - optc1->tg_regs->reg - -#define CTX \ - optc1->base.ctx - -#undef FN -#define FN(reg_name, field_name) \ - optc1->tg_shift->field_name, optc1->tg_mask->field_name - -/* - * Enable CRTC - * Enable CRTC - call ASIC Control Object to enable Timing generator. - */ - -static void optc314_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, - struct dc_crtc_timing *timing) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - uint32_t memory_mask = 0; - int h_active = timing->h_addressable + timing->h_border_left + timing->h_border_right; - int mpcc_hactive = h_active / opp_cnt; - /* Each memory instance is 2048x(314x2) bits to support half line of 4096 */ - int odm_mem_count = (h_active + 2047) / 2048; - - /* - * display <= 4k : 2 memories + 2 pipes - * 4k < display <= 8k : 4 memories + 2 pipes - * 8k < display <= 12k : 6 memories + 4 pipes - */ - if (opp_cnt == 4) { - if (odm_mem_count <= 2) - memory_mask = 0x3; - else if (odm_mem_count <= 4) - memory_mask = 0xf; - else - memory_mask = 0x3f; - } else { - if (odm_mem_count <= 2) - memory_mask = 0x1 << (opp_id[0] * 2) | 0x1 << (opp_id[1] * 2); - else if (odm_mem_count <= 4) - memory_mask = 0x3 << (opp_id[0] * 2) | 0x3 << (opp_id[1] * 2); - else - memory_mask = 0x77; - } - - REG_SET(OPTC_MEMORY_CONFIG, 0, - OPTC_MEM_SEL, memory_mask); - - if (opp_cnt == 2) { - REG_SET_3(OPTC_DATA_SOURCE_SELECT, 0, - OPTC_NUM_OF_INPUT_SEGMENT, 1, - OPTC_SEG0_SRC_SEL, opp_id[0], - OPTC_SEG1_SRC_SEL, opp_id[1]); - } else if (opp_cnt == 4) { - REG_SET_5(OPTC_DATA_SOURCE_SELECT, 0, - OPTC_NUM_OF_INPUT_SEGMENT, 3, - OPTC_SEG0_SRC_SEL, opp_id[0], - OPTC_SEG1_SRC_SEL, opp_id[1], - OPTC_SEG2_SRC_SEL, opp_id[2], - OPTC_SEG3_SRC_SEL, opp_id[3]); - } - - REG_UPDATE(OPTC_WIDTH_CONTROL, - OPTC_SEGMENT_WIDTH, mpcc_hactive); - - REG_UPDATE(OTG_H_TIMING_CNTL, - OTG_H_TIMING_DIV_MODE, opp_cnt - 1); - optc1->opp_count = opp_cnt; -} - -static bool optc314_enable_crtc(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - /* opp instance for OTG, 1 to 1 mapping and odm will adjust */ - REG_UPDATE(OPTC_DATA_SOURCE_SELECT, - OPTC_SEG0_SRC_SEL, optc->inst); - - /* VTG enable first is for HW workaround */ - REG_UPDATE(CONTROL, - VTG0_ENABLE, 1); - - REG_SEQ_START(); - - /* Enable CRTC */ - REG_UPDATE_2(OTG_CONTROL, - OTG_DISABLE_POINT_CNTL, 2, - OTG_MASTER_EN, 1); - - REG_SEQ_SUBMIT(); - REG_SEQ_WAIT_DONE(); - - return true; -} - -/* disable_crtc */ -static bool optc314_disable_crtc(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - /* disable otg request until end of the first line - * in the vertical blank region - */ - REG_UPDATE(OTG_CONTROL, - OTG_MASTER_EN, 0); - - REG_UPDATE(CONTROL, - VTG0_ENABLE, 0); - - /* CRTC disabled, so disable clock. */ - REG_WAIT(OTG_CLOCK_CONTROL, - OTG_BUSY, 0, - 1, 100000); - - return true; -} - -static void optc314_phantom_crtc_post_enable(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - /* Disable immediately. */ - REG_UPDATE_2(OTG_CONTROL, OTG_DISABLE_POINT_CNTL, 0, OTG_MASTER_EN, 0); - - /* CRTC disabled, so disable clock. */ - REG_WAIT(OTG_CLOCK_CONTROL, OTG_BUSY, 0, 1, 100000); -} - -static void optc314_set_odm_bypass(struct timing_generator *optc, - const struct dc_crtc_timing *dc_crtc_timing) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - enum h_timing_div_mode h_div = H_TIMING_NO_DIV; - - REG_SET_5(OPTC_DATA_SOURCE_SELECT, 0, - OPTC_NUM_OF_INPUT_SEGMENT, 0, - OPTC_SEG0_SRC_SEL, optc->inst, - OPTC_SEG1_SRC_SEL, 0xf, - OPTC_SEG2_SRC_SEL, 0xf, - OPTC_SEG3_SRC_SEL, 0xf - ); - - h_div = optc1_is_two_pixels_per_containter(dc_crtc_timing); - REG_UPDATE(OTG_H_TIMING_CNTL, - OTG_H_TIMING_DIV_MODE, h_div); - - REG_SET(OPTC_MEMORY_CONFIG, 0, - OPTC_MEM_SEL, 0); - optc1->opp_count = 1; -} - -static void optc314_set_h_timing_div_manual_mode(struct timing_generator *optc, bool manual_mode) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_UPDATE(OTG_H_TIMING_CNTL, - OTG_H_TIMING_DIV_MODE_MANUAL, manual_mode ? 1 : 0); -} - - -static struct timing_generator_funcs dcn314_tg_funcs = { - .validate_timing = optc1_validate_timing, - .program_timing = optc1_program_timing, - .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0, - .setup_vertical_interrupt1 = optc1_setup_vertical_interrupt1, - .setup_vertical_interrupt2 = optc1_setup_vertical_interrupt2, - .program_global_sync = optc1_program_global_sync, - .enable_crtc = optc314_enable_crtc, - .disable_crtc = optc314_disable_crtc, - .immediate_disable_crtc = optc31_immediate_disable_crtc, - .phantom_crtc_post_enable = optc314_phantom_crtc_post_enable, - /* used by enable_timing_synchronization. Not need for FPGA */ - .is_counter_moving = optc1_is_counter_moving, - .get_position = optc1_get_position, - .get_frame_count = optc1_get_vblank_counter, - .get_scanoutpos = optc1_get_crtc_scanoutpos, - .get_otg_active_size = optc1_get_otg_active_size, - .set_early_control = optc1_set_early_control, - /* used by enable_timing_synchronization. Not need for FPGA */ - .wait_for_state = optc1_wait_for_state, - .set_blank_color = optc3_program_blank_color, - .did_triggered_reset_occur = optc1_did_triggered_reset_occur, - .triplebuffer_lock = optc3_triplebuffer_lock, - .triplebuffer_unlock = optc2_triplebuffer_unlock, - .enable_reset_trigger = optc1_enable_reset_trigger, - .enable_crtc_reset = optc1_enable_crtc_reset, - .disable_reset_trigger = optc1_disable_reset_trigger, - .lock = optc3_lock, - .unlock = optc1_unlock, - .lock_doublebuffer_enable = optc3_lock_doublebuffer_enable, - .lock_doublebuffer_disable = optc3_lock_doublebuffer_disable, - .enable_optc_clock = optc1_enable_optc_clock, - .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 = optc1_set_static_screen_control, - .program_stereo = optc1_program_stereo, - .is_stereo_left_eye = optc1_is_stereo_left_eye, - .tg_init = optc3_tg_init, - .is_tg_enabled = optc1_is_tg_enabled, - .is_optc_underflow_occurred = optc1_is_optc_underflow_occurred, - .clear_optc_underflow = optc1_clear_optc_underflow, - .setup_global_swap_lock = NULL, - .get_crc = optc1_get_crc, - .configure_crc = optc1_configure_crc, - .set_dsc_config = optc3_set_dsc_config, - .get_dsc_status = optc2_get_dsc_status, - .set_dwb_source = NULL, - .get_optc_source = optc2_get_optc_source, - .set_out_mux = optc3_set_out_mux, - .set_drr_trigger_window = optc3_set_drr_trigger_window, - .set_vtotal_change_limit = optc3_set_vtotal_change_limit, - .set_gsl = optc2_set_gsl, - .set_gsl_source_select = optc2_set_gsl_source_select, - .set_vtg_params = optc1_set_vtg_params, - .program_manual_trigger = optc2_program_manual_trigger, - .setup_manual_trigger = optc2_setup_manual_trigger, - .get_hw_timing = optc1_get_hw_timing, - .init_odm = optc3_init_odm, - .set_odm_bypass = optc314_set_odm_bypass, - .set_odm_combine = optc314_set_odm_combine, - .set_h_timing_div_manual_mode = optc314_set_h_timing_div_manual_mode, -}; - -void dcn314_timing_generator_init(struct optc *optc1) -{ - optc1->base.funcs = &dcn314_tg_funcs; - - optc1->max_h_total = optc1->tg_mask->OTG_H_TOTAL + 1; - optc1->max_v_total = optc1->tg_mask->OTG_V_TOTAL + 1; - - optc1->min_h_blank = 32; - optc1->min_v_blank = 3; - optc1->min_v_blank_interlace = 5; - optc1->min_h_sync_width = 4; - optc1->min_v_sync_width = 1; -} - diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_optc.h b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_optc.h deleted file mode 100644 index 99c098e76116fc..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_optc.h +++ /dev/null @@ -1,255 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * 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_OPTC_DCN314_H__ -#define __DC_OPTC_DCN314_H__ - -#include "dcn10/dcn10_optc.h" - -#define OPTC_COMMON_REG_LIST_DCN3_14(inst) \ - SRI(OTG_VSTARTUP_PARAM, OTG, inst),\ - SRI(OTG_VUPDATE_PARAM, OTG, inst),\ - SRI(OTG_VREADY_PARAM, OTG, inst),\ - SRI(OTG_MASTER_UPDATE_LOCK, OTG, inst),\ - SRI(OTG_GLOBAL_CONTROL0, OTG, inst),\ - SRI(OTG_GLOBAL_CONTROL1, OTG, inst),\ - SRI(OTG_GLOBAL_CONTROL2, OTG, inst),\ - SRI(OTG_GLOBAL_CONTROL4, OTG, inst),\ - SRI(OTG_DOUBLE_BUFFER_CONTROL, OTG, inst),\ - SRI(OTG_H_TOTAL, OTG, inst),\ - SRI(OTG_H_BLANK_START_END, OTG, inst),\ - SRI(OTG_H_SYNC_A, OTG, inst),\ - SRI(OTG_H_SYNC_A_CNTL, OTG, inst),\ - SRI(OTG_H_TIMING_CNTL, OTG, inst),\ - SRI(OTG_V_TOTAL, OTG, inst),\ - SRI(OTG_V_BLANK_START_END, OTG, inst),\ - SRI(OTG_V_SYNC_A, OTG, inst),\ - SRI(OTG_V_SYNC_A_CNTL, OTG, inst),\ - SRI(OTG_CONTROL, OTG, inst),\ - SRI(OTG_STEREO_CONTROL, OTG, inst),\ - SRI(OTG_3D_STRUCTURE_CONTROL, OTG, inst),\ - SRI(OTG_STEREO_STATUS, OTG, inst),\ - SRI(OTG_V_TOTAL_MAX, OTG, inst),\ - SRI(OTG_V_TOTAL_MIN, OTG, inst),\ - SRI(OTG_V_TOTAL_CONTROL, OTG, inst),\ - SRI(OTG_TRIGA_CNTL, OTG, inst),\ - SRI(OTG_FORCE_COUNT_NOW_CNTL, OTG, inst),\ - SRI(OTG_STATIC_SCREEN_CONTROL, OTG, inst),\ - SRI(OTG_STATUS_FRAME_COUNT, OTG, inst),\ - SRI(OTG_STATUS, OTG, inst),\ - SRI(OTG_STATUS_POSITION, OTG, inst),\ - SRI(OTG_NOM_VERT_POSITION, OTG, inst),\ - SRI(OTG_M_CONST_DTO0, OTG, inst),\ - SRI(OTG_M_CONST_DTO1, OTG, inst),\ - SRI(OTG_CLOCK_CONTROL, OTG, inst),\ - SRI(OTG_VERTICAL_INTERRUPT0_CONTROL, OTG, inst),\ - SRI(OTG_VERTICAL_INTERRUPT0_POSITION, OTG, inst),\ - SRI(OTG_VERTICAL_INTERRUPT1_CONTROL, OTG, inst),\ - SRI(OTG_VERTICAL_INTERRUPT1_POSITION, OTG, inst),\ - SRI(OTG_VERTICAL_INTERRUPT2_CONTROL, OTG, inst),\ - SRI(OTG_VERTICAL_INTERRUPT2_POSITION, OTG, inst),\ - SRI(OPTC_INPUT_CLOCK_CONTROL, ODM, inst),\ - SRI(OPTC_DATA_SOURCE_SELECT, ODM, inst),\ - SRI(OPTC_INPUT_GLOBAL_CONTROL, ODM, inst),\ - SRI(CONTROL, VTG, inst),\ - SRI(OTG_VERT_SYNC_CONTROL, OTG, inst),\ - SRI(OTG_GSL_CONTROL, OTG, inst),\ - SRI(OTG_CRC_CNTL, OTG, inst),\ - SRI(OTG_CRC0_DATA_RG, OTG, inst),\ - SRI(OTG_CRC0_DATA_B, OTG, inst),\ - SRI(OTG_CRC0_WINDOWA_X_CONTROL, OTG, inst),\ - SRI(OTG_CRC0_WINDOWA_Y_CONTROL, OTG, inst),\ - SRI(OTG_CRC0_WINDOWB_X_CONTROL, OTG, inst),\ - SRI(OTG_CRC0_WINDOWB_Y_CONTROL, OTG, inst),\ - SR(GSL_SOURCE_SELECT),\ - SRI(OTG_TRIGA_MANUAL_TRIG, OTG, inst),\ - SRI(OTG_GLOBAL_CONTROL1, OTG, inst),\ - SRI(OTG_GLOBAL_CONTROL2, OTG, inst),\ - SRI(OTG_GSL_WINDOW_X, OTG, inst),\ - SRI(OTG_GSL_WINDOW_Y, OTG, inst),\ - SRI(OTG_VUPDATE_KEEPOUT, OTG, inst),\ - SRI(OTG_DSC_START_POSITION, OTG, inst),\ - SRI(OTG_DRR_TRIGGER_WINDOW, OTG, inst),\ - SRI(OTG_DRR_V_TOTAL_CHANGE, OTG, inst),\ - SRI(OPTC_DATA_FORMAT_CONTROL, ODM, inst),\ - SRI(OPTC_BYTES_PER_PIXEL, ODM, inst),\ - SRI(OPTC_WIDTH_CONTROL, ODM, inst),\ - SRI(OPTC_MEMORY_CONFIG, ODM, inst),\ - SRI(OTG_DRR_CONTROL, OTG, inst) - -#define OPTC_COMMON_MASK_SH_LIST_DCN3_14(mask_sh)\ - SF(OTG0_OTG_VSTARTUP_PARAM, VSTARTUP_START, mask_sh),\ - SF(OTG0_OTG_VUPDATE_PARAM, VUPDATE_OFFSET, mask_sh),\ - SF(OTG0_OTG_VUPDATE_PARAM, VUPDATE_WIDTH, mask_sh),\ - SF(OTG0_OTG_VREADY_PARAM, VREADY_OFFSET, mask_sh),\ - SF(OTG0_OTG_MASTER_UPDATE_LOCK, OTG_MASTER_UPDATE_LOCK, mask_sh),\ - SF(OTG0_OTG_MASTER_UPDATE_LOCK, UPDATE_LOCK_STATUS, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL0, MASTER_UPDATE_LOCK_DB_START_X, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL0, MASTER_UPDATE_LOCK_DB_END_X, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL0, MASTER_UPDATE_LOCK_DB_EN, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_START_Y, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_END_Y, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL2, OTG_MASTER_UPDATE_LOCK_SEL, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL4, DIG_UPDATE_POSITION_X, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL4, DIG_UPDATE_POSITION_Y, mask_sh),\ - SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_UPDATE_PENDING, mask_sh),\ - SF(OTG0_OTG_H_TOTAL, OTG_H_TOTAL, mask_sh),\ - SF(OTG0_OTG_H_BLANK_START_END, OTG_H_BLANK_START, mask_sh),\ - SF(OTG0_OTG_H_BLANK_START_END, OTG_H_BLANK_END, mask_sh),\ - SF(OTG0_OTG_H_SYNC_A, OTG_H_SYNC_A_START, mask_sh),\ - SF(OTG0_OTG_H_SYNC_A, OTG_H_SYNC_A_END, mask_sh),\ - SF(OTG0_OTG_H_SYNC_A_CNTL, OTG_H_SYNC_A_POL, mask_sh),\ - SF(OTG0_OTG_V_TOTAL, OTG_V_TOTAL, mask_sh),\ - SF(OTG0_OTG_V_BLANK_START_END, OTG_V_BLANK_START, mask_sh),\ - SF(OTG0_OTG_V_BLANK_START_END, OTG_V_BLANK_END, mask_sh),\ - SF(OTG0_OTG_V_SYNC_A, OTG_V_SYNC_A_START, mask_sh),\ - SF(OTG0_OTG_V_SYNC_A, OTG_V_SYNC_A_END, mask_sh),\ - SF(OTG0_OTG_V_SYNC_A_CNTL, OTG_V_SYNC_A_POL, mask_sh),\ - SF(OTG0_OTG_V_SYNC_A_CNTL, OTG_V_SYNC_MODE, mask_sh),\ - SF(OTG0_OTG_CONTROL, OTG_MASTER_EN, mask_sh),\ - SF(OTG0_OTG_CONTROL, OTG_START_POINT_CNTL, mask_sh),\ - SF(OTG0_OTG_CONTROL, OTG_DISABLE_POINT_CNTL, mask_sh),\ - SF(OTG0_OTG_CONTROL, OTG_FIELD_NUMBER_CNTL, mask_sh),\ - SF(OTG0_OTG_CONTROL, OTG_OUT_MUX, mask_sh),\ - SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_EN, mask_sh),\ - SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_SYNC_OUTPUT_LINE_NUM, mask_sh),\ - SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_SYNC_OUTPUT_POLARITY, mask_sh),\ - SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_EYE_FLAG_POLARITY, mask_sh),\ - SF(OTG0_OTG_STEREO_CONTROL, OTG_DISABLE_STEREOSYNC_OUTPUT_FOR_DP, mask_sh),\ - SF(OTG0_OTG_STEREO_STATUS, OTG_STEREO_CURRENT_EYE, mask_sh),\ - SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_EN, mask_sh),\ - SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_V_UPDATE_MODE, mask_sh),\ - SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_STEREO_SEL_OVR, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_MAX, OTG_V_TOTAL_MAX, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_MIN, OTG_V_TOTAL_MIN, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_V_TOTAL_MIN_SEL, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_V_TOTAL_MAX_SEL, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_FORCE_LOCK_ON_EVENT, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_SET_V_TOTAL_MIN_MASK, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_VTOTAL_MID_REPLACING_MIN_EN, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_VTOTAL_MID_REPLACING_MAX_EN, mask_sh),\ - SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_CLEAR, mask_sh),\ - SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_MODE, mask_sh),\ - SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_OCCURRED, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_SOURCE_SELECT, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_SOURCE_PIPE_SELECT, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_RISING_EDGE_DETECT_CNTL, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_POLARITY_SELECT, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_FREQUENCY_SELECT, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_DELAY, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_CLEAR, mask_sh),\ - SF(OTG0_OTG_STATIC_SCREEN_CONTROL, OTG_STATIC_SCREEN_EVENT_MASK, mask_sh),\ - SF(OTG0_OTG_STATIC_SCREEN_CONTROL, OTG_STATIC_SCREEN_FRAME_COUNT, mask_sh),\ - SF(OTG0_OTG_STATUS_FRAME_COUNT, OTG_FRAME_COUNT, mask_sh),\ - SF(OTG0_OTG_STATUS, OTG_V_BLANK, mask_sh),\ - SF(OTG0_OTG_STATUS, OTG_V_ACTIVE_DISP, mask_sh),\ - SF(OTG0_OTG_STATUS_POSITION, OTG_HORZ_COUNT, mask_sh),\ - SF(OTG0_OTG_STATUS_POSITION, OTG_VERT_COUNT, mask_sh),\ - SF(OTG0_OTG_NOM_VERT_POSITION, OTG_VERT_COUNT_NOM, mask_sh),\ - SF(OTG0_OTG_M_CONST_DTO0, OTG_M_CONST_DTO_PHASE, mask_sh),\ - SF(OTG0_OTG_M_CONST_DTO1, OTG_M_CONST_DTO_MODULO, mask_sh),\ - SF(OTG0_OTG_CLOCK_CONTROL, OTG_BUSY, mask_sh),\ - SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_EN, mask_sh),\ - SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_ON, mask_sh),\ - SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_GATE_DIS, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_INT_ENABLE, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT0_POSITION, OTG_VERTICAL_INTERRUPT0_LINE_START, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT0_POSITION, OTG_VERTICAL_INTERRUPT0_LINE_END, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT1_CONTROL, OTG_VERTICAL_INTERRUPT1_INT_ENABLE, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT1_POSITION, OTG_VERTICAL_INTERRUPT1_LINE_START, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT2_POSITION, OTG_VERTICAL_INTERRUPT2_LINE_START, mask_sh),\ - SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_EN, mask_sh),\ - SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_ON, mask_sh),\ - SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_GATE_DIS, mask_sh),\ - SF(ODM0_OPTC_INPUT_GLOBAL_CONTROL, OPTC_UNDERFLOW_OCCURRED_STATUS, mask_sh),\ - SF(ODM0_OPTC_INPUT_GLOBAL_CONTROL, OPTC_UNDERFLOW_CLEAR, mask_sh),\ - SF(VTG0_CONTROL, VTG0_ENABLE, mask_sh),\ - SF(VTG0_CONTROL, VTG0_FP2, mask_sh),\ - SF(VTG0_CONTROL, VTG0_VCOUNT_INIT, mask_sh),\ - SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_FORCE_VSYNC_NEXT_LINE_OCCURRED, mask_sh),\ - SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_FORCE_VSYNC_NEXT_LINE_CLEAR, mask_sh),\ - SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_AUTO_FORCE_VSYNC_MODE, mask_sh),\ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL0_EN, mask_sh),\ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL1_EN, mask_sh),\ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL2_EN, mask_sh),\ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_MASTER_EN, mask_sh),\ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_FORCE_DELAY, mask_sh),\ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_CHECK_ALL_FIELDS, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL, OTG_CRC_CONT_EN, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL, OTG_CRC0_SELECT, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL, OTG_CRC_EN, mask_sh),\ - SF(OTG0_OTG_CRC0_DATA_RG, CRC0_R_CR, mask_sh),\ - SF(OTG0_OTG_CRC0_DATA_RG, CRC0_G_Y, mask_sh),\ - SF(OTG0_OTG_CRC0_DATA_B, CRC0_B_CB, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWA_X_CONTROL, OTG_CRC0_WINDOWA_X_START, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWA_X_CONTROL, OTG_CRC0_WINDOWA_X_END, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWA_Y_CONTROL, OTG_CRC0_WINDOWA_Y_START, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWA_Y_CONTROL, OTG_CRC0_WINDOWA_Y_END, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWB_X_CONTROL, OTG_CRC0_WINDOWB_X_START, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWB_X_CONTROL, OTG_CRC0_WINDOWB_X_END, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL, OTG_CRC0_WINDOWB_Y_START, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL, OTG_CRC0_WINDOWB_Y_END, mask_sh),\ - SF(OTG0_OTG_TRIGA_MANUAL_TRIG, OTG_TRIGA_MANUAL_TRIG, mask_sh),\ - SF(GSL_SOURCE_SELECT, GSL0_READY_SOURCE_SEL, mask_sh),\ - SF(GSL_SOURCE_SELECT, GSL1_READY_SOURCE_SEL, mask_sh),\ - SF(GSL_SOURCE_SELECT, GSL2_READY_SOURCE_SEL, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL2, MANUAL_FLOW_CONTROL_SEL, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, mask_sh),\ - SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_START_X, mask_sh),\ - SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_END_X, mask_sh), \ - SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_START_Y, mask_sh),\ - SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_END_Y, mask_sh),\ - SF(OTG0_OTG_VUPDATE_KEEPOUT, OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, mask_sh), \ - SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET, mask_sh), \ - SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET, mask_sh), \ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_MASTER_MODE, mask_sh), \ - SF(OTG0_OTG_GSL_CONTROL, OTG_MASTER_UPDATE_LOCK_GSL_EN, mask_sh), \ - SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_X, mask_sh), \ - SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_LINE_NUM, mask_sh),\ - SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG0_SRC_SEL, mask_sh),\ - SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG1_SRC_SEL, mask_sh),\ - SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG2_SRC_SEL, mask_sh),\ - SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG3_SRC_SEL, mask_sh),\ - SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_NUM_OF_INPUT_SEGMENT, mask_sh),\ - SF(ODM0_OPTC_MEMORY_CONFIG, OPTC_MEM_SEL, mask_sh),\ - SF(ODM0_OPTC_DATA_FORMAT_CONTROL, OPTC_DATA_FORMAT, mask_sh),\ - SF(ODM0_OPTC_DATA_FORMAT_CONTROL, OPTC_DSC_MODE, mask_sh),\ - SF(ODM0_OPTC_BYTES_PER_PIXEL, OPTC_DSC_BYTES_PER_PIXEL, mask_sh),\ - SF(ODM0_OPTC_WIDTH_CONTROL, OPTC_DSC_SLICE_WIDTH, mask_sh),\ - SF(ODM0_OPTC_WIDTH_CONTROL, OPTC_SEGMENT_WIDTH, mask_sh),\ - SF(OTG0_OTG_DRR_TRIGGER_WINDOW, OTG_DRR_TRIGGER_WINDOW_START_X, mask_sh),\ - 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_H_TIMING_CNTL, OTG_H_TIMING_DIV_MODE_MANUAL, mask_sh),\ - SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_DRR_TIMING_DBUF_UPDATE_MODE, mask_sh),\ - SF(OTG0_OTG_DRR_CONTROL, OTG_V_TOTAL_LAST_USED_BY_DRR, mask_sh) - -void dcn314_timing_generator_init(struct optc *optc1); - -#endif /* __DC_OPTC_DCN314_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c deleted file mode 100644 index c97391edb5ff7a..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c +++ /dev/null @@ -1,2180 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - * 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 "dm_services.h" -#include "dc.h" - -#include "dcn31/dcn31_init.h" -#include "dcn314/dcn314_init.h" - -#include "resource.h" -#include "include/irq_service_interface.h" -#include "dcn314_resource.h" - -#include "dcn20/dcn20_resource.h" -#include "dcn30/dcn30_resource.h" -#include "dcn31/dcn31_resource.h" - -#include "dcn10/dcn10_ipp.h" -#include "dcn30/dcn30_hubbub.h" -#include "dcn31/dcn31_hubbub.h" -#include "dcn30/dcn30_mpc.h" -#include "dcn31/dcn31_hubp.h" -#include "irq/dcn31/irq_service_dcn31.h" -#include "irq/dcn314/irq_service_dcn314.h" -#include "dcn30/dcn30_dpp.h" -#include "dcn314/dcn314_optc.h" -#include "dcn20/dcn20_hwseq.h" -#include "dcn30/dcn30_hwseq.h" -#include "dce110/dce110_hwseq.h" -#include "dcn30/dcn30_opp.h" -#include "dcn20/dcn20_dsc.h" -#include "dcn30/dcn30_vpg.h" -#include "dcn30/dcn30_afmt.h" -#include "dcn31/dcn31_dio_link_encoder.h" -#include "dcn314/dcn314_dio_stream_encoder.h" -#include "dcn31/dcn31_hpo_dp_stream_encoder.h" -#include "dcn31/dcn31_hpo_dp_link_encoder.h" -#include "dcn31/dcn31_apg.h" -#include "dcn31/dcn31_vpg.h" -#include "dcn31/dcn31_afmt.h" -#include "dce/dce_clock_source.h" -#include "dce/dce_audio.h" -#include "dce/dce_hwseq.h" -#include "clk_mgr.h" -#include "virtual/virtual_stream_encoder.h" -#include "dce110/dce110_resource.h" -#include "dml/display_mode_vba.h" -#include "dml/dcn31/dcn31_fpu.h" -#include "dml/dcn314/dcn314_fpu.h" -#include "dcn314/dcn314_dccg.h" -#include "dcn10/dcn10_resource.h" -#include "dcn31/dcn31_panel_cntl.h" -#include "dcn314/dcn314_hwseq.h" - -#include "dcn30/dcn30_dwb.h" -#include "dcn30/dcn30_mmhubbub.h" - -#include "dcn/dcn_3_1_4_offset.h" -#include "dcn/dcn_3_1_4_sh_mask.h" -#include "dpcs/dpcs_3_1_4_offset.h" -#include "dpcs/dpcs_3_1_4_sh_mask.h" - -#define DCHUBBUB_DEBUG_CTRL_0__DET_DEPTH__SHIFT 0x10 -#define DCHUBBUB_DEBUG_CTRL_0__DET_DEPTH_MASK 0x01FF0000L - -#define DSCC0_DSCC_CONFIG0__ICH_RESET_AT_END_OF_LINE__SHIFT 0x0 -#define DSCC0_DSCC_CONFIG0__ICH_RESET_AT_END_OF_LINE_MASK 0x0000000FL - -#include "reg_helper.h" -#include "dce/dmub_abm.h" -#include "dce/dmub_psr.h" -#include "dce/dmub_replay.h" -#include "dce/dce_aux.h" -#include "dce/dce_i2c.h" -#include "dml/dcn314/display_mode_vba_314.h" -#include "vm_helper.h" -#include "dcn20/dcn20_vmid.h" - -#include "link_enc_cfg.h" - -#define DCN_BASE__INST0_SEG1 0x000000C0 -#define DCN_BASE__INST0_SEG2 0x000034C0 -#define DCN_BASE__INST0_SEG3 0x00009000 - -#define NBIO_BASE__INST0_SEG1 0x00000014 - -#define MAX_INSTANCE 7 -#define MAX_SEGMENT 8 - -#define regBIF_BX2_BIOS_SCRATCH_2 0x003a -#define regBIF_BX2_BIOS_SCRATCH_2_BASE_IDX 1 -#define regBIF_BX2_BIOS_SCRATCH_3 0x003b -#define regBIF_BX2_BIOS_SCRATCH_3_BASE_IDX 1 -#define regBIF_BX2_BIOS_SCRATCH_6 0x003e -#define regBIF_BX2_BIOS_SCRATCH_6_BASE_IDX 1 - -#define DC_LOGGER \ - dc->ctx->logger -#define DC_LOGGER_INIT(logger) - -enum dcn31_clk_src_array_id { - DCN31_CLK_SRC_PLL0, - DCN31_CLK_SRC_PLL1, - DCN31_CLK_SRC_PLL2, - DCN31_CLK_SRC_PLL3, - DCN31_CLK_SRC_PLL4, - DCN30_CLK_SRC_TOTAL -}; - -/* begin ********************* - * macros to expend register list macro defined in HW object header file - */ - -/* DCN */ -/* TODO awful hack. fixup dcn20_dwb.h */ -#undef BASE_INNER -#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg - -#define BASE(seg) BASE_INNER(seg) - -#define SR(reg_name)\ - .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ - reg ## reg_name - -#define SRI(reg_name, block, id)\ - .reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRI2(reg_name, block, id)\ - .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ - reg ## reg_name - -#define SRIR(var_name, reg_name, block, id)\ - .var_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRII(reg_name, block, id)\ - .reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRII_MPC_RMU(reg_name, block, id)\ - .RMU##_##reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRII_DWB(reg_name, temp_name, block, id)\ - .reg_name[id] = BASE(reg ## block ## id ## _ ## temp_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## temp_name - -#define SF_DWB2(reg_name, block, id, field_name, post_fix) \ - .field_name = reg_name ## __ ## field_name ## post_fix - -#define DCCG_SRII(reg_name, block, id)\ - .block ## _ ## reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define VUPDATE_SRII(reg_name, block, id)\ - .reg_name[id] = BASE(reg ## reg_name ## _ ## block ## id ## _BASE_IDX) + \ - reg ## reg_name ## _ ## block ## id - -/* NBIO */ -#define NBIO_BASE_INNER(seg) \ - NBIO_BASE__INST0_SEG ## seg - -#define NBIO_BASE(seg) \ - NBIO_BASE_INNER(seg) - -#define NBIO_SR(reg_name)\ - .reg_name = NBIO_BASE(regBIF_BX2_ ## reg_name ## _BASE_IDX) + \ - regBIF_BX2_ ## reg_name - -/* MMHUB */ -#define MMHUB_BASE_INNER(seg) \ - MMHUB_BASE__INST0_SEG ## seg - -#define MMHUB_BASE(seg) \ - MMHUB_BASE_INNER(seg) - -#define MMHUB_SR(reg_name)\ - .reg_name = MMHUB_BASE(reg ## reg_name ## _BASE_IDX) + \ - reg ## reg_name - -/* CLOCK */ -#define CLK_BASE_INNER(seg) \ - CLK_BASE__INST0_SEG ## seg - -#define CLK_BASE(seg) \ - CLK_BASE_INNER(seg) - -#define CLK_SRI(reg_name, block, inst)\ - .reg_name = CLK_BASE(reg ## block ## _ ## inst ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## _ ## inst ## _ ## reg_name - - -static const struct bios_registers bios_regs = { - NBIO_SR(BIOS_SCRATCH_3), - NBIO_SR(BIOS_SCRATCH_6) -}; - -#define clk_src_regs(index, pllid)\ -[index] = {\ - CS_COMMON_REG_LIST_DCN3_0(index, pllid),\ -} - -static const struct dce110_clk_src_regs clk_src_regs[] = { - clk_src_regs(0, A), - clk_src_regs(1, B), - clk_src_regs(2, C), - clk_src_regs(3, D), - clk_src_regs(4, E) -}; - -static const struct dce110_clk_src_shift cs_shift = { - CS_COMMON_MASK_SH_LIST_DCN3_1_4(__SHIFT) -}; - -static const struct dce110_clk_src_mask cs_mask = { - CS_COMMON_MASK_SH_LIST_DCN3_1_4(_MASK) -}; - -#define abm_regs(id)\ -[id] = {\ - ABM_DCN302_REG_LIST(id)\ -} - -static const struct dce_abm_registers abm_regs[] = { - abm_regs(0), - abm_regs(1), - abm_regs(2), - abm_regs(3), -}; - -static const struct dce_abm_shift abm_shift = { - ABM_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dce_abm_mask abm_mask = { - ABM_MASK_SH_LIST_DCN30(_MASK) -}; - -#define audio_regs(id)\ -[id] = {\ - AUD_COMMON_REG_LIST(id)\ -} - -static const struct dce_audio_registers audio_regs[] = { - audio_regs(0), - audio_regs(1), - audio_regs(2), - audio_regs(3), - audio_regs(4), - audio_regs(5), - audio_regs(6) -}; - -#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ - SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ - SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ - AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) - -static const struct dce_audio_shift audio_shift = { - DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_audio_mask audio_mask = { - DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) -}; - -#define vpg_regs(id)\ -[id] = {\ - VPG_DCN31_REG_LIST(id)\ -} - -static const struct dcn31_vpg_registers vpg_regs[] = { - vpg_regs(0), - vpg_regs(1), - vpg_regs(2), - vpg_regs(3), - vpg_regs(4), - vpg_regs(5), - vpg_regs(6), - vpg_regs(7), - vpg_regs(8), - vpg_regs(9), -}; - -static const struct dcn31_vpg_shift vpg_shift = { - DCN31_VPG_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn31_vpg_mask vpg_mask = { - DCN31_VPG_MASK_SH_LIST(_MASK) -}; - -#define afmt_regs(id)\ -[id] = {\ - AFMT_DCN31_REG_LIST(id)\ -} - -static const struct dcn31_afmt_registers afmt_regs[] = { - afmt_regs(0), - afmt_regs(1), - afmt_regs(2), - afmt_regs(3), - afmt_regs(4), - afmt_regs(5) -}; - -static const struct dcn31_afmt_shift afmt_shift = { - DCN31_AFMT_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn31_afmt_mask afmt_mask = { - DCN31_AFMT_MASK_SH_LIST(_MASK) -}; - -#define apg_regs(id)\ -[id] = {\ - APG_DCN31_REG_LIST(id)\ -} - -static const struct dcn31_apg_registers apg_regs[] = { - apg_regs(0), - apg_regs(1), - apg_regs(2), - apg_regs(3) -}; - -static const struct dcn31_apg_shift apg_shift = { - DCN31_APG_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn31_apg_mask apg_mask = { - DCN31_APG_MASK_SH_LIST(_MASK) -}; - -#define stream_enc_regs(id)\ -[id] = {\ - SE_DCN314_REG_LIST(id)\ -} - -static const struct dcn10_stream_enc_registers stream_enc_regs[] = { - stream_enc_regs(0), - stream_enc_regs(1), - stream_enc_regs(2), - stream_enc_regs(3), - stream_enc_regs(4) -}; - -static const struct dcn10_stream_encoder_shift se_shift = { - SE_COMMON_MASK_SH_LIST_DCN314(__SHIFT) -}; - -static const struct dcn10_stream_encoder_mask se_mask = { - SE_COMMON_MASK_SH_LIST_DCN314(_MASK) -}; - - -#define aux_regs(id)\ -[id] = {\ - DCN2_AUX_REG_LIST(id)\ -} - -static const struct dcn10_link_enc_aux_registers link_enc_aux_regs[] = { - aux_regs(0), - aux_regs(1), - aux_regs(2), - aux_regs(3), - aux_regs(4) -}; - -#define hpd_regs(id)\ -[id] = {\ - HPD_REG_LIST(id)\ -} - -static const struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[] = { - hpd_regs(0), - hpd_regs(1), - hpd_regs(2), - hpd_regs(3), - hpd_regs(4) -}; - -#define link_regs(id, phyid)\ -[id] = {\ - LE_DCN31_REG_LIST(id), \ - UNIPHY_DCN2_REG_LIST(phyid), \ -} - -static const struct dce110_aux_registers_shift aux_shift = { - DCN_AUX_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce110_aux_registers_mask aux_mask = { - DCN_AUX_MASK_SH_LIST(_MASK) -}; - -static const struct dcn10_link_enc_registers link_enc_regs[] = { - link_regs(0, A), - link_regs(1, B), - link_regs(2, C), - link_regs(3, D), - link_regs(4, E) -}; - -static const struct dcn10_link_enc_shift le_shift = { - LINK_ENCODER_MASK_SH_LIST_DCN31(__SHIFT), - DPCS_DCN31_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn10_link_enc_mask le_mask = { - LINK_ENCODER_MASK_SH_LIST_DCN31(_MASK), - DPCS_DCN31_MASK_SH_LIST(_MASK) -}; - -#define hpo_dp_stream_encoder_reg_list(id)\ -[id] = {\ - DCN3_1_HPO_DP_STREAM_ENC_REG_LIST(id)\ -} - -static const struct dcn31_hpo_dp_stream_encoder_registers hpo_dp_stream_enc_regs[] = { - hpo_dp_stream_encoder_reg_list(0), - hpo_dp_stream_encoder_reg_list(1), - hpo_dp_stream_encoder_reg_list(2), - hpo_dp_stream_encoder_reg_list(3) -}; - -static const struct dcn31_hpo_dp_stream_encoder_shift hpo_dp_se_shift = { - DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn31_hpo_dp_stream_encoder_mask hpo_dp_se_mask = { - DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(_MASK) -}; - - -#define hpo_dp_link_encoder_reg_list(id)\ -[id] = {\ - DCN3_1_HPO_DP_LINK_ENC_REG_LIST(id),\ - DCN3_1_RDPCSTX_REG_LIST(0),\ - DCN3_1_RDPCSTX_REG_LIST(1),\ - DCN3_1_RDPCSTX_REG_LIST(2),\ -} - -static const struct dcn31_hpo_dp_link_encoder_registers hpo_dp_link_enc_regs[] = { - hpo_dp_link_encoder_reg_list(0), - hpo_dp_link_encoder_reg_list(1), -}; - -static const struct dcn31_hpo_dp_link_encoder_shift hpo_dp_le_shift = { - DCN3_1_HPO_DP_LINK_ENC_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn31_hpo_dp_link_encoder_mask hpo_dp_le_mask = { - DCN3_1_HPO_DP_LINK_ENC_MASK_SH_LIST(_MASK) -}; - -#define dpp_regs(id)\ -[id] = {\ - DPP_REG_LIST_DCN30(id),\ -} - -static const struct dcn3_dpp_registers dpp_regs[] = { - dpp_regs(0), - dpp_regs(1), - dpp_regs(2), - dpp_regs(3) -}; - -static const struct dcn3_dpp_shift tf_shift = { - DPP_REG_LIST_SH_MASK_DCN30(__SHIFT) -}; - -static const struct dcn3_dpp_mask tf_mask = { - DPP_REG_LIST_SH_MASK_DCN30(_MASK) -}; - -#define opp_regs(id)\ -[id] = {\ - OPP_REG_LIST_DCN30(id),\ -} - -static const struct dcn20_opp_registers opp_regs[] = { - opp_regs(0), - opp_regs(1), - opp_regs(2), - opp_regs(3) -}; - -static const struct dcn20_opp_shift opp_shift = { - OPP_MASK_SH_LIST_DCN20(__SHIFT) -}; - -static const struct dcn20_opp_mask opp_mask = { - OPP_MASK_SH_LIST_DCN20(_MASK) -}; - -#define aux_engine_regs(id)\ -[id] = {\ - AUX_COMMON_REG_LIST0(id), \ - .AUXN_IMPCAL = 0, \ - .AUXP_IMPCAL = 0, \ - .AUX_RESET_MASK = DP_AUX0_AUX_CONTROL__AUX_RESET_MASK, \ -} - -static const struct dce110_aux_registers aux_engine_regs[] = { - aux_engine_regs(0), - aux_engine_regs(1), - aux_engine_regs(2), - aux_engine_regs(3), - aux_engine_regs(4) -}; - -#define dwbc_regs_dcn3(id)\ -[id] = {\ - DWBC_COMMON_REG_LIST_DCN30(id),\ -} - -static const struct dcn30_dwbc_registers dwbc30_regs[] = { - dwbc_regs_dcn3(0), -}; - -static const struct dcn30_dwbc_shift dwbc30_shift = { - DWBC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn30_dwbc_mask dwbc30_mask = { - DWBC_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -#define mcif_wb_regs_dcn3(id)\ -[id] = {\ - MCIF_WB_COMMON_REG_LIST_DCN30(id),\ -} - -static const struct dcn30_mmhubbub_registers mcif_wb30_regs[] = { - mcif_wb_regs_dcn3(0) -}; - -static const struct dcn30_mmhubbub_shift mcif_wb30_shift = { - MCIF_WB_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn30_mmhubbub_mask mcif_wb30_mask = { - MCIF_WB_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -#define dsc_regsDCN314(id)\ -[id] = {\ - DSC_REG_LIST_DCN20(id)\ -} - -static const struct dcn20_dsc_registers dsc_regs[] = { - dsc_regsDCN314(0), - dsc_regsDCN314(1), - dsc_regsDCN314(2), - dsc_regsDCN314(3) -}; - -static const struct dcn20_dsc_shift dsc_shift = { - DSC_REG_LIST_SH_MASK_DCN20(__SHIFT) -}; - -static const struct dcn20_dsc_mask dsc_mask = { - DSC_REG_LIST_SH_MASK_DCN20(_MASK) -}; - -static const struct dcn30_mpc_registers mpc_regs = { - MPC_REG_LIST_DCN3_0(0), - MPC_REG_LIST_DCN3_0(1), - MPC_REG_LIST_DCN3_0(2), - MPC_REG_LIST_DCN3_0(3), - MPC_OUT_MUX_REG_LIST_DCN3_0(0), - MPC_OUT_MUX_REG_LIST_DCN3_0(1), - MPC_OUT_MUX_REG_LIST_DCN3_0(2), - MPC_OUT_MUX_REG_LIST_DCN3_0(3), - MPC_RMU_GLOBAL_REG_LIST_DCN3AG, - MPC_RMU_REG_LIST_DCN3AG(0), - MPC_RMU_REG_LIST_DCN3AG(1), - //MPC_RMU_REG_LIST_DCN3AG(2), - MPC_DWB_MUX_REG_LIST_DCN3_0(0), -}; - -static const struct dcn30_mpc_shift mpc_shift = { - MPC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn30_mpc_mask mpc_mask = { - MPC_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -#define optc_regs(id)\ -[id] = {OPTC_COMMON_REG_LIST_DCN3_14(id)} - -static const struct dcn_optc_registers optc_regs[] = { - optc_regs(0), - optc_regs(1), - optc_regs(2), - optc_regs(3) -}; - -static const struct dcn_optc_shift optc_shift = { - OPTC_COMMON_MASK_SH_LIST_DCN3_14(__SHIFT) -}; - -static const struct dcn_optc_mask optc_mask = { - OPTC_COMMON_MASK_SH_LIST_DCN3_14(_MASK) -}; - -#define hubp_regs(id)\ -[id] = {\ - HUBP_REG_LIST_DCN30(id)\ -} - -static const struct dcn_hubp2_registers hubp_regs[] = { - hubp_regs(0), - hubp_regs(1), - hubp_regs(2), - hubp_regs(3) -}; - - -static const struct dcn_hubp2_shift hubp_shift = { - HUBP_MASK_SH_LIST_DCN31(__SHIFT) -}; - -static const struct dcn_hubp2_mask hubp_mask = { - HUBP_MASK_SH_LIST_DCN31(_MASK) -}; -static const struct dcn_hubbub_registers hubbub_reg = { - HUBBUB_REG_LIST_DCN31(0) -}; - -static const struct dcn_hubbub_shift hubbub_shift = { - HUBBUB_MASK_SH_LIST_DCN31(__SHIFT) -}; - -static const struct dcn_hubbub_mask hubbub_mask = { - HUBBUB_MASK_SH_LIST_DCN31(_MASK) -}; - -static const struct dccg_registers dccg_regs = { - DCCG_REG_LIST_DCN314() -}; - -static const struct dccg_shift dccg_shift = { - DCCG_MASK_SH_LIST_DCN314(__SHIFT) -}; - -static const struct dccg_mask dccg_mask = { - DCCG_MASK_SH_LIST_DCN314(_MASK) -}; - - -#define SRII2(reg_name_pre, reg_name_post, id)\ - .reg_name_pre ## _ ## reg_name_post[id] = BASE(reg ## reg_name_pre \ - ## id ## _ ## reg_name_post ## _BASE_IDX) + \ - reg ## reg_name_pre ## id ## _ ## reg_name_post - - -#define HWSEQ_DCN31_REG_LIST()\ - SR(DCHUBBUB_GLOBAL_TIMER_CNTL), \ - SR(DCHUBBUB_ARB_HOSTVM_CNTL), \ - SR(DIO_MEM_PWR_CTRL), \ - SR(ODM_MEM_PWR_CTRL3), \ - SR(DMU_MEM_PWR_CNTL), \ - SR(MMHUBBUB_MEM_PWR_CNTL), \ - SR(DCCG_GATE_DISABLE_CNTL), \ - SR(DCCG_GATE_DISABLE_CNTL2), \ - SR(DCFCLK_CNTL),\ - SR(DC_MEM_GLOBAL_PWR_REQ_CNTL), \ - SRII(PIXEL_RATE_CNTL, OTG, 0), \ - SRII(PIXEL_RATE_CNTL, OTG, 1),\ - SRII(PIXEL_RATE_CNTL, OTG, 2),\ - SRII(PIXEL_RATE_CNTL, OTG, 3),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 0),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 1),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 2),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 3),\ - SR(MICROSECOND_TIME_BASE_DIV), \ - SR(MILLISECOND_TIME_BASE_DIV), \ - SR(DISPCLK_FREQ_CHANGE_CNTL), \ - SR(RBBMIF_TIMEOUT_DIS), \ - SR(RBBMIF_TIMEOUT_DIS_2), \ - SR(DCHUBBUB_CRC_CTRL), \ - SR(DPP_TOP0_DPP_CRC_CTRL), \ - SR(DPP_TOP0_DPP_CRC_VAL_B_A), \ - SR(DPP_TOP0_DPP_CRC_VAL_R_G), \ - SR(MPC_CRC_CTRL), \ - SR(MPC_CRC_RESULT_GB), \ - SR(MPC_CRC_RESULT_C), \ - SR(MPC_CRC_RESULT_AR), \ - SR(DOMAIN0_PG_CONFIG), \ - SR(DOMAIN1_PG_CONFIG), \ - SR(DOMAIN2_PG_CONFIG), \ - SR(DOMAIN3_PG_CONFIG), \ - SR(DOMAIN16_PG_CONFIG), \ - SR(DOMAIN17_PG_CONFIG), \ - SR(DOMAIN18_PG_CONFIG), \ - SR(DOMAIN19_PG_CONFIG), \ - SR(DOMAIN0_PG_STATUS), \ - SR(DOMAIN1_PG_STATUS), \ - SR(DOMAIN2_PG_STATUS), \ - SR(DOMAIN3_PG_STATUS), \ - SR(DOMAIN16_PG_STATUS), \ - SR(DOMAIN17_PG_STATUS), \ - SR(DOMAIN18_PG_STATUS), \ - SR(DOMAIN19_PG_STATUS), \ - SR(D1VGA_CONTROL), \ - SR(D2VGA_CONTROL), \ - SR(D3VGA_CONTROL), \ - SR(D4VGA_CONTROL), \ - SR(D5VGA_CONTROL), \ - SR(D6VGA_CONTROL), \ - SR(DC_IP_REQUEST_CNTL), \ - SR(AZALIA_AUDIO_DTO), \ - SR(AZALIA_CONTROLLER_CLOCK_GATING), \ - SR(HPO_TOP_HW_CONTROL) - -static const struct dce_hwseq_registers hwseq_reg = { - HWSEQ_DCN31_REG_LIST() -}; - -#define HWSEQ_DCN31_MASK_SH_LIST(mask_sh)\ - HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ - HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \ - HWS_SF(, DCHUBBUB_ARB_HOSTVM_CNTL, DISABLE_HOSTVM_FORCE_ALLOW_PSTATE, mask_sh), \ - HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN19_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN19_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN16_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN17_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN18_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN19_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \ - HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh), \ - HWS_SF(, HPO_TOP_CLOCK_CONTROL, HPO_HDMISTREAMCLK_G_GATE_DIS, mask_sh), \ - HWS_SF(, DMU_MEM_PWR_CNTL, DMCU_ERAM_MEM_PWR_FORCE, mask_sh), \ - HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_UNASSIGNED_PWR_MODE, mask_sh), \ - HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_VBLANK_PWR_MODE, mask_sh), \ - HWS_SF(, MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, mask_sh), \ - HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh), \ - HWS_SF(, HPO_TOP_HW_CONTROL, HPO_IO_EN, mask_sh) - -static const struct dce_hwseq_shift hwseq_shift = { - HWSEQ_DCN31_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_hwseq_mask hwseq_mask = { - HWSEQ_DCN31_MASK_SH_LIST(_MASK) -}; -#define vmid_regs(id)\ -[id] = {\ - DCN20_VMID_REG_LIST(id)\ -} - -static const struct dcn_vmid_registers vmid_regs[] = { - vmid_regs(0), - vmid_regs(1), - vmid_regs(2), - vmid_regs(3), - vmid_regs(4), - vmid_regs(5), - vmid_regs(6), - vmid_regs(7), - vmid_regs(8), - vmid_regs(9), - vmid_regs(10), - vmid_regs(11), - vmid_regs(12), - vmid_regs(13), - vmid_regs(14), - vmid_regs(15) -}; - -static const struct dcn20_vmid_shift vmid_shifts = { - DCN20_VMID_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn20_vmid_mask vmid_masks = { - DCN20_VMID_MASK_SH_LIST(_MASK) -}; - -static const struct resource_caps res_cap_dcn314 = { - .num_timing_generator = 4, - .num_opp = 4, - .num_video_plane = 4, - .num_audio = 5, - .num_stream_encoder = 5, - .num_dig_link_enc = 5, - .num_hpo_dp_stream_encoder = 4, - .num_hpo_dp_link_encoder = 2, - .num_pll = 5, - .num_dwb = 1, - .num_ddc = 5, - .num_vmid = 16, - .num_mpc_3dlut = 2, - .num_dsc = 4, -}; - -static const struct dc_plane_cap plane_cap = { - .type = DC_PLANE_TYPE_DCN_UNIVERSAL, - .per_pixel_alpha = true, - - .pixel_format_support = { - .argb8888 = true, - .nv12 = true, - .fp16 = true, - .p010 = true, - .ayuv = false, - }, - - .max_upscale_factor = { - .argb8888 = 16000, - .nv12 = 16000, - .fp16 = 16000 - }, - - // 6:1 downscaling ratio: 1000/6 = 166.666 - // 4:1 downscaling ratio for ARGB888 to prevent underflow during P010 playback: 1000/4 = 250 - .max_downscale_factor = { - .argb8888 = 250, - .nv12 = 167, - .fp16 = 167 - }, - 64, - 64 -}; - -static const struct dc_debug_options debug_defaults_drv = { - .disable_z10 = false, - .enable_z9_disable_interface = true, - .minimum_z8_residency_time = 2100, - .psr_skip_crtc_disable = true, - .replay_skip_crtc_disabled = true, - .disable_dmcu = true, - .force_abm_enable = false, - .timing_trace = false, - .clock_trace = true, - .disable_dpp_power_gate = false, - .disable_hubp_power_gate = false, - .disable_pplib_clock_request = false, - .pipe_split_policy = MPC_SPLIT_DYNAMIC, - .force_single_disp_pipe_split = false, - .disable_dcc = DCC_ENABLE, - .vsr_support = true, - .performance_trace = false, - .max_downscale_src_width = 4096,/*upto true 4k*/ - .disable_pplib_wm_range = false, - .scl_reset_length10 = true, - .sanity_checks = true, - .underflow_assert_delay_us = 0xFFFFFFFF, - .dwb_fi_phase = -1, // -1 = disable, - .dmub_command_table = true, - .pstate_enabled = true, - .use_max_lb = true, - .enable_mem_low_power = { - .bits = { - .vga = true, - .i2c = true, - .dmcu = false, // This is previously known to cause hang on S3 cycles if enabled - .dscl = true, - .cm = true, - .mpc = true, - .optc = true, - .vpg = true, - .afmt = true, - } - }, - - .root_clock_optimization = { - .bits = { - .dpp = true, - .dsc = true, - .hdmistream = true, - .hdmichar = true, - .dpstream = true, - .symclk32_se = false, - .symclk32_le = true, - .symclk_fe = true, - .physymclk = true, - .dpiasymclk = true, - } - }, - - .seamless_boot_odm_combine = true, - .using_dml2 = false, -}; - -static const struct dc_debug_options debug_defaults_diags = { - .disable_dmcu = true, - .force_abm_enable = false, - .timing_trace = true, - .clock_trace = true, - .disable_dpp_power_gate = true, - .disable_hubp_power_gate = true, - .disable_clock_gate = true, - .disable_pplib_clock_request = true, - .disable_pplib_wm_range = true, - .disable_stutter = false, - .scl_reset_length10 = true, - .dwb_fi_phase = -1, // -1 = disable - .dmub_command_table = true, - .enable_tri_buf = true, - .use_max_lb = true -}; - -static const struct dc_panel_config panel_config_defaults = { - .psr = { - .disable_psr = false, - .disallow_psrsu = false, - .disallow_replay = false, - }, - .ilr = { - .optimize_edp_link_rate = true, - }, -}; - -static void dcn31_dpp_destroy(struct dpp **dpp) -{ - kfree(TO_DCN20_DPP(*dpp)); - *dpp = NULL; -} - -static struct dpp *dcn31_dpp_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn3_dpp *dpp = - kzalloc(sizeof(struct dcn3_dpp), GFP_KERNEL); - - if (!dpp) - return NULL; - - if (dpp3_construct(dpp, ctx, inst, - &dpp_regs[inst], &tf_shift, &tf_mask)) - return &dpp->base; - - BREAK_TO_DEBUGGER(); - kfree(dpp); - return NULL; -} - -static struct output_pixel_processor *dcn31_opp_create( - struct dc_context *ctx, uint32_t inst) -{ - struct dcn20_opp *opp = - kzalloc(sizeof(struct dcn20_opp), GFP_KERNEL); - - if (!opp) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dcn20_opp_construct(opp, ctx, inst, - &opp_regs[inst], &opp_shift, &opp_mask); - return &opp->base; -} - -static struct dce_aux *dcn31_aux_engine_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct aux_engine_dce110 *aux_engine = - kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); - - if (!aux_engine) - return NULL; - - dce110_aux_engine_construct(aux_engine, ctx, inst, - SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, - &aux_engine_regs[inst], - &aux_mask, - &aux_shift, - ctx->dc->caps.extended_aux_timeout_support); - - return &aux_engine->base; -} -#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST_DCN30(id) } - -static const struct dce_i2c_registers i2c_hw_regs[] = { - i2c_inst_regs(1), - i2c_inst_regs(2), - i2c_inst_regs(3), - i2c_inst_regs(4), - i2c_inst_regs(5), -}; - -static const struct dce_i2c_shift i2c_shifts = { - I2C_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dce_i2c_mask i2c_masks = { - I2C_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -/* ========================================================== */ - -/* - * DPIA index | Preferred Encoder | Host Router - * 0 | C | 0 - * 1 | First Available | 0 - * 2 | D | 1 - * 3 | First Available | 1 - */ -/* ========================================================== */ -static const enum engine_id dpia_to_preferred_enc_id_table[] = { - ENGINE_ID_DIGC, - ENGINE_ID_DIGC, - ENGINE_ID_DIGD, - ENGINE_ID_DIGD -}; - -static enum engine_id dcn314_get_preferred_eng_id_dpia(unsigned int dpia_index) -{ - return dpia_to_preferred_enc_id_table[dpia_index]; -} - -static struct dce_i2c_hw *dcn31_i2c_hw_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dce_i2c_hw *dce_i2c_hw = - kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); - - if (!dce_i2c_hw) - return NULL; - - dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst, - &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); - - return dce_i2c_hw; -} -static struct mpc *dcn31_mpc_create( - struct dc_context *ctx, - int num_mpcc, - int num_rmu) -{ - struct dcn30_mpc *mpc30 = kzalloc(sizeof(struct dcn30_mpc), - GFP_KERNEL); - - if (!mpc30) - return NULL; - - dcn30_mpc_construct(mpc30, ctx, - &mpc_regs, - &mpc_shift, - &mpc_mask, - num_mpcc, - num_rmu); - - return &mpc30->base; -} - -static struct hubbub *dcn31_hubbub_create(struct dc_context *ctx) -{ - int i; - - struct dcn20_hubbub *hubbub3 = kzalloc(sizeof(struct dcn20_hubbub), - GFP_KERNEL); - - if (!hubbub3) - return NULL; - - hubbub31_construct(hubbub3, ctx, - &hubbub_reg, - &hubbub_shift, - &hubbub_mask, - dcn3_14_ip.det_buffer_size_kbytes, - dcn3_14_ip.pixel_chunk_size_kbytes, - dcn3_14_ip.config_return_buffer_size_in_kbytes); - - - for (i = 0; i < res_cap_dcn314.num_vmid; i++) { - struct dcn20_vmid *vmid = &hubbub3->vmid[i]; - - vmid->ctx = ctx; - - vmid->regs = &vmid_regs[i]; - vmid->shifts = &vmid_shifts; - vmid->masks = &vmid_masks; - } - - return &hubbub3->base; -} - -static struct timing_generator *dcn31_timing_generator_create( - struct dc_context *ctx, - uint32_t instance) -{ - struct optc *tgn10 = - kzalloc(sizeof(struct optc), GFP_KERNEL); - - if (!tgn10) - return NULL; - - tgn10->base.inst = instance; - tgn10->base.ctx = ctx; - - tgn10->tg_regs = &optc_regs[instance]; - tgn10->tg_shift = &optc_shift; - tgn10->tg_mask = &optc_mask; - - dcn314_timing_generator_init(tgn10); - - return &tgn10->base; -} - -static const struct encoder_feature_support link_enc_feature = { - .max_hdmi_deep_color = COLOR_DEPTH_121212, - .max_hdmi_pixel_clock = 600000, - .hdmi_ycbcr420_supported = true, - .dp_ycbcr420_supported = true, - .fec_supported = true, - .flags.bits.IS_HBR2_CAPABLE = true, - .flags.bits.IS_HBR3_CAPABLE = true, - .flags.bits.IS_TPS3_CAPABLE = true, - .flags.bits.IS_TPS4_CAPABLE = true -}; - -static struct link_encoder *dcn31_link_encoder_create( - struct dc_context *ctx, - const struct encoder_init_data *enc_init_data) -{ - struct dcn20_link_encoder *enc20 = - kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); - - if (!enc20) - return NULL; - - dcn31_link_encoder_construct(enc20, - enc_init_data, - &link_enc_feature, - &link_enc_regs[enc_init_data->transmitter], - &link_enc_aux_regs[enc_init_data->channel - 1], - &link_enc_hpd_regs[enc_init_data->hpd_source], - &le_shift, - &le_mask); - - return &enc20->enc10.base; -} - -/* Create a minimal link encoder object not associated with a particular - * physical connector. - * resource_funcs.link_enc_create_minimal - */ -static struct link_encoder *dcn31_link_enc_create_minimal( - struct dc_context *ctx, enum engine_id eng_id) -{ - struct dcn20_link_encoder *enc20; - - if ((eng_id - ENGINE_ID_DIGA) > ctx->dc->res_pool->res_cap->num_dig_link_enc) - return NULL; - - enc20 = kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); - if (!enc20) - return NULL; - - dcn31_link_encoder_construct_minimal( - enc20, - ctx, - &link_enc_feature, - &link_enc_regs[eng_id - ENGINE_ID_DIGA], - eng_id); - - return &enc20->enc10.base; -} - -static struct panel_cntl *dcn31_panel_cntl_create(const struct panel_cntl_init_data *init_data) -{ - struct dcn31_panel_cntl *panel_cntl = - kzalloc(sizeof(struct dcn31_panel_cntl), GFP_KERNEL); - - if (!panel_cntl) - return NULL; - - dcn31_panel_cntl_construct(panel_cntl, init_data); - - return &panel_cntl->base; -} - -static void read_dce_straps( - struct dc_context *ctx, - struct resource_straps *straps) -{ - generic_reg_get(ctx, regDC_PINSTRAPS + BASE(regDC_PINSTRAPS_BASE_IDX), - FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio); - -} - -static struct audio *dcn31_create_audio( - struct dc_context *ctx, unsigned int inst) -{ - return dce_audio_create(ctx, inst, - &audio_regs[inst], &audio_shift, &audio_mask); -} - -static struct vpg *dcn31_vpg_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn31_vpg *vpg31 = kzalloc(sizeof(struct dcn31_vpg), GFP_KERNEL); - - if (!vpg31) - return NULL; - - vpg31_construct(vpg31, ctx, inst, - &vpg_regs[inst], - &vpg_shift, - &vpg_mask); - - return &vpg31->base; -} - -static struct afmt *dcn31_afmt_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn31_afmt *afmt31 = kzalloc(sizeof(struct dcn31_afmt), GFP_KERNEL); - - if (!afmt31) - return NULL; - - afmt31_construct(afmt31, ctx, inst, - &afmt_regs[inst], - &afmt_shift, - &afmt_mask); - - // Light sleep by default, no need to power down here - - return &afmt31->base; -} - -static struct apg *dcn31_apg_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn31_apg *apg31 = kzalloc(sizeof(struct dcn31_apg), GFP_KERNEL); - - if (!apg31) - return NULL; - - apg31_construct(apg31, ctx, inst, - &apg_regs[inst], - &apg_shift, - &apg_mask); - - return &apg31->base; -} - -static struct stream_encoder *dcn314_stream_encoder_create( - enum engine_id eng_id, - struct dc_context *ctx) -{ - struct dcn10_stream_encoder *enc1; - struct vpg *vpg; - struct afmt *afmt; - int vpg_inst; - int afmt_inst; - - /* Mapping of VPG, AFMT, DME register blocks to DIO block instance */ - if (eng_id < ENGINE_ID_DIGF) { - vpg_inst = eng_id; - afmt_inst = eng_id; - } else - return NULL; - - enc1 = kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL); - vpg = dcn31_vpg_create(ctx, vpg_inst); - afmt = dcn31_afmt_create(ctx, afmt_inst); - - if (!enc1 || !vpg || !afmt) { - kfree(enc1); - kfree(vpg); - kfree(afmt); - return NULL; - } - - dcn314_dio_stream_encoder_construct(enc1, ctx, ctx->dc_bios, - eng_id, vpg, afmt, - &stream_enc_regs[eng_id], - &se_shift, &se_mask); - - return &enc1->base; -} - -static struct hpo_dp_stream_encoder *dcn31_hpo_dp_stream_encoder_create( - enum engine_id eng_id, - struct dc_context *ctx) -{ - struct dcn31_hpo_dp_stream_encoder *hpo_dp_enc31; - struct vpg *vpg; - struct apg *apg; - uint32_t hpo_dp_inst; - uint32_t vpg_inst; - uint32_t apg_inst; - - ASSERT((eng_id >= ENGINE_ID_HPO_DP_0) && (eng_id <= ENGINE_ID_HPO_DP_3)); - hpo_dp_inst = eng_id - ENGINE_ID_HPO_DP_0; - - /* Mapping of VPG register blocks to HPO DP block instance: - * VPG[6] -> HPO_DP[0] - * VPG[7] -> HPO_DP[1] - * VPG[8] -> HPO_DP[2] - * VPG[9] -> HPO_DP[3] - */ - //Uses offset index 5-8, but actually maps to vpg_inst 6-9 - vpg_inst = hpo_dp_inst + 5; - - /* Mapping of APG register blocks to HPO DP block instance: - * APG[0] -> HPO_DP[0] - * APG[1] -> HPO_DP[1] - * APG[2] -> HPO_DP[2] - * APG[3] -> HPO_DP[3] - */ - apg_inst = hpo_dp_inst; - - /* allocate HPO stream encoder and create VPG sub-block */ - hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_stream_encoder), GFP_KERNEL); - vpg = dcn31_vpg_create(ctx, vpg_inst); - apg = dcn31_apg_create(ctx, apg_inst); - - if (!hpo_dp_enc31 || !vpg || !apg) { - kfree(hpo_dp_enc31); - kfree(vpg); - kfree(apg); - return NULL; - } - - dcn31_hpo_dp_stream_encoder_construct(hpo_dp_enc31, ctx, ctx->dc_bios, - hpo_dp_inst, eng_id, vpg, apg, - &hpo_dp_stream_enc_regs[hpo_dp_inst], - &hpo_dp_se_shift, &hpo_dp_se_mask); - - return &hpo_dp_enc31->base; -} - -static struct hpo_dp_link_encoder *dcn31_hpo_dp_link_encoder_create( - uint8_t inst, - struct dc_context *ctx) -{ - struct dcn31_hpo_dp_link_encoder *hpo_dp_enc31; - - /* allocate HPO link encoder */ - hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_link_encoder), GFP_KERNEL); - - hpo_dp_link_encoder31_construct(hpo_dp_enc31, ctx, inst, - &hpo_dp_link_enc_regs[inst], - &hpo_dp_le_shift, &hpo_dp_le_mask); - - return &hpo_dp_enc31->base; -} - -static struct dce_hwseq *dcn314_hwseq_create( - struct dc_context *ctx) -{ - struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); - - if (hws) { - hws->ctx = ctx; - hws->regs = &hwseq_reg; - hws->shifts = &hwseq_shift; - hws->masks = &hwseq_mask; - } - return hws; -} -static const struct resource_create_funcs res_create_funcs = { - .read_dce_straps = read_dce_straps, - .create_audio = dcn31_create_audio, - .create_stream_encoder = dcn314_stream_encoder_create, - .create_hpo_dp_stream_encoder = dcn31_hpo_dp_stream_encoder_create, - .create_hpo_dp_link_encoder = dcn31_hpo_dp_link_encoder_create, - .create_hwseq = dcn314_hwseq_create, -}; - -static void dcn314_resource_destruct(struct dcn314_resource_pool *pool) -{ - unsigned int i; - - for (i = 0; i < pool->base.stream_enc_count; i++) { - if (pool->base.stream_enc[i] != NULL) { - if (pool->base.stream_enc[i]->vpg != NULL) { - kfree(DCN30_VPG_FROM_VPG(pool->base.stream_enc[i]->vpg)); - pool->base.stream_enc[i]->vpg = NULL; - } - if (pool->base.stream_enc[i]->afmt != NULL) { - kfree(DCN30_AFMT_FROM_AFMT(pool->base.stream_enc[i]->afmt)); - pool->base.stream_enc[i]->afmt = NULL; - } - kfree(DCN10STRENC_FROM_STRENC(pool->base.stream_enc[i])); - pool->base.stream_enc[i] = NULL; - } - } - - for (i = 0; i < pool->base.hpo_dp_stream_enc_count; i++) { - if (pool->base.hpo_dp_stream_enc[i] != NULL) { - if (pool->base.hpo_dp_stream_enc[i]->vpg != NULL) { - kfree(DCN30_VPG_FROM_VPG(pool->base.hpo_dp_stream_enc[i]->vpg)); - pool->base.hpo_dp_stream_enc[i]->vpg = NULL; - } - if (pool->base.hpo_dp_stream_enc[i]->apg != NULL) { - kfree(DCN31_APG_FROM_APG(pool->base.hpo_dp_stream_enc[i]->apg)); - pool->base.hpo_dp_stream_enc[i]->apg = NULL; - } - kfree(DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(pool->base.hpo_dp_stream_enc[i])); - pool->base.hpo_dp_stream_enc[i] = NULL; - } - } - - for (i = 0; i < pool->base.hpo_dp_link_enc_count; i++) { - if (pool->base.hpo_dp_link_enc[i] != NULL) { - kfree(DCN3_1_HPO_DP_LINK_ENC_FROM_HPO_LINK_ENC(pool->base.hpo_dp_link_enc[i])); - pool->base.hpo_dp_link_enc[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_dsc; i++) { - if (pool->base.dscs[i] != NULL) - dcn20_dsc_destroy(&pool->base.dscs[i]); - } - - if (pool->base.mpc != NULL) { - kfree(TO_DCN20_MPC(pool->base.mpc)); - pool->base.mpc = NULL; - } - if (pool->base.hubbub != NULL) { - kfree(pool->base.hubbub); - pool->base.hubbub = NULL; - } - for (i = 0; i < pool->base.pipe_count; i++) { - if (pool->base.dpps[i] != NULL) - dcn31_dpp_destroy(&pool->base.dpps[i]); - - if (pool->base.ipps[i] != NULL) - pool->base.ipps[i]->funcs->ipp_destroy(&pool->base.ipps[i]); - - if (pool->base.hubps[i] != NULL) { - kfree(TO_DCN20_HUBP(pool->base.hubps[i])); - pool->base.hubps[i] = NULL; - } - - if (pool->base.irqs != NULL) - dal_irq_service_destroy(&pool->base.irqs); - } - - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - if (pool->base.engines[i] != NULL) - dce110_engine_destroy(&pool->base.engines[i]); - if (pool->base.hw_i2cs[i] != NULL) { - kfree(pool->base.hw_i2cs[i]); - pool->base.hw_i2cs[i] = NULL; - } - if (pool->base.sw_i2cs[i] != NULL) { - kfree(pool->base.sw_i2cs[i]); - pool->base.sw_i2cs[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_opp; i++) { - if (pool->base.opps[i] != NULL) - pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]); - } - - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - if (pool->base.timing_generators[i] != NULL) { - kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i])); - pool->base.timing_generators[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_dwb; i++) { - if (pool->base.dwbc[i] != NULL) { - kfree(TO_DCN30_DWBC(pool->base.dwbc[i])); - pool->base.dwbc[i] = NULL; - } - if (pool->base.mcif_wb[i] != NULL) { - kfree(TO_DCN30_MMHUBBUB(pool->base.mcif_wb[i])); - pool->base.mcif_wb[i] = NULL; - } - } - - for (i = 0; i < pool->base.audio_count; i++) { - if (pool->base.audios[i]) - dce_aud_destroy(&pool->base.audios[i]); - } - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] != NULL) { - dcn20_clock_source_destroy(&pool->base.clock_sources[i]); - pool->base.clock_sources[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_mpc_3dlut; i++) { - if (pool->base.mpc_lut[i] != NULL) { - dc_3dlut_func_release(pool->base.mpc_lut[i]); - pool->base.mpc_lut[i] = NULL; - } - if (pool->base.mpc_shaper[i] != NULL) { - dc_transfer_func_release(pool->base.mpc_shaper[i]); - pool->base.mpc_shaper[i] = NULL; - } - } - - if (pool->base.dp_clock_source != NULL) { - dcn20_clock_source_destroy(&pool->base.dp_clock_source); - pool->base.dp_clock_source = NULL; - } - - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - if (pool->base.multiple_abms[i] != NULL) - dce_abm_destroy(&pool->base.multiple_abms[i]); - } - - if (pool->base.psr != NULL) - dmub_psr_destroy(&pool->base.psr); - - if (pool->base.replay != NULL) - dmub_replay_destroy(&pool->base.replay); - - if (pool->base.dccg != NULL) - dcn_dccg_destroy(&pool->base.dccg); -} - -static struct hubp *dcn31_hubp_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn20_hubp *hubp2 = - kzalloc(sizeof(struct dcn20_hubp), GFP_KERNEL); - - if (!hubp2) - return NULL; - - if (hubp31_construct(hubp2, ctx, inst, - &hubp_regs[inst], &hubp_shift, &hubp_mask)) - return &hubp2->base; - - BREAK_TO_DEBUGGER(); - kfree(hubp2); - return NULL; -} - -static bool dcn31_dwbc_create(struct dc_context *ctx, struct resource_pool *pool) -{ - int i; - uint32_t pipe_count = pool->res_cap->num_dwb; - - for (i = 0; i < pipe_count; i++) { - struct dcn30_dwbc *dwbc30 = kzalloc(sizeof(struct dcn30_dwbc), - GFP_KERNEL); - - if (!dwbc30) { - dm_error("DC: failed to create dwbc30!\n"); - return false; - } - - dcn30_dwbc_construct(dwbc30, ctx, - &dwbc30_regs[i], - &dwbc30_shift, - &dwbc30_mask, - i); - - pool->dwbc[i] = &dwbc30->base; - } - return true; -} - -static bool dcn31_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool) -{ - int i; - uint32_t pipe_count = pool->res_cap->num_dwb; - - for (i = 0; i < pipe_count; i++) { - struct dcn30_mmhubbub *mcif_wb30 = kzalloc(sizeof(struct dcn30_mmhubbub), - GFP_KERNEL); - - if (!mcif_wb30) { - dm_error("DC: failed to create mcif_wb30!\n"); - return false; - } - - dcn30_mmhubbub_construct(mcif_wb30, ctx, - &mcif_wb30_regs[i], - &mcif_wb30_shift, - &mcif_wb30_mask, - i); - - pool->mcif_wb[i] = &mcif_wb30->base; - } - return true; -} - -static struct display_stream_compressor *dcn314_dsc_create( - struct dc_context *ctx, uint32_t inst) -{ - struct dcn20_dsc *dsc = - kzalloc(sizeof(struct dcn20_dsc), GFP_KERNEL); - - if (!dsc) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dsc2_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask); - return &dsc->base; -} - -static void dcn314_destroy_resource_pool(struct resource_pool **pool) -{ - struct dcn314_resource_pool *dcn314_pool = TO_DCN314_RES_POOL(*pool); - - dcn314_resource_destruct(dcn314_pool); - kfree(dcn314_pool); - *pool = NULL; -} - -static struct clock_source *dcn31_clock_source_create( - struct dc_context *ctx, - struct dc_bios *bios, - enum clock_source_id id, - const struct dce110_clk_src_regs *regs, - bool dp_clk_src) -{ - struct dce110_clk_src *clk_src = - kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); - - if (!clk_src) - return NULL; - - if (dcn31_clk_src_construct(clk_src, ctx, bios, id, - regs, &cs_shift, &cs_mask)) { - clk_src->base.dp_clk_src = dp_clk_src; - return &clk_src->base; - } - - BREAK_TO_DEBUGGER(); - kfree(clk_src); - return NULL; -} - -static int dcn314_populate_dml_pipes_from_context( - struct dc *dc, struct dc_state *context, - display_e2e_pipe_params_st *pipes, - bool fast_validate) -{ - int pipe_cnt; - - DC_FP_START(); - pipe_cnt = dcn314_populate_dml_pipes_from_context_fpu(dc, context, pipes, fast_validate); - DC_FP_END(); - - return pipe_cnt; -} - -static struct dc_cap_funcs cap_funcs = { - .get_dcc_compression_cap = dcn20_get_dcc_compression_cap -}; - -static void dcn314_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) -{ - DC_FP_START(); - dcn314_update_bw_bounding_box_fpu(dc, bw_params); - DC_FP_END(); -} - -static void dcn314_get_panel_config_defaults(struct dc_panel_config *panel_config) -{ - *panel_config = panel_config_defaults; -} - -static bool filter_modes_for_single_channel_workaround(struct dc *dc, - struct dc_state *context) -{ - // Filter 2K@240Hz+8K@24fps above combination timing if memory only has single dimm LPDDR - if (dc->clk_mgr->bw_params->vram_type == 34 && - dc->clk_mgr->bw_params->num_channels < 2 && - context->stream_count > 1) { - int total_phy_pix_clk = 0; - - for (int i = 0; i < context->stream_count; i++) - if (context->res_ctx.pipe_ctx[i].stream) - total_phy_pix_clk += context->res_ctx.pipe_ctx[i].stream->phy_pix_clk; - - if (total_phy_pix_clk >= (1148928+826260)) //2K@240Hz+8K@24fps - return true; - } - return false; -} - -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(); - - if (filter_modes_for_single_channel_workaround(dc, context)) - goto validate_fail; - - 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; - } - if (dc->res_pool->funcs->calculate_wm_and_dlg) - 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, - .link_enc_create_minimal = dcn31_link_enc_create_minimal, - .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 = 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, - .acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer, - .release_pipe = dcn20_release_pipe, - .add_stream_to_ctx = dcn30_add_stream_to_ctx, - .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource, - .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, - .populate_dml_writeback_from_context = dcn30_populate_dml_writeback_from_context, - .set_mcif_arb_params = dcn30_set_mcif_arb_params, - .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 = dcn314_update_bw_bounding_box, - .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, - .get_panel_config_defaults = dcn314_get_panel_config_defaults, - .get_preferred_eng_id_dpia = dcn314_get_preferred_eng_id_dpia, -}; - -static struct clock_source *dcn30_clock_source_create( - struct dc_context *ctx, - struct dc_bios *bios, - enum clock_source_id id, - const struct dce110_clk_src_regs *regs, - bool dp_clk_src) -{ - struct dce110_clk_src *clk_src = - kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); - - if (!clk_src) - return NULL; - - if (dcn31_clk_src_construct(clk_src, ctx, bios, id, - regs, &cs_shift, &cs_mask)) { - clk_src->base.dp_clk_src = dp_clk_src; - return &clk_src->base; - } - - BREAK_TO_DEBUGGER(); - kfree(clk_src); - return NULL; -} - -static bool dcn314_resource_construct( - uint8_t num_virtual_links, - struct dc *dc, - struct dcn314_resource_pool *pool) -{ - int i; - struct dc_context *ctx = dc->ctx; - struct irq_service_init_data init_data; - - ctx->dc_bios->regs = &bios_regs; - - pool->base.res_cap = &res_cap_dcn314; - pool->base.funcs = &dcn314_res_pool_funcs; - - /************************************************* - * Resource + asic cap harcoding * - *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; - pool->base.pipe_count = pool->base.res_cap->num_timing_generator; - pool->base.mpcc_count = pool->base.res_cap->num_timing_generator; - dc->caps.max_downscale_ratio = 400; - dc->caps.i2c_speed_in_khz = 100; - dc->caps.i2c_speed_in_khz_hdcp = 100; - dc->caps.max_cursor_size = 256; - dc->caps.min_horizontal_blanking_period = 80; - dc->caps.dmdata_alloc_size = 2048; - dc->caps.max_slave_planes = 2; - dc->caps.max_slave_yuv_planes = 2; - dc->caps.max_slave_rgb_planes = 2; - dc->caps.post_blend_color_processing = true; - dc->caps.force_dp_tps4_for_cp2520 = true; - if (dc->config.forceHBR2CP2520) - dc->caps.force_dp_tps4_for_cp2520 = false; - dc->caps.dp_hpo = true; - dc->caps.dp_hdmi21_pcon_support = true; - dc->caps.edp_dsc_support = true; - dc->caps.extended_aux_timeout_support = true; - dc->caps.dmcub_support = true; - dc->caps.is_apu = true; - dc->caps.seamless_odm = true; - - dc->caps.zstate_support = true; - - /* Color pipeline capabilities */ - dc->caps.color.dpp.dcn_arch = 1; - dc->caps.color.dpp.input_lut_shared = 0; - dc->caps.color.dpp.icsc = 1; - dc->caps.color.dpp.dgam_ram = 0; // must use gamma_corr - dc->caps.color.dpp.dgam_rom_caps.srgb = 1; - dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1; - dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 1; - dc->caps.color.dpp.dgam_rom_caps.pq = 1; - dc->caps.color.dpp.dgam_rom_caps.hlg = 1; - dc->caps.color.dpp.post_csc = 1; - dc->caps.color.dpp.gamma_corr = 1; - dc->caps.color.dpp.dgam_rom_for_yuv = 0; - - dc->caps.color.dpp.hw_3d_lut = 1; - dc->caps.color.dpp.ogam_ram = 1; - // no OGAM ROM on DCN301 - dc->caps.color.dpp.ogam_rom_caps.srgb = 0; - dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0; - dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0; - dc->caps.color.dpp.ogam_rom_caps.pq = 0; - dc->caps.color.dpp.ogam_rom_caps.hlg = 0; - dc->caps.color.dpp.ocsc = 0; - - dc->caps.color.mpc.gamut_remap = 1; - dc->caps.color.mpc.num_3dluts = pool->base.res_cap->num_mpc_3dlut; //2 - dc->caps.color.mpc.ogam_ram = 1; - dc->caps.color.mpc.ogam_rom_caps.srgb = 0; - dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0; - dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0; - dc->caps.color.mpc.ogam_rom_caps.pq = 0; - dc->caps.color.mpc.ogam_rom_caps.hlg = 0; - dc->caps.color.mpc.ocsc = 1; - - dc->caps.max_disp_clock_khz_at_vmin = 650000; - - /* Use pipe context based otg sync logic */ - dc->config.use_pipe_ctx_sync_logic = true; - - /* read VBIOS LTTPR caps */ - { - if (ctx->dc_bios->funcs->get_lttpr_caps) { - enum bp_result bp_query_result; - uint8_t is_vbios_lttpr_enable = 0; - - bp_query_result = ctx->dc_bios->funcs->get_lttpr_caps(ctx->dc_bios, &is_vbios_lttpr_enable); - dc->caps.vbios_lttpr_enable = (bp_query_result == BP_RESULT_OK) && !!is_vbios_lttpr_enable; - } - - /* interop bit is implicit */ - { - dc->caps.vbios_lttpr_aware = true; - } - } - - if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) - dc->debug = debug_defaults_drv; - else - dc->debug = debug_defaults_diags; - - /* Disable pipe power gating */ - dc->debug.disable_dpp_power_gate = true; - dc->debug.disable_hubp_power_gate = true; - - /* Disable root clock optimization */ - dc->debug.root_clock_optimization.u32All = 0; - - // Init the vm_helper - if (dc->vm_helper) - vm_helper_init(dc->vm_helper, 16); - - /************************************************* - * Create resources * - *************************************************/ - - /* Clock Sources for Pixel Clock*/ - pool->base.clock_sources[DCN31_CLK_SRC_PLL0] = - dcn30_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL0, - &clk_src_regs[0], false); - pool->base.clock_sources[DCN31_CLK_SRC_PLL1] = - dcn30_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL1, - &clk_src_regs[1], false); - pool->base.clock_sources[DCN31_CLK_SRC_PLL2] = - dcn30_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL2, - &clk_src_regs[2], false); - pool->base.clock_sources[DCN31_CLK_SRC_PLL3] = - dcn30_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL3, - &clk_src_regs[3], false); - pool->base.clock_sources[DCN31_CLK_SRC_PLL4] = - dcn30_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL4, - &clk_src_regs[4], false); - - pool->base.clk_src_count = DCN30_CLK_SRC_TOTAL; - - /* todo: not reuse phy_pll registers */ - pool->base.dp_clock_source = - dcn31_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_ID_DP_DTO, - &clk_src_regs[0], true); - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] == NULL) { - dm_error("DC: failed to create clock sources!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - } - - pool->base.dccg = dccg314_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask); - if (pool->base.dccg == NULL) { - dm_error("DC: failed to create dccg!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - - init_data.ctx = dc->ctx; - pool->base.irqs = dal_irq_service_dcn314_create(&init_data); - if (!pool->base.irqs) - goto create_fail; - - /* HUBBUB */ - pool->base.hubbub = dcn31_hubbub_create(ctx); - if (pool->base.hubbub == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create hubbub!\n"); - goto create_fail; - } - - /* HUBPs, DPPs, OPPs and TGs */ - for (i = 0; i < pool->base.pipe_count; i++) { - pool->base.hubps[i] = dcn31_hubp_create(ctx, i); - if (pool->base.hubps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create hubps!\n"); - goto create_fail; - } - - pool->base.dpps[i] = dcn31_dpp_create(ctx, i); - if (pool->base.dpps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create dpps!\n"); - goto create_fail; - } - } - - for (i = 0; i < pool->base.res_cap->num_opp; i++) { - pool->base.opps[i] = dcn31_opp_create(ctx, i); - if (pool->base.opps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create output pixel processor!\n"); - goto create_fail; - } - } - - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - pool->base.timing_generators[i] = dcn31_timing_generator_create( - ctx, i); - if (pool->base.timing_generators[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create tg!\n"); - goto create_fail; - } - } - pool->base.timing_generator_count = i; - - /* PSR */ - pool->base.psr = dmub_psr_create(ctx); - if (pool->base.psr == NULL) { - dm_error("DC: failed to create psr obj!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - - /* Replay */ - pool->base.replay = dmub_replay_create(ctx); - if (pool->base.replay == NULL) { - dm_error("DC: failed to create replay obj!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - - /* ABM */ - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - pool->base.multiple_abms[i] = dmub_abm_create(ctx, - &abm_regs[i], - &abm_shift, - &abm_mask); - if (pool->base.multiple_abms[i] == NULL) { - dm_error("DC: failed to create abm for pipe %d!\n", i); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - } - - /* MPC and DSC */ - pool->base.mpc = dcn31_mpc_create(ctx, pool->base.mpcc_count, pool->base.res_cap->num_mpc_3dlut); - if (pool->base.mpc == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create mpc!\n"); - goto create_fail; - } - - for (i = 0; i < pool->base.res_cap->num_dsc; i++) { - pool->base.dscs[i] = dcn314_dsc_create(ctx, i); - if (pool->base.dscs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create display stream compressor %d!\n", i); - goto create_fail; - } - } - - /* DWB and MMHUBBUB */ - if (!dcn31_dwbc_create(ctx, &pool->base)) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create dwbc!\n"); - goto create_fail; - } - - if (!dcn31_mmhubbub_create(ctx, &pool->base)) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create mcif_wb!\n"); - goto create_fail; - } - - /* AUX and I2C */ - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - pool->base.engines[i] = dcn31_aux_engine_create(ctx, i); - if (pool->base.engines[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create aux engine!!\n"); - goto create_fail; - } - pool->base.hw_i2cs[i] = dcn31_i2c_hw_create(ctx, i); - if (pool->base.hw_i2cs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create hw i2c!!\n"); - goto create_fail; - } - pool->base.sw_i2cs[i] = NULL; - } - - /* DCN314 has 4 DPIA */ - pool->base.usb4_dpia_count = 4; - - /* Audio, Stream Encoders including HPO and virtual, MPC 3D LUTs */ - if (!resource_construct(num_virtual_links, dc, &pool->base, - &res_create_funcs)) - goto create_fail; - - /* HW Sequencer and Plane caps */ - dcn314_hw_sequencer_construct(dc); - - dc->caps.max_planes = pool->base.pipe_count; - - for (i = 0; i < dc->caps.max_planes; ++i) - dc->caps.planes[i] = plane_cap; - - dc->cap_funcs = cap_funcs; - - dc->dcn_ip->max_num_dpp = dcn3_14_ip.max_num_dpp; - - return true; - -create_fail: - - dcn314_resource_destruct(pool); - - return false; -} - -struct resource_pool *dcn314_create_resource_pool( - const struct dc_init_data *init_data, - struct dc *dc) -{ - struct dcn314_resource_pool *pool = - kzalloc(sizeof(struct dcn314_resource_pool), GFP_KERNEL); - - if (!pool) - return NULL; - - if (dcn314_resource_construct(init_data->num_virtual_links, dc, pool)) - return &pool->base; - - BREAK_TO_DEBUGGER(); - kfree(pool); - return NULL; -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.h b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.h deleted file mode 100644 index 49ffe71018dfb9..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.h +++ /dev/null @@ -1,50 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * 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 _DCN314_RESOURCE_H_ -#define _DCN314_RESOURCE_H_ - -#include "core_types.h" - -extern struct _vcs_dpi_ip_params_st dcn3_14_ip; -extern struct _vcs_dpi_soc_bounding_box_st dcn3_14_soc; - -#define TO_DCN314_RES_POOL(pool)\ - container_of(pool, struct dcn314_resource_pool, base) - -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); - -#endif /* _DCN314_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn315/Makefile b/drivers/gpu/drm/amd/display/dc/dcn315/Makefile deleted file mode 100644 index 59381d24800b39..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn315/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -# -# 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 -# -# Makefile for dcn315. - -DCN315 = dcn315_resource.o - -AMD_DAL_DCN315 = $(addprefix $(AMDDALPATH)/dc/dcn315/,$(DCN315)) - -AMD_DISPLAY_FILES += $(AMD_DAL_DCN315) diff --git a/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c b/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c deleted file mode 100644 index cb8024eee8e4d9..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c +++ /dev/null @@ -1,2151 +0,0 @@ -/* - * 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 "dm_services.h" -#include "dc.h" - -#include "dcn31/dcn31_init.h" - -#include "resource.h" -#include "include/irq_service_interface.h" -#include "dcn315_resource.h" - -#include "dcn20/dcn20_resource.h" -#include "dcn30/dcn30_resource.h" -#include "dcn31/dcn31_resource.h" - -#include "dcn10/dcn10_ipp.h" -#include "dcn30/dcn30_hubbub.h" -#include "dcn31/dcn31_hubbub.h" -#include "dcn30/dcn30_mpc.h" -#include "dcn31/dcn31_hubp.h" -#include "irq/dcn315/irq_service_dcn315.h" -#include "dcn30/dcn30_dpp.h" -#include "dcn31/dcn31_optc.h" -#include "dcn20/dcn20_hwseq.h" -#include "dcn30/dcn30_hwseq.h" -#include "dce110/dce110_hwseq.h" -#include "dcn30/dcn30_opp.h" -#include "dcn20/dcn20_dsc.h" -#include "dcn30/dcn30_vpg.h" -#include "dcn30/dcn30_afmt.h" -#include "dcn30/dcn30_dio_stream_encoder.h" -#include "dcn31/dcn31_hpo_dp_stream_encoder.h" -#include "dcn31/dcn31_hpo_dp_link_encoder.h" -#include "dcn31/dcn31_apg.h" -#include "dcn31/dcn31_dio_link_encoder.h" -#include "dcn31/dcn31_vpg.h" -#include "dcn31/dcn31_afmt.h" -#include "dce/dce_clock_source.h" -#include "dce/dce_audio.h" -#include "dce/dce_hwseq.h" -#include "clk_mgr.h" -#include "virtual/virtual_stream_encoder.h" -#include "dce110/dce110_resource.h" -#include "dml/display_mode_vba.h" -#include "dml/dcn31/dcn31_fpu.h" -#include "dcn31/dcn31_dccg.h" -#include "dcn10/dcn10_resource.h" -#include "dcn31/dcn31_panel_cntl.h" - -#include "dcn30/dcn30_dwb.h" -#include "dcn30/dcn30_mmhubbub.h" - -#include "dcn/dcn_3_1_5_offset.h" -#include "dcn/dcn_3_1_5_sh_mask.h" -#include "dpcs/dpcs_4_2_2_offset.h" -#include "dpcs/dpcs_4_2_2_sh_mask.h" - -#define NBIO_BASE__INST0_SEG0 0x00000000 -#define NBIO_BASE__INST0_SEG1 0x00000014 -#define NBIO_BASE__INST0_SEG2 0x00000D20 -#define NBIO_BASE__INST0_SEG3 0x00010400 -#define NBIO_BASE__INST0_SEG4 0x0241B000 -#define NBIO_BASE__INST0_SEG5 0x04040000 - -#define DPCS_BASE__INST0_SEG0 0x00000012 -#define DPCS_BASE__INST0_SEG1 0x000000C0 -#define DPCS_BASE__INST0_SEG2 0x000034C0 -#define DPCS_BASE__INST0_SEG3 0x00009000 -#define DPCS_BASE__INST0_SEG4 0x02403C00 -#define DPCS_BASE__INST0_SEG5 0 - -#define DCN_BASE__INST0_SEG0 0x00000012 -#define DCN_BASE__INST0_SEG1 0x000000C0 -#define DCN_BASE__INST0_SEG2 0x000034C0 -#define DCN_BASE__INST0_SEG3 0x00009000 -#define DCN_BASE__INST0_SEG4 0x02403C00 -#define DCN_BASE__INST0_SEG5 0 - -#define regBIF_BX_PF2_RSMU_INDEX 0x0000 -#define regBIF_BX_PF2_RSMU_INDEX_BASE_IDX 1 -#define regBIF_BX_PF2_RSMU_DATA 0x0001 -#define regBIF_BX_PF2_RSMU_DATA_BASE_IDX 1 -#define regBIF_BX2_BIOS_SCRATCH_6 0x003e -#define regBIF_BX2_BIOS_SCRATCH_6_BASE_IDX 1 -#define BIF_BX2_BIOS_SCRATCH_6__BIOS_SCRATCH_6__SHIFT 0x0 -#define BIF_BX2_BIOS_SCRATCH_6__BIOS_SCRATCH_6_MASK 0xFFFFFFFFL -#define regBIF_BX2_BIOS_SCRATCH_2 0x003a -#define regBIF_BX2_BIOS_SCRATCH_2_BASE_IDX 1 -#define BIF_BX2_BIOS_SCRATCH_2__BIOS_SCRATCH_2__SHIFT 0x0 -#define BIF_BX2_BIOS_SCRATCH_2__BIOS_SCRATCH_2_MASK 0xFFFFFFFFL -#define regBIF_BX2_BIOS_SCRATCH_3 0x003b -#define regBIF_BX2_BIOS_SCRATCH_3_BASE_IDX 1 -#define BIF_BX2_BIOS_SCRATCH_3__BIOS_SCRATCH_3__SHIFT 0x0 -#define BIF_BX2_BIOS_SCRATCH_3__BIOS_SCRATCH_3_MASK 0xFFFFFFFFL - -#define regDCHUBBUB_DEBUG_CTRL_0 0x04d6 -#define regDCHUBBUB_DEBUG_CTRL_0_BASE_IDX 2 -#define DCHUBBUB_DEBUG_CTRL_0__DET_DEPTH__SHIFT 0x10 -#define DCHUBBUB_DEBUG_CTRL_0__DET_DEPTH_MASK 0x01FF0000L - -#include "reg_helper.h" -#include "dce/dmub_abm.h" -#include "dce/dmub_psr.h" -#include "dce/dce_aux.h" -#include "dce/dce_i2c.h" - -#include "dml/dcn30/display_mode_vba_30.h" -#include "vm_helper.h" -#include "dcn20/dcn20_vmid.h" - -#include "link_enc_cfg.h" - -#define DCN3_15_MAX_DET_SIZE 384 -#define DCN3_15_CRB_SEGMENT_SIZE_KB 64 -#define DCN3_15_MAX_DET_SEGS (DCN3_15_MAX_DET_SIZE / DCN3_15_CRB_SEGMENT_SIZE_KB) -/* Minimum 3 extra segments need to be in compbuf and claimable to guarantee seamless mpo transitions */ -#define MIN_RESERVED_DET_SEGS 3 - -enum dcn31_clk_src_array_id { - DCN31_CLK_SRC_PLL0, - DCN31_CLK_SRC_PLL1, - DCN31_CLK_SRC_PLL2, - DCN31_CLK_SRC_PLL3, - DCN31_CLK_SRC_PLL4, - DCN30_CLK_SRC_TOTAL -}; - -/* begin ********************* - * macros to expend register list macro defined in HW object header file - */ - -/* DCN */ -#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg - -#define BASE(seg) BASE_INNER(seg) - -#define SR(reg_name)\ - .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ - reg ## reg_name - -#define SRI(reg_name, block, id)\ - .reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRI2(reg_name, block, id)\ - .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ - reg ## reg_name - -#define SRIR(var_name, reg_name, block, id)\ - .var_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRII(reg_name, block, id)\ - .reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRII_MPC_RMU(reg_name, block, id)\ - .RMU##_##reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRII_DWB(reg_name, temp_name, block, id)\ - .reg_name[id] = BASE(reg ## block ## id ## _ ## temp_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## temp_name - -#define SF_DWB2(reg_name, block, id, field_name, post_fix) \ - .field_name = reg_name ## __ ## field_name ## post_fix - -#define DCCG_SRII(reg_name, block, id)\ - .block ## _ ## reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define VUPDATE_SRII(reg_name, block, id)\ - .reg_name[id] = BASE(reg ## reg_name ## _ ## block ## id ## _BASE_IDX) + \ - reg ## reg_name ## _ ## block ## id - -/* NBIO */ -#define NBIO_BASE_INNER(seg) \ - NBIO_BASE__INST0_SEG ## seg - -#define NBIO_BASE(seg) \ - NBIO_BASE_INNER(seg) - -#define NBIO_SR(reg_name)\ - .reg_name = NBIO_BASE(regBIF_BX2_ ## reg_name ## _BASE_IDX) + \ - regBIF_BX2_ ## reg_name - -static const struct bios_registers bios_regs = { - NBIO_SR(BIOS_SCRATCH_3), - NBIO_SR(BIOS_SCRATCH_6) -}; - -#define clk_src_regs(index, pllid)\ -[index] = {\ - CS_COMMON_REG_LIST_DCN3_0(index, pllid),\ -} - -static const struct dce110_clk_src_regs clk_src_regs[] = { - clk_src_regs(0, A), - clk_src_regs(1, B), - clk_src_regs(2, C), - clk_src_regs(3, D), - clk_src_regs(4, E) -}; - -static const struct dce110_clk_src_shift cs_shift = { - CS_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) -}; - -static const struct dce110_clk_src_mask cs_mask = { - CS_COMMON_MASK_SH_LIST_DCN2_0(_MASK) -}; - -#define abm_regs(id)\ -[id] = {\ - ABM_DCN302_REG_LIST(id)\ -} - -static const struct dce_abm_registers abm_regs[] = { - abm_regs(0), - abm_regs(1), - abm_regs(2), - abm_regs(3), -}; - -static const struct dce_abm_shift abm_shift = { - ABM_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dce_abm_mask abm_mask = { - ABM_MASK_SH_LIST_DCN30(_MASK) -}; - -#define audio_regs(id)\ -[id] = {\ - AUD_COMMON_REG_LIST(id)\ -} - -static const struct dce_audio_registers audio_regs[] = { - audio_regs(0), - audio_regs(1), - audio_regs(2), - audio_regs(3), - audio_regs(4), - audio_regs(5), - audio_regs(6) -}; - -#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ - SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ - SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ - AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) - -static const struct dce_audio_shift audio_shift = { - DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_audio_mask audio_mask = { - DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) -}; - -#define vpg_regs(id)\ -[id] = {\ - VPG_DCN31_REG_LIST(id)\ -} - -static const struct dcn31_vpg_registers vpg_regs[] = { - vpg_regs(0), - vpg_regs(1), - vpg_regs(2), - vpg_regs(3), - vpg_regs(4), - vpg_regs(5), - vpg_regs(6), - vpg_regs(7), - vpg_regs(8), - vpg_regs(9), -}; - -static const struct dcn31_vpg_shift vpg_shift = { - DCN31_VPG_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn31_vpg_mask vpg_mask = { - DCN31_VPG_MASK_SH_LIST(_MASK) -}; - -#define afmt_regs(id)\ -[id] = {\ - AFMT_DCN31_REG_LIST(id)\ -} - -static const struct dcn31_afmt_registers afmt_regs[] = { - afmt_regs(0), - afmt_regs(1), - afmt_regs(2), - afmt_regs(3), - afmt_regs(4), - afmt_regs(5) -}; - -static const struct dcn31_afmt_shift afmt_shift = { - DCN31_AFMT_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn31_afmt_mask afmt_mask = { - DCN31_AFMT_MASK_SH_LIST(_MASK) -}; - -#define apg_regs(id)\ -[id] = {\ - APG_DCN31_REG_LIST(id)\ -} - -static const struct dcn31_apg_registers apg_regs[] = { - apg_regs(0), - apg_regs(1), - apg_regs(2), - apg_regs(3) -}; - -static const struct dcn31_apg_shift apg_shift = { - DCN31_APG_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn31_apg_mask apg_mask = { - DCN31_APG_MASK_SH_LIST(_MASK) -}; - -#define stream_enc_regs(id)\ -[id] = {\ - SE_DCN3_REG_LIST(id)\ -} - -static const struct dcn10_stream_enc_registers stream_enc_regs[] = { - stream_enc_regs(0), - stream_enc_regs(1), - stream_enc_regs(2), - stream_enc_regs(3), - stream_enc_regs(4) -}; - -static const struct dcn10_stream_encoder_shift se_shift = { - SE_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn10_stream_encoder_mask se_mask = { - SE_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - - -#define aux_regs(id)\ -[id] = {\ - DCN2_AUX_REG_LIST(id)\ -} - -static const struct dcn10_link_enc_aux_registers link_enc_aux_regs[] = { - aux_regs(0), - aux_regs(1), - aux_regs(2), - aux_regs(3), - aux_regs(4) -}; - -#define hpd_regs(id)\ -[id] = {\ - HPD_REG_LIST(id)\ -} - -static const struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[] = { - hpd_regs(0), - hpd_regs(1), - hpd_regs(2), - hpd_regs(3), - hpd_regs(4) -}; - -#define link_regs(id, phyid)\ -[id] = {\ - LE_DCN31_REG_LIST(id), \ - UNIPHY_DCN2_REG_LIST(phyid), \ - DPCS_DCN31_REG_LIST(id), \ -} - -static const struct dce110_aux_registers_shift aux_shift = { - DCN_AUX_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce110_aux_registers_mask aux_mask = { - DCN_AUX_MASK_SH_LIST(_MASK) -}; - -static const struct dcn10_link_enc_registers link_enc_regs[] = { - link_regs(0, A), - link_regs(1, B), - link_regs(2, C), - link_regs(3, D), - link_regs(4, E) -}; - -static const struct dcn10_link_enc_shift le_shift = { - LINK_ENCODER_MASK_SH_LIST_DCN31(__SHIFT), \ - DPCS_DCN31_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn10_link_enc_mask le_mask = { - LINK_ENCODER_MASK_SH_LIST_DCN31(_MASK), \ - DPCS_DCN31_MASK_SH_LIST(_MASK) -}; - -#define hpo_dp_stream_encoder_reg_list(id)\ -[id] = {\ - DCN3_1_HPO_DP_STREAM_ENC_REG_LIST(id)\ -} - -static const struct dcn31_hpo_dp_stream_encoder_registers hpo_dp_stream_enc_regs[] = { - hpo_dp_stream_encoder_reg_list(0), - hpo_dp_stream_encoder_reg_list(1), - hpo_dp_stream_encoder_reg_list(2), - hpo_dp_stream_encoder_reg_list(3), -}; - -static const struct dcn31_hpo_dp_stream_encoder_shift hpo_dp_se_shift = { - DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn31_hpo_dp_stream_encoder_mask hpo_dp_se_mask = { - DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(_MASK) -}; - - -#define hpo_dp_link_encoder_reg_list(id)\ -[id] = {\ - DCN3_1_HPO_DP_LINK_ENC_REG_LIST(id),\ - DCN3_1_RDPCSTX_REG_LIST(0),\ - DCN3_1_RDPCSTX_REG_LIST(1),\ - DCN3_1_RDPCSTX_REG_LIST(2),\ - DCN3_1_RDPCSTX_REG_LIST(3),\ - DCN3_1_RDPCSTX_REG_LIST(4)\ -} - -static const struct dcn31_hpo_dp_link_encoder_registers hpo_dp_link_enc_regs[] = { - hpo_dp_link_encoder_reg_list(0), - hpo_dp_link_encoder_reg_list(1), -}; - -static const struct dcn31_hpo_dp_link_encoder_shift hpo_dp_le_shift = { - DCN3_1_HPO_DP_LINK_ENC_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn31_hpo_dp_link_encoder_mask hpo_dp_le_mask = { - DCN3_1_HPO_DP_LINK_ENC_MASK_SH_LIST(_MASK) -}; - -#define dpp_regs(id)\ -[id] = {\ - DPP_REG_LIST_DCN30(id),\ -} - -static const struct dcn3_dpp_registers dpp_regs[] = { - dpp_regs(0), - dpp_regs(1), - dpp_regs(2), - dpp_regs(3) -}; - -static const struct dcn3_dpp_shift tf_shift = { - DPP_REG_LIST_SH_MASK_DCN30(__SHIFT) -}; - -static const struct dcn3_dpp_mask tf_mask = { - DPP_REG_LIST_SH_MASK_DCN30(_MASK) -}; - -#define opp_regs(id)\ -[id] = {\ - OPP_REG_LIST_DCN30(id),\ -} - -static const struct dcn20_opp_registers opp_regs[] = { - opp_regs(0), - opp_regs(1), - opp_regs(2), - opp_regs(3) -}; - -static const struct dcn20_opp_shift opp_shift = { - OPP_MASK_SH_LIST_DCN20(__SHIFT) -}; - -static const struct dcn20_opp_mask opp_mask = { - OPP_MASK_SH_LIST_DCN20(_MASK) -}; - -#define aux_engine_regs(id)\ -[id] = {\ - AUX_COMMON_REG_LIST0(id), \ - .AUXN_IMPCAL = 0, \ - .AUXP_IMPCAL = 0, \ - .AUX_RESET_MASK = DP_AUX0_AUX_CONTROL__AUX_RESET_MASK, \ -} - -static const struct dce110_aux_registers aux_engine_regs[] = { - aux_engine_regs(0), - aux_engine_regs(1), - aux_engine_regs(2), - aux_engine_regs(3), - aux_engine_regs(4) -}; - -#define dwbc_regs_dcn3(id)\ -[id] = {\ - DWBC_COMMON_REG_LIST_DCN30(id),\ -} - -static const struct dcn30_dwbc_registers dwbc30_regs[] = { - dwbc_regs_dcn3(0), -}; - -static const struct dcn30_dwbc_shift dwbc30_shift = { - DWBC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn30_dwbc_mask dwbc30_mask = { - DWBC_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -#define mcif_wb_regs_dcn3(id)\ -[id] = {\ - MCIF_WB_COMMON_REG_LIST_DCN30(id),\ -} - -static const struct dcn30_mmhubbub_registers mcif_wb30_regs[] = { - mcif_wb_regs_dcn3(0) -}; - -static const struct dcn30_mmhubbub_shift mcif_wb30_shift = { - MCIF_WB_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn30_mmhubbub_mask mcif_wb30_mask = { - MCIF_WB_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -#define dsc_regsDCN20(id)\ -[id] = {\ - DSC_REG_LIST_DCN20(id)\ -} - -static const struct dcn20_dsc_registers dsc_regs[] = { - dsc_regsDCN20(0), - dsc_regsDCN20(1), - dsc_regsDCN20(2) -}; - -static const struct dcn20_dsc_shift dsc_shift = { - DSC_REG_LIST_SH_MASK_DCN20(__SHIFT) -}; - -static const struct dcn20_dsc_mask dsc_mask = { - DSC_REG_LIST_SH_MASK_DCN20(_MASK) -}; - -static const struct dcn30_mpc_registers mpc_regs = { - MPC_REG_LIST_DCN3_0(0), - MPC_REG_LIST_DCN3_0(1), - MPC_REG_LIST_DCN3_0(2), - MPC_REG_LIST_DCN3_0(3), - MPC_OUT_MUX_REG_LIST_DCN3_0(0), - MPC_OUT_MUX_REG_LIST_DCN3_0(1), - MPC_OUT_MUX_REG_LIST_DCN3_0(2), - MPC_OUT_MUX_REG_LIST_DCN3_0(3), - MPC_DWB_MUX_REG_LIST_DCN3_0(0), -}; - -static const struct dcn30_mpc_shift mpc_shift = { - MPC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn30_mpc_mask mpc_mask = { - MPC_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -#define optc_regs(id)\ -[id] = {OPTC_COMMON_REG_LIST_DCN3_1(id)} - -static const struct dcn_optc_registers optc_regs[] = { - optc_regs(0), - optc_regs(1), - optc_regs(2), - optc_regs(3) -}; - -static const struct dcn_optc_shift optc_shift = { - OPTC_COMMON_MASK_SH_LIST_DCN3_1(__SHIFT) -}; - -static const struct dcn_optc_mask optc_mask = { - OPTC_COMMON_MASK_SH_LIST_DCN3_1(_MASK) -}; - -#define hubp_regs(id)\ -[id] = {\ - HUBP_REG_LIST_DCN30(id)\ -} - -static const struct dcn_hubp2_registers hubp_regs[] = { - hubp_regs(0), - hubp_regs(1), - hubp_regs(2), - hubp_regs(3) -}; - - -static const struct dcn_hubp2_shift hubp_shift = { - HUBP_MASK_SH_LIST_DCN31(__SHIFT) -}; - -static const struct dcn_hubp2_mask hubp_mask = { - HUBP_MASK_SH_LIST_DCN31(_MASK) -}; -static const struct dcn_hubbub_registers hubbub_reg = { - HUBBUB_REG_LIST_DCN31(0) -}; - -static const struct dcn_hubbub_shift hubbub_shift = { - HUBBUB_MASK_SH_LIST_DCN31(__SHIFT) -}; - -static const struct dcn_hubbub_mask hubbub_mask = { - HUBBUB_MASK_SH_LIST_DCN31(_MASK) -}; - -static const struct dccg_registers dccg_regs = { - DCCG_REG_LIST_DCN31() -}; - -static const struct dccg_shift dccg_shift = { - DCCG_MASK_SH_LIST_DCN31(__SHIFT) -}; - -static const struct dccg_mask dccg_mask = { - DCCG_MASK_SH_LIST_DCN31(_MASK) -}; - - -#define SRII2(reg_name_pre, reg_name_post, id)\ - .reg_name_pre ## _ ## reg_name_post[id] = BASE(reg ## reg_name_pre \ - ## id ## _ ## reg_name_post ## _BASE_IDX) + \ - reg ## reg_name_pre ## id ## _ ## reg_name_post - - -#define HWSEQ_DCN31_REG_LIST()\ - SR(DCHUBBUB_GLOBAL_TIMER_CNTL), \ - SR(DCHUBBUB_ARB_HOSTVM_CNTL), \ - SR(DIO_MEM_PWR_CTRL), \ - SR(ODM_MEM_PWR_CTRL3), \ - SR(DMU_MEM_PWR_CNTL), \ - SR(MMHUBBUB_MEM_PWR_CNTL), \ - SR(DCCG_GATE_DISABLE_CNTL), \ - SR(DCCG_GATE_DISABLE_CNTL2), \ - SR(DCFCLK_CNTL),\ - SR(DC_MEM_GLOBAL_PWR_REQ_CNTL), \ - SRII(PIXEL_RATE_CNTL, OTG, 0), \ - SRII(PIXEL_RATE_CNTL, OTG, 1),\ - SRII(PIXEL_RATE_CNTL, OTG, 2),\ - SRII(PIXEL_RATE_CNTL, OTG, 3),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 0),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 1),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 2),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 3),\ - SR(MICROSECOND_TIME_BASE_DIV), \ - SR(MILLISECOND_TIME_BASE_DIV), \ - SR(DISPCLK_FREQ_CHANGE_CNTL), \ - SR(RBBMIF_TIMEOUT_DIS), \ - SR(RBBMIF_TIMEOUT_DIS_2), \ - SR(DCHUBBUB_CRC_CTRL), \ - SR(DPP_TOP0_DPP_CRC_CTRL), \ - SR(DPP_TOP0_DPP_CRC_VAL_B_A), \ - SR(DPP_TOP0_DPP_CRC_VAL_R_G), \ - SR(MPC_CRC_CTRL), \ - SR(MPC_CRC_RESULT_GB), \ - SR(MPC_CRC_RESULT_C), \ - SR(MPC_CRC_RESULT_AR), \ - SR(DOMAIN0_PG_CONFIG), \ - SR(DOMAIN1_PG_CONFIG), \ - SR(DOMAIN2_PG_CONFIG), \ - SR(DOMAIN3_PG_CONFIG), \ - SR(DOMAIN16_PG_CONFIG), \ - SR(DOMAIN17_PG_CONFIG), \ - SR(DOMAIN18_PG_CONFIG), \ - SR(DOMAIN0_PG_STATUS), \ - SR(DOMAIN1_PG_STATUS), \ - SR(DOMAIN2_PG_STATUS), \ - SR(DOMAIN3_PG_STATUS), \ - SR(DOMAIN16_PG_STATUS), \ - SR(DOMAIN17_PG_STATUS), \ - SR(DOMAIN18_PG_STATUS), \ - SR(D1VGA_CONTROL), \ - SR(D2VGA_CONTROL), \ - SR(D3VGA_CONTROL), \ - SR(D4VGA_CONTROL), \ - SR(D5VGA_CONTROL), \ - SR(D6VGA_CONTROL), \ - SR(DC_IP_REQUEST_CNTL), \ - SR(AZALIA_AUDIO_DTO), \ - SR(AZALIA_CONTROLLER_CLOCK_GATING), \ - SR(HPO_TOP_HW_CONTROL) - -static const struct dce_hwseq_registers hwseq_reg = { - HWSEQ_DCN31_REG_LIST() -}; - -#define HWSEQ_DCN31_MASK_SH_LIST(mask_sh)\ - HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ - HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \ - HWS_SF(, DCHUBBUB_ARB_HOSTVM_CNTL, DISABLE_HOSTVM_FORCE_ALLOW_PSTATE, mask_sh), \ - HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN16_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN17_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN18_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \ - HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh), \ - HWS_SF(, HPO_TOP_CLOCK_CONTROL, HPO_HDMISTREAMCLK_G_GATE_DIS, mask_sh), \ - HWS_SF(, DMU_MEM_PWR_CNTL, DMCU_ERAM_MEM_PWR_FORCE, mask_sh), \ - HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_UNASSIGNED_PWR_MODE, mask_sh), \ - HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_VBLANK_PWR_MODE, mask_sh), \ - HWS_SF(, MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, mask_sh), \ - HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh), \ - HWS_SF(, HPO_TOP_HW_CONTROL, HPO_IO_EN, mask_sh) - -static const struct dce_hwseq_shift hwseq_shift = { - HWSEQ_DCN31_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_hwseq_mask hwseq_mask = { - HWSEQ_DCN31_MASK_SH_LIST(_MASK) -}; -#define vmid_regs(id)\ -[id] = {\ - DCN20_VMID_REG_LIST(id)\ -} - -static const struct dcn_vmid_registers vmid_regs[] = { - vmid_regs(0), - vmid_regs(1), - vmid_regs(2), - vmid_regs(3), - vmid_regs(4), - vmid_regs(5), - vmid_regs(6), - vmid_regs(7), - vmid_regs(8), - vmid_regs(9), - vmid_regs(10), - vmid_regs(11), - vmid_regs(12), - vmid_regs(13), - vmid_regs(14), - vmid_regs(15) -}; - -static const struct dcn20_vmid_shift vmid_shifts = { - DCN20_VMID_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn20_vmid_mask vmid_masks = { - DCN20_VMID_MASK_SH_LIST(_MASK) -}; - -static const struct resource_caps res_cap_dcn31 = { - .num_timing_generator = 4, - .num_opp = 4, - .num_video_plane = 4, - .num_audio = 5, - .num_stream_encoder = 5, - .num_dig_link_enc = 5, - .num_hpo_dp_stream_encoder = 4, - .num_hpo_dp_link_encoder = 2, - .num_pll = 5, - .num_dwb = 1, - .num_ddc = 5, - .num_vmid = 16, - .num_mpc_3dlut = 2, - .num_dsc = 3, -}; - -static const struct dc_plane_cap plane_cap = { - .type = DC_PLANE_TYPE_DCN_UNIVERSAL, - .per_pixel_alpha = true, - - .pixel_format_support = { - .argb8888 = true, - .nv12 = true, - .fp16 = true, - .p010 = true, - .ayuv = false, - }, - - .max_upscale_factor = { - .argb8888 = 16000, - .nv12 = 16000, - .fp16 = 16000 - }, - - // 6:1 downscaling ratio: 1000/6 = 166.666 - .max_downscale_factor = { - .argb8888 = 167, - .nv12 = 167, - .fp16 = 167 - }, - 64, - 64 -}; - -static const struct dc_debug_options debug_defaults_drv = { - .disable_z10 = true, /*hw not support it*/ - .disable_dmcu = true, - .force_abm_enable = false, - .timing_trace = false, - .clock_trace = true, - .disable_pplib_clock_request = false, - .pipe_split_policy = MPC_SPLIT_DYNAMIC, - .force_single_disp_pipe_split = false, - .disable_dcc = DCC_ENABLE, - .vsr_support = true, - .performance_trace = false, - .max_downscale_src_width = 4096,/*upto true 4k*/ - .disable_pplib_wm_range = false, - .scl_reset_length10 = true, - .sanity_checks = false, - .underflow_assert_delay_us = 0xFFFFFFFF, - .dwb_fi_phase = -1, // -1 = disable, - .dmub_command_table = true, - .pstate_enabled = true, - .use_max_lb = true, - .enable_mem_low_power = { - .bits = { - .vga = true, - .i2c = true, - .dmcu = false, // This is previously known to cause hang on S3 cycles if enabled - .dscl = true, - .cm = true, - .mpc = true, - .optc = true, - .vpg = true, - .afmt = true, - } - }, - .enable_legacy_fast_update = true, - .psr_power_use_phy_fsm = 0, - .using_dml2 = false, -}; - -static const struct dc_panel_config panel_config_defaults = { - .psr = { - .disable_psr = false, - .disallow_psrsu = false, - .disallow_replay = false, - }, - .ilr = { - .optimize_edp_link_rate = true, - }, -}; - -static void dcn31_dpp_destroy(struct dpp **dpp) -{ - kfree(TO_DCN20_DPP(*dpp)); - *dpp = NULL; -} - -static struct dpp *dcn31_dpp_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn3_dpp *dpp = - kzalloc(sizeof(struct dcn3_dpp), GFP_KERNEL); - - if (!dpp) - return NULL; - - if (dpp3_construct(dpp, ctx, inst, - &dpp_regs[inst], &tf_shift, &tf_mask)) - return &dpp->base; - - BREAK_TO_DEBUGGER(); - kfree(dpp); - return NULL; -} - -static struct output_pixel_processor *dcn31_opp_create( - struct dc_context *ctx, uint32_t inst) -{ - struct dcn20_opp *opp = - kzalloc(sizeof(struct dcn20_opp), GFP_KERNEL); - - if (!opp) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dcn20_opp_construct(opp, ctx, inst, - &opp_regs[inst], &opp_shift, &opp_mask); - return &opp->base; -} - -static struct dce_aux *dcn31_aux_engine_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct aux_engine_dce110 *aux_engine = - kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); - - if (!aux_engine) - return NULL; - - dce110_aux_engine_construct(aux_engine, ctx, inst, - SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, - &aux_engine_regs[inst], - &aux_mask, - &aux_shift, - ctx->dc->caps.extended_aux_timeout_support); - - return &aux_engine->base; -} -#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST_DCN30(id) } - -static const struct dce_i2c_registers i2c_hw_regs[] = { - i2c_inst_regs(1), - i2c_inst_regs(2), - i2c_inst_regs(3), - i2c_inst_regs(4), - i2c_inst_regs(5), -}; - -static const struct dce_i2c_shift i2c_shifts = { - I2C_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dce_i2c_mask i2c_masks = { - I2C_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -static struct dce_i2c_hw *dcn31_i2c_hw_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dce_i2c_hw *dce_i2c_hw = - kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); - - if (!dce_i2c_hw) - return NULL; - - dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst, - &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); - - return dce_i2c_hw; -} -static struct mpc *dcn31_mpc_create( - struct dc_context *ctx, - int num_mpcc, - int num_rmu) -{ - struct dcn30_mpc *mpc30 = kzalloc(sizeof(struct dcn30_mpc), - GFP_KERNEL); - - if (!mpc30) - return NULL; - - dcn30_mpc_construct(mpc30, ctx, - &mpc_regs, - &mpc_shift, - &mpc_mask, - num_mpcc, - num_rmu); - - return &mpc30->base; -} - -static struct hubbub *dcn31_hubbub_create(struct dc_context *ctx) -{ - int i; - - struct dcn20_hubbub *hubbub3 = kzalloc(sizeof(struct dcn20_hubbub), - GFP_KERNEL); - - if (!hubbub3) - return NULL; - - hubbub31_construct(hubbub3, ctx, - &hubbub_reg, - &hubbub_shift, - &hubbub_mask, - dcn3_15_ip.det_buffer_size_kbytes, - dcn3_15_ip.pixel_chunk_size_kbytes, - dcn3_15_ip.config_return_buffer_size_in_kbytes); - - - for (i = 0; i < res_cap_dcn31.num_vmid; i++) { - struct dcn20_vmid *vmid = &hubbub3->vmid[i]; - - vmid->ctx = ctx; - - vmid->regs = &vmid_regs[i]; - vmid->shifts = &vmid_shifts; - vmid->masks = &vmid_masks; - } - - return &hubbub3->base; -} - -static struct timing_generator *dcn31_timing_generator_create( - struct dc_context *ctx, - uint32_t instance) -{ - struct optc *tgn10 = - kzalloc(sizeof(struct optc), GFP_KERNEL); - - if (!tgn10) - return NULL; - - tgn10->base.inst = instance; - tgn10->base.ctx = ctx; - - tgn10->tg_regs = &optc_regs[instance]; - tgn10->tg_shift = &optc_shift; - tgn10->tg_mask = &optc_mask; - - dcn31_timing_generator_init(tgn10); - - return &tgn10->base; -} - -static const struct encoder_feature_support link_enc_feature = { - .max_hdmi_deep_color = COLOR_DEPTH_121212, - .max_hdmi_pixel_clock = 600000, - .hdmi_ycbcr420_supported = true, - .dp_ycbcr420_supported = true, - .fec_supported = true, - .flags.bits.IS_HBR2_CAPABLE = true, - .flags.bits.IS_HBR3_CAPABLE = true, - .flags.bits.IS_TPS3_CAPABLE = true, - .flags.bits.IS_TPS4_CAPABLE = true -}; - -static struct link_encoder *dcn31_link_encoder_create( - struct dc_context *ctx, - const struct encoder_init_data *enc_init_data) -{ - struct dcn20_link_encoder *enc20 = - kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); - - if (!enc20) - return NULL; - - dcn31_link_encoder_construct(enc20, - enc_init_data, - &link_enc_feature, - &link_enc_regs[enc_init_data->transmitter], - &link_enc_aux_regs[enc_init_data->channel - 1], - &link_enc_hpd_regs[enc_init_data->hpd_source], - &le_shift, - &le_mask); - - return &enc20->enc10.base; -} - -/* Create a minimal link encoder object not associated with a particular - * physical connector. - * resource_funcs.link_enc_create_minimal - */ -static struct link_encoder *dcn31_link_enc_create_minimal( - struct dc_context *ctx, enum engine_id eng_id) -{ - struct dcn20_link_encoder *enc20; - - if ((eng_id - ENGINE_ID_DIGA) > ctx->dc->res_pool->res_cap->num_dig_link_enc) - return NULL; - - enc20 = kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); - if (!enc20) - return NULL; - - dcn31_link_encoder_construct_minimal( - enc20, - ctx, - &link_enc_feature, - &link_enc_regs[eng_id - ENGINE_ID_DIGA], - eng_id); - - return &enc20->enc10.base; -} - -static struct panel_cntl *dcn31_panel_cntl_create(const struct panel_cntl_init_data *init_data) -{ - struct dcn31_panel_cntl *panel_cntl = - kzalloc(sizeof(struct dcn31_panel_cntl), GFP_KERNEL); - - if (!panel_cntl) - return NULL; - - dcn31_panel_cntl_construct(panel_cntl, init_data); - - return &panel_cntl->base; -} - -static void read_dce_straps( - struct dc_context *ctx, - struct resource_straps *straps) -{ - generic_reg_get(ctx, regDC_PINSTRAPS + BASE(regDC_PINSTRAPS_BASE_IDX), - FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio); - -} - -static struct audio *dcn31_create_audio( - struct dc_context *ctx, unsigned int inst) -{ - return dce_audio_create(ctx, inst, - &audio_regs[inst], &audio_shift, &audio_mask); -} - -static struct vpg *dcn31_vpg_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn31_vpg *vpg31 = kzalloc(sizeof(struct dcn31_vpg), GFP_KERNEL); - - if (!vpg31) - return NULL; - - vpg31_construct(vpg31, ctx, inst, - &vpg_regs[inst], - &vpg_shift, - &vpg_mask); - - return &vpg31->base; -} - -static struct afmt *dcn31_afmt_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn31_afmt *afmt31 = kzalloc(sizeof(struct dcn31_afmt), GFP_KERNEL); - - if (!afmt31) - return NULL; - - afmt31_construct(afmt31, ctx, inst, - &afmt_regs[inst], - &afmt_shift, - &afmt_mask); - - // Light sleep by default, no need to power down here - - return &afmt31->base; -} - -static struct apg *dcn31_apg_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn31_apg *apg31 = kzalloc(sizeof(struct dcn31_apg), GFP_KERNEL); - - if (!apg31) - return NULL; - - apg31_construct(apg31, ctx, inst, - &apg_regs[inst], - &apg_shift, - &apg_mask); - - return &apg31->base; -} - -static struct stream_encoder *dcn315_stream_encoder_create( - enum engine_id eng_id, - struct dc_context *ctx) -{ - struct dcn10_stream_encoder *enc1; - struct vpg *vpg; - struct afmt *afmt; - int vpg_inst; - int afmt_inst; - - /*PHYB is wired off in HW, allow front end to remapping, otherwise needs more changes*/ - - /* Mapping of VPG, AFMT, DME register blocks to DIO block instance */ - if (eng_id <= ENGINE_ID_DIGF) { - vpg_inst = eng_id; - afmt_inst = eng_id; - } else - return NULL; - - enc1 = kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL); - vpg = dcn31_vpg_create(ctx, vpg_inst); - afmt = dcn31_afmt_create(ctx, afmt_inst); - - if (!enc1 || !vpg || !afmt) { - kfree(enc1); - kfree(vpg); - kfree(afmt); - return NULL; - } - - dcn30_dio_stream_encoder_construct(enc1, ctx, ctx->dc_bios, - eng_id, vpg, afmt, - &stream_enc_regs[eng_id], - &se_shift, &se_mask); - - return &enc1->base; -} - -static struct hpo_dp_stream_encoder *dcn31_hpo_dp_stream_encoder_create( - enum engine_id eng_id, - struct dc_context *ctx) -{ - struct dcn31_hpo_dp_stream_encoder *hpo_dp_enc31; - struct vpg *vpg; - struct apg *apg; - uint32_t hpo_dp_inst; - uint32_t vpg_inst; - uint32_t apg_inst; - - ASSERT((eng_id >= ENGINE_ID_HPO_DP_0) && (eng_id <= ENGINE_ID_HPO_DP_3)); - hpo_dp_inst = eng_id - ENGINE_ID_HPO_DP_0; - - /* Mapping of VPG register blocks to HPO DP block instance: - * VPG[6] -> HPO_DP[0] - * VPG[7] -> HPO_DP[1] - * VPG[8] -> HPO_DP[2] - * VPG[9] -> HPO_DP[3] - */ - vpg_inst = hpo_dp_inst + 6; - - /* Mapping of APG register blocks to HPO DP block instance: - * APG[0] -> HPO_DP[0] - * APG[1] -> HPO_DP[1] - * APG[2] -> HPO_DP[2] - * APG[3] -> HPO_DP[3] - */ - apg_inst = hpo_dp_inst; - - /* allocate HPO stream encoder and create VPG sub-block */ - hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_stream_encoder), GFP_KERNEL); - vpg = dcn31_vpg_create(ctx, vpg_inst); - apg = dcn31_apg_create(ctx, apg_inst); - - if (!hpo_dp_enc31 || !vpg || !apg) { - kfree(hpo_dp_enc31); - kfree(vpg); - kfree(apg); - return NULL; - } - - dcn31_hpo_dp_stream_encoder_construct(hpo_dp_enc31, ctx, ctx->dc_bios, - hpo_dp_inst, eng_id, vpg, apg, - &hpo_dp_stream_enc_regs[hpo_dp_inst], - &hpo_dp_se_shift, &hpo_dp_se_mask); - - return &hpo_dp_enc31->base; -} - -static struct hpo_dp_link_encoder *dcn31_hpo_dp_link_encoder_create( - uint8_t inst, - struct dc_context *ctx) -{ - struct dcn31_hpo_dp_link_encoder *hpo_dp_enc31; - - /* allocate HPO link encoder */ - hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_link_encoder), GFP_KERNEL); - - hpo_dp_link_encoder31_construct(hpo_dp_enc31, ctx, inst, - &hpo_dp_link_enc_regs[inst], - &hpo_dp_le_shift, &hpo_dp_le_mask); - - return &hpo_dp_enc31->base; -} - -static struct dce_hwseq *dcn31_hwseq_create( - struct dc_context *ctx) -{ - struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); - - if (hws) { - hws->ctx = ctx; - hws->regs = &hwseq_reg; - hws->shifts = &hwseq_shift; - hws->masks = &hwseq_mask; - } - return hws; -} -static const struct resource_create_funcs res_create_funcs = { - .read_dce_straps = read_dce_straps, - .create_audio = dcn31_create_audio, - .create_stream_encoder = dcn315_stream_encoder_create, - .create_hpo_dp_stream_encoder = dcn31_hpo_dp_stream_encoder_create, - .create_hpo_dp_link_encoder = dcn31_hpo_dp_link_encoder_create, - .create_hwseq = dcn31_hwseq_create, -}; - -static void dcn315_resource_destruct(struct dcn315_resource_pool *pool) -{ - unsigned int i; - - for (i = 0; i < pool->base.stream_enc_count; i++) { - if (pool->base.stream_enc[i] != NULL) { - if (pool->base.stream_enc[i]->vpg != NULL) { - kfree(DCN30_VPG_FROM_VPG(pool->base.stream_enc[i]->vpg)); - pool->base.stream_enc[i]->vpg = NULL; - } - if (pool->base.stream_enc[i]->afmt != NULL) { - kfree(DCN30_AFMT_FROM_AFMT(pool->base.stream_enc[i]->afmt)); - pool->base.stream_enc[i]->afmt = NULL; - } - kfree(DCN10STRENC_FROM_STRENC(pool->base.stream_enc[i])); - pool->base.stream_enc[i] = NULL; - } - } - - for (i = 0; i < pool->base.hpo_dp_stream_enc_count; i++) { - if (pool->base.hpo_dp_stream_enc[i] != NULL) { - if (pool->base.hpo_dp_stream_enc[i]->vpg != NULL) { - kfree(DCN30_VPG_FROM_VPG(pool->base.hpo_dp_stream_enc[i]->vpg)); - pool->base.hpo_dp_stream_enc[i]->vpg = NULL; - } - if (pool->base.hpo_dp_stream_enc[i]->apg != NULL) { - kfree(DCN31_APG_FROM_APG(pool->base.hpo_dp_stream_enc[i]->apg)); - pool->base.hpo_dp_stream_enc[i]->apg = NULL; - } - kfree(DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(pool->base.hpo_dp_stream_enc[i])); - pool->base.hpo_dp_stream_enc[i] = NULL; - } - } - - for (i = 0; i < pool->base.hpo_dp_link_enc_count; i++) { - if (pool->base.hpo_dp_link_enc[i] != NULL) { - kfree(DCN3_1_HPO_DP_LINK_ENC_FROM_HPO_LINK_ENC(pool->base.hpo_dp_link_enc[i])); - pool->base.hpo_dp_link_enc[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_dsc; i++) { - if (pool->base.dscs[i] != NULL) - dcn20_dsc_destroy(&pool->base.dscs[i]); - } - - if (pool->base.mpc != NULL) { - kfree(TO_DCN20_MPC(pool->base.mpc)); - pool->base.mpc = NULL; - } - if (pool->base.hubbub != NULL) { - kfree(pool->base.hubbub); - pool->base.hubbub = NULL; - } - for (i = 0; i < pool->base.pipe_count; i++) { - if (pool->base.dpps[i] != NULL) - dcn31_dpp_destroy(&pool->base.dpps[i]); - - if (pool->base.ipps[i] != NULL) - pool->base.ipps[i]->funcs->ipp_destroy(&pool->base.ipps[i]); - - if (pool->base.hubps[i] != NULL) { - kfree(TO_DCN20_HUBP(pool->base.hubps[i])); - pool->base.hubps[i] = NULL; - } - - if (pool->base.irqs != NULL) { - dal_irq_service_destroy(&pool->base.irqs); - } - } - - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - if (pool->base.engines[i] != NULL) - dce110_engine_destroy(&pool->base.engines[i]); - if (pool->base.hw_i2cs[i] != NULL) { - kfree(pool->base.hw_i2cs[i]); - pool->base.hw_i2cs[i] = NULL; - } - if (pool->base.sw_i2cs[i] != NULL) { - kfree(pool->base.sw_i2cs[i]); - pool->base.sw_i2cs[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_opp; i++) { - if (pool->base.opps[i] != NULL) - pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]); - } - - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - if (pool->base.timing_generators[i] != NULL) { - kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i])); - pool->base.timing_generators[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_dwb; i++) { - if (pool->base.dwbc[i] != NULL) { - kfree(TO_DCN30_DWBC(pool->base.dwbc[i])); - pool->base.dwbc[i] = NULL; - } - if (pool->base.mcif_wb[i] != NULL) { - kfree(TO_DCN30_MMHUBBUB(pool->base.mcif_wb[i])); - pool->base.mcif_wb[i] = NULL; - } - } - - for (i = 0; i < pool->base.audio_count; i++) { - if (pool->base.audios[i]) - dce_aud_destroy(&pool->base.audios[i]); - } - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] != NULL) { - dcn20_clock_source_destroy(&pool->base.clock_sources[i]); - pool->base.clock_sources[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_mpc_3dlut; i++) { - if (pool->base.mpc_lut[i] != NULL) { - dc_3dlut_func_release(pool->base.mpc_lut[i]); - pool->base.mpc_lut[i] = NULL; - } - if (pool->base.mpc_shaper[i] != NULL) { - dc_transfer_func_release(pool->base.mpc_shaper[i]); - pool->base.mpc_shaper[i] = NULL; - } - } - - if (pool->base.dp_clock_source != NULL) { - dcn20_clock_source_destroy(&pool->base.dp_clock_source); - pool->base.dp_clock_source = NULL; - } - - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - if (pool->base.multiple_abms[i] != NULL) - dce_abm_destroy(&pool->base.multiple_abms[i]); - } - - if (pool->base.psr != NULL) - dmub_psr_destroy(&pool->base.psr); - - if (pool->base.dccg != NULL) - dcn_dccg_destroy(&pool->base.dccg); -} - -static struct hubp *dcn31_hubp_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn20_hubp *hubp2 = - kzalloc(sizeof(struct dcn20_hubp), GFP_KERNEL); - - if (!hubp2) - return NULL; - - if (hubp31_construct(hubp2, ctx, inst, - &hubp_regs[inst], &hubp_shift, &hubp_mask)) - return &hubp2->base; - - BREAK_TO_DEBUGGER(); - kfree(hubp2); - return NULL; -} - -static bool dcn31_dwbc_create(struct dc_context *ctx, struct resource_pool *pool) -{ - int i; - uint32_t pipe_count = pool->res_cap->num_dwb; - - for (i = 0; i < pipe_count; i++) { - struct dcn30_dwbc *dwbc30 = kzalloc(sizeof(struct dcn30_dwbc), - GFP_KERNEL); - - if (!dwbc30) { - dm_error("DC: failed to create dwbc30!\n"); - return false; - } - - dcn30_dwbc_construct(dwbc30, ctx, - &dwbc30_regs[i], - &dwbc30_shift, - &dwbc30_mask, - i); - - pool->dwbc[i] = &dwbc30->base; - } - return true; -} - -static bool dcn31_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool) -{ - int i; - uint32_t pipe_count = pool->res_cap->num_dwb; - - for (i = 0; i < pipe_count; i++) { - struct dcn30_mmhubbub *mcif_wb30 = kzalloc(sizeof(struct dcn30_mmhubbub), - GFP_KERNEL); - - if (!mcif_wb30) { - dm_error("DC: failed to create mcif_wb30!\n"); - return false; - } - - dcn30_mmhubbub_construct(mcif_wb30, ctx, - &mcif_wb30_regs[i], - &mcif_wb30_shift, - &mcif_wb30_mask, - i); - - pool->mcif_wb[i] = &mcif_wb30->base; - } - return true; -} - -static struct display_stream_compressor *dcn31_dsc_create( - struct dc_context *ctx, uint32_t inst) -{ - struct dcn20_dsc *dsc = - kzalloc(sizeof(struct dcn20_dsc), GFP_KERNEL); - - if (!dsc) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dsc2_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask); - return &dsc->base; -} - -static void dcn315_destroy_resource_pool(struct resource_pool **pool) -{ - struct dcn315_resource_pool *dcn31_pool = TO_DCN315_RES_POOL(*pool); - - dcn315_resource_destruct(dcn31_pool); - kfree(dcn31_pool); - *pool = NULL; -} - -static struct clock_source *dcn31_clock_source_create( - struct dc_context *ctx, - struct dc_bios *bios, - enum clock_source_id id, - const struct dce110_clk_src_regs *regs, - bool dp_clk_src) -{ - struct dce110_clk_src *clk_src = - kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); - - if (!clk_src) - return NULL; - - if (dcn31_clk_src_construct(clk_src, ctx, bios, id, - regs, &cs_shift, &cs_mask)) { - clk_src->base.dp_clk_src = dp_clk_src; - return &clk_src->base; - } - - kfree(clk_src); - BREAK_TO_DEBUGGER(); - return NULL; -} - -static bool is_dual_plane(enum surface_pixel_format format) -{ - return format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN || format == SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA; -} - -static int source_format_to_bpp (enum source_format_class SourcePixelFormat) -{ - if (SourcePixelFormat == dm_444_64) - return 8; - else if (SourcePixelFormat == dm_444_16) - return 2; - else if (SourcePixelFormat == dm_444_8) - return 1; - else if (SourcePixelFormat == dm_rgbe_alpha) - return 5; - else if (SourcePixelFormat == dm_420_8) - return 3; - else if (SourcePixelFormat == dm_420_12) - return 6; - else - return 4; -} - -static bool allow_pixel_rate_crb(struct dc *dc, struct dc_state *context) -{ - int i; - struct resource_context *res_ctx = &context->res_ctx; - - /*Don't apply for single stream*/ - if (context->stream_count < 2) - return false; - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - if (!res_ctx->pipe_ctx[i].stream) - continue; - - /*Don't apply if scaling*/ - if (res_ctx->pipe_ctx[i].stream->src.width != res_ctx->pipe_ctx[i].stream->dst.width || - res_ctx->pipe_ctx[i].stream->src.height != res_ctx->pipe_ctx[i].stream->dst.height || - (res_ctx->pipe_ctx[i].plane_state && (res_ctx->pipe_ctx[i].plane_state->src_rect.width - != res_ctx->pipe_ctx[i].plane_state->dst_rect.width || - res_ctx->pipe_ctx[i].plane_state->src_rect.height - != res_ctx->pipe_ctx[i].plane_state->dst_rect.height))) - return false; - /*Don't apply if MPO to avoid transition issues*/ - if (res_ctx->pipe_ctx[i].top_pipe && res_ctx->pipe_ctx[i].top_pipe->plane_state != res_ctx->pipe_ctx[i].plane_state) - return false; - } - return true; -} - -static int dcn315_populate_dml_pipes_from_context( - struct dc *dc, struct dc_state *context, - display_e2e_pipe_params_st *pipes, - bool fast_validate) -{ - int i, pipe_cnt, crb_idx, crb_pipes; - struct resource_context *res_ctx = &context->res_ctx; - struct pipe_ctx *pipe = NULL; - const int max_usable_det = context->bw_ctx.dml.ip.config_return_buffer_size_in_kbytes - DCN3_15_MIN_COMPBUF_SIZE_KB; - int remaining_det_segs = max_usable_det / DCN3_15_CRB_SEGMENT_SIZE_KB; - bool pixel_rate_crb = allow_pixel_rate_crb(dc, context); - - DC_FP_START(); - dcn31x_populate_dml_pipes_from_context(dc, context, pipes, fast_validate); - DC_FP_END(); - - for (i = 0, pipe_cnt = 0, crb_pipes = 0; i < dc->res_pool->pipe_count; i++) { - struct dc_crtc_timing *timing; - - if (!res_ctx->pipe_ctx[i].stream) - continue; - pipe = &res_ctx->pipe_ctx[i]; - timing = &pipe->stream->timing; - - /* - * Immediate flip can be set dynamically after enabling the plane. - * We need to require support for immediate flip or underflow can be - * intermittently experienced depending on peak b/w requirements. - */ - pipes[pipe_cnt].pipe.src.immediate_flip = true; - - pipes[pipe_cnt].pipe.src.unbounded_req_mode = false; - pipes[pipe_cnt].pipe.dest.vfront_porch = timing->v_front_porch; - pipes[pipe_cnt].pipe.src.dcc_rate = 3; - pipes[pipe_cnt].dout.dsc_input_bpc = 0; - DC_FP_START(); - dcn31_zero_pipe_dcc_fraction(pipes, pipe_cnt); - if (pixel_rate_crb && !pipe->top_pipe && !pipe->prev_odm_pipe) { - int bpp = source_format_to_bpp(pipes[pipe_cnt].pipe.src.source_format); - /* Ceil to crb segment size */ - int approx_det_segs_required_for_pstate = dcn_get_approx_det_segs_required_for_pstate( - &context->bw_ctx.dml.soc, timing->pix_clk_100hz, bpp, DCN3_15_CRB_SEGMENT_SIZE_KB); - - if (approx_det_segs_required_for_pstate <= 2 * DCN3_15_MAX_DET_SEGS) { - bool split_required = approx_det_segs_required_for_pstate > DCN3_15_MAX_DET_SEGS; - split_required = split_required || timing->pix_clk_100hz >= dcn_get_max_non_odm_pix_rate_100hz(&dc->dml.soc); - split_required = split_required || (pipe->plane_state && pipe->plane_state->src_rect.width > 5120); - - /* Minimum 2 segments to allow mpc/odm combine if its used later */ - if (approx_det_segs_required_for_pstate < 2) - approx_det_segs_required_for_pstate = 2; - if (split_required) - approx_det_segs_required_for_pstate += approx_det_segs_required_for_pstate % 2; - pipes[pipe_cnt].pipe.src.det_size_override = approx_det_segs_required_for_pstate; - remaining_det_segs -= approx_det_segs_required_for_pstate; - } else - remaining_det_segs = -1; - crb_pipes++; - } - DC_FP_END(); - - if (pipes[pipe_cnt].dout.dsc_enable) { - switch (timing->display_color_depth) { - case COLOR_DEPTH_888: - pipes[pipe_cnt].dout.dsc_input_bpc = 8; - break; - case COLOR_DEPTH_101010: - pipes[pipe_cnt].dout.dsc_input_bpc = 10; - break; - case COLOR_DEPTH_121212: - pipes[pipe_cnt].dout.dsc_input_bpc = 12; - break; - default: - ASSERT(0); - break; - } - } - pipe_cnt++; - } - - /* Spread remaining unreserved crb evenly among all pipes*/ - if (pixel_rate_crb) { - for (i = 0, pipe_cnt = 0, crb_idx = 0; i < dc->res_pool->pipe_count; i++) { - pipe = &res_ctx->pipe_ctx[i]; - if (!pipe->stream) - continue; - - /* Do not use asymetric crb if not enough for pstate support */ - if (remaining_det_segs < 0) { - pipes[pipe_cnt].pipe.src.det_size_override = 0; - pipe_cnt++; - continue; - } - - if (!pipe->top_pipe && !pipe->prev_odm_pipe) { - bool split_required = pipe->stream->timing.pix_clk_100hz >= dcn_get_max_non_odm_pix_rate_100hz(&dc->dml.soc) - || (pipe->plane_state && pipe->plane_state->src_rect.width > 5120); - - if (remaining_det_segs > MIN_RESERVED_DET_SEGS) - pipes[pipe_cnt].pipe.src.det_size_override += (remaining_det_segs - MIN_RESERVED_DET_SEGS) / crb_pipes + - (crb_idx < (remaining_det_segs - MIN_RESERVED_DET_SEGS) % crb_pipes ? 1 : 0); - if (pipes[pipe_cnt].pipe.src.det_size_override > 2 * DCN3_15_MAX_DET_SEGS) { - /* Clamp to 2 pipe split max det segments */ - remaining_det_segs += pipes[pipe_cnt].pipe.src.det_size_override - 2 * (DCN3_15_MAX_DET_SEGS); - pipes[pipe_cnt].pipe.src.det_size_override = 2 * DCN3_15_MAX_DET_SEGS; - } - if (pipes[pipe_cnt].pipe.src.det_size_override > DCN3_15_MAX_DET_SEGS || split_required) { - /* If we are splitting we must have an even number of segments */ - remaining_det_segs += pipes[pipe_cnt].pipe.src.det_size_override % 2; - pipes[pipe_cnt].pipe.src.det_size_override -= pipes[pipe_cnt].pipe.src.det_size_override % 2; - } - /* Convert segments into size for DML use */ - pipes[pipe_cnt].pipe.src.det_size_override *= DCN3_15_CRB_SEGMENT_SIZE_KB; - - crb_idx++; - } - pipe_cnt++; - } - } - - if (pipe_cnt) - context->bw_ctx.dml.ip.det_buffer_size_kbytes = - (max_usable_det / DCN3_15_CRB_SEGMENT_SIZE_KB / pipe_cnt) * DCN3_15_CRB_SEGMENT_SIZE_KB; - if (context->bw_ctx.dml.ip.det_buffer_size_kbytes > DCN3_15_MAX_DET_SIZE) - context->bw_ctx.dml.ip.det_buffer_size_kbytes = DCN3_15_MAX_DET_SIZE; - - dc->config.enable_4to1MPC = false; - if (pipe_cnt == 1 && pipe->plane_state && !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; - context->bw_ctx.dml.ip.det_buffer_size_kbytes = - (max_usable_det / DCN3_15_CRB_SEGMENT_SIZE_KB / 4) * DCN3_15_CRB_SEGMENT_SIZE_KB; - } else if (!is_dual_plane(pipe->plane_state->format) - && pipe->plane_state->src_rect.width <= 5120 - && pipe->stream->timing.pix_clk_100hz < dcn_get_max_non_odm_pix_rate_100hz(&dc->dml.soc)) { - /* Limit to 5k max to avoid forced pipe split when there is not enough detile for swath */ - context->bw_ctx.dml.ip.det_buffer_size_kbytes = 192; - pipes[0].pipe.src.unbounded_req_mode = true; - } - } - - return pipe_cnt; -} - -static void dcn315_get_panel_config_defaults(struct dc_panel_config *panel_config) -{ - *panel_config = panel_config_defaults; -} - -static struct dc_cap_funcs cap_funcs = { - .get_dcc_compression_cap = dcn20_get_dcc_compression_cap -}; - -static struct resource_funcs dcn315_res_pool_funcs = { - .destroy = dcn315_destroy_resource_pool, - .link_enc_create = dcn31_link_encoder_create, - .link_enc_create_minimal = dcn31_link_enc_create_minimal, - .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, - .calculate_wm_and_dlg = dcn31_calculate_wm_and_dlg, - .update_soc_for_wm_a = dcn315_update_soc_for_wm_a, - .populate_dml_pipes = dcn315_populate_dml_pipes_from_context, - .acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer, - .release_pipe = dcn20_release_pipe, - .add_stream_to_ctx = dcn30_add_stream_to_ctx, - .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource, - .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, - .populate_dml_writeback_from_context = dcn31_populate_dml_writeback_from_context, - .set_mcif_arb_params = dcn31_set_mcif_arb_params, - .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 = dcn315_update_bw_bounding_box, - .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, - .get_panel_config_defaults = dcn315_get_panel_config_defaults, -}; - -static bool dcn315_resource_construct( - uint8_t num_virtual_links, - struct dc *dc, - struct dcn315_resource_pool *pool) -{ - int i; - struct dc_context *ctx = dc->ctx; - struct irq_service_init_data init_data; - - ctx->dc_bios->regs = &bios_regs; - - pool->base.res_cap = &res_cap_dcn31; - - pool->base.funcs = &dcn315_res_pool_funcs; - - /************************************************* - * Resource + asic cap harcoding * - *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; - pool->base.pipe_count = pool->base.res_cap->num_timing_generator; - 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.max_cursor_size = 256; - dc->caps.min_horizontal_blanking_period = 80; - dc->caps.dmdata_alloc_size = 2048; - dc->caps.max_slave_planes = 2; - dc->caps.max_slave_yuv_planes = 2; - dc->caps.max_slave_rgb_planes = 2; - dc->caps.post_blend_color_processing = true; - dc->caps.force_dp_tps4_for_cp2520 = true; - if (dc->config.forceHBR2CP2520) - dc->caps.force_dp_tps4_for_cp2520 = false; - dc->caps.dp_hpo = true; - dc->caps.dp_hdmi21_pcon_support = true; - dc->caps.edp_dsc_support = true; - dc->caps.extended_aux_timeout_support = true; - dc->caps.dmcub_support = true; - dc->caps.is_apu = true; - - /* Color pipeline capabilities */ - dc->caps.color.dpp.dcn_arch = 1; - dc->caps.color.dpp.input_lut_shared = 0; - dc->caps.color.dpp.icsc = 1; - dc->caps.color.dpp.dgam_ram = 0; // must use gamma_corr - dc->caps.color.dpp.dgam_rom_caps.srgb = 1; - dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1; - dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 1; - dc->caps.color.dpp.dgam_rom_caps.pq = 1; - dc->caps.color.dpp.dgam_rom_caps.hlg = 1; - dc->caps.color.dpp.post_csc = 1; - dc->caps.color.dpp.gamma_corr = 1; - dc->caps.color.dpp.dgam_rom_for_yuv = 0; - - dc->caps.color.dpp.hw_3d_lut = 1; - dc->caps.color.dpp.ogam_ram = 1; - // no OGAM ROM on DCN301 - dc->caps.color.dpp.ogam_rom_caps.srgb = 0; - dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0; - dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0; - dc->caps.color.dpp.ogam_rom_caps.pq = 0; - dc->caps.color.dpp.ogam_rom_caps.hlg = 0; - dc->caps.color.dpp.ocsc = 0; - - dc->caps.color.mpc.gamut_remap = 1; - dc->caps.color.mpc.num_3dluts = pool->base.res_cap->num_mpc_3dlut; //2 - dc->caps.color.mpc.ogam_ram = 1; - dc->caps.color.mpc.ogam_rom_caps.srgb = 0; - dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0; - dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0; - dc->caps.color.mpc.ogam_rom_caps.pq = 0; - dc->caps.color.mpc.ogam_rom_caps.hlg = 0; - dc->caps.color.mpc.ocsc = 1; - - /* read VBIOS LTTPR caps */ - { - if (ctx->dc_bios->funcs->get_lttpr_caps) { - enum bp_result bp_query_result; - uint8_t is_vbios_lttpr_enable = 0; - - bp_query_result = ctx->dc_bios->funcs->get_lttpr_caps(ctx->dc_bios, &is_vbios_lttpr_enable); - dc->caps.vbios_lttpr_enable = (bp_query_result == BP_RESULT_OK) && !!is_vbios_lttpr_enable; - } - - /* interop bit is implicit */ - { - dc->caps.vbios_lttpr_aware = true; - } - } - - if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) - dc->debug = debug_defaults_drv; - - // Init the vm_helper - if (dc->vm_helper) - vm_helper_init(dc->vm_helper, 16); - - /************************************************* - * Create resources * - *************************************************/ - - /* Clock Sources for Pixel Clock*/ - pool->base.clock_sources[DCN31_CLK_SRC_PLL0] = - dcn31_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL0, - &clk_src_regs[0], false); - pool->base.clock_sources[DCN31_CLK_SRC_PLL1] = - dcn31_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL1, - &clk_src_regs[1], false); - pool->base.clock_sources[DCN31_CLK_SRC_PLL2] = - dcn31_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL2, - &clk_src_regs[2], false); - pool->base.clock_sources[DCN31_CLK_SRC_PLL3] = - dcn31_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL3, - &clk_src_regs[3], false); - pool->base.clock_sources[DCN31_CLK_SRC_PLL4] = - dcn31_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL4, - &clk_src_regs[4], false); - - pool->base.clk_src_count = DCN30_CLK_SRC_TOTAL; - - /* todo: not reuse phy_pll registers */ - pool->base.dp_clock_source = - dcn31_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_ID_DP_DTO, - &clk_src_regs[0], true); - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] == NULL) { - dm_error("DC: failed to create clock sources!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - } - - /* TODO: DCCG */ - pool->base.dccg = dccg31_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask); - if (pool->base.dccg == NULL) { - dm_error("DC: failed to create dccg!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - - /* TODO: IRQ */ - init_data.ctx = dc->ctx; - pool->base.irqs = dal_irq_service_dcn315_create(&init_data); - if (!pool->base.irqs) - goto create_fail; - - /* HUBBUB */ - pool->base.hubbub = dcn31_hubbub_create(ctx); - if (pool->base.hubbub == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create hubbub!\n"); - goto create_fail; - } - - /* HUBPs, DPPs, OPPs and TGs */ - for (i = 0; i < pool->base.pipe_count; i++) { - pool->base.hubps[i] = dcn31_hubp_create(ctx, i); - if (pool->base.hubps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create hubps!\n"); - goto create_fail; - } - - pool->base.dpps[i] = dcn31_dpp_create(ctx, i); - if (pool->base.dpps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create dpps!\n"); - goto create_fail; - } - } - - for (i = 0; i < pool->base.res_cap->num_opp; i++) { - pool->base.opps[i] = dcn31_opp_create(ctx, i); - if (pool->base.opps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create output pixel processor!\n"); - goto create_fail; - } - } - - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - pool->base.timing_generators[i] = dcn31_timing_generator_create( - ctx, i); - if (pool->base.timing_generators[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create tg!\n"); - goto create_fail; - } - } - pool->base.timing_generator_count = i; - - /* PSR */ - pool->base.psr = dmub_psr_create(ctx); - if (pool->base.psr == NULL) { - dm_error("DC: failed to create psr obj!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - - /* ABM */ - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - pool->base.multiple_abms[i] = dmub_abm_create(ctx, - &abm_regs[i], - &abm_shift, - &abm_mask); - if (pool->base.multiple_abms[i] == NULL) { - dm_error("DC: failed to create abm for pipe %d!\n", i); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - } - - /* MPC and DSC */ - pool->base.mpc = dcn31_mpc_create(ctx, pool->base.mpcc_count, pool->base.res_cap->num_mpc_3dlut); - if (pool->base.mpc == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create mpc!\n"); - goto create_fail; - } - - for (i = 0; i < pool->base.res_cap->num_dsc; i++) { - pool->base.dscs[i] = dcn31_dsc_create(ctx, i); - if (pool->base.dscs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create display stream compressor %d!\n", i); - goto create_fail; - } - } - - /* DWB and MMHUBBUB */ - if (!dcn31_dwbc_create(ctx, &pool->base)) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create dwbc!\n"); - goto create_fail; - } - - if (!dcn31_mmhubbub_create(ctx, &pool->base)) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create mcif_wb!\n"); - goto create_fail; - } - - /* AUX and I2C */ - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - pool->base.engines[i] = dcn31_aux_engine_create(ctx, i); - if (pool->base.engines[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create aux engine!!\n"); - goto create_fail; - } - pool->base.hw_i2cs[i] = dcn31_i2c_hw_create(ctx, i); - if (pool->base.hw_i2cs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create hw i2c!!\n"); - goto create_fail; - } - pool->base.sw_i2cs[i] = NULL; - } - - /* Audio, Stream Encoders including HPO and virtual, MPC 3D LUTs */ - if (!resource_construct(num_virtual_links, dc, &pool->base, - &res_create_funcs)) - goto create_fail; - - /* HW Sequencer and Plane caps */ - dcn31_hw_sequencer_construct(dc); - - dc->caps.max_planes = pool->base.pipe_count; - - for (i = 0; i < dc->caps.max_planes; ++i) - dc->caps.planes[i] = plane_cap; - - dc->cap_funcs = cap_funcs; - - dc->dcn_ip->max_num_dpp = dcn3_15_ip.max_num_dpp; - - return true; - -create_fail: - - dcn315_resource_destruct(pool); - - return false; -} - -struct resource_pool *dcn315_create_resource_pool( - const struct dc_init_data *init_data, - struct dc *dc) -{ - struct dcn315_resource_pool *pool = - kzalloc(sizeof(struct dcn315_resource_pool), GFP_KERNEL); - - if (!pool) - return NULL; - - if (dcn315_resource_construct(init_data->num_virtual_links, dc, pool)) - return &pool->base; - - BREAK_TO_DEBUGGER(); - kfree(pool); - return NULL; -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.h b/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.h deleted file mode 100644 index 22849eaa6f243e..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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 _DCN315_RESOURCE_H_ -#define _DCN315_RESOURCE_H_ - -#include "core_types.h" - -#define TO_DCN315_RES_POOL(pool)\ - container_of(pool, struct dcn315_resource_pool, base) - -extern struct _vcs_dpi_ip_params_st dcn3_15_ip; - -struct dcn315_resource_pool { - struct resource_pool base; -}; - -struct resource_pool *dcn315_create_resource_pool( - const struct dc_init_data *init_data, - struct dc *dc); - -#endif /* _DCN315_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn316/Makefile b/drivers/gpu/drm/amd/display/dc/dcn316/Makefile deleted file mode 100644 index 819d44a9439b02..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn316/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -# -# 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 -# -# Makefile for dcn316. - -DCN316 = dcn316_resource.o - -AMD_DAL_DCN316 = $(addprefix $(AMDDALPATH)/dc/dcn316/,$(DCN316)) - -AMD_DISPLAY_FILES += $(AMD_DAL_DCN316) diff --git a/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c b/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c deleted file mode 100644 index b9753d4606f89d..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c +++ /dev/null @@ -1,2038 +0,0 @@ -/* - * 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 "dm_services.h" -#include "dc.h" - -#include "dcn31/dcn31_init.h" - -#include "resource.h" -#include "include/irq_service_interface.h" -#include "dcn316_resource.h" - -#include "dcn20/dcn20_resource.h" -#include "dcn30/dcn30_resource.h" -#include "dcn31/dcn31_resource.h" - -#include "dcn10/dcn10_ipp.h" -#include "dcn30/dcn30_hubbub.h" -#include "dcn31/dcn31_hubbub.h" -#include "dcn30/dcn30_mpc.h" -#include "dcn31/dcn31_hubp.h" -#include "irq/dcn31/irq_service_dcn31.h" -#include "dcn30/dcn30_dpp.h" -#include "dcn31/dcn31_optc.h" -#include "dcn20/dcn20_hwseq.h" -#include "dcn30/dcn30_hwseq.h" -#include "dce110/dce110_hwseq.h" -#include "dcn30/dcn30_opp.h" -#include "dcn20/dcn20_dsc.h" -#include "dcn30/dcn30_vpg.h" -#include "dcn30/dcn30_afmt.h" -#include "dcn30/dcn30_dio_stream_encoder.h" -#include "dcn31/dcn31_hpo_dp_stream_encoder.h" -#include "dcn31/dcn31_hpo_dp_link_encoder.h" -#include "dcn31/dcn31_apg.h" -#include "dcn31/dcn31_dio_link_encoder.h" -#include "dcn31/dcn31_vpg.h" -#include "dcn31/dcn31_afmt.h" -#include "dce/dce_clock_source.h" -#include "dce/dce_audio.h" -#include "dce/dce_hwseq.h" -#include "clk_mgr.h" -#include "virtual/virtual_stream_encoder.h" -#include "dce110/dce110_resource.h" -#include "dml/display_mode_vba.h" -#include "dml/dcn31/dcn31_fpu.h" -#include "dcn31/dcn31_dccg.h" -#include "dcn10/dcn10_resource.h" -#include "dcn31/dcn31_panel_cntl.h" - -#include "dcn30/dcn30_dwb.h" -#include "dcn30/dcn30_mmhubbub.h" - -#include "dcn/dcn_3_1_6_offset.h" -#include "dcn/dcn_3_1_6_sh_mask.h" -#include "dpcs/dpcs_4_2_3_offset.h" -#include "dpcs/dpcs_4_2_3_sh_mask.h" - -#define regBIF_BX1_BIOS_SCRATCH_2 0x003a -#define regBIF_BX1_BIOS_SCRATCH_2_BASE_IDX 1 -#define regBIF_BX1_BIOS_SCRATCH_3 0x003b -#define regBIF_BX1_BIOS_SCRATCH_3_BASE_IDX 1 -#define regBIF_BX1_BIOS_SCRATCH_6 0x003e -#define regBIF_BX1_BIOS_SCRATCH_6_BASE_IDX 1 - -#define regDCHUBBUB_DEBUG_CTRL_0 0x04d6 -#define regDCHUBBUB_DEBUG_CTRL_0_BASE_IDX 2 -#define DCHUBBUB_DEBUG_CTRL_0__DET_DEPTH__SHIFT 0x10 -#define DCHUBBUB_DEBUG_CTRL_0__DET_DEPTH_MASK 0x01FF0000L - -#define DCN_BASE__INST0_SEG0 0x00000012 -#define DCN_BASE__INST0_SEG1 0x000000C0 -#define DCN_BASE__INST0_SEG2 0x000034C0 -#define DCN_BASE__INST0_SEG3 0x00009000 -#define DCN_BASE__INST0_SEG4 0x02403C00 -#define DCN_BASE__INST0_SEG5 0 - -#define DPCS_BASE__INST0_SEG0 0x00000012 -#define DPCS_BASE__INST0_SEG1 0x000000C0 -#define DPCS_BASE__INST0_SEG2 0x000034C0 -#define DPCS_BASE__INST0_SEG3 0x00009000 -#define DPCS_BASE__INST0_SEG4 0x02403C00 -#define DPCS_BASE__INST0_SEG5 0 - -#define NBIO_BASE__INST0_SEG0 0x00000000 -#define NBIO_BASE__INST0_SEG1 0x00000014 -#define NBIO_BASE__INST0_SEG2 0x00000D20 -#define NBIO_BASE__INST0_SEG3 0x00010400 -#define NBIO_BASE__INST0_SEG4 0x0241B000 -#define NBIO_BASE__INST0_SEG5 0x04040000 - -#include "reg_helper.h" -#include "dce/dmub_abm.h" -#include "dce/dmub_psr.h" -#include "dce/dce_aux.h" -#include "dce/dce_i2c.h" - -#include "dml/dcn30/display_mode_vba_30.h" -#include "vm_helper.h" -#include "dcn20/dcn20_vmid.h" - -#include "link_enc_cfg.h" - -#define DCN3_16_MAX_DET_SIZE 384 -#define DCN3_16_MIN_COMPBUF_SIZE_KB 128 -#define DCN3_16_CRB_SEGMENT_SIZE_KB 64 - -enum dcn31_clk_src_array_id { - DCN31_CLK_SRC_PLL0, - DCN31_CLK_SRC_PLL1, - DCN31_CLK_SRC_PLL2, - DCN31_CLK_SRC_PLL3, - DCN31_CLK_SRC_PLL4, - DCN30_CLK_SRC_TOTAL -}; - -/* begin ********************* - * macros to expend register list macro defined in HW object header file - */ - -/* DCN */ -#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg - -#define BASE(seg) BASE_INNER(seg) - -#define SR(reg_name)\ - .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ - reg ## reg_name - -#define SRI(reg_name, block, id)\ - .reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRI2(reg_name, block, id)\ - .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ - reg ## reg_name - -#define SRIR(var_name, reg_name, block, id)\ - .var_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRII(reg_name, block, id)\ - .reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRII_MPC_RMU(reg_name, block, id)\ - .RMU##_##reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRII_DWB(reg_name, temp_name, block, id)\ - .reg_name[id] = BASE(reg ## block ## id ## _ ## temp_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## temp_name - -#define SF_DWB2(reg_name, block, id, field_name, post_fix) \ - .field_name = reg_name ## __ ## field_name ## post_fix - -#define DCCG_SRII(reg_name, block, id)\ - .block ## _ ## reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define VUPDATE_SRII(reg_name, block, id)\ - .reg_name[id] = BASE(reg ## reg_name ## _ ## block ## id ## _BASE_IDX) + \ - reg ## reg_name ## _ ## block ## id - -/* NBIO */ -#define NBIO_BASE_INNER(seg) \ - NBIO_BASE__INST0_SEG ## seg - -#define NBIO_BASE(seg) \ - NBIO_BASE_INNER(seg) - -#define NBIO_SR(reg_name)\ - .reg_name = NBIO_BASE(regBIF_BX1_ ## reg_name ## _BASE_IDX) + \ - regBIF_BX1_ ## reg_name - -static const struct bios_registers bios_regs = { - NBIO_SR(BIOS_SCRATCH_3), - NBIO_SR(BIOS_SCRATCH_6) -}; - -#define clk_src_regs(index, pllid)\ -[index] = {\ - CS_COMMON_REG_LIST_DCN3_0(index, pllid),\ -} - -static const struct dce110_clk_src_regs clk_src_regs[] = { - clk_src_regs(0, A), - clk_src_regs(1, B), - clk_src_regs(2, C), - clk_src_regs(3, D), - clk_src_regs(4, E) -}; - -static const struct dce110_clk_src_shift cs_shift = { - CS_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) -}; - -static const struct dce110_clk_src_mask cs_mask = { - CS_COMMON_MASK_SH_LIST_DCN2_0(_MASK) -}; - -#define abm_regs(id)\ -[id] = {\ - ABM_DCN302_REG_LIST(id)\ -} - -static const struct dce_abm_registers abm_regs[] = { - abm_regs(0), - abm_regs(1), - abm_regs(2), - abm_regs(3), -}; - -static const struct dce_abm_shift abm_shift = { - ABM_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dce_abm_mask abm_mask = { - ABM_MASK_SH_LIST_DCN30(_MASK) -}; - -#define audio_regs(id)\ -[id] = {\ - AUD_COMMON_REG_LIST(id)\ -} - -static const struct dce_audio_registers audio_regs[] = { - audio_regs(0), - audio_regs(1), - audio_regs(2), - audio_regs(3), - audio_regs(4), - audio_regs(5), - audio_regs(6) -}; - -#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ - SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ - SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ - AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) - -static const struct dce_audio_shift audio_shift = { - DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_audio_mask audio_mask = { - DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) -}; - -#define vpg_regs(id)\ -[id] = {\ - VPG_DCN31_REG_LIST(id)\ -} - -static const struct dcn31_vpg_registers vpg_regs[] = { - vpg_regs(0), - vpg_regs(1), - vpg_regs(2), - vpg_regs(3), - vpg_regs(4), - vpg_regs(5), - vpg_regs(6), - vpg_regs(7), - vpg_regs(8), - vpg_regs(9), -}; - -static const struct dcn31_vpg_shift vpg_shift = { - DCN31_VPG_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn31_vpg_mask vpg_mask = { - DCN31_VPG_MASK_SH_LIST(_MASK) -}; - -#define afmt_regs(id)\ -[id] = {\ - AFMT_DCN31_REG_LIST(id)\ -} - -static const struct dcn31_afmt_registers afmt_regs[] = { - afmt_regs(0), - afmt_regs(1), - afmt_regs(2), - afmt_regs(3), - afmt_regs(4), - afmt_regs(5) -}; - -static const struct dcn31_afmt_shift afmt_shift = { - DCN31_AFMT_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn31_afmt_mask afmt_mask = { - DCN31_AFMT_MASK_SH_LIST(_MASK) -}; - - -#define apg_regs(id)\ -[id] = {\ - APG_DCN31_REG_LIST(id)\ -} - -static const struct dcn31_apg_registers apg_regs[] = { - apg_regs(0), - apg_regs(1), - apg_regs(2), - apg_regs(3) -}; - -static const struct dcn31_apg_shift apg_shift = { - DCN31_APG_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn31_apg_mask apg_mask = { - DCN31_APG_MASK_SH_LIST(_MASK) -}; - - -#define stream_enc_regs(id)\ -[id] = {\ - SE_DCN3_REG_LIST(id)\ -} - -static const struct dcn10_stream_enc_registers stream_enc_regs[] = { - stream_enc_regs(0), - stream_enc_regs(1), - stream_enc_regs(2), - stream_enc_regs(3), - stream_enc_regs(4) -}; - -static const struct dcn10_stream_encoder_shift se_shift = { - SE_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn10_stream_encoder_mask se_mask = { - SE_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - - -#define aux_regs(id)\ -[id] = {\ - DCN2_AUX_REG_LIST(id)\ -} - -static const struct dcn10_link_enc_aux_registers link_enc_aux_regs[] = { - aux_regs(0), - aux_regs(1), - aux_regs(2), - aux_regs(3), - aux_regs(4) -}; - -#define hpd_regs(id)\ -[id] = {\ - HPD_REG_LIST(id)\ -} - -static const struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[] = { - hpd_regs(0), - hpd_regs(1), - hpd_regs(2), - hpd_regs(3), - hpd_regs(4) -}; - -#define link_regs(id, phyid)\ -[id] = {\ - LE_DCN31_REG_LIST(id), \ - UNIPHY_DCN2_REG_LIST(phyid), \ - DPCS_DCN31_REG_LIST(id), \ -} - -static const struct dce110_aux_registers_shift aux_shift = { - DCN_AUX_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce110_aux_registers_mask aux_mask = { - DCN_AUX_MASK_SH_LIST(_MASK) -}; - -static const struct dcn10_link_enc_registers link_enc_regs[] = { - link_regs(0, A), - link_regs(1, B), - link_regs(2, C), - link_regs(3, D), - link_regs(4, E) -}; - -static const struct dcn10_link_enc_shift le_shift = { - LINK_ENCODER_MASK_SH_LIST_DCN31(__SHIFT), \ - DPCS_DCN31_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn10_link_enc_mask le_mask = { - LINK_ENCODER_MASK_SH_LIST_DCN31(_MASK), \ - DPCS_DCN31_MASK_SH_LIST(_MASK) -}; - - - -#define hpo_dp_stream_encoder_reg_list(id)\ -[id] = {\ - DCN3_1_HPO_DP_STREAM_ENC_REG_LIST(id)\ -} - -static const struct dcn31_hpo_dp_stream_encoder_registers hpo_dp_stream_enc_regs[] = { - hpo_dp_stream_encoder_reg_list(0), - hpo_dp_stream_encoder_reg_list(1), - hpo_dp_stream_encoder_reg_list(2), - hpo_dp_stream_encoder_reg_list(3), -}; - -static const struct dcn31_hpo_dp_stream_encoder_shift hpo_dp_se_shift = { - DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn31_hpo_dp_stream_encoder_mask hpo_dp_se_mask = { - DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(_MASK) -}; - - -#define hpo_dp_link_encoder_reg_list(id)\ -[id] = {\ - DCN3_1_HPO_DP_LINK_ENC_REG_LIST(id),\ - DCN3_1_RDPCSTX_REG_LIST(0),\ - DCN3_1_RDPCSTX_REG_LIST(1),\ - DCN3_1_RDPCSTX_REG_LIST(2),\ - DCN3_1_RDPCSTX_REG_LIST(3),\ - DCN3_1_RDPCSTX_REG_LIST(4)\ -} - -static const struct dcn31_hpo_dp_link_encoder_registers hpo_dp_link_enc_regs[] = { - hpo_dp_link_encoder_reg_list(0), - hpo_dp_link_encoder_reg_list(1), -}; - -static const struct dcn31_hpo_dp_link_encoder_shift hpo_dp_le_shift = { - DCN3_1_HPO_DP_LINK_ENC_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn31_hpo_dp_link_encoder_mask hpo_dp_le_mask = { - DCN3_1_HPO_DP_LINK_ENC_MASK_SH_LIST(_MASK) -}; - - -#define dpp_regs(id)\ -[id] = {\ - DPP_REG_LIST_DCN30(id),\ -} - -static const struct dcn3_dpp_registers dpp_regs[] = { - dpp_regs(0), - dpp_regs(1), - dpp_regs(2), - dpp_regs(3) -}; - -static const struct dcn3_dpp_shift tf_shift = { - DPP_REG_LIST_SH_MASK_DCN30(__SHIFT) -}; - -static const struct dcn3_dpp_mask tf_mask = { - DPP_REG_LIST_SH_MASK_DCN30(_MASK) -}; - -#define opp_regs(id)\ -[id] = {\ - OPP_REG_LIST_DCN30(id),\ -} - -static const struct dcn20_opp_registers opp_regs[] = { - opp_regs(0), - opp_regs(1), - opp_regs(2), - opp_regs(3) -}; - -static const struct dcn20_opp_shift opp_shift = { - OPP_MASK_SH_LIST_DCN20(__SHIFT) -}; - -static const struct dcn20_opp_mask opp_mask = { - OPP_MASK_SH_LIST_DCN20(_MASK) -}; - -#define aux_engine_regs(id)\ -[id] = {\ - AUX_COMMON_REG_LIST0(id), \ - .AUXN_IMPCAL = 0, \ - .AUXP_IMPCAL = 0, \ - .AUX_RESET_MASK = DP_AUX0_AUX_CONTROL__AUX_RESET_MASK, \ -} - -static const struct dce110_aux_registers aux_engine_regs[] = { - aux_engine_regs(0), - aux_engine_regs(1), - aux_engine_regs(2), - aux_engine_regs(3), - aux_engine_regs(4) -}; - -#define dwbc_regs_dcn3(id)\ -[id] = {\ - DWBC_COMMON_REG_LIST_DCN30(id),\ -} - -static const struct dcn30_dwbc_registers dwbc30_regs[] = { - dwbc_regs_dcn3(0), -}; - -static const struct dcn30_dwbc_shift dwbc30_shift = { - DWBC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn30_dwbc_mask dwbc30_mask = { - DWBC_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -#define mcif_wb_regs_dcn3(id)\ -[id] = {\ - MCIF_WB_COMMON_REG_LIST_DCN30(id),\ -} - -static const struct dcn30_mmhubbub_registers mcif_wb30_regs[] = { - mcif_wb_regs_dcn3(0) -}; - -static const struct dcn30_mmhubbub_shift mcif_wb30_shift = { - MCIF_WB_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn30_mmhubbub_mask mcif_wb30_mask = { - MCIF_WB_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -#define dsc_regsDCN20(id)\ -[id] = {\ - DSC_REG_LIST_DCN20(id)\ -} - -static const struct dcn20_dsc_registers dsc_regs[] = { - dsc_regsDCN20(0), - dsc_regsDCN20(1), - dsc_regsDCN20(2) -}; - -static const struct dcn20_dsc_shift dsc_shift = { - DSC_REG_LIST_SH_MASK_DCN20(__SHIFT) -}; - -static const struct dcn20_dsc_mask dsc_mask = { - DSC_REG_LIST_SH_MASK_DCN20(_MASK) -}; - -static const struct dcn30_mpc_registers mpc_regs = { - MPC_REG_LIST_DCN3_0(0), - MPC_REG_LIST_DCN3_0(1), - MPC_REG_LIST_DCN3_0(2), - MPC_REG_LIST_DCN3_0(3), - MPC_OUT_MUX_REG_LIST_DCN3_0(0), - MPC_OUT_MUX_REG_LIST_DCN3_0(1), - MPC_OUT_MUX_REG_LIST_DCN3_0(2), - MPC_OUT_MUX_REG_LIST_DCN3_0(3), - MPC_RMU_GLOBAL_REG_LIST_DCN3AG, - MPC_RMU_REG_LIST_DCN3AG(0), - MPC_RMU_REG_LIST_DCN3AG(1), - //MPC_RMU_REG_LIST_DCN3AG(2), - MPC_DWB_MUX_REG_LIST_DCN3_0(0), -}; - -static const struct dcn30_mpc_shift mpc_shift = { - MPC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn30_mpc_mask mpc_mask = { - MPC_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -#define optc_regs(id)\ -[id] = {OPTC_COMMON_REG_LIST_DCN3_1(id)} - -static const struct dcn_optc_registers optc_regs[] = { - optc_regs(0), - optc_regs(1), - optc_regs(2), - optc_regs(3) -}; - -static const struct dcn_optc_shift optc_shift = { - OPTC_COMMON_MASK_SH_LIST_DCN3_1(__SHIFT) -}; - -static const struct dcn_optc_mask optc_mask = { - OPTC_COMMON_MASK_SH_LIST_DCN3_1(_MASK) -}; - -#define hubp_regs(id)\ -[id] = {\ - HUBP_REG_LIST_DCN30(id)\ -} - -static const struct dcn_hubp2_registers hubp_regs[] = { - hubp_regs(0), - hubp_regs(1), - hubp_regs(2), - hubp_regs(3) -}; - - -static const struct dcn_hubp2_shift hubp_shift = { - HUBP_MASK_SH_LIST_DCN31(__SHIFT) -}; - -static const struct dcn_hubp2_mask hubp_mask = { - HUBP_MASK_SH_LIST_DCN31(_MASK) -}; -static const struct dcn_hubbub_registers hubbub_reg = { - HUBBUB_REG_LIST_DCN31(0) -}; - -static const struct dcn_hubbub_shift hubbub_shift = { - HUBBUB_MASK_SH_LIST_DCN31(__SHIFT) -}; - -static const struct dcn_hubbub_mask hubbub_mask = { - HUBBUB_MASK_SH_LIST_DCN31(_MASK) -}; - -static const struct dccg_registers dccg_regs = { - DCCG_REG_LIST_DCN31() -}; - -static const struct dccg_shift dccg_shift = { - DCCG_MASK_SH_LIST_DCN31(__SHIFT) -}; - -static const struct dccg_mask dccg_mask = { - DCCG_MASK_SH_LIST_DCN31(_MASK) -}; - - -#define SRII2(reg_name_pre, reg_name_post, id)\ - .reg_name_pre ## _ ## reg_name_post[id] = BASE(reg ## reg_name_pre \ - ## id ## _ ## reg_name_post ## _BASE_IDX) + \ - reg ## reg_name_pre ## id ## _ ## reg_name_post - - -#define HWSEQ_DCN31_REG_LIST()\ - SR(DCHUBBUB_GLOBAL_TIMER_CNTL), \ - SR(DCHUBBUB_ARB_HOSTVM_CNTL), \ - SR(DIO_MEM_PWR_CTRL), \ - SR(ODM_MEM_PWR_CTRL3), \ - SR(DMU_MEM_PWR_CNTL), \ - SR(MMHUBBUB_MEM_PWR_CNTL), \ - SR(DCCG_GATE_DISABLE_CNTL), \ - SR(DCCG_GATE_DISABLE_CNTL2), \ - SR(DCFCLK_CNTL),\ - SR(DC_MEM_GLOBAL_PWR_REQ_CNTL), \ - SRII(PIXEL_RATE_CNTL, OTG, 0), \ - SRII(PIXEL_RATE_CNTL, OTG, 1),\ - SRII(PIXEL_RATE_CNTL, OTG, 2),\ - SRII(PIXEL_RATE_CNTL, OTG, 3),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 0),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 1),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 2),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 3),\ - SR(MICROSECOND_TIME_BASE_DIV), \ - SR(MILLISECOND_TIME_BASE_DIV), \ - SR(DISPCLK_FREQ_CHANGE_CNTL), \ - SR(RBBMIF_TIMEOUT_DIS), \ - SR(RBBMIF_TIMEOUT_DIS_2), \ - SR(DCHUBBUB_CRC_CTRL), \ - SR(DPP_TOP0_DPP_CRC_CTRL), \ - SR(DPP_TOP0_DPP_CRC_VAL_B_A), \ - SR(DPP_TOP0_DPP_CRC_VAL_R_G), \ - SR(MPC_CRC_CTRL), \ - SR(MPC_CRC_RESULT_GB), \ - SR(MPC_CRC_RESULT_C), \ - SR(MPC_CRC_RESULT_AR), \ - SR(DOMAIN0_PG_CONFIG), \ - SR(DOMAIN1_PG_CONFIG), \ - SR(DOMAIN2_PG_CONFIG), \ - SR(DOMAIN3_PG_CONFIG), \ - SR(DOMAIN16_PG_CONFIG), \ - SR(DOMAIN17_PG_CONFIG), \ - SR(DOMAIN18_PG_CONFIG), \ - SR(DOMAIN0_PG_STATUS), \ - SR(DOMAIN1_PG_STATUS), \ - SR(DOMAIN2_PG_STATUS), \ - SR(DOMAIN3_PG_STATUS), \ - SR(DOMAIN16_PG_STATUS), \ - SR(DOMAIN17_PG_STATUS), \ - SR(DOMAIN18_PG_STATUS), \ - SR(D1VGA_CONTROL), \ - SR(D2VGA_CONTROL), \ - SR(D3VGA_CONTROL), \ - SR(D4VGA_CONTROL), \ - SR(D5VGA_CONTROL), \ - SR(D6VGA_CONTROL), \ - SR(DC_IP_REQUEST_CNTL), \ - SR(AZALIA_AUDIO_DTO), \ - SR(AZALIA_CONTROLLER_CLOCK_GATING), \ - SR(HPO_TOP_HW_CONTROL) - -static const struct dce_hwseq_registers hwseq_reg = { - HWSEQ_DCN31_REG_LIST() -}; - -#define HWSEQ_DCN31_MASK_SH_LIST(mask_sh)\ - HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ - HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \ - HWS_SF(, DCHUBBUB_ARB_HOSTVM_CNTL, DISABLE_HOSTVM_FORCE_ALLOW_PSTATE, mask_sh), \ - HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN16_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN17_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN18_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \ - HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh), \ - HWS_SF(, HPO_TOP_CLOCK_CONTROL, HPO_HDMISTREAMCLK_G_GATE_DIS, mask_sh), \ - HWS_SF(, DMU_MEM_PWR_CNTL, DMCU_ERAM_MEM_PWR_FORCE, mask_sh), \ - HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_UNASSIGNED_PWR_MODE, mask_sh), \ - HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_VBLANK_PWR_MODE, mask_sh), \ - HWS_SF(, MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, mask_sh), \ - HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh), \ - HWS_SF(, HPO_TOP_HW_CONTROL, HPO_IO_EN, mask_sh) - -static const struct dce_hwseq_shift hwseq_shift = { - HWSEQ_DCN31_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_hwseq_mask hwseq_mask = { - HWSEQ_DCN31_MASK_SH_LIST(_MASK) -}; -#define vmid_regs(id)\ -[id] = {\ - DCN20_VMID_REG_LIST(id)\ -} - -static const struct dcn_vmid_registers vmid_regs[] = { - vmid_regs(0), - vmid_regs(1), - vmid_regs(2), - vmid_regs(3), - vmid_regs(4), - vmid_regs(5), - vmid_regs(6), - vmid_regs(7), - vmid_regs(8), - vmid_regs(9), - vmid_regs(10), - vmid_regs(11), - vmid_regs(12), - vmid_regs(13), - vmid_regs(14), - vmid_regs(15) -}; - -static const struct dcn20_vmid_shift vmid_shifts = { - DCN20_VMID_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn20_vmid_mask vmid_masks = { - DCN20_VMID_MASK_SH_LIST(_MASK) -}; - -static const struct resource_caps res_cap_dcn31 = { - .num_timing_generator = 4, - .num_opp = 4, - .num_video_plane = 4, - .num_audio = 5, - .num_stream_encoder = 5, - .num_dig_link_enc = 5, - .num_hpo_dp_stream_encoder = 4, - .num_hpo_dp_link_encoder = 2, - .num_pll = 5, - .num_dwb = 1, - .num_ddc = 5, - .num_vmid = 16, - .num_mpc_3dlut = 2, - .num_dsc = 3, -}; - -static const struct dc_plane_cap plane_cap = { - .type = DC_PLANE_TYPE_DCN_UNIVERSAL, - .per_pixel_alpha = true, - - .pixel_format_support = { - .argb8888 = true, - .nv12 = true, - .fp16 = true, - .p010 = true, - .ayuv = false, - }, - - .max_upscale_factor = { - .argb8888 = 16000, - .nv12 = 16000, - .fp16 = 16000 - }, - - // 6:1 downscaling ratio: 1000/6 = 166.666 - .max_downscale_factor = { - .argb8888 = 167, - .nv12 = 167, - .fp16 = 167 - }, - 64, - 64 -}; - -static const struct dc_debug_options debug_defaults_drv = { - .disable_z10 = true, /*hw not support it*/ - .disable_dmcu = true, - .force_abm_enable = false, - .timing_trace = false, - .clock_trace = true, - .disable_pplib_clock_request = false, - .pipe_split_policy = MPC_SPLIT_DYNAMIC, - .force_single_disp_pipe_split = false, - .disable_dcc = DCC_ENABLE, - .vsr_support = true, - .performance_trace = false, - .max_downscale_src_width = 4096,/*upto true 4k*/ - .disable_pplib_wm_range = false, - .scl_reset_length10 = true, - .sanity_checks = false, - .underflow_assert_delay_us = 0xFFFFFFFF, - .dwb_fi_phase = -1, // -1 = disable, - .dmub_command_table = true, - .pstate_enabled = true, - .use_max_lb = true, - .enable_mem_low_power = { - .bits = { - .vga = true, - .i2c = true, - .dmcu = false, // This is previously known to cause hang on S3 cycles if enabled - .dscl = true, - .cm = true, - .mpc = true, - .optc = true, - .vpg = true, - .afmt = true, - } - }, - .enable_legacy_fast_update = true, - .using_dml2 = false, -}; - -static const struct dc_panel_config panel_config_defaults = { - .psr = { - .disable_psr = false, - .disallow_psrsu = false, - .disallow_replay = false, - }, - .ilr = { - .optimize_edp_link_rate = true, - }, -}; - -static void dcn31_dpp_destroy(struct dpp **dpp) -{ - kfree(TO_DCN20_DPP(*dpp)); - *dpp = NULL; -} - -static struct dpp *dcn31_dpp_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn3_dpp *dpp = - kzalloc(sizeof(struct dcn3_dpp), GFP_KERNEL); - - if (!dpp) - return NULL; - - if (dpp3_construct(dpp, ctx, inst, - &dpp_regs[inst], &tf_shift, &tf_mask)) - return &dpp->base; - - BREAK_TO_DEBUGGER(); - kfree(dpp); - return NULL; -} - -static struct output_pixel_processor *dcn31_opp_create( - struct dc_context *ctx, uint32_t inst) -{ - struct dcn20_opp *opp = - kzalloc(sizeof(struct dcn20_opp), GFP_KERNEL); - - if (!opp) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dcn20_opp_construct(opp, ctx, inst, - &opp_regs[inst], &opp_shift, &opp_mask); - return &opp->base; -} - -static struct dce_aux *dcn31_aux_engine_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct aux_engine_dce110 *aux_engine = - kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); - - if (!aux_engine) - return NULL; - - dce110_aux_engine_construct(aux_engine, ctx, inst, - SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, - &aux_engine_regs[inst], - &aux_mask, - &aux_shift, - ctx->dc->caps.extended_aux_timeout_support); - - return &aux_engine->base; -} -#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST_DCN30(id) } - -static const struct dce_i2c_registers i2c_hw_regs[] = { - i2c_inst_regs(1), - i2c_inst_regs(2), - i2c_inst_regs(3), - i2c_inst_regs(4), - i2c_inst_regs(5), -}; - -static const struct dce_i2c_shift i2c_shifts = { - I2C_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dce_i2c_mask i2c_masks = { - I2C_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -static struct dce_i2c_hw *dcn31_i2c_hw_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dce_i2c_hw *dce_i2c_hw = - kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); - - if (!dce_i2c_hw) - return NULL; - - dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst, - &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); - - return dce_i2c_hw; -} -static struct mpc *dcn31_mpc_create( - struct dc_context *ctx, - int num_mpcc, - int num_rmu) -{ - struct dcn30_mpc *mpc30 = kzalloc(sizeof(struct dcn30_mpc), - GFP_KERNEL); - - if (!mpc30) - return NULL; - - dcn30_mpc_construct(mpc30, ctx, - &mpc_regs, - &mpc_shift, - &mpc_mask, - num_mpcc, - num_rmu); - - return &mpc30->base; -} - -static struct hubbub *dcn31_hubbub_create(struct dc_context *ctx) -{ - int i; - - struct dcn20_hubbub *hubbub3 = kzalloc(sizeof(struct dcn20_hubbub), - GFP_KERNEL); - - if (!hubbub3) - return NULL; - - hubbub31_construct(hubbub3, ctx, - &hubbub_reg, - &hubbub_shift, - &hubbub_mask, - dcn3_16_ip.det_buffer_size_kbytes, - dcn3_16_ip.pixel_chunk_size_kbytes, - dcn3_16_ip.config_return_buffer_size_in_kbytes); - - - for (i = 0; i < res_cap_dcn31.num_vmid; i++) { - struct dcn20_vmid *vmid = &hubbub3->vmid[i]; - - vmid->ctx = ctx; - - vmid->regs = &vmid_regs[i]; - vmid->shifts = &vmid_shifts; - vmid->masks = &vmid_masks; - } - - return &hubbub3->base; -} - -static struct timing_generator *dcn31_timing_generator_create( - struct dc_context *ctx, - uint32_t instance) -{ - struct optc *tgn10 = - kzalloc(sizeof(struct optc), GFP_KERNEL); - - if (!tgn10) - return NULL; - - tgn10->base.inst = instance; - tgn10->base.ctx = ctx; - - tgn10->tg_regs = &optc_regs[instance]; - tgn10->tg_shift = &optc_shift; - tgn10->tg_mask = &optc_mask; - - dcn31_timing_generator_init(tgn10); - - return &tgn10->base; -} - -static const struct encoder_feature_support link_enc_feature = { - .max_hdmi_deep_color = COLOR_DEPTH_121212, - .max_hdmi_pixel_clock = 600000, - .hdmi_ycbcr420_supported = true, - .dp_ycbcr420_supported = true, - .fec_supported = true, - .flags.bits.IS_HBR2_CAPABLE = true, - .flags.bits.IS_HBR3_CAPABLE = true, - .flags.bits.IS_TPS3_CAPABLE = true, - .flags.bits.IS_TPS4_CAPABLE = true -}; - -static struct link_encoder *dcn31_link_encoder_create( - struct dc_context *ctx, - const struct encoder_init_data *enc_init_data) -{ - struct dcn20_link_encoder *enc20 = - kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); - - if (!enc20) - return NULL; - - dcn31_link_encoder_construct(enc20, - enc_init_data, - &link_enc_feature, - &link_enc_regs[enc_init_data->transmitter], - &link_enc_aux_regs[enc_init_data->channel - 1], - &link_enc_hpd_regs[enc_init_data->hpd_source], - &le_shift, - &le_mask); - - return &enc20->enc10.base; -} - -/* Create a minimal link encoder object not associated with a particular - * physical connector. - * resource_funcs.link_enc_create_minimal - */ -static struct link_encoder *dcn31_link_enc_create_minimal( - struct dc_context *ctx, enum engine_id eng_id) -{ - struct dcn20_link_encoder *enc20; - - if ((eng_id - ENGINE_ID_DIGA) > ctx->dc->res_pool->res_cap->num_dig_link_enc) - return NULL; - - enc20 = kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); - if (!enc20) - return NULL; - - dcn31_link_encoder_construct_minimal( - enc20, - ctx, - &link_enc_feature, - &link_enc_regs[eng_id - ENGINE_ID_DIGA], - eng_id); - - return &enc20->enc10.base; -} - -static struct panel_cntl *dcn31_panel_cntl_create(const struct panel_cntl_init_data *init_data) -{ - struct dcn31_panel_cntl *panel_cntl = - kzalloc(sizeof(struct dcn31_panel_cntl), GFP_KERNEL); - - if (!panel_cntl) - return NULL; - - dcn31_panel_cntl_construct(panel_cntl, init_data); - - return &panel_cntl->base; -} - -static void read_dce_straps( - struct dc_context *ctx, - struct resource_straps *straps) -{ - generic_reg_get(ctx, regDC_PINSTRAPS + BASE(regDC_PINSTRAPS_BASE_IDX), - FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio); - -} - -static struct audio *dcn31_create_audio( - struct dc_context *ctx, unsigned int inst) -{ - return dce_audio_create(ctx, inst, - &audio_regs[inst], &audio_shift, &audio_mask); -} - -static struct vpg *dcn31_vpg_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn31_vpg *vpg31 = kzalloc(sizeof(struct dcn31_vpg), GFP_KERNEL); - - if (!vpg31) - return NULL; - - vpg31_construct(vpg31, ctx, inst, - &vpg_regs[inst], - &vpg_shift, - &vpg_mask); - - return &vpg31->base; -} - -static struct afmt *dcn31_afmt_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn31_afmt *afmt31 = kzalloc(sizeof(struct dcn31_afmt), GFP_KERNEL); - - if (!afmt31) - return NULL; - - afmt31_construct(afmt31, ctx, inst, - &afmt_regs[inst], - &afmt_shift, - &afmt_mask); - - // Light sleep by default, no need to power down here - - return &afmt31->base; -} - - -static struct apg *dcn31_apg_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn31_apg *apg31 = kzalloc(sizeof(struct dcn31_apg), GFP_KERNEL); - - if (!apg31) - return NULL; - - apg31_construct(apg31, ctx, inst, - &apg_regs[inst], - &apg_shift, - &apg_mask); - - return &apg31->base; -} - - -static struct stream_encoder *dcn316_stream_encoder_create( - enum engine_id eng_id, - struct dc_context *ctx) -{ - struct dcn10_stream_encoder *enc1; - struct vpg *vpg; - struct afmt *afmt; - int vpg_inst; - int afmt_inst; - - /* Mapping of VPG, AFMT, DME register blocks to DIO block instance */ - if (eng_id <= ENGINE_ID_DIGF) { - vpg_inst = eng_id; - afmt_inst = eng_id; - } else - return NULL; - - enc1 = kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL); - vpg = dcn31_vpg_create(ctx, vpg_inst); - afmt = dcn31_afmt_create(ctx, afmt_inst); - - if (!enc1 || !vpg || !afmt) { - kfree(enc1); - kfree(vpg); - kfree(afmt); - return NULL; - } - - dcn30_dio_stream_encoder_construct(enc1, ctx, ctx->dc_bios, - eng_id, vpg, afmt, - &stream_enc_regs[eng_id], - &se_shift, &se_mask); - - return &enc1->base; -} - - -static struct hpo_dp_stream_encoder *dcn31_hpo_dp_stream_encoder_create( - enum engine_id eng_id, - struct dc_context *ctx) -{ - struct dcn31_hpo_dp_stream_encoder *hpo_dp_enc31; - struct vpg *vpg; - struct apg *apg; - uint32_t hpo_dp_inst; - uint32_t vpg_inst; - uint32_t apg_inst; - - ASSERT((eng_id >= ENGINE_ID_HPO_DP_0) && (eng_id <= ENGINE_ID_HPO_DP_3)); - hpo_dp_inst = eng_id - ENGINE_ID_HPO_DP_0; - - /* Mapping of VPG register blocks to HPO DP block instance: - * VPG[6] -> HPO_DP[0] - * VPG[7] -> HPO_DP[1] - * VPG[8] -> HPO_DP[2] - * VPG[9] -> HPO_DP[3] - */ - vpg_inst = hpo_dp_inst + 6; - - /* Mapping of APG register blocks to HPO DP block instance: - * APG[0] -> HPO_DP[0] - * APG[1] -> HPO_DP[1] - * APG[2] -> HPO_DP[2] - * APG[3] -> HPO_DP[3] - */ - apg_inst = hpo_dp_inst; - - /* allocate HPO stream encoder and create VPG sub-block */ - hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_stream_encoder), GFP_KERNEL); - vpg = dcn31_vpg_create(ctx, vpg_inst); - apg = dcn31_apg_create(ctx, apg_inst); - - if (!hpo_dp_enc31 || !vpg || !apg) { - kfree(hpo_dp_enc31); - kfree(vpg); - kfree(apg); - return NULL; - } - - dcn31_hpo_dp_stream_encoder_construct(hpo_dp_enc31, ctx, ctx->dc_bios, - hpo_dp_inst, eng_id, vpg, apg, - &hpo_dp_stream_enc_regs[hpo_dp_inst], - &hpo_dp_se_shift, &hpo_dp_se_mask); - - return &hpo_dp_enc31->base; -} - -static struct hpo_dp_link_encoder *dcn31_hpo_dp_link_encoder_create( - uint8_t inst, - struct dc_context *ctx) -{ - struct dcn31_hpo_dp_link_encoder *hpo_dp_enc31; - - /* allocate HPO link encoder */ - hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_link_encoder), GFP_KERNEL); - - hpo_dp_link_encoder31_construct(hpo_dp_enc31, ctx, inst, - &hpo_dp_link_enc_regs[inst], - &hpo_dp_le_shift, &hpo_dp_le_mask); - - return &hpo_dp_enc31->base; -} - - -static struct dce_hwseq *dcn31_hwseq_create( - struct dc_context *ctx) -{ - struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); - - if (hws) { - hws->ctx = ctx; - hws->regs = &hwseq_reg; - hws->shifts = &hwseq_shift; - hws->masks = &hwseq_mask; - } - return hws; -} -static const struct resource_create_funcs res_create_funcs = { - .read_dce_straps = read_dce_straps, - .create_audio = dcn31_create_audio, - .create_stream_encoder = dcn316_stream_encoder_create, - .create_hpo_dp_stream_encoder = dcn31_hpo_dp_stream_encoder_create, - .create_hpo_dp_link_encoder = dcn31_hpo_dp_link_encoder_create, - .create_hwseq = dcn31_hwseq_create, -}; - -static void dcn316_resource_destruct(struct dcn316_resource_pool *pool) -{ - unsigned int i; - - for (i = 0; i < pool->base.stream_enc_count; i++) { - if (pool->base.stream_enc[i] != NULL) { - if (pool->base.stream_enc[i]->vpg != NULL) { - kfree(DCN30_VPG_FROM_VPG(pool->base.stream_enc[i]->vpg)); - pool->base.stream_enc[i]->vpg = NULL; - } - if (pool->base.stream_enc[i]->afmt != NULL) { - kfree(DCN30_AFMT_FROM_AFMT(pool->base.stream_enc[i]->afmt)); - pool->base.stream_enc[i]->afmt = NULL; - } - kfree(DCN10STRENC_FROM_STRENC(pool->base.stream_enc[i])); - pool->base.stream_enc[i] = NULL; - } - } - - for (i = 0; i < pool->base.hpo_dp_stream_enc_count; i++) { - if (pool->base.hpo_dp_stream_enc[i] != NULL) { - if (pool->base.hpo_dp_stream_enc[i]->vpg != NULL) { - kfree(DCN30_VPG_FROM_VPG(pool->base.hpo_dp_stream_enc[i]->vpg)); - pool->base.hpo_dp_stream_enc[i]->vpg = NULL; - } - if (pool->base.hpo_dp_stream_enc[i]->apg != NULL) { - kfree(DCN31_APG_FROM_APG(pool->base.hpo_dp_stream_enc[i]->apg)); - pool->base.hpo_dp_stream_enc[i]->apg = NULL; - } - kfree(DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(pool->base.hpo_dp_stream_enc[i])); - pool->base.hpo_dp_stream_enc[i] = NULL; - } - } - - for (i = 0; i < pool->base.hpo_dp_link_enc_count; i++) { - if (pool->base.hpo_dp_link_enc[i] != NULL) { - kfree(DCN3_1_HPO_DP_LINK_ENC_FROM_HPO_LINK_ENC(pool->base.hpo_dp_link_enc[i])); - pool->base.hpo_dp_link_enc[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_dsc; i++) { - if (pool->base.dscs[i] != NULL) - dcn20_dsc_destroy(&pool->base.dscs[i]); - } - - if (pool->base.mpc != NULL) { - kfree(TO_DCN20_MPC(pool->base.mpc)); - pool->base.mpc = NULL; - } - if (pool->base.hubbub != NULL) { - kfree(pool->base.hubbub); - pool->base.hubbub = NULL; - } - for (i = 0; i < pool->base.pipe_count; i++) { - if (pool->base.dpps[i] != NULL) - dcn31_dpp_destroy(&pool->base.dpps[i]); - - if (pool->base.ipps[i] != NULL) - pool->base.ipps[i]->funcs->ipp_destroy(&pool->base.ipps[i]); - - if (pool->base.hubps[i] != NULL) { - kfree(TO_DCN20_HUBP(pool->base.hubps[i])); - pool->base.hubps[i] = NULL; - } - - if (pool->base.irqs != NULL) { - dal_irq_service_destroy(&pool->base.irqs); - } - } - - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - if (pool->base.engines[i] != NULL) - dce110_engine_destroy(&pool->base.engines[i]); - if (pool->base.hw_i2cs[i] != NULL) { - kfree(pool->base.hw_i2cs[i]); - pool->base.hw_i2cs[i] = NULL; - } - if (pool->base.sw_i2cs[i] != NULL) { - kfree(pool->base.sw_i2cs[i]); - pool->base.sw_i2cs[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_opp; i++) { - if (pool->base.opps[i] != NULL) - pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]); - } - - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - if (pool->base.timing_generators[i] != NULL) { - kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i])); - pool->base.timing_generators[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_dwb; i++) { - if (pool->base.dwbc[i] != NULL) { - kfree(TO_DCN30_DWBC(pool->base.dwbc[i])); - pool->base.dwbc[i] = NULL; - } - if (pool->base.mcif_wb[i] != NULL) { - kfree(TO_DCN30_MMHUBBUB(pool->base.mcif_wb[i])); - pool->base.mcif_wb[i] = NULL; - } - } - - for (i = 0; i < pool->base.audio_count; i++) { - if (pool->base.audios[i]) - dce_aud_destroy(&pool->base.audios[i]); - } - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] != NULL) { - dcn20_clock_source_destroy(&pool->base.clock_sources[i]); - pool->base.clock_sources[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_mpc_3dlut; i++) { - if (pool->base.mpc_lut[i] != NULL) { - dc_3dlut_func_release(pool->base.mpc_lut[i]); - pool->base.mpc_lut[i] = NULL; - } - if (pool->base.mpc_shaper[i] != NULL) { - dc_transfer_func_release(pool->base.mpc_shaper[i]); - pool->base.mpc_shaper[i] = NULL; - } - } - - if (pool->base.dp_clock_source != NULL) { - dcn20_clock_source_destroy(&pool->base.dp_clock_source); - pool->base.dp_clock_source = NULL; - } - - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - if (pool->base.multiple_abms[i] != NULL) - dce_abm_destroy(&pool->base.multiple_abms[i]); - } - - if (pool->base.psr != NULL) - dmub_psr_destroy(&pool->base.psr); - - if (pool->base.dccg != NULL) - dcn_dccg_destroy(&pool->base.dccg); -} - -static struct hubp *dcn31_hubp_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn20_hubp *hubp2 = - kzalloc(sizeof(struct dcn20_hubp), GFP_KERNEL); - - if (!hubp2) - return NULL; - - if (hubp31_construct(hubp2, ctx, inst, - &hubp_regs[inst], &hubp_shift, &hubp_mask)) - return &hubp2->base; - - BREAK_TO_DEBUGGER(); - kfree(hubp2); - return NULL; -} - -static bool dcn31_dwbc_create(struct dc_context *ctx, struct resource_pool *pool) -{ - int i; - uint32_t pipe_count = pool->res_cap->num_dwb; - - for (i = 0; i < pipe_count; i++) { - struct dcn30_dwbc *dwbc30 = kzalloc(sizeof(struct dcn30_dwbc), - GFP_KERNEL); - - if (!dwbc30) { - dm_error("DC: failed to create dwbc30!\n"); - return false; - } - - dcn30_dwbc_construct(dwbc30, ctx, - &dwbc30_regs[i], - &dwbc30_shift, - &dwbc30_mask, - i); - - pool->dwbc[i] = &dwbc30->base; - } - return true; -} - -static bool dcn31_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool) -{ - int i; - uint32_t pipe_count = pool->res_cap->num_dwb; - - for (i = 0; i < pipe_count; i++) { - struct dcn30_mmhubbub *mcif_wb30 = kzalloc(sizeof(struct dcn30_mmhubbub), - GFP_KERNEL); - - if (!mcif_wb30) { - dm_error("DC: failed to create mcif_wb30!\n"); - return false; - } - - dcn30_mmhubbub_construct(mcif_wb30, ctx, - &mcif_wb30_regs[i], - &mcif_wb30_shift, - &mcif_wb30_mask, - i); - - pool->mcif_wb[i] = &mcif_wb30->base; - } - return true; -} - -static struct display_stream_compressor *dcn31_dsc_create( - struct dc_context *ctx, uint32_t inst) -{ - struct dcn20_dsc *dsc = - kzalloc(sizeof(struct dcn20_dsc), GFP_KERNEL); - - if (!dsc) { - BREAK_TO_DEBUGGER(); - return NULL; - } - - dsc2_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask); - return &dsc->base; -} - -static void dcn316_destroy_resource_pool(struct resource_pool **pool) -{ - struct dcn316_resource_pool *dcn31_pool = TO_DCN316_RES_POOL(*pool); - - dcn316_resource_destruct(dcn31_pool); - kfree(dcn31_pool); - *pool = NULL; -} - -static struct clock_source *dcn31_clock_source_create( - struct dc_context *ctx, - struct dc_bios *bios, - enum clock_source_id id, - const struct dce110_clk_src_regs *regs, - bool dp_clk_src) -{ - struct dce110_clk_src *clk_src = - kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); - - if (!clk_src) - return NULL; - - if (dcn31_clk_src_construct(clk_src, ctx, bios, id, - regs, &cs_shift, &cs_mask)) { - clk_src->base.dp_clk_src = dp_clk_src; - return &clk_src->base; - } - - kfree(clk_src); - - BREAK_TO_DEBUGGER(); - return NULL; -} - -static bool is_dual_plane(enum surface_pixel_format format) -{ - return format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN || format == SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA; -} - -static int dcn316_populate_dml_pipes_from_context( - struct dc *dc, struct dc_state *context, - display_e2e_pipe_params_st *pipes, - bool fast_validate) -{ - int i, pipe_cnt; - struct resource_context *res_ctx = &context->res_ctx; - struct pipe_ctx *pipe; - const int max_usable_det = context->bw_ctx.dml.ip.config_return_buffer_size_in_kbytes - DCN3_16_MIN_COMPBUF_SIZE_KB; - - DC_FP_START(); - dcn31x_populate_dml_pipes_from_context(dc, context, pipes, fast_validate); - DC_FP_END(); - - for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) { - struct dc_crtc_timing *timing; - - if (!res_ctx->pipe_ctx[i].stream) - continue; - pipe = &res_ctx->pipe_ctx[i]; - timing = &pipe->stream->timing; - - /* - * Immediate flip can be set dynamically after enabling the plane. - * We need to require support for immediate flip or underflow can be - * intermittently experienced depending on peak b/w requirements. - */ - pipes[pipe_cnt].pipe.src.immediate_flip = true; - - pipes[pipe_cnt].pipe.src.unbounded_req_mode = false; - pipes[pipe_cnt].pipe.dest.vfront_porch = timing->v_front_porch; - pipes[pipe_cnt].pipe.src.dcc_rate = 3; - pipes[pipe_cnt].dout.dsc_input_bpc = 0; - DC_FP_START(); - dcn31_zero_pipe_dcc_fraction(pipes, pipe_cnt); - DC_FP_END(); - - if (pipes[pipe_cnt].dout.dsc_enable) { - switch (timing->display_color_depth) { - case COLOR_DEPTH_888: - pipes[pipe_cnt].dout.dsc_input_bpc = 8; - break; - case COLOR_DEPTH_101010: - pipes[pipe_cnt].dout.dsc_input_bpc = 10; - break; - case COLOR_DEPTH_121212: - pipes[pipe_cnt].dout.dsc_input_bpc = 12; - break; - default: - ASSERT(0); - break; - } - } - - pipe_cnt++; - } - - if (pipe_cnt) - context->bw_ctx.dml.ip.det_buffer_size_kbytes = - (max_usable_det / DCN3_16_CRB_SEGMENT_SIZE_KB / pipe_cnt) * DCN3_16_CRB_SEGMENT_SIZE_KB; - if (context->bw_ctx.dml.ip.det_buffer_size_kbytes > DCN3_16_MAX_DET_SIZE) - context->bw_ctx.dml.ip.det_buffer_size_kbytes = DCN3_16_MAX_DET_SIZE; - ASSERT(context->bw_ctx.dml.ip.det_buffer_size_kbytes >= DCN3_16_DEFAULT_DET_SIZE); - dc->config.enable_4to1MPC = false; - if (pipe_cnt == 1 && pipe->plane_state && !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; - context->bw_ctx.dml.ip.det_buffer_size_kbytes = - (max_usable_det / DCN3_16_CRB_SEGMENT_SIZE_KB / 4) * DCN3_16_CRB_SEGMENT_SIZE_KB; - } else if (!is_dual_plane(pipe->plane_state->format)) { - context->bw_ctx.dml.ip.det_buffer_size_kbytes = 192; - pipes[0].pipe.src.unbounded_req_mode = true; - } - } - - return pipe_cnt; -} - -static void dcn316_get_panel_config_defaults(struct dc_panel_config *panel_config) -{ - *panel_config = panel_config_defaults; -} - -static struct dc_cap_funcs cap_funcs = { - .get_dcc_compression_cap = dcn20_get_dcc_compression_cap -}; - -static struct resource_funcs dcn316_res_pool_funcs = { - .destroy = dcn316_destroy_resource_pool, - .link_enc_create = dcn31_link_encoder_create, - .link_enc_create_minimal = dcn31_link_enc_create_minimal, - .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, - .calculate_wm_and_dlg = dcn31_calculate_wm_and_dlg, - .update_soc_for_wm_a = dcn31_update_soc_for_wm_a, - .populate_dml_pipes = dcn316_populate_dml_pipes_from_context, - .acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer, - .release_pipe = dcn20_release_pipe, - .add_stream_to_ctx = dcn30_add_stream_to_ctx, - .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource, - .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, - .populate_dml_writeback_from_context = dcn31_populate_dml_writeback_from_context, - .set_mcif_arb_params = dcn31_set_mcif_arb_params, - .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 = dcn316_update_bw_bounding_box, - .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, - .get_panel_config_defaults = dcn316_get_panel_config_defaults, -}; - -static bool dcn316_resource_construct( - uint8_t num_virtual_links, - struct dc *dc, - struct dcn316_resource_pool *pool) -{ - int i; - struct dc_context *ctx = dc->ctx; - struct irq_service_init_data init_data; - - ctx->dc_bios->regs = &bios_regs; - - pool->base.res_cap = &res_cap_dcn31; - - pool->base.funcs = &dcn316_res_pool_funcs; - - /************************************************* - * Resource + asic cap harcoding * - *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; - pool->base.pipe_count = pool->base.res_cap->num_timing_generator; - 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 = 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; - dc->caps.max_slave_planes = 2; - dc->caps.max_slave_yuv_planes = 2; - dc->caps.max_slave_rgb_planes = 2; - dc->caps.post_blend_color_processing = true; - dc->caps.force_dp_tps4_for_cp2520 = true; - if (dc->config.forceHBR2CP2520) - dc->caps.force_dp_tps4_for_cp2520 = false; - dc->caps.dp_hpo = true; - dc->caps.dp_hdmi21_pcon_support = true; - dc->caps.edp_dsc_support = true; - dc->caps.extended_aux_timeout_support = true; - dc->caps.dmcub_support = true; - dc->caps.is_apu = true; - - /* Color pipeline capabilities */ - dc->caps.color.dpp.dcn_arch = 1; - dc->caps.color.dpp.input_lut_shared = 0; - dc->caps.color.dpp.icsc = 1; - dc->caps.color.dpp.dgam_ram = 0; // must use gamma_corr - dc->caps.color.dpp.dgam_rom_caps.srgb = 1; - dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1; - dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 1; - dc->caps.color.dpp.dgam_rom_caps.pq = 1; - dc->caps.color.dpp.dgam_rom_caps.hlg = 1; - dc->caps.color.dpp.post_csc = 1; - dc->caps.color.dpp.gamma_corr = 1; - dc->caps.color.dpp.dgam_rom_for_yuv = 0; - - dc->caps.color.dpp.hw_3d_lut = 1; - dc->caps.color.dpp.ogam_ram = 1; - // no OGAM ROM on DCN301 - dc->caps.color.dpp.ogam_rom_caps.srgb = 0; - dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0; - dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0; - dc->caps.color.dpp.ogam_rom_caps.pq = 0; - dc->caps.color.dpp.ogam_rom_caps.hlg = 0; - dc->caps.color.dpp.ocsc = 0; - - dc->caps.color.mpc.gamut_remap = 1; - dc->caps.color.mpc.num_3dluts = pool->base.res_cap->num_mpc_3dlut; //2 - dc->caps.color.mpc.ogam_ram = 1; - dc->caps.color.mpc.ogam_rom_caps.srgb = 0; - dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0; - dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0; - dc->caps.color.mpc.ogam_rom_caps.pq = 0; - dc->caps.color.mpc.ogam_rom_caps.hlg = 0; - dc->caps.color.mpc.ocsc = 1; - - /* read VBIOS LTTPR caps */ - { - if (ctx->dc_bios->funcs->get_lttpr_caps) { - enum bp_result bp_query_result; - uint8_t is_vbios_lttpr_enable = 0; - - bp_query_result = ctx->dc_bios->funcs->get_lttpr_caps(ctx->dc_bios, &is_vbios_lttpr_enable); - dc->caps.vbios_lttpr_enable = (bp_query_result == BP_RESULT_OK) && !!is_vbios_lttpr_enable; - } - - /* interop bit is implicit */ - { - dc->caps.vbios_lttpr_aware = true; - } - } - - if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) - dc->debug = debug_defaults_drv; - - // Init the vm_helper - if (dc->vm_helper) - vm_helper_init(dc->vm_helper, 16); - - /************************************************* - * Create resources * - *************************************************/ - - /* Clock Sources for Pixel Clock*/ - pool->base.clock_sources[DCN31_CLK_SRC_PLL0] = - dcn31_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL0, - &clk_src_regs[0], false); - pool->base.clock_sources[DCN31_CLK_SRC_PLL1] = - dcn31_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL1, - &clk_src_regs[1], false); - pool->base.clock_sources[DCN31_CLK_SRC_PLL2] = - dcn31_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL2, - &clk_src_regs[2], false); - pool->base.clock_sources[DCN31_CLK_SRC_PLL3] = - dcn31_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL3, - &clk_src_regs[3], false); - pool->base.clock_sources[DCN31_CLK_SRC_PLL4] = - dcn31_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL4, - &clk_src_regs[4], false); - - pool->base.clk_src_count = DCN30_CLK_SRC_TOTAL; - - /* todo: not reuse phy_pll registers */ - pool->base.dp_clock_source = - dcn31_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_ID_DP_DTO, - &clk_src_regs[0], true); - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] == NULL) { - dm_error("DC: failed to create clock sources!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - } - - /* TODO: DCCG */ - pool->base.dccg = dccg31_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask); - if (pool->base.dccg == NULL) { - dm_error("DC: failed to create dccg!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - - /* TODO: IRQ */ - init_data.ctx = dc->ctx; - pool->base.irqs = dal_irq_service_dcn31_create(&init_data); - if (!pool->base.irqs) - goto create_fail; - - /* HUBBUB */ - pool->base.hubbub = dcn31_hubbub_create(ctx); - if (pool->base.hubbub == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create hubbub!\n"); - goto create_fail; - } - - /* HUBPs, DPPs, OPPs and TGs */ - for (i = 0; i < pool->base.pipe_count; i++) { - pool->base.hubps[i] = dcn31_hubp_create(ctx, i); - if (pool->base.hubps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create hubps!\n"); - goto create_fail; - } - - pool->base.dpps[i] = dcn31_dpp_create(ctx, i); - if (pool->base.dpps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create dpps!\n"); - goto create_fail; - } - } - - for (i = 0; i < pool->base.res_cap->num_opp; i++) { - pool->base.opps[i] = dcn31_opp_create(ctx, i); - if (pool->base.opps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create output pixel processor!\n"); - goto create_fail; - } - } - - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - pool->base.timing_generators[i] = dcn31_timing_generator_create( - ctx, i); - if (pool->base.timing_generators[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create tg!\n"); - goto create_fail; - } - } - pool->base.timing_generator_count = i; - - /* PSR */ - pool->base.psr = dmub_psr_create(ctx); - if (pool->base.psr == NULL) { - dm_error("DC: failed to create psr obj!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - - /* ABM */ - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - pool->base.multiple_abms[i] = dmub_abm_create(ctx, - &abm_regs[i], - &abm_shift, - &abm_mask); - if (pool->base.multiple_abms[i] == NULL) { - dm_error("DC: failed to create abm for pipe %d!\n", i); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - } - - /* MPC and DSC */ - pool->base.mpc = dcn31_mpc_create(ctx, pool->base.mpcc_count, pool->base.res_cap->num_mpc_3dlut); - if (pool->base.mpc == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create mpc!\n"); - goto create_fail; - } - - for (i = 0; i < pool->base.res_cap->num_dsc; i++) { - pool->base.dscs[i] = dcn31_dsc_create(ctx, i); - if (pool->base.dscs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create display stream compressor %d!\n", i); - goto create_fail; - } - } - - /* DWB and MMHUBBUB */ - if (!dcn31_dwbc_create(ctx, &pool->base)) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create dwbc!\n"); - goto create_fail; - } - - if (!dcn31_mmhubbub_create(ctx, &pool->base)) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create mcif_wb!\n"); - goto create_fail; - } - - /* AUX and I2C */ - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - pool->base.engines[i] = dcn31_aux_engine_create(ctx, i); - if (pool->base.engines[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create aux engine!!\n"); - goto create_fail; - } - pool->base.hw_i2cs[i] = dcn31_i2c_hw_create(ctx, i); - if (pool->base.hw_i2cs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create hw i2c!!\n"); - goto create_fail; - } - pool->base.sw_i2cs[i] = NULL; - } - - /* Audio, Stream Encoders including HPO and virtual, MPC 3D LUTs */ - if (!resource_construct(num_virtual_links, dc, &pool->base, - &res_create_funcs)) - goto create_fail; - - /* HW Sequencer and Plane caps */ - dcn31_hw_sequencer_construct(dc); - - dc->caps.max_planes = pool->base.pipe_count; - - for (i = 0; i < dc->caps.max_planes; ++i) - dc->caps.planes[i] = plane_cap; - - dc->cap_funcs = cap_funcs; - - dc->dcn_ip->max_num_dpp = dcn3_16_ip.max_num_dpp; - - return true; - -create_fail: - - dcn316_resource_destruct(pool); - - return false; -} - -struct resource_pool *dcn316_create_resource_pool( - const struct dc_init_data *init_data, - struct dc *dc) -{ - struct dcn316_resource_pool *pool = - kzalloc(sizeof(struct dcn316_resource_pool), GFP_KERNEL); - - if (!pool) - return NULL; - - if (dcn316_resource_construct(init_data->num_virtual_links, dc, pool)) - return &pool->base; - - BREAK_TO_DEBUGGER(); - kfree(pool); - return NULL; -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.h b/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.h deleted file mode 100644 index aba6d634131b41..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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 _DCN316_RESOURCE_H_ -#define _DCN316_RESOURCE_H_ - -#include "core_types.h" - -#define TO_DCN316_RES_POOL(pool)\ - container_of(pool, struct dcn316_resource_pool, base) - -extern struct _vcs_dpi_ip_params_st dcn3_16_ip; - -struct dcn316_resource_pool { - struct resource_pool base; -}; - -struct resource_pool *dcn316_create_resource_pool( - const struct dc_init_data *init_data, - struct dc *dc); - -#endif /* _DCN316_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/Makefile b/drivers/gpu/drm/amd/display/dc/dcn32/Makefile index 8bb251307247e1..5314770fff1c06 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn32/Makefile @@ -10,10 +10,10 @@ # # Makefile for dcn32. -DCN32 = dcn32_resource.o dcn32_hubbub.o dcn32_init.o dcn32_dccg.o \ - dcn32_dccg.o dcn32_optc.o dcn32_mmhubbub.o dcn32_hubp.o dcn32_dpp.o \ - dcn32_dio_stream_encoder.o dcn32_dio_link_encoder.o dcn32_hpo_dp_link_encoder.o \ - dcn32_resource_helpers.o dcn32_mpc.o +DCN32 = dcn32_hubbub.o dcn32_dccg.o \ + dcn32_mmhubbub.o dcn32_dpp.o dcn32_hubp.o dcn32_mpc.o \ + dcn32_dio_stream_encoder.o dcn32_dio_link_encoder.o dcn32_resource_helpers.o \ + dcn32_hpo_dp_link_encoder.o AMD_DAL_DCN32 = $(addprefix $(AMDDALPATH)/dc/dcn32/,$(DCN32)) diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c deleted file mode 100644 index 427cfc8c24a4b7..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * 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 "dce110/dce110_hwseq.h" -#include "dcn10/dcn10_hwseq.h" -#include "dcn20/dcn20_hwseq.h" -#include "dcn21/dcn21_hwseq.h" -#include "dcn30/dcn30_hwseq.h" -#include "dcn31/dcn31_hwseq.h" -#include "dcn32/dcn32_hwseq.h" -#include "dcn32_init.h" - -static const struct hw_sequencer_funcs dcn32_funcs = { - .program_gamut_remap = dcn30_program_gamut_remap, - .init_hw = dcn32_init_hw, - .apply_ctx_to_hw = dce110_apply_ctx_to_hw, - .apply_ctx_for_surface = NULL, - .program_front_end_for_ctx = dcn20_program_front_end_for_ctx, - .wait_for_pending_cleared = dcn10_wait_for_pending_cleared, - .post_unlock_program_front_end = dcn20_post_unlock_program_front_end, - .update_plane_addr = dcn20_update_plane_addr, - .update_dchub = dcn10_update_dchub, - .update_pending_status = dcn10_update_pending_status, - .program_output_csc = dcn20_program_output_csc, - .enable_accelerated_mode = dce110_enable_accelerated_mode, - .enable_timing_synchronization = dcn10_enable_timing_synchronization, - .enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset, - .update_info_frame = dcn31_update_info_frame, - .send_immediate_sdp_message = dcn10_send_immediate_sdp_message, - .enable_stream = dcn20_enable_stream, - .disable_stream = dce110_disable_stream, - .unblank_stream = dcn32_unblank_stream, - .blank_stream = dce110_blank_stream, - .enable_audio_stream = dce110_enable_audio_stream, - .disable_audio_stream = dce110_disable_audio_stream, - .disable_plane = dcn20_disable_plane, - .disable_pixel_data = dcn20_disable_pixel_data, - .pipe_control_lock = dcn20_pipe_control_lock, - .interdependent_update_lock = dcn10_lock_all_pipes, - .cursor_lock = dcn10_cursor_lock, - .prepare_bandwidth = dcn32_prepare_bandwidth, - .optimize_bandwidth = dcn20_optimize_bandwidth, - .update_bandwidth = dcn20_update_bandwidth, - .set_drr = dcn10_set_drr, - .get_position = dcn10_get_position, - .set_static_screen_control = dcn30_set_static_screen_control, - .setup_stereo = dcn10_setup_stereo, - .set_avmute = dcn30_set_avmute, - .log_hw_state = dcn10_log_hw_state, - .get_hw_state = dcn10_get_hw_state, - .clear_status_bits = dcn10_clear_status_bits, - .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, - .edp_backlight_control = dce110_edp_backlight_control, - .edp_power_control = dce110_edp_power_control, - .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, - .edp_wait_for_T12 = dce110_edp_wait_for_T12, - .set_cursor_position = dcn10_set_cursor_position, - .set_cursor_attribute = dcn10_set_cursor_attribute, - .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level, - .setup_periodic_interrupt = dcn10_setup_periodic_interrupt, - .set_clock = dcn10_set_clock, - .get_clock = dcn10_get_clock, - .program_triplebuffer = dcn20_program_triple_buffer, - .enable_writeback = dcn30_enable_writeback, - .disable_writeback = dcn30_disable_writeback, - .update_writeback = dcn30_update_writeback, - .mmhubbub_warmup = dcn30_mmhubbub_warmup, - .dmdata_status_done = dcn20_dmdata_status_done, - .program_dmdata_engine = dcn30_program_dmdata_engine, - .set_dmdata_attributes = dcn20_set_dmdata_attributes, - .init_sys_ctx = dcn20_init_sys_ctx, - .init_vm_ctx = dcn20_init_vm_ctx, - .set_flip_control_gsl = dcn20_set_flip_control_gsl, - .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync, - .calc_vupdate_position = dcn10_calc_vupdate_position, - .apply_idle_power_optimizations = dcn32_apply_idle_power_optimizations, - .does_plane_fit_in_mall = NULL, - .set_backlight_level = dcn21_set_backlight_level, - .set_abm_immediate_disable = dcn21_set_abm_immediate_disable, - .hardware_release = dcn30_hardware_release, - .set_pipe = dcn21_set_pipe, - .enable_lvds_link_output = dce110_enable_lvds_link_output, - .enable_tmds_link_output = dce110_enable_tmds_link_output, - .enable_dp_link_output = dce110_enable_dp_link_output, - .disable_link_output = dcn32_disable_link_output, - .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 = dcn10_update_visual_confirm_color, - .subvp_pipe_control_lock_fast = dcn32_subvp_pipe_control_lock_fast, - .update_phantom_vp_position = dcn32_update_phantom_vp_position, - .update_dsc_pg = dcn32_update_dsc_pg, - .apply_update_flags_for_phantom = dcn32_apply_update_flags_for_phantom, - .blank_phantom = dcn32_blank_phantom, - .is_pipe_topology_transition_seamless = dcn32_is_pipe_topology_transition_seamless, -}; - -static const struct hwseq_private_funcs dcn32_private_funcs = { - .init_pipes = dcn10_init_pipes, - .update_plane_addr = dcn20_update_plane_addr, - .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, - .update_mpcc = dcn20_update_mpcc, - .set_input_transfer_func = dcn32_set_input_transfer_func, - .set_output_transfer_func = dcn32_set_output_transfer_func, - .power_down = dce110_power_down, - .enable_display_power_gating = dcn10_dummy_display_power_gating, - .blank_pixel_data = dcn20_blank_pixel_data, - .reset_hw_ctx_wrap = dcn20_reset_hw_ctx_wrap, - .enable_stream_timing = dcn20_enable_stream_timing, - .edp_backlight_control = dce110_edp_backlight_control, - .disable_stream_gating = dcn20_disable_stream_gating, - .enable_stream_gating = dcn20_enable_stream_gating, - .setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt, - .did_underflow_occur = dcn10_did_underflow_occur, - .init_blank = dcn32_init_blank, - .disable_vga = dcn20_disable_vga, - .bios_golden_init = dcn10_bios_golden_init, - .plane_atomic_disable = dcn20_plane_atomic_disable, - .plane_atomic_power_down = dcn10_plane_atomic_power_down, - .enable_power_gating_plane = dcn32_enable_power_gating_plane, - .hubp_pg_control = dcn32_hubp_pg_control, - .program_all_writeback_pipes_in_tree = dcn30_program_all_writeback_pipes_in_tree, - .update_odm = dcn32_update_odm, - .dsc_pg_control = dcn32_dsc_pg_control, - .dsc_pg_status = dcn32_dsc_pg_status, - .set_hdr_multiplier = dcn10_set_hdr_multiplier, - .verify_allow_pstate_change_high = dcn10_verify_allow_pstate_change_high, - .wait_for_blank_complete = dcn20_wait_for_blank_complete, - .dccg_init = dcn20_dccg_init, - .set_mcm_luts = dcn32_set_mcm_luts, - .program_mall_pipe_config = dcn32_program_mall_pipe_config, - .update_force_pstate = dcn32_update_force_pstate, - .update_mall_sel = dcn32_update_mall_sel, - .calculate_dccg_k1_k2_values = dcn32_calculate_dccg_k1_k2_values, - .set_pixels_per_cycle = dcn32_set_pixels_per_cycle, - .resync_fifo_dccg_dio = dcn32_resync_fifo_dccg_dio, - .is_dp_dig_pixel_rate_div_policy = dcn32_is_dp_dig_pixel_rate_div_policy, -}; - -void dcn32_hw_sequencer_init_functions(struct dc *dc) -{ - dc->hwss = dcn32_funcs; - dc->hwseq->funcs = dcn32_private_funcs; - -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.h b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.h deleted file mode 100644 index 89a591eb2c230a..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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_DCN32_INIT_H__ -#define __DC_DCN32_INIT_H__ - -struct dc; - -void dcn32_hw_sequencer_init_functions(struct dc *dc); - -#endif /* __DC_DCN32_INIT_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c index 994b21ed272f17..e789e654c38705 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c @@ -71,12 +71,13 @@ void mpc32_power_on_blnd_lut( { struct dcn30_mpc *mpc30 = TO_DCN30_MPC(mpc); + REG_SET(MPCC_MCM_MEM_PWR_CTRL[mpcc_id], 0, MPCC_MCM_1DLUT_MEM_PWR_DIS, power_on); + if (mpc->ctx->dc->debug.enable_mem_low_power.bits.cm) { if (power_on) { REG_UPDATE(MPCC_MCM_MEM_PWR_CTRL[mpcc_id], MPCC_MCM_1DLUT_MEM_PWR_FORCE, 0); REG_WAIT(MPCC_MCM_MEM_PWR_CTRL[mpcc_id], MPCC_MCM_1DLUT_MEM_PWR_STATE, 0, 1, 5); } else if (!mpc->ctx->dc->debug.disable_mem_low_power) { - ASSERT(false); /* TODO: change to mpc * dpp_base->ctx->dc->optimized_required = true; * dpp_base->deferred_reg_writes.bits.disable_blnd_lut = true; diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_optc.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_optc.c deleted file mode 100644 index a2c4db2cebdd6c..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_optc.c +++ /dev/null @@ -1,357 +0,0 @@ -/* - * 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 "dcn32_optc.h" - -#include "dcn30/dcn30_optc.h" -#include "dcn31/dcn31_optc.h" -#include "reg_helper.h" -#include "dc.h" -#include "dcn_calc_math.h" -#include "dc_dmub_srv.h" - -#define REG(reg)\ - optc1->tg_regs->reg - -#define CTX \ - optc1->base.ctx - -#undef FN -#define FN(reg_name, field_name) \ - optc1->tg_shift->field_name, optc1->tg_mask->field_name - -static void optc32_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, - struct dc_crtc_timing *timing) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - uint32_t memory_mask = 0; - int h_active = timing->h_addressable + timing->h_border_left + timing->h_border_right; - int mpcc_hactive = h_active / opp_cnt; - /* Each memory instance is 2048x(32x2) bits to support half line of 4096 */ - int odm_mem_count = (h_active + 2047) / 2048; - - /* - * display <= 4k : 2 memories + 2 pipes - * 4k < display <= 8k : 4 memories + 2 pipes - * 8k < display <= 12k : 6 memories + 4 pipes - */ - if (opp_cnt == 4) { - if (odm_mem_count <= 2) - memory_mask = 0x3; - else if (odm_mem_count <= 4) - memory_mask = 0xf; - else - memory_mask = 0x3f; - } else { - if (odm_mem_count <= 2) - memory_mask = 0x1 << (opp_id[0] * 2) | 0x1 << (opp_id[1] * 2); - else if (odm_mem_count <= 4) - memory_mask = 0x3 << (opp_id[0] * 2) | 0x3 << (opp_id[1] * 2); - else - memory_mask = 0x77; - } - - REG_SET(OPTC_MEMORY_CONFIG, 0, - OPTC_MEM_SEL, memory_mask); - - if (opp_cnt == 2) { - REG_SET_3(OPTC_DATA_SOURCE_SELECT, 0, - OPTC_NUM_OF_INPUT_SEGMENT, 1, - OPTC_SEG0_SRC_SEL, opp_id[0], - OPTC_SEG1_SRC_SEL, opp_id[1]); - } else if (opp_cnt == 4) { - REG_SET_5(OPTC_DATA_SOURCE_SELECT, 0, - OPTC_NUM_OF_INPUT_SEGMENT, 3, - OPTC_SEG0_SRC_SEL, opp_id[0], - OPTC_SEG1_SRC_SEL, opp_id[1], - OPTC_SEG2_SRC_SEL, opp_id[2], - OPTC_SEG3_SRC_SEL, opp_id[3]); - } - - REG_UPDATE(OPTC_WIDTH_CONTROL, - OPTC_SEGMENT_WIDTH, mpcc_hactive); - - REG_UPDATE(OTG_H_TIMING_CNTL, - OTG_H_TIMING_DIV_MODE, opp_cnt - 1); - optc1->opp_count = opp_cnt; -} - -void optc32_get_odm_combine_segments(struct timing_generator *tg, int *odm_combine_segments) -{ - struct optc *optc1 = DCN10TG_FROM_TG(tg); - int segments; - - REG_GET(OPTC_DATA_SOURCE_SELECT, OPTC_NUM_OF_INPUT_SEGMENT, &segments); - - switch (segments) { - case 0: - *odm_combine_segments = 1; - break; - case 1: - *odm_combine_segments = 2; - break; - case 3: - *odm_combine_segments = 4; - break; - /* 2 is reserved */ - case 2: - default: - *odm_combine_segments = -1; - } -} - -void optc32_set_h_timing_div_manual_mode(struct timing_generator *optc, bool manual_mode) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_UPDATE(OTG_H_TIMING_CNTL, - OTG_H_TIMING_DIV_MODE_MANUAL, manual_mode ? 1 : 0); -} -/** - * optc32_enable_crtc() - Enable CRTC - call ASIC Control Object to enable Timing generator. - * - * @optc: timing_generator instance. - * - * Return: If CRTC is enabled, return true. - */ -static bool optc32_enable_crtc(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - /* opp instance for OTG, 1 to 1 mapping and odm will adjust */ - REG_UPDATE(OPTC_DATA_SOURCE_SELECT, - OPTC_SEG0_SRC_SEL, optc->inst); - - /* VTG enable first is for HW workaround */ - REG_UPDATE(CONTROL, - VTG0_ENABLE, 1); - - REG_SEQ_START(); - - /* Enable CRTC */ - REG_UPDATE_2(OTG_CONTROL, - OTG_DISABLE_POINT_CNTL, 2, - OTG_MASTER_EN, 1); - - REG_SEQ_SUBMIT(); - REG_SEQ_WAIT_DONE(); - - return true; -} - -/* disable_crtc */ -static bool optc32_disable_crtc(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - /* disable otg request until end of the first line - * in the vertical blank region - */ - REG_UPDATE(OTG_CONTROL, - OTG_MASTER_EN, 0); - - REG_UPDATE(CONTROL, - VTG0_ENABLE, 0); - - /* CRTC disabled, so disable clock. */ - REG_WAIT(OTG_CLOCK_CONTROL, - OTG_BUSY, 0, - 1, 150000); - - return true; -} - -static void optc32_phantom_crtc_post_enable(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - /* Disable immediately. */ - REG_UPDATE_2(OTG_CONTROL, OTG_DISABLE_POINT_CNTL, 0, OTG_MASTER_EN, 0); - - /* CRTC disabled, so disable clock. */ - REG_WAIT(OTG_CLOCK_CONTROL, OTG_BUSY, 0, 1, 100000); -} - -static void optc32_disable_phantom_otg(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - REG_UPDATE(OTG_CONTROL, OTG_MASTER_EN, 0); -} - -void optc32_set_odm_bypass(struct timing_generator *optc, - const struct dc_crtc_timing *dc_crtc_timing) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - enum h_timing_div_mode h_div = H_TIMING_NO_DIV; - - REG_SET_5(OPTC_DATA_SOURCE_SELECT, 0, - OPTC_NUM_OF_INPUT_SEGMENT, 0, - OPTC_SEG0_SRC_SEL, optc->inst, - OPTC_SEG1_SRC_SEL, 0xf, - OPTC_SEG2_SRC_SEL, 0xf, - OPTC_SEG3_SRC_SEL, 0xf - ); - - h_div = optc1_is_two_pixels_per_containter(dc_crtc_timing); - REG_UPDATE(OTG_H_TIMING_CNTL, - OTG_H_TIMING_DIV_MODE, h_div); - - REG_SET(OPTC_MEMORY_CONFIG, 0, - OPTC_MEM_SEL, 0); - optc1->opp_count = 1; -} - -static void optc32_setup_manual_trigger(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - struct dc *dc = optc->ctx->dc; - - if (dc->caps.dmub_caps.mclk_sw && !dc->debug.disable_fams) - dc_dmub_srv_set_drr_manual_trigger_cmd(dc, optc->inst); - else { - /* - * MIN_MASK_EN is gone and MASK is now always enabled. - * - * To get it to it work with manual trigger we need to make sure - * we program the correct bit. - */ - REG_UPDATE_4(OTG_V_TOTAL_CONTROL, - OTG_V_TOTAL_MIN_SEL, 1, - OTG_V_TOTAL_MAX_SEL, 1, - OTG_FORCE_LOCK_ON_EVENT, 0, - OTG_SET_V_TOTAL_MIN_MASK, (1 << 1)); /* TRIGA */ - - // Setup manual flow control for EOF via TRIG_A - optc->funcs->setup_manual_trigger(optc); - } -} - -static void optc32_set_drr( - struct timing_generator *optc, - const struct drr_params *params) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - if (params != NULL && - params->vertical_total_max > 0 && - params->vertical_total_min > 0) { - - if (params->vertical_total_mid != 0) { - - REG_SET(OTG_V_TOTAL_MID, 0, - OTG_V_TOTAL_MID, params->vertical_total_mid - 1); - - REG_UPDATE_2(OTG_V_TOTAL_CONTROL, - OTG_VTOTAL_MID_REPLACING_MAX_EN, 1, - OTG_VTOTAL_MID_FRAME_NUM, - (uint8_t)params->vertical_total_mid_frame_num); - - } - - optc->funcs->set_vtotal_min_max(optc, params->vertical_total_min - 1, params->vertical_total_max - 1); - } - - optc32_setup_manual_trigger(optc); -} - -static struct timing_generator_funcs dcn32_tg_funcs = { - .validate_timing = optc1_validate_timing, - .program_timing = optc1_program_timing, - .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0, - .setup_vertical_interrupt1 = optc1_setup_vertical_interrupt1, - .setup_vertical_interrupt2 = optc1_setup_vertical_interrupt2, - .program_global_sync = optc1_program_global_sync, - .enable_crtc = optc32_enable_crtc, - .disable_crtc = optc32_disable_crtc, - .phantom_crtc_post_enable = optc32_phantom_crtc_post_enable, - .disable_phantom_crtc = optc32_disable_phantom_otg, - /* used by enable_timing_synchronization. Not need for FPGA */ - .is_counter_moving = optc1_is_counter_moving, - .get_position = optc1_get_position, - .get_frame_count = optc1_get_vblank_counter, - .get_scanoutpos = optc1_get_crtc_scanoutpos, - .get_otg_active_size = optc1_get_otg_active_size, - .set_early_control = optc1_set_early_control, - /* used by enable_timing_synchronization. Not need for FPGA */ - .wait_for_state = optc1_wait_for_state, - .set_blank_color = optc3_program_blank_color, - .did_triggered_reset_occur = optc1_did_triggered_reset_occur, - .triplebuffer_lock = optc3_triplebuffer_lock, - .triplebuffer_unlock = optc2_triplebuffer_unlock, - .enable_reset_trigger = optc1_enable_reset_trigger, - .enable_crtc_reset = optc1_enable_crtc_reset, - .disable_reset_trigger = optc1_disable_reset_trigger, - .lock = optc3_lock, - .unlock = optc1_unlock, - .lock_doublebuffer_enable = optc3_lock_doublebuffer_enable, - .lock_doublebuffer_disable = optc3_lock_doublebuffer_disable, - .enable_optc_clock = optc1_enable_optc_clock, - .set_drr = optc32_set_drr, - .get_last_used_drr_vtotal = optc2_get_last_used_drr_vtotal, - .set_vtotal_min_max = optc3_set_vtotal_min_max, - .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, - .is_tg_enabled = optc1_is_tg_enabled, - .is_optc_underflow_occurred = optc1_is_optc_underflow_occurred, - .clear_optc_underflow = optc1_clear_optc_underflow, - .setup_global_swap_lock = NULL, - .get_crc = optc1_get_crc, - .configure_crc = optc1_configure_crc, - .set_dsc_config = optc3_set_dsc_config, - .get_dsc_status = optc2_get_dsc_status, - .set_dwb_source = NULL, - .set_odm_bypass = optc32_set_odm_bypass, - .set_odm_combine = optc32_set_odm_combine, - .get_odm_combine_segments = optc32_get_odm_combine_segments, - .set_h_timing_div_manual_mode = optc32_set_h_timing_div_manual_mode, - .get_optc_source = optc2_get_optc_source, - .set_out_mux = optc3_set_out_mux, - .set_drr_trigger_window = optc3_set_drr_trigger_window, - .set_vtotal_change_limit = optc3_set_vtotal_change_limit, - .set_gsl = optc2_set_gsl, - .set_gsl_source_select = optc2_set_gsl_source_select, - .set_vtg_params = optc1_set_vtg_params, - .program_manual_trigger = optc2_program_manual_trigger, - .setup_manual_trigger = optc2_setup_manual_trigger, - .get_hw_timing = optc1_get_hw_timing, -}; - -void dcn32_timing_generator_init(struct optc *optc1) -{ - optc1->base.funcs = &dcn32_tg_funcs; - - optc1->max_h_total = optc1->tg_mask->OTG_H_TOTAL + 1; - optc1->max_v_total = optc1->tg_mask->OTG_V_TOTAL + 1; - - optc1->min_h_blank = 32; - optc1->min_v_blank = 3; - optc1->min_v_blank_interlace = 5; - optc1->min_h_sync_width = 4; - optc1->min_v_sync_width = 1; -} - diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_optc.h b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_optc.h deleted file mode 100644 index 8ce3b178cab065..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_optc.h +++ /dev/null @@ -1,187 +0,0 @@ -/* - * 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_OPTC_DCN32_H__ -#define __DC_OPTC_DCN32_H__ - -#include "dcn10/dcn10_optc.h" - -#define OPTC_COMMON_MASK_SH_LIST_DCN3_2(mask_sh)\ - SF(OTG0_OTG_VSTARTUP_PARAM, VSTARTUP_START, mask_sh),\ - SF(OTG0_OTG_VUPDATE_PARAM, VUPDATE_OFFSET, mask_sh),\ - SF(OTG0_OTG_VUPDATE_PARAM, VUPDATE_WIDTH, mask_sh),\ - SF(OTG0_OTG_VREADY_PARAM, VREADY_OFFSET, mask_sh),\ - SF(OTG0_OTG_MASTER_UPDATE_LOCK, OTG_MASTER_UPDATE_LOCK, mask_sh),\ - SF(OTG0_OTG_MASTER_UPDATE_LOCK, UPDATE_LOCK_STATUS, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL0, MASTER_UPDATE_LOCK_DB_START_X, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL0, MASTER_UPDATE_LOCK_DB_END_X, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL0, MASTER_UPDATE_LOCK_DB_EN, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_START_Y, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_END_Y, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL2, OTG_MASTER_UPDATE_LOCK_SEL, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL4, DIG_UPDATE_POSITION_X, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL4, DIG_UPDATE_POSITION_Y, mask_sh),\ - SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_UPDATE_PENDING, mask_sh),\ - SF(OTG0_OTG_H_TOTAL, OTG_H_TOTAL, mask_sh),\ - SF(OTG0_OTG_H_BLANK_START_END, OTG_H_BLANK_START, mask_sh),\ - SF(OTG0_OTG_H_BLANK_START_END, OTG_H_BLANK_END, mask_sh),\ - SF(OTG0_OTG_H_SYNC_A, OTG_H_SYNC_A_START, mask_sh),\ - SF(OTG0_OTG_H_SYNC_A, OTG_H_SYNC_A_END, mask_sh),\ - SF(OTG0_OTG_H_SYNC_A_CNTL, OTG_H_SYNC_A_POL, mask_sh),\ - SF(OTG0_OTG_V_TOTAL, OTG_V_TOTAL, mask_sh),\ - SF(OTG0_OTG_V_BLANK_START_END, OTG_V_BLANK_START, mask_sh),\ - SF(OTG0_OTG_V_BLANK_START_END, OTG_V_BLANK_END, mask_sh),\ - SF(OTG0_OTG_V_SYNC_A, OTG_V_SYNC_A_START, mask_sh),\ - SF(OTG0_OTG_V_SYNC_A, OTG_V_SYNC_A_END, mask_sh),\ - SF(OTG0_OTG_V_SYNC_A_CNTL, OTG_V_SYNC_A_POL, mask_sh),\ - SF(OTG0_OTG_V_SYNC_A_CNTL, OTG_V_SYNC_MODE, mask_sh),\ - SF(OTG0_OTG_CONTROL, OTG_MASTER_EN, mask_sh),\ - SF(OTG0_OTG_CONTROL, OTG_START_POINT_CNTL, mask_sh),\ - SF(OTG0_OTG_CONTROL, OTG_DISABLE_POINT_CNTL, mask_sh),\ - SF(OTG0_OTG_CONTROL, OTG_FIELD_NUMBER_CNTL, mask_sh),\ - SF(OTG0_OTG_CONTROL, OTG_OUT_MUX, mask_sh),\ - SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_EN, mask_sh),\ - SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_SYNC_OUTPUT_LINE_NUM, mask_sh),\ - SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_SYNC_OUTPUT_POLARITY, mask_sh),\ - SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_EYE_FLAG_POLARITY, mask_sh),\ - SF(OTG0_OTG_STEREO_CONTROL, OTG_DISABLE_STEREOSYNC_OUTPUT_FOR_DP, mask_sh),\ - SF(OTG0_OTG_STEREO_STATUS, OTG_STEREO_CURRENT_EYE, mask_sh),\ - SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_EN, mask_sh),\ - SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_V_UPDATE_MODE, mask_sh),\ - SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_STEREO_SEL_OVR, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_MAX, OTG_V_TOTAL_MAX, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_MIN, OTG_V_TOTAL_MIN, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_V_TOTAL_MIN_SEL, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_V_TOTAL_MAX_SEL, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_FORCE_LOCK_ON_EVENT, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_SET_V_TOTAL_MIN_MASK, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_VTOTAL_MID_REPLACING_MIN_EN, mask_sh),\ - SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_VTOTAL_MID_REPLACING_MAX_EN, mask_sh),\ - SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_CLEAR, mask_sh),\ - SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_MODE, mask_sh),\ - SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_OCCURRED, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_SOURCE_SELECT, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_SOURCE_PIPE_SELECT, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_RISING_EDGE_DETECT_CNTL, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_POLARITY_SELECT, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_FREQUENCY_SELECT, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_DELAY, mask_sh),\ - SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_CLEAR, mask_sh),\ - SF(OTG0_OTG_STATIC_SCREEN_CONTROL, OTG_STATIC_SCREEN_EVENT_MASK, mask_sh),\ - SF(OTG0_OTG_STATIC_SCREEN_CONTROL, OTG_STATIC_SCREEN_FRAME_COUNT, mask_sh),\ - SF(OTG0_OTG_STATUS_FRAME_COUNT, OTG_FRAME_COUNT, mask_sh),\ - SF(OTG0_OTG_STATUS, OTG_V_BLANK, mask_sh),\ - SF(OTG0_OTG_STATUS, OTG_V_ACTIVE_DISP, mask_sh),\ - SF(OTG0_OTG_STATUS_POSITION, OTG_HORZ_COUNT, mask_sh),\ - SF(OTG0_OTG_STATUS_POSITION, OTG_VERT_COUNT, mask_sh),\ - SF(OTG0_OTG_NOM_VERT_POSITION, OTG_VERT_COUNT_NOM, mask_sh),\ - SF(OTG0_OTG_M_CONST_DTO0, OTG_M_CONST_DTO_PHASE, mask_sh),\ - SF(OTG0_OTG_M_CONST_DTO1, OTG_M_CONST_DTO_MODULO, mask_sh),\ - SF(OTG0_OTG_CLOCK_CONTROL, OTG_BUSY, mask_sh),\ - SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_EN, mask_sh),\ - SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_ON, mask_sh),\ - SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_GATE_DIS, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_INT_ENABLE, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT0_POSITION, OTG_VERTICAL_INTERRUPT0_LINE_START, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT0_POSITION, OTG_VERTICAL_INTERRUPT0_LINE_END, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT1_CONTROL, OTG_VERTICAL_INTERRUPT1_INT_ENABLE, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT1_POSITION, OTG_VERTICAL_INTERRUPT1_LINE_START, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE, mask_sh),\ - SF(OTG0_OTG_VERTICAL_INTERRUPT2_POSITION, OTG_VERTICAL_INTERRUPT2_LINE_START, mask_sh),\ - SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_EN, mask_sh),\ - SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_ON, mask_sh),\ - SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_GATE_DIS, mask_sh),\ - SF(ODM0_OPTC_INPUT_GLOBAL_CONTROL, OPTC_UNDERFLOW_OCCURRED_STATUS, mask_sh),\ - SF(ODM0_OPTC_INPUT_GLOBAL_CONTROL, OPTC_UNDERFLOW_CLEAR, mask_sh),\ - SF(VTG0_CONTROL, VTG0_ENABLE, mask_sh),\ - SF(VTG0_CONTROL, VTG0_FP2, mask_sh),\ - SF(VTG0_CONTROL, VTG0_VCOUNT_INIT, mask_sh),\ - SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_FORCE_VSYNC_NEXT_LINE_OCCURRED, mask_sh),\ - SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_FORCE_VSYNC_NEXT_LINE_CLEAR, mask_sh),\ - SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_AUTO_FORCE_VSYNC_MODE, mask_sh),\ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL0_EN, mask_sh),\ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL1_EN, mask_sh),\ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL2_EN, mask_sh),\ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_MASTER_EN, mask_sh),\ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_FORCE_DELAY, mask_sh),\ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_CHECK_ALL_FIELDS, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL, OTG_CRC_CONT_EN, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL, OTG_CRC0_SELECT, mask_sh),\ - SF(OTG0_OTG_CRC_CNTL, OTG_CRC_EN, mask_sh),\ - SF(OTG0_OTG_CRC0_DATA_RG, CRC0_R_CR, mask_sh),\ - SF(OTG0_OTG_CRC0_DATA_RG, CRC0_G_Y, mask_sh),\ - SF(OTG0_OTG_CRC0_DATA_B, CRC0_B_CB, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWA_X_CONTROL, OTG_CRC0_WINDOWA_X_START, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWA_X_CONTROL, OTG_CRC0_WINDOWA_X_END, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWA_Y_CONTROL, OTG_CRC0_WINDOWA_Y_START, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWA_Y_CONTROL, OTG_CRC0_WINDOWA_Y_END, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWB_X_CONTROL, OTG_CRC0_WINDOWB_X_START, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWB_X_CONTROL, OTG_CRC0_WINDOWB_X_END, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL, OTG_CRC0_WINDOWB_Y_START, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL, OTG_CRC0_WINDOWB_Y_END, mask_sh),\ - SF(OTG0_OTG_TRIGA_MANUAL_TRIG, OTG_TRIGA_MANUAL_TRIG, mask_sh),\ - SF(GSL_SOURCE_SELECT, GSL0_READY_SOURCE_SEL, mask_sh),\ - SF(GSL_SOURCE_SELECT, GSL1_READY_SOURCE_SEL, mask_sh),\ - SF(GSL_SOURCE_SELECT, GSL2_READY_SOURCE_SEL, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL2, MANUAL_FLOW_CONTROL_SEL, mask_sh),\ - SF(OTG0_OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, mask_sh),\ - SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_START_X, mask_sh),\ - SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_END_X, mask_sh), \ - SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_START_Y, mask_sh),\ - SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_END_Y, mask_sh),\ - SF(OTG0_OTG_VUPDATE_KEEPOUT, OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, mask_sh), \ - SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET, mask_sh), \ - SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET, mask_sh), \ - SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_MASTER_MODE, mask_sh), \ - SF(OTG0_OTG_GSL_CONTROL, OTG_MASTER_UPDATE_LOCK_GSL_EN, mask_sh), \ - SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_X, mask_sh), \ - SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_LINE_NUM, mask_sh),\ - SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG0_SRC_SEL, mask_sh),\ - SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG1_SRC_SEL, mask_sh),\ - SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG2_SRC_SEL, mask_sh),\ - SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG3_SRC_SEL, mask_sh),\ - SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_NUM_OF_INPUT_SEGMENT, mask_sh),\ - SF(ODM0_OPTC_MEMORY_CONFIG, OPTC_MEM_SEL, mask_sh),\ - SF(ODM0_OPTC_DATA_FORMAT_CONTROL, OPTC_DATA_FORMAT, mask_sh),\ - SF(ODM0_OPTC_DATA_FORMAT_CONTROL, OPTC_DSC_MODE, mask_sh),\ - SF(ODM0_OPTC_BYTES_PER_PIXEL, OPTC_DSC_BYTES_PER_PIXEL, mask_sh),\ - SF(ODM0_OPTC_WIDTH_CONTROL, OPTC_DSC_SLICE_WIDTH, mask_sh),\ - SF(ODM0_OPTC_WIDTH_CONTROL, OPTC_SEGMENT_WIDTH, mask_sh),\ - SF(OTG0_OTG_DRR_TRIGGER_WINDOW, OTG_DRR_TRIGGER_WINDOW_START_X, mask_sh),\ - 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_H_TIMING_CNTL, OTG_H_TIMING_DIV_MODE_MANUAL, mask_sh),\ - SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_DRR_TIMING_DBUF_UPDATE_MODE, mask_sh),\ - SF(OTG0_OTG_DRR_CONTROL, OTG_V_TOTAL_LAST_USED_BY_DRR, mask_sh) - -void dcn32_timing_generator_init(struct optc *optc1); -void optc32_set_h_timing_div_manual_mode(struct timing_generator *optc, bool manual_mode); -void optc32_get_odm_combine_segments(struct timing_generator *tg, int *odm_combine_segments); -void optc32_set_odm_bypass(struct timing_generator *optc, - const struct dc_crtc_timing *dc_crtc_timing); - -#endif /* __DC_OPTC_DCN32_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c deleted file mode 100644 index 89b072447dba9b..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c +++ /dev/null @@ -1,2862 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - * 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 "dm_services.h" -#include "dc.h" - -#include "dcn32_init.h" - -#include "resource.h" -#include "include/irq_service_interface.h" -#include "dcn32_resource.h" - -#include "dcn20/dcn20_resource.h" -#include "dcn30/dcn30_resource.h" - -#include "dcn10/dcn10_ipp.h" -#include "dcn30/dcn30_hubbub.h" -#include "dcn31/dcn31_hubbub.h" -#include "dcn32/dcn32_hubbub.h" -#include "dcn32/dcn32_mpc.h" -#include "dcn32_hubp.h" -#include "irq/dcn32/irq_service_dcn32.h" -#include "dcn32/dcn32_dpp.h" -#include "dcn32/dcn32_optc.h" -#include "dcn20/dcn20_hwseq.h" -#include "dcn30/dcn30_hwseq.h" -#include "dce110/dce110_hwseq.h" -#include "dcn30/dcn30_opp.h" -#include "dcn20/dcn20_dsc.h" -#include "dcn30/dcn30_vpg.h" -#include "dcn30/dcn30_afmt.h" -#include "dcn30/dcn30_dio_stream_encoder.h" -#include "dcn32/dcn32_dio_stream_encoder.h" -#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 "dcn31/dcn31_apg.h" -#include "dcn31/dcn31_dio_link_encoder.h" -#include "dcn32/dcn32_dio_link_encoder.h" -#include "dce/dce_clock_source.h" -#include "dce/dce_audio.h" -#include "dce/dce_hwseq.h" -#include "clk_mgr.h" -#include "virtual/virtual_stream_encoder.h" -#include "dml/display_mode_vba.h" -#include "dcn32/dcn32_dccg.h" -#include "dcn10/dcn10_resource.h" -#include "link.h" -#include "dcn31/dcn31_panel_cntl.h" - -#include "dcn30/dcn30_dwb.h" -#include "dcn32/dcn32_mmhubbub.h" - -#include "dcn/dcn_3_2_0_offset.h" -#include "dcn/dcn_3_2_0_sh_mask.h" -#include "nbio/nbio_4_3_0_offset.h" - -#include "reg_helper.h" -#include "dce/dmub_abm.h" -#include "dce/dmub_psr.h" -#include "dce/dce_aux.h" -#include "dce/dce_i2c.h" - -#include "dml/dcn30/display_mode_vba_30.h" -#include "vm_helper.h" -#include "dcn20/dcn20_vmid.h" -#include "dml/dcn32/dcn32_fpu.h" - -#include "dml2/dml2_wrapper.h" - -#define DC_LOGGER_INIT(logger) - -enum dcn32_clk_src_array_id { - DCN32_CLK_SRC_PLL0, - DCN32_CLK_SRC_PLL1, - DCN32_CLK_SRC_PLL2, - DCN32_CLK_SRC_PLL3, - DCN32_CLK_SRC_PLL4, - DCN32_CLK_SRC_TOTAL -}; - -/* begin ********************* - * macros to expend register list macro defined in HW object header file - */ - -/* DCN */ -#define BASE_INNER(seg) ctx->dcn_reg_offsets[seg] - -#define BASE(seg) BASE_INNER(seg) - -#define SR(reg_name)\ - REG_STRUCT.reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ - reg ## reg_name -#define SR_ARR(reg_name, id) \ - REG_STRUCT[id].reg_name = BASE(reg##reg_name##_BASE_IDX) + reg##reg_name - -#define SR_ARR_INIT(reg_name, id, value) \ - REG_STRUCT[id].reg_name = value - -#define SRI(reg_name, block, id)\ - REG_STRUCT.reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRI_ARR(reg_name, block, id)\ - REG_STRUCT[id].reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SR_ARR_I2C(reg_name, id) \ - REG_STRUCT[id-1].reg_name = BASE(reg##reg_name##_BASE_IDX) + reg##reg_name - -#define SRI_ARR_I2C(reg_name, block, id)\ - REG_STRUCT[id-1].reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRI_ARR_ALPHABET(reg_name, block, index, id)\ - REG_STRUCT[index].reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRI2(reg_name, block, id)\ - .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ - reg ## reg_name -#define SRI2_ARR(reg_name, block, id)\ - REG_STRUCT[id].reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ - reg ## reg_name - -#define SRIR(var_name, reg_name, block, id)\ - .var_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRII(reg_name, block, id)\ - REG_STRUCT.reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRII_ARR_2(reg_name, block, id, inst)\ - REG_STRUCT[inst].reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRII_MPC_RMU(reg_name, block, id)\ - .RMU##_##reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRII_DWB(reg_name, temp_name, block, id)\ - REG_STRUCT.reg_name[id] = BASE(reg ## block ## id ## _ ## temp_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## temp_name - -#define SF_DWB2(reg_name, block, id, field_name, post_fix) \ - .field_name = reg_name ## __ ## field_name ## post_fix - -#define DCCG_SRII(reg_name, block, id)\ - REG_STRUCT.block ## _ ## reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define VUPDATE_SRII(reg_name, block, id)\ - REG_STRUCT.reg_name[id] = BASE(reg ## reg_name ## _ ## block ## id ## _BASE_IDX) + \ - reg ## reg_name ## _ ## block ## id - -/* NBIO */ -#define NBIO_BASE_INNER(seg) ctx->nbio_reg_offsets[seg] - -#define NBIO_BASE(seg) \ - NBIO_BASE_INNER(seg) - -#define NBIO_SR(reg_name)\ - REG_STRUCT.reg_name = NBIO_BASE(regBIF_BX0_ ## reg_name ## _BASE_IDX) + \ - regBIF_BX0_ ## reg_name -#define NBIO_SR_ARR(reg_name, id)\ - REG_STRUCT[id].reg_name = NBIO_BASE(regBIF_BX0_ ## reg_name ## _BASE_IDX) + \ - regBIF_BX0_ ## reg_name - -#undef CTX -#define CTX ctx -#define REG(reg_name) \ - (ctx->dcn_reg_offsets[reg ## reg_name ## _BASE_IDX] + reg ## reg_name) - -static struct bios_registers bios_regs; - -#define bios_regs_init() \ - ( \ - NBIO_SR(BIOS_SCRATCH_3),\ - NBIO_SR(BIOS_SCRATCH_6)\ - ) - -#define clk_src_regs_init(index, pllid)\ - CS_COMMON_REG_LIST_DCN3_0_RI(index, pllid) - -static struct dce110_clk_src_regs clk_src_regs[5]; - -static const struct dce110_clk_src_shift cs_shift = { - CS_COMMON_MASK_SH_LIST_DCN3_2(__SHIFT) -}; - -static const struct dce110_clk_src_mask cs_mask = { - CS_COMMON_MASK_SH_LIST_DCN3_2(_MASK) -}; - -#define abm_regs_init(id)\ - ABM_DCN32_REG_LIST_RI(id) - -static struct dce_abm_registers abm_regs[4]; - -static const struct dce_abm_shift abm_shift = { - ABM_MASK_SH_LIST_DCN32(__SHIFT) -}; - -static const struct dce_abm_mask abm_mask = { - ABM_MASK_SH_LIST_DCN32(_MASK) -}; - -#define audio_regs_init(id)\ - AUD_COMMON_REG_LIST_RI(id) - -static struct dce_audio_registers audio_regs[5]; - -#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ - SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ - SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ - AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) - -static const struct dce_audio_shift audio_shift = { - DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_audio_mask audio_mask = { - DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) -}; - -#define vpg_regs_init(id)\ - VPG_DCN3_REG_LIST_RI(id) - -static struct dcn30_vpg_registers vpg_regs[10]; - -static const struct dcn30_vpg_shift vpg_shift = { - DCN3_VPG_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn30_vpg_mask vpg_mask = { - DCN3_VPG_MASK_SH_LIST(_MASK) -}; - -#define afmt_regs_init(id)\ - AFMT_DCN3_REG_LIST_RI(id) - -static struct dcn30_afmt_registers afmt_regs[6]; - -static const struct dcn30_afmt_shift afmt_shift = { - DCN3_AFMT_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn30_afmt_mask afmt_mask = { - DCN3_AFMT_MASK_SH_LIST(_MASK) -}; - -#define apg_regs_init(id)\ - APG_DCN31_REG_LIST_RI(id) - -static struct dcn31_apg_registers apg_regs[4]; - -static const struct dcn31_apg_shift apg_shift = { - DCN31_APG_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn31_apg_mask apg_mask = { - DCN31_APG_MASK_SH_LIST(_MASK) -}; - -#define stream_enc_regs_init(id)\ - SE_DCN32_REG_LIST_RI(id) - -static struct dcn10_stream_enc_registers stream_enc_regs[5]; - -static const struct dcn10_stream_encoder_shift se_shift = { - SE_COMMON_MASK_SH_LIST_DCN32(__SHIFT) -}; - -static const struct dcn10_stream_encoder_mask se_mask = { - SE_COMMON_MASK_SH_LIST_DCN32(_MASK) -}; - - -#define aux_regs_init(id)\ - DCN2_AUX_REG_LIST_RI(id) - -static struct dcn10_link_enc_aux_registers link_enc_aux_regs[5]; - -#define hpd_regs_init(id)\ - HPD_REG_LIST_RI(id) - -static struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[5]; - -#define link_regs_init(id, phyid)\ - ( \ - LE_DCN31_REG_LIST_RI(id), \ - UNIPHY_DCN2_REG_LIST_RI(id, phyid)\ - ) - /*DPCS_DCN31_REG_LIST(id),*/ \ - -static struct dcn10_link_enc_registers link_enc_regs[5]; - -static const struct dcn10_link_enc_shift le_shift = { - LINK_ENCODER_MASK_SH_LIST_DCN31(__SHIFT), \ - //DPCS_DCN31_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn10_link_enc_mask le_mask = { - LINK_ENCODER_MASK_SH_LIST_DCN31(_MASK), \ - //DPCS_DCN31_MASK_SH_LIST(_MASK) -}; - -#define hpo_dp_stream_encoder_reg_init(id)\ - DCN3_1_HPO_DP_STREAM_ENC_REG_LIST_RI(id) - -static struct dcn31_hpo_dp_stream_encoder_registers hpo_dp_stream_enc_regs[4]; - -static const struct dcn31_hpo_dp_stream_encoder_shift hpo_dp_se_shift = { - DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn31_hpo_dp_stream_encoder_mask hpo_dp_se_mask = { - DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(_MASK) -}; - - -#define hpo_dp_link_encoder_reg_init(id)\ - DCN3_1_HPO_DP_LINK_ENC_REG_LIST_RI(id) - /*DCN3_1_RDPCSTX_REG_LIST(0),*/ - /*DCN3_1_RDPCSTX_REG_LIST(1),*/ - /*DCN3_1_RDPCSTX_REG_LIST(2),*/ - /*DCN3_1_RDPCSTX_REG_LIST(3),*/ - -static struct dcn31_hpo_dp_link_encoder_registers hpo_dp_link_enc_regs[2]; - -static const struct dcn31_hpo_dp_link_encoder_shift hpo_dp_le_shift = { - DCN3_2_HPO_DP_LINK_ENC_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn31_hpo_dp_link_encoder_mask hpo_dp_le_mask = { - DCN3_2_HPO_DP_LINK_ENC_MASK_SH_LIST(_MASK) -}; - -#define dpp_regs_init(id)\ - DPP_REG_LIST_DCN30_COMMON_RI(id) - -static struct dcn3_dpp_registers dpp_regs[4]; - -static const struct dcn3_dpp_shift tf_shift = { - DPP_REG_LIST_SH_MASK_DCN30_COMMON(__SHIFT) -}; - -static const struct dcn3_dpp_mask tf_mask = { - DPP_REG_LIST_SH_MASK_DCN30_COMMON(_MASK) -}; - - -#define opp_regs_init(id)\ - OPP_REG_LIST_DCN30_RI(id) - -static struct dcn20_opp_registers opp_regs[4]; - -static const struct dcn20_opp_shift opp_shift = { - OPP_MASK_SH_LIST_DCN20(__SHIFT) -}; - -static const struct dcn20_opp_mask opp_mask = { - OPP_MASK_SH_LIST_DCN20(_MASK) -}; - -#define aux_engine_regs_init(id)\ - ( \ - AUX_COMMON_REG_LIST0_RI(id), \ - SR_ARR_INIT(AUXN_IMPCAL, id, 0), \ - SR_ARR_INIT(AUXP_IMPCAL, id, 0), \ - SR_ARR_INIT(AUX_RESET_MASK, id, DP_AUX0_AUX_CONTROL__AUX_RESET_MASK), \ - SR_ARR_INIT(AUX_RESET_MASK, id, DP_AUX0_AUX_CONTROL__AUX_RESET_MASK)\ - ) - -static struct dce110_aux_registers aux_engine_regs[5]; - -static const struct dce110_aux_registers_shift aux_shift = { - DCN_AUX_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce110_aux_registers_mask aux_mask = { - DCN_AUX_MASK_SH_LIST(_MASK) -}; - -#define dwbc_regs_dcn3_init(id)\ - DWBC_COMMON_REG_LIST_DCN30_RI(id) - -static struct dcn30_dwbc_registers dwbc30_regs[1]; - -static const struct dcn30_dwbc_shift dwbc30_shift = { - DWBC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn30_dwbc_mask dwbc30_mask = { - DWBC_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -#define mcif_wb_regs_dcn3_init(id)\ - MCIF_WB_COMMON_REG_LIST_DCN32_RI(id) - -static struct dcn30_mmhubbub_registers mcif_wb30_regs[1]; - -static const struct dcn30_mmhubbub_shift mcif_wb30_shift = { - MCIF_WB_COMMON_MASK_SH_LIST_DCN32(__SHIFT) -}; - -static const struct dcn30_mmhubbub_mask mcif_wb30_mask = { - MCIF_WB_COMMON_MASK_SH_LIST_DCN32(_MASK) -}; - -#define dsc_regsDCN20_init(id)\ - DSC_REG_LIST_DCN20_RI(id) - -static struct dcn20_dsc_registers dsc_regs[4]; - -static const struct dcn20_dsc_shift dsc_shift = { - DSC_REG_LIST_SH_MASK_DCN20(__SHIFT) -}; - -static const struct dcn20_dsc_mask dsc_mask = { - DSC_REG_LIST_SH_MASK_DCN20(_MASK) -}; - -static struct dcn30_mpc_registers mpc_regs; - -#define dcn_mpc_regs_init() \ - MPC_REG_LIST_DCN3_2_RI(0),\ - MPC_REG_LIST_DCN3_2_RI(1),\ - MPC_REG_LIST_DCN3_2_RI(2),\ - MPC_REG_LIST_DCN3_2_RI(3),\ - MPC_OUT_MUX_REG_LIST_DCN3_0_RI(0),\ - MPC_OUT_MUX_REG_LIST_DCN3_0_RI(1),\ - MPC_OUT_MUX_REG_LIST_DCN3_0_RI(2),\ - MPC_OUT_MUX_REG_LIST_DCN3_0_RI(3),\ - MPC_DWB_MUX_REG_LIST_DCN3_0_RI(0) - -static const struct dcn30_mpc_shift mpc_shift = { - MPC_COMMON_MASK_SH_LIST_DCN32(__SHIFT) -}; - -static const struct dcn30_mpc_mask mpc_mask = { - MPC_COMMON_MASK_SH_LIST_DCN32(_MASK) -}; - -#define optc_regs_init(id)\ - OPTC_COMMON_REG_LIST_DCN3_2_RI(id) - -static struct dcn_optc_registers optc_regs[4]; - -static const struct dcn_optc_shift optc_shift = { - OPTC_COMMON_MASK_SH_LIST_DCN3_2(__SHIFT) -}; - -static const struct dcn_optc_mask optc_mask = { - OPTC_COMMON_MASK_SH_LIST_DCN3_2(_MASK) -}; - -#define hubp_regs_init(id)\ - HUBP_REG_LIST_DCN32_RI(id) - -static struct dcn_hubp2_registers hubp_regs[4]; - - -static const struct dcn_hubp2_shift hubp_shift = { - HUBP_MASK_SH_LIST_DCN32(__SHIFT) -}; - -static const struct dcn_hubp2_mask hubp_mask = { - HUBP_MASK_SH_LIST_DCN32(_MASK) -}; - -static struct dcn_hubbub_registers hubbub_reg; -#define hubbub_reg_init()\ - HUBBUB_REG_LIST_DCN32_RI(0) - -static const struct dcn_hubbub_shift hubbub_shift = { - HUBBUB_MASK_SH_LIST_DCN32(__SHIFT) -}; - -static const struct dcn_hubbub_mask hubbub_mask = { - HUBBUB_MASK_SH_LIST_DCN32(_MASK) -}; - -static struct dccg_registers dccg_regs; - -#define dccg_regs_init()\ - DCCG_REG_LIST_DCN32_RI() - -static const struct dccg_shift dccg_shift = { - DCCG_MASK_SH_LIST_DCN32(__SHIFT) -}; - -static const struct dccg_mask dccg_mask = { - DCCG_MASK_SH_LIST_DCN32(_MASK) -}; - - -#define SRII2(reg_name_pre, reg_name_post, id)\ - .reg_name_pre ## _ ## reg_name_post[id] = BASE(reg ## reg_name_pre \ - ## id ## _ ## reg_name_post ## _BASE_IDX) + \ - reg ## reg_name_pre ## id ## _ ## reg_name_post - - -#define HWSEQ_DCN32_REG_LIST()\ - SR(DCHUBBUB_GLOBAL_TIMER_CNTL), \ - SR(DIO_MEM_PWR_CTRL), \ - SR(ODM_MEM_PWR_CTRL3), \ - SR(MMHUBBUB_MEM_PWR_CNTL), \ - SR(DCCG_GATE_DISABLE_CNTL), \ - SR(DCCG_GATE_DISABLE_CNTL2), \ - SR(DCFCLK_CNTL),\ - SR(DC_MEM_GLOBAL_PWR_REQ_CNTL), \ - SRII(PIXEL_RATE_CNTL, OTG, 0), \ - SRII(PIXEL_RATE_CNTL, OTG, 1),\ - SRII(PIXEL_RATE_CNTL, OTG, 2),\ - SRII(PIXEL_RATE_CNTL, OTG, 3),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 0),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 1),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 2),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 3),\ - SR(MICROSECOND_TIME_BASE_DIV), \ - SR(MILLISECOND_TIME_BASE_DIV), \ - SR(DISPCLK_FREQ_CHANGE_CNTL), \ - SR(RBBMIF_TIMEOUT_DIS), \ - SR(RBBMIF_TIMEOUT_DIS_2), \ - SR(DCHUBBUB_CRC_CTRL), \ - SR(DPP_TOP0_DPP_CRC_CTRL), \ - SR(DPP_TOP0_DPP_CRC_VAL_B_A), \ - SR(DPP_TOP0_DPP_CRC_VAL_R_G), \ - SR(MPC_CRC_CTRL), \ - SR(MPC_CRC_RESULT_GB), \ - SR(MPC_CRC_RESULT_C), \ - SR(MPC_CRC_RESULT_AR), \ - SR(DOMAIN0_PG_CONFIG), \ - SR(DOMAIN1_PG_CONFIG), \ - SR(DOMAIN2_PG_CONFIG), \ - SR(DOMAIN3_PG_CONFIG), \ - SR(DOMAIN16_PG_CONFIG), \ - SR(DOMAIN17_PG_CONFIG), \ - SR(DOMAIN18_PG_CONFIG), \ - SR(DOMAIN19_PG_CONFIG), \ - SR(DOMAIN0_PG_STATUS), \ - SR(DOMAIN1_PG_STATUS), \ - SR(DOMAIN2_PG_STATUS), \ - SR(DOMAIN3_PG_STATUS), \ - SR(DOMAIN16_PG_STATUS), \ - SR(DOMAIN17_PG_STATUS), \ - SR(DOMAIN18_PG_STATUS), \ - SR(DOMAIN19_PG_STATUS), \ - SR(D1VGA_CONTROL), \ - SR(D2VGA_CONTROL), \ - SR(D3VGA_CONTROL), \ - SR(D4VGA_CONTROL), \ - SR(D5VGA_CONTROL), \ - SR(D6VGA_CONTROL), \ - SR(DC_IP_REQUEST_CNTL), \ - SR(AZALIA_AUDIO_DTO), \ - SR(AZALIA_CONTROLLER_CLOCK_GATING) - -static struct dce_hwseq_registers hwseq_reg; - -#define hwseq_reg_init()\ - HWSEQ_DCN32_REG_LIST() - -#define HWSEQ_DCN32_MASK_SH_LIST(mask_sh)\ - HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ - HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \ - HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN19_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN19_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN16_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN17_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN18_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN19_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \ - HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh), \ - HWS_SF(, HPO_TOP_CLOCK_CONTROL, HPO_HDMISTREAMCLK_G_GATE_DIS, mask_sh), \ - HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_UNASSIGNED_PWR_MODE, mask_sh), \ - HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_VBLANK_PWR_MODE, mask_sh), \ - HWS_SF(, MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, mask_sh) - -static const struct dce_hwseq_shift hwseq_shift = { - HWSEQ_DCN32_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_hwseq_mask hwseq_mask = { - HWSEQ_DCN32_MASK_SH_LIST(_MASK) -}; -#define vmid_regs_init(id)\ - DCN20_VMID_REG_LIST_RI(id) - -static struct dcn_vmid_registers vmid_regs[16]; - -static const struct dcn20_vmid_shift vmid_shifts = { - DCN20_VMID_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn20_vmid_mask vmid_masks = { - DCN20_VMID_MASK_SH_LIST(_MASK) -}; - -static const struct resource_caps res_cap_dcn32 = { - .num_timing_generator = 4, - .num_opp = 4, - .num_video_plane = 4, - .num_audio = 5, - .num_stream_encoder = 5, - .num_hpo_dp_stream_encoder = 4, - .num_hpo_dp_link_encoder = 2, - .num_pll = 5, - .num_dwb = 1, - .num_ddc = 5, - .num_vmid = 16, - .num_mpc_3dlut = 4, - .num_dsc = 4, -}; - -static const struct dc_plane_cap plane_cap = { - .type = DC_PLANE_TYPE_DCN_UNIVERSAL, - .per_pixel_alpha = true, - - .pixel_format_support = { - .argb8888 = true, - .nv12 = true, - .fp16 = true, - .p010 = true, - .ayuv = false, - }, - - .max_upscale_factor = { - .argb8888 = 16000, - .nv12 = 16000, - .fp16 = 16000 - }, - - // 6:1 downscaling ratio: 1000/6 = 166.666 - .max_downscale_factor = { - .argb8888 = 167, - .nv12 = 167, - .fp16 = 167 - }, - 64, - 64 -}; - -static const struct dc_debug_options debug_defaults_drv = { - .disable_dmcu = true, - .force_abm_enable = false, - .timing_trace = false, - .clock_trace = true, - .disable_pplib_clock_request = false, - .pipe_split_policy = MPC_SPLIT_AVOID, // Due to CRB, no need to MPC split anymore - .force_single_disp_pipe_split = false, - .disable_dcc = DCC_ENABLE, - .vsr_support = true, - .performance_trace = false, - .max_downscale_src_width = 7680,/*upto 8K*/ - .disable_pplib_wm_range = false, - .scl_reset_length10 = true, - .sanity_checks = false, - .underflow_assert_delay_us = 0xFFFFFFFF, - .dwb_fi_phase = -1, // -1 = disable, - .dmub_command_table = true, - .enable_mem_low_power = { - .bits = { - .vga = false, - .i2c = false, - .dmcu = false, // This is previously known to cause hang on S3 cycles if enabled - .dscl = false, - .cm = false, - .mpc = false, - .optc = true, - } - }, - .use_max_lb = true, - .force_disable_subvp = false, - .exit_idle_opt_for_cursor_updates = true, - .using_dml2 = false, - .enable_single_display_2to1_odm_policy = true, - - /* Must match enable_single_display_2to1_odm_policy to support dynamic ODM transitions*/ - .enable_double_buffered_dsc_pg_support = true, - .enable_dp_dig_pixel_rate_div_policy = 1, - .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, - .override_dispclk_programming = true, - .disable_fpo_optimizations = false, - .fpo_vactive_margin_us = 2000, // 2000us - .disable_fpo_vactive = false, - .disable_boot_optimizations = false, - .disable_subvp_high_refresh = false, - .disable_dp_plus_plus_wa = true, - .fpo_vactive_min_active_margin_us = 200, - .fpo_vactive_max_blank_us = 1000, - .enable_legacy_fast_update = false, -}; - -static struct dce_aux *dcn32_aux_engine_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct aux_engine_dce110 *aux_engine = - kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); - - if (!aux_engine) - return NULL; - -#undef REG_STRUCT -#define REG_STRUCT aux_engine_regs - aux_engine_regs_init(0), - aux_engine_regs_init(1), - aux_engine_regs_init(2), - aux_engine_regs_init(3), - aux_engine_regs_init(4); - - dce110_aux_engine_construct(aux_engine, ctx, inst, - SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, - &aux_engine_regs[inst], - &aux_mask, - &aux_shift, - ctx->dc->caps.extended_aux_timeout_support); - - return &aux_engine->base; -} -#define i2c_inst_regs_init(id)\ - I2C_HW_ENGINE_COMMON_REG_LIST_DCN30_RI(id) - -static struct dce_i2c_registers i2c_hw_regs[5]; - -static const struct dce_i2c_shift i2c_shifts = { - I2C_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dce_i2c_mask i2c_masks = { - I2C_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -static struct dce_i2c_hw *dcn32_i2c_hw_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dce_i2c_hw *dce_i2c_hw = - kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); - - if (!dce_i2c_hw) - return NULL; - -#undef REG_STRUCT -#define REG_STRUCT i2c_hw_regs - i2c_inst_regs_init(1), - i2c_inst_regs_init(2), - i2c_inst_regs_init(3), - i2c_inst_regs_init(4), - i2c_inst_regs_init(5); - - dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst, - &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); - - return dce_i2c_hw; -} - -static struct clock_source *dcn32_clock_source_create( - struct dc_context *ctx, - struct dc_bios *bios, - enum clock_source_id id, - const struct dce110_clk_src_regs *regs, - bool dp_clk_src) -{ - struct dce110_clk_src *clk_src = - kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); - - if (!clk_src) - return NULL; - - if (dcn31_clk_src_construct(clk_src, ctx, bios, id, - regs, &cs_shift, &cs_mask)) { - clk_src->base.dp_clk_src = dp_clk_src; - return &clk_src->base; - } - - kfree(clk_src); - BREAK_TO_DEBUGGER(); - return NULL; -} - -static struct hubbub *dcn32_hubbub_create(struct dc_context *ctx) -{ - int i; - - struct dcn20_hubbub *hubbub2 = kzalloc(sizeof(struct dcn20_hubbub), - GFP_KERNEL); - - if (!hubbub2) - return NULL; - -#undef REG_STRUCT -#define REG_STRUCT hubbub_reg - hubbub_reg_init(); - -#undef REG_STRUCT -#define REG_STRUCT vmid_regs - vmid_regs_init(0), - vmid_regs_init(1), - vmid_regs_init(2), - vmid_regs_init(3), - vmid_regs_init(4), - vmid_regs_init(5), - vmid_regs_init(6), - vmid_regs_init(7), - vmid_regs_init(8), - vmid_regs_init(9), - vmid_regs_init(10), - vmid_regs_init(11), - vmid_regs_init(12), - vmid_regs_init(13), - vmid_regs_init(14), - vmid_regs_init(15); - - hubbub32_construct(hubbub2, ctx, - &hubbub_reg, - &hubbub_shift, - &hubbub_mask, - ctx->dc->dml.ip.det_buffer_size_kbytes, - ctx->dc->dml.ip.pixel_chunk_size_kbytes, - ctx->dc->dml.ip.config_return_buffer_size_in_kbytes); - - - for (i = 0; i < res_cap_dcn32.num_vmid; i++) { - struct dcn20_vmid *vmid = &hubbub2->vmid[i]; - - vmid->ctx = ctx; - - vmid->regs = &vmid_regs[i]; - vmid->shifts = &vmid_shifts; - vmid->masks = &vmid_masks; - } - - return &hubbub2->base; -} - -static struct hubp *dcn32_hubp_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn20_hubp *hubp2 = - kzalloc(sizeof(struct dcn20_hubp), GFP_KERNEL); - - if (!hubp2) - return NULL; - -#undef REG_STRUCT -#define REG_STRUCT hubp_regs - hubp_regs_init(0), - hubp_regs_init(1), - hubp_regs_init(2), - hubp_regs_init(3); - - if (hubp32_construct(hubp2, ctx, inst, - &hubp_regs[inst], &hubp_shift, &hubp_mask)) - return &hubp2->base; - - BREAK_TO_DEBUGGER(); - kfree(hubp2); - return NULL; -} - -static void dcn32_dpp_destroy(struct dpp **dpp) -{ - kfree(TO_DCN30_DPP(*dpp)); - *dpp = NULL; -} - -static struct dpp *dcn32_dpp_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn3_dpp *dpp3 = - kzalloc(sizeof(struct dcn3_dpp), GFP_KERNEL); - - if (!dpp3) - return NULL; - -#undef REG_STRUCT -#define REG_STRUCT dpp_regs - dpp_regs_init(0), - dpp_regs_init(1), - dpp_regs_init(2), - dpp_regs_init(3); - - if (dpp32_construct(dpp3, ctx, inst, - &dpp_regs[inst], &tf_shift, &tf_mask)) - return &dpp3->base; - - BREAK_TO_DEBUGGER(); - kfree(dpp3); - return NULL; -} - -static struct mpc *dcn32_mpc_create( - struct dc_context *ctx, - int num_mpcc, - int num_rmu) -{ - struct dcn30_mpc *mpc30 = kzalloc(sizeof(struct dcn30_mpc), - GFP_KERNEL); - - if (!mpc30) - return NULL; - -#undef REG_STRUCT -#define REG_STRUCT mpc_regs - dcn_mpc_regs_init(); - - dcn32_mpc_construct(mpc30, ctx, - &mpc_regs, - &mpc_shift, - &mpc_mask, - num_mpcc, - num_rmu); - - return &mpc30->base; -} - -static struct output_pixel_processor *dcn32_opp_create( - struct dc_context *ctx, uint32_t inst) -{ - struct dcn20_opp *opp2 = - kzalloc(sizeof(struct dcn20_opp), GFP_KERNEL); - - if (!opp2) { - BREAK_TO_DEBUGGER(); - return NULL; - } - -#undef REG_STRUCT -#define REG_STRUCT opp_regs - opp_regs_init(0), - opp_regs_init(1), - opp_regs_init(2), - opp_regs_init(3); - - dcn20_opp_construct(opp2, ctx, inst, - &opp_regs[inst], &opp_shift, &opp_mask); - return &opp2->base; -} - - -static struct timing_generator *dcn32_timing_generator_create( - struct dc_context *ctx, - uint32_t instance) -{ - struct optc *tgn10 = - kzalloc(sizeof(struct optc), GFP_KERNEL); - - if (!tgn10) - return NULL; - -#undef REG_STRUCT -#define REG_STRUCT optc_regs - optc_regs_init(0), - optc_regs_init(1), - optc_regs_init(2), - optc_regs_init(3); - - tgn10->base.inst = instance; - tgn10->base.ctx = ctx; - - tgn10->tg_regs = &optc_regs[instance]; - tgn10->tg_shift = &optc_shift; - tgn10->tg_mask = &optc_mask; - - dcn32_timing_generator_init(tgn10); - - return &tgn10->base; -} - -static const struct encoder_feature_support link_enc_feature = { - .max_hdmi_deep_color = COLOR_DEPTH_121212, - .max_hdmi_pixel_clock = 600000, - .hdmi_ycbcr420_supported = true, - .dp_ycbcr420_supported = true, - .fec_supported = true, - .flags.bits.IS_HBR2_CAPABLE = true, - .flags.bits.IS_HBR3_CAPABLE = true, - .flags.bits.IS_TPS3_CAPABLE = true, - .flags.bits.IS_TPS4_CAPABLE = true -}; - -static struct link_encoder *dcn32_link_encoder_create( - struct dc_context *ctx, - const struct encoder_init_data *enc_init_data) -{ - struct dcn20_link_encoder *enc20 = - kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); - - if (!enc20) - return NULL; - -#undef REG_STRUCT -#define REG_STRUCT link_enc_aux_regs - aux_regs_init(0), - aux_regs_init(1), - aux_regs_init(2), - aux_regs_init(3), - aux_regs_init(4); - -#undef REG_STRUCT -#define REG_STRUCT link_enc_hpd_regs - hpd_regs_init(0), - hpd_regs_init(1), - hpd_regs_init(2), - hpd_regs_init(3), - hpd_regs_init(4); - -#undef REG_STRUCT -#define REG_STRUCT link_enc_regs - link_regs_init(0, A), - link_regs_init(1, B), - link_regs_init(2, C), - link_regs_init(3, D), - link_regs_init(4, E); - - dcn32_link_encoder_construct(enc20, - enc_init_data, - &link_enc_feature, - &link_enc_regs[enc_init_data->transmitter], - &link_enc_aux_regs[enc_init_data->channel - 1], - &link_enc_hpd_regs[enc_init_data->hpd_source], - &le_shift, - &le_mask); - - return &enc20->enc10.base; -} - -struct panel_cntl *dcn32_panel_cntl_create(const struct panel_cntl_init_data *init_data) -{ - struct dcn31_panel_cntl *panel_cntl = - kzalloc(sizeof(struct dcn31_panel_cntl), GFP_KERNEL); - - if (!panel_cntl) - return NULL; - - dcn31_panel_cntl_construct(panel_cntl, init_data); - - return &panel_cntl->base; -} - -static void read_dce_straps( - struct dc_context *ctx, - struct resource_straps *straps) -{ - generic_reg_get(ctx, ctx->dcn_reg_offsets[regDC_PINSTRAPS_BASE_IDX] + regDC_PINSTRAPS, - FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio); - -} - -static struct audio *dcn32_create_audio( - struct dc_context *ctx, unsigned int inst) -{ - -#undef REG_STRUCT -#define REG_STRUCT audio_regs - audio_regs_init(0), - audio_regs_init(1), - audio_regs_init(2), - audio_regs_init(3), - audio_regs_init(4); - - return dce_audio_create(ctx, inst, - &audio_regs[inst], &audio_shift, &audio_mask); -} - -static struct vpg *dcn32_vpg_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn30_vpg *vpg3 = kzalloc(sizeof(struct dcn30_vpg), GFP_KERNEL); - - if (!vpg3) - return NULL; - -#undef REG_STRUCT -#define REG_STRUCT vpg_regs - vpg_regs_init(0), - vpg_regs_init(1), - vpg_regs_init(2), - vpg_regs_init(3), - vpg_regs_init(4), - vpg_regs_init(5), - vpg_regs_init(6), - vpg_regs_init(7), - vpg_regs_init(8), - vpg_regs_init(9); - - vpg3_construct(vpg3, ctx, inst, - &vpg_regs[inst], - &vpg_shift, - &vpg_mask); - - return &vpg3->base; -} - -static struct afmt *dcn32_afmt_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn30_afmt *afmt3 = kzalloc(sizeof(struct dcn30_afmt), GFP_KERNEL); - - if (!afmt3) - return NULL; - -#undef REG_STRUCT -#define REG_STRUCT afmt_regs - afmt_regs_init(0), - afmt_regs_init(1), - afmt_regs_init(2), - afmt_regs_init(3), - afmt_regs_init(4), - afmt_regs_init(5); - - afmt3_construct(afmt3, ctx, inst, - &afmt_regs[inst], - &afmt_shift, - &afmt_mask); - - return &afmt3->base; -} - -static struct apg *dcn31_apg_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn31_apg *apg31 = kzalloc(sizeof(struct dcn31_apg), GFP_KERNEL); - - if (!apg31) - return NULL; - -#undef REG_STRUCT -#define REG_STRUCT apg_regs - apg_regs_init(0), - apg_regs_init(1), - apg_regs_init(2), - apg_regs_init(3); - - apg31_construct(apg31, ctx, inst, - &apg_regs[inst], - &apg_shift, - &apg_mask); - - return &apg31->base; -} - -static struct stream_encoder *dcn32_stream_encoder_create( - enum engine_id eng_id, - struct dc_context *ctx) -{ - struct dcn10_stream_encoder *enc1; - struct vpg *vpg; - struct afmt *afmt; - int vpg_inst; - int afmt_inst; - - /* Mapping of VPG, AFMT, DME register blocks to DIO block instance */ - if (eng_id <= ENGINE_ID_DIGF) { - vpg_inst = eng_id; - afmt_inst = eng_id; - } else - return NULL; - - enc1 = kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL); - vpg = dcn32_vpg_create(ctx, vpg_inst); - afmt = dcn32_afmt_create(ctx, afmt_inst); - - if (!enc1 || !vpg || !afmt) { - kfree(enc1); - kfree(vpg); - kfree(afmt); - return NULL; - } - -#undef REG_STRUCT -#define REG_STRUCT stream_enc_regs - stream_enc_regs_init(0), - stream_enc_regs_init(1), - stream_enc_regs_init(2), - stream_enc_regs_init(3), - stream_enc_regs_init(4); - - dcn32_dio_stream_encoder_construct(enc1, ctx, ctx->dc_bios, - eng_id, vpg, afmt, - &stream_enc_regs[eng_id], - &se_shift, &se_mask); - - return &enc1->base; -} - -static struct hpo_dp_stream_encoder *dcn32_hpo_dp_stream_encoder_create( - enum engine_id eng_id, - struct dc_context *ctx) -{ - struct dcn31_hpo_dp_stream_encoder *hpo_dp_enc31; - struct vpg *vpg; - struct apg *apg; - uint32_t hpo_dp_inst; - uint32_t vpg_inst; - uint32_t apg_inst; - - ASSERT((eng_id >= ENGINE_ID_HPO_DP_0) && (eng_id <= ENGINE_ID_HPO_DP_3)); - hpo_dp_inst = eng_id - ENGINE_ID_HPO_DP_0; - - /* Mapping of VPG register blocks to HPO DP block instance: - * VPG[6] -> HPO_DP[0] - * VPG[7] -> HPO_DP[1] - * VPG[8] -> HPO_DP[2] - * VPG[9] -> HPO_DP[3] - */ - vpg_inst = hpo_dp_inst + 6; - - /* Mapping of APG register blocks to HPO DP block instance: - * APG[0] -> HPO_DP[0] - * APG[1] -> HPO_DP[1] - * APG[2] -> HPO_DP[2] - * APG[3] -> HPO_DP[3] - */ - apg_inst = hpo_dp_inst; - - /* allocate HPO stream encoder and create VPG sub-block */ - hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_stream_encoder), GFP_KERNEL); - vpg = dcn32_vpg_create(ctx, vpg_inst); - apg = dcn31_apg_create(ctx, apg_inst); - - if (!hpo_dp_enc31 || !vpg || !apg) { - kfree(hpo_dp_enc31); - kfree(vpg); - kfree(apg); - return NULL; - } - -#undef REG_STRUCT -#define REG_STRUCT hpo_dp_stream_enc_regs - hpo_dp_stream_encoder_reg_init(0), - hpo_dp_stream_encoder_reg_init(1), - hpo_dp_stream_encoder_reg_init(2), - hpo_dp_stream_encoder_reg_init(3); - - dcn31_hpo_dp_stream_encoder_construct(hpo_dp_enc31, ctx, ctx->dc_bios, - hpo_dp_inst, eng_id, vpg, apg, - &hpo_dp_stream_enc_regs[hpo_dp_inst], - &hpo_dp_se_shift, &hpo_dp_se_mask); - - return &hpo_dp_enc31->base; -} - -static struct hpo_dp_link_encoder *dcn32_hpo_dp_link_encoder_create( - uint8_t inst, - struct dc_context *ctx) -{ - struct dcn31_hpo_dp_link_encoder *hpo_dp_enc31; - - /* allocate HPO link encoder */ - hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_link_encoder), GFP_KERNEL); - -#undef REG_STRUCT -#define REG_STRUCT hpo_dp_link_enc_regs - hpo_dp_link_encoder_reg_init(0), - hpo_dp_link_encoder_reg_init(1); - - hpo_dp_link_encoder32_construct(hpo_dp_enc31, ctx, inst, - &hpo_dp_link_enc_regs[inst], - &hpo_dp_le_shift, &hpo_dp_le_mask); - - return &hpo_dp_enc31->base; -} - -static struct dce_hwseq *dcn32_hwseq_create( - struct dc_context *ctx) -{ - struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); - -#undef REG_STRUCT -#define REG_STRUCT hwseq_reg - hwseq_reg_init(); - - if (hws) { - hws->ctx = ctx; - hws->regs = &hwseq_reg; - hws->shifts = &hwseq_shift; - hws->masks = &hwseq_mask; - } - return hws; -} -static const struct resource_create_funcs res_create_funcs = { - .read_dce_straps = read_dce_straps, - .create_audio = dcn32_create_audio, - .create_stream_encoder = dcn32_stream_encoder_create, - .create_hpo_dp_stream_encoder = dcn32_hpo_dp_stream_encoder_create, - .create_hpo_dp_link_encoder = dcn32_hpo_dp_link_encoder_create, - .create_hwseq = dcn32_hwseq_create, -}; - -static void dcn32_resource_destruct(struct dcn32_resource_pool *pool) -{ - unsigned int i; - - for (i = 0; i < pool->base.stream_enc_count; i++) { - if (pool->base.stream_enc[i] != NULL) { - if (pool->base.stream_enc[i]->vpg != NULL) { - kfree(DCN30_VPG_FROM_VPG(pool->base.stream_enc[i]->vpg)); - pool->base.stream_enc[i]->vpg = NULL; - } - if (pool->base.stream_enc[i]->afmt != NULL) { - kfree(DCN30_AFMT_FROM_AFMT(pool->base.stream_enc[i]->afmt)); - pool->base.stream_enc[i]->afmt = NULL; - } - kfree(DCN10STRENC_FROM_STRENC(pool->base.stream_enc[i])); - pool->base.stream_enc[i] = NULL; - } - } - - for (i = 0; i < pool->base.hpo_dp_stream_enc_count; i++) { - if (pool->base.hpo_dp_stream_enc[i] != NULL) { - if (pool->base.hpo_dp_stream_enc[i]->vpg != NULL) { - kfree(DCN30_VPG_FROM_VPG(pool->base.hpo_dp_stream_enc[i]->vpg)); - pool->base.hpo_dp_stream_enc[i]->vpg = NULL; - } - if (pool->base.hpo_dp_stream_enc[i]->apg != NULL) { - kfree(DCN31_APG_FROM_APG(pool->base.hpo_dp_stream_enc[i]->apg)); - pool->base.hpo_dp_stream_enc[i]->apg = NULL; - } - kfree(DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(pool->base.hpo_dp_stream_enc[i])); - pool->base.hpo_dp_stream_enc[i] = NULL; - } - } - - for (i = 0; i < pool->base.hpo_dp_link_enc_count; i++) { - if (pool->base.hpo_dp_link_enc[i] != NULL) { - kfree(DCN3_1_HPO_DP_LINK_ENC_FROM_HPO_LINK_ENC(pool->base.hpo_dp_link_enc[i])); - pool->base.hpo_dp_link_enc[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_dsc; i++) { - if (pool->base.dscs[i] != NULL) - dcn20_dsc_destroy(&pool->base.dscs[i]); - } - - if (pool->base.mpc != NULL) { - kfree(TO_DCN20_MPC(pool->base.mpc)); - pool->base.mpc = NULL; - } - if (pool->base.hubbub != NULL) { - kfree(TO_DCN20_HUBBUB(pool->base.hubbub)); - pool->base.hubbub = NULL; - } - for (i = 0; i < pool->base.pipe_count; i++) { - if (pool->base.dpps[i] != NULL) - dcn32_dpp_destroy(&pool->base.dpps[i]); - - if (pool->base.ipps[i] != NULL) - pool->base.ipps[i]->funcs->ipp_destroy(&pool->base.ipps[i]); - - if (pool->base.hubps[i] != NULL) { - kfree(TO_DCN20_HUBP(pool->base.hubps[i])); - pool->base.hubps[i] = NULL; - } - - if (pool->base.irqs != NULL) { - dal_irq_service_destroy(&pool->base.irqs); - } - } - - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - if (pool->base.engines[i] != NULL) - dce110_engine_destroy(&pool->base.engines[i]); - if (pool->base.hw_i2cs[i] != NULL) { - kfree(pool->base.hw_i2cs[i]); - pool->base.hw_i2cs[i] = NULL; - } - if (pool->base.sw_i2cs[i] != NULL) { - kfree(pool->base.sw_i2cs[i]); - pool->base.sw_i2cs[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_opp; i++) { - if (pool->base.opps[i] != NULL) - pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]); - } - - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - if (pool->base.timing_generators[i] != NULL) { - kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i])); - pool->base.timing_generators[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_dwb; i++) { - if (pool->base.dwbc[i] != NULL) { - kfree(TO_DCN30_DWBC(pool->base.dwbc[i])); - pool->base.dwbc[i] = NULL; - } - if (pool->base.mcif_wb[i] != NULL) { - kfree(TO_DCN30_MMHUBBUB(pool->base.mcif_wb[i])); - pool->base.mcif_wb[i] = NULL; - } - } - - for (i = 0; i < pool->base.audio_count; i++) { - if (pool->base.audios[i]) - dce_aud_destroy(&pool->base.audios[i]); - } - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] != NULL) { - dcn20_clock_source_destroy(&pool->base.clock_sources[i]); - pool->base.clock_sources[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_mpc_3dlut; i++) { - if (pool->base.mpc_lut[i] != NULL) { - dc_3dlut_func_release(pool->base.mpc_lut[i]); - pool->base.mpc_lut[i] = NULL; - } - if (pool->base.mpc_shaper[i] != NULL) { - dc_transfer_func_release(pool->base.mpc_shaper[i]); - pool->base.mpc_shaper[i] = NULL; - } - } - - if (pool->base.dp_clock_source != NULL) { - dcn20_clock_source_destroy(&pool->base.dp_clock_source); - pool->base.dp_clock_source = NULL; - } - - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - if (pool->base.multiple_abms[i] != NULL) - dce_abm_destroy(&pool->base.multiple_abms[i]); - } - - if (pool->base.psr != NULL) - dmub_psr_destroy(&pool->base.psr); - - if (pool->base.dccg != NULL) - dcn_dccg_destroy(&pool->base.dccg); - - if (pool->base.oem_device != NULL) { - struct dc *dc = pool->base.oem_device->ctx->dc; - - dc->link_srv->destroy_ddc_service(&pool->base.oem_device); - } -} - - -static bool dcn32_dwbc_create(struct dc_context *ctx, struct resource_pool *pool) -{ - int i; - uint32_t dwb_count = pool->res_cap->num_dwb; - - for (i = 0; i < dwb_count; i++) { - struct dcn30_dwbc *dwbc30 = kzalloc(sizeof(struct dcn30_dwbc), - GFP_KERNEL); - - if (!dwbc30) { - dm_error("DC: failed to create dwbc30!\n"); - return false; - } - -#undef REG_STRUCT -#define REG_STRUCT dwbc30_regs - dwbc_regs_dcn3_init(0); - - dcn30_dwbc_construct(dwbc30, ctx, - &dwbc30_regs[i], - &dwbc30_shift, - &dwbc30_mask, - i); - - pool->dwbc[i] = &dwbc30->base; - } - return true; -} - -static bool dcn32_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool) -{ - int i; - uint32_t dwb_count = pool->res_cap->num_dwb; - - for (i = 0; i < dwb_count; i++) { - struct dcn30_mmhubbub *mcif_wb30 = kzalloc(sizeof(struct dcn30_mmhubbub), - GFP_KERNEL); - - if (!mcif_wb30) { - dm_error("DC: failed to create mcif_wb30!\n"); - return false; - } - -#undef REG_STRUCT -#define REG_STRUCT mcif_wb30_regs - mcif_wb_regs_dcn3_init(0); - - dcn32_mmhubbub_construct(mcif_wb30, ctx, - &mcif_wb30_regs[i], - &mcif_wb30_shift, - &mcif_wb30_mask, - i); - - pool->mcif_wb[i] = &mcif_wb30->base; - } - return true; -} - -static struct display_stream_compressor *dcn32_dsc_create( - struct dc_context *ctx, uint32_t inst) -{ - struct dcn20_dsc *dsc = - kzalloc(sizeof(struct dcn20_dsc), GFP_KERNEL); - - if (!dsc) { - BREAK_TO_DEBUGGER(); - return NULL; - } - -#undef REG_STRUCT -#define REG_STRUCT dsc_regs - dsc_regsDCN20_init(0), - dsc_regsDCN20_init(1), - dsc_regsDCN20_init(2), - dsc_regsDCN20_init(3); - - dsc2_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask); - - dsc->max_image_width = 6016; - - return &dsc->base; -} - -static void dcn32_destroy_resource_pool(struct resource_pool **pool) -{ - struct dcn32_resource_pool *dcn32_pool = TO_DCN32_RES_POOL(*pool); - - dcn32_resource_destruct(dcn32_pool); - kfree(dcn32_pool); - *pool = NULL; -} - -bool dcn32_acquire_post_bldn_3dlut( - struct resource_context *res_ctx, - const struct resource_pool *pool, - int mpcc_id, - struct dc_3dlut **lut, - struct dc_transfer_func **shaper) -{ - bool ret = false; - - ASSERT(*lut == NULL && *shaper == NULL); - *lut = NULL; - *shaper = NULL; - - if (!res_ctx->is_mpc_3dlut_acquired[mpcc_id]) { - *lut = pool->mpc_lut[mpcc_id]; - *shaper = pool->mpc_shaper[mpcc_id]; - res_ctx->is_mpc_3dlut_acquired[mpcc_id] = true; - ret = true; - } - return ret; -} - -bool dcn32_release_post_bldn_3dlut( - struct resource_context *res_ctx, - const struct resource_pool *pool, - struct dc_3dlut **lut, - struct dc_transfer_func **shaper) -{ - int i; - bool ret = false; - - for (i = 0; i < pool->res_cap->num_mpc_3dlut; i++) { - if (pool->mpc_lut[i] == *lut && pool->mpc_shaper[i] == *shaper) { - res_ctx->is_mpc_3dlut_acquired[i] = false; - pool->mpc_lut[i]->state.raw = 0; - *lut = NULL; - *shaper = NULL; - ret = true; - break; - } - } - return ret; -} - -static void dcn32_enable_phantom_plane(struct dc *dc, - struct dc_state *context, - struct dc_stream_state *phantom_stream, - unsigned int dc_pipe_idx) -{ - struct dc_plane_state *phantom_plane = NULL; - struct dc_plane_state *prev_phantom_plane = NULL; - struct pipe_ctx *curr_pipe = &context->res_ctx.pipe_ctx[dc_pipe_idx]; - - while (curr_pipe) { - if (curr_pipe->top_pipe && curr_pipe->top_pipe->plane_state == curr_pipe->plane_state) - phantom_plane = prev_phantom_plane; - else - phantom_plane = dc_create_plane_state(dc); - - memcpy(&phantom_plane->address, &curr_pipe->plane_state->address, sizeof(phantom_plane->address)); - memcpy(&phantom_plane->scaling_quality, &curr_pipe->plane_state->scaling_quality, - sizeof(phantom_plane->scaling_quality)); - memcpy(&phantom_plane->src_rect, &curr_pipe->plane_state->src_rect, sizeof(phantom_plane->src_rect)); - memcpy(&phantom_plane->dst_rect, &curr_pipe->plane_state->dst_rect, sizeof(phantom_plane->dst_rect)); - memcpy(&phantom_plane->clip_rect, &curr_pipe->plane_state->clip_rect, sizeof(phantom_plane->clip_rect)); - memcpy(&phantom_plane->plane_size, &curr_pipe->plane_state->plane_size, - sizeof(phantom_plane->plane_size)); - memcpy(&phantom_plane->tiling_info, &curr_pipe->plane_state->tiling_info, - sizeof(phantom_plane->tiling_info)); - memcpy(&phantom_plane->dcc, &curr_pipe->plane_state->dcc, sizeof(phantom_plane->dcc)); - phantom_plane->format = curr_pipe->plane_state->format; - phantom_plane->rotation = curr_pipe->plane_state->rotation; - phantom_plane->visible = curr_pipe->plane_state->visible; - - /* Shadow pipe has small viewport. */ - phantom_plane->clip_rect.y = 0; - phantom_plane->clip_rect.height = phantom_stream->src.height; - - phantom_plane->is_phantom = true; - - dc_add_plane_to_context(dc, phantom_stream, phantom_plane, context); - - curr_pipe = curr_pipe->bottom_pipe; - prev_phantom_plane = phantom_plane; - } -} - -static struct dc_stream_state *dcn32_enable_phantom_stream(struct dc *dc, - struct dc_state *context, - display_e2e_pipe_params_st *pipes, - unsigned int pipe_cnt, - unsigned int dc_pipe_idx) -{ - struct dc_stream_state *phantom_stream = NULL; - struct pipe_ctx *ref_pipe = &context->res_ctx.pipe_ctx[dc_pipe_idx]; - - phantom_stream = dc_create_stream_for_sink(ref_pipe->stream->sink); - phantom_stream->signal = SIGNAL_TYPE_VIRTUAL; - phantom_stream->dpms_off = true; - phantom_stream->mall_stream_config.type = SUBVP_PHANTOM; - phantom_stream->mall_stream_config.paired_stream = ref_pipe->stream; - ref_pipe->stream->mall_stream_config.type = SUBVP_MAIN; - ref_pipe->stream->mall_stream_config.paired_stream = phantom_stream; - - /* stream has limited viewport and small timing */ - memcpy(&phantom_stream->timing, &ref_pipe->stream->timing, sizeof(phantom_stream->timing)); - memcpy(&phantom_stream->src, &ref_pipe->stream->src, sizeof(phantom_stream->src)); - memcpy(&phantom_stream->dst, &ref_pipe->stream->dst, sizeof(phantom_stream->dst)); - DC_FP_START(); - dcn32_set_phantom_stream_timing(dc, context, ref_pipe, phantom_stream, pipes, pipe_cnt, dc_pipe_idx); - DC_FP_END(); - - dc_add_stream_to_ctx(dc, context, phantom_stream); - return phantom_stream; -} - -void dcn32_retain_phantom_pipes(struct dc *dc, struct dc_state *context) -{ - int i; - struct dc_plane_state *phantom_plane = NULL; - struct dc_stream_state *phantom_stream = NULL; - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - - if (resource_is_pipe_type(pipe, OTG_MASTER) && - resource_is_pipe_type(pipe, DPP_PIPE) && - pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) { - phantom_plane = pipe->plane_state; - phantom_stream = pipe->stream; - - dc_plane_state_retain(phantom_plane); - dc_stream_retain(phantom_stream); - } - } -} - -// return true if removed piped from ctx, false otherwise -bool dcn32_remove_phantom_pipes(struct dc *dc, struct dc_state *context, bool fast_update) -{ - int i; - bool removed_pipe = false; - struct dc_plane_state *phantom_plane = NULL; - struct dc_stream_state *phantom_stream = NULL; - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - // build scaling params for phantom pipes - if (pipe->plane_state && pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) { - phantom_plane = pipe->plane_state; - phantom_stream = pipe->stream; - - dc_rem_all_planes_for_stream(dc, pipe->stream, context); - dc_remove_stream_from_ctx(dc, context, pipe->stream); - - /* Ref count is incremented on allocation and also when added to the context. - * Therefore we must call release for the the phantom plane and stream once - * they are removed from the ctx to finally decrement the refcount to 0 to free. - */ - dc_plane_state_release(phantom_plane); - dc_stream_release(phantom_stream); - - removed_pipe = true; - } - - /* For non-full updates, a shallow copy of the current state - * is created. In this case we don't want to erase the current - * state (there can be 2 HIRQL threads, one in flip, and one in - * checkMPO) that can cause a race condition. - * - * This is just a workaround, needs a proper fix. - */ - if (!fast_update) { - // Clear all phantom stream info - if (pipe->stream) { - pipe->stream->mall_stream_config.type = SUBVP_NONE; - pipe->stream->mall_stream_config.paired_stream = NULL; - } - - if (pipe->plane_state) { - pipe->plane_state->is_phantom = false; - } - } - } - return removed_pipe; -} - -/* TODO: Input to this function should indicate which pipe indexes (or streams) - * require a phantom pipe / stream - */ -void dcn32_add_phantom_pipes(struct dc *dc, struct dc_state *context, - display_e2e_pipe_params_st *pipes, - unsigned int pipe_cnt, - unsigned int index) -{ - struct dc_stream_state *phantom_stream = NULL; - unsigned int i; - - // The index of the DC pipe passed into this function is guarenteed to - // be a valid candidate for SubVP (i.e. has a plane, stream, doesn't - // already have phantom pipe assigned, etc.) by previous checks. - phantom_stream = dcn32_enable_phantom_stream(dc, context, pipes, pipe_cnt, index); - dcn32_enable_phantom_plane(dc, context, phantom_stream, index); - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - - // Build scaling params for phantom pipes which were newly added. - // We determine which phantom pipes were added by comparing with - // the phantom stream. - if (pipe->plane_state && pipe->stream && pipe->stream == phantom_stream && - pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) { - pipe->stream->use_dynamic_meta = false; - pipe->plane_state->flip_immediate = false; - if (!resource_build_scaling_params(pipe)) { - // Log / remove phantom pipes since failed to build scaling params - } - } - } -} - -static bool dml1_validate(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); - struct mall_temp_config mall_temp_config; - - /* To handle Freesync properly, setting FreeSync DML parameters - * to its default state for the first stage of validation - */ - context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching = false; - context->bw_ctx.dml.soc.dram_clock_change_requirement_final = true; - - DC_LOGGER_INIT(dc->ctx->logger); - - /* For fast validation, there are situations where a shallow copy of - * of the dc->current_state is created for the validation. In this case - * we want to save and restore the mall config because we always - * teardown subvp at the beginning of validation (and don't attempt - * to add it back if it's fast validation). If we don't restore the - * subvp config in cases of fast validation + shallow copy of the - * dc->current_state, the dc->current_state will have a partially - * removed subvp state when we did not intend to remove it. - */ - if (fast_validate) { - memset(&mall_temp_config, 0, sizeof(mall_temp_config)); - dcn32_save_mall_state(dc, context, &mall_temp_config); - } - - BW_VAL_TRACE_COUNT(); - - DC_FP_START(); - out = dcn32_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, fast_validate); - DC_FP_END(); - - if (fast_validate) - dcn32_restore_mall_state(dc, context, &mall_temp_config); - - if (pipe_cnt == 0) - goto validate_out; - - 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); - - dcn32_override_min_req_memclk(dc, context); - - 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; -} - -bool dcn32_validate_bandwidth(struct dc *dc, - struct dc_state *context, - bool fast_validate) -{ - bool out = false; - - if (dc->debug.using_dml2) - out = dml2_validate(dc, context, fast_validate); - else - out = dml1_validate(dc, context, fast_validate); - return out; -} - -int dcn32_populate_dml_pipes_from_context( - struct dc *dc, struct dc_state *context, - display_e2e_pipe_params_st *pipes, - bool fast_validate) -{ - int i, pipe_cnt; - struct resource_context *res_ctx = &context->res_ctx; - struct pipe_ctx *pipe = NULL; - bool subvp_in_use = false; - struct dc_crtc_timing *timing; - - dcn20_populate_dml_pipes_from_context(dc, context, pipes, fast_validate); - - for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) { - - if (!res_ctx->pipe_ctx[i].stream) - continue; - pipe = &res_ctx->pipe_ctx[i]; - timing = &pipe->stream->timing; - - pipes[pipe_cnt].pipe.src.gpuvm = true; - DC_FP_START(); - dcn32_zero_pipe_dcc_fraction(pipes, pipe_cnt); - DC_FP_END(); - pipes[pipe_cnt].pipe.dest.vfront_porch = timing->v_front_porch; - pipes[pipe_cnt].pipe.dest.odm_combine_policy = dm_odm_combine_policy_dal; - pipes[pipe_cnt].pipe.src.gpuvm_min_page_size_kbytes = 256; // according to spreadsheet - pipes[pipe_cnt].pipe.src.unbounded_req_mode = false; - pipes[pipe_cnt].pipe.scale_ratio_depth.lb_depth = dm_lb_19; - - /* Only populate DML input with subvp info for full updates. - * This is just a workaround -- needs a proper fix. - */ - if (!fast_validate) { - switch (pipe->stream->mall_stream_config.type) { - case SUBVP_MAIN: - pipes[pipe_cnt].pipe.src.use_mall_for_pstate_change = dm_use_mall_pstate_change_sub_viewport; - subvp_in_use = true; - break; - case SUBVP_PHANTOM: - pipes[pipe_cnt].pipe.src.use_mall_for_pstate_change = dm_use_mall_pstate_change_phantom_pipe; - pipes[pipe_cnt].pipe.src.use_mall_for_static_screen = dm_use_mall_static_screen_disable; - // Disallow unbounded req for SubVP according to DCHUB programming guide - pipes[pipe_cnt].pipe.src.unbounded_req_mode = false; - break; - case SUBVP_NONE: - pipes[pipe_cnt].pipe.src.use_mall_for_pstate_change = dm_use_mall_pstate_change_disable; - pipes[pipe_cnt].pipe.src.use_mall_for_static_screen = dm_use_mall_static_screen_disable; - break; - default: - break; - } - } - - pipes[pipe_cnt].dout.dsc_input_bpc = 0; - if (pipes[pipe_cnt].dout.dsc_enable) { - switch (timing->display_color_depth) { - case COLOR_DEPTH_888: - pipes[pipe_cnt].dout.dsc_input_bpc = 8; - break; - case COLOR_DEPTH_101010: - pipes[pipe_cnt].dout.dsc_input_bpc = 10; - break; - case COLOR_DEPTH_121212: - pipes[pipe_cnt].dout.dsc_input_bpc = 12; - break; - default: - ASSERT(0); - break; - } - } - - - pipe_cnt++; - } - - /* For DET allocation, we don't want to use DML policy (not optimal for utilizing all - * the DET available for each pipe). Use the DET override input to maintain our driver - * policy. - */ - dcn32_set_det_allocations(dc, context, pipes); - - // In general cases we want to keep the dram clock change requirement - // (prefer configs that support MCLK switch). Only override to false - // for SubVP - if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching || subvp_in_use) - context->bw_ctx.dml.soc.dram_clock_change_requirement_final = false; - else - context->bw_ctx.dml.soc.dram_clock_change_requirement_final = true; - - return pipe_cnt; -} - -static struct dc_cap_funcs cap_funcs = { - .get_dcc_compression_cap = dcn20_get_dcc_compression_cap, - .get_subvp_en = dcn32_subvp_in_use, -}; - -void dcn32_calculate_wm_and_dlg(struct dc *dc, struct dc_state *context, - display_e2e_pipe_params_st *pipes, - int pipe_cnt, - int vlevel) -{ - DC_FP_START(); - dcn32_calculate_wm_and_dlg_fpu(dc, context, pipes, pipe_cnt, vlevel); - DC_FP_END(); -} - -static void dcn32_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) -{ - DC_FP_START(); - dcn32_update_bw_bounding_box_fpu(dc, bw_params); - DC_FP_END(); -} - -static struct resource_funcs dcn32_res_pool_funcs = { - .destroy = dcn32_destroy_resource_pool, - .link_enc_create = dcn32_link_encoder_create, - .link_enc_create_minimal = NULL, - .panel_cntl_create = dcn32_panel_cntl_create, - .validate_bandwidth = dcn32_validate_bandwidth, - .calculate_wm_and_dlg = dcn32_calculate_wm_and_dlg, - .populate_dml_pipes = dcn32_populate_dml_pipes_from_context, - .acquire_free_pipe_as_secondary_dpp_pipe = dcn32_acquire_free_pipe_as_secondary_dpp_pipe, - .acquire_free_pipe_as_secondary_opp_head = dcn32_acquire_free_pipe_as_secondary_opp_head, - .release_pipe = dcn20_release_pipe, - .add_stream_to_ctx = dcn30_add_stream_to_ctx, - .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource, - .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, - .populate_dml_writeback_from_context = dcn30_populate_dml_writeback_from_context, - .set_mcif_arb_params = dcn30_set_mcif_arb_params, - .find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link, - .acquire_post_bldn_3dlut = dcn32_acquire_post_bldn_3dlut, - .release_post_bldn_3dlut = dcn32_release_post_bldn_3dlut, - .update_bw_bounding_box = dcn32_update_bw_bounding_box, - .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, - .update_soc_for_wm_a = dcn30_update_soc_for_wm_a, - .add_phantom_pipes = dcn32_add_phantom_pipes, - .remove_phantom_pipes = dcn32_remove_phantom_pipes, - .retain_phantom_pipes = dcn32_retain_phantom_pipes, - .save_mall_state = dcn32_save_mall_state, - .restore_mall_state = dcn32_restore_mall_state, -}; - -static uint32_t read_pipe_fuses(struct dc_context *ctx) -{ - uint32_t value = REG_READ(CC_DC_PIPE_DIS); - /* DCN32 support max 4 pipes */ - value = value & 0xf; - return value; -} - - -static bool dcn32_resource_construct( - uint8_t num_virtual_links, - struct dc *dc, - struct dcn32_resource_pool *pool) -{ - int i, j; - struct dc_context *ctx = dc->ctx; - struct irq_service_init_data init_data; - struct ddc_service_init_data ddc_init_data = {0}; - uint32_t pipe_fuses = 0; - uint32_t num_pipes = 4; - -#undef REG_STRUCT -#define REG_STRUCT bios_regs - bios_regs_init(); - -#undef REG_STRUCT -#define REG_STRUCT clk_src_regs - clk_src_regs_init(0, A), - clk_src_regs_init(1, B), - clk_src_regs_init(2, C), - clk_src_regs_init(3, D), - clk_src_regs_init(4, E); - -#undef REG_STRUCT -#define REG_STRUCT abm_regs - abm_regs_init(0), - abm_regs_init(1), - abm_regs_init(2), - abm_regs_init(3); - -#undef REG_STRUCT -#define REG_STRUCT dccg_regs - dccg_regs_init(); - - DC_FP_START(); - - ctx->dc_bios->regs = &bios_regs; - - pool->base.res_cap = &res_cap_dcn32; - /* max number of pipes for ASIC before checking for pipe fuses */ - num_pipes = pool->base.res_cap->num_timing_generator; - pipe_fuses = read_pipe_fuses(ctx); - - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) - if (pipe_fuses & 1 << i) - num_pipes--; - - if (pipe_fuses & 1) - ASSERT(0); //Unexpected - Pipe 0 should always be fully functional! - - if (pipe_fuses & CC_DC_PIPE_DIS__DC_FULL_DIS_MASK) - ASSERT(0); //Entire DCN is harvested! - - /* within dml lib, initial value is hard coded, if ASIC pipe is fused, the - * value will be changed, update max_num_dpp and max_num_otg for dml. - */ - dcn3_2_ip.max_num_dpp = num_pipes; - dcn3_2_ip.max_num_otg = num_pipes; - - pool->base.funcs = &dcn32_res_pool_funcs; - - /************************************************* - * Resource + asic cap harcoding * - *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; - pool->base.timing_generator_count = num_pipes; - pool->base.pipe_count = num_pipes; - pool->base.mpcc_count = num_pipes; - dc->caps.max_downscale_ratio = 600; - dc->caps.i2c_speed_in_khz = 100; - dc->caps.i2c_speed_in_khz_hdcp = 100; /*1.4 w/a applied by default*/ - /* TODO: Bring max_cursor_size back to 256 after subvp cursor corruption is fixed*/ - 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 = 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; - - /* 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; - dc->caps.subvp_swath_height_margin_lines = 16; - dc->caps.subvp_pstate_allow_width_us = 20; - dc->caps.subvp_vertical_int_margin_us = 30; - dc->caps.subvp_drr_vblank_start_margin_us = 100; // 100us margin - - dc->caps.max_slave_planes = 2; - dc->caps.max_slave_yuv_planes = 2; - dc->caps.max_slave_rgb_planes = 2; - dc->caps.post_blend_color_processing = true; - dc->caps.force_dp_tps4_for_cp2520 = true; - if (dc->config.forceHBR2CP2520) - dc->caps.force_dp_tps4_for_cp2520 = false; - dc->caps.dp_hpo = true; - dc->caps.dp_hdmi21_pcon_support = true; - dc->caps.edp_dsc_support = true; - dc->caps.extended_aux_timeout_support = true; - dc->caps.dmcub_support = true; - dc->caps.seamless_odm = true; - dc->caps.max_v_total = (1 << 15) - 1; - - /* Color pipeline capabilities */ - dc->caps.color.dpp.dcn_arch = 1; - dc->caps.color.dpp.input_lut_shared = 0; - dc->caps.color.dpp.icsc = 1; - dc->caps.color.dpp.dgam_ram = 0; // must use gamma_corr - dc->caps.color.dpp.dgam_rom_caps.srgb = 1; - dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1; - dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 1; - dc->caps.color.dpp.dgam_rom_caps.pq = 1; - dc->caps.color.dpp.dgam_rom_caps.hlg = 1; - dc->caps.color.dpp.post_csc = 1; - dc->caps.color.dpp.gamma_corr = 1; - dc->caps.color.dpp.dgam_rom_for_yuv = 0; - - dc->caps.color.dpp.hw_3d_lut = 1; - dc->caps.color.dpp.ogam_ram = 0; // no OGAM in DPP since DCN1 - // no OGAM ROM on DCN2 and later ASICs - dc->caps.color.dpp.ogam_rom_caps.srgb = 0; - dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0; - dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0; - dc->caps.color.dpp.ogam_rom_caps.pq = 0; - dc->caps.color.dpp.ogam_rom_caps.hlg = 0; - dc->caps.color.dpp.ocsc = 0; - - dc->caps.color.mpc.gamut_remap = 1; - dc->caps.color.mpc.num_3dluts = pool->base.res_cap->num_mpc_3dlut; //4, configurable to be before or after BLND in MPCC - dc->caps.color.mpc.ogam_ram = 1; - dc->caps.color.mpc.ogam_rom_caps.srgb = 0; - dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0; - dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0; - dc->caps.color.mpc.ogam_rom_caps.pq = 0; - dc->caps.color.mpc.ogam_rom_caps.hlg = 0; - dc->caps.color.mpc.ocsc = 1; - - /* Use pipe context based otg sync logic */ - dc->config.use_pipe_ctx_sync_logic = true; - - dc->config.dc_mode_clk_limit_support = true; - /* read VBIOS LTTPR caps */ - { - if (ctx->dc_bios->funcs->get_lttpr_caps) { - enum bp_result bp_query_result; - uint8_t is_vbios_lttpr_enable = 0; - - bp_query_result = ctx->dc_bios->funcs->get_lttpr_caps(ctx->dc_bios, &is_vbios_lttpr_enable); - dc->caps.vbios_lttpr_enable = (bp_query_result == BP_RESULT_OK) && !!is_vbios_lttpr_enable; - } - - /* interop bit is implicit */ - { - dc->caps.vbios_lttpr_aware = true; - } - } - - if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) - dc->debug = debug_defaults_drv; - - // Init the vm_helper - if (dc->vm_helper) - vm_helper_init(dc->vm_helper, 16); - - /************************************************* - * Create resources * - *************************************************/ - - /* Clock Sources for Pixel Clock*/ - pool->base.clock_sources[DCN32_CLK_SRC_PLL0] = - dcn32_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL0, - &clk_src_regs[0], false); - pool->base.clock_sources[DCN32_CLK_SRC_PLL1] = - dcn32_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL1, - &clk_src_regs[1], false); - pool->base.clock_sources[DCN32_CLK_SRC_PLL2] = - dcn32_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL2, - &clk_src_regs[2], false); - pool->base.clock_sources[DCN32_CLK_SRC_PLL3] = - dcn32_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL3, - &clk_src_regs[3], false); - pool->base.clock_sources[DCN32_CLK_SRC_PLL4] = - dcn32_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL4, - &clk_src_regs[4], false); - - pool->base.clk_src_count = DCN32_CLK_SRC_TOTAL; - - /* todo: not reuse phy_pll registers */ - pool->base.dp_clock_source = - dcn32_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_ID_DP_DTO, - &clk_src_regs[0], true); - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] == NULL) { - dm_error("DC: failed to create clock sources!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - } - - /* DCCG */ - pool->base.dccg = dccg32_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask); - if (pool->base.dccg == NULL) { - dm_error("DC: failed to create dccg!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - - /* DML */ - dml_init_instance(&dc->dml, &dcn3_2_soc, &dcn3_2_ip, DML_PROJECT_DCN32); - - /* IRQ Service */ - init_data.ctx = dc->ctx; - pool->base.irqs = dal_irq_service_dcn32_create(&init_data); - if (!pool->base.irqs) - goto create_fail; - - /* HUBBUB */ - pool->base.hubbub = dcn32_hubbub_create(ctx); - if (pool->base.hubbub == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create hubbub!\n"); - goto create_fail; - } - - /* HUBPs, DPPs, OPPs, TGs, ABMs */ - for (i = 0, j = 0; i < pool->base.res_cap->num_timing_generator; i++) { - - /* if pipe is disabled, skip instance of HW pipe, - * i.e, skip ASIC register instance - */ - if (pipe_fuses & 1 << i) - continue; - - /* HUBPs */ - pool->base.hubps[j] = dcn32_hubp_create(ctx, i); - if (pool->base.hubps[j] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create hubps!\n"); - goto create_fail; - } - - /* DPPs */ - pool->base.dpps[j] = dcn32_dpp_create(ctx, i); - if (pool->base.dpps[j] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create dpps!\n"); - goto create_fail; - } - - /* OPPs */ - pool->base.opps[j] = dcn32_opp_create(ctx, i); - if (pool->base.opps[j] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create output pixel processor!\n"); - goto create_fail; - } - - /* TGs */ - pool->base.timing_generators[j] = dcn32_timing_generator_create( - ctx, i); - if (pool->base.timing_generators[j] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create tg!\n"); - goto create_fail; - } - - /* ABMs */ - pool->base.multiple_abms[j] = dmub_abm_create(ctx, - &abm_regs[i], - &abm_shift, - &abm_mask); - if (pool->base.multiple_abms[j] == NULL) { - dm_error("DC: failed to create abm for pipe %d!\n", i); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - - /* index for resource pool arrays for next valid pipe */ - j++; - } - - /* PSR */ - pool->base.psr = dmub_psr_create(ctx); - if (pool->base.psr == NULL) { - dm_error("DC: failed to create psr obj!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - - /* MPCCs */ - pool->base.mpc = dcn32_mpc_create(ctx, pool->base.res_cap->num_timing_generator, pool->base.res_cap->num_mpc_3dlut); - if (pool->base.mpc == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create mpc!\n"); - goto create_fail; - } - - /* DSCs */ - for (i = 0; i < pool->base.res_cap->num_dsc; i++) { - pool->base.dscs[i] = dcn32_dsc_create(ctx, i); - if (pool->base.dscs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create display stream compressor %d!\n", i); - goto create_fail; - } - } - - /* DWB */ - if (!dcn32_dwbc_create(ctx, &pool->base)) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create dwbc!\n"); - goto create_fail; - } - - /* MMHUBBUB */ - if (!dcn32_mmhubbub_create(ctx, &pool->base)) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create mcif_wb!\n"); - goto create_fail; - } - - /* AUX and I2C */ - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - pool->base.engines[i] = dcn32_aux_engine_create(ctx, i); - if (pool->base.engines[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create aux engine!!\n"); - goto create_fail; - } - pool->base.hw_i2cs[i] = dcn32_i2c_hw_create(ctx, i); - if (pool->base.hw_i2cs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create hw i2c!!\n"); - goto create_fail; - } - pool->base.sw_i2cs[i] = NULL; - } - - /* Audio, HWSeq, Stream Encoders including HPO and virtual, MPC 3D LUTs */ - if (!resource_construct(num_virtual_links, dc, &pool->base, - &res_create_funcs)) - goto create_fail; - - /* HW Sequencer init functions and Plane caps */ - dcn32_hw_sequencer_init_functions(dc); - - dc->caps.max_planes = pool->base.pipe_count; - - for (i = 0; i < dc->caps.max_planes; ++i) - dc->caps.planes[i] = plane_cap; - - 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->base.oem_device = dc->link_srv->create_ddc_service(&ddc_init_data); - } else { - pool->base.oem_device = NULL; - } - - dc->dml2_options.dcn_pipe_count = pool->base.pipe_count; - dc->dml2_options.use_native_pstate_optimization = false; - dc->dml2_options.use_native_soc_bb_construction = true; - dc->dml2_options.minimize_dispclk_using_odm = true; - - dc->dml2_options.callbacks.dc = dc; - dc->dml2_options.callbacks.build_scaling_params = &resource_build_scaling_params; - dc->dml2_options.callbacks.can_support_mclk_switch_using_fw_based_vblank_stretch = &dcn30_can_support_mclk_switch_using_fw_based_vblank_stretch; - dc->dml2_options.callbacks.acquire_secondary_pipe_for_mpc_odm = &dc_resource_acquire_secondary_pipe_for_mpc_odm_legacy; - dc->dml2_options.callbacks.update_pipes_for_stream_with_slice_count = &resource_update_pipes_for_stream_with_slice_count; - dc->dml2_options.callbacks.update_pipes_for_plane_with_slice_count = &resource_update_pipes_for_plane_with_slice_count; - dc->dml2_options.callbacks.get_mpc_slice_index = &resource_get_mpc_slice_index; - dc->dml2_options.callbacks.get_odm_slice_index = &resource_get_odm_slice_index; - dc->dml2_options.callbacks.get_opp_head = &resource_get_opp_head; - - dc->dml2_options.svp_pstate.callbacks.dc = dc; - dc->dml2_options.svp_pstate.callbacks.add_plane_to_context = &dc_add_plane_to_context; - dc->dml2_options.svp_pstate.callbacks.add_stream_to_ctx = &dc_add_stream_to_ctx; - dc->dml2_options.svp_pstate.callbacks.build_scaling_params = &resource_build_scaling_params; - dc->dml2_options.svp_pstate.callbacks.create_plane = &dc_create_plane_state; - dc->dml2_options.svp_pstate.callbacks.remove_plane_from_context = &dc_remove_plane_from_context; - dc->dml2_options.svp_pstate.callbacks.remove_stream_from_ctx = &dc_remove_stream_from_ctx; - dc->dml2_options.svp_pstate.callbacks.create_stream_for_sink = &dc_create_stream_for_sink; - dc->dml2_options.svp_pstate.callbacks.plane_state_release = &dc_plane_state_release; - dc->dml2_options.svp_pstate.callbacks.stream_release = &dc_stream_release; - dc->dml2_options.svp_pstate.callbacks.release_dsc = &dcn20_release_dsc; - - dc->dml2_options.svp_pstate.subvp_fw_processing_delay_us = dc->caps.subvp_fw_processing_delay_us; - dc->dml2_options.svp_pstate.subvp_prefetch_end_to_mall_start_us = dc->caps.subvp_prefetch_end_to_mall_start_us; - dc->dml2_options.svp_pstate.subvp_pstate_allow_width_us = dc->caps.subvp_pstate_allow_width_us; - dc->dml2_options.svp_pstate.subvp_swath_height_margin_lines = dc->caps.subvp_swath_height_margin_lines; - - dc->dml2_options.svp_pstate.force_disable_subvp = dc->debug.force_disable_subvp; - dc->dml2_options.svp_pstate.force_enable_subvp = dc->debug.force_subvp_mclk_switch; - - dc->dml2_options.mall_cfg.cache_line_size_bytes = dc->caps.cache_line_size; - dc->dml2_options.mall_cfg.cache_num_ways = dc->caps.cache_num_ways; - dc->dml2_options.mall_cfg.max_cab_allocation_bytes = dc->caps.max_cab_allocation_bytes; - dc->dml2_options.mall_cfg.mblk_height_4bpe_pixels = DCN3_2_MBLK_HEIGHT_4BPE; - dc->dml2_options.mall_cfg.mblk_height_8bpe_pixels = DCN3_2_MBLK_HEIGHT_8BPE; - dc->dml2_options.mall_cfg.mblk_size_bytes = DCN3_2_MALL_MBLK_SIZE_BYTES; - dc->dml2_options.mall_cfg.mblk_width_pixels = DCN3_2_MBLK_WIDTH; - - dc->dml2_options.max_segments_per_hubp = 18; - dc->dml2_options.det_segment_size = DCN3_2_DET_SEG_SIZE; - dc->dml2_options.map_dc_pipes_with_callbacks = true; - - if (ASICREV_IS_GC_11_0_3(dc->ctx->asic_id.hw_internal_rev) && (dc->config.sdpif_request_limit_words_per_umc == 0)) - dc->config.sdpif_request_limit_words_per_umc = 16; - - DC_FP_END(); - - return true; - -create_fail: - - DC_FP_END(); - - dcn32_resource_destruct(pool); - - return false; -} - -struct resource_pool *dcn32_create_resource_pool( - const struct dc_init_data *init_data, - struct dc *dc) -{ - struct dcn32_resource_pool *pool = - kzalloc(sizeof(struct dcn32_resource_pool), GFP_KERNEL); - - if (!pool) - return NULL; - - if (dcn32_resource_construct(init_data->num_virtual_links, dc, pool)) - return &pool->base; - - BREAK_TO_DEBUGGER(); - kfree(pool); - return NULL; -} - -/* - * Find the most optimal free pipe from res_ctx, which could be used as a - * secondary dpp pipe for input opp head pipe. - * - * a free pipe - a pipe in input res_ctx not yet used for any streams or - * planes. - * secondary dpp pipe - a pipe gets inserted to a head OPP pipe's MPC blending - * tree. This is typical used for rendering MPO planes or additional offset - * areas in MPCC combine. - * - * Hardware Transition Minimization Algorithm for Finding a Secondary DPP Pipe - * ------------------------------------------------------------------------- - * - * PROBLEM: - * - * 1. There is a hardware limitation that a secondary DPP pipe cannot be - * transferred from one MPC blending tree to the other in a single frame. - * Otherwise it could cause glitches on the screen. - * - * For instance, we cannot transition from state 1 to state 2 in one frame. This - * is because PIPE1 is transferred from PIPE0's MPC blending tree over to - * PIPE2's MPC blending tree, which is not supported by hardware. - * To support this transition we need to first remove PIPE1 from PIPE0's MPC - * blending tree in one frame and then insert PIPE1 to PIPE2's MPC blending tree - * in the next frame. This is not optimal as it will delay the flip for two - * frames. - * - * State 1: - * PIPE0 -- secondary DPP pipe --> (PIPE1) - * PIPE2 -- secondary DPP pipe --> NONE - * - * State 2: - * PIPE0 -- secondary DPP pipe --> NONE - * PIPE2 -- secondary DPP pipe --> (PIPE1) - * - * 2. We want to in general minimize the unnecessary changes in pipe topology. - * If a pipe is already added in current blending tree and there are no changes - * to plane topology, we don't want to swap it with another free pipe - * unnecessarily in every update. Powering up and down a pipe would require a - * full update which delays the flip for 1 frame. If we use the original pipe - * we don't have to toggle its power. So we can flip faster. - */ -static int find_optimal_free_pipe_as_secondary_dpp_pipe( - const struct resource_context *cur_res_ctx, - struct resource_context *new_res_ctx, - const struct resource_pool *pool, - const struct pipe_ctx *new_opp_head) -{ - const struct pipe_ctx *cur_opp_head; - int free_pipe_idx; - - cur_opp_head = &cur_res_ctx->pipe_ctx[new_opp_head->pipe_idx]; - free_pipe_idx = resource_find_free_pipe_used_in_cur_mpc_blending_tree( - cur_res_ctx, new_res_ctx, cur_opp_head); - - /* Up until here if we have not found a free secondary pipe, we will - * need to wait for at least one frame to complete the transition - * sequence. - */ - if (free_pipe_idx == FREE_PIPE_INDEX_NOT_FOUND) - free_pipe_idx = recource_find_free_pipe_not_used_in_cur_res_ctx( - cur_res_ctx, new_res_ctx, pool); - - /* Up until here if we have not found a free secondary pipe, we will - * need to wait for at least two frames to complete the transition - * sequence. It really doesn't matter which pipe we decide take from - * current enabled pipes. It won't save our frame time when we swap only - * one pipe or more pipes. - */ - if (free_pipe_idx == FREE_PIPE_INDEX_NOT_FOUND) - free_pipe_idx = resource_find_free_pipe_used_as_cur_sec_dpp_in_mpcc_combine( - cur_res_ctx, new_res_ctx, pool); - - if (free_pipe_idx == FREE_PIPE_INDEX_NOT_FOUND) - free_pipe_idx = resource_find_any_free_pipe(new_res_ctx, pool); - - return free_pipe_idx; -} - -static struct pipe_ctx *find_idle_secondary_pipe_check_mpo( - struct resource_context *res_ctx, - const struct resource_pool *pool, - const struct pipe_ctx *primary_pipe) -{ - int i; - struct pipe_ctx *secondary_pipe = NULL; - struct pipe_ctx *next_odm_mpo_pipe = NULL; - int primary_index, preferred_pipe_idx; - struct pipe_ctx *old_primary_pipe = NULL; - - /* - * Modified from find_idle_secondary_pipe - * With windowed MPO and ODM, we want to avoid the case where we want a - * free pipe for the left side but the free pipe is being used on the - * right side. - * Add check on current_state if the primary_pipe is the left side, - * to check the right side ( primary_pipe->next_odm_pipe ) to see if - * it is using a pipe for MPO ( primary_pipe->next_odm_pipe->bottom_pipe ) - * - If so, then don't use this pipe - * EXCEPTION - 3 plane ( 2 MPO plane ) case - * - in this case, the primary pipe has already gotten a free pipe for the - * MPO window in the left - * - when it tries to get a free pipe for the MPO window on the right, - * it will see that it is already assigned to the right side - * ( primary_pipe->next_odm_pipe ). But in this case, we want this - * free pipe, since it will be for the right side. So add an - * additional condition, that skipping the free pipe on the right only - * applies if the primary pipe has no bottom pipe currently assigned - */ - if (primary_pipe) { - primary_index = primary_pipe->pipe_idx; - old_primary_pipe = &primary_pipe->stream->ctx->dc->current_state->res_ctx.pipe_ctx[primary_index]; - if ((old_primary_pipe->next_odm_pipe) && (old_primary_pipe->next_odm_pipe->bottom_pipe) - && (!primary_pipe->bottom_pipe)) - next_odm_mpo_pipe = old_primary_pipe->next_odm_pipe->bottom_pipe; - - preferred_pipe_idx = (pool->pipe_count - 1) - primary_pipe->pipe_idx; - if ((res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) && - !(next_odm_mpo_pipe && next_odm_mpo_pipe->pipe_idx == preferred_pipe_idx)) { - secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx]; - secondary_pipe->pipe_idx = preferred_pipe_idx; - } - } - - /* - * search backwards for the second pipe to keep pipe - * assignment more consistent - */ - if (!secondary_pipe) - for (i = pool->pipe_count - 1; i >= 0; i--) { - if ((res_ctx->pipe_ctx[i].stream == NULL) && - !(next_odm_mpo_pipe && next_odm_mpo_pipe->pipe_idx == i)) { - secondary_pipe = &res_ctx->pipe_ctx[i]; - secondary_pipe->pipe_idx = i; - break; - } - } - - return secondary_pipe; -} - -static struct pipe_ctx *dcn32_acquire_idle_pipe_for_head_pipe_in_layer( - struct dc_state *state, - const struct resource_pool *pool, - struct dc_stream_state *stream, - const struct pipe_ctx *head_pipe) -{ - struct resource_context *res_ctx = &state->res_ctx; - struct pipe_ctx *idle_pipe, *pipe; - struct resource_context *old_ctx = &stream->ctx->dc->current_state->res_ctx; - int head_index; - - if (!head_pipe) - ASSERT(0); - - /* - * Modified from dcn20_acquire_idle_pipe_for_layer - * Check if head_pipe in old_context already has bottom_pipe allocated. - * - If so, check if that pipe is available in the current context. - * -- If so, reuse pipe from old_context - */ - head_index = head_pipe->pipe_idx; - pipe = &old_ctx->pipe_ctx[head_index]; - if (pipe->bottom_pipe && res_ctx->pipe_ctx[pipe->bottom_pipe->pipe_idx].stream == NULL) { - idle_pipe = &res_ctx->pipe_ctx[pipe->bottom_pipe->pipe_idx]; - idle_pipe->pipe_idx = pipe->bottom_pipe->pipe_idx; - } else { - idle_pipe = find_idle_secondary_pipe_check_mpo(res_ctx, pool, head_pipe); - if (!idle_pipe) - return NULL; - } - - idle_pipe->stream = head_pipe->stream; - idle_pipe->stream_res.tg = head_pipe->stream_res.tg; - idle_pipe->stream_res.opp = head_pipe->stream_res.opp; - - idle_pipe->plane_res.hubp = pool->hubps[idle_pipe->pipe_idx]; - idle_pipe->plane_res.ipp = pool->ipps[idle_pipe->pipe_idx]; - idle_pipe->plane_res.dpp = pool->dpps[idle_pipe->pipe_idx]; - idle_pipe->plane_res.mpcc_inst = pool->dpps[idle_pipe->pipe_idx]->inst; - - return idle_pipe; -} - -static int find_optimal_free_pipe_as_secondary_opp_head( - const struct resource_context *cur_res_ctx, - struct resource_context *new_res_ctx, - const struct resource_pool *pool, - const struct pipe_ctx *new_otg_master) -{ - const struct pipe_ctx *cur_otg_master; - int free_pipe_idx; - - cur_otg_master = &cur_res_ctx->pipe_ctx[new_otg_master->pipe_idx]; - free_pipe_idx = resource_find_free_pipe_used_as_sec_opp_head_by_cur_otg_master( - cur_res_ctx, new_res_ctx, cur_otg_master); - - /* Up until here if we have not found a free secondary pipe, we will - * need to wait for at least one frame to complete the transition - * sequence. - */ - if (free_pipe_idx == FREE_PIPE_INDEX_NOT_FOUND) - free_pipe_idx = recource_find_free_pipe_not_used_in_cur_res_ctx( - cur_res_ctx, new_res_ctx, pool); - - if (free_pipe_idx == FREE_PIPE_INDEX_NOT_FOUND) - free_pipe_idx = resource_find_any_free_pipe(new_res_ctx, pool); - - return free_pipe_idx; -} - -struct pipe_ctx *dcn32_acquire_free_pipe_as_secondary_dpp_pipe( - const struct dc_state *cur_ctx, - struct dc_state *new_ctx, - const struct resource_pool *pool, - const struct pipe_ctx *opp_head_pipe) -{ - - int free_pipe_idx; - struct pipe_ctx *free_pipe; - - if (!opp_head_pipe->stream->ctx->dc->config.enable_windowed_mpo_odm) - return dcn32_acquire_idle_pipe_for_head_pipe_in_layer( - new_ctx, pool, opp_head_pipe->stream, opp_head_pipe); - - free_pipe_idx = find_optimal_free_pipe_as_secondary_dpp_pipe( - &cur_ctx->res_ctx, &new_ctx->res_ctx, - pool, opp_head_pipe); - if (free_pipe_idx >= 0) { - free_pipe = &new_ctx->res_ctx.pipe_ctx[free_pipe_idx]; - free_pipe->pipe_idx = free_pipe_idx; - free_pipe->stream = opp_head_pipe->stream; - free_pipe->stream_res.tg = opp_head_pipe->stream_res.tg; - free_pipe->stream_res.opp = opp_head_pipe->stream_res.opp; - - free_pipe->plane_res.hubp = pool->hubps[free_pipe->pipe_idx]; - free_pipe->plane_res.ipp = pool->ipps[free_pipe->pipe_idx]; - free_pipe->plane_res.dpp = pool->dpps[free_pipe->pipe_idx]; - free_pipe->plane_res.mpcc_inst = - pool->dpps[free_pipe->pipe_idx]->inst; - } else { - ASSERT(opp_head_pipe); - free_pipe = NULL; - } - - return free_pipe; -} - -struct pipe_ctx *dcn32_acquire_free_pipe_as_secondary_opp_head( - const struct dc_state *cur_ctx, - struct dc_state *new_ctx, - const struct resource_pool *pool, - const struct pipe_ctx *otg_master) -{ - int free_pipe_idx = find_optimal_free_pipe_as_secondary_opp_head( - &cur_ctx->res_ctx, &new_ctx->res_ctx, - pool, otg_master); - struct pipe_ctx *free_pipe; - - if (free_pipe_idx >= 0) { - free_pipe = &new_ctx->res_ctx.pipe_ctx[free_pipe_idx]; - free_pipe->pipe_idx = free_pipe_idx; - free_pipe->stream = otg_master->stream; - free_pipe->stream_res.tg = otg_master->stream_res.tg; - free_pipe->stream_res.dsc = NULL; - free_pipe->stream_res.opp = pool->opps[free_pipe_idx]; - free_pipe->plane_res.mi = pool->mis[free_pipe_idx]; - free_pipe->plane_res.hubp = pool->hubps[free_pipe_idx]; - free_pipe->plane_res.ipp = pool->ipps[free_pipe_idx]; - free_pipe->plane_res.xfm = pool->transforms[free_pipe_idx]; - free_pipe->plane_res.dpp = pool->dpps[free_pipe_idx]; - free_pipe->plane_res.mpcc_inst = pool->dpps[free_pipe_idx]->inst; - if (free_pipe->stream->timing.flags.DSC == 1) { - dcn20_acquire_dsc(free_pipe->stream->ctx->dc, - &new_ctx->res_ctx, - &free_pipe->stream_res.dsc, - free_pipe_idx); - ASSERT(free_pipe->stream_res.dsc); - if (free_pipe->stream_res.dsc == NULL) { - memset(free_pipe, 0, sizeof(*free_pipe)); - free_pipe = NULL; - } - } - } else { - ASSERT(otg_master); - free_pipe = NULL; - } - - return free_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 deleted file mode 100644 index b931008114c91d..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.h +++ /dev/null @@ -1,1263 +0,0 @@ -/* - * Copyright 2020 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 _DCN32_RESOURCE_H_ -#define _DCN32_RESOURCE_H_ - -#include "core_types.h" - -#define DCN3_2_DEFAULT_DET_SIZE 256 -#define DCN3_2_MAX_DET_SIZE 1152 -#define DCN3_2_MIN_DET_SIZE 128 -#define DCN3_2_MIN_COMPBUF_SIZE_KB 128 -#define DCN3_2_DET_SEG_SIZE 64 -#define DCN3_2_MALL_MBLK_SIZE_BYTES 65536 // 64 * 1024 -#define DCN3_2_MBLK_WIDTH 128 -#define DCN3_2_MBLK_HEIGHT_4BPE 128 -#define DCN3_2_MBLK_HEIGHT_8BPE 64 -#define DCN3_2_DCFCLK_DS_INIT_KHZ 10000 // Choose 10Mhz for init DCFCLK DS freq -#define SUBVP_HIGH_REFRESH_LIST_LEN 4 -#define DCN3_2_MAX_SUBVP_PIXEL_RATE_MHZ 1800 -#define DCN3_2_VMIN_DISPCLK_HZ 717000000 - -#define TO_DCN32_RES_POOL(pool)\ - container_of(pool, struct dcn32_resource_pool, base) - -extern struct _vcs_dpi_ip_params_st dcn3_2_ip; -extern struct _vcs_dpi_soc_bounding_box_st dcn3_2_soc; - -struct subvp_high_refresh_list { - int min_refresh; - int max_refresh; - struct resolution { - int width; - int height; - } res[SUBVP_HIGH_REFRESH_LIST_LEN]; -}; - -struct dcn32_resource_pool { - struct resource_pool base; -}; - -struct resource_pool *dcn32_create_resource_pool( - const struct dc_init_data *init_data, - struct dc *dc); - -struct panel_cntl *dcn32_panel_cntl_create( - const struct panel_cntl_init_data *init_data); - -bool dcn32_acquire_post_bldn_3dlut( - struct resource_context *res_ctx, - const struct resource_pool *pool, - int mpcc_id, - struct dc_3dlut **lut, - struct dc_transfer_func **shaper); - -bool dcn32_release_post_bldn_3dlut( - struct resource_context *res_ctx, - const struct resource_pool *pool, - struct dc_3dlut **lut, - struct dc_transfer_func **shaper); - -bool dcn32_remove_phantom_pipes(struct dc *dc, - struct dc_state *context, bool fast_update); - -void dcn32_retain_phantom_pipes(struct dc *dc, - struct dc_state *context); - -void dcn32_add_phantom_pipes(struct dc *dc, - struct dc_state *context, - display_e2e_pipe_params_st *pipes, - unsigned int pipe_cnt, - unsigned int index); - -bool dcn32_validate_bandwidth(struct dc *dc, - struct dc_state *context, - bool fast_validate); - -int dcn32_populate_dml_pipes_from_context( - struct dc *dc, struct dc_state *context, - display_e2e_pipe_params_st *pipes, - bool fast_validate); - -void dcn32_calculate_wm_and_dlg( - struct dc *dc, struct dc_state *context, - display_e2e_pipe_params_st *pipes, - int pipe_cnt, - int vlevel); - -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, - struct dc_state *context); - -bool dcn32_all_pipes_have_stream_and_plane(struct dc *dc, - struct dc_state *context); - -bool dcn32_subvp_in_use(struct dc *dc, - struct dc_state *context); - -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_free_pipe_as_secondary_dpp_pipe( - const struct dc_state *cur_ctx, - struct dc_state *new_ctx, - const struct resource_pool *pool, - const struct pipe_ctx *opp_head_pipe); - -struct pipe_ctx *dcn32_acquire_free_pipe_as_secondary_opp_head( - const struct dc_state *cur_ctx, - struct dc_state *new_ctx, - const struct resource_pool *pool, - const struct pipe_ctx *otg_master); - -void dcn32_release_pipe(struct dc_state *context, - struct pipe_ctx *pipe, - const struct resource_pool *pool); - -void dcn32_determine_det_override(struct dc *dc, - struct dc_state *context, - display_e2e_pipe_params_st *pipes); - -void dcn32_set_det_allocations(struct dc *dc, struct dc_state *context, - display_e2e_pipe_params_st *pipes); - -void dcn32_save_mall_state(struct dc *dc, - struct dc_state *context, - struct mall_temp_config *temp_config); - -void dcn32_restore_mall_state(struct dc *dc, - struct dc_state *context, - struct mall_temp_config *temp_config); - -struct dc_stream_state *dcn32_can_support_mclk_switch_using_fw_based_vblank_stretch(struct dc *dc, const struct dc_state *context); - -bool dcn32_allow_subvp_with_active_margin(struct pipe_ctx *pipe); - -bool dcn32_allow_subvp_high_refresh_rate(struct dc *dc, struct dc_state *context, 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); - -bool dcn32_check_native_scaling_for_res(struct pipe_ctx *pipe, unsigned int width, unsigned int height); - -bool dcn32_subvp_drr_admissable(struct dc *dc, struct dc_state *context); - -bool dcn32_subvp_vblank_admissable(struct dc *dc, struct dc_state *context, int vlevel); - -/* definitions for run time init of reg offsets */ - -/* CLK SRC */ -#define CS_COMMON_REG_LIST_DCN3_0_RI(index, pllid) \ - SRI_ARR_ALPHABET(PIXCLK_RESYNC_CNTL, PHYPLL, index, pllid), \ - SRII_ARR_2(PHASE, DP_DTO, 0, index), \ - SRII_ARR_2(PHASE, DP_DTO, 1, index), \ - SRII_ARR_2(PHASE, DP_DTO, 2, index), \ - SRII_ARR_2(PHASE, DP_DTO, 3, index), \ - SRII_ARR_2(MODULO, DP_DTO, 0, index), \ - SRII_ARR_2(MODULO, DP_DTO, 1, index), \ - SRII_ARR_2(MODULO, DP_DTO, 2, index), \ - SRII_ARR_2(MODULO, DP_DTO, 3, index), \ - SRII_ARR_2(PIXEL_RATE_CNTL, OTG, 0, index), \ - SRII_ARR_2(PIXEL_RATE_CNTL, OTG, 1, index), \ - SRII_ARR_2(PIXEL_RATE_CNTL, OTG, 2, index), \ - SRII_ARR_2(PIXEL_RATE_CNTL, OTG, 3, index) - -/* ABM */ -#define ABM_DCN32_REG_LIST_RI(id) \ - SRI_ARR(DC_ABM1_HG_SAMPLE_RATE, ABM, id), \ - SRI_ARR(DC_ABM1_LS_SAMPLE_RATE, ABM, id), \ - SRI_ARR(BL1_PWM_BL_UPDATE_SAMPLE_RATE, ABM, id), \ - SRI_ARR(DC_ABM1_HG_MISC_CTRL, ABM, id), \ - SRI_ARR(DC_ABM1_IPCSC_COEFF_SEL, ABM, id), \ - SRI_ARR(BL1_PWM_CURRENT_ABM_LEVEL, ABM, id), \ - SRI_ARR(BL1_PWM_TARGET_ABM_LEVEL, ABM, id), \ - SRI_ARR(BL1_PWM_USER_LEVEL, ABM, id), \ - SRI_ARR(DC_ABM1_LS_MIN_MAX_PIXEL_VALUE_THRES, ABM, id), \ - SRI_ARR(DC_ABM1_HGLS_REG_READ_PROGRESS, ABM, id), \ - SRI_ARR(DC_ABM1_ACE_OFFSET_SLOPE_0, ABM, id), \ - SRI_ARR(DC_ABM1_ACE_THRES_12, ABM, id), NBIO_SR_ARR(BIOS_SCRATCH_2, id) - -/* Audio */ -#define AUD_COMMON_REG_LIST_RI(id) \ - SRI_ARR(AZALIA_F0_CODEC_ENDPOINT_INDEX, AZF0ENDPOINT, id), \ - SRI_ARR(AZALIA_F0_CODEC_ENDPOINT_DATA, AZF0ENDPOINT, id), \ - SR_ARR(AZALIA_F0_CODEC_FUNCTION_PARAMETER_STREAM_FORMATS, id), \ - SR_ARR(AZALIA_F0_CODEC_FUNCTION_PARAMETER_SUPPORTED_SIZE_RATES, id), \ - SR_ARR(AZALIA_F0_CODEC_FUNCTION_PARAMETER_POWER_STATES, id), \ - SR_ARR(DCCG_AUDIO_DTO_SOURCE, id), SR_ARR(DCCG_AUDIO_DTO0_MODULE, id), \ - SR_ARR(DCCG_AUDIO_DTO0_PHASE, id), SR_ARR(DCCG_AUDIO_DTO1_MODULE, id), \ - SR_ARR(DCCG_AUDIO_DTO1_PHASE, id) \ - -/* VPG */ - -#define VPG_DCN3_REG_LIST_RI(id) \ - SRI_ARR(VPG_GENERIC_STATUS, VPG, id), \ - SRI_ARR(VPG_GENERIC_PACKET_ACCESS_CTRL, VPG, id), \ - SRI_ARR(VPG_GENERIC_PACKET_DATA, VPG, id), \ - SRI_ARR(VPG_GSP_FRAME_UPDATE_CTRL, VPG, id), \ - SRI_ARR(VPG_GSP_IMMEDIATE_UPDATE_CTRL, VPG, id) - -/* AFMT */ -#define AFMT_DCN3_REG_LIST_RI(id) \ - SRI_ARR(AFMT_INFOFRAME_CONTROL0, AFMT, id), \ - SRI_ARR(AFMT_VBI_PACKET_CONTROL, AFMT, id), \ - SRI_ARR(AFMT_AUDIO_PACKET_CONTROL, AFMT, id), \ - SRI_ARR(AFMT_AUDIO_PACKET_CONTROL2, AFMT, id), \ - SRI_ARR(AFMT_AUDIO_SRC_CONTROL, AFMT, id), \ - SRI_ARR(AFMT_60958_0, AFMT, id), SRI_ARR(AFMT_60958_1, AFMT, id), \ - SRI_ARR(AFMT_60958_2, AFMT, id), SRI_ARR(AFMT_MEM_PWR, AFMT, id) - -/* APG */ -#define APG_DCN31_REG_LIST_RI(id) \ - SRI_ARR(APG_CONTROL, APG, id), SRI_ARR(APG_CONTROL2, APG, id), \ - SRI_ARR(APG_MEM_PWR, APG, id), SRI_ARR(APG_DBG_GEN_CONTROL, APG, id) - -/* Stream encoder */ -#define SE_DCN32_REG_LIST_RI(id) \ - SRI_ARR(AFMT_CNTL, DIG, id), SRI_ARR(DIG_FE_CNTL, DIG, id), \ - SRI_ARR(HDMI_CONTROL, DIG, id), SRI_ARR(HDMI_DB_CONTROL, DIG, id), \ - SRI_ARR(HDMI_GC, DIG, id), \ - SRI_ARR(HDMI_GENERIC_PACKET_CONTROL0, DIG, id), \ - SRI_ARR(HDMI_GENERIC_PACKET_CONTROL1, DIG, id), \ - SRI_ARR(HDMI_GENERIC_PACKET_CONTROL2, DIG, id), \ - SRI_ARR(HDMI_GENERIC_PACKET_CONTROL3, DIG, id), \ - SRI_ARR(HDMI_GENERIC_PACKET_CONTROL4, DIG, id), \ - SRI_ARR(HDMI_GENERIC_PACKET_CONTROL5, DIG, id), \ - SRI_ARR(HDMI_GENERIC_PACKET_CONTROL6, DIG, id), \ - SRI_ARR(HDMI_GENERIC_PACKET_CONTROL7, DIG, id), \ - SRI_ARR(HDMI_GENERIC_PACKET_CONTROL8, DIG, id), \ - SRI_ARR(HDMI_GENERIC_PACKET_CONTROL9, DIG, id), \ - SRI_ARR(HDMI_GENERIC_PACKET_CONTROL10, DIG, id), \ - SRI_ARR(HDMI_INFOFRAME_CONTROL0, DIG, id), \ - SRI_ARR(HDMI_INFOFRAME_CONTROL1, DIG, id), \ - SRI_ARR(HDMI_VBI_PACKET_CONTROL, DIG, id), \ - SRI_ARR(HDMI_AUDIO_PACKET_CONTROL, DIG, id), \ - SRI_ARR(HDMI_ACR_PACKET_CONTROL, DIG, id), \ - SRI_ARR(HDMI_ACR_32_0, DIG, id), SRI_ARR(HDMI_ACR_32_1, DIG, id), \ - SRI_ARR(HDMI_ACR_44_0, DIG, id), SRI_ARR(HDMI_ACR_44_1, DIG, id), \ - SRI_ARR(HDMI_ACR_48_0, DIG, id), SRI_ARR(HDMI_ACR_48_1, DIG, id), \ - SRI_ARR(DP_DB_CNTL, DP, id), SRI_ARR(DP_MSA_MISC, DP, id), \ - SRI_ARR(DP_MSA_VBID_MISC, DP, id), SRI_ARR(DP_MSA_COLORIMETRY, DP, id), \ - SRI_ARR(DP_MSA_TIMING_PARAM1, DP, id), \ - SRI_ARR(DP_MSA_TIMING_PARAM2, DP, id), \ - SRI_ARR(DP_MSA_TIMING_PARAM3, DP, id), \ - SRI_ARR(DP_MSA_TIMING_PARAM4, DP, id), \ - SRI_ARR(DP_MSE_RATE_CNTL, DP, id), SRI_ARR(DP_MSE_RATE_UPDATE, DP, id), \ - SRI_ARR(DP_PIXEL_FORMAT, DP, id), SRI_ARR(DP_SEC_CNTL, DP, id), \ - SRI_ARR(DP_SEC_CNTL1, DP, id), SRI_ARR(DP_SEC_CNTL2, DP, id), \ - SRI_ARR(DP_SEC_CNTL5, DP, id), SRI_ARR(DP_SEC_CNTL6, DP, id), \ - SRI_ARR(DP_STEER_FIFO, DP, id), SRI_ARR(DP_VID_M, DP, id), \ - SRI_ARR(DP_VID_N, DP, id), SRI_ARR(DP_VID_STREAM_CNTL, DP, id), \ - SRI_ARR(DP_VID_TIMING, DP, id), SRI_ARR(DP_SEC_AUD_N, DP, id), \ - SRI_ARR(DP_SEC_TIMESTAMP, DP, id), SRI_ARR(DP_DSC_CNTL, DP, id), \ - SRI_ARR(DP_SEC_METADATA_TRANSMISSION, DP, id), \ - SRI_ARR(HDMI_METADATA_PACKET_CONTROL, DIG, id), \ - SRI_ARR(DP_SEC_FRAMING4, DP, id), SRI_ARR(DP_GSP11_CNTL, DP, id), \ - SRI_ARR(DME_CONTROL, DME, id), \ - SRI_ARR(DP_SEC_METADATA_TRANSMISSION, DP, id), \ - SRI_ARR(HDMI_METADATA_PACKET_CONTROL, DIG, id), \ - SRI_ARR(DIG_FE_CNTL, DIG, id), SRI_ARR(DIG_CLOCK_PATTERN, DIG, id), \ - SRI_ARR(DIG_FIFO_CTRL0, DIG, id) - -/* Aux regs */ - -#define AUX_REG_LIST_RI(id) \ - SRI_ARR(AUX_CONTROL, DP_AUX, id), SRI_ARR(AUX_DPHY_RX_CONTROL0, DP_AUX, id), \ - SRI_ARR(AUX_DPHY_RX_CONTROL1, DP_AUX, id) - -#define DCN2_AUX_REG_LIST_RI(id) \ - AUX_REG_LIST_RI(id), SRI_ARR(AUX_DPHY_TX_CONTROL, DP_AUX, id) - -/* HDP */ -#define HPD_REG_LIST_RI(id) SRI_ARR(DC_HPD_CONTROL, HPD, id) - -/* Link encoder */ -#define LE_DCN3_REG_LIST_RI(id) \ - SRI_ARR(DIG_BE_CNTL, DIG, id), SRI_ARR(DIG_BE_EN_CNTL, DIG, id), \ - SRI_ARR(TMDS_CTL_BITS, DIG, id), \ - SRI_ARR(TMDS_DCBALANCER_CONTROL, DIG, id), SRI_ARR(DP_CONFIG, DP, id), \ - SRI_ARR(DP_DPHY_CNTL, DP, id), SRI_ARR(DP_DPHY_PRBS_CNTL, DP, id), \ - SRI_ARR(DP_DPHY_SCRAM_CNTL, DP, id), SRI_ARR(DP_DPHY_SYM0, DP, id), \ - SRI_ARR(DP_DPHY_SYM1, DP, id), SRI_ARR(DP_DPHY_SYM2, DP, id), \ - SRI_ARR(DP_DPHY_TRAINING_PATTERN_SEL, DP, id), \ - SRI_ARR(DP_LINK_CNTL, DP, id), SRI_ARR(DP_LINK_FRAMING_CNTL, DP, id), \ - SRI_ARR(DP_MSE_SAT0, DP, id), SRI_ARR(DP_MSE_SAT1, DP, id), \ - SRI_ARR(DP_MSE_SAT2, DP, id), SRI_ARR(DP_MSE_SAT_UPDATE, DP, id), \ - SRI_ARR(DP_SEC_CNTL, DP, id), SRI_ARR(DP_VID_STREAM_CNTL, DP, id), \ - SRI_ARR(DP_DPHY_FAST_TRAINING, DP, id), SRI_ARR(DP_SEC_CNTL1, DP, id), \ - SRI_ARR(DP_DPHY_BS_SR_SWAP_CNTL, DP, id), \ - SRI_ARR(DP_DPHY_HBR2_PATTERN_CONTROL, DP, id) - -#define LE_DCN31_REG_LIST_RI(id) \ - LE_DCN3_REG_LIST_RI(id), SRI_ARR(DP_DPHY_INTERNAL_CTRL, DP, id), \ - SR_ARR(DIO_LINKA_CNTL, id), SR_ARR(DIO_LINKB_CNTL, id), \ - SR_ARR(DIO_LINKC_CNTL, id), SR_ARR(DIO_LINKD_CNTL, id), \ - SR_ARR(DIO_LINKE_CNTL, id), SR_ARR(DIO_LINKF_CNTL, id) - -#define UNIPHY_DCN2_REG_LIST_RI(id, phyid) \ - SRI_ARR_ALPHABET(CLOCK_ENABLE, SYMCLK, id, phyid), \ - SRI_ARR_ALPHABET(CHANNEL_XBAR_CNTL, UNIPHY, id, phyid) - -/* HPO DP stream encoder */ -#define DCN3_1_HPO_DP_STREAM_ENC_REG_LIST_RI(id) \ - SR_ARR(DP_STREAM_MAPPER_CONTROL0, id), \ - SR_ARR(DP_STREAM_MAPPER_CONTROL1, id), \ - SR_ARR(DP_STREAM_MAPPER_CONTROL2, id), \ - SR_ARR(DP_STREAM_MAPPER_CONTROL3, id), \ - SRI_ARR(DP_STREAM_ENC_CLOCK_CONTROL, DP_STREAM_ENC, id), \ - SRI_ARR(DP_STREAM_ENC_INPUT_MUX_CONTROL, DP_STREAM_ENC, id), \ - SRI_ARR(DP_STREAM_ENC_AUDIO_CONTROL, DP_STREAM_ENC, id), \ - SRI_ARR(DP_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, DP_STREAM_ENC, id), \ - SRI_ARR(DP_SYM32_ENC_CONTROL, DP_SYM32_ENC, id), \ - SRI_ARR(DP_SYM32_ENC_VID_PIXEL_FORMAT, DP_SYM32_ENC, id), \ - SRI_ARR(DP_SYM32_ENC_VID_PIXEL_FORMAT_DOUBLE_BUFFER_CONTROL, DP_SYM32_ENC, id), \ - SRI_ARR(DP_SYM32_ENC_VID_MSA0, DP_SYM32_ENC, id), \ - SRI_ARR(DP_SYM32_ENC_VID_MSA1, DP_SYM32_ENC, id), \ - SRI_ARR(DP_SYM32_ENC_VID_MSA2, DP_SYM32_ENC, id), \ - SRI_ARR(DP_SYM32_ENC_VID_MSA3, DP_SYM32_ENC, id), \ - SRI_ARR(DP_SYM32_ENC_VID_MSA4, DP_SYM32_ENC, id), \ - SRI_ARR(DP_SYM32_ENC_VID_MSA5, DP_SYM32_ENC, id), \ - SRI_ARR(DP_SYM32_ENC_VID_MSA6, DP_SYM32_ENC, id), \ - SRI_ARR(DP_SYM32_ENC_VID_MSA7, DP_SYM32_ENC, id), \ - SRI_ARR(DP_SYM32_ENC_VID_MSA8, DP_SYM32_ENC, id), \ - SRI_ARR(DP_SYM32_ENC_VID_MSA_CONTROL, DP_SYM32_ENC, id), \ - SRI_ARR(DP_SYM32_ENC_VID_MSA_DOUBLE_BUFFER_CONTROL, DP_SYM32_ENC, id), \ - SRI_ARR(DP_SYM32_ENC_VID_FIFO_CONTROL, DP_SYM32_ENC, id), \ - SRI_ARR(DP_SYM32_ENC_VID_STREAM_CONTROL, DP_SYM32_ENC, id), \ - SRI_ARR(DP_SYM32_ENC_VID_VBID_CONTROL, DP_SYM32_ENC, id), \ - SRI_ARR(DP_SYM32_ENC_SDP_CONTROL, DP_SYM32_ENC, id), \ - SRI_ARR(DP_SYM32_ENC_SDP_GSP_CONTROL0, DP_SYM32_ENC, id), \ - SRI_ARR(DP_SYM32_ENC_SDP_GSP_CONTROL2, DP_SYM32_ENC, id), \ - SRI_ARR(DP_SYM32_ENC_SDP_GSP_CONTROL3, DP_SYM32_ENC, id), \ - SRI_ARR(DP_SYM32_ENC_SDP_GSP_CONTROL5, DP_SYM32_ENC, id), \ - SRI_ARR(DP_SYM32_ENC_SDP_GSP_CONTROL11, DP_SYM32_ENC, id), \ - SRI_ARR(DP_SYM32_ENC_SDP_METADATA_PACKET_CONTROL, DP_SYM32_ENC, id), \ - SRI_ARR(DP_SYM32_ENC_SDP_AUDIO_CONTROL0, DP_SYM32_ENC, id), \ - SRI_ARR(DP_SYM32_ENC_VID_CRC_CONTROL, DP_SYM32_ENC, id), \ - SRI_ARR(DP_SYM32_ENC_HBLANK_CONTROL, DP_SYM32_ENC, id) - -/* HPO DP link encoder regs */ -#define DCN3_1_HPO_DP_LINK_ENC_REG_LIST_RI(id) \ - SRI_ARR(DP_LINK_ENC_CLOCK_CONTROL, DP_LINK_ENC, id), \ - SRI_ARR(DP_DPHY_SYM32_CONTROL, DP_DPHY_SYM32, id), \ - SRI_ARR(DP_DPHY_SYM32_STATUS, DP_DPHY_SYM32, id), \ - SRI_ARR(DP_DPHY_SYM32_TP_CONFIG, DP_DPHY_SYM32, id), \ - SRI_ARR(DP_DPHY_SYM32_TP_PRBS_SEED0, DP_DPHY_SYM32, id), \ - SRI_ARR(DP_DPHY_SYM32_TP_PRBS_SEED1, DP_DPHY_SYM32, id), \ - SRI_ARR(DP_DPHY_SYM32_TP_PRBS_SEED2, DP_DPHY_SYM32, id), \ - SRI_ARR(DP_DPHY_SYM32_TP_PRBS_SEED3, DP_DPHY_SYM32, id), \ - SRI_ARR(DP_DPHY_SYM32_TP_SQ_PULSE, DP_DPHY_SYM32, id), \ - SRI_ARR(DP_DPHY_SYM32_TP_CUSTOM0, DP_DPHY_SYM32, id), \ - SRI_ARR(DP_DPHY_SYM32_TP_CUSTOM1, DP_DPHY_SYM32, id), \ - SRI_ARR(DP_DPHY_SYM32_TP_CUSTOM2, DP_DPHY_SYM32, id), \ - SRI_ARR(DP_DPHY_SYM32_TP_CUSTOM3, DP_DPHY_SYM32, id), \ - SRI_ARR(DP_DPHY_SYM32_TP_CUSTOM4, DP_DPHY_SYM32, id), \ - SRI_ARR(DP_DPHY_SYM32_TP_CUSTOM5, DP_DPHY_SYM32, id), \ - SRI_ARR(DP_DPHY_SYM32_TP_CUSTOM6, DP_DPHY_SYM32, id), \ - SRI_ARR(DP_DPHY_SYM32_TP_CUSTOM7, DP_DPHY_SYM32, id), \ - SRI_ARR(DP_DPHY_SYM32_TP_CUSTOM8, DP_DPHY_SYM32, id), \ - SRI_ARR(DP_DPHY_SYM32_TP_CUSTOM9, DP_DPHY_SYM32, id), \ - SRI_ARR(DP_DPHY_SYM32_TP_CUSTOM10, DP_DPHY_SYM32, id), \ - SRI_ARR(DP_DPHY_SYM32_SAT_VC0, DP_DPHY_SYM32, id), \ - SRI_ARR(DP_DPHY_SYM32_SAT_VC1, DP_DPHY_SYM32, id), \ - SRI_ARR(DP_DPHY_SYM32_SAT_VC2, DP_DPHY_SYM32, id), \ - SRI_ARR(DP_DPHY_SYM32_SAT_VC3, DP_DPHY_SYM32, id), \ - SRI_ARR(DP_DPHY_SYM32_VC_RATE_CNTL0, DP_DPHY_SYM32, id), \ - SRI_ARR(DP_DPHY_SYM32_VC_RATE_CNTL1, DP_DPHY_SYM32, id), \ - SRI_ARR(DP_DPHY_SYM32_VC_RATE_CNTL2, DP_DPHY_SYM32, id), \ - SRI_ARR(DP_DPHY_SYM32_VC_RATE_CNTL3, DP_DPHY_SYM32, id), \ - SRI_ARR(DP_DPHY_SYM32_SAT_UPDATE, DP_DPHY_SYM32, id) - -/* DPP */ -#define DPP_REG_LIST_DCN30_COMMON_RI(id) \ - SRI_ARR(CM_DEALPHA, CM, id), SRI_ARR(CM_MEM_PWR_STATUS, CM, id), \ - SRI_ARR(CM_BIAS_CR_R, CM, id), SRI_ARR(CM_BIAS_Y_G_CB_B, CM, id), \ - SRI_ARR(PRE_DEGAM, CNVC_CFG, id), SRI_ARR(CM_GAMCOR_CONTROL, CM, id), \ - SRI_ARR(CM_GAMCOR_LUT_CONTROL, CM, id), \ - SRI_ARR(CM_GAMCOR_LUT_INDEX, CM, id), \ - SRI_ARR(CM_GAMCOR_LUT_INDEX, CM, id), \ - SRI_ARR(CM_GAMCOR_LUT_DATA, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMB_START_CNTL_B, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMB_START_CNTL_G, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMB_START_CNTL_R, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMB_START_SLOPE_CNTL_B, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMB_START_SLOPE_CNTL_G, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMB_START_SLOPE_CNTL_R, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMB_END_CNTL1_B, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMB_END_CNTL2_B, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMB_END_CNTL1_G, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMB_END_CNTL2_G, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMB_END_CNTL1_R, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMB_END_CNTL2_R, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMB_REGION_0_1, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMB_REGION_32_33, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMB_OFFSET_B, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMB_OFFSET_G, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMB_OFFSET_R, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMB_START_BASE_CNTL_B, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMB_START_BASE_CNTL_G, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMB_START_BASE_CNTL_R, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMA_START_CNTL_B, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMA_START_CNTL_G, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMA_START_CNTL_R, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMA_START_SLOPE_CNTL_B, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMA_START_SLOPE_CNTL_G, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMA_START_SLOPE_CNTL_R, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMA_END_CNTL1_B, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMA_END_CNTL2_B, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMA_END_CNTL1_G, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMA_END_CNTL2_G, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMA_END_CNTL1_R, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMA_END_CNTL2_R, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMA_REGION_0_1, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMA_REGION_32_33, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMA_OFFSET_B, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMA_OFFSET_G, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMA_OFFSET_R, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMA_START_BASE_CNTL_B, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMA_START_BASE_CNTL_G, CM, id), \ - SRI_ARR(CM_GAMCOR_RAMA_START_BASE_CNTL_R, CM, id), \ - SRI_ARR(CM_GAMUT_REMAP_CONTROL, CM, id), \ - SRI_ARR(CM_GAMUT_REMAP_C11_C12, CM, id), \ - SRI_ARR(CM_GAMUT_REMAP_C13_C14, CM, id), \ - SRI_ARR(CM_GAMUT_REMAP_C21_C22, CM, id), \ - SRI_ARR(CM_GAMUT_REMAP_C23_C24, CM, id), \ - SRI_ARR(CM_GAMUT_REMAP_C31_C32, CM, id), \ - SRI_ARR(CM_GAMUT_REMAP_C33_C34, CM, id), \ - SRI_ARR(CM_GAMUT_REMAP_B_C11_C12, CM, id), \ - SRI_ARR(CM_GAMUT_REMAP_B_C13_C14, CM, id), \ - SRI_ARR(CM_GAMUT_REMAP_B_C21_C22, CM, id), \ - SRI_ARR(CM_GAMUT_REMAP_B_C23_C24, CM, id), \ - SRI_ARR(CM_GAMUT_REMAP_B_C31_C32, CM, id), \ - SRI_ARR(CM_GAMUT_REMAP_B_C33_C34, CM, id), \ - SRI_ARR(DSCL_EXT_OVERSCAN_LEFT_RIGHT, DSCL, id), \ - SRI_ARR(DSCL_EXT_OVERSCAN_TOP_BOTTOM, DSCL, id), \ - SRI_ARR(OTG_H_BLANK, DSCL, id), SRI_ARR(OTG_V_BLANK, DSCL, id), \ - SRI_ARR(SCL_MODE, DSCL, id), SRI_ARR(LB_DATA_FORMAT, DSCL, id), \ - SRI_ARR(LB_MEMORY_CTRL, DSCL, id), SRI_ARR(DSCL_AUTOCAL, DSCL, id), \ - SRI_ARR(DSCL_CONTROL, DSCL, id), \ - SRI_ARR(SCL_TAP_CONTROL, DSCL, id), \ - SRI_ARR(SCL_COEF_RAM_TAP_SELECT, DSCL, id), \ - SRI_ARR(SCL_COEF_RAM_TAP_DATA, DSCL, id), \ - SRI_ARR(DSCL_2TAP_CONTROL, DSCL, id), SRI_ARR(MPC_SIZE, DSCL, id), \ - SRI_ARR(SCL_HORZ_FILTER_SCALE_RATIO, DSCL, id), \ - SRI_ARR(SCL_VERT_FILTER_SCALE_RATIO, DSCL, id), \ - SRI_ARR(SCL_HORZ_FILTER_SCALE_RATIO_C, DSCL, id), \ - SRI_ARR(SCL_VERT_FILTER_SCALE_RATIO_C, DSCL, id), \ - SRI_ARR(SCL_HORZ_FILTER_INIT, DSCL, id), \ - SRI_ARR(SCL_HORZ_FILTER_INIT_C, DSCL, id), \ - SRI_ARR(SCL_VERT_FILTER_INIT, DSCL, id), \ - SRI_ARR(SCL_VERT_FILTER_INIT_C, DSCL, id), \ - SRI_ARR(RECOUT_START, DSCL, id), SRI_ARR(RECOUT_SIZE, DSCL, id), \ - SRI_ARR(PRE_DEALPHA, CNVC_CFG, id), SRI_ARR(PRE_REALPHA, CNVC_CFG, id), \ - SRI_ARR(PRE_CSC_MODE, CNVC_CFG, id), \ - SRI_ARR(PRE_CSC_C11_C12, CNVC_CFG, id), \ - SRI_ARR(PRE_CSC_C33_C34, CNVC_CFG, id), \ - SRI_ARR(PRE_CSC_B_C11_C12, CNVC_CFG, id), \ - SRI_ARR(PRE_CSC_B_C33_C34, CNVC_CFG, id), \ - SRI_ARR(CM_POST_CSC_CONTROL, CM, id), \ - SRI_ARR(CM_POST_CSC_C11_C12, CM, id), \ - SRI_ARR(CM_POST_CSC_C33_C34, CM, id), \ - SRI_ARR(CM_POST_CSC_B_C11_C12, CM, id), \ - SRI_ARR(CM_POST_CSC_B_C33_C34, CM, id), \ - SRI_ARR(CM_MEM_PWR_CTRL, CM, id), SRI_ARR(CM_CONTROL, CM, id), \ - SRI_ARR(FORMAT_CONTROL, CNVC_CFG, id), \ - SRI_ARR(CNVC_SURFACE_PIXEL_FORMAT, CNVC_CFG, id), \ - SRI_ARR(CURSOR0_CONTROL, CNVC_CUR, id), \ - SRI_ARR(CURSOR0_COLOR0, CNVC_CUR, id), \ - SRI_ARR(CURSOR0_COLOR1, CNVC_CUR, id), \ - SRI_ARR(CURSOR0_FP_SCALE_BIAS, CNVC_CUR, id), \ - SRI_ARR(DPP_CONTROL, DPP_TOP, id), SRI_ARR(CM_HDR_MULT_COEF, CM, id), \ - SRI_ARR(CURSOR_CONTROL, CURSOR0_, id), \ - SRI_ARR(ALPHA_2BIT_LUT, CNVC_CFG, id), \ - SRI_ARR(FCNV_FP_BIAS_R, CNVC_CFG, id), \ - SRI_ARR(FCNV_FP_BIAS_G, CNVC_CFG, id), \ - SRI_ARR(FCNV_FP_BIAS_B, CNVC_CFG, id), \ - SRI_ARR(FCNV_FP_SCALE_R, CNVC_CFG, id), \ - SRI_ARR(FCNV_FP_SCALE_G, CNVC_CFG, id), \ - SRI_ARR(FCNV_FP_SCALE_B, CNVC_CFG, id), \ - SRI_ARR(COLOR_KEYER_CONTROL, CNVC_CFG, id), \ - SRI_ARR(COLOR_KEYER_ALPHA, CNVC_CFG, id), \ - SRI_ARR(COLOR_KEYER_RED, CNVC_CFG, id), \ - SRI_ARR(COLOR_KEYER_GREEN, CNVC_CFG, id), \ - SRI_ARR(COLOR_KEYER_BLUE, CNVC_CFG, id), \ - SRI_ARR(CURSOR_CONTROL, CURSOR0_, id), \ - SRI_ARR(OBUF_MEM_PWR_CTRL, DSCL, id), \ - SRI_ARR(DSCL_MEM_PWR_STATUS, DSCL, id), \ - SRI_ARR(DSCL_MEM_PWR_CTRL, DSCL, id) - -/* OPP */ -#define OPP_REG_LIST_DCN_RI(id) \ - SRI_ARR(FMT_BIT_DEPTH_CONTROL, FMT, id), SRI_ARR(FMT_CONTROL, FMT, id), \ - SRI_ARR(FMT_DITHER_RAND_R_SEED, FMT, id), \ - SRI_ARR(FMT_DITHER_RAND_G_SEED, FMT, id), \ - SRI_ARR(FMT_DITHER_RAND_B_SEED, FMT, id), \ - SRI_ARR(FMT_CLAMP_CNTL, FMT, id), \ - SRI_ARR(FMT_DYNAMIC_EXP_CNTL, FMT, id), \ - SRI_ARR(FMT_MAP420_MEMORY_CONTROL, FMT, id), \ - SRI_ARR(OPPBUF_CONTROL, OPPBUF, id), \ - SRI_ARR(OPPBUF_3D_PARAMETERS_0, OPPBUF, id), \ - SRI_ARR(OPPBUF_3D_PARAMETERS_1, OPPBUF, id), \ - SRI_ARR(OPP_PIPE_CONTROL, OPP_PIPE, id) \ - -#define OPP_REG_LIST_DCN10_RI(id) OPP_REG_LIST_DCN_RI(id) - -#define OPP_DPG_REG_LIST_RI(id) \ - SRI_ARR(DPG_CONTROL, DPG, id), SRI_ARR(DPG_DIMENSIONS, DPG, id), \ - SRI_ARR(DPG_OFFSET_SEGMENT, DPG, id), SRI_ARR(DPG_COLOUR_B_CB, DPG, id), \ - SRI_ARR(DPG_COLOUR_G_Y, DPG, id), SRI_ARR(DPG_COLOUR_R_CR, DPG, id), \ - SRI_ARR(DPG_RAMP_CONTROL, DPG, id), SRI_ARR(DPG_STATUS, DPG, id) - -#define OPP_REG_LIST_DCN30_RI(id) \ - OPP_REG_LIST_DCN10_RI(id), OPP_DPG_REG_LIST_RI(id), \ - SRI_ARR(FMT_422_CONTROL, FMT, id) - -/* Aux engine regs */ -#define AUX_COMMON_REG_LIST0_RI(id) \ - SRI_ARR(AUX_CONTROL, DP_AUX, id), SRI_ARR(AUX_ARB_CONTROL, DP_AUX, id), \ - SRI_ARR(AUX_SW_DATA, DP_AUX, id), SRI_ARR(AUX_SW_CONTROL, DP_AUX, id), \ - SRI_ARR(AUX_INTERRUPT_CONTROL, DP_AUX, id), \ - SRI_ARR(AUX_DPHY_RX_CONTROL1, DP_AUX, id), \ - SRI_ARR(AUX_SW_STATUS, DP_AUX, id) - -/* DWBC */ -#define DWBC_COMMON_REG_LIST_DCN30_RI(id) \ - SR_ARR(DWB_ENABLE_CLK_CTRL, id), SR_ARR(DWB_MEM_PWR_CTRL, id), \ - SR_ARR(FC_MODE_CTRL, id), SR_ARR(FC_FLOW_CTRL, id), \ - SR_ARR(FC_WINDOW_START, id), SR_ARR(FC_WINDOW_SIZE, id), \ - SR_ARR(FC_SOURCE_SIZE, id), SR_ARR(DWB_UPDATE_CTRL, id), \ - SR_ARR(DWB_CRC_CTRL, id), SR_ARR(DWB_CRC_MASK_R_G, id), \ - SR_ARR(DWB_CRC_MASK_B_A, id), SR_ARR(DWB_CRC_VAL_R_G, id), \ - SR_ARR(DWB_CRC_VAL_B_A, id), SR_ARR(DWB_OUT_CTRL, id), \ - SR_ARR(DWB_MMHUBBUB_BACKPRESSURE_CNT_EN, id), \ - SR_ARR(DWB_MMHUBBUB_BACKPRESSURE_CNT, id), \ - SR_ARR(DWB_HOST_READ_CONTROL, id), SR_ARR(DWB_SOFT_RESET, id), \ - SR_ARR(DWB_HDR_MULT_COEF, id), SR_ARR(DWB_GAMUT_REMAP_MODE, id), \ - SR_ARR(DWB_GAMUT_REMAP_COEF_FORMAT, id), \ - SR_ARR(DWB_GAMUT_REMAPA_C11_C12, id), \ - SR_ARR(DWB_GAMUT_REMAPA_C13_C14, id), \ - SR_ARR(DWB_GAMUT_REMAPA_C21_C22, id), \ - SR_ARR(DWB_GAMUT_REMAPA_C23_C24, id), \ - SR_ARR(DWB_GAMUT_REMAPA_C31_C32, id), \ - SR_ARR(DWB_GAMUT_REMAPA_C33_C34, id), \ - SR_ARR(DWB_GAMUT_REMAPB_C11_C12, id), \ - SR_ARR(DWB_GAMUT_REMAPB_C13_C14, id), \ - SR_ARR(DWB_GAMUT_REMAPB_C21_C22, id), \ - SR_ARR(DWB_GAMUT_REMAPB_C23_C24, id), \ - SR_ARR(DWB_GAMUT_REMAPB_C31_C32, id), \ - SR_ARR(DWB_GAMUT_REMAPB_C33_C34, id), SR_ARR(DWB_OGAM_CONTROL, id), \ - SR_ARR(DWB_OGAM_LUT_INDEX, id), SR_ARR(DWB_OGAM_LUT_DATA, id), \ - SR_ARR(DWB_OGAM_LUT_CONTROL, id), \ - SR_ARR(DWB_OGAM_RAMA_START_CNTL_B, id), \ - SR_ARR(DWB_OGAM_RAMA_START_CNTL_G, id), \ - SR_ARR(DWB_OGAM_RAMA_START_CNTL_R, id), \ - SR_ARR(DWB_OGAM_RAMA_START_BASE_CNTL_B, id), \ - SR_ARR(DWB_OGAM_RAMA_START_SLOPE_CNTL_B, id), \ - SR_ARR(DWB_OGAM_RAMA_START_BASE_CNTL_G, id), \ - SR_ARR(DWB_OGAM_RAMA_START_SLOPE_CNTL_G, id), \ - SR_ARR(DWB_OGAM_RAMA_START_BASE_CNTL_R, id), \ - SR_ARR(DWB_OGAM_RAMA_START_SLOPE_CNTL_R, id), \ - SR_ARR(DWB_OGAM_RAMA_END_CNTL1_B, id), \ - SR_ARR(DWB_OGAM_RAMA_END_CNTL2_B, id), \ - SR_ARR(DWB_OGAM_RAMA_END_CNTL1_G, id), \ - SR_ARR(DWB_OGAM_RAMA_END_CNTL2_G, id), \ - SR_ARR(DWB_OGAM_RAMA_END_CNTL1_R, id), \ - SR_ARR(DWB_OGAM_RAMA_END_CNTL2_R, id), \ - SR_ARR(DWB_OGAM_RAMA_OFFSET_B, id), SR_ARR(DWB_OGAM_RAMA_OFFSET_G, id), \ - SR_ARR(DWB_OGAM_RAMA_OFFSET_R, id), \ - SR_ARR(DWB_OGAM_RAMA_REGION_0_1, id), \ - SR_ARR(DWB_OGAM_RAMA_REGION_2_3, id), \ - SR_ARR(DWB_OGAM_RAMA_REGION_4_5, id), \ - SR_ARR(DWB_OGAM_RAMA_REGION_6_7, id), \ - SR_ARR(DWB_OGAM_RAMA_REGION_8_9, id), \ - SR_ARR(DWB_OGAM_RAMA_REGION_10_11, id), \ - SR_ARR(DWB_OGAM_RAMA_REGION_12_13, id), \ - SR_ARR(DWB_OGAM_RAMA_REGION_14_15, id), \ - SR_ARR(DWB_OGAM_RAMA_REGION_16_17, id), \ - SR_ARR(DWB_OGAM_RAMA_REGION_18_19, id), \ - SR_ARR(DWB_OGAM_RAMA_REGION_20_21, id), \ - SR_ARR(DWB_OGAM_RAMA_REGION_22_23, id), \ - SR_ARR(DWB_OGAM_RAMA_REGION_24_25, id), \ - SR_ARR(DWB_OGAM_RAMA_REGION_26_27, id), \ - SR_ARR(DWB_OGAM_RAMA_REGION_28_29, id), \ - SR_ARR(DWB_OGAM_RAMA_REGION_30_31, id), \ - SR_ARR(DWB_OGAM_RAMA_REGION_32_33, id), \ - SR_ARR(DWB_OGAM_RAMB_START_CNTL_B, id), \ - SR_ARR(DWB_OGAM_RAMB_START_CNTL_G, id), \ - SR_ARR(DWB_OGAM_RAMB_START_CNTL_R, id), \ - SR_ARR(DWB_OGAM_RAMB_START_BASE_CNTL_B, id), \ - SR_ARR(DWB_OGAM_RAMB_START_SLOPE_CNTL_B, id), \ - SR_ARR(DWB_OGAM_RAMB_START_BASE_CNTL_G, id), \ - SR_ARR(DWB_OGAM_RAMB_START_SLOPE_CNTL_G, id), \ - SR_ARR(DWB_OGAM_RAMB_START_BASE_CNTL_R, id), \ - SR_ARR(DWB_OGAM_RAMB_START_SLOPE_CNTL_R, id), \ - SR_ARR(DWB_OGAM_RAMB_END_CNTL1_B, id), \ - SR_ARR(DWB_OGAM_RAMB_END_CNTL2_B, id), \ - SR_ARR(DWB_OGAM_RAMB_END_CNTL1_G, id), \ - SR_ARR(DWB_OGAM_RAMB_END_CNTL2_G, id), \ - SR_ARR(DWB_OGAM_RAMB_END_CNTL1_R, id), \ - SR_ARR(DWB_OGAM_RAMB_END_CNTL2_R, id), \ - SR_ARR(DWB_OGAM_RAMB_OFFSET_B, id), SR_ARR(DWB_OGAM_RAMB_OFFSET_G, id), \ - SR_ARR(DWB_OGAM_RAMB_OFFSET_R, id), \ - SR_ARR(DWB_OGAM_RAMB_REGION_0_1, id), \ - SR_ARR(DWB_OGAM_RAMB_REGION_2_3, id), \ - SR_ARR(DWB_OGAM_RAMB_REGION_4_5, id), \ - SR_ARR(DWB_OGAM_RAMB_REGION_6_7, id), \ - SR_ARR(DWB_OGAM_RAMB_REGION_8_9, id), \ - SR_ARR(DWB_OGAM_RAMB_REGION_10_11, id), \ - SR_ARR(DWB_OGAM_RAMB_REGION_12_13, id), \ - SR_ARR(DWB_OGAM_RAMB_REGION_14_15, id), \ - SR_ARR(DWB_OGAM_RAMB_REGION_16_17, id), \ - SR_ARR(DWB_OGAM_RAMB_REGION_18_19, id), \ - SR_ARR(DWB_OGAM_RAMB_REGION_20_21, id), \ - SR_ARR(DWB_OGAM_RAMB_REGION_22_23, id), \ - SR_ARR(DWB_OGAM_RAMB_REGION_24_25, id), \ - SR_ARR(DWB_OGAM_RAMB_REGION_26_27, id), \ - SR_ARR(DWB_OGAM_RAMB_REGION_28_29, id), \ - SR_ARR(DWB_OGAM_RAMB_REGION_30_31, id), \ - SR_ARR(DWB_OGAM_RAMB_REGION_32_33, id) - -/* MCIF */ - -#define MCIF_WB_COMMON_REG_LIST_DCN32_RI(inst) \ - SRI2_ARR(MCIF_WB_BUFMGR_SW_CONTROL, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_BUFMGR_STATUS, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_BUF_PITCH, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_BUF_1_STATUS, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_BUF_1_STATUS2, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_BUF_2_STATUS, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_BUF_2_STATUS2, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_BUF_3_STATUS, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_BUF_3_STATUS2, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_BUF_4_STATUS, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_BUF_4_STATUS2, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_ARBITRATION_CONTROL, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_SCLK_CHANGE, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_BUF_1_ADDR_Y, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_BUF_1_ADDR_C, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_BUF_2_ADDR_Y, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_BUF_2_ADDR_C, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_BUF_3_ADDR_Y, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_BUF_3_ADDR_C, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_BUF_4_ADDR_Y, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_BUF_4_ADDR_C, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_BUFMGR_VCE_CONTROL, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_NB_PSTATE_LATENCY_WATERMARK, MMHUBBUB, inst), \ - SRI2_ARR(MCIF_WB_NB_PSTATE_CONTROL, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_WATERMARK, MMHUBBUB, inst), \ - SRI2_ARR(MCIF_WB_CLOCK_GATER_CONTROL, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_SELF_REFRESH_CONTROL, MCIF_WB, inst), \ - SRI2_ARR(MULTI_LEVEL_QOS_CTRL, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_SECURITY_LEVEL, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_BUF_LUMA_SIZE, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_BUF_CHROMA_SIZE, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_BUF_1_ADDR_Y_HIGH, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_BUF_1_ADDR_C_HIGH, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_BUF_2_ADDR_Y_HIGH, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_BUF_2_ADDR_C_HIGH, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_BUF_3_ADDR_Y_HIGH, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_BUF_3_ADDR_C_HIGH, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_BUF_4_ADDR_Y_HIGH, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_BUF_4_ADDR_C_HIGH, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_BUF_1_RESOLUTION, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_BUF_2_RESOLUTION, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_BUF_3_RESOLUTION, MCIF_WB, inst), \ - SRI2_ARR(MCIF_WB_BUF_4_RESOLUTION, MCIF_WB, inst), \ - SRI2_ARR(MMHUBBUB_MEM_PWR_CNTL, MMHUBBUB, inst), \ - SRI2_ARR(MMHUBBUB_WARMUP_ADDR_REGION, MMHUBBUB, inst), \ - SRI2_ARR(MMHUBBUB_WARMUP_BASE_ADDR_HIGH, MMHUBBUB, inst), \ - SRI2_ARR(MMHUBBUB_WARMUP_BASE_ADDR_LOW, MMHUBBUB, inst), \ - SRI2_ARR(MMHUBBUB_WARMUP_CONTROL_STATUS, MMHUBBUB, inst) - -/* DSC */ - -#define DSC_REG_LIST_DCN20_RI(id) \ - SRI_ARR(DSC_TOP_CONTROL, DSC_TOP, id), \ - SRI_ARR(DSC_DEBUG_CONTROL, DSC_TOP, id), \ - SRI_ARR(DSCC_CONFIG0, DSCC, id), SRI_ARR(DSCC_CONFIG1, DSCC, id), \ - SRI_ARR(DSCC_STATUS, DSCC, id), \ - SRI_ARR(DSCC_INTERRUPT_CONTROL_STATUS, DSCC, id), \ - SRI_ARR(DSCC_PPS_CONFIG0, DSCC, id), \ - SRI_ARR(DSCC_PPS_CONFIG1, DSCC, id), \ - SRI_ARR(DSCC_PPS_CONFIG2, DSCC, id), \ - SRI_ARR(DSCC_PPS_CONFIG3, DSCC, id), \ - SRI_ARR(DSCC_PPS_CONFIG4, DSCC, id), \ - SRI_ARR(DSCC_PPS_CONFIG5, DSCC, id), \ - SRI_ARR(DSCC_PPS_CONFIG6, DSCC, id), \ - SRI_ARR(DSCC_PPS_CONFIG7, DSCC, id), \ - SRI_ARR(DSCC_PPS_CONFIG8, DSCC, id), \ - SRI_ARR(DSCC_PPS_CONFIG9, DSCC, id), \ - SRI_ARR(DSCC_PPS_CONFIG10, DSCC, id), \ - SRI_ARR(DSCC_PPS_CONFIG11, DSCC, id), \ - SRI_ARR(DSCC_PPS_CONFIG12, DSCC, id), \ - SRI_ARR(DSCC_PPS_CONFIG13, DSCC, id), \ - SRI_ARR(DSCC_PPS_CONFIG14, DSCC, id), \ - SRI_ARR(DSCC_PPS_CONFIG15, DSCC, id), \ - SRI_ARR(DSCC_PPS_CONFIG16, DSCC, id), \ - SRI_ARR(DSCC_PPS_CONFIG17, DSCC, id), \ - SRI_ARR(DSCC_PPS_CONFIG18, DSCC, id), \ - SRI_ARR(DSCC_PPS_CONFIG19, DSCC, id), \ - SRI_ARR(DSCC_PPS_CONFIG20, DSCC, id), \ - SRI_ARR(DSCC_PPS_CONFIG21, DSCC, id), \ - SRI_ARR(DSCC_PPS_CONFIG22, DSCC, id), \ - SRI_ARR(DSCC_MEM_POWER_CONTROL, DSCC, id), \ - SRI_ARR(DSCC_R_Y_SQUARED_ERROR_LOWER, DSCC, id), \ - SRI_ARR(DSCC_R_Y_SQUARED_ERROR_UPPER, DSCC, id), \ - SRI_ARR(DSCC_G_CB_SQUARED_ERROR_LOWER, DSCC, id), \ - SRI_ARR(DSCC_G_CB_SQUARED_ERROR_UPPER, DSCC, id), \ - SRI_ARR(DSCC_B_CR_SQUARED_ERROR_LOWER, DSCC, id), \ - SRI_ARR(DSCC_B_CR_SQUARED_ERROR_UPPER, DSCC, id), \ - SRI_ARR(DSCC_MAX_ABS_ERROR0, DSCC, id), \ - SRI_ARR(DSCC_MAX_ABS_ERROR1, DSCC, id), \ - SRI_ARR(DSCC_RATE_BUFFER0_MAX_FULLNESS_LEVEL, DSCC, id), \ - SRI_ARR(DSCC_RATE_BUFFER1_MAX_FULLNESS_LEVEL, DSCC, id), \ - SRI_ARR(DSCC_RATE_BUFFER2_MAX_FULLNESS_LEVEL, DSCC, id), \ - SRI_ARR(DSCC_RATE_BUFFER3_MAX_FULLNESS_LEVEL, DSCC, id), \ - SRI_ARR(DSCC_RATE_CONTROL_BUFFER0_MAX_FULLNESS_LEVEL, DSCC, id), \ - SRI_ARR(DSCC_RATE_CONTROL_BUFFER1_MAX_FULLNESS_LEVEL, DSCC, id), \ - SRI_ARR(DSCC_RATE_CONTROL_BUFFER2_MAX_FULLNESS_LEVEL, DSCC, id), \ - SRI_ARR(DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL, DSCC, id), \ - SRI_ARR(DSCCIF_CONFIG0, DSCCIF, id), \ - SRI_ARR(DSCCIF_CONFIG1, DSCCIF, id), \ - SRI_ARR(DSCRM_DSC_FORWARD_CONFIG, DSCRM, id) - -/* MPC */ - -#define MPC_DWB_MUX_REG_LIST_DCN3_0_RI(inst) \ - SRII_DWB(DWB_MUX, MUX, MPC_DWB, inst) - -#define MPC_OUT_MUX_COMMON_REG_LIST_DCN1_0_RI(inst) \ - SRII(MUX, MPC_OUT, inst), VUPDATE_SRII(CUR, VUPDATE_LOCK_SET, inst) - -#define MPC_OUT_MUX_REG_LIST_DCN3_0_RI(inst) \ - MPC_OUT_MUX_COMMON_REG_LIST_DCN1_0_RI(inst), SRII(CSC_MODE, MPC_OUT, inst), \ - SRII(CSC_C11_C12_A, MPC_OUT, inst), SRII(CSC_C33_C34_A, MPC_OUT, inst), \ - SRII(CSC_C11_C12_B, MPC_OUT, inst), SRII(CSC_C33_C34_B, MPC_OUT, inst), \ - SRII(DENORM_CONTROL, MPC_OUT, inst), \ - SRII(DENORM_CLAMP_G_Y, MPC_OUT, inst), \ - SRII(DENORM_CLAMP_B_CB, MPC_OUT, inst), SR(MPC_OUT_CSC_COEF_FORMAT) - -#define MPC_COMMON_REG_LIST_DCN1_0_RI(inst) \ - SRII(MPCC_TOP_SEL, MPCC, inst), SRII(MPCC_BOT_SEL, MPCC, inst), \ - SRII(MPCC_CONTROL, MPCC, inst), SRII(MPCC_STATUS, MPCC, inst), \ - SRII(MPCC_OPP_ID, MPCC, inst), SRII(MPCC_BG_G_Y, MPCC, inst), \ - SRII(MPCC_BG_R_CR, MPCC, inst), SRII(MPCC_BG_B_CB, MPCC, inst), \ - SRII(MPCC_SM_CONTROL, MPCC, inst), \ - SRII(MPCC_UPDATE_LOCK_SEL, MPCC, inst) - -#define MPC_REG_LIST_DCN3_0_RI(inst) \ - MPC_COMMON_REG_LIST_DCN1_0_RI(inst), SRII(MPCC_TOP_GAIN, MPCC, inst), \ - SRII(MPCC_BOT_GAIN_INSIDE, MPCC, inst), \ - SRII(MPCC_BOT_GAIN_OUTSIDE, MPCC, inst), \ - SRII(MPCC_MEM_PWR_CTRL, MPCC, inst), \ - SRII(MPCC_OGAM_LUT_INDEX, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_LUT_DATA, MPCC_OGAM, inst), \ - SRII(MPCC_GAMUT_REMAP_COEF_FORMAT, MPCC_OGAM, inst), \ - SRII(MPCC_GAMUT_REMAP_MODE, MPCC_OGAM, inst), \ - SRII(MPC_GAMUT_REMAP_C11_C12_A, MPCC_OGAM, inst), \ - SRII(MPC_GAMUT_REMAP_C33_C34_A, MPCC_OGAM, inst), \ - SRII(MPC_GAMUT_REMAP_C11_C12_B, MPCC_OGAM, inst), \ - SRII(MPC_GAMUT_REMAP_C33_C34_B, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMA_START_CNTL_B, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMA_START_CNTL_G, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMA_START_CNTL_R, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMA_START_SLOPE_CNTL_B, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMA_START_SLOPE_CNTL_G, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMA_START_SLOPE_CNTL_R, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMA_END_CNTL1_B, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMA_END_CNTL2_B, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMA_END_CNTL1_G, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMA_END_CNTL2_G, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMA_END_CNTL1_R, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMA_END_CNTL2_R, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMA_REGION_0_1, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMA_REGION_32_33, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMA_OFFSET_B, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMA_OFFSET_G, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMA_OFFSET_R, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMA_START_BASE_CNTL_B, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMA_START_BASE_CNTL_G, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMA_START_BASE_CNTL_R, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMB_START_CNTL_B, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMB_START_CNTL_G, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMB_START_CNTL_R, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMB_START_SLOPE_CNTL_B, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMB_START_SLOPE_CNTL_G, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMB_START_SLOPE_CNTL_R, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMB_END_CNTL1_B, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMB_END_CNTL2_B, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMB_END_CNTL1_G, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMB_END_CNTL2_G, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMB_END_CNTL1_R, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMB_END_CNTL2_R, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMB_REGION_0_1, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMB_REGION_32_33, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMB_OFFSET_B, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMB_OFFSET_G, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMB_OFFSET_R, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMB_START_BASE_CNTL_B, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMB_START_BASE_CNTL_G, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_RAMB_START_BASE_CNTL_R, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_CONTROL, MPCC_OGAM, inst), \ - SRII(MPCC_OGAM_LUT_CONTROL, MPCC_OGAM, inst) - -#define MPC_REG_LIST_DCN3_2_RI(inst) \ - MPC_REG_LIST_DCN3_0_RI(inst),\ - SRII(MPCC_MOVABLE_CM_LOCATION_CONTROL, MPCC, inst),\ - SRII(MPCC_MCM_SHAPER_CONTROL, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_OFFSET_R, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_OFFSET_G, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_OFFSET_B, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_SCALE_R, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_SCALE_G_B, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_LUT_INDEX, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_LUT_DATA, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_LUT_WRITE_EN_MASK, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMA_START_CNTL_B, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMA_START_CNTL_G, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMA_START_CNTL_R, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMA_END_CNTL_B, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMA_END_CNTL_G, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMA_END_CNTL_R, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMA_REGION_0_1, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMA_REGION_2_3, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMA_REGION_4_5, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMA_REGION_6_7, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMA_REGION_8_9, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMA_REGION_10_11, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMA_REGION_12_13, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMA_REGION_14_15, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMA_REGION_16_17, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMA_REGION_18_19, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMA_REGION_20_21, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMA_REGION_22_23, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMA_REGION_24_25, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMA_REGION_26_27, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMA_REGION_28_29, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMA_REGION_30_31, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMA_REGION_32_33, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMB_START_CNTL_B, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMB_START_CNTL_G, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMB_START_CNTL_R, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMB_END_CNTL_B, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMB_END_CNTL_G, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMB_END_CNTL_R, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMB_REGION_0_1, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMB_REGION_2_3, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMB_REGION_4_5, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMB_REGION_6_7, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMB_REGION_8_9, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMB_REGION_10_11, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMB_REGION_12_13, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMB_REGION_14_15, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMB_REGION_16_17, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMB_REGION_18_19, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMB_REGION_20_21, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMB_REGION_22_23, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMB_REGION_24_25, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMB_REGION_26_27, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMB_REGION_28_29, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMB_REGION_30_31, MPCC_MCM, inst),\ - SRII(MPCC_MCM_SHAPER_RAMB_REGION_32_33, MPCC_MCM, inst),\ - SRII(MPCC_MCM_3DLUT_MODE, MPCC_MCM, inst), /*TODO: may need to add other 3DLUT regs*/\ - SRII(MPCC_MCM_3DLUT_INDEX, MPCC_MCM, inst),\ - SRII(MPCC_MCM_3DLUT_DATA, MPCC_MCM, inst),\ - SRII(MPCC_MCM_3DLUT_DATA_30BIT, MPCC_MCM, inst),\ - SRII(MPCC_MCM_3DLUT_READ_WRITE_CONTROL, MPCC_MCM, inst),\ - SRII(MPCC_MCM_3DLUT_OUT_NORM_FACTOR, MPCC_MCM, inst),\ - SRII(MPCC_MCM_3DLUT_OUT_OFFSET_R, MPCC_MCM, inst),\ - SRII(MPCC_MCM_3DLUT_OUT_OFFSET_G, MPCC_MCM, inst),\ - SRII(MPCC_MCM_3DLUT_OUT_OFFSET_B, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_CONTROL, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_LUT_INDEX, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_LUT_DATA, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_LUT_CONTROL, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_START_CNTL_B, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_START_CNTL_G, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_START_CNTL_R, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_START_SLOPE_CNTL_B, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_START_SLOPE_CNTL_G, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_START_SLOPE_CNTL_R, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_START_BASE_CNTL_B, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_START_BASE_CNTL_G, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_START_BASE_CNTL_R, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_END_CNTL1_B, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_END_CNTL2_B, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_END_CNTL1_G, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_END_CNTL2_G, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_END_CNTL1_R, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_END_CNTL2_R, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_OFFSET_B, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_OFFSET_G, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_OFFSET_R, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_REGION_0_1, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_REGION_2_3, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_REGION_4_5, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_REGION_6_7, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_REGION_8_9, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_REGION_10_11, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_REGION_12_13, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_REGION_14_15, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_REGION_16_17, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_REGION_18_19, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_REGION_20_21, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_REGION_22_23, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_REGION_24_25, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_REGION_26_27, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_REGION_28_29, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_REGION_30_31, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMA_REGION_32_33, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_START_CNTL_B, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_START_CNTL_G, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_START_CNTL_R, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_START_SLOPE_CNTL_B, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_START_SLOPE_CNTL_G, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_START_SLOPE_CNTL_R, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_START_BASE_CNTL_B, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_START_BASE_CNTL_G, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_START_BASE_CNTL_R, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_END_CNTL1_B, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_END_CNTL2_B, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_END_CNTL1_G, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_END_CNTL2_G, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_END_CNTL1_R, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_END_CNTL2_R, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_OFFSET_B, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_OFFSET_G, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_OFFSET_R, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_REGION_0_1, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_REGION_2_3, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_REGION_4_5, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_REGION_6_7, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_REGION_8_9, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_REGION_10_11, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_REGION_12_13, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_REGION_14_15, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_REGION_16_17, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_REGION_18_19, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_REGION_20_21, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_REGION_22_23, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_REGION_24_25, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_REGION_26_27, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_REGION_28_29, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_REGION_30_31, MPCC_MCM, inst),\ - SRII(MPCC_MCM_1DLUT_RAMB_REGION_32_33, MPCC_MCM, inst),\ - SRII(MPCC_MCM_MEM_PWR_CTRL, MPCC_MCM, inst) -/* OPTC */ - -#define OPTC_COMMON_REG_LIST_DCN3_2_RI(inst) \ - SRI_ARR(OTG_VSTARTUP_PARAM, OTG, inst), \ - SRI_ARR(OTG_VUPDATE_PARAM, OTG, inst), \ - SRI_ARR(OTG_VREADY_PARAM, OTG, inst), \ - SRI_ARR(OTG_MASTER_UPDATE_LOCK, OTG, inst), \ - SRI_ARR(OTG_GLOBAL_CONTROL0, OTG, inst), \ - SRI_ARR(OTG_GLOBAL_CONTROL1, OTG, inst), \ - SRI_ARR(OTG_GLOBAL_CONTROL2, OTG, inst), \ - SRI_ARR(OTG_GLOBAL_CONTROL4, OTG, inst), \ - SRI_ARR(OTG_DOUBLE_BUFFER_CONTROL, OTG, inst), \ - SRI_ARR(OTG_H_TOTAL, OTG, inst), \ - SRI_ARR(OTG_H_BLANK_START_END, OTG, inst), \ - SRI_ARR(OTG_H_SYNC_A, OTG, inst), SRI_ARR(OTG_H_SYNC_A_CNTL, OTG, inst), \ - SRI_ARR(OTG_H_TIMING_CNTL, OTG, inst), SRI_ARR(OTG_V_TOTAL, OTG, inst), \ - SRI_ARR(OTG_V_BLANK_START_END, OTG, inst), \ - SRI_ARR(OTG_V_SYNC_A, OTG, inst), SRI_ARR(OTG_V_SYNC_A_CNTL, OTG, inst), \ - SRI_ARR(OTG_CONTROL, OTG, inst), SRI_ARR(OTG_STEREO_CONTROL, OTG, inst), \ - SRI_ARR(OTG_3D_STRUCTURE_CONTROL, OTG, inst), \ - SRI_ARR(OTG_STEREO_STATUS, OTG, inst), \ - SRI_ARR(OTG_V_TOTAL_MAX, OTG, inst), \ - SRI_ARR(OTG_V_TOTAL_MIN, OTG, inst), \ - SRI_ARR(OTG_V_TOTAL_CONTROL, OTG, inst), \ - SRI_ARR(OTG_TRIGA_CNTL, OTG, inst), \ - SRI_ARR(OTG_FORCE_COUNT_NOW_CNTL, OTG, inst), \ - SRI_ARR(OTG_STATIC_SCREEN_CONTROL, OTG, inst), \ - SRI_ARR(OTG_STATUS_FRAME_COUNT, OTG, inst), \ - SRI_ARR(OTG_STATUS, OTG, inst), SRI_ARR(OTG_STATUS_POSITION, OTG, inst), \ - SRI_ARR(OTG_NOM_VERT_POSITION, OTG, inst), \ - SRI_ARR(OTG_M_CONST_DTO0, OTG, inst), \ - SRI_ARR(OTG_M_CONST_DTO1, OTG, inst), \ - SRI_ARR(OTG_CLOCK_CONTROL, OTG, inst), \ - SRI_ARR(OTG_VERTICAL_INTERRUPT0_CONTROL, OTG, inst), \ - SRI_ARR(OTG_VERTICAL_INTERRUPT0_POSITION, OTG, inst), \ - SRI_ARR(OTG_VERTICAL_INTERRUPT1_CONTROL, OTG, inst), \ - SRI_ARR(OTG_VERTICAL_INTERRUPT1_POSITION, OTG, inst), \ - SRI_ARR(OTG_VERTICAL_INTERRUPT2_CONTROL, OTG, inst), \ - SRI_ARR(OTG_VERTICAL_INTERRUPT2_POSITION, OTG, inst), \ - SRI_ARR(OPTC_INPUT_CLOCK_CONTROL, ODM, inst), \ - SRI_ARR(OPTC_DATA_SOURCE_SELECT, ODM, inst), \ - SRI_ARR(OPTC_INPUT_GLOBAL_CONTROL, ODM, inst), \ - SRI_ARR(CONTROL, VTG, inst), SRI_ARR(OTG_VERT_SYNC_CONTROL, OTG, inst), \ - SRI_ARR(OTG_GSL_CONTROL, OTG, inst), SRI_ARR(OTG_CRC_CNTL, OTG, inst), \ - SRI_ARR(OTG_CRC0_DATA_RG, OTG, inst), \ - SRI_ARR(OTG_CRC0_DATA_B, OTG, inst), \ - SRI_ARR(OTG_CRC0_WINDOWA_X_CONTROL, OTG, inst), \ - SRI_ARR(OTG_CRC0_WINDOWA_Y_CONTROL, OTG, inst), \ - SRI_ARR(OTG_CRC0_WINDOWB_X_CONTROL, OTG, inst), \ - SRI_ARR(OTG_CRC0_WINDOWB_Y_CONTROL, OTG, inst), \ - SR_ARR(GSL_SOURCE_SELECT, inst), \ - SRI_ARR(OTG_TRIGA_MANUAL_TRIG, OTG, inst), \ - SRI_ARR(OTG_GLOBAL_CONTROL1, OTG, inst), \ - SRI_ARR(OTG_GLOBAL_CONTROL2, OTG, inst), \ - SRI_ARR(OTG_GSL_WINDOW_X, OTG, inst), \ - SRI_ARR(OTG_GSL_WINDOW_Y, OTG, inst), \ - SRI_ARR(OTG_VUPDATE_KEEPOUT, OTG, inst), \ - SRI_ARR(OTG_DSC_START_POSITION, OTG, inst), \ - SRI_ARR(OTG_DRR_TRIGGER_WINDOW, OTG, inst), \ - SRI_ARR(OTG_DRR_V_TOTAL_CHANGE, OTG, inst), \ - SRI_ARR(OPTC_DATA_FORMAT_CONTROL, ODM, inst), \ - SRI_ARR(OPTC_BYTES_PER_PIXEL, ODM, inst), \ - SRI_ARR(OPTC_WIDTH_CONTROL, ODM, inst), \ - SRI_ARR(OPTC_MEMORY_CONFIG, ODM, inst), \ - SRI_ARR(OTG_DRR_CONTROL, OTG, inst) - -/* HUBP */ - -#define HUBP_REG_LIST_DCN_VM_RI(id) \ - SRI_ARR(NOM_PARAMETERS_0, HUBPREQ, id), \ - SRI_ARR(NOM_PARAMETERS_1, HUBPREQ, id), \ - SRI_ARR(NOM_PARAMETERS_2, HUBPREQ, id), \ - SRI_ARR(NOM_PARAMETERS_3, HUBPREQ, id), \ - SRI_ARR(DCN_VM_MX_L1_TLB_CNTL, HUBPREQ, id) -#define HUBP_REG_LIST_DCN_RI(id) \ - SRI_ARR(DCHUBP_CNTL, HUBP, id), SRI_ARR(HUBPREQ_DEBUG_DB, HUBP, id), \ - SRI_ARR(HUBPREQ_DEBUG, HUBP, id), SRI_ARR(DCSURF_ADDR_CONFIG, HUBP, id), \ - SRI_ARR(DCSURF_TILING_CONFIG, HUBP, id), \ - SRI_ARR(DCSURF_SURFACE_PITCH, HUBPREQ, id), \ - SRI_ARR(DCSURF_SURFACE_PITCH_C, HUBPREQ, id), \ - SRI_ARR(DCSURF_SURFACE_CONFIG, HUBP, id), \ - SRI_ARR(DCSURF_FLIP_CONTROL, HUBPREQ, id), \ - SRI_ARR(DCSURF_PRI_VIEWPORT_DIMENSION, HUBP, id), \ - SRI_ARR(DCSURF_PRI_VIEWPORT_START, HUBP, id), \ - SRI_ARR(DCSURF_SEC_VIEWPORT_DIMENSION, HUBP, id), \ - SRI_ARR(DCSURF_SEC_VIEWPORT_START, HUBP, id), \ - SRI_ARR(DCSURF_PRI_VIEWPORT_DIMENSION_C, HUBP, id), \ - SRI_ARR(DCSURF_PRI_VIEWPORT_START_C, HUBP, id), \ - SRI_ARR(DCSURF_SEC_VIEWPORT_DIMENSION_C, HUBP, id), \ - SRI_ARR(DCSURF_SEC_VIEWPORT_START_C, HUBP, id), \ - SRI_ARR(DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH, HUBPREQ, id), \ - SRI_ARR(DCSURF_PRIMARY_SURFACE_ADDRESS, HUBPREQ, id), \ - SRI_ARR(DCSURF_SECONDARY_SURFACE_ADDRESS_HIGH, HUBPREQ, id), \ - SRI_ARR(DCSURF_SECONDARY_SURFACE_ADDRESS, HUBPREQ, id), \ - SRI_ARR(DCSURF_PRIMARY_META_SURFACE_ADDRESS_HIGH, HUBPREQ, id), \ - SRI_ARR(DCSURF_PRIMARY_META_SURFACE_ADDRESS, HUBPREQ, id), \ - SRI_ARR(DCSURF_SECONDARY_META_SURFACE_ADDRESS_HIGH, HUBPREQ, id), \ - SRI_ARR(DCSURF_SECONDARY_META_SURFACE_ADDRESS, HUBPREQ, id), \ - SRI_ARR(DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH_C, HUBPREQ, id), \ - SRI_ARR(DCSURF_PRIMARY_SURFACE_ADDRESS_C, HUBPREQ, id), \ - SRI_ARR(DCSURF_SECONDARY_SURFACE_ADDRESS_HIGH_C, HUBPREQ, id), \ - SRI_ARR(DCSURF_SECONDARY_SURFACE_ADDRESS_C, HUBPREQ, id), \ - SRI_ARR(DCSURF_PRIMARY_META_SURFACE_ADDRESS_HIGH_C, HUBPREQ, id), \ - SRI_ARR(DCSURF_PRIMARY_META_SURFACE_ADDRESS_C, HUBPREQ, id), \ - SRI_ARR(DCSURF_SECONDARY_META_SURFACE_ADDRESS_HIGH_C, HUBPREQ, id), \ - SRI_ARR(DCSURF_SECONDARY_META_SURFACE_ADDRESS_C, HUBPREQ, id), \ - SRI_ARR(DCSURF_SURFACE_INUSE, HUBPREQ, id), \ - SRI_ARR(DCSURF_SURFACE_INUSE_HIGH, HUBPREQ, id), \ - SRI_ARR(DCSURF_SURFACE_INUSE_C, HUBPREQ, id), \ - SRI_ARR(DCSURF_SURFACE_INUSE_HIGH_C, HUBPREQ, id), \ - SRI_ARR(DCSURF_SURFACE_EARLIEST_INUSE, HUBPREQ, id), \ - SRI_ARR(DCSURF_SURFACE_EARLIEST_INUSE_HIGH, HUBPREQ, id), \ - SRI_ARR(DCSURF_SURFACE_EARLIEST_INUSE_C, HUBPREQ, id), \ - SRI_ARR(DCSURF_SURFACE_EARLIEST_INUSE_HIGH_C, HUBPREQ, id), \ - SRI_ARR(DCSURF_SURFACE_CONTROL, HUBPREQ, id), \ - SRI_ARR(DCSURF_SURFACE_FLIP_INTERRUPT, HUBPREQ, id), \ - SRI_ARR(HUBPRET_CONTROL, HUBPRET, id), \ - SRI_ARR(HUBPRET_READ_LINE_STATUS, HUBPRET, id), \ - SRI_ARR(DCN_EXPANSION_MODE, HUBPREQ, id), \ - SRI_ARR(DCHUBP_REQ_SIZE_CONFIG, HUBP, id), \ - SRI_ARR(DCHUBP_REQ_SIZE_CONFIG_C, HUBP, id), \ - SRI_ARR(BLANK_OFFSET_0, HUBPREQ, id), \ - SRI_ARR(BLANK_OFFSET_1, HUBPREQ, id), \ - SRI_ARR(DST_DIMENSIONS, HUBPREQ, id), \ - SRI_ARR(DST_AFTER_SCALER, HUBPREQ, id), \ - SRI_ARR(VBLANK_PARAMETERS_0, HUBPREQ, id), \ - SRI_ARR(REF_FREQ_TO_PIX_FREQ, HUBPREQ, id), \ - SRI_ARR(VBLANK_PARAMETERS_1, HUBPREQ, id), \ - SRI_ARR(VBLANK_PARAMETERS_3, HUBPREQ, id), \ - SRI_ARR(NOM_PARAMETERS_4, HUBPREQ, id), \ - SRI_ARR(NOM_PARAMETERS_5, HUBPREQ, id), \ - SRI_ARR(PER_LINE_DELIVERY_PRE, HUBPREQ, id), \ - SRI_ARR(PER_LINE_DELIVERY, HUBPREQ, id), \ - SRI_ARR(VBLANK_PARAMETERS_2, HUBPREQ, id), \ - SRI_ARR(VBLANK_PARAMETERS_4, HUBPREQ, id), \ - SRI_ARR(NOM_PARAMETERS_6, HUBPREQ, id), \ - SRI_ARR(NOM_PARAMETERS_7, HUBPREQ, id), \ - SRI_ARR(DCN_TTU_QOS_WM, HUBPREQ, id), \ - SRI_ARR(DCN_GLOBAL_TTU_CNTL, HUBPREQ, id), \ - SRI_ARR(DCN_SURF0_TTU_CNTL0, HUBPREQ, id), \ - SRI_ARR(DCN_SURF0_TTU_CNTL1, HUBPREQ, id), \ - SRI_ARR(DCN_SURF1_TTU_CNTL0, HUBPREQ, id), \ - SRI_ARR(DCN_SURF1_TTU_CNTL1, HUBPREQ, id), \ - SRI_ARR(DCN_CUR0_TTU_CNTL0, HUBPREQ, id), \ - SRI_ARR(DCN_CUR0_TTU_CNTL1, HUBPREQ, id), \ - SRI_ARR(HUBP_CLK_CNTL, HUBP, id) -#define HUBP_REG_LIST_DCN2_COMMON_RI(id) \ - HUBP_REG_LIST_DCN_RI(id), HUBP_REG_LIST_DCN_VM_RI(id), \ - SRI_ARR(PREFETCH_SETTINGS, HUBPREQ, id), \ - SRI_ARR(PREFETCH_SETTINGS_C, HUBPREQ, id), \ - SRI_ARR(DCN_VM_SYSTEM_APERTURE_LOW_ADDR, HUBPREQ, id), \ - SRI_ARR(DCN_VM_SYSTEM_APERTURE_HIGH_ADDR, HUBPREQ, id), \ - SRI_ARR(CURSOR_SETTINGS, HUBPREQ, id), \ - SRI_ARR(CURSOR_SURFACE_ADDRESS_HIGH, CURSOR0_, id), \ - SRI_ARR(CURSOR_SURFACE_ADDRESS, CURSOR0_, id), \ - SRI_ARR(CURSOR_SIZE, CURSOR0_, id), \ - SRI_ARR(CURSOR_CONTROL, CURSOR0_, id), \ - SRI_ARR(CURSOR_POSITION, CURSOR0_, id), \ - SRI_ARR(CURSOR_HOT_SPOT, CURSOR0_, id), \ - SRI_ARR(CURSOR_DST_OFFSET, CURSOR0_, id), \ - SRI_ARR(DMDATA_ADDRESS_HIGH, CURSOR0_, id), \ - SRI_ARR(DMDATA_ADDRESS_LOW, CURSOR0_, id), \ - SRI_ARR(DMDATA_CNTL, CURSOR0_, id), \ - SRI_ARR(DMDATA_SW_CNTL, CURSOR0_, id), \ - SRI_ARR(DMDATA_QOS_CNTL, CURSOR0_, id), \ - SRI_ARR(DMDATA_SW_DATA, CURSOR0_, id), \ - SRI_ARR(DMDATA_STATUS, CURSOR0_, id), \ - SRI_ARR(FLIP_PARAMETERS_0, HUBPREQ, id), \ - SRI_ARR(FLIP_PARAMETERS_1, HUBPREQ, id), \ - SRI_ARR(FLIP_PARAMETERS_2, HUBPREQ, id), \ - SRI_ARR(DCN_CUR1_TTU_CNTL0, HUBPREQ, id), \ - SRI_ARR(DCN_CUR1_TTU_CNTL1, HUBPREQ, id), \ - SRI_ARR(DCSURF_FLIP_CONTROL2, HUBPREQ, id), \ - SRI_ARR(VMID_SETTINGS_0, HUBPREQ, id) -#define HUBP_REG_LIST_DCN21_RI(id) \ - HUBP_REG_LIST_DCN2_COMMON_RI(id), SRI_ARR(FLIP_PARAMETERS_3, HUBPREQ, id), \ - SRI_ARR(FLIP_PARAMETERS_4, HUBPREQ, id), \ - SRI_ARR(FLIP_PARAMETERS_5, HUBPREQ, id), \ - SRI_ARR(FLIP_PARAMETERS_6, HUBPREQ, id), \ - SRI_ARR(VBLANK_PARAMETERS_5, HUBPREQ, id), \ - SRI_ARR(VBLANK_PARAMETERS_6, HUBPREQ, id) -#define HUBP_REG_LIST_DCN30_RI(id) \ - HUBP_REG_LIST_DCN21_RI(id), SRI_ARR(DCN_DMDATA_VM_CNTL, HUBPREQ, id) -#define HUBP_REG_LIST_DCN32_RI(id) \ - HUBP_REG_LIST_DCN30_RI(id), SRI_ARR(DCHUBP_MALL_CONFIG, HUBP, id), \ - SRI_ARR(DCHUBP_VMPG_CONFIG, HUBP, id), \ - SRI_ARR(UCLK_PSTATE_FORCE, HUBPREQ, id) - -/* HUBBUB */ - -#define HUBBUB_REG_LIST_DCN32_RI(id) \ - SR(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A), \ - SR(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B), \ - SR(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C), \ - SR(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D), \ - SR(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL), \ - SR(DCHUBBUB_ARB_DRAM_STATE_CNTL), SR(DCHUBBUB_ARB_SAT_LEVEL), \ - SR(DCHUBBUB_ARB_DF_REQ_OUTSTAND), SR(DCHUBBUB_GLOBAL_TIMER_CNTL), \ - SR(DCHUBBUB_SOFT_RESET), SR(DCHUBBUB_CRC_CTRL), \ - SR(DCN_VM_FB_LOCATION_BASE), SR(DCN_VM_FB_LOCATION_TOP), \ - SR(DCN_VM_FB_OFFSET), SR(DCN_VM_AGP_BOT), SR(DCN_VM_AGP_TOP), \ - SR(DCN_VM_AGP_BASE), HUBBUB_SR_WATERMARK_REG_LIST(), \ - SR(DCHUBBUB_ARB_FRAC_URG_BW_NOM_A), SR(DCHUBBUB_ARB_FRAC_URG_BW_NOM_B), \ - SR(DCHUBBUB_ARB_FRAC_URG_BW_NOM_C), SR(DCHUBBUB_ARB_FRAC_URG_BW_NOM_D), \ - SR(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A), \ - SR(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B), \ - SR(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C), \ - SR(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D), \ - SR(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A), \ - SR(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B), \ - SR(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C), \ - SR(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D), SR(DCHUBBUB_DET0_CTRL), \ - SR(DCHUBBUB_DET1_CTRL), SR(DCHUBBUB_DET2_CTRL), SR(DCHUBBUB_DET3_CTRL), \ - SR(DCHUBBUB_COMPBUF_CTRL), SR(COMPBUF_RESERVED_SPACE), \ - SR(DCHUBBUB_DEBUG_CTRL_0), \ - SR(DCHUBBUB_ARB_USR_RETRAINING_CNTL), \ - SR(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_A), \ - SR(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_B), \ - SR(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_C), \ - SR(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_D), \ - SR(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_A), \ - SR(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_B), \ - SR(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_C), \ - SR(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_D), \ - SR(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_A), \ - SR(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_B), \ - SR(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_C), \ - SR(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_D), \ - SR(DCHUBBUB_ARB_MALL_CNTL), \ - SR(DCN_VM_FAULT_ADDR_MSB), SR(DCN_VM_FAULT_ADDR_LSB), \ - SR(DCN_VM_FAULT_CNTL), SR(DCN_VM_FAULT_STATUS), \ - SR(SDPIF_REQUEST_RATE_LIMIT) - -/* DCCG */ - -#define DCCG_REG_LIST_DCN32_RI() \ - SR(DPPCLK_DTO_CTRL), DCCG_SRII(DTO_PARAM, DPPCLK, 0), \ - DCCG_SRII(DTO_PARAM, DPPCLK, 1), DCCG_SRII(DTO_PARAM, DPPCLK, 2), \ - DCCG_SRII(DTO_PARAM, DPPCLK, 3), DCCG_SRII(CLOCK_CNTL, HDMICHARCLK, 0), \ - SR(PHYASYMCLK_CLOCK_CNTL), SR(PHYBSYMCLK_CLOCK_CNTL), \ - SR(PHYCSYMCLK_CLOCK_CNTL), SR(PHYDSYMCLK_CLOCK_CNTL), \ - SR(PHYESYMCLK_CLOCK_CNTL), SR(DPSTREAMCLK_CNTL), SR(HDMISTREAMCLK_CNTL), \ - SR(SYMCLK32_SE_CNTL), SR(SYMCLK32_LE_CNTL), \ - DCCG_SRII(PIXEL_RATE_CNTL, OTG, 0), DCCG_SRII(PIXEL_RATE_CNTL, OTG, 1), \ - DCCG_SRII(PIXEL_RATE_CNTL, OTG, 2), DCCG_SRII(PIXEL_RATE_CNTL, OTG, 3), \ - DCCG_SRII(MODULO, DTBCLK_DTO, 0), DCCG_SRII(MODULO, DTBCLK_DTO, 1), \ - DCCG_SRII(MODULO, DTBCLK_DTO, 2), DCCG_SRII(MODULO, DTBCLK_DTO, 3), \ - DCCG_SRII(PHASE, DTBCLK_DTO, 0), DCCG_SRII(PHASE, DTBCLK_DTO, 1), \ - DCCG_SRII(PHASE, DTBCLK_DTO, 2), DCCG_SRII(PHASE, DTBCLK_DTO, 3), \ - SR(DCCG_AUDIO_DTBCLK_DTO_MODULO), SR(DCCG_AUDIO_DTBCLK_DTO_PHASE), \ - SR(OTG_PIXEL_RATE_DIV), SR(DTBCLK_P_CNTL), \ - SR(DCCG_AUDIO_DTO_SOURCE), SR(DENTIST_DISPCLK_CNTL) - -/* VMID */ -#define DCN20_VMID_REG_LIST_RI(id) \ - SRI_ARR(CNTL, DCN_VM_CONTEXT, id), \ - SRI_ARR(PAGE_TABLE_BASE_ADDR_HI32, DCN_VM_CONTEXT, id), \ - SRI_ARR(PAGE_TABLE_BASE_ADDR_LO32, DCN_VM_CONTEXT, id), \ - SRI_ARR(PAGE_TABLE_START_ADDR_HI32, DCN_VM_CONTEXT, id), \ - SRI_ARR(PAGE_TABLE_START_ADDR_LO32, DCN_VM_CONTEXT, id), \ - SRI_ARR(PAGE_TABLE_END_ADDR_HI32, DCN_VM_CONTEXT, id), \ - SRI_ARR(PAGE_TABLE_END_ADDR_LO32, DCN_VM_CONTEXT, id) - -/* I2C HW */ - -#define I2C_HW_ENGINE_COMMON_REG_LIST_RI(id) \ - SRI_ARR_I2C(SETUP, DC_I2C_DDC, id), SRI_ARR_I2C(SPEED, DC_I2C_DDC, id), \ - SRI_ARR_I2C(HW_STATUS, DC_I2C_DDC, id), \ - SR_ARR_I2C(DC_I2C_ARBITRATION, id), \ - SR_ARR_I2C(DC_I2C_CONTROL, id), SR_ARR_I2C(DC_I2C_SW_STATUS, id), \ - SR_ARR_I2C(DC_I2C_TRANSACTION0, id), SR_ARR_I2C(DC_I2C_TRANSACTION1, id),\ - SR_ARR_I2C(DC_I2C_TRANSACTION2, id), SR_ARR_I2C(DC_I2C_TRANSACTION3, id),\ - SR_ARR_I2C(DC_I2C_DATA, id), SR_ARR_I2C(MICROSECOND_TIME_BASE_DIV, id) - -#define I2C_HW_ENGINE_COMMON_REG_LIST_DCN30_RI(id) \ - I2C_HW_ENGINE_COMMON_REG_LIST_RI(id), SR_ARR_I2C(DIO_MEM_PWR_CTRL, id), \ - SR_ARR_I2C(DIO_MEM_PWR_STATUS, id) - -#endif /* _DCN32_RESOURCE_H_ */ 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 bc5f0db23d0c36..87760600e154da 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 @@ -24,10 +24,11 @@ */ // header file of functions being implemented -#include "dcn32_resource.h" +#include "dcn32/dcn32_resource.h" #include "dcn20/dcn20_resource.h" #include "dml/dcn32/display_mode_vba_util_32.h" #include "dml/dcn32/dcn32_fpu.h" +#include "dc_state_priv.h" static bool is_dual_plane(enum surface_pixel_format format) { @@ -190,7 +191,7 @@ bool dcn32_subvp_in_use(struct dc *dc, 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_NONE) + if (dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_NONE) return true; } return false; @@ -264,18 +265,17 @@ static void override_det_for_subvp(struct dc *dc, struct dc_state *context, uint // Do not override if a stream has multiple planes for (i = 0; i < context->stream_count; i++) { - if (context->stream_status[i].plane_count > 1) { + if (context->stream_status[i].plane_count > 1) return; - } - if (context->streams[i]->mall_stream_config.type != SUBVP_PHANTOM) { + + if (dc_state_get_stream_subvp_type(context, context->streams[i]) != SUBVP_PHANTOM) stream_count++; - } } for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - if (pipe_ctx->stream && pipe_ctx->plane_state && pipe_ctx->stream->mall_stream_config.type != SUBVP_PHANTOM) { + if (pipe_ctx->stream && pipe_ctx->plane_state && dc_state_get_pipe_subvp_type(context, pipe_ctx) != SUBVP_PHANTOM) { if (dcn32_allow_subvp_high_refresh_rate(dc, context, pipe_ctx)) { if (pipe_ctx->stream->timing.v_addressable == 1080 && pipe_ctx->stream->timing.h_addressable == 1920) { @@ -290,7 +290,7 @@ static void override_det_for_subvp(struct dc *dc, struct dc_state *context, uint for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - if (pipe_ctx->stream && pipe_ctx->plane_state && pipe_ctx->stream->mall_stream_config.type != SUBVP_PHANTOM) { + if (pipe_ctx->stream && pipe_ctx->plane_state && dc_state_get_pipe_subvp_type(context, pipe_ctx) != SUBVP_PHANTOM) { if (pipe_ctx->stream->timing.v_addressable == 1080 && pipe_ctx->stream->timing.h_addressable == 1920) { if (pipe_segments[i] > 4) pipe_segments[i] = 4; @@ -337,14 +337,14 @@ void dcn32_determine_det_override(struct dc *dc, for (i = 0; i < context->stream_count; i++) { /* Don't count SubVP streams for DET allocation */ - if (context->streams[i]->mall_stream_config.type != SUBVP_PHANTOM) + if (dc_state_get_stream_subvp_type(context, context->streams[i]) != SUBVP_PHANTOM) stream_count++; } if (stream_count > 0) { stream_segments = 18 / stream_count; for (i = 0; i < context->stream_count; i++) { - if (context->streams[i]->mall_stream_config.type == SUBVP_PHANTOM) + if (dc_state_get_stream_subvp_type(context, context->streams[i]) == SUBVP_PHANTOM) continue; if (context->stream_status[i].plane_count > 0) @@ -430,71 +430,6 @@ void dcn32_set_det_allocations(struct dc *dc, struct dc_state *context, dcn32_determine_det_override(dc, context, pipes); } -/** - * dcn32_save_mall_state(): Save MALL (SubVP) state for fast validation cases - * - * This function saves the MALL (SubVP) case for fast validation cases. For fast validation, - * there are situations where a shallow copy of the dc->current_state is created for the - * validation. In this case we want to save and restore the mall config because we always - * teardown subvp at the beginning of validation (and don't attempt to add it back if it's - * fast validation). If we don't restore the subvp config in cases of fast validation + - * shallow copy of the dc->current_state, the dc->current_state will have a partially - * removed subvp state when we did not intend to remove it. - * - * NOTE: This function ONLY works if the streams are not moved to a different pipe in the - * validation. We don't expect this to happen in fast_validation=1 cases. - * - * @dc: Current DC state - * @context: New DC state to be programmed - * @temp_config: struct used to cache the existing MALL state - * - * Return: void - */ -void dcn32_save_mall_state(struct dc *dc, - struct dc_state *context, - struct mall_temp_config *temp_config) -{ - uint32_t i; - - for (i = 0; i < dc->res_pool->pipe_count; i++) { - struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - - if (pipe->stream) - temp_config->mall_stream_config[i] = pipe->stream->mall_stream_config; - - if (pipe->plane_state) - temp_config->is_phantom_plane[i] = pipe->plane_state->is_phantom; - } -} - -/** - * dcn32_restore_mall_state(): Restore MALL (SubVP) state for fast validation cases - * - * Restore the MALL state based on the previously saved state from dcn32_save_mall_state - * - * @dc: Current DC state - * @context: New DC state to be programmed, restore MALL state into here - * @temp_config: struct that has the cached MALL state - * - * Return: void - */ -void dcn32_restore_mall_state(struct dc *dc, - struct dc_state *context, - struct mall_temp_config *temp_config) -{ - uint32_t i; - - 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 = temp_config->mall_stream_config[i]; - - if (pipe->plane_state) - pipe->plane_state->is_phantom = temp_config->is_phantom_plane[i]; - } -} - #define MAX_STRETCHED_V_BLANK 1000 // in micro-seconds (must ensure to match value in FW) /* * Scaling factor for v_blank stretch calculations considering timing in @@ -589,13 +524,14 @@ static int get_refresh_rate(struct dc_stream_state *fpo_candidate_stream) * * Return: Pointer to FPO stream candidate if config can support FPO, otherwise NULL */ -struct dc_stream_state *dcn32_can_support_mclk_switch_using_fw_based_vblank_stretch(struct dc *dc, const struct dc_state *context) +struct dc_stream_state *dcn32_can_support_mclk_switch_using_fw_based_vblank_stretch(struct dc *dc, struct dc_state *context) { int refresh_rate = 0; const int minimum_refreshrate_supported = 120; struct dc_stream_state *fpo_candidate_stream = NULL; bool is_fpo_vactive = false; uint32_t fpo_vactive_margin_us = 0; + struct dc_stream_status *fpo_stream_status = NULL; if (context == NULL) return NULL; @@ -618,16 +554,28 @@ struct dc_stream_state *dcn32_can_support_mclk_switch_using_fw_based_vblank_stre DC_FP_START(); dcn32_assign_fpo_vactive_candidate(dc, context, &fpo_candidate_stream); DC_FP_END(); - + if (fpo_candidate_stream) + fpo_stream_status = dc_state_get_stream_status(context, fpo_candidate_stream); DC_FP_START(); is_fpo_vactive = dcn32_find_vactive_pipe(dc, context, dc->debug.fpo_vactive_min_active_margin_us); DC_FP_END(); if (!is_fpo_vactive || dc->debug.disable_fpo_vactive) return NULL; - } else + } else { fpo_candidate_stream = context->streams[0]; + if (fpo_candidate_stream) + fpo_stream_status = dc_state_get_stream_status(context, fpo_candidate_stream); + } - if (!fpo_candidate_stream) + /* In DCN32/321, FPO uses per-pipe P-State force. + * If there's no planes, HUBP is power gated and + * therefore programming UCLK_PSTATE_FORCE does + * nothing (P-State will always be asserted naturally + * on a pipe that has HUBP power gated. Therefore we + * only want to enable FPO if the FPO pipe has both + * a stream and a plane. + */ + if (!fpo_candidate_stream || !fpo_stream_status || fpo_stream_status->plane_count == 0) return NULL; if (fpo_candidate_stream->sink->edid_caps.panel_patch.disable_fams) @@ -665,6 +613,30 @@ bool dcn32_check_native_scaling_for_res(struct pipe_ctx *pipe, unsigned int widt return is_native_scaling; } +/** + * disallow_subvp_in_active_plus_blank() - Function to determine disallowed subvp + drr/vblank configs + * + * @pipe: subvp pipe to be used for the subvp + drr/vblank config + * + * Since subvp is being enabled on more configs (such as 1080p60), we want + * to explicitly block any configs that we don't want to enable. We do not + * want to enable any 1080p60 (SubVP) + drr / vblank configs since these + * are already convered by FPO. + * + * Return: True if disallowed, false otherwise + */ +static bool disallow_subvp_in_active_plus_blank(struct pipe_ctx *pipe) +{ + bool disallow = false; + + if (resource_is_pipe_type(pipe, OPP_HEAD) && + resource_is_pipe_type(pipe, DPP_PIPE)) { + if (pipe->stream->timing.v_addressable == 1080 && pipe->stream->timing.h_addressable == 1920) + disallow = true; + } + return disallow; +} + /** * dcn32_subvp_drr_admissable() - Determine if SubVP + DRR config is admissible * @@ -688,21 +660,24 @@ bool dcn32_subvp_drr_admissable(struct dc *dc, struct dc_state *context) bool drr_pipe_found = false; bool drr_psr_capable = false; uint64_t refresh_rate = 0; + bool subvp_disallow = false; for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + enum mall_stream_type pipe_mall_type = dc_state_get_pipe_subvp_type(context, pipe); if (resource_is_pipe_type(pipe, OPP_HEAD) && resource_is_pipe_type(pipe, DPP_PIPE)) { - if (pipe->stream->mall_stream_config.type == SUBVP_MAIN) { + if (pipe_mall_type == SUBVP_MAIN) { subvp_count++; + subvp_disallow |= disallow_subvp_in_active_plus_blank(pipe); refresh_rate = (pipe->stream->timing.pix_clk_100hz * (uint64_t)100 + pipe->stream->timing.v_total * pipe->stream->timing.h_total - (uint64_t)1); refresh_rate = div_u64(refresh_rate, pipe->stream->timing.v_total); refresh_rate = div_u64(refresh_rate, pipe->stream->timing.h_total); } - if (pipe->stream->mall_stream_config.type == SUBVP_NONE) { + if (pipe_mall_type == SUBVP_NONE) { non_subvp_pipes++; drr_psr_capable = (drr_psr_capable || dcn32_is_psr_capable(pipe)); if (pipe->stream->ignore_msa_timing_param && @@ -713,7 +688,7 @@ bool dcn32_subvp_drr_admissable(struct dc *dc, struct dc_state *context) } } - if (subvp_count == 1 && non_subvp_pipes == 1 && drr_pipe_found && !drr_psr_capable && + if (subvp_count == 1 && !subvp_disallow && non_subvp_pipes == 1 && drr_pipe_found && !drr_psr_capable && ((uint32_t)refresh_rate < 120)) result = true; @@ -746,21 +721,24 @@ bool dcn32_subvp_vblank_admissable(struct dc *dc, struct dc_state *context, int struct vba_vars_st *vba = &context->bw_ctx.dml.vba; bool vblank_psr_capable = false; uint64_t refresh_rate = 0; + bool subvp_disallow = false; for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + enum mall_stream_type pipe_mall_type = dc_state_get_pipe_subvp_type(context, pipe); if (resource_is_pipe_type(pipe, OPP_HEAD) && resource_is_pipe_type(pipe, DPP_PIPE)) { - if (pipe->stream->mall_stream_config.type == SUBVP_MAIN) { + if (pipe_mall_type == SUBVP_MAIN) { subvp_count++; + subvp_disallow |= disallow_subvp_in_active_plus_blank(pipe); refresh_rate = (pipe->stream->timing.pix_clk_100hz * (uint64_t)100 + pipe->stream->timing.v_total * pipe->stream->timing.h_total - (uint64_t)1); refresh_rate = div_u64(refresh_rate, pipe->stream->timing.v_total); refresh_rate = div_u64(refresh_rate, pipe->stream->timing.h_total); } - if (pipe->stream->mall_stream_config.type == SUBVP_NONE) { + if (pipe_mall_type == SUBVP_NONE) { non_subvp_pipes++; vblank_psr_capable = (vblank_psr_capable || dcn32_is_psr_capable(pipe)); if (pipe->stream->ignore_msa_timing_param && @@ -772,9 +750,35 @@ bool dcn32_subvp_vblank_admissable(struct dc *dc, struct dc_state *context, int } if (subvp_count == 1 && non_subvp_pipes == 1 && !drr_pipe_found && !vblank_psr_capable && - ((uint32_t)refresh_rate < 120) && + ((uint32_t)refresh_rate < 120) && !subvp_disallow && vba->DRAMClockChangeSupport[vlevel][vba->maxMpcComb] == dm_dram_clock_change_vblank_w_mall_sub_vp) result = true; return result; } + +void dcn32_update_dml_pipes_odm_policy_based_on_context(struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes) +{ + int i, pipe_cnt; + struct resource_context *res_ctx = &context->res_ctx; + struct pipe_ctx *pipe = NULL; + + for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) { + int odm_slice_count = 0; + + if (!res_ctx->pipe_ctx[i].stream) + continue; + pipe = &res_ctx->pipe_ctx[i]; + odm_slice_count = resource_get_odm_slice_count(pipe); + + if (odm_slice_count == 1) + pipes[pipe_cnt].pipe.dest.odm_combine_policy = dm_odm_combine_policy_dal; + else if (odm_slice_count == 2) + pipes[pipe_cnt].pipe.dest.odm_combine_policy = dm_odm_combine_policy_2to1; + else if (odm_slice_count == 4) + pipes[pipe_cnt].pipe.dest.odm_combine_policy = dm_odm_combine_policy_4to1; + + pipe_cnt++; + } +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn321/Makefile b/drivers/gpu/drm/amd/display/dc/dcn321/Makefile index 0a199c83bb5b33..c195c47f58b460 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn321/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn321/Makefile @@ -10,7 +10,7 @@ # # Makefile for dcn321. -DCN321 = dcn321_resource.o dcn321_dio_link_encoder.o +DCN321 = dcn321_dio_link_encoder.o AMD_DAL_DCN321 = $(addprefix $(AMDDALPATH)/dc/dcn321/,$(DCN321)) diff --git a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c deleted file mode 100644 index f7de3eca1225ab..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.c +++ /dev/null @@ -1,2065 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - * Copyright 2019 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 "dcn32/dcn32_init.h" - -#include "resource.h" -#include "include/irq_service_interface.h" -#include "dcn32/dcn32_resource.h" -#include "dcn321_resource.h" - -#include "dcn20/dcn20_resource.h" -#include "dcn30/dcn30_resource.h" - -#include "dml/dcn321/dcn321_fpu.h" - -#include "dcn10/dcn10_ipp.h" -#include "dcn30/dcn30_hubbub.h" -#include "dcn31/dcn31_hubbub.h" -#include "dcn32/dcn32_hubbub.h" -#include "dcn32/dcn32_mpc.h" -#include "dcn32/dcn32_hubp.h" -#include "irq/dcn32/irq_service_dcn32.h" -#include "dcn32/dcn32_dpp.h" -#include "dcn32/dcn32_optc.h" -#include "dcn20/dcn20_hwseq.h" -#include "dcn30/dcn30_hwseq.h" -#include "dce110/dce110_hwseq.h" -#include "dcn30/dcn30_opp.h" -#include "dcn20/dcn20_dsc.h" -#include "dcn30/dcn30_vpg.h" -#include "dcn30/dcn30_afmt.h" -#include "dcn30/dcn30_dio_stream_encoder.h" -#include "dcn32/dcn32_dio_stream_encoder.h" -#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 "dcn31/dcn31_apg.h" -#include "dcn31/dcn31_dio_link_encoder.h" -#include "dcn32/dcn32_dio_link_encoder.h" -#include "dcn321_dio_link_encoder.h" -#include "dce/dce_clock_source.h" -#include "dce/dce_audio.h" -#include "dce/dce_hwseq.h" -#include "clk_mgr.h" -#include "virtual/virtual_stream_encoder.h" -#include "dml/display_mode_vba.h" -#include "dcn32/dcn32_dccg.h" -#include "dcn10/dcn10_resource.h" -#include "link.h" -#include "dcn31/dcn31_panel_cntl.h" - -#include "dcn30/dcn30_dwb.h" -#include "dcn32/dcn32_mmhubbub.h" - -#include "dcn/dcn_3_2_1_offset.h" -#include "dcn/dcn_3_2_1_sh_mask.h" -#include "nbio/nbio_4_3_0_offset.h" - -#include "reg_helper.h" -#include "dce/dmub_abm.h" -#include "dce/dmub_psr.h" -#include "dce/dce_aux.h" -#include "dce/dce_i2c.h" - -#include "dml/dcn30/display_mode_vba_30.h" -#include "vm_helper.h" -#include "dcn20/dcn20_vmid.h" - -#define DC_LOGGER_INIT(logger) - -enum dcn321_clk_src_array_id { - DCN321_CLK_SRC_PLL0, - DCN321_CLK_SRC_PLL1, - DCN321_CLK_SRC_PLL2, - DCN321_CLK_SRC_PLL3, - DCN321_CLK_SRC_PLL4, - DCN321_CLK_SRC_TOTAL -}; - -/* begin ********************* - * macros to expend register list macro defined in HW object header file - */ - -/* DCN */ -#define BASE_INNER(seg) ctx->dcn_reg_offsets[seg] - -#define BASE(seg) BASE_INNER(seg) - -#define SR(reg_name)\ - REG_STRUCT.reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ - reg ## reg_name -#define SR_ARR(reg_name, id)\ - REG_STRUCT[id].reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ - reg ## reg_name -#define SR_ARR_INIT(reg_name, id, value)\ - REG_STRUCT[id].reg_name = value - -#define SRI(reg_name, block, id)\ - REG_STRUCT.reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRI_ARR(reg_name, block, id)\ - REG_STRUCT[id].reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SR_ARR_I2C(reg_name, id) \ - REG_STRUCT[id-1].reg_name = BASE(reg##reg_name##_BASE_IDX) + reg##reg_name - -#define SRI_ARR_I2C(reg_name, block, id)\ - REG_STRUCT[id-1].reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRI_ARR_ALPHABET(reg_name, block, index, id)\ - REG_STRUCT[index].reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRI2(reg_name, block, id)\ - .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ - reg ## reg_name -#define SRI2_ARR(reg_name, block, id)\ - REG_STRUCT[id].reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ - reg ## reg_name - -#define SRIR(var_name, reg_name, block, id)\ - .var_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRII(reg_name, block, id)\ - REG_STRUCT.reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRII_ARR_2(reg_name, block, id, inst)\ - REG_STRUCT[inst].reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRII_MPC_RMU(reg_name, block, id)\ - .RMU##_##reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRII_DWB(reg_name, temp_name, block, id)\ - REG_STRUCT.reg_name[id] = BASE(reg ## block ## id ## _ ## temp_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## temp_name - -#define DCCG_SRII(reg_name, block, id)\ - REG_STRUCT.block ## _ ## reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SF_DWB2(reg_name, block, id, field_name, post_fix) \ - .field_name = reg_name ## __ ## field_name ## post_fix - -#define VUPDATE_SRII(reg_name, block, id)\ - REG_STRUCT.reg_name[id] = BASE(reg ## reg_name ## _ ## block ## id ## _BASE_IDX) + \ - reg ## reg_name ## _ ## block ## id - -/* NBIO */ -#define NBIO_BASE_INNER(seg) ctx->nbio_reg_offsets[seg] - -#define NBIO_BASE(seg) \ - NBIO_BASE_INNER(seg) - -#define NBIO_SR(reg_name)\ - REG_STRUCT.reg_name = NBIO_BASE(regBIF_BX0_ ## reg_name ## _BASE_IDX) + \ - regBIF_BX0_ ## reg_name -#define NBIO_SR_ARR(reg_name, id)\ - REG_STRUCT[id].reg_name = NBIO_BASE(regBIF_BX0_ ## reg_name ## _BASE_IDX) + \ - regBIF_BX0_ ## reg_name - -#define CTX ctx -#define REG(reg_name) \ - (ctx->dcn_reg_offsets[reg ## reg_name ## _BASE_IDX] + reg ## reg_name) - -static struct bios_registers bios_regs; - -#define bios_regs_init() \ - ( \ - NBIO_SR(BIOS_SCRATCH_3),\ - NBIO_SR(BIOS_SCRATCH_6)\ - ) - -#define clk_src_regs_init(index, pllid)\ - CS_COMMON_REG_LIST_DCN3_0_RI(index, pllid) - -static struct dce110_clk_src_regs clk_src_regs[5]; - -static const struct dce110_clk_src_shift cs_shift = { - CS_COMMON_MASK_SH_LIST_DCN3_2(__SHIFT) -}; - -static const struct dce110_clk_src_mask cs_mask = { - CS_COMMON_MASK_SH_LIST_DCN3_2(_MASK) -}; - -#define abm_regs_init(id)\ - ABM_DCN32_REG_LIST_RI(id) - -static struct dce_abm_registers abm_regs[4]; - -static const struct dce_abm_shift abm_shift = { - ABM_MASK_SH_LIST_DCN32(__SHIFT) -}; - -static const struct dce_abm_mask abm_mask = { - ABM_MASK_SH_LIST_DCN32(_MASK) -}; - -#define audio_regs_init(id)\ - AUD_COMMON_REG_LIST_RI(id) - -static struct dce_audio_registers audio_regs[5]; - -#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ - SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ - SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ - AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) - -static const struct dce_audio_shift audio_shift = { - DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_audio_mask audio_mask = { - DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) -}; - -#define vpg_regs_init(id)\ - VPG_DCN3_REG_LIST_RI(id) - -static struct dcn30_vpg_registers vpg_regs[10]; - -static const struct dcn30_vpg_shift vpg_shift = { - DCN3_VPG_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn30_vpg_mask vpg_mask = { - DCN3_VPG_MASK_SH_LIST(_MASK) -}; - -#define afmt_regs_init(id)\ - AFMT_DCN3_REG_LIST_RI(id) - -static struct dcn30_afmt_registers afmt_regs[6]; - -static const struct dcn30_afmt_shift afmt_shift = { - DCN3_AFMT_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn30_afmt_mask afmt_mask = { - DCN3_AFMT_MASK_SH_LIST(_MASK) -}; - -#define apg_regs_init(id)\ - APG_DCN31_REG_LIST_RI(id) - -static struct dcn31_apg_registers apg_regs[4]; - -static const struct dcn31_apg_shift apg_shift = { - DCN31_APG_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn31_apg_mask apg_mask = { - DCN31_APG_MASK_SH_LIST(_MASK) -}; - -#define stream_enc_regs_init(id)\ - SE_DCN32_REG_LIST_RI(id) - -static struct dcn10_stream_enc_registers stream_enc_regs[5]; - -static const struct dcn10_stream_encoder_shift se_shift = { - SE_COMMON_MASK_SH_LIST_DCN32(__SHIFT) -}; - -static const struct dcn10_stream_encoder_mask se_mask = { - SE_COMMON_MASK_SH_LIST_DCN32(_MASK) -}; - - -#define aux_regs_init(id)\ - DCN2_AUX_REG_LIST_RI(id) - -static struct dcn10_link_enc_aux_registers link_enc_aux_regs[5]; - -#define hpd_regs_init(id)\ - HPD_REG_LIST_RI(id) - -static struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[5]; - -#define link_regs_init(id, phyid)\ - ( \ - LE_DCN31_REG_LIST_RI(id), \ - UNIPHY_DCN2_REG_LIST_RI(id, phyid)\ - ) - /*DPCS_DCN31_REG_LIST(id),*/ \ - -static struct dcn10_link_enc_registers link_enc_regs[5]; - -static const struct dcn10_link_enc_shift le_shift = { - LINK_ENCODER_MASK_SH_LIST_DCN31(__SHIFT), \ -// DPCS_DCN31_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn10_link_enc_mask le_mask = { - LINK_ENCODER_MASK_SH_LIST_DCN31(_MASK), \ -// DPCS_DCN31_MASK_SH_LIST(_MASK) -}; - -#define hpo_dp_stream_encoder_reg_init(id)\ - DCN3_1_HPO_DP_STREAM_ENC_REG_LIST_RI(id) - -static struct dcn31_hpo_dp_stream_encoder_registers hpo_dp_stream_enc_regs[4]; - -static const struct dcn31_hpo_dp_stream_encoder_shift hpo_dp_se_shift = { - DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn31_hpo_dp_stream_encoder_mask hpo_dp_se_mask = { - DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(_MASK) -}; - - -#define hpo_dp_link_encoder_reg_init(id)\ - DCN3_1_HPO_DP_LINK_ENC_REG_LIST_RI(id) - /*DCN3_1_RDPCSTX_REG_LIST(0),*/ - /*DCN3_1_RDPCSTX_REG_LIST(1),*/ - /*DCN3_1_RDPCSTX_REG_LIST(2),*/ - /*DCN3_1_RDPCSTX_REG_LIST(3),*/ - -static struct dcn31_hpo_dp_link_encoder_registers hpo_dp_link_enc_regs[2]; - -static const struct dcn31_hpo_dp_link_encoder_shift hpo_dp_le_shift = { - DCN3_2_HPO_DP_LINK_ENC_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn31_hpo_dp_link_encoder_mask hpo_dp_le_mask = { - DCN3_2_HPO_DP_LINK_ENC_MASK_SH_LIST(_MASK) -}; - -#define dpp_regs_init(id)\ - DPP_REG_LIST_DCN30_COMMON_RI(id) - -static struct dcn3_dpp_registers dpp_regs[4]; - -static const struct dcn3_dpp_shift tf_shift = { - DPP_REG_LIST_SH_MASK_DCN30_COMMON(__SHIFT) -}; - -static const struct dcn3_dpp_mask tf_mask = { - DPP_REG_LIST_SH_MASK_DCN30_COMMON(_MASK) -}; - - -#define opp_regs_init(id)\ - OPP_REG_LIST_DCN30_RI(id) - -static struct dcn20_opp_registers opp_regs[4]; - -static const struct dcn20_opp_shift opp_shift = { - OPP_MASK_SH_LIST_DCN20(__SHIFT) -}; - -static const struct dcn20_opp_mask opp_mask = { - OPP_MASK_SH_LIST_DCN20(_MASK) -}; - -#define aux_engine_regs_init(id) \ - ( \ - AUX_COMMON_REG_LIST0_RI(id), SR_ARR_INIT(AUXN_IMPCAL, id, 0), \ - SR_ARR_INIT(AUXP_IMPCAL, id, 0), \ - SR_ARR_INIT(AUX_RESET_MASK, id, DP_AUX0_AUX_CONTROL__AUX_RESET_MASK), \ - SR_ARR_INIT(AUX_RESET_MASK, id, DP_AUX0_AUX_CONTROL__AUX_RESET_MASK)\ - ) - -static struct dce110_aux_registers aux_engine_regs[5]; - -static const struct dce110_aux_registers_shift aux_shift = { - DCN_AUX_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce110_aux_registers_mask aux_mask = { - DCN_AUX_MASK_SH_LIST(_MASK) -}; - -#define dwbc_regs_dcn3_init(id)\ - DWBC_COMMON_REG_LIST_DCN30_RI(id) - -static struct dcn30_dwbc_registers dwbc30_regs[1]; - -static const struct dcn30_dwbc_shift dwbc30_shift = { - DWBC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dcn30_dwbc_mask dwbc30_mask = { - DWBC_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -#define mcif_wb_regs_dcn3_init(id)\ - MCIF_WB_COMMON_REG_LIST_DCN32_RI(id) - -static struct dcn30_mmhubbub_registers mcif_wb30_regs[1]; - -static const struct dcn30_mmhubbub_shift mcif_wb30_shift = { - MCIF_WB_COMMON_MASK_SH_LIST_DCN32(__SHIFT) -}; - -static const struct dcn30_mmhubbub_mask mcif_wb30_mask = { - MCIF_WB_COMMON_MASK_SH_LIST_DCN32(_MASK) -}; - -#define dsc_regsDCN20_init(id)\ - DSC_REG_LIST_DCN20_RI(id) - -static struct dcn20_dsc_registers dsc_regs[4]; - -static const struct dcn20_dsc_shift dsc_shift = { - DSC_REG_LIST_SH_MASK_DCN20(__SHIFT) -}; - -static const struct dcn20_dsc_mask dsc_mask = { - DSC_REG_LIST_SH_MASK_DCN20(_MASK) -}; - -static struct dcn30_mpc_registers mpc_regs; -#define dcn_mpc_regs_init()\ - MPC_REG_LIST_DCN3_2_RI(0),\ - MPC_REG_LIST_DCN3_2_RI(1),\ - MPC_REG_LIST_DCN3_2_RI(2),\ - MPC_REG_LIST_DCN3_2_RI(3),\ - MPC_OUT_MUX_REG_LIST_DCN3_0_RI(0),\ - MPC_OUT_MUX_REG_LIST_DCN3_0_RI(1),\ - MPC_OUT_MUX_REG_LIST_DCN3_0_RI(2),\ - MPC_OUT_MUX_REG_LIST_DCN3_0_RI(3),\ - MPC_DWB_MUX_REG_LIST_DCN3_0_RI(0) - -static const struct dcn30_mpc_shift mpc_shift = { - MPC_COMMON_MASK_SH_LIST_DCN32(__SHIFT) -}; - -static const struct dcn30_mpc_mask mpc_mask = { - MPC_COMMON_MASK_SH_LIST_DCN32(_MASK) -}; - -#define optc_regs_init(id)\ - OPTC_COMMON_REG_LIST_DCN3_2_RI(id) - -static struct dcn_optc_registers optc_regs[4]; - -static const struct dcn_optc_shift optc_shift = { - OPTC_COMMON_MASK_SH_LIST_DCN3_2(__SHIFT) -}; - -static const struct dcn_optc_mask optc_mask = { - OPTC_COMMON_MASK_SH_LIST_DCN3_2(_MASK) -}; - -#define hubp_regs_init(id) \ - HUBP_REG_LIST_DCN32_RI(id) - -static struct dcn_hubp2_registers hubp_regs[4]; - -static const struct dcn_hubp2_shift hubp_shift = { - HUBP_MASK_SH_LIST_DCN32(__SHIFT) -}; - -static const struct dcn_hubp2_mask hubp_mask = { - HUBP_MASK_SH_LIST_DCN32(_MASK) -}; - -static struct dcn_hubbub_registers hubbub_reg; -#define hubbub_reg_init()\ - HUBBUB_REG_LIST_DCN32_RI(0) - -static const struct dcn_hubbub_shift hubbub_shift = { - HUBBUB_MASK_SH_LIST_DCN32(__SHIFT) -}; - -static const struct dcn_hubbub_mask hubbub_mask = { - HUBBUB_MASK_SH_LIST_DCN32(_MASK) -}; - -static struct dccg_registers dccg_regs; - -#define dccg_regs_init()\ - DCCG_REG_LIST_DCN32_RI() - -static const struct dccg_shift dccg_shift = { - DCCG_MASK_SH_LIST_DCN32(__SHIFT) -}; - -static const struct dccg_mask dccg_mask = { - DCCG_MASK_SH_LIST_DCN32(_MASK) -}; - - -#define SRII2(reg_name_pre, reg_name_post, id)\ - .reg_name_pre ## _ ## reg_name_post[id] = BASE(reg ## reg_name_pre \ - ## id ## _ ## reg_name_post ## _BASE_IDX) + \ - reg ## reg_name_pre ## id ## _ ## reg_name_post - - -#define HWSEQ_DCN32_REG_LIST()\ - SR(DCHUBBUB_GLOBAL_TIMER_CNTL), \ - SR(DIO_MEM_PWR_CTRL), \ - SR(ODM_MEM_PWR_CTRL3), \ - SR(MMHUBBUB_MEM_PWR_CNTL), \ - SR(DCCG_GATE_DISABLE_CNTL), \ - SR(DCCG_GATE_DISABLE_CNTL2), \ - SR(DCFCLK_CNTL),\ - SR(DC_MEM_GLOBAL_PWR_REQ_CNTL), \ - SRII(PIXEL_RATE_CNTL, OTG, 0), \ - SRII(PIXEL_RATE_CNTL, OTG, 1),\ - SRII(PIXEL_RATE_CNTL, OTG, 2),\ - SRII(PIXEL_RATE_CNTL, OTG, 3),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 0),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 1),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 2),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 3),\ - SR(MICROSECOND_TIME_BASE_DIV), \ - SR(MILLISECOND_TIME_BASE_DIV), \ - SR(DISPCLK_FREQ_CHANGE_CNTL), \ - SR(RBBMIF_TIMEOUT_DIS), \ - SR(RBBMIF_TIMEOUT_DIS_2), \ - SR(DCHUBBUB_CRC_CTRL), \ - SR(DPP_TOP0_DPP_CRC_CTRL), \ - SR(DPP_TOP0_DPP_CRC_VAL_B_A), \ - SR(DPP_TOP0_DPP_CRC_VAL_R_G), \ - SR(MPC_CRC_CTRL), \ - SR(MPC_CRC_RESULT_GB), \ - SR(MPC_CRC_RESULT_C), \ - SR(MPC_CRC_RESULT_AR), \ - SR(DOMAIN0_PG_CONFIG), \ - SR(DOMAIN1_PG_CONFIG), \ - SR(DOMAIN2_PG_CONFIG), \ - SR(DOMAIN3_PG_CONFIG), \ - SR(DOMAIN16_PG_CONFIG), \ - SR(DOMAIN17_PG_CONFIG), \ - SR(DOMAIN18_PG_CONFIG), \ - SR(DOMAIN19_PG_CONFIG), \ - SR(DOMAIN0_PG_STATUS), \ - SR(DOMAIN1_PG_STATUS), \ - SR(DOMAIN2_PG_STATUS), \ - SR(DOMAIN3_PG_STATUS), \ - SR(DOMAIN16_PG_STATUS), \ - SR(DOMAIN17_PG_STATUS), \ - SR(DOMAIN18_PG_STATUS), \ - SR(DOMAIN19_PG_STATUS), \ - SR(D1VGA_CONTROL), \ - SR(D2VGA_CONTROL), \ - SR(D3VGA_CONTROL), \ - SR(D4VGA_CONTROL), \ - SR(D5VGA_CONTROL), \ - SR(D6VGA_CONTROL), \ - SR(DC_IP_REQUEST_CNTL), \ - SR(AZALIA_AUDIO_DTO), \ - SR(AZALIA_CONTROLLER_CLOCK_GATING) - -static struct dce_hwseq_registers hwseq_reg; - -#define hwseq_reg_init()\ - HWSEQ_DCN32_REG_LIST() - -#define HWSEQ_DCN32_MASK_SH_LIST(mask_sh)\ - HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ - HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \ - HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN19_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN19_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN16_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN17_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN18_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN19_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \ - HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh), \ - HWS_SF(, HPO_TOP_CLOCK_CONTROL, HPO_HDMISTREAMCLK_G_GATE_DIS, mask_sh), \ - HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_UNASSIGNED_PWR_MODE, mask_sh), \ - HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_VBLANK_PWR_MODE, mask_sh), \ - HWS_SF(, MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, mask_sh) - -static const struct dce_hwseq_shift hwseq_shift = { - HWSEQ_DCN32_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_hwseq_mask hwseq_mask = { - HWSEQ_DCN32_MASK_SH_LIST(_MASK) -}; -#define vmid_regs_init(id)\ - DCN20_VMID_REG_LIST_RI(id) - -static struct dcn_vmid_registers vmid_regs[16]; - -static const struct dcn20_vmid_shift vmid_shifts = { - DCN20_VMID_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn20_vmid_mask vmid_masks = { - DCN20_VMID_MASK_SH_LIST(_MASK) -}; - -static const struct resource_caps res_cap_dcn321 = { - .num_timing_generator = 4, - .num_opp = 4, - .num_video_plane = 4, - .num_audio = 5, - .num_stream_encoder = 5, - .num_hpo_dp_stream_encoder = 4, - .num_hpo_dp_link_encoder = 2, - .num_pll = 5, - .num_dwb = 1, - .num_ddc = 5, - .num_vmid = 16, - .num_mpc_3dlut = 4, - .num_dsc = 4, -}; - -static const struct dc_plane_cap plane_cap = { - .type = DC_PLANE_TYPE_DCN_UNIVERSAL, - .per_pixel_alpha = true, - - .pixel_format_support = { - .argb8888 = true, - .nv12 = true, - .fp16 = true, - .p010 = true, - .ayuv = false, - }, - - .max_upscale_factor = { - .argb8888 = 16000, - .nv12 = 16000, - .fp16 = 16000 - }, - - // 6:1 downscaling ratio: 1000/6 = 166.666 - .max_downscale_factor = { - .argb8888 = 167, - .nv12 = 167, - .fp16 = 167 - }, - 64, - 64 -}; - -static const struct dc_debug_options debug_defaults_drv = { - .disable_dmcu = true, - .force_abm_enable = false, - .timing_trace = false, - .clock_trace = true, - .disable_pplib_clock_request = false, - .pipe_split_policy = MPC_SPLIT_AVOID, - .force_single_disp_pipe_split = false, - .disable_dcc = DCC_ENABLE, - .vsr_support = true, - .performance_trace = false, - .max_downscale_src_width = 7680,/*upto 8K*/ - .disable_pplib_wm_range = false, - .scl_reset_length10 = true, - .sanity_checks = false, - .underflow_assert_delay_us = 0xFFFFFFFF, - .dwb_fi_phase = -1, // -1 = disable, - .dmub_command_table = true, - .enable_mem_low_power = { - .bits = { - .vga = false, - .i2c = false, - .dmcu = false, // This is previously known to cause hang on S3 cycles if enabled - .dscl = false, - .cm = false, - .mpc = false, - .optc = true, - } - }, - .use_max_lb = true, - .force_disable_subvp = false, - .exit_idle_opt_for_cursor_updates = true, - .enable_single_display_2to1_odm_policy = true, - - /*must match enable_single_display_2to1_odm_policy to support dynamic ODM transitions*/ - .enable_double_buffered_dsc_pg_support = true, - .enable_dp_dig_pixel_rate_div_policy = 1, - .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, - .override_dispclk_programming = true, - .disable_fpo_optimizations = false, - .fpo_vactive_margin_us = 2000, // 2000us - .disable_fpo_vactive = false, - .disable_boot_optimizations = false, - .disable_subvp_high_refresh = false, - .fpo_vactive_min_active_margin_us = 200, - .fpo_vactive_max_blank_us = 1000, - .enable_legacy_fast_update = false, - .disable_dc_mode_overwrite = true, - .using_dml2 = false, -}; - -static struct dce_aux *dcn321_aux_engine_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct aux_engine_dce110 *aux_engine = - kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); - - if (!aux_engine) - return NULL; - -#undef REG_STRUCT -#define REG_STRUCT aux_engine_regs - aux_engine_regs_init(0), - aux_engine_regs_init(1), - aux_engine_regs_init(2), - aux_engine_regs_init(3), - aux_engine_regs_init(4); - - dce110_aux_engine_construct(aux_engine, ctx, inst, - SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, - &aux_engine_regs[inst], - &aux_mask, - &aux_shift, - ctx->dc->caps.extended_aux_timeout_support); - - return &aux_engine->base; -} -#define i2c_inst_regs_init(id)\ - I2C_HW_ENGINE_COMMON_REG_LIST_DCN30_RI(id) - -static struct dce_i2c_registers i2c_hw_regs[5]; - -static const struct dce_i2c_shift i2c_shifts = { - I2C_COMMON_MASK_SH_LIST_DCN30(__SHIFT) -}; - -static const struct dce_i2c_mask i2c_masks = { - I2C_COMMON_MASK_SH_LIST_DCN30(_MASK) -}; - -static struct dce_i2c_hw *dcn321_i2c_hw_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dce_i2c_hw *dce_i2c_hw = - kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); - - if (!dce_i2c_hw) - return NULL; - -#undef REG_STRUCT -#define REG_STRUCT i2c_hw_regs - i2c_inst_regs_init(1), - i2c_inst_regs_init(2), - i2c_inst_regs_init(3), - i2c_inst_regs_init(4), - i2c_inst_regs_init(5); - - dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst, - &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); - - return dce_i2c_hw; -} - -static struct clock_source *dcn321_clock_source_create( - struct dc_context *ctx, - struct dc_bios *bios, - enum clock_source_id id, - const struct dce110_clk_src_regs *regs, - bool dp_clk_src) -{ - struct dce110_clk_src *clk_src = - kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); - - if (!clk_src) - return NULL; - - if (dcn31_clk_src_construct(clk_src, ctx, bios, id, - regs, &cs_shift, &cs_mask)) { - clk_src->base.dp_clk_src = dp_clk_src; - return &clk_src->base; - } - - kfree(clk_src); - BREAK_TO_DEBUGGER(); - return NULL; -} - -static struct hubbub *dcn321_hubbub_create(struct dc_context *ctx) -{ - int i; - - struct dcn20_hubbub *hubbub2 = kzalloc(sizeof(struct dcn20_hubbub), - GFP_KERNEL); - - if (!hubbub2) - return NULL; - -#undef REG_STRUCT -#define REG_STRUCT hubbub_reg - hubbub_reg_init(); - -#undef REG_STRUCT -#define REG_STRUCT vmid_regs - vmid_regs_init(0), - vmid_regs_init(1), - vmid_regs_init(2), - vmid_regs_init(3), - vmid_regs_init(4), - vmid_regs_init(5), - vmid_regs_init(6), - vmid_regs_init(7), - vmid_regs_init(8), - vmid_regs_init(9), - vmid_regs_init(10), - vmid_regs_init(11), - vmid_regs_init(12), - vmid_regs_init(13), - vmid_regs_init(14), - vmid_regs_init(15); - - hubbub32_construct(hubbub2, ctx, - &hubbub_reg, - &hubbub_shift, - &hubbub_mask, - ctx->dc->dml.ip.det_buffer_size_kbytes, - ctx->dc->dml.ip.pixel_chunk_size_kbytes, - ctx->dc->dml.ip.config_return_buffer_size_in_kbytes); - - - for (i = 0; i < res_cap_dcn321.num_vmid; i++) { - struct dcn20_vmid *vmid = &hubbub2->vmid[i]; - - vmid->ctx = ctx; - - vmid->regs = &vmid_regs[i]; - vmid->shifts = &vmid_shifts; - vmid->masks = &vmid_masks; - } - - return &hubbub2->base; -} - -static struct hubp *dcn321_hubp_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn20_hubp *hubp2 = - kzalloc(sizeof(struct dcn20_hubp), GFP_KERNEL); - - if (!hubp2) - return NULL; - -#undef REG_STRUCT -#define REG_STRUCT hubp_regs - hubp_regs_init(0), - hubp_regs_init(1), - hubp_regs_init(2), - hubp_regs_init(3); - - if (hubp32_construct(hubp2, ctx, inst, - &hubp_regs[inst], &hubp_shift, &hubp_mask)) - return &hubp2->base; - - BREAK_TO_DEBUGGER(); - kfree(hubp2); - return NULL; -} - -static void dcn321_dpp_destroy(struct dpp **dpp) -{ - kfree(TO_DCN30_DPP(*dpp)); - *dpp = NULL; -} - -static struct dpp *dcn321_dpp_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn3_dpp *dpp3 = - kzalloc(sizeof(struct dcn3_dpp), GFP_KERNEL); - - if (!dpp3) - return NULL; - -#undef REG_STRUCT -#define REG_STRUCT dpp_regs - dpp_regs_init(0), - dpp_regs_init(1), - dpp_regs_init(2), - dpp_regs_init(3); - - if (dpp32_construct(dpp3, ctx, inst, - &dpp_regs[inst], &tf_shift, &tf_mask)) - return &dpp3->base; - - BREAK_TO_DEBUGGER(); - kfree(dpp3); - return NULL; -} - -static struct mpc *dcn321_mpc_create( - struct dc_context *ctx, - int num_mpcc, - int num_rmu) -{ - struct dcn30_mpc *mpc30 = kzalloc(sizeof(struct dcn30_mpc), - GFP_KERNEL); - - if (!mpc30) - return NULL; - -#undef REG_STRUCT -#define REG_STRUCT mpc_regs - dcn_mpc_regs_init(); - - dcn32_mpc_construct(mpc30, ctx, - &mpc_regs, - &mpc_shift, - &mpc_mask, - num_mpcc, - num_rmu); - - return &mpc30->base; -} - -static struct output_pixel_processor *dcn321_opp_create( - struct dc_context *ctx, uint32_t inst) -{ - struct dcn20_opp *opp2 = - kzalloc(sizeof(struct dcn20_opp), GFP_KERNEL); - - if (!opp2) { - BREAK_TO_DEBUGGER(); - return NULL; - } - -#undef REG_STRUCT -#define REG_STRUCT opp_regs - opp_regs_init(0), - opp_regs_init(1), - opp_regs_init(2), - opp_regs_init(3); - - dcn20_opp_construct(opp2, ctx, inst, - &opp_regs[inst], &opp_shift, &opp_mask); - return &opp2->base; -} - - -static struct timing_generator *dcn321_timing_generator_create( - struct dc_context *ctx, - uint32_t instance) -{ - struct optc *tgn10 = - kzalloc(sizeof(struct optc), GFP_KERNEL); - - if (!tgn10) - return NULL; - -#undef REG_STRUCT -#define REG_STRUCT optc_regs - optc_regs_init(0), - optc_regs_init(1), - optc_regs_init(2), - optc_regs_init(3); - - tgn10->base.inst = instance; - tgn10->base.ctx = ctx; - - tgn10->tg_regs = &optc_regs[instance]; - tgn10->tg_shift = &optc_shift; - tgn10->tg_mask = &optc_mask; - - dcn32_timing_generator_init(tgn10); - - return &tgn10->base; -} - -static const struct encoder_feature_support link_enc_feature = { - .max_hdmi_deep_color = COLOR_DEPTH_121212, - .max_hdmi_pixel_clock = 600000, - .hdmi_ycbcr420_supported = true, - .dp_ycbcr420_supported = true, - .fec_supported = true, - .flags.bits.IS_HBR2_CAPABLE = true, - .flags.bits.IS_HBR3_CAPABLE = true, - .flags.bits.IS_TPS3_CAPABLE = true, - .flags.bits.IS_TPS4_CAPABLE = true -}; - -static struct link_encoder *dcn321_link_encoder_create( - struct dc_context *ctx, - const struct encoder_init_data *enc_init_data) -{ - struct dcn20_link_encoder *enc20 = - kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); - - if (!enc20) - return NULL; - -#undef REG_STRUCT -#define REG_STRUCT link_enc_aux_regs - aux_regs_init(0), - aux_regs_init(1), - aux_regs_init(2), - aux_regs_init(3), - aux_regs_init(4); - -#undef REG_STRUCT -#define REG_STRUCT link_enc_hpd_regs - hpd_regs_init(0), - hpd_regs_init(1), - hpd_regs_init(2), - hpd_regs_init(3), - hpd_regs_init(4); - -#undef REG_STRUCT -#define REG_STRUCT link_enc_regs - link_regs_init(0, A), - link_regs_init(1, B), - link_regs_init(2, C), - link_regs_init(3, D), - link_regs_init(4, E); - - dcn321_link_encoder_construct(enc20, - enc_init_data, - &link_enc_feature, - &link_enc_regs[enc_init_data->transmitter], - &link_enc_aux_regs[enc_init_data->channel - 1], - &link_enc_hpd_regs[enc_init_data->hpd_source], - &le_shift, - &le_mask); - - return &enc20->enc10.base; -} - -static void read_dce_straps( - struct dc_context *ctx, - struct resource_straps *straps) -{ - generic_reg_get(ctx, ctx->dcn_reg_offsets[regDC_PINSTRAPS_BASE_IDX] + regDC_PINSTRAPS, - FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio); - -} - -static struct audio *dcn321_create_audio( - struct dc_context *ctx, unsigned int inst) -{ - -#undef REG_STRUCT -#define REG_STRUCT audio_regs - audio_regs_init(0), - audio_regs_init(1), - audio_regs_init(2), - audio_regs_init(3), - audio_regs_init(4); - - return dce_audio_create(ctx, inst, - &audio_regs[inst], &audio_shift, &audio_mask); -} - -static struct vpg *dcn321_vpg_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn30_vpg *vpg3 = kzalloc(sizeof(struct dcn30_vpg), GFP_KERNEL); - - if (!vpg3) - return NULL; - -#undef REG_STRUCT -#define REG_STRUCT vpg_regs - vpg_regs_init(0), - vpg_regs_init(1), - vpg_regs_init(2), - vpg_regs_init(3), - vpg_regs_init(4), - vpg_regs_init(5), - vpg_regs_init(6), - vpg_regs_init(7), - vpg_regs_init(8), - vpg_regs_init(9); - - vpg3_construct(vpg3, ctx, inst, - &vpg_regs[inst], - &vpg_shift, - &vpg_mask); - - return &vpg3->base; -} - -static struct afmt *dcn321_afmt_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn30_afmt *afmt3 = kzalloc(sizeof(struct dcn30_afmt), GFP_KERNEL); - - if (!afmt3) - return NULL; - -#undef REG_STRUCT -#define REG_STRUCT afmt_regs - afmt_regs_init(0), - afmt_regs_init(1), - afmt_regs_init(2), - afmt_regs_init(3), - afmt_regs_init(4), - afmt_regs_init(5); - - afmt3_construct(afmt3, ctx, inst, - &afmt_regs[inst], - &afmt_shift, - &afmt_mask); - - return &afmt3->base; -} - -static struct apg *dcn321_apg_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn31_apg *apg31 = kzalloc(sizeof(struct dcn31_apg), GFP_KERNEL); - - if (!apg31) - return NULL; - -#undef REG_STRUCT -#define REG_STRUCT apg_regs - apg_regs_init(0), - apg_regs_init(1), - apg_regs_init(2), - apg_regs_init(3); - - apg31_construct(apg31, ctx, inst, - &apg_regs[inst], - &apg_shift, - &apg_mask); - - return &apg31->base; -} - -static struct stream_encoder *dcn321_stream_encoder_create( - enum engine_id eng_id, - struct dc_context *ctx) -{ - struct dcn10_stream_encoder *enc1; - struct vpg *vpg; - struct afmt *afmt; - int vpg_inst; - int afmt_inst; - - /* Mapping of VPG, AFMT, DME register blocks to DIO block instance */ - if (eng_id <= ENGINE_ID_DIGF) { - vpg_inst = eng_id; - afmt_inst = eng_id; - } else - return NULL; - - enc1 = kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL); - vpg = dcn321_vpg_create(ctx, vpg_inst); - afmt = dcn321_afmt_create(ctx, afmt_inst); - - if (!enc1 || !vpg || !afmt) { - kfree(enc1); - kfree(vpg); - kfree(afmt); - return NULL; - } - -#undef REG_STRUCT -#define REG_STRUCT stream_enc_regs - stream_enc_regs_init(0), - stream_enc_regs_init(1), - stream_enc_regs_init(2), - stream_enc_regs_init(3), - stream_enc_regs_init(4); - - dcn32_dio_stream_encoder_construct(enc1, ctx, ctx->dc_bios, - eng_id, vpg, afmt, - &stream_enc_regs[eng_id], - &se_shift, &se_mask); - - return &enc1->base; -} - -static struct hpo_dp_stream_encoder *dcn321_hpo_dp_stream_encoder_create( - enum engine_id eng_id, - struct dc_context *ctx) -{ - struct dcn31_hpo_dp_stream_encoder *hpo_dp_enc31; - struct vpg *vpg; - struct apg *apg; - uint32_t hpo_dp_inst; - uint32_t vpg_inst; - uint32_t apg_inst; - - ASSERT((eng_id >= ENGINE_ID_HPO_DP_0) && (eng_id <= ENGINE_ID_HPO_DP_3)); - hpo_dp_inst = eng_id - ENGINE_ID_HPO_DP_0; - - /* Mapping of VPG register blocks to HPO DP block instance: - * VPG[6] -> HPO_DP[0] - * VPG[7] -> HPO_DP[1] - * VPG[8] -> HPO_DP[2] - * VPG[9] -> HPO_DP[3] - */ - vpg_inst = hpo_dp_inst + 6; - - /* Mapping of APG register blocks to HPO DP block instance: - * APG[0] -> HPO_DP[0] - * APG[1] -> HPO_DP[1] - * APG[2] -> HPO_DP[2] - * APG[3] -> HPO_DP[3] - */ - apg_inst = hpo_dp_inst; - - /* allocate HPO stream encoder and create VPG sub-block */ - hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_stream_encoder), GFP_KERNEL); - vpg = dcn321_vpg_create(ctx, vpg_inst); - apg = dcn321_apg_create(ctx, apg_inst); - - if (!hpo_dp_enc31 || !vpg || !apg) { - kfree(hpo_dp_enc31); - kfree(vpg); - kfree(apg); - return NULL; - } - -#undef REG_STRUCT -#define REG_STRUCT hpo_dp_stream_enc_regs - hpo_dp_stream_encoder_reg_init(0), - hpo_dp_stream_encoder_reg_init(1), - hpo_dp_stream_encoder_reg_init(2), - hpo_dp_stream_encoder_reg_init(3); - - dcn31_hpo_dp_stream_encoder_construct(hpo_dp_enc31, ctx, ctx->dc_bios, - hpo_dp_inst, eng_id, vpg, apg, - &hpo_dp_stream_enc_regs[hpo_dp_inst], - &hpo_dp_se_shift, &hpo_dp_se_mask); - - return &hpo_dp_enc31->base; -} - -static struct hpo_dp_link_encoder *dcn321_hpo_dp_link_encoder_create( - uint8_t inst, - struct dc_context *ctx) -{ - struct dcn31_hpo_dp_link_encoder *hpo_dp_enc31; - - /* allocate HPO link encoder */ - hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_link_encoder), GFP_KERNEL); - -#undef REG_STRUCT -#define REG_STRUCT hpo_dp_link_enc_regs - hpo_dp_link_encoder_reg_init(0), - hpo_dp_link_encoder_reg_init(1); - - hpo_dp_link_encoder32_construct(hpo_dp_enc31, ctx, inst, - &hpo_dp_link_enc_regs[inst], - &hpo_dp_le_shift, &hpo_dp_le_mask); - - return &hpo_dp_enc31->base; -} - -static struct dce_hwseq *dcn321_hwseq_create( - struct dc_context *ctx) -{ - struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); - -#undef REG_STRUCT -#define REG_STRUCT hwseq_reg - hwseq_reg_init(); - - if (hws) { - hws->ctx = ctx; - hws->regs = &hwseq_reg; - hws->shifts = &hwseq_shift; - hws->masks = &hwseq_mask; - } - return hws; -} -static const struct resource_create_funcs res_create_funcs = { - .read_dce_straps = read_dce_straps, - .create_audio = dcn321_create_audio, - .create_stream_encoder = dcn321_stream_encoder_create, - .create_hpo_dp_stream_encoder = dcn321_hpo_dp_stream_encoder_create, - .create_hpo_dp_link_encoder = dcn321_hpo_dp_link_encoder_create, - .create_hwseq = dcn321_hwseq_create, -}; - -static void dcn321_resource_destruct(struct dcn321_resource_pool *pool) -{ - unsigned int i; - - for (i = 0; i < pool->base.stream_enc_count; i++) { - if (pool->base.stream_enc[i] != NULL) { - if (pool->base.stream_enc[i]->vpg != NULL) { - kfree(DCN30_VPG_FROM_VPG(pool->base.stream_enc[i]->vpg)); - pool->base.stream_enc[i]->vpg = NULL; - } - if (pool->base.stream_enc[i]->afmt != NULL) { - kfree(DCN30_AFMT_FROM_AFMT(pool->base.stream_enc[i]->afmt)); - pool->base.stream_enc[i]->afmt = NULL; - } - kfree(DCN10STRENC_FROM_STRENC(pool->base.stream_enc[i])); - pool->base.stream_enc[i] = NULL; - } - } - - for (i = 0; i < pool->base.hpo_dp_stream_enc_count; i++) { - if (pool->base.hpo_dp_stream_enc[i] != NULL) { - if (pool->base.hpo_dp_stream_enc[i]->vpg != NULL) { - kfree(DCN30_VPG_FROM_VPG(pool->base.hpo_dp_stream_enc[i]->vpg)); - pool->base.hpo_dp_stream_enc[i]->vpg = NULL; - } - if (pool->base.hpo_dp_stream_enc[i]->apg != NULL) { - kfree(DCN31_APG_FROM_APG(pool->base.hpo_dp_stream_enc[i]->apg)); - pool->base.hpo_dp_stream_enc[i]->apg = NULL; - } - kfree(DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(pool->base.hpo_dp_stream_enc[i])); - pool->base.hpo_dp_stream_enc[i] = NULL; - } - } - - for (i = 0; i < pool->base.hpo_dp_link_enc_count; i++) { - if (pool->base.hpo_dp_link_enc[i] != NULL) { - kfree(DCN3_1_HPO_DP_LINK_ENC_FROM_HPO_LINK_ENC(pool->base.hpo_dp_link_enc[i])); - pool->base.hpo_dp_link_enc[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_dsc; i++) { - if (pool->base.dscs[i] != NULL) - dcn20_dsc_destroy(&pool->base.dscs[i]); - } - - if (pool->base.mpc != NULL) { - kfree(TO_DCN20_MPC(pool->base.mpc)); - pool->base.mpc = NULL; - } - if (pool->base.hubbub != NULL) { - kfree(TO_DCN20_HUBBUB(pool->base.hubbub)); - pool->base.hubbub = NULL; - } - for (i = 0; i < pool->base.pipe_count; i++) { - if (pool->base.dpps[i] != NULL) - dcn321_dpp_destroy(&pool->base.dpps[i]); - - if (pool->base.ipps[i] != NULL) - pool->base.ipps[i]->funcs->ipp_destroy(&pool->base.ipps[i]); - - if (pool->base.hubps[i] != NULL) { - kfree(TO_DCN20_HUBP(pool->base.hubps[i])); - pool->base.hubps[i] = NULL; - } - - if (pool->base.irqs != NULL) - dal_irq_service_destroy(&pool->base.irqs); - } - - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - if (pool->base.engines[i] != NULL) - dce110_engine_destroy(&pool->base.engines[i]); - if (pool->base.hw_i2cs[i] != NULL) { - kfree(pool->base.hw_i2cs[i]); - pool->base.hw_i2cs[i] = NULL; - } - if (pool->base.sw_i2cs[i] != NULL) { - kfree(pool->base.sw_i2cs[i]); - pool->base.sw_i2cs[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_opp; i++) { - if (pool->base.opps[i] != NULL) - pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]); - } - - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - if (pool->base.timing_generators[i] != NULL) { - kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i])); - pool->base.timing_generators[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_dwb; i++) { - if (pool->base.dwbc[i] != NULL) { - kfree(TO_DCN30_DWBC(pool->base.dwbc[i])); - pool->base.dwbc[i] = NULL; - } - if (pool->base.mcif_wb[i] != NULL) { - kfree(TO_DCN30_MMHUBBUB(pool->base.mcif_wb[i])); - pool->base.mcif_wb[i] = NULL; - } - } - - for (i = 0; i < pool->base.audio_count; i++) { - if (pool->base.audios[i]) - dce_aud_destroy(&pool->base.audios[i]); - } - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] != NULL) { - dcn20_clock_source_destroy(&pool->base.clock_sources[i]); - pool->base.clock_sources[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_mpc_3dlut; i++) { - if (pool->base.mpc_lut[i] != NULL) { - dc_3dlut_func_release(pool->base.mpc_lut[i]); - pool->base.mpc_lut[i] = NULL; - } - if (pool->base.mpc_shaper[i] != NULL) { - dc_transfer_func_release(pool->base.mpc_shaper[i]); - pool->base.mpc_shaper[i] = NULL; - } - } - - if (pool->base.dp_clock_source != NULL) { - dcn20_clock_source_destroy(&pool->base.dp_clock_source); - pool->base.dp_clock_source = NULL; - } - - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - if (pool->base.multiple_abms[i] != NULL) - dce_abm_destroy(&pool->base.multiple_abms[i]); - } - - if (pool->base.psr != NULL) - dmub_psr_destroy(&pool->base.psr); - - if (pool->base.dccg != NULL) - dcn_dccg_destroy(&pool->base.dccg); - - if (pool->base.oem_device != NULL) { - struct dc *dc = pool->base.oem_device->ctx->dc; - - dc->link_srv->destroy_ddc_service(&pool->base.oem_device); - } -} - - -static bool dcn321_dwbc_create(struct dc_context *ctx, struct resource_pool *pool) -{ - int i; - uint32_t dwb_count = pool->res_cap->num_dwb; - - for (i = 0; i < dwb_count; i++) { - struct dcn30_dwbc *dwbc30 = kzalloc(sizeof(struct dcn30_dwbc), - GFP_KERNEL); - - if (!dwbc30) { - dm_error("DC: failed to create dwbc30!\n"); - return false; - } - -#undef REG_STRUCT -#define REG_STRUCT dwbc30_regs - dwbc_regs_dcn3_init(0); - - dcn30_dwbc_construct(dwbc30, ctx, - &dwbc30_regs[i], - &dwbc30_shift, - &dwbc30_mask, - i); - - pool->dwbc[i] = &dwbc30->base; - } - return true; -} - -static bool dcn321_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool) -{ - int i; - uint32_t dwb_count = pool->res_cap->num_dwb; - - for (i = 0; i < dwb_count; i++) { - struct dcn30_mmhubbub *mcif_wb30 = kzalloc(sizeof(struct dcn30_mmhubbub), - GFP_KERNEL); - - if (!mcif_wb30) { - dm_error("DC: failed to create mcif_wb30!\n"); - return false; - } - -#undef REG_STRUCT -#define REG_STRUCT mcif_wb30_regs - mcif_wb_regs_dcn3_init(0); - - dcn32_mmhubbub_construct(mcif_wb30, ctx, - &mcif_wb30_regs[i], - &mcif_wb30_shift, - &mcif_wb30_mask, - i); - - pool->mcif_wb[i] = &mcif_wb30->base; - } - return true; -} - -static struct display_stream_compressor *dcn321_dsc_create( - struct dc_context *ctx, uint32_t inst) -{ - struct dcn20_dsc *dsc = - kzalloc(sizeof(struct dcn20_dsc), GFP_KERNEL); - - if (!dsc) { - BREAK_TO_DEBUGGER(); - return NULL; - } - -#undef REG_STRUCT -#define REG_STRUCT dsc_regs - dsc_regsDCN20_init(0), - dsc_regsDCN20_init(1), - dsc_regsDCN20_init(2), - dsc_regsDCN20_init(3); - - dsc2_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask); - - dsc->max_image_width = 6016; - - return &dsc->base; -} - -static void dcn321_destroy_resource_pool(struct resource_pool **pool) -{ - struct dcn321_resource_pool *dcn321_pool = TO_DCN321_RES_POOL(*pool); - - dcn321_resource_destruct(dcn321_pool); - kfree(dcn321_pool); - *pool = NULL; -} - -static struct dc_cap_funcs cap_funcs = { - .get_dcc_compression_cap = dcn20_get_dcc_compression_cap, - .get_subvp_en = dcn32_subvp_in_use, -}; - -static void dcn321_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) -{ - DC_FP_START(); - dcn321_update_bw_bounding_box_fpu(dc, bw_params); - DC_FP_END(); -} - -static struct resource_funcs dcn321_res_pool_funcs = { - .destroy = dcn321_destroy_resource_pool, - .link_enc_create = dcn321_link_encoder_create, - .link_enc_create_minimal = NULL, - .panel_cntl_create = dcn32_panel_cntl_create, - .validate_bandwidth = dcn32_validate_bandwidth, - .calculate_wm_and_dlg = dcn32_calculate_wm_and_dlg, - .populate_dml_pipes = dcn32_populate_dml_pipes_from_context, - .acquire_free_pipe_as_secondary_dpp_pipe = dcn32_acquire_free_pipe_as_secondary_dpp_pipe, - .acquire_free_pipe_as_secondary_opp_head = dcn32_acquire_free_pipe_as_secondary_opp_head, - .release_pipe = dcn20_release_pipe, - .add_stream_to_ctx = dcn30_add_stream_to_ctx, - .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource, - .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, - .populate_dml_writeback_from_context = dcn30_populate_dml_writeback_from_context, - .set_mcif_arb_params = dcn30_set_mcif_arb_params, - .find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link, - .acquire_post_bldn_3dlut = dcn32_acquire_post_bldn_3dlut, - .release_post_bldn_3dlut = dcn32_release_post_bldn_3dlut, - .update_bw_bounding_box = dcn321_update_bw_bounding_box, - .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, - .update_soc_for_wm_a = dcn30_update_soc_for_wm_a, - .add_phantom_pipes = dcn32_add_phantom_pipes, - .remove_phantom_pipes = dcn32_remove_phantom_pipes, - .retain_phantom_pipes = dcn32_retain_phantom_pipes, - .save_mall_state = dcn32_save_mall_state, - .restore_mall_state = dcn32_restore_mall_state, -}; - -static uint32_t read_pipe_fuses(struct dc_context *ctx) -{ - uint32_t value = REG_READ(CC_DC_PIPE_DIS); - /* DCN321 support max 4 pipes */ - value = value & 0xf; - return value; -} - - -static bool dcn321_resource_construct( - uint8_t num_virtual_links, - struct dc *dc, - struct dcn321_resource_pool *pool) -{ - int i, j; - struct dc_context *ctx = dc->ctx; - struct irq_service_init_data init_data; - struct ddc_service_init_data ddc_init_data = {0}; - uint32_t pipe_fuses = 0; - uint32_t num_pipes = 4; - -#undef REG_STRUCT -#define REG_STRUCT bios_regs - bios_regs_init(); - -#undef REG_STRUCT -#define REG_STRUCT clk_src_regs - clk_src_regs_init(0, A), - clk_src_regs_init(1, B), - clk_src_regs_init(2, C), - clk_src_regs_init(3, D), - clk_src_regs_init(4, E); - -#undef REG_STRUCT -#define REG_STRUCT abm_regs - abm_regs_init(0), - abm_regs_init(1), - abm_regs_init(2), - abm_regs_init(3); - -#undef REG_STRUCT -#define REG_STRUCT dccg_regs - dccg_regs_init(); - - - ctx->dc_bios->regs = &bios_regs; - - pool->base.res_cap = &res_cap_dcn321; - /* max number of pipes for ASIC before checking for pipe fuses */ - num_pipes = pool->base.res_cap->num_timing_generator; - pipe_fuses = read_pipe_fuses(ctx); - - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) - if (pipe_fuses & 1 << i) - num_pipes--; - - if (pipe_fuses & 1) - ASSERT(0); //Unexpected - Pipe 0 should always be fully functional! - - if (pipe_fuses & CC_DC_PIPE_DIS__DC_FULL_DIS_MASK) - ASSERT(0); //Entire DCN is harvested! - - /* within dml lib, initial value is hard coded, if ASIC pipe is fused, the - * value will be changed, update max_num_dpp and max_num_otg for dml. - */ - dcn3_21_ip.max_num_dpp = num_pipes; - dcn3_21_ip.max_num_otg = num_pipes; - - pool->base.funcs = &dcn321_res_pool_funcs; - - /************************************************* - * Resource + asic cap harcoding * - *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; - pool->base.timing_generator_count = num_pipes; - pool->base.pipe_count = num_pipes; - pool->base.mpcc_count = num_pipes; - dc->caps.max_downscale_ratio = 600; - dc->caps.i2c_speed_in_khz = 100; - dc->caps.i2c_speed_in_khz_hdcp = 100; /*1.4 w/a applied by default*/ - /* TODO: Bring max cursor size back to 256 after subvp cursor corruption is fixed*/ - 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 = 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; - - /* 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; - dc->caps.subvp_swath_height_margin_lines = 16; - dc->caps.subvp_pstate_allow_width_us = 20; - dc->caps.subvp_vertical_int_margin_us = 30; - dc->caps.subvp_drr_vblank_start_margin_us = 100; // 100us margin - dc->caps.max_slave_planes = 2; - dc->caps.max_slave_yuv_planes = 2; - dc->caps.max_slave_rgb_planes = 2; - dc->caps.post_blend_color_processing = true; - dc->caps.force_dp_tps4_for_cp2520 = true; - dc->caps.dp_hpo = true; - dc->caps.dp_hdmi21_pcon_support = true; - dc->caps.edp_dsc_support = true; - dc->caps.extended_aux_timeout_support = true; - dc->caps.dmcub_support = true; - dc->caps.max_v_total = (1 << 15) - 1; - - /* Color pipeline capabilities */ - dc->caps.color.dpp.dcn_arch = 1; - dc->caps.color.dpp.input_lut_shared = 0; - dc->caps.color.dpp.icsc = 1; - dc->caps.color.dpp.dgam_ram = 0; // must use gamma_corr - dc->caps.color.dpp.dgam_rom_caps.srgb = 1; - dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1; - dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 1; - dc->caps.color.dpp.dgam_rom_caps.pq = 1; - dc->caps.color.dpp.dgam_rom_caps.hlg = 1; - dc->caps.color.dpp.post_csc = 1; - dc->caps.color.dpp.gamma_corr = 1; - dc->caps.color.dpp.dgam_rom_for_yuv = 0; - - dc->caps.color.dpp.hw_3d_lut = 1; - dc->caps.color.dpp.ogam_ram = 1; - // no OGAM ROM on DCN2 and later ASICs - dc->caps.color.dpp.ogam_rom_caps.srgb = 0; - dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0; - dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0; - dc->caps.color.dpp.ogam_rom_caps.pq = 0; - dc->caps.color.dpp.ogam_rom_caps.hlg = 0; - dc->caps.color.dpp.ocsc = 0; - - dc->caps.color.mpc.gamut_remap = 1; - dc->caps.color.mpc.num_3dluts = pool->base.res_cap->num_mpc_3dlut; //4, configurable to be before or after BLND in MPCC - dc->caps.color.mpc.ogam_ram = 1; - dc->caps.color.mpc.ogam_rom_caps.srgb = 0; - dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0; - dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0; - dc->caps.color.mpc.ogam_rom_caps.pq = 0; - dc->caps.color.mpc.ogam_rom_caps.hlg = 0; - dc->caps.color.mpc.ocsc = 1; - - dc->config.dc_mode_clk_limit_support = true; - /* read VBIOS LTTPR caps */ - { - if (ctx->dc_bios->funcs->get_lttpr_caps) { - enum bp_result bp_query_result; - uint8_t is_vbios_lttpr_enable = 0; - - bp_query_result = ctx->dc_bios->funcs->get_lttpr_caps(ctx->dc_bios, &is_vbios_lttpr_enable); - dc->caps.vbios_lttpr_enable = (bp_query_result == BP_RESULT_OK) && !!is_vbios_lttpr_enable; - } - - /* interop bit is implicit */ - { - dc->caps.vbios_lttpr_aware = true; - } - } - - if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) - dc->debug = debug_defaults_drv; - - // Init the vm_helper - if (dc->vm_helper) - vm_helper_init(dc->vm_helper, 16); - - /************************************************* - * Create resources * - *************************************************/ - - /* Clock Sources for Pixel Clock*/ - pool->base.clock_sources[DCN321_CLK_SRC_PLL0] = - dcn321_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL0, - &clk_src_regs[0], false); - pool->base.clock_sources[DCN321_CLK_SRC_PLL1] = - dcn321_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL1, - &clk_src_regs[1], false); - pool->base.clock_sources[DCN321_CLK_SRC_PLL2] = - dcn321_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL2, - &clk_src_regs[2], false); - pool->base.clock_sources[DCN321_CLK_SRC_PLL3] = - dcn321_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL3, - &clk_src_regs[3], false); - pool->base.clock_sources[DCN321_CLK_SRC_PLL4] = - dcn321_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL4, - &clk_src_regs[4], false); - - pool->base.clk_src_count = DCN321_CLK_SRC_TOTAL; - - /* todo: not reuse phy_pll registers */ - pool->base.dp_clock_source = - dcn321_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_ID_DP_DTO, - &clk_src_regs[0], true); - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] == NULL) { - dm_error("DC: failed to create clock sources!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - } - - /* DCCG */ - pool->base.dccg = dccg32_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask); - if (pool->base.dccg == NULL) { - dm_error("DC: failed to create dccg!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - - /* DML */ - dml_init_instance(&dc->dml, &dcn3_21_soc, &dcn3_21_ip, DML_PROJECT_DCN32); - - /* IRQ Service */ - init_data.ctx = dc->ctx; - pool->base.irqs = dal_irq_service_dcn32_create(&init_data); - if (!pool->base.irqs) - goto create_fail; - - /* HUBBUB */ - pool->base.hubbub = dcn321_hubbub_create(ctx); - if (pool->base.hubbub == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create hubbub!\n"); - goto create_fail; - } - - /* HUBPs, DPPs, OPPs, TGs, ABMs */ - for (i = 0, j = 0; i < pool->base.res_cap->num_timing_generator; i++) { - - /* if pipe is disabled, skip instance of HW pipe, - * i.e, skip ASIC register instance - */ - if (pipe_fuses & 1 << i) - continue; - - pool->base.hubps[j] = dcn321_hubp_create(ctx, i); - if (pool->base.hubps[j] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create hubps!\n"); - goto create_fail; - } - - pool->base.dpps[j] = dcn321_dpp_create(ctx, i); - if (pool->base.dpps[j] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create dpps!\n"); - goto create_fail; - } - - pool->base.opps[j] = dcn321_opp_create(ctx, i); - if (pool->base.opps[j] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create output pixel processor!\n"); - goto create_fail; - } - - pool->base.timing_generators[j] = dcn321_timing_generator_create( - ctx, i); - if (pool->base.timing_generators[j] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create tg!\n"); - goto create_fail; - } - - pool->base.multiple_abms[j] = dmub_abm_create(ctx, - &abm_regs[i], - &abm_shift, - &abm_mask); - if (pool->base.multiple_abms[j] == NULL) { - dm_error("DC: failed to create abm for pipe %d!\n", i); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - - /* index for resource pool arrays for next valid pipe */ - j++; - } - - /* PSR */ - pool->base.psr = dmub_psr_create(ctx); - if (pool->base.psr == NULL) { - dm_error("DC: failed to create psr obj!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - - /* MPCCs */ - pool->base.mpc = dcn321_mpc_create(ctx, pool->base.res_cap->num_timing_generator, pool->base.res_cap->num_mpc_3dlut); - if (pool->base.mpc == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create mpc!\n"); - goto create_fail; - } - - /* DSCs */ - for (i = 0; i < pool->base.res_cap->num_dsc; i++) { - pool->base.dscs[i] = dcn321_dsc_create(ctx, i); - if (pool->base.dscs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create display stream compressor %d!\n", i); - goto create_fail; - } - } - - /* DWB */ - if (!dcn321_dwbc_create(ctx, &pool->base)) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create dwbc!\n"); - goto create_fail; - } - - /* MMHUBBUB */ - if (!dcn321_mmhubbub_create(ctx, &pool->base)) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create mcif_wb!\n"); - goto create_fail; - } - - /* AUX and I2C */ - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - pool->base.engines[i] = dcn321_aux_engine_create(ctx, i); - if (pool->base.engines[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create aux engine!!\n"); - goto create_fail; - } - pool->base.hw_i2cs[i] = dcn321_i2c_hw_create(ctx, i); - if (pool->base.hw_i2cs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create hw i2c!!\n"); - goto create_fail; - } - pool->base.sw_i2cs[i] = NULL; - } - - /* Audio, HWSeq, Stream Encoders including HPO and virtual, MPC 3D LUTs */ - if (!resource_construct(num_virtual_links, dc, &pool->base, - &res_create_funcs)) - goto create_fail; - - /* HW Sequencer init functions and Plane caps */ - dcn32_hw_sequencer_init_functions(dc); - - dc->caps.max_planes = pool->base.pipe_count; - - for (i = 0; i < dc->caps.max_planes; ++i) - dc->caps.planes[i] = plane_cap; - - 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->base.oem_device = dc->link_srv->create_ddc_service(&ddc_init_data); - } else { - pool->base.oem_device = NULL; - } - - dc->dml2_options.dcn_pipe_count = pool->base.pipe_count; - dc->dml2_options.use_native_pstate_optimization = false; - dc->dml2_options.use_native_soc_bb_construction = true; - dc->dml2_options.minimize_dispclk_using_odm = true; - - dc->dml2_options.callbacks.dc = dc; - dc->dml2_options.callbacks.build_scaling_params = &resource_build_scaling_params; - dc->dml2_options.callbacks.can_support_mclk_switch_using_fw_based_vblank_stretch = &dcn30_can_support_mclk_switch_using_fw_based_vblank_stretch; - dc->dml2_options.callbacks.acquire_secondary_pipe_for_mpc_odm = &dc_resource_acquire_secondary_pipe_for_mpc_odm_legacy; - dc->dml2_options.callbacks.update_pipes_for_stream_with_slice_count = &resource_update_pipes_for_stream_with_slice_count; - dc->dml2_options.callbacks.update_pipes_for_plane_with_slice_count = &resource_update_pipes_for_plane_with_slice_count; - dc->dml2_options.callbacks.get_mpc_slice_index = &resource_get_mpc_slice_index; - dc->dml2_options.callbacks.get_odm_slice_index = &resource_get_odm_slice_index; - dc->dml2_options.callbacks.get_opp_head = &resource_get_opp_head; - - dc->dml2_options.svp_pstate.callbacks.dc = dc; - dc->dml2_options.svp_pstate.callbacks.add_plane_to_context = &dc_add_plane_to_context; - dc->dml2_options.svp_pstate.callbacks.add_stream_to_ctx = &dc_add_stream_to_ctx; - dc->dml2_options.svp_pstate.callbacks.build_scaling_params = &resource_build_scaling_params; - dc->dml2_options.svp_pstate.callbacks.create_plane = &dc_create_plane_state; - dc->dml2_options.svp_pstate.callbacks.remove_plane_from_context = &dc_remove_plane_from_context; - dc->dml2_options.svp_pstate.callbacks.remove_stream_from_ctx = &dc_remove_stream_from_ctx; - dc->dml2_options.svp_pstate.callbacks.create_stream_for_sink = &dc_create_stream_for_sink; - dc->dml2_options.svp_pstate.callbacks.plane_state_release = &dc_plane_state_release; - dc->dml2_options.svp_pstate.callbacks.stream_release = &dc_stream_release; - dc->dml2_options.svp_pstate.callbacks.release_dsc = &dcn20_release_dsc; - - dc->dml2_options.svp_pstate.subvp_fw_processing_delay_us = dc->caps.subvp_fw_processing_delay_us; - dc->dml2_options.svp_pstate.subvp_prefetch_end_to_mall_start_us = dc->caps.subvp_prefetch_end_to_mall_start_us; - dc->dml2_options.svp_pstate.subvp_pstate_allow_width_us = dc->caps.subvp_pstate_allow_width_us; - dc->dml2_options.svp_pstate.subvp_swath_height_margin_lines = dc->caps.subvp_swath_height_margin_lines; - - dc->dml2_options.svp_pstate.force_disable_subvp = dc->debug.force_disable_subvp; - dc->dml2_options.svp_pstate.force_enable_subvp = dc->debug.force_subvp_mclk_switch; - - dc->dml2_options.mall_cfg.cache_line_size_bytes = dc->caps.cache_line_size; - dc->dml2_options.mall_cfg.cache_num_ways = dc->caps.cache_num_ways; - dc->dml2_options.mall_cfg.max_cab_allocation_bytes = dc->caps.max_cab_allocation_bytes; - dc->dml2_options.mall_cfg.mblk_height_4bpe_pixels = DCN3_2_MBLK_HEIGHT_4BPE; - dc->dml2_options.mall_cfg.mblk_height_8bpe_pixels = DCN3_2_MBLK_HEIGHT_8BPE; - dc->dml2_options.mall_cfg.mblk_size_bytes = DCN3_2_MALL_MBLK_SIZE_BYTES; - dc->dml2_options.mall_cfg.mblk_width_pixels = DCN3_2_MBLK_WIDTH; - - dc->dml2_options.max_segments_per_hubp = 18; - dc->dml2_options.det_segment_size = DCN3_2_DET_SEG_SIZE; - - return true; - -create_fail: - - dcn321_resource_destruct(pool); - - return false; -} - -struct resource_pool *dcn321_create_resource_pool( - const struct dc_init_data *init_data, - struct dc *dc) -{ - struct dcn321_resource_pool *pool = - kzalloc(sizeof(struct dcn321_resource_pool), GFP_KERNEL); - - if (!pool) - return NULL; - - if (dcn321_resource_construct(init_data->num_virtual_links, dc, pool)) - return &pool->base; - - BREAK_TO_DEBUGGER(); - kfree(pool); - return NULL; -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.h b/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.h deleted file mode 100644 index 82cbf009f2d380..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn321/dcn321_resource.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2020 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 _DCN321_RESOURCE_H_ -#define _DCN321_RESOURCE_H_ - -#include "core_types.h" - -#define TO_DCN321_RES_POOL(pool)\ - container_of(pool, struct dcn321_resource_pool, base) - -extern struct _vcs_dpi_ip_params_st dcn3_21_ip; -extern struct _vcs_dpi_soc_bounding_box_st dcn3_21_soc; - -struct dcn321_resource_pool { - struct resource_pool base; -}; - -struct resource_pool *dcn321_create_resource_pool( - const struct dc_init_data *init_data, - struct dc *dc); - -#endif /* _DCN321_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/Makefile b/drivers/gpu/drm/amd/display/dc/dcn35/Makefile index 20d0eef1a13bfd..0e317e0c36a083 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn35/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dcn35/Makefile @@ -10,9 +10,9 @@ # # Makefile for DCN35. -DCN35 = dcn35_resource.o dcn35_init.o dcn35_dio_stream_encoder.o \ - dcn35_dio_link_encoder.o dcn35_dccg.o dcn35_optc.o \ - dcn35_dsc.o dcn35_hubp.o dcn35_hubbub.o \ +DCN35 = dcn35_dio_stream_encoder.o \ + dcn35_dio_link_encoder.o dcn35_dccg.o \ + dcn35_hubp.o dcn35_hubbub.o \ dcn35_mmhubbub.o dcn35_opp.o dcn35_dpp.o dcn35_pg_cntl.o dcn35_dwb.o AMD_DAL_DCN35 = $(addprefix $(AMDDALPATH)/dc/dcn35/,$(DCN35)) diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dccg.c b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dccg.c index 479f3683c0b70e..f1ba7bb792ea26 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dccg.c @@ -256,6 +256,21 @@ static void dccg35_set_dtbclk_dto( if (params->ref_dtbclk_khz && req_dtbclk_khz) { uint32_t modulo, phase; + switch (params->otg_inst) { + case 0: + REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P0_GATE_DISABLE, 1); + break; + case 1: + REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P1_GATE_DISABLE, 1); + break; + case 2: + REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P2_GATE_DISABLE, 1); + break; + case 3: + REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P3_GATE_DISABLE, 1); + break; + } + // phase / modulo = dtbclk / dtbclk ref modulo = params->ref_dtbclk_khz * 1000; phase = req_dtbclk_khz * 1000; @@ -280,6 +295,21 @@ static void dccg35_set_dtbclk_dto( REG_UPDATE(OTG_PIXEL_RATE_CNTL[params->otg_inst], PIPE_DTO_SRC_SEL[params->otg_inst], 2); } else { + switch (params->otg_inst) { + case 0: + REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P0_GATE_DISABLE, 0); + break; + case 1: + REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P1_GATE_DISABLE, 0); + break; + case 2: + REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P2_GATE_DISABLE, 0); + break; + case 3: + REG_UPDATE(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P3_GATE_DISABLE, 0); + break; + } + REG_UPDATE_2(OTG_PIXEL_RATE_CNTL[params->otg_inst], DTBCLK_DTO_ENABLE[params->otg_inst], 0, PIPE_DTO_SRC_SEL[params->otg_inst], params->is_hdmi ? 0 : 1); @@ -476,6 +506,64 @@ static void dccg35_dpp_root_clock_control( dccg->dpp_clock_gated[dpp_inst] = !clock_on; } +static void dccg35_disable_symclk32_se( + struct dccg *dccg, + int hpo_se_inst) +{ + struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); + + /* set refclk as the source for symclk32_se */ + switch (hpo_se_inst) { + case 0: + REG_UPDATE_2(SYMCLK32_SE_CNTL, + SYMCLK32_SE0_SRC_SEL, 0, + SYMCLK32_SE0_EN, 0); + if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se) { + REG_UPDATE(DCCG_GATE_DISABLE_CNTL3, + SYMCLK32_SE0_GATE_DISABLE, 0); +// REG_UPDATE(DCCG_GATE_DISABLE_CNTL3, +// SYMCLK32_ROOT_SE0_GATE_DISABLE, 0); + } + break; + case 1: + REG_UPDATE_2(SYMCLK32_SE_CNTL, + SYMCLK32_SE1_SRC_SEL, 0, + SYMCLK32_SE1_EN, 0); + if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se) { + REG_UPDATE(DCCG_GATE_DISABLE_CNTL3, + SYMCLK32_SE1_GATE_DISABLE, 0); +// REG_UPDATE(DCCG_GATE_DISABLE_CNTL3, +// SYMCLK32_ROOT_SE1_GATE_DISABLE, 0); + } + break; + case 2: + REG_UPDATE_2(SYMCLK32_SE_CNTL, + SYMCLK32_SE2_SRC_SEL, 0, + SYMCLK32_SE2_EN, 0); + if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se) { + REG_UPDATE(DCCG_GATE_DISABLE_CNTL3, + SYMCLK32_SE2_GATE_DISABLE, 0); +// REG_UPDATE(DCCG_GATE_DISABLE_CNTL3, +// SYMCLK32_ROOT_SE2_GATE_DISABLE, 0); + } + break; + case 3: + REG_UPDATE_2(SYMCLK32_SE_CNTL, + SYMCLK32_SE3_SRC_SEL, 0, + SYMCLK32_SE3_EN, 0); + if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se) { + REG_UPDATE(DCCG_GATE_DISABLE_CNTL3, + SYMCLK32_SE3_GATE_DISABLE, 0); +// REG_UPDATE(DCCG_GATE_DISABLE_CNTL3, +// SYMCLK32_ROOT_SE3_GATE_DISABLE, 0); + } + break; + default: + BREAK_TO_DEBUGGER(); + return; + } +} + void dccg35_init(struct dccg *dccg) { int otg_inst; @@ -484,7 +572,7 @@ void dccg35_init(struct dccg *dccg) * will cause DCN to hang. */ for (otg_inst = 0; otg_inst < 4; otg_inst++) - dccg31_disable_symclk32_se(dccg, otg_inst); + dccg35_disable_symclk32_se(dccg, otg_inst); if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_le) for (otg_inst = 0; otg_inst < 2; otg_inst++) @@ -758,7 +846,7 @@ static const struct dccg_funcs dccg35_funcs = { .dccg_init = dccg35_init, .set_dpstreamclk = dccg35_set_dpstreamclk, .enable_symclk32_se = dccg31_enable_symclk32_se, - .disable_symclk32_se = dccg31_disable_symclk32_se, + .disable_symclk32_se = dccg35_disable_symclk32_se, .enable_symclk32_le = dccg31_enable_symclk32_le, .disable_symclk32_le = dccg31_disable_symclk32_le, .set_symclk32_le_root_clock_gating = dccg31_set_symclk32_le_root_clock_gating, diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dccg.h b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dccg.h index 423feb4c2f3f59..1586a45ca3bd40 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dccg.h +++ b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dccg.h @@ -34,6 +34,8 @@ #define DCCG_REG_LIST_DCN35() \ DCCG_REG_LIST_DCN314(),\ SR(DPPCLK_CTRL),\ + SR(DCCG_GATE_DISABLE_CNTL4),\ + SR(DCCG_GATE_DISABLE_CNTL5),\ SR(DCCG_GATE_DISABLE_CNTL6),\ SR(DCCG_GLOBAL_FGCG_REP_CNTL),\ SR(SYMCLKA_CLOCK_ENABLE),\ @@ -174,7 +176,61 @@ DCCG_SF(SYMCLKB_CLOCK_ENABLE, SYMCLKB_FE_SRC_SEL, mask_sh),\ DCCG_SF(SYMCLKC_CLOCK_ENABLE, SYMCLKC_FE_SRC_SEL, mask_sh),\ DCCG_SF(SYMCLKD_CLOCK_ENABLE, SYMCLKD_FE_SRC_SEL, mask_sh),\ - DCCG_SF(SYMCLKE_CLOCK_ENABLE, SYMCLKE_FE_SRC_SEL, mask_sh) + DCCG_SF(SYMCLKE_CLOCK_ENABLE, SYMCLKE_FE_SRC_SEL, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P0_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P1_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P2_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P3_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DSCCLK0_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DSCCLK1_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DSCCLK2_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DSCCLK3_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKA_FE_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKB_FE_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKC_FE_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKD_FE_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKE_FE_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DPPCLK0_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DPPCLK1_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DPPCLK2_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DPPCLK3_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL2, HDMICHARCLK0_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL4, HDMICHARCLK0_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL6, HDMISTREAMCLK0_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKA_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKB_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKC_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKD_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKE_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE0_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE1_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE2_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE3_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_LE0_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_LE1_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_SE0_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_SE1_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_SE2_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_SE3_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_LE0_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_LE1_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL4, PHYA_REFCLK_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL4, PHYB_REFCLK_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL4, PHYC_REFCLK_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL4, PHYD_REFCLK_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL4, PHYE_REFCLK_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK0_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK1_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK2_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK3_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(HDMISTREAMCLK0_DTO_PARAM, HDMISTREAMCLK0_DTO_PHASE, mask_sh),\ + DCCG_SF(HDMISTREAMCLK0_DTO_PARAM, HDMISTREAMCLK0_DTO_MODULO, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL, DISPCLK_DCCG_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, HDMISTREAMCLK0_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK0_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK1_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK2_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK3_GATE_DISABLE, mask_sh),\ struct dccg *dccg35_create( struct dc_context *ctx, diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dio_link_encoder.c index f91e0889527555..da94e5309fbaf0 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dio_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dio_link_encoder.c @@ -256,6 +256,10 @@ void dcn35_link_encoder_construct( enc10->base.features.flags.bits.IS_UHBR10_CAPABLE = bp_cap_info.DP_UHBR10_EN; enc10->base.features.flags.bits.IS_UHBR13_5_CAPABLE = bp_cap_info.DP_UHBR13_5_EN; enc10->base.features.flags.bits.IS_UHBR20_CAPABLE = bp_cap_info.DP_UHBR20_EN; + if (bp_cap_info.DP_IS_USB_C) { + /*BIOS not switch to use CONNECTOR_ID_USBC = 24 yet*/ + enc10->base.features.flags.bits.DP_IS_USB_C = 1; + } } else { DC_LOG_WARNING("%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n", @@ -264,4 +268,5 @@ void dcn35_link_encoder_construct( } if (enc10->base.ctx->dc->debug.hdmi20_disable) enc10->base.features.flags.bits.HDMI_6GB_EN = 0; + } diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dsc.c b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dsc.c deleted file mode 100644 index 71d2dff9986d5f..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dsc.c +++ /dev/null @@ -1,60 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * 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 "dcn35_dsc.h" -#include "reg_helper.h" - -/* Macro definitios for REG_SET macros*/ -#define CTX \ - dsc20->base.ctx - -#define REG(reg)\ - dsc20->dsc_regs->reg - -#undef FN -#define FN(reg_name, field_name) \ - ((const struct dcn35_dsc_shift *)(dsc20->dsc_shift))->field_name, \ - ((const struct dcn35_dsc_mask *)(dsc20->dsc_mask))->field_name - -#define DC_LOGGER \ - dsc->ctx->logger - -void dsc35_construct(struct dcn20_dsc *dsc, - struct dc_context *ctx, - int inst, - const struct dcn20_dsc_registers *dsc_regs, - const struct dcn35_dsc_shift *dsc_shift, - const struct dcn35_dsc_mask *dsc_mask) -{ - dsc2_construct(dsc, ctx, inst, dsc_regs, - (const struct dcn20_dsc_shift *)(dsc_shift), - (const struct dcn20_dsc_mask *)(dsc_mask)); -} - -void dsc35_set_fgcg(struct dcn20_dsc *dsc20, bool enable) -{ - REG_UPDATE(DSC_TOP_CONTROL, DSC_FGCG_REP_DIS, !enable); -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dsc.h b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dsc.h deleted file mode 100644 index 133ad38842cc40..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_dsc.h +++ /dev/null @@ -1,59 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * 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 __DCN35_DSC_H__ -#define __DCN35_DSC_H__ - -#include "dcn20/dcn20_dsc.h" - -#define DSC_REG_LIST_SH_MASK_DCN35(mask_sh) \ - DSC_REG_LIST_SH_MASK_DCN20(mask_sh), \ - DSC_SF(DSC_TOP0_DSC_TOP_CONTROL, DSC_FGCG_REP_DIS, mask_sh) - -#define DSC_FIELD_LIST_DCN35(type) \ - struct { \ - DSC_FIELD_LIST_DCN20(type); \ - type DSC_FGCG_REP_DIS; \ - } - -struct dcn35_dsc_shift { - DSC_FIELD_LIST_DCN35(uint8_t); -}; - -struct dcn35_dsc_mask { - DSC_FIELD_LIST_DCN35(uint32_t); -}; - -void dsc35_construct(struct dcn20_dsc *dsc, - struct dc_context *ctx, - int inst, - const struct dcn20_dsc_registers *dsc_regs, - const struct dcn35_dsc_shift *dsc_shift, - const struct dcn35_dsc_mask *dsc_mask); - -void dsc35_set_fgcg(struct dcn20_dsc *dsc20, bool enable); - -#endif /* __DCN35_DSC_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_init.c b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_init.c deleted file mode 100644 index 296bf3a38cb906..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_init.c +++ /dev/null @@ -1,171 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * 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 "dce110/dce110_hwseq.h" -#include "dcn10/dcn10_hwseq.h" -#include "dcn20/dcn20_hwseq.h" -#include "dcn21/dcn21_hwseq.h" -#include "dcn30/dcn30_hwseq.h" -#include "dcn301/dcn301_hwseq.h" -#include "dcn31/dcn31_hwseq.h" -#include "dcn32/dcn32_hwseq.h" -#include "dcn35/dcn35_hwseq.h" - -#include "dcn35_init.h" - -static const struct hw_sequencer_funcs dcn35_funcs = { - .program_gamut_remap = dcn30_program_gamut_remap, - .init_hw = dcn35_init_hw, - .power_down_on_boot = dcn35_power_down_on_boot, - .apply_ctx_to_hw = dce110_apply_ctx_to_hw, - .apply_ctx_for_surface = NULL, - .program_front_end_for_ctx = dcn20_program_front_end_for_ctx, - .wait_for_pending_cleared = dcn10_wait_for_pending_cleared, - .post_unlock_program_front_end = dcn20_post_unlock_program_front_end, - .update_plane_addr = dcn20_update_plane_addr, - .update_dchub = dcn10_update_dchub, - .update_pending_status = dcn10_update_pending_status, - .program_output_csc = dcn20_program_output_csc, - .enable_accelerated_mode = dce110_enable_accelerated_mode, - .enable_timing_synchronization = dcn10_enable_timing_synchronization, - .enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset, - .update_info_frame = dcn31_update_info_frame, - .send_immediate_sdp_message = dcn10_send_immediate_sdp_message, - .enable_stream = dcn20_enable_stream, - .disable_stream = dce110_disable_stream, - .unblank_stream = dcn32_unblank_stream, - .blank_stream = dce110_blank_stream, - .enable_audio_stream = dce110_enable_audio_stream, - .disable_audio_stream = dce110_disable_audio_stream, - .disable_plane = dcn35_disable_plane, - .disable_pixel_data = dcn20_disable_pixel_data, - .pipe_control_lock = dcn20_pipe_control_lock, - .interdependent_update_lock = dcn10_lock_all_pipes, - .cursor_lock = dcn10_cursor_lock, - .prepare_bandwidth = dcn35_prepare_bandwidth, - .optimize_bandwidth = dcn35_optimize_bandwidth, - .update_bandwidth = dcn20_update_bandwidth, - .set_drr = dcn10_set_drr, - .get_position = dcn10_get_position, - .set_static_screen_control = dcn30_set_static_screen_control, - .setup_stereo = dcn10_setup_stereo, - .set_avmute = dcn30_set_avmute, - .log_hw_state = dcn10_log_hw_state, - .get_hw_state = dcn10_get_hw_state, - .clear_status_bits = dcn10_clear_status_bits, - .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, - .edp_backlight_control = dce110_edp_backlight_control, - .edp_power_control = dce110_edp_power_control, - .edp_wait_for_T12 = dce110_edp_wait_for_T12, - .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, - .set_cursor_position = dcn10_set_cursor_position, - .set_cursor_attribute = dcn10_set_cursor_attribute, - .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level, - .setup_periodic_interrupt = dcn10_setup_periodic_interrupt, - .set_clock = dcn10_set_clock, - .get_clock = dcn10_get_clock, - .program_triplebuffer = dcn20_program_triple_buffer, - .enable_writeback = dcn30_enable_writeback, - .disable_writeback = dcn30_disable_writeback, - .update_writeback = dcn30_update_writeback, - .mmhubbub_warmup = dcn30_mmhubbub_warmup, - .dmdata_status_done = dcn20_dmdata_status_done, - .program_dmdata_engine = dcn30_program_dmdata_engine, - .set_dmdata_attributes = dcn20_set_dmdata_attributes, - .init_sys_ctx = dcn31_init_sys_ctx, - .init_vm_ctx = dcn20_init_vm_ctx, - .set_flip_control_gsl = dcn20_set_flip_control_gsl, - .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync, - .calc_vupdate_position = dcn10_calc_vupdate_position, - .power_down = dce110_power_down, - .set_backlight_level = dcn21_set_backlight_level, - .set_abm_immediate_disable = dcn21_set_abm_immediate_disable, - .set_pipe = dcn21_set_pipe, - .enable_lvds_link_output = dce110_enable_lvds_link_output, - .enable_tmds_link_output = dce110_enable_tmds_link_output, - .enable_dp_link_output = dce110_enable_dp_link_output, - .disable_link_output = dcn32_disable_link_output, - .z10_restore = dcn35_z10_restore, - .z10_save_init = dcn31_z10_save_init, - .set_disp_pattern_generator = dcn30_set_disp_pattern_generator, - .optimize_pwr_state = dcn21_optimize_pwr_state, - .exit_optimized_pwr_state = dcn21_exit_optimized_pwr_state, - .update_visual_confirm_color = dcn10_update_visual_confirm_color, - .apply_idle_power_optimizations = dcn35_apply_idle_power_optimizations, - .update_dsc_pg = dcn32_update_dsc_pg, - .calc_blocks_to_gate = dcn35_calc_blocks_to_gate, - .calc_blocks_to_ungate = dcn35_calc_blocks_to_ungate, - .block_power_control = dcn35_block_power_control, - .root_clock_control = dcn35_root_clock_control, - .set_idle_state = dcn35_set_idle_state, - .get_idle_state = dcn35_get_idle_state -}; - -static const struct hwseq_private_funcs dcn35_private_funcs = { - .init_pipes = dcn35_init_pipes, - .update_plane_addr = dcn20_update_plane_addr, - .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, - .update_mpcc = dcn20_update_mpcc, - .set_input_transfer_func = dcn32_set_input_transfer_func, - .set_output_transfer_func = dcn32_set_output_transfer_func, - .power_down = dce110_power_down, - .enable_display_power_gating = dcn10_dummy_display_power_gating, - .blank_pixel_data = dcn20_blank_pixel_data, - .reset_hw_ctx_wrap = dcn31_reset_hw_ctx_wrap, - .enable_stream_timing = dcn20_enable_stream_timing, - .edp_backlight_control = dce110_edp_backlight_control, - .setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt, - .did_underflow_occur = dcn10_did_underflow_occur, - .init_blank = dcn20_init_blank, - .disable_vga = NULL, - .bios_golden_init = dcn10_bios_golden_init, - .plane_atomic_disable = dcn35_plane_atomic_disable, - //.plane_atomic_disable = dcn20_plane_atomic_disable,/*todo*/ - //.hubp_pg_control = dcn35_hubp_pg_control, - .enable_power_gating_plane = dcn35_enable_power_gating_plane, - .dpp_root_clock_control = dcn35_dpp_root_clock_control, - .program_all_writeback_pipes_in_tree = dcn30_program_all_writeback_pipes_in_tree, - .update_odm = dcn35_update_odm, - .set_hdr_multiplier = dcn10_set_hdr_multiplier, - .verify_allow_pstate_change_high = dcn10_verify_allow_pstate_change_high, - .wait_for_blank_complete = dcn20_wait_for_blank_complete, - .dccg_init = dcn20_dccg_init, - .set_mcm_luts = dcn32_set_mcm_luts, - .setup_hpo_hw_control = dcn35_setup_hpo_hw_control, - .calculate_dccg_k1_k2_values = dcn32_calculate_dccg_k1_k2_values, - .set_pixels_per_cycle = dcn32_set_pixels_per_cycle, - .is_dp_dig_pixel_rate_div_policy = dcn32_is_dp_dig_pixel_rate_div_policy, - .dsc_pg_control = dcn35_dsc_pg_control, - .dsc_pg_status = dcn32_dsc_pg_status, - .enable_plane = dcn35_enable_plane, -}; - -void dcn35_hw_sequencer_construct(struct dc *dc) -{ - dc->hwss = dcn35_funcs; - dc->hwseq->funcs = dcn35_private_funcs; - -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_init.h b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_init.h deleted file mode 100644 index b67015032c3513..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_init.h +++ /dev/null @@ -1,34 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * 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_DCN35_INIT_H__ -#define __DC_DCN35_INIT_H__ - -struct dc; - -void dcn35_hw_sequencer_construct(struct dc *dc); - -#endif /* __DC_DCN35_INIT_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_optc.c b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_optc.c deleted file mode 100644 index a4a39f1638cf26..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_optc.c +++ /dev/null @@ -1,290 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * 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 "dcn35_optc.h" - -#include "dcn30/dcn30_optc.h" -#include "dcn31/dcn31_optc.h" -#include "dcn32/dcn32_optc.h" -#include "reg_helper.h" -#include "dc.h" -#include "dcn_calc_math.h" - -#define REG(reg)\ - optc1->tg_regs->reg - -#define CTX \ - optc1->base.ctx - -#undef FN -#define FN(reg_name, field_name) \ - optc1->tg_shift->field_name, optc1->tg_mask->field_name - -/** - * optc35_set_odm_combine() - Enable CRTC - call ASIC Control Object to enable Timing generator. - * - * @optc: Output Pipe Timing Combine instance reference. - * @opp_id: Output Plane Processor instance ID. - * @opp_cnt: Output Plane Processor count. - * @timing: Timing parameters used to configure DCN blocks. - * - * Return: void. - */ -static void optc35_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, - struct dc_crtc_timing *timing) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - uint32_t memory_mask = 0; - int h_active = timing->h_addressable + timing->h_border_left + timing->h_border_right; - int mpcc_hactive = h_active / opp_cnt; - /* Each memory instance is 2048x(314x2) bits to support half line of 4096 */ - int odm_mem_count = (h_active + 2047) / 2048; - - /* - * display <= 4k : 2 memories + 2 pipes - * 4k < display <= 8k : 4 memories + 2 pipes - * 8k < display <= 12k : 6 memories + 4 pipes - */ - if (opp_cnt == 4) { - if (odm_mem_count <= 2) - memory_mask = 0x3; - else if (odm_mem_count <= 4) - memory_mask = 0xf; - else - memory_mask = 0x3f; - } else { - if (odm_mem_count <= 2) - memory_mask = 0x1 << (opp_id[0] * 2) | 0x1 << (opp_id[1] * 2); - else if (odm_mem_count <= 4) - memory_mask = 0x3 << (opp_id[0] * 2) | 0x3 << (opp_id[1] * 2); - else - memory_mask = 0x77; - } - - REG_SET(OPTC_MEMORY_CONFIG, 0, - OPTC_MEM_SEL, memory_mask); - - if (opp_cnt == 2) { - REG_SET_3(OPTC_DATA_SOURCE_SELECT, 0, - OPTC_NUM_OF_INPUT_SEGMENT, 1, - OPTC_SEG0_SRC_SEL, opp_id[0], - OPTC_SEG1_SRC_SEL, opp_id[1]); - } else if (opp_cnt == 4) { - REG_SET_5(OPTC_DATA_SOURCE_SELECT, 0, - OPTC_NUM_OF_INPUT_SEGMENT, 3, - OPTC_SEG0_SRC_SEL, opp_id[0], - OPTC_SEG1_SRC_SEL, opp_id[1], - OPTC_SEG2_SRC_SEL, opp_id[2], - OPTC_SEG3_SRC_SEL, opp_id[3]); - } - - REG_UPDATE(OPTC_WIDTH_CONTROL, - OPTC_SEGMENT_WIDTH, mpcc_hactive); - - REG_UPDATE(OTG_H_TIMING_CNTL, OTG_H_TIMING_DIV_MODE, opp_cnt - 1); - optc1->opp_count = opp_cnt; -} - -static bool optc35_enable_crtc(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - /* opp instance for OTG, 1 to 1 mapping and odm will adjust */ - REG_UPDATE(OPTC_DATA_SOURCE_SELECT, - OPTC_SEG0_SRC_SEL, optc->inst); - - /* VTG enable first is for HW workaround */ - REG_UPDATE(CONTROL, - VTG0_ENABLE, 1); - - REG_SEQ_START(); - - /* Enable CRTC */ - REG_UPDATE_2(OTG_CONTROL, - OTG_DISABLE_POINT_CNTL, 2, - OTG_MASTER_EN, 1); - - REG_SEQ_SUBMIT(); - REG_SEQ_WAIT_DONE(); - - return true; -} - -/* disable_crtc */ -static bool optc35_disable_crtc(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - /* disable otg request until end of the first line - * in the vertical blank region - */ - REG_UPDATE(OTG_CONTROL, - OTG_MASTER_EN, 0); - - REG_UPDATE(CONTROL, - VTG0_ENABLE, 0); - - /* CRTC disabled, so disable clock. */ - REG_WAIT(OTG_CLOCK_CONTROL, - OTG_BUSY, 0, - 1, 100000); - optc1_clear_optc_underflow(optc); - - return true; -} - -static void optc35_phantom_crtc_post_enable(struct timing_generator *optc) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - /* Disable immediately. */ - REG_UPDATE_2(OTG_CONTROL, OTG_DISABLE_POINT_CNTL, 0, OTG_MASTER_EN, 0); - - /* CRTC disabled, so disable clock. */ - REG_WAIT(OTG_CLOCK_CONTROL, OTG_BUSY, 0, 1, 100000); -} - -static bool optc35_configure_crc(struct timing_generator *optc, - const struct crc_params *params) -{ - struct optc *optc1 = DCN10TG_FROM_TG(optc); - - if (!optc1_is_tg_enabled(optc)) - return false; - REG_WRITE(OTG_CRC_CNTL, 0); - if (!params->enable) - return true; - REG_UPDATE_2(OTG_CRC0_WINDOWA_X_CONTROL, - OTG_CRC0_WINDOWA_X_START, params->windowa_x_start, - OTG_CRC0_WINDOWA_X_END, params->windowa_x_end); - REG_UPDATE_2(OTG_CRC0_WINDOWA_Y_CONTROL, - OTG_CRC0_WINDOWA_Y_START, params->windowa_y_start, - OTG_CRC0_WINDOWA_Y_END, params->windowa_y_end); - REG_UPDATE_2(OTG_CRC0_WINDOWB_X_CONTROL, - OTG_CRC0_WINDOWB_X_START, params->windowb_x_start, - OTG_CRC0_WINDOWB_X_END, params->windowb_x_end); - REG_UPDATE_2(OTG_CRC0_WINDOWB_Y_CONTROL, - OTG_CRC0_WINDOWB_Y_START, params->windowb_y_start, - OTG_CRC0_WINDOWB_Y_END, params->windowb_y_end); - if (optc1->base.ctx->dc->debug.otg_crc_db && optc1->tg_mask->OTG_CRC_WINDOW_DB_EN != 0) { - REG_UPDATE_4(OTG_CRC_CNTL, - OTG_CRC_CONT_EN, params->continuous_mode ? 1 : 0, - OTG_CRC0_SELECT, params->selection, - OTG_CRC_EN, 1, - OTG_CRC_WINDOW_DB_EN, 1); - } else - REG_UPDATE_3(OTG_CRC_CNTL, - OTG_CRC_CONT_EN, params->continuous_mode ? 1 : 0, - OTG_CRC0_SELECT, params->selection, - OTG_CRC_EN, 1); - return true; -} - -static struct timing_generator_funcs dcn35_tg_funcs = { - .validate_timing = optc1_validate_timing, - .program_timing = optc1_program_timing, - .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0, - .setup_vertical_interrupt1 = optc1_setup_vertical_interrupt1, - .setup_vertical_interrupt2 = optc1_setup_vertical_interrupt2, - .program_global_sync = optc1_program_global_sync, - .enable_crtc = optc35_enable_crtc, - .disable_crtc = optc35_disable_crtc, - .immediate_disable_crtc = optc31_immediate_disable_crtc, - .phantom_crtc_post_enable = optc35_phantom_crtc_post_enable, - /* used by enable_timing_synchronization. Not need for FPGA */ - .is_counter_moving = optc1_is_counter_moving, - .get_position = optc1_get_position, - .get_frame_count = optc1_get_vblank_counter, - .get_scanoutpos = optc1_get_crtc_scanoutpos, - .get_otg_active_size = optc1_get_otg_active_size, - .set_early_control = optc1_set_early_control, - /* used by enable_timing_synchronization. Not need for FPGA */ - .wait_for_state = optc1_wait_for_state, - .set_blank_color = optc3_program_blank_color, - .did_triggered_reset_occur = optc1_did_triggered_reset_occur, - .triplebuffer_lock = optc3_triplebuffer_lock, - .triplebuffer_unlock = optc2_triplebuffer_unlock, - .enable_reset_trigger = optc1_enable_reset_trigger, - .enable_crtc_reset = optc1_enable_crtc_reset, - .disable_reset_trigger = optc1_disable_reset_trigger, - .lock = optc3_lock, - .unlock = optc1_unlock, - .lock_doublebuffer_enable = optc3_lock_doublebuffer_enable, - .lock_doublebuffer_disable = optc3_lock_doublebuffer_disable, - .enable_optc_clock = optc1_enable_optc_clock, - .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 = optc1_set_static_screen_control, - .program_stereo = optc1_program_stereo, - .is_stereo_left_eye = optc1_is_stereo_left_eye, - .tg_init = optc3_tg_init, - .is_tg_enabled = optc1_is_tg_enabled, - .is_optc_underflow_occurred = optc1_is_optc_underflow_occurred, - .clear_optc_underflow = optc1_clear_optc_underflow, - .setup_global_swap_lock = NULL, - .get_crc = optc1_get_crc, - .configure_crc = optc35_configure_crc, - .set_dsc_config = optc3_set_dsc_config, - .get_dsc_status = optc2_get_dsc_status, - .set_dwb_source = NULL, - .set_odm_bypass = optc32_set_odm_bypass, - .set_odm_combine = optc35_set_odm_combine, - .get_optc_source = optc2_get_optc_source, - .set_h_timing_div_manual_mode = optc32_set_h_timing_div_manual_mode, - .set_out_mux = optc3_set_out_mux, - .set_drr_trigger_window = optc3_set_drr_trigger_window, - .set_vtotal_change_limit = optc3_set_vtotal_change_limit, - .set_gsl = optc2_set_gsl, - .set_gsl_source_select = optc2_set_gsl_source_select, - .set_vtg_params = optc1_set_vtg_params, - .program_manual_trigger = optc2_program_manual_trigger, - .setup_manual_trigger = optc2_setup_manual_trigger, - .get_hw_timing = optc1_get_hw_timing, - .init_odm = optc3_init_odm, -}; - -void dcn35_timing_generator_init(struct optc *optc1) -{ - optc1->base.funcs = &dcn35_tg_funcs; - - optc1->max_h_total = optc1->tg_mask->OTG_H_TOTAL + 1; - optc1->max_v_total = optc1->tg_mask->OTG_V_TOTAL + 1; - - optc1->min_h_blank = 32; - optc1->min_v_blank = 3; - optc1->min_v_blank_interlace = 5; - optc1->min_h_sync_width = 4; - optc1->min_v_sync_width = 1; - - dcn35_timing_generator_set_fgcg( - optc1, CTX->dc->debug.enable_fine_grain_clock_gating.bits.optc); -} - -void dcn35_timing_generator_set_fgcg(struct optc *optc1, bool enable) -{ - REG_UPDATE(OPTC_CLOCK_CONTROL, OPTC_FGCG_REP_DIS, !enable); -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_optc.h b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_optc.h deleted file mode 100644 index 1f422e4c468f1a..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_optc.h +++ /dev/null @@ -1,74 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * 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_OPTC_DCN35_H__ -#define __DC_OPTC_DCN35_H__ - -#include "dcn10/dcn10_optc.h" -#include "dcn32/dcn32_optc.h" -#define OPTC_COMMON_MASK_SH_LIST_DCN3_5(mask_sh)\ - OPTC_COMMON_MASK_SH_LIST_DCN3_2(mask_sh),\ - SF(OTG0_OTG_CRC_CNTL, OTG_CRC_WINDOW_DB_EN, mask_sh),\ - SF(OTG0_OTG_CRC1_DATA_RG, CRC1_R_CR, mask_sh),\ - SF(OTG0_OTG_CRC1_DATA_RG, CRC1_G_Y, mask_sh),\ - SF(OTG0_OTG_CRC1_DATA_B, CRC1_B_CB, mask_sh),\ - SF(OTG0_OTG_CRC2_DATA_RG, CRC2_R_CR, mask_sh),\ - SF(OTG0_OTG_CRC2_DATA_RG, CRC2_G_Y, mask_sh),\ - SF(OTG0_OTG_CRC2_DATA_B, CRC2_B_CB, mask_sh),\ - SF(OTG0_OTG_CRC3_DATA_RG, CRC3_R_CR, mask_sh),\ - SF(OTG0_OTG_CRC3_DATA_RG, CRC3_G_Y, mask_sh),\ - SF(OTG0_OTG_CRC3_DATA_B, CRC3_B_CB, mask_sh),\ - SF(OTG0_OTG_CRC1_WINDOWA_X_CONTROL, OTG_CRC1_WINDOWA_X_START, mask_sh),\ - SF(OTG0_OTG_CRC1_WINDOWA_X_CONTROL, OTG_CRC1_WINDOWA_X_END, mask_sh),\ - SF(OTG0_OTG_CRC1_WINDOWA_Y_CONTROL, OTG_CRC1_WINDOWA_Y_START, mask_sh),\ - SF(OTG0_OTG_CRC1_WINDOWA_Y_CONTROL, OTG_CRC1_WINDOWA_Y_END, mask_sh),\ - SF(OTG0_OTG_CRC1_WINDOWB_X_CONTROL, OTG_CRC1_WINDOWB_X_START, mask_sh),\ - SF(OTG0_OTG_CRC1_WINDOWB_X_CONTROL, OTG_CRC1_WINDOWB_X_END, mask_sh),\ - SF(OTG0_OTG_CRC1_WINDOWB_Y_CONTROL, OTG_CRC1_WINDOWB_Y_START, mask_sh),\ - SF(OTG0_OTG_CRC1_WINDOWB_Y_CONTROL, OTG_CRC1_WINDOWB_Y_END, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWA_X_CONTROL_READBACK, OTG_CRC0_WINDOWA_X_START_READBACK, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWA_X_CONTROL_READBACK, OTG_CRC0_WINDOWA_X_END_READBACK, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWA_Y_CONTROL_READBACK, OTG_CRC0_WINDOWA_Y_START_READBACK, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWA_Y_CONTROL_READBACK, OTG_CRC0_WINDOWA_Y_END_READBACK, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWB_X_CONTROL_READBACK, OTG_CRC0_WINDOWB_X_START_READBACK, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWB_X_CONTROL_READBACK, OTG_CRC0_WINDOWB_X_END_READBACK, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL_READBACK, OTG_CRC0_WINDOWB_Y_START_READBACK, mask_sh),\ - SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL_READBACK, OTG_CRC0_WINDOWB_Y_END_READBACK, mask_sh),\ - SF(OTG0_OTG_CRC1_WINDOWA_X_CONTROL_READBACK, OTG_CRC1_WINDOWA_X_START_READBACK, mask_sh),\ - SF(OTG0_OTG_CRC1_WINDOWA_X_CONTROL_READBACK, OTG_CRC1_WINDOWA_X_END_READBACK, mask_sh),\ - SF(OTG0_OTG_CRC1_WINDOWA_Y_CONTROL_READBACK, OTG_CRC1_WINDOWA_Y_START_READBACK, mask_sh),\ - SF(OTG0_OTG_CRC1_WINDOWA_Y_CONTROL_READBACK, OTG_CRC1_WINDOWA_Y_END_READBACK, mask_sh),\ - SF(OTG0_OTG_CRC1_WINDOWB_X_CONTROL_READBACK, OTG_CRC1_WINDOWB_X_START_READBACK, mask_sh),\ - SF(OTG0_OTG_CRC1_WINDOWB_X_CONTROL_READBACK, OTG_CRC1_WINDOWB_X_END_READBACK, mask_sh),\ - SF(OTG0_OTG_CRC1_WINDOWB_Y_CONTROL_READBACK, OTG_CRC1_WINDOWB_Y_START_READBACK, mask_sh),\ - SF(OTG0_OTG_CRC1_WINDOWB_Y_CONTROL_READBACK, OTG_CRC1_WINDOWB_Y_END_READBACK, mask_sh),\ - SF(OPTC_CLOCK_CONTROL, OPTC_FGCG_REP_DIS, mask_sh) - -void dcn35_timing_generator_init(struct optc *optc1); - -void dcn35_timing_generator_set_fgcg(struct optc *optc1, bool enable); - -#endif /* __DC_OPTC_DCN35_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_pg_cntl.c b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_pg_cntl.c index d19db8e9b8a54f..53bd0ae4bab5ed 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_pg_cntl.c +++ b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_pg_cntl.c @@ -342,13 +342,6 @@ void pg_cntl35_io_clk_pg_control(struct pg_cntl *pg_cntl, bool power_on) pg_cntl->pg_res_enable[PG_DCIO] = power_on; } -void pg_cntl35_set_force_poweron_domain22(struct pg_cntl *pg_cntl, bool power_on) -{ - struct dcn_pg_cntl *pg_cntl_dcn = TO_DCN_PG_CNTL(pg_cntl); - - REG_UPDATE(DOMAIN22_PG_CONFIG, DOMAIN_POWER_FORCEON, power_on ? 1 : 0); -} - static bool pg_cntl35_plane_otg_status(struct pg_cntl *pg_cntl) { struct dcn_pg_cntl *pg_cntl_dcn = TO_DCN_PG_CNTL(pg_cntl); @@ -518,8 +511,7 @@ static const struct pg_cntl_funcs pg_cntl35_funcs = { .mpcc_pg_control = pg_cntl35_mpcc_pg_control, .opp_pg_control = pg_cntl35_opp_pg_control, .optc_pg_control = pg_cntl35_optc_pg_control, - .dwb_pg_control = pg_cntl35_dwb_pg_control, - .set_force_poweron_domain22 = pg_cntl35_set_force_poweron_domain22 + .dwb_pg_control = pg_cntl35_dwb_pg_control }; struct pg_cntl *pg_cntl35_create( diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_pg_cntl.h b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_pg_cntl.h index 069dae08e2224b..3de240884d22fa 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_pg_cntl.h +++ b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_pg_cntl.h @@ -183,7 +183,6 @@ void pg_cntl35_optc_pg_control(struct pg_cntl *pg_cntl, unsigned int optc_inst, bool power_on); void pg_cntl35_dwb_pg_control(struct pg_cntl *pg_cntl, bool power_on); void pg_cntl35_init_pg_status(struct pg_cntl *pg_cntl); -void pg_cntl35_set_force_poweron_domain22(struct pg_cntl *pg_cntl, bool power_on); struct pg_cntl *pg_cntl35_create( struct dc_context *ctx, diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_resource.c b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_resource.c deleted file mode 100644 index 70ef1e7ff84113..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_resource.c +++ /dev/null @@ -1,2148 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * 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 "dm_services.h" -#include "dc.h" - -#include "dcn31/dcn31_init.h" -#include "dcn35/dcn35_init.h" - -#include "resource.h" -#include "include/irq_service_interface.h" -#include "dcn35_resource.h" -#include "dml2/dml2_wrapper.h" - -#include "dcn20/dcn20_resource.h" -#include "dcn30/dcn30_resource.h" -#include "dcn31/dcn31_resource.h" -#include "dcn32/dcn32_resource.h" - -#include "dcn10/dcn10_ipp.h" -#include "dcn30/dcn30_hubbub.h" -#include "dcn31/dcn31_hubbub.h" -#include "dcn35/dcn35_hubbub.h" -#include "dcn32/dcn32_mpc.h" -#include "dcn35/dcn35_hubp.h" -#include "irq/dcn35/irq_service_dcn35.h" -#include "dcn35/dcn35_dpp.h" -#include "dcn35/dcn35_optc.h" -#include "dcn20/dcn20_hwseq.h" -#include "dcn30/dcn30_hwseq.h" -#include "dce110/dce110_hwseq.h" -#include "dcn35/dcn35_opp.h" -#include "dcn35/dcn35_dsc.h" -#include "dcn30/dcn30_vpg.h" -#include "dcn30/dcn30_afmt.h" -#include "dcn31/dcn31_dio_link_encoder.h" -#include "dcn35/dcn35_dio_stream_encoder.h" -#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 "link.h" -#include "dcn31/dcn31_apg.h" -#include "dcn32/dcn32_dio_link_encoder.h" -#include "dcn31/dcn31_vpg.h" -#include "dcn31/dcn31_afmt.h" -#include "dce/dce_clock_source.h" -#include "dce/dce_audio.h" -#include "dce/dce_hwseq.h" -#include "clk_mgr.h" -#include "virtual/virtual_stream_encoder.h" -#include "dce110/dce110_resource.h" -#include "dml/display_mode_vba.h" -#include "dcn35/dcn35_dccg.h" -#include "dcn35/dcn35_pg_cntl.h" -#include "dcn10/dcn10_resource.h" -#include "dcn31/dcn31_panel_cntl.h" -#include "dcn35/dcn35_hwseq.h" -#include "dcn35_dio_link_encoder.h" -#include "dml/dcn31/dcn31_fpu.h" /*todo*/ -#include "dml/dcn35/dcn35_fpu.h" -#include "dcn35/dcn35_dwb.h" -#include "dcn35/dcn35_mmhubbub.h" - -#include "dcn/dcn_3_5_0_offset.h" -#include "dcn/dcn_3_5_0_sh_mask.h" -#include "nbio/nbio_7_11_0_offset.h" -#include "mmhub/mmhub_3_3_0_offset.h" -#include "mmhub/mmhub_3_3_0_sh_mask.h" - -#define DSCC0_DSCC_CONFIG0__ICH_RESET_AT_END_OF_LINE__SHIFT 0x0 -#define DSCC0_DSCC_CONFIG0__ICH_RESET_AT_END_OF_LINE_MASK 0x0000000FL - -#include "reg_helper.h" -#include "dce/dmub_abm.h" -#include "dce/dmub_psr.h" -#include "dce/dce_aux.h" -#include "dce/dce_i2c.h" -#include "dml/dcn31/display_mode_vba_31.h" /*temp*/ -#include "vm_helper.h" -#include "dcn20/dcn20_vmid.h" - -#include "link_enc_cfg.h" -#define DC_LOGGER_INIT(logger) - -enum dcn35_clk_src_array_id { - DCN35_CLK_SRC_PLL0, - DCN35_CLK_SRC_PLL1, - DCN35_CLK_SRC_PLL2, - DCN35_CLK_SRC_PLL3, - DCN35_CLK_SRC_PLL4, - DCN35_CLK_SRC_TOTAL -}; - -/* begin ********************* - * macros to expend register list macro defined in HW object header file - */ - -/* DCN */ -/* TODO awful hack. fixup dcn20_dwb.h */ -#undef BASE_INNER -#define BASE_INNER(seg) ctx->dcn_reg_offsets[seg] - -#define BASE(seg) BASE_INNER(seg) - -#define SR(reg_name)\ - REG_STRUCT.reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ - reg ## reg_name - -#define SR_ARR(reg_name, id) \ - REG_STRUCT[id].reg_name = BASE(reg##reg_name##_BASE_IDX) + reg##reg_name - -#define SR_ARR_INIT(reg_name, id, value) \ - REG_STRUCT[id].reg_name = value - -#define SRI(reg_name, block, id)\ - REG_STRUCT.reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRI_ARR(reg_name, block, id)\ - REG_STRUCT[id].reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SR_ARR_I2C(reg_name, id) \ - REG_STRUCT[id-1].reg_name = BASE(reg##reg_name##_BASE_IDX) + reg##reg_name - -#define SRI_ARR_I2C(reg_name, block, id)\ - REG_STRUCT[id-1].reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRI_ARR_ALPHABET(reg_name, block, index, id)\ - REG_STRUCT[index].reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRI2(reg_name, block, id)\ - .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ - reg ## reg_name - -#define SRI2_ARR(reg_name, block, id)\ - REG_STRUCT[id].reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ - reg ## reg_name - -#define SRIR(var_name, reg_name, block, id)\ - .var_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRII(reg_name, block, id)\ - REG_STRUCT.reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRII_ARR_2(reg_name, block, id, inst)\ - REG_STRUCT[inst].reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRII_MPC_RMU(reg_name, block, id)\ - .RMU##_##reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define SRII_DWB(reg_name, temp_name, block, id)\ - REG_STRUCT.reg_name[id] = BASE(reg ## block ## id ## _ ## temp_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## temp_name - -#define SF_DWB2(reg_name, block, id, field_name, post_fix) \ - .field_name = reg_name ## __ ## field_name ## post_fix - -#define DCCG_SRII(reg_name, block, id)\ - REG_STRUCT.block ## _ ## reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ - reg ## block ## id ## _ ## reg_name - -#define VUPDATE_SRII(reg_name, block, id)\ - REG_STRUCT.reg_name[id] = BASE(reg ## reg_name ## _ ## block ## id ## _BASE_IDX) + \ - reg ## reg_name ## _ ## block ## id - -/* NBIO */ -#define NBIO_BASE_INNER(seg) ctx->nbio_reg_offsets[seg] - -#define NBIO_BASE(seg) \ - NBIO_BASE_INNER(seg) - -#define NBIO_SR(reg_name)\ - REG_STRUCT.reg_name = NBIO_BASE(regBIF_BX2_ ## reg_name ## _BASE_IDX) + \ - regBIF_BX2_ ## reg_name - -#define NBIO_SR_ARR(reg_name, id)\ - REG_STRUCT[id].reg_name = NBIO_BASE(regBIF_BX2_ ## reg_name ## _BASE_IDX) + \ - regBIF_BX2_ ## reg_name - -#define bios_regs_init() \ - ( \ - NBIO_SR(BIOS_SCRATCH_3),\ - NBIO_SR(BIOS_SCRATCH_6)\ - ) - -static struct bios_registers bios_regs; - -#define clk_src_regs_init(index, pllid)\ - CS_COMMON_REG_LIST_DCN3_0_RI(index, pllid) - -static struct dce110_clk_src_regs clk_src_regs[5]; - -static const struct dce110_clk_src_shift cs_shift = { - CS_COMMON_MASK_SH_LIST_DCN3_1_4(__SHIFT) -}; - -static const struct dce110_clk_src_mask cs_mask = { - CS_COMMON_MASK_SH_LIST_DCN3_1_4(_MASK) -}; - -#define abm_regs_init(id)\ - ABM_DCN32_REG_LIST_RI(id) - -static struct dce_abm_registers abm_regs[4]; - -static const struct dce_abm_shift abm_shift = { - ABM_MASK_SH_LIST_DCN35(__SHIFT) -}; - -static const struct dce_abm_mask abm_mask = { - ABM_MASK_SH_LIST_DCN35(_MASK) -}; - -#define audio_regs_init(id)\ - AUD_COMMON_REG_LIST_RI(id) - -static struct dce_audio_registers audio_regs[7]; - - -#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ - SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ - SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ - AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) - -static const struct dce_audio_shift audio_shift = { - DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_audio_mask audio_mask = { - DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) -}; - -#define vpg_regs_init(id)\ - VPG_DCN31_REG_LIST_RI(id) - -static struct dcn31_vpg_registers vpg_regs[10]; - -static const struct dcn31_vpg_shift vpg_shift = { - DCN31_VPG_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn31_vpg_mask vpg_mask = { - DCN31_VPG_MASK_SH_LIST(_MASK) -}; - -#define afmt_regs_init(id)\ - AFMT_DCN31_REG_LIST_RI(id) - -static struct dcn31_afmt_registers afmt_regs[6]; - -static const struct dcn31_afmt_shift afmt_shift = { - DCN31_AFMT_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn31_afmt_mask afmt_mask = { - DCN31_AFMT_MASK_SH_LIST(_MASK) -}; - -#define apg_regs_init(id)\ - APG_DCN31_REG_LIST_RI(id) - -static struct dcn31_apg_registers apg_regs[4]; - -static const struct dcn31_apg_shift apg_shift = { - DCN31_APG_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn31_apg_mask apg_mask = { - DCN31_APG_MASK_SH_LIST(_MASK) -}; - -#define stream_enc_regs_init(id)\ - SE_DCN35_REG_LIST_RI(id) - -static struct dcn10_stream_enc_registers stream_enc_regs[5]; - -static const struct dcn10_stream_encoder_shift se_shift = { - SE_COMMON_MASK_SH_LIST_DCN35(__SHIFT) -}; - -static const struct dcn10_stream_encoder_mask se_mask = { - SE_COMMON_MASK_SH_LIST_DCN35(_MASK) -}; - -#define aux_regs_init(id)\ - DCN2_AUX_REG_LIST_RI(id) - -static struct dcn10_link_enc_aux_registers link_enc_aux_regs[5]; - -#define hpd_regs_init(id)\ - HPD_REG_LIST_RI(id) - -static struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[5]; - - -static const struct dce110_aux_registers_shift aux_shift = { - DCN_AUX_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce110_aux_registers_mask aux_mask = { - DCN_AUX_MASK_SH_LIST(_MASK) -}; - -#define link_regs_init(id, phyid)\ - ( \ - LE_DCN35_REG_LIST_RI(id), \ - UNIPHY_DCN2_REG_LIST_RI(id, phyid)\ - ) - -static struct dcn10_link_enc_registers link_enc_regs[5]; - -static const struct dcn10_link_enc_shift le_shift = { - LINK_ENCODER_MASK_SH_LIST_DCN35(__SHIFT), \ - //DPCS_DCN31_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn10_link_enc_mask le_mask = { - LINK_ENCODER_MASK_SH_LIST_DCN35(_MASK), \ - //DPCS_DCN31_MASK_SH_LIST(_MASK) -}; - -#define hpo_dp_stream_encoder_reg_init(id)\ - DCN3_1_HPO_DP_STREAM_ENC_REG_LIST_RI(id) - -static struct dcn31_hpo_dp_stream_encoder_registers hpo_dp_stream_enc_regs[4]; - -static const struct dcn31_hpo_dp_stream_encoder_shift hpo_dp_se_shift = { - DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn31_hpo_dp_stream_encoder_mask hpo_dp_se_mask = { - DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(_MASK) -}; - -#define hpo_dp_link_encoder_reg_init(id)\ - DCN3_1_HPO_DP_LINK_ENC_REG_LIST_RI(id) - /*DCN3_1_RDPCSTX_REG_LIST(0),*/ - /*DCN3_1_RDPCSTX_REG_LIST(1),*/ - /*DCN3_1_RDPCSTX_REG_LIST(2),*/ - /*DCN3_1_RDPCSTX_REG_LIST(3),*/ - -static struct dcn31_hpo_dp_link_encoder_registers hpo_dp_link_enc_regs[2]; - -static const struct dcn31_hpo_dp_link_encoder_shift hpo_dp_le_shift = { - DCN3_1_HPO_DP_LINK_ENC_COMMON_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn31_hpo_dp_link_encoder_mask hpo_dp_le_mask = { - DCN3_1_HPO_DP_LINK_ENC_COMMON_MASK_SH_LIST(_MASK) -}; - -#define dpp_regs_init(id)\ - DPP_REG_LIST_DCN35_RI(id) - -static struct dcn3_dpp_registers dpp_regs[4]; - -static const struct dcn35_dpp_shift tf_shift = { - DPP_REG_LIST_SH_MASK_DCN35(__SHIFT) -}; - -static const struct dcn35_dpp_mask tf_mask = { - DPP_REG_LIST_SH_MASK_DCN35(_MASK) -}; - -#define opp_regs_init(id)\ - OPP_REG_LIST_DCN35_RI(id) - -static struct dcn35_opp_registers opp_regs[4]; - -static const struct dcn35_opp_shift opp_shift = { - OPP_MASK_SH_LIST_DCN35(__SHIFT) -}; - -static const struct dcn35_opp_mask opp_mask = { - OPP_MASK_SH_LIST_DCN35(_MASK) -}; - -#define aux_engine_regs_init(id)\ - ( \ - AUX_COMMON_REG_LIST0_RI(id), \ - SR_ARR_INIT(AUXN_IMPCAL, id, 0), \ - SR_ARR_INIT(AUXP_IMPCAL, id, 0), \ - SR_ARR_INIT(AUX_RESET_MASK, id, DP_AUX0_AUX_CONTROL__AUX_RESET_MASK) \ - ) - -static struct dce110_aux_registers aux_engine_regs[5]; - -#define dwbc_regs_dcn3_init(id)\ - DWBC_COMMON_REG_LIST_DCN30_RI(id) - -static struct dcn30_dwbc_registers dwbc35_regs[1]; - -static const struct dcn35_dwbc_shift dwbc35_shift = { - DWBC_COMMON_MASK_SH_LIST_DCN35(__SHIFT) -}; - -static const struct dcn35_dwbc_mask dwbc35_mask = { - DWBC_COMMON_MASK_SH_LIST_DCN35(_MASK) -}; - -#define mcif_wb_regs_dcn3_init(id)\ - MCIF_WB_COMMON_REG_LIST_DCN3_5_RI(id) - -static struct dcn35_mmhubbub_registers mcif_wb35_regs[1]; - -static const struct dcn35_mmhubbub_shift mcif_wb35_shift = { - MCIF_WB_COMMON_MASK_SH_LIST_DCN3_5(__SHIFT) -}; - -static const struct dcn35_mmhubbub_mask mcif_wb35_mask = { - MCIF_WB_COMMON_MASK_SH_LIST_DCN3_5(_MASK) -}; - -#define dsc_regsDCN35_init(id)\ - DSC_REG_LIST_DCN20_RI(id) - -static struct dcn20_dsc_registers dsc_regs[4]; - -static const struct dcn35_dsc_shift dsc_shift = { - DSC_REG_LIST_SH_MASK_DCN35(__SHIFT) -}; - -static const struct dcn35_dsc_mask dsc_mask = { - DSC_REG_LIST_SH_MASK_DCN35(_MASK) -}; - -static struct dcn30_mpc_registers mpc_regs; - -#define dcn_mpc_regs_init() \ - MPC_REG_LIST_DCN3_2_RI(0),\ - MPC_REG_LIST_DCN3_2_RI(1),\ - MPC_REG_LIST_DCN3_2_RI(2),\ - MPC_REG_LIST_DCN3_2_RI(3),\ - MPC_OUT_MUX_REG_LIST_DCN3_0_RI(0),\ - MPC_OUT_MUX_REG_LIST_DCN3_0_RI(1),\ - MPC_OUT_MUX_REG_LIST_DCN3_0_RI(2),\ - MPC_OUT_MUX_REG_LIST_DCN3_0_RI(3),\ - MPC_DWB_MUX_REG_LIST_DCN3_0_RI(0) - -static const struct dcn30_mpc_shift mpc_shift = { - MPC_COMMON_MASK_SH_LIST_DCN32(__SHIFT) -}; - -static const struct dcn30_mpc_mask mpc_mask = { - MPC_COMMON_MASK_SH_LIST_DCN32(_MASK) -}; - -#define optc_regs_init(id)\ - OPTC_COMMON_REG_LIST_DCN3_5_RI(id) - -static struct dcn_optc_registers optc_regs[4]; - -static const struct dcn_optc_shift optc_shift = { - OPTC_COMMON_MASK_SH_LIST_DCN3_5(__SHIFT) -}; - -static const struct dcn_optc_mask optc_mask = { - OPTC_COMMON_MASK_SH_LIST_DCN3_5(_MASK) -}; - -#define hubp_regs_init(id)\ - HUBP_REG_LIST_DCN30_RI(id) - -static struct dcn_hubp2_registers hubp_regs[4]; - - -static const struct dcn35_hubp2_shift hubp_shift = { - HUBP_MASK_SH_LIST_DCN35(__SHIFT) -}; - -static const struct dcn35_hubp2_mask hubp_mask = { - HUBP_MASK_SH_LIST_DCN35(_MASK) -}; - -static struct dcn_hubbub_registers hubbub_reg; - -#define hubbub_reg_init()\ - HUBBUB_REG_LIST_DCN35(0) - -static const struct dcn_hubbub_shift hubbub_shift = { - HUBBUB_MASK_SH_LIST_DCN35(__SHIFT) -}; - -static const struct dcn_hubbub_mask hubbub_mask = { - HUBBUB_MASK_SH_LIST_DCN35(_MASK) -}; - -static struct dccg_registers dccg_regs; - -#define dccg_regs_init()\ - DCCG_REG_LIST_DCN35() - -static const struct dccg_shift dccg_shift = { - DCCG_MASK_SH_LIST_DCN35(__SHIFT) -}; - -static const struct dccg_mask dccg_mask = { - DCCG_MASK_SH_LIST_DCN35(_MASK) -}; - -static struct pg_cntl_registers pg_cntl_regs; - -#define pg_cntl_dcn35_regs_init() \ - PG_CNTL_REG_LIST_DCN35() - -static const struct pg_cntl_shift pg_cntl_shift = { - PG_CNTL_MASK_SH_LIST_DCN35(__SHIFT) -}; - -static const struct pg_cntl_mask pg_cntl_mask = { - PG_CNTL_MASK_SH_LIST_DCN35(_MASK) -}; - -#define SRII2(reg_name_pre, reg_name_post, id)\ - .reg_name_pre ## _ ## reg_name_post[id] = BASE(reg ## reg_name_pre \ - ## id ## _ ## reg_name_post ## _BASE_IDX) + \ - reg ## reg_name_pre ## id ## _ ## reg_name_post - -static struct dce_hwseq_registers hwseq_reg; - -#define hwseq_reg_init()\ - HWSEQ_DCN35_REG_LIST() - -#define HWSEQ_DCN35_MASK_SH_LIST(mask_sh)\ - HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ - HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \ - HWS_SF(, DCHUBBUB_ARB_HOSTVM_CNTL, DISABLE_HOSTVM_FORCE_ALLOW_PSTATE, mask_sh), \ - HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN19_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN19_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN22_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN22_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN23_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN23_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN24_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN24_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN25_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ - HWS_SF(, DOMAIN25_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ - HWS_SF(, DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN16_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN17_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN18_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN19_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN22_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN23_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN24_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DOMAIN25_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \ - HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh), \ - HWS_SF(, HPO_TOP_CLOCK_CONTROL, HPO_HDMISTREAMCLK_G_GATE_DIS, mask_sh), \ - HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_UNASSIGNED_PWR_MODE, mask_sh), \ - HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_VBLANK_PWR_MODE, mask_sh), \ - HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh), \ - HWS_SF(, HPO_TOP_HW_CONTROL, HPO_IO_EN, mask_sh),\ - HWS_SF(, DMU_CLK_CNTL, DISPCLK_R_DMU_GATE_DIS, mask_sh),\ - HWS_SF(, DMU_CLK_CNTL, DISPCLK_G_RBBMIF_GATE_DIS, mask_sh),\ - HWS_SF(, DMU_CLK_CNTL, RBBMIF_FGCG_REP_DIS, mask_sh),\ - HWS_SF(, DMU_CLK_CNTL, DPREFCLK_ALLOW_DS_CLKSTOP, mask_sh),\ - HWS_SF(, DMU_CLK_CNTL, DISPCLK_ALLOW_DS_CLKSTOP, mask_sh),\ - HWS_SF(, DMU_CLK_CNTL, DPPCLK_ALLOW_DS_CLKSTOP, mask_sh),\ - HWS_SF(, DMU_CLK_CNTL, DTBCLK_ALLOW_DS_CLKSTOP, mask_sh),\ - HWS_SF(, DMU_CLK_CNTL, DCFCLK_ALLOW_DS_CLKSTOP, mask_sh),\ - HWS_SF(, DMU_CLK_CNTL, DPIACLK_ALLOW_DS_CLKSTOP, mask_sh),\ - HWS_SF(, DMU_CLK_CNTL, LONO_FGCG_REP_DIS, mask_sh),\ - HWS_SF(, DMU_CLK_CNTL, LONO_DISPCLK_GATE_DISABLE, mask_sh),\ - HWS_SF(, DMU_CLK_CNTL, LONO_SOCCLK_GATE_DISABLE, mask_sh),\ - HWS_SF(, DMU_CLK_CNTL, LONO_DMCUBCLK_GATE_DISABLE, mask_sh),\ - HWS_SF(, DCCG_GATE_DISABLE_CNTL2, SYMCLKA_FE_GATE_DISABLE, mask_sh), \ - HWS_SF(, DCCG_GATE_DISABLE_CNTL2, SYMCLKB_FE_GATE_DISABLE, mask_sh), \ - HWS_SF(, DCCG_GATE_DISABLE_CNTL2, SYMCLKC_FE_GATE_DISABLE, mask_sh), \ - HWS_SF(, DCCG_GATE_DISABLE_CNTL2, SYMCLKD_FE_GATE_DISABLE, mask_sh), \ - HWS_SF(, DCCG_GATE_DISABLE_CNTL2, SYMCLKE_FE_GATE_DISABLE, mask_sh), \ - HWS_SF(, DCCG_GATE_DISABLE_CNTL2, HDMICHARCLK0_GATE_DISABLE, mask_sh), \ - HWS_SF(, DCCG_GATE_DISABLE_CNTL2, SYMCLKA_GATE_DISABLE, mask_sh), \ - HWS_SF(, DCCG_GATE_DISABLE_CNTL2, SYMCLKB_GATE_DISABLE, mask_sh), \ - HWS_SF(, DCCG_GATE_DISABLE_CNTL2, SYMCLKC_GATE_DISABLE, mask_sh), \ - HWS_SF(, DCCG_GATE_DISABLE_CNTL2, SYMCLKD_GATE_DISABLE, mask_sh), \ - HWS_SF(, DCCG_GATE_DISABLE_CNTL2, SYMCLKE_GATE_DISABLE, mask_sh), \ - HWS_SF(, DCCG_GATE_DISABLE_CNTL2, PHYASYMCLK_ROOT_GATE_DISABLE, mask_sh), \ - HWS_SF(, DCCG_GATE_DISABLE_CNTL2, PHYBSYMCLK_ROOT_GATE_DISABLE, mask_sh), \ - HWS_SF(, DCCG_GATE_DISABLE_CNTL2, PHYCSYMCLK_ROOT_GATE_DISABLE, mask_sh), \ - HWS_SF(, DCCG_GATE_DISABLE_CNTL2, PHYDSYMCLK_ROOT_GATE_DISABLE, mask_sh), \ - HWS_SF(, DCCG_GATE_DISABLE_CNTL2, PHYESYMCLK_ROOT_GATE_DISABLE, mask_sh) - -static const struct dce_hwseq_shift hwseq_shift = { - HWSEQ_DCN35_MASK_SH_LIST(__SHIFT) -}; - -static const struct dce_hwseq_mask hwseq_mask = { - HWSEQ_DCN35_MASK_SH_LIST(_MASK) -}; - -#define vmid_regs_init(id)\ - DCN20_VMID_REG_LIST_RI(id) - -static struct dcn_vmid_registers vmid_regs[16]; - -static const struct dcn20_vmid_shift vmid_shifts = { - DCN20_VMID_MASK_SH_LIST(__SHIFT) -}; - -static const struct dcn20_vmid_mask vmid_masks = { - DCN20_VMID_MASK_SH_LIST(_MASK) -}; - -static const struct resource_caps res_cap_dcn35 = { - .num_timing_generator = 4, - .num_opp = 4, - .num_video_plane = 4, - .num_audio = 5, - .num_stream_encoder = 5, - .num_dig_link_enc = 5, - .num_hpo_dp_stream_encoder = 4, - .num_hpo_dp_link_encoder = 2, - .num_pll = 4,/*1 c10 edp, 3xc20 combo PHY*/ - .num_dwb = 1, - .num_ddc = 5, - .num_vmid = 16, - .num_mpc_3dlut = 2, - .num_dsc = 4, -}; - -static const struct dc_plane_cap plane_cap = { - .type = DC_PLANE_TYPE_DCN_UNIVERSAL, - .per_pixel_alpha = true, - - .pixel_format_support = { - .argb8888 = true, - .nv12 = true, - .fp16 = true, - .p010 = true, - .ayuv = false, - }, - - .max_upscale_factor = { - .argb8888 = 16000, - .nv12 = 16000, - .fp16 = 16000 - }, - - // 6:1 downscaling ratio: 1000/6 = 166.666 - .max_downscale_factor = { - .argb8888 = 167, - .nv12 = 167, - .fp16 = 167 - }, - 64, - 64 -}; - -static const struct dc_debug_options debug_defaults_drv = { - .disable_dmcu = true, - .force_abm_enable = false, - .timing_trace = false, - .clock_trace = true, - .disable_pplib_clock_request = false, - .pipe_split_policy = MPC_SPLIT_AVOID, - .force_single_disp_pipe_split = false, - .disable_dcc = DCC_ENABLE, - .disable_dpp_power_gate = true, - .disable_hubp_power_gate = true, - .disable_clock_gate = true, - .disable_dsc_power_gate = true, - .vsr_support = true, - .performance_trace = false, - .max_downscale_src_width = 4096,/*upto true 4k*/ - .disable_pplib_wm_range = false, - .scl_reset_length10 = true, - .sanity_checks = false, - .underflow_assert_delay_us = 0xFFFFFFFF, - .dwb_fi_phase = -1, // -1 = disable, - .dmub_command_table = true, - .pstate_enabled = true, - .use_max_lb = true, - .enable_mem_low_power = { - .bits = { - .vga = false, - .i2c = true, - .dmcu = false, // This is previously known to cause hang on S3 cycles if enabled - .dscl = true, - .cm = false, - .mpc = true, - .optc = true, - .vpg = true, - .afmt = true, - } - }, - .root_clock_optimization = { - .bits = { - .dpp = true, - .dsc = true,/*dscclk and dsc pg*/ - .hdmistream = true, - .hdmichar = true, - .dpstream = true, - .symclk32_se = true, - .symclk32_le = true, - .symclk_fe = true, - .physymclk = true, - .dpiasymclk = true, - } - }, - .seamless_boot_odm_combine = DML_FAIL_SOURCE_PIXEL_FORMAT, - .enable_z9_disable_interface = true, /* Allow support for the PMFW interface for disable Z9*/ - .using_dml2 = true, - .support_eDP1_5 = true, - .enable_hpo_pg_support = false, - .enable_legacy_fast_update = true, - .enable_single_display_2to1_odm_policy = false, - .disable_idle_power_optimizations = true, - .dmcub_emulation = false, - .disable_boot_optimizations = false, - .disable_unbounded_requesting = false, - .disable_mem_low_power = false, - //must match enable_single_display_2to1_odm_policy to support dynamic ODM transitions - .enable_double_buffered_dsc_pg_support = true, - .enable_dp_dig_pixel_rate_div_policy = 1, - .disable_z10 = false, - .ignore_pg = true, - .psp_disabled_wa = true, - .ips2_eval_delay_us = 200, - .ips2_entry_delay_us = 400 -}; - -static const struct dc_panel_config panel_config_defaults = { - .psr = { - .disable_psr = false, - .disallow_psrsu = false, - }, - .ilr = { - .optimize_edp_link_rate = true, - }, -}; - -static void dcn35_dpp_destroy(struct dpp **dpp) -{ - kfree(TO_DCN20_DPP(*dpp)); - *dpp = NULL; -} - -static struct dpp *dcn35_dpp_create(struct dc_context *ctx, uint32_t inst) -{ - struct dcn3_dpp *dpp = kzalloc(sizeof(struct dcn3_dpp), GFP_KERNEL); - bool success = (dpp != NULL); - - if (!success) - return NULL; - -#undef REG_STRUCT -#define REG_STRUCT dpp_regs - dpp_regs_init(0), - dpp_regs_init(1), - dpp_regs_init(2), - dpp_regs_init(3); - - success = dpp35_construct(dpp, ctx, inst, &dpp_regs[inst], &tf_shift, - &tf_mask); - if (success) { - dpp35_set_fgcg( - dpp, - ctx->dc->debug.enable_fine_grain_clock_gating.bits.dpp); - return &dpp->base; - } - - BREAK_TO_DEBUGGER(); - kfree(dpp); - return NULL; -} - -static struct output_pixel_processor *dcn35_opp_create( - struct dc_context *ctx, uint32_t inst) -{ - struct dcn20_opp *opp = - kzalloc(sizeof(struct dcn20_opp), GFP_KERNEL); - - if (!opp) { - BREAK_TO_DEBUGGER(); - return NULL; - } - -#undef REG_STRUCT -#define REG_STRUCT opp_regs - opp_regs_init(0), - opp_regs_init(1), - opp_regs_init(2), - opp_regs_init(3); - - dcn35_opp_construct(opp, ctx, inst, - &opp_regs[inst], &opp_shift, &opp_mask); - - dcn35_opp_set_fgcg(opp, ctx->dc->debug.enable_fine_grain_clock_gating.bits.opp); - - return &opp->base; -} - -static struct dce_aux *dcn31_aux_engine_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct aux_engine_dce110 *aux_engine = - kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); - - if (!aux_engine) - return NULL; - -#undef REG_STRUCT -#define REG_STRUCT aux_engine_regs - aux_engine_regs_init(0), - aux_engine_regs_init(1), - aux_engine_regs_init(2), - aux_engine_regs_init(3), - aux_engine_regs_init(4); - - dce110_aux_engine_construct(aux_engine, ctx, inst, - SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, - &aux_engine_regs[inst], - &aux_mask, - &aux_shift, - ctx->dc->caps.extended_aux_timeout_support); - - return &aux_engine->base; -} - -#define i2c_inst_regs_init(id)\ - I2C_HW_ENGINE_COMMON_REG_LIST_DCN30_RI(id) - -static struct dce_i2c_registers i2c_hw_regs[5]; - -static const struct dce_i2c_shift i2c_shifts = { - I2C_COMMON_MASK_SH_LIST_DCN35(__SHIFT) -}; - -static const struct dce_i2c_mask i2c_masks = { - I2C_COMMON_MASK_SH_LIST_DCN35(_MASK) -}; - -/* ========================================================== */ - -/* - * DPIA index | Preferred Encoder | Host Router - * 0 | C | 0 - * 1 | First Available | 0 - * 2 | D | 1 - * 3 | First Available | 1 - */ -/* ========================================================== */ -static const enum engine_id dpia_to_preferred_enc_id_table[] = { - ENGINE_ID_DIGC, - ENGINE_ID_DIGC, - ENGINE_ID_DIGD, - ENGINE_ID_DIGD -}; - -static enum engine_id dcn35_get_preferred_eng_id_dpia(unsigned int dpia_index) -{ - return dpia_to_preferred_enc_id_table[dpia_index]; -} - -static struct dce_i2c_hw *dcn31_i2c_hw_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dce_i2c_hw *dce_i2c_hw = - kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); - - if (!dce_i2c_hw) - return NULL; - -#undef REG_STRUCT -#define REG_STRUCT i2c_hw_regs - i2c_inst_regs_init(1), - i2c_inst_regs_init(2), - i2c_inst_regs_init(3), - i2c_inst_regs_init(4), - i2c_inst_regs_init(5); - - dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst, - &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); - - return dce_i2c_hw; -} -static struct mpc *dcn35_mpc_create( - struct dc_context *ctx, - int num_mpcc, - int num_rmu) -{ - struct dcn30_mpc *mpc30 = kzalloc(sizeof(struct dcn30_mpc), GFP_KERNEL); - - if (!mpc30) - return NULL; - -#undef REG_STRUCT -#define REG_STRUCT mpc_regs - dcn_mpc_regs_init(); - - dcn32_mpc_construct(mpc30, ctx, - &mpc_regs, - &mpc_shift, - &mpc_mask, - num_mpcc, - num_rmu); - - return &mpc30->base; -} - -static struct hubbub *dcn35_hubbub_create(struct dc_context *ctx) -{ - int i; - - struct dcn20_hubbub *hubbub3 = kzalloc(sizeof(struct dcn20_hubbub), - GFP_KERNEL); - - if (!hubbub3) - return NULL; - -#undef REG_STRUCT -#define REG_STRUCT hubbub_reg - hubbub_reg_init(); - -#undef REG_STRUCT -#define REG_STRUCT vmid_regs - vmid_regs_init(0), - vmid_regs_init(1), - vmid_regs_init(2), - vmid_regs_init(3), - vmid_regs_init(4), - vmid_regs_init(5), - vmid_regs_init(6), - vmid_regs_init(7), - vmid_regs_init(8), - vmid_regs_init(9), - vmid_regs_init(10), - vmid_regs_init(11), - vmid_regs_init(12), - vmid_regs_init(13), - vmid_regs_init(14), - vmid_regs_init(15); - - hubbub35_construct(hubbub3, ctx, - &hubbub_reg, - &hubbub_shift, - &hubbub_mask, - 384,/*ctx->dc->dml.ip.det_buffer_size_kbytes,*/ - 8, /*ctx->dc->dml.ip.pixel_chunk_size_kbytes,*/ - 1792 /*ctx->dc->dml.ip.config_return_buffer_size_in_kbytes*/); - - - for (i = 0; i < res_cap_dcn35.num_vmid; i++) { - struct dcn20_vmid *vmid = &hubbub3->vmid[i]; - - vmid->ctx = ctx; - - vmid->regs = &vmid_regs[i]; - vmid->shifts = &vmid_shifts; - vmid->masks = &vmid_masks; - } - - return &hubbub3->base; -} - -static struct timing_generator *dcn35_timing_generator_create( - struct dc_context *ctx, - uint32_t instance) -{ - struct optc *tgn10 = - kzalloc(sizeof(struct optc), GFP_KERNEL); - - if (!tgn10) - return NULL; - -#undef REG_STRUCT -#define REG_STRUCT optc_regs - optc_regs_init(0), - optc_regs_init(1), - optc_regs_init(2), - optc_regs_init(3); - - tgn10->base.inst = instance; - tgn10->base.ctx = ctx; - - tgn10->tg_regs = &optc_regs[instance]; - tgn10->tg_shift = &optc_shift; - tgn10->tg_mask = &optc_mask; - - dcn35_timing_generator_init(tgn10); - - return &tgn10->base; -} - -static const struct encoder_feature_support link_enc_feature = { - .max_hdmi_deep_color = COLOR_DEPTH_121212, - .max_hdmi_pixel_clock = 600000, - .hdmi_ycbcr420_supported = true, - .dp_ycbcr420_supported = true, - .fec_supported = true, - .flags.bits.IS_HBR2_CAPABLE = true, - .flags.bits.IS_HBR3_CAPABLE = true, - .flags.bits.IS_TPS3_CAPABLE = true, - .flags.bits.IS_TPS4_CAPABLE = true -}; - -static struct link_encoder *dcn35_link_encoder_create( - struct dc_context *ctx, - const struct encoder_init_data *enc_init_data) -{ - struct dcn20_link_encoder *enc20 = - kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); - - if (!enc20) - return NULL; - -#undef REG_STRUCT -#define REG_STRUCT link_enc_aux_regs - aux_regs_init(0), - aux_regs_init(1), - aux_regs_init(2), - aux_regs_init(3), - aux_regs_init(4); - -#undef REG_STRUCT -#define REG_STRUCT link_enc_hpd_regs - hpd_regs_init(0), - hpd_regs_init(1), - hpd_regs_init(2), - hpd_regs_init(3), - hpd_regs_init(4); - -#undef REG_STRUCT -#define REG_STRUCT link_enc_regs - link_regs_init(0, A), - link_regs_init(1, B), - link_regs_init(2, C), - link_regs_init(3, D), - link_regs_init(4, E); - - dcn35_link_encoder_construct(enc20, - enc_init_data, - &link_enc_feature, - &link_enc_regs[enc_init_data->transmitter], - &link_enc_aux_regs[enc_init_data->channel - 1], - &link_enc_hpd_regs[enc_init_data->hpd_source], - &le_shift, - &le_mask); - - return &enc20->enc10.base; -} - -/* Create a minimal link encoder object not associated with a particular - * physical connector. - * resource_funcs.link_enc_create_minimal - */ -static struct link_encoder *dcn31_link_enc_create_minimal( - struct dc_context *ctx, enum engine_id eng_id) -{ - struct dcn20_link_encoder *enc20; - - if ((eng_id - ENGINE_ID_DIGA) > ctx->dc->res_pool->res_cap->num_dig_link_enc) - return NULL; - - enc20 = kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); - if (!enc20) - return NULL; - - dcn31_link_encoder_construct_minimal( - enc20, - ctx, - &link_enc_feature, - &link_enc_regs[eng_id - ENGINE_ID_DIGA], - eng_id); - - return &enc20->enc10.base; -} - -static struct panel_cntl *dcn31_panel_cntl_create(const struct panel_cntl_init_data *init_data) -{ - struct dcn31_panel_cntl *panel_cntl = - kzalloc(sizeof(struct dcn31_panel_cntl), GFP_KERNEL); - - if (!panel_cntl) - return NULL; - - dcn31_panel_cntl_construct(panel_cntl, init_data); - - return &panel_cntl->base; -} - -static void read_dce_straps( - struct dc_context *ctx, - struct resource_straps *straps) -{ - generic_reg_get(ctx, regDC_PINSTRAPS + BASE(regDC_PINSTRAPS_BASE_IDX), - FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio); - -} - -static struct audio *dcn31_create_audio( - struct dc_context *ctx, unsigned int inst) -{ - -#undef REG_STRUCT -#define REG_STRUCT audio_regs - audio_regs_init(0), - audio_regs_init(1), - audio_regs_init(2), - audio_regs_init(3), - audio_regs_init(4); - audio_regs_init(5); - audio_regs_init(6); - - return dce_audio_create(ctx, inst, - &audio_regs[inst], &audio_shift, &audio_mask); -} - -static struct vpg *dcn31_vpg_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn31_vpg *vpg31 = kzalloc(sizeof(struct dcn31_vpg), GFP_KERNEL); - - if (!vpg31) - return NULL; - -#undef REG_STRUCT -#define REG_STRUCT vpg_regs - vpg_regs_init(0), - vpg_regs_init(1), - vpg_regs_init(2), - vpg_regs_init(3), - vpg_regs_init(4), - vpg_regs_init(5), - vpg_regs_init(6), - vpg_regs_init(7), - vpg_regs_init(8), - vpg_regs_init(9); - - vpg31_construct(vpg31, ctx, inst, - &vpg_regs[inst], - &vpg_shift, - &vpg_mask); - - return &vpg31->base; -} - -static struct afmt *dcn31_afmt_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn31_afmt *afmt31 = kzalloc(sizeof(struct dcn31_afmt), GFP_KERNEL); - - if (!afmt31) - return NULL; - -#undef REG_STRUCT -#define REG_STRUCT afmt_regs - afmt_regs_init(0), - afmt_regs_init(1), - afmt_regs_init(2), - afmt_regs_init(3), - afmt_regs_init(4), - afmt_regs_init(5); - - afmt31_construct(afmt31, ctx, inst, - &afmt_regs[inst], - &afmt_shift, - &afmt_mask); - - // Light sleep by default, no need to power down here - - return &afmt31->base; -} - -static struct apg *dcn31_apg_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn31_apg *apg31 = kzalloc(sizeof(struct dcn31_apg), GFP_KERNEL); - - if (!apg31) - return NULL; - -#undef REG_STRUCT -#define REG_STRUCT apg_regs - apg_regs_init(0), - apg_regs_init(1), - apg_regs_init(2), - apg_regs_init(3); - - apg31_construct(apg31, ctx, inst, - &apg_regs[inst], - &apg_shift, - &apg_mask); - - return &apg31->base; -} - -static struct stream_encoder *dcn35_stream_encoder_create( - enum engine_id eng_id, - struct dc_context *ctx) -{ - struct dcn10_stream_encoder *enc1; - struct vpg *vpg; - struct afmt *afmt; - int vpg_inst; - int afmt_inst; - - /* Mapping of VPG, AFMT, DME register blocks to DIO block instance */ - if (eng_id <= ENGINE_ID_DIGF) { - vpg_inst = eng_id; - afmt_inst = eng_id; - } else - return NULL; - - enc1 = kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL); - vpg = dcn31_vpg_create(ctx, vpg_inst); - afmt = dcn31_afmt_create(ctx, afmt_inst); - - if (!enc1 || !vpg || !afmt) { - kfree(enc1); - kfree(vpg); - kfree(afmt); - return NULL; - } - -#undef REG_STRUCT -#define REG_STRUCT stream_enc_regs - stream_enc_regs_init(0), - stream_enc_regs_init(1), - stream_enc_regs_init(2), - stream_enc_regs_init(3), - stream_enc_regs_init(4); - - dcn35_dio_stream_encoder_construct(enc1, ctx, ctx->dc_bios, - eng_id, vpg, afmt, - &stream_enc_regs[eng_id], - &se_shift, &se_mask); - - return &enc1->base; -} - -static struct hpo_dp_stream_encoder *dcn31_hpo_dp_stream_encoder_create( - enum engine_id eng_id, - struct dc_context *ctx) -{ - struct dcn31_hpo_dp_stream_encoder *hpo_dp_enc31; - struct vpg *vpg; - struct apg *apg; - uint32_t hpo_dp_inst; - uint32_t vpg_inst; - uint32_t apg_inst; - - ASSERT((eng_id >= ENGINE_ID_HPO_DP_0) && (eng_id <= ENGINE_ID_HPO_DP_3)); - hpo_dp_inst = eng_id - ENGINE_ID_HPO_DP_0; - - /* Mapping of VPG register blocks to HPO DP block instance: - * VPG[6] -> HPO_DP[0] - * VPG[7] -> HPO_DP[1] - * VPG[8] -> HPO_DP[2] - * VPG[9] -> HPO_DP[3] - */ - vpg_inst = hpo_dp_inst + 6; - - /* Mapping of APG register blocks to HPO DP block instance: - * APG[0] -> HPO_DP[0] - * APG[1] -> HPO_DP[1] - * APG[2] -> HPO_DP[2] - * APG[3] -> HPO_DP[3] - */ - apg_inst = hpo_dp_inst; - - /* allocate HPO stream encoder and create VPG sub-block */ - hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_stream_encoder), GFP_KERNEL); - vpg = dcn31_vpg_create(ctx, vpg_inst); - apg = dcn31_apg_create(ctx, apg_inst); - - if (!hpo_dp_enc31 || !vpg || !apg) { - kfree(hpo_dp_enc31); - kfree(vpg); - kfree(apg); - return NULL; - } - -#undef REG_STRUCT -#define REG_STRUCT hpo_dp_stream_enc_regs - hpo_dp_stream_encoder_reg_init(0), - hpo_dp_stream_encoder_reg_init(1), - hpo_dp_stream_encoder_reg_init(2), - hpo_dp_stream_encoder_reg_init(3); - - dcn31_hpo_dp_stream_encoder_construct(hpo_dp_enc31, ctx, ctx->dc_bios, - hpo_dp_inst, eng_id, vpg, apg, - &hpo_dp_stream_enc_regs[hpo_dp_inst], - &hpo_dp_se_shift, &hpo_dp_se_mask); - - return &hpo_dp_enc31->base; -} - -static struct hpo_dp_link_encoder *dcn31_hpo_dp_link_encoder_create( - uint8_t inst, - struct dc_context *ctx) -{ - struct dcn31_hpo_dp_link_encoder *hpo_dp_enc31; - - /* allocate HPO link encoder */ - hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_link_encoder), GFP_KERNEL); - -#undef REG_STRUCT -#define REG_STRUCT hpo_dp_link_enc_regs - hpo_dp_link_encoder_reg_init(0), - hpo_dp_link_encoder_reg_init(1); - - hpo_dp_link_encoder31_construct(hpo_dp_enc31, ctx, inst, - &hpo_dp_link_enc_regs[inst], - &hpo_dp_le_shift, &hpo_dp_le_mask); - - return &hpo_dp_enc31->base; -} - -static struct dce_hwseq *dcn35_hwseq_create( - struct dc_context *ctx) -{ - struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); - -#undef REG_STRUCT -#define REG_STRUCT hwseq_reg - hwseq_reg_init(); - - if (hws) { - hws->ctx = ctx; - hws->regs = &hwseq_reg; - hws->shifts = &hwseq_shift; - hws->masks = &hwseq_mask; - } - return hws; -} -static const struct resource_create_funcs res_create_funcs = { - .read_dce_straps = read_dce_straps, - .create_audio = dcn31_create_audio, - .create_stream_encoder = dcn35_stream_encoder_create, - .create_hpo_dp_stream_encoder = dcn31_hpo_dp_stream_encoder_create, - .create_hpo_dp_link_encoder = dcn31_hpo_dp_link_encoder_create, - .create_hwseq = dcn35_hwseq_create, -}; - -static void dcn35_resource_destruct(struct dcn35_resource_pool *pool) -{ - unsigned int i; - - for (i = 0; i < pool->base.stream_enc_count; i++) { - if (pool->base.stream_enc[i] != NULL) { - if (pool->base.stream_enc[i]->vpg != NULL) { - kfree(DCN30_VPG_FROM_VPG(pool->base.stream_enc[i]->vpg)); - pool->base.stream_enc[i]->vpg = NULL; - } - if (pool->base.stream_enc[i]->afmt != NULL) { - kfree(DCN30_AFMT_FROM_AFMT(pool->base.stream_enc[i]->afmt)); - pool->base.stream_enc[i]->afmt = NULL; - } - kfree(DCN10STRENC_FROM_STRENC(pool->base.stream_enc[i])); - pool->base.stream_enc[i] = NULL; - } - } - - for (i = 0; i < pool->base.hpo_dp_stream_enc_count; i++) { - if (pool->base.hpo_dp_stream_enc[i] != NULL) { - if (pool->base.hpo_dp_stream_enc[i]->vpg != NULL) { - kfree(DCN30_VPG_FROM_VPG(pool->base.hpo_dp_stream_enc[i]->vpg)); - pool->base.hpo_dp_stream_enc[i]->vpg = NULL; - } - if (pool->base.hpo_dp_stream_enc[i]->apg != NULL) { - kfree(DCN31_APG_FROM_APG(pool->base.hpo_dp_stream_enc[i]->apg)); - pool->base.hpo_dp_stream_enc[i]->apg = NULL; - } - kfree(DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(pool->base.hpo_dp_stream_enc[i])); - pool->base.hpo_dp_stream_enc[i] = NULL; - } - } - - for (i = 0; i < pool->base.hpo_dp_link_enc_count; i++) { - if (pool->base.hpo_dp_link_enc[i] != NULL) { - kfree(DCN3_1_HPO_DP_LINK_ENC_FROM_HPO_LINK_ENC(pool->base.hpo_dp_link_enc[i])); - pool->base.hpo_dp_link_enc[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_dsc; i++) { - if (pool->base.dscs[i] != NULL) - dcn20_dsc_destroy(&pool->base.dscs[i]); - } - - if (pool->base.mpc != NULL) { - kfree(TO_DCN20_MPC(pool->base.mpc)); - pool->base.mpc = NULL; - } - if (pool->base.hubbub != NULL) { - kfree(pool->base.hubbub); - pool->base.hubbub = NULL; - } - for (i = 0; i < pool->base.pipe_count; i++) { - if (pool->base.dpps[i] != NULL) - dcn35_dpp_destroy(&pool->base.dpps[i]); - - if (pool->base.ipps[i] != NULL) - pool->base.ipps[i]->funcs->ipp_destroy(&pool->base.ipps[i]); - - if (pool->base.hubps[i] != NULL) { - kfree(TO_DCN20_HUBP(pool->base.hubps[i])); - pool->base.hubps[i] = NULL; - } - - if (pool->base.irqs != NULL) { - dal_irq_service_destroy(&pool->base.irqs); - } - } - - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - if (pool->base.engines[i] != NULL) - dce110_engine_destroy(&pool->base.engines[i]); - if (pool->base.hw_i2cs[i] != NULL) { - kfree(pool->base.hw_i2cs[i]); - pool->base.hw_i2cs[i] = NULL; - } - if (pool->base.sw_i2cs[i] != NULL) { - kfree(pool->base.sw_i2cs[i]); - pool->base.sw_i2cs[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_opp; i++) { - if (pool->base.opps[i] != NULL) - pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]); - } - - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - if (pool->base.timing_generators[i] != NULL) { - kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i])); - pool->base.timing_generators[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_dwb; i++) { - if (pool->base.dwbc[i] != NULL) { - kfree(TO_DCN30_DWBC(pool->base.dwbc[i])); - pool->base.dwbc[i] = NULL; - } - if (pool->base.mcif_wb[i] != NULL) { - kfree(TO_DCN30_MMHUBBUB(pool->base.mcif_wb[i])); - pool->base.mcif_wb[i] = NULL; - } - } - - for (i = 0; i < pool->base.audio_count; i++) { - if (pool->base.audios[i]) - dce_aud_destroy(&pool->base.audios[i]); - } - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] != NULL) { - dcn20_clock_source_destroy(&pool->base.clock_sources[i]); - pool->base.clock_sources[i] = NULL; - } - } - - for (i = 0; i < pool->base.res_cap->num_mpc_3dlut; i++) { - if (pool->base.mpc_lut[i] != NULL) { - dc_3dlut_func_release(pool->base.mpc_lut[i]); - pool->base.mpc_lut[i] = NULL; - } - if (pool->base.mpc_shaper[i] != NULL) { - dc_transfer_func_release(pool->base.mpc_shaper[i]); - pool->base.mpc_shaper[i] = NULL; - } - } - - if (pool->base.dp_clock_source != NULL) { - dcn20_clock_source_destroy(&pool->base.dp_clock_source); - pool->base.dp_clock_source = NULL; - } - - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - if (pool->base.multiple_abms[i] != NULL) - dce_abm_destroy(&pool->base.multiple_abms[i]); - } - - if (pool->base.psr != NULL) - dmub_psr_destroy(&pool->base.psr); - - if (pool->base.pg_cntl != NULL) - dcn_pg_cntl_destroy(&pool->base.pg_cntl); - - if (pool->base.dccg != NULL) - dcn_dccg_destroy(&pool->base.dccg); -} - -static struct hubp *dcn35_hubp_create( - struct dc_context *ctx, - uint32_t inst) -{ - struct dcn20_hubp *hubp2 = - kzalloc(sizeof(struct dcn20_hubp), GFP_KERNEL); - - if (!hubp2) - return NULL; - -#undef REG_STRUCT -#define REG_STRUCT hubp_regs - hubp_regs_init(0), - hubp_regs_init(1), - hubp_regs_init(2), - hubp_regs_init(3); - - if (hubp35_construct(hubp2, ctx, inst, - &hubp_regs[inst], &hubp_shift, &hubp_mask)) - return &hubp2->base; - - BREAK_TO_DEBUGGER(); - kfree(hubp2); - return NULL; -} - -static void dcn35_dwbc_init(struct dcn30_dwbc *dwbc30, struct dc_context *ctx) -{ - dcn35_dwbc_set_fgcg( - dwbc30, ctx->dc->debug.enable_fine_grain_clock_gating.bits.dwb); -} - -static bool dcn35_dwbc_create(struct dc_context *ctx, struct resource_pool *pool) -{ - int i; - uint32_t pipe_count = pool->res_cap->num_dwb; - - for (i = 0; i < pipe_count; i++) { - struct dcn30_dwbc *dwbc30 = kzalloc(sizeof(struct dcn30_dwbc), - GFP_KERNEL); - - if (!dwbc30) { - dm_error("DC: failed to create dwbc30!\n"); - return false; - } - -#undef REG_STRUCT -#define REG_STRUCT dwbc35_regs - dwbc_regs_dcn3_init(0); - - dcn35_dwbc_construct(dwbc30, ctx, - &dwbc35_regs[i], - &dwbc35_shift, - &dwbc35_mask, - i); - - pool->dwbc[i] = &dwbc30->base; - - dcn35_dwbc_init(dwbc30, ctx); - } - return true; -} - -static void dcn35_mmhubbub_init(struct dcn30_mmhubbub *mcif_wb30, - struct dc_context *ctx) -{ - dcn35_mmhubbub_set_fgcg( - mcif_wb30, - ctx->dc->debug.enable_fine_grain_clock_gating.bits.mmhubbub); -} - -static bool dcn35_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool) -{ - int i; - uint32_t pipe_count = pool->res_cap->num_dwb; - - for (i = 0; i < pipe_count; i++) { - struct dcn30_mmhubbub *mcif_wb30 = kzalloc(sizeof(struct dcn30_mmhubbub), - GFP_KERNEL); - - if (!mcif_wb30) { - dm_error("DC: failed to create mcif_wb30!\n"); - return false; - } - -#undef REG_STRUCT -#define REG_STRUCT mcif_wb35_regs - mcif_wb_regs_dcn3_init(0); - - dcn35_mmhubbub_construct(mcif_wb30, ctx, - &mcif_wb35_regs[i], - &mcif_wb35_shift, - &mcif_wb35_mask, - i); - - dcn35_mmhubbub_init(mcif_wb30, ctx); - - pool->mcif_wb[i] = &mcif_wb30->base; - } - return true; -} - -static struct display_stream_compressor *dcn35_dsc_create( - struct dc_context *ctx, uint32_t inst) -{ - struct dcn20_dsc *dsc = - kzalloc(sizeof(struct dcn20_dsc), GFP_KERNEL); - - if (!dsc) { - BREAK_TO_DEBUGGER(); - return NULL; - } - -#undef REG_STRUCT -#define REG_STRUCT dsc_regs - dsc_regsDCN35_init(0), - dsc_regsDCN35_init(1), - dsc_regsDCN35_init(2), - dsc_regsDCN35_init(3); - - dsc35_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask); - dsc35_set_fgcg(dsc, - ctx->dc->debug.enable_fine_grain_clock_gating.bits.dsc); - return &dsc->base; -} - -static void dcn35_destroy_resource_pool(struct resource_pool **pool) -{ - struct dcn35_resource_pool *dcn35_pool = TO_DCN35_RES_POOL(*pool); - - dcn35_resource_destruct(dcn35_pool); - kfree(dcn35_pool); - *pool = NULL; -} - -static struct clock_source *dcn35_clock_source_create( - struct dc_context *ctx, - struct dc_bios *bios, - enum clock_source_id id, - const struct dce110_clk_src_regs *regs, - bool dp_clk_src) -{ - struct dce110_clk_src *clk_src = - kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); - - if (!clk_src) - return NULL; - - if (dcn31_clk_src_construct(clk_src, ctx, bios, id, - regs, &cs_shift, &cs_mask)) { - clk_src->base.dp_clk_src = dp_clk_src; - return &clk_src->base; - } - - BREAK_TO_DEBUGGER(); - return NULL; -} - -static struct dc_cap_funcs cap_funcs = { - .get_dcc_compression_cap = dcn20_get_dcc_compression_cap -}; - -static void dcn35_get_panel_config_defaults(struct dc_panel_config *panel_config) -{ - *panel_config = panel_config_defaults; -} - - -static bool dcn35_validate_bandwidth(struct dc *dc, - struct dc_state *context, - bool fast_validate) -{ - bool out = false; - - out = dml2_validate(dc, context, fast_validate); - - if (fast_validate) - return out; - - DC_FP_START(); - dcn35_decide_zstate_support(dc, context); - DC_FP_END(); - - return out; -} - - -static struct resource_funcs dcn35_res_pool_funcs = { - .destroy = dcn35_destroy_resource_pool, - .link_enc_create = dcn35_link_encoder_create, - .link_enc_create_minimal = dcn31_link_enc_create_minimal, - .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 = dcn35_validate_bandwidth, - .calculate_wm_and_dlg = NULL, - .update_soc_for_wm_a = dcn31_update_soc_for_wm_a, - .populate_dml_pipes = dcn35_populate_dml_pipes_from_context_fpu, - .acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer, - .release_pipe = dcn20_release_pipe, - .add_stream_to_ctx = dcn30_add_stream_to_ctx, - .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource, - .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, - .populate_dml_writeback_from_context = dcn30_populate_dml_writeback_from_context, - .set_mcif_arb_params = dcn30_set_mcif_arb_params, - .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 = dcn35_update_bw_bounding_box_fpu, - .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, - .get_panel_config_defaults = dcn35_get_panel_config_defaults, - .get_preferred_eng_id_dpia = dcn35_get_preferred_eng_id_dpia, -}; - -static bool dcn35_resource_construct( - uint8_t num_virtual_links, - struct dc *dc, - struct dcn35_resource_pool *pool) -{ - int i; - struct dc_context *ctx = dc->ctx; - struct irq_service_init_data init_data; - -#undef REG_STRUCT -#define REG_STRUCT bios_regs - bios_regs_init(); - -#undef REG_STRUCT -#define REG_STRUCT clk_src_regs - clk_src_regs_init(0, A), - clk_src_regs_init(1, B), - clk_src_regs_init(2, C), - clk_src_regs_init(3, D), - clk_src_regs_init(4, E); - -#undef REG_STRUCT -#define REG_STRUCT abm_regs - abm_regs_init(0), - abm_regs_init(1), - abm_regs_init(2), - abm_regs_init(3); - -#undef REG_STRUCT -#define REG_STRUCT dccg_regs - dccg_regs_init(); - - ctx->dc_bios->regs = &bios_regs; - - pool->base.res_cap = &res_cap_dcn35; - - pool->base.funcs = &dcn35_res_pool_funcs; - - /************************************************* - * Resource + asic cap harcoding * - *************************************************/ - pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; - pool->base.pipe_count = pool->base.res_cap->num_timing_generator; - 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.max_cursor_size = 256; - dc->caps.min_horizontal_blanking_period = 80; - dc->caps.dmdata_alloc_size = 2048; - dc->caps.max_slave_planes = 2; - dc->caps.max_slave_yuv_planes = 2; - dc->caps.max_slave_rgb_planes = 2; - dc->caps.post_blend_color_processing = true; - dc->caps.force_dp_tps4_for_cp2520 = true; - if (dc->config.forceHBR2CP2520) - dc->caps.force_dp_tps4_for_cp2520 = false; - dc->caps.dp_hpo = true; - dc->caps.dp_hdmi21_pcon_support = true; - - dc->caps.edp_dsc_support = true; - dc->caps.extended_aux_timeout_support = true; - dc->caps.dmcub_support = true; - dc->caps.is_apu = true; - dc->caps.seamless_odm = true; - - dc->caps.zstate_support = true; - dc->caps.ips_support = true; - dc->caps.max_v_total = (1 << 15) - 1; - - /* Color pipeline capabilities */ - dc->caps.color.dpp.dcn_arch = 1; - dc->caps.color.dpp.input_lut_shared = 0; - dc->caps.color.dpp.icsc = 1; - dc->caps.color.dpp.dgam_ram = 0; // must use gamma_corr - dc->caps.color.dpp.dgam_rom_caps.srgb = 1; - dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1; - dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 1; - dc->caps.color.dpp.dgam_rom_caps.pq = 1; - dc->caps.color.dpp.dgam_rom_caps.hlg = 1; - dc->caps.color.dpp.post_csc = 1; - dc->caps.color.dpp.gamma_corr = 1; - dc->caps.color.dpp.dgam_rom_for_yuv = 0; - - dc->caps.color.dpp.hw_3d_lut = 1; - dc->caps.color.dpp.ogam_ram = 0; // no OGAM in DPP since DCN1 - // no OGAM ROM on DCN301 - dc->caps.color.dpp.ogam_rom_caps.srgb = 0; - dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0; - dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0; - dc->caps.color.dpp.ogam_rom_caps.pq = 0; - dc->caps.color.dpp.ogam_rom_caps.hlg = 0; - dc->caps.color.dpp.ocsc = 0; - - dc->caps.color.mpc.gamut_remap = 1; - dc->caps.color.mpc.num_3dluts = pool->base.res_cap->num_mpc_3dlut; //2 - dc->caps.color.mpc.ogam_ram = 1; - dc->caps.color.mpc.ogam_rom_caps.srgb = 0; - dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0; - dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0; - dc->caps.color.mpc.ogam_rom_caps.pq = 0; - dc->caps.color.mpc.ogam_rom_caps.hlg = 0; - dc->caps.color.mpc.ocsc = 1; - - /* max_disp_clock_khz_at_vmin is slightly lower than the STA value in order - * to provide some margin. - * It's expected for furture ASIC to have equal or higher value, in order to - * have determinstic power improvement from generate to genration. - * (i.e., we should not expect new ASIC generation with lower vmin rate) - */ - dc->caps.max_disp_clock_khz_at_vmin = 650000; - - /* Use pipe context based otg sync logic */ - dc->config.use_pipe_ctx_sync_logic = true; - - /* read VBIOS LTTPR caps */ - { - if (ctx->dc_bios->funcs->get_lttpr_caps) { - enum bp_result bp_query_result; - uint8_t is_vbios_lttpr_enable = 0; - - bp_query_result = ctx->dc_bios->funcs->get_lttpr_caps(ctx->dc_bios, &is_vbios_lttpr_enable); - dc->caps.vbios_lttpr_enable = (bp_query_result == BP_RESULT_OK) && !!is_vbios_lttpr_enable; - } - - /* interop bit is implicit */ - { - dc->caps.vbios_lttpr_aware = true; - } - } - - if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) - dc->debug = debug_defaults_drv; - - // Init the vm_helper - if (dc->vm_helper) - vm_helper_init(dc->vm_helper, 16); - - /************************************************* - * Create resources * - *************************************************/ - - /* Clock Sources for Pixel Clock*/ - pool->base.clock_sources[DCN35_CLK_SRC_PLL0] = - dcn35_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL0, - &clk_src_regs[0], false); - pool->base.clock_sources[DCN35_CLK_SRC_PLL1] = - dcn35_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL1, - &clk_src_regs[1], false); - pool->base.clock_sources[DCN35_CLK_SRC_PLL2] = - dcn35_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL2, - &clk_src_regs[2], false); - pool->base.clock_sources[DCN35_CLK_SRC_PLL3] = - dcn35_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL3, - &clk_src_regs[3], false); - pool->base.clock_sources[DCN35_CLK_SRC_PLL4] = - dcn35_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_COMBO_PHY_PLL4, - &clk_src_regs[4], false); - - pool->base.clk_src_count = DCN35_CLK_SRC_TOTAL; - - /* todo: not reuse phy_pll registers */ - pool->base.dp_clock_source = - dcn35_clock_source_create(ctx, ctx->dc_bios, - CLOCK_SOURCE_ID_DP_DTO, - &clk_src_regs[0], true); - - for (i = 0; i < pool->base.clk_src_count; i++) { - if (pool->base.clock_sources[i] == NULL) { - dm_error("DC: failed to create clock sources!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - } - /*temp till dml2 fully work without dml1*/ - dml_init_instance(&dc->dml, &dcn3_5_soc, &dcn3_5_ip, DML_PROJECT_DCN31); - - /* TODO: DCCG */ - pool->base.dccg = dccg35_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask); - if (pool->base.dccg == NULL) { - dm_error("DC: failed to create dccg!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - -#undef REG_STRUCT -#define REG_STRUCT pg_cntl_regs - pg_cntl_dcn35_regs_init(); - - pool->base.pg_cntl = pg_cntl35_create(ctx, &pg_cntl_regs, &pg_cntl_shift, &pg_cntl_mask); - if (pool->base.pg_cntl == NULL) { - dm_error("DC: failed to create power gate control!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - - /* TODO: IRQ */ - init_data.ctx = dc->ctx; - pool->base.irqs = dal_irq_service_dcn35_create(&init_data); - if (!pool->base.irqs) - goto create_fail; - - /* HUBBUB */ - pool->base.hubbub = dcn35_hubbub_create(ctx); - if (pool->base.hubbub == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create hubbub!\n"); - goto create_fail; - } - - /* HUBPs, DPPs, OPPs and TGs */ - for (i = 0; i < pool->base.pipe_count; i++) { - pool->base.hubps[i] = dcn35_hubp_create(ctx, i); - if (pool->base.hubps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create hubps!\n"); - goto create_fail; - } - - pool->base.dpps[i] = dcn35_dpp_create(ctx, i); - if (pool->base.dpps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create dpps!\n"); - goto create_fail; - } - } - - for (i = 0; i < pool->base.res_cap->num_opp; i++) { - pool->base.opps[i] = dcn35_opp_create(ctx, i); - if (pool->base.opps[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC: failed to create output pixel processor!\n"); - goto create_fail; - } - } - - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - pool->base.timing_generators[i] = dcn35_timing_generator_create( - ctx, i); - if (pool->base.timing_generators[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create tg!\n"); - goto create_fail; - } - } - pool->base.timing_generator_count = i; - - /* PSR */ - pool->base.psr = dmub_psr_create(ctx); - if (pool->base.psr == NULL) { - dm_error("DC: failed to create psr obj!\n"); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - - /* ABM */ - for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { - pool->base.multiple_abms[i] = dmub_abm_create(ctx, - &abm_regs[i], - &abm_shift, - &abm_mask); - if (pool->base.multiple_abms[i] == NULL) { - dm_error("DC: failed to create abm for pipe %d!\n", i); - BREAK_TO_DEBUGGER(); - goto create_fail; - } - } - - /* MPC and DSC */ - pool->base.mpc = dcn35_mpc_create(ctx, pool->base.mpcc_count, pool->base.res_cap->num_mpc_3dlut); - if (pool->base.mpc == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create mpc!\n"); - goto create_fail; - } - - for (i = 0; i < pool->base.res_cap->num_dsc; i++) { - pool->base.dscs[i] = dcn35_dsc_create(ctx, i); - if (pool->base.dscs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create display stream compressor %d!\n", i); - goto create_fail; - } - } - - /* DWB and MMHUBBUB */ - if (!dcn35_dwbc_create(ctx, &pool->base)) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create dwbc!\n"); - goto create_fail; - } - - if (!dcn35_mmhubbub_create(ctx, &pool->base)) { - BREAK_TO_DEBUGGER(); - dm_error("DC: failed to create mcif_wb!\n"); - goto create_fail; - } - - /* AUX and I2C */ - for (i = 0; i < pool->base.res_cap->num_ddc; i++) { - pool->base.engines[i] = dcn31_aux_engine_create(ctx, i); - if (pool->base.engines[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create aux engine!!\n"); - goto create_fail; - } - pool->base.hw_i2cs[i] = dcn31_i2c_hw_create(ctx, i); - if (pool->base.hw_i2cs[i] == NULL) { - BREAK_TO_DEBUGGER(); - dm_error( - "DC:failed to create hw i2c!!\n"); - goto create_fail; - } - pool->base.sw_i2cs[i] = NULL; - } - - /* DCN3.5 has 6 DPIA */ - pool->base.usb4_dpia_count = 4; - if (dc->debug.dpia_debug.bits.disable_dpia) - pool->base.usb4_dpia_count = 0; - - /* Audio, Stream Encoders including HPO and virtual, MPC 3D LUTs */ - if (!resource_construct(num_virtual_links, dc, &pool->base, - &res_create_funcs)) - goto create_fail; - - /* HW Sequencer and Plane caps */ - dcn35_hw_sequencer_construct(dc); - - dc->caps.max_planes = pool->base.pipe_count; - - for (i = 0; i < dc->caps.max_planes; ++i) - dc->caps.planes[i] = plane_cap; - - dc->cap_funcs = cap_funcs; - - dc->dcn_ip->max_num_dpp = pool->base.pipe_count; - - dc->dml2_options.dcn_pipe_count = pool->base.pipe_count; - dc->dml2_options.use_native_pstate_optimization = true; - dc->dml2_options.use_native_soc_bb_construction = true; - if (dc->config.EnableMinDispClkODM) - dc->dml2_options.minimize_dispclk_using_odm = true; - dc->dml2_options.enable_windowed_mpo_odm = dc->config.enable_windowed_mpo_odm; - - dc->dml2_options.callbacks.dc = dc; - dc->dml2_options.callbacks.build_scaling_params = &resource_build_scaling_params; - dc->dml2_options.callbacks.can_support_mclk_switch_using_fw_based_vblank_stretch = &dcn30_can_support_mclk_switch_using_fw_based_vblank_stretch; - dc->dml2_options.callbacks.acquire_secondary_pipe_for_mpc_odm = &dc_resource_acquire_secondary_pipe_for_mpc_odm_legacy; - dc->dml2_options.callbacks.update_pipes_for_stream_with_slice_count = &resource_update_pipes_for_stream_with_slice_count; - dc->dml2_options.callbacks.update_pipes_for_plane_with_slice_count = &resource_update_pipes_for_plane_with_slice_count; - dc->dml2_options.callbacks.get_mpc_slice_index = &resource_get_mpc_slice_index; - dc->dml2_options.callbacks.get_odm_slice_index = &resource_get_odm_slice_index; - dc->dml2_options.callbacks.get_opp_head = &resource_get_opp_head; - dc->dml2_options.max_segments_per_hubp = 24; - - dc->dml2_options.det_segment_size = DCN3_2_DET_SEG_SIZE;/*todo*/ - - if (dc->config.sdpif_request_limit_words_per_umc == 0) - dc->config.sdpif_request_limit_words_per_umc = 16;/*todo*/ - - return true; - -create_fail: - - dcn35_resource_destruct(pool); - - return false; -} - -struct resource_pool *dcn35_create_resource_pool( - const struct dc_init_data *init_data, - struct dc *dc) -{ - struct dcn35_resource_pool *pool = - kzalloc(sizeof(struct dcn35_resource_pool), GFP_KERNEL); - - if (!pool) - return NULL; - - if (dcn35_resource_construct(init_data->num_virtual_links, dc, pool)) - return &pool->base; - - BREAK_TO_DEBUGGER(); - kfree(pool); - return NULL; -} diff --git a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_resource.h b/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_resource.h deleted file mode 100644 index 99aea102e3f741..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/dcn35/dcn35_resource.h +++ /dev/null @@ -1,310 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * 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 _DCN35_RESOURCE_H_ -#define _DCN35_RESOURCE_H_ - -#include "core_types.h" - -#define DCN3_5_VMIN_DISPCLK_HZ 717000000 -#define TO_DCN35_RES_POOL(pool)\ - container_of(pool, struct dcn35_resource_pool, base) - -extern struct _vcs_dpi_ip_params_st dcn3_5_ip; -extern struct _vcs_dpi_soc_bounding_box_st dcn3_5_soc; - -struct dcn35_resource_pool { - struct resource_pool base; -}; - -struct resource_pool *dcn35_create_resource_pool( - const struct dc_init_data *init_data, - struct dc *dc); - -/* Defs for runtime init of registers */ - -#define OPP_REG_LIST_DCN20_RI(id) \ - OPP_REG_LIST_DCN10_RI(id), \ - OPP_DPG_REG_LIST_RI(id), \ - SRI_ARR(FMT_422_CONTROL, FMT, id), \ - SRI_ARR(OPPBUF_CONTROL1, OPPBUF, id) - -#define OPP_REG_LIST_DCN35_RI(id) \ - OPP_REG_LIST_DCN20_RI(id), \ - SRI2_ARR(OPP_TOP_CLK_CONTROL, OPP, id) - -#define VPG_DCN31_REG_LIST_RI(id) \ - SRI_ARR(VPG_GENERIC_STATUS, VPG, id), \ - SRI_ARR(VPG_GENERIC_PACKET_ACCESS_CTRL, VPG, id), \ - SRI_ARR(VPG_GENERIC_PACKET_DATA, VPG, id), \ - SRI_ARR(VPG_GSP_FRAME_UPDATE_CTRL, VPG, id), \ - SRI_ARR(VPG_GSP_IMMEDIATE_UPDATE_CTRL, VPG, id), \ - SRI_ARR(VPG_MEM_PWR, VPG, id) - -#define AFMT_DCN31_REG_LIST_RI(id) \ - SRI_ARR(AFMT_INFOFRAME_CONTROL0, AFMT, id), \ - SRI_ARR(AFMT_VBI_PACKET_CONTROL, AFMT, id), \ - SRI_ARR(AFMT_AUDIO_PACKET_CONTROL, AFMT, id), \ - SRI_ARR(AFMT_AUDIO_PACKET_CONTROL2, AFMT, id), \ - SRI_ARR(AFMT_AUDIO_SRC_CONTROL, AFMT, id), \ - SRI_ARR(AFMT_60958_0, AFMT, id), \ - SRI_ARR(AFMT_60958_1, AFMT, id), \ - SRI_ARR(AFMT_60958_2, AFMT, id), \ - SRI_ARR(AFMT_MEM_PWR, AFMT, id) - -/* Stream encoder */ -#define SE_DCN35_REG_LIST_RI(id) \ - SRI_ARR(AFMT_CNTL, DIG, id), \ - SRI_ARR(DIG_FE_CNTL, DIG, id), \ - SRI_ARR(HDMI_CONTROL, DIG, id), \ - SRI_ARR(HDMI_DB_CONTROL, DIG, id), \ - SRI_ARR(HDMI_GC, DIG, id), \ - SRI_ARR(HDMI_GENERIC_PACKET_CONTROL0, DIG, id), \ - SRI_ARR(HDMI_GENERIC_PACKET_CONTROL1, DIG, id), \ - SRI_ARR(HDMI_GENERIC_PACKET_CONTROL2, DIG, id), \ - SRI_ARR(HDMI_GENERIC_PACKET_CONTROL3, DIG, id), \ - SRI_ARR(HDMI_GENERIC_PACKET_CONTROL4, DIG, id), \ - SRI_ARR(HDMI_GENERIC_PACKET_CONTROL5, DIG, id), \ - SRI_ARR(HDMI_GENERIC_PACKET_CONTROL6, DIG, id), \ - SRI_ARR(HDMI_GENERIC_PACKET_CONTROL7, DIG, id), \ - SRI_ARR(HDMI_GENERIC_PACKET_CONTROL8, DIG, id), \ - SRI_ARR(HDMI_GENERIC_PACKET_CONTROL9, DIG, id), \ - SRI_ARR(HDMI_GENERIC_PACKET_CONTROL10, DIG, id), \ - SRI_ARR(HDMI_INFOFRAME_CONTROL0, DIG, id), \ - SRI_ARR(HDMI_INFOFRAME_CONTROL1, DIG, id), \ - SRI_ARR(HDMI_VBI_PACKET_CONTROL, DIG, id), \ - SRI_ARR(HDMI_AUDIO_PACKET_CONTROL, DIG, id),\ - SRI_ARR(HDMI_ACR_PACKET_CONTROL, DIG, id),\ - SRI_ARR(HDMI_ACR_32_0, DIG, id),\ - SRI_ARR(HDMI_ACR_32_1, DIG, id),\ - SRI_ARR(HDMI_ACR_44_0, DIG, id),\ - SRI_ARR(HDMI_ACR_44_1, DIG, id),\ - SRI_ARR(HDMI_ACR_48_0, DIG, id),\ - SRI_ARR(HDMI_ACR_48_1, DIG, id),\ - SRI_ARR(DP_DB_CNTL, DP, id), \ - SRI_ARR(DP_MSA_MISC, DP, id), \ - SRI_ARR(DP_MSA_VBID_MISC, DP, id), \ - SRI_ARR(DP_MSA_COLORIMETRY, DP, id), \ - SRI_ARR(DP_MSA_TIMING_PARAM1, DP, id), \ - SRI_ARR(DP_MSA_TIMING_PARAM2, DP, id), \ - SRI_ARR(DP_MSA_TIMING_PARAM3, DP, id), \ - SRI_ARR(DP_MSA_TIMING_PARAM4, DP, id), \ - SRI_ARR(DP_MSE_RATE_CNTL, DP, id), \ - SRI_ARR(DP_MSE_RATE_UPDATE, DP, id), \ - SRI_ARR(DP_PIXEL_FORMAT, DP, id), \ - SRI_ARR(DP_SEC_CNTL, DP, id), \ - SRI_ARR(DP_SEC_CNTL1, DP, id), \ - SRI_ARR(DP_SEC_CNTL2, DP, id), \ - SRI_ARR(DP_SEC_CNTL5, DP, id), \ - SRI_ARR(DP_SEC_CNTL6, DP, id), \ - SRI_ARR(DP_STEER_FIFO, DP, id), \ - SRI_ARR(DP_VID_M, DP, id), \ - SRI_ARR(DP_VID_N, DP, id), \ - SRI_ARR(DP_VID_STREAM_CNTL, DP, id), \ - SRI_ARR(DP_VID_TIMING, DP, id), \ - SRI_ARR(DP_SEC_AUD_N, DP, id), \ - SRI_ARR(DP_SEC_TIMESTAMP, DP, id), \ - SRI_ARR(DP_DSC_CNTL, DP, id), \ - SRI_ARR(DP_SEC_METADATA_TRANSMISSION, DP, id), \ - SRI_ARR(HDMI_METADATA_PACKET_CONTROL, DIG, id), \ - SRI_ARR(DP_SEC_FRAMING4, DP, id), \ - SRI_ARR(DP_GSP11_CNTL, DP, id), \ - SRI_ARR(DME_CONTROL, DME, id),\ - SRI_ARR(DP_SEC_METADATA_TRANSMISSION, DP, id), \ - SRI_ARR(HDMI_METADATA_PACKET_CONTROL, DIG, id), \ - SRI_ARR(DIG_FE_CNTL, DIG, id), \ - SRI_ARR(DIG_FE_EN_CNTL, DIG, id), \ - SRI_ARR(DIG_FE_CLK_CNTL, DIG, id), \ - SRI_ARR(DIG_CLOCK_PATTERN, DIG, id), \ - SRI_ARR(DIG_FIFO_CTRL0, DIG, id), \ - SRI_ARR(STREAM_MAPPER_CONTROL, DIG, id) - -#define LE_DCN35_REG_LIST_RI(id)\ - LE_DCN3_REG_LIST_RI(id),\ - SRI_ARR(DP_DPHY_INTERNAL_CTRL, DP, id), \ - SR_ARR(DIO_LINKA_CNTL, id), \ - SR_ARR(DIO_LINKB_CNTL, id), \ - SR_ARR(DIO_LINKC_CNTL, id), \ - SR_ARR(DIO_LINKD_CNTL, id), \ - SR_ARR(DIO_LINKE_CNTL, id), \ - SR_ARR(DIO_LINKF_CNTL, id),\ - SRI_ARR(DIG_BE_CLK_CNTL, DIG, id),\ - SR_ARR(DIO_CLK_CNTL, id) - -#define MCIF_WB_COMMON_REG_LIST_DCN3_5_RI(inst) \ - MCIF_WB_COMMON_REG_LIST_DCN32_RI(inst), \ - SRI2_ARR(MMHUBBUB_CLOCK_CNTL, MMHUBBUB, inst) - -#define HWSEQ_DCN35_REG_LIST()\ - SR(DCHUBBUB_GLOBAL_TIMER_CNTL), \ - SR(DCHUBBUB_ARB_HOSTVM_CNTL), \ - SR(DIO_MEM_PWR_CTRL), \ - SR(ODM_MEM_PWR_CTRL3), \ - SR(MMHUBBUB_MEM_PWR_CNTL), \ - SR(DCCG_GATE_DISABLE_CNTL), \ - SR(DCCG_GATE_DISABLE_CNTL2), \ - SR(DCCG_GATE_DISABLE_CNTL5), \ - SR(DCFCLK_CNTL),\ - SR(DC_MEM_GLOBAL_PWR_REQ_CNTL), \ - SRII(PIXEL_RATE_CNTL, OTG, 0), \ - SRII(PIXEL_RATE_CNTL, OTG, 1),\ - SRII(PIXEL_RATE_CNTL, OTG, 2),\ - SRII(PIXEL_RATE_CNTL, OTG, 3),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 0),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 1),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 2),\ - SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 3),\ - SR(MICROSECOND_TIME_BASE_DIV), \ - SR(MILLISECOND_TIME_BASE_DIV), \ - SR(DISPCLK_FREQ_CHANGE_CNTL), \ - SR(RBBMIF_TIMEOUT_DIS), \ - SR(RBBMIF_TIMEOUT_DIS_2), \ - SR(DCHUBBUB_CRC_CTRL), \ - SR(DPP_TOP0_DPP_CRC_CTRL), \ - SR(DPP_TOP0_DPP_CRC_VAL_B_A), \ - SR(DPP_TOP0_DPP_CRC_VAL_R_G), \ - SR(MPC_CRC_CTRL), \ - SR(MPC_CRC_RESULT_GB), \ - SR(MPC_CRC_RESULT_C), \ - SR(MPC_CRC_RESULT_AR), \ - SR(DOMAIN0_PG_CONFIG), \ - SR(DOMAIN1_PG_CONFIG), \ - SR(DOMAIN2_PG_CONFIG), \ - SR(DOMAIN3_PG_CONFIG), \ - SR(DOMAIN16_PG_CONFIG), \ - SR(DOMAIN17_PG_CONFIG), \ - SR(DOMAIN18_PG_CONFIG), \ - SR(DOMAIN19_PG_CONFIG), \ - SR(DOMAIN0_PG_STATUS), \ - SR(DOMAIN1_PG_STATUS), \ - SR(DOMAIN2_PG_STATUS), \ - SR(DOMAIN3_PG_STATUS), \ - SR(DOMAIN16_PG_STATUS), \ - SR(DOMAIN17_PG_STATUS), \ - SR(DOMAIN18_PG_STATUS), \ - SR(DOMAIN19_PG_STATUS), \ - SR(DC_IP_REQUEST_CNTL), \ - SR(AZALIA_AUDIO_DTO), \ - SR(AZALIA_CONTROLLER_CLOCK_GATING), \ - SR(HPO_TOP_HW_CONTROL),\ - SR(DMU_CLK_CNTL) - -/* OPTC */ -#define OPTC_COMMON_REG_LIST_DCN3_5_RI(inst) \ - SRI_ARR(OTG_VSTARTUP_PARAM, OTG, inst),\ - SRI_ARR(OTG_VUPDATE_PARAM, OTG, inst),\ - SRI_ARR(OTG_VREADY_PARAM, OTG, inst),\ - SRI_ARR(OTG_MASTER_UPDATE_LOCK, OTG, inst),\ - SRI_ARR(OTG_GLOBAL_CONTROL0, OTG, inst),\ - SRI_ARR(OTG_GLOBAL_CONTROL1, OTG, inst),\ - SRI_ARR(OTG_GLOBAL_CONTROL2, OTG, inst),\ - SRI_ARR(OTG_GLOBAL_CONTROL4, OTG, inst),\ - SRI_ARR(OTG_DOUBLE_BUFFER_CONTROL, OTG, inst),\ - SRI_ARR(OTG_H_TOTAL, OTG, inst),\ - SRI_ARR(OTG_H_BLANK_START_END, OTG, inst),\ - SRI_ARR(OTG_H_SYNC_A, OTG, inst),\ - SRI_ARR(OTG_H_SYNC_A_CNTL, OTG, inst),\ - SRI_ARR(OTG_H_TIMING_CNTL, OTG, inst),\ - SRI_ARR(OTG_V_TOTAL, OTG, inst),\ - SRI_ARR(OTG_V_BLANK_START_END, OTG, inst),\ - SRI_ARR(OTG_V_SYNC_A, OTG, inst),\ - SRI_ARR(OTG_V_SYNC_A_CNTL, OTG, inst),\ - SRI_ARR(OTG_CONTROL, OTG, inst),\ - SRI_ARR(OTG_STEREO_CONTROL, OTG, inst),\ - SRI_ARR(OTG_3D_STRUCTURE_CONTROL, OTG, inst),\ - SRI_ARR(OTG_STEREO_STATUS, OTG, inst),\ - SRI_ARR(OTG_V_TOTAL_MAX, OTG, inst),\ - SRI_ARR(OTG_V_TOTAL_MIN, OTG, inst),\ - SRI_ARR(OTG_V_TOTAL_CONTROL, OTG, inst),\ - SRI_ARR(OTG_TRIGA_CNTL, OTG, inst),\ - SRI_ARR(OTG_FORCE_COUNT_NOW_CNTL, OTG, inst),\ - SRI_ARR(OTG_STATIC_SCREEN_CONTROL, OTG, inst),\ - SRI_ARR(OTG_STATUS_FRAME_COUNT, OTG, inst),\ - SRI_ARR(OTG_STATUS, OTG, inst),\ - SRI_ARR(OTG_STATUS_POSITION, OTG, inst),\ - SRI_ARR(OTG_NOM_VERT_POSITION, OTG, inst),\ - SRI_ARR(OTG_M_CONST_DTO0, OTG, inst),\ - SRI_ARR(OTG_M_CONST_DTO1, OTG, inst),\ - SRI_ARR(OTG_CLOCK_CONTROL, OTG, inst),\ - SRI_ARR(OTG_VERTICAL_INTERRUPT0_CONTROL, OTG, inst),\ - SRI_ARR(OTG_VERTICAL_INTERRUPT0_POSITION, OTG, inst),\ - SRI_ARR(OTG_VERTICAL_INTERRUPT1_CONTROL, OTG, inst),\ - SRI_ARR(OTG_VERTICAL_INTERRUPT1_POSITION, OTG, inst),\ - SRI_ARR(OTG_VERTICAL_INTERRUPT2_CONTROL, OTG, inst),\ - SRI_ARR(OTG_VERTICAL_INTERRUPT2_POSITION, OTG, inst),\ - SRI_ARR(OPTC_INPUT_CLOCK_CONTROL, ODM, inst),\ - SRI_ARR(OPTC_DATA_SOURCE_SELECT, ODM, inst),\ - SRI_ARR(OPTC_INPUT_GLOBAL_CONTROL, ODM, inst),\ - SRI_ARR(CONTROL, VTG, inst),\ - SRI_ARR(OTG_VERT_SYNC_CONTROL, OTG, inst),\ - SRI_ARR(OTG_GSL_CONTROL, OTG, inst),\ - SRI_ARR(OTG_CRC_CNTL, OTG, inst),\ - SRI_ARR(OTG_CRC0_DATA_RG, OTG, inst),\ - SRI_ARR(OTG_CRC0_DATA_B, OTG, inst),\ - SRI_ARR(OTG_CRC1_DATA_RG, OTG, inst),\ - SRI_ARR(OTG_CRC1_DATA_B, OTG, inst),\ - SRI_ARR(OTG_CRC2_DATA_RG, OTG, inst),\ - SRI_ARR(OTG_CRC2_DATA_B, OTG, inst),\ - SRI_ARR(OTG_CRC3_DATA_RG, OTG, inst),\ - SRI_ARR(OTG_CRC3_DATA_B, OTG, inst),\ - SRI_ARR(OTG_CRC0_WINDOWA_X_CONTROL, OTG, inst),\ - SRI_ARR(OTG_CRC0_WINDOWA_Y_CONTROL, OTG, inst),\ - SRI_ARR(OTG_CRC0_WINDOWB_X_CONTROL, OTG, inst),\ - SRI_ARR(OTG_CRC0_WINDOWB_Y_CONTROL, OTG, inst),\ - SRI_ARR(OTG_CRC1_WINDOWA_X_CONTROL, OTG, inst),\ - SRI_ARR(OTG_CRC1_WINDOWA_Y_CONTROL, OTG, inst),\ - SRI_ARR(OTG_CRC1_WINDOWB_X_CONTROL, OTG, inst),\ - SRI_ARR(OTG_CRC1_WINDOWB_Y_CONTROL, OTG, inst),\ - SRI_ARR(OTG_CRC0_WINDOWA_X_CONTROL_READBACK, OTG, inst),\ - SRI_ARR(OTG_CRC0_WINDOWA_Y_CONTROL_READBACK, OTG, inst),\ - SRI_ARR(OTG_CRC0_WINDOWB_X_CONTROL_READBACK, OTG, inst),\ - SRI_ARR(OTG_CRC0_WINDOWB_Y_CONTROL_READBACK, OTG, inst),\ - SRI_ARR(OTG_CRC1_WINDOWA_X_CONTROL_READBACK, OTG, inst),\ - SRI_ARR(OTG_CRC1_WINDOWA_Y_CONTROL_READBACK, OTG, inst),\ - SRI_ARR(OTG_CRC1_WINDOWB_X_CONTROL_READBACK, OTG, inst),\ - SRI_ARR(OTG_CRC1_WINDOWB_Y_CONTROL_READBACK, OTG, inst),\ - SR_ARR(GSL_SOURCE_SELECT, inst),\ - SRI_ARR(OTG_TRIGA_MANUAL_TRIG, OTG, inst),\ - SRI_ARR(OTG_GLOBAL_CONTROL1, OTG, inst),\ - SRI_ARR(OTG_GLOBAL_CONTROL2, OTG, inst),\ - SRI_ARR(OTG_GSL_WINDOW_X, OTG, inst),\ - SRI_ARR(OTG_GSL_WINDOW_Y, OTG, inst),\ - SRI_ARR(OTG_VUPDATE_KEEPOUT, OTG, inst),\ - SRI_ARR(OTG_DSC_START_POSITION, OTG, inst),\ - SRI_ARR(OTG_DRR_TRIGGER_WINDOW, OTG, inst),\ - SRI_ARR(OTG_DRR_V_TOTAL_CHANGE, OTG, inst),\ - SRI_ARR(OPTC_DATA_FORMAT_CONTROL, ODM, inst),\ - SRI_ARR(OPTC_BYTES_PER_PIXEL, ODM, inst),\ - SRI_ARR(OPTC_WIDTH_CONTROL, ODM, inst),\ - SRI_ARR(OPTC_MEMORY_CONFIG, ODM, inst),\ - SRI_ARR(OTG_DRR_CONTROL, OTG, inst),\ - SRI2_ARR(OPTC_CLOCK_CONTROL, OPTC, inst) - -/* DPP */ -#define DPP_REG_LIST_DCN35_RI(id)\ - DPP_REG_LIST_DCN30_COMMON_RI(id) - -#endif /* _DCN35_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dm_helpers.h b/drivers/gpu/drm/amd/display/dc/dm_helpers.h index 7ce9a5b6c33bad..6d7a15dcf8a7ba 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_helpers.h +++ b/drivers/gpu/drm/amd/display/dc/dm_helpers.h @@ -103,10 +103,16 @@ enum act_return_status dm_helpers_dp_mst_poll_for_allocation_change_trigger( /* * Sends ALLOCATE_PAYLOAD message. */ -bool dm_helpers_dp_mst_send_payload_allocation( +void dm_helpers_dp_mst_send_payload_allocation( struct dc_context *ctx, - const struct dc_stream_state *stream, - bool enable); + const struct dc_stream_state *stream); + +/* + * Update mst manager relevant variables + */ +void dm_helpers_dp_mst_update_mst_mgr_for_deallocation( + struct dc_context *ctx, + const struct dc_stream_state *stream); bool dm_helpers_dp_mst_start_top_mgr( struct dc_context *ctx, diff --git a/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h b/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h index 4440d08743aa18..bd7ba0a25198db 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h +++ b/drivers/gpu/drm/amd/display/dc/dm_pp_smu.h @@ -247,6 +247,7 @@ struct pp_smu_funcs_nv { #define PP_SMU_NUM_MEMCLK_DPM_LEVELS 4 #define PP_SMU_NUM_DCLK_DPM_LEVELS 8 #define PP_SMU_NUM_VCLK_DPM_LEVELS 8 +#define PP_SMU_NUM_VPECLK_DPM_LEVELS 8 struct dpm_clock { uint32_t Freq; // In MHz @@ -262,6 +263,7 @@ struct dpm_clocks { struct dpm_clock MemClocks[PP_SMU_NUM_MEMCLK_DPM_LEVELS]; struct dpm_clock VClocks[PP_SMU_NUM_VCLK_DPM_LEVELS]; struct dpm_clock DClocks[PP_SMU_NUM_DCLK_DPM_LEVELS]; + struct dpm_clock VPEClocks[PP_SMU_NUM_VPECLK_DPM_LEVELS]; }; diff --git a/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c index 50b0434354f8f5..0c4a8fe8e5ca62 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c @@ -30,7 +30,7 @@ #include "dcn_calc_auto.h" #include "dal_asic_id.h" #include "resource.h" -#include "dcn10/dcn10_resource.h" +#include "resource/dcn10/dcn10_resource.h" #include "dcn10/dcn10_hubbub.h" #include "dml/dml1_display_rq_dlg_calc.h" 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 d2271e308fa010..38ab9ad60ef8bc 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 @@ -33,6 +33,7 @@ #include "link.h" #include "dcn20_fpu.h" +#include "dc_state_priv.h" #define DC_LOGGER \ dc->ctx->logger @@ -1182,7 +1183,7 @@ void dcn20_calculate_dlg_params(struct dc *dc, pipes[pipe_idx].pipe.dest.vupdate_width = get_vupdate_width(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx); pipes[pipe_idx].pipe.dest.vready_offset = get_vready_offset(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx); - if (context->res_ctx.pipe_ctx[i].stream->mall_stream_config.type == SUBVP_PHANTOM) { + if (dc_state_get_pipe_subvp_type(context, &context->res_ctx.pipe_ctx[i]) == SUBVP_PHANTOM) { // Phantom pipe requires that DET_SIZE = 0 and no unbounded requests context->res_ctx.pipe_ctx[i].det_buffer_size_kb = 0; context->res_ctx.pipe_ctx[i].unbounded_req = false; @@ -1532,7 +1533,7 @@ int dcn20_populate_dml_pipes_from_context(struct dc *dc, */ if (res_ctx->pipe_ctx[i].plane_state && (res_ctx->pipe_ctx[i].plane_state->address.type == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE || - res_ctx->pipe_ctx[i].stream->mall_stream_config.type == SUBVP_PHANTOM)) + dc_state_get_pipe_subvp_type(context, &res_ctx->pipe_ctx[i]) == SUBVP_PHANTOM)) pipes[pipe_cnt].pipe.src.num_cursors = 0; else pipes[pipe_cnt].pipe.src.num_cursors = dc->dml.ip.number_of_cursors; 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 3686f1e7de3abf..63c48c29ba4910 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 @@ -3542,7 +3542,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l { struct vba_vars_st *v = &mode_lib->vba; int MinPrefetchMode, MaxPrefetchMode; - int i; + int i, start_state; unsigned int j, k, m; bool EnoughWritebackUnits = true; bool WritebackModeSupport = true; @@ -3553,6 +3553,11 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l /*MODE SUPPORT, VOLTAGE STATE AND SOC CONFIGURATION*/ + if (mode_lib->validate_max_state) + start_state = v->soc.num_states - 1; + else + start_state = 0; + CalculateMinAndMaxPrefetchMode( mode_lib->vba.AllowDRAMSelfRefreshOrDRAMClockChangeInVblank, &MinPrefetchMode, &MaxPrefetchMode); @@ -3851,7 +3856,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l v->SingleDPPViewportSizeSupportPerPlane, &v->ViewportSizeSupport[0][0]); - 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++) { v->MaxDispclkRoundedDownToDFSGranularity = RoundToDFSGranularityDown(v->MaxDispclk[i], v->DISPCLKDPPCLKVCOSpeed); v->MaxDppclkRoundedDownToDFSGranularity = RoundToDFSGranularityDown(v->MaxDppclk[i], v->DISPCLKDPPCLKVCOSpeed); @@ -4007,7 +4012,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l /*Total Available Pipes Support Check*/ - 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++) { if (v->TotalNumberOfActiveDPP[i][j] <= v->MaxNumDPP) { v->TotalAvailablePipesSupport[i][j] = true; @@ -4046,7 +4051,7 @@ void dml30_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++) { for (k = 0; k <= v->NumberOfActivePlanes - 1; k++) { v->RequiresDSC[i][k] = false; v->RequiresFEC[i][k] = false; @@ -4174,7 +4179,7 @@ void dml30_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++) { v->DIOSupport[i] = true; for (k = 0; k <= v->NumberOfActivePlanes - 1; k++) { if (!v->skip_dio_check[k] && v->BlendingAndTiming[k] == k && (v->Output[k] == dm_dp || v->Output[k] == dm_edp || v->Output[k] == dm_hdmi) @@ -4185,7 +4190,7 @@ void dml30_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) { v->ODMCombine4To1SupportCheckOK[i] = true; for (k = 0; k < v->NumberOfActivePlanes; ++k) { if (v->BlendingAndTiming[k] == k && v->ODMCombineEnablePerState[i][k] == dm_odm_combine_mode_4to1 @@ -4197,7 +4202,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l /* Skip dscclk validation: as long as dispclk is supported, dscclk is also implicitly supported */ - for (i = 0; i < v->soc.num_states; i++) { + for (i = start_state; i < v->soc.num_states; i++) { v->NotEnoughDSCUnits[i] = false; v->TotalDSCUnitsRequired = 0.0; for (k = 0; k <= v->NumberOfActivePlanes - 1; k++) { @@ -4217,7 +4222,7 @@ void dml30_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 <= v->NumberOfActivePlanes - 1; k++) { if (v->OutputBppPerState[i][k] == BPP_INVALID) { v->BPP = 0.0; @@ -4333,7 +4338,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l v->cursor_bw[k] = v->NumberOfCursors[k] * v->CursorWidth[k][0] * v->CursorBPP[k][0] / 8.0 / (v->HTotal[k] / v->PixelClock[k]) * v->VRatio[k]; } - 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 <= v->NumberOfActivePlanes - 1; k++) { v->swath_width_luma_ub_this_state[k] = v->swath_width_luma_ub_all_states[i][j][k]; @@ -5075,7 +5080,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l /*PTE Buffer Size Check*/ - 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++) { v->PTEBufferSizeNotExceeded[i][j] = true; for (k = 0; k <= v->NumberOfActivePlanes - 1; k++) { @@ -5136,7 +5141,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l } /*Mode Support, Voltage State and SOC Configuration*/ - 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 (v->ScaleRatioAndTapsSupport == 1 && v->SourceFormatPixelAndScanSupport == 1 && v->ViewportSizeSupport[i][j] == 1 && v->DIOSupport[i] == 1 && v->ODMCombine4To1SupportCheckOK[i] == 1 @@ -5158,7 +5163,7 @@ void dml30_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l } { unsigned int 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 || v->ModeSupport[i][0] == true || v->ModeSupport[i][1] == true) { v->VoltageLevel = i; v->ModeIsSupported = v->ModeSupport[i][0] == true || v->ModeSupport[i][1] == true; 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 b46cde52506699..9f37f717a1f86f 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 @@ -32,6 +32,7 @@ #include "clk_mgr/dcn32/dcn32_smu13_driver_if.h" #include "dcn30/dcn30_resource.h" #include "link.h" +#include "dc_state_priv.h" #define DC_LOGGER_INIT(logger) @@ -45,6 +46,14 @@ static const struct subvp_high_refresh_list subvp_high_refresh_list = { {.width = 1920, .height = 1080, }}, }; +static const struct subvp_active_margin_list subvp_active_margin_list = { + .min_refresh = 55, + .max_refresh = 65, + .res = { + {.width = 2560, .height = 1440, }, + {.width = 1920, .height = 1080, }}, +}; + struct _vcs_dpi_ip_params_st dcn3_2_ip = { .gpuvm_enable = 0, .gpuvm_max_page_table_levels = 4, @@ -333,7 +342,7 @@ void dcn32_helper_populate_phantom_dlg_params(struct dc *dc, if (!pipe->stream) continue; - if (pipe->plane_state && pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) { + if (pipe->plane_state && dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) { pipes[pipe_idx].pipe.dest.vstartup_start = get_vstartup(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx); pipes[pipe_idx].pipe.dest.vupdate_offset = @@ -616,7 +625,7 @@ static bool dcn32_assign_subvp_pipe(struct dc *dc, if (pipe->plane_state && !pipe->top_pipe && !dcn32_is_center_timing(pipe) && !(pipe->stream->timing.pix_clk_100hz / 10000 > DCN3_2_MAX_SUBVP_PIXEL_RATE_MHZ) && (!dcn32_is_psr_capable(pipe) || (context->stream_count == 1 && dc->caps.dmub_caps.subvp_psr)) && - pipe->stream->mall_stream_config.type == SUBVP_NONE && + dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_NONE && (refresh_rate < 120 || dcn32_allow_subvp_high_refresh_rate(dc, context, pipe)) && !pipe->plane_state->address.tmz_surface && (vba->ActiveDRAMClockChangeLatencyMarginPerState[vba->VoltageLevel][vba->maxMpcComb][vba->pipe_plane[pipe_idx]] <= 0 || @@ -674,7 +683,7 @@ static bool dcn32_enough_pipes_for_subvp(struct dc *dc, struct dc_state *context // Find the minimum pipe split count for non SubVP pipes if (resource_is_pipe_type(pipe, OPP_HEAD) && - pipe->stream->mall_stream_config.type == SUBVP_NONE) { + dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_NONE) { split_cnt = 0; while (pipe) { split_cnt++; @@ -727,8 +736,8 @@ static bool subvp_subvp_schedulable(struct dc *dc, struct dc_state *context) * and also to store the two main SubVP pipe pointers in subvp_pipes[2]. */ if (pipe->stream && pipe->plane_state && !pipe->top_pipe && - pipe->stream->mall_stream_config.type == SUBVP_MAIN) { - phantom = pipe->stream->mall_stream_config.paired_stream; + dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_MAIN) { + phantom = dc_state_get_paired_subvp_stream(context, pipe->stream); microschedule_lines = (phantom->timing.v_total - phantom->timing.v_front_porch) + phantom->timing.v_addressable; @@ -796,6 +805,9 @@ static bool subvp_drr_schedulable(struct dc *dc, struct dc_state *context) int16_t stretched_drr_us = 0; int16_t drr_stretched_vblank_us = 0; int16_t max_vblank_mallregion = 0; + struct dc_stream_state *phantom_stream; + bool subvp_found = false; + bool drr_found = false; // Find SubVP pipe for (i = 0; i < dc->res_pool->pipe_count; i++) { @@ -808,8 +820,10 @@ static bool subvp_drr_schedulable(struct dc *dc, struct dc_state *context) continue; // Find the SubVP pipe - if (pipe->stream->mall_stream_config.type == SUBVP_MAIN) + if (dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_MAIN) { + subvp_found = true; break; + } } // Find the DRR pipe @@ -817,32 +831,37 @@ static bool subvp_drr_schedulable(struct dc *dc, struct dc_state *context) drr_pipe = &context->res_ctx.pipe_ctx[i]; // We check for master pipe only - if (!resource_is_pipe_type(pipe, OTG_MASTER) || - !resource_is_pipe_type(pipe, DPP_PIPE)) + if (!resource_is_pipe_type(drr_pipe, OTG_MASTER) || + !resource_is_pipe_type(drr_pipe, DPP_PIPE)) continue; - if (drr_pipe->stream->mall_stream_config.type == SUBVP_NONE && drr_pipe->stream->ignore_msa_timing_param && - (drr_pipe->stream->allow_freesync || drr_pipe->stream->vrr_active_variable || drr_pipe->stream->vrr_active_fixed)) + if (dc_state_get_pipe_subvp_type(context, drr_pipe) == SUBVP_NONE && drr_pipe->stream->ignore_msa_timing_param && + (drr_pipe->stream->allow_freesync || drr_pipe->stream->vrr_active_variable || drr_pipe->stream->vrr_active_fixed)) { + drr_found = true; break; + } } - main_timing = &pipe->stream->timing; - phantom_timing = &pipe->stream->mall_stream_config.paired_stream->timing; - drr_timing = &drr_pipe->stream->timing; - prefetch_us = (phantom_timing->v_total - phantom_timing->v_front_porch) * phantom_timing->h_total / - (double)(phantom_timing->pix_clk_100hz * 100) * 1000000 + - dc->caps.subvp_prefetch_end_to_mall_start_us; - subvp_active_us = main_timing->v_addressable * main_timing->h_total / - (double)(main_timing->pix_clk_100hz * 100) * 1000000; - drr_frame_us = drr_timing->v_total * drr_timing->h_total / - (double)(drr_timing->pix_clk_100hz * 100) * 1000000; - // P-State allow width and FW delays already included phantom_timing->v_addressable - mall_region_us = phantom_timing->v_addressable * phantom_timing->h_total / - (double)(phantom_timing->pix_clk_100hz * 100) * 1000000; - stretched_drr_us = drr_frame_us + mall_region_us + SUBVP_DRR_MARGIN_US; - drr_stretched_vblank_us = (drr_timing->v_total - drr_timing->v_addressable) * drr_timing->h_total / - (double)(drr_timing->pix_clk_100hz * 100) * 1000000 + (stretched_drr_us - drr_frame_us); - max_vblank_mallregion = drr_stretched_vblank_us > mall_region_us ? drr_stretched_vblank_us : mall_region_us; + if (subvp_found && drr_found) { + phantom_stream = dc_state_get_paired_subvp_stream(context, pipe->stream); + main_timing = &pipe->stream->timing; + phantom_timing = &phantom_stream->timing; + drr_timing = &drr_pipe->stream->timing; + prefetch_us = (phantom_timing->v_total - phantom_timing->v_front_porch) * phantom_timing->h_total / + (double)(phantom_timing->pix_clk_100hz * 100) * 1000000 + + dc->caps.subvp_prefetch_end_to_mall_start_us; + subvp_active_us = main_timing->v_addressable * main_timing->h_total / + (double)(main_timing->pix_clk_100hz * 100) * 1000000; + drr_frame_us = drr_timing->v_total * drr_timing->h_total / + (double)(drr_timing->pix_clk_100hz * 100) * 1000000; + // P-State allow width and FW delays already included phantom_timing->v_addressable + mall_region_us = phantom_timing->v_addressable * phantom_timing->h_total / + (double)(phantom_timing->pix_clk_100hz * 100) * 1000000; + stretched_drr_us = drr_frame_us + mall_region_us + SUBVP_DRR_MARGIN_US; + drr_stretched_vblank_us = (drr_timing->v_total - drr_timing->v_addressable) * drr_timing->h_total / + (double)(drr_timing->pix_clk_100hz * 100) * 1000000 + (stretched_drr_us - drr_frame_us); + max_vblank_mallregion = drr_stretched_vblank_us > mall_region_us ? drr_stretched_vblank_us : mall_region_us; + } /* We consider SubVP + DRR schedulable if the stretched frame duration of the DRR display (i.e. the * highest refresh rate + margin that can support UCLK P-State switch) passes the static analysis @@ -887,6 +906,8 @@ static bool subvp_vblank_schedulable(struct dc *dc, struct dc_state *context) struct dc_crtc_timing *main_timing = NULL; struct dc_crtc_timing *phantom_timing = NULL; struct dc_crtc_timing *vblank_timing = NULL; + struct dc_stream_state *phantom_stream; + enum mall_stream_type pipe_mall_type; /* For SubVP + VBLANK/DRR cases, we assume there can only be * a single VBLANK/DRR display. If DML outputs SubVP + VBLANK @@ -896,6 +917,7 @@ static bool subvp_vblank_schedulable(struct dc *dc, struct dc_state *context) */ for (i = 0; i < dc->res_pool->pipe_count; i++) { pipe = &context->res_ctx.pipe_ctx[i]; + pipe_mall_type = dc_state_get_pipe_subvp_type(context, pipe); // We check for master pipe, but it shouldn't matter since we only need // the pipe for timing info (stream should be same for any pipe splits) @@ -903,18 +925,19 @@ static bool subvp_vblank_schedulable(struct dc *dc, struct dc_state *context) !resource_is_pipe_type(pipe, DPP_PIPE)) continue; - if (!found && pipe->stream->mall_stream_config.type == SUBVP_NONE) { + if (!found && pipe_mall_type == SUBVP_NONE) { // Found pipe which is not SubVP or Phantom (i.e. the VBLANK pipe). vblank_index = i; found = true; } - if (!subvp_pipe && pipe->stream->mall_stream_config.type == SUBVP_MAIN) + if (!subvp_pipe && pipe_mall_type == SUBVP_MAIN) subvp_pipe = pipe; } if (found) { + phantom_stream = dc_state_get_paired_subvp_stream(context, subvp_pipe->stream); main_timing = &subvp_pipe->stream->timing; - phantom_timing = &subvp_pipe->stream->mall_stream_config.paired_stream->timing; + phantom_timing = &phantom_stream->timing; vblank_timing = &context->res_ctx.pipe_ctx[vblank_index].stream->timing; // Prefetch time is equal to VACTIVE + BP + VSYNC of the phantom pipe // Also include the prefetch end to mallstart delay time @@ -969,7 +992,7 @@ static bool subvp_subvp_admissable(struct dc *dc, continue; if (pipe->plane_state && !pipe->top_pipe && - pipe->stream->mall_stream_config.type == SUBVP_MAIN) { + dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_MAIN) { refresh_rate = (pipe->stream->timing.pix_clk_100hz * (uint64_t)100 + pipe->stream->timing.v_total * pipe->stream->timing.h_total - (uint64_t)1); refresh_rate = div_u64(refresh_rate, pipe->stream->timing.v_total); @@ -1018,23 +1041,23 @@ static bool subvp_validate_static_schedulability(struct dc *dc, for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + enum mall_stream_type pipe_mall_type = dc_state_get_pipe_subvp_type(context, pipe); if (!pipe->stream) continue; if (pipe->plane_state && !pipe->top_pipe) { - if (pipe->stream->mall_stream_config.type == SUBVP_MAIN) + if (pipe_mall_type == SUBVP_MAIN) subvp_count++; - if (pipe->stream->mall_stream_config.type == SUBVP_NONE) { + if (pipe_mall_type == SUBVP_NONE) non_subvp_pipes++; - } } // Count how many planes that aren't SubVP/phantom are capable of VACTIVE // switching (SubVP + VACTIVE unsupported). In situations where we force // SubVP for a VACTIVE plane, we don't want to increment the vactive_count. if (vba->ActiveDRAMClockChangeLatencyMarginPerState[vlevel][vba->maxMpcComb][vba->pipe_plane[pipe_idx]] > 0 && - pipe->stream->mall_stream_config.type == SUBVP_NONE) { + pipe_mall_type == SUBVP_NONE) { vactive_count++; } pipe_idx++; @@ -1070,7 +1093,7 @@ static void assign_subvp_index(struct dc *dc, struct dc_state *context) struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; if (resource_is_pipe_type(pipe_ctx, OTG_MASTER) && - pipe_ctx->stream->mall_stream_config.type == SUBVP_MAIN) { + dc_state_get_pipe_subvp_type(context, pipe_ctx) == SUBVP_MAIN) { pipe_ctx->subvp_index = index++; } else { pipe_ctx->subvp_index = 0; @@ -1237,15 +1260,11 @@ static void update_pipes_with_slice_table(struct dc *dc, struct dc_state *contex { int i; - for (i = 0; i < table->odm_combine_count; i++) { + for (i = 0; i < table->odm_combine_count; i++) resource_update_pipes_for_stream_with_slice_count(context, dc->current_state, dc->res_pool, table->odm_combines[i].stream, table->odm_combines[i].slice_count); - /* TODO: move this into the function above */ - dcn20_build_mapped_resource(dc, context, - table->odm_combines[i].stream); - } for (i = 0; i < table->mpc_combine_count; i++) resource_update_pipes_for_plane_with_slice_count(context, @@ -1412,6 +1431,7 @@ static void dcn32_full_validate_bw_helper(struct dc *dc, unsigned int dc_pipe_idx = 0; int i = 0; bool found_supported_config = false; + int vlevel_temp = 0; dc_assert_fp_enabled(); @@ -1444,13 +1464,15 @@ static void dcn32_full_validate_bw_helper(struct dc *dc, */ if (!dc->debug.force_disable_subvp && !dc->caps.dmub_caps.gecc_enable && dcn32_all_pipes_have_stream_and_plane(dc, context) && !dcn32_mpo_in_use(context) && !dcn32_any_surfaces_rotated(dc, context) && !is_test_pattern_enabled(context) && - (*vlevel == context->bw_ctx.dml.soc.num_states || + (*vlevel == context->bw_ctx.dml.soc.num_states || (vba->DRAMSpeedPerState[*vlevel] != vba->DRAMSpeedPerState[0] && + vba->DRAMClockChangeSupport[*vlevel][vba->maxMpcComb] != dm_dram_clock_change_unsupported) || vba->DRAMClockChangeSupport[*vlevel][vba->maxMpcComb] == dm_dram_clock_change_unsupported || dc->debug.force_subvp_mclk_switch)) { dcn32_merge_pipes_for_subvp(dc, context); memset(merge, 0, MAX_PIPES * sizeof(bool)); + vlevel_temp = *vlevel; /* to re-initialize viewport after the pipe merge */ for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; @@ -1519,10 +1541,14 @@ static void dcn32_full_validate_bw_helper(struct dc *dc, } } + if (vba->DRAMSpeedPerState[*vlevel] >= vba->DRAMSpeedPerState[vlevel_temp]) + found_supported_config = false; + // If SubVP pipe config is unsupported (or cannot be used for UCLK switching) // remove phantom pipes and repopulate dml pipes if (!found_supported_config) { - dc->res_pool->funcs->remove_phantom_pipes(dc, context, false); + dc_state_remove_phantom_streams_and_planes(dc, context); + dc_state_release_phantom_streams_and_planes(dc, context); vba->DRAMClockChangeSupport[*vlevel][vba->maxMpcComb] = dm_dram_clock_change_unsupported; *pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, context, pipes, false); @@ -1674,7 +1700,7 @@ static void dcn32_calculate_dlg_params(struct dc *dc, struct dc_state *context, pipes[pipe_idx].pipe.dest.vready_offset = get_vready_offset(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx); - if (context->res_ctx.pipe_ctx[i].stream->mall_stream_config.type == SUBVP_PHANTOM) { + if (dc_state_get_pipe_subvp_type(context, &context->res_ctx.pipe_ctx[i]) == SUBVP_PHANTOM) { // Phantom pipe requires that DET_SIZE = 0 and no unbounded requests context->res_ctx.pipe_ctx[i].det_buffer_size_kb = 0; context->res_ctx.pipe_ctx[i].unbounded_req = false; @@ -1706,7 +1732,7 @@ static void dcn32_calculate_dlg_params(struct dc *dc, struct dc_state *context, 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) { + if (dc_state_get_pipe_subvp_type(context, &context->res_ctx.pipe_ctx[i]) != 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) { @@ -1920,7 +1946,8 @@ bool dcn32_internal_validate_bw(struct dc *dc, return false; // For each full update, remove all existing phantom pipes first - dc->res_pool->funcs->remove_phantom_pipes(dc, context, fast_validate); + dc_state_remove_phantom_streams_and_planes(dc, context); + dc_state_release_phantom_streams_and_planes(dc, context); dc->res_pool->funcs->update_soc_for_wm_a(dc, context); @@ -2182,6 +2209,7 @@ bool dcn32_internal_validate_bw(struct dc *dc, int i; pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, context, pipes, fast_validate); + dcn32_update_dml_pipes_odm_policy_based_on_context(dc, context, pipes); /* repopulate_pipes = 1 means the pipes were either split or merged. In this case * we have to re-calculate the DET allocation and run through DML once more to @@ -2190,7 +2218,9 @@ bool dcn32_internal_validate_bw(struct dc *dc, * */ context->bw_ctx.dml.soc.allow_for_pstate_or_stutter_in_vblank_final = dm_prefetch_support_uclk_fclk_and_stutter_if_possible; + vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt); + if (vlevel == context->bw_ctx.dml.soc.num_states) { /* failed after DET size changes */ goto validate_fail; @@ -3299,25 +3329,24 @@ bool dcn32_allow_subvp_with_active_margin(struct pipe_ctx *pipe) { bool allow = false; uint32_t refresh_rate = 0; + uint32_t min_refresh = subvp_active_margin_list.min_refresh; + uint32_t max_refresh = subvp_active_margin_list.max_refresh; + uint32_t i; - /* 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) + for (i = 0; i < SUBVP_ACTIVE_MARGIN_LIST_LEN; i++) { + uint32_t width = subvp_active_margin_list.res[i].width; + uint32_t height = subvp_active_margin_list.res[i].height; + + refresh_rate = (pipe->stream->timing.pix_clk_100hz * (uint64_t)100 + + pipe->stream->timing.v_total * pipe->stream->timing.h_total - (uint64_t)1); + refresh_rate = div_u64(refresh_rate, pipe->stream->timing.v_total); + refresh_rate = div_u64(refresh_rate, pipe->stream->timing.h_total); + + if (refresh_rate >= min_refresh && refresh_rate <= max_refresh && + dcn32_check_native_scaling_for_res(pipe, width, height)) { allow = true; + break; + } } return allow; } @@ -3436,7 +3465,15 @@ void dcn32_assign_fpo_vactive_candidate(struct dc *dc, const struct dc_state *co for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { const struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - if (!pipe->stream) + /* In DCN32/321, FPO uses per-pipe P-State force. + * If there's no planes, HUBP is power gated and + * therefore programming UCLK_PSTATE_FORCE does + * nothing (P-State will always be asserted naturally + * on a pipe that has HUBP power gated. Therefore we + * only want to enable FPO if the FPO pipe has both + * a stream and a plane. + */ + if (!pipe->stream || !pipe->plane_state) continue; if (vba->ActiveDRAMClockChangeLatencyMarginPerState[vba->VoltageLevel][vba->maxMpcComb][vba->pipe_plane[pipe_idx]] <= 0) { 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 cbdfb762c10c58..6c84b0fa40f44d 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 @@ -813,6 +813,8 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman (v->DRAMSpeedPerState[mode_lib->vba.VoltageLevel] <= MEM_STROBE_FREQ_MHZ || v->DCFCLKPerState[mode_lib->vba.VoltageLevel] <= DCFCLK_FREQ_EXTRA_PREFETCH_REQ_MHZ) ? mode_lib->vba.ip.min_prefetch_in_strobe_us : 0, + mode_lib->vba.PrefetchModePerState[mode_lib->vba.VoltageLevel][mode_lib->vba.maxMpcComb] > 0 || mode_lib->vba.DRAMClockChangeRequirementFinal == false, + /* Output */ &v->DSTXAfterScaler[k], &v->DSTYAfterScaler[k], @@ -3317,6 +3319,7 @@ void dml32_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l v->SwathHeightCThisState[k], v->TWait, (v->DRAMSpeedPerState[i] <= MEM_STROBE_FREQ_MHZ || v->DCFCLKState[i][j] <= DCFCLK_FREQ_EXTRA_PREFETCH_REQ_MHZ) ? mode_lib->vba.ip.min_prefetch_in_strobe_us : 0, + mode_lib->vba.PrefetchModePerState[i][j] > 0 || mode_lib->vba.DRAMClockChangeRequirementFinal == false, /* Output */ &v->dummy_vars.dml32_ModeSupportAndSystemConfigurationFull.DSTXAfterScaler[k], 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 d940dfa5ae43eb..80fccd4999a58a 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 @@ -3423,6 +3423,7 @@ bool dml32_CalculatePrefetchSchedule( unsigned int SwathHeightC, double TWait, double TPreReq, + bool ExtendPrefetchIfPossible, /* Output */ double *DSTXAfterScaler, double *DSTYAfterScaler, @@ -3892,12 +3893,32 @@ bool dml32_CalculatePrefetchSchedule( /* Clamp to oto for bandwidth calculation */ LinesForPrefetchBandwidth = dst_y_prefetch_oto; } else { - *DestinationLinesForPrefetch = dst_y_prefetch_equ; - TimeForFetchingMetaPTE = Tvm_equ; - TimeForFetchingRowInVBlank = Tr0_equ; - *PrefetchBandwidth = prefetch_bw_equ; - /* Clamp to equ for bandwidth calculation */ - LinesForPrefetchBandwidth = dst_y_prefetch_equ; + /* For mode programming we want to extend the prefetch as much as possible + * (up to oto, or as long as we can for equ) if we're not already applying + * the 60us prefetch requirement. This is to avoid intermittent underflow + * issues during prefetch. + * + * The prefetch extension is applied under the following scenarios: + * 1. We're in prefetch mode > 0 (i.e. we don't support MCLK switch in blank) + * 2. We're using subvp or drr methods of p-state switch, in which case we + * we don't care if prefetch takes up more of the blanking time + * + * Mode programming typically chooses the smallest prefetch time possible + * (i.e. highest bandwidth during prefetch) presumably to create margin between + * p-states / c-states that happen in vblank and prefetch. Therefore we only + * apply this prefetch extension when p-state in vblank is not required (UCLK + * p-states take up the most vblank time). + */ + if (ExtendPrefetchIfPossible && TPreReq == 0 && VStartup < MaxVStartup) { + MyError = true; + } else { + *DestinationLinesForPrefetch = dst_y_prefetch_equ; + TimeForFetchingMetaPTE = Tvm_equ; + TimeForFetchingRowInVBlank = Tr0_equ; + *PrefetchBandwidth = prefetch_bw_equ; + /* Clamp to equ for bandwidth calculation */ + LinesForPrefetchBandwidth = dst_y_prefetch_equ; + } } *DestinationLinesToRequestVMInVBlank = dml_ceil(4.0 * TimeForFetchingMetaPTE / LineTime, 1.0) / 4.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 592d174df6c629..5d34735df83db1 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 @@ -747,6 +747,7 @@ bool dml32_CalculatePrefetchSchedule( unsigned int SwathHeightC, double TWait, double TPreReq, + bool ExtendPrefetchIfPossible, /* Output */ double *DSTXAfterScaler, double *DSTYAfterScaler, diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c index f154a3eb1d1a0a..475c4ec43c013f 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn35/dcn35_fpu.c @@ -166,9 +166,9 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_5_soc = { .num_states = 5, .sr_exit_time_us = 14.0, .sr_enter_plus_exit_time_us = 16.0, - .sr_exit_z8_time_us = 525.0, - .sr_enter_plus_exit_z8_time_us = 715.0, - .fclk_change_latency_us = 20.0, + .sr_exit_z8_time_us = 210.0, + .sr_enter_plus_exit_z8_time_us = 320.0, + .fclk_change_latency_us = 24.0, .usr_retraining_latency_us = 2, .writeback_latency_us = 12.0, @@ -326,6 +326,25 @@ void dcn35_update_bw_bounding_box_fpu(struct dc *dc, dcn3_5_soc.dram_clock_change_latency_us = dc->debug.dram_clock_change_latency_ns / 1000.0; } + + if (dc->bb_overrides.dram_clock_change_latency_ns > 0) + dcn3_5_soc.dram_clock_change_latency_us = + dc->bb_overrides.dram_clock_change_latency_ns / 1000.0; + + if (dc->bb_overrides.sr_exit_time_ns > 0) + dcn3_5_soc.sr_exit_time_us = dc->bb_overrides.sr_exit_time_ns / 1000.0; + + if (dc->bb_overrides.sr_enter_plus_exit_time_ns > 0) + dcn3_5_soc.sr_enter_plus_exit_time_us = + dc->bb_overrides.sr_enter_plus_exit_time_ns / 1000.0; + + if (dc->bb_overrides.sr_exit_z8_time_ns > 0) + dcn3_5_soc.sr_exit_z8_time_us = dc->bb_overrides.sr_exit_z8_time_ns / 1000.0; + + if (dc->bb_overrides.sr_enter_plus_exit_z8_time_ns > 0) + dcn3_5_soc.sr_enter_plus_exit_z8_time_us = + dc->bb_overrides.sr_enter_plus_exit_z8_time_ns / 1000.0; + /*temp till dml2 fully work without dml1*/ dml_init_instance(&dc->dml, &dcn3_5_soc, &dcn3_5_ip, DML_PROJECT_DCN31); diff --git a/drivers/gpu/drm/amd/display/dc/dml2/display_mode_core.c b/drivers/gpu/drm/amd/display/dc/dml2/display_mode_core.c index b95bf27f2fe2fe..9be5ebf3a8c0ba 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/display_mode_core.c +++ b/drivers/gpu/drm/amd/display/dc/dml2/display_mode_core.c @@ -6229,7 +6229,7 @@ static void set_calculate_prefetch_schedule_params(struct display_mode_lib_st *m CalculatePrefetchSchedule_params->GPUVMEnable = mode_lib->ms.cache_display_cfg.plane.GPUVMEnable; CalculatePrefetchSchedule_params->HostVMEnable = mode_lib->ms.cache_display_cfg.plane.HostVMEnable; CalculatePrefetchSchedule_params->HostVMMaxNonCachedPageTableLevels = mode_lib->ms.cache_display_cfg.plane.HostVMMaxPageTableLevels; - CalculatePrefetchSchedule_params->HostVMMinPageSize = mode_lib->ms.soc.hostvm_min_page_size_kbytes; + CalculatePrefetchSchedule_params->HostVMMinPageSize = mode_lib->ms.soc.hostvm_min_page_size_kbytes * 1024; CalculatePrefetchSchedule_params->DynamicMetadataEnable = mode_lib->ms.cache_display_cfg.plane.DynamicMetadataEnable[k]; CalculatePrefetchSchedule_params->DynamicMetadataVMEnabled = mode_lib->ms.ip.dynamic_metadata_vm_enabled; CalculatePrefetchSchedule_params->DynamicMetadataLinesBeforeActiveRequired = mode_lib->ms.cache_display_cfg.plane.DynamicMetadataLinesBeforeActiveRequired[k]; @@ -6329,7 +6329,7 @@ static void dml_prefetch_check(struct display_mode_lib_st *mode_lib) mode_lib->ms.NoOfDPPThisState, mode_lib->ms.dpte_group_bytes, s->HostVMInefficiencyFactor, - mode_lib->ms.soc.hostvm_min_page_size_kbytes, + mode_lib->ms.soc.hostvm_min_page_size_kbytes * 1024, mode_lib->ms.cache_display_cfg.plane.HostVMMaxPageTableLevels); s->NextMaxVStartup = s->MaxVStartupAllPlanes[j]; @@ -6542,7 +6542,7 @@ static void dml_prefetch_check(struct display_mode_lib_st *mode_lib) mode_lib->ms.cache_display_cfg.plane.HostVMEnable, mode_lib->ms.cache_display_cfg.plane.HostVMMaxPageTableLevels, mode_lib->ms.cache_display_cfg.plane.GPUVMEnable, - mode_lib->ms.soc.hostvm_min_page_size_kbytes, + mode_lib->ms.soc.hostvm_min_page_size_kbytes * 1024, mode_lib->ms.PDEAndMetaPTEBytesPerFrame[j][k], mode_lib->ms.MetaRowBytes[j][k], mode_lib->ms.DPTEBytesPerRow[j][k], @@ -7687,7 +7687,7 @@ dml_bool_t dml_core_mode_support(struct display_mode_lib_st *mode_lib) CalculateVMRowAndSwath_params->HostVMMaxNonCachedPageTableLevels = mode_lib->ms.cache_display_cfg.plane.HostVMMaxPageTableLevels; CalculateVMRowAndSwath_params->GPUVMMaxPageTableLevels = mode_lib->ms.cache_display_cfg.plane.GPUVMMaxPageTableLevels; CalculateVMRowAndSwath_params->GPUVMMinPageSizeKBytes = mode_lib->ms.cache_display_cfg.plane.GPUVMMinPageSizeKBytes; - CalculateVMRowAndSwath_params->HostVMMinPageSize = mode_lib->ms.soc.hostvm_min_page_size_kbytes; + CalculateVMRowAndSwath_params->HostVMMinPageSize = mode_lib->ms.soc.hostvm_min_page_size_kbytes * 1024; CalculateVMRowAndSwath_params->PTEBufferModeOverrideEn = mode_lib->ms.cache_display_cfg.plane.PTEBufferModeOverrideEn; CalculateVMRowAndSwath_params->PTEBufferModeOverrideVal = mode_lib->ms.cache_display_cfg.plane.PTEBufferMode; CalculateVMRowAndSwath_params->PTEBufferSizeNotExceeded = mode_lib->ms.PTEBufferSizeNotExceededPerState; @@ -7957,7 +7957,7 @@ dml_bool_t dml_core_mode_support(struct display_mode_lib_st *mode_lib) UseMinimumDCFCLK_params->GPUVMMaxPageTableLevels = mode_lib->ms.cache_display_cfg.plane.GPUVMMaxPageTableLevels; UseMinimumDCFCLK_params->HostVMEnable = mode_lib->ms.cache_display_cfg.plane.HostVMEnable; UseMinimumDCFCLK_params->NumberOfActiveSurfaces = mode_lib->ms.num_active_planes; - UseMinimumDCFCLK_params->HostVMMinPageSize = mode_lib->ms.soc.hostvm_min_page_size_kbytes; + UseMinimumDCFCLK_params->HostVMMinPageSize = mode_lib->ms.soc.hostvm_min_page_size_kbytes * 1024; UseMinimumDCFCLK_params->HostVMMaxNonCachedPageTableLevels = mode_lib->ms.cache_display_cfg.plane.HostVMMaxPageTableLevels; UseMinimumDCFCLK_params->DynamicMetadataVMEnabled = mode_lib->ms.ip.dynamic_metadata_vm_enabled; UseMinimumDCFCLK_params->ImmediateFlipRequirement = s->ImmediateFlipRequiredFinal; @@ -8699,7 +8699,7 @@ void dml_core_mode_programming(struct display_mode_lib_st *mode_lib, const struc CalculateVMRowAndSwath_params->HostVMMaxNonCachedPageTableLevels = mode_lib->ms.cache_display_cfg.plane.HostVMMaxPageTableLevels; CalculateVMRowAndSwath_params->GPUVMMaxPageTableLevels = mode_lib->ms.cache_display_cfg.plane.GPUVMMaxPageTableLevels; CalculateVMRowAndSwath_params->GPUVMMinPageSizeKBytes = mode_lib->ms.cache_display_cfg.plane.GPUVMMinPageSizeKBytes; - CalculateVMRowAndSwath_params->HostVMMinPageSize = mode_lib->ms.soc.hostvm_min_page_size_kbytes; + CalculateVMRowAndSwath_params->HostVMMinPageSize = mode_lib->ms.soc.hostvm_min_page_size_kbytes * 1024; CalculateVMRowAndSwath_params->PTEBufferModeOverrideEn = mode_lib->ms.cache_display_cfg.plane.PTEBufferModeOverrideEn; CalculateVMRowAndSwath_params->PTEBufferModeOverrideVal = mode_lib->ms.cache_display_cfg.plane.PTEBufferMode; CalculateVMRowAndSwath_params->PTEBufferSizeNotExceeded = s->dummy_boolean_array[0]; @@ -8805,7 +8805,7 @@ void dml_core_mode_programming(struct display_mode_lib_st *mode_lib, const struc mode_lib->ms.cache_display_cfg.hw.DPPPerSurface, locals->dpte_group_bytes, s->HostVMInefficiencyFactor, - mode_lib->ms.soc.hostvm_min_page_size_kbytes, + mode_lib->ms.soc.hostvm_min_page_size_kbytes * 1024, mode_lib->ms.cache_display_cfg.plane.HostVMMaxPageTableLevels); locals->TCalc = 24.0 / locals->DCFCLKDeepSleep; @@ -8995,7 +8995,7 @@ void dml_core_mode_programming(struct display_mode_lib_st *mode_lib, const struc CalculatePrefetchSchedule_params->GPUVMEnable = mode_lib->ms.cache_display_cfg.plane.GPUVMEnable; CalculatePrefetchSchedule_params->HostVMEnable = mode_lib->ms.cache_display_cfg.plane.HostVMEnable; CalculatePrefetchSchedule_params->HostVMMaxNonCachedPageTableLevels = mode_lib->ms.cache_display_cfg.plane.HostVMMaxPageTableLevels; - CalculatePrefetchSchedule_params->HostVMMinPageSize = mode_lib->ms.soc.hostvm_min_page_size_kbytes; + CalculatePrefetchSchedule_params->HostVMMinPageSize = mode_lib->ms.soc.hostvm_min_page_size_kbytes * 1024; CalculatePrefetchSchedule_params->DynamicMetadataEnable = mode_lib->ms.cache_display_cfg.plane.DynamicMetadataEnable[k]; CalculatePrefetchSchedule_params->DynamicMetadataVMEnabled = mode_lib->ms.ip.dynamic_metadata_vm_enabled; CalculatePrefetchSchedule_params->DynamicMetadataLinesBeforeActiveRequired = mode_lib->ms.cache_display_cfg.plane.DynamicMetadataLinesBeforeActiveRequired[k]; @@ -9240,7 +9240,7 @@ void dml_core_mode_programming(struct display_mode_lib_st *mode_lib, const struc mode_lib->ms.cache_display_cfg.plane.HostVMEnable, mode_lib->ms.cache_display_cfg.plane.HostVMMaxPageTableLevels, mode_lib->ms.cache_display_cfg.plane.GPUVMEnable, - mode_lib->ms.soc.hostvm_min_page_size_kbytes, + mode_lib->ms.soc.hostvm_min_page_size_kbytes * 1024, locals->PDEAndMetaPTEBytesFrame[k], locals->MetaRowByte[k], locals->PixelPTEBytesPerRow[k], @@ -9446,13 +9446,13 @@ void dml_core_mode_programming(struct display_mode_lib_st *mode_lib, const struc CalculateWatermarks_params->CompressedBufferSizeInkByte = locals->CompressedBufferSizeInkByte; // Output - CalculateWatermarks_params->Watermark = &s->dummy_watermark; // Watermarks *Watermark - CalculateWatermarks_params->DRAMClockChangeSupport = &mode_lib->ms.support.DRAMClockChangeSupport[0]; - CalculateWatermarks_params->MaxActiveDRAMClockChangeLatencySupported = &s->dummy_single_array[0][0]; // dml_float_t *MaxActiveDRAMClockChangeLatencySupported[] - CalculateWatermarks_params->SubViewportLinesNeededInMALL = &mode_lib->ms.SubViewportLinesNeededInMALL[j]; // dml_uint_t SubViewportLinesNeededInMALL[] - CalculateWatermarks_params->FCLKChangeSupport = &mode_lib->ms.support.FCLKChangeSupport[0]; - CalculateWatermarks_params->MaxActiveFCLKChangeLatencySupported = &s->dummy_single[0]; // dml_float_t *MaxActiveFCLKChangeLatencySupported - CalculateWatermarks_params->USRRetrainingSupport = &mode_lib->ms.support.USRRetrainingSupport[0]; + CalculateWatermarks_params->Watermark = &locals->Watermark; // Watermarks *Watermark + CalculateWatermarks_params->DRAMClockChangeSupport = &locals->DRAMClockChangeSupport; + CalculateWatermarks_params->MaxActiveDRAMClockChangeLatencySupported = locals->MaxActiveDRAMClockChangeLatencySupported; // dml_float_t *MaxActiveDRAMClockChangeLatencySupported[] + CalculateWatermarks_params->SubViewportLinesNeededInMALL = locals->SubViewportLinesNeededInMALL; // dml_uint_t SubViewportLinesNeededInMALL[] + CalculateWatermarks_params->FCLKChangeSupport = &locals->FCLKChangeSupport; + CalculateWatermarks_params->MaxActiveFCLKChangeLatencySupported = &locals->MaxActiveFCLKChangeLatencySupported; // dml_float_t *MaxActiveFCLKChangeLatencySupported + CalculateWatermarks_params->USRRetrainingSupport = &locals->USRRetrainingSupport; CalculateWatermarksMALLUseAndDRAMSpeedChangeSupport( &mode_lib->scratch, diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_dc_resource_mgmt.c b/drivers/gpu/drm/amd/display/dc/dml2/dml2_dc_resource_mgmt.c index 1a2b24cc6b61d5..0baf39d64a2d4f 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_dc_resource_mgmt.c +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_dc_resource_mgmt.c @@ -772,18 +772,29 @@ static unsigned int get_mpc_factor(struct dml2_context *ctx, const struct dc_state *state, const struct dml_display_cfg_st *disp_cfg, struct dml2_dml_to_dc_pipe_mapping *mapping, - const struct dc_stream_status *status, unsigned int stream_id, + const struct dc_stream_status *status, + const struct dc_stream_state *stream, int plane_idx) { unsigned int plane_id; unsigned int cfg_idx; + unsigned int mpc_factor; - get_plane_id(ctx, state, status->plane_states[plane_idx], stream_id, plane_idx, &plane_id); + get_plane_id(ctx, state, status->plane_states[plane_idx], + stream->stream_id, plane_idx, &plane_id); cfg_idx = find_disp_cfg_idx_by_plane_id(mapping, plane_id); - if (ctx->architecture == dml2_architecture_20) - return (unsigned int)disp_cfg->hw.DPPPerSurface[cfg_idx]; - ASSERT(false); - return 1; + if (ctx->architecture == dml2_architecture_20) { + mpc_factor = (unsigned int)disp_cfg->hw.DPPPerSurface[cfg_idx]; + } else { + mpc_factor = 1; + ASSERT(false); + } + + /* For stereo timings, we need to pipe split */ + if (dml2_is_stereo_timing(stream)) + mpc_factor = 2; + + return mpc_factor; } static unsigned int get_odm_factor( @@ -820,14 +831,13 @@ static void populate_mpc_factors_for_stream( unsigned int mpc_factors[MAX_PIPES]) { const struct dc_stream_status *status = &state->stream_status[stream_idx]; - unsigned int stream_id = state->streams[stream_idx]->stream_id; int i; for (i = 0; i < status->plane_count; i++) if (odm_factor == 1) mpc_factors[i] = get_mpc_factor( ctx, state, disp_cfg, mapping, status, - stream_id, i); + state->streams[stream_idx], i); else mpc_factors[i] = 1; } diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_dc_types.h b/drivers/gpu/drm/amd/display/dc/dml2/dml2_dc_types.h index e85866db80ff7b..7ca7f2a743c254 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_dc_types.h @@ -38,5 +38,6 @@ #include "core_types.h" #include "dsc.h" #include "clk_mgr.h" +#include "dc_state_priv.h" #endif //__DML2_DC_TYPES_H__ diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_mall_phantom.c b/drivers/gpu/drm/amd/display/dc/dml2/dml2_mall_phantom.c index 32f8a43af3d68c..282d70e2b18ab8 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_mall_phantom.c +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_mall_phantom.c @@ -51,7 +51,7 @@ unsigned int dml2_helper_calculate_num_ways_for_subvp(struct dml2_context *ctx, // Find the phantom pipes if (pipe->stream && pipe->plane_state && !pipe->top_pipe && !pipe->prev_odm_pipe && - pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) { + ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) { bytes_per_pixel = pipe->plane_state->format >= SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 ? 8 : 4; mblk_width = ctx->config.mall_cfg.mblk_width_pixels; mblk_height = bytes_per_pixel == 4 ? mblk_width = ctx->config.mall_cfg.mblk_height_4bpe_pixels : ctx->config.mall_cfg.mblk_height_8bpe_pixels; @@ -253,7 +253,7 @@ static bool assign_subvp_pipe(struct dml2_context *ctx, struct dc_state *context * to combine this with SubVP can cause issues with the scheduling). */ if (pipe->plane_state && !pipe->top_pipe && - pipe->stream->mall_stream_config.type == SUBVP_NONE && refresh_rate < 120 && + ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, pipe) == SUBVP_NONE && refresh_rate < 120 && vba->ActiveDRAMClockChangeLatencyMarginPerState[vba->VoltageLevel][vba->maxMpcComb][vba->pipe_plane[pipe_idx]] <= 0) { while (pipe) { num_pipes++; @@ -317,7 +317,7 @@ static bool enough_pipes_for_subvp(struct dml2_context *ctx, struct dc_state *st // Find the minimum pipe split count for non SubVP pipes if (pipe->stream && !pipe->top_pipe && - pipe->stream->mall_stream_config.type == SUBVP_NONE) { + ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(state, pipe) == SUBVP_NONE) { split_cnt = 0; while (pipe) { split_cnt++; @@ -372,8 +372,8 @@ static bool subvp_subvp_schedulable(struct dml2_context *ctx, struct dc_state *c * and also to store the two main SubVP pipe pointers in subvp_pipes[2]. */ if (pipe->stream && pipe->plane_state && !pipe->top_pipe && - pipe->stream->mall_stream_config.type == SUBVP_MAIN) { - phantom = pipe->stream->mall_stream_config.paired_stream; + ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, pipe) == SUBVP_MAIN) { + phantom = ctx->config.svp_pstate.callbacks.get_paired_subvp_stream(context, pipe->stream); microschedule_lines = (phantom->timing.v_total - phantom->timing.v_front_porch) + phantom->timing.v_addressable; @@ -435,6 +435,7 @@ bool dml2_svp_drr_schedulable(struct dml2_context *ctx, struct dc_state *context struct pipe_ctx *pipe = NULL; struct dc_crtc_timing *main_timing = NULL; struct dc_crtc_timing *phantom_timing = NULL; + struct dc_stream_state *phantom_stream; int16_t prefetch_us = 0; int16_t mall_region_us = 0; int16_t drr_frame_us = 0; // nominal frame time @@ -453,12 +454,13 @@ bool dml2_svp_drr_schedulable(struct dml2_context *ctx, struct dc_state *context continue; // Find the SubVP pipe - if (pipe->stream->mall_stream_config.type == SUBVP_MAIN) + if (ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, pipe) == SUBVP_MAIN) break; } + phantom_stream = ctx->config.svp_pstate.callbacks.get_paired_subvp_stream(context, pipe->stream); main_timing = &pipe->stream->timing; - phantom_timing = &pipe->stream->mall_stream_config.paired_stream->timing; + phantom_timing = &phantom_stream->timing; prefetch_us = (phantom_timing->v_total - phantom_timing->v_front_porch) * phantom_timing->h_total / (double)(phantom_timing->pix_clk_100hz * 100) * 1000000 + ctx->config.svp_pstate.subvp_prefetch_end_to_mall_start_us; @@ -519,6 +521,8 @@ static bool subvp_vblank_schedulable(struct dml2_context *ctx, struct dc_state * struct dc_crtc_timing *main_timing = NULL; struct dc_crtc_timing *phantom_timing = NULL; struct dc_crtc_timing *vblank_timing = NULL; + struct dc_stream_state *phantom_stream; + enum mall_stream_type pipe_mall_type; /* For SubVP + VBLANK/DRR cases, we assume there can only be * a single VBLANK/DRR display. If DML outputs SubVP + VBLANK @@ -528,19 +532,20 @@ static bool subvp_vblank_schedulable(struct dml2_context *ctx, struct dc_state * */ for (i = 0; i < ctx->config.dcn_pipe_count; i++) { pipe = &context->res_ctx.pipe_ctx[i]; + pipe_mall_type = ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, pipe); // We check for master pipe, but it shouldn't matter since we only need // the pipe for timing info (stream should be same for any pipe splits) if (!pipe->stream || !pipe->plane_state || pipe->top_pipe || pipe->prev_odm_pipe) continue; - if (!found && pipe->stream->mall_stream_config.type == SUBVP_NONE) { + if (!found && pipe_mall_type == SUBVP_NONE) { // Found pipe which is not SubVP or Phantom (i.e. the VBLANK pipe). vblank_index = i; found = true; } - if (!subvp_pipe && pipe->stream->mall_stream_config.type == SUBVP_MAIN) + if (!subvp_pipe && pipe_mall_type == SUBVP_MAIN) subvp_pipe = pipe; } // Use ignore_msa_timing_param flag to identify as DRR @@ -548,8 +553,9 @@ static bool subvp_vblank_schedulable(struct dml2_context *ctx, struct dc_state * // SUBVP + DRR case schedulable = dml2_svp_drr_schedulable(ctx, context, &context->res_ctx.pipe_ctx[vblank_index].stream->timing); } else if (found) { + phantom_stream = ctx->config.svp_pstate.callbacks.get_paired_subvp_stream(context, subvp_pipe->stream); main_timing = &subvp_pipe->stream->timing; - phantom_timing = &subvp_pipe->stream->mall_stream_config.paired_stream->timing; + phantom_timing = &phantom_stream->timing; vblank_timing = &context->res_ctx.pipe_ctx[vblank_index].stream->timing; // Prefetch time is equal to VACTIVE + BP + VSYNC of the phantom pipe // Also include the prefetch end to mallstart delay time @@ -602,19 +608,20 @@ bool dml2_svp_validate_static_schedulability(struct dml2_context *ctx, struct dc for (i = 0, pipe_idx = 0; i < ctx->config.dcn_pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + enum mall_stream_type pipe_mall_type = ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, pipe); if (!pipe->stream) continue; if (pipe->plane_state && !pipe->top_pipe && - pipe->stream->mall_stream_config.type == SUBVP_MAIN) + pipe_mall_type == SUBVP_MAIN) subvp_count++; // Count how many planes that aren't SubVP/phantom are capable of VACTIVE // switching (SubVP + VACTIVE unsupported). In situations where we force // SubVP for a VACTIVE plane, we don't want to increment the vactive_count. if (vba->ActiveDRAMClockChangeLatencyMargin[vba->pipe_plane[pipe_idx]] > 0 && - pipe->stream->mall_stream_config.type == SUBVP_NONE) { + pipe_mall_type == SUBVP_NONE) { vactive_count++; } pipe_idx++; @@ -708,14 +715,10 @@ static void set_phantom_stream_timing(struct dml2_context *ctx, struct dc_state static struct dc_stream_state *enable_phantom_stream(struct dml2_context *ctx, struct dc_state *state, unsigned int dc_pipe_idx, unsigned int svp_height, unsigned int vstartup) { struct pipe_ctx *ref_pipe = &state->res_ctx.pipe_ctx[dc_pipe_idx]; - struct dc_stream_state *phantom_stream = ctx->config.svp_pstate.callbacks.create_stream_for_sink(ref_pipe->stream->sink); - - phantom_stream->signal = SIGNAL_TYPE_VIRTUAL; - phantom_stream->dpms_off = true; - phantom_stream->mall_stream_config.type = SUBVP_PHANTOM; - phantom_stream->mall_stream_config.paired_stream = ref_pipe->stream; - ref_pipe->stream->mall_stream_config.type = SUBVP_MAIN; - ref_pipe->stream->mall_stream_config.paired_stream = phantom_stream; + struct dc_stream_state *phantom_stream = ctx->config.svp_pstate.callbacks.create_phantom_stream( + ctx->config.svp_pstate.callbacks.dc, + state, + ref_pipe->stream); /* stream has limited viewport and small timing */ memcpy(&phantom_stream->timing, &ref_pipe->stream->timing, sizeof(phantom_stream->timing)); @@ -723,7 +726,10 @@ static struct dc_stream_state *enable_phantom_stream(struct dml2_context *ctx, s memcpy(&phantom_stream->dst, &ref_pipe->stream->dst, sizeof(phantom_stream->dst)); set_phantom_stream_timing(ctx, state, ref_pipe, phantom_stream, dc_pipe_idx, svp_height, vstartup); - ctx->config.svp_pstate.callbacks.add_stream_to_ctx(ctx->config.svp_pstate.callbacks.dc, state, phantom_stream); + ctx->config.svp_pstate.callbacks.add_phantom_stream(ctx->config.svp_pstate.callbacks.dc, + state, + phantom_stream, + ref_pipe->stream); return phantom_stream; } @@ -740,7 +746,10 @@ static void enable_phantom_plane(struct dml2_context *ctx, if (curr_pipe->top_pipe && curr_pipe->top_pipe->plane_state == curr_pipe->plane_state) { phantom_plane = prev_phantom_plane; } else { - phantom_plane = ctx->config.svp_pstate.callbacks.create_plane(ctx->config.svp_pstate.callbacks.dc); + phantom_plane = ctx->config.svp_pstate.callbacks.create_phantom_plane( + ctx->config.svp_pstate.callbacks.dc, + state, + curr_pipe->plane_state); } memcpy(&phantom_plane->address, &curr_pipe->plane_state->address, sizeof(phantom_plane->address)); @@ -763,9 +772,7 @@ static void enable_phantom_plane(struct dml2_context *ctx, phantom_plane->clip_rect.y = 0; phantom_plane->clip_rect.height = phantom_stream->timing.v_addressable; - phantom_plane->is_phantom = true; - - ctx->config.svp_pstate.callbacks.add_plane_to_context(ctx->config.svp_pstate.callbacks.dc, phantom_stream, phantom_plane, state); + ctx->config.svp_pstate.callbacks.add_phantom_plane(ctx->config.svp_pstate.callbacks.dc, phantom_stream, phantom_plane, state); curr_pipe = curr_pipe->bottom_pipe; prev_phantom_plane = phantom_plane; @@ -790,7 +797,7 @@ static void add_phantom_pipes_for_main_pipe(struct dml2_context *ctx, struct dc_ // We determine which phantom pipes were added by comparing with // the phantom stream. if (pipe->plane_state && pipe->stream && pipe->stream == phantom_stream && - pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) { + ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(state, pipe) == SUBVP_PHANTOM) { pipe->stream->use_dynamic_meta = false; pipe->plane_state->flip_immediate = false; if (!ctx->config.svp_pstate.callbacks.build_scaling_params(pipe)) { @@ -800,7 +807,7 @@ static void add_phantom_pipes_for_main_pipe(struct dml2_context *ctx, struct dc_ } } -static bool remove_all_planes_for_stream(struct dml2_context *ctx, struct dc_stream_state *stream, struct dc_state *context) +static bool remove_all_phantom_planes_for_stream(struct dml2_context *ctx, struct dc_stream_state *stream, struct dc_state *context) { int i, old_plane_count; struct dc_stream_status *stream_status = NULL; @@ -821,9 +828,11 @@ static bool remove_all_planes_for_stream(struct dml2_context *ctx, struct dc_str for (i = 0; i < old_plane_count; i++) del_planes[i] = stream_status->plane_states[i]; - for (i = 0; i < old_plane_count; i++) - if (!ctx->config.svp_pstate.callbacks.remove_plane_from_context(ctx->config.svp_pstate.callbacks.dc, stream, del_planes[i], context)) + for (i = 0; i < old_plane_count; i++) { + if (!ctx->config.svp_pstate.callbacks.remove_phantom_plane(ctx->config.svp_pstate.callbacks.dc, stream, del_planes[i], context)) return false; + ctx->config.svp_pstate.callbacks.release_phantom_plane(ctx->config.svp_pstate.callbacks.dc, context, del_planes[i]); + } return true; } @@ -832,35 +841,21 @@ bool dml2_svp_remove_all_phantom_pipes(struct dml2_context *ctx, struct dc_state { int i; bool removed_pipe = false; - struct dc_plane_state *phantom_plane = NULL; struct dc_stream_state *phantom_stream = NULL; for (i = 0; i < ctx->config.dcn_pipe_count; i++) { struct pipe_ctx *pipe = &state->res_ctx.pipe_ctx[i]; // build scaling params for phantom pipes - if (pipe->plane_state && pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) { - phantom_plane = pipe->plane_state; + if (pipe->plane_state && pipe->stream && ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(state, pipe) == SUBVP_PHANTOM) { phantom_stream = pipe->stream; - remove_all_planes_for_stream(ctx, pipe->stream, state); - ctx->config.svp_pstate.callbacks.remove_stream_from_ctx(ctx->config.svp_pstate.callbacks.dc, state, pipe->stream); - - /* Ref count is incremented on allocation and also when added to the context. - * Therefore we must call release for the the phantom plane and stream once - * they are removed from the ctx to finally decrement the refcount to 0 to free. - */ - ctx->config.svp_pstate.callbacks.plane_state_release(phantom_plane); - ctx->config.svp_pstate.callbacks.stream_release(phantom_stream); + remove_all_phantom_planes_for_stream(ctx, phantom_stream, state); + ctx->config.svp_pstate.callbacks.remove_phantom_stream(ctx->config.svp_pstate.callbacks.dc, state, phantom_stream); + ctx->config.svp_pstate.callbacks.release_phantom_stream(ctx->config.svp_pstate.callbacks.dc, state, phantom_stream); removed_pipe = true; } - // Clear all phantom stream info - if (pipe->stream) { - pipe->stream->mall_stream_config.type = SUBVP_NONE; - pipe->stream->mall_stream_config.paired_stream = NULL; - } - if (pipe->plane_state) { pipe->plane_state->is_phantom = false; } diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c b/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c index db06a5b749b408..64d01a9cd68c85 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_translation_helper.c @@ -341,6 +341,9 @@ void dml2_init_soc_states(struct dml2_context *dml2, const struct dc *in_dc, break; } + if (dml2->config.bbox_overrides.clks_table.num_states) + p->in_states->num_states = dml2->config.bbox_overrides.clks_table.num_states; + /* Override from passed values, if available */ for (i = 0; i < p->in_states->num_states; i++) { if (dml2->config.bbox_overrides.sr_exit_latency_us) { @@ -397,7 +400,6 @@ void dml2_init_soc_states(struct dml2_context *dml2, const struct dc *in_dc, } /* Copy clocks tables entries, if available */ if (dml2->config.bbox_overrides.clks_table.num_states) { - p->in_states->num_states = dml2->config.bbox_overrides.clks_table.num_states; for (i = 0; i < dml2->config.bbox_overrides.clks_table.num_entries_per_clk.num_dcfclk_levels; i++) { p->in_states->state_array[i].dcfclk_mhz = dml2->config.bbox_overrides.clks_table.clk_entries[i].dcfclk_mhz; @@ -624,8 +626,8 @@ static void populate_dml_output_cfg_from_stream_state(struct dml_output_cfg_st * if (is_dp2p0_output_encoder(pipe)) out->OutputEncoder[location] = dml_dp2p0; break; - out->OutputEncoder[location] = dml_edp; case SIGNAL_TYPE_EDP: + out->OutputEncoder[location] = dml_edp; break; case SIGNAL_TYPE_HDMI_TYPE_A: case SIGNAL_TYPE_DVI_SINGLE_LINK: @@ -1047,8 +1049,10 @@ static void dml2_populate_pipe_to_plane_index_mapping(struct dml2_context *dml2, void map_dc_state_into_dml_display_cfg(struct dml2_context *dml2, struct dc_state *context, struct dml_display_cfg_st *dml_dispcfg) { - int i = 0, j = 0; + int i = 0, j = 0, k = 0; int disp_cfg_stream_location, disp_cfg_plane_location; + enum mall_stream_type stream_mall_type; + struct pipe_ctx *current_pipe_context; for (i = 0; i < __DML2_WRAPPER_MAX_STREAMS_PLANES__; i++) { dml2->v20.scratch.dml_to_dc_pipe_mapping.disp_cfg_to_stream_id_valid[i] = false; @@ -1068,7 +1072,17 @@ void map_dc_state_into_dml_display_cfg(struct dml2_context *dml2, struct dc_stat dml2_populate_pipe_to_plane_index_mapping(dml2, context); for (i = 0; i < context->stream_count; i++) { + current_pipe_context = NULL; + for (k = 0; k < MAX_PIPES; k++) { + /* find one pipe allocated to this stream for the purpose of getting + info about the link later */ + if (context->streams[i] == context->res_ctx.pipe_ctx[k].stream) { + current_pipe_context = &context->res_ctx.pipe_ctx[k]; + break; + } + } disp_cfg_stream_location = map_stream_to_dml_display_cfg(dml2, context->streams[i], dml_dispcfg); + stream_mall_type = dc_state_get_stream_subvp_type(context, context->streams[i]); if (disp_cfg_stream_location < 0) disp_cfg_stream_location = dml_dispcfg->num_timings++; @@ -1076,7 +1090,7 @@ void map_dc_state_into_dml_display_cfg(struct dml2_context *dml2, struct dc_stat ASSERT(disp_cfg_stream_location >= 0 && disp_cfg_stream_location <= __DML2_WRAPPER_MAX_STREAMS_PLANES__); populate_dml_timing_cfg_from_stream_state(&dml_dispcfg->timing, disp_cfg_stream_location, context->streams[i]); - populate_dml_output_cfg_from_stream_state(&dml_dispcfg->output, disp_cfg_stream_location, context->streams[i], &context->res_ctx.pipe_ctx[i]); + populate_dml_output_cfg_from_stream_state(&dml_dispcfg->output, disp_cfg_stream_location, context->streams[i], current_pipe_context); switch (context->streams[i]->debug.force_odm_combine_segments) { case 2: dml2->v20.dml_core_ctx.policy.ODMUse[disp_cfg_stream_location] = dml_odm_use_policy_combine_2to1; @@ -1113,10 +1127,10 @@ void map_dc_state_into_dml_display_cfg(struct dml2_context *dml2, struct dc_stat populate_dml_surface_cfg_from_plane_state(dml2->v20.dml_core_ctx.project, &dml_dispcfg->surface, disp_cfg_plane_location, context->stream_status[i].plane_states[j]); populate_dml_plane_cfg_from_plane_state(&dml_dispcfg->plane, disp_cfg_plane_location, context->stream_status[i].plane_states[j], context); - if (context->streams[i]->mall_stream_config.type == SUBVP_MAIN) { + if (stream_mall_type == SUBVP_MAIN) { dml_dispcfg->plane.UseMALLForPStateChange[disp_cfg_plane_location] = dml_use_mall_pstate_change_sub_viewport; dml_dispcfg->plane.UseMALLForStaticScreen[disp_cfg_plane_location] = dml_use_mall_static_screen_optimize; - } else if (context->streams[i]->mall_stream_config.type == SUBVP_PHANTOM) { + } else if (stream_mall_type == SUBVP_PHANTOM) { dml_dispcfg->plane.UseMALLForPStateChange[disp_cfg_plane_location] = dml_use_mall_pstate_change_phantom_pipe; dml_dispcfg->plane.UseMALLForStaticScreen[disp_cfg_plane_location] = dml_use_mall_static_screen_disable; dml2->v20.dml_core_ctx.policy.ImmediateFlipRequirement[disp_cfg_plane_location] = dml_immediate_flip_not_required; @@ -1133,7 +1147,7 @@ void map_dc_state_into_dml_display_cfg(struct dml2_context *dml2, struct dc_stat if (j >= 1) { populate_dml_timing_cfg_from_stream_state(&dml_dispcfg->timing, disp_cfg_plane_location, context->streams[i]); - populate_dml_output_cfg_from_stream_state(&dml_dispcfg->output, disp_cfg_plane_location, context->streams[i], &context->res_ctx.pipe_ctx[i]); + populate_dml_output_cfg_from_stream_state(&dml_dispcfg->output, disp_cfg_plane_location, context->streams[i], current_pipe_context); switch (context->streams[i]->debug.force_odm_combine_segments) { case 2: dml2->v20.dml_core_ctx.policy.ODMUse[disp_cfg_plane_location] = dml_odm_use_policy_combine_2to1; @@ -1145,9 +1159,9 @@ void map_dc_state_into_dml_display_cfg(struct dml2_context *dml2, struct dc_stat break; } - if (context->streams[i]->mall_stream_config.type == SUBVP_MAIN) + if (stream_mall_type == SUBVP_MAIN) dml_dispcfg->plane.UseMALLForPStateChange[disp_cfg_plane_location] = dml_use_mall_pstate_change_sub_viewport; - else if (context->streams[i]->mall_stream_config.type == SUBVP_PHANTOM) + else if (stream_mall_type == SUBVP_PHANTOM) dml_dispcfg->plane.UseMALLForPStateChange[disp_cfg_plane_location] = dml_use_mall_pstate_change_phantom_pipe; dml2->v20.scratch.dml_to_dc_pipe_mapping.disp_cfg_to_stream_id[disp_cfg_plane_location] = context->streams[i]->stream_id; diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_utils.c b/drivers/gpu/drm/amd/display/dc/dml2/dml2_utils.c index 2498b8341199ba..1068b962d1c12b 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_utils.c +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_utils.c @@ -155,8 +155,20 @@ unsigned int dml2_util_get_maximum_odm_combine_for_output(bool force_odm_4to1, e bool is_dp2p0_output_encoder(const struct pipe_ctx *pipe_ctx) { + if (pipe_ctx == NULL || pipe_ctx->stream == NULL) + return false; + /* 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); + + /* Count MST hubs once by treating only 1st remote sink in topology as an encoder */ + if (pipe_ctx->stream->link && pipe_ctx->stream->link->remote_sinks[0]) { + 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) && + (pipe_ctx->stream->link->remote_sinks[0]->sink_id == pipe_ctx->stream->sink->sink_id)); + } + 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)); @@ -275,6 +287,7 @@ static void populate_pipe_ctx_dlg_params_from_dml(struct pipe_ctx *pipe_ctx, str void dml2_calculate_rq_and_dlg_params(const struct dc *dc, struct dc_state *context, struct resource_context *out_new_hw_state, struct dml2_context *in_ctx, unsigned int pipe_cnt) { unsigned int dc_pipe_ctx_index, dml_pipe_idx, plane_id; + enum mall_stream_type pipe_mall_type; bool unbounded_req_enabled = false; struct dml2_calculate_rq_and_dlg_params_scratch *s = &in_ctx->v20.scratch.calculate_rq_and_dlg_params_scratch; @@ -322,7 +335,8 @@ void dml2_calculate_rq_and_dlg_params(const struct dc *dc, struct dc_state *cont */ populate_pipe_ctx_dlg_params_from_dml(&context->res_ctx.pipe_ctx[dc_pipe_ctx_index], &context->bw_ctx.dml2->v20.dml_core_ctx, dml_pipe_idx); - if (context->res_ctx.pipe_ctx[dc_pipe_ctx_index].stream->mall_stream_config.type == SUBVP_PHANTOM) { + pipe_mall_type = dc_state_get_pipe_subvp_type(context, &context->res_ctx.pipe_ctx[dc_pipe_ctx_index]); + if (pipe_mall_type == SUBVP_PHANTOM) { // Phantom pipe requires that DET_SIZE = 0 and no unbounded requests context->res_ctx.pipe_ctx[dc_pipe_ctx_index].det_buffer_size_kb = 0; context->res_ctx.pipe_ctx[dc_pipe_ctx_index].unbounded_req = false; @@ -349,7 +363,7 @@ void dml2_calculate_rq_and_dlg_params(const struct dc *dc, struct dc_state *cont context->res_ctx.pipe_ctx[dc_pipe_ctx_index].plane_state != context->res_ctx.pipe_ctx[dc_pipe_ctx_index].top_pipe->plane_state) && context->res_ctx.pipe_ctx[dc_pipe_ctx_index].prev_odm_pipe == NULL) { /* SS: all active surfaces stored in MALL */ - if (context->res_ctx.pipe_ctx[dc_pipe_ctx_index].stream->mall_stream_config.type != SUBVP_PHANTOM) { + if (pipe_mall_type != SUBVP_PHANTOM) { context->bw_ctx.bw.dcn.mall_ss_size_bytes += context->res_ctx.pipe_ctx[dc_pipe_ctx_index].surface_size_in_mall_bytes; } else { /* SUBVP: phantom surfaces only stored in MALL */ @@ -468,7 +482,7 @@ bool dml2_verify_det_buffer_configuration(struct dml2_context *in_ctx, struct dc return need_recalculation; } -bool dml2_is_stereo_timing(struct dc_stream_state *stream) +bool dml2_is_stereo_timing(const struct dc_stream_state *stream) { bool is_stereo = false; diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_utils.h b/drivers/gpu/drm/amd/display/dc/dml2/dml2_utils.h index 23b9028337d43e..5842d6d3c4b601 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_utils.h +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_utils.h @@ -42,7 +42,7 @@ void dml2_copy_clocks_to_dc_state(struct dml2_dcn_clocks *out_clks, struct dc_st void dml2_extract_watermark_set(struct dcn_watermarks *watermark, struct display_mode_lib_st *dml_core_ctx); int dml2_helper_find_dml_pipe_idx_by_stream_id(struct dml2_context *ctx, unsigned int stream_id); bool is_dtbclk_required(const struct dc *dc, struct dc_state *context); -bool dml2_is_stereo_timing(struct dc_stream_state *stream); +bool dml2_is_stereo_timing(const struct dc_stream_state *stream); /* * dml2_dc_construct_pipes - This function will determine if we need additional pipes based diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.c b/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.c index 8f231418870f2a..26307e599614c6 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.c +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.c @@ -418,7 +418,7 @@ static int find_drr_eligible_stream(struct dc_state *display_state) int i; for (i = 0; i < display_state->stream_count; i++) { - if (display_state->streams[i]->mall_stream_config.type == SUBVP_NONE + if (dc_state_get_stream_subvp_type(display_state, display_state->streams[i]) == SUBVP_NONE && display_state->streams[i]->ignore_msa_timing_param) { // Use ignore_msa_timing_param flag to identify as DRR return i; @@ -634,6 +634,8 @@ static bool dml2_validate_and_build_resource(const struct dc *in_dc, struct dc_s dml2_extract_watermark_set(&context->bw_ctx.bw.dcn.watermarks.b, &dml2->v20.dml_core_ctx); memcpy(&context->bw_ctx.bw.dcn.watermarks.c, &dml2->v20.g6_temp_read_watermark_set, sizeof(context->bw_ctx.bw.dcn.watermarks.c)); dml2_extract_watermark_set(&context->bw_ctx.bw.dcn.watermarks.d, &dml2->v20.dml_core_ctx); + //copy for deciding zstate use + context->bw_ctx.dml.vba.StutterPeriod = context->bw_ctx.dml2->v20.dml_core_ctx.mp.StutterPeriod; } return result; @@ -691,10 +693,15 @@ bool dml2_validate(const struct dc *in_dc, struct dc_state *context, bool fast_v return out; } +static inline struct dml2_context *dml2_allocate_memory(void) +{ + return (struct dml2_context *) kzalloc(sizeof(struct dml2_context), GFP_KERNEL); +} + bool dml2_create(const struct dc *in_dc, const struct dml2_configuration_options *config, struct dml2_context **dml2) { // Allocate Mode Lib Ctx - *dml2 = (struct dml2_context *) kzalloc(sizeof(struct dml2_context), GFP_KERNEL); + *dml2 = dml2_allocate_memory(); if (!(*dml2)) return false; @@ -745,3 +752,25 @@ void dml2_extract_dram_and_fclk_change_support(struct dml2_context *dml2, *fclk_change_support = (unsigned int) dml2->v20.dml_core_ctx.ms.support.FCLKChangeSupport[0]; *dram_clk_change_support = (unsigned int) dml2->v20.dml_core_ctx.ms.support.DRAMClockChangeSupport[0]; } + +void dml2_copy(struct dml2_context *dst_dml2, + struct dml2_context *src_dml2) +{ + /* copy Mode Lib Ctx */ + memcpy(dst_dml2, src_dml2, sizeof(struct dml2_context)); +} + +bool dml2_create_copy(struct dml2_context **dst_dml2, + struct dml2_context *src_dml2) +{ + /* Allocate Mode Lib Ctx */ + *dst_dml2 = dml2_allocate_memory(); + + if (!(*dst_dml2)) + return false; + + /* copy Mode Lib Ctx */ + dml2_copy(*dst_dml2, src_dml2); + + return true; +} diff --git a/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.h b/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.h index fe15baa4bf0948..ee0eb184eb6d7e 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.h +++ b/drivers/gpu/drm/amd/display/dc/dml2/dml2_wrapper.h @@ -93,15 +93,34 @@ struct dml2_dc_callbacks { struct dml2_dc_svp_callbacks { struct dc *dc; bool (*build_scaling_params)(struct pipe_ctx *pipe_ctx); - struct dc_stream_state* (*create_stream_for_sink)(struct dc_sink *dc_sink_data); - struct dc_plane_state* (*create_plane)(struct dc *dc); - enum dc_status (*add_stream_to_ctx)(struct dc *dc, struct dc_state *new_ctx, struct dc_stream_state *dc_stream); - bool (*add_plane_to_context)(const struct dc *dc, struct dc_stream_state *stream, struct dc_plane_state *plane_state, struct dc_state *context); - bool (*remove_plane_from_context)(const struct dc *dc, struct dc_stream_state *stream, struct dc_plane_state *plane_state, struct dc_state *context); - enum dc_status (*remove_stream_from_ctx)(struct dc *dc, struct dc_state *new_ctx, struct dc_stream_state *stream); - void (*plane_state_release)(struct dc_plane_state *plane_state); - void (*stream_release)(struct dc_stream_state *stream); + struct dc_stream_state* (*create_phantom_stream)(const struct dc *dc, + struct dc_state *state, + struct dc_stream_state *main_stream); + struct dc_plane_state* (*create_phantom_plane)(struct dc *dc, + struct dc_state *state, + struct dc_plane_state *main_plane); + enum dc_status (*add_phantom_stream)(struct dc *dc, + struct dc_state *state, + struct dc_stream_state *phantom_stream, + struct dc_stream_state *main_stream); + bool (*add_phantom_plane)(const struct dc *dc, struct dc_stream_state *stream, struct dc_plane_state *plane_state, struct dc_state *context); + bool (*remove_phantom_plane)(const struct dc *dc, + struct dc_stream_state *stream, + struct dc_plane_state *plane_state, + struct dc_state *context); + enum dc_status (*remove_phantom_stream)(struct dc *dc, + struct dc_state *state, + struct dc_stream_state *stream); + void (*release_phantom_plane)(const struct dc *dc, + struct dc_state *state, + struct dc_plane_state *plane); + void (*release_phantom_stream)(const struct dc *dc, + struct dc_state *state, + struct dc_stream_state *stream); void (*release_dsc)(struct resource_context *res_ctx, const struct resource_pool *pool, struct display_stream_compressor **dsc); + enum mall_stream_type (*get_pipe_subvp_type)(const struct dc_state *state, const struct pipe_ctx *pipe_ctx); + enum mall_stream_type (*get_stream_subvp_type)(const struct dc_state *state, const struct dc_stream_state *stream); + struct dc_stream_state *(*get_paired_subvp_stream)(const struct dc_state *state, const struct dc_stream_state *stream); }; struct dml2_clks_table_entry { @@ -191,6 +210,10 @@ bool dml2_create(const struct dc *in_dc, struct dml2_context **dml2); void dml2_destroy(struct dml2_context *dml2); +void dml2_copy(struct dml2_context *dst_dml2, + struct dml2_context *src_dml2); +bool dml2_create_copy(struct dml2_context **dst_dml2, + struct dml2_context *src_dml2); /* * dml2_validate - Determines if a display configuration is supported or not. diff --git a/drivers/gpu/drm/amd/display/dc/dsc/Makefile b/drivers/gpu/drm/amd/display/dc/dsc/Makefile index a2537229ee88bb..b183ba5a692efa 100644 --- a/drivers/gpu/drm/amd/display/dc/dsc/Makefile +++ b/drivers/gpu/drm/amd/display/dc/dsc/Makefile @@ -1,8 +1,34 @@ # SPDX-License-Identifier: MIT # # Makefile for the 'dsc' sub-component of DAL. + +ifdef CONFIG_DRM_AMD_DC_FP + +############################################################################### +# DCN20 +############################################################################### +DSC_DCN20 = dcn20_dsc.o + +AMD_DISPLAY_FILES += $(addprefix $(AMDDALPATH)/dc/dsc/dcn20/,$(DSC_DCN20)) + + + + +############################################################################### +# DCN35 +############################################################################### + +DSC_DCN35 = dcn35_dsc.o + +AMD_DISPLAY_FILES += $(addprefix $(AMDDALPATH)/dc/dsc/dcn35/,$(DSC_DCN35)) + + + +endif + DSC = dc_dsc.o rc_calc.o rc_calc_dpi.o AMD_DAL_DSC = $(addprefix $(AMDDALPATH)/dc/dsc/,$(DSC)) AMD_DISPLAY_FILES += $(AMD_DAL_DSC) + diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c b/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c index e8b5f17beb9636..0df6c55eb32608 100644 --- a/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c +++ b/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c @@ -331,8 +331,9 @@ bool dc_dsc_parse_dsc_dpcd(const struct dc *dc, int buff_block_size; int buff_size; - if (!dsc_buff_block_size_from_dpcd(dpcd_dsc_basic_data[DP_DSC_RC_BUF_BLK_SIZE - DP_DSC_SUPPORT], - &buff_block_size)) + if (!dsc_buff_block_size_from_dpcd( + dpcd_dsc_basic_data[DP_DSC_RC_BUF_BLK_SIZE - DP_DSC_SUPPORT] & 0x03, + &buff_block_size)) return false; buff_size = dpcd_dsc_basic_data[DP_DSC_RC_BUF_SIZE - DP_DSC_SUPPORT] + 1; @@ -357,10 +358,15 @@ bool dc_dsc_parse_dsc_dpcd(const struct dc *dc, { int dpcd_throughput = dpcd_dsc_basic_data[DP_DSC_PEAK_THROUGHPUT - DP_DSC_SUPPORT]; + int dsc_throughput_granular_delta; + + dsc_throughput_granular_delta = dpcd_dsc_basic_data[DP_DSC_RC_BUF_BLK_SIZE - DP_DSC_SUPPORT] >> 3; + dsc_throughput_granular_delta *= 2; if (!dsc_throughput_from_dpcd(dpcd_throughput & DP_DSC_THROUGHPUT_MODE_0_MASK, &dsc_sink_caps->throughput_mode_0_mps)) return false; + dsc_sink_caps->throughput_mode_0_mps += dsc_throughput_granular_delta; dpcd_throughput = (dpcd_throughput & DP_DSC_THROUGHPUT_MODE_1_MASK) >> DP_DSC_THROUGHPUT_MODE_1_SHIFT; if (!dsc_throughput_from_dpcd(dpcd_throughput, &dsc_sink_caps->throughput_mode_1_mps)) diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dcn20/dcn20_dsc.c b/drivers/gpu/drm/amd/display/dc/dsc/dcn20/dcn20_dsc.c new file mode 100644 index 00000000000000..c9ae2d8f0096fa --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dsc/dcn20/dcn20_dsc.c @@ -0,0 +1,780 @@ +/* + * Copyright 2017 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 + +#include "reg_helper.h" +#include "dcn20_dsc.h" +#include "dsc/dscc_types.h" +#include "dsc/rc_calc.h" + +static void dsc_write_to_registers(struct display_stream_compressor *dsc, const struct dsc_reg_values *reg_vals); + +/* Object I/F functions */ +static void dsc2_read_state(struct display_stream_compressor *dsc, struct dcn_dsc_state *s); +static bool dsc2_validate_stream(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg); +static void dsc2_set_config(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg, + struct dsc_optc_config *dsc_optc_cfg); +static void dsc2_enable(struct display_stream_compressor *dsc, int opp_pipe); +static void dsc2_disable(struct display_stream_compressor *dsc); +static void dsc2_disconnect(struct display_stream_compressor *dsc); + +static const struct dsc_funcs dcn20_dsc_funcs = { + .dsc_get_enc_caps = dsc2_get_enc_caps, + .dsc_read_state = dsc2_read_state, + .dsc_validate_stream = dsc2_validate_stream, + .dsc_set_config = dsc2_set_config, + .dsc_get_packed_pps = dsc2_get_packed_pps, + .dsc_enable = dsc2_enable, + .dsc_disable = dsc2_disable, + .dsc_disconnect = dsc2_disconnect, +}; + +/* Macro definitios for REG_SET macros*/ +#define CTX \ + dsc20->base.ctx + +#define REG(reg)\ + dsc20->dsc_regs->reg + +#undef FN +#define FN(reg_name, field_name) \ + dsc20->dsc_shift->field_name, dsc20->dsc_mask->field_name +#define DC_LOGGER \ + dsc->ctx->logger + +enum dsc_bits_per_comp { + DSC_BPC_8 = 8, + DSC_BPC_10 = 10, + DSC_BPC_12 = 12, + DSC_BPC_UNKNOWN +}; + +/* API functions (external or via structure->function_pointer) */ + +void dsc2_construct(struct dcn20_dsc *dsc, + struct dc_context *ctx, + int inst, + const struct dcn20_dsc_registers *dsc_regs, + const struct dcn20_dsc_shift *dsc_shift, + const struct dcn20_dsc_mask *dsc_mask) +{ + dsc->base.ctx = ctx; + dsc->base.inst = inst; + dsc->base.funcs = &dcn20_dsc_funcs; + + dsc->dsc_regs = dsc_regs; + dsc->dsc_shift = dsc_shift; + dsc->dsc_mask = dsc_mask; + + dsc->max_image_width = 5184; +} + + +#define DCN20_MAX_PIXEL_CLOCK_Mhz 1188 +#define DCN20_MAX_DISPLAY_CLOCK_Mhz 1200 + +/* This returns the capabilities for a single DSC encoder engine. Number of slices and total throughput + * can be doubled, tripled etc. by using additional DSC engines. + */ +void dsc2_get_enc_caps(struct dsc_enc_caps *dsc_enc_caps, int pixel_clock_100Hz) +{ + dsc_enc_caps->dsc_version = 0x21; /* v1.2 - DP spec defined it in reverse order and we kept it */ + + dsc_enc_caps->slice_caps.bits.NUM_SLICES_1 = 1; + dsc_enc_caps->slice_caps.bits.NUM_SLICES_2 = 1; + dsc_enc_caps->slice_caps.bits.NUM_SLICES_3 = 1; + dsc_enc_caps->slice_caps.bits.NUM_SLICES_4 = 1; + + dsc_enc_caps->lb_bit_depth = 13; + dsc_enc_caps->is_block_pred_supported = true; + + dsc_enc_caps->color_formats.bits.RGB = 1; + dsc_enc_caps->color_formats.bits.YCBCR_444 = 1; + dsc_enc_caps->color_formats.bits.YCBCR_SIMPLE_422 = 1; + dsc_enc_caps->color_formats.bits.YCBCR_NATIVE_422 = 0; + dsc_enc_caps->color_formats.bits.YCBCR_NATIVE_420 = 1; + + dsc_enc_caps->color_depth.bits.COLOR_DEPTH_8_BPC = 1; + dsc_enc_caps->color_depth.bits.COLOR_DEPTH_10_BPC = 1; + dsc_enc_caps->color_depth.bits.COLOR_DEPTH_12_BPC = 1; + + /* Maximum total throughput with all the slices combined. This is different from how DP spec specifies it. + * Our decoder's total throughput in Pix/s is equal to DISPCLK. This is then shared between slices. + * The value below is the absolute maximum value. The actual throughput may be lower, but it'll always + * be sufficient to process the input pixel rate fed into a single DSC engine. + */ + dsc_enc_caps->max_total_throughput_mps = DCN20_MAX_DISPLAY_CLOCK_Mhz; + + /* For pixel clock bigger than a single-pipe limit we'll need two engines, which then doubles our + * throughput and number of slices, but also introduces a lower limit of 2 slices + */ + if (pixel_clock_100Hz >= DCN20_MAX_PIXEL_CLOCK_Mhz*10000) { + dsc_enc_caps->slice_caps.bits.NUM_SLICES_1 = 0; + dsc_enc_caps->slice_caps.bits.NUM_SLICES_8 = 1; + dsc_enc_caps->max_total_throughput_mps = DCN20_MAX_DISPLAY_CLOCK_Mhz * 2; + } + + /* For pixel clock bigger than a single-pipe limit needing four engines ODM 4:1, which then quardruples our + * throughput and number of slices + */ + if (pixel_clock_100Hz > DCN20_MAX_PIXEL_CLOCK_Mhz*10000*2) { + dsc_enc_caps->slice_caps.bits.NUM_SLICES_12 = 1; + dsc_enc_caps->slice_caps.bits.NUM_SLICES_16 = 1; + dsc_enc_caps->max_total_throughput_mps = DCN20_MAX_DISPLAY_CLOCK_Mhz * 4; + } + + dsc_enc_caps->max_slice_width = 5184; /* (including 64 overlap pixels for eDP MSO mode) */ + dsc_enc_caps->bpp_increment_div = 16; /* 1/16th of a bit */ +} + + +/* this function read dsc related register fields to be logged later in dcn10_log_hw_state + * into a dcn_dsc_state struct. + */ +static void dsc2_read_state(struct display_stream_compressor *dsc, struct dcn_dsc_state *s) +{ + struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc); + + REG_GET(DSC_TOP_CONTROL, DSC_CLOCK_EN, &s->dsc_clock_en); + REG_GET(DSCC_PPS_CONFIG3, SLICE_WIDTH, &s->dsc_slice_width); + REG_GET(DSCC_PPS_CONFIG1, BITS_PER_PIXEL, &s->dsc_bits_per_pixel); + REG_GET(DSCC_PPS_CONFIG3, SLICE_HEIGHT, &s->dsc_slice_height); + REG_GET(DSCC_PPS_CONFIG1, CHUNK_SIZE, &s->dsc_chunk_size); + REG_GET(DSCC_PPS_CONFIG2, PIC_WIDTH, &s->dsc_pic_width); + REG_GET(DSCC_PPS_CONFIG2, PIC_HEIGHT, &s->dsc_pic_height); + REG_GET(DSCC_PPS_CONFIG7, SLICE_BPG_OFFSET, &s->dsc_slice_bpg_offset); + REG_GET_2(DSCRM_DSC_FORWARD_CONFIG, DSCRM_DSC_FORWARD_EN, &s->dsc_fw_en, + DSCRM_DSC_OPP_PIPE_SOURCE, &s->dsc_opp_source); +} + + +static bool dsc2_validate_stream(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg) +{ + struct dsc_optc_config dsc_optc_cfg; + struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc); + + if (dsc_cfg->pic_width > dsc20->max_image_width) + return false; + + return dsc_prepare_config(dsc_cfg, &dsc20->reg_vals, &dsc_optc_cfg); +} + + +void dsc_config_log(struct display_stream_compressor *dsc, const struct dsc_config *config) +{ + DC_LOG_DSC("\tnum_slices_h %d", config->dc_dsc_cfg.num_slices_h); + DC_LOG_DSC("\tnum_slices_v %d", config->dc_dsc_cfg.num_slices_v); + DC_LOG_DSC("\tbits_per_pixel %d (%d.%04d)", + config->dc_dsc_cfg.bits_per_pixel, + config->dc_dsc_cfg.bits_per_pixel / 16, + ((config->dc_dsc_cfg.bits_per_pixel % 16) * 10000) / 16); + DC_LOG_DSC("\tcolor_depth %d", config->color_depth); +} + +static void dsc2_set_config(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg, + struct dsc_optc_config *dsc_optc_cfg) +{ + bool is_config_ok; + struct dcn20_dsc *dsc20 = TO_DCN20_DSC(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); + ASSERT(is_config_ok); + DC_LOG_DSC("programming DSC Picture Parameter Set (PPS):"); + dsc_log_pps(dsc, &dsc20->reg_vals.pps); + dsc_write_to_registers(dsc, &dsc20->reg_vals); +} + + +bool dsc2_get_packed_pps(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg, uint8_t *dsc_packed_pps) +{ + bool is_config_ok; + struct dsc_reg_values dsc_reg_vals; + struct dsc_optc_config dsc_optc_cfg; + + memset(&dsc_reg_vals, 0, sizeof(dsc_reg_vals)); + memset(&dsc_optc_cfg, 0, sizeof(dsc_optc_cfg)); + + DC_LOG_DSC("Getting packed DSC PPS for DSC Config:"); + dsc_config_log(dsc, dsc_cfg); + DC_LOG_DSC("DSC Picture Parameter Set (PPS):"); + is_config_ok = dsc_prepare_config(dsc_cfg, &dsc_reg_vals, &dsc_optc_cfg); + ASSERT(is_config_ok); + drm_dsc_pps_payload_pack((struct drm_dsc_picture_parameter_set *)dsc_packed_pps, &dsc_reg_vals.pps); + dsc_log_pps(dsc, &dsc_reg_vals.pps); + + return is_config_ok; +} + + +static void dsc2_enable(struct display_stream_compressor *dsc, int opp_pipe) +{ + struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc); + int dsc_clock_en; + int dsc_fw_config; + int enabled_opp_pipe; + + DC_LOG_DSC("enable DSC %d at opp pipe %d", dsc->inst, opp_pipe); + + REG_GET(DSC_TOP_CONTROL, DSC_CLOCK_EN, &dsc_clock_en); + REG_GET_2(DSCRM_DSC_FORWARD_CONFIG, DSCRM_DSC_FORWARD_EN, &dsc_fw_config, DSCRM_DSC_OPP_PIPE_SOURCE, &enabled_opp_pipe); + if ((dsc_clock_en || dsc_fw_config) && enabled_opp_pipe != opp_pipe) { + DC_LOG_DSC("ERROR: DSC %d at opp pipe %d already enabled!", dsc->inst, enabled_opp_pipe); + ASSERT(0); + } + + REG_UPDATE(DSC_TOP_CONTROL, + DSC_CLOCK_EN, 1); + + REG_UPDATE_2(DSCRM_DSC_FORWARD_CONFIG, + DSCRM_DSC_FORWARD_EN, 1, + DSCRM_DSC_OPP_PIPE_SOURCE, opp_pipe); +} + + +static void dsc2_disable(struct display_stream_compressor *dsc) +{ + struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc); + int dsc_clock_en; + int dsc_fw_config; + int enabled_opp_pipe; + + DC_LOG_DSC("disable DSC %d", dsc->inst); + + REG_GET(DSC_TOP_CONTROL, DSC_CLOCK_EN, &dsc_clock_en); + REG_GET_2(DSCRM_DSC_FORWARD_CONFIG, DSCRM_DSC_FORWARD_EN, &dsc_fw_config, DSCRM_DSC_OPP_PIPE_SOURCE, &enabled_opp_pipe); + if (!dsc_clock_en || !dsc_fw_config) { + DC_LOG_DSC("ERROR: DSC %d at opp pipe %d already disabled!", dsc->inst, enabled_opp_pipe); + ASSERT(0); + } + + REG_UPDATE(DSCRM_DSC_FORWARD_CONFIG, + DSCRM_DSC_FORWARD_EN, 0); + + REG_UPDATE(DSC_TOP_CONTROL, + DSC_CLOCK_EN, 0); +} + +static void dsc2_disconnect(struct display_stream_compressor *dsc) +{ + struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc); + + DC_LOG_DSC("disconnect DSC %d", dsc->inst); + + REG_UPDATE(DSCRM_DSC_FORWARD_CONFIG, + DSCRM_DSC_FORWARD_EN, 0); +} + +/* This module's internal functions */ +void dsc_log_pps(struct display_stream_compressor *dsc, struct drm_dsc_config *pps) +{ + int i; + int bits_per_pixel = pps->bits_per_pixel; + + DC_LOG_DSC("\tdsc_version_major %d", pps->dsc_version_major); + DC_LOG_DSC("\tdsc_version_minor %d", pps->dsc_version_minor); + DC_LOG_DSC("\tbits_per_component %d", pps->bits_per_component); + DC_LOG_DSC("\tline_buf_depth %d", pps->line_buf_depth); + DC_LOG_DSC("\tblock_pred_enable %d", pps->block_pred_enable); + DC_LOG_DSC("\tconvert_rgb %d", pps->convert_rgb); + DC_LOG_DSC("\tsimple_422 %d", pps->simple_422); + DC_LOG_DSC("\tvbr_enable %d", pps->vbr_enable); + DC_LOG_DSC("\tbits_per_pixel %d (%d.%04d)", bits_per_pixel, bits_per_pixel / 16, ((bits_per_pixel % 16) * 10000) / 16); + DC_LOG_DSC("\tpic_height %d", pps->pic_height); + DC_LOG_DSC("\tpic_width %d", pps->pic_width); + DC_LOG_DSC("\tslice_height %d", pps->slice_height); + DC_LOG_DSC("\tslice_width %d", pps->slice_width); + DC_LOG_DSC("\tslice_chunk_size %d", pps->slice_chunk_size); + DC_LOG_DSC("\tinitial_xmit_delay %d", pps->initial_xmit_delay); + DC_LOG_DSC("\tinitial_dec_delay %d", pps->initial_dec_delay); + DC_LOG_DSC("\tinitial_scale_value %d", pps->initial_scale_value); + DC_LOG_DSC("\tscale_increment_interval %d", pps->scale_increment_interval); + DC_LOG_DSC("\tscale_decrement_interval %d", pps->scale_decrement_interval); + DC_LOG_DSC("\tfirst_line_bpg_offset %d", pps->first_line_bpg_offset); + DC_LOG_DSC("\tnfl_bpg_offset %d", pps->nfl_bpg_offset); + DC_LOG_DSC("\tslice_bpg_offset %d", pps->slice_bpg_offset); + DC_LOG_DSC("\tinitial_offset %d", pps->initial_offset); + DC_LOG_DSC("\tfinal_offset %d", pps->final_offset); + DC_LOG_DSC("\tflatness_min_qp %d", pps->flatness_min_qp); + DC_LOG_DSC("\tflatness_max_qp %d", pps->flatness_max_qp); + /* DC_LOG_DSC("\trc_parameter_set %d", pps->rc_parameter_set); */ + DC_LOG_DSC("\tnative_420 %d", pps->native_420); + DC_LOG_DSC("\tnative_422 %d", pps->native_422); + DC_LOG_DSC("\tsecond_line_bpg_offset %d", pps->second_line_bpg_offset); + DC_LOG_DSC("\tnsl_bpg_offset %d", pps->nsl_bpg_offset); + DC_LOG_DSC("\tsecond_line_offset_adj %d", pps->second_line_offset_adj); + DC_LOG_DSC("\trc_model_size %d", pps->rc_model_size); + DC_LOG_DSC("\trc_edge_factor %d", pps->rc_edge_factor); + DC_LOG_DSC("\trc_quant_incr_limit0 %d", pps->rc_quant_incr_limit0); + DC_LOG_DSC("\trc_quant_incr_limit1 %d", pps->rc_quant_incr_limit1); + DC_LOG_DSC("\trc_tgt_offset_high %d", pps->rc_tgt_offset_high); + DC_LOG_DSC("\trc_tgt_offset_low %d", pps->rc_tgt_offset_low); + + for (i = 0; i < NUM_BUF_RANGES - 1; i++) + DC_LOG_DSC("\trc_buf_thresh[%d] %d", i, pps->rc_buf_thresh[i]); + + for (i = 0; i < NUM_BUF_RANGES; i++) { + DC_LOG_DSC("\trc_range_parameters[%d].range_min_qp %d", i, pps->rc_range_params[i].range_min_qp); + DC_LOG_DSC("\trc_range_parameters[%d].range_max_qp %d", i, pps->rc_range_params[i].range_max_qp); + DC_LOG_DSC("\trc_range_parameters[%d].range_bpg_offset %d", i, pps->rc_range_params[i].range_bpg_offset); + } +} + +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; +} + +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); + ASSERT(dsc_cfg->dc_dsc_cfg.num_slices_v); + ASSERT(dsc_cfg->dc_dsc_cfg.version_minor == 1 || dsc_cfg->dc_dsc_cfg.version_minor == 2); + ASSERT(dsc_cfg->pic_width); + ASSERT(dsc_cfg->pic_height); + ASSERT((dsc_cfg->dc_dsc_cfg.version_minor == 1 && + (8 <= dsc_cfg->dc_dsc_cfg.linebuf_depth && dsc_cfg->dc_dsc_cfg.linebuf_depth <= 13)) || + (dsc_cfg->dc_dsc_cfg.version_minor == 2 && + ((8 <= dsc_cfg->dc_dsc_cfg.linebuf_depth && dsc_cfg->dc_dsc_cfg.linebuf_depth <= 15) || + dsc_cfg->dc_dsc_cfg.linebuf_depth == 0))); + ASSERT(96 <= dsc_cfg->dc_dsc_cfg.bits_per_pixel && dsc_cfg->dc_dsc_cfg.bits_per_pixel <= 0x3ff); // 6.0 <= bits_per_pixel <= 63.9375 + + if (!dsc_cfg->dc_dsc_cfg.num_slices_v || !dsc_cfg->dc_dsc_cfg.num_slices_h || + !(dsc_cfg->dc_dsc_cfg.version_minor == 1 || dsc_cfg->dc_dsc_cfg.version_minor == 2) || + !dsc_cfg->pic_width || !dsc_cfg->pic_height || + !((dsc_cfg->dc_dsc_cfg.version_minor == 1 && // v1.1 line buffer depth range: + 8 <= dsc_cfg->dc_dsc_cfg.linebuf_depth && dsc_cfg->dc_dsc_cfg.linebuf_depth <= 13) || + (dsc_cfg->dc_dsc_cfg.version_minor == 2 && // v1.2 line buffer depth range: + ((8 <= dsc_cfg->dc_dsc_cfg.linebuf_depth && dsc_cfg->dc_dsc_cfg.linebuf_depth <= 15) || + dsc_cfg->dc_dsc_cfg.linebuf_depth == 0))) || + !(96 <= dsc_cfg->dc_dsc_cfg.bits_per_pixel && dsc_cfg->dc_dsc_cfg.bits_per_pixel <= 0x3ff)) { + dm_output_to_console("%s: Invalid parameters\n", __func__); + return false; + } + + dsc_init_reg_values(dsc_reg_vals); + + /* Copy input config */ + dsc_reg_vals->pixel_format = dsc_dc_pixel_encoding_to_dsc_pixel_format(dsc_cfg->pixel_encoding, dsc_cfg->dc_dsc_cfg.ycbcr422_simple); + dsc_reg_vals->num_slices_h = dsc_cfg->dc_dsc_cfg.num_slices_h; + dsc_reg_vals->num_slices_v = dsc_cfg->dc_dsc_cfg.num_slices_v; + dsc_reg_vals->pps.dsc_version_minor = dsc_cfg->dc_dsc_cfg.version_minor; + dsc_reg_vals->pps.pic_width = dsc_cfg->pic_width; + dsc_reg_vals->pps.pic_height = dsc_cfg->pic_height; + dsc_reg_vals->pps.bits_per_component = dsc_dc_color_depth_to_dsc_bits_per_comp(dsc_cfg->color_depth); + dsc_reg_vals->pps.block_pred_enable = dsc_cfg->dc_dsc_cfg.block_pred_enable; + dsc_reg_vals->pps.line_buf_depth = dsc_cfg->dc_dsc_cfg.linebuf_depth; + dsc_reg_vals->alternate_ich_encoding_en = dsc_reg_vals->pps.dsc_version_minor == 1 ? 0 : 1; + dsc_reg_vals->ich_reset_at_eol = (dsc_cfg->is_odm || dsc_reg_vals->num_slices_h > 1) ? 0xF : 0; + + // TODO: in addition to validating slice height (pic height must be divisible by slice height), + // see what happens when the same condition doesn't apply for slice_width/pic_width. + dsc_reg_vals->pps.slice_width = dsc_cfg->pic_width / dsc_cfg->dc_dsc_cfg.num_slices_h; + dsc_reg_vals->pps.slice_height = dsc_cfg->pic_height / dsc_cfg->dc_dsc_cfg.num_slices_v; + + ASSERT(dsc_reg_vals->pps.slice_height * dsc_cfg->dc_dsc_cfg.num_slices_v == dsc_cfg->pic_height); + if (!(dsc_reg_vals->pps.slice_height * dsc_cfg->dc_dsc_cfg.num_slices_v == dsc_cfg->pic_height)) { + dm_output_to_console("%s: pix height %d not divisible by num_slices_v %d\n\n", __func__, dsc_cfg->pic_height, dsc_cfg->dc_dsc_cfg.num_slices_v); + return false; + } + + dsc_reg_vals->bpp_x32 = dsc_cfg->dc_dsc_cfg.bits_per_pixel << 1; + if (dsc_reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR420 || dsc_reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR422) + dsc_reg_vals->pps.bits_per_pixel = dsc_reg_vals->bpp_x32; + else + dsc_reg_vals->pps.bits_per_pixel = dsc_reg_vals->bpp_x32 >> 1; + + dsc_reg_vals->pps.convert_rgb = dsc_reg_vals->pixel_format == DSC_PIXFMT_RGB ? 1 : 0; + dsc_reg_vals->pps.native_422 = (dsc_reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR422); + 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); + + 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; + } + + dsc_update_from_dsc_parameters(dsc_reg_vals, &dsc_params); + + dsc_optc_cfg->bytes_per_pixel = dsc_params.bytes_per_pixel; + dsc_optc_cfg->slice_width = dsc_reg_vals->pps.slice_width; + dsc_optc_cfg->is_pixel_format_444 = dsc_reg_vals->pixel_format == DSC_PIXFMT_RGB || + dsc_reg_vals->pixel_format == DSC_PIXFMT_YCBCR444 || + dsc_reg_vals->pixel_format == DSC_PIXFMT_SIMPLE_YCBCR422; + + return true; +} + + +enum dsc_pixel_format dsc_dc_pixel_encoding_to_dsc_pixel_format(enum dc_pixel_encoding dc_pix_enc, bool is_ycbcr422_simple) +{ + enum dsc_pixel_format dsc_pix_fmt = DSC_PIXFMT_UNKNOWN; + + /* NOTE: We don't support DSC_PIXFMT_SIMPLE_YCBCR422 */ + + switch (dc_pix_enc) { + case PIXEL_ENCODING_RGB: + dsc_pix_fmt = DSC_PIXFMT_RGB; + break; + case PIXEL_ENCODING_YCBCR422: + if (is_ycbcr422_simple) + dsc_pix_fmt = DSC_PIXFMT_SIMPLE_YCBCR422; + else + dsc_pix_fmt = DSC_PIXFMT_NATIVE_YCBCR422; + break; + case PIXEL_ENCODING_YCBCR444: + dsc_pix_fmt = DSC_PIXFMT_YCBCR444; + break; + case PIXEL_ENCODING_YCBCR420: + dsc_pix_fmt = DSC_PIXFMT_NATIVE_YCBCR420; + break; + default: + dsc_pix_fmt = DSC_PIXFMT_UNKNOWN; + break; + } + + ASSERT(dsc_pix_fmt != DSC_PIXFMT_UNKNOWN); + return dsc_pix_fmt; +} + + +enum dsc_bits_per_comp dsc_dc_color_depth_to_dsc_bits_per_comp(enum dc_color_depth dc_color_depth) +{ + enum dsc_bits_per_comp bpc = DSC_BPC_UNKNOWN; + + switch (dc_color_depth) { + case COLOR_DEPTH_888: + bpc = DSC_BPC_8; + break; + case COLOR_DEPTH_101010: + bpc = DSC_BPC_10; + break; + case COLOR_DEPTH_121212: + bpc = DSC_BPC_12; + break; + default: + bpc = DSC_BPC_UNKNOWN; + break; + } + + return bpc; +} + + +void dsc_init_reg_values(struct dsc_reg_values *reg_vals) +{ + int i; + + memset(reg_vals, 0, sizeof(struct dsc_reg_values)); + + /* Non-PPS values */ + reg_vals->dsc_clock_enable = 1; + reg_vals->dsc_clock_gating_disable = 0; + reg_vals->underflow_recovery_en = 0; + reg_vals->underflow_occurred_int_en = 0; + reg_vals->underflow_occurred_status = 0; + reg_vals->ich_reset_at_eol = 0; + reg_vals->alternate_ich_encoding_en = 0; + reg_vals->rc_buffer_model_size = 0; + /*reg_vals->disable_ich = 0;*/ + reg_vals->dsc_dbg_en = 0; + + for (i = 0; i < 4; i++) + reg_vals->rc_buffer_model_overflow_int_en[i] = 0; + + /* PPS values */ + reg_vals->pps.dsc_version_minor = 2; + reg_vals->pps.dsc_version_major = 1; + reg_vals->pps.line_buf_depth = 9; + reg_vals->pps.bits_per_component = 8; + reg_vals->pps.block_pred_enable = 1; + reg_vals->pps.slice_chunk_size = 0; + reg_vals->pps.pic_width = 0; + reg_vals->pps.pic_height = 0; + reg_vals->pps.slice_width = 0; + reg_vals->pps.slice_height = 0; + reg_vals->pps.initial_xmit_delay = 170; + reg_vals->pps.initial_dec_delay = 0; + reg_vals->pps.initial_scale_value = 0; + reg_vals->pps.scale_increment_interval = 0; + reg_vals->pps.scale_decrement_interval = 0; + reg_vals->pps.nfl_bpg_offset = 0; + reg_vals->pps.slice_bpg_offset = 0; + reg_vals->pps.nsl_bpg_offset = 0; + reg_vals->pps.initial_offset = 6144; + reg_vals->pps.final_offset = 0; + reg_vals->pps.flatness_min_qp = 3; + reg_vals->pps.flatness_max_qp = 12; + reg_vals->pps.rc_model_size = 8192; + reg_vals->pps.rc_edge_factor = 6; + reg_vals->pps.rc_quant_incr_limit0 = 11; + reg_vals->pps.rc_quant_incr_limit1 = 11; + reg_vals->pps.rc_tgt_offset_low = 3; + reg_vals->pps.rc_tgt_offset_high = 3; +} + +/* Updates dsc_reg_values::reg_vals::xxx fields based on the values from computed params. + * This is required because dscc_compute_dsc_parameters returns a modified PPS, which in turn + * affects non-PPS register values. + */ +void dsc_update_from_dsc_parameters(struct dsc_reg_values *reg_vals, const struct dsc_parameters *dsc_params) +{ + int i; + + reg_vals->pps = dsc_params->pps; + + // pps_computed will have the "expanded" values; need to shift them to make them fit for regs. + for (i = 0; i < NUM_BUF_RANGES - 1; i++) + reg_vals->pps.rc_buf_thresh[i] = reg_vals->pps.rc_buf_thresh[i] >> 6; + + reg_vals->rc_buffer_model_size = dsc_params->rc_buffer_model_size; +} + +static void dsc_write_to_registers(struct display_stream_compressor *dsc, const struct dsc_reg_values *reg_vals) +{ + uint32_t temp_int; + struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc); + + REG_SET(DSC_DEBUG_CONTROL, 0, + DSC_DBG_EN, reg_vals->dsc_dbg_en); + + // dsccif registers + REG_SET_5(DSCCIF_CONFIG0, 0, + INPUT_INTERFACE_UNDERFLOW_RECOVERY_EN, reg_vals->underflow_recovery_en, + INPUT_INTERFACE_UNDERFLOW_OCCURRED_INT_EN, reg_vals->underflow_occurred_int_en, + INPUT_INTERFACE_UNDERFLOW_OCCURRED_STATUS, reg_vals->underflow_occurred_status, + INPUT_PIXEL_FORMAT, reg_vals->pixel_format, + DSCCIF_CONFIG0__BITS_PER_COMPONENT, reg_vals->pps.bits_per_component); + + REG_SET_2(DSCCIF_CONFIG1, 0, + PIC_WIDTH, reg_vals->pps.pic_width, + PIC_HEIGHT, reg_vals->pps.pic_height); + + // dscc registers + if (dsc20->dsc_mask->ICH_RESET_AT_END_OF_LINE == 0) { + REG_SET_3(DSCC_CONFIG0, 0, + NUMBER_OF_SLICES_PER_LINE, reg_vals->num_slices_h - 1, + ALTERNATE_ICH_ENCODING_EN, reg_vals->alternate_ich_encoding_en, + NUMBER_OF_SLICES_IN_VERTICAL_DIRECTION, reg_vals->num_slices_v - 1); + } else { + REG_SET_4(DSCC_CONFIG0, 0, ICH_RESET_AT_END_OF_LINE, + reg_vals->ich_reset_at_eol, NUMBER_OF_SLICES_PER_LINE, + reg_vals->num_slices_h - 1, ALTERNATE_ICH_ENCODING_EN, + reg_vals->alternate_ich_encoding_en, NUMBER_OF_SLICES_IN_VERTICAL_DIRECTION, + reg_vals->num_slices_v - 1); + } + + REG_SET(DSCC_CONFIG1, 0, + DSCC_RATE_CONTROL_BUFFER_MODEL_SIZE, reg_vals->rc_buffer_model_size); + /*REG_SET_2(DSCC_CONFIG1, 0, + DSCC_RATE_CONTROL_BUFFER_MODEL_SIZE, reg_vals->rc_buffer_model_size, + DSCC_DISABLE_ICH, reg_vals->disable_ich);*/ + + REG_SET_4(DSCC_INTERRUPT_CONTROL_STATUS, 0, + DSCC_RATE_CONTROL_BUFFER_MODEL0_OVERFLOW_OCCURRED_INT_EN, reg_vals->rc_buffer_model_overflow_int_en[0], + DSCC_RATE_CONTROL_BUFFER_MODEL1_OVERFLOW_OCCURRED_INT_EN, reg_vals->rc_buffer_model_overflow_int_en[1], + DSCC_RATE_CONTROL_BUFFER_MODEL2_OVERFLOW_OCCURRED_INT_EN, reg_vals->rc_buffer_model_overflow_int_en[2], + DSCC_RATE_CONTROL_BUFFER_MODEL3_OVERFLOW_OCCURRED_INT_EN, reg_vals->rc_buffer_model_overflow_int_en[3]); + + REG_SET_3(DSCC_PPS_CONFIG0, 0, + DSC_VERSION_MINOR, reg_vals->pps.dsc_version_minor, + LINEBUF_DEPTH, reg_vals->pps.line_buf_depth, + DSCC_PPS_CONFIG0__BITS_PER_COMPONENT, reg_vals->pps.bits_per_component); + + if (reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR420 || reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR422) + temp_int = reg_vals->bpp_x32; + else + temp_int = reg_vals->bpp_x32 >> 1; + + REG_SET_7(DSCC_PPS_CONFIG1, 0, + BITS_PER_PIXEL, temp_int, + SIMPLE_422, reg_vals->pixel_format == DSC_PIXFMT_SIMPLE_YCBCR422, + CONVERT_RGB, reg_vals->pixel_format == DSC_PIXFMT_RGB, + BLOCK_PRED_ENABLE, reg_vals->pps.block_pred_enable, + NATIVE_422, reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR422, + NATIVE_420, reg_vals->pixel_format == DSC_PIXFMT_NATIVE_YCBCR420, + CHUNK_SIZE, reg_vals->pps.slice_chunk_size); + + REG_SET_2(DSCC_PPS_CONFIG2, 0, + PIC_WIDTH, reg_vals->pps.pic_width, + PIC_HEIGHT, reg_vals->pps.pic_height); + + REG_SET_2(DSCC_PPS_CONFIG3, 0, + SLICE_WIDTH, reg_vals->pps.slice_width, + SLICE_HEIGHT, reg_vals->pps.slice_height); + + REG_SET(DSCC_PPS_CONFIG4, 0, + INITIAL_XMIT_DELAY, reg_vals->pps.initial_xmit_delay); + + REG_SET_2(DSCC_PPS_CONFIG5, 0, + INITIAL_SCALE_VALUE, reg_vals->pps.initial_scale_value, + SCALE_INCREMENT_INTERVAL, reg_vals->pps.scale_increment_interval); + + REG_SET_3(DSCC_PPS_CONFIG6, 0, + SCALE_DECREMENT_INTERVAL, reg_vals->pps.scale_decrement_interval, + FIRST_LINE_BPG_OFFSET, reg_vals->pps.first_line_bpg_offset, + SECOND_LINE_BPG_OFFSET, reg_vals->pps.second_line_bpg_offset); + + REG_SET_2(DSCC_PPS_CONFIG7, 0, + NFL_BPG_OFFSET, reg_vals->pps.nfl_bpg_offset, + SLICE_BPG_OFFSET, reg_vals->pps.slice_bpg_offset); + + REG_SET_2(DSCC_PPS_CONFIG8, 0, + NSL_BPG_OFFSET, reg_vals->pps.nsl_bpg_offset, + SECOND_LINE_OFFSET_ADJ, reg_vals->pps.second_line_offset_adj); + + REG_SET_2(DSCC_PPS_CONFIG9, 0, + INITIAL_OFFSET, reg_vals->pps.initial_offset, + FINAL_OFFSET, reg_vals->pps.final_offset); + + REG_SET_3(DSCC_PPS_CONFIG10, 0, + FLATNESS_MIN_QP, reg_vals->pps.flatness_min_qp, + FLATNESS_MAX_QP, reg_vals->pps.flatness_max_qp, + RC_MODEL_SIZE, reg_vals->pps.rc_model_size); + + REG_SET_5(DSCC_PPS_CONFIG11, 0, + RC_EDGE_FACTOR, reg_vals->pps.rc_edge_factor, + RC_QUANT_INCR_LIMIT0, reg_vals->pps.rc_quant_incr_limit0, + RC_QUANT_INCR_LIMIT1, reg_vals->pps.rc_quant_incr_limit1, + RC_TGT_OFFSET_LO, reg_vals->pps.rc_tgt_offset_low, + RC_TGT_OFFSET_HI, reg_vals->pps.rc_tgt_offset_high); + + REG_SET_4(DSCC_PPS_CONFIG12, 0, + RC_BUF_THRESH0, reg_vals->pps.rc_buf_thresh[0], + RC_BUF_THRESH1, reg_vals->pps.rc_buf_thresh[1], + RC_BUF_THRESH2, reg_vals->pps.rc_buf_thresh[2], + RC_BUF_THRESH3, reg_vals->pps.rc_buf_thresh[3]); + + REG_SET_4(DSCC_PPS_CONFIG13, 0, + RC_BUF_THRESH4, reg_vals->pps.rc_buf_thresh[4], + RC_BUF_THRESH5, reg_vals->pps.rc_buf_thresh[5], + RC_BUF_THRESH6, reg_vals->pps.rc_buf_thresh[6], + RC_BUF_THRESH7, reg_vals->pps.rc_buf_thresh[7]); + + REG_SET_4(DSCC_PPS_CONFIG14, 0, + RC_BUF_THRESH8, reg_vals->pps.rc_buf_thresh[8], + RC_BUF_THRESH9, reg_vals->pps.rc_buf_thresh[9], + RC_BUF_THRESH10, reg_vals->pps.rc_buf_thresh[10], + RC_BUF_THRESH11, reg_vals->pps.rc_buf_thresh[11]); + + REG_SET_5(DSCC_PPS_CONFIG15, 0, + RC_BUF_THRESH12, reg_vals->pps.rc_buf_thresh[12], + RC_BUF_THRESH13, reg_vals->pps.rc_buf_thresh[13], + RANGE_MIN_QP0, reg_vals->pps.rc_range_params[0].range_min_qp, + RANGE_MAX_QP0, reg_vals->pps.rc_range_params[0].range_max_qp, + RANGE_BPG_OFFSET0, reg_vals->pps.rc_range_params[0].range_bpg_offset); + + REG_SET_6(DSCC_PPS_CONFIG16, 0, + RANGE_MIN_QP1, reg_vals->pps.rc_range_params[1].range_min_qp, + RANGE_MAX_QP1, reg_vals->pps.rc_range_params[1].range_max_qp, + RANGE_BPG_OFFSET1, reg_vals->pps.rc_range_params[1].range_bpg_offset, + RANGE_MIN_QP2, reg_vals->pps.rc_range_params[2].range_min_qp, + RANGE_MAX_QP2, reg_vals->pps.rc_range_params[2].range_max_qp, + RANGE_BPG_OFFSET2, reg_vals->pps.rc_range_params[2].range_bpg_offset); + + REG_SET_6(DSCC_PPS_CONFIG17, 0, + RANGE_MIN_QP3, reg_vals->pps.rc_range_params[3].range_min_qp, + RANGE_MAX_QP3, reg_vals->pps.rc_range_params[3].range_max_qp, + RANGE_BPG_OFFSET3, reg_vals->pps.rc_range_params[3].range_bpg_offset, + RANGE_MIN_QP4, reg_vals->pps.rc_range_params[4].range_min_qp, + RANGE_MAX_QP4, reg_vals->pps.rc_range_params[4].range_max_qp, + RANGE_BPG_OFFSET4, reg_vals->pps.rc_range_params[4].range_bpg_offset); + + REG_SET_6(DSCC_PPS_CONFIG18, 0, + RANGE_MIN_QP5, reg_vals->pps.rc_range_params[5].range_min_qp, + RANGE_MAX_QP5, reg_vals->pps.rc_range_params[5].range_max_qp, + RANGE_BPG_OFFSET5, reg_vals->pps.rc_range_params[5].range_bpg_offset, + RANGE_MIN_QP6, reg_vals->pps.rc_range_params[6].range_min_qp, + RANGE_MAX_QP6, reg_vals->pps.rc_range_params[6].range_max_qp, + RANGE_BPG_OFFSET6, reg_vals->pps.rc_range_params[6].range_bpg_offset); + + REG_SET_6(DSCC_PPS_CONFIG19, 0, + RANGE_MIN_QP7, reg_vals->pps.rc_range_params[7].range_min_qp, + RANGE_MAX_QP7, reg_vals->pps.rc_range_params[7].range_max_qp, + RANGE_BPG_OFFSET7, reg_vals->pps.rc_range_params[7].range_bpg_offset, + RANGE_MIN_QP8, reg_vals->pps.rc_range_params[8].range_min_qp, + RANGE_MAX_QP8, reg_vals->pps.rc_range_params[8].range_max_qp, + RANGE_BPG_OFFSET8, reg_vals->pps.rc_range_params[8].range_bpg_offset); + + REG_SET_6(DSCC_PPS_CONFIG20, 0, + RANGE_MIN_QP9, reg_vals->pps.rc_range_params[9].range_min_qp, + RANGE_MAX_QP9, reg_vals->pps.rc_range_params[9].range_max_qp, + RANGE_BPG_OFFSET9, reg_vals->pps.rc_range_params[9].range_bpg_offset, + RANGE_MIN_QP10, reg_vals->pps.rc_range_params[10].range_min_qp, + RANGE_MAX_QP10, reg_vals->pps.rc_range_params[10].range_max_qp, + RANGE_BPG_OFFSET10, reg_vals->pps.rc_range_params[10].range_bpg_offset); + + REG_SET_6(DSCC_PPS_CONFIG21, 0, + RANGE_MIN_QP11, reg_vals->pps.rc_range_params[11].range_min_qp, + RANGE_MAX_QP11, reg_vals->pps.rc_range_params[11].range_max_qp, + RANGE_BPG_OFFSET11, reg_vals->pps.rc_range_params[11].range_bpg_offset, + RANGE_MIN_QP12, reg_vals->pps.rc_range_params[12].range_min_qp, + RANGE_MAX_QP12, reg_vals->pps.rc_range_params[12].range_max_qp, + RANGE_BPG_OFFSET12, reg_vals->pps.rc_range_params[12].range_bpg_offset); + + REG_SET_6(DSCC_PPS_CONFIG22, 0, + RANGE_MIN_QP13, reg_vals->pps.rc_range_params[13].range_min_qp, + RANGE_MAX_QP13, reg_vals->pps.rc_range_params[13].range_max_qp, + RANGE_BPG_OFFSET13, reg_vals->pps.rc_range_params[13].range_bpg_offset, + RANGE_MIN_QP14, reg_vals->pps.rc_range_params[14].range_min_qp, + RANGE_MAX_QP14, reg_vals->pps.rc_range_params[14].range_max_qp, + RANGE_BPG_OFFSET14, reg_vals->pps.rc_range_params[14].range_bpg_offset); + +} + diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dcn20/dcn20_dsc.h b/drivers/gpu/drm/amd/display/dc/dsc/dcn20/dcn20_dsc.h new file mode 100644 index 00000000000000..ba869387c3c583 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dsc/dcn20/dcn20_dsc.h @@ -0,0 +1,589 @@ +/* Copyright 2017 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 __DCN20_DSC_H__ +#define __DCN20_DSC_H__ + +#include "dsc.h" +#include "dsc/dscc_types.h" +#include + +#define TO_DCN20_DSC(dsc)\ + container_of(dsc, struct dcn20_dsc, base) + +#define DSC_REG_LIST_DCN20(id) \ + SRI(DSC_TOP_CONTROL, DSC_TOP, id),\ + SRI(DSC_DEBUG_CONTROL, DSC_TOP, id),\ + SRI(DSCC_CONFIG0, DSCC, id),\ + SRI(DSCC_CONFIG1, DSCC, id),\ + SRI(DSCC_STATUS, DSCC, id),\ + SRI(DSCC_INTERRUPT_CONTROL_STATUS, DSCC, id),\ + SRI(DSCC_PPS_CONFIG0, DSCC, id),\ + SRI(DSCC_PPS_CONFIG1, DSCC, id),\ + SRI(DSCC_PPS_CONFIG2, DSCC, id),\ + SRI(DSCC_PPS_CONFIG3, DSCC, id),\ + SRI(DSCC_PPS_CONFIG4, DSCC, id),\ + SRI(DSCC_PPS_CONFIG5, DSCC, id),\ + SRI(DSCC_PPS_CONFIG6, DSCC, id),\ + SRI(DSCC_PPS_CONFIG7, DSCC, id),\ + SRI(DSCC_PPS_CONFIG8, DSCC, id),\ + SRI(DSCC_PPS_CONFIG9, DSCC, id),\ + SRI(DSCC_PPS_CONFIG10, DSCC, id),\ + SRI(DSCC_PPS_CONFIG11, DSCC, id),\ + SRI(DSCC_PPS_CONFIG12, DSCC, id),\ + SRI(DSCC_PPS_CONFIG13, DSCC, id),\ + SRI(DSCC_PPS_CONFIG14, DSCC, id),\ + SRI(DSCC_PPS_CONFIG15, DSCC, id),\ + SRI(DSCC_PPS_CONFIG16, DSCC, id),\ + SRI(DSCC_PPS_CONFIG17, DSCC, id),\ + SRI(DSCC_PPS_CONFIG18, DSCC, id),\ + SRI(DSCC_PPS_CONFIG19, DSCC, id),\ + SRI(DSCC_PPS_CONFIG20, DSCC, id),\ + SRI(DSCC_PPS_CONFIG21, DSCC, id),\ + SRI(DSCC_PPS_CONFIG22, DSCC, id),\ + SRI(DSCC_MEM_POWER_CONTROL, DSCC, id),\ + SRI(DSCC_R_Y_SQUARED_ERROR_LOWER, DSCC, id),\ + SRI(DSCC_R_Y_SQUARED_ERROR_UPPER, DSCC, id),\ + SRI(DSCC_G_CB_SQUARED_ERROR_LOWER, DSCC, id),\ + SRI(DSCC_G_CB_SQUARED_ERROR_UPPER, DSCC, id),\ + SRI(DSCC_B_CR_SQUARED_ERROR_LOWER, DSCC, id),\ + SRI(DSCC_B_CR_SQUARED_ERROR_UPPER, DSCC, id),\ + SRI(DSCC_MAX_ABS_ERROR0, DSCC, id),\ + SRI(DSCC_MAX_ABS_ERROR1, DSCC, id),\ + SRI(DSCC_RATE_BUFFER0_MAX_FULLNESS_LEVEL, DSCC, id),\ + SRI(DSCC_RATE_BUFFER1_MAX_FULLNESS_LEVEL, DSCC, id),\ + SRI(DSCC_RATE_BUFFER2_MAX_FULLNESS_LEVEL, DSCC, id),\ + SRI(DSCC_RATE_BUFFER3_MAX_FULLNESS_LEVEL, DSCC, id),\ + SRI(DSCC_RATE_CONTROL_BUFFER0_MAX_FULLNESS_LEVEL, DSCC, id),\ + SRI(DSCC_RATE_CONTROL_BUFFER1_MAX_FULLNESS_LEVEL, DSCC, id),\ + SRI(DSCC_RATE_CONTROL_BUFFER2_MAX_FULLNESS_LEVEL, DSCC, id),\ + SRI(DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL, DSCC, id),\ + SRI(DSCCIF_CONFIG0, DSCCIF, id),\ + SRI(DSCCIF_CONFIG1, DSCCIF, id),\ + SRI(DSCRM_DSC_FORWARD_CONFIG, DSCRM, id) + + +#define DSC_SF(reg_name, field_name, post_fix)\ + .field_name = reg_name ## __ ## field_name ## post_fix + +//Used in resolving the corner case with duplicate field name +#define DSC2_SF(reg_name, field_name, post_fix)\ + .field_name = reg_name ## _ ## field_name ## post_fix + +#define DSC_REG_LIST_SH_MASK_DCN20(mask_sh)\ + DSC_SF(DSC_TOP0_DSC_TOP_CONTROL, DSC_CLOCK_EN, mask_sh), \ + DSC_SF(DSC_TOP0_DSC_TOP_CONTROL, DSC_DISPCLK_R_GATE_DIS, mask_sh), \ + DSC_SF(DSC_TOP0_DSC_TOP_CONTROL, DSC_DSCCLK_R_GATE_DIS, mask_sh), \ + DSC_SF(DSC_TOP0_DSC_DEBUG_CONTROL, DSC_DBG_EN, mask_sh), \ + DSC_SF(DSCC0_DSCC_CONFIG0, ICH_RESET_AT_END_OF_LINE, mask_sh), \ + DSC_SF(DSCC0_DSCC_CONFIG0, NUMBER_OF_SLICES_PER_LINE, mask_sh), \ + DSC_SF(DSCC0_DSCC_CONFIG0, ALTERNATE_ICH_ENCODING_EN, mask_sh), \ + DSC_SF(DSCC0_DSCC_CONFIG0, NUMBER_OF_SLICES_IN_VERTICAL_DIRECTION, mask_sh), \ + DSC_SF(DSCC0_DSCC_CONFIG1, DSCC_RATE_CONTROL_BUFFER_MODEL_SIZE, mask_sh), \ + /*DSC_SF(DSCC0_DSCC_CONFIG1, DSCC_DISABLE_ICH, mask_sh),*/ \ + DSC_SF(DSCC0_DSCC_STATUS, DSCC_DOUBLE_BUFFER_REG_UPDATE_PENDING, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER0_OVERFLOW_OCCURRED, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER1_OVERFLOW_OCCURRED, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER2_OVERFLOW_OCCURRED, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER3_OVERFLOW_OCCURRED, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER0_UNDERFLOW_OCCURRED, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER1_UNDERFLOW_OCCURRED, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER2_UNDERFLOW_OCCURRED, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER3_UNDERFLOW_OCCURRED, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL0_OVERFLOW_OCCURRED, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL1_OVERFLOW_OCCURRED, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL2_OVERFLOW_OCCURRED, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL3_OVERFLOW_OCCURRED, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER0_OVERFLOW_OCCURRED_INT_EN, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER1_OVERFLOW_OCCURRED_INT_EN, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER2_OVERFLOW_OCCURRED_INT_EN, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER3_OVERFLOW_OCCURRED_INT_EN, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER0_UNDERFLOW_OCCURRED_INT_EN, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER1_UNDERFLOW_OCCURRED_INT_EN, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER2_UNDERFLOW_OCCURRED_INT_EN, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_BUFFER3_UNDERFLOW_OCCURRED_INT_EN, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL0_OVERFLOW_OCCURRED_INT_EN, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL1_OVERFLOW_OCCURRED_INT_EN, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL2_OVERFLOW_OCCURRED_INT_EN, mask_sh), \ + DSC_SF(DSCC0_DSCC_INTERRUPT_CONTROL_STATUS, DSCC_RATE_CONTROL_BUFFER_MODEL3_OVERFLOW_OCCURRED_INT_EN, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG0, DSC_VERSION_MINOR, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG0, DSC_VERSION_MAJOR, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG0, PPS_IDENTIFIER, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG0, LINEBUF_DEPTH, mask_sh), \ + DSC2_SF(DSCC0, DSCC_PPS_CONFIG0__BITS_PER_COMPONENT, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG1, BITS_PER_PIXEL, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG1, VBR_ENABLE, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG1, SIMPLE_422, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG1, CONVERT_RGB, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG1, BLOCK_PRED_ENABLE, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG1, NATIVE_422, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG1, NATIVE_420, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG1, CHUNK_SIZE, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG2, PIC_WIDTH, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG2, PIC_HEIGHT, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG3, SLICE_WIDTH, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG3, SLICE_HEIGHT, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG4, INITIAL_XMIT_DELAY, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG4, INITIAL_DEC_DELAY, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG5, INITIAL_SCALE_VALUE, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG5, SCALE_INCREMENT_INTERVAL, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG6, SCALE_DECREMENT_INTERVAL, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG6, FIRST_LINE_BPG_OFFSET, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG6, SECOND_LINE_BPG_OFFSET, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG7, NFL_BPG_OFFSET, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG7, SLICE_BPG_OFFSET, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG8, NSL_BPG_OFFSET, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG8, SECOND_LINE_OFFSET_ADJ, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG9, INITIAL_OFFSET, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG9, FINAL_OFFSET, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG10, FLATNESS_MIN_QP, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG10, FLATNESS_MAX_QP, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG10, RC_MODEL_SIZE, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG11, RC_EDGE_FACTOR, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG11, RC_QUANT_INCR_LIMIT0, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG11, RC_QUANT_INCR_LIMIT1, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG11, RC_TGT_OFFSET_LO, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG11, RC_TGT_OFFSET_HI, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG12, RC_BUF_THRESH0, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG12, RC_BUF_THRESH1, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG12, RC_BUF_THRESH2, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG12, RC_BUF_THRESH3, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG13, RC_BUF_THRESH4, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG13, RC_BUF_THRESH5, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG13, RC_BUF_THRESH6, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG13, RC_BUF_THRESH7, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG14, RC_BUF_THRESH8, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG14, RC_BUF_THRESH9, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG14, RC_BUF_THRESH10, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG14, RC_BUF_THRESH11, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG15, RC_BUF_THRESH12, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG15, RC_BUF_THRESH13, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG15, RANGE_MIN_QP0, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG15, RANGE_MAX_QP0, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG15, RANGE_BPG_OFFSET0, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_MIN_QP1, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_MAX_QP1, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_BPG_OFFSET1, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_MIN_QP2, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_MAX_QP2, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG16, RANGE_BPG_OFFSET2, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_MIN_QP3, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_MAX_QP3, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_BPG_OFFSET3, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_MIN_QP4, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_MAX_QP4, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG17, RANGE_BPG_OFFSET4, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_MIN_QP5, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_MAX_QP5, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_BPG_OFFSET5, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_MIN_QP6, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_MAX_QP6, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG18, RANGE_BPG_OFFSET6, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_MIN_QP7, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_MAX_QP7, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_BPG_OFFSET7, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_MIN_QP8, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_MAX_QP8, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG19, RANGE_BPG_OFFSET8, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_MIN_QP9, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_MAX_QP9, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_BPG_OFFSET9, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_MIN_QP10, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_MAX_QP10, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG20, RANGE_BPG_OFFSET10, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_MIN_QP11, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_MAX_QP11, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_BPG_OFFSET11, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_MIN_QP12, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_MAX_QP12, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG21, RANGE_BPG_OFFSET12, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_MIN_QP13, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_MAX_QP13, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_BPG_OFFSET13, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_MIN_QP14, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_MAX_QP14, mask_sh), \ + DSC_SF(DSCC0_DSCC_PPS_CONFIG22, RANGE_BPG_OFFSET14, mask_sh), \ + DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_DEFAULT_MEM_LOW_POWER_STATE, mask_sh), \ + DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_MEM_PWR_FORCE, mask_sh), \ + DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_MEM_PWR_DIS, mask_sh), \ + DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_MEM_PWR_STATE, mask_sh), \ + DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_NATIVE_422_MEM_PWR_FORCE, mask_sh), \ + DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_NATIVE_422_MEM_PWR_DIS, mask_sh), \ + DSC_SF(DSCC0_DSCC_MEM_POWER_CONTROL, DSCC_NATIVE_422_MEM_PWR_STATE, mask_sh), \ + DSC_SF(DSCC0_DSCC_R_Y_SQUARED_ERROR_LOWER, DSCC_R_Y_SQUARED_ERROR_LOWER, mask_sh), \ + DSC_SF(DSCC0_DSCC_R_Y_SQUARED_ERROR_UPPER, DSCC_R_Y_SQUARED_ERROR_UPPER, mask_sh), \ + DSC_SF(DSCC0_DSCC_G_CB_SQUARED_ERROR_LOWER, DSCC_G_CB_SQUARED_ERROR_LOWER, mask_sh), \ + DSC_SF(DSCC0_DSCC_G_CB_SQUARED_ERROR_UPPER, DSCC_G_CB_SQUARED_ERROR_UPPER, mask_sh), \ + DSC_SF(DSCC0_DSCC_B_CR_SQUARED_ERROR_LOWER, DSCC_B_CR_SQUARED_ERROR_LOWER, mask_sh), \ + DSC_SF(DSCC0_DSCC_B_CR_SQUARED_ERROR_UPPER, DSCC_B_CR_SQUARED_ERROR_UPPER, mask_sh), \ + DSC_SF(DSCC0_DSCC_MAX_ABS_ERROR0, DSCC_R_Y_MAX_ABS_ERROR, mask_sh), \ + DSC_SF(DSCC0_DSCC_MAX_ABS_ERROR0, DSCC_G_CB_MAX_ABS_ERROR, mask_sh), \ + DSC_SF(DSCC0_DSCC_MAX_ABS_ERROR1, DSCC_B_CR_MAX_ABS_ERROR, mask_sh), \ + DSC_SF(DSCC0_DSCC_RATE_BUFFER0_MAX_FULLNESS_LEVEL, DSCC_RATE_BUFFER0_MAX_FULLNESS_LEVEL, mask_sh), \ + DSC_SF(DSCC0_DSCC_RATE_BUFFER1_MAX_FULLNESS_LEVEL, DSCC_RATE_BUFFER1_MAX_FULLNESS_LEVEL, mask_sh), \ + DSC_SF(DSCC0_DSCC_RATE_BUFFER2_MAX_FULLNESS_LEVEL, DSCC_RATE_BUFFER2_MAX_FULLNESS_LEVEL, mask_sh), \ + DSC_SF(DSCC0_DSCC_RATE_BUFFER3_MAX_FULLNESS_LEVEL, DSCC_RATE_BUFFER3_MAX_FULLNESS_LEVEL, mask_sh), \ + DSC_SF(DSCC0_DSCC_RATE_CONTROL_BUFFER0_MAX_FULLNESS_LEVEL, DSCC_RATE_CONTROL_BUFFER0_MAX_FULLNESS_LEVEL, mask_sh), \ + DSC_SF(DSCC0_DSCC_RATE_CONTROL_BUFFER1_MAX_FULLNESS_LEVEL, DSCC_RATE_CONTROL_BUFFER1_MAX_FULLNESS_LEVEL, mask_sh), \ + DSC_SF(DSCC0_DSCC_RATE_CONTROL_BUFFER2_MAX_FULLNESS_LEVEL, DSCC_RATE_CONTROL_BUFFER2_MAX_FULLNESS_LEVEL, mask_sh), \ + DSC_SF(DSCC0_DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL, DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL, mask_sh), \ + DSC_SF(DSCCIF0_DSCCIF_CONFIG0, INPUT_INTERFACE_UNDERFLOW_RECOVERY_EN, mask_sh), \ + DSC_SF(DSCCIF0_DSCCIF_CONFIG0, INPUT_INTERFACE_UNDERFLOW_OCCURRED_INT_EN, mask_sh), \ + DSC_SF(DSCCIF0_DSCCIF_CONFIG0, INPUT_INTERFACE_UNDERFLOW_OCCURRED_STATUS, mask_sh), \ + DSC_SF(DSCCIF0_DSCCIF_CONFIG0, INPUT_PIXEL_FORMAT, mask_sh), \ + DSC2_SF(DSCCIF0, DSCCIF_CONFIG0__BITS_PER_COMPONENT, mask_sh), \ + DSC_SF(DSCCIF0_DSCCIF_CONFIG0, DOUBLE_BUFFER_REG_UPDATE_PENDING, mask_sh), \ + DSC_SF(DSCCIF0_DSCCIF_CONFIG1, PIC_WIDTH, mask_sh), \ + DSC_SF(DSCCIF0_DSCCIF_CONFIG1, PIC_HEIGHT, mask_sh), \ + DSC_SF(DSCRM0_DSCRM_DSC_FORWARD_CONFIG, DSCRM_DSC_FORWARD_EN, mask_sh), \ + DSC_SF(DSCRM0_DSCRM_DSC_FORWARD_CONFIG, DSCRM_DSC_OPP_PIPE_SOURCE, mask_sh) + + + +#define DSC_FIELD_LIST_DCN20(type)\ + type DSC_CLOCK_EN; \ + type DSC_DISPCLK_R_GATE_DIS; \ + type DSC_DSCCLK_R_GATE_DIS; \ + type DSC_DBG_EN; \ + type DSC_TEST_CLOCK_MUX_SEL; \ + type ICH_RESET_AT_END_OF_LINE; \ + type NUMBER_OF_SLICES_PER_LINE; \ + type ALTERNATE_ICH_ENCODING_EN; \ + type NUMBER_OF_SLICES_IN_VERTICAL_DIRECTION; \ + type DSCC_RATE_CONTROL_BUFFER_MODEL_SIZE; \ + /*type DSCC_DISABLE_ICH;*/ \ + type DSCC_DOUBLE_BUFFER_REG_UPDATE_PENDING; \ + type DSCC_RATE_BUFFER0_OVERFLOW_OCCURRED; \ + type DSCC_RATE_BUFFER1_OVERFLOW_OCCURRED; \ + type DSCC_RATE_BUFFER2_OVERFLOW_OCCURRED; \ + type DSCC_RATE_BUFFER3_OVERFLOW_OCCURRED; \ + type DSCC_RATE_BUFFER0_UNDERFLOW_OCCURRED; \ + type DSCC_RATE_BUFFER1_UNDERFLOW_OCCURRED; \ + type DSCC_RATE_BUFFER2_UNDERFLOW_OCCURRED; \ + type DSCC_RATE_BUFFER3_UNDERFLOW_OCCURRED; \ + type DSCC_RATE_CONTROL_BUFFER_MODEL0_OVERFLOW_OCCURRED; \ + type DSCC_RATE_CONTROL_BUFFER_MODEL1_OVERFLOW_OCCURRED; \ + type DSCC_RATE_CONTROL_BUFFER_MODEL2_OVERFLOW_OCCURRED; \ + type DSCC_RATE_CONTROL_BUFFER_MODEL3_OVERFLOW_OCCURRED; \ + type DSCC_RATE_BUFFER0_OVERFLOW_OCCURRED_INT_EN; \ + type DSCC_RATE_BUFFER1_OVERFLOW_OCCURRED_INT_EN; \ + type DSCC_RATE_BUFFER2_OVERFLOW_OCCURRED_INT_EN; \ + type DSCC_RATE_BUFFER3_OVERFLOW_OCCURRED_INT_EN; \ + type DSCC_RATE_BUFFER0_UNDERFLOW_OCCURRED_INT_EN; \ + type DSCC_RATE_BUFFER1_UNDERFLOW_OCCURRED_INT_EN; \ + type DSCC_RATE_BUFFER2_UNDERFLOW_OCCURRED_INT_EN; \ + type DSCC_RATE_BUFFER3_UNDERFLOW_OCCURRED_INT_EN; \ + type DSCC_RATE_CONTROL_BUFFER_MODEL0_OVERFLOW_OCCURRED_INT_EN; \ + type DSCC_RATE_CONTROL_BUFFER_MODEL1_OVERFLOW_OCCURRED_INT_EN; \ + type DSCC_RATE_CONTROL_BUFFER_MODEL2_OVERFLOW_OCCURRED_INT_EN; \ + type DSCC_RATE_CONTROL_BUFFER_MODEL3_OVERFLOW_OCCURRED_INT_EN; \ + type DSC_VERSION_MINOR; \ + type DSC_VERSION_MAJOR; \ + type PPS_IDENTIFIER; \ + type LINEBUF_DEPTH; \ + type DSCC_PPS_CONFIG0__BITS_PER_COMPONENT; \ + type BITS_PER_PIXEL; \ + type VBR_ENABLE; \ + type SIMPLE_422; \ + type CONVERT_RGB; \ + type BLOCK_PRED_ENABLE; \ + type NATIVE_422; \ + type NATIVE_420; \ + type CHUNK_SIZE; \ + type PIC_WIDTH; \ + type PIC_HEIGHT; \ + type SLICE_WIDTH; \ + type SLICE_HEIGHT; \ + type INITIAL_XMIT_DELAY; \ + type INITIAL_DEC_DELAY; \ + type INITIAL_SCALE_VALUE; \ + type SCALE_INCREMENT_INTERVAL; \ + type SCALE_DECREMENT_INTERVAL; \ + type FIRST_LINE_BPG_OFFSET; \ + type SECOND_LINE_BPG_OFFSET; \ + type NFL_BPG_OFFSET; \ + type SLICE_BPG_OFFSET; \ + type NSL_BPG_OFFSET; \ + type SECOND_LINE_OFFSET_ADJ; \ + type INITIAL_OFFSET; \ + type FINAL_OFFSET; \ + type FLATNESS_MIN_QP; \ + type FLATNESS_MAX_QP; \ + type RC_MODEL_SIZE; \ + type RC_EDGE_FACTOR; \ + type RC_QUANT_INCR_LIMIT0; \ + type RC_QUANT_INCR_LIMIT1; \ + type RC_TGT_OFFSET_LO; \ + type RC_TGT_OFFSET_HI; \ + type RC_BUF_THRESH0; \ + type RC_BUF_THRESH1; \ + type RC_BUF_THRESH2; \ + type RC_BUF_THRESH3; \ + type RC_BUF_THRESH4; \ + type RC_BUF_THRESH5; \ + type RC_BUF_THRESH6; \ + type RC_BUF_THRESH7; \ + type RC_BUF_THRESH8; \ + type RC_BUF_THRESH9; \ + type RC_BUF_THRESH10; \ + type RC_BUF_THRESH11; \ + type RC_BUF_THRESH12; \ + type RC_BUF_THRESH13; \ + type RANGE_MIN_QP0; \ + type RANGE_MAX_QP0; \ + type RANGE_BPG_OFFSET0; \ + type RANGE_MIN_QP1; \ + type RANGE_MAX_QP1; \ + type RANGE_BPG_OFFSET1; \ + type RANGE_MIN_QP2; \ + type RANGE_MAX_QP2; \ + type RANGE_BPG_OFFSET2; \ + type RANGE_MIN_QP3; \ + type RANGE_MAX_QP3; \ + type RANGE_BPG_OFFSET3; \ + type RANGE_MIN_QP4; \ + type RANGE_MAX_QP4; \ + type RANGE_BPG_OFFSET4; \ + type RANGE_MIN_QP5; \ + type RANGE_MAX_QP5; \ + type RANGE_BPG_OFFSET5; \ + type RANGE_MIN_QP6; \ + type RANGE_MAX_QP6; \ + type RANGE_BPG_OFFSET6; \ + type RANGE_MIN_QP7; \ + type RANGE_MAX_QP7; \ + type RANGE_BPG_OFFSET7; \ + type RANGE_MIN_QP8; \ + type RANGE_MAX_QP8; \ + type RANGE_BPG_OFFSET8; \ + type RANGE_MIN_QP9; \ + type RANGE_MAX_QP9; \ + type RANGE_BPG_OFFSET9; \ + type RANGE_MIN_QP10; \ + type RANGE_MAX_QP10; \ + type RANGE_BPG_OFFSET10; \ + type RANGE_MIN_QP11; \ + type RANGE_MAX_QP11; \ + type RANGE_BPG_OFFSET11; \ + type RANGE_MIN_QP12; \ + type RANGE_MAX_QP12; \ + type RANGE_BPG_OFFSET12; \ + type RANGE_MIN_QP13; \ + type RANGE_MAX_QP13; \ + type RANGE_BPG_OFFSET13; \ + type RANGE_MIN_QP14; \ + type RANGE_MAX_QP14; \ + type RANGE_BPG_OFFSET14; \ + type DSCC_DEFAULT_MEM_LOW_POWER_STATE; \ + type DSCC_MEM_PWR_FORCE; \ + type DSCC_MEM_PWR_DIS; \ + type DSCC_MEM_PWR_STATE; \ + type DSCC_NATIVE_422_MEM_PWR_FORCE; \ + type DSCC_NATIVE_422_MEM_PWR_DIS; \ + type DSCC_NATIVE_422_MEM_PWR_STATE; \ + type DSCC_R_Y_SQUARED_ERROR_LOWER; \ + type DSCC_R_Y_SQUARED_ERROR_UPPER; \ + type DSCC_G_CB_SQUARED_ERROR_LOWER; \ + type DSCC_G_CB_SQUARED_ERROR_UPPER; \ + type DSCC_B_CR_SQUARED_ERROR_LOWER; \ + type DSCC_B_CR_SQUARED_ERROR_UPPER; \ + type DSCC_R_Y_MAX_ABS_ERROR; \ + type DSCC_G_CB_MAX_ABS_ERROR; \ + type DSCC_B_CR_MAX_ABS_ERROR; \ + type DSCC_RATE_BUFFER0_MAX_FULLNESS_LEVEL; \ + type DSCC_RATE_BUFFER1_MAX_FULLNESS_LEVEL; \ + type DSCC_RATE_BUFFER2_MAX_FULLNESS_LEVEL; \ + type DSCC_RATE_BUFFER3_MAX_FULLNESS_LEVEL; \ + type DSCC_RATE_CONTROL_BUFFER0_MAX_FULLNESS_LEVEL; \ + type DSCC_RATE_CONTROL_BUFFER1_MAX_FULLNESS_LEVEL; \ + type DSCC_RATE_CONTROL_BUFFER2_MAX_FULLNESS_LEVEL; \ + type DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL; \ + type DSCC_UPDATE_PENDING_STATUS; \ + type DSCC_UPDATE_TAKEN_STATUS; \ + type DSCC_UPDATE_TAKEN_ACK; \ + type DSCC_RATE_BUFFER0_FULLNESS_LEVEL; \ + type DSCC_RATE_BUFFER1_FULLNESS_LEVEL; \ + type DSCC_RATE_BUFFER2_FULLNESS_LEVEL; \ + type DSCC_RATE_BUFFER3_FULLNESS_LEVEL; \ + type DSCC_RATE_CONTROL_BUFFER0_FULLNESS_LEVEL; \ + type DSCC_RATE_CONTROL_BUFFER1_FULLNESS_LEVEL; \ + type DSCC_RATE_CONTROL_BUFFER2_FULLNESS_LEVEL; \ + type DSCC_RATE_CONTROL_BUFFER3_FULLNESS_LEVEL; \ + type DSCC_RATE_BUFFER0_INITIAL_XMIT_DELAY_REACHED; \ + type DSCC_RATE_BUFFER1_INITIAL_XMIT_DELAY_REACHED; \ + type DSCC_RATE_BUFFER2_INITIAL_XMIT_DELAY_REACHED; \ + type DSCC_RATE_BUFFER3_INITIAL_XMIT_DELAY_REACHED; \ + type INPUT_INTERFACE_UNDERFLOW_RECOVERY_EN; \ + type INPUT_INTERFACE_UNDERFLOW_OCCURRED_INT_EN; \ + type INPUT_INTERFACE_UNDERFLOW_OCCURRED_STATUS; \ + type INPUT_PIXEL_FORMAT; \ + type DSCCIF_CONFIG0__BITS_PER_COMPONENT; \ + type DOUBLE_BUFFER_REG_UPDATE_PENDING; \ + type DSCCIF_UPDATE_PENDING_STATUS; \ + type DSCCIF_UPDATE_TAKEN_STATUS; \ + type DSCCIF_UPDATE_TAKEN_ACK; \ + type DSCRM_DSC_FORWARD_EN; \ + type DSCRM_DSC_OPP_PIPE_SOURCE + +struct dcn20_dsc_registers { + uint32_t DSC_TOP_CONTROL; + uint32_t DSC_DEBUG_CONTROL; + uint32_t DSCC_CONFIG0; + uint32_t DSCC_CONFIG1; + uint32_t DSCC_STATUS; + uint32_t DSCC_INTERRUPT_CONTROL_STATUS; + uint32_t DSCC_PPS_CONFIG0; + uint32_t DSCC_PPS_CONFIG1; + uint32_t DSCC_PPS_CONFIG2; + uint32_t DSCC_PPS_CONFIG3; + uint32_t DSCC_PPS_CONFIG4; + uint32_t DSCC_PPS_CONFIG5; + uint32_t DSCC_PPS_CONFIG6; + uint32_t DSCC_PPS_CONFIG7; + uint32_t DSCC_PPS_CONFIG8; + uint32_t DSCC_PPS_CONFIG9; + uint32_t DSCC_PPS_CONFIG10; + uint32_t DSCC_PPS_CONFIG11; + uint32_t DSCC_PPS_CONFIG12; + uint32_t DSCC_PPS_CONFIG13; + uint32_t DSCC_PPS_CONFIG14; + uint32_t DSCC_PPS_CONFIG15; + uint32_t DSCC_PPS_CONFIG16; + uint32_t DSCC_PPS_CONFIG17; + uint32_t DSCC_PPS_CONFIG18; + uint32_t DSCC_PPS_CONFIG19; + uint32_t DSCC_PPS_CONFIG20; + uint32_t DSCC_PPS_CONFIG21; + uint32_t DSCC_PPS_CONFIG22; + uint32_t DSCC_MEM_POWER_CONTROL; + uint32_t DSCC_R_Y_SQUARED_ERROR_LOWER; + uint32_t DSCC_R_Y_SQUARED_ERROR_UPPER; + uint32_t DSCC_G_CB_SQUARED_ERROR_LOWER; + uint32_t DSCC_G_CB_SQUARED_ERROR_UPPER; + uint32_t DSCC_B_CR_SQUARED_ERROR_LOWER; + uint32_t DSCC_B_CR_SQUARED_ERROR_UPPER; + uint32_t DSCC_MAX_ABS_ERROR0; + uint32_t DSCC_MAX_ABS_ERROR1; + uint32_t DSCC_RATE_BUFFER0_MAX_FULLNESS_LEVEL; + uint32_t DSCC_RATE_BUFFER1_MAX_FULLNESS_LEVEL; + uint32_t DSCC_RATE_BUFFER2_MAX_FULLNESS_LEVEL; + uint32_t DSCC_RATE_BUFFER3_MAX_FULLNESS_LEVEL; + uint32_t DSCC_RATE_CONTROL_BUFFER0_MAX_FULLNESS_LEVEL; + uint32_t DSCC_RATE_CONTROL_BUFFER1_MAX_FULLNESS_LEVEL; + uint32_t DSCC_RATE_CONTROL_BUFFER2_MAX_FULLNESS_LEVEL; + uint32_t DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL; + uint32_t DSCCIF_CONFIG0; + uint32_t DSCCIF_CONFIG1; + uint32_t DSCRM_DSC_FORWARD_CONFIG; +}; + + +struct dcn20_dsc_shift { + DSC_FIELD_LIST_DCN20(uint8_t); +}; + +struct dcn20_dsc_mask { + DSC_FIELD_LIST_DCN20(uint32_t); +}; + +/* DSCCIF_CONFIG.INPUT_PIXEL_FORMAT values */ +enum dsc_pixel_format { + DSC_PIXFMT_RGB, + DSC_PIXFMT_YCBCR444, + DSC_PIXFMT_SIMPLE_YCBCR422, + DSC_PIXFMT_NATIVE_YCBCR422, + DSC_PIXFMT_NATIVE_YCBCR420, + DSC_PIXFMT_UNKNOWN +}; + +struct dsc_reg_values { + /* PPS registers */ + struct drm_dsc_config pps; + + /* Additional registers */ + uint32_t dsc_clock_enable; + uint32_t dsc_clock_gating_disable; + uint32_t underflow_recovery_en; + uint32_t underflow_occurred_int_en; + uint32_t underflow_occurred_status; + enum dsc_pixel_format pixel_format; + uint32_t ich_reset_at_eol; + uint32_t alternate_ich_encoding_en; + uint32_t num_slices_h; + uint32_t num_slices_v; + uint32_t rc_buffer_model_size; + uint32_t disable_ich; + uint32_t bpp_x32; + uint32_t dsc_dbg_en; + uint32_t rc_buffer_model_overflow_int_en[4]; +}; + +struct dcn20_dsc { + struct display_stream_compressor base; + const struct dcn20_dsc_registers *dsc_regs; + const struct dcn20_dsc_shift *dsc_shift; + const struct dcn20_dsc_mask *dsc_mask; + + struct dsc_reg_values reg_vals; + + int max_image_width; +}; + +void dsc_config_log(struct display_stream_compressor *dsc, + const struct dsc_config *config); + +void dsc_log_pps(struct display_stream_compressor *dsc, + struct drm_dsc_config *pps); + +void dsc_override_rc_params(struct rc_params *rc, + const struct dc_dsc_rc_params_override *override); + +bool dsc_prepare_config(const struct dsc_config *dsc_cfg, + struct dsc_reg_values *dsc_reg_vals, + struct dsc_optc_config *dsc_optc_cfg); + +enum dsc_pixel_format dsc_dc_pixel_encoding_to_dsc_pixel_format(enum dc_pixel_encoding dc_pix_enc, + bool is_ycbcr422_simple); + +enum dsc_bits_per_comp dsc_dc_color_depth_to_dsc_bits_per_comp(enum dc_color_depth dc_color_depth); + +void dsc_init_reg_values(struct dsc_reg_values *reg_vals); + +void dsc_update_from_dsc_parameters(struct dsc_reg_values *reg_vals, const struct dsc_parameters *dsc_params); + +void dsc2_construct(struct dcn20_dsc *dsc, + struct dc_context *ctx, + int inst, + const struct dcn20_dsc_registers *dsc_regs, + const struct dcn20_dsc_shift *dsc_shift, + const struct dcn20_dsc_mask *dsc_mask); + +void dsc2_get_enc_caps(struct dsc_enc_caps *dsc_enc_caps, + int pixel_clock_100Hz); + +bool dsc2_get_packed_pps(struct display_stream_compressor *dsc, + const struct dsc_config *dsc_cfg, + uint8_t *dsc_packed_pps); + +#endif + diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dcn35/dcn35_dsc.c b/drivers/gpu/drm/amd/display/dc/dsc/dcn35/dcn35_dsc.c new file mode 100644 index 00000000000000..71d2dff9986d5f --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dsc/dcn35/dcn35_dsc.c @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: MIT */ +/* + * 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 "dcn35_dsc.h" +#include "reg_helper.h" + +/* Macro definitios for REG_SET macros*/ +#define CTX \ + dsc20->base.ctx + +#define REG(reg)\ + dsc20->dsc_regs->reg + +#undef FN +#define FN(reg_name, field_name) \ + ((const struct dcn35_dsc_shift *)(dsc20->dsc_shift))->field_name, \ + ((const struct dcn35_dsc_mask *)(dsc20->dsc_mask))->field_name + +#define DC_LOGGER \ + dsc->ctx->logger + +void dsc35_construct(struct dcn20_dsc *dsc, + struct dc_context *ctx, + int inst, + const struct dcn20_dsc_registers *dsc_regs, + const struct dcn35_dsc_shift *dsc_shift, + const struct dcn35_dsc_mask *dsc_mask) +{ + dsc2_construct(dsc, ctx, inst, dsc_regs, + (const struct dcn20_dsc_shift *)(dsc_shift), + (const struct dcn20_dsc_mask *)(dsc_mask)); +} + +void dsc35_set_fgcg(struct dcn20_dsc *dsc20, bool enable) +{ + REG_UPDATE(DSC_TOP_CONTROL, DSC_FGCG_REP_DIS, !enable); +} diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dcn35/dcn35_dsc.h b/drivers/gpu/drm/amd/display/dc/dsc/dcn35/dcn35_dsc.h new file mode 100644 index 00000000000000..133ad38842cc40 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dsc/dcn35/dcn35_dsc.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: MIT */ +/* + * 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 __DCN35_DSC_H__ +#define __DCN35_DSC_H__ + +#include "dcn20/dcn20_dsc.h" + +#define DSC_REG_LIST_SH_MASK_DCN35(mask_sh) \ + DSC_REG_LIST_SH_MASK_DCN20(mask_sh), \ + DSC_SF(DSC_TOP0_DSC_TOP_CONTROL, DSC_FGCG_REP_DIS, mask_sh) + +#define DSC_FIELD_LIST_DCN35(type) \ + struct { \ + DSC_FIELD_LIST_DCN20(type); \ + type DSC_FGCG_REP_DIS; \ + } + +struct dcn35_dsc_shift { + DSC_FIELD_LIST_DCN35(uint8_t); +}; + +struct dcn35_dsc_mask { + DSC_FIELD_LIST_DCN35(uint32_t); +}; + +void dsc35_construct(struct dcn20_dsc *dsc, + struct dc_context *ctx, + int inst, + const struct dcn20_dsc_registers *dsc_regs, + const struct dcn35_dsc_shift *dsc_shift, + const struct dcn35_dsc_mask *dsc_mask); + +void dsc35_set_fgcg(struct dcn20_dsc *dsc20, bool enable); + +#endif /* __DCN35_DSC_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dsc.h b/drivers/gpu/drm/amd/display/dc/dsc/dsc.h new file mode 100644 index 00000000000000..4b27f29d0d80d9 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dsc/dsc.h @@ -0,0 +1,112 @@ +/* + * Copyright 2017 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_DSC_H__ +#define __DAL_DSC_H__ + +#include "dc_dsc.h" +#include "dc_hw_types.h" +#include "dc_types.h" +/* do not include any other headers + * or else it might break Edid Utility functionality. + */ + + +/* Input parameters for configuring DSC from the outside of DSC */ +struct dsc_config { + uint32_t pic_width; + uint32_t pic_height; + enum dc_pixel_encoding pixel_encoding; + enum dc_color_depth color_depth; /* Bits per component */ + bool is_odm; + struct dc_dsc_config dc_dsc_cfg; +}; + + +/* Output parameters for configuring DSC-related part of OPTC */ +struct dsc_optc_config { + uint32_t slice_width; /* Slice width in pixels */ + uint32_t bytes_per_pixel; /* Bytes per pixel in u3.28 format */ + bool is_pixel_format_444; /* 'true' if pixel format is 'RGB 444' or 'Simple YCbCr 4:2:2' (4:2:2 upsampled to 4:4:4)' */ +}; + + +struct dcn_dsc_state { + uint32_t dsc_clock_en; + uint32_t dsc_slice_width; + uint32_t dsc_bits_per_pixel; + uint32_t dsc_slice_height; + uint32_t dsc_pic_width; + uint32_t dsc_pic_height; + uint32_t dsc_slice_bpg_offset; + uint32_t dsc_chunk_size; + uint32_t dsc_fw_en; + uint32_t dsc_opp_source; +}; + + +/* DSC encoder capabilities + * They differ from the DPCD DSC caps because they are based on AMD DSC encoder caps. + */ +union dsc_enc_slice_caps { + struct { + uint8_t NUM_SLICES_1 : 1; + uint8_t NUM_SLICES_2 : 1; + uint8_t NUM_SLICES_3 : 1; /* This one is not per DSC spec, but our encoder supports it */ + uint8_t NUM_SLICES_4 : 1; + uint8_t NUM_SLICES_8 : 1; + uint8_t NUM_SLICES_12 : 1; + uint8_t NUM_SLICES_16 : 1; + } bits; + uint8_t raw; +}; + +struct dsc_enc_caps { + uint8_t dsc_version; + union dsc_enc_slice_caps slice_caps; + int32_t lb_bit_depth; + bool is_block_pred_supported; + union dsc_color_formats color_formats; + union dsc_color_depth color_depth; + int32_t max_total_throughput_mps; /* Maximum total throughput with all the slices combined */ + int32_t max_slice_width; + uint32_t bpp_increment_div; /* bpp increment divisor, e.g. if 16, it's 1/16th of a bit */ + uint32_t edp_sink_max_bits_per_pixel; + bool is_dp; +}; + +struct dsc_funcs { + void (*dsc_get_enc_caps)(struct dsc_enc_caps *dsc_enc_caps, int pixel_clock_100Hz); + void (*dsc_read_state)(struct display_stream_compressor *dsc, struct dcn_dsc_state *s); + bool (*dsc_validate_stream)(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg); + void (*dsc_set_config)(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg, + struct dsc_optc_config *dsc_optc_cfg); + bool (*dsc_get_packed_pps)(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg, + uint8_t *dsc_packed_pps); + void (*dsc_enable)(struct display_stream_compressor *dsc, int opp_pipe); + void (*dsc_disable)(struct display_stream_compressor *dsc); + void (*dsc_disconnect)(struct display_stream_compressor *dsc); +}; + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/hwss/Makefile b/drivers/gpu/drm/amd/display/dc/hwss/Makefile index bccd46bd18158c..254136f8e3f907 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/Makefile +++ b/drivers/gpu/drm/amd/display/dc/hwss/Makefile @@ -78,7 +78,7 @@ ifdef CONFIG_DRM_AMD_DC_FP # DCN ############################################################################### -HWSS_DCN10 = dcn10_hwseq.o +HWSS_DCN10 = dcn10_hwseq.o dcn10_init.o AMD_DAL_HWSS_DCN10 = $(addprefix $(AMDDALPATH)/dc/hwss/dcn10/,$(HWSS_DCN10)) @@ -86,7 +86,7 @@ AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCN10) ############################################################################### -HWSS_DCN20 = dcn20_hwseq.o +HWSS_DCN20 = dcn20_hwseq.o dcn20_init.o AMD_DAL_HWSS_DCN20 = $(addprefix $(AMDDALPATH)/dc/hwss/dcn20/,$(HWSS_DCN20)) @@ -94,7 +94,7 @@ AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCN20) ############################################################################### -HWSS_DCN201 = dcn201_hwseq.o +HWSS_DCN201 = dcn201_hwseq.o dcn201_init.o AMD_DAL_HWSS_DCN201 = $(addprefix $(AMDDALPATH)/dc/hwss/dcn201/,$(HWSS_DCN201)) @@ -102,7 +102,7 @@ AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCN201) ############################################################################### -HWSS_DCN21 = dcn21_hwseq.o +HWSS_DCN21 = dcn21_hwseq.o dcn21_init.o AMD_DAL_HWSS_DCN21 = $(addprefix $(AMDDALPATH)/dc/hwss/dcn21/,$(HWSS_DCN21)) @@ -114,7 +114,7 @@ AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCN21) ############################################################################### -HWSS_DCN30 = dcn30_hwseq.o +HWSS_DCN30 = dcn30_hwseq.o dcn30_init.o AMD_DAL_HWSS_DCN30 = $(addprefix $(AMDDALPATH)/dc/hwss/dcn30/,$(HWSS_DCN30)) @@ -122,7 +122,7 @@ AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCN30) ############################################################################### -HWSS_DCN301 = dcn301_hwseq.o +HWSS_DCN301 = dcn301_hwseq.o dcn301_init.o AMD_DAL_HWSS_DCN301 = $(addprefix $(AMDDALPATH)/dc/hwss/dcn301/,$(HWSS_DCN301)) @@ -130,15 +130,17 @@ AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCN301) ############################################################################### -HWSS_DCN302 = dcn302_hwseq.o +HWSS_DCN302 = dcn302_hwseq.o dcn302_init.o AMD_DAL_HWSS_DCN302 = $(addprefix $(AMDDALPATH)/dc/hwss/dcn302/,$(HWSS_DCN302)) AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCN302) + + ############################################################################### -HWSS_DCN303 = dcn303_hwseq.o +HWSS_DCN303 = dcn303_hwseq.o dcn303_init.o AMD_DAL_HWSS_DCN303 = $(addprefix $(AMDDALPATH)/dc/hwss/dcn303/,$(HWSS_DCN303)) @@ -146,7 +148,7 @@ AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCN303) ############################################################################### -HWSS_DCN31 = dcn31_hwseq.o +HWSS_DCN31 = dcn31_hwseq.o dcn31_init.o AMD_DAL_HWSS_DCN31 = $(addprefix $(AMDDALPATH)/dc/hwss/dcn31/,$(HWSS_DCN31)) @@ -154,7 +156,7 @@ AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCN31) ############################################################################### -HWSS_DCN314 = dcn314_hwseq.o +HWSS_DCN314 = dcn314_hwseq.o dcn314_init.o AMD_DAL_HWSS_DCN314 = $(addprefix $(AMDDALPATH)/dc/hwss/dcn314/,$(HWSS_DCN314)) @@ -162,7 +164,7 @@ AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCN314) ############################################################################### -HWSS_DCN32 = dcn32_hwseq.o +HWSS_DCN32 = dcn32_hwseq.o dcn32_init.o AMD_DAL_HWSS_DCN32 = $(addprefix $(AMDDALPATH)/dc/hwss/dcn32/,$(HWSS_DCN32)) @@ -170,7 +172,7 @@ AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCN32) ############################################################################### -HWSS_DCN35 = dcn35_hwseq.o +HWSS_DCN35 = dcn35_hwseq.o dcn35_init.o AMD_DAL_HWSS_DCN35 = $(addprefix $(AMDDALPATH)/dc/hwss/dcn35/,$(HWSS_DCN35)) @@ -180,4 +182,4 @@ AMD_DISPLAY_FILES += $(AMD_DAL_HWSS_DCN35) ############################################################################### -endif \ No newline at end of file +endif diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce/dce_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dce/dce_hwseq.h index 44b4df6469d1aa..52f045cfd52a99 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dce/dce_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce/dce_hwseq.h @@ -682,6 +682,7 @@ struct dce_hwseq_registers { uint32_t DCHUBBUB_ARB_HOSTVM_CNTL; uint32_t HPO_TOP_HW_CONTROL; uint32_t DMU_CLK_CNTL; + uint32_t DCCG_GATE_DISABLE_CNTL4; uint32_t DCCG_GATE_DISABLE_CNTL5; }; /* set field name */ @@ -1199,7 +1200,19 @@ struct dce_hwseq_registers { type PHYBSYMCLK_ROOT_GATE_DISABLE;\ type PHYCSYMCLK_ROOT_GATE_DISABLE;\ type PHYDSYMCLK_ROOT_GATE_DISABLE;\ - type PHYESYMCLK_ROOT_GATE_DISABLE; + type PHYESYMCLK_ROOT_GATE_DISABLE;\ + type DTBCLK_P0_GATE_DISABLE;\ + type DTBCLK_P1_GATE_DISABLE;\ + type DTBCLK_P2_GATE_DISABLE;\ + type DTBCLK_P3_GATE_DISABLE;\ + type DPSTREAMCLK0_GATE_DISABLE;\ + type DPSTREAMCLK1_GATE_DISABLE;\ + type DPSTREAMCLK2_GATE_DISABLE;\ + type DPSTREAMCLK3_GATE_DISABLE;\ + type DPIASYMCLK0_GATE_DISABLE;\ + type DPIASYMCLK1_GATE_DISABLE;\ + type DPIASYMCLK2_GATE_DISABLE;\ + type DPIASYMCLK3_GATE_DISABLE; struct dce_hwseq_shift { HWSEQ_REG_FIELD_LIST(uint8_t) diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c index 960a55e06375b2..5660f15da291e9 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c @@ -55,6 +55,7 @@ #include "audio.h" #include "reg_helper.h" #include "panel_cntl.h" +#include "dc_state_priv.h" #include "dpcd_defs.h" /* include DCE11 register header files */ #include "dce/dce_11_0_d.h" @@ -790,7 +791,7 @@ void dce110_edp_power_control( struct dc_context *ctx = link->ctx; struct bp_transmitter_control cntl = { 0 }; enum bp_result bp_result; - uint8_t panel_instance; + uint8_t pwrseq_instance; if (dal_graphics_object_id_get_connector_id(link->link_enc->connector) @@ -873,7 +874,7 @@ void dce110_edp_power_control( cntl.coherent = false; cntl.lanes_number = LANE_COUNT_FOUR; cntl.hpd_sel = link->link_enc->hpd_source; - panel_instance = link->panel_cntl->inst; + pwrseq_instance = link->panel_cntl->pwrseq_inst; if (ctx->dc->ctx->dmub_srv && ctx->dc->debug.dmub_command_table) { @@ -881,11 +882,11 @@ void dce110_edp_power_control( 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, link->link_powered_externally); + pwrseq_instance, link->link_powered_externally); } else { bp_result = ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios, LVTMA_CONTROL_POWER_OFF, - panel_instance, link->link_powered_externally); + pwrseq_instance, link->link_powered_externally); } } @@ -956,7 +957,7 @@ void dce110_edp_backlight_control( { struct dc_context *ctx = link->ctx; struct bp_transmitter_control cntl = { 0 }; - uint8_t panel_instance; + uint8_t pwrseq_instance; unsigned int pre_T11_delay = OLED_PRE_T11_DELAY; unsigned int post_T7_delay = OLED_POST_T7_DELAY; @@ -1009,7 +1010,7 @@ void dce110_edp_backlight_control( */ /* dc_service_sleep_in_milliseconds(50); */ /*edp 1.2*/ - panel_instance = link->panel_cntl->inst; + pwrseq_instance = link->panel_cntl->pwrseq_inst; if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_ON) { if (!link->dc->config.edp_no_power_sequencing) @@ -1034,11 +1035,11 @@ void dce110_edp_backlight_control( if (cntl.action == TRANSMITTER_CONTROL_BACKLIGHT_ON) ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios, LVTMA_CONTROL_LCD_BLON, - panel_instance, link->link_powered_externally); + pwrseq_instance, link->link_powered_externally); else ctx->dc_bios->funcs->enable_lvtma_control(ctx->dc_bios, LVTMA_CONTROL_LCD_BLOFF, - panel_instance, link->link_powered_externally); + pwrseq_instance, link->link_powered_externally); } link_transmitter_control(ctx->dc_bios, &cntl); @@ -1353,7 +1354,7 @@ static void build_audio_output( if (state->clk_mgr && (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT || pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)) { - audio_output->pll_info.dp_dto_source_clock_in_khz = + audio_output->pll_info.audio_dto_source_clock_in_khz = state->clk_mgr->funcs->get_dp_ref_clk_frequency( state->clk_mgr); } @@ -1596,7 +1597,7 @@ static enum dc_status apply_single_controller_ctx_to_hw( * is constructed with the same sink). Make sure not to override * and link programming on the main. */ - if (pipe_ctx->stream->mall_stream_config.type != SUBVP_PHANTOM) { + if (dc_state_get_pipe_subvp_type(context, pipe_ctx) != SUBVP_PHANTOM) { pipe_ctx->stream->link->psr_settings.psr_feature_enabled = false; pipe_ctx->stream->link->replay_settings.replay_feature_enabled = false; } @@ -1684,7 +1685,7 @@ static void disable_vga_and_power_gate_all_controllers( true); dc->current_state->res_ctx.pipe_ctx[i].pipe_idx = i; - dc->hwss.disable_plane(dc, + dc->hwss.disable_plane(dc, dc->current_state, &dc->current_state->res_ctx.pipe_ctx[i]); } } @@ -2124,7 +2125,8 @@ static void dce110_reset_hw_ctx_wrap( BREAK_TO_DEBUGGER(); } pipe_ctx_old->stream_res.tg->funcs->disable_crtc(pipe_ctx_old->stream_res.tg); - pipe_ctx_old->stream->link->phy_state.symclk_ref_cnts.otg = 0; + if (dc_is_hdmi_tmds_signal(pipe_ctx_old->stream->signal)) + pipe_ctx_old->stream->link->phy_state.symclk_ref_cnts.otg = 0; pipe_ctx_old->plane_res.mi->funcs->free_mem_input( pipe_ctx_old->plane_res.mi, dc->current_state->stream_count); @@ -2133,7 +2135,7 @@ static void dce110_reset_hw_ctx_wrap( old_clk)) old_clk->funcs->cs_power_down(old_clk); - dc->hwss.disable_plane(dc, pipe_ctx_old); + dc->hwss.disable_plane(dc, dc->current_state, pipe_ctx_old); pipe_ctx_old->stream = NULL; } @@ -2497,6 +2499,7 @@ static bool wait_for_reset_trigger_to_occur( /* Enable timing synchronization for a group of Timing Generators. */ static void dce110_enable_timing_synchronization( struct dc *dc, + struct dc_state *state, int group_index, int group_size, struct pipe_ctx *grouped_pipes[]) @@ -2590,6 +2593,7 @@ static void init_hw(struct dc *dc) struct dmcu *dmcu; struct dce_hwseq *hws = dc->hwseq; uint32_t backlight = MAX_BACKLIGHT_LEVEL; + uint32_t user_level = MAX_BACKLIGHT_LEVEL; bp = dc->ctx->dc_bios; for (i = 0; i < dc->res_pool->pipe_count; i++) { @@ -2639,13 +2643,15 @@ static void init_hw(struct dc *dc) for (i = 0; i < dc->link_count; i++) { struct dc_link *link = dc->links[i]; - if (link->panel_cntl) + if (link->panel_cntl) { backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl); + user_level = link->panel_cntl->stored_backlight_registers.USER_LEVEL; + } } abm = dc->res_pool->abm; if (abm != NULL) - abm->funcs->abm_init(abm, backlight); + abm->funcs->abm_init(abm, backlight, user_level); dmcu = dc->res_pool->dmcu; if (dmcu != NULL && abm != NULL) @@ -2842,7 +2848,7 @@ static void dce110_post_unlock_program_front_end( { } -static void dce110_power_down_fe(struct dc *dc, struct pipe_ctx *pipe_ctx) +static void dce110_power_down_fe(struct dc *dc, struct dc_state *state, struct pipe_ctx *pipe_ctx) { struct dce_hwseq *hws = dc->hwseq; int fe_idx = pipe_ctx->plane_res.mi ? @@ -3115,7 +3121,8 @@ void dce110_disable_link_output(struct dc_link *link, struct dmcu *dmcu = dc->res_pool->dmcu; if (signal == SIGNAL_TYPE_EDP && - link->dc->hwss.edp_backlight_control) + link->dc->hwss.edp_backlight_control && + !link->skip_implict_edp_power_control) link->dc->hwss.edp_backlight_control(link, false); else if (dmcu != NULL && dmcu->funcs->lock_phy) dmcu->funcs->lock_phy(dmcu); diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c index cdb903116eb7ca..6dd479e8a34850 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c @@ -56,6 +56,7 @@ #include "dc_trace.h" #include "dce/dmub_outbox.h" #include "link.h" +#include "dc_state_priv.h" #define DC_LOGGER \ dc_logger @@ -115,7 +116,7 @@ void dcn10_lock_all_pipes(struct dc *dc, !pipe_ctx->stream || (!pipe_ctx->plane_state && !old_pipe_ctx->plane_state) || !tg->funcs->is_tg_enabled(tg) || - pipe_ctx->stream->mall_stream_config.type == SUBVP_PHANTOM) + dc_state_get_pipe_subvp_type(context, pipe_ctx) == SUBVP_PHANTOM) continue; if (lock) @@ -1057,7 +1058,8 @@ static void dcn10_reset_back_end_for_pipe( if (pipe_ctx->stream_res.tg->funcs->set_drr) pipe_ctx->stream_res.tg->funcs->set_drr( pipe_ctx->stream_res.tg, NULL); - pipe_ctx->stream->link->phy_state.symclk_ref_cnts.otg = 0; + if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal)) + pipe_ctx->stream->link->phy_state.symclk_ref_cnts.otg = 0; } for (i = 0; i < dc->res_pool->pipe_count; i++) @@ -1180,7 +1182,9 @@ void dcn10_verify_allow_pstate_change_high(struct dc *dc) } /* trigger HW to start disconnect plane from stream on the next vsync */ -void dcn10_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx) +void dcn10_plane_atomic_disconnect(struct dc *dc, + struct dc_state *state, + struct pipe_ctx *pipe_ctx) { struct dce_hwseq *hws = dc->hwseq; struct hubp *hubp = pipe_ctx->plane_res.hubp; @@ -1200,7 +1204,7 @@ void dcn10_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx) mpc->funcs->remove_mpcc(mpc, mpc_tree_params, mpcc_to_remove); // Phantom pipes have OTG disabled by default, so MPCC_STATUS will never assert idle, // so don't wait for MPCC_IDLE in the programming sequence - if (opp != NULL && !pipe_ctx->plane_state->is_phantom) + if (opp != NULL && dc_state_get_pipe_subvp_type(state, pipe_ctx) != SUBVP_PHANTOM) opp->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; dc->optimized_required = true; @@ -1290,7 +1294,7 @@ void dcn10_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) pipe_ctx->plane_state = NULL; } -void dcn10_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) +void dcn10_disable_plane(struct dc *dc, struct dc_state *state, struct pipe_ctx *pipe_ctx) { struct dce_hwseq *hws = dc->hwseq; DC_LOGGER_INIT(dc->ctx->logger); @@ -1416,12 +1420,12 @@ void dcn10_init_pipes(struct dc *dc, struct dc_state *context) dc->res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; pipe_ctx->stream_res.opp = dc->res_pool->opps[i]; - hws->funcs.plane_atomic_disconnect(dc, pipe_ctx); + hws->funcs.plane_atomic_disconnect(dc, context, pipe_ctx); if (tg->funcs->is_tg_enabled(tg)) tg->funcs->unlock(tg); - dc->hwss.disable_plane(dc, pipe_ctx); + dc->hwss.disable_plane(dc, context, pipe_ctx); pipe_ctx->stream_res.tg = NULL; pipe_ctx->plane_res.hubp = NULL; @@ -1486,6 +1490,7 @@ void dcn10_init_hw(struct dc *dc) struct dc_bios *dcb = dc->ctx->dc_bios; struct resource_pool *res_pool = dc->res_pool; uint32_t backlight = MAX_BACKLIGHT_LEVEL; + uint32_t user_level = MAX_BACKLIGHT_LEVEL; bool is_optimized_init_done = false; if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) @@ -1583,12 +1588,14 @@ void dcn10_init_hw(struct dc *dc) for (i = 0; i < dc->link_count; i++) { struct dc_link *link = dc->links[i]; - if (link->panel_cntl) + if (link->panel_cntl) { backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl); + user_level = link->panel_cntl->stored_backlight_registers.USER_LEVEL; + } } if (abm != NULL) - abm->funcs->abm_init(abm, backlight); + abm->funcs->abm_init(abm, backlight, user_level); if (dmcu != NULL && !dmcu->auto_load_dmcu) dmcu->funcs->dmcu_init(dmcu); @@ -2262,6 +2269,7 @@ void dcn10_enable_vblanks_synchronization( void dcn10_enable_timing_synchronization( struct dc *dc, + struct dc_state *state, int group_index, int group_size, struct pipe_ctx *grouped_pipes[]) @@ -2276,7 +2284,7 @@ void dcn10_enable_timing_synchronization( DC_SYNC_INFO("Setting up OTG reset trigger\n"); for (i = 1; i < group_size; i++) { - if (grouped_pipes[i]->stream && grouped_pipes[i]->stream->mall_stream_config.type == SUBVP_PHANTOM) + if (grouped_pipes[i]->stream && dc_state_get_pipe_subvp_type(state, grouped_pipes[i]) == SUBVP_PHANTOM) continue; opp = grouped_pipes[i]->stream_res.opp; @@ -2296,14 +2304,14 @@ void dcn10_enable_timing_synchronization( if (grouped_pipes[i]->stream == NULL) continue; - if (grouped_pipes[i]->stream && grouped_pipes[i]->stream->mall_stream_config.type == SUBVP_PHANTOM) + if (grouped_pipes[i]->stream && dc_state_get_pipe_subvp_type(state, grouped_pipes[i]) == SUBVP_PHANTOM) continue; grouped_pipes[i]->stream->vblank_synchronized = false; } for (i = 1; i < group_size; i++) { - if (grouped_pipes[i]->stream && grouped_pipes[i]->stream->mall_stream_config.type == SUBVP_PHANTOM) + if (grouped_pipes[i]->stream && dc_state_get_pipe_subvp_type(state, grouped_pipes[i]) == SUBVP_PHANTOM) continue; grouped_pipes[i]->stream_res.tg->funcs->enable_reset_trigger( @@ -2317,11 +2325,11 @@ void dcn10_enable_timing_synchronization( * synchronized. Look at last pipe programmed to reset. */ - if (grouped_pipes[1]->stream && grouped_pipes[1]->stream->mall_stream_config.type != SUBVP_PHANTOM) + if (grouped_pipes[1]->stream && dc_state_get_pipe_subvp_type(state, grouped_pipes[1]) != SUBVP_PHANTOM) wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[1]->stream_res.tg); for (i = 1; i < group_size; i++) { - if (grouped_pipes[i]->stream && grouped_pipes[i]->stream->mall_stream_config.type == SUBVP_PHANTOM) + if (grouped_pipes[i]->stream && dc_state_get_pipe_subvp_type(state, grouped_pipes[i]) == SUBVP_PHANTOM) continue; grouped_pipes[i]->stream_res.tg->funcs->disable_reset_trigger( @@ -2329,7 +2337,7 @@ void dcn10_enable_timing_synchronization( } for (i = 1; i < group_size; i++) { - if (grouped_pipes[i]->stream && grouped_pipes[i]->stream->mall_stream_config.type == SUBVP_PHANTOM) + if (dc_state_get_pipe_subvp_type(state, grouped_pipes[i]) == SUBVP_PHANTOM) continue; opp = grouped_pipes[i]->stream_res.opp; @@ -3021,7 +3029,7 @@ void dcn10_post_unlock_program_front_end( for (i = 0; i < dc->res_pool->pipe_count; i++) if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable) - dc->hwss.disable_plane(dc, &dc->current_state->res_ctx.pipe_ctx[i]); + dc->hwss.disable_plane(dc, dc->current_state, &dc->current_state->res_ctx.pipe_ctx[i]); for (i = 0; i < dc->res_pool->pipe_count; i++) if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable) { diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h index ef6d56da417cdf..bc5dd68a240880 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.h @@ -75,7 +75,7 @@ void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx); void dcn10_reset_hw_ctx_wrap( struct dc *dc, struct dc_state *context); -void dcn10_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn10_disable_plane(struct dc *dc, struct dc_state *state, struct pipe_ctx *pipe_ctx); void dcn10_lock_all_pipes( struct dc *dc, struct dc_state *context, @@ -108,13 +108,16 @@ void dcn10_power_down_on_boot(struct dc *dc); enum dc_status dce110_apply_ctx_to_hw( struct dc *dc, struct dc_state *context); -void dcn10_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn10_plane_atomic_disconnect(struct dc *dc, + struct dc_state *state, + struct pipe_ctx *pipe_ctx); void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data); void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx); void dce110_power_down(struct dc *dc); void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context); void dcn10_enable_timing_synchronization( struct dc *dc, + struct dc_state *state, int group_index, int group_size, struct pipe_ctx *grouped_pipes[]); diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_init.c new file mode 100644 index 00000000000000..a5bdac79a744eb --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_init.c @@ -0,0 +1,128 @@ +/* + * Copyright 2016-2020 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 "hw_sequencer_private.h" +#include "dce110/dce110_hwseq.h" +#include "dcn10/dcn10_hwseq.h" +#include "dcn20/dcn20_hwseq.h" + +static const struct hw_sequencer_funcs dcn10_funcs = { + .program_gamut_remap = dcn10_program_gamut_remap, + .init_hw = dcn10_init_hw, + .power_down_on_boot = dcn10_power_down_on_boot, + .apply_ctx_to_hw = dce110_apply_ctx_to_hw, + .apply_ctx_for_surface = NULL, + .program_front_end_for_ctx = dcn20_program_front_end_for_ctx, + .post_unlock_program_front_end = dcn10_post_unlock_program_front_end, + .wait_for_pending_cleared = dcn10_wait_for_pending_cleared, + .update_plane_addr = dcn10_update_plane_addr, + .update_dchub = dcn10_update_dchub, + .update_pending_status = dcn10_update_pending_status, + .program_output_csc = dcn10_program_output_csc, + .enable_accelerated_mode = dce110_enable_accelerated_mode, + .enable_timing_synchronization = dcn10_enable_timing_synchronization, + .enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset, + .update_info_frame = dce110_update_info_frame, + .send_immediate_sdp_message = dcn10_send_immediate_sdp_message, + .enable_stream = dce110_enable_stream, + .disable_stream = dce110_disable_stream, + .unblank_stream = dcn10_unblank_stream, + .blank_stream = dce110_blank_stream, + .enable_audio_stream = dce110_enable_audio_stream, + .disable_audio_stream = dce110_disable_audio_stream, + .disable_plane = dcn10_disable_plane, + .pipe_control_lock = dcn10_pipe_control_lock, + .cursor_lock = dcn10_cursor_lock, + .interdependent_update_lock = dcn10_lock_all_pipes, + .prepare_bandwidth = dcn10_prepare_bandwidth, + .optimize_bandwidth = dcn10_optimize_bandwidth, + .set_drr = dcn10_set_drr, + .get_position = dcn10_get_position, + .set_static_screen_control = dcn10_set_static_screen_control, + .setup_stereo = dcn10_setup_stereo, + .set_avmute = dce110_set_avmute, + .log_hw_state = dcn10_log_hw_state, + .get_hw_state = dcn10_get_hw_state, + .clear_status_bits = dcn10_clear_status_bits, + .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, + .edp_backlight_control = dce110_edp_backlight_control, + .edp_power_control = dce110_edp_power_control, + .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, + .set_cursor_position = dcn10_set_cursor_position, + .set_cursor_attribute = dcn10_set_cursor_attribute, + .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level, + .setup_periodic_interrupt = dcn10_setup_periodic_interrupt, + .set_clock = dcn10_set_clock, + .get_clock = dcn10_get_clock, + .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync, + .calc_vupdate_position = dcn10_calc_vupdate_position, + .power_down = dce110_power_down, + .set_backlight_level = dce110_set_backlight_level, + .set_abm_immediate_disable = dce110_set_abm_immediate_disable, + .set_pipe = dce110_set_pipe, + .enable_lvds_link_output = dce110_enable_lvds_link_output, + .enable_tmds_link_output = dce110_enable_tmds_link_output, + .enable_dp_link_output = dce110_enable_dp_link_output, + .disable_link_output = dce110_disable_link_output, + .get_dcc_en_bits = dcn10_get_dcc_en_bits, + .update_visual_confirm_color = dcn10_update_visual_confirm_color, +}; + +static const struct hwseq_private_funcs dcn10_private_funcs = { + .init_pipes = dcn10_init_pipes, + .update_plane_addr = dcn10_update_plane_addr, + .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, + .program_pipe = dcn10_program_pipe, + .update_mpcc = dcn10_update_mpcc, + .set_input_transfer_func = dcn10_set_input_transfer_func, + .set_output_transfer_func = dcn10_set_output_transfer_func, + .power_down = dce110_power_down, + .enable_display_power_gating = dcn10_dummy_display_power_gating, + .blank_pixel_data = dcn10_blank_pixel_data, + .reset_hw_ctx_wrap = dcn10_reset_hw_ctx_wrap, + .enable_stream_timing = dcn10_enable_stream_timing, + .edp_backlight_control = dce110_edp_backlight_control, + .disable_stream_gating = NULL, + .enable_stream_gating = NULL, + .setup_vupdate_interrupt = dcn10_setup_vupdate_interrupt, + .did_underflow_occur = dcn10_did_underflow_occur, + .init_blank = NULL, + .disable_vga = dcn10_disable_vga, + .bios_golden_init = dcn10_bios_golden_init, + .plane_atomic_disable = dcn10_plane_atomic_disable, + .plane_atomic_power_down = dcn10_plane_atomic_power_down, + .enable_power_gating_plane = dcn10_enable_power_gating_plane, + .dpp_pg_control = dcn10_dpp_pg_control, + .hubp_pg_control = dcn10_hubp_pg_control, + .dsc_pg_control = NULL, + .set_hdr_multiplier = dcn10_set_hdr_multiplier, + .verify_allow_pstate_change_high = dcn10_verify_allow_pstate_change_high, +}; + +void dcn10_hw_sequencer_construct(struct dc *dc) +{ + dc->hwss = dcn10_funcs; + dc->hwseq->funcs = dcn10_private_funcs; +} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_init.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_init.h new file mode 100644 index 00000000000000..8c6fd7b844a4d7 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_init.h @@ -0,0 +1,33 @@ +/* + * Copyright 2016 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_DCN10_INIT_H__ +#define __DC_DCN10_INIT_H__ + +struct dc; + +void dcn10_hw_sequencer_construct(struct dc *dc); + +#endif /* __DC_DCN10_INIT_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c index 608221b0dd5dca..e931342fcf4cf1 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c @@ -55,6 +55,7 @@ #include "inc/link_enc_cfg.h" #include "link_hwss.h" #include "link.h" +#include "dc_state_priv.h" #define DC_LOGGER \ dc_logger @@ -623,9 +624,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) +void dcn20_disable_plane(struct dc *dc, struct dc_state *state, struct pipe_ctx *pipe_ctx) { - bool is_phantom = pipe_ctx->plane_state && pipe_ctx->plane_state->is_phantom; + bool is_phantom = dc_state_get_pipe_subvp_type(state, pipe_ctx) == SUBVP_PHANTOM; struct timing_generator *tg = is_phantom ? pipe_ctx->stream_res.tg : NULL; DC_LOGGER_INIT(dc->ctx->logger); @@ -847,7 +848,7 @@ enum dc_status dcn20_enable_stream_timing( /* TODO enable stream if timing changed */ /* TODO unblank stream if DP */ - if (pipe_ctx->stream && pipe_ctx->stream->mall_stream_config.type == SUBVP_PHANTOM) { + if (pipe_ctx->stream && dc_state_get_pipe_subvp_type(context, pipe_ctx) == SUBVP_PHANTOM) { if (pipe_ctx->stream_res.tg && pipe_ctx->stream_res.tg->funcs->phantom_crtc_post_enable) pipe_ctx->stream_res.tg->funcs->phantom_crtc_post_enable(pipe_ctx->stream_res.tg); } @@ -1368,8 +1369,14 @@ void dcn20_pipe_control_lock( } } -static void dcn20_detect_pipe_changes(struct pipe_ctx *old_pipe, struct pipe_ctx *new_pipe) +static void dcn20_detect_pipe_changes(struct dc_state *old_state, + struct dc_state *new_state, + struct pipe_ctx *old_pipe, + struct pipe_ctx *new_pipe) { + bool old_is_phantom = dc_state_get_pipe_subvp_type(old_state, old_pipe) == SUBVP_PHANTOM; + bool new_is_phantom = dc_state_get_pipe_subvp_type(new_state, new_pipe) == SUBVP_PHANTOM; + new_pipe->update_flags.raw = 0; /* If non-phantom pipe is being transitioned to a phantom pipe, @@ -1379,8 +1386,8 @@ static void dcn20_detect_pipe_changes(struct pipe_ctx *old_pipe, struct pipe_ctx * be different). The post_unlock sequence will set the correct * update flags to enable the phantom pipe. */ - if (old_pipe->plane_state && !old_pipe->plane_state->is_phantom && - new_pipe->plane_state && new_pipe->plane_state->is_phantom) { + if (old_pipe->plane_state && !old_is_phantom && + new_pipe->plane_state && new_is_phantom) { new_pipe->update_flags.bits.disable = 1; return; } @@ -1400,6 +1407,10 @@ static void dcn20_detect_pipe_changes(struct pipe_ctx *old_pipe, struct pipe_ctx new_pipe->update_flags.bits.scaler = 1; new_pipe->update_flags.bits.viewport = 1; new_pipe->update_flags.bits.det_size = 1; + if (new_pipe->stream->test_pattern.type != DP_TEST_PATTERN_VIDEO_MODE && + new_pipe->stream_res.test_pattern_params.width != 0 && + new_pipe->stream_res.test_pattern_params.height != 0) + new_pipe->update_flags.bits.test_pattern_changed = 1; if (!new_pipe->top_pipe && !new_pipe->prev_odm_pipe) { new_pipe->update_flags.bits.odm = 1; new_pipe->update_flags.bits.global_sync = 1; @@ -1412,14 +1423,14 @@ static void dcn20_detect_pipe_changes(struct pipe_ctx *old_pipe, struct pipe_ctx * The remove-add sequence of the phantom pipe always results in the pipe * being blanked in enable_stream_timing (DPG). */ - if (new_pipe->stream && new_pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) + if (new_pipe->stream && dc_state_get_pipe_subvp_type(new_state, new_pipe) == SUBVP_PHANTOM) new_pipe->update_flags.bits.enable = 1; /* Phantom pipes are effectively disabled, if the pipe was previously phantom * we have to enable */ - if (old_pipe->plane_state && old_pipe->plane_state->is_phantom && - new_pipe->plane_state && !new_pipe->plane_state->is_phantom) + if (old_pipe->plane_state && old_is_phantom && + new_pipe->plane_state && !new_is_phantom) new_pipe->update_flags.bits.enable = 1; if (old_pipe->plane_state && !new_pipe->plane_state) { @@ -1556,6 +1567,7 @@ static void dcn20_update_dchubp_dpp( struct dc_plane_state *plane_state = pipe_ctx->plane_state; struct dccg *dccg = dc->res_pool->dccg; bool viewport_changed = false; + enum mall_stream_type pipe_mall_type = dc_state_get_pipe_subvp_type(context, pipe_ctx); if (pipe_ctx->update_flags.bits.dppclk) dpp->funcs->dpp_dppclk_control(dpp, false, true); @@ -1701,7 +1713,7 @@ static void dcn20_update_dchubp_dpp( pipe_ctx->update_flags.bits.plane_changed || plane_state->update_flags.bits.addr_update) { if (resource_is_pipe_type(pipe_ctx, OTG_MASTER) && - pipe_ctx->stream->mall_stream_config.type == SUBVP_MAIN) { + pipe_mall_type == SUBVP_MAIN) { union block_sequence_params params; params.subvp_save_surf_addr.dc_dmub_srv = dc->ctx->dmub_srv; @@ -1715,7 +1727,7 @@ static void dcn20_update_dchubp_dpp( if (pipe_ctx->update_flags.bits.enable) hubp->funcs->set_blank(hubp, false); /* If the stream paired with this plane is phantom, the plane is also phantom */ - if (pipe_ctx->stream && pipe_ctx->stream->mall_stream_config.type == SUBVP_PHANTOM + if (pipe_ctx->stream && pipe_mall_type == SUBVP_PHANTOM && hubp->funcs->phantom_hubp_post_enable) hubp->funcs->phantom_hubp_post_enable(hubp); } @@ -1773,7 +1785,7 @@ static void dcn20_program_pipe( pipe_ctx->pipe_dlg_param.vupdate_offset, pipe_ctx->pipe_dlg_param.vupdate_width); - if (pipe_ctx->stream->mall_stream_config.type != SUBVP_PHANTOM) + if (dc_state_get_pipe_subvp_type(context, pipe_ctx) != SUBVP_PHANTOM) pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE); pipe_ctx->stream_res.tg->funcs->set_vtg_params( @@ -1877,6 +1889,8 @@ void dcn20_program_front_end_for_ctx( int i; struct dce_hwseq *hws = dc->hwseq; DC_LOGGER_INIT(dc->ctx->logger); + unsigned int prev_hubp_count = 0; + unsigned int hubp_count = 0; if (resource_is_pipe_topology_changed(dc->current_state, context)) resource_log_pipe_topology_update(dc, context); @@ -1894,9 +1908,23 @@ void dcn20_program_front_end_for_ctx( } } + for (i = 0; i < dc->res_pool->pipe_count; i++) { + if (dc->current_state->res_ctx.pipe_ctx[i].plane_state) + prev_hubp_count++; + if (context->res_ctx.pipe_ctx[i].plane_state) + hubp_count++; + } + + if (prev_hubp_count == 0 && hubp_count > 0) { + if (dc->res_pool->hubbub->funcs->force_pstate_change_control) + dc->res_pool->hubbub->funcs->force_pstate_change_control( + dc->res_pool->hubbub, true, false); + udelay(500); + } + /* Set pipe update flags and lock pipes */ for (i = 0; i < dc->res_pool->pipe_count; i++) - dcn20_detect_pipe_changes(&dc->current_state->res_ctx.pipe_ctx[i], + dcn20_detect_pipe_changes(dc->current_state, context, &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 @@ -1906,15 +1934,16 @@ void dcn20_program_front_end_for_ctx( 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) { + dc_state_get_pipe_subvp_type(dc->current_state, &dc->current_state->res_ctx.pipe_ctx[i]) == SUBVP_PHANTOM) { struct timing_generator *tg = dc->current_state->res_ctx.pipe_ctx[i].stream_res.tg; if (tg->funcs->enable_crtc) { if (dc->hwss.blank_phantom) { int main_pipe_width, main_pipe_height; + struct dc_stream_state *phantom_stream = dc_state_get_paired_subvp_stream(dc->current_state, dc->current_state->res_ctx.pipe_ctx[i].stream); - main_pipe_width = dc->current_state->res_ctx.pipe_ctx[i].stream->mall_stream_config.paired_stream->dst.width; - main_pipe_height = dc->current_state->res_ctx.pipe_ctx[i].stream->mall_stream_config.paired_stream->dst.height; + main_pipe_width = phantom_stream->dst.width; + main_pipe_height = phantom_stream->dst.height; dc->hwss.blank_phantom(dc, tg, main_pipe_width, main_pipe_height); } tg->funcs->enable_crtc(tg); @@ -1943,9 +1972,9 @@ void dcn20_program_front_end_for_ctx( * DET allocation. */ if (hubbub->funcs->program_det_size && (context->res_ctx.pipe_ctx[i].update_flags.bits.disable || - (context->res_ctx.pipe_ctx[i].plane_state && context->res_ctx.pipe_ctx[i].plane_state->is_phantom))) + (context->res_ctx.pipe_ctx[i].plane_state && dc_state_get_pipe_subvp_type(context, &context->res_ctx.pipe_ctx[i]) == SUBVP_PHANTOM))) hubbub->funcs->program_det_size(hubbub, dc->current_state->res_ctx.pipe_ctx[i].plane_res.hubp->inst, 0); - hws->funcs.plane_atomic_disconnect(dc, &dc->current_state->res_ctx.pipe_ctx[i]); + hws->funcs.plane_atomic_disconnect(dc, dc->current_state, &dc->current_state->res_ctx.pipe_ctx[i]); DC_LOG_DC("Reset mpcc for pipe %d\n", dc->current_state->res_ctx.pipe_ctx[i].pipe_idx); } @@ -1968,7 +1997,7 @@ void dcn20_program_front_end_for_ctx( * but the MPO still exists until the double buffered update of the main pipe so we * will get a frame of underflow if the phantom pipe is programmed here. */ - if (pipe->stream && pipe->stream->mall_stream_config.type != SUBVP_PHANTOM) + if (pipe->stream && dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_PHANTOM) dcn20_program_pipe(dc, pipe, context); } @@ -2018,7 +2047,7 @@ void dcn20_post_unlock_program_front_end( for (i = 0; i < dc->res_pool->pipe_count; i++) if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable) - dc->hwss.disable_plane(dc, &dc->current_state->res_ctx.pipe_ctx[i]); + dc->hwss.disable_plane(dc, dc->current_state, &dc->current_state->res_ctx.pipe_ctx[i]); /* * If we are enabling a pipe, we need to wait for pending clear as this is a critical @@ -2030,7 +2059,7 @@ void dcn20_post_unlock_program_front_end( struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; // Don't check flip pending on phantom pipes if (pipe->plane_state && !pipe->top_pipe && pipe->update_flags.bits.enable && - pipe->stream->mall_stream_config.type != SUBVP_PHANTOM) { + dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_PHANTOM) { struct hubp *hubp = pipe->plane_res.hubp; int j = 0; for (j = 0; j < TIMEOUT_FOR_PIPE_ENABLE_US / polling_interval_us @@ -2039,6 +2068,10 @@ void dcn20_post_unlock_program_front_end( } } + if (dc->res_pool->hubbub->funcs->force_pstate_change_control) + dc->res_pool->hubbub->funcs->force_pstate_change_control( + dc->res_pool->hubbub, false, false); + for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; @@ -2049,7 +2082,7 @@ void dcn20_post_unlock_program_front_end( * programming sequence). */ while (pipe) { - if (pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) { + if (pipe->stream && dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) { /* When turning on the phantom pipe we want to run through the * entire enable sequence, so apply all the "enable" flags. */ @@ -2119,7 +2152,7 @@ void dcn20_prepare_bandwidth( struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; // At optimize don't restore the original watermark value - if (pipe->stream && pipe->stream->mall_stream_config.type != SUBVP_NONE) { + if (pipe->stream && dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_NONE) { context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = 4U * 1000U * 1000U * 1000U; break; } @@ -2163,7 +2196,7 @@ void dcn20_optimize_bandwidth( struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; // At optimize don't need to restore the original watermark value - if (pipe->stream && pipe->stream->mall_stream_config.type != SUBVP_NONE) { + if (pipe->stream && dc_state_get_pipe_subvp_type(context, pipe) != SUBVP_NONE) { context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = 4U * 1000U * 1000U * 1000U; break; } @@ -2197,7 +2230,8 @@ void dcn20_optimize_bandwidth( dc->clk_mgr, context, true); - if (context->bw_ctx.bw.dcn.clk.zstate_support == DCN_ZSTATE_SUPPORT_ALLOW) { + if (context->bw_ctx.bw.dcn.clk.zstate_support == DCN_ZSTATE_SUPPORT_ALLOW && + !dc->debug.disable_extblankadj) { for (i = 0; i < dc->res_pool->pipe_count; ++i) { struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; @@ -2590,7 +2624,8 @@ static void dcn20_reset_back_end_for_pipe( * the case where the same symclk is shared across multiple otg * instances */ - link->phy_state.symclk_ref_cnts.otg = 0; + if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal)) + link->phy_state.symclk_ref_cnts.otg = 0; if (link->phy_state.symclk_state == SYMCLK_ON_TX_OFF) { link_hwss->disable_link_output(link, &pipe_ctx->link_res, pipe_ctx->stream->signal); @@ -2923,7 +2958,7 @@ void dcn20_fpga_init_hw(struct dc *dc) dc->res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; pipe_ctx->stream_res.opp = dc->res_pool->opps[i]; /*to do*/ - hws->funcs.plane_atomic_disconnect(dc, pipe_ctx); + hws->funcs.plane_atomic_disconnect(dc, context, pipe_ctx); } /* initialize DWB pointer to MCIF_WB */ @@ -2940,7 +2975,7 @@ void dcn20_fpga_init_hw(struct dc *dc) for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - dc->hwss.disable_plane(dc, pipe_ctx); + dc->hwss.disable_plane(dc, context, pipe_ctx); pipe_ctx->stream_res.tg = NULL; pipe_ctx->plane_res.hubp = NULL; diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.h index ab02e4e9c8c292..b94c85340abff7 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.h @@ -52,7 +52,7 @@ void dcn20_program_output_csc(struct dc *dc, void dcn20_enable_stream(struct pipe_ctx *pipe_ctx); void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx, struct dc_link_settings *link_settings); -void dcn20_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn20_disable_plane(struct dc *dc, struct dc_state *state, struct pipe_ctx *pipe_ctx); void dcn20_disable_pixel_data( struct dc *dc, struct pipe_ctx *pipe_ctx, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_init.c new file mode 100644 index 00000000000000..884e3e32333808 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_init.c @@ -0,0 +1,145 @@ +/* + * Copyright 2016 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 "dce110/dce110_hwseq.h" +#include "dcn10/dcn10_hwseq.h" +#include "dcn20/dcn20_hwseq.h" + +#include "dcn20_init.h" + +static const struct hw_sequencer_funcs dcn20_funcs = { + .program_gamut_remap = dcn10_program_gamut_remap, + .init_hw = dcn10_init_hw, + .power_down_on_boot = dcn10_power_down_on_boot, + .apply_ctx_to_hw = dce110_apply_ctx_to_hw, + .apply_ctx_for_surface = NULL, + .program_front_end_for_ctx = dcn20_program_front_end_for_ctx, + .wait_for_pending_cleared = dcn10_wait_for_pending_cleared, + .post_unlock_program_front_end = dcn20_post_unlock_program_front_end, + .update_plane_addr = dcn20_update_plane_addr, + .update_dchub = dcn10_update_dchub, + .update_pending_status = dcn10_update_pending_status, + .program_output_csc = dcn20_program_output_csc, + .enable_accelerated_mode = dce110_enable_accelerated_mode, + .enable_timing_synchronization = dcn10_enable_timing_synchronization, + .enable_vblanks_synchronization = dcn10_enable_vblanks_synchronization, + .enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset, + .update_info_frame = dce110_update_info_frame, + .send_immediate_sdp_message = dcn10_send_immediate_sdp_message, + .enable_stream = dcn20_enable_stream, + .disable_stream = dce110_disable_stream, + .unblank_stream = dcn20_unblank_stream, + .blank_stream = dce110_blank_stream, + .enable_audio_stream = dce110_enable_audio_stream, + .disable_audio_stream = dce110_disable_audio_stream, + .disable_plane = dcn20_disable_plane, + .pipe_control_lock = dcn20_pipe_control_lock, + .interdependent_update_lock = dcn10_lock_all_pipes, + .cursor_lock = dcn10_cursor_lock, + .prepare_bandwidth = dcn20_prepare_bandwidth, + .optimize_bandwidth = dcn20_optimize_bandwidth, + .update_bandwidth = dcn20_update_bandwidth, + .set_drr = dcn10_set_drr, + .get_position = dcn10_get_position, + .set_static_screen_control = dcn10_set_static_screen_control, + .setup_stereo = dcn10_setup_stereo, + .set_avmute = dce110_set_avmute, + .log_hw_state = dcn10_log_hw_state, + .get_hw_state = dcn10_get_hw_state, + .clear_status_bits = dcn10_clear_status_bits, + .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, + .edp_backlight_control = dce110_edp_backlight_control, + .edp_power_control = dce110_edp_power_control, + .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, + .set_cursor_position = dcn10_set_cursor_position, + .set_cursor_attribute = dcn10_set_cursor_attribute, + .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level, + .setup_periodic_interrupt = dcn10_setup_periodic_interrupt, + .set_clock = dcn10_set_clock, + .get_clock = dcn10_get_clock, + .program_triplebuffer = dcn20_program_triple_buffer, + .enable_writeback = dcn20_enable_writeback, + .disable_writeback = dcn20_disable_writeback, + .dmdata_status_done = dcn20_dmdata_status_done, + .program_dmdata_engine = dcn20_program_dmdata_engine, + .set_dmdata_attributes = dcn20_set_dmdata_attributes, + .init_sys_ctx = dcn20_init_sys_ctx, + .init_vm_ctx = dcn20_init_vm_ctx, + .set_flip_control_gsl = dcn20_set_flip_control_gsl, + .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync, + .calc_vupdate_position = dcn10_calc_vupdate_position, + .set_backlight_level = dce110_set_backlight_level, + .set_abm_immediate_disable = dce110_set_abm_immediate_disable, + .set_pipe = dce110_set_pipe, + .enable_lvds_link_output = dce110_enable_lvds_link_output, + .enable_tmds_link_output = dce110_enable_tmds_link_output, + .enable_dp_link_output = dce110_enable_dp_link_output, + .disable_link_output = dce110_disable_link_output, + .set_disp_pattern_generator = dcn20_set_disp_pattern_generator, + .get_dcc_en_bits = dcn10_get_dcc_en_bits, + .update_visual_confirm_color = dcn10_update_visual_confirm_color, +}; + +static const struct hwseq_private_funcs dcn20_private_funcs = { + .init_pipes = dcn10_init_pipes, + .update_plane_addr = dcn20_update_plane_addr, + .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, + .update_mpcc = dcn20_update_mpcc, + .set_input_transfer_func = dcn20_set_input_transfer_func, + .set_output_transfer_func = dcn20_set_output_transfer_func, + .power_down = dce110_power_down, + .enable_display_power_gating = dcn10_dummy_display_power_gating, + .blank_pixel_data = dcn20_blank_pixel_data, + .reset_hw_ctx_wrap = dcn20_reset_hw_ctx_wrap, + .enable_stream_timing = dcn20_enable_stream_timing, + .edp_backlight_control = dce110_edp_backlight_control, + .disable_stream_gating = dcn20_disable_stream_gating, + .enable_stream_gating = dcn20_enable_stream_gating, + .setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt, + .did_underflow_occur = dcn10_did_underflow_occur, + .init_blank = dcn20_init_blank, + .disable_vga = dcn20_disable_vga, + .bios_golden_init = dcn10_bios_golden_init, + .plane_atomic_disable = dcn20_plane_atomic_disable, + .plane_atomic_power_down = dcn10_plane_atomic_power_down, + .enable_power_gating_plane = dcn20_enable_power_gating_plane, + .dpp_pg_control = dcn20_dpp_pg_control, + .hubp_pg_control = dcn20_hubp_pg_control, + .update_odm = dcn20_update_odm, + .dsc_pg_control = dcn20_dsc_pg_control, + .set_hdr_multiplier = dcn10_set_hdr_multiplier, + .verify_allow_pstate_change_high = dcn10_verify_allow_pstate_change_high, + .wait_for_blank_complete = dcn20_wait_for_blank_complete, + .dccg_init = dcn20_dccg_init, + .set_blend_lut = dcn20_set_blend_lut, + .set_shaper_3dlut = dcn20_set_shaper_3dlut, +}; + +void dcn20_hw_sequencer_construct(struct dc *dc) +{ + dc->hwss = dcn20_funcs; + dc->hwseq->funcs = dcn20_private_funcs; + +} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_init.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_init.h new file mode 100644 index 00000000000000..12277797cd7106 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_init.h @@ -0,0 +1,33 @@ +/* + * Copyright 2016 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_DCN20_INIT_H__ +#define __DC_DCN20_INIT_H__ + +struct dc; + +void dcn20_hw_sequencer_construct(struct dc *dc); + +#endif /* __DC_DCN20_INIT_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.c index d3fe6092f50e8f..d5769f38874fd4 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.c @@ -320,7 +320,7 @@ void dcn201_init_hw(struct dc *dc) res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; pipe_ctx->stream_res.opp = res_pool->opps[i]; /*To do: number of MPCC != number of opp*/ - hws->funcs.plane_atomic_disconnect(dc, pipe_ctx); + hws->funcs.plane_atomic_disconnect(dc, context, pipe_ctx); } /* initialize DWB pointer to MCIF_WB */ @@ -337,7 +337,7 @@ void dcn201_init_hw(struct dc *dc) for (i = 0; i < res_pool->pipe_count; i++) { struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - dc->hwss.disable_plane(dc, pipe_ctx); + dc->hwss.disable_plane(dc, context, pipe_ctx); pipe_ctx->stream_res.tg = NULL; pipe_ctx->plane_res.hubp = NULL; @@ -369,7 +369,9 @@ void dcn201_init_hw(struct dc *dc) } /* trigger HW to start disconnect plane from stream on the next vsync */ -void dcn201_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx) +void dcn201_plane_atomic_disconnect(struct dc *dc, + struct dc_state *state, + struct pipe_ctx *pipe_ctx) { struct dce_hwseq *hws = dc->hwseq; struct hubp *hubp = pipe_ctx->plane_res.hubp; diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.h index 26cd62be64181e..6a50a9894be6ae 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.h @@ -33,7 +33,7 @@ void dcn201_init_hw(struct dc *dc); void dcn201_unblank_stream(struct pipe_ctx *pipe_ctx, struct dc_link_settings *link_settings); void dcn201_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx); -void dcn201_plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn201_plane_atomic_disconnect(struct dc *dc, struct dc_state *state, struct pipe_ctx *pipe_ctx); void dcn201_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx); void dcn201_set_cursor_attribute(struct pipe_ctx *pipe_ctx); void dcn201_pipe_control_lock( diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_init.c new file mode 100644 index 00000000000000..a13bf6c9386e0a --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_init.c @@ -0,0 +1,136 @@ +/* + * Copyright 2016 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 "dce110/dce110_hwseq.h" +#include "dcn10/dcn10_hwseq.h" +#include "dcn20/dcn20_hwseq.h" +#include "dcn201/dcn201_hwseq.h" +#include "dcn201_init.h" + +static const struct hw_sequencer_funcs dcn201_funcs = { + .program_gamut_remap = dcn10_program_gamut_remap, + .init_hw = dcn201_init_hw, + .power_down_on_boot = NULL, + .apply_ctx_to_hw = dce110_apply_ctx_to_hw, + .apply_ctx_for_surface = NULL, + .program_front_end_for_ctx = dcn20_program_front_end_for_ctx, + .wait_for_pending_cleared = dcn10_wait_for_pending_cleared, + .post_unlock_program_front_end = dcn10_post_unlock_program_front_end, + .update_plane_addr = dcn201_update_plane_addr, + .update_dchub = dcn10_update_dchub, + .update_pending_status = dcn10_update_pending_status, + .program_output_csc = dcn20_program_output_csc, + .enable_accelerated_mode = dce110_enable_accelerated_mode, + .enable_timing_synchronization = dcn10_enable_timing_synchronization, + .enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset, + .update_info_frame = dce110_update_info_frame, + .send_immediate_sdp_message = dcn10_send_immediate_sdp_message, + .enable_stream = dce110_enable_stream, + .disable_stream = dce110_disable_stream, + .unblank_stream = dcn201_unblank_stream, + .blank_stream = dce110_blank_stream, + .enable_audio_stream = dce110_enable_audio_stream, + .disable_audio_stream = dce110_disable_audio_stream, + .disable_plane = dcn10_disable_plane, + .pipe_control_lock = dcn201_pipe_control_lock, + .interdependent_update_lock = dcn10_lock_all_pipes, + .cursor_lock = dcn10_cursor_lock, + .prepare_bandwidth = dcn20_prepare_bandwidth, + .optimize_bandwidth = dcn20_optimize_bandwidth, + .update_bandwidth = dcn20_update_bandwidth, + .set_drr = dcn10_set_drr, + .get_position = dcn10_get_position, + .set_static_screen_control = dcn10_set_static_screen_control, + .setup_stereo = dcn10_setup_stereo, + .set_avmute = dce110_set_avmute, + .log_hw_state = dcn10_log_hw_state, + .get_hw_state = dcn10_get_hw_state, + .clear_status_bits = dcn10_clear_status_bits, + .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, + .edp_backlight_control = dce110_edp_backlight_control, + .edp_power_control = dce110_edp_power_control, + .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, + .setup_periodic_interrupt = dcn10_setup_periodic_interrupt, + .set_clock = dcn10_set_clock, + .get_clock = dcn10_get_clock, + .program_triplebuffer = dcn20_program_triple_buffer, + .dmdata_status_done = dcn20_dmdata_status_done, + .set_dmdata_attributes = dcn201_set_dmdata_attributes, + .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync, + .calc_vupdate_position = dcn10_calc_vupdate_position, + .set_cursor_position = dcn10_set_cursor_position, + .set_cursor_attribute = dcn201_set_cursor_attribute, + .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level, + .set_backlight_level = dce110_set_backlight_level, + .set_abm_immediate_disable = dce110_set_abm_immediate_disable, + .set_pipe = dce110_set_pipe, + .enable_lvds_link_output = dce110_enable_lvds_link_output, + .enable_tmds_link_output = dce110_enable_tmds_link_output, + .enable_dp_link_output = dce110_enable_dp_link_output, + .disable_link_output = dce110_disable_link_output, + .set_disp_pattern_generator = dcn20_set_disp_pattern_generator, + .update_visual_confirm_color = dcn10_update_visual_confirm_color, +}; + +static const struct hwseq_private_funcs dcn201_private_funcs = { + .init_pipes = NULL, + .update_plane_addr = dcn201_update_plane_addr, + .plane_atomic_disconnect = dcn201_plane_atomic_disconnect, + .program_pipe = dcn10_program_pipe, + .update_mpcc = dcn201_update_mpcc, + .set_input_transfer_func = dcn20_set_input_transfer_func, + .set_output_transfer_func = dcn20_set_output_transfer_func, + .power_down = dce110_power_down, + .enable_display_power_gating = dcn10_dummy_display_power_gating, + .blank_pixel_data = dcn20_blank_pixel_data, + .reset_hw_ctx_wrap = dcn10_reset_hw_ctx_wrap, + .enable_stream_timing = dcn20_enable_stream_timing, + .edp_backlight_control = dce110_edp_backlight_control, + .disable_stream_gating = NULL, + .enable_stream_gating = NULL, + .setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt, + .did_underflow_occur = dcn10_did_underflow_occur, + .init_blank = dcn201_init_blank, + .disable_vga = dcn10_disable_vga, + .bios_golden_init = dcn10_bios_golden_init, + .plane_atomic_disable = dcn10_plane_atomic_disable, + .plane_atomic_power_down = dcn10_plane_atomic_power_down, + .enable_power_gating_plane = dcn10_enable_power_gating_plane, + .dpp_pg_control = dcn10_dpp_pg_control, + .hubp_pg_control = dcn10_hubp_pg_control, + .dsc_pg_control = NULL, + .set_hdr_multiplier = dcn10_set_hdr_multiplier, + .verify_allow_pstate_change_high = dcn10_verify_allow_pstate_change_high, + .wait_for_blank_complete = dcn20_wait_for_blank_complete, + .dccg_init = dcn20_dccg_init, + .set_blend_lut = dcn20_set_blend_lut, + .set_shaper_3dlut = dcn20_set_shaper_3dlut, +}; + +void dcn201_hw_sequencer_construct(struct dc *dc) +{ + dc->hwss = dcn201_funcs; + dc->hwseq->funcs = dcn201_private_funcs; +} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_init.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_init.h new file mode 100644 index 00000000000000..1168887b033dee --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_init.h @@ -0,0 +1,33 @@ +/* + * Copyright 2016 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_DCN201_INIT_H__ +#define __DC_DCN201_INIT_H__ + +struct dc; + +void dcn201_hw_sequencer_construct(struct dc *dc); + +#endif /* __DC_DCN201_INIT_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c index 467812cf33686e..8e88dcaf88f5b2 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_hwseq.c @@ -137,7 +137,8 @@ void dcn21_PLAT_58856_wa(struct dc_state *context, struct pipe_ctx *pipe_ctx) pipe_ctx->stream->dpms_off = true; } -static bool dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, uint32_t option, uint32_t panel_inst) +static bool dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, + uint32_t option, uint32_t panel_inst, uint32_t pwrseq_inst) { union dmub_rb_cmd cmd; struct dc_context *dc = abm->ctx; @@ -147,12 +148,13 @@ static bool dmub_abm_set_pipe(struct abm *abm, uint32_t otg_inst, uint32_t optio cmd.abm_set_pipe.header.type = DMUB_CMD__ABM; cmd.abm_set_pipe.header.sub_type = DMUB_CMD__ABM_SET_PIPE; cmd.abm_set_pipe.abm_set_pipe_data.otg_inst = otg_inst; + cmd.abm_set_pipe.abm_set_pipe_data.pwrseq_inst = pwrseq_inst; cmd.abm_set_pipe.abm_set_pipe_data.set_pipe_option = option; cmd.abm_set_pipe.abm_set_pipe_data.panel_inst = panel_inst; cmd.abm_set_pipe.abm_set_pipe_data.ramping_boundary = ramping_boundary; cmd.abm_set_pipe.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_pipe_data); - dm_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); return true; } @@ -171,7 +173,7 @@ static void dmub_abm_set_backlight(struct dc_context *dc, uint32_t backlight_pwm cmd.abm_set_backlight.abm_set_backlight_data.panel_mask = (0x01 << panel_inst); cmd.abm_set_backlight.header.payload_bytes = sizeof(struct dmub_cmd_abm_set_backlight_data); - dm_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dc, &cmd, DM_DMUB_WAIT_TYPE_WAIT); } void dcn21_set_abm_immediate_disable(struct pipe_ctx *pipe_ctx) @@ -179,7 +181,6 @@ void dcn21_set_abm_immediate_disable(struct pipe_ctx *pipe_ctx) struct abm *abm = pipe_ctx->stream_res.abm; uint32_t otg_inst = pipe_ctx->stream_res.tg->inst; struct panel_cntl *panel_cntl = pipe_ctx->stream->link->panel_cntl; - struct dmcu *dmcu = pipe_ctx->stream->ctx->dc->res_pool->dmcu; if (dmcu) { @@ -190,9 +191,13 @@ void dcn21_set_abm_immediate_disable(struct pipe_ctx *pipe_ctx) if (abm && panel_cntl) { if (abm->funcs && abm->funcs->set_pipe_ex) { abm->funcs->set_pipe_ex(abm, otg_inst, SET_ABM_PIPE_IMMEDIATELY_DISABLE, - panel_cntl->inst); + panel_cntl->inst, panel_cntl->pwrseq_inst); } else { - dmub_abm_set_pipe(abm, otg_inst, SET_ABM_PIPE_IMMEDIATELY_DISABLE, panel_cntl->inst); + dmub_abm_set_pipe(abm, + otg_inst, + SET_ABM_PIPE_IMMEDIATELY_DISABLE, + panel_cntl->inst, + panel_cntl->pwrseq_inst); } panel_cntl->funcs->store_backlight_level(panel_cntl); } @@ -212,9 +217,16 @@ void dcn21_set_pipe(struct pipe_ctx *pipe_ctx) if (abm && panel_cntl) { if (abm->funcs && abm->funcs->set_pipe_ex) { - abm->funcs->set_pipe_ex(abm, otg_inst, SET_ABM_PIPE_NORMAL, panel_cntl->inst); + abm->funcs->set_pipe_ex(abm, + otg_inst, + SET_ABM_PIPE_NORMAL, + panel_cntl->inst, + panel_cntl->pwrseq_inst); } else { - dmub_abm_set_pipe(abm, otg_inst, SET_ABM_PIPE_NORMAL, panel_cntl->inst); + dmub_abm_set_pipe(abm, otg_inst, + SET_ABM_PIPE_NORMAL, + panel_cntl->inst, + panel_cntl->pwrseq_inst); } } } @@ -237,9 +249,17 @@ bool dcn21_set_backlight_level(struct pipe_ctx *pipe_ctx, if (abm && panel_cntl) { if (abm->funcs && abm->funcs->set_pipe_ex) { - abm->funcs->set_pipe_ex(abm, otg_inst, SET_ABM_PIPE_NORMAL, panel_cntl->inst); + abm->funcs->set_pipe_ex(abm, + otg_inst, + SET_ABM_PIPE_NORMAL, + panel_cntl->inst, + panel_cntl->pwrseq_inst); } else { - dmub_abm_set_pipe(abm, otg_inst, SET_ABM_PIPE_NORMAL, panel_cntl->inst); + dmub_abm_set_pipe(abm, + otg_inst, + SET_ABM_PIPE_NORMAL, + panel_cntl->inst, + panel_cntl->pwrseq_inst); } } } diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_init.c new file mode 100644 index 00000000000000..18249c6b6d81c5 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_init.c @@ -0,0 +1,151 @@ +/* + * Copyright 2016-2020 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 "dce110/dce110_hwseq.h" +#include "dcn10/dcn10_hwseq.h" +#include "dcn20/dcn20_hwseq.h" +#include "dcn21/dcn21_hwseq.h" + +#include "dcn21_init.h" + +static const struct hw_sequencer_funcs dcn21_funcs = { + .program_gamut_remap = dcn10_program_gamut_remap, + .init_hw = dcn10_init_hw, + .power_down_on_boot = dcn10_power_down_on_boot, + .apply_ctx_to_hw = dce110_apply_ctx_to_hw, + .apply_ctx_for_surface = NULL, + .program_front_end_for_ctx = dcn20_program_front_end_for_ctx, + .wait_for_pending_cleared = dcn10_wait_for_pending_cleared, + .post_unlock_program_front_end = dcn20_post_unlock_program_front_end, + .update_plane_addr = dcn20_update_plane_addr, + .update_dchub = dcn10_update_dchub, + .update_pending_status = dcn10_update_pending_status, + .program_output_csc = dcn20_program_output_csc, + .enable_accelerated_mode = dce110_enable_accelerated_mode, + .enable_timing_synchronization = dcn10_enable_timing_synchronization, + .enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset, + .update_info_frame = dce110_update_info_frame, + .send_immediate_sdp_message = dcn10_send_immediate_sdp_message, + .enable_stream = dcn20_enable_stream, + .disable_stream = dce110_disable_stream, + .unblank_stream = dcn20_unblank_stream, + .blank_stream = dce110_blank_stream, + .enable_audio_stream = dce110_enable_audio_stream, + .disable_audio_stream = dce110_disable_audio_stream, + .disable_plane = dcn20_disable_plane, + .pipe_control_lock = dcn20_pipe_control_lock, + .interdependent_update_lock = dcn10_lock_all_pipes, + .cursor_lock = dcn10_cursor_lock, + .prepare_bandwidth = dcn20_prepare_bandwidth, + .optimize_bandwidth = dcn20_optimize_bandwidth, + .update_bandwidth = dcn20_update_bandwidth, + .set_drr = dcn10_set_drr, + .get_position = dcn10_get_position, + .set_static_screen_control = dcn10_set_static_screen_control, + .setup_stereo = dcn10_setup_stereo, + .set_avmute = dce110_set_avmute, + .log_hw_state = dcn10_log_hw_state, + .get_hw_state = dcn10_get_hw_state, + .clear_status_bits = dcn10_clear_status_bits, + .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, + .edp_backlight_control = dce110_edp_backlight_control, + .edp_power_control = dce110_edp_power_control, + .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, + .set_cursor_position = dcn10_set_cursor_position, + .set_cursor_attribute = dcn10_set_cursor_attribute, + .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level, + .setup_periodic_interrupt = dcn10_setup_periodic_interrupt, + .set_clock = dcn10_set_clock, + .get_clock = dcn10_get_clock, + .program_triplebuffer = dcn20_program_triple_buffer, + .enable_writeback = dcn20_enable_writeback, + .disable_writeback = dcn20_disable_writeback, + .dmdata_status_done = dcn20_dmdata_status_done, + .program_dmdata_engine = dcn20_program_dmdata_engine, + .set_dmdata_attributes = dcn20_set_dmdata_attributes, + .init_sys_ctx = dcn21_init_sys_ctx, + .init_vm_ctx = dcn20_init_vm_ctx, + .set_flip_control_gsl = dcn20_set_flip_control_gsl, + .optimize_pwr_state = dcn21_optimize_pwr_state, + .exit_optimized_pwr_state = dcn21_exit_optimized_pwr_state, + .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync, + .calc_vupdate_position = dcn10_calc_vupdate_position, + .power_down = dce110_power_down, + .set_backlight_level = dcn21_set_backlight_level, + .set_abm_immediate_disable = dcn21_set_abm_immediate_disable, + .set_pipe = dcn21_set_pipe, + .enable_lvds_link_output = dce110_enable_lvds_link_output, + .enable_tmds_link_output = dce110_enable_tmds_link_output, + .enable_dp_link_output = dce110_enable_dp_link_output, + .disable_link_output = dce110_disable_link_output, + .is_abm_supported = dcn21_is_abm_supported, + .set_disp_pattern_generator = dcn20_set_disp_pattern_generator, + .get_dcc_en_bits = dcn10_get_dcc_en_bits, + .update_visual_confirm_color = dcn10_update_visual_confirm_color, +}; + +static const struct hwseq_private_funcs dcn21_private_funcs = { + .init_pipes = dcn10_init_pipes, + .update_plane_addr = dcn20_update_plane_addr, + .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, + .update_mpcc = dcn20_update_mpcc, + .set_input_transfer_func = dcn20_set_input_transfer_func, + .set_output_transfer_func = dcn20_set_output_transfer_func, + .power_down = dce110_power_down, + .enable_display_power_gating = dcn10_dummy_display_power_gating, + .blank_pixel_data = dcn20_blank_pixel_data, + .reset_hw_ctx_wrap = dcn20_reset_hw_ctx_wrap, + .enable_stream_timing = dcn20_enable_stream_timing, + .edp_backlight_control = dce110_edp_backlight_control, + .disable_stream_gating = dcn20_disable_stream_gating, + .enable_stream_gating = dcn20_enable_stream_gating, + .setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt, + .did_underflow_occur = dcn10_did_underflow_occur, + .init_blank = dcn20_init_blank, + .disable_vga = dcn20_disable_vga, + .bios_golden_init = dcn10_bios_golden_init, + .plane_atomic_disable = dcn20_plane_atomic_disable, + .plane_atomic_power_down = dcn10_plane_atomic_power_down, + .enable_power_gating_plane = dcn20_enable_power_gating_plane, + .dpp_pg_control = dcn20_dpp_pg_control, + .hubp_pg_control = dcn20_hubp_pg_control, + .update_odm = dcn20_update_odm, + .dsc_pg_control = dcn20_dsc_pg_control, + .set_hdr_multiplier = dcn10_set_hdr_multiplier, + .verify_allow_pstate_change_high = dcn10_verify_allow_pstate_change_high, + .s0i3_golden_init_wa = dcn21_s0i3_golden_init_wa, + .wait_for_blank_complete = dcn20_wait_for_blank_complete, + .dccg_init = dcn20_dccg_init, + .set_blend_lut = dcn20_set_blend_lut, + .set_shaper_3dlut = dcn20_set_shaper_3dlut, + .PLAT_58856_wa = dcn21_PLAT_58856_wa, +}; + +void dcn21_hw_sequencer_construct(struct dc *dc) +{ + dc->hwss = dcn21_funcs; + dc->hwseq->funcs = dcn21_private_funcs; + +} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_init.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_init.h new file mode 100644 index 00000000000000..3ed24292648a4f --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn21/dcn21_init.h @@ -0,0 +1,33 @@ +/* + * Copyright 2016 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_DCN21_INIT_H__ +#define __DC_DCN21_INIT_H__ + +struct dc; + +void dcn21_hw_sequencer_construct(struct dc *dc); + +#endif /* __DC_DCN20_INIT_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c index d71faf2ecd413c..c34c13e1e0a4ea 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c @@ -51,7 +51,7 @@ #include "dcn20/dcn20_hwseq.h" #include "dcn30/dcn30_resource.h" #include "link.h" - +#include "dc_state_priv.h" @@ -367,6 +367,10 @@ void dcn30_enable_writeback( DC_LOG_DWB("%s dwb_pipe_inst = %d, mpcc_inst = %d",\ __func__, wb_info->dwb_pipe_inst,\ wb_info->mpcc_inst); + + /* Warmup interface */ + dcn30_mmhubbub_warmup(dc, 1, wb_info); + /* Update writeback pipe */ dcn30_set_writeback(dc, wb_info, context); @@ -472,6 +476,7 @@ void dcn30_init_hw(struct dc *dc) int i; int edp_num; uint32_t backlight = MAX_BACKLIGHT_LEVEL; + uint32_t user_level = MAX_BACKLIGHT_LEVEL; if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); @@ -608,13 +613,15 @@ void dcn30_init_hw(struct dc *dc) for (i = 0; i < dc->link_count; i++) { struct dc_link *link = dc->links[i]; - if (link->panel_cntl) + if (link->panel_cntl) { backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl); + user_level = link->panel_cntl->stored_backlight_registers.USER_LEVEL; + } } for (i = 0; i < dc->res_pool->pipe_count; i++) { if (abms[i] != NULL) - abms[i]->funcs->abm_init(abms[i], backlight); + abms[i]->funcs->abm_init(abms[i], backlight, user_level); } /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ @@ -750,7 +757,7 @@ bool dcn30_apply_idle_power_optimizations(struct dc *dc, bool enable) cmd.mall.header.sub_type = DMUB_CMD__MALL_ACTION_NO_DF_REQ; cmd.mall.header.payload_bytes = sizeof(cmd.mall) - sizeof(cmd.mall.header); - dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT); + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT); return true; } @@ -872,7 +879,7 @@ bool dcn30_apply_idle_power_optimizations(struct dc *dc, bool enable) cmd.mall.cursor_height = cursor_attr.height; cmd.mall.cursor_pitch = cursor_attr.pitch; - dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); /* Use copied cursor, and it's okay to not switch back */ cursor_attr.address.quad_part = cmd.mall.cursor_copy_dst.quad_part; @@ -888,7 +895,7 @@ bool dcn30_apply_idle_power_optimizations(struct dc *dc, bool enable) cmd.mall.tmr_scale = tmr_scale; cmd.mall.debug_bits = dc->debug.mall_error_as_fatal; - dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT); + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT); return true; } @@ -905,7 +912,7 @@ bool dcn30_apply_idle_power_optimizations(struct dc *dc, bool enable) cmd.mall.header.payload_bytes = sizeof(cmd.mall) - sizeof(cmd.mall.header); - dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); return true; } @@ -962,7 +969,7 @@ void dcn30_hardware_release(struct dc *dc) if (!pipe->stream) continue; - if (pipe->stream->mall_stream_config.type == SUBVP_MAIN) { + if (dc_state_get_pipe_subvp_type(dc->current_state, pipe) == SUBVP_MAIN) { subvp_in_use = true; break; } diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c new file mode 100644 index 00000000000000..9894caedffed73 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.c @@ -0,0 +1,154 @@ +/* + * Copyright 2016-2020 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 "dce110/dce110_hwseq.h" +#include "dcn10/dcn10_hwseq.h" +#include "dcn20/dcn20_hwseq.h" +#include "dcn21/dcn21_hwseq.h" +#include "dcn30/dcn30_hwseq.h" + +#include "dcn30_init.h" + +static const struct hw_sequencer_funcs dcn30_funcs = { + .program_gamut_remap = dcn30_program_gamut_remap, + .init_hw = dcn30_init_hw, + .apply_ctx_to_hw = dce110_apply_ctx_to_hw, + .apply_ctx_for_surface = NULL, + .program_front_end_for_ctx = dcn20_program_front_end_for_ctx, + .wait_for_pending_cleared = dcn10_wait_for_pending_cleared, + .post_unlock_program_front_end = dcn20_post_unlock_program_front_end, + .update_plane_addr = dcn20_update_plane_addr, + .update_dchub = dcn10_update_dchub, + .update_pending_status = dcn10_update_pending_status, + .program_output_csc = dcn20_program_output_csc, + .enable_accelerated_mode = dce110_enable_accelerated_mode, + .enable_timing_synchronization = dcn10_enable_timing_synchronization, + .enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset, + .update_info_frame = dcn30_update_info_frame, + .send_immediate_sdp_message = dcn10_send_immediate_sdp_message, + .enable_stream = dcn20_enable_stream, + .disable_stream = dce110_disable_stream, + .unblank_stream = dcn20_unblank_stream, + .blank_stream = dce110_blank_stream, + .enable_audio_stream = dce110_enable_audio_stream, + .disable_audio_stream = dce110_disable_audio_stream, + .disable_plane = dcn20_disable_plane, + .disable_pixel_data = dcn20_disable_pixel_data, + .pipe_control_lock = dcn20_pipe_control_lock, + .interdependent_update_lock = dcn10_lock_all_pipes, + .cursor_lock = dcn10_cursor_lock, + .prepare_bandwidth = dcn30_prepare_bandwidth, + .optimize_bandwidth = dcn20_optimize_bandwidth, + .update_bandwidth = dcn20_update_bandwidth, + .set_drr = dcn10_set_drr, + .get_position = dcn10_get_position, + .set_static_screen_control = dcn30_set_static_screen_control, + .setup_stereo = dcn10_setup_stereo, + .set_avmute = dcn30_set_avmute, + .log_hw_state = dcn10_log_hw_state, + .get_hw_state = dcn10_get_hw_state, + .clear_status_bits = dcn10_clear_status_bits, + .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, + .edp_backlight_control = dce110_edp_backlight_control, + .edp_power_control = dce110_edp_power_control, + .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, + .edp_wait_for_T12 = dce110_edp_wait_for_T12, + .set_cursor_position = dcn10_set_cursor_position, + .set_cursor_attribute = dcn10_set_cursor_attribute, + .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level, + .setup_periodic_interrupt = dcn10_setup_periodic_interrupt, + .set_clock = dcn10_set_clock, + .get_clock = dcn10_get_clock, + .program_triplebuffer = dcn20_program_triple_buffer, + .enable_writeback = dcn30_enable_writeback, + .disable_writeback = dcn30_disable_writeback, + .update_writeback = dcn30_update_writeback, + .mmhubbub_warmup = dcn30_mmhubbub_warmup, + .dmdata_status_done = dcn20_dmdata_status_done, + .program_dmdata_engine = dcn30_program_dmdata_engine, + .set_dmdata_attributes = dcn20_set_dmdata_attributes, + .init_sys_ctx = dcn20_init_sys_ctx, + .init_vm_ctx = dcn20_init_vm_ctx, + .set_flip_control_gsl = dcn20_set_flip_control_gsl, + .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync, + .calc_vupdate_position = dcn10_calc_vupdate_position, + .apply_idle_power_optimizations = dcn30_apply_idle_power_optimizations, + .does_plane_fit_in_mall = dcn30_does_plane_fit_in_mall, + .set_backlight_level = dcn21_set_backlight_level, + .set_abm_immediate_disable = dcn21_set_abm_immediate_disable, + .hardware_release = dcn30_hardware_release, + .set_pipe = dcn21_set_pipe, + .enable_lvds_link_output = dce110_enable_lvds_link_output, + .enable_tmds_link_output = dce110_enable_tmds_link_output, + .enable_dp_link_output = dce110_enable_dp_link_output, + .disable_link_output = dce110_disable_link_output, + .set_disp_pattern_generator = dcn30_set_disp_pattern_generator, + .get_dcc_en_bits = dcn10_get_dcc_en_bits, + .update_visual_confirm_color = dcn10_update_visual_confirm_color, + .is_abm_supported = dcn21_is_abm_supported +}; + +static const struct hwseq_private_funcs dcn30_private_funcs = { + .init_pipes = dcn10_init_pipes, + .update_plane_addr = dcn20_update_plane_addr, + .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, + .update_mpcc = dcn20_update_mpcc, + .set_input_transfer_func = dcn30_set_input_transfer_func, + .set_output_transfer_func = dcn30_set_output_transfer_func, + .power_down = dce110_power_down, + .enable_display_power_gating = dcn10_dummy_display_power_gating, + .blank_pixel_data = dcn20_blank_pixel_data, + .reset_hw_ctx_wrap = dcn20_reset_hw_ctx_wrap, + .enable_stream_timing = dcn20_enable_stream_timing, + .edp_backlight_control = dce110_edp_backlight_control, + .disable_stream_gating = dcn20_disable_stream_gating, + .enable_stream_gating = dcn20_enable_stream_gating, + .setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt, + .did_underflow_occur = dcn10_did_underflow_occur, + .init_blank = dcn20_init_blank, + .disable_vga = dcn20_disable_vga, + .bios_golden_init = dcn10_bios_golden_init, + .plane_atomic_disable = dcn20_plane_atomic_disable, + .plane_atomic_power_down = dcn10_plane_atomic_power_down, + .enable_power_gating_plane = dcn20_enable_power_gating_plane, + .dpp_pg_control = dcn20_dpp_pg_control, + .hubp_pg_control = dcn20_hubp_pg_control, + .program_all_writeback_pipes_in_tree = dcn30_program_all_writeback_pipes_in_tree, + .update_odm = dcn20_update_odm, + .dsc_pg_control = dcn20_dsc_pg_control, + .set_hdr_multiplier = dcn10_set_hdr_multiplier, + .verify_allow_pstate_change_high = dcn10_verify_allow_pstate_change_high, + .wait_for_blank_complete = dcn20_wait_for_blank_complete, + .dccg_init = dcn20_dccg_init, + .set_blend_lut = dcn30_set_blend_lut, + .set_shaper_3dlut = dcn20_set_shaper_3dlut, +}; + +void dcn30_hw_sequencer_construct(struct dc *dc) +{ + dc->hwss = dcn30_funcs; + dc->hwseq->funcs = dcn30_private_funcs; + +} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.h new file mode 100644 index 00000000000000..c280ff90bfa3b6 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_init.h @@ -0,0 +1,33 @@ +/* + * Copyright 2020 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_DCN30_INIT_H__ +#define __DC_DCN30_INIT_H__ + +struct dc; + +void dcn30_hw_sequencer_construct(struct dc *dc); + +#endif /* __DC_DCN30_INIT_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.c new file mode 100644 index 00000000000000..6477009ce0654d --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.c @@ -0,0 +1,154 @@ +/* + * Copyright 2016-2020 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 "dce110/dce110_hwseq.h" +#include "dcn10/dcn10_hwseq.h" +#include "dcn20/dcn20_hwseq.h" +#include "dcn21/dcn21_hwseq.h" +#include "dcn30/dcn30_hwseq.h" +#include "dcn301/dcn301_hwseq.h" + +#include "dcn301_init.h" + +static const struct hw_sequencer_funcs dcn301_funcs = { + .program_gamut_remap = dcn30_program_gamut_remap, + .init_hw = dcn10_init_hw, + .power_down_on_boot = dcn10_power_down_on_boot, + .apply_ctx_to_hw = dce110_apply_ctx_to_hw, + .apply_ctx_for_surface = NULL, + .program_front_end_for_ctx = dcn20_program_front_end_for_ctx, + .wait_for_pending_cleared = dcn10_wait_for_pending_cleared, + .post_unlock_program_front_end = dcn20_post_unlock_program_front_end, + .update_plane_addr = dcn20_update_plane_addr, + .update_dchub = dcn10_update_dchub, + .update_pending_status = dcn10_update_pending_status, + .program_output_csc = dcn20_program_output_csc, + .enable_accelerated_mode = dce110_enable_accelerated_mode, + .enable_timing_synchronization = dcn10_enable_timing_synchronization, + .enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset, + .update_info_frame = dcn30_update_info_frame, + .send_immediate_sdp_message = dcn10_send_immediate_sdp_message, + .enable_stream = dcn20_enable_stream, + .disable_stream = dce110_disable_stream, + .unblank_stream = dcn20_unblank_stream, +#ifdef FREESYNC_POWER_OPTIMIZE + .are_streams_coarse_grain_aligned = dcn20_are_streams_coarse_grain_aligned, +#endif + .blank_stream = dce110_blank_stream, + .enable_audio_stream = dce110_enable_audio_stream, + .disable_audio_stream = dce110_disable_audio_stream, + .disable_plane = dcn20_disable_plane, + .pipe_control_lock = dcn20_pipe_control_lock, + .interdependent_update_lock = dcn10_lock_all_pipes, + .cursor_lock = dcn10_cursor_lock, + .prepare_bandwidth = dcn20_prepare_bandwidth, + .optimize_bandwidth = dcn20_optimize_bandwidth, + .update_bandwidth = dcn20_update_bandwidth, + .set_drr = dcn10_set_drr, + .get_position = dcn10_get_position, + .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, + .get_hw_state = dcn10_get_hw_state, + .clear_status_bits = dcn10_clear_status_bits, + .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, + .edp_backlight_control = dce110_edp_backlight_control, + .edp_power_control = dce110_edp_power_control, + .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, + .set_cursor_position = dcn10_set_cursor_position, + .set_cursor_attribute = dcn10_set_cursor_attribute, + .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level, + .setup_periodic_interrupt = dcn10_setup_periodic_interrupt, + .set_clock = dcn10_set_clock, + .get_clock = dcn10_get_clock, + .program_triplebuffer = dcn20_program_triple_buffer, + .enable_writeback = dcn30_enable_writeback, + .disable_writeback = dcn30_disable_writeback, + .update_writeback = dcn30_update_writeback, + .mmhubbub_warmup = dcn30_mmhubbub_warmup, + .dmdata_status_done = dcn20_dmdata_status_done, + .program_dmdata_engine = dcn30_program_dmdata_engine, + .set_dmdata_attributes = dcn20_set_dmdata_attributes, + .init_sys_ctx = dcn20_init_sys_ctx, + .init_vm_ctx = dcn20_init_vm_ctx, + .set_flip_control_gsl = dcn20_set_flip_control_gsl, + .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync, + .calc_vupdate_position = dcn10_calc_vupdate_position, + .set_backlight_level = dcn21_set_backlight_level, + .set_abm_immediate_disable = dcn21_set_abm_immediate_disable, + .set_pipe = dcn21_set_pipe, + .enable_lvds_link_output = dce110_enable_lvds_link_output, + .enable_tmds_link_output = dce110_enable_tmds_link_output, + .enable_dp_link_output = dce110_enable_dp_link_output, + .disable_link_output = dce110_disable_link_output, + .set_disp_pattern_generator = dcn30_set_disp_pattern_generator, + .get_dcc_en_bits = dcn10_get_dcc_en_bits, + .optimize_pwr_state = dcn21_optimize_pwr_state, + .exit_optimized_pwr_state = dcn21_exit_optimized_pwr_state, + .update_visual_confirm_color = dcn10_update_visual_confirm_color, +}; + +static const struct hwseq_private_funcs dcn301_private_funcs = { + .init_pipes = dcn10_init_pipes, + .update_plane_addr = dcn20_update_plane_addr, + .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, + .update_mpcc = dcn20_update_mpcc, + .set_input_transfer_func = dcn30_set_input_transfer_func, + .set_output_transfer_func = dcn30_set_output_transfer_func, + .power_down = dce110_power_down, + .enable_display_power_gating = dcn10_dummy_display_power_gating, + .blank_pixel_data = dcn20_blank_pixel_data, + .reset_hw_ctx_wrap = dcn20_reset_hw_ctx_wrap, + .enable_stream_timing = dcn20_enable_stream_timing, + .edp_backlight_control = dce110_edp_backlight_control, + .disable_stream_gating = dcn20_disable_stream_gating, + .enable_stream_gating = dcn20_enable_stream_gating, + .setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt, + .did_underflow_occur = dcn10_did_underflow_occur, + .init_blank = dcn20_init_blank, + .disable_vga = dcn20_disable_vga, + .bios_golden_init = dcn10_bios_golden_init, + .plane_atomic_disable = dcn20_plane_atomic_disable, + .plane_atomic_power_down = dcn10_plane_atomic_power_down, + .enable_power_gating_plane = dcn20_enable_power_gating_plane, + .dpp_pg_control = dcn20_dpp_pg_control, + .hubp_pg_control = dcn20_hubp_pg_control, + .program_all_writeback_pipes_in_tree = dcn30_program_all_writeback_pipes_in_tree, + .update_odm = dcn20_update_odm, + .dsc_pg_control = dcn20_dsc_pg_control, + .set_hdr_multiplier = dcn10_set_hdr_multiplier, + .verify_allow_pstate_change_high = dcn10_verify_allow_pstate_change_high, + .wait_for_blank_complete = dcn20_wait_for_blank_complete, + .dccg_init = dcn20_dccg_init, + .set_blend_lut = dcn30_set_blend_lut, + .set_shaper_3dlut = dcn20_set_shaper_3dlut, +}; + +void dcn301_hw_sequencer_construct(struct dc *dc) +{ + dc->hwss = dcn301_funcs; + dc->hwseq->funcs = dcn301_private_funcs; +} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.h new file mode 100644 index 00000000000000..0bca48ccbfa200 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn301/dcn301_init.h @@ -0,0 +1,33 @@ +/* + * Copyright 2020 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_DCN30_INIT_H__ +#define __DC_DCN30_INIT_H__ + +struct dc; + +void dcn301_hw_sequencer_construct(struct dc *dc); + +#endif /* __DC_DCN30_INIT_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn302/dcn302_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn302/dcn302_init.c new file mode 100644 index 00000000000000..637f9514d37b2d --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn302/dcn302_init.c @@ -0,0 +1,41 @@ +/* + * Copyright 2020 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 "dcn302/dcn302_hwseq.h" + +#include "dcn30/dcn30_init.h" + +#include "dc.h" + +#include "dcn302_init.h" + +void dcn302_hw_sequencer_construct(struct dc *dc) +{ + dcn30_hw_sequencer_construct(dc); + + dc->hwseq->funcs.dpp_pg_control = dcn302_dpp_pg_control; + dc->hwseq->funcs.hubp_pg_control = dcn302_hubp_pg_control; + dc->hwseq->funcs.dsc_pg_control = dcn302_dsc_pg_control; +} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn302/dcn302_init.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn302/dcn302_init.h new file mode 100644 index 00000000000000..899587b93aa1c2 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn302/dcn302_init.h @@ -0,0 +1,33 @@ +/* + * Copyright 2020 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_DCN302_INIT_H__ +#define __DC_DCN302_INIT_H__ + +struct dc; + +void dcn302_hw_sequencer_construct(struct dc *dc); + +#endif /* __DC_DCN302_INIT_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn303/dcn303_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn303/dcn303_init.c new file mode 100644 index 00000000000000..edb4d68b81871c --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn303/dcn303_init.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (C) 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 "dcn303/dcn303_hwseq.h" +#include "dcn30/dcn30_init.h" +#include "dc.h" + +#include "dcn303_init.h" + +void dcn303_hw_sequencer_construct(struct dc *dc) +{ + dcn30_hw_sequencer_construct(dc); + + dc->hwseq->funcs.dpp_pg_control = dcn303_dpp_pg_control; + dc->hwseq->funcs.hubp_pg_control = dcn303_hubp_pg_control; + dc->hwseq->funcs.dsc_pg_control = dcn303_dsc_pg_control; + dc->hwseq->funcs.enable_power_gating_plane = dcn303_enable_power_gating_plane; +} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn303/dcn303_init.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn303/dcn303_init.h new file mode 100644 index 00000000000000..4949981126d762 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn303/dcn303_init.h @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (C) 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_DCN303_INIT_H__ +#define __DC_DCN303_INIT_H__ + +struct dc; + +void dcn303_hw_sequencer_construct(struct dc *dc); + +#endif /* __DC_DCN303_INIT_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c index 97798cee876e2e..7423880fabb6e3 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_hwseq.c @@ -96,7 +96,8 @@ static void enable_memory_low_power(struct dc *dc) if (dc->debug.enable_mem_low_power.bits.vpg && dc->res_pool->stream_enc[0]->vpg->funcs->vpg_powerdown) { // Power down VPGs for (i = 0; i < dc->res_pool->stream_enc_count; i++) - dc->res_pool->stream_enc[i]->vpg->funcs->vpg_powerdown(dc->res_pool->stream_enc[i]->vpg); + if (dc->res_pool->stream_enc[i]->vpg) + dc->res_pool->stream_enc[i]->vpg->funcs->vpg_powerdown(dc->res_pool->stream_enc[i]->vpg); #if defined(CONFIG_DRM_AMD_DC_FP) for (i = 0; i < dc->res_pool->hpo_dp_stream_enc_count; i++) dc->res_pool->hpo_dp_stream_enc[i]->vpg->funcs->vpg_powerdown(dc->res_pool->hpo_dp_stream_enc[i]->vpg); @@ -112,6 +113,7 @@ void dcn31_init_hw(struct dc *dc) struct dc_bios *dcb = dc->ctx->dc_bios; struct resource_pool *res_pool = dc->res_pool; uint32_t backlight = MAX_BACKLIGHT_LEVEL; + uint32_t user_level = MAX_BACKLIGHT_LEVEL; int i; if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) @@ -223,13 +225,15 @@ void dcn31_init_hw(struct dc *dc) for (i = 0; i < dc->link_count; i++) { struct dc_link *link = dc->links[i]; - if (link->panel_cntl) + if (link->panel_cntl) { backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl); + user_level = link->panel_cntl->stored_backlight_registers.USER_LEVEL; + } } for (i = 0; i < dc->res_pool->pipe_count; i++) { if (abms[i] != NULL) - abms[i]->funcs->abm_init(abms[i], backlight); + abms[i]->funcs->abm_init(abms[i], backlight, user_level); } /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ @@ -415,7 +419,7 @@ void dcn31_z10_save_init(struct dc *dc) cmd.dcn_restore.header.type = DMUB_CMD__IDLE_OPT; cmd.dcn_restore.header.sub_type = DMUB_CMD__IDLE_OPT_DCN_SAVE_INIT; - dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); } void dcn31_z10_restore(const struct dc *dc) @@ -433,7 +437,7 @@ void dcn31_z10_restore(const struct dc *dc) cmd.dcn_restore.header.type = DMUB_CMD__IDLE_OPT; cmd.dcn_restore.header.sub_type = DMUB_CMD__IDLE_OPT_DCN_RESTORE; - dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); } void dcn31_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on) @@ -523,7 +527,8 @@ static void dcn31_reset_back_end_for_pipe( if (pipe_ctx->stream_res.tg->funcs->set_odm_bypass) pipe_ctx->stream_res.tg->funcs->set_odm_bypass( pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); - pipe_ctx->stream->link->phy_state.symclk_ref_cnts.otg = 0; + if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal)) + pipe_ctx->stream->link->phy_state.symclk_ref_cnts.otg = 0; if (pipe_ctx->stream_res.tg->funcs->set_drr) pipe_ctx->stream_res.tg->funcs->set_drr( diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c new file mode 100644 index 00000000000000..669f524bd064d5 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.c @@ -0,0 +1,157 @@ +/* + * Copyright 2016 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 "dce110/dce110_hwseq.h" +#include "dcn10/dcn10_hwseq.h" +#include "dcn20/dcn20_hwseq.h" +#include "dcn21/dcn21_hwseq.h" +#include "dcn30/dcn30_hwseq.h" +#include "dcn301/dcn301_hwseq.h" +#include "dcn31/dcn31_hwseq.h" + +#include "dcn31_init.h" + +static const struct hw_sequencer_funcs dcn31_funcs = { + .program_gamut_remap = dcn30_program_gamut_remap, + .init_hw = dcn31_init_hw, + .power_down_on_boot = dcn10_power_down_on_boot, + .apply_ctx_to_hw = dce110_apply_ctx_to_hw, + .apply_ctx_for_surface = NULL, + .program_front_end_for_ctx = dcn20_program_front_end_for_ctx, + .wait_for_pending_cleared = dcn10_wait_for_pending_cleared, + .post_unlock_program_front_end = dcn20_post_unlock_program_front_end, + .update_plane_addr = dcn20_update_plane_addr, + .update_dchub = dcn10_update_dchub, + .update_pending_status = dcn10_update_pending_status, + .program_output_csc = dcn20_program_output_csc, + .enable_accelerated_mode = dce110_enable_accelerated_mode, + .enable_timing_synchronization = dcn10_enable_timing_synchronization, + .enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset, + .update_info_frame = dcn31_update_info_frame, + .send_immediate_sdp_message = dcn10_send_immediate_sdp_message, + .enable_stream = dcn20_enable_stream, + .disable_stream = dce110_disable_stream, + .unblank_stream = dcn20_unblank_stream, + .blank_stream = dce110_blank_stream, + .enable_audio_stream = dce110_enable_audio_stream, + .disable_audio_stream = dce110_disable_audio_stream, + .disable_plane = dcn20_disable_plane, + .disable_pixel_data = dcn20_disable_pixel_data, + .pipe_control_lock = dcn20_pipe_control_lock, + .interdependent_update_lock = dcn10_lock_all_pipes, + .cursor_lock = dcn10_cursor_lock, + .prepare_bandwidth = dcn20_prepare_bandwidth, + .optimize_bandwidth = dcn20_optimize_bandwidth, + .update_bandwidth = dcn20_update_bandwidth, + .set_drr = dcn10_set_drr, + .get_position = dcn10_get_position, + .set_static_screen_control = dcn30_set_static_screen_control, + .setup_stereo = dcn10_setup_stereo, + .set_avmute = dcn30_set_avmute, + .log_hw_state = dcn10_log_hw_state, + .get_hw_state = dcn10_get_hw_state, + .clear_status_bits = dcn10_clear_status_bits, + .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, + .edp_backlight_control = dce110_edp_backlight_control, + .edp_power_control = dce110_edp_power_control, + .edp_wait_for_T12 = dce110_edp_wait_for_T12, + .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, + .set_cursor_position = dcn10_set_cursor_position, + .set_cursor_attribute = dcn10_set_cursor_attribute, + .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level, + .setup_periodic_interrupt = dcn10_setup_periodic_interrupt, + .set_clock = dcn10_set_clock, + .get_clock = dcn10_get_clock, + .program_triplebuffer = dcn20_program_triple_buffer, + .enable_writeback = dcn30_enable_writeback, + .disable_writeback = dcn30_disable_writeback, + .update_writeback = dcn30_update_writeback, + .mmhubbub_warmup = dcn30_mmhubbub_warmup, + .dmdata_status_done = dcn20_dmdata_status_done, + .program_dmdata_engine = dcn30_program_dmdata_engine, + .set_dmdata_attributes = dcn20_set_dmdata_attributes, + .init_sys_ctx = dcn31_init_sys_ctx, + .init_vm_ctx = dcn20_init_vm_ctx, + .set_flip_control_gsl = dcn20_set_flip_control_gsl, + .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync, + .calc_vupdate_position = dcn10_calc_vupdate_position, + .power_down = dce110_power_down, + .set_backlight_level = dcn21_set_backlight_level, + .set_abm_immediate_disable = dcn21_set_abm_immediate_disable, + .set_pipe = dcn21_set_pipe, + .enable_lvds_link_output = dce110_enable_lvds_link_output, + .enable_tmds_link_output = dce110_enable_tmds_link_output, + .enable_dp_link_output = dce110_enable_dp_link_output, + .disable_link_output = dce110_disable_link_output, + .z10_restore = dcn31_z10_restore, + .z10_save_init = dcn31_z10_save_init, + .set_disp_pattern_generator = dcn30_set_disp_pattern_generator, + .optimize_pwr_state = dcn21_optimize_pwr_state, + .exit_optimized_pwr_state = dcn21_exit_optimized_pwr_state, + .update_visual_confirm_color = dcn10_update_visual_confirm_color, +}; + +static const struct hwseq_private_funcs dcn31_private_funcs = { + .init_pipes = dcn10_init_pipes, + .update_plane_addr = dcn20_update_plane_addr, + .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, + .update_mpcc = dcn20_update_mpcc, + .set_input_transfer_func = dcn30_set_input_transfer_func, + .set_output_transfer_func = dcn30_set_output_transfer_func, + .power_down = dce110_power_down, + .enable_display_power_gating = dcn10_dummy_display_power_gating, + .blank_pixel_data = dcn20_blank_pixel_data, + .reset_hw_ctx_wrap = dcn31_reset_hw_ctx_wrap, + .enable_stream_timing = dcn20_enable_stream_timing, + .edp_backlight_control = dce110_edp_backlight_control, + .disable_stream_gating = dcn20_disable_stream_gating, + .enable_stream_gating = dcn20_enable_stream_gating, + .setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt, + .did_underflow_occur = dcn10_did_underflow_occur, + .init_blank = dcn20_init_blank, + .disable_vga = dcn20_disable_vga, + .bios_golden_init = dcn10_bios_golden_init, + .plane_atomic_disable = dcn20_plane_atomic_disable, + .plane_atomic_power_down = dcn10_plane_atomic_power_down, + .enable_power_gating_plane = dcn31_enable_power_gating_plane, + .hubp_pg_control = dcn31_hubp_pg_control, + .program_all_writeback_pipes_in_tree = dcn30_program_all_writeback_pipes_in_tree, + .update_odm = dcn20_update_odm, + .dsc_pg_control = dcn31_dsc_pg_control, + .set_hdr_multiplier = dcn10_set_hdr_multiplier, + .verify_allow_pstate_change_high = dcn10_verify_allow_pstate_change_high, + .wait_for_blank_complete = dcn20_wait_for_blank_complete, + .dccg_init = dcn20_dccg_init, + .set_blend_lut = dcn30_set_blend_lut, + .set_shaper_3dlut = dcn20_set_shaper_3dlut, + .setup_hpo_hw_control = dcn31_setup_hpo_hw_control, +}; + +void dcn31_hw_sequencer_construct(struct dc *dc) +{ + dc->hwss = dcn31_funcs; + dc->hwseq->funcs = dcn31_private_funcs; + +} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.h new file mode 100644 index 00000000000000..a3db08c8bd35bd --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn31/dcn31_init.h @@ -0,0 +1,33 @@ +/* + * Copyright 2016 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_DCN31_INIT_H__ +#define __DC_DCN31_INIT_H__ + +struct dc; + +void dcn31_hw_sequencer_construct(struct dc *dc); + +#endif /* __DC_DCN31_INIT_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c new file mode 100644 index 00000000000000..ccb7e317e86af1 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.c @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: MIT +/* + * 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 "dce110/dce110_hwseq.h" +#include "dcn10/dcn10_hwseq.h" +#include "dcn20/dcn20_hwseq.h" +#include "dcn21/dcn21_hwseq.h" +#include "dcn30/dcn30_hwseq.h" +#include "dcn301/dcn301_hwseq.h" +#include "dcn31/dcn31_hwseq.h" +#include "dcn314/dcn314_hwseq.h" + +#include "dcn314_init.h" + +static const struct hw_sequencer_funcs dcn314_funcs = { + .program_gamut_remap = dcn30_program_gamut_remap, + .init_hw = dcn31_init_hw, + .power_down_on_boot = dcn10_power_down_on_boot, + .apply_ctx_to_hw = dce110_apply_ctx_to_hw, + .apply_ctx_for_surface = NULL, + .program_front_end_for_ctx = dcn20_program_front_end_for_ctx, + .wait_for_pending_cleared = dcn10_wait_for_pending_cleared, + .post_unlock_program_front_end = dcn20_post_unlock_program_front_end, + .update_plane_addr = dcn20_update_plane_addr, + .update_dchub = dcn10_update_dchub, + .update_pending_status = dcn10_update_pending_status, + .program_output_csc = dcn20_program_output_csc, + .enable_accelerated_mode = dce110_enable_accelerated_mode, + .enable_timing_synchronization = dcn10_enable_timing_synchronization, + .enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset, + .update_info_frame = dcn31_update_info_frame, + .send_immediate_sdp_message = dcn10_send_immediate_sdp_message, + .enable_stream = dcn20_enable_stream, + .disable_stream = dce110_disable_stream, + .unblank_stream = dcn20_unblank_stream, + .blank_stream = dce110_blank_stream, + .enable_audio_stream = dce110_enable_audio_stream, + .disable_audio_stream = dce110_disable_audio_stream, + .disable_plane = dcn20_disable_plane, + .disable_pixel_data = dcn20_disable_pixel_data, + .pipe_control_lock = dcn20_pipe_control_lock, + .interdependent_update_lock = dcn10_lock_all_pipes, + .cursor_lock = dcn10_cursor_lock, + .prepare_bandwidth = dcn20_prepare_bandwidth, + .optimize_bandwidth = dcn20_optimize_bandwidth, + .update_bandwidth = dcn20_update_bandwidth, + .set_drr = dcn10_set_drr, + .get_position = dcn10_get_position, + .set_static_screen_control = dcn30_set_static_screen_control, + .setup_stereo = dcn10_setup_stereo, + .set_avmute = dcn30_set_avmute, + .log_hw_state = dcn10_log_hw_state, + .get_hw_state = dcn10_get_hw_state, + .clear_status_bits = dcn10_clear_status_bits, + .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, + .edp_backlight_control = dce110_edp_backlight_control, + .edp_power_control = dce110_edp_power_control, + .edp_wait_for_T12 = dce110_edp_wait_for_T12, + .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, + .set_cursor_position = dcn10_set_cursor_position, + .set_cursor_attribute = dcn10_set_cursor_attribute, + .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level, + .setup_periodic_interrupt = dcn10_setup_periodic_interrupt, + .set_clock = dcn10_set_clock, + .get_clock = dcn10_get_clock, + .program_triplebuffer = dcn20_program_triple_buffer, + .enable_writeback = dcn30_enable_writeback, + .disable_writeback = dcn30_disable_writeback, + .update_writeback = dcn30_update_writeback, + .mmhubbub_warmup = dcn30_mmhubbub_warmup, + .dmdata_status_done = dcn20_dmdata_status_done, + .program_dmdata_engine = dcn30_program_dmdata_engine, + .set_dmdata_attributes = dcn20_set_dmdata_attributes, + .init_sys_ctx = dcn31_init_sys_ctx, + .init_vm_ctx = dcn20_init_vm_ctx, + .set_flip_control_gsl = dcn20_set_flip_control_gsl, + .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync, + .calc_vupdate_position = dcn10_calc_vupdate_position, + .power_down = dce110_power_down, + .set_backlight_level = dcn21_set_backlight_level, + .set_abm_immediate_disable = dcn21_set_abm_immediate_disable, + .set_pipe = dcn21_set_pipe, + .enable_lvds_link_output = dce110_enable_lvds_link_output, + .enable_tmds_link_output = dce110_enable_tmds_link_output, + .enable_dp_link_output = dce110_enable_dp_link_output, + .disable_link_output = dcn314_disable_link_output, + .z10_restore = dcn31_z10_restore, + .z10_save_init = dcn31_z10_save_init, + .set_disp_pattern_generator = dcn30_set_disp_pattern_generator, + .optimize_pwr_state = dcn21_optimize_pwr_state, + .exit_optimized_pwr_state = dcn21_exit_optimized_pwr_state, + .update_visual_confirm_color = dcn10_update_visual_confirm_color, +}; + +static const struct hwseq_private_funcs dcn314_private_funcs = { + .init_pipes = dcn10_init_pipes, + .update_plane_addr = dcn20_update_plane_addr, + .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, + .update_mpcc = dcn20_update_mpcc, + .set_input_transfer_func = dcn30_set_input_transfer_func, + .set_output_transfer_func = dcn30_set_output_transfer_func, + .power_down = dce110_power_down, + .enable_display_power_gating = dcn10_dummy_display_power_gating, + .blank_pixel_data = dcn20_blank_pixel_data, + .reset_hw_ctx_wrap = dcn31_reset_hw_ctx_wrap, + .enable_stream_timing = dcn20_enable_stream_timing, + .edp_backlight_control = dce110_edp_backlight_control, + .disable_stream_gating = dcn20_disable_stream_gating, + .enable_stream_gating = dcn20_enable_stream_gating, + .setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt, + .did_underflow_occur = dcn10_did_underflow_occur, + .init_blank = dcn20_init_blank, + .disable_vga = dcn20_disable_vga, + .bios_golden_init = dcn10_bios_golden_init, + .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, + .dpp_root_clock_control = dcn314_dpp_root_clock_control, + .hubp_pg_control = dcn31_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, + .set_hdr_multiplier = dcn10_set_hdr_multiplier, + .verify_allow_pstate_change_high = dcn10_verify_allow_pstate_change_high, + .wait_for_blank_complete = dcn20_wait_for_blank_complete, + .dccg_init = dcn20_dccg_init, + .set_blend_lut = dcn30_set_blend_lut, + .set_shaper_3dlut = dcn20_set_shaper_3dlut, + .setup_hpo_hw_control = dcn31_setup_hpo_hw_control, + .calculate_dccg_k1_k2_values = dcn314_calculate_dccg_k1_k2_values, + .set_pixels_per_cycle = dcn314_set_pixels_per_cycle, + .resync_fifo_dccg_dio = dcn314_resync_fifo_dccg_dio, +}; + +void dcn314_hw_sequencer_construct(struct dc *dc) +{ + dc->hwss = dcn314_funcs; + dc->hwseq->funcs = dcn314_private_funcs; + +} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.h new file mode 100644 index 00000000000000..8f92e66577cf17 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_init.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: MIT */ +/* + * 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_DCN314_INIT_H__ +#define __DC_DCN314_INIT_H__ + +struct dc; + +void dcn314_hw_sequencer_construct(struct dc *dc); + +#endif /* __DC_DCN314_INIT_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c index c1a9b746c43fef..6c9299c7683df1 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c @@ -51,6 +51,7 @@ #include "dcn32/dcn32_resource.h" #include "link.h" #include "../dcn20/dcn20_hwseq.h" +#include "dc_state_priv.h" #define DC_LOGGER_INIT(logger) @@ -277,7 +278,7 @@ bool dcn32_apply_idle_power_optimizations(struct dc *dc, bool enable) cmd.cab.header.sub_type = DMUB_CMD__CAB_NO_DCN_REQ; cmd.cab.header.payload_bytes = sizeof(cmd.cab) - sizeof(cmd.cab.header); - dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT); + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT); return true; } @@ -311,7 +312,7 @@ bool dcn32_apply_idle_power_optimizations(struct dc *dc, bool enable) cmd.cab.header.payload_bytes = sizeof(cmd.cab) - sizeof(cmd.cab.header); cmd.cab.cab_alloc_ways = (uint8_t)ways; - dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT); + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_NO_WAIT); return true; } @@ -327,7 +328,7 @@ bool dcn32_apply_idle_power_optimizations(struct dc *dc, bool enable) cmd.cab.header.payload_bytes = sizeof(cmd.cab) - sizeof(cmd.cab.header); - dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); + dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); return true; } @@ -348,8 +349,7 @@ void dcn32_commit_subvp_config(struct dc *dc, struct dc_state *context) for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; - if (pipe_ctx->stream && pipe_ctx->stream->mall_stream_config.paired_stream && - pipe_ctx->stream->mall_stream_config.type == SUBVP_MAIN) { + if (pipe_ctx->stream && dc_state_get_pipe_subvp_type(context, pipe_ctx) == SUBVP_MAIN) { // There is at least 1 SubVP pipe, so enable SubVP enable_subvp = true; break; @@ -375,18 +375,20 @@ void dcn32_subvp_pipe_control_lock(struct dc *dc, bool subvp_immediate_flip = false; bool subvp_in_use = false; struct pipe_ctx *pipe; + enum mall_stream_type pipe_mall_type = SUBVP_NONE; for (i = 0; i < dc->res_pool->pipe_count; i++) { pipe = &context->res_ctx.pipe_ctx[i]; + pipe_mall_type = dc_state_get_pipe_subvp_type(context, pipe); - if (pipe->stream && pipe->plane_state && pipe->stream->mall_stream_config.type == SUBVP_MAIN) { + if (pipe->stream && pipe->plane_state && pipe_mall_type == SUBVP_MAIN) { subvp_in_use = true; break; } } if (top_pipe_to_program && top_pipe_to_program->stream && top_pipe_to_program->plane_state) { - if (top_pipe_to_program->stream->mall_stream_config.type == SUBVP_MAIN && + if (dc_state_get_pipe_subvp_type(context, top_pipe_to_program) == SUBVP_MAIN && top_pipe_to_program->plane_state->flip_immediate) subvp_immediate_flip = true; } @@ -398,7 +400,7 @@ void dcn32_subvp_pipe_control_lock(struct dc *dc, if (!lock) { for (i = 0; i < dc->res_pool->pipe_count; i++) { pipe = &context->res_ctx.pipe_ctx[i]; - if (pipe->stream && pipe->plane_state && pipe->stream->mall_stream_config.type == SUBVP_MAIN && + if (pipe->stream && pipe->plane_state && pipe_mall_type == SUBVP_MAIN && should_lock_all_pipes) pipe->stream_res.tg->funcs->wait_for_state(pipe->stream_res.tg, CRTC_STATE_VBLANK); } @@ -416,14 +418,7 @@ void dcn32_subvp_pipe_control_lock_fast(union block_sequence_params *params) { struct dc *dc = params->subvp_pipe_control_lock_fast_params.dc; bool lock = params->subvp_pipe_control_lock_fast_params.lock; - struct pipe_ctx *pipe_ctx = params->subvp_pipe_control_lock_fast_params.pipe_ctx; - bool subvp_immediate_flip = false; - - if (pipe_ctx && pipe_ctx->stream && pipe_ctx->plane_state) { - if (pipe_ctx->stream->mall_stream_config.type == SUBVP_MAIN && - pipe_ctx->plane_state->flip_immediate) - subvp_immediate_flip = true; - } + bool subvp_immediate_flip = params->subvp_pipe_control_lock_fast_params.subvp_immediate_flip; // Don't need to lock for DRR VSYNC flips -- FW will wait for DRR pending update cleared. if (subvp_immediate_flip) { @@ -609,7 +604,7 @@ void dcn32_update_force_pstate(struct dc *dc, struct dc_state *context) struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; struct hubp *hubp = pipe->plane_res.hubp; - if (!pipe->stream || !(pipe->stream->mall_stream_config.type == SUBVP_MAIN || + if (!pipe->stream || !(dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_MAIN || pipe->stream->fpo_in_use)) { if (hubp && hubp->funcs->hubp_update_force_pstate_disallow) hubp->funcs->hubp_update_force_pstate_disallow(hubp, false); @@ -624,7 +619,7 @@ void dcn32_update_force_pstate(struct dc *dc, struct dc_state *context) struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; struct hubp *hubp = pipe->plane_res.hubp; - if (pipe->stream && (pipe->stream->mall_stream_config.type == SUBVP_MAIN || + if (pipe->stream && (dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_MAIN || pipe->stream->fpo_in_use)) { if (hubp && hubp->funcs->hubp_update_force_pstate_disallow) hubp->funcs->hubp_update_force_pstate_disallow(hubp, true); @@ -671,8 +666,8 @@ void dcn32_update_mall_sel(struct dc *dc, struct dc_state *context) if (cursor_size > 16384) cache_cursor = true; - if (pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) { - hubp->funcs->hubp_update_mall_sel(hubp, 1, false); + if (dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) { + hubp->funcs->hubp_update_mall_sel(hubp, 1, false); } else { // MALL not supported with Stereo3D hubp->funcs->hubp_update_mall_sel(hubp, @@ -714,9 +709,8 @@ void dcn32_program_mall_pipe_config(struct dc *dc, struct dc_state *context) * see if CURSOR_REQ_MODE will be back to 1 for SubVP * when it should be 0 for MPO */ - if (pipe->stream->mall_stream_config.type == SUBVP_MAIN) { + if (dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_MAIN) hubp->funcs->hubp_prepare_subvp_buffering(hubp, true); - } } } } @@ -759,6 +753,7 @@ void dcn32_init_hw(struct dc *dc) int i; int edp_num; uint32_t backlight = MAX_BACKLIGHT_LEVEL; + uint32_t user_level = MAX_BACKLIGHT_LEVEL; if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); @@ -913,13 +908,15 @@ void dcn32_init_hw(struct dc *dc) for (i = 0; i < dc->link_count; i++) { struct dc_link *link = dc->links[i]; - if (link->panel_cntl) + if (link->panel_cntl) { backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl); + user_level = link->panel_cntl->stored_backlight_registers.USER_LEVEL; + } } for (i = 0; i < dc->res_pool->pipe_count; i++) { if (abms[i] != NULL && abms[i]->funcs != NULL) - abms[i]->funcs->abm_init(abms[i], backlight); + abms[i]->funcs->abm_init(abms[i], backlight, user_level); } /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ @@ -995,9 +992,22 @@ static int calc_mpc_flow_ctrl_cnt(const struct dc_stream_state *stream, static void update_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; + struct dccg *dccg = dc->res_pool->dccg; + /* It has been found that when DSCCLK is lower than 16Mhz, we will get DCN + * register access hung. When DSCCLk is based on refclk, DSCCLk is always a + * fixed value higher than 16Mhz so the issue doesn't occur. When DSCCLK is + * generated by DTO, DSCCLK would be based on 1/3 dispclk. For small timings + * with DSC such as 480p60Hz, the dispclk could be low enough to trigger + * this problem. We are implementing a workaround here to keep using dscclk + * based on fixed value refclk when timing is smaller than 3x16Mhz (i.e + * 48Mhz) pixel clock to avoid hitting this problem. + */ + bool should_use_dto_dscclk = (dccg->funcs->set_dto_dscclk != NULL) && + stream->timing.pix_clk_100hz > 480000; ASSERT(dsc); for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) @@ -1020,12 +1030,16 @@ static void update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg); dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst); + if (should_use_dto_dscclk) + dccg->funcs->set_dto_dscclk(dccg, dsc->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; ASSERT(odm_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); + if (should_use_dto_dscclk) + dccg->funcs->set_dto_dscclk(dccg, odm_dsc->inst); } dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt; dsc_cfg.pic_width *= opp_cnt; @@ -1045,9 +1059,13 @@ static void update_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) OPTC_DSC_DISABLED, 0, 0); /* disable DSC block */ + if (dccg->funcs->set_ref_dscclk) + dccg->funcs->set_ref_dscclk(dccg, pipe_ctx->stream_res.dsc->inst); 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) { ASSERT(odm_pipe->stream_res.dsc); + if (dccg->funcs->set_ref_dscclk) + dccg->funcs->set_ref_dscclk(dccg, odm_pipe->stream_res.dsc->inst); odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc); } } @@ -1130,6 +1148,10 @@ void dcn32_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx * if (!pipe_ctx->next_odm_pipe && current_pipe_ctx->next_odm_pipe && current_pipe_ctx->next_odm_pipe->stream_res.dsc) { struct display_stream_compressor *dsc = current_pipe_ctx->next_odm_pipe->stream_res.dsc; + struct dccg *dccg = dc->res_pool->dccg; + + if (dccg->funcs->set_ref_dscclk) + dccg->funcs->set_ref_dscclk(dccg, dsc->inst); /* disconnect DSC block from stream */ dsc->funcs->dsc_disconnect(dsc); } @@ -1203,7 +1225,7 @@ void dcn32_resync_fifo_dccg_dio(struct dce_hwseq *hws, struct dc *dc, struct dc_ continue; if ((pipe->stream->dpms_off || dc_is_virtual_signal(pipe->stream->signal)) - && pipe->stream->mall_stream_config.type != SUBVP_PHANTOM) { + && dc_state_get_pipe_subvp_type(dc->current_state, pipe) != SUBVP_PHANTOM) { pipe->stream_res.tg->funcs->disable_crtc(pipe->stream_res.tg); reset_sync_context_for_pipe(dc, context, i); otg_disabled[i] = true; @@ -1354,8 +1376,8 @@ void dcn32_update_phantom_vp_position(struct dc *dc, 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_MAIN && - pipe->stream->mall_stream_config.paired_stream == phantom_pipe->stream) { + if (pipe->stream && dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_MAIN && + dc_state_get_paired_subvp_stream(context, pipe->stream) == phantom_pipe->stream) { if (pipe->plane_state && pipe->plane_state->update_flags.bits.position_change) { phantom_plane->src_rect.x = pipe->plane_state->src_rect.x; @@ -1380,21 +1402,19 @@ void dcn32_update_phantom_vp_position(struct dc *dc, void dcn32_apply_update_flags_for_phantom(struct pipe_ctx *phantom_pipe) { phantom_pipe->update_flags.raw = 0; - if (phantom_pipe->stream && phantom_pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) { - if (resource_is_pipe_type(phantom_pipe, DPP_PIPE)) { - phantom_pipe->update_flags.bits.enable = 1; - phantom_pipe->update_flags.bits.mpcc = 1; - phantom_pipe->update_flags.bits.dppclk = 1; - phantom_pipe->update_flags.bits.hubp_interdependent = 1; - phantom_pipe->update_flags.bits.hubp_rq_dlg_ttu = 1; - phantom_pipe->update_flags.bits.gamut_remap = 1; - phantom_pipe->update_flags.bits.scaler = 1; - phantom_pipe->update_flags.bits.viewport = 1; - phantom_pipe->update_flags.bits.det_size = 1; - if (resource_is_pipe_type(phantom_pipe, OTG_MASTER)) { - phantom_pipe->update_flags.bits.odm = 1; - phantom_pipe->update_flags.bits.global_sync = 1; - } + if (resource_is_pipe_type(phantom_pipe, DPP_PIPE)) { + phantom_pipe->update_flags.bits.enable = 1; + phantom_pipe->update_flags.bits.mpcc = 1; + phantom_pipe->update_flags.bits.dppclk = 1; + phantom_pipe->update_flags.bits.hubp_interdependent = 1; + phantom_pipe->update_flags.bits.hubp_rq_dlg_ttu = 1; + phantom_pipe->update_flags.bits.gamut_remap = 1; + phantom_pipe->update_flags.bits.scaler = 1; + phantom_pipe->update_flags.bits.viewport = 1; + phantom_pipe->update_flags.bits.det_size = 1; + if (resource_is_pipe_type(phantom_pipe, OTG_MASTER)) { + phantom_pipe->update_flags.bits.odm = 1; + phantom_pipe->update_flags.bits.global_sync = 1; } } } @@ -1466,8 +1486,8 @@ void dcn32_enable_phantom_streams(struct dc *dc, struct dc_state *context) * 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) { + if (pipe->stream && dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM && + old_pipe->stream && dc_state_get_pipe_subvp_type(dc->current_state, old_pipe) != SUBVP_PHANTOM) { old_pipe->stream_res.tg->funcs->wait_for_state( old_pipe->stream_res.tg, CRTC_STATE_VBLANK); @@ -1479,7 +1499,7 @@ void dcn32_enable_phantom_streams(struct dc *dc, struct dc_state *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) { + if (new_pipe->stream && dc_state_get_pipe_subvp_type(context, new_pipe) == 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 diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c new file mode 100644 index 00000000000000..427cfc8c24a4b7 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c @@ -0,0 +1,169 @@ +/* + * 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 "dce110/dce110_hwseq.h" +#include "dcn10/dcn10_hwseq.h" +#include "dcn20/dcn20_hwseq.h" +#include "dcn21/dcn21_hwseq.h" +#include "dcn30/dcn30_hwseq.h" +#include "dcn31/dcn31_hwseq.h" +#include "dcn32/dcn32_hwseq.h" +#include "dcn32_init.h" + +static const struct hw_sequencer_funcs dcn32_funcs = { + .program_gamut_remap = dcn30_program_gamut_remap, + .init_hw = dcn32_init_hw, + .apply_ctx_to_hw = dce110_apply_ctx_to_hw, + .apply_ctx_for_surface = NULL, + .program_front_end_for_ctx = dcn20_program_front_end_for_ctx, + .wait_for_pending_cleared = dcn10_wait_for_pending_cleared, + .post_unlock_program_front_end = dcn20_post_unlock_program_front_end, + .update_plane_addr = dcn20_update_plane_addr, + .update_dchub = dcn10_update_dchub, + .update_pending_status = dcn10_update_pending_status, + .program_output_csc = dcn20_program_output_csc, + .enable_accelerated_mode = dce110_enable_accelerated_mode, + .enable_timing_synchronization = dcn10_enable_timing_synchronization, + .enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset, + .update_info_frame = dcn31_update_info_frame, + .send_immediate_sdp_message = dcn10_send_immediate_sdp_message, + .enable_stream = dcn20_enable_stream, + .disable_stream = dce110_disable_stream, + .unblank_stream = dcn32_unblank_stream, + .blank_stream = dce110_blank_stream, + .enable_audio_stream = dce110_enable_audio_stream, + .disable_audio_stream = dce110_disable_audio_stream, + .disable_plane = dcn20_disable_plane, + .disable_pixel_data = dcn20_disable_pixel_data, + .pipe_control_lock = dcn20_pipe_control_lock, + .interdependent_update_lock = dcn10_lock_all_pipes, + .cursor_lock = dcn10_cursor_lock, + .prepare_bandwidth = dcn32_prepare_bandwidth, + .optimize_bandwidth = dcn20_optimize_bandwidth, + .update_bandwidth = dcn20_update_bandwidth, + .set_drr = dcn10_set_drr, + .get_position = dcn10_get_position, + .set_static_screen_control = dcn30_set_static_screen_control, + .setup_stereo = dcn10_setup_stereo, + .set_avmute = dcn30_set_avmute, + .log_hw_state = dcn10_log_hw_state, + .get_hw_state = dcn10_get_hw_state, + .clear_status_bits = dcn10_clear_status_bits, + .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, + .edp_backlight_control = dce110_edp_backlight_control, + .edp_power_control = dce110_edp_power_control, + .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, + .edp_wait_for_T12 = dce110_edp_wait_for_T12, + .set_cursor_position = dcn10_set_cursor_position, + .set_cursor_attribute = dcn10_set_cursor_attribute, + .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level, + .setup_periodic_interrupt = dcn10_setup_periodic_interrupt, + .set_clock = dcn10_set_clock, + .get_clock = dcn10_get_clock, + .program_triplebuffer = dcn20_program_triple_buffer, + .enable_writeback = dcn30_enable_writeback, + .disable_writeback = dcn30_disable_writeback, + .update_writeback = dcn30_update_writeback, + .mmhubbub_warmup = dcn30_mmhubbub_warmup, + .dmdata_status_done = dcn20_dmdata_status_done, + .program_dmdata_engine = dcn30_program_dmdata_engine, + .set_dmdata_attributes = dcn20_set_dmdata_attributes, + .init_sys_ctx = dcn20_init_sys_ctx, + .init_vm_ctx = dcn20_init_vm_ctx, + .set_flip_control_gsl = dcn20_set_flip_control_gsl, + .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync, + .calc_vupdate_position = dcn10_calc_vupdate_position, + .apply_idle_power_optimizations = dcn32_apply_idle_power_optimizations, + .does_plane_fit_in_mall = NULL, + .set_backlight_level = dcn21_set_backlight_level, + .set_abm_immediate_disable = dcn21_set_abm_immediate_disable, + .hardware_release = dcn30_hardware_release, + .set_pipe = dcn21_set_pipe, + .enable_lvds_link_output = dce110_enable_lvds_link_output, + .enable_tmds_link_output = dce110_enable_tmds_link_output, + .enable_dp_link_output = dce110_enable_dp_link_output, + .disable_link_output = dcn32_disable_link_output, + .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 = dcn10_update_visual_confirm_color, + .subvp_pipe_control_lock_fast = dcn32_subvp_pipe_control_lock_fast, + .update_phantom_vp_position = dcn32_update_phantom_vp_position, + .update_dsc_pg = dcn32_update_dsc_pg, + .apply_update_flags_for_phantom = dcn32_apply_update_flags_for_phantom, + .blank_phantom = dcn32_blank_phantom, + .is_pipe_topology_transition_seamless = dcn32_is_pipe_topology_transition_seamless, +}; + +static const struct hwseq_private_funcs dcn32_private_funcs = { + .init_pipes = dcn10_init_pipes, + .update_plane_addr = dcn20_update_plane_addr, + .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, + .update_mpcc = dcn20_update_mpcc, + .set_input_transfer_func = dcn32_set_input_transfer_func, + .set_output_transfer_func = dcn32_set_output_transfer_func, + .power_down = dce110_power_down, + .enable_display_power_gating = dcn10_dummy_display_power_gating, + .blank_pixel_data = dcn20_blank_pixel_data, + .reset_hw_ctx_wrap = dcn20_reset_hw_ctx_wrap, + .enable_stream_timing = dcn20_enable_stream_timing, + .edp_backlight_control = dce110_edp_backlight_control, + .disable_stream_gating = dcn20_disable_stream_gating, + .enable_stream_gating = dcn20_enable_stream_gating, + .setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt, + .did_underflow_occur = dcn10_did_underflow_occur, + .init_blank = dcn32_init_blank, + .disable_vga = dcn20_disable_vga, + .bios_golden_init = dcn10_bios_golden_init, + .plane_atomic_disable = dcn20_plane_atomic_disable, + .plane_atomic_power_down = dcn10_plane_atomic_power_down, + .enable_power_gating_plane = dcn32_enable_power_gating_plane, + .hubp_pg_control = dcn32_hubp_pg_control, + .program_all_writeback_pipes_in_tree = dcn30_program_all_writeback_pipes_in_tree, + .update_odm = dcn32_update_odm, + .dsc_pg_control = dcn32_dsc_pg_control, + .dsc_pg_status = dcn32_dsc_pg_status, + .set_hdr_multiplier = dcn10_set_hdr_multiplier, + .verify_allow_pstate_change_high = dcn10_verify_allow_pstate_change_high, + .wait_for_blank_complete = dcn20_wait_for_blank_complete, + .dccg_init = dcn20_dccg_init, + .set_mcm_luts = dcn32_set_mcm_luts, + .program_mall_pipe_config = dcn32_program_mall_pipe_config, + .update_force_pstate = dcn32_update_force_pstate, + .update_mall_sel = dcn32_update_mall_sel, + .calculate_dccg_k1_k2_values = dcn32_calculate_dccg_k1_k2_values, + .set_pixels_per_cycle = dcn32_set_pixels_per_cycle, + .resync_fifo_dccg_dio = dcn32_resync_fifo_dccg_dio, + .is_dp_dig_pixel_rate_div_policy = dcn32_is_dp_dig_pixel_rate_div_policy, +}; + +void dcn32_hw_sequencer_init_functions(struct dc *dc) +{ + dc->hwss = dcn32_funcs; + dc->hwseq->funcs = dcn32_private_funcs; + +} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.h new file mode 100644 index 00000000000000..89a591eb2c230a --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.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_DCN32_INIT_H__ +#define __DC_DCN32_INIT_H__ + +struct dc; + +void dcn32_hw_sequencer_init_functions(struct dc *dc); + +#endif /* __DC_DCN32_INIT_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c index 5a8258287438e9..8b6c49622f3b63 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c @@ -56,6 +56,7 @@ #include "dcn30/dcn30_cm_common.h" #include "dcn31/dcn31_hwseq.h" #include "dcn20/dcn20_hwseq.h" +#include "dc_state_priv.h" #define DC_LOGGER_INIT(logger) \ struct dal_logger *dc_logger = logger @@ -133,6 +134,7 @@ void dcn35_init_hw(struct dc *dc) struct dc_bios *dcb = dc->ctx->dc_bios; struct resource_pool *res_pool = dc->res_pool; uint32_t backlight = MAX_BACKLIGHT_LEVEL; + uint32_t user_level = MAX_BACKLIGHT_LEVEL; int i; if (dc->clk_mgr && dc->clk_mgr->funcs->init_clocks) @@ -145,17 +147,36 @@ void dcn35_init_hw(struct dc *dc) hws->funcs.bios_golden_init(dc); } - REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); - REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); - - /* Disable gating for PHYASYMCLK. This will be enabled in dccg if needed */ - REG_UPDATE_5(DCCG_GATE_DISABLE_CNTL2, PHYASYMCLK_ROOT_GATE_DISABLE, 1, - PHYBSYMCLK_ROOT_GATE_DISABLE, 1, - PHYCSYMCLK_ROOT_GATE_DISABLE, 1, - PHYDSYMCLK_ROOT_GATE_DISABLE, 1, - PHYESYMCLK_ROOT_GATE_DISABLE, 1); + if (!dc->debug.disable_clock_gate) { + REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); + REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); + + /* Disable gating for PHYASYMCLK. This will be enabled in dccg if needed */ + REG_UPDATE_5(DCCG_GATE_DISABLE_CNTL2, PHYASYMCLK_ROOT_GATE_DISABLE, 1, + PHYBSYMCLK_ROOT_GATE_DISABLE, 1, + PHYCSYMCLK_ROOT_GATE_DISABLE, 1, + PHYDSYMCLK_ROOT_GATE_DISABLE, 1, + PHYESYMCLK_ROOT_GATE_DISABLE, 1); + + REG_UPDATE_4(DCCG_GATE_DISABLE_CNTL4, + DPIASYMCLK0_GATE_DISABLE, 0, + DPIASYMCLK1_GATE_DISABLE, 0, + DPIASYMCLK2_GATE_DISABLE, 0, + DPIASYMCLK3_GATE_DISABLE, 0); + + REG_WRITE(DCCG_GATE_DISABLE_CNTL5, 0xFFFFFFFF); + REG_UPDATE_4(DCCG_GATE_DISABLE_CNTL5, + DTBCLK_P0_GATE_DISABLE, 0, + DTBCLK_P1_GATE_DISABLE, 0, + DTBCLK_P2_GATE_DISABLE, 0, + DTBCLK_P3_GATE_DISABLE, 0); + REG_UPDATE_4(DCCG_GATE_DISABLE_CNTL5, + DPSTREAMCLK0_GATE_DISABLE, 0, + DPSTREAMCLK1_GATE_DISABLE, 0, + DPSTREAMCLK2_GATE_DISABLE, 0, + DPSTREAMCLK3_GATE_DISABLE, 0); - REG_WRITE(DCCG_GATE_DISABLE_CNTL5, 0x1f7c3fcf); + } // Initialize the dccg if (res_pool->dccg->funcs->dccg_init) @@ -260,13 +281,15 @@ void dcn35_init_hw(struct dc *dc) for (i = 0; i < dc->link_count; i++) { struct dc_link *link = dc->links[i]; - if (link->panel_cntl) + if (link->panel_cntl) { backlight = link->panel_cntl->funcs->hw_init(link->panel_cntl); + user_level = link->panel_cntl->stored_backlight_registers.USER_LEVEL; + } } if (dc->ctx->dmub_srv) { for (i = 0; i < dc->res_pool->pipe_count; i++) { if (abms[i] != NULL && abms[i]->funcs != NULL) - abms[i]->funcs->abm_init(abms[i], backlight); + abms[i]->funcs->abm_init(abms[i], backlight, user_level); } } @@ -332,9 +355,6 @@ void dcn35_init_hw(struct dc *dc) if (dc->res_pool->pg_cntl) { if (dc->res_pool->pg_cntl->funcs->init_pg_status) dc->res_pool->pg_cntl->funcs->init_pg_status(dc->res_pool->pg_cntl); - - if (dc->res_pool->pg_cntl->funcs->set_force_poweron_domain22) - dc->res_pool->pg_cntl->funcs->set_force_poweron_domain22(dc->res_pool->pg_cntl, false); } } @@ -660,7 +680,7 @@ void dcn35_power_down_on_boot(struct dc *dc) bool dcn35_apply_idle_power_optimizations(struct dc *dc, bool enable) { struct dc_link *edp_links[MAX_NUM_EDP]; - int edp_num; + int i, edp_num; if (dc->debug.dmcub_emulation) return true; @@ -668,14 +688,17 @@ bool dcn35_apply_idle_power_optimizations(struct dc *dc, bool enable) dc_get_edp_links(dc, edp_links, &edp_num); if (edp_num == 0 || edp_num > 1) return false; + + for (i = 0; i < dc->current_state->stream_count; ++i) { + struct dc_stream_state *stream = dc->current_state->streams[i]; + + if (!stream->dpms_off && !dc_is_embedded_signal(stream->signal)) + return false; + } } // TODO: review other cases when idle optimization is allowed - - if (!enable) - dc_dmub_srv_exit_low_power_state(dc); - else - dc_dmub_srv_notify_idle(dc, enable); + dc_dmub_srv_apply_idle_power_optimizations(dc, enable); return true; } @@ -685,7 +708,7 @@ void dcn35_z10_restore(const struct dc *dc) if (dc->debug.disable_z10) return; - dc_dmub_srv_exit_low_power_state(dc); + dc_dmub_srv_apply_idle_power_optimizations(dc, false); dcn31_z10_restore(dc); } @@ -801,12 +824,12 @@ void dcn35_init_pipes(struct dc *dc, struct dc_state *context) dc->res_pool->opps[i]->mpcc_disconnect_pending[pipe_ctx->plane_res.mpcc_inst] = true; pipe_ctx->stream_res.opp = dc->res_pool->opps[i]; - hws->funcs.plane_atomic_disconnect(dc, pipe_ctx); + hws->funcs.plane_atomic_disconnect(dc, context, pipe_ctx); if (tg->funcs->is_tg_enabled(tg)) tg->funcs->unlock(tg); - dc->hwss.disable_plane(dc, pipe_ctx); + dc->hwss.disable_plane(dc, context, pipe_ctx); pipe_ctx->stream_res.tg = NULL; pipe_ctx->plane_res.hubp = NULL; @@ -933,10 +956,10 @@ void dcn35_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) pipe_ctx->plane_state = NULL; } -void dcn35_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) +void dcn35_disable_plane(struct dc *dc, struct dc_state *state, struct pipe_ctx *pipe_ctx) { struct dce_hwseq *hws = dc->hwseq; - bool is_phantom = pipe_ctx->plane_state && pipe_ctx->plane_state->is_phantom; + bool is_phantom = dc_state_get_pipe_subvp_type(state, pipe_ctx) == SUBVP_PHANTOM; struct timing_generator *tg = is_phantom ? pipe_ctx->stream_res.tg : NULL; DC_LOGGER_INIT(dc->ctx->logger); @@ -963,6 +986,8 @@ void dcn35_calc_blocks_to_gate(struct dc *dc, struct dc_state *context, bool hpo_frl_stream_enc_acquired = false; bool hpo_dp_stream_enc_acquired = false; int i = 0, j = 0; + int edp_num = 0; + struct dc_link *edp_links[MAX_NUM_EDP] = { NULL }; memset(update_state, 0, sizeof(struct pg_block_update)); @@ -1003,10 +1028,24 @@ void dcn35_calc_blocks_to_gate(struct dc *dc, struct dc_state *context, if (pipe_ctx->stream_res.opp) update_state->pg_pipe_res_update[PG_OPP][pipe_ctx->stream_res.opp->inst] = false; + } + /*domain24 controls all the otg, mpc, opp, as long as one otg is still up, avoid enabling OTG PG*/ + for (i = 0; i < dc->res_pool->timing_generator_count; i++) { + struct timing_generator *tg = dc->res_pool->timing_generators[i]; + if (tg && tg->funcs->is_tg_enabled(tg)) { + update_state->pg_pipe_res_update[PG_OPTC][i] = false; + break; + } + } - if (pipe_ctx->stream_res.tg) - update_state->pg_pipe_res_update[PG_OPTC][pipe_ctx->stream_res.tg->inst] = false; + dc_get_edp_links(dc, edp_links, &edp_num); + if (edp_num == 0 || + ((!edp_links[0] || !edp_links[0]->edp_sink_present) && + (!edp_links[1] || !edp_links[1]->edp_sink_present))) { + /*eDP not exist on this config, keep Domain24 power on, for S0i3, this will be handled in dmubfw*/ + update_state->pg_pipe_res_update[PG_OPTC][0] = false; } + } void dcn35_calc_blocks_to_ungate(struct dc *dc, struct dc_state *context, @@ -1092,8 +1131,29 @@ void dcn35_calc_blocks_to_ungate(struct dc *dc, struct dc_state *context, } -void dcn35_block_power_control(struct dc *dc, - struct pg_block_update *update_state, bool power_on) +/** + * dcn35_hw_block_power_down() - power down sequence + * + * The following sequence describes the ON-OFF (ONO) for power down: + * + * ONO Region 3, DCPG 25: hpo - SKIPPED + * ONO Region 4, DCPG 0: dchubp0, dpp0 + * ONO Region 6, DCPG 1: dchubp1, dpp1 + * ONO Region 8, DCPG 2: dchubp2, dpp2 + * ONO Region 10, DCPG 3: dchubp3, dpp3 + * ONO Region 1, DCPG 23: dchubbub dchvm dchubbubmem - SKIPPED. PMFW will pwr dwn at IPS2 entry + * ONO Region 5, DCPG 16: dsc0 + * ONO Region 7, DCPG 17: dsc1 + * ONO Region 9, DCPG 18: dsc2 + * ONO Region 11, DCPG 19: dsc3 + * ONO Region 2, DCPG 24: mpc opp optc dwb + * ONO Region 0, DCPG 22: dccg dio dcio - SKIPPED. will be pwr dwn after lono timer is armed + * + * @dc: Current DC state + * @update_state: update PG sequence states for HW block + */ +void dcn35_hw_block_power_down(struct dc *dc, + struct pg_block_update *update_state) { int i = 0; struct pg_cntl *pg_cntl = dc->res_pool->pg_cntl; @@ -1102,64 +1162,106 @@ void dcn35_block_power_control(struct dc *dc, return; if (dc->debug.ignore_pg) return; + if (update_state->pg_res_update[PG_HPO]) { if (pg_cntl->funcs->hpo_pg_control) - pg_cntl->funcs->hpo_pg_control(pg_cntl, power_on); + pg_cntl->funcs->hpo_pg_control(pg_cntl, false); } for (i = 0; i < dc->res_pool->pipe_count; i++) { if (update_state->pg_pipe_res_update[PG_HUBP][i] && update_state->pg_pipe_res_update[PG_DPP][i]) { if (pg_cntl->funcs->hubp_dpp_pg_control) - pg_cntl->funcs->hubp_dpp_pg_control(pg_cntl, i, power_on); + pg_cntl->funcs->hubp_dpp_pg_control(pg_cntl, i, false); } - + } + for (i = 0; i < dc->res_pool->res_cap->num_dsc; i++) if (update_state->pg_pipe_res_update[PG_DSC][i]) { if (pg_cntl->funcs->dsc_pg_control) - pg_cntl->funcs->dsc_pg_control(pg_cntl, i, power_on); + pg_cntl->funcs->dsc_pg_control(pg_cntl, i, false); } - if (update_state->pg_pipe_res_update[PG_MPCC][i]) { - if (pg_cntl->funcs->mpcc_pg_control) - pg_cntl->funcs->mpcc_pg_control(pg_cntl, i, power_on); - } - if (update_state->pg_pipe_res_update[PG_OPP][i]) { - if (pg_cntl->funcs->opp_pg_control) - pg_cntl->funcs->opp_pg_control(pg_cntl, i, power_on); - } - - if (update_state->pg_pipe_res_update[PG_OPTC][i]) { - if (pg_cntl->funcs->optc_pg_control) - pg_cntl->funcs->optc_pg_control(pg_cntl, i, power_on); - } - } + /*this will need all the clients to unregister optc interruts let dmubfw handle this*/ + if (pg_cntl->funcs->plane_otg_pg_control) + pg_cntl->funcs->plane_otg_pg_control(pg_cntl, false); - if (update_state->pg_res_update[PG_DWB]) { - if (pg_cntl->funcs->dwb_pg_control) - pg_cntl->funcs->dwb_pg_control(pg_cntl, power_on); - } + //domain22, 23, 25 currently always on. - if (pg_cntl->funcs->plane_otg_pg_control) - pg_cntl->funcs->plane_otg_pg_control(pg_cntl, power_on); } -void dcn35_root_clock_control(struct dc *dc, - struct pg_block_update *update_state, bool power_on) +/** + * dcn35_hw_block_power_up() - power up sequence + * + * The following sequence describes the ON-OFF (ONO) for power up: + * + * ONO Region 0, DCPG 22: dccg dio dcio - SKIPPED + * ONO Region 2, DCPG 24: mpc opp optc dwb + * ONO Region 5, DCPG 16: dsc0 + * ONO Region 7, DCPG 17: dsc1 + * ONO Region 9, DCPG 18: dsc2 + * ONO Region 11, DCPG 19: dsc3 + * ONO Region 1, DCPG 23: dchubbub dchvm dchubbubmem - SKIPPED. PMFW will power up at IPS2 exit + * ONO Region 4, DCPG 0: dchubp0, dpp0 + * ONO Region 6, DCPG 1: dchubp1, dpp1 + * ONO Region 8, DCPG 2: dchubp2, dpp2 + * ONO Region 10, DCPG 3: dchubp3, dpp3 + * ONO Region 3, DCPG 25: hpo - SKIPPED + * + * @dc: Current DC state + * @update_state: update PG sequence states for HW block + */ +void dcn35_hw_block_power_up(struct dc *dc, + struct pg_block_update *update_state) { int i = 0; struct pg_cntl *pg_cntl = dc->res_pool->pg_cntl; if (!pg_cntl) return; + if (dc->debug.ignore_pg) + return; + //domain22, 23, 25 currently always on. + /*this will need all the clients to unregister optc interruts let dmubfw handle this*/ + if (pg_cntl->funcs->plane_otg_pg_control) + pg_cntl->funcs->plane_otg_pg_control(pg_cntl, true); + + for (i = 0; i < dc->res_pool->res_cap->num_dsc; i++) + if (update_state->pg_pipe_res_update[PG_DSC][i]) { + if (pg_cntl->funcs->dsc_pg_control) + pg_cntl->funcs->dsc_pg_control(pg_cntl, i, true); + } for (i = 0; i < dc->res_pool->pipe_count; i++) { if (update_state->pg_pipe_res_update[PG_HUBP][i] && update_state->pg_pipe_res_update[PG_DPP][i]) { - if (dc->hwseq->funcs.dpp_root_clock_control) - dc->hwseq->funcs.dpp_root_clock_control(dc->hwseq, i, power_on); + if (pg_cntl->funcs->hubp_dpp_pg_control) + pg_cntl->funcs->hubp_dpp_pg_control(pg_cntl, i, true); } + } + if (update_state->pg_res_update[PG_HPO]) { + if (pg_cntl->funcs->hpo_pg_control) + pg_cntl->funcs->hpo_pg_control(pg_cntl, true); + } +} +void dcn35_root_clock_control(struct dc *dc, + struct pg_block_update *update_state, bool power_on) +{ + int i = 0; + struct pg_cntl *pg_cntl = dc->res_pool->pg_cntl; + if (!pg_cntl) + return; + /*enable root clock first when power up*/ + if (power_on) + for (i = 0; i < dc->res_pool->pipe_count; i++) { + if (update_state->pg_pipe_res_update[PG_HUBP][i] && + update_state->pg_pipe_res_update[PG_DPP][i]) { + if (dc->hwseq->funcs.dpp_root_clock_control) + dc->hwseq->funcs.dpp_root_clock_control(dc->hwseq, i, power_on); + } + } + for (i = 0; i < dc->res_pool->res_cap->num_dsc; i++) { if (update_state->pg_pipe_res_update[PG_DSC][i]) { if (power_on) { if (dc->res_pool->dccg->funcs->enable_dsc) @@ -1170,6 +1272,15 @@ void dcn35_root_clock_control(struct dc *dc, } } } + /*disable root clock first when power down*/ + if (!power_on) + for (i = 0; i < dc->res_pool->pipe_count; i++) { + if (update_state->pg_pipe_res_update[PG_HUBP][i] && + update_state->pg_pipe_res_update[PG_DPP][i]) { + if (dc->hwseq->funcs.dpp_root_clock_control) + dc->hwseq->funcs.dpp_root_clock_control(dc->hwseq, i, power_on); + } + } } void dcn35_prepare_bandwidth( @@ -1183,9 +1294,9 @@ void dcn35_prepare_bandwidth( if (dc->hwss.root_clock_control) dc->hwss.root_clock_control(dc, &pg_update_state, true); - - if (dc->hwss.block_power_control) - dc->hwss.block_power_control(dc, &pg_update_state, true); + /*power up required HW block*/ + if (dc->hwss.hw_block_power_up) + dc->hwss.hw_block_power_up(dc, &pg_update_state); } dcn20_prepare_bandwidth(dc, context); @@ -1201,9 +1312,9 @@ void dcn35_optimize_bandwidth( if (dc->hwss.calc_blocks_to_gate) { dc->hwss.calc_blocks_to_gate(dc, context, &pg_update_state); - - if (dc->hwss.block_power_control) - dc->hwss.block_power_control(dc, &pg_update_state, false); + /*try to power down unused block*/ + if (dc->hwss.hw_block_power_down) + dc->hwss.hw_block_power_down(dc, &pg_update_state); if (dc->hwss.root_clock_control) dc->hwss.root_clock_control(dc, &pg_update_state, false); @@ -1225,3 +1336,44 @@ uint32_t dcn35_get_idle_state(const struct dc *dc) return 0; } + +void dcn35_set_drr(struct pipe_ctx **pipe_ctx, + int num_pipes, struct dc_crtc_timing_adjust adjust) +{ + int i = 0; + struct drr_params params = {0}; + // DRR set trigger event mapped to OTG_TRIG_A (bit 11) for manual control flow + unsigned int event_triggers = 0x800; + // Note DRR trigger events are generated regardless of whether num frames met. + 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) { + struct dc_crtc_timing *timing = &pipe_ctx[i]->stream->timing; + struct dc *dc = pipe_ctx[i]->stream->ctx->dc; + + if (dc->debug.static_screen_wait_frames) { + unsigned int frame_rate = timing->pix_clk_100hz / (timing->h_total * timing->v_total); + + if (frame_rate >= 120 && dc->caps.ips_support && + dc->config.disable_ips != DMUB_IPS_DISABLE_ALL) { + /*ips enable case*/ + num_frames = 2 * (frame_rate % 60); + } + } + 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, ¶ms); + 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); + } + } +} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h index 0dff10d179b86d..fd66316e33de36 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.h @@ -57,14 +57,16 @@ void dcn35_init_pipes(struct dc *dc, struct dc_state *context); void dcn35_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx); void dcn35_enable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx, struct dc_state *context); -void dcn35_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx); +void dcn35_disable_plane(struct dc *dc, struct dc_state *state, struct pipe_ctx *pipe_ctx); void dcn35_calc_blocks_to_gate(struct dc *dc, struct dc_state *context, struct pg_block_update *update_state); void dcn35_calc_blocks_to_ungate(struct dc *dc, struct dc_state *context, struct pg_block_update *update_state); -void dcn35_block_power_control(struct dc *dc, - struct pg_block_update *update_state, bool power_on); +void dcn35_hw_block_power_up(struct dc *dc, + struct pg_block_update *update_state); +void dcn35_hw_block_power_down(struct dc *dc, + struct pg_block_update *update_state); void dcn35_root_clock_control(struct dc *dc, struct pg_block_update *update_state, bool power_on); @@ -84,4 +86,8 @@ void dcn35_dsc_pg_control( void dcn35_set_idle_state(const struct dc *dc, bool allow_idle); uint32_t dcn35_get_idle_state(const struct dc *dc); + +void dcn35_set_drr(struct pipe_ctx **pipe_ctx, + int num_pipes, struct dc_crtc_timing_adjust adjust); + #endif /* __DC_HWSS_DCN35_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c new file mode 100644 index 00000000000000..a630aa77dcec03 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.c @@ -0,0 +1,172 @@ +/* SPDX-License-Identifier: MIT */ +/* + * 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 "dce110/dce110_hwseq.h" +#include "dcn10/dcn10_hwseq.h" +#include "dcn20/dcn20_hwseq.h" +#include "dcn21/dcn21_hwseq.h" +#include "dcn30/dcn30_hwseq.h" +#include "dcn301/dcn301_hwseq.h" +#include "dcn31/dcn31_hwseq.h" +#include "dcn32/dcn32_hwseq.h" +#include "dcn35/dcn35_hwseq.h" + +#include "dcn35_init.h" + +static const struct hw_sequencer_funcs dcn35_funcs = { + .program_gamut_remap = dcn30_program_gamut_remap, + .init_hw = dcn35_init_hw, + .power_down_on_boot = dcn35_power_down_on_boot, + .apply_ctx_to_hw = dce110_apply_ctx_to_hw, + .apply_ctx_for_surface = NULL, + .program_front_end_for_ctx = dcn20_program_front_end_for_ctx, + .wait_for_pending_cleared = dcn10_wait_for_pending_cleared, + .post_unlock_program_front_end = dcn20_post_unlock_program_front_end, + .update_plane_addr = dcn20_update_plane_addr, + .update_dchub = dcn10_update_dchub, + .update_pending_status = dcn10_update_pending_status, + .program_output_csc = dcn20_program_output_csc, + .enable_accelerated_mode = dce110_enable_accelerated_mode, + .enable_timing_synchronization = dcn10_enable_timing_synchronization, + .enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset, + .update_info_frame = dcn31_update_info_frame, + .send_immediate_sdp_message = dcn10_send_immediate_sdp_message, + .enable_stream = dcn20_enable_stream, + .disable_stream = dce110_disable_stream, + .unblank_stream = dcn32_unblank_stream, + .blank_stream = dce110_blank_stream, + .enable_audio_stream = dce110_enable_audio_stream, + .disable_audio_stream = dce110_disable_audio_stream, + .disable_plane = dcn35_disable_plane, + .disable_pixel_data = dcn20_disable_pixel_data, + .pipe_control_lock = dcn20_pipe_control_lock, + .interdependent_update_lock = dcn10_lock_all_pipes, + .cursor_lock = dcn10_cursor_lock, + .prepare_bandwidth = dcn35_prepare_bandwidth, + .optimize_bandwidth = dcn35_optimize_bandwidth, + .update_bandwidth = dcn20_update_bandwidth, + .set_drr = dcn35_set_drr, + .get_position = dcn10_get_position, + .set_static_screen_control = dcn30_set_static_screen_control, + .setup_stereo = dcn10_setup_stereo, + .set_avmute = dcn30_set_avmute, + .log_hw_state = dcn10_log_hw_state, + .get_hw_state = dcn10_get_hw_state, + .clear_status_bits = dcn10_clear_status_bits, + .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, + .edp_backlight_control = dce110_edp_backlight_control, + .edp_power_control = dce110_edp_power_control, + .edp_wait_for_T12 = dce110_edp_wait_for_T12, + .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, + .set_cursor_position = dcn10_set_cursor_position, + .set_cursor_attribute = dcn10_set_cursor_attribute, + .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level, + .setup_periodic_interrupt = dcn10_setup_periodic_interrupt, + .set_clock = dcn10_set_clock, + .get_clock = dcn10_get_clock, + .program_triplebuffer = dcn20_program_triple_buffer, + .enable_writeback = dcn30_enable_writeback, + .disable_writeback = dcn30_disable_writeback, + .update_writeback = dcn30_update_writeback, + .mmhubbub_warmup = dcn30_mmhubbub_warmup, + .dmdata_status_done = dcn20_dmdata_status_done, + .program_dmdata_engine = dcn30_program_dmdata_engine, + .set_dmdata_attributes = dcn20_set_dmdata_attributes, + .init_sys_ctx = dcn31_init_sys_ctx, + .init_vm_ctx = dcn20_init_vm_ctx, + .set_flip_control_gsl = dcn20_set_flip_control_gsl, + .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync, + .calc_vupdate_position = dcn10_calc_vupdate_position, + .power_down = dce110_power_down, + .set_backlight_level = dcn21_set_backlight_level, + .set_abm_immediate_disable = dcn21_set_abm_immediate_disable, + .set_pipe = dcn21_set_pipe, + .enable_lvds_link_output = dce110_enable_lvds_link_output, + .enable_tmds_link_output = dce110_enable_tmds_link_output, + .enable_dp_link_output = dce110_enable_dp_link_output, + .disable_link_output = dcn32_disable_link_output, + .z10_restore = dcn35_z10_restore, + .z10_save_init = dcn31_z10_save_init, + .set_disp_pattern_generator = dcn30_set_disp_pattern_generator, + .optimize_pwr_state = dcn21_optimize_pwr_state, + .exit_optimized_pwr_state = dcn21_exit_optimized_pwr_state, + .update_visual_confirm_color = dcn10_update_visual_confirm_color, + .apply_idle_power_optimizations = dcn35_apply_idle_power_optimizations, + .update_dsc_pg = dcn32_update_dsc_pg, + .calc_blocks_to_gate = dcn35_calc_blocks_to_gate, + .calc_blocks_to_ungate = dcn35_calc_blocks_to_ungate, + .hw_block_power_up = dcn35_hw_block_power_up, + .hw_block_power_down = dcn35_hw_block_power_down, + .root_clock_control = dcn35_root_clock_control, + .set_idle_state = dcn35_set_idle_state, + .get_idle_state = dcn35_get_idle_state +}; + +static const struct hwseq_private_funcs dcn35_private_funcs = { + .init_pipes = dcn35_init_pipes, + .update_plane_addr = dcn20_update_plane_addr, + .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, + .update_mpcc = dcn20_update_mpcc, + .set_input_transfer_func = dcn32_set_input_transfer_func, + .set_output_transfer_func = dcn32_set_output_transfer_func, + .power_down = dce110_power_down, + .enable_display_power_gating = dcn10_dummy_display_power_gating, + .blank_pixel_data = dcn20_blank_pixel_data, + .reset_hw_ctx_wrap = dcn31_reset_hw_ctx_wrap, + .enable_stream_timing = dcn20_enable_stream_timing, + .edp_backlight_control = dce110_edp_backlight_control, + .setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt, + .did_underflow_occur = dcn10_did_underflow_occur, + .init_blank = dcn20_init_blank, + .disable_vga = NULL, + .bios_golden_init = dcn10_bios_golden_init, + .plane_atomic_disable = dcn35_plane_atomic_disable, + //.plane_atomic_disable = dcn20_plane_atomic_disable,/*todo*/ + //.hubp_pg_control = dcn35_hubp_pg_control, + .enable_power_gating_plane = dcn35_enable_power_gating_plane, + .dpp_root_clock_control = dcn35_dpp_root_clock_control, + .program_all_writeback_pipes_in_tree = dcn30_program_all_writeback_pipes_in_tree, + .update_odm = dcn35_update_odm, + .set_hdr_multiplier = dcn10_set_hdr_multiplier, + .verify_allow_pstate_change_high = dcn10_verify_allow_pstate_change_high, + .wait_for_blank_complete = dcn20_wait_for_blank_complete, + .dccg_init = dcn20_dccg_init, + .set_mcm_luts = dcn32_set_mcm_luts, + .setup_hpo_hw_control = dcn35_setup_hpo_hw_control, + .calculate_dccg_k1_k2_values = dcn32_calculate_dccg_k1_k2_values, + .set_pixels_per_cycle = dcn32_set_pixels_per_cycle, + .is_dp_dig_pixel_rate_div_policy = dcn32_is_dp_dig_pixel_rate_div_policy, + .dsc_pg_control = dcn35_dsc_pg_control, + .dsc_pg_status = dcn32_dsc_pg_status, + .enable_plane = dcn35_enable_plane, +}; + +void dcn35_hw_sequencer_construct(struct dc *dc) +{ + dc->hwss = dcn35_funcs; + dc->hwseq->funcs = dcn35_private_funcs; + +} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.h new file mode 100644 index 00000000000000..b67015032c3513 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_init.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: MIT */ +/* + * 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_DCN35_INIT_H__ +#define __DC_DCN35_INIT_H__ + +struct dc; + +void dcn35_hw_sequencer_construct(struct dc *dc); + +#endif /* __DC_DCN35_INIT_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn351/CMakeLists.txt b/drivers/gpu/drm/amd/display/dc/hwss/dcn351/CMakeLists.txt new file mode 100644 index 00000000000000..951ca2da4486f2 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn351/CMakeLists.txt @@ -0,0 +1,4 @@ +dal3_subdirectory_sources( + dcn351_init.c + dcn351_init.h +) diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn351/Makefile b/drivers/gpu/drm/amd/display/dc/hwss/dcn351/Makefile new file mode 100644 index 00000000000000..b24ad27fe6ef07 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn351/Makefile @@ -0,0 +1,17 @@ +# +# (c) Copyright 2022 Advanced Micro Devices, Inc. All the rights reserved +# +# All rights reserved. This notice is intended as a precaution against +# inadvertent publication and does not imply publication or any waiver +# of confidentiality. The year included in the foregoing notice is the +# year of creation of the work. +# +# Authors: AMD +# +# Makefile for DCN351. + +DCN351 = dcn351_init.o + +AMD_DAL_DCN351 = $(addprefix $(AMDDALPATH)/dc/dcn351/,$(DCN351)) + +AMD_DISPLAY_FILES += $(AMD_DAL_DCN351) diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c new file mode 100644 index 00000000000000..143d3fc0221cf8 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.c @@ -0,0 +1,171 @@ +/* + * 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 "dce110/dce110_hwseq.h" +#include "dcn10/dcn10_hwseq.h" +#include "dcn20/dcn20_hwseq.h" +#include "dcn21/dcn21_hwseq.h" +#include "dcn30/dcn30_hwseq.h" +#include "dcn301/dcn301_hwseq.h" +#include "dcn31/dcn31_hwseq.h" +#include "dcn32/dcn32_hwseq.h" +#include "dcn35/dcn35_hwseq.h" + +#include "dcn351_init.h" + +static const struct hw_sequencer_funcs dcn351_funcs = { + .program_gamut_remap = dcn30_program_gamut_remap, + .init_hw = dcn35_init_hw, + .power_down_on_boot = dcn35_power_down_on_boot, + .apply_ctx_to_hw = dce110_apply_ctx_to_hw, + .apply_ctx_for_surface = NULL, + .program_front_end_for_ctx = dcn20_program_front_end_for_ctx, + .wait_for_pending_cleared = dcn10_wait_for_pending_cleared, + .post_unlock_program_front_end = dcn20_post_unlock_program_front_end, + .update_plane_addr = dcn20_update_plane_addr, + .update_dchub = dcn10_update_dchub, + .update_pending_status = dcn10_update_pending_status, + .program_output_csc = dcn20_program_output_csc, + .enable_accelerated_mode = dce110_enable_accelerated_mode, + .enable_timing_synchronization = dcn10_enable_timing_synchronization, + .enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset, + .update_info_frame = dcn31_update_info_frame, + .send_immediate_sdp_message = dcn10_send_immediate_sdp_message, + .enable_stream = dcn20_enable_stream, + .disable_stream = dce110_disable_stream, + .unblank_stream = dcn32_unblank_stream, + .blank_stream = dce110_blank_stream, + .enable_audio_stream = dce110_enable_audio_stream, + .disable_audio_stream = dce110_disable_audio_stream, + .disable_plane = dcn35_disable_plane, + .disable_pixel_data = dcn20_disable_pixel_data, + .pipe_control_lock = dcn20_pipe_control_lock, + .interdependent_update_lock = dcn10_lock_all_pipes, + .cursor_lock = dcn10_cursor_lock, + .prepare_bandwidth = dcn35_prepare_bandwidth, + .optimize_bandwidth = dcn35_optimize_bandwidth, + .update_bandwidth = dcn20_update_bandwidth, + .set_drr = dcn10_set_drr, + .get_position = dcn10_get_position, + .set_static_screen_control = dcn30_set_static_screen_control, + .setup_stereo = dcn10_setup_stereo, + .set_avmute = dcn30_set_avmute, + .log_hw_state = dcn10_log_hw_state, + .get_hw_state = dcn10_get_hw_state, + .clear_status_bits = dcn10_clear_status_bits, + .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, + .edp_backlight_control = dce110_edp_backlight_control, + .edp_power_control = dce110_edp_power_control, + .edp_wait_for_T12 = dce110_edp_wait_for_T12, + .edp_wait_for_hpd_ready = dce110_edp_wait_for_hpd_ready, + .set_cursor_position = dcn10_set_cursor_position, + .set_cursor_attribute = dcn10_set_cursor_attribute, + .set_cursor_sdr_white_level = dcn10_set_cursor_sdr_white_level, + .setup_periodic_interrupt = dcn10_setup_periodic_interrupt, + .set_clock = dcn10_set_clock, + .get_clock = dcn10_get_clock, + .program_triplebuffer = dcn20_program_triple_buffer, + .enable_writeback = dcn30_enable_writeback, + .disable_writeback = dcn30_disable_writeback, + .update_writeback = dcn30_update_writeback, + .mmhubbub_warmup = dcn30_mmhubbub_warmup, + .dmdata_status_done = dcn20_dmdata_status_done, + .program_dmdata_engine = dcn30_program_dmdata_engine, + .set_dmdata_attributes = dcn20_set_dmdata_attributes, + .init_sys_ctx = dcn31_init_sys_ctx, + .init_vm_ctx = dcn20_init_vm_ctx, + .set_flip_control_gsl = dcn20_set_flip_control_gsl, + .get_vupdate_offset_from_vsync = dcn10_get_vupdate_offset_from_vsync, + .calc_vupdate_position = dcn10_calc_vupdate_position, + .power_down = dce110_power_down, + .set_backlight_level = dcn21_set_backlight_level, + .set_abm_immediate_disable = dcn21_set_abm_immediate_disable, + .set_pipe = dcn21_set_pipe, + .enable_lvds_link_output = dce110_enable_lvds_link_output, + .enable_tmds_link_output = dce110_enable_tmds_link_output, + .enable_dp_link_output = dce110_enable_dp_link_output, + .disable_link_output = dcn32_disable_link_output, + .z10_restore = dcn35_z10_restore, + .z10_save_init = dcn31_z10_save_init, + .set_disp_pattern_generator = dcn30_set_disp_pattern_generator, + .optimize_pwr_state = dcn21_optimize_pwr_state, + .exit_optimized_pwr_state = dcn21_exit_optimized_pwr_state, + .update_visual_confirm_color = dcn10_update_visual_confirm_color, + .apply_idle_power_optimizations = dcn35_apply_idle_power_optimizations, + .update_dsc_pg = dcn32_update_dsc_pg, + .calc_blocks_to_gate = dcn35_calc_blocks_to_gate, + .calc_blocks_to_ungate = dcn35_calc_blocks_to_ungate, + .hw_block_power_up = dcn35_hw_block_power_up, + .hw_block_power_down = dcn35_hw_block_power_down, + .root_clock_control = dcn35_root_clock_control, + .set_idle_state = dcn35_set_idle_state, + .get_idle_state = dcn35_get_idle_state +}; + +static const struct hwseq_private_funcs dcn351_private_funcs = { + .init_pipes = dcn35_init_pipes, + .update_plane_addr = dcn20_update_plane_addr, + .plane_atomic_disconnect = dcn10_plane_atomic_disconnect, + .update_mpcc = dcn20_update_mpcc, + .set_input_transfer_func = dcn32_set_input_transfer_func, + .set_output_transfer_func = dcn32_set_output_transfer_func, + .power_down = dce110_power_down, + .enable_display_power_gating = dcn10_dummy_display_power_gating, + .blank_pixel_data = dcn20_blank_pixel_data, + .reset_hw_ctx_wrap = dcn31_reset_hw_ctx_wrap, + .enable_stream_timing = dcn20_enable_stream_timing, + .edp_backlight_control = dce110_edp_backlight_control, + .setup_vupdate_interrupt = dcn20_setup_vupdate_interrupt, + .did_underflow_occur = dcn10_did_underflow_occur, + .init_blank = dcn20_init_blank, + .disable_vga = NULL, + .bios_golden_init = dcn10_bios_golden_init, + .plane_atomic_disable = dcn35_plane_atomic_disable, + //.plane_atomic_disable = dcn20_plane_atomic_disable,/*todo*/ + //.hubp_pg_control = dcn35_hubp_pg_control, + .enable_power_gating_plane = dcn35_enable_power_gating_plane, + .dpp_root_clock_control = dcn35_dpp_root_clock_control, + .program_all_writeback_pipes_in_tree = dcn30_program_all_writeback_pipes_in_tree, + .update_odm = dcn35_update_odm, + .set_hdr_multiplier = dcn10_set_hdr_multiplier, + .verify_allow_pstate_change_high = dcn10_verify_allow_pstate_change_high, + .wait_for_blank_complete = dcn20_wait_for_blank_complete, + .dccg_init = dcn20_dccg_init, + .set_mcm_luts = dcn32_set_mcm_luts, + .setup_hpo_hw_control = dcn35_setup_hpo_hw_control, + .calculate_dccg_k1_k2_values = dcn32_calculate_dccg_k1_k2_values, + .set_pixels_per_cycle = dcn32_set_pixels_per_cycle, + .is_dp_dig_pixel_rate_div_policy = dcn32_is_dp_dig_pixel_rate_div_policy, + .dsc_pg_control = dcn35_dsc_pg_control, + .dsc_pg_status = dcn32_dsc_pg_status, + .enable_plane = dcn35_enable_plane, +}; + +void dcn351_hw_sequencer_construct(struct dc *dc) +{ + dc->hwss = dcn351_funcs; + dc->hwseq->funcs = dcn351_private_funcs; + +} diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.h new file mode 100644 index 00000000000000..970b01008b238b --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn351/dcn351_init.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 __DC_DCN351_INIT_H__ +#define __DC_DCN351_INIT_H__ + +struct dc; + +void dcn351_hw_sequencer_construct(struct dc *dc); + +#endif /* __DC_DCN351_INIT_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h index 452680fe9aabd5..a5439938331814 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h @@ -50,7 +50,7 @@ struct pg_block_update; struct subvp_pipe_control_lock_fast_params { struct dc *dc; bool lock; - struct pipe_ctx *pipe_ctx; + bool subvp_immediate_flip; }; struct pipe_control_lock_params { @@ -200,7 +200,7 @@ struct hw_sequencer_funcs { struct dc_state *context); enum dc_status (*apply_ctx_to_hw)(struct dc *dc, struct dc_state *context); - void (*disable_plane)(struct dc *dc, struct pipe_ctx *pipe_ctx); + void (*disable_plane)(struct dc *dc, struct dc_state *state, struct pipe_ctx *pipe_ctx); void (*disable_pixel_data)(struct dc *dc, struct pipe_ctx *pipe_ctx, bool blank); void (*apply_ctx_for_surface)(struct dc *dc, const struct dc_stream_state *stream, @@ -248,6 +248,7 @@ struct hw_sequencer_funcs { void (*enable_per_frame_crtc_position_reset)(struct dc *dc, int group_size, struct pipe_ctx *grouped_pipes[]); void (*enable_timing_synchronization)(struct dc *dc, + struct dc_state *state, int group_index, int group_size, struct pipe_ctx *grouped_pipes[]); void (*enable_vblanks_synchronization)(struct dc *dc, @@ -414,8 +415,10 @@ struct hw_sequencer_funcs { struct pg_block_update *update_state); void (*calc_blocks_to_ungate)(struct dc *dc, struct dc_state *context, struct pg_block_update *update_state); - void (*block_power_control)(struct dc *dc, - struct pg_block_update *update_state, bool power_on); + void (*hw_block_power_up)(struct dc *dc, + struct pg_block_update *update_state); + void (*hw_block_power_down)(struct dc *dc, + struct pg_block_update *update_state); void (*root_clock_control)(struct dc *dc, struct pg_block_update *update_state, bool power_on); void (*set_idle_state)(const struct dc *dc, bool allow_idle); @@ -452,17 +455,18 @@ void get_mpctree_visual_confirm_color( struct tg_color *color); void get_subvp_visual_confirm_color( - struct dc *dc, - struct dc_state *context, struct pipe_ctx *pipe_ctx, struct tg_color *color); void get_mclk_switch_visual_confirm_color( - struct dc *dc, - struct dc_state *context, struct pipe_ctx *pipe_ctx, struct tg_color *color); +void set_p_state_switch_method( + struct dc *dc, + struct dc_state *context, + struct pipe_ctx *pipe_ctx); + void hwss_execute_sequence(struct dc *dc, struct block_sequence block_sequence[], int num_steps); @@ -472,7 +476,8 @@ void hwss_build_fast_sequence(struct dc *dc, unsigned int dmub_cmd_count, struct block_sequence block_sequence[], int *num_steps, - struct pipe_ctx *pipe_ctx); + struct pipe_ctx *pipe_ctx, + struct dc_stream_status *stream_status); void hwss_send_dmcub_cmd(union block_sequence_params *params); diff --git a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h index 82c5921668754c..6137cf09aa54d2 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h @@ -79,6 +79,7 @@ struct hwseq_private_funcs { void (*update_plane_addr)(const struct dc *dc, struct pipe_ctx *pipe_ctx); void (*plane_atomic_disconnect)(struct dc *dc, + struct dc_state *state, struct pipe_ctx *pipe_ctx); void (*update_mpcc)(struct dc *dc, struct pipe_ctx *pipe_ctx); bool (*set_input_transfer_func)(struct dc *dc, 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 bac1420b1de84f..f74ae0d41d3c49 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -200,11 +200,8 @@ struct resource_funcs { unsigned int pipe_cnt, unsigned int index); - bool (*remove_phantom_pipes)(struct dc *dc, struct dc_state *context, bool fast_update); - void (*retain_phantom_pipes)(struct dc *dc, struct dc_state *context); void (*get_panel_config_defaults)(struct dc_panel_config *panel_config); - void (*save_mall_state)(struct dc *dc, struct dc_state *context, struct mall_temp_config *temp_config); - void (*restore_mall_state)(struct dc *dc, struct dc_state *context, struct mall_temp_config *temp_config); + void (*build_pipe_pix_clk_params)(struct pipe_ctx *pipe_ctx); }; struct audio_support{ @@ -384,6 +381,16 @@ union pipe_update_flags { uint32_t raw; }; +enum p_state_switch_method { + P_STATE_UNKNOWN = 0, + P_STATE_V_BLANK = 1, + P_STATE_FPO, + P_STATE_V_ACTIVE, + P_STATE_SUB_VP, + P_STATE_DRR_SUB_VP, + P_STATE_V_BLANK_SUB_VP +}; + struct pipe_ctx { struct dc_plane_state *plane_state; struct dc_stream_state *stream; @@ -432,6 +439,7 @@ struct pipe_ctx { struct dwbc *dwbc; struct mcif_wb *mcif_wb; union pipe_update_flags update_flags; + enum p_state_switch_method p_state_type; struct tg_color visual_confirm_color; bool has_vactive_margin; /* subvp_index: only valid if the pipe is a SUBVP_MAIN*/ @@ -525,6 +533,14 @@ struct dc_state { * @stream_status: Planes status on a given stream */ struct dc_stream_status stream_status[MAX_PIPES]; + /** + * @phantom_streams: Stream state properties for phantoms + */ + struct dc_stream_state *phantom_streams[MAX_PHANTOM_PIPES]; + /** + * @phantom_planes: Planes state properties for phantoms + */ + struct dc_plane_state *phantom_planes[MAX_PHANTOM_PIPES]; /** * @stream_count: Total of streams in use @@ -532,6 +548,14 @@ struct dc_state { uint8_t stream_count; uint8_t stream_mask; + /** + * @stream_count: Total phantom streams in use + */ + uint8_t phantom_stream_count; + /** + * @stream_count: Total phantom planes in use + */ + uint8_t phantom_plane_count; /** * @res_ctx: Persistent state of resources */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/abm.h b/drivers/gpu/drm/amd/display/dc/inc/hw/abm.h index 33db15d69f2337..3f0161d6467556 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/abm.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/abm.h @@ -36,7 +36,7 @@ struct abm { }; struct abm_funcs { - void (*abm_init)(struct abm *abm, uint32_t back_light); + void (*abm_init)(struct abm *abm, uint32_t back_light, uint32_t user_level); bool (*set_abm_level)(struct abm *abm, unsigned int abm_level); bool (*set_abm_immediate_disable)(struct abm *abm, unsigned int panel_inst); bool (*set_pipe)(struct abm *abm, unsigned int controller_id, unsigned int panel_inst); @@ -64,7 +64,8 @@ struct abm_funcs { bool (*set_pipe_ex)(struct abm *abm, unsigned int otg_inst, unsigned int option, - unsigned int panel_inst); + unsigned int panel_inst, + unsigned int pwrseq_inst); }; #endif diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h index fa9614bcb1605f..17e014d3bdc840 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h @@ -62,6 +62,25 @@ struct dcn3_clk_internal { uint32_t CLK4_CLK0_CURRENT_CNT; //fclk }; +struct dcn35_clk_internal { + int dummy; + uint32_t CLK1_CLK0_CURRENT_CNT; //dispclk + uint32_t CLK1_CLK1_CURRENT_CNT; //dppclk + uint32_t CLK1_CLK2_CURRENT_CNT; //dprefclk + uint32_t CLK1_CLK3_CURRENT_CNT; //dcfclk + uint32_t CLK1_CLK4_CURRENT_CNT; //dtbclk + //uint32_t CLK1_CLK5_CURRENT_CNT; //dpiaclk + //uint32_t CLK1_CLK6_CURRENT_CNT; //srdbgclk + uint32_t CLK1_CLK3_DS_CNTL; //dcf_deep_sleep_divider + uint32_t CLK1_CLK3_ALLOW_DS; //dcf_deep_sleep_allow + + uint32_t CLK1_CLK0_BYPASS_CNTL; //dispclk bypass + uint32_t CLK1_CLK1_BYPASS_CNTL; //dppclk bypass + uint32_t CLK1_CLK2_BYPASS_CNTL; //dprefclk bypass + uint32_t CLK1_CLK3_BYPASS_CNTL; //dcfclk bypass + uint32_t CLK1_CLK4_BYPASS_CNTL; //dtbclk bypass +}; + struct dcn301_clk_internal { int dummy; uint32_t CLK1_CLK0_CURRENT_CNT; //dispclk @@ -314,6 +333,7 @@ struct clk_mgr { bool force_smu_not_present; bool dc_mode_softmax_enabled; int dprefclk_khz; // Used by program pixel clock in clock source funcs, need to figureout where this goes + int dp_dto_source_clock_in_khz; // Used to program DP DTO with ss adjustment on DCN314 int dentist_vco_freq_khz; struct clk_state_registers_and_bypass boot_snapshot; struct clk_bw_params *bw_params; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h index ce2f0c0e82bd65..b9a06bf84cc97f 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h @@ -59,8 +59,8 @@ enum dentist_dispclk_change_mode { struct dp_dto_params { int otg_inst; enum signal_type signal; - long long pixclk_hz; - long long refclk_hz; + uint64_t pixclk_hz; + uint64_t refclk_hz; }; enum pixel_rate_div { @@ -201,6 +201,10 @@ struct dccg_funcs { struct dccg *dccg, enum streamclk_source src, uint32_t otg_inst); + void (*set_dto_dscclk)( + struct dccg *dccg, + uint32_t dsc_inst); + void (*set_ref_dscclk)(struct dccg *dccg, uint32_t dsc_inst); }; #endif //__DAL_DCCG_H__ diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dsc.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dsc.h deleted file mode 100644 index 4b27f29d0d80d9..00000000000000 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dsc.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2017 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_DSC_H__ -#define __DAL_DSC_H__ - -#include "dc_dsc.h" -#include "dc_hw_types.h" -#include "dc_types.h" -/* do not include any other headers - * or else it might break Edid Utility functionality. - */ - - -/* Input parameters for configuring DSC from the outside of DSC */ -struct dsc_config { - uint32_t pic_width; - uint32_t pic_height; - enum dc_pixel_encoding pixel_encoding; - enum dc_color_depth color_depth; /* Bits per component */ - bool is_odm; - struct dc_dsc_config dc_dsc_cfg; -}; - - -/* Output parameters for configuring DSC-related part of OPTC */ -struct dsc_optc_config { - uint32_t slice_width; /* Slice width in pixels */ - uint32_t bytes_per_pixel; /* Bytes per pixel in u3.28 format */ - bool is_pixel_format_444; /* 'true' if pixel format is 'RGB 444' or 'Simple YCbCr 4:2:2' (4:2:2 upsampled to 4:4:4)' */ -}; - - -struct dcn_dsc_state { - uint32_t dsc_clock_en; - uint32_t dsc_slice_width; - uint32_t dsc_bits_per_pixel; - uint32_t dsc_slice_height; - uint32_t dsc_pic_width; - uint32_t dsc_pic_height; - uint32_t dsc_slice_bpg_offset; - uint32_t dsc_chunk_size; - uint32_t dsc_fw_en; - uint32_t dsc_opp_source; -}; - - -/* DSC encoder capabilities - * They differ from the DPCD DSC caps because they are based on AMD DSC encoder caps. - */ -union dsc_enc_slice_caps { - struct { - uint8_t NUM_SLICES_1 : 1; - uint8_t NUM_SLICES_2 : 1; - uint8_t NUM_SLICES_3 : 1; /* This one is not per DSC spec, but our encoder supports it */ - uint8_t NUM_SLICES_4 : 1; - uint8_t NUM_SLICES_8 : 1; - uint8_t NUM_SLICES_12 : 1; - uint8_t NUM_SLICES_16 : 1; - } bits; - uint8_t raw; -}; - -struct dsc_enc_caps { - uint8_t dsc_version; - union dsc_enc_slice_caps slice_caps; - int32_t lb_bit_depth; - bool is_block_pred_supported; - union dsc_color_formats color_formats; - union dsc_color_depth color_depth; - int32_t max_total_throughput_mps; /* Maximum total throughput with all the slices combined */ - int32_t max_slice_width; - uint32_t bpp_increment_div; /* bpp increment divisor, e.g. if 16, it's 1/16th of a bit */ - uint32_t edp_sink_max_bits_per_pixel; - bool is_dp; -}; - -struct dsc_funcs { - void (*dsc_get_enc_caps)(struct dsc_enc_caps *dsc_enc_caps, int pixel_clock_100Hz); - void (*dsc_read_state)(struct display_stream_compressor *dsc, struct dcn_dsc_state *s); - bool (*dsc_validate_stream)(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg); - void (*dsc_set_config)(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg, - struct dsc_optc_config *dsc_optc_cfg); - bool (*dsc_get_packed_pps)(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg, - uint8_t *dsc_packed_pps); - void (*dsc_enable)(struct display_stream_compressor *dsc, int opp_pipe); - void (*dsc_disable)(struct display_stream_compressor *dsc); - void (*dsc_disconnect)(struct display_stream_compressor *dsc); -}; - -#endif diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dwb.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dwb.h index 86b711dcc78586..729ca0064e94d5 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dwb.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dwb.h @@ -188,6 +188,10 @@ struct dwbc_funcs { bool (*is_enabled)( struct dwbc *dwbc); + void (*set_fc_enable)( + struct dwbc *dwbc, + enum dwb_frame_capture_enable enable); + void (*set_stereo)( struct dwbc *dwbc, struct dwb_stereo_params *stereo_params); diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h b/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h index b95ae9596c3b1e..dcae23faeee3d3 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h @@ -43,6 +43,7 @@ * to be used inside loops and for determining array sizes. */ #define MAX_PIPES 6 +#define MAX_PHANTOM_PIPES (MAX_PIPES / 2) #define MAX_DIG_LINK_ENCODERS 7 #define MAX_DWB_PIPES 1 #define MAX_HPO_DP2_ENCODERS 4 diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/panel_cntl.h b/drivers/gpu/drm/amd/display/dc/inc/hw/panel_cntl.h index 24af9d80b9373a..5dcbaa2db964ae 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/panel_cntl.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/panel_cntl.h @@ -40,6 +40,7 @@ struct panel_cntl_backlight_registers { unsigned int BL_PWM_PERIOD_CNTL; unsigned int LVTMA_PWRSEQ_REF_DIV_BL_PWM_REF_DIV; unsigned int PANEL_PWRSEQ_REF_DIV2; + unsigned int USER_LEVEL; }; struct panel_cntl_funcs { @@ -56,12 +57,14 @@ struct panel_cntl_funcs { struct panel_cntl_init_data { struct dc_context *ctx; uint32_t inst; + uint32_t pwrseq_inst; }; struct panel_cntl { const struct panel_cntl_funcs *funcs; struct dc_context *ctx; uint32_t inst; + uint32_t pwrseq_inst; /* registers setting needs to be saved and restored at InitBacklight */ struct panel_cntl_backlight_registers stored_backlight_registers; }; diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/pg_cntl.h b/drivers/gpu/drm/amd/display/dc/inc/hw/pg_cntl.h index b9812afb886be1..00ea3864dd4df4 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/pg_cntl.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/pg_cntl.h @@ -47,8 +47,6 @@ struct pg_cntl_funcs { void (*optc_pg_control)(struct pg_cntl *pg_cntl, unsigned int optc_inst, bool power_on); void (*dwb_pg_control)(struct pg_cntl *pg_cntl, bool power_on); void (*init_pg_status)(struct pg_cntl *pg_cntl); - - void (*set_force_poweron_domain22)(struct pg_cntl *pg_cntl, bool power_on); }; #endif //__DC_PG_CNTL_H__ diff --git a/drivers/gpu/drm/amd/display/dc/inc/link.h b/drivers/gpu/drm/amd/display/dc/inc/link.h index d7685368140ab5..26fe81f213da55 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/link.h +++ b/drivers/gpu/drm/amd/display/dc/inc/link.h @@ -281,11 +281,16 @@ struct link_service { const unsigned int *power_opts); bool (*edp_setup_replay)(struct dc_link *link, const struct dc_stream_state *stream); + bool (*edp_send_replay_cmd)(struct dc_link *link, + enum replay_FW_Message_type msg, + union dmub_replay_cmd_set *cmd_data); bool (*edp_set_coasting_vtotal)( struct dc_link *link, uint16_t coasting_vtotal); bool (*edp_replay_residency)(const struct dc_link *link, unsigned int *residency, const bool is_start, const bool is_alpm); + bool (*edp_set_replay_power_opt_and_coasting_vtotal)(struct dc_link *link, + const unsigned int *power_opts, uint16_t coasting_vtotal); bool (*edp_wait_for_t12)(struct dc_link *link); bool (*edp_is_ilr_optimization_required)(struct dc_link *link, diff --git a/drivers/gpu/drm/amd/display/dc/inc/resource.h b/drivers/gpu/drm/amd/display/dc/inc/resource.h index 06ca8bfb91e7dd..c958ef37b78a66 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/resource.h +++ b/drivers/gpu/drm/amd/display/dc/inc/resource.h @@ -500,6 +500,18 @@ int recource_find_free_pipe_not_used_in_cur_res_ctx( struct resource_context *new_res_ctx, const struct resource_pool *pool); +/* + * Look for a free pipe in new resource context that is used in current resource + * context as an OTG master pipe. + * + * return - FREE_PIPE_INDEX_NOT_FOUND if free pipe is not found, otherwise + * pipe idx of the free pipe + */ +int recource_find_free_pipe_used_as_otg_master_in_cur_res_ctx( + const struct resource_context *cur_res_ctx, + struct resource_context *new_res_ctx, + const struct resource_pool *pool); + /* * Look for a free pipe in new resource context that is used as a secondary DPP * pipe in any MPCC combine in current resource context. @@ -561,9 +573,6 @@ void update_audio_usage( unsigned int resource_pixel_format_to_bpp(enum surface_pixel_format format); -void get_audio_check(struct audio_info *aud_modes, - struct audio_check *aud_chk); - bool get_temp_dp_link_res(struct dc_link *link, struct link_resource *link_res, struct dc_link_settings *link_settings); @@ -610,5 +619,4 @@ enum dc_status update_dp_encoder_resources_for_test_harness(const struct dc *dc, struct pipe_ctx *pipe_ctx); bool check_subvp_sw_cursor_fallback_req(const struct dc *dc, struct dc_stream_state *stream); - #endif /* DRIVERS_GPU_DRM_AMD_DC_DEV_DC_INC_RESOURCE_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 index f8e01ca09d9646..3cbfbf8d107e9b 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c @@ -776,10 +776,26 @@ static bool dp_set_dsc_on_rx(struct pipe_ctx *pipe_ctx, bool enable) */ void link_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) { + /* TODO: Move this to HWSS as this is hardware programming sequence not a + * link layer sequence + */ 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; + struct dccg *dccg = dc->res_pool->dccg; + /* It has been found that when DSCCLK is lower than 16Mhz, we will get DCN + * register access hung. When DSCCLk is based on refclk, DSCCLk is always a + * fixed value higher than 16Mhz so the issue doesn't occur. When DSCCLK is + * generated by DTO, DSCCLK would be based on 1/3 dispclk. For small timings + * with DSC such as 480p60Hz, the dispclk could be low enough to trigger + * this problem. We are implementing a workaround here to keep using dscclk + * based on fixed value refclk when timing is smaller than 3x16Mhz (i.e + * 48Mhz) pixel clock to avoid hitting this problem. + */ + bool should_use_dto_dscclk = (dccg->funcs->set_dto_dscclk != NULL) && + stream->timing.pix_clk_100hz > 480000; DC_LOGGER_INIT(dsc->ctx->logger); for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) @@ -802,11 +818,15 @@ void link_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg); dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst); + if (should_use_dto_dscclk) + dccg->funcs->set_dto_dscclk(dccg, dsc->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); + if (should_use_dto_dscclk) + dccg->funcs->set_dto_dscclk(dccg, odm_dsc->inst); } dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt; dsc_cfg.pic_width *= opp_cnt; @@ -856,9 +876,14 @@ void link_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) } /* disable DSC block */ + if (dccg->funcs->set_ref_dscclk) + dccg->funcs->set_ref_dscclk(dccg, pipe_ctx->stream_res.dsc->inst); 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) + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { + if (dccg->funcs->set_ref_dscclk) + dccg->funcs->set_ref_dscclk(dccg, odm_pipe->stream_res.dsc->inst); odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc); + } } } @@ -875,11 +900,15 @@ bool link_set_dsc_pps_packet(struct pipe_ctx *pipe_ctx, bool enable, bool immedi { 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) + if (!pipe_ctx->stream->timing.flags.DSC) + return false; + + if (!dsc) return false; + DC_LOGGER_INIT(dsc->ctx->logger); + if (enable) { struct dsc_config dsc_cfg; uint8_t dsc_packed_pps[128]; @@ -1057,18 +1086,21 @@ static struct fixed31_32 get_pbn_from_bw_in_kbps(uint64_t kbps) uint32_t denominator = 1; /* - * margin 5300ppm + 300ppm ~ 0.6% as per spec, factor is 1.006 + * The 1.006 factor (margin 5300ppm + 300ppm ~ 0.6% as per spec) is not + * required when determining PBN/time slot utilization on the link between + * us and the branch, since that overhead is already accounted for in + * the get_pbn_per_slot function. + * * 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 + * peak_kbps /= (8 * 1000) convert to bytes */ - numerator = 64 * PEAK_FACTOR_X1000; - denominator = 54 * 8 * 1000 * 1000; + numerator = 64; + denominator = 54 * 8 * 1000; kbps *= numerator; peak_kbps = dc_fixpt_from_fraction(kbps, denominator); @@ -1247,86 +1279,6 @@ static void remove_stream_from_alloc_table( } } -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; @@ -1339,9 +1291,6 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx) 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 @@ -1414,16 +1363,14 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx) link_hwss->ext.update_stream_allocation_table(link, &pipe_ctx->link_res, &link->mst_stream_alloc_table); - if (mst_mode) { + 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); - } + dm_helpers_dp_mst_update_mst_mgr_for_deallocation( + stream->ctx, + stream); return DC_OK; } @@ -1504,12 +1451,10 @@ static enum dc_status allocate_mst_payload(struct pipe_ctx *pipe_ctx) stream->ctx, stream); - if (ret != ACT_LINK_LOST) { + if (ret != ACT_LINK_LOST) dm_helpers_dp_mst_send_payload_allocation( stream->ctx, - stream, - true); - } + stream); /* slot X.Y for only current stream */ pbn_per_slot = get_pbn_per_slot(stream); @@ -1769,8 +1714,7 @@ enum dc_status link_reduce_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t bw_in /* send ALLOCATE_PAYLOAD sideband message with updated pbn */ dm_helpers_dp_mst_send_payload_allocation( stream->ctx, - stream, - true); + stream); /* notify immediate branch device table update */ if (dm_helpers_dp_mst_write_payload_allocation_table( @@ -1899,8 +1843,7 @@ enum dc_status link_increase_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t bw_ /* send ALLOCATE_PAYLOAD sideband message with updated pbn */ dm_helpers_dp_mst_send_payload_allocation( stream->ctx, - stream, - true); + stream); } /* increase throttled vcp size */ @@ -2066,17 +2009,11 @@ static enum dc_status enable_link_dp(struct dc_state *state, } } - /* - * If the link is DP-over-USB4 do the following: - * - Train with fallback when enabling DPIA link. Conventional links are + /* Train with fallback when enabling DPIA link. Conventional links are * trained with fallback during sink detection. - * - Allocate only what the stream needs for bw in Gbps. Inform the CM - * in case stream needs more or less bw from what has been allocated - * earlier at plug time. */ - if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) { + if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) do_fallback = true; - } /* * Temporary w/a to get DP2.0 link rates to work with SST. @@ -2258,6 +2195,32 @@ static enum dc_status enable_link( return status; } +static bool allocate_usb4_bandwidth_for_stream(struct dc_stream_state *stream, int bw) +{ + return true; +} + +static bool allocate_usb4_bandwidth(struct dc_stream_state *stream) +{ + bool ret; + + int bw = dc_bandwidth_in_kbps_from_timing(&stream->timing, + dc_link_get_highest_encoding_format(stream->sink->link)); + + ret = allocate_usb4_bandwidth_for_stream(stream, bw); + + return ret; +} + +static bool deallocate_usb4_bandwidth(struct dc_stream_state *stream) +{ + bool ret; + + ret = allocate_usb4_bandwidth_for_stream(stream, 0); + + return ret; +} + void link_set_dpms_off(struct pipe_ctx *pipe_ctx) { struct dc *dc = pipe_ctx->stream->ctx->dc; @@ -2293,6 +2256,9 @@ void link_set_dpms_off(struct pipe_ctx *pipe_ctx) update_psp_stream_config(pipe_ctx, true); dc->hwss.blank_stream(pipe_ctx); + if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) + deallocate_usb4_bandwidth(pipe_ctx->stream); + 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 && @@ -2535,6 +2501,9 @@ void link_set_dpms_on( } } + if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) + allocate_usb4_bandwidth(pipe_ctx->stream); + 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 && diff --git a/drivers/gpu/drm/amd/display/dc/link/link_factory.c b/drivers/gpu/drm/amd/display/dc/link/link_factory.c index 7abfc67d10a62d..37d3027c32dcb1 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_factory.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_factory.c @@ -213,8 +213,10 @@ static void construct_link_service_edp_panel_control(struct link_service *link_s link_srv->edp_get_replay_state = edp_get_replay_state; link_srv->edp_set_replay_allow_active = edp_set_replay_allow_active; link_srv->edp_setup_replay = edp_setup_replay; + link_srv->edp_send_replay_cmd = edp_send_replay_cmd; link_srv->edp_set_coasting_vtotal = edp_set_coasting_vtotal; link_srv->edp_replay_residency = edp_replay_residency; + link_srv->edp_set_replay_power_opt_and_coasting_vtotal = edp_set_replay_power_opt_and_coasting_vtotal; link_srv->edp_wait_for_t12 = edp_wait_for_t12; link_srv->edp_is_ilr_optimization_required = @@ -368,6 +370,30 @@ static enum transmitter translate_encoder_to_transmitter( } } +static uint8_t translate_dig_inst_to_pwrseq_inst(struct dc_link *link) +{ + uint8_t pwrseq_inst = 0xF; + struct dc_context *dc_ctx = link->dc->ctx; + + DC_LOGGER_INIT(dc_ctx->logger); + + switch (link->eng_id) { + case ENGINE_ID_DIGA: + pwrseq_inst = 0; + break; + case ENGINE_ID_DIGB: + pwrseq_inst = 1; + break; + default: + DC_LOG_WARNING("Unsupported pwrseq engine id: %d!\n", link->eng_id); + ASSERT(false); + break; + } + + return pwrseq_inst; +} + + static void link_destruct(struct dc_link *link) { int i; @@ -595,24 +621,6 @@ static bool construct_phy(struct dc_link *link, 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); @@ -643,6 +651,23 @@ static bool construct_phy(struct dc_link *link, link->dc->res_pool->dig_link_enc_count++; link->link_enc_hw_inst = link->link_enc->transmitter; + + 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; + panel_cntl_init_data.pwrseq_inst = translate_dig_inst_to_pwrseq_inst(link); + 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; + } + } for (i = 0; i < 4; i++) { if (bp_funcs->get_device_tag(dc_ctx->dc_bios, link->link_id, i, diff --git a/drivers/gpu/drm/amd/display/dc/link/link_validation.c b/drivers/gpu/drm/amd/display/dc/link/link_validation.c index b45fda96eaf649..8fe66c3678508d 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_validation.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_validation.c @@ -346,23 +346,61 @@ enum dc_status link_validate_mode_timing( return DC_OK; } +/* + * This function calculates the bandwidth required for the stream timing + * and aggregates the stream bandwidth for the respective dpia link + * + * @stream: pointer to the dc_stream_state struct instance + * @num_streams: number of streams to be validated + * + * return: true if validation is succeeded + */ bool link_validate_dpia_bandwidth(const struct dc_stream_state *stream, const unsigned int num_streams) { - bool ret = true; - int bw_needed[MAX_DPIA_NUM]; - struct dc_link *link[MAX_DPIA_NUM]; - - if (!num_streams || num_streams > MAX_DPIA_NUM) - return ret; + int bw_needed[MAX_DPIA_NUM] = {0}; + struct dc_link *dpia_link[MAX_DPIA_NUM] = {0}; + int num_dpias = 0; for (uint8_t i = 0; i < num_streams; ++i) { + if (stream[i].signal == SIGNAL_TYPE_DISPLAY_PORT) { + /* new dpia sst stream, check whether it exceeds max dpia */ + if (num_dpias >= MAX_DPIA_NUM) + return false; - link[i] = stream[i].link; - bw_needed[i] = dc_bandwidth_in_kbps_from_timing(&stream[i].timing, - dc_link_get_highest_encoding_format(link[i])); + dpia_link[num_dpias] = stream[i].link; + bw_needed[num_dpias] = dc_bandwidth_in_kbps_from_timing(&stream[i].timing, + dc_link_get_highest_encoding_format(dpia_link[num_dpias])); + num_dpias++; + } else if (stream[i].signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { + uint8_t j = 0; + /* check whether its a known dpia link */ + for (; j < num_dpias; ++j) { + if (dpia_link[j] == stream[i].link) + break; + } + + if (j == num_dpias) { + /* new dpia mst stream, check whether it exceeds max dpia */ + if (num_dpias >= MAX_DPIA_NUM) + return false; + else { + dpia_link[j] = stream[i].link; + num_dpias++; + } + } + + bw_needed[j] += dc_bandwidth_in_kbps_from_timing(&stream[i].timing, + dc_link_get_highest_encoding_format(dpia_link[j])); + } } - ret = dpia_validate_usb4_bw(link, bw_needed, num_streams); + /* Include dp overheads */ + for (uint8_t i = 0; i < num_dpias; ++i) { + int dp_overhead = 0; + + dp_overhead = link_dp_dpia_get_dp_overhead_in_dp_tunneling(dpia_link[i]); + bw_needed[i] += dp_overhead; + } - return ret; + return dpia_validate_usb4_bw(dpia_link, bw_needed, num_dpias); } diff --git a/drivers/gpu/drm/amd/display/dc/link/link_validation.h b/drivers/gpu/drm/amd/display/dc/link/link_validation.h index 4a954317d0dacc..595fb05946e9d1 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_validation.h +++ b/drivers/gpu/drm/amd/display/dc/link/link_validation.h @@ -25,6 +25,7 @@ #ifndef __LINK_VALIDATION_H__ #define __LINK_VALIDATION_H__ #include "link.h" + enum dc_status link_validate_mode_timing( const struct dc_stream_state *stream, struct dc_link *link, 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 index db87aa7b5c90f6..289f5d1333424b 100644 --- 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 @@ -412,12 +412,18 @@ 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) + 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) + } 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; + } else if (link->dpcd_caps.cable_id.bits.UHBR10_20_CAPABILITY & DP_UHBR10) { + // allow DP40 cables to do UHBR13.5 for passive or unknown cable type + if (link->dpcd_caps.cable_id.bits.CABLE_TYPE < 2) { + cable_max_link_rate = LINK_RATE_UHBR13_5; + } else { + cable_max_link_rate = LINK_RATE_UHBR10; + } + } return cable_max_link_rate; } @@ -1392,7 +1398,7 @@ static bool get_usbc_cable_id(struct dc_link *link, union dp_cable_id *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 (dm_execute_dmub_cmd(link->dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY) && + if (dc_wake_and_execute_dmub_cmd(link->dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY) && 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); 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 index 0bb7491339098a..6af42ba9885c05 100644 --- 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 @@ -82,24 +82,33 @@ bool 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 (dm_execute_dmub_cmd(dmub_srv->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY) && 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; + /* Query dpia hpd status from dmub */ + if (dc_wake_and_execute_dmub_cmd(dmub_srv->ctx, &cmd, + DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY) && + cmd.query_hpd.data.status == AUX_RET_SUCCESS) { + DC_LOG_DEBUG("%s: for link(%d) dpia(%d) success, current_hpd_status(%d) new_hpd_status(%d)\n", + __func__, + link->link_index, + link->link_id.enum_id - ENUM_ID_1, + link->hpd_status, + cmd.query_hpd.data.result); + link->hpd_status = cmd.query_hpd.data.result; + } else { + DC_LOG_ERROR("%s: for link(%d) dpia(%d) failed with status(%d), current_hpd_status(%d) new_hpd_status(0)\n", + __func__, + link->link_index, + link->link_id.enum_id - ENUM_ID_1, + cmd.query_hpd.data.status, + link->hpd_status); + link->hpd_status = false; + } + + return link->hpd_status; } 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 index 7581023daa4789..dd0d2b206462c9 100644 --- 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 @@ -50,15 +50,28 @@ static bool get_bw_alloc_proceed_flag(struct dc_link *tmp) && 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.link_verified_bw = 0; + link->dpia_bw_alloc_config.link_max_bw = 0; + link->dpia_bw_alloc_config.allocated_bw = 0; link->dpia_bw_alloc_config.estimated_bw = 0; link->dpia_bw_alloc_config.bw_granularity = 0; + link->dpia_bw_alloc_config.dp_overhead = 0; link->dpia_bw_alloc_config.response_ready = false; + link->dpia_bw_alloc_config.nrd_max_lane_count = 0; + link->dpia_bw_alloc_config.nrd_max_link_rate = 0; + for (int i = 0; i < MAX_SINKS_PER_LINK; i++) + link->dpia_bw_alloc_config.remote_sink_req_bw[i] = 0; + DC_LOG_DEBUG("reset usb4 bw alloc of link(%d)\n", link->link_index); } + +#define BW_GRANULARITY_0 4 // 0.25 Gbps +#define BW_GRANULARITY_1 2 // 0.5 Gbps +#define BW_GRANULARITY_2 1 // 1 Gbps + static uint8_t get_bw_granularity(struct dc_link *link) { uint8_t bw_granularity = 0; @@ -71,16 +84,20 @@ static uint8_t get_bw_granularity(struct dc_link *link) switch (bw_granularity & 0x3) { case 0: - bw_granularity = 4; + bw_granularity = BW_GRANULARITY_0; break; case 1: + bw_granularity = BW_GRANULARITY_1; + break; + case 2: default: - bw_granularity = 2; + bw_granularity = BW_GRANULARITY_2; break; } return bw_granularity; } + static int get_estimated_bw(struct dc_link *link) { uint8_t bw_estimated_bw = 0; @@ -93,31 +110,33 @@ static int get_estimated_bw(struct dc_link *link) 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) + +static int get_non_reduced_max_link_rate(struct dc_link *link) { - if (bw_needed > 0) - *stream_allocated_bw += bw_needed; + uint8_t nrd_max_link_rate = 0; - return true; + core_link_read_dpcd( + link, + DP_TUNNELING_MAX_LINK_RATE, + &nrd_max_link_rate, + sizeof(uint8_t)); + + return nrd_max_link_rate; } -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; - } +static int get_non_reduced_max_lane_count(struct dc_link *link) +{ + uint8_t nrd_max_lane_count = 0; - // Unplug so reset values - if (!link->hpd_status) - reset_bw_alloc_struct(link); + core_link_read_dpcd( + link, + DP_TUNNELING_MAX_LANE_COUNT, + &nrd_max_lane_count, + sizeof(uint8_t)); - return ret; + return nrd_max_lane_count; } + /* * Read all New BW alloc configuration ex: estimated_bw, allocated_bw, * granuality, Driver_ID, CM_Group, & populate the BW allocation structs @@ -125,10 +144,22 @@ static bool deallocate_usb4_bw(int *stream_allocated_bw, int bw_to_dealloc, stru */ static void init_usb4_bw_struct(struct dc_link *link) { - // Init the known values + reset_bw_alloc_struct(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); + link->dpia_bw_alloc_config.nrd_max_link_rate = get_non_reduced_max_link_rate(link); + link->dpia_bw_alloc_config.nrd_max_lane_count = get_non_reduced_max_lane_count(link); + + DC_LOG_DEBUG("%s: bw_granularity(%d), estimated_bw(%d)\n", + __func__, link->dpia_bw_alloc_config.bw_granularity, + link->dpia_bw_alloc_config.estimated_bw); + DC_LOG_DEBUG("%s: nrd_max_link_rate(%d), nrd_max_lane_count(%d)\n", + __func__, link->dpia_bw_alloc_config.nrd_max_link_rate, + link->dpia_bw_alloc_config.nrd_max_lane_count); } + static uint8_t get_lowest_dpia_index(struct dc_link *link) { const struct dc *dc_struct = link->dc; @@ -141,51 +172,66 @@ static uint8_t get_lowest_dpia_index(struct dc_link *link) dc_struct->links[i]->ep_type != DISPLAY_ENDPOINT_USB4_DPIA) continue; - if (idx > dc_struct->links[i]->link_index) + if (idx > dc_struct->links[i]->link_index) { idx = dc_struct->links[i]->link_index; + break; + } } return idx; } + /* - * Get the Max Available BW or Max Estimated BW for each Host Router + * Get the maximum dp tunnel banwidth of host router * - * @link: pointer to the dc_link struct instance - * @type: ESTIMATD BW or MAX AVAILABLE BW + * @dc: pointer to the dc struct instance + * @hr_index: host router index * - * return: response_ready flag from dc_link struct + * return: host router maximum dp tunnel bandwidth */ -static int get_host_router_total_bw(struct dc_link *link, uint8_t type) +static int get_host_router_total_dp_tunnel_bw(const struct dc *dc, uint8_t hr_index) { - 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; + uint8_t lowest_dpia_index = get_lowest_dpia_index(dc->links[0]); + uint8_t hr_index_temp = 0; + struct dc_link *link_dpia_primary, *link_dpia_secondary; int total_bw = 0; - int i; - - for (i = 0; i < MAX_PIPES * 2; ++i) { - if (!dc_struct->links[i] || dc_struct->links[i]->ep_type != DISPLAY_ENDPOINT_USB4_DPIA) - continue; + for (uint8_t i = 0; i < MAX_PIPES * 2; ++i) { - link_temp = dc_struct->links[i]; - if (!link_temp || !link_temp->hpd_status) + if (!dc->links[i] || dc->links[i]->ep_type != DISPLAY_ENDPOINT_USB4_DPIA) 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; + hr_index_temp = (dc->links[i]->link_index - lowest_dpia_index) / 2; + + if (hr_index_temp == hr_index) { + link_dpia_primary = dc->links[i]; + link_dpia_secondary = dc->links[i + 1]; + + /** + * If BW allocation enabled on both DPIAs, then + * HR BW = Estimated(dpia_primary) + Allocated(dpia_secondary) + * otherwise HR BW = Estimated(bw alloc enabled dpia) + */ + if ((link_dpia_primary->hpd_status && + link_dpia_primary->dpia_bw_alloc_config.bw_alloc_enabled) && + (link_dpia_secondary->hpd_status && + link_dpia_secondary->dpia_bw_alloc_config.bw_alloc_enabled)) { + total_bw += link_dpia_primary->dpia_bw_alloc_config.estimated_bw + + link_dpia_secondary->dpia_bw_alloc_config.allocated_bw; + } else if (link_dpia_primary->hpd_status && + link_dpia_primary->dpia_bw_alloc_config.bw_alloc_enabled) { + total_bw = link_dpia_primary->dpia_bw_alloc_config.estimated_bw; + } else if (link_dpia_secondary->hpd_status && + link_dpia_secondary->dpia_bw_alloc_config.bw_alloc_enabled) { + total_bw += link_dpia_secondary->dpia_bw_alloc_config.estimated_bw; + } + break; } } return total_bw; } + /* * Cleanup function for when the dpia is unplugged to reset struct * and perform any required clean up @@ -194,42 +240,49 @@ static int get_host_router_total_bw(struct dc_link *link, uint8_t type) * * return: none */ -static bool dpia_bw_alloc_unplug(struct dc_link *link) +static void dpia_bw_alloc_unplug(struct dc_link *link) { - 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); + if (link) { + DC_LOG_DEBUG("%s: resetting bw alloc config for link(%d)\n", + __func__, link->link_index); + reset_bw_alloc_struct(link); + } } + static void 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) + /* Error check whether request bw greater than allocated */ + if (req_bw > link->dpia_bw_alloc_config.estimated_bw) { + DC_LOG_ERROR("%s: Request bw greater than estimated bw for link(%d)\n", + __func__, link->link_index); 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 + /* 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 + /* Error check whether requested and allocated are equal */ 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 (req_bw == link->dpia_bw_alloc_config.allocated_bw) { + DC_LOG_ERROR("%s: Request bw equals to allocated bw for link(%d)\n", + __func__, link->link_index); + } - if (core_link_write_dpcd( + link->dpia_bw_alloc_config.response_ready = false; // Reset flag + core_link_write_dpcd( link, REQUESTED_BW, &requested_bw, - sizeof(uint8_t)) == DC_OK) - link->dpia_bw_alloc_config.response_ready = false; // Reset flag + sizeof(uint8_t)); } + /* * Return the response_ready flag from dc_link struct * @@ -241,6 +294,7 @@ static bool get_cm_response_ready_flag(struct dc_link *link) { return link->dpia_bw_alloc_config.response_ready; } + // ------------------------------------------------------------------ // PUBLIC FUNCTIONS // ------------------------------------------------------------------ @@ -277,27 +331,27 @@ bool link_dp_dpia_set_dptx_usb4_bw_alloc_support(struct dc_link *link) DPTX_BW_ALLOCATION_MODE_CONTROL, &response, sizeof(uint8_t)) != DC_OK) { - DC_LOG_DEBUG("%s: **** FAILURE Enabling DPtx BW Allocation Mode Support ***\n", - __func__); + DC_LOG_DEBUG("%s: FAILURE Enabling DPtx BW Allocation Mode Support for link(%d)\n", + __func__, link->link_index); } else { // SUCCESS Enabled DPtx BW Allocation Mode Support - link->dpia_bw_alloc_config.bw_alloc_enabled = true; - DC_LOG_DEBUG("%s: **** SUCCESS Enabling DPtx BW Allocation Mode Support ***\n", - __func__); + DC_LOG_DEBUG("%s: SUCCESS Enabling DPtx BW Allocation Mode Support for link(%d)\n", + __func__, link->link_index); ret = true; init_usb4_bw_struct(link); + link->dpia_bw_alloc_config.bw_alloc_enabled = true; } } out: return ret; } + void dpia_handle_bw_alloc_response(struct dc_link *link, uint8_t bw, uint8_t result) { int bw_needed = 0; int estimated = 0; - int host_router_total_estimated_bw = 0; if (!get_bw_alloc_proceed_flag((link))) return; @@ -306,14 +360,22 @@ void dpia_handle_bw_alloc_response(struct dc_link *link, uint8_t bw, uint8_t res case DPIA_BW_REQ_FAILED: - DC_LOG_DEBUG("%s: *** *** BW REQ FAILURE for DP-TX Request *** ***\n", __func__); + /* + * Ideally, we shouldn't run into this case as we always validate available + * bandwidth and request within that limit + */ + estimated = bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity); + + DC_LOG_ERROR("%s: BW REQ FAILURE for DP-TX Request for link(%d)\n", + __func__, link->link_index); + DC_LOG_ERROR("%s: current estimated_bw(%d), new estimated_bw(%d)\n", + __func__, link->dpia_bw_alloc_config.estimated_bw, estimated); - // 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); + /* Update the new Estimated BW value updated by CM */ + link->dpia_bw_alloc_config.estimated_bw = estimated; + /* Allocate the previously requested bandwidth */ 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: @@ -326,68 +388,34 @@ void dpia_handle_bw_alloc_response(struct dc_link *link, uint8_t bw, uint8_t res case DPIA_BW_REQ_SUCCESS: - DC_LOG_DEBUG("%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 - bw_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, 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 > bw_needed) - deallocate_usb4_bw(&link->dpia_bw_alloc_config.sink_allocated_bw, - link->dpia_bw_alloc_config.sink_allocated_bw - bw_needed, link); - else - allocate_usb4_bw(&link->dpia_bw_alloc_config.sink_allocated_bw, - bw_needed - link->dpia_bw_alloc_config.sink_allocated_bw, link); - } + DC_LOG_DEBUG("%s: BW REQ SUCCESS for DP-TX Request for link(%d)\n", + __func__, link->link_index); + DC_LOG_DEBUG("%s: current allocated_bw(%d), new allocated_bw(%d)\n", + __func__, link->dpia_bw_alloc_config.allocated_bw, bw_needed); - // 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.allocated_bw = bw_needed; link->dpia_bw_alloc_config.response_ready = true; break; case DPIA_EST_BW_CHANGED: - DC_LOG_DEBUG("%s: *** ESTIMATED BW CHANGED for DP-TX Request ***\n", __func__); - estimated = bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity); - 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) - 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 lost estimated bw usually due to plug event of other dpia - link->dpia_bw_alloc_config.estimated_bw = estimated; - } + DC_LOG_DEBUG("%s: ESTIMATED BW CHANGED for link(%d)\n", + __func__, link->link_index); + DC_LOG_DEBUG("%s: current estimated_bw(%d), new estimated_bw(%d)\n", + __func__, link->dpia_bw_alloc_config.estimated_bw, estimated); + + link->dpia_bw_alloc_config.estimated_bw = estimated; break; case DPIA_BW_ALLOC_CAPS_CHANGED: - DC_LOG_DEBUG("%s: *** BW ALLOC CAPABILITY CHANGED for DP-TX Request ***\n", __func__); + DC_LOG_ERROR("%s: BW ALLOC CAPABILITY CHANGED to Disabled for link(%d)\n", + __func__, link->link_index); link->dpia_bw_alloc_config.bw_alloc_enabled = false; break; } @@ -405,21 +433,21 @@ int dpia_handle_usb4_bandwidth_allocation_for_link(struct dc_link *link, int pea 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; - set_usb4_req_bw_req(link, link->dpia_bw_alloc_config.sink_max_bw); + link->dpia_bw_alloc_config.link_max_bw = peak_bw; + set_usb4_req_bw_req(link, link->dpia_bw_alloc_config.link_max_bw); do { - if (!(timeout > 0)) + if (timeout > 0) timeout--; else break; - fsleep(10 * 1000); + msleep(10); } 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); + else if (link->dpia_bw_alloc_config.allocated_bw > 0) + ret = link->dpia_bw_alloc_config.allocated_bw; } //2. Cold Unplug else if (!link->hpd_status) @@ -428,65 +456,102 @@ int dpia_handle_usb4_bandwidth_allocation_for_link(struct dc_link *link, int pea out: return ret; } -int link_dp_dpia_allocate_usb4_bandwidth_for_stream(struct dc_link *link, int req_bw) +bool link_dp_dpia_allocate_usb4_bandwidth_for_stream(struct dc_link *link, int req_bw) { - int ret = 0; + bool ret = false; uint8_t timeout = 10; + DC_LOG_DEBUG("%s: ENTER: link(%d), hpd_status(%d), current allocated_bw(%d), req_bw(%d)\n", + __func__, link->link_index, link->hpd_status, + link->dpia_bw_alloc_config.allocated_bw, req_bw); + if (!get_bw_alloc_proceed_flag(link)) goto out; - /* - * Sometimes stream uses same timing parameters as the already - * allocated max sink bw so no need to re-alloc - */ - if (req_bw != link->dpia_bw_alloc_config.sink_allocated_bw) { - set_usb4_req_bw_req(link, req_bw); - do { - if (!(timeout > 0)) - timeout--; - else - break; - udelay(10 * 1000); - } while (!get_cm_response_ready_flag(link)); + set_usb4_req_bw_req(link, req_bw); + do { + if (timeout > 0) + timeout--; + else + break; + msleep(10); + } 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); - } + if (timeout) + ret = true; out: + DC_LOG_DEBUG("%s: EXIT: timeout(%d), ret(%d)\n", __func__, timeout, ret); return ret; } + bool dpia_validate_usb4_bw(struct dc_link **link, int *bw_needed_per_dpia, const unsigned int num_dpias) { bool ret = true; - int bw_needed_per_hr[MAX_HR_NUM] = { 0, 0 }; - uint8_t lowest_dpia_index = 0, dpia_index = 0; - uint8_t i; + int bw_needed_per_hr[MAX_HR_NUM] = { 0, 0 }, host_router_total_dp_bw = 0; + uint8_t lowest_dpia_index, i, hr_index; if (!num_dpias || num_dpias > MAX_DPIA_NUM) return ret; - //Get total Host Router BW & Validate against each Host Router max BW + lowest_dpia_index = get_lowest_dpia_index(link[0]); + + /* get total Host Router BW with granularity for the given modes */ for (i = 0; i < num_dpias; ++i) { + int granularity_Gbps = 0; + int bw_granularity = 0; if (!link[i]->dpia_bw_alloc_config.bw_alloc_enabled) continue; - lowest_dpia_index = get_lowest_dpia_index(link[i]); if (link[i]->link_index < lowest_dpia_index) continue; - dpia_index = (link[i]->link_index - lowest_dpia_index) / 2; - bw_needed_per_hr[dpia_index] += bw_needed_per_dpia[i]; - if (bw_needed_per_hr[dpia_index] > get_host_router_total_bw(link[i], HOST_ROUTER_BW_ALLOCATED)) { + granularity_Gbps = (Kbps_TO_Gbps / link[i]->dpia_bw_alloc_config.bw_granularity); + bw_granularity = (bw_needed_per_dpia[i] / granularity_Gbps) * granularity_Gbps + + ((bw_needed_per_dpia[i] % granularity_Gbps) ? granularity_Gbps : 0); - ret = false; - break; + hr_index = (link[i]->link_index - lowest_dpia_index) / 2; + bw_needed_per_hr[hr_index] += bw_granularity; + } + + /* validate against each Host Router max BW */ + for (hr_index = 0; hr_index < MAX_HR_NUM; ++hr_index) { + if (bw_needed_per_hr[hr_index]) { + host_router_total_dp_bw = get_host_router_total_dp_tunnel_bw(link[0]->dc, hr_index); + if (bw_needed_per_hr[hr_index] > host_router_total_dp_bw) { + ret = false; + break; + } } } return ret; } + +int link_dp_dpia_get_dp_overhead_in_dp_tunneling(struct dc_link *link) +{ + int dp_overhead = 0, link_mst_overhead = 0; + + if (!get_bw_alloc_proceed_flag((link))) + return dp_overhead; + + /* if its mst link, add MTPH overhead */ + if ((link->type == dc_connection_mst_branch) && + !link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED) { + /* For 8b/10b encoding: MTP is 64 time slots long, slot 0 is used for MTPH + * MST overhead is 1/64 of link bandwidth (excluding any overhead) + */ + const struct dc_link_settings *link_cap = + dc_link_get_link_cap(link); + uint32_t link_bw_in_kbps = (uint32_t)link_cap->link_rate * + (uint32_t)link_cap->lane_count * + LINK_RATE_REF_FREQ_IN_KHZ * 8; + link_mst_overhead = (link_bw_in_kbps / 64) + ((link_bw_in_kbps % 64) ? 1 : 0); + } + + /* add all the overheads */ + dp_overhead = link_mst_overhead; + + return dp_overhead; +} diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.h index 7292690383ae1f..3b6d8494f9d5da 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.h +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.h @@ -59,9 +59,9 @@ bool link_dp_dpia_set_dptx_usb4_bw_alloc_support(struct dc_link *link); * @link: pointer to the dc_link struct instance * @req_bw: Bw requested by the stream * - * return: allocated bw else return 0 + * return: true if allocated successfully */ -int link_dp_dpia_allocate_usb4_bandwidth_for_stream(struct dc_link *link, int req_bw); +bool link_dp_dpia_allocate_usb4_bandwidth_for_stream(struct dc_link *link, int req_bw); /* * Handle the USB4 BW Allocation related functionality here: @@ -99,4 +99,13 @@ void dpia_handle_bw_alloc_response(struct dc_link *link, uint8_t bw, uint8_t res */ bool dpia_validate_usb4_bw(struct dc_link **link, int *bw_needed, const unsigned int num_dpias); +/* + * Obtain all the DP overheads in dp tunneling for the dpia link + * + * @link: pointer to the dc_link struct instance + * + * return: DP overheads in DP tunneling + */ +int link_dp_dpia_get_dp_overhead_in_dp_tunneling(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 index 0c00e94e90b1d5..ba69874be5a491 100644 --- 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 @@ -190,9 +190,6 @@ static void handle_hpd_irq_replay_sink(struct dc_link *link) /*AMD Replay version reuse DP_PSR_ERROR_STATUS for REPLAY_ERROR status.*/ union psr_error_status replay_error_status; - if (link->replay_settings.config.force_disable_desync_error_check) - return; - if (!link->replay_settings.replay_feature_enabled) return; @@ -210,9 +207,6 @@ static void handle_hpd_irq_replay_sink(struct dc_link *link) &replay_error_status.raw, sizeof(replay_error_status.raw)); - if (replay_configuration.bits.DESYNC_ERROR_STATUS) - link->replay_settings.config.received_desync_error_hpd = 1; - link->replay_settings.config.replay_error_status.bits.LINK_CRC_ERROR = replay_error_status.bits.LINK_CRC_ERROR; link->replay_settings.config.replay_error_status.bits.DESYNC_ERROR = @@ -225,6 +219,12 @@ static void handle_hpd_irq_replay_sink(struct dc_link *link) link->replay_settings.config.replay_error_status.bits.STATE_TRANSITION_ERROR) { bool allow_active; + if (link->replay_settings.config.replay_error_status.bits.DESYNC_ERROR) + link->replay_settings.config.received_desync_error_hpd = 1; + + if (link->replay_settings.config.force_disable_desync_error_check) + return; + /* Acknowledge and clear configuration bits */ dm_helpers_dp_write_dpcd( link->ctx, @@ -265,7 +265,7 @@ void dp_handle_link_loss(struct dc_link *link) for (i = count - 1; i >= 0; i--) { // Always use max settings here for DP 1.4a LL Compliance CTS - if (link->is_automated) { + if (link->skip_fallback_on_link_loss) { pipes[i]->link_config.dp_link_settings.lane_count = link->verified_link_cap.lane_count; pipes[i]->link_config.dp_link_settings.link_rate = @@ -404,7 +404,9 @@ bool dp_handle_hpd_rx_irq(struct dc_link *link, 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; + if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) + link->skip_fallback_on_link_loss = true; + device_service_clear.bits.AUTOMATED_TEST = 1; core_link_write_dpcd( link, 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 index 90339c2dfd8487..5a0b0451895690 100644 --- 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 @@ -807,7 +807,7 @@ 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]) + union dpcd_training_lane *dpcd_lane_settings) { uint32_t lane; 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 index 7d027bac82551d..851bd17317a0c4 100644 --- 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 @@ -111,7 +111,7 @@ 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]); + union dpcd_training_lane *dpcd_lane_settings); enum dc_dp_training_pattern decide_cr_training_pattern( const struct dc_link_settings *link_settings); diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c index 4f4e899e5c46dc..e8dda44b23cb29 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c @@ -811,7 +811,7 @@ static enum link_training_result dpia_training_eq_transparent( /* Take into consideration corner case for DP 1.4a LL Compliance CTS as USB4 * has to share encoders unlike DP and USBC */ - if (dp_is_interlane_aligned(dpcd_lane_status_updated) || (link->is_automated && retries_eq)) { + if (dp_is_interlane_aligned(dpcd_lane_status_updated) || (link->skip_fallback_on_link_loss && retries_eq)) { result = LINK_TRAINING_SUCCESS; break; } @@ -1037,7 +1037,7 @@ enum link_training_result dpia_perform_link_training( */ if (result == LINK_TRAINING_SUCCESS) { fsleep(5000); - if (!link->is_automated) + if (!link->skip_fallback_on_link_loss) result = dp_check_link_loss_status(link, <_settings); } else if (result == LINK_TRAINING_ABORT) dpia_training_abort(link, <_settings, repeater_id); 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 index 68096d12f52fd6..7087cdc9e9775c 100644 --- 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 @@ -205,6 +205,7 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence_legacy( const uint8_t vendor_lttpr_write_data_4lane_3[4] = {0x1, 0x6D, 0xF2, 0x18}; const uint8_t vendor_lttpr_write_data_4lane_4[4] = {0x1, 0x6C, 0xF2, 0x03}; const uint8_t vendor_lttpr_write_data_4lane_5[4] = {0x1, 0x03, 0xF3, 0x06}; + const uint8_t vendor_lttpr_write_data_dpmf[4] = {0x1, 0x6, 0x70, 0x87}; enum link_training_result status = LINK_TRAINING_SUCCESS; uint8_t lane = 0; union down_spread_ctrl downspread = {0}; @@ -293,6 +294,10 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence_legacy( DP_DOWNSPREAD_CTRL, lt_settings->link_settings.link_spread); + link_configure_fixed_vs_pe_retimer(link->ddc, + &vendor_lttpr_write_data_dpmf[0], + sizeof(vendor_lttpr_write_data_dpmf)); + if (lt_settings->link_settings.lane_count == LANE_COUNT_FOUR) { link_configure_fixed_vs_pe_retimer(link->ddc, &vendor_lttpr_write_data_4lane_1[0], sizeof(vendor_lttpr_write_data_4lane_1)); @@ -552,6 +557,7 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence( const uint8_t vendor_lttpr_write_data_4lane_3[4] = {0x1, 0x6D, 0xF2, 0x18}; const uint8_t vendor_lttpr_write_data_4lane_4[4] = {0x1, 0x6C, 0xF2, 0x03}; const uint8_t vendor_lttpr_write_data_4lane_5[4] = {0x1, 0x03, 0xF3, 0x06}; + const uint8_t vendor_lttpr_write_data_dpmf[4] = {0x1, 0x6, 0x70, 0x87}; enum link_training_result status = LINK_TRAINING_SUCCESS; uint8_t lane = 0; union down_spread_ctrl downspread = {0}; @@ -639,6 +645,10 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence( DP_DOWNSPREAD_CTRL, lt_settings->link_settings.link_spread); + link_configure_fixed_vs_pe_retimer(link->ddc, + &vendor_lttpr_write_data_dpmf[0], + sizeof(vendor_lttpr_write_data_dpmf)); + if (lt_settings->link_settings.lane_count == LANE_COUNT_FOUR) { link_configure_fixed_vs_pe_retimer(link->ddc, &vendor_lttpr_write_data_4lane_1[0], sizeof(vendor_lttpr_write_data_4lane_1)); diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dpcd.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dpcd.c index 5c9a30211c109f..fc50931c2aecbb 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dpcd.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dpcd.c @@ -205,7 +205,7 @@ enum dc_status core_link_read_dpcd( uint32_t extended_size; /* size of the remaining partitioned address space */ uint32_t size_left_to_read; - enum dc_status status; + enum dc_status status = DC_ERROR_UNEXPECTED; /* size of the next partition to be read from */ uint32_t partition_size; uint32_t data_index = 0; @@ -234,7 +234,7 @@ enum dc_status core_link_write_dpcd( { uint32_t partition_size; uint32_t data_index = 0; - enum dc_status status; + enum dc_status status = DC_ERROR_UNEXPECTED; while (size) { partition_size = dpcd_get_next_partition_size(address, size); 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 index e5cfaaef70b3f7..046d3e20541531 100644 --- 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 @@ -529,6 +529,9 @@ bool edp_set_backlight_level(const struct dc_link *link, if (dc_is_embedded_signal(link->connector_signal)) { struct pipe_ctx *pipe_ctx = get_pipe_from_link(link); + if (link->panel_cntl) + link->panel_cntl->stored_backlight_registers.USER_LEVEL = backlight_pwm_u16_16; + if (pipe_ctx) { /* Disable brightness ramping when the display is blanked * as it can hang the DMCU @@ -927,8 +930,8 @@ bool edp_get_replay_state(const struct dc_link *link, uint64_t *state) bool edp_setup_replay(struct dc_link *link, const struct dc_stream_state *stream) { /* To-do: Setup Replay */ - struct dc *dc = link->ctx->dc; - struct dmub_replay *replay = dc->res_pool->replay; + struct dc *dc; + struct dmub_replay *replay; int i; unsigned int panel_inst; struct replay_context replay_context = { 0 }; @@ -944,6 +947,10 @@ bool edp_setup_replay(struct dc_link *link, const struct dc_stream_state *stream if (!link) return false; + dc = link->ctx->dc; + + replay = dc->res_pool->replay; + if (!replay) return false; @@ -972,8 +979,7 @@ bool edp_setup_replay(struct dc_link *link, const struct dc_stream_state *stream replay_context.line_time_in_ns = lineTimeInNs; - if (replay) - link->replay_settings.replay_feature_enabled = + link->replay_settings.replay_feature_enabled = replay->funcs->replay_copy_settings(replay, link, &replay_context, panel_inst); if (link->replay_settings.replay_feature_enabled) { @@ -997,6 +1003,36 @@ bool edp_setup_replay(struct dc_link *link, const struct dc_stream_state *stream return true; } +/* + * This is general Interface for Replay to set an 32 bit variable to dmub + * replay_FW_Message_type: Indicates which instruction or variable pass to DMUB + * cmd_data: Value of the config. + */ +bool edp_send_replay_cmd(struct dc_link *link, + enum replay_FW_Message_type msg, + union dmub_replay_cmd_set *cmd_data) +{ + struct dc *dc = link->ctx->dc; + struct dmub_replay *replay = dc->res_pool->replay; + unsigned int panel_inst; + + if (!replay) + return false; + + DC_LOGGER_INIT(link->ctx->logger); + + if (dc_get_edp_link_panel_inst(dc, link, &panel_inst)) + cmd_data->panel_inst = panel_inst; + else { + DC_LOG_DC("%s(): get edp panel inst fail ", __func__); + return false; + } + + replay->funcs->replay_send_cmd(replay, msg, cmd_data); + + return true; +} + bool edp_set_coasting_vtotal(struct dc_link *link, uint16_t coasting_vtotal) { struct dc *dc = link->ctx->dc; @@ -1035,6 +1071,33 @@ bool edp_replay_residency(const struct dc_link *link, return true; } +bool edp_set_replay_power_opt_and_coasting_vtotal(struct dc_link *link, + const unsigned int *power_opts, uint16_t coasting_vtotal) +{ + struct dc *dc = link->ctx->dc; + struct dmub_replay *replay = dc->res_pool->replay; + unsigned int panel_inst; + + if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst)) + return false; + + /* Only both power and coasting vtotal changed, this func could return true */ + if (power_opts && link->replay_settings.replay_power_opt_active != *power_opts && + coasting_vtotal && link->replay_settings.coasting_vtotal != coasting_vtotal) { + if (link->replay_settings.replay_feature_enabled && + replay->funcs->replay_set_power_opt_and_coasting_vtotal) { + replay->funcs->replay_set_power_opt_and_coasting_vtotal(replay, + *power_opts, panel_inst, coasting_vtotal); + link->replay_settings.replay_power_opt_active = *power_opts; + link->replay_settings.coasting_vtotal = coasting_vtotal; + } else + return false; + } else + return false; + + return true; +} + static struct abm *get_abm_from_stream_res(const struct dc_link *link) { int i; 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 index a034288ad75d4a..34e521af7bb482 100644 --- 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 @@ -56,10 +56,15 @@ bool edp_set_replay_allow_active(struct dc_link *dc_link, const bool *enable, bool wait, bool force_static, const unsigned int *power_opts); bool edp_setup_replay(struct dc_link *link, const struct dc_stream_state *stream); +bool edp_send_replay_cmd(struct dc_link *link, + enum replay_FW_Message_type msg, + union dmub_replay_cmd_set *cmd_data); bool edp_set_coasting_vtotal(struct dc_link *link, uint16_t coasting_vtotal); bool edp_replay_residency(const struct dc_link *link, unsigned int *residency, const bool is_start, const bool is_alpm); bool edp_get_replay_state(const struct dc_link *link, uint64_t *state); +bool edp_set_replay_power_opt_and_coasting_vtotal(struct dc_link *link, + const unsigned int *power_opts, uint16_t coasting_vtotal); bool edp_wait_for_t12(struct dc_link *link); bool edp_is_ilr_optimization_required(struct dc_link *link, struct dc_crtc_timing *crtc_timing); diff --git a/drivers/gpu/drm/amd/display/dc/optc/Makefile b/drivers/gpu/drm/amd/display/dc/optc/Makefile new file mode 100644 index 00000000000000..bb213335fb9fd5 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/optc/Makefile @@ -0,0 +1,108 @@ + +# 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. +# +# Makefile for the 'optc' sub-component of DAL. +# + + +ifdef CONFIG_DRM_AMD_DC_FP +############################################################################### +# DCN +############################################################################### + +OPTC_DCN10 = dcn10_optc.o + +AMD_DAL_OPTC_DCN10 = $(addprefix $(AMDDALPATH)/dc/optc/dcn10/,$(OPTC_DCN10)) + +AMD_DISPLAY_FILES += $(AMD_DAL_OPTC_DCN10) + +############################################################################### + +OPTC_DCN20 = dcn20_optc.o + +AMD_DAL_OPTC_DCN20 = $(addprefix $(AMDDALPATH)/dc/optc/dcn20/,$(OPTC_DCN20)) + +AMD_DISPLAY_FILES += $(AMD_DAL_OPTC_DCN20) + +############################################################################### + +OPTC_DCN201 = dcn201_optc.o + +AMD_DAL_OPTC_DCN201 = $(addprefix $(AMDDALPATH)/dc/optc/dcn201/,$(OPTC_DCN201)) + +AMD_DISPLAY_FILES += $(AMD_DAL_OPTC_DCN201) + +############################################################################### + +############################################################################### + +############################################################################### + +OPTC_DCN30 = dcn30_optc.o + +AMD_DAL_OPTC_DCN30 = $(addprefix $(AMDDALPATH)/dc/optc/dcn30/,$(OPTC_DCN30)) + +AMD_DISPLAY_FILES += $(AMD_DAL_OPTC_DCN30) + +############################################################################### + +OPTC_DCN301 = dcn301_optc.o + +AMD_DAL_OPTC_DCN301 = $(addprefix $(AMDDALPATH)/dc/optc/dcn301/,$(OPTC_DCN301)) + +AMD_DISPLAY_FILES += $(AMD_DAL_OPTC_DCN301) + +############################################################################### + +OPTC_DCN31 = dcn31_optc.o + +AMD_DAL_OPTC_DCN31 = $(addprefix $(AMDDALPATH)/dc/optc/dcn31/,$(OPTC_DCN31)) + +AMD_DISPLAY_FILES += $(AMD_DAL_OPTC_DCN31) + +############################################################################### + +OPTC_DCN314 = dcn314_optc.o + +AMD_DAL_OPTC_DCN314 = $(addprefix $(AMDDALPATH)/dc/optc/dcn314/,$(OPTC_DCN314)) + +AMD_DISPLAY_FILES += $(AMD_DAL_OPTC_DCN314) + +############################################################################### + +OPTC_DCN32 = dcn32_optc.o + +AMD_DAL_OPTC_DCN32 = $(addprefix $(AMDDALPATH)/dc/optc/dcn32/,$(OPTC_DCN32)) + +AMD_DISPLAY_FILES += $(AMD_DAL_OPTC_DCN32) + +############################################################################### + +OPTC_DCN35 = dcn35_optc.o + +AMD_DAL_OPTC_DCN35 = $(addprefix $(AMDDALPATH)/dc/optc/dcn35/,$(OPTC_DCN35)) + +AMD_DISPLAY_FILES += $(AMD_DAL_OPTC_DCN35) + +############################################################################### + +############################################################################### +endif diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.c new file mode 100644 index 00000000000000..0e8f4f36c87c51 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.c @@ -0,0 +1,1621 @@ +/* + * 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 + * + */ + + +#include "reg_helper.h" +#include "dcn10_optc.h" +#include "dc.h" +#include "dc_trace.h" + +#define REG(reg)\ + optc1->tg_regs->reg + +#define CTX \ + optc1->base.ctx + +#undef FN +#define FN(reg_name, field_name) \ + optc1->tg_shift->field_name, optc1->tg_mask->field_name + +#define STATIC_SCREEN_EVENT_MASK_RANGETIMING_DOUBLE_BUFFER_UPDATE_EN 0x100 + +/** + * apply_front_porch_workaround() - This is a workaround for a bug that has + * existed since R5xx and has not been fixed + * keep Front porch at minimum 2 for Interlaced + * mode or 1 for progressive. + * + * @timing: Timing parameters used to configure DCN blocks. + */ +static void apply_front_porch_workaround(struct dc_crtc_timing *timing) +{ + if (timing->flags.INTERLACE == 1) { + if (timing->v_front_porch < 2) + timing->v_front_porch = 2; + } else { + if (timing->v_front_porch < 1) + timing->v_front_porch = 1; + } +} + +void optc1_program_global_sync( + struct timing_generator *optc, + int vready_offset, + int vstartup_start, + int vupdate_offset, + int vupdate_width) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + optc1->vready_offset = vready_offset; + optc1->vstartup_start = vstartup_start; + optc1->vupdate_offset = vupdate_offset; + optc1->vupdate_width = vupdate_width; + + if (optc1->vstartup_start == 0) { + BREAK_TO_DEBUGGER(); + return; + } + + REG_SET(OTG_VSTARTUP_PARAM, 0, + VSTARTUP_START, optc1->vstartup_start); + + REG_SET_2(OTG_VUPDATE_PARAM, 0, + VUPDATE_OFFSET, optc1->vupdate_offset, + VUPDATE_WIDTH, optc1->vupdate_width); + + REG_SET(OTG_VREADY_PARAM, 0, + VREADY_OFFSET, optc1->vready_offset); +} + +static void optc1_disable_stereo(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET(OTG_STEREO_CONTROL, 0, + OTG_STEREO_EN, 0); + + REG_SET_2(OTG_3D_STRUCTURE_CONTROL, 0, + OTG_3D_STRUCTURE_EN, 0, + OTG_3D_STRUCTURE_STEREO_SEL_OVR, 0); +} + +void optc1_setup_vertical_interrupt0( + struct timing_generator *optc, + uint32_t start_line, + uint32_t end_line) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET_2(OTG_VERTICAL_INTERRUPT0_POSITION, 0, + OTG_VERTICAL_INTERRUPT0_LINE_START, start_line, + OTG_VERTICAL_INTERRUPT0_LINE_END, end_line); +} + +void optc1_setup_vertical_interrupt1( + struct timing_generator *optc, + uint32_t start_line) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET(OTG_VERTICAL_INTERRUPT1_POSITION, 0, + OTG_VERTICAL_INTERRUPT1_LINE_START, start_line); +} + +void optc1_setup_vertical_interrupt2( + struct timing_generator *optc, + uint32_t start_line) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET(OTG_VERTICAL_INTERRUPT2_POSITION, 0, + OTG_VERTICAL_INTERRUPT2_LINE_START, start_line); +} + +/** + * optc1_program_timing() - used by mode timing set Program + * CRTC Timing Registers - OTG_H_*, + * OTG_V_*, Pixel repetition. + * Including SYNC. Call BIOS command table to program Timings. + * + * @optc: timing_generator instance. + * @dc_crtc_timing: Timing parameters used to configure DCN blocks. + * @vready_offset: Vready's starting position. + * @vstartup_start: Vstartup period. + * @vupdate_offset: Vupdate starting position. + * @vupdate_width: Vupdate duration. + * @signal: DC signal types. + * @use_vbios: to program timings from BIOS command table. + * + */ +void optc1_program_timing( + struct timing_generator *optc, + const struct dc_crtc_timing *dc_crtc_timing, + int vready_offset, + int vstartup_start, + int vupdate_offset, + int vupdate_width, + const enum signal_type signal, + bool use_vbios) +{ + struct dc_crtc_timing patched_crtc_timing; + uint32_t asic_blank_end; + uint32_t asic_blank_start; + uint32_t v_total; + uint32_t v_sync_end; + uint32_t h_sync_polarity, v_sync_polarity; + uint32_t start_point = 0; + uint32_t field_num = 0; + enum h_timing_div_mode h_div = H_TIMING_NO_DIV; + + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + optc1->signal = signal; + optc1->vready_offset = vready_offset; + optc1->vstartup_start = vstartup_start; + optc1->vupdate_offset = vupdate_offset; + optc1->vupdate_width = vupdate_width; + patched_crtc_timing = *dc_crtc_timing; + apply_front_porch_workaround(&patched_crtc_timing); + optc1->orginal_patched_timing = patched_crtc_timing; + + /* Load horizontal timing */ + + /* CRTC_H_TOTAL = vesa.h_total - 1 */ + REG_SET(OTG_H_TOTAL, 0, + OTG_H_TOTAL, patched_crtc_timing.h_total - 1); + + /* h_sync_start = 0, h_sync_end = vesa.h_sync_width */ + REG_UPDATE_2(OTG_H_SYNC_A, + OTG_H_SYNC_A_START, 0, + OTG_H_SYNC_A_END, patched_crtc_timing.h_sync_width); + + /* blank_start = line end - front porch */ + asic_blank_start = patched_crtc_timing.h_total - + patched_crtc_timing.h_front_porch; + + /* blank_end = blank_start - active */ + asic_blank_end = asic_blank_start - + patched_crtc_timing.h_border_right - + patched_crtc_timing.h_addressable - + patched_crtc_timing.h_border_left; + + REG_UPDATE_2(OTG_H_BLANK_START_END, + OTG_H_BLANK_START, asic_blank_start, + OTG_H_BLANK_END, asic_blank_end); + + /* h_sync polarity */ + h_sync_polarity = patched_crtc_timing.flags.HSYNC_POSITIVE_POLARITY ? + 0 : 1; + + REG_UPDATE(OTG_H_SYNC_A_CNTL, + OTG_H_SYNC_A_POL, h_sync_polarity); + + v_total = patched_crtc_timing.v_total - 1; + + REG_SET(OTG_V_TOTAL, 0, + OTG_V_TOTAL, v_total); + + /* In case of V_TOTAL_CONTROL is on, make sure OTG_V_TOTAL_MAX and + * OTG_V_TOTAL_MIN are equal to V_TOTAL. + */ + optc->funcs->set_vtotal_min_max(optc, v_total, v_total); + + /* v_sync_start = 0, v_sync_end = v_sync_width */ + v_sync_end = patched_crtc_timing.v_sync_width; + + REG_UPDATE_2(OTG_V_SYNC_A, + OTG_V_SYNC_A_START, 0, + OTG_V_SYNC_A_END, v_sync_end); + + /* 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; + + REG_UPDATE_2(OTG_V_BLANK_START_END, + OTG_V_BLANK_START, asic_blank_start, + OTG_V_BLANK_END, asic_blank_end); + + /* v_sync polarity */ + v_sync_polarity = patched_crtc_timing.flags.VSYNC_POSITIVE_POLARITY ? + 0 : 1; + + REG_UPDATE(OTG_V_SYNC_A_CNTL, + OTG_V_SYNC_A_POL, v_sync_polarity); + + if (optc1->signal == SIGNAL_TYPE_DISPLAY_PORT || + optc1->signal == SIGNAL_TYPE_DISPLAY_PORT_MST || + optc1->signal == SIGNAL_TYPE_EDP) { + start_point = 1; + if (patched_crtc_timing.flags.INTERLACE == 1) + field_num = 1; + } + + /* Interlace */ + if (REG(OTG_INTERLACE_CONTROL)) { + if (patched_crtc_timing.flags.INTERLACE == 1) + REG_UPDATE(OTG_INTERLACE_CONTROL, + OTG_INTERLACE_ENABLE, 1); + else + REG_UPDATE(OTG_INTERLACE_CONTROL, + OTG_INTERLACE_ENABLE, 0); + } + + /* VTG enable set to 0 first VInit */ + REG_UPDATE(CONTROL, + VTG0_ENABLE, 0); + + /* original code is using VTG offset to address OTG reg, seems wrong */ + REG_UPDATE_2(OTG_CONTROL, + OTG_START_POINT_CNTL, start_point, + OTG_FIELD_NUMBER_CNTL, field_num); + + optc->funcs->program_global_sync(optc, + vready_offset, + vstartup_start, + vupdate_offset, + vupdate_width); + + optc->funcs->set_vtg_params(optc, dc_crtc_timing, true); + + /* TODO + * patched_crtc_timing.flags.HORZ_COUNT_BY_TWO == 1 + * program_horz_count_by_2 + * for DVI 30bpp mode, 0 otherwise + * program_horz_count_by_2(optc, &patched_crtc_timing); + */ + + /* Enable stereo - only when we need to pack 3D frame. Other types + * of stereo handled in explicit call + */ + + if (optc1_is_two_pixels_per_containter(&patched_crtc_timing) || optc1->opp_count == 2) + h_div = H_TIMING_DIV_BY2; + + if (REG(OPTC_DATA_FORMAT_CONTROL) && optc1->tg_mask->OPTC_DATA_FORMAT != 0) { + uint32_t data_fmt = 0; + + if (patched_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR422) + data_fmt = 1; + else if (patched_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) + data_fmt = 2; + + REG_UPDATE(OPTC_DATA_FORMAT_CONTROL, OPTC_DATA_FORMAT, data_fmt); + } + + if (optc1->tg_mask->OTG_H_TIMING_DIV_MODE != 0) { + if (optc1->opp_count == 4) + h_div = H_TIMING_DIV_BY4; + + REG_UPDATE(OTG_H_TIMING_CNTL, + OTG_H_TIMING_DIV_MODE, h_div); + } else { + REG_UPDATE(OTG_H_TIMING_CNTL, + OTG_H_TIMING_DIV_BY2, h_div); + } +} + +/** + * optc1_set_vtg_params - Set Vertical Timing Generator (VTG) parameters + * + * @optc: timing_generator struct used to extract the optc parameters + * @dc_crtc_timing: Timing parameters configured + * @program_fp2: Boolean value indicating if FP2 will be programmed or not + * + * OTG is responsible for generating the global sync signals, including + * vertical timing information for each HUBP in the dcfclk domain. Each VTG is + * associated with one OTG that provides HUBP with vertical timing information + * (i.e., there is 1:1 correspondence between OTG and VTG). This function is + * responsible for setting the OTG parameters to the VTG during the pipe + * programming. + */ +void optc1_set_vtg_params(struct timing_generator *optc, + const struct dc_crtc_timing *dc_crtc_timing, bool program_fp2) +{ + struct dc_crtc_timing patched_crtc_timing; + uint32_t asic_blank_end; + uint32_t v_init; + uint32_t v_fp2 = 0; + int32_t vertical_line_start; + + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + patched_crtc_timing = *dc_crtc_timing; + apply_front_porch_workaround(&patched_crtc_timing); + + /* VCOUNT_INIT is the start of blank */ + v_init = patched_crtc_timing.v_total - patched_crtc_timing.v_front_porch; + + /* end of blank = v_init - active */ + asic_blank_end = v_init - + patched_crtc_timing.v_border_bottom - + patched_crtc_timing.v_addressable - + patched_crtc_timing.v_border_top; + + /* if VSTARTUP is before VSYNC, FP2 is the offset, otherwise 0 */ + vertical_line_start = asic_blank_end - optc1->vstartup_start + 1; + if (vertical_line_start < 0) + v_fp2 = -vertical_line_start; + + /* Interlace */ + if (REG(OTG_INTERLACE_CONTROL)) { + if (patched_crtc_timing.flags.INTERLACE == 1) { + v_init = v_init / 2; + if ((optc1->vstartup_start/2)*2 > asic_blank_end) + v_fp2 = v_fp2 / 2; + } + } + + if (program_fp2) + REG_UPDATE_2(CONTROL, + VTG0_FP2, v_fp2, + VTG0_VCOUNT_INIT, v_init); + else + REG_UPDATE(CONTROL, VTG0_VCOUNT_INIT, v_init); +} + +void optc1_set_blank_data_double_buffer(struct timing_generator *optc, bool enable) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + uint32_t blank_data_double_buffer_enable = enable ? 1 : 0; + + REG_UPDATE(OTG_DOUBLE_BUFFER_CONTROL, + OTG_BLANK_DATA_DOUBLE_BUFFER_EN, blank_data_double_buffer_enable); +} + +/** + * optc1_set_timing_double_buffer() - DRR double buffering control + * + * Sets double buffer point for V_TOTAL, H_TOTAL, VTOTAL_MIN, + * VTOTAL_MAX, VTOTAL_MIN_SEL and VTOTAL_MAX_SEL registers. + * + * @optc: timing_generator instance. + * @enable: Enable DRR double buffering control if true, disable otherwise. + * + * Options: any time, start of frame, dp start of frame (range timing) + */ +void optc1_set_timing_double_buffer(struct timing_generator *optc, bool enable) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + uint32_t mode = enable ? 2 : 0; + + REG_UPDATE(OTG_DOUBLE_BUFFER_CONTROL, + OTG_RANGE_TIMING_DBUF_UPDATE_MODE, mode); +} + +/** + * optc1_unblank_crtc() - Call ASIC Control Object to UnBlank CRTC. + * + * @optc: timing_generator instance. + */ +static void optc1_unblank_crtc(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_UPDATE_2(OTG_BLANK_CONTROL, + OTG_BLANK_DATA_EN, 0, + OTG_BLANK_DE_MODE, 0); + + /* W/A for automated testing + * Automated testing will fail underflow test as there + * sporadic underflows which occur during the optc blank + * sequence. As a w/a, clear underflow on unblank. + * This prevents the failure, but will not mask actual + * underflow that affect real use cases. + */ + optc1_clear_optc_underflow(optc); +} + +/** + * optc1_blank_crtc() - Call ASIC Control Object to Blank CRTC. + * + * @optc: timing_generator instance. + */ + +static void optc1_blank_crtc(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_UPDATE_2(OTG_BLANK_CONTROL, + OTG_BLANK_DATA_EN, 1, + OTG_BLANK_DE_MODE, 0); + + optc1_set_blank_data_double_buffer(optc, false); +} + +void optc1_set_blank(struct timing_generator *optc, + bool enable_blanking) +{ + if (enable_blanking) + optc1_blank_crtc(optc); + else + optc1_unblank_crtc(optc); +} + +bool optc1_is_blanked(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + uint32_t blank_en; + uint32_t blank_state; + + REG_GET_2(OTG_BLANK_CONTROL, + OTG_BLANK_DATA_EN, &blank_en, + OTG_CURRENT_BLANK_STATE, &blank_state); + + return blank_en && blank_state; +} + +void optc1_enable_optc_clock(struct timing_generator *optc, bool enable) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + if (enable) { + REG_UPDATE_2(OPTC_INPUT_CLOCK_CONTROL, + OPTC_INPUT_CLK_EN, 1, + OPTC_INPUT_CLK_GATE_DIS, 1); + + REG_WAIT(OPTC_INPUT_CLOCK_CONTROL, + OPTC_INPUT_CLK_ON, 1, + 1, 1000); + + /* Enable clock */ + REG_UPDATE_2(OTG_CLOCK_CONTROL, + OTG_CLOCK_EN, 1, + OTG_CLOCK_GATE_DIS, 1); + REG_WAIT(OTG_CLOCK_CONTROL, + OTG_CLOCK_ON, 1, + 1, 1000); + } else { + + //last chance to clear underflow, otherwise, it will always there due to clock is off. + if (optc->funcs->is_optc_underflow_occurred(optc) == true) + optc->funcs->clear_optc_underflow(optc); + + REG_UPDATE_2(OTG_CLOCK_CONTROL, + OTG_CLOCK_GATE_DIS, 0, + OTG_CLOCK_EN, 0); + + REG_UPDATE_2(OPTC_INPUT_CLOCK_CONTROL, + OPTC_INPUT_CLK_GATE_DIS, 0, + OPTC_INPUT_CLK_EN, 0); + } +} + +/** + * optc1_enable_crtc() - Enable CRTC - call ASIC Control Object to enable Timing generator. + * + * @optc: timing_generator instance. + */ +static bool optc1_enable_crtc(struct timing_generator *optc) +{ + /* TODO FPGA wait for answer + * OTG_MASTER_UPDATE_MODE != CRTC_MASTER_UPDATE_MODE + * OTG_MASTER_UPDATE_LOCK != CRTC_MASTER_UPDATE_LOCK + */ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + /* opp instance for OTG. For DCN1.0, ODM is remoed. + * OPP and OPTC should 1:1 mapping + */ + REG_UPDATE(OPTC_DATA_SOURCE_SELECT, + OPTC_SRC_SEL, optc->inst); + + /* VTG enable first is for HW workaround */ + REG_UPDATE(CONTROL, + VTG0_ENABLE, 1); + + REG_SEQ_START(); + + /* Enable CRTC */ + REG_UPDATE_2(OTG_CONTROL, + OTG_DISABLE_POINT_CNTL, 3, + OTG_MASTER_EN, 1); + + REG_SEQ_SUBMIT(); + REG_SEQ_WAIT_DONE(); + + return true; +} + +/* disable_crtc - call ASIC Control Object to disable Timing generator. */ +bool optc1_disable_crtc(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + /* disable otg request until end of the first line + * in the vertical blank region + */ + REG_UPDATE_2(OTG_CONTROL, + OTG_DISABLE_POINT_CNTL, 3, + OTG_MASTER_EN, 0); + + REG_UPDATE(CONTROL, + VTG0_ENABLE, 0); + + /* CRTC disabled, so disable clock. */ + REG_WAIT(OTG_CLOCK_CONTROL, + OTG_BUSY, 0, + 1, 100000); + + return true; +} + + +void optc1_program_blank_color( + struct timing_generator *optc, + const struct tg_color *black_color) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET_3(OTG_BLACK_COLOR, 0, + OTG_BLACK_COLOR_B_CB, black_color->color_b_cb, + OTG_BLACK_COLOR_G_Y, black_color->color_g_y, + OTG_BLACK_COLOR_R_CR, black_color->color_r_cr); +} + +bool optc1_validate_timing( + struct timing_generator *optc, + const struct dc_crtc_timing *timing) +{ + uint32_t v_blank; + uint32_t h_blank; + uint32_t min_v_blank; + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + ASSERT(timing != NULL); + + v_blank = (timing->v_total - timing->v_addressable - + timing->v_border_top - timing->v_border_bottom); + + h_blank = (timing->h_total - timing->h_addressable - + timing->h_border_right - + timing->h_border_left); + + if (timing->timing_3d_format != TIMING_3D_FORMAT_NONE && + timing->timing_3d_format != TIMING_3D_FORMAT_HW_FRAME_PACKING && + timing->timing_3d_format != TIMING_3D_FORMAT_TOP_AND_BOTTOM && + timing->timing_3d_format != TIMING_3D_FORMAT_SIDE_BY_SIDE && + timing->timing_3d_format != TIMING_3D_FORMAT_FRAME_ALTERNATE && + timing->timing_3d_format != TIMING_3D_FORMAT_INBAND_FA) + return false; + + /* Temporarily blocking interlacing mode until it's supported */ + if (timing->flags.INTERLACE == 1) + return false; + + /* Check maximum number of pixels supported by Timing Generator + * (Currently will never fail, in order to fail needs display which + * needs more than 8192 horizontal and + * more than 8192 vertical total pixels) + */ + if (timing->h_total > optc1->max_h_total || + timing->v_total > optc1->max_v_total) + return false; + + + if (h_blank < optc1->min_h_blank) + return false; + + if (timing->h_sync_width < optc1->min_h_sync_width || + timing->v_sync_width < optc1->min_v_sync_width) + return false; + + min_v_blank = timing->flags.INTERLACE?optc1->min_v_blank_interlace:optc1->min_v_blank; + + if (v_blank < min_v_blank) + return false; + + return true; + +} + +/* + * get_vblank_counter + * + * @brief + * Get counter for vertical blanks. use register CRTC_STATUS_FRAME_COUNT which + * holds the counter of frames. + * + * @param + * struct timing_generator *optc - [in] timing generator which controls the + * desired CRTC + * + * @return + * Counter of frames, which should equal to number of vblanks. + */ +uint32_t optc1_get_vblank_counter(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + uint32_t frame_count; + + REG_GET(OTG_STATUS_FRAME_COUNT, + OTG_FRAME_COUNT, &frame_count); + + return frame_count; +} + +void optc1_lock(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET(OTG_GLOBAL_CONTROL0, 0, + OTG_MASTER_UPDATE_LOCK_SEL, optc->inst); + REG_SET(OTG_MASTER_UPDATE_LOCK, 0, + OTG_MASTER_UPDATE_LOCK, 1); + + REG_WAIT(OTG_MASTER_UPDATE_LOCK, + UPDATE_LOCK_STATUS, 1, + 1, 10); + + TRACE_OPTC_LOCK_UNLOCK_STATE(optc1, optc->inst, true); +} + +void optc1_unlock(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET(OTG_MASTER_UPDATE_LOCK, 0, + OTG_MASTER_UPDATE_LOCK, 0); + + TRACE_OPTC_LOCK_UNLOCK_STATE(optc1, optc->inst, false); +} + +void optc1_get_position(struct timing_generator *optc, + struct crtc_position *position) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_GET_2(OTG_STATUS_POSITION, + OTG_HORZ_COUNT, &position->horizontal_count, + OTG_VERT_COUNT, &position->vertical_count); + + REG_GET(OTG_NOM_VERT_POSITION, + OTG_VERT_COUNT_NOM, &position->nominal_vcount); +} + +bool optc1_is_counter_moving(struct timing_generator *optc) +{ + struct crtc_position position1, position2; + + optc->funcs->get_position(optc, &position1); + optc->funcs->get_position(optc, &position2); + + if (position1.horizontal_count == position2.horizontal_count && + position1.vertical_count == position2.vertical_count) + return false; + else + return true; +} + +bool optc1_did_triggered_reset_occur( + struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + uint32_t occurred_force, occurred_vsync; + + REG_GET(OTG_FORCE_COUNT_NOW_CNTL, + OTG_FORCE_COUNT_NOW_OCCURRED, &occurred_force); + + REG_GET(OTG_VERT_SYNC_CONTROL, + OTG_FORCE_VSYNC_NEXT_LINE_OCCURRED, &occurred_vsync); + + return occurred_vsync != 0 || occurred_force != 0; +} + +void optc1_disable_reset_trigger(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_WRITE(OTG_TRIGA_CNTL, 0); + + REG_SET(OTG_FORCE_COUNT_NOW_CNTL, 0, + OTG_FORCE_COUNT_NOW_CLEAR, 1); + + REG_SET(OTG_VERT_SYNC_CONTROL, 0, + OTG_FORCE_VSYNC_NEXT_LINE_CLEAR, 1); +} + +void optc1_enable_reset_trigger(struct timing_generator *optc, int source_tg_inst) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + uint32_t falling_edge; + + REG_GET(OTG_V_SYNC_A_CNTL, + OTG_V_SYNC_A_POL, &falling_edge); + + if (falling_edge) + REG_SET_3(OTG_TRIGA_CNTL, 0, + /* vsync signal from selected OTG pipe based + * on OTG_TRIG_SOURCE_PIPE_SELECT setting + */ + OTG_TRIGA_SOURCE_SELECT, 20, + OTG_TRIGA_SOURCE_PIPE_SELECT, source_tg_inst, + /* always detect falling edge */ + OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, 1); + else + REG_SET_3(OTG_TRIGA_CNTL, 0, + /* vsync signal from selected OTG pipe based + * on OTG_TRIG_SOURCE_PIPE_SELECT setting + */ + OTG_TRIGA_SOURCE_SELECT, 20, + OTG_TRIGA_SOURCE_PIPE_SELECT, source_tg_inst, + /* always detect rising edge */ + OTG_TRIGA_RISING_EDGE_DETECT_CNTL, 1); + + REG_SET(OTG_FORCE_COUNT_NOW_CNTL, 0, + /* force H count to H_TOTAL and V count to V_TOTAL in + * progressive mode and V_TOTAL-1 in interlaced mode + */ + OTG_FORCE_COUNT_NOW_MODE, 2); +} + +void optc1_enable_crtc_reset( + struct timing_generator *optc, + int source_tg_inst, + struct crtc_trigger_info *crtc_tp) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + uint32_t falling_edge = 0; + uint32_t rising_edge = 0; + + switch (crtc_tp->event) { + + case CRTC_EVENT_VSYNC_RISING: + rising_edge = 1; + break; + + case CRTC_EVENT_VSYNC_FALLING: + falling_edge = 1; + break; + } + + REG_SET_4(OTG_TRIGA_CNTL, 0, + /* vsync signal from selected OTG pipe based + * on OTG_TRIG_SOURCE_PIPE_SELECT setting + */ + OTG_TRIGA_SOURCE_SELECT, 20, + OTG_TRIGA_SOURCE_PIPE_SELECT, source_tg_inst, + /* always detect falling edge */ + OTG_TRIGA_RISING_EDGE_DETECT_CNTL, rising_edge, + OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, falling_edge); + + switch (crtc_tp->delay) { + case TRIGGER_DELAY_NEXT_LINE: + REG_SET(OTG_VERT_SYNC_CONTROL, 0, + OTG_AUTO_FORCE_VSYNC_MODE, 1); + break; + case TRIGGER_DELAY_NEXT_PIXEL: + REG_SET(OTG_FORCE_COUNT_NOW_CNTL, 0, + /* force H count to H_TOTAL and V count to V_TOTAL in + * progressive mode and V_TOTAL-1 in interlaced mode + */ + OTG_FORCE_COUNT_NOW_MODE, 2); + break; + } +} + +void optc1_wait_for_state(struct timing_generator *optc, + enum crtc_state state) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + switch (state) { + case CRTC_STATE_VBLANK: + REG_WAIT(OTG_STATUS, + OTG_V_BLANK, 1, + 1, 100000); /* 1 vupdate at 10hz */ + break; + + case CRTC_STATE_VACTIVE: + REG_WAIT(OTG_STATUS, + OTG_V_ACTIVE_DISP, 1, + 1, 100000); /* 1 vupdate at 10hz */ + break; + + default: + break; + } +} + +void optc1_set_early_control( + struct timing_generator *optc, + uint32_t early_cntl) +{ + /* asic design change, do not need this control + * empty for share caller logic + */ +} + + +void optc1_set_static_screen_control( + struct timing_generator *optc, + uint32_t event_triggers, + uint32_t num_frames) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + // By register spec, it only takes 8 bit value + if (num_frames > 0xFF) + num_frames = 0xFF; + + /* Bit 8 is no longer applicable in RV for PSR case, + * set bit 8 to 0 if given + */ + if ((event_triggers & STATIC_SCREEN_EVENT_MASK_RANGETIMING_DOUBLE_BUFFER_UPDATE_EN) + != 0) + event_triggers = event_triggers & + ~STATIC_SCREEN_EVENT_MASK_RANGETIMING_DOUBLE_BUFFER_UPDATE_EN; + + REG_SET_2(OTG_STATIC_SCREEN_CONTROL, 0, + OTG_STATIC_SCREEN_EVENT_MASK, event_triggers, + OTG_STATIC_SCREEN_FRAME_COUNT, num_frames); +} + +static void optc1_setup_manual_trigger(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET(OTG_GLOBAL_CONTROL2, 0, + MANUAL_FLOW_CONTROL_SEL, optc->inst); + + REG_SET_8(OTG_TRIGA_CNTL, 0, + OTG_TRIGA_SOURCE_SELECT, 22, + OTG_TRIGA_SOURCE_PIPE_SELECT, optc->inst, + OTG_TRIGA_RISING_EDGE_DETECT_CNTL, 1, + OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, 0, + OTG_TRIGA_POLARITY_SELECT, 0, + OTG_TRIGA_FREQUENCY_SELECT, 0, + OTG_TRIGA_DELAY, 0, + OTG_TRIGA_CLEAR, 1); +} + +static void optc1_program_manual_trigger(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET(OTG_MANUAL_FLOW_CONTROL, 0, + MANUAL_FLOW_CONTROL, 1); + + REG_SET(OTG_MANUAL_FLOW_CONTROL, 0, + MANUAL_FLOW_CONTROL, 0); +} + +/** + * optc1_set_drr() - Program dynamic refresh rate registers m_OTGx_OTG_V_TOTAL_*. + * + * @optc: timing_generator instance. + * @params: parameters used for Dynamic Refresh Rate. + */ +void optc1_set_drr( + struct timing_generator *optc, + const struct drr_params *params) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + if (params != NULL && + params->vertical_total_max > 0 && + params->vertical_total_min > 0) { + + if (params->vertical_total_mid != 0) { + + REG_SET(OTG_V_TOTAL_MID, 0, + OTG_V_TOTAL_MID, params->vertical_total_mid - 1); + + REG_UPDATE_2(OTG_V_TOTAL_CONTROL, + OTG_VTOTAL_MID_REPLACING_MAX_EN, 1, + OTG_VTOTAL_MID_FRAME_NUM, + (uint8_t)params->vertical_total_mid_frame_num); + + } + + optc->funcs->set_vtotal_min_max(optc, params->vertical_total_min - 1, params->vertical_total_max - 1); + + REG_UPDATE_5(OTG_V_TOTAL_CONTROL, + OTG_V_TOTAL_MIN_SEL, 1, + OTG_V_TOTAL_MAX_SEL, 1, + OTG_FORCE_LOCK_ON_EVENT, 0, + OTG_SET_V_TOTAL_MIN_MASK_EN, 0, + OTG_SET_V_TOTAL_MIN_MASK, 0); + } + + // Setup manual flow control for EOF via TRIG_A + optc->funcs->setup_manual_trigger(optc); +} + +void optc1_set_vtotal_min_max(struct timing_generator *optc, int vtotal_min, int vtotal_max) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET(OTG_V_TOTAL_MAX, 0, + OTG_V_TOTAL_MAX, vtotal_max); + + REG_SET(OTG_V_TOTAL_MIN, 0, + OTG_V_TOTAL_MIN, vtotal_min); +} + +static void optc1_set_test_pattern( + struct timing_generator *optc, + /* TODO: replace 'controller_dp_test_pattern' by 'test_pattern_mode' + * because this is not DP-specific (which is probably somewhere in DP + * encoder) */ + enum controller_dp_test_pattern test_pattern, + enum dc_color_depth color_depth) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + enum test_pattern_color_format bit_depth; + enum test_pattern_dyn_range dyn_range; + enum test_pattern_mode mode; + uint32_t pattern_mask; + uint32_t pattern_data; + /* color ramp generator mixes 16-bits color */ + uint32_t src_bpc = 16; + /* requested bpc */ + uint32_t dst_bpc; + uint32_t index; + /* RGB values of the color bars. + * Produce two RGB colors: RGB0 - white (all Fs) + * and RGB1 - black (all 0s) + * (three RGB components for two colors) + */ + uint16_t src_color[6] = {0xFFFF, 0xFFFF, 0xFFFF, 0x0000, + 0x0000, 0x0000}; + /* dest color (converted to the specified color format) */ + uint16_t dst_color[6]; + uint32_t inc_base; + + /* translate to bit depth */ + switch (color_depth) { + case COLOR_DEPTH_666: + bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_6; + break; + case COLOR_DEPTH_888: + bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_8; + break; + case COLOR_DEPTH_101010: + bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_10; + break; + case COLOR_DEPTH_121212: + bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_12; + break; + default: + bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_8; + break; + } + + switch (test_pattern) { + case CONTROLLER_DP_TEST_PATTERN_COLORSQUARES: + case CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA: + { + dyn_range = (test_pattern == + CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA ? + TEST_PATTERN_DYN_RANGE_CEA : + TEST_PATTERN_DYN_RANGE_VESA); + mode = TEST_PATTERN_MODE_COLORSQUARES_RGB; + + REG_UPDATE_2(OTG_TEST_PATTERN_PARAMETERS, + OTG_TEST_PATTERN_VRES, 6, + OTG_TEST_PATTERN_HRES, 6); + + REG_UPDATE_4(OTG_TEST_PATTERN_CONTROL, + OTG_TEST_PATTERN_EN, 1, + OTG_TEST_PATTERN_MODE, mode, + OTG_TEST_PATTERN_DYNAMIC_RANGE, dyn_range, + OTG_TEST_PATTERN_COLOR_FORMAT, bit_depth); + } + break; + + case CONTROLLER_DP_TEST_PATTERN_VERTICALBARS: + case CONTROLLER_DP_TEST_PATTERN_HORIZONTALBARS: + { + mode = (test_pattern == + CONTROLLER_DP_TEST_PATTERN_VERTICALBARS ? + TEST_PATTERN_MODE_VERTICALBARS : + TEST_PATTERN_MODE_HORIZONTALBARS); + + switch (bit_depth) { + case TEST_PATTERN_COLOR_FORMAT_BPC_6: + dst_bpc = 6; + break; + case TEST_PATTERN_COLOR_FORMAT_BPC_8: + dst_bpc = 8; + break; + case TEST_PATTERN_COLOR_FORMAT_BPC_10: + dst_bpc = 10; + break; + default: + dst_bpc = 8; + break; + } + + /* adjust color to the required colorFormat */ + for (index = 0; index < 6; index++) { + /* dst = 2^dstBpc * src / 2^srcBpc = src >> + * (srcBpc - dstBpc); + */ + dst_color[index] = + src_color[index] >> (src_bpc - dst_bpc); + /* CRTC_TEST_PATTERN_DATA has 16 bits, + * lowest 6 are hardwired to ZERO + * color bits should be left aligned to MSB + * XXXXXXXXXX000000 for 10 bit, + * XXXXXXXX00000000 for 8 bit and XXXXXX0000000000 for 6 + */ + dst_color[index] <<= (16 - dst_bpc); + } + + REG_WRITE(OTG_TEST_PATTERN_PARAMETERS, 0); + + /* We have to write the mask before data, similar to pipeline. + * For example, for 8 bpc, if we want RGB0 to be magenta, + * and RGB1 to be cyan, + * we need to make 7 writes: + * MASK DATA + * 000001 00000000 00000000 set mask to R0 + * 000010 11111111 00000000 R0 255, 0xFF00, set mask to G0 + * 000100 00000000 00000000 G0 0, 0x0000, set mask to B0 + * 001000 11111111 00000000 B0 255, 0xFF00, set mask to R1 + * 010000 00000000 00000000 R1 0, 0x0000, set mask to G1 + * 100000 11111111 00000000 G1 255, 0xFF00, set mask to B1 + * 100000 11111111 00000000 B1 255, 0xFF00 + * + * we will make a loop of 6 in which we prepare the mask, + * then write, then prepare the color for next write. + * first iteration will write mask only, + * but each next iteration color prepared in + * previous iteration will be written within new mask, + * the last component will written separately, + * mask is not changing between 6th and 7th write + * and color will be prepared by last iteration + */ + + /* write color, color values mask in CRTC_TEST_PATTERN_MASK + * is B1, G1, R1, B0, G0, R0 + */ + pattern_data = 0; + for (index = 0; index < 6; index++) { + /* prepare color mask, first write PATTERN_DATA + * will have all zeros + */ + pattern_mask = (1 << index); + + /* write color component */ + REG_SET_2(OTG_TEST_PATTERN_COLOR, 0, + OTG_TEST_PATTERN_MASK, pattern_mask, + OTG_TEST_PATTERN_DATA, pattern_data); + + /* prepare next color component, + * will be written in the next iteration + */ + pattern_data = dst_color[index]; + } + /* write last color component, + * it's been already prepared in the loop + */ + REG_SET_2(OTG_TEST_PATTERN_COLOR, 0, + OTG_TEST_PATTERN_MASK, pattern_mask, + OTG_TEST_PATTERN_DATA, pattern_data); + + /* enable test pattern */ + REG_UPDATE_4(OTG_TEST_PATTERN_CONTROL, + OTG_TEST_PATTERN_EN, 1, + OTG_TEST_PATTERN_MODE, mode, + OTG_TEST_PATTERN_DYNAMIC_RANGE, 0, + OTG_TEST_PATTERN_COLOR_FORMAT, bit_depth); + } + break; + + case CONTROLLER_DP_TEST_PATTERN_COLORRAMP: + { + mode = (bit_depth == + TEST_PATTERN_COLOR_FORMAT_BPC_10 ? + TEST_PATTERN_MODE_DUALRAMP_RGB : + TEST_PATTERN_MODE_SINGLERAMP_RGB); + + switch (bit_depth) { + case TEST_PATTERN_COLOR_FORMAT_BPC_6: + dst_bpc = 6; + break; + case TEST_PATTERN_COLOR_FORMAT_BPC_8: + dst_bpc = 8; + break; + case TEST_PATTERN_COLOR_FORMAT_BPC_10: + dst_bpc = 10; + break; + default: + dst_bpc = 8; + break; + } + + /* increment for the first ramp for one color gradation + * 1 gradation for 6-bit color is 2^10 + * gradations in 16-bit color + */ + inc_base = (src_bpc - dst_bpc); + + switch (bit_depth) { + case TEST_PATTERN_COLOR_FORMAT_BPC_6: + { + REG_UPDATE_5(OTG_TEST_PATTERN_PARAMETERS, + OTG_TEST_PATTERN_INC0, inc_base, + OTG_TEST_PATTERN_INC1, 0, + OTG_TEST_PATTERN_HRES, 6, + OTG_TEST_PATTERN_VRES, 6, + OTG_TEST_PATTERN_RAMP0_OFFSET, 0); + } + break; + case TEST_PATTERN_COLOR_FORMAT_BPC_8: + { + REG_UPDATE_5(OTG_TEST_PATTERN_PARAMETERS, + OTG_TEST_PATTERN_INC0, inc_base, + OTG_TEST_PATTERN_INC1, 0, + OTG_TEST_PATTERN_HRES, 8, + OTG_TEST_PATTERN_VRES, 6, + OTG_TEST_PATTERN_RAMP0_OFFSET, 0); + } + break; + case TEST_PATTERN_COLOR_FORMAT_BPC_10: + { + REG_UPDATE_5(OTG_TEST_PATTERN_PARAMETERS, + OTG_TEST_PATTERN_INC0, inc_base, + OTG_TEST_PATTERN_INC1, inc_base + 2, + OTG_TEST_PATTERN_HRES, 8, + OTG_TEST_PATTERN_VRES, 5, + OTG_TEST_PATTERN_RAMP0_OFFSET, 384 << 6); + } + break; + default: + break; + } + + REG_WRITE(OTG_TEST_PATTERN_COLOR, 0); + + /* enable test pattern */ + REG_WRITE(OTG_TEST_PATTERN_CONTROL, 0); + + REG_SET_4(OTG_TEST_PATTERN_CONTROL, 0, + OTG_TEST_PATTERN_EN, 1, + OTG_TEST_PATTERN_MODE, mode, + OTG_TEST_PATTERN_DYNAMIC_RANGE, 0, + OTG_TEST_PATTERN_COLOR_FORMAT, bit_depth); + } + break; + case CONTROLLER_DP_TEST_PATTERN_VIDEOMODE: + { + REG_WRITE(OTG_TEST_PATTERN_CONTROL, 0); + REG_WRITE(OTG_TEST_PATTERN_COLOR, 0); + REG_WRITE(OTG_TEST_PATTERN_PARAMETERS, 0); + } + break; + default: + break; + + } +} + +void optc1_get_crtc_scanoutpos( + struct timing_generator *optc, + uint32_t *v_blank_start, + uint32_t *v_blank_end, + uint32_t *h_position, + uint32_t *v_position) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + struct crtc_position position; + + REG_GET_2(OTG_V_BLANK_START_END, + OTG_V_BLANK_START, v_blank_start, + OTG_V_BLANK_END, v_blank_end); + + optc1_get_position(optc, &position); + + *h_position = position.horizontal_count; + *v_position = position.vertical_count; +} + +static void optc1_enable_stereo(struct timing_generator *optc, + const struct dc_crtc_timing *timing, struct crtc_stereo_flags *flags) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + if (flags) { + uint32_t stereo_en; + stereo_en = flags->FRAME_PACKED == 0 ? 1 : 0; + + if (flags->PROGRAM_STEREO) + REG_UPDATE_3(OTG_STEREO_CONTROL, + OTG_STEREO_EN, stereo_en, + OTG_STEREO_SYNC_OUTPUT_LINE_NUM, 0, + OTG_STEREO_SYNC_OUTPUT_POLARITY, flags->RIGHT_EYE_POLARITY == 0 ? 0 : 1); + + if (flags->PROGRAM_POLARITY) + REG_UPDATE(OTG_STEREO_CONTROL, + OTG_STEREO_EYE_FLAG_POLARITY, + flags->RIGHT_EYE_POLARITY == 0 ? 0 : 1); + + if (flags->DISABLE_STEREO_DP_SYNC) + REG_UPDATE(OTG_STEREO_CONTROL, + OTG_DISABLE_STEREOSYNC_OUTPUT_FOR_DP, 1); + + if (flags->PROGRAM_STEREO) + REG_UPDATE_2(OTG_3D_STRUCTURE_CONTROL, + OTG_3D_STRUCTURE_EN, flags->FRAME_PACKED, + OTG_3D_STRUCTURE_STEREO_SEL_OVR, flags->FRAME_PACKED); + + } +} + +void optc1_program_stereo(struct timing_generator *optc, + const struct dc_crtc_timing *timing, struct crtc_stereo_flags *flags) +{ + if (flags->PROGRAM_STEREO) + optc1_enable_stereo(optc, timing, flags); + else + optc1_disable_stereo(optc); +} + + +bool optc1_is_stereo_left_eye(struct timing_generator *optc) +{ + bool ret = false; + uint32_t left_eye = 0; + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_GET(OTG_STEREO_STATUS, + OTG_STEREO_CURRENT_EYE, &left_eye); + if (left_eye == 1) + ret = true; + else + ret = false; + + return ret; +} + +bool optc1_get_hw_timing(struct timing_generator *tg, + struct dc_crtc_timing *hw_crtc_timing) +{ + struct dcn_otg_state s = {0}; + + if (tg == NULL || hw_crtc_timing == NULL) + return false; + + optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s); + + hw_crtc_timing->h_total = s.h_total + 1; + hw_crtc_timing->h_addressable = s.h_total - ((s.h_total - s.h_blank_start) + s.h_blank_end); + hw_crtc_timing->h_front_porch = s.h_total + 1 - s.h_blank_start; + hw_crtc_timing->h_sync_width = s.h_sync_a_end - s.h_sync_a_start; + + hw_crtc_timing->v_total = s.v_total + 1; + hw_crtc_timing->v_addressable = s.v_total - ((s.v_total - s.v_blank_start) + s.v_blank_end); + hw_crtc_timing->v_front_porch = s.v_total + 1 - s.v_blank_start; + hw_crtc_timing->v_sync_width = s.v_sync_a_end - s.v_sync_a_start; + + return true; +} + + +void optc1_read_otg_state(struct optc *optc1, + struct dcn_otg_state *s) +{ + REG_GET(OTG_CONTROL, + OTG_MASTER_EN, &s->otg_enabled); + + REG_GET_2(OTG_V_BLANK_START_END, + OTG_V_BLANK_START, &s->v_blank_start, + OTG_V_BLANK_END, &s->v_blank_end); + + REG_GET(OTG_V_SYNC_A_CNTL, + OTG_V_SYNC_A_POL, &s->v_sync_a_pol); + + REG_GET(OTG_V_TOTAL, + OTG_V_TOTAL, &s->v_total); + + REG_GET(OTG_V_TOTAL_MAX, + OTG_V_TOTAL_MAX, &s->v_total_max); + + REG_GET(OTG_V_TOTAL_MIN, + OTG_V_TOTAL_MIN, &s->v_total_min); + + REG_GET(OTG_V_TOTAL_CONTROL, + OTG_V_TOTAL_MAX_SEL, &s->v_total_max_sel); + + REG_GET(OTG_V_TOTAL_CONTROL, + OTG_V_TOTAL_MIN_SEL, &s->v_total_min_sel); + + REG_GET_2(OTG_V_SYNC_A, + OTG_V_SYNC_A_START, &s->v_sync_a_start, + OTG_V_SYNC_A_END, &s->v_sync_a_end); + + REG_GET_2(OTG_H_BLANK_START_END, + OTG_H_BLANK_START, &s->h_blank_start, + OTG_H_BLANK_END, &s->h_blank_end); + + REG_GET_2(OTG_H_SYNC_A, + OTG_H_SYNC_A_START, &s->h_sync_a_start, + OTG_H_SYNC_A_END, &s->h_sync_a_end); + + REG_GET(OTG_H_SYNC_A_CNTL, + OTG_H_SYNC_A_POL, &s->h_sync_a_pol); + + REG_GET(OTG_H_TOTAL, + OTG_H_TOTAL, &s->h_total); + + REG_GET(OPTC_INPUT_GLOBAL_CONTROL, + OPTC_UNDERFLOW_OCCURRED_STATUS, &s->underflow_occurred_status); + + REG_GET(OTG_VERTICAL_INTERRUPT1_CONTROL, + OTG_VERTICAL_INTERRUPT1_INT_ENABLE, &s->vertical_interrupt1_en); + + REG_GET(OTG_VERTICAL_INTERRUPT1_POSITION, + OTG_VERTICAL_INTERRUPT1_LINE_START, &s->vertical_interrupt1_line); + + REG_GET(OTG_VERTICAL_INTERRUPT2_CONTROL, + OTG_VERTICAL_INTERRUPT2_INT_ENABLE, &s->vertical_interrupt2_en); + + REG_GET(OTG_VERTICAL_INTERRUPT2_POSITION, + OTG_VERTICAL_INTERRUPT2_LINE_START, &s->vertical_interrupt2_line); +} + +bool optc1_get_otg_active_size(struct timing_generator *optc, + uint32_t *otg_active_width, + uint32_t *otg_active_height) +{ + uint32_t otg_enabled; + uint32_t v_blank_start; + uint32_t v_blank_end; + uint32_t h_blank_start; + uint32_t h_blank_end; + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + + REG_GET(OTG_CONTROL, + OTG_MASTER_EN, &otg_enabled); + + if (otg_enabled == 0) + return false; + + REG_GET_2(OTG_V_BLANK_START_END, + OTG_V_BLANK_START, &v_blank_start, + OTG_V_BLANK_END, &v_blank_end); + + REG_GET_2(OTG_H_BLANK_START_END, + OTG_H_BLANK_START, &h_blank_start, + OTG_H_BLANK_END, &h_blank_end); + + *otg_active_width = v_blank_start - v_blank_end; + *otg_active_height = h_blank_start - h_blank_end; + return true; +} + +void optc1_clear_optc_underflow(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_UPDATE(OPTC_INPUT_GLOBAL_CONTROL, OPTC_UNDERFLOW_CLEAR, 1); +} + +void optc1_tg_init(struct timing_generator *optc) +{ + optc1_set_blank_data_double_buffer(optc, true); + optc1_set_timing_double_buffer(optc, true); + optc1_clear_optc_underflow(optc); +} + +bool optc1_is_tg_enabled(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + uint32_t otg_enabled = 0; + + REG_GET(OTG_CONTROL, OTG_MASTER_EN, &otg_enabled); + + return (otg_enabled != 0); + +} + +bool optc1_is_optc_underflow_occurred(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + uint32_t underflow_occurred = 0; + + REG_GET(OPTC_INPUT_GLOBAL_CONTROL, + OPTC_UNDERFLOW_OCCURRED_STATUS, + &underflow_occurred); + + return (underflow_occurred == 1); +} + +bool optc1_configure_crc(struct timing_generator *optc, + const struct crc_params *params) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + /* Cannot configure crc on a CRTC that is disabled */ + if (!optc1_is_tg_enabled(optc)) + return false; + + REG_WRITE(OTG_CRC_CNTL, 0); + + if (!params->enable) + return true; + + /* Program frame boundaries */ + /* Window A x axis start and end. */ + REG_UPDATE_2(OTG_CRC0_WINDOWA_X_CONTROL, + OTG_CRC0_WINDOWA_X_START, params->windowa_x_start, + OTG_CRC0_WINDOWA_X_END, params->windowa_x_end); + + /* Window A y axis start and end. */ + REG_UPDATE_2(OTG_CRC0_WINDOWA_Y_CONTROL, + OTG_CRC0_WINDOWA_Y_START, params->windowa_y_start, + OTG_CRC0_WINDOWA_Y_END, params->windowa_y_end); + + /* Window B x axis start and end. */ + REG_UPDATE_2(OTG_CRC0_WINDOWB_X_CONTROL, + OTG_CRC0_WINDOWB_X_START, params->windowb_x_start, + OTG_CRC0_WINDOWB_X_END, params->windowb_x_end); + + /* Window B y axis start and end. */ + REG_UPDATE_2(OTG_CRC0_WINDOWB_Y_CONTROL, + OTG_CRC0_WINDOWB_Y_START, params->windowb_y_start, + OTG_CRC0_WINDOWB_Y_END, params->windowb_y_end); + + /* Set crc mode and selection, and enable. Only using CRC0*/ + REG_UPDATE_3(OTG_CRC_CNTL, + OTG_CRC_CONT_EN, params->continuous_mode ? 1 : 0, + OTG_CRC0_SELECT, params->selection, + OTG_CRC_EN, 1); + + return true; +} + +/** + * optc1_get_crc - Capture CRC result per component + * + * @optc: timing_generator instance. + * @r_cr: 16-bit primary CRC signature for red data. + * @g_y: 16-bit primary CRC signature for green data. + * @b_cb: 16-bit primary CRC signature for blue data. + * + * This function reads the CRC signature from the OPTC registers. Notice that + * we have three registers to keep the CRC result per color component (RGB). + * + * Returns: + * If CRC is disabled, return false; otherwise, return true, and the CRC + * results in the parameters. + */ +bool optc1_get_crc(struct timing_generator *optc, + uint32_t *r_cr, uint32_t *g_y, uint32_t *b_cb) +{ + uint32_t field = 0; + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_GET(OTG_CRC_CNTL, OTG_CRC_EN, &field); + + /* Early return if CRC is not enabled for this CRTC */ + if (!field) + return false; + + /* OTG_CRC0_DATA_RG has the CRC16 results for the red and green component */ + REG_GET_2(OTG_CRC0_DATA_RG, + CRC0_R_CR, r_cr, + CRC0_G_Y, g_y); + + /* OTG_CRC0_DATA_B has the CRC16 results for the blue component */ + REG_GET(OTG_CRC0_DATA_B, + CRC0_B_CB, b_cb); + + return true; +} + +static const struct timing_generator_funcs dcn10_tg_funcs = { + .validate_timing = optc1_validate_timing, + .program_timing = optc1_program_timing, + .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0, + .setup_vertical_interrupt1 = optc1_setup_vertical_interrupt1, + .setup_vertical_interrupt2 = optc1_setup_vertical_interrupt2, + .program_global_sync = optc1_program_global_sync, + .enable_crtc = optc1_enable_crtc, + .disable_crtc = optc1_disable_crtc, + /* used by enable_timing_synchronization. Not need for FPGA */ + .is_counter_moving = optc1_is_counter_moving, + .get_position = optc1_get_position, + .get_frame_count = optc1_get_vblank_counter, + .get_scanoutpos = optc1_get_crtc_scanoutpos, + .get_otg_active_size = optc1_get_otg_active_size, + .set_early_control = optc1_set_early_control, + /* used by enable_timing_synchronization. Not need for FPGA */ + .wait_for_state = optc1_wait_for_state, + .set_blank = optc1_set_blank, + .is_blanked = optc1_is_blanked, + .set_blank_color = optc1_program_blank_color, + .did_triggered_reset_occur = optc1_did_triggered_reset_occur, + .enable_reset_trigger = optc1_enable_reset_trigger, + .enable_crtc_reset = optc1_enable_crtc_reset, + .disable_reset_trigger = optc1_disable_reset_trigger, + .lock = optc1_lock, + .unlock = optc1_unlock, + .enable_optc_clock = optc1_enable_optc_clock, + .set_drr = optc1_set_drr, + .get_last_used_drr_vtotal = NULL, + .set_vtotal_min_max = optc1_set_vtotal_min_max, + .set_static_screen_control = optc1_set_static_screen_control, + .set_test_pattern = optc1_set_test_pattern, + .program_stereo = optc1_program_stereo, + .is_stereo_left_eye = optc1_is_stereo_left_eye, + .set_blank_data_double_buffer = optc1_set_blank_data_double_buffer, + .tg_init = optc1_tg_init, + .is_tg_enabled = optc1_is_tg_enabled, + .is_optc_underflow_occurred = optc1_is_optc_underflow_occurred, + .clear_optc_underflow = optc1_clear_optc_underflow, + .get_crc = optc1_get_crc, + .configure_crc = optc1_configure_crc, + .set_vtg_params = optc1_set_vtg_params, + .program_manual_trigger = optc1_program_manual_trigger, + .setup_manual_trigger = optc1_setup_manual_trigger, + .get_hw_timing = optc1_get_hw_timing, +}; + +void dcn10_timing_generator_init(struct optc *optc1) +{ + optc1->base.funcs = &dcn10_tg_funcs; + + optc1->max_h_total = optc1->tg_mask->OTG_H_TOTAL + 1; + optc1->max_v_total = optc1->tg_mask->OTG_V_TOTAL + 1; + + optc1->min_h_blank = 32; + optc1->min_v_blank = 3; + optc1->min_v_blank_interlace = 5; + optc1->min_h_sync_width = 4; + optc1->min_v_sync_width = 1; +} + +/* "Containter" vs. "pixel" is a concept within HW blocks, mostly those closer to the back-end. It works like this: + * + * - In most of the formats (RGB or YCbCr 4:4:4, 4:2:2 uncompressed and DSC 4:2:2 Simple) pixel rate is the same as + * containter rate. + * + * - In 4:2:0 (DSC or uncompressed) there are two pixels per container, hence the target container rate has to be + * halved to maintain the correct pixel rate. + * + * - Unlike 4:2:2 uncompressed, DSC 4:2:2 Native also has two pixels per container (this happens when DSC is applied + * to it) and has to be treated the same as 4:2:0, i.e. target containter rate has to be halved in this case as well. + * + */ +bool optc1_is_two_pixels_per_containter(const struct dc_crtc_timing *timing) +{ + bool two_pix = timing->pixel_encoding == PIXEL_ENCODING_YCBCR420; + + two_pix = two_pix || (timing->flags.DSC && timing->pixel_encoding == PIXEL_ENCODING_YCBCR422 + && !timing->dsc_cfg.ycbcr422_simple); + return two_pix; +} + diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.h new file mode 100644 index 00000000000000..ab81594a7fadcc --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.h @@ -0,0 +1,599 @@ +/* + * 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 __DC_TIMING_GENERATOR_DCN10_H__ +#define __DC_TIMING_GENERATOR_DCN10_H__ + +#include "optc.h" + +#define DCN10TG_FROM_TG(tg)\ + container_of(tg, struct optc, base) + +#define TG_COMMON_REG_LIST_DCN(inst) \ + SRI(OTG_VSTARTUP_PARAM, OTG, inst),\ + SRI(OTG_VUPDATE_PARAM, OTG, inst),\ + SRI(OTG_VREADY_PARAM, OTG, inst),\ + SRI(OTG_BLANK_CONTROL, OTG, inst),\ + SRI(OTG_MASTER_UPDATE_LOCK, OTG, inst),\ + SRI(OTG_GLOBAL_CONTROL0, OTG, inst),\ + SRI(OTG_DOUBLE_BUFFER_CONTROL, OTG, inst),\ + SRI(OTG_H_TOTAL, OTG, inst),\ + SRI(OTG_H_BLANK_START_END, OTG, inst),\ + SRI(OTG_H_SYNC_A, OTG, inst),\ + SRI(OTG_H_SYNC_A_CNTL, OTG, inst),\ + SRI(OTG_H_TIMING_CNTL, OTG, inst),\ + SRI(OTG_V_TOTAL, OTG, inst),\ + SRI(OTG_V_BLANK_START_END, OTG, inst),\ + SRI(OTG_V_SYNC_A, OTG, inst),\ + SRI(OTG_V_SYNC_A_CNTL, OTG, inst),\ + SRI(OTG_INTERLACE_CONTROL, OTG, inst),\ + SRI(OTG_CONTROL, OTG, inst),\ + SRI(OTG_STEREO_CONTROL, OTG, inst),\ + SRI(OTG_3D_STRUCTURE_CONTROL, OTG, inst),\ + SRI(OTG_STEREO_STATUS, OTG, inst),\ + SRI(OTG_V_TOTAL_MAX, OTG, inst),\ + SRI(OTG_V_TOTAL_MID, OTG, inst),\ + SRI(OTG_V_TOTAL_MIN, OTG, inst),\ + SRI(OTG_V_TOTAL_CONTROL, OTG, inst),\ + SRI(OTG_TRIGA_CNTL, OTG, inst),\ + SRI(OTG_FORCE_COUNT_NOW_CNTL, OTG, inst),\ + SRI(OTG_STATIC_SCREEN_CONTROL, OTG, inst),\ + SRI(OTG_STATUS_FRAME_COUNT, OTG, inst),\ + SRI(OTG_STATUS, OTG, inst),\ + SRI(OTG_STATUS_POSITION, OTG, inst),\ + SRI(OTG_NOM_VERT_POSITION, OTG, inst),\ + SRI(OTG_BLACK_COLOR, OTG, inst),\ + SRI(OTG_CLOCK_CONTROL, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT0_CONTROL, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT0_POSITION, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT1_CONTROL, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT1_POSITION, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT2_CONTROL, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT2_POSITION, OTG, inst),\ + SRI(OPTC_INPUT_CLOCK_CONTROL, ODM, inst),\ + SRI(OPTC_DATA_SOURCE_SELECT, ODM, inst),\ + SRI(OPTC_INPUT_GLOBAL_CONTROL, ODM, inst),\ + SRI(CONTROL, VTG, inst),\ + SRI(OTG_VERT_SYNC_CONTROL, OTG, inst),\ + SRI(OTG_MASTER_UPDATE_MODE, OTG, inst),\ + SRI(OTG_GSL_CONTROL, OTG, inst),\ + SRI(OTG_CRC_CNTL, OTG, inst),\ + SRI(OTG_CRC0_DATA_RG, OTG, inst),\ + SRI(OTG_CRC0_DATA_B, OTG, inst),\ + SRI(OTG_CRC0_WINDOWA_X_CONTROL, OTG, inst),\ + SRI(OTG_CRC0_WINDOWA_Y_CONTROL, OTG, inst),\ + SRI(OTG_CRC0_WINDOWB_X_CONTROL, OTG, inst),\ + SRI(OTG_CRC0_WINDOWB_Y_CONTROL, OTG, inst),\ + SR(GSL_SOURCE_SELECT),\ + SRI(OTG_GLOBAL_CONTROL2, OTG, inst),\ + SRI(OTG_TRIGA_MANUAL_TRIG, OTG, inst) + +#define TG_COMMON_REG_LIST_DCN1_0(inst) \ + TG_COMMON_REG_LIST_DCN(inst),\ + SRI(OTG_TEST_PATTERN_PARAMETERS, OTG, inst),\ + SRI(OTG_TEST_PATTERN_CONTROL, OTG, inst),\ + SRI(OTG_TEST_PATTERN_COLOR, OTG, inst),\ + SRI(OTG_MANUAL_FLOW_CONTROL, OTG, inst) + + +struct dcn_optc_registers { + uint32_t OTG_GLOBAL_CONTROL1; + uint32_t OTG_GLOBAL_CONTROL2; + uint32_t OTG_VERT_SYNC_CONTROL; + uint32_t OTG_MASTER_UPDATE_MODE; + uint32_t OTG_GSL_CONTROL; + uint32_t OTG_VSTARTUP_PARAM; + uint32_t OTG_VUPDATE_PARAM; + uint32_t OTG_VREADY_PARAM; + uint32_t OTG_BLANK_CONTROL; + uint32_t OTG_MASTER_UPDATE_LOCK; + uint32_t OTG_GLOBAL_CONTROL0; + uint32_t OTG_DOUBLE_BUFFER_CONTROL; + uint32_t OTG_H_TOTAL; + uint32_t OTG_H_BLANK_START_END; + uint32_t OTG_H_SYNC_A; + uint32_t OTG_H_SYNC_A_CNTL; + uint32_t OTG_H_TIMING_CNTL; + uint32_t OTG_V_TOTAL; + uint32_t OTG_V_BLANK_START_END; + uint32_t OTG_V_SYNC_A; + uint32_t OTG_V_SYNC_A_CNTL; + uint32_t OTG_INTERLACE_CONTROL; + uint32_t OTG_CONTROL; + uint32_t OTG_STEREO_CONTROL; + uint32_t OTG_3D_STRUCTURE_CONTROL; + uint32_t OTG_STEREO_STATUS; + uint32_t OTG_V_TOTAL_MAX; + uint32_t OTG_V_TOTAL_MID; + uint32_t OTG_V_TOTAL_MIN; + uint32_t OTG_V_TOTAL_CONTROL; + uint32_t OTG_TRIGA_CNTL; + uint32_t OTG_TRIGA_MANUAL_TRIG; + uint32_t OTG_MANUAL_FLOW_CONTROL; + uint32_t OTG_FORCE_COUNT_NOW_CNTL; + uint32_t OTG_STATIC_SCREEN_CONTROL; + uint32_t OTG_STATUS_FRAME_COUNT; + uint32_t OTG_STATUS; + uint32_t OTG_STATUS_POSITION; + uint32_t OTG_NOM_VERT_POSITION; + uint32_t OTG_BLACK_COLOR; + uint32_t OTG_TEST_PATTERN_PARAMETERS; + uint32_t OTG_TEST_PATTERN_CONTROL; + uint32_t OTG_TEST_PATTERN_COLOR; + uint32_t OTG_CLOCK_CONTROL; + uint32_t OTG_VERTICAL_INTERRUPT0_CONTROL; + uint32_t OTG_VERTICAL_INTERRUPT0_POSITION; + uint32_t OTG_VERTICAL_INTERRUPT1_CONTROL; + uint32_t OTG_VERTICAL_INTERRUPT1_POSITION; + uint32_t OTG_VERTICAL_INTERRUPT2_CONTROL; + uint32_t OTG_VERTICAL_INTERRUPT2_POSITION; + uint32_t OPTC_INPUT_CLOCK_CONTROL; + uint32_t OPTC_DATA_SOURCE_SELECT; + uint32_t OPTC_MEMORY_CONFIG; + uint32_t OPTC_INPUT_GLOBAL_CONTROL; + uint32_t CONTROL; + uint32_t OTG_GSL_WINDOW_X; + uint32_t OTG_GSL_WINDOW_Y; + uint32_t OTG_VUPDATE_KEEPOUT; + uint32_t OTG_CRC_CNTL; + uint32_t OTG_CRC_CNTL2; + uint32_t OTG_CRC0_DATA_RG; + uint32_t OTG_CRC0_DATA_B; + uint32_t OTG_CRC1_DATA_B; + uint32_t OTG_CRC2_DATA_B; + uint32_t OTG_CRC3_DATA_B; + uint32_t OTG_CRC1_DATA_RG; + uint32_t OTG_CRC2_DATA_RG; + uint32_t OTG_CRC3_DATA_RG; + uint32_t OTG_CRC0_WINDOWA_X_CONTROL; + uint32_t OTG_CRC0_WINDOWA_Y_CONTROL; + uint32_t OTG_CRC0_WINDOWB_X_CONTROL; + uint32_t OTG_CRC0_WINDOWB_Y_CONTROL; + uint32_t OTG_CRC1_WINDOWA_X_CONTROL; + uint32_t OTG_CRC1_WINDOWA_Y_CONTROL; + uint32_t OTG_CRC1_WINDOWB_X_CONTROL; + uint32_t OTG_CRC1_WINDOWB_Y_CONTROL; + uint32_t GSL_SOURCE_SELECT; + uint32_t DWB_SOURCE_SELECT; + uint32_t OTG_DSC_START_POSITION; + uint32_t OPTC_DATA_FORMAT_CONTROL; + uint32_t OPTC_BYTES_PER_PIXEL; + uint32_t OPTC_WIDTH_CONTROL; + uint32_t OTG_DRR_CONTROL; + uint32_t OTG_BLANK_DATA_COLOR; + uint32_t OTG_BLANK_DATA_COLOR_EXT; + uint32_t OTG_DRR_TRIGGER_WINDOW; + uint32_t OTG_M_CONST_DTO0; + uint32_t OTG_M_CONST_DTO1; + uint32_t OTG_DRR_V_TOTAL_CHANGE; + uint32_t OTG_GLOBAL_CONTROL4; + uint32_t OTG_CRC0_WINDOWA_X_CONTROL_READBACK; + uint32_t OTG_CRC0_WINDOWA_Y_CONTROL_READBACK; + uint32_t OTG_CRC0_WINDOWB_X_CONTROL_READBACK; + uint32_t OTG_CRC0_WINDOWB_Y_CONTROL_READBACK; + uint32_t OTG_CRC1_WINDOWA_X_CONTROL_READBACK; + uint32_t OTG_CRC1_WINDOWA_Y_CONTROL_READBACK; + uint32_t OTG_CRC1_WINDOWB_X_CONTROL_READBACK; + uint32_t OTG_CRC1_WINDOWB_Y_CONTROL_READBACK; + uint32_t OPTC_CLOCK_CONTROL; +}; + +#define TG_COMMON_MASK_SH_LIST_DCN(mask_sh)\ + SF(OTG0_OTG_VSTARTUP_PARAM, VSTARTUP_START, mask_sh),\ + SF(OTG0_OTG_VUPDATE_PARAM, VUPDATE_OFFSET, mask_sh),\ + SF(OTG0_OTG_VUPDATE_PARAM, VUPDATE_WIDTH, mask_sh),\ + SF(OTG0_OTG_VREADY_PARAM, VREADY_OFFSET, mask_sh),\ + SF(OTG0_OTG_BLANK_CONTROL, OTG_BLANK_DATA_EN, mask_sh),\ + SF(OTG0_OTG_BLANK_CONTROL, OTG_BLANK_DE_MODE, mask_sh),\ + SF(OTG0_OTG_BLANK_CONTROL, OTG_CURRENT_BLANK_STATE, mask_sh),\ + SF(OTG0_OTG_MASTER_UPDATE_LOCK, OTG_MASTER_UPDATE_LOCK, mask_sh),\ + SF(OTG0_OTG_MASTER_UPDATE_LOCK, UPDATE_LOCK_STATUS, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL0, OTG_MASTER_UPDATE_LOCK_SEL, mask_sh),\ + SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_UPDATE_PENDING, mask_sh),\ + SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_BLANK_DATA_DOUBLE_BUFFER_EN, mask_sh),\ + SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_RANGE_TIMING_DBUF_UPDATE_MODE, mask_sh),\ + SF(OTG0_OTG_VUPDATE_KEEPOUT, OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, mask_sh), \ + SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET, mask_sh), \ + SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET, mask_sh), \ + SF(OTG0_OTG_H_TOTAL, OTG_H_TOTAL, mask_sh),\ + SF(OTG0_OTG_H_BLANK_START_END, OTG_H_BLANK_START, mask_sh),\ + SF(OTG0_OTG_H_BLANK_START_END, OTG_H_BLANK_END, mask_sh),\ + SF(OTG0_OTG_H_SYNC_A, OTG_H_SYNC_A_START, mask_sh),\ + SF(OTG0_OTG_H_SYNC_A, OTG_H_SYNC_A_END, mask_sh),\ + SF(OTG0_OTG_H_SYNC_A_CNTL, OTG_H_SYNC_A_POL, mask_sh),\ + SF(OTG0_OTG_H_TIMING_CNTL, OTG_H_TIMING_DIV_BY2, mask_sh),\ + SF(OTG0_OTG_V_TOTAL, OTG_V_TOTAL, mask_sh),\ + SF(OTG0_OTG_V_BLANK_START_END, OTG_V_BLANK_START, mask_sh),\ + SF(OTG0_OTG_V_BLANK_START_END, OTG_V_BLANK_END, mask_sh),\ + SF(OTG0_OTG_V_SYNC_A, OTG_V_SYNC_A_START, mask_sh),\ + SF(OTG0_OTG_V_SYNC_A, OTG_V_SYNC_A_END, mask_sh),\ + SF(OTG0_OTG_V_SYNC_A_CNTL, OTG_V_SYNC_A_POL, mask_sh),\ + SF(OTG0_OTG_INTERLACE_CONTROL, OTG_INTERLACE_ENABLE, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_MASTER_EN, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_START_POINT_CNTL, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_DISABLE_POINT_CNTL, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_FIELD_NUMBER_CNTL, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_CURRENT_MASTER_EN_STATE, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_EN, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_SYNC_OUTPUT_LINE_NUM, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_SYNC_OUTPUT_POLARITY, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_EYE_FLAG_POLARITY, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_DISABLE_STEREOSYNC_OUTPUT_FOR_DP, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_DISABLE_STEREOSYNC_OUTPUT_FOR_DP, mask_sh),\ + SF(OTG0_OTG_STEREO_STATUS, OTG_STEREO_CURRENT_EYE, mask_sh),\ + SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_EN, mask_sh),\ + SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_V_UPDATE_MODE, mask_sh),\ + SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_STEREO_SEL_OVR, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_MAX, OTG_V_TOTAL_MAX, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_MID, OTG_V_TOTAL_MID, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_MIN, OTG_V_TOTAL_MIN, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_V_TOTAL_MIN_SEL, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_V_TOTAL_MAX_SEL, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_FORCE_LOCK_ON_EVENT, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_SET_V_TOTAL_MIN_MASK_EN, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_SET_V_TOTAL_MIN_MASK, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_VTOTAL_MID_REPLACING_MAX_EN, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_VTOTAL_MID_FRAME_NUM, mask_sh),\ + SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_CLEAR, mask_sh),\ + SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_MODE, mask_sh),\ + SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_OCCURRED, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_SOURCE_SELECT, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_SOURCE_PIPE_SELECT, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_RISING_EDGE_DETECT_CNTL, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_POLARITY_SELECT, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_FREQUENCY_SELECT, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_DELAY, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_CLEAR, mask_sh),\ + SF(OTG0_OTG_TRIGA_MANUAL_TRIG, OTG_TRIGA_MANUAL_TRIG, mask_sh),\ + SF(OTG0_OTG_STATIC_SCREEN_CONTROL, OTG_STATIC_SCREEN_EVENT_MASK, mask_sh),\ + SF(OTG0_OTG_STATIC_SCREEN_CONTROL, OTG_STATIC_SCREEN_FRAME_COUNT, mask_sh),\ + SF(OTG0_OTG_STATUS_FRAME_COUNT, OTG_FRAME_COUNT, mask_sh),\ + SF(OTG0_OTG_STATUS, OTG_V_BLANK, mask_sh),\ + SF(OTG0_OTG_STATUS, OTG_V_ACTIVE_DISP, mask_sh),\ + SF(OTG0_OTG_STATUS_POSITION, OTG_HORZ_COUNT, mask_sh),\ + SF(OTG0_OTG_STATUS_POSITION, OTG_VERT_COUNT, mask_sh),\ + SF(OTG0_OTG_NOM_VERT_POSITION, OTG_VERT_COUNT_NOM, mask_sh),\ + SF(OTG0_OTG_BLACK_COLOR, OTG_BLACK_COLOR_B_CB, mask_sh),\ + SF(OTG0_OTG_BLACK_COLOR, OTG_BLACK_COLOR_G_Y, mask_sh),\ + SF(OTG0_OTG_BLACK_COLOR, OTG_BLACK_COLOR_R_CR, mask_sh),\ + SF(OTG0_OTG_CLOCK_CONTROL, OTG_BUSY, mask_sh),\ + SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_EN, mask_sh),\ + SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_ON, mask_sh),\ + SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_GATE_DIS, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_INT_ENABLE, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT0_POSITION, OTG_VERTICAL_INTERRUPT0_LINE_START, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT0_POSITION, OTG_VERTICAL_INTERRUPT0_LINE_END, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT1_CONTROL, OTG_VERTICAL_INTERRUPT1_INT_ENABLE, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT1_POSITION, OTG_VERTICAL_INTERRUPT1_LINE_START, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT2_POSITION, OTG_VERTICAL_INTERRUPT2_LINE_START, mask_sh),\ + SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_EN, mask_sh),\ + SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_ON, mask_sh),\ + SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_GATE_DIS, mask_sh),\ + SF(ODM0_OPTC_INPUT_GLOBAL_CONTROL, OPTC_UNDERFLOW_OCCURRED_STATUS, mask_sh),\ + SF(ODM0_OPTC_INPUT_GLOBAL_CONTROL, OPTC_UNDERFLOW_CLEAR, mask_sh),\ + SF(VTG0_CONTROL, VTG0_ENABLE, mask_sh),\ + SF(VTG0_CONTROL, VTG0_FP2, mask_sh),\ + SF(VTG0_CONTROL, VTG0_VCOUNT_INIT, mask_sh),\ + SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_FORCE_VSYNC_NEXT_LINE_OCCURRED, mask_sh),\ + SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_FORCE_VSYNC_NEXT_LINE_CLEAR, mask_sh),\ + SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_AUTO_FORCE_VSYNC_MODE, mask_sh),\ + SF(OTG0_OTG_MASTER_UPDATE_MODE, MASTER_UPDATE_INTERLACED_MODE, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL0_EN, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL1_EN, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL2_EN, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_MASTER_EN, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_FORCE_DELAY, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_CHECK_ALL_FIELDS, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL, OTG_CRC_CONT_EN, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL, OTG_CRC0_SELECT, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL, OTG_CRC_EN, mask_sh),\ + SF(OTG0_OTG_CRC0_DATA_RG, CRC0_R_CR, mask_sh),\ + SF(OTG0_OTG_CRC0_DATA_RG, CRC0_G_Y, mask_sh),\ + SF(OTG0_OTG_CRC0_DATA_B, CRC0_B_CB, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWA_X_CONTROL, OTG_CRC0_WINDOWA_X_START, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWA_X_CONTROL, OTG_CRC0_WINDOWA_X_END, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWA_Y_CONTROL, OTG_CRC0_WINDOWA_Y_START, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWA_Y_CONTROL, OTG_CRC0_WINDOWA_Y_END, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWB_X_CONTROL, OTG_CRC0_WINDOWB_X_START, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWB_X_CONTROL, OTG_CRC0_WINDOWB_X_END, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL, OTG_CRC0_WINDOWB_Y_START, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL, OTG_CRC0_WINDOWB_Y_END, mask_sh),\ + SF(GSL_SOURCE_SELECT, GSL0_READY_SOURCE_SEL, mask_sh),\ + SF(GSL_SOURCE_SELECT, GSL1_READY_SOURCE_SEL, mask_sh),\ + SF(GSL_SOURCE_SELECT, GSL2_READY_SOURCE_SEL, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL2, MANUAL_FLOW_CONTROL_SEL, mask_sh) + + + +#define TG_COMMON_MASK_SH_LIST_DCN1_0(mask_sh)\ + TG_COMMON_MASK_SH_LIST_DCN(mask_sh),\ + SF(OTG0_OTG_TEST_PATTERN_PARAMETERS, OTG_TEST_PATTERN_INC0, mask_sh),\ + SF(OTG0_OTG_TEST_PATTERN_PARAMETERS, OTG_TEST_PATTERN_INC1, mask_sh),\ + SF(OTG0_OTG_TEST_PATTERN_PARAMETERS, OTG_TEST_PATTERN_VRES, mask_sh),\ + SF(OTG0_OTG_TEST_PATTERN_PARAMETERS, OTG_TEST_PATTERN_HRES, mask_sh),\ + SF(OTG0_OTG_TEST_PATTERN_PARAMETERS, OTG_TEST_PATTERN_RAMP0_OFFSET, mask_sh),\ + SF(OTG0_OTG_TEST_PATTERN_CONTROL, OTG_TEST_PATTERN_EN, mask_sh),\ + SF(OTG0_OTG_TEST_PATTERN_CONTROL, OTG_TEST_PATTERN_MODE, mask_sh),\ + SF(OTG0_OTG_TEST_PATTERN_CONTROL, OTG_TEST_PATTERN_DYNAMIC_RANGE, mask_sh),\ + SF(OTG0_OTG_TEST_PATTERN_CONTROL, OTG_TEST_PATTERN_COLOR_FORMAT, mask_sh),\ + SF(OTG0_OTG_TEST_PATTERN_COLOR, OTG_TEST_PATTERN_MASK, mask_sh),\ + SF(OTG0_OTG_TEST_PATTERN_COLOR, OTG_TEST_PATTERN_DATA, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SRC_SEL, mask_sh),\ + SF(OTG0_OTG_MANUAL_FLOW_CONTROL, MANUAL_FLOW_CONTROL, mask_sh),\ + +#define TG_REG_FIELD_LIST_DCN1_0(type) \ + type VSTARTUP_START;\ + type VUPDATE_OFFSET;\ + type VUPDATE_WIDTH;\ + type VREADY_OFFSET;\ + type OTG_BLANK_DATA_EN;\ + type OTG_BLANK_DE_MODE;\ + type OTG_CURRENT_BLANK_STATE;\ + type OTG_MASTER_UPDATE_LOCK;\ + type UPDATE_LOCK_STATUS;\ + type OTG_UPDATE_PENDING;\ + type OTG_MASTER_UPDATE_LOCK_SEL;\ + type OTG_BLANK_DATA_DOUBLE_BUFFER_EN;\ + type OTG_H_TOTAL;\ + type OTG_H_BLANK_START;\ + type OTG_H_BLANK_END;\ + type OTG_H_SYNC_A_START;\ + type OTG_H_SYNC_A_END;\ + type OTG_H_SYNC_A_POL;\ + type OTG_H_TIMING_DIV_BY2;\ + type OTG_V_TOTAL;\ + type OTG_V_BLANK_START;\ + type OTG_V_BLANK_END;\ + type OTG_V_SYNC_A_START;\ + type OTG_V_SYNC_A_END;\ + type OTG_V_SYNC_A_POL;\ + type OTG_INTERLACE_ENABLE;\ + type OTG_MASTER_EN;\ + type OTG_START_POINT_CNTL;\ + type OTG_DISABLE_POINT_CNTL;\ + type OTG_FIELD_NUMBER_CNTL;\ + type OTG_CURRENT_MASTER_EN_STATE;\ + type OTG_STEREO_EN;\ + type OTG_STEREO_SYNC_OUTPUT_LINE_NUM;\ + type OTG_STEREO_SYNC_OUTPUT_POLARITY;\ + type OTG_STEREO_EYE_FLAG_POLARITY;\ + type OTG_STEREO_CURRENT_EYE;\ + type OTG_DISABLE_STEREOSYNC_OUTPUT_FOR_DP;\ + type OTG_3D_STRUCTURE_EN;\ + type OTG_3D_STRUCTURE_V_UPDATE_MODE;\ + type OTG_3D_STRUCTURE_STEREO_SEL_OVR;\ + type OTG_V_TOTAL_MAX;\ + type OTG_V_TOTAL_MID;\ + type OTG_V_TOTAL_MIN;\ + type OTG_V_TOTAL_MIN_SEL;\ + type OTG_V_TOTAL_MAX_SEL;\ + type OTG_VTOTAL_MID_REPLACING_MAX_EN;\ + type OTG_VTOTAL_MID_FRAME_NUM;\ + type OTG_FORCE_LOCK_ON_EVENT;\ + type OTG_SET_V_TOTAL_MIN_MASK_EN;\ + type OTG_SET_V_TOTAL_MIN_MASK;\ + type OTG_FORCE_COUNT_NOW_CLEAR;\ + type OTG_FORCE_COUNT_NOW_MODE;\ + type OTG_FORCE_COUNT_NOW_OCCURRED;\ + type OTG_TRIGA_SOURCE_SELECT;\ + type OTG_TRIGA_SOURCE_PIPE_SELECT;\ + type OTG_TRIGA_RISING_EDGE_DETECT_CNTL;\ + type OTG_TRIGA_FALLING_EDGE_DETECT_CNTL;\ + type OTG_TRIGA_POLARITY_SELECT;\ + type OTG_TRIGA_FREQUENCY_SELECT;\ + type OTG_TRIGA_DELAY;\ + type OTG_TRIGA_CLEAR;\ + type OTG_TRIGA_MANUAL_TRIG;\ + type OTG_STATIC_SCREEN_EVENT_MASK;\ + type OTG_STATIC_SCREEN_FRAME_COUNT;\ + type OTG_FRAME_COUNT;\ + type OTG_V_BLANK;\ + type OTG_V_ACTIVE_DISP;\ + type OTG_HORZ_COUNT;\ + type OTG_VERT_COUNT;\ + type OTG_VERT_COUNT_NOM;\ + type OTG_BLACK_COLOR_B_CB;\ + type OTG_BLACK_COLOR_G_Y;\ + type OTG_BLACK_COLOR_R_CR;\ + type OTG_BLANK_DATA_COLOR_BLUE_CB;\ + type OTG_BLANK_DATA_COLOR_GREEN_Y;\ + type OTG_BLANK_DATA_COLOR_RED_CR;\ + type OTG_BLANK_DATA_COLOR_BLUE_CB_EXT;\ + type OTG_BLANK_DATA_COLOR_GREEN_Y_EXT;\ + type OTG_BLANK_DATA_COLOR_RED_CR_EXT;\ + type OTG_VTOTAL_MID_REPLACING_MIN_EN;\ + type OTG_TEST_PATTERN_INC0;\ + type OTG_TEST_PATTERN_INC1;\ + type OTG_TEST_PATTERN_VRES;\ + type OTG_TEST_PATTERN_HRES;\ + type OTG_TEST_PATTERN_RAMP0_OFFSET;\ + type OTG_TEST_PATTERN_EN;\ + type OTG_TEST_PATTERN_MODE;\ + type OTG_TEST_PATTERN_DYNAMIC_RANGE;\ + type OTG_TEST_PATTERN_COLOR_FORMAT;\ + type OTG_TEST_PATTERN_MASK;\ + type OTG_TEST_PATTERN_DATA;\ + type OTG_BUSY;\ + type OTG_CLOCK_EN;\ + type OTG_CLOCK_ON;\ + type OTG_CLOCK_GATE_DIS;\ + type OTG_VERTICAL_INTERRUPT0_INT_ENABLE;\ + type OTG_VERTICAL_INTERRUPT0_LINE_START;\ + type OTG_VERTICAL_INTERRUPT0_LINE_END;\ + type OTG_VERTICAL_INTERRUPT1_INT_ENABLE;\ + type OTG_VERTICAL_INTERRUPT1_LINE_START;\ + type OTG_VERTICAL_INTERRUPT2_INT_ENABLE;\ + type OTG_VERTICAL_INTERRUPT2_LINE_START;\ + type OPTC_INPUT_CLK_EN;\ + type OPTC_INPUT_CLK_ON;\ + type OPTC_INPUT_CLK_GATE_DIS;\ + type OPTC_UNDERFLOW_OCCURRED_STATUS;\ + type OPTC_UNDERFLOW_CLEAR;\ + type OPTC_SRC_SEL;\ + type VTG0_ENABLE;\ + type VTG0_FP2;\ + type VTG0_VCOUNT_INIT;\ + type OTG_FORCE_VSYNC_NEXT_LINE_OCCURRED;\ + type OTG_FORCE_VSYNC_NEXT_LINE_CLEAR;\ + type OTG_AUTO_FORCE_VSYNC_MODE;\ + type MASTER_UPDATE_INTERLACED_MODE;\ + type OTG_GSL0_EN;\ + type OTG_GSL1_EN;\ + type OTG_GSL2_EN;\ + type OTG_GSL_MASTER_EN;\ + type OTG_GSL_FORCE_DELAY;\ + type OTG_GSL_CHECK_ALL_FIELDS;\ + type OTG_GSL_WINDOW_START_X;\ + type OTG_GSL_WINDOW_END_X;\ + type OTG_GSL_WINDOW_START_Y;\ + type OTG_GSL_WINDOW_END_Y;\ + type OTG_RANGE_TIMING_DBUF_UPDATE_MODE;\ + type OTG_GSL_MASTER_MODE;\ + type OTG_MASTER_UPDATE_LOCK_GSL_EN;\ + type MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET;\ + type MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET;\ + type OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN;\ + type OTG_CRC_CONT_EN;\ + type OTG_CRC0_SELECT;\ + type OTG_CRC_EN;\ + type CRC0_R_CR;\ + type CRC0_G_Y;\ + type CRC0_B_CB;\ + type CRC1_R_CR;\ + type CRC1_G_Y;\ + type CRC1_B_CB;\ + type CRC2_R_CR;\ + type CRC2_G_Y;\ + type CRC2_B_CB;\ + type CRC3_R_CR;\ + type CRC3_G_Y;\ + type CRC3_B_CB;\ + type OTG_CRC0_WINDOWA_X_START;\ + type OTG_CRC0_WINDOWA_X_END;\ + type OTG_CRC0_WINDOWA_Y_START;\ + type OTG_CRC0_WINDOWA_Y_END;\ + type OTG_CRC0_WINDOWB_X_START;\ + type OTG_CRC0_WINDOWB_X_END;\ + type OTG_CRC0_WINDOWB_Y_START;\ + type OTG_CRC0_WINDOWB_Y_END;\ + type OTG_CRC_WINDOW_DB_EN;\ + type OTG_CRC1_WINDOWA_X_START;\ + type OTG_CRC1_WINDOWA_X_END;\ + type OTG_CRC1_WINDOWA_Y_START;\ + type OTG_CRC1_WINDOWA_Y_END;\ + type OTG_CRC1_WINDOWB_X_START;\ + type OTG_CRC1_WINDOWB_X_END;\ + type OTG_CRC1_WINDOWB_Y_START;\ + type OTG_CRC1_WINDOWB_Y_END;\ + type GSL0_READY_SOURCE_SEL;\ + type GSL1_READY_SOURCE_SEL;\ + type GSL2_READY_SOURCE_SEL;\ + type MANUAL_FLOW_CONTROL;\ + type MANUAL_FLOW_CONTROL_SEL; + +#define TG_REG_FIELD_LIST(type) \ + TG_REG_FIELD_LIST_DCN1_0(type)\ + type OTG_V_SYNC_MODE;\ + type OTG_DRR_TRIGGER_WINDOW_START_X;\ + type OTG_DRR_TRIGGER_WINDOW_END_X;\ + type OTG_DRR_V_TOTAL_CHANGE_LIMIT;\ + type OTG_OUT_MUX;\ + type OTG_M_CONST_DTO_PHASE;\ + type OTG_M_CONST_DTO_MODULO;\ + type MASTER_UPDATE_LOCK_DB_X;\ + type MASTER_UPDATE_LOCK_DB_Y;\ + type MASTER_UPDATE_LOCK_DB_EN;\ + type GLOBAL_UPDATE_LOCK_EN;\ + type DIG_UPDATE_LOCATION;\ + type OTG_DSC_START_POSITION_X;\ + type OTG_DSC_START_POSITION_LINE_NUM;\ + type OPTC_NUM_OF_INPUT_SEGMENT;\ + type OPTC_SEG0_SRC_SEL;\ + type OPTC_SEG1_SRC_SEL;\ + type OPTC_SEG2_SRC_SEL;\ + type OPTC_SEG3_SRC_SEL;\ + type OPTC_MEM_SEL;\ + type OPTC_DATA_FORMAT;\ + type OPTC_DSC_MODE;\ + type OPTC_DSC_BYTES_PER_PIXEL;\ + type OPTC_DSC_SLICE_WIDTH;\ + type OPTC_SEGMENT_WIDTH;\ + type OPTC_DWB0_SOURCE_SELECT;\ + type OPTC_DWB1_SOURCE_SELECT;\ + type MASTER_UPDATE_LOCK_DB_START_X;\ + type MASTER_UPDATE_LOCK_DB_END_X;\ + type MASTER_UPDATE_LOCK_DB_START_Y;\ + type MASTER_UPDATE_LOCK_DB_END_Y;\ + type DIG_UPDATE_POSITION_X;\ + type DIG_UPDATE_POSITION_Y;\ + type OTG_H_TIMING_DIV_MODE;\ + type OTG_DRR_TIMING_DBUF_UPDATE_MODE;\ + type OTG_CRC_DSC_MODE;\ + 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_DRR_TIMING_DBUF_UPDATE_PENDING; + +#define TG_REG_FIELD_LIST_DCN3_2(type) \ + type OTG_H_TIMING_DIV_MODE_MANUAL; + + +#define TG_REG_FIELD_LIST_DCN3_5(type) \ + type OTG_CRC0_WINDOWA_X_START_READBACK;\ + type OTG_CRC0_WINDOWA_X_END_READBACK;\ + type OTG_CRC0_WINDOWA_Y_START_READBACK;\ + type OTG_CRC0_WINDOWA_Y_END_READBACK;\ + type OTG_CRC0_WINDOWB_X_START_READBACK;\ + type OTG_CRC0_WINDOWB_X_END_READBACK;\ + type OTG_CRC0_WINDOWB_Y_START_READBACK;\ + type OTG_CRC0_WINDOWB_Y_END_READBACK; \ + type OTG_CRC1_WINDOWA_X_START_READBACK;\ + type OTG_CRC1_WINDOWA_X_END_READBACK;\ + type OTG_CRC1_WINDOWA_Y_START_READBACK;\ + type OTG_CRC1_WINDOWA_Y_END_READBACK;\ + type OTG_CRC1_WINDOWB_X_START_READBACK;\ + type OTG_CRC1_WINDOWB_X_END_READBACK;\ + type OTG_CRC1_WINDOWB_Y_START_READBACK;\ + type OTG_CRC1_WINDOWB_Y_END_READBACK;\ + type OPTC_FGCG_REP_DIS; + +struct dcn_optc_shift { + TG_REG_FIELD_LIST(uint8_t) + TG_REG_FIELD_LIST_DCN3_2(uint8_t) + TG_REG_FIELD_LIST_DCN3_5(uint8_t) +}; + +struct dcn_optc_mask { + TG_REG_FIELD_LIST(uint32_t) + TG_REG_FIELD_LIST_DCN3_2(uint32_t) + TG_REG_FIELD_LIST_DCN3_5(uint32_t) +}; + +void dcn10_timing_generator_init(struct optc *optc); + +#endif /* __DC_TIMING_GENERATOR_DCN10_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.c new file mode 100644 index 00000000000000..58bdbd859bf9b0 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.c @@ -0,0 +1,587 @@ +/* + * 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 + * + */ + +#include "reg_helper.h" +#include "dcn20_optc.h" +#include "dc.h" + +#define REG(reg)\ + optc1->tg_regs->reg + +#define CTX \ + optc1->base.ctx + +#undef FN +#define FN(reg_name, field_name) \ + optc1->tg_shift->field_name, optc1->tg_mask->field_name + +/** + * optc2_enable_crtc() - Enable CRTC - call ASIC Control Object to enable Timing generator. + * + * @optc: timing_generator instance. + * + * Return: If CRTC is enabled, return true. + * + */ +bool optc2_enable_crtc(struct timing_generator *optc) +{ + /* TODO FPGA wait for answer + * OTG_MASTER_UPDATE_MODE != CRTC_MASTER_UPDATE_MODE + * OTG_MASTER_UPDATE_LOCK != CRTC_MASTER_UPDATE_LOCK + */ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + /* opp instance for OTG. For DCN1.0, ODM is remoed. + * OPP and OPTC should 1:1 mapping + */ + REG_UPDATE(OPTC_DATA_SOURCE_SELECT, + OPTC_SEG0_SRC_SEL, optc->inst); + + /* VTG enable first is for HW workaround */ + REG_UPDATE(CONTROL, + VTG0_ENABLE, 1); + + REG_SEQ_START(); + + /* Enable CRTC */ + REG_UPDATE_2(OTG_CONTROL, + OTG_DISABLE_POINT_CNTL, 3, + OTG_MASTER_EN, 1); + + REG_SEQ_SUBMIT(); + REG_SEQ_WAIT_DONE(); + + return true; +} + +/** + * optc2_set_gsl() - Assign OTG to GSL groups, + * set one of the OTGs to be master & rest are slaves + * + * @optc: timing_generator instance. + * @params: pointer to gsl_params + */ +void optc2_set_gsl(struct timing_generator *optc, + const struct gsl_params *params) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + +/* + * There are (MAX_OPTC+1)/2 gsl groups available for use. + * In each group (assign an OTG to a group by setting OTG_GSLX_EN = 1, + * set one of the OTGs to be the master (OTG_GSL_MASTER_EN = 1) and the rest are slaves. + */ + REG_UPDATE_5(OTG_GSL_CONTROL, + OTG_GSL0_EN, params->gsl0_en, + OTG_GSL1_EN, params->gsl1_en, + OTG_GSL2_EN, params->gsl2_en, + OTG_GSL_MASTER_EN, params->gsl_master_en, + OTG_GSL_MASTER_MODE, params->gsl_master_mode); +} + + +void optc2_set_gsl_source_select( + struct timing_generator *optc, + int group_idx, + uint32_t gsl_ready_signal) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + switch (group_idx) { + case 1: + REG_UPDATE(GSL_SOURCE_SELECT, GSL0_READY_SOURCE_SEL, gsl_ready_signal); + break; + case 2: + REG_UPDATE(GSL_SOURCE_SELECT, GSL1_READY_SOURCE_SEL, gsl_ready_signal); + break; + case 3: + REG_UPDATE(GSL_SOURCE_SELECT, GSL2_READY_SOURCE_SEL, gsl_ready_signal); + break; + default: + break; + } +} + +/* Set DSC-related configuration. + * dsc_mode: 0 disables DSC, other values enable DSC in specified format + * sc_bytes_per_pixel: Bytes per pixel in u3.28 format + * dsc_slice_width: Slice width in pixels + */ +void optc2_set_dsc_config(struct timing_generator *optc, + enum optc_dsc_mode dsc_mode, + uint32_t dsc_bytes_per_pixel, + uint32_t dsc_slice_width) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_UPDATE(OPTC_DATA_FORMAT_CONTROL, + OPTC_DSC_MODE, dsc_mode); + + REG_SET(OPTC_BYTES_PER_PIXEL, 0, + OPTC_DSC_BYTES_PER_PIXEL, dsc_bytes_per_pixel); + + REG_UPDATE(OPTC_WIDTH_CONTROL, + OPTC_DSC_SLICE_WIDTH, dsc_slice_width); +} + +/* Get DSC-related configuration. + * dsc_mode: 0 disables DSC, other values enable DSC in specified format + */ +void optc2_get_dsc_status(struct timing_generator *optc, + uint32_t *dsc_mode) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_GET(OPTC_DATA_FORMAT_CONTROL, + OPTC_DSC_MODE, dsc_mode); +} + + +/*TEMP: Need to figure out inheritance model here.*/ +bool optc2_is_two_pixels_per_containter(const struct dc_crtc_timing *timing) +{ + return optc1_is_two_pixels_per_containter(timing); +} + +void optc2_set_odm_bypass(struct timing_generator *optc, + const struct dc_crtc_timing *dc_crtc_timing) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + uint32_t h_div_2 = 0; + + REG_SET_3(OPTC_DATA_SOURCE_SELECT, 0, + OPTC_NUM_OF_INPUT_SEGMENT, 0, + OPTC_SEG0_SRC_SEL, optc->inst, + OPTC_SEG1_SRC_SEL, 0xf); + REG_WRITE(OTG_H_TIMING_CNTL, 0); + + h_div_2 = optc2_is_two_pixels_per_containter(dc_crtc_timing); + REG_UPDATE(OTG_H_TIMING_CNTL, + OTG_H_TIMING_DIV_BY2, h_div_2); + REG_SET(OPTC_MEMORY_CONFIG, 0, + OPTC_MEM_SEL, 0); + optc1->opp_count = 1; +} + +void optc2_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, + struct dc_crtc_timing *timing) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + int mpcc_hactive = (timing->h_addressable + timing->h_border_left + timing->h_border_right) + / opp_cnt; + uint32_t memory_mask; + + ASSERT(opp_cnt == 2); + + /* TODO: In pseudocode but does not affect maximus, delete comment if we dont need on asic + * REG_SET(OTG_GLOBAL_CONTROL2, 0, GLOBAL_UPDATE_LOCK_EN, 1); + * Program OTG register MASTER_UPDATE_LOCK_DB_X/Y to the position before DP frame start + * REG_SET_2(OTG_GLOBAL_CONTROL1, 0, + * MASTER_UPDATE_LOCK_DB_X, 160, + * MASTER_UPDATE_LOCK_DB_Y, 240); + */ + + /* 2 pieces of memory required for up to 5120 displays, 4 for up to 8192, + * however, for ODM combine we can simplify by always using 4. + * To make sure there's no overlap, each instance "reserves" 2 memories and + * they are uniquely combined here. + */ + memory_mask = 0x3 << (opp_id[0] * 2) | 0x3 << (opp_id[1] * 2); + + if (REG(OPTC_MEMORY_CONFIG)) + REG_SET(OPTC_MEMORY_CONFIG, 0, + OPTC_MEM_SEL, memory_mask); + + REG_SET_3(OPTC_DATA_SOURCE_SELECT, 0, + OPTC_NUM_OF_INPUT_SEGMENT, 1, + OPTC_SEG0_SRC_SEL, opp_id[0], + OPTC_SEG1_SRC_SEL, opp_id[1]); + + REG_UPDATE(OPTC_WIDTH_CONTROL, + OPTC_SEGMENT_WIDTH, mpcc_hactive); + + REG_SET(OTG_H_TIMING_CNTL, 0, OTG_H_TIMING_DIV_BY2, 1); + optc1->opp_count = opp_cnt; +} + +void optc2_get_optc_source(struct timing_generator *optc, + uint32_t *num_of_src_opp, + uint32_t *src_opp_id_0, + uint32_t *src_opp_id_1) +{ + uint32_t num_of_input_segments; + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_GET_3(OPTC_DATA_SOURCE_SELECT, + OPTC_NUM_OF_INPUT_SEGMENT, &num_of_input_segments, + OPTC_SEG0_SRC_SEL, src_opp_id_0, + OPTC_SEG1_SRC_SEL, src_opp_id_1); + + if (num_of_input_segments == 1) + *num_of_src_opp = 2; + else + *num_of_src_opp = 1; + + /* Work around VBIOS not updating OPTC_NUM_OF_INPUT_SEGMENT */ + if (*src_opp_id_1 == 0xf) + *num_of_src_opp = 1; +} + +static void optc2_set_dwb_source(struct timing_generator *optc, + uint32_t dwb_pipe_inst) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + if (dwb_pipe_inst == 0) + REG_UPDATE(DWB_SOURCE_SELECT, + OPTC_DWB0_SOURCE_SELECT, optc->inst); + else if (dwb_pipe_inst == 1) + REG_UPDATE(DWB_SOURCE_SELECT, + OPTC_DWB1_SOURCE_SELECT, optc->inst); +} + +static void optc2_align_vblanks( + struct timing_generator *optc_master, + struct timing_generator *optc_slave, + uint32_t master_pixel_clock_100Hz, + uint32_t slave_pixel_clock_100Hz, + uint8_t master_clock_divider, + uint8_t slave_clock_divider) +{ + /* accessing slave OTG registers */ + struct optc *optc1 = DCN10TG_FROM_TG(optc_slave); + + uint32_t master_v_active = 0; + uint32_t master_h_total = 0; + uint32_t slave_h_total = 0; + uint64_t L, XY; + uint32_t X, Y, p = 10000; + uint32_t master_update_lock; + + /* disable slave OTG */ + REG_UPDATE(OTG_CONTROL, OTG_MASTER_EN, 0); + /* wait until disabled */ + REG_WAIT(OTG_CONTROL, + OTG_CURRENT_MASTER_EN_STATE, + 0, 10, 5000); + + REG_GET(OTG_H_TOTAL, OTG_H_TOTAL, &slave_h_total); + + /* assign slave OTG to be controlled by master update lock */ + REG_SET(OTG_GLOBAL_CONTROL0, 0, + OTG_MASTER_UPDATE_LOCK_SEL, optc_master->inst); + + /* accessing master OTG registers */ + optc1 = DCN10TG_FROM_TG(optc_master); + + /* saving update lock state, not sure if it's needed */ + REG_GET(OTG_MASTER_UPDATE_LOCK, + OTG_MASTER_UPDATE_LOCK, &master_update_lock); + /* unlocking master OTG */ + REG_SET(OTG_MASTER_UPDATE_LOCK, 0, + OTG_MASTER_UPDATE_LOCK, 0); + + REG_GET(OTG_V_BLANK_START_END, + OTG_V_BLANK_START, &master_v_active); + REG_GET(OTG_H_TOTAL, OTG_H_TOTAL, &master_h_total); + + /* calculate when to enable slave OTG */ + L = (uint64_t)p * slave_h_total * master_pixel_clock_100Hz; + L = div_u64(L, master_h_total); + L = div_u64(L, slave_pixel_clock_100Hz); + XY = div_u64(L, p); + Y = master_v_active - XY - 1; + X = div_u64(((XY + 1) * p - L) * master_h_total, p * master_clock_divider); + + /* + * set master OTG to unlock when V/H + * counters reach calculated values + */ + REG_UPDATE(OTG_GLOBAL_CONTROL1, + MASTER_UPDATE_LOCK_DB_EN, 1); + REG_UPDATE_2(OTG_GLOBAL_CONTROL1, + MASTER_UPDATE_LOCK_DB_X, + X, + MASTER_UPDATE_LOCK_DB_Y, + Y); + + /* lock master OTG */ + REG_SET(OTG_MASTER_UPDATE_LOCK, 0, + OTG_MASTER_UPDATE_LOCK, 1); + REG_WAIT(OTG_MASTER_UPDATE_LOCK, + UPDATE_LOCK_STATUS, 1, 1, 10); + + /* accessing slave OTG registers */ + optc1 = DCN10TG_FROM_TG(optc_slave); + + /* + * enable slave OTG, the OTG is locked with + * master's update lock, so it will not run + */ + REG_UPDATE(OTG_CONTROL, + OTG_MASTER_EN, 1); + + /* accessing master OTG registers */ + optc1 = DCN10TG_FROM_TG(optc_master); + + /* + * unlock master OTG. When master H/V counters reach + * DB_XY point, slave OTG will start + */ + REG_SET(OTG_MASTER_UPDATE_LOCK, 0, + OTG_MASTER_UPDATE_LOCK, 0); + + /* accessing slave OTG registers */ + optc1 = DCN10TG_FROM_TG(optc_slave); + + /* wait for slave OTG to start running*/ + REG_WAIT(OTG_CONTROL, + OTG_CURRENT_MASTER_EN_STATE, + 1, 10, 5000); + + /* accessing master OTG registers */ + optc1 = DCN10TG_FROM_TG(optc_master); + + /* disable the XY point*/ + REG_UPDATE(OTG_GLOBAL_CONTROL1, + MASTER_UPDATE_LOCK_DB_EN, 0); + REG_UPDATE_2(OTG_GLOBAL_CONTROL1, + MASTER_UPDATE_LOCK_DB_X, + 0, + MASTER_UPDATE_LOCK_DB_Y, + 0); + + /*restore master update lock*/ + REG_SET(OTG_MASTER_UPDATE_LOCK, 0, + OTG_MASTER_UPDATE_LOCK, master_update_lock); + + /* accessing slave OTG registers */ + optc1 = DCN10TG_FROM_TG(optc_slave); + /* restore slave to be controlled by it's own */ + REG_SET(OTG_GLOBAL_CONTROL0, 0, + OTG_MASTER_UPDATE_LOCK_SEL, optc_slave->inst); + +} + +void optc2_triplebuffer_lock(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET(OTG_GLOBAL_CONTROL0, 0, + OTG_MASTER_UPDATE_LOCK_SEL, optc->inst); + + REG_SET(OTG_VUPDATE_KEEPOUT, 0, + OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, 1); + + REG_SET(OTG_MASTER_UPDATE_LOCK, 0, + OTG_MASTER_UPDATE_LOCK, 1); + + REG_WAIT(OTG_MASTER_UPDATE_LOCK, + UPDATE_LOCK_STATUS, 1, + 1, 10); +} + +void optc2_triplebuffer_unlock(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET(OTG_MASTER_UPDATE_LOCK, 0, + OTG_MASTER_UPDATE_LOCK, 0); + + REG_SET(OTG_VUPDATE_KEEPOUT, 0, + OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, 0); + +} + +void optc2_lock_doublebuffer_enable(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + uint32_t v_blank_start = 0; + uint32_t h_blank_start = 0; + + REG_UPDATE(OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_EN, 1); + + REG_UPDATE_2(OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, 1, + DIG_UPDATE_LOCATION, 20); + + REG_GET(OTG_V_BLANK_START_END, OTG_V_BLANK_START, &v_blank_start); + + REG_GET(OTG_H_BLANK_START_END, OTG_H_BLANK_START, &h_blank_start); + + REG_UPDATE_2(OTG_GLOBAL_CONTROL1, + MASTER_UPDATE_LOCK_DB_X, + (h_blank_start - 200 - 1) / optc1->opp_count, + MASTER_UPDATE_LOCK_DB_Y, + v_blank_start - 1); + + REG_SET_3(OTG_VUPDATE_KEEPOUT, 0, + MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET, 0, + MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET, 100, + OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, 1); +} + +void optc2_lock_doublebuffer_disable(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_UPDATE_2(OTG_GLOBAL_CONTROL1, + MASTER_UPDATE_LOCK_DB_X, + 0, + MASTER_UPDATE_LOCK_DB_Y, + 0); + + REG_UPDATE_2(OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, 0, + DIG_UPDATE_LOCATION, 0); + + REG_UPDATE(OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_EN, 0); +} + +void optc2_setup_manual_trigger(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + /* Set the min/max selectors unconditionally so that + * DMCUB fw may change OTG timings when necessary + * TODO: Remove the w/a after fixing the issue in DMCUB firmware + */ + REG_UPDATE_4(OTG_V_TOTAL_CONTROL, + OTG_V_TOTAL_MIN_SEL, 1, + OTG_V_TOTAL_MAX_SEL, 1, + OTG_FORCE_LOCK_ON_EVENT, 0, + OTG_SET_V_TOTAL_MIN_MASK, (1 << 1)); /* TRIGA */ + + REG_SET_8(OTG_TRIGA_CNTL, 0, + OTG_TRIGA_SOURCE_SELECT, 21, + OTG_TRIGA_SOURCE_PIPE_SELECT, optc->inst, + OTG_TRIGA_RISING_EDGE_DETECT_CNTL, 1, + OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, 0, + OTG_TRIGA_POLARITY_SELECT, 0, + OTG_TRIGA_FREQUENCY_SELECT, 0, + OTG_TRIGA_DELAY, 0, + OTG_TRIGA_CLEAR, 1); +} + +void optc2_program_manual_trigger(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET(OTG_TRIGA_MANUAL_TRIG, 0, + OTG_TRIGA_MANUAL_TRIG, 1); +} + +bool optc2_configure_crc(struct timing_generator *optc, + const struct crc_params *params) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET_2(OTG_CRC_CNTL2, 0, + OTG_CRC_DSC_MODE, params->dsc_mode, + OTG_CRC_DATA_STREAM_COMBINE_MODE, params->odm_mode); + + return optc1_configure_crc(optc, params); +} + + +void optc2_get_last_used_drr_vtotal(struct timing_generator *optc, uint32_t *refresh_rate) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_GET(OTG_DRR_CONTROL, OTG_V_TOTAL_LAST_USED_BY_DRR, refresh_rate); +} + +static struct timing_generator_funcs dcn20_tg_funcs = { + .validate_timing = optc1_validate_timing, + .program_timing = optc1_program_timing, + .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0, + .setup_vertical_interrupt1 = optc1_setup_vertical_interrupt1, + .setup_vertical_interrupt2 = optc1_setup_vertical_interrupt2, + .program_global_sync = optc1_program_global_sync, + .enable_crtc = optc2_enable_crtc, + .disable_crtc = optc1_disable_crtc, + /* used by enable_timing_synchronization. Not need for FPGA */ + .is_counter_moving = optc1_is_counter_moving, + .get_position = optc1_get_position, + .get_frame_count = optc1_get_vblank_counter, + .get_scanoutpos = optc1_get_crtc_scanoutpos, + .get_otg_active_size = optc1_get_otg_active_size, + .set_early_control = optc1_set_early_control, + /* used by enable_timing_synchronization. Not need for FPGA */ + .wait_for_state = optc1_wait_for_state, + .set_blank = optc1_set_blank, + .is_blanked = optc1_is_blanked, + .set_blank_color = optc1_program_blank_color, + .enable_reset_trigger = optc1_enable_reset_trigger, + .enable_crtc_reset = optc1_enable_crtc_reset, + .did_triggered_reset_occur = optc1_did_triggered_reset_occur, + .triplebuffer_lock = optc2_triplebuffer_lock, + .triplebuffer_unlock = optc2_triplebuffer_unlock, + .disable_reset_trigger = optc1_disable_reset_trigger, + .lock = optc1_lock, + .unlock = optc1_unlock, + .lock_doublebuffer_enable = optc2_lock_doublebuffer_enable, + .lock_doublebuffer_disable = optc2_lock_doublebuffer_disable, + .enable_optc_clock = optc1_enable_optc_clock, + .set_drr = optc1_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 = optc1_set_static_screen_control, + .program_stereo = optc1_program_stereo, + .is_stereo_left_eye = optc1_is_stereo_left_eye, + .set_blank_data_double_buffer = optc1_set_blank_data_double_buffer, + .tg_init = optc1_tg_init, + .is_tg_enabled = optc1_is_tg_enabled, + .is_optc_underflow_occurred = optc1_is_optc_underflow_occurred, + .clear_optc_underflow = optc1_clear_optc_underflow, + .setup_global_swap_lock = NULL, + .get_crc = optc1_get_crc, + .configure_crc = optc2_configure_crc, + .set_dsc_config = optc2_set_dsc_config, + .get_dsc_status = optc2_get_dsc_status, + .set_dwb_source = optc2_set_dwb_source, + .set_odm_bypass = optc2_set_odm_bypass, + .set_odm_combine = optc2_set_odm_combine, + .get_optc_source = optc2_get_optc_source, + .set_gsl = optc2_set_gsl, + .set_gsl_source_select = optc2_set_gsl_source_select, + .set_vtg_params = optc1_set_vtg_params, + .program_manual_trigger = optc2_program_manual_trigger, + .setup_manual_trigger = optc2_setup_manual_trigger, + .get_hw_timing = optc1_get_hw_timing, + .align_vblanks = optc2_align_vblanks, +}; + +void dcn20_timing_generator_init(struct optc *optc1) +{ + optc1->base.funcs = &dcn20_tg_funcs; + + optc1->max_h_total = optc1->tg_mask->OTG_H_TOTAL + 1; + optc1->max_v_total = optc1->tg_mask->OTG_V_TOTAL + 1; + + optc1->min_h_blank = 32; + optc1->min_v_blank = 3; + optc1->min_v_blank_interlace = 5; + optc1->min_h_sync_width = 4;// Minimum HSYNC = 8 pixels asked By HW in the first place for no actual reason. Oculus Rift S will not light up with 8 as it's hsyncWidth is 6. Changing it to 4 to fix that issue. + optc1->min_v_sync_width = 1; +} diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.h new file mode 100644 index 00000000000000..c2e03ced392ee4 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.h @@ -0,0 +1,124 @@ +/* + * 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 __DC_OPTC_DCN20_H__ +#define __DC_OPTC_DCN20_H__ + +#include "dcn10/dcn10_optc.h" + +#define TG_COMMON_REG_LIST_DCN2_0(inst) \ + TG_COMMON_REG_LIST_DCN(inst),\ + SRI(OTG_GLOBAL_CONTROL1, OTG, inst),\ + SRI(OTG_GLOBAL_CONTROL2, OTG, inst),\ + SRI(OTG_GSL_WINDOW_X, OTG, inst),\ + SRI(OTG_GSL_WINDOW_Y, OTG, inst),\ + SRI(OTG_VUPDATE_KEEPOUT, OTG, inst),\ + SRI(OTG_DSC_START_POSITION, OTG, inst),\ + SRI(OTG_CRC_CNTL2, OTG, inst),\ + SRI(OPTC_DATA_FORMAT_CONTROL, ODM, inst),\ + SRI(OPTC_BYTES_PER_PIXEL, ODM, inst),\ + SRI(OPTC_WIDTH_CONTROL, ODM, inst),\ + SRI(OPTC_MEMORY_CONFIG, ODM, inst),\ + SR(DWB_SOURCE_SELECT),\ + SRI(OTG_MANUAL_FLOW_CONTROL, OTG, inst), \ + SRI(OTG_DRR_CONTROL, OTG, inst) + +#define TG_COMMON_MASK_SH_LIST_DCN2_0(mask_sh)\ + TG_COMMON_MASK_SH_LIST_DCN(mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_X, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_Y, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_EN, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL2, DIG_UPDATE_LOCATION, mask_sh),\ + SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_RANGE_TIMING_DBUF_UPDATE_MODE, mask_sh),\ + SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_START_X, mask_sh),\ + SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_END_X, mask_sh), \ + SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_START_Y, mask_sh),\ + SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_END_Y, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_MASTER_MODE, mask_sh), \ + SF(OTG0_OTG_GSL_CONTROL, OTG_MASTER_UPDATE_LOCK_GSL_EN, mask_sh), \ + SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_X, mask_sh), \ + SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_LINE_NUM, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DSC_MODE, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_STREAM_COMBINE_MODE, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_STREAM_SPLIT_MODE, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_FORMAT, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG0_SRC_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG1_SRC_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_NUM_OF_INPUT_SEGMENT, mask_sh),\ + SF(ODM0_OPTC_MEMORY_CONFIG, OPTC_MEM_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_FORMAT_CONTROL, OPTC_DATA_FORMAT, mask_sh),\ + SF(ODM0_OPTC_DATA_FORMAT_CONTROL, OPTC_DSC_MODE, mask_sh),\ + SF(ODM0_OPTC_BYTES_PER_PIXEL, OPTC_DSC_BYTES_PER_PIXEL, mask_sh),\ + SF(ODM0_OPTC_WIDTH_CONTROL, OPTC_DSC_SLICE_WIDTH, mask_sh),\ + SF(ODM0_OPTC_WIDTH_CONTROL, OPTC_SEGMENT_WIDTH, mask_sh),\ + SF(DWB_SOURCE_SELECT, OPTC_DWB0_SOURCE_SELECT, mask_sh),\ + SF(DWB_SOURCE_SELECT, OPTC_DWB1_SOURCE_SELECT, mask_sh),\ + SF(OTG0_OTG_MANUAL_FLOW_CONTROL, MANUAL_FLOW_CONTROL, mask_sh), \ + SF(OTG0_OTG_DRR_CONTROL, OTG_V_TOTAL_LAST_USED_BY_DRR, mask_sh) + +void dcn20_timing_generator_init(struct optc *optc); + +void optc2_get_last_used_drr_vtotal(struct timing_generator *optc, + uint32_t *refresh_rate); + +bool optc2_enable_crtc(struct timing_generator *optc); + +void optc2_set_gsl(struct timing_generator *optc, + const struct gsl_params *params); + +void optc2_set_gsl_source_select(struct timing_generator *optc, + int group_idx, + uint32_t gsl_ready_signal); + +void optc2_set_dsc_config(struct timing_generator *optc, + enum optc_dsc_mode dsc_mode, + uint32_t dsc_bytes_per_pixel, + uint32_t dsc_slice_width); + +void optc2_get_dsc_status(struct timing_generator *optc, + uint32_t *dsc_mode); + +void optc2_set_odm_bypass(struct timing_generator *optc, + const struct dc_crtc_timing *dc_crtc_timing); + +void optc2_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, + struct dc_crtc_timing *timing); + +void optc2_get_optc_source(struct timing_generator *optc, + uint32_t *num_of_src_opp, + uint32_t *src_opp_id_0, + uint32_t *src_opp_id_1); + +void optc2_triplebuffer_lock(struct timing_generator *optc); +void optc2_triplebuffer_unlock(struct timing_generator *optc); +void optc2_lock_doublebuffer_disable(struct timing_generator *optc); +void optc2_lock_doublebuffer_enable(struct timing_generator *optc); +void optc2_setup_manual_trigger(struct timing_generator *optc); +void optc2_program_manual_trigger(struct timing_generator *optc); +bool optc2_is_two_pixels_per_containter(const struct dc_crtc_timing *timing); +bool optc2_configure_crc(struct timing_generator *optc, + const struct crc_params *params); +#endif /* __DC_OPTC_DCN20_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn201/dcn201_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn201/dcn201_optc.c new file mode 100644 index 00000000000000..70fcbec03fb6b7 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn201/dcn201_optc.c @@ -0,0 +1,202 @@ +/* + * 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 + * + */ + +#include "reg_helper.h" +#include "dcn201_optc.h" +#include "dcn10/dcn10_optc.h" +#include "dc.h" + +#define REG(reg)\ + optc1->tg_regs->reg + +#define CTX \ + optc1->base.ctx + +#undef FN +#define FN(reg_name, field_name) \ + optc1->tg_shift->field_name, optc1->tg_mask->field_name + +/*TEMP: Need to figure out inheritance model here.*/ +bool optc201_is_two_pixels_per_containter(const struct dc_crtc_timing *timing) +{ + return optc1_is_two_pixels_per_containter(timing); +} + +static void optc201_triplebuffer_lock(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET(OTG_GLOBAL_CONTROL0, 0, + OTG_MASTER_UPDATE_LOCK_SEL, optc->inst); + REG_SET(OTG_VUPDATE_KEEPOUT, 0, + OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, 1); + REG_SET(OTG_MASTER_UPDATE_LOCK, 0, + OTG_MASTER_UPDATE_LOCK, 1); + + REG_WAIT(OTG_MASTER_UPDATE_LOCK, + UPDATE_LOCK_STATUS, 1, + 1, 10); +} + +static void optc201_triplebuffer_unlock(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET(OTG_MASTER_UPDATE_LOCK, 0, + OTG_MASTER_UPDATE_LOCK, 0); + REG_SET(OTG_VUPDATE_KEEPOUT, 0, + OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, 0); + +} + +static bool optc201_validate_timing( + struct timing_generator *optc, + const struct dc_crtc_timing *timing) +{ + uint32_t v_blank; + uint32_t h_blank; + uint32_t min_v_blank; + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + ASSERT(timing != NULL); + + v_blank = (timing->v_total - timing->v_addressable - + timing->v_border_top - timing->v_border_bottom); + + h_blank = (timing->h_total - timing->h_addressable - + timing->h_border_right - + timing->h_border_left); + + if (timing->timing_3d_format != TIMING_3D_FORMAT_NONE && + timing->timing_3d_format != TIMING_3D_FORMAT_HW_FRAME_PACKING && + timing->timing_3d_format != TIMING_3D_FORMAT_TOP_AND_BOTTOM && + timing->timing_3d_format != TIMING_3D_FORMAT_SIDE_BY_SIDE && + timing->timing_3d_format != TIMING_3D_FORMAT_FRAME_ALTERNATE && + timing->timing_3d_format != TIMING_3D_FORMAT_INBAND_FA) + return false; + + /* Check maximum number of pixels supported by Timing Generator + * (Currently will never fail, in order to fail needs display which + * needs more than 8192 horizontal and + * more than 8192 vertical total pixels) + */ + if (timing->h_total > optc1->max_h_total || + timing->v_total > optc1->max_v_total) + return false; + + if (h_blank < optc1->min_h_blank) + return false; + + if (timing->h_sync_width < optc1->min_h_sync_width || + timing->v_sync_width < optc1->min_v_sync_width) + return false; + + min_v_blank = timing->flags.INTERLACE?optc1->min_v_blank_interlace:optc1->min_v_blank; + + if (v_blank < min_v_blank) + return false; + + return true; + +} + +static void optc201_get_optc_source(struct timing_generator *optc, + uint32_t *num_of_src_opp, + uint32_t *src_opp_id_0, + uint32_t *src_opp_id_1) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_GET(OPTC_DATA_SOURCE_SELECT, + OPTC_SEG0_SRC_SEL, src_opp_id_0); + + *num_of_src_opp = 1; +} + +static struct timing_generator_funcs dcn201_tg_funcs = { + .validate_timing = optc201_validate_timing, + .program_timing = optc1_program_timing, + .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0, + .setup_vertical_interrupt1 = optc1_setup_vertical_interrupt1, + .setup_vertical_interrupt2 = optc1_setup_vertical_interrupt2, + .program_global_sync = optc1_program_global_sync, + .enable_crtc = optc2_enable_crtc, + .disable_crtc = optc1_disable_crtc, + /* used by enable_timing_synchronization. Not need for FPGA */ + .is_counter_moving = optc1_is_counter_moving, + .get_position = optc1_get_position, + .get_frame_count = optc1_get_vblank_counter, + .get_scanoutpos = optc1_get_crtc_scanoutpos, + .get_otg_active_size = optc1_get_otg_active_size, + .set_early_control = optc1_set_early_control, + /* used by enable_timing_synchronization. Not need for FPGA */ + .wait_for_state = optc1_wait_for_state, + .set_blank = optc1_set_blank, + .is_blanked = optc1_is_blanked, + .set_blank_color = optc1_program_blank_color, + .did_triggered_reset_occur = optc1_did_triggered_reset_occur, + .enable_reset_trigger = optc1_enable_reset_trigger, + .enable_crtc_reset = optc1_enable_crtc_reset, + .disable_reset_trigger = optc1_disable_reset_trigger, + .triplebuffer_lock = optc201_triplebuffer_lock, + .triplebuffer_unlock = optc201_triplebuffer_unlock, + .lock = optc1_lock, + .unlock = optc1_unlock, + .enable_optc_clock = optc1_enable_optc_clock, + .set_drr = optc1_set_drr, + .get_last_used_drr_vtotal = NULL, + .set_vtotal_min_max = optc1_set_vtotal_min_max, + .set_static_screen_control = optc1_set_static_screen_control, + .program_stereo = optc1_program_stereo, + .is_stereo_left_eye = optc1_is_stereo_left_eye, + .set_blank_data_double_buffer = optc1_set_blank_data_double_buffer, + .tg_init = optc1_tg_init, + .is_tg_enabled = optc1_is_tg_enabled, + .is_optc_underflow_occurred = optc1_is_optc_underflow_occurred, + .clear_optc_underflow = optc1_clear_optc_underflow, + .get_crc = optc1_get_crc, + .configure_crc = optc2_configure_crc, + .set_dsc_config = optc2_set_dsc_config, + .set_dwb_source = NULL, + .get_optc_source = optc201_get_optc_source, + .set_vtg_params = optc1_set_vtg_params, + .program_manual_trigger = optc2_program_manual_trigger, + .setup_manual_trigger = optc2_setup_manual_trigger, + .get_hw_timing = optc1_get_hw_timing, +}; + +void dcn201_timing_generator_init(struct optc *optc1) +{ + optc1->base.funcs = &dcn201_tg_funcs; + + optc1->max_h_total = optc1->tg_mask->OTG_H_TOTAL + 1; + optc1->max_v_total = optc1->tg_mask->OTG_V_TOTAL + 1; + + optc1->min_h_blank = 32; + optc1->min_v_blank = 3; + optc1->min_v_blank_interlace = 5; + optc1->min_h_sync_width = 8; + optc1->min_v_sync_width = 1; +} diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn201/dcn201_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn201/dcn201_optc.h new file mode 100644 index 00000000000000..e9545b73513abe --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn201/dcn201_optc.h @@ -0,0 +1,74 @@ +/* + * 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 __DC_OPTC_DCN201_H__ +#define __DC_OPTC_DCN201_H__ + +#include "dcn20/dcn20_optc.h" + +#define TG_COMMON_REG_LIST_DCN201(inst) \ + TG_COMMON_REG_LIST_DCN(inst),\ + SRI(OTG_GLOBAL_CONTROL1, OTG, inst),\ + SRI(OTG_GLOBAL_CONTROL2, OTG, inst),\ + SRI(OTG_GSL_WINDOW_X, OTG, inst),\ + SRI(OTG_GSL_WINDOW_Y, OTG, inst),\ + SRI(OTG_VUPDATE_KEEPOUT, OTG, inst),\ + SRI(OTG_DSC_START_POSITION, OTG, inst),\ + SRI(OPTC_DATA_FORMAT_CONTROL, ODM, inst),\ + SRI(OPTC_BYTES_PER_PIXEL, ODM, inst),\ + SRI(OPTC_WIDTH_CONTROL, ODM, inst),\ + SR(DWB_SOURCE_SELECT) + +#define TG_COMMON_MASK_SH_LIST_DCN201(mask_sh)\ + TG_COMMON_MASK_SH_LIST_DCN(mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_X, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_Y, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_EN, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, mask_sh),\ + SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_RANGE_TIMING_DBUF_UPDATE_MODE, mask_sh),\ + SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_START_X, mask_sh),\ + SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_END_X, mask_sh), \ + SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_START_Y, mask_sh),\ + SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_END_Y, mask_sh),\ + SF(OTG0_OTG_VUPDATE_KEEPOUT, OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, mask_sh), \ + SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET, mask_sh), \ + SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET, mask_sh), \ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_MASTER_MODE, mask_sh), \ + SF(OTG0_OTG_GSL_CONTROL, OTG_MASTER_UPDATE_LOCK_GSL_EN, mask_sh), \ + SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_X, mask_sh), \ + SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_LINE_NUM, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG0_SRC_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_FORMAT_CONTROL, OPTC_DSC_MODE, mask_sh),\ + SF(ODM0_OPTC_BYTES_PER_PIXEL, OPTC_DSC_BYTES_PER_PIXEL, mask_sh),\ + SF(ODM0_OPTC_WIDTH_CONTROL, OPTC_DSC_SLICE_WIDTH, mask_sh),\ + SF(DWB_SOURCE_SELECT, OPTC_DWB0_SOURCE_SELECT, mask_sh),\ + SF(DWB_SOURCE_SELECT, OPTC_DWB1_SOURCE_SELECT, mask_sh),\ + SF(DWB_SOURCE_SELECT, OPTC_DWB1_SOURCE_SELECT, mask_sh) + +void dcn201_timing_generator_init(struct optc *optc); + +bool optc201_is_two_pixels_per_containter(const struct dc_crtc_timing *timing); + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.c new file mode 100644 index 00000000000000..b97bdb868a0e7f --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.c @@ -0,0 +1,393 @@ +/* + * Copyright 2020 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 "reg_helper.h" +#include "dcn30_optc.h" +#include "dc.h" +#include "dcn_calc_math.h" +#include "dc_dmub_srv.h" + +#include "dml/dcn30/dcn30_fpu.h" +#include "dc_trace.h" + +#define REG(reg)\ + optc1->tg_regs->reg + +#define CTX \ + optc1->base.ctx + +#undef FN +#define FN(reg_name, field_name) \ + optc1->tg_shift->field_name, optc1->tg_mask->field_name + +void optc3_triplebuffer_lock(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_UPDATE(OTG_GLOBAL_CONTROL2, + OTG_MASTER_UPDATE_LOCK_SEL, optc->inst); + + REG_SET(OTG_VUPDATE_KEEPOUT, 0, + OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, 1); + + REG_SET(OTG_MASTER_UPDATE_LOCK, 0, + OTG_MASTER_UPDATE_LOCK, 1); + + REG_WAIT(OTG_MASTER_UPDATE_LOCK, + UPDATE_LOCK_STATUS, 1, + 1, 10); + + TRACE_OPTC_LOCK_UNLOCK_STATE(optc1, optc->inst, true); +} + +void optc3_lock_doublebuffer_enable(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + uint32_t v_blank_start = 0; + uint32_t v_blank_end = 0; + uint32_t h_blank_start = 0; + uint32_t h_blank_end = 0; + + REG_GET_2(OTG_V_BLANK_START_END, + OTG_V_BLANK_START, &v_blank_start, + OTG_V_BLANK_END, &v_blank_end); + REG_GET_2(OTG_H_BLANK_START_END, + OTG_H_BLANK_START, &h_blank_start, + OTG_H_BLANK_END, &h_blank_end); + + REG_UPDATE_2(OTG_GLOBAL_CONTROL1, + MASTER_UPDATE_LOCK_DB_START_Y, v_blank_start - 1, + MASTER_UPDATE_LOCK_DB_END_Y, v_blank_start); + REG_UPDATE_2(OTG_GLOBAL_CONTROL4, + DIG_UPDATE_POSITION_X, h_blank_start - 180 - 1, + DIG_UPDATE_POSITION_Y, v_blank_start - 1); + // there is a DIG_UPDATE_VCOUNT_MODE and it is 0. + + REG_UPDATE_3(OTG_GLOBAL_CONTROL0, + MASTER_UPDATE_LOCK_DB_START_X, h_blank_start - 200 - 1, + MASTER_UPDATE_LOCK_DB_END_X, h_blank_start - 180, + MASTER_UPDATE_LOCK_DB_EN, 1); + REG_UPDATE(OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, 1); + + REG_SET_3(OTG_VUPDATE_KEEPOUT, 0, + MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET, 0, + MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET, 100, + OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, 1); + + TRACE_OPTC_LOCK_UNLOCK_STATE(optc1, optc->inst, true); +} + +void optc3_lock_doublebuffer_disable(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_UPDATE_2(OTG_GLOBAL_CONTROL0, + MASTER_UPDATE_LOCK_DB_START_X, 0, + MASTER_UPDATE_LOCK_DB_END_X, 0); + REG_UPDATE_2(OTG_GLOBAL_CONTROL1, + MASTER_UPDATE_LOCK_DB_START_Y, 0, + MASTER_UPDATE_LOCK_DB_END_Y, 0); + + REG_UPDATE(OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, 0); + REG_UPDATE(OTG_GLOBAL_CONTROL0, MASTER_UPDATE_LOCK_DB_EN, 0); + + TRACE_OPTC_LOCK_UNLOCK_STATE(optc1, optc->inst, true); +} + +void optc3_lock(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_UPDATE(OTG_GLOBAL_CONTROL2, + OTG_MASTER_UPDATE_LOCK_SEL, optc->inst); + REG_SET(OTG_MASTER_UPDATE_LOCK, 0, + OTG_MASTER_UPDATE_LOCK, 1); + + REG_WAIT(OTG_MASTER_UPDATE_LOCK, + UPDATE_LOCK_STATUS, 1, + 1, 10); + + TRACE_OPTC_LOCK_UNLOCK_STATE(optc1, optc->inst, true); +} + +void optc3_set_out_mux(struct timing_generator *optc, enum otg_out_mux_dest dest) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_UPDATE(OTG_CONTROL, OTG_OUT_MUX, dest); +} + +void optc3_program_blank_color(struct timing_generator *optc, + const struct tg_color *blank_color) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET_3(OTG_BLANK_DATA_COLOR, 0, + OTG_BLANK_DATA_COLOR_BLUE_CB, blank_color->color_b_cb, + OTG_BLANK_DATA_COLOR_GREEN_Y, blank_color->color_g_y, + OTG_BLANK_DATA_COLOR_RED_CR, blank_color->color_r_cr); + + REG_SET_3(OTG_BLANK_DATA_COLOR_EXT, 0, + OTG_BLANK_DATA_COLOR_BLUE_CB_EXT, blank_color->color_b_cb >> 10, + OTG_BLANK_DATA_COLOR_GREEN_Y_EXT, blank_color->color_g_y >> 10, + OTG_BLANK_DATA_COLOR_RED_CR_EXT, blank_color->color_r_cr >> 10); +} + +void optc3_set_drr_trigger_window(struct timing_generator *optc, + uint32_t window_start, uint32_t window_end) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET_2(OTG_DRR_TRIGGER_WINDOW, 0, + OTG_DRR_TRIGGER_WINDOW_START_X, window_start, + OTG_DRR_TRIGGER_WINDOW_END_X, window_end); +} + +void optc3_set_vtotal_change_limit(struct timing_generator *optc, + uint32_t limit) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + + REG_SET(OTG_DRR_V_TOTAL_CHANGE, 0, + OTG_DRR_V_TOTAL_CHANGE_LIMIT, limit); +} + + +/* Set DSC-related configuration. + * dsc_mode: 0 disables DSC, other values enable DSC in specified format + * sc_bytes_per_pixel: Bytes per pixel in u3.28 format + * dsc_slice_width: Slice width in pixels + */ +void optc3_set_dsc_config(struct timing_generator *optc, + enum optc_dsc_mode dsc_mode, + uint32_t dsc_bytes_per_pixel, + uint32_t dsc_slice_width) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + optc2_set_dsc_config(optc, dsc_mode, dsc_bytes_per_pixel, dsc_slice_width); + REG_UPDATE(OTG_V_SYNC_A_CNTL, OTG_V_SYNC_MODE, 0); +} + +void optc3_set_odm_bypass(struct timing_generator *optc, + const struct dc_crtc_timing *dc_crtc_timing) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + enum h_timing_div_mode h_div = H_TIMING_NO_DIV; + + REG_SET_5(OPTC_DATA_SOURCE_SELECT, 0, + OPTC_NUM_OF_INPUT_SEGMENT, 0, + OPTC_SEG0_SRC_SEL, optc->inst, + OPTC_SEG1_SRC_SEL, 0xf, + OPTC_SEG2_SRC_SEL, 0xf, + OPTC_SEG3_SRC_SEL, 0xf + ); + + h_div = optc1_is_two_pixels_per_containter(dc_crtc_timing); + REG_UPDATE(OTG_H_TIMING_CNTL, + OTG_H_TIMING_DIV_MODE, h_div); + + REG_SET(OPTC_MEMORY_CONFIG, 0, + OPTC_MEM_SEL, 0); + optc1->opp_count = 1; +} + +void optc3_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, + struct dc_crtc_timing *timing) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + int mpcc_hactive = (timing->h_addressable + timing->h_border_left + timing->h_border_right) + / opp_cnt; + uint32_t memory_mask = 0; + + /* TODO: In pseudocode but does not affect maximus, delete comment if we dont need on asic + * REG_SET(OTG_GLOBAL_CONTROL2, 0, GLOBAL_UPDATE_LOCK_EN, 1); + * Program OTG register MASTER_UPDATE_LOCK_DB_X/Y to the position before DP frame start + * REG_SET_2(OTG_GLOBAL_CONTROL1, 0, + * MASTER_UPDATE_LOCK_DB_X, 160, + * MASTER_UPDATE_LOCK_DB_Y, 240); + */ + + ASSERT(opp_cnt == 2 || opp_cnt == 4); + + /* 2 pieces of memory required for up to 5120 displays, 4 for up to 8192, + * however, for ODM combine we can simplify by always using 4. + */ + if (opp_cnt == 2) { + /* To make sure there's no memory overlap, each instance "reserves" 2 + * memories and they are uniquely combined here. + */ + memory_mask = 0x3 << (opp_id[0] * 2) | 0x3 << (opp_id[1] * 2); + } else if (opp_cnt == 4) { + /* To make sure there's no memory overlap, each instance "reserves" 1 + * memory and they are uniquely combined here. + */ + memory_mask = 0x1 << (opp_id[0] * 2) | 0x1 << (opp_id[1] * 2) | 0x1 << (opp_id[2] * 2) | 0x1 << (opp_id[3] * 2); + } + + if (REG(OPTC_MEMORY_CONFIG)) + REG_SET(OPTC_MEMORY_CONFIG, 0, + OPTC_MEM_SEL, memory_mask); + + if (opp_cnt == 2) { + REG_SET_3(OPTC_DATA_SOURCE_SELECT, 0, + OPTC_NUM_OF_INPUT_SEGMENT, 1, + OPTC_SEG0_SRC_SEL, opp_id[0], + OPTC_SEG1_SRC_SEL, opp_id[1]); + } else if (opp_cnt == 4) { + REG_SET_5(OPTC_DATA_SOURCE_SELECT, 0, + OPTC_NUM_OF_INPUT_SEGMENT, 3, + OPTC_SEG0_SRC_SEL, opp_id[0], + OPTC_SEG1_SRC_SEL, opp_id[1], + OPTC_SEG2_SRC_SEL, opp_id[2], + OPTC_SEG3_SRC_SEL, opp_id[3]); + } + + REG_UPDATE(OPTC_WIDTH_CONTROL, + OPTC_SEGMENT_WIDTH, mpcc_hactive); + + REG_SET(OTG_H_TIMING_CNTL, 0, OTG_H_TIMING_DIV_MODE, opp_cnt - 1); + optc1->opp_count = opp_cnt; +} + +/** + * optc3_set_timing_double_buffer() - DRR double buffering control + * + * Sets double buffer point for V_TOTAL, H_TOTAL, VTOTAL_MIN, + * VTOTAL_MAX, VTOTAL_MIN_SEL and VTOTAL_MAX_SEL registers. + * + * @optc: timing_generator instance. + * @enable: Enable DRR double buffering control if true, disable otherwise. + * + * Options: any time, start of frame, dp start of frame (range timing) + */ +static void optc3_set_timing_double_buffer(struct timing_generator *optc, bool enable) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + uint32_t mode = enable ? 2 : 0; + + REG_UPDATE(OTG_DOUBLE_BUFFER_CONTROL, + 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) +{ + struct dc *dc = optc->ctx->dc; + + if (dc->caps.dmub_caps.mclk_sw && !dc->debug.disable_fams) + dc_dmub_srv_drr_update_cmd(dc, optc->inst, vtotal_min, vtotal_max); + else + optc1_set_vtotal_min_max(optc, vtotal_min, vtotal_max); +} + +void optc3_tg_init(struct timing_generator *optc) +{ + optc3_set_timing_double_buffer(optc, true); + optc1_clear_optc_underflow(optc); +} + +static struct timing_generator_funcs dcn30_tg_funcs = { + .validate_timing = optc1_validate_timing, + .program_timing = optc1_program_timing, + .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0, + .setup_vertical_interrupt1 = optc1_setup_vertical_interrupt1, + .setup_vertical_interrupt2 = optc1_setup_vertical_interrupt2, + .program_global_sync = optc1_program_global_sync, + .enable_crtc = optc2_enable_crtc, + .disable_crtc = optc1_disable_crtc, + /* used by enable_timing_synchronization. Not need for FPGA */ + .is_counter_moving = optc1_is_counter_moving, + .get_position = optc1_get_position, + .get_frame_count = optc1_get_vblank_counter, + .get_scanoutpos = optc1_get_crtc_scanoutpos, + .get_otg_active_size = optc1_get_otg_active_size, + .set_early_control = optc1_set_early_control, + /* used by enable_timing_synchronization. Not need for FPGA */ + .wait_for_state = optc1_wait_for_state, + .set_blank_color = optc3_program_blank_color, + .did_triggered_reset_occur = optc1_did_triggered_reset_occur, + .triplebuffer_lock = optc3_triplebuffer_lock, + .triplebuffer_unlock = optc2_triplebuffer_unlock, + .enable_reset_trigger = optc1_enable_reset_trigger, + .enable_crtc_reset = optc1_enable_crtc_reset, + .disable_reset_trigger = optc1_disable_reset_trigger, + .lock = optc3_lock, + .unlock = optc1_unlock, + .lock_doublebuffer_enable = optc3_lock_doublebuffer_enable, + .lock_doublebuffer_disable = optc3_lock_doublebuffer_disable, + .enable_optc_clock = optc1_enable_optc_clock, + .set_drr = optc1_set_drr, + .get_last_used_drr_vtotal = optc2_get_last_used_drr_vtotal, + .set_vtotal_min_max = optc3_set_vtotal_min_max, + .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, + .is_tg_enabled = optc1_is_tg_enabled, + .is_optc_underflow_occurred = optc1_is_optc_underflow_occurred, + .clear_optc_underflow = optc1_clear_optc_underflow, + .setup_global_swap_lock = NULL, + .get_crc = optc1_get_crc, + .configure_crc = optc2_configure_crc, + .set_dsc_config = optc3_set_dsc_config, + .get_dsc_status = optc2_get_dsc_status, + .set_dwb_source = NULL, + .set_odm_bypass = optc3_set_odm_bypass, + .set_odm_combine = optc3_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, + .set_vtotal_change_limit = optc3_set_vtotal_change_limit, + .set_gsl = optc2_set_gsl, + .set_gsl_source_select = optc2_set_gsl_source_select, + .set_vtg_params = optc1_set_vtg_params, + .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) +{ + optc1->base.funcs = &dcn30_tg_funcs; + + optc1->max_h_total = optc1->tg_mask->OTG_H_TOTAL + 1; + optc1->max_v_total = optc1->tg_mask->OTG_V_TOTAL + 1; + + optc1->min_h_blank = 32; + optc1->min_v_blank = 3; + optc1->min_v_blank_interlace = 5; + optc1->min_h_sync_width = 4; + optc1->min_v_sync_width = 1; +} diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.h new file mode 100644 index 00000000000000..d3a056c12b0dc7 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.h @@ -0,0 +1,359 @@ +/* + * Copyright 2020 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_OPTC_DCN30_H__ +#define __DC_OPTC_DCN30_H__ + +#include "dcn20/dcn20_optc.h" + +#define V_TOTAL_REGS_DCN30_SRI(inst) + +#define OPTC_COMMON_REG_LIST_DCN3_BASE(inst) \ + SRI(OTG_VSTARTUP_PARAM, OTG, inst),\ + SRI(OTG_VUPDATE_PARAM, OTG, inst),\ + SRI(OTG_VREADY_PARAM, OTG, inst),\ + SRI(OTG_MASTER_UPDATE_LOCK, OTG, inst),\ + SRI(OTG_GLOBAL_CONTROL0, OTG, inst),\ + SRI(OTG_GLOBAL_CONTROL1, OTG, inst),\ + SRI(OTG_GLOBAL_CONTROL2, OTG, inst),\ + SRI(OTG_GLOBAL_CONTROL4, OTG, inst),\ + SRI(OTG_DOUBLE_BUFFER_CONTROL, OTG, inst),\ + SRI(OTG_H_TOTAL, OTG, inst),\ + SRI(OTG_H_BLANK_START_END, OTG, inst),\ + SRI(OTG_H_SYNC_A, OTG, inst),\ + SRI(OTG_H_SYNC_A_CNTL, OTG, inst),\ + SRI(OTG_H_TIMING_CNTL, OTG, inst),\ + SRI(OTG_V_TOTAL, OTG, inst),\ + SRI(OTG_V_BLANK_START_END, OTG, inst),\ + SRI(OTG_V_SYNC_A, OTG, inst),\ + SRI(OTG_V_SYNC_A_CNTL, OTG, inst),\ + SRI(OTG_CONTROL, OTG, inst),\ + SRI(OTG_STEREO_CONTROL, OTG, inst),\ + SRI(OTG_3D_STRUCTURE_CONTROL, OTG, inst),\ + SRI(OTG_STEREO_STATUS, OTG, inst),\ + SRI(OTG_V_TOTAL_MAX, OTG, inst),\ + SRI(OTG_V_TOTAL_MIN, OTG, inst),\ + SRI(OTG_V_TOTAL_CONTROL, OTG, inst),\ + V_TOTAL_REGS_DCN30_SRI(inst)\ + SRI(OTG_TRIGA_CNTL, OTG, inst),\ + SRI(OTG_FORCE_COUNT_NOW_CNTL, OTG, inst),\ + SRI(OTG_STATIC_SCREEN_CONTROL, OTG, inst),\ + SRI(OTG_STATUS_FRAME_COUNT, OTG, inst),\ + SRI(OTG_STATUS, OTG, inst),\ + SRI(OTG_STATUS_POSITION, OTG, inst),\ + SRI(OTG_NOM_VERT_POSITION, OTG, inst),\ + SRI(OTG_BLANK_DATA_COLOR, OTG, inst),\ + SRI(OTG_BLANK_DATA_COLOR_EXT, OTG, inst),\ + SRI(OTG_M_CONST_DTO0, OTG, inst),\ + SRI(OTG_M_CONST_DTO1, OTG, inst),\ + SRI(OTG_CLOCK_CONTROL, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT0_CONTROL, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT0_POSITION, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT1_CONTROL, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT1_POSITION, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT2_CONTROL, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT2_POSITION, OTG, inst),\ + SRI(OPTC_INPUT_CLOCK_CONTROL, ODM, inst),\ + SRI(OPTC_DATA_SOURCE_SELECT, ODM, inst),\ + SRI(OPTC_INPUT_GLOBAL_CONTROL, ODM, inst),\ + SRI(CONTROL, VTG, inst),\ + SRI(OTG_VERT_SYNC_CONTROL, OTG, inst),\ + SRI(OTG_GSL_CONTROL, OTG, inst),\ + SRI(OTG_CRC_CNTL, OTG, inst),\ + SRI(OTG_CRC_CNTL2, OTG, inst),\ + SRI(OTG_CRC0_DATA_RG, OTG, inst),\ + SRI(OTG_CRC0_DATA_B, OTG, inst),\ + SRI(OTG_CRC0_WINDOWA_X_CONTROL, OTG, inst),\ + SRI(OTG_CRC0_WINDOWA_Y_CONTROL, OTG, inst),\ + SRI(OTG_CRC0_WINDOWB_X_CONTROL, OTG, inst),\ + SRI(OTG_CRC0_WINDOWB_Y_CONTROL, OTG, inst),\ + SR(GSL_SOURCE_SELECT),\ + SRI(OTG_TRIGA_MANUAL_TRIG, OTG, inst),\ + SRI(OTG_DRR_CONTROL, OTG, inst) + + +#define OPTC_COMMON_REG_LIST_DCN3_0(inst) \ + OPTC_COMMON_REG_LIST_DCN3_BASE(inst),\ + SRI(OTG_GLOBAL_CONTROL1, OTG, inst),\ + SRI(OTG_GLOBAL_CONTROL2, OTG, inst),\ + SRI(OTG_GSL_WINDOW_X, OTG, inst),\ + SRI(OTG_GSL_WINDOW_Y, OTG, inst),\ + SRI(OTG_VUPDATE_KEEPOUT, OTG, inst),\ + SRI(OTG_DSC_START_POSITION, OTG, inst),\ + SRI(OTG_CRC_CNTL2, OTG, inst),\ + SRI(OTG_DRR_TRIGGER_WINDOW, OTG, inst),\ + SRI(OTG_DRR_V_TOTAL_CHANGE, OTG, inst),\ + SRI(OPTC_DATA_FORMAT_CONTROL, ODM, inst),\ + SRI(OPTC_BYTES_PER_PIXEL, ODM, inst),\ + SRI(OPTC_WIDTH_CONTROL, ODM, inst),\ + SRI(OPTC_MEMORY_CONFIG, ODM, inst),\ + SR(DWB_SOURCE_SELECT) + +#define DCN30_VTOTAL_REGS_SF(mask_sh) + +#define OPTC_COMMON_MASK_SH_LIST_DCN3_BASE(mask_sh)\ + SF(OTG0_OTG_VSTARTUP_PARAM, VSTARTUP_START, mask_sh),\ + SF(OTG0_OTG_VUPDATE_PARAM, VUPDATE_OFFSET, mask_sh),\ + SF(OTG0_OTG_VUPDATE_PARAM, VUPDATE_WIDTH, mask_sh),\ + SF(OTG0_OTG_VREADY_PARAM, VREADY_OFFSET, mask_sh),\ + SF(OTG0_OTG_MASTER_UPDATE_LOCK, OTG_MASTER_UPDATE_LOCK, mask_sh),\ + SF(OTG0_OTG_MASTER_UPDATE_LOCK, UPDATE_LOCK_STATUS, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL0, MASTER_UPDATE_LOCK_DB_START_X, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL0, MASTER_UPDATE_LOCK_DB_END_X, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL0, MASTER_UPDATE_LOCK_DB_EN, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_START_Y, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_END_Y, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL2, OTG_MASTER_UPDATE_LOCK_SEL, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL4, DIG_UPDATE_POSITION_X, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL4, DIG_UPDATE_POSITION_Y, mask_sh),\ + SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_UPDATE_PENDING, mask_sh),\ + SF(OTG0_OTG_H_TOTAL, OTG_H_TOTAL, mask_sh),\ + SF(OTG0_OTG_H_BLANK_START_END, OTG_H_BLANK_START, mask_sh),\ + SF(OTG0_OTG_H_BLANK_START_END, OTG_H_BLANK_END, mask_sh),\ + SF(OTG0_OTG_H_SYNC_A, OTG_H_SYNC_A_START, mask_sh),\ + SF(OTG0_OTG_H_SYNC_A, OTG_H_SYNC_A_END, mask_sh),\ + SF(OTG0_OTG_H_SYNC_A_CNTL, OTG_H_SYNC_A_POL, mask_sh),\ + SF(OTG0_OTG_V_TOTAL, OTG_V_TOTAL, mask_sh),\ + SF(OTG0_OTG_V_BLANK_START_END, OTG_V_BLANK_START, mask_sh),\ + SF(OTG0_OTG_V_BLANK_START_END, OTG_V_BLANK_END, mask_sh),\ + SF(OTG0_OTG_V_SYNC_A, OTG_V_SYNC_A_START, mask_sh),\ + SF(OTG0_OTG_V_SYNC_A, OTG_V_SYNC_A_END, mask_sh),\ + SF(OTG0_OTG_V_SYNC_A_CNTL, OTG_V_SYNC_A_POL, mask_sh),\ + SF(OTG0_OTG_V_SYNC_A_CNTL, OTG_V_SYNC_MODE, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_MASTER_EN, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_START_POINT_CNTL, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_DISABLE_POINT_CNTL, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_FIELD_NUMBER_CNTL, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_OUT_MUX, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_EN, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_SYNC_OUTPUT_LINE_NUM, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_SYNC_OUTPUT_POLARITY, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_EYE_FLAG_POLARITY, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_DISABLE_STEREOSYNC_OUTPUT_FOR_DP, mask_sh),\ + SF(OTG0_OTG_STEREO_STATUS, OTG_STEREO_CURRENT_EYE, mask_sh),\ + SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_EN, mask_sh),\ + SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_V_UPDATE_MODE, mask_sh),\ + SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_STEREO_SEL_OVR, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_MAX, OTG_V_TOTAL_MAX, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_MIN, OTG_V_TOTAL_MIN, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_V_TOTAL_MIN_SEL, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_V_TOTAL_MAX_SEL, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_FORCE_LOCK_ON_EVENT, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_SET_V_TOTAL_MIN_MASK_EN, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_SET_V_TOTAL_MIN_MASK, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_VTOTAL_MID_REPLACING_MIN_EN, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_VTOTAL_MID_REPLACING_MAX_EN, mask_sh),\ + DCN30_VTOTAL_REGS_SF(mask_sh)\ + SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_CLEAR, mask_sh),\ + SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_MODE, mask_sh),\ + SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_OCCURRED, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_SOURCE_SELECT, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_SOURCE_PIPE_SELECT, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_RISING_EDGE_DETECT_CNTL, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_POLARITY_SELECT, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_FREQUENCY_SELECT, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_DELAY, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_CLEAR, mask_sh),\ + SF(OTG0_OTG_STATIC_SCREEN_CONTROL, OTG_STATIC_SCREEN_EVENT_MASK, mask_sh),\ + SF(OTG0_OTG_STATIC_SCREEN_CONTROL, OTG_STATIC_SCREEN_FRAME_COUNT, mask_sh),\ + SF(OTG0_OTG_STATUS_FRAME_COUNT, OTG_FRAME_COUNT, mask_sh),\ + SF(OTG0_OTG_STATUS, OTG_V_BLANK, mask_sh),\ + SF(OTG0_OTG_STATUS, OTG_V_ACTIVE_DISP, mask_sh),\ + SF(OTG0_OTG_STATUS_POSITION, OTG_HORZ_COUNT, mask_sh),\ + SF(OTG0_OTG_STATUS_POSITION, OTG_VERT_COUNT, mask_sh),\ + SF(OTG0_OTG_NOM_VERT_POSITION, OTG_VERT_COUNT_NOM, mask_sh),\ + SF(OTG0_OTG_BLANK_DATA_COLOR, OTG_BLANK_DATA_COLOR_BLUE_CB, mask_sh),\ + SF(OTG0_OTG_BLANK_DATA_COLOR, OTG_BLANK_DATA_COLOR_GREEN_Y, mask_sh),\ + SF(OTG0_OTG_BLANK_DATA_COLOR, OTG_BLANK_DATA_COLOR_RED_CR, mask_sh),\ + SF(OTG0_OTG_BLANK_DATA_COLOR_EXT, OTG_BLANK_DATA_COLOR_BLUE_CB_EXT, mask_sh),\ + SF(OTG0_OTG_BLANK_DATA_COLOR_EXT, OTG_BLANK_DATA_COLOR_GREEN_Y_EXT, mask_sh),\ + SF(OTG0_OTG_BLANK_DATA_COLOR_EXT, OTG_BLANK_DATA_COLOR_RED_CR_EXT, mask_sh),\ + SF(OTG0_OTG_M_CONST_DTO0, OTG_M_CONST_DTO_PHASE, mask_sh),\ + SF(OTG0_OTG_M_CONST_DTO1, OTG_M_CONST_DTO_MODULO, mask_sh),\ + SF(OTG0_OTG_CLOCK_CONTROL, OTG_BUSY, mask_sh),\ + SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_EN, mask_sh),\ + SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_ON, mask_sh),\ + SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_GATE_DIS, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_INT_ENABLE, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT0_POSITION, OTG_VERTICAL_INTERRUPT0_LINE_START, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT0_POSITION, OTG_VERTICAL_INTERRUPT0_LINE_END, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT1_CONTROL, OTG_VERTICAL_INTERRUPT1_INT_ENABLE, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT1_POSITION, OTG_VERTICAL_INTERRUPT1_LINE_START, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT2_POSITION, OTG_VERTICAL_INTERRUPT2_LINE_START, mask_sh),\ + SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_EN, mask_sh),\ + SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_ON, mask_sh),\ + SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_GATE_DIS, mask_sh),\ + SF(ODM0_OPTC_INPUT_GLOBAL_CONTROL, OPTC_UNDERFLOW_OCCURRED_STATUS, mask_sh),\ + SF(ODM0_OPTC_INPUT_GLOBAL_CONTROL, OPTC_UNDERFLOW_CLEAR, mask_sh),\ + SF(VTG0_CONTROL, VTG0_ENABLE, mask_sh),\ + SF(VTG0_CONTROL, VTG0_FP2, mask_sh),\ + SF(VTG0_CONTROL, VTG0_VCOUNT_INIT, mask_sh),\ + SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_FORCE_VSYNC_NEXT_LINE_OCCURRED, mask_sh),\ + SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_FORCE_VSYNC_NEXT_LINE_CLEAR, mask_sh),\ + SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_AUTO_FORCE_VSYNC_MODE, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL0_EN, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL1_EN, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL2_EN, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_MASTER_EN, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_FORCE_DELAY, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_CHECK_ALL_FIELDS, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL, OTG_CRC_CONT_EN, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL, OTG_CRC0_SELECT, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL, OTG_CRC_EN, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DSC_MODE, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_STREAM_COMBINE_MODE, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_STREAM_SPLIT_MODE, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_FORMAT, mask_sh),\ + SF(OTG0_OTG_CRC0_DATA_RG, CRC0_R_CR, mask_sh),\ + SF(OTG0_OTG_CRC0_DATA_RG, CRC0_G_Y, mask_sh),\ + SF(OTG0_OTG_CRC0_DATA_B, CRC0_B_CB, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWA_X_CONTROL, OTG_CRC0_WINDOWA_X_START, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWA_X_CONTROL, OTG_CRC0_WINDOWA_X_END, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWA_Y_CONTROL, OTG_CRC0_WINDOWA_Y_START, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWA_Y_CONTROL, OTG_CRC0_WINDOWA_Y_END, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWB_X_CONTROL, OTG_CRC0_WINDOWB_X_START, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWB_X_CONTROL, OTG_CRC0_WINDOWB_X_END, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL, OTG_CRC0_WINDOWB_Y_START, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL, OTG_CRC0_WINDOWB_Y_END, mask_sh),\ + SF(OTG0_OTG_TRIGA_MANUAL_TRIG, OTG_TRIGA_MANUAL_TRIG, mask_sh),\ + SF(GSL_SOURCE_SELECT, GSL0_READY_SOURCE_SEL, mask_sh),\ + SF(GSL_SOURCE_SELECT, GSL1_READY_SOURCE_SEL, mask_sh),\ + SF(GSL_SOURCE_SELECT, GSL2_READY_SOURCE_SEL, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL2, MANUAL_FLOW_CONTROL_SEL, mask_sh),\ + SF(OTG0_OTG_DRR_CONTROL, OTG_V_TOTAL_LAST_USED_BY_DRR, mask_sh) + +#define OPTC_COMMON_MASK_SH_LIST_DCN3_0(mask_sh)\ + OPTC_COMMON_MASK_SH_LIST_DCN3_BASE(mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, mask_sh),\ + SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_START_X, mask_sh),\ + SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_END_X, mask_sh), \ + SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_START_Y, mask_sh),\ + SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_END_Y, mask_sh),\ + SF(OTG0_OTG_VUPDATE_KEEPOUT, OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, mask_sh), \ + SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET, mask_sh), \ + SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET, mask_sh), \ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_MASTER_MODE, mask_sh), \ + SF(OTG0_OTG_GSL_CONTROL, OTG_MASTER_UPDATE_LOCK_GSL_EN, mask_sh), \ + SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_X, mask_sh), \ + SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_LINE_NUM, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DSC_MODE, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_STREAM_COMBINE_MODE, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_STREAM_SPLIT_MODE, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_FORMAT, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG0_SRC_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG1_SRC_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_NUM_OF_INPUT_SEGMENT, mask_sh),\ + SF(ODM0_OPTC_MEMORY_CONFIG, OPTC_MEM_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_FORMAT_CONTROL, OPTC_DATA_FORMAT, mask_sh),\ + SF(ODM0_OPTC_DATA_FORMAT_CONTROL, OPTC_DSC_MODE, mask_sh),\ + SF(ODM0_OPTC_BYTES_PER_PIXEL, OPTC_DSC_BYTES_PER_PIXEL, mask_sh),\ + SF(ODM0_OPTC_WIDTH_CONTROL, OPTC_DSC_SLICE_WIDTH, mask_sh),\ + SF(ODM0_OPTC_WIDTH_CONTROL, OPTC_SEGMENT_WIDTH, mask_sh),\ + SF(DWB_SOURCE_SELECT, OPTC_DWB0_SOURCE_SELECT, mask_sh),\ + SF(DWB_SOURCE_SELECT, OPTC_DWB1_SOURCE_SELECT, mask_sh),\ + SF(OTG0_OTG_DRR_TRIGGER_WINDOW, OTG_DRR_TRIGGER_WINDOW_START_X, mask_sh),\ + 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) + +#define OPTC_COMMON_MASK_SH_LIST_DCN30(mask_sh)\ + OPTC_COMMON_MASK_SH_LIST_DCN3_BASE(mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, mask_sh),\ + SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_START_X, mask_sh),\ + SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_END_X, mask_sh), \ + SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_START_Y, mask_sh),\ + SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_END_Y, mask_sh),\ + SF(OTG0_OTG_VUPDATE_KEEPOUT, OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, mask_sh), \ + SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET, mask_sh), \ + SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET, mask_sh), \ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_MASTER_MODE, mask_sh), \ + SF(OTG0_OTG_GSL_CONTROL, OTG_MASTER_UPDATE_LOCK_GSL_EN, mask_sh), \ + SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_X, mask_sh), \ + SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_LINE_NUM, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DSC_MODE, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_STREAM_COMBINE_MODE, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_STREAM_SPLIT_MODE, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_FORMAT, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG0_SRC_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG1_SRC_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG2_SRC_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG3_SRC_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_NUM_OF_INPUT_SEGMENT, mask_sh),\ + SF(ODM0_OPTC_MEMORY_CONFIG, OPTC_MEM_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_FORMAT_CONTROL, OPTC_DATA_FORMAT, mask_sh),\ + SF(ODM0_OPTC_DATA_FORMAT_CONTROL, OPTC_DSC_MODE, mask_sh),\ + SF(ODM0_OPTC_BYTES_PER_PIXEL, OPTC_DSC_BYTES_PER_PIXEL, mask_sh),\ + SF(ODM0_OPTC_WIDTH_CONTROL, OPTC_DSC_SLICE_WIDTH, mask_sh),\ + SF(ODM0_OPTC_WIDTH_CONTROL, OPTC_SEGMENT_WIDTH, mask_sh),\ + SF(DWB_SOURCE_SELECT, OPTC_DWB0_SOURCE_SELECT, mask_sh),\ + SF(DWB_SOURCE_SELECT, OPTC_DWB1_SOURCE_SELECT, mask_sh),\ + SF(OTG0_OTG_DRR_TRIGGER_WINDOW, OTG_DRR_TRIGGER_WINDOW_START_X, mask_sh),\ + 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); + +void optc3_set_out_mux(struct timing_generator *optc, enum otg_out_mux_dest dest); + +void optc3_lock(struct timing_generator *optc); + +void optc3_lock_doublebuffer_enable(struct timing_generator *optc); + +void optc3_lock_doublebuffer_disable(struct timing_generator *optc); + +void optc3_set_drr_trigger_window(struct timing_generator *optc, + uint32_t window_start, uint32_t window_end); + +void optc3_triplebuffer_lock(struct timing_generator *optc); + +void optc3_program_blank_color(struct timing_generator *optc, + const struct tg_color *blank_color); + +void optc3_set_vtotal_change_limit(struct timing_generator *optc, + uint32_t limit); + +void optc3_set_dsc_config(struct timing_generator *optc, + enum optc_dsc_mode dsc_mode, + uint32_t dsc_bytes_per_pixel, + uint32_t dsc_slice_width); + +void optc3_set_timing_db_mode(struct timing_generator *optc, bool enable); + +void optc3_set_odm_bypass(struct timing_generator *optc, + const struct dc_crtc_timing *dc_crtc_timing); +void optc3_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, + struct dc_crtc_timing *timing); +void optc3_wait_drr_doublebuffer_pending_clear(struct timing_generator *optc); +void optc3_tg_init(struct timing_generator *optc); +void optc3_set_vtotal_min_max(struct timing_generator *optc, int vtotal_min, int vtotal_max); +#endif /* __DC_OPTC_DCN30_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn301/dcn301_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn301/dcn301_optc.c new file mode 100644 index 00000000000000..b3cfcb8879050a --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn301/dcn301_optc.c @@ -0,0 +1,185 @@ +/* + * Copyright 2020 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 "reg_helper.h" +#include "dcn301_optc.h" +#include "dc.h" +#include "dcn_calc_math.h" +#include "dc_dmub_srv.h" + +#include "dml/dcn30/dcn30_fpu.h" +#include "dc_trace.h" + +#define REG(reg)\ + optc1->tg_regs->reg + +#define CTX \ + optc1->base.ctx + +#undef FN +#define FN(reg_name, field_name) \ + optc1->tg_shift->field_name, optc1->tg_mask->field_name + + +/** + * optc301_set_drr() - Program dynamic refresh rate registers m_OTGx_OTG_V_TOTAL_*. + * + * @optc: timing_generator instance. + * @params: parameters used for Dynamic Refresh Rate. + */ +void optc301_set_drr( + struct timing_generator *optc, + const struct drr_params *params) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + if (params != NULL && + params->vertical_total_max > 0 && + params->vertical_total_min > 0) { + + if (params->vertical_total_mid != 0) { + + REG_SET(OTG_V_TOTAL_MID, 0, + OTG_V_TOTAL_MID, params->vertical_total_mid - 1); + + REG_UPDATE_2(OTG_V_TOTAL_CONTROL, + OTG_VTOTAL_MID_REPLACING_MAX_EN, 1, + OTG_VTOTAL_MID_FRAME_NUM, + (uint8_t)params->vertical_total_mid_frame_num); + + } + + optc->funcs->set_vtotal_min_max(optc, params->vertical_total_min - 1, params->vertical_total_max - 1); + + REG_UPDATE_5(OTG_V_TOTAL_CONTROL, + OTG_V_TOTAL_MIN_SEL, 1, + OTG_V_TOTAL_MAX_SEL, 1, + OTG_FORCE_LOCK_ON_EVENT, 0, + OTG_SET_V_TOTAL_MIN_MASK_EN, 0, + OTG_SET_V_TOTAL_MIN_MASK, 0); + // Setup manual flow control for EOF via TRIG_A + optc->funcs->setup_manual_trigger(optc); + + } else { + REG_UPDATE_4(OTG_V_TOTAL_CONTROL, + OTG_SET_V_TOTAL_MIN_MASK, 0, + OTG_V_TOTAL_MIN_SEL, 0, + OTG_V_TOTAL_MAX_SEL, 0, + OTG_FORCE_LOCK_ON_EVENT, 0); + + optc->funcs->set_vtotal_min_max(optc, 0, 0); + } +} + + +void optc301_setup_manual_trigger(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET_8(OTG_TRIGA_CNTL, 0, + OTG_TRIGA_SOURCE_SELECT, 21, + OTG_TRIGA_SOURCE_PIPE_SELECT, optc->inst, + OTG_TRIGA_RISING_EDGE_DETECT_CNTL, 1, + OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, 0, + OTG_TRIGA_POLARITY_SELECT, 0, + OTG_TRIGA_FREQUENCY_SELECT, 0, + OTG_TRIGA_DELAY, 0, + OTG_TRIGA_CLEAR, 1); +} + +static struct timing_generator_funcs dcn30_tg_funcs = { + .validate_timing = optc1_validate_timing, + .program_timing = optc1_program_timing, + .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0, + .setup_vertical_interrupt1 = optc1_setup_vertical_interrupt1, + .setup_vertical_interrupt2 = optc1_setup_vertical_interrupt2, + .program_global_sync = optc1_program_global_sync, + .enable_crtc = optc2_enable_crtc, + .disable_crtc = optc1_disable_crtc, + /* used by enable_timing_synchronization. Not need for FPGA */ + .is_counter_moving = optc1_is_counter_moving, + .get_position = optc1_get_position, + .get_frame_count = optc1_get_vblank_counter, + .get_scanoutpos = optc1_get_crtc_scanoutpos, + .get_otg_active_size = optc1_get_otg_active_size, + .set_early_control = optc1_set_early_control, + /* used by enable_timing_synchronization. Not need for FPGA */ + .wait_for_state = optc1_wait_for_state, + .set_blank_color = optc3_program_blank_color, + .did_triggered_reset_occur = optc1_did_triggered_reset_occur, + .triplebuffer_lock = optc3_triplebuffer_lock, + .triplebuffer_unlock = optc2_triplebuffer_unlock, + .enable_reset_trigger = optc1_enable_reset_trigger, + .enable_crtc_reset = optc1_enable_crtc_reset, + .disable_reset_trigger = optc1_disable_reset_trigger, + .lock = optc3_lock, + .unlock = optc1_unlock, + .lock_doublebuffer_enable = optc3_lock_doublebuffer_enable, + .lock_doublebuffer_disable = optc3_lock_doublebuffer_disable, + .enable_optc_clock = optc1_enable_optc_clock, + .set_drr = optc301_set_drr, + .get_last_used_drr_vtotal = optc2_get_last_used_drr_vtotal, + .set_vtotal_min_max = optc3_set_vtotal_min_max, + .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, + .is_tg_enabled = optc1_is_tg_enabled, + .is_optc_underflow_occurred = optc1_is_optc_underflow_occurred, + .clear_optc_underflow = optc1_clear_optc_underflow, + .setup_global_swap_lock = NULL, + .get_crc = optc1_get_crc, + .configure_crc = optc2_configure_crc, + .set_dsc_config = optc3_set_dsc_config, + .get_dsc_status = optc2_get_dsc_status, + .set_dwb_source = NULL, + .set_odm_bypass = optc3_set_odm_bypass, + .set_odm_combine = optc3_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, + .set_vtotal_change_limit = optc3_set_vtotal_change_limit, + .set_gsl = optc2_set_gsl, + .set_gsl_source_select = optc2_set_gsl_source_select, + .set_vtg_params = optc1_set_vtg_params, + .program_manual_trigger = optc2_program_manual_trigger, + .setup_manual_trigger = optc301_setup_manual_trigger, + .get_hw_timing = optc1_get_hw_timing, + .wait_drr_doublebuffer_pending_clear = optc3_wait_drr_doublebuffer_pending_clear, +}; + +void dcn301_timing_generator_init(struct optc *optc1) +{ + optc1->base.funcs = &dcn30_tg_funcs; + + optc1->max_h_total = optc1->tg_mask->OTG_H_TOTAL + 1; + optc1->max_v_total = optc1->tg_mask->OTG_V_TOTAL + 1; + + optc1->min_h_blank = 32; + optc1->min_v_blank = 3; + optc1->min_v_blank_interlace = 5; + optc1->min_h_sync_width = 4; + optc1->min_v_sync_width = 1; +} diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn301/dcn301_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn301/dcn301_optc.h new file mode 100644 index 00000000000000..b49585682a1599 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn301/dcn301_optc.h @@ -0,0 +1,36 @@ +/* + * Copyright 2020 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_OPTC_DCN301_H__ +#define __DC_OPTC_DCN301_H__ + +#include "dcn20/dcn20_optc.h" +#include "dcn30/dcn30_optc.h" + +void dcn301_timing_generator_init(struct optc *optc1); +void optc301_setup_manual_trigger(struct timing_generator *optc); +void optc301_set_drr(struct timing_generator *optc, const struct drr_params *params); + +#endif /* __DC_OPTC_DCN301_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c new file mode 100644 index 00000000000000..63a677c8ee2726 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c @@ -0,0 +1,310 @@ +/* + * 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 + * + */ + +#include "dcn31_optc.h" + +#include "dcn30/dcn30_optc.h" +#include "reg_helper.h" +#include "dc.h" +#include "dcn_calc_math.h" + +#define REG(reg)\ + optc1->tg_regs->reg + +#define CTX \ + optc1->base.ctx + +#undef FN +#define FN(reg_name, field_name) \ + optc1->tg_shift->field_name, optc1->tg_mask->field_name + +static void optc31_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, + struct dc_crtc_timing *timing) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + int mpcc_hactive = (timing->h_addressable + timing->h_border_left + timing->h_border_right) + / opp_cnt; + uint32_t memory_mask = 0; + int mem_count_per_opp = (mpcc_hactive + 2559) / 2560; + + /* Assume less than 6 pipes */ + if (opp_cnt == 4) { + if (mem_count_per_opp == 1) + memory_mask = 0xf; + else { + ASSERT(mem_count_per_opp == 2); + memory_mask = 0xff; + } + } else if (mem_count_per_opp == 1) + memory_mask = 0x1 << (opp_id[0] * 2) | 0x1 << (opp_id[1] * 2); + else if (mem_count_per_opp == 2) + memory_mask = 0x3 << (opp_id[0] * 2) | 0x3 << (opp_id[1] * 2); + else if (mem_count_per_opp == 3) + memory_mask = 0x77; + else if (mem_count_per_opp == 4) + memory_mask = 0xff; + + if (REG(OPTC_MEMORY_CONFIG)) + REG_SET(OPTC_MEMORY_CONFIG, 0, + OPTC_MEM_SEL, memory_mask); + + if (opp_cnt == 2) { + REG_SET_3(OPTC_DATA_SOURCE_SELECT, 0, + OPTC_NUM_OF_INPUT_SEGMENT, 1, + OPTC_SEG0_SRC_SEL, opp_id[0], + OPTC_SEG1_SRC_SEL, opp_id[1]); + } else if (opp_cnt == 4) { + REG_SET_5(OPTC_DATA_SOURCE_SELECT, 0, + OPTC_NUM_OF_INPUT_SEGMENT, 3, + OPTC_SEG0_SRC_SEL, opp_id[0], + OPTC_SEG1_SRC_SEL, opp_id[1], + OPTC_SEG2_SRC_SEL, opp_id[2], + OPTC_SEG3_SRC_SEL, opp_id[3]); + } + + REG_UPDATE(OPTC_WIDTH_CONTROL, + OPTC_SEGMENT_WIDTH, mpcc_hactive); + + REG_SET(OTG_H_TIMING_CNTL, 0, OTG_H_TIMING_DIV_MODE, opp_cnt - 1); + optc1->opp_count = opp_cnt; +} + +/* + * Enable CRTC - call ASIC Control Object to enable Timing generator. + */ +static bool optc31_enable_crtc(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + /* opp instance for OTG, 1 to 1 mapping and odm will adjust */ + REG_UPDATE(OPTC_DATA_SOURCE_SELECT, + OPTC_SEG0_SRC_SEL, optc->inst); + + /* VTG enable first is for HW workaround */ + REG_UPDATE(CONTROL, + VTG0_ENABLE, 1); + + REG_SEQ_START(); + + /* Enable CRTC */ + REG_UPDATE_2(OTG_CONTROL, + OTG_DISABLE_POINT_CNTL, 2, + OTG_MASTER_EN, 1); + + REG_SEQ_SUBMIT(); + REG_SEQ_WAIT_DONE(); + + return true; +} + +/* disable_crtc - call ASIC Control Object to disable Timing generator. */ +static bool optc31_disable_crtc(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + /* disable otg request until end of the first line + * in the vertical blank region + */ + REG_UPDATE(OTG_CONTROL, + OTG_MASTER_EN, 0); + + REG_UPDATE(CONTROL, + VTG0_ENABLE, 0); + + /* CRTC disabled, so disable clock. */ + REG_WAIT(OTG_CLOCK_CONTROL, + OTG_BUSY, 0, + 1, 100000); + optc1_clear_optc_underflow(optc); + + return true; +} + +bool optc31_immediate_disable_crtc(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_UPDATE_2(OTG_CONTROL, + OTG_DISABLE_POINT_CNTL, 0, + OTG_MASTER_EN, 0); + + REG_UPDATE(CONTROL, + VTG0_ENABLE, 0); + + /* CRTC disabled, so disable clock. */ + REG_WAIT(OTG_CLOCK_CONTROL, + OTG_BUSY, 0, + 1, 100000); + + /* clear the false state */ + optc1_clear_optc_underflow(optc); + + return true; +} + +void optc31_set_drr( + struct timing_generator *optc, + const struct drr_params *params) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + if (params != NULL && + params->vertical_total_max > 0 && + params->vertical_total_min > 0) { + + if (params->vertical_total_mid != 0) { + + REG_SET(OTG_V_TOTAL_MID, 0, + OTG_V_TOTAL_MID, params->vertical_total_mid - 1); + + REG_UPDATE_2(OTG_V_TOTAL_CONTROL, + OTG_VTOTAL_MID_REPLACING_MAX_EN, 1, + OTG_VTOTAL_MID_FRAME_NUM, + (uint8_t)params->vertical_total_mid_frame_num); + + } + + optc->funcs->set_vtotal_min_max(optc, params->vertical_total_min - 1, params->vertical_total_max - 1); + + /* + * MIN_MASK_EN is gone and MASK is now always enabled. + * + * To get it to it work with manual trigger we need to make sure + * we program the correct bit. + */ + REG_UPDATE_4(OTG_V_TOTAL_CONTROL, + OTG_V_TOTAL_MIN_SEL, 1, + OTG_V_TOTAL_MAX_SEL, 1, + OTG_FORCE_LOCK_ON_EVENT, 0, + OTG_SET_V_TOTAL_MIN_MASK, (1 << 1)); /* TRIGA */ + + // Setup manual flow control for EOF via TRIG_A + optc->funcs->setup_manual_trigger(optc); + } else { + REG_UPDATE_4(OTG_V_TOTAL_CONTROL, + OTG_SET_V_TOTAL_MIN_MASK, 0, + OTG_V_TOTAL_MIN_SEL, 0, + OTG_V_TOTAL_MAX_SEL, 0, + OTG_FORCE_LOCK_ON_EVENT, 0); + + optc->funcs->set_vtotal_min_max(optc, 0, 0); + } +} + +void optc3_init_odm(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET_5(OPTC_DATA_SOURCE_SELECT, 0, + OPTC_NUM_OF_INPUT_SEGMENT, 0, + OPTC_SEG0_SRC_SEL, optc->inst, + OPTC_SEG1_SRC_SEL, 0xf, + OPTC_SEG2_SRC_SEL, 0xf, + OPTC_SEG3_SRC_SEL, 0xf + ); + + REG_SET(OTG_H_TIMING_CNTL, 0, + OTG_H_TIMING_DIV_MODE, 0); + + REG_SET(OPTC_MEMORY_CONFIG, 0, + OPTC_MEM_SEL, 0); + optc1->opp_count = 1; +} + +static struct timing_generator_funcs dcn31_tg_funcs = { + .validate_timing = optc1_validate_timing, + .program_timing = optc1_program_timing, + .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0, + .setup_vertical_interrupt1 = optc1_setup_vertical_interrupt1, + .setup_vertical_interrupt2 = optc1_setup_vertical_interrupt2, + .program_global_sync = optc1_program_global_sync, + .enable_crtc = optc31_enable_crtc, + .disable_crtc = optc31_disable_crtc, + .immediate_disable_crtc = optc31_immediate_disable_crtc, + /* used by enable_timing_synchronization. Not need for FPGA */ + .is_counter_moving = optc1_is_counter_moving, + .get_position = optc1_get_position, + .get_frame_count = optc1_get_vblank_counter, + .get_scanoutpos = optc1_get_crtc_scanoutpos, + .get_otg_active_size = optc1_get_otg_active_size, + .set_early_control = optc1_set_early_control, + /* used by enable_timing_synchronization. Not need for FPGA */ + .wait_for_state = optc1_wait_for_state, + .set_blank_color = optc3_program_blank_color, + .did_triggered_reset_occur = optc1_did_triggered_reset_occur, + .triplebuffer_lock = optc3_triplebuffer_lock, + .triplebuffer_unlock = optc2_triplebuffer_unlock, + .enable_reset_trigger = optc1_enable_reset_trigger, + .enable_crtc_reset = optc1_enable_crtc_reset, + .disable_reset_trigger = optc1_disable_reset_trigger, + .lock = optc3_lock, + .unlock = optc1_unlock, + .lock_doublebuffer_enable = optc3_lock_doublebuffer_enable, + .lock_doublebuffer_disable = optc3_lock_doublebuffer_disable, + .enable_optc_clock = optc1_enable_optc_clock, + .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 = optc1_set_static_screen_control, + .program_stereo = optc1_program_stereo, + .is_stereo_left_eye = optc1_is_stereo_left_eye, + .tg_init = optc3_tg_init, + .is_tg_enabled = optc1_is_tg_enabled, + .is_optc_underflow_occurred = optc1_is_optc_underflow_occurred, + .clear_optc_underflow = optc1_clear_optc_underflow, + .setup_global_swap_lock = NULL, + .get_crc = optc1_get_crc, + .configure_crc = optc2_configure_crc, + .set_dsc_config = optc3_set_dsc_config, + .get_dsc_status = optc2_get_dsc_status, + .set_dwb_source = NULL, + .set_odm_bypass = optc3_set_odm_bypass, + .set_odm_combine = optc31_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, + .set_vtotal_change_limit = optc3_set_vtotal_change_limit, + .set_gsl = optc2_set_gsl, + .set_gsl_source_select = optc2_set_gsl_source_select, + .set_vtg_params = optc1_set_vtg_params, + .program_manual_trigger = optc2_program_manual_trigger, + .setup_manual_trigger = optc2_setup_manual_trigger, + .get_hw_timing = optc1_get_hw_timing, + .init_odm = optc3_init_odm, +}; + +void dcn31_timing_generator_init(struct optc *optc1) +{ + optc1->base.funcs = &dcn31_tg_funcs; + + optc1->max_h_total = optc1->tg_mask->OTG_H_TOTAL + 1; + optc1->max_v_total = optc1->tg_mask->OTG_V_TOTAL + 1; + + optc1->min_h_blank = 32; + optc1->min_v_blank = 3; + optc1->min_v_blank_interlace = 5; + optc1->min_h_sync_width = 4; + optc1->min_v_sync_width = 1; +} + diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.h new file mode 100644 index 00000000000000..30b81a448ce2d1 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.h @@ -0,0 +1,267 @@ +/* + * 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 __DC_OPTC_DCN31_H__ +#define __DC_OPTC_DCN31_H__ + +#include "dcn10/dcn10_optc.h" + +#define OPTC_COMMON_REG_LIST_DCN3_1(inst) \ + SRI(OTG_VSTARTUP_PARAM, OTG, inst),\ + SRI(OTG_VUPDATE_PARAM, OTG, inst),\ + SRI(OTG_VREADY_PARAM, OTG, inst),\ + SRI(OTG_MASTER_UPDATE_LOCK, OTG, inst),\ + SRI(OTG_GLOBAL_CONTROL0, OTG, inst),\ + SRI(OTG_GLOBAL_CONTROL1, OTG, inst),\ + SRI(OTG_GLOBAL_CONTROL2, OTG, inst),\ + SRI(OTG_GLOBAL_CONTROL4, OTG, inst),\ + SRI(OTG_DOUBLE_BUFFER_CONTROL, OTG, inst),\ + SRI(OTG_H_TOTAL, OTG, inst),\ + SRI(OTG_H_BLANK_START_END, OTG, inst),\ + SRI(OTG_H_SYNC_A, OTG, inst),\ + SRI(OTG_H_SYNC_A_CNTL, OTG, inst),\ + SRI(OTG_H_TIMING_CNTL, OTG, inst),\ + SRI(OTG_V_TOTAL, OTG, inst),\ + SRI(OTG_V_BLANK_START_END, OTG, inst),\ + SRI(OTG_V_SYNC_A, OTG, inst),\ + SRI(OTG_V_SYNC_A_CNTL, OTG, inst),\ + SRI(OTG_CONTROL, OTG, inst),\ + SRI(OTG_STEREO_CONTROL, OTG, inst),\ + SRI(OTG_3D_STRUCTURE_CONTROL, OTG, inst),\ + SRI(OTG_STEREO_STATUS, OTG, inst),\ + SRI(OTG_V_TOTAL_MAX, OTG, inst),\ + SRI(OTG_V_TOTAL_MIN, OTG, inst),\ + SRI(OTG_V_TOTAL_CONTROL, OTG, inst),\ + SRI(OTG_TRIGA_CNTL, OTG, inst),\ + SRI(OTG_FORCE_COUNT_NOW_CNTL, OTG, inst),\ + SRI(OTG_STATIC_SCREEN_CONTROL, OTG, inst),\ + SRI(OTG_STATUS_FRAME_COUNT, OTG, inst),\ + SRI(OTG_STATUS, OTG, inst),\ + SRI(OTG_STATUS_POSITION, OTG, inst),\ + SRI(OTG_NOM_VERT_POSITION, OTG, inst),\ + SRI(OTG_M_CONST_DTO0, OTG, inst),\ + SRI(OTG_M_CONST_DTO1, OTG, inst),\ + SRI(OTG_CLOCK_CONTROL, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT0_CONTROL, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT0_POSITION, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT1_CONTROL, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT1_POSITION, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT2_CONTROL, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT2_POSITION, OTG, inst),\ + SRI(OPTC_INPUT_CLOCK_CONTROL, ODM, inst),\ + SRI(OPTC_DATA_SOURCE_SELECT, ODM, inst),\ + SRI(OPTC_INPUT_GLOBAL_CONTROL, ODM, inst),\ + SRI(CONTROL, VTG, inst),\ + SRI(OTG_VERT_SYNC_CONTROL, OTG, inst),\ + SRI(OTG_GSL_CONTROL, OTG, inst),\ + SRI(OTG_CRC_CNTL, OTG, inst),\ + SRI(OTG_CRC0_DATA_RG, OTG, inst),\ + SRI(OTG_CRC0_DATA_B, OTG, inst),\ + SRI(OTG_CRC0_WINDOWA_X_CONTROL, OTG, inst),\ + SRI(OTG_CRC0_WINDOWA_Y_CONTROL, OTG, inst),\ + SRI(OTG_CRC0_WINDOWB_X_CONTROL, OTG, inst),\ + SRI(OTG_CRC0_WINDOWB_Y_CONTROL, OTG, inst),\ + SR(GSL_SOURCE_SELECT),\ + SRI(OTG_TRIGA_MANUAL_TRIG, OTG, inst),\ + SRI(OTG_GLOBAL_CONTROL1, OTG, inst),\ + SRI(OTG_GLOBAL_CONTROL2, OTG, inst),\ + SRI(OTG_GSL_WINDOW_X, OTG, inst),\ + SRI(OTG_GSL_WINDOW_Y, OTG, inst),\ + SRI(OTG_VUPDATE_KEEPOUT, OTG, inst),\ + SRI(OTG_DSC_START_POSITION, OTG, inst),\ + SRI(OTG_DRR_TRIGGER_WINDOW, OTG, inst),\ + SRI(OTG_DRR_V_TOTAL_CHANGE, OTG, inst),\ + SRI(OPTC_DATA_FORMAT_CONTROL, ODM, inst),\ + SRI(OPTC_BYTES_PER_PIXEL, ODM, inst),\ + SRI(OPTC_WIDTH_CONTROL, ODM, inst),\ + SRI(OPTC_MEMORY_CONFIG, ODM, inst),\ + SRI(OTG_CRC_CNTL2, OTG, inst),\ + SR(DWB_SOURCE_SELECT),\ + SRI(OTG_DRR_CONTROL, OTG, inst) + +#define OPTC_COMMON_MASK_SH_LIST_DCN3_1(mask_sh)\ + SF(OTG0_OTG_VSTARTUP_PARAM, VSTARTUP_START, mask_sh),\ + SF(OTG0_OTG_VUPDATE_PARAM, VUPDATE_OFFSET, mask_sh),\ + SF(OTG0_OTG_VUPDATE_PARAM, VUPDATE_WIDTH, mask_sh),\ + SF(OTG0_OTG_VREADY_PARAM, VREADY_OFFSET, mask_sh),\ + SF(OTG0_OTG_MASTER_UPDATE_LOCK, OTG_MASTER_UPDATE_LOCK, mask_sh),\ + SF(OTG0_OTG_MASTER_UPDATE_LOCK, UPDATE_LOCK_STATUS, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL0, MASTER_UPDATE_LOCK_DB_START_X, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL0, MASTER_UPDATE_LOCK_DB_END_X, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL0, MASTER_UPDATE_LOCK_DB_EN, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_START_Y, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_END_Y, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL2, OTG_MASTER_UPDATE_LOCK_SEL, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL4, DIG_UPDATE_POSITION_X, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL4, DIG_UPDATE_POSITION_Y, mask_sh),\ + SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_UPDATE_PENDING, mask_sh),\ + SF(OTG0_OTG_H_TOTAL, OTG_H_TOTAL, mask_sh),\ + SF(OTG0_OTG_H_BLANK_START_END, OTG_H_BLANK_START, mask_sh),\ + SF(OTG0_OTG_H_BLANK_START_END, OTG_H_BLANK_END, mask_sh),\ + SF(OTG0_OTG_H_SYNC_A, OTG_H_SYNC_A_START, mask_sh),\ + SF(OTG0_OTG_H_SYNC_A, OTG_H_SYNC_A_END, mask_sh),\ + SF(OTG0_OTG_H_SYNC_A_CNTL, OTG_H_SYNC_A_POL, mask_sh),\ + SF(OTG0_OTG_V_TOTAL, OTG_V_TOTAL, mask_sh),\ + SF(OTG0_OTG_V_BLANK_START_END, OTG_V_BLANK_START, mask_sh),\ + SF(OTG0_OTG_V_BLANK_START_END, OTG_V_BLANK_END, mask_sh),\ + SF(OTG0_OTG_V_SYNC_A, OTG_V_SYNC_A_START, mask_sh),\ + SF(OTG0_OTG_V_SYNC_A, OTG_V_SYNC_A_END, mask_sh),\ + SF(OTG0_OTG_V_SYNC_A_CNTL, OTG_V_SYNC_A_POL, mask_sh),\ + SF(OTG0_OTG_V_SYNC_A_CNTL, OTG_V_SYNC_MODE, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_MASTER_EN, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_START_POINT_CNTL, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_DISABLE_POINT_CNTL, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_FIELD_NUMBER_CNTL, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_OUT_MUX, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_EN, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_SYNC_OUTPUT_LINE_NUM, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_SYNC_OUTPUT_POLARITY, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_EYE_FLAG_POLARITY, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_DISABLE_STEREOSYNC_OUTPUT_FOR_DP, mask_sh),\ + SF(OTG0_OTG_STEREO_STATUS, OTG_STEREO_CURRENT_EYE, mask_sh),\ + SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_EN, mask_sh),\ + SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_V_UPDATE_MODE, mask_sh),\ + SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_STEREO_SEL_OVR, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_MAX, OTG_V_TOTAL_MAX, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_MIN, OTG_V_TOTAL_MIN, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_V_TOTAL_MIN_SEL, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_V_TOTAL_MAX_SEL, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_FORCE_LOCK_ON_EVENT, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_SET_V_TOTAL_MIN_MASK, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_VTOTAL_MID_REPLACING_MIN_EN, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_VTOTAL_MID_REPLACING_MAX_EN, mask_sh),\ + SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_CLEAR, mask_sh),\ + SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_MODE, mask_sh),\ + SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_OCCURRED, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_SOURCE_SELECT, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_SOURCE_PIPE_SELECT, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_RISING_EDGE_DETECT_CNTL, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_POLARITY_SELECT, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_FREQUENCY_SELECT, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_DELAY, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_CLEAR, mask_sh),\ + SF(OTG0_OTG_STATIC_SCREEN_CONTROL, OTG_STATIC_SCREEN_EVENT_MASK, mask_sh),\ + SF(OTG0_OTG_STATIC_SCREEN_CONTROL, OTG_STATIC_SCREEN_FRAME_COUNT, mask_sh),\ + SF(OTG0_OTG_STATUS_FRAME_COUNT, OTG_FRAME_COUNT, mask_sh),\ + SF(OTG0_OTG_STATUS, OTG_V_BLANK, mask_sh),\ + SF(OTG0_OTG_STATUS, OTG_V_ACTIVE_DISP, mask_sh),\ + SF(OTG0_OTG_STATUS_POSITION, OTG_HORZ_COUNT, mask_sh),\ + SF(OTG0_OTG_STATUS_POSITION, OTG_VERT_COUNT, mask_sh),\ + SF(OTG0_OTG_NOM_VERT_POSITION, OTG_VERT_COUNT_NOM, mask_sh),\ + SF(OTG0_OTG_M_CONST_DTO0, OTG_M_CONST_DTO_PHASE, mask_sh),\ + SF(OTG0_OTG_M_CONST_DTO1, OTG_M_CONST_DTO_MODULO, mask_sh),\ + SF(OTG0_OTG_CLOCK_CONTROL, OTG_BUSY, mask_sh),\ + SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_EN, mask_sh),\ + SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_ON, mask_sh),\ + SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_GATE_DIS, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_INT_ENABLE, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT0_POSITION, OTG_VERTICAL_INTERRUPT0_LINE_START, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT0_POSITION, OTG_VERTICAL_INTERRUPT0_LINE_END, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT1_CONTROL, OTG_VERTICAL_INTERRUPT1_INT_ENABLE, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT1_POSITION, OTG_VERTICAL_INTERRUPT1_LINE_START, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT2_POSITION, OTG_VERTICAL_INTERRUPT2_LINE_START, mask_sh),\ + SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_EN, mask_sh),\ + SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_ON, mask_sh),\ + SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_GATE_DIS, mask_sh),\ + SF(ODM0_OPTC_INPUT_GLOBAL_CONTROL, OPTC_UNDERFLOW_OCCURRED_STATUS, mask_sh),\ + SF(ODM0_OPTC_INPUT_GLOBAL_CONTROL, OPTC_UNDERFLOW_CLEAR, mask_sh),\ + SF(VTG0_CONTROL, VTG0_ENABLE, mask_sh),\ + SF(VTG0_CONTROL, VTG0_FP2, mask_sh),\ + SF(VTG0_CONTROL, VTG0_VCOUNT_INIT, mask_sh),\ + SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_FORCE_VSYNC_NEXT_LINE_OCCURRED, mask_sh),\ + SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_FORCE_VSYNC_NEXT_LINE_CLEAR, mask_sh),\ + SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_AUTO_FORCE_VSYNC_MODE, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL0_EN, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL1_EN, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL2_EN, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_MASTER_EN, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_FORCE_DELAY, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_CHECK_ALL_FIELDS, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL, OTG_CRC_CONT_EN, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL, OTG_CRC0_SELECT, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL, OTG_CRC_EN, mask_sh),\ + SF(OTG0_OTG_CRC0_DATA_RG, CRC0_R_CR, mask_sh),\ + SF(OTG0_OTG_CRC0_DATA_RG, CRC0_G_Y, mask_sh),\ + SF(OTG0_OTG_CRC0_DATA_B, CRC0_B_CB, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWA_X_CONTROL, OTG_CRC0_WINDOWA_X_START, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWA_X_CONTROL, OTG_CRC0_WINDOWA_X_END, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWA_Y_CONTROL, OTG_CRC0_WINDOWA_Y_START, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWA_Y_CONTROL, OTG_CRC0_WINDOWA_Y_END, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWB_X_CONTROL, OTG_CRC0_WINDOWB_X_START, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWB_X_CONTROL, OTG_CRC0_WINDOWB_X_END, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL, OTG_CRC0_WINDOWB_Y_START, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL, OTG_CRC0_WINDOWB_Y_END, mask_sh),\ + SF(OTG0_OTG_TRIGA_MANUAL_TRIG, OTG_TRIGA_MANUAL_TRIG, mask_sh),\ + SF(GSL_SOURCE_SELECT, GSL0_READY_SOURCE_SEL, mask_sh),\ + SF(GSL_SOURCE_SELECT, GSL1_READY_SOURCE_SEL, mask_sh),\ + SF(GSL_SOURCE_SELECT, GSL2_READY_SOURCE_SEL, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL2, MANUAL_FLOW_CONTROL_SEL, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, mask_sh),\ + SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_START_X, mask_sh),\ + SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_END_X, mask_sh), \ + SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_START_Y, mask_sh),\ + SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_END_Y, mask_sh),\ + SF(OTG0_OTG_VUPDATE_KEEPOUT, OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, mask_sh), \ + SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET, mask_sh), \ + SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET, mask_sh), \ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_MASTER_MODE, mask_sh), \ + SF(OTG0_OTG_GSL_CONTROL, OTG_MASTER_UPDATE_LOCK_GSL_EN, mask_sh), \ + SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_X, mask_sh), \ + SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_LINE_NUM, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG0_SRC_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG1_SRC_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG2_SRC_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG3_SRC_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_NUM_OF_INPUT_SEGMENT, mask_sh),\ + SF(ODM0_OPTC_MEMORY_CONFIG, OPTC_MEM_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_FORMAT_CONTROL, OPTC_DATA_FORMAT, mask_sh),\ + SF(ODM0_OPTC_DATA_FORMAT_CONTROL, OPTC_DSC_MODE, mask_sh),\ + SF(ODM0_OPTC_BYTES_PER_PIXEL, OPTC_DSC_BYTES_PER_PIXEL, mask_sh),\ + SF(ODM0_OPTC_WIDTH_CONTROL, OPTC_DSC_SLICE_WIDTH, mask_sh),\ + SF(ODM0_OPTC_WIDTH_CONTROL, OPTC_SEGMENT_WIDTH, mask_sh),\ + SF(DWB_SOURCE_SELECT, OPTC_DWB0_SOURCE_SELECT, mask_sh),\ + SF(DWB_SOURCE_SELECT, OPTC_DWB1_SOURCE_SELECT, mask_sh),\ + SF(OTG0_OTG_DRR_TRIGGER_WINDOW, OTG_DRR_TRIGGER_WINDOW_START_X, mask_sh),\ + 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_MODE, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DSC_MODE, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_STREAM_COMBINE_MODE, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_STREAM_SPLIT_MODE, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL2, OTG_CRC_DATA_FORMAT, mask_sh),\ + SF(OTG0_OTG_DRR_CONTROL, OTG_V_TOTAL_LAST_USED_BY_DRR, mask_sh) + +void dcn31_timing_generator_init(struct optc *optc1); + +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); + +#endif /* __DC_OPTC_DCN31_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c new file mode 100644 index 00000000000000..0086cafb0f7a82 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c @@ -0,0 +1,273 @@ +// SPDX-License-Identifier: MIT +/* + * 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 "dcn314_optc.h" + +#include "dcn30/dcn30_optc.h" +#include "dcn31/dcn31_optc.h" +#include "reg_helper.h" +#include "dc.h" +#include "dcn_calc_math.h" + +#define REG(reg)\ + optc1->tg_regs->reg + +#define CTX \ + optc1->base.ctx + +#undef FN +#define FN(reg_name, field_name) \ + optc1->tg_shift->field_name, optc1->tg_mask->field_name + +/* + * Enable CRTC + * Enable CRTC - call ASIC Control Object to enable Timing generator. + */ + +static void optc314_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, + struct dc_crtc_timing *timing) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + uint32_t memory_mask = 0; + int h_active = timing->h_addressable + timing->h_border_left + timing->h_border_right; + int mpcc_hactive = h_active / opp_cnt; + /* Each memory instance is 2048x(314x2) bits to support half line of 4096 */ + int odm_mem_count = (h_active + 2047) / 2048; + + /* + * display <= 4k : 2 memories + 2 pipes + * 4k < display <= 8k : 4 memories + 2 pipes + * 8k < display <= 12k : 6 memories + 4 pipes + */ + if (opp_cnt == 4) { + if (odm_mem_count <= 2) + memory_mask = 0x3; + else if (odm_mem_count <= 4) + memory_mask = 0xf; + else + memory_mask = 0x3f; + } else { + if (odm_mem_count <= 2) + memory_mask = 0x1 << (opp_id[0] * 2) | 0x1 << (opp_id[1] * 2); + else if (odm_mem_count <= 4) + memory_mask = 0x3 << (opp_id[0] * 2) | 0x3 << (opp_id[1] * 2); + else + memory_mask = 0x77; + } + + REG_SET(OPTC_MEMORY_CONFIG, 0, + OPTC_MEM_SEL, memory_mask); + + if (opp_cnt == 2) { + REG_SET_3(OPTC_DATA_SOURCE_SELECT, 0, + OPTC_NUM_OF_INPUT_SEGMENT, 1, + OPTC_SEG0_SRC_SEL, opp_id[0], + OPTC_SEG1_SRC_SEL, opp_id[1]); + } else if (opp_cnt == 4) { + REG_SET_5(OPTC_DATA_SOURCE_SELECT, 0, + OPTC_NUM_OF_INPUT_SEGMENT, 3, + OPTC_SEG0_SRC_SEL, opp_id[0], + OPTC_SEG1_SRC_SEL, opp_id[1], + OPTC_SEG2_SRC_SEL, opp_id[2], + OPTC_SEG3_SRC_SEL, opp_id[3]); + } + + REG_UPDATE(OPTC_WIDTH_CONTROL, + OPTC_SEGMENT_WIDTH, mpcc_hactive); + + REG_UPDATE(OTG_H_TIMING_CNTL, + OTG_H_TIMING_DIV_MODE, opp_cnt - 1); + optc1->opp_count = opp_cnt; +} + +static bool optc314_enable_crtc(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + /* opp instance for OTG, 1 to 1 mapping and odm will adjust */ + REG_UPDATE(OPTC_DATA_SOURCE_SELECT, + OPTC_SEG0_SRC_SEL, optc->inst); + + /* VTG enable first is for HW workaround */ + REG_UPDATE(CONTROL, + VTG0_ENABLE, 1); + + REG_SEQ_START(); + + /* Enable CRTC */ + REG_UPDATE_2(OTG_CONTROL, + OTG_DISABLE_POINT_CNTL, 2, + OTG_MASTER_EN, 1); + + REG_SEQ_SUBMIT(); + REG_SEQ_WAIT_DONE(); + + return true; +} + +/* disable_crtc */ +static bool optc314_disable_crtc(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + /* disable otg request until end of the first line + * in the vertical blank region + */ + REG_UPDATE(OTG_CONTROL, + OTG_MASTER_EN, 0); + + REG_UPDATE(CONTROL, + VTG0_ENABLE, 0); + + /* CRTC disabled, so disable clock. */ + REG_WAIT(OTG_CLOCK_CONTROL, + OTG_BUSY, 0, + 1, 100000); + + return true; +} + +static void optc314_phantom_crtc_post_enable(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + /* Disable immediately. */ + REG_UPDATE_2(OTG_CONTROL, OTG_DISABLE_POINT_CNTL, 0, OTG_MASTER_EN, 0); + + /* CRTC disabled, so disable clock. */ + REG_WAIT(OTG_CLOCK_CONTROL, OTG_BUSY, 0, 1, 100000); +} + +static void optc314_set_odm_bypass(struct timing_generator *optc, + const struct dc_crtc_timing *dc_crtc_timing) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + enum h_timing_div_mode h_div = H_TIMING_NO_DIV; + + REG_SET_5(OPTC_DATA_SOURCE_SELECT, 0, + OPTC_NUM_OF_INPUT_SEGMENT, 0, + OPTC_SEG0_SRC_SEL, optc->inst, + OPTC_SEG1_SRC_SEL, 0xf, + OPTC_SEG2_SRC_SEL, 0xf, + OPTC_SEG3_SRC_SEL, 0xf + ); + + h_div = optc1_is_two_pixels_per_containter(dc_crtc_timing); + REG_UPDATE(OTG_H_TIMING_CNTL, + OTG_H_TIMING_DIV_MODE, h_div); + + REG_SET(OPTC_MEMORY_CONFIG, 0, + OPTC_MEM_SEL, 0); + optc1->opp_count = 1; +} + +static void optc314_set_h_timing_div_manual_mode(struct timing_generator *optc, bool manual_mode) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_UPDATE(OTG_H_TIMING_CNTL, + OTG_H_TIMING_DIV_MODE_MANUAL, manual_mode ? 1 : 0); +} + + +static struct timing_generator_funcs dcn314_tg_funcs = { + .validate_timing = optc1_validate_timing, + .program_timing = optc1_program_timing, + .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0, + .setup_vertical_interrupt1 = optc1_setup_vertical_interrupt1, + .setup_vertical_interrupt2 = optc1_setup_vertical_interrupt2, + .program_global_sync = optc1_program_global_sync, + .enable_crtc = optc314_enable_crtc, + .disable_crtc = optc314_disable_crtc, + .immediate_disable_crtc = optc31_immediate_disable_crtc, + .phantom_crtc_post_enable = optc314_phantom_crtc_post_enable, + /* used by enable_timing_synchronization. Not need for FPGA */ + .is_counter_moving = optc1_is_counter_moving, + .get_position = optc1_get_position, + .get_frame_count = optc1_get_vblank_counter, + .get_scanoutpos = optc1_get_crtc_scanoutpos, + .get_otg_active_size = optc1_get_otg_active_size, + .set_early_control = optc1_set_early_control, + /* used by enable_timing_synchronization. Not need for FPGA */ + .wait_for_state = optc1_wait_for_state, + .set_blank_color = optc3_program_blank_color, + .did_triggered_reset_occur = optc1_did_triggered_reset_occur, + .triplebuffer_lock = optc3_triplebuffer_lock, + .triplebuffer_unlock = optc2_triplebuffer_unlock, + .enable_reset_trigger = optc1_enable_reset_trigger, + .enable_crtc_reset = optc1_enable_crtc_reset, + .disable_reset_trigger = optc1_disable_reset_trigger, + .lock = optc3_lock, + .unlock = optc1_unlock, + .lock_doublebuffer_enable = optc3_lock_doublebuffer_enable, + .lock_doublebuffer_disable = optc3_lock_doublebuffer_disable, + .enable_optc_clock = optc1_enable_optc_clock, + .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 = optc1_set_static_screen_control, + .program_stereo = optc1_program_stereo, + .is_stereo_left_eye = optc1_is_stereo_left_eye, + .tg_init = optc3_tg_init, + .is_tg_enabled = optc1_is_tg_enabled, + .is_optc_underflow_occurred = optc1_is_optc_underflow_occurred, + .clear_optc_underflow = optc1_clear_optc_underflow, + .setup_global_swap_lock = NULL, + .get_crc = optc1_get_crc, + .configure_crc = optc1_configure_crc, + .set_dsc_config = optc3_set_dsc_config, + .get_dsc_status = optc2_get_dsc_status, + .set_dwb_source = NULL, + .get_optc_source = optc2_get_optc_source, + .set_out_mux = optc3_set_out_mux, + .set_drr_trigger_window = optc3_set_drr_trigger_window, + .set_vtotal_change_limit = optc3_set_vtotal_change_limit, + .set_gsl = optc2_set_gsl, + .set_gsl_source_select = optc2_set_gsl_source_select, + .set_vtg_params = optc1_set_vtg_params, + .program_manual_trigger = optc2_program_manual_trigger, + .setup_manual_trigger = optc2_setup_manual_trigger, + .get_hw_timing = optc1_get_hw_timing, + .init_odm = optc3_init_odm, + .set_odm_bypass = optc314_set_odm_bypass, + .set_odm_combine = optc314_set_odm_combine, + .set_h_timing_div_manual_mode = optc314_set_h_timing_div_manual_mode, +}; + +void dcn314_timing_generator_init(struct optc *optc1) +{ + optc1->base.funcs = &dcn314_tg_funcs; + + optc1->max_h_total = optc1->tg_mask->OTG_H_TOTAL + 1; + optc1->max_v_total = optc1->tg_mask->OTG_V_TOTAL + 1; + + optc1->min_h_blank = 32; + optc1->min_v_blank = 3; + optc1->min_v_blank_interlace = 5; + optc1->min_h_sync_width = 4; + optc1->min_v_sync_width = 1; +} + diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.h new file mode 100644 index 00000000000000..99c098e76116fc --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.h @@ -0,0 +1,255 @@ +/* SPDX-License-Identifier: MIT */ +/* + * 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_OPTC_DCN314_H__ +#define __DC_OPTC_DCN314_H__ + +#include "dcn10/dcn10_optc.h" + +#define OPTC_COMMON_REG_LIST_DCN3_14(inst) \ + SRI(OTG_VSTARTUP_PARAM, OTG, inst),\ + SRI(OTG_VUPDATE_PARAM, OTG, inst),\ + SRI(OTG_VREADY_PARAM, OTG, inst),\ + SRI(OTG_MASTER_UPDATE_LOCK, OTG, inst),\ + SRI(OTG_GLOBAL_CONTROL0, OTG, inst),\ + SRI(OTG_GLOBAL_CONTROL1, OTG, inst),\ + SRI(OTG_GLOBAL_CONTROL2, OTG, inst),\ + SRI(OTG_GLOBAL_CONTROL4, OTG, inst),\ + SRI(OTG_DOUBLE_BUFFER_CONTROL, OTG, inst),\ + SRI(OTG_H_TOTAL, OTG, inst),\ + SRI(OTG_H_BLANK_START_END, OTG, inst),\ + SRI(OTG_H_SYNC_A, OTG, inst),\ + SRI(OTG_H_SYNC_A_CNTL, OTG, inst),\ + SRI(OTG_H_TIMING_CNTL, OTG, inst),\ + SRI(OTG_V_TOTAL, OTG, inst),\ + SRI(OTG_V_BLANK_START_END, OTG, inst),\ + SRI(OTG_V_SYNC_A, OTG, inst),\ + SRI(OTG_V_SYNC_A_CNTL, OTG, inst),\ + SRI(OTG_CONTROL, OTG, inst),\ + SRI(OTG_STEREO_CONTROL, OTG, inst),\ + SRI(OTG_3D_STRUCTURE_CONTROL, OTG, inst),\ + SRI(OTG_STEREO_STATUS, OTG, inst),\ + SRI(OTG_V_TOTAL_MAX, OTG, inst),\ + SRI(OTG_V_TOTAL_MIN, OTG, inst),\ + SRI(OTG_V_TOTAL_CONTROL, OTG, inst),\ + SRI(OTG_TRIGA_CNTL, OTG, inst),\ + SRI(OTG_FORCE_COUNT_NOW_CNTL, OTG, inst),\ + SRI(OTG_STATIC_SCREEN_CONTROL, OTG, inst),\ + SRI(OTG_STATUS_FRAME_COUNT, OTG, inst),\ + SRI(OTG_STATUS, OTG, inst),\ + SRI(OTG_STATUS_POSITION, OTG, inst),\ + SRI(OTG_NOM_VERT_POSITION, OTG, inst),\ + SRI(OTG_M_CONST_DTO0, OTG, inst),\ + SRI(OTG_M_CONST_DTO1, OTG, inst),\ + SRI(OTG_CLOCK_CONTROL, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT0_CONTROL, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT0_POSITION, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT1_CONTROL, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT1_POSITION, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT2_CONTROL, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT2_POSITION, OTG, inst),\ + SRI(OPTC_INPUT_CLOCK_CONTROL, ODM, inst),\ + SRI(OPTC_DATA_SOURCE_SELECT, ODM, inst),\ + SRI(OPTC_INPUT_GLOBAL_CONTROL, ODM, inst),\ + SRI(CONTROL, VTG, inst),\ + SRI(OTG_VERT_SYNC_CONTROL, OTG, inst),\ + SRI(OTG_GSL_CONTROL, OTG, inst),\ + SRI(OTG_CRC_CNTL, OTG, inst),\ + SRI(OTG_CRC0_DATA_RG, OTG, inst),\ + SRI(OTG_CRC0_DATA_B, OTG, inst),\ + SRI(OTG_CRC0_WINDOWA_X_CONTROL, OTG, inst),\ + SRI(OTG_CRC0_WINDOWA_Y_CONTROL, OTG, inst),\ + SRI(OTG_CRC0_WINDOWB_X_CONTROL, OTG, inst),\ + SRI(OTG_CRC0_WINDOWB_Y_CONTROL, OTG, inst),\ + SR(GSL_SOURCE_SELECT),\ + SRI(OTG_TRIGA_MANUAL_TRIG, OTG, inst),\ + SRI(OTG_GLOBAL_CONTROL1, OTG, inst),\ + SRI(OTG_GLOBAL_CONTROL2, OTG, inst),\ + SRI(OTG_GSL_WINDOW_X, OTG, inst),\ + SRI(OTG_GSL_WINDOW_Y, OTG, inst),\ + SRI(OTG_VUPDATE_KEEPOUT, OTG, inst),\ + SRI(OTG_DSC_START_POSITION, OTG, inst),\ + SRI(OTG_DRR_TRIGGER_WINDOW, OTG, inst),\ + SRI(OTG_DRR_V_TOTAL_CHANGE, OTG, inst),\ + SRI(OPTC_DATA_FORMAT_CONTROL, ODM, inst),\ + SRI(OPTC_BYTES_PER_PIXEL, ODM, inst),\ + SRI(OPTC_WIDTH_CONTROL, ODM, inst),\ + SRI(OPTC_MEMORY_CONFIG, ODM, inst),\ + SRI(OTG_DRR_CONTROL, OTG, inst) + +#define OPTC_COMMON_MASK_SH_LIST_DCN3_14(mask_sh)\ + SF(OTG0_OTG_VSTARTUP_PARAM, VSTARTUP_START, mask_sh),\ + SF(OTG0_OTG_VUPDATE_PARAM, VUPDATE_OFFSET, mask_sh),\ + SF(OTG0_OTG_VUPDATE_PARAM, VUPDATE_WIDTH, mask_sh),\ + SF(OTG0_OTG_VREADY_PARAM, VREADY_OFFSET, mask_sh),\ + SF(OTG0_OTG_MASTER_UPDATE_LOCK, OTG_MASTER_UPDATE_LOCK, mask_sh),\ + SF(OTG0_OTG_MASTER_UPDATE_LOCK, UPDATE_LOCK_STATUS, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL0, MASTER_UPDATE_LOCK_DB_START_X, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL0, MASTER_UPDATE_LOCK_DB_END_X, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL0, MASTER_UPDATE_LOCK_DB_EN, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_START_Y, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_END_Y, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL2, OTG_MASTER_UPDATE_LOCK_SEL, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL4, DIG_UPDATE_POSITION_X, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL4, DIG_UPDATE_POSITION_Y, mask_sh),\ + SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_UPDATE_PENDING, mask_sh),\ + SF(OTG0_OTG_H_TOTAL, OTG_H_TOTAL, mask_sh),\ + SF(OTG0_OTG_H_BLANK_START_END, OTG_H_BLANK_START, mask_sh),\ + SF(OTG0_OTG_H_BLANK_START_END, OTG_H_BLANK_END, mask_sh),\ + SF(OTG0_OTG_H_SYNC_A, OTG_H_SYNC_A_START, mask_sh),\ + SF(OTG0_OTG_H_SYNC_A, OTG_H_SYNC_A_END, mask_sh),\ + SF(OTG0_OTG_H_SYNC_A_CNTL, OTG_H_SYNC_A_POL, mask_sh),\ + SF(OTG0_OTG_V_TOTAL, OTG_V_TOTAL, mask_sh),\ + SF(OTG0_OTG_V_BLANK_START_END, OTG_V_BLANK_START, mask_sh),\ + SF(OTG0_OTG_V_BLANK_START_END, OTG_V_BLANK_END, mask_sh),\ + SF(OTG0_OTG_V_SYNC_A, OTG_V_SYNC_A_START, mask_sh),\ + SF(OTG0_OTG_V_SYNC_A, OTG_V_SYNC_A_END, mask_sh),\ + SF(OTG0_OTG_V_SYNC_A_CNTL, OTG_V_SYNC_A_POL, mask_sh),\ + SF(OTG0_OTG_V_SYNC_A_CNTL, OTG_V_SYNC_MODE, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_MASTER_EN, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_START_POINT_CNTL, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_DISABLE_POINT_CNTL, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_FIELD_NUMBER_CNTL, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_OUT_MUX, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_EN, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_SYNC_OUTPUT_LINE_NUM, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_SYNC_OUTPUT_POLARITY, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_EYE_FLAG_POLARITY, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_DISABLE_STEREOSYNC_OUTPUT_FOR_DP, mask_sh),\ + SF(OTG0_OTG_STEREO_STATUS, OTG_STEREO_CURRENT_EYE, mask_sh),\ + SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_EN, mask_sh),\ + SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_V_UPDATE_MODE, mask_sh),\ + SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_STEREO_SEL_OVR, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_MAX, OTG_V_TOTAL_MAX, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_MIN, OTG_V_TOTAL_MIN, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_V_TOTAL_MIN_SEL, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_V_TOTAL_MAX_SEL, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_FORCE_LOCK_ON_EVENT, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_SET_V_TOTAL_MIN_MASK, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_VTOTAL_MID_REPLACING_MIN_EN, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_VTOTAL_MID_REPLACING_MAX_EN, mask_sh),\ + SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_CLEAR, mask_sh),\ + SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_MODE, mask_sh),\ + SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_OCCURRED, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_SOURCE_SELECT, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_SOURCE_PIPE_SELECT, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_RISING_EDGE_DETECT_CNTL, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_POLARITY_SELECT, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_FREQUENCY_SELECT, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_DELAY, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_CLEAR, mask_sh),\ + SF(OTG0_OTG_STATIC_SCREEN_CONTROL, OTG_STATIC_SCREEN_EVENT_MASK, mask_sh),\ + SF(OTG0_OTG_STATIC_SCREEN_CONTROL, OTG_STATIC_SCREEN_FRAME_COUNT, mask_sh),\ + SF(OTG0_OTG_STATUS_FRAME_COUNT, OTG_FRAME_COUNT, mask_sh),\ + SF(OTG0_OTG_STATUS, OTG_V_BLANK, mask_sh),\ + SF(OTG0_OTG_STATUS, OTG_V_ACTIVE_DISP, mask_sh),\ + SF(OTG0_OTG_STATUS_POSITION, OTG_HORZ_COUNT, mask_sh),\ + SF(OTG0_OTG_STATUS_POSITION, OTG_VERT_COUNT, mask_sh),\ + SF(OTG0_OTG_NOM_VERT_POSITION, OTG_VERT_COUNT_NOM, mask_sh),\ + SF(OTG0_OTG_M_CONST_DTO0, OTG_M_CONST_DTO_PHASE, mask_sh),\ + SF(OTG0_OTG_M_CONST_DTO1, OTG_M_CONST_DTO_MODULO, mask_sh),\ + SF(OTG0_OTG_CLOCK_CONTROL, OTG_BUSY, mask_sh),\ + SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_EN, mask_sh),\ + SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_ON, mask_sh),\ + SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_GATE_DIS, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_INT_ENABLE, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT0_POSITION, OTG_VERTICAL_INTERRUPT0_LINE_START, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT0_POSITION, OTG_VERTICAL_INTERRUPT0_LINE_END, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT1_CONTROL, OTG_VERTICAL_INTERRUPT1_INT_ENABLE, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT1_POSITION, OTG_VERTICAL_INTERRUPT1_LINE_START, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT2_POSITION, OTG_VERTICAL_INTERRUPT2_LINE_START, mask_sh),\ + SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_EN, mask_sh),\ + SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_ON, mask_sh),\ + SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_GATE_DIS, mask_sh),\ + SF(ODM0_OPTC_INPUT_GLOBAL_CONTROL, OPTC_UNDERFLOW_OCCURRED_STATUS, mask_sh),\ + SF(ODM0_OPTC_INPUT_GLOBAL_CONTROL, OPTC_UNDERFLOW_CLEAR, mask_sh),\ + SF(VTG0_CONTROL, VTG0_ENABLE, mask_sh),\ + SF(VTG0_CONTROL, VTG0_FP2, mask_sh),\ + SF(VTG0_CONTROL, VTG0_VCOUNT_INIT, mask_sh),\ + SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_FORCE_VSYNC_NEXT_LINE_OCCURRED, mask_sh),\ + SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_FORCE_VSYNC_NEXT_LINE_CLEAR, mask_sh),\ + SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_AUTO_FORCE_VSYNC_MODE, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL0_EN, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL1_EN, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL2_EN, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_MASTER_EN, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_FORCE_DELAY, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_CHECK_ALL_FIELDS, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL, OTG_CRC_CONT_EN, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL, OTG_CRC0_SELECT, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL, OTG_CRC_EN, mask_sh),\ + SF(OTG0_OTG_CRC0_DATA_RG, CRC0_R_CR, mask_sh),\ + SF(OTG0_OTG_CRC0_DATA_RG, CRC0_G_Y, mask_sh),\ + SF(OTG0_OTG_CRC0_DATA_B, CRC0_B_CB, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWA_X_CONTROL, OTG_CRC0_WINDOWA_X_START, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWA_X_CONTROL, OTG_CRC0_WINDOWA_X_END, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWA_Y_CONTROL, OTG_CRC0_WINDOWA_Y_START, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWA_Y_CONTROL, OTG_CRC0_WINDOWA_Y_END, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWB_X_CONTROL, OTG_CRC0_WINDOWB_X_START, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWB_X_CONTROL, OTG_CRC0_WINDOWB_X_END, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL, OTG_CRC0_WINDOWB_Y_START, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL, OTG_CRC0_WINDOWB_Y_END, mask_sh),\ + SF(OTG0_OTG_TRIGA_MANUAL_TRIG, OTG_TRIGA_MANUAL_TRIG, mask_sh),\ + SF(GSL_SOURCE_SELECT, GSL0_READY_SOURCE_SEL, mask_sh),\ + SF(GSL_SOURCE_SELECT, GSL1_READY_SOURCE_SEL, mask_sh),\ + SF(GSL_SOURCE_SELECT, GSL2_READY_SOURCE_SEL, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL2, MANUAL_FLOW_CONTROL_SEL, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, mask_sh),\ + SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_START_X, mask_sh),\ + SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_END_X, mask_sh), \ + SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_START_Y, mask_sh),\ + SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_END_Y, mask_sh),\ + SF(OTG0_OTG_VUPDATE_KEEPOUT, OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, mask_sh), \ + SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET, mask_sh), \ + SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET, mask_sh), \ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_MASTER_MODE, mask_sh), \ + SF(OTG0_OTG_GSL_CONTROL, OTG_MASTER_UPDATE_LOCK_GSL_EN, mask_sh), \ + SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_X, mask_sh), \ + SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_LINE_NUM, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG0_SRC_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG1_SRC_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG2_SRC_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG3_SRC_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_NUM_OF_INPUT_SEGMENT, mask_sh),\ + SF(ODM0_OPTC_MEMORY_CONFIG, OPTC_MEM_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_FORMAT_CONTROL, OPTC_DATA_FORMAT, mask_sh),\ + SF(ODM0_OPTC_DATA_FORMAT_CONTROL, OPTC_DSC_MODE, mask_sh),\ + SF(ODM0_OPTC_BYTES_PER_PIXEL, OPTC_DSC_BYTES_PER_PIXEL, mask_sh),\ + SF(ODM0_OPTC_WIDTH_CONTROL, OPTC_DSC_SLICE_WIDTH, mask_sh),\ + SF(ODM0_OPTC_WIDTH_CONTROL, OPTC_SEGMENT_WIDTH, mask_sh),\ + SF(OTG0_OTG_DRR_TRIGGER_WINDOW, OTG_DRR_TRIGGER_WINDOW_START_X, mask_sh),\ + 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_H_TIMING_CNTL, OTG_H_TIMING_DIV_MODE_MANUAL, mask_sh),\ + SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_DRR_TIMING_DBUF_UPDATE_MODE, mask_sh),\ + SF(OTG0_OTG_DRR_CONTROL, OTG_V_TOTAL_LAST_USED_BY_DRR, mask_sh) + +void dcn314_timing_generator_init(struct optc *optc1); + +#endif /* __DC_OPTC_DCN314_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c new file mode 100644 index 00000000000000..82349354332548 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c @@ -0,0 +1,374 @@ +/* + * 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 "dcn32_optc.h" + +#include "dcn30/dcn30_optc.h" +#include "dcn31/dcn31_optc.h" +#include "reg_helper.h" +#include "dc.h" +#include "dcn_calc_math.h" +#include "dc_dmub_srv.h" + +#define REG(reg)\ + optc1->tg_regs->reg + +#define CTX \ + optc1->base.ctx + +#undef FN +#define FN(reg_name, field_name) \ + optc1->tg_shift->field_name, optc1->tg_mask->field_name + +static void optc32_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, + struct dc_crtc_timing *timing) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + uint32_t memory_mask = 0; + int h_active = timing->h_addressable + timing->h_border_left + timing->h_border_right; + int mpcc_hactive = h_active / opp_cnt; + /* Each memory instance is 2048x(32x2) bits to support half line of 4096 */ + int odm_mem_count = (h_active + 2047) / 2048; + + /* + * display <= 4k : 2 memories + 2 pipes + * 4k < display <= 8k : 4 memories + 2 pipes + * 8k < display <= 12k : 6 memories + 4 pipes + */ + if (opp_cnt == 4) { + if (odm_mem_count <= 2) + memory_mask = 0x3; + else if (odm_mem_count <= 4) + memory_mask = 0xf; + else + memory_mask = 0x3f; + } else { + if (odm_mem_count <= 2) + memory_mask = 0x1 << (opp_id[0] * 2) | 0x1 << (opp_id[1] * 2); + else if (odm_mem_count <= 4) + memory_mask = 0x3 << (opp_id[0] * 2) | 0x3 << (opp_id[1] * 2); + else + memory_mask = 0x77; + } + + REG_SET(OPTC_MEMORY_CONFIG, 0, + OPTC_MEM_SEL, memory_mask); + + if (opp_cnt == 2) { + REG_SET_3(OPTC_DATA_SOURCE_SELECT, 0, + OPTC_NUM_OF_INPUT_SEGMENT, 1, + OPTC_SEG0_SRC_SEL, opp_id[0], + OPTC_SEG1_SRC_SEL, opp_id[1]); + } else if (opp_cnt == 4) { + REG_SET_5(OPTC_DATA_SOURCE_SELECT, 0, + OPTC_NUM_OF_INPUT_SEGMENT, 3, + OPTC_SEG0_SRC_SEL, opp_id[0], + OPTC_SEG1_SRC_SEL, opp_id[1], + OPTC_SEG2_SRC_SEL, opp_id[2], + OPTC_SEG3_SRC_SEL, opp_id[3]); + } + + REG_UPDATE(OPTC_WIDTH_CONTROL, + OPTC_SEGMENT_WIDTH, mpcc_hactive); + + REG_UPDATE(OTG_H_TIMING_CNTL, + OTG_H_TIMING_DIV_MODE, opp_cnt - 1); + optc1->opp_count = opp_cnt; +} + +void optc32_get_odm_combine_segments(struct timing_generator *tg, int *odm_combine_segments) +{ + struct optc *optc1 = DCN10TG_FROM_TG(tg); + int segments; + + REG_GET(OPTC_DATA_SOURCE_SELECT, OPTC_NUM_OF_INPUT_SEGMENT, &segments); + + switch (segments) { + case 0: + *odm_combine_segments = 1; + break; + case 1: + *odm_combine_segments = 2; + break; + case 3: + *odm_combine_segments = 4; + break; + /* 2 is reserved */ + case 2: + default: + *odm_combine_segments = -1; + } +} + +void optc32_set_h_timing_div_manual_mode(struct timing_generator *optc, bool manual_mode) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_UPDATE(OTG_H_TIMING_CNTL, + OTG_H_TIMING_DIV_MODE_MANUAL, manual_mode ? 1 : 0); +} +/** + * optc32_enable_crtc() - Enable CRTC - call ASIC Control Object to enable Timing generator. + * + * @optc: timing_generator instance. + * + * Return: If CRTC is enabled, return true. + */ +static bool optc32_enable_crtc(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + /* opp instance for OTG, 1 to 1 mapping and odm will adjust */ + REG_UPDATE(OPTC_DATA_SOURCE_SELECT, + OPTC_SEG0_SRC_SEL, optc->inst); + + /* VTG enable first is for HW workaround */ + REG_UPDATE(CONTROL, + VTG0_ENABLE, 1); + + REG_SEQ_START(); + + /* Enable CRTC */ + REG_UPDATE_2(OTG_CONTROL, + OTG_DISABLE_POINT_CNTL, 2, + OTG_MASTER_EN, 1); + + REG_SEQ_SUBMIT(); + REG_SEQ_WAIT_DONE(); + + return true; +} + +/* disable_crtc */ +static bool optc32_disable_crtc(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_UPDATE_5(OPTC_DATA_SOURCE_SELECT, + OPTC_SEG0_SRC_SEL, 0xf, + OPTC_SEG1_SRC_SEL, 0xf, + OPTC_SEG2_SRC_SEL, 0xf, + OPTC_SEG3_SRC_SEL, 0xf, + OPTC_NUM_OF_INPUT_SEGMENT, 0); + + REG_UPDATE(OPTC_MEMORY_CONFIG, + OPTC_MEM_SEL, 0); + + /* disable otg request until end of the first line + * in the vertical blank region + */ + REG_UPDATE(OTG_CONTROL, + OTG_MASTER_EN, 0); + + REG_UPDATE(CONTROL, + VTG0_ENABLE, 0); + + /* CRTC disabled, so disable clock. */ + REG_WAIT(OTG_CLOCK_CONTROL, + OTG_BUSY, 0, + 1, 150000); + + return true; +} + +static void optc32_phantom_crtc_post_enable(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + /* Disable immediately. */ + REG_UPDATE_2(OTG_CONTROL, OTG_DISABLE_POINT_CNTL, 0, OTG_MASTER_EN, 0); + + /* CRTC disabled, so disable clock. */ + REG_WAIT(OTG_CLOCK_CONTROL, OTG_BUSY, 0, 1, 100000); +} + +static void optc32_disable_phantom_otg(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_UPDATE_5(OPTC_DATA_SOURCE_SELECT, + OPTC_SEG0_SRC_SEL, 0xf, + OPTC_SEG1_SRC_SEL, 0xf, + OPTC_SEG2_SRC_SEL, 0xf, + OPTC_SEG3_SRC_SEL, 0xf, + OPTC_NUM_OF_INPUT_SEGMENT, 0); + + REG_UPDATE(OTG_CONTROL, OTG_MASTER_EN, 0); +} + +void optc32_set_odm_bypass(struct timing_generator *optc, + const struct dc_crtc_timing *dc_crtc_timing) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + enum h_timing_div_mode h_div = H_TIMING_NO_DIV; + + REG_SET_5(OPTC_DATA_SOURCE_SELECT, 0, + OPTC_NUM_OF_INPUT_SEGMENT, 0, + OPTC_SEG0_SRC_SEL, optc->inst, + OPTC_SEG1_SRC_SEL, 0xf, + OPTC_SEG2_SRC_SEL, 0xf, + OPTC_SEG3_SRC_SEL, 0xf + ); + + h_div = optc1_is_two_pixels_per_containter(dc_crtc_timing); + REG_UPDATE(OTG_H_TIMING_CNTL, + OTG_H_TIMING_DIV_MODE, h_div); + + REG_SET(OPTC_MEMORY_CONFIG, 0, + OPTC_MEM_SEL, 0); + optc1->opp_count = 1; +} + +static void optc32_setup_manual_trigger(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + struct dc *dc = optc->ctx->dc; + + if (dc->caps.dmub_caps.mclk_sw && !dc->debug.disable_fams) + dc_dmub_srv_set_drr_manual_trigger_cmd(dc, optc->inst); + else { + /* + * MIN_MASK_EN is gone and MASK is now always enabled. + * + * To get it to it work with manual trigger we need to make sure + * we program the correct bit. + */ + REG_UPDATE_4(OTG_V_TOTAL_CONTROL, + OTG_V_TOTAL_MIN_SEL, 1, + OTG_V_TOTAL_MAX_SEL, 1, + OTG_FORCE_LOCK_ON_EVENT, 0, + OTG_SET_V_TOTAL_MIN_MASK, (1 << 1)); /* TRIGA */ + + // Setup manual flow control for EOF via TRIG_A + optc->funcs->setup_manual_trigger(optc); + } +} + +static void optc32_set_drr( + struct timing_generator *optc, + const struct drr_params *params) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + if (params != NULL && + params->vertical_total_max > 0 && + params->vertical_total_min > 0) { + + if (params->vertical_total_mid != 0) { + + REG_SET(OTG_V_TOTAL_MID, 0, + OTG_V_TOTAL_MID, params->vertical_total_mid - 1); + + REG_UPDATE_2(OTG_V_TOTAL_CONTROL, + OTG_VTOTAL_MID_REPLACING_MAX_EN, 1, + OTG_VTOTAL_MID_FRAME_NUM, + (uint8_t)params->vertical_total_mid_frame_num); + + } + + optc->funcs->set_vtotal_min_max(optc, params->vertical_total_min - 1, params->vertical_total_max - 1); + } + + optc32_setup_manual_trigger(optc); +} + +static struct timing_generator_funcs dcn32_tg_funcs = { + .validate_timing = optc1_validate_timing, + .program_timing = optc1_program_timing, + .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0, + .setup_vertical_interrupt1 = optc1_setup_vertical_interrupt1, + .setup_vertical_interrupt2 = optc1_setup_vertical_interrupt2, + .program_global_sync = optc1_program_global_sync, + .enable_crtc = optc32_enable_crtc, + .disable_crtc = optc32_disable_crtc, + .phantom_crtc_post_enable = optc32_phantom_crtc_post_enable, + .disable_phantom_crtc = optc32_disable_phantom_otg, + /* used by enable_timing_synchronization. Not need for FPGA */ + .is_counter_moving = optc1_is_counter_moving, + .get_position = optc1_get_position, + .get_frame_count = optc1_get_vblank_counter, + .get_scanoutpos = optc1_get_crtc_scanoutpos, + .get_otg_active_size = optc1_get_otg_active_size, + .set_early_control = optc1_set_early_control, + /* used by enable_timing_synchronization. Not need for FPGA */ + .wait_for_state = optc1_wait_for_state, + .set_blank_color = optc3_program_blank_color, + .did_triggered_reset_occur = optc1_did_triggered_reset_occur, + .triplebuffer_lock = optc3_triplebuffer_lock, + .triplebuffer_unlock = optc2_triplebuffer_unlock, + .enable_reset_trigger = optc1_enable_reset_trigger, + .enable_crtc_reset = optc1_enable_crtc_reset, + .disable_reset_trigger = optc1_disable_reset_trigger, + .lock = optc3_lock, + .unlock = optc1_unlock, + .lock_doublebuffer_enable = optc3_lock_doublebuffer_enable, + .lock_doublebuffer_disable = optc3_lock_doublebuffer_disable, + .enable_optc_clock = optc1_enable_optc_clock, + .set_drr = optc32_set_drr, + .get_last_used_drr_vtotal = optc2_get_last_used_drr_vtotal, + .set_vtotal_min_max = optc3_set_vtotal_min_max, + .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, + .is_tg_enabled = optc1_is_tg_enabled, + .is_optc_underflow_occurred = optc1_is_optc_underflow_occurred, + .clear_optc_underflow = optc1_clear_optc_underflow, + .setup_global_swap_lock = NULL, + .get_crc = optc1_get_crc, + .configure_crc = optc1_configure_crc, + .set_dsc_config = optc3_set_dsc_config, + .get_dsc_status = optc2_get_dsc_status, + .set_dwb_source = NULL, + .set_odm_bypass = optc32_set_odm_bypass, + .set_odm_combine = optc32_set_odm_combine, + .get_odm_combine_segments = optc32_get_odm_combine_segments, + .set_h_timing_div_manual_mode = optc32_set_h_timing_div_manual_mode, + .get_optc_source = optc2_get_optc_source, + .set_out_mux = optc3_set_out_mux, + .set_drr_trigger_window = optc3_set_drr_trigger_window, + .set_vtotal_change_limit = optc3_set_vtotal_change_limit, + .set_gsl = optc2_set_gsl, + .set_gsl_source_select = optc2_set_gsl_source_select, + .set_vtg_params = optc1_set_vtg_params, + .program_manual_trigger = optc2_program_manual_trigger, + .setup_manual_trigger = optc2_setup_manual_trigger, + .get_hw_timing = optc1_get_hw_timing, +}; + +void dcn32_timing_generator_init(struct optc *optc1) +{ + optc1->base.funcs = &dcn32_tg_funcs; + + optc1->max_h_total = optc1->tg_mask->OTG_H_TOTAL + 1; + optc1->max_v_total = optc1->tg_mask->OTG_V_TOTAL + 1; + + optc1->min_h_blank = 32; + optc1->min_v_blank = 3; + optc1->min_v_blank_interlace = 5; + optc1->min_h_sync_width = 4; + optc1->min_v_sync_width = 1; +} + diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.h new file mode 100644 index 00000000000000..8ce3b178cab065 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.h @@ -0,0 +1,187 @@ +/* + * 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_OPTC_DCN32_H__ +#define __DC_OPTC_DCN32_H__ + +#include "dcn10/dcn10_optc.h" + +#define OPTC_COMMON_MASK_SH_LIST_DCN3_2(mask_sh)\ + SF(OTG0_OTG_VSTARTUP_PARAM, VSTARTUP_START, mask_sh),\ + SF(OTG0_OTG_VUPDATE_PARAM, VUPDATE_OFFSET, mask_sh),\ + SF(OTG0_OTG_VUPDATE_PARAM, VUPDATE_WIDTH, mask_sh),\ + SF(OTG0_OTG_VREADY_PARAM, VREADY_OFFSET, mask_sh),\ + SF(OTG0_OTG_MASTER_UPDATE_LOCK, OTG_MASTER_UPDATE_LOCK, mask_sh),\ + SF(OTG0_OTG_MASTER_UPDATE_LOCK, UPDATE_LOCK_STATUS, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL0, MASTER_UPDATE_LOCK_DB_START_X, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL0, MASTER_UPDATE_LOCK_DB_END_X, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL0, MASTER_UPDATE_LOCK_DB_EN, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_START_Y, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL1, MASTER_UPDATE_LOCK_DB_END_Y, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL2, OTG_MASTER_UPDATE_LOCK_SEL, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL4, DIG_UPDATE_POSITION_X, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL4, DIG_UPDATE_POSITION_Y, mask_sh),\ + SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_UPDATE_PENDING, mask_sh),\ + SF(OTG0_OTG_H_TOTAL, OTG_H_TOTAL, mask_sh),\ + SF(OTG0_OTG_H_BLANK_START_END, OTG_H_BLANK_START, mask_sh),\ + SF(OTG0_OTG_H_BLANK_START_END, OTG_H_BLANK_END, mask_sh),\ + SF(OTG0_OTG_H_SYNC_A, OTG_H_SYNC_A_START, mask_sh),\ + SF(OTG0_OTG_H_SYNC_A, OTG_H_SYNC_A_END, mask_sh),\ + SF(OTG0_OTG_H_SYNC_A_CNTL, OTG_H_SYNC_A_POL, mask_sh),\ + SF(OTG0_OTG_V_TOTAL, OTG_V_TOTAL, mask_sh),\ + SF(OTG0_OTG_V_BLANK_START_END, OTG_V_BLANK_START, mask_sh),\ + SF(OTG0_OTG_V_BLANK_START_END, OTG_V_BLANK_END, mask_sh),\ + SF(OTG0_OTG_V_SYNC_A, OTG_V_SYNC_A_START, mask_sh),\ + SF(OTG0_OTG_V_SYNC_A, OTG_V_SYNC_A_END, mask_sh),\ + SF(OTG0_OTG_V_SYNC_A_CNTL, OTG_V_SYNC_A_POL, mask_sh),\ + SF(OTG0_OTG_V_SYNC_A_CNTL, OTG_V_SYNC_MODE, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_MASTER_EN, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_START_POINT_CNTL, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_DISABLE_POINT_CNTL, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_FIELD_NUMBER_CNTL, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_OUT_MUX, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_EN, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_SYNC_OUTPUT_LINE_NUM, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_SYNC_OUTPUT_POLARITY, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_EYE_FLAG_POLARITY, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_DISABLE_STEREOSYNC_OUTPUT_FOR_DP, mask_sh),\ + SF(OTG0_OTG_STEREO_STATUS, OTG_STEREO_CURRENT_EYE, mask_sh),\ + SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_EN, mask_sh),\ + SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_V_UPDATE_MODE, mask_sh),\ + SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_STEREO_SEL_OVR, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_MAX, OTG_V_TOTAL_MAX, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_MIN, OTG_V_TOTAL_MIN, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_V_TOTAL_MIN_SEL, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_V_TOTAL_MAX_SEL, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_FORCE_LOCK_ON_EVENT, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_SET_V_TOTAL_MIN_MASK, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_VTOTAL_MID_REPLACING_MIN_EN, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_VTOTAL_MID_REPLACING_MAX_EN, mask_sh),\ + SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_CLEAR, mask_sh),\ + SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_MODE, mask_sh),\ + SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_OCCURRED, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_SOURCE_SELECT, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_SOURCE_PIPE_SELECT, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_RISING_EDGE_DETECT_CNTL, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_POLARITY_SELECT, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_FREQUENCY_SELECT, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_DELAY, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_CLEAR, mask_sh),\ + SF(OTG0_OTG_STATIC_SCREEN_CONTROL, OTG_STATIC_SCREEN_EVENT_MASK, mask_sh),\ + SF(OTG0_OTG_STATIC_SCREEN_CONTROL, OTG_STATIC_SCREEN_FRAME_COUNT, mask_sh),\ + SF(OTG0_OTG_STATUS_FRAME_COUNT, OTG_FRAME_COUNT, mask_sh),\ + SF(OTG0_OTG_STATUS, OTG_V_BLANK, mask_sh),\ + SF(OTG0_OTG_STATUS, OTG_V_ACTIVE_DISP, mask_sh),\ + SF(OTG0_OTG_STATUS_POSITION, OTG_HORZ_COUNT, mask_sh),\ + SF(OTG0_OTG_STATUS_POSITION, OTG_VERT_COUNT, mask_sh),\ + SF(OTG0_OTG_NOM_VERT_POSITION, OTG_VERT_COUNT_NOM, mask_sh),\ + SF(OTG0_OTG_M_CONST_DTO0, OTG_M_CONST_DTO_PHASE, mask_sh),\ + SF(OTG0_OTG_M_CONST_DTO1, OTG_M_CONST_DTO_MODULO, mask_sh),\ + SF(OTG0_OTG_CLOCK_CONTROL, OTG_BUSY, mask_sh),\ + SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_EN, mask_sh),\ + SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_ON, mask_sh),\ + SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_GATE_DIS, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_INT_ENABLE, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT0_POSITION, OTG_VERTICAL_INTERRUPT0_LINE_START, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT0_POSITION, OTG_VERTICAL_INTERRUPT0_LINE_END, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT1_CONTROL, OTG_VERTICAL_INTERRUPT1_INT_ENABLE, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT1_POSITION, OTG_VERTICAL_INTERRUPT1_LINE_START, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT2_POSITION, OTG_VERTICAL_INTERRUPT2_LINE_START, mask_sh),\ + SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_EN, mask_sh),\ + SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_ON, mask_sh),\ + SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_GATE_DIS, mask_sh),\ + SF(ODM0_OPTC_INPUT_GLOBAL_CONTROL, OPTC_UNDERFLOW_OCCURRED_STATUS, mask_sh),\ + SF(ODM0_OPTC_INPUT_GLOBAL_CONTROL, OPTC_UNDERFLOW_CLEAR, mask_sh),\ + SF(VTG0_CONTROL, VTG0_ENABLE, mask_sh),\ + SF(VTG0_CONTROL, VTG0_FP2, mask_sh),\ + SF(VTG0_CONTROL, VTG0_VCOUNT_INIT, mask_sh),\ + SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_FORCE_VSYNC_NEXT_LINE_OCCURRED, mask_sh),\ + SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_FORCE_VSYNC_NEXT_LINE_CLEAR, mask_sh),\ + SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_AUTO_FORCE_VSYNC_MODE, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL0_EN, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL1_EN, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL2_EN, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_MASTER_EN, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_FORCE_DELAY, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_CHECK_ALL_FIELDS, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL, OTG_CRC_CONT_EN, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL, OTG_CRC0_SELECT, mask_sh),\ + SF(OTG0_OTG_CRC_CNTL, OTG_CRC_EN, mask_sh),\ + SF(OTG0_OTG_CRC0_DATA_RG, CRC0_R_CR, mask_sh),\ + SF(OTG0_OTG_CRC0_DATA_RG, CRC0_G_Y, mask_sh),\ + SF(OTG0_OTG_CRC0_DATA_B, CRC0_B_CB, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWA_X_CONTROL, OTG_CRC0_WINDOWA_X_START, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWA_X_CONTROL, OTG_CRC0_WINDOWA_X_END, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWA_Y_CONTROL, OTG_CRC0_WINDOWA_Y_START, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWA_Y_CONTROL, OTG_CRC0_WINDOWA_Y_END, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWB_X_CONTROL, OTG_CRC0_WINDOWB_X_START, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWB_X_CONTROL, OTG_CRC0_WINDOWB_X_END, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL, OTG_CRC0_WINDOWB_Y_START, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL, OTG_CRC0_WINDOWB_Y_END, mask_sh),\ + SF(OTG0_OTG_TRIGA_MANUAL_TRIG, OTG_TRIGA_MANUAL_TRIG, mask_sh),\ + SF(GSL_SOURCE_SELECT, GSL0_READY_SOURCE_SEL, mask_sh),\ + SF(GSL_SOURCE_SELECT, GSL1_READY_SOURCE_SEL, mask_sh),\ + SF(GSL_SOURCE_SELECT, GSL2_READY_SOURCE_SEL, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL2, MANUAL_FLOW_CONTROL_SEL, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, mask_sh),\ + SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_START_X, mask_sh),\ + SF(OTG0_OTG_GSL_WINDOW_X, OTG_GSL_WINDOW_END_X, mask_sh), \ + SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_START_Y, mask_sh),\ + SF(OTG0_OTG_GSL_WINDOW_Y, OTG_GSL_WINDOW_END_Y, mask_sh),\ + SF(OTG0_OTG_VUPDATE_KEEPOUT, OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN, mask_sh), \ + SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET, mask_sh), \ + SF(OTG0_OTG_VUPDATE_KEEPOUT, MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET, mask_sh), \ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_MASTER_MODE, mask_sh), \ + SF(OTG0_OTG_GSL_CONTROL, OTG_MASTER_UPDATE_LOCK_GSL_EN, mask_sh), \ + SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_X, mask_sh), \ + SF(OTG0_OTG_DSC_START_POSITION, OTG_DSC_START_POSITION_LINE_NUM, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG0_SRC_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG1_SRC_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG2_SRC_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SEG3_SRC_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_NUM_OF_INPUT_SEGMENT, mask_sh),\ + SF(ODM0_OPTC_MEMORY_CONFIG, OPTC_MEM_SEL, mask_sh),\ + SF(ODM0_OPTC_DATA_FORMAT_CONTROL, OPTC_DATA_FORMAT, mask_sh),\ + SF(ODM0_OPTC_DATA_FORMAT_CONTROL, OPTC_DSC_MODE, mask_sh),\ + SF(ODM0_OPTC_BYTES_PER_PIXEL, OPTC_DSC_BYTES_PER_PIXEL, mask_sh),\ + SF(ODM0_OPTC_WIDTH_CONTROL, OPTC_DSC_SLICE_WIDTH, mask_sh),\ + SF(ODM0_OPTC_WIDTH_CONTROL, OPTC_SEGMENT_WIDTH, mask_sh),\ + SF(OTG0_OTG_DRR_TRIGGER_WINDOW, OTG_DRR_TRIGGER_WINDOW_START_X, mask_sh),\ + 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_H_TIMING_CNTL, OTG_H_TIMING_DIV_MODE_MANUAL, mask_sh),\ + SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_DRR_TIMING_DBUF_UPDATE_MODE, mask_sh),\ + SF(OTG0_OTG_DRR_CONTROL, OTG_V_TOTAL_LAST_USED_BY_DRR, mask_sh) + +void dcn32_timing_generator_init(struct optc *optc1); +void optc32_set_h_timing_div_manual_mode(struct timing_generator *optc, bool manual_mode); +void optc32_get_odm_combine_segments(struct timing_generator *tg, int *odm_combine_segments); +void optc32_set_odm_bypass(struct timing_generator *optc, + const struct dc_crtc_timing *dc_crtc_timing); + +#endif /* __DC_OPTC_DCN32_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c new file mode 100644 index 00000000000000..5b154750885030 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c @@ -0,0 +1,300 @@ +/* SPDX-License-Identifier: MIT */ +/* + * 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 "dcn35_optc.h" + +#include "dcn30/dcn30_optc.h" +#include "dcn31/dcn31_optc.h" +#include "dcn32/dcn32_optc.h" +#include "reg_helper.h" +#include "dc.h" +#include "dcn_calc_math.h" + +#define REG(reg)\ + optc1->tg_regs->reg + +#define CTX \ + optc1->base.ctx + +#undef FN +#define FN(reg_name, field_name) \ + optc1->tg_shift->field_name, optc1->tg_mask->field_name + +/** + * optc35_set_odm_combine() - Enable CRTC - call ASIC Control Object to enable Timing generator. + * + * @optc: Output Pipe Timing Combine instance reference. + * @opp_id: Output Plane Processor instance ID. + * @opp_cnt: Output Plane Processor count. + * @timing: Timing parameters used to configure DCN blocks. + * + * Return: void. + */ +static void optc35_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, + struct dc_crtc_timing *timing) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + uint32_t memory_mask = 0; + int h_active = timing->h_addressable + timing->h_border_left + timing->h_border_right; + int mpcc_hactive = h_active / opp_cnt; + /* Each memory instance is 2048x(314x2) bits to support half line of 4096 */ + int odm_mem_count = (h_active + 2047) / 2048; + + /* + * display <= 4k : 2 memories + 2 pipes + * 4k < display <= 8k : 4 memories + 2 pipes + * 8k < display <= 12k : 6 memories + 4 pipes + */ + if (opp_cnt == 4) { + if (odm_mem_count <= 2) + memory_mask = 0x3; + else if (odm_mem_count <= 4) + memory_mask = 0xf; + else + memory_mask = 0x3f; + } else { + if (odm_mem_count <= 2) + memory_mask = 0x1 << (opp_id[0] * 2) | 0x1 << (opp_id[1] * 2); + else if (odm_mem_count <= 4) + memory_mask = 0x3 << (opp_id[0] * 2) | 0x3 << (opp_id[1] * 2); + else + memory_mask = 0x77; + } + + REG_SET(OPTC_MEMORY_CONFIG, 0, + OPTC_MEM_SEL, memory_mask); + + if (opp_cnt == 2) { + REG_SET_3(OPTC_DATA_SOURCE_SELECT, 0, + OPTC_NUM_OF_INPUT_SEGMENT, 1, + OPTC_SEG0_SRC_SEL, opp_id[0], + OPTC_SEG1_SRC_SEL, opp_id[1]); + } else if (opp_cnt == 4) { + REG_SET_5(OPTC_DATA_SOURCE_SELECT, 0, + OPTC_NUM_OF_INPUT_SEGMENT, 3, + OPTC_SEG0_SRC_SEL, opp_id[0], + OPTC_SEG1_SRC_SEL, opp_id[1], + OPTC_SEG2_SRC_SEL, opp_id[2], + OPTC_SEG3_SRC_SEL, opp_id[3]); + } + + REG_UPDATE(OPTC_WIDTH_CONTROL, + OPTC_SEGMENT_WIDTH, mpcc_hactive); + + REG_UPDATE(OTG_H_TIMING_CNTL, OTG_H_TIMING_DIV_MODE, opp_cnt - 1); + optc1->opp_count = opp_cnt; +} + +static bool optc35_enable_crtc(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + /* opp instance for OTG, 1 to 1 mapping and odm will adjust */ + REG_UPDATE(OPTC_DATA_SOURCE_SELECT, + OPTC_SEG0_SRC_SEL, optc->inst); + + /* VTG enable first is for HW workaround */ + REG_UPDATE(CONTROL, + VTG0_ENABLE, 1); + + REG_SEQ_START(); + + /* Enable CRTC */ + REG_UPDATE_2(OTG_CONTROL, + OTG_DISABLE_POINT_CNTL, 2, + OTG_MASTER_EN, 1); + + REG_SEQ_SUBMIT(); + REG_SEQ_WAIT_DONE(); + + return true; +} + +/* disable_crtc */ +static bool optc35_disable_crtc(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_UPDATE_5(OPTC_DATA_SOURCE_SELECT, + OPTC_SEG0_SRC_SEL, 0xf, + OPTC_SEG1_SRC_SEL, 0xf, + OPTC_SEG2_SRC_SEL, 0xf, + OPTC_SEG3_SRC_SEL, 0xf, + OPTC_NUM_OF_INPUT_SEGMENT, 0); + + REG_UPDATE(OPTC_MEMORY_CONFIG, + OPTC_MEM_SEL, 0); + + /* disable otg request until end of the first line + * in the vertical blank region + */ + REG_UPDATE(OTG_CONTROL, + OTG_MASTER_EN, 0); + + REG_UPDATE(CONTROL, + VTG0_ENABLE, 0); + + /* CRTC disabled, so disable clock. */ + REG_WAIT(OTG_CLOCK_CONTROL, + OTG_BUSY, 0, + 1, 100000); + optc1_clear_optc_underflow(optc); + + return true; +} + +static void optc35_phantom_crtc_post_enable(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + /* Disable immediately. */ + REG_UPDATE_2(OTG_CONTROL, OTG_DISABLE_POINT_CNTL, 0, OTG_MASTER_EN, 0); + + /* CRTC disabled, so disable clock. */ + REG_WAIT(OTG_CLOCK_CONTROL, OTG_BUSY, 0, 1, 100000); +} + +static bool optc35_configure_crc(struct timing_generator *optc, + const struct crc_params *params) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + if (!optc1_is_tg_enabled(optc)) + return false; + REG_WRITE(OTG_CRC_CNTL, 0); + if (!params->enable) + return true; + REG_UPDATE_2(OTG_CRC0_WINDOWA_X_CONTROL, + OTG_CRC0_WINDOWA_X_START, params->windowa_x_start, + OTG_CRC0_WINDOWA_X_END, params->windowa_x_end); + REG_UPDATE_2(OTG_CRC0_WINDOWA_Y_CONTROL, + OTG_CRC0_WINDOWA_Y_START, params->windowa_y_start, + OTG_CRC0_WINDOWA_Y_END, params->windowa_y_end); + REG_UPDATE_2(OTG_CRC0_WINDOWB_X_CONTROL, + OTG_CRC0_WINDOWB_X_START, params->windowb_x_start, + OTG_CRC0_WINDOWB_X_END, params->windowb_x_end); + REG_UPDATE_2(OTG_CRC0_WINDOWB_Y_CONTROL, + OTG_CRC0_WINDOWB_Y_START, params->windowb_y_start, + OTG_CRC0_WINDOWB_Y_END, params->windowb_y_end); + if (optc1->base.ctx->dc->debug.otg_crc_db && optc1->tg_mask->OTG_CRC_WINDOW_DB_EN != 0) { + REG_UPDATE_4(OTG_CRC_CNTL, + OTG_CRC_CONT_EN, params->continuous_mode ? 1 : 0, + OTG_CRC0_SELECT, params->selection, + OTG_CRC_EN, 1, + OTG_CRC_WINDOW_DB_EN, 1); + } else + REG_UPDATE_3(OTG_CRC_CNTL, + OTG_CRC_CONT_EN, params->continuous_mode ? 1 : 0, + OTG_CRC0_SELECT, params->selection, + OTG_CRC_EN, 1); + return true; +} + +static struct timing_generator_funcs dcn35_tg_funcs = { + .validate_timing = optc1_validate_timing, + .program_timing = optc1_program_timing, + .setup_vertical_interrupt0 = optc1_setup_vertical_interrupt0, + .setup_vertical_interrupt1 = optc1_setup_vertical_interrupt1, + .setup_vertical_interrupt2 = optc1_setup_vertical_interrupt2, + .program_global_sync = optc1_program_global_sync, + .enable_crtc = optc35_enable_crtc, + .disable_crtc = optc35_disable_crtc, + .immediate_disable_crtc = optc31_immediate_disable_crtc, + .phantom_crtc_post_enable = optc35_phantom_crtc_post_enable, + /* used by enable_timing_synchronization. Not need for FPGA */ + .is_counter_moving = optc1_is_counter_moving, + .get_position = optc1_get_position, + .get_frame_count = optc1_get_vblank_counter, + .get_scanoutpos = optc1_get_crtc_scanoutpos, + .get_otg_active_size = optc1_get_otg_active_size, + .set_early_control = optc1_set_early_control, + /* used by enable_timing_synchronization. Not need for FPGA */ + .wait_for_state = optc1_wait_for_state, + .set_blank_color = optc3_program_blank_color, + .did_triggered_reset_occur = optc1_did_triggered_reset_occur, + .triplebuffer_lock = optc3_triplebuffer_lock, + .triplebuffer_unlock = optc2_triplebuffer_unlock, + .enable_reset_trigger = optc1_enable_reset_trigger, + .enable_crtc_reset = optc1_enable_crtc_reset, + .disable_reset_trigger = optc1_disable_reset_trigger, + .lock = optc3_lock, + .unlock = optc1_unlock, + .lock_doublebuffer_enable = optc3_lock_doublebuffer_enable, + .lock_doublebuffer_disable = optc3_lock_doublebuffer_disable, + .enable_optc_clock = optc1_enable_optc_clock, + .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 = optc1_set_static_screen_control, + .program_stereo = optc1_program_stereo, + .is_stereo_left_eye = optc1_is_stereo_left_eye, + .tg_init = optc3_tg_init, + .is_tg_enabled = optc1_is_tg_enabled, + .is_optc_underflow_occurred = optc1_is_optc_underflow_occurred, + .clear_optc_underflow = optc1_clear_optc_underflow, + .setup_global_swap_lock = NULL, + .get_crc = optc1_get_crc, + .configure_crc = optc35_configure_crc, + .set_dsc_config = optc3_set_dsc_config, + .get_dsc_status = optc2_get_dsc_status, + .set_dwb_source = NULL, + .set_odm_bypass = optc32_set_odm_bypass, + .set_odm_combine = optc35_set_odm_combine, + .get_optc_source = optc2_get_optc_source, + .set_h_timing_div_manual_mode = optc32_set_h_timing_div_manual_mode, + .set_out_mux = optc3_set_out_mux, + .set_drr_trigger_window = optc3_set_drr_trigger_window, + .set_vtotal_change_limit = optc3_set_vtotal_change_limit, + .set_gsl = optc2_set_gsl, + .set_gsl_source_select = optc2_set_gsl_source_select, + .set_vtg_params = optc1_set_vtg_params, + .program_manual_trigger = optc2_program_manual_trigger, + .setup_manual_trigger = optc2_setup_manual_trigger, + .get_hw_timing = optc1_get_hw_timing, + .init_odm = optc3_init_odm, +}; + +void dcn35_timing_generator_init(struct optc *optc1) +{ + optc1->base.funcs = &dcn35_tg_funcs; + + optc1->max_h_total = optc1->tg_mask->OTG_H_TOTAL + 1; + optc1->max_v_total = optc1->tg_mask->OTG_V_TOTAL + 1; + + optc1->min_h_blank = 32; + optc1->min_v_blank = 3; + optc1->min_v_blank_interlace = 5; + optc1->min_h_sync_width = 4; + optc1->min_v_sync_width = 1; + + dcn35_timing_generator_set_fgcg( + optc1, CTX->dc->debug.enable_fine_grain_clock_gating.bits.optc); +} + +void dcn35_timing_generator_set_fgcg(struct optc *optc1, bool enable) +{ + REG_UPDATE(OPTC_CLOCK_CONTROL, OPTC_FGCG_REP_DIS, !enable); +} diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.h new file mode 100644 index 00000000000000..1f422e4c468f1a --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.h @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: MIT */ +/* + * 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_OPTC_DCN35_H__ +#define __DC_OPTC_DCN35_H__ + +#include "dcn10/dcn10_optc.h" +#include "dcn32/dcn32_optc.h" +#define OPTC_COMMON_MASK_SH_LIST_DCN3_5(mask_sh)\ + OPTC_COMMON_MASK_SH_LIST_DCN3_2(mask_sh),\ + SF(OTG0_OTG_CRC_CNTL, OTG_CRC_WINDOW_DB_EN, mask_sh),\ + SF(OTG0_OTG_CRC1_DATA_RG, CRC1_R_CR, mask_sh),\ + SF(OTG0_OTG_CRC1_DATA_RG, CRC1_G_Y, mask_sh),\ + SF(OTG0_OTG_CRC1_DATA_B, CRC1_B_CB, mask_sh),\ + SF(OTG0_OTG_CRC2_DATA_RG, CRC2_R_CR, mask_sh),\ + SF(OTG0_OTG_CRC2_DATA_RG, CRC2_G_Y, mask_sh),\ + SF(OTG0_OTG_CRC2_DATA_B, CRC2_B_CB, mask_sh),\ + SF(OTG0_OTG_CRC3_DATA_RG, CRC3_R_CR, mask_sh),\ + SF(OTG0_OTG_CRC3_DATA_RG, CRC3_G_Y, mask_sh),\ + SF(OTG0_OTG_CRC3_DATA_B, CRC3_B_CB, mask_sh),\ + SF(OTG0_OTG_CRC1_WINDOWA_X_CONTROL, OTG_CRC1_WINDOWA_X_START, mask_sh),\ + SF(OTG0_OTG_CRC1_WINDOWA_X_CONTROL, OTG_CRC1_WINDOWA_X_END, mask_sh),\ + SF(OTG0_OTG_CRC1_WINDOWA_Y_CONTROL, OTG_CRC1_WINDOWA_Y_START, mask_sh),\ + SF(OTG0_OTG_CRC1_WINDOWA_Y_CONTROL, OTG_CRC1_WINDOWA_Y_END, mask_sh),\ + SF(OTG0_OTG_CRC1_WINDOWB_X_CONTROL, OTG_CRC1_WINDOWB_X_START, mask_sh),\ + SF(OTG0_OTG_CRC1_WINDOWB_X_CONTROL, OTG_CRC1_WINDOWB_X_END, mask_sh),\ + SF(OTG0_OTG_CRC1_WINDOWB_Y_CONTROL, OTG_CRC1_WINDOWB_Y_START, mask_sh),\ + SF(OTG0_OTG_CRC1_WINDOWB_Y_CONTROL, OTG_CRC1_WINDOWB_Y_END, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWA_X_CONTROL_READBACK, OTG_CRC0_WINDOWA_X_START_READBACK, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWA_X_CONTROL_READBACK, OTG_CRC0_WINDOWA_X_END_READBACK, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWA_Y_CONTROL_READBACK, OTG_CRC0_WINDOWA_Y_START_READBACK, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWA_Y_CONTROL_READBACK, OTG_CRC0_WINDOWA_Y_END_READBACK, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWB_X_CONTROL_READBACK, OTG_CRC0_WINDOWB_X_START_READBACK, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWB_X_CONTROL_READBACK, OTG_CRC0_WINDOWB_X_END_READBACK, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL_READBACK, OTG_CRC0_WINDOWB_Y_START_READBACK, mask_sh),\ + SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL_READBACK, OTG_CRC0_WINDOWB_Y_END_READBACK, mask_sh),\ + SF(OTG0_OTG_CRC1_WINDOWA_X_CONTROL_READBACK, OTG_CRC1_WINDOWA_X_START_READBACK, mask_sh),\ + SF(OTG0_OTG_CRC1_WINDOWA_X_CONTROL_READBACK, OTG_CRC1_WINDOWA_X_END_READBACK, mask_sh),\ + SF(OTG0_OTG_CRC1_WINDOWA_Y_CONTROL_READBACK, OTG_CRC1_WINDOWA_Y_START_READBACK, mask_sh),\ + SF(OTG0_OTG_CRC1_WINDOWA_Y_CONTROL_READBACK, OTG_CRC1_WINDOWA_Y_END_READBACK, mask_sh),\ + SF(OTG0_OTG_CRC1_WINDOWB_X_CONTROL_READBACK, OTG_CRC1_WINDOWB_X_START_READBACK, mask_sh),\ + SF(OTG0_OTG_CRC1_WINDOWB_X_CONTROL_READBACK, OTG_CRC1_WINDOWB_X_END_READBACK, mask_sh),\ + SF(OTG0_OTG_CRC1_WINDOWB_Y_CONTROL_READBACK, OTG_CRC1_WINDOWB_Y_START_READBACK, mask_sh),\ + SF(OTG0_OTG_CRC1_WINDOWB_Y_CONTROL_READBACK, OTG_CRC1_WINDOWB_Y_END_READBACK, mask_sh),\ + SF(OPTC_CLOCK_CONTROL, OPTC_FGCG_REP_DIS, mask_sh) + +void dcn35_timing_generator_init(struct optc *optc1); + +void dcn35_timing_generator_set_fgcg(struct optc *optc1, bool enable); + +#endif /* __DC_OPTC_DCN35_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/resource/Makefile b/drivers/gpu/drm/amd/display/dc/resource/Makefile new file mode 100644 index 00000000000000..0a75ed8962a559 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/Makefile @@ -0,0 +1,199 @@ + +# 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. +# +# Makefile for the 'resource' sub-component of DAL. +# + + +############################################################################### +# DCE +############################################################################### + +RESOURCE_DCE100 = dce100_resource.o + +AMD_DAL_RESOURCE_DCE100 = $(addprefix $(AMDDALPATH)/dc/resource/dce100/,$(RESOURCE_DCE100)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCE100) + +############################################################################### + +RESOURCE_DCE110 = dce110_resource.o + +AMD_DAL_RESOURCE_DCE110 = $(addprefix $(AMDDALPATH)/dc/resource/dce110/,$(RESOURCE_DCE110)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCE110) + +############################################################################### + +RESOURCE_DCE112 = dce112_resource.o + +AMD_DAL_RESOURCE_DCE112 = $(addprefix $(AMDDALPATH)/dc/resource/dce112/,$(RESOURCE_DCE112)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCE112) + +############################################################################### + +RESOURCE_DCE120 = dce120_resource.o + +AMD_DAL_RESOURCE_DCE120 = $(addprefix $(AMDDALPATH)/dc/resource/dce120/,$(RESOURCE_DCE120)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCE120) + +############################################################################### + +RESOURCE_DCE80 = dce80_resource.o + +AMD_DAL_RESOURCE_DCE80 = $(addprefix $(AMDDALPATH)/dc/resource/dce80/,$(RESOURCE_DCE80)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCE80) + +ifdef CONFIG_DRM_AMD_DC_FP +############################################################################### +# DCN +############################################################################### + +RESOURCE_DCN10 = dcn10_resource.o + +AMD_DAL_RESOURCE_DCN10 = $(addprefix $(AMDDALPATH)/dc/resource/dcn10/,$(RESOURCE_DCN10)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCN10) + +############################################################################### + +RESOURCE_DCN20 = dcn20_resource.o + +AMD_DAL_RESOURCE_DCN20 = $(addprefix $(AMDDALPATH)/dc/resource/dcn20/,$(RESOURCE_DCN20)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCN20) + +############################################################################### + +RESOURCE_DCN201 = dcn201_resource.o + +AMD_DAL_RESOURCE_DCN201 = $(addprefix $(AMDDALPATH)/dc/resource/dcn201/,$(RESOURCE_DCN201)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCN201) + +############################################################################### + +RESOURCE_DCN21 = dcn21_resource.o + +AMD_DAL_RESOURCE_DCN21 = $(addprefix $(AMDDALPATH)/dc/resource/dcn21/,$(RESOURCE_DCN21)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCN21) + +############################################################################### + +############################################################################### + +############################################################################### + +RESOURCE_DCN30 = dcn30_resource.o + +AMD_DAL_RESOURCE_DCN30 = $(addprefix $(AMDDALPATH)/dc/resource/dcn30/,$(RESOURCE_DCN30)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCN30) + +############################################################################### + +RESOURCE_DCN301 = dcn301_resource.o + +AMD_DAL_RESOURCE_DCN301 = $(addprefix $(AMDDALPATH)/dc/resource/dcn301/,$(RESOURCE_DCN301)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCN301) + +############################################################################### + +RESOURCE_DCN302 = dcn302_resource.o + +AMD_DAL_RESOURCE_DCN302 = $(addprefix $(AMDDALPATH)/dc/resource/dcn302/,$(RESOURCE_DCN302)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCN302) + +############################################################################### + +RESOURCE_DCN303 = dcn303_resource.o + +AMD_DAL_RESOURCE_DCN303 = $(addprefix $(AMDDALPATH)/dc/resource/dcn303/,$(RESOURCE_DCN303)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCN303) + +############################################################################### + +RESOURCE_DCN31 = dcn31_resource.o + +AMD_DAL_RESOURCE_DCN31 = $(addprefix $(AMDDALPATH)/dc/resource/dcn31/,$(RESOURCE_DCN31)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCN31) + +############################################################################### + +RESOURCE_DCN314 = dcn314_resource.o + +AMD_DAL_RESOURCE_DCN314 = $(addprefix $(AMDDALPATH)/dc/resource/dcn314/,$(RESOURCE_DCN314)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCN314) + +############################################################################### + +RESOURCE_DCN315 = dcn315_resource.o + +AMD_DAL_RESOURCE_DCN315 = $(addprefix $(AMDDALPATH)/dc/resource/dcn315/,$(RESOURCE_DCN315)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCN315) + +############################################################################### + +RESOURCE_DCN316 = dcn316_resource.o + +AMD_DAL_RESOURCE_DCN316 = $(addprefix $(AMDDALPATH)/dc/resource/dcn316/,$(RESOURCE_DCN316)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCN316) + +############################################################################### + +RESOURCE_DCN32 = dcn32_resource.o + +AMD_DAL_RESOURCE_DCN32 = $(addprefix $(AMDDALPATH)/dc/resource/dcn32/,$(RESOURCE_DCN32)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCN32) + +############################################################################### + +RESOURCE_DCN321 = dcn321_resource.o + +AMD_DAL_RESOURCE_DCN321 = $(addprefix $(AMDDALPATH)/dc/resource/dcn321/,$(RESOURCE_DCN321)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCN321) + +############################################################################### + +RESOURCE_DCN35 = dcn35_resource.o + +AMD_DAL_RESOURCE_DCN35 = $(addprefix $(AMDDALPATH)/dc/resource/dcn35/,$(RESOURCE_DCN35)) + +AMD_DISPLAY_FILES += $(AMD_DAL_RESOURCE_DCN35) + +############################################################################### + +############################################################################### + +endif diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c new file mode 100644 index 00000000000000..53a5f4cb648cbd --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c @@ -0,0 +1,1179 @@ +/* + * 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 + * + */ + +#include "dm_services.h" + +#include "link_encoder.h" +#include "stream_encoder.h" + +#include "resource.h" +#include "include/irq_service_interface.h" +#include "virtual/virtual_stream_encoder.h" +#include "dce110/dce110_resource.h" +#include "dce110/dce110_timing_generator.h" +#include "irq/dce110/irq_service_dce110.h" +#include "dce/dce_link_encoder.h" +#include "dce/dce_stream_encoder.h" +#include "dce/dce_mem_input.h" +#include "dce/dce_ipp.h" +#include "dce/dce_transform.h" +#include "dce/dce_opp.h" +#include "dce/dce_clock_source.h" +#include "dce/dce_audio.h" +#include "dce/dce_hwseq.h" +#include "dce100/dce100_hwseq.h" +#include "dce/dce_panel_cntl.h" + +#include "reg_helper.h" + +#include "dce/dce_10_0_d.h" +#include "dce/dce_10_0_sh_mask.h" + +#include "dce/dce_dmcu.h" +#include "dce/dce_aux.h" +#include "dce/dce_abm.h" +#include "dce/dce_i2c.h" + +#include "dce100_resource.h" + +#ifndef mmMC_HUB_RDREQ_DMIF_LIMIT +#include "gmc/gmc_8_2_d.h" +#include "gmc/gmc_8_2_sh_mask.h" +#endif + +#ifndef mmDP_DPHY_INTERNAL_CTRL + #define mmDP_DPHY_INTERNAL_CTRL 0x4aa7 + #define mmDP0_DP_DPHY_INTERNAL_CTRL 0x4aa7 + #define mmDP1_DP_DPHY_INTERNAL_CTRL 0x4ba7 + #define mmDP2_DP_DPHY_INTERNAL_CTRL 0x4ca7 + #define mmDP3_DP_DPHY_INTERNAL_CTRL 0x4da7 + #define mmDP4_DP_DPHY_INTERNAL_CTRL 0x4ea7 + #define mmDP5_DP_DPHY_INTERNAL_CTRL 0x4fa7 + #define mmDP6_DP_DPHY_INTERNAL_CTRL 0x54a7 + #define mmDP7_DP_DPHY_INTERNAL_CTRL 0x56a7 + #define mmDP8_DP_DPHY_INTERNAL_CTRL 0x57a7 +#endif + +#ifndef mmBIOS_SCRATCH_2 + #define mmBIOS_SCRATCH_2 0x05CB + #define mmBIOS_SCRATCH_3 0x05CC + #define mmBIOS_SCRATCH_6 0x05CF +#endif + +#ifndef mmDP_DPHY_BS_SR_SWAP_CNTL + #define mmDP_DPHY_BS_SR_SWAP_CNTL 0x4ADC + #define mmDP0_DP_DPHY_BS_SR_SWAP_CNTL 0x4ADC + #define mmDP1_DP_DPHY_BS_SR_SWAP_CNTL 0x4BDC + #define mmDP2_DP_DPHY_BS_SR_SWAP_CNTL 0x4CDC + #define mmDP3_DP_DPHY_BS_SR_SWAP_CNTL 0x4DDC + #define mmDP4_DP_DPHY_BS_SR_SWAP_CNTL 0x4EDC + #define mmDP5_DP_DPHY_BS_SR_SWAP_CNTL 0x4FDC + #define mmDP6_DP_DPHY_BS_SR_SWAP_CNTL 0x54DC +#endif + +#ifndef mmDP_DPHY_FAST_TRAINING + #define mmDP_DPHY_FAST_TRAINING 0x4ABC + #define mmDP0_DP_DPHY_FAST_TRAINING 0x4ABC + #define mmDP1_DP_DPHY_FAST_TRAINING 0x4BBC + #define mmDP2_DP_DPHY_FAST_TRAINING 0x4CBC + #define mmDP3_DP_DPHY_FAST_TRAINING 0x4DBC + #define mmDP4_DP_DPHY_FAST_TRAINING 0x4EBC + #define mmDP5_DP_DPHY_FAST_TRAINING 0x4FBC + #define mmDP6_DP_DPHY_FAST_TRAINING 0x54BC +#endif + +static const struct dce110_timing_generator_offsets dce100_tg_offsets[] = { + { + .crtc = (mmCRTC0_CRTC_CONTROL - mmCRTC_CONTROL), + .dcp = (mmDCP0_GRPH_CONTROL - mmGRPH_CONTROL), + }, + { + .crtc = (mmCRTC1_CRTC_CONTROL - mmCRTC_CONTROL), + .dcp = (mmDCP1_GRPH_CONTROL - mmGRPH_CONTROL), + }, + { + .crtc = (mmCRTC2_CRTC_CONTROL - mmCRTC_CONTROL), + .dcp = (mmDCP2_GRPH_CONTROL - mmGRPH_CONTROL), + }, + { + .crtc = (mmCRTC3_CRTC_CONTROL - mmCRTC_CONTROL), + .dcp = (mmDCP3_GRPH_CONTROL - mmGRPH_CONTROL), + }, + { + .crtc = (mmCRTC4_CRTC_CONTROL - mmCRTC_CONTROL), + .dcp = (mmDCP4_GRPH_CONTROL - mmGRPH_CONTROL), + }, + { + .crtc = (mmCRTC5_CRTC_CONTROL - mmCRTC_CONTROL), + .dcp = (mmDCP5_GRPH_CONTROL - mmGRPH_CONTROL), + } +}; + +/* set register offset */ +#define SR(reg_name)\ + .reg_name = mm ## reg_name + +/* set register offset with instance */ +#define SRI(reg_name, block, id)\ + .reg_name = mm ## block ## id ## _ ## reg_name + +#define ipp_regs(id)\ +[id] = {\ + IPP_DCE100_REG_LIST_DCE_BASE(id)\ +} + +static const struct dce_ipp_registers ipp_regs[] = { + ipp_regs(0), + ipp_regs(1), + ipp_regs(2), + ipp_regs(3), + ipp_regs(4), + ipp_regs(5) +}; + +static const struct dce_ipp_shift ipp_shift = { + IPP_DCE100_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) +}; + +static const struct dce_ipp_mask ipp_mask = { + IPP_DCE100_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) +}; + +#define transform_regs(id)\ +[id] = {\ + XFM_COMMON_REG_LIST_DCE100(id)\ +} + +static const struct dce_transform_registers xfm_regs[] = { + transform_regs(0), + transform_regs(1), + transform_regs(2), + transform_regs(3), + transform_regs(4), + transform_regs(5) +}; + +static const struct dce_transform_shift xfm_shift = { + XFM_COMMON_MASK_SH_LIST_DCE110(__SHIFT) +}; + +static const struct dce_transform_mask xfm_mask = { + XFM_COMMON_MASK_SH_LIST_DCE110(_MASK) +}; + +#define aux_regs(id)\ +[id] = {\ + AUX_REG_LIST(id)\ +} + +static const struct dce110_link_enc_aux_registers link_enc_aux_regs[] = { + aux_regs(0), + aux_regs(1), + aux_regs(2), + aux_regs(3), + aux_regs(4), + aux_regs(5) +}; + +#define hpd_regs(id)\ +[id] = {\ + HPD_REG_LIST(id)\ +} + +static const struct dce110_link_enc_hpd_registers link_enc_hpd_regs[] = { + hpd_regs(0), + hpd_regs(1), + hpd_regs(2), + hpd_regs(3), + hpd_regs(4), + hpd_regs(5) +}; + +#define link_regs(id)\ +[id] = {\ + LE_DCE100_REG_LIST(id)\ +} + +static const struct dce110_link_enc_registers link_enc_regs[] = { + link_regs(0), + link_regs(1), + link_regs(2), + link_regs(3), + link_regs(4), + link_regs(5), + link_regs(6), +}; + +#define stream_enc_regs(id)\ +[id] = {\ + SE_COMMON_REG_LIST_DCE_BASE(id),\ + .AFMT_CNTL = 0,\ +} + +static const struct dce110_stream_enc_registers stream_enc_regs[] = { + stream_enc_regs(0), + stream_enc_regs(1), + stream_enc_regs(2), + stream_enc_regs(3), + stream_enc_regs(4), + stream_enc_regs(5), + stream_enc_regs(6) +}; + +static const struct dce_stream_encoder_shift se_shift = { + SE_COMMON_MASK_SH_LIST_DCE80_100(__SHIFT) +}; + +static const struct dce_stream_encoder_mask se_mask = { + SE_COMMON_MASK_SH_LIST_DCE80_100(_MASK) +}; + +static const struct dce_panel_cntl_registers panel_cntl_regs[] = { + { DCE_PANEL_CNTL_REG_LIST() } +}; + +static const struct dce_panel_cntl_shift panel_cntl_shift = { + DCE_PANEL_CNTL_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_panel_cntl_mask panel_cntl_mask = { + DCE_PANEL_CNTL_MASK_SH_LIST(_MASK) +}; + +#define opp_regs(id)\ +[id] = {\ + OPP_DCE_100_REG_LIST(id),\ +} + +static const struct dce_opp_registers opp_regs[] = { + opp_regs(0), + opp_regs(1), + opp_regs(2), + opp_regs(3), + opp_regs(4), + opp_regs(5) +}; + +static const struct dce_opp_shift opp_shift = { + OPP_COMMON_MASK_SH_LIST_DCE_100(__SHIFT) +}; + +static const struct dce_opp_mask opp_mask = { + OPP_COMMON_MASK_SH_LIST_DCE_100(_MASK) +}; +#define aux_engine_regs(id)\ +[id] = {\ + AUX_COMMON_REG_LIST(id), \ + .AUX_RESET_MASK = 0 \ +} + +static const struct dce110_aux_registers aux_engine_regs[] = { + aux_engine_regs(0), + aux_engine_regs(1), + aux_engine_regs(2), + aux_engine_regs(3), + aux_engine_regs(4), + aux_engine_regs(5) +}; + +#define audio_regs(id)\ +[id] = {\ + AUD_COMMON_REG_LIST(id)\ +} + +static const struct dce_audio_registers audio_regs[] = { + audio_regs(0), + audio_regs(1), + audio_regs(2), + audio_regs(3), + audio_regs(4), + audio_regs(5), + audio_regs(6), +}; + +static const struct dce_audio_shift audio_shift = { + AUD_COMMON_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_audio_mask audio_mask = { + AUD_COMMON_MASK_SH_LIST(_MASK) +}; + +#define clk_src_regs(id)\ +[id] = {\ + CS_COMMON_REG_LIST_DCE_100_110(id),\ +} + +static const struct dce110_clk_src_regs clk_src_regs[] = { + clk_src_regs(0), + clk_src_regs(1), + clk_src_regs(2) +}; + +static const struct dce110_clk_src_shift cs_shift = { + CS_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) +}; + +static const struct dce110_clk_src_mask cs_mask = { + CS_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) +}; + +static const struct dce_dmcu_registers dmcu_regs = { + DMCU_DCE110_COMMON_REG_LIST() +}; + +static const struct dce_dmcu_shift dmcu_shift = { + DMCU_MASK_SH_LIST_DCE110(__SHIFT) +}; + +static const struct dce_dmcu_mask dmcu_mask = { + DMCU_MASK_SH_LIST_DCE110(_MASK) +}; + +static const struct dce_abm_registers abm_regs = { + ABM_DCE110_COMMON_REG_LIST() +}; + +static const struct dce_abm_shift abm_shift = { + ABM_MASK_SH_LIST_DCE110(__SHIFT) +}; + +static const struct dce_abm_mask abm_mask = { + ABM_MASK_SH_LIST_DCE110(_MASK) +}; + +#define DCFE_MEM_PWR_CTRL_REG_BASE 0x1b03 + +static const struct bios_registers bios_regs = { + .BIOS_SCRATCH_3 = mmBIOS_SCRATCH_3, + .BIOS_SCRATCH_6 = mmBIOS_SCRATCH_6 +}; + +static const struct resource_caps res_cap = { + .num_timing_generator = 6, + .num_audio = 6, + .num_stream_encoder = 6, + .num_pll = 3, + .num_ddc = 6, +}; + +static const struct dc_plane_cap plane_cap = { + .type = DC_PLANE_TYPE_DCE_RGB, + + .pixel_format_support = { + .argb8888 = true, + .nv12 = false, + .fp16 = true + }, + + .max_upscale_factor = { + .argb8888 = 16000, + .nv12 = 1, + .fp16 = 1 + }, + + .max_downscale_factor = { + .argb8888 = 250, + .nv12 = 1, + .fp16 = 1 + } +}; + +static const struct dc_debug_options debug_defaults = { + .enable_legacy_fast_update = true, +}; + +#define CTX ctx +#define REG(reg) mm ## reg + +#ifndef mmCC_DC_HDMI_STRAPS +#define mmCC_DC_HDMI_STRAPS 0x1918 +#define CC_DC_HDMI_STRAPS__HDMI_DISABLE_MASK 0x40 +#define CC_DC_HDMI_STRAPS__HDMI_DISABLE__SHIFT 0x6 +#define CC_DC_HDMI_STRAPS__AUDIO_STREAM_NUMBER_MASK 0x700 +#define CC_DC_HDMI_STRAPS__AUDIO_STREAM_NUMBER__SHIFT 0x8 +#endif + +static int map_transmitter_id_to_phy_instance( + enum transmitter transmitter) +{ + switch (transmitter) { + case TRANSMITTER_UNIPHY_A: + return 0; + case TRANSMITTER_UNIPHY_B: + return 1; + case TRANSMITTER_UNIPHY_C: + return 2; + case TRANSMITTER_UNIPHY_D: + return 3; + case TRANSMITTER_UNIPHY_E: + return 4; + case TRANSMITTER_UNIPHY_F: + return 5; + case TRANSMITTER_UNIPHY_G: + return 6; + default: + ASSERT(0); + return 0; + } +} + +static void read_dce_straps( + struct dc_context *ctx, + struct resource_straps *straps) +{ + REG_GET_2(CC_DC_HDMI_STRAPS, + HDMI_DISABLE, &straps->hdmi_disable, + AUDIO_STREAM_NUMBER, &straps->audio_stream_number); + + REG_GET(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO, &straps->dc_pinstraps_audio); +} + +static struct audio *create_audio( + struct dc_context *ctx, unsigned int inst) +{ + return dce_audio_create(ctx, inst, + &audio_regs[inst], &audio_shift, &audio_mask); +} + +static struct timing_generator *dce100_timing_generator_create( + struct dc_context *ctx, + uint32_t instance, + const struct dce110_timing_generator_offsets *offsets) +{ + struct dce110_timing_generator *tg110 = + kzalloc(sizeof(struct dce110_timing_generator), GFP_KERNEL); + + if (!tg110) + return NULL; + + dce110_timing_generator_construct(tg110, ctx, instance, offsets); + return &tg110->base; +} + +static struct stream_encoder *dce100_stream_encoder_create( + enum engine_id eng_id, + struct dc_context *ctx) +{ + struct dce110_stream_encoder *enc110 = + kzalloc(sizeof(struct dce110_stream_encoder), GFP_KERNEL); + + if (!enc110) + return NULL; + + dce110_stream_encoder_construct(enc110, ctx, ctx->dc_bios, eng_id, + &stream_enc_regs[eng_id], &se_shift, &se_mask); + return &enc110->base; +} + +#define SRII(reg_name, block, id)\ + .reg_name[id] = mm ## block ## id ## _ ## reg_name + +static const struct dce_hwseq_registers hwseq_reg = { + HWSEQ_DCE10_REG_LIST() +}; + +static const struct dce_hwseq_shift hwseq_shift = { + HWSEQ_DCE10_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_hwseq_mask hwseq_mask = { + HWSEQ_DCE10_MASK_SH_LIST(_MASK) +}; + +static struct dce_hwseq *dce100_hwseq_create( + struct dc_context *ctx) +{ + struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); + + if (hws) { + hws->ctx = ctx; + hws->regs = &hwseq_reg; + hws->shifts = &hwseq_shift; + hws->masks = &hwseq_mask; + } + return hws; +} + +static const struct resource_create_funcs res_create_funcs = { + .read_dce_straps = read_dce_straps, + .create_audio = create_audio, + .create_stream_encoder = dce100_stream_encoder_create, + .create_hwseq = dce100_hwseq_create, +}; + +#define mi_inst_regs(id) { \ + MI_DCE8_REG_LIST(id), \ + .MC_HUB_RDREQ_DMIF_LIMIT = mmMC_HUB_RDREQ_DMIF_LIMIT \ +} +static const struct dce_mem_input_registers mi_regs[] = { + mi_inst_regs(0), + mi_inst_regs(1), + mi_inst_regs(2), + mi_inst_regs(3), + mi_inst_regs(4), + mi_inst_regs(5), +}; + +static const struct dce_mem_input_shift mi_shifts = { + MI_DCE8_MASK_SH_LIST(__SHIFT), + .ENABLE = MC_HUB_RDREQ_DMIF_LIMIT__ENABLE__SHIFT +}; + +static const struct dce_mem_input_mask mi_masks = { + MI_DCE8_MASK_SH_LIST(_MASK), + .ENABLE = MC_HUB_RDREQ_DMIF_LIMIT__ENABLE_MASK +}; + +static const struct dce110_aux_registers_shift aux_shift = { + DCE10_AUX_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce110_aux_registers_mask aux_mask = { + DCE10_AUX_MASK_SH_LIST(_MASK) +}; + +static struct mem_input *dce100_mem_input_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce_mem_input *dce_mi = kzalloc(sizeof(struct dce_mem_input), + GFP_KERNEL); + + if (!dce_mi) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dce_mem_input_construct(dce_mi, ctx, inst, &mi_regs[inst], &mi_shifts, &mi_masks); + dce_mi->wa.single_head_rdreq_dmif_limit = 2; + return &dce_mi->base; +} + +static void dce100_transform_destroy(struct transform **xfm) +{ + kfree(TO_DCE_TRANSFORM(*xfm)); + *xfm = NULL; +} + +static struct transform *dce100_transform_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce_transform *transform = + kzalloc(sizeof(struct dce_transform), GFP_KERNEL); + + if (!transform) + return NULL; + + dce_transform_construct(transform, ctx, inst, + &xfm_regs[inst], &xfm_shift, &xfm_mask); + return &transform->base; +} + +static struct input_pixel_processor *dce100_ipp_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dce_ipp *ipp = kzalloc(sizeof(struct dce_ipp), GFP_KERNEL); + + if (!ipp) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dce_ipp_construct(ipp, ctx, inst, + &ipp_regs[inst], &ipp_shift, &ipp_mask); + return &ipp->base; +} + +static const struct encoder_feature_support link_enc_feature = { + .max_hdmi_deep_color = COLOR_DEPTH_121212, + .max_hdmi_pixel_clock = 300000, + .flags.bits.IS_HBR2_CAPABLE = true, + .flags.bits.IS_TPS3_CAPABLE = true +}; + +static struct link_encoder *dce100_link_encoder_create( + struct dc_context *ctx, + const struct encoder_init_data *enc_init_data) +{ + struct dce110_link_encoder *enc110 = + kzalloc(sizeof(struct dce110_link_encoder), GFP_KERNEL); + int link_regs_id; + + if (!enc110) + return NULL; + + link_regs_id = + map_transmitter_id_to_phy_instance(enc_init_data->transmitter); + + dce110_link_encoder_construct(enc110, + enc_init_data, + &link_enc_feature, + &link_enc_regs[link_regs_id], + &link_enc_aux_regs[enc_init_data->channel - 1], + &link_enc_hpd_regs[enc_init_data->hpd_source]); + return &enc110->base; +} + +static struct panel_cntl *dce100_panel_cntl_create(const struct panel_cntl_init_data *init_data) +{ + struct dce_panel_cntl *panel_cntl = + kzalloc(sizeof(struct dce_panel_cntl), GFP_KERNEL); + + if (!panel_cntl) + return NULL; + + dce_panel_cntl_construct(panel_cntl, + init_data, + &panel_cntl_regs[init_data->inst], + &panel_cntl_shift, + &panel_cntl_mask); + + return &panel_cntl->base; +} + +static struct output_pixel_processor *dce100_opp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce110_opp *opp = + kzalloc(sizeof(struct dce110_opp), GFP_KERNEL); + + if (!opp) + return NULL; + + dce110_opp_construct(opp, + ctx, inst, &opp_regs[inst], &opp_shift, &opp_mask); + return &opp->base; +} + +static struct dce_aux *dce100_aux_engine_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct aux_engine_dce110 *aux_engine = + kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); + + if (!aux_engine) + return NULL; + + dce110_aux_engine_construct(aux_engine, ctx, inst, + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, + &aux_engine_regs[inst], + &aux_mask, + &aux_shift, + ctx->dc->caps.extended_aux_timeout_support); + + return &aux_engine->base; +} +#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST(id) } + +static const struct dce_i2c_registers i2c_hw_regs[] = { + i2c_inst_regs(1), + i2c_inst_regs(2), + i2c_inst_regs(3), + i2c_inst_regs(4), + i2c_inst_regs(5), + i2c_inst_regs(6), +}; + +static const struct dce_i2c_shift i2c_shifts = { + I2C_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) +}; + +static const struct dce_i2c_mask i2c_masks = { + I2C_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) +}; + +static struct dce_i2c_hw *dce100_i2c_hw_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce_i2c_hw *dce_i2c_hw = + kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); + + if (!dce_i2c_hw) + return NULL; + + dce100_i2c_hw_construct(dce_i2c_hw, ctx, inst, + &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); + + return dce_i2c_hw; +} +static struct clock_source *dce100_clock_source_create( + struct dc_context *ctx, + struct dc_bios *bios, + enum clock_source_id id, + const struct dce110_clk_src_regs *regs, + bool dp_clk_src) +{ + struct dce110_clk_src *clk_src = + kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); + + if (!clk_src) + return NULL; + + if (dce110_clk_src_construct(clk_src, ctx, bios, id, + regs, &cs_shift, &cs_mask)) { + clk_src->base.dp_clk_src = dp_clk_src; + return &clk_src->base; + } + + kfree(clk_src); + BREAK_TO_DEBUGGER(); + return NULL; +} + +static void dce100_clock_source_destroy(struct clock_source **clk_src) +{ + kfree(TO_DCE110_CLK_SRC(*clk_src)); + *clk_src = NULL; +} + +static void dce100_resource_destruct(struct dce110_resource_pool *pool) +{ + unsigned int i; + + for (i = 0; i < pool->base.pipe_count; i++) { + if (pool->base.opps[i] != NULL) + dce110_opp_destroy(&pool->base.opps[i]); + + if (pool->base.transforms[i] != NULL) + dce100_transform_destroy(&pool->base.transforms[i]); + + if (pool->base.ipps[i] != NULL) + dce_ipp_destroy(&pool->base.ipps[i]); + + if (pool->base.mis[i] != NULL) { + kfree(TO_DCE_MEM_INPUT(pool->base.mis[i])); + pool->base.mis[i] = NULL; + } + + if (pool->base.timing_generators[i] != NULL) { + kfree(DCE110TG_FROM_TG(pool->base.timing_generators[i])); + pool->base.timing_generators[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + if (pool->base.engines[i] != NULL) + dce110_engine_destroy(&pool->base.engines[i]); + if (pool->base.hw_i2cs[i] != NULL) { + kfree(pool->base.hw_i2cs[i]); + pool->base.hw_i2cs[i] = NULL; + } + if (pool->base.sw_i2cs[i] != NULL) { + kfree(pool->base.sw_i2cs[i]); + pool->base.sw_i2cs[i] = NULL; + } + } + + for (i = 0; i < pool->base.stream_enc_count; i++) { + if (pool->base.stream_enc[i] != NULL) + kfree(DCE110STRENC_FROM_STRENC(pool->base.stream_enc[i])); + } + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] != NULL) + dce100_clock_source_destroy(&pool->base.clock_sources[i]); + } + + if (pool->base.dp_clock_source != NULL) + dce100_clock_source_destroy(&pool->base.dp_clock_source); + + for (i = 0; i < pool->base.audio_count; i++) { + if (pool->base.audios[i] != NULL) + dce_aud_destroy(&pool->base.audios[i]); + } + + if (pool->base.abm != NULL) + dce_abm_destroy(&pool->base.abm); + + if (pool->base.dmcu != NULL) + dce_dmcu_destroy(&pool->base.dmcu); + + if (pool->base.irqs != NULL) + dal_irq_service_destroy(&pool->base.irqs); +} + +static enum dc_status build_mapped_resource( + const struct dc *dc, + struct dc_state *context, + struct dc_stream_state *stream) +{ + struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream); + + if (!pipe_ctx) + return DC_ERROR_UNEXPECTED; + + dce110_resource_build_pipe_hw_param(pipe_ctx); + + resource_build_info_frame(pipe_ctx); + + return DC_OK; +} + +static bool dce100_validate_bandwidth( + struct dc *dc, + struct dc_state *context, + bool fast_validate) +{ + int i; + bool at_least_one_pipe = false; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + if (context->res_ctx.pipe_ctx[i].stream) + at_least_one_pipe = true; + } + + if (at_least_one_pipe) { + /* TODO implement when needed but for now hardcode max value*/ + context->bw_ctx.bw.dce.dispclk_khz = 681000; + context->bw_ctx.bw.dce.yclk_khz = 250000 * MEMORY_TYPE_MULTIPLIER_CZ; + } else { + context->bw_ctx.bw.dce.dispclk_khz = 0; + context->bw_ctx.bw.dce.yclk_khz = 0; + } + + return true; +} + +static bool dce100_validate_surface_sets( + struct dc_state *context) +{ + int i; + + for (i = 0; i < context->stream_count; i++) { + if (context->stream_status[i].plane_count == 0) + continue; + + if (context->stream_status[i].plane_count > 1) + return false; + + if (context->stream_status[i].plane_states[0]->format + >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) + return false; + } + + return true; +} + +static enum dc_status dce100_validate_global( + struct dc *dc, + struct dc_state *context) +{ + if (!dce100_validate_surface_sets(context)) + return DC_FAIL_SURFACE_VALIDATE; + + return DC_OK; +} + +enum dc_status dce100_add_stream_to_ctx( + struct dc *dc, + struct dc_state *new_ctx, + struct dc_stream_state *dc_stream) +{ + enum dc_status result = DC_ERROR_UNEXPECTED; + + result = resource_map_pool_resources(dc, new_ctx, dc_stream); + + if (result == DC_OK) + result = resource_map_clock_resources(dc, new_ctx, dc_stream); + + if (result == DC_OK) + result = build_mapped_resource(dc, new_ctx, dc_stream); + + return result; +} + +static void dce100_destroy_resource_pool(struct resource_pool **pool) +{ + struct dce110_resource_pool *dce110_pool = TO_DCE110_RES_POOL(*pool); + + dce100_resource_destruct(dce110_pool); + kfree(dce110_pool); + *pool = NULL; +} + +enum dc_status dce100_validate_plane(const struct dc_plane_state *plane_state, struct dc_caps *caps) +{ + + if (plane_state->format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) + return DC_OK; + + return DC_FAIL_SURFACE_VALIDATE; +} + +struct stream_encoder *dce100_find_first_free_match_stream_enc_for_link( + struct resource_context *res_ctx, + const struct resource_pool *pool, + struct dc_stream_state *stream) +{ + int i; + int j = -1; + struct dc_link *link = stream->link; + + for (i = 0; i < pool->stream_enc_count; i++) { + if (!res_ctx->is_stream_enc_acquired[i] && + pool->stream_enc[i]) { + /* Store first available for MST second display + * in daisy chain use case + */ + j = i; + if (pool->stream_enc[i]->id == + link->link_enc->preferred_engine) + return pool->stream_enc[i]; + } + } + + /* + * below can happen in cases when stream encoder is acquired: + * 1) for second MST display in chain, so preferred engine already + * acquired; + * 2) for another link, which preferred engine already acquired by any + * MST configuration. + * + * If signal is of DP type and preferred engine not found, return last available + * + * TODO - This is just a patch up and a generic solution is + * required for non DP connectors. + */ + + if (j >= 0 && link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT) + return pool->stream_enc[j]; + + return NULL; +} + +static const struct resource_funcs dce100_res_pool_funcs = { + .destroy = dce100_destroy_resource_pool, + .link_enc_create = dce100_link_encoder_create, + .panel_cntl_create = dce100_panel_cntl_create, + .validate_bandwidth = dce100_validate_bandwidth, + .validate_plane = dce100_validate_plane, + .add_stream_to_ctx = dce100_add_stream_to_ctx, + .validate_global = dce100_validate_global, + .find_first_free_match_stream_enc_for_link = dce100_find_first_free_match_stream_enc_for_link +}; + +static bool dce100_resource_construct( + uint8_t num_virtual_links, + struct dc *dc, + struct dce110_resource_pool *pool) +{ + unsigned int i; + struct dc_context *ctx = dc->ctx; + struct dc_bios *bp; + + ctx->dc_bios->regs = &bios_regs; + + pool->base.res_cap = &res_cap; + pool->base.funcs = &dce100_res_pool_funcs; + pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + + bp = ctx->dc_bios; + + if (bp->fw_info_valid && bp->fw_info.external_clock_source_frequency_for_dp != 0) { + pool->base.dp_clock_source = + dce100_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_EXTERNAL, NULL, true); + + pool->base.clock_sources[0] = + dce100_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL0, &clk_src_regs[0], false); + pool->base.clock_sources[1] = + dce100_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL1, &clk_src_regs[1], false); + pool->base.clock_sources[2] = + dce100_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL2, &clk_src_regs[2], false); + pool->base.clk_src_count = 3; + + } else { + pool->base.dp_clock_source = + dce100_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL0, &clk_src_regs[0], true); + + pool->base.clock_sources[0] = + dce100_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL1, &clk_src_regs[1], false); + pool->base.clock_sources[1] = + dce100_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL2, &clk_src_regs[2], false); + pool->base.clk_src_count = 2; + } + + if (pool->base.dp_clock_source == NULL) { + dm_error("DC: failed to create dp clock source!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] == NULL) { + dm_error("DC: failed to create clock sources!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + } + + pool->base.dmcu = dce_dmcu_create(ctx, + &dmcu_regs, + &dmcu_shift, + &dmcu_mask); + if (pool->base.dmcu == NULL) { + dm_error("DC: failed to create dmcu!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + pool->base.abm = dce_abm_create(ctx, + &abm_regs, + &abm_shift, + &abm_mask); + if (pool->base.abm == NULL) { + dm_error("DC: failed to create abm!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + { + struct irq_service_init_data init_data; + init_data.ctx = dc->ctx; + pool->base.irqs = dal_irq_service_dce110_create(&init_data); + if (!pool->base.irqs) + goto res_create_fail; + } + + /************************************************* + * Resource + asic cap harcoding * + *************************************************/ + pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.pipe_count = res_cap.num_timing_generator; + pool->base.timing_generator_count = pool->base.res_cap->num_timing_generator; + dc->caps.max_downscale_ratio = 200; + dc->caps.i2c_speed_in_khz = 40; + dc->caps.i2c_speed_in_khz = 40; + dc->caps.max_cursor_size = 128; + dc->caps.min_horizontal_blanking_period = 80; + dc->caps.dual_link_dvi = true; + dc->caps.disable_dp_clk_share = true; + dc->caps.extended_aux_timeout_support = false; + dc->debug = debug_defaults; + + for (i = 0; i < pool->base.pipe_count; i++) { + pool->base.timing_generators[i] = + dce100_timing_generator_create( + ctx, + i, + &dce100_tg_offsets[i]); + if (pool->base.timing_generators[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create tg!\n"); + goto res_create_fail; + } + + pool->base.mis[i] = dce100_mem_input_create(ctx, i); + if (pool->base.mis[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create memory input!\n"); + goto res_create_fail; + } + + pool->base.ipps[i] = dce100_ipp_create(ctx, i); + if (pool->base.ipps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create input pixel processor!\n"); + goto res_create_fail; + } + + pool->base.transforms[i] = dce100_transform_create(ctx, i); + if (pool->base.transforms[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create transform!\n"); + goto res_create_fail; + } + + pool->base.opps[i] = dce100_opp_create(ctx, i); + if (pool->base.opps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create output pixel processor!\n"); + goto res_create_fail; + } + } + + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + pool->base.engines[i] = dce100_aux_engine_create(ctx, i); + if (pool->base.engines[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create aux engine!!\n"); + goto res_create_fail; + } + pool->base.hw_i2cs[i] = dce100_i2c_hw_create(ctx, i); + if (pool->base.hw_i2cs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create i2c engine!!\n"); + goto res_create_fail; + } + pool->base.sw_i2cs[i] = NULL; + } + + dc->caps.max_planes = pool->base.pipe_count; + + for (i = 0; i < dc->caps.max_planes; ++i) + dc->caps.planes[i] = plane_cap; + + if (!resource_construct(num_virtual_links, dc, &pool->base, + &res_create_funcs)) + goto res_create_fail; + + /* Create hardware sequencer */ + dce100_hw_sequencer_construct(dc); + return true; + +res_create_fail: + dce100_resource_destruct(pool); + + return false; +} + +struct resource_pool *dce100_create_resource_pool( + uint8_t num_virtual_links, + struct dc *dc) +{ + struct dce110_resource_pool *pool = + kzalloc(sizeof(struct dce110_resource_pool), GFP_KERNEL); + + if (!pool) + return NULL; + + if (dce100_resource_construct(num_virtual_links, dc, pool)) + return &pool->base; + + kfree(pool); + BREAK_TO_DEBUGGER(); + return NULL; +} + diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.h new file mode 100644 index 00000000000000..fecab7c560f5ba --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.h @@ -0,0 +1,54 @@ +/* + * Copyright 2017 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. + * + * + */ +/* + * dce100_resource.h + * + * Created on: 2016-01-20 + * Author: qyang + */ + +#ifndef DCE100_RESOURCE_H_ +#define DCE100_RESOURCE_H_ + +struct dc; +struct resource_pool; +struct dc_validation_set; + +struct resource_pool *dce100_create_resource_pool( + uint8_t num_virtual_links, + struct dc *dc); + +enum dc_status dce100_validate_plane(const struct dc_plane_state *plane_state, struct dc_caps *caps); + +enum dc_status dce100_add_stream_to_ctx( + struct dc *dc, + struct dc_state *new_ctx, + struct dc_stream_state *dc_stream); + +struct stream_encoder *dce100_find_first_free_match_stream_enc_for_link( + struct resource_context *res_ctx, + const struct resource_pool *pool, + struct dc_stream_state *stream); + +#endif /* DCE100_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce110/dce110_resource.c new file mode 100644 index 00000000000000..fe518fd27b083d --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dce110/dce110_resource.c @@ -0,0 +1,1551 @@ +/* + * 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 + * + */ + +#include "dm_services.h" + +#include "link_encoder.h" +#include "stream_encoder.h" + +#include "resource.h" +#include "dce110/dce110_resource.h" +#include "include/irq_service_interface.h" +#include "dce/dce_audio.h" +#include "dce110/dce110_timing_generator.h" +#include "irq/dce110/irq_service_dce110.h" +#include "dce110/dce110_timing_generator_v.h" +#include "dce/dce_link_encoder.h" +#include "dce/dce_stream_encoder.h" +#include "dce/dce_mem_input.h" +#include "dce110/dce110_mem_input_v.h" +#include "dce/dce_ipp.h" +#include "dce/dce_transform.h" +#include "dce110/dce110_transform_v.h" +#include "dce/dce_opp.h" +#include "dce110/dce110_opp_v.h" +#include "dce/dce_clock_source.h" +#include "dce/dce_hwseq.h" +#include "dce110/dce110_hwseq.h" +#include "dce/dce_aux.h" +#include "dce/dce_abm.h" +#include "dce/dce_dmcu.h" +#include "dce/dce_i2c.h" +#include "dce/dce_panel_cntl.h" + +#define DC_LOGGER \ + dc->ctx->logger + +#include "dce110/dce110_compressor.h" + +#include "reg_helper.h" + +#include "dce/dce_11_0_d.h" +#include "dce/dce_11_0_sh_mask.h" + +#ifndef mmMC_HUB_RDREQ_DMIF_LIMIT +#include "gmc/gmc_8_2_d.h" +#include "gmc/gmc_8_2_sh_mask.h" +#endif + +#ifndef mmDP_DPHY_INTERNAL_CTRL + #define mmDP_DPHY_INTERNAL_CTRL 0x4aa7 + #define mmDP0_DP_DPHY_INTERNAL_CTRL 0x4aa7 + #define mmDP1_DP_DPHY_INTERNAL_CTRL 0x4ba7 + #define mmDP2_DP_DPHY_INTERNAL_CTRL 0x4ca7 + #define mmDP3_DP_DPHY_INTERNAL_CTRL 0x4da7 + #define mmDP4_DP_DPHY_INTERNAL_CTRL 0x4ea7 + #define mmDP5_DP_DPHY_INTERNAL_CTRL 0x4fa7 + #define mmDP6_DP_DPHY_INTERNAL_CTRL 0x54a7 + #define mmDP7_DP_DPHY_INTERNAL_CTRL 0x56a7 + #define mmDP8_DP_DPHY_INTERNAL_CTRL 0x57a7 +#endif + +#ifndef mmBIOS_SCRATCH_2 + #define mmBIOS_SCRATCH_2 0x05CB + #define mmBIOS_SCRATCH_3 0x05CC + #define mmBIOS_SCRATCH_6 0x05CF +#endif + +#ifndef mmDP_DPHY_BS_SR_SWAP_CNTL + #define mmDP_DPHY_BS_SR_SWAP_CNTL 0x4ADC + #define mmDP0_DP_DPHY_BS_SR_SWAP_CNTL 0x4ADC + #define mmDP1_DP_DPHY_BS_SR_SWAP_CNTL 0x4BDC + #define mmDP2_DP_DPHY_BS_SR_SWAP_CNTL 0x4CDC + #define mmDP3_DP_DPHY_BS_SR_SWAP_CNTL 0x4DDC + #define mmDP4_DP_DPHY_BS_SR_SWAP_CNTL 0x4EDC + #define mmDP5_DP_DPHY_BS_SR_SWAP_CNTL 0x4FDC + #define mmDP6_DP_DPHY_BS_SR_SWAP_CNTL 0x54DC +#endif + +#ifndef mmDP_DPHY_FAST_TRAINING + #define mmDP_DPHY_FAST_TRAINING 0x4ABC + #define mmDP0_DP_DPHY_FAST_TRAINING 0x4ABC + #define mmDP1_DP_DPHY_FAST_TRAINING 0x4BBC + #define mmDP2_DP_DPHY_FAST_TRAINING 0x4CBC + #define mmDP3_DP_DPHY_FAST_TRAINING 0x4DBC + #define mmDP4_DP_DPHY_FAST_TRAINING 0x4EBC + #define mmDP5_DP_DPHY_FAST_TRAINING 0x4FBC + #define mmDP6_DP_DPHY_FAST_TRAINING 0x54BC +#endif + +#ifndef DPHY_RX_FAST_TRAINING_CAPABLE + #define DPHY_RX_FAST_TRAINING_CAPABLE 0x1 +#endif + +static const struct dce110_timing_generator_offsets dce110_tg_offsets[] = { + { + .crtc = (mmCRTC0_CRTC_CONTROL - mmCRTC_CONTROL), + .dcp = (mmDCP0_GRPH_CONTROL - mmGRPH_CONTROL), + }, + { + .crtc = (mmCRTC1_CRTC_CONTROL - mmCRTC_CONTROL), + .dcp = (mmDCP1_GRPH_CONTROL - mmGRPH_CONTROL), + }, + { + .crtc = (mmCRTC2_CRTC_CONTROL - mmCRTC_CONTROL), + .dcp = (mmDCP2_GRPH_CONTROL - mmGRPH_CONTROL), + }, + { + .crtc = (mmCRTC3_CRTC_CONTROL - mmCRTC_CONTROL), + .dcp = (mmDCP3_GRPH_CONTROL - mmGRPH_CONTROL), + }, + { + .crtc = (mmCRTC4_CRTC_CONTROL - mmCRTC_CONTROL), + .dcp = (mmDCP4_GRPH_CONTROL - mmGRPH_CONTROL), + }, + { + .crtc = (mmCRTC5_CRTC_CONTROL - mmCRTC_CONTROL), + .dcp = (mmDCP5_GRPH_CONTROL - mmGRPH_CONTROL), + } +}; + +/* set register offset */ +#define SR(reg_name)\ + .reg_name = mm ## reg_name + +/* set register offset with instance */ +#define SRI(reg_name, block, id)\ + .reg_name = mm ## block ## id ## _ ## reg_name + +static const struct dce_dmcu_registers dmcu_regs = { + DMCU_DCE110_COMMON_REG_LIST() +}; + +static const struct dce_dmcu_shift dmcu_shift = { + DMCU_MASK_SH_LIST_DCE110(__SHIFT) +}; + +static const struct dce_dmcu_mask dmcu_mask = { + DMCU_MASK_SH_LIST_DCE110(_MASK) +}; + +static const struct dce_abm_registers abm_regs = { + ABM_DCE110_COMMON_REG_LIST() +}; + +static const struct dce_abm_shift abm_shift = { + ABM_MASK_SH_LIST_DCE110(__SHIFT) +}; + +static const struct dce_abm_mask abm_mask = { + ABM_MASK_SH_LIST_DCE110(_MASK) +}; + +#define ipp_regs(id)\ +[id] = {\ + IPP_DCE110_REG_LIST_DCE_BASE(id)\ +} + +static const struct dce_ipp_registers ipp_regs[] = { + ipp_regs(0), + ipp_regs(1), + ipp_regs(2) +}; + +static const struct dce_ipp_shift ipp_shift = { + IPP_DCE100_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) +}; + +static const struct dce_ipp_mask ipp_mask = { + IPP_DCE100_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) +}; + +#define transform_regs(id)\ +[id] = {\ + XFM_COMMON_REG_LIST_DCE110(id)\ +} + +static const struct dce_transform_registers xfm_regs[] = { + transform_regs(0), + transform_regs(1), + transform_regs(2) +}; + +static const struct dce_transform_shift xfm_shift = { + XFM_COMMON_MASK_SH_LIST_DCE110(__SHIFT) +}; + +static const struct dce_transform_mask xfm_mask = { + XFM_COMMON_MASK_SH_LIST_DCE110(_MASK) +}; + +#define aux_regs(id)\ +[id] = {\ + AUX_REG_LIST(id)\ +} + +static const struct dce110_link_enc_aux_registers link_enc_aux_regs[] = { + aux_regs(0), + aux_regs(1), + aux_regs(2), + aux_regs(3), + aux_regs(4), + aux_regs(5) +}; + +#define hpd_regs(id)\ +[id] = {\ + HPD_REG_LIST(id)\ +} + +static const struct dce110_link_enc_hpd_registers link_enc_hpd_regs[] = { + hpd_regs(0), + hpd_regs(1), + hpd_regs(2), + hpd_regs(3), + hpd_regs(4), + hpd_regs(5) +}; + + +#define link_regs(id)\ +[id] = {\ + LE_DCE110_REG_LIST(id)\ +} + +static const struct dce110_link_enc_registers link_enc_regs[] = { + link_regs(0), + link_regs(1), + link_regs(2), + link_regs(3), + link_regs(4), + link_regs(5), + link_regs(6), +}; + +#define stream_enc_regs(id)\ +[id] = {\ + SE_COMMON_REG_LIST(id),\ + .TMDS_CNTL = 0,\ +} + +static const struct dce110_stream_enc_registers stream_enc_regs[] = { + stream_enc_regs(0), + stream_enc_regs(1), + stream_enc_regs(2) +}; + +static const struct dce_stream_encoder_shift se_shift = { + SE_COMMON_MASK_SH_LIST_DCE110(__SHIFT) +}; + +static const struct dce_stream_encoder_mask se_mask = { + SE_COMMON_MASK_SH_LIST_DCE110(_MASK) +}; + +static const struct dce_panel_cntl_registers panel_cntl_regs[] = { + { DCE_PANEL_CNTL_REG_LIST() } +}; + +static const struct dce_panel_cntl_shift panel_cntl_shift = { + DCE_PANEL_CNTL_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_panel_cntl_mask panel_cntl_mask = { + DCE_PANEL_CNTL_MASK_SH_LIST(_MASK) +}; + +static const struct dce110_aux_registers_shift aux_shift = { + DCE_AUX_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce110_aux_registers_mask aux_mask = { + DCE_AUX_MASK_SH_LIST(_MASK) +}; + +#define opp_regs(id)\ +[id] = {\ + OPP_DCE_110_REG_LIST(id),\ +} + +static const struct dce_opp_registers opp_regs[] = { + opp_regs(0), + opp_regs(1), + opp_regs(2), + opp_regs(3), + opp_regs(4), + opp_regs(5) +}; + +static const struct dce_opp_shift opp_shift = { + OPP_COMMON_MASK_SH_LIST_DCE_110(__SHIFT) +}; + +static const struct dce_opp_mask opp_mask = { + OPP_COMMON_MASK_SH_LIST_DCE_110(_MASK) +}; + +#define aux_engine_regs(id)\ +[id] = {\ + AUX_COMMON_REG_LIST(id), \ + .AUX_RESET_MASK = 0 \ +} + +static const struct dce110_aux_registers aux_engine_regs[] = { + aux_engine_regs(0), + aux_engine_regs(1), + aux_engine_regs(2), + aux_engine_regs(3), + aux_engine_regs(4), + aux_engine_regs(5) +}; + +#define audio_regs(id)\ +[id] = {\ + AUD_COMMON_REG_LIST(id)\ +} + +static const struct dce_audio_registers audio_regs[] = { + audio_regs(0), + audio_regs(1), + audio_regs(2), + audio_regs(3), + audio_regs(4), + audio_regs(5), + audio_regs(6), +}; + +static const struct dce_audio_shift audio_shift = { + AUD_COMMON_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_audio_mask audio_mask = { + AUD_COMMON_MASK_SH_LIST(_MASK) +}; + +/* AG TBD Needs to be reduced back to 3 pipes once dce10 hw sequencer implemented. */ + + +#define clk_src_regs(id)\ +[id] = {\ + CS_COMMON_REG_LIST_DCE_100_110(id),\ +} + +static const struct dce110_clk_src_regs clk_src_regs[] = { + clk_src_regs(0), + clk_src_regs(1), + clk_src_regs(2) +}; + +static const struct dce110_clk_src_shift cs_shift = { + CS_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) +}; + +static const struct dce110_clk_src_mask cs_mask = { + CS_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) +}; + +static const struct bios_registers bios_regs = { + .BIOS_SCRATCH_3 = mmBIOS_SCRATCH_3, + .BIOS_SCRATCH_6 = mmBIOS_SCRATCH_6 +}; + +static const struct resource_caps carrizo_resource_cap = { + .num_timing_generator = 3, + .num_video_plane = 1, + .num_audio = 3, + .num_stream_encoder = 3, + .num_pll = 2, + .num_ddc = 3, +}; + +static const struct resource_caps stoney_resource_cap = { + .num_timing_generator = 2, + .num_video_plane = 1, + .num_audio = 3, + .num_stream_encoder = 3, + .num_pll = 2, + .num_ddc = 3, +}; + +static const struct dc_plane_cap plane_cap = { + .type = DC_PLANE_TYPE_DCE_RGB, + .per_pixel_alpha = 1, + + .pixel_format_support = { + .argb8888 = true, + .nv12 = false, + .fp16 = true + }, + + .max_upscale_factor = { + .argb8888 = 16000, + .nv12 = 1, + .fp16 = 1 + }, + + .max_downscale_factor = { + .argb8888 = 250, + .nv12 = 1, + .fp16 = 1 + }, + 64, + 64 +}; + +static const struct dc_debug_options debug_defaults = { + .enable_legacy_fast_update = true, +}; + +static const struct dc_plane_cap underlay_plane_cap = { + .type = DC_PLANE_TYPE_DCE_UNDERLAY, + .per_pixel_alpha = 1, + + .pixel_format_support = { + .argb8888 = false, + .nv12 = true, + .fp16 = false + }, + + .max_upscale_factor = { + .argb8888 = 1, + .nv12 = 16000, + .fp16 = 1 + }, + + .max_downscale_factor = { + .argb8888 = 1, + .nv12 = 250, + .fp16 = 1 + }, + 64, + 64 +}; + +#define CTX ctx +#define REG(reg) mm ## reg + +#ifndef mmCC_DC_HDMI_STRAPS +#define mmCC_DC_HDMI_STRAPS 0x4819 +#define CC_DC_HDMI_STRAPS__HDMI_DISABLE_MASK 0x40 +#define CC_DC_HDMI_STRAPS__HDMI_DISABLE__SHIFT 0x6 +#define CC_DC_HDMI_STRAPS__AUDIO_STREAM_NUMBER_MASK 0x700 +#define CC_DC_HDMI_STRAPS__AUDIO_STREAM_NUMBER__SHIFT 0x8 +#endif + +static int map_transmitter_id_to_phy_instance( + enum transmitter transmitter) +{ + switch (transmitter) { + case TRANSMITTER_UNIPHY_A: + return 0; + case TRANSMITTER_UNIPHY_B: + return 1; + case TRANSMITTER_UNIPHY_C: + return 2; + case TRANSMITTER_UNIPHY_D: + return 3; + case TRANSMITTER_UNIPHY_E: + return 4; + case TRANSMITTER_UNIPHY_F: + return 5; + case TRANSMITTER_UNIPHY_G: + return 6; + default: + ASSERT(0); + return 0; + } +} + +static void read_dce_straps( + struct dc_context *ctx, + struct resource_straps *straps) +{ + REG_GET_2(CC_DC_HDMI_STRAPS, + HDMI_DISABLE, &straps->hdmi_disable, + AUDIO_STREAM_NUMBER, &straps->audio_stream_number); + + REG_GET(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO, &straps->dc_pinstraps_audio); +} + +static struct audio *create_audio( + struct dc_context *ctx, unsigned int inst) +{ + return dce_audio_create(ctx, inst, + &audio_regs[inst], &audio_shift, &audio_mask); +} + +static struct timing_generator *dce110_timing_generator_create( + struct dc_context *ctx, + uint32_t instance, + const struct dce110_timing_generator_offsets *offsets) +{ + struct dce110_timing_generator *tg110 = + kzalloc(sizeof(struct dce110_timing_generator), GFP_KERNEL); + + if (!tg110) + return NULL; + + dce110_timing_generator_construct(tg110, ctx, instance, offsets); + return &tg110->base; +} + +static struct stream_encoder *dce110_stream_encoder_create( + enum engine_id eng_id, + struct dc_context *ctx) +{ + struct dce110_stream_encoder *enc110 = + kzalloc(sizeof(struct dce110_stream_encoder), GFP_KERNEL); + + if (!enc110) + return NULL; + + dce110_stream_encoder_construct(enc110, ctx, ctx->dc_bios, eng_id, + &stream_enc_regs[eng_id], + &se_shift, &se_mask); + return &enc110->base; +} + +#define SRII(reg_name, block, id)\ + .reg_name[id] = mm ## block ## id ## _ ## reg_name + +static const struct dce_hwseq_registers hwseq_stoney_reg = { + HWSEQ_ST_REG_LIST() +}; + +static const struct dce_hwseq_registers hwseq_cz_reg = { + HWSEQ_CZ_REG_LIST() +}; + +static const struct dce_hwseq_shift hwseq_shift = { + HWSEQ_DCE11_MASK_SH_LIST(__SHIFT), +}; + +static const struct dce_hwseq_mask hwseq_mask = { + HWSEQ_DCE11_MASK_SH_LIST(_MASK), +}; + +static struct dce_hwseq *dce110_hwseq_create( + struct dc_context *ctx) +{ + struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); + + if (hws) { + hws->ctx = ctx; + hws->regs = ASIC_REV_IS_STONEY(ctx->asic_id.hw_internal_rev) ? + &hwseq_stoney_reg : &hwseq_cz_reg; + hws->shifts = &hwseq_shift; + hws->masks = &hwseq_mask; + hws->wa.blnd_crtc_trigger = true; + } + return hws; +} + +static const struct resource_create_funcs res_create_funcs = { + .read_dce_straps = read_dce_straps, + .create_audio = create_audio, + .create_stream_encoder = dce110_stream_encoder_create, + .create_hwseq = dce110_hwseq_create, +}; + +#define mi_inst_regs(id) { \ + MI_DCE11_REG_LIST(id), \ + .MC_HUB_RDREQ_DMIF_LIMIT = mmMC_HUB_RDREQ_DMIF_LIMIT \ +} +static const struct dce_mem_input_registers mi_regs[] = { + mi_inst_regs(0), + mi_inst_regs(1), + mi_inst_regs(2), +}; + +static const struct dce_mem_input_shift mi_shifts = { + MI_DCE11_MASK_SH_LIST(__SHIFT), + .ENABLE = MC_HUB_RDREQ_DMIF_LIMIT__ENABLE__SHIFT +}; + +static const struct dce_mem_input_mask mi_masks = { + MI_DCE11_MASK_SH_LIST(_MASK), + .ENABLE = MC_HUB_RDREQ_DMIF_LIMIT__ENABLE_MASK +}; + + +static struct mem_input *dce110_mem_input_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce_mem_input *dce_mi = kzalloc(sizeof(struct dce_mem_input), + GFP_KERNEL); + + if (!dce_mi) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dce_mem_input_construct(dce_mi, ctx, inst, &mi_regs[inst], &mi_shifts, &mi_masks); + dce_mi->wa.single_head_rdreq_dmif_limit = 3; + return &dce_mi->base; +} + +static void dce110_transform_destroy(struct transform **xfm) +{ + kfree(TO_DCE_TRANSFORM(*xfm)); + *xfm = NULL; +} + +static struct transform *dce110_transform_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce_transform *transform = + kzalloc(sizeof(struct dce_transform), GFP_KERNEL); + + if (!transform) + return NULL; + + dce_transform_construct(transform, ctx, inst, + &xfm_regs[inst], &xfm_shift, &xfm_mask); + return &transform->base; +} + +static struct input_pixel_processor *dce110_ipp_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dce_ipp *ipp = kzalloc(sizeof(struct dce_ipp), GFP_KERNEL); + + if (!ipp) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dce_ipp_construct(ipp, ctx, inst, + &ipp_regs[inst], &ipp_shift, &ipp_mask); + return &ipp->base; +} + +static const struct encoder_feature_support link_enc_feature = { + .max_hdmi_deep_color = COLOR_DEPTH_121212, + .max_hdmi_pixel_clock = 300000, + .flags.bits.IS_HBR2_CAPABLE = true, + .flags.bits.IS_TPS3_CAPABLE = true +}; + +static struct link_encoder *dce110_link_encoder_create( + struct dc_context *ctx, + const struct encoder_init_data *enc_init_data) +{ + struct dce110_link_encoder *enc110 = + kzalloc(sizeof(struct dce110_link_encoder), GFP_KERNEL); + int link_regs_id; + + if (!enc110) + return NULL; + + link_regs_id = + map_transmitter_id_to_phy_instance(enc_init_data->transmitter); + + dce110_link_encoder_construct(enc110, + enc_init_data, + &link_enc_feature, + &link_enc_regs[link_regs_id], + &link_enc_aux_regs[enc_init_data->channel - 1], + &link_enc_hpd_regs[enc_init_data->hpd_source]); + return &enc110->base; +} + +static struct panel_cntl *dce110_panel_cntl_create(const struct panel_cntl_init_data *init_data) +{ + struct dce_panel_cntl *panel_cntl = + kzalloc(sizeof(struct dce_panel_cntl), GFP_KERNEL); + + if (!panel_cntl) + return NULL; + + dce_panel_cntl_construct(panel_cntl, + init_data, + &panel_cntl_regs[init_data->inst], + &panel_cntl_shift, + &panel_cntl_mask); + + return &panel_cntl->base; +} + +static struct output_pixel_processor *dce110_opp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce110_opp *opp = + kzalloc(sizeof(struct dce110_opp), GFP_KERNEL); + + if (!opp) + return NULL; + + dce110_opp_construct(opp, + ctx, inst, &opp_regs[inst], &opp_shift, &opp_mask); + return &opp->base; +} + +static struct dce_aux *dce110_aux_engine_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct aux_engine_dce110 *aux_engine = + kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); + + if (!aux_engine) + return NULL; + + dce110_aux_engine_construct(aux_engine, ctx, inst, + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, + &aux_engine_regs[inst], + &aux_mask, + &aux_shift, + ctx->dc->caps.extended_aux_timeout_support); + + return &aux_engine->base; +} +#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST(id) } + +static const struct dce_i2c_registers i2c_hw_regs[] = { + i2c_inst_regs(1), + i2c_inst_regs(2), + i2c_inst_regs(3), + i2c_inst_regs(4), + i2c_inst_regs(5), + i2c_inst_regs(6), +}; + +static const struct dce_i2c_shift i2c_shifts = { + I2C_COMMON_MASK_SH_LIST_DCE110(__SHIFT) +}; + +static const struct dce_i2c_mask i2c_masks = { + I2C_COMMON_MASK_SH_LIST_DCE110(_MASK) +}; + +static struct dce_i2c_hw *dce110_i2c_hw_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce_i2c_hw *dce_i2c_hw = + kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); + + if (!dce_i2c_hw) + return NULL; + + dce100_i2c_hw_construct(dce_i2c_hw, ctx, inst, + &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); + + return dce_i2c_hw; +} +static struct clock_source *dce110_clock_source_create( + struct dc_context *ctx, + struct dc_bios *bios, + enum clock_source_id id, + const struct dce110_clk_src_regs *regs, + bool dp_clk_src) +{ + struct dce110_clk_src *clk_src = + kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); + + if (!clk_src) + return NULL; + + if (dce110_clk_src_construct(clk_src, ctx, bios, id, + regs, &cs_shift, &cs_mask)) { + clk_src->base.dp_clk_src = dp_clk_src; + return &clk_src->base; + } + + kfree(clk_src); + BREAK_TO_DEBUGGER(); + return NULL; +} + +static void dce110_clock_source_destroy(struct clock_source **clk_src) +{ + struct dce110_clk_src *dce110_clk_src; + + if (!clk_src) + return; + + dce110_clk_src = TO_DCE110_CLK_SRC(*clk_src); + + kfree(dce110_clk_src->dp_ss_params); + kfree(dce110_clk_src->hdmi_ss_params); + kfree(dce110_clk_src->dvi_ss_params); + + kfree(dce110_clk_src); + *clk_src = NULL; +} + +static void dce110_resource_destruct(struct dce110_resource_pool *pool) +{ + unsigned int i; + + for (i = 0; i < pool->base.pipe_count; i++) { + if (pool->base.opps[i] != NULL) + dce110_opp_destroy(&pool->base.opps[i]); + + if (pool->base.transforms[i] != NULL) + dce110_transform_destroy(&pool->base.transforms[i]); + + if (pool->base.ipps[i] != NULL) + dce_ipp_destroy(&pool->base.ipps[i]); + + if (pool->base.mis[i] != NULL) { + kfree(TO_DCE_MEM_INPUT(pool->base.mis[i])); + pool->base.mis[i] = NULL; + } + + if (pool->base.timing_generators[i] != NULL) { + kfree(DCE110TG_FROM_TG(pool->base.timing_generators[i])); + pool->base.timing_generators[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + if (pool->base.engines[i] != NULL) + dce110_engine_destroy(&pool->base.engines[i]); + if (pool->base.hw_i2cs[i] != NULL) { + kfree(pool->base.hw_i2cs[i]); + pool->base.hw_i2cs[i] = NULL; + } + if (pool->base.sw_i2cs[i] != NULL) { + kfree(pool->base.sw_i2cs[i]); + pool->base.sw_i2cs[i] = NULL; + } + } + + for (i = 0; i < pool->base.stream_enc_count; i++) { + if (pool->base.stream_enc[i] != NULL) + kfree(DCE110STRENC_FROM_STRENC(pool->base.stream_enc[i])); + } + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] != NULL) { + dce110_clock_source_destroy(&pool->base.clock_sources[i]); + } + } + + if (pool->base.dp_clock_source != NULL) + dce110_clock_source_destroy(&pool->base.dp_clock_source); + + for (i = 0; i < pool->base.audio_count; i++) { + if (pool->base.audios[i] != NULL) { + dce_aud_destroy(&pool->base.audios[i]); + } + } + + if (pool->base.abm != NULL) + dce_abm_destroy(&pool->base.abm); + + if (pool->base.dmcu != NULL) + dce_dmcu_destroy(&pool->base.dmcu); + + if (pool->base.irqs != NULL) { + dal_irq_service_destroy(&pool->base.irqs); + } +} + + +static void get_pixel_clock_parameters( + const struct pipe_ctx *pipe_ctx, + struct pixel_clk_params *pixel_clk_params) +{ + const struct dc_stream_state *stream = pipe_ctx->stream; + + /*TODO: is this halved for YCbCr 420? in that case we might want to move + * the pixel clock normalization for hdmi up to here instead of doing it + * in pll_adjust_pix_clk + */ + pixel_clk_params->requested_pix_clk_100hz = stream->timing.pix_clk_100hz; + pixel_clk_params->encoder_object_id = stream->link->link_enc->id; + pixel_clk_params->signal_type = pipe_ctx->stream->signal; + pixel_clk_params->controller_id = pipe_ctx->stream_res.tg->inst + 1; + /* TODO: un-hardcode*/ + pixel_clk_params->requested_sym_clk = LINK_RATE_LOW * + LINK_RATE_REF_FREQ_IN_KHZ; + pixel_clk_params->flags.ENABLE_SS = 0; + pixel_clk_params->color_depth = + stream->timing.display_color_depth; + pixel_clk_params->flags.DISPLAY_BLANKED = 1; + pixel_clk_params->flags.SUPPORT_YCBCR420 = (stream->timing.pixel_encoding == + PIXEL_ENCODING_YCBCR420); + pixel_clk_params->pixel_encoding = stream->timing.pixel_encoding; + if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR422) { + pixel_clk_params->color_depth = COLOR_DEPTH_888; + } + if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) { + pixel_clk_params->requested_pix_clk_100hz = pixel_clk_params->requested_pix_clk_100hz / 2; + } + if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING) + pixel_clk_params->requested_pix_clk_100hz *= 2; + +} + +void dce110_resource_build_pipe_hw_param(struct pipe_ctx *pipe_ctx) +{ + get_pixel_clock_parameters(pipe_ctx, &pipe_ctx->stream_res.pix_clk_params); + pipe_ctx->clock_source->funcs->get_pix_clk_dividers( + pipe_ctx->clock_source, + &pipe_ctx->stream_res.pix_clk_params, + &pipe_ctx->pll_settings); + resource_build_bit_depth_reduction_params(pipe_ctx->stream, + &pipe_ctx->stream->bit_depth_params); + pipe_ctx->stream->clamping.pixel_encoding = pipe_ctx->stream->timing.pixel_encoding; +} + +static bool is_surface_pixel_format_supported(struct pipe_ctx *pipe_ctx, unsigned int underlay_idx) +{ + if (pipe_ctx->pipe_idx != underlay_idx) + return true; + if (!pipe_ctx->plane_state) + return false; + if (pipe_ctx->plane_state->format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) + return false; + return true; +} + +static enum dc_status build_mapped_resource( + const struct dc *dc, + struct dc_state *context, + struct dc_stream_state *stream) +{ + struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream); + + if (!pipe_ctx) + return DC_ERROR_UNEXPECTED; + + if (!is_surface_pixel_format_supported(pipe_ctx, + dc->res_pool->underlay_pipe_index)) + return DC_SURFACE_PIXEL_FORMAT_UNSUPPORTED; + + dce110_resource_build_pipe_hw_param(pipe_ctx); + + /* TODO: validate audio ASIC caps, encoder */ + + resource_build_info_frame(pipe_ctx); + + return DC_OK; +} + +static bool dce110_validate_bandwidth( + struct dc *dc, + struct dc_state *context, + bool fast_validate) +{ + bool result = false; + + DC_LOG_BANDWIDTH_CALCS( + "%s: start", + __func__); + + if (bw_calcs( + dc->ctx, + dc->bw_dceip, + dc->bw_vbios, + context->res_ctx.pipe_ctx, + dc->res_pool->pipe_count, + &context->bw_ctx.bw.dce)) + result = true; + + if (!result) + DC_LOG_BANDWIDTH_VALIDATION("%s: %dx%d@%d Bandwidth validation failed!\n", + __func__, + context->streams[0]->timing.h_addressable, + context->streams[0]->timing.v_addressable, + context->streams[0]->timing.pix_clk_100hz / 10); + + if (memcmp(&dc->current_state->bw_ctx.bw.dce, + &context->bw_ctx.bw.dce, sizeof(context->bw_ctx.bw.dce))) { + + DC_LOG_BANDWIDTH_CALCS( + "%s: finish,\n" + "nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n" + "stutMark_b: %d stutMark_a: %d\n" + "nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n" + "stutMark_b: %d stutMark_a: %d\n" + "nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n" + "stutMark_b: %d stutMark_a: %d stutter_mode_enable: %d\n" + "cstate: %d pstate: %d nbpstate: %d sync: %d dispclk: %d\n" + "sclk: %d sclk_sleep: %d yclk: %d blackout_recovery_time_us: %d\n" + , + __func__, + context->bw_ctx.bw.dce.nbp_state_change_wm_ns[0].b_mark, + context->bw_ctx.bw.dce.nbp_state_change_wm_ns[0].a_mark, + context->bw_ctx.bw.dce.urgent_wm_ns[0].b_mark, + context->bw_ctx.bw.dce.urgent_wm_ns[0].a_mark, + context->bw_ctx.bw.dce.stutter_exit_wm_ns[0].b_mark, + context->bw_ctx.bw.dce.stutter_exit_wm_ns[0].a_mark, + context->bw_ctx.bw.dce.nbp_state_change_wm_ns[1].b_mark, + context->bw_ctx.bw.dce.nbp_state_change_wm_ns[1].a_mark, + context->bw_ctx.bw.dce.urgent_wm_ns[1].b_mark, + context->bw_ctx.bw.dce.urgent_wm_ns[1].a_mark, + context->bw_ctx.bw.dce.stutter_exit_wm_ns[1].b_mark, + context->bw_ctx.bw.dce.stutter_exit_wm_ns[1].a_mark, + context->bw_ctx.bw.dce.nbp_state_change_wm_ns[2].b_mark, + context->bw_ctx.bw.dce.nbp_state_change_wm_ns[2].a_mark, + context->bw_ctx.bw.dce.urgent_wm_ns[2].b_mark, + context->bw_ctx.bw.dce.urgent_wm_ns[2].a_mark, + context->bw_ctx.bw.dce.stutter_exit_wm_ns[2].b_mark, + context->bw_ctx.bw.dce.stutter_exit_wm_ns[2].a_mark, + context->bw_ctx.bw.dce.stutter_mode_enable, + context->bw_ctx.bw.dce.cpuc_state_change_enable, + context->bw_ctx.bw.dce.cpup_state_change_enable, + context->bw_ctx.bw.dce.nbp_state_change_enable, + context->bw_ctx.bw.dce.all_displays_in_sync, + context->bw_ctx.bw.dce.dispclk_khz, + context->bw_ctx.bw.dce.sclk_khz, + context->bw_ctx.bw.dce.sclk_deep_sleep_khz, + context->bw_ctx.bw.dce.yclk_khz, + context->bw_ctx.bw.dce.blackout_recovery_time_us); + } + return result; +} + +static enum dc_status dce110_validate_plane(const struct dc_plane_state *plane_state, + struct dc_caps *caps) +{ + if (((plane_state->dst_rect.width * 2) < plane_state->src_rect.width) || + ((plane_state->dst_rect.height * 2) < plane_state->src_rect.height)) + return DC_FAIL_SURFACE_VALIDATE; + + return DC_OK; +} + +static bool dce110_validate_surface_sets( + struct dc_state *context) +{ + int i, j; + + for (i = 0; i < context->stream_count; i++) { + if (context->stream_status[i].plane_count == 0) + continue; + + if (context->stream_status[i].plane_count > 2) + return false; + + for (j = 0; j < context->stream_status[i].plane_count; j++) { + struct dc_plane_state *plane = + context->stream_status[i].plane_states[j]; + + /* underlay validation */ + if (plane->format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) { + + if ((plane->src_rect.width > 1920 || + plane->src_rect.height > 1080)) + return false; + + /* we don't have the logic to support underlay + * only yet so block the use case where we get + * NV12 plane as top layer + */ + if (j == 0) + return false; + + /* irrespective of plane format, + * stream should be RGB encoded + */ + if (context->streams[i]->timing.pixel_encoding + != PIXEL_ENCODING_RGB) + return false; + + } + + } + } + + return true; +} + +static enum dc_status dce110_validate_global( + struct dc *dc, + struct dc_state *context) +{ + if (!dce110_validate_surface_sets(context)) + return DC_FAIL_SURFACE_VALIDATE; + + return DC_OK; +} + +static enum dc_status dce110_add_stream_to_ctx( + struct dc *dc, + struct dc_state *new_ctx, + struct dc_stream_state *dc_stream) +{ + enum dc_status result = DC_ERROR_UNEXPECTED; + + result = resource_map_pool_resources(dc, new_ctx, dc_stream); + + if (result == DC_OK) + result = resource_map_clock_resources(dc, new_ctx, dc_stream); + + + if (result == DC_OK) + result = build_mapped_resource(dc, new_ctx, dc_stream); + + return result; +} + +static struct pipe_ctx *dce110_acquire_underlay( + const struct dc_state *cur_ctx, + struct dc_state *new_ctx, + const struct resource_pool *pool, + const struct pipe_ctx *opp_head_pipe) +{ + struct dc_stream_state *stream = opp_head_pipe->stream; + struct dc *dc = stream->ctx->dc; + struct dce_hwseq *hws = dc->hwseq; + struct resource_context *res_ctx = &new_ctx->res_ctx; + unsigned int underlay_idx = pool->underlay_pipe_index; + struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[underlay_idx]; + + if (res_ctx->pipe_ctx[underlay_idx].stream) + return NULL; + + pipe_ctx->stream_res.tg = pool->timing_generators[underlay_idx]; + pipe_ctx->plane_res.mi = pool->mis[underlay_idx]; + /*pipe_ctx->plane_res.ipp = res_ctx->pool->ipps[underlay_idx];*/ + pipe_ctx->plane_res.xfm = pool->transforms[underlay_idx]; + pipe_ctx->stream_res.opp = pool->opps[underlay_idx]; + pipe_ctx->pipe_idx = underlay_idx; + + pipe_ctx->stream = stream; + + if (!dc->current_state->res_ctx.pipe_ctx[underlay_idx].stream) { + struct tg_color black_color = {0}; + struct dc_bios *dcb = dc->ctx->dc_bios; + + hws->funcs.enable_display_power_gating( + dc, + pipe_ctx->stream_res.tg->inst, + dcb, PIPE_GATING_CONTROL_DISABLE); + + /* + * This is for powering on underlay, so crtc does not + * need to be enabled + */ + + pipe_ctx->stream_res.tg->funcs->program_timing(pipe_ctx->stream_res.tg, + &stream->timing, + 0, + 0, + 0, + 0, + pipe_ctx->stream->signal, + false); + + pipe_ctx->stream_res.tg->funcs->enable_advanced_request( + pipe_ctx->stream_res.tg, + true, + &stream->timing); + + pipe_ctx->plane_res.mi->funcs->allocate_mem_input(pipe_ctx->plane_res.mi, + stream->timing.h_total, + stream->timing.v_total, + stream->timing.pix_clk_100hz / 10, + new_ctx->stream_count); + + color_space_to_black_color(dc, + COLOR_SPACE_YCBCR601, &black_color); + pipe_ctx->stream_res.tg->funcs->set_blank_color( + pipe_ctx->stream_res.tg, + &black_color); + } + + return pipe_ctx; +} + +static void dce110_destroy_resource_pool(struct resource_pool **pool) +{ + struct dce110_resource_pool *dce110_pool = TO_DCE110_RES_POOL(*pool); + + dce110_resource_destruct(dce110_pool); + kfree(dce110_pool); + *pool = NULL; +} + +struct stream_encoder *dce110_find_first_free_match_stream_enc_for_link( + struct resource_context *res_ctx, + const struct resource_pool *pool, + struct dc_stream_state *stream) +{ + int i; + int j = -1; + struct dc_link *link = stream->link; + + for (i = 0; i < pool->stream_enc_count; i++) { + if (!res_ctx->is_stream_enc_acquired[i] && + pool->stream_enc[i]) { + /* Store first available for MST second display + * in daisy chain use case + */ + j = i; + if (pool->stream_enc[i]->id == + link->link_enc->preferred_engine) + return pool->stream_enc[i]; + } + } + + /* + * For CZ and later, we can allow DIG FE and BE to differ for all display types + */ + + if (j >= 0) + return pool->stream_enc[j]; + + return NULL; +} + + +static const struct resource_funcs dce110_res_pool_funcs = { + .destroy = dce110_destroy_resource_pool, + .link_enc_create = dce110_link_encoder_create, + .panel_cntl_create = dce110_panel_cntl_create, + .validate_bandwidth = dce110_validate_bandwidth, + .validate_plane = dce110_validate_plane, + .acquire_free_pipe_as_secondary_dpp_pipe = dce110_acquire_underlay, + .add_stream_to_ctx = dce110_add_stream_to_ctx, + .validate_global = dce110_validate_global, + .find_first_free_match_stream_enc_for_link = dce110_find_first_free_match_stream_enc_for_link +}; + +static bool underlay_create(struct dc_context *ctx, struct resource_pool *pool) +{ + struct dce110_timing_generator *dce110_tgv = kzalloc(sizeof(*dce110_tgv), + GFP_KERNEL); + struct dce_transform *dce110_xfmv = kzalloc(sizeof(*dce110_xfmv), + GFP_KERNEL); + struct dce_mem_input *dce110_miv = kzalloc(sizeof(*dce110_miv), + GFP_KERNEL); + struct dce110_opp *dce110_oppv = kzalloc(sizeof(*dce110_oppv), + GFP_KERNEL); + + if (!dce110_tgv || !dce110_xfmv || !dce110_miv || !dce110_oppv) { + kfree(dce110_tgv); + kfree(dce110_xfmv); + kfree(dce110_miv); + kfree(dce110_oppv); + return false; + } + + dce110_opp_v_construct(dce110_oppv, ctx); + + dce110_timing_generator_v_construct(dce110_tgv, ctx); + dce110_mem_input_v_construct(dce110_miv, ctx); + dce110_transform_v_construct(dce110_xfmv, ctx); + + pool->opps[pool->pipe_count] = &dce110_oppv->base; + pool->timing_generators[pool->pipe_count] = &dce110_tgv->base; + pool->mis[pool->pipe_count] = &dce110_miv->base; + pool->transforms[pool->pipe_count] = &dce110_xfmv->base; + pool->pipe_count++; + + /* update the public caps to indicate an underlay is available */ + ctx->dc->caps.max_slave_planes = 1; + ctx->dc->caps.max_slave_yuv_planes = 1; + ctx->dc->caps.max_slave_rgb_planes = 0; + + return true; +} + +static void bw_calcs_data_update_from_pplib(struct dc *dc) +{ + struct dm_pp_clock_levels clks = {0}; + + /*do system clock*/ + dm_pp_get_clock_levels_by_type( + dc->ctx, + DM_PP_CLOCK_TYPE_ENGINE_CLK, + &clks); + /* convert all the clock fro kHz to fix point mHz */ + dc->bw_vbios->high_sclk = bw_frc_to_fixed( + clks.clocks_in_khz[clks.num_levels-1], 1000); + dc->bw_vbios->mid1_sclk = bw_frc_to_fixed( + clks.clocks_in_khz[clks.num_levels/8], 1000); + dc->bw_vbios->mid2_sclk = bw_frc_to_fixed( + clks.clocks_in_khz[clks.num_levels*2/8], 1000); + dc->bw_vbios->mid3_sclk = bw_frc_to_fixed( + clks.clocks_in_khz[clks.num_levels*3/8], 1000); + dc->bw_vbios->mid4_sclk = bw_frc_to_fixed( + clks.clocks_in_khz[clks.num_levels*4/8], 1000); + dc->bw_vbios->mid5_sclk = bw_frc_to_fixed( + clks.clocks_in_khz[clks.num_levels*5/8], 1000); + dc->bw_vbios->mid6_sclk = bw_frc_to_fixed( + clks.clocks_in_khz[clks.num_levels*6/8], 1000); + dc->bw_vbios->low_sclk = bw_frc_to_fixed( + clks.clocks_in_khz[0], 1000); + dc->sclk_lvls = clks; + + /*do display clock*/ + dm_pp_get_clock_levels_by_type( + dc->ctx, + DM_PP_CLOCK_TYPE_DISPLAY_CLK, + &clks); + dc->bw_vbios->high_voltage_max_dispclk = bw_frc_to_fixed( + clks.clocks_in_khz[clks.num_levels-1], 1000); + dc->bw_vbios->mid_voltage_max_dispclk = bw_frc_to_fixed( + clks.clocks_in_khz[clks.num_levels>>1], 1000); + dc->bw_vbios->low_voltage_max_dispclk = bw_frc_to_fixed( + clks.clocks_in_khz[0], 1000); + + /*do memory clock*/ + dm_pp_get_clock_levels_by_type( + dc->ctx, + DM_PP_CLOCK_TYPE_MEMORY_CLK, + &clks); + + dc->bw_vbios->low_yclk = bw_frc_to_fixed( + clks.clocks_in_khz[0] * MEMORY_TYPE_MULTIPLIER_CZ, 1000); + dc->bw_vbios->mid_yclk = bw_frc_to_fixed( + clks.clocks_in_khz[clks.num_levels>>1] * MEMORY_TYPE_MULTIPLIER_CZ, + 1000); + dc->bw_vbios->high_yclk = bw_frc_to_fixed( + clks.clocks_in_khz[clks.num_levels-1] * MEMORY_TYPE_MULTIPLIER_CZ, + 1000); +} + +static const struct resource_caps *dce110_resource_cap( + struct hw_asic_id *asic_id) +{ + if (ASIC_REV_IS_STONEY(asic_id->hw_internal_rev)) + return &stoney_resource_cap; + else + return &carrizo_resource_cap; +} + +static bool dce110_resource_construct( + uint8_t num_virtual_links, + struct dc *dc, + struct dce110_resource_pool *pool, + struct hw_asic_id asic_id) +{ + unsigned int i; + struct dc_context *ctx = dc->ctx; + struct dc_bios *bp; + + ctx->dc_bios->regs = &bios_regs; + + pool->base.res_cap = dce110_resource_cap(&ctx->asic_id); + pool->base.funcs = &dce110_res_pool_funcs; + + /************************************************* + * Resource + asic cap harcoding * + *************************************************/ + + pool->base.pipe_count = pool->base.res_cap->num_timing_generator; + pool->base.underlay_pipe_index = pool->base.pipe_count; + pool->base.timing_generator_count = pool->base.res_cap->num_timing_generator; + dc->caps.max_downscale_ratio = 150; + dc->caps.i2c_speed_in_khz = 40; + dc->caps.i2c_speed_in_khz_hdcp = 40; + dc->caps.max_cursor_size = 128; + dc->caps.min_horizontal_blanking_period = 80; + dc->caps.is_apu = true; + dc->caps.extended_aux_timeout_support = false; + dc->debug = debug_defaults; + + /************************************************* + * Create resources * + *************************************************/ + + bp = ctx->dc_bios; + + if (bp->fw_info_valid && bp->fw_info.external_clock_source_frequency_for_dp != 0) { + pool->base.dp_clock_source = + dce110_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_EXTERNAL, NULL, true); + + pool->base.clock_sources[0] = + dce110_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL0, + &clk_src_regs[0], false); + pool->base.clock_sources[1] = + dce110_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL1, + &clk_src_regs[1], false); + + pool->base.clk_src_count = 2; + + /* TODO: find out if CZ support 3 PLLs */ + } + + if (pool->base.dp_clock_source == NULL) { + dm_error("DC: failed to create dp clock source!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] == NULL) { + dm_error("DC: failed to create clock sources!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + } + + pool->base.dmcu = dce_dmcu_create(ctx, + &dmcu_regs, + &dmcu_shift, + &dmcu_mask); + if (pool->base.dmcu == NULL) { + dm_error("DC: failed to create dmcu!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + pool->base.abm = dce_abm_create(ctx, + &abm_regs, + &abm_shift, + &abm_mask); + if (pool->base.abm == NULL) { + dm_error("DC: failed to create abm!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + { + struct irq_service_init_data init_data; + init_data.ctx = dc->ctx; + pool->base.irqs = dal_irq_service_dce110_create(&init_data); + if (!pool->base.irqs) + goto res_create_fail; + } + + for (i = 0; i < pool->base.pipe_count; i++) { + pool->base.timing_generators[i] = dce110_timing_generator_create( + ctx, i, &dce110_tg_offsets[i]); + if (pool->base.timing_generators[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create tg!\n"); + goto res_create_fail; + } + + pool->base.mis[i] = dce110_mem_input_create(ctx, i); + if (pool->base.mis[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create memory input!\n"); + goto res_create_fail; + } + + pool->base.ipps[i] = dce110_ipp_create(ctx, i); + if (pool->base.ipps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create input pixel processor!\n"); + goto res_create_fail; + } + + pool->base.transforms[i] = dce110_transform_create(ctx, i); + if (pool->base.transforms[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create transform!\n"); + goto res_create_fail; + } + + pool->base.opps[i] = dce110_opp_create(ctx, i); + if (pool->base.opps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create output pixel processor!\n"); + goto res_create_fail; + } + } + + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + pool->base.engines[i] = dce110_aux_engine_create(ctx, i); + if (pool->base.engines[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create aux engine!!\n"); + goto res_create_fail; + } + pool->base.hw_i2cs[i] = dce110_i2c_hw_create(ctx, i); + if (pool->base.hw_i2cs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create i2c engine!!\n"); + goto res_create_fail; + } + pool->base.sw_i2cs[i] = NULL; + } + + if (dc->config.fbc_support) + dc->fbc_compressor = dce110_compressor_create(ctx); + + if (!underlay_create(ctx, &pool->base)) + goto res_create_fail; + + if (!resource_construct(num_virtual_links, dc, &pool->base, + &res_create_funcs)) + goto res_create_fail; + + /* Create hardware sequencer */ + dce110_hw_sequencer_construct(dc); + + dc->caps.max_planes = pool->base.pipe_count; + + for (i = 0; i < pool->base.underlay_pipe_index; ++i) + dc->caps.planes[i] = plane_cap; + + dc->caps.planes[pool->base.underlay_pipe_index] = underlay_plane_cap; + + bw_calcs_init(dc->bw_dceip, dc->bw_vbios, dc->ctx->asic_id); + + bw_calcs_data_update_from_pplib(dc); + + return true; + +res_create_fail: + dce110_resource_destruct(pool); + return false; +} + +struct resource_pool *dce110_create_resource_pool( + uint8_t num_virtual_links, + struct dc *dc, + struct hw_asic_id asic_id) +{ + struct dce110_resource_pool *pool = + kzalloc(sizeof(struct dce110_resource_pool), GFP_KERNEL); + + if (!pool) + return NULL; + + if (dce110_resource_construct(num_virtual_links, dc, pool, asic_id)) + return &pool->base; + + kfree(pool); + BREAK_TO_DEBUGGER(); + return NULL; +} diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce110/dce110_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dce110/dce110_resource.h new file mode 100644 index 00000000000000..aa4531e0800e69 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dce110/dce110_resource.h @@ -0,0 +1,54 @@ +/* +* 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 __DC_RESOURCE_DCE110_H__ +#define __DC_RESOURCE_DCE110_H__ + +#include "core_types.h" + +struct dc; +struct resource_pool; + +#define TO_DCE110_RES_POOL(pool)\ + container_of(pool, struct dce110_resource_pool, base) + +struct dce110_resource_pool { + struct resource_pool base; +}; + +void dce110_resource_build_pipe_hw_param(struct pipe_ctx *pipe_ctx); + +struct resource_pool *dce110_create_resource_pool( + uint8_t num_virtual_links, + struct dc *dc, + struct hw_asic_id asic_id); + +struct stream_encoder *dce110_find_first_free_match_stream_enc_for_link( + struct resource_context *res_ctx, + const struct resource_pool *pool, + struct dc_stream_state *stream); + +#endif /* __DC_RESOURCE_DCE110_H__ */ + diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce112/dce112_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce112/dce112_resource.c new file mode 100644 index 00000000000000..d1edac46c9a089 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dce112/dce112_resource.c @@ -0,0 +1,1431 @@ +/* +* 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 + * + */ + +#include "dm_services.h" + +#include "link_encoder.h" +#include "stream_encoder.h" + +#include "resource.h" +#include "include/irq_service_interface.h" +#include "dce110/dce110_resource.h" +#include "dce110/dce110_timing_generator.h" + +#include "irq/dce110/irq_service_dce110.h" +#include "dce/dce_mem_input.h" +#include "dce/dce_transform.h" +#include "dce/dce_link_encoder.h" +#include "dce/dce_stream_encoder.h" +#include "dce/dce_audio.h" +#include "dce/dce_opp.h" +#include "dce/dce_ipp.h" +#include "dce/dce_clock_source.h" + +#include "dce/dce_hwseq.h" +#include "dce112/dce112_hwseq.h" +#include "dce/dce_abm.h" +#include "dce/dce_dmcu.h" +#include "dce/dce_aux.h" +#include "dce/dce_i2c.h" +#include "dce/dce_panel_cntl.h" + +#include "reg_helper.h" + +#include "dce/dce_11_2_d.h" +#include "dce/dce_11_2_sh_mask.h" + +#include "dce100/dce100_resource.h" +#include "dce112_resource.h" + +#define DC_LOGGER \ + dc->ctx->logger + +#ifndef mmDP_DPHY_INTERNAL_CTRL + #define mmDP_DPHY_INTERNAL_CTRL 0x4aa7 + #define mmDP0_DP_DPHY_INTERNAL_CTRL 0x4aa7 + #define mmDP1_DP_DPHY_INTERNAL_CTRL 0x4ba7 + #define mmDP2_DP_DPHY_INTERNAL_CTRL 0x4ca7 + #define mmDP3_DP_DPHY_INTERNAL_CTRL 0x4da7 + #define mmDP4_DP_DPHY_INTERNAL_CTRL 0x4ea7 + #define mmDP5_DP_DPHY_INTERNAL_CTRL 0x4fa7 + #define mmDP6_DP_DPHY_INTERNAL_CTRL 0x54a7 + #define mmDP7_DP_DPHY_INTERNAL_CTRL 0x56a7 + #define mmDP8_DP_DPHY_INTERNAL_CTRL 0x57a7 +#endif + +#ifndef mmBIOS_SCRATCH_2 + #define mmBIOS_SCRATCH_2 0x05CB + #define mmBIOS_SCRATCH_3 0x05CC + #define mmBIOS_SCRATCH_6 0x05CF +#endif + +#ifndef mmDP_DPHY_BS_SR_SWAP_CNTL + #define mmDP_DPHY_BS_SR_SWAP_CNTL 0x4ADC + #define mmDP0_DP_DPHY_BS_SR_SWAP_CNTL 0x4ADC + #define mmDP1_DP_DPHY_BS_SR_SWAP_CNTL 0x4BDC + #define mmDP2_DP_DPHY_BS_SR_SWAP_CNTL 0x4CDC + #define mmDP3_DP_DPHY_BS_SR_SWAP_CNTL 0x4DDC + #define mmDP4_DP_DPHY_BS_SR_SWAP_CNTL 0x4EDC + #define mmDP5_DP_DPHY_BS_SR_SWAP_CNTL 0x4FDC + #define mmDP6_DP_DPHY_BS_SR_SWAP_CNTL 0x54DC +#endif + +#ifndef mmDP_DPHY_FAST_TRAINING + #define mmDP_DPHY_FAST_TRAINING 0x4ABC + #define mmDP0_DP_DPHY_FAST_TRAINING 0x4ABC + #define mmDP1_DP_DPHY_FAST_TRAINING 0x4BBC + #define mmDP2_DP_DPHY_FAST_TRAINING 0x4CBC + #define mmDP3_DP_DPHY_FAST_TRAINING 0x4DBC + #define mmDP4_DP_DPHY_FAST_TRAINING 0x4EBC + #define mmDP5_DP_DPHY_FAST_TRAINING 0x4FBC + #define mmDP6_DP_DPHY_FAST_TRAINING 0x54BC +#endif + +enum dce112_clk_src_array_id { + DCE112_CLK_SRC_PLL0, + DCE112_CLK_SRC_PLL1, + DCE112_CLK_SRC_PLL2, + DCE112_CLK_SRC_PLL3, + DCE112_CLK_SRC_PLL4, + DCE112_CLK_SRC_PLL5, + + DCE112_CLK_SRC_TOTAL +}; + +static const struct dce110_timing_generator_offsets dce112_tg_offsets[] = { + { + .crtc = (mmCRTC0_CRTC_CONTROL - mmCRTC_CONTROL), + .dcp = (mmDCP0_GRPH_CONTROL - mmGRPH_CONTROL), + }, + { + .crtc = (mmCRTC1_CRTC_CONTROL - mmCRTC_CONTROL), + .dcp = (mmDCP1_GRPH_CONTROL - mmGRPH_CONTROL), + }, + { + .crtc = (mmCRTC2_CRTC_CONTROL - mmCRTC_CONTROL), + .dcp = (mmDCP2_GRPH_CONTROL - mmGRPH_CONTROL), + }, + { + .crtc = (mmCRTC3_CRTC_CONTROL - mmCRTC_CONTROL), + .dcp = (mmDCP3_GRPH_CONTROL - mmGRPH_CONTROL), + }, + { + .crtc = (mmCRTC4_CRTC_CONTROL - mmCRTC_CONTROL), + .dcp = (mmDCP4_GRPH_CONTROL - mmGRPH_CONTROL), + }, + { + .crtc = (mmCRTC5_CRTC_CONTROL - mmCRTC_CONTROL), + .dcp = (mmDCP5_GRPH_CONTROL - mmGRPH_CONTROL), + } +}; + +/* set register offset */ +#define SR(reg_name)\ + .reg_name = mm ## reg_name + +/* set register offset with instance */ +#define SRI(reg_name, block, id)\ + .reg_name = mm ## block ## id ## _ ## reg_name + +static const struct dce_dmcu_registers dmcu_regs = { + DMCU_DCE110_COMMON_REG_LIST() +}; + +static const struct dce_dmcu_shift dmcu_shift = { + DMCU_MASK_SH_LIST_DCE110(__SHIFT) +}; + +static const struct dce_dmcu_mask dmcu_mask = { + DMCU_MASK_SH_LIST_DCE110(_MASK) +}; + +static const struct dce_abm_registers abm_regs = { + ABM_DCE110_COMMON_REG_LIST() +}; + +static const struct dce_abm_shift abm_shift = { + ABM_MASK_SH_LIST_DCE110(__SHIFT) +}; + +static const struct dce_abm_mask abm_mask = { + ABM_MASK_SH_LIST_DCE110(_MASK) +}; + +static const struct dce110_aux_registers_shift aux_shift = { + DCE_AUX_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce110_aux_registers_mask aux_mask = { + DCE_AUX_MASK_SH_LIST(_MASK) +}; + +#define ipp_regs(id)\ +[id] = {\ + IPP_DCE110_REG_LIST_DCE_BASE(id)\ +} + +static const struct dce_ipp_registers ipp_regs[] = { + ipp_regs(0), + ipp_regs(1), + ipp_regs(2), + ipp_regs(3), + ipp_regs(4), + ipp_regs(5) +}; + +static const struct dce_ipp_shift ipp_shift = { + IPP_DCE100_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) +}; + +static const struct dce_ipp_mask ipp_mask = { + IPP_DCE100_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) +}; + +#define transform_regs(id)\ +[id] = {\ + XFM_COMMON_REG_LIST_DCE110(id)\ +} + +static const struct dce_transform_registers xfm_regs[] = { + transform_regs(0), + transform_regs(1), + transform_regs(2), + transform_regs(3), + transform_regs(4), + transform_regs(5) +}; + +static const struct dce_transform_shift xfm_shift = { + XFM_COMMON_MASK_SH_LIST_DCE110(__SHIFT) +}; + +static const struct dce_transform_mask xfm_mask = { + XFM_COMMON_MASK_SH_LIST_DCE110(_MASK) +}; + +#define aux_regs(id)\ +[id] = {\ + AUX_REG_LIST(id)\ +} + +static const struct dce110_link_enc_aux_registers link_enc_aux_regs[] = { + aux_regs(0), + aux_regs(1), + aux_regs(2), + aux_regs(3), + aux_regs(4), + aux_regs(5) +}; + +static const struct dce_panel_cntl_registers panel_cntl_regs[] = { + { DCE_PANEL_CNTL_REG_LIST() } +}; + +static const struct dce_panel_cntl_shift panel_cntl_shift = { + DCE_PANEL_CNTL_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_panel_cntl_mask panel_cntl_mask = { + DCE_PANEL_CNTL_MASK_SH_LIST(_MASK) +}; + +#define hpd_regs(id)\ +[id] = {\ + HPD_REG_LIST(id)\ +} + +static const struct dce110_link_enc_hpd_registers link_enc_hpd_regs[] = { + hpd_regs(0), + hpd_regs(1), + hpd_regs(2), + hpd_regs(3), + hpd_regs(4), + hpd_regs(5) +}; + +#define link_regs(id)\ +[id] = {\ + LE_DCE110_REG_LIST(id)\ +} + +static const struct dce110_link_enc_registers link_enc_regs[] = { + link_regs(0), + link_regs(1), + link_regs(2), + link_regs(3), + link_regs(4), + link_regs(5), + link_regs(6), +}; + +#define stream_enc_regs(id)\ +[id] = {\ + SE_COMMON_REG_LIST(id),\ + .TMDS_CNTL = 0,\ +} + +static const struct dce110_stream_enc_registers stream_enc_regs[] = { + stream_enc_regs(0), + stream_enc_regs(1), + stream_enc_regs(2), + stream_enc_regs(3), + stream_enc_regs(4), + stream_enc_regs(5) +}; + +static const struct dce_stream_encoder_shift se_shift = { + SE_COMMON_MASK_SH_LIST_DCE112(__SHIFT) +}; + +static const struct dce_stream_encoder_mask se_mask = { + SE_COMMON_MASK_SH_LIST_DCE112(_MASK) +}; + +#define opp_regs(id)\ +[id] = {\ + OPP_DCE_112_REG_LIST(id),\ +} + +static const struct dce_opp_registers opp_regs[] = { + opp_regs(0), + opp_regs(1), + opp_regs(2), + opp_regs(3), + opp_regs(4), + opp_regs(5) +}; + +static const struct dce_opp_shift opp_shift = { + OPP_COMMON_MASK_SH_LIST_DCE_112(__SHIFT) +}; + +static const struct dce_opp_mask opp_mask = { + OPP_COMMON_MASK_SH_LIST_DCE_112(_MASK) +}; + +#define aux_engine_regs(id)\ +[id] = {\ + AUX_COMMON_REG_LIST(id), \ + .AUX_RESET_MASK = 0 \ +} + +static const struct dce110_aux_registers aux_engine_regs[] = { + aux_engine_regs(0), + aux_engine_regs(1), + aux_engine_regs(2), + aux_engine_regs(3), + aux_engine_regs(4), + aux_engine_regs(5) +}; + +#define audio_regs(id)\ +[id] = {\ + AUD_COMMON_REG_LIST(id)\ +} + +static const struct dce_audio_registers audio_regs[] = { + audio_regs(0), + audio_regs(1), + audio_regs(2), + audio_regs(3), + audio_regs(4), + audio_regs(5) +}; + +static const struct dce_audio_shift audio_shift = { + AUD_COMMON_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_audio_mask audio_mask = { + AUD_COMMON_MASK_SH_LIST(_MASK) +}; + +#define clk_src_regs(index, id)\ +[index] = {\ + CS_COMMON_REG_LIST_DCE_112(id),\ +} + +static const struct dce110_clk_src_regs clk_src_regs[] = { + clk_src_regs(0, A), + clk_src_regs(1, B), + clk_src_regs(2, C), + clk_src_regs(3, D), + clk_src_regs(4, E), + clk_src_regs(5, F) +}; + +static const struct dce110_clk_src_shift cs_shift = { + CS_COMMON_MASK_SH_LIST_DCE_112(__SHIFT) +}; + +static const struct dce110_clk_src_mask cs_mask = { + CS_COMMON_MASK_SH_LIST_DCE_112(_MASK) +}; + +static const struct bios_registers bios_regs = { + .BIOS_SCRATCH_3 = mmBIOS_SCRATCH_3, + .BIOS_SCRATCH_6 = mmBIOS_SCRATCH_6 +}; + +static const struct resource_caps polaris_10_resource_cap = { + .num_timing_generator = 6, + .num_audio = 6, + .num_stream_encoder = 6, + .num_pll = 8, /* why 8? 6 combo PHY PLL + 2 regular PLLs? */ + .num_ddc = 6, +}; + +static const struct resource_caps polaris_11_resource_cap = { + .num_timing_generator = 5, + .num_audio = 5, + .num_stream_encoder = 5, + .num_pll = 8, /* why 8? 6 combo PHY PLL + 2 regular PLLs? */ + .num_ddc = 5, +}; + +static const struct dc_plane_cap plane_cap = { + .type = DC_PLANE_TYPE_DCE_RGB, + + .pixel_format_support = { + .argb8888 = true, + .nv12 = false, + .fp16 = true + }, + + .max_upscale_factor = { + .argb8888 = 16000, + .nv12 = 1, + .fp16 = 1 + }, + + .max_downscale_factor = { + .argb8888 = 250, + .nv12 = 1, + .fp16 = 1 + }, + 64, + 64 +}; + +static const struct dc_debug_options debug_defaults = { + .enable_legacy_fast_update = true, +}; + +#define CTX ctx +#define REG(reg) mm ## reg + +#ifndef mmCC_DC_HDMI_STRAPS +#define mmCC_DC_HDMI_STRAPS 0x4819 +#define CC_DC_HDMI_STRAPS__HDMI_DISABLE_MASK 0x40 +#define CC_DC_HDMI_STRAPS__HDMI_DISABLE__SHIFT 0x6 +#define CC_DC_HDMI_STRAPS__AUDIO_STREAM_NUMBER_MASK 0x700 +#define CC_DC_HDMI_STRAPS__AUDIO_STREAM_NUMBER__SHIFT 0x8 +#endif + +static int map_transmitter_id_to_phy_instance( + enum transmitter transmitter) +{ + switch (transmitter) { + case TRANSMITTER_UNIPHY_A: + return 0; + case TRANSMITTER_UNIPHY_B: + return 1; + case TRANSMITTER_UNIPHY_C: + return 2; + case TRANSMITTER_UNIPHY_D: + return 3; + case TRANSMITTER_UNIPHY_E: + return 4; + case TRANSMITTER_UNIPHY_F: + return 5; + case TRANSMITTER_UNIPHY_G: + return 6; + default: + ASSERT(0); + return 0; + } +} + +static void read_dce_straps( + struct dc_context *ctx, + struct resource_straps *straps) +{ + REG_GET_2(CC_DC_HDMI_STRAPS, + HDMI_DISABLE, &straps->hdmi_disable, + AUDIO_STREAM_NUMBER, &straps->audio_stream_number); + + REG_GET(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO, &straps->dc_pinstraps_audio); +} + +static struct audio *create_audio( + struct dc_context *ctx, unsigned int inst) +{ + return dce_audio_create(ctx, inst, + &audio_regs[inst], &audio_shift, &audio_mask); +} + + +static struct timing_generator *dce112_timing_generator_create( + struct dc_context *ctx, + uint32_t instance, + const struct dce110_timing_generator_offsets *offsets) +{ + struct dce110_timing_generator *tg110 = + kzalloc(sizeof(struct dce110_timing_generator), GFP_KERNEL); + + if (!tg110) + return NULL; + + dce110_timing_generator_construct(tg110, ctx, instance, offsets); + return &tg110->base; +} + +static struct stream_encoder *dce112_stream_encoder_create( + enum engine_id eng_id, + struct dc_context *ctx) +{ + struct dce110_stream_encoder *enc110 = + kzalloc(sizeof(struct dce110_stream_encoder), GFP_KERNEL); + + if (!enc110) + return NULL; + + dce110_stream_encoder_construct(enc110, ctx, ctx->dc_bios, eng_id, + &stream_enc_regs[eng_id], + &se_shift, &se_mask); + return &enc110->base; +} + +#define SRII(reg_name, block, id)\ + .reg_name[id] = mm ## block ## id ## _ ## reg_name + +static const struct dce_hwseq_registers hwseq_reg = { + HWSEQ_DCE112_REG_LIST() +}; + +static const struct dce_hwseq_shift hwseq_shift = { + HWSEQ_DCE112_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_hwseq_mask hwseq_mask = { + HWSEQ_DCE112_MASK_SH_LIST(_MASK) +}; + +static struct dce_hwseq *dce112_hwseq_create( + struct dc_context *ctx) +{ + struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); + + if (hws) { + hws->ctx = ctx; + hws->regs = &hwseq_reg; + hws->shifts = &hwseq_shift; + hws->masks = &hwseq_mask; + } + return hws; +} + +static const struct resource_create_funcs res_create_funcs = { + .read_dce_straps = read_dce_straps, + .create_audio = create_audio, + .create_stream_encoder = dce112_stream_encoder_create, + .create_hwseq = dce112_hwseq_create, +}; + +#define mi_inst_regs(id) { MI_DCE11_2_REG_LIST(id) } +static const struct dce_mem_input_registers mi_regs[] = { + mi_inst_regs(0), + mi_inst_regs(1), + mi_inst_regs(2), + mi_inst_regs(3), + mi_inst_regs(4), + mi_inst_regs(5), +}; + +static const struct dce_mem_input_shift mi_shifts = { + MI_DCE11_2_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_mem_input_mask mi_masks = { + MI_DCE11_2_MASK_SH_LIST(_MASK) +}; + +static struct mem_input *dce112_mem_input_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce_mem_input *dce_mi = kzalloc(sizeof(struct dce_mem_input), + GFP_KERNEL); + + if (!dce_mi) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dce112_mem_input_construct(dce_mi, ctx, inst, &mi_regs[inst], &mi_shifts, &mi_masks); + return &dce_mi->base; +} + +static void dce112_transform_destroy(struct transform **xfm) +{ + kfree(TO_DCE_TRANSFORM(*xfm)); + *xfm = NULL; +} + +static struct transform *dce112_transform_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce_transform *transform = + kzalloc(sizeof(struct dce_transform), GFP_KERNEL); + + if (!transform) + return NULL; + + dce_transform_construct(transform, ctx, inst, + &xfm_regs[inst], &xfm_shift, &xfm_mask); + transform->lb_memory_size = 0x1404; /*5124*/ + return &transform->base; +} + +static const struct encoder_feature_support link_enc_feature = { + .max_hdmi_deep_color = COLOR_DEPTH_121212, + .max_hdmi_pixel_clock = 600000, + .hdmi_ycbcr420_supported = true, + .dp_ycbcr420_supported = false, + .flags.bits.IS_HBR2_CAPABLE = true, + .flags.bits.IS_HBR3_CAPABLE = true, + .flags.bits.IS_TPS3_CAPABLE = true, + .flags.bits.IS_TPS4_CAPABLE = true +}; + +static struct link_encoder *dce112_link_encoder_create( + struct dc_context *ctx, + const struct encoder_init_data *enc_init_data) +{ + struct dce110_link_encoder *enc110 = + kzalloc(sizeof(struct dce110_link_encoder), GFP_KERNEL); + int link_regs_id; + + if (!enc110) + return NULL; + + link_regs_id = + map_transmitter_id_to_phy_instance(enc_init_data->transmitter); + + dce110_link_encoder_construct(enc110, + enc_init_data, + &link_enc_feature, + &link_enc_regs[link_regs_id], + &link_enc_aux_regs[enc_init_data->channel - 1], + &link_enc_hpd_regs[enc_init_data->hpd_source]); + return &enc110->base; +} + +static struct panel_cntl *dce112_panel_cntl_create(const struct panel_cntl_init_data *init_data) +{ + struct dce_panel_cntl *panel_cntl = + kzalloc(sizeof(struct dce_panel_cntl), GFP_KERNEL); + + if (!panel_cntl) + return NULL; + + dce_panel_cntl_construct(panel_cntl, + init_data, + &panel_cntl_regs[init_data->inst], + &panel_cntl_shift, + &panel_cntl_mask); + + return &panel_cntl->base; +} + +static struct input_pixel_processor *dce112_ipp_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dce_ipp *ipp = kzalloc(sizeof(struct dce_ipp), GFP_KERNEL); + + if (!ipp) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dce_ipp_construct(ipp, ctx, inst, + &ipp_regs[inst], &ipp_shift, &ipp_mask); + return &ipp->base; +} + +static struct output_pixel_processor *dce112_opp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce110_opp *opp = + kzalloc(sizeof(struct dce110_opp), GFP_KERNEL); + + if (!opp) + return NULL; + + dce110_opp_construct(opp, + ctx, inst, &opp_regs[inst], &opp_shift, &opp_mask); + return &opp->base; +} + +static struct dce_aux *dce112_aux_engine_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct aux_engine_dce110 *aux_engine = + kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); + + if (!aux_engine) + return NULL; + + dce110_aux_engine_construct(aux_engine, ctx, inst, + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, + &aux_engine_regs[inst], + &aux_mask, + &aux_shift, + ctx->dc->caps.extended_aux_timeout_support); + + return &aux_engine->base; +} +#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST(id) } + +static const struct dce_i2c_registers i2c_hw_regs[] = { + i2c_inst_regs(1), + i2c_inst_regs(2), + i2c_inst_regs(3), + i2c_inst_regs(4), + i2c_inst_regs(5), + i2c_inst_regs(6), +}; + +static const struct dce_i2c_shift i2c_shifts = { + I2C_COMMON_MASK_SH_LIST_DCE110(__SHIFT) +}; + +static const struct dce_i2c_mask i2c_masks = { + I2C_COMMON_MASK_SH_LIST_DCE110(_MASK) +}; + +static struct dce_i2c_hw *dce112_i2c_hw_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce_i2c_hw *dce_i2c_hw = + kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); + + if (!dce_i2c_hw) + return NULL; + + dce112_i2c_hw_construct(dce_i2c_hw, ctx, inst, + &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); + + return dce_i2c_hw; +} +static struct clock_source *dce112_clock_source_create( + struct dc_context *ctx, + struct dc_bios *bios, + enum clock_source_id id, + const struct dce110_clk_src_regs *regs, + bool dp_clk_src) +{ + struct dce110_clk_src *clk_src = + kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); + + if (!clk_src) + return NULL; + + if (dce112_clk_src_construct(clk_src, ctx, bios, id, + regs, &cs_shift, &cs_mask)) { + clk_src->base.dp_clk_src = dp_clk_src; + return &clk_src->base; + } + + kfree(clk_src); + BREAK_TO_DEBUGGER(); + return NULL; +} + +static void dce112_clock_source_destroy(struct clock_source **clk_src) +{ + kfree(TO_DCE110_CLK_SRC(*clk_src)); + *clk_src = NULL; +} + +static void dce112_resource_destruct(struct dce110_resource_pool *pool) +{ + unsigned int i; + + for (i = 0; i < pool->base.pipe_count; i++) { + if (pool->base.opps[i] != NULL) + dce110_opp_destroy(&pool->base.opps[i]); + + if (pool->base.transforms[i] != NULL) + dce112_transform_destroy(&pool->base.transforms[i]); + + if (pool->base.ipps[i] != NULL) + dce_ipp_destroy(&pool->base.ipps[i]); + + if (pool->base.mis[i] != NULL) { + kfree(TO_DCE_MEM_INPUT(pool->base.mis[i])); + pool->base.mis[i] = NULL; + } + + if (pool->base.timing_generators[i] != NULL) { + kfree(DCE110TG_FROM_TG(pool->base.timing_generators[i])); + pool->base.timing_generators[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + if (pool->base.engines[i] != NULL) + dce110_engine_destroy(&pool->base.engines[i]); + if (pool->base.hw_i2cs[i] != NULL) { + kfree(pool->base.hw_i2cs[i]); + pool->base.hw_i2cs[i] = NULL; + } + if (pool->base.sw_i2cs[i] != NULL) { + kfree(pool->base.sw_i2cs[i]); + pool->base.sw_i2cs[i] = NULL; + } + } + + for (i = 0; i < pool->base.stream_enc_count; i++) { + if (pool->base.stream_enc[i] != NULL) + kfree(DCE110STRENC_FROM_STRENC(pool->base.stream_enc[i])); + } + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] != NULL) { + dce112_clock_source_destroy(&pool->base.clock_sources[i]); + } + } + + if (pool->base.dp_clock_source != NULL) + dce112_clock_source_destroy(&pool->base.dp_clock_source); + + for (i = 0; i < pool->base.audio_count; i++) { + if (pool->base.audios[i] != NULL) { + dce_aud_destroy(&pool->base.audios[i]); + } + } + + if (pool->base.abm != NULL) + dce_abm_destroy(&pool->base.abm); + + if (pool->base.dmcu != NULL) + dce_dmcu_destroy(&pool->base.dmcu); + + if (pool->base.irqs != NULL) { + dal_irq_service_destroy(&pool->base.irqs); + } +} + +static struct clock_source *find_matching_pll( + struct resource_context *res_ctx, + const struct resource_pool *pool, + const struct dc_stream_state *const stream) +{ + switch (stream->link->link_enc->transmitter) { + case TRANSMITTER_UNIPHY_A: + return pool->clock_sources[DCE112_CLK_SRC_PLL0]; + case TRANSMITTER_UNIPHY_B: + return pool->clock_sources[DCE112_CLK_SRC_PLL1]; + case TRANSMITTER_UNIPHY_C: + return pool->clock_sources[DCE112_CLK_SRC_PLL2]; + case TRANSMITTER_UNIPHY_D: + return pool->clock_sources[DCE112_CLK_SRC_PLL3]; + case TRANSMITTER_UNIPHY_E: + return pool->clock_sources[DCE112_CLK_SRC_PLL4]; + case TRANSMITTER_UNIPHY_F: + return pool->clock_sources[DCE112_CLK_SRC_PLL5]; + default: + return NULL; + } + + return NULL; +} + +static enum dc_status build_mapped_resource( + const struct dc *dc, + struct dc_state *context, + struct dc_stream_state *stream) +{ + struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream); + + if (!pipe_ctx) + return DC_ERROR_UNEXPECTED; + + dce110_resource_build_pipe_hw_param(pipe_ctx); + + resource_build_info_frame(pipe_ctx); + + return DC_OK; +} + +bool dce112_validate_bandwidth( + struct dc *dc, + struct dc_state *context, + bool fast_validate) +{ + bool result = false; + + DC_LOG_BANDWIDTH_CALCS( + "%s: start", + __func__); + + if (bw_calcs( + dc->ctx, + dc->bw_dceip, + dc->bw_vbios, + context->res_ctx.pipe_ctx, + dc->res_pool->pipe_count, + &context->bw_ctx.bw.dce)) + result = true; + + if (!result) + DC_LOG_BANDWIDTH_VALIDATION( + "%s: Bandwidth validation failed!", + __func__); + + if (memcmp(&dc->current_state->bw_ctx.bw.dce, + &context->bw_ctx.bw.dce, sizeof(context->bw_ctx.bw.dce))) { + + DC_LOG_BANDWIDTH_CALCS( + "%s: finish,\n" + "nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n" + "stutMark_b: %d stutMark_a: %d\n" + "nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n" + "stutMark_b: %d stutMark_a: %d\n" + "nbpMark_b: %d nbpMark_a: %d urgentMark_b: %d urgentMark_a: %d\n" + "stutMark_b: %d stutMark_a: %d stutter_mode_enable: %d\n" + "cstate: %d pstate: %d nbpstate: %d sync: %d dispclk: %d\n" + "sclk: %d sclk_sleep: %d yclk: %d blackout_recovery_time_us: %d\n" + , + __func__, + context->bw_ctx.bw.dce.nbp_state_change_wm_ns[0].b_mark, + context->bw_ctx.bw.dce.nbp_state_change_wm_ns[0].a_mark, + context->bw_ctx.bw.dce.urgent_wm_ns[0].b_mark, + context->bw_ctx.bw.dce.urgent_wm_ns[0].a_mark, + context->bw_ctx.bw.dce.stutter_exit_wm_ns[0].b_mark, + context->bw_ctx.bw.dce.stutter_exit_wm_ns[0].a_mark, + context->bw_ctx.bw.dce.nbp_state_change_wm_ns[1].b_mark, + context->bw_ctx.bw.dce.nbp_state_change_wm_ns[1].a_mark, + context->bw_ctx.bw.dce.urgent_wm_ns[1].b_mark, + context->bw_ctx.bw.dce.urgent_wm_ns[1].a_mark, + context->bw_ctx.bw.dce.stutter_exit_wm_ns[1].b_mark, + context->bw_ctx.bw.dce.stutter_exit_wm_ns[1].a_mark, + context->bw_ctx.bw.dce.nbp_state_change_wm_ns[2].b_mark, + context->bw_ctx.bw.dce.nbp_state_change_wm_ns[2].a_mark, + context->bw_ctx.bw.dce.urgent_wm_ns[2].b_mark, + context->bw_ctx.bw.dce.urgent_wm_ns[2].a_mark, + context->bw_ctx.bw.dce.stutter_exit_wm_ns[2].b_mark, + context->bw_ctx.bw.dce.stutter_exit_wm_ns[2].a_mark, + context->bw_ctx.bw.dce.stutter_mode_enable, + context->bw_ctx.bw.dce.cpuc_state_change_enable, + context->bw_ctx.bw.dce.cpup_state_change_enable, + context->bw_ctx.bw.dce.nbp_state_change_enable, + context->bw_ctx.bw.dce.all_displays_in_sync, + context->bw_ctx.bw.dce.dispclk_khz, + context->bw_ctx.bw.dce.sclk_khz, + context->bw_ctx.bw.dce.sclk_deep_sleep_khz, + context->bw_ctx.bw.dce.yclk_khz, + context->bw_ctx.bw.dce.blackout_recovery_time_us); + } + return result; +} + +enum dc_status resource_map_phy_clock_resources( + const struct dc *dc, + struct dc_state *context, + struct dc_stream_state *stream) +{ + + /* acquire new resources */ + struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream( + &context->res_ctx, stream); + + if (!pipe_ctx) + return DC_ERROR_UNEXPECTED; + + if (dc_is_dp_signal(pipe_ctx->stream->signal) + || dc_is_virtual_signal(pipe_ctx->stream->signal)) + pipe_ctx->clock_source = + dc->res_pool->dp_clock_source; + else { + if (stream && stream->link && stream->link->link_enc) + pipe_ctx->clock_source = find_matching_pll( + &context->res_ctx, dc->res_pool, + stream); + } + + if (pipe_ctx->clock_source == NULL) + return DC_NO_CLOCK_SOURCE_RESOURCE; + + resource_reference_clock_source( + &context->res_ctx, + dc->res_pool, + pipe_ctx->clock_source); + + return DC_OK; +} + +static bool dce112_validate_surface_sets( + struct dc_state *context) +{ + int i; + + for (i = 0; i < context->stream_count; i++) { + if (context->stream_status[i].plane_count == 0) + continue; + + if (context->stream_status[i].plane_count > 1) + return false; + + if (context->stream_status[i].plane_states[0]->format + >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) + return false; + } + + return true; +} + +enum dc_status dce112_add_stream_to_ctx( + struct dc *dc, + struct dc_state *new_ctx, + struct dc_stream_state *dc_stream) +{ + enum dc_status result; + + result = resource_map_pool_resources(dc, new_ctx, dc_stream); + + if (result == DC_OK) + result = resource_map_phy_clock_resources(dc, new_ctx, dc_stream); + + + if (result == DC_OK) + result = build_mapped_resource(dc, new_ctx, dc_stream); + + return result; +} + +static enum dc_status dce112_validate_global( + struct dc *dc, + struct dc_state *context) +{ + if (!dce112_validate_surface_sets(context)) + return DC_FAIL_SURFACE_VALIDATE; + + return DC_OK; +} + +static void dce112_destroy_resource_pool(struct resource_pool **pool) +{ + struct dce110_resource_pool *dce110_pool = TO_DCE110_RES_POOL(*pool); + + dce112_resource_destruct(dce110_pool); + kfree(dce110_pool); + *pool = NULL; +} + +static const struct resource_funcs dce112_res_pool_funcs = { + .destroy = dce112_destroy_resource_pool, + .link_enc_create = dce112_link_encoder_create, + .panel_cntl_create = dce112_panel_cntl_create, + .validate_bandwidth = dce112_validate_bandwidth, + .validate_plane = dce100_validate_plane, + .add_stream_to_ctx = dce112_add_stream_to_ctx, + .validate_global = dce112_validate_global, + .find_first_free_match_stream_enc_for_link = dce110_find_first_free_match_stream_enc_for_link +}; + +static void bw_calcs_data_update_from_pplib(struct dc *dc) +{ + struct dm_pp_clock_levels_with_latency eng_clks = {0}; + struct dm_pp_clock_levels_with_latency mem_clks = {0}; + struct dm_pp_wm_sets_with_clock_ranges clk_ranges = {0}; + struct dm_pp_clock_levels clks = {0}; + int memory_type_multiplier = MEMORY_TYPE_MULTIPLIER_CZ; + + if (dc->bw_vbios && dc->bw_vbios->memory_type == bw_def_hbm) + memory_type_multiplier = MEMORY_TYPE_HBM; + + /*do system clock TODO PPLIB: after PPLIB implement, + * then remove old way + */ + if (!dm_pp_get_clock_levels_by_type_with_latency( + dc->ctx, + DM_PP_CLOCK_TYPE_ENGINE_CLK, + &eng_clks)) { + + /* This is only for temporary */ + dm_pp_get_clock_levels_by_type( + dc->ctx, + DM_PP_CLOCK_TYPE_ENGINE_CLK, + &clks); + /* convert all the clock fro kHz to fix point mHz */ + dc->bw_vbios->high_sclk = bw_frc_to_fixed( + clks.clocks_in_khz[clks.num_levels-1], 1000); + dc->bw_vbios->mid1_sclk = bw_frc_to_fixed( + clks.clocks_in_khz[clks.num_levels/8], 1000); + dc->bw_vbios->mid2_sclk = bw_frc_to_fixed( + clks.clocks_in_khz[clks.num_levels*2/8], 1000); + dc->bw_vbios->mid3_sclk = bw_frc_to_fixed( + clks.clocks_in_khz[clks.num_levels*3/8], 1000); + dc->bw_vbios->mid4_sclk = bw_frc_to_fixed( + clks.clocks_in_khz[clks.num_levels*4/8], 1000); + dc->bw_vbios->mid5_sclk = bw_frc_to_fixed( + clks.clocks_in_khz[clks.num_levels*5/8], 1000); + dc->bw_vbios->mid6_sclk = bw_frc_to_fixed( + clks.clocks_in_khz[clks.num_levels*6/8], 1000); + dc->bw_vbios->low_sclk = bw_frc_to_fixed( + clks.clocks_in_khz[0], 1000); + + /*do memory clock*/ + dm_pp_get_clock_levels_by_type( + dc->ctx, + DM_PP_CLOCK_TYPE_MEMORY_CLK, + &clks); + + dc->bw_vbios->low_yclk = bw_frc_to_fixed( + clks.clocks_in_khz[0] * memory_type_multiplier, 1000); + dc->bw_vbios->mid_yclk = bw_frc_to_fixed( + clks.clocks_in_khz[clks.num_levels>>1] * memory_type_multiplier, + 1000); + dc->bw_vbios->high_yclk = bw_frc_to_fixed( + clks.clocks_in_khz[clks.num_levels-1] * memory_type_multiplier, + 1000); + + return; + } + + /* convert all the clock fro kHz to fix point mHz TODO: wloop data */ + dc->bw_vbios->high_sclk = bw_frc_to_fixed( + eng_clks.data[eng_clks.num_levels-1].clocks_in_khz, 1000); + dc->bw_vbios->mid1_sclk = bw_frc_to_fixed( + eng_clks.data[eng_clks.num_levels/8].clocks_in_khz, 1000); + dc->bw_vbios->mid2_sclk = bw_frc_to_fixed( + eng_clks.data[eng_clks.num_levels*2/8].clocks_in_khz, 1000); + dc->bw_vbios->mid3_sclk = bw_frc_to_fixed( + eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz, 1000); + dc->bw_vbios->mid4_sclk = bw_frc_to_fixed( + eng_clks.data[eng_clks.num_levels*4/8].clocks_in_khz, 1000); + dc->bw_vbios->mid5_sclk = bw_frc_to_fixed( + eng_clks.data[eng_clks.num_levels*5/8].clocks_in_khz, 1000); + dc->bw_vbios->mid6_sclk = bw_frc_to_fixed( + eng_clks.data[eng_clks.num_levels*6/8].clocks_in_khz, 1000); + dc->bw_vbios->low_sclk = bw_frc_to_fixed( + eng_clks.data[0].clocks_in_khz, 1000); + + /*do memory clock*/ + dm_pp_get_clock_levels_by_type_with_latency( + dc->ctx, + DM_PP_CLOCK_TYPE_MEMORY_CLK, + &mem_clks); + + /* we don't need to call PPLIB for validation clock since they + * also give us the highest sclk and highest mclk (UMA clock). + * ALSO always convert UMA clock (from PPLIB) to YCLK (HW formula): + * YCLK = UMACLK*m_memoryTypeMultiplier + */ + dc->bw_vbios->low_yclk = bw_frc_to_fixed( + mem_clks.data[0].clocks_in_khz * memory_type_multiplier, 1000); + dc->bw_vbios->mid_yclk = bw_frc_to_fixed( + mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz * memory_type_multiplier, + 1000); + dc->bw_vbios->high_yclk = bw_frc_to_fixed( + mem_clks.data[mem_clks.num_levels-1].clocks_in_khz * memory_type_multiplier, + 1000); + + /* Now notify PPLib/SMU about which Watermarks sets they should select + * depending on DPM state they are in. And update BW MGR GFX Engine and + * Memory clock member variables for Watermarks calculations for each + * Watermark Set + */ + clk_ranges.num_wm_sets = 4; + clk_ranges.wm_clk_ranges[0].wm_set_id = WM_SET_A; + clk_ranges.wm_clk_ranges[0].wm_min_eng_clk_in_khz = + eng_clks.data[0].clocks_in_khz; + clk_ranges.wm_clk_ranges[0].wm_max_eng_clk_in_khz = + eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz - 1; + clk_ranges.wm_clk_ranges[0].wm_min_mem_clk_in_khz = + mem_clks.data[0].clocks_in_khz; + clk_ranges.wm_clk_ranges[0].wm_max_mem_clk_in_khz = + mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz - 1; + + clk_ranges.wm_clk_ranges[1].wm_set_id = WM_SET_B; + clk_ranges.wm_clk_ranges[1].wm_min_eng_clk_in_khz = + eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz; + /* 5 GHz instead of data[7].clockInKHz to cover Overdrive */ + clk_ranges.wm_clk_ranges[1].wm_max_eng_clk_in_khz = 5000000; + clk_ranges.wm_clk_ranges[1].wm_min_mem_clk_in_khz = + mem_clks.data[0].clocks_in_khz; + clk_ranges.wm_clk_ranges[1].wm_max_mem_clk_in_khz = + mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz - 1; + + clk_ranges.wm_clk_ranges[2].wm_set_id = WM_SET_C; + clk_ranges.wm_clk_ranges[2].wm_min_eng_clk_in_khz = + eng_clks.data[0].clocks_in_khz; + clk_ranges.wm_clk_ranges[2].wm_max_eng_clk_in_khz = + eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz - 1; + clk_ranges.wm_clk_ranges[2].wm_min_mem_clk_in_khz = + mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz; + /* 5 GHz instead of data[2].clockInKHz to cover Overdrive */ + clk_ranges.wm_clk_ranges[2].wm_max_mem_clk_in_khz = 5000000; + + clk_ranges.wm_clk_ranges[3].wm_set_id = WM_SET_D; + clk_ranges.wm_clk_ranges[3].wm_min_eng_clk_in_khz = + eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz; + /* 5 GHz instead of data[7].clockInKHz to cover Overdrive */ + clk_ranges.wm_clk_ranges[3].wm_max_eng_clk_in_khz = 5000000; + clk_ranges.wm_clk_ranges[3].wm_min_mem_clk_in_khz = + mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz; + /* 5 GHz instead of data[2].clockInKHz to cover Overdrive */ + clk_ranges.wm_clk_ranges[3].wm_max_mem_clk_in_khz = 5000000; + + /* Notify PP Lib/SMU which Watermarks to use for which clock ranges */ + dm_pp_notify_wm_clock_changes(dc->ctx, &clk_ranges); +} + +static const struct resource_caps *dce112_resource_cap( + struct hw_asic_id *asic_id) +{ + if (ASIC_REV_IS_POLARIS11_M(asic_id->hw_internal_rev) || + ASIC_REV_IS_POLARIS12_V(asic_id->hw_internal_rev)) + return &polaris_11_resource_cap; + else + return &polaris_10_resource_cap; +} + +static bool dce112_resource_construct( + uint8_t num_virtual_links, + struct dc *dc, + struct dce110_resource_pool *pool) +{ + unsigned int i; + struct dc_context *ctx = dc->ctx; + + ctx->dc_bios->regs = &bios_regs; + + pool->base.res_cap = dce112_resource_cap(&ctx->asic_id); + pool->base.funcs = &dce112_res_pool_funcs; + + /************************************************* + * Resource + asic cap harcoding * + *************************************************/ + pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.pipe_count = pool->base.res_cap->num_timing_generator; + pool->base.timing_generator_count = pool->base.res_cap->num_timing_generator; + dc->caps.max_downscale_ratio = 200; + dc->caps.i2c_speed_in_khz = 100; + dc->caps.i2c_speed_in_khz_hdcp = 100; /*1.4 w/a not applied by default*/ + dc->caps.max_cursor_size = 128; + dc->caps.min_horizontal_blanking_period = 80; + dc->caps.dual_link_dvi = true; + dc->caps.extended_aux_timeout_support = false; + dc->debug = debug_defaults; + + /************************************************* + * Create resources * + *************************************************/ + + pool->base.clock_sources[DCE112_CLK_SRC_PLL0] = + dce112_clock_source_create( + ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL0, + &clk_src_regs[0], false); + pool->base.clock_sources[DCE112_CLK_SRC_PLL1] = + dce112_clock_source_create( + ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL1, + &clk_src_regs[1], false); + pool->base.clock_sources[DCE112_CLK_SRC_PLL2] = + dce112_clock_source_create( + ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL2, + &clk_src_regs[2], false); + pool->base.clock_sources[DCE112_CLK_SRC_PLL3] = + dce112_clock_source_create( + ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL3, + &clk_src_regs[3], false); + pool->base.clock_sources[DCE112_CLK_SRC_PLL4] = + dce112_clock_source_create( + ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL4, + &clk_src_regs[4], false); + pool->base.clock_sources[DCE112_CLK_SRC_PLL5] = + dce112_clock_source_create( + ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL5, + &clk_src_regs[5], false); + pool->base.clk_src_count = DCE112_CLK_SRC_TOTAL; + + pool->base.dp_clock_source = dce112_clock_source_create( + ctx, ctx->dc_bios, + CLOCK_SOURCE_ID_DP_DTO, &clk_src_regs[0], true); + + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] == NULL) { + dm_error("DC: failed to create clock sources!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + } + + pool->base.dmcu = dce_dmcu_create(ctx, + &dmcu_regs, + &dmcu_shift, + &dmcu_mask); + if (pool->base.dmcu == NULL) { + dm_error("DC: failed to create dmcu!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + pool->base.abm = dce_abm_create(ctx, + &abm_regs, + &abm_shift, + &abm_mask); + if (pool->base.abm == NULL) { + dm_error("DC: failed to create abm!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + { + struct irq_service_init_data init_data; + init_data.ctx = dc->ctx; + pool->base.irqs = dal_irq_service_dce110_create(&init_data); + if (!pool->base.irqs) + goto res_create_fail; + } + + for (i = 0; i < pool->base.pipe_count; i++) { + pool->base.timing_generators[i] = + dce112_timing_generator_create( + ctx, + i, + &dce112_tg_offsets[i]); + if (pool->base.timing_generators[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create tg!\n"); + goto res_create_fail; + } + + pool->base.mis[i] = dce112_mem_input_create(ctx, i); + if (pool->base.mis[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create memory input!\n"); + goto res_create_fail; + } + + pool->base.ipps[i] = dce112_ipp_create(ctx, i); + if (pool->base.ipps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create input pixel processor!\n"); + goto res_create_fail; + } + + pool->base.transforms[i] = dce112_transform_create(ctx, i); + if (pool->base.transforms[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create transform!\n"); + goto res_create_fail; + } + + pool->base.opps[i] = dce112_opp_create( + ctx, + i); + if (pool->base.opps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create output pixel processor!\n"); + goto res_create_fail; + } + } + + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + pool->base.engines[i] = dce112_aux_engine_create(ctx, i); + if (pool->base.engines[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create aux engine!!\n"); + goto res_create_fail; + } + pool->base.hw_i2cs[i] = dce112_i2c_hw_create(ctx, i); + if (pool->base.hw_i2cs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create i2c engine!!\n"); + goto res_create_fail; + } + pool->base.sw_i2cs[i] = NULL; + } + + if (!resource_construct(num_virtual_links, dc, &pool->base, + &res_create_funcs)) + goto res_create_fail; + + dc->caps.max_planes = pool->base.pipe_count; + + for (i = 0; i < dc->caps.max_planes; ++i) + dc->caps.planes[i] = plane_cap; + + /* Create hardware sequencer */ + dce112_hw_sequencer_construct(dc); + + bw_calcs_init(dc->bw_dceip, dc->bw_vbios, dc->ctx->asic_id); + + bw_calcs_data_update_from_pplib(dc); + + return true; + +res_create_fail: + dce112_resource_destruct(pool); + return false; +} + +struct resource_pool *dce112_create_resource_pool( + uint8_t num_virtual_links, + struct dc *dc) +{ + struct dce110_resource_pool *pool = + kzalloc(sizeof(struct dce110_resource_pool), GFP_KERNEL); + + if (!pool) + return NULL; + + if (dce112_resource_construct(num_virtual_links, dc, pool)) + return &pool->base; + + kfree(pool); + BREAK_TO_DEBUGGER(); + return NULL; +} diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce112/dce112_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dce112/dce112_resource.h new file mode 100644 index 00000000000000..1f57ebc6f9b440 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dce112/dce112_resource.h @@ -0,0 +1,57 @@ +/* +* 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 __DC_RESOURCE_DCE112_H__ +#define __DC_RESOURCE_DCE112_H__ + +#include "core_types.h" + +struct dc; +struct resource_pool; + +struct resource_pool *dce112_create_resource_pool( + uint8_t num_virtual_links, + struct dc *dc); + +enum dc_status dce112_validate_with_context( + struct dc *dc, + const struct dc_validation_set set[], + int set_count, + struct dc_state *context, + struct dc_state *old_context); + +bool dce112_validate_bandwidth( + struct dc *dc, + struct dc_state *context, + bool fast_validate); + +enum dc_status dce112_add_stream_to_ctx( + struct dc *dc, + struct dc_state *new_ctx, + struct dc_stream_state *dc_stream); + + +#endif /* __DC_RESOURCE_DCE112_H__ */ + diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce120/dce120_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce120/dce120_resource.c new file mode 100644 index 00000000000000..20662edd0ae457 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dce120/dce120_resource.c @@ -0,0 +1,1288 @@ +/* +* Copyright 2012-15 Advanced Micro Devices, Inc.cls +* + * + * 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 "stream_encoder.h" +#include "resource.h" +#include "include/irq_service_interface.h" +#include "dce120_resource.h" + +#include "dce112/dce112_resource.h" + +#include "dce110/dce110_resource.h" +#include "virtual/virtual_stream_encoder.h" +#include "dce120/dce120_timing_generator.h" +#include "irq/dce120/irq_service_dce120.h" +#include "dce/dce_opp.h" +#include "dce/dce_clock_source.h" +#include "dce/dce_ipp.h" +#include "dce/dce_mem_input.h" +#include "dce/dce_panel_cntl.h" + +#include "dce110/dce110_hwseq.h" +#include "dce120/dce120_hwseq.h" +#include "dce/dce_transform.h" +#include "clk_mgr.h" +#include "dce/dce_audio.h" +#include "dce/dce_link_encoder.h" +#include "dce/dce_stream_encoder.h" +#include "dce/dce_hwseq.h" +#include "dce/dce_abm.h" +#include "dce/dce_dmcu.h" +#include "dce/dce_aux.h" +#include "dce/dce_i2c.h" + +#include "dce/dce_12_0_offset.h" +#include "dce/dce_12_0_sh_mask.h" +#include "soc15_hw_ip.h" +#include "vega10_ip_offset.h" +#include "nbio/nbio_6_1_offset.h" +#include "mmhub/mmhub_1_0_offset.h" +#include "mmhub/mmhub_1_0_sh_mask.h" +#include "reg_helper.h" + +#include "dce100/dce100_resource.h" + +#ifndef mmDP0_DP_DPHY_INTERNAL_CTRL + #define mmDP0_DP_DPHY_INTERNAL_CTRL 0x210f + #define mmDP0_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 + #define mmDP1_DP_DPHY_INTERNAL_CTRL 0x220f + #define mmDP1_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 + #define mmDP2_DP_DPHY_INTERNAL_CTRL 0x230f + #define mmDP2_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 + #define mmDP3_DP_DPHY_INTERNAL_CTRL 0x240f + #define mmDP3_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 + #define mmDP4_DP_DPHY_INTERNAL_CTRL 0x250f + #define mmDP4_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 + #define mmDP5_DP_DPHY_INTERNAL_CTRL 0x260f + #define mmDP5_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 + #define mmDP6_DP_DPHY_INTERNAL_CTRL 0x270f + #define mmDP6_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 +#endif + +enum dce120_clk_src_array_id { + DCE120_CLK_SRC_PLL0, + DCE120_CLK_SRC_PLL1, + DCE120_CLK_SRC_PLL2, + DCE120_CLK_SRC_PLL3, + DCE120_CLK_SRC_PLL4, + DCE120_CLK_SRC_PLL5, + + DCE120_CLK_SRC_TOTAL +}; + +static const struct dce110_timing_generator_offsets dce120_tg_offsets[] = { + { + .crtc = (mmCRTC0_CRTC_CONTROL - mmCRTC0_CRTC_CONTROL), + }, + { + .crtc = (mmCRTC1_CRTC_CONTROL - mmCRTC0_CRTC_CONTROL), + }, + { + .crtc = (mmCRTC2_CRTC_CONTROL - mmCRTC0_CRTC_CONTROL), + }, + { + .crtc = (mmCRTC3_CRTC_CONTROL - mmCRTC0_CRTC_CONTROL), + }, + { + .crtc = (mmCRTC4_CRTC_CONTROL - mmCRTC0_CRTC_CONTROL), + }, + { + .crtc = (mmCRTC5_CRTC_CONTROL - mmCRTC0_CRTC_CONTROL), + } +}; + +/* begin ********************* + * macros to expend register list macro defined in HW object header file */ + +#define BASE_INNER(seg) \ + DCE_BASE__INST0_SEG ## seg + +#define NBIO_BASE_INNER(seg) \ + NBIF_BASE__INST0_SEG ## seg + +#define NBIO_BASE(seg) \ + NBIO_BASE_INNER(seg) + +/* compile time expand base address. */ +#define BASE(seg) \ + BASE_INNER(seg) + +#define SR(reg_name)\ + .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + \ + mm ## reg_name + +#define SRI(reg_name, block, id)\ + .reg_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +/* MMHUB */ +#define MMHUB_BASE_INNER(seg) \ + MMHUB_BASE__INST0_SEG ## seg + +#define MMHUB_BASE(seg) \ + MMHUB_BASE_INNER(seg) + +#define MMHUB_SR(reg_name)\ + .reg_name = MMHUB_BASE(mm ## reg_name ## _BASE_IDX) + \ + mm ## reg_name + +/* macros to expend register list macro defined in HW object header file + * end *********************/ + + +static const struct dce_dmcu_registers dmcu_regs = { + DMCU_DCE110_COMMON_REG_LIST() +}; + +static const struct dce_dmcu_shift dmcu_shift = { + DMCU_MASK_SH_LIST_DCE110(__SHIFT) +}; + +static const struct dce_dmcu_mask dmcu_mask = { + DMCU_MASK_SH_LIST_DCE110(_MASK) +}; + +static const struct dce_abm_registers abm_regs = { + ABM_DCE110_COMMON_REG_LIST() +}; + +static const struct dce_abm_shift abm_shift = { + ABM_MASK_SH_LIST_DCE110(__SHIFT) +}; + +static const struct dce_abm_mask abm_mask = { + ABM_MASK_SH_LIST_DCE110(_MASK) +}; + +#define ipp_regs(id)\ +[id] = {\ + IPP_DCE110_REG_LIST_DCE_BASE(id)\ +} + +static const struct dce_ipp_registers ipp_regs[] = { + ipp_regs(0), + ipp_regs(1), + ipp_regs(2), + ipp_regs(3), + ipp_regs(4), + ipp_regs(5) +}; + +static const struct dce_ipp_shift ipp_shift = { + IPP_DCE120_MASK_SH_LIST_SOC_BASE(__SHIFT) +}; + +static const struct dce_ipp_mask ipp_mask = { + IPP_DCE120_MASK_SH_LIST_SOC_BASE(_MASK) +}; + +#define transform_regs(id)\ +[id] = {\ + XFM_COMMON_REG_LIST_DCE110(id)\ +} + +static const struct dce_transform_registers xfm_regs[] = { + transform_regs(0), + transform_regs(1), + transform_regs(2), + transform_regs(3), + transform_regs(4), + transform_regs(5) +}; + +static const struct dce_transform_shift xfm_shift = { + XFM_COMMON_MASK_SH_LIST_SOC_BASE(__SHIFT) +}; + +static const struct dce_transform_mask xfm_mask = { + XFM_COMMON_MASK_SH_LIST_SOC_BASE(_MASK) +}; + +#define aux_regs(id)\ +[id] = {\ + AUX_REG_LIST(id)\ +} + +static const struct dce110_link_enc_aux_registers link_enc_aux_regs[] = { + aux_regs(0), + aux_regs(1), + aux_regs(2), + aux_regs(3), + aux_regs(4), + aux_regs(5) +}; + +#define hpd_regs(id)\ +[id] = {\ + HPD_REG_LIST(id)\ +} + +static const struct dce110_link_enc_hpd_registers link_enc_hpd_regs[] = { + hpd_regs(0), + hpd_regs(1), + hpd_regs(2), + hpd_regs(3), + hpd_regs(4), + hpd_regs(5) +}; + +#define link_regs(id)\ +[id] = {\ + LE_DCE120_REG_LIST(id), \ + SRI(DP_DPHY_INTERNAL_CTRL, DP, id) \ +} + +static const struct dce110_link_enc_registers link_enc_regs[] = { + link_regs(0), + link_regs(1), + link_regs(2), + link_regs(3), + link_regs(4), + link_regs(5), + link_regs(6), +}; + + +#define stream_enc_regs(id)\ +[id] = {\ + SE_COMMON_REG_LIST(id),\ + .TMDS_CNTL = 0,\ +} + +static const struct dce110_stream_enc_registers stream_enc_regs[] = { + stream_enc_regs(0), + stream_enc_regs(1), + stream_enc_regs(2), + stream_enc_regs(3), + stream_enc_regs(4), + stream_enc_regs(5) +}; + +static const struct dce_stream_encoder_shift se_shift = { + SE_COMMON_MASK_SH_LIST_DCE120(__SHIFT) +}; + +static const struct dce_stream_encoder_mask se_mask = { + SE_COMMON_MASK_SH_LIST_DCE120(_MASK) +}; + +static const struct dce_panel_cntl_registers panel_cntl_regs[] = { + { DCE_PANEL_CNTL_REG_LIST() } +}; + +static const struct dce_panel_cntl_shift panel_cntl_shift = { + DCE_PANEL_CNTL_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_panel_cntl_mask panel_cntl_mask = { + DCE_PANEL_CNTL_MASK_SH_LIST(_MASK) +}; + +static const struct dce110_aux_registers_shift aux_shift = { + DCE12_AUX_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce110_aux_registers_mask aux_mask = { + DCE12_AUX_MASK_SH_LIST(_MASK) +}; + +#define opp_regs(id)\ +[id] = {\ + OPP_DCE_120_REG_LIST(id),\ +} + +static const struct dce_opp_registers opp_regs[] = { + opp_regs(0), + opp_regs(1), + opp_regs(2), + opp_regs(3), + opp_regs(4), + opp_regs(5) +}; + +static const struct dce_opp_shift opp_shift = { + OPP_COMMON_MASK_SH_LIST_DCE_120(__SHIFT) +}; + +static const struct dce_opp_mask opp_mask = { + OPP_COMMON_MASK_SH_LIST_DCE_120(_MASK) +}; + #define aux_engine_regs(id)\ +[id] = {\ + AUX_COMMON_REG_LIST(id), \ + .AUX_RESET_MASK = 0 \ +} + +static const struct dce110_aux_registers aux_engine_regs[] = { + aux_engine_regs(0), + aux_engine_regs(1), + aux_engine_regs(2), + aux_engine_regs(3), + aux_engine_regs(4), + aux_engine_regs(5) +}; + +#define audio_regs(id)\ +[id] = {\ + AUD_COMMON_REG_LIST(id)\ +} + +static const struct dce_audio_registers audio_regs[] = { + audio_regs(0), + audio_regs(1), + audio_regs(2), + audio_regs(3), + audio_regs(4), + audio_regs(5), + audio_regs(6), +}; + +#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ + AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) + +static const struct dce_audio_shift audio_shift = { + DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_audio_mask audio_mask = { + DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) +}; + +static int map_transmitter_id_to_phy_instance( + enum transmitter transmitter) +{ + switch (transmitter) { + case TRANSMITTER_UNIPHY_A: + return 0; + case TRANSMITTER_UNIPHY_B: + return 1; + case TRANSMITTER_UNIPHY_C: + return 2; + case TRANSMITTER_UNIPHY_D: + return 3; + case TRANSMITTER_UNIPHY_E: + return 4; + case TRANSMITTER_UNIPHY_F: + return 5; + case TRANSMITTER_UNIPHY_G: + return 6; + default: + ASSERT(0); + return 0; + } +} + +#define clk_src_regs(index, id)\ +[index] = {\ + CS_COMMON_REG_LIST_DCE_112(id),\ +} + +static const struct dce110_clk_src_regs clk_src_regs[] = { + clk_src_regs(0, A), + clk_src_regs(1, B), + clk_src_regs(2, C), + clk_src_regs(3, D), + clk_src_regs(4, E), + clk_src_regs(5, F) +}; + +static const struct dce110_clk_src_shift cs_shift = { + CS_COMMON_MASK_SH_LIST_DCE_112(__SHIFT) +}; + +static const struct dce110_clk_src_mask cs_mask = { + CS_COMMON_MASK_SH_LIST_DCE_112(_MASK) +}; + +static struct output_pixel_processor *dce120_opp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce110_opp *opp = + kzalloc(sizeof(struct dce110_opp), GFP_KERNEL); + + if (!opp) + return NULL; + + dce110_opp_construct(opp, + ctx, inst, &opp_regs[inst], &opp_shift, &opp_mask); + return &opp->base; +} +static struct dce_aux *dce120_aux_engine_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct aux_engine_dce110 *aux_engine = + kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); + + if (!aux_engine) + return NULL; + + dce110_aux_engine_construct(aux_engine, ctx, inst, + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, + &aux_engine_regs[inst], + &aux_mask, + &aux_shift, + ctx->dc->caps.extended_aux_timeout_support); + + return &aux_engine->base; +} +#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST(id) } + +static const struct dce_i2c_registers i2c_hw_regs[] = { + i2c_inst_regs(1), + i2c_inst_regs(2), + i2c_inst_regs(3), + i2c_inst_regs(4), + i2c_inst_regs(5), + i2c_inst_regs(6), +}; + +static const struct dce_i2c_shift i2c_shifts = { + I2C_COMMON_MASK_SH_LIST_DCE110(__SHIFT) +}; + +static const struct dce_i2c_mask i2c_masks = { + I2C_COMMON_MASK_SH_LIST_DCE110(_MASK) +}; + +static struct dce_i2c_hw *dce120_i2c_hw_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce_i2c_hw *dce_i2c_hw = + kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); + + if (!dce_i2c_hw) + return NULL; + + dce112_i2c_hw_construct(dce_i2c_hw, ctx, inst, + &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); + + return dce_i2c_hw; +} +static const struct bios_registers bios_regs = { + .BIOS_SCRATCH_3 = mmBIOS_SCRATCH_3 + NBIO_BASE(mmBIOS_SCRATCH_3_BASE_IDX), + .BIOS_SCRATCH_6 = mmBIOS_SCRATCH_6 + NBIO_BASE(mmBIOS_SCRATCH_6_BASE_IDX) +}; + +static const struct resource_caps res_cap = { + .num_timing_generator = 6, + .num_audio = 7, + .num_stream_encoder = 6, + .num_pll = 6, + .num_ddc = 6, +}; + +static const struct dc_plane_cap plane_cap = { + .type = DC_PLANE_TYPE_DCE_RGB, + + .pixel_format_support = { + .argb8888 = true, + .nv12 = false, + .fp16 = true + }, + + .max_upscale_factor = { + .argb8888 = 16000, + .nv12 = 1, + .fp16 = 1 + }, + + .max_downscale_factor = { + .argb8888 = 250, + .nv12 = 1, + .fp16 = 1 + } +}; + +static const struct dc_debug_options debug_defaults = { + .disable_clock_gate = true, + .enable_legacy_fast_update = true, +}; + +static struct clock_source *dce120_clock_source_create( + struct dc_context *ctx, + struct dc_bios *bios, + enum clock_source_id id, + const struct dce110_clk_src_regs *regs, + bool dp_clk_src) +{ + struct dce110_clk_src *clk_src = + kzalloc(sizeof(*clk_src), GFP_KERNEL); + + if (!clk_src) + return NULL; + + if (dce112_clk_src_construct(clk_src, ctx, bios, id, + regs, &cs_shift, &cs_mask)) { + clk_src->base.dp_clk_src = dp_clk_src; + return &clk_src->base; + } + + kfree(clk_src); + BREAK_TO_DEBUGGER(); + return NULL; +} + +static void dce120_clock_source_destroy(struct clock_source **clk_src) +{ + kfree(TO_DCE110_CLK_SRC(*clk_src)); + *clk_src = NULL; +} + + +static bool dce120_hw_sequencer_create(struct dc *dc) +{ + /* All registers used by dce11.2 match those in dce11 in offset and + * structure + */ + dce120_hw_sequencer_construct(dc); + + /*TODO Move to separate file and Override what is needed */ + + return true; +} + +static struct timing_generator *dce120_timing_generator_create( + struct dc_context *ctx, + uint32_t instance, + const struct dce110_timing_generator_offsets *offsets) +{ + struct dce110_timing_generator *tg110 = + kzalloc(sizeof(struct dce110_timing_generator), GFP_KERNEL); + + if (!tg110) + return NULL; + + dce120_timing_generator_construct(tg110, ctx, instance, offsets); + return &tg110->base; +} + +static void dce120_transform_destroy(struct transform **xfm) +{ + kfree(TO_DCE_TRANSFORM(*xfm)); + *xfm = NULL; +} + +static void dce120_resource_destruct(struct dce110_resource_pool *pool) +{ + unsigned int i; + + for (i = 0; i < pool->base.pipe_count; i++) { + if (pool->base.opps[i] != NULL) + dce110_opp_destroy(&pool->base.opps[i]); + + if (pool->base.transforms[i] != NULL) + dce120_transform_destroy(&pool->base.transforms[i]); + + if (pool->base.ipps[i] != NULL) + dce_ipp_destroy(&pool->base.ipps[i]); + + if (pool->base.mis[i] != NULL) { + kfree(TO_DCE_MEM_INPUT(pool->base.mis[i])); + pool->base.mis[i] = NULL; + } + + if (pool->base.irqs != NULL) { + dal_irq_service_destroy(&pool->base.irqs); + } + + if (pool->base.timing_generators[i] != NULL) { + kfree(DCE110TG_FROM_TG(pool->base.timing_generators[i])); + pool->base.timing_generators[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + if (pool->base.engines[i] != NULL) + dce110_engine_destroy(&pool->base.engines[i]); + if (pool->base.hw_i2cs[i] != NULL) { + kfree(pool->base.hw_i2cs[i]); + pool->base.hw_i2cs[i] = NULL; + } + if (pool->base.sw_i2cs[i] != NULL) { + kfree(pool->base.sw_i2cs[i]); + pool->base.sw_i2cs[i] = NULL; + } + } + + for (i = 0; i < pool->base.audio_count; i++) { + if (pool->base.audios[i]) + dce_aud_destroy(&pool->base.audios[i]); + } + + for (i = 0; i < pool->base.stream_enc_count; i++) { + if (pool->base.stream_enc[i] != NULL) + kfree(DCE110STRENC_FROM_STRENC(pool->base.stream_enc[i])); + } + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] != NULL) + dce120_clock_source_destroy( + &pool->base.clock_sources[i]); + } + + if (pool->base.dp_clock_source != NULL) + dce120_clock_source_destroy(&pool->base.dp_clock_source); + + if (pool->base.abm != NULL) + dce_abm_destroy(&pool->base.abm); + + if (pool->base.dmcu != NULL) + dce_dmcu_destroy(&pool->base.dmcu); +} + +static void read_dce_straps( + struct dc_context *ctx, + struct resource_straps *straps) +{ + uint32_t reg_val = dm_read_reg_soc15(ctx, mmCC_DC_MISC_STRAPS, 0); + + straps->audio_stream_number = get_reg_field_value(reg_val, + CC_DC_MISC_STRAPS, + AUDIO_STREAM_NUMBER); + straps->hdmi_disable = get_reg_field_value(reg_val, + CC_DC_MISC_STRAPS, + HDMI_DISABLE); + + reg_val = dm_read_reg_soc15(ctx, mmDC_PINSTRAPS, 0); + straps->dc_pinstraps_audio = get_reg_field_value(reg_val, + DC_PINSTRAPS, + DC_PINSTRAPS_AUDIO); +} + +static struct audio *create_audio( + struct dc_context *ctx, unsigned int inst) +{ + return dce_audio_create(ctx, inst, + &audio_regs[inst], &audio_shift, &audio_mask); +} + +static const struct encoder_feature_support link_enc_feature = { + .max_hdmi_deep_color = COLOR_DEPTH_121212, + .max_hdmi_pixel_clock = 600000, + .hdmi_ycbcr420_supported = true, + .dp_ycbcr420_supported = false, + .flags.bits.IS_HBR2_CAPABLE = true, + .flags.bits.IS_HBR3_CAPABLE = true, + .flags.bits.IS_TPS3_CAPABLE = true, + .flags.bits.IS_TPS4_CAPABLE = true, +}; + +static struct link_encoder *dce120_link_encoder_create( + struct dc_context *ctx, + const struct encoder_init_data *enc_init_data) +{ + struct dce110_link_encoder *enc110 = + kzalloc(sizeof(struct dce110_link_encoder), GFP_KERNEL); + int link_regs_id; + + if (!enc110) + return NULL; + + link_regs_id = + map_transmitter_id_to_phy_instance(enc_init_data->transmitter); + + dce110_link_encoder_construct(enc110, + enc_init_data, + &link_enc_feature, + &link_enc_regs[link_regs_id], + &link_enc_aux_regs[enc_init_data->channel - 1], + &link_enc_hpd_regs[enc_init_data->hpd_source]); + + return &enc110->base; +} + +static struct panel_cntl *dce120_panel_cntl_create(const struct panel_cntl_init_data *init_data) +{ + struct dce_panel_cntl *panel_cntl = + kzalloc(sizeof(struct dce_panel_cntl), GFP_KERNEL); + + if (!panel_cntl) + return NULL; + + dce_panel_cntl_construct(panel_cntl, + init_data, + &panel_cntl_regs[init_data->inst], + &panel_cntl_shift, + &panel_cntl_mask); + + return &panel_cntl->base; +} + +static struct input_pixel_processor *dce120_ipp_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dce_ipp *ipp = kzalloc(sizeof(struct dce_ipp), GFP_KERNEL); + + if (!ipp) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dce_ipp_construct(ipp, ctx, inst, + &ipp_regs[inst], &ipp_shift, &ipp_mask); + return &ipp->base; +} + +static struct stream_encoder *dce120_stream_encoder_create( + enum engine_id eng_id, + struct dc_context *ctx) +{ + struct dce110_stream_encoder *enc110 = + kzalloc(sizeof(struct dce110_stream_encoder), GFP_KERNEL); + + if (!enc110) + return NULL; + + dce110_stream_encoder_construct(enc110, ctx, ctx->dc_bios, eng_id, + &stream_enc_regs[eng_id], + &se_shift, &se_mask); + return &enc110->base; +} + +#define SRII(reg_name, block, id)\ + .reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +static const struct dce_hwseq_registers hwseq_reg = { + HWSEQ_DCE120_REG_LIST() +}; + +static const struct dce_hwseq_shift hwseq_shift = { + HWSEQ_DCE12_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_hwseq_mask hwseq_mask = { + HWSEQ_DCE12_MASK_SH_LIST(_MASK) +}; + +/* HWSEQ regs for VG20 */ +static const struct dce_hwseq_registers dce121_hwseq_reg = { + HWSEQ_VG20_REG_LIST() +}; + +static const struct dce_hwseq_shift dce121_hwseq_shift = { + HWSEQ_VG20_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_hwseq_mask dce121_hwseq_mask = { + HWSEQ_VG20_MASK_SH_LIST(_MASK) +}; + +static struct dce_hwseq *dce120_hwseq_create( + struct dc_context *ctx) +{ + struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); + + if (hws) { + hws->ctx = ctx; + hws->regs = &hwseq_reg; + hws->shifts = &hwseq_shift; + hws->masks = &hwseq_mask; + } + return hws; +} + +static struct dce_hwseq *dce121_hwseq_create( + struct dc_context *ctx) +{ + struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); + + if (hws) { + hws->ctx = ctx; + hws->regs = &dce121_hwseq_reg; + hws->shifts = &dce121_hwseq_shift; + hws->masks = &dce121_hwseq_mask; + } + return hws; +} + +static const struct resource_create_funcs res_create_funcs = { + .read_dce_straps = read_dce_straps, + .create_audio = create_audio, + .create_stream_encoder = dce120_stream_encoder_create, + .create_hwseq = dce120_hwseq_create, +}; + +static const struct resource_create_funcs dce121_res_create_funcs = { + .read_dce_straps = read_dce_straps, + .create_audio = create_audio, + .create_stream_encoder = dce120_stream_encoder_create, + .create_hwseq = dce121_hwseq_create, +}; + + +#define mi_inst_regs(id) { MI_DCE12_REG_LIST(id) } +static const struct dce_mem_input_registers mi_regs[] = { + mi_inst_regs(0), + mi_inst_regs(1), + mi_inst_regs(2), + mi_inst_regs(3), + mi_inst_regs(4), + mi_inst_regs(5), +}; + +static const struct dce_mem_input_shift mi_shifts = { + MI_DCE12_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_mem_input_mask mi_masks = { + MI_DCE12_MASK_SH_LIST(_MASK) +}; + +static struct mem_input *dce120_mem_input_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce_mem_input *dce_mi = kzalloc(sizeof(struct dce_mem_input), + GFP_KERNEL); + + if (!dce_mi) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dce120_mem_input_construct(dce_mi, ctx, inst, &mi_regs[inst], &mi_shifts, &mi_masks); + return &dce_mi->base; +} + +static struct transform *dce120_transform_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce_transform *transform = + kzalloc(sizeof(struct dce_transform), GFP_KERNEL); + + if (!transform) + return NULL; + + dce_transform_construct(transform, ctx, inst, + &xfm_regs[inst], &xfm_shift, &xfm_mask); + transform->lb_memory_size = 0x1404; /*5124*/ + return &transform->base; +} + +static void dce120_destroy_resource_pool(struct resource_pool **pool) +{ + struct dce110_resource_pool *dce110_pool = TO_DCE110_RES_POOL(*pool); + + dce120_resource_destruct(dce110_pool); + kfree(dce110_pool); + *pool = NULL; +} + +static const struct resource_funcs dce120_res_pool_funcs = { + .destroy = dce120_destroy_resource_pool, + .link_enc_create = dce120_link_encoder_create, + .panel_cntl_create = dce120_panel_cntl_create, + .validate_bandwidth = dce112_validate_bandwidth, + .validate_plane = dce100_validate_plane, + .add_stream_to_ctx = dce112_add_stream_to_ctx, + .find_first_free_match_stream_enc_for_link = dce110_find_first_free_match_stream_enc_for_link +}; + +static void bw_calcs_data_update_from_pplib(struct dc *dc) +{ + struct dm_pp_clock_levels_with_latency eng_clks = {0}; + struct dm_pp_clock_levels_with_latency mem_clks = {0}; + struct dm_pp_wm_sets_with_clock_ranges clk_ranges = {0}; + int i; + unsigned int clk; + unsigned int latency; + /*original logic in dal3*/ + int memory_type_multiplier = MEMORY_TYPE_MULTIPLIER_CZ; + + /*do system clock*/ + if (!dm_pp_get_clock_levels_by_type_with_latency( + dc->ctx, + DM_PP_CLOCK_TYPE_ENGINE_CLK, + &eng_clks) || eng_clks.num_levels == 0) { + + eng_clks.num_levels = 8; + clk = 300000; + + for (i = 0; i < eng_clks.num_levels; i++) { + eng_clks.data[i].clocks_in_khz = clk; + clk += 100000; + } + } + + /* convert all the clock fro kHz to fix point mHz TODO: wloop data */ + dc->bw_vbios->high_sclk = bw_frc_to_fixed( + eng_clks.data[eng_clks.num_levels-1].clocks_in_khz, 1000); + dc->bw_vbios->mid1_sclk = bw_frc_to_fixed( + eng_clks.data[eng_clks.num_levels/8].clocks_in_khz, 1000); + dc->bw_vbios->mid2_sclk = bw_frc_to_fixed( + eng_clks.data[eng_clks.num_levels*2/8].clocks_in_khz, 1000); + dc->bw_vbios->mid3_sclk = bw_frc_to_fixed( + eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz, 1000); + dc->bw_vbios->mid4_sclk = bw_frc_to_fixed( + eng_clks.data[eng_clks.num_levels*4/8].clocks_in_khz, 1000); + dc->bw_vbios->mid5_sclk = bw_frc_to_fixed( + eng_clks.data[eng_clks.num_levels*5/8].clocks_in_khz, 1000); + dc->bw_vbios->mid6_sclk = bw_frc_to_fixed( + eng_clks.data[eng_clks.num_levels*6/8].clocks_in_khz, 1000); + dc->bw_vbios->low_sclk = bw_frc_to_fixed( + eng_clks.data[0].clocks_in_khz, 1000); + + /*do memory clock*/ + if (!dm_pp_get_clock_levels_by_type_with_latency( + dc->ctx, + DM_PP_CLOCK_TYPE_MEMORY_CLK, + &mem_clks) || mem_clks.num_levels == 0) { + + mem_clks.num_levels = 3; + clk = 250000; + latency = 45; + + for (i = 0; i < eng_clks.num_levels; i++) { + mem_clks.data[i].clocks_in_khz = clk; + mem_clks.data[i].latency_in_us = latency; + clk += 500000; + latency -= 5; + } + + } + + /* we don't need to call PPLIB for validation clock since they + * also give us the highest sclk and highest mclk (UMA clock). + * ALSO always convert UMA clock (from PPLIB) to YCLK (HW formula): + * YCLK = UMACLK*m_memoryTypeMultiplier + */ + if (dc->bw_vbios->memory_type == bw_def_hbm) + memory_type_multiplier = MEMORY_TYPE_HBM; + + dc->bw_vbios->low_yclk = bw_frc_to_fixed( + mem_clks.data[0].clocks_in_khz * memory_type_multiplier, 1000); + dc->bw_vbios->mid_yclk = bw_frc_to_fixed( + mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz * memory_type_multiplier, + 1000); + dc->bw_vbios->high_yclk = bw_frc_to_fixed( + mem_clks.data[mem_clks.num_levels-1].clocks_in_khz * memory_type_multiplier, + 1000); + + /* Now notify PPLib/SMU about which Watermarks sets they should select + * depending on DPM state they are in. And update BW MGR GFX Engine and + * Memory clock member variables for Watermarks calculations for each + * Watermark Set + */ + clk_ranges.num_wm_sets = 4; + clk_ranges.wm_clk_ranges[0].wm_set_id = WM_SET_A; + clk_ranges.wm_clk_ranges[0].wm_min_eng_clk_in_khz = + eng_clks.data[0].clocks_in_khz; + clk_ranges.wm_clk_ranges[0].wm_max_eng_clk_in_khz = + eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz - 1; + clk_ranges.wm_clk_ranges[0].wm_min_mem_clk_in_khz = + mem_clks.data[0].clocks_in_khz; + clk_ranges.wm_clk_ranges[0].wm_max_mem_clk_in_khz = + mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz - 1; + + clk_ranges.wm_clk_ranges[1].wm_set_id = WM_SET_B; + clk_ranges.wm_clk_ranges[1].wm_min_eng_clk_in_khz = + eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz; + /* 5 GHz instead of data[7].clockInKHz to cover Overdrive */ + clk_ranges.wm_clk_ranges[1].wm_max_eng_clk_in_khz = 5000000; + clk_ranges.wm_clk_ranges[1].wm_min_mem_clk_in_khz = + mem_clks.data[0].clocks_in_khz; + clk_ranges.wm_clk_ranges[1].wm_max_mem_clk_in_khz = + mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz - 1; + + clk_ranges.wm_clk_ranges[2].wm_set_id = WM_SET_C; + clk_ranges.wm_clk_ranges[2].wm_min_eng_clk_in_khz = + eng_clks.data[0].clocks_in_khz; + clk_ranges.wm_clk_ranges[2].wm_max_eng_clk_in_khz = + eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz - 1; + clk_ranges.wm_clk_ranges[2].wm_min_mem_clk_in_khz = + mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz; + /* 5 GHz instead of data[2].clockInKHz to cover Overdrive */ + clk_ranges.wm_clk_ranges[2].wm_max_mem_clk_in_khz = 5000000; + + clk_ranges.wm_clk_ranges[3].wm_set_id = WM_SET_D; + clk_ranges.wm_clk_ranges[3].wm_min_eng_clk_in_khz = + eng_clks.data[eng_clks.num_levels*3/8].clocks_in_khz; + /* 5 GHz instead of data[7].clockInKHz to cover Overdrive */ + clk_ranges.wm_clk_ranges[3].wm_max_eng_clk_in_khz = 5000000; + clk_ranges.wm_clk_ranges[3].wm_min_mem_clk_in_khz = + mem_clks.data[mem_clks.num_levels>>1].clocks_in_khz; + /* 5 GHz instead of data[2].clockInKHz to cover Overdrive */ + clk_ranges.wm_clk_ranges[3].wm_max_mem_clk_in_khz = 5000000; + + /* Notify PP Lib/SMU which Watermarks to use for which clock ranges */ + dm_pp_notify_wm_clock_changes(dc->ctx, &clk_ranges); +} + +static uint32_t read_pipe_fuses(struct dc_context *ctx) +{ + uint32_t value = dm_read_reg_soc15(ctx, mmCC_DC_PIPE_DIS, 0); + /* VG20 support max 6 pipes */ + value = value & 0x3f; + return value; +} + +static bool dce120_resource_construct( + uint8_t num_virtual_links, + struct dc *dc, + struct dce110_resource_pool *pool) +{ + unsigned int i; + int j; + struct dc_context *ctx = dc->ctx; + struct irq_service_init_data irq_init_data; + static const struct resource_create_funcs *res_funcs; + bool is_vg20 = ASICREV_IS_VEGA20_P(ctx->asic_id.hw_internal_rev); + uint32_t pipe_fuses; + + ctx->dc_bios->regs = &bios_regs; + + pool->base.res_cap = &res_cap; + pool->base.funcs = &dce120_res_pool_funcs; + + /* TODO: Fill more data from GreenlandAsicCapability.cpp */ + pool->base.pipe_count = res_cap.num_timing_generator; + pool->base.timing_generator_count = pool->base.res_cap->num_timing_generator; + pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + + dc->caps.max_downscale_ratio = 200; + dc->caps.i2c_speed_in_khz = 100; + dc->caps.i2c_speed_in_khz_hdcp = 100; /*1.4 w/a not applied by default*/ + dc->caps.max_cursor_size = 128; + dc->caps.min_horizontal_blanking_period = 80; + dc->caps.dual_link_dvi = true; + dc->caps.psp_setup_panel_mode = true; + dc->caps.extended_aux_timeout_support = false; + dc->debug = debug_defaults; + + /************************************************* + * Create resources * + *************************************************/ + + pool->base.clock_sources[DCE120_CLK_SRC_PLL0] = + dce120_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL0, + &clk_src_regs[0], false); + pool->base.clock_sources[DCE120_CLK_SRC_PLL1] = + dce120_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL1, + &clk_src_regs[1], false); + pool->base.clock_sources[DCE120_CLK_SRC_PLL2] = + dce120_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL2, + &clk_src_regs[2], false); + pool->base.clock_sources[DCE120_CLK_SRC_PLL3] = + dce120_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL3, + &clk_src_regs[3], false); + pool->base.clock_sources[DCE120_CLK_SRC_PLL4] = + dce120_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL4, + &clk_src_regs[4], false); + pool->base.clock_sources[DCE120_CLK_SRC_PLL5] = + dce120_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL5, + &clk_src_regs[5], false); + pool->base.clk_src_count = DCE120_CLK_SRC_TOTAL; + + pool->base.dp_clock_source = + dce120_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_ID_DP_DTO, + &clk_src_regs[0], true); + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] == NULL) { + dm_error("DC: failed to create clock sources!\n"); + BREAK_TO_DEBUGGER(); + goto clk_src_create_fail; + } + } + + pool->base.dmcu = dce_dmcu_create(ctx, + &dmcu_regs, + &dmcu_shift, + &dmcu_mask); + if (pool->base.dmcu == NULL) { + dm_error("DC: failed to create dmcu!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + pool->base.abm = dce_abm_create(ctx, + &abm_regs, + &abm_shift, + &abm_mask); + if (pool->base.abm == NULL) { + dm_error("DC: failed to create abm!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + + irq_init_data.ctx = dc->ctx; + pool->base.irqs = dal_irq_service_dce120_create(&irq_init_data); + if (!pool->base.irqs) + goto irqs_create_fail; + + /* VG20: Pipe harvesting enabled, retrieve valid pipe fuses */ + if (is_vg20) + pipe_fuses = read_pipe_fuses(ctx); + + /* index to valid pipe resource */ + j = 0; + for (i = 0; i < pool->base.pipe_count; i++) { + if (is_vg20) { + if ((pipe_fuses & (1 << i)) != 0) { + dm_error("DC: skip invalid pipe %d!\n", i); + continue; + } + } + + pool->base.timing_generators[j] = + dce120_timing_generator_create( + ctx, + i, + &dce120_tg_offsets[i]); + if (pool->base.timing_generators[j] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create tg!\n"); + goto controller_create_fail; + } + + pool->base.mis[j] = dce120_mem_input_create(ctx, i); + + if (pool->base.mis[j] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create memory input!\n"); + goto controller_create_fail; + } + + pool->base.ipps[j] = dce120_ipp_create(ctx, i); + if (pool->base.ipps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create input pixel processor!\n"); + goto controller_create_fail; + } + + pool->base.transforms[j] = dce120_transform_create(ctx, i); + if (pool->base.transforms[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create transform!\n"); + goto res_create_fail; + } + + pool->base.opps[j] = dce120_opp_create( + ctx, + i); + if (pool->base.opps[j] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create output pixel processor!\n"); + } + + /* check next valid pipe */ + j++; + } + + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + pool->base.engines[i] = dce120_aux_engine_create(ctx, i); + if (pool->base.engines[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create aux engine!!\n"); + goto res_create_fail; + } + pool->base.hw_i2cs[i] = dce120_i2c_hw_create(ctx, i); + if (pool->base.hw_i2cs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create i2c engine!!\n"); + goto res_create_fail; + } + pool->base.sw_i2cs[i] = NULL; + } + + /* valid pipe num */ + pool->base.pipe_count = j; + pool->base.timing_generator_count = j; + + if (is_vg20) + res_funcs = &dce121_res_create_funcs; + else + res_funcs = &res_create_funcs; + + if (!resource_construct(num_virtual_links, dc, &pool->base, res_funcs)) + goto res_create_fail; + + /* Create hardware sequencer */ + if (!dce120_hw_sequencer_create(dc)) + goto controller_create_fail; + + dc->caps.max_planes = pool->base.pipe_count; + + for (i = 0; i < dc->caps.max_planes; ++i) + dc->caps.planes[i] = plane_cap; + + bw_calcs_init(dc->bw_dceip, dc->bw_vbios, dc->ctx->asic_id); + + bw_calcs_data_update_from_pplib(dc); + + return true; + +irqs_create_fail: +controller_create_fail: +clk_src_create_fail: +res_create_fail: + + dce120_resource_destruct(pool); + + return false; +} + +struct resource_pool *dce120_create_resource_pool( + uint8_t num_virtual_links, + struct dc *dc) +{ + struct dce110_resource_pool *pool = + kzalloc(sizeof(struct dce110_resource_pool), GFP_KERNEL); + + if (!pool) + return NULL; + + if (dce120_resource_construct(num_virtual_links, dc, pool)) + return &pool->base; + + kfree(pool); + BREAK_TO_DEBUGGER(); + return NULL; +} diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce120/dce120_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dce120/dce120_resource.h new file mode 100644 index 00000000000000..3d1f3cf012f4a6 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dce120/dce120_resource.h @@ -0,0 +1,39 @@ +/* +* 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 __DC_RESOURCE_DCE120_H__ +#define __DC_RESOURCE_DCE120_H__ + +#include "core_types.h" + +struct dc; +struct resource_pool; + +struct resource_pool *dce120_create_resource_pool( + uint8_t num_virtual_links, + struct dc *dc); + +#endif /* __DC_RESOURCE_DCE120_H__ */ + diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce80/CMakeLists.txt b/drivers/gpu/drm/amd/display/dc/resource/dce80/CMakeLists.txt new file mode 100644 index 00000000000000..19dd73bc9ab03b --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dce80/CMakeLists.txt @@ -0,0 +1,4 @@ +dal3_subdirectory_sources( + dce80_resource.c + dce80_resource.h + ) \ No newline at end of file diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c new file mode 100644 index 00000000000000..35a2cce0c2b8e6 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c @@ -0,0 +1,1544 @@ +/* + * 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 + * + */ + +#include "dce/dce_8_0_d.h" +#include "dce/dce_8_0_sh_mask.h" + +#include "dm_services.h" + +#include "link_encoder.h" +#include "stream_encoder.h" + +#include "resource.h" +#include "include/irq_service_interface.h" +#include "irq/dce80/irq_service_dce80.h" +#include "dce110/dce110_timing_generator.h" +#include "dce110/dce110_resource.h" +#include "dce80/dce80_timing_generator.h" +#include "dce/dce_mem_input.h" +#include "dce/dce_link_encoder.h" +#include "dce/dce_stream_encoder.h" +#include "dce/dce_ipp.h" +#include "dce/dce_transform.h" +#include "dce/dce_opp.h" +#include "dce/dce_clock_source.h" +#include "dce/dce_audio.h" +#include "dce/dce_hwseq.h" +#include "dce80/dce80_hwseq.h" +#include "dce100/dce100_resource.h" +#include "dce/dce_panel_cntl.h" + +#include "reg_helper.h" + +#include "dce/dce_dmcu.h" +#include "dce/dce_aux.h" +#include "dce/dce_abm.h" +#include "dce/dce_i2c.h" +/* TODO remove this include */ + +#ifndef mmMC_HUB_RDREQ_DMIF_LIMIT +#include "gmc/gmc_7_1_d.h" +#include "gmc/gmc_7_1_sh_mask.h" +#endif + +#include "dce80/dce80_resource.h" + +#ifndef mmDP_DPHY_INTERNAL_CTRL +#define mmDP_DPHY_INTERNAL_CTRL 0x1CDE +#define mmDP0_DP_DPHY_INTERNAL_CTRL 0x1CDE +#define mmDP1_DP_DPHY_INTERNAL_CTRL 0x1FDE +#define mmDP2_DP_DPHY_INTERNAL_CTRL 0x42DE +#define mmDP3_DP_DPHY_INTERNAL_CTRL 0x45DE +#define mmDP4_DP_DPHY_INTERNAL_CTRL 0x48DE +#define mmDP5_DP_DPHY_INTERNAL_CTRL 0x4BDE +#define mmDP6_DP_DPHY_INTERNAL_CTRL 0x4EDE +#endif + + +#ifndef mmBIOS_SCRATCH_2 + #define mmBIOS_SCRATCH_2 0x05CB + #define mmBIOS_SCRATCH_3 0x05CC + #define mmBIOS_SCRATCH_6 0x05CF +#endif + +#ifndef mmDP_DPHY_FAST_TRAINING + #define mmDP_DPHY_FAST_TRAINING 0x1CCE + #define mmDP0_DP_DPHY_FAST_TRAINING 0x1CCE + #define mmDP1_DP_DPHY_FAST_TRAINING 0x1FCE + #define mmDP2_DP_DPHY_FAST_TRAINING 0x42CE + #define mmDP3_DP_DPHY_FAST_TRAINING 0x45CE + #define mmDP4_DP_DPHY_FAST_TRAINING 0x48CE + #define mmDP5_DP_DPHY_FAST_TRAINING 0x4BCE + #define mmDP6_DP_DPHY_FAST_TRAINING 0x4ECE +#endif + + +#ifndef mmHPD_DC_HPD_CONTROL + #define mmHPD_DC_HPD_CONTROL 0x189A + #define mmHPD0_DC_HPD_CONTROL 0x189A + #define mmHPD1_DC_HPD_CONTROL 0x18A2 + #define mmHPD2_DC_HPD_CONTROL 0x18AA + #define mmHPD3_DC_HPD_CONTROL 0x18B2 + #define mmHPD4_DC_HPD_CONTROL 0x18BA + #define mmHPD5_DC_HPD_CONTROL 0x18C2 +#endif + +#define DCE11_DIG_FE_CNTL 0x4a00 +#define DCE11_DIG_BE_CNTL 0x4a47 +#define DCE11_DP_SEC 0x4ac3 + +static const struct dce110_timing_generator_offsets dce80_tg_offsets[] = { + { + .crtc = (mmCRTC0_CRTC_CONTROL - mmCRTC_CONTROL), + .dcp = (mmGRPH_CONTROL - mmGRPH_CONTROL), + .dmif = (mmDMIF_PG0_DPG_WATERMARK_MASK_CONTROL + - mmDPG_WATERMARK_MASK_CONTROL), + }, + { + .crtc = (mmCRTC1_CRTC_CONTROL - mmCRTC_CONTROL), + .dcp = (mmDCP1_GRPH_CONTROL - mmGRPH_CONTROL), + .dmif = (mmDMIF_PG1_DPG_WATERMARK_MASK_CONTROL + - mmDPG_WATERMARK_MASK_CONTROL), + }, + { + .crtc = (mmCRTC2_CRTC_CONTROL - mmCRTC_CONTROL), + .dcp = (mmDCP2_GRPH_CONTROL - mmGRPH_CONTROL), + .dmif = (mmDMIF_PG2_DPG_WATERMARK_MASK_CONTROL + - mmDPG_WATERMARK_MASK_CONTROL), + }, + { + .crtc = (mmCRTC3_CRTC_CONTROL - mmCRTC_CONTROL), + .dcp = (mmDCP3_GRPH_CONTROL - mmGRPH_CONTROL), + .dmif = (mmDMIF_PG3_DPG_WATERMARK_MASK_CONTROL + - mmDPG_WATERMARK_MASK_CONTROL), + }, + { + .crtc = (mmCRTC4_CRTC_CONTROL - mmCRTC_CONTROL), + .dcp = (mmDCP4_GRPH_CONTROL - mmGRPH_CONTROL), + .dmif = (mmDMIF_PG4_DPG_WATERMARK_MASK_CONTROL + - mmDPG_WATERMARK_MASK_CONTROL), + }, + { + .crtc = (mmCRTC5_CRTC_CONTROL - mmCRTC_CONTROL), + .dcp = (mmDCP5_GRPH_CONTROL - mmGRPH_CONTROL), + .dmif = (mmDMIF_PG5_DPG_WATERMARK_MASK_CONTROL + - mmDPG_WATERMARK_MASK_CONTROL), + } +}; + +/* set register offset */ +#define SR(reg_name)\ + .reg_name = mm ## reg_name + +/* set register offset with instance */ +#define SRI(reg_name, block, id)\ + .reg_name = mm ## block ## id ## _ ## reg_name + +#define ipp_regs(id)\ +[id] = {\ + IPP_COMMON_REG_LIST_DCE_BASE(id)\ +} + +static const struct dce_ipp_registers ipp_regs[] = { + ipp_regs(0), + ipp_regs(1), + ipp_regs(2), + ipp_regs(3), + ipp_regs(4), + ipp_regs(5) +}; + +static const struct dce_ipp_shift ipp_shift = { + IPP_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) +}; + +static const struct dce_ipp_mask ipp_mask = { + IPP_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) +}; + +#define transform_regs(id)\ +[id] = {\ + XFM_COMMON_REG_LIST_DCE80(id)\ +} + +static const struct dce_transform_registers xfm_regs[] = { + transform_regs(0), + transform_regs(1), + transform_regs(2), + transform_regs(3), + transform_regs(4), + transform_regs(5) +}; + +static const struct dce_transform_shift xfm_shift = { + XFM_COMMON_MASK_SH_LIST_DCE80(__SHIFT) +}; + +static const struct dce_transform_mask xfm_mask = { + XFM_COMMON_MASK_SH_LIST_DCE80(_MASK) +}; + +#define aux_regs(id)\ +[id] = {\ + AUX_REG_LIST(id)\ +} + +static const struct dce110_link_enc_aux_registers link_enc_aux_regs[] = { + aux_regs(0), + aux_regs(1), + aux_regs(2), + aux_regs(3), + aux_regs(4), + aux_regs(5) +}; + +#define hpd_regs(id)\ +[id] = {\ + HPD_REG_LIST(id)\ +} + +static const struct dce110_link_enc_hpd_registers link_enc_hpd_regs[] = { + hpd_regs(0), + hpd_regs(1), + hpd_regs(2), + hpd_regs(3), + hpd_regs(4), + hpd_regs(5) +}; + +#define link_regs(id)\ +[id] = {\ + LE_DCE80_REG_LIST(id)\ +} + +static const struct dce110_link_enc_registers link_enc_regs[] = { + link_regs(0), + link_regs(1), + link_regs(2), + link_regs(3), + link_regs(4), + link_regs(5), + link_regs(6), +}; + +#define stream_enc_regs(id)\ +[id] = {\ + SE_COMMON_REG_LIST_DCE_BASE(id),\ + .AFMT_CNTL = 0,\ +} + +static const struct dce110_stream_enc_registers stream_enc_regs[] = { + stream_enc_regs(0), + stream_enc_regs(1), + stream_enc_regs(2), + stream_enc_regs(3), + stream_enc_regs(4), + stream_enc_regs(5), + stream_enc_regs(6) +}; + +static const struct dce_stream_encoder_shift se_shift = { + SE_COMMON_MASK_SH_LIST_DCE80_100(__SHIFT) +}; + +static const struct dce_stream_encoder_mask se_mask = { + SE_COMMON_MASK_SH_LIST_DCE80_100(_MASK) +}; + +static const struct dce_panel_cntl_registers panel_cntl_regs[] = { + { DCE_PANEL_CNTL_REG_LIST() } +}; + +static const struct dce_panel_cntl_shift panel_cntl_shift = { + DCE_PANEL_CNTL_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_panel_cntl_mask panel_cntl_mask = { + DCE_PANEL_CNTL_MASK_SH_LIST(_MASK) +}; + +#define opp_regs(id)\ +[id] = {\ + OPP_DCE_80_REG_LIST(id),\ +} + +static const struct dce_opp_registers opp_regs[] = { + opp_regs(0), + opp_regs(1), + opp_regs(2), + opp_regs(3), + opp_regs(4), + opp_regs(5) +}; + +static const struct dce_opp_shift opp_shift = { + OPP_COMMON_MASK_SH_LIST_DCE_80(__SHIFT) +}; + +static const struct dce_opp_mask opp_mask = { + OPP_COMMON_MASK_SH_LIST_DCE_80(_MASK) +}; + +static const struct dce110_aux_registers_shift aux_shift = { + DCE10_AUX_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce110_aux_registers_mask aux_mask = { + DCE10_AUX_MASK_SH_LIST(_MASK) +}; + +#define aux_engine_regs(id)\ +[id] = {\ + AUX_COMMON_REG_LIST(id), \ + .AUX_RESET_MASK = 0 \ +} + +static const struct dce110_aux_registers aux_engine_regs[] = { + aux_engine_regs(0), + aux_engine_regs(1), + aux_engine_regs(2), + aux_engine_regs(3), + aux_engine_regs(4), + aux_engine_regs(5) +}; + +#define audio_regs(id)\ +[id] = {\ + AUD_COMMON_REG_LIST(id)\ +} + +static const struct dce_audio_registers audio_regs[] = { + audio_regs(0), + audio_regs(1), + audio_regs(2), + audio_regs(3), + audio_regs(4), + audio_regs(5), + audio_regs(6), +}; + +static const struct dce_audio_shift audio_shift = { + AUD_COMMON_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_audio_mask audio_mask = { + AUD_COMMON_MASK_SH_LIST(_MASK) +}; + +#define clk_src_regs(id)\ +[id] = {\ + CS_COMMON_REG_LIST_DCE_80(id),\ +} + + +static const struct dce110_clk_src_regs clk_src_regs[] = { + clk_src_regs(0), + clk_src_regs(1), + clk_src_regs(2) +}; + +static const struct dce110_clk_src_shift cs_shift = { + CS_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) +}; + +static const struct dce110_clk_src_mask cs_mask = { + CS_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) +}; + +static const struct bios_registers bios_regs = { + .BIOS_SCRATCH_3 = mmBIOS_SCRATCH_3, + .BIOS_SCRATCH_6 = mmBIOS_SCRATCH_6 +}; + +static const struct resource_caps res_cap = { + .num_timing_generator = 6, + .num_audio = 6, + .num_stream_encoder = 6, + .num_pll = 3, + .num_ddc = 6, +}; + +static const struct resource_caps res_cap_81 = { + .num_timing_generator = 4, + .num_audio = 7, + .num_stream_encoder = 7, + .num_pll = 3, + .num_ddc = 6, +}; + +static const struct resource_caps res_cap_83 = { + .num_timing_generator = 2, + .num_audio = 6, + .num_stream_encoder = 6, + .num_pll = 2, + .num_ddc = 2, +}; + +static const struct dc_plane_cap plane_cap = { + .type = DC_PLANE_TYPE_DCE_RGB, + + .pixel_format_support = { + .argb8888 = true, + .nv12 = false, + .fp16 = true + }, + + .max_upscale_factor = { + .argb8888 = 16000, + .nv12 = 1, + .fp16 = 1 + }, + + .max_downscale_factor = { + .argb8888 = 250, + .nv12 = 1, + .fp16 = 1 + } +}; + +static const struct dc_debug_options debug_defaults = { + .enable_legacy_fast_update = true, +}; + +static const struct dce_dmcu_registers dmcu_regs = { + DMCU_DCE80_REG_LIST() +}; + +static const struct dce_dmcu_shift dmcu_shift = { + DMCU_MASK_SH_LIST_DCE80(__SHIFT) +}; + +static const struct dce_dmcu_mask dmcu_mask = { + DMCU_MASK_SH_LIST_DCE80(_MASK) +}; +static const struct dce_abm_registers abm_regs = { + ABM_DCE110_COMMON_REG_LIST() +}; + +static const struct dce_abm_shift abm_shift = { + ABM_MASK_SH_LIST_DCE110(__SHIFT) +}; + +static const struct dce_abm_mask abm_mask = { + ABM_MASK_SH_LIST_DCE110(_MASK) +}; + +#define CTX ctx +#define REG(reg) mm ## reg + +#ifndef mmCC_DC_HDMI_STRAPS +#define mmCC_DC_HDMI_STRAPS 0x1918 +#define CC_DC_HDMI_STRAPS__HDMI_DISABLE_MASK 0x40 +#define CC_DC_HDMI_STRAPS__HDMI_DISABLE__SHIFT 0x6 +#define CC_DC_HDMI_STRAPS__AUDIO_STREAM_NUMBER_MASK 0x700 +#define CC_DC_HDMI_STRAPS__AUDIO_STREAM_NUMBER__SHIFT 0x8 +#endif + +static int map_transmitter_id_to_phy_instance( + enum transmitter transmitter) +{ + switch (transmitter) { + case TRANSMITTER_UNIPHY_A: + return 0; + case TRANSMITTER_UNIPHY_B: + return 1; + case TRANSMITTER_UNIPHY_C: + return 2; + case TRANSMITTER_UNIPHY_D: + return 3; + case TRANSMITTER_UNIPHY_E: + return 4; + case TRANSMITTER_UNIPHY_F: + return 5; + case TRANSMITTER_UNIPHY_G: + return 6; + default: + ASSERT(0); + return 0; + } +} + +static void read_dce_straps( + struct dc_context *ctx, + struct resource_straps *straps) +{ + REG_GET_2(CC_DC_HDMI_STRAPS, + HDMI_DISABLE, &straps->hdmi_disable, + AUDIO_STREAM_NUMBER, &straps->audio_stream_number); + + REG_GET(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO, &straps->dc_pinstraps_audio); +} + +static struct audio *create_audio( + struct dc_context *ctx, unsigned int inst) +{ + return dce_audio_create(ctx, inst, + &audio_regs[inst], &audio_shift, &audio_mask); +} + +static struct timing_generator *dce80_timing_generator_create( + struct dc_context *ctx, + uint32_t instance, + const struct dce110_timing_generator_offsets *offsets) +{ + struct dce110_timing_generator *tg110 = + kzalloc(sizeof(struct dce110_timing_generator), GFP_KERNEL); + + if (!tg110) + return NULL; + + dce80_timing_generator_construct(tg110, ctx, instance, offsets); + return &tg110->base; +} + +static struct output_pixel_processor *dce80_opp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce110_opp *opp = + kzalloc(sizeof(struct dce110_opp), GFP_KERNEL); + + if (!opp) + return NULL; + + dce110_opp_construct(opp, + ctx, inst, &opp_regs[inst], &opp_shift, &opp_mask); + return &opp->base; +} + +static struct dce_aux *dce80_aux_engine_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct aux_engine_dce110 *aux_engine = + kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); + + if (!aux_engine) + return NULL; + + dce110_aux_engine_construct(aux_engine, ctx, inst, + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, + &aux_engine_regs[inst], + &aux_mask, + &aux_shift, + ctx->dc->caps.extended_aux_timeout_support); + + return &aux_engine->base; +} +#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST(id) } + +static const struct dce_i2c_registers i2c_hw_regs[] = { + i2c_inst_regs(1), + i2c_inst_regs(2), + i2c_inst_regs(3), + i2c_inst_regs(4), + i2c_inst_regs(5), + i2c_inst_regs(6), +}; + +static const struct dce_i2c_shift i2c_shifts = { + I2C_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(__SHIFT) +}; + +static const struct dce_i2c_mask i2c_masks = { + I2C_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(_MASK) +}; + +static struct dce_i2c_hw *dce80_i2c_hw_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce_i2c_hw *dce_i2c_hw = + kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); + + if (!dce_i2c_hw) + return NULL; + + dce_i2c_hw_construct(dce_i2c_hw, ctx, inst, + &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); + + return dce_i2c_hw; +} + +static struct dce_i2c_sw *dce80_i2c_sw_create( + struct dc_context *ctx) +{ + struct dce_i2c_sw *dce_i2c_sw = + kzalloc(sizeof(struct dce_i2c_sw), GFP_KERNEL); + + if (!dce_i2c_sw) + return NULL; + + dce_i2c_sw_construct(dce_i2c_sw, ctx); + + return dce_i2c_sw; +} +static struct stream_encoder *dce80_stream_encoder_create( + enum engine_id eng_id, + struct dc_context *ctx) +{ + struct dce110_stream_encoder *enc110 = + kzalloc(sizeof(struct dce110_stream_encoder), GFP_KERNEL); + + if (!enc110) + return NULL; + + dce110_stream_encoder_construct(enc110, ctx, ctx->dc_bios, eng_id, + &stream_enc_regs[eng_id], + &se_shift, &se_mask); + return &enc110->base; +} + +#define SRII(reg_name, block, id)\ + .reg_name[id] = mm ## block ## id ## _ ## reg_name + +static const struct dce_hwseq_registers hwseq_reg = { + HWSEQ_DCE8_REG_LIST() +}; + +static const struct dce_hwseq_shift hwseq_shift = { + HWSEQ_DCE8_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_hwseq_mask hwseq_mask = { + HWSEQ_DCE8_MASK_SH_LIST(_MASK) +}; + +static struct dce_hwseq *dce80_hwseq_create( + struct dc_context *ctx) +{ + struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); + + if (hws) { + hws->ctx = ctx; + hws->regs = &hwseq_reg; + hws->shifts = &hwseq_shift; + hws->masks = &hwseq_mask; + } + return hws; +} + +static const struct resource_create_funcs res_create_funcs = { + .read_dce_straps = read_dce_straps, + .create_audio = create_audio, + .create_stream_encoder = dce80_stream_encoder_create, + .create_hwseq = dce80_hwseq_create, +}; + +#define mi_inst_regs(id) { \ + MI_DCE8_REG_LIST(id), \ + .MC_HUB_RDREQ_DMIF_LIMIT = mmMC_HUB_RDREQ_DMIF_LIMIT \ +} +static const struct dce_mem_input_registers mi_regs[] = { + mi_inst_regs(0), + mi_inst_regs(1), + mi_inst_regs(2), + mi_inst_regs(3), + mi_inst_regs(4), + mi_inst_regs(5), +}; + +static const struct dce_mem_input_shift mi_shifts = { + MI_DCE8_MASK_SH_LIST(__SHIFT), + .ENABLE = MC_HUB_RDREQ_DMIF_LIMIT__ENABLE__SHIFT +}; + +static const struct dce_mem_input_mask mi_masks = { + MI_DCE8_MASK_SH_LIST(_MASK), + .ENABLE = MC_HUB_RDREQ_DMIF_LIMIT__ENABLE_MASK +}; + +static struct mem_input *dce80_mem_input_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce_mem_input *dce_mi = kzalloc(sizeof(struct dce_mem_input), + GFP_KERNEL); + + if (!dce_mi) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dce_mem_input_construct(dce_mi, ctx, inst, &mi_regs[inst], &mi_shifts, &mi_masks); + dce_mi->wa.single_head_rdreq_dmif_limit = 2; + return &dce_mi->base; +} + +static void dce80_transform_destroy(struct transform **xfm) +{ + kfree(TO_DCE_TRANSFORM(*xfm)); + *xfm = NULL; +} + +static struct transform *dce80_transform_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce_transform *transform = + kzalloc(sizeof(struct dce_transform), GFP_KERNEL); + + if (!transform) + return NULL; + + dce_transform_construct(transform, ctx, inst, + &xfm_regs[inst], &xfm_shift, &xfm_mask); + transform->prescaler_on = false; + return &transform->base; +} + +static const struct encoder_feature_support link_enc_feature = { + .max_hdmi_deep_color = COLOR_DEPTH_121212, + .max_hdmi_pixel_clock = 297000, + .flags.bits.IS_HBR2_CAPABLE = true, + .flags.bits.IS_TPS3_CAPABLE = true +}; + +static struct link_encoder *dce80_link_encoder_create( + struct dc_context *ctx, + const struct encoder_init_data *enc_init_data) +{ + struct dce110_link_encoder *enc110 = + kzalloc(sizeof(struct dce110_link_encoder), GFP_KERNEL); + int link_regs_id; + + if (!enc110) + return NULL; + + link_regs_id = + map_transmitter_id_to_phy_instance(enc_init_data->transmitter); + + dce110_link_encoder_construct(enc110, + enc_init_data, + &link_enc_feature, + &link_enc_regs[link_regs_id], + &link_enc_aux_regs[enc_init_data->channel - 1], + &link_enc_hpd_regs[enc_init_data->hpd_source]); + return &enc110->base; +} + +static struct panel_cntl *dce80_panel_cntl_create(const struct panel_cntl_init_data *init_data) +{ + struct dce_panel_cntl *panel_cntl = + kzalloc(sizeof(struct dce_panel_cntl), GFP_KERNEL); + + if (!panel_cntl) + return NULL; + + dce_panel_cntl_construct(panel_cntl, + init_data, + &panel_cntl_regs[init_data->inst], + &panel_cntl_shift, + &panel_cntl_mask); + + return &panel_cntl->base; +} + +static struct clock_source *dce80_clock_source_create( + struct dc_context *ctx, + struct dc_bios *bios, + enum clock_source_id id, + const struct dce110_clk_src_regs *regs, + bool dp_clk_src) +{ + struct dce110_clk_src *clk_src = + kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); + + if (!clk_src) + return NULL; + + if (dce110_clk_src_construct(clk_src, ctx, bios, id, + regs, &cs_shift, &cs_mask)) { + clk_src->base.dp_clk_src = dp_clk_src; + return &clk_src->base; + } + + kfree(clk_src); + BREAK_TO_DEBUGGER(); + return NULL; +} + +static void dce80_clock_source_destroy(struct clock_source **clk_src) +{ + kfree(TO_DCE110_CLK_SRC(*clk_src)); + *clk_src = NULL; +} + +static struct input_pixel_processor *dce80_ipp_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dce_ipp *ipp = kzalloc(sizeof(struct dce_ipp), GFP_KERNEL); + + if (!ipp) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dce_ipp_construct(ipp, ctx, inst, + &ipp_regs[inst], &ipp_shift, &ipp_mask); + return &ipp->base; +} + +static void dce80_resource_destruct(struct dce110_resource_pool *pool) +{ + unsigned int i; + + for (i = 0; i < pool->base.pipe_count; i++) { + if (pool->base.opps[i] != NULL) + dce110_opp_destroy(&pool->base.opps[i]); + + if (pool->base.transforms[i] != NULL) + dce80_transform_destroy(&pool->base.transforms[i]); + + if (pool->base.ipps[i] != NULL) + dce_ipp_destroy(&pool->base.ipps[i]); + + if (pool->base.mis[i] != NULL) { + kfree(TO_DCE_MEM_INPUT(pool->base.mis[i])); + pool->base.mis[i] = NULL; + } + + if (pool->base.timing_generators[i] != NULL) { + kfree(DCE110TG_FROM_TG(pool->base.timing_generators[i])); + pool->base.timing_generators[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + if (pool->base.engines[i] != NULL) + dce110_engine_destroy(&pool->base.engines[i]); + if (pool->base.hw_i2cs[i] != NULL) { + kfree(pool->base.hw_i2cs[i]); + pool->base.hw_i2cs[i] = NULL; + } + if (pool->base.sw_i2cs[i] != NULL) { + kfree(pool->base.sw_i2cs[i]); + pool->base.sw_i2cs[i] = NULL; + } + } + + for (i = 0; i < pool->base.stream_enc_count; i++) { + if (pool->base.stream_enc[i] != NULL) + kfree(DCE110STRENC_FROM_STRENC(pool->base.stream_enc[i])); + } + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] != NULL) { + dce80_clock_source_destroy(&pool->base.clock_sources[i]); + } + } + + if (pool->base.abm != NULL) + dce_abm_destroy(&pool->base.abm); + + if (pool->base.dmcu != NULL) + dce_dmcu_destroy(&pool->base.dmcu); + + if (pool->base.dp_clock_source != NULL) + dce80_clock_source_destroy(&pool->base.dp_clock_source); + + for (i = 0; i < pool->base.audio_count; i++) { + if (pool->base.audios[i] != NULL) { + dce_aud_destroy(&pool->base.audios[i]); + } + } + + if (pool->base.irqs != NULL) { + dal_irq_service_destroy(&pool->base.irqs); + } +} + +static bool dce80_validate_bandwidth( + struct dc *dc, + struct dc_state *context, + bool fast_validate) +{ + int i; + bool at_least_one_pipe = false; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + if (context->res_ctx.pipe_ctx[i].stream) + at_least_one_pipe = true; + } + + if (at_least_one_pipe) { + /* TODO implement when needed but for now hardcode max value*/ + context->bw_ctx.bw.dce.dispclk_khz = 681000; + context->bw_ctx.bw.dce.yclk_khz = 250000 * MEMORY_TYPE_MULTIPLIER_CZ; + } else { + context->bw_ctx.bw.dce.dispclk_khz = 0; + context->bw_ctx.bw.dce.yclk_khz = 0; + } + + return true; +} + +static bool dce80_validate_surface_sets( + struct dc_state *context) +{ + int i; + + for (i = 0; i < context->stream_count; i++) { + if (context->stream_status[i].plane_count == 0) + continue; + + if (context->stream_status[i].plane_count > 1) + return false; + + if (context->stream_status[i].plane_states[0]->format + >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) + return false; + } + + return true; +} + +static enum dc_status dce80_validate_global( + struct dc *dc, + struct dc_state *context) +{ + if (!dce80_validate_surface_sets(context)) + return DC_FAIL_SURFACE_VALIDATE; + + return DC_OK; +} + +static void dce80_destroy_resource_pool(struct resource_pool **pool) +{ + struct dce110_resource_pool *dce110_pool = TO_DCE110_RES_POOL(*pool); + + dce80_resource_destruct(dce110_pool); + kfree(dce110_pool); + *pool = NULL; +} + +static const struct resource_funcs dce80_res_pool_funcs = { + .destroy = dce80_destroy_resource_pool, + .link_enc_create = dce80_link_encoder_create, + .panel_cntl_create = dce80_panel_cntl_create, + .validate_bandwidth = dce80_validate_bandwidth, + .validate_plane = dce100_validate_plane, + .add_stream_to_ctx = dce100_add_stream_to_ctx, + .validate_global = dce80_validate_global, + .find_first_free_match_stream_enc_for_link = dce100_find_first_free_match_stream_enc_for_link +}; + +static bool dce80_construct( + uint8_t num_virtual_links, + struct dc *dc, + struct dce110_resource_pool *pool) +{ + unsigned int i; + struct dc_context *ctx = dc->ctx; + struct dc_bios *bp; + + ctx->dc_bios->regs = &bios_regs; + + pool->base.res_cap = &res_cap; + pool->base.funcs = &dce80_res_pool_funcs; + + + /************************************************* + * Resource + asic cap harcoding * + *************************************************/ + pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.pipe_count = res_cap.num_timing_generator; + pool->base.timing_generator_count = res_cap.num_timing_generator; + dc->caps.max_downscale_ratio = 200; + dc->caps.i2c_speed_in_khz = 40; + dc->caps.i2c_speed_in_khz_hdcp = 40; + dc->caps.max_cursor_size = 128; + dc->caps.min_horizontal_blanking_period = 80; + dc->caps.dual_link_dvi = true; + dc->caps.extended_aux_timeout_support = false; + dc->debug = debug_defaults; + + /************************************************* + * Create resources * + *************************************************/ + + bp = ctx->dc_bios; + + if (bp->fw_info_valid && bp->fw_info.external_clock_source_frequency_for_dp != 0) { + pool->base.dp_clock_source = + dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_EXTERNAL, NULL, true); + + pool->base.clock_sources[0] = + dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL0, &clk_src_regs[0], false); + pool->base.clock_sources[1] = + dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL1, &clk_src_regs[1], false); + pool->base.clock_sources[2] = + dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL2, &clk_src_regs[2], false); + pool->base.clk_src_count = 3; + + } else { + pool->base.dp_clock_source = + dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL0, &clk_src_regs[0], true); + + pool->base.clock_sources[0] = + dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL1, &clk_src_regs[1], false); + pool->base.clock_sources[1] = + dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL2, &clk_src_regs[2], false); + pool->base.clk_src_count = 2; + } + + if (pool->base.dp_clock_source == NULL) { + dm_error("DC: failed to create dp clock source!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] == NULL) { + dm_error("DC: failed to create clock sources!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + } + + pool->base.dmcu = dce_dmcu_create(ctx, + &dmcu_regs, + &dmcu_shift, + &dmcu_mask); + if (pool->base.dmcu == NULL) { + dm_error("DC: failed to create dmcu!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + pool->base.abm = dce_abm_create(ctx, + &abm_regs, + &abm_shift, + &abm_mask); + if (pool->base.abm == NULL) { + dm_error("DC: failed to create abm!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + { + struct irq_service_init_data init_data; + init_data.ctx = dc->ctx; + pool->base.irqs = dal_irq_service_dce80_create(&init_data); + if (!pool->base.irqs) + goto res_create_fail; + } + + for (i = 0; i < pool->base.pipe_count; i++) { + pool->base.timing_generators[i] = dce80_timing_generator_create( + ctx, i, &dce80_tg_offsets[i]); + if (pool->base.timing_generators[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create tg!\n"); + goto res_create_fail; + } + + pool->base.mis[i] = dce80_mem_input_create(ctx, i); + if (pool->base.mis[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create memory input!\n"); + goto res_create_fail; + } + + pool->base.ipps[i] = dce80_ipp_create(ctx, i); + if (pool->base.ipps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create input pixel processor!\n"); + goto res_create_fail; + } + + pool->base.transforms[i] = dce80_transform_create(ctx, i); + if (pool->base.transforms[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create transform!\n"); + goto res_create_fail; + } + + pool->base.opps[i] = dce80_opp_create(ctx, i); + if (pool->base.opps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create output pixel processor!\n"); + goto res_create_fail; + } + } + + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + pool->base.engines[i] = dce80_aux_engine_create(ctx, i); + if (pool->base.engines[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create aux engine!!\n"); + goto res_create_fail; + } + pool->base.hw_i2cs[i] = dce80_i2c_hw_create(ctx, i); + if (pool->base.hw_i2cs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create i2c engine!!\n"); + goto res_create_fail; + } + pool->base.sw_i2cs[i] = dce80_i2c_sw_create(ctx); + if (pool->base.sw_i2cs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create sw i2c!!\n"); + goto res_create_fail; + } + } + + dc->caps.max_planes = pool->base.pipe_count; + + for (i = 0; i < dc->caps.max_planes; ++i) + dc->caps.planes[i] = plane_cap; + + dc->caps.disable_dp_clk_share = true; + + if (!resource_construct(num_virtual_links, dc, &pool->base, + &res_create_funcs)) + goto res_create_fail; + + /* Create hardware sequencer */ + dce80_hw_sequencer_construct(dc); + + return true; + +res_create_fail: + dce80_resource_destruct(pool); + return false; +} + +struct resource_pool *dce80_create_resource_pool( + uint8_t num_virtual_links, + struct dc *dc) +{ + struct dce110_resource_pool *pool = + kzalloc(sizeof(struct dce110_resource_pool), GFP_KERNEL); + + if (!pool) + return NULL; + + if (dce80_construct(num_virtual_links, dc, pool)) + return &pool->base; + + kfree(pool); + BREAK_TO_DEBUGGER(); + return NULL; +} + +static bool dce81_construct( + uint8_t num_virtual_links, + struct dc *dc, + struct dce110_resource_pool *pool) +{ + unsigned int i; + struct dc_context *ctx = dc->ctx; + struct dc_bios *bp; + + ctx->dc_bios->regs = &bios_regs; + + pool->base.res_cap = &res_cap_81; + pool->base.funcs = &dce80_res_pool_funcs; + + + /************************************************* + * Resource + asic cap harcoding * + *************************************************/ + pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.pipe_count = res_cap_81.num_timing_generator; + pool->base.timing_generator_count = res_cap_81.num_timing_generator; + dc->caps.max_downscale_ratio = 200; + dc->caps.i2c_speed_in_khz = 40; + dc->caps.i2c_speed_in_khz_hdcp = 40; + dc->caps.max_cursor_size = 128; + dc->caps.min_horizontal_blanking_period = 80; + dc->caps.is_apu = true; + + /************************************************* + * Create resources * + *************************************************/ + + bp = ctx->dc_bios; + + if (bp->fw_info_valid && bp->fw_info.external_clock_source_frequency_for_dp != 0) { + pool->base.dp_clock_source = + dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_EXTERNAL, NULL, true); + + pool->base.clock_sources[0] = + dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL0, &clk_src_regs[0], false); + pool->base.clock_sources[1] = + dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL1, &clk_src_regs[1], false); + pool->base.clock_sources[2] = + dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL2, &clk_src_regs[2], false); + pool->base.clk_src_count = 3; + + } else { + pool->base.dp_clock_source = + dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL0, &clk_src_regs[0], true); + + pool->base.clock_sources[0] = + dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL1, &clk_src_regs[1], false); + pool->base.clock_sources[1] = + dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL2, &clk_src_regs[2], false); + pool->base.clk_src_count = 2; + } + + if (pool->base.dp_clock_source == NULL) { + dm_error("DC: failed to create dp clock source!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] == NULL) { + dm_error("DC: failed to create clock sources!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + } + + pool->base.dmcu = dce_dmcu_create(ctx, + &dmcu_regs, + &dmcu_shift, + &dmcu_mask); + if (pool->base.dmcu == NULL) { + dm_error("DC: failed to create dmcu!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + pool->base.abm = dce_abm_create(ctx, + &abm_regs, + &abm_shift, + &abm_mask); + if (pool->base.abm == NULL) { + dm_error("DC: failed to create abm!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + { + struct irq_service_init_data init_data; + init_data.ctx = dc->ctx; + pool->base.irqs = dal_irq_service_dce80_create(&init_data); + if (!pool->base.irqs) + goto res_create_fail; + } + + for (i = 0; i < pool->base.pipe_count; i++) { + pool->base.timing_generators[i] = dce80_timing_generator_create( + ctx, i, &dce80_tg_offsets[i]); + if (pool->base.timing_generators[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create tg!\n"); + goto res_create_fail; + } + + pool->base.mis[i] = dce80_mem_input_create(ctx, i); + if (pool->base.mis[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create memory input!\n"); + goto res_create_fail; + } + + pool->base.ipps[i] = dce80_ipp_create(ctx, i); + if (pool->base.ipps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create input pixel processor!\n"); + goto res_create_fail; + } + + pool->base.transforms[i] = dce80_transform_create(ctx, i); + if (pool->base.transforms[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create transform!\n"); + goto res_create_fail; + } + + pool->base.opps[i] = dce80_opp_create(ctx, i); + if (pool->base.opps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create output pixel processor!\n"); + goto res_create_fail; + } + } + + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + pool->base.engines[i] = dce80_aux_engine_create(ctx, i); + if (pool->base.engines[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create aux engine!!\n"); + goto res_create_fail; + } + pool->base.hw_i2cs[i] = dce80_i2c_hw_create(ctx, i); + if (pool->base.hw_i2cs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create i2c engine!!\n"); + goto res_create_fail; + } + pool->base.sw_i2cs[i] = dce80_i2c_sw_create(ctx); + if (pool->base.sw_i2cs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create sw i2c!!\n"); + goto res_create_fail; + } + } + + dc->caps.max_planes = pool->base.pipe_count; + + for (i = 0; i < dc->caps.max_planes; ++i) + dc->caps.planes[i] = plane_cap; + + dc->caps.disable_dp_clk_share = true; + + if (!resource_construct(num_virtual_links, dc, &pool->base, + &res_create_funcs)) + goto res_create_fail; + + /* Create hardware sequencer */ + dce80_hw_sequencer_construct(dc); + + return true; + +res_create_fail: + dce80_resource_destruct(pool); + return false; +} + +struct resource_pool *dce81_create_resource_pool( + uint8_t num_virtual_links, + struct dc *dc) +{ + struct dce110_resource_pool *pool = + kzalloc(sizeof(struct dce110_resource_pool), GFP_KERNEL); + + if (!pool) + return NULL; + + if (dce81_construct(num_virtual_links, dc, pool)) + return &pool->base; + + kfree(pool); + BREAK_TO_DEBUGGER(); + return NULL; +} + +static bool dce83_construct( + uint8_t num_virtual_links, + struct dc *dc, + struct dce110_resource_pool *pool) +{ + unsigned int i; + struct dc_context *ctx = dc->ctx; + struct dc_bios *bp; + + ctx->dc_bios->regs = &bios_regs; + + pool->base.res_cap = &res_cap_83; + pool->base.funcs = &dce80_res_pool_funcs; + + + /************************************************* + * Resource + asic cap harcoding * + *************************************************/ + pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.pipe_count = res_cap_83.num_timing_generator; + pool->base.timing_generator_count = res_cap_83.num_timing_generator; + dc->caps.max_downscale_ratio = 200; + dc->caps.i2c_speed_in_khz = 40; + dc->caps.i2c_speed_in_khz_hdcp = 40; + dc->caps.max_cursor_size = 128; + dc->caps.min_horizontal_blanking_period = 80; + dc->caps.is_apu = true; + dc->debug = debug_defaults; + + /************************************************* + * Create resources * + *************************************************/ + + bp = ctx->dc_bios; + + if (bp->fw_info_valid && bp->fw_info.external_clock_source_frequency_for_dp != 0) { + pool->base.dp_clock_source = + dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_EXTERNAL, NULL, true); + + pool->base.clock_sources[0] = + dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL1, &clk_src_regs[0], false); + pool->base.clock_sources[1] = + dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL2, &clk_src_regs[1], false); + pool->base.clk_src_count = 2; + + } else { + pool->base.dp_clock_source = + dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL1, &clk_src_regs[0], true); + + pool->base.clock_sources[0] = + dce80_clock_source_create(ctx, bp, CLOCK_SOURCE_ID_PLL2, &clk_src_regs[1], false); + pool->base.clk_src_count = 1; + } + + if (pool->base.dp_clock_source == NULL) { + dm_error("DC: failed to create dp clock source!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] == NULL) { + dm_error("DC: failed to create clock sources!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + } + + pool->base.dmcu = dce_dmcu_create(ctx, + &dmcu_regs, + &dmcu_shift, + &dmcu_mask); + if (pool->base.dmcu == NULL) { + dm_error("DC: failed to create dmcu!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + pool->base.abm = dce_abm_create(ctx, + &abm_regs, + &abm_shift, + &abm_mask); + if (pool->base.abm == NULL) { + dm_error("DC: failed to create abm!\n"); + BREAK_TO_DEBUGGER(); + goto res_create_fail; + } + + { + struct irq_service_init_data init_data; + init_data.ctx = dc->ctx; + pool->base.irqs = dal_irq_service_dce80_create(&init_data); + if (!pool->base.irqs) + goto res_create_fail; + } + + for (i = 0; i < pool->base.pipe_count; i++) { + pool->base.timing_generators[i] = dce80_timing_generator_create( + ctx, i, &dce80_tg_offsets[i]); + if (pool->base.timing_generators[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create tg!\n"); + goto res_create_fail; + } + + pool->base.mis[i] = dce80_mem_input_create(ctx, i); + if (pool->base.mis[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create memory input!\n"); + goto res_create_fail; + } + + pool->base.ipps[i] = dce80_ipp_create(ctx, i); + if (pool->base.ipps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create input pixel processor!\n"); + goto res_create_fail; + } + + pool->base.transforms[i] = dce80_transform_create(ctx, i); + if (pool->base.transforms[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create transform!\n"); + goto res_create_fail; + } + + pool->base.opps[i] = dce80_opp_create(ctx, i); + if (pool->base.opps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create output pixel processor!\n"); + goto res_create_fail; + } + } + + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + pool->base.engines[i] = dce80_aux_engine_create(ctx, i); + if (pool->base.engines[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create aux engine!!\n"); + goto res_create_fail; + } + pool->base.hw_i2cs[i] = dce80_i2c_hw_create(ctx, i); + if (pool->base.hw_i2cs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create i2c engine!!\n"); + goto res_create_fail; + } + pool->base.sw_i2cs[i] = dce80_i2c_sw_create(ctx); + if (pool->base.sw_i2cs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create sw i2c!!\n"); + goto res_create_fail; + } + } + + dc->caps.max_planes = pool->base.pipe_count; + + for (i = 0; i < dc->caps.max_planes; ++i) + dc->caps.planes[i] = plane_cap; + + dc->caps.disable_dp_clk_share = true; + + if (!resource_construct(num_virtual_links, dc, &pool->base, + &res_create_funcs)) + goto res_create_fail; + + /* Create hardware sequencer */ + dce80_hw_sequencer_construct(dc); + + return true; + +res_create_fail: + dce80_resource_destruct(pool); + return false; +} + +struct resource_pool *dce83_create_resource_pool( + uint8_t num_virtual_links, + struct dc *dc) +{ + struct dce110_resource_pool *pool = + kzalloc(sizeof(struct dce110_resource_pool), GFP_KERNEL); + + if (!pool) + return NULL; + + if (dce83_construct(num_virtual_links, dc, pool)) + return &pool->base; + + BREAK_TO_DEBUGGER(); + return NULL; +} diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.h new file mode 100644 index 00000000000000..eff31ab83a39f9 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.h @@ -0,0 +1,47 @@ +/* +* 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 __DC_RESOURCE_DCE80_H__ +#define __DC_RESOURCE_DCE80_H__ + +#include "core_types.h" + +struct dc; +struct resource_pool; + +struct resource_pool *dce80_create_resource_pool( + uint8_t num_virtual_links, + struct dc *dc); + +struct resource_pool *dce81_create_resource_pool( + uint8_t num_virtual_links, + struct dc *dc); + +struct resource_pool *dce83_create_resource_pool( + uint8_t num_virtual_links, + struct dc *dc); + +#endif /* __DC_RESOURCE_DCE80_H__ */ + diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c new file mode 100644 index 00000000000000..d08d1096925143 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c @@ -0,0 +1,1692 @@ +/* +* Copyright 2016 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 "dcn10/dcn10_init.h" + +#include "resource.h" +#include "include/irq_service_interface.h" +#include "dcn10/dcn10_resource.h" +#include "dcn10/dcn10_ipp.h" +#include "dcn10/dcn10_mpc.h" + +#include "dcn10/dcn10_dwb.h" + +#include "irq/dcn10/irq_service_dcn10.h" +#include "dcn10/dcn10_dpp.h" +#include "dcn10/dcn10_optc.h" +#include "dcn10/dcn10_hwseq.h" +#include "dce110/dce110_hwseq.h" +#include "dcn10/dcn10_opp.h" +#include "dcn10/dcn10_link_encoder.h" +#include "dcn10/dcn10_stream_encoder.h" +#include "dce/dce_clock_source.h" +#include "dce/dce_audio.h" +#include "dce/dce_hwseq.h" +#include "virtual/virtual_stream_encoder.h" +#include "dce110/dce110_resource.h" +#include "dce112/dce112_resource.h" +#include "dcn10/dcn10_hubp.h" +#include "dcn10/dcn10_hubbub.h" +#include "dce/dce_panel_cntl.h" + +#include "soc15_hw_ip.h" +#include "vega10_ip_offset.h" + +#include "dcn/dcn_1_0_offset.h" +#include "dcn/dcn_1_0_sh_mask.h" + +#include "nbio/nbio_7_0_offset.h" + +#include "mmhub/mmhub_9_1_offset.h" +#include "mmhub/mmhub_9_1_sh_mask.h" + +#include "reg_helper.h" +#include "dce/dce_abm.h" +#include "dce/dce_dmcu.h" +#include "dce/dce_aux.h" +#include "dce/dce_i2c.h" + +#ifndef mmDP0_DP_DPHY_INTERNAL_CTRL + #define mmDP0_DP_DPHY_INTERNAL_CTRL 0x210f + #define mmDP0_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 + #define mmDP1_DP_DPHY_INTERNAL_CTRL 0x220f + #define mmDP1_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 + #define mmDP2_DP_DPHY_INTERNAL_CTRL 0x230f + #define mmDP2_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 + #define mmDP3_DP_DPHY_INTERNAL_CTRL 0x240f + #define mmDP3_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 + #define mmDP4_DP_DPHY_INTERNAL_CTRL 0x250f + #define mmDP4_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 + #define mmDP5_DP_DPHY_INTERNAL_CTRL 0x260f + #define mmDP5_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 + #define mmDP6_DP_DPHY_INTERNAL_CTRL 0x270f + #define mmDP6_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 +#endif + + +enum dcn10_clk_src_array_id { + DCN10_CLK_SRC_PLL0, + DCN10_CLK_SRC_PLL1, + DCN10_CLK_SRC_PLL2, + DCN10_CLK_SRC_PLL3, + DCN10_CLK_SRC_TOTAL, + DCN101_CLK_SRC_TOTAL = DCN10_CLK_SRC_PLL3 +}; + +/* begin ********************* + * macros to expend register list macro defined in HW object header file */ + +/* DCN */ +#define BASE_INNER(seg) \ + DCE_BASE__INST0_SEG ## seg + +#define BASE(seg) \ + BASE_INNER(seg) + +#define SR(reg_name)\ + .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + \ + mm ## reg_name + +#define SRI(reg_name, block, id)\ + .reg_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + + +#define SRII(reg_name, block, id)\ + .reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define VUPDATE_SRII(reg_name, block, id)\ + .reg_name[id] = BASE(mm ## reg_name ## 0 ## _ ## block ## id ## _BASE_IDX) + \ + mm ## reg_name ## 0 ## _ ## block ## id + +/* set field/register/bitfield name */ +#define SFRB(field_name, reg_name, bitfield, post_fix)\ + .field_name = reg_name ## __ ## bitfield ## post_fix + +/* NBIO */ +#define NBIO_BASE_INNER(seg) \ + NBIF_BASE__INST0_SEG ## seg + +#define NBIO_BASE(seg) \ + NBIO_BASE_INNER(seg) + +#define NBIO_SR(reg_name)\ + .reg_name = NBIO_BASE(mm ## reg_name ## _BASE_IDX) + \ + mm ## reg_name + +/* MMHUB */ +#define MMHUB_BASE_INNER(seg) \ + MMHUB_BASE__INST0_SEG ## seg + +#define MMHUB_BASE(seg) \ + MMHUB_BASE_INNER(seg) + +#define MMHUB_SR(reg_name)\ + .reg_name = MMHUB_BASE(mm ## reg_name ## _BASE_IDX) + \ + mm ## reg_name + +/* macros to expend register list macro defined in HW object header file + * end *********************/ + + +static const struct dce_dmcu_registers dmcu_regs = { + DMCU_DCN10_REG_LIST() +}; + +static const struct dce_dmcu_shift dmcu_shift = { + DMCU_MASK_SH_LIST_DCN10(__SHIFT) +}; + +static const struct dce_dmcu_mask dmcu_mask = { + DMCU_MASK_SH_LIST_DCN10(_MASK) +}; + +static const struct dce_abm_registers abm_regs = { + ABM_DCN10_REG_LIST(0) +}; + +static const struct dce_abm_shift abm_shift = { + ABM_MASK_SH_LIST_DCN10(__SHIFT) +}; + +static const struct dce_abm_mask abm_mask = { + ABM_MASK_SH_LIST_DCN10(_MASK) +}; + +#define stream_enc_regs(id)\ +[id] = {\ + SE_DCN_REG_LIST(id)\ +} + +static const struct dcn10_stream_enc_registers stream_enc_regs[] = { + stream_enc_regs(0), + stream_enc_regs(1), + stream_enc_regs(2), + stream_enc_regs(3), +}; + +static const struct dcn10_stream_encoder_shift se_shift = { + SE_COMMON_MASK_SH_LIST_DCN10(__SHIFT) +}; + +static const struct dcn10_stream_encoder_mask se_mask = { + SE_COMMON_MASK_SH_LIST_DCN10(_MASK) +}; + +#define audio_regs(id)\ +[id] = {\ + AUD_COMMON_REG_LIST(id)\ +} + +static const struct dce_audio_registers audio_regs[] = { + audio_regs(0), + audio_regs(1), + audio_regs(2), + audio_regs(3), +}; + +#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ + AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) + +static const struct dce_audio_shift audio_shift = { + DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_audio_mask audio_mask = { + DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) +}; + +#define aux_regs(id)\ +[id] = {\ + AUX_REG_LIST(id)\ +} + +static const struct dcn10_link_enc_aux_registers link_enc_aux_regs[] = { + aux_regs(0), + aux_regs(1), + aux_regs(2), + aux_regs(3) +}; + +#define hpd_regs(id)\ +[id] = {\ + HPD_REG_LIST(id)\ +} + +static const struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[] = { + hpd_regs(0), + hpd_regs(1), + hpd_regs(2), + hpd_regs(3) +}; + +#define link_regs(id)\ +[id] = {\ + LE_DCN10_REG_LIST(id), \ + SRI(DP_DPHY_INTERNAL_CTRL, DP, id) \ +} + +static const struct dcn10_link_enc_registers link_enc_regs[] = { + link_regs(0), + link_regs(1), + link_regs(2), + link_regs(3) +}; + +static const struct dcn10_link_enc_shift le_shift = { + LINK_ENCODER_MASK_SH_LIST_DCN10(__SHIFT) +}; + +static const struct dcn10_link_enc_mask le_mask = { + LINK_ENCODER_MASK_SH_LIST_DCN10(_MASK) +}; + +static const struct dce_panel_cntl_registers panel_cntl_regs[] = { + { DCN_PANEL_CNTL_REG_LIST() } +}; + +static const struct dce_panel_cntl_shift panel_cntl_shift = { + DCE_PANEL_CNTL_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_panel_cntl_mask panel_cntl_mask = { + DCE_PANEL_CNTL_MASK_SH_LIST(_MASK) +}; + +static const struct dce110_aux_registers_shift aux_shift = { + DCN10_AUX_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce110_aux_registers_mask aux_mask = { + DCN10_AUX_MASK_SH_LIST(_MASK) +}; + +#define ipp_regs(id)\ +[id] = {\ + IPP_REG_LIST_DCN10(id),\ +} + +static const struct dcn10_ipp_registers ipp_regs[] = { + ipp_regs(0), + ipp_regs(1), + ipp_regs(2), + ipp_regs(3), +}; + +static const struct dcn10_ipp_shift ipp_shift = { + IPP_MASK_SH_LIST_DCN10(__SHIFT) +}; + +static const struct dcn10_ipp_mask ipp_mask = { + IPP_MASK_SH_LIST_DCN10(_MASK), +}; + +#define opp_regs(id)\ +[id] = {\ + OPP_REG_LIST_DCN10(id),\ +} + +static const struct dcn10_opp_registers opp_regs[] = { + opp_regs(0), + opp_regs(1), + opp_regs(2), + opp_regs(3), +}; + +static const struct dcn10_opp_shift opp_shift = { + OPP_MASK_SH_LIST_DCN10(__SHIFT) +}; + +static const struct dcn10_opp_mask opp_mask = { + OPP_MASK_SH_LIST_DCN10(_MASK), +}; + +#define aux_engine_regs(id)\ +[id] = {\ + AUX_COMMON_REG_LIST(id), \ + .AUX_RESET_MASK = 0 \ +} + +static const struct dce110_aux_registers aux_engine_regs[] = { + aux_engine_regs(0), + aux_engine_regs(1), + aux_engine_regs(2), + aux_engine_regs(3), + aux_engine_regs(4), + aux_engine_regs(5) +}; + +#define tf_regs(id)\ +[id] = {\ + TF_REG_LIST_DCN10(id),\ +} + +static const struct dcn_dpp_registers tf_regs[] = { + tf_regs(0), + tf_regs(1), + tf_regs(2), + tf_regs(3), +}; + +static const struct dcn_dpp_shift tf_shift = { + TF_REG_LIST_SH_MASK_DCN10(__SHIFT), + TF_DEBUG_REG_LIST_SH_DCN10 + +}; + +static const struct dcn_dpp_mask tf_mask = { + TF_REG_LIST_SH_MASK_DCN10(_MASK), + TF_DEBUG_REG_LIST_MASK_DCN10 +}; + +static const struct dcn_mpc_registers mpc_regs = { + MPC_COMMON_REG_LIST_DCN1_0(0), + MPC_COMMON_REG_LIST_DCN1_0(1), + MPC_COMMON_REG_LIST_DCN1_0(2), + MPC_COMMON_REG_LIST_DCN1_0(3), + MPC_OUT_MUX_COMMON_REG_LIST_DCN1_0(0), + MPC_OUT_MUX_COMMON_REG_LIST_DCN1_0(1), + MPC_OUT_MUX_COMMON_REG_LIST_DCN1_0(2), + MPC_OUT_MUX_COMMON_REG_LIST_DCN1_0(3) +}; + +static const struct dcn_mpc_shift mpc_shift = { + MPC_COMMON_MASK_SH_LIST_DCN1_0(__SHIFT),\ + SFRB(CUR_VUPDATE_LOCK_SET, CUR0_VUPDATE_LOCK_SET0, CUR0_VUPDATE_LOCK_SET, __SHIFT) +}; + +static const struct dcn_mpc_mask mpc_mask = { + MPC_COMMON_MASK_SH_LIST_DCN1_0(_MASK),\ + SFRB(CUR_VUPDATE_LOCK_SET, CUR0_VUPDATE_LOCK_SET0, CUR0_VUPDATE_LOCK_SET, _MASK) +}; + +#define tg_regs(id)\ +[id] = {TG_COMMON_REG_LIST_DCN1_0(id)} + +static const struct dcn_optc_registers tg_regs[] = { + tg_regs(0), + tg_regs(1), + tg_regs(2), + tg_regs(3), +}; + +static const struct dcn_optc_shift tg_shift = { + TG_COMMON_MASK_SH_LIST_DCN1_0(__SHIFT) +}; + +static const struct dcn_optc_mask tg_mask = { + TG_COMMON_MASK_SH_LIST_DCN1_0(_MASK) +}; + +static const struct bios_registers bios_regs = { + NBIO_SR(BIOS_SCRATCH_3), + NBIO_SR(BIOS_SCRATCH_6) +}; + +#define hubp_regs(id)\ +[id] = {\ + HUBP_REG_LIST_DCN10(id)\ +} + +static const struct dcn_mi_registers hubp_regs[] = { + hubp_regs(0), + hubp_regs(1), + hubp_regs(2), + hubp_regs(3), +}; + +static const struct dcn_mi_shift hubp_shift = { + HUBP_MASK_SH_LIST_DCN10(__SHIFT) +}; + +static const struct dcn_mi_mask hubp_mask = { + HUBP_MASK_SH_LIST_DCN10(_MASK) +}; + +static const struct dcn_hubbub_registers hubbub_reg = { + HUBBUB_REG_LIST_DCN10(0) +}; + +static const struct dcn_hubbub_shift hubbub_shift = { + HUBBUB_MASK_SH_LIST_DCN10(__SHIFT) +}; + +static const struct dcn_hubbub_mask hubbub_mask = { + HUBBUB_MASK_SH_LIST_DCN10(_MASK) +}; + +static int map_transmitter_id_to_phy_instance( + enum transmitter transmitter) +{ + switch (transmitter) { + case TRANSMITTER_UNIPHY_A: + return 0; + break; + case TRANSMITTER_UNIPHY_B: + return 1; + break; + case TRANSMITTER_UNIPHY_C: + return 2; + break; + case TRANSMITTER_UNIPHY_D: + return 3; + break; + default: + ASSERT(0); + return 0; + } +} + +#define clk_src_regs(index, pllid)\ +[index] = {\ + CS_COMMON_REG_LIST_DCN1_0(index, pllid),\ +} + +static const struct dce110_clk_src_regs clk_src_regs[] = { + clk_src_regs(0, A), + clk_src_regs(1, B), + clk_src_regs(2, C), + clk_src_regs(3, D) +}; + +static const struct dce110_clk_src_shift cs_shift = { + CS_COMMON_MASK_SH_LIST_DCN1_0(__SHIFT) +}; + +static const struct dce110_clk_src_mask cs_mask = { + CS_COMMON_MASK_SH_LIST_DCN1_0(_MASK) +}; + +static const struct resource_caps res_cap = { + .num_timing_generator = 4, + .num_opp = 4, + .num_video_plane = 4, + .num_audio = 4, + .num_stream_encoder = 4, + .num_pll = 4, + .num_ddc = 4, +}; + +static const struct resource_caps rv2_res_cap = { + .num_timing_generator = 3, + .num_opp = 3, + .num_video_plane = 3, + .num_audio = 3, + .num_stream_encoder = 3, + .num_pll = 3, + .num_ddc = 4, +}; + +static const struct dc_plane_cap plane_cap = { + .type = DC_PLANE_TYPE_DCN_UNIVERSAL, + .per_pixel_alpha = true, + + .pixel_format_support = { + .argb8888 = true, + .nv12 = true, + .fp16 = true, + .p010 = true + }, + + .max_upscale_factor = { + .argb8888 = 16000, + .nv12 = 16000, + .fp16 = 1 + }, + + .max_downscale_factor = { + .argb8888 = 250, + .nv12 = 250, + .fp16 = 1 + } +}; + +static const struct dc_debug_options debug_defaults_drv = { + .sanity_checks = true, + .disable_dmcu = false, + .force_abm_enable = false, + .timing_trace = false, + .clock_trace = true, + + /* raven smu dones't allow 0 disp clk, + * smu min disp clk limit is 50Mhz + * keep min disp clk 100Mhz avoid smu hang + */ + .min_disp_clk_khz = 100000, + + .disable_pplib_clock_request = false, + .disable_pplib_wm_range = false, + .pplib_wm_report_mode = WM_REPORT_DEFAULT, + .pipe_split_policy = MPC_SPLIT_DYNAMIC, + .force_single_disp_pipe_split = true, + .disable_dcc = DCC_ENABLE, + .voltage_align_fclk = true, + .disable_stereo_support = true, + .vsr_support = true, + .performance_trace = false, + .az_endpoint_mute_only = true, + .recovery_enabled = false, /*enable this by default after testing.*/ + .max_downscale_src_width = 3840, + .underflow_assert_delay_us = 0xFFFFFFFF, + .enable_legacy_fast_update = true, + .using_dml2 = false, +}; + +static const struct dc_debug_options debug_defaults_diags = { + .disable_dmcu = false, + .force_abm_enable = false, + .timing_trace = true, + .clock_trace = true, + .disable_stutter = true, + .disable_pplib_clock_request = true, + .disable_pplib_wm_range = true, + .underflow_assert_delay_us = 0xFFFFFFFF, +}; + +static void dcn10_dpp_destroy(struct dpp **dpp) +{ + kfree(TO_DCN10_DPP(*dpp)); + *dpp = NULL; +} + +static struct dpp *dcn10_dpp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn10_dpp *dpp = + kzalloc(sizeof(struct dcn10_dpp), GFP_KERNEL); + + if (!dpp) + return NULL; + + dpp1_construct(dpp, ctx, inst, + &tf_regs[inst], &tf_shift, &tf_mask); + return &dpp->base; +} + +static struct input_pixel_processor *dcn10_ipp_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dcn10_ipp *ipp = + kzalloc(sizeof(struct dcn10_ipp), GFP_KERNEL); + + if (!ipp) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dcn10_ipp_construct(ipp, ctx, inst, + &ipp_regs[inst], &ipp_shift, &ipp_mask); + return &ipp->base; +} + + +static struct output_pixel_processor *dcn10_opp_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dcn10_opp *opp = + kzalloc(sizeof(struct dcn10_opp), GFP_KERNEL); + + if (!opp) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dcn10_opp_construct(opp, ctx, inst, + &opp_regs[inst], &opp_shift, &opp_mask); + return &opp->base; +} + +static struct dce_aux *dcn10_aux_engine_create(struct dc_context *ctx, + uint32_t inst) +{ + struct aux_engine_dce110 *aux_engine = + kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); + + if (!aux_engine) + return NULL; + + dce110_aux_engine_construct(aux_engine, ctx, inst, + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, + &aux_engine_regs[inst], + &aux_mask, + &aux_shift, + ctx->dc->caps.extended_aux_timeout_support); + + return &aux_engine->base; +} +#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST(id) } + +static const struct dce_i2c_registers i2c_hw_regs[] = { + i2c_inst_regs(1), + i2c_inst_regs(2), + i2c_inst_regs(3), + i2c_inst_regs(4), + i2c_inst_regs(5), + i2c_inst_regs(6), +}; + +static const struct dce_i2c_shift i2c_shifts = { + I2C_COMMON_MASK_SH_LIST_DCE110(__SHIFT) +}; + +static const struct dce_i2c_mask i2c_masks = { + I2C_COMMON_MASK_SH_LIST_DCE110(_MASK) +}; + +static struct dce_i2c_hw *dcn10_i2c_hw_create(struct dc_context *ctx, + uint32_t inst) +{ + struct dce_i2c_hw *dce_i2c_hw = + kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); + + if (!dce_i2c_hw) + return NULL; + + dcn1_i2c_hw_construct(dce_i2c_hw, ctx, inst, + &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); + + return dce_i2c_hw; +} +static struct mpc *dcn10_mpc_create(struct dc_context *ctx) +{ + struct dcn10_mpc *mpc10 = kzalloc(sizeof(struct dcn10_mpc), + GFP_KERNEL); + + if (!mpc10) + return NULL; + + dcn10_mpc_construct(mpc10, ctx, + &mpc_regs, + &mpc_shift, + &mpc_mask, + 4); + + return &mpc10->base; +} + +static struct hubbub *dcn10_hubbub_create(struct dc_context *ctx) +{ + struct dcn10_hubbub *dcn10_hubbub = kzalloc(sizeof(struct dcn10_hubbub), + GFP_KERNEL); + + if (!dcn10_hubbub) + return NULL; + + hubbub1_construct(&dcn10_hubbub->base, ctx, + &hubbub_reg, + &hubbub_shift, + &hubbub_mask); + + return &dcn10_hubbub->base; +} + +static struct timing_generator *dcn10_timing_generator_create( + struct dc_context *ctx, + uint32_t instance) +{ + struct optc *tgn10 = + kzalloc(sizeof(struct optc), GFP_KERNEL); + + if (!tgn10) + return NULL; + + tgn10->base.inst = instance; + tgn10->base.ctx = ctx; + + tgn10->tg_regs = &tg_regs[instance]; + tgn10->tg_shift = &tg_shift; + tgn10->tg_mask = &tg_mask; + + dcn10_timing_generator_init(tgn10); + + return &tgn10->base; +} + +static const struct encoder_feature_support link_enc_feature = { + .max_hdmi_deep_color = COLOR_DEPTH_121212, + .max_hdmi_pixel_clock = 600000, + .hdmi_ycbcr420_supported = true, + .dp_ycbcr420_supported = true, + .flags.bits.IS_HBR2_CAPABLE = true, + .flags.bits.IS_HBR3_CAPABLE = true, + .flags.bits.IS_TPS3_CAPABLE = true, + .flags.bits.IS_TPS4_CAPABLE = true +}; + +static struct link_encoder *dcn10_link_encoder_create( + struct dc_context *ctx, + const struct encoder_init_data *enc_init_data) +{ + struct dcn10_link_encoder *enc10 = + kzalloc(sizeof(struct dcn10_link_encoder), GFP_KERNEL); + int link_regs_id; + + if (!enc10) + return NULL; + + link_regs_id = + map_transmitter_id_to_phy_instance(enc_init_data->transmitter); + + dcn10_link_encoder_construct(enc10, + enc_init_data, + &link_enc_feature, + &link_enc_regs[link_regs_id], + &link_enc_aux_regs[enc_init_data->channel - 1], + &link_enc_hpd_regs[enc_init_data->hpd_source], + &le_shift, + &le_mask); + + return &enc10->base; +} + +static struct panel_cntl *dcn10_panel_cntl_create(const struct panel_cntl_init_data *init_data) +{ + struct dce_panel_cntl *panel_cntl = + kzalloc(sizeof(struct dce_panel_cntl), GFP_KERNEL); + + if (!panel_cntl) + return NULL; + + dce_panel_cntl_construct(panel_cntl, + init_data, + &panel_cntl_regs[init_data->inst], + &panel_cntl_shift, + &panel_cntl_mask); + + return &panel_cntl->base; +} + +static struct clock_source *dcn10_clock_source_create( + struct dc_context *ctx, + struct dc_bios *bios, + enum clock_source_id id, + const struct dce110_clk_src_regs *regs, + bool dp_clk_src) +{ + struct dce110_clk_src *clk_src = + kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); + + if (!clk_src) + return NULL; + + if (dce112_clk_src_construct(clk_src, ctx, bios, id, + regs, &cs_shift, &cs_mask)) { + clk_src->base.dp_clk_src = dp_clk_src; + return &clk_src->base; + } + + kfree(clk_src); + BREAK_TO_DEBUGGER(); + return NULL; +} + +static void read_dce_straps( + struct dc_context *ctx, + struct resource_straps *straps) +{ + generic_reg_get(ctx, mmDC_PINSTRAPS + BASE(mmDC_PINSTRAPS_BASE_IDX), + FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio); +} + +static struct audio *create_audio( + struct dc_context *ctx, unsigned int inst) +{ + return dce_audio_create(ctx, inst, + &audio_regs[inst], &audio_shift, &audio_mask); +} + +static struct stream_encoder *dcn10_stream_encoder_create( + enum engine_id eng_id, + struct dc_context *ctx) +{ + struct dcn10_stream_encoder *enc1 = + kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL); + + if (!enc1) + return NULL; + + dcn10_stream_encoder_construct(enc1, ctx, ctx->dc_bios, eng_id, + &stream_enc_regs[eng_id], + &se_shift, &se_mask); + return &enc1->base; +} + +static const struct dce_hwseq_registers hwseq_reg = { + HWSEQ_DCN1_REG_LIST() +}; + +static const struct dce_hwseq_shift hwseq_shift = { + HWSEQ_DCN1_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_hwseq_mask hwseq_mask = { + HWSEQ_DCN1_MASK_SH_LIST(_MASK) +}; + +static struct dce_hwseq *dcn10_hwseq_create( + struct dc_context *ctx) +{ + struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); + + if (hws) { + hws->ctx = ctx; + hws->regs = &hwseq_reg; + hws->shifts = &hwseq_shift; + hws->masks = &hwseq_mask; + hws->wa.DEGVIDCN10_253 = true; + hws->wa.false_optc_underflow = true; + hws->wa.DEGVIDCN10_254 = true; + + if ((ctx->asic_id.chip_family == FAMILY_RV) && + ASICREV_IS_RAVEN2(ctx->asic_id.hw_internal_rev)) + switch (ctx->asic_id.pci_revision_id) { + case PRID_POLLOCK_94: + case PRID_POLLOCK_95: + case PRID_POLLOCK_E9: + case PRID_POLLOCK_EA: + case PRID_POLLOCK_EB: + hws->wa.wait_hubpret_read_start_during_mpo_transition = true; + break; + default: + hws->wa.wait_hubpret_read_start_during_mpo_transition = false; + break; + } + } + return hws; +} + +static const struct resource_create_funcs res_create_funcs = { + .read_dce_straps = read_dce_straps, + .create_audio = create_audio, + .create_stream_encoder = dcn10_stream_encoder_create, + .create_hwseq = dcn10_hwseq_create, +}; + +static void dcn10_clock_source_destroy(struct clock_source **clk_src) +{ + kfree(TO_DCE110_CLK_SRC(*clk_src)); + *clk_src = NULL; +} + +static struct pp_smu_funcs *dcn10_pp_smu_create(struct dc_context *ctx) +{ + struct pp_smu_funcs *pp_smu = kzalloc(sizeof(*pp_smu), GFP_KERNEL); + + if (!pp_smu) + return pp_smu; + + dm_pp_get_funcs(ctx, pp_smu); + return pp_smu; +} + +static void dcn10_resource_destruct(struct dcn10_resource_pool *pool) +{ + unsigned int i; + + for (i = 0; i < pool->base.stream_enc_count; i++) { + if (pool->base.stream_enc[i] != NULL) { + kfree(DCN10STRENC_FROM_STRENC(pool->base.stream_enc[i])); + pool->base.stream_enc[i] = NULL; + } + } + + if (pool->base.mpc != NULL) { + kfree(TO_DCN10_MPC(pool->base.mpc)); + pool->base.mpc = NULL; + } + + kfree(pool->base.hubbub); + pool->base.hubbub = NULL; + + for (i = 0; i < pool->base.pipe_count; i++) { + if (pool->base.opps[i] != NULL) + pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]); + + if (pool->base.dpps[i] != NULL) + dcn10_dpp_destroy(&pool->base.dpps[i]); + + if (pool->base.ipps[i] != NULL) + pool->base.ipps[i]->funcs->ipp_destroy(&pool->base.ipps[i]); + + if (pool->base.hubps[i] != NULL) { + kfree(TO_DCN10_HUBP(pool->base.hubps[i])); + pool->base.hubps[i] = NULL; + } + + if (pool->base.irqs != NULL) { + dal_irq_service_destroy(&pool->base.irqs); + } + + if (pool->base.timing_generators[i] != NULL) { + kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i])); + pool->base.timing_generators[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + if (pool->base.engines[i] != NULL) + dce110_engine_destroy(&pool->base.engines[i]); + kfree(pool->base.hw_i2cs[i]); + pool->base.hw_i2cs[i] = NULL; + kfree(pool->base.sw_i2cs[i]); + pool->base.sw_i2cs[i] = NULL; + } + + for (i = 0; i < pool->base.audio_count; i++) { + if (pool->base.audios[i]) + dce_aud_destroy(&pool->base.audios[i]); + } + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] != NULL) { + dcn10_clock_source_destroy(&pool->base.clock_sources[i]); + pool->base.clock_sources[i] = NULL; + } + } + + if (pool->base.dp_clock_source != NULL) { + dcn10_clock_source_destroy(&pool->base.dp_clock_source); + pool->base.dp_clock_source = NULL; + } + + if (pool->base.abm != NULL) + dce_abm_destroy(&pool->base.abm); + + if (pool->base.dmcu != NULL) + dce_dmcu_destroy(&pool->base.dmcu); + + kfree(pool->base.pp_smu); +} + +static struct hubp *dcn10_hubp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn10_hubp *hubp1 = + kzalloc(sizeof(struct dcn10_hubp), GFP_KERNEL); + + if (!hubp1) + return NULL; + + dcn10_hubp_construct(hubp1, ctx, inst, + &hubp_regs[inst], &hubp_shift, &hubp_mask); + return &hubp1->base; +} + +static void get_pixel_clock_parameters( + const struct pipe_ctx *pipe_ctx, + struct pixel_clk_params *pixel_clk_params) +{ + const struct dc_stream_state *stream = pipe_ctx->stream; + pixel_clk_params->requested_pix_clk_100hz = stream->timing.pix_clk_100hz; + pixel_clk_params->encoder_object_id = stream->link->link_enc->id; + pixel_clk_params->signal_type = pipe_ctx->stream->signal; + pixel_clk_params->controller_id = pipe_ctx->stream_res.tg->inst + 1; + /* TODO: un-hardcode*/ + pixel_clk_params->requested_sym_clk = LINK_RATE_LOW * + LINK_RATE_REF_FREQ_IN_KHZ; + pixel_clk_params->flags.ENABLE_SS = 0; + pixel_clk_params->color_depth = + stream->timing.display_color_depth; + pixel_clk_params->flags.DISPLAY_BLANKED = 1; + pixel_clk_params->pixel_encoding = stream->timing.pixel_encoding; + + if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR422) + pixel_clk_params->color_depth = COLOR_DEPTH_888; + + if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) + pixel_clk_params->requested_pix_clk_100hz /= 2; + if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING) + pixel_clk_params->requested_pix_clk_100hz *= 2; + +} + +static void build_clamping_params(struct dc_stream_state *stream) +{ + stream->clamping.clamping_level = CLAMPING_FULL_RANGE; + stream->clamping.c_depth = stream->timing.display_color_depth; + stream->clamping.pixel_encoding = stream->timing.pixel_encoding; +} + +static void build_pipe_hw_param(struct pipe_ctx *pipe_ctx) +{ + + get_pixel_clock_parameters(pipe_ctx, &pipe_ctx->stream_res.pix_clk_params); + + pipe_ctx->clock_source->funcs->get_pix_clk_dividers( + pipe_ctx->clock_source, + &pipe_ctx->stream_res.pix_clk_params, + &pipe_ctx->pll_settings); + + pipe_ctx->stream->clamping.pixel_encoding = pipe_ctx->stream->timing.pixel_encoding; + + resource_build_bit_depth_reduction_params(pipe_ctx->stream, + &pipe_ctx->stream->bit_depth_params); + build_clamping_params(pipe_ctx->stream); +} + +static enum dc_status build_mapped_resource( + const struct dc *dc, + struct dc_state *context, + struct dc_stream_state *stream) +{ + struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream); + + if (!pipe_ctx) + return DC_ERROR_UNEXPECTED; + + build_pipe_hw_param(pipe_ctx); + return DC_OK; +} + +static enum dc_status dcn10_add_stream_to_ctx( + struct dc *dc, + struct dc_state *new_ctx, + struct dc_stream_state *dc_stream) +{ + enum dc_status result = DC_ERROR_UNEXPECTED; + + result = resource_map_pool_resources(dc, new_ctx, dc_stream); + + if (result == DC_OK) + result = resource_map_phy_clock_resources(dc, new_ctx, dc_stream); + + + if (result == DC_OK) + result = build_mapped_resource(dc, new_ctx, dc_stream); + + return result; +} + +static struct pipe_ctx *dcn10_acquire_free_pipe_for_layer( + const struct dc_state *cur_ctx, + struct dc_state *new_ctx, + const struct resource_pool *pool, + const struct pipe_ctx *opp_head_pipe) +{ + struct resource_context *res_ctx = &new_ctx->res_ctx; + struct pipe_ctx *head_pipe = resource_get_otg_master_for_stream(res_ctx, opp_head_pipe->stream); + struct pipe_ctx *idle_pipe = resource_find_free_secondary_pipe_legacy(res_ctx, pool, head_pipe); + + if (!head_pipe) { + ASSERT(0); + return NULL; + } + + if (!idle_pipe) + return NULL; + + idle_pipe->stream = head_pipe->stream; + idle_pipe->stream_res.tg = head_pipe->stream_res.tg; + idle_pipe->stream_res.abm = head_pipe->stream_res.abm; + idle_pipe->stream_res.opp = head_pipe->stream_res.opp; + + idle_pipe->plane_res.hubp = pool->hubps[idle_pipe->pipe_idx]; + idle_pipe->plane_res.ipp = pool->ipps[idle_pipe->pipe_idx]; + idle_pipe->plane_res.dpp = pool->dpps[idle_pipe->pipe_idx]; + idle_pipe->plane_res.mpcc_inst = pool->dpps[idle_pipe->pipe_idx]->inst; + + return idle_pipe; +} + +static bool dcn10_get_dcc_compression_cap(const struct dc *dc, + const struct dc_dcc_surface_param *input, + struct dc_surface_dcc_cap *output) +{ + return dc->res_pool->hubbub->funcs->get_dcc_compression_cap( + dc->res_pool->hubbub, + input, + output); +} + +static void dcn10_destroy_resource_pool(struct resource_pool **pool) +{ + struct dcn10_resource_pool *dcn10_pool = TO_DCN10_RES_POOL(*pool); + + dcn10_resource_destruct(dcn10_pool); + kfree(dcn10_pool); + *pool = NULL; +} + +static bool dcn10_validate_bandwidth( + struct dc *dc, + struct dc_state *context, + bool fast_validate) +{ + bool voltage_supported; + + DC_FP_START(); + voltage_supported = dcn_validate_bandwidth(dc, context, fast_validate); + DC_FP_END(); + + return voltage_supported; +} + +static enum dc_status dcn10_validate_plane(const struct dc_plane_state *plane_state, struct dc_caps *caps) +{ + if (plane_state->format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN + && caps->max_video_width != 0 + && plane_state->src_rect.width > caps->max_video_width) + return DC_FAIL_SURFACE_VALIDATE; + + return DC_OK; +} + +static enum dc_status dcn10_validate_global(struct dc *dc, struct dc_state *context) +{ + int i, j; + bool video_down_scaled = false; + bool video_large = false; + bool desktop_large = false; + bool dcc_disabled = false; + bool mpo_enabled = false; + + for (i = 0; i < context->stream_count; i++) { + if (context->stream_status[i].plane_count == 0) + continue; + + if (context->stream_status[i].plane_count > 2) + return DC_FAIL_UNSUPPORTED_1; + + if (context->stream_status[i].plane_count > 1) + mpo_enabled = true; + + for (j = 0; j < context->stream_status[i].plane_count; j++) { + struct dc_plane_state *plane = + context->stream_status[i].plane_states[j]; + + + if (plane->format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) { + + if (plane->src_rect.width > plane->dst_rect.width || + plane->src_rect.height > plane->dst_rect.height) + video_down_scaled = true; + + if (plane->src_rect.width >= 3840) + video_large = true; + + } else { + if (plane->src_rect.width >= 3840) + desktop_large = true; + if (!plane->dcc.enable) + dcc_disabled = true; + } + } + } + + /* Disable MPO in multi-display configurations. */ + if (context->stream_count > 1 && mpo_enabled) + return DC_FAIL_UNSUPPORTED_1; + + /* + * Workaround: On DCN10 there is UMC issue that causes underflow when + * playing 4k video on 4k desktop with video downscaled and single channel + * memory + */ + if (video_large && desktop_large && video_down_scaled && dcc_disabled && + dc->dcn_soc->number_of_channels == 1) + return DC_FAIL_SURFACE_VALIDATE; + + return DC_OK; +} + +static enum dc_status dcn10_patch_unknown_plane_state(struct dc_plane_state *plane_state) +{ + 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; + + if (bpp == 64) + swizzle = DC_SW_64KB_D; + else + swizzle = DC_SW_64KB_S; + + plane_state->tiling_info.gfx9.swizzle = swizzle; + return DC_OK; +} + +struct stream_encoder *dcn10_find_first_free_match_stream_enc_for_link( + struct resource_context *res_ctx, + const struct resource_pool *pool, + struct dc_stream_state *stream) +{ + int i; + int j = -1; + struct dc_link *link = stream->link; + + for (i = 0; i < pool->stream_enc_count; i++) { + if (!res_ctx->is_stream_enc_acquired[i] && + pool->stream_enc[i]) { + /* Store first available for MST second display + * in daisy chain use case + */ + + if (pool->stream_enc[i]->id != ENGINE_ID_VIRTUAL) + j = i; + + if (link->ep_type == DISPLAY_ENDPOINT_PHY && pool->stream_enc[i]->id == + link->link_enc->preferred_engine) + return pool->stream_enc[i]; + } + } + + /* + * For CZ and later, we can allow DIG FE and BE to differ for all display types + */ + + if (j >= 0) + return pool->stream_enc[j]; + + return NULL; +} + +static const struct dc_cap_funcs cap_funcs = { + .get_dcc_compression_cap = dcn10_get_dcc_compression_cap +}; + +static const struct resource_funcs dcn10_res_pool_funcs = { + .destroy = dcn10_destroy_resource_pool, + .link_enc_create = dcn10_link_encoder_create, + .panel_cntl_create = dcn10_panel_cntl_create, + .validate_bandwidth = dcn10_validate_bandwidth, + .acquire_free_pipe_as_secondary_dpp_pipe = dcn10_acquire_free_pipe_for_layer, + .validate_plane = dcn10_validate_plane, + .validate_global = dcn10_validate_global, + .add_stream_to_ctx = dcn10_add_stream_to_ctx, + .patch_unknown_plane_state = dcn10_patch_unknown_plane_state, + .find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link +}; + +static uint32_t read_pipe_fuses(struct dc_context *ctx) +{ + uint32_t value = dm_read_reg_soc15(ctx, mmCC_DC_PIPE_DIS, 0); + /* RV1 support max 4 pipes */ + value = value & 0xf; + return value; +} + +static bool verify_clock_values(struct dm_pp_clock_levels_with_voltage *clks) +{ + int i; + + if (clks->num_levels == 0) + return false; + + for (i = 0; i < clks->num_levels; i++) + /* Ensure that the result is sane */ + if (clks->data[i].clocks_in_khz == 0) + return false; + + return true; +} + +static bool dcn10_resource_construct( + uint8_t num_virtual_links, + struct dc *dc, + struct dcn10_resource_pool *pool) +{ + int i; + int j; + struct dc_context *ctx = dc->ctx; + uint32_t pipe_fuses = read_pipe_fuses(ctx); + struct dm_pp_clock_levels_with_voltage fclks = {0}, dcfclks = {0}; + int min_fclk_khz, min_dcfclk_khz, socclk_khz; + bool res; + + ctx->dc_bios->regs = &bios_regs; + + if (ctx->dce_version == DCN_VERSION_1_01) + pool->base.res_cap = &rv2_res_cap; + else + pool->base.res_cap = &res_cap; + pool->base.funcs = &dcn10_res_pool_funcs; + + /* + * TODO fill in from actual raven resource when we create + * more than virtual encoder + */ + + /************************************************* + * Resource + asic cap harcoding * + *************************************************/ + pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + + /* max pipe num for ASIC before check pipe fuses */ + pool->base.pipe_count = pool->base.res_cap->num_timing_generator; + + if (dc->ctx->dce_version == DCN_VERSION_1_01) + pool->base.pipe_count = 3; + dc->caps.max_video_width = 3840; + dc->caps.max_downscale_ratio = 200; + dc->caps.i2c_speed_in_khz = 100; + dc->caps.i2c_speed_in_khz_hdcp = 100; /*1.4 w/a not applied by default*/ + dc->caps.max_cursor_size = 256; + dc->caps.min_horizontal_blanking_period = 80; + dc->caps.max_slave_planes = 1; + dc->caps.max_slave_yuv_planes = 1; + dc->caps.max_slave_rgb_planes = 0; + dc->caps.is_apu = true; + dc->caps.post_blend_color_processing = false; + dc->caps.extended_aux_timeout_support = false; + + /* Raven DP PHY HBR2 eye diagram pattern is not stable. Use TP4 */ + dc->caps.force_dp_tps4_for_cp2520 = true; + + /* Color pipeline capabilities */ + dc->caps.color.dpp.dcn_arch = 1; + dc->caps.color.dpp.input_lut_shared = 1; + dc->caps.color.dpp.icsc = 1; + dc->caps.color.dpp.dgam_ram = 1; + dc->caps.color.dpp.dgam_rom_caps.srgb = 1; + dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1; + dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 0; + dc->caps.color.dpp.dgam_rom_caps.pq = 0; + dc->caps.color.dpp.dgam_rom_caps.hlg = 0; + dc->caps.color.dpp.post_csc = 0; + dc->caps.color.dpp.gamma_corr = 0; + dc->caps.color.dpp.dgam_rom_for_yuv = 1; + + dc->caps.color.dpp.hw_3d_lut = 0; + dc->caps.color.dpp.ogam_ram = 1; // RGAM on DCN1 + dc->caps.color.dpp.ogam_rom_caps.srgb = 1; + dc->caps.color.dpp.ogam_rom_caps.bt2020 = 1; + dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0; + dc->caps.color.dpp.ogam_rom_caps.pq = 0; + dc->caps.color.dpp.ogam_rom_caps.hlg = 0; + dc->caps.color.dpp.ocsc = 1; + + /* no post-blend color operations */ + dc->caps.color.mpc.gamut_remap = 0; + dc->caps.color.mpc.num_3dluts = 0; + dc->caps.color.mpc.shared_3d_lut = 0; + dc->caps.color.mpc.ogam_ram = 0; + dc->caps.color.mpc.ogam_rom_caps.srgb = 0; + dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0; + dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0; + dc->caps.color.mpc.ogam_rom_caps.pq = 0; + dc->caps.color.mpc.ogam_rom_caps.hlg = 0; + dc->caps.color.mpc.ocsc = 0; + + if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) + dc->debug = debug_defaults_drv; + else + dc->debug = debug_defaults_diags; + + /************************************************* + * Create resources * + *************************************************/ + + pool->base.clock_sources[DCN10_CLK_SRC_PLL0] = + dcn10_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL0, + &clk_src_regs[0], false); + pool->base.clock_sources[DCN10_CLK_SRC_PLL1] = + dcn10_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL1, + &clk_src_regs[1], false); + pool->base.clock_sources[DCN10_CLK_SRC_PLL2] = + dcn10_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL2, + &clk_src_regs[2], false); + + if (dc->ctx->dce_version == DCN_VERSION_1_0) { + pool->base.clock_sources[DCN10_CLK_SRC_PLL3] = + dcn10_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL3, + &clk_src_regs[3], false); + } + + pool->base.clk_src_count = DCN10_CLK_SRC_TOTAL; + + if (dc->ctx->dce_version == DCN_VERSION_1_01) + pool->base.clk_src_count = DCN101_CLK_SRC_TOTAL; + + pool->base.dp_clock_source = + dcn10_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_ID_DP_DTO, + /* todo: not reuse phy_pll registers */ + &clk_src_regs[0], true); + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] == NULL) { + dm_error("DC: failed to create clock sources!\n"); + BREAK_TO_DEBUGGER(); + goto fail; + } + } + + pool->base.dmcu = dcn10_dmcu_create(ctx, + &dmcu_regs, + &dmcu_shift, + &dmcu_mask); + if (pool->base.dmcu == NULL) { + dm_error("DC: failed to create dmcu!\n"); + BREAK_TO_DEBUGGER(); + goto fail; + } + + pool->base.abm = dce_abm_create(ctx, + &abm_regs, + &abm_shift, + &abm_mask); + if (pool->base.abm == NULL) { + dm_error("DC: failed to create abm!\n"); + BREAK_TO_DEBUGGER(); + goto fail; + } + + dml_init_instance(&dc->dml, &dcn1_0_soc, &dcn1_0_ip, DML_PROJECT_RAVEN1); + memcpy(dc->dcn_ip, &dcn10_ip_defaults, sizeof(dcn10_ip_defaults)); + memcpy(dc->dcn_soc, &dcn10_soc_defaults, sizeof(dcn10_soc_defaults)); + + DC_FP_START(); + dcn10_resource_construct_fp(dc); + DC_FP_END(); + + if (!dc->config.is_vmin_only_asic) + if (ASICREV_IS_RAVEN2(dc->ctx->asic_id.hw_internal_rev)) + switch (dc->ctx->asic_id.pci_revision_id) { + case PRID_DALI_DE: + case PRID_DALI_DF: + case PRID_DALI_E3: + case PRID_DALI_E4: + case PRID_POLLOCK_94: + case PRID_POLLOCK_95: + case PRID_POLLOCK_E9: + case PRID_POLLOCK_EA: + case PRID_POLLOCK_EB: + dc->config.is_vmin_only_asic = true; + break; + default: + break; + } + + pool->base.pp_smu = dcn10_pp_smu_create(ctx); + + /* + * Right now SMU/PPLIB and DAL all have the AZ D3 force PME notification * + * implemented. So AZ D3 should work.For issue 197007. * + */ + if (pool->base.pp_smu != NULL + && pool->base.pp_smu->rv_funcs.set_pme_wa_enable != NULL) + dc->debug.az_endpoint_mute_only = false; + + + if (!dc->debug.disable_pplib_clock_request) { + /* + * TODO: This is not the proper way to obtain + * fabric_and_dram_bandwidth, should be min(fclk, memclk). + */ + res = dm_pp_get_clock_levels_by_type_with_voltage( + ctx, DM_PP_CLOCK_TYPE_FCLK, &fclks); + + DC_FP_START(); + + if (res) + res = verify_clock_values(&fclks); + + if (res) + dcn_bw_update_from_pplib_fclks(dc, &fclks); + else + BREAK_TO_DEBUGGER(); + + DC_FP_END(); + + res = dm_pp_get_clock_levels_by_type_with_voltage( + ctx, DM_PP_CLOCK_TYPE_DCFCLK, &dcfclks); + + DC_FP_START(); + + if (res) + res = verify_clock_values(&dcfclks); + + if (res) + dcn_bw_update_from_pplib_dcfclks(dc, &dcfclks); + else + BREAK_TO_DEBUGGER(); + + DC_FP_END(); + } + + dcn_bw_sync_calcs_and_dml(dc); + if (!dc->debug.disable_pplib_wm_range) { + dc->res_pool = &pool->base; + DC_FP_START(); + dcn_get_soc_clks( + dc, &min_fclk_khz, &min_dcfclk_khz, &socclk_khz); + DC_FP_END(); + dcn_bw_notify_pplib_of_wm_ranges( + dc, min_fclk_khz, min_dcfclk_khz, socclk_khz); + } + + { + struct irq_service_init_data init_data; + init_data.ctx = dc->ctx; + pool->base.irqs = dal_irq_service_dcn10_create(&init_data); + if (!pool->base.irqs) + goto fail; + } + + /* index to valid pipe resource */ + j = 0; + /* mem input -> ipp -> dpp -> opp -> TG */ + for (i = 0; i < pool->base.pipe_count; i++) { + /* if pipe is disabled, skip instance of HW pipe, + * i.e, skip ASIC register instance + */ + if ((pipe_fuses & (1 << i)) != 0) + continue; + + pool->base.hubps[j] = dcn10_hubp_create(ctx, i); + if (pool->base.hubps[j] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create memory input!\n"); + goto fail; + } + + pool->base.ipps[j] = dcn10_ipp_create(ctx, i); + if (pool->base.ipps[j] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create input pixel processor!\n"); + goto fail; + } + + pool->base.dpps[j] = dcn10_dpp_create(ctx, i); + if (pool->base.dpps[j] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create dpp!\n"); + goto fail; + } + + pool->base.opps[j] = dcn10_opp_create(ctx, i); + if (pool->base.opps[j] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create output pixel processor!\n"); + goto fail; + } + + pool->base.timing_generators[j] = dcn10_timing_generator_create( + ctx, i); + if (pool->base.timing_generators[j] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create tg!\n"); + goto fail; + } + /* check next valid pipe */ + j++; + } + + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + pool->base.engines[i] = dcn10_aux_engine_create(ctx, i); + if (pool->base.engines[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create aux engine!!\n"); + goto fail; + } + pool->base.hw_i2cs[i] = dcn10_i2c_hw_create(ctx, i); + if (pool->base.hw_i2cs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create hw i2c!!\n"); + goto fail; + } + pool->base.sw_i2cs[i] = NULL; + } + + /* valid pipe num */ + pool->base.pipe_count = j; + pool->base.timing_generator_count = j; + + /* within dml lib, it is hard code to 4. If ASIC pipe is fused, + * the value may be changed + */ + dc->dml.ip.max_num_dpp = pool->base.pipe_count; + dc->dcn_ip->max_num_dpp = pool->base.pipe_count; + + pool->base.mpc = dcn10_mpc_create(ctx); + if (pool->base.mpc == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create mpc!\n"); + goto fail; + } + + pool->base.hubbub = dcn10_hubbub_create(ctx); + if (pool->base.hubbub == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create hubbub!\n"); + goto fail; + } + + if (!resource_construct(num_virtual_links, dc, &pool->base, + &res_create_funcs)) + goto fail; + + dcn10_hw_sequencer_construct(dc); + dc->caps.max_planes = pool->base.pipe_count; + + for (i = 0; i < dc->caps.max_planes; ++i) + dc->caps.planes[i] = plane_cap; + + dc->cap_funcs = cap_funcs; + + return true; + +fail: + + dcn10_resource_destruct(pool); + + return false; +} + +struct resource_pool *dcn10_create_resource_pool( + const struct dc_init_data *init_data, + struct dc *dc) +{ + struct dcn10_resource_pool *pool = + kzalloc(sizeof(struct dcn10_resource_pool), GFP_KERNEL); + + if (!pool) + return NULL; + + if (dcn10_resource_construct(init_data->num_virtual_links, dc, pool)) + return &pool->base; + + kfree(pool); + BREAK_TO_DEBUGGER(); + return NULL; +} diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.h new file mode 100644 index 00000000000000..bf8e33cd8147c8 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.h @@ -0,0 +1,56 @@ +/* +* Copyright 2016 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_RESOURCE_DCN10_H__ +#define __DC_RESOURCE_DCN10_H__ + +#include "core_types.h" +#include "dml/dcn10/dcn10_fpu.h" + +#define TO_DCN10_RES_POOL(pool)\ + container_of(pool, struct dcn10_resource_pool, base) + +struct dc; +struct resource_pool; +struct _vcs_dpi_display_pipe_params_st; + +extern struct _vcs_dpi_ip_params_st dcn1_0_ip; +extern struct _vcs_dpi_soc_bounding_box_st dcn1_0_soc; + +struct dcn10_resource_pool { + struct resource_pool base; +}; +struct resource_pool *dcn10_create_resource_pool( + const struct dc_init_data *init_data, + struct dc *dc); + +struct stream_encoder *dcn10_find_first_free_match_stream_enc_for_link( + struct resource_context *res_ctx, + const struct resource_pool *pool, + struct dc_stream_state *stream); + + +#endif /* __DC_RESOURCE_DCN10_H__ */ + diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c new file mode 100644 index 00000000000000..f9c5bc624be305 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c @@ -0,0 +1,2793 @@ +/* +* Copyright 2016 Advanced Micro Devices, Inc. + * Copyright 2019 Raptor Engineering, LLC + * + * 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 + +#include "dm_services.h" +#include "dc.h" + +#include "dcn20/dcn20_init.h" + +#include "resource.h" +#include "include/irq_service_interface.h" +#include "dcn20/dcn20_resource.h" + +#include "dml/dcn20/dcn20_fpu.h" + +#include "dcn10/dcn10_hubp.h" +#include "dcn10/dcn10_ipp.h" +#include "dcn20/dcn20_hubbub.h" +#include "dcn20/dcn20_mpc.h" +#include "dcn20/dcn20_hubp.h" +#include "irq/dcn20/irq_service_dcn20.h" +#include "dcn20/dcn20_dpp.h" +#include "dcn20/dcn20_optc.h" +#include "dcn20/dcn20_hwseq.h" +#include "dce110/dce110_hwseq.h" +#include "dcn10/dcn10_resource.h" +#include "dcn20/dcn20_opp.h" + +#include "dcn20/dcn20_dsc.h" + +#include "dcn20/dcn20_link_encoder.h" +#include "dcn20/dcn20_stream_encoder.h" +#include "dce/dce_clock_source.h" +#include "dce/dce_audio.h" +#include "dce/dce_hwseq.h" +#include "virtual/virtual_stream_encoder.h" +#include "dce110/dce110_resource.h" +#include "dml/display_mode_vba.h" +#include "dcn20/dcn20_dccg.h" +#include "dcn20/dcn20_vmid.h" +#include "dce/dce_panel_cntl.h" + +#include "navi10_ip_offset.h" + +#include "dcn/dcn_2_0_0_offset.h" +#include "dcn/dcn_2_0_0_sh_mask.h" +#include "dpcs/dpcs_2_0_0_offset.h" +#include "dpcs/dpcs_2_0_0_sh_mask.h" + +#include "nbio/nbio_2_3_offset.h" + +#include "dcn20/dcn20_dwb.h" +#include "dcn20/dcn20_mmhubbub.h" + +#include "mmhub/mmhub_2_0_0_offset.h" +#include "mmhub/mmhub_2_0_0_sh_mask.h" + +#include "reg_helper.h" +#include "dce/dce_abm.h" +#include "dce/dce_dmcu.h" +#include "dce/dce_aux.h" +#include "dce/dce_i2c.h" +#include "vm_helper.h" +#include "link_enc_cfg.h" + +#include "amdgpu_socbb.h" + +#include "link.h" +#define DC_LOGGER_INIT(logger) + +#ifndef mmDP0_DP_DPHY_INTERNAL_CTRL + #define mmDP0_DP_DPHY_INTERNAL_CTRL 0x210f + #define mmDP0_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 + #define mmDP1_DP_DPHY_INTERNAL_CTRL 0x220f + #define mmDP1_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 + #define mmDP2_DP_DPHY_INTERNAL_CTRL 0x230f + #define mmDP2_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 + #define mmDP3_DP_DPHY_INTERNAL_CTRL 0x240f + #define mmDP3_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 + #define mmDP4_DP_DPHY_INTERNAL_CTRL 0x250f + #define mmDP4_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 + #define mmDP5_DP_DPHY_INTERNAL_CTRL 0x260f + #define mmDP5_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 + #define mmDP6_DP_DPHY_INTERNAL_CTRL 0x270f + #define mmDP6_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 +#endif + + +enum dcn20_clk_src_array_id { + DCN20_CLK_SRC_PLL0, + DCN20_CLK_SRC_PLL1, + DCN20_CLK_SRC_PLL2, + DCN20_CLK_SRC_PLL3, + DCN20_CLK_SRC_PLL4, + DCN20_CLK_SRC_PLL5, + DCN20_CLK_SRC_TOTAL +}; + +/* begin ********************* + * macros to expend register list macro defined in HW object header file */ + +/* DCN */ +#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg + +#define BASE(seg) BASE_INNER(seg) + +#define SR(reg_name)\ + .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + \ + mm ## reg_name + +#define SRI(reg_name, block, id)\ + .reg_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define SRI2_DWB(reg_name, block, id)\ + .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + \ + mm ## reg_name +#define SF_DWB(reg_name, field_name, post_fix)\ + .field_name = reg_name ## __ ## field_name ## post_fix + +#define SF_DWB2(reg_name, block, id, field_name, post_fix) \ + .field_name = reg_name ## __ ## field_name ## post_fix + +#define SRIR(var_name, reg_name, block, id)\ + .var_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define SRII(reg_name, block, id)\ + .reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define DCCG_SRII(reg_name, block, id)\ + .block ## _ ## reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define VUPDATE_SRII(reg_name, block, id)\ + .reg_name[id] = BASE(mm ## reg_name ## _ ## block ## id ## _BASE_IDX) + \ + mm ## reg_name ## _ ## block ## id + +/* NBIO */ +#define NBIO_BASE_INNER(seg) \ + NBIO_BASE__INST0_SEG ## seg + +#define NBIO_BASE(seg) \ + NBIO_BASE_INNER(seg) + +#define NBIO_SR(reg_name)\ + .reg_name = NBIO_BASE(mm ## reg_name ## _BASE_IDX) + \ + mm ## reg_name + +/* MMHUB */ +#define MMHUB_BASE_INNER(seg) \ + MMHUB_BASE__INST0_SEG ## seg + +#define MMHUB_BASE(seg) \ + MMHUB_BASE_INNER(seg) + +#define MMHUB_SR(reg_name)\ + .reg_name = MMHUB_BASE(mmMM ## reg_name ## _BASE_IDX) + \ + mmMM ## reg_name + +static const struct bios_registers bios_regs = { + NBIO_SR(BIOS_SCRATCH_3), + NBIO_SR(BIOS_SCRATCH_6) +}; + +#define clk_src_regs(index, pllid)\ +[index] = {\ + CS_COMMON_REG_LIST_DCN2_0(index, pllid),\ +} + +static const struct dce110_clk_src_regs clk_src_regs[] = { + clk_src_regs(0, A), + clk_src_regs(1, B), + clk_src_regs(2, C), + clk_src_regs(3, D), + clk_src_regs(4, E), + clk_src_regs(5, F) +}; + +static const struct dce110_clk_src_shift cs_shift = { + CS_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) +}; + +static const struct dce110_clk_src_mask cs_mask = { + CS_COMMON_MASK_SH_LIST_DCN2_0(_MASK) +}; + +static const struct dce_dmcu_registers dmcu_regs = { + DMCU_DCN10_REG_LIST() +}; + +static const struct dce_dmcu_shift dmcu_shift = { + DMCU_MASK_SH_LIST_DCN10(__SHIFT) +}; + +static const struct dce_dmcu_mask dmcu_mask = { + DMCU_MASK_SH_LIST_DCN10(_MASK) +}; + +static const struct dce_abm_registers abm_regs = { + ABM_DCN20_REG_LIST() +}; + +static const struct dce_abm_shift abm_shift = { + ABM_MASK_SH_LIST_DCN20(__SHIFT) +}; + +static const struct dce_abm_mask abm_mask = { + ABM_MASK_SH_LIST_DCN20(_MASK) +}; + +#define audio_regs(id)\ +[id] = {\ + AUD_COMMON_REG_LIST(id)\ +} + +static const struct dce_audio_registers audio_regs[] = { + audio_regs(0), + audio_regs(1), + audio_regs(2), + audio_regs(3), + audio_regs(4), + audio_regs(5), + audio_regs(6), +}; + +#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ + AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) + +static const struct dce_audio_shift audio_shift = { + DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_audio_mask audio_mask = { + DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) +}; + +#define stream_enc_regs(id)\ +[id] = {\ + SE_DCN2_REG_LIST(id)\ +} + +static const struct dcn10_stream_enc_registers stream_enc_regs[] = { + stream_enc_regs(0), + stream_enc_regs(1), + stream_enc_regs(2), + stream_enc_regs(3), + stream_enc_regs(4), + stream_enc_regs(5), +}; + +static const struct dcn10_stream_encoder_shift se_shift = { + SE_COMMON_MASK_SH_LIST_DCN20(__SHIFT) +}; + +static const struct dcn10_stream_encoder_mask se_mask = { + SE_COMMON_MASK_SH_LIST_DCN20(_MASK) +}; + + +#define aux_regs(id)\ +[id] = {\ + DCN2_AUX_REG_LIST(id)\ +} + +static const struct dcn10_link_enc_aux_registers link_enc_aux_regs[] = { + aux_regs(0), + aux_regs(1), + aux_regs(2), + aux_regs(3), + aux_regs(4), + aux_regs(5) +}; + +#define hpd_regs(id)\ +[id] = {\ + HPD_REG_LIST(id)\ +} + +static const struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[] = { + hpd_regs(0), + hpd_regs(1), + hpd_regs(2), + hpd_regs(3), + hpd_regs(4), + hpd_regs(5) +}; + +#define link_regs(id, phyid)\ +[id] = {\ + LE_DCN10_REG_LIST(id), \ + UNIPHY_DCN2_REG_LIST(phyid), \ + DPCS_DCN2_REG_LIST(id), \ + SRI(DP_DPHY_INTERNAL_CTRL, DP, id) \ +} + +static const struct dcn10_link_enc_registers link_enc_regs[] = { + link_regs(0, A), + link_regs(1, B), + link_regs(2, C), + link_regs(3, D), + link_regs(4, E), + link_regs(5, F) +}; + +static const struct dcn10_link_enc_shift le_shift = { + LINK_ENCODER_MASK_SH_LIST_DCN20(__SHIFT),\ + DPCS_DCN2_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn10_link_enc_mask le_mask = { + LINK_ENCODER_MASK_SH_LIST_DCN20(_MASK),\ + DPCS_DCN2_MASK_SH_LIST(_MASK) +}; + +static const struct dce_panel_cntl_registers panel_cntl_regs[] = { + { DCN_PANEL_CNTL_REG_LIST() } +}; + +static const struct dce_panel_cntl_shift panel_cntl_shift = { + DCE_PANEL_CNTL_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_panel_cntl_mask panel_cntl_mask = { + DCE_PANEL_CNTL_MASK_SH_LIST(_MASK) +}; + +#define ipp_regs(id)\ +[id] = {\ + IPP_REG_LIST_DCN20(id),\ +} + +static const struct dcn10_ipp_registers ipp_regs[] = { + ipp_regs(0), + ipp_regs(1), + ipp_regs(2), + ipp_regs(3), + ipp_regs(4), + ipp_regs(5), +}; + +static const struct dcn10_ipp_shift ipp_shift = { + IPP_MASK_SH_LIST_DCN20(__SHIFT) +}; + +static const struct dcn10_ipp_mask ipp_mask = { + IPP_MASK_SH_LIST_DCN20(_MASK), +}; + +#define opp_regs(id)\ +[id] = {\ + OPP_REG_LIST_DCN20(id),\ +} + +static const struct dcn20_opp_registers opp_regs[] = { + opp_regs(0), + opp_regs(1), + opp_regs(2), + opp_regs(3), + opp_regs(4), + opp_regs(5), +}; + +static const struct dcn20_opp_shift opp_shift = { + OPP_MASK_SH_LIST_DCN20(__SHIFT) +}; + +static const struct dcn20_opp_mask opp_mask = { + OPP_MASK_SH_LIST_DCN20(_MASK) +}; + +#define aux_engine_regs(id)\ +[id] = {\ + AUX_COMMON_REG_LIST0(id), \ + .AUXN_IMPCAL = 0, \ + .AUXP_IMPCAL = 0, \ + .AUX_RESET_MASK = DP_AUX0_AUX_CONTROL__AUX_RESET_MASK, \ +} + +static const struct dce110_aux_registers aux_engine_regs[] = { + aux_engine_regs(0), + aux_engine_regs(1), + aux_engine_regs(2), + aux_engine_regs(3), + aux_engine_regs(4), + aux_engine_regs(5) +}; + +#define tf_regs(id)\ +[id] = {\ + TF_REG_LIST_DCN20(id),\ + TF_REG_LIST_DCN20_COMMON_APPEND(id),\ +} + +static const struct dcn2_dpp_registers tf_regs[] = { + tf_regs(0), + tf_regs(1), + tf_regs(2), + tf_regs(3), + tf_regs(4), + tf_regs(5), +}; + +static const struct dcn2_dpp_shift tf_shift = { + TF_REG_LIST_SH_MASK_DCN20(__SHIFT), + TF_DEBUG_REG_LIST_SH_DCN20 +}; + +static const struct dcn2_dpp_mask tf_mask = { + TF_REG_LIST_SH_MASK_DCN20(_MASK), + TF_DEBUG_REG_LIST_MASK_DCN20 +}; + +#define dwbc_regs_dcn2(id)\ +[id] = {\ + DWBC_COMMON_REG_LIST_DCN2_0(id),\ + } + +static const struct dcn20_dwbc_registers dwbc20_regs[] = { + dwbc_regs_dcn2(0), +}; + +static const struct dcn20_dwbc_shift dwbc20_shift = { + DWBC_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) +}; + +static const struct dcn20_dwbc_mask dwbc20_mask = { + DWBC_COMMON_MASK_SH_LIST_DCN2_0(_MASK) +}; + +#define mcif_wb_regs_dcn2(id)\ +[id] = {\ + MCIF_WB_COMMON_REG_LIST_DCN2_0(id),\ + } + +static const struct dcn20_mmhubbub_registers mcif_wb20_regs[] = { + mcif_wb_regs_dcn2(0), +}; + +static const struct dcn20_mmhubbub_shift mcif_wb20_shift = { + MCIF_WB_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) +}; + +static const struct dcn20_mmhubbub_mask mcif_wb20_mask = { + MCIF_WB_COMMON_MASK_SH_LIST_DCN2_0(_MASK) +}; + +static const struct dcn20_mpc_registers mpc_regs = { + MPC_REG_LIST_DCN2_0(0), + MPC_REG_LIST_DCN2_0(1), + MPC_REG_LIST_DCN2_0(2), + MPC_REG_LIST_DCN2_0(3), + MPC_REG_LIST_DCN2_0(4), + MPC_REG_LIST_DCN2_0(5), + MPC_OUT_MUX_REG_LIST_DCN2_0(0), + MPC_OUT_MUX_REG_LIST_DCN2_0(1), + MPC_OUT_MUX_REG_LIST_DCN2_0(2), + MPC_OUT_MUX_REG_LIST_DCN2_0(3), + MPC_OUT_MUX_REG_LIST_DCN2_0(4), + MPC_OUT_MUX_REG_LIST_DCN2_0(5), + MPC_DBG_REG_LIST_DCN2_0() +}; + +static const struct dcn20_mpc_shift mpc_shift = { + MPC_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT), + MPC_DEBUG_REG_LIST_SH_DCN20 +}; + +static const struct dcn20_mpc_mask mpc_mask = { + MPC_COMMON_MASK_SH_LIST_DCN2_0(_MASK), + MPC_DEBUG_REG_LIST_MASK_DCN20 +}; + +#define tg_regs(id)\ +[id] = {TG_COMMON_REG_LIST_DCN2_0(id)} + + +static const struct dcn_optc_registers tg_regs[] = { + tg_regs(0), + tg_regs(1), + tg_regs(2), + tg_regs(3), + tg_regs(4), + tg_regs(5) +}; + +static const struct dcn_optc_shift tg_shift = { + TG_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) +}; + +static const struct dcn_optc_mask tg_mask = { + TG_COMMON_MASK_SH_LIST_DCN2_0(_MASK) +}; + +#define hubp_regs(id)\ +[id] = {\ + HUBP_REG_LIST_DCN20(id)\ +} + +static const struct dcn_hubp2_registers hubp_regs[] = { + hubp_regs(0), + hubp_regs(1), + hubp_regs(2), + hubp_regs(3), + hubp_regs(4), + hubp_regs(5) +}; + +static const struct dcn_hubp2_shift hubp_shift = { + HUBP_MASK_SH_LIST_DCN20(__SHIFT) +}; + +static const struct dcn_hubp2_mask hubp_mask = { + HUBP_MASK_SH_LIST_DCN20(_MASK) +}; + +static const struct dcn_hubbub_registers hubbub_reg = { + HUBBUB_REG_LIST_DCN20(0) +}; + +static const struct dcn_hubbub_shift hubbub_shift = { + HUBBUB_MASK_SH_LIST_DCN20(__SHIFT) +}; + +static const struct dcn_hubbub_mask hubbub_mask = { + HUBBUB_MASK_SH_LIST_DCN20(_MASK) +}; + +#define vmid_regs(id)\ +[id] = {\ + DCN20_VMID_REG_LIST(id)\ +} + +static const struct dcn_vmid_registers vmid_regs[] = { + vmid_regs(0), + vmid_regs(1), + vmid_regs(2), + vmid_regs(3), + vmid_regs(4), + vmid_regs(5), + vmid_regs(6), + vmid_regs(7), + vmid_regs(8), + vmid_regs(9), + vmid_regs(10), + vmid_regs(11), + vmid_regs(12), + vmid_regs(13), + vmid_regs(14), + vmid_regs(15) +}; + +static const struct dcn20_vmid_shift vmid_shifts = { + DCN20_VMID_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn20_vmid_mask vmid_masks = { + DCN20_VMID_MASK_SH_LIST(_MASK) +}; + +static const struct dce110_aux_registers_shift aux_shift = { + DCN_AUX_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce110_aux_registers_mask aux_mask = { + DCN_AUX_MASK_SH_LIST(_MASK) +}; + +static int map_transmitter_id_to_phy_instance( + enum transmitter transmitter) +{ + switch (transmitter) { + case TRANSMITTER_UNIPHY_A: + return 0; + break; + case TRANSMITTER_UNIPHY_B: + return 1; + break; + case TRANSMITTER_UNIPHY_C: + return 2; + break; + case TRANSMITTER_UNIPHY_D: + return 3; + break; + case TRANSMITTER_UNIPHY_E: + return 4; + break; + case TRANSMITTER_UNIPHY_F: + return 5; + break; + default: + ASSERT(0); + return 0; + } +} + +#define dsc_regsDCN20(id)\ +[id] = {\ + DSC_REG_LIST_DCN20(id)\ +} + +static const struct dcn20_dsc_registers dsc_regs[] = { + dsc_regsDCN20(0), + dsc_regsDCN20(1), + dsc_regsDCN20(2), + dsc_regsDCN20(3), + dsc_regsDCN20(4), + dsc_regsDCN20(5) +}; + +static const struct dcn20_dsc_shift dsc_shift = { + DSC_REG_LIST_SH_MASK_DCN20(__SHIFT) +}; + +static const struct dcn20_dsc_mask dsc_mask = { + DSC_REG_LIST_SH_MASK_DCN20(_MASK) +}; + +static const struct dccg_registers dccg_regs = { + DCCG_REG_LIST_DCN2() +}; + +static const struct dccg_shift dccg_shift = { + DCCG_MASK_SH_LIST_DCN2(__SHIFT) +}; + +static const struct dccg_mask dccg_mask = { + DCCG_MASK_SH_LIST_DCN2(_MASK) +}; + +static const struct resource_caps res_cap_nv10 = { + .num_timing_generator = 6, + .num_opp = 6, + .num_video_plane = 6, + .num_audio = 7, + .num_stream_encoder = 6, + .num_pll = 6, + .num_dwb = 1, + .num_ddc = 6, + .num_vmid = 16, + .num_dsc = 6, +}; + +static const struct dc_plane_cap plane_cap = { + .type = DC_PLANE_TYPE_DCN_UNIVERSAL, + .per_pixel_alpha = true, + + .pixel_format_support = { + .argb8888 = true, + .nv12 = true, + .fp16 = true, + .p010 = true + }, + + .max_upscale_factor = { + .argb8888 = 16000, + .nv12 = 16000, + .fp16 = 1 + }, + + .max_downscale_factor = { + .argb8888 = 250, + .nv12 = 250, + .fp16 = 1 + }, + 16, + 16 +}; +static const struct resource_caps res_cap_nv14 = { + .num_timing_generator = 5, + .num_opp = 5, + .num_video_plane = 5, + .num_audio = 6, + .num_stream_encoder = 5, + .num_pll = 5, + .num_dwb = 1, + .num_ddc = 5, + .num_vmid = 16, + .num_dsc = 5, +}; + +static const struct dc_debug_options debug_defaults_drv = { + .disable_dmcu = false, + .force_abm_enable = false, + .timing_trace = false, + .clock_trace = true, + .disable_pplib_clock_request = true, + .pipe_split_policy = MPC_SPLIT_AVOID_MULT_DISP, + .force_single_disp_pipe_split = false, + .disable_dcc = DCC_ENABLE, + .vsr_support = true, + .performance_trace = false, + .max_downscale_src_width = 5120,/*upto 5K*/ + .disable_pplib_wm_range = false, + .scl_reset_length10 = true, + .sanity_checks = false, + .underflow_assert_delay_us = 0xFFFFFFFF, + .enable_legacy_fast_update = true, + .using_dml2 = false, +}; + +void dcn20_dpp_destroy(struct dpp **dpp) +{ + kfree(TO_DCN20_DPP(*dpp)); + *dpp = NULL; +} + +struct dpp *dcn20_dpp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn20_dpp *dpp = + kzalloc(sizeof(struct dcn20_dpp), GFP_ATOMIC); + + if (!dpp) + return NULL; + + if (dpp2_construct(dpp, ctx, inst, + &tf_regs[inst], &tf_shift, &tf_mask)) + return &dpp->base; + + BREAK_TO_DEBUGGER(); + kfree(dpp); + return NULL; +} + +struct input_pixel_processor *dcn20_ipp_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dcn10_ipp *ipp = + kzalloc(sizeof(struct dcn10_ipp), GFP_ATOMIC); + + if (!ipp) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dcn20_ipp_construct(ipp, ctx, inst, + &ipp_regs[inst], &ipp_shift, &ipp_mask); + return &ipp->base; +} + + +struct output_pixel_processor *dcn20_opp_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dcn20_opp *opp = + kzalloc(sizeof(struct dcn20_opp), GFP_ATOMIC); + + if (!opp) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dcn20_opp_construct(opp, ctx, inst, + &opp_regs[inst], &opp_shift, &opp_mask); + return &opp->base; +} + +struct dce_aux *dcn20_aux_engine_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct aux_engine_dce110 *aux_engine = + kzalloc(sizeof(struct aux_engine_dce110), GFP_ATOMIC); + + if (!aux_engine) + return NULL; + + dce110_aux_engine_construct(aux_engine, ctx, inst, + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, + &aux_engine_regs[inst], + &aux_mask, + &aux_shift, + ctx->dc->caps.extended_aux_timeout_support); + + return &aux_engine->base; +} +#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST(id) } + +static const struct dce_i2c_registers i2c_hw_regs[] = { + i2c_inst_regs(1), + i2c_inst_regs(2), + i2c_inst_regs(3), + i2c_inst_regs(4), + i2c_inst_regs(5), + i2c_inst_regs(6), +}; + +static const struct dce_i2c_shift i2c_shifts = { + I2C_COMMON_MASK_SH_LIST_DCN2(__SHIFT) +}; + +static const struct dce_i2c_mask i2c_masks = { + I2C_COMMON_MASK_SH_LIST_DCN2(_MASK) +}; + +struct dce_i2c_hw *dcn20_i2c_hw_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce_i2c_hw *dce_i2c_hw = + kzalloc(sizeof(struct dce_i2c_hw), GFP_ATOMIC); + + if (!dce_i2c_hw) + return NULL; + + dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst, + &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); + + return dce_i2c_hw; +} +struct mpc *dcn20_mpc_create(struct dc_context *ctx) +{ + struct dcn20_mpc *mpc20 = kzalloc(sizeof(struct dcn20_mpc), + GFP_ATOMIC); + + if (!mpc20) + return NULL; + + dcn20_mpc_construct(mpc20, ctx, + &mpc_regs, + &mpc_shift, + &mpc_mask, + 6); + + return &mpc20->base; +} + +struct hubbub *dcn20_hubbub_create(struct dc_context *ctx) +{ + int i; + struct dcn20_hubbub *hubbub = kzalloc(sizeof(struct dcn20_hubbub), + GFP_ATOMIC); + + if (!hubbub) + return NULL; + + hubbub2_construct(hubbub, ctx, + &hubbub_reg, + &hubbub_shift, + &hubbub_mask); + + for (i = 0; i < res_cap_nv10.num_vmid; i++) { + struct dcn20_vmid *vmid = &hubbub->vmid[i]; + + vmid->ctx = ctx; + + vmid->regs = &vmid_regs[i]; + vmid->shifts = &vmid_shifts; + vmid->masks = &vmid_masks; + } + + return &hubbub->base; +} + +struct timing_generator *dcn20_timing_generator_create( + struct dc_context *ctx, + uint32_t instance) +{ + struct optc *tgn10 = + kzalloc(sizeof(struct optc), GFP_ATOMIC); + + if (!tgn10) + return NULL; + + tgn10->base.inst = instance; + tgn10->base.ctx = ctx; + + tgn10->tg_regs = &tg_regs[instance]; + tgn10->tg_shift = &tg_shift; + tgn10->tg_mask = &tg_mask; + + dcn20_timing_generator_init(tgn10); + + return &tgn10->base; +} + +static const struct encoder_feature_support link_enc_feature = { + .max_hdmi_deep_color = COLOR_DEPTH_121212, + .max_hdmi_pixel_clock = 600000, + .hdmi_ycbcr420_supported = true, + .dp_ycbcr420_supported = true, + .fec_supported = true, + .flags.bits.IS_HBR2_CAPABLE = true, + .flags.bits.IS_HBR3_CAPABLE = true, + .flags.bits.IS_TPS3_CAPABLE = true, + .flags.bits.IS_TPS4_CAPABLE = true +}; + +struct link_encoder *dcn20_link_encoder_create( + struct dc_context *ctx, + const struct encoder_init_data *enc_init_data) +{ + struct dcn20_link_encoder *enc20 = + kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); + int link_regs_id; + + if (!enc20) + return NULL; + + link_regs_id = + map_transmitter_id_to_phy_instance(enc_init_data->transmitter); + + dcn20_link_encoder_construct(enc20, + enc_init_data, + &link_enc_feature, + &link_enc_regs[link_regs_id], + &link_enc_aux_regs[enc_init_data->channel - 1], + &link_enc_hpd_regs[enc_init_data->hpd_source], + &le_shift, + &le_mask); + + return &enc20->enc10.base; +} + +static struct panel_cntl *dcn20_panel_cntl_create(const struct panel_cntl_init_data *init_data) +{ + struct dce_panel_cntl *panel_cntl = + kzalloc(sizeof(struct dce_panel_cntl), GFP_KERNEL); + + if (!panel_cntl) + return NULL; + + dce_panel_cntl_construct(panel_cntl, + init_data, + &panel_cntl_regs[init_data->inst], + &panel_cntl_shift, + &panel_cntl_mask); + + return &panel_cntl->base; +} + +static struct clock_source *dcn20_clock_source_create( + struct dc_context *ctx, + struct dc_bios *bios, + enum clock_source_id id, + const struct dce110_clk_src_regs *regs, + bool dp_clk_src) +{ + struct dce110_clk_src *clk_src = + kzalloc(sizeof(struct dce110_clk_src), GFP_ATOMIC); + + if (!clk_src) + return NULL; + + if (dcn20_clk_src_construct(clk_src, ctx, bios, id, + regs, &cs_shift, &cs_mask)) { + clk_src->base.dp_clk_src = dp_clk_src; + return &clk_src->base; + } + + kfree(clk_src); + BREAK_TO_DEBUGGER(); + return NULL; +} + +static void read_dce_straps( + struct dc_context *ctx, + struct resource_straps *straps) +{ + generic_reg_get(ctx, mmDC_PINSTRAPS + BASE(mmDC_PINSTRAPS_BASE_IDX), + FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio); +} + +static struct audio *dcn20_create_audio( + struct dc_context *ctx, unsigned int inst) +{ + return dce_audio_create(ctx, inst, + &audio_regs[inst], &audio_shift, &audio_mask); +} + +struct stream_encoder *dcn20_stream_encoder_create( + enum engine_id eng_id, + struct dc_context *ctx) +{ + struct dcn10_stream_encoder *enc1 = + kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL); + + if (!enc1) + return NULL; + + if (ASICREV_IS_NAVI14_M(ctx->asic_id.hw_internal_rev)) { + if (eng_id >= ENGINE_ID_DIGD) + eng_id++; + } + + dcn20_stream_encoder_construct(enc1, ctx, ctx->dc_bios, eng_id, + &stream_enc_regs[eng_id], + &se_shift, &se_mask); + + return &enc1->base; +} + +static const struct dce_hwseq_registers hwseq_reg = { + HWSEQ_DCN2_REG_LIST() +}; + +static const struct dce_hwseq_shift hwseq_shift = { + HWSEQ_DCN2_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_hwseq_mask hwseq_mask = { + HWSEQ_DCN2_MASK_SH_LIST(_MASK) +}; + +struct dce_hwseq *dcn20_hwseq_create( + struct dc_context *ctx) +{ + struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); + + if (hws) { + hws->ctx = ctx; + hws->regs = &hwseq_reg; + hws->shifts = &hwseq_shift; + hws->masks = &hwseq_mask; + } + return hws; +} + +static const struct resource_create_funcs res_create_funcs = { + .read_dce_straps = read_dce_straps, + .create_audio = dcn20_create_audio, + .create_stream_encoder = dcn20_stream_encoder_create, + .create_hwseq = dcn20_hwseq_create, +}; + +static void dcn20_pp_smu_destroy(struct pp_smu_funcs **pp_smu); + +void dcn20_clock_source_destroy(struct clock_source **clk_src) +{ + kfree(TO_DCE110_CLK_SRC(*clk_src)); + *clk_src = NULL; +} + + +struct display_stream_compressor *dcn20_dsc_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dcn20_dsc *dsc = + kzalloc(sizeof(struct dcn20_dsc), GFP_ATOMIC); + + if (!dsc) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dsc2_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask); + return &dsc->base; +} + +void dcn20_dsc_destroy(struct display_stream_compressor **dsc) +{ + kfree(container_of(*dsc, struct dcn20_dsc, base)); + *dsc = NULL; +} + + +static void dcn20_resource_destruct(struct dcn20_resource_pool *pool) +{ + unsigned int i; + + for (i = 0; i < pool->base.stream_enc_count; i++) { + if (pool->base.stream_enc[i] != NULL) { + kfree(DCN10STRENC_FROM_STRENC(pool->base.stream_enc[i])); + pool->base.stream_enc[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_dsc; i++) { + if (pool->base.dscs[i] != NULL) + dcn20_dsc_destroy(&pool->base.dscs[i]); + } + + if (pool->base.mpc != NULL) { + kfree(TO_DCN20_MPC(pool->base.mpc)); + pool->base.mpc = NULL; + } + if (pool->base.hubbub != NULL) { + kfree(pool->base.hubbub); + pool->base.hubbub = NULL; + } + for (i = 0; i < pool->base.pipe_count; i++) { + if (pool->base.dpps[i] != NULL) + dcn20_dpp_destroy(&pool->base.dpps[i]); + + if (pool->base.ipps[i] != NULL) + pool->base.ipps[i]->funcs->ipp_destroy(&pool->base.ipps[i]); + + if (pool->base.hubps[i] != NULL) { + kfree(TO_DCN20_HUBP(pool->base.hubps[i])); + pool->base.hubps[i] = NULL; + } + + if (pool->base.irqs != NULL) { + dal_irq_service_destroy(&pool->base.irqs); + } + } + + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + if (pool->base.engines[i] != NULL) + dce110_engine_destroy(&pool->base.engines[i]); + if (pool->base.hw_i2cs[i] != NULL) { + kfree(pool->base.hw_i2cs[i]); + pool->base.hw_i2cs[i] = NULL; + } + if (pool->base.sw_i2cs[i] != NULL) { + kfree(pool->base.sw_i2cs[i]); + pool->base.sw_i2cs[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_opp; i++) { + if (pool->base.opps[i] != NULL) + pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]); + } + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + if (pool->base.timing_generators[i] != NULL) { + kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i])); + pool->base.timing_generators[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_dwb; i++) { + if (pool->base.dwbc[i] != NULL) { + kfree(TO_DCN20_DWBC(pool->base.dwbc[i])); + pool->base.dwbc[i] = NULL; + } + if (pool->base.mcif_wb[i] != NULL) { + kfree(TO_DCN20_MMHUBBUB(pool->base.mcif_wb[i])); + pool->base.mcif_wb[i] = NULL; + } + } + + for (i = 0; i < pool->base.audio_count; i++) { + if (pool->base.audios[i]) + dce_aud_destroy(&pool->base.audios[i]); + } + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] != NULL) { + dcn20_clock_source_destroy(&pool->base.clock_sources[i]); + pool->base.clock_sources[i] = NULL; + } + } + + if (pool->base.dp_clock_source != NULL) { + dcn20_clock_source_destroy(&pool->base.dp_clock_source); + pool->base.dp_clock_source = NULL; + } + + + if (pool->base.abm != NULL) + dce_abm_destroy(&pool->base.abm); + + if (pool->base.dmcu != NULL) + dce_dmcu_destroy(&pool->base.dmcu); + + if (pool->base.dccg != NULL) + dcn_dccg_destroy(&pool->base.dccg); + + if (pool->base.pp_smu != NULL) + dcn20_pp_smu_destroy(&pool->base.pp_smu); + + if (pool->base.oem_device != NULL) { + struct dc *dc = pool->base.oem_device->ctx->dc; + + dc->link_srv->destroy_ddc_service(&pool->base.oem_device); + } +} + +struct hubp *dcn20_hubp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn20_hubp *hubp2 = + kzalloc(sizeof(struct dcn20_hubp), GFP_ATOMIC); + + if (!hubp2) + return NULL; + + if (hubp2_construct(hubp2, ctx, inst, + &hubp_regs[inst], &hubp_shift, &hubp_mask)) + return &hubp2->base; + + BREAK_TO_DEBUGGER(); + kfree(hubp2); + return NULL; +} + +static void get_pixel_clock_parameters( + struct pipe_ctx *pipe_ctx, + struct pixel_clk_params *pixel_clk_params) +{ + const struct dc_stream_state *stream = pipe_ctx->stream; + struct pipe_ctx *odm_pipe; + int opp_cnt = 1; + struct dc_link *link = stream->link; + struct link_encoder *link_enc = NULL; + struct dc *dc = pipe_ctx->stream->ctx->dc; + struct dce_hwseq *hws = dc->hwseq; + + for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) + opp_cnt++; + + pixel_clk_params->requested_pix_clk_100hz = stream->timing.pix_clk_100hz; + + link_enc = link_enc_cfg_get_link_enc(link); + if (link_enc) + pixel_clk_params->encoder_object_id = link_enc->id; + + pixel_clk_params->signal_type = pipe_ctx->stream->signal; + pixel_clk_params->controller_id = pipe_ctx->stream_res.tg->inst + 1; + /* TODO: un-hardcode*/ + /* TODO - DP2.0 HW: calculate requested_sym_clk for UHBR rates */ + pixel_clk_params->requested_sym_clk = LINK_RATE_LOW * + LINK_RATE_REF_FREQ_IN_KHZ; + pixel_clk_params->flags.ENABLE_SS = 0; + pixel_clk_params->color_depth = + stream->timing.display_color_depth; + pixel_clk_params->flags.DISPLAY_BLANKED = 1; + pixel_clk_params->pixel_encoding = stream->timing.pixel_encoding; + + if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR422) + pixel_clk_params->color_depth = COLOR_DEPTH_888; + + if (opp_cnt == 4) + pixel_clk_params->requested_pix_clk_100hz /= 4; + else if (optc2_is_two_pixels_per_containter(&stream->timing) || opp_cnt == 2) + pixel_clk_params->requested_pix_clk_100hz /= 2; + else if (hws->funcs.is_dp_dig_pixel_rate_div_policy) { + if (hws->funcs.is_dp_dig_pixel_rate_div_policy(pipe_ctx)) + pixel_clk_params->requested_pix_clk_100hz /= 2; + } + + if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING) + pixel_clk_params->requested_pix_clk_100hz *= 2; + +} + +static void build_clamping_params(struct dc_stream_state *stream) +{ + stream->clamping.clamping_level = CLAMPING_FULL_RANGE; + stream->clamping.c_depth = stream->timing.display_color_depth; + stream->clamping.pixel_encoding = stream->timing.pixel_encoding; +} + +void dcn20_build_pipe_pix_clk_params(struct pipe_ctx *pipe_ctx) +{ + get_pixel_clock_parameters(pipe_ctx, &pipe_ctx->stream_res.pix_clk_params); + pipe_ctx->clock_source->funcs->get_pix_clk_dividers( + pipe_ctx->clock_source, + &pipe_ctx->stream_res.pix_clk_params, + &pipe_ctx->pll_settings); +} + +static enum dc_status build_pipe_hw_param(struct pipe_ctx *pipe_ctx) +{ + + dcn20_build_pipe_pix_clk_params(pipe_ctx); + + pipe_ctx->stream->clamping.pixel_encoding = pipe_ctx->stream->timing.pixel_encoding; + + resource_build_bit_depth_reduction_params(pipe_ctx->stream, + &pipe_ctx->stream->bit_depth_params); + build_clamping_params(pipe_ctx->stream); + + return DC_OK; +} + +enum dc_status dcn20_build_mapped_resource(const struct dc *dc, struct dc_state *context, struct dc_stream_state *stream) +{ + enum dc_status status = DC_OK; + struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream); + + if (!pipe_ctx) + return DC_ERROR_UNEXPECTED; + + + status = build_pipe_hw_param(pipe_ctx); + + return status; +} + + +void dcn20_acquire_dsc(const struct dc *dc, + struct resource_context *res_ctx, + struct display_stream_compressor **dsc, + int pipe_idx) +{ + int i; + const struct resource_pool *pool = dc->res_pool; + struct display_stream_compressor *dsc_old = dc->current_state->res_ctx.pipe_ctx[pipe_idx].stream_res.dsc; + + ASSERT(*dsc == NULL); /* If this ASSERT fails, dsc was not released properly */ + *dsc = NULL; + + /* Always do 1-to-1 mapping when number of DSCs is same as number of pipes */ + if (pool->res_cap->num_dsc == pool->res_cap->num_opp) { + *dsc = pool->dscs[pipe_idx]; + res_ctx->is_dsc_acquired[pipe_idx] = true; + return; + } + + /* Return old DSC to avoid the need for re-programming */ + if (dsc_old && !res_ctx->is_dsc_acquired[dsc_old->inst]) { + *dsc = dsc_old; + res_ctx->is_dsc_acquired[dsc_old->inst] = true; + return ; + } + + /* Find first free DSC */ + for (i = 0; i < pool->res_cap->num_dsc; i++) + if (!res_ctx->is_dsc_acquired[i]) { + *dsc = pool->dscs[i]; + res_ctx->is_dsc_acquired[i] = true; + break; + } +} + +void dcn20_release_dsc(struct resource_context *res_ctx, + const struct resource_pool *pool, + struct display_stream_compressor **dsc) +{ + int i; + + for (i = 0; i < pool->res_cap->num_dsc; i++) + if (pool->dscs[i] == *dsc) { + res_ctx->is_dsc_acquired[i] = false; + *dsc = NULL; + break; + } +} + + + +enum dc_status dcn20_add_dsc_to_stream_resource(struct dc *dc, + struct dc_state *dc_ctx, + struct dc_stream_state *dc_stream) +{ + enum dc_status result = DC_OK; + int i; + + /* Get a DSC if required and available */ + 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; + + if (pipe_ctx->stream_res.dsc) + continue; + + dcn20_acquire_dsc(dc, &dc_ctx->res_ctx, &pipe_ctx->stream_res.dsc, i); + + /* The number of DSCs can be less than the number of pipes */ + if (!pipe_ctx->stream_res.dsc) { + result = DC_NO_DSC_RESOURCE; + } + + break; + } + + return result; +} + + +static enum dc_status remove_dsc_from_stream_resource(struct dc *dc, + struct dc_state *new_ctx, + struct dc_stream_state *dc_stream) +{ + struct pipe_ctx *pipe_ctx = NULL; + int i; + + for (i = 0; i < MAX_PIPES; i++) { + if (new_ctx->res_ctx.pipe_ctx[i].stream == dc_stream && !new_ctx->res_ctx.pipe_ctx[i].top_pipe) { + pipe_ctx = &new_ctx->res_ctx.pipe_ctx[i]; + + if (pipe_ctx->stream_res.dsc) + dcn20_release_dsc(&new_ctx->res_ctx, dc->res_pool, &pipe_ctx->stream_res.dsc); + } + } + + if (!pipe_ctx) + return DC_ERROR_UNEXPECTED; + else + return DC_OK; +} + + +enum dc_status dcn20_add_stream_to_ctx(struct dc *dc, struct dc_state *new_ctx, struct dc_stream_state *dc_stream) +{ + enum dc_status result = DC_ERROR_UNEXPECTED; + + result = resource_map_pool_resources(dc, new_ctx, dc_stream); + + if (result == DC_OK) + result = resource_map_phy_clock_resources(dc, new_ctx, dc_stream); + + /* Get a DSC if required and available */ + if (result == DC_OK && dc_stream->timing.flags.DSC) + result = dcn20_add_dsc_to_stream_resource(dc, new_ctx, dc_stream); + + if (result == DC_OK) + result = dcn20_build_mapped_resource(dc, new_ctx, dc_stream); + + return result; +} + + +enum dc_status dcn20_remove_stream_from_ctx(struct dc *dc, struct dc_state *new_ctx, struct dc_stream_state *dc_stream) +{ + enum dc_status result = DC_OK; + + result = remove_dsc_from_stream_resource(dc, new_ctx, dc_stream); + + return result; +} + +/** + * dcn20_split_stream_for_odm - Check if stream can be splited for ODM + * + * @dc: DC object with resource pool info required for pipe split + * @res_ctx: Persistent state of resources + * @prev_odm_pipe: Reference to the previous ODM pipe + * @next_odm_pipe: Reference to the next ODM pipe + * + * This function takes a logically active pipe and a logically free pipe and + * halves all the scaling parameters that need to be halved while populating + * the free pipe with the required resources and configuring the next/previous + * ODM pipe pointers. + * + * Return: + * Return true if split stream for ODM is possible, otherwise, return false. + */ +bool dcn20_split_stream_for_odm( + const struct dc *dc, + struct resource_context *res_ctx, + struct pipe_ctx *prev_odm_pipe, + struct pipe_ctx *next_odm_pipe) +{ + int pipe_idx = next_odm_pipe->pipe_idx; + const struct resource_pool *pool = dc->res_pool; + + *next_odm_pipe = *prev_odm_pipe; + + next_odm_pipe->pipe_idx = pipe_idx; + next_odm_pipe->plane_res.mi = pool->mis[next_odm_pipe->pipe_idx]; + next_odm_pipe->plane_res.hubp = pool->hubps[next_odm_pipe->pipe_idx]; + next_odm_pipe->plane_res.ipp = pool->ipps[next_odm_pipe->pipe_idx]; + next_odm_pipe->plane_res.xfm = pool->transforms[next_odm_pipe->pipe_idx]; + next_odm_pipe->plane_res.dpp = pool->dpps[next_odm_pipe->pipe_idx]; + next_odm_pipe->plane_res.mpcc_inst = pool->dpps[next_odm_pipe->pipe_idx]->inst; + next_odm_pipe->stream_res.dsc = NULL; + if (prev_odm_pipe->next_odm_pipe && prev_odm_pipe->next_odm_pipe != next_odm_pipe) { + next_odm_pipe->next_odm_pipe = prev_odm_pipe->next_odm_pipe; + next_odm_pipe->next_odm_pipe->prev_odm_pipe = next_odm_pipe; + } + if (prev_odm_pipe->top_pipe && prev_odm_pipe->top_pipe->next_odm_pipe) { + prev_odm_pipe->top_pipe->next_odm_pipe->bottom_pipe = next_odm_pipe; + next_odm_pipe->top_pipe = prev_odm_pipe->top_pipe->next_odm_pipe; + } + if (prev_odm_pipe->bottom_pipe && prev_odm_pipe->bottom_pipe->next_odm_pipe) { + prev_odm_pipe->bottom_pipe->next_odm_pipe->top_pipe = next_odm_pipe; + next_odm_pipe->bottom_pipe = prev_odm_pipe->bottom_pipe->next_odm_pipe; + } + prev_odm_pipe->next_odm_pipe = next_odm_pipe; + next_odm_pipe->prev_odm_pipe = prev_odm_pipe; + + if (prev_odm_pipe->plane_state) { + struct scaler_data *sd = &prev_odm_pipe->plane_res.scl_data; + int new_width; + + /* HACTIVE halved for odm combine */ + sd->h_active /= 2; + /* Calculate new vp and recout for left pipe */ + /* Need at least 16 pixels width per side */ + if (sd->recout.x + 16 >= sd->h_active) + return false; + new_width = sd->h_active - sd->recout.x; + sd->viewport.width -= dc_fixpt_floor(dc_fixpt_mul_int( + sd->ratios.horz, sd->recout.width - new_width)); + sd->viewport_c.width -= dc_fixpt_floor(dc_fixpt_mul_int( + sd->ratios.horz_c, sd->recout.width - new_width)); + sd->recout.width = new_width; + + /* Calculate new vp and recout for right pipe */ + sd = &next_odm_pipe->plane_res.scl_data; + /* HACTIVE halved for odm combine */ + sd->h_active /= 2; + /* Need at least 16 pixels width per side */ + if (new_width <= 16) + return false; + new_width = sd->recout.width + sd->recout.x - sd->h_active; + sd->viewport.width -= dc_fixpt_floor(dc_fixpt_mul_int( + sd->ratios.horz, sd->recout.width - new_width)); + sd->viewport_c.width -= dc_fixpt_floor(dc_fixpt_mul_int( + sd->ratios.horz_c, sd->recout.width - new_width)); + sd->recout.width = new_width; + sd->viewport.x += dc_fixpt_floor(dc_fixpt_mul_int( + sd->ratios.horz, sd->h_active - sd->recout.x)); + sd->viewport_c.x += dc_fixpt_floor(dc_fixpt_mul_int( + sd->ratios.horz_c, sd->h_active - sd->recout.x)); + sd->recout.x = 0; + } + if (!next_odm_pipe->top_pipe) + next_odm_pipe->stream_res.opp = pool->opps[next_odm_pipe->pipe_idx]; + else + next_odm_pipe->stream_res.opp = next_odm_pipe->top_pipe->stream_res.opp; + if (next_odm_pipe->stream->timing.flags.DSC == 1 && !next_odm_pipe->top_pipe) { + dcn20_acquire_dsc(dc, res_ctx, &next_odm_pipe->stream_res.dsc, next_odm_pipe->pipe_idx); + ASSERT(next_odm_pipe->stream_res.dsc); + if (next_odm_pipe->stream_res.dsc == NULL) + return false; + } + + return true; +} + +void dcn20_split_stream_for_mpc( + struct resource_context *res_ctx, + const struct resource_pool *pool, + struct pipe_ctx *primary_pipe, + struct pipe_ctx *secondary_pipe) +{ + int pipe_idx = secondary_pipe->pipe_idx; + struct pipe_ctx *sec_bot_pipe = secondary_pipe->bottom_pipe; + + *secondary_pipe = *primary_pipe; + secondary_pipe->bottom_pipe = sec_bot_pipe; + + secondary_pipe->pipe_idx = pipe_idx; + secondary_pipe->plane_res.mi = pool->mis[secondary_pipe->pipe_idx]; + secondary_pipe->plane_res.hubp = pool->hubps[secondary_pipe->pipe_idx]; + secondary_pipe->plane_res.ipp = pool->ipps[secondary_pipe->pipe_idx]; + secondary_pipe->plane_res.xfm = pool->transforms[secondary_pipe->pipe_idx]; + secondary_pipe->plane_res.dpp = pool->dpps[secondary_pipe->pipe_idx]; + secondary_pipe->plane_res.mpcc_inst = pool->dpps[secondary_pipe->pipe_idx]->inst; + secondary_pipe->stream_res.dsc = NULL; + if (primary_pipe->bottom_pipe && primary_pipe->bottom_pipe != secondary_pipe) { + ASSERT(!secondary_pipe->bottom_pipe); + secondary_pipe->bottom_pipe = primary_pipe->bottom_pipe; + secondary_pipe->bottom_pipe->top_pipe = secondary_pipe; + } + primary_pipe->bottom_pipe = secondary_pipe; + secondary_pipe->top_pipe = primary_pipe; + + ASSERT(primary_pipe->plane_state); +} + +unsigned int dcn20_calc_max_scaled_time( + unsigned int time_per_pixel, + enum mmhubbub_wbif_mode mode, + unsigned int urgent_watermark) +{ + unsigned int time_per_byte = 0; + unsigned int total_y_free_entry = 0x200; /* two memory piece for luma */ + unsigned int total_c_free_entry = 0x140; /* two memory piece for chroma */ + unsigned int small_free_entry, max_free_entry; + unsigned int buf_lh_capability; + unsigned int max_scaled_time; + + if (mode == PACKED_444) /* packed mode */ + time_per_byte = time_per_pixel/4; + else if (mode == PLANAR_420_8BPC) + time_per_byte = time_per_pixel; + else if (mode == PLANAR_420_10BPC) /* p010 */ + time_per_byte = time_per_pixel * 819/1024; + + if (time_per_byte == 0) + time_per_byte = 1; + + small_free_entry = (total_y_free_entry > total_c_free_entry) ? total_c_free_entry : total_y_free_entry; + max_free_entry = (mode == PACKED_444) ? total_y_free_entry + total_c_free_entry : small_free_entry; + buf_lh_capability = max_free_entry*time_per_byte*32/16; /* there is 4bit fraction */ + max_scaled_time = buf_lh_capability - urgent_watermark; + return max_scaled_time; +} + +void dcn20_set_mcif_arb_params( + struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int pipe_cnt) +{ + enum mmhubbub_wbif_mode wbif_mode; + struct mcif_arb_params *wb_arb_params; + int i, j, dwb_pipe; + + /* Writeback MCIF_WB arbitration parameters */ + dwb_pipe = 0; + for (i = 0; i < dc->res_pool->pipe_count; i++) { + + if (!context->res_ctx.pipe_ctx[i].stream) + continue; + + for (j = 0; j < MAX_DWB_PIPES; j++) { + if (context->res_ctx.pipe_ctx[i].stream->writeback_info[j].wb_enabled == false) + continue; + + //wb_arb_params = &context->res_ctx.pipe_ctx[i].stream->writeback_info[j].mcif_arb_params; + wb_arb_params = &context->bw_ctx.bw.dcn.bw_writeback.mcif_wb_arb[dwb_pipe]; + + if (context->res_ctx.pipe_ctx[i].stream->writeback_info[j].dwb_params.out_format == dwb_scaler_mode_yuv420) { + if (context->res_ctx.pipe_ctx[i].stream->writeback_info[j].dwb_params.output_depth == DWB_OUTPUT_PIXEL_DEPTH_8BPC) + wbif_mode = PLANAR_420_8BPC; + else + wbif_mode = PLANAR_420_10BPC; + } else + wbif_mode = PACKED_444; + + DC_FP_START(); + dcn20_fpu_set_wb_arb_params(wb_arb_params, context, pipes, pipe_cnt, i); + DC_FP_END(); + + wb_arb_params->slice_lines = 32; + wb_arb_params->arbitration_slice = 2; + wb_arb_params->max_scaled_time = dcn20_calc_max_scaled_time(wb_arb_params->time_per_pixel, + wbif_mode, + wb_arb_params->cli_watermark[0]); /* assume 4 watermark sets have the same value */ + + dwb_pipe++; + + if (dwb_pipe >= MAX_DWB_PIPES) + return; + } + if (dwb_pipe >= MAX_DWB_PIPES) + return; + } +} + +bool dcn20_validate_dsc(struct dc *dc, struct dc_state *new_ctx) +{ + int i; + + /* Validate DSC config, dsc count validation is already done */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &new_ctx->res_ctx.pipe_ctx[i]; + struct dc_stream_state *stream = pipe_ctx->stream; + struct dsc_config dsc_cfg; + 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++; + + /* Only need to validate top pipe */ + if (pipe_ctx->top_pipe || pipe_ctx->prev_odm_pipe || !stream || !stream->timing.flags.DSC) + continue; + + 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; + dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt; + + if (!pipe_ctx->stream_res.dsc->funcs->dsc_validate_stream(pipe_ctx->stream_res.dsc, &dsc_cfg)) + return false; + } + return true; +} + +struct pipe_ctx *dcn20_find_secondary_pipe(struct dc *dc, + struct resource_context *res_ctx, + const struct resource_pool *pool, + const struct pipe_ctx *primary_pipe) +{ + struct pipe_ctx *secondary_pipe = NULL; + + if (dc && primary_pipe) { + int j; + int preferred_pipe_idx = 0; + + /* first check the prev dc state: + * if this primary pipe has a bottom pipe in prev. state + * and if the bottom pipe is still available (which it should be), + * pick that pipe as secondary + * Same logic applies for ODM pipes + */ + if (dc->current_state->res_ctx.pipe_ctx[primary_pipe->pipe_idx].next_odm_pipe) { + preferred_pipe_idx = dc->current_state->res_ctx.pipe_ctx[primary_pipe->pipe_idx].next_odm_pipe->pipe_idx; + if (res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) { + secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx]; + secondary_pipe->pipe_idx = preferred_pipe_idx; + } + } + if (secondary_pipe == NULL && + dc->current_state->res_ctx.pipe_ctx[primary_pipe->pipe_idx].bottom_pipe) { + preferred_pipe_idx = dc->current_state->res_ctx.pipe_ctx[primary_pipe->pipe_idx].bottom_pipe->pipe_idx; + if (res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) { + secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx]; + secondary_pipe->pipe_idx = preferred_pipe_idx; + } + } + + /* + * if this primary pipe does not have a bottom pipe in prev. state + * start backward and find a pipe that did not used to be a bottom pipe in + * prev. dc state. This way we make sure we keep the same assignment as + * last state and will not have to reprogram every pipe + */ + if (secondary_pipe == NULL) { + for (j = dc->res_pool->pipe_count - 1; j >= 0; j--) { + if (dc->current_state->res_ctx.pipe_ctx[j].top_pipe == NULL + && dc->current_state->res_ctx.pipe_ctx[j].prev_odm_pipe == NULL) { + preferred_pipe_idx = j; + + if (res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) { + secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx]; + secondary_pipe->pipe_idx = preferred_pipe_idx; + break; + } + } + } + } + /* + * We should never hit this assert unless assignments are shuffled around + * if this happens we will prob. hit a vsync tdr + */ + ASSERT(secondary_pipe); + /* + * search backwards for the second pipe to keep pipe + * assignment more consistent + */ + if (secondary_pipe == NULL) { + for (j = dc->res_pool->pipe_count - 1; j >= 0; j--) { + preferred_pipe_idx = j; + + if (res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) { + secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx]; + secondary_pipe->pipe_idx = preferred_pipe_idx; + break; + } + } + } + } + + return secondary_pipe; +} + +void dcn20_merge_pipes_for_validate( + struct dc *dc, + struct dc_state *context) +{ + int i; + + /* merge previously split odm pipes since mode support needs to make the decision */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + struct pipe_ctx *odm_pipe = pipe->next_odm_pipe; + + if (pipe->prev_odm_pipe) + continue; + + pipe->next_odm_pipe = NULL; + while (odm_pipe) { + struct pipe_ctx *next_odm_pipe = odm_pipe->next_odm_pipe; + + odm_pipe->plane_state = NULL; + odm_pipe->stream = NULL; + odm_pipe->top_pipe = NULL; + odm_pipe->bottom_pipe = NULL; + odm_pipe->prev_odm_pipe = NULL; + odm_pipe->next_odm_pipe = NULL; + if (odm_pipe->stream_res.dsc) + dcn20_release_dsc(&context->res_ctx, dc->res_pool, &odm_pipe->stream_res.dsc); + /* Clear plane_res and stream_res */ + memset(&odm_pipe->plane_res, 0, sizeof(odm_pipe->plane_res)); + memset(&odm_pipe->stream_res, 0, sizeof(odm_pipe->stream_res)); + odm_pipe = next_odm_pipe; + } + if (pipe->plane_state) + resource_build_scaling_params(pipe); + } + + /* merge previously mpc split pipes since mode support needs to make the decision */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + struct pipe_ctx *hsplit_pipe = pipe->bottom_pipe; + + if (!hsplit_pipe || hsplit_pipe->plane_state != pipe->plane_state) + continue; + + pipe->bottom_pipe = hsplit_pipe->bottom_pipe; + if (hsplit_pipe->bottom_pipe) + hsplit_pipe->bottom_pipe->top_pipe = pipe; + hsplit_pipe->plane_state = NULL; + hsplit_pipe->stream = NULL; + hsplit_pipe->top_pipe = NULL; + hsplit_pipe->bottom_pipe = NULL; + + /* Clear plane_res and stream_res */ + memset(&hsplit_pipe->plane_res, 0, sizeof(hsplit_pipe->plane_res)); + memset(&hsplit_pipe->stream_res, 0, sizeof(hsplit_pipe->stream_res)); + if (pipe->plane_state) + resource_build_scaling_params(pipe); + } +} + +int dcn20_validate_apply_pipe_split_flags( + struct dc *dc, + struct dc_state *context, + int vlevel, + int *split, + bool *merge) +{ + int i, pipe_idx, vlevel_split; + int plane_count = 0; + bool force_split = false; + bool avoid_split = dc->debug.pipe_split_policy == MPC_SPLIT_AVOID; + struct vba_vars_st *v = &context->bw_ctx.dml.vba; + int max_mpc_comb = v->maxMpcComb; + + if (context->stream_count > 1) { + if (dc->debug.pipe_split_policy == MPC_SPLIT_AVOID_MULT_DISP) + avoid_split = true; + } else if (dc->debug.force_single_disp_pipe_split) + force_split = true; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + + /** + * Workaround for avoiding pipe-split in cases where we'd split + * planes that are too small, resulting in splits that aren't + * valid for the scaler. + */ + if (pipe->plane_state && + (pipe->plane_state->dst_rect.width <= 16 || + pipe->plane_state->dst_rect.height <= 16 || + pipe->plane_state->src_rect.width <= 16 || + pipe->plane_state->src_rect.height <= 16)) + avoid_split = true; + + /* TODO: fix dc bugs and remove this split threshold thing */ + if (pipe->stream && !pipe->prev_odm_pipe && + (!pipe->top_pipe || pipe->top_pipe->plane_state != pipe->plane_state)) + ++plane_count; + } + if (plane_count > dc->res_pool->pipe_count / 2) + avoid_split = true; + + /* W/A: Mode timing with borders may not work well with pipe split, avoid for this corner case */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + struct dc_crtc_timing timing; + + if (!pipe->stream) + continue; + else { + timing = pipe->stream->timing; + if (timing.h_border_left + timing.h_border_right + + timing.v_border_top + timing.v_border_bottom > 0) { + avoid_split = true; + break; + } + } + } + + /* Avoid split loop looks for lowest voltage level that allows most unsplit pipes possible */ + if (avoid_split) { + for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { + if (!context->res_ctx.pipe_ctx[i].stream) + continue; + + for (vlevel_split = vlevel; vlevel <= context->bw_ctx.dml.soc.num_states; vlevel++) + if (v->NoOfDPP[vlevel][0][pipe_idx] == 1 && + v->ModeSupport[vlevel][0]) + break; + /* Impossible to not split this pipe */ + if (vlevel > context->bw_ctx.dml.soc.num_states) + vlevel = vlevel_split; + else + max_mpc_comb = 0; + pipe_idx++; + } + v->maxMpcComb = max_mpc_comb; + } + + /* Split loop sets which pipe should be split based on dml outputs and dc flags */ + for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + int pipe_plane = v->pipe_plane[pipe_idx]; + bool split4mpc = context->stream_count == 1 && plane_count == 1 + && dc->config.enable_4to1MPC && dc->res_pool->pipe_count >= 4; + + if (!context->res_ctx.pipe_ctx[i].stream) + continue; + + if (split4mpc || v->NoOfDPP[vlevel][max_mpc_comb][pipe_plane] == 4) + split[i] = 4; + else if (force_split || v->NoOfDPP[vlevel][max_mpc_comb][pipe_plane] == 2) + split[i] = 2; + + if ((pipe->stream->view_format == + VIEW_3D_FORMAT_SIDE_BY_SIDE || + pipe->stream->view_format == + VIEW_3D_FORMAT_TOP_AND_BOTTOM) && + (pipe->stream->timing.timing_3d_format == + TIMING_3D_FORMAT_TOP_AND_BOTTOM || + pipe->stream->timing.timing_3d_format == + TIMING_3D_FORMAT_SIDE_BY_SIDE)) + split[i] = 2; + if (dc->debug.force_odm_combine & (1 << pipe->stream_res.tg->inst)) { + split[i] = 2; + v->ODMCombineEnablePerState[vlevel][pipe_plane] = dm_odm_combine_mode_2to1; + } + if (dc->debug.force_odm_combine_4to1 & (1 << pipe->stream_res.tg->inst)) { + split[i] = 4; + v->ODMCombineEnablePerState[vlevel][pipe_plane] = dm_odm_combine_mode_4to1; + } + /*420 format workaround*/ + if (pipe->stream->timing.h_addressable > 7680 && + pipe->stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) { + split[i] = 4; + } + v->ODMCombineEnabled[pipe_plane] = + v->ODMCombineEnablePerState[vlevel][pipe_plane]; + + if (v->ODMCombineEnabled[pipe_plane] == dm_odm_combine_mode_disabled) { + if (resource_get_mpc_slice_count(pipe) == 2) { + /*If need split for mpc but 2 way split already*/ + if (split[i] == 4) + split[i] = 2; /* 2 -> 4 MPC */ + else if (split[i] == 2) + split[i] = 0; /* 2 -> 2 MPC */ + else if (pipe->top_pipe && pipe->top_pipe->plane_state == pipe->plane_state) + merge[i] = true; /* 2 -> 1 MPC */ + } else if (resource_get_mpc_slice_count(pipe) == 4) { + /*If need split for mpc but 4 way split already*/ + if (split[i] == 2 && ((pipe->top_pipe && !pipe->top_pipe->top_pipe) + || !pipe->bottom_pipe)) { + merge[i] = true; /* 4 -> 2 MPC */ + } else if (split[i] == 0 && pipe->top_pipe && + pipe->top_pipe->plane_state == pipe->plane_state) + merge[i] = true; /* 4 -> 1 MPC */ + split[i] = 0; + } else if (resource_get_odm_slice_count(pipe) > 1) { + /* ODM -> MPC transition */ + if (pipe->prev_odm_pipe) { + split[i] = 0; + merge[i] = true; + } + } + } else { + if (resource_get_odm_slice_count(pipe) == 2) { + /*If need split for odm but 2 way split already*/ + if (split[i] == 4) + split[i] = 2; /* 2 -> 4 ODM */ + else if (split[i] == 2) + split[i] = 0; /* 2 -> 2 ODM */ + else if (pipe->prev_odm_pipe) { + ASSERT(0); /* NOT expected yet */ + merge[i] = true; /* exit ODM */ + } + } else if (resource_get_odm_slice_count(pipe) == 4) { + /*If need split for odm but 4 way split already*/ + if (split[i] == 2 && ((pipe->prev_odm_pipe && !pipe->prev_odm_pipe->prev_odm_pipe) + || !pipe->next_odm_pipe)) { + merge[i] = true; /* 4 -> 2 ODM */ + } else if (split[i] == 0 && pipe->prev_odm_pipe) { + ASSERT(0); /* NOT expected yet */ + merge[i] = true; /* exit ODM */ + } + split[i] = 0; + } else if (resource_get_mpc_slice_count(pipe) > 1) { + /* MPC -> ODM transition */ + ASSERT(0); /* NOT expected yet */ + if (pipe->top_pipe && pipe->top_pipe->plane_state == pipe->plane_state) { + split[i] = 0; + merge[i] = true; + } + } + } + + /* Adjust dppclk when split is forced, do not bother with dispclk */ + if (split[i] != 0 && v->NoOfDPP[vlevel][max_mpc_comb][pipe_idx] == 1) { + DC_FP_START(); + dcn20_fpu_adjust_dppclk(v, vlevel, max_mpc_comb, pipe_idx, false); + DC_FP_END(); + } + pipe_idx++; + } + + return vlevel; +} + +bool dcn20_fast_validate_bw( + struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int *pipe_cnt_out, + int *pipe_split_from, + int *vlevel_out, + bool fast_validate) +{ + bool out = false; + int split[MAX_PIPES] = { 0 }; + int pipe_cnt, i, pipe_idx, vlevel; + + ASSERT(pipes); + if (!pipes) + return false; + + dcn20_merge_pipes_for_validate(dc, context); + + DC_FP_START(); + pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, context, pipes, fast_validate); + DC_FP_END(); + + *pipe_cnt_out = pipe_cnt; + + if (!pipe_cnt) { + out = true; + goto validate_out; + } + + vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt); + + if (vlevel > context->bw_ctx.dml.soc.num_states) + goto validate_fail; + + vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, vlevel, split, NULL); + + /*initialize pipe_just_split_from to invalid idx*/ + for (i = 0; i < MAX_PIPES; i++) + pipe_split_from[i] = -1; + + for (i = 0, pipe_idx = -1; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + struct pipe_ctx *hsplit_pipe = pipe->bottom_pipe; + + if (!pipe->stream || pipe_split_from[i] >= 0) + continue; + + pipe_idx++; + + if (!pipe->top_pipe && !pipe->plane_state && context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_idx]) { + hsplit_pipe = dcn20_find_secondary_pipe(dc, &context->res_ctx, dc->res_pool, pipe); + ASSERT(hsplit_pipe); + if (!dcn20_split_stream_for_odm( + dc, &context->res_ctx, + pipe, hsplit_pipe)) + goto validate_fail; + pipe_split_from[hsplit_pipe->pipe_idx] = pipe_idx; + dcn20_build_mapped_resource(dc, context, pipe->stream); + } + + if (!pipe->plane_state) + continue; + /* Skip 2nd half of already split pipe */ + if (pipe->top_pipe && pipe->plane_state == pipe->top_pipe->plane_state) + continue; + + /* We do not support mpo + odm at the moment */ + if (hsplit_pipe && hsplit_pipe->plane_state != pipe->plane_state + && context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_idx]) + goto validate_fail; + + if (split[i] == 2) { + if (!hsplit_pipe || hsplit_pipe->plane_state != pipe->plane_state) { + /* pipe not split previously needs split */ + hsplit_pipe = dcn20_find_secondary_pipe(dc, &context->res_ctx, dc->res_pool, pipe); + ASSERT(hsplit_pipe); + if (!hsplit_pipe) { + DC_FP_START(); + dcn20_fpu_adjust_dppclk(&context->bw_ctx.dml.vba, vlevel, context->bw_ctx.dml.vba.maxMpcComb, pipe_idx, true); + DC_FP_END(); + continue; + } + if (context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_idx]) { + if (!dcn20_split_stream_for_odm( + dc, &context->res_ctx, + pipe, hsplit_pipe)) + goto validate_fail; + dcn20_build_mapped_resource(dc, context, pipe->stream); + } else { + dcn20_split_stream_for_mpc( + &context->res_ctx, dc->res_pool, + pipe, hsplit_pipe); + resource_build_scaling_params(pipe); + resource_build_scaling_params(hsplit_pipe); + } + pipe_split_from[hsplit_pipe->pipe_idx] = pipe_idx; + } + } else if (hsplit_pipe && hsplit_pipe->plane_state == pipe->plane_state) { + /* merge should already have been done */ + ASSERT(0); + } + } + /* Actual dsc count per stream dsc validation*/ + if (!dcn20_validate_dsc(dc, context)) { + context->bw_ctx.dml.vba.ValidationStatus[context->bw_ctx.dml.vba.soc.num_states] = + DML_FAIL_DSC_VALIDATION_FAILURE; + goto validate_fail; + } + + *vlevel_out = vlevel; + + out = true; + goto validate_out; + +validate_fail: + out = false; + +validate_out: + return out; +} + +bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, + bool fast_validate) +{ + bool voltage_supported; + display_e2e_pipe_params_st *pipes; + + pipes = kcalloc(dc->res_pool->pipe_count, sizeof(display_e2e_pipe_params_st), GFP_KERNEL); + if (!pipes) + return false; + + DC_FP_START(); + voltage_supported = dcn20_validate_bandwidth_fp(dc, context, fast_validate, pipes); + DC_FP_END(); + + kfree(pipes); + return voltage_supported; +} + +struct pipe_ctx *dcn20_acquire_free_pipe_for_layer( + const struct dc_state *cur_ctx, + struct dc_state *new_ctx, + const struct resource_pool *pool, + const struct pipe_ctx *opp_head) +{ + struct resource_context *res_ctx = &new_ctx->res_ctx; + struct pipe_ctx *otg_master = resource_get_otg_master_for_stream(res_ctx, opp_head->stream); + struct pipe_ctx *sec_dpp_pipe = resource_find_free_secondary_pipe_legacy(res_ctx, pool, otg_master); + + ASSERT(otg_master); + + if (!sec_dpp_pipe) + return NULL; + + sec_dpp_pipe->stream = opp_head->stream; + sec_dpp_pipe->stream_res.tg = opp_head->stream_res.tg; + sec_dpp_pipe->stream_res.opp = opp_head->stream_res.opp; + + sec_dpp_pipe->plane_res.hubp = pool->hubps[sec_dpp_pipe->pipe_idx]; + sec_dpp_pipe->plane_res.ipp = pool->ipps[sec_dpp_pipe->pipe_idx]; + sec_dpp_pipe->plane_res.dpp = pool->dpps[sec_dpp_pipe->pipe_idx]; + sec_dpp_pipe->plane_res.mpcc_inst = pool->dpps[sec_dpp_pipe->pipe_idx]->inst; + + return sec_dpp_pipe; +} + +bool dcn20_get_dcc_compression_cap(const struct dc *dc, + const struct dc_dcc_surface_param *input, + struct dc_surface_dcc_cap *output) +{ + return dc->res_pool->hubbub->funcs->get_dcc_compression_cap( + dc->res_pool->hubbub, + input, + output); +} + +static void dcn20_destroy_resource_pool(struct resource_pool **pool) +{ + struct dcn20_resource_pool *dcn20_pool = TO_DCN20_RES_POOL(*pool); + + dcn20_resource_destruct(dcn20_pool); + kfree(dcn20_pool); + *pool = NULL; +} + + +static struct dc_cap_funcs cap_funcs = { + .get_dcc_compression_cap = dcn20_get_dcc_compression_cap +}; + + +enum dc_status dcn20_patch_unknown_plane_state(struct dc_plane_state *plane_state) +{ + enum surface_pixel_format surf_pix_format = plane_state->format; + unsigned int bpp = resource_pixel_format_to_bpp(surf_pix_format); + + plane_state->tiling_info.gfx9.swizzle = DC_SW_64KB_S; + if (bpp == 64) + plane_state->tiling_info.gfx9.swizzle = DC_SW_64KB_D; + + return DC_OK; +} + +void dcn20_release_pipe(struct dc_state *context, + struct pipe_ctx *pipe, + const struct resource_pool *pool) +{ + if (resource_is_pipe_type(pipe, OPP_HEAD) && pipe->stream_res.dsc) + dcn20_release_dsc(&context->res_ctx, pool, &pipe->stream_res.dsc); + memset(pipe, 0, sizeof(*pipe)); +} + +static const struct resource_funcs dcn20_res_pool_funcs = { + .destroy = dcn20_destroy_resource_pool, + .link_enc_create = dcn20_link_encoder_create, + .panel_cntl_create = dcn20_panel_cntl_create, + .validate_bandwidth = dcn20_validate_bandwidth, + .acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer, + .release_pipe = dcn20_release_pipe, + .add_stream_to_ctx = dcn20_add_stream_to_ctx, + .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource, + .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, + .populate_dml_writeback_from_context = dcn20_populate_dml_writeback_from_context, + .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, + .set_mcif_arb_params = dcn20_set_mcif_arb_params, + .populate_dml_pipes = dcn20_populate_dml_pipes_from_context, + .find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link +}; + +bool dcn20_dwbc_create(struct dc_context *ctx, struct resource_pool *pool) +{ + int i; + uint32_t pipe_count = pool->res_cap->num_dwb; + + for (i = 0; i < pipe_count; i++) { + struct dcn20_dwbc *dwbc20 = kzalloc(sizeof(struct dcn20_dwbc), + GFP_KERNEL); + + if (!dwbc20) { + dm_error("DC: failed to create dwbc20!\n"); + return false; + } + dcn20_dwbc_construct(dwbc20, ctx, + &dwbc20_regs[i], + &dwbc20_shift, + &dwbc20_mask, + i); + pool->dwbc[i] = &dwbc20->base; + } + return true; +} + +bool dcn20_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool) +{ + int i; + uint32_t pipe_count = pool->res_cap->num_dwb; + + ASSERT(pipe_count > 0); + + for (i = 0; i < pipe_count; i++) { + struct dcn20_mmhubbub *mcif_wb20 = kzalloc(sizeof(struct dcn20_mmhubbub), + GFP_KERNEL); + + if (!mcif_wb20) { + dm_error("DC: failed to create mcif_wb20!\n"); + return false; + } + + dcn20_mmhubbub_construct(mcif_wb20, ctx, + &mcif_wb20_regs[i], + &mcif_wb20_shift, + &mcif_wb20_mask, + i); + + pool->mcif_wb[i] = &mcif_wb20->base; + } + return true; +} + +static struct pp_smu_funcs *dcn20_pp_smu_create(struct dc_context *ctx) +{ + struct pp_smu_funcs *pp_smu = kzalloc(sizeof(*pp_smu), GFP_ATOMIC); + + if (!pp_smu) + return pp_smu; + + dm_pp_get_funcs(ctx, pp_smu); + + if (pp_smu->ctx.ver != PP_SMU_VER_NV) + pp_smu = memset(pp_smu, 0, sizeof(struct pp_smu_funcs)); + + return pp_smu; +} + +static void dcn20_pp_smu_destroy(struct pp_smu_funcs **pp_smu) +{ + if (pp_smu && *pp_smu) { + kfree(*pp_smu); + *pp_smu = NULL; + } +} + +static struct _vcs_dpi_soc_bounding_box_st *get_asic_rev_soc_bb( + uint32_t hw_internal_rev) +{ + if (ASICREV_IS_NAVI14_M(hw_internal_rev)) + return &dcn2_0_nv14_soc; + + if (ASICREV_IS_NAVI12_P(hw_internal_rev)) + return &dcn2_0_nv12_soc; + + return &dcn2_0_soc; +} + +static struct _vcs_dpi_ip_params_st *get_asic_rev_ip_params( + uint32_t hw_internal_rev) +{ + /* NV14 */ + if (ASICREV_IS_NAVI14_M(hw_internal_rev)) + return &dcn2_0_nv14_ip; + + /* NV12 and NV10 */ + return &dcn2_0_ip; +} + +static enum dml_project get_dml_project_version(uint32_t hw_internal_rev) +{ + return DML_PROJECT_NAVI10v2; +} + +static bool init_soc_bounding_box(struct dc *dc, + struct dcn20_resource_pool *pool) +{ + struct _vcs_dpi_soc_bounding_box_st *loaded_bb = + get_asic_rev_soc_bb(dc->ctx->asic_id.hw_internal_rev); + struct _vcs_dpi_ip_params_st *loaded_ip = + get_asic_rev_ip_params(dc->ctx->asic_id.hw_internal_rev); + + DC_LOGGER_INIT(dc->ctx->logger); + + if (pool->base.pp_smu) { + struct pp_smu_nv_clock_table max_clocks = {0}; + unsigned int uclk_states[8] = {0}; + unsigned int num_states = 0; + enum pp_smu_status status; + bool clock_limits_available = false; + bool uclk_states_available = false; + + if (pool->base.pp_smu->nv_funcs.get_uclk_dpm_states) { + status = (pool->base.pp_smu->nv_funcs.get_uclk_dpm_states) + (&pool->base.pp_smu->nv_funcs.pp_smu, uclk_states, &num_states); + + uclk_states_available = (status == PP_SMU_RESULT_OK); + } + + if (pool->base.pp_smu->nv_funcs.get_maximum_sustainable_clocks) { + status = (*pool->base.pp_smu->nv_funcs.get_maximum_sustainable_clocks) + (&pool->base.pp_smu->nv_funcs.pp_smu, &max_clocks); + /* SMU cannot set DCF clock to anything equal to or higher than SOC clock + */ + if (max_clocks.dcfClockInKhz >= max_clocks.socClockInKhz) + max_clocks.dcfClockInKhz = max_clocks.socClockInKhz - 1000; + clock_limits_available = (status == PP_SMU_RESULT_OK); + } + + if (clock_limits_available && uclk_states_available && num_states) { + DC_FP_START(); + dcn20_update_bounding_box(dc, loaded_bb, &max_clocks, uclk_states, num_states); + DC_FP_END(); + } else if (clock_limits_available) { + DC_FP_START(); + dcn20_cap_soc_clocks(loaded_bb, max_clocks); + DC_FP_END(); + } + } + + loaded_ip->max_num_otg = pool->base.res_cap->num_timing_generator; + loaded_ip->max_num_dpp = pool->base.pipe_count; + DC_FP_START(); + dcn20_patch_bounding_box(dc, loaded_bb); + DC_FP_END(); + return true; +} + +static bool dcn20_resource_construct( + uint8_t num_virtual_links, + struct dc *dc, + struct dcn20_resource_pool *pool) +{ + int i; + struct dc_context *ctx = dc->ctx; + struct irq_service_init_data init_data; + struct ddc_service_init_data ddc_init_data = {0}; + struct _vcs_dpi_soc_bounding_box_st *loaded_bb = + get_asic_rev_soc_bb(ctx->asic_id.hw_internal_rev); + struct _vcs_dpi_ip_params_st *loaded_ip = + get_asic_rev_ip_params(ctx->asic_id.hw_internal_rev); + enum dml_project dml_project_version = + get_dml_project_version(ctx->asic_id.hw_internal_rev); + + ctx->dc_bios->regs = &bios_regs; + pool->base.funcs = &dcn20_res_pool_funcs; + + if (ASICREV_IS_NAVI14_M(ctx->asic_id.hw_internal_rev)) { + pool->base.res_cap = &res_cap_nv14; + pool->base.pipe_count = 5; + pool->base.mpcc_count = 5; + } else { + pool->base.res_cap = &res_cap_nv10; + pool->base.pipe_count = 6; + pool->base.mpcc_count = 6; + } + /************************************************* + * Resource + asic cap harcoding * + *************************************************/ + pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + + dc->caps.max_downscale_ratio = 200; + dc->caps.i2c_speed_in_khz = 100; + dc->caps.i2c_speed_in_khz_hdcp = 100; /*1.4 w/a not applied by default*/ + dc->caps.max_cursor_size = 256; + dc->caps.min_horizontal_blanking_period = 80; + dc->caps.dmdata_alloc_size = 2048; + + dc->caps.max_slave_planes = 1; + dc->caps.max_slave_yuv_planes = 1; + dc->caps.max_slave_rgb_planes = 1; + dc->caps.post_blend_color_processing = true; + dc->caps.force_dp_tps4_for_cp2520 = true; + dc->caps.extended_aux_timeout_support = true; + + /* Color pipeline capabilities */ + dc->caps.color.dpp.dcn_arch = 1; + dc->caps.color.dpp.input_lut_shared = 0; + dc->caps.color.dpp.icsc = 1; + dc->caps.color.dpp.dgam_ram = 1; + dc->caps.color.dpp.dgam_rom_caps.srgb = 1; + dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1; + dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 0; + dc->caps.color.dpp.dgam_rom_caps.pq = 0; + dc->caps.color.dpp.dgam_rom_caps.hlg = 0; + dc->caps.color.dpp.post_csc = 0; + dc->caps.color.dpp.gamma_corr = 0; + dc->caps.color.dpp.dgam_rom_for_yuv = 1; + + dc->caps.color.dpp.hw_3d_lut = 1; + dc->caps.color.dpp.ogam_ram = 1; + // no OGAM ROM on DCN2, only MPC ROM + dc->caps.color.dpp.ogam_rom_caps.srgb = 0; + dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0; + dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0; + dc->caps.color.dpp.ogam_rom_caps.pq = 0; + dc->caps.color.dpp.ogam_rom_caps.hlg = 0; + dc->caps.color.dpp.ocsc = 0; + + dc->caps.color.mpc.gamut_remap = 0; + dc->caps.color.mpc.num_3dluts = 0; + dc->caps.color.mpc.shared_3d_lut = 0; + dc->caps.color.mpc.ogam_ram = 1; + dc->caps.color.mpc.ogam_rom_caps.srgb = 0; + dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0; + dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0; + dc->caps.color.mpc.ogam_rom_caps.pq = 0; + dc->caps.color.mpc.ogam_rom_caps.hlg = 0; + dc->caps.color.mpc.ocsc = 1; + + dc->caps.dp_hdmi21_pcon_support = true; + + if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) + dc->debug = debug_defaults_drv; + + //dcn2.0x + dc->work_arounds.dedcn20_305_wa = true; + + // Init the vm_helper + if (dc->vm_helper) + vm_helper_init(dc->vm_helper, 16); + + /************************************************* + * Create resources * + *************************************************/ + + pool->base.clock_sources[DCN20_CLK_SRC_PLL0] = + dcn20_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL0, + &clk_src_regs[0], false); + pool->base.clock_sources[DCN20_CLK_SRC_PLL1] = + dcn20_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL1, + &clk_src_regs[1], false); + pool->base.clock_sources[DCN20_CLK_SRC_PLL2] = + dcn20_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL2, + &clk_src_regs[2], false); + pool->base.clock_sources[DCN20_CLK_SRC_PLL3] = + dcn20_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL3, + &clk_src_regs[3], false); + pool->base.clock_sources[DCN20_CLK_SRC_PLL4] = + dcn20_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL4, + &clk_src_regs[4], false); + pool->base.clock_sources[DCN20_CLK_SRC_PLL5] = + dcn20_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL5, + &clk_src_regs[5], false); + pool->base.clk_src_count = DCN20_CLK_SRC_TOTAL; + /* todo: not reuse phy_pll registers */ + pool->base.dp_clock_source = + dcn20_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_ID_DP_DTO, + &clk_src_regs[0], true); + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] == NULL) { + dm_error("DC: failed to create clock sources!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + } + + pool->base.dccg = dccg2_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask); + if (pool->base.dccg == NULL) { + dm_error("DC: failed to create dccg!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + pool->base.dmcu = dcn20_dmcu_create(ctx, + &dmcu_regs, + &dmcu_shift, + &dmcu_mask); + if (pool->base.dmcu == NULL) { + dm_error("DC: failed to create dmcu!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + pool->base.abm = dce_abm_create(ctx, + &abm_regs, + &abm_shift, + &abm_mask); + if (pool->base.abm == NULL) { + dm_error("DC: failed to create abm!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + pool->base.pp_smu = dcn20_pp_smu_create(ctx); + + + if (!init_soc_bounding_box(dc, pool)) { + dm_error("DC: failed to initialize soc bounding box!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + dml_init_instance(&dc->dml, loaded_bb, loaded_ip, dml_project_version); + + if (!dc->debug.disable_pplib_wm_range) { + struct pp_smu_wm_range_sets ranges = {0}; + int i = 0; + + ranges.num_reader_wm_sets = 0; + + if (loaded_bb->num_states == 1) { + ranges.reader_wm_sets[0].wm_inst = i; + ranges.reader_wm_sets[0].min_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; + ranges.reader_wm_sets[0].max_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; + ranges.reader_wm_sets[0].min_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; + ranges.reader_wm_sets[0].max_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; + + ranges.num_reader_wm_sets = 1; + } else if (loaded_bb->num_states > 1) { + for (i = 0; i < 4 && i < loaded_bb->num_states; i++) { + ranges.reader_wm_sets[i].wm_inst = i; + ranges.reader_wm_sets[i].min_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; + ranges.reader_wm_sets[i].max_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; + DC_FP_START(); + dcn20_fpu_set_wm_ranges(i, &ranges, loaded_bb); + DC_FP_END(); + + ranges.num_reader_wm_sets = i + 1; + } + + ranges.reader_wm_sets[0].min_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; + ranges.reader_wm_sets[ranges.num_reader_wm_sets - 1].max_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; + } + + ranges.num_writer_wm_sets = 1; + + ranges.writer_wm_sets[0].wm_inst = 0; + ranges.writer_wm_sets[0].min_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; + ranges.writer_wm_sets[0].max_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; + ranges.writer_wm_sets[0].min_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; + ranges.writer_wm_sets[0].max_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; + + /* Notify PP Lib/SMU which Watermarks to use for which clock ranges */ + if (pool->base.pp_smu->nv_funcs.set_wm_ranges) + pool->base.pp_smu->nv_funcs.set_wm_ranges(&pool->base.pp_smu->nv_funcs.pp_smu, &ranges); + } + + init_data.ctx = dc->ctx; + pool->base.irqs = dal_irq_service_dcn20_create(&init_data); + if (!pool->base.irqs) + goto create_fail; + + /* mem input -> ipp -> dpp -> opp -> TG */ + for (i = 0; i < pool->base.pipe_count; i++) { + pool->base.hubps[i] = dcn20_hubp_create(ctx, i); + if (pool->base.hubps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create memory input!\n"); + goto create_fail; + } + + pool->base.ipps[i] = dcn20_ipp_create(ctx, i); + if (pool->base.ipps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create input pixel processor!\n"); + goto create_fail; + } + + pool->base.dpps[i] = dcn20_dpp_create(ctx, i); + if (pool->base.dpps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create dpps!\n"); + goto create_fail; + } + } + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + pool->base.engines[i] = dcn20_aux_engine_create(ctx, i); + if (pool->base.engines[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create aux engine!!\n"); + goto create_fail; + } + pool->base.hw_i2cs[i] = dcn20_i2c_hw_create(ctx, i); + if (pool->base.hw_i2cs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create hw i2c!!\n"); + goto create_fail; + } + pool->base.sw_i2cs[i] = NULL; + } + + for (i = 0; i < pool->base.res_cap->num_opp; i++) { + pool->base.opps[i] = dcn20_opp_create(ctx, i); + if (pool->base.opps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create output pixel processor!\n"); + goto create_fail; + } + } + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + pool->base.timing_generators[i] = dcn20_timing_generator_create( + ctx, i); + if (pool->base.timing_generators[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create tg!\n"); + goto create_fail; + } + } + + pool->base.timing_generator_count = i; + + pool->base.mpc = dcn20_mpc_create(ctx); + if (pool->base.mpc == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create mpc!\n"); + goto create_fail; + } + + pool->base.hubbub = dcn20_hubbub_create(ctx); + if (pool->base.hubbub == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create hubbub!\n"); + goto create_fail; + } + + for (i = 0; i < pool->base.res_cap->num_dsc; i++) { + pool->base.dscs[i] = dcn20_dsc_create(ctx, i); + if (pool->base.dscs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create display stream compressor %d!\n", i); + goto create_fail; + } + } + + if (!dcn20_dwbc_create(ctx, &pool->base)) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dwbc!\n"); + goto create_fail; + } + if (!dcn20_mmhubbub_create(ctx, &pool->base)) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create mcif_wb!\n"); + goto create_fail; + } + + if (!resource_construct(num_virtual_links, dc, &pool->base, + &res_create_funcs)) + goto create_fail; + + dcn20_hw_sequencer_construct(dc); + + // IF NV12, set PG function pointer to NULL. It's not that + // PG isn't supported for NV12, it's that we don't want to + // program the registers because that will cause more power + // to be consumed. We could have created dcn20_init_hw to get + // the same effect by checking ASIC rev, but there was a + // request at some point to not check ASIC rev on hw sequencer. + if (ASICREV_IS_NAVI12_P(dc->ctx->asic_id.hw_internal_rev)) { + dc->hwseq->funcs.enable_power_gating_plane = NULL; + dc->debug.disable_dpp_power_gate = true; + dc->debug.disable_hubp_power_gate = true; + } + + + dc->caps.max_planes = pool->base.pipe_count; + + for (i = 0; i < dc->caps.max_planes; ++i) + dc->caps.planes[i] = plane_cap; + + 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->base.oem_device = dc->link_srv->create_ddc_service(&ddc_init_data); + } else { + pool->base.oem_device = NULL; + } + + return true; + +create_fail: + + dcn20_resource_destruct(pool); + + return false; +} + +struct resource_pool *dcn20_create_resource_pool( + const struct dc_init_data *init_data, + struct dc *dc) +{ + struct dcn20_resource_pool *pool = + kzalloc(sizeof(struct dcn20_resource_pool), GFP_ATOMIC); + + if (!pool) + return NULL; + + if (dcn20_resource_construct(init_data->num_virtual_links, dc, pool)) + return &pool->base; + + BREAK_TO_DEBUGGER(); + kfree(pool); + return NULL; +} diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.h new file mode 100644 index 00000000000000..4cee3fa11a7ff4 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.h @@ -0,0 +1,171 @@ +/* +* Copyright 2017 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_RESOURCE_DCN20_H__ +#define __DC_RESOURCE_DCN20_H__ + +#include "core_types.h" +#include "dml/dcn20/dcn20_fpu.h" + +#define TO_DCN20_RES_POOL(pool)\ + container_of(pool, struct dcn20_resource_pool, base) + +struct dc; +struct resource_pool; +struct _vcs_dpi_display_pipe_params_st; + +extern struct _vcs_dpi_ip_params_st dcn2_0_ip; +extern struct _vcs_dpi_ip_params_st dcn2_0_nv14_ip; +extern struct _vcs_dpi_soc_bounding_box_st dcn2_0_soc; +extern struct _vcs_dpi_soc_bounding_box_st dcn2_0_nv14_soc; +extern struct _vcs_dpi_soc_bounding_box_st dcn2_0_nv12_soc; + +struct dcn20_resource_pool { + struct resource_pool base; +}; +struct resource_pool *dcn20_create_resource_pool( + const struct dc_init_data *init_data, + struct dc *dc); + +struct link_encoder *dcn20_link_encoder_create( + struct dc_context *ctx, + const struct encoder_init_data *enc_init_data); + +unsigned int dcn20_calc_max_scaled_time( + unsigned int time_per_pixel, + enum mmhubbub_wbif_mode mode, + unsigned int urgent_watermark); + +struct pipe_ctx *dcn20_acquire_free_pipe_for_layer( + const struct dc_state *cur_ctx, + struct dc_state *new_ctx, + const struct resource_pool *pool, + const struct pipe_ctx *opp_head_pipe); +void dcn20_release_pipe(struct dc_state *context, + struct pipe_ctx *pipe, + const struct resource_pool *pool); +struct stream_encoder *dcn20_stream_encoder_create( + enum engine_id eng_id, + struct dc_context *ctx); + +struct dce_hwseq *dcn20_hwseq_create( + struct dc_context *ctx); + +bool dcn20_get_dcc_compression_cap(const struct dc *dc, + const struct dc_dcc_surface_param *input, + struct dc_surface_dcc_cap *output); + +void dcn20_dpp_destroy(struct dpp **dpp); + +struct dpp *dcn20_dpp_create( + struct dc_context *ctx, + uint32_t inst); + +struct input_pixel_processor *dcn20_ipp_create( + struct dc_context *ctx, uint32_t inst); + +struct output_pixel_processor *dcn20_opp_create( + struct dc_context *ctx, uint32_t inst); + +struct dce_aux *dcn20_aux_engine_create( + struct dc_context *ctx, uint32_t inst); + +struct dce_i2c_hw *dcn20_i2c_hw_create( + struct dc_context *ctx, + uint32_t inst); + +void dcn20_clock_source_destroy(struct clock_source **clk_src); + +struct display_stream_compressor *dcn20_dsc_create( + struct dc_context *ctx, uint32_t inst); +void dcn20_dsc_destroy(struct display_stream_compressor **dsc); + +struct hubp *dcn20_hubp_create( + struct dc_context *ctx, + uint32_t inst); +struct timing_generator *dcn20_timing_generator_create( + struct dc_context *ctx, + uint32_t instance); +struct mpc *dcn20_mpc_create(struct dc_context *ctx); +struct hubbub *dcn20_hubbub_create(struct dc_context *ctx); + +bool dcn20_dwbc_create(struct dc_context *ctx, struct resource_pool *pool); +bool dcn20_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool); + +void dcn20_set_mcif_arb_params( + struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int pipe_cnt); +bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context, bool fast_validate); +void dcn20_merge_pipes_for_validate( + struct dc *dc, + struct dc_state *context); +int dcn20_validate_apply_pipe_split_flags( + struct dc *dc, + struct dc_state *context, + int vlevel, + int *split, + bool *merge); +void dcn20_release_dsc(struct resource_context *res_ctx, + const struct resource_pool *pool, + struct display_stream_compressor **dsc); +bool dcn20_validate_dsc(struct dc *dc, struct dc_state *new_ctx); +void dcn20_split_stream_for_mpc( + struct resource_context *res_ctx, + const struct resource_pool *pool, + struct pipe_ctx *primary_pipe, + struct pipe_ctx *secondary_pipe); +bool dcn20_split_stream_for_odm( + const struct dc *dc, + struct resource_context *res_ctx, + struct pipe_ctx *prev_odm_pipe, + struct pipe_ctx *next_odm_pipe); +void dcn20_acquire_dsc(const struct dc *dc, + struct resource_context *res_ctx, + struct display_stream_compressor **dsc, + int pipe_idx); +struct pipe_ctx *dcn20_find_secondary_pipe(struct dc *dc, + struct resource_context *res_ctx, + const struct resource_pool *pool, + const struct pipe_ctx *primary_pipe); +bool dcn20_fast_validate_bw( + struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int *pipe_cnt_out, + int *pipe_split_from, + int *vlevel_out, + bool fast_validate); + +enum dc_status dcn20_build_mapped_resource(const struct dc *dc, struct dc_state *context, struct dc_stream_state *stream); +enum dc_status dcn20_add_stream_to_ctx(struct dc *dc, struct dc_state *new_ctx, struct dc_stream_state *dc_stream); +enum dc_status dcn20_add_dsc_to_stream_resource(struct dc *dc, struct dc_state *dc_ctx, struct dc_stream_state *dc_stream); +enum dc_status dcn20_remove_stream_from_ctx(struct dc *dc, struct dc_state *new_ctx, struct dc_stream_state *dc_stream); +enum dc_status dcn20_patch_unknown_plane_state(struct dc_plane_state *plane_state); +void dcn20_build_pipe_pix_clk_params(struct pipe_ctx *pipe_ctx); + +#endif /* __DC_RESOURCE_DCN20_H__ */ + diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c new file mode 100644 index 00000000000000..914b234d7f6b7f --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c @@ -0,0 +1,1308 @@ +/* +* Copyright 2016 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 "dcn201/dcn201_init.h" +#include "dml/dcn20/dcn20_fpu.h" +#include "resource.h" +#include "include/irq_service_interface.h" +#include "dcn201_resource.h" + +#include "dcn20/dcn20_resource.h" + +#include "dcn10/dcn10_hubp.h" +#include "dcn10/dcn10_ipp.h" +#include "dcn201/dcn201_mpc.h" +#include "dcn201/dcn201_hubp.h" +#include "irq/dcn201/irq_service_dcn201.h" +#include "dcn201/dcn201_dpp.h" +#include "dcn201/dcn201_hubbub.h" +#include "dcn201/dcn201_dccg.h" +#include "dcn201/dcn201_optc.h" +#include "dcn201/dcn201_hwseq.h" +#include "dce110/dce110_hwseq.h" +#include "dcn201/dcn201_opp.h" +#include "dcn201/dcn201_link_encoder.h" +#include "dcn20/dcn20_stream_encoder.h" +#include "dce/dce_clock_source.h" +#include "dce/dce_audio.h" +#include "dce/dce_hwseq.h" +#include "virtual/virtual_stream_encoder.h" +#include "dce110/dce110_resource.h" +#include "dce/dce_aux.h" +#include "dce/dce_i2c.h" +#include "dcn201/dcn201_hubbub.h" +#include "dcn10/dcn10_resource.h" + +#include "cyan_skillfish_ip_offset.h" + +#include "dcn/dcn_2_0_3_offset.h" +#include "dcn/dcn_2_0_3_sh_mask.h" +#include "dpcs/dpcs_2_0_3_offset.h" +#include "dpcs/dpcs_2_0_3_sh_mask.h" + +#include "mmhub/mmhub_2_0_0_offset.h" +#include "mmhub/mmhub_2_0_0_sh_mask.h" +#include "nbio/nbio_7_4_offset.h" + +#include "reg_helper.h" + +#define MIN_DISP_CLK_KHZ 100000 +#define MIN_DPP_CLK_KHZ 100000 + +static struct _vcs_dpi_ip_params_st dcn201_ip = { + .gpuvm_enable = 0, + .hostvm_enable = 0, + .gpuvm_max_page_table_levels = 4, + .hostvm_max_page_table_levels = 4, + .hostvm_cached_page_table_levels = 0, + .pte_group_size_bytes = 2048, + .rob_buffer_size_kbytes = 168, + .det_buffer_size_kbytes = 164, + .dpte_buffer_size_in_pte_reqs_luma = 84, + .pde_proc_buffer_size_64k_reqs = 48, + .dpp_output_buffer_pixels = 2560, + .opp_output_buffer_lines = 1, + .pixel_chunk_size_kbytes = 8, + .pte_chunk_size_kbytes = 2, + .meta_chunk_size_kbytes = 2, + .writeback_chunk_size_kbytes = 2, + .line_buffer_size_bits = 789504, + .is_line_buffer_bpp_fixed = 0, + .line_buffer_fixed_bpp = 0, + .dcc_supported = true, + .max_line_buffer_lines = 12, + .writeback_luma_buffer_size_kbytes = 12, + .writeback_chroma_buffer_size_kbytes = 8, + .writeback_chroma_line_buffer_width_pixels = 4, + .writeback_max_hscl_ratio = 1, + .writeback_max_vscl_ratio = 1, + .writeback_min_hscl_ratio = 1, + .writeback_min_vscl_ratio = 1, + .writeback_max_hscl_taps = 12, + .writeback_max_vscl_taps = 12, + .writeback_line_buffer_luma_buffer_size = 0, + .writeback_line_buffer_chroma_buffer_size = 9600, + .cursor_buffer_size = 8, + .cursor_chunk_size = 2, + .max_num_otg = 2, + .max_num_dpp = 4, + .max_num_wb = 0, + .max_dchub_pscl_bw_pix_per_clk = 4, + .max_pscl_lb_bw_pix_per_clk = 2, + .max_lb_vscl_bw_pix_per_clk = 4, + .max_vscl_hscl_bw_pix_per_clk = 4, + .max_hscl_ratio = 8, + .max_vscl_ratio = 8, + .hscl_mults = 4, + .vscl_mults = 4, + .max_hscl_taps = 8, + .max_vscl_taps = 8, + .dispclk_ramp_margin_percent = 1, + .underscan_factor = 1.10, + .min_vblank_lines = 30, + .dppclk_delay_subtotal = 77, + .dppclk_delay_scl_lb_only = 16, + .dppclk_delay_scl = 50, + .dppclk_delay_cnvc_formatter = 8, + .dppclk_delay_cnvc_cursor = 6, + .dispclk_delay_subtotal = 87, + .dcfclk_cstate_latency = 10, + .max_inter_dcn_tile_repeaters = 8, + .number_of_cursors = 1, +}; + +static struct _vcs_dpi_soc_bounding_box_st dcn201_soc = { + .clock_limits = { + { + .state = 0, + .dscclk_mhz = 400.0, + .dcfclk_mhz = 1000.0, + .fabricclk_mhz = 200.0, + .dispclk_mhz = 300.0, + .dppclk_mhz = 300.0, + .phyclk_mhz = 810.0, + .socclk_mhz = 1254.0, + .dram_speed_mts = 2000.0, + }, + { + .state = 1, + .dscclk_mhz = 400.0, + .dcfclk_mhz = 1000.0, + .fabricclk_mhz = 250.0, + .dispclk_mhz = 1200.0, + .dppclk_mhz = 1200.0, + .phyclk_mhz = 810.0, + .socclk_mhz = 1254.0, + .dram_speed_mts = 3600.0, + }, + { + .state = 2, + .dscclk_mhz = 400.0, + .dcfclk_mhz = 1000.0, + .fabricclk_mhz = 750.0, + .dispclk_mhz = 1200.0, + .dppclk_mhz = 1200.0, + .phyclk_mhz = 810.0, + .socclk_mhz = 1254.0, + .dram_speed_mts = 6800.0, + }, + { + .state = 3, + .dscclk_mhz = 400.0, + .dcfclk_mhz = 1000.0, + .fabricclk_mhz = 250.0, + .dispclk_mhz = 1200.0, + .dppclk_mhz = 1200.0, + .phyclk_mhz = 810.0, + .socclk_mhz = 1254.0, + .dram_speed_mts = 14000.0, + }, + { + .state = 4, + .dscclk_mhz = 400.0, + .dcfclk_mhz = 1000.0, + .fabricclk_mhz = 750.0, + .dispclk_mhz = 1200.0, + .dppclk_mhz = 1200.0, + .phyclk_mhz = 810.0, + .socclk_mhz = 1254.0, + .dram_speed_mts = 14000.0, + } + }, + .num_states = 4, + .sr_exit_time_us = 9.0, + .sr_enter_plus_exit_time_us = 11.0, + .urgent_latency_us = 4.0, + .urgent_latency_pixel_data_only_us = 4.0, + .urgent_latency_pixel_mixed_with_vm_data_us = 4.0, + .urgent_latency_vm_data_only_us = 4.0, + .urgent_out_of_order_return_per_channel_pixel_only_bytes = 256, + .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 256, + .urgent_out_of_order_return_per_channel_vm_only_bytes = 256, + .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 80.0, + .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 80.0, + .pct_ideal_dram_sdp_bw_after_urgent_vm_only = 80.0, + .max_avg_sdp_bw_use_normal_percent = 80.0, + .max_avg_dram_bw_use_normal_percent = 69.0, + .writeback_latency_us = 12.0, + .ideal_dram_bw_after_urgent_percent = 80.0, + .max_request_size_bytes = 256, + .dram_channel_width_bytes = 2, + .fabric_datapath_to_dcn_data_return_bytes = 64, + .dcn_downspread_percent = 0.3, + .downspread_percent = 0.3, + .dram_page_open_time_ns = 50.0, + .dram_rw_turnaround_time_ns = 17.5, + .dram_return_buffer_per_channel_bytes = 8192, + .round_trip_ping_latency_dcfclk_cycles = 128, + .urgent_out_of_order_return_per_channel_bytes = 256, + .channel_interleave_bytes = 256, + .num_banks = 8, + .num_chans = 16, + .vmm_page_size_bytes = 4096, + .dram_clock_change_latency_us = 250.0, + .writeback_dram_clock_change_latency_us = 23.0, + .return_bus_width_bytes = 64, + .dispclk_dppclk_vco_speed_mhz = 3000, + .use_urgent_burst_bw = 0, +}; + +enum dcn20_clk_src_array_id { + DCN20_CLK_SRC_PLL0, + DCN20_CLK_SRC_PLL1, + DCN20_CLK_SRC_TOTAL_DCN201 +}; + +/* begin ********************* + * macros to expend register list macro defined in HW object header file */ + +/* DCN */ + +#undef BASE_INNER +#define BASE_INNER(seg) DMU_BASE__INST0_SEG ## seg + +#define BASE(seg) BASE_INNER(seg) + +#define SR(reg_name)\ + .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + \ + mm ## reg_name + +#define SRI(reg_name, block, id)\ + .reg_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define SRIR(var_name, reg_name, block, id)\ + .var_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define SRII(reg_name, block, id)\ + .reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define SRI_IX(reg_name, block, id)\ + .reg_name = ix ## block ## id ## _ ## reg_name + +#define DCCG_SRII(reg_name, block, id)\ + .block ## _ ## reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define VUPDATE_SRII(reg_name, block, id)\ + .reg_name[id] = BASE(mm ## reg_name ## _ ## block ## id ## _BASE_IDX) + \ + mm ## reg_name ## _ ## block ## id + +/* NBIO */ +#define NBIO_BASE_INNER(seg) \ + NBIO_BASE__INST0_SEG ## seg + +#define NBIO_BASE(seg) \ + NBIO_BASE_INNER(seg) + +#define NBIO_SR(reg_name)\ + .reg_name = NBIO_BASE(mm ## reg_name ## _BASE_IDX) + \ + mm ## reg_name + +/* MMHUB */ +#define MMHUB_BASE_INNER(seg) \ + MMHUB_BASE__INST0_SEG ## seg + +#define MMHUB_BASE(seg) \ + MMHUB_BASE_INNER(seg) + +#define MMHUB_SR(reg_name)\ + .reg_name = MMHUB_BASE(mmMM ## reg_name ## _BASE_IDX) + \ + mmMM ## reg_name + +static const struct bios_registers bios_regs = { + NBIO_SR(BIOS_SCRATCH_3), + NBIO_SR(BIOS_SCRATCH_6) +}; + +#define clk_src_regs(index, pllid)\ +[index] = {\ + CS_COMMON_REG_LIST_DCN201(index, pllid),\ +} + +static const struct dce110_clk_src_regs clk_src_regs[] = { + clk_src_regs(0, A), + clk_src_regs(1, B) +}; + +static const struct dce110_clk_src_shift cs_shift = { + CS_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) +}; + +static const struct dce110_clk_src_mask cs_mask = { + CS_COMMON_MASK_SH_LIST_DCN2_0(_MASK) +}; + +#define audio_regs(id)\ +[id] = {\ + AUD_COMMON_REG_LIST(id)\ +} + +static const struct dce_audio_registers audio_regs[] = { + audio_regs(0), + audio_regs(1), +}; + +#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ + AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) + +static const struct dce_audio_shift audio_shift = { + DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_audio_mask audio_mask = { + DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) +}; + +#define stream_enc_regs(id)\ +[id] = {\ + SE_DCN2_REG_LIST(id)\ +} + +static const struct dcn10_stream_enc_registers stream_enc_regs[] = { + stream_enc_regs(0), + stream_enc_regs(1) +}; + +static const struct dcn10_stream_encoder_shift se_shift = { + SE_COMMON_MASK_SH_LIST_DCN20(__SHIFT) +}; + +static const struct dcn10_stream_encoder_mask se_mask = { + SE_COMMON_MASK_SH_LIST_DCN20(_MASK) +}; + +static const struct dce110_aux_registers_shift aux_shift = { + DCN_AUX_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce110_aux_registers_mask aux_mask = { + DCN_AUX_MASK_SH_LIST(_MASK) +}; + +#define aux_regs(id)\ +[id] = {\ + DCN2_AUX_REG_LIST(id)\ +} + +static const struct dcn10_link_enc_aux_registers link_enc_aux_regs[] = { + aux_regs(0), + aux_regs(1), +}; + +#define hpd_regs(id)\ +[id] = {\ + HPD_REG_LIST(id)\ +} + +static const struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[] = { + hpd_regs(0), + hpd_regs(1), +}; + +#define link_regs(id, phyid)\ +[id] = {\ + LE_DCN_COMMON_REG_LIST(id), \ + UNIPHY_DCN2_REG_LIST(phyid) \ +} + +static const struct dcn10_link_enc_registers link_enc_regs[] = { + link_regs(0, A), + link_regs(1, B), +}; + +#define LINK_ENCODER_MASK_SH_LIST_DCN201(mask_sh)\ + LINK_ENCODER_MASK_SH_LIST_DCN20(mask_sh) + +static const struct dcn10_link_enc_shift le_shift = { + LINK_ENCODER_MASK_SH_LIST_DCN201(__SHIFT) +}; + +static const struct dcn10_link_enc_mask le_mask = { + LINK_ENCODER_MASK_SH_LIST_DCN201(_MASK) +}; + +#define ipp_regs(id)\ +[id] = {\ + IPP_REG_LIST_DCN201(id),\ +} + +static const struct dcn10_ipp_registers ipp_regs[] = { + ipp_regs(0), + ipp_regs(1), + ipp_regs(2), + ipp_regs(3), +}; + +static const struct dcn10_ipp_shift ipp_shift = { + IPP_MASK_SH_LIST_DCN201(__SHIFT) +}; + +static const struct dcn10_ipp_mask ipp_mask = { + IPP_MASK_SH_LIST_DCN201(_MASK) +}; + +#define opp_regs(id)\ +[id] = {\ + OPP_REG_LIST_DCN201(id),\ +} + +static const struct dcn201_opp_registers opp_regs[] = { + opp_regs(0), + opp_regs(1), +}; + +static const struct dcn201_opp_shift opp_shift = { + OPP_MASK_SH_LIST_DCN201(__SHIFT) +}; + +static const struct dcn201_opp_mask opp_mask = { + OPP_MASK_SH_LIST_DCN201(_MASK) +}; + +#define aux_engine_regs(id)\ +[id] = {\ + AUX_COMMON_REG_LIST0(id), \ + .AUX_RESET_MASK = 0 \ +} + +static const struct dce110_aux_registers aux_engine_regs[] = { + aux_engine_regs(0), + aux_engine_regs(1) +}; + +#define tf_regs(id)\ +[id] = {\ + TF_REG_LIST_DCN201(id),\ +} + +static const struct dcn201_dpp_registers tf_regs[] = { + tf_regs(0), + tf_regs(1), + tf_regs(2), + tf_regs(3), +}; + +static const struct dcn201_dpp_shift tf_shift = { + TF_REG_LIST_SH_MASK_DCN201(__SHIFT) +}; + +static const struct dcn201_dpp_mask tf_mask = { + TF_REG_LIST_SH_MASK_DCN201(_MASK) +}; + +static const struct dcn201_mpc_registers mpc_regs = { + MPC_REG_LIST_DCN201(0), + MPC_REG_LIST_DCN201(1), + MPC_REG_LIST_DCN201(2), + MPC_REG_LIST_DCN201(3), + MPC_REG_LIST_DCN201(4), + MPC_OUT_MUX_REG_LIST_DCN201(0), + MPC_OUT_MUX_REG_LIST_DCN201(1), +}; + +static const struct dcn201_mpc_shift mpc_shift = { + MPC_COMMON_MASK_SH_LIST_DCN201(__SHIFT) +}; + +static const struct dcn201_mpc_mask mpc_mask = { + MPC_COMMON_MASK_SH_LIST_DCN201(_MASK) +}; + +#define tg_regs_dcn201(id)\ +[id] = {TG_COMMON_REG_LIST_DCN201(id)} + +static const struct dcn_optc_registers tg_regs[] = { + tg_regs_dcn201(0), + tg_regs_dcn201(1) +}; + +static const struct dcn_optc_shift tg_shift = { + TG_COMMON_MASK_SH_LIST_DCN201(__SHIFT) +}; + +static const struct dcn_optc_mask tg_mask = { + TG_COMMON_MASK_SH_LIST_DCN201(_MASK) +}; + +#define hubp_regsDCN201(id)\ +[id] = {\ + HUBP_REG_LIST_DCN201(id)\ +} + +static const struct dcn201_hubp_registers hubp_regs[] = { + hubp_regsDCN201(0), + hubp_regsDCN201(1), + hubp_regsDCN201(2), + hubp_regsDCN201(3) +}; + +static const struct dcn201_hubp_shift hubp_shift = { + HUBP_MASK_SH_LIST_DCN201(__SHIFT) +}; + +static const struct dcn201_hubp_mask hubp_mask = { + HUBP_MASK_SH_LIST_DCN201(_MASK) +}; + +static const struct dcn_hubbub_registers hubbub_reg = { + HUBBUB_REG_LIST_DCN201(0) +}; + +static const struct dcn_hubbub_shift hubbub_shift = { + HUBBUB_MASK_SH_LIST_DCN201(__SHIFT) +}; + +static const struct dcn_hubbub_mask hubbub_mask = { + HUBBUB_MASK_SH_LIST_DCN201(_MASK) +}; + + +static const struct dccg_registers dccg_regs = { + DCCG_COMMON_REG_LIST_DCN_BASE() +}; + +static const struct dccg_shift dccg_shift = { + DCCG_COMMON_MASK_SH_LIST_DCN_COMMON_BASE(__SHIFT) +}; + +static const struct dccg_mask dccg_mask = { + DCCG_COMMON_MASK_SH_LIST_DCN_COMMON_BASE(_MASK) +}; + +static const struct resource_caps res_cap_dnc201 = { + .num_timing_generator = 2, + .num_opp = 2, + .num_video_plane = 4, + .num_audio = 2, + .num_stream_encoder = 2, + .num_pll = 2, + .num_ddc = 2, +}; + +static const struct dc_plane_cap plane_cap = { + .type = DC_PLANE_TYPE_DCN_UNIVERSAL, + .per_pixel_alpha = true, + + .pixel_format_support = { + .argb8888 = true, + .nv12 = false, + .fp16 = true, + .p010 = false, + }, + + .max_upscale_factor = { + .argb8888 = 16000, + .nv12 = 16000, + .fp16 = 1 + }, + + .max_downscale_factor = { + .argb8888 = 250, + .nv12 = 250, + .fp16 = 250 + }, + 64, + 64 +}; + +static const struct dc_debug_options debug_defaults_drv = { + .disable_dmcu = true, + .force_abm_enable = false, + .timing_trace = false, + .clock_trace = true, + .disable_pplib_clock_request = true, + .pipe_split_policy = MPC_SPLIT_DYNAMIC, + .force_single_disp_pipe_split = false, + .disable_dcc = DCC_ENABLE, + .vsr_support = true, + .performance_trace = false, + .az_endpoint_mute_only = true, + .max_downscale_src_width = 3840, + .disable_pplib_wm_range = true, + .scl_reset_length10 = true, + .sanity_checks = false, + .underflow_assert_delay_us = 0xFFFFFFFF, + .enable_tri_buf = false, + .enable_legacy_fast_update = true, + .using_dml2 = false, +}; + +static void dcn201_dpp_destroy(struct dpp **dpp) +{ + kfree(TO_DCN201_DPP(*dpp)); + *dpp = NULL; +} + +static struct dpp *dcn201_dpp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn201_dpp *dpp = + kzalloc(sizeof(struct dcn201_dpp), GFP_ATOMIC); + + if (!dpp) + return NULL; + + if (dpp201_construct(dpp, ctx, inst, + &tf_regs[inst], &tf_shift, &tf_mask)) + return &dpp->base; + + kfree(dpp); + return NULL; +} + +static struct input_pixel_processor *dcn201_ipp_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dcn10_ipp *ipp = + kzalloc(sizeof(struct dcn10_ipp), GFP_ATOMIC); + + if (!ipp) { + return NULL; + } + + dcn20_ipp_construct(ipp, ctx, inst, + &ipp_regs[inst], &ipp_shift, &ipp_mask); + return &ipp->base; +} + + +static struct output_pixel_processor *dcn201_opp_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dcn201_opp *opp = + kzalloc(sizeof(struct dcn201_opp), GFP_ATOMIC); + + if (!opp) { + return NULL; + } + + dcn201_opp_construct(opp, ctx, inst, + &opp_regs[inst], &opp_shift, &opp_mask); + return &opp->base; +} + +static struct dce_aux *dcn201_aux_engine_create(struct dc_context *ctx, + uint32_t inst) +{ + struct aux_engine_dce110 *aux_engine = + kzalloc(sizeof(struct aux_engine_dce110), GFP_ATOMIC); + + if (!aux_engine) + return NULL; + + dce110_aux_engine_construct(aux_engine, ctx, inst, + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, + &aux_engine_regs[inst], + &aux_mask, + &aux_shift, + ctx->dc->caps.extended_aux_timeout_support); + + return &aux_engine->base; +} +#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST(id) } + +static const struct dce_i2c_registers i2c_hw_regs[] = { + i2c_inst_regs(1), + i2c_inst_regs(2), +}; + +static const struct dce_i2c_shift i2c_shifts = { + I2C_COMMON_MASK_SH_LIST_DCN2(__SHIFT) +}; + +static const struct dce_i2c_mask i2c_masks = { + I2C_COMMON_MASK_SH_LIST_DCN2(_MASK) +}; + +static struct dce_i2c_hw *dcn201_i2c_hw_create(struct dc_context *ctx, + uint32_t inst) +{ + struct dce_i2c_hw *dce_i2c_hw = + kzalloc(sizeof(struct dce_i2c_hw), GFP_ATOMIC); + + if (!dce_i2c_hw) + return NULL; + + dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst, + &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); + + return dce_i2c_hw; +} + +static struct mpc *dcn201_mpc_create(struct dc_context *ctx, uint32_t num_mpcc) +{ + struct dcn201_mpc *mpc201 = kzalloc(sizeof(struct dcn201_mpc), + GFP_ATOMIC); + + if (!mpc201) + return NULL; + + dcn201_mpc_construct(mpc201, ctx, + &mpc_regs, + &mpc_shift, + &mpc_mask, + num_mpcc); + + return &mpc201->base; +} + +static struct hubbub *dcn201_hubbub_create(struct dc_context *ctx) +{ + struct dcn20_hubbub *hubbub = kzalloc(sizeof(struct dcn20_hubbub), + GFP_ATOMIC); + + if (!hubbub) + return NULL; + + hubbub201_construct(hubbub, ctx, + &hubbub_reg, + &hubbub_shift, + &hubbub_mask); + + return &hubbub->base; +} + +static struct timing_generator *dcn201_timing_generator_create( + struct dc_context *ctx, + uint32_t instance) +{ + struct optc *tgn10 = + kzalloc(sizeof(struct optc), GFP_ATOMIC); + + if (!tgn10) + return NULL; + + tgn10->base.inst = instance; + tgn10->base.ctx = ctx; + + tgn10->tg_regs = &tg_regs[instance]; + tgn10->tg_shift = &tg_shift; + tgn10->tg_mask = &tg_mask; + + dcn201_timing_generator_init(tgn10); + + return &tgn10->base; +} + +static const struct encoder_feature_support link_enc_feature = { + .max_hdmi_deep_color = COLOR_DEPTH_121212, + .max_hdmi_pixel_clock = 600000, + .hdmi_ycbcr420_supported = true, + .dp_ycbcr420_supported = true, + .fec_supported = true, + .flags.bits.IS_HBR2_CAPABLE = true, + .flags.bits.IS_HBR3_CAPABLE = true, + .flags.bits.IS_TPS3_CAPABLE = true, + .flags.bits.IS_TPS4_CAPABLE = true +}; + +static struct link_encoder *dcn201_link_encoder_create( + struct dc_context *ctx, + const struct encoder_init_data *enc_init_data) +{ + struct dcn20_link_encoder *enc20 = + kzalloc(sizeof(struct dcn20_link_encoder), GFP_ATOMIC); + struct dcn10_link_encoder *enc10 = &enc20->enc10; + + if (!enc20) + return NULL; + + dcn201_link_encoder_construct(enc20, + enc_init_data, + &link_enc_feature, + &link_enc_regs[enc_init_data->transmitter], + &link_enc_aux_regs[enc_init_data->channel - 1], + &link_enc_hpd_regs[enc_init_data->hpd_source], + &le_shift, + &le_mask); + + return &enc10->base; +} + +static struct clock_source *dcn201_clock_source_create( + struct dc_context *ctx, + struct dc_bios *bios, + enum clock_source_id id, + const struct dce110_clk_src_regs *regs, + bool dp_clk_src) +{ + struct dce110_clk_src *clk_src = + kzalloc(sizeof(struct dce110_clk_src), GFP_ATOMIC); + + if (!clk_src) + return NULL; + + if (dce112_clk_src_construct(clk_src, ctx, bios, id, + regs, &cs_shift, &cs_mask)) { + clk_src->base.dp_clk_src = dp_clk_src; + return &clk_src->base; + } + kfree(clk_src); + return NULL; +} + +static void read_dce_straps( + struct dc_context *ctx, + struct resource_straps *straps) +{ + generic_reg_get(ctx, mmDC_PINSTRAPS + BASE(mmDC_PINSTRAPS_BASE_IDX), + + FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio); +} + +static struct audio *dcn201_create_audio( + struct dc_context *ctx, unsigned int inst) +{ + return dce_audio_create(ctx, inst, + &audio_regs[inst], &audio_shift, &audio_mask); +} + +static struct stream_encoder *dcn201_stream_encoder_create( + enum engine_id eng_id, + struct dc_context *ctx) +{ + struct dcn10_stream_encoder *enc1 = + kzalloc(sizeof(struct dcn10_stream_encoder), GFP_ATOMIC); + + if (!enc1) + return NULL; + + dcn20_stream_encoder_construct(enc1, ctx, ctx->dc_bios, eng_id, + &stream_enc_regs[eng_id], + &se_shift, &se_mask); + + return &enc1->base; +} + +static const struct dce_hwseq_registers hwseq_reg = { + HWSEQ_DCN201_REG_LIST() +}; + +static const struct dce_hwseq_shift hwseq_shift = { + HWSEQ_DCN201_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_hwseq_mask hwseq_mask = { + HWSEQ_DCN201_MASK_SH_LIST(_MASK) +}; + +static struct dce_hwseq *dcn201_hwseq_create( + struct dc_context *ctx) +{ + struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_ATOMIC); + + if (hws) { + hws->ctx = ctx; + hws->regs = &hwseq_reg; + hws->shifts = &hwseq_shift; + hws->masks = &hwseq_mask; + } + return hws; +} + +static const struct resource_create_funcs res_create_funcs = { + .read_dce_straps = read_dce_straps, + .create_audio = dcn201_create_audio, + .create_stream_encoder = dcn201_stream_encoder_create, + .create_hwseq = dcn201_hwseq_create, +}; + +static void dcn201_clock_source_destroy(struct clock_source **clk_src) +{ + kfree(TO_DCE110_CLK_SRC(*clk_src)); + *clk_src = NULL; +} + +static void dcn201_resource_destruct(struct dcn201_resource_pool *pool) +{ + unsigned int i; + + for (i = 0; i < pool->base.stream_enc_count; i++) { + if (pool->base.stream_enc[i] != NULL) { + kfree(DCN10STRENC_FROM_STRENC(pool->base.stream_enc[i])); + pool->base.stream_enc[i] = NULL; + } + } + + + if (pool->base.mpc != NULL) { + kfree(TO_DCN201_MPC(pool->base.mpc)); + pool->base.mpc = NULL; + } + + if (pool->base.hubbub != NULL) { + kfree(pool->base.hubbub); + pool->base.hubbub = NULL; + } + + for (i = 0; i < pool->base.pipe_count; i++) { + if (pool->base.dpps[i] != NULL) + dcn201_dpp_destroy(&pool->base.dpps[i]); + + if (pool->base.ipps[i] != NULL) + pool->base.ipps[i]->funcs->ipp_destroy(&pool->base.ipps[i]); + + if (pool->base.hubps[i] != NULL) { + kfree(TO_DCN10_HUBP(pool->base.hubps[i])); + pool->base.hubps[i] = NULL; + } + + if (pool->base.irqs != NULL) { + dal_irq_service_destroy(&pool->base.irqs); + } + } + + for (i = 0; i < pool->base.res_cap->num_opp; i++) { + if (pool->base.opps[i] != NULL) + pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]); + } + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + if (pool->base.timing_generators[i] != NULL) { + kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i])); + pool->base.timing_generators[i] = NULL; + } + } + for (i = 0; i < pool->base.audio_count; i++) { + if (pool->base.audios[i]) + dce_aud_destroy(&pool->base.audios[i]); + } + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] != NULL) { + dcn201_clock_source_destroy(&pool->base.clock_sources[i]); + pool->base.clock_sources[i] = NULL; + } + } + + if (pool->base.dp_clock_source != NULL) { + dcn201_clock_source_destroy(&pool->base.dp_clock_source); + pool->base.dp_clock_source = NULL; + } + + if (pool->base.dccg != NULL) + dcn_dccg_destroy(&pool->base.dccg); +} + +static struct hubp *dcn201_hubp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn201_hubp *hubp201 = + kzalloc(sizeof(struct dcn201_hubp), GFP_ATOMIC); + + if (!hubp201) + return NULL; + + if (dcn201_hubp_construct(hubp201, ctx, inst, + &hubp_regs[inst], &hubp_shift, &hubp_mask)) + return &hubp201->base; + + kfree(hubp201); + return NULL; +} + +static struct pipe_ctx *dcn201_acquire_free_pipe_for_layer( + const struct dc_state *cur_ctx, + struct dc_state *new_ctx, + const struct resource_pool *pool, + const struct pipe_ctx *opp_head_pipe) +{ + struct resource_context *res_ctx = &new_ctx->res_ctx; + struct pipe_ctx *head_pipe = resource_get_otg_master_for_stream(res_ctx, opp_head_pipe->stream); + struct pipe_ctx *idle_pipe = resource_find_free_secondary_pipe_legacy(res_ctx, pool, head_pipe); + + if (!head_pipe) + ASSERT(0); + + if (!idle_pipe) + return NULL; + + idle_pipe->stream = head_pipe->stream; + idle_pipe->stream_res.tg = head_pipe->stream_res.tg; + idle_pipe->stream_res.opp = head_pipe->stream_res.opp; + + idle_pipe->plane_res.hubp = pool->hubps[idle_pipe->pipe_idx]; + idle_pipe->plane_res.ipp = pool->ipps[idle_pipe->pipe_idx]; + idle_pipe->plane_res.dpp = pool->dpps[idle_pipe->pipe_idx]; + idle_pipe->plane_res.mpcc_inst = pool->dpps[idle_pipe->pipe_idx]->inst; + + return idle_pipe; +} + +static bool dcn201_get_dcc_compression_cap(const struct dc *dc, + const struct dc_dcc_surface_param *input, + struct dc_surface_dcc_cap *output) +{ + return dc->res_pool->hubbub->funcs->get_dcc_compression_cap( + dc->res_pool->hubbub, + input, + output); +} + +static void dcn201_populate_dml_writeback_from_context(struct dc *dc, + struct resource_context *res_ctx, + display_e2e_pipe_params_st *pipes) +{ + DC_FP_START(); + dcn201_populate_dml_writeback_from_context_fpu(dc, res_ctx, pipes); + DC_FP_END(); +} + +static void dcn201_destroy_resource_pool(struct resource_pool **pool) +{ + struct dcn201_resource_pool *dcn201_pool = TO_DCN201_RES_POOL(*pool); + + dcn201_resource_destruct(dcn201_pool); + kfree(dcn201_pool); + *pool = NULL; +} + +static void dcn201_link_init(struct dc_link *link) +{ + if (link->ctx->dc_bios->integrated_info) + link->dp_ss_off = !link->ctx->dc_bios->integrated_info->dp_ss_control; +} + +static struct dc_cap_funcs cap_funcs = { + .get_dcc_compression_cap = dcn201_get_dcc_compression_cap, +}; + +static struct resource_funcs dcn201_res_pool_funcs = { + .link_init = dcn201_link_init, + .destroy = dcn201_destroy_resource_pool, + .link_enc_create = dcn201_link_encoder_create, + .panel_cntl_create = NULL, + .validate_bandwidth = dcn20_validate_bandwidth, + .populate_dml_pipes = dcn20_populate_dml_pipes_from_context, + .add_stream_to_ctx = dcn20_add_stream_to_ctx, + .add_dsc_to_stream_resource = NULL, + .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, + .acquire_free_pipe_as_secondary_dpp_pipe = dcn201_acquire_free_pipe_for_layer, + .release_pipe = dcn20_release_pipe, + .populate_dml_writeback_from_context = dcn201_populate_dml_writeback_from_context, + .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, + .set_mcif_arb_params = dcn20_set_mcif_arb_params, + .find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link +}; + +static bool dcn201_resource_construct( + uint8_t num_virtual_links, + struct dc *dc, + struct dcn201_resource_pool *pool) +{ + int i; + struct dc_context *ctx = dc->ctx; + + ctx->dc_bios->regs = &bios_regs; + + pool->base.res_cap = &res_cap_dnc201; + pool->base.funcs = &dcn201_res_pool_funcs; + + /************************************************* + * Resource + asic cap harcoding * + *************************************************/ + pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + + pool->base.pipe_count = 4; + pool->base.mpcc_count = 5; + dc->caps.max_downscale_ratio = 200; + dc->caps.i2c_speed_in_khz = 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; + + dc->caps.max_slave_planes = 1; + dc->caps.max_slave_yuv_planes = 1; + dc->caps.max_slave_rgb_planes = 1; + dc->caps.post_blend_color_processing = true; + dc->caps.force_dp_tps4_for_cp2520 = true; + dc->caps.extended_aux_timeout_support = true; + + /* Color pipeline capabilities */ + dc->caps.color.dpp.dcn_arch = 1; + dc->caps.color.dpp.input_lut_shared = 0; + dc->caps.color.dpp.icsc = 1; + dc->caps.color.dpp.dgam_ram = 1; + dc->caps.color.dpp.dgam_rom_caps.srgb = 1; + dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1; + dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 0; + dc->caps.color.dpp.dgam_rom_caps.pq = 0; + dc->caps.color.dpp.dgam_rom_caps.hlg = 0; + dc->caps.color.dpp.post_csc = 0; + dc->caps.color.dpp.gamma_corr = 0; + dc->caps.color.dpp.dgam_rom_for_yuv = 1; + + dc->caps.color.dpp.hw_3d_lut = 1; + dc->caps.color.dpp.ogam_ram = 1; + // no OGAM ROM on DCN2 + dc->caps.color.dpp.ogam_rom_caps.srgb = 0; + dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0; + dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0; + dc->caps.color.dpp.ogam_rom_caps.pq = 0; + dc->caps.color.dpp.ogam_rom_caps.hlg = 0; + dc->caps.color.dpp.ocsc = 0; + + dc->caps.color.mpc.gamut_remap = 0; + dc->caps.color.mpc.num_3dluts = 0; + dc->caps.color.mpc.shared_3d_lut = 0; + dc->caps.color.mpc.ogam_ram = 1; + dc->caps.color.mpc.ogam_rom_caps.srgb = 0; + dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0; + dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0; + dc->caps.color.mpc.ogam_rom_caps.pq = 0; + dc->caps.color.mpc.ogam_rom_caps.hlg = 0; + dc->caps.color.mpc.ocsc = 1; + + dc->debug = debug_defaults_drv; + + /*a0 only, remove later*/ + dc->work_arounds.no_connect_phy_config = true; + dc->work_arounds.dedcn20_305_wa = true; + /************************************************* + * Create resources * + *************************************************/ + + pool->base.clock_sources[DCN20_CLK_SRC_PLL0] = + dcn201_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL0, + &clk_src_regs[0], false); + pool->base.clock_sources[DCN20_CLK_SRC_PLL1] = + dcn201_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL1, + &clk_src_regs[1], false); + + pool->base.clk_src_count = DCN20_CLK_SRC_TOTAL_DCN201; + + /* todo: not reuse phy_pll registers */ + pool->base.dp_clock_source = + dcn201_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_ID_DP_DTO, + &clk_src_regs[0], true); + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] == NULL) { + dm_error("DC: failed to create clock sources!\n"); + goto create_fail; + } + } + + pool->base.dccg = dccg201_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask); + if (pool->base.dccg == NULL) { + dm_error("DC: failed to create dccg!\n"); + goto create_fail; + } + + dcn201_ip.max_num_otg = pool->base.res_cap->num_timing_generator; + dcn201_ip.max_num_dpp = pool->base.pipe_count; + dml_init_instance(&dc->dml, &dcn201_soc, &dcn201_ip, DML_PROJECT_DCN201); + { + struct irq_service_init_data init_data; + init_data.ctx = dc->ctx; + pool->base.irqs = dal_irq_service_dcn201_create(&init_data); + if (!pool->base.irqs) + goto create_fail; + } + + /* mem input -> ipp -> dpp -> opp -> TG */ + for (i = 0; i < pool->base.pipe_count; i++) { + pool->base.hubps[i] = dcn201_hubp_create(ctx, i); + if (pool->base.hubps[i] == NULL) { + dm_error( + "DC: failed to create memory input!\n"); + goto create_fail; + } + + pool->base.ipps[i] = dcn201_ipp_create(ctx, i); + if (pool->base.ipps[i] == NULL) { + dm_error( + "DC: failed to create input pixel processor!\n"); + goto create_fail; + } + + pool->base.dpps[i] = dcn201_dpp_create(ctx, i); + if (pool->base.dpps[i] == NULL) { + dm_error( + "DC: failed to create dpps!\n"); + goto create_fail; + } + } + + for (i = 0; i < pool->base.res_cap->num_opp; i++) { + pool->base.opps[i] = dcn201_opp_create(ctx, i); + if (pool->base.opps[i] == NULL) { + dm_error( + "DC: failed to create output pixel processor!\n"); + goto create_fail; + } + } + + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + pool->base.engines[i] = dcn201_aux_engine_create(ctx, i); + if (pool->base.engines[i] == NULL) { + dm_error( + "DC:failed to create aux engine!!\n"); + goto create_fail; + } + pool->base.hw_i2cs[i] = dcn201_i2c_hw_create(ctx, i); + if (pool->base.hw_i2cs[i] == NULL) { + dm_error( + "DC:failed to create hw i2c!!\n"); + goto create_fail; + } + pool->base.sw_i2cs[i] = NULL; + } + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + pool->base.timing_generators[i] = dcn201_timing_generator_create( + ctx, i); + if (pool->base.timing_generators[i] == NULL) { + dm_error("DC: failed to create tg!\n"); + goto create_fail; + } + } + + pool->base.timing_generator_count = i; + + pool->base.mpc = dcn201_mpc_create(ctx, pool->base.mpcc_count); + if (pool->base.mpc == NULL) { + dm_error("DC: failed to create mpc!\n"); + goto create_fail; + } + + pool->base.hubbub = dcn201_hubbub_create(ctx); + if (pool->base.hubbub == NULL) { + dm_error("DC: failed to create hubbub!\n"); + goto create_fail; + } + + if (!resource_construct(num_virtual_links, dc, &pool->base, + &res_create_funcs)) + goto create_fail; + + dcn201_hw_sequencer_construct(dc); + + dc->caps.max_planes = pool->base.pipe_count; + + for (i = 0; i < dc->caps.max_planes; ++i) + dc->caps.planes[i] = plane_cap; + + dc->cap_funcs = cap_funcs; + + return true; + +create_fail: + + dcn201_resource_destruct(pool); + + return false; +} + +struct resource_pool *dcn201_create_resource_pool( + const struct dc_init_data *init_data, + struct dc *dc) +{ + struct dcn201_resource_pool *pool = + kzalloc(sizeof(struct dcn201_resource_pool), GFP_ATOMIC); + + if (!pool) + return NULL; + + if (dcn201_resource_construct(init_data->num_virtual_links, dc, pool)) + return &pool->base; + + kfree(pool); + return NULL; +} diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.h new file mode 100644 index 00000000000000..e0467d17d4ae8d --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.h @@ -0,0 +1,50 @@ +/* +* Copyright 2017 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_RESOURCE_DCN201_H__ +#define __DC_RESOURCE_DCN201_H__ + +#include "core_types.h" + +#define RRDPCS_PHY_DP_TX_PSTATE_POWER_UP 0x00000000 +#define RRDPCS_PHY_DP_TX_PSTATE_HOLD 0x00000001 +#define RRDPCS_PHY_DP_TX_PSTATE_HOLD_OFF 0x00000002 +#define RRDPCS_PHY_DP_TX_PSTATE_POWER_DOWN 0x00000003 + +#define TO_DCN201_RES_POOL(pool)\ + container_of(pool, struct dcn201_resource_pool, base) + +struct dc; +struct resource_pool; +struct _vcs_dpi_display_pipe_params_st; + +struct dcn201_resource_pool { + struct resource_pool base; +}; +struct resource_pool *dcn201_create_resource_pool( + const struct dc_init_data *init_data, + struct dc *dc); + +#endif /* __DC_RESOURCE_DCN201_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c new file mode 100644 index 00000000000000..65d337731f5671 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c @@ -0,0 +1,1744 @@ +/* +* Copyright 2018 Advanced Micro Devices, Inc. + * Copyright 2019 Raptor Engineering, LLC + * + * 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 + +#include "dm_services.h" +#include "dc.h" + +#include "dcn21/dcn21_init.h" + +#include "resource.h" +#include "include/irq_service_interface.h" +#include "dcn20/dcn20_resource.h" +#include "dcn21/dcn21_resource.h" + +#include "dml/dcn20/dcn20_fpu.h" + +#include "clk_mgr.h" +#include "dcn10/dcn10_hubp.h" +#include "dcn10/dcn10_ipp.h" +#include "dcn20/dcn20_hubbub.h" +#include "dcn20/dcn20_mpc.h" +#include "dcn20/dcn20_hubp.h" +#include "dcn21/dcn21_hubp.h" +#include "irq/dcn21/irq_service_dcn21.h" +#include "dcn20/dcn20_dpp.h" +#include "dcn20/dcn20_optc.h" +#include "dcn21/dcn21_hwseq.h" +#include "dce110/dce110_hwseq.h" +#include "dcn20/dcn20_opp.h" +#include "dcn20/dcn20_dsc.h" +#include "dcn21/dcn21_link_encoder.h" +#include "dcn20/dcn20_stream_encoder.h" +#include "dce/dce_clock_source.h" +#include "dce/dce_audio.h" +#include "dce/dce_hwseq.h" +#include "virtual/virtual_stream_encoder.h" +#include "dml/display_mode_vba.h" +#include "dcn20/dcn20_dccg.h" +#include "dcn21/dcn21_dccg.h" +#include "dcn21/dcn21_hubbub.h" +#include "dcn10/dcn10_resource.h" +#include "dce/dce_panel_cntl.h" + +#include "dcn20/dcn20_dwb.h" +#include "dcn20/dcn20_mmhubbub.h" +#include "dpcs/dpcs_2_1_0_offset.h" +#include "dpcs/dpcs_2_1_0_sh_mask.h" + +#include "renoir_ip_offset.h" +#include "dcn/dcn_2_1_0_offset.h" +#include "dcn/dcn_2_1_0_sh_mask.h" + +#include "nbio/nbio_7_0_offset.h" + +#include "mmhub/mmhub_2_0_0_offset.h" +#include "mmhub/mmhub_2_0_0_sh_mask.h" + +#include "reg_helper.h" +#include "dce/dce_abm.h" +#include "dce/dce_dmcu.h" +#include "dce/dce_aux.h" +#include "dce/dce_i2c.h" +#include "dcn21_resource.h" +#include "vm_helper.h" +#include "dcn20/dcn20_vmid.h" +#include "dce/dmub_psr.h" +#include "dce/dmub_abm.h" + +/* begin ********************* + * macros to expend register list macro defined in HW object header file */ + +/* DCN */ +#define BASE_INNER(seg) DMU_BASE__INST0_SEG ## seg + +#define BASE(seg) BASE_INNER(seg) + +#define SR(reg_name)\ + .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + \ + mm ## reg_name + +#define SRI(reg_name, block, id)\ + .reg_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define SRIR(var_name, reg_name, block, id)\ + .var_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define SRII(reg_name, block, id)\ + .reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define DCCG_SRII(reg_name, block, id)\ + .block ## _ ## reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define VUPDATE_SRII(reg_name, block, id)\ + .reg_name[id] = BASE(mm ## reg_name ## _ ## block ## id ## _BASE_IDX) + \ + mm ## reg_name ## _ ## block ## id + +/* NBIO */ +#define NBIO_BASE_INNER(seg) \ + NBIF0_BASE__INST0_SEG ## seg + +#define NBIO_BASE(seg) \ + NBIO_BASE_INNER(seg) + +#define NBIO_SR(reg_name)\ + .reg_name = NBIO_BASE(mm ## reg_name ## _BASE_IDX) + \ + mm ## reg_name + +/* MMHUB */ +#define MMHUB_BASE_INNER(seg) \ + MMHUB_BASE__INST0_SEG ## seg + +#define MMHUB_BASE(seg) \ + MMHUB_BASE_INNER(seg) + +#define MMHUB_SR(reg_name)\ + .reg_name = MMHUB_BASE(mmMM ## reg_name ## _BASE_IDX) + \ + mmMM ## reg_name + +#define clk_src_regs(index, pllid)\ +[index] = {\ + CS_COMMON_REG_LIST_DCN2_1(index, pllid),\ +} + +static const struct dce110_clk_src_regs clk_src_regs[] = { + clk_src_regs(0, A), + clk_src_regs(1, B), + clk_src_regs(2, C), + clk_src_regs(3, D), + clk_src_regs(4, E), +}; + +static const struct dce110_clk_src_shift cs_shift = { + CS_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) +}; + +static const struct dce110_clk_src_mask cs_mask = { + CS_COMMON_MASK_SH_LIST_DCN2_0(_MASK) +}; + +static const struct bios_registers bios_regs = { + NBIO_SR(BIOS_SCRATCH_3), + NBIO_SR(BIOS_SCRATCH_6) +}; + +static const struct dce_dmcu_registers dmcu_regs = { + DMCU_DCN20_REG_LIST() +}; + +static const struct dce_dmcu_shift dmcu_shift = { + DMCU_MASK_SH_LIST_DCN10(__SHIFT) +}; + +static const struct dce_dmcu_mask dmcu_mask = { + DMCU_MASK_SH_LIST_DCN10(_MASK) +}; + +static const struct dce_abm_registers abm_regs = { + ABM_DCN20_REG_LIST() +}; + +static const struct dce_abm_shift abm_shift = { + ABM_MASK_SH_LIST_DCN20(__SHIFT) +}; + +static const struct dce_abm_mask abm_mask = { + ABM_MASK_SH_LIST_DCN20(_MASK) +}; + +#define audio_regs(id)\ +[id] = {\ + AUD_COMMON_REG_LIST(id)\ +} + +static const struct dce_audio_registers audio_regs[] = { + audio_regs(0), + audio_regs(1), + audio_regs(2), + audio_regs(3), + audio_regs(4), + audio_regs(5), +}; + +#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ + AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) + +static const struct dce_audio_shift audio_shift = { + DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_audio_mask audio_mask = { + DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) +}; + +static const struct dccg_registers dccg_regs = { + DCCG_COMMON_REG_LIST_DCN_BASE() +}; + +static const struct dccg_shift dccg_shift = { + DCCG_MASK_SH_LIST_DCN2_1(__SHIFT) +}; + +static const struct dccg_mask dccg_mask = { + DCCG_MASK_SH_LIST_DCN2_1(_MASK) +}; + +#define opp_regs(id)\ +[id] = {\ + OPP_REG_LIST_DCN20(id),\ +} + +static const struct dcn20_opp_registers opp_regs[] = { + opp_regs(0), + opp_regs(1), + opp_regs(2), + opp_regs(3), + opp_regs(4), + opp_regs(5), +}; + +static const struct dcn20_opp_shift opp_shift = { + OPP_MASK_SH_LIST_DCN20(__SHIFT) +}; + +static const struct dcn20_opp_mask opp_mask = { + OPP_MASK_SH_LIST_DCN20(_MASK) +}; + +#define tg_regs(id)\ +[id] = {TG_COMMON_REG_LIST_DCN2_0(id)} + +static const struct dcn_optc_registers tg_regs[] = { + tg_regs(0), + tg_regs(1), + tg_regs(2), + tg_regs(3) +}; + +static const struct dcn_optc_shift tg_shift = { + TG_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) +}; + +static const struct dcn_optc_mask tg_mask = { + TG_COMMON_MASK_SH_LIST_DCN2_0(_MASK) +}; + +static const struct dcn20_mpc_registers mpc_regs = { + MPC_REG_LIST_DCN2_0(0), + MPC_REG_LIST_DCN2_0(1), + MPC_REG_LIST_DCN2_0(2), + MPC_REG_LIST_DCN2_0(3), + MPC_REG_LIST_DCN2_0(4), + MPC_REG_LIST_DCN2_0(5), + MPC_OUT_MUX_REG_LIST_DCN2_0(0), + MPC_OUT_MUX_REG_LIST_DCN2_0(1), + MPC_OUT_MUX_REG_LIST_DCN2_0(2), + MPC_OUT_MUX_REG_LIST_DCN2_0(3), + MPC_DBG_REG_LIST_DCN2_0() +}; + +static const struct dcn20_mpc_shift mpc_shift = { + MPC_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT), + MPC_DEBUG_REG_LIST_SH_DCN20 +}; + +static const struct dcn20_mpc_mask mpc_mask = { + MPC_COMMON_MASK_SH_LIST_DCN2_0(_MASK), + MPC_DEBUG_REG_LIST_MASK_DCN20 +}; + +#define hubp_regs(id)\ +[id] = {\ + HUBP_REG_LIST_DCN21(id)\ +} + +static const struct dcn_hubp2_registers hubp_regs[] = { + hubp_regs(0), + hubp_regs(1), + hubp_regs(2), + hubp_regs(3) +}; + +static const struct dcn_hubp2_shift hubp_shift = { + HUBP_MASK_SH_LIST_DCN21(__SHIFT) +}; + +static const struct dcn_hubp2_mask hubp_mask = { + HUBP_MASK_SH_LIST_DCN21(_MASK) +}; + +static const struct dcn_hubbub_registers hubbub_reg = { + HUBBUB_REG_LIST_DCN21() +}; + +static const struct dcn_hubbub_shift hubbub_shift = { + HUBBUB_MASK_SH_LIST_DCN21(__SHIFT) +}; + +static const struct dcn_hubbub_mask hubbub_mask = { + HUBBUB_MASK_SH_LIST_DCN21(_MASK) +}; + + +#define vmid_regs(id)\ +[id] = {\ + DCN20_VMID_REG_LIST(id)\ +} + +static const struct dcn_vmid_registers vmid_regs[] = { + vmid_regs(0), + vmid_regs(1), + vmid_regs(2), + vmid_regs(3), + vmid_regs(4), + vmid_regs(5), + vmid_regs(6), + vmid_regs(7), + vmid_regs(8), + vmid_regs(9), + vmid_regs(10), + vmid_regs(11), + vmid_regs(12), + vmid_regs(13), + vmid_regs(14), + vmid_regs(15) +}; + +static const struct dcn20_vmid_shift vmid_shifts = { + DCN20_VMID_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn20_vmid_mask vmid_masks = { + DCN20_VMID_MASK_SH_LIST(_MASK) +}; + +#define dsc_regsDCN20(id)\ +[id] = {\ + DSC_REG_LIST_DCN20(id)\ +} + +static const struct dcn20_dsc_registers dsc_regs[] = { + dsc_regsDCN20(0), + dsc_regsDCN20(1), + dsc_regsDCN20(2), + dsc_regsDCN20(3), + dsc_regsDCN20(4), + dsc_regsDCN20(5) +}; + +static const struct dcn20_dsc_shift dsc_shift = { + DSC_REG_LIST_SH_MASK_DCN20(__SHIFT) +}; + +static const struct dcn20_dsc_mask dsc_mask = { + DSC_REG_LIST_SH_MASK_DCN20(_MASK) +}; + +#define ipp_regs(id)\ +[id] = {\ + IPP_REG_LIST_DCN20(id),\ +} + +static const struct dcn10_ipp_registers ipp_regs[] = { + ipp_regs(0), + ipp_regs(1), + ipp_regs(2), + ipp_regs(3), +}; + +static const struct dcn10_ipp_shift ipp_shift = { + IPP_MASK_SH_LIST_DCN20(__SHIFT) +}; + +static const struct dcn10_ipp_mask ipp_mask = { + IPP_MASK_SH_LIST_DCN20(_MASK), +}; + +#define opp_regs(id)\ +[id] = {\ + OPP_REG_LIST_DCN20(id),\ +} + + +#define aux_engine_regs(id)\ +[id] = {\ + AUX_COMMON_REG_LIST0(id), \ + .AUXN_IMPCAL = 0, \ + .AUXP_IMPCAL = 0, \ + .AUX_RESET_MASK = DP_AUX0_AUX_CONTROL__AUX_RESET_MASK, \ +} + +static const struct dce110_aux_registers aux_engine_regs[] = { + aux_engine_regs(0), + aux_engine_regs(1), + aux_engine_regs(2), + aux_engine_regs(3), + aux_engine_regs(4), +}; + +#define tf_regs(id)\ +[id] = {\ + TF_REG_LIST_DCN20(id),\ + TF_REG_LIST_DCN20_COMMON_APPEND(id),\ +} + +static const struct dcn2_dpp_registers tf_regs[] = { + tf_regs(0), + tf_regs(1), + tf_regs(2), + tf_regs(3), +}; + +static const struct dcn2_dpp_shift tf_shift = { + TF_REG_LIST_SH_MASK_DCN20(__SHIFT), + TF_DEBUG_REG_LIST_SH_DCN20 +}; + +static const struct dcn2_dpp_mask tf_mask = { + TF_REG_LIST_SH_MASK_DCN20(_MASK), + TF_DEBUG_REG_LIST_MASK_DCN20 +}; + +#define stream_enc_regs(id)\ +[id] = {\ + SE_DCN2_REG_LIST(id)\ +} + +static const struct dcn10_stream_enc_registers stream_enc_regs[] = { + stream_enc_regs(0), + stream_enc_regs(1), + stream_enc_regs(2), + stream_enc_regs(3), + stream_enc_regs(4), +}; + +static const struct dce110_aux_registers_shift aux_shift = { + DCN_AUX_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce110_aux_registers_mask aux_mask = { + DCN_AUX_MASK_SH_LIST(_MASK) +}; + +static const struct dcn10_stream_encoder_shift se_shift = { + SE_COMMON_MASK_SH_LIST_DCN20(__SHIFT) +}; + +static const struct dcn10_stream_encoder_mask se_mask = { + SE_COMMON_MASK_SH_LIST_DCN20(_MASK) +}; + +static void dcn21_pp_smu_destroy(struct pp_smu_funcs **pp_smu); + +static struct input_pixel_processor *dcn21_ipp_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dcn10_ipp *ipp = + kzalloc(sizeof(struct dcn10_ipp), GFP_KERNEL); + + if (!ipp) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dcn20_ipp_construct(ipp, ctx, inst, + &ipp_regs[inst], &ipp_shift, &ipp_mask); + return &ipp->base; +} + +static struct dpp *dcn21_dpp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn20_dpp *dpp = + kzalloc(sizeof(struct dcn20_dpp), GFP_KERNEL); + + if (!dpp) + return NULL; + + if (dpp2_construct(dpp, ctx, inst, + &tf_regs[inst], &tf_shift, &tf_mask)) + return &dpp->base; + + BREAK_TO_DEBUGGER(); + kfree(dpp); + return NULL; +} + +static struct dce_aux *dcn21_aux_engine_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct aux_engine_dce110 *aux_engine = + kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); + + if (!aux_engine) + return NULL; + + dce110_aux_engine_construct(aux_engine, ctx, inst, + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, + &aux_engine_regs[inst], + &aux_mask, + &aux_shift, + ctx->dc->caps.extended_aux_timeout_support); + + return &aux_engine->base; +} + +#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST(id) } + +static const struct dce_i2c_registers i2c_hw_regs[] = { + i2c_inst_regs(1), + i2c_inst_regs(2), + i2c_inst_regs(3), + i2c_inst_regs(4), + i2c_inst_regs(5), +}; + +static const struct dce_i2c_shift i2c_shifts = { + I2C_COMMON_MASK_SH_LIST_DCN2(__SHIFT) +}; + +static const struct dce_i2c_mask i2c_masks = { + I2C_COMMON_MASK_SH_LIST_DCN2(_MASK) +}; + +static struct dce_i2c_hw *dcn21_i2c_hw_create(struct dc_context *ctx, + uint32_t inst) +{ + struct dce_i2c_hw *dce_i2c_hw = + kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); + + if (!dce_i2c_hw) + return NULL; + + dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst, + &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); + + return dce_i2c_hw; +} + +static const struct resource_caps res_cap_rn = { + .num_timing_generator = 4, + .num_opp = 4, + .num_video_plane = 4, + .num_audio = 4, // 4 audio endpoints. 4 audio streams + .num_stream_encoder = 5, + .num_pll = 5, // maybe 3 because the last two used for USB-c + .num_dwb = 1, + .num_ddc = 5, + .num_vmid = 16, + .num_dsc = 3, +}; + +#ifdef DIAGS_BUILD +static const struct resource_caps res_cap_rn_FPGA_4pipe = { + .num_timing_generator = 4, + .num_opp = 4, + .num_video_plane = 4, + .num_audio = 7, + .num_stream_encoder = 4, + .num_pll = 4, + .num_dwb = 1, + .num_ddc = 4, + .num_dsc = 0, +}; + +static const struct resource_caps res_cap_rn_FPGA_2pipe_dsc = { + .num_timing_generator = 2, + .num_opp = 2, + .num_video_plane = 2, + .num_audio = 7, + .num_stream_encoder = 2, + .num_pll = 4, + .num_dwb = 1, + .num_ddc = 4, + .num_dsc = 2, +}; +#endif + +static const struct dc_plane_cap plane_cap = { + .type = DC_PLANE_TYPE_DCN_UNIVERSAL, + .per_pixel_alpha = true, + + .pixel_format_support = { + .argb8888 = true, + .nv12 = true, + .fp16 = true, + .p010 = true + }, + + .max_upscale_factor = { + .argb8888 = 16000, + .nv12 = 16000, + .fp16 = 16000 + }, + + .max_downscale_factor = { + .argb8888 = 250, + .nv12 = 250, + .fp16 = 250 + }, + 64, + 64 +}; + +static const struct dc_debug_options debug_defaults_drv = { + .disable_dmcu = false, + .force_abm_enable = false, + .timing_trace = false, + .clock_trace = true, + .disable_pplib_clock_request = true, + .min_disp_clk_khz = 100000, + .pipe_split_policy = MPC_SPLIT_DYNAMIC, + .force_single_disp_pipe_split = false, + .disable_dcc = DCC_ENABLE, + .vsr_support = true, + .performance_trace = false, + .max_downscale_src_width = 4096, + .disable_pplib_wm_range = false, + .scl_reset_length10 = true, + .sanity_checks = true, + .disable_48mhz_pwrdwn = false, + .usbc_combo_phy_reset_wa = true, + .dmub_command_table = true, + .use_max_lb = true, + .enable_legacy_fast_update = true, + .using_dml2 = false, +}; + +static const struct dc_panel_config panel_config_defaults = { + .psr = { + .disable_psr = false, + .disallow_psrsu = false, + .disallow_replay = false, + }, + .ilr = { + .optimize_edp_link_rate = true, + }, +}; + +enum dcn20_clk_src_array_id { + DCN20_CLK_SRC_PLL0, + DCN20_CLK_SRC_PLL1, + DCN20_CLK_SRC_PLL2, + DCN20_CLK_SRC_PLL3, + DCN20_CLK_SRC_PLL4, + DCN20_CLK_SRC_TOTAL_DCN21 +}; + +static void dcn21_resource_destruct(struct dcn21_resource_pool *pool) +{ + unsigned int i; + + for (i = 0; i < pool->base.stream_enc_count; i++) { + if (pool->base.stream_enc[i] != NULL) { + kfree(DCN10STRENC_FROM_STRENC(pool->base.stream_enc[i])); + pool->base.stream_enc[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_dsc; i++) { + if (pool->base.dscs[i] != NULL) + dcn20_dsc_destroy(&pool->base.dscs[i]); + } + + if (pool->base.mpc != NULL) { + kfree(TO_DCN20_MPC(pool->base.mpc)); + pool->base.mpc = NULL; + } + if (pool->base.hubbub != NULL) { + kfree(pool->base.hubbub); + pool->base.hubbub = NULL; + } + for (i = 0; i < pool->base.pipe_count; i++) { + if (pool->base.dpps[i] != NULL) + dcn20_dpp_destroy(&pool->base.dpps[i]); + + if (pool->base.ipps[i] != NULL) + pool->base.ipps[i]->funcs->ipp_destroy(&pool->base.ipps[i]); + + if (pool->base.hubps[i] != NULL) { + kfree(TO_DCN20_HUBP(pool->base.hubps[i])); + pool->base.hubps[i] = NULL; + } + + if (pool->base.irqs != NULL) + dal_irq_service_destroy(&pool->base.irqs); + } + + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + if (pool->base.engines[i] != NULL) + dce110_engine_destroy(&pool->base.engines[i]); + if (pool->base.hw_i2cs[i] != NULL) { + kfree(pool->base.hw_i2cs[i]); + pool->base.hw_i2cs[i] = NULL; + } + if (pool->base.sw_i2cs[i] != NULL) { + kfree(pool->base.sw_i2cs[i]); + pool->base.sw_i2cs[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_opp; i++) { + if (pool->base.opps[i] != NULL) + pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]); + } + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + if (pool->base.timing_generators[i] != NULL) { + kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i])); + pool->base.timing_generators[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_dwb; i++) { + if (pool->base.dwbc[i] != NULL) { + kfree(TO_DCN20_DWBC(pool->base.dwbc[i])); + pool->base.dwbc[i] = NULL; + } + if (pool->base.mcif_wb[i] != NULL) { + kfree(TO_DCN20_MMHUBBUB(pool->base.mcif_wb[i])); + pool->base.mcif_wb[i] = NULL; + } + } + + for (i = 0; i < pool->base.audio_count; i++) { + if (pool->base.audios[i]) + dce_aud_destroy(&pool->base.audios[i]); + } + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] != NULL) { + dcn20_clock_source_destroy(&pool->base.clock_sources[i]); + pool->base.clock_sources[i] = NULL; + } + } + + if (pool->base.dp_clock_source != NULL) { + dcn20_clock_source_destroy(&pool->base.dp_clock_source); + pool->base.dp_clock_source = NULL; + } + + if (pool->base.abm != NULL) { + if (pool->base.abm->ctx->dc->config.disable_dmcu) + dmub_abm_destroy(&pool->base.abm); + else + dce_abm_destroy(&pool->base.abm); + } + + if (pool->base.dmcu != NULL) + dce_dmcu_destroy(&pool->base.dmcu); + + if (pool->base.psr != NULL) + dmub_psr_destroy(&pool->base.psr); + + if (pool->base.dccg != NULL) + dcn_dccg_destroy(&pool->base.dccg); + + if (pool->base.pp_smu != NULL) + dcn21_pp_smu_destroy(&pool->base.pp_smu); +} + +bool dcn21_fast_validate_bw(struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int *pipe_cnt_out, + int *pipe_split_from, + int *vlevel_out, + bool fast_validate) +{ + bool out = false; + int split[MAX_PIPES] = { 0 }; + int pipe_cnt, i, pipe_idx, vlevel; + + ASSERT(pipes); + if (!pipes) + return false; + + dcn20_merge_pipes_for_validate(dc, context); + + DC_FP_START(); + pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, context, pipes, fast_validate); + DC_FP_END(); + + *pipe_cnt_out = pipe_cnt; + + if (!pipe_cnt) { + out = true; + goto validate_out; + } + /* + * DML favors voltage over p-state, but we're more interested in + * supporting p-state over voltage. We can't support p-state in + * prefetch mode > 0 so try capping the prefetch mode to start. + */ + context->bw_ctx.dml.soc.allow_dram_self_refresh_or_dram_clock_change_in_vblank = + dm_allow_self_refresh_and_mclk_switch; + vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt); + + if (vlevel > context->bw_ctx.dml.soc.num_states) { + /* + * 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. + */ + context->bw_ctx.dml.soc.allow_dram_self_refresh_or_dram_clock_change_in_vblank = + dm_allow_self_refresh; + vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt); + if (vlevel > context->bw_ctx.dml.soc.num_states) + goto validate_fail; + } + + vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, vlevel, split, NULL); + + for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + struct pipe_ctx *mpo_pipe = pipe->bottom_pipe; + struct vba_vars_st *vba = &context->bw_ctx.dml.vba; + + if (!pipe->stream) + continue; + + /* We only support full screen mpo with ODM */ + if (vba->ODMCombineEnabled[vba->pipe_plane[pipe_idx]] != dm_odm_combine_mode_disabled + && pipe->plane_state && mpo_pipe + && memcmp(&mpo_pipe->plane_state->clip_rect, + &pipe->stream->src, + sizeof(struct rect)) != 0) { + ASSERT(mpo_pipe->plane_state != pipe->plane_state); + goto validate_fail; + } + pipe_idx++; + } + + /*initialize pipe_just_split_from to invalid idx*/ + for (i = 0; i < MAX_PIPES; i++) + pipe_split_from[i] = -1; + + for (i = 0, pipe_idx = -1; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + struct pipe_ctx *hsplit_pipe = pipe->bottom_pipe; + + if (!pipe->stream || pipe_split_from[i] >= 0) + continue; + + pipe_idx++; + + if (!pipe->top_pipe && !pipe->plane_state && context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_idx]) { + hsplit_pipe = dcn20_find_secondary_pipe(dc, &context->res_ctx, dc->res_pool, pipe); + ASSERT(hsplit_pipe); + if (!dcn20_split_stream_for_odm( + dc, &context->res_ctx, + pipe, hsplit_pipe)) + goto validate_fail; + pipe_split_from[hsplit_pipe->pipe_idx] = pipe_idx; + dcn20_build_mapped_resource(dc, context, pipe->stream); + } + + if (!pipe->plane_state) + continue; + /* Skip 2nd half of already split pipe */ + if (pipe->top_pipe && pipe->plane_state == pipe->top_pipe->plane_state) + continue; + + if (split[i] == 2) { + if (!hsplit_pipe || hsplit_pipe->plane_state != pipe->plane_state) { + /* pipe not split previously needs split */ + hsplit_pipe = dcn20_find_secondary_pipe(dc, &context->res_ctx, dc->res_pool, pipe); + ASSERT(hsplit_pipe); + if (!hsplit_pipe) { + DC_FP_START(); + dcn20_fpu_adjust_dppclk(&context->bw_ctx.dml.vba, vlevel, context->bw_ctx.dml.vba.maxMpcComb, pipe_idx, true); + DC_FP_END(); + continue; + } + if (context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_idx]) { + if (!dcn20_split_stream_for_odm( + dc, &context->res_ctx, + pipe, hsplit_pipe)) + goto validate_fail; + dcn20_build_mapped_resource(dc, context, pipe->stream); + } else { + dcn20_split_stream_for_mpc( + &context->res_ctx, dc->res_pool, + pipe, hsplit_pipe); + resource_build_scaling_params(pipe); + resource_build_scaling_params(hsplit_pipe); + } + pipe_split_from[hsplit_pipe->pipe_idx] = pipe_idx; + } + } else if (hsplit_pipe && hsplit_pipe->plane_state == pipe->plane_state) { + /* merge should already have been done */ + ASSERT(0); + } + } + /* Actual dsc count per stream dsc validation*/ + if (!dcn20_validate_dsc(dc, context)) { + context->bw_ctx.dml.vba.ValidationStatus[context->bw_ctx.dml.vba.soc.num_states] = + DML_FAIL_DSC_VALIDATION_FAILURE; + goto validate_fail; + } + + *vlevel_out = vlevel; + + out = true; + goto validate_out; + +validate_fail: + out = false; + +validate_out: + return out; +} + +/* + * Some of the functions further below use the FPU, so we need to wrap this + * with DC_FP_START()/DC_FP_END(). Use the same approach as for + * dcn20_validate_bandwidth in dcn20_resource.c. + */ +static bool dcn21_validate_bandwidth(struct dc *dc, struct dc_state *context, + bool fast_validate) +{ + bool voltage_supported; + display_e2e_pipe_params_st *pipes; + + pipes = kcalloc(dc->res_pool->pipe_count, sizeof(display_e2e_pipe_params_st), GFP_KERNEL); + if (!pipes) + return false; + + DC_FP_START(); + voltage_supported = dcn21_validate_bandwidth_fp(dc, context, fast_validate, pipes); + DC_FP_END(); + + kfree(pipes); + return voltage_supported; +} + +static void dcn21_destroy_resource_pool(struct resource_pool **pool) +{ + struct dcn21_resource_pool *dcn21_pool = TO_DCN21_RES_POOL(*pool); + + dcn21_resource_destruct(dcn21_pool); + kfree(dcn21_pool); + *pool = NULL; +} + +static struct clock_source *dcn21_clock_source_create( + struct dc_context *ctx, + struct dc_bios *bios, + enum clock_source_id id, + const struct dce110_clk_src_regs *regs, + bool dp_clk_src) +{ + struct dce110_clk_src *clk_src = + kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); + + if (!clk_src) + return NULL; + + if (dcn20_clk_src_construct(clk_src, ctx, bios, id, + regs, &cs_shift, &cs_mask)) { + clk_src->base.dp_clk_src = dp_clk_src; + return &clk_src->base; + } + + kfree(clk_src); + BREAK_TO_DEBUGGER(); + return NULL; +} + +static struct hubp *dcn21_hubp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn21_hubp *hubp21 = + kzalloc(sizeof(struct dcn21_hubp), GFP_KERNEL); + + if (!hubp21) + return NULL; + + if (hubp21_construct(hubp21, ctx, inst, + &hubp_regs[inst], &hubp_shift, &hubp_mask)) + return &hubp21->base; + + BREAK_TO_DEBUGGER(); + kfree(hubp21); + return NULL; +} + +static struct hubbub *dcn21_hubbub_create(struct dc_context *ctx) +{ + int i; + + struct dcn20_hubbub *hubbub = kzalloc(sizeof(struct dcn20_hubbub), + GFP_KERNEL); + + if (!hubbub) + return NULL; + + hubbub21_construct(hubbub, ctx, + &hubbub_reg, + &hubbub_shift, + &hubbub_mask); + + for (i = 0; i < res_cap_rn.num_vmid; i++) { + struct dcn20_vmid *vmid = &hubbub->vmid[i]; + + vmid->ctx = ctx; + + vmid->regs = &vmid_regs[i]; + vmid->shifts = &vmid_shifts; + vmid->masks = &vmid_masks; + } + hubbub->num_vmid = res_cap_rn.num_vmid; + + return &hubbub->base; +} + +static struct output_pixel_processor *dcn21_opp_create(struct dc_context *ctx, + uint32_t inst) +{ + struct dcn20_opp *opp = + kzalloc(sizeof(struct dcn20_opp), GFP_KERNEL); + + if (!opp) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dcn20_opp_construct(opp, ctx, inst, + &opp_regs[inst], &opp_shift, &opp_mask); + return &opp->base; +} + +static struct timing_generator *dcn21_timing_generator_create(struct dc_context *ctx, + uint32_t instance) +{ + struct optc *tgn10 = + kzalloc(sizeof(struct optc), GFP_KERNEL); + + if (!tgn10) + return NULL; + + tgn10->base.inst = instance; + tgn10->base.ctx = ctx; + + tgn10->tg_regs = &tg_regs[instance]; + tgn10->tg_shift = &tg_shift; + tgn10->tg_mask = &tg_mask; + + dcn20_timing_generator_init(tgn10); + + return &tgn10->base; +} + +static struct mpc *dcn21_mpc_create(struct dc_context *ctx) +{ + struct dcn20_mpc *mpc20 = kzalloc(sizeof(struct dcn20_mpc), + GFP_KERNEL); + + if (!mpc20) + return NULL; + + dcn20_mpc_construct(mpc20, ctx, + &mpc_regs, + &mpc_shift, + &mpc_mask, + 6); + + return &mpc20->base; +} + +static void read_dce_straps( + struct dc_context *ctx, + struct resource_straps *straps) +{ + generic_reg_get(ctx, mmDC_PINSTRAPS + BASE(mmDC_PINSTRAPS_BASE_IDX), + FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio); + +} + + +static struct display_stream_compressor *dcn21_dsc_create(struct dc_context *ctx, + uint32_t inst) +{ + struct dcn20_dsc *dsc = + kzalloc(sizeof(struct dcn20_dsc), GFP_KERNEL); + + if (!dsc) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dsc2_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask); + return &dsc->base; +} + +static struct pp_smu_funcs *dcn21_pp_smu_create(struct dc_context *ctx) +{ + struct pp_smu_funcs *pp_smu = kzalloc(sizeof(*pp_smu), GFP_KERNEL); + + if (!pp_smu) + return pp_smu; + + dm_pp_get_funcs(ctx, pp_smu); + + if (pp_smu->ctx.ver != PP_SMU_VER_RN) + pp_smu = memset(pp_smu, 0, sizeof(struct pp_smu_funcs)); + + + return pp_smu; +} + +static void dcn21_pp_smu_destroy(struct pp_smu_funcs **pp_smu) +{ + if (pp_smu && *pp_smu) { + kfree(*pp_smu); + *pp_smu = NULL; + } +} + +static struct audio *dcn21_create_audio( + struct dc_context *ctx, unsigned int inst) +{ + return dce_audio_create(ctx, inst, + &audio_regs[inst], &audio_shift, &audio_mask); +} + +static struct dc_cap_funcs cap_funcs = { + .get_dcc_compression_cap = dcn20_get_dcc_compression_cap +}; + +static struct stream_encoder *dcn21_stream_encoder_create(enum engine_id eng_id, + struct dc_context *ctx) +{ + struct dcn10_stream_encoder *enc1 = + kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL); + + if (!enc1) + return NULL; + + dcn20_stream_encoder_construct(enc1, ctx, ctx->dc_bios, eng_id, + &stream_enc_regs[eng_id], + &se_shift, &se_mask); + + return &enc1->base; +} + +static const struct dce_hwseq_registers hwseq_reg = { + HWSEQ_DCN21_REG_LIST() +}; + +static const struct dce_hwseq_shift hwseq_shift = { + HWSEQ_DCN21_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_hwseq_mask hwseq_mask = { + HWSEQ_DCN21_MASK_SH_LIST(_MASK) +}; + +static struct dce_hwseq *dcn21_hwseq_create( + struct dc_context *ctx) +{ + struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); + + if (hws) { + hws->ctx = ctx; + hws->regs = &hwseq_reg; + hws->shifts = &hwseq_shift; + hws->masks = &hwseq_mask; + hws->wa.DEGVIDCN21 = true; + hws->wa.disallow_self_refresh_during_multi_plane_transition = true; + } + return hws; +} + +static const struct resource_create_funcs res_create_funcs = { + .read_dce_straps = read_dce_straps, + .create_audio = dcn21_create_audio, + .create_stream_encoder = dcn21_stream_encoder_create, + .create_hwseq = dcn21_hwseq_create, +}; + +static const struct encoder_feature_support link_enc_feature = { + .max_hdmi_deep_color = COLOR_DEPTH_121212, + .max_hdmi_pixel_clock = 600000, + .hdmi_ycbcr420_supported = true, + .dp_ycbcr420_supported = true, + .fec_supported = true, + .flags.bits.IS_HBR2_CAPABLE = true, + .flags.bits.IS_HBR3_CAPABLE = true, + .flags.bits.IS_TPS3_CAPABLE = true, + .flags.bits.IS_TPS4_CAPABLE = true +}; + + +#define link_regs(id, phyid)\ +[id] = {\ + LE_DCN2_REG_LIST(id), \ + UNIPHY_DCN2_REG_LIST(phyid), \ + DPCS_DCN21_REG_LIST(id), \ + SRI(DP_DPHY_INTERNAL_CTRL, DP, id) \ +} + +static const struct dcn10_link_enc_registers link_enc_regs[] = { + link_regs(0, A), + link_regs(1, B), + link_regs(2, C), + link_regs(3, D), + link_regs(4, E), +}; + +static const struct dce_panel_cntl_registers panel_cntl_regs[] = { + { DCN_PANEL_CNTL_REG_LIST() } +}; + +static const struct dce_panel_cntl_shift panel_cntl_shift = { + DCE_PANEL_CNTL_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_panel_cntl_mask panel_cntl_mask = { + DCE_PANEL_CNTL_MASK_SH_LIST(_MASK) +}; + +#define aux_regs(id)\ +[id] = {\ + DCN2_AUX_REG_LIST(id)\ +} + +static const struct dcn10_link_enc_aux_registers link_enc_aux_regs[] = { + aux_regs(0), + aux_regs(1), + aux_regs(2), + aux_regs(3), + aux_regs(4) +}; + +#define hpd_regs(id)\ +[id] = {\ + HPD_REG_LIST(id)\ +} + +static const struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[] = { + hpd_regs(0), + hpd_regs(1), + hpd_regs(2), + hpd_regs(3), + hpd_regs(4) +}; + +static const struct dcn10_link_enc_shift le_shift = { + LINK_ENCODER_MASK_SH_LIST_DCN20(__SHIFT),\ + DPCS_DCN21_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn10_link_enc_mask le_mask = { + LINK_ENCODER_MASK_SH_LIST_DCN20(_MASK),\ + DPCS_DCN21_MASK_SH_LIST(_MASK) +}; + +static int map_transmitter_id_to_phy_instance( + enum transmitter transmitter) +{ + switch (transmitter) { + case TRANSMITTER_UNIPHY_A: + return 0; + break; + case TRANSMITTER_UNIPHY_B: + return 1; + break; + case TRANSMITTER_UNIPHY_C: + return 2; + break; + case TRANSMITTER_UNIPHY_D: + return 3; + break; + case TRANSMITTER_UNIPHY_E: + return 4; + break; + default: + ASSERT(0); + return 0; + } +} + +static struct link_encoder *dcn21_link_encoder_create( + struct dc_context *ctx, + const struct encoder_init_data *enc_init_data) +{ + struct dcn21_link_encoder *enc21 = + kzalloc(sizeof(struct dcn21_link_encoder), GFP_KERNEL); + int link_regs_id; + + if (!enc21) + return NULL; + + link_regs_id = + map_transmitter_id_to_phy_instance(enc_init_data->transmitter); + + dcn21_link_encoder_construct(enc21, + enc_init_data, + &link_enc_feature, + &link_enc_regs[link_regs_id], + &link_enc_aux_regs[enc_init_data->channel - 1], + &link_enc_hpd_regs[enc_init_data->hpd_source], + &le_shift, + &le_mask); + + return &enc21->enc10.base; +} + +static struct panel_cntl *dcn21_panel_cntl_create(const struct panel_cntl_init_data *init_data) +{ + struct dce_panel_cntl *panel_cntl = + kzalloc(sizeof(struct dce_panel_cntl), GFP_KERNEL); + + if (!panel_cntl) + return NULL; + + dce_panel_cntl_construct(panel_cntl, + init_data, + &panel_cntl_regs[init_data->inst], + &panel_cntl_shift, + &panel_cntl_mask); + + return &panel_cntl->base; +} + +static void dcn21_get_panel_config_defaults(struct dc_panel_config *panel_config) +{ + *panel_config = panel_config_defaults; +} + +#define CTX ctx + +#define REG(reg_name) \ + (DCN_BASE.instance[0].segment[mm ## reg_name ## _BASE_IDX] + mm ## reg_name) + +static uint32_t read_pipe_fuses(struct dc_context *ctx) +{ + uint32_t value = REG_READ(CC_DC_PIPE_DIS); + /* RV1 support max 4 pipes */ + value = value & 0xf; + return value; +} + +static enum dc_status dcn21_patch_unknown_plane_state(struct dc_plane_state *plane_state) +{ + 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; + } + + return dcn20_patch_unknown_plane_state(plane_state); +} + +static const struct resource_funcs dcn21_res_pool_funcs = { + .destroy = dcn21_destroy_resource_pool, + .link_enc_create = dcn21_link_encoder_create, + .panel_cntl_create = dcn21_panel_cntl_create, + .validate_bandwidth = dcn21_validate_bandwidth, + .populate_dml_pipes = dcn21_populate_dml_pipes_from_context, + .add_stream_to_ctx = dcn20_add_stream_to_ctx, + .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource, + .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, + .acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer, + .release_pipe = dcn20_release_pipe, + .populate_dml_writeback_from_context = dcn20_populate_dml_writeback_from_context, + .patch_unknown_plane_state = dcn21_patch_unknown_plane_state, + .set_mcif_arb_params = dcn20_set_mcif_arb_params, + .find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link, + .update_bw_bounding_box = dcn21_update_bw_bounding_box, + .get_panel_config_defaults = dcn21_get_panel_config_defaults, +}; + +static bool dcn21_resource_construct( + uint8_t num_virtual_links, + struct dc *dc, + struct dcn21_resource_pool *pool) +{ + int i, j; + struct dc_context *ctx = dc->ctx; + struct irq_service_init_data init_data; + uint32_t pipe_fuses = read_pipe_fuses(ctx); + uint32_t num_pipes; + + ctx->dc_bios->regs = &bios_regs; + + pool->base.res_cap = &res_cap_rn; +#ifdef DIAGS_BUILD + if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) + //pool->base.res_cap = &res_cap_nv10_FPGA_2pipe_dsc; + pool->base.res_cap = &res_cap_rn_FPGA_4pipe; +#endif + + pool->base.funcs = &dcn21_res_pool_funcs; + + /************************************************* + * Resource + asic cap harcoding * + *************************************************/ + pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + + /* max pipe num for ASIC before check pipe fuses */ + pool->base.pipe_count = pool->base.res_cap->num_timing_generator; + + dc->caps.max_downscale_ratio = 200; + dc->caps.i2c_speed_in_khz = 100; + dc->caps.i2c_speed_in_khz_hdcp = 5; /*1.4 w/a applied by default*/ + dc->caps.max_cursor_size = 256; + dc->caps.min_horizontal_blanking_period = 80; + dc->caps.dmdata_alloc_size = 2048; + + dc->caps.max_slave_planes = 1; + dc->caps.max_slave_yuv_planes = 1; + dc->caps.max_slave_rgb_planes = 1; + dc->caps.post_blend_color_processing = true; + dc->caps.force_dp_tps4_for_cp2520 = true; + dc->caps.extended_aux_timeout_support = true; + dc->caps.dmcub_support = true; + dc->caps.is_apu = true; + + /* Color pipeline capabilities */ + dc->caps.color.dpp.dcn_arch = 1; + dc->caps.color.dpp.input_lut_shared = 0; + dc->caps.color.dpp.icsc = 1; + dc->caps.color.dpp.dgam_ram = 1; + dc->caps.color.dpp.dgam_rom_caps.srgb = 1; + dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1; + dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 0; + dc->caps.color.dpp.dgam_rom_caps.pq = 0; + dc->caps.color.dpp.dgam_rom_caps.hlg = 0; + dc->caps.color.dpp.post_csc = 0; + dc->caps.color.dpp.gamma_corr = 0; + dc->caps.color.dpp.dgam_rom_for_yuv = 1; + + dc->caps.color.dpp.hw_3d_lut = 1; + dc->caps.color.dpp.ogam_ram = 1; + // no OGAM ROM on DCN2 + dc->caps.color.dpp.ogam_rom_caps.srgb = 0; + dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0; + dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0; + dc->caps.color.dpp.ogam_rom_caps.pq = 0; + dc->caps.color.dpp.ogam_rom_caps.hlg = 0; + dc->caps.color.dpp.ocsc = 0; + + dc->caps.color.mpc.gamut_remap = 0; + dc->caps.color.mpc.num_3dluts = 0; + dc->caps.color.mpc.shared_3d_lut = 0; + dc->caps.color.mpc.ogam_ram = 1; + dc->caps.color.mpc.ogam_rom_caps.srgb = 0; + dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0; + dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0; + dc->caps.color.mpc.ogam_rom_caps.pq = 0; + dc->caps.color.mpc.ogam_rom_caps.hlg = 0; + dc->caps.color.mpc.ocsc = 1; + + dc->caps.dp_hdmi21_pcon_support = true; + + if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) + dc->debug = debug_defaults_drv; + + // Init the vm_helper + if (dc->vm_helper) + vm_helper_init(dc->vm_helper, 16); + + /************************************************* + * Create resources * + *************************************************/ + + pool->base.clock_sources[DCN20_CLK_SRC_PLL0] = + dcn21_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL0, + &clk_src_regs[0], false); + pool->base.clock_sources[DCN20_CLK_SRC_PLL1] = + dcn21_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL1, + &clk_src_regs[1], false); + pool->base.clock_sources[DCN20_CLK_SRC_PLL2] = + dcn21_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL2, + &clk_src_regs[2], false); + pool->base.clock_sources[DCN20_CLK_SRC_PLL3] = + dcn21_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL3, + &clk_src_regs[3], false); + pool->base.clock_sources[DCN20_CLK_SRC_PLL4] = + dcn21_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL4, + &clk_src_regs[4], false); + + pool->base.clk_src_count = DCN20_CLK_SRC_TOTAL_DCN21; + + /* todo: not reuse phy_pll registers */ + pool->base.dp_clock_source = + dcn21_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_ID_DP_DTO, + &clk_src_regs[0], true); + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] == NULL) { + dm_error("DC: failed to create clock sources!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + } + + pool->base.dccg = dccg21_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask); + if (pool->base.dccg == NULL) { + dm_error("DC: failed to create dccg!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + if (!dc->config.disable_dmcu) { + pool->base.dmcu = dcn21_dmcu_create(ctx, + &dmcu_regs, + &dmcu_shift, + &dmcu_mask); + if (pool->base.dmcu == NULL) { + dm_error("DC: failed to create dmcu!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + dc->debug.dmub_command_table = false; + } + + if (dc->config.disable_dmcu) { + pool->base.psr = dmub_psr_create(ctx); + + if (pool->base.psr == NULL) { + dm_error("DC: failed to create psr obj!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + } + + if (dc->config.disable_dmcu) + pool->base.abm = dmub_abm_create(ctx, + &abm_regs, + &abm_shift, + &abm_mask); + else + pool->base.abm = dce_abm_create(ctx, + &abm_regs, + &abm_shift, + &abm_mask); + + pool->base.pp_smu = dcn21_pp_smu_create(ctx); + + num_pipes = dcn2_1_ip.max_num_dpp; + + for (i = 0; i < dcn2_1_ip.max_num_dpp; i++) + if (pipe_fuses & 1 << i) + num_pipes--; + dcn2_1_ip.max_num_dpp = num_pipes; + dcn2_1_ip.max_num_otg = num_pipes; + + dml_init_instance(&dc->dml, &dcn2_1_soc, &dcn2_1_ip, DML_PROJECT_DCN21); + + init_data.ctx = dc->ctx; + pool->base.irqs = dal_irq_service_dcn21_create(&init_data); + if (!pool->base.irqs) + goto create_fail; + + j = 0; + /* mem input -> ipp -> dpp -> opp -> TG */ + for (i = 0; i < pool->base.pipe_count; i++) { + /* if pipe is disabled, skip instance of HW pipe, + * i.e, skip ASIC register instance + */ + if ((pipe_fuses & (1 << i)) != 0) + continue; + + pool->base.hubps[j] = dcn21_hubp_create(ctx, i); + if (pool->base.hubps[j] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create memory input!\n"); + goto create_fail; + } + + pool->base.ipps[j] = dcn21_ipp_create(ctx, i); + if (pool->base.ipps[j] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create input pixel processor!\n"); + goto create_fail; + } + + pool->base.dpps[j] = dcn21_dpp_create(ctx, i); + if (pool->base.dpps[j] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create dpps!\n"); + goto create_fail; + } + + pool->base.opps[j] = dcn21_opp_create(ctx, i); + if (pool->base.opps[j] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create output pixel processor!\n"); + goto create_fail; + } + + pool->base.timing_generators[j] = dcn21_timing_generator_create( + ctx, i); + if (pool->base.timing_generators[j] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create tg!\n"); + goto create_fail; + } + j++; + } + + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + pool->base.engines[i] = dcn21_aux_engine_create(ctx, i); + if (pool->base.engines[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create aux engine!!\n"); + goto create_fail; + } + pool->base.hw_i2cs[i] = dcn21_i2c_hw_create(ctx, i); + if (pool->base.hw_i2cs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create hw i2c!!\n"); + goto create_fail; + } + pool->base.sw_i2cs[i] = NULL; + } + + pool->base.timing_generator_count = j; + pool->base.pipe_count = j; + pool->base.mpcc_count = j; + + pool->base.mpc = dcn21_mpc_create(ctx); + if (pool->base.mpc == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create mpc!\n"); + goto create_fail; + } + + pool->base.hubbub = dcn21_hubbub_create(ctx); + if (pool->base.hubbub == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create hubbub!\n"); + goto create_fail; + } + + for (i = 0; i < pool->base.res_cap->num_dsc; i++) { + pool->base.dscs[i] = dcn21_dsc_create(ctx, i); + if (pool->base.dscs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create display stream compressor %d!\n", i); + goto create_fail; + } + } + + if (!dcn20_dwbc_create(ctx, &pool->base)) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dwbc!\n"); + goto create_fail; + } + if (!dcn20_mmhubbub_create(ctx, &pool->base)) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create mcif_wb!\n"); + goto create_fail; + } + + if (!resource_construct(num_virtual_links, dc, &pool->base, + &res_create_funcs)) + goto create_fail; + + dcn21_hw_sequencer_construct(dc); + + dc->caps.max_planes = pool->base.pipe_count; + + for (i = 0; i < dc->caps.max_planes; ++i) + dc->caps.planes[i] = plane_cap; + + dc->cap_funcs = cap_funcs; + + return true; + +create_fail: + + dcn21_resource_destruct(pool); + + return false; +} + +struct resource_pool *dcn21_create_resource_pool( + const struct dc_init_data *init_data, + struct dc *dc) +{ + struct dcn21_resource_pool *pool = + kzalloc(sizeof(struct dcn21_resource_pool), GFP_KERNEL); + + if (!pool) + return NULL; + + if (dcn21_resource_construct(init_data->num_virtual_links, dc, pool)) + return &pool->base; + + BREAK_TO_DEBUGGER(); + kfree(pool); + return NULL; +} diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.h new file mode 100644 index 00000000000000..f7ecc002c2f7f6 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.h @@ -0,0 +1,56 @@ +/* + * Copyright 2018 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 _DCN21_RESOURCE_H_ +#define _DCN21_RESOURCE_H_ + +#include "core_types.h" + +#define TO_DCN21_RES_POOL(pool)\ + container_of(pool, struct dcn21_resource_pool, base) + +struct dc; +struct resource_pool; +struct _vcs_dpi_display_pipe_params_st; + +extern struct _vcs_dpi_ip_params_st dcn2_1_ip; +extern struct _vcs_dpi_soc_bounding_box_st dcn2_1_soc; + +struct dcn21_resource_pool { + struct resource_pool base; +}; +struct resource_pool *dcn21_create_resource_pool( + const struct dc_init_data *init_data, + struct dc *dc); +bool dcn21_fast_validate_bw( + struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int *pipe_cnt_out, + int *pipe_split_from, + int *vlevel_out, + bool fast_validate); + +#endif /* _DCN21_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c new file mode 100644 index 00000000000000..37a64186f3241a --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c @@ -0,0 +1,2613 @@ +/* + * Copyright 2020 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 "dcn30/dcn30_init.h" + +#include "resource.h" +#include "include/irq_service_interface.h" +#include "dcn20/dcn20_resource.h" + +#include "dcn30_resource.h" + +#include "dcn10/dcn10_ipp.h" +#include "dcn30/dcn30_hubbub.h" +#include "dcn30/dcn30_mpc.h" +#include "dcn30/dcn30_hubp.h" +#include "irq/dcn30/irq_service_dcn30.h" +#include "dcn30/dcn30_dpp.h" +#include "dcn30/dcn30_optc.h" +#include "dcn20/dcn20_hwseq.h" +#include "dcn30/dcn30_hwseq.h" +#include "dce110/dce110_hwseq.h" +#include "dcn30/dcn30_opp.h" +#include "dcn20/dcn20_dsc.h" +#include "dcn30/dcn30_vpg.h" +#include "dcn30/dcn30_afmt.h" +#include "dcn30/dcn30_dio_stream_encoder.h" +#include "dcn30/dcn30_dio_link_encoder.h" +#include "dce/dce_clock_source.h" +#include "dce/dce_audio.h" +#include "dce/dce_hwseq.h" +#include "clk_mgr.h" +#include "virtual/virtual_stream_encoder.h" +#include "dce110/dce110_resource.h" +#include "dml/display_mode_vba.h" +#include "dcn30/dcn30_dccg.h" +#include "dcn10/dcn10_resource.h" +#include "link.h" +#include "dce/dce_panel_cntl.h" + +#include "dcn30/dcn30_dwb.h" +#include "dcn30/dcn30_mmhubbub.h" + +#include "sienna_cichlid_ip_offset.h" +#include "dcn/dcn_3_0_0_offset.h" +#include "dcn/dcn_3_0_0_sh_mask.h" + +#include "nbio/nbio_7_4_offset.h" + +#include "dpcs/dpcs_3_0_0_offset.h" +#include "dpcs/dpcs_3_0_0_sh_mask.h" + +#include "mmhub/mmhub_2_0_0_offset.h" +#include "mmhub/mmhub_2_0_0_sh_mask.h" + +#include "reg_helper.h" +#include "dce/dmub_abm.h" +#include "dce/dmub_psr.h" +#include "dce/dce_aux.h" +#include "dce/dce_i2c.h" + +#include "dml/dcn30/dcn30_fpu.h" +#include "dml/dcn30/display_mode_vba_30.h" +#include "vm_helper.h" +#include "dcn20/dcn20_vmid.h" +#include "amdgpu_socbb.h" +#include "dc_dmub_srv.h" + +#define DC_LOGGER \ + dc->ctx->logger +#define DC_LOGGER_INIT(logger) + +enum dcn30_clk_src_array_id { + DCN30_CLK_SRC_PLL0, + DCN30_CLK_SRC_PLL1, + DCN30_CLK_SRC_PLL2, + DCN30_CLK_SRC_PLL3, + DCN30_CLK_SRC_PLL4, + DCN30_CLK_SRC_PLL5, + DCN30_CLK_SRC_TOTAL +}; + +/* begin ********************* + * macros to expend register list macro defined in HW object header file + */ + +/* DCN */ +#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg + +#define BASE(seg) BASE_INNER(seg) + +#define SR(reg_name)\ + .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + \ + mm ## reg_name + +#define SRI(reg_name, block, id)\ + .reg_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define SRI2(reg_name, block, id)\ + .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + \ + mm ## reg_name + +#define SRIR(var_name, reg_name, block, id)\ + .var_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define SRII(reg_name, block, id)\ + .reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define SRII_MPC_RMU(reg_name, block, id)\ + .RMU##_##reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define SRII_DWB(reg_name, temp_name, block, id)\ + .reg_name[id] = BASE(mm ## block ## id ## _ ## temp_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## temp_name + +#define SF_DWB2(reg_name, block, id, field_name, post_fix) \ + .field_name = reg_name ## __ ## field_name ## post_fix + +#define DCCG_SRII(reg_name, block, id)\ + .block ## _ ## reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define VUPDATE_SRII(reg_name, block, id)\ + .reg_name[id] = BASE(mm ## reg_name ## _ ## block ## id ## _BASE_IDX) + \ + mm ## reg_name ## _ ## block ## id + +/* NBIO */ +#define NBIO_BASE_INNER(seg) \ + NBIO_BASE__INST0_SEG ## seg + +#define NBIO_BASE(seg) \ + NBIO_BASE_INNER(seg) + +#define NBIO_SR(reg_name)\ + .reg_name = NBIO_BASE(mm ## reg_name ## _BASE_IDX) + \ + mm ## reg_name + +/* MMHUB */ +#define MMHUB_BASE_INNER(seg) \ + MMHUB_BASE__INST0_SEG ## seg + +#define MMHUB_BASE(seg) \ + MMHUB_BASE_INNER(seg) + +#define MMHUB_SR(reg_name)\ + .reg_name = MMHUB_BASE(mmMM ## reg_name ## _BASE_IDX) + \ + mmMM ## reg_name + +/* CLOCK */ +#define CLK_BASE_INNER(seg) \ + CLK_BASE__INST0_SEG ## seg + +#define CLK_BASE(seg) \ + CLK_BASE_INNER(seg) + +#define CLK_SRI(reg_name, block, inst)\ + .reg_name = CLK_BASE(mm ## block ## _ ## inst ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## _ ## inst ## _ ## reg_name + + +static const struct bios_registers bios_regs = { + NBIO_SR(BIOS_SCRATCH_3), + NBIO_SR(BIOS_SCRATCH_6) +}; + +#define clk_src_regs(index, pllid)\ +[index] = {\ + CS_COMMON_REG_LIST_DCN2_0(index, pllid),\ +} + +static const struct dce110_clk_src_regs clk_src_regs[] = { + clk_src_regs(0, A), + clk_src_regs(1, B), + clk_src_regs(2, C), + clk_src_regs(3, D), + clk_src_regs(4, E), + clk_src_regs(5, F) +}; + +static const struct dce110_clk_src_shift cs_shift = { + CS_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) +}; + +static const struct dce110_clk_src_mask cs_mask = { + CS_COMMON_MASK_SH_LIST_DCN2_0(_MASK) +}; + +#define abm_regs(id)\ +[id] = {\ + ABM_DCN30_REG_LIST(id)\ +} + +static const struct dce_abm_registers abm_regs[] = { + abm_regs(0), + abm_regs(1), + abm_regs(2), + abm_regs(3), + abm_regs(4), + abm_regs(5), +}; + +static const struct dce_abm_shift abm_shift = { + ABM_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dce_abm_mask abm_mask = { + ABM_MASK_SH_LIST_DCN30(_MASK) +}; + + + +#define audio_regs(id)\ +[id] = {\ + AUD_COMMON_REG_LIST(id)\ +} + +static const struct dce_audio_registers audio_regs[] = { + audio_regs(0), + audio_regs(1), + audio_regs(2), + audio_regs(3), + audio_regs(4), + audio_regs(5), + audio_regs(6) +}; + +#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ + AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) + +static const struct dce_audio_shift audio_shift = { + DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_audio_mask audio_mask = { + DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) +}; + +#define vpg_regs(id)\ +[id] = {\ + VPG_DCN3_REG_LIST(id)\ +} + +static const struct dcn30_vpg_registers vpg_regs[] = { + vpg_regs(0), + vpg_regs(1), + vpg_regs(2), + vpg_regs(3), + vpg_regs(4), + vpg_regs(5), + vpg_regs(6), +}; + +static const struct dcn30_vpg_shift vpg_shift = { + DCN3_VPG_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn30_vpg_mask vpg_mask = { + DCN3_VPG_MASK_SH_LIST(_MASK) +}; + +#define afmt_regs(id)\ +[id] = {\ + AFMT_DCN3_REG_LIST(id)\ +} + +static const struct dcn30_afmt_registers afmt_regs[] = { + afmt_regs(0), + afmt_regs(1), + afmt_regs(2), + afmt_regs(3), + afmt_regs(4), + afmt_regs(5), + afmt_regs(6), +}; + +static const struct dcn30_afmt_shift afmt_shift = { + DCN3_AFMT_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn30_afmt_mask afmt_mask = { + DCN3_AFMT_MASK_SH_LIST(_MASK) +}; + +#define stream_enc_regs(id)\ +[id] = {\ + SE_DCN3_REG_LIST(id)\ +} + +static const struct dcn10_stream_enc_registers stream_enc_regs[] = { + stream_enc_regs(0), + stream_enc_regs(1), + stream_enc_regs(2), + stream_enc_regs(3), + stream_enc_regs(4), + stream_enc_regs(5) +}; + +static const struct dcn10_stream_encoder_shift se_shift = { + SE_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn10_stream_encoder_mask se_mask = { + SE_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + + +#define aux_regs(id)\ +[id] = {\ + DCN2_AUX_REG_LIST(id)\ +} + +static const struct dcn10_link_enc_aux_registers link_enc_aux_regs[] = { + aux_regs(0), + aux_regs(1), + aux_regs(2), + aux_regs(3), + aux_regs(4), + aux_regs(5) +}; + +#define hpd_regs(id)\ +[id] = {\ + HPD_REG_LIST(id)\ +} + +static const struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[] = { + hpd_regs(0), + hpd_regs(1), + hpd_regs(2), + hpd_regs(3), + hpd_regs(4), + hpd_regs(5) +}; + +#define link_regs(id, phyid)\ +[id] = {\ + LE_DCN3_REG_LIST(id), \ + UNIPHY_DCN2_REG_LIST(phyid), \ + DPCS_DCN2_REG_LIST(id), \ + SRI(DP_DPHY_INTERNAL_CTRL, DP, id) \ +} + +static const struct dce110_aux_registers_shift aux_shift = { + DCN_AUX_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce110_aux_registers_mask aux_mask = { + DCN_AUX_MASK_SH_LIST(_MASK) +}; + +static const struct dcn10_link_enc_registers link_enc_regs[] = { + link_regs(0, A), + link_regs(1, B), + link_regs(2, C), + link_regs(3, D), + link_regs(4, E), + link_regs(5, F) +}; + +static const struct dcn10_link_enc_shift le_shift = { + LINK_ENCODER_MASK_SH_LIST_DCN30(__SHIFT),\ + DPCS_DCN2_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn10_link_enc_mask le_mask = { + LINK_ENCODER_MASK_SH_LIST_DCN30(_MASK),\ + DPCS_DCN2_MASK_SH_LIST(_MASK) +}; + + +static const struct dce_panel_cntl_registers panel_cntl_regs[] = { + { DCN_PANEL_CNTL_REG_LIST() } +}; + +static const struct dce_panel_cntl_shift panel_cntl_shift = { + DCE_PANEL_CNTL_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_panel_cntl_mask panel_cntl_mask = { + DCE_PANEL_CNTL_MASK_SH_LIST(_MASK) +}; + +#define dpp_regs(id)\ +[id] = {\ + DPP_REG_LIST_DCN30(id),\ +} + +static const struct dcn3_dpp_registers dpp_regs[] = { + dpp_regs(0), + dpp_regs(1), + dpp_regs(2), + dpp_regs(3), + dpp_regs(4), + dpp_regs(5), +}; + +static const struct dcn3_dpp_shift tf_shift = { + DPP_REG_LIST_SH_MASK_DCN30(__SHIFT) +}; + +static const struct dcn3_dpp_mask tf_mask = { + DPP_REG_LIST_SH_MASK_DCN30(_MASK) +}; + +#define opp_regs(id)\ +[id] = {\ + OPP_REG_LIST_DCN30(id),\ +} + +static const struct dcn20_opp_registers opp_regs[] = { + opp_regs(0), + opp_regs(1), + opp_regs(2), + opp_regs(3), + opp_regs(4), + opp_regs(5) +}; + +static const struct dcn20_opp_shift opp_shift = { + OPP_MASK_SH_LIST_DCN20(__SHIFT) +}; + +static const struct dcn20_opp_mask opp_mask = { + OPP_MASK_SH_LIST_DCN20(_MASK) +}; + +#define aux_engine_regs(id)\ +[id] = {\ + AUX_COMMON_REG_LIST0(id), \ + .AUXN_IMPCAL = 0, \ + .AUXP_IMPCAL = 0, \ + .AUX_RESET_MASK = DP_AUX0_AUX_CONTROL__AUX_RESET_MASK, \ +} + +static const struct dce110_aux_registers aux_engine_regs[] = { + aux_engine_regs(0), + aux_engine_regs(1), + aux_engine_regs(2), + aux_engine_regs(3), + aux_engine_regs(4), + aux_engine_regs(5) +}; + +#define dwbc_regs_dcn3(id)\ +[id] = {\ + DWBC_COMMON_REG_LIST_DCN30(id),\ +} + +static const struct dcn30_dwbc_registers dwbc30_regs[] = { + dwbc_regs_dcn3(0), +}; + +static const struct dcn30_dwbc_shift dwbc30_shift = { + DWBC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn30_dwbc_mask dwbc30_mask = { + DWBC_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +#define mcif_wb_regs_dcn3(id)\ +[id] = {\ + MCIF_WB_COMMON_REG_LIST_DCN30(id),\ +} + +static const struct dcn30_mmhubbub_registers mcif_wb30_regs[] = { + mcif_wb_regs_dcn3(0) +}; + +static const struct dcn30_mmhubbub_shift mcif_wb30_shift = { + MCIF_WB_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn30_mmhubbub_mask mcif_wb30_mask = { + MCIF_WB_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +#define dsc_regsDCN20(id)\ +[id] = {\ + DSC_REG_LIST_DCN20(id)\ +} + +static const struct dcn20_dsc_registers dsc_regs[] = { + dsc_regsDCN20(0), + dsc_regsDCN20(1), + dsc_regsDCN20(2), + dsc_regsDCN20(3), + dsc_regsDCN20(4), + dsc_regsDCN20(5) +}; + +static const struct dcn20_dsc_shift dsc_shift = { + DSC_REG_LIST_SH_MASK_DCN20(__SHIFT) +}; + +static const struct dcn20_dsc_mask dsc_mask = { + DSC_REG_LIST_SH_MASK_DCN20(_MASK) +}; + +static const struct dcn30_mpc_registers mpc_regs = { + MPC_REG_LIST_DCN3_0(0), + MPC_REG_LIST_DCN3_0(1), + MPC_REG_LIST_DCN3_0(2), + MPC_REG_LIST_DCN3_0(3), + MPC_REG_LIST_DCN3_0(4), + MPC_REG_LIST_DCN3_0(5), + MPC_OUT_MUX_REG_LIST_DCN3_0(0), + MPC_OUT_MUX_REG_LIST_DCN3_0(1), + MPC_OUT_MUX_REG_LIST_DCN3_0(2), + MPC_OUT_MUX_REG_LIST_DCN3_0(3), + MPC_OUT_MUX_REG_LIST_DCN3_0(4), + MPC_OUT_MUX_REG_LIST_DCN3_0(5), + MPC_RMU_GLOBAL_REG_LIST_DCN3AG, + MPC_RMU_REG_LIST_DCN3AG(0), + MPC_RMU_REG_LIST_DCN3AG(1), + MPC_RMU_REG_LIST_DCN3AG(2), + MPC_DWB_MUX_REG_LIST_DCN3_0(0), +}; + +static const struct dcn30_mpc_shift mpc_shift = { + MPC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn30_mpc_mask mpc_mask = { + MPC_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +#define optc_regs(id)\ +[id] = {OPTC_COMMON_REG_LIST_DCN3_0(id)} + + +static const struct dcn_optc_registers optc_regs[] = { + optc_regs(0), + optc_regs(1), + optc_regs(2), + optc_regs(3), + optc_regs(4), + optc_regs(5) +}; + +static const struct dcn_optc_shift optc_shift = { + OPTC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn_optc_mask optc_mask = { + OPTC_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +#define hubp_regs(id)\ +[id] = {\ + HUBP_REG_LIST_DCN30(id)\ +} + +static const struct dcn_hubp2_registers hubp_regs[] = { + hubp_regs(0), + hubp_regs(1), + hubp_regs(2), + hubp_regs(3), + hubp_regs(4), + hubp_regs(5) +}; + +static const struct dcn_hubp2_shift hubp_shift = { + HUBP_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn_hubp2_mask hubp_mask = { + HUBP_MASK_SH_LIST_DCN30(_MASK) +}; + +static const struct dcn_hubbub_registers hubbub_reg = { + HUBBUB_REG_LIST_DCN30(0) +}; + +static const struct dcn_hubbub_shift hubbub_shift = { + HUBBUB_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn_hubbub_mask hubbub_mask = { + HUBBUB_MASK_SH_LIST_DCN30(_MASK) +}; + +static const struct dccg_registers dccg_regs = { + DCCG_REG_LIST_DCN30() +}; + +static const struct dccg_shift dccg_shift = { + DCCG_MASK_SH_LIST_DCN3(__SHIFT) +}; + +static const struct dccg_mask dccg_mask = { + DCCG_MASK_SH_LIST_DCN3(_MASK) +}; + +static const struct dce_hwseq_registers hwseq_reg = { + HWSEQ_DCN30_REG_LIST() +}; + +static const struct dce_hwseq_shift hwseq_shift = { + HWSEQ_DCN30_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_hwseq_mask hwseq_mask = { + HWSEQ_DCN30_MASK_SH_LIST(_MASK) +}; +#define vmid_regs(id)\ +[id] = {\ + DCN20_VMID_REG_LIST(id)\ +} + +static const struct dcn_vmid_registers vmid_regs[] = { + vmid_regs(0), + vmid_regs(1), + vmid_regs(2), + vmid_regs(3), + vmid_regs(4), + vmid_regs(5), + vmid_regs(6), + vmid_regs(7), + vmid_regs(8), + vmid_regs(9), + vmid_regs(10), + vmid_regs(11), + vmid_regs(12), + vmid_regs(13), + vmid_regs(14), + vmid_regs(15) +}; + +static const struct dcn20_vmid_shift vmid_shifts = { + DCN20_VMID_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn20_vmid_mask vmid_masks = { + DCN20_VMID_MASK_SH_LIST(_MASK) +}; + +static const struct resource_caps res_cap_dcn3 = { + .num_timing_generator = 6, + .num_opp = 6, + .num_video_plane = 6, + .num_audio = 6, + .num_stream_encoder = 6, + .num_pll = 6, + .num_dwb = 1, + .num_ddc = 6, + .num_vmid = 16, + .num_mpc_3dlut = 3, + .num_dsc = 6, +}; + +static const struct dc_plane_cap plane_cap = { + .type = DC_PLANE_TYPE_DCN_UNIVERSAL, + .per_pixel_alpha = true, + + .pixel_format_support = { + .argb8888 = true, + .nv12 = true, + .fp16 = true, + .p010 = true, + .ayuv = false, + }, + + .max_upscale_factor = { + .argb8888 = 16000, + .nv12 = 16000, + .fp16 = 16000 + }, + + /* 6:1 downscaling ratio: 1000/6 = 166.666 */ + .max_downscale_factor = { + .argb8888 = 167, + .nv12 = 167, + .fp16 = 167 + }, + 16, + 16 +}; + +static const struct dc_debug_options debug_defaults_drv = { + .disable_dmcu = true, //No DMCU on DCN30 + .force_abm_enable = false, + .timing_trace = false, + .clock_trace = true, + .disable_pplib_clock_request = true, + .pipe_split_policy = MPC_SPLIT_DYNAMIC, + .force_single_disp_pipe_split = false, + .disable_dcc = DCC_ENABLE, + .vsr_support = true, + .performance_trace = false, + .max_downscale_src_width = 7680,/*upto 8K*/ + .disable_pplib_wm_range = false, + .scl_reset_length10 = true, + .sanity_checks = false, + .underflow_assert_delay_us = 0xFFFFFFFF, + .dwb_fi_phase = -1, // -1 = disable, + .dmub_command_table = true, + .use_max_lb = true, + .exit_idle_opt_for_cursor_updates = true, + .enable_legacy_fast_update = false, + .using_dml2 = false, +}; + +static const struct dc_panel_config panel_config_defaults = { + .psr = { + .disable_psr = false, + .disallow_psrsu = false, + .disallow_replay = false, + }, +}; + +static void dcn30_dpp_destroy(struct dpp **dpp) +{ + kfree(TO_DCN20_DPP(*dpp)); + *dpp = NULL; +} + +static struct dpp *dcn30_dpp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn3_dpp *dpp = + kzalloc(sizeof(struct dcn3_dpp), GFP_KERNEL); + + if (!dpp) + return NULL; + + if (dpp3_construct(dpp, ctx, inst, + &dpp_regs[inst], &tf_shift, &tf_mask)) + return &dpp->base; + + BREAK_TO_DEBUGGER(); + kfree(dpp); + return NULL; +} + +static struct output_pixel_processor *dcn30_opp_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dcn20_opp *opp = + kzalloc(sizeof(struct dcn20_opp), GFP_KERNEL); + + if (!opp) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dcn20_opp_construct(opp, ctx, inst, + &opp_regs[inst], &opp_shift, &opp_mask); + return &opp->base; +} + +static struct dce_aux *dcn30_aux_engine_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct aux_engine_dce110 *aux_engine = + kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); + + if (!aux_engine) + return NULL; + + dce110_aux_engine_construct(aux_engine, ctx, inst, + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, + &aux_engine_regs[inst], + &aux_mask, + &aux_shift, + ctx->dc->caps.extended_aux_timeout_support); + + return &aux_engine->base; +} + +#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST_DCN30(id) } + +static const struct dce_i2c_registers i2c_hw_regs[] = { + i2c_inst_regs(1), + i2c_inst_regs(2), + i2c_inst_regs(3), + i2c_inst_regs(4), + i2c_inst_regs(5), + i2c_inst_regs(6), +}; + +static const struct dce_i2c_shift i2c_shifts = { + I2C_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dce_i2c_mask i2c_masks = { + I2C_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +static struct dce_i2c_hw *dcn30_i2c_hw_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce_i2c_hw *dce_i2c_hw = + kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); + + if (!dce_i2c_hw) + return NULL; + + dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst, + &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); + + return dce_i2c_hw; +} + +static struct mpc *dcn30_mpc_create( + struct dc_context *ctx, + int num_mpcc, + int num_rmu) +{ + struct dcn30_mpc *mpc30 = kzalloc(sizeof(struct dcn30_mpc), + GFP_KERNEL); + + if (!mpc30) + return NULL; + + dcn30_mpc_construct(mpc30, ctx, + &mpc_regs, + &mpc_shift, + &mpc_mask, + num_mpcc, + num_rmu); + + return &mpc30->base; +} + +static struct hubbub *dcn30_hubbub_create(struct dc_context *ctx) +{ + int i; + + struct dcn20_hubbub *hubbub3 = kzalloc(sizeof(struct dcn20_hubbub), + GFP_KERNEL); + + if (!hubbub3) + return NULL; + + hubbub3_construct(hubbub3, ctx, + &hubbub_reg, + &hubbub_shift, + &hubbub_mask); + + + for (i = 0; i < res_cap_dcn3.num_vmid; i++) { + struct dcn20_vmid *vmid = &hubbub3->vmid[i]; + + vmid->ctx = ctx; + + vmid->regs = &vmid_regs[i]; + vmid->shifts = &vmid_shifts; + vmid->masks = &vmid_masks; + } + + return &hubbub3->base; +} + +static struct timing_generator *dcn30_timing_generator_create( + struct dc_context *ctx, + uint32_t instance) +{ + struct optc *tgn10 = + kzalloc(sizeof(struct optc), GFP_KERNEL); + + if (!tgn10) + return NULL; + + tgn10->base.inst = instance; + tgn10->base.ctx = ctx; + + tgn10->tg_regs = &optc_regs[instance]; + tgn10->tg_shift = &optc_shift; + tgn10->tg_mask = &optc_mask; + + dcn30_timing_generator_init(tgn10); + + return &tgn10->base; +} + +static const struct encoder_feature_support link_enc_feature = { + .max_hdmi_deep_color = COLOR_DEPTH_121212, + .max_hdmi_pixel_clock = 600000, + .hdmi_ycbcr420_supported = true, + .dp_ycbcr420_supported = true, + .fec_supported = true, + .flags.bits.IS_HBR2_CAPABLE = true, + .flags.bits.IS_HBR3_CAPABLE = true, + .flags.bits.IS_TPS3_CAPABLE = true, + .flags.bits.IS_TPS4_CAPABLE = true +}; + +static struct link_encoder *dcn30_link_encoder_create( + struct dc_context *ctx, + const struct encoder_init_data *enc_init_data) +{ + struct dcn20_link_encoder *enc20 = + kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); + + if (!enc20) + return NULL; + + dcn30_link_encoder_construct(enc20, + enc_init_data, + &link_enc_feature, + &link_enc_regs[enc_init_data->transmitter], + &link_enc_aux_regs[enc_init_data->channel - 1], + &link_enc_hpd_regs[enc_init_data->hpd_source], + &le_shift, + &le_mask); + + return &enc20->enc10.base; +} + +static struct panel_cntl *dcn30_panel_cntl_create(const struct panel_cntl_init_data *init_data) +{ + struct dce_panel_cntl *panel_cntl = + kzalloc(sizeof(struct dce_panel_cntl), GFP_KERNEL); + + if (!panel_cntl) + return NULL; + + dce_panel_cntl_construct(panel_cntl, + init_data, + &panel_cntl_regs[init_data->inst], + &panel_cntl_shift, + &panel_cntl_mask); + + return &panel_cntl->base; +} + +static void read_dce_straps( + struct dc_context *ctx, + struct resource_straps *straps) +{ + generic_reg_get(ctx, mmDC_PINSTRAPS + BASE(mmDC_PINSTRAPS_BASE_IDX), + FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio); + +} + +static struct audio *dcn30_create_audio( + struct dc_context *ctx, unsigned int inst) +{ + return dce_audio_create(ctx, inst, + &audio_regs[inst], &audio_shift, &audio_mask); +} + +static struct vpg *dcn30_vpg_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn30_vpg *vpg3 = kzalloc(sizeof(struct dcn30_vpg), GFP_KERNEL); + + if (!vpg3) + return NULL; + + vpg3_construct(vpg3, ctx, inst, + &vpg_regs[inst], + &vpg_shift, + &vpg_mask); + + return &vpg3->base; +} + +static struct afmt *dcn30_afmt_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn30_afmt *afmt3 = kzalloc(sizeof(struct dcn30_afmt), GFP_KERNEL); + + if (!afmt3) + return NULL; + + afmt3_construct(afmt3, ctx, inst, + &afmt_regs[inst], + &afmt_shift, + &afmt_mask); + + return &afmt3->base; +} + +static struct stream_encoder *dcn30_stream_encoder_create(enum engine_id eng_id, + struct dc_context *ctx) +{ + struct dcn10_stream_encoder *enc1; + struct vpg *vpg; + struct afmt *afmt; + int vpg_inst; + int afmt_inst; + + /* Mapping of VPG, AFMT, DME register blocks to DIO block instance */ + if (eng_id <= ENGINE_ID_DIGF) { + vpg_inst = eng_id; + afmt_inst = eng_id; + } else + return NULL; + + enc1 = kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL); + vpg = dcn30_vpg_create(ctx, vpg_inst); + afmt = dcn30_afmt_create(ctx, afmt_inst); + + if (!enc1 || !vpg || !afmt) { + kfree(enc1); + kfree(vpg); + kfree(afmt); + return NULL; + } + + dcn30_dio_stream_encoder_construct(enc1, ctx, ctx->dc_bios, + eng_id, vpg, afmt, + &stream_enc_regs[eng_id], + &se_shift, &se_mask); + + return &enc1->base; +} + +static struct dce_hwseq *dcn30_hwseq_create(struct dc_context *ctx) +{ + struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); + + if (hws) { + hws->ctx = ctx; + hws->regs = &hwseq_reg; + hws->shifts = &hwseq_shift; + hws->masks = &hwseq_mask; + } + return hws; +} +static const struct resource_create_funcs res_create_funcs = { + .read_dce_straps = read_dce_straps, + .create_audio = dcn30_create_audio, + .create_stream_encoder = dcn30_stream_encoder_create, + .create_hwseq = dcn30_hwseq_create, +}; + +static void dcn30_resource_destruct(struct dcn30_resource_pool *pool) +{ + unsigned int i; + + for (i = 0; i < pool->base.stream_enc_count; i++) { + if (pool->base.stream_enc[i] != NULL) { + if (pool->base.stream_enc[i]->vpg != NULL) { + kfree(DCN30_VPG_FROM_VPG(pool->base.stream_enc[i]->vpg)); + pool->base.stream_enc[i]->vpg = NULL; + } + if (pool->base.stream_enc[i]->afmt != NULL) { + kfree(DCN30_AFMT_FROM_AFMT(pool->base.stream_enc[i]->afmt)); + pool->base.stream_enc[i]->afmt = NULL; + } + kfree(DCN10STRENC_FROM_STRENC(pool->base.stream_enc[i])); + pool->base.stream_enc[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_dsc; i++) { + if (pool->base.dscs[i] != NULL) + dcn20_dsc_destroy(&pool->base.dscs[i]); + } + + if (pool->base.mpc != NULL) { + kfree(TO_DCN20_MPC(pool->base.mpc)); + pool->base.mpc = NULL; + } + if (pool->base.hubbub != NULL) { + kfree(pool->base.hubbub); + pool->base.hubbub = NULL; + } + for (i = 0; i < pool->base.pipe_count; i++) { + if (pool->base.dpps[i] != NULL) + dcn30_dpp_destroy(&pool->base.dpps[i]); + + if (pool->base.ipps[i] != NULL) + pool->base.ipps[i]->funcs->ipp_destroy(&pool->base.ipps[i]); + + if (pool->base.hubps[i] != NULL) { + kfree(TO_DCN20_HUBP(pool->base.hubps[i])); + pool->base.hubps[i] = NULL; + } + + if (pool->base.irqs != NULL) { + dal_irq_service_destroy(&pool->base.irqs); + } + } + + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + if (pool->base.engines[i] != NULL) + dce110_engine_destroy(&pool->base.engines[i]); + if (pool->base.hw_i2cs[i] != NULL) { + kfree(pool->base.hw_i2cs[i]); + pool->base.hw_i2cs[i] = NULL; + } + if (pool->base.sw_i2cs[i] != NULL) { + kfree(pool->base.sw_i2cs[i]); + pool->base.sw_i2cs[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_opp; i++) { + if (pool->base.opps[i] != NULL) + pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]); + } + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + if (pool->base.timing_generators[i] != NULL) { + kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i])); + pool->base.timing_generators[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_dwb; i++) { + if (pool->base.dwbc[i] != NULL) { + kfree(TO_DCN30_DWBC(pool->base.dwbc[i])); + pool->base.dwbc[i] = NULL; + } + if (pool->base.mcif_wb[i] != NULL) { + kfree(TO_DCN30_MMHUBBUB(pool->base.mcif_wb[i])); + pool->base.mcif_wb[i] = NULL; + } + } + + for (i = 0; i < pool->base.audio_count; i++) { + if (pool->base.audios[i]) + dce_aud_destroy(&pool->base.audios[i]); + } + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] != NULL) { + dcn20_clock_source_destroy(&pool->base.clock_sources[i]); + pool->base.clock_sources[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_mpc_3dlut; i++) { + if (pool->base.mpc_lut[i] != NULL) { + dc_3dlut_func_release(pool->base.mpc_lut[i]); + pool->base.mpc_lut[i] = NULL; + } + if (pool->base.mpc_shaper[i] != NULL) { + dc_transfer_func_release(pool->base.mpc_shaper[i]); + pool->base.mpc_shaper[i] = NULL; + } + } + + if (pool->base.dp_clock_source != NULL) { + dcn20_clock_source_destroy(&pool->base.dp_clock_source); + pool->base.dp_clock_source = NULL; + } + + for (i = 0; i < pool->base.pipe_count; i++) { + if (pool->base.multiple_abms[i] != NULL) + dce_abm_destroy(&pool->base.multiple_abms[i]); + } + + if (pool->base.psr != NULL) + dmub_psr_destroy(&pool->base.psr); + + if (pool->base.dccg != NULL) + dcn_dccg_destroy(&pool->base.dccg); + + if (pool->base.oem_device != NULL) { + struct dc *dc = pool->base.oem_device->ctx->dc; + + dc->link_srv->destroy_ddc_service(&pool->base.oem_device); + } +} + +static struct hubp *dcn30_hubp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn20_hubp *hubp2 = + kzalloc(sizeof(struct dcn20_hubp), GFP_KERNEL); + + if (!hubp2) + return NULL; + + if (hubp3_construct(hubp2, ctx, inst, + &hubp_regs[inst], &hubp_shift, &hubp_mask)) + return &hubp2->base; + + BREAK_TO_DEBUGGER(); + kfree(hubp2); + return NULL; +} + +static bool dcn30_dwbc_create(struct dc_context *ctx, struct resource_pool *pool) +{ + int i; + uint32_t pipe_count = pool->res_cap->num_dwb; + + for (i = 0; i < pipe_count; i++) { + struct dcn30_dwbc *dwbc30 = kzalloc(sizeof(struct dcn30_dwbc), + GFP_KERNEL); + + if (!dwbc30) { + dm_error("DC: failed to create dwbc30!\n"); + return false; + } + + dcn30_dwbc_construct(dwbc30, ctx, + &dwbc30_regs[i], + &dwbc30_shift, + &dwbc30_mask, + i); + + pool->dwbc[i] = &dwbc30->base; + } + return true; +} + +static bool dcn30_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool) +{ + int i; + uint32_t pipe_count = pool->res_cap->num_dwb; + + for (i = 0; i < pipe_count; i++) { + struct dcn30_mmhubbub *mcif_wb30 = kzalloc(sizeof(struct dcn30_mmhubbub), + GFP_KERNEL); + + if (!mcif_wb30) { + dm_error("DC: failed to create mcif_wb30!\n"); + return false; + } + + dcn30_mmhubbub_construct(mcif_wb30, ctx, + &mcif_wb30_regs[i], + &mcif_wb30_shift, + &mcif_wb30_mask, + i); + + pool->mcif_wb[i] = &mcif_wb30->base; + } + return true; +} + +static struct display_stream_compressor *dcn30_dsc_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dcn20_dsc *dsc = + kzalloc(sizeof(struct dcn20_dsc), GFP_KERNEL); + + if (!dsc) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dsc2_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask); + return &dsc->base; +} + +enum dc_status dcn30_add_stream_to_ctx(struct dc *dc, struct dc_state *new_ctx, struct dc_stream_state *dc_stream) +{ + + return dcn20_add_stream_to_ctx(dc, new_ctx, dc_stream); +} + +static void dcn30_destroy_resource_pool(struct resource_pool **pool) +{ + struct dcn30_resource_pool *dcn30_pool = TO_DCN30_RES_POOL(*pool); + + dcn30_resource_destruct(dcn30_pool); + kfree(dcn30_pool); + *pool = NULL; +} + +static struct clock_source *dcn30_clock_source_create( + struct dc_context *ctx, + struct dc_bios *bios, + enum clock_source_id id, + const struct dce110_clk_src_regs *regs, + bool dp_clk_src) +{ + struct dce110_clk_src *clk_src = + kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); + + if (!clk_src) + return NULL; + + if (dcn3_clk_src_construct(clk_src, ctx, bios, id, + regs, &cs_shift, &cs_mask)) { + clk_src->base.dp_clk_src = dp_clk_src; + return &clk_src->base; + } + + kfree(clk_src); + BREAK_TO_DEBUGGER(); + return NULL; +} + +int dcn30_populate_dml_pipes_from_context( + struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes, + bool fast_validate) +{ + int i, pipe_cnt; + struct resource_context *res_ctx = &context->res_ctx; + + DC_FP_START(); + dcn20_populate_dml_pipes_from_context(dc, context, pipes, fast_validate); + DC_FP_END(); + + for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) { + if (!res_ctx->pipe_ctx[i].stream) + continue; + + pipes[pipe_cnt++].pipe.scale_ratio_depth.lb_depth = + dm_lb_16; + } + + return pipe_cnt; +} + +void dcn30_populate_dml_writeback_from_context( + struct dc *dc, struct resource_context *res_ctx, display_e2e_pipe_params_st *pipes) +{ + DC_FP_START(); + dcn30_fpu_populate_dml_writeback_from_context(dc, res_ctx, pipes); + DC_FP_END(); +} + +unsigned int dcn30_calc_max_scaled_time( + unsigned int time_per_pixel, + enum mmhubbub_wbif_mode mode, + unsigned int urgent_watermark) +{ + unsigned int time_per_byte = 0; + unsigned int total_free_entry = 0xb40; + unsigned int buf_lh_capability; + unsigned int max_scaled_time; + + if (mode == PACKED_444) /* packed mode 32 bpp */ + time_per_byte = time_per_pixel/4; + else if (mode == PACKED_444_FP16) /* packed mode 64 bpp */ + time_per_byte = time_per_pixel/8; + + if (time_per_byte == 0) + time_per_byte = 1; + + buf_lh_capability = (total_free_entry*time_per_byte*32) >> 6; /* time_per_byte is in u6.6*/ + max_scaled_time = buf_lh_capability - urgent_watermark; + return max_scaled_time; +} + +void dcn30_set_mcif_arb_params( + struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int pipe_cnt) +{ + enum mmhubbub_wbif_mode wbif_mode; + struct display_mode_lib *dml = &context->bw_ctx.dml; + struct mcif_arb_params *wb_arb_params; + int i, j, dwb_pipe; + + /* Writeback MCIF_WB arbitration parameters */ + dwb_pipe = 0; + for (i = 0; i < dc->res_pool->pipe_count; i++) { + + if (!context->res_ctx.pipe_ctx[i].stream) + continue; + + for (j = 0; j < MAX_DWB_PIPES; j++) { + struct dc_writeback_info *writeback_info = &context->res_ctx.pipe_ctx[i].stream->writeback_info[j]; + + if (writeback_info->wb_enabled == false) + continue; + + //wb_arb_params = &context->res_ctx.pipe_ctx[i].stream->writeback_info[j].mcif_arb_params; + wb_arb_params = &context->bw_ctx.bw.dcn.bw_writeback.mcif_wb_arb[dwb_pipe]; + + if (writeback_info->dwb_params.cnv_params.fc_out_format == DWB_OUT_FORMAT_64BPP_ARGB || + writeback_info->dwb_params.cnv_params.fc_out_format == DWB_OUT_FORMAT_64BPP_RGBA) + wbif_mode = PACKED_444_FP16; + else + wbif_mode = PACKED_444; + + DC_FP_START(); + dcn30_fpu_set_mcif_arb_params(wb_arb_params, dml, pipes, pipe_cnt, j); + DC_FP_END(); + wb_arb_params->time_per_pixel = (1000000 << 6) / context->res_ctx.pipe_ctx[i].stream->phy_pix_clk; /* time_per_pixel should be in u6.6 format */ + wb_arb_params->slice_lines = 32; + wb_arb_params->arbitration_slice = 2; /* irrelevant since there is no YUV output */ + wb_arb_params->max_scaled_time = dcn30_calc_max_scaled_time(wb_arb_params->time_per_pixel, + wbif_mode, + wb_arb_params->cli_watermark[0]); /* assume 4 watermark sets have the same value */ + + dwb_pipe++; + + if (dwb_pipe >= MAX_DWB_PIPES) + return; + } + if (dwb_pipe >= MAX_DWB_PIPES) + return; + } + +} + +static struct dc_cap_funcs cap_funcs = { + .get_dcc_compression_cap = dcn20_get_dcc_compression_cap +}; + +bool dcn30_acquire_post_bldn_3dlut( + struct resource_context *res_ctx, + const struct resource_pool *pool, + int mpcc_id, + struct dc_3dlut **lut, + struct dc_transfer_func **shaper) +{ + int i; + bool ret = false; + union dc_3dlut_state *state; + + ASSERT(*lut == NULL && *shaper == NULL); + *lut = NULL; + *shaper = NULL; + + for (i = 0; i < pool->res_cap->num_mpc_3dlut; i++) { + if (!res_ctx->is_mpc_3dlut_acquired[i]) { + *lut = pool->mpc_lut[i]; + *shaper = pool->mpc_shaper[i]; + state = &pool->mpc_lut[i]->state; + res_ctx->is_mpc_3dlut_acquired[i] = true; + state->bits.rmu_idx_valid = 1; + state->bits.rmu_mux_num = i; + if (state->bits.rmu_mux_num == 0) + state->bits.mpc_rmu0_mux = mpcc_id; + else if (state->bits.rmu_mux_num == 1) + state->bits.mpc_rmu1_mux = mpcc_id; + else if (state->bits.rmu_mux_num == 2) + state->bits.mpc_rmu2_mux = mpcc_id; + ret = true; + break; + } + } + return ret; +} + +bool dcn30_release_post_bldn_3dlut( + struct resource_context *res_ctx, + const struct resource_pool *pool, + struct dc_3dlut **lut, + struct dc_transfer_func **shaper) +{ + int i; + bool ret = false; + + for (i = 0; i < pool->res_cap->num_mpc_3dlut; i++) { + if (pool->mpc_lut[i] == *lut && pool->mpc_shaper[i] == *shaper) { + res_ctx->is_mpc_3dlut_acquired[i] = false; + pool->mpc_lut[i]->state.raw = 0; + *lut = NULL; + *shaper = NULL; + ret = true; + break; + } + } + return ret; +} + +static bool is_soc_bounding_box_valid(struct dc *dc) +{ + uint32_t hw_internal_rev = dc->ctx->asic_id.hw_internal_rev; + + if (ASICREV_IS_SIENNA_CICHLID_P(hw_internal_rev)) + return true; + + return false; +} + +static bool init_soc_bounding_box(struct dc *dc, + struct dcn30_resource_pool *pool) +{ + struct _vcs_dpi_soc_bounding_box_st *loaded_bb = &dcn3_0_soc; + struct _vcs_dpi_ip_params_st *loaded_ip = &dcn3_0_ip; + + DC_LOGGER_INIT(dc->ctx->logger); + + if (!is_soc_bounding_box_valid(dc)) { + DC_LOG_ERROR("%s: not valid soc bounding box\n", __func__); + return false; + } + + loaded_ip->max_num_otg = pool->base.res_cap->num_timing_generator; + loaded_ip->max_num_dpp = pool->base.pipe_count; + loaded_ip->clamp_min_dcfclk = dc->config.clamp_min_dcfclk; + dcn20_patch_bounding_box(dc, loaded_bb); + DC_FP_START(); + patch_dcn30_soc_bounding_box(dc, &dcn3_0_soc); + DC_FP_END(); + + return true; +} + +static bool dcn30_split_stream_for_mpc_or_odm( + const struct dc *dc, + struct resource_context *res_ctx, + struct pipe_ctx *pri_pipe, + struct pipe_ctx *sec_pipe, + bool odm) +{ + int pipe_idx = sec_pipe->pipe_idx; + const struct resource_pool *pool = dc->res_pool; + + *sec_pipe = *pri_pipe; + + sec_pipe->pipe_idx = pipe_idx; + sec_pipe->plane_res.mi = pool->mis[pipe_idx]; + sec_pipe->plane_res.hubp = pool->hubps[pipe_idx]; + sec_pipe->plane_res.ipp = pool->ipps[pipe_idx]; + sec_pipe->plane_res.xfm = pool->transforms[pipe_idx]; + sec_pipe->plane_res.dpp = pool->dpps[pipe_idx]; + sec_pipe->plane_res.mpcc_inst = pool->dpps[pipe_idx]->inst; + sec_pipe->stream_res.dsc = NULL; + if (odm) { + if (pri_pipe->next_odm_pipe) { + ASSERT(pri_pipe->next_odm_pipe != sec_pipe); + sec_pipe->next_odm_pipe = pri_pipe->next_odm_pipe; + sec_pipe->next_odm_pipe->prev_odm_pipe = sec_pipe; + } + if (pri_pipe->top_pipe && pri_pipe->top_pipe->next_odm_pipe) { + pri_pipe->top_pipe->next_odm_pipe->bottom_pipe = sec_pipe; + sec_pipe->top_pipe = pri_pipe->top_pipe->next_odm_pipe; + } + if (pri_pipe->bottom_pipe && pri_pipe->bottom_pipe->next_odm_pipe) { + pri_pipe->bottom_pipe->next_odm_pipe->top_pipe = sec_pipe; + sec_pipe->bottom_pipe = pri_pipe->bottom_pipe->next_odm_pipe; + } + pri_pipe->next_odm_pipe = sec_pipe; + sec_pipe->prev_odm_pipe = pri_pipe; + + if (!sec_pipe->top_pipe) + sec_pipe->stream_res.opp = pool->opps[pipe_idx]; + else + sec_pipe->stream_res.opp = sec_pipe->top_pipe->stream_res.opp; + if (sec_pipe->stream->timing.flags.DSC == 1) { + dcn20_acquire_dsc(dc, res_ctx, &sec_pipe->stream_res.dsc, pipe_idx); + ASSERT(sec_pipe->stream_res.dsc); + if (sec_pipe->stream_res.dsc == NULL) + return false; + } + } else { + if (pri_pipe->bottom_pipe) { + ASSERT(pri_pipe->bottom_pipe != sec_pipe); + sec_pipe->bottom_pipe = pri_pipe->bottom_pipe; + sec_pipe->bottom_pipe->top_pipe = sec_pipe; + } + pri_pipe->bottom_pipe = sec_pipe; + sec_pipe->top_pipe = pri_pipe; + + ASSERT(pri_pipe->plane_state); + } + + return true; +} + +static struct pipe_ctx *dcn30_find_split_pipe( + struct dc *dc, + struct dc_state *context, + int old_index) +{ + struct pipe_ctx *pipe = NULL; + int i; + + if (old_index >= 0 && context->res_ctx.pipe_ctx[old_index].stream == NULL) { + pipe = &context->res_ctx.pipe_ctx[old_index]; + pipe->pipe_idx = old_index; + } + + if (!pipe) + for (i = dc->res_pool->pipe_count - 1; i >= 0; i--) { + if (dc->current_state->res_ctx.pipe_ctx[i].top_pipe == NULL + && dc->current_state->res_ctx.pipe_ctx[i].prev_odm_pipe == NULL) { + if (context->res_ctx.pipe_ctx[i].stream == NULL) { + pipe = &context->res_ctx.pipe_ctx[i]; + pipe->pipe_idx = i; + break; + } + } + } + + /* + * May need to fix pipes getting tossed from 1 opp to another on flip + * Add for debugging transient underflow during topology updates: + * ASSERT(pipe); + */ + if (!pipe) + for (i = dc->res_pool->pipe_count - 1; i >= 0; i--) { + if (context->res_ctx.pipe_ctx[i].stream == NULL) { + pipe = &context->res_ctx.pipe_ctx[i]; + pipe->pipe_idx = i; + break; + } + } + + return pipe; +} + +noinline bool dcn30_internal_validate_bw( + struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int *pipe_cnt_out, + int *vlevel_out, + bool fast_validate, + bool allow_self_refresh_only) +{ + bool out = false; + bool repopulate_pipes = false; + int split[MAX_PIPES] = { 0 }; + bool merge[MAX_PIPES] = { false }; + bool newly_split[MAX_PIPES] = { false }; + int pipe_cnt, i, pipe_idx, vlevel; + struct vba_vars_st *vba = &context->bw_ctx.dml.vba; + + ASSERT(pipes); + if (!pipes) + return false; + + context->bw_ctx.dml.vba.maxMpcComb = 0; + context->bw_ctx.dml.vba.VoltageLevel = 0; + context->bw_ctx.dml.vba.DRAMClockChangeSupport[0][0] = dm_dram_clock_change_vactive; + dc->res_pool->funcs->update_soc_for_wm_a(dc, context); + pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, context, pipes, fast_validate); + + if (!pipe_cnt) { + out = true; + goto validate_out; + } + + dml_log_pipe_params(&context->bw_ctx.dml, pipes, pipe_cnt); + + 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 + * prefetch mode > 0 so try capping the prefetch mode to start. + */ + context->bw_ctx.dml.soc.allow_dram_self_refresh_or_dram_clock_change_in_vblank = + dm_allow_self_refresh_and_mclk_switch; + vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt); + /* This may adjust vlevel and maxMpcComb */ + if (vlevel < context->bw_ctx.dml.soc.num_states) + vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, vlevel, split, merge); + } + 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. + * + * We don't actually support prefetch mode 2, so require that we + * at least support prefetch mode 1. + */ + context->bw_ctx.dml.validate_max_state = fast_validate; + context->bw_ctx.dml.soc.allow_dram_self_refresh_or_dram_clock_change_in_vblank = + dm_allow_self_refresh; + + vlevel = dml_get_voltage_level(&context->bw_ctx.dml, pipes, pipe_cnt); + if (vlevel < context->bw_ctx.dml.soc.num_states) { + memset(split, 0, sizeof(split)); + memset(merge, 0, sizeof(merge)); + vlevel = dcn20_validate_apply_pipe_split_flags(dc, context, vlevel, split, merge); + } + context->bw_ctx.dml.validate_max_state = false; + } + + dml_log_mode_support_params(&context->bw_ctx.dml); + + if (vlevel == context->bw_ctx.dml.soc.num_states) + goto validate_fail; + + if (!dc->config.enable_windowed_mpo_odm) { + for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + struct pipe_ctx *mpo_pipe = pipe->bottom_pipe; + + if (!pipe->stream) + continue; + + /* We only support full screen mpo with ODM */ + if (vba->ODMCombineEnabled[vba->pipe_plane[pipe_idx]] != dm_odm_combine_mode_disabled + && pipe->plane_state && mpo_pipe + && memcmp(&mpo_pipe->plane_state->clip_rect, + &pipe->stream->src, + sizeof(struct rect)) != 0) { + ASSERT(mpo_pipe->plane_state != pipe->plane_state); + goto validate_fail; + } + pipe_idx++; + } + } + + /* merge pipes if necessary */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + + /*skip pipes that don't need merging*/ + if (!merge[i]) + continue; + + /* if ODM merge we ignore mpc tree, mpo pipes will have their own flags */ + if (pipe->prev_odm_pipe) { + /*split off odm pipe*/ + pipe->prev_odm_pipe->next_odm_pipe = pipe->next_odm_pipe; + if (pipe->next_odm_pipe) + pipe->next_odm_pipe->prev_odm_pipe = pipe->prev_odm_pipe; + + pipe->bottom_pipe = NULL; + pipe->next_odm_pipe = NULL; + pipe->plane_state = NULL; + pipe->stream = NULL; + pipe->top_pipe = NULL; + pipe->prev_odm_pipe = NULL; + if (pipe->stream_res.dsc) + 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)); + repopulate_pipes = true; + } else if (pipe->top_pipe && pipe->top_pipe->plane_state == pipe->plane_state) { + struct pipe_ctx *top_pipe = pipe->top_pipe; + struct pipe_ctx *bottom_pipe = pipe->bottom_pipe; + + top_pipe->bottom_pipe = bottom_pipe; + if (bottom_pipe) + bottom_pipe->top_pipe = top_pipe; + + pipe->top_pipe = NULL; + pipe->bottom_pipe = NULL; + pipe->plane_state = NULL; + pipe->stream = NULL; + memset(&pipe->plane_res, 0, sizeof(pipe->plane_res)); + memset(&pipe->stream_res, 0, sizeof(pipe->stream_res)); + repopulate_pipes = true; + } else + ASSERT(0); /* Should never try to merge master pipe */ + + } + + for (i = 0, pipe_idx = -1; 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]; + struct pipe_ctx *hsplit_pipe = NULL; + bool odm; + int old_index = -1; + + if (!pipe->stream || newly_split[i]) + continue; + + pipe_idx++; + odm = vba->ODMCombineEnabled[vba->pipe_plane[pipe_idx]] != dm_odm_combine_mode_disabled; + + if (!pipe->plane_state && !odm) + continue; + + if (split[i]) { + if (odm) { + if (split[i] == 4 && old_pipe->next_odm_pipe && old_pipe->next_odm_pipe->next_odm_pipe) + old_index = old_pipe->next_odm_pipe->next_odm_pipe->pipe_idx; + else if (old_pipe->next_odm_pipe) + old_index = old_pipe->next_odm_pipe->pipe_idx; + } else { + if (split[i] == 4 && old_pipe->bottom_pipe && old_pipe->bottom_pipe->bottom_pipe && + old_pipe->bottom_pipe->bottom_pipe->plane_state == old_pipe->plane_state) + old_index = old_pipe->bottom_pipe->bottom_pipe->pipe_idx; + else if (old_pipe->bottom_pipe && + old_pipe->bottom_pipe->plane_state == old_pipe->plane_state) + old_index = old_pipe->bottom_pipe->pipe_idx; + } + hsplit_pipe = dcn30_find_split_pipe(dc, context, old_index); + ASSERT(hsplit_pipe); + if (!hsplit_pipe) + goto validate_fail; + + if (!dcn30_split_stream_for_mpc_or_odm( + dc, &context->res_ctx, + pipe, hsplit_pipe, odm)) + goto validate_fail; + + newly_split[hsplit_pipe->pipe_idx] = true; + repopulate_pipes = true; + } + if (split[i] == 4) { + struct pipe_ctx *pipe_4to1; + + if (odm && old_pipe->next_odm_pipe) + old_index = old_pipe->next_odm_pipe->pipe_idx; + else if (!odm && old_pipe->bottom_pipe && + old_pipe->bottom_pipe->plane_state == old_pipe->plane_state) + old_index = old_pipe->bottom_pipe->pipe_idx; + else + old_index = -1; + pipe_4to1 = dcn30_find_split_pipe(dc, context, old_index); + ASSERT(pipe_4to1); + if (!pipe_4to1) + goto validate_fail; + if (!dcn30_split_stream_for_mpc_or_odm( + dc, &context->res_ctx, + pipe, pipe_4to1, odm)) + goto validate_fail; + newly_split[pipe_4to1->pipe_idx] = true; + + if (odm && old_pipe->next_odm_pipe && old_pipe->next_odm_pipe->next_odm_pipe + && old_pipe->next_odm_pipe->next_odm_pipe->next_odm_pipe) + old_index = old_pipe->next_odm_pipe->next_odm_pipe->next_odm_pipe->pipe_idx; + else if (!odm && old_pipe->bottom_pipe && old_pipe->bottom_pipe->bottom_pipe && + old_pipe->bottom_pipe->bottom_pipe->bottom_pipe && + old_pipe->bottom_pipe->bottom_pipe->bottom_pipe->plane_state == old_pipe->plane_state) + old_index = old_pipe->bottom_pipe->bottom_pipe->bottom_pipe->pipe_idx; + else + old_index = -1; + pipe_4to1 = dcn30_find_split_pipe(dc, context, old_index); + ASSERT(pipe_4to1); + if (!pipe_4to1) + goto validate_fail; + if (!dcn30_split_stream_for_mpc_or_odm( + dc, &context->res_ctx, + hsplit_pipe, pipe_4to1, odm)) + goto validate_fail; + newly_split[pipe_4to1->pipe_idx] = true; + } + if (odm) + dcn20_build_mapped_resource(dc, context, pipe->stream); + } + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + + if (pipe->plane_state) { + if (!resource_build_scaling_params(pipe)) + goto validate_fail; + } + } + + /* Actual dsc count per stream dsc validation*/ + if (!dcn20_validate_dsc(dc, context)) { + vba->ValidationStatus[vba->soc.num_states] = DML_FAIL_DSC_VALIDATION_FAILURE; + goto validate_fail; + } + + if (repopulate_pipes) + pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, context, pipes, fast_validate); + context->bw_ctx.dml.vba.VoltageLevel = vlevel; + *vlevel_out = vlevel; + *pipe_cnt_out = pipe_cnt; + + out = true; + goto validate_out; + +validate_fail: + out = false; + +validate_out: + return out; +} + +static int get_refresh_rate(struct dc_state *context) +{ + int refresh_rate = 0; + int h_v_total = 0; + struct dc_crtc_timing *timing = NULL; + + if (context == NULL || context->streams[0] == NULL) + return 0; + + /* check if refresh rate at least 120hz */ + timing = &context->streams[0]->timing; + if (timing == NULL) + return 0; + + h_v_total = timing->h_total * timing->v_total; + if (h_v_total == 0) + return 0; + + refresh_rate = ((timing->pix_clk_100hz * 100) / (h_v_total)) + 1; + return refresh_rate; +} + +#define MAX_STRETCHED_V_BLANK 500 // in micro-seconds +/* + * Scaling factor for v_blank stretch calculations considering timing in + * micro-seconds and pixel clock in 100hz. + * Note: the parenthesis are necessary to ensure the correct order of + * operation where V_SCALE is used. + */ +#define V_SCALE (10000 / MAX_STRETCHED_V_BLANK) + +static int get_frame_rate_at_max_stretch_100hz(struct dc_state *context) +{ + struct dc_crtc_timing *timing = NULL; + uint32_t sec_per_100_lines; + uint32_t max_v_blank; + uint32_t curr_v_blank; + uint32_t v_stretch_max; + uint32_t stretched_frame_pix_cnt; + uint32_t scaled_stretched_frame_pix_cnt; + uint32_t scaled_refresh_rate; + + if (context == NULL || context->streams[0] == NULL) + return 0; + + /* check if refresh rate at least 120hz */ + timing = &context->streams[0]->timing; + if (timing == NULL) + return 0; + + sec_per_100_lines = timing->pix_clk_100hz / timing->h_total + 1; + max_v_blank = sec_per_100_lines / V_SCALE + 1; + curr_v_blank = timing->v_total - timing->v_addressable; + v_stretch_max = (max_v_blank > curr_v_blank) ? (max_v_blank - curr_v_blank) : (0); + stretched_frame_pix_cnt = (v_stretch_max + timing->v_total) * timing->h_total; + scaled_stretched_frame_pix_cnt = stretched_frame_pix_cnt / 10000; + scaled_refresh_rate = (timing->pix_clk_100hz) / scaled_stretched_frame_pix_cnt + 1; + + return scaled_refresh_rate; +} + +static bool is_refresh_rate_support_mclk_switch_using_fw_based_vblank_stretch(struct dc_state *context) +{ + int refresh_rate_max_stretch_100hz; + int min_refresh_100hz; + + if (context == NULL || context->streams[0] == NULL) + return false; + + refresh_rate_max_stretch_100hz = get_frame_rate_at_max_stretch_100hz(context); + min_refresh_100hz = context->streams[0]->timing.min_refresh_in_uhz / 10000; + + if (refresh_rate_max_stretch_100hz < min_refresh_100hz) + return false; + + return true; +} + +bool dcn30_can_support_mclk_switch_using_fw_based_vblank_stretch(struct dc *dc, struct dc_state *context) +{ + int refresh_rate = 0; + const int minimum_refreshrate_supported = 120; + + if (context == NULL || context->streams[0] == NULL) + return false; + + if (context->streams[0]->sink->edid_caps.panel_patch.disable_fams) + return false; + + if (dc->debug.disable_fams) + return false; + + if (!dc->caps.dmub_caps.mclk_sw) + return false; + + if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching_shut_down) + return false; + + /* more then 1 monitor connected */ + if (context->stream_count != 1) + return false; + + refresh_rate = get_refresh_rate(context); + if (refresh_rate < minimum_refreshrate_supported) + return false; + + if (!is_refresh_rate_support_mclk_switch_using_fw_based_vblank_stretch(context)) + return false; + + if (!context->streams[0]->allow_freesync) + return false; + + if (context->streams[0]->vrr_active_variable && dc->debug.disable_fams_gaming) + return false; + + context->streams[0]->fpo_in_use = true; + + return true; +} + +/* + * set up FPO watermarks, pstate, dram latency + */ +void dcn30_setup_mclk_switch_using_fw_based_vblank_stretch(struct dc *dc, struct dc_state *context) +{ + ASSERT(dc != NULL && context != NULL); + if (dc == NULL || context == NULL) + return; + + /* Set wm_a.pstate so high natural MCLK switches are impossible: 4 seconds */ + context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = 4U * 1000U * 1000U * 1000U; +} + +void dcn30_update_soc_for_wm_a(struct dc *dc, struct dc_state *context) +{ + DC_FP_START(); + dcn30_fpu_update_soc_for_wm_a(dc, context); + DC_FP_END(); +} + +void dcn30_calculate_wm_and_dlg( + struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int pipe_cnt, + int vlevel) +{ + DC_FP_START(); + dcn30_fpu_calculate_wm_and_dlg(dc, context, pipes, pipe_cnt, vlevel); + DC_FP_END(); +} + +bool dcn30_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(); + out = dcn30_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, fast_validate, true); + DC_FP_END(); + + if (pipe_cnt == 0) + goto validate_out; + + if (!out) + goto validate_fail; + + BW_VAL_TRACE_END_VOLTAGE_LEVEL(); + + if (fast_validate) { + BW_VAL_TRACE_SKIP(fast); + goto validate_out; + } + + DC_FP_START(); + if (dc->res_pool->funcs->calculate_wm_and_dlg) + dc->res_pool->funcs->calculate_wm_and_dlg(dc, context, pipes, pipe_cnt, vlevel); + DC_FP_END(); + + 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; +} + +void dcn30_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) +{ + unsigned int i, j; + unsigned int num_states = 0; + + unsigned int dcfclk_mhz[DC__VOLTAGE_STATES] = {0}; + unsigned int dram_speed_mts[DC__VOLTAGE_STATES] = {0}; + unsigned int optimal_uclk_for_dcfclk_sta_targets[DC__VOLTAGE_STATES] = {0}; + unsigned int optimal_dcfclk_for_uclk[DC__VOLTAGE_STATES] = {0}; + + unsigned int dcfclk_sta_targets[DC__VOLTAGE_STATES] = {694, 875, 1000, 1200}; + unsigned int num_dcfclk_sta_targets = 4; + unsigned int num_uclk_states; + + struct dc_bounding_box_max_clk dcn30_bb_max_clk; + + memset(&dcn30_bb_max_clk, 0, sizeof(dcn30_bb_max_clk)); + + if (dc->ctx->dc_bios->vram_info.num_chans) + dcn3_0_soc.num_chans = dc->ctx->dc_bios->vram_info.num_chans; + + DC_FP_START(); + dcn30_fpu_update_dram_channel_width_bytes(dc); + DC_FP_END(); + + if (bw_params->clk_table.entries[0].memclk_mhz) { + + for (i = 0; i < MAX_NUM_DPM_LVL; i++) { + if (bw_params->clk_table.entries[i].dcfclk_mhz > dcn30_bb_max_clk.max_dcfclk_mhz) + dcn30_bb_max_clk.max_dcfclk_mhz = bw_params->clk_table.entries[i].dcfclk_mhz; + if (bw_params->clk_table.entries[i].dispclk_mhz > dcn30_bb_max_clk.max_dispclk_mhz) + dcn30_bb_max_clk.max_dispclk_mhz = bw_params->clk_table.entries[i].dispclk_mhz; + if (bw_params->clk_table.entries[i].dppclk_mhz > dcn30_bb_max_clk.max_dppclk_mhz) + dcn30_bb_max_clk.max_dppclk_mhz = bw_params->clk_table.entries[i].dppclk_mhz; + if (bw_params->clk_table.entries[i].phyclk_mhz > dcn30_bb_max_clk.max_phyclk_mhz) + dcn30_bb_max_clk.max_phyclk_mhz = bw_params->clk_table.entries[i].phyclk_mhz; + } + + DC_FP_START(); + dcn30_fpu_update_max_clk(&dcn30_bb_max_clk); + DC_FP_END(); + + if (dcn30_bb_max_clk.max_dcfclk_mhz > dcfclk_sta_targets[num_dcfclk_sta_targets-1]) { + // If max DCFCLK is greater than the max DCFCLK STA target, insert into the DCFCLK STA target array + dcfclk_sta_targets[num_dcfclk_sta_targets] = dcn30_bb_max_clk.max_dcfclk_mhz; + num_dcfclk_sta_targets++; + } else if (dcn30_bb_max_clk.max_dcfclk_mhz < dcfclk_sta_targets[num_dcfclk_sta_targets-1]) { + // If max DCFCLK is less than the max DCFCLK STA target, cap values and remove duplicates + for (i = 0; i < num_dcfclk_sta_targets; i++) { + if (dcfclk_sta_targets[i] > dcn30_bb_max_clk.max_dcfclk_mhz) { + dcfclk_sta_targets[i] = dcn30_bb_max_clk.max_dcfclk_mhz; + break; + } + } + // Update size of array since we "removed" duplicates + num_dcfclk_sta_targets = i + 1; + } + + num_uclk_states = bw_params->clk_table.num_entries; + + // Calculate optimal dcfclk for each uclk + for (i = 0; i < num_uclk_states; i++) { + DC_FP_START(); + dcn30_fpu_get_optimal_dcfclk_fclk_for_uclk(bw_params->clk_table.entries[i].memclk_mhz * 16, + &optimal_dcfclk_for_uclk[i], NULL); + DC_FP_END(); + if (optimal_dcfclk_for_uclk[i] < bw_params->clk_table.entries[0].dcfclk_mhz) { + optimal_dcfclk_for_uclk[i] = bw_params->clk_table.entries[0].dcfclk_mhz; + } + } + + // Calculate optimal uclk for each dcfclk sta target + for (i = 0; i < num_dcfclk_sta_targets; i++) { + for (j = 0; j < num_uclk_states; j++) { + if (dcfclk_sta_targets[i] < optimal_dcfclk_for_uclk[j]) { + optimal_uclk_for_dcfclk_sta_targets[i] = + bw_params->clk_table.entries[j].memclk_mhz * 16; + break; + } + } + } + + i = 0; + j = 0; + // create the final dcfclk and uclk table + while (i < num_dcfclk_sta_targets && j < num_uclk_states && num_states < DC__VOLTAGE_STATES) { + if (dcfclk_sta_targets[i] < optimal_dcfclk_for_uclk[j] && i < num_dcfclk_sta_targets) { + dcfclk_mhz[num_states] = dcfclk_sta_targets[i]; + dram_speed_mts[num_states++] = optimal_uclk_for_dcfclk_sta_targets[i++]; + } else { + if (j < num_uclk_states && optimal_dcfclk_for_uclk[j] <= dcn30_bb_max_clk.max_dcfclk_mhz) { + dcfclk_mhz[num_states] = optimal_dcfclk_for_uclk[j]; + dram_speed_mts[num_states++] = bw_params->clk_table.entries[j++].memclk_mhz * 16; + } else { + j = num_uclk_states; + } + } + } + + while (i < num_dcfclk_sta_targets && num_states < DC__VOLTAGE_STATES) { + dcfclk_mhz[num_states] = dcfclk_sta_targets[i]; + dram_speed_mts[num_states++] = optimal_uclk_for_dcfclk_sta_targets[i++]; + } + + while (j < num_uclk_states && num_states < DC__VOLTAGE_STATES && + optimal_dcfclk_for_uclk[j] <= dcn30_bb_max_clk.max_dcfclk_mhz) { + dcfclk_mhz[num_states] = optimal_dcfclk_for_uclk[j]; + dram_speed_mts[num_states++] = bw_params->clk_table.entries[j++].memclk_mhz * 16; + } + + dcn3_0_soc.num_states = num_states; + DC_FP_START(); + dcn30_fpu_update_bw_bounding_box(dc, bw_params, &dcn30_bb_max_clk, dcfclk_mhz, dram_speed_mts); + DC_FP_END(); + } +} + +static void dcn30_get_panel_config_defaults(struct dc_panel_config *panel_config) +{ + *panel_config = panel_config_defaults; +} + +static const struct resource_funcs dcn30_res_pool_funcs = { + .destroy = dcn30_destroy_resource_pool, + .link_enc_create = dcn30_link_encoder_create, + .panel_cntl_create = dcn30_panel_cntl_create, + .validate_bandwidth = dcn30_validate_bandwidth, + .calculate_wm_and_dlg = dcn30_calculate_wm_and_dlg, + .update_soc_for_wm_a = dcn30_update_soc_for_wm_a, + .populate_dml_pipes = dcn30_populate_dml_pipes_from_context, + .acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer, + .release_pipe = dcn20_release_pipe, + .add_stream_to_ctx = dcn30_add_stream_to_ctx, + .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource, + .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, + .populate_dml_writeback_from_context = dcn30_populate_dml_writeback_from_context, + .set_mcif_arb_params = dcn30_set_mcif_arb_params, + .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 = dcn30_update_bw_bounding_box, + .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, + .get_panel_config_defaults = dcn30_get_panel_config_defaults, +}; + +#define CTX ctx + +#define REG(reg_name) \ + (DCN_BASE.instance[0].segment[mm ## reg_name ## _BASE_IDX] + mm ## reg_name) + +static uint32_t read_pipe_fuses(struct dc_context *ctx) +{ + uint32_t value = REG_READ(CC_DC_PIPE_DIS); + /* Support for max 6 pipes */ + value = value & 0x3f; + return value; +} + +static bool dcn30_resource_construct( + uint8_t num_virtual_links, + struct dc *dc, + struct dcn30_resource_pool *pool) +{ + int i; + struct dc_context *ctx = dc->ctx; + struct irq_service_init_data init_data; + struct ddc_service_init_data ddc_init_data = {0}; + uint32_t pipe_fuses = read_pipe_fuses(ctx); + uint32_t num_pipes = 0; + + if (!(pipe_fuses == 0 || pipe_fuses == 0x3e)) { + BREAK_TO_DEBUGGER(); + dm_error("DC: Unexpected fuse recipe for navi2x !\n"); + /* fault to single pipe */ + pipe_fuses = 0x3e; + } + + DC_FP_START(); + + ctx->dc_bios->regs = &bios_regs; + + pool->base.res_cap = &res_cap_dcn3; + + pool->base.funcs = &dcn30_res_pool_funcs; + + /************************************************* + * Resource + asic cap harcoding * + *************************************************/ + pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.pipe_count = pool->base.res_cap->num_timing_generator; + 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; /*1.4 w/a not applied by default*/ + dc->caps.max_cursor_size = 256; + dc->caps.min_horizontal_blanking_period = 80; + dc->caps.dmdata_alloc_size = 2048; + dc->caps.mall_size_per_mem_channel = 8; + /* total size = mall per channel * num channels * 1024 * 1024 */ + dc->caps.mall_size_total = dc->caps.mall_size_per_mem_channel * dc->ctx->dc_bios->vram_info.num_chans * 1048576; + dc->caps.cursor_cache_size = dc->caps.max_cursor_size * dc->caps.max_cursor_size * 8; + + dc->caps.max_slave_planes = 2; + dc->caps.max_slave_yuv_planes = 2; + dc->caps.max_slave_rgb_planes = 2; + dc->caps.post_blend_color_processing = true; + dc->caps.force_dp_tps4_for_cp2520 = true; + dc->caps.extended_aux_timeout_support = true; + dc->caps.dmcub_support = true; + + /* Color pipeline capabilities */ + dc->caps.color.dpp.dcn_arch = 1; + dc->caps.color.dpp.input_lut_shared = 0; + dc->caps.color.dpp.icsc = 1; + dc->caps.color.dpp.dgam_ram = 0; // must use gamma_corr + dc->caps.color.dpp.dgam_rom_caps.srgb = 1; + dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1; + dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 1; + dc->caps.color.dpp.dgam_rom_caps.pq = 1; + dc->caps.color.dpp.dgam_rom_caps.hlg = 1; + dc->caps.color.dpp.post_csc = 1; + dc->caps.color.dpp.gamma_corr = 1; + dc->caps.color.dpp.dgam_rom_for_yuv = 0; + + dc->caps.color.dpp.hw_3d_lut = 1; + dc->caps.color.dpp.ogam_ram = 1; + // no OGAM ROM on DCN3 + dc->caps.color.dpp.ogam_rom_caps.srgb = 0; + dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0; + dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0; + dc->caps.color.dpp.ogam_rom_caps.pq = 0; + dc->caps.color.dpp.ogam_rom_caps.hlg = 0; + dc->caps.color.dpp.ocsc = 0; + + dc->caps.color.mpc.gamut_remap = 1; + dc->caps.color.mpc.num_3dluts = pool->base.res_cap->num_mpc_3dlut; //3 + dc->caps.color.mpc.ogam_ram = 1; + dc->caps.color.mpc.ogam_rom_caps.srgb = 0; + dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0; + dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0; + dc->caps.color.mpc.ogam_rom_caps.pq = 0; + dc->caps.color.mpc.ogam_rom_caps.hlg = 0; + dc->caps.color.mpc.ocsc = 1; + + dc->caps.dp_hdmi21_pcon_support = true; + dc->caps.max_v_total = (1 << 15) - 1; + + /* read VBIOS LTTPR caps */ + { + if (ctx->dc_bios->funcs->get_lttpr_caps) { + enum bp_result bp_query_result; + uint8_t is_vbios_lttpr_enable = 0; + + bp_query_result = ctx->dc_bios->funcs->get_lttpr_caps(ctx->dc_bios, &is_vbios_lttpr_enable); + dc->caps.vbios_lttpr_enable = (bp_query_result == BP_RESULT_OK) && !!is_vbios_lttpr_enable; + } + + if (ctx->dc_bios->funcs->get_lttpr_interop) { + enum bp_result bp_query_result; + uint8_t is_vbios_interop_enabled = 0; + + bp_query_result = ctx->dc_bios->funcs->get_lttpr_interop(ctx->dc_bios, + &is_vbios_interop_enabled); + dc->caps.vbios_lttpr_aware = (bp_query_result == BP_RESULT_OK) && !!is_vbios_interop_enabled; + } + } + + if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) + dc->debug = debug_defaults_drv; + + // Init the vm_helper + if (dc->vm_helper) + vm_helper_init(dc->vm_helper, 16); + + /************************************************* + * Create resources * + *************************************************/ + + /* Clock Sources for Pixel Clock*/ + pool->base.clock_sources[DCN30_CLK_SRC_PLL0] = + dcn30_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL0, + &clk_src_regs[0], false); + pool->base.clock_sources[DCN30_CLK_SRC_PLL1] = + dcn30_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL1, + &clk_src_regs[1], false); + pool->base.clock_sources[DCN30_CLK_SRC_PLL2] = + dcn30_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL2, + &clk_src_regs[2], false); + pool->base.clock_sources[DCN30_CLK_SRC_PLL3] = + dcn30_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL3, + &clk_src_regs[3], false); + pool->base.clock_sources[DCN30_CLK_SRC_PLL4] = + dcn30_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL4, + &clk_src_regs[4], false); + pool->base.clock_sources[DCN30_CLK_SRC_PLL5] = + dcn30_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL5, + &clk_src_regs[5], false); + + pool->base.clk_src_count = DCN30_CLK_SRC_TOTAL; + + /* todo: not reuse phy_pll registers */ + pool->base.dp_clock_source = + dcn30_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_ID_DP_DTO, + &clk_src_regs[0], true); + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] == NULL) { + dm_error("DC: failed to create clock sources!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + } + + /* DCCG */ + pool->base.dccg = dccg30_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask); + if (pool->base.dccg == NULL) { + dm_error("DC: failed to create dccg!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + /* PP Lib and SMU interfaces */ + init_soc_bounding_box(dc, pool); + + num_pipes = dcn3_0_ip.max_num_dpp; + + for (i = 0; i < dcn3_0_ip.max_num_dpp; i++) + if (pipe_fuses & 1 << i) + num_pipes--; + + dcn3_0_ip.max_num_dpp = num_pipes; + dcn3_0_ip.max_num_otg = num_pipes; + + dml_init_instance(&dc->dml, &dcn3_0_soc, &dcn3_0_ip, DML_PROJECT_DCN30); + + /* IRQ */ + init_data.ctx = dc->ctx; + pool->base.irqs = dal_irq_service_dcn30_create(&init_data); + if (!pool->base.irqs) + goto create_fail; + + /* HUBBUB */ + pool->base.hubbub = dcn30_hubbub_create(ctx); + if (pool->base.hubbub == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create hubbub!\n"); + goto create_fail; + } + + /* HUBPs, DPPs, OPPs and TGs */ + for (i = 0; i < pool->base.pipe_count; i++) { + pool->base.hubps[i] = dcn30_hubp_create(ctx, i); + if (pool->base.hubps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create hubps!\n"); + goto create_fail; + } + + pool->base.dpps[i] = dcn30_dpp_create(ctx, i); + if (pool->base.dpps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create dpps!\n"); + goto create_fail; + } + } + + for (i = 0; i < pool->base.res_cap->num_opp; i++) { + pool->base.opps[i] = dcn30_opp_create(ctx, i); + if (pool->base.opps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create output pixel processor!\n"); + goto create_fail; + } + } + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + pool->base.timing_generators[i] = dcn30_timing_generator_create( + ctx, i); + if (pool->base.timing_generators[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create tg!\n"); + goto create_fail; + } + } + pool->base.timing_generator_count = i; + /* PSR */ + pool->base.psr = dmub_psr_create(ctx); + + if (pool->base.psr == NULL) { + dm_error("DC: failed to create PSR obj!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + /* ABM */ + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + pool->base.multiple_abms[i] = dmub_abm_create(ctx, + &abm_regs[i], + &abm_shift, + &abm_mask); + if (pool->base.multiple_abms[i] == NULL) { + dm_error("DC: failed to create abm for pipe %d!\n", i); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + } + /* MPC and DSC */ + pool->base.mpc = dcn30_mpc_create(ctx, pool->base.mpcc_count, pool->base.res_cap->num_mpc_3dlut); + if (pool->base.mpc == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create mpc!\n"); + goto create_fail; + } + + for (i = 0; i < pool->base.res_cap->num_dsc; i++) { + pool->base.dscs[i] = dcn30_dsc_create(ctx, i); + if (pool->base.dscs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create display stream compressor %d!\n", i); + goto create_fail; + } + } + + /* DWB and MMHUBBUB */ + if (!dcn30_dwbc_create(ctx, &pool->base)) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dwbc!\n"); + goto create_fail; + } + + if (!dcn30_mmhubbub_create(ctx, &pool->base)) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create mcif_wb!\n"); + goto create_fail; + } + + /* AUX and I2C */ + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + pool->base.engines[i] = dcn30_aux_engine_create(ctx, i); + if (pool->base.engines[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create aux engine!!\n"); + goto create_fail; + } + pool->base.hw_i2cs[i] = dcn30_i2c_hw_create(ctx, i); + if (pool->base.hw_i2cs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create hw i2c!!\n"); + goto create_fail; + } + pool->base.sw_i2cs[i] = NULL; + } + + /* Audio, Stream Encoders including DIG and virtual, MPC 3D LUTs */ + if (!resource_construct(num_virtual_links, dc, &pool->base, + &res_create_funcs)) + goto create_fail; + + /* HW Sequencer and Plane caps */ + dcn30_hw_sequencer_construct(dc); + + dc->caps.max_planes = pool->base.pipe_count; + + for (i = 0; i < dc->caps.max_planes; ++i) + dc->caps.planes[i] = plane_cap; + + 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->base.oem_device = dc->link_srv->create_ddc_service(&ddc_init_data); + } else { + pool->base.oem_device = NULL; + } + + DC_FP_END(); + + return true; + +create_fail: + + DC_FP_END(); + dcn30_resource_destruct(pool); + + return false; +} + +struct resource_pool *dcn30_create_resource_pool( + const struct dc_init_data *init_data, + struct dc *dc) +{ + struct dcn30_resource_pool *pool = + kzalloc(sizeof(struct dcn30_resource_pool), GFP_KERNEL); + + if (!pool) + return NULL; + + if (dcn30_resource_construct(init_data->num_virtual_links, dc, pool)) + return &pool->base; + + BREAK_TO_DEBUGGER(); + kfree(pool); + return NULL; +} diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.h new file mode 100644 index 00000000000000..8e6b8b7368fdb3 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.h @@ -0,0 +1,108 @@ +/* + * Copyright 2020 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 _DCN30_RESOURCE_H_ +#define _DCN30_RESOURCE_H_ + +#include "core_types.h" + +#define TO_DCN30_RES_POOL(pool)\ + container_of(pool, struct dcn30_resource_pool, base) + +struct dc; +struct resource_pool; +struct _vcs_dpi_display_pipe_params_st; + +extern struct _vcs_dpi_ip_params_st dcn3_0_ip; +extern struct _vcs_dpi_soc_bounding_box_st dcn3_0_soc; + +struct dcn30_resource_pool { + struct resource_pool base; +}; +struct resource_pool *dcn30_create_resource_pool( + const struct dc_init_data *init_data, + struct dc *dc); + +void dcn30_set_mcif_arb_params( + struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int pipe_cnt); + +unsigned int dcn30_calc_max_scaled_time( + unsigned int time_per_pixel, + enum mmhubbub_wbif_mode mode, + unsigned int urgent_watermark); + +bool dcn30_validate_bandwidth(struct dc *dc, struct dc_state *context, + bool fast_validate); +bool dcn30_internal_validate_bw( + struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int *pipe_cnt_out, + int *vlevel_out, + 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, + int pipe_cnt, + int vlevel); +void dcn30_update_soc_for_wm_a(struct dc *dc, struct dc_state *context); +void dcn30_populate_dml_writeback_from_context( + struct dc *dc, struct resource_context *res_ctx, display_e2e_pipe_params_st *pipes); + +int dcn30_populate_dml_pipes_from_context( + struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes, + bool fast_validate); + +bool dcn30_acquire_post_bldn_3dlut( + struct resource_context *res_ctx, + const struct resource_pool *pool, + int mpcc_id, + struct dc_3dlut **lut, + struct dc_transfer_func **shaper); + +bool dcn30_release_post_bldn_3dlut( + struct resource_context *res_ctx, + const struct resource_pool *pool, + struct dc_3dlut **lut, + struct dc_transfer_func **shaper); + +enum dc_status dcn30_add_stream_to_ctx( + struct dc *dc, + struct dc_state *new_ctx, + struct dc_stream_state *dc_stream); + +void dcn30_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params); + +bool dcn30_can_support_mclk_switch_using_fw_based_vblank_stretch(struct dc *dc, struct dc_state *context); +void dcn30_setup_mclk_switch_using_fw_based_vblank_stretch(struct dc *dc, struct dc_state *context); +int dcn30_find_dummy_latency_index_for_fw_based_mclk_switch(struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes, int pipe_cnt, int vlevel); + +#endif /* _DCN30_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c new file mode 100644 index 00000000000000..511ff6b5b98567 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c @@ -0,0 +1,1728 @@ +/* + * Copyright 2019-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 "dm_services.h" +#include "dc.h" + +#include "dcn301/dcn301_init.h" + +#include "resource.h" +#include "include/irq_service_interface.h" +#include "dcn30/dcn30_resource.h" +#include "dcn301_resource.h" + +#include "dcn20/dcn20_resource.h" + +#include "dcn10/dcn10_ipp.h" +#include "dcn301/dcn301_hubbub.h" +#include "dcn30/dcn30_mpc.h" +#include "dcn30/dcn30_hubp.h" +#include "irq/dcn30/irq_service_dcn30.h" +#include "dcn30/dcn30_dpp.h" +#include "dcn301/dcn301_optc.h" +#include "dcn20/dcn20_hwseq.h" +#include "dcn30/dcn30_hwseq.h" +#include "dce110/dce110_hwseq.h" +#include "dcn30/dcn30_opp.h" +#include "dcn20/dcn20_dsc.h" +#include "dcn30/dcn30_vpg.h" +#include "dcn30/dcn30_afmt.h" +#include "dce/dce_clock_source.h" +#include "dce/dce_audio.h" +#include "dce/dce_hwseq.h" +#include "clk_mgr.h" +#include "virtual/virtual_stream_encoder.h" +#include "dce110/dce110_resource.h" +#include "dml/display_mode_vba.h" +#include "dcn301/dcn301_dccg.h" +#include "dcn10/dcn10_resource.h" +#include "dcn30/dcn30_dio_stream_encoder.h" +#include "dcn301/dcn301_dio_link_encoder.h" +#include "dcn301/dcn301_panel_cntl.h" + +#include "vangogh_ip_offset.h" + +#include "dcn30/dcn30_dwb.h" +#include "dcn30/dcn30_mmhubbub.h" + +#include "dcn/dcn_3_0_1_offset.h" +#include "dcn/dcn_3_0_1_sh_mask.h" + +#include "nbio/nbio_7_2_0_offset.h" + +#include "dpcs/dpcs_3_0_0_offset.h" +#include "dpcs/dpcs_3_0_0_sh_mask.h" + +#include "reg_helper.h" +#include "dce/dmub_abm.h" +#include "dce/dce_aux.h" +#include "dce/dce_i2c.h" + +#include "dml/dcn30/dcn30_fpu.h" + +#include "dml/dcn30/display_mode_vba_30.h" +#include "dml/dcn301/dcn301_fpu.h" +#include "vm_helper.h" +#include "dcn20/dcn20_vmid.h" +#include "amdgpu_socbb.h" + +#define TO_DCN301_RES_POOL(pool)\ + container_of(pool, struct dcn301_resource_pool, base) + +#define DC_LOGGER \ + dc->ctx->logger +#define DC_LOGGER_INIT(logger) + +enum dcn301_clk_src_array_id { + DCN301_CLK_SRC_PLL0, + DCN301_CLK_SRC_PLL1, + DCN301_CLK_SRC_PLL2, + DCN301_CLK_SRC_PLL3, + DCN301_CLK_SRC_TOTAL +}; + +/* begin ********************* + * macros to expend register list macro defined in HW object header file + */ + +/* DCN */ +#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg + +#define BASE(seg) BASE_INNER(seg) + +#define SR(reg_name)\ + .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + \ + mm ## reg_name + +#define SRI(reg_name, block, id)\ + .reg_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define SRI2(reg_name, block, id)\ + .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + \ + mm ## reg_name + +#define SRIR(var_name, reg_name, block, id)\ + .var_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define SRII(reg_name, block, id)\ + .reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define SRII2(reg_name_pre, reg_name_post, id)\ + .reg_name_pre ## _ ## reg_name_post[id] = BASE(mm ## reg_name_pre \ + ## id ## _ ## reg_name_post ## _BASE_IDX) + \ + mm ## reg_name_pre ## id ## _ ## reg_name_post + +#define SRII_MPC_RMU(reg_name, block, id)\ + .RMU##_##reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define SRII_DWB(reg_name, temp_name, block, id)\ + .reg_name[id] = BASE(mm ## block ## id ## _ ## temp_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## temp_name + +#define SF_DWB2(reg_name, block, id, field_name, post_fix) \ + .field_name = reg_name ## __ ## field_name ## post_fix + +#define DCCG_SRII(reg_name, block, id)\ + .block ## _ ## reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define VUPDATE_SRII(reg_name, block, id)\ + .reg_name[id] = BASE(mm ## reg_name ## _ ## block ## id ## _BASE_IDX) + \ + mm ## reg_name ## _ ## block ## id + +/* NBIO */ +#define NBIO_BASE_INNER(seg) \ + NBIO_BASE__INST0_SEG ## seg + +#define NBIO_BASE(seg) \ + NBIO_BASE_INNER(seg) + +#define NBIO_SR(reg_name)\ + .reg_name = NBIO_BASE(regBIF_BX0_ ## reg_name ## _BASE_IDX) + \ + regBIF_BX0_ ## reg_name + +/* MMHUB */ +#define MMHUB_BASE_INNER(seg) \ + MMHUB_BASE__INST0_SEG ## seg + +#define MMHUB_BASE(seg) \ + MMHUB_BASE_INNER(seg) + +#define MMHUB_SR(reg_name)\ + .reg_name = MMHUB_BASE(regMM ## reg_name ## _BASE_IDX) + \ + regMM ## reg_name + +/* CLOCK */ +#define CLK_BASE_INNER(seg) \ + CLK_BASE__INST0_SEG ## seg + +#define CLK_BASE(seg) \ + CLK_BASE_INNER(seg) + +#define CLK_SRI(reg_name, block, inst)\ + .reg_name = CLK_BASE(mm ## block ## _ ## inst ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## _ ## inst ## _ ## reg_name + +static const struct bios_registers bios_regs = { + NBIO_SR(BIOS_SCRATCH_3), + NBIO_SR(BIOS_SCRATCH_6) +}; + +#define clk_src_regs(index, pllid)\ +[index] = {\ + CS_COMMON_REG_LIST_DCN3_01(index, pllid),\ +} + +static const struct dce110_clk_src_regs clk_src_regs[] = { + clk_src_regs(0, A), + clk_src_regs(1, B), + clk_src_regs(2, C), + clk_src_regs(3, D) +}; + +static const struct dce110_clk_src_shift cs_shift = { + CS_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) +}; + +static const struct dce110_clk_src_mask cs_mask = { + CS_COMMON_MASK_SH_LIST_DCN2_0(_MASK) +}; + +#define abm_regs(id)\ +[id] = {\ + ABM_DCN301_REG_LIST(id)\ +} + +static const struct dce_abm_registers abm_regs[] = { + abm_regs(0), + abm_regs(1), + abm_regs(2), + abm_regs(3), +}; + +static const struct dce_abm_shift abm_shift = { + ABM_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dce_abm_mask abm_mask = { + ABM_MASK_SH_LIST_DCN30(_MASK) +}; + +#define audio_regs(id)\ +[id] = {\ + AUD_COMMON_REG_LIST(id)\ +} + +static const struct dce_audio_registers audio_regs[] = { + audio_regs(0), + audio_regs(1), + audio_regs(2), + audio_regs(3), + audio_regs(4), + audio_regs(5), + audio_regs(6) +}; + +#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ + AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) + +static const struct dce_audio_shift audio_shift = { + DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_audio_mask audio_mask = { + DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) +}; + +#define vpg_regs(id)\ +[id] = {\ + VPG_DCN3_REG_LIST(id)\ +} + +static const struct dcn30_vpg_registers vpg_regs[] = { + vpg_regs(0), + vpg_regs(1), + vpg_regs(2), + vpg_regs(3), +}; + +static const struct dcn30_vpg_shift vpg_shift = { + DCN3_VPG_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn30_vpg_mask vpg_mask = { + DCN3_VPG_MASK_SH_LIST(_MASK) +}; + +#define afmt_regs(id)\ +[id] = {\ + AFMT_DCN3_REG_LIST(id)\ +} + +static const struct dcn30_afmt_registers afmt_regs[] = { + afmt_regs(0), + afmt_regs(1), + afmt_regs(2), + afmt_regs(3), +}; + +static const struct dcn30_afmt_shift afmt_shift = { + DCN3_AFMT_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn30_afmt_mask afmt_mask = { + DCN3_AFMT_MASK_SH_LIST(_MASK) +}; + +#define stream_enc_regs(id)\ +[id] = {\ + SE_DCN3_REG_LIST(id)\ +} + +static const struct dcn10_stream_enc_registers stream_enc_regs[] = { + stream_enc_regs(0), + stream_enc_regs(1), + stream_enc_regs(2), + stream_enc_regs(3), +}; + +static const struct dcn10_stream_encoder_shift se_shift = { + SE_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn10_stream_encoder_mask se_mask = { + SE_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + + +#define aux_regs(id)\ +[id] = {\ + DCN2_AUX_REG_LIST(id)\ +} + +static const struct dcn10_link_enc_aux_registers link_enc_aux_regs[] = { + aux_regs(0), + aux_regs(1), + aux_regs(2), + aux_regs(3), +}; + +#define hpd_regs(id)\ +[id] = {\ + HPD_REG_LIST(id)\ +} + +static const struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[] = { + hpd_regs(0), + hpd_regs(1), + hpd_regs(2), + hpd_regs(3), +}; + + +#define link_regs(id, phyid)\ +[id] = {\ + LE_DCN301_REG_LIST(id), \ + UNIPHY_DCN2_REG_LIST(phyid), \ + DPCS_DCN2_REG_LIST(id), \ + SRI(DP_DPHY_INTERNAL_CTRL, DP, id) \ +} + +static const struct dce110_aux_registers_shift aux_shift = { + DCN_AUX_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce110_aux_registers_mask aux_mask = { + DCN_AUX_MASK_SH_LIST(_MASK) +}; + +static const struct dcn10_link_enc_registers link_enc_regs[] = { + link_regs(0, A), + link_regs(1, B), + link_regs(2, C), + link_regs(3, D), +}; + +static const struct dcn10_link_enc_shift le_shift = { + LINK_ENCODER_MASK_SH_LIST_DCN301(__SHIFT),\ + DPCS_DCN2_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn10_link_enc_mask le_mask = { + LINK_ENCODER_MASK_SH_LIST_DCN301(_MASK),\ + DPCS_DCN2_MASK_SH_LIST(_MASK) +}; + +#define panel_cntl_regs(id)\ +[id] = {\ + DCN301_PANEL_CNTL_REG_LIST(id),\ +} + +static const struct dce_panel_cntl_registers panel_cntl_regs[] = { + panel_cntl_regs(0), + panel_cntl_regs(1), +}; + +static const struct dcn301_panel_cntl_shift panel_cntl_shift = { + DCN301_PANEL_CNTL_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn301_panel_cntl_mask panel_cntl_mask = { + DCN301_PANEL_CNTL_MASK_SH_LIST(_MASK) +}; + +#define dpp_regs(id)\ +[id] = {\ + DPP_REG_LIST_DCN30(id),\ +} + +static const struct dcn3_dpp_registers dpp_regs[] = { + dpp_regs(0), + dpp_regs(1), + dpp_regs(2), + dpp_regs(3), +}; + +static const struct dcn3_dpp_shift tf_shift = { + DPP_REG_LIST_SH_MASK_DCN30(__SHIFT) +}; + +static const struct dcn3_dpp_mask tf_mask = { + DPP_REG_LIST_SH_MASK_DCN30(_MASK) +}; + +#define opp_regs(id)\ +[id] = {\ + OPP_REG_LIST_DCN30(id),\ +} + +static const struct dcn20_opp_registers opp_regs[] = { + opp_regs(0), + opp_regs(1), + opp_regs(2), + opp_regs(3), +}; + +static const struct dcn20_opp_shift opp_shift = { + OPP_MASK_SH_LIST_DCN20(__SHIFT) +}; + +static const struct dcn20_opp_mask opp_mask = { + OPP_MASK_SH_LIST_DCN20(_MASK) +}; + +#define aux_engine_regs(id)\ +[id] = {\ + AUX_COMMON_REG_LIST0(id), \ + .AUXN_IMPCAL = 0, \ + .AUXP_IMPCAL = 0, \ + .AUX_RESET_MASK = DP_AUX0_AUX_CONTROL__AUX_RESET_MASK, \ +} + +static const struct dce110_aux_registers aux_engine_regs[] = { + aux_engine_regs(0), + aux_engine_regs(1), + aux_engine_regs(2), + aux_engine_regs(3), +}; + +#define dwbc_regs_dcn3(id)\ +[id] = {\ + DWBC_COMMON_REG_LIST_DCN30(id),\ +} + +static const struct dcn30_dwbc_registers dwbc30_regs[] = { + dwbc_regs_dcn3(0), +}; + +static const struct dcn30_dwbc_shift dwbc30_shift = { + DWBC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn30_dwbc_mask dwbc30_mask = { + DWBC_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +#define mcif_wb_regs_dcn3(id)\ +[id] = {\ + MCIF_WB_COMMON_REG_LIST_DCN30(id),\ +} + +static const struct dcn30_mmhubbub_registers mcif_wb30_regs[] = { + mcif_wb_regs_dcn3(0) +}; + +static const struct dcn30_mmhubbub_shift mcif_wb30_shift = { + MCIF_WB_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn30_mmhubbub_mask mcif_wb30_mask = { + MCIF_WB_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +#define dsc_regsDCN20(id)\ +[id] = {\ + DSC_REG_LIST_DCN20(id)\ +} + +static const struct dcn20_dsc_registers dsc_regs[] = { + dsc_regsDCN20(0), + dsc_regsDCN20(1), + dsc_regsDCN20(2), +}; + +static const struct dcn20_dsc_shift dsc_shift = { + DSC_REG_LIST_SH_MASK_DCN20(__SHIFT) +}; + +static const struct dcn20_dsc_mask dsc_mask = { + DSC_REG_LIST_SH_MASK_DCN20(_MASK) +}; + +static const struct dcn30_mpc_registers mpc_regs = { + MPC_REG_LIST_DCN3_0(0), + MPC_REG_LIST_DCN3_0(1), + MPC_REG_LIST_DCN3_0(2), + MPC_REG_LIST_DCN3_0(3), + MPC_OUT_MUX_REG_LIST_DCN3_0(0), + MPC_OUT_MUX_REG_LIST_DCN3_0(1), + MPC_OUT_MUX_REG_LIST_DCN3_0(2), + MPC_OUT_MUX_REG_LIST_DCN3_0(3), + MPC_RMU_GLOBAL_REG_LIST_DCN3AG, + MPC_RMU_REG_LIST_DCN3AG(0), + MPC_RMU_REG_LIST_DCN3AG(1), + MPC_DWB_MUX_REG_LIST_DCN3_0(0), +}; + +static const struct dcn30_mpc_shift mpc_shift = { + MPC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn30_mpc_mask mpc_mask = { + MPC_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +#define optc_regs(id)\ +[id] = {OPTC_COMMON_REG_LIST_DCN3_0(id)} + + +static const struct dcn_optc_registers optc_regs[] = { + optc_regs(0), + optc_regs(1), + optc_regs(2), + optc_regs(3), +}; + +static const struct dcn_optc_shift optc_shift = { + OPTC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn_optc_mask optc_mask = { + OPTC_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +#define hubp_regs(id)\ +[id] = {\ + HUBP_REG_LIST_DCN30(id)\ +} + +static const struct dcn_hubp2_registers hubp_regs[] = { + hubp_regs(0), + hubp_regs(1), + hubp_regs(2), + hubp_regs(3), +}; + +static const struct dcn_hubp2_shift hubp_shift = { + HUBP_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn_hubp2_mask hubp_mask = { + HUBP_MASK_SH_LIST_DCN30(_MASK) +}; + +static const struct dcn_hubbub_registers hubbub_reg = { + HUBBUB_REG_LIST_DCN301(0) +}; + +static const struct dcn_hubbub_shift hubbub_shift = { + HUBBUB_MASK_SH_LIST_DCN301(__SHIFT) +}; + +static const struct dcn_hubbub_mask hubbub_mask = { + HUBBUB_MASK_SH_LIST_DCN301(_MASK) +}; + +static const struct dccg_registers dccg_regs = { + DCCG_REG_LIST_DCN301() +}; + +static const struct dccg_shift dccg_shift = { + DCCG_MASK_SH_LIST_DCN301(__SHIFT) +}; + +static const struct dccg_mask dccg_mask = { + DCCG_MASK_SH_LIST_DCN301(_MASK) +}; + +static const struct dce_hwseq_registers hwseq_reg = { + HWSEQ_DCN301_REG_LIST() +}; + +static const struct dce_hwseq_shift hwseq_shift = { + HWSEQ_DCN301_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_hwseq_mask hwseq_mask = { + HWSEQ_DCN301_MASK_SH_LIST(_MASK) +}; +#define vmid_regs(id)\ +[id] = {\ + DCN20_VMID_REG_LIST(id)\ +} + +static const struct dcn_vmid_registers vmid_regs[] = { + vmid_regs(0), + vmid_regs(1), + vmid_regs(2), + vmid_regs(3), + vmid_regs(4), + vmid_regs(5), + vmid_regs(6), + vmid_regs(7), + vmid_regs(8), + vmid_regs(9), + vmid_regs(10), + vmid_regs(11), + vmid_regs(12), + vmid_regs(13), + vmid_regs(14), + vmid_regs(15) +}; + +static const struct dcn20_vmid_shift vmid_shifts = { + DCN20_VMID_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn20_vmid_mask vmid_masks = { + DCN20_VMID_MASK_SH_LIST(_MASK) +}; + +static struct resource_caps res_cap_dcn301 = { + .num_timing_generator = 4, + .num_opp = 4, + .num_video_plane = 4, + .num_audio = 4, + .num_stream_encoder = 4, + .num_pll = 4, + .num_dwb = 1, + .num_ddc = 4, + .num_vmid = 16, + .num_mpc_3dlut = 2, + .num_dsc = 3, +}; + +static const struct dc_plane_cap plane_cap = { + .type = DC_PLANE_TYPE_DCN_UNIVERSAL, + .per_pixel_alpha = true, + + .pixel_format_support = { + .argb8888 = true, + .nv12 = true, + .fp16 = true, + .p010 = true, + .ayuv = false, + }, + + .max_upscale_factor = { + .argb8888 = 16000, + .nv12 = 16000, + .fp16 = 16000 + }, + + /* 6:1 downscaling ratio: 1000/6 = 166.666 */ + .max_downscale_factor = { + .argb8888 = 167, + .nv12 = 167, + .fp16 = 167 + }, + 64, + 64 +}; + +static const struct dc_debug_options debug_defaults_drv = { + .disable_dmcu = true, + .force_abm_enable = false, + .timing_trace = false, + .clock_trace = true, + .disable_dpp_power_gate = false, + .disable_hubp_power_gate = false, + .disable_clock_gate = true, + .disable_pplib_clock_request = true, + .disable_pplib_wm_range = true, + .pipe_split_policy = MPC_SPLIT_DYNAMIC, + .force_single_disp_pipe_split = false, + .disable_dcc = DCC_ENABLE, + .vsr_support = true, + .performance_trace = false, + .max_downscale_src_width = 7680,/*upto 8K*/ + .scl_reset_length10 = true, + .sanity_checks = false, + .underflow_assert_delay_us = 0xFFFFFFFF, + .dwb_fi_phase = -1, // -1 = disable + .dmub_command_table = true, + .use_max_lb = false, + .exit_idle_opt_for_cursor_updates = true, + .using_dml2 = false, +}; + +static void dcn301_dpp_destroy(struct dpp **dpp) +{ + kfree(TO_DCN20_DPP(*dpp)); + *dpp = NULL; +} + +static struct dpp *dcn301_dpp_create(struct dc_context *ctx, uint32_t inst) +{ + struct dcn3_dpp *dpp = + kzalloc(sizeof(struct dcn3_dpp), GFP_KERNEL); + + if (!dpp) + return NULL; + + if (dpp3_construct(dpp, ctx, inst, + &dpp_regs[inst], &tf_shift, &tf_mask)) + return &dpp->base; + + BREAK_TO_DEBUGGER(); + kfree(dpp); + return NULL; +} +static struct output_pixel_processor *dcn301_opp_create(struct dc_context *ctx, + uint32_t inst) +{ + struct dcn20_opp *opp = + kzalloc(sizeof(struct dcn20_opp), GFP_KERNEL); + + if (!opp) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dcn20_opp_construct(opp, ctx, inst, + &opp_regs[inst], &opp_shift, &opp_mask); + return &opp->base; +} + +static struct dce_aux *dcn301_aux_engine_create(struct dc_context *ctx, uint32_t inst) +{ + struct aux_engine_dce110 *aux_engine = + kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); + + if (!aux_engine) + return NULL; + + dce110_aux_engine_construct(aux_engine, ctx, inst, + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, + &aux_engine_regs[inst], + &aux_mask, + &aux_shift, + ctx->dc->caps.extended_aux_timeout_support); + + return &aux_engine->base; +} +#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST(id) } + +static const struct dce_i2c_registers i2c_hw_regs[] = { + i2c_inst_regs(1), + i2c_inst_regs(2), + i2c_inst_regs(3), + i2c_inst_regs(4), +}; + +static const struct dce_i2c_shift i2c_shifts = { + I2C_COMMON_MASK_SH_LIST_DCN2(__SHIFT) +}; + +static const struct dce_i2c_mask i2c_masks = { + I2C_COMMON_MASK_SH_LIST_DCN2(_MASK) +}; + +static struct dce_i2c_hw *dcn301_i2c_hw_create(struct dc_context *ctx, uint32_t inst) +{ + struct dce_i2c_hw *dce_i2c_hw = + kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); + + if (!dce_i2c_hw) + return NULL; + + dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst, + &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); + + return dce_i2c_hw; +} +static struct mpc *dcn301_mpc_create( + struct dc_context *ctx, + int num_mpcc, + int num_rmu) +{ + struct dcn30_mpc *mpc30 = kzalloc(sizeof(struct dcn30_mpc), + GFP_KERNEL); + + if (!mpc30) + return NULL; + + dcn30_mpc_construct(mpc30, ctx, + &mpc_regs, + &mpc_shift, + &mpc_mask, + num_mpcc, + num_rmu); + + return &mpc30->base; +} + +static struct hubbub *dcn301_hubbub_create(struct dc_context *ctx) +{ + int i; + + struct dcn20_hubbub *hubbub3 = kzalloc(sizeof(struct dcn20_hubbub), + GFP_KERNEL); + + if (!hubbub3) + return NULL; + + hubbub301_construct(hubbub3, ctx, + &hubbub_reg, + &hubbub_shift, + &hubbub_mask); + + + for (i = 0; i < res_cap_dcn301.num_vmid; i++) { + struct dcn20_vmid *vmid = &hubbub3->vmid[i]; + + vmid->ctx = ctx; + + vmid->regs = &vmid_regs[i]; + vmid->shifts = &vmid_shifts; + vmid->masks = &vmid_masks; + } + + hubbub3->num_vmid = res_cap_dcn301.num_vmid; + + return &hubbub3->base; +} + +static struct timing_generator *dcn301_timing_generator_create( + struct dc_context *ctx, uint32_t instance) +{ + struct optc *tgn10 = + kzalloc(sizeof(struct optc), GFP_KERNEL); + + if (!tgn10) + return NULL; + + tgn10->base.inst = instance; + tgn10->base.ctx = ctx; + + tgn10->tg_regs = &optc_regs[instance]; + tgn10->tg_shift = &optc_shift; + tgn10->tg_mask = &optc_mask; + + dcn301_timing_generator_init(tgn10); + + return &tgn10->base; +} + +static const struct encoder_feature_support link_enc_feature = { + .max_hdmi_deep_color = COLOR_DEPTH_121212, + .max_hdmi_pixel_clock = 600000, + .hdmi_ycbcr420_supported = true, + .dp_ycbcr420_supported = true, + .fec_supported = true, + .flags.bits.IS_HBR2_CAPABLE = true, + .flags.bits.IS_HBR3_CAPABLE = true, + .flags.bits.IS_TPS3_CAPABLE = true, + .flags.bits.IS_TPS4_CAPABLE = true +}; + +static struct link_encoder *dcn301_link_encoder_create( + struct dc_context *ctx, + const struct encoder_init_data *enc_init_data) +{ + struct dcn20_link_encoder *enc20 = + kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); + + if (!enc20) + return NULL; + + dcn301_link_encoder_construct(enc20, + enc_init_data, + &link_enc_feature, + &link_enc_regs[enc_init_data->transmitter], + &link_enc_aux_regs[enc_init_data->channel - 1], + &link_enc_hpd_regs[enc_init_data->hpd_source], + &le_shift, + &le_mask); + + return &enc20->enc10.base; +} + +static struct panel_cntl *dcn301_panel_cntl_create(const struct panel_cntl_init_data *init_data) +{ + struct dcn301_panel_cntl *panel_cntl = + kzalloc(sizeof(struct dcn301_panel_cntl), GFP_KERNEL); + + if (!panel_cntl) + return NULL; + + dcn301_panel_cntl_construct(panel_cntl, + init_data, + &panel_cntl_regs[init_data->inst], + &panel_cntl_shift, + &panel_cntl_mask); + + return &panel_cntl->base; +} + + +#define CTX ctx + +#define REG(reg_name) \ + (DCN_BASE.instance[0].segment[mm ## reg_name ## _BASE_IDX] + mm ## reg_name) + +static uint32_t read_pipe_fuses(struct dc_context *ctx) +{ + uint32_t value = REG_READ(CC_DC_PIPE_DIS); + /* RV1 support max 4 pipes */ + value = value & 0xf; + return value; +} + + +static void read_dce_straps( + struct dc_context *ctx, + struct resource_straps *straps) +{ + generic_reg_get(ctx, mmDC_PINSTRAPS + BASE(mmDC_PINSTRAPS_BASE_IDX), + FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio); + +} + +static struct audio *dcn301_create_audio( + struct dc_context *ctx, unsigned int inst) +{ + return dce_audio_create(ctx, inst, + &audio_regs[inst], &audio_shift, &audio_mask); +} + +static struct vpg *dcn301_vpg_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn30_vpg *vpg3 = kzalloc(sizeof(struct dcn30_vpg), GFP_KERNEL); + + if (!vpg3) + return NULL; + + vpg3_construct(vpg3, ctx, inst, + &vpg_regs[inst], + &vpg_shift, + &vpg_mask); + + return &vpg3->base; +} + +static struct afmt *dcn301_afmt_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn30_afmt *afmt3 = kzalloc(sizeof(struct dcn30_afmt), GFP_KERNEL); + + if (!afmt3) + return NULL; + + afmt3_construct(afmt3, ctx, inst, + &afmt_regs[inst], + &afmt_shift, + &afmt_mask); + + return &afmt3->base; +} + +static struct stream_encoder *dcn301_stream_encoder_create(enum engine_id eng_id, + struct dc_context *ctx) +{ + struct dcn10_stream_encoder *enc1; + struct vpg *vpg; + struct afmt *afmt; + int vpg_inst; + int afmt_inst; + + /* Mapping of VPG, AFMT, DME register blocks to DIO block instance */ + if (eng_id <= ENGINE_ID_DIGF) { + vpg_inst = eng_id; + afmt_inst = eng_id; + } else + return NULL; + + enc1 = kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL); + vpg = dcn301_vpg_create(ctx, vpg_inst); + afmt = dcn301_afmt_create(ctx, afmt_inst); + + if (!enc1 || !vpg || !afmt) { + kfree(enc1); + kfree(vpg); + kfree(afmt); + return NULL; + } + + dcn30_dio_stream_encoder_construct(enc1, ctx, ctx->dc_bios, + eng_id, vpg, afmt, + &stream_enc_regs[eng_id], + &se_shift, &se_mask); + + return &enc1->base; +} + +static struct dce_hwseq *dcn301_hwseq_create(struct dc_context *ctx) +{ + struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); + + if (hws) { + hws->ctx = ctx; + hws->regs = &hwseq_reg; + hws->shifts = &hwseq_shift; + hws->masks = &hwseq_mask; + } + return hws; +} +static const struct resource_create_funcs res_create_funcs = { + .read_dce_straps = read_dce_straps, + .create_audio = dcn301_create_audio, + .create_stream_encoder = dcn301_stream_encoder_create, + .create_hwseq = dcn301_hwseq_create, +}; + +static void dcn301_destruct(struct dcn301_resource_pool *pool) +{ + unsigned int i; + + for (i = 0; i < pool->base.stream_enc_count; i++) { + if (pool->base.stream_enc[i] != NULL) { + if (pool->base.stream_enc[i]->vpg != NULL) { + kfree(DCN30_VPG_FROM_VPG(pool->base.stream_enc[i]->vpg)); + pool->base.stream_enc[i]->vpg = NULL; + } + if (pool->base.stream_enc[i]->afmt != NULL) { + kfree(DCN30_AFMT_FROM_AFMT(pool->base.stream_enc[i]->afmt)); + pool->base.stream_enc[i]->afmt = NULL; + } + kfree(DCN10STRENC_FROM_STRENC(pool->base.stream_enc[i])); + pool->base.stream_enc[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_dsc; i++) { + if (pool->base.dscs[i] != NULL) + dcn20_dsc_destroy(&pool->base.dscs[i]); + } + + if (pool->base.mpc != NULL) { + kfree(TO_DCN20_MPC(pool->base.mpc)); + pool->base.mpc = NULL; + } + if (pool->base.hubbub != NULL) { + kfree(pool->base.hubbub); + pool->base.hubbub = NULL; + } + for (i = 0; i < pool->base.pipe_count; i++) { + if (pool->base.dpps[i] != NULL) + dcn301_dpp_destroy(&pool->base.dpps[i]); + + if (pool->base.ipps[i] != NULL) + pool->base.ipps[i]->funcs->ipp_destroy(&pool->base.ipps[i]); + + if (pool->base.hubps[i] != NULL) { + kfree(TO_DCN20_HUBP(pool->base.hubps[i])); + pool->base.hubps[i] = NULL; + } + + if (pool->base.irqs != NULL) { + dal_irq_service_destroy(&pool->base.irqs); + } + } + + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + if (pool->base.engines[i] != NULL) + dce110_engine_destroy(&pool->base.engines[i]); + if (pool->base.hw_i2cs[i] != NULL) { + kfree(pool->base.hw_i2cs[i]); + pool->base.hw_i2cs[i] = NULL; + } + if (pool->base.sw_i2cs[i] != NULL) { + kfree(pool->base.sw_i2cs[i]); + pool->base.sw_i2cs[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_opp; i++) { + if (pool->base.opps[i] != NULL) + pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]); + } + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + if (pool->base.timing_generators[i] != NULL) { + kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i])); + pool->base.timing_generators[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_dwb; i++) { + if (pool->base.dwbc[i] != NULL) { + kfree(TO_DCN30_DWBC(pool->base.dwbc[i])); + pool->base.dwbc[i] = NULL; + } + if (pool->base.mcif_wb[i] != NULL) { + kfree(TO_DCN30_MMHUBBUB(pool->base.mcif_wb[i])); + pool->base.mcif_wb[i] = NULL; + } + } + + for (i = 0; i < pool->base.audio_count; i++) { + if (pool->base.audios[i]) + dce_aud_destroy(&pool->base.audios[i]); + } + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] != NULL) { + dcn20_clock_source_destroy(&pool->base.clock_sources[i]); + pool->base.clock_sources[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_mpc_3dlut; i++) { + if (pool->base.mpc_lut[i] != NULL) { + dc_3dlut_func_release(pool->base.mpc_lut[i]); + pool->base.mpc_lut[i] = NULL; + } + if (pool->base.mpc_shaper[i] != NULL) { + dc_transfer_func_release(pool->base.mpc_shaper[i]); + pool->base.mpc_shaper[i] = NULL; + } + } + + if (pool->base.dp_clock_source != NULL) { + dcn20_clock_source_destroy(&pool->base.dp_clock_source); + pool->base.dp_clock_source = NULL; + } + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + if (pool->base.multiple_abms[i] != NULL) + dce_abm_destroy(&pool->base.multiple_abms[i]); + } + + if (pool->base.dccg != NULL) + dcn_dccg_destroy(&pool->base.dccg); +} + +static struct hubp *dcn301_hubp_create(struct dc_context *ctx, uint32_t inst) +{ + struct dcn20_hubp *hubp2 = + kzalloc(sizeof(struct dcn20_hubp), GFP_KERNEL); + + if (!hubp2) + return NULL; + + if (hubp3_construct(hubp2, ctx, inst, + &hubp_regs[inst], &hubp_shift, &hubp_mask)) + return &hubp2->base; + + BREAK_TO_DEBUGGER(); + kfree(hubp2); + return NULL; +} + +static bool dcn301_dwbc_create(struct dc_context *ctx, struct resource_pool *pool) +{ + int i; + uint32_t pipe_count = pool->res_cap->num_dwb; + + for (i = 0; i < pipe_count; i++) { + struct dcn30_dwbc *dwbc30 = kzalloc(sizeof(struct dcn30_dwbc), + GFP_KERNEL); + + if (!dwbc30) { + dm_error("DC: failed to create dwbc30!\n"); + return false; + } + + dcn30_dwbc_construct(dwbc30, ctx, + &dwbc30_regs[i], + &dwbc30_shift, + &dwbc30_mask, + i); + + pool->dwbc[i] = &dwbc30->base; + } + return true; +} + +static bool dcn301_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool) +{ + int i; + uint32_t pipe_count = pool->res_cap->num_dwb; + + for (i = 0; i < pipe_count; i++) { + struct dcn30_mmhubbub *mcif_wb30 = kzalloc(sizeof(struct dcn30_mmhubbub), + GFP_KERNEL); + + if (!mcif_wb30) { + dm_error("DC: failed to create mcif_wb30!\n"); + return false; + } + + dcn30_mmhubbub_construct(mcif_wb30, ctx, + &mcif_wb30_regs[i], + &mcif_wb30_shift, + &mcif_wb30_mask, + i); + + pool->mcif_wb[i] = &mcif_wb30->base; + } + return true; +} + +static struct display_stream_compressor *dcn301_dsc_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dcn20_dsc *dsc = + kzalloc(sizeof(struct dcn20_dsc), GFP_KERNEL); + + if (!dsc) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dsc2_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask); + return &dsc->base; +} + + +static void dcn301_destroy_resource_pool(struct resource_pool **pool) +{ + struct dcn301_resource_pool *dcn301_pool = TO_DCN301_RES_POOL(*pool); + + dcn301_destruct(dcn301_pool); + kfree(dcn301_pool); + *pool = NULL; +} + +static struct clock_source *dcn301_clock_source_create( + struct dc_context *ctx, + struct dc_bios *bios, + enum clock_source_id id, + const struct dce110_clk_src_regs *regs, + bool dp_clk_src) +{ + struct dce110_clk_src *clk_src = + kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); + + if (!clk_src) + return NULL; + + if (dcn301_clk_src_construct(clk_src, ctx, bios, id, + regs, &cs_shift, &cs_mask)) { + clk_src->base.dp_clk_src = dp_clk_src; + return &clk_src->base; + } + + kfree(clk_src); + BREAK_TO_DEBUGGER(); + return NULL; +} + +static struct dc_cap_funcs cap_funcs = { + .get_dcc_compression_cap = dcn20_get_dcc_compression_cap +}; + + +static bool is_soc_bounding_box_valid(struct dc *dc) +{ + uint32_t hw_internal_rev = dc->ctx->asic_id.hw_internal_rev; + + if (ASICREV_IS_VANGOGH(hw_internal_rev)) + return true; + + return false; +} + +static bool init_soc_bounding_box(struct dc *dc, + struct dcn301_resource_pool *pool) +{ + struct _vcs_dpi_soc_bounding_box_st *loaded_bb = &dcn3_01_soc; + struct _vcs_dpi_ip_params_st *loaded_ip = &dcn3_01_ip; + + DC_LOGGER_INIT(dc->ctx->logger); + + if (!is_soc_bounding_box_valid(dc)) { + DC_LOG_ERROR("%s: not valid soc bounding box\n", __func__); + return false; + } + + loaded_ip->max_num_otg = pool->base.res_cap->num_timing_generator; + loaded_ip->max_num_dpp = pool->base.pipe_count; + DC_FP_START(); + dcn20_patch_bounding_box(dc, loaded_bb); + DC_FP_END(); + + if (dc->ctx->dc_bios->funcs->get_soc_bb_info) { + struct bp_soc_bb_info bb_info = {0}; + + if (dc->ctx->dc_bios->funcs->get_soc_bb_info(dc->ctx->dc_bios, &bb_info) == BP_RESULT_OK) { + DC_FP_START(); + dcn301_fpu_init_soc_bounding_box(bb_info); + DC_FP_END(); + } + } + + return true; +} + + +static void set_wm_ranges( + struct pp_smu_funcs *pp_smu, + struct _vcs_dpi_soc_bounding_box_st *loaded_bb) +{ + struct pp_smu_wm_range_sets ranges = {0}; + int i; + + ranges.num_reader_wm_sets = 0; + + if (loaded_bb->num_states == 1) { + ranges.reader_wm_sets[0].wm_inst = 0; + ranges.reader_wm_sets[0].min_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; + ranges.reader_wm_sets[0].max_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; + ranges.reader_wm_sets[0].min_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; + ranges.reader_wm_sets[0].max_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; + + ranges.num_reader_wm_sets = 1; + } else if (loaded_bb->num_states > 1) { + for (i = 0; i < 4 && i < loaded_bb->num_states; i++) { + ranges.reader_wm_sets[i].wm_inst = i; + ranges.reader_wm_sets[i].min_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; + ranges.reader_wm_sets[i].max_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; + DC_FP_START(); + dcn301_fpu_set_wm_ranges(i, &ranges, loaded_bb); + DC_FP_END(); + ranges.num_reader_wm_sets = i + 1; + } + + ranges.reader_wm_sets[0].min_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; + ranges.reader_wm_sets[ranges.num_reader_wm_sets - 1].max_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; + } + + ranges.num_writer_wm_sets = 1; + + ranges.writer_wm_sets[0].wm_inst = 0; + ranges.writer_wm_sets[0].min_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; + ranges.writer_wm_sets[0].max_fill_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; + ranges.writer_wm_sets[0].min_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN; + ranges.writer_wm_sets[0].max_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX; + + /* Notify PP Lib/SMU which Watermarks to use for which clock ranges */ + pp_smu->nv_funcs.set_wm_ranges(&pp_smu->nv_funcs.pp_smu, &ranges); +} + +static void dcn301_calculate_wm_and_dlg( + struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int pipe_cnt, + int vlevel) +{ + DC_FP_START(); + dcn301_calculate_wm_and_dlg_fp(dc, context, pipes, pipe_cnt, vlevel); + DC_FP_END(); +} + +static struct resource_funcs dcn301_res_pool_funcs = { + .destroy = dcn301_destroy_resource_pool, + .link_enc_create = dcn301_link_encoder_create, + .panel_cntl_create = dcn301_panel_cntl_create, + .validate_bandwidth = dcn30_validate_bandwidth, + .calculate_wm_and_dlg = dcn301_calculate_wm_and_dlg, + .update_soc_for_wm_a = dcn30_update_soc_for_wm_a, + .populate_dml_pipes = dcn30_populate_dml_pipes_from_context, + .acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer, + .release_pipe = dcn20_release_pipe, + .add_stream_to_ctx = dcn30_add_stream_to_ctx, + .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource, + .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, + .populate_dml_writeback_from_context = dcn30_populate_dml_writeback_from_context, + .set_mcif_arb_params = dcn30_set_mcif_arb_params, + .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, + .patch_unknown_plane_state = dcn20_patch_unknown_plane_state +}; + +static bool dcn301_resource_construct( + uint8_t num_virtual_links, + struct dc *dc, + struct dcn301_resource_pool *pool) +{ + int i, j; + struct dc_context *ctx = dc->ctx; + struct irq_service_init_data init_data; + uint32_t pipe_fuses = read_pipe_fuses(ctx); + uint32_t num_pipes = 0; + + DC_LOGGER_INIT(dc->ctx->logger); + + ctx->dc_bios->regs = &bios_regs; + + if (dc->ctx->asic_id.chip_id == DEVICE_ID_VGH_1435) + res_cap_dcn301.num_pll = 2; + pool->base.res_cap = &res_cap_dcn301; + + pool->base.funcs = &dcn301_res_pool_funcs; + + /************************************************* + * Resource + asic cap harcoding * + *************************************************/ + pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.pipe_count = pool->base.res_cap->num_timing_generator; + 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 = 5; /*1.4 w/a enabled by default*/ + dc->caps.max_cursor_size = 256; + dc->caps.min_horizontal_blanking_period = 80; + dc->caps.dmdata_alloc_size = 2048; + dc->caps.max_slave_planes = 2; + dc->caps.max_slave_yuv_planes = 2; + dc->caps.max_slave_rgb_planes = 2; + dc->caps.is_apu = true; + dc->caps.post_blend_color_processing = true; + dc->caps.force_dp_tps4_for_cp2520 = true; + dc->caps.extended_aux_timeout_support = true; + dc->caps.dmcub_support = true; + + /* Color pipeline capabilities */ + dc->caps.color.dpp.dcn_arch = 1; + dc->caps.color.dpp.input_lut_shared = 0; + dc->caps.color.dpp.icsc = 1; + dc->caps.color.dpp.dgam_ram = 0; // must use gamma_corr + dc->caps.color.dpp.dgam_rom_caps.srgb = 1; + dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1; + dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 1; + dc->caps.color.dpp.dgam_rom_caps.pq = 1; + dc->caps.color.dpp.dgam_rom_caps.hlg = 1; + dc->caps.color.dpp.post_csc = 1; + dc->caps.color.dpp.gamma_corr = 1; + dc->caps.color.dpp.dgam_rom_for_yuv = 0; + + dc->caps.color.dpp.hw_3d_lut = 1; + dc->caps.color.dpp.ogam_ram = 1; + // no OGAM ROM on DCN301 + dc->caps.color.dpp.ogam_rom_caps.srgb = 0; + dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0; + dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0; + dc->caps.color.dpp.ogam_rom_caps.pq = 0; + dc->caps.color.dpp.ogam_rom_caps.hlg = 0; + dc->caps.color.dpp.ocsc = 0; + + dc->caps.color.mpc.gamut_remap = 1; + dc->caps.color.mpc.num_3dluts = pool->base.res_cap->num_mpc_3dlut; //2 + dc->caps.color.mpc.ogam_ram = 1; + dc->caps.color.mpc.ogam_rom_caps.srgb = 0; + dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0; + dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0; + dc->caps.color.mpc.ogam_rom_caps.pq = 0; + dc->caps.color.mpc.ogam_rom_caps.hlg = 0; + dc->caps.color.mpc.ocsc = 1; + + dc->caps.dp_hdmi21_pcon_support = true; + + /* read VBIOS LTTPR caps */ + if (ctx->dc_bios->funcs->get_lttpr_caps) { + enum bp_result bp_query_result; + uint8_t is_vbios_lttpr_enable = 0; + + bp_query_result = ctx->dc_bios->funcs->get_lttpr_caps(ctx->dc_bios, &is_vbios_lttpr_enable); + dc->caps.vbios_lttpr_enable = (bp_query_result == BP_RESULT_OK) && !!is_vbios_lttpr_enable; + } + + if (ctx->dc_bios->funcs->get_lttpr_interop) { + enum bp_result bp_query_result; + uint8_t is_vbios_interop_enabled = 0; + + bp_query_result = ctx->dc_bios->funcs->get_lttpr_interop(ctx->dc_bios, &is_vbios_interop_enabled); + dc->caps.vbios_lttpr_aware = (bp_query_result == BP_RESULT_OK) && !!is_vbios_interop_enabled; + } + + if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) + dc->debug = debug_defaults_drv; + + // Init the vm_helper + if (dc->vm_helper) + vm_helper_init(dc->vm_helper, 16); + + /************************************************* + * Create resources * + *************************************************/ + + /* Clock Sources for Pixel Clock*/ + pool->base.clock_sources[DCN301_CLK_SRC_PLL0] = + dcn301_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL0, + &clk_src_regs[0], false); + pool->base.clock_sources[DCN301_CLK_SRC_PLL1] = + dcn301_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL1, + &clk_src_regs[1], false); + pool->base.clock_sources[DCN301_CLK_SRC_PLL2] = + dcn301_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL2, + &clk_src_regs[2], false); + pool->base.clock_sources[DCN301_CLK_SRC_PLL3] = + dcn301_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL3, + &clk_src_regs[3], false); + + pool->base.clk_src_count = DCN301_CLK_SRC_TOTAL; + + /* todo: not reuse phy_pll registers */ + pool->base.dp_clock_source = + dcn301_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_ID_DP_DTO, + &clk_src_regs[0], true); + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] == NULL) { + dm_error("DC: failed to create clock sources!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + } + + /* DCCG */ + pool->base.dccg = dccg301_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask); + if (pool->base.dccg == NULL) { + dm_error("DC: failed to create dccg!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + init_soc_bounding_box(dc, pool); + + if (!dc->debug.disable_pplib_wm_range && pool->base.pp_smu->nv_funcs.set_wm_ranges) + set_wm_ranges(pool->base.pp_smu, &dcn3_01_soc); + + num_pipes = dcn3_01_ip.max_num_dpp; + + for (i = 0; i < dcn3_01_ip.max_num_dpp; i++) + if (pipe_fuses & 1 << i) + num_pipes--; + dcn3_01_ip.max_num_dpp = num_pipes; + dcn3_01_ip.max_num_otg = num_pipes; + + + dml_init_instance(&dc->dml, &dcn3_01_soc, &dcn3_01_ip, DML_PROJECT_DCN30); + + /* IRQ */ + init_data.ctx = dc->ctx; + pool->base.irqs = dal_irq_service_dcn30_create(&init_data); + if (!pool->base.irqs) + goto create_fail; + + /* HUBBUB */ + pool->base.hubbub = dcn301_hubbub_create(ctx); + if (pool->base.hubbub == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create hubbub!\n"); + goto create_fail; + } + + j = 0; + /* HUBPs, DPPs, OPPs and TGs */ + for (i = 0; i < pool->base.pipe_count; i++) { + + /* if pipe is disabled, skip instance of HW pipe, + * i.e, skip ASIC register instance + */ + if ((pipe_fuses & (1 << i)) != 0) { + DC_LOG_DEBUG("%s: fusing pipe %d\n", __func__, i); + continue; + } + + pool->base.hubps[j] = dcn301_hubp_create(ctx, i); + if (pool->base.hubps[j] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create hubps!\n"); + goto create_fail; + } + + pool->base.dpps[j] = dcn301_dpp_create(ctx, i); + if (pool->base.dpps[j] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create dpps!\n"); + goto create_fail; + } + + pool->base.opps[j] = dcn301_opp_create(ctx, i); + if (pool->base.opps[j] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create output pixel processor!\n"); + goto create_fail; + } + + pool->base.timing_generators[j] = dcn301_timing_generator_create(ctx, i); + if (pool->base.timing_generators[j] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create tg!\n"); + goto create_fail; + } + j++; + } + pool->base.timing_generator_count = j; + pool->base.pipe_count = j; + pool->base.mpcc_count = j; + + /* ABM (or ABMs for NV2x) */ + /* TODO: */ + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + pool->base.multiple_abms[i] = dmub_abm_create(ctx, + &abm_regs[i], + &abm_shift, + &abm_mask); + if (pool->base.multiple_abms[i] == NULL) { + dm_error("DC: failed to create abm for pipe %d!\n", i); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + } + + /* MPC and DSC */ + pool->base.mpc = dcn301_mpc_create(ctx, pool->base.mpcc_count, pool->base.res_cap->num_mpc_3dlut); + if (pool->base.mpc == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create mpc!\n"); + goto create_fail; + } + + for (i = 0; i < pool->base.res_cap->num_dsc; i++) { + pool->base.dscs[i] = dcn301_dsc_create(ctx, i); + if (pool->base.dscs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create display stream compressor %d!\n", i); + goto create_fail; + } + } + + /* DWB and MMHUBBUB */ + if (!dcn301_dwbc_create(ctx, &pool->base)) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dwbc!\n"); + goto create_fail; + } + + if (!dcn301_mmhubbub_create(ctx, &pool->base)) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create mcif_wb!\n"); + goto create_fail; + } + + /* AUX and I2C */ + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + pool->base.engines[i] = dcn301_aux_engine_create(ctx, i); + if (pool->base.engines[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create aux engine!!\n"); + goto create_fail; + } + pool->base.hw_i2cs[i] = dcn301_i2c_hw_create(ctx, i); + if (pool->base.hw_i2cs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create hw i2c!!\n"); + goto create_fail; + } + pool->base.sw_i2cs[i] = NULL; + } + + /* Audio, Stream Encoders including HPO and virtual, MPC 3D LUTs */ + if (!resource_construct(num_virtual_links, dc, &pool->base, + &res_create_funcs)) + goto create_fail; + + /* HW Sequencer and Plane caps */ + dcn301_hw_sequencer_construct(dc); + + dc->caps.max_planes = pool->base.pipe_count; + + for (i = 0; i < dc->caps.max_planes; ++i) + dc->caps.planes[i] = plane_cap; + + dc->cap_funcs = cap_funcs; + + return true; + +create_fail: + + dcn301_destruct(pool); + + return false; +} + +struct resource_pool *dcn301_create_resource_pool( + const struct dc_init_data *init_data, + struct dc *dc) +{ + struct dcn301_resource_pool *pool = + kzalloc(sizeof(struct dcn301_resource_pool), GFP_KERNEL); + + if (!pool) + return NULL; + + if (dcn301_resource_construct(init_data->num_virtual_links, dc, pool)) + return &pool->base; + + BREAK_TO_DEBUGGER(); + kfree(pool); + return NULL; +} diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.h new file mode 100644 index 00000000000000..ae8672680cdd13 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.h @@ -0,0 +1,45 @@ +/* + * Copyright 2020 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 _DCN301_RESOURCE_H_ +#define _DCN301_RESOURCE_H_ + +#include "core_types.h" + +struct dc; +struct resource_pool; +struct _vcs_dpi_display_pipe_params_st; + +extern struct _vcs_dpi_ip_params_st dcn3_01_ip; +extern struct _vcs_dpi_soc_bounding_box_st dcn3_01_soc; + +struct dcn301_resource_pool { + struct resource_pool base; +}; +struct resource_pool *dcn301_create_resource_pool( + const struct dc_init_data *init_data, + struct dc *dc); + +#endif /* _DCN301_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.c new file mode 100644 index 00000000000000..5791b5cc287529 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.c @@ -0,0 +1,1518 @@ +/* + * Copyright 2020 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 "dcn302/dcn302_init.h" +#include "dcn302_resource.h" +#include "dcn302/dcn302_dccg.h" +#include "irq/dcn302/irq_service_dcn302.h" + +#include "dcn30/dcn30_dio_link_encoder.h" +#include "dcn30/dcn30_dio_stream_encoder.h" +#include "dcn30/dcn30_dwb.h" +#include "dcn30/dcn30_dpp.h" +#include "dcn30/dcn30_hubbub.h" +#include "dcn30/dcn30_hubp.h" +#include "dcn30/dcn30_mmhubbub.h" +#include "dcn30/dcn30_mpc.h" +#include "dcn30/dcn30_opp.h" +#include "dcn30/dcn30_optc.h" +#include "dcn30/dcn30_resource.h" + +#include "dcn20/dcn20_dsc.h" +#include "dcn20/dcn20_resource.h" + +#include "dml/dcn30/dcn30_fpu.h" + +#include "dcn10/dcn10_resource.h" + +#include "link.h" +#include "dce/dce_abm.h" +#include "dce/dce_audio.h" +#include "dce/dce_aux.h" +#include "dce/dce_clock_source.h" +#include "dce/dce_hwseq.h" +#include "dce/dce_i2c_hw.h" +#include "dce/dce_panel_cntl.h" +#include "dce/dmub_abm.h" +#include "dce/dmub_psr.h" +#include "clk_mgr.h" + +#include "hw_sequencer_private.h" +#include "reg_helper.h" +#include "resource.h" +#include "vm_helper.h" + +#include "dml/dcn302/dcn302_fpu.h" + +#include "dimgrey_cavefish_ip_offset.h" +#include "dcn/dcn_3_0_2_offset.h" +#include "dcn/dcn_3_0_2_sh_mask.h" +#include "dpcs/dpcs_3_0_0_offset.h" +#include "dpcs/dpcs_3_0_0_sh_mask.h" +#include "nbio/nbio_7_4_offset.h" +#include "amdgpu_socbb.h" + +#define DC_LOGGER \ + dc->ctx->logger +#define DC_LOGGER_INIT(logger) + +static const struct dc_debug_options debug_defaults_drv = { + .disable_dmcu = true, + .force_abm_enable = false, + .timing_trace = false, + .clock_trace = true, + .disable_pplib_clock_request = true, + .pipe_split_policy = MPC_SPLIT_DYNAMIC, + .force_single_disp_pipe_split = false, + .disable_dcc = DCC_ENABLE, + .vsr_support = true, + .performance_trace = false, + .max_downscale_src_width = 7680,/*upto 8K*/ + .disable_pplib_wm_range = false, + .scl_reset_length10 = true, + .sanity_checks = false, + .underflow_assert_delay_us = 0xFFFFFFFF, + .dwb_fi_phase = -1, // -1 = disable, + .dmub_command_table = true, + .use_max_lb = true, + .exit_idle_opt_for_cursor_updates = true, + .enable_legacy_fast_update = false, + .using_dml2 = false, +}; + +static const struct dc_panel_config panel_config_defaults = { + .psr = { + .disable_psr = false, + .disallow_psrsu = false, + .disallow_replay = false, + }, +}; + +enum dcn302_clk_src_array_id { + DCN302_CLK_SRC_PLL0, + DCN302_CLK_SRC_PLL1, + DCN302_CLK_SRC_PLL2, + DCN302_CLK_SRC_PLL3, + DCN302_CLK_SRC_PLL4, + DCN302_CLK_SRC_TOTAL +}; + +static const struct resource_caps res_cap_dcn302 = { + .num_timing_generator = 5, + .num_opp = 5, + .num_video_plane = 5, + .num_audio = 5, + .num_stream_encoder = 5, + .num_dwb = 1, + .num_ddc = 5, + .num_vmid = 16, + .num_mpc_3dlut = 2, + .num_dsc = 5, +}; + +static const struct dc_plane_cap plane_cap = { + .type = DC_PLANE_TYPE_DCN_UNIVERSAL, + .per_pixel_alpha = true, + .pixel_format_support = { + .argb8888 = true, + .nv12 = true, + .fp16 = true, + .p010 = true, + .ayuv = false, + }, + .max_upscale_factor = { + .argb8888 = 16000, + .nv12 = 16000, + .fp16 = 16000 + }, + /* 6:1 downscaling ratio: 1000/6 = 166.666 */ + .max_downscale_factor = { + .argb8888 = 167, + .nv12 = 167, + .fp16 = 167 + }, + 16, + 16 +}; + +/* NBIO */ +#define NBIO_BASE_INNER(seg) \ + NBIO_BASE__INST0_SEG ## seg + +#define NBIO_BASE(seg) \ + NBIO_BASE_INNER(seg) + +#define NBIO_SR(reg_name)\ + .reg_name = NBIO_BASE(mm ## reg_name ## _BASE_IDX) + \ + mm ## reg_name + +/* DCN */ +#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg + +#define BASE(seg) BASE_INNER(seg) + +#define SR(reg_name)\ + .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + mm ## reg_name + +#define SF(reg_name, field_name, post_fix)\ + .field_name = reg_name ## __ ## field_name ## post_fix + +#define SRI(reg_name, block, id)\ + .reg_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + mm ## block ## id ## _ ## reg_name + +#define SRI2(reg_name, block, id)\ + .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + mm ## reg_name + +#define SRII(reg_name, block, id)\ + .reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define DCCG_SRII(reg_name, block, id)\ + .block ## _ ## reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define VUPDATE_SRII(reg_name, block, id)\ + .reg_name[id] = BASE(mm ## reg_name ## _ ## block ## id ## _BASE_IDX) + \ + mm ## reg_name ## _ ## block ## id + +#define SRII_DWB(reg_name, temp_name, block, id)\ + .reg_name[id] = BASE(mm ## block ## id ## _ ## temp_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## temp_name + +#define SF_DWB2(reg_name, block, id, field_name, post_fix) \ + .field_name = reg_name ## __ ## field_name ## post_fix + +#define SRII_MPC_RMU(reg_name, block, id)\ + .RMU##_##reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +static const struct dcn_hubbub_registers hubbub_reg = { + HUBBUB_REG_LIST_DCN30(0) +}; + +static const struct dcn_hubbub_shift hubbub_shift = { + HUBBUB_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn_hubbub_mask hubbub_mask = { + HUBBUB_MASK_SH_LIST_DCN30(_MASK) +}; + +#define vmid_regs(id)\ + [id] = { DCN20_VMID_REG_LIST(id) } + +static const struct dcn_vmid_registers vmid_regs[] = { + vmid_regs(0), + vmid_regs(1), + vmid_regs(2), + vmid_regs(3), + vmid_regs(4), + vmid_regs(5), + vmid_regs(6), + vmid_regs(7), + vmid_regs(8), + vmid_regs(9), + vmid_regs(10), + vmid_regs(11), + vmid_regs(12), + vmid_regs(13), + vmid_regs(14), + vmid_regs(15) +}; + +static const struct dcn20_vmid_shift vmid_shifts = { + DCN20_VMID_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn20_vmid_mask vmid_masks = { + DCN20_VMID_MASK_SH_LIST(_MASK) +}; + +static struct hubbub *dcn302_hubbub_create(struct dc_context *ctx) +{ + int i; + + struct dcn20_hubbub *hubbub3 = kzalloc(sizeof(struct dcn20_hubbub), GFP_KERNEL); + + if (!hubbub3) + return NULL; + + hubbub3_construct(hubbub3, ctx, &hubbub_reg, &hubbub_shift, &hubbub_mask); + + for (i = 0; i < res_cap_dcn302.num_vmid; i++) { + struct dcn20_vmid *vmid = &hubbub3->vmid[i]; + + vmid->ctx = ctx; + + vmid->regs = &vmid_regs[i]; + vmid->shifts = &vmid_shifts; + vmid->masks = &vmid_masks; + } + + return &hubbub3->base; +} + +#define vpg_regs(id)\ + [id] = { VPG_DCN3_REG_LIST(id) } + +static const struct dcn30_vpg_registers vpg_regs[] = { + vpg_regs(0), + vpg_regs(1), + vpg_regs(2), + vpg_regs(3), + vpg_regs(4), + vpg_regs(5) +}; + +static const struct dcn30_vpg_shift vpg_shift = { + DCN3_VPG_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn30_vpg_mask vpg_mask = { + DCN3_VPG_MASK_SH_LIST(_MASK) +}; + +static struct vpg *dcn302_vpg_create(struct dc_context *ctx, uint32_t inst) +{ + struct dcn30_vpg *vpg3 = kzalloc(sizeof(struct dcn30_vpg), GFP_KERNEL); + + if (!vpg3) + return NULL; + + vpg3_construct(vpg3, ctx, inst, &vpg_regs[inst], &vpg_shift, &vpg_mask); + + return &vpg3->base; +} + +#define afmt_regs(id)\ + [id] = { AFMT_DCN3_REG_LIST(id) } + +static const struct dcn30_afmt_registers afmt_regs[] = { + afmt_regs(0), + afmt_regs(1), + afmt_regs(2), + afmt_regs(3), + afmt_regs(4), + afmt_regs(5) +}; + +static const struct dcn30_afmt_shift afmt_shift = { + DCN3_AFMT_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn30_afmt_mask afmt_mask = { + DCN3_AFMT_MASK_SH_LIST(_MASK) +}; + +static struct afmt *dcn302_afmt_create(struct dc_context *ctx, uint32_t inst) +{ + struct dcn30_afmt *afmt3 = kzalloc(sizeof(struct dcn30_afmt), GFP_KERNEL); + + if (!afmt3) + return NULL; + + afmt3_construct(afmt3, ctx, inst, &afmt_regs[inst], &afmt_shift, &afmt_mask); + + return &afmt3->base; +} + +#define audio_regs(id)\ + [id] = { AUD_COMMON_REG_LIST(id) } + +static const struct dce_audio_registers audio_regs[] = { + audio_regs(0), + audio_regs(1), + audio_regs(2), + audio_regs(3), + audio_regs(4), + audio_regs(5), + audio_regs(6) +}; + +#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ + AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) + +static const struct dce_audio_shift audio_shift = { + DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_audio_mask audio_mask = { + DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) +}; + +static struct audio *dcn302_create_audio(struct dc_context *ctx, unsigned int inst) +{ + return dce_audio_create(ctx, inst, &audio_regs[inst], &audio_shift, &audio_mask); +} + +#define stream_enc_regs(id)\ + [id] = { SE_DCN3_REG_LIST(id) } + +static const struct dcn10_stream_enc_registers stream_enc_regs[] = { + stream_enc_regs(0), + stream_enc_regs(1), + stream_enc_regs(2), + stream_enc_regs(3), + stream_enc_regs(4) +}; + +static const struct dcn10_stream_encoder_shift se_shift = { + SE_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn10_stream_encoder_mask se_mask = { + SE_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +static struct stream_encoder *dcn302_stream_encoder_create(enum engine_id eng_id, struct dc_context *ctx) +{ + struct dcn10_stream_encoder *enc1; + struct vpg *vpg; + struct afmt *afmt; + int vpg_inst; + int afmt_inst; + + /* Mapping of VPG, AFMT, DME register blocks to DIO block instance */ + if (eng_id <= ENGINE_ID_DIGE) { + vpg_inst = eng_id; + afmt_inst = eng_id; + } else + return NULL; + + enc1 = kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL); + vpg = dcn302_vpg_create(ctx, vpg_inst); + afmt = dcn302_afmt_create(ctx, afmt_inst); + + if (!enc1 || !vpg || !afmt) { + kfree(enc1); + kfree(vpg); + kfree(afmt); + return NULL; + } + + dcn30_dio_stream_encoder_construct(enc1, ctx, ctx->dc_bios, eng_id, vpg, afmt, &stream_enc_regs[eng_id], + &se_shift, &se_mask); + + return &enc1->base; +} + +#define clk_src_regs(index, pllid)\ + [index] = { CS_COMMON_REG_LIST_DCN3_02(index, pllid) } + +static const struct dce110_clk_src_regs clk_src_regs[] = { + clk_src_regs(0, A), + clk_src_regs(1, B), + clk_src_regs(2, C), + clk_src_regs(3, D), + clk_src_regs(4, E) +}; + +static const struct dce110_clk_src_shift cs_shift = { + CS_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) +}; + +static const struct dce110_clk_src_mask cs_mask = { + CS_COMMON_MASK_SH_LIST_DCN2_0(_MASK) +}; + +static struct clock_source *dcn302_clock_source_create(struct dc_context *ctx, struct dc_bios *bios, + enum clock_source_id id, const struct dce110_clk_src_regs *regs, bool dp_clk_src) +{ + struct dce110_clk_src *clk_src = kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); + + if (!clk_src) + return NULL; + + if (dcn3_clk_src_construct(clk_src, ctx, bios, id, regs, &cs_shift, &cs_mask)) { + clk_src->base.dp_clk_src = dp_clk_src; + return &clk_src->base; + } + + kfree(clk_src); + BREAK_TO_DEBUGGER(); + return NULL; +} + +static const struct dce_hwseq_registers hwseq_reg = { + HWSEQ_DCN302_REG_LIST() +}; + +static const struct dce_hwseq_shift hwseq_shift = { + HWSEQ_DCN302_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_hwseq_mask hwseq_mask = { + HWSEQ_DCN302_MASK_SH_LIST(_MASK) +}; + +static struct dce_hwseq *dcn302_hwseq_create(struct dc_context *ctx) +{ + struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); + + if (hws) { + hws->ctx = ctx; + hws->regs = &hwseq_reg; + hws->shifts = &hwseq_shift; + hws->masks = &hwseq_mask; + } + return hws; +} + +#define hubp_regs(id)\ + [id] = { HUBP_REG_LIST_DCN30(id) } + +static const struct dcn_hubp2_registers hubp_regs[] = { + hubp_regs(0), + hubp_regs(1), + hubp_regs(2), + hubp_regs(3), + hubp_regs(4) +}; + +static const struct dcn_hubp2_shift hubp_shift = { + HUBP_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn_hubp2_mask hubp_mask = { + HUBP_MASK_SH_LIST_DCN30(_MASK) +}; + +static struct hubp *dcn302_hubp_create(struct dc_context *ctx, uint32_t inst) +{ + struct dcn20_hubp *hubp2 = kzalloc(sizeof(struct dcn20_hubp), GFP_KERNEL); + + if (!hubp2) + return NULL; + + if (hubp3_construct(hubp2, ctx, inst, &hubp_regs[inst], &hubp_shift, &hubp_mask)) + return &hubp2->base; + + BREAK_TO_DEBUGGER(); + kfree(hubp2); + return NULL; +} + +#define dpp_regs(id)\ + [id] = { DPP_REG_LIST_DCN30(id) } + +static const struct dcn3_dpp_registers dpp_regs[] = { + dpp_regs(0), + dpp_regs(1), + dpp_regs(2), + dpp_regs(3), + dpp_regs(4) +}; + +static const struct dcn3_dpp_shift tf_shift = { + DPP_REG_LIST_SH_MASK_DCN30(__SHIFT) +}; + +static const struct dcn3_dpp_mask tf_mask = { + DPP_REG_LIST_SH_MASK_DCN30(_MASK) +}; + +static struct dpp *dcn302_dpp_create(struct dc_context *ctx, uint32_t inst) +{ + struct dcn3_dpp *dpp = kzalloc(sizeof(struct dcn3_dpp), GFP_KERNEL); + + if (!dpp) + return NULL; + + if (dpp3_construct(dpp, ctx, inst, &dpp_regs[inst], &tf_shift, &tf_mask)) + return &dpp->base; + + BREAK_TO_DEBUGGER(); + kfree(dpp); + return NULL; +} + +#define opp_regs(id)\ + [id] = { OPP_REG_LIST_DCN30(id) } + +static const struct dcn20_opp_registers opp_regs[] = { + opp_regs(0), + opp_regs(1), + opp_regs(2), + opp_regs(3), + opp_regs(4) +}; + +static const struct dcn20_opp_shift opp_shift = { + OPP_MASK_SH_LIST_DCN20(__SHIFT) +}; + +static const struct dcn20_opp_mask opp_mask = { + OPP_MASK_SH_LIST_DCN20(_MASK) +}; + +static struct output_pixel_processor *dcn302_opp_create(struct dc_context *ctx, uint32_t inst) +{ + struct dcn20_opp *opp = kzalloc(sizeof(struct dcn20_opp), GFP_KERNEL); + + if (!opp) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dcn20_opp_construct(opp, ctx, inst, &opp_regs[inst], &opp_shift, &opp_mask); + return &opp->base; +} + +#define optc_regs(id)\ + [id] = { OPTC_COMMON_REG_LIST_DCN3_0(id) } + +static const struct dcn_optc_registers optc_regs[] = { + optc_regs(0), + optc_regs(1), + optc_regs(2), + optc_regs(3), + optc_regs(4) +}; + +static const struct dcn_optc_shift optc_shift = { + OPTC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn_optc_mask optc_mask = { + OPTC_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +static struct timing_generator *dcn302_timing_generator_create(struct dc_context *ctx, uint32_t instance) +{ + struct optc *tgn10 = kzalloc(sizeof(struct optc), GFP_KERNEL); + + if (!tgn10) + return NULL; + + tgn10->base.inst = instance; + tgn10->base.ctx = ctx; + + tgn10->tg_regs = &optc_regs[instance]; + tgn10->tg_shift = &optc_shift; + tgn10->tg_mask = &optc_mask; + + dcn30_timing_generator_init(tgn10); + + return &tgn10->base; +} + +static const struct dcn30_mpc_registers mpc_regs = { + MPC_REG_LIST_DCN3_0(0), + MPC_REG_LIST_DCN3_0(1), + MPC_REG_LIST_DCN3_0(2), + MPC_REG_LIST_DCN3_0(3), + MPC_REG_LIST_DCN3_0(4), + MPC_OUT_MUX_REG_LIST_DCN3_0(0), + MPC_OUT_MUX_REG_LIST_DCN3_0(1), + MPC_OUT_MUX_REG_LIST_DCN3_0(2), + MPC_OUT_MUX_REG_LIST_DCN3_0(3), + MPC_OUT_MUX_REG_LIST_DCN3_0(4), + MPC_RMU_GLOBAL_REG_LIST_DCN3AG, + MPC_RMU_REG_LIST_DCN3AG(0), + MPC_RMU_REG_LIST_DCN3AG(1), + MPC_RMU_REG_LIST_DCN3AG(2), + MPC_DWB_MUX_REG_LIST_DCN3_0(0), +}; + +static const struct dcn30_mpc_shift mpc_shift = { + MPC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn30_mpc_mask mpc_mask = { + MPC_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +static struct mpc *dcn302_mpc_create(struct dc_context *ctx, int num_mpcc, int num_rmu) +{ + struct dcn30_mpc *mpc30 = kzalloc(sizeof(struct dcn30_mpc), GFP_KERNEL); + + if (!mpc30) + return NULL; + + dcn30_mpc_construct(mpc30, ctx, &mpc_regs, &mpc_shift, &mpc_mask, num_mpcc, num_rmu); + + return &mpc30->base; +} + +#define dsc_regsDCN20(id)\ +[id] = { DSC_REG_LIST_DCN20(id) } + +static const struct dcn20_dsc_registers dsc_regs[] = { + dsc_regsDCN20(0), + dsc_regsDCN20(1), + dsc_regsDCN20(2), + dsc_regsDCN20(3), + dsc_regsDCN20(4) +}; + +static const struct dcn20_dsc_shift dsc_shift = { + DSC_REG_LIST_SH_MASK_DCN20(__SHIFT) +}; + +static const struct dcn20_dsc_mask dsc_mask = { + DSC_REG_LIST_SH_MASK_DCN20(_MASK) +}; + +static struct display_stream_compressor *dcn302_dsc_create(struct dc_context *ctx, uint32_t inst) +{ + struct dcn20_dsc *dsc = kzalloc(sizeof(struct dcn20_dsc), GFP_KERNEL); + + if (!dsc) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dsc2_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask); + return &dsc->base; +} + +#define dwbc_regs_dcn3(id)\ +[id] = { DWBC_COMMON_REG_LIST_DCN30(id) } + +static const struct dcn30_dwbc_registers dwbc30_regs[] = { + dwbc_regs_dcn3(0) +}; + +static const struct dcn30_dwbc_shift dwbc30_shift = { + DWBC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn30_dwbc_mask dwbc30_mask = { + DWBC_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +static bool dcn302_dwbc_create(struct dc_context *ctx, struct resource_pool *pool) +{ + int i; + uint32_t pipe_count = pool->res_cap->num_dwb; + + for (i = 0; i < pipe_count; i++) { + struct dcn30_dwbc *dwbc30 = kzalloc(sizeof(struct dcn30_dwbc), GFP_KERNEL); + + if (!dwbc30) { + dm_error("DC: failed to create dwbc30!\n"); + return false; + } + + dcn30_dwbc_construct(dwbc30, ctx, &dwbc30_regs[i], &dwbc30_shift, &dwbc30_mask, i); + + pool->dwbc[i] = &dwbc30->base; + } + return true; +} + +#define mcif_wb_regs_dcn3(id)\ +[id] = { MCIF_WB_COMMON_REG_LIST_DCN30(id) } + +static const struct dcn30_mmhubbub_registers mcif_wb30_regs[] = { + mcif_wb_regs_dcn3(0) +}; + +static const struct dcn30_mmhubbub_shift mcif_wb30_shift = { + MCIF_WB_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn30_mmhubbub_mask mcif_wb30_mask = { + MCIF_WB_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +static bool dcn302_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool) +{ + int i; + uint32_t pipe_count = pool->res_cap->num_dwb; + + for (i = 0; i < pipe_count; i++) { + struct dcn30_mmhubbub *mcif_wb30 = kzalloc(sizeof(struct dcn30_mmhubbub), GFP_KERNEL); + + if (!mcif_wb30) { + dm_error("DC: failed to create mcif_wb30!\n"); + return false; + } + + dcn30_mmhubbub_construct(mcif_wb30, ctx, &mcif_wb30_regs[i], &mcif_wb30_shift, &mcif_wb30_mask, i); + + pool->mcif_wb[i] = &mcif_wb30->base; + } + return true; +} + +#define aux_engine_regs(id)\ +[id] = {\ + AUX_COMMON_REG_LIST0(id), \ + .AUXN_IMPCAL = 0, \ + .AUXP_IMPCAL = 0, \ + .AUX_RESET_MASK = DP_AUX0_AUX_CONTROL__AUX_RESET_MASK, \ +} + +static const struct dce110_aux_registers aux_engine_regs[] = { + aux_engine_regs(0), + aux_engine_regs(1), + aux_engine_regs(2), + aux_engine_regs(3), + aux_engine_regs(4) +}; + +static const struct dce110_aux_registers_shift aux_shift = { + DCN_AUX_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce110_aux_registers_mask aux_mask = { + DCN_AUX_MASK_SH_LIST(_MASK) +}; + +static struct dce_aux *dcn302_aux_engine_create(struct dc_context *ctx, uint32_t inst) +{ + struct aux_engine_dce110 *aux_engine = kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); + + if (!aux_engine) + return NULL; + + dce110_aux_engine_construct(aux_engine, ctx, inst, SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, + &aux_engine_regs[inst], &aux_mask, &aux_shift, ctx->dc->caps.extended_aux_timeout_support); + + return &aux_engine->base; +} + +#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST(id) } + +static const struct dce_i2c_registers i2c_hw_regs[] = { + i2c_inst_regs(1), + i2c_inst_regs(2), + i2c_inst_regs(3), + i2c_inst_regs(4), + i2c_inst_regs(5) +}; + +static const struct dce_i2c_shift i2c_shifts = { + I2C_COMMON_MASK_SH_LIST_DCN2(__SHIFT) +}; + +static const struct dce_i2c_mask i2c_masks = { + I2C_COMMON_MASK_SH_LIST_DCN2(_MASK) +}; + +static struct dce_i2c_hw *dcn302_i2c_hw_create(struct dc_context *ctx, uint32_t inst) +{ + struct dce_i2c_hw *dce_i2c_hw = kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); + + if (!dce_i2c_hw) + return NULL; + + dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst, &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); + + return dce_i2c_hw; +} + +static const struct encoder_feature_support link_enc_feature = { + .max_hdmi_deep_color = COLOR_DEPTH_121212, + .max_hdmi_pixel_clock = 600000, + .hdmi_ycbcr420_supported = true, + .dp_ycbcr420_supported = true, + .fec_supported = true, + .flags.bits.IS_HBR2_CAPABLE = true, + .flags.bits.IS_HBR3_CAPABLE = true, + .flags.bits.IS_TPS3_CAPABLE = true, + .flags.bits.IS_TPS4_CAPABLE = true +}; + +#define link_regs(id, phyid)\ + [id] = {\ + LE_DCN3_REG_LIST(id), \ + UNIPHY_DCN2_REG_LIST(phyid), \ + DPCS_DCN2_REG_LIST(id), \ + SRI(DP_DPHY_INTERNAL_CTRL, DP, id) \ + } + +static const struct dcn10_link_enc_registers link_enc_regs[] = { + link_regs(0, A), + link_regs(1, B), + link_regs(2, C), + link_regs(3, D), + link_regs(4, E) +}; + +static const struct dcn10_link_enc_shift le_shift = { + LINK_ENCODER_MASK_SH_LIST_DCN30(__SHIFT), + DPCS_DCN2_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn10_link_enc_mask le_mask = { + LINK_ENCODER_MASK_SH_LIST_DCN30(_MASK), + DPCS_DCN2_MASK_SH_LIST(_MASK) +}; + +#define aux_regs(id)\ + [id] = { DCN2_AUX_REG_LIST(id) } + +static const struct dcn10_link_enc_aux_registers link_enc_aux_regs[] = { + aux_regs(0), + aux_regs(1), + aux_regs(2), + aux_regs(3), + aux_regs(4) +}; + +#define hpd_regs(id)\ + [id] = { HPD_REG_LIST(id) } + +static const struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[] = { + hpd_regs(0), + hpd_regs(1), + hpd_regs(2), + hpd_regs(3), + hpd_regs(4) +}; + +static struct link_encoder *dcn302_link_encoder_create( + struct dc_context *ctx, + const struct encoder_init_data *enc_init_data) +{ + struct dcn20_link_encoder *enc20 = kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); + + if (!enc20) + return NULL; + + dcn30_link_encoder_construct(enc20, enc_init_data, &link_enc_feature, + &link_enc_regs[enc_init_data->transmitter], &link_enc_aux_regs[enc_init_data->channel - 1], + &link_enc_hpd_regs[enc_init_data->hpd_source], &le_shift, &le_mask); + + return &enc20->enc10.base; +} + +static const struct dce_panel_cntl_registers panel_cntl_regs[] = { + { DCN_PANEL_CNTL_REG_LIST() } +}; + +static const struct dce_panel_cntl_shift panel_cntl_shift = { + DCE_PANEL_CNTL_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_panel_cntl_mask panel_cntl_mask = { + DCE_PANEL_CNTL_MASK_SH_LIST(_MASK) +}; + +static struct panel_cntl *dcn302_panel_cntl_create(const struct panel_cntl_init_data *init_data) +{ + struct dce_panel_cntl *panel_cntl = kzalloc(sizeof(struct dce_panel_cntl), GFP_KERNEL); + + if (!panel_cntl) + return NULL; + + dce_panel_cntl_construct(panel_cntl, init_data, &panel_cntl_regs[init_data->inst], + &panel_cntl_shift, &panel_cntl_mask); + + return &panel_cntl->base; +} + +static void read_dce_straps(struct dc_context *ctx, struct resource_straps *straps) +{ + generic_reg_get(ctx, mmDC_PINSTRAPS + BASE(mmDC_PINSTRAPS_BASE_IDX), + FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio); +} + +static const struct resource_create_funcs res_create_funcs = { + .read_dce_straps = read_dce_straps, + .create_audio = dcn302_create_audio, + .create_stream_encoder = dcn302_stream_encoder_create, + .create_hwseq = dcn302_hwseq_create, +}; + +static bool is_soc_bounding_box_valid(struct dc *dc) +{ + uint32_t hw_internal_rev = dc->ctx->asic_id.hw_internal_rev; + + if (ASICREV_IS_DIMGREY_CAVEFISH_P(hw_internal_rev)) + return true; + + return false; +} + +static bool init_soc_bounding_box(struct dc *dc, struct resource_pool *pool) +{ + struct _vcs_dpi_soc_bounding_box_st *loaded_bb = &dcn3_02_soc; + struct _vcs_dpi_ip_params_st *loaded_ip = &dcn3_02_ip; + + DC_LOGGER_INIT(dc->ctx->logger); + + if (!is_soc_bounding_box_valid(dc)) { + DC_LOG_ERROR("%s: not valid soc bounding box\n", __func__); + return false; + } + + loaded_ip->max_num_otg = pool->pipe_count; + loaded_ip->max_num_dpp = pool->pipe_count; + loaded_ip->clamp_min_dcfclk = dc->config.clamp_min_dcfclk; + DC_FP_START(); + dcn20_patch_bounding_box(dc, loaded_bb); + DC_FP_END(); + + if (dc->ctx->dc_bios->funcs->get_soc_bb_info) { + struct bp_soc_bb_info bb_info = { 0 }; + + if (dc->ctx->dc_bios->funcs->get_soc_bb_info( + dc->ctx->dc_bios, &bb_info) == BP_RESULT_OK) { + + DC_FP_START(); + dcn302_fpu_init_soc_bounding_box(bb_info); + DC_FP_END(); + } + } + + return true; +} + +static void dcn302_resource_destruct(struct resource_pool *pool) +{ + unsigned int i; + + for (i = 0; i < pool->stream_enc_count; i++) { + if (pool->stream_enc[i] != NULL) { + if (pool->stream_enc[i]->vpg != NULL) { + kfree(DCN30_VPG_FROM_VPG(pool->stream_enc[i]->vpg)); + pool->stream_enc[i]->vpg = NULL; + } + if (pool->stream_enc[i]->afmt != NULL) { + kfree(DCN30_AFMT_FROM_AFMT(pool->stream_enc[i]->afmt)); + pool->stream_enc[i]->afmt = NULL; + } + kfree(DCN10STRENC_FROM_STRENC(pool->stream_enc[i])); + pool->stream_enc[i] = NULL; + } + } + + for (i = 0; i < pool->res_cap->num_dsc; i++) { + if (pool->dscs[i] != NULL) + dcn20_dsc_destroy(&pool->dscs[i]); + } + + if (pool->mpc != NULL) { + kfree(TO_DCN20_MPC(pool->mpc)); + pool->mpc = NULL; + } + + if (pool->hubbub != NULL) { + kfree(pool->hubbub); + pool->hubbub = NULL; + } + + for (i = 0; i < pool->pipe_count; i++) { + if (pool->dpps[i] != NULL) { + kfree(TO_DCN20_DPP(pool->dpps[i])); + pool->dpps[i] = NULL; + } + + if (pool->hubps[i] != NULL) { + kfree(TO_DCN20_HUBP(pool->hubps[i])); + pool->hubps[i] = NULL; + } + + if (pool->irqs != NULL) + dal_irq_service_destroy(&pool->irqs); + } + + for (i = 0; i < pool->res_cap->num_ddc; i++) { + if (pool->engines[i] != NULL) + dce110_engine_destroy(&pool->engines[i]); + if (pool->hw_i2cs[i] != NULL) { + kfree(pool->hw_i2cs[i]); + pool->hw_i2cs[i] = NULL; + } + if (pool->sw_i2cs[i] != NULL) { + kfree(pool->sw_i2cs[i]); + pool->sw_i2cs[i] = NULL; + } + } + + for (i = 0; i < pool->res_cap->num_opp; i++) { + if (pool->opps[i] != NULL) + pool->opps[i]->funcs->opp_destroy(&pool->opps[i]); + } + + for (i = 0; i < pool->res_cap->num_timing_generator; i++) { + if (pool->timing_generators[i] != NULL) { + kfree(DCN10TG_FROM_TG(pool->timing_generators[i])); + pool->timing_generators[i] = NULL; + } + } + + for (i = 0; i < pool->res_cap->num_dwb; i++) { + if (pool->dwbc[i] != NULL) { + kfree(TO_DCN30_DWBC(pool->dwbc[i])); + pool->dwbc[i] = NULL; + } + if (pool->mcif_wb[i] != NULL) { + kfree(TO_DCN30_MMHUBBUB(pool->mcif_wb[i])); + pool->mcif_wb[i] = NULL; + } + } + + for (i = 0; i < pool->audio_count; i++) { + if (pool->audios[i]) + dce_aud_destroy(&pool->audios[i]); + } + + for (i = 0; i < pool->clk_src_count; i++) { + if (pool->clock_sources[i] != NULL) + dcn20_clock_source_destroy(&pool->clock_sources[i]); + } + + if (pool->dp_clock_source != NULL) + dcn20_clock_source_destroy(&pool->dp_clock_source); + + for (i = 0; i < pool->res_cap->num_mpc_3dlut; i++) { + if (pool->mpc_lut[i] != NULL) { + dc_3dlut_func_release(pool->mpc_lut[i]); + pool->mpc_lut[i] = NULL; + } + if (pool->mpc_shaper[i] != NULL) { + dc_transfer_func_release(pool->mpc_shaper[i]); + pool->mpc_shaper[i] = NULL; + } + } + + for (i = 0; i < pool->pipe_count; i++) { + if (pool->multiple_abms[i] != NULL) + dce_abm_destroy(&pool->multiple_abms[i]); + } + + if (pool->psr != NULL) + dmub_psr_destroy(&pool->psr); + + if (pool->dccg != NULL) + dcn_dccg_destroy(&pool->dccg); + + if (pool->oem_device != NULL) { + struct dc *dc = pool->oem_device->ctx->dc; + + dc->link_srv->destroy_ddc_service(&pool->oem_device); + } +} + +static void dcn302_destroy_resource_pool(struct resource_pool **pool) +{ + dcn302_resource_destruct(*pool); + kfree(*pool); + *pool = NULL; +} + +void dcn302_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) +{ + DC_FP_START(); + dcn302_fpu_update_bw_bounding_box(dc, bw_params); + DC_FP_END(); +} + +static void dcn302_get_panel_config_defaults(struct dc_panel_config *panel_config) +{ + *panel_config = panel_config_defaults; +} + +static struct resource_funcs dcn302_res_pool_funcs = { + .destroy = dcn302_destroy_resource_pool, + .link_enc_create = dcn302_link_encoder_create, + .panel_cntl_create = dcn302_panel_cntl_create, + .validate_bandwidth = dcn30_validate_bandwidth, + .calculate_wm_and_dlg = dcn30_calculate_wm_and_dlg, + .update_soc_for_wm_a = dcn30_update_soc_for_wm_a, + .populate_dml_pipes = dcn30_populate_dml_pipes_from_context, + .acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer, + .release_pipe = dcn20_release_pipe, + .add_stream_to_ctx = dcn30_add_stream_to_ctx, + .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource, + .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, + .populate_dml_writeback_from_context = dcn30_populate_dml_writeback_from_context, + .set_mcif_arb_params = dcn30_set_mcif_arb_params, + .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 = dcn302_update_bw_bounding_box, + .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, + .get_panel_config_defaults = dcn302_get_panel_config_defaults, +}; + +static struct dc_cap_funcs cap_funcs = { + .get_dcc_compression_cap = dcn20_get_dcc_compression_cap +}; + +static const struct bios_registers bios_regs = { + NBIO_SR(BIOS_SCRATCH_3), + NBIO_SR(BIOS_SCRATCH_6) +}; + +static const struct dccg_registers dccg_regs = { + DCCG_REG_LIST_DCN3_02() +}; + +static const struct dccg_shift dccg_shift = { + DCCG_MASK_SH_LIST_DCN3_02(__SHIFT) +}; + +static const struct dccg_mask dccg_mask = { + DCCG_MASK_SH_LIST_DCN3_02(_MASK) +}; + +#define abm_regs(id)\ + [id] = { ABM_DCN302_REG_LIST(id) } + +static const struct dce_abm_registers abm_regs[] = { + abm_regs(0), + abm_regs(1), + abm_regs(2), + abm_regs(3), + abm_regs(4) +}; + +static const struct dce_abm_shift abm_shift = { + ABM_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dce_abm_mask abm_mask = { + ABM_MASK_SH_LIST_DCN30(_MASK) +}; + +static bool dcn302_resource_construct( + uint8_t num_virtual_links, + struct dc *dc, + struct resource_pool *pool) +{ + 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; + + pool->res_cap = &res_cap_dcn302; + + pool->funcs = &dcn302_res_pool_funcs; + + /************************************************* + * Resource + asic cap harcoding * + *************************************************/ + pool->underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->pipe_count = pool->res_cap->num_timing_generator; + pool->mpcc_count = pool->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 = 5; /*1.4 w/a applied by derfault*/ + dc->caps.max_cursor_size = 256; + dc->caps.min_horizontal_blanking_period = 80; + dc->caps.dmdata_alloc_size = 2048; + dc->caps.mall_size_per_mem_channel = 4; + /* total size = mall per channel * num channels * 1024 * 1024 */ + dc->caps.mall_size_total = dc->caps.mall_size_per_mem_channel * dc->ctx->dc_bios->vram_info.num_chans * 1048576; + dc->caps.cursor_cache_size = dc->caps.max_cursor_size * dc->caps.max_cursor_size * 8; + dc->caps.max_slave_planes = 2; + dc->caps.max_slave_yuv_planes = 2; + dc->caps.max_slave_rgb_planes = 2; + dc->caps.post_blend_color_processing = true; + dc->caps.force_dp_tps4_for_cp2520 = true; + dc->caps.extended_aux_timeout_support = true; + dc->caps.dmcub_support = true; + dc->caps.max_v_total = (1 << 15) - 1; + + /* Color pipeline capabilities */ + dc->caps.color.dpp.dcn_arch = 1; + dc->caps.color.dpp.input_lut_shared = 0; + dc->caps.color.dpp.icsc = 1; + dc->caps.color.dpp.dgam_ram = 0; // must use gamma_corr + dc->caps.color.dpp.dgam_rom_caps.srgb = 1; + dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1; + dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 1; + dc->caps.color.dpp.dgam_rom_caps.pq = 1; + dc->caps.color.dpp.dgam_rom_caps.hlg = 1; + dc->caps.color.dpp.post_csc = 1; + dc->caps.color.dpp.gamma_corr = 1; + dc->caps.color.dpp.dgam_rom_for_yuv = 0; + + dc->caps.color.dpp.hw_3d_lut = 1; + dc->caps.color.dpp.ogam_ram = 1; + // no OGAM ROM on DCN3 + dc->caps.color.dpp.ogam_rom_caps.srgb = 0; + dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0; + dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0; + dc->caps.color.dpp.ogam_rom_caps.pq = 0; + dc->caps.color.dpp.ogam_rom_caps.hlg = 0; + dc->caps.color.dpp.ocsc = 0; + + dc->caps.color.mpc.gamut_remap = 1; + dc->caps.color.mpc.num_3dluts = pool->res_cap->num_mpc_3dlut; //3 + dc->caps.color.mpc.ogam_ram = 1; + dc->caps.color.mpc.ogam_rom_caps.srgb = 0; + dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0; + dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0; + dc->caps.color.mpc.ogam_rom_caps.pq = 0; + dc->caps.color.mpc.ogam_rom_caps.hlg = 0; + dc->caps.color.mpc.ocsc = 1; + + dc->caps.dp_hdmi21_pcon_support = true; + + /* read VBIOS LTTPR caps */ + if (ctx->dc_bios->funcs->get_lttpr_caps) { + enum bp_result bp_query_result; + uint8_t is_vbios_lttpr_enable = 0; + + bp_query_result = ctx->dc_bios->funcs->get_lttpr_caps(ctx->dc_bios, &is_vbios_lttpr_enable); + dc->caps.vbios_lttpr_enable = (bp_query_result == BP_RESULT_OK) && !!is_vbios_lttpr_enable; + } + + if (ctx->dc_bios->funcs->get_lttpr_interop) { + enum bp_result bp_query_result; + uint8_t is_vbios_interop_enabled = 0; + + bp_query_result = ctx->dc_bios->funcs->get_lttpr_interop(ctx->dc_bios, + &is_vbios_interop_enabled); + dc->caps.vbios_lttpr_aware = (bp_query_result == BP_RESULT_OK) && !!is_vbios_interop_enabled; + } + + if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) + dc->debug = debug_defaults_drv; + + // Init the vm_helper + if (dc->vm_helper) + vm_helper_init(dc->vm_helper, 16); + + /************************************************* + * Create resources * + *************************************************/ + + /* Clock Sources for Pixel Clock*/ + pool->clock_sources[DCN302_CLK_SRC_PLL0] = + dcn302_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL0, + &clk_src_regs[0], false); + pool->clock_sources[DCN302_CLK_SRC_PLL1] = + dcn302_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL1, + &clk_src_regs[1], false); + pool->clock_sources[DCN302_CLK_SRC_PLL2] = + dcn302_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL2, + &clk_src_regs[2], false); + pool->clock_sources[DCN302_CLK_SRC_PLL3] = + dcn302_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL3, + &clk_src_regs[3], false); + pool->clock_sources[DCN302_CLK_SRC_PLL4] = + dcn302_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL4, + &clk_src_regs[4], false); + + pool->clk_src_count = DCN302_CLK_SRC_TOTAL; + + /* todo: not reuse phy_pll registers */ + pool->dp_clock_source = + dcn302_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_ID_DP_DTO, + &clk_src_regs[0], true); + + for (i = 0; i < pool->clk_src_count; i++) { + if (pool->clock_sources[i] == NULL) { + dm_error("DC: failed to create clock sources!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + } + + /* DCCG */ + pool->dccg = dccg30_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask); + if (pool->dccg == NULL) { + dm_error("DC: failed to create dccg!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + /* PP Lib and SMU interfaces */ + init_soc_bounding_box(dc, pool); + + /* DML */ + dml_init_instance(&dc->dml, &dcn3_02_soc, &dcn3_02_ip, DML_PROJECT_DCN30); + + /* IRQ */ + init_data.ctx = dc->ctx; + pool->irqs = dal_irq_service_dcn302_create(&init_data); + if (!pool->irqs) + goto create_fail; + + /* HUBBUB */ + pool->hubbub = dcn302_hubbub_create(ctx); + if (pool->hubbub == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create hubbub!\n"); + goto create_fail; + } + + /* HUBPs, DPPs, OPPs and TGs */ + for (i = 0; i < pool->pipe_count; i++) { + pool->hubps[i] = dcn302_hubp_create(ctx, i); + if (pool->hubps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create hubps!\n"); + goto create_fail; + } + + pool->dpps[i] = dcn302_dpp_create(ctx, i); + if (pool->dpps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dpps!\n"); + goto create_fail; + } + } + + for (i = 0; i < pool->res_cap->num_opp; i++) { + pool->opps[i] = dcn302_opp_create(ctx, i); + if (pool->opps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create output pixel processor!\n"); + goto create_fail; + } + } + + for (i = 0; i < pool->res_cap->num_timing_generator; i++) { + pool->timing_generators[i] = dcn302_timing_generator_create(ctx, i); + if (pool->timing_generators[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create tg!\n"); + goto create_fail; + } + } + pool->timing_generator_count = i; + + /* PSR */ + pool->psr = dmub_psr_create(ctx); + if (pool->psr == NULL) { + dm_error("DC: failed to create psr!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + /* ABMs */ + for (i = 0; i < pool->res_cap->num_timing_generator; i++) { + pool->multiple_abms[i] = dmub_abm_create(ctx, &abm_regs[i], &abm_shift, &abm_mask); + if (pool->multiple_abms[i] == NULL) { + dm_error("DC: failed to create abm for pipe %d!\n", i); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + } + + /* MPC and DSC */ + pool->mpc = dcn302_mpc_create(ctx, pool->mpcc_count, pool->res_cap->num_mpc_3dlut); + if (pool->mpc == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create mpc!\n"); + goto create_fail; + } + + for (i = 0; i < pool->res_cap->num_dsc; i++) { + pool->dscs[i] = dcn302_dsc_create(ctx, i); + if (pool->dscs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create display stream compressor %d!\n", i); + goto create_fail; + } + } + + /* DWB and MMHUBBUB */ + if (!dcn302_dwbc_create(ctx, pool)) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dwbc!\n"); + goto create_fail; + } + + if (!dcn302_mmhubbub_create(ctx, pool)) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create mcif_wb!\n"); + goto create_fail; + } + + /* AUX and I2C */ + for (i = 0; i < pool->res_cap->num_ddc; i++) { + pool->engines[i] = dcn302_aux_engine_create(ctx, i); + if (pool->engines[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC:failed to create aux engine!!\n"); + goto create_fail; + } + pool->hw_i2cs[i] = dcn302_i2c_hw_create(ctx, i); + if (pool->hw_i2cs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC:failed to create hw i2c!!\n"); + goto create_fail; + } + pool->sw_i2cs[i] = NULL; + } + + /* Audio, Stream Encoders including HPO and virtual, MPC 3D LUTs */ + if (!resource_construct(num_virtual_links, dc, pool, + &res_create_funcs)) + goto create_fail; + + /* HW Sequencer and Plane caps */ + dcn302_hw_sequencer_construct(dc); + + dc->caps.max_planes = pool->pipe_count; + + for (i = 0; i < dc->caps.max_planes; ++i) + dc->caps.planes[i] = plane_cap; + + 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 = dc->link_srv->create_ddc_service(&ddc_init_data); + } else { + pool->oem_device = NULL; + } + + return true; + +create_fail: + + dcn302_resource_destruct(pool); + + return false; +} + +struct resource_pool *dcn302_create_resource_pool(const struct dc_init_data *init_data, struct dc *dc) +{ + struct resource_pool *pool = kzalloc(sizeof(struct resource_pool), GFP_KERNEL); + + if (!pool) + return NULL; + + if (dcn302_resource_construct(init_data->num_virtual_links, dc, pool)) + return pool; + + BREAK_TO_DEBUGGER(); + kfree(pool); + return NULL; +} diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.h new file mode 100644 index 00000000000000..9f24e73b92b314 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.h @@ -0,0 +1,38 @@ +/* + * Copyright 2020 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 _DCN302_RESOURCE_H_ +#define _DCN302_RESOURCE_H_ + +#include "core_types.h" + +extern struct _vcs_dpi_ip_params_st dcn3_02_ip; +extern struct _vcs_dpi_soc_bounding_box_st dcn3_02_soc; + +struct resource_pool *dcn302_create_resource_pool(const struct dc_init_data *init_data, struct dc *dc); + +void dcn302_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params); + +#endif /* _DCN302_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.c new file mode 100644 index 00000000000000..25cd6236b054ef --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.c @@ -0,0 +1,1448 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (C) 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 "dcn303/dcn303_init.h" +#include "dcn303_resource.h" +#include "dcn303/dcn303_dccg.h" +#include "irq/dcn303/irq_service_dcn303.h" + +#include "dcn30/dcn30_dio_link_encoder.h" +#include "dcn30/dcn30_dio_stream_encoder.h" +#include "dcn30/dcn30_dpp.h" +#include "dcn30/dcn30_dwb.h" +#include "dcn30/dcn30_hubbub.h" +#include "dcn30/dcn30_hubp.h" +#include "dcn30/dcn30_mmhubbub.h" +#include "dcn30/dcn30_mpc.h" +#include "dcn30/dcn30_opp.h" +#include "dcn30/dcn30_optc.h" +#include "dcn30/dcn30_resource.h" + +#include "dcn20/dcn20_dsc.h" +#include "dcn20/dcn20_resource.h" + +#include "dml/dcn30/dcn30_fpu.h" + +#include "dcn10/dcn10_resource.h" + +#include "link.h" + +#include "dce/dce_abm.h" +#include "dce/dce_audio.h" +#include "dce/dce_aux.h" +#include "dce/dce_clock_source.h" +#include "dce/dce_hwseq.h" +#include "dce/dce_i2c_hw.h" +#include "dce/dce_panel_cntl.h" +#include "dce/dmub_abm.h" +#include "dce/dmub_psr.h" +#include "clk_mgr.h" + +#include "hw_sequencer_private.h" +#include "reg_helper.h" +#include "resource.h" +#include "vm_helper.h" + +#include "sienna_cichlid_ip_offset.h" +#include "dcn/dcn_3_0_3_offset.h" +#include "dcn/dcn_3_0_3_sh_mask.h" +#include "dpcs/dpcs_3_0_3_offset.h" +#include "dpcs/dpcs_3_0_3_sh_mask.h" +#include "nbio/nbio_2_3_offset.h" + +#include "dml/dcn303/dcn303_fpu.h" + +#define DC_LOGGER \ + dc->ctx->logger +#define DC_LOGGER_INIT(logger) + + +static const struct dc_debug_options debug_defaults_drv = { + .disable_dmcu = true, + .force_abm_enable = false, + .timing_trace = false, + .clock_trace = true, + .disable_pplib_clock_request = true, + .pipe_split_policy = MPC_SPLIT_AVOID, + .force_single_disp_pipe_split = false, + .disable_dcc = DCC_ENABLE, + .vsr_support = true, + .performance_trace = false, + .max_downscale_src_width = 7680,/*upto 8K*/ + .disable_pplib_wm_range = false, + .scl_reset_length10 = true, + .sanity_checks = false, + .underflow_assert_delay_us = 0xFFFFFFFF, + .dwb_fi_phase = -1, // -1 = disable, + .dmub_command_table = true, + .exit_idle_opt_for_cursor_updates = true, + .disable_idle_power_optimizations = false, + .using_dml2 = false, +}; + +static const struct dc_panel_config panel_config_defaults = { + .psr = { + .disable_psr = false, + .disallow_psrsu = false, + .disallow_replay = false, + }, +}; + +enum dcn303_clk_src_array_id { + DCN303_CLK_SRC_PLL0, + DCN303_CLK_SRC_PLL1, + DCN303_CLK_SRC_TOTAL +}; + +static const struct resource_caps res_cap_dcn303 = { + .num_timing_generator = 2, + .num_opp = 2, + .num_video_plane = 2, + .num_audio = 2, + .num_stream_encoder = 2, + .num_dwb = 1, + .num_ddc = 2, + .num_vmid = 16, + .num_mpc_3dlut = 1, + .num_dsc = 2, +}; + +static const struct dc_plane_cap plane_cap = { + .type = DC_PLANE_TYPE_DCN_UNIVERSAL, + .per_pixel_alpha = true, + .pixel_format_support = { + .argb8888 = true, + .nv12 = true, + .fp16 = true, + .p010 = true, + .ayuv = false, + }, + .max_upscale_factor = { + .argb8888 = 16000, + .nv12 = 16000, + .fp16 = 16000 + }, + .max_downscale_factor = { + .argb8888 = 600, + .nv12 = 600, + .fp16 = 600 + }, + 16, + 16 +}; + +/* NBIO */ +#define NBIO_BASE_INNER(seg) \ + NBIO_BASE__INST0_SEG ## seg + +#define NBIO_BASE(seg) \ + NBIO_BASE_INNER(seg) + +#define NBIO_SR(reg_name)\ + .reg_name = NBIO_BASE(mm ## reg_name ## _BASE_IDX) + \ + mm ## reg_name + +/* DCN */ +#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg + +#define BASE(seg) BASE_INNER(seg) + +#define SR(reg_name)\ + .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + mm ## reg_name + +#define SF(reg_name, field_name, post_fix)\ + .field_name = reg_name ## __ ## field_name ## post_fix + +#define SRI(reg_name, block, id)\ + .reg_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + mm ## block ## id ## _ ## reg_name + +#define SRI2(reg_name, block, id)\ + .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + mm ## reg_name + +#define SRII(reg_name, block, id)\ + .reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define DCCG_SRII(reg_name, block, id)\ + .block ## _ ## reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +#define VUPDATE_SRII(reg_name, block, id)\ + .reg_name[id] = BASE(mm ## reg_name ## _ ## block ## id ## _BASE_IDX) + \ + mm ## reg_name ## _ ## block ## id + +#define SRII_DWB(reg_name, temp_name, block, id)\ + .reg_name[id] = BASE(mm ## block ## id ## _ ## temp_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## temp_name + +#define SF_DWB2(reg_name, block, id, field_name, post_fix) \ + .field_name = reg_name ## __ ## field_name ## post_fix + +#define SRII_MPC_RMU(reg_name, block, id)\ + .RMU##_##reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +static const struct dcn_hubbub_registers hubbub_reg = { + HUBBUB_REG_LIST_DCN30(0) +}; + +static const struct dcn_hubbub_shift hubbub_shift = { + HUBBUB_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn_hubbub_mask hubbub_mask = { + HUBBUB_MASK_SH_LIST_DCN30(_MASK) +}; + +#define vmid_regs(id)\ + [id] = { DCN20_VMID_REG_LIST(id) } + +static const struct dcn_vmid_registers vmid_regs[] = { + vmid_regs(0), + vmid_regs(1), + vmid_regs(2), + vmid_regs(3), + vmid_regs(4), + vmid_regs(5), + vmid_regs(6), + vmid_regs(7), + vmid_regs(8), + vmid_regs(9), + vmid_regs(10), + vmid_regs(11), + vmid_regs(12), + vmid_regs(13), + vmid_regs(14), + vmid_regs(15) +}; + +static const struct dcn20_vmid_shift vmid_shifts = { + DCN20_VMID_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn20_vmid_mask vmid_masks = { + DCN20_VMID_MASK_SH_LIST(_MASK) +}; + +static struct hubbub *dcn303_hubbub_create(struct dc_context *ctx) +{ + int i; + + struct dcn20_hubbub *hubbub3 = kzalloc(sizeof(struct dcn20_hubbub), GFP_KERNEL); + + if (!hubbub3) + return NULL; + + hubbub3_construct(hubbub3, ctx, &hubbub_reg, &hubbub_shift, &hubbub_mask); + + for (i = 0; i < res_cap_dcn303.num_vmid; i++) { + struct dcn20_vmid *vmid = &hubbub3->vmid[i]; + + vmid->ctx = ctx; + + vmid->regs = &vmid_regs[i]; + vmid->shifts = &vmid_shifts; + vmid->masks = &vmid_masks; + } + + return &hubbub3->base; +} + +#define vpg_regs(id)\ + [id] = { VPG_DCN3_REG_LIST(id) } + +static const struct dcn30_vpg_registers vpg_regs[] = { + vpg_regs(0), + vpg_regs(1), + vpg_regs(2) +}; + +static const struct dcn30_vpg_shift vpg_shift = { + DCN3_VPG_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn30_vpg_mask vpg_mask = { + DCN3_VPG_MASK_SH_LIST(_MASK) +}; + +static struct vpg *dcn303_vpg_create(struct dc_context *ctx, uint32_t inst) +{ + struct dcn30_vpg *vpg3 = kzalloc(sizeof(struct dcn30_vpg), GFP_KERNEL); + + if (!vpg3) + return NULL; + + vpg3_construct(vpg3, ctx, inst, &vpg_regs[inst], &vpg_shift, &vpg_mask); + + return &vpg3->base; +} + +#define afmt_regs(id)\ + [id] = { AFMT_DCN3_REG_LIST(id) } + +static const struct dcn30_afmt_registers afmt_regs[] = { + afmt_regs(0), + afmt_regs(1), + afmt_regs(2) +}; + +static const struct dcn30_afmt_shift afmt_shift = { + DCN3_AFMT_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn30_afmt_mask afmt_mask = { + DCN3_AFMT_MASK_SH_LIST(_MASK) +}; + +static struct afmt *dcn303_afmt_create(struct dc_context *ctx, uint32_t inst) +{ + struct dcn30_afmt *afmt3 = kzalloc(sizeof(struct dcn30_afmt), GFP_KERNEL); + + if (!afmt3) + return NULL; + + afmt3_construct(afmt3, ctx, inst, &afmt_regs[inst], &afmt_shift, &afmt_mask); + + return &afmt3->base; +} + +#define audio_regs(id)\ + [id] = { AUD_COMMON_REG_LIST(id) } + +static const struct dce_audio_registers audio_regs[] = { + audio_regs(0), + audio_regs(1), + audio_regs(2), + audio_regs(3), + audio_regs(4), + audio_regs(5), + audio_regs(6) +}; + +#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ + AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) + +static const struct dce_audio_shift audio_shift = { + DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_audio_mask audio_mask = { + DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) +}; + +static struct audio *dcn303_create_audio(struct dc_context *ctx, unsigned int inst) +{ + return dce_audio_create(ctx, inst, &audio_regs[inst], &audio_shift, &audio_mask); +} + +#define stream_enc_regs(id)\ + [id] = { SE_DCN3_REG_LIST(id) } + +static const struct dcn10_stream_enc_registers stream_enc_regs[] = { + stream_enc_regs(0), + stream_enc_regs(1) +}; + +static const struct dcn10_stream_encoder_shift se_shift = { + SE_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn10_stream_encoder_mask se_mask = { + SE_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +static struct stream_encoder *dcn303_stream_encoder_create(enum engine_id eng_id, struct dc_context *ctx) +{ + struct dcn10_stream_encoder *enc1; + struct vpg *vpg; + struct afmt *afmt; + int vpg_inst; + int afmt_inst; + + /* Mapping of VPG, AFMT, DME register blocks to DIO block instance */ + if (eng_id <= ENGINE_ID_DIGB) { + vpg_inst = eng_id; + afmt_inst = eng_id; + } else + return NULL; + + enc1 = kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL); + vpg = dcn303_vpg_create(ctx, vpg_inst); + afmt = dcn303_afmt_create(ctx, afmt_inst); + + if (!enc1 || !vpg || !afmt) { + kfree(enc1); + kfree(vpg); + kfree(afmt); + return NULL; + } + + dcn30_dio_stream_encoder_construct(enc1, ctx, ctx->dc_bios, eng_id, vpg, afmt, &stream_enc_regs[eng_id], + &se_shift, &se_mask); + + return &enc1->base; +} + +#define clk_src_regs(index, pllid)\ + [index] = { CS_COMMON_REG_LIST_DCN3_03(index, pllid) } + +static const struct dce110_clk_src_regs clk_src_regs[] = { + clk_src_regs(0, A), + clk_src_regs(1, B) +}; + +static const struct dce110_clk_src_shift cs_shift = { + CS_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) +}; + +static const struct dce110_clk_src_mask cs_mask = { + CS_COMMON_MASK_SH_LIST_DCN2_0(_MASK) +}; + +static struct clock_source *dcn303_clock_source_create(struct dc_context *ctx, struct dc_bios *bios, + enum clock_source_id id, const struct dce110_clk_src_regs *regs, bool dp_clk_src) +{ + struct dce110_clk_src *clk_src = kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); + + if (!clk_src) + return NULL; + + if (dcn3_clk_src_construct(clk_src, ctx, bios, id, regs, &cs_shift, &cs_mask)) { + clk_src->base.dp_clk_src = dp_clk_src; + return &clk_src->base; + } + + kfree(clk_src); + BREAK_TO_DEBUGGER(); + return NULL; +} + +static const struct dce_hwseq_registers hwseq_reg = { + HWSEQ_DCN303_REG_LIST() +}; + +static const struct dce_hwseq_shift hwseq_shift = { + HWSEQ_DCN303_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_hwseq_mask hwseq_mask = { + HWSEQ_DCN303_MASK_SH_LIST(_MASK) +}; + +static struct dce_hwseq *dcn303_hwseq_create(struct dc_context *ctx) +{ + struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); + + if (hws) { + hws->ctx = ctx; + hws->regs = &hwseq_reg; + hws->shifts = &hwseq_shift; + hws->masks = &hwseq_mask; + } + return hws; +} + +#define hubp_regs(id)\ + [id] = { HUBP_REG_LIST_DCN30(id) } + +static const struct dcn_hubp2_registers hubp_regs[] = { + hubp_regs(0), + hubp_regs(1) +}; + +static const struct dcn_hubp2_shift hubp_shift = { + HUBP_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn_hubp2_mask hubp_mask = { + HUBP_MASK_SH_LIST_DCN30(_MASK) +}; + +static struct hubp *dcn303_hubp_create(struct dc_context *ctx, uint32_t inst) +{ + struct dcn20_hubp *hubp2 = kzalloc(sizeof(struct dcn20_hubp), GFP_KERNEL); + + if (!hubp2) + return NULL; + + if (hubp3_construct(hubp2, ctx, inst, &hubp_regs[inst], &hubp_shift, &hubp_mask)) + return &hubp2->base; + + BREAK_TO_DEBUGGER(); + kfree(hubp2); + return NULL; +} + +#define dpp_regs(id)\ + [id] = { DPP_REG_LIST_DCN30(id) } + +static const struct dcn3_dpp_registers dpp_regs[] = { + dpp_regs(0), + dpp_regs(1) +}; + +static const struct dcn3_dpp_shift tf_shift = { + DPP_REG_LIST_SH_MASK_DCN30(__SHIFT) +}; + +static const struct dcn3_dpp_mask tf_mask = { + DPP_REG_LIST_SH_MASK_DCN30(_MASK) +}; + +static struct dpp *dcn303_dpp_create(struct dc_context *ctx, uint32_t inst) +{ + struct dcn3_dpp *dpp = kzalloc(sizeof(struct dcn3_dpp), GFP_KERNEL); + + if (!dpp) + return NULL; + + if (dpp3_construct(dpp, ctx, inst, &dpp_regs[inst], &tf_shift, &tf_mask)) + return &dpp->base; + + BREAK_TO_DEBUGGER(); + kfree(dpp); + return NULL; +} + +#define opp_regs(id)\ + [id] = { OPP_REG_LIST_DCN30(id) } + +static const struct dcn20_opp_registers opp_regs[] = { + opp_regs(0), + opp_regs(1) +}; + +static const struct dcn20_opp_shift opp_shift = { + OPP_MASK_SH_LIST_DCN20(__SHIFT) +}; + +static const struct dcn20_opp_mask opp_mask = { + OPP_MASK_SH_LIST_DCN20(_MASK) +}; + +static struct output_pixel_processor *dcn303_opp_create(struct dc_context *ctx, uint32_t inst) +{ + struct dcn20_opp *opp = kzalloc(sizeof(struct dcn20_opp), GFP_KERNEL); + + if (!opp) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dcn20_opp_construct(opp, ctx, inst, &opp_regs[inst], &opp_shift, &opp_mask); + return &opp->base; +} + +#define optc_regs(id)\ + [id] = { OPTC_COMMON_REG_LIST_DCN3_0(id) } + +static const struct dcn_optc_registers optc_regs[] = { + optc_regs(0), + optc_regs(1) +}; + +static const struct dcn_optc_shift optc_shift = { + OPTC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn_optc_mask optc_mask = { + OPTC_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +static struct timing_generator *dcn303_timing_generator_create(struct dc_context *ctx, uint32_t instance) +{ + struct optc *tgn10 = kzalloc(sizeof(struct optc), GFP_KERNEL); + + if (!tgn10) + return NULL; + + tgn10->base.inst = instance; + tgn10->base.ctx = ctx; + + tgn10->tg_regs = &optc_regs[instance]; + tgn10->tg_shift = &optc_shift; + tgn10->tg_mask = &optc_mask; + + dcn30_timing_generator_init(tgn10); + + return &tgn10->base; +} + +static const struct dcn30_mpc_registers mpc_regs = { + MPC_REG_LIST_DCN3_0(0), + MPC_REG_LIST_DCN3_0(1), + MPC_OUT_MUX_REG_LIST_DCN3_0(0), + MPC_OUT_MUX_REG_LIST_DCN3_0(1), + MPC_RMU_GLOBAL_REG_LIST_DCN3AG, + MPC_RMU_REG_LIST_DCN3AG(0), + MPC_DWB_MUX_REG_LIST_DCN3_0(0), +}; + +static const struct dcn30_mpc_shift mpc_shift = { + MPC_COMMON_MASK_SH_LIST_DCN303(__SHIFT) +}; + +static const struct dcn30_mpc_mask mpc_mask = { + MPC_COMMON_MASK_SH_LIST_DCN303(_MASK) +}; + +static struct mpc *dcn303_mpc_create(struct dc_context *ctx, int num_mpcc, int num_rmu) +{ + struct dcn30_mpc *mpc30 = kzalloc(sizeof(struct dcn30_mpc), GFP_KERNEL); + + if (!mpc30) + return NULL; + + dcn30_mpc_construct(mpc30, ctx, &mpc_regs, &mpc_shift, &mpc_mask, num_mpcc, num_rmu); + + return &mpc30->base; +} + +#define dsc_regsDCN20(id)\ +[id] = { DSC_REG_LIST_DCN20(id) } + +static const struct dcn20_dsc_registers dsc_regs[] = { + dsc_regsDCN20(0), + dsc_regsDCN20(1) +}; + +static const struct dcn20_dsc_shift dsc_shift = { + DSC_REG_LIST_SH_MASK_DCN20(__SHIFT) +}; + +static const struct dcn20_dsc_mask dsc_mask = { + DSC_REG_LIST_SH_MASK_DCN20(_MASK) +}; + +static struct display_stream_compressor *dcn303_dsc_create(struct dc_context *ctx, uint32_t inst) +{ + struct dcn20_dsc *dsc = kzalloc(sizeof(struct dcn20_dsc), GFP_KERNEL); + + if (!dsc) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dsc2_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask); + return &dsc->base; +} + +#define dwbc_regs_dcn3(id)\ +[id] = { DWBC_COMMON_REG_LIST_DCN30(id) } + +static const struct dcn30_dwbc_registers dwbc30_regs[] = { + dwbc_regs_dcn3(0) +}; + +static const struct dcn30_dwbc_shift dwbc30_shift = { + DWBC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn30_dwbc_mask dwbc30_mask = { + DWBC_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +static bool dcn303_dwbc_create(struct dc_context *ctx, struct resource_pool *pool) +{ + int i; + uint32_t pipe_count = pool->res_cap->num_dwb; + + for (i = 0; i < pipe_count; i++) { + struct dcn30_dwbc *dwbc30 = kzalloc(sizeof(struct dcn30_dwbc), GFP_KERNEL); + + if (!dwbc30) { + dm_error("DC: failed to create dwbc30!\n"); + return false; + } + + dcn30_dwbc_construct(dwbc30, ctx, &dwbc30_regs[i], &dwbc30_shift, &dwbc30_mask, i); + + pool->dwbc[i] = &dwbc30->base; + } + return true; +} + +#define mcif_wb_regs_dcn3(id)\ +[id] = { MCIF_WB_COMMON_REG_LIST_DCN30(id) } + +static const struct dcn30_mmhubbub_registers mcif_wb30_regs[] = { + mcif_wb_regs_dcn3(0) +}; + +static const struct dcn30_mmhubbub_shift mcif_wb30_shift = { + MCIF_WB_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn30_mmhubbub_mask mcif_wb30_mask = { + MCIF_WB_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +static bool dcn303_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool) +{ + int i; + uint32_t pipe_count = pool->res_cap->num_dwb; + + for (i = 0; i < pipe_count; i++) { + struct dcn30_mmhubbub *mcif_wb30 = kzalloc(sizeof(struct dcn30_mmhubbub), GFP_KERNEL); + + if (!mcif_wb30) { + dm_error("DC: failed to create mcif_wb30!\n"); + return false; + } + + dcn30_mmhubbub_construct(mcif_wb30, ctx, &mcif_wb30_regs[i], &mcif_wb30_shift, &mcif_wb30_mask, i); + + pool->mcif_wb[i] = &mcif_wb30->base; + } + return true; +} + +#define aux_engine_regs(id)\ +[id] = {\ + AUX_COMMON_REG_LIST0(id), \ + .AUXN_IMPCAL = 0, \ + .AUXP_IMPCAL = 0, \ + .AUX_RESET_MASK = DP_AUX0_AUX_CONTROL__AUX_RESET_MASK, \ +} + +static const struct dce110_aux_registers aux_engine_regs[] = { + aux_engine_regs(0), + aux_engine_regs(1) +}; + +static const struct dce110_aux_registers_shift aux_shift = { + DCN_AUX_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce110_aux_registers_mask aux_mask = { + DCN_AUX_MASK_SH_LIST(_MASK) +}; + +static struct dce_aux *dcn303_aux_engine_create(struct dc_context *ctx, uint32_t inst) +{ + struct aux_engine_dce110 *aux_engine = kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); + + if (!aux_engine) + return NULL; + + dce110_aux_engine_construct(aux_engine, ctx, inst, SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, + &aux_engine_regs[inst], &aux_mask, &aux_shift, ctx->dc->caps.extended_aux_timeout_support); + + return &aux_engine->base; +} + +#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST(id) } + +static const struct dce_i2c_registers i2c_hw_regs[] = { + i2c_inst_regs(1), + i2c_inst_regs(2) +}; + +static const struct dce_i2c_shift i2c_shifts = { + I2C_COMMON_MASK_SH_LIST_DCN2(__SHIFT) +}; + +static const struct dce_i2c_mask i2c_masks = { + I2C_COMMON_MASK_SH_LIST_DCN2(_MASK) +}; + +static struct dce_i2c_hw *dcn303_i2c_hw_create(struct dc_context *ctx, uint32_t inst) +{ + struct dce_i2c_hw *dce_i2c_hw = kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); + + if (!dce_i2c_hw) + return NULL; + + dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst, &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); + + return dce_i2c_hw; +} + +static const struct encoder_feature_support link_enc_feature = { + .max_hdmi_deep_color = COLOR_DEPTH_121212, + .max_hdmi_pixel_clock = 600000, + .hdmi_ycbcr420_supported = true, + .dp_ycbcr420_supported = true, + .fec_supported = true, + .flags.bits.IS_HBR2_CAPABLE = true, + .flags.bits.IS_HBR3_CAPABLE = true, + .flags.bits.IS_TPS3_CAPABLE = true, + .flags.bits.IS_TPS4_CAPABLE = true +}; + +#define link_regs(id, phyid)\ + [id] = {\ + LE_DCN3_REG_LIST(id), \ + UNIPHY_DCN2_REG_LIST(phyid), \ + SRI(DP_DPHY_INTERNAL_CTRL, DP, id) \ + } + +static const struct dcn10_link_enc_registers link_enc_regs[] = { + link_regs(0, A), + link_regs(1, B) +}; + +static const struct dcn10_link_enc_shift le_shift = { + LINK_ENCODER_MASK_SH_LIST_DCN30(__SHIFT), + DPCS_DCN2_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn10_link_enc_mask le_mask = { + LINK_ENCODER_MASK_SH_LIST_DCN30(_MASK), + DPCS_DCN2_MASK_SH_LIST(_MASK) +}; + +#define aux_regs(id)\ + [id] = { DCN2_AUX_REG_LIST(id) } + +static const struct dcn10_link_enc_aux_registers link_enc_aux_regs[] = { + aux_regs(0), + aux_regs(1) +}; + +#define hpd_regs(id)\ + [id] = { HPD_REG_LIST(id) } + +static const struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[] = { + hpd_regs(0), + hpd_regs(1) +}; + +static struct link_encoder *dcn303_link_encoder_create( + struct dc_context *ctx, + const struct encoder_init_data *enc_init_data) +{ + struct dcn20_link_encoder *enc20 = kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); + + if (!enc20) + return NULL; + + dcn30_link_encoder_construct(enc20, enc_init_data, &link_enc_feature, + &link_enc_regs[enc_init_data->transmitter], &link_enc_aux_regs[enc_init_data->channel - 1], + &link_enc_hpd_regs[enc_init_data->hpd_source], &le_shift, &le_mask); + + return &enc20->enc10.base; +} + +static const struct dce_panel_cntl_registers panel_cntl_regs[] = { + { DCN_PANEL_CNTL_REG_LIST() } +}; + +static const struct dce_panel_cntl_shift panel_cntl_shift = { + DCE_PANEL_CNTL_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_panel_cntl_mask panel_cntl_mask = { + DCE_PANEL_CNTL_MASK_SH_LIST(_MASK) +}; + +static struct panel_cntl *dcn303_panel_cntl_create(const struct panel_cntl_init_data *init_data) +{ + struct dce_panel_cntl *panel_cntl = kzalloc(sizeof(struct dce_panel_cntl), GFP_KERNEL); + + if (!panel_cntl) + return NULL; + + dce_panel_cntl_construct(panel_cntl, init_data, &panel_cntl_regs[init_data->inst], + &panel_cntl_shift, &panel_cntl_mask); + + return &panel_cntl->base; +} + +static void read_dce_straps(struct dc_context *ctx, struct resource_straps *straps) +{ + generic_reg_get(ctx, mmDC_PINSTRAPS + BASE(mmDC_PINSTRAPS_BASE_IDX), + FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio); +} + +static const struct resource_create_funcs res_create_funcs = { + .read_dce_straps = read_dce_straps, + .create_audio = dcn303_create_audio, + .create_stream_encoder = dcn303_stream_encoder_create, + .create_hwseq = dcn303_hwseq_create, +}; + +static bool is_soc_bounding_box_valid(struct dc *dc) +{ + uint32_t hw_internal_rev = dc->ctx->asic_id.hw_internal_rev; + + if (ASICREV_IS_BEIGE_GOBY_P(hw_internal_rev)) + return true; + + return false; +} + +static bool init_soc_bounding_box(struct dc *dc, struct resource_pool *pool) +{ + struct _vcs_dpi_soc_bounding_box_st *loaded_bb = &dcn3_03_soc; + struct _vcs_dpi_ip_params_st *loaded_ip = &dcn3_03_ip; + + DC_LOGGER_INIT(dc->ctx->logger); + + if (!is_soc_bounding_box_valid(dc)) { + DC_LOG_ERROR("%s: not valid soc bounding box/n", __func__); + return false; + } + + loaded_ip->max_num_otg = pool->pipe_count; + loaded_ip->max_num_dpp = pool->pipe_count; + loaded_ip->clamp_min_dcfclk = dc->config.clamp_min_dcfclk; + DC_FP_START(); + dcn20_patch_bounding_box(dc, loaded_bb); + DC_FP_END(); + + if (dc->ctx->dc_bios->funcs->get_soc_bb_info) { + struct bp_soc_bb_info bb_info = { 0 }; + + if (dc->ctx->dc_bios->funcs->get_soc_bb_info( + dc->ctx->dc_bios, &bb_info) == BP_RESULT_OK) { + DC_FP_START(); + dcn303_fpu_init_soc_bounding_box(bb_info); + DC_FP_END(); + } + } + + return true; +} + +static void dcn303_resource_destruct(struct resource_pool *pool) +{ + unsigned int i; + + for (i = 0; i < pool->stream_enc_count; i++) { + if (pool->stream_enc[i] != NULL) { + if (pool->stream_enc[i]->vpg != NULL) { + kfree(DCN30_VPG_FROM_VPG(pool->stream_enc[i]->vpg)); + pool->stream_enc[i]->vpg = NULL; + } + if (pool->stream_enc[i]->afmt != NULL) { + kfree(DCN30_AFMT_FROM_AFMT(pool->stream_enc[i]->afmt)); + pool->stream_enc[i]->afmt = NULL; + } + kfree(DCN10STRENC_FROM_STRENC(pool->stream_enc[i])); + pool->stream_enc[i] = NULL; + } + } + + for (i = 0; i < pool->res_cap->num_dsc; i++) { + if (pool->dscs[i] != NULL) + dcn20_dsc_destroy(&pool->dscs[i]); + } + + if (pool->mpc != NULL) { + kfree(TO_DCN20_MPC(pool->mpc)); + pool->mpc = NULL; + } + + if (pool->hubbub != NULL) { + kfree(pool->hubbub); + pool->hubbub = NULL; + } + + for (i = 0; i < pool->pipe_count; i++) { + if (pool->dpps[i] != NULL) { + kfree(TO_DCN20_DPP(pool->dpps[i])); + pool->dpps[i] = NULL; + } + + if (pool->hubps[i] != NULL) { + kfree(TO_DCN20_HUBP(pool->hubps[i])); + pool->hubps[i] = NULL; + } + + if (pool->irqs != NULL) + dal_irq_service_destroy(&pool->irqs); + } + + for (i = 0; i < pool->res_cap->num_ddc; i++) { + if (pool->engines[i] != NULL) + dce110_engine_destroy(&pool->engines[i]); + if (pool->hw_i2cs[i] != NULL) { + kfree(pool->hw_i2cs[i]); + pool->hw_i2cs[i] = NULL; + } + if (pool->sw_i2cs[i] != NULL) { + kfree(pool->sw_i2cs[i]); + pool->sw_i2cs[i] = NULL; + } + } + + for (i = 0; i < pool->res_cap->num_opp; i++) { + if (pool->opps[i] != NULL) + pool->opps[i]->funcs->opp_destroy(&pool->opps[i]); + } + + for (i = 0; i < pool->res_cap->num_timing_generator; i++) { + if (pool->timing_generators[i] != NULL) { + kfree(DCN10TG_FROM_TG(pool->timing_generators[i])); + pool->timing_generators[i] = NULL; + } + } + + for (i = 0; i < pool->res_cap->num_dwb; i++) { + if (pool->dwbc[i] != NULL) { + kfree(TO_DCN30_DWBC(pool->dwbc[i])); + pool->dwbc[i] = NULL; + } + if (pool->mcif_wb[i] != NULL) { + kfree(TO_DCN30_MMHUBBUB(pool->mcif_wb[i])); + pool->mcif_wb[i] = NULL; + } + } + + for (i = 0; i < pool->audio_count; i++) { + if (pool->audios[i]) + dce_aud_destroy(&pool->audios[i]); + } + + for (i = 0; i < pool->clk_src_count; i++) { + if (pool->clock_sources[i] != NULL) + dcn20_clock_source_destroy(&pool->clock_sources[i]); + } + + if (pool->dp_clock_source != NULL) + dcn20_clock_source_destroy(&pool->dp_clock_source); + + for (i = 0; i < pool->res_cap->num_mpc_3dlut; i++) { + if (pool->mpc_lut[i] != NULL) { + dc_3dlut_func_release(pool->mpc_lut[i]); + pool->mpc_lut[i] = NULL; + } + if (pool->mpc_shaper[i] != NULL) { + dc_transfer_func_release(pool->mpc_shaper[i]); + pool->mpc_shaper[i] = NULL; + } + } + + for (i = 0; i < pool->pipe_count; i++) { + if (pool->multiple_abms[i] != NULL) + dce_abm_destroy(&pool->multiple_abms[i]); + } + + if (pool->psr != NULL) + dmub_psr_destroy(&pool->psr); + + if (pool->dccg != NULL) + dcn_dccg_destroy(&pool->dccg); + + if (pool->oem_device != NULL) { + struct dc *dc = pool->oem_device->ctx->dc; + + dc->link_srv->destroy_ddc_service(&pool->oem_device); + } +} + +static void dcn303_destroy_resource_pool(struct resource_pool **pool) +{ + dcn303_resource_destruct(*pool); + kfree(*pool); + *pool = NULL; +} + +static void dcn303_get_panel_config_defaults(struct dc_panel_config *panel_config) +{ + *panel_config = panel_config_defaults; +} + +void dcn303_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) +{ + DC_FP_START(); + dcn303_fpu_update_bw_bounding_box(dc, bw_params); + DC_FP_END(); +} + +static struct resource_funcs dcn303_res_pool_funcs = { + .destroy = dcn303_destroy_resource_pool, + .link_enc_create = dcn303_link_encoder_create, + .panel_cntl_create = dcn303_panel_cntl_create, + .validate_bandwidth = dcn30_validate_bandwidth, + .calculate_wm_and_dlg = dcn30_calculate_wm_and_dlg, + .update_soc_for_wm_a = dcn30_update_soc_for_wm_a, + .populate_dml_pipes = dcn30_populate_dml_pipes_from_context, + .acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer, + .release_pipe = dcn20_release_pipe, + .add_stream_to_ctx = dcn30_add_stream_to_ctx, + .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource, + .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, + .populate_dml_writeback_from_context = dcn30_populate_dml_writeback_from_context, + .set_mcif_arb_params = dcn30_set_mcif_arb_params, + .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 = dcn303_update_bw_bounding_box, + .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, + .get_panel_config_defaults = dcn303_get_panel_config_defaults, +}; + +static struct dc_cap_funcs cap_funcs = { + .get_dcc_compression_cap = dcn20_get_dcc_compression_cap +}; + +static const struct bios_registers bios_regs = { + NBIO_SR(BIOS_SCRATCH_3), + NBIO_SR(BIOS_SCRATCH_6) +}; + +static const struct dccg_registers dccg_regs = { + DCCG_REG_LIST_DCN3_03() +}; + +static const struct dccg_shift dccg_shift = { + DCCG_MASK_SH_LIST_DCN3_03(__SHIFT) +}; + +static const struct dccg_mask dccg_mask = { + DCCG_MASK_SH_LIST_DCN3_03(_MASK) +}; + +#define abm_regs(id)\ + [id] = { ABM_DCN302_REG_LIST(id) } + +static const struct dce_abm_registers abm_regs[] = { + abm_regs(0), + abm_regs(1) +}; + +static const struct dce_abm_shift abm_shift = { + ABM_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dce_abm_mask abm_mask = { + ABM_MASK_SH_LIST_DCN30(_MASK) +}; + +static bool dcn303_resource_construct( + uint8_t num_virtual_links, + struct dc *dc, + struct resource_pool *pool) +{ + int i; + struct dc_context *ctx = dc->ctx; + struct irq_service_init_data init_data; + struct ddc_service_init_data ddc_init_data; + + ctx->dc_bios->regs = &bios_regs; + + pool->res_cap = &res_cap_dcn303; + + pool->funcs = &dcn303_res_pool_funcs; + + /************************************************* + * Resource + asic cap harcoding * + *************************************************/ + pool->underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->pipe_count = pool->res_cap->num_timing_generator; + pool->mpcc_count = pool->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 = 5; /*1.4 w/a applied by derfault*/ + dc->caps.max_cursor_size = 256; + dc->caps.min_horizontal_blanking_period = 80; + dc->caps.dmdata_alloc_size = 2048; + dc->caps.mall_size_per_mem_channel = 4; + /* total size = mall per channel * num channels * 1024 * 1024 */ + dc->caps.mall_size_total = dc->caps.mall_size_per_mem_channel * + dc->ctx->dc_bios->vram_info.num_chans * + 1024 * 1024; + dc->caps.cursor_cache_size = + dc->caps.max_cursor_size * dc->caps.max_cursor_size * 8; + dc->caps.max_slave_planes = 1; + dc->caps.post_blend_color_processing = true; + dc->caps.force_dp_tps4_for_cp2520 = true; + dc->caps.extended_aux_timeout_support = true; + dc->caps.dmcub_support = true; + dc->caps.max_v_total = (1 << 15) - 1; + + /* Color pipeline capabilities */ + dc->caps.color.dpp.dcn_arch = 1; + dc->caps.color.dpp.input_lut_shared = 0; + dc->caps.color.dpp.icsc = 1; + dc->caps.color.dpp.dgam_ram = 0; // must use gamma_corr + dc->caps.color.dpp.dgam_rom_caps.srgb = 1; + dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1; + dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 1; + dc->caps.color.dpp.dgam_rom_caps.pq = 1; + dc->caps.color.dpp.dgam_rom_caps.hlg = 1; + dc->caps.color.dpp.post_csc = 1; + dc->caps.color.dpp.gamma_corr = 1; + dc->caps.color.dpp.dgam_rom_for_yuv = 0; + + dc->caps.color.dpp.hw_3d_lut = 1; + dc->caps.color.dpp.ogam_ram = 1; + // no OGAM ROM on DCN3 + dc->caps.color.dpp.ogam_rom_caps.srgb = 0; + dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0; + dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0; + dc->caps.color.dpp.ogam_rom_caps.pq = 0; + dc->caps.color.dpp.ogam_rom_caps.hlg = 0; + dc->caps.color.dpp.ocsc = 0; + + dc->caps.color.mpc.gamut_remap = 1; + dc->caps.color.mpc.num_3dluts = pool->res_cap->num_mpc_3dlut; //3 + dc->caps.color.mpc.ogam_ram = 1; + dc->caps.color.mpc.ogam_rom_caps.srgb = 0; + dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0; + dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0; + dc->caps.color.mpc.ogam_rom_caps.pq = 0; + dc->caps.color.mpc.ogam_rom_caps.hlg = 0; + dc->caps.color.mpc.ocsc = 1; + + dc->caps.dp_hdmi21_pcon_support = true; + + dc->config.dc_mode_clk_limit_support = true; + /* read VBIOS LTTPR caps */ + if (ctx->dc_bios->funcs->get_lttpr_caps) { + enum bp_result bp_query_result; + uint8_t is_vbios_lttpr_enable = 0; + + bp_query_result = ctx->dc_bios->funcs->get_lttpr_caps(ctx->dc_bios, &is_vbios_lttpr_enable); + dc->caps.vbios_lttpr_enable = (bp_query_result == BP_RESULT_OK) && !!is_vbios_lttpr_enable; + } + + if (ctx->dc_bios->funcs->get_lttpr_interop) { + enum bp_result bp_query_result; + uint8_t is_vbios_interop_enabled = 0; + + bp_query_result = ctx->dc_bios->funcs->get_lttpr_interop(ctx->dc_bios, &is_vbios_interop_enabled); + dc->caps.vbios_lttpr_aware = (bp_query_result == BP_RESULT_OK) && !!is_vbios_interop_enabled; + } + + if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) + dc->debug = debug_defaults_drv; + + // Init the vm_helper + if (dc->vm_helper) + vm_helper_init(dc->vm_helper, 16); + + /************************************************* + * Create resources * + *************************************************/ + + /* Clock Sources for Pixel Clock*/ + pool->clock_sources[DCN303_CLK_SRC_PLL0] = + dcn303_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL0, + &clk_src_regs[0], false); + pool->clock_sources[DCN303_CLK_SRC_PLL1] = + dcn303_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL1, + &clk_src_regs[1], false); + + pool->clk_src_count = DCN303_CLK_SRC_TOTAL; + + /* todo: not reuse phy_pll registers */ + pool->dp_clock_source = + dcn303_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_ID_DP_DTO, + &clk_src_regs[0], true); + + for (i = 0; i < pool->clk_src_count; i++) { + if (pool->clock_sources[i] == NULL) { + dm_error("DC: failed to create clock sources!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + } + + /* DCCG */ + pool->dccg = dccg30_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask); + if (pool->dccg == NULL) { + dm_error("DC: failed to create dccg!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + /* PP Lib and SMU interfaces */ + init_soc_bounding_box(dc, pool); + + /* DML */ + dml_init_instance(&dc->dml, &dcn3_03_soc, &dcn3_03_ip, DML_PROJECT_DCN30); + + /* IRQ */ + init_data.ctx = dc->ctx; + pool->irqs = dal_irq_service_dcn303_create(&init_data); + if (!pool->irqs) + goto create_fail; + + /* HUBBUB */ + pool->hubbub = dcn303_hubbub_create(ctx); + if (pool->hubbub == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create hubbub!\n"); + goto create_fail; + } + + /* HUBPs, DPPs, OPPs and TGs */ + for (i = 0; i < pool->pipe_count; i++) { + pool->hubps[i] = dcn303_hubp_create(ctx, i); + if (pool->hubps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create hubps!\n"); + goto create_fail; + } + + pool->dpps[i] = dcn303_dpp_create(ctx, i); + if (pool->dpps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dpps!\n"); + goto create_fail; + } + } + + for (i = 0; i < pool->res_cap->num_opp; i++) { + pool->opps[i] = dcn303_opp_create(ctx, i); + if (pool->opps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create output pixel processor!\n"); + goto create_fail; + } + } + + for (i = 0; i < pool->res_cap->num_timing_generator; i++) { + pool->timing_generators[i] = dcn303_timing_generator_create(ctx, i); + if (pool->timing_generators[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create tg!\n"); + goto create_fail; + } + } + pool->timing_generator_count = i; + + /* PSR */ + pool->psr = dmub_psr_create(ctx); + if (pool->psr == NULL) { + dm_error("DC: failed to create psr!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + /* ABM */ + for (i = 0; i < pool->res_cap->num_timing_generator; i++) { + pool->multiple_abms[i] = dmub_abm_create(ctx, &abm_regs[i], &abm_shift, &abm_mask); + if (pool->multiple_abms[i] == NULL) { + dm_error("DC: failed to create abm for pipe %d!\n", i); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + } + + /* MPC and DSC */ + pool->mpc = dcn303_mpc_create(ctx, pool->mpcc_count, pool->res_cap->num_mpc_3dlut); + if (pool->mpc == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create mpc!\n"); + goto create_fail; + } + + for (i = 0; i < pool->res_cap->num_dsc; i++) { + pool->dscs[i] = dcn303_dsc_create(ctx, i); + if (pool->dscs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create display stream compressor %d!\n", i); + goto create_fail; + } + } + + /* DWB and MMHUBBUB */ + if (!dcn303_dwbc_create(ctx, pool)) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dwbc!\n"); + goto create_fail; + } + + if (!dcn303_mmhubbub_create(ctx, pool)) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create mcif_wb!\n"); + goto create_fail; + } + + /* AUX and I2C */ + for (i = 0; i < pool->res_cap->num_ddc; i++) { + pool->engines[i] = dcn303_aux_engine_create(ctx, i); + if (pool->engines[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC:failed to create aux engine!!\n"); + goto create_fail; + } + pool->hw_i2cs[i] = dcn303_i2c_hw_create(ctx, i); + if (pool->hw_i2cs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC:failed to create hw i2c!!\n"); + goto create_fail; + } + pool->sw_i2cs[i] = NULL; + } + + /* Audio, Stream Encoders including HPO and virtual, MPC 3D LUTs */ + if (!resource_construct(num_virtual_links, dc, pool, + &res_create_funcs)) + goto create_fail; + + /* HW Sequencer and Plane caps */ + dcn303_hw_sequencer_construct(dc); + + dc->caps.max_planes = pool->pipe_count; + + for (i = 0; i < dc->caps.max_planes; ++i) + dc->caps.planes[i] = plane_cap; + + 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 = dc->link_srv->create_ddc_service(&ddc_init_data); + } else { + pool->oem_device = NULL; + } + + return true; + +create_fail: + + dcn303_resource_destruct(pool); + + return false; +} + +struct resource_pool *dcn303_create_resource_pool(const struct dc_init_data *init_data, struct dc *dc) +{ + struct resource_pool *pool = kzalloc(sizeof(struct resource_pool), GFP_KERNEL); + + if (!pool) + return NULL; + + if (dcn303_resource_construct(init_data->num_virtual_links, dc, pool)) + return pool; + + BREAK_TO_DEBUGGER(); + kfree(pool); + return NULL; +} diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.h new file mode 100644 index 00000000000000..37cf1525820bbc --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.h @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright (C) 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 _DCN303_RESOURCE_H_ +#define _DCN303_RESOURCE_H_ + +#include "core_types.h" + +extern struct _vcs_dpi_ip_params_st dcn3_03_ip; +extern struct _vcs_dpi_soc_bounding_box_st dcn3_03_soc; + +struct resource_pool *dcn303_create_resource_pool(const struct dc_init_data *init_data, struct dc *dc); + +void dcn303_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params); + +#endif /* _DCN303_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c new file mode 100644 index 00000000000000..31035fc3d86863 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c @@ -0,0 +1,2218 @@ +/* + * Copyright 2019 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 "dcn31/dcn31_init.h" + +#include "resource.h" +#include "include/irq_service_interface.h" +#include "dcn31_resource.h" + +#include "dcn20/dcn20_resource.h" +#include "dcn30/dcn30_resource.h" + +#include "dml/dcn30/dcn30_fpu.h" + +#include "dcn10/dcn10_ipp.h" +#include "dcn30/dcn30_hubbub.h" +#include "dcn31/dcn31_hubbub.h" +#include "dcn30/dcn30_mpc.h" +#include "dcn31/dcn31_hubp.h" +#include "irq/dcn31/irq_service_dcn31.h" +#include "dcn30/dcn30_dpp.h" +#include "dcn31/dcn31_optc.h" +#include "dcn20/dcn20_hwseq.h" +#include "dcn30/dcn30_hwseq.h" +#include "dce110/dce110_hwseq.h" +#include "dcn30/dcn30_opp.h" +#include "dcn20/dcn20_dsc.h" +#include "dcn30/dcn30_vpg.h" +#include "dcn30/dcn30_afmt.h" +#include "dcn30/dcn30_dio_stream_encoder.h" +#include "dcn31/dcn31_hpo_dp_stream_encoder.h" +#include "dcn31/dcn31_hpo_dp_link_encoder.h" +#include "dcn31/dcn31_apg.h" +#include "dcn31/dcn31_dio_link_encoder.h" +#include "dcn31/dcn31_vpg.h" +#include "dcn31/dcn31_afmt.h" +#include "dce/dce_clock_source.h" +#include "dce/dce_audio.h" +#include "dce/dce_hwseq.h" +#include "clk_mgr.h" +#include "virtual/virtual_stream_encoder.h" +#include "dce110/dce110_resource.h" +#include "dml/display_mode_vba.h" +#include "dml/dcn31/dcn31_fpu.h" +#include "dcn31/dcn31_dccg.h" +#include "dcn10/dcn10_resource.h" +#include "dcn31/dcn31_panel_cntl.h" + +#include "dcn30/dcn30_dwb.h" +#include "dcn30/dcn30_mmhubbub.h" + +// TODO: change include headers /amd/include/asic_reg after upstream +#include "yellow_carp_offset.h" +#include "dcn/dcn_3_1_2_offset.h" +#include "dcn/dcn_3_1_2_sh_mask.h" +#include "nbio/nbio_7_2_0_offset.h" +#include "dpcs/dpcs_4_2_0_offset.h" +#include "dpcs/dpcs_4_2_0_sh_mask.h" +#include "mmhub/mmhub_2_3_0_offset.h" +#include "mmhub/mmhub_2_3_0_sh_mask.h" + + +#define regDCHUBBUB_DEBUG_CTRL_0 0x04d6 +#define regDCHUBBUB_DEBUG_CTRL_0_BASE_IDX 2 +#define DCHUBBUB_DEBUG_CTRL_0__DET_DEPTH__SHIFT 0x10 +#define DCHUBBUB_DEBUG_CTRL_0__DET_DEPTH_MASK 0x01FF0000L + +#include "reg_helper.h" +#include "dce/dmub_abm.h" +#include "dce/dmub_psr.h" +#include "dce/dce_aux.h" +#include "dce/dce_i2c.h" +#include "dce/dmub_replay.h" + +#include "dml/dcn30/display_mode_vba_30.h" +#include "vm_helper.h" +#include "dcn20/dcn20_vmid.h" + +#include "link_enc_cfg.h" + +#define DC_LOGGER \ + dc->ctx->logger +#define DC_LOGGER_INIT(logger) + +enum dcn31_clk_src_array_id { + DCN31_CLK_SRC_PLL0, + DCN31_CLK_SRC_PLL1, + DCN31_CLK_SRC_PLL2, + DCN31_CLK_SRC_PLL3, + DCN31_CLK_SRC_PLL4, + DCN30_CLK_SRC_TOTAL +}; + +/* begin ********************* + * macros to expend register list macro defined in HW object header file + */ + +/* DCN */ +#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg + +#define BASE(seg) BASE_INNER(seg) + +#define SR(reg_name)\ + .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ + reg ## reg_name + +#define SRI(reg_name, block, id)\ + .reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRI2(reg_name, block, id)\ + .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ + reg ## reg_name + +#define SRIR(var_name, reg_name, block, id)\ + .var_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRII(reg_name, block, id)\ + .reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRII_MPC_RMU(reg_name, block, id)\ + .RMU##_##reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRII_DWB(reg_name, temp_name, block, id)\ + .reg_name[id] = BASE(reg ## block ## id ## _ ## temp_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## temp_name + +#define SF_DWB2(reg_name, block, id, field_name, post_fix) \ + .field_name = reg_name ## __ ## field_name ## post_fix + +#define DCCG_SRII(reg_name, block, id)\ + .block ## _ ## reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define VUPDATE_SRII(reg_name, block, id)\ + .reg_name[id] = BASE(reg ## reg_name ## _ ## block ## id ## _BASE_IDX) + \ + reg ## reg_name ## _ ## block ## id + +/* NBIO */ +#define NBIO_BASE_INNER(seg) \ + NBIO_BASE__INST0_SEG ## seg + +#define NBIO_BASE(seg) \ + NBIO_BASE_INNER(seg) + +#define NBIO_SR(reg_name)\ + .reg_name = NBIO_BASE(regBIF_BX1_ ## reg_name ## _BASE_IDX) + \ + regBIF_BX1_ ## reg_name + +/* MMHUB */ +#define MMHUB_BASE_INNER(seg) \ + MMHUB_BASE__INST0_SEG ## seg + +#define MMHUB_BASE(seg) \ + MMHUB_BASE_INNER(seg) + +#define MMHUB_SR(reg_name)\ + .reg_name = MMHUB_BASE(mm ## reg_name ## _BASE_IDX) + \ + mm ## reg_name + +/* CLOCK */ +#define CLK_BASE_INNER(seg) \ + CLK_BASE__INST0_SEG ## seg + +#define CLK_BASE(seg) \ + CLK_BASE_INNER(seg) + +#define CLK_SRI(reg_name, block, inst)\ + .reg_name = CLK_BASE(reg ## block ## _ ## inst ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## _ ## inst ## _ ## reg_name + + +static const struct bios_registers bios_regs = { + NBIO_SR(BIOS_SCRATCH_3), + NBIO_SR(BIOS_SCRATCH_6) +}; + +#define clk_src_regs(index, pllid)\ +[index] = {\ + CS_COMMON_REG_LIST_DCN3_0(index, pllid),\ +} + +static const struct dce110_clk_src_regs clk_src_regs[] = { + clk_src_regs(0, A), + clk_src_regs(1, B), + clk_src_regs(2, C), + clk_src_regs(3, D), + clk_src_regs(4, E) +}; +/*pll_id being rempped in dmub, in driver it is logical instance*/ +static const struct dce110_clk_src_regs clk_src_regs_b0[] = { + clk_src_regs(0, A), + clk_src_regs(1, B), + clk_src_regs(2, F), + clk_src_regs(3, G), + clk_src_regs(4, E) +}; + +static const struct dce110_clk_src_shift cs_shift = { + CS_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) +}; + +static const struct dce110_clk_src_mask cs_mask = { + CS_COMMON_MASK_SH_LIST_DCN2_0(_MASK) +}; + +#define abm_regs(id)\ +[id] = {\ + ABM_DCN302_REG_LIST(id)\ +} + +static const struct dce_abm_registers abm_regs[] = { + abm_regs(0), + abm_regs(1), + abm_regs(2), + abm_regs(3), +}; + +static const struct dce_abm_shift abm_shift = { + ABM_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dce_abm_mask abm_mask = { + ABM_MASK_SH_LIST_DCN30(_MASK) +}; + +#define audio_regs(id)\ +[id] = {\ + AUD_COMMON_REG_LIST(id)\ +} + +static const struct dce_audio_registers audio_regs[] = { + audio_regs(0), + audio_regs(1), + audio_regs(2), + audio_regs(3), + audio_regs(4), + audio_regs(5), + audio_regs(6) +}; + +#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ + AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) + +static const struct dce_audio_shift audio_shift = { + DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_audio_mask audio_mask = { + DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) +}; + +#define vpg_regs(id)\ +[id] = {\ + VPG_DCN31_REG_LIST(id)\ +} + +static const struct dcn31_vpg_registers vpg_regs[] = { + vpg_regs(0), + vpg_regs(1), + vpg_regs(2), + vpg_regs(3), + vpg_regs(4), + vpg_regs(5), + vpg_regs(6), + vpg_regs(7), + vpg_regs(8), + vpg_regs(9), +}; + +static const struct dcn31_vpg_shift vpg_shift = { + DCN31_VPG_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn31_vpg_mask vpg_mask = { + DCN31_VPG_MASK_SH_LIST(_MASK) +}; + +#define afmt_regs(id)\ +[id] = {\ + AFMT_DCN31_REG_LIST(id)\ +} + +static const struct dcn31_afmt_registers afmt_regs[] = { + afmt_regs(0), + afmt_regs(1), + afmt_regs(2), + afmt_regs(3), + afmt_regs(4), + afmt_regs(5) +}; + +static const struct dcn31_afmt_shift afmt_shift = { + DCN31_AFMT_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn31_afmt_mask afmt_mask = { + DCN31_AFMT_MASK_SH_LIST(_MASK) +}; + +#define apg_regs(id)\ +[id] = {\ + APG_DCN31_REG_LIST(id)\ +} + +static const struct dcn31_apg_registers apg_regs[] = { + apg_regs(0), + apg_regs(1), + apg_regs(2), + apg_regs(3) +}; + +static const struct dcn31_apg_shift apg_shift = { + DCN31_APG_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn31_apg_mask apg_mask = { + DCN31_APG_MASK_SH_LIST(_MASK) +}; + +#define stream_enc_regs(id)\ +[id] = {\ + SE_DCN3_REG_LIST(id)\ +} + +/* Some encoders won't be initialized here - but they're logical, not physical. */ +static const struct dcn10_stream_enc_registers stream_enc_regs[ENGINE_ID_COUNT] = { + stream_enc_regs(0), + stream_enc_regs(1), + stream_enc_regs(2), + stream_enc_regs(3), + stream_enc_regs(4) +}; + +static const struct dcn10_stream_encoder_shift se_shift = { + SE_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn10_stream_encoder_mask se_mask = { + SE_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + + +#define aux_regs(id)\ +[id] = {\ + DCN2_AUX_REG_LIST(id)\ +} + +static const struct dcn10_link_enc_aux_registers link_enc_aux_regs[] = { + aux_regs(0), + aux_regs(1), + aux_regs(2), + aux_regs(3), + aux_regs(4) +}; + +#define hpd_regs(id)\ +[id] = {\ + HPD_REG_LIST(id)\ +} + +static const struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[] = { + hpd_regs(0), + hpd_regs(1), + hpd_regs(2), + hpd_regs(3), + hpd_regs(4) +}; + +#define link_regs(id, phyid)\ +[id] = {\ + LE_DCN31_REG_LIST(id), \ + UNIPHY_DCN2_REG_LIST(phyid), \ + DPCS_DCN31_REG_LIST(id), \ +} + +static const struct dce110_aux_registers_shift aux_shift = { + DCN_AUX_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce110_aux_registers_mask aux_mask = { + DCN_AUX_MASK_SH_LIST(_MASK) +}; + +static const struct dcn10_link_enc_registers link_enc_regs[] = { + link_regs(0, A), + link_regs(1, B), + link_regs(2, C), + link_regs(3, D), + link_regs(4, E) +}; + +static const struct dcn10_link_enc_shift le_shift = { + LINK_ENCODER_MASK_SH_LIST_DCN31(__SHIFT), \ + DPCS_DCN31_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn10_link_enc_mask le_mask = { + LINK_ENCODER_MASK_SH_LIST_DCN31(_MASK), \ + DPCS_DCN31_MASK_SH_LIST(_MASK) +}; + +#define hpo_dp_stream_encoder_reg_list(id)\ +[id] = {\ + DCN3_1_HPO_DP_STREAM_ENC_REG_LIST(id)\ +} + +static const struct dcn31_hpo_dp_stream_encoder_registers hpo_dp_stream_enc_regs[] = { + hpo_dp_stream_encoder_reg_list(0), + hpo_dp_stream_encoder_reg_list(1), + hpo_dp_stream_encoder_reg_list(2), + hpo_dp_stream_encoder_reg_list(3), +}; + +static const struct dcn31_hpo_dp_stream_encoder_shift hpo_dp_se_shift = { + DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn31_hpo_dp_stream_encoder_mask hpo_dp_se_mask = { + DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(_MASK) +}; + +#define hpo_dp_link_encoder_reg_list(id)\ +[id] = {\ + DCN3_1_HPO_DP_LINK_ENC_REG_LIST(id),\ + DCN3_1_RDPCSTX_REG_LIST(0),\ + DCN3_1_RDPCSTX_REG_LIST(1),\ + DCN3_1_RDPCSTX_REG_LIST(2),\ + DCN3_1_RDPCSTX_REG_LIST(3),\ + DCN3_1_RDPCSTX_REG_LIST(4)\ +} + +static const struct dcn31_hpo_dp_link_encoder_registers hpo_dp_link_enc_regs[] = { + hpo_dp_link_encoder_reg_list(0), + hpo_dp_link_encoder_reg_list(1), +}; + +static const struct dcn31_hpo_dp_link_encoder_shift hpo_dp_le_shift = { + DCN3_1_HPO_DP_LINK_ENC_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn31_hpo_dp_link_encoder_mask hpo_dp_le_mask = { + DCN3_1_HPO_DP_LINK_ENC_MASK_SH_LIST(_MASK) +}; + +#define dpp_regs(id)\ +[id] = {\ + DPP_REG_LIST_DCN30(id),\ +} + +static const struct dcn3_dpp_registers dpp_regs[] = { + dpp_regs(0), + dpp_regs(1), + dpp_regs(2), + dpp_regs(3) +}; + +static const struct dcn3_dpp_shift tf_shift = { + DPP_REG_LIST_SH_MASK_DCN30(__SHIFT) +}; + +static const struct dcn3_dpp_mask tf_mask = { + DPP_REG_LIST_SH_MASK_DCN30(_MASK) +}; + +#define opp_regs(id)\ +[id] = {\ + OPP_REG_LIST_DCN30(id),\ +} + +static const struct dcn20_opp_registers opp_regs[] = { + opp_regs(0), + opp_regs(1), + opp_regs(2), + opp_regs(3) +}; + +static const struct dcn20_opp_shift opp_shift = { + OPP_MASK_SH_LIST_DCN20(__SHIFT) +}; + +static const struct dcn20_opp_mask opp_mask = { + OPP_MASK_SH_LIST_DCN20(_MASK) +}; + +#define aux_engine_regs(id)\ +[id] = {\ + AUX_COMMON_REG_LIST0(id), \ + .AUXN_IMPCAL = 0, \ + .AUXP_IMPCAL = 0, \ + .AUX_RESET_MASK = DP_AUX0_AUX_CONTROL__AUX_RESET_MASK, \ +} + +static const struct dce110_aux_registers aux_engine_regs[] = { + aux_engine_regs(0), + aux_engine_regs(1), + aux_engine_regs(2), + aux_engine_regs(3), + aux_engine_regs(4) +}; + +#define dwbc_regs_dcn3(id)\ +[id] = {\ + DWBC_COMMON_REG_LIST_DCN30(id),\ +} + +static const struct dcn30_dwbc_registers dwbc30_regs[] = { + dwbc_regs_dcn3(0), +}; + +static const struct dcn30_dwbc_shift dwbc30_shift = { + DWBC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn30_dwbc_mask dwbc30_mask = { + DWBC_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +#define mcif_wb_regs_dcn3(id)\ +[id] = {\ + MCIF_WB_COMMON_REG_LIST_DCN30(id),\ +} + +static const struct dcn30_mmhubbub_registers mcif_wb30_regs[] = { + mcif_wb_regs_dcn3(0) +}; + +static const struct dcn30_mmhubbub_shift mcif_wb30_shift = { + MCIF_WB_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn30_mmhubbub_mask mcif_wb30_mask = { + MCIF_WB_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +#define dsc_regsDCN20(id)\ +[id] = {\ + DSC_REG_LIST_DCN20(id)\ +} + +static const struct dcn20_dsc_registers dsc_regs[] = { + dsc_regsDCN20(0), + dsc_regsDCN20(1), + dsc_regsDCN20(2) +}; + +static const struct dcn20_dsc_shift dsc_shift = { + DSC_REG_LIST_SH_MASK_DCN20(__SHIFT) +}; + +static const struct dcn20_dsc_mask dsc_mask = { + DSC_REG_LIST_SH_MASK_DCN20(_MASK) +}; + +static const struct dcn30_mpc_registers mpc_regs = { + MPC_REG_LIST_DCN3_0(0), + MPC_REG_LIST_DCN3_0(1), + MPC_REG_LIST_DCN3_0(2), + MPC_REG_LIST_DCN3_0(3), + MPC_OUT_MUX_REG_LIST_DCN3_0(0), + MPC_OUT_MUX_REG_LIST_DCN3_0(1), + MPC_OUT_MUX_REG_LIST_DCN3_0(2), + MPC_OUT_MUX_REG_LIST_DCN3_0(3), + MPC_RMU_GLOBAL_REG_LIST_DCN3AG, + MPC_RMU_REG_LIST_DCN3AG(0), + MPC_RMU_REG_LIST_DCN3AG(1), + //MPC_RMU_REG_LIST_DCN3AG(2), + MPC_DWB_MUX_REG_LIST_DCN3_0(0), +}; + +static const struct dcn30_mpc_shift mpc_shift = { + MPC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn30_mpc_mask mpc_mask = { + MPC_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +#define optc_regs(id)\ +[id] = {OPTC_COMMON_REG_LIST_DCN3_1(id)} + +static const struct dcn_optc_registers optc_regs[] = { + optc_regs(0), + optc_regs(1), + optc_regs(2), + optc_regs(3) +}; + +static const struct dcn_optc_shift optc_shift = { + OPTC_COMMON_MASK_SH_LIST_DCN3_1(__SHIFT) +}; + +static const struct dcn_optc_mask optc_mask = { + OPTC_COMMON_MASK_SH_LIST_DCN3_1(_MASK) +}; + +#define hubp_regs(id)\ +[id] = {\ + HUBP_REG_LIST_DCN30(id)\ +} + +static const struct dcn_hubp2_registers hubp_regs[] = { + hubp_regs(0), + hubp_regs(1), + hubp_regs(2), + hubp_regs(3) +}; + + +static const struct dcn_hubp2_shift hubp_shift = { + HUBP_MASK_SH_LIST_DCN31(__SHIFT) +}; + +static const struct dcn_hubp2_mask hubp_mask = { + HUBP_MASK_SH_LIST_DCN31(_MASK) +}; +static const struct dcn_hubbub_registers hubbub_reg = { + HUBBUB_REG_LIST_DCN31(0) +}; + +static const struct dcn_hubbub_shift hubbub_shift = { + HUBBUB_MASK_SH_LIST_DCN31(__SHIFT) +}; + +static const struct dcn_hubbub_mask hubbub_mask = { + HUBBUB_MASK_SH_LIST_DCN31(_MASK) +}; + +static const struct dccg_registers dccg_regs = { + DCCG_REG_LIST_DCN31() +}; + +static const struct dccg_shift dccg_shift = { + DCCG_MASK_SH_LIST_DCN31(__SHIFT) +}; + +static const struct dccg_mask dccg_mask = { + DCCG_MASK_SH_LIST_DCN31(_MASK) +}; + + +#define SRII2(reg_name_pre, reg_name_post, id)\ + .reg_name_pre ## _ ## reg_name_post[id] = BASE(reg ## reg_name_pre \ + ## id ## _ ## reg_name_post ## _BASE_IDX) + \ + reg ## reg_name_pre ## id ## _ ## reg_name_post + + +#define HWSEQ_DCN31_REG_LIST()\ + SR(DCHUBBUB_GLOBAL_TIMER_CNTL), \ + SR(DCHUBBUB_ARB_HOSTVM_CNTL), \ + SR(DIO_MEM_PWR_CTRL), \ + SR(ODM_MEM_PWR_CTRL3), \ + SR(DMU_MEM_PWR_CNTL), \ + SR(MMHUBBUB_MEM_PWR_CNTL), \ + SR(DCCG_GATE_DISABLE_CNTL), \ + SR(DCCG_GATE_DISABLE_CNTL2), \ + SR(DCFCLK_CNTL),\ + SR(DC_MEM_GLOBAL_PWR_REQ_CNTL), \ + SRII(PIXEL_RATE_CNTL, OTG, 0), \ + SRII(PIXEL_RATE_CNTL, OTG, 1),\ + SRII(PIXEL_RATE_CNTL, OTG, 2),\ + SRII(PIXEL_RATE_CNTL, OTG, 3),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 0),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 1),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 2),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 3),\ + SR(MICROSECOND_TIME_BASE_DIV), \ + SR(MILLISECOND_TIME_BASE_DIV), \ + SR(DISPCLK_FREQ_CHANGE_CNTL), \ + SR(RBBMIF_TIMEOUT_DIS), \ + SR(RBBMIF_TIMEOUT_DIS_2), \ + SR(DCHUBBUB_CRC_CTRL), \ + SR(DPP_TOP0_DPP_CRC_CTRL), \ + SR(DPP_TOP0_DPP_CRC_VAL_B_A), \ + SR(DPP_TOP0_DPP_CRC_VAL_R_G), \ + SR(MPC_CRC_CTRL), \ + SR(MPC_CRC_RESULT_GB), \ + SR(MPC_CRC_RESULT_C), \ + SR(MPC_CRC_RESULT_AR), \ + SR(DOMAIN0_PG_CONFIG), \ + SR(DOMAIN1_PG_CONFIG), \ + SR(DOMAIN2_PG_CONFIG), \ + SR(DOMAIN3_PG_CONFIG), \ + SR(DOMAIN16_PG_CONFIG), \ + SR(DOMAIN17_PG_CONFIG), \ + SR(DOMAIN18_PG_CONFIG), \ + SR(DOMAIN0_PG_STATUS), \ + SR(DOMAIN1_PG_STATUS), \ + SR(DOMAIN2_PG_STATUS), \ + SR(DOMAIN3_PG_STATUS), \ + SR(DOMAIN16_PG_STATUS), \ + SR(DOMAIN17_PG_STATUS), \ + SR(DOMAIN18_PG_STATUS), \ + SR(D1VGA_CONTROL), \ + SR(D2VGA_CONTROL), \ + SR(D3VGA_CONTROL), \ + SR(D4VGA_CONTROL), \ + SR(D5VGA_CONTROL), \ + SR(D6VGA_CONTROL), \ + SR(DC_IP_REQUEST_CNTL), \ + SR(AZALIA_AUDIO_DTO), \ + SR(AZALIA_CONTROLLER_CLOCK_GATING), \ + SR(HPO_TOP_HW_CONTROL) + +static const struct dce_hwseq_registers hwseq_reg = { + HWSEQ_DCN31_REG_LIST() +}; + +#define HWSEQ_DCN31_MASK_SH_LIST(mask_sh)\ + HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ + HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \ + HWS_SF(, DCHUBBUB_ARB_HOSTVM_CNTL, DISABLE_HOSTVM_FORCE_ALLOW_PSTATE, mask_sh), \ + HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN16_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN17_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN18_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \ + HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh), \ + HWS_SF(, HPO_TOP_CLOCK_CONTROL, HPO_HDMISTREAMCLK_G_GATE_DIS, mask_sh), \ + HWS_SF(, DMU_MEM_PWR_CNTL, DMCU_ERAM_MEM_PWR_FORCE, mask_sh), \ + HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_UNASSIGNED_PWR_MODE, mask_sh), \ + HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_VBLANK_PWR_MODE, mask_sh), \ + HWS_SF(, MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, mask_sh), \ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh), \ + HWS_SF(, HPO_TOP_HW_CONTROL, HPO_IO_EN, mask_sh) + +static const struct dce_hwseq_shift hwseq_shift = { + HWSEQ_DCN31_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_hwseq_mask hwseq_mask = { + HWSEQ_DCN31_MASK_SH_LIST(_MASK) +}; +#define vmid_regs(id)\ +[id] = {\ + DCN20_VMID_REG_LIST(id)\ +} + +static const struct dcn_vmid_registers vmid_regs[] = { + vmid_regs(0), + vmid_regs(1), + vmid_regs(2), + vmid_regs(3), + vmid_regs(4), + vmid_regs(5), + vmid_regs(6), + vmid_regs(7), + vmid_regs(8), + vmid_regs(9), + vmid_regs(10), + vmid_regs(11), + vmid_regs(12), + vmid_regs(13), + vmid_regs(14), + vmid_regs(15) +}; + +static const struct dcn20_vmid_shift vmid_shifts = { + DCN20_VMID_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn20_vmid_mask vmid_masks = { + DCN20_VMID_MASK_SH_LIST(_MASK) +}; + +static const struct resource_caps res_cap_dcn31 = { + .num_timing_generator = 4, + .num_opp = 4, + .num_video_plane = 4, + .num_audio = 5, + .num_stream_encoder = 5, + .num_dig_link_enc = 5, + .num_hpo_dp_stream_encoder = 4, + .num_hpo_dp_link_encoder = 2, + .num_pll = 5, + .num_dwb = 1, + .num_ddc = 5, + .num_vmid = 16, + .num_mpc_3dlut = 2, + .num_dsc = 3, +}; + +static const struct dc_plane_cap plane_cap = { + .type = DC_PLANE_TYPE_DCN_UNIVERSAL, + .per_pixel_alpha = true, + + .pixel_format_support = { + .argb8888 = true, + .nv12 = true, + .fp16 = true, + .p010 = true, + .ayuv = false, + }, + + .max_upscale_factor = { + .argb8888 = 16000, + .nv12 = 16000, + .fp16 = 16000 + }, + + // 6:1 downscaling ratio: 1000/6 = 166.666 + .max_downscale_factor = { + .argb8888 = 167, + .nv12 = 167, + .fp16 = 167 + }, + 64, + 64 +}; + +static const struct dc_debug_options debug_defaults_drv = { + .disable_dmcu = true, + .force_abm_enable = false, + .timing_trace = false, + .clock_trace = true, + .disable_pplib_clock_request = false, + .pipe_split_policy = MPC_SPLIT_DYNAMIC, + .force_single_disp_pipe_split = false, + .disable_dcc = DCC_ENABLE, + .vsr_support = true, + .performance_trace = false, + .max_downscale_src_width = 4096,/*upto true 4K*/ + .disable_pplib_wm_range = false, + .scl_reset_length10 = true, + .sanity_checks = true, + .underflow_assert_delay_us = 0xFFFFFFFF, + .dwb_fi_phase = -1, // -1 = disable, + .dmub_command_table = true, + .pstate_enabled = true, + .use_max_lb = true, + .enable_mem_low_power = { + .bits = { + .vga = true, + .i2c = true, + .dmcu = false, // This is previously known to cause hang on S3 cycles if enabled + .dscl = true, + .cm = true, + .mpc = true, + .optc = true, + .vpg = true, + .afmt = true, + } + }, + .disable_z10 = true, + .enable_legacy_fast_update = true, + .enable_z9_disable_interface = true, /* Allow support for the PMFW interface for disable Z9*/ + .dml_hostvm_override = DML_HOSTVM_OVERRIDE_FALSE, + .using_dml2 = false, +}; + +static const struct dc_panel_config panel_config_defaults = { + .psr = { + .disable_psr = false, + .disallow_psrsu = false, + .disallow_replay = false, + }, + .ilr = { + .optimize_edp_link_rate = true, + }, +}; + +static void dcn31_dpp_destroy(struct dpp **dpp) +{ + kfree(TO_DCN20_DPP(*dpp)); + *dpp = NULL; +} + +static struct dpp *dcn31_dpp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn3_dpp *dpp = + kzalloc(sizeof(struct dcn3_dpp), GFP_KERNEL); + + if (!dpp) + return NULL; + + if (dpp3_construct(dpp, ctx, inst, + &dpp_regs[inst], &tf_shift, &tf_mask)) + return &dpp->base; + + BREAK_TO_DEBUGGER(); + kfree(dpp); + return NULL; +} + +static struct output_pixel_processor *dcn31_opp_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dcn20_opp *opp = + kzalloc(sizeof(struct dcn20_opp), GFP_KERNEL); + + if (!opp) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dcn20_opp_construct(opp, ctx, inst, + &opp_regs[inst], &opp_shift, &opp_mask); + return &opp->base; +} + +static struct dce_aux *dcn31_aux_engine_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct aux_engine_dce110 *aux_engine = + kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); + + if (!aux_engine) + return NULL; + + dce110_aux_engine_construct(aux_engine, ctx, inst, + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, + &aux_engine_regs[inst], + &aux_mask, + &aux_shift, + ctx->dc->caps.extended_aux_timeout_support); + + return &aux_engine->base; +} +#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST_DCN30(id) } + +static const struct dce_i2c_registers i2c_hw_regs[] = { + i2c_inst_regs(1), + i2c_inst_regs(2), + i2c_inst_regs(3), + i2c_inst_regs(4), + i2c_inst_regs(5), +}; + +static const struct dce_i2c_shift i2c_shifts = { + I2C_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dce_i2c_mask i2c_masks = { + I2C_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +static struct dce_i2c_hw *dcn31_i2c_hw_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce_i2c_hw *dce_i2c_hw = + kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); + + if (!dce_i2c_hw) + return NULL; + + dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst, + &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); + + return dce_i2c_hw; +} +static struct mpc *dcn31_mpc_create( + struct dc_context *ctx, + int num_mpcc, + int num_rmu) +{ + struct dcn30_mpc *mpc30 = kzalloc(sizeof(struct dcn30_mpc), + GFP_KERNEL); + + if (!mpc30) + return NULL; + + dcn30_mpc_construct(mpc30, ctx, + &mpc_regs, + &mpc_shift, + &mpc_mask, + num_mpcc, + num_rmu); + + return &mpc30->base; +} + +static struct hubbub *dcn31_hubbub_create(struct dc_context *ctx) +{ + int i; + + struct dcn20_hubbub *hubbub3 = kzalloc(sizeof(struct dcn20_hubbub), + GFP_KERNEL); + + if (!hubbub3) + return NULL; + + hubbub31_construct(hubbub3, ctx, + &hubbub_reg, + &hubbub_shift, + &hubbub_mask, + dcn3_1_ip.det_buffer_size_kbytes, + dcn3_1_ip.pixel_chunk_size_kbytes, + dcn3_1_ip.config_return_buffer_size_in_kbytes); + + + for (i = 0; i < res_cap_dcn31.num_vmid; i++) { + struct dcn20_vmid *vmid = &hubbub3->vmid[i]; + + vmid->ctx = ctx; + + vmid->regs = &vmid_regs[i]; + vmid->shifts = &vmid_shifts; + vmid->masks = &vmid_masks; + } + + return &hubbub3->base; +} + +static struct timing_generator *dcn31_timing_generator_create( + struct dc_context *ctx, + uint32_t instance) +{ + struct optc *tgn10 = + kzalloc(sizeof(struct optc), GFP_KERNEL); + + if (!tgn10) + return NULL; + + tgn10->base.inst = instance; + tgn10->base.ctx = ctx; + + tgn10->tg_regs = &optc_regs[instance]; + tgn10->tg_shift = &optc_shift; + tgn10->tg_mask = &optc_mask; + + dcn31_timing_generator_init(tgn10); + + return &tgn10->base; +} + +static const struct encoder_feature_support link_enc_feature = { + .max_hdmi_deep_color = COLOR_DEPTH_121212, + .max_hdmi_pixel_clock = 600000, + .hdmi_ycbcr420_supported = true, + .dp_ycbcr420_supported = true, + .fec_supported = true, + .flags.bits.IS_HBR2_CAPABLE = true, + .flags.bits.IS_HBR3_CAPABLE = true, + .flags.bits.IS_TPS3_CAPABLE = true, + .flags.bits.IS_TPS4_CAPABLE = true +}; + +static struct link_encoder *dcn31_link_encoder_create( + struct dc_context *ctx, + const struct encoder_init_data *enc_init_data) +{ + struct dcn20_link_encoder *enc20 = + kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); + + if (!enc20) + return NULL; + + dcn31_link_encoder_construct(enc20, + enc_init_data, + &link_enc_feature, + &link_enc_regs[enc_init_data->transmitter], + &link_enc_aux_regs[enc_init_data->channel - 1], + &link_enc_hpd_regs[enc_init_data->hpd_source], + &le_shift, + &le_mask); + + return &enc20->enc10.base; +} + +/* Create a minimal link encoder object not associated with a particular + * physical connector. + * resource_funcs.link_enc_create_minimal + */ +static struct link_encoder *dcn31_link_enc_create_minimal( + struct dc_context *ctx, enum engine_id eng_id) +{ + struct dcn20_link_encoder *enc20; + + if ((eng_id - ENGINE_ID_DIGA) > ctx->dc->res_pool->res_cap->num_dig_link_enc) + return NULL; + + enc20 = kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); + if (!enc20) + return NULL; + + dcn31_link_encoder_construct_minimal( + enc20, + ctx, + &link_enc_feature, + &link_enc_regs[eng_id - ENGINE_ID_DIGA], + eng_id); + + return &enc20->enc10.base; +} + +static struct panel_cntl *dcn31_panel_cntl_create(const struct panel_cntl_init_data *init_data) +{ + struct dcn31_panel_cntl *panel_cntl = + kzalloc(sizeof(struct dcn31_panel_cntl), GFP_KERNEL); + + if (!panel_cntl) + return NULL; + + dcn31_panel_cntl_construct(panel_cntl, init_data); + + return &panel_cntl->base; +} + +static void read_dce_straps( + struct dc_context *ctx, + struct resource_straps *straps) +{ + generic_reg_get(ctx, regDC_PINSTRAPS + BASE(regDC_PINSTRAPS_BASE_IDX), + FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio); + +} + +static struct audio *dcn31_create_audio( + struct dc_context *ctx, unsigned int inst) +{ + return dce_audio_create(ctx, inst, + &audio_regs[inst], &audio_shift, &audio_mask); +} + +static struct vpg *dcn31_vpg_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn31_vpg *vpg31 = kzalloc(sizeof(struct dcn31_vpg), GFP_KERNEL); + + if (!vpg31) + return NULL; + + vpg31_construct(vpg31, ctx, inst, + &vpg_regs[inst], + &vpg_shift, + &vpg_mask); + + return &vpg31->base; +} + +static struct afmt *dcn31_afmt_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn31_afmt *afmt31 = kzalloc(sizeof(struct dcn31_afmt), GFP_KERNEL); + + if (!afmt31) + return NULL; + + afmt31_construct(afmt31, ctx, inst, + &afmt_regs[inst], + &afmt_shift, + &afmt_mask); + + // Light sleep by default, no need to power down here + + return &afmt31->base; +} + +static struct apg *dcn31_apg_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn31_apg *apg31 = kzalloc(sizeof(struct dcn31_apg), GFP_KERNEL); + + if (!apg31) + return NULL; + + apg31_construct(apg31, ctx, inst, + &apg_regs[inst], + &apg_shift, + &apg_mask); + + return &apg31->base; +} + +static struct stream_encoder *dcn31_stream_encoder_create( + enum engine_id eng_id, + struct dc_context *ctx) +{ + struct dcn10_stream_encoder *enc1; + struct vpg *vpg; + struct afmt *afmt; + int vpg_inst; + int afmt_inst; + + /* Mapping of VPG, AFMT, DME register blocks to DIO block instance */ + if (eng_id <= ENGINE_ID_DIGF) { + vpg_inst = eng_id; + afmt_inst = eng_id; + } else + return NULL; + + enc1 = kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL); + vpg = dcn31_vpg_create(ctx, vpg_inst); + afmt = dcn31_afmt_create(ctx, afmt_inst); + + if (!enc1 || !vpg || !afmt) { + kfree(enc1); + kfree(vpg); + kfree(afmt); + return NULL; + } + + dcn30_dio_stream_encoder_construct(enc1, ctx, ctx->dc_bios, + eng_id, vpg, afmt, + &stream_enc_regs[eng_id], + &se_shift, &se_mask); + + return &enc1->base; +} + +static struct hpo_dp_stream_encoder *dcn31_hpo_dp_stream_encoder_create( + enum engine_id eng_id, + struct dc_context *ctx) +{ + struct dcn31_hpo_dp_stream_encoder *hpo_dp_enc31; + struct vpg *vpg; + struct apg *apg; + uint32_t hpo_dp_inst; + uint32_t vpg_inst; + uint32_t apg_inst; + + ASSERT((eng_id >= ENGINE_ID_HPO_DP_0) && (eng_id <= ENGINE_ID_HPO_DP_3)); + hpo_dp_inst = eng_id - ENGINE_ID_HPO_DP_0; + + /* Mapping of VPG register blocks to HPO DP block instance: + * VPG[6] -> HPO_DP[0] + * VPG[7] -> HPO_DP[1] + * VPG[8] -> HPO_DP[2] + * VPG[9] -> HPO_DP[3] + */ + vpg_inst = hpo_dp_inst + 6; + + /* Mapping of APG register blocks to HPO DP block instance: + * APG[0] -> HPO_DP[0] + * APG[1] -> HPO_DP[1] + * APG[2] -> HPO_DP[2] + * APG[3] -> HPO_DP[3] + */ + apg_inst = hpo_dp_inst; + + /* allocate HPO stream encoder and create VPG sub-block */ + hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_stream_encoder), GFP_KERNEL); + vpg = dcn31_vpg_create(ctx, vpg_inst); + apg = dcn31_apg_create(ctx, apg_inst); + + if (!hpo_dp_enc31 || !vpg || !apg) { + kfree(hpo_dp_enc31); + kfree(vpg); + kfree(apg); + return NULL; + } + + dcn31_hpo_dp_stream_encoder_construct(hpo_dp_enc31, ctx, ctx->dc_bios, + hpo_dp_inst, eng_id, vpg, apg, + &hpo_dp_stream_enc_regs[hpo_dp_inst], + &hpo_dp_se_shift, &hpo_dp_se_mask); + + return &hpo_dp_enc31->base; +} + +static struct hpo_dp_link_encoder *dcn31_hpo_dp_link_encoder_create( + uint8_t inst, + struct dc_context *ctx) +{ + struct dcn31_hpo_dp_link_encoder *hpo_dp_enc31; + + /* allocate HPO link encoder */ + hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_link_encoder), GFP_KERNEL); + + hpo_dp_link_encoder31_construct(hpo_dp_enc31, ctx, inst, + &hpo_dp_link_enc_regs[inst], + &hpo_dp_le_shift, &hpo_dp_le_mask); + + return &hpo_dp_enc31->base; +} + +static struct dce_hwseq *dcn31_hwseq_create( + struct dc_context *ctx) +{ + struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); + + if (hws) { + hws->ctx = ctx; + hws->regs = &hwseq_reg; + hws->shifts = &hwseq_shift; + hws->masks = &hwseq_mask; + } + return hws; +} +static const struct resource_create_funcs res_create_funcs = { + .read_dce_straps = read_dce_straps, + .create_audio = dcn31_create_audio, + .create_stream_encoder = dcn31_stream_encoder_create, + .create_hpo_dp_stream_encoder = dcn31_hpo_dp_stream_encoder_create, + .create_hpo_dp_link_encoder = dcn31_hpo_dp_link_encoder_create, + .create_hwseq = dcn31_hwseq_create, +}; + +static void dcn31_resource_destruct(struct dcn31_resource_pool *pool) +{ + unsigned int i; + + for (i = 0; i < pool->base.stream_enc_count; i++) { + if (pool->base.stream_enc[i] != NULL) { + if (pool->base.stream_enc[i]->vpg != NULL) { + kfree(DCN30_VPG_FROM_VPG(pool->base.stream_enc[i]->vpg)); + pool->base.stream_enc[i]->vpg = NULL; + } + if (pool->base.stream_enc[i]->afmt != NULL) { + kfree(DCN30_AFMT_FROM_AFMT(pool->base.stream_enc[i]->afmt)); + pool->base.stream_enc[i]->afmt = NULL; + } + kfree(DCN10STRENC_FROM_STRENC(pool->base.stream_enc[i])); + pool->base.stream_enc[i] = NULL; + } + } + + for (i = 0; i < pool->base.hpo_dp_stream_enc_count; i++) { + if (pool->base.hpo_dp_stream_enc[i] != NULL) { + if (pool->base.hpo_dp_stream_enc[i]->vpg != NULL) { + kfree(DCN30_VPG_FROM_VPG(pool->base.hpo_dp_stream_enc[i]->vpg)); + pool->base.hpo_dp_stream_enc[i]->vpg = NULL; + } + if (pool->base.hpo_dp_stream_enc[i]->apg != NULL) { + kfree(DCN31_APG_FROM_APG(pool->base.hpo_dp_stream_enc[i]->apg)); + pool->base.hpo_dp_stream_enc[i]->apg = NULL; + } + kfree(DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(pool->base.hpo_dp_stream_enc[i])); + pool->base.hpo_dp_stream_enc[i] = NULL; + } + } + + for (i = 0; i < pool->base.hpo_dp_link_enc_count; i++) { + if (pool->base.hpo_dp_link_enc[i] != NULL) { + kfree(DCN3_1_HPO_DP_LINK_ENC_FROM_HPO_LINK_ENC(pool->base.hpo_dp_link_enc[i])); + pool->base.hpo_dp_link_enc[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_dsc; i++) { + if (pool->base.dscs[i] != NULL) + dcn20_dsc_destroy(&pool->base.dscs[i]); + } + + if (pool->base.mpc != NULL) { + kfree(TO_DCN20_MPC(pool->base.mpc)); + pool->base.mpc = NULL; + } + if (pool->base.hubbub != NULL) { + kfree(pool->base.hubbub); + pool->base.hubbub = NULL; + } + for (i = 0; i < pool->base.pipe_count; i++) { + if (pool->base.dpps[i] != NULL) + dcn31_dpp_destroy(&pool->base.dpps[i]); + + if (pool->base.ipps[i] != NULL) + pool->base.ipps[i]->funcs->ipp_destroy(&pool->base.ipps[i]); + + if (pool->base.hubps[i] != NULL) { + kfree(TO_DCN20_HUBP(pool->base.hubps[i])); + pool->base.hubps[i] = NULL; + } + + if (pool->base.irqs != NULL) { + dal_irq_service_destroy(&pool->base.irqs); + } + } + + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + if (pool->base.engines[i] != NULL) + dce110_engine_destroy(&pool->base.engines[i]); + if (pool->base.hw_i2cs[i] != NULL) { + kfree(pool->base.hw_i2cs[i]); + pool->base.hw_i2cs[i] = NULL; + } + if (pool->base.sw_i2cs[i] != NULL) { + kfree(pool->base.sw_i2cs[i]); + pool->base.sw_i2cs[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_opp; i++) { + if (pool->base.opps[i] != NULL) + pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]); + } + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + if (pool->base.timing_generators[i] != NULL) { + kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i])); + pool->base.timing_generators[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_dwb; i++) { + if (pool->base.dwbc[i] != NULL) { + kfree(TO_DCN30_DWBC(pool->base.dwbc[i])); + pool->base.dwbc[i] = NULL; + } + if (pool->base.mcif_wb[i] != NULL) { + kfree(TO_DCN30_MMHUBBUB(pool->base.mcif_wb[i])); + pool->base.mcif_wb[i] = NULL; + } + } + + for (i = 0; i < pool->base.audio_count; i++) { + if (pool->base.audios[i]) + dce_aud_destroy(&pool->base.audios[i]); + } + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] != NULL) { + dcn20_clock_source_destroy(&pool->base.clock_sources[i]); + pool->base.clock_sources[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_mpc_3dlut; i++) { + if (pool->base.mpc_lut[i] != NULL) { + dc_3dlut_func_release(pool->base.mpc_lut[i]); + pool->base.mpc_lut[i] = NULL; + } + if (pool->base.mpc_shaper[i] != NULL) { + dc_transfer_func_release(pool->base.mpc_shaper[i]); + pool->base.mpc_shaper[i] = NULL; + } + } + + if (pool->base.dp_clock_source != NULL) { + dcn20_clock_source_destroy(&pool->base.dp_clock_source); + pool->base.dp_clock_source = NULL; + } + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + if (pool->base.multiple_abms[i] != NULL) + dce_abm_destroy(&pool->base.multiple_abms[i]); + } + + if (pool->base.psr != NULL) + dmub_psr_destroy(&pool->base.psr); + + if (pool->base.replay != NULL) + dmub_replay_destroy(&pool->base.replay); + + if (pool->base.dccg != NULL) + dcn_dccg_destroy(&pool->base.dccg); +} + +static struct hubp *dcn31_hubp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn20_hubp *hubp2 = + kzalloc(sizeof(struct dcn20_hubp), GFP_KERNEL); + + if (!hubp2) + return NULL; + + if (hubp31_construct(hubp2, ctx, inst, + &hubp_regs[inst], &hubp_shift, &hubp_mask)) + return &hubp2->base; + + BREAK_TO_DEBUGGER(); + kfree(hubp2); + return NULL; +} + +static bool dcn31_dwbc_create(struct dc_context *ctx, struct resource_pool *pool) +{ + int i; + uint32_t pipe_count = pool->res_cap->num_dwb; + + for (i = 0; i < pipe_count; i++) { + struct dcn30_dwbc *dwbc30 = kzalloc(sizeof(struct dcn30_dwbc), + GFP_KERNEL); + + if (!dwbc30) { + dm_error("DC: failed to create dwbc30!\n"); + return false; + } + + dcn30_dwbc_construct(dwbc30, ctx, + &dwbc30_regs[i], + &dwbc30_shift, + &dwbc30_mask, + i); + + pool->dwbc[i] = &dwbc30->base; + } + return true; +} + +static bool dcn31_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool) +{ + int i; + uint32_t pipe_count = pool->res_cap->num_dwb; + + for (i = 0; i < pipe_count; i++) { + struct dcn30_mmhubbub *mcif_wb30 = kzalloc(sizeof(struct dcn30_mmhubbub), + GFP_KERNEL); + + if (!mcif_wb30) { + dm_error("DC: failed to create mcif_wb30!\n"); + return false; + } + + dcn30_mmhubbub_construct(mcif_wb30, ctx, + &mcif_wb30_regs[i], + &mcif_wb30_shift, + &mcif_wb30_mask, + i); + + pool->mcif_wb[i] = &mcif_wb30->base; + } + return true; +} + +static struct display_stream_compressor *dcn31_dsc_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dcn20_dsc *dsc = + kzalloc(sizeof(struct dcn20_dsc), GFP_KERNEL); + + if (!dsc) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dsc2_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask); + return &dsc->base; +} + +static void dcn31_destroy_resource_pool(struct resource_pool **pool) +{ + struct dcn31_resource_pool *dcn31_pool = TO_DCN31_RES_POOL(*pool); + + dcn31_resource_destruct(dcn31_pool); + kfree(dcn31_pool); + *pool = NULL; +} + +static struct clock_source *dcn31_clock_source_create( + struct dc_context *ctx, + struct dc_bios *bios, + enum clock_source_id id, + const struct dce110_clk_src_regs *regs, + bool dp_clk_src) +{ + struct dce110_clk_src *clk_src = + kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); + + if (!clk_src) + return NULL; + + if (dcn3_clk_src_construct(clk_src, ctx, bios, id, + regs, &cs_shift, &cs_mask)) { + clk_src->base.dp_clk_src = dp_clk_src; + return &clk_src->base; + } + + kfree(clk_src); + BREAK_TO_DEBUGGER(); + return NULL; +} + +static bool is_dual_plane(enum surface_pixel_format format) +{ + return format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN || format == SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA; +} + +int dcn31x_populate_dml_pipes_from_context(struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + bool fast_validate) +{ + uint32_t pipe_cnt; + int i; + + dc_assert_fp_enabled(); + + pipe_cnt = dcn20_populate_dml_pipes_from_context(dc, context, pipes, fast_validate); + + for (i = 0; i < pipe_cnt; i++) { + pipes[i].pipe.src.gpuvm = 1; + if (dc->debug.dml_hostvm_override == DML_HOSTVM_NO_OVERRIDE) { + //pipes[pipe_cnt].pipe.src.hostvm = dc->res_pool->hubbub->riommu_active; + pipes[i].pipe.src.hostvm = dc->vm_pa_config.is_hvm_enabled; + } else if (dc->debug.dml_hostvm_override == DML_HOSTVM_OVERRIDE_FALSE) + pipes[i].pipe.src.hostvm = false; + else if (dc->debug.dml_hostvm_override == DML_HOSTVM_OVERRIDE_TRUE) + pipes[i].pipe.src.hostvm = true; + } + return pipe_cnt; +} + +int dcn31_populate_dml_pipes_from_context( + struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes, + bool fast_validate) +{ + int i, pipe_cnt; + struct resource_context *res_ctx = &context->res_ctx; + struct pipe_ctx *pipe; + bool upscaled = false; + + DC_FP_START(); + dcn31x_populate_dml_pipes_from_context(dc, context, pipes, fast_validate); + DC_FP_END(); + + for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) { + struct dc_crtc_timing *timing; + + if (!res_ctx->pipe_ctx[i].stream) + continue; + pipe = &res_ctx->pipe_ctx[i]; + timing = &pipe->stream->timing; + if (pipe->plane_state && + (pipe->plane_state->src_rect.height < pipe->plane_state->dst_rect.height || + pipe->plane_state->src_rect.width < pipe->plane_state->dst_rect.width)) + upscaled = true; + + /* + * Immediate flip can be set dynamically after enabling the plane. + * We need to require support for immediate flip or underflow can be + * intermittently experienced depending on peak b/w requirements. + */ + pipes[pipe_cnt].pipe.src.immediate_flip = true; + pipes[pipe_cnt].pipe.src.unbounded_req_mode = false; + pipes[pipe_cnt].pipe.src.gpuvm = true; + pipes[pipe_cnt].pipe.dest.vfront_porch = timing->v_front_porch; + pipes[pipe_cnt].pipe.src.dcc_rate = 3; + pipes[pipe_cnt].dout.dsc_input_bpc = 0; + DC_FP_START(); + dcn31_zero_pipe_dcc_fraction(pipes, pipe_cnt); + DC_FP_END(); + + + if (pipes[pipe_cnt].dout.dsc_enable) { + switch (timing->display_color_depth) { + case COLOR_DEPTH_888: + pipes[pipe_cnt].dout.dsc_input_bpc = 8; + break; + case COLOR_DEPTH_101010: + pipes[pipe_cnt].dout.dsc_input_bpc = 10; + break; + case COLOR_DEPTH_121212: + pipes[pipe_cnt].dout.dsc_input_bpc = 12; + break; + default: + ASSERT(0); + break; + } + } + + pipe_cnt++; + } + context->bw_ctx.dml.ip.det_buffer_size_kbytes = DCN3_1_DEFAULT_DET_SIZE; + dc->config.enable_4to1MPC = false; + if (pipe_cnt == 1 && pipe->plane_state && !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; + } else if (!is_dual_plane(pipe->plane_state->format) && pipe->plane_state->src_rect.width <= 5120) { + /* Limit to 5k max to avoid forced pipe split when there is not enough detile for swath */ + context->bw_ctx.dml.ip.det_buffer_size_kbytes = 192; + pipes[0].pipe.src.unbounded_req_mode = true; + } + } else if (context->stream_count >= dc->debug.crb_alloc_policy_min_disp_count + && dc->debug.crb_alloc_policy > DET_SIZE_DEFAULT) { + context->bw_ctx.dml.ip.det_buffer_size_kbytes = dc->debug.crb_alloc_policy * 64; + } else if (context->stream_count >= 3 && upscaled) { + context->bw_ctx.dml.ip.det_buffer_size_kbytes = 192; + } + + return pipe_cnt; +} + +void dcn31_calculate_wm_and_dlg( + struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int pipe_cnt, + int vlevel) +{ + DC_FP_START(); + dcn31_calculate_wm_and_dlg_fp(dc, context, pipes, pipe_cnt, vlevel); + DC_FP_END(); +} + +void +dcn31_populate_dml_writeback_from_context(struct dc *dc, + struct resource_context *res_ctx, + display_e2e_pipe_params_st *pipes) +{ + DC_FP_START(); + dcn30_populate_dml_writeback_from_context(dc, res_ctx, pipes); + DC_FP_END(); +} + +void +dcn31_set_mcif_arb_params(struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int pipe_cnt) +{ + DC_FP_START(); + dcn30_set_mcif_arb_params(dc, context, pipes, pipe_cnt); + DC_FP_END(); +} + +bool dcn31_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(); + 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 + 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; + } + if (dc->res_pool->funcs->calculate_wm_and_dlg) + 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 void dcn31_get_panel_config_defaults(struct dc_panel_config *panel_config) +{ + *panel_config = panel_config_defaults; +} + +static struct dc_cap_funcs cap_funcs = { + .get_dcc_compression_cap = dcn20_get_dcc_compression_cap +}; + +static struct resource_funcs dcn31_res_pool_funcs = { + .destroy = dcn31_destroy_resource_pool, + .link_enc_create = dcn31_link_encoder_create, + .link_enc_create_minimal = dcn31_link_enc_create_minimal, + .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, + .calculate_wm_and_dlg = dcn31_calculate_wm_and_dlg, + .update_soc_for_wm_a = dcn31_update_soc_for_wm_a, + .populate_dml_pipes = dcn31_populate_dml_pipes_from_context, + .acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer, + .release_pipe = dcn20_release_pipe, + .add_stream_to_ctx = dcn30_add_stream_to_ctx, + .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource, + .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, + .populate_dml_writeback_from_context = dcn31_populate_dml_writeback_from_context, + .set_mcif_arb_params = dcn31_set_mcif_arb_params, + .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 = dcn31_update_bw_bounding_box, + .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, + .get_panel_config_defaults = dcn31_get_panel_config_defaults, +}; + +static struct clock_source *dcn30_clock_source_create( + struct dc_context *ctx, + struct dc_bios *bios, + enum clock_source_id id, + const struct dce110_clk_src_regs *regs, + bool dp_clk_src) +{ + struct dce110_clk_src *clk_src = + kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); + + if (!clk_src) + return NULL; + + if (dcn31_clk_src_construct(clk_src, ctx, bios, id, + regs, &cs_shift, &cs_mask)) { + clk_src->base.dp_clk_src = dp_clk_src; + return &clk_src->base; + } + + BREAK_TO_DEBUGGER(); + return NULL; +} + +static bool dcn31_resource_construct( + uint8_t num_virtual_links, + struct dc *dc, + struct dcn31_resource_pool *pool) +{ + int i; + struct dc_context *ctx = dc->ctx; + struct irq_service_init_data init_data; + + ctx->dc_bios->regs = &bios_regs; + + pool->base.res_cap = &res_cap_dcn31; + + pool->base.funcs = &dcn31_res_pool_funcs; + + /************************************************* + * Resource + asic cap harcoding * + *************************************************/ + pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.pipe_count = pool->base.res_cap->num_timing_generator; + 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 = 5; /*1.4 w/a applied by default*/ + dc->caps.max_cursor_size = 256; + dc->caps.min_horizontal_blanking_period = 80; + dc->caps.dmdata_alloc_size = 2048; + + dc->caps.max_slave_planes = 2; + dc->caps.max_slave_yuv_planes = 2; + dc->caps.max_slave_rgb_planes = 2; + dc->caps.post_blend_color_processing = true; + dc->caps.force_dp_tps4_for_cp2520 = true; + if (dc->config.forceHBR2CP2520) + dc->caps.force_dp_tps4_for_cp2520 = false; + dc->caps.dp_hpo = true; + dc->caps.dp_hdmi21_pcon_support = true; + dc->caps.edp_dsc_support = true; + dc->caps.extended_aux_timeout_support = true; + dc->caps.dmcub_support = true; + dc->caps.is_apu = true; + dc->caps.zstate_support = true; + + /* Color pipeline capabilities */ + dc->caps.color.dpp.dcn_arch = 1; + dc->caps.color.dpp.input_lut_shared = 0; + dc->caps.color.dpp.icsc = 1; + dc->caps.color.dpp.dgam_ram = 0; // must use gamma_corr + dc->caps.color.dpp.dgam_rom_caps.srgb = 1; + dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1; + dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 1; + dc->caps.color.dpp.dgam_rom_caps.pq = 1; + dc->caps.color.dpp.dgam_rom_caps.hlg = 1; + dc->caps.color.dpp.post_csc = 1; + dc->caps.color.dpp.gamma_corr = 1; + dc->caps.color.dpp.dgam_rom_for_yuv = 0; + + dc->caps.color.dpp.hw_3d_lut = 1; + dc->caps.color.dpp.ogam_ram = 1; + // no OGAM ROM on DCN301 + dc->caps.color.dpp.ogam_rom_caps.srgb = 0; + dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0; + dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0; + dc->caps.color.dpp.ogam_rom_caps.pq = 0; + dc->caps.color.dpp.ogam_rom_caps.hlg = 0; + dc->caps.color.dpp.ocsc = 0; + + dc->caps.color.mpc.gamut_remap = 1; + dc->caps.color.mpc.num_3dluts = pool->base.res_cap->num_mpc_3dlut; //2 + dc->caps.color.mpc.ogam_ram = 1; + dc->caps.color.mpc.ogam_rom_caps.srgb = 0; + dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0; + dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0; + dc->caps.color.mpc.ogam_rom_caps.pq = 0; + dc->caps.color.mpc.ogam_rom_caps.hlg = 0; + dc->caps.color.mpc.ocsc = 1; + + dc->config.use_old_fixed_vs_sequence = true; + + /* Use pipe context based otg sync logic */ + dc->config.use_pipe_ctx_sync_logic = true; + + /* read VBIOS LTTPR caps */ + { + if (ctx->dc_bios->funcs->get_lttpr_caps) { + enum bp_result bp_query_result; + uint8_t is_vbios_lttpr_enable = 0; + + bp_query_result = ctx->dc_bios->funcs->get_lttpr_caps(ctx->dc_bios, &is_vbios_lttpr_enable); + dc->caps.vbios_lttpr_enable = (bp_query_result == BP_RESULT_OK) && !!is_vbios_lttpr_enable; + } + + /* interop bit is implicit */ + { + dc->caps.vbios_lttpr_aware = true; + } + } + + if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) + dc->debug = debug_defaults_drv; + + // Init the vm_helper + if (dc->vm_helper) + vm_helper_init(dc->vm_helper, 16); + + /************************************************* + * Create resources * + *************************************************/ + + /* Clock Sources for Pixel Clock*/ + pool->base.clock_sources[DCN31_CLK_SRC_PLL0] = + dcn30_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL0, + &clk_src_regs[0], false); + pool->base.clock_sources[DCN31_CLK_SRC_PLL1] = + dcn30_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL1, + &clk_src_regs[1], false); + /*move phypllx_pixclk_resync to dmub next*/ + if (dc->ctx->asic_id.hw_internal_rev == YELLOW_CARP_B0) { + pool->base.clock_sources[DCN31_CLK_SRC_PLL2] = + dcn30_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL2, + &clk_src_regs_b0[2], false); + pool->base.clock_sources[DCN31_CLK_SRC_PLL3] = + dcn30_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL3, + &clk_src_regs_b0[3], false); + } else { + pool->base.clock_sources[DCN31_CLK_SRC_PLL2] = + dcn30_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL2, + &clk_src_regs[2], false); + pool->base.clock_sources[DCN31_CLK_SRC_PLL3] = + dcn30_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL3, + &clk_src_regs[3], false); + } + + pool->base.clock_sources[DCN31_CLK_SRC_PLL4] = + dcn30_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL4, + &clk_src_regs[4], false); + + pool->base.clk_src_count = DCN30_CLK_SRC_TOTAL; + + /* todo: not reuse phy_pll registers */ + pool->base.dp_clock_source = + dcn31_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_ID_DP_DTO, + &clk_src_regs[0], true); + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] == NULL) { + dm_error("DC: failed to create clock sources!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + } + + /* TODO: DCCG */ + pool->base.dccg = dccg31_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask); + if (pool->base.dccg == NULL) { + dm_error("DC: failed to create dccg!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + /* TODO: IRQ */ + init_data.ctx = dc->ctx; + pool->base.irqs = dal_irq_service_dcn31_create(&init_data); + if (!pool->base.irqs) + goto create_fail; + + /* HUBBUB */ + pool->base.hubbub = dcn31_hubbub_create(ctx); + if (pool->base.hubbub == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create hubbub!\n"); + goto create_fail; + } + + /* HUBPs, DPPs, OPPs and TGs */ + for (i = 0; i < pool->base.pipe_count; i++) { + pool->base.hubps[i] = dcn31_hubp_create(ctx, i); + if (pool->base.hubps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create hubps!\n"); + goto create_fail; + } + + pool->base.dpps[i] = dcn31_dpp_create(ctx, i); + if (pool->base.dpps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create dpps!\n"); + goto create_fail; + } + } + + for (i = 0; i < pool->base.res_cap->num_opp; i++) { + pool->base.opps[i] = dcn31_opp_create(ctx, i); + if (pool->base.opps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create output pixel processor!\n"); + goto create_fail; + } + } + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + pool->base.timing_generators[i] = dcn31_timing_generator_create( + ctx, i); + if (pool->base.timing_generators[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create tg!\n"); + goto create_fail; + } + } + pool->base.timing_generator_count = i; + + /* PSR */ + pool->base.psr = dmub_psr_create(ctx); + if (pool->base.psr == NULL) { + dm_error("DC: failed to create psr obj!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + /* Replay */ + pool->base.replay = dmub_replay_create(ctx); + if (pool->base.replay == NULL) { + dm_error("DC: failed to create replay obj!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + /* ABM */ + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + pool->base.multiple_abms[i] = dmub_abm_create(ctx, + &abm_regs[i], + &abm_shift, + &abm_mask); + if (pool->base.multiple_abms[i] == NULL) { + dm_error("DC: failed to create abm for pipe %d!\n", i); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + } + + /* MPC and DSC */ + pool->base.mpc = dcn31_mpc_create(ctx, pool->base.mpcc_count, pool->base.res_cap->num_mpc_3dlut); + if (pool->base.mpc == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create mpc!\n"); + goto create_fail; + } + + for (i = 0; i < pool->base.res_cap->num_dsc; i++) { + pool->base.dscs[i] = dcn31_dsc_create(ctx, i); + if (pool->base.dscs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create display stream compressor %d!\n", i); + goto create_fail; + } + } + + /* DWB and MMHUBBUB */ + if (!dcn31_dwbc_create(ctx, &pool->base)) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dwbc!\n"); + goto create_fail; + } + + if (!dcn31_mmhubbub_create(ctx, &pool->base)) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create mcif_wb!\n"); + goto create_fail; + } + + /* AUX and I2C */ + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + pool->base.engines[i] = dcn31_aux_engine_create(ctx, i); + if (pool->base.engines[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create aux engine!!\n"); + goto create_fail; + } + pool->base.hw_i2cs[i] = dcn31_i2c_hw_create(ctx, i); + if (pool->base.hw_i2cs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create hw i2c!!\n"); + goto create_fail; + } + pool->base.sw_i2cs[i] = NULL; + } + + if (dc->ctx->asic_id.chip_family == FAMILY_YELLOW_CARP && + dc->ctx->asic_id.hw_internal_rev == YELLOW_CARP_B0 && + !dc->debug.dpia_debug.bits.disable_dpia) { + /* YELLOW CARP B0 has 4 DPIA's */ + pool->base.usb4_dpia_count = 4; + } + + if (dc->ctx->asic_id.chip_family == AMDGPU_FAMILY_GC_11_0_1) + pool->base.usb4_dpia_count = 4; + + /* Audio, Stream Encoders including HPO and virtual, MPC 3D LUTs */ + if (!resource_construct(num_virtual_links, dc, &pool->base, + &res_create_funcs)) + goto create_fail; + + /* HW Sequencer and Plane caps */ + dcn31_hw_sequencer_construct(dc); + + dc->caps.max_planes = pool->base.pipe_count; + + for (i = 0; i < dc->caps.max_planes; ++i) + dc->caps.planes[i] = plane_cap; + + dc->cap_funcs = cap_funcs; + + dc->dcn_ip->max_num_dpp = dcn3_1_ip.max_num_dpp; + + return true; + +create_fail: + dcn31_resource_destruct(pool); + + return false; +} + +struct resource_pool *dcn31_create_resource_pool( + const struct dc_init_data *init_data, + struct dc *dc) +{ + struct dcn31_resource_pool *pool = + kzalloc(sizeof(struct dcn31_resource_pool), GFP_KERNEL); + + if (!pool) + return NULL; + + if (dcn31_resource_construct(init_data->num_virtual_links, dc, pool)) + return &pool->base; + + BREAK_TO_DEBUGGER(); + kfree(pool); + return NULL; +} diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.h new file mode 100644 index 00000000000000..901436591ed45c --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.h @@ -0,0 +1,97 @@ +/* + * Copyright 2020 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 _DCN31_RESOURCE_H_ +#define _DCN31_RESOURCE_H_ + +#include "core_types.h" + +#define TO_DCN31_RES_POOL(pool)\ + container_of(pool, struct dcn31_resource_pool, base) + +extern struct _vcs_dpi_ip_params_st dcn3_1_ip; + +struct dcn31_resource_pool { + struct resource_pool base; +}; + +bool dcn31_validate_bandwidth(struct dc *dc, + struct dc_state *context, + bool fast_validate); +void dcn31_calculate_wm_and_dlg( + struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int pipe_cnt, + int vlevel); +int dcn31_populate_dml_pipes_from_context( + struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes, + bool fast_validate); +void +dcn31_populate_dml_writeback_from_context(struct dc *dc, + struct resource_context *res_ctx, + display_e2e_pipe_params_st *pipes); +void +dcn31_set_mcif_arb_params(struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int pipe_cnt); + +struct resource_pool *dcn31_create_resource_pool( + const struct dc_init_data *init_data, + struct dc *dc); + +/*temp: B0 specific before switch to dcn313 headers*/ +#ifndef regPHYPLLF_PIXCLK_RESYNC_CNTL +#define regPHYPLLF_PIXCLK_RESYNC_CNTL 0x007e +#define regPHYPLLF_PIXCLK_RESYNC_CNTL_BASE_IDX 1 +#define regPHYPLLG_PIXCLK_RESYNC_CNTL 0x005f +#define regPHYPLLG_PIXCLK_RESYNC_CNTL_BASE_IDX 1 + +//PHYPLLF_PIXCLK_RESYNC_CNTL +#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_PIXCLK_RESYNC_ENABLE__SHIFT 0x0 +#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_DEEP_COLOR_DTO_ENABLE_STATUS__SHIFT 0x1 +#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_DCCG_DEEP_COLOR_CNTL__SHIFT 0x4 +#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_PIXCLK_ENABLE__SHIFT 0x8 +#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_PIXCLK_DOUBLE_RATE_ENABLE__SHIFT 0x9 +#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_PIXCLK_RESYNC_ENABLE_MASK 0x00000001L +#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_DEEP_COLOR_DTO_ENABLE_STATUS_MASK 0x00000002L +#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_DCCG_DEEP_COLOR_CNTL_MASK 0x00000030L +#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_PIXCLK_ENABLE_MASK 0x00000100L +#define PHYPLLF_PIXCLK_RESYNC_CNTL__PHYPLLF_PIXCLK_DOUBLE_RATE_ENABLE_MASK 0x00000200L + +//PHYPLLG_PIXCLK_RESYNC_CNTL +#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_PIXCLK_RESYNC_ENABLE__SHIFT 0x0 +#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_DEEP_COLOR_DTO_ENABLE_STATUS__SHIFT 0x1 +#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_DCCG_DEEP_COLOR_CNTL__SHIFT 0x4 +#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_PIXCLK_ENABLE__SHIFT 0x8 +#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_PIXCLK_DOUBLE_RATE_ENABLE__SHIFT 0x9 +#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_PIXCLK_RESYNC_ENABLE_MASK 0x00000001L +#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_DEEP_COLOR_DTO_ENABLE_STATUS_MASK 0x00000002L +#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_DCCG_DEEP_COLOR_CNTL_MASK 0x00000030L +#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_PIXCLK_ENABLE_MASK 0x00000100L +#define PHYPLLG_PIXCLK_RESYNC_CNTL__PHYPLLG_PIXCLK_DOUBLE_RATE_ENABLE_MASK 0x00000200L +#endif +#endif /* _DCN31_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c new file mode 100644 index 00000000000000..c97391edb5ff7a --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c @@ -0,0 +1,2180 @@ +// SPDX-License-Identifier: MIT +/* + * 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 "dm_services.h" +#include "dc.h" + +#include "dcn31/dcn31_init.h" +#include "dcn314/dcn314_init.h" + +#include "resource.h" +#include "include/irq_service_interface.h" +#include "dcn314_resource.h" + +#include "dcn20/dcn20_resource.h" +#include "dcn30/dcn30_resource.h" +#include "dcn31/dcn31_resource.h" + +#include "dcn10/dcn10_ipp.h" +#include "dcn30/dcn30_hubbub.h" +#include "dcn31/dcn31_hubbub.h" +#include "dcn30/dcn30_mpc.h" +#include "dcn31/dcn31_hubp.h" +#include "irq/dcn31/irq_service_dcn31.h" +#include "irq/dcn314/irq_service_dcn314.h" +#include "dcn30/dcn30_dpp.h" +#include "dcn314/dcn314_optc.h" +#include "dcn20/dcn20_hwseq.h" +#include "dcn30/dcn30_hwseq.h" +#include "dce110/dce110_hwseq.h" +#include "dcn30/dcn30_opp.h" +#include "dcn20/dcn20_dsc.h" +#include "dcn30/dcn30_vpg.h" +#include "dcn30/dcn30_afmt.h" +#include "dcn31/dcn31_dio_link_encoder.h" +#include "dcn314/dcn314_dio_stream_encoder.h" +#include "dcn31/dcn31_hpo_dp_stream_encoder.h" +#include "dcn31/dcn31_hpo_dp_link_encoder.h" +#include "dcn31/dcn31_apg.h" +#include "dcn31/dcn31_vpg.h" +#include "dcn31/dcn31_afmt.h" +#include "dce/dce_clock_source.h" +#include "dce/dce_audio.h" +#include "dce/dce_hwseq.h" +#include "clk_mgr.h" +#include "virtual/virtual_stream_encoder.h" +#include "dce110/dce110_resource.h" +#include "dml/display_mode_vba.h" +#include "dml/dcn31/dcn31_fpu.h" +#include "dml/dcn314/dcn314_fpu.h" +#include "dcn314/dcn314_dccg.h" +#include "dcn10/dcn10_resource.h" +#include "dcn31/dcn31_panel_cntl.h" +#include "dcn314/dcn314_hwseq.h" + +#include "dcn30/dcn30_dwb.h" +#include "dcn30/dcn30_mmhubbub.h" + +#include "dcn/dcn_3_1_4_offset.h" +#include "dcn/dcn_3_1_4_sh_mask.h" +#include "dpcs/dpcs_3_1_4_offset.h" +#include "dpcs/dpcs_3_1_4_sh_mask.h" + +#define DCHUBBUB_DEBUG_CTRL_0__DET_DEPTH__SHIFT 0x10 +#define DCHUBBUB_DEBUG_CTRL_0__DET_DEPTH_MASK 0x01FF0000L + +#define DSCC0_DSCC_CONFIG0__ICH_RESET_AT_END_OF_LINE__SHIFT 0x0 +#define DSCC0_DSCC_CONFIG0__ICH_RESET_AT_END_OF_LINE_MASK 0x0000000FL + +#include "reg_helper.h" +#include "dce/dmub_abm.h" +#include "dce/dmub_psr.h" +#include "dce/dmub_replay.h" +#include "dce/dce_aux.h" +#include "dce/dce_i2c.h" +#include "dml/dcn314/display_mode_vba_314.h" +#include "vm_helper.h" +#include "dcn20/dcn20_vmid.h" + +#include "link_enc_cfg.h" + +#define DCN_BASE__INST0_SEG1 0x000000C0 +#define DCN_BASE__INST0_SEG2 0x000034C0 +#define DCN_BASE__INST0_SEG3 0x00009000 + +#define NBIO_BASE__INST0_SEG1 0x00000014 + +#define MAX_INSTANCE 7 +#define MAX_SEGMENT 8 + +#define regBIF_BX2_BIOS_SCRATCH_2 0x003a +#define regBIF_BX2_BIOS_SCRATCH_2_BASE_IDX 1 +#define regBIF_BX2_BIOS_SCRATCH_3 0x003b +#define regBIF_BX2_BIOS_SCRATCH_3_BASE_IDX 1 +#define regBIF_BX2_BIOS_SCRATCH_6 0x003e +#define regBIF_BX2_BIOS_SCRATCH_6_BASE_IDX 1 + +#define DC_LOGGER \ + dc->ctx->logger +#define DC_LOGGER_INIT(logger) + +enum dcn31_clk_src_array_id { + DCN31_CLK_SRC_PLL0, + DCN31_CLK_SRC_PLL1, + DCN31_CLK_SRC_PLL2, + DCN31_CLK_SRC_PLL3, + DCN31_CLK_SRC_PLL4, + DCN30_CLK_SRC_TOTAL +}; + +/* begin ********************* + * macros to expend register list macro defined in HW object header file + */ + +/* DCN */ +/* TODO awful hack. fixup dcn20_dwb.h */ +#undef BASE_INNER +#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg + +#define BASE(seg) BASE_INNER(seg) + +#define SR(reg_name)\ + .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ + reg ## reg_name + +#define SRI(reg_name, block, id)\ + .reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRI2(reg_name, block, id)\ + .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ + reg ## reg_name + +#define SRIR(var_name, reg_name, block, id)\ + .var_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRII(reg_name, block, id)\ + .reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRII_MPC_RMU(reg_name, block, id)\ + .RMU##_##reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRII_DWB(reg_name, temp_name, block, id)\ + .reg_name[id] = BASE(reg ## block ## id ## _ ## temp_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## temp_name + +#define SF_DWB2(reg_name, block, id, field_name, post_fix) \ + .field_name = reg_name ## __ ## field_name ## post_fix + +#define DCCG_SRII(reg_name, block, id)\ + .block ## _ ## reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define VUPDATE_SRII(reg_name, block, id)\ + .reg_name[id] = BASE(reg ## reg_name ## _ ## block ## id ## _BASE_IDX) + \ + reg ## reg_name ## _ ## block ## id + +/* NBIO */ +#define NBIO_BASE_INNER(seg) \ + NBIO_BASE__INST0_SEG ## seg + +#define NBIO_BASE(seg) \ + NBIO_BASE_INNER(seg) + +#define NBIO_SR(reg_name)\ + .reg_name = NBIO_BASE(regBIF_BX2_ ## reg_name ## _BASE_IDX) + \ + regBIF_BX2_ ## reg_name + +/* MMHUB */ +#define MMHUB_BASE_INNER(seg) \ + MMHUB_BASE__INST0_SEG ## seg + +#define MMHUB_BASE(seg) \ + MMHUB_BASE_INNER(seg) + +#define MMHUB_SR(reg_name)\ + .reg_name = MMHUB_BASE(reg ## reg_name ## _BASE_IDX) + \ + reg ## reg_name + +/* CLOCK */ +#define CLK_BASE_INNER(seg) \ + CLK_BASE__INST0_SEG ## seg + +#define CLK_BASE(seg) \ + CLK_BASE_INNER(seg) + +#define CLK_SRI(reg_name, block, inst)\ + .reg_name = CLK_BASE(reg ## block ## _ ## inst ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## _ ## inst ## _ ## reg_name + + +static const struct bios_registers bios_regs = { + NBIO_SR(BIOS_SCRATCH_3), + NBIO_SR(BIOS_SCRATCH_6) +}; + +#define clk_src_regs(index, pllid)\ +[index] = {\ + CS_COMMON_REG_LIST_DCN3_0(index, pllid),\ +} + +static const struct dce110_clk_src_regs clk_src_regs[] = { + clk_src_regs(0, A), + clk_src_regs(1, B), + clk_src_regs(2, C), + clk_src_regs(3, D), + clk_src_regs(4, E) +}; + +static const struct dce110_clk_src_shift cs_shift = { + CS_COMMON_MASK_SH_LIST_DCN3_1_4(__SHIFT) +}; + +static const struct dce110_clk_src_mask cs_mask = { + CS_COMMON_MASK_SH_LIST_DCN3_1_4(_MASK) +}; + +#define abm_regs(id)\ +[id] = {\ + ABM_DCN302_REG_LIST(id)\ +} + +static const struct dce_abm_registers abm_regs[] = { + abm_regs(0), + abm_regs(1), + abm_regs(2), + abm_regs(3), +}; + +static const struct dce_abm_shift abm_shift = { + ABM_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dce_abm_mask abm_mask = { + ABM_MASK_SH_LIST_DCN30(_MASK) +}; + +#define audio_regs(id)\ +[id] = {\ + AUD_COMMON_REG_LIST(id)\ +} + +static const struct dce_audio_registers audio_regs[] = { + audio_regs(0), + audio_regs(1), + audio_regs(2), + audio_regs(3), + audio_regs(4), + audio_regs(5), + audio_regs(6) +}; + +#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ + AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) + +static const struct dce_audio_shift audio_shift = { + DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_audio_mask audio_mask = { + DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) +}; + +#define vpg_regs(id)\ +[id] = {\ + VPG_DCN31_REG_LIST(id)\ +} + +static const struct dcn31_vpg_registers vpg_regs[] = { + vpg_regs(0), + vpg_regs(1), + vpg_regs(2), + vpg_regs(3), + vpg_regs(4), + vpg_regs(5), + vpg_regs(6), + vpg_regs(7), + vpg_regs(8), + vpg_regs(9), +}; + +static const struct dcn31_vpg_shift vpg_shift = { + DCN31_VPG_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn31_vpg_mask vpg_mask = { + DCN31_VPG_MASK_SH_LIST(_MASK) +}; + +#define afmt_regs(id)\ +[id] = {\ + AFMT_DCN31_REG_LIST(id)\ +} + +static const struct dcn31_afmt_registers afmt_regs[] = { + afmt_regs(0), + afmt_regs(1), + afmt_regs(2), + afmt_regs(3), + afmt_regs(4), + afmt_regs(5) +}; + +static const struct dcn31_afmt_shift afmt_shift = { + DCN31_AFMT_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn31_afmt_mask afmt_mask = { + DCN31_AFMT_MASK_SH_LIST(_MASK) +}; + +#define apg_regs(id)\ +[id] = {\ + APG_DCN31_REG_LIST(id)\ +} + +static const struct dcn31_apg_registers apg_regs[] = { + apg_regs(0), + apg_regs(1), + apg_regs(2), + apg_regs(3) +}; + +static const struct dcn31_apg_shift apg_shift = { + DCN31_APG_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn31_apg_mask apg_mask = { + DCN31_APG_MASK_SH_LIST(_MASK) +}; + +#define stream_enc_regs(id)\ +[id] = {\ + SE_DCN314_REG_LIST(id)\ +} + +static const struct dcn10_stream_enc_registers stream_enc_regs[] = { + stream_enc_regs(0), + stream_enc_regs(1), + stream_enc_regs(2), + stream_enc_regs(3), + stream_enc_regs(4) +}; + +static const struct dcn10_stream_encoder_shift se_shift = { + SE_COMMON_MASK_SH_LIST_DCN314(__SHIFT) +}; + +static const struct dcn10_stream_encoder_mask se_mask = { + SE_COMMON_MASK_SH_LIST_DCN314(_MASK) +}; + + +#define aux_regs(id)\ +[id] = {\ + DCN2_AUX_REG_LIST(id)\ +} + +static const struct dcn10_link_enc_aux_registers link_enc_aux_regs[] = { + aux_regs(0), + aux_regs(1), + aux_regs(2), + aux_regs(3), + aux_regs(4) +}; + +#define hpd_regs(id)\ +[id] = {\ + HPD_REG_LIST(id)\ +} + +static const struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[] = { + hpd_regs(0), + hpd_regs(1), + hpd_regs(2), + hpd_regs(3), + hpd_regs(4) +}; + +#define link_regs(id, phyid)\ +[id] = {\ + LE_DCN31_REG_LIST(id), \ + UNIPHY_DCN2_REG_LIST(phyid), \ +} + +static const struct dce110_aux_registers_shift aux_shift = { + DCN_AUX_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce110_aux_registers_mask aux_mask = { + DCN_AUX_MASK_SH_LIST(_MASK) +}; + +static const struct dcn10_link_enc_registers link_enc_regs[] = { + link_regs(0, A), + link_regs(1, B), + link_regs(2, C), + link_regs(3, D), + link_regs(4, E) +}; + +static const struct dcn10_link_enc_shift le_shift = { + LINK_ENCODER_MASK_SH_LIST_DCN31(__SHIFT), + DPCS_DCN31_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn10_link_enc_mask le_mask = { + LINK_ENCODER_MASK_SH_LIST_DCN31(_MASK), + DPCS_DCN31_MASK_SH_LIST(_MASK) +}; + +#define hpo_dp_stream_encoder_reg_list(id)\ +[id] = {\ + DCN3_1_HPO_DP_STREAM_ENC_REG_LIST(id)\ +} + +static const struct dcn31_hpo_dp_stream_encoder_registers hpo_dp_stream_enc_regs[] = { + hpo_dp_stream_encoder_reg_list(0), + hpo_dp_stream_encoder_reg_list(1), + hpo_dp_stream_encoder_reg_list(2), + hpo_dp_stream_encoder_reg_list(3) +}; + +static const struct dcn31_hpo_dp_stream_encoder_shift hpo_dp_se_shift = { + DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn31_hpo_dp_stream_encoder_mask hpo_dp_se_mask = { + DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(_MASK) +}; + + +#define hpo_dp_link_encoder_reg_list(id)\ +[id] = {\ + DCN3_1_HPO_DP_LINK_ENC_REG_LIST(id),\ + DCN3_1_RDPCSTX_REG_LIST(0),\ + DCN3_1_RDPCSTX_REG_LIST(1),\ + DCN3_1_RDPCSTX_REG_LIST(2),\ +} + +static const struct dcn31_hpo_dp_link_encoder_registers hpo_dp_link_enc_regs[] = { + hpo_dp_link_encoder_reg_list(0), + hpo_dp_link_encoder_reg_list(1), +}; + +static const struct dcn31_hpo_dp_link_encoder_shift hpo_dp_le_shift = { + DCN3_1_HPO_DP_LINK_ENC_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn31_hpo_dp_link_encoder_mask hpo_dp_le_mask = { + DCN3_1_HPO_DP_LINK_ENC_MASK_SH_LIST(_MASK) +}; + +#define dpp_regs(id)\ +[id] = {\ + DPP_REG_LIST_DCN30(id),\ +} + +static const struct dcn3_dpp_registers dpp_regs[] = { + dpp_regs(0), + dpp_regs(1), + dpp_regs(2), + dpp_regs(3) +}; + +static const struct dcn3_dpp_shift tf_shift = { + DPP_REG_LIST_SH_MASK_DCN30(__SHIFT) +}; + +static const struct dcn3_dpp_mask tf_mask = { + DPP_REG_LIST_SH_MASK_DCN30(_MASK) +}; + +#define opp_regs(id)\ +[id] = {\ + OPP_REG_LIST_DCN30(id),\ +} + +static const struct dcn20_opp_registers opp_regs[] = { + opp_regs(0), + opp_regs(1), + opp_regs(2), + opp_regs(3) +}; + +static const struct dcn20_opp_shift opp_shift = { + OPP_MASK_SH_LIST_DCN20(__SHIFT) +}; + +static const struct dcn20_opp_mask opp_mask = { + OPP_MASK_SH_LIST_DCN20(_MASK) +}; + +#define aux_engine_regs(id)\ +[id] = {\ + AUX_COMMON_REG_LIST0(id), \ + .AUXN_IMPCAL = 0, \ + .AUXP_IMPCAL = 0, \ + .AUX_RESET_MASK = DP_AUX0_AUX_CONTROL__AUX_RESET_MASK, \ +} + +static const struct dce110_aux_registers aux_engine_regs[] = { + aux_engine_regs(0), + aux_engine_regs(1), + aux_engine_regs(2), + aux_engine_regs(3), + aux_engine_regs(4) +}; + +#define dwbc_regs_dcn3(id)\ +[id] = {\ + DWBC_COMMON_REG_LIST_DCN30(id),\ +} + +static const struct dcn30_dwbc_registers dwbc30_regs[] = { + dwbc_regs_dcn3(0), +}; + +static const struct dcn30_dwbc_shift dwbc30_shift = { + DWBC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn30_dwbc_mask dwbc30_mask = { + DWBC_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +#define mcif_wb_regs_dcn3(id)\ +[id] = {\ + MCIF_WB_COMMON_REG_LIST_DCN30(id),\ +} + +static const struct dcn30_mmhubbub_registers mcif_wb30_regs[] = { + mcif_wb_regs_dcn3(0) +}; + +static const struct dcn30_mmhubbub_shift mcif_wb30_shift = { + MCIF_WB_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn30_mmhubbub_mask mcif_wb30_mask = { + MCIF_WB_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +#define dsc_regsDCN314(id)\ +[id] = {\ + DSC_REG_LIST_DCN20(id)\ +} + +static const struct dcn20_dsc_registers dsc_regs[] = { + dsc_regsDCN314(0), + dsc_regsDCN314(1), + dsc_regsDCN314(2), + dsc_regsDCN314(3) +}; + +static const struct dcn20_dsc_shift dsc_shift = { + DSC_REG_LIST_SH_MASK_DCN20(__SHIFT) +}; + +static const struct dcn20_dsc_mask dsc_mask = { + DSC_REG_LIST_SH_MASK_DCN20(_MASK) +}; + +static const struct dcn30_mpc_registers mpc_regs = { + MPC_REG_LIST_DCN3_0(0), + MPC_REG_LIST_DCN3_0(1), + MPC_REG_LIST_DCN3_0(2), + MPC_REG_LIST_DCN3_0(3), + MPC_OUT_MUX_REG_LIST_DCN3_0(0), + MPC_OUT_MUX_REG_LIST_DCN3_0(1), + MPC_OUT_MUX_REG_LIST_DCN3_0(2), + MPC_OUT_MUX_REG_LIST_DCN3_0(3), + MPC_RMU_GLOBAL_REG_LIST_DCN3AG, + MPC_RMU_REG_LIST_DCN3AG(0), + MPC_RMU_REG_LIST_DCN3AG(1), + //MPC_RMU_REG_LIST_DCN3AG(2), + MPC_DWB_MUX_REG_LIST_DCN3_0(0), +}; + +static const struct dcn30_mpc_shift mpc_shift = { + MPC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn30_mpc_mask mpc_mask = { + MPC_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +#define optc_regs(id)\ +[id] = {OPTC_COMMON_REG_LIST_DCN3_14(id)} + +static const struct dcn_optc_registers optc_regs[] = { + optc_regs(0), + optc_regs(1), + optc_regs(2), + optc_regs(3) +}; + +static const struct dcn_optc_shift optc_shift = { + OPTC_COMMON_MASK_SH_LIST_DCN3_14(__SHIFT) +}; + +static const struct dcn_optc_mask optc_mask = { + OPTC_COMMON_MASK_SH_LIST_DCN3_14(_MASK) +}; + +#define hubp_regs(id)\ +[id] = {\ + HUBP_REG_LIST_DCN30(id)\ +} + +static const struct dcn_hubp2_registers hubp_regs[] = { + hubp_regs(0), + hubp_regs(1), + hubp_regs(2), + hubp_regs(3) +}; + + +static const struct dcn_hubp2_shift hubp_shift = { + HUBP_MASK_SH_LIST_DCN31(__SHIFT) +}; + +static const struct dcn_hubp2_mask hubp_mask = { + HUBP_MASK_SH_LIST_DCN31(_MASK) +}; +static const struct dcn_hubbub_registers hubbub_reg = { + HUBBUB_REG_LIST_DCN31(0) +}; + +static const struct dcn_hubbub_shift hubbub_shift = { + HUBBUB_MASK_SH_LIST_DCN31(__SHIFT) +}; + +static const struct dcn_hubbub_mask hubbub_mask = { + HUBBUB_MASK_SH_LIST_DCN31(_MASK) +}; + +static const struct dccg_registers dccg_regs = { + DCCG_REG_LIST_DCN314() +}; + +static const struct dccg_shift dccg_shift = { + DCCG_MASK_SH_LIST_DCN314(__SHIFT) +}; + +static const struct dccg_mask dccg_mask = { + DCCG_MASK_SH_LIST_DCN314(_MASK) +}; + + +#define SRII2(reg_name_pre, reg_name_post, id)\ + .reg_name_pre ## _ ## reg_name_post[id] = BASE(reg ## reg_name_pre \ + ## id ## _ ## reg_name_post ## _BASE_IDX) + \ + reg ## reg_name_pre ## id ## _ ## reg_name_post + + +#define HWSEQ_DCN31_REG_LIST()\ + SR(DCHUBBUB_GLOBAL_TIMER_CNTL), \ + SR(DCHUBBUB_ARB_HOSTVM_CNTL), \ + SR(DIO_MEM_PWR_CTRL), \ + SR(ODM_MEM_PWR_CTRL3), \ + SR(DMU_MEM_PWR_CNTL), \ + SR(MMHUBBUB_MEM_PWR_CNTL), \ + SR(DCCG_GATE_DISABLE_CNTL), \ + SR(DCCG_GATE_DISABLE_CNTL2), \ + SR(DCFCLK_CNTL),\ + SR(DC_MEM_GLOBAL_PWR_REQ_CNTL), \ + SRII(PIXEL_RATE_CNTL, OTG, 0), \ + SRII(PIXEL_RATE_CNTL, OTG, 1),\ + SRII(PIXEL_RATE_CNTL, OTG, 2),\ + SRII(PIXEL_RATE_CNTL, OTG, 3),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 0),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 1),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 2),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 3),\ + SR(MICROSECOND_TIME_BASE_DIV), \ + SR(MILLISECOND_TIME_BASE_DIV), \ + SR(DISPCLK_FREQ_CHANGE_CNTL), \ + SR(RBBMIF_TIMEOUT_DIS), \ + SR(RBBMIF_TIMEOUT_DIS_2), \ + SR(DCHUBBUB_CRC_CTRL), \ + SR(DPP_TOP0_DPP_CRC_CTRL), \ + SR(DPP_TOP0_DPP_CRC_VAL_B_A), \ + SR(DPP_TOP0_DPP_CRC_VAL_R_G), \ + SR(MPC_CRC_CTRL), \ + SR(MPC_CRC_RESULT_GB), \ + SR(MPC_CRC_RESULT_C), \ + SR(MPC_CRC_RESULT_AR), \ + SR(DOMAIN0_PG_CONFIG), \ + SR(DOMAIN1_PG_CONFIG), \ + SR(DOMAIN2_PG_CONFIG), \ + SR(DOMAIN3_PG_CONFIG), \ + SR(DOMAIN16_PG_CONFIG), \ + SR(DOMAIN17_PG_CONFIG), \ + SR(DOMAIN18_PG_CONFIG), \ + SR(DOMAIN19_PG_CONFIG), \ + SR(DOMAIN0_PG_STATUS), \ + SR(DOMAIN1_PG_STATUS), \ + SR(DOMAIN2_PG_STATUS), \ + SR(DOMAIN3_PG_STATUS), \ + SR(DOMAIN16_PG_STATUS), \ + SR(DOMAIN17_PG_STATUS), \ + SR(DOMAIN18_PG_STATUS), \ + SR(DOMAIN19_PG_STATUS), \ + SR(D1VGA_CONTROL), \ + SR(D2VGA_CONTROL), \ + SR(D3VGA_CONTROL), \ + SR(D4VGA_CONTROL), \ + SR(D5VGA_CONTROL), \ + SR(D6VGA_CONTROL), \ + SR(DC_IP_REQUEST_CNTL), \ + SR(AZALIA_AUDIO_DTO), \ + SR(AZALIA_CONTROLLER_CLOCK_GATING), \ + SR(HPO_TOP_HW_CONTROL) + +static const struct dce_hwseq_registers hwseq_reg = { + HWSEQ_DCN31_REG_LIST() +}; + +#define HWSEQ_DCN31_MASK_SH_LIST(mask_sh)\ + HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ + HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \ + HWS_SF(, DCHUBBUB_ARB_HOSTVM_CNTL, DISABLE_HOSTVM_FORCE_ALLOW_PSTATE, mask_sh), \ + HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN19_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN19_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN16_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN17_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN18_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN19_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \ + HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh), \ + HWS_SF(, HPO_TOP_CLOCK_CONTROL, HPO_HDMISTREAMCLK_G_GATE_DIS, mask_sh), \ + HWS_SF(, DMU_MEM_PWR_CNTL, DMCU_ERAM_MEM_PWR_FORCE, mask_sh), \ + HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_UNASSIGNED_PWR_MODE, mask_sh), \ + HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_VBLANK_PWR_MODE, mask_sh), \ + HWS_SF(, MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, mask_sh), \ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh), \ + HWS_SF(, HPO_TOP_HW_CONTROL, HPO_IO_EN, mask_sh) + +static const struct dce_hwseq_shift hwseq_shift = { + HWSEQ_DCN31_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_hwseq_mask hwseq_mask = { + HWSEQ_DCN31_MASK_SH_LIST(_MASK) +}; +#define vmid_regs(id)\ +[id] = {\ + DCN20_VMID_REG_LIST(id)\ +} + +static const struct dcn_vmid_registers vmid_regs[] = { + vmid_regs(0), + vmid_regs(1), + vmid_regs(2), + vmid_regs(3), + vmid_regs(4), + vmid_regs(5), + vmid_regs(6), + vmid_regs(7), + vmid_regs(8), + vmid_regs(9), + vmid_regs(10), + vmid_regs(11), + vmid_regs(12), + vmid_regs(13), + vmid_regs(14), + vmid_regs(15) +}; + +static const struct dcn20_vmid_shift vmid_shifts = { + DCN20_VMID_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn20_vmid_mask vmid_masks = { + DCN20_VMID_MASK_SH_LIST(_MASK) +}; + +static const struct resource_caps res_cap_dcn314 = { + .num_timing_generator = 4, + .num_opp = 4, + .num_video_plane = 4, + .num_audio = 5, + .num_stream_encoder = 5, + .num_dig_link_enc = 5, + .num_hpo_dp_stream_encoder = 4, + .num_hpo_dp_link_encoder = 2, + .num_pll = 5, + .num_dwb = 1, + .num_ddc = 5, + .num_vmid = 16, + .num_mpc_3dlut = 2, + .num_dsc = 4, +}; + +static const struct dc_plane_cap plane_cap = { + .type = DC_PLANE_TYPE_DCN_UNIVERSAL, + .per_pixel_alpha = true, + + .pixel_format_support = { + .argb8888 = true, + .nv12 = true, + .fp16 = true, + .p010 = true, + .ayuv = false, + }, + + .max_upscale_factor = { + .argb8888 = 16000, + .nv12 = 16000, + .fp16 = 16000 + }, + + // 6:1 downscaling ratio: 1000/6 = 166.666 + // 4:1 downscaling ratio for ARGB888 to prevent underflow during P010 playback: 1000/4 = 250 + .max_downscale_factor = { + .argb8888 = 250, + .nv12 = 167, + .fp16 = 167 + }, + 64, + 64 +}; + +static const struct dc_debug_options debug_defaults_drv = { + .disable_z10 = false, + .enable_z9_disable_interface = true, + .minimum_z8_residency_time = 2100, + .psr_skip_crtc_disable = true, + .replay_skip_crtc_disabled = true, + .disable_dmcu = true, + .force_abm_enable = false, + .timing_trace = false, + .clock_trace = true, + .disable_dpp_power_gate = false, + .disable_hubp_power_gate = false, + .disable_pplib_clock_request = false, + .pipe_split_policy = MPC_SPLIT_DYNAMIC, + .force_single_disp_pipe_split = false, + .disable_dcc = DCC_ENABLE, + .vsr_support = true, + .performance_trace = false, + .max_downscale_src_width = 4096,/*upto true 4k*/ + .disable_pplib_wm_range = false, + .scl_reset_length10 = true, + .sanity_checks = true, + .underflow_assert_delay_us = 0xFFFFFFFF, + .dwb_fi_phase = -1, // -1 = disable, + .dmub_command_table = true, + .pstate_enabled = true, + .use_max_lb = true, + .enable_mem_low_power = { + .bits = { + .vga = true, + .i2c = true, + .dmcu = false, // This is previously known to cause hang on S3 cycles if enabled + .dscl = true, + .cm = true, + .mpc = true, + .optc = true, + .vpg = true, + .afmt = true, + } + }, + + .root_clock_optimization = { + .bits = { + .dpp = true, + .dsc = true, + .hdmistream = true, + .hdmichar = true, + .dpstream = true, + .symclk32_se = false, + .symclk32_le = true, + .symclk_fe = true, + .physymclk = true, + .dpiasymclk = true, + } + }, + + .seamless_boot_odm_combine = true, + .using_dml2 = false, +}; + +static const struct dc_debug_options debug_defaults_diags = { + .disable_dmcu = true, + .force_abm_enable = false, + .timing_trace = true, + .clock_trace = true, + .disable_dpp_power_gate = true, + .disable_hubp_power_gate = true, + .disable_clock_gate = true, + .disable_pplib_clock_request = true, + .disable_pplib_wm_range = true, + .disable_stutter = false, + .scl_reset_length10 = true, + .dwb_fi_phase = -1, // -1 = disable + .dmub_command_table = true, + .enable_tri_buf = true, + .use_max_lb = true +}; + +static const struct dc_panel_config panel_config_defaults = { + .psr = { + .disable_psr = false, + .disallow_psrsu = false, + .disallow_replay = false, + }, + .ilr = { + .optimize_edp_link_rate = true, + }, +}; + +static void dcn31_dpp_destroy(struct dpp **dpp) +{ + kfree(TO_DCN20_DPP(*dpp)); + *dpp = NULL; +} + +static struct dpp *dcn31_dpp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn3_dpp *dpp = + kzalloc(sizeof(struct dcn3_dpp), GFP_KERNEL); + + if (!dpp) + return NULL; + + if (dpp3_construct(dpp, ctx, inst, + &dpp_regs[inst], &tf_shift, &tf_mask)) + return &dpp->base; + + BREAK_TO_DEBUGGER(); + kfree(dpp); + return NULL; +} + +static struct output_pixel_processor *dcn31_opp_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dcn20_opp *opp = + kzalloc(sizeof(struct dcn20_opp), GFP_KERNEL); + + if (!opp) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dcn20_opp_construct(opp, ctx, inst, + &opp_regs[inst], &opp_shift, &opp_mask); + return &opp->base; +} + +static struct dce_aux *dcn31_aux_engine_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct aux_engine_dce110 *aux_engine = + kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); + + if (!aux_engine) + return NULL; + + dce110_aux_engine_construct(aux_engine, ctx, inst, + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, + &aux_engine_regs[inst], + &aux_mask, + &aux_shift, + ctx->dc->caps.extended_aux_timeout_support); + + return &aux_engine->base; +} +#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST_DCN30(id) } + +static const struct dce_i2c_registers i2c_hw_regs[] = { + i2c_inst_regs(1), + i2c_inst_regs(2), + i2c_inst_regs(3), + i2c_inst_regs(4), + i2c_inst_regs(5), +}; + +static const struct dce_i2c_shift i2c_shifts = { + I2C_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dce_i2c_mask i2c_masks = { + I2C_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +/* ========================================================== */ + +/* + * DPIA index | Preferred Encoder | Host Router + * 0 | C | 0 + * 1 | First Available | 0 + * 2 | D | 1 + * 3 | First Available | 1 + */ +/* ========================================================== */ +static const enum engine_id dpia_to_preferred_enc_id_table[] = { + ENGINE_ID_DIGC, + ENGINE_ID_DIGC, + ENGINE_ID_DIGD, + ENGINE_ID_DIGD +}; + +static enum engine_id dcn314_get_preferred_eng_id_dpia(unsigned int dpia_index) +{ + return dpia_to_preferred_enc_id_table[dpia_index]; +} + +static struct dce_i2c_hw *dcn31_i2c_hw_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce_i2c_hw *dce_i2c_hw = + kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); + + if (!dce_i2c_hw) + return NULL; + + dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst, + &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); + + return dce_i2c_hw; +} +static struct mpc *dcn31_mpc_create( + struct dc_context *ctx, + int num_mpcc, + int num_rmu) +{ + struct dcn30_mpc *mpc30 = kzalloc(sizeof(struct dcn30_mpc), + GFP_KERNEL); + + if (!mpc30) + return NULL; + + dcn30_mpc_construct(mpc30, ctx, + &mpc_regs, + &mpc_shift, + &mpc_mask, + num_mpcc, + num_rmu); + + return &mpc30->base; +} + +static struct hubbub *dcn31_hubbub_create(struct dc_context *ctx) +{ + int i; + + struct dcn20_hubbub *hubbub3 = kzalloc(sizeof(struct dcn20_hubbub), + GFP_KERNEL); + + if (!hubbub3) + return NULL; + + hubbub31_construct(hubbub3, ctx, + &hubbub_reg, + &hubbub_shift, + &hubbub_mask, + dcn3_14_ip.det_buffer_size_kbytes, + dcn3_14_ip.pixel_chunk_size_kbytes, + dcn3_14_ip.config_return_buffer_size_in_kbytes); + + + for (i = 0; i < res_cap_dcn314.num_vmid; i++) { + struct dcn20_vmid *vmid = &hubbub3->vmid[i]; + + vmid->ctx = ctx; + + vmid->regs = &vmid_regs[i]; + vmid->shifts = &vmid_shifts; + vmid->masks = &vmid_masks; + } + + return &hubbub3->base; +} + +static struct timing_generator *dcn31_timing_generator_create( + struct dc_context *ctx, + uint32_t instance) +{ + struct optc *tgn10 = + kzalloc(sizeof(struct optc), GFP_KERNEL); + + if (!tgn10) + return NULL; + + tgn10->base.inst = instance; + tgn10->base.ctx = ctx; + + tgn10->tg_regs = &optc_regs[instance]; + tgn10->tg_shift = &optc_shift; + tgn10->tg_mask = &optc_mask; + + dcn314_timing_generator_init(tgn10); + + return &tgn10->base; +} + +static const struct encoder_feature_support link_enc_feature = { + .max_hdmi_deep_color = COLOR_DEPTH_121212, + .max_hdmi_pixel_clock = 600000, + .hdmi_ycbcr420_supported = true, + .dp_ycbcr420_supported = true, + .fec_supported = true, + .flags.bits.IS_HBR2_CAPABLE = true, + .flags.bits.IS_HBR3_CAPABLE = true, + .flags.bits.IS_TPS3_CAPABLE = true, + .flags.bits.IS_TPS4_CAPABLE = true +}; + +static struct link_encoder *dcn31_link_encoder_create( + struct dc_context *ctx, + const struct encoder_init_data *enc_init_data) +{ + struct dcn20_link_encoder *enc20 = + kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); + + if (!enc20) + return NULL; + + dcn31_link_encoder_construct(enc20, + enc_init_data, + &link_enc_feature, + &link_enc_regs[enc_init_data->transmitter], + &link_enc_aux_regs[enc_init_data->channel - 1], + &link_enc_hpd_regs[enc_init_data->hpd_source], + &le_shift, + &le_mask); + + return &enc20->enc10.base; +} + +/* Create a minimal link encoder object not associated with a particular + * physical connector. + * resource_funcs.link_enc_create_minimal + */ +static struct link_encoder *dcn31_link_enc_create_minimal( + struct dc_context *ctx, enum engine_id eng_id) +{ + struct dcn20_link_encoder *enc20; + + if ((eng_id - ENGINE_ID_DIGA) > ctx->dc->res_pool->res_cap->num_dig_link_enc) + return NULL; + + enc20 = kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); + if (!enc20) + return NULL; + + dcn31_link_encoder_construct_minimal( + enc20, + ctx, + &link_enc_feature, + &link_enc_regs[eng_id - ENGINE_ID_DIGA], + eng_id); + + return &enc20->enc10.base; +} + +static struct panel_cntl *dcn31_panel_cntl_create(const struct panel_cntl_init_data *init_data) +{ + struct dcn31_panel_cntl *panel_cntl = + kzalloc(sizeof(struct dcn31_panel_cntl), GFP_KERNEL); + + if (!panel_cntl) + return NULL; + + dcn31_panel_cntl_construct(panel_cntl, init_data); + + return &panel_cntl->base; +} + +static void read_dce_straps( + struct dc_context *ctx, + struct resource_straps *straps) +{ + generic_reg_get(ctx, regDC_PINSTRAPS + BASE(regDC_PINSTRAPS_BASE_IDX), + FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio); + +} + +static struct audio *dcn31_create_audio( + struct dc_context *ctx, unsigned int inst) +{ + return dce_audio_create(ctx, inst, + &audio_regs[inst], &audio_shift, &audio_mask); +} + +static struct vpg *dcn31_vpg_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn31_vpg *vpg31 = kzalloc(sizeof(struct dcn31_vpg), GFP_KERNEL); + + if (!vpg31) + return NULL; + + vpg31_construct(vpg31, ctx, inst, + &vpg_regs[inst], + &vpg_shift, + &vpg_mask); + + return &vpg31->base; +} + +static struct afmt *dcn31_afmt_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn31_afmt *afmt31 = kzalloc(sizeof(struct dcn31_afmt), GFP_KERNEL); + + if (!afmt31) + return NULL; + + afmt31_construct(afmt31, ctx, inst, + &afmt_regs[inst], + &afmt_shift, + &afmt_mask); + + // Light sleep by default, no need to power down here + + return &afmt31->base; +} + +static struct apg *dcn31_apg_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn31_apg *apg31 = kzalloc(sizeof(struct dcn31_apg), GFP_KERNEL); + + if (!apg31) + return NULL; + + apg31_construct(apg31, ctx, inst, + &apg_regs[inst], + &apg_shift, + &apg_mask); + + return &apg31->base; +} + +static struct stream_encoder *dcn314_stream_encoder_create( + enum engine_id eng_id, + struct dc_context *ctx) +{ + struct dcn10_stream_encoder *enc1; + struct vpg *vpg; + struct afmt *afmt; + int vpg_inst; + int afmt_inst; + + /* Mapping of VPG, AFMT, DME register blocks to DIO block instance */ + if (eng_id < ENGINE_ID_DIGF) { + vpg_inst = eng_id; + afmt_inst = eng_id; + } else + return NULL; + + enc1 = kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL); + vpg = dcn31_vpg_create(ctx, vpg_inst); + afmt = dcn31_afmt_create(ctx, afmt_inst); + + if (!enc1 || !vpg || !afmt) { + kfree(enc1); + kfree(vpg); + kfree(afmt); + return NULL; + } + + dcn314_dio_stream_encoder_construct(enc1, ctx, ctx->dc_bios, + eng_id, vpg, afmt, + &stream_enc_regs[eng_id], + &se_shift, &se_mask); + + return &enc1->base; +} + +static struct hpo_dp_stream_encoder *dcn31_hpo_dp_stream_encoder_create( + enum engine_id eng_id, + struct dc_context *ctx) +{ + struct dcn31_hpo_dp_stream_encoder *hpo_dp_enc31; + struct vpg *vpg; + struct apg *apg; + uint32_t hpo_dp_inst; + uint32_t vpg_inst; + uint32_t apg_inst; + + ASSERT((eng_id >= ENGINE_ID_HPO_DP_0) && (eng_id <= ENGINE_ID_HPO_DP_3)); + hpo_dp_inst = eng_id - ENGINE_ID_HPO_DP_0; + + /* Mapping of VPG register blocks to HPO DP block instance: + * VPG[6] -> HPO_DP[0] + * VPG[7] -> HPO_DP[1] + * VPG[8] -> HPO_DP[2] + * VPG[9] -> HPO_DP[3] + */ + //Uses offset index 5-8, but actually maps to vpg_inst 6-9 + vpg_inst = hpo_dp_inst + 5; + + /* Mapping of APG register blocks to HPO DP block instance: + * APG[0] -> HPO_DP[0] + * APG[1] -> HPO_DP[1] + * APG[2] -> HPO_DP[2] + * APG[3] -> HPO_DP[3] + */ + apg_inst = hpo_dp_inst; + + /* allocate HPO stream encoder and create VPG sub-block */ + hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_stream_encoder), GFP_KERNEL); + vpg = dcn31_vpg_create(ctx, vpg_inst); + apg = dcn31_apg_create(ctx, apg_inst); + + if (!hpo_dp_enc31 || !vpg || !apg) { + kfree(hpo_dp_enc31); + kfree(vpg); + kfree(apg); + return NULL; + } + + dcn31_hpo_dp_stream_encoder_construct(hpo_dp_enc31, ctx, ctx->dc_bios, + hpo_dp_inst, eng_id, vpg, apg, + &hpo_dp_stream_enc_regs[hpo_dp_inst], + &hpo_dp_se_shift, &hpo_dp_se_mask); + + return &hpo_dp_enc31->base; +} + +static struct hpo_dp_link_encoder *dcn31_hpo_dp_link_encoder_create( + uint8_t inst, + struct dc_context *ctx) +{ + struct dcn31_hpo_dp_link_encoder *hpo_dp_enc31; + + /* allocate HPO link encoder */ + hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_link_encoder), GFP_KERNEL); + + hpo_dp_link_encoder31_construct(hpo_dp_enc31, ctx, inst, + &hpo_dp_link_enc_regs[inst], + &hpo_dp_le_shift, &hpo_dp_le_mask); + + return &hpo_dp_enc31->base; +} + +static struct dce_hwseq *dcn314_hwseq_create( + struct dc_context *ctx) +{ + struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); + + if (hws) { + hws->ctx = ctx; + hws->regs = &hwseq_reg; + hws->shifts = &hwseq_shift; + hws->masks = &hwseq_mask; + } + return hws; +} +static const struct resource_create_funcs res_create_funcs = { + .read_dce_straps = read_dce_straps, + .create_audio = dcn31_create_audio, + .create_stream_encoder = dcn314_stream_encoder_create, + .create_hpo_dp_stream_encoder = dcn31_hpo_dp_stream_encoder_create, + .create_hpo_dp_link_encoder = dcn31_hpo_dp_link_encoder_create, + .create_hwseq = dcn314_hwseq_create, +}; + +static void dcn314_resource_destruct(struct dcn314_resource_pool *pool) +{ + unsigned int i; + + for (i = 0; i < pool->base.stream_enc_count; i++) { + if (pool->base.stream_enc[i] != NULL) { + if (pool->base.stream_enc[i]->vpg != NULL) { + kfree(DCN30_VPG_FROM_VPG(pool->base.stream_enc[i]->vpg)); + pool->base.stream_enc[i]->vpg = NULL; + } + if (pool->base.stream_enc[i]->afmt != NULL) { + kfree(DCN30_AFMT_FROM_AFMT(pool->base.stream_enc[i]->afmt)); + pool->base.stream_enc[i]->afmt = NULL; + } + kfree(DCN10STRENC_FROM_STRENC(pool->base.stream_enc[i])); + pool->base.stream_enc[i] = NULL; + } + } + + for (i = 0; i < pool->base.hpo_dp_stream_enc_count; i++) { + if (pool->base.hpo_dp_stream_enc[i] != NULL) { + if (pool->base.hpo_dp_stream_enc[i]->vpg != NULL) { + kfree(DCN30_VPG_FROM_VPG(pool->base.hpo_dp_stream_enc[i]->vpg)); + pool->base.hpo_dp_stream_enc[i]->vpg = NULL; + } + if (pool->base.hpo_dp_stream_enc[i]->apg != NULL) { + kfree(DCN31_APG_FROM_APG(pool->base.hpo_dp_stream_enc[i]->apg)); + pool->base.hpo_dp_stream_enc[i]->apg = NULL; + } + kfree(DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(pool->base.hpo_dp_stream_enc[i])); + pool->base.hpo_dp_stream_enc[i] = NULL; + } + } + + for (i = 0; i < pool->base.hpo_dp_link_enc_count; i++) { + if (pool->base.hpo_dp_link_enc[i] != NULL) { + kfree(DCN3_1_HPO_DP_LINK_ENC_FROM_HPO_LINK_ENC(pool->base.hpo_dp_link_enc[i])); + pool->base.hpo_dp_link_enc[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_dsc; i++) { + if (pool->base.dscs[i] != NULL) + dcn20_dsc_destroy(&pool->base.dscs[i]); + } + + if (pool->base.mpc != NULL) { + kfree(TO_DCN20_MPC(pool->base.mpc)); + pool->base.mpc = NULL; + } + if (pool->base.hubbub != NULL) { + kfree(pool->base.hubbub); + pool->base.hubbub = NULL; + } + for (i = 0; i < pool->base.pipe_count; i++) { + if (pool->base.dpps[i] != NULL) + dcn31_dpp_destroy(&pool->base.dpps[i]); + + if (pool->base.ipps[i] != NULL) + pool->base.ipps[i]->funcs->ipp_destroy(&pool->base.ipps[i]); + + if (pool->base.hubps[i] != NULL) { + kfree(TO_DCN20_HUBP(pool->base.hubps[i])); + pool->base.hubps[i] = NULL; + } + + if (pool->base.irqs != NULL) + dal_irq_service_destroy(&pool->base.irqs); + } + + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + if (pool->base.engines[i] != NULL) + dce110_engine_destroy(&pool->base.engines[i]); + if (pool->base.hw_i2cs[i] != NULL) { + kfree(pool->base.hw_i2cs[i]); + pool->base.hw_i2cs[i] = NULL; + } + if (pool->base.sw_i2cs[i] != NULL) { + kfree(pool->base.sw_i2cs[i]); + pool->base.sw_i2cs[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_opp; i++) { + if (pool->base.opps[i] != NULL) + pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]); + } + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + if (pool->base.timing_generators[i] != NULL) { + kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i])); + pool->base.timing_generators[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_dwb; i++) { + if (pool->base.dwbc[i] != NULL) { + kfree(TO_DCN30_DWBC(pool->base.dwbc[i])); + pool->base.dwbc[i] = NULL; + } + if (pool->base.mcif_wb[i] != NULL) { + kfree(TO_DCN30_MMHUBBUB(pool->base.mcif_wb[i])); + pool->base.mcif_wb[i] = NULL; + } + } + + for (i = 0; i < pool->base.audio_count; i++) { + if (pool->base.audios[i]) + dce_aud_destroy(&pool->base.audios[i]); + } + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] != NULL) { + dcn20_clock_source_destroy(&pool->base.clock_sources[i]); + pool->base.clock_sources[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_mpc_3dlut; i++) { + if (pool->base.mpc_lut[i] != NULL) { + dc_3dlut_func_release(pool->base.mpc_lut[i]); + pool->base.mpc_lut[i] = NULL; + } + if (pool->base.mpc_shaper[i] != NULL) { + dc_transfer_func_release(pool->base.mpc_shaper[i]); + pool->base.mpc_shaper[i] = NULL; + } + } + + if (pool->base.dp_clock_source != NULL) { + dcn20_clock_source_destroy(&pool->base.dp_clock_source); + pool->base.dp_clock_source = NULL; + } + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + if (pool->base.multiple_abms[i] != NULL) + dce_abm_destroy(&pool->base.multiple_abms[i]); + } + + if (pool->base.psr != NULL) + dmub_psr_destroy(&pool->base.psr); + + if (pool->base.replay != NULL) + dmub_replay_destroy(&pool->base.replay); + + if (pool->base.dccg != NULL) + dcn_dccg_destroy(&pool->base.dccg); +} + +static struct hubp *dcn31_hubp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn20_hubp *hubp2 = + kzalloc(sizeof(struct dcn20_hubp), GFP_KERNEL); + + if (!hubp2) + return NULL; + + if (hubp31_construct(hubp2, ctx, inst, + &hubp_regs[inst], &hubp_shift, &hubp_mask)) + return &hubp2->base; + + BREAK_TO_DEBUGGER(); + kfree(hubp2); + return NULL; +} + +static bool dcn31_dwbc_create(struct dc_context *ctx, struct resource_pool *pool) +{ + int i; + uint32_t pipe_count = pool->res_cap->num_dwb; + + for (i = 0; i < pipe_count; i++) { + struct dcn30_dwbc *dwbc30 = kzalloc(sizeof(struct dcn30_dwbc), + GFP_KERNEL); + + if (!dwbc30) { + dm_error("DC: failed to create dwbc30!\n"); + return false; + } + + dcn30_dwbc_construct(dwbc30, ctx, + &dwbc30_regs[i], + &dwbc30_shift, + &dwbc30_mask, + i); + + pool->dwbc[i] = &dwbc30->base; + } + return true; +} + +static bool dcn31_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool) +{ + int i; + uint32_t pipe_count = pool->res_cap->num_dwb; + + for (i = 0; i < pipe_count; i++) { + struct dcn30_mmhubbub *mcif_wb30 = kzalloc(sizeof(struct dcn30_mmhubbub), + GFP_KERNEL); + + if (!mcif_wb30) { + dm_error("DC: failed to create mcif_wb30!\n"); + return false; + } + + dcn30_mmhubbub_construct(mcif_wb30, ctx, + &mcif_wb30_regs[i], + &mcif_wb30_shift, + &mcif_wb30_mask, + i); + + pool->mcif_wb[i] = &mcif_wb30->base; + } + return true; +} + +static struct display_stream_compressor *dcn314_dsc_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dcn20_dsc *dsc = + kzalloc(sizeof(struct dcn20_dsc), GFP_KERNEL); + + if (!dsc) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dsc2_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask); + return &dsc->base; +} + +static void dcn314_destroy_resource_pool(struct resource_pool **pool) +{ + struct dcn314_resource_pool *dcn314_pool = TO_DCN314_RES_POOL(*pool); + + dcn314_resource_destruct(dcn314_pool); + kfree(dcn314_pool); + *pool = NULL; +} + +static struct clock_source *dcn31_clock_source_create( + struct dc_context *ctx, + struct dc_bios *bios, + enum clock_source_id id, + const struct dce110_clk_src_regs *regs, + bool dp_clk_src) +{ + struct dce110_clk_src *clk_src = + kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); + + if (!clk_src) + return NULL; + + if (dcn31_clk_src_construct(clk_src, ctx, bios, id, + regs, &cs_shift, &cs_mask)) { + clk_src->base.dp_clk_src = dp_clk_src; + return &clk_src->base; + } + + BREAK_TO_DEBUGGER(); + kfree(clk_src); + return NULL; +} + +static int dcn314_populate_dml_pipes_from_context( + struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes, + bool fast_validate) +{ + int pipe_cnt; + + DC_FP_START(); + pipe_cnt = dcn314_populate_dml_pipes_from_context_fpu(dc, context, pipes, fast_validate); + DC_FP_END(); + + return pipe_cnt; +} + +static struct dc_cap_funcs cap_funcs = { + .get_dcc_compression_cap = dcn20_get_dcc_compression_cap +}; + +static void dcn314_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) +{ + DC_FP_START(); + dcn314_update_bw_bounding_box_fpu(dc, bw_params); + DC_FP_END(); +} + +static void dcn314_get_panel_config_defaults(struct dc_panel_config *panel_config) +{ + *panel_config = panel_config_defaults; +} + +static bool filter_modes_for_single_channel_workaround(struct dc *dc, + struct dc_state *context) +{ + // Filter 2K@240Hz+8K@24fps above combination timing if memory only has single dimm LPDDR + if (dc->clk_mgr->bw_params->vram_type == 34 && + dc->clk_mgr->bw_params->num_channels < 2 && + context->stream_count > 1) { + int total_phy_pix_clk = 0; + + for (int i = 0; i < context->stream_count; i++) + if (context->res_ctx.pipe_ctx[i].stream) + total_phy_pix_clk += context->res_ctx.pipe_ctx[i].stream->phy_pix_clk; + + if (total_phy_pix_clk >= (1148928+826260)) //2K@240Hz+8K@24fps + return true; + } + return false; +} + +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(); + + if (filter_modes_for_single_channel_workaround(dc, context)) + goto validate_fail; + + 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; + } + if (dc->res_pool->funcs->calculate_wm_and_dlg) + 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, + .link_enc_create_minimal = dcn31_link_enc_create_minimal, + .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 = 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, + .acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer, + .release_pipe = dcn20_release_pipe, + .add_stream_to_ctx = dcn30_add_stream_to_ctx, + .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource, + .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, + .populate_dml_writeback_from_context = dcn30_populate_dml_writeback_from_context, + .set_mcif_arb_params = dcn30_set_mcif_arb_params, + .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 = dcn314_update_bw_bounding_box, + .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, + .get_panel_config_defaults = dcn314_get_panel_config_defaults, + .get_preferred_eng_id_dpia = dcn314_get_preferred_eng_id_dpia, +}; + +static struct clock_source *dcn30_clock_source_create( + struct dc_context *ctx, + struct dc_bios *bios, + enum clock_source_id id, + const struct dce110_clk_src_regs *regs, + bool dp_clk_src) +{ + struct dce110_clk_src *clk_src = + kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); + + if (!clk_src) + return NULL; + + if (dcn31_clk_src_construct(clk_src, ctx, bios, id, + regs, &cs_shift, &cs_mask)) { + clk_src->base.dp_clk_src = dp_clk_src; + return &clk_src->base; + } + + BREAK_TO_DEBUGGER(); + kfree(clk_src); + return NULL; +} + +static bool dcn314_resource_construct( + uint8_t num_virtual_links, + struct dc *dc, + struct dcn314_resource_pool *pool) +{ + int i; + struct dc_context *ctx = dc->ctx; + struct irq_service_init_data init_data; + + ctx->dc_bios->regs = &bios_regs; + + pool->base.res_cap = &res_cap_dcn314; + pool->base.funcs = &dcn314_res_pool_funcs; + + /************************************************* + * Resource + asic cap harcoding * + *************************************************/ + pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.pipe_count = pool->base.res_cap->num_timing_generator; + pool->base.mpcc_count = pool->base.res_cap->num_timing_generator; + dc->caps.max_downscale_ratio = 400; + dc->caps.i2c_speed_in_khz = 100; + dc->caps.i2c_speed_in_khz_hdcp = 100; + dc->caps.max_cursor_size = 256; + dc->caps.min_horizontal_blanking_period = 80; + dc->caps.dmdata_alloc_size = 2048; + dc->caps.max_slave_planes = 2; + dc->caps.max_slave_yuv_planes = 2; + dc->caps.max_slave_rgb_planes = 2; + dc->caps.post_blend_color_processing = true; + dc->caps.force_dp_tps4_for_cp2520 = true; + if (dc->config.forceHBR2CP2520) + dc->caps.force_dp_tps4_for_cp2520 = false; + dc->caps.dp_hpo = true; + dc->caps.dp_hdmi21_pcon_support = true; + dc->caps.edp_dsc_support = true; + dc->caps.extended_aux_timeout_support = true; + dc->caps.dmcub_support = true; + dc->caps.is_apu = true; + dc->caps.seamless_odm = true; + + dc->caps.zstate_support = true; + + /* Color pipeline capabilities */ + dc->caps.color.dpp.dcn_arch = 1; + dc->caps.color.dpp.input_lut_shared = 0; + dc->caps.color.dpp.icsc = 1; + dc->caps.color.dpp.dgam_ram = 0; // must use gamma_corr + dc->caps.color.dpp.dgam_rom_caps.srgb = 1; + dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1; + dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 1; + dc->caps.color.dpp.dgam_rom_caps.pq = 1; + dc->caps.color.dpp.dgam_rom_caps.hlg = 1; + dc->caps.color.dpp.post_csc = 1; + dc->caps.color.dpp.gamma_corr = 1; + dc->caps.color.dpp.dgam_rom_for_yuv = 0; + + dc->caps.color.dpp.hw_3d_lut = 1; + dc->caps.color.dpp.ogam_ram = 1; + // no OGAM ROM on DCN301 + dc->caps.color.dpp.ogam_rom_caps.srgb = 0; + dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0; + dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0; + dc->caps.color.dpp.ogam_rom_caps.pq = 0; + dc->caps.color.dpp.ogam_rom_caps.hlg = 0; + dc->caps.color.dpp.ocsc = 0; + + dc->caps.color.mpc.gamut_remap = 1; + dc->caps.color.mpc.num_3dluts = pool->base.res_cap->num_mpc_3dlut; //2 + dc->caps.color.mpc.ogam_ram = 1; + dc->caps.color.mpc.ogam_rom_caps.srgb = 0; + dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0; + dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0; + dc->caps.color.mpc.ogam_rom_caps.pq = 0; + dc->caps.color.mpc.ogam_rom_caps.hlg = 0; + dc->caps.color.mpc.ocsc = 1; + + dc->caps.max_disp_clock_khz_at_vmin = 650000; + + /* Use pipe context based otg sync logic */ + dc->config.use_pipe_ctx_sync_logic = true; + + /* read VBIOS LTTPR caps */ + { + if (ctx->dc_bios->funcs->get_lttpr_caps) { + enum bp_result bp_query_result; + uint8_t is_vbios_lttpr_enable = 0; + + bp_query_result = ctx->dc_bios->funcs->get_lttpr_caps(ctx->dc_bios, &is_vbios_lttpr_enable); + dc->caps.vbios_lttpr_enable = (bp_query_result == BP_RESULT_OK) && !!is_vbios_lttpr_enable; + } + + /* interop bit is implicit */ + { + dc->caps.vbios_lttpr_aware = true; + } + } + + if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) + dc->debug = debug_defaults_drv; + else + dc->debug = debug_defaults_diags; + + /* Disable pipe power gating */ + dc->debug.disable_dpp_power_gate = true; + dc->debug.disable_hubp_power_gate = true; + + /* Disable root clock optimization */ + dc->debug.root_clock_optimization.u32All = 0; + + // Init the vm_helper + if (dc->vm_helper) + vm_helper_init(dc->vm_helper, 16); + + /************************************************* + * Create resources * + *************************************************/ + + /* Clock Sources for Pixel Clock*/ + pool->base.clock_sources[DCN31_CLK_SRC_PLL0] = + dcn30_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL0, + &clk_src_regs[0], false); + pool->base.clock_sources[DCN31_CLK_SRC_PLL1] = + dcn30_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL1, + &clk_src_regs[1], false); + pool->base.clock_sources[DCN31_CLK_SRC_PLL2] = + dcn30_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL2, + &clk_src_regs[2], false); + pool->base.clock_sources[DCN31_CLK_SRC_PLL3] = + dcn30_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL3, + &clk_src_regs[3], false); + pool->base.clock_sources[DCN31_CLK_SRC_PLL4] = + dcn30_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL4, + &clk_src_regs[4], false); + + pool->base.clk_src_count = DCN30_CLK_SRC_TOTAL; + + /* todo: not reuse phy_pll registers */ + pool->base.dp_clock_source = + dcn31_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_ID_DP_DTO, + &clk_src_regs[0], true); + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] == NULL) { + dm_error("DC: failed to create clock sources!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + } + + pool->base.dccg = dccg314_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask); + if (pool->base.dccg == NULL) { + dm_error("DC: failed to create dccg!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + init_data.ctx = dc->ctx; + pool->base.irqs = dal_irq_service_dcn314_create(&init_data); + if (!pool->base.irqs) + goto create_fail; + + /* HUBBUB */ + pool->base.hubbub = dcn31_hubbub_create(ctx); + if (pool->base.hubbub == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create hubbub!\n"); + goto create_fail; + } + + /* HUBPs, DPPs, OPPs and TGs */ + for (i = 0; i < pool->base.pipe_count; i++) { + pool->base.hubps[i] = dcn31_hubp_create(ctx, i); + if (pool->base.hubps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create hubps!\n"); + goto create_fail; + } + + pool->base.dpps[i] = dcn31_dpp_create(ctx, i); + if (pool->base.dpps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create dpps!\n"); + goto create_fail; + } + } + + for (i = 0; i < pool->base.res_cap->num_opp; i++) { + pool->base.opps[i] = dcn31_opp_create(ctx, i); + if (pool->base.opps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create output pixel processor!\n"); + goto create_fail; + } + } + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + pool->base.timing_generators[i] = dcn31_timing_generator_create( + ctx, i); + if (pool->base.timing_generators[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create tg!\n"); + goto create_fail; + } + } + pool->base.timing_generator_count = i; + + /* PSR */ + pool->base.psr = dmub_psr_create(ctx); + if (pool->base.psr == NULL) { + dm_error("DC: failed to create psr obj!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + /* Replay */ + pool->base.replay = dmub_replay_create(ctx); + if (pool->base.replay == NULL) { + dm_error("DC: failed to create replay obj!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + /* ABM */ + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + pool->base.multiple_abms[i] = dmub_abm_create(ctx, + &abm_regs[i], + &abm_shift, + &abm_mask); + if (pool->base.multiple_abms[i] == NULL) { + dm_error("DC: failed to create abm for pipe %d!\n", i); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + } + + /* MPC and DSC */ + pool->base.mpc = dcn31_mpc_create(ctx, pool->base.mpcc_count, pool->base.res_cap->num_mpc_3dlut); + if (pool->base.mpc == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create mpc!\n"); + goto create_fail; + } + + for (i = 0; i < pool->base.res_cap->num_dsc; i++) { + pool->base.dscs[i] = dcn314_dsc_create(ctx, i); + if (pool->base.dscs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create display stream compressor %d!\n", i); + goto create_fail; + } + } + + /* DWB and MMHUBBUB */ + if (!dcn31_dwbc_create(ctx, &pool->base)) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dwbc!\n"); + goto create_fail; + } + + if (!dcn31_mmhubbub_create(ctx, &pool->base)) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create mcif_wb!\n"); + goto create_fail; + } + + /* AUX and I2C */ + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + pool->base.engines[i] = dcn31_aux_engine_create(ctx, i); + if (pool->base.engines[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create aux engine!!\n"); + goto create_fail; + } + pool->base.hw_i2cs[i] = dcn31_i2c_hw_create(ctx, i); + if (pool->base.hw_i2cs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create hw i2c!!\n"); + goto create_fail; + } + pool->base.sw_i2cs[i] = NULL; + } + + /* DCN314 has 4 DPIA */ + pool->base.usb4_dpia_count = 4; + + /* Audio, Stream Encoders including HPO and virtual, MPC 3D LUTs */ + if (!resource_construct(num_virtual_links, dc, &pool->base, + &res_create_funcs)) + goto create_fail; + + /* HW Sequencer and Plane caps */ + dcn314_hw_sequencer_construct(dc); + + dc->caps.max_planes = pool->base.pipe_count; + + for (i = 0; i < dc->caps.max_planes; ++i) + dc->caps.planes[i] = plane_cap; + + dc->cap_funcs = cap_funcs; + + dc->dcn_ip->max_num_dpp = dcn3_14_ip.max_num_dpp; + + return true; + +create_fail: + + dcn314_resource_destruct(pool); + + return false; +} + +struct resource_pool *dcn314_create_resource_pool( + const struct dc_init_data *init_data, + struct dc *dc) +{ + struct dcn314_resource_pool *pool = + kzalloc(sizeof(struct dcn314_resource_pool), GFP_KERNEL); + + if (!pool) + return NULL; + + if (dcn314_resource_construct(init_data->num_virtual_links, dc, pool)) + return &pool->base; + + BREAK_TO_DEBUGGER(); + kfree(pool); + return NULL; +} diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.h new file mode 100644 index 00000000000000..49ffe71018dfb9 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: MIT */ +/* + * 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 _DCN314_RESOURCE_H_ +#define _DCN314_RESOURCE_H_ + +#include "core_types.h" + +extern struct _vcs_dpi_ip_params_st dcn3_14_ip; +extern struct _vcs_dpi_soc_bounding_box_st dcn3_14_soc; + +#define TO_DCN314_RES_POOL(pool)\ + container_of(pool, struct dcn314_resource_pool, base) + +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); + +#endif /* _DCN314_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c new file mode 100644 index 00000000000000..515ba435f759c8 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c @@ -0,0 +1,2153 @@ +/* + * 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 "dm_services.h" +#include "dc.h" + +#include "dcn31/dcn31_init.h" + +#include "resource.h" +#include "include/irq_service_interface.h" +#include "dcn315_resource.h" + +#include "dcn20/dcn20_resource.h" +#include "dcn30/dcn30_resource.h" +#include "dcn31/dcn31_resource.h" + +#include "dcn10/dcn10_ipp.h" +#include "dcn30/dcn30_hubbub.h" +#include "dcn31/dcn31_hubbub.h" +#include "dcn30/dcn30_mpc.h" +#include "dcn31/dcn31_hubp.h" +#include "irq/dcn315/irq_service_dcn315.h" +#include "dcn30/dcn30_dpp.h" +#include "dcn31/dcn31_optc.h" +#include "dcn20/dcn20_hwseq.h" +#include "dcn30/dcn30_hwseq.h" +#include "dce110/dce110_hwseq.h" +#include "dcn30/dcn30_opp.h" +#include "dcn20/dcn20_dsc.h" +#include "dcn30/dcn30_vpg.h" +#include "dcn30/dcn30_afmt.h" +#include "dcn30/dcn30_dio_stream_encoder.h" +#include "dcn31/dcn31_hpo_dp_stream_encoder.h" +#include "dcn31/dcn31_hpo_dp_link_encoder.h" +#include "dcn31/dcn31_apg.h" +#include "dcn31/dcn31_dio_link_encoder.h" +#include "dcn31/dcn31_vpg.h" +#include "dcn31/dcn31_afmt.h" +#include "dce/dce_clock_source.h" +#include "dce/dce_audio.h" +#include "dce/dce_hwseq.h" +#include "clk_mgr.h" +#include "virtual/virtual_stream_encoder.h" +#include "dce110/dce110_resource.h" +#include "dml/display_mode_vba.h" +#include "dml/dcn31/dcn31_fpu.h" +#include "dcn31/dcn31_dccg.h" +#include "dcn10/dcn10_resource.h" +#include "dcn31/dcn31_panel_cntl.h" + +#include "dcn30/dcn30_dwb.h" +#include "dcn30/dcn30_mmhubbub.h" + +#include "dcn/dcn_3_1_5_offset.h" +#include "dcn/dcn_3_1_5_sh_mask.h" +#include "dpcs/dpcs_4_2_2_offset.h" +#include "dpcs/dpcs_4_2_2_sh_mask.h" + +#define NBIO_BASE__INST0_SEG0 0x00000000 +#define NBIO_BASE__INST0_SEG1 0x00000014 +#define NBIO_BASE__INST0_SEG2 0x00000D20 +#define NBIO_BASE__INST0_SEG3 0x00010400 +#define NBIO_BASE__INST0_SEG4 0x0241B000 +#define NBIO_BASE__INST0_SEG5 0x04040000 + +#define DPCS_BASE__INST0_SEG0 0x00000012 +#define DPCS_BASE__INST0_SEG1 0x000000C0 +#define DPCS_BASE__INST0_SEG2 0x000034C0 +#define DPCS_BASE__INST0_SEG3 0x00009000 +#define DPCS_BASE__INST0_SEG4 0x02403C00 +#define DPCS_BASE__INST0_SEG5 0 + +#define DCN_BASE__INST0_SEG0 0x00000012 +#define DCN_BASE__INST0_SEG1 0x000000C0 +#define DCN_BASE__INST0_SEG2 0x000034C0 +#define DCN_BASE__INST0_SEG3 0x00009000 +#define DCN_BASE__INST0_SEG4 0x02403C00 +#define DCN_BASE__INST0_SEG5 0 + +#define regBIF_BX_PF2_RSMU_INDEX 0x0000 +#define regBIF_BX_PF2_RSMU_INDEX_BASE_IDX 1 +#define regBIF_BX_PF2_RSMU_DATA 0x0001 +#define regBIF_BX_PF2_RSMU_DATA_BASE_IDX 1 +#define regBIF_BX2_BIOS_SCRATCH_6 0x003e +#define regBIF_BX2_BIOS_SCRATCH_6_BASE_IDX 1 +#define BIF_BX2_BIOS_SCRATCH_6__BIOS_SCRATCH_6__SHIFT 0x0 +#define BIF_BX2_BIOS_SCRATCH_6__BIOS_SCRATCH_6_MASK 0xFFFFFFFFL +#define regBIF_BX2_BIOS_SCRATCH_2 0x003a +#define regBIF_BX2_BIOS_SCRATCH_2_BASE_IDX 1 +#define BIF_BX2_BIOS_SCRATCH_2__BIOS_SCRATCH_2__SHIFT 0x0 +#define BIF_BX2_BIOS_SCRATCH_2__BIOS_SCRATCH_2_MASK 0xFFFFFFFFL +#define regBIF_BX2_BIOS_SCRATCH_3 0x003b +#define regBIF_BX2_BIOS_SCRATCH_3_BASE_IDX 1 +#define BIF_BX2_BIOS_SCRATCH_3__BIOS_SCRATCH_3__SHIFT 0x0 +#define BIF_BX2_BIOS_SCRATCH_3__BIOS_SCRATCH_3_MASK 0xFFFFFFFFL + +#define regDCHUBBUB_DEBUG_CTRL_0 0x04d6 +#define regDCHUBBUB_DEBUG_CTRL_0_BASE_IDX 2 +#define DCHUBBUB_DEBUG_CTRL_0__DET_DEPTH__SHIFT 0x10 +#define DCHUBBUB_DEBUG_CTRL_0__DET_DEPTH_MASK 0x01FF0000L + +#include "reg_helper.h" +#include "dce/dmub_abm.h" +#include "dce/dmub_psr.h" +#include "dce/dce_aux.h" +#include "dce/dce_i2c.h" + +#include "dml/dcn30/display_mode_vba_30.h" +#include "vm_helper.h" +#include "dcn20/dcn20_vmid.h" + +#include "link_enc_cfg.h" + +#define DCN3_15_MAX_DET_SIZE 384 +#define DCN3_15_CRB_SEGMENT_SIZE_KB 64 +#define DCN3_15_MAX_DET_SEGS (DCN3_15_MAX_DET_SIZE / DCN3_15_CRB_SEGMENT_SIZE_KB) +/* Minimum 3 extra segments need to be in compbuf and claimable to guarantee seamless mpo transitions */ +#define MIN_RESERVED_DET_SEGS 3 + +enum dcn31_clk_src_array_id { + DCN31_CLK_SRC_PLL0, + DCN31_CLK_SRC_PLL1, + DCN31_CLK_SRC_PLL2, + DCN31_CLK_SRC_PLL3, + DCN31_CLK_SRC_PLL4, + DCN30_CLK_SRC_TOTAL +}; + +/* begin ********************* + * macros to expend register list macro defined in HW object header file + */ + +/* DCN */ +#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg + +#define BASE(seg) BASE_INNER(seg) + +#define SR(reg_name)\ + .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ + reg ## reg_name + +#define SRI(reg_name, block, id)\ + .reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRI2(reg_name, block, id)\ + .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ + reg ## reg_name + +#define SRIR(var_name, reg_name, block, id)\ + .var_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRII(reg_name, block, id)\ + .reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRII_MPC_RMU(reg_name, block, id)\ + .RMU##_##reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRII_DWB(reg_name, temp_name, block, id)\ + .reg_name[id] = BASE(reg ## block ## id ## _ ## temp_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## temp_name + +#define SF_DWB2(reg_name, block, id, field_name, post_fix) \ + .field_name = reg_name ## __ ## field_name ## post_fix + +#define DCCG_SRII(reg_name, block, id)\ + .block ## _ ## reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define VUPDATE_SRII(reg_name, block, id)\ + .reg_name[id] = BASE(reg ## reg_name ## _ ## block ## id ## _BASE_IDX) + \ + reg ## reg_name ## _ ## block ## id + +/* NBIO */ +#define NBIO_BASE_INNER(seg) \ + NBIO_BASE__INST0_SEG ## seg + +#define NBIO_BASE(seg) \ + NBIO_BASE_INNER(seg) + +#define NBIO_SR(reg_name)\ + .reg_name = NBIO_BASE(regBIF_BX2_ ## reg_name ## _BASE_IDX) + \ + regBIF_BX2_ ## reg_name + +static const struct bios_registers bios_regs = { + NBIO_SR(BIOS_SCRATCH_3), + NBIO_SR(BIOS_SCRATCH_6) +}; + +#define clk_src_regs(index, pllid)\ +[index] = {\ + CS_COMMON_REG_LIST_DCN3_0(index, pllid),\ +} + +static const struct dce110_clk_src_regs clk_src_regs[] = { + clk_src_regs(0, A), + clk_src_regs(1, B), + clk_src_regs(2, C), + clk_src_regs(3, D), + clk_src_regs(4, E) +}; + +static const struct dce110_clk_src_shift cs_shift = { + CS_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) +}; + +static const struct dce110_clk_src_mask cs_mask = { + CS_COMMON_MASK_SH_LIST_DCN2_0(_MASK) +}; + +#define abm_regs(id)\ +[id] = {\ + ABM_DCN302_REG_LIST(id)\ +} + +static const struct dce_abm_registers abm_regs[] = { + abm_regs(0), + abm_regs(1), + abm_regs(2), + abm_regs(3), +}; + +static const struct dce_abm_shift abm_shift = { + ABM_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dce_abm_mask abm_mask = { + ABM_MASK_SH_LIST_DCN30(_MASK) +}; + +#define audio_regs(id)\ +[id] = {\ + AUD_COMMON_REG_LIST(id)\ +} + +static const struct dce_audio_registers audio_regs[] = { + audio_regs(0), + audio_regs(1), + audio_regs(2), + audio_regs(3), + audio_regs(4), + audio_regs(5), + audio_regs(6) +}; + +#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ + AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) + +static const struct dce_audio_shift audio_shift = { + DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_audio_mask audio_mask = { + DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) +}; + +#define vpg_regs(id)\ +[id] = {\ + VPG_DCN31_REG_LIST(id)\ +} + +static const struct dcn31_vpg_registers vpg_regs[] = { + vpg_regs(0), + vpg_regs(1), + vpg_regs(2), + vpg_regs(3), + vpg_regs(4), + vpg_regs(5), + vpg_regs(6), + vpg_regs(7), + vpg_regs(8), + vpg_regs(9), +}; + +static const struct dcn31_vpg_shift vpg_shift = { + DCN31_VPG_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn31_vpg_mask vpg_mask = { + DCN31_VPG_MASK_SH_LIST(_MASK) +}; + +#define afmt_regs(id)\ +[id] = {\ + AFMT_DCN31_REG_LIST(id)\ +} + +static const struct dcn31_afmt_registers afmt_regs[] = { + afmt_regs(0), + afmt_regs(1), + afmt_regs(2), + afmt_regs(3), + afmt_regs(4), + afmt_regs(5) +}; + +static const struct dcn31_afmt_shift afmt_shift = { + DCN31_AFMT_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn31_afmt_mask afmt_mask = { + DCN31_AFMT_MASK_SH_LIST(_MASK) +}; + +#define apg_regs(id)\ +[id] = {\ + APG_DCN31_REG_LIST(id)\ +} + +static const struct dcn31_apg_registers apg_regs[] = { + apg_regs(0), + apg_regs(1), + apg_regs(2), + apg_regs(3) +}; + +static const struct dcn31_apg_shift apg_shift = { + DCN31_APG_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn31_apg_mask apg_mask = { + DCN31_APG_MASK_SH_LIST(_MASK) +}; + +#define stream_enc_regs(id)\ +[id] = {\ + SE_DCN3_REG_LIST(id)\ +} + +static const struct dcn10_stream_enc_registers stream_enc_regs[] = { + stream_enc_regs(0), + stream_enc_regs(1), + stream_enc_regs(2), + stream_enc_regs(3), + stream_enc_regs(4) +}; + +static const struct dcn10_stream_encoder_shift se_shift = { + SE_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn10_stream_encoder_mask se_mask = { + SE_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + + +#define aux_regs(id)\ +[id] = {\ + DCN2_AUX_REG_LIST(id)\ +} + +static const struct dcn10_link_enc_aux_registers link_enc_aux_regs[] = { + aux_regs(0), + aux_regs(1), + aux_regs(2), + aux_regs(3), + aux_regs(4) +}; + +#define hpd_regs(id)\ +[id] = {\ + HPD_REG_LIST(id)\ +} + +static const struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[] = { + hpd_regs(0), + hpd_regs(1), + hpd_regs(2), + hpd_regs(3), + hpd_regs(4) +}; + +#define link_regs(id, phyid)\ +[id] = {\ + LE_DCN31_REG_LIST(id), \ + UNIPHY_DCN2_REG_LIST(phyid), \ + DPCS_DCN31_REG_LIST(id), \ +} + +static const struct dce110_aux_registers_shift aux_shift = { + DCN_AUX_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce110_aux_registers_mask aux_mask = { + DCN_AUX_MASK_SH_LIST(_MASK) +}; + +static const struct dcn10_link_enc_registers link_enc_regs[] = { + link_regs(0, A), + link_regs(1, B), + link_regs(2, C), + link_regs(3, D), + link_regs(4, E) +}; + +static const struct dcn10_link_enc_shift le_shift = { + LINK_ENCODER_MASK_SH_LIST_DCN31(__SHIFT), \ + DPCS_DCN31_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn10_link_enc_mask le_mask = { + LINK_ENCODER_MASK_SH_LIST_DCN31(_MASK), \ + DPCS_DCN31_MASK_SH_LIST(_MASK) +}; + +#define hpo_dp_stream_encoder_reg_list(id)\ +[id] = {\ + DCN3_1_HPO_DP_STREAM_ENC_REG_LIST(id)\ +} + +static const struct dcn31_hpo_dp_stream_encoder_registers hpo_dp_stream_enc_regs[] = { + hpo_dp_stream_encoder_reg_list(0), + hpo_dp_stream_encoder_reg_list(1), + hpo_dp_stream_encoder_reg_list(2), + hpo_dp_stream_encoder_reg_list(3), +}; + +static const struct dcn31_hpo_dp_stream_encoder_shift hpo_dp_se_shift = { + DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn31_hpo_dp_stream_encoder_mask hpo_dp_se_mask = { + DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(_MASK) +}; + + +#define hpo_dp_link_encoder_reg_list(id)\ +[id] = {\ + DCN3_1_HPO_DP_LINK_ENC_REG_LIST(id),\ + DCN3_1_RDPCSTX_REG_LIST(0),\ + DCN3_1_RDPCSTX_REG_LIST(1),\ + DCN3_1_RDPCSTX_REG_LIST(2),\ + DCN3_1_RDPCSTX_REG_LIST(3),\ + DCN3_1_RDPCSTX_REG_LIST(4)\ +} + +static const struct dcn31_hpo_dp_link_encoder_registers hpo_dp_link_enc_regs[] = { + hpo_dp_link_encoder_reg_list(0), + hpo_dp_link_encoder_reg_list(1), +}; + +static const struct dcn31_hpo_dp_link_encoder_shift hpo_dp_le_shift = { + DCN3_1_HPO_DP_LINK_ENC_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn31_hpo_dp_link_encoder_mask hpo_dp_le_mask = { + DCN3_1_HPO_DP_LINK_ENC_MASK_SH_LIST(_MASK) +}; + +#define dpp_regs(id)\ +[id] = {\ + DPP_REG_LIST_DCN30(id),\ +} + +static const struct dcn3_dpp_registers dpp_regs[] = { + dpp_regs(0), + dpp_regs(1), + dpp_regs(2), + dpp_regs(3) +}; + +static const struct dcn3_dpp_shift tf_shift = { + DPP_REG_LIST_SH_MASK_DCN30(__SHIFT) +}; + +static const struct dcn3_dpp_mask tf_mask = { + DPP_REG_LIST_SH_MASK_DCN30(_MASK) +}; + +#define opp_regs(id)\ +[id] = {\ + OPP_REG_LIST_DCN30(id),\ +} + +static const struct dcn20_opp_registers opp_regs[] = { + opp_regs(0), + opp_regs(1), + opp_regs(2), + opp_regs(3) +}; + +static const struct dcn20_opp_shift opp_shift = { + OPP_MASK_SH_LIST_DCN20(__SHIFT) +}; + +static const struct dcn20_opp_mask opp_mask = { + OPP_MASK_SH_LIST_DCN20(_MASK) +}; + +#define aux_engine_regs(id)\ +[id] = {\ + AUX_COMMON_REG_LIST0(id), \ + .AUXN_IMPCAL = 0, \ + .AUXP_IMPCAL = 0, \ + .AUX_RESET_MASK = DP_AUX0_AUX_CONTROL__AUX_RESET_MASK, \ +} + +static const struct dce110_aux_registers aux_engine_regs[] = { + aux_engine_regs(0), + aux_engine_regs(1), + aux_engine_regs(2), + aux_engine_regs(3), + aux_engine_regs(4) +}; + +#define dwbc_regs_dcn3(id)\ +[id] = {\ + DWBC_COMMON_REG_LIST_DCN30(id),\ +} + +static const struct dcn30_dwbc_registers dwbc30_regs[] = { + dwbc_regs_dcn3(0), +}; + +static const struct dcn30_dwbc_shift dwbc30_shift = { + DWBC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn30_dwbc_mask dwbc30_mask = { + DWBC_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +#define mcif_wb_regs_dcn3(id)\ +[id] = {\ + MCIF_WB_COMMON_REG_LIST_DCN30(id),\ +} + +static const struct dcn30_mmhubbub_registers mcif_wb30_regs[] = { + mcif_wb_regs_dcn3(0) +}; + +static const struct dcn30_mmhubbub_shift mcif_wb30_shift = { + MCIF_WB_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn30_mmhubbub_mask mcif_wb30_mask = { + MCIF_WB_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +#define dsc_regsDCN20(id)\ +[id] = {\ + DSC_REG_LIST_DCN20(id)\ +} + +static const struct dcn20_dsc_registers dsc_regs[] = { + dsc_regsDCN20(0), + dsc_regsDCN20(1), + dsc_regsDCN20(2) +}; + +static const struct dcn20_dsc_shift dsc_shift = { + DSC_REG_LIST_SH_MASK_DCN20(__SHIFT) +}; + +static const struct dcn20_dsc_mask dsc_mask = { + DSC_REG_LIST_SH_MASK_DCN20(_MASK) +}; + +static const struct dcn30_mpc_registers mpc_regs = { + MPC_REG_LIST_DCN3_0(0), + MPC_REG_LIST_DCN3_0(1), + MPC_REG_LIST_DCN3_0(2), + MPC_REG_LIST_DCN3_0(3), + MPC_OUT_MUX_REG_LIST_DCN3_0(0), + MPC_OUT_MUX_REG_LIST_DCN3_0(1), + MPC_OUT_MUX_REG_LIST_DCN3_0(2), + MPC_OUT_MUX_REG_LIST_DCN3_0(3), + MPC_DWB_MUX_REG_LIST_DCN3_0(0), +}; + +static const struct dcn30_mpc_shift mpc_shift = { + MPC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn30_mpc_mask mpc_mask = { + MPC_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +#define optc_regs(id)\ +[id] = {OPTC_COMMON_REG_LIST_DCN3_1(id)} + +static const struct dcn_optc_registers optc_regs[] = { + optc_regs(0), + optc_regs(1), + optc_regs(2), + optc_regs(3) +}; + +static const struct dcn_optc_shift optc_shift = { + OPTC_COMMON_MASK_SH_LIST_DCN3_1(__SHIFT) +}; + +static const struct dcn_optc_mask optc_mask = { + OPTC_COMMON_MASK_SH_LIST_DCN3_1(_MASK) +}; + +#define hubp_regs(id)\ +[id] = {\ + HUBP_REG_LIST_DCN30(id)\ +} + +static const struct dcn_hubp2_registers hubp_regs[] = { + hubp_regs(0), + hubp_regs(1), + hubp_regs(2), + hubp_regs(3) +}; + + +static const struct dcn_hubp2_shift hubp_shift = { + HUBP_MASK_SH_LIST_DCN31(__SHIFT) +}; + +static const struct dcn_hubp2_mask hubp_mask = { + HUBP_MASK_SH_LIST_DCN31(_MASK) +}; +static const struct dcn_hubbub_registers hubbub_reg = { + HUBBUB_REG_LIST_DCN31(0) +}; + +static const struct dcn_hubbub_shift hubbub_shift = { + HUBBUB_MASK_SH_LIST_DCN31(__SHIFT) +}; + +static const struct dcn_hubbub_mask hubbub_mask = { + HUBBUB_MASK_SH_LIST_DCN31(_MASK) +}; + +static const struct dccg_registers dccg_regs = { + DCCG_REG_LIST_DCN31() +}; + +static const struct dccg_shift dccg_shift = { + DCCG_MASK_SH_LIST_DCN31(__SHIFT) +}; + +static const struct dccg_mask dccg_mask = { + DCCG_MASK_SH_LIST_DCN31(_MASK) +}; + + +#define SRII2(reg_name_pre, reg_name_post, id)\ + .reg_name_pre ## _ ## reg_name_post[id] = BASE(reg ## reg_name_pre \ + ## id ## _ ## reg_name_post ## _BASE_IDX) + \ + reg ## reg_name_pre ## id ## _ ## reg_name_post + + +#define HWSEQ_DCN31_REG_LIST()\ + SR(DCHUBBUB_GLOBAL_TIMER_CNTL), \ + SR(DCHUBBUB_ARB_HOSTVM_CNTL), \ + SR(DIO_MEM_PWR_CTRL), \ + SR(ODM_MEM_PWR_CTRL3), \ + SR(DMU_MEM_PWR_CNTL), \ + SR(MMHUBBUB_MEM_PWR_CNTL), \ + SR(DCCG_GATE_DISABLE_CNTL), \ + SR(DCCG_GATE_DISABLE_CNTL2), \ + SR(DCFCLK_CNTL),\ + SR(DC_MEM_GLOBAL_PWR_REQ_CNTL), \ + SRII(PIXEL_RATE_CNTL, OTG, 0), \ + SRII(PIXEL_RATE_CNTL, OTG, 1),\ + SRII(PIXEL_RATE_CNTL, OTG, 2),\ + SRII(PIXEL_RATE_CNTL, OTG, 3),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 0),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 1),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 2),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 3),\ + SR(MICROSECOND_TIME_BASE_DIV), \ + SR(MILLISECOND_TIME_BASE_DIV), \ + SR(DISPCLK_FREQ_CHANGE_CNTL), \ + SR(RBBMIF_TIMEOUT_DIS), \ + SR(RBBMIF_TIMEOUT_DIS_2), \ + SR(DCHUBBUB_CRC_CTRL), \ + SR(DPP_TOP0_DPP_CRC_CTRL), \ + SR(DPP_TOP0_DPP_CRC_VAL_B_A), \ + SR(DPP_TOP0_DPP_CRC_VAL_R_G), \ + SR(MPC_CRC_CTRL), \ + SR(MPC_CRC_RESULT_GB), \ + SR(MPC_CRC_RESULT_C), \ + SR(MPC_CRC_RESULT_AR), \ + SR(DOMAIN0_PG_CONFIG), \ + SR(DOMAIN1_PG_CONFIG), \ + SR(DOMAIN2_PG_CONFIG), \ + SR(DOMAIN3_PG_CONFIG), \ + SR(DOMAIN16_PG_CONFIG), \ + SR(DOMAIN17_PG_CONFIG), \ + SR(DOMAIN18_PG_CONFIG), \ + SR(DOMAIN0_PG_STATUS), \ + SR(DOMAIN1_PG_STATUS), \ + SR(DOMAIN2_PG_STATUS), \ + SR(DOMAIN3_PG_STATUS), \ + SR(DOMAIN16_PG_STATUS), \ + SR(DOMAIN17_PG_STATUS), \ + SR(DOMAIN18_PG_STATUS), \ + SR(D1VGA_CONTROL), \ + SR(D2VGA_CONTROL), \ + SR(D3VGA_CONTROL), \ + SR(D4VGA_CONTROL), \ + SR(D5VGA_CONTROL), \ + SR(D6VGA_CONTROL), \ + SR(DC_IP_REQUEST_CNTL), \ + SR(AZALIA_AUDIO_DTO), \ + SR(AZALIA_CONTROLLER_CLOCK_GATING), \ + SR(HPO_TOP_HW_CONTROL) + +static const struct dce_hwseq_registers hwseq_reg = { + HWSEQ_DCN31_REG_LIST() +}; + +#define HWSEQ_DCN31_MASK_SH_LIST(mask_sh)\ + HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ + HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \ + HWS_SF(, DCHUBBUB_ARB_HOSTVM_CNTL, DISABLE_HOSTVM_FORCE_ALLOW_PSTATE, mask_sh), \ + HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN16_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN17_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN18_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \ + HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh), \ + HWS_SF(, HPO_TOP_CLOCK_CONTROL, HPO_HDMISTREAMCLK_G_GATE_DIS, mask_sh), \ + HWS_SF(, DMU_MEM_PWR_CNTL, DMCU_ERAM_MEM_PWR_FORCE, mask_sh), \ + HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_UNASSIGNED_PWR_MODE, mask_sh), \ + HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_VBLANK_PWR_MODE, mask_sh), \ + HWS_SF(, MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, mask_sh), \ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh), \ + HWS_SF(, HPO_TOP_HW_CONTROL, HPO_IO_EN, mask_sh) + +static const struct dce_hwseq_shift hwseq_shift = { + HWSEQ_DCN31_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_hwseq_mask hwseq_mask = { + HWSEQ_DCN31_MASK_SH_LIST(_MASK) +}; +#define vmid_regs(id)\ +[id] = {\ + DCN20_VMID_REG_LIST(id)\ +} + +static const struct dcn_vmid_registers vmid_regs[] = { + vmid_regs(0), + vmid_regs(1), + vmid_regs(2), + vmid_regs(3), + vmid_regs(4), + vmid_regs(5), + vmid_regs(6), + vmid_regs(7), + vmid_regs(8), + vmid_regs(9), + vmid_regs(10), + vmid_regs(11), + vmid_regs(12), + vmid_regs(13), + vmid_regs(14), + vmid_regs(15) +}; + +static const struct dcn20_vmid_shift vmid_shifts = { + DCN20_VMID_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn20_vmid_mask vmid_masks = { + DCN20_VMID_MASK_SH_LIST(_MASK) +}; + +static const struct resource_caps res_cap_dcn31 = { + .num_timing_generator = 4, + .num_opp = 4, + .num_video_plane = 4, + .num_audio = 5, + .num_stream_encoder = 5, + .num_dig_link_enc = 5, + .num_hpo_dp_stream_encoder = 4, + .num_hpo_dp_link_encoder = 2, + .num_pll = 5, + .num_dwb = 1, + .num_ddc = 5, + .num_vmid = 16, + .num_mpc_3dlut = 2, + .num_dsc = 3, +}; + +static const struct dc_plane_cap plane_cap = { + .type = DC_PLANE_TYPE_DCN_UNIVERSAL, + .per_pixel_alpha = true, + + .pixel_format_support = { + .argb8888 = true, + .nv12 = true, + .fp16 = true, + .p010 = true, + .ayuv = false, + }, + + .max_upscale_factor = { + .argb8888 = 16000, + .nv12 = 16000, + .fp16 = 16000 + }, + + // 6:1 downscaling ratio: 1000/6 = 166.666 + .max_downscale_factor = { + .argb8888 = 167, + .nv12 = 167, + .fp16 = 167 + }, + 64, + 64 +}; + +static const struct dc_debug_options debug_defaults_drv = { + .disable_z10 = true, /*hw not support it*/ + .disable_dmcu = true, + .force_abm_enable = false, + .timing_trace = false, + .clock_trace = true, + .disable_pplib_clock_request = false, + .pipe_split_policy = MPC_SPLIT_DYNAMIC, + .force_single_disp_pipe_split = false, + .disable_dcc = DCC_ENABLE, + .vsr_support = true, + .performance_trace = false, + .max_downscale_src_width = 4096,/*upto true 4k*/ + .disable_pplib_wm_range = false, + .scl_reset_length10 = true, + .sanity_checks = false, + .underflow_assert_delay_us = 0xFFFFFFFF, + .dwb_fi_phase = -1, // -1 = disable, + .dmub_command_table = true, + .pstate_enabled = true, + .use_max_lb = true, + .enable_mem_low_power = { + .bits = { + .vga = true, + .i2c = true, + .dmcu = false, // This is previously known to cause hang on S3 cycles if enabled + .dscl = true, + .cm = true, + .mpc = true, + .optc = true, + .vpg = true, + .afmt = true, + } + }, + .enable_legacy_fast_update = true, + .psr_power_use_phy_fsm = 0, + .using_dml2 = false, +}; + +static const struct dc_panel_config panel_config_defaults = { + .psr = { + .disable_psr = false, + .disallow_psrsu = false, + .disallow_replay = false, + }, + .ilr = { + .optimize_edp_link_rate = true, + }, +}; + +static void dcn31_dpp_destroy(struct dpp **dpp) +{ + kfree(TO_DCN20_DPP(*dpp)); + *dpp = NULL; +} + +static struct dpp *dcn31_dpp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn3_dpp *dpp = + kzalloc(sizeof(struct dcn3_dpp), GFP_KERNEL); + + if (!dpp) + return NULL; + + if (dpp3_construct(dpp, ctx, inst, + &dpp_regs[inst], &tf_shift, &tf_mask)) + return &dpp->base; + + BREAK_TO_DEBUGGER(); + kfree(dpp); + return NULL; +} + +static struct output_pixel_processor *dcn31_opp_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dcn20_opp *opp = + kzalloc(sizeof(struct dcn20_opp), GFP_KERNEL); + + if (!opp) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dcn20_opp_construct(opp, ctx, inst, + &opp_regs[inst], &opp_shift, &opp_mask); + return &opp->base; +} + +static struct dce_aux *dcn31_aux_engine_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct aux_engine_dce110 *aux_engine = + kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); + + if (!aux_engine) + return NULL; + + dce110_aux_engine_construct(aux_engine, ctx, inst, + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, + &aux_engine_regs[inst], + &aux_mask, + &aux_shift, + ctx->dc->caps.extended_aux_timeout_support); + + return &aux_engine->base; +} +#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST_DCN30(id) } + +static const struct dce_i2c_registers i2c_hw_regs[] = { + i2c_inst_regs(1), + i2c_inst_regs(2), + i2c_inst_regs(3), + i2c_inst_regs(4), + i2c_inst_regs(5), +}; + +static const struct dce_i2c_shift i2c_shifts = { + I2C_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dce_i2c_mask i2c_masks = { + I2C_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +static struct dce_i2c_hw *dcn31_i2c_hw_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce_i2c_hw *dce_i2c_hw = + kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); + + if (!dce_i2c_hw) + return NULL; + + dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst, + &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); + + return dce_i2c_hw; +} +static struct mpc *dcn31_mpc_create( + struct dc_context *ctx, + int num_mpcc, + int num_rmu) +{ + struct dcn30_mpc *mpc30 = kzalloc(sizeof(struct dcn30_mpc), + GFP_KERNEL); + + if (!mpc30) + return NULL; + + dcn30_mpc_construct(mpc30, ctx, + &mpc_regs, + &mpc_shift, + &mpc_mask, + num_mpcc, + num_rmu); + + return &mpc30->base; +} + +static struct hubbub *dcn31_hubbub_create(struct dc_context *ctx) +{ + int i; + + struct dcn20_hubbub *hubbub3 = kzalloc(sizeof(struct dcn20_hubbub), + GFP_KERNEL); + + if (!hubbub3) + return NULL; + + hubbub31_construct(hubbub3, ctx, + &hubbub_reg, + &hubbub_shift, + &hubbub_mask, + dcn3_15_ip.det_buffer_size_kbytes, + dcn3_15_ip.pixel_chunk_size_kbytes, + dcn3_15_ip.config_return_buffer_size_in_kbytes); + + + for (i = 0; i < res_cap_dcn31.num_vmid; i++) { + struct dcn20_vmid *vmid = &hubbub3->vmid[i]; + + vmid->ctx = ctx; + + vmid->regs = &vmid_regs[i]; + vmid->shifts = &vmid_shifts; + vmid->masks = &vmid_masks; + } + + return &hubbub3->base; +} + +static struct timing_generator *dcn31_timing_generator_create( + struct dc_context *ctx, + uint32_t instance) +{ + struct optc *tgn10 = + kzalloc(sizeof(struct optc), GFP_KERNEL); + + if (!tgn10) + return NULL; + + tgn10->base.inst = instance; + tgn10->base.ctx = ctx; + + tgn10->tg_regs = &optc_regs[instance]; + tgn10->tg_shift = &optc_shift; + tgn10->tg_mask = &optc_mask; + + dcn31_timing_generator_init(tgn10); + + return &tgn10->base; +} + +static const struct encoder_feature_support link_enc_feature = { + .max_hdmi_deep_color = COLOR_DEPTH_121212, + .max_hdmi_pixel_clock = 600000, + .hdmi_ycbcr420_supported = true, + .dp_ycbcr420_supported = true, + .fec_supported = true, + .flags.bits.IS_HBR2_CAPABLE = true, + .flags.bits.IS_HBR3_CAPABLE = true, + .flags.bits.IS_TPS3_CAPABLE = true, + .flags.bits.IS_TPS4_CAPABLE = true +}; + +static struct link_encoder *dcn31_link_encoder_create( + struct dc_context *ctx, + const struct encoder_init_data *enc_init_data) +{ + struct dcn20_link_encoder *enc20 = + kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); + + if (!enc20) + return NULL; + + dcn31_link_encoder_construct(enc20, + enc_init_data, + &link_enc_feature, + &link_enc_regs[enc_init_data->transmitter], + &link_enc_aux_regs[enc_init_data->channel - 1], + &link_enc_hpd_regs[enc_init_data->hpd_source], + &le_shift, + &le_mask); + + return &enc20->enc10.base; +} + +/* Create a minimal link encoder object not associated with a particular + * physical connector. + * resource_funcs.link_enc_create_minimal + */ +static struct link_encoder *dcn31_link_enc_create_minimal( + struct dc_context *ctx, enum engine_id eng_id) +{ + struct dcn20_link_encoder *enc20; + + if ((eng_id - ENGINE_ID_DIGA) > ctx->dc->res_pool->res_cap->num_dig_link_enc) + return NULL; + + enc20 = kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); + if (!enc20) + return NULL; + + dcn31_link_encoder_construct_minimal( + enc20, + ctx, + &link_enc_feature, + &link_enc_regs[eng_id - ENGINE_ID_DIGA], + eng_id); + + return &enc20->enc10.base; +} + +static struct panel_cntl *dcn31_panel_cntl_create(const struct panel_cntl_init_data *init_data) +{ + struct dcn31_panel_cntl *panel_cntl = + kzalloc(sizeof(struct dcn31_panel_cntl), GFP_KERNEL); + + if (!panel_cntl) + return NULL; + + dcn31_panel_cntl_construct(panel_cntl, init_data); + + return &panel_cntl->base; +} + +static void read_dce_straps( + struct dc_context *ctx, + struct resource_straps *straps) +{ + generic_reg_get(ctx, regDC_PINSTRAPS + BASE(regDC_PINSTRAPS_BASE_IDX), + FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio); + +} + +static struct audio *dcn31_create_audio( + struct dc_context *ctx, unsigned int inst) +{ + return dce_audio_create(ctx, inst, + &audio_regs[inst], &audio_shift, &audio_mask); +} + +static struct vpg *dcn31_vpg_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn31_vpg *vpg31 = kzalloc(sizeof(struct dcn31_vpg), GFP_KERNEL); + + if (!vpg31) + return NULL; + + vpg31_construct(vpg31, ctx, inst, + &vpg_regs[inst], + &vpg_shift, + &vpg_mask); + + return &vpg31->base; +} + +static struct afmt *dcn31_afmt_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn31_afmt *afmt31 = kzalloc(sizeof(struct dcn31_afmt), GFP_KERNEL); + + if (!afmt31) + return NULL; + + afmt31_construct(afmt31, ctx, inst, + &afmt_regs[inst], + &afmt_shift, + &afmt_mask); + + // Light sleep by default, no need to power down here + + return &afmt31->base; +} + +static struct apg *dcn31_apg_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn31_apg *apg31 = kzalloc(sizeof(struct dcn31_apg), GFP_KERNEL); + + if (!apg31) + return NULL; + + apg31_construct(apg31, ctx, inst, + &apg_regs[inst], + &apg_shift, + &apg_mask); + + return &apg31->base; +} + +static struct stream_encoder *dcn315_stream_encoder_create( + enum engine_id eng_id, + struct dc_context *ctx) +{ + struct dcn10_stream_encoder *enc1; + struct vpg *vpg; + struct afmt *afmt; + int vpg_inst; + int afmt_inst; + + /*PHYB is wired off in HW, allow front end to remapping, otherwise needs more changes*/ + + /* Mapping of VPG, AFMT, DME register blocks to DIO block instance */ + if (eng_id <= ENGINE_ID_DIGF) { + vpg_inst = eng_id; + afmt_inst = eng_id; + } else + return NULL; + + enc1 = kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL); + vpg = dcn31_vpg_create(ctx, vpg_inst); + afmt = dcn31_afmt_create(ctx, afmt_inst); + + if (!enc1 || !vpg || !afmt) { + kfree(enc1); + kfree(vpg); + kfree(afmt); + return NULL; + } + + dcn30_dio_stream_encoder_construct(enc1, ctx, ctx->dc_bios, + eng_id, vpg, afmt, + &stream_enc_regs[eng_id], + &se_shift, &se_mask); + + return &enc1->base; +} + +static struct hpo_dp_stream_encoder *dcn31_hpo_dp_stream_encoder_create( + enum engine_id eng_id, + struct dc_context *ctx) +{ + struct dcn31_hpo_dp_stream_encoder *hpo_dp_enc31; + struct vpg *vpg; + struct apg *apg; + uint32_t hpo_dp_inst; + uint32_t vpg_inst; + uint32_t apg_inst; + + ASSERT((eng_id >= ENGINE_ID_HPO_DP_0) && (eng_id <= ENGINE_ID_HPO_DP_3)); + hpo_dp_inst = eng_id - ENGINE_ID_HPO_DP_0; + + /* Mapping of VPG register blocks to HPO DP block instance: + * VPG[6] -> HPO_DP[0] + * VPG[7] -> HPO_DP[1] + * VPG[8] -> HPO_DP[2] + * VPG[9] -> HPO_DP[3] + */ + vpg_inst = hpo_dp_inst + 6; + + /* Mapping of APG register blocks to HPO DP block instance: + * APG[0] -> HPO_DP[0] + * APG[1] -> HPO_DP[1] + * APG[2] -> HPO_DP[2] + * APG[3] -> HPO_DP[3] + */ + apg_inst = hpo_dp_inst; + + /* allocate HPO stream encoder and create VPG sub-block */ + hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_stream_encoder), GFP_KERNEL); + vpg = dcn31_vpg_create(ctx, vpg_inst); + apg = dcn31_apg_create(ctx, apg_inst); + + if (!hpo_dp_enc31 || !vpg || !apg) { + kfree(hpo_dp_enc31); + kfree(vpg); + kfree(apg); + return NULL; + } + + dcn31_hpo_dp_stream_encoder_construct(hpo_dp_enc31, ctx, ctx->dc_bios, + hpo_dp_inst, eng_id, vpg, apg, + &hpo_dp_stream_enc_regs[hpo_dp_inst], + &hpo_dp_se_shift, &hpo_dp_se_mask); + + return &hpo_dp_enc31->base; +} + +static struct hpo_dp_link_encoder *dcn31_hpo_dp_link_encoder_create( + uint8_t inst, + struct dc_context *ctx) +{ + struct dcn31_hpo_dp_link_encoder *hpo_dp_enc31; + + /* allocate HPO link encoder */ + hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_link_encoder), GFP_KERNEL); + + hpo_dp_link_encoder31_construct(hpo_dp_enc31, ctx, inst, + &hpo_dp_link_enc_regs[inst], + &hpo_dp_le_shift, &hpo_dp_le_mask); + + return &hpo_dp_enc31->base; +} + +static struct dce_hwseq *dcn31_hwseq_create( + struct dc_context *ctx) +{ + struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); + + if (hws) { + hws->ctx = ctx; + hws->regs = &hwseq_reg; + hws->shifts = &hwseq_shift; + hws->masks = &hwseq_mask; + } + return hws; +} +static const struct resource_create_funcs res_create_funcs = { + .read_dce_straps = read_dce_straps, + .create_audio = dcn31_create_audio, + .create_stream_encoder = dcn315_stream_encoder_create, + .create_hpo_dp_stream_encoder = dcn31_hpo_dp_stream_encoder_create, + .create_hpo_dp_link_encoder = dcn31_hpo_dp_link_encoder_create, + .create_hwseq = dcn31_hwseq_create, +}; + +static void dcn315_resource_destruct(struct dcn315_resource_pool *pool) +{ + unsigned int i; + + for (i = 0; i < pool->base.stream_enc_count; i++) { + if (pool->base.stream_enc[i] != NULL) { + if (pool->base.stream_enc[i]->vpg != NULL) { + kfree(DCN30_VPG_FROM_VPG(pool->base.stream_enc[i]->vpg)); + pool->base.stream_enc[i]->vpg = NULL; + } + if (pool->base.stream_enc[i]->afmt != NULL) { + kfree(DCN30_AFMT_FROM_AFMT(pool->base.stream_enc[i]->afmt)); + pool->base.stream_enc[i]->afmt = NULL; + } + kfree(DCN10STRENC_FROM_STRENC(pool->base.stream_enc[i])); + pool->base.stream_enc[i] = NULL; + } + } + + for (i = 0; i < pool->base.hpo_dp_stream_enc_count; i++) { + if (pool->base.hpo_dp_stream_enc[i] != NULL) { + if (pool->base.hpo_dp_stream_enc[i]->vpg != NULL) { + kfree(DCN30_VPG_FROM_VPG(pool->base.hpo_dp_stream_enc[i]->vpg)); + pool->base.hpo_dp_stream_enc[i]->vpg = NULL; + } + if (pool->base.hpo_dp_stream_enc[i]->apg != NULL) { + kfree(DCN31_APG_FROM_APG(pool->base.hpo_dp_stream_enc[i]->apg)); + pool->base.hpo_dp_stream_enc[i]->apg = NULL; + } + kfree(DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(pool->base.hpo_dp_stream_enc[i])); + pool->base.hpo_dp_stream_enc[i] = NULL; + } + } + + for (i = 0; i < pool->base.hpo_dp_link_enc_count; i++) { + if (pool->base.hpo_dp_link_enc[i] != NULL) { + kfree(DCN3_1_HPO_DP_LINK_ENC_FROM_HPO_LINK_ENC(pool->base.hpo_dp_link_enc[i])); + pool->base.hpo_dp_link_enc[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_dsc; i++) { + if (pool->base.dscs[i] != NULL) + dcn20_dsc_destroy(&pool->base.dscs[i]); + } + + if (pool->base.mpc != NULL) { + kfree(TO_DCN20_MPC(pool->base.mpc)); + pool->base.mpc = NULL; + } + if (pool->base.hubbub != NULL) { + kfree(pool->base.hubbub); + pool->base.hubbub = NULL; + } + for (i = 0; i < pool->base.pipe_count; i++) { + if (pool->base.dpps[i] != NULL) + dcn31_dpp_destroy(&pool->base.dpps[i]); + + if (pool->base.ipps[i] != NULL) + pool->base.ipps[i]->funcs->ipp_destroy(&pool->base.ipps[i]); + + if (pool->base.hubps[i] != NULL) { + kfree(TO_DCN20_HUBP(pool->base.hubps[i])); + pool->base.hubps[i] = NULL; + } + + if (pool->base.irqs != NULL) { + dal_irq_service_destroy(&pool->base.irqs); + } + } + + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + if (pool->base.engines[i] != NULL) + dce110_engine_destroy(&pool->base.engines[i]); + if (pool->base.hw_i2cs[i] != NULL) { + kfree(pool->base.hw_i2cs[i]); + pool->base.hw_i2cs[i] = NULL; + } + if (pool->base.sw_i2cs[i] != NULL) { + kfree(pool->base.sw_i2cs[i]); + pool->base.sw_i2cs[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_opp; i++) { + if (pool->base.opps[i] != NULL) + pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]); + } + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + if (pool->base.timing_generators[i] != NULL) { + kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i])); + pool->base.timing_generators[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_dwb; i++) { + if (pool->base.dwbc[i] != NULL) { + kfree(TO_DCN30_DWBC(pool->base.dwbc[i])); + pool->base.dwbc[i] = NULL; + } + if (pool->base.mcif_wb[i] != NULL) { + kfree(TO_DCN30_MMHUBBUB(pool->base.mcif_wb[i])); + pool->base.mcif_wb[i] = NULL; + } + } + + for (i = 0; i < pool->base.audio_count; i++) { + if (pool->base.audios[i]) + dce_aud_destroy(&pool->base.audios[i]); + } + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] != NULL) { + dcn20_clock_source_destroy(&pool->base.clock_sources[i]); + pool->base.clock_sources[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_mpc_3dlut; i++) { + if (pool->base.mpc_lut[i] != NULL) { + dc_3dlut_func_release(pool->base.mpc_lut[i]); + pool->base.mpc_lut[i] = NULL; + } + if (pool->base.mpc_shaper[i] != NULL) { + dc_transfer_func_release(pool->base.mpc_shaper[i]); + pool->base.mpc_shaper[i] = NULL; + } + } + + if (pool->base.dp_clock_source != NULL) { + dcn20_clock_source_destroy(&pool->base.dp_clock_source); + pool->base.dp_clock_source = NULL; + } + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + if (pool->base.multiple_abms[i] != NULL) + dce_abm_destroy(&pool->base.multiple_abms[i]); + } + + if (pool->base.psr != NULL) + dmub_psr_destroy(&pool->base.psr); + + if (pool->base.dccg != NULL) + dcn_dccg_destroy(&pool->base.dccg); +} + +static struct hubp *dcn31_hubp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn20_hubp *hubp2 = + kzalloc(sizeof(struct dcn20_hubp), GFP_KERNEL); + + if (!hubp2) + return NULL; + + if (hubp31_construct(hubp2, ctx, inst, + &hubp_regs[inst], &hubp_shift, &hubp_mask)) + return &hubp2->base; + + BREAK_TO_DEBUGGER(); + kfree(hubp2); + return NULL; +} + +static bool dcn31_dwbc_create(struct dc_context *ctx, struct resource_pool *pool) +{ + int i; + uint32_t pipe_count = pool->res_cap->num_dwb; + + for (i = 0; i < pipe_count; i++) { + struct dcn30_dwbc *dwbc30 = kzalloc(sizeof(struct dcn30_dwbc), + GFP_KERNEL); + + if (!dwbc30) { + dm_error("DC: failed to create dwbc30!\n"); + return false; + } + + dcn30_dwbc_construct(dwbc30, ctx, + &dwbc30_regs[i], + &dwbc30_shift, + &dwbc30_mask, + i); + + pool->dwbc[i] = &dwbc30->base; + } + return true; +} + +static bool dcn31_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool) +{ + int i; + uint32_t pipe_count = pool->res_cap->num_dwb; + + for (i = 0; i < pipe_count; i++) { + struct dcn30_mmhubbub *mcif_wb30 = kzalloc(sizeof(struct dcn30_mmhubbub), + GFP_KERNEL); + + if (!mcif_wb30) { + dm_error("DC: failed to create mcif_wb30!\n"); + return false; + } + + dcn30_mmhubbub_construct(mcif_wb30, ctx, + &mcif_wb30_regs[i], + &mcif_wb30_shift, + &mcif_wb30_mask, + i); + + pool->mcif_wb[i] = &mcif_wb30->base; + } + return true; +} + +static struct display_stream_compressor *dcn31_dsc_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dcn20_dsc *dsc = + kzalloc(sizeof(struct dcn20_dsc), GFP_KERNEL); + + if (!dsc) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dsc2_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask); + return &dsc->base; +} + +static void dcn315_destroy_resource_pool(struct resource_pool **pool) +{ + struct dcn315_resource_pool *dcn31_pool = TO_DCN315_RES_POOL(*pool); + + dcn315_resource_destruct(dcn31_pool); + kfree(dcn31_pool); + *pool = NULL; +} + +static struct clock_source *dcn31_clock_source_create( + struct dc_context *ctx, + struct dc_bios *bios, + enum clock_source_id id, + const struct dce110_clk_src_regs *regs, + bool dp_clk_src) +{ + struct dce110_clk_src *clk_src = + kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); + + if (!clk_src) + return NULL; + + if (dcn31_clk_src_construct(clk_src, ctx, bios, id, + regs, &cs_shift, &cs_mask)) { + clk_src->base.dp_clk_src = dp_clk_src; + return &clk_src->base; + } + + kfree(clk_src); + BREAK_TO_DEBUGGER(); + return NULL; +} + +static bool is_dual_plane(enum surface_pixel_format format) +{ + return format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN || format == SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA; +} + +static int source_format_to_bpp (enum source_format_class SourcePixelFormat) +{ + if (SourcePixelFormat == dm_444_64) + return 8; + else if (SourcePixelFormat == dm_444_16) + return 2; + else if (SourcePixelFormat == dm_444_8) + return 1; + else if (SourcePixelFormat == dm_rgbe_alpha) + return 5; + else if (SourcePixelFormat == dm_420_8) + return 3; + else if (SourcePixelFormat == dm_420_12) + return 6; + else + return 4; +} + +static bool allow_pixel_rate_crb(struct dc *dc, struct dc_state *context) +{ + int i; + struct resource_context *res_ctx = &context->res_ctx; + + /* Only apply for dual stream scenarios with edp*/ + if (context->stream_count != 2) + return false; + if (context->streams[0]->signal != SIGNAL_TYPE_EDP && context->streams[1]->signal != SIGNAL_TYPE_EDP) + return false; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + if (!res_ctx->pipe_ctx[i].stream) + continue; + + /*Don't apply if scaling*/ + if (res_ctx->pipe_ctx[i].stream->src.width != res_ctx->pipe_ctx[i].stream->dst.width || + res_ctx->pipe_ctx[i].stream->src.height != res_ctx->pipe_ctx[i].stream->dst.height || + (res_ctx->pipe_ctx[i].plane_state && (res_ctx->pipe_ctx[i].plane_state->src_rect.width + != res_ctx->pipe_ctx[i].plane_state->dst_rect.width || + res_ctx->pipe_ctx[i].plane_state->src_rect.height + != res_ctx->pipe_ctx[i].plane_state->dst_rect.height))) + return false; + /*Don't apply if MPO to avoid transition issues*/ + if (res_ctx->pipe_ctx[i].top_pipe && res_ctx->pipe_ctx[i].top_pipe->plane_state != res_ctx->pipe_ctx[i].plane_state) + return false; + } + return true; +} + +static int dcn315_populate_dml_pipes_from_context( + struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes, + bool fast_validate) +{ + int i, pipe_cnt, crb_idx, crb_pipes; + struct resource_context *res_ctx = &context->res_ctx; + struct pipe_ctx *pipe = NULL; + const int max_usable_det = context->bw_ctx.dml.ip.config_return_buffer_size_in_kbytes - DCN3_15_MIN_COMPBUF_SIZE_KB; + int remaining_det_segs = max_usable_det / DCN3_15_CRB_SEGMENT_SIZE_KB; + bool pixel_rate_crb = allow_pixel_rate_crb(dc, context); + + DC_FP_START(); + dcn31x_populate_dml_pipes_from_context(dc, context, pipes, fast_validate); + DC_FP_END(); + + for (i = 0, pipe_cnt = 0, crb_pipes = 0; i < dc->res_pool->pipe_count; i++) { + struct dc_crtc_timing *timing; + + if (!res_ctx->pipe_ctx[i].stream) + continue; + pipe = &res_ctx->pipe_ctx[i]; + timing = &pipe->stream->timing; + + /* + * Immediate flip can be set dynamically after enabling the plane. + * We need to require support for immediate flip or underflow can be + * intermittently experienced depending on peak b/w requirements. + */ + pipes[pipe_cnt].pipe.src.immediate_flip = true; + + pipes[pipe_cnt].pipe.src.unbounded_req_mode = false; + pipes[pipe_cnt].pipe.dest.vfront_porch = timing->v_front_porch; + pipes[pipe_cnt].pipe.src.dcc_rate = 3; + pipes[pipe_cnt].dout.dsc_input_bpc = 0; + DC_FP_START(); + dcn31_zero_pipe_dcc_fraction(pipes, pipe_cnt); + if (pixel_rate_crb && !pipe->top_pipe && !pipe->prev_odm_pipe) { + int bpp = source_format_to_bpp(pipes[pipe_cnt].pipe.src.source_format); + /* Ceil to crb segment size */ + int approx_det_segs_required_for_pstate = dcn_get_approx_det_segs_required_for_pstate( + &context->bw_ctx.dml.soc, timing->pix_clk_100hz, bpp, DCN3_15_CRB_SEGMENT_SIZE_KB); + + if (approx_det_segs_required_for_pstate <= 2 * DCN3_15_MAX_DET_SEGS) { + bool split_required = approx_det_segs_required_for_pstate > DCN3_15_MAX_DET_SEGS; + split_required = split_required || timing->pix_clk_100hz >= dcn_get_max_non_odm_pix_rate_100hz(&dc->dml.soc); + split_required = split_required || (pipe->plane_state && pipe->plane_state->src_rect.width > 5120); + + /* Minimum 2 segments to allow mpc/odm combine if its used later */ + if (approx_det_segs_required_for_pstate < 2) + approx_det_segs_required_for_pstate = 2; + if (split_required) + approx_det_segs_required_for_pstate += approx_det_segs_required_for_pstate % 2; + pipes[pipe_cnt].pipe.src.det_size_override = approx_det_segs_required_for_pstate; + remaining_det_segs -= approx_det_segs_required_for_pstate; + } else + remaining_det_segs = -1; + crb_pipes++; + } + DC_FP_END(); + + if (pipes[pipe_cnt].dout.dsc_enable) { + switch (timing->display_color_depth) { + case COLOR_DEPTH_888: + pipes[pipe_cnt].dout.dsc_input_bpc = 8; + break; + case COLOR_DEPTH_101010: + pipes[pipe_cnt].dout.dsc_input_bpc = 10; + break; + case COLOR_DEPTH_121212: + pipes[pipe_cnt].dout.dsc_input_bpc = 12; + break; + default: + ASSERT(0); + break; + } + } + pipe_cnt++; + } + + /* Spread remaining unreserved crb evenly among all pipes*/ + if (pixel_rate_crb) { + for (i = 0, pipe_cnt = 0, crb_idx = 0; i < dc->res_pool->pipe_count; i++) { + pipe = &res_ctx->pipe_ctx[i]; + if (!pipe->stream) + continue; + + /* Do not use asymetric crb if not enough for pstate support */ + if (remaining_det_segs < 0) { + pipes[pipe_cnt].pipe.src.det_size_override = 0; + pipe_cnt++; + continue; + } + + if (!pipe->top_pipe && !pipe->prev_odm_pipe) { + bool split_required = pipe->stream->timing.pix_clk_100hz >= dcn_get_max_non_odm_pix_rate_100hz(&dc->dml.soc) + || (pipe->plane_state && pipe->plane_state->src_rect.width > 5120); + + if (remaining_det_segs > MIN_RESERVED_DET_SEGS) + pipes[pipe_cnt].pipe.src.det_size_override += (remaining_det_segs - MIN_RESERVED_DET_SEGS) / crb_pipes + + (crb_idx < (remaining_det_segs - MIN_RESERVED_DET_SEGS) % crb_pipes ? 1 : 0); + if (pipes[pipe_cnt].pipe.src.det_size_override > 2 * DCN3_15_MAX_DET_SEGS) { + /* Clamp to 2 pipe split max det segments */ + remaining_det_segs += pipes[pipe_cnt].pipe.src.det_size_override - 2 * (DCN3_15_MAX_DET_SEGS); + pipes[pipe_cnt].pipe.src.det_size_override = 2 * DCN3_15_MAX_DET_SEGS; + } + if (pipes[pipe_cnt].pipe.src.det_size_override > DCN3_15_MAX_DET_SEGS || split_required) { + /* If we are splitting we must have an even number of segments */ + remaining_det_segs += pipes[pipe_cnt].pipe.src.det_size_override % 2; + pipes[pipe_cnt].pipe.src.det_size_override -= pipes[pipe_cnt].pipe.src.det_size_override % 2; + } + /* Convert segments into size for DML use */ + pipes[pipe_cnt].pipe.src.det_size_override *= DCN3_15_CRB_SEGMENT_SIZE_KB; + + crb_idx++; + } + pipe_cnt++; + } + } + + if (pipe_cnt) + context->bw_ctx.dml.ip.det_buffer_size_kbytes = + (max_usable_det / DCN3_15_CRB_SEGMENT_SIZE_KB / pipe_cnt) * DCN3_15_CRB_SEGMENT_SIZE_KB; + if (context->bw_ctx.dml.ip.det_buffer_size_kbytes > DCN3_15_MAX_DET_SIZE) + context->bw_ctx.dml.ip.det_buffer_size_kbytes = DCN3_15_MAX_DET_SIZE; + + dc->config.enable_4to1MPC = false; + if (pipe_cnt == 1 && pipe->plane_state && !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; + context->bw_ctx.dml.ip.det_buffer_size_kbytes = + (max_usable_det / DCN3_15_CRB_SEGMENT_SIZE_KB / 4) * DCN3_15_CRB_SEGMENT_SIZE_KB; + } else if (!is_dual_plane(pipe->plane_state->format) + && pipe->plane_state->src_rect.width <= 5120 + && pipe->stream->timing.pix_clk_100hz < dcn_get_max_non_odm_pix_rate_100hz(&dc->dml.soc)) { + /* Limit to 5k max to avoid forced pipe split when there is not enough detile for swath */ + context->bw_ctx.dml.ip.det_buffer_size_kbytes = 192; + pipes[0].pipe.src.unbounded_req_mode = true; + } + } + + return pipe_cnt; +} + +static void dcn315_get_panel_config_defaults(struct dc_panel_config *panel_config) +{ + *panel_config = panel_config_defaults; +} + +static struct dc_cap_funcs cap_funcs = { + .get_dcc_compression_cap = dcn20_get_dcc_compression_cap +}; + +static struct resource_funcs dcn315_res_pool_funcs = { + .destroy = dcn315_destroy_resource_pool, + .link_enc_create = dcn31_link_encoder_create, + .link_enc_create_minimal = dcn31_link_enc_create_minimal, + .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, + .calculate_wm_and_dlg = dcn31_calculate_wm_and_dlg, + .update_soc_for_wm_a = dcn315_update_soc_for_wm_a, + .populate_dml_pipes = dcn315_populate_dml_pipes_from_context, + .acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer, + .release_pipe = dcn20_release_pipe, + .add_stream_to_ctx = dcn30_add_stream_to_ctx, + .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource, + .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, + .populate_dml_writeback_from_context = dcn31_populate_dml_writeback_from_context, + .set_mcif_arb_params = dcn31_set_mcif_arb_params, + .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 = dcn315_update_bw_bounding_box, + .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, + .get_panel_config_defaults = dcn315_get_panel_config_defaults, +}; + +static bool dcn315_resource_construct( + uint8_t num_virtual_links, + struct dc *dc, + struct dcn315_resource_pool *pool) +{ + int i; + struct dc_context *ctx = dc->ctx; + struct irq_service_init_data init_data; + + ctx->dc_bios->regs = &bios_regs; + + pool->base.res_cap = &res_cap_dcn31; + + pool->base.funcs = &dcn315_res_pool_funcs; + + /************************************************* + * Resource + asic cap harcoding * + *************************************************/ + pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.pipe_count = pool->base.res_cap->num_timing_generator; + 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.max_cursor_size = 256; + dc->caps.min_horizontal_blanking_period = 80; + dc->caps.dmdata_alloc_size = 2048; + dc->caps.max_slave_planes = 2; + dc->caps.max_slave_yuv_planes = 2; + dc->caps.max_slave_rgb_planes = 2; + dc->caps.post_blend_color_processing = true; + dc->caps.force_dp_tps4_for_cp2520 = true; + if (dc->config.forceHBR2CP2520) + dc->caps.force_dp_tps4_for_cp2520 = false; + dc->caps.dp_hpo = true; + dc->caps.dp_hdmi21_pcon_support = true; + dc->caps.edp_dsc_support = true; + dc->caps.extended_aux_timeout_support = true; + dc->caps.dmcub_support = true; + dc->caps.is_apu = true; + + /* Color pipeline capabilities */ + dc->caps.color.dpp.dcn_arch = 1; + dc->caps.color.dpp.input_lut_shared = 0; + dc->caps.color.dpp.icsc = 1; + dc->caps.color.dpp.dgam_ram = 0; // must use gamma_corr + dc->caps.color.dpp.dgam_rom_caps.srgb = 1; + dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1; + dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 1; + dc->caps.color.dpp.dgam_rom_caps.pq = 1; + dc->caps.color.dpp.dgam_rom_caps.hlg = 1; + dc->caps.color.dpp.post_csc = 1; + dc->caps.color.dpp.gamma_corr = 1; + dc->caps.color.dpp.dgam_rom_for_yuv = 0; + + dc->caps.color.dpp.hw_3d_lut = 1; + dc->caps.color.dpp.ogam_ram = 1; + // no OGAM ROM on DCN301 + dc->caps.color.dpp.ogam_rom_caps.srgb = 0; + dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0; + dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0; + dc->caps.color.dpp.ogam_rom_caps.pq = 0; + dc->caps.color.dpp.ogam_rom_caps.hlg = 0; + dc->caps.color.dpp.ocsc = 0; + + dc->caps.color.mpc.gamut_remap = 1; + dc->caps.color.mpc.num_3dluts = pool->base.res_cap->num_mpc_3dlut; //2 + dc->caps.color.mpc.ogam_ram = 1; + dc->caps.color.mpc.ogam_rom_caps.srgb = 0; + dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0; + dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0; + dc->caps.color.mpc.ogam_rom_caps.pq = 0; + dc->caps.color.mpc.ogam_rom_caps.hlg = 0; + dc->caps.color.mpc.ocsc = 1; + + /* read VBIOS LTTPR caps */ + { + if (ctx->dc_bios->funcs->get_lttpr_caps) { + enum bp_result bp_query_result; + uint8_t is_vbios_lttpr_enable = 0; + + bp_query_result = ctx->dc_bios->funcs->get_lttpr_caps(ctx->dc_bios, &is_vbios_lttpr_enable); + dc->caps.vbios_lttpr_enable = (bp_query_result == BP_RESULT_OK) && !!is_vbios_lttpr_enable; + } + + /* interop bit is implicit */ + { + dc->caps.vbios_lttpr_aware = true; + } + } + + if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) + dc->debug = debug_defaults_drv; + + // Init the vm_helper + if (dc->vm_helper) + vm_helper_init(dc->vm_helper, 16); + + /************************************************* + * Create resources * + *************************************************/ + + /* Clock Sources for Pixel Clock*/ + pool->base.clock_sources[DCN31_CLK_SRC_PLL0] = + dcn31_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL0, + &clk_src_regs[0], false); + pool->base.clock_sources[DCN31_CLK_SRC_PLL1] = + dcn31_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL1, + &clk_src_regs[1], false); + pool->base.clock_sources[DCN31_CLK_SRC_PLL2] = + dcn31_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL2, + &clk_src_regs[2], false); + pool->base.clock_sources[DCN31_CLK_SRC_PLL3] = + dcn31_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL3, + &clk_src_regs[3], false); + pool->base.clock_sources[DCN31_CLK_SRC_PLL4] = + dcn31_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL4, + &clk_src_regs[4], false); + + pool->base.clk_src_count = DCN30_CLK_SRC_TOTAL; + + /* todo: not reuse phy_pll registers */ + pool->base.dp_clock_source = + dcn31_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_ID_DP_DTO, + &clk_src_regs[0], true); + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] == NULL) { + dm_error("DC: failed to create clock sources!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + } + + /* TODO: DCCG */ + pool->base.dccg = dccg31_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask); + if (pool->base.dccg == NULL) { + dm_error("DC: failed to create dccg!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + /* TODO: IRQ */ + init_data.ctx = dc->ctx; + pool->base.irqs = dal_irq_service_dcn315_create(&init_data); + if (!pool->base.irqs) + goto create_fail; + + /* HUBBUB */ + pool->base.hubbub = dcn31_hubbub_create(ctx); + if (pool->base.hubbub == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create hubbub!\n"); + goto create_fail; + } + + /* HUBPs, DPPs, OPPs and TGs */ + for (i = 0; i < pool->base.pipe_count; i++) { + pool->base.hubps[i] = dcn31_hubp_create(ctx, i); + if (pool->base.hubps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create hubps!\n"); + goto create_fail; + } + + pool->base.dpps[i] = dcn31_dpp_create(ctx, i); + if (pool->base.dpps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create dpps!\n"); + goto create_fail; + } + } + + for (i = 0; i < pool->base.res_cap->num_opp; i++) { + pool->base.opps[i] = dcn31_opp_create(ctx, i); + if (pool->base.opps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create output pixel processor!\n"); + goto create_fail; + } + } + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + pool->base.timing_generators[i] = dcn31_timing_generator_create( + ctx, i); + if (pool->base.timing_generators[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create tg!\n"); + goto create_fail; + } + } + pool->base.timing_generator_count = i; + + /* PSR */ + pool->base.psr = dmub_psr_create(ctx); + if (pool->base.psr == NULL) { + dm_error("DC: failed to create psr obj!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + /* ABM */ + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + pool->base.multiple_abms[i] = dmub_abm_create(ctx, + &abm_regs[i], + &abm_shift, + &abm_mask); + if (pool->base.multiple_abms[i] == NULL) { + dm_error("DC: failed to create abm for pipe %d!\n", i); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + } + + /* MPC and DSC */ + pool->base.mpc = dcn31_mpc_create(ctx, pool->base.mpcc_count, pool->base.res_cap->num_mpc_3dlut); + if (pool->base.mpc == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create mpc!\n"); + goto create_fail; + } + + for (i = 0; i < pool->base.res_cap->num_dsc; i++) { + pool->base.dscs[i] = dcn31_dsc_create(ctx, i); + if (pool->base.dscs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create display stream compressor %d!\n", i); + goto create_fail; + } + } + + /* DWB and MMHUBBUB */ + if (!dcn31_dwbc_create(ctx, &pool->base)) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dwbc!\n"); + goto create_fail; + } + + if (!dcn31_mmhubbub_create(ctx, &pool->base)) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create mcif_wb!\n"); + goto create_fail; + } + + /* AUX and I2C */ + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + pool->base.engines[i] = dcn31_aux_engine_create(ctx, i); + if (pool->base.engines[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create aux engine!!\n"); + goto create_fail; + } + pool->base.hw_i2cs[i] = dcn31_i2c_hw_create(ctx, i); + if (pool->base.hw_i2cs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create hw i2c!!\n"); + goto create_fail; + } + pool->base.sw_i2cs[i] = NULL; + } + + /* Audio, Stream Encoders including HPO and virtual, MPC 3D LUTs */ + if (!resource_construct(num_virtual_links, dc, &pool->base, + &res_create_funcs)) + goto create_fail; + + /* HW Sequencer and Plane caps */ + dcn31_hw_sequencer_construct(dc); + + dc->caps.max_planes = pool->base.pipe_count; + + for (i = 0; i < dc->caps.max_planes; ++i) + dc->caps.planes[i] = plane_cap; + + dc->cap_funcs = cap_funcs; + + dc->dcn_ip->max_num_dpp = dcn3_15_ip.max_num_dpp; + + return true; + +create_fail: + + dcn315_resource_destruct(pool); + + return false; +} + +struct resource_pool *dcn315_create_resource_pool( + const struct dc_init_data *init_data, + struct dc *dc) +{ + struct dcn315_resource_pool *pool = + kzalloc(sizeof(struct dcn315_resource_pool), GFP_KERNEL); + + if (!pool) + return NULL; + + if (dcn315_resource_construct(init_data->num_virtual_links, dc, pool)) + return &pool->base; + + BREAK_TO_DEBUGGER(); + kfree(pool); + return NULL; +} diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.h new file mode 100644 index 00000000000000..22849eaa6f243e --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.h @@ -0,0 +1,44 @@ +/* + * 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 _DCN315_RESOURCE_H_ +#define _DCN315_RESOURCE_H_ + +#include "core_types.h" + +#define TO_DCN315_RES_POOL(pool)\ + container_of(pool, struct dcn315_resource_pool, base) + +extern struct _vcs_dpi_ip_params_st dcn3_15_ip; + +struct dcn315_resource_pool { + struct resource_pool base; +}; + +struct resource_pool *dcn315_create_resource_pool( + const struct dc_init_data *init_data, + struct dc *dc); + +#endif /* _DCN315_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c new file mode 100644 index 00000000000000..b9753d4606f89d --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c @@ -0,0 +1,2038 @@ +/* + * 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 "dm_services.h" +#include "dc.h" + +#include "dcn31/dcn31_init.h" + +#include "resource.h" +#include "include/irq_service_interface.h" +#include "dcn316_resource.h" + +#include "dcn20/dcn20_resource.h" +#include "dcn30/dcn30_resource.h" +#include "dcn31/dcn31_resource.h" + +#include "dcn10/dcn10_ipp.h" +#include "dcn30/dcn30_hubbub.h" +#include "dcn31/dcn31_hubbub.h" +#include "dcn30/dcn30_mpc.h" +#include "dcn31/dcn31_hubp.h" +#include "irq/dcn31/irq_service_dcn31.h" +#include "dcn30/dcn30_dpp.h" +#include "dcn31/dcn31_optc.h" +#include "dcn20/dcn20_hwseq.h" +#include "dcn30/dcn30_hwseq.h" +#include "dce110/dce110_hwseq.h" +#include "dcn30/dcn30_opp.h" +#include "dcn20/dcn20_dsc.h" +#include "dcn30/dcn30_vpg.h" +#include "dcn30/dcn30_afmt.h" +#include "dcn30/dcn30_dio_stream_encoder.h" +#include "dcn31/dcn31_hpo_dp_stream_encoder.h" +#include "dcn31/dcn31_hpo_dp_link_encoder.h" +#include "dcn31/dcn31_apg.h" +#include "dcn31/dcn31_dio_link_encoder.h" +#include "dcn31/dcn31_vpg.h" +#include "dcn31/dcn31_afmt.h" +#include "dce/dce_clock_source.h" +#include "dce/dce_audio.h" +#include "dce/dce_hwseq.h" +#include "clk_mgr.h" +#include "virtual/virtual_stream_encoder.h" +#include "dce110/dce110_resource.h" +#include "dml/display_mode_vba.h" +#include "dml/dcn31/dcn31_fpu.h" +#include "dcn31/dcn31_dccg.h" +#include "dcn10/dcn10_resource.h" +#include "dcn31/dcn31_panel_cntl.h" + +#include "dcn30/dcn30_dwb.h" +#include "dcn30/dcn30_mmhubbub.h" + +#include "dcn/dcn_3_1_6_offset.h" +#include "dcn/dcn_3_1_6_sh_mask.h" +#include "dpcs/dpcs_4_2_3_offset.h" +#include "dpcs/dpcs_4_2_3_sh_mask.h" + +#define regBIF_BX1_BIOS_SCRATCH_2 0x003a +#define regBIF_BX1_BIOS_SCRATCH_2_BASE_IDX 1 +#define regBIF_BX1_BIOS_SCRATCH_3 0x003b +#define regBIF_BX1_BIOS_SCRATCH_3_BASE_IDX 1 +#define regBIF_BX1_BIOS_SCRATCH_6 0x003e +#define regBIF_BX1_BIOS_SCRATCH_6_BASE_IDX 1 + +#define regDCHUBBUB_DEBUG_CTRL_0 0x04d6 +#define regDCHUBBUB_DEBUG_CTRL_0_BASE_IDX 2 +#define DCHUBBUB_DEBUG_CTRL_0__DET_DEPTH__SHIFT 0x10 +#define DCHUBBUB_DEBUG_CTRL_0__DET_DEPTH_MASK 0x01FF0000L + +#define DCN_BASE__INST0_SEG0 0x00000012 +#define DCN_BASE__INST0_SEG1 0x000000C0 +#define DCN_BASE__INST0_SEG2 0x000034C0 +#define DCN_BASE__INST0_SEG3 0x00009000 +#define DCN_BASE__INST0_SEG4 0x02403C00 +#define DCN_BASE__INST0_SEG5 0 + +#define DPCS_BASE__INST0_SEG0 0x00000012 +#define DPCS_BASE__INST0_SEG1 0x000000C0 +#define DPCS_BASE__INST0_SEG2 0x000034C0 +#define DPCS_BASE__INST0_SEG3 0x00009000 +#define DPCS_BASE__INST0_SEG4 0x02403C00 +#define DPCS_BASE__INST0_SEG5 0 + +#define NBIO_BASE__INST0_SEG0 0x00000000 +#define NBIO_BASE__INST0_SEG1 0x00000014 +#define NBIO_BASE__INST0_SEG2 0x00000D20 +#define NBIO_BASE__INST0_SEG3 0x00010400 +#define NBIO_BASE__INST0_SEG4 0x0241B000 +#define NBIO_BASE__INST0_SEG5 0x04040000 + +#include "reg_helper.h" +#include "dce/dmub_abm.h" +#include "dce/dmub_psr.h" +#include "dce/dce_aux.h" +#include "dce/dce_i2c.h" + +#include "dml/dcn30/display_mode_vba_30.h" +#include "vm_helper.h" +#include "dcn20/dcn20_vmid.h" + +#include "link_enc_cfg.h" + +#define DCN3_16_MAX_DET_SIZE 384 +#define DCN3_16_MIN_COMPBUF_SIZE_KB 128 +#define DCN3_16_CRB_SEGMENT_SIZE_KB 64 + +enum dcn31_clk_src_array_id { + DCN31_CLK_SRC_PLL0, + DCN31_CLK_SRC_PLL1, + DCN31_CLK_SRC_PLL2, + DCN31_CLK_SRC_PLL3, + DCN31_CLK_SRC_PLL4, + DCN30_CLK_SRC_TOTAL +}; + +/* begin ********************* + * macros to expend register list macro defined in HW object header file + */ + +/* DCN */ +#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg + +#define BASE(seg) BASE_INNER(seg) + +#define SR(reg_name)\ + .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ + reg ## reg_name + +#define SRI(reg_name, block, id)\ + .reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRI2(reg_name, block, id)\ + .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ + reg ## reg_name + +#define SRIR(var_name, reg_name, block, id)\ + .var_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRII(reg_name, block, id)\ + .reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRII_MPC_RMU(reg_name, block, id)\ + .RMU##_##reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRII_DWB(reg_name, temp_name, block, id)\ + .reg_name[id] = BASE(reg ## block ## id ## _ ## temp_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## temp_name + +#define SF_DWB2(reg_name, block, id, field_name, post_fix) \ + .field_name = reg_name ## __ ## field_name ## post_fix + +#define DCCG_SRII(reg_name, block, id)\ + .block ## _ ## reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define VUPDATE_SRII(reg_name, block, id)\ + .reg_name[id] = BASE(reg ## reg_name ## _ ## block ## id ## _BASE_IDX) + \ + reg ## reg_name ## _ ## block ## id + +/* NBIO */ +#define NBIO_BASE_INNER(seg) \ + NBIO_BASE__INST0_SEG ## seg + +#define NBIO_BASE(seg) \ + NBIO_BASE_INNER(seg) + +#define NBIO_SR(reg_name)\ + .reg_name = NBIO_BASE(regBIF_BX1_ ## reg_name ## _BASE_IDX) + \ + regBIF_BX1_ ## reg_name + +static const struct bios_registers bios_regs = { + NBIO_SR(BIOS_SCRATCH_3), + NBIO_SR(BIOS_SCRATCH_6) +}; + +#define clk_src_regs(index, pllid)\ +[index] = {\ + CS_COMMON_REG_LIST_DCN3_0(index, pllid),\ +} + +static const struct dce110_clk_src_regs clk_src_regs[] = { + clk_src_regs(0, A), + clk_src_regs(1, B), + clk_src_regs(2, C), + clk_src_regs(3, D), + clk_src_regs(4, E) +}; + +static const struct dce110_clk_src_shift cs_shift = { + CS_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT) +}; + +static const struct dce110_clk_src_mask cs_mask = { + CS_COMMON_MASK_SH_LIST_DCN2_0(_MASK) +}; + +#define abm_regs(id)\ +[id] = {\ + ABM_DCN302_REG_LIST(id)\ +} + +static const struct dce_abm_registers abm_regs[] = { + abm_regs(0), + abm_regs(1), + abm_regs(2), + abm_regs(3), +}; + +static const struct dce_abm_shift abm_shift = { + ABM_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dce_abm_mask abm_mask = { + ABM_MASK_SH_LIST_DCN30(_MASK) +}; + +#define audio_regs(id)\ +[id] = {\ + AUD_COMMON_REG_LIST(id)\ +} + +static const struct dce_audio_registers audio_regs[] = { + audio_regs(0), + audio_regs(1), + audio_regs(2), + audio_regs(3), + audio_regs(4), + audio_regs(5), + audio_regs(6) +}; + +#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ + AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) + +static const struct dce_audio_shift audio_shift = { + DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_audio_mask audio_mask = { + DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) +}; + +#define vpg_regs(id)\ +[id] = {\ + VPG_DCN31_REG_LIST(id)\ +} + +static const struct dcn31_vpg_registers vpg_regs[] = { + vpg_regs(0), + vpg_regs(1), + vpg_regs(2), + vpg_regs(3), + vpg_regs(4), + vpg_regs(5), + vpg_regs(6), + vpg_regs(7), + vpg_regs(8), + vpg_regs(9), +}; + +static const struct dcn31_vpg_shift vpg_shift = { + DCN31_VPG_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn31_vpg_mask vpg_mask = { + DCN31_VPG_MASK_SH_LIST(_MASK) +}; + +#define afmt_regs(id)\ +[id] = {\ + AFMT_DCN31_REG_LIST(id)\ +} + +static const struct dcn31_afmt_registers afmt_regs[] = { + afmt_regs(0), + afmt_regs(1), + afmt_regs(2), + afmt_regs(3), + afmt_regs(4), + afmt_regs(5) +}; + +static const struct dcn31_afmt_shift afmt_shift = { + DCN31_AFMT_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn31_afmt_mask afmt_mask = { + DCN31_AFMT_MASK_SH_LIST(_MASK) +}; + + +#define apg_regs(id)\ +[id] = {\ + APG_DCN31_REG_LIST(id)\ +} + +static const struct dcn31_apg_registers apg_regs[] = { + apg_regs(0), + apg_regs(1), + apg_regs(2), + apg_regs(3) +}; + +static const struct dcn31_apg_shift apg_shift = { + DCN31_APG_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn31_apg_mask apg_mask = { + DCN31_APG_MASK_SH_LIST(_MASK) +}; + + +#define stream_enc_regs(id)\ +[id] = {\ + SE_DCN3_REG_LIST(id)\ +} + +static const struct dcn10_stream_enc_registers stream_enc_regs[] = { + stream_enc_regs(0), + stream_enc_regs(1), + stream_enc_regs(2), + stream_enc_regs(3), + stream_enc_regs(4) +}; + +static const struct dcn10_stream_encoder_shift se_shift = { + SE_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn10_stream_encoder_mask se_mask = { + SE_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + + +#define aux_regs(id)\ +[id] = {\ + DCN2_AUX_REG_LIST(id)\ +} + +static const struct dcn10_link_enc_aux_registers link_enc_aux_regs[] = { + aux_regs(0), + aux_regs(1), + aux_regs(2), + aux_regs(3), + aux_regs(4) +}; + +#define hpd_regs(id)\ +[id] = {\ + HPD_REG_LIST(id)\ +} + +static const struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[] = { + hpd_regs(0), + hpd_regs(1), + hpd_regs(2), + hpd_regs(3), + hpd_regs(4) +}; + +#define link_regs(id, phyid)\ +[id] = {\ + LE_DCN31_REG_LIST(id), \ + UNIPHY_DCN2_REG_LIST(phyid), \ + DPCS_DCN31_REG_LIST(id), \ +} + +static const struct dce110_aux_registers_shift aux_shift = { + DCN_AUX_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce110_aux_registers_mask aux_mask = { + DCN_AUX_MASK_SH_LIST(_MASK) +}; + +static const struct dcn10_link_enc_registers link_enc_regs[] = { + link_regs(0, A), + link_regs(1, B), + link_regs(2, C), + link_regs(3, D), + link_regs(4, E) +}; + +static const struct dcn10_link_enc_shift le_shift = { + LINK_ENCODER_MASK_SH_LIST_DCN31(__SHIFT), \ + DPCS_DCN31_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn10_link_enc_mask le_mask = { + LINK_ENCODER_MASK_SH_LIST_DCN31(_MASK), \ + DPCS_DCN31_MASK_SH_LIST(_MASK) +}; + + + +#define hpo_dp_stream_encoder_reg_list(id)\ +[id] = {\ + DCN3_1_HPO_DP_STREAM_ENC_REG_LIST(id)\ +} + +static const struct dcn31_hpo_dp_stream_encoder_registers hpo_dp_stream_enc_regs[] = { + hpo_dp_stream_encoder_reg_list(0), + hpo_dp_stream_encoder_reg_list(1), + hpo_dp_stream_encoder_reg_list(2), + hpo_dp_stream_encoder_reg_list(3), +}; + +static const struct dcn31_hpo_dp_stream_encoder_shift hpo_dp_se_shift = { + DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn31_hpo_dp_stream_encoder_mask hpo_dp_se_mask = { + DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(_MASK) +}; + + +#define hpo_dp_link_encoder_reg_list(id)\ +[id] = {\ + DCN3_1_HPO_DP_LINK_ENC_REG_LIST(id),\ + DCN3_1_RDPCSTX_REG_LIST(0),\ + DCN3_1_RDPCSTX_REG_LIST(1),\ + DCN3_1_RDPCSTX_REG_LIST(2),\ + DCN3_1_RDPCSTX_REG_LIST(3),\ + DCN3_1_RDPCSTX_REG_LIST(4)\ +} + +static const struct dcn31_hpo_dp_link_encoder_registers hpo_dp_link_enc_regs[] = { + hpo_dp_link_encoder_reg_list(0), + hpo_dp_link_encoder_reg_list(1), +}; + +static const struct dcn31_hpo_dp_link_encoder_shift hpo_dp_le_shift = { + DCN3_1_HPO_DP_LINK_ENC_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn31_hpo_dp_link_encoder_mask hpo_dp_le_mask = { + DCN3_1_HPO_DP_LINK_ENC_MASK_SH_LIST(_MASK) +}; + + +#define dpp_regs(id)\ +[id] = {\ + DPP_REG_LIST_DCN30(id),\ +} + +static const struct dcn3_dpp_registers dpp_regs[] = { + dpp_regs(0), + dpp_regs(1), + dpp_regs(2), + dpp_regs(3) +}; + +static const struct dcn3_dpp_shift tf_shift = { + DPP_REG_LIST_SH_MASK_DCN30(__SHIFT) +}; + +static const struct dcn3_dpp_mask tf_mask = { + DPP_REG_LIST_SH_MASK_DCN30(_MASK) +}; + +#define opp_regs(id)\ +[id] = {\ + OPP_REG_LIST_DCN30(id),\ +} + +static const struct dcn20_opp_registers opp_regs[] = { + opp_regs(0), + opp_regs(1), + opp_regs(2), + opp_regs(3) +}; + +static const struct dcn20_opp_shift opp_shift = { + OPP_MASK_SH_LIST_DCN20(__SHIFT) +}; + +static const struct dcn20_opp_mask opp_mask = { + OPP_MASK_SH_LIST_DCN20(_MASK) +}; + +#define aux_engine_regs(id)\ +[id] = {\ + AUX_COMMON_REG_LIST0(id), \ + .AUXN_IMPCAL = 0, \ + .AUXP_IMPCAL = 0, \ + .AUX_RESET_MASK = DP_AUX0_AUX_CONTROL__AUX_RESET_MASK, \ +} + +static const struct dce110_aux_registers aux_engine_regs[] = { + aux_engine_regs(0), + aux_engine_regs(1), + aux_engine_regs(2), + aux_engine_regs(3), + aux_engine_regs(4) +}; + +#define dwbc_regs_dcn3(id)\ +[id] = {\ + DWBC_COMMON_REG_LIST_DCN30(id),\ +} + +static const struct dcn30_dwbc_registers dwbc30_regs[] = { + dwbc_regs_dcn3(0), +}; + +static const struct dcn30_dwbc_shift dwbc30_shift = { + DWBC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn30_dwbc_mask dwbc30_mask = { + DWBC_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +#define mcif_wb_regs_dcn3(id)\ +[id] = {\ + MCIF_WB_COMMON_REG_LIST_DCN30(id),\ +} + +static const struct dcn30_mmhubbub_registers mcif_wb30_regs[] = { + mcif_wb_regs_dcn3(0) +}; + +static const struct dcn30_mmhubbub_shift mcif_wb30_shift = { + MCIF_WB_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn30_mmhubbub_mask mcif_wb30_mask = { + MCIF_WB_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +#define dsc_regsDCN20(id)\ +[id] = {\ + DSC_REG_LIST_DCN20(id)\ +} + +static const struct dcn20_dsc_registers dsc_regs[] = { + dsc_regsDCN20(0), + dsc_regsDCN20(1), + dsc_regsDCN20(2) +}; + +static const struct dcn20_dsc_shift dsc_shift = { + DSC_REG_LIST_SH_MASK_DCN20(__SHIFT) +}; + +static const struct dcn20_dsc_mask dsc_mask = { + DSC_REG_LIST_SH_MASK_DCN20(_MASK) +}; + +static const struct dcn30_mpc_registers mpc_regs = { + MPC_REG_LIST_DCN3_0(0), + MPC_REG_LIST_DCN3_0(1), + MPC_REG_LIST_DCN3_0(2), + MPC_REG_LIST_DCN3_0(3), + MPC_OUT_MUX_REG_LIST_DCN3_0(0), + MPC_OUT_MUX_REG_LIST_DCN3_0(1), + MPC_OUT_MUX_REG_LIST_DCN3_0(2), + MPC_OUT_MUX_REG_LIST_DCN3_0(3), + MPC_RMU_GLOBAL_REG_LIST_DCN3AG, + MPC_RMU_REG_LIST_DCN3AG(0), + MPC_RMU_REG_LIST_DCN3AG(1), + //MPC_RMU_REG_LIST_DCN3AG(2), + MPC_DWB_MUX_REG_LIST_DCN3_0(0), +}; + +static const struct dcn30_mpc_shift mpc_shift = { + MPC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn30_mpc_mask mpc_mask = { + MPC_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +#define optc_regs(id)\ +[id] = {OPTC_COMMON_REG_LIST_DCN3_1(id)} + +static const struct dcn_optc_registers optc_regs[] = { + optc_regs(0), + optc_regs(1), + optc_regs(2), + optc_regs(3) +}; + +static const struct dcn_optc_shift optc_shift = { + OPTC_COMMON_MASK_SH_LIST_DCN3_1(__SHIFT) +}; + +static const struct dcn_optc_mask optc_mask = { + OPTC_COMMON_MASK_SH_LIST_DCN3_1(_MASK) +}; + +#define hubp_regs(id)\ +[id] = {\ + HUBP_REG_LIST_DCN30(id)\ +} + +static const struct dcn_hubp2_registers hubp_regs[] = { + hubp_regs(0), + hubp_regs(1), + hubp_regs(2), + hubp_regs(3) +}; + + +static const struct dcn_hubp2_shift hubp_shift = { + HUBP_MASK_SH_LIST_DCN31(__SHIFT) +}; + +static const struct dcn_hubp2_mask hubp_mask = { + HUBP_MASK_SH_LIST_DCN31(_MASK) +}; +static const struct dcn_hubbub_registers hubbub_reg = { + HUBBUB_REG_LIST_DCN31(0) +}; + +static const struct dcn_hubbub_shift hubbub_shift = { + HUBBUB_MASK_SH_LIST_DCN31(__SHIFT) +}; + +static const struct dcn_hubbub_mask hubbub_mask = { + HUBBUB_MASK_SH_LIST_DCN31(_MASK) +}; + +static const struct dccg_registers dccg_regs = { + DCCG_REG_LIST_DCN31() +}; + +static const struct dccg_shift dccg_shift = { + DCCG_MASK_SH_LIST_DCN31(__SHIFT) +}; + +static const struct dccg_mask dccg_mask = { + DCCG_MASK_SH_LIST_DCN31(_MASK) +}; + + +#define SRII2(reg_name_pre, reg_name_post, id)\ + .reg_name_pre ## _ ## reg_name_post[id] = BASE(reg ## reg_name_pre \ + ## id ## _ ## reg_name_post ## _BASE_IDX) + \ + reg ## reg_name_pre ## id ## _ ## reg_name_post + + +#define HWSEQ_DCN31_REG_LIST()\ + SR(DCHUBBUB_GLOBAL_TIMER_CNTL), \ + SR(DCHUBBUB_ARB_HOSTVM_CNTL), \ + SR(DIO_MEM_PWR_CTRL), \ + SR(ODM_MEM_PWR_CTRL3), \ + SR(DMU_MEM_PWR_CNTL), \ + SR(MMHUBBUB_MEM_PWR_CNTL), \ + SR(DCCG_GATE_DISABLE_CNTL), \ + SR(DCCG_GATE_DISABLE_CNTL2), \ + SR(DCFCLK_CNTL),\ + SR(DC_MEM_GLOBAL_PWR_REQ_CNTL), \ + SRII(PIXEL_RATE_CNTL, OTG, 0), \ + SRII(PIXEL_RATE_CNTL, OTG, 1),\ + SRII(PIXEL_RATE_CNTL, OTG, 2),\ + SRII(PIXEL_RATE_CNTL, OTG, 3),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 0),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 1),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 2),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 3),\ + SR(MICROSECOND_TIME_BASE_DIV), \ + SR(MILLISECOND_TIME_BASE_DIV), \ + SR(DISPCLK_FREQ_CHANGE_CNTL), \ + SR(RBBMIF_TIMEOUT_DIS), \ + SR(RBBMIF_TIMEOUT_DIS_2), \ + SR(DCHUBBUB_CRC_CTRL), \ + SR(DPP_TOP0_DPP_CRC_CTRL), \ + SR(DPP_TOP0_DPP_CRC_VAL_B_A), \ + SR(DPP_TOP0_DPP_CRC_VAL_R_G), \ + SR(MPC_CRC_CTRL), \ + SR(MPC_CRC_RESULT_GB), \ + SR(MPC_CRC_RESULT_C), \ + SR(MPC_CRC_RESULT_AR), \ + SR(DOMAIN0_PG_CONFIG), \ + SR(DOMAIN1_PG_CONFIG), \ + SR(DOMAIN2_PG_CONFIG), \ + SR(DOMAIN3_PG_CONFIG), \ + SR(DOMAIN16_PG_CONFIG), \ + SR(DOMAIN17_PG_CONFIG), \ + SR(DOMAIN18_PG_CONFIG), \ + SR(DOMAIN0_PG_STATUS), \ + SR(DOMAIN1_PG_STATUS), \ + SR(DOMAIN2_PG_STATUS), \ + SR(DOMAIN3_PG_STATUS), \ + SR(DOMAIN16_PG_STATUS), \ + SR(DOMAIN17_PG_STATUS), \ + SR(DOMAIN18_PG_STATUS), \ + SR(D1VGA_CONTROL), \ + SR(D2VGA_CONTROL), \ + SR(D3VGA_CONTROL), \ + SR(D4VGA_CONTROL), \ + SR(D5VGA_CONTROL), \ + SR(D6VGA_CONTROL), \ + SR(DC_IP_REQUEST_CNTL), \ + SR(AZALIA_AUDIO_DTO), \ + SR(AZALIA_CONTROLLER_CLOCK_GATING), \ + SR(HPO_TOP_HW_CONTROL) + +static const struct dce_hwseq_registers hwseq_reg = { + HWSEQ_DCN31_REG_LIST() +}; + +#define HWSEQ_DCN31_MASK_SH_LIST(mask_sh)\ + HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ + HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \ + HWS_SF(, DCHUBBUB_ARB_HOSTVM_CNTL, DISABLE_HOSTVM_FORCE_ALLOW_PSTATE, mask_sh), \ + HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN16_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN17_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN18_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \ + HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh), \ + HWS_SF(, HPO_TOP_CLOCK_CONTROL, HPO_HDMISTREAMCLK_G_GATE_DIS, mask_sh), \ + HWS_SF(, DMU_MEM_PWR_CNTL, DMCU_ERAM_MEM_PWR_FORCE, mask_sh), \ + HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_UNASSIGNED_PWR_MODE, mask_sh), \ + HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_VBLANK_PWR_MODE, mask_sh), \ + HWS_SF(, MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, mask_sh), \ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh), \ + HWS_SF(, HPO_TOP_HW_CONTROL, HPO_IO_EN, mask_sh) + +static const struct dce_hwseq_shift hwseq_shift = { + HWSEQ_DCN31_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_hwseq_mask hwseq_mask = { + HWSEQ_DCN31_MASK_SH_LIST(_MASK) +}; +#define vmid_regs(id)\ +[id] = {\ + DCN20_VMID_REG_LIST(id)\ +} + +static const struct dcn_vmid_registers vmid_regs[] = { + vmid_regs(0), + vmid_regs(1), + vmid_regs(2), + vmid_regs(3), + vmid_regs(4), + vmid_regs(5), + vmid_regs(6), + vmid_regs(7), + vmid_regs(8), + vmid_regs(9), + vmid_regs(10), + vmid_regs(11), + vmid_regs(12), + vmid_regs(13), + vmid_regs(14), + vmid_regs(15) +}; + +static const struct dcn20_vmid_shift vmid_shifts = { + DCN20_VMID_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn20_vmid_mask vmid_masks = { + DCN20_VMID_MASK_SH_LIST(_MASK) +}; + +static const struct resource_caps res_cap_dcn31 = { + .num_timing_generator = 4, + .num_opp = 4, + .num_video_plane = 4, + .num_audio = 5, + .num_stream_encoder = 5, + .num_dig_link_enc = 5, + .num_hpo_dp_stream_encoder = 4, + .num_hpo_dp_link_encoder = 2, + .num_pll = 5, + .num_dwb = 1, + .num_ddc = 5, + .num_vmid = 16, + .num_mpc_3dlut = 2, + .num_dsc = 3, +}; + +static const struct dc_plane_cap plane_cap = { + .type = DC_PLANE_TYPE_DCN_UNIVERSAL, + .per_pixel_alpha = true, + + .pixel_format_support = { + .argb8888 = true, + .nv12 = true, + .fp16 = true, + .p010 = true, + .ayuv = false, + }, + + .max_upscale_factor = { + .argb8888 = 16000, + .nv12 = 16000, + .fp16 = 16000 + }, + + // 6:1 downscaling ratio: 1000/6 = 166.666 + .max_downscale_factor = { + .argb8888 = 167, + .nv12 = 167, + .fp16 = 167 + }, + 64, + 64 +}; + +static const struct dc_debug_options debug_defaults_drv = { + .disable_z10 = true, /*hw not support it*/ + .disable_dmcu = true, + .force_abm_enable = false, + .timing_trace = false, + .clock_trace = true, + .disable_pplib_clock_request = false, + .pipe_split_policy = MPC_SPLIT_DYNAMIC, + .force_single_disp_pipe_split = false, + .disable_dcc = DCC_ENABLE, + .vsr_support = true, + .performance_trace = false, + .max_downscale_src_width = 4096,/*upto true 4k*/ + .disable_pplib_wm_range = false, + .scl_reset_length10 = true, + .sanity_checks = false, + .underflow_assert_delay_us = 0xFFFFFFFF, + .dwb_fi_phase = -1, // -1 = disable, + .dmub_command_table = true, + .pstate_enabled = true, + .use_max_lb = true, + .enable_mem_low_power = { + .bits = { + .vga = true, + .i2c = true, + .dmcu = false, // This is previously known to cause hang on S3 cycles if enabled + .dscl = true, + .cm = true, + .mpc = true, + .optc = true, + .vpg = true, + .afmt = true, + } + }, + .enable_legacy_fast_update = true, + .using_dml2 = false, +}; + +static const struct dc_panel_config panel_config_defaults = { + .psr = { + .disable_psr = false, + .disallow_psrsu = false, + .disallow_replay = false, + }, + .ilr = { + .optimize_edp_link_rate = true, + }, +}; + +static void dcn31_dpp_destroy(struct dpp **dpp) +{ + kfree(TO_DCN20_DPP(*dpp)); + *dpp = NULL; +} + +static struct dpp *dcn31_dpp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn3_dpp *dpp = + kzalloc(sizeof(struct dcn3_dpp), GFP_KERNEL); + + if (!dpp) + return NULL; + + if (dpp3_construct(dpp, ctx, inst, + &dpp_regs[inst], &tf_shift, &tf_mask)) + return &dpp->base; + + BREAK_TO_DEBUGGER(); + kfree(dpp); + return NULL; +} + +static struct output_pixel_processor *dcn31_opp_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dcn20_opp *opp = + kzalloc(sizeof(struct dcn20_opp), GFP_KERNEL); + + if (!opp) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dcn20_opp_construct(opp, ctx, inst, + &opp_regs[inst], &opp_shift, &opp_mask); + return &opp->base; +} + +static struct dce_aux *dcn31_aux_engine_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct aux_engine_dce110 *aux_engine = + kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); + + if (!aux_engine) + return NULL; + + dce110_aux_engine_construct(aux_engine, ctx, inst, + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, + &aux_engine_regs[inst], + &aux_mask, + &aux_shift, + ctx->dc->caps.extended_aux_timeout_support); + + return &aux_engine->base; +} +#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST_DCN30(id) } + +static const struct dce_i2c_registers i2c_hw_regs[] = { + i2c_inst_regs(1), + i2c_inst_regs(2), + i2c_inst_regs(3), + i2c_inst_regs(4), + i2c_inst_regs(5), +}; + +static const struct dce_i2c_shift i2c_shifts = { + I2C_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dce_i2c_mask i2c_masks = { + I2C_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +static struct dce_i2c_hw *dcn31_i2c_hw_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce_i2c_hw *dce_i2c_hw = + kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); + + if (!dce_i2c_hw) + return NULL; + + dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst, + &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); + + return dce_i2c_hw; +} +static struct mpc *dcn31_mpc_create( + struct dc_context *ctx, + int num_mpcc, + int num_rmu) +{ + struct dcn30_mpc *mpc30 = kzalloc(sizeof(struct dcn30_mpc), + GFP_KERNEL); + + if (!mpc30) + return NULL; + + dcn30_mpc_construct(mpc30, ctx, + &mpc_regs, + &mpc_shift, + &mpc_mask, + num_mpcc, + num_rmu); + + return &mpc30->base; +} + +static struct hubbub *dcn31_hubbub_create(struct dc_context *ctx) +{ + int i; + + struct dcn20_hubbub *hubbub3 = kzalloc(sizeof(struct dcn20_hubbub), + GFP_KERNEL); + + if (!hubbub3) + return NULL; + + hubbub31_construct(hubbub3, ctx, + &hubbub_reg, + &hubbub_shift, + &hubbub_mask, + dcn3_16_ip.det_buffer_size_kbytes, + dcn3_16_ip.pixel_chunk_size_kbytes, + dcn3_16_ip.config_return_buffer_size_in_kbytes); + + + for (i = 0; i < res_cap_dcn31.num_vmid; i++) { + struct dcn20_vmid *vmid = &hubbub3->vmid[i]; + + vmid->ctx = ctx; + + vmid->regs = &vmid_regs[i]; + vmid->shifts = &vmid_shifts; + vmid->masks = &vmid_masks; + } + + return &hubbub3->base; +} + +static struct timing_generator *dcn31_timing_generator_create( + struct dc_context *ctx, + uint32_t instance) +{ + struct optc *tgn10 = + kzalloc(sizeof(struct optc), GFP_KERNEL); + + if (!tgn10) + return NULL; + + tgn10->base.inst = instance; + tgn10->base.ctx = ctx; + + tgn10->tg_regs = &optc_regs[instance]; + tgn10->tg_shift = &optc_shift; + tgn10->tg_mask = &optc_mask; + + dcn31_timing_generator_init(tgn10); + + return &tgn10->base; +} + +static const struct encoder_feature_support link_enc_feature = { + .max_hdmi_deep_color = COLOR_DEPTH_121212, + .max_hdmi_pixel_clock = 600000, + .hdmi_ycbcr420_supported = true, + .dp_ycbcr420_supported = true, + .fec_supported = true, + .flags.bits.IS_HBR2_CAPABLE = true, + .flags.bits.IS_HBR3_CAPABLE = true, + .flags.bits.IS_TPS3_CAPABLE = true, + .flags.bits.IS_TPS4_CAPABLE = true +}; + +static struct link_encoder *dcn31_link_encoder_create( + struct dc_context *ctx, + const struct encoder_init_data *enc_init_data) +{ + struct dcn20_link_encoder *enc20 = + kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); + + if (!enc20) + return NULL; + + dcn31_link_encoder_construct(enc20, + enc_init_data, + &link_enc_feature, + &link_enc_regs[enc_init_data->transmitter], + &link_enc_aux_regs[enc_init_data->channel - 1], + &link_enc_hpd_regs[enc_init_data->hpd_source], + &le_shift, + &le_mask); + + return &enc20->enc10.base; +} + +/* Create a minimal link encoder object not associated with a particular + * physical connector. + * resource_funcs.link_enc_create_minimal + */ +static struct link_encoder *dcn31_link_enc_create_minimal( + struct dc_context *ctx, enum engine_id eng_id) +{ + struct dcn20_link_encoder *enc20; + + if ((eng_id - ENGINE_ID_DIGA) > ctx->dc->res_pool->res_cap->num_dig_link_enc) + return NULL; + + enc20 = kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); + if (!enc20) + return NULL; + + dcn31_link_encoder_construct_minimal( + enc20, + ctx, + &link_enc_feature, + &link_enc_regs[eng_id - ENGINE_ID_DIGA], + eng_id); + + return &enc20->enc10.base; +} + +static struct panel_cntl *dcn31_panel_cntl_create(const struct panel_cntl_init_data *init_data) +{ + struct dcn31_panel_cntl *panel_cntl = + kzalloc(sizeof(struct dcn31_panel_cntl), GFP_KERNEL); + + if (!panel_cntl) + return NULL; + + dcn31_panel_cntl_construct(panel_cntl, init_data); + + return &panel_cntl->base; +} + +static void read_dce_straps( + struct dc_context *ctx, + struct resource_straps *straps) +{ + generic_reg_get(ctx, regDC_PINSTRAPS + BASE(regDC_PINSTRAPS_BASE_IDX), + FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio); + +} + +static struct audio *dcn31_create_audio( + struct dc_context *ctx, unsigned int inst) +{ + return dce_audio_create(ctx, inst, + &audio_regs[inst], &audio_shift, &audio_mask); +} + +static struct vpg *dcn31_vpg_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn31_vpg *vpg31 = kzalloc(sizeof(struct dcn31_vpg), GFP_KERNEL); + + if (!vpg31) + return NULL; + + vpg31_construct(vpg31, ctx, inst, + &vpg_regs[inst], + &vpg_shift, + &vpg_mask); + + return &vpg31->base; +} + +static struct afmt *dcn31_afmt_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn31_afmt *afmt31 = kzalloc(sizeof(struct dcn31_afmt), GFP_KERNEL); + + if (!afmt31) + return NULL; + + afmt31_construct(afmt31, ctx, inst, + &afmt_regs[inst], + &afmt_shift, + &afmt_mask); + + // Light sleep by default, no need to power down here + + return &afmt31->base; +} + + +static struct apg *dcn31_apg_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn31_apg *apg31 = kzalloc(sizeof(struct dcn31_apg), GFP_KERNEL); + + if (!apg31) + return NULL; + + apg31_construct(apg31, ctx, inst, + &apg_regs[inst], + &apg_shift, + &apg_mask); + + return &apg31->base; +} + + +static struct stream_encoder *dcn316_stream_encoder_create( + enum engine_id eng_id, + struct dc_context *ctx) +{ + struct dcn10_stream_encoder *enc1; + struct vpg *vpg; + struct afmt *afmt; + int vpg_inst; + int afmt_inst; + + /* Mapping of VPG, AFMT, DME register blocks to DIO block instance */ + if (eng_id <= ENGINE_ID_DIGF) { + vpg_inst = eng_id; + afmt_inst = eng_id; + } else + return NULL; + + enc1 = kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL); + vpg = dcn31_vpg_create(ctx, vpg_inst); + afmt = dcn31_afmt_create(ctx, afmt_inst); + + if (!enc1 || !vpg || !afmt) { + kfree(enc1); + kfree(vpg); + kfree(afmt); + return NULL; + } + + dcn30_dio_stream_encoder_construct(enc1, ctx, ctx->dc_bios, + eng_id, vpg, afmt, + &stream_enc_regs[eng_id], + &se_shift, &se_mask); + + return &enc1->base; +} + + +static struct hpo_dp_stream_encoder *dcn31_hpo_dp_stream_encoder_create( + enum engine_id eng_id, + struct dc_context *ctx) +{ + struct dcn31_hpo_dp_stream_encoder *hpo_dp_enc31; + struct vpg *vpg; + struct apg *apg; + uint32_t hpo_dp_inst; + uint32_t vpg_inst; + uint32_t apg_inst; + + ASSERT((eng_id >= ENGINE_ID_HPO_DP_0) && (eng_id <= ENGINE_ID_HPO_DP_3)); + hpo_dp_inst = eng_id - ENGINE_ID_HPO_DP_0; + + /* Mapping of VPG register blocks to HPO DP block instance: + * VPG[6] -> HPO_DP[0] + * VPG[7] -> HPO_DP[1] + * VPG[8] -> HPO_DP[2] + * VPG[9] -> HPO_DP[3] + */ + vpg_inst = hpo_dp_inst + 6; + + /* Mapping of APG register blocks to HPO DP block instance: + * APG[0] -> HPO_DP[0] + * APG[1] -> HPO_DP[1] + * APG[2] -> HPO_DP[2] + * APG[3] -> HPO_DP[3] + */ + apg_inst = hpo_dp_inst; + + /* allocate HPO stream encoder and create VPG sub-block */ + hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_stream_encoder), GFP_KERNEL); + vpg = dcn31_vpg_create(ctx, vpg_inst); + apg = dcn31_apg_create(ctx, apg_inst); + + if (!hpo_dp_enc31 || !vpg || !apg) { + kfree(hpo_dp_enc31); + kfree(vpg); + kfree(apg); + return NULL; + } + + dcn31_hpo_dp_stream_encoder_construct(hpo_dp_enc31, ctx, ctx->dc_bios, + hpo_dp_inst, eng_id, vpg, apg, + &hpo_dp_stream_enc_regs[hpo_dp_inst], + &hpo_dp_se_shift, &hpo_dp_se_mask); + + return &hpo_dp_enc31->base; +} + +static struct hpo_dp_link_encoder *dcn31_hpo_dp_link_encoder_create( + uint8_t inst, + struct dc_context *ctx) +{ + struct dcn31_hpo_dp_link_encoder *hpo_dp_enc31; + + /* allocate HPO link encoder */ + hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_link_encoder), GFP_KERNEL); + + hpo_dp_link_encoder31_construct(hpo_dp_enc31, ctx, inst, + &hpo_dp_link_enc_regs[inst], + &hpo_dp_le_shift, &hpo_dp_le_mask); + + return &hpo_dp_enc31->base; +} + + +static struct dce_hwseq *dcn31_hwseq_create( + struct dc_context *ctx) +{ + struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); + + if (hws) { + hws->ctx = ctx; + hws->regs = &hwseq_reg; + hws->shifts = &hwseq_shift; + hws->masks = &hwseq_mask; + } + return hws; +} +static const struct resource_create_funcs res_create_funcs = { + .read_dce_straps = read_dce_straps, + .create_audio = dcn31_create_audio, + .create_stream_encoder = dcn316_stream_encoder_create, + .create_hpo_dp_stream_encoder = dcn31_hpo_dp_stream_encoder_create, + .create_hpo_dp_link_encoder = dcn31_hpo_dp_link_encoder_create, + .create_hwseq = dcn31_hwseq_create, +}; + +static void dcn316_resource_destruct(struct dcn316_resource_pool *pool) +{ + unsigned int i; + + for (i = 0; i < pool->base.stream_enc_count; i++) { + if (pool->base.stream_enc[i] != NULL) { + if (pool->base.stream_enc[i]->vpg != NULL) { + kfree(DCN30_VPG_FROM_VPG(pool->base.stream_enc[i]->vpg)); + pool->base.stream_enc[i]->vpg = NULL; + } + if (pool->base.stream_enc[i]->afmt != NULL) { + kfree(DCN30_AFMT_FROM_AFMT(pool->base.stream_enc[i]->afmt)); + pool->base.stream_enc[i]->afmt = NULL; + } + kfree(DCN10STRENC_FROM_STRENC(pool->base.stream_enc[i])); + pool->base.stream_enc[i] = NULL; + } + } + + for (i = 0; i < pool->base.hpo_dp_stream_enc_count; i++) { + if (pool->base.hpo_dp_stream_enc[i] != NULL) { + if (pool->base.hpo_dp_stream_enc[i]->vpg != NULL) { + kfree(DCN30_VPG_FROM_VPG(pool->base.hpo_dp_stream_enc[i]->vpg)); + pool->base.hpo_dp_stream_enc[i]->vpg = NULL; + } + if (pool->base.hpo_dp_stream_enc[i]->apg != NULL) { + kfree(DCN31_APG_FROM_APG(pool->base.hpo_dp_stream_enc[i]->apg)); + pool->base.hpo_dp_stream_enc[i]->apg = NULL; + } + kfree(DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(pool->base.hpo_dp_stream_enc[i])); + pool->base.hpo_dp_stream_enc[i] = NULL; + } + } + + for (i = 0; i < pool->base.hpo_dp_link_enc_count; i++) { + if (pool->base.hpo_dp_link_enc[i] != NULL) { + kfree(DCN3_1_HPO_DP_LINK_ENC_FROM_HPO_LINK_ENC(pool->base.hpo_dp_link_enc[i])); + pool->base.hpo_dp_link_enc[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_dsc; i++) { + if (pool->base.dscs[i] != NULL) + dcn20_dsc_destroy(&pool->base.dscs[i]); + } + + if (pool->base.mpc != NULL) { + kfree(TO_DCN20_MPC(pool->base.mpc)); + pool->base.mpc = NULL; + } + if (pool->base.hubbub != NULL) { + kfree(pool->base.hubbub); + pool->base.hubbub = NULL; + } + for (i = 0; i < pool->base.pipe_count; i++) { + if (pool->base.dpps[i] != NULL) + dcn31_dpp_destroy(&pool->base.dpps[i]); + + if (pool->base.ipps[i] != NULL) + pool->base.ipps[i]->funcs->ipp_destroy(&pool->base.ipps[i]); + + if (pool->base.hubps[i] != NULL) { + kfree(TO_DCN20_HUBP(pool->base.hubps[i])); + pool->base.hubps[i] = NULL; + } + + if (pool->base.irqs != NULL) { + dal_irq_service_destroy(&pool->base.irqs); + } + } + + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + if (pool->base.engines[i] != NULL) + dce110_engine_destroy(&pool->base.engines[i]); + if (pool->base.hw_i2cs[i] != NULL) { + kfree(pool->base.hw_i2cs[i]); + pool->base.hw_i2cs[i] = NULL; + } + if (pool->base.sw_i2cs[i] != NULL) { + kfree(pool->base.sw_i2cs[i]); + pool->base.sw_i2cs[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_opp; i++) { + if (pool->base.opps[i] != NULL) + pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]); + } + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + if (pool->base.timing_generators[i] != NULL) { + kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i])); + pool->base.timing_generators[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_dwb; i++) { + if (pool->base.dwbc[i] != NULL) { + kfree(TO_DCN30_DWBC(pool->base.dwbc[i])); + pool->base.dwbc[i] = NULL; + } + if (pool->base.mcif_wb[i] != NULL) { + kfree(TO_DCN30_MMHUBBUB(pool->base.mcif_wb[i])); + pool->base.mcif_wb[i] = NULL; + } + } + + for (i = 0; i < pool->base.audio_count; i++) { + if (pool->base.audios[i]) + dce_aud_destroy(&pool->base.audios[i]); + } + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] != NULL) { + dcn20_clock_source_destroy(&pool->base.clock_sources[i]); + pool->base.clock_sources[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_mpc_3dlut; i++) { + if (pool->base.mpc_lut[i] != NULL) { + dc_3dlut_func_release(pool->base.mpc_lut[i]); + pool->base.mpc_lut[i] = NULL; + } + if (pool->base.mpc_shaper[i] != NULL) { + dc_transfer_func_release(pool->base.mpc_shaper[i]); + pool->base.mpc_shaper[i] = NULL; + } + } + + if (pool->base.dp_clock_source != NULL) { + dcn20_clock_source_destroy(&pool->base.dp_clock_source); + pool->base.dp_clock_source = NULL; + } + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + if (pool->base.multiple_abms[i] != NULL) + dce_abm_destroy(&pool->base.multiple_abms[i]); + } + + if (pool->base.psr != NULL) + dmub_psr_destroy(&pool->base.psr); + + if (pool->base.dccg != NULL) + dcn_dccg_destroy(&pool->base.dccg); +} + +static struct hubp *dcn31_hubp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn20_hubp *hubp2 = + kzalloc(sizeof(struct dcn20_hubp), GFP_KERNEL); + + if (!hubp2) + return NULL; + + if (hubp31_construct(hubp2, ctx, inst, + &hubp_regs[inst], &hubp_shift, &hubp_mask)) + return &hubp2->base; + + BREAK_TO_DEBUGGER(); + kfree(hubp2); + return NULL; +} + +static bool dcn31_dwbc_create(struct dc_context *ctx, struct resource_pool *pool) +{ + int i; + uint32_t pipe_count = pool->res_cap->num_dwb; + + for (i = 0; i < pipe_count; i++) { + struct dcn30_dwbc *dwbc30 = kzalloc(sizeof(struct dcn30_dwbc), + GFP_KERNEL); + + if (!dwbc30) { + dm_error("DC: failed to create dwbc30!\n"); + return false; + } + + dcn30_dwbc_construct(dwbc30, ctx, + &dwbc30_regs[i], + &dwbc30_shift, + &dwbc30_mask, + i); + + pool->dwbc[i] = &dwbc30->base; + } + return true; +} + +static bool dcn31_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool) +{ + int i; + uint32_t pipe_count = pool->res_cap->num_dwb; + + for (i = 0; i < pipe_count; i++) { + struct dcn30_mmhubbub *mcif_wb30 = kzalloc(sizeof(struct dcn30_mmhubbub), + GFP_KERNEL); + + if (!mcif_wb30) { + dm_error("DC: failed to create mcif_wb30!\n"); + return false; + } + + dcn30_mmhubbub_construct(mcif_wb30, ctx, + &mcif_wb30_regs[i], + &mcif_wb30_shift, + &mcif_wb30_mask, + i); + + pool->mcif_wb[i] = &mcif_wb30->base; + } + return true; +} + +static struct display_stream_compressor *dcn31_dsc_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dcn20_dsc *dsc = + kzalloc(sizeof(struct dcn20_dsc), GFP_KERNEL); + + if (!dsc) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dsc2_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask); + return &dsc->base; +} + +static void dcn316_destroy_resource_pool(struct resource_pool **pool) +{ + struct dcn316_resource_pool *dcn31_pool = TO_DCN316_RES_POOL(*pool); + + dcn316_resource_destruct(dcn31_pool); + kfree(dcn31_pool); + *pool = NULL; +} + +static struct clock_source *dcn31_clock_source_create( + struct dc_context *ctx, + struct dc_bios *bios, + enum clock_source_id id, + const struct dce110_clk_src_regs *regs, + bool dp_clk_src) +{ + struct dce110_clk_src *clk_src = + kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); + + if (!clk_src) + return NULL; + + if (dcn31_clk_src_construct(clk_src, ctx, bios, id, + regs, &cs_shift, &cs_mask)) { + clk_src->base.dp_clk_src = dp_clk_src; + return &clk_src->base; + } + + kfree(clk_src); + + BREAK_TO_DEBUGGER(); + return NULL; +} + +static bool is_dual_plane(enum surface_pixel_format format) +{ + return format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN || format == SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA; +} + +static int dcn316_populate_dml_pipes_from_context( + struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes, + bool fast_validate) +{ + int i, pipe_cnt; + struct resource_context *res_ctx = &context->res_ctx; + struct pipe_ctx *pipe; + const int max_usable_det = context->bw_ctx.dml.ip.config_return_buffer_size_in_kbytes - DCN3_16_MIN_COMPBUF_SIZE_KB; + + DC_FP_START(); + dcn31x_populate_dml_pipes_from_context(dc, context, pipes, fast_validate); + DC_FP_END(); + + for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) { + struct dc_crtc_timing *timing; + + if (!res_ctx->pipe_ctx[i].stream) + continue; + pipe = &res_ctx->pipe_ctx[i]; + timing = &pipe->stream->timing; + + /* + * Immediate flip can be set dynamically after enabling the plane. + * We need to require support for immediate flip or underflow can be + * intermittently experienced depending on peak b/w requirements. + */ + pipes[pipe_cnt].pipe.src.immediate_flip = true; + + pipes[pipe_cnt].pipe.src.unbounded_req_mode = false; + pipes[pipe_cnt].pipe.dest.vfront_porch = timing->v_front_porch; + pipes[pipe_cnt].pipe.src.dcc_rate = 3; + pipes[pipe_cnt].dout.dsc_input_bpc = 0; + DC_FP_START(); + dcn31_zero_pipe_dcc_fraction(pipes, pipe_cnt); + DC_FP_END(); + + if (pipes[pipe_cnt].dout.dsc_enable) { + switch (timing->display_color_depth) { + case COLOR_DEPTH_888: + pipes[pipe_cnt].dout.dsc_input_bpc = 8; + break; + case COLOR_DEPTH_101010: + pipes[pipe_cnt].dout.dsc_input_bpc = 10; + break; + case COLOR_DEPTH_121212: + pipes[pipe_cnt].dout.dsc_input_bpc = 12; + break; + default: + ASSERT(0); + break; + } + } + + pipe_cnt++; + } + + if (pipe_cnt) + context->bw_ctx.dml.ip.det_buffer_size_kbytes = + (max_usable_det / DCN3_16_CRB_SEGMENT_SIZE_KB / pipe_cnt) * DCN3_16_CRB_SEGMENT_SIZE_KB; + if (context->bw_ctx.dml.ip.det_buffer_size_kbytes > DCN3_16_MAX_DET_SIZE) + context->bw_ctx.dml.ip.det_buffer_size_kbytes = DCN3_16_MAX_DET_SIZE; + ASSERT(context->bw_ctx.dml.ip.det_buffer_size_kbytes >= DCN3_16_DEFAULT_DET_SIZE); + dc->config.enable_4to1MPC = false; + if (pipe_cnt == 1 && pipe->plane_state && !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; + context->bw_ctx.dml.ip.det_buffer_size_kbytes = + (max_usable_det / DCN3_16_CRB_SEGMENT_SIZE_KB / 4) * DCN3_16_CRB_SEGMENT_SIZE_KB; + } else if (!is_dual_plane(pipe->plane_state->format)) { + context->bw_ctx.dml.ip.det_buffer_size_kbytes = 192; + pipes[0].pipe.src.unbounded_req_mode = true; + } + } + + return pipe_cnt; +} + +static void dcn316_get_panel_config_defaults(struct dc_panel_config *panel_config) +{ + *panel_config = panel_config_defaults; +} + +static struct dc_cap_funcs cap_funcs = { + .get_dcc_compression_cap = dcn20_get_dcc_compression_cap +}; + +static struct resource_funcs dcn316_res_pool_funcs = { + .destroy = dcn316_destroy_resource_pool, + .link_enc_create = dcn31_link_encoder_create, + .link_enc_create_minimal = dcn31_link_enc_create_minimal, + .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, + .calculate_wm_and_dlg = dcn31_calculate_wm_and_dlg, + .update_soc_for_wm_a = dcn31_update_soc_for_wm_a, + .populate_dml_pipes = dcn316_populate_dml_pipes_from_context, + .acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer, + .release_pipe = dcn20_release_pipe, + .add_stream_to_ctx = dcn30_add_stream_to_ctx, + .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource, + .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, + .populate_dml_writeback_from_context = dcn31_populate_dml_writeback_from_context, + .set_mcif_arb_params = dcn31_set_mcif_arb_params, + .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 = dcn316_update_bw_bounding_box, + .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, + .get_panel_config_defaults = dcn316_get_panel_config_defaults, +}; + +static bool dcn316_resource_construct( + uint8_t num_virtual_links, + struct dc *dc, + struct dcn316_resource_pool *pool) +{ + int i; + struct dc_context *ctx = dc->ctx; + struct irq_service_init_data init_data; + + ctx->dc_bios->regs = &bios_regs; + + pool->base.res_cap = &res_cap_dcn31; + + pool->base.funcs = &dcn316_res_pool_funcs; + + /************************************************* + * Resource + asic cap harcoding * + *************************************************/ + pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.pipe_count = pool->base.res_cap->num_timing_generator; + 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 = 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; + dc->caps.max_slave_planes = 2; + dc->caps.max_slave_yuv_planes = 2; + dc->caps.max_slave_rgb_planes = 2; + dc->caps.post_blend_color_processing = true; + dc->caps.force_dp_tps4_for_cp2520 = true; + if (dc->config.forceHBR2CP2520) + dc->caps.force_dp_tps4_for_cp2520 = false; + dc->caps.dp_hpo = true; + dc->caps.dp_hdmi21_pcon_support = true; + dc->caps.edp_dsc_support = true; + dc->caps.extended_aux_timeout_support = true; + dc->caps.dmcub_support = true; + dc->caps.is_apu = true; + + /* Color pipeline capabilities */ + dc->caps.color.dpp.dcn_arch = 1; + dc->caps.color.dpp.input_lut_shared = 0; + dc->caps.color.dpp.icsc = 1; + dc->caps.color.dpp.dgam_ram = 0; // must use gamma_corr + dc->caps.color.dpp.dgam_rom_caps.srgb = 1; + dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1; + dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 1; + dc->caps.color.dpp.dgam_rom_caps.pq = 1; + dc->caps.color.dpp.dgam_rom_caps.hlg = 1; + dc->caps.color.dpp.post_csc = 1; + dc->caps.color.dpp.gamma_corr = 1; + dc->caps.color.dpp.dgam_rom_for_yuv = 0; + + dc->caps.color.dpp.hw_3d_lut = 1; + dc->caps.color.dpp.ogam_ram = 1; + // no OGAM ROM on DCN301 + dc->caps.color.dpp.ogam_rom_caps.srgb = 0; + dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0; + dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0; + dc->caps.color.dpp.ogam_rom_caps.pq = 0; + dc->caps.color.dpp.ogam_rom_caps.hlg = 0; + dc->caps.color.dpp.ocsc = 0; + + dc->caps.color.mpc.gamut_remap = 1; + dc->caps.color.mpc.num_3dluts = pool->base.res_cap->num_mpc_3dlut; //2 + dc->caps.color.mpc.ogam_ram = 1; + dc->caps.color.mpc.ogam_rom_caps.srgb = 0; + dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0; + dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0; + dc->caps.color.mpc.ogam_rom_caps.pq = 0; + dc->caps.color.mpc.ogam_rom_caps.hlg = 0; + dc->caps.color.mpc.ocsc = 1; + + /* read VBIOS LTTPR caps */ + { + if (ctx->dc_bios->funcs->get_lttpr_caps) { + enum bp_result bp_query_result; + uint8_t is_vbios_lttpr_enable = 0; + + bp_query_result = ctx->dc_bios->funcs->get_lttpr_caps(ctx->dc_bios, &is_vbios_lttpr_enable); + dc->caps.vbios_lttpr_enable = (bp_query_result == BP_RESULT_OK) && !!is_vbios_lttpr_enable; + } + + /* interop bit is implicit */ + { + dc->caps.vbios_lttpr_aware = true; + } + } + + if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) + dc->debug = debug_defaults_drv; + + // Init the vm_helper + if (dc->vm_helper) + vm_helper_init(dc->vm_helper, 16); + + /************************************************* + * Create resources * + *************************************************/ + + /* Clock Sources for Pixel Clock*/ + pool->base.clock_sources[DCN31_CLK_SRC_PLL0] = + dcn31_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL0, + &clk_src_regs[0], false); + pool->base.clock_sources[DCN31_CLK_SRC_PLL1] = + dcn31_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL1, + &clk_src_regs[1], false); + pool->base.clock_sources[DCN31_CLK_SRC_PLL2] = + dcn31_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL2, + &clk_src_regs[2], false); + pool->base.clock_sources[DCN31_CLK_SRC_PLL3] = + dcn31_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL3, + &clk_src_regs[3], false); + pool->base.clock_sources[DCN31_CLK_SRC_PLL4] = + dcn31_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL4, + &clk_src_regs[4], false); + + pool->base.clk_src_count = DCN30_CLK_SRC_TOTAL; + + /* todo: not reuse phy_pll registers */ + pool->base.dp_clock_source = + dcn31_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_ID_DP_DTO, + &clk_src_regs[0], true); + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] == NULL) { + dm_error("DC: failed to create clock sources!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + } + + /* TODO: DCCG */ + pool->base.dccg = dccg31_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask); + if (pool->base.dccg == NULL) { + dm_error("DC: failed to create dccg!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + /* TODO: IRQ */ + init_data.ctx = dc->ctx; + pool->base.irqs = dal_irq_service_dcn31_create(&init_data); + if (!pool->base.irqs) + goto create_fail; + + /* HUBBUB */ + pool->base.hubbub = dcn31_hubbub_create(ctx); + if (pool->base.hubbub == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create hubbub!\n"); + goto create_fail; + } + + /* HUBPs, DPPs, OPPs and TGs */ + for (i = 0; i < pool->base.pipe_count; i++) { + pool->base.hubps[i] = dcn31_hubp_create(ctx, i); + if (pool->base.hubps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create hubps!\n"); + goto create_fail; + } + + pool->base.dpps[i] = dcn31_dpp_create(ctx, i); + if (pool->base.dpps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create dpps!\n"); + goto create_fail; + } + } + + for (i = 0; i < pool->base.res_cap->num_opp; i++) { + pool->base.opps[i] = dcn31_opp_create(ctx, i); + if (pool->base.opps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create output pixel processor!\n"); + goto create_fail; + } + } + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + pool->base.timing_generators[i] = dcn31_timing_generator_create( + ctx, i); + if (pool->base.timing_generators[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create tg!\n"); + goto create_fail; + } + } + pool->base.timing_generator_count = i; + + /* PSR */ + pool->base.psr = dmub_psr_create(ctx); + if (pool->base.psr == NULL) { + dm_error("DC: failed to create psr obj!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + /* ABM */ + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + pool->base.multiple_abms[i] = dmub_abm_create(ctx, + &abm_regs[i], + &abm_shift, + &abm_mask); + if (pool->base.multiple_abms[i] == NULL) { + dm_error("DC: failed to create abm for pipe %d!\n", i); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + } + + /* MPC and DSC */ + pool->base.mpc = dcn31_mpc_create(ctx, pool->base.mpcc_count, pool->base.res_cap->num_mpc_3dlut); + if (pool->base.mpc == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create mpc!\n"); + goto create_fail; + } + + for (i = 0; i < pool->base.res_cap->num_dsc; i++) { + pool->base.dscs[i] = dcn31_dsc_create(ctx, i); + if (pool->base.dscs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create display stream compressor %d!\n", i); + goto create_fail; + } + } + + /* DWB and MMHUBBUB */ + if (!dcn31_dwbc_create(ctx, &pool->base)) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dwbc!\n"); + goto create_fail; + } + + if (!dcn31_mmhubbub_create(ctx, &pool->base)) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create mcif_wb!\n"); + goto create_fail; + } + + /* AUX and I2C */ + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + pool->base.engines[i] = dcn31_aux_engine_create(ctx, i); + if (pool->base.engines[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create aux engine!!\n"); + goto create_fail; + } + pool->base.hw_i2cs[i] = dcn31_i2c_hw_create(ctx, i); + if (pool->base.hw_i2cs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create hw i2c!!\n"); + goto create_fail; + } + pool->base.sw_i2cs[i] = NULL; + } + + /* Audio, Stream Encoders including HPO and virtual, MPC 3D LUTs */ + if (!resource_construct(num_virtual_links, dc, &pool->base, + &res_create_funcs)) + goto create_fail; + + /* HW Sequencer and Plane caps */ + dcn31_hw_sequencer_construct(dc); + + dc->caps.max_planes = pool->base.pipe_count; + + for (i = 0; i < dc->caps.max_planes; ++i) + dc->caps.planes[i] = plane_cap; + + dc->cap_funcs = cap_funcs; + + dc->dcn_ip->max_num_dpp = dcn3_16_ip.max_num_dpp; + + return true; + +create_fail: + + dcn316_resource_destruct(pool); + + return false; +} + +struct resource_pool *dcn316_create_resource_pool( + const struct dc_init_data *init_data, + struct dc *dc) +{ + struct dcn316_resource_pool *pool = + kzalloc(sizeof(struct dcn316_resource_pool), GFP_KERNEL); + + if (!pool) + return NULL; + + if (dcn316_resource_construct(init_data->num_virtual_links, dc, pool)) + return &pool->base; + + BREAK_TO_DEBUGGER(); + kfree(pool); + return NULL; +} diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.h new file mode 100644 index 00000000000000..aba6d634131b41 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.h @@ -0,0 +1,44 @@ +/* + * 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 _DCN316_RESOURCE_H_ +#define _DCN316_RESOURCE_H_ + +#include "core_types.h" + +#define TO_DCN316_RES_POOL(pool)\ + container_of(pool, struct dcn316_resource_pool, base) + +extern struct _vcs_dpi_ip_params_st dcn3_16_ip; + +struct dcn316_resource_pool { + struct resource_pool base; +}; + +struct resource_pool *dcn316_create_resource_pool( + const struct dc_init_data *init_data, + struct dc *dc); + +#endif /* _DCN316_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c new file mode 100644 index 00000000000000..c4d71e7f18af47 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c @@ -0,0 +1,2767 @@ +// SPDX-License-Identifier: MIT +/* + * 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 "dm_services.h" +#include "dc.h" + +#include "dcn32/dcn32_init.h" + +#include "resource.h" +#include "include/irq_service_interface.h" +#include "dcn32_resource.h" + +#include "dcn20/dcn20_resource.h" +#include "dcn30/dcn30_resource.h" + +#include "dcn10/dcn10_ipp.h" +#include "dcn30/dcn30_hubbub.h" +#include "dcn31/dcn31_hubbub.h" +#include "dcn32/dcn32_hubbub.h" +#include "dcn32/dcn32_mpc.h" +#include "dcn32/dcn32_hubp.h" +#include "irq/dcn32/irq_service_dcn32.h" +#include "dcn32/dcn32_dpp.h" +#include "dcn32/dcn32_optc.h" +#include "dcn20/dcn20_hwseq.h" +#include "dcn30/dcn30_hwseq.h" +#include "dce110/dce110_hwseq.h" +#include "dcn30/dcn30_opp.h" +#include "dcn20/dcn20_dsc.h" +#include "dcn30/dcn30_vpg.h" +#include "dcn30/dcn30_afmt.h" +#include "dcn30/dcn30_dio_stream_encoder.h" +#include "dcn32/dcn32_dio_stream_encoder.h" +#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 "dcn31/dcn31_apg.h" +#include "dcn31/dcn31_dio_link_encoder.h" +#include "dcn32/dcn32_dio_link_encoder.h" +#include "dce/dce_clock_source.h" +#include "dce/dce_audio.h" +#include "dce/dce_hwseq.h" +#include "clk_mgr.h" +#include "virtual/virtual_stream_encoder.h" +#include "dml/display_mode_vba.h" +#include "dcn32/dcn32_dccg.h" +#include "dcn10/dcn10_resource.h" +#include "link.h" +#include "dcn31/dcn31_panel_cntl.h" + +#include "dcn30/dcn30_dwb.h" +#include "dcn32/dcn32_mmhubbub.h" + +#include "dcn/dcn_3_2_0_offset.h" +#include "dcn/dcn_3_2_0_sh_mask.h" +#include "nbio/nbio_4_3_0_offset.h" + +#include "reg_helper.h" +#include "dce/dmub_abm.h" +#include "dce/dmub_psr.h" +#include "dce/dce_aux.h" +#include "dce/dce_i2c.h" + +#include "dml/dcn30/display_mode_vba_30.h" +#include "vm_helper.h" +#include "dcn20/dcn20_vmid.h" +#include "dml/dcn32/dcn32_fpu.h" + +#include "dc_state_priv.h" + +#include "dml2/dml2_wrapper.h" + +#define DC_LOGGER_INIT(logger) + +enum dcn32_clk_src_array_id { + DCN32_CLK_SRC_PLL0, + DCN32_CLK_SRC_PLL1, + DCN32_CLK_SRC_PLL2, + DCN32_CLK_SRC_PLL3, + DCN32_CLK_SRC_PLL4, + DCN32_CLK_SRC_TOTAL +}; + +/* begin ********************* + * macros to expend register list macro defined in HW object header file + */ + +/* DCN */ +#define BASE_INNER(seg) ctx->dcn_reg_offsets[seg] + +#define BASE(seg) BASE_INNER(seg) + +#define SR(reg_name)\ + REG_STRUCT.reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ + reg ## reg_name +#define SR_ARR(reg_name, id) \ + REG_STRUCT[id].reg_name = BASE(reg##reg_name##_BASE_IDX) + reg##reg_name + +#define SR_ARR_INIT(reg_name, id, value) \ + REG_STRUCT[id].reg_name = value + +#define SRI(reg_name, block, id)\ + REG_STRUCT.reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRI_ARR(reg_name, block, id)\ + REG_STRUCT[id].reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SR_ARR_I2C(reg_name, id) \ + REG_STRUCT[id-1].reg_name = BASE(reg##reg_name##_BASE_IDX) + reg##reg_name + +#define SRI_ARR_I2C(reg_name, block, id)\ + REG_STRUCT[id-1].reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRI_ARR_ALPHABET(reg_name, block, index, id)\ + REG_STRUCT[index].reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRI2(reg_name, block, id)\ + .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ + reg ## reg_name +#define SRI2_ARR(reg_name, block, id)\ + REG_STRUCT[id].reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ + reg ## reg_name + +#define SRIR(var_name, reg_name, block, id)\ + .var_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRII(reg_name, block, id)\ + REG_STRUCT.reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRII_ARR_2(reg_name, block, id, inst)\ + REG_STRUCT[inst].reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRII_MPC_RMU(reg_name, block, id)\ + .RMU##_##reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRII_DWB(reg_name, temp_name, block, id)\ + REG_STRUCT.reg_name[id] = BASE(reg ## block ## id ## _ ## temp_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## temp_name + +#define SF_DWB2(reg_name, block, id, field_name, post_fix) \ + .field_name = reg_name ## __ ## field_name ## post_fix + +#define DCCG_SRII(reg_name, block, id)\ + REG_STRUCT.block ## _ ## reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define VUPDATE_SRII(reg_name, block, id)\ + REG_STRUCT.reg_name[id] = BASE(reg ## reg_name ## _ ## block ## id ## _BASE_IDX) + \ + reg ## reg_name ## _ ## block ## id + +/* NBIO */ +#define NBIO_BASE_INNER(seg) ctx->nbio_reg_offsets[seg] + +#define NBIO_BASE(seg) \ + NBIO_BASE_INNER(seg) + +#define NBIO_SR(reg_name)\ + REG_STRUCT.reg_name = NBIO_BASE(regBIF_BX0_ ## reg_name ## _BASE_IDX) + \ + regBIF_BX0_ ## reg_name +#define NBIO_SR_ARR(reg_name, id)\ + REG_STRUCT[id].reg_name = NBIO_BASE(regBIF_BX0_ ## reg_name ## _BASE_IDX) + \ + regBIF_BX0_ ## reg_name + +#undef CTX +#define CTX ctx +#define REG(reg_name) \ + (ctx->dcn_reg_offsets[reg ## reg_name ## _BASE_IDX] + reg ## reg_name) + +static struct bios_registers bios_regs; + +#define bios_regs_init() \ + ( \ + NBIO_SR(BIOS_SCRATCH_3),\ + NBIO_SR(BIOS_SCRATCH_6)\ + ) + +#define clk_src_regs_init(index, pllid)\ + CS_COMMON_REG_LIST_DCN3_0_RI(index, pllid) + +static struct dce110_clk_src_regs clk_src_regs[5]; + +static const struct dce110_clk_src_shift cs_shift = { + CS_COMMON_MASK_SH_LIST_DCN3_2(__SHIFT) +}; + +static const struct dce110_clk_src_mask cs_mask = { + CS_COMMON_MASK_SH_LIST_DCN3_2(_MASK) +}; + +#define abm_regs_init(id)\ + ABM_DCN32_REG_LIST_RI(id) + +static struct dce_abm_registers abm_regs[4]; + +static const struct dce_abm_shift abm_shift = { + ABM_MASK_SH_LIST_DCN32(__SHIFT) +}; + +static const struct dce_abm_mask abm_mask = { + ABM_MASK_SH_LIST_DCN32(_MASK) +}; + +#define audio_regs_init(id)\ + AUD_COMMON_REG_LIST_RI(id) + +static struct dce_audio_registers audio_regs[5]; + +#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ + AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) + +static const struct dce_audio_shift audio_shift = { + DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_audio_mask audio_mask = { + DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) +}; + +#define vpg_regs_init(id)\ + VPG_DCN3_REG_LIST_RI(id) + +static struct dcn30_vpg_registers vpg_regs[10]; + +static const struct dcn30_vpg_shift vpg_shift = { + DCN3_VPG_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn30_vpg_mask vpg_mask = { + DCN3_VPG_MASK_SH_LIST(_MASK) +}; + +#define afmt_regs_init(id)\ + AFMT_DCN3_REG_LIST_RI(id) + +static struct dcn30_afmt_registers afmt_regs[6]; + +static const struct dcn30_afmt_shift afmt_shift = { + DCN3_AFMT_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn30_afmt_mask afmt_mask = { + DCN3_AFMT_MASK_SH_LIST(_MASK) +}; + +#define apg_regs_init(id)\ + APG_DCN31_REG_LIST_RI(id) + +static struct dcn31_apg_registers apg_regs[4]; + +static const struct dcn31_apg_shift apg_shift = { + DCN31_APG_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn31_apg_mask apg_mask = { + DCN31_APG_MASK_SH_LIST(_MASK) +}; + +#define stream_enc_regs_init(id)\ + SE_DCN32_REG_LIST_RI(id) + +static struct dcn10_stream_enc_registers stream_enc_regs[5]; + +static const struct dcn10_stream_encoder_shift se_shift = { + SE_COMMON_MASK_SH_LIST_DCN32(__SHIFT) +}; + +static const struct dcn10_stream_encoder_mask se_mask = { + SE_COMMON_MASK_SH_LIST_DCN32(_MASK) +}; + + +#define aux_regs_init(id)\ + DCN2_AUX_REG_LIST_RI(id) + +static struct dcn10_link_enc_aux_registers link_enc_aux_regs[5]; + +#define hpd_regs_init(id)\ + HPD_REG_LIST_RI(id) + +static struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[5]; + +#define link_regs_init(id, phyid)\ + ( \ + LE_DCN31_REG_LIST_RI(id), \ + UNIPHY_DCN2_REG_LIST_RI(id, phyid)\ + ) + /*DPCS_DCN31_REG_LIST(id),*/ \ + +static struct dcn10_link_enc_registers link_enc_regs[5]; + +static const struct dcn10_link_enc_shift le_shift = { + LINK_ENCODER_MASK_SH_LIST_DCN31(__SHIFT), \ + //DPCS_DCN31_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn10_link_enc_mask le_mask = { + LINK_ENCODER_MASK_SH_LIST_DCN31(_MASK), \ + //DPCS_DCN31_MASK_SH_LIST(_MASK) +}; + +#define hpo_dp_stream_encoder_reg_init(id)\ + DCN3_1_HPO_DP_STREAM_ENC_REG_LIST_RI(id) + +static struct dcn31_hpo_dp_stream_encoder_registers hpo_dp_stream_enc_regs[4]; + +static const struct dcn31_hpo_dp_stream_encoder_shift hpo_dp_se_shift = { + DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn31_hpo_dp_stream_encoder_mask hpo_dp_se_mask = { + DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(_MASK) +}; + + +#define hpo_dp_link_encoder_reg_init(id)\ + DCN3_1_HPO_DP_LINK_ENC_REG_LIST_RI(id) + /*DCN3_1_RDPCSTX_REG_LIST(0),*/ + /*DCN3_1_RDPCSTX_REG_LIST(1),*/ + /*DCN3_1_RDPCSTX_REG_LIST(2),*/ + /*DCN3_1_RDPCSTX_REG_LIST(3),*/ + +static struct dcn31_hpo_dp_link_encoder_registers hpo_dp_link_enc_regs[2]; + +static const struct dcn31_hpo_dp_link_encoder_shift hpo_dp_le_shift = { + DCN3_2_HPO_DP_LINK_ENC_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn31_hpo_dp_link_encoder_mask hpo_dp_le_mask = { + DCN3_2_HPO_DP_LINK_ENC_MASK_SH_LIST(_MASK) +}; + +#define dpp_regs_init(id)\ + DPP_REG_LIST_DCN30_COMMON_RI(id) + +static struct dcn3_dpp_registers dpp_regs[4]; + +static const struct dcn3_dpp_shift tf_shift = { + DPP_REG_LIST_SH_MASK_DCN30_COMMON(__SHIFT) +}; + +static const struct dcn3_dpp_mask tf_mask = { + DPP_REG_LIST_SH_MASK_DCN30_COMMON(_MASK) +}; + + +#define opp_regs_init(id)\ + OPP_REG_LIST_DCN30_RI(id) + +static struct dcn20_opp_registers opp_regs[4]; + +static const struct dcn20_opp_shift opp_shift = { + OPP_MASK_SH_LIST_DCN20(__SHIFT) +}; + +static const struct dcn20_opp_mask opp_mask = { + OPP_MASK_SH_LIST_DCN20(_MASK) +}; + +#define aux_engine_regs_init(id)\ + ( \ + AUX_COMMON_REG_LIST0_RI(id), \ + SR_ARR_INIT(AUXN_IMPCAL, id, 0), \ + SR_ARR_INIT(AUXP_IMPCAL, id, 0), \ + SR_ARR_INIT(AUX_RESET_MASK, id, DP_AUX0_AUX_CONTROL__AUX_RESET_MASK), \ + SR_ARR_INIT(AUX_RESET_MASK, id, DP_AUX0_AUX_CONTROL__AUX_RESET_MASK)\ + ) + +static struct dce110_aux_registers aux_engine_regs[5]; + +static const struct dce110_aux_registers_shift aux_shift = { + DCN_AUX_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce110_aux_registers_mask aux_mask = { + DCN_AUX_MASK_SH_LIST(_MASK) +}; + +#define dwbc_regs_dcn3_init(id)\ + DWBC_COMMON_REG_LIST_DCN30_RI(id) + +static struct dcn30_dwbc_registers dwbc30_regs[1]; + +static const struct dcn30_dwbc_shift dwbc30_shift = { + DWBC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn30_dwbc_mask dwbc30_mask = { + DWBC_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +#define mcif_wb_regs_dcn3_init(id)\ + MCIF_WB_COMMON_REG_LIST_DCN32_RI(id) + +static struct dcn30_mmhubbub_registers mcif_wb30_regs[1]; + +static const struct dcn30_mmhubbub_shift mcif_wb30_shift = { + MCIF_WB_COMMON_MASK_SH_LIST_DCN32(__SHIFT) +}; + +static const struct dcn30_mmhubbub_mask mcif_wb30_mask = { + MCIF_WB_COMMON_MASK_SH_LIST_DCN32(_MASK) +}; + +#define dsc_regsDCN20_init(id)\ + DSC_REG_LIST_DCN20_RI(id) + +static struct dcn20_dsc_registers dsc_regs[4]; + +static const struct dcn20_dsc_shift dsc_shift = { + DSC_REG_LIST_SH_MASK_DCN20(__SHIFT) +}; + +static const struct dcn20_dsc_mask dsc_mask = { + DSC_REG_LIST_SH_MASK_DCN20(_MASK) +}; + +static struct dcn30_mpc_registers mpc_regs; + +#define dcn_mpc_regs_init() \ + MPC_REG_LIST_DCN3_2_RI(0),\ + MPC_REG_LIST_DCN3_2_RI(1),\ + MPC_REG_LIST_DCN3_2_RI(2),\ + MPC_REG_LIST_DCN3_2_RI(3),\ + MPC_OUT_MUX_REG_LIST_DCN3_0_RI(0),\ + MPC_OUT_MUX_REG_LIST_DCN3_0_RI(1),\ + MPC_OUT_MUX_REG_LIST_DCN3_0_RI(2),\ + MPC_OUT_MUX_REG_LIST_DCN3_0_RI(3),\ + MPC_DWB_MUX_REG_LIST_DCN3_0_RI(0) + +static const struct dcn30_mpc_shift mpc_shift = { + MPC_COMMON_MASK_SH_LIST_DCN32(__SHIFT) +}; + +static const struct dcn30_mpc_mask mpc_mask = { + MPC_COMMON_MASK_SH_LIST_DCN32(_MASK) +}; + +#define optc_regs_init(id)\ + OPTC_COMMON_REG_LIST_DCN3_2_RI(id) + +static struct dcn_optc_registers optc_regs[4]; + +static const struct dcn_optc_shift optc_shift = { + OPTC_COMMON_MASK_SH_LIST_DCN3_2(__SHIFT) +}; + +static const struct dcn_optc_mask optc_mask = { + OPTC_COMMON_MASK_SH_LIST_DCN3_2(_MASK) +}; + +#define hubp_regs_init(id)\ + HUBP_REG_LIST_DCN32_RI(id) + +static struct dcn_hubp2_registers hubp_regs[4]; + + +static const struct dcn_hubp2_shift hubp_shift = { + HUBP_MASK_SH_LIST_DCN32(__SHIFT) +}; + +static const struct dcn_hubp2_mask hubp_mask = { + HUBP_MASK_SH_LIST_DCN32(_MASK) +}; + +static struct dcn_hubbub_registers hubbub_reg; +#define hubbub_reg_init()\ + HUBBUB_REG_LIST_DCN32_RI(0) + +static const struct dcn_hubbub_shift hubbub_shift = { + HUBBUB_MASK_SH_LIST_DCN32(__SHIFT) +}; + +static const struct dcn_hubbub_mask hubbub_mask = { + HUBBUB_MASK_SH_LIST_DCN32(_MASK) +}; + +static struct dccg_registers dccg_regs; + +#define dccg_regs_init()\ + DCCG_REG_LIST_DCN32_RI() + +static const struct dccg_shift dccg_shift = { + DCCG_MASK_SH_LIST_DCN32(__SHIFT) +}; + +static const struct dccg_mask dccg_mask = { + DCCG_MASK_SH_LIST_DCN32(_MASK) +}; + + +#define SRII2(reg_name_pre, reg_name_post, id)\ + .reg_name_pre ## _ ## reg_name_post[id] = BASE(reg ## reg_name_pre \ + ## id ## _ ## reg_name_post ## _BASE_IDX) + \ + reg ## reg_name_pre ## id ## _ ## reg_name_post + + +#define HWSEQ_DCN32_REG_LIST()\ + SR(DCHUBBUB_GLOBAL_TIMER_CNTL), \ + SR(DIO_MEM_PWR_CTRL), \ + SR(ODM_MEM_PWR_CTRL3), \ + SR(MMHUBBUB_MEM_PWR_CNTL), \ + SR(DCCG_GATE_DISABLE_CNTL), \ + SR(DCCG_GATE_DISABLE_CNTL2), \ + SR(DCFCLK_CNTL),\ + SR(DC_MEM_GLOBAL_PWR_REQ_CNTL), \ + SRII(PIXEL_RATE_CNTL, OTG, 0), \ + SRII(PIXEL_RATE_CNTL, OTG, 1),\ + SRII(PIXEL_RATE_CNTL, OTG, 2),\ + SRII(PIXEL_RATE_CNTL, OTG, 3),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 0),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 1),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 2),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 3),\ + SR(MICROSECOND_TIME_BASE_DIV), \ + SR(MILLISECOND_TIME_BASE_DIV), \ + SR(DISPCLK_FREQ_CHANGE_CNTL), \ + SR(RBBMIF_TIMEOUT_DIS), \ + SR(RBBMIF_TIMEOUT_DIS_2), \ + SR(DCHUBBUB_CRC_CTRL), \ + SR(DPP_TOP0_DPP_CRC_CTRL), \ + SR(DPP_TOP0_DPP_CRC_VAL_B_A), \ + SR(DPP_TOP0_DPP_CRC_VAL_R_G), \ + SR(MPC_CRC_CTRL), \ + SR(MPC_CRC_RESULT_GB), \ + SR(MPC_CRC_RESULT_C), \ + SR(MPC_CRC_RESULT_AR), \ + SR(DOMAIN0_PG_CONFIG), \ + SR(DOMAIN1_PG_CONFIG), \ + SR(DOMAIN2_PG_CONFIG), \ + SR(DOMAIN3_PG_CONFIG), \ + SR(DOMAIN16_PG_CONFIG), \ + SR(DOMAIN17_PG_CONFIG), \ + SR(DOMAIN18_PG_CONFIG), \ + SR(DOMAIN19_PG_CONFIG), \ + SR(DOMAIN0_PG_STATUS), \ + SR(DOMAIN1_PG_STATUS), \ + SR(DOMAIN2_PG_STATUS), \ + SR(DOMAIN3_PG_STATUS), \ + SR(DOMAIN16_PG_STATUS), \ + SR(DOMAIN17_PG_STATUS), \ + SR(DOMAIN18_PG_STATUS), \ + SR(DOMAIN19_PG_STATUS), \ + SR(D1VGA_CONTROL), \ + SR(D2VGA_CONTROL), \ + SR(D3VGA_CONTROL), \ + SR(D4VGA_CONTROL), \ + SR(D5VGA_CONTROL), \ + SR(D6VGA_CONTROL), \ + SR(DC_IP_REQUEST_CNTL), \ + SR(AZALIA_AUDIO_DTO), \ + SR(AZALIA_CONTROLLER_CLOCK_GATING) + +static struct dce_hwseq_registers hwseq_reg; + +#define hwseq_reg_init()\ + HWSEQ_DCN32_REG_LIST() + +#define HWSEQ_DCN32_MASK_SH_LIST(mask_sh)\ + HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ + HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \ + HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN19_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN19_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN16_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN17_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN18_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN19_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \ + HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh), \ + HWS_SF(, HPO_TOP_CLOCK_CONTROL, HPO_HDMISTREAMCLK_G_GATE_DIS, mask_sh), \ + HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_UNASSIGNED_PWR_MODE, mask_sh), \ + HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_VBLANK_PWR_MODE, mask_sh), \ + HWS_SF(, MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, mask_sh) + +static const struct dce_hwseq_shift hwseq_shift = { + HWSEQ_DCN32_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_hwseq_mask hwseq_mask = { + HWSEQ_DCN32_MASK_SH_LIST(_MASK) +}; +#define vmid_regs_init(id)\ + DCN20_VMID_REG_LIST_RI(id) + +static struct dcn_vmid_registers vmid_regs[16]; + +static const struct dcn20_vmid_shift vmid_shifts = { + DCN20_VMID_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn20_vmid_mask vmid_masks = { + DCN20_VMID_MASK_SH_LIST(_MASK) +}; + +static const struct resource_caps res_cap_dcn32 = { + .num_timing_generator = 4, + .num_opp = 4, + .num_video_plane = 4, + .num_audio = 5, + .num_stream_encoder = 5, + .num_hpo_dp_stream_encoder = 4, + .num_hpo_dp_link_encoder = 2, + .num_pll = 5, + .num_dwb = 1, + .num_ddc = 5, + .num_vmid = 16, + .num_mpc_3dlut = 4, + .num_dsc = 4, +}; + +static const struct dc_plane_cap plane_cap = { + .type = DC_PLANE_TYPE_DCN_UNIVERSAL, + .per_pixel_alpha = true, + + .pixel_format_support = { + .argb8888 = true, + .nv12 = true, + .fp16 = true, + .p010 = true, + .ayuv = false, + }, + + .max_upscale_factor = { + .argb8888 = 16000, + .nv12 = 16000, + .fp16 = 16000 + }, + + // 6:1 downscaling ratio: 1000/6 = 166.666 + .max_downscale_factor = { + .argb8888 = 167, + .nv12 = 167, + .fp16 = 167 + }, + 64, + 64 +}; + +static const struct dc_debug_options debug_defaults_drv = { + .disable_dmcu = true, + .force_abm_enable = false, + .timing_trace = false, + .clock_trace = true, + .disable_pplib_clock_request = false, + .pipe_split_policy = MPC_SPLIT_AVOID, // Due to CRB, no need to MPC split anymore + .force_single_disp_pipe_split = false, + .disable_dcc = DCC_ENABLE, + .vsr_support = true, + .performance_trace = false, + .max_downscale_src_width = 7680,/*upto 8K*/ + .disable_pplib_wm_range = false, + .scl_reset_length10 = true, + .sanity_checks = false, + .underflow_assert_delay_us = 0xFFFFFFFF, + .dwb_fi_phase = -1, // -1 = disable, + .dmub_command_table = true, + .enable_mem_low_power = { + .bits = { + .vga = false, + .i2c = false, + .dmcu = false, // This is previously known to cause hang on S3 cycles if enabled + .dscl = false, + .cm = false, + .mpc = false, + .optc = true, + } + }, + .use_max_lb = true, + .force_disable_subvp = false, + .exit_idle_opt_for_cursor_updates = true, + .using_dml2 = false, + .enable_single_display_2to1_odm_policy = true, + + /* Must match enable_single_display_2to1_odm_policy to support dynamic ODM transitions*/ + .enable_double_buffered_dsc_pg_support = true, + .enable_dp_dig_pixel_rate_div_policy = 1, + .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, + .override_dispclk_programming = true, + .disable_fpo_optimizations = false, + .fpo_vactive_margin_us = 2000, // 2000us + .disable_fpo_vactive = false, + .disable_boot_optimizations = false, + .disable_subvp_high_refresh = false, + .disable_dp_plus_plus_wa = true, + .fpo_vactive_min_active_margin_us = 200, + .fpo_vactive_max_blank_us = 1000, + .enable_legacy_fast_update = false, +}; + +static struct dce_aux *dcn32_aux_engine_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct aux_engine_dce110 *aux_engine = + kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); + + if (!aux_engine) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT aux_engine_regs + aux_engine_regs_init(0), + aux_engine_regs_init(1), + aux_engine_regs_init(2), + aux_engine_regs_init(3), + aux_engine_regs_init(4); + + dce110_aux_engine_construct(aux_engine, ctx, inst, + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, + &aux_engine_regs[inst], + &aux_mask, + &aux_shift, + ctx->dc->caps.extended_aux_timeout_support); + + return &aux_engine->base; +} +#define i2c_inst_regs_init(id)\ + I2C_HW_ENGINE_COMMON_REG_LIST_DCN30_RI(id) + +static struct dce_i2c_registers i2c_hw_regs[5]; + +static const struct dce_i2c_shift i2c_shifts = { + I2C_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dce_i2c_mask i2c_masks = { + I2C_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +static struct dce_i2c_hw *dcn32_i2c_hw_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce_i2c_hw *dce_i2c_hw = + kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); + + if (!dce_i2c_hw) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT i2c_hw_regs + i2c_inst_regs_init(1), + i2c_inst_regs_init(2), + i2c_inst_regs_init(3), + i2c_inst_regs_init(4), + i2c_inst_regs_init(5); + + dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst, + &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); + + return dce_i2c_hw; +} + +static struct clock_source *dcn32_clock_source_create( + struct dc_context *ctx, + struct dc_bios *bios, + enum clock_source_id id, + const struct dce110_clk_src_regs *regs, + bool dp_clk_src) +{ + struct dce110_clk_src *clk_src = + kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); + + if (!clk_src) + return NULL; + + if (dcn31_clk_src_construct(clk_src, ctx, bios, id, + regs, &cs_shift, &cs_mask)) { + clk_src->base.dp_clk_src = dp_clk_src; + return &clk_src->base; + } + + kfree(clk_src); + BREAK_TO_DEBUGGER(); + return NULL; +} + +static struct hubbub *dcn32_hubbub_create(struct dc_context *ctx) +{ + int i; + + struct dcn20_hubbub *hubbub2 = kzalloc(sizeof(struct dcn20_hubbub), + GFP_KERNEL); + + if (!hubbub2) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT hubbub_reg + hubbub_reg_init(); + +#undef REG_STRUCT +#define REG_STRUCT vmid_regs + vmid_regs_init(0), + vmid_regs_init(1), + vmid_regs_init(2), + vmid_regs_init(3), + vmid_regs_init(4), + vmid_regs_init(5), + vmid_regs_init(6), + vmid_regs_init(7), + vmid_regs_init(8), + vmid_regs_init(9), + vmid_regs_init(10), + vmid_regs_init(11), + vmid_regs_init(12), + vmid_regs_init(13), + vmid_regs_init(14), + vmid_regs_init(15); + + hubbub32_construct(hubbub2, ctx, + &hubbub_reg, + &hubbub_shift, + &hubbub_mask, + ctx->dc->dml.ip.det_buffer_size_kbytes, + ctx->dc->dml.ip.pixel_chunk_size_kbytes, + ctx->dc->dml.ip.config_return_buffer_size_in_kbytes); + + + for (i = 0; i < res_cap_dcn32.num_vmid; i++) { + struct dcn20_vmid *vmid = &hubbub2->vmid[i]; + + vmid->ctx = ctx; + + vmid->regs = &vmid_regs[i]; + vmid->shifts = &vmid_shifts; + vmid->masks = &vmid_masks; + } + + return &hubbub2->base; +} + +static struct hubp *dcn32_hubp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn20_hubp *hubp2 = + kzalloc(sizeof(struct dcn20_hubp), GFP_KERNEL); + + if (!hubp2) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT hubp_regs + hubp_regs_init(0), + hubp_regs_init(1), + hubp_regs_init(2), + hubp_regs_init(3); + + if (hubp32_construct(hubp2, ctx, inst, + &hubp_regs[inst], &hubp_shift, &hubp_mask)) + return &hubp2->base; + + BREAK_TO_DEBUGGER(); + kfree(hubp2); + return NULL; +} + +static void dcn32_dpp_destroy(struct dpp **dpp) +{ + kfree(TO_DCN30_DPP(*dpp)); + *dpp = NULL; +} + +static struct dpp *dcn32_dpp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn3_dpp *dpp3 = + kzalloc(sizeof(struct dcn3_dpp), GFP_KERNEL); + + if (!dpp3) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT dpp_regs + dpp_regs_init(0), + dpp_regs_init(1), + dpp_regs_init(2), + dpp_regs_init(3); + + if (dpp32_construct(dpp3, ctx, inst, + &dpp_regs[inst], &tf_shift, &tf_mask)) + return &dpp3->base; + + BREAK_TO_DEBUGGER(); + kfree(dpp3); + return NULL; +} + +static struct mpc *dcn32_mpc_create( + struct dc_context *ctx, + int num_mpcc, + int num_rmu) +{ + struct dcn30_mpc *mpc30 = kzalloc(sizeof(struct dcn30_mpc), + GFP_KERNEL); + + if (!mpc30) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT mpc_regs + dcn_mpc_regs_init(); + + dcn32_mpc_construct(mpc30, ctx, + &mpc_regs, + &mpc_shift, + &mpc_mask, + num_mpcc, + num_rmu); + + return &mpc30->base; +} + +static struct output_pixel_processor *dcn32_opp_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dcn20_opp *opp2 = + kzalloc(sizeof(struct dcn20_opp), GFP_KERNEL); + + if (!opp2) { + BREAK_TO_DEBUGGER(); + return NULL; + } + +#undef REG_STRUCT +#define REG_STRUCT opp_regs + opp_regs_init(0), + opp_regs_init(1), + opp_regs_init(2), + opp_regs_init(3); + + dcn20_opp_construct(opp2, ctx, inst, + &opp_regs[inst], &opp_shift, &opp_mask); + return &opp2->base; +} + + +static struct timing_generator *dcn32_timing_generator_create( + struct dc_context *ctx, + uint32_t instance) +{ + struct optc *tgn10 = + kzalloc(sizeof(struct optc), GFP_KERNEL); + + if (!tgn10) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT optc_regs + optc_regs_init(0), + optc_regs_init(1), + optc_regs_init(2), + optc_regs_init(3); + + tgn10->base.inst = instance; + tgn10->base.ctx = ctx; + + tgn10->tg_regs = &optc_regs[instance]; + tgn10->tg_shift = &optc_shift; + tgn10->tg_mask = &optc_mask; + + dcn32_timing_generator_init(tgn10); + + return &tgn10->base; +} + +static const struct encoder_feature_support link_enc_feature = { + .max_hdmi_deep_color = COLOR_DEPTH_121212, + .max_hdmi_pixel_clock = 600000, + .hdmi_ycbcr420_supported = true, + .dp_ycbcr420_supported = true, + .fec_supported = true, + .flags.bits.IS_HBR2_CAPABLE = true, + .flags.bits.IS_HBR3_CAPABLE = true, + .flags.bits.IS_TPS3_CAPABLE = true, + .flags.bits.IS_TPS4_CAPABLE = true +}; + +static struct link_encoder *dcn32_link_encoder_create( + struct dc_context *ctx, + const struct encoder_init_data *enc_init_data) +{ + struct dcn20_link_encoder *enc20 = + kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); + + if (!enc20) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT link_enc_aux_regs + aux_regs_init(0), + aux_regs_init(1), + aux_regs_init(2), + aux_regs_init(3), + aux_regs_init(4); + +#undef REG_STRUCT +#define REG_STRUCT link_enc_hpd_regs + hpd_regs_init(0), + hpd_regs_init(1), + hpd_regs_init(2), + hpd_regs_init(3), + hpd_regs_init(4); + +#undef REG_STRUCT +#define REG_STRUCT link_enc_regs + link_regs_init(0, A), + link_regs_init(1, B), + link_regs_init(2, C), + link_regs_init(3, D), + link_regs_init(4, E); + + dcn32_link_encoder_construct(enc20, + enc_init_data, + &link_enc_feature, + &link_enc_regs[enc_init_data->transmitter], + &link_enc_aux_regs[enc_init_data->channel - 1], + &link_enc_hpd_regs[enc_init_data->hpd_source], + &le_shift, + &le_mask); + + return &enc20->enc10.base; +} + +struct panel_cntl *dcn32_panel_cntl_create(const struct panel_cntl_init_data *init_data) +{ + struct dcn31_panel_cntl *panel_cntl = + kzalloc(sizeof(struct dcn31_panel_cntl), GFP_KERNEL); + + if (!panel_cntl) + return NULL; + + dcn31_panel_cntl_construct(panel_cntl, init_data); + + return &panel_cntl->base; +} + +static void read_dce_straps( + struct dc_context *ctx, + struct resource_straps *straps) +{ + generic_reg_get(ctx, ctx->dcn_reg_offsets[regDC_PINSTRAPS_BASE_IDX] + regDC_PINSTRAPS, + FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio); + +} + +static struct audio *dcn32_create_audio( + struct dc_context *ctx, unsigned int inst) +{ + +#undef REG_STRUCT +#define REG_STRUCT audio_regs + audio_regs_init(0), + audio_regs_init(1), + audio_regs_init(2), + audio_regs_init(3), + audio_regs_init(4); + + return dce_audio_create(ctx, inst, + &audio_regs[inst], &audio_shift, &audio_mask); +} + +static struct vpg *dcn32_vpg_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn30_vpg *vpg3 = kzalloc(sizeof(struct dcn30_vpg), GFP_KERNEL); + + if (!vpg3) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT vpg_regs + vpg_regs_init(0), + vpg_regs_init(1), + vpg_regs_init(2), + vpg_regs_init(3), + vpg_regs_init(4), + vpg_regs_init(5), + vpg_regs_init(6), + vpg_regs_init(7), + vpg_regs_init(8), + vpg_regs_init(9); + + vpg3_construct(vpg3, ctx, inst, + &vpg_regs[inst], + &vpg_shift, + &vpg_mask); + + return &vpg3->base; +} + +static struct afmt *dcn32_afmt_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn30_afmt *afmt3 = kzalloc(sizeof(struct dcn30_afmt), GFP_KERNEL); + + if (!afmt3) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT afmt_regs + afmt_regs_init(0), + afmt_regs_init(1), + afmt_regs_init(2), + afmt_regs_init(3), + afmt_regs_init(4), + afmt_regs_init(5); + + afmt3_construct(afmt3, ctx, inst, + &afmt_regs[inst], + &afmt_shift, + &afmt_mask); + + return &afmt3->base; +} + +static struct apg *dcn31_apg_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn31_apg *apg31 = kzalloc(sizeof(struct dcn31_apg), GFP_KERNEL); + + if (!apg31) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT apg_regs + apg_regs_init(0), + apg_regs_init(1), + apg_regs_init(2), + apg_regs_init(3); + + apg31_construct(apg31, ctx, inst, + &apg_regs[inst], + &apg_shift, + &apg_mask); + + return &apg31->base; +} + +static struct stream_encoder *dcn32_stream_encoder_create( + enum engine_id eng_id, + struct dc_context *ctx) +{ + struct dcn10_stream_encoder *enc1; + struct vpg *vpg; + struct afmt *afmt; + int vpg_inst; + int afmt_inst; + + /* Mapping of VPG, AFMT, DME register blocks to DIO block instance */ + if (eng_id <= ENGINE_ID_DIGF) { + vpg_inst = eng_id; + afmt_inst = eng_id; + } else + return NULL; + + enc1 = kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL); + vpg = dcn32_vpg_create(ctx, vpg_inst); + afmt = dcn32_afmt_create(ctx, afmt_inst); + + if (!enc1 || !vpg || !afmt) { + kfree(enc1); + kfree(vpg); + kfree(afmt); + return NULL; + } + +#undef REG_STRUCT +#define REG_STRUCT stream_enc_regs + stream_enc_regs_init(0), + stream_enc_regs_init(1), + stream_enc_regs_init(2), + stream_enc_regs_init(3), + stream_enc_regs_init(4); + + dcn32_dio_stream_encoder_construct(enc1, ctx, ctx->dc_bios, + eng_id, vpg, afmt, + &stream_enc_regs[eng_id], + &se_shift, &se_mask); + + return &enc1->base; +} + +static struct hpo_dp_stream_encoder *dcn32_hpo_dp_stream_encoder_create( + enum engine_id eng_id, + struct dc_context *ctx) +{ + struct dcn31_hpo_dp_stream_encoder *hpo_dp_enc31; + struct vpg *vpg; + struct apg *apg; + uint32_t hpo_dp_inst; + uint32_t vpg_inst; + uint32_t apg_inst; + + ASSERT((eng_id >= ENGINE_ID_HPO_DP_0) && (eng_id <= ENGINE_ID_HPO_DP_3)); + hpo_dp_inst = eng_id - ENGINE_ID_HPO_DP_0; + + /* Mapping of VPG register blocks to HPO DP block instance: + * VPG[6] -> HPO_DP[0] + * VPG[7] -> HPO_DP[1] + * VPG[8] -> HPO_DP[2] + * VPG[9] -> HPO_DP[3] + */ + vpg_inst = hpo_dp_inst + 6; + + /* Mapping of APG register blocks to HPO DP block instance: + * APG[0] -> HPO_DP[0] + * APG[1] -> HPO_DP[1] + * APG[2] -> HPO_DP[2] + * APG[3] -> HPO_DP[3] + */ + apg_inst = hpo_dp_inst; + + /* allocate HPO stream encoder and create VPG sub-block */ + hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_stream_encoder), GFP_KERNEL); + vpg = dcn32_vpg_create(ctx, vpg_inst); + apg = dcn31_apg_create(ctx, apg_inst); + + if (!hpo_dp_enc31 || !vpg || !apg) { + kfree(hpo_dp_enc31); + kfree(vpg); + kfree(apg); + return NULL; + } + +#undef REG_STRUCT +#define REG_STRUCT hpo_dp_stream_enc_regs + hpo_dp_stream_encoder_reg_init(0), + hpo_dp_stream_encoder_reg_init(1), + hpo_dp_stream_encoder_reg_init(2), + hpo_dp_stream_encoder_reg_init(3); + + dcn31_hpo_dp_stream_encoder_construct(hpo_dp_enc31, ctx, ctx->dc_bios, + hpo_dp_inst, eng_id, vpg, apg, + &hpo_dp_stream_enc_regs[hpo_dp_inst], + &hpo_dp_se_shift, &hpo_dp_se_mask); + + return &hpo_dp_enc31->base; +} + +static struct hpo_dp_link_encoder *dcn32_hpo_dp_link_encoder_create( + uint8_t inst, + struct dc_context *ctx) +{ + struct dcn31_hpo_dp_link_encoder *hpo_dp_enc31; + + /* allocate HPO link encoder */ + hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_link_encoder), GFP_KERNEL); + +#undef REG_STRUCT +#define REG_STRUCT hpo_dp_link_enc_regs + hpo_dp_link_encoder_reg_init(0), + hpo_dp_link_encoder_reg_init(1); + + hpo_dp_link_encoder32_construct(hpo_dp_enc31, ctx, inst, + &hpo_dp_link_enc_regs[inst], + &hpo_dp_le_shift, &hpo_dp_le_mask); + + return &hpo_dp_enc31->base; +} + +static struct dce_hwseq *dcn32_hwseq_create( + struct dc_context *ctx) +{ + struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); + +#undef REG_STRUCT +#define REG_STRUCT hwseq_reg + hwseq_reg_init(); + + if (hws) { + hws->ctx = ctx; + hws->regs = &hwseq_reg; + hws->shifts = &hwseq_shift; + hws->masks = &hwseq_mask; + } + return hws; +} +static const struct resource_create_funcs res_create_funcs = { + .read_dce_straps = read_dce_straps, + .create_audio = dcn32_create_audio, + .create_stream_encoder = dcn32_stream_encoder_create, + .create_hpo_dp_stream_encoder = dcn32_hpo_dp_stream_encoder_create, + .create_hpo_dp_link_encoder = dcn32_hpo_dp_link_encoder_create, + .create_hwseq = dcn32_hwseq_create, +}; + +static void dcn32_resource_destruct(struct dcn32_resource_pool *pool) +{ + unsigned int i; + + for (i = 0; i < pool->base.stream_enc_count; i++) { + if (pool->base.stream_enc[i] != NULL) { + if (pool->base.stream_enc[i]->vpg != NULL) { + kfree(DCN30_VPG_FROM_VPG(pool->base.stream_enc[i]->vpg)); + pool->base.stream_enc[i]->vpg = NULL; + } + if (pool->base.stream_enc[i]->afmt != NULL) { + kfree(DCN30_AFMT_FROM_AFMT(pool->base.stream_enc[i]->afmt)); + pool->base.stream_enc[i]->afmt = NULL; + } + kfree(DCN10STRENC_FROM_STRENC(pool->base.stream_enc[i])); + pool->base.stream_enc[i] = NULL; + } + } + + for (i = 0; i < pool->base.hpo_dp_stream_enc_count; i++) { + if (pool->base.hpo_dp_stream_enc[i] != NULL) { + if (pool->base.hpo_dp_stream_enc[i]->vpg != NULL) { + kfree(DCN30_VPG_FROM_VPG(pool->base.hpo_dp_stream_enc[i]->vpg)); + pool->base.hpo_dp_stream_enc[i]->vpg = NULL; + } + if (pool->base.hpo_dp_stream_enc[i]->apg != NULL) { + kfree(DCN31_APG_FROM_APG(pool->base.hpo_dp_stream_enc[i]->apg)); + pool->base.hpo_dp_stream_enc[i]->apg = NULL; + } + kfree(DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(pool->base.hpo_dp_stream_enc[i])); + pool->base.hpo_dp_stream_enc[i] = NULL; + } + } + + for (i = 0; i < pool->base.hpo_dp_link_enc_count; i++) { + if (pool->base.hpo_dp_link_enc[i] != NULL) { + kfree(DCN3_1_HPO_DP_LINK_ENC_FROM_HPO_LINK_ENC(pool->base.hpo_dp_link_enc[i])); + pool->base.hpo_dp_link_enc[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_dsc; i++) { + if (pool->base.dscs[i] != NULL) + dcn20_dsc_destroy(&pool->base.dscs[i]); + } + + if (pool->base.mpc != NULL) { + kfree(TO_DCN20_MPC(pool->base.mpc)); + pool->base.mpc = NULL; + } + if (pool->base.hubbub != NULL) { + kfree(TO_DCN20_HUBBUB(pool->base.hubbub)); + pool->base.hubbub = NULL; + } + for (i = 0; i < pool->base.pipe_count; i++) { + if (pool->base.dpps[i] != NULL) + dcn32_dpp_destroy(&pool->base.dpps[i]); + + if (pool->base.ipps[i] != NULL) + pool->base.ipps[i]->funcs->ipp_destroy(&pool->base.ipps[i]); + + if (pool->base.hubps[i] != NULL) { + kfree(TO_DCN20_HUBP(pool->base.hubps[i])); + pool->base.hubps[i] = NULL; + } + + if (pool->base.irqs != NULL) { + dal_irq_service_destroy(&pool->base.irqs); + } + } + + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + if (pool->base.engines[i] != NULL) + dce110_engine_destroy(&pool->base.engines[i]); + if (pool->base.hw_i2cs[i] != NULL) { + kfree(pool->base.hw_i2cs[i]); + pool->base.hw_i2cs[i] = NULL; + } + if (pool->base.sw_i2cs[i] != NULL) { + kfree(pool->base.sw_i2cs[i]); + pool->base.sw_i2cs[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_opp; i++) { + if (pool->base.opps[i] != NULL) + pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]); + } + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + if (pool->base.timing_generators[i] != NULL) { + kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i])); + pool->base.timing_generators[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_dwb; i++) { + if (pool->base.dwbc[i] != NULL) { + kfree(TO_DCN30_DWBC(pool->base.dwbc[i])); + pool->base.dwbc[i] = NULL; + } + if (pool->base.mcif_wb[i] != NULL) { + kfree(TO_DCN30_MMHUBBUB(pool->base.mcif_wb[i])); + pool->base.mcif_wb[i] = NULL; + } + } + + for (i = 0; i < pool->base.audio_count; i++) { + if (pool->base.audios[i]) + dce_aud_destroy(&pool->base.audios[i]); + } + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] != NULL) { + dcn20_clock_source_destroy(&pool->base.clock_sources[i]); + pool->base.clock_sources[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_mpc_3dlut; i++) { + if (pool->base.mpc_lut[i] != NULL) { + dc_3dlut_func_release(pool->base.mpc_lut[i]); + pool->base.mpc_lut[i] = NULL; + } + if (pool->base.mpc_shaper[i] != NULL) { + dc_transfer_func_release(pool->base.mpc_shaper[i]); + pool->base.mpc_shaper[i] = NULL; + } + } + + if (pool->base.dp_clock_source != NULL) { + dcn20_clock_source_destroy(&pool->base.dp_clock_source); + pool->base.dp_clock_source = NULL; + } + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + if (pool->base.multiple_abms[i] != NULL) + dce_abm_destroy(&pool->base.multiple_abms[i]); + } + + if (pool->base.psr != NULL) + dmub_psr_destroy(&pool->base.psr); + + if (pool->base.dccg != NULL) + dcn_dccg_destroy(&pool->base.dccg); + + if (pool->base.oem_device != NULL) { + struct dc *dc = pool->base.oem_device->ctx->dc; + + dc->link_srv->destroy_ddc_service(&pool->base.oem_device); + } +} + + +static bool dcn32_dwbc_create(struct dc_context *ctx, struct resource_pool *pool) +{ + int i; + uint32_t dwb_count = pool->res_cap->num_dwb; + + for (i = 0; i < dwb_count; i++) { + struct dcn30_dwbc *dwbc30 = kzalloc(sizeof(struct dcn30_dwbc), + GFP_KERNEL); + + if (!dwbc30) { + dm_error("DC: failed to create dwbc30!\n"); + return false; + } + +#undef REG_STRUCT +#define REG_STRUCT dwbc30_regs + dwbc_regs_dcn3_init(0); + + dcn30_dwbc_construct(dwbc30, ctx, + &dwbc30_regs[i], + &dwbc30_shift, + &dwbc30_mask, + i); + + pool->dwbc[i] = &dwbc30->base; + } + return true; +} + +static bool dcn32_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool) +{ + int i; + uint32_t dwb_count = pool->res_cap->num_dwb; + + for (i = 0; i < dwb_count; i++) { + struct dcn30_mmhubbub *mcif_wb30 = kzalloc(sizeof(struct dcn30_mmhubbub), + GFP_KERNEL); + + if (!mcif_wb30) { + dm_error("DC: failed to create mcif_wb30!\n"); + return false; + } + +#undef REG_STRUCT +#define REG_STRUCT mcif_wb30_regs + mcif_wb_regs_dcn3_init(0); + + dcn32_mmhubbub_construct(mcif_wb30, ctx, + &mcif_wb30_regs[i], + &mcif_wb30_shift, + &mcif_wb30_mask, + i); + + pool->mcif_wb[i] = &mcif_wb30->base; + } + return true; +} + +static struct display_stream_compressor *dcn32_dsc_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dcn20_dsc *dsc = + kzalloc(sizeof(struct dcn20_dsc), GFP_KERNEL); + + if (!dsc) { + BREAK_TO_DEBUGGER(); + return NULL; + } + +#undef REG_STRUCT +#define REG_STRUCT dsc_regs + dsc_regsDCN20_init(0), + dsc_regsDCN20_init(1), + dsc_regsDCN20_init(2), + dsc_regsDCN20_init(3); + + dsc2_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask); + + dsc->max_image_width = 6016; + + return &dsc->base; +} + +static void dcn32_destroy_resource_pool(struct resource_pool **pool) +{ + struct dcn32_resource_pool *dcn32_pool = TO_DCN32_RES_POOL(*pool); + + dcn32_resource_destruct(dcn32_pool); + kfree(dcn32_pool); + *pool = NULL; +} + +bool dcn32_acquire_post_bldn_3dlut( + struct resource_context *res_ctx, + const struct resource_pool *pool, + int mpcc_id, + struct dc_3dlut **lut, + struct dc_transfer_func **shaper) +{ + bool ret = false; + + ASSERT(*lut == NULL && *shaper == NULL); + *lut = NULL; + *shaper = NULL; + + if (!res_ctx->is_mpc_3dlut_acquired[mpcc_id]) { + *lut = pool->mpc_lut[mpcc_id]; + *shaper = pool->mpc_shaper[mpcc_id]; + res_ctx->is_mpc_3dlut_acquired[mpcc_id] = true; + ret = true; + } + return ret; +} + +bool dcn32_release_post_bldn_3dlut( + struct resource_context *res_ctx, + const struct resource_pool *pool, + struct dc_3dlut **lut, + struct dc_transfer_func **shaper) +{ + int i; + bool ret = false; + + for (i = 0; i < pool->res_cap->num_mpc_3dlut; i++) { + if (pool->mpc_lut[i] == *lut && pool->mpc_shaper[i] == *shaper) { + res_ctx->is_mpc_3dlut_acquired[i] = false; + pool->mpc_lut[i]->state.raw = 0; + *lut = NULL; + *shaper = NULL; + ret = true; + break; + } + } + return ret; +} + +static void dcn32_enable_phantom_plane(struct dc *dc, + struct dc_state *context, + struct dc_stream_state *phantom_stream, + unsigned int dc_pipe_idx) +{ + struct dc_plane_state *phantom_plane = NULL; + struct dc_plane_state *prev_phantom_plane = NULL; + struct pipe_ctx *curr_pipe = &context->res_ctx.pipe_ctx[dc_pipe_idx]; + + while (curr_pipe) { + if (curr_pipe->top_pipe && curr_pipe->top_pipe->plane_state == curr_pipe->plane_state) + phantom_plane = prev_phantom_plane; + else + phantom_plane = dc_state_create_phantom_plane(dc, context, curr_pipe->plane_state); + + memcpy(&phantom_plane->address, &curr_pipe->plane_state->address, sizeof(phantom_plane->address)); + memcpy(&phantom_plane->scaling_quality, &curr_pipe->plane_state->scaling_quality, + sizeof(phantom_plane->scaling_quality)); + memcpy(&phantom_plane->src_rect, &curr_pipe->plane_state->src_rect, sizeof(phantom_plane->src_rect)); + memcpy(&phantom_plane->dst_rect, &curr_pipe->plane_state->dst_rect, sizeof(phantom_plane->dst_rect)); + memcpy(&phantom_plane->clip_rect, &curr_pipe->plane_state->clip_rect, sizeof(phantom_plane->clip_rect)); + memcpy(&phantom_plane->plane_size, &curr_pipe->plane_state->plane_size, + sizeof(phantom_plane->plane_size)); + memcpy(&phantom_plane->tiling_info, &curr_pipe->plane_state->tiling_info, + sizeof(phantom_plane->tiling_info)); + memcpy(&phantom_plane->dcc, &curr_pipe->plane_state->dcc, sizeof(phantom_plane->dcc)); + phantom_plane->format = curr_pipe->plane_state->format; + phantom_plane->rotation = curr_pipe->plane_state->rotation; + phantom_plane->visible = curr_pipe->plane_state->visible; + + /* Shadow pipe has small viewport. */ + phantom_plane->clip_rect.y = 0; + phantom_plane->clip_rect.height = phantom_stream->src.height; + + dc_state_add_phantom_plane(dc, phantom_stream, phantom_plane, context); + + curr_pipe = curr_pipe->bottom_pipe; + prev_phantom_plane = phantom_plane; + } +} + +static struct dc_stream_state *dcn32_enable_phantom_stream(struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + unsigned int pipe_cnt, + unsigned int dc_pipe_idx) +{ + struct dc_stream_state *phantom_stream = NULL; + struct pipe_ctx *ref_pipe = &context->res_ctx.pipe_ctx[dc_pipe_idx]; + + phantom_stream = dc_state_create_phantom_stream(dc, context, ref_pipe->stream); + + /* stream has limited viewport and small timing */ + memcpy(&phantom_stream->timing, &ref_pipe->stream->timing, sizeof(phantom_stream->timing)); + memcpy(&phantom_stream->src, &ref_pipe->stream->src, sizeof(phantom_stream->src)); + memcpy(&phantom_stream->dst, &ref_pipe->stream->dst, sizeof(phantom_stream->dst)); + DC_FP_START(); + dcn32_set_phantom_stream_timing(dc, context, ref_pipe, phantom_stream, pipes, pipe_cnt, dc_pipe_idx); + DC_FP_END(); + + dc_state_add_phantom_stream(dc, context, phantom_stream, ref_pipe->stream); + return phantom_stream; +} + +/* TODO: Input to this function should indicate which pipe indexes (or streams) + * require a phantom pipe / stream + */ +void dcn32_add_phantom_pipes(struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes, + unsigned int pipe_cnt, + unsigned int index) +{ + struct dc_stream_state *phantom_stream = NULL; + unsigned int i; + + // The index of the DC pipe passed into this function is guarenteed to + // be a valid candidate for SubVP (i.e. has a plane, stream, doesn't + // already have phantom pipe assigned, etc.) by previous checks. + phantom_stream = dcn32_enable_phantom_stream(dc, context, pipes, pipe_cnt, index); + dcn32_enable_phantom_plane(dc, context, phantom_stream, index); + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + + // Build scaling params for phantom pipes which were newly added. + // We determine which phantom pipes were added by comparing with + // the phantom stream. + if (pipe->plane_state && pipe->stream && pipe->stream == phantom_stream && + dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) { + pipe->stream->use_dynamic_meta = false; + pipe->plane_state->flip_immediate = false; + if (!resource_build_scaling_params(pipe)) { + // Log / remove phantom pipes since failed to build scaling params + } + } + } +} + +static bool dml1_validate(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); + + /* To handle Freesync properly, setting FreeSync DML parameters + * to its default state for the first stage of validation + */ + context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching = false; + context->bw_ctx.dml.soc.dram_clock_change_requirement_final = true; + + DC_LOGGER_INIT(dc->ctx->logger); + + BW_VAL_TRACE_COUNT(); + + DC_FP_START(); + out = dcn32_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, fast_validate); + DC_FP_END(); + + if (pipe_cnt == 0) + goto validate_out; + + 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); + + dcn32_override_min_req_memclk(dc, context); + + 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; +} + +bool dcn32_validate_bandwidth(struct dc *dc, + struct dc_state *context, + bool fast_validate) +{ + bool out = false; + + if (dc->debug.using_dml2) + out = dml2_validate(dc, context, fast_validate); + else + out = dml1_validate(dc, context, fast_validate); + return out; +} + +int dcn32_populate_dml_pipes_from_context( + struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes, + bool fast_validate) +{ + int i, pipe_cnt; + struct resource_context *res_ctx = &context->res_ctx; + struct pipe_ctx *pipe = NULL; + bool subvp_in_use = false; + struct dc_crtc_timing *timing; + + dcn20_populate_dml_pipes_from_context(dc, context, pipes, fast_validate); + + for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) { + + if (!res_ctx->pipe_ctx[i].stream) + continue; + pipe = &res_ctx->pipe_ctx[i]; + timing = &pipe->stream->timing; + + pipes[pipe_cnt].pipe.src.gpuvm = true; + DC_FP_START(); + dcn32_zero_pipe_dcc_fraction(pipes, pipe_cnt); + DC_FP_END(); + pipes[pipe_cnt].pipe.dest.vfront_porch = timing->v_front_porch; + pipes[pipe_cnt].pipe.dest.odm_combine_policy = dm_odm_combine_policy_dal; + pipes[pipe_cnt].pipe.src.gpuvm_min_page_size_kbytes = 256; // according to spreadsheet + pipes[pipe_cnt].pipe.src.unbounded_req_mode = false; + pipes[pipe_cnt].pipe.scale_ratio_depth.lb_depth = dm_lb_19; + + /* Only populate DML input with subvp info for full updates. + * This is just a workaround -- needs a proper fix. + */ + if (!fast_validate) { + switch (dc_state_get_pipe_subvp_type(context, pipe)) { + case SUBVP_MAIN: + pipes[pipe_cnt].pipe.src.use_mall_for_pstate_change = dm_use_mall_pstate_change_sub_viewport; + subvp_in_use = true; + break; + case SUBVP_PHANTOM: + pipes[pipe_cnt].pipe.src.use_mall_for_pstate_change = dm_use_mall_pstate_change_phantom_pipe; + pipes[pipe_cnt].pipe.src.use_mall_for_static_screen = dm_use_mall_static_screen_disable; + // Disallow unbounded req for SubVP according to DCHUB programming guide + pipes[pipe_cnt].pipe.src.unbounded_req_mode = false; + break; + case SUBVP_NONE: + pipes[pipe_cnt].pipe.src.use_mall_for_pstate_change = dm_use_mall_pstate_change_disable; + pipes[pipe_cnt].pipe.src.use_mall_for_static_screen = dm_use_mall_static_screen_disable; + break; + default: + break; + } + } + + pipes[pipe_cnt].dout.dsc_input_bpc = 0; + if (pipes[pipe_cnt].dout.dsc_enable) { + switch (timing->display_color_depth) { + case COLOR_DEPTH_888: + pipes[pipe_cnt].dout.dsc_input_bpc = 8; + break; + case COLOR_DEPTH_101010: + pipes[pipe_cnt].dout.dsc_input_bpc = 10; + break; + case COLOR_DEPTH_121212: + pipes[pipe_cnt].dout.dsc_input_bpc = 12; + break; + default: + ASSERT(0); + break; + } + } + + + pipe_cnt++; + } + + /* For DET allocation, we don't want to use DML policy (not optimal for utilizing all + * the DET available for each pipe). Use the DET override input to maintain our driver + * policy. + */ + dcn32_set_det_allocations(dc, context, pipes); + + // In general cases we want to keep the dram clock change requirement + // (prefer configs that support MCLK switch). Only override to false + // for SubVP + if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching || subvp_in_use) + context->bw_ctx.dml.soc.dram_clock_change_requirement_final = false; + else + context->bw_ctx.dml.soc.dram_clock_change_requirement_final = true; + + return pipe_cnt; +} + +static struct dc_cap_funcs cap_funcs = { + .get_dcc_compression_cap = dcn20_get_dcc_compression_cap, + .get_subvp_en = dcn32_subvp_in_use, +}; + +void dcn32_calculate_wm_and_dlg(struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int pipe_cnt, + int vlevel) +{ + DC_FP_START(); + dcn32_calculate_wm_and_dlg_fpu(dc, context, pipes, pipe_cnt, vlevel); + DC_FP_END(); +} + +static void dcn32_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) +{ + DC_FP_START(); + dcn32_update_bw_bounding_box_fpu(dc, bw_params); + DC_FP_END(); +} + +static struct resource_funcs dcn32_res_pool_funcs = { + .destroy = dcn32_destroy_resource_pool, + .link_enc_create = dcn32_link_encoder_create, + .link_enc_create_minimal = NULL, + .panel_cntl_create = dcn32_panel_cntl_create, + .validate_bandwidth = dcn32_validate_bandwidth, + .calculate_wm_and_dlg = dcn32_calculate_wm_and_dlg, + .populate_dml_pipes = dcn32_populate_dml_pipes_from_context, + .acquire_free_pipe_as_secondary_dpp_pipe = dcn32_acquire_free_pipe_as_secondary_dpp_pipe, + .acquire_free_pipe_as_secondary_opp_head = dcn32_acquire_free_pipe_as_secondary_opp_head, + .release_pipe = dcn20_release_pipe, + .add_stream_to_ctx = dcn30_add_stream_to_ctx, + .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource, + .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, + .populate_dml_writeback_from_context = dcn30_populate_dml_writeback_from_context, + .set_mcif_arb_params = dcn30_set_mcif_arb_params, + .find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link, + .acquire_post_bldn_3dlut = dcn32_acquire_post_bldn_3dlut, + .release_post_bldn_3dlut = dcn32_release_post_bldn_3dlut, + .update_bw_bounding_box = dcn32_update_bw_bounding_box, + .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, + .update_soc_for_wm_a = dcn30_update_soc_for_wm_a, + .add_phantom_pipes = dcn32_add_phantom_pipes, + .build_pipe_pix_clk_params = dcn20_build_pipe_pix_clk_params, +}; + +static uint32_t read_pipe_fuses(struct dc_context *ctx) +{ + uint32_t value = REG_READ(CC_DC_PIPE_DIS); + /* DCN32 support max 4 pipes */ + value = value & 0xf; + return value; +} + + +static bool dcn32_resource_construct( + uint8_t num_virtual_links, + struct dc *dc, + struct dcn32_resource_pool *pool) +{ + int i, j; + struct dc_context *ctx = dc->ctx; + struct irq_service_init_data init_data; + struct ddc_service_init_data ddc_init_data = {0}; + uint32_t pipe_fuses = 0; + uint32_t num_pipes = 4; + +#undef REG_STRUCT +#define REG_STRUCT bios_regs + bios_regs_init(); + +#undef REG_STRUCT +#define REG_STRUCT clk_src_regs + clk_src_regs_init(0, A), + clk_src_regs_init(1, B), + clk_src_regs_init(2, C), + clk_src_regs_init(3, D), + clk_src_regs_init(4, E); + +#undef REG_STRUCT +#define REG_STRUCT abm_regs + abm_regs_init(0), + abm_regs_init(1), + abm_regs_init(2), + abm_regs_init(3); + +#undef REG_STRUCT +#define REG_STRUCT dccg_regs + dccg_regs_init(); + + DC_FP_START(); + + ctx->dc_bios->regs = &bios_regs; + + pool->base.res_cap = &res_cap_dcn32; + /* max number of pipes for ASIC before checking for pipe fuses */ + num_pipes = pool->base.res_cap->num_timing_generator; + pipe_fuses = read_pipe_fuses(ctx); + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) + if (pipe_fuses & 1 << i) + num_pipes--; + + if (pipe_fuses & 1) + ASSERT(0); //Unexpected - Pipe 0 should always be fully functional! + + if (pipe_fuses & CC_DC_PIPE_DIS__DC_FULL_DIS_MASK) + ASSERT(0); //Entire DCN is harvested! + + /* within dml lib, initial value is hard coded, if ASIC pipe is fused, the + * value will be changed, update max_num_dpp and max_num_otg for dml. + */ + dcn3_2_ip.max_num_dpp = num_pipes; + dcn3_2_ip.max_num_otg = num_pipes; + + pool->base.funcs = &dcn32_res_pool_funcs; + + /************************************************* + * Resource + asic cap harcoding * + *************************************************/ + pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.timing_generator_count = num_pipes; + pool->base.pipe_count = num_pipes; + pool->base.mpcc_count = num_pipes; + dc->caps.max_downscale_ratio = 600; + dc->caps.i2c_speed_in_khz = 100; + dc->caps.i2c_speed_in_khz_hdcp = 100; /*1.4 w/a applied by default*/ + /* TODO: Bring max_cursor_size back to 256 after subvp cursor corruption is fixed*/ + 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 = 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; + + /* 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; + dc->caps.subvp_swath_height_margin_lines = 16; + dc->caps.subvp_pstate_allow_width_us = 20; + dc->caps.subvp_vertical_int_margin_us = 30; + dc->caps.subvp_drr_vblank_start_margin_us = 100; // 100us margin + + dc->caps.max_slave_planes = 2; + dc->caps.max_slave_yuv_planes = 2; + dc->caps.max_slave_rgb_planes = 2; + dc->caps.post_blend_color_processing = true; + dc->caps.force_dp_tps4_for_cp2520 = true; + if (dc->config.forceHBR2CP2520) + dc->caps.force_dp_tps4_for_cp2520 = false; + dc->caps.dp_hpo = true; + dc->caps.dp_hdmi21_pcon_support = true; + dc->caps.edp_dsc_support = true; + dc->caps.extended_aux_timeout_support = true; + dc->caps.dmcub_support = true; + dc->caps.seamless_odm = true; + dc->caps.max_v_total = (1 << 15) - 1; + + /* Color pipeline capabilities */ + dc->caps.color.dpp.dcn_arch = 1; + dc->caps.color.dpp.input_lut_shared = 0; + dc->caps.color.dpp.icsc = 1; + dc->caps.color.dpp.dgam_ram = 0; // must use gamma_corr + dc->caps.color.dpp.dgam_rom_caps.srgb = 1; + dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1; + dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 1; + dc->caps.color.dpp.dgam_rom_caps.pq = 1; + dc->caps.color.dpp.dgam_rom_caps.hlg = 1; + dc->caps.color.dpp.post_csc = 1; + dc->caps.color.dpp.gamma_corr = 1; + dc->caps.color.dpp.dgam_rom_for_yuv = 0; + + dc->caps.color.dpp.hw_3d_lut = 1; + dc->caps.color.dpp.ogam_ram = 0; // no OGAM in DPP since DCN1 + // no OGAM ROM on DCN2 and later ASICs + dc->caps.color.dpp.ogam_rom_caps.srgb = 0; + dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0; + dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0; + dc->caps.color.dpp.ogam_rom_caps.pq = 0; + dc->caps.color.dpp.ogam_rom_caps.hlg = 0; + dc->caps.color.dpp.ocsc = 0; + + dc->caps.color.mpc.gamut_remap = 1; + dc->caps.color.mpc.num_3dluts = pool->base.res_cap->num_mpc_3dlut; //4, configurable to be before or after BLND in MPCC + dc->caps.color.mpc.ogam_ram = 1; + dc->caps.color.mpc.ogam_rom_caps.srgb = 0; + dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0; + dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0; + dc->caps.color.mpc.ogam_rom_caps.pq = 0; + dc->caps.color.mpc.ogam_rom_caps.hlg = 0; + dc->caps.color.mpc.ocsc = 1; + + /* Use pipe context based otg sync logic */ + dc->config.use_pipe_ctx_sync_logic = true; + + dc->config.dc_mode_clk_limit_support = true; + /* read VBIOS LTTPR caps */ + { + if (ctx->dc_bios->funcs->get_lttpr_caps) { + enum bp_result bp_query_result; + uint8_t is_vbios_lttpr_enable = 0; + + bp_query_result = ctx->dc_bios->funcs->get_lttpr_caps(ctx->dc_bios, &is_vbios_lttpr_enable); + dc->caps.vbios_lttpr_enable = (bp_query_result == BP_RESULT_OK) && !!is_vbios_lttpr_enable; + } + + /* interop bit is implicit */ + { + dc->caps.vbios_lttpr_aware = true; + } + } + + if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) + dc->debug = debug_defaults_drv; + + // Init the vm_helper + if (dc->vm_helper) + vm_helper_init(dc->vm_helper, 16); + + /************************************************* + * Create resources * + *************************************************/ + + /* Clock Sources for Pixel Clock*/ + pool->base.clock_sources[DCN32_CLK_SRC_PLL0] = + dcn32_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL0, + &clk_src_regs[0], false); + pool->base.clock_sources[DCN32_CLK_SRC_PLL1] = + dcn32_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL1, + &clk_src_regs[1], false); + pool->base.clock_sources[DCN32_CLK_SRC_PLL2] = + dcn32_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL2, + &clk_src_regs[2], false); + pool->base.clock_sources[DCN32_CLK_SRC_PLL3] = + dcn32_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL3, + &clk_src_regs[3], false); + pool->base.clock_sources[DCN32_CLK_SRC_PLL4] = + dcn32_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL4, + &clk_src_regs[4], false); + + pool->base.clk_src_count = DCN32_CLK_SRC_TOTAL; + + /* todo: not reuse phy_pll registers */ + pool->base.dp_clock_source = + dcn32_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_ID_DP_DTO, + &clk_src_regs[0], true); + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] == NULL) { + dm_error("DC: failed to create clock sources!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + } + + /* DCCG */ + pool->base.dccg = dccg32_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask); + if (pool->base.dccg == NULL) { + dm_error("DC: failed to create dccg!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + /* DML */ + dml_init_instance(&dc->dml, &dcn3_2_soc, &dcn3_2_ip, DML_PROJECT_DCN32); + + /* IRQ Service */ + init_data.ctx = dc->ctx; + pool->base.irqs = dal_irq_service_dcn32_create(&init_data); + if (!pool->base.irqs) + goto create_fail; + + /* HUBBUB */ + pool->base.hubbub = dcn32_hubbub_create(ctx); + if (pool->base.hubbub == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create hubbub!\n"); + goto create_fail; + } + + /* HUBPs, DPPs, OPPs, TGs, ABMs */ + for (i = 0, j = 0; i < pool->base.res_cap->num_timing_generator; i++) { + + /* if pipe is disabled, skip instance of HW pipe, + * i.e, skip ASIC register instance + */ + if (pipe_fuses & 1 << i) + continue; + + /* HUBPs */ + pool->base.hubps[j] = dcn32_hubp_create(ctx, i); + if (pool->base.hubps[j] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create hubps!\n"); + goto create_fail; + } + + /* DPPs */ + pool->base.dpps[j] = dcn32_dpp_create(ctx, i); + if (pool->base.dpps[j] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create dpps!\n"); + goto create_fail; + } + + /* OPPs */ + pool->base.opps[j] = dcn32_opp_create(ctx, i); + if (pool->base.opps[j] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create output pixel processor!\n"); + goto create_fail; + } + + /* TGs */ + pool->base.timing_generators[j] = dcn32_timing_generator_create( + ctx, i); + if (pool->base.timing_generators[j] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create tg!\n"); + goto create_fail; + } + + /* ABMs */ + pool->base.multiple_abms[j] = dmub_abm_create(ctx, + &abm_regs[i], + &abm_shift, + &abm_mask); + if (pool->base.multiple_abms[j] == NULL) { + dm_error("DC: failed to create abm for pipe %d!\n", i); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + /* index for resource pool arrays for next valid pipe */ + j++; + } + + /* PSR */ + pool->base.psr = dmub_psr_create(ctx); + if (pool->base.psr == NULL) { + dm_error("DC: failed to create psr obj!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + /* MPCCs */ + pool->base.mpc = dcn32_mpc_create(ctx, pool->base.res_cap->num_timing_generator, pool->base.res_cap->num_mpc_3dlut); + if (pool->base.mpc == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create mpc!\n"); + goto create_fail; + } + + /* DSCs */ + for (i = 0; i < pool->base.res_cap->num_dsc; i++) { + pool->base.dscs[i] = dcn32_dsc_create(ctx, i); + if (pool->base.dscs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create display stream compressor %d!\n", i); + goto create_fail; + } + } + + /* DWB */ + if (!dcn32_dwbc_create(ctx, &pool->base)) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dwbc!\n"); + goto create_fail; + } + + /* MMHUBBUB */ + if (!dcn32_mmhubbub_create(ctx, &pool->base)) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create mcif_wb!\n"); + goto create_fail; + } + + /* AUX and I2C */ + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + pool->base.engines[i] = dcn32_aux_engine_create(ctx, i); + if (pool->base.engines[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create aux engine!!\n"); + goto create_fail; + } + pool->base.hw_i2cs[i] = dcn32_i2c_hw_create(ctx, i); + if (pool->base.hw_i2cs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create hw i2c!!\n"); + goto create_fail; + } + pool->base.sw_i2cs[i] = NULL; + } + + /* Audio, HWSeq, Stream Encoders including HPO and virtual, MPC 3D LUTs */ + if (!resource_construct(num_virtual_links, dc, &pool->base, + &res_create_funcs)) + goto create_fail; + + /* HW Sequencer init functions and Plane caps */ + dcn32_hw_sequencer_init_functions(dc); + + dc->caps.max_planes = pool->base.pipe_count; + + for (i = 0; i < dc->caps.max_planes; ++i) + dc->caps.planes[i] = plane_cap; + + 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->base.oem_device = dc->link_srv->create_ddc_service(&ddc_init_data); + } else { + pool->base.oem_device = NULL; + } + + dc->dml2_options.dcn_pipe_count = pool->base.pipe_count; + dc->dml2_options.use_native_pstate_optimization = false; + dc->dml2_options.use_native_soc_bb_construction = true; + dc->dml2_options.minimize_dispclk_using_odm = true; + + dc->dml2_options.callbacks.dc = dc; + dc->dml2_options.callbacks.build_scaling_params = &resource_build_scaling_params; + dc->dml2_options.callbacks.can_support_mclk_switch_using_fw_based_vblank_stretch = &dcn30_can_support_mclk_switch_using_fw_based_vblank_stretch; + dc->dml2_options.callbacks.acquire_secondary_pipe_for_mpc_odm = &dc_resource_acquire_secondary_pipe_for_mpc_odm_legacy; + dc->dml2_options.callbacks.update_pipes_for_stream_with_slice_count = &resource_update_pipes_for_stream_with_slice_count; + dc->dml2_options.callbacks.update_pipes_for_plane_with_slice_count = &resource_update_pipes_for_plane_with_slice_count; + dc->dml2_options.callbacks.get_mpc_slice_index = &resource_get_mpc_slice_index; + dc->dml2_options.callbacks.get_odm_slice_index = &resource_get_odm_slice_index; + dc->dml2_options.callbacks.get_opp_head = &resource_get_opp_head; + + dc->dml2_options.svp_pstate.callbacks.dc = dc; + dc->dml2_options.svp_pstate.callbacks.add_phantom_plane = &dc_state_add_phantom_plane; + dc->dml2_options.svp_pstate.callbacks.add_phantom_stream = &dc_state_add_phantom_stream; + dc->dml2_options.svp_pstate.callbacks.build_scaling_params = &resource_build_scaling_params; + dc->dml2_options.svp_pstate.callbacks.create_phantom_plane = &dc_state_create_phantom_plane; + dc->dml2_options.svp_pstate.callbacks.remove_phantom_plane = &dc_state_remove_phantom_plane; + dc->dml2_options.svp_pstate.callbacks.remove_phantom_stream = &dc_state_remove_phantom_stream; + dc->dml2_options.svp_pstate.callbacks.create_phantom_stream = &dc_state_create_phantom_stream; + dc->dml2_options.svp_pstate.callbacks.release_phantom_plane = &dc_state_release_phantom_plane; + dc->dml2_options.svp_pstate.callbacks.release_phantom_stream = &dc_state_release_phantom_stream; + dc->dml2_options.svp_pstate.callbacks.release_dsc = &dcn20_release_dsc; + dc->dml2_options.svp_pstate.callbacks.get_pipe_subvp_type = &dc_state_get_pipe_subvp_type; + dc->dml2_options.svp_pstate.callbacks.get_stream_subvp_type = &dc_state_get_stream_subvp_type; + dc->dml2_options.svp_pstate.callbacks.get_paired_subvp_stream = &dc_state_get_paired_subvp_stream; + + dc->dml2_options.svp_pstate.subvp_fw_processing_delay_us = dc->caps.subvp_fw_processing_delay_us; + dc->dml2_options.svp_pstate.subvp_prefetch_end_to_mall_start_us = dc->caps.subvp_prefetch_end_to_mall_start_us; + dc->dml2_options.svp_pstate.subvp_pstate_allow_width_us = dc->caps.subvp_pstate_allow_width_us; + dc->dml2_options.svp_pstate.subvp_swath_height_margin_lines = dc->caps.subvp_swath_height_margin_lines; + + dc->dml2_options.svp_pstate.force_disable_subvp = dc->debug.force_disable_subvp; + dc->dml2_options.svp_pstate.force_enable_subvp = dc->debug.force_subvp_mclk_switch; + + dc->dml2_options.mall_cfg.cache_line_size_bytes = dc->caps.cache_line_size; + dc->dml2_options.mall_cfg.cache_num_ways = dc->caps.cache_num_ways; + dc->dml2_options.mall_cfg.max_cab_allocation_bytes = dc->caps.max_cab_allocation_bytes; + dc->dml2_options.mall_cfg.mblk_height_4bpe_pixels = DCN3_2_MBLK_HEIGHT_4BPE; + dc->dml2_options.mall_cfg.mblk_height_8bpe_pixels = DCN3_2_MBLK_HEIGHT_8BPE; + dc->dml2_options.mall_cfg.mblk_size_bytes = DCN3_2_MALL_MBLK_SIZE_BYTES; + dc->dml2_options.mall_cfg.mblk_width_pixels = DCN3_2_MBLK_WIDTH; + + dc->dml2_options.max_segments_per_hubp = 18; + dc->dml2_options.det_segment_size = DCN3_2_DET_SEG_SIZE; + dc->dml2_options.map_dc_pipes_with_callbacks = true; + + if (ASICREV_IS_GC_11_0_3(dc->ctx->asic_id.hw_internal_rev) && (dc->config.sdpif_request_limit_words_per_umc == 0)) + dc->config.sdpif_request_limit_words_per_umc = 16; + + DC_FP_END(); + + return true; + +create_fail: + + DC_FP_END(); + + dcn32_resource_destruct(pool); + + return false; +} + +struct resource_pool *dcn32_create_resource_pool( + const struct dc_init_data *init_data, + struct dc *dc) +{ + struct dcn32_resource_pool *pool = + kzalloc(sizeof(struct dcn32_resource_pool), GFP_KERNEL); + + if (!pool) + return NULL; + + if (dcn32_resource_construct(init_data->num_virtual_links, dc, pool)) + return &pool->base; + + BREAK_TO_DEBUGGER(); + kfree(pool); + return NULL; +} + +/* + * Find the most optimal free pipe from res_ctx, which could be used as a + * secondary dpp pipe for input opp head pipe. + * + * a free pipe - a pipe in input res_ctx not yet used for any streams or + * planes. + * secondary dpp pipe - a pipe gets inserted to a head OPP pipe's MPC blending + * tree. This is typical used for rendering MPO planes or additional offset + * areas in MPCC combine. + * + * Hardware Transition Minimization Algorithm for Finding a Secondary DPP Pipe + * ------------------------------------------------------------------------- + * + * PROBLEM: + * + * 1. There is a hardware limitation that a secondary DPP pipe cannot be + * transferred from one MPC blending tree to the other in a single frame. + * Otherwise it could cause glitches on the screen. + * + * For instance, we cannot transition from state 1 to state 2 in one frame. This + * is because PIPE1 is transferred from PIPE0's MPC blending tree over to + * PIPE2's MPC blending tree, which is not supported by hardware. + * To support this transition we need to first remove PIPE1 from PIPE0's MPC + * blending tree in one frame and then insert PIPE1 to PIPE2's MPC blending tree + * in the next frame. This is not optimal as it will delay the flip for two + * frames. + * + * State 1: + * PIPE0 -- secondary DPP pipe --> (PIPE1) + * PIPE2 -- secondary DPP pipe --> NONE + * + * State 2: + * PIPE0 -- secondary DPP pipe --> NONE + * PIPE2 -- secondary DPP pipe --> (PIPE1) + * + * 2. We want to in general minimize the unnecessary changes in pipe topology. + * If a pipe is already added in current blending tree and there are no changes + * to plane topology, we don't want to swap it with another free pipe + * unnecessarily in every update. Powering up and down a pipe would require a + * full update which delays the flip for 1 frame. If we use the original pipe + * we don't have to toggle its power. So we can flip faster. + */ +static int find_optimal_free_pipe_as_secondary_dpp_pipe( + const struct resource_context *cur_res_ctx, + struct resource_context *new_res_ctx, + const struct resource_pool *pool, + const struct pipe_ctx *new_opp_head) +{ + const struct pipe_ctx *cur_opp_head; + int free_pipe_idx; + + cur_opp_head = &cur_res_ctx->pipe_ctx[new_opp_head->pipe_idx]; + free_pipe_idx = resource_find_free_pipe_used_in_cur_mpc_blending_tree( + cur_res_ctx, new_res_ctx, cur_opp_head); + + /* Up until here if we have not found a free secondary pipe, we will + * need to wait for at least one frame to complete the transition + * sequence. + */ + if (free_pipe_idx == FREE_PIPE_INDEX_NOT_FOUND) + free_pipe_idx = recource_find_free_pipe_not_used_in_cur_res_ctx( + cur_res_ctx, new_res_ctx, pool); + + /* Up until here if we have not found a free secondary pipe, we will + * need to wait for at least two frames to complete the transition + * sequence. It really doesn't matter which pipe we decide take from + * current enabled pipes. It won't save our frame time when we swap only + * one pipe or more pipes. + */ + if (free_pipe_idx == FREE_PIPE_INDEX_NOT_FOUND) + free_pipe_idx = resource_find_free_pipe_used_as_cur_sec_dpp_in_mpcc_combine( + cur_res_ctx, new_res_ctx, pool); + + if (free_pipe_idx == FREE_PIPE_INDEX_NOT_FOUND) + free_pipe_idx = resource_find_any_free_pipe(new_res_ctx, pool); + + return free_pipe_idx; +} + +static struct pipe_ctx *find_idle_secondary_pipe_check_mpo( + struct resource_context *res_ctx, + const struct resource_pool *pool, + const struct pipe_ctx *primary_pipe) +{ + int i; + struct pipe_ctx *secondary_pipe = NULL; + struct pipe_ctx *next_odm_mpo_pipe = NULL; + int primary_index, preferred_pipe_idx; + struct pipe_ctx *old_primary_pipe = NULL; + + /* + * Modified from find_idle_secondary_pipe + * With windowed MPO and ODM, we want to avoid the case where we want a + * free pipe for the left side but the free pipe is being used on the + * right side. + * Add check on current_state if the primary_pipe is the left side, + * to check the right side ( primary_pipe->next_odm_pipe ) to see if + * it is using a pipe for MPO ( primary_pipe->next_odm_pipe->bottom_pipe ) + * - If so, then don't use this pipe + * EXCEPTION - 3 plane ( 2 MPO plane ) case + * - in this case, the primary pipe has already gotten a free pipe for the + * MPO window in the left + * - when it tries to get a free pipe for the MPO window on the right, + * it will see that it is already assigned to the right side + * ( primary_pipe->next_odm_pipe ). But in this case, we want this + * free pipe, since it will be for the right side. So add an + * additional condition, that skipping the free pipe on the right only + * applies if the primary pipe has no bottom pipe currently assigned + */ + if (primary_pipe) { + primary_index = primary_pipe->pipe_idx; + old_primary_pipe = &primary_pipe->stream->ctx->dc->current_state->res_ctx.pipe_ctx[primary_index]; + if ((old_primary_pipe->next_odm_pipe) && (old_primary_pipe->next_odm_pipe->bottom_pipe) + && (!primary_pipe->bottom_pipe)) + next_odm_mpo_pipe = old_primary_pipe->next_odm_pipe->bottom_pipe; + + preferred_pipe_idx = (pool->pipe_count - 1) - primary_pipe->pipe_idx; + if ((res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) && + !(next_odm_mpo_pipe && next_odm_mpo_pipe->pipe_idx == preferred_pipe_idx)) { + secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx]; + secondary_pipe->pipe_idx = preferred_pipe_idx; + } + } + + /* + * search backwards for the second pipe to keep pipe + * assignment more consistent + */ + if (!secondary_pipe) + for (i = pool->pipe_count - 1; i >= 0; i--) { + if ((res_ctx->pipe_ctx[i].stream == NULL) && + !(next_odm_mpo_pipe && next_odm_mpo_pipe->pipe_idx == i)) { + secondary_pipe = &res_ctx->pipe_ctx[i]; + secondary_pipe->pipe_idx = i; + break; + } + } + + return secondary_pipe; +} + +static struct pipe_ctx *dcn32_acquire_idle_pipe_for_head_pipe_in_layer( + struct dc_state *state, + const struct resource_pool *pool, + struct dc_stream_state *stream, + const struct pipe_ctx *head_pipe) +{ + struct resource_context *res_ctx = &state->res_ctx; + struct pipe_ctx *idle_pipe, *pipe; + struct resource_context *old_ctx = &stream->ctx->dc->current_state->res_ctx; + int head_index; + + if (!head_pipe) + ASSERT(0); + + /* + * Modified from dcn20_acquire_idle_pipe_for_layer + * Check if head_pipe in old_context already has bottom_pipe allocated. + * - If so, check if that pipe is available in the current context. + * -- If so, reuse pipe from old_context + */ + head_index = head_pipe->pipe_idx; + pipe = &old_ctx->pipe_ctx[head_index]; + if (pipe->bottom_pipe && res_ctx->pipe_ctx[pipe->bottom_pipe->pipe_idx].stream == NULL) { + idle_pipe = &res_ctx->pipe_ctx[pipe->bottom_pipe->pipe_idx]; + idle_pipe->pipe_idx = pipe->bottom_pipe->pipe_idx; + } else { + idle_pipe = find_idle_secondary_pipe_check_mpo(res_ctx, pool, head_pipe); + if (!idle_pipe) + return NULL; + } + + idle_pipe->stream = head_pipe->stream; + idle_pipe->stream_res.tg = head_pipe->stream_res.tg; + idle_pipe->stream_res.opp = head_pipe->stream_res.opp; + + idle_pipe->plane_res.hubp = pool->hubps[idle_pipe->pipe_idx]; + idle_pipe->plane_res.ipp = pool->ipps[idle_pipe->pipe_idx]; + idle_pipe->plane_res.dpp = pool->dpps[idle_pipe->pipe_idx]; + idle_pipe->plane_res.mpcc_inst = pool->dpps[idle_pipe->pipe_idx]->inst; + + return idle_pipe; +} + +static int find_optimal_free_pipe_as_secondary_opp_head( + const struct resource_context *cur_res_ctx, + struct resource_context *new_res_ctx, + const struct resource_pool *pool, + const struct pipe_ctx *new_otg_master) +{ + const struct pipe_ctx *cur_otg_master; + int free_pipe_idx; + + cur_otg_master = &cur_res_ctx->pipe_ctx[new_otg_master->pipe_idx]; + free_pipe_idx = resource_find_free_pipe_used_as_sec_opp_head_by_cur_otg_master( + cur_res_ctx, new_res_ctx, cur_otg_master); + + /* Up until here if we have not found a free secondary pipe, we will + * need to wait for at least one frame to complete the transition + * sequence. + */ + if (free_pipe_idx == FREE_PIPE_INDEX_NOT_FOUND) + free_pipe_idx = recource_find_free_pipe_not_used_in_cur_res_ctx( + cur_res_ctx, new_res_ctx, pool); + + if (free_pipe_idx == FREE_PIPE_INDEX_NOT_FOUND) + free_pipe_idx = resource_find_any_free_pipe(new_res_ctx, pool); + + return free_pipe_idx; +} + +struct pipe_ctx *dcn32_acquire_free_pipe_as_secondary_dpp_pipe( + const struct dc_state *cur_ctx, + struct dc_state *new_ctx, + const struct resource_pool *pool, + const struct pipe_ctx *opp_head_pipe) +{ + + int free_pipe_idx; + struct pipe_ctx *free_pipe; + + if (!opp_head_pipe->stream->ctx->dc->config.enable_windowed_mpo_odm) + return dcn32_acquire_idle_pipe_for_head_pipe_in_layer( + new_ctx, pool, opp_head_pipe->stream, opp_head_pipe); + + free_pipe_idx = find_optimal_free_pipe_as_secondary_dpp_pipe( + &cur_ctx->res_ctx, &new_ctx->res_ctx, + pool, opp_head_pipe); + if (free_pipe_idx >= 0) { + free_pipe = &new_ctx->res_ctx.pipe_ctx[free_pipe_idx]; + free_pipe->pipe_idx = free_pipe_idx; + free_pipe->stream = opp_head_pipe->stream; + free_pipe->stream_res.tg = opp_head_pipe->stream_res.tg; + free_pipe->stream_res.opp = opp_head_pipe->stream_res.opp; + + free_pipe->plane_res.hubp = pool->hubps[free_pipe->pipe_idx]; + free_pipe->plane_res.ipp = pool->ipps[free_pipe->pipe_idx]; + free_pipe->plane_res.dpp = pool->dpps[free_pipe->pipe_idx]; + free_pipe->plane_res.mpcc_inst = + pool->dpps[free_pipe->pipe_idx]->inst; + } else { + ASSERT(opp_head_pipe); + free_pipe = NULL; + } + + return free_pipe; +} + +struct pipe_ctx *dcn32_acquire_free_pipe_as_secondary_opp_head( + const struct dc_state *cur_ctx, + struct dc_state *new_ctx, + const struct resource_pool *pool, + const struct pipe_ctx *otg_master) +{ + int free_pipe_idx = find_optimal_free_pipe_as_secondary_opp_head( + &cur_ctx->res_ctx, &new_ctx->res_ctx, + pool, otg_master); + struct pipe_ctx *free_pipe; + + if (free_pipe_idx >= 0) { + free_pipe = &new_ctx->res_ctx.pipe_ctx[free_pipe_idx]; + free_pipe->pipe_idx = free_pipe_idx; + free_pipe->stream = otg_master->stream; + free_pipe->stream_res.tg = otg_master->stream_res.tg; + free_pipe->stream_res.dsc = NULL; + free_pipe->stream_res.opp = pool->opps[free_pipe_idx]; + free_pipe->plane_res.mi = pool->mis[free_pipe_idx]; + free_pipe->plane_res.hubp = pool->hubps[free_pipe_idx]; + free_pipe->plane_res.ipp = pool->ipps[free_pipe_idx]; + free_pipe->plane_res.xfm = pool->transforms[free_pipe_idx]; + free_pipe->plane_res.dpp = pool->dpps[free_pipe_idx]; + free_pipe->plane_res.mpcc_inst = pool->dpps[free_pipe_idx]->inst; + if (free_pipe->stream->timing.flags.DSC == 1) { + dcn20_acquire_dsc(free_pipe->stream->ctx->dc, + &new_ctx->res_ctx, + &free_pipe->stream_res.dsc, + free_pipe_idx); + ASSERT(free_pipe->stream_res.dsc); + if (free_pipe->stream_res.dsc == NULL) { + memset(free_pipe, 0, sizeof(*free_pipe)); + free_pipe = NULL; + } + } + } else { + ASSERT(otg_master); + free_pipe = NULL; + } + + return free_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/resource/dcn32/dcn32_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.h new file mode 100644 index 00000000000000..0c87b0fabba7d9 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.h @@ -0,0 +1,1261 @@ +/* + * Copyright 2020 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 _DCN32_RESOURCE_H_ +#define _DCN32_RESOURCE_H_ + +#include "core_types.h" + +#define DCN3_2_DEFAULT_DET_SIZE 256 +#define DCN3_2_MAX_DET_SIZE 1152 +#define DCN3_2_MIN_DET_SIZE 128 +#define DCN3_2_MIN_COMPBUF_SIZE_KB 128 +#define DCN3_2_DET_SEG_SIZE 64 +#define DCN3_2_MALL_MBLK_SIZE_BYTES 65536 // 64 * 1024 +#define DCN3_2_MBLK_WIDTH 128 +#define DCN3_2_MBLK_HEIGHT_4BPE 128 +#define DCN3_2_MBLK_HEIGHT_8BPE 64 +#define DCN3_2_DCFCLK_DS_INIT_KHZ 10000 // Choose 10Mhz for init DCFCLK DS freq +#define SUBVP_HIGH_REFRESH_LIST_LEN 4 +#define SUBVP_ACTIVE_MARGIN_LIST_LEN 2 +#define DCN3_2_MAX_SUBVP_PIXEL_RATE_MHZ 1800 +#define DCN3_2_VMIN_DISPCLK_HZ 717000000 + +#define TO_DCN32_RES_POOL(pool)\ + container_of(pool, struct dcn32_resource_pool, base) + +extern struct _vcs_dpi_ip_params_st dcn3_2_ip; +extern struct _vcs_dpi_soc_bounding_box_st dcn3_2_soc; + +struct subvp_high_refresh_list { + int min_refresh; + int max_refresh; + struct resolution { + int width; + int height; + } res[SUBVP_HIGH_REFRESH_LIST_LEN]; +}; + +struct subvp_active_margin_list { + int min_refresh; + int max_refresh; + struct { + int width; + int height; + } res[SUBVP_ACTIVE_MARGIN_LIST_LEN]; +}; + +struct dcn32_resource_pool { + struct resource_pool base; +}; + +struct resource_pool *dcn32_create_resource_pool( + const struct dc_init_data *init_data, + struct dc *dc); + +struct panel_cntl *dcn32_panel_cntl_create( + const struct panel_cntl_init_data *init_data); + +bool dcn32_acquire_post_bldn_3dlut( + struct resource_context *res_ctx, + const struct resource_pool *pool, + int mpcc_id, + struct dc_3dlut **lut, + struct dc_transfer_func **shaper); + +bool dcn32_release_post_bldn_3dlut( + struct resource_context *res_ctx, + const struct resource_pool *pool, + struct dc_3dlut **lut, + struct dc_transfer_func **shaper); + +void dcn32_add_phantom_pipes(struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes, + unsigned int pipe_cnt, + unsigned int index); + +bool dcn32_validate_bandwidth(struct dc *dc, + struct dc_state *context, + bool fast_validate); + +int dcn32_populate_dml_pipes_from_context( + struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes, + bool fast_validate); + +void dcn32_calculate_wm_and_dlg( + struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes, + int pipe_cnt, + int vlevel); + +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, + struct dc_state *context); + +bool dcn32_all_pipes_have_stream_and_plane(struct dc *dc, + struct dc_state *context); + +bool dcn32_subvp_in_use(struct dc *dc, + struct dc_state *context); + +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_free_pipe_as_secondary_dpp_pipe( + const struct dc_state *cur_ctx, + struct dc_state *new_ctx, + const struct resource_pool *pool, + const struct pipe_ctx *opp_head_pipe); + +struct pipe_ctx *dcn32_acquire_free_pipe_as_secondary_opp_head( + const struct dc_state *cur_ctx, + struct dc_state *new_ctx, + const struct resource_pool *pool, + const struct pipe_ctx *otg_master); + +void dcn32_release_pipe(struct dc_state *context, + struct pipe_ctx *pipe, + const struct resource_pool *pool); + +void dcn32_determine_det_override(struct dc *dc, + struct dc_state *context, + display_e2e_pipe_params_st *pipes); + +void dcn32_set_det_allocations(struct dc *dc, struct dc_state *context, + display_e2e_pipe_params_st *pipes); + +struct dc_stream_state *dcn32_can_support_mclk_switch_using_fw_based_vblank_stretch(struct dc *dc, struct dc_state *context); + +bool dcn32_allow_subvp_with_active_margin(struct pipe_ctx *pipe); + +bool dcn32_allow_subvp_high_refresh_rate(struct dc *dc, struct dc_state *context, 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); + +bool dcn32_check_native_scaling_for_res(struct pipe_ctx *pipe, unsigned int width, unsigned int height); + +bool dcn32_subvp_drr_admissable(struct dc *dc, struct dc_state *context); + +bool dcn32_subvp_vblank_admissable(struct dc *dc, struct dc_state *context, int vlevel); + +void dcn32_update_dml_pipes_odm_policy_based_on_context(struct dc *dc, struct dc_state *context, display_e2e_pipe_params_st *pipes); + +/* definitions for run time init of reg offsets */ + +/* CLK SRC */ +#define CS_COMMON_REG_LIST_DCN3_0_RI(index, pllid) \ + SRI_ARR_ALPHABET(PIXCLK_RESYNC_CNTL, PHYPLL, index, pllid), \ + SRII_ARR_2(PHASE, DP_DTO, 0, index), \ + SRII_ARR_2(PHASE, DP_DTO, 1, index), \ + SRII_ARR_2(PHASE, DP_DTO, 2, index), \ + SRII_ARR_2(PHASE, DP_DTO, 3, index), \ + SRII_ARR_2(MODULO, DP_DTO, 0, index), \ + SRII_ARR_2(MODULO, DP_DTO, 1, index), \ + SRII_ARR_2(MODULO, DP_DTO, 2, index), \ + SRII_ARR_2(MODULO, DP_DTO, 3, index), \ + SRII_ARR_2(PIXEL_RATE_CNTL, OTG, 0, index), \ + SRII_ARR_2(PIXEL_RATE_CNTL, OTG, 1, index), \ + SRII_ARR_2(PIXEL_RATE_CNTL, OTG, 2, index), \ + SRII_ARR_2(PIXEL_RATE_CNTL, OTG, 3, index) + +/* ABM */ +#define ABM_DCN32_REG_LIST_RI(id) \ + SRI_ARR(DC_ABM1_HG_SAMPLE_RATE, ABM, id), \ + SRI_ARR(DC_ABM1_LS_SAMPLE_RATE, ABM, id), \ + SRI_ARR(BL1_PWM_BL_UPDATE_SAMPLE_RATE, ABM, id), \ + SRI_ARR(DC_ABM1_HG_MISC_CTRL, ABM, id), \ + SRI_ARR(DC_ABM1_IPCSC_COEFF_SEL, ABM, id), \ + SRI_ARR(BL1_PWM_CURRENT_ABM_LEVEL, ABM, id), \ + SRI_ARR(BL1_PWM_TARGET_ABM_LEVEL, ABM, id), \ + SRI_ARR(BL1_PWM_USER_LEVEL, ABM, id), \ + SRI_ARR(DC_ABM1_LS_MIN_MAX_PIXEL_VALUE_THRES, ABM, id), \ + SRI_ARR(DC_ABM1_HGLS_REG_READ_PROGRESS, ABM, id), \ + SRI_ARR(DC_ABM1_ACE_OFFSET_SLOPE_0, ABM, id), \ + SRI_ARR(DC_ABM1_ACE_THRES_12, ABM, id), NBIO_SR_ARR(BIOS_SCRATCH_2, id) + +/* Audio */ +#define AUD_COMMON_REG_LIST_RI(id) \ + SRI_ARR(AZALIA_F0_CODEC_ENDPOINT_INDEX, AZF0ENDPOINT, id), \ + SRI_ARR(AZALIA_F0_CODEC_ENDPOINT_DATA, AZF0ENDPOINT, id), \ + SR_ARR(AZALIA_F0_CODEC_FUNCTION_PARAMETER_STREAM_FORMATS, id), \ + SR_ARR(AZALIA_F0_CODEC_FUNCTION_PARAMETER_SUPPORTED_SIZE_RATES, id), \ + SR_ARR(AZALIA_F0_CODEC_FUNCTION_PARAMETER_POWER_STATES, id), \ + SR_ARR(DCCG_AUDIO_DTO_SOURCE, id), SR_ARR(DCCG_AUDIO_DTO0_MODULE, id), \ + SR_ARR(DCCG_AUDIO_DTO0_PHASE, id), SR_ARR(DCCG_AUDIO_DTO1_MODULE, id), \ + SR_ARR(DCCG_AUDIO_DTO1_PHASE, id) \ + +/* VPG */ + +#define VPG_DCN3_REG_LIST_RI(id) \ + SRI_ARR(VPG_GENERIC_STATUS, VPG, id), \ + SRI_ARR(VPG_GENERIC_PACKET_ACCESS_CTRL, VPG, id), \ + SRI_ARR(VPG_GENERIC_PACKET_DATA, VPG, id), \ + SRI_ARR(VPG_GSP_FRAME_UPDATE_CTRL, VPG, id), \ + SRI_ARR(VPG_GSP_IMMEDIATE_UPDATE_CTRL, VPG, id) + +/* AFMT */ +#define AFMT_DCN3_REG_LIST_RI(id) \ + SRI_ARR(AFMT_INFOFRAME_CONTROL0, AFMT, id), \ + SRI_ARR(AFMT_VBI_PACKET_CONTROL, AFMT, id), \ + SRI_ARR(AFMT_AUDIO_PACKET_CONTROL, AFMT, id), \ + SRI_ARR(AFMT_AUDIO_PACKET_CONTROL2, AFMT, id), \ + SRI_ARR(AFMT_AUDIO_SRC_CONTROL, AFMT, id), \ + SRI_ARR(AFMT_60958_0, AFMT, id), SRI_ARR(AFMT_60958_1, AFMT, id), \ + SRI_ARR(AFMT_60958_2, AFMT, id), SRI_ARR(AFMT_MEM_PWR, AFMT, id) + +/* APG */ +#define APG_DCN31_REG_LIST_RI(id) \ + SRI_ARR(APG_CONTROL, APG, id), SRI_ARR(APG_CONTROL2, APG, id), \ + SRI_ARR(APG_MEM_PWR, APG, id), SRI_ARR(APG_DBG_GEN_CONTROL, APG, id) + +/* Stream encoder */ +#define SE_DCN32_REG_LIST_RI(id) \ + SRI_ARR(AFMT_CNTL, DIG, id), SRI_ARR(DIG_FE_CNTL, DIG, id), \ + SRI_ARR(HDMI_CONTROL, DIG, id), SRI_ARR(HDMI_DB_CONTROL, DIG, id), \ + SRI_ARR(HDMI_GC, DIG, id), \ + SRI_ARR(HDMI_GENERIC_PACKET_CONTROL0, DIG, id), \ + SRI_ARR(HDMI_GENERIC_PACKET_CONTROL1, DIG, id), \ + SRI_ARR(HDMI_GENERIC_PACKET_CONTROL2, DIG, id), \ + SRI_ARR(HDMI_GENERIC_PACKET_CONTROL3, DIG, id), \ + SRI_ARR(HDMI_GENERIC_PACKET_CONTROL4, DIG, id), \ + SRI_ARR(HDMI_GENERIC_PACKET_CONTROL5, DIG, id), \ + SRI_ARR(HDMI_GENERIC_PACKET_CONTROL6, DIG, id), \ + SRI_ARR(HDMI_GENERIC_PACKET_CONTROL7, DIG, id), \ + SRI_ARR(HDMI_GENERIC_PACKET_CONTROL8, DIG, id), \ + SRI_ARR(HDMI_GENERIC_PACKET_CONTROL9, DIG, id), \ + SRI_ARR(HDMI_GENERIC_PACKET_CONTROL10, DIG, id), \ + SRI_ARR(HDMI_INFOFRAME_CONTROL0, DIG, id), \ + SRI_ARR(HDMI_INFOFRAME_CONTROL1, DIG, id), \ + SRI_ARR(HDMI_VBI_PACKET_CONTROL, DIG, id), \ + SRI_ARR(HDMI_AUDIO_PACKET_CONTROL, DIG, id), \ + SRI_ARR(HDMI_ACR_PACKET_CONTROL, DIG, id), \ + SRI_ARR(HDMI_ACR_32_0, DIG, id), SRI_ARR(HDMI_ACR_32_1, DIG, id), \ + SRI_ARR(HDMI_ACR_44_0, DIG, id), SRI_ARR(HDMI_ACR_44_1, DIG, id), \ + SRI_ARR(HDMI_ACR_48_0, DIG, id), SRI_ARR(HDMI_ACR_48_1, DIG, id), \ + SRI_ARR(DP_DB_CNTL, DP, id), SRI_ARR(DP_MSA_MISC, DP, id), \ + SRI_ARR(DP_MSA_VBID_MISC, DP, id), SRI_ARR(DP_MSA_COLORIMETRY, DP, id), \ + SRI_ARR(DP_MSA_TIMING_PARAM1, DP, id), \ + SRI_ARR(DP_MSA_TIMING_PARAM2, DP, id), \ + SRI_ARR(DP_MSA_TIMING_PARAM3, DP, id), \ + SRI_ARR(DP_MSA_TIMING_PARAM4, DP, id), \ + SRI_ARR(DP_MSE_RATE_CNTL, DP, id), SRI_ARR(DP_MSE_RATE_UPDATE, DP, id), \ + SRI_ARR(DP_PIXEL_FORMAT, DP, id), SRI_ARR(DP_SEC_CNTL, DP, id), \ + SRI_ARR(DP_SEC_CNTL1, DP, id), SRI_ARR(DP_SEC_CNTL2, DP, id), \ + SRI_ARR(DP_SEC_CNTL5, DP, id), SRI_ARR(DP_SEC_CNTL6, DP, id), \ + SRI_ARR(DP_STEER_FIFO, DP, id), SRI_ARR(DP_VID_M, DP, id), \ + SRI_ARR(DP_VID_N, DP, id), SRI_ARR(DP_VID_STREAM_CNTL, DP, id), \ + SRI_ARR(DP_VID_TIMING, DP, id), SRI_ARR(DP_SEC_AUD_N, DP, id), \ + SRI_ARR(DP_SEC_TIMESTAMP, DP, id), SRI_ARR(DP_DSC_CNTL, DP, id), \ + SRI_ARR(DP_SEC_METADATA_TRANSMISSION, DP, id), \ + SRI_ARR(HDMI_METADATA_PACKET_CONTROL, DIG, id), \ + SRI_ARR(DP_SEC_FRAMING4, DP, id), SRI_ARR(DP_GSP11_CNTL, DP, id), \ + SRI_ARR(DME_CONTROL, DME, id), \ + SRI_ARR(DP_SEC_METADATA_TRANSMISSION, DP, id), \ + SRI_ARR(HDMI_METADATA_PACKET_CONTROL, DIG, id), \ + SRI_ARR(DIG_FE_CNTL, DIG, id), SRI_ARR(DIG_CLOCK_PATTERN, DIG, id), \ + SRI_ARR(DIG_FIFO_CTRL0, DIG, id) + +/* Aux regs */ + +#define AUX_REG_LIST_RI(id) \ + SRI_ARR(AUX_CONTROL, DP_AUX, id), SRI_ARR(AUX_DPHY_RX_CONTROL0, DP_AUX, id), \ + SRI_ARR(AUX_DPHY_RX_CONTROL1, DP_AUX, id) + +#define DCN2_AUX_REG_LIST_RI(id) \ + AUX_REG_LIST_RI(id), SRI_ARR(AUX_DPHY_TX_CONTROL, DP_AUX, id) + +/* HDP */ +#define HPD_REG_LIST_RI(id) SRI_ARR(DC_HPD_CONTROL, HPD, id) + +/* Link encoder */ +#define LE_DCN3_REG_LIST_RI(id) \ + SRI_ARR(DIG_BE_CNTL, DIG, id), SRI_ARR(DIG_BE_EN_CNTL, DIG, id), \ + SRI_ARR(TMDS_CTL_BITS, DIG, id), \ + SRI_ARR(TMDS_DCBALANCER_CONTROL, DIG, id), SRI_ARR(DP_CONFIG, DP, id), \ + SRI_ARR(DP_DPHY_CNTL, DP, id), SRI_ARR(DP_DPHY_PRBS_CNTL, DP, id), \ + SRI_ARR(DP_DPHY_SCRAM_CNTL, DP, id), SRI_ARR(DP_DPHY_SYM0, DP, id), \ + SRI_ARR(DP_DPHY_SYM1, DP, id), SRI_ARR(DP_DPHY_SYM2, DP, id), \ + SRI_ARR(DP_DPHY_TRAINING_PATTERN_SEL, DP, id), \ + SRI_ARR(DP_LINK_CNTL, DP, id), SRI_ARR(DP_LINK_FRAMING_CNTL, DP, id), \ + SRI_ARR(DP_MSE_SAT0, DP, id), SRI_ARR(DP_MSE_SAT1, DP, id), \ + SRI_ARR(DP_MSE_SAT2, DP, id), SRI_ARR(DP_MSE_SAT_UPDATE, DP, id), \ + SRI_ARR(DP_SEC_CNTL, DP, id), SRI_ARR(DP_VID_STREAM_CNTL, DP, id), \ + SRI_ARR(DP_DPHY_FAST_TRAINING, DP, id), SRI_ARR(DP_SEC_CNTL1, DP, id), \ + SRI_ARR(DP_DPHY_BS_SR_SWAP_CNTL, DP, id), \ + SRI_ARR(DP_DPHY_HBR2_PATTERN_CONTROL, DP, id) + +#define LE_DCN31_REG_LIST_RI(id) \ + LE_DCN3_REG_LIST_RI(id), SRI_ARR(DP_DPHY_INTERNAL_CTRL, DP, id), \ + SR_ARR(DIO_LINKA_CNTL, id), SR_ARR(DIO_LINKB_CNTL, id), \ + SR_ARR(DIO_LINKC_CNTL, id), SR_ARR(DIO_LINKD_CNTL, id), \ + SR_ARR(DIO_LINKE_CNTL, id), SR_ARR(DIO_LINKF_CNTL, id) + +#define UNIPHY_DCN2_REG_LIST_RI(id, phyid) \ + SRI_ARR_ALPHABET(CLOCK_ENABLE, SYMCLK, id, phyid), \ + SRI_ARR_ALPHABET(CHANNEL_XBAR_CNTL, UNIPHY, id, phyid) + +/* HPO DP stream encoder */ +#define DCN3_1_HPO_DP_STREAM_ENC_REG_LIST_RI(id) \ + SR_ARR(DP_STREAM_MAPPER_CONTROL0, id), \ + SR_ARR(DP_STREAM_MAPPER_CONTROL1, id), \ + SR_ARR(DP_STREAM_MAPPER_CONTROL2, id), \ + SR_ARR(DP_STREAM_MAPPER_CONTROL3, id), \ + SRI_ARR(DP_STREAM_ENC_CLOCK_CONTROL, DP_STREAM_ENC, id), \ + SRI_ARR(DP_STREAM_ENC_INPUT_MUX_CONTROL, DP_STREAM_ENC, id), \ + SRI_ARR(DP_STREAM_ENC_AUDIO_CONTROL, DP_STREAM_ENC, id), \ + SRI_ARR(DP_STREAM_ENC_CLOCK_RAMP_ADJUSTER_FIFO_STATUS_CONTROL0, DP_STREAM_ENC, id), \ + SRI_ARR(DP_SYM32_ENC_CONTROL, DP_SYM32_ENC, id), \ + SRI_ARR(DP_SYM32_ENC_VID_PIXEL_FORMAT, DP_SYM32_ENC, id), \ + SRI_ARR(DP_SYM32_ENC_VID_PIXEL_FORMAT_DOUBLE_BUFFER_CONTROL, DP_SYM32_ENC, id), \ + SRI_ARR(DP_SYM32_ENC_VID_MSA0, DP_SYM32_ENC, id), \ + SRI_ARR(DP_SYM32_ENC_VID_MSA1, DP_SYM32_ENC, id), \ + SRI_ARR(DP_SYM32_ENC_VID_MSA2, DP_SYM32_ENC, id), \ + SRI_ARR(DP_SYM32_ENC_VID_MSA3, DP_SYM32_ENC, id), \ + SRI_ARR(DP_SYM32_ENC_VID_MSA4, DP_SYM32_ENC, id), \ + SRI_ARR(DP_SYM32_ENC_VID_MSA5, DP_SYM32_ENC, id), \ + SRI_ARR(DP_SYM32_ENC_VID_MSA6, DP_SYM32_ENC, id), \ + SRI_ARR(DP_SYM32_ENC_VID_MSA7, DP_SYM32_ENC, id), \ + SRI_ARR(DP_SYM32_ENC_VID_MSA8, DP_SYM32_ENC, id), \ + SRI_ARR(DP_SYM32_ENC_VID_MSA_CONTROL, DP_SYM32_ENC, id), \ + SRI_ARR(DP_SYM32_ENC_VID_MSA_DOUBLE_BUFFER_CONTROL, DP_SYM32_ENC, id), \ + SRI_ARR(DP_SYM32_ENC_VID_FIFO_CONTROL, DP_SYM32_ENC, id), \ + SRI_ARR(DP_SYM32_ENC_VID_STREAM_CONTROL, DP_SYM32_ENC, id), \ + SRI_ARR(DP_SYM32_ENC_VID_VBID_CONTROL, DP_SYM32_ENC, id), \ + SRI_ARR(DP_SYM32_ENC_SDP_CONTROL, DP_SYM32_ENC, id), \ + SRI_ARR(DP_SYM32_ENC_SDP_GSP_CONTROL0, DP_SYM32_ENC, id), \ + SRI_ARR(DP_SYM32_ENC_SDP_GSP_CONTROL2, DP_SYM32_ENC, id), \ + SRI_ARR(DP_SYM32_ENC_SDP_GSP_CONTROL3, DP_SYM32_ENC, id), \ + SRI_ARR(DP_SYM32_ENC_SDP_GSP_CONTROL5, DP_SYM32_ENC, id), \ + SRI_ARR(DP_SYM32_ENC_SDP_GSP_CONTROL11, DP_SYM32_ENC, id), \ + SRI_ARR(DP_SYM32_ENC_SDP_METADATA_PACKET_CONTROL, DP_SYM32_ENC, id), \ + SRI_ARR(DP_SYM32_ENC_SDP_AUDIO_CONTROL0, DP_SYM32_ENC, id), \ + SRI_ARR(DP_SYM32_ENC_VID_CRC_CONTROL, DP_SYM32_ENC, id), \ + SRI_ARR(DP_SYM32_ENC_HBLANK_CONTROL, DP_SYM32_ENC, id) + +/* HPO DP link encoder regs */ +#define DCN3_1_HPO_DP_LINK_ENC_REG_LIST_RI(id) \ + SRI_ARR(DP_LINK_ENC_CLOCK_CONTROL, DP_LINK_ENC, id), \ + SRI_ARR(DP_DPHY_SYM32_CONTROL, DP_DPHY_SYM32, id), \ + SRI_ARR(DP_DPHY_SYM32_STATUS, DP_DPHY_SYM32, id), \ + SRI_ARR(DP_DPHY_SYM32_TP_CONFIG, DP_DPHY_SYM32, id), \ + SRI_ARR(DP_DPHY_SYM32_TP_PRBS_SEED0, DP_DPHY_SYM32, id), \ + SRI_ARR(DP_DPHY_SYM32_TP_PRBS_SEED1, DP_DPHY_SYM32, id), \ + SRI_ARR(DP_DPHY_SYM32_TP_PRBS_SEED2, DP_DPHY_SYM32, id), \ + SRI_ARR(DP_DPHY_SYM32_TP_PRBS_SEED3, DP_DPHY_SYM32, id), \ + SRI_ARR(DP_DPHY_SYM32_TP_SQ_PULSE, DP_DPHY_SYM32, id), \ + SRI_ARR(DP_DPHY_SYM32_TP_CUSTOM0, DP_DPHY_SYM32, id), \ + SRI_ARR(DP_DPHY_SYM32_TP_CUSTOM1, DP_DPHY_SYM32, id), \ + SRI_ARR(DP_DPHY_SYM32_TP_CUSTOM2, DP_DPHY_SYM32, id), \ + SRI_ARR(DP_DPHY_SYM32_TP_CUSTOM3, DP_DPHY_SYM32, id), \ + SRI_ARR(DP_DPHY_SYM32_TP_CUSTOM4, DP_DPHY_SYM32, id), \ + SRI_ARR(DP_DPHY_SYM32_TP_CUSTOM5, DP_DPHY_SYM32, id), \ + SRI_ARR(DP_DPHY_SYM32_TP_CUSTOM6, DP_DPHY_SYM32, id), \ + SRI_ARR(DP_DPHY_SYM32_TP_CUSTOM7, DP_DPHY_SYM32, id), \ + SRI_ARR(DP_DPHY_SYM32_TP_CUSTOM8, DP_DPHY_SYM32, id), \ + SRI_ARR(DP_DPHY_SYM32_TP_CUSTOM9, DP_DPHY_SYM32, id), \ + SRI_ARR(DP_DPHY_SYM32_TP_CUSTOM10, DP_DPHY_SYM32, id), \ + SRI_ARR(DP_DPHY_SYM32_SAT_VC0, DP_DPHY_SYM32, id), \ + SRI_ARR(DP_DPHY_SYM32_SAT_VC1, DP_DPHY_SYM32, id), \ + SRI_ARR(DP_DPHY_SYM32_SAT_VC2, DP_DPHY_SYM32, id), \ + SRI_ARR(DP_DPHY_SYM32_SAT_VC3, DP_DPHY_SYM32, id), \ + SRI_ARR(DP_DPHY_SYM32_VC_RATE_CNTL0, DP_DPHY_SYM32, id), \ + SRI_ARR(DP_DPHY_SYM32_VC_RATE_CNTL1, DP_DPHY_SYM32, id), \ + SRI_ARR(DP_DPHY_SYM32_VC_RATE_CNTL2, DP_DPHY_SYM32, id), \ + SRI_ARR(DP_DPHY_SYM32_VC_RATE_CNTL3, DP_DPHY_SYM32, id), \ + SRI_ARR(DP_DPHY_SYM32_SAT_UPDATE, DP_DPHY_SYM32, id) + +/* DPP */ +#define DPP_REG_LIST_DCN30_COMMON_RI(id) \ + SRI_ARR(CM_DEALPHA, CM, id), SRI_ARR(CM_MEM_PWR_STATUS, CM, id), \ + SRI_ARR(CM_BIAS_CR_R, CM, id), SRI_ARR(CM_BIAS_Y_G_CB_B, CM, id), \ + SRI_ARR(PRE_DEGAM, CNVC_CFG, id), SRI_ARR(CM_GAMCOR_CONTROL, CM, id), \ + SRI_ARR(CM_GAMCOR_LUT_CONTROL, CM, id), \ + SRI_ARR(CM_GAMCOR_LUT_INDEX, CM, id), \ + SRI_ARR(CM_GAMCOR_LUT_INDEX, CM, id), \ + SRI_ARR(CM_GAMCOR_LUT_DATA, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMB_START_CNTL_B, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMB_START_CNTL_G, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMB_START_CNTL_R, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMB_START_SLOPE_CNTL_B, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMB_START_SLOPE_CNTL_G, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMB_START_SLOPE_CNTL_R, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMB_END_CNTL1_B, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMB_END_CNTL2_B, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMB_END_CNTL1_G, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMB_END_CNTL2_G, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMB_END_CNTL1_R, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMB_END_CNTL2_R, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMB_REGION_0_1, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMB_REGION_32_33, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMB_OFFSET_B, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMB_OFFSET_G, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMB_OFFSET_R, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMB_START_BASE_CNTL_B, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMB_START_BASE_CNTL_G, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMB_START_BASE_CNTL_R, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMA_START_CNTL_B, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMA_START_CNTL_G, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMA_START_CNTL_R, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMA_START_SLOPE_CNTL_B, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMA_START_SLOPE_CNTL_G, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMA_START_SLOPE_CNTL_R, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMA_END_CNTL1_B, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMA_END_CNTL2_B, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMA_END_CNTL1_G, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMA_END_CNTL2_G, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMA_END_CNTL1_R, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMA_END_CNTL2_R, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMA_REGION_0_1, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMA_REGION_32_33, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMA_OFFSET_B, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMA_OFFSET_G, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMA_OFFSET_R, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMA_START_BASE_CNTL_B, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMA_START_BASE_CNTL_G, CM, id), \ + SRI_ARR(CM_GAMCOR_RAMA_START_BASE_CNTL_R, CM, id), \ + SRI_ARR(CM_GAMUT_REMAP_CONTROL, CM, id), \ + SRI_ARR(CM_GAMUT_REMAP_C11_C12, CM, id), \ + SRI_ARR(CM_GAMUT_REMAP_C13_C14, CM, id), \ + SRI_ARR(CM_GAMUT_REMAP_C21_C22, CM, id), \ + SRI_ARR(CM_GAMUT_REMAP_C23_C24, CM, id), \ + SRI_ARR(CM_GAMUT_REMAP_C31_C32, CM, id), \ + SRI_ARR(CM_GAMUT_REMAP_C33_C34, CM, id), \ + SRI_ARR(CM_GAMUT_REMAP_B_C11_C12, CM, id), \ + SRI_ARR(CM_GAMUT_REMAP_B_C13_C14, CM, id), \ + SRI_ARR(CM_GAMUT_REMAP_B_C21_C22, CM, id), \ + SRI_ARR(CM_GAMUT_REMAP_B_C23_C24, CM, id), \ + SRI_ARR(CM_GAMUT_REMAP_B_C31_C32, CM, id), \ + SRI_ARR(CM_GAMUT_REMAP_B_C33_C34, CM, id), \ + SRI_ARR(DSCL_EXT_OVERSCAN_LEFT_RIGHT, DSCL, id), \ + SRI_ARR(DSCL_EXT_OVERSCAN_TOP_BOTTOM, DSCL, id), \ + SRI_ARR(OTG_H_BLANK, DSCL, id), SRI_ARR(OTG_V_BLANK, DSCL, id), \ + SRI_ARR(SCL_MODE, DSCL, id), SRI_ARR(LB_DATA_FORMAT, DSCL, id), \ + SRI_ARR(LB_MEMORY_CTRL, DSCL, id), SRI_ARR(DSCL_AUTOCAL, DSCL, id), \ + SRI_ARR(DSCL_CONTROL, DSCL, id), \ + SRI_ARR(SCL_TAP_CONTROL, DSCL, id), \ + SRI_ARR(SCL_COEF_RAM_TAP_SELECT, DSCL, id), \ + SRI_ARR(SCL_COEF_RAM_TAP_DATA, DSCL, id), \ + SRI_ARR(DSCL_2TAP_CONTROL, DSCL, id), SRI_ARR(MPC_SIZE, DSCL, id), \ + SRI_ARR(SCL_HORZ_FILTER_SCALE_RATIO, DSCL, id), \ + SRI_ARR(SCL_VERT_FILTER_SCALE_RATIO, DSCL, id), \ + SRI_ARR(SCL_HORZ_FILTER_SCALE_RATIO_C, DSCL, id), \ + SRI_ARR(SCL_VERT_FILTER_SCALE_RATIO_C, DSCL, id), \ + SRI_ARR(SCL_HORZ_FILTER_INIT, DSCL, id), \ + SRI_ARR(SCL_HORZ_FILTER_INIT_C, DSCL, id), \ + SRI_ARR(SCL_VERT_FILTER_INIT, DSCL, id), \ + SRI_ARR(SCL_VERT_FILTER_INIT_C, DSCL, id), \ + SRI_ARR(RECOUT_START, DSCL, id), SRI_ARR(RECOUT_SIZE, DSCL, id), \ + SRI_ARR(PRE_DEALPHA, CNVC_CFG, id), SRI_ARR(PRE_REALPHA, CNVC_CFG, id), \ + SRI_ARR(PRE_CSC_MODE, CNVC_CFG, id), \ + SRI_ARR(PRE_CSC_C11_C12, CNVC_CFG, id), \ + SRI_ARR(PRE_CSC_C33_C34, CNVC_CFG, id), \ + SRI_ARR(PRE_CSC_B_C11_C12, CNVC_CFG, id), \ + SRI_ARR(PRE_CSC_B_C33_C34, CNVC_CFG, id), \ + SRI_ARR(CM_POST_CSC_CONTROL, CM, id), \ + SRI_ARR(CM_POST_CSC_C11_C12, CM, id), \ + SRI_ARR(CM_POST_CSC_C33_C34, CM, id), \ + SRI_ARR(CM_POST_CSC_B_C11_C12, CM, id), \ + SRI_ARR(CM_POST_CSC_B_C33_C34, CM, id), \ + SRI_ARR(CM_MEM_PWR_CTRL, CM, id), SRI_ARR(CM_CONTROL, CM, id), \ + SRI_ARR(FORMAT_CONTROL, CNVC_CFG, id), \ + SRI_ARR(CNVC_SURFACE_PIXEL_FORMAT, CNVC_CFG, id), \ + SRI_ARR(CURSOR0_CONTROL, CNVC_CUR, id), \ + SRI_ARR(CURSOR0_COLOR0, CNVC_CUR, id), \ + SRI_ARR(CURSOR0_COLOR1, CNVC_CUR, id), \ + SRI_ARR(CURSOR0_FP_SCALE_BIAS, CNVC_CUR, id), \ + SRI_ARR(DPP_CONTROL, DPP_TOP, id), SRI_ARR(CM_HDR_MULT_COEF, CM, id), \ + SRI_ARR(CURSOR_CONTROL, CURSOR0_, id), \ + SRI_ARR(ALPHA_2BIT_LUT, CNVC_CFG, id), \ + SRI_ARR(FCNV_FP_BIAS_R, CNVC_CFG, id), \ + SRI_ARR(FCNV_FP_BIAS_G, CNVC_CFG, id), \ + SRI_ARR(FCNV_FP_BIAS_B, CNVC_CFG, id), \ + SRI_ARR(FCNV_FP_SCALE_R, CNVC_CFG, id), \ + SRI_ARR(FCNV_FP_SCALE_G, CNVC_CFG, id), \ + SRI_ARR(FCNV_FP_SCALE_B, CNVC_CFG, id), \ + SRI_ARR(COLOR_KEYER_CONTROL, CNVC_CFG, id), \ + SRI_ARR(COLOR_KEYER_ALPHA, CNVC_CFG, id), \ + SRI_ARR(COLOR_KEYER_RED, CNVC_CFG, id), \ + SRI_ARR(COLOR_KEYER_GREEN, CNVC_CFG, id), \ + SRI_ARR(COLOR_KEYER_BLUE, CNVC_CFG, id), \ + SRI_ARR(CURSOR_CONTROL, CURSOR0_, id), \ + SRI_ARR(OBUF_MEM_PWR_CTRL, DSCL, id), \ + SRI_ARR(DSCL_MEM_PWR_STATUS, DSCL, id), \ + SRI_ARR(DSCL_MEM_PWR_CTRL, DSCL, id) + +/* OPP */ +#define OPP_REG_LIST_DCN_RI(id) \ + SRI_ARR(FMT_BIT_DEPTH_CONTROL, FMT, id), SRI_ARR(FMT_CONTROL, FMT, id), \ + SRI_ARR(FMT_DITHER_RAND_R_SEED, FMT, id), \ + SRI_ARR(FMT_DITHER_RAND_G_SEED, FMT, id), \ + SRI_ARR(FMT_DITHER_RAND_B_SEED, FMT, id), \ + SRI_ARR(FMT_CLAMP_CNTL, FMT, id), \ + SRI_ARR(FMT_DYNAMIC_EXP_CNTL, FMT, id), \ + SRI_ARR(FMT_MAP420_MEMORY_CONTROL, FMT, id), \ + SRI_ARR(OPPBUF_CONTROL, OPPBUF, id), \ + SRI_ARR(OPPBUF_3D_PARAMETERS_0, OPPBUF, id), \ + SRI_ARR(OPPBUF_3D_PARAMETERS_1, OPPBUF, id), \ + SRI_ARR(OPP_PIPE_CONTROL, OPP_PIPE, id) \ + +#define OPP_REG_LIST_DCN10_RI(id) OPP_REG_LIST_DCN_RI(id) + +#define OPP_DPG_REG_LIST_RI(id) \ + SRI_ARR(DPG_CONTROL, DPG, id), SRI_ARR(DPG_DIMENSIONS, DPG, id), \ + SRI_ARR(DPG_OFFSET_SEGMENT, DPG, id), SRI_ARR(DPG_COLOUR_B_CB, DPG, id), \ + SRI_ARR(DPG_COLOUR_G_Y, DPG, id), SRI_ARR(DPG_COLOUR_R_CR, DPG, id), \ + SRI_ARR(DPG_RAMP_CONTROL, DPG, id), SRI_ARR(DPG_STATUS, DPG, id) + +#define OPP_REG_LIST_DCN30_RI(id) \ + OPP_REG_LIST_DCN10_RI(id), OPP_DPG_REG_LIST_RI(id), \ + SRI_ARR(FMT_422_CONTROL, FMT, id) + +/* Aux engine regs */ +#define AUX_COMMON_REG_LIST0_RI(id) \ + SRI_ARR(AUX_CONTROL, DP_AUX, id), SRI_ARR(AUX_ARB_CONTROL, DP_AUX, id), \ + SRI_ARR(AUX_SW_DATA, DP_AUX, id), SRI_ARR(AUX_SW_CONTROL, DP_AUX, id), \ + SRI_ARR(AUX_INTERRUPT_CONTROL, DP_AUX, id), \ + SRI_ARR(AUX_DPHY_RX_CONTROL1, DP_AUX, id), \ + SRI_ARR(AUX_SW_STATUS, DP_AUX, id) + +/* DWBC */ +#define DWBC_COMMON_REG_LIST_DCN30_RI(id) \ + SR_ARR(DWB_ENABLE_CLK_CTRL, id), SR_ARR(DWB_MEM_PWR_CTRL, id), \ + SR_ARR(FC_MODE_CTRL, id), SR_ARR(FC_FLOW_CTRL, id), \ + SR_ARR(FC_WINDOW_START, id), SR_ARR(FC_WINDOW_SIZE, id), \ + SR_ARR(FC_SOURCE_SIZE, id), SR_ARR(DWB_UPDATE_CTRL, id), \ + SR_ARR(DWB_CRC_CTRL, id), SR_ARR(DWB_CRC_MASK_R_G, id), \ + SR_ARR(DWB_CRC_MASK_B_A, id), SR_ARR(DWB_CRC_VAL_R_G, id), \ + SR_ARR(DWB_CRC_VAL_B_A, id), SR_ARR(DWB_OUT_CTRL, id), \ + SR_ARR(DWB_MMHUBBUB_BACKPRESSURE_CNT_EN, id), \ + SR_ARR(DWB_MMHUBBUB_BACKPRESSURE_CNT, id), \ + SR_ARR(DWB_HOST_READ_CONTROL, id), SR_ARR(DWB_SOFT_RESET, id), \ + SR_ARR(DWB_HDR_MULT_COEF, id), SR_ARR(DWB_GAMUT_REMAP_MODE, id), \ + SR_ARR(DWB_GAMUT_REMAP_COEF_FORMAT, id), \ + SR_ARR(DWB_GAMUT_REMAPA_C11_C12, id), \ + SR_ARR(DWB_GAMUT_REMAPA_C13_C14, id), \ + SR_ARR(DWB_GAMUT_REMAPA_C21_C22, id), \ + SR_ARR(DWB_GAMUT_REMAPA_C23_C24, id), \ + SR_ARR(DWB_GAMUT_REMAPA_C31_C32, id), \ + SR_ARR(DWB_GAMUT_REMAPA_C33_C34, id), \ + SR_ARR(DWB_GAMUT_REMAPB_C11_C12, id), \ + SR_ARR(DWB_GAMUT_REMAPB_C13_C14, id), \ + SR_ARR(DWB_GAMUT_REMAPB_C21_C22, id), \ + SR_ARR(DWB_GAMUT_REMAPB_C23_C24, id), \ + SR_ARR(DWB_GAMUT_REMAPB_C31_C32, id), \ + SR_ARR(DWB_GAMUT_REMAPB_C33_C34, id), SR_ARR(DWB_OGAM_CONTROL, id), \ + SR_ARR(DWB_OGAM_LUT_INDEX, id), SR_ARR(DWB_OGAM_LUT_DATA, id), \ + SR_ARR(DWB_OGAM_LUT_CONTROL, id), \ + SR_ARR(DWB_OGAM_RAMA_START_CNTL_B, id), \ + SR_ARR(DWB_OGAM_RAMA_START_CNTL_G, id), \ + SR_ARR(DWB_OGAM_RAMA_START_CNTL_R, id), \ + SR_ARR(DWB_OGAM_RAMA_START_BASE_CNTL_B, id), \ + SR_ARR(DWB_OGAM_RAMA_START_SLOPE_CNTL_B, id), \ + SR_ARR(DWB_OGAM_RAMA_START_BASE_CNTL_G, id), \ + SR_ARR(DWB_OGAM_RAMA_START_SLOPE_CNTL_G, id), \ + SR_ARR(DWB_OGAM_RAMA_START_BASE_CNTL_R, id), \ + SR_ARR(DWB_OGAM_RAMA_START_SLOPE_CNTL_R, id), \ + SR_ARR(DWB_OGAM_RAMA_END_CNTL1_B, id), \ + SR_ARR(DWB_OGAM_RAMA_END_CNTL2_B, id), \ + SR_ARR(DWB_OGAM_RAMA_END_CNTL1_G, id), \ + SR_ARR(DWB_OGAM_RAMA_END_CNTL2_G, id), \ + SR_ARR(DWB_OGAM_RAMA_END_CNTL1_R, id), \ + SR_ARR(DWB_OGAM_RAMA_END_CNTL2_R, id), \ + SR_ARR(DWB_OGAM_RAMA_OFFSET_B, id), SR_ARR(DWB_OGAM_RAMA_OFFSET_G, id), \ + SR_ARR(DWB_OGAM_RAMA_OFFSET_R, id), \ + SR_ARR(DWB_OGAM_RAMA_REGION_0_1, id), \ + SR_ARR(DWB_OGAM_RAMA_REGION_2_3, id), \ + SR_ARR(DWB_OGAM_RAMA_REGION_4_5, id), \ + SR_ARR(DWB_OGAM_RAMA_REGION_6_7, id), \ + SR_ARR(DWB_OGAM_RAMA_REGION_8_9, id), \ + SR_ARR(DWB_OGAM_RAMA_REGION_10_11, id), \ + SR_ARR(DWB_OGAM_RAMA_REGION_12_13, id), \ + SR_ARR(DWB_OGAM_RAMA_REGION_14_15, id), \ + SR_ARR(DWB_OGAM_RAMA_REGION_16_17, id), \ + SR_ARR(DWB_OGAM_RAMA_REGION_18_19, id), \ + SR_ARR(DWB_OGAM_RAMA_REGION_20_21, id), \ + SR_ARR(DWB_OGAM_RAMA_REGION_22_23, id), \ + SR_ARR(DWB_OGAM_RAMA_REGION_24_25, id), \ + SR_ARR(DWB_OGAM_RAMA_REGION_26_27, id), \ + SR_ARR(DWB_OGAM_RAMA_REGION_28_29, id), \ + SR_ARR(DWB_OGAM_RAMA_REGION_30_31, id), \ + SR_ARR(DWB_OGAM_RAMA_REGION_32_33, id), \ + SR_ARR(DWB_OGAM_RAMB_START_CNTL_B, id), \ + SR_ARR(DWB_OGAM_RAMB_START_CNTL_G, id), \ + SR_ARR(DWB_OGAM_RAMB_START_CNTL_R, id), \ + SR_ARR(DWB_OGAM_RAMB_START_BASE_CNTL_B, id), \ + SR_ARR(DWB_OGAM_RAMB_START_SLOPE_CNTL_B, id), \ + SR_ARR(DWB_OGAM_RAMB_START_BASE_CNTL_G, id), \ + SR_ARR(DWB_OGAM_RAMB_START_SLOPE_CNTL_G, id), \ + SR_ARR(DWB_OGAM_RAMB_START_BASE_CNTL_R, id), \ + SR_ARR(DWB_OGAM_RAMB_START_SLOPE_CNTL_R, id), \ + SR_ARR(DWB_OGAM_RAMB_END_CNTL1_B, id), \ + SR_ARR(DWB_OGAM_RAMB_END_CNTL2_B, id), \ + SR_ARR(DWB_OGAM_RAMB_END_CNTL1_G, id), \ + SR_ARR(DWB_OGAM_RAMB_END_CNTL2_G, id), \ + SR_ARR(DWB_OGAM_RAMB_END_CNTL1_R, id), \ + SR_ARR(DWB_OGAM_RAMB_END_CNTL2_R, id), \ + SR_ARR(DWB_OGAM_RAMB_OFFSET_B, id), SR_ARR(DWB_OGAM_RAMB_OFFSET_G, id), \ + SR_ARR(DWB_OGAM_RAMB_OFFSET_R, id), \ + SR_ARR(DWB_OGAM_RAMB_REGION_0_1, id), \ + SR_ARR(DWB_OGAM_RAMB_REGION_2_3, id), \ + SR_ARR(DWB_OGAM_RAMB_REGION_4_5, id), \ + SR_ARR(DWB_OGAM_RAMB_REGION_6_7, id), \ + SR_ARR(DWB_OGAM_RAMB_REGION_8_9, id), \ + SR_ARR(DWB_OGAM_RAMB_REGION_10_11, id), \ + SR_ARR(DWB_OGAM_RAMB_REGION_12_13, id), \ + SR_ARR(DWB_OGAM_RAMB_REGION_14_15, id), \ + SR_ARR(DWB_OGAM_RAMB_REGION_16_17, id), \ + SR_ARR(DWB_OGAM_RAMB_REGION_18_19, id), \ + SR_ARR(DWB_OGAM_RAMB_REGION_20_21, id), \ + SR_ARR(DWB_OGAM_RAMB_REGION_22_23, id), \ + SR_ARR(DWB_OGAM_RAMB_REGION_24_25, id), \ + SR_ARR(DWB_OGAM_RAMB_REGION_26_27, id), \ + SR_ARR(DWB_OGAM_RAMB_REGION_28_29, id), \ + SR_ARR(DWB_OGAM_RAMB_REGION_30_31, id), \ + SR_ARR(DWB_OGAM_RAMB_REGION_32_33, id) + +/* MCIF */ + +#define MCIF_WB_COMMON_REG_LIST_DCN32_RI(inst) \ + SRI2_ARR(MCIF_WB_BUFMGR_SW_CONTROL, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_BUFMGR_STATUS, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_BUF_PITCH, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_BUF_1_STATUS, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_BUF_1_STATUS2, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_BUF_2_STATUS, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_BUF_2_STATUS2, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_BUF_3_STATUS, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_BUF_3_STATUS2, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_BUF_4_STATUS, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_BUF_4_STATUS2, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_ARBITRATION_CONTROL, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_SCLK_CHANGE, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_BUF_1_ADDR_Y, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_BUF_1_ADDR_C, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_BUF_2_ADDR_Y, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_BUF_2_ADDR_C, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_BUF_3_ADDR_Y, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_BUF_3_ADDR_C, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_BUF_4_ADDR_Y, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_BUF_4_ADDR_C, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_BUFMGR_VCE_CONTROL, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_NB_PSTATE_LATENCY_WATERMARK, MMHUBBUB, inst), \ + SRI2_ARR(MCIF_WB_NB_PSTATE_CONTROL, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_WATERMARK, MMHUBBUB, inst), \ + SRI2_ARR(MCIF_WB_CLOCK_GATER_CONTROL, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_SELF_REFRESH_CONTROL, MCIF_WB, inst), \ + SRI2_ARR(MULTI_LEVEL_QOS_CTRL, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_SECURITY_LEVEL, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_BUF_LUMA_SIZE, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_BUF_CHROMA_SIZE, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_BUF_1_ADDR_Y_HIGH, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_BUF_1_ADDR_C_HIGH, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_BUF_2_ADDR_Y_HIGH, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_BUF_2_ADDR_C_HIGH, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_BUF_3_ADDR_Y_HIGH, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_BUF_3_ADDR_C_HIGH, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_BUF_4_ADDR_Y_HIGH, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_BUF_4_ADDR_C_HIGH, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_BUF_1_RESOLUTION, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_BUF_2_RESOLUTION, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_BUF_3_RESOLUTION, MCIF_WB, inst), \ + SRI2_ARR(MCIF_WB_BUF_4_RESOLUTION, MCIF_WB, inst), \ + SRI2_ARR(MMHUBBUB_MEM_PWR_CNTL, MMHUBBUB, inst), \ + SRI2_ARR(MMHUBBUB_WARMUP_ADDR_REGION, MMHUBBUB, inst), \ + SRI2_ARR(MMHUBBUB_WARMUP_BASE_ADDR_HIGH, MMHUBBUB, inst), \ + SRI2_ARR(MMHUBBUB_WARMUP_BASE_ADDR_LOW, MMHUBBUB, inst), \ + SRI2_ARR(MMHUBBUB_WARMUP_CONTROL_STATUS, MMHUBBUB, inst) + +/* DSC */ + +#define DSC_REG_LIST_DCN20_RI(id) \ + SRI_ARR(DSC_TOP_CONTROL, DSC_TOP, id), \ + SRI_ARR(DSC_DEBUG_CONTROL, DSC_TOP, id), \ + SRI_ARR(DSCC_CONFIG0, DSCC, id), SRI_ARR(DSCC_CONFIG1, DSCC, id), \ + SRI_ARR(DSCC_STATUS, DSCC, id), \ + SRI_ARR(DSCC_INTERRUPT_CONTROL_STATUS, DSCC, id), \ + SRI_ARR(DSCC_PPS_CONFIG0, DSCC, id), \ + SRI_ARR(DSCC_PPS_CONFIG1, DSCC, id), \ + SRI_ARR(DSCC_PPS_CONFIG2, DSCC, id), \ + SRI_ARR(DSCC_PPS_CONFIG3, DSCC, id), \ + SRI_ARR(DSCC_PPS_CONFIG4, DSCC, id), \ + SRI_ARR(DSCC_PPS_CONFIG5, DSCC, id), \ + SRI_ARR(DSCC_PPS_CONFIG6, DSCC, id), \ + SRI_ARR(DSCC_PPS_CONFIG7, DSCC, id), \ + SRI_ARR(DSCC_PPS_CONFIG8, DSCC, id), \ + SRI_ARR(DSCC_PPS_CONFIG9, DSCC, id), \ + SRI_ARR(DSCC_PPS_CONFIG10, DSCC, id), \ + SRI_ARR(DSCC_PPS_CONFIG11, DSCC, id), \ + SRI_ARR(DSCC_PPS_CONFIG12, DSCC, id), \ + SRI_ARR(DSCC_PPS_CONFIG13, DSCC, id), \ + SRI_ARR(DSCC_PPS_CONFIG14, DSCC, id), \ + SRI_ARR(DSCC_PPS_CONFIG15, DSCC, id), \ + SRI_ARR(DSCC_PPS_CONFIG16, DSCC, id), \ + SRI_ARR(DSCC_PPS_CONFIG17, DSCC, id), \ + SRI_ARR(DSCC_PPS_CONFIG18, DSCC, id), \ + SRI_ARR(DSCC_PPS_CONFIG19, DSCC, id), \ + SRI_ARR(DSCC_PPS_CONFIG20, DSCC, id), \ + SRI_ARR(DSCC_PPS_CONFIG21, DSCC, id), \ + SRI_ARR(DSCC_PPS_CONFIG22, DSCC, id), \ + SRI_ARR(DSCC_MEM_POWER_CONTROL, DSCC, id), \ + SRI_ARR(DSCC_R_Y_SQUARED_ERROR_LOWER, DSCC, id), \ + SRI_ARR(DSCC_R_Y_SQUARED_ERROR_UPPER, DSCC, id), \ + SRI_ARR(DSCC_G_CB_SQUARED_ERROR_LOWER, DSCC, id), \ + SRI_ARR(DSCC_G_CB_SQUARED_ERROR_UPPER, DSCC, id), \ + SRI_ARR(DSCC_B_CR_SQUARED_ERROR_LOWER, DSCC, id), \ + SRI_ARR(DSCC_B_CR_SQUARED_ERROR_UPPER, DSCC, id), \ + SRI_ARR(DSCC_MAX_ABS_ERROR0, DSCC, id), \ + SRI_ARR(DSCC_MAX_ABS_ERROR1, DSCC, id), \ + SRI_ARR(DSCC_RATE_BUFFER0_MAX_FULLNESS_LEVEL, DSCC, id), \ + SRI_ARR(DSCC_RATE_BUFFER1_MAX_FULLNESS_LEVEL, DSCC, id), \ + SRI_ARR(DSCC_RATE_BUFFER2_MAX_FULLNESS_LEVEL, DSCC, id), \ + SRI_ARR(DSCC_RATE_BUFFER3_MAX_FULLNESS_LEVEL, DSCC, id), \ + SRI_ARR(DSCC_RATE_CONTROL_BUFFER0_MAX_FULLNESS_LEVEL, DSCC, id), \ + SRI_ARR(DSCC_RATE_CONTROL_BUFFER1_MAX_FULLNESS_LEVEL, DSCC, id), \ + SRI_ARR(DSCC_RATE_CONTROL_BUFFER2_MAX_FULLNESS_LEVEL, DSCC, id), \ + SRI_ARR(DSCC_RATE_CONTROL_BUFFER3_MAX_FULLNESS_LEVEL, DSCC, id), \ + SRI_ARR(DSCCIF_CONFIG0, DSCCIF, id), \ + SRI_ARR(DSCCIF_CONFIG1, DSCCIF, id), \ + SRI_ARR(DSCRM_DSC_FORWARD_CONFIG, DSCRM, id) + +/* MPC */ + +#define MPC_DWB_MUX_REG_LIST_DCN3_0_RI(inst) \ + SRII_DWB(DWB_MUX, MUX, MPC_DWB, inst) + +#define MPC_OUT_MUX_COMMON_REG_LIST_DCN1_0_RI(inst) \ + SRII(MUX, MPC_OUT, inst), VUPDATE_SRII(CUR, VUPDATE_LOCK_SET, inst) + +#define MPC_OUT_MUX_REG_LIST_DCN3_0_RI(inst) \ + MPC_OUT_MUX_COMMON_REG_LIST_DCN1_0_RI(inst), SRII(CSC_MODE, MPC_OUT, inst), \ + SRII(CSC_C11_C12_A, MPC_OUT, inst), SRII(CSC_C33_C34_A, MPC_OUT, inst), \ + SRII(CSC_C11_C12_B, MPC_OUT, inst), SRII(CSC_C33_C34_B, MPC_OUT, inst), \ + SRII(DENORM_CONTROL, MPC_OUT, inst), \ + SRII(DENORM_CLAMP_G_Y, MPC_OUT, inst), \ + SRII(DENORM_CLAMP_B_CB, MPC_OUT, inst), SR(MPC_OUT_CSC_COEF_FORMAT) + +#define MPC_COMMON_REG_LIST_DCN1_0_RI(inst) \ + SRII(MPCC_TOP_SEL, MPCC, inst), SRII(MPCC_BOT_SEL, MPCC, inst), \ + SRII(MPCC_CONTROL, MPCC, inst), SRII(MPCC_STATUS, MPCC, inst), \ + SRII(MPCC_OPP_ID, MPCC, inst), SRII(MPCC_BG_G_Y, MPCC, inst), \ + SRII(MPCC_BG_R_CR, MPCC, inst), SRII(MPCC_BG_B_CB, MPCC, inst), \ + SRII(MPCC_SM_CONTROL, MPCC, inst), \ + SRII(MPCC_UPDATE_LOCK_SEL, MPCC, inst) + +#define MPC_REG_LIST_DCN3_0_RI(inst) \ + MPC_COMMON_REG_LIST_DCN1_0_RI(inst), SRII(MPCC_TOP_GAIN, MPCC, inst), \ + SRII(MPCC_BOT_GAIN_INSIDE, MPCC, inst), \ + SRII(MPCC_BOT_GAIN_OUTSIDE, MPCC, inst), \ + SRII(MPCC_MEM_PWR_CTRL, MPCC, inst), \ + SRII(MPCC_OGAM_LUT_INDEX, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_LUT_DATA, MPCC_OGAM, inst), \ + SRII(MPCC_GAMUT_REMAP_COEF_FORMAT, MPCC_OGAM, inst), \ + SRII(MPCC_GAMUT_REMAP_MODE, MPCC_OGAM, inst), \ + SRII(MPC_GAMUT_REMAP_C11_C12_A, MPCC_OGAM, inst), \ + SRII(MPC_GAMUT_REMAP_C33_C34_A, MPCC_OGAM, inst), \ + SRII(MPC_GAMUT_REMAP_C11_C12_B, MPCC_OGAM, inst), \ + SRII(MPC_GAMUT_REMAP_C33_C34_B, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMA_START_CNTL_B, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMA_START_CNTL_G, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMA_START_CNTL_R, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMA_START_SLOPE_CNTL_B, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMA_START_SLOPE_CNTL_G, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMA_START_SLOPE_CNTL_R, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMA_END_CNTL1_B, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMA_END_CNTL2_B, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMA_END_CNTL1_G, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMA_END_CNTL2_G, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMA_END_CNTL1_R, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMA_END_CNTL2_R, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMA_REGION_0_1, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMA_REGION_32_33, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMA_OFFSET_B, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMA_OFFSET_G, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMA_OFFSET_R, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMA_START_BASE_CNTL_B, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMA_START_BASE_CNTL_G, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMA_START_BASE_CNTL_R, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMB_START_CNTL_B, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMB_START_CNTL_G, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMB_START_CNTL_R, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMB_START_SLOPE_CNTL_B, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMB_START_SLOPE_CNTL_G, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMB_START_SLOPE_CNTL_R, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMB_END_CNTL1_B, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMB_END_CNTL2_B, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMB_END_CNTL1_G, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMB_END_CNTL2_G, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMB_END_CNTL1_R, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMB_END_CNTL2_R, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMB_REGION_0_1, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMB_REGION_32_33, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMB_OFFSET_B, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMB_OFFSET_G, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMB_OFFSET_R, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMB_START_BASE_CNTL_B, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMB_START_BASE_CNTL_G, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_RAMB_START_BASE_CNTL_R, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_CONTROL, MPCC_OGAM, inst), \ + SRII(MPCC_OGAM_LUT_CONTROL, MPCC_OGAM, inst) + +#define MPC_REG_LIST_DCN3_2_RI(inst) \ + MPC_REG_LIST_DCN3_0_RI(inst),\ + SRII(MPCC_MOVABLE_CM_LOCATION_CONTROL, MPCC, inst),\ + SRII(MPCC_MCM_SHAPER_CONTROL, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_OFFSET_R, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_OFFSET_G, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_OFFSET_B, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_SCALE_R, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_SCALE_G_B, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_LUT_INDEX, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_LUT_DATA, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_LUT_WRITE_EN_MASK, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMA_START_CNTL_B, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMA_START_CNTL_G, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMA_START_CNTL_R, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMA_END_CNTL_B, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMA_END_CNTL_G, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMA_END_CNTL_R, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMA_REGION_0_1, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMA_REGION_2_3, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMA_REGION_4_5, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMA_REGION_6_7, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMA_REGION_8_9, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMA_REGION_10_11, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMA_REGION_12_13, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMA_REGION_14_15, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMA_REGION_16_17, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMA_REGION_18_19, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMA_REGION_20_21, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMA_REGION_22_23, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMA_REGION_24_25, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMA_REGION_26_27, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMA_REGION_28_29, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMA_REGION_30_31, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMA_REGION_32_33, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMB_START_CNTL_B, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMB_START_CNTL_G, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMB_START_CNTL_R, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMB_END_CNTL_B, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMB_END_CNTL_G, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMB_END_CNTL_R, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMB_REGION_0_1, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMB_REGION_2_3, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMB_REGION_4_5, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMB_REGION_6_7, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMB_REGION_8_9, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMB_REGION_10_11, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMB_REGION_12_13, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMB_REGION_14_15, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMB_REGION_16_17, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMB_REGION_18_19, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMB_REGION_20_21, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMB_REGION_22_23, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMB_REGION_24_25, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMB_REGION_26_27, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMB_REGION_28_29, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMB_REGION_30_31, MPCC_MCM, inst),\ + SRII(MPCC_MCM_SHAPER_RAMB_REGION_32_33, MPCC_MCM, inst),\ + SRII(MPCC_MCM_3DLUT_MODE, MPCC_MCM, inst), /*TODO: may need to add other 3DLUT regs*/\ + SRII(MPCC_MCM_3DLUT_INDEX, MPCC_MCM, inst),\ + SRII(MPCC_MCM_3DLUT_DATA, MPCC_MCM, inst),\ + SRII(MPCC_MCM_3DLUT_DATA_30BIT, MPCC_MCM, inst),\ + SRII(MPCC_MCM_3DLUT_READ_WRITE_CONTROL, MPCC_MCM, inst),\ + SRII(MPCC_MCM_3DLUT_OUT_NORM_FACTOR, MPCC_MCM, inst),\ + SRII(MPCC_MCM_3DLUT_OUT_OFFSET_R, MPCC_MCM, inst),\ + SRII(MPCC_MCM_3DLUT_OUT_OFFSET_G, MPCC_MCM, inst),\ + SRII(MPCC_MCM_3DLUT_OUT_OFFSET_B, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_CONTROL, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_LUT_INDEX, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_LUT_DATA, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_LUT_CONTROL, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_START_CNTL_B, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_START_CNTL_G, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_START_CNTL_R, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_START_SLOPE_CNTL_B, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_START_SLOPE_CNTL_G, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_START_SLOPE_CNTL_R, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_START_BASE_CNTL_B, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_START_BASE_CNTL_G, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_START_BASE_CNTL_R, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_END_CNTL1_B, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_END_CNTL2_B, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_END_CNTL1_G, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_END_CNTL2_G, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_END_CNTL1_R, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_END_CNTL2_R, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_OFFSET_B, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_OFFSET_G, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_OFFSET_R, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_REGION_0_1, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_REGION_2_3, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_REGION_4_5, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_REGION_6_7, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_REGION_8_9, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_REGION_10_11, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_REGION_12_13, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_REGION_14_15, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_REGION_16_17, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_REGION_18_19, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_REGION_20_21, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_REGION_22_23, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_REGION_24_25, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_REGION_26_27, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_REGION_28_29, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_REGION_30_31, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMA_REGION_32_33, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_START_CNTL_B, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_START_CNTL_G, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_START_CNTL_R, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_START_SLOPE_CNTL_B, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_START_SLOPE_CNTL_G, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_START_SLOPE_CNTL_R, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_START_BASE_CNTL_B, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_START_BASE_CNTL_G, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_START_BASE_CNTL_R, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_END_CNTL1_B, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_END_CNTL2_B, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_END_CNTL1_G, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_END_CNTL2_G, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_END_CNTL1_R, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_END_CNTL2_R, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_OFFSET_B, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_OFFSET_G, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_OFFSET_R, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_REGION_0_1, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_REGION_2_3, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_REGION_4_5, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_REGION_6_7, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_REGION_8_9, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_REGION_10_11, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_REGION_12_13, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_REGION_14_15, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_REGION_16_17, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_REGION_18_19, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_REGION_20_21, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_REGION_22_23, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_REGION_24_25, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_REGION_26_27, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_REGION_28_29, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_REGION_30_31, MPCC_MCM, inst),\ + SRII(MPCC_MCM_1DLUT_RAMB_REGION_32_33, MPCC_MCM, inst),\ + SRII(MPCC_MCM_MEM_PWR_CTRL, MPCC_MCM, inst) +/* OPTC */ + +#define OPTC_COMMON_REG_LIST_DCN3_2_RI(inst) \ + SRI_ARR(OTG_VSTARTUP_PARAM, OTG, inst), \ + SRI_ARR(OTG_VUPDATE_PARAM, OTG, inst), \ + SRI_ARR(OTG_VREADY_PARAM, OTG, inst), \ + SRI_ARR(OTG_MASTER_UPDATE_LOCK, OTG, inst), \ + SRI_ARR(OTG_GLOBAL_CONTROL0, OTG, inst), \ + SRI_ARR(OTG_GLOBAL_CONTROL1, OTG, inst), \ + SRI_ARR(OTG_GLOBAL_CONTROL2, OTG, inst), \ + SRI_ARR(OTG_GLOBAL_CONTROL4, OTG, inst), \ + SRI_ARR(OTG_DOUBLE_BUFFER_CONTROL, OTG, inst), \ + SRI_ARR(OTG_H_TOTAL, OTG, inst), \ + SRI_ARR(OTG_H_BLANK_START_END, OTG, inst), \ + SRI_ARR(OTG_H_SYNC_A, OTG, inst), SRI_ARR(OTG_H_SYNC_A_CNTL, OTG, inst), \ + SRI_ARR(OTG_H_TIMING_CNTL, OTG, inst), SRI_ARR(OTG_V_TOTAL, OTG, inst), \ + SRI_ARR(OTG_V_BLANK_START_END, OTG, inst), \ + SRI_ARR(OTG_V_SYNC_A, OTG, inst), SRI_ARR(OTG_V_SYNC_A_CNTL, OTG, inst), \ + SRI_ARR(OTG_CONTROL, OTG, inst), SRI_ARR(OTG_STEREO_CONTROL, OTG, inst), \ + SRI_ARR(OTG_3D_STRUCTURE_CONTROL, OTG, inst), \ + SRI_ARR(OTG_STEREO_STATUS, OTG, inst), \ + SRI_ARR(OTG_V_TOTAL_MAX, OTG, inst), \ + SRI_ARR(OTG_V_TOTAL_MIN, OTG, inst), \ + SRI_ARR(OTG_V_TOTAL_CONTROL, OTG, inst), \ + SRI_ARR(OTG_TRIGA_CNTL, OTG, inst), \ + SRI_ARR(OTG_FORCE_COUNT_NOW_CNTL, OTG, inst), \ + SRI_ARR(OTG_STATIC_SCREEN_CONTROL, OTG, inst), \ + SRI_ARR(OTG_STATUS_FRAME_COUNT, OTG, inst), \ + SRI_ARR(OTG_STATUS, OTG, inst), SRI_ARR(OTG_STATUS_POSITION, OTG, inst), \ + SRI_ARR(OTG_NOM_VERT_POSITION, OTG, inst), \ + SRI_ARR(OTG_M_CONST_DTO0, OTG, inst), \ + SRI_ARR(OTG_M_CONST_DTO1, OTG, inst), \ + SRI_ARR(OTG_CLOCK_CONTROL, OTG, inst), \ + SRI_ARR(OTG_VERTICAL_INTERRUPT0_CONTROL, OTG, inst), \ + SRI_ARR(OTG_VERTICAL_INTERRUPT0_POSITION, OTG, inst), \ + SRI_ARR(OTG_VERTICAL_INTERRUPT1_CONTROL, OTG, inst), \ + SRI_ARR(OTG_VERTICAL_INTERRUPT1_POSITION, OTG, inst), \ + SRI_ARR(OTG_VERTICAL_INTERRUPT2_CONTROL, OTG, inst), \ + SRI_ARR(OTG_VERTICAL_INTERRUPT2_POSITION, OTG, inst), \ + SRI_ARR(OPTC_INPUT_CLOCK_CONTROL, ODM, inst), \ + SRI_ARR(OPTC_DATA_SOURCE_SELECT, ODM, inst), \ + SRI_ARR(OPTC_INPUT_GLOBAL_CONTROL, ODM, inst), \ + SRI_ARR(CONTROL, VTG, inst), SRI_ARR(OTG_VERT_SYNC_CONTROL, OTG, inst), \ + SRI_ARR(OTG_GSL_CONTROL, OTG, inst), SRI_ARR(OTG_CRC_CNTL, OTG, inst), \ + SRI_ARR(OTG_CRC0_DATA_RG, OTG, inst), \ + SRI_ARR(OTG_CRC0_DATA_B, OTG, inst), \ + SRI_ARR(OTG_CRC0_WINDOWA_X_CONTROL, OTG, inst), \ + SRI_ARR(OTG_CRC0_WINDOWA_Y_CONTROL, OTG, inst), \ + SRI_ARR(OTG_CRC0_WINDOWB_X_CONTROL, OTG, inst), \ + SRI_ARR(OTG_CRC0_WINDOWB_Y_CONTROL, OTG, inst), \ + SR_ARR(GSL_SOURCE_SELECT, inst), \ + SRI_ARR(OTG_TRIGA_MANUAL_TRIG, OTG, inst), \ + SRI_ARR(OTG_GLOBAL_CONTROL1, OTG, inst), \ + SRI_ARR(OTG_GLOBAL_CONTROL2, OTG, inst), \ + SRI_ARR(OTG_GSL_WINDOW_X, OTG, inst), \ + SRI_ARR(OTG_GSL_WINDOW_Y, OTG, inst), \ + SRI_ARR(OTG_VUPDATE_KEEPOUT, OTG, inst), \ + SRI_ARR(OTG_DSC_START_POSITION, OTG, inst), \ + SRI_ARR(OTG_DRR_TRIGGER_WINDOW, OTG, inst), \ + SRI_ARR(OTG_DRR_V_TOTAL_CHANGE, OTG, inst), \ + SRI_ARR(OPTC_DATA_FORMAT_CONTROL, ODM, inst), \ + SRI_ARR(OPTC_BYTES_PER_PIXEL, ODM, inst), \ + SRI_ARR(OPTC_WIDTH_CONTROL, ODM, inst), \ + SRI_ARR(OPTC_MEMORY_CONFIG, ODM, inst), \ + SRI_ARR(OTG_DRR_CONTROL, OTG, inst) + +/* HUBP */ + +#define HUBP_REG_LIST_DCN_VM_RI(id) \ + SRI_ARR(NOM_PARAMETERS_0, HUBPREQ, id), \ + SRI_ARR(NOM_PARAMETERS_1, HUBPREQ, id), \ + SRI_ARR(NOM_PARAMETERS_2, HUBPREQ, id), \ + SRI_ARR(NOM_PARAMETERS_3, HUBPREQ, id), \ + SRI_ARR(DCN_VM_MX_L1_TLB_CNTL, HUBPREQ, id) +#define HUBP_REG_LIST_DCN_RI(id) \ + SRI_ARR(DCHUBP_CNTL, HUBP, id), SRI_ARR(HUBPREQ_DEBUG_DB, HUBP, id), \ + SRI_ARR(HUBPREQ_DEBUG, HUBP, id), SRI_ARR(DCSURF_ADDR_CONFIG, HUBP, id), \ + SRI_ARR(DCSURF_TILING_CONFIG, HUBP, id), \ + SRI_ARR(DCSURF_SURFACE_PITCH, HUBPREQ, id), \ + SRI_ARR(DCSURF_SURFACE_PITCH_C, HUBPREQ, id), \ + SRI_ARR(DCSURF_SURFACE_CONFIG, HUBP, id), \ + SRI_ARR(DCSURF_FLIP_CONTROL, HUBPREQ, id), \ + SRI_ARR(DCSURF_PRI_VIEWPORT_DIMENSION, HUBP, id), \ + SRI_ARR(DCSURF_PRI_VIEWPORT_START, HUBP, id), \ + SRI_ARR(DCSURF_SEC_VIEWPORT_DIMENSION, HUBP, id), \ + SRI_ARR(DCSURF_SEC_VIEWPORT_START, HUBP, id), \ + SRI_ARR(DCSURF_PRI_VIEWPORT_DIMENSION_C, HUBP, id), \ + SRI_ARR(DCSURF_PRI_VIEWPORT_START_C, HUBP, id), \ + SRI_ARR(DCSURF_SEC_VIEWPORT_DIMENSION_C, HUBP, id), \ + SRI_ARR(DCSURF_SEC_VIEWPORT_START_C, HUBP, id), \ + SRI_ARR(DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH, HUBPREQ, id), \ + SRI_ARR(DCSURF_PRIMARY_SURFACE_ADDRESS, HUBPREQ, id), \ + SRI_ARR(DCSURF_SECONDARY_SURFACE_ADDRESS_HIGH, HUBPREQ, id), \ + SRI_ARR(DCSURF_SECONDARY_SURFACE_ADDRESS, HUBPREQ, id), \ + SRI_ARR(DCSURF_PRIMARY_META_SURFACE_ADDRESS_HIGH, HUBPREQ, id), \ + SRI_ARR(DCSURF_PRIMARY_META_SURFACE_ADDRESS, HUBPREQ, id), \ + SRI_ARR(DCSURF_SECONDARY_META_SURFACE_ADDRESS_HIGH, HUBPREQ, id), \ + SRI_ARR(DCSURF_SECONDARY_META_SURFACE_ADDRESS, HUBPREQ, id), \ + SRI_ARR(DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH_C, HUBPREQ, id), \ + SRI_ARR(DCSURF_PRIMARY_SURFACE_ADDRESS_C, HUBPREQ, id), \ + SRI_ARR(DCSURF_SECONDARY_SURFACE_ADDRESS_HIGH_C, HUBPREQ, id), \ + SRI_ARR(DCSURF_SECONDARY_SURFACE_ADDRESS_C, HUBPREQ, id), \ + SRI_ARR(DCSURF_PRIMARY_META_SURFACE_ADDRESS_HIGH_C, HUBPREQ, id), \ + SRI_ARR(DCSURF_PRIMARY_META_SURFACE_ADDRESS_C, HUBPREQ, id), \ + SRI_ARR(DCSURF_SECONDARY_META_SURFACE_ADDRESS_HIGH_C, HUBPREQ, id), \ + SRI_ARR(DCSURF_SECONDARY_META_SURFACE_ADDRESS_C, HUBPREQ, id), \ + SRI_ARR(DCSURF_SURFACE_INUSE, HUBPREQ, id), \ + SRI_ARR(DCSURF_SURFACE_INUSE_HIGH, HUBPREQ, id), \ + SRI_ARR(DCSURF_SURFACE_INUSE_C, HUBPREQ, id), \ + SRI_ARR(DCSURF_SURFACE_INUSE_HIGH_C, HUBPREQ, id), \ + SRI_ARR(DCSURF_SURFACE_EARLIEST_INUSE, HUBPREQ, id), \ + SRI_ARR(DCSURF_SURFACE_EARLIEST_INUSE_HIGH, HUBPREQ, id), \ + SRI_ARR(DCSURF_SURFACE_EARLIEST_INUSE_C, HUBPREQ, id), \ + SRI_ARR(DCSURF_SURFACE_EARLIEST_INUSE_HIGH_C, HUBPREQ, id), \ + SRI_ARR(DCSURF_SURFACE_CONTROL, HUBPREQ, id), \ + SRI_ARR(DCSURF_SURFACE_FLIP_INTERRUPT, HUBPREQ, id), \ + SRI_ARR(HUBPRET_CONTROL, HUBPRET, id), \ + SRI_ARR(HUBPRET_READ_LINE_STATUS, HUBPRET, id), \ + SRI_ARR(DCN_EXPANSION_MODE, HUBPREQ, id), \ + SRI_ARR(DCHUBP_REQ_SIZE_CONFIG, HUBP, id), \ + SRI_ARR(DCHUBP_REQ_SIZE_CONFIG_C, HUBP, id), \ + SRI_ARR(BLANK_OFFSET_0, HUBPREQ, id), \ + SRI_ARR(BLANK_OFFSET_1, HUBPREQ, id), \ + SRI_ARR(DST_DIMENSIONS, HUBPREQ, id), \ + SRI_ARR(DST_AFTER_SCALER, HUBPREQ, id), \ + SRI_ARR(VBLANK_PARAMETERS_0, HUBPREQ, id), \ + SRI_ARR(REF_FREQ_TO_PIX_FREQ, HUBPREQ, id), \ + SRI_ARR(VBLANK_PARAMETERS_1, HUBPREQ, id), \ + SRI_ARR(VBLANK_PARAMETERS_3, HUBPREQ, id), \ + SRI_ARR(NOM_PARAMETERS_4, HUBPREQ, id), \ + SRI_ARR(NOM_PARAMETERS_5, HUBPREQ, id), \ + SRI_ARR(PER_LINE_DELIVERY_PRE, HUBPREQ, id), \ + SRI_ARR(PER_LINE_DELIVERY, HUBPREQ, id), \ + SRI_ARR(VBLANK_PARAMETERS_2, HUBPREQ, id), \ + SRI_ARR(VBLANK_PARAMETERS_4, HUBPREQ, id), \ + SRI_ARR(NOM_PARAMETERS_6, HUBPREQ, id), \ + SRI_ARR(NOM_PARAMETERS_7, HUBPREQ, id), \ + SRI_ARR(DCN_TTU_QOS_WM, HUBPREQ, id), \ + SRI_ARR(DCN_GLOBAL_TTU_CNTL, HUBPREQ, id), \ + SRI_ARR(DCN_SURF0_TTU_CNTL0, HUBPREQ, id), \ + SRI_ARR(DCN_SURF0_TTU_CNTL1, HUBPREQ, id), \ + SRI_ARR(DCN_SURF1_TTU_CNTL0, HUBPREQ, id), \ + SRI_ARR(DCN_SURF1_TTU_CNTL1, HUBPREQ, id), \ + SRI_ARR(DCN_CUR0_TTU_CNTL0, HUBPREQ, id), \ + SRI_ARR(DCN_CUR0_TTU_CNTL1, HUBPREQ, id), \ + SRI_ARR(HUBP_CLK_CNTL, HUBP, id) +#define HUBP_REG_LIST_DCN2_COMMON_RI(id) \ + HUBP_REG_LIST_DCN_RI(id), HUBP_REG_LIST_DCN_VM_RI(id), \ + SRI_ARR(PREFETCH_SETTINGS, HUBPREQ, id), \ + SRI_ARR(PREFETCH_SETTINGS_C, HUBPREQ, id), \ + SRI_ARR(DCN_VM_SYSTEM_APERTURE_LOW_ADDR, HUBPREQ, id), \ + SRI_ARR(DCN_VM_SYSTEM_APERTURE_HIGH_ADDR, HUBPREQ, id), \ + SRI_ARR(CURSOR_SETTINGS, HUBPREQ, id), \ + SRI_ARR(CURSOR_SURFACE_ADDRESS_HIGH, CURSOR0_, id), \ + SRI_ARR(CURSOR_SURFACE_ADDRESS, CURSOR0_, id), \ + SRI_ARR(CURSOR_SIZE, CURSOR0_, id), \ + SRI_ARR(CURSOR_CONTROL, CURSOR0_, id), \ + SRI_ARR(CURSOR_POSITION, CURSOR0_, id), \ + SRI_ARR(CURSOR_HOT_SPOT, CURSOR0_, id), \ + SRI_ARR(CURSOR_DST_OFFSET, CURSOR0_, id), \ + SRI_ARR(DMDATA_ADDRESS_HIGH, CURSOR0_, id), \ + SRI_ARR(DMDATA_ADDRESS_LOW, CURSOR0_, id), \ + SRI_ARR(DMDATA_CNTL, CURSOR0_, id), \ + SRI_ARR(DMDATA_SW_CNTL, CURSOR0_, id), \ + SRI_ARR(DMDATA_QOS_CNTL, CURSOR0_, id), \ + SRI_ARR(DMDATA_SW_DATA, CURSOR0_, id), \ + SRI_ARR(DMDATA_STATUS, CURSOR0_, id), \ + SRI_ARR(FLIP_PARAMETERS_0, HUBPREQ, id), \ + SRI_ARR(FLIP_PARAMETERS_1, HUBPREQ, id), \ + SRI_ARR(FLIP_PARAMETERS_2, HUBPREQ, id), \ + SRI_ARR(DCN_CUR1_TTU_CNTL0, HUBPREQ, id), \ + SRI_ARR(DCN_CUR1_TTU_CNTL1, HUBPREQ, id), \ + SRI_ARR(DCSURF_FLIP_CONTROL2, HUBPREQ, id), \ + SRI_ARR(VMID_SETTINGS_0, HUBPREQ, id) +#define HUBP_REG_LIST_DCN21_RI(id) \ + HUBP_REG_LIST_DCN2_COMMON_RI(id), SRI_ARR(FLIP_PARAMETERS_3, HUBPREQ, id), \ + SRI_ARR(FLIP_PARAMETERS_4, HUBPREQ, id), \ + SRI_ARR(FLIP_PARAMETERS_5, HUBPREQ, id), \ + SRI_ARR(FLIP_PARAMETERS_6, HUBPREQ, id), \ + SRI_ARR(VBLANK_PARAMETERS_5, HUBPREQ, id), \ + SRI_ARR(VBLANK_PARAMETERS_6, HUBPREQ, id) +#define HUBP_REG_LIST_DCN30_RI(id) \ + HUBP_REG_LIST_DCN21_RI(id), SRI_ARR(DCN_DMDATA_VM_CNTL, HUBPREQ, id) +#define HUBP_REG_LIST_DCN32_RI(id) \ + HUBP_REG_LIST_DCN30_RI(id), SRI_ARR(DCHUBP_MALL_CONFIG, HUBP, id), \ + SRI_ARR(DCHUBP_VMPG_CONFIG, HUBP, id), \ + SRI_ARR(UCLK_PSTATE_FORCE, HUBPREQ, id) + +/* HUBBUB */ + +#define HUBBUB_REG_LIST_DCN32_RI(id) \ + SR(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A), \ + SR(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B), \ + SR(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C), \ + SR(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D), \ + SR(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL), \ + SR(DCHUBBUB_ARB_DRAM_STATE_CNTL), SR(DCHUBBUB_ARB_SAT_LEVEL), \ + SR(DCHUBBUB_ARB_DF_REQ_OUTSTAND), SR(DCHUBBUB_GLOBAL_TIMER_CNTL), \ + SR(DCHUBBUB_SOFT_RESET), SR(DCHUBBUB_CRC_CTRL), \ + SR(DCN_VM_FB_LOCATION_BASE), SR(DCN_VM_FB_LOCATION_TOP), \ + SR(DCN_VM_FB_OFFSET), SR(DCN_VM_AGP_BOT), SR(DCN_VM_AGP_TOP), \ + SR(DCN_VM_AGP_BASE), HUBBUB_SR_WATERMARK_REG_LIST(), \ + SR(DCHUBBUB_ARB_FRAC_URG_BW_NOM_A), SR(DCHUBBUB_ARB_FRAC_URG_BW_NOM_B), \ + SR(DCHUBBUB_ARB_FRAC_URG_BW_NOM_C), SR(DCHUBBUB_ARB_FRAC_URG_BW_NOM_D), \ + SR(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_A), \ + SR(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_B), \ + SR(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_C), \ + SR(DCHUBBUB_ARB_FRAC_URG_BW_FLIP_D), \ + SR(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_A), \ + SR(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_B), \ + SR(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_C), \ + SR(DCHUBBUB_ARB_REFCYC_PER_TRIP_TO_MEMORY_D), SR(DCHUBBUB_DET0_CTRL), \ + SR(DCHUBBUB_DET1_CTRL), SR(DCHUBBUB_DET2_CTRL), SR(DCHUBBUB_DET3_CTRL), \ + SR(DCHUBBUB_COMPBUF_CTRL), SR(COMPBUF_RESERVED_SPACE), \ + SR(DCHUBBUB_DEBUG_CTRL_0), \ + SR(DCHUBBUB_ARB_USR_RETRAINING_CNTL), \ + SR(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_A), \ + SR(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_B), \ + SR(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_C), \ + SR(DCHUBBUB_ARB_USR_RETRAINING_WATERMARK_D), \ + SR(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_A), \ + SR(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_B), \ + SR(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_C), \ + SR(DCHUBBUB_ARB_UCLK_PSTATE_CHANGE_WATERMARK_D), \ + SR(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_A), \ + SR(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_B), \ + SR(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_C), \ + SR(DCHUBBUB_ARB_FCLK_PSTATE_CHANGE_WATERMARK_D), \ + SR(DCHUBBUB_ARB_MALL_CNTL), \ + SR(DCN_VM_FAULT_ADDR_MSB), SR(DCN_VM_FAULT_ADDR_LSB), \ + SR(DCN_VM_FAULT_CNTL), SR(DCN_VM_FAULT_STATUS), \ + SR(SDPIF_REQUEST_RATE_LIMIT) + +/* DCCG */ + +#define DCCG_REG_LIST_DCN32_RI() \ + SR(DPPCLK_DTO_CTRL), DCCG_SRII(DTO_PARAM, DPPCLK, 0), \ + DCCG_SRII(DTO_PARAM, DPPCLK, 1), DCCG_SRII(DTO_PARAM, DPPCLK, 2), \ + DCCG_SRII(DTO_PARAM, DPPCLK, 3), DCCG_SRII(CLOCK_CNTL, HDMICHARCLK, 0), \ + SR(PHYASYMCLK_CLOCK_CNTL), SR(PHYBSYMCLK_CLOCK_CNTL), \ + SR(PHYCSYMCLK_CLOCK_CNTL), SR(PHYDSYMCLK_CLOCK_CNTL), \ + SR(PHYESYMCLK_CLOCK_CNTL), SR(DPSTREAMCLK_CNTL), SR(HDMISTREAMCLK_CNTL), \ + SR(SYMCLK32_SE_CNTL), SR(SYMCLK32_LE_CNTL), \ + DCCG_SRII(PIXEL_RATE_CNTL, OTG, 0), DCCG_SRII(PIXEL_RATE_CNTL, OTG, 1), \ + DCCG_SRII(PIXEL_RATE_CNTL, OTG, 2), DCCG_SRII(PIXEL_RATE_CNTL, OTG, 3), \ + DCCG_SRII(MODULO, DTBCLK_DTO, 0), DCCG_SRII(MODULO, DTBCLK_DTO, 1), \ + DCCG_SRII(MODULO, DTBCLK_DTO, 2), DCCG_SRII(MODULO, DTBCLK_DTO, 3), \ + DCCG_SRII(PHASE, DTBCLK_DTO, 0), DCCG_SRII(PHASE, DTBCLK_DTO, 1), \ + DCCG_SRII(PHASE, DTBCLK_DTO, 2), DCCG_SRII(PHASE, DTBCLK_DTO, 3), \ + SR(DCCG_AUDIO_DTBCLK_DTO_MODULO), SR(DCCG_AUDIO_DTBCLK_DTO_PHASE), \ + SR(OTG_PIXEL_RATE_DIV), SR(DTBCLK_P_CNTL), \ + SR(DCCG_AUDIO_DTO_SOURCE), SR(DENTIST_DISPCLK_CNTL) + +/* VMID */ +#define DCN20_VMID_REG_LIST_RI(id) \ + SRI_ARR(CNTL, DCN_VM_CONTEXT, id), \ + SRI_ARR(PAGE_TABLE_BASE_ADDR_HI32, DCN_VM_CONTEXT, id), \ + SRI_ARR(PAGE_TABLE_BASE_ADDR_LO32, DCN_VM_CONTEXT, id), \ + SRI_ARR(PAGE_TABLE_START_ADDR_HI32, DCN_VM_CONTEXT, id), \ + SRI_ARR(PAGE_TABLE_START_ADDR_LO32, DCN_VM_CONTEXT, id), \ + SRI_ARR(PAGE_TABLE_END_ADDR_HI32, DCN_VM_CONTEXT, id), \ + SRI_ARR(PAGE_TABLE_END_ADDR_LO32, DCN_VM_CONTEXT, id) + +/* I2C HW */ + +#define I2C_HW_ENGINE_COMMON_REG_LIST_RI(id) \ + SRI_ARR_I2C(SETUP, DC_I2C_DDC, id), SRI_ARR_I2C(SPEED, DC_I2C_DDC, id), \ + SRI_ARR_I2C(HW_STATUS, DC_I2C_DDC, id), \ + SR_ARR_I2C(DC_I2C_ARBITRATION, id), \ + SR_ARR_I2C(DC_I2C_CONTROL, id), SR_ARR_I2C(DC_I2C_SW_STATUS, id), \ + SR_ARR_I2C(DC_I2C_TRANSACTION0, id), SR_ARR_I2C(DC_I2C_TRANSACTION1, id),\ + SR_ARR_I2C(DC_I2C_TRANSACTION2, id), SR_ARR_I2C(DC_I2C_TRANSACTION3, id),\ + SR_ARR_I2C(DC_I2C_DATA, id), SR_ARR_I2C(MICROSECOND_TIME_BASE_DIV, id) + +#define I2C_HW_ENGINE_COMMON_REG_LIST_DCN30_RI(id) \ + I2C_HW_ENGINE_COMMON_REG_LIST_RI(id), SR_ARR_I2C(DIO_MEM_PWR_CTRL, id), \ + SR_ARR_I2C(DIO_MEM_PWR_STATUS, id) + +#endif /* _DCN32_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c new file mode 100644 index 00000000000000..74412e5f03fefb --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c @@ -0,0 +1,2067 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright 2019 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 "dcn32/dcn32_init.h" + +#include "resource.h" +#include "include/irq_service_interface.h" +#include "dcn32/dcn32_resource.h" +#include "dcn321_resource.h" + +#include "dcn20/dcn20_resource.h" +#include "dcn30/dcn30_resource.h" + +#include "dml/dcn321/dcn321_fpu.h" + +#include "dcn10/dcn10_ipp.h" +#include "dcn30/dcn30_hubbub.h" +#include "dcn31/dcn31_hubbub.h" +#include "dcn32/dcn32_hubbub.h" +#include "dcn32/dcn32_mpc.h" +#include "dcn32/dcn32_hubp.h" +#include "irq/dcn32/irq_service_dcn32.h" +#include "dcn32/dcn32_dpp.h" +#include "dcn32/dcn32_optc.h" +#include "dcn20/dcn20_hwseq.h" +#include "dcn30/dcn30_hwseq.h" +#include "dce110/dce110_hwseq.h" +#include "dcn30/dcn30_opp.h" +#include "dcn20/dcn20_dsc.h" +#include "dcn30/dcn30_vpg.h" +#include "dcn30/dcn30_afmt.h" +#include "dcn30/dcn30_dio_stream_encoder.h" +#include "dcn32/dcn32_dio_stream_encoder.h" +#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 "dcn31/dcn31_apg.h" +#include "dcn31/dcn31_dio_link_encoder.h" +#include "dcn32/dcn32_dio_link_encoder.h" +#include "dcn321/dcn321_dio_link_encoder.h" +#include "dce/dce_clock_source.h" +#include "dce/dce_audio.h" +#include "dce/dce_hwseq.h" +#include "clk_mgr.h" +#include "virtual/virtual_stream_encoder.h" +#include "dml/display_mode_vba.h" +#include "dcn32/dcn32_dccg.h" +#include "dcn10/dcn10_resource.h" +#include "link.h" +#include "dcn31/dcn31_panel_cntl.h" + +#include "dcn30/dcn30_dwb.h" +#include "dcn32/dcn32_mmhubbub.h" + +#include "dcn/dcn_3_2_1_offset.h" +#include "dcn/dcn_3_2_1_sh_mask.h" +#include "nbio/nbio_4_3_0_offset.h" + +#include "reg_helper.h" +#include "dce/dmub_abm.h" +#include "dce/dmub_psr.h" +#include "dce/dce_aux.h" +#include "dce/dce_i2c.h" + +#include "dml/dcn30/display_mode_vba_30.h" +#include "vm_helper.h" +#include "dcn20/dcn20_vmid.h" + +#include "dc_state_priv.h" + +#define DC_LOGGER_INIT(logger) + +enum dcn321_clk_src_array_id { + DCN321_CLK_SRC_PLL0, + DCN321_CLK_SRC_PLL1, + DCN321_CLK_SRC_PLL2, + DCN321_CLK_SRC_PLL3, + DCN321_CLK_SRC_PLL4, + DCN321_CLK_SRC_TOTAL +}; + +/* begin ********************* + * macros to expend register list macro defined in HW object header file + */ + +/* DCN */ +#define BASE_INNER(seg) ctx->dcn_reg_offsets[seg] + +#define BASE(seg) BASE_INNER(seg) + +#define SR(reg_name)\ + REG_STRUCT.reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ + reg ## reg_name +#define SR_ARR(reg_name, id)\ + REG_STRUCT[id].reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ + reg ## reg_name +#define SR_ARR_INIT(reg_name, id, value)\ + REG_STRUCT[id].reg_name = value + +#define SRI(reg_name, block, id)\ + REG_STRUCT.reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRI_ARR(reg_name, block, id)\ + REG_STRUCT[id].reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SR_ARR_I2C(reg_name, id) \ + REG_STRUCT[id-1].reg_name = BASE(reg##reg_name##_BASE_IDX) + reg##reg_name + +#define SRI_ARR_I2C(reg_name, block, id)\ + REG_STRUCT[id-1].reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRI_ARR_ALPHABET(reg_name, block, index, id)\ + REG_STRUCT[index].reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRI2(reg_name, block, id)\ + .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ + reg ## reg_name +#define SRI2_ARR(reg_name, block, id)\ + REG_STRUCT[id].reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ + reg ## reg_name + +#define SRIR(var_name, reg_name, block, id)\ + .var_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRII(reg_name, block, id)\ + REG_STRUCT.reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRII_ARR_2(reg_name, block, id, inst)\ + REG_STRUCT[inst].reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRII_MPC_RMU(reg_name, block, id)\ + .RMU##_##reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRII_DWB(reg_name, temp_name, block, id)\ + REG_STRUCT.reg_name[id] = BASE(reg ## block ## id ## _ ## temp_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## temp_name + +#define DCCG_SRII(reg_name, block, id)\ + REG_STRUCT.block ## _ ## reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SF_DWB2(reg_name, block, id, field_name, post_fix) \ + .field_name = reg_name ## __ ## field_name ## post_fix + +#define VUPDATE_SRII(reg_name, block, id)\ + REG_STRUCT.reg_name[id] = BASE(reg ## reg_name ## _ ## block ## id ## _BASE_IDX) + \ + reg ## reg_name ## _ ## block ## id + +/* NBIO */ +#define NBIO_BASE_INNER(seg) ctx->nbio_reg_offsets[seg] + +#define NBIO_BASE(seg) \ + NBIO_BASE_INNER(seg) + +#define NBIO_SR(reg_name)\ + REG_STRUCT.reg_name = NBIO_BASE(regBIF_BX0_ ## reg_name ## _BASE_IDX) + \ + regBIF_BX0_ ## reg_name +#define NBIO_SR_ARR(reg_name, id)\ + REG_STRUCT[id].reg_name = NBIO_BASE(regBIF_BX0_ ## reg_name ## _BASE_IDX) + \ + regBIF_BX0_ ## reg_name + +#define CTX ctx +#define REG(reg_name) \ + (ctx->dcn_reg_offsets[reg ## reg_name ## _BASE_IDX] + reg ## reg_name) + +static struct bios_registers bios_regs; + +#define bios_regs_init() \ + ( \ + NBIO_SR(BIOS_SCRATCH_3),\ + NBIO_SR(BIOS_SCRATCH_6)\ + ) + +#define clk_src_regs_init(index, pllid)\ + CS_COMMON_REG_LIST_DCN3_0_RI(index, pllid) + +static struct dce110_clk_src_regs clk_src_regs[5]; + +static const struct dce110_clk_src_shift cs_shift = { + CS_COMMON_MASK_SH_LIST_DCN3_2(__SHIFT) +}; + +static const struct dce110_clk_src_mask cs_mask = { + CS_COMMON_MASK_SH_LIST_DCN3_2(_MASK) +}; + +#define abm_regs_init(id)\ + ABM_DCN32_REG_LIST_RI(id) + +static struct dce_abm_registers abm_regs[4]; + +static const struct dce_abm_shift abm_shift = { + ABM_MASK_SH_LIST_DCN32(__SHIFT) +}; + +static const struct dce_abm_mask abm_mask = { + ABM_MASK_SH_LIST_DCN32(_MASK) +}; + +#define audio_regs_init(id)\ + AUD_COMMON_REG_LIST_RI(id) + +static struct dce_audio_registers audio_regs[5]; + +#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ + AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) + +static const struct dce_audio_shift audio_shift = { + DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_audio_mask audio_mask = { + DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) +}; + +#define vpg_regs_init(id)\ + VPG_DCN3_REG_LIST_RI(id) + +static struct dcn30_vpg_registers vpg_regs[10]; + +static const struct dcn30_vpg_shift vpg_shift = { + DCN3_VPG_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn30_vpg_mask vpg_mask = { + DCN3_VPG_MASK_SH_LIST(_MASK) +}; + +#define afmt_regs_init(id)\ + AFMT_DCN3_REG_LIST_RI(id) + +static struct dcn30_afmt_registers afmt_regs[6]; + +static const struct dcn30_afmt_shift afmt_shift = { + DCN3_AFMT_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn30_afmt_mask afmt_mask = { + DCN3_AFMT_MASK_SH_LIST(_MASK) +}; + +#define apg_regs_init(id)\ + APG_DCN31_REG_LIST_RI(id) + +static struct dcn31_apg_registers apg_regs[4]; + +static const struct dcn31_apg_shift apg_shift = { + DCN31_APG_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn31_apg_mask apg_mask = { + DCN31_APG_MASK_SH_LIST(_MASK) +}; + +#define stream_enc_regs_init(id)\ + SE_DCN32_REG_LIST_RI(id) + +static struct dcn10_stream_enc_registers stream_enc_regs[5]; + +static const struct dcn10_stream_encoder_shift se_shift = { + SE_COMMON_MASK_SH_LIST_DCN32(__SHIFT) +}; + +static const struct dcn10_stream_encoder_mask se_mask = { + SE_COMMON_MASK_SH_LIST_DCN32(_MASK) +}; + + +#define aux_regs_init(id)\ + DCN2_AUX_REG_LIST_RI(id) + +static struct dcn10_link_enc_aux_registers link_enc_aux_regs[5]; + +#define hpd_regs_init(id)\ + HPD_REG_LIST_RI(id) + +static struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[5]; + +#define link_regs_init(id, phyid)\ + ( \ + LE_DCN31_REG_LIST_RI(id), \ + UNIPHY_DCN2_REG_LIST_RI(id, phyid)\ + ) + /*DPCS_DCN31_REG_LIST(id),*/ \ + +static struct dcn10_link_enc_registers link_enc_regs[5]; + +static const struct dcn10_link_enc_shift le_shift = { + LINK_ENCODER_MASK_SH_LIST_DCN31(__SHIFT), \ +// DPCS_DCN31_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn10_link_enc_mask le_mask = { + LINK_ENCODER_MASK_SH_LIST_DCN31(_MASK), \ +// DPCS_DCN31_MASK_SH_LIST(_MASK) +}; + +#define hpo_dp_stream_encoder_reg_init(id)\ + DCN3_1_HPO_DP_STREAM_ENC_REG_LIST_RI(id) + +static struct dcn31_hpo_dp_stream_encoder_registers hpo_dp_stream_enc_regs[4]; + +static const struct dcn31_hpo_dp_stream_encoder_shift hpo_dp_se_shift = { + DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn31_hpo_dp_stream_encoder_mask hpo_dp_se_mask = { + DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(_MASK) +}; + + +#define hpo_dp_link_encoder_reg_init(id)\ + DCN3_1_HPO_DP_LINK_ENC_REG_LIST_RI(id) + /*DCN3_1_RDPCSTX_REG_LIST(0),*/ + /*DCN3_1_RDPCSTX_REG_LIST(1),*/ + /*DCN3_1_RDPCSTX_REG_LIST(2),*/ + /*DCN3_1_RDPCSTX_REG_LIST(3),*/ + +static struct dcn31_hpo_dp_link_encoder_registers hpo_dp_link_enc_regs[2]; + +static const struct dcn31_hpo_dp_link_encoder_shift hpo_dp_le_shift = { + DCN3_2_HPO_DP_LINK_ENC_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn31_hpo_dp_link_encoder_mask hpo_dp_le_mask = { + DCN3_2_HPO_DP_LINK_ENC_MASK_SH_LIST(_MASK) +}; + +#define dpp_regs_init(id)\ + DPP_REG_LIST_DCN30_COMMON_RI(id) + +static struct dcn3_dpp_registers dpp_regs[4]; + +static const struct dcn3_dpp_shift tf_shift = { + DPP_REG_LIST_SH_MASK_DCN30_COMMON(__SHIFT) +}; + +static const struct dcn3_dpp_mask tf_mask = { + DPP_REG_LIST_SH_MASK_DCN30_COMMON(_MASK) +}; + + +#define opp_regs_init(id)\ + OPP_REG_LIST_DCN30_RI(id) + +static struct dcn20_opp_registers opp_regs[4]; + +static const struct dcn20_opp_shift opp_shift = { + OPP_MASK_SH_LIST_DCN20(__SHIFT) +}; + +static const struct dcn20_opp_mask opp_mask = { + OPP_MASK_SH_LIST_DCN20(_MASK) +}; + +#define aux_engine_regs_init(id) \ + ( \ + AUX_COMMON_REG_LIST0_RI(id), SR_ARR_INIT(AUXN_IMPCAL, id, 0), \ + SR_ARR_INIT(AUXP_IMPCAL, id, 0), \ + SR_ARR_INIT(AUX_RESET_MASK, id, DP_AUX0_AUX_CONTROL__AUX_RESET_MASK), \ + SR_ARR_INIT(AUX_RESET_MASK, id, DP_AUX0_AUX_CONTROL__AUX_RESET_MASK)\ + ) + +static struct dce110_aux_registers aux_engine_regs[5]; + +static const struct dce110_aux_registers_shift aux_shift = { + DCN_AUX_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce110_aux_registers_mask aux_mask = { + DCN_AUX_MASK_SH_LIST(_MASK) +}; + +#define dwbc_regs_dcn3_init(id)\ + DWBC_COMMON_REG_LIST_DCN30_RI(id) + +static struct dcn30_dwbc_registers dwbc30_regs[1]; + +static const struct dcn30_dwbc_shift dwbc30_shift = { + DWBC_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dcn30_dwbc_mask dwbc30_mask = { + DWBC_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +#define mcif_wb_regs_dcn3_init(id)\ + MCIF_WB_COMMON_REG_LIST_DCN32_RI(id) + +static struct dcn30_mmhubbub_registers mcif_wb30_regs[1]; + +static const struct dcn30_mmhubbub_shift mcif_wb30_shift = { + MCIF_WB_COMMON_MASK_SH_LIST_DCN32(__SHIFT) +}; + +static const struct dcn30_mmhubbub_mask mcif_wb30_mask = { + MCIF_WB_COMMON_MASK_SH_LIST_DCN32(_MASK) +}; + +#define dsc_regsDCN20_init(id)\ + DSC_REG_LIST_DCN20_RI(id) + +static struct dcn20_dsc_registers dsc_regs[4]; + +static const struct dcn20_dsc_shift dsc_shift = { + DSC_REG_LIST_SH_MASK_DCN20(__SHIFT) +}; + +static const struct dcn20_dsc_mask dsc_mask = { + DSC_REG_LIST_SH_MASK_DCN20(_MASK) +}; + +static struct dcn30_mpc_registers mpc_regs; +#define dcn_mpc_regs_init()\ + MPC_REG_LIST_DCN3_2_RI(0),\ + MPC_REG_LIST_DCN3_2_RI(1),\ + MPC_REG_LIST_DCN3_2_RI(2),\ + MPC_REG_LIST_DCN3_2_RI(3),\ + MPC_OUT_MUX_REG_LIST_DCN3_0_RI(0),\ + MPC_OUT_MUX_REG_LIST_DCN3_0_RI(1),\ + MPC_OUT_MUX_REG_LIST_DCN3_0_RI(2),\ + MPC_OUT_MUX_REG_LIST_DCN3_0_RI(3),\ + MPC_DWB_MUX_REG_LIST_DCN3_0_RI(0) + +static const struct dcn30_mpc_shift mpc_shift = { + MPC_COMMON_MASK_SH_LIST_DCN32(__SHIFT) +}; + +static const struct dcn30_mpc_mask mpc_mask = { + MPC_COMMON_MASK_SH_LIST_DCN32(_MASK) +}; + +#define optc_regs_init(id)\ + OPTC_COMMON_REG_LIST_DCN3_2_RI(id) + +static struct dcn_optc_registers optc_regs[4]; + +static const struct dcn_optc_shift optc_shift = { + OPTC_COMMON_MASK_SH_LIST_DCN3_2(__SHIFT) +}; + +static const struct dcn_optc_mask optc_mask = { + OPTC_COMMON_MASK_SH_LIST_DCN3_2(_MASK) +}; + +#define hubp_regs_init(id) \ + HUBP_REG_LIST_DCN32_RI(id) + +static struct dcn_hubp2_registers hubp_regs[4]; + +static const struct dcn_hubp2_shift hubp_shift = { + HUBP_MASK_SH_LIST_DCN32(__SHIFT) +}; + +static const struct dcn_hubp2_mask hubp_mask = { + HUBP_MASK_SH_LIST_DCN32(_MASK) +}; + +static struct dcn_hubbub_registers hubbub_reg; +#define hubbub_reg_init()\ + HUBBUB_REG_LIST_DCN32_RI(0) + +static const struct dcn_hubbub_shift hubbub_shift = { + HUBBUB_MASK_SH_LIST_DCN32(__SHIFT) +}; + +static const struct dcn_hubbub_mask hubbub_mask = { + HUBBUB_MASK_SH_LIST_DCN32(_MASK) +}; + +static struct dccg_registers dccg_regs; + +#define dccg_regs_init()\ + DCCG_REG_LIST_DCN32_RI() + +static const struct dccg_shift dccg_shift = { + DCCG_MASK_SH_LIST_DCN32(__SHIFT) +}; + +static const struct dccg_mask dccg_mask = { + DCCG_MASK_SH_LIST_DCN32(_MASK) +}; + + +#define SRII2(reg_name_pre, reg_name_post, id)\ + .reg_name_pre ## _ ## reg_name_post[id] = BASE(reg ## reg_name_pre \ + ## id ## _ ## reg_name_post ## _BASE_IDX) + \ + reg ## reg_name_pre ## id ## _ ## reg_name_post + + +#define HWSEQ_DCN32_REG_LIST()\ + SR(DCHUBBUB_GLOBAL_TIMER_CNTL), \ + SR(DIO_MEM_PWR_CTRL), \ + SR(ODM_MEM_PWR_CTRL3), \ + SR(MMHUBBUB_MEM_PWR_CNTL), \ + SR(DCCG_GATE_DISABLE_CNTL), \ + SR(DCCG_GATE_DISABLE_CNTL2), \ + SR(DCFCLK_CNTL),\ + SR(DC_MEM_GLOBAL_PWR_REQ_CNTL), \ + SRII(PIXEL_RATE_CNTL, OTG, 0), \ + SRII(PIXEL_RATE_CNTL, OTG, 1),\ + SRII(PIXEL_RATE_CNTL, OTG, 2),\ + SRII(PIXEL_RATE_CNTL, OTG, 3),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 0),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 1),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 2),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 3),\ + SR(MICROSECOND_TIME_BASE_DIV), \ + SR(MILLISECOND_TIME_BASE_DIV), \ + SR(DISPCLK_FREQ_CHANGE_CNTL), \ + SR(RBBMIF_TIMEOUT_DIS), \ + SR(RBBMIF_TIMEOUT_DIS_2), \ + SR(DCHUBBUB_CRC_CTRL), \ + SR(DPP_TOP0_DPP_CRC_CTRL), \ + SR(DPP_TOP0_DPP_CRC_VAL_B_A), \ + SR(DPP_TOP0_DPP_CRC_VAL_R_G), \ + SR(MPC_CRC_CTRL), \ + SR(MPC_CRC_RESULT_GB), \ + SR(MPC_CRC_RESULT_C), \ + SR(MPC_CRC_RESULT_AR), \ + SR(DOMAIN0_PG_CONFIG), \ + SR(DOMAIN1_PG_CONFIG), \ + SR(DOMAIN2_PG_CONFIG), \ + SR(DOMAIN3_PG_CONFIG), \ + SR(DOMAIN16_PG_CONFIG), \ + SR(DOMAIN17_PG_CONFIG), \ + SR(DOMAIN18_PG_CONFIG), \ + SR(DOMAIN19_PG_CONFIG), \ + SR(DOMAIN0_PG_STATUS), \ + SR(DOMAIN1_PG_STATUS), \ + SR(DOMAIN2_PG_STATUS), \ + SR(DOMAIN3_PG_STATUS), \ + SR(DOMAIN16_PG_STATUS), \ + SR(DOMAIN17_PG_STATUS), \ + SR(DOMAIN18_PG_STATUS), \ + SR(DOMAIN19_PG_STATUS), \ + SR(D1VGA_CONTROL), \ + SR(D2VGA_CONTROL), \ + SR(D3VGA_CONTROL), \ + SR(D4VGA_CONTROL), \ + SR(D5VGA_CONTROL), \ + SR(D6VGA_CONTROL), \ + SR(DC_IP_REQUEST_CNTL), \ + SR(AZALIA_AUDIO_DTO), \ + SR(AZALIA_CONTROLLER_CLOCK_GATING) + +static struct dce_hwseq_registers hwseq_reg; + +#define hwseq_reg_init()\ + HWSEQ_DCN32_REG_LIST() + +#define HWSEQ_DCN32_MASK_SH_LIST(mask_sh)\ + HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ + HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \ + HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN19_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN19_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN16_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN17_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN18_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN19_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \ + HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh), \ + HWS_SF(, HPO_TOP_CLOCK_CONTROL, HPO_HDMISTREAMCLK_G_GATE_DIS, mask_sh), \ + HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_UNASSIGNED_PWR_MODE, mask_sh), \ + HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_VBLANK_PWR_MODE, mask_sh), \ + HWS_SF(, MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, mask_sh) + +static const struct dce_hwseq_shift hwseq_shift = { + HWSEQ_DCN32_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_hwseq_mask hwseq_mask = { + HWSEQ_DCN32_MASK_SH_LIST(_MASK) +}; +#define vmid_regs_init(id)\ + DCN20_VMID_REG_LIST_RI(id) + +static struct dcn_vmid_registers vmid_regs[16]; + +static const struct dcn20_vmid_shift vmid_shifts = { + DCN20_VMID_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn20_vmid_mask vmid_masks = { + DCN20_VMID_MASK_SH_LIST(_MASK) +}; + +static const struct resource_caps res_cap_dcn321 = { + .num_timing_generator = 4, + .num_opp = 4, + .num_video_plane = 4, + .num_audio = 5, + .num_stream_encoder = 5, + .num_hpo_dp_stream_encoder = 4, + .num_hpo_dp_link_encoder = 2, + .num_pll = 5, + .num_dwb = 1, + .num_ddc = 5, + .num_vmid = 16, + .num_mpc_3dlut = 4, + .num_dsc = 4, +}; + +static const struct dc_plane_cap plane_cap = { + .type = DC_PLANE_TYPE_DCN_UNIVERSAL, + .per_pixel_alpha = true, + + .pixel_format_support = { + .argb8888 = true, + .nv12 = true, + .fp16 = true, + .p010 = true, + .ayuv = false, + }, + + .max_upscale_factor = { + .argb8888 = 16000, + .nv12 = 16000, + .fp16 = 16000 + }, + + // 6:1 downscaling ratio: 1000/6 = 166.666 + .max_downscale_factor = { + .argb8888 = 167, + .nv12 = 167, + .fp16 = 167 + }, + 64, + 64 +}; + +static const struct dc_debug_options debug_defaults_drv = { + .disable_dmcu = true, + .force_abm_enable = false, + .timing_trace = false, + .clock_trace = true, + .disable_pplib_clock_request = false, + .pipe_split_policy = MPC_SPLIT_AVOID, + .force_single_disp_pipe_split = false, + .disable_dcc = DCC_ENABLE, + .vsr_support = true, + .performance_trace = false, + .max_downscale_src_width = 7680,/*upto 8K*/ + .disable_pplib_wm_range = false, + .scl_reset_length10 = true, + .sanity_checks = false, + .underflow_assert_delay_us = 0xFFFFFFFF, + .dwb_fi_phase = -1, // -1 = disable, + .dmub_command_table = true, + .enable_mem_low_power = { + .bits = { + .vga = false, + .i2c = false, + .dmcu = false, // This is previously known to cause hang on S3 cycles if enabled + .dscl = false, + .cm = false, + .mpc = false, + .optc = true, + } + }, + .use_max_lb = true, + .force_disable_subvp = false, + .exit_idle_opt_for_cursor_updates = true, + .enable_single_display_2to1_odm_policy = true, + + /*must match enable_single_display_2to1_odm_policy to support dynamic ODM transitions*/ + .enable_double_buffered_dsc_pg_support = true, + .enable_dp_dig_pixel_rate_div_policy = 1, + .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, + .override_dispclk_programming = true, + .disable_fpo_optimizations = false, + .fpo_vactive_margin_us = 2000, // 2000us + .disable_fpo_vactive = false, + .disable_boot_optimizations = false, + .disable_subvp_high_refresh = false, + .fpo_vactive_min_active_margin_us = 200, + .fpo_vactive_max_blank_us = 1000, + .enable_legacy_fast_update = false, + .disable_dc_mode_overwrite = true, + .using_dml2 = false, +}; + +static struct dce_aux *dcn321_aux_engine_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct aux_engine_dce110 *aux_engine = + kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); + + if (!aux_engine) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT aux_engine_regs + aux_engine_regs_init(0), + aux_engine_regs_init(1), + aux_engine_regs_init(2), + aux_engine_regs_init(3), + aux_engine_regs_init(4); + + dce110_aux_engine_construct(aux_engine, ctx, inst, + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, + &aux_engine_regs[inst], + &aux_mask, + &aux_shift, + ctx->dc->caps.extended_aux_timeout_support); + + return &aux_engine->base; +} +#define i2c_inst_regs_init(id)\ + I2C_HW_ENGINE_COMMON_REG_LIST_DCN30_RI(id) + +static struct dce_i2c_registers i2c_hw_regs[5]; + +static const struct dce_i2c_shift i2c_shifts = { + I2C_COMMON_MASK_SH_LIST_DCN30(__SHIFT) +}; + +static const struct dce_i2c_mask i2c_masks = { + I2C_COMMON_MASK_SH_LIST_DCN30(_MASK) +}; + +static struct dce_i2c_hw *dcn321_i2c_hw_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce_i2c_hw *dce_i2c_hw = + kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); + + if (!dce_i2c_hw) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT i2c_hw_regs + i2c_inst_regs_init(1), + i2c_inst_regs_init(2), + i2c_inst_regs_init(3), + i2c_inst_regs_init(4), + i2c_inst_regs_init(5); + + dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst, + &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); + + return dce_i2c_hw; +} + +static struct clock_source *dcn321_clock_source_create( + struct dc_context *ctx, + struct dc_bios *bios, + enum clock_source_id id, + const struct dce110_clk_src_regs *regs, + bool dp_clk_src) +{ + struct dce110_clk_src *clk_src = + kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); + + if (!clk_src) + return NULL; + + if (dcn31_clk_src_construct(clk_src, ctx, bios, id, + regs, &cs_shift, &cs_mask)) { + clk_src->base.dp_clk_src = dp_clk_src; + return &clk_src->base; + } + + kfree(clk_src); + BREAK_TO_DEBUGGER(); + return NULL; +} + +static struct hubbub *dcn321_hubbub_create(struct dc_context *ctx) +{ + int i; + + struct dcn20_hubbub *hubbub2 = kzalloc(sizeof(struct dcn20_hubbub), + GFP_KERNEL); + + if (!hubbub2) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT hubbub_reg + hubbub_reg_init(); + +#undef REG_STRUCT +#define REG_STRUCT vmid_regs + vmid_regs_init(0), + vmid_regs_init(1), + vmid_regs_init(2), + vmid_regs_init(3), + vmid_regs_init(4), + vmid_regs_init(5), + vmid_regs_init(6), + vmid_regs_init(7), + vmid_regs_init(8), + vmid_regs_init(9), + vmid_regs_init(10), + vmid_regs_init(11), + vmid_regs_init(12), + vmid_regs_init(13), + vmid_regs_init(14), + vmid_regs_init(15); + + hubbub32_construct(hubbub2, ctx, + &hubbub_reg, + &hubbub_shift, + &hubbub_mask, + ctx->dc->dml.ip.det_buffer_size_kbytes, + ctx->dc->dml.ip.pixel_chunk_size_kbytes, + ctx->dc->dml.ip.config_return_buffer_size_in_kbytes); + + + for (i = 0; i < res_cap_dcn321.num_vmid; i++) { + struct dcn20_vmid *vmid = &hubbub2->vmid[i]; + + vmid->ctx = ctx; + + vmid->regs = &vmid_regs[i]; + vmid->shifts = &vmid_shifts; + vmid->masks = &vmid_masks; + } + + return &hubbub2->base; +} + +static struct hubp *dcn321_hubp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn20_hubp *hubp2 = + kzalloc(sizeof(struct dcn20_hubp), GFP_KERNEL); + + if (!hubp2) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT hubp_regs + hubp_regs_init(0), + hubp_regs_init(1), + hubp_regs_init(2), + hubp_regs_init(3); + + if (hubp32_construct(hubp2, ctx, inst, + &hubp_regs[inst], &hubp_shift, &hubp_mask)) + return &hubp2->base; + + BREAK_TO_DEBUGGER(); + kfree(hubp2); + return NULL; +} + +static void dcn321_dpp_destroy(struct dpp **dpp) +{ + kfree(TO_DCN30_DPP(*dpp)); + *dpp = NULL; +} + +static struct dpp *dcn321_dpp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn3_dpp *dpp3 = + kzalloc(sizeof(struct dcn3_dpp), GFP_KERNEL); + + if (!dpp3) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT dpp_regs + dpp_regs_init(0), + dpp_regs_init(1), + dpp_regs_init(2), + dpp_regs_init(3); + + if (dpp32_construct(dpp3, ctx, inst, + &dpp_regs[inst], &tf_shift, &tf_mask)) + return &dpp3->base; + + BREAK_TO_DEBUGGER(); + kfree(dpp3); + return NULL; +} + +static struct mpc *dcn321_mpc_create( + struct dc_context *ctx, + int num_mpcc, + int num_rmu) +{ + struct dcn30_mpc *mpc30 = kzalloc(sizeof(struct dcn30_mpc), + GFP_KERNEL); + + if (!mpc30) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT mpc_regs + dcn_mpc_regs_init(); + + dcn32_mpc_construct(mpc30, ctx, + &mpc_regs, + &mpc_shift, + &mpc_mask, + num_mpcc, + num_rmu); + + return &mpc30->base; +} + +static struct output_pixel_processor *dcn321_opp_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dcn20_opp *opp2 = + kzalloc(sizeof(struct dcn20_opp), GFP_KERNEL); + + if (!opp2) { + BREAK_TO_DEBUGGER(); + return NULL; + } + +#undef REG_STRUCT +#define REG_STRUCT opp_regs + opp_regs_init(0), + opp_regs_init(1), + opp_regs_init(2), + opp_regs_init(3); + + dcn20_opp_construct(opp2, ctx, inst, + &opp_regs[inst], &opp_shift, &opp_mask); + return &opp2->base; +} + + +static struct timing_generator *dcn321_timing_generator_create( + struct dc_context *ctx, + uint32_t instance) +{ + struct optc *tgn10 = + kzalloc(sizeof(struct optc), GFP_KERNEL); + + if (!tgn10) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT optc_regs + optc_regs_init(0), + optc_regs_init(1), + optc_regs_init(2), + optc_regs_init(3); + + tgn10->base.inst = instance; + tgn10->base.ctx = ctx; + + tgn10->tg_regs = &optc_regs[instance]; + tgn10->tg_shift = &optc_shift; + tgn10->tg_mask = &optc_mask; + + dcn32_timing_generator_init(tgn10); + + return &tgn10->base; +} + +static const struct encoder_feature_support link_enc_feature = { + .max_hdmi_deep_color = COLOR_DEPTH_121212, + .max_hdmi_pixel_clock = 600000, + .hdmi_ycbcr420_supported = true, + .dp_ycbcr420_supported = true, + .fec_supported = true, + .flags.bits.IS_HBR2_CAPABLE = true, + .flags.bits.IS_HBR3_CAPABLE = true, + .flags.bits.IS_TPS3_CAPABLE = true, + .flags.bits.IS_TPS4_CAPABLE = true +}; + +static struct link_encoder *dcn321_link_encoder_create( + struct dc_context *ctx, + const struct encoder_init_data *enc_init_data) +{ + struct dcn20_link_encoder *enc20 = + kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); + + if (!enc20) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT link_enc_aux_regs + aux_regs_init(0), + aux_regs_init(1), + aux_regs_init(2), + aux_regs_init(3), + aux_regs_init(4); + +#undef REG_STRUCT +#define REG_STRUCT link_enc_hpd_regs + hpd_regs_init(0), + hpd_regs_init(1), + hpd_regs_init(2), + hpd_regs_init(3), + hpd_regs_init(4); + +#undef REG_STRUCT +#define REG_STRUCT link_enc_regs + link_regs_init(0, A), + link_regs_init(1, B), + link_regs_init(2, C), + link_regs_init(3, D), + link_regs_init(4, E); + + dcn321_link_encoder_construct(enc20, + enc_init_data, + &link_enc_feature, + &link_enc_regs[enc_init_data->transmitter], + &link_enc_aux_regs[enc_init_data->channel - 1], + &link_enc_hpd_regs[enc_init_data->hpd_source], + &le_shift, + &le_mask); + + return &enc20->enc10.base; +} + +static void read_dce_straps( + struct dc_context *ctx, + struct resource_straps *straps) +{ + generic_reg_get(ctx, ctx->dcn_reg_offsets[regDC_PINSTRAPS_BASE_IDX] + regDC_PINSTRAPS, + FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio); + +} + +static struct audio *dcn321_create_audio( + struct dc_context *ctx, unsigned int inst) +{ + +#undef REG_STRUCT +#define REG_STRUCT audio_regs + audio_regs_init(0), + audio_regs_init(1), + audio_regs_init(2), + audio_regs_init(3), + audio_regs_init(4); + + return dce_audio_create(ctx, inst, + &audio_regs[inst], &audio_shift, &audio_mask); +} + +static struct vpg *dcn321_vpg_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn30_vpg *vpg3 = kzalloc(sizeof(struct dcn30_vpg), GFP_KERNEL); + + if (!vpg3) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT vpg_regs + vpg_regs_init(0), + vpg_regs_init(1), + vpg_regs_init(2), + vpg_regs_init(3), + vpg_regs_init(4), + vpg_regs_init(5), + vpg_regs_init(6), + vpg_regs_init(7), + vpg_regs_init(8), + vpg_regs_init(9); + + vpg3_construct(vpg3, ctx, inst, + &vpg_regs[inst], + &vpg_shift, + &vpg_mask); + + return &vpg3->base; +} + +static struct afmt *dcn321_afmt_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn30_afmt *afmt3 = kzalloc(sizeof(struct dcn30_afmt), GFP_KERNEL); + + if (!afmt3) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT afmt_regs + afmt_regs_init(0), + afmt_regs_init(1), + afmt_regs_init(2), + afmt_regs_init(3), + afmt_regs_init(4), + afmt_regs_init(5); + + afmt3_construct(afmt3, ctx, inst, + &afmt_regs[inst], + &afmt_shift, + &afmt_mask); + + return &afmt3->base; +} + +static struct apg *dcn321_apg_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn31_apg *apg31 = kzalloc(sizeof(struct dcn31_apg), GFP_KERNEL); + + if (!apg31) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT apg_regs + apg_regs_init(0), + apg_regs_init(1), + apg_regs_init(2), + apg_regs_init(3); + + apg31_construct(apg31, ctx, inst, + &apg_regs[inst], + &apg_shift, + &apg_mask); + + return &apg31->base; +} + +static struct stream_encoder *dcn321_stream_encoder_create( + enum engine_id eng_id, + struct dc_context *ctx) +{ + struct dcn10_stream_encoder *enc1; + struct vpg *vpg; + struct afmt *afmt; + int vpg_inst; + int afmt_inst; + + /* Mapping of VPG, AFMT, DME register blocks to DIO block instance */ + if (eng_id <= ENGINE_ID_DIGF) { + vpg_inst = eng_id; + afmt_inst = eng_id; + } else + return NULL; + + enc1 = kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL); + vpg = dcn321_vpg_create(ctx, vpg_inst); + afmt = dcn321_afmt_create(ctx, afmt_inst); + + if (!enc1 || !vpg || !afmt) { + kfree(enc1); + kfree(vpg); + kfree(afmt); + return NULL; + } + +#undef REG_STRUCT +#define REG_STRUCT stream_enc_regs + stream_enc_regs_init(0), + stream_enc_regs_init(1), + stream_enc_regs_init(2), + stream_enc_regs_init(3), + stream_enc_regs_init(4); + + dcn32_dio_stream_encoder_construct(enc1, ctx, ctx->dc_bios, + eng_id, vpg, afmt, + &stream_enc_regs[eng_id], + &se_shift, &se_mask); + + return &enc1->base; +} + +static struct hpo_dp_stream_encoder *dcn321_hpo_dp_stream_encoder_create( + enum engine_id eng_id, + struct dc_context *ctx) +{ + struct dcn31_hpo_dp_stream_encoder *hpo_dp_enc31; + struct vpg *vpg; + struct apg *apg; + uint32_t hpo_dp_inst; + uint32_t vpg_inst; + uint32_t apg_inst; + + ASSERT((eng_id >= ENGINE_ID_HPO_DP_0) && (eng_id <= ENGINE_ID_HPO_DP_3)); + hpo_dp_inst = eng_id - ENGINE_ID_HPO_DP_0; + + /* Mapping of VPG register blocks to HPO DP block instance: + * VPG[6] -> HPO_DP[0] + * VPG[7] -> HPO_DP[1] + * VPG[8] -> HPO_DP[2] + * VPG[9] -> HPO_DP[3] + */ + vpg_inst = hpo_dp_inst + 6; + + /* Mapping of APG register blocks to HPO DP block instance: + * APG[0] -> HPO_DP[0] + * APG[1] -> HPO_DP[1] + * APG[2] -> HPO_DP[2] + * APG[3] -> HPO_DP[3] + */ + apg_inst = hpo_dp_inst; + + /* allocate HPO stream encoder and create VPG sub-block */ + hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_stream_encoder), GFP_KERNEL); + vpg = dcn321_vpg_create(ctx, vpg_inst); + apg = dcn321_apg_create(ctx, apg_inst); + + if (!hpo_dp_enc31 || !vpg || !apg) { + kfree(hpo_dp_enc31); + kfree(vpg); + kfree(apg); + return NULL; + } + +#undef REG_STRUCT +#define REG_STRUCT hpo_dp_stream_enc_regs + hpo_dp_stream_encoder_reg_init(0), + hpo_dp_stream_encoder_reg_init(1), + hpo_dp_stream_encoder_reg_init(2), + hpo_dp_stream_encoder_reg_init(3); + + dcn31_hpo_dp_stream_encoder_construct(hpo_dp_enc31, ctx, ctx->dc_bios, + hpo_dp_inst, eng_id, vpg, apg, + &hpo_dp_stream_enc_regs[hpo_dp_inst], + &hpo_dp_se_shift, &hpo_dp_se_mask); + + return &hpo_dp_enc31->base; +} + +static struct hpo_dp_link_encoder *dcn321_hpo_dp_link_encoder_create( + uint8_t inst, + struct dc_context *ctx) +{ + struct dcn31_hpo_dp_link_encoder *hpo_dp_enc31; + + /* allocate HPO link encoder */ + hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_link_encoder), GFP_KERNEL); + +#undef REG_STRUCT +#define REG_STRUCT hpo_dp_link_enc_regs + hpo_dp_link_encoder_reg_init(0), + hpo_dp_link_encoder_reg_init(1); + + hpo_dp_link_encoder32_construct(hpo_dp_enc31, ctx, inst, + &hpo_dp_link_enc_regs[inst], + &hpo_dp_le_shift, &hpo_dp_le_mask); + + return &hpo_dp_enc31->base; +} + +static struct dce_hwseq *dcn321_hwseq_create( + struct dc_context *ctx) +{ + struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); + +#undef REG_STRUCT +#define REG_STRUCT hwseq_reg + hwseq_reg_init(); + + if (hws) { + hws->ctx = ctx; + hws->regs = &hwseq_reg; + hws->shifts = &hwseq_shift; + hws->masks = &hwseq_mask; + } + return hws; +} +static const struct resource_create_funcs res_create_funcs = { + .read_dce_straps = read_dce_straps, + .create_audio = dcn321_create_audio, + .create_stream_encoder = dcn321_stream_encoder_create, + .create_hpo_dp_stream_encoder = dcn321_hpo_dp_stream_encoder_create, + .create_hpo_dp_link_encoder = dcn321_hpo_dp_link_encoder_create, + .create_hwseq = dcn321_hwseq_create, +}; + +static void dcn321_resource_destruct(struct dcn321_resource_pool *pool) +{ + unsigned int i; + + for (i = 0; i < pool->base.stream_enc_count; i++) { + if (pool->base.stream_enc[i] != NULL) { + if (pool->base.stream_enc[i]->vpg != NULL) { + kfree(DCN30_VPG_FROM_VPG(pool->base.stream_enc[i]->vpg)); + pool->base.stream_enc[i]->vpg = NULL; + } + if (pool->base.stream_enc[i]->afmt != NULL) { + kfree(DCN30_AFMT_FROM_AFMT(pool->base.stream_enc[i]->afmt)); + pool->base.stream_enc[i]->afmt = NULL; + } + kfree(DCN10STRENC_FROM_STRENC(pool->base.stream_enc[i])); + pool->base.stream_enc[i] = NULL; + } + } + + for (i = 0; i < pool->base.hpo_dp_stream_enc_count; i++) { + if (pool->base.hpo_dp_stream_enc[i] != NULL) { + if (pool->base.hpo_dp_stream_enc[i]->vpg != NULL) { + kfree(DCN30_VPG_FROM_VPG(pool->base.hpo_dp_stream_enc[i]->vpg)); + pool->base.hpo_dp_stream_enc[i]->vpg = NULL; + } + if (pool->base.hpo_dp_stream_enc[i]->apg != NULL) { + kfree(DCN31_APG_FROM_APG(pool->base.hpo_dp_stream_enc[i]->apg)); + pool->base.hpo_dp_stream_enc[i]->apg = NULL; + } + kfree(DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(pool->base.hpo_dp_stream_enc[i])); + pool->base.hpo_dp_stream_enc[i] = NULL; + } + } + + for (i = 0; i < pool->base.hpo_dp_link_enc_count; i++) { + if (pool->base.hpo_dp_link_enc[i] != NULL) { + kfree(DCN3_1_HPO_DP_LINK_ENC_FROM_HPO_LINK_ENC(pool->base.hpo_dp_link_enc[i])); + pool->base.hpo_dp_link_enc[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_dsc; i++) { + if (pool->base.dscs[i] != NULL) + dcn20_dsc_destroy(&pool->base.dscs[i]); + } + + if (pool->base.mpc != NULL) { + kfree(TO_DCN20_MPC(pool->base.mpc)); + pool->base.mpc = NULL; + } + if (pool->base.hubbub != NULL) { + kfree(TO_DCN20_HUBBUB(pool->base.hubbub)); + pool->base.hubbub = NULL; + } + for (i = 0; i < pool->base.pipe_count; i++) { + if (pool->base.dpps[i] != NULL) + dcn321_dpp_destroy(&pool->base.dpps[i]); + + if (pool->base.ipps[i] != NULL) + pool->base.ipps[i]->funcs->ipp_destroy(&pool->base.ipps[i]); + + if (pool->base.hubps[i] != NULL) { + kfree(TO_DCN20_HUBP(pool->base.hubps[i])); + pool->base.hubps[i] = NULL; + } + + if (pool->base.irqs != NULL) + dal_irq_service_destroy(&pool->base.irqs); + } + + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + if (pool->base.engines[i] != NULL) + dce110_engine_destroy(&pool->base.engines[i]); + if (pool->base.hw_i2cs[i] != NULL) { + kfree(pool->base.hw_i2cs[i]); + pool->base.hw_i2cs[i] = NULL; + } + if (pool->base.sw_i2cs[i] != NULL) { + kfree(pool->base.sw_i2cs[i]); + pool->base.sw_i2cs[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_opp; i++) { + if (pool->base.opps[i] != NULL) + pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]); + } + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + if (pool->base.timing_generators[i] != NULL) { + kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i])); + pool->base.timing_generators[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_dwb; i++) { + if (pool->base.dwbc[i] != NULL) { + kfree(TO_DCN30_DWBC(pool->base.dwbc[i])); + pool->base.dwbc[i] = NULL; + } + if (pool->base.mcif_wb[i] != NULL) { + kfree(TO_DCN30_MMHUBBUB(pool->base.mcif_wb[i])); + pool->base.mcif_wb[i] = NULL; + } + } + + for (i = 0; i < pool->base.audio_count; i++) { + if (pool->base.audios[i]) + dce_aud_destroy(&pool->base.audios[i]); + } + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] != NULL) { + dcn20_clock_source_destroy(&pool->base.clock_sources[i]); + pool->base.clock_sources[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_mpc_3dlut; i++) { + if (pool->base.mpc_lut[i] != NULL) { + dc_3dlut_func_release(pool->base.mpc_lut[i]); + pool->base.mpc_lut[i] = NULL; + } + if (pool->base.mpc_shaper[i] != NULL) { + dc_transfer_func_release(pool->base.mpc_shaper[i]); + pool->base.mpc_shaper[i] = NULL; + } + } + + if (pool->base.dp_clock_source != NULL) { + dcn20_clock_source_destroy(&pool->base.dp_clock_source); + pool->base.dp_clock_source = NULL; + } + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + if (pool->base.multiple_abms[i] != NULL) + dce_abm_destroy(&pool->base.multiple_abms[i]); + } + + if (pool->base.psr != NULL) + dmub_psr_destroy(&pool->base.psr); + + if (pool->base.dccg != NULL) + dcn_dccg_destroy(&pool->base.dccg); + + if (pool->base.oem_device != NULL) { + struct dc *dc = pool->base.oem_device->ctx->dc; + + dc->link_srv->destroy_ddc_service(&pool->base.oem_device); + } +} + + +static bool dcn321_dwbc_create(struct dc_context *ctx, struct resource_pool *pool) +{ + int i; + uint32_t dwb_count = pool->res_cap->num_dwb; + + for (i = 0; i < dwb_count; i++) { + struct dcn30_dwbc *dwbc30 = kzalloc(sizeof(struct dcn30_dwbc), + GFP_KERNEL); + + if (!dwbc30) { + dm_error("DC: failed to create dwbc30!\n"); + return false; + } + +#undef REG_STRUCT +#define REG_STRUCT dwbc30_regs + dwbc_regs_dcn3_init(0); + + dcn30_dwbc_construct(dwbc30, ctx, + &dwbc30_regs[i], + &dwbc30_shift, + &dwbc30_mask, + i); + + pool->dwbc[i] = &dwbc30->base; + } + return true; +} + +static bool dcn321_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool) +{ + int i; + uint32_t dwb_count = pool->res_cap->num_dwb; + + for (i = 0; i < dwb_count; i++) { + struct dcn30_mmhubbub *mcif_wb30 = kzalloc(sizeof(struct dcn30_mmhubbub), + GFP_KERNEL); + + if (!mcif_wb30) { + dm_error("DC: failed to create mcif_wb30!\n"); + return false; + } + +#undef REG_STRUCT +#define REG_STRUCT mcif_wb30_regs + mcif_wb_regs_dcn3_init(0); + + dcn32_mmhubbub_construct(mcif_wb30, ctx, + &mcif_wb30_regs[i], + &mcif_wb30_shift, + &mcif_wb30_mask, + i); + + pool->mcif_wb[i] = &mcif_wb30->base; + } + return true; +} + +static struct display_stream_compressor *dcn321_dsc_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dcn20_dsc *dsc = + kzalloc(sizeof(struct dcn20_dsc), GFP_KERNEL); + + if (!dsc) { + BREAK_TO_DEBUGGER(); + return NULL; + } + +#undef REG_STRUCT +#define REG_STRUCT dsc_regs + dsc_regsDCN20_init(0), + dsc_regsDCN20_init(1), + dsc_regsDCN20_init(2), + dsc_regsDCN20_init(3); + + dsc2_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask); + + dsc->max_image_width = 6016; + + return &dsc->base; +} + +static void dcn321_destroy_resource_pool(struct resource_pool **pool) +{ + struct dcn321_resource_pool *dcn321_pool = TO_DCN321_RES_POOL(*pool); + + dcn321_resource_destruct(dcn321_pool); + kfree(dcn321_pool); + *pool = NULL; +} + +static struct dc_cap_funcs cap_funcs = { + .get_dcc_compression_cap = dcn20_get_dcc_compression_cap, + .get_subvp_en = dcn32_subvp_in_use, +}; + +static void dcn321_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params) +{ + DC_FP_START(); + dcn321_update_bw_bounding_box_fpu(dc, bw_params); + DC_FP_END(); +} + +static struct resource_funcs dcn321_res_pool_funcs = { + .destroy = dcn321_destroy_resource_pool, + .link_enc_create = dcn321_link_encoder_create, + .link_enc_create_minimal = NULL, + .panel_cntl_create = dcn32_panel_cntl_create, + .validate_bandwidth = dcn32_validate_bandwidth, + .calculate_wm_and_dlg = dcn32_calculate_wm_and_dlg, + .populate_dml_pipes = dcn32_populate_dml_pipes_from_context, + .acquire_free_pipe_as_secondary_dpp_pipe = dcn32_acquire_free_pipe_as_secondary_dpp_pipe, + .acquire_free_pipe_as_secondary_opp_head = dcn32_acquire_free_pipe_as_secondary_opp_head, + .release_pipe = dcn20_release_pipe, + .add_stream_to_ctx = dcn30_add_stream_to_ctx, + .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource, + .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, + .populate_dml_writeback_from_context = dcn30_populate_dml_writeback_from_context, + .set_mcif_arb_params = dcn30_set_mcif_arb_params, + .find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link, + .acquire_post_bldn_3dlut = dcn32_acquire_post_bldn_3dlut, + .release_post_bldn_3dlut = dcn32_release_post_bldn_3dlut, + .update_bw_bounding_box = dcn321_update_bw_bounding_box, + .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, + .update_soc_for_wm_a = dcn30_update_soc_for_wm_a, + .add_phantom_pipes = dcn32_add_phantom_pipes, + .build_pipe_pix_clk_params = dcn20_build_pipe_pix_clk_params, +}; + +static uint32_t read_pipe_fuses(struct dc_context *ctx) +{ + uint32_t value = REG_READ(CC_DC_PIPE_DIS); + /* DCN321 support max 4 pipes */ + value = value & 0xf; + return value; +} + + +static bool dcn321_resource_construct( + uint8_t num_virtual_links, + struct dc *dc, + struct dcn321_resource_pool *pool) +{ + int i, j; + struct dc_context *ctx = dc->ctx; + struct irq_service_init_data init_data; + struct ddc_service_init_data ddc_init_data = {0}; + uint32_t pipe_fuses = 0; + uint32_t num_pipes = 4; + +#undef REG_STRUCT +#define REG_STRUCT bios_regs + bios_regs_init(); + +#undef REG_STRUCT +#define REG_STRUCT clk_src_regs + clk_src_regs_init(0, A), + clk_src_regs_init(1, B), + clk_src_regs_init(2, C), + clk_src_regs_init(3, D), + clk_src_regs_init(4, E); + +#undef REG_STRUCT +#define REG_STRUCT abm_regs + abm_regs_init(0), + abm_regs_init(1), + abm_regs_init(2), + abm_regs_init(3); + +#undef REG_STRUCT +#define REG_STRUCT dccg_regs + dccg_regs_init(); + + + ctx->dc_bios->regs = &bios_regs; + + pool->base.res_cap = &res_cap_dcn321; + /* max number of pipes for ASIC before checking for pipe fuses */ + num_pipes = pool->base.res_cap->num_timing_generator; + pipe_fuses = read_pipe_fuses(ctx); + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) + if (pipe_fuses & 1 << i) + num_pipes--; + + if (pipe_fuses & 1) + ASSERT(0); //Unexpected - Pipe 0 should always be fully functional! + + if (pipe_fuses & CC_DC_PIPE_DIS__DC_FULL_DIS_MASK) + ASSERT(0); //Entire DCN is harvested! + + /* within dml lib, initial value is hard coded, if ASIC pipe is fused, the + * value will be changed, update max_num_dpp and max_num_otg for dml. + */ + dcn3_21_ip.max_num_dpp = num_pipes; + dcn3_21_ip.max_num_otg = num_pipes; + + pool->base.funcs = &dcn321_res_pool_funcs; + + /************************************************* + * Resource + asic cap harcoding * + *************************************************/ + pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.timing_generator_count = num_pipes; + pool->base.pipe_count = num_pipes; + pool->base.mpcc_count = num_pipes; + dc->caps.max_downscale_ratio = 600; + dc->caps.i2c_speed_in_khz = 100; + dc->caps.i2c_speed_in_khz_hdcp = 100; /*1.4 w/a applied by default*/ + /* TODO: Bring max cursor size back to 256 after subvp cursor corruption is fixed*/ + 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 = 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; + + /* 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; + dc->caps.subvp_swath_height_margin_lines = 16; + dc->caps.subvp_pstate_allow_width_us = 20; + dc->caps.subvp_vertical_int_margin_us = 30; + dc->caps.subvp_drr_vblank_start_margin_us = 100; // 100us margin + dc->caps.max_slave_planes = 2; + dc->caps.max_slave_yuv_planes = 2; + dc->caps.max_slave_rgb_planes = 2; + dc->caps.post_blend_color_processing = true; + dc->caps.force_dp_tps4_for_cp2520 = true; + dc->caps.dp_hpo = true; + dc->caps.dp_hdmi21_pcon_support = true; + dc->caps.edp_dsc_support = true; + dc->caps.extended_aux_timeout_support = true; + dc->caps.dmcub_support = true; + dc->caps.max_v_total = (1 << 15) - 1; + + /* Color pipeline capabilities */ + dc->caps.color.dpp.dcn_arch = 1; + dc->caps.color.dpp.input_lut_shared = 0; + dc->caps.color.dpp.icsc = 1; + dc->caps.color.dpp.dgam_ram = 0; // must use gamma_corr + dc->caps.color.dpp.dgam_rom_caps.srgb = 1; + dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1; + dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 1; + dc->caps.color.dpp.dgam_rom_caps.pq = 1; + dc->caps.color.dpp.dgam_rom_caps.hlg = 1; + dc->caps.color.dpp.post_csc = 1; + dc->caps.color.dpp.gamma_corr = 1; + dc->caps.color.dpp.dgam_rom_for_yuv = 0; + + dc->caps.color.dpp.hw_3d_lut = 1; + dc->caps.color.dpp.ogam_ram = 1; + // no OGAM ROM on DCN2 and later ASICs + dc->caps.color.dpp.ogam_rom_caps.srgb = 0; + dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0; + dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0; + dc->caps.color.dpp.ogam_rom_caps.pq = 0; + dc->caps.color.dpp.ogam_rom_caps.hlg = 0; + dc->caps.color.dpp.ocsc = 0; + + dc->caps.color.mpc.gamut_remap = 1; + dc->caps.color.mpc.num_3dluts = pool->base.res_cap->num_mpc_3dlut; //4, configurable to be before or after BLND in MPCC + dc->caps.color.mpc.ogam_ram = 1; + dc->caps.color.mpc.ogam_rom_caps.srgb = 0; + dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0; + dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0; + dc->caps.color.mpc.ogam_rom_caps.pq = 0; + dc->caps.color.mpc.ogam_rom_caps.hlg = 0; + dc->caps.color.mpc.ocsc = 1; + + dc->config.dc_mode_clk_limit_support = true; + /* read VBIOS LTTPR caps */ + { + if (ctx->dc_bios->funcs->get_lttpr_caps) { + enum bp_result bp_query_result; + uint8_t is_vbios_lttpr_enable = 0; + + bp_query_result = ctx->dc_bios->funcs->get_lttpr_caps(ctx->dc_bios, &is_vbios_lttpr_enable); + dc->caps.vbios_lttpr_enable = (bp_query_result == BP_RESULT_OK) && !!is_vbios_lttpr_enable; + } + + /* interop bit is implicit */ + { + dc->caps.vbios_lttpr_aware = true; + } + } + + if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) + dc->debug = debug_defaults_drv; + + // Init the vm_helper + if (dc->vm_helper) + vm_helper_init(dc->vm_helper, 16); + + /************************************************* + * Create resources * + *************************************************/ + + /* Clock Sources for Pixel Clock*/ + pool->base.clock_sources[DCN321_CLK_SRC_PLL0] = + dcn321_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL0, + &clk_src_regs[0], false); + pool->base.clock_sources[DCN321_CLK_SRC_PLL1] = + dcn321_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL1, + &clk_src_regs[1], false); + pool->base.clock_sources[DCN321_CLK_SRC_PLL2] = + dcn321_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL2, + &clk_src_regs[2], false); + pool->base.clock_sources[DCN321_CLK_SRC_PLL3] = + dcn321_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL3, + &clk_src_regs[3], false); + pool->base.clock_sources[DCN321_CLK_SRC_PLL4] = + dcn321_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL4, + &clk_src_regs[4], false); + + pool->base.clk_src_count = DCN321_CLK_SRC_TOTAL; + + /* todo: not reuse phy_pll registers */ + pool->base.dp_clock_source = + dcn321_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_ID_DP_DTO, + &clk_src_regs[0], true); + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] == NULL) { + dm_error("DC: failed to create clock sources!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + } + + /* DCCG */ + pool->base.dccg = dccg32_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask); + if (pool->base.dccg == NULL) { + dm_error("DC: failed to create dccg!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + /* DML */ + dml_init_instance(&dc->dml, &dcn3_21_soc, &dcn3_21_ip, DML_PROJECT_DCN32); + + /* IRQ Service */ + init_data.ctx = dc->ctx; + pool->base.irqs = dal_irq_service_dcn32_create(&init_data); + if (!pool->base.irqs) + goto create_fail; + + /* HUBBUB */ + pool->base.hubbub = dcn321_hubbub_create(ctx); + if (pool->base.hubbub == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create hubbub!\n"); + goto create_fail; + } + + /* HUBPs, DPPs, OPPs, TGs, ABMs */ + for (i = 0, j = 0; i < pool->base.res_cap->num_timing_generator; i++) { + + /* if pipe is disabled, skip instance of HW pipe, + * i.e, skip ASIC register instance + */ + if (pipe_fuses & 1 << i) + continue; + + pool->base.hubps[j] = dcn321_hubp_create(ctx, i); + if (pool->base.hubps[j] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create hubps!\n"); + goto create_fail; + } + + pool->base.dpps[j] = dcn321_dpp_create(ctx, i); + if (pool->base.dpps[j] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create dpps!\n"); + goto create_fail; + } + + pool->base.opps[j] = dcn321_opp_create(ctx, i); + if (pool->base.opps[j] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create output pixel processor!\n"); + goto create_fail; + } + + pool->base.timing_generators[j] = dcn321_timing_generator_create( + ctx, i); + if (pool->base.timing_generators[j] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create tg!\n"); + goto create_fail; + } + + pool->base.multiple_abms[j] = dmub_abm_create(ctx, + &abm_regs[i], + &abm_shift, + &abm_mask); + if (pool->base.multiple_abms[j] == NULL) { + dm_error("DC: failed to create abm for pipe %d!\n", i); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + /* index for resource pool arrays for next valid pipe */ + j++; + } + + /* PSR */ + pool->base.psr = dmub_psr_create(ctx); + if (pool->base.psr == NULL) { + dm_error("DC: failed to create psr obj!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + /* MPCCs */ + pool->base.mpc = dcn321_mpc_create(ctx, pool->base.res_cap->num_timing_generator, pool->base.res_cap->num_mpc_3dlut); + if (pool->base.mpc == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create mpc!\n"); + goto create_fail; + } + + /* DSCs */ + for (i = 0; i < pool->base.res_cap->num_dsc; i++) { + pool->base.dscs[i] = dcn321_dsc_create(ctx, i); + if (pool->base.dscs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create display stream compressor %d!\n", i); + goto create_fail; + } + } + + /* DWB */ + if (!dcn321_dwbc_create(ctx, &pool->base)) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dwbc!\n"); + goto create_fail; + } + + /* MMHUBBUB */ + if (!dcn321_mmhubbub_create(ctx, &pool->base)) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create mcif_wb!\n"); + goto create_fail; + } + + /* AUX and I2C */ + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + pool->base.engines[i] = dcn321_aux_engine_create(ctx, i); + if (pool->base.engines[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create aux engine!!\n"); + goto create_fail; + } + pool->base.hw_i2cs[i] = dcn321_i2c_hw_create(ctx, i); + if (pool->base.hw_i2cs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create hw i2c!!\n"); + goto create_fail; + } + pool->base.sw_i2cs[i] = NULL; + } + + /* Audio, HWSeq, Stream Encoders including HPO and virtual, MPC 3D LUTs */ + if (!resource_construct(num_virtual_links, dc, &pool->base, + &res_create_funcs)) + goto create_fail; + + /* HW Sequencer init functions and Plane caps */ + dcn32_hw_sequencer_init_functions(dc); + + dc->caps.max_planes = pool->base.pipe_count; + + for (i = 0; i < dc->caps.max_planes; ++i) + dc->caps.planes[i] = plane_cap; + + 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->base.oem_device = dc->link_srv->create_ddc_service(&ddc_init_data); + } else { + pool->base.oem_device = NULL; + } + + dc->dml2_options.dcn_pipe_count = pool->base.pipe_count; + dc->dml2_options.use_native_pstate_optimization = false; + dc->dml2_options.use_native_soc_bb_construction = true; + dc->dml2_options.minimize_dispclk_using_odm = true; + + dc->dml2_options.callbacks.dc = dc; + dc->dml2_options.callbacks.build_scaling_params = &resource_build_scaling_params; + dc->dml2_options.callbacks.can_support_mclk_switch_using_fw_based_vblank_stretch = &dcn30_can_support_mclk_switch_using_fw_based_vblank_stretch; + dc->dml2_options.callbacks.acquire_secondary_pipe_for_mpc_odm = &dc_resource_acquire_secondary_pipe_for_mpc_odm_legacy; + dc->dml2_options.callbacks.update_pipes_for_stream_with_slice_count = &resource_update_pipes_for_stream_with_slice_count; + dc->dml2_options.callbacks.update_pipes_for_plane_with_slice_count = &resource_update_pipes_for_plane_with_slice_count; + dc->dml2_options.callbacks.get_mpc_slice_index = &resource_get_mpc_slice_index; + dc->dml2_options.callbacks.get_odm_slice_index = &resource_get_odm_slice_index; + dc->dml2_options.callbacks.get_opp_head = &resource_get_opp_head; + + dc->dml2_options.svp_pstate.callbacks.dc = dc; + dc->dml2_options.svp_pstate.callbacks.add_phantom_plane = &dc_state_add_phantom_plane; + dc->dml2_options.svp_pstate.callbacks.add_phantom_stream = &dc_state_add_phantom_stream; + dc->dml2_options.svp_pstate.callbacks.build_scaling_params = &resource_build_scaling_params; + dc->dml2_options.svp_pstate.callbacks.create_phantom_plane = &dc_state_create_phantom_plane; + dc->dml2_options.svp_pstate.callbacks.remove_phantom_plane = &dc_state_remove_phantom_plane; + dc->dml2_options.svp_pstate.callbacks.remove_phantom_stream = &dc_state_remove_phantom_stream; + dc->dml2_options.svp_pstate.callbacks.create_phantom_stream = &dc_state_create_phantom_stream; + dc->dml2_options.svp_pstate.callbacks.release_phantom_plane = &dc_state_release_phantom_plane; + dc->dml2_options.svp_pstate.callbacks.release_phantom_stream = &dc_state_release_phantom_stream; + dc->dml2_options.svp_pstate.callbacks.release_dsc = &dcn20_release_dsc; + dc->dml2_options.svp_pstate.callbacks.get_pipe_subvp_type = &dc_state_get_pipe_subvp_type; + dc->dml2_options.svp_pstate.callbacks.get_stream_subvp_type = &dc_state_get_stream_subvp_type; + dc->dml2_options.svp_pstate.callbacks.get_paired_subvp_stream = &dc_state_get_paired_subvp_stream; + + dc->dml2_options.svp_pstate.subvp_fw_processing_delay_us = dc->caps.subvp_fw_processing_delay_us; + dc->dml2_options.svp_pstate.subvp_prefetch_end_to_mall_start_us = dc->caps.subvp_prefetch_end_to_mall_start_us; + dc->dml2_options.svp_pstate.subvp_pstate_allow_width_us = dc->caps.subvp_pstate_allow_width_us; + dc->dml2_options.svp_pstate.subvp_swath_height_margin_lines = dc->caps.subvp_swath_height_margin_lines; + + dc->dml2_options.svp_pstate.force_disable_subvp = dc->debug.force_disable_subvp; + dc->dml2_options.svp_pstate.force_enable_subvp = dc->debug.force_subvp_mclk_switch; + + dc->dml2_options.mall_cfg.cache_line_size_bytes = dc->caps.cache_line_size; + dc->dml2_options.mall_cfg.cache_num_ways = dc->caps.cache_num_ways; + dc->dml2_options.mall_cfg.max_cab_allocation_bytes = dc->caps.max_cab_allocation_bytes; + dc->dml2_options.mall_cfg.mblk_height_4bpe_pixels = DCN3_2_MBLK_HEIGHT_4BPE; + dc->dml2_options.mall_cfg.mblk_height_8bpe_pixels = DCN3_2_MBLK_HEIGHT_8BPE; + dc->dml2_options.mall_cfg.mblk_size_bytes = DCN3_2_MALL_MBLK_SIZE_BYTES; + dc->dml2_options.mall_cfg.mblk_width_pixels = DCN3_2_MBLK_WIDTH; + + dc->dml2_options.max_segments_per_hubp = 18; + dc->dml2_options.det_segment_size = DCN3_2_DET_SEG_SIZE; + + return true; + +create_fail: + + dcn321_resource_destruct(pool); + + return false; +} + +struct resource_pool *dcn321_create_resource_pool( + const struct dc_init_data *init_data, + struct dc *dc) +{ + struct dcn321_resource_pool *pool = + kzalloc(sizeof(struct dcn321_resource_pool), GFP_KERNEL); + + if (!pool) + return NULL; + + if (dcn321_resource_construct(init_data->num_virtual_links, dc, pool)) + return &pool->base; + + BREAK_TO_DEBUGGER(); + kfree(pool); + return NULL; +} diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.h new file mode 100644 index 00000000000000..82cbf009f2d380 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.h @@ -0,0 +1,45 @@ +/* + * Copyright 2020 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 _DCN321_RESOURCE_H_ +#define _DCN321_RESOURCE_H_ + +#include "core_types.h" + +#define TO_DCN321_RES_POOL(pool)\ + container_of(pool, struct dcn321_resource_pool, base) + +extern struct _vcs_dpi_ip_params_st dcn3_21_ip; +extern struct _vcs_dpi_soc_bounding_box_st dcn3_21_soc; + +struct dcn321_resource_pool { + struct resource_pool base; +}; + +struct resource_pool *dcn321_create_resource_pool( + const struct dc_init_data *init_data, + struct dc *dc); + +#endif /* _DCN321_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c new file mode 100644 index 00000000000000..761ec989187568 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c @@ -0,0 +1,2178 @@ +/* SPDX-License-Identifier: MIT */ +/* + * 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 "dm_services.h" +#include "dc.h" + +#include "dcn31/dcn31_init.h" +#include "dcn35/dcn35_init.h" + +#include "resource.h" +#include "include/irq_service_interface.h" +#include "dcn35_resource.h" +#include "dml2/dml2_wrapper.h" + +#include "dcn20/dcn20_resource.h" +#include "dcn30/dcn30_resource.h" +#include "dcn31/dcn31_resource.h" +#include "dcn32/dcn32_resource.h" + +#include "dcn10/dcn10_ipp.h" +#include "dcn30/dcn30_hubbub.h" +#include "dcn31/dcn31_hubbub.h" +#include "dcn35/dcn35_hubbub.h" +#include "dcn32/dcn32_mpc.h" +#include "dcn35/dcn35_hubp.h" +#include "irq/dcn35/irq_service_dcn35.h" +#include "dcn35/dcn35_dpp.h" +#include "dcn35/dcn35_optc.h" +#include "dcn20/dcn20_hwseq.h" +#include "dcn30/dcn30_hwseq.h" +#include "dce110/dce110_hwseq.h" +#include "dcn35/dcn35_opp.h" +#include "dcn35/dcn35_dsc.h" +#include "dcn30/dcn30_vpg.h" +#include "dcn30/dcn30_afmt.h" +#include "dcn31/dcn31_dio_link_encoder.h" +#include "dcn35/dcn35_dio_stream_encoder.h" +#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 "link.h" +#include "dcn31/dcn31_apg.h" +#include "dcn32/dcn32_dio_link_encoder.h" +#include "dcn31/dcn31_vpg.h" +#include "dcn31/dcn31_afmt.h" +#include "dce/dce_clock_source.h" +#include "dce/dce_audio.h" +#include "dce/dce_hwseq.h" +#include "clk_mgr.h" +#include "virtual/virtual_stream_encoder.h" +#include "dce110/dce110_resource.h" +#include "dml/display_mode_vba.h" +#include "dcn35/dcn35_dccg.h" +#include "dcn35/dcn35_pg_cntl.h" +#include "dcn10/dcn10_resource.h" +#include "dcn31/dcn31_panel_cntl.h" +#include "dcn35/dcn35_hwseq.h" +#include "dcn35/dcn35_dio_link_encoder.h" +#include "dml/dcn31/dcn31_fpu.h" /*todo*/ +#include "dml/dcn35/dcn35_fpu.h" +#include "dcn35/dcn35_dwb.h" +#include "dcn35/dcn35_mmhubbub.h" + +#include "dcn/dcn_3_5_0_offset.h" +#include "dcn/dcn_3_5_0_sh_mask.h" +#include "nbio/nbio_7_11_0_offset.h" +#include "mmhub/mmhub_3_3_0_offset.h" +#include "mmhub/mmhub_3_3_0_sh_mask.h" + +#define DSCC0_DSCC_CONFIG0__ICH_RESET_AT_END_OF_LINE__SHIFT 0x0 +#define DSCC0_DSCC_CONFIG0__ICH_RESET_AT_END_OF_LINE_MASK 0x0000000FL + +#include "reg_helper.h" +#include "dce/dmub_abm.h" +#include "dce/dmub_psr.h" +#include "dce/dmub_replay.h" +#include "dce/dce_aux.h" +#include "dce/dce_i2c.h" +#include "dml/dcn31/display_mode_vba_31.h" /*temp*/ +#include "vm_helper.h" +#include "dcn20/dcn20_vmid.h" + +#include "dc_state_priv.h" + +#include "link_enc_cfg.h" +#define DC_LOGGER_INIT(logger) + +enum dcn35_clk_src_array_id { + DCN35_CLK_SRC_PLL0, + DCN35_CLK_SRC_PLL1, + DCN35_CLK_SRC_PLL2, + DCN35_CLK_SRC_PLL3, + DCN35_CLK_SRC_PLL4, + DCN35_CLK_SRC_TOTAL +}; + +/* begin ********************* + * macros to expend register list macro defined in HW object header file + */ + +/* DCN */ +/* TODO awful hack. fixup dcn20_dwb.h */ +#undef BASE_INNER +#define BASE_INNER(seg) ctx->dcn_reg_offsets[seg] + +#define BASE(seg) BASE_INNER(seg) + +#define SR(reg_name)\ + REG_STRUCT.reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ + reg ## reg_name + +#define SR_ARR(reg_name, id) \ + REG_STRUCT[id].reg_name = BASE(reg##reg_name##_BASE_IDX) + reg##reg_name + +#define SR_ARR_INIT(reg_name, id, value) \ + REG_STRUCT[id].reg_name = value + +#define SRI(reg_name, block, id)\ + REG_STRUCT.reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRI_ARR(reg_name, block, id)\ + REG_STRUCT[id].reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SR_ARR_I2C(reg_name, id) \ + REG_STRUCT[id-1].reg_name = BASE(reg##reg_name##_BASE_IDX) + reg##reg_name + +#define SRI_ARR_I2C(reg_name, block, id)\ + REG_STRUCT[id-1].reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRI_ARR_ALPHABET(reg_name, block, index, id)\ + REG_STRUCT[index].reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRI2(reg_name, block, id)\ + .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ + reg ## reg_name + +#define SRI2_ARR(reg_name, block, id)\ + REG_STRUCT[id].reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ + reg ## reg_name + +#define SRIR(var_name, reg_name, block, id)\ + .var_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRII(reg_name, block, id)\ + REG_STRUCT.reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRII_ARR_2(reg_name, block, id, inst)\ + REG_STRUCT[inst].reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRII_MPC_RMU(reg_name, block, id)\ + .RMU##_##reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define SRII_DWB(reg_name, temp_name, block, id)\ + REG_STRUCT.reg_name[id] = BASE(reg ## block ## id ## _ ## temp_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## temp_name + +#define SF_DWB2(reg_name, block, id, field_name, post_fix) \ + .field_name = reg_name ## __ ## field_name ## post_fix + +#define DCCG_SRII(reg_name, block, id)\ + REG_STRUCT.block ## _ ## reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + reg ## block ## id ## _ ## reg_name + +#define VUPDATE_SRII(reg_name, block, id)\ + REG_STRUCT.reg_name[id] = BASE(reg ## reg_name ## _ ## block ## id ## _BASE_IDX) + \ + reg ## reg_name ## _ ## block ## id + +/* NBIO */ +#define NBIO_BASE_INNER(seg) ctx->nbio_reg_offsets[seg] + +#define NBIO_BASE(seg) \ + NBIO_BASE_INNER(seg) + +#define NBIO_SR(reg_name)\ + REG_STRUCT.reg_name = NBIO_BASE(regBIF_BX2_ ## reg_name ## _BASE_IDX) + \ + regBIF_BX2_ ## reg_name + +#define NBIO_SR_ARR(reg_name, id)\ + REG_STRUCT[id].reg_name = NBIO_BASE(regBIF_BX2_ ## reg_name ## _BASE_IDX) + \ + regBIF_BX2_ ## reg_name + +#define bios_regs_init() \ + ( \ + NBIO_SR(BIOS_SCRATCH_3),\ + NBIO_SR(BIOS_SCRATCH_6)\ + ) + +static struct bios_registers bios_regs; + +#define clk_src_regs_init(index, pllid)\ + CS_COMMON_REG_LIST_DCN3_0_RI(index, pllid) + +static struct dce110_clk_src_regs clk_src_regs[5]; + +static const struct dce110_clk_src_shift cs_shift = { + CS_COMMON_MASK_SH_LIST_DCN3_1_4(__SHIFT) +}; + +static const struct dce110_clk_src_mask cs_mask = { + CS_COMMON_MASK_SH_LIST_DCN3_1_4(_MASK) +}; + +#define abm_regs_init(id)\ + ABM_DCN32_REG_LIST_RI(id) + +static struct dce_abm_registers abm_regs[4]; + +static const struct dce_abm_shift abm_shift = { + ABM_MASK_SH_LIST_DCN35(__SHIFT) +}; + +static const struct dce_abm_mask abm_mask = { + ABM_MASK_SH_LIST_DCN35(_MASK) +}; + +#define audio_regs_init(id)\ + AUD_COMMON_REG_LIST_RI(id) + +static struct dce_audio_registers audio_regs[7]; + + +#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ + AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) + +static const struct dce_audio_shift audio_shift = { + DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_audio_mask audio_mask = { + DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) +}; + +#define vpg_regs_init(id)\ + VPG_DCN31_REG_LIST_RI(id) + +static struct dcn31_vpg_registers vpg_regs[10]; + +static const struct dcn31_vpg_shift vpg_shift = { + DCN31_VPG_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn31_vpg_mask vpg_mask = { + DCN31_VPG_MASK_SH_LIST(_MASK) +}; + +#define afmt_regs_init(id)\ + AFMT_DCN31_REG_LIST_RI(id) + +static struct dcn31_afmt_registers afmt_regs[6]; + +static const struct dcn31_afmt_shift afmt_shift = { + DCN31_AFMT_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn31_afmt_mask afmt_mask = { + DCN31_AFMT_MASK_SH_LIST(_MASK) +}; + +#define apg_regs_init(id)\ + APG_DCN31_REG_LIST_RI(id) + +static struct dcn31_apg_registers apg_regs[4]; + +static const struct dcn31_apg_shift apg_shift = { + DCN31_APG_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn31_apg_mask apg_mask = { + DCN31_APG_MASK_SH_LIST(_MASK) +}; + +#define stream_enc_regs_init(id)\ + SE_DCN35_REG_LIST_RI(id) + +static struct dcn10_stream_enc_registers stream_enc_regs[5]; + +static const struct dcn10_stream_encoder_shift se_shift = { + SE_COMMON_MASK_SH_LIST_DCN35(__SHIFT) +}; + +static const struct dcn10_stream_encoder_mask se_mask = { + SE_COMMON_MASK_SH_LIST_DCN35(_MASK) +}; + +#define aux_regs_init(id)\ + DCN2_AUX_REG_LIST_RI(id) + +static struct dcn10_link_enc_aux_registers link_enc_aux_regs[5]; + +#define hpd_regs_init(id)\ + HPD_REG_LIST_RI(id) + +static struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[5]; + + +static const struct dce110_aux_registers_shift aux_shift = { + DCN_AUX_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce110_aux_registers_mask aux_mask = { + DCN_AUX_MASK_SH_LIST(_MASK) +}; + +#define link_regs_init(id, phyid)\ + ( \ + LE_DCN35_REG_LIST_RI(id), \ + UNIPHY_DCN2_REG_LIST_RI(id, phyid)\ + ) + +static struct dcn10_link_enc_registers link_enc_regs[5]; + +static const struct dcn10_link_enc_shift le_shift = { + LINK_ENCODER_MASK_SH_LIST_DCN35(__SHIFT), \ + //DPCS_DCN31_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn10_link_enc_mask le_mask = { + LINK_ENCODER_MASK_SH_LIST_DCN35(_MASK), \ + //DPCS_DCN31_MASK_SH_LIST(_MASK) +}; + +#define hpo_dp_stream_encoder_reg_init(id)\ + DCN3_1_HPO_DP_STREAM_ENC_REG_LIST_RI(id) + +static struct dcn31_hpo_dp_stream_encoder_registers hpo_dp_stream_enc_regs[4]; + +static const struct dcn31_hpo_dp_stream_encoder_shift hpo_dp_se_shift = { + DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn31_hpo_dp_stream_encoder_mask hpo_dp_se_mask = { + DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(_MASK) +}; + +#define hpo_dp_link_encoder_reg_init(id)\ + DCN3_1_HPO_DP_LINK_ENC_REG_LIST_RI(id) + /*DCN3_1_RDPCSTX_REG_LIST(0),*/ + /*DCN3_1_RDPCSTX_REG_LIST(1),*/ + /*DCN3_1_RDPCSTX_REG_LIST(2),*/ + /*DCN3_1_RDPCSTX_REG_LIST(3),*/ + +static struct dcn31_hpo_dp_link_encoder_registers hpo_dp_link_enc_regs[2]; + +static const struct dcn31_hpo_dp_link_encoder_shift hpo_dp_le_shift = { + DCN3_1_HPO_DP_LINK_ENC_COMMON_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn31_hpo_dp_link_encoder_mask hpo_dp_le_mask = { + DCN3_1_HPO_DP_LINK_ENC_COMMON_MASK_SH_LIST(_MASK) +}; + +#define dpp_regs_init(id)\ + DPP_REG_LIST_DCN35_RI(id) + +static struct dcn3_dpp_registers dpp_regs[4]; + +static const struct dcn35_dpp_shift tf_shift = { + DPP_REG_LIST_SH_MASK_DCN35(__SHIFT) +}; + +static const struct dcn35_dpp_mask tf_mask = { + DPP_REG_LIST_SH_MASK_DCN35(_MASK) +}; + +#define opp_regs_init(id)\ + OPP_REG_LIST_DCN35_RI(id) + +static struct dcn35_opp_registers opp_regs[4]; + +static const struct dcn35_opp_shift opp_shift = { + OPP_MASK_SH_LIST_DCN35(__SHIFT) +}; + +static const struct dcn35_opp_mask opp_mask = { + OPP_MASK_SH_LIST_DCN35(_MASK) +}; + +#define aux_engine_regs_init(id)\ + ( \ + AUX_COMMON_REG_LIST0_RI(id), \ + SR_ARR_INIT(AUXN_IMPCAL, id, 0), \ + SR_ARR_INIT(AUXP_IMPCAL, id, 0), \ + SR_ARR_INIT(AUX_RESET_MASK, id, DP_AUX0_AUX_CONTROL__AUX_RESET_MASK) \ + ) + +static struct dce110_aux_registers aux_engine_regs[5]; + +#define dwbc_regs_dcn3_init(id)\ + DWBC_COMMON_REG_LIST_DCN30_RI(id) + +static struct dcn30_dwbc_registers dwbc35_regs[1]; + +static const struct dcn35_dwbc_shift dwbc35_shift = { + DWBC_COMMON_MASK_SH_LIST_DCN35(__SHIFT) +}; + +static const struct dcn35_dwbc_mask dwbc35_mask = { + DWBC_COMMON_MASK_SH_LIST_DCN35(_MASK) +}; + +#define mcif_wb_regs_dcn3_init(id)\ + MCIF_WB_COMMON_REG_LIST_DCN3_5_RI(id) + +static struct dcn35_mmhubbub_registers mcif_wb35_regs[1]; + +static const struct dcn35_mmhubbub_shift mcif_wb35_shift = { + MCIF_WB_COMMON_MASK_SH_LIST_DCN3_5(__SHIFT) +}; + +static const struct dcn35_mmhubbub_mask mcif_wb35_mask = { + MCIF_WB_COMMON_MASK_SH_LIST_DCN3_5(_MASK) +}; + +#define dsc_regsDCN35_init(id)\ + DSC_REG_LIST_DCN20_RI(id) + +static struct dcn20_dsc_registers dsc_regs[4]; + +static const struct dcn35_dsc_shift dsc_shift = { + DSC_REG_LIST_SH_MASK_DCN35(__SHIFT) +}; + +static const struct dcn35_dsc_mask dsc_mask = { + DSC_REG_LIST_SH_MASK_DCN35(_MASK) +}; + +static struct dcn30_mpc_registers mpc_regs; + +#define dcn_mpc_regs_init() \ + MPC_REG_LIST_DCN3_2_RI(0),\ + MPC_REG_LIST_DCN3_2_RI(1),\ + MPC_REG_LIST_DCN3_2_RI(2),\ + MPC_REG_LIST_DCN3_2_RI(3),\ + MPC_OUT_MUX_REG_LIST_DCN3_0_RI(0),\ + MPC_OUT_MUX_REG_LIST_DCN3_0_RI(1),\ + MPC_OUT_MUX_REG_LIST_DCN3_0_RI(2),\ + MPC_OUT_MUX_REG_LIST_DCN3_0_RI(3),\ + MPC_DWB_MUX_REG_LIST_DCN3_0_RI(0) + +static const struct dcn30_mpc_shift mpc_shift = { + MPC_COMMON_MASK_SH_LIST_DCN32(__SHIFT) +}; + +static const struct dcn30_mpc_mask mpc_mask = { + MPC_COMMON_MASK_SH_LIST_DCN32(_MASK) +}; + +#define optc_regs_init(id)\ + OPTC_COMMON_REG_LIST_DCN3_5_RI(id) + +static struct dcn_optc_registers optc_regs[4]; + +static const struct dcn_optc_shift optc_shift = { + OPTC_COMMON_MASK_SH_LIST_DCN3_5(__SHIFT) +}; + +static const struct dcn_optc_mask optc_mask = { + OPTC_COMMON_MASK_SH_LIST_DCN3_5(_MASK) +}; + +#define hubp_regs_init(id)\ + HUBP_REG_LIST_DCN30_RI(id) + +static struct dcn_hubp2_registers hubp_regs[4]; + + +static const struct dcn35_hubp2_shift hubp_shift = { + HUBP_MASK_SH_LIST_DCN35(__SHIFT) +}; + +static const struct dcn35_hubp2_mask hubp_mask = { + HUBP_MASK_SH_LIST_DCN35(_MASK) +}; + +static struct dcn_hubbub_registers hubbub_reg; + +#define hubbub_reg_init()\ + HUBBUB_REG_LIST_DCN35(0) + +static const struct dcn_hubbub_shift hubbub_shift = { + HUBBUB_MASK_SH_LIST_DCN35(__SHIFT) +}; + +static const struct dcn_hubbub_mask hubbub_mask = { + HUBBUB_MASK_SH_LIST_DCN35(_MASK) +}; + +static struct dccg_registers dccg_regs; + +#define dccg_regs_init()\ + DCCG_REG_LIST_DCN35() + +static const struct dccg_shift dccg_shift = { + DCCG_MASK_SH_LIST_DCN35(__SHIFT) +}; + +static const struct dccg_mask dccg_mask = { + DCCG_MASK_SH_LIST_DCN35(_MASK) +}; + +static struct pg_cntl_registers pg_cntl_regs; + +#define pg_cntl_dcn35_regs_init() \ + PG_CNTL_REG_LIST_DCN35() + +static const struct pg_cntl_shift pg_cntl_shift = { + PG_CNTL_MASK_SH_LIST_DCN35(__SHIFT) +}; + +static const struct pg_cntl_mask pg_cntl_mask = { + PG_CNTL_MASK_SH_LIST_DCN35(_MASK) +}; + +#define SRII2(reg_name_pre, reg_name_post, id)\ + .reg_name_pre ## _ ## reg_name_post[id] = BASE(reg ## reg_name_pre \ + ## id ## _ ## reg_name_post ## _BASE_IDX) + \ + reg ## reg_name_pre ## id ## _ ## reg_name_post + +static struct dce_hwseq_registers hwseq_reg; + +#define hwseq_reg_init()\ + HWSEQ_DCN35_REG_LIST() + +#define HWSEQ_DCN35_MASK_SH_LIST(mask_sh)\ + HWSEQ_DCN_MASK_SH_LIST(mask_sh), \ + HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \ + HWS_SF(, DCHUBBUB_ARB_HOSTVM_CNTL, DISABLE_HOSTVM_FORCE_ALLOW_PSTATE, mask_sh), \ + HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN19_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN19_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN22_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN22_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN23_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN23_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN24_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN24_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN25_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \ + HWS_SF(, DOMAIN25_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \ + HWS_SF(, DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN16_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN17_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN18_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN19_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN22_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN23_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN24_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DOMAIN25_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ + HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \ + HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh), \ + HWS_SF(, HPO_TOP_CLOCK_CONTROL, HPO_HDMISTREAMCLK_G_GATE_DIS, mask_sh), \ + HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_UNASSIGNED_PWR_MODE, mask_sh), \ + HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_VBLANK_PWR_MODE, mask_sh), \ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh), \ + HWS_SF(, HPO_TOP_HW_CONTROL, HPO_IO_EN, mask_sh),\ + HWS_SF(, DMU_CLK_CNTL, DISPCLK_R_DMU_GATE_DIS, mask_sh),\ + HWS_SF(, DMU_CLK_CNTL, DISPCLK_G_RBBMIF_GATE_DIS, mask_sh),\ + HWS_SF(, DMU_CLK_CNTL, RBBMIF_FGCG_REP_DIS, mask_sh),\ + HWS_SF(, DMU_CLK_CNTL, DPREFCLK_ALLOW_DS_CLKSTOP, mask_sh),\ + HWS_SF(, DMU_CLK_CNTL, DISPCLK_ALLOW_DS_CLKSTOP, mask_sh),\ + HWS_SF(, DMU_CLK_CNTL, DPPCLK_ALLOW_DS_CLKSTOP, mask_sh),\ + HWS_SF(, DMU_CLK_CNTL, DTBCLK_ALLOW_DS_CLKSTOP, mask_sh),\ + HWS_SF(, DMU_CLK_CNTL, DCFCLK_ALLOW_DS_CLKSTOP, mask_sh),\ + HWS_SF(, DMU_CLK_CNTL, DPIACLK_ALLOW_DS_CLKSTOP, mask_sh),\ + HWS_SF(, DMU_CLK_CNTL, LONO_FGCG_REP_DIS, mask_sh),\ + HWS_SF(, DMU_CLK_CNTL, LONO_DISPCLK_GATE_DISABLE, mask_sh),\ + HWS_SF(, DMU_CLK_CNTL, LONO_SOCCLK_GATE_DISABLE, mask_sh),\ + HWS_SF(, DMU_CLK_CNTL, LONO_DMCUBCLK_GATE_DISABLE, mask_sh),\ + HWS_SF(, DCCG_GATE_DISABLE_CNTL2, SYMCLKA_FE_GATE_DISABLE, mask_sh), \ + HWS_SF(, DCCG_GATE_DISABLE_CNTL2, SYMCLKB_FE_GATE_DISABLE, mask_sh), \ + HWS_SF(, DCCG_GATE_DISABLE_CNTL2, SYMCLKC_FE_GATE_DISABLE, mask_sh), \ + HWS_SF(, DCCG_GATE_DISABLE_CNTL2, SYMCLKD_FE_GATE_DISABLE, mask_sh), \ + HWS_SF(, DCCG_GATE_DISABLE_CNTL2, SYMCLKE_FE_GATE_DISABLE, mask_sh), \ + HWS_SF(, DCCG_GATE_DISABLE_CNTL2, HDMICHARCLK0_GATE_DISABLE, mask_sh), \ + HWS_SF(, DCCG_GATE_DISABLE_CNTL2, SYMCLKA_GATE_DISABLE, mask_sh), \ + HWS_SF(, DCCG_GATE_DISABLE_CNTL2, SYMCLKB_GATE_DISABLE, mask_sh), \ + HWS_SF(, DCCG_GATE_DISABLE_CNTL2, SYMCLKC_GATE_DISABLE, mask_sh), \ + HWS_SF(, DCCG_GATE_DISABLE_CNTL2, SYMCLKD_GATE_DISABLE, mask_sh), \ + HWS_SF(, DCCG_GATE_DISABLE_CNTL2, SYMCLKE_GATE_DISABLE, mask_sh), \ + HWS_SF(, DCCG_GATE_DISABLE_CNTL2, PHYASYMCLK_ROOT_GATE_DISABLE, mask_sh), \ + HWS_SF(, DCCG_GATE_DISABLE_CNTL2, PHYBSYMCLK_ROOT_GATE_DISABLE, mask_sh), \ + HWS_SF(, DCCG_GATE_DISABLE_CNTL2, PHYCSYMCLK_ROOT_GATE_DISABLE, mask_sh), \ + HWS_SF(, DCCG_GATE_DISABLE_CNTL2, PHYDSYMCLK_ROOT_GATE_DISABLE, mask_sh), \ + HWS_SF(, DCCG_GATE_DISABLE_CNTL2, PHYESYMCLK_ROOT_GATE_DISABLE, mask_sh),\ + HWS_SF(, DCCG_GATE_DISABLE_CNTL5, DTBCLK_P0_GATE_DISABLE, mask_sh),\ + HWS_SF(, DCCG_GATE_DISABLE_CNTL5, DTBCLK_P1_GATE_DISABLE, mask_sh),\ + HWS_SF(, DCCG_GATE_DISABLE_CNTL5, DTBCLK_P2_GATE_DISABLE, mask_sh),\ + HWS_SF(, DCCG_GATE_DISABLE_CNTL5, DTBCLK_P3_GATE_DISABLE, mask_sh),\ + HWS_SF(, DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK0_GATE_DISABLE, mask_sh),\ + HWS_SF(, DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK1_GATE_DISABLE, mask_sh),\ + HWS_SF(, DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK2_GATE_DISABLE, mask_sh),\ + HWS_SF(, DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK3_GATE_DISABLE, mask_sh),\ + HWS_SF(, DCCG_GATE_DISABLE_CNTL4, DPIASYMCLK0_GATE_DISABLE, mask_sh),\ + HWS_SF(, DCCG_GATE_DISABLE_CNTL4, DPIASYMCLK1_GATE_DISABLE, mask_sh),\ + HWS_SF(, DCCG_GATE_DISABLE_CNTL4, DPIASYMCLK2_GATE_DISABLE, mask_sh),\ + HWS_SF(, DCCG_GATE_DISABLE_CNTL4, DPIASYMCLK3_GATE_DISABLE, mask_sh) + +static const struct dce_hwseq_shift hwseq_shift = { + HWSEQ_DCN35_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_hwseq_mask hwseq_mask = { + HWSEQ_DCN35_MASK_SH_LIST(_MASK) +}; + +#define vmid_regs_init(id)\ + DCN20_VMID_REG_LIST_RI(id) + +static struct dcn_vmid_registers vmid_regs[16]; + +static const struct dcn20_vmid_shift vmid_shifts = { + DCN20_VMID_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn20_vmid_mask vmid_masks = { + DCN20_VMID_MASK_SH_LIST(_MASK) +}; + +static const struct resource_caps res_cap_dcn35 = { + .num_timing_generator = 4, + .num_opp = 4, + .num_video_plane = 4, + .num_audio = 5, + .num_stream_encoder = 5, + .num_dig_link_enc = 5, + .num_hpo_dp_stream_encoder = 4, + .num_hpo_dp_link_encoder = 2, + .num_pll = 4,/*1 c10 edp, 3xc20 combo PHY*/ + .num_dwb = 1, + .num_ddc = 5, + .num_vmid = 16, + .num_mpc_3dlut = 2, + .num_dsc = 4, +}; + +static const struct dc_plane_cap plane_cap = { + .type = DC_PLANE_TYPE_DCN_UNIVERSAL, + .per_pixel_alpha = true, + + .pixel_format_support = { + .argb8888 = true, + .nv12 = true, + .fp16 = true, + .p010 = true, + .ayuv = false, + }, + + .max_upscale_factor = { + .argb8888 = 16000, + .nv12 = 16000, + .fp16 = 16000 + }, + + // 6:1 downscaling ratio: 1000/6 = 166.666 + .max_downscale_factor = { + .argb8888 = 167, + .nv12 = 167, + .fp16 = 167 + }, + 64, + 64 +}; + +static const struct dc_debug_options debug_defaults_drv = { + .disable_dmcu = true, + .force_abm_enable = false, + .timing_trace = false, + .clock_trace = true, + .disable_pplib_clock_request = false, + .pipe_split_policy = MPC_SPLIT_AVOID, + .force_single_disp_pipe_split = false, + .disable_dcc = DCC_ENABLE, + .disable_dpp_power_gate = true, + .disable_hubp_power_gate = true, + .disable_optc_power_gate = true, /*should the same as above two*/ + .disable_hpo_power_gate = true, /*dmubfw force domain25 on*/ + .disable_clock_gate = false, + .disable_dsc_power_gate = true, + .vsr_support = true, + .performance_trace = false, + .max_downscale_src_width = 4096,/*upto true 4k*/ + .disable_pplib_wm_range = false, + .scl_reset_length10 = true, + .sanity_checks = false, + .underflow_assert_delay_us = 0xFFFFFFFF, + .dwb_fi_phase = -1, // -1 = disable, + .dmub_command_table = true, + .pstate_enabled = true, + .use_max_lb = true, + .enable_mem_low_power = { + .bits = { + .vga = false, + .i2c = true, + .dmcu = false, // This is previously known to cause hang on S3 cycles if enabled + .dscl = true, + .cm = true, + .mpc = true, + .optc = true, + .vpg = true, + .afmt = true, + } + }, + .root_clock_optimization = { + .bits = { + .dpp = true, + .dsc = true,/*dscclk and dsc pg*/ + .hdmistream = true, + .hdmichar = true, + .dpstream = true, + .symclk32_se = true, + .symclk32_le = true, + .symclk_fe = true, + .physymclk = true, + .dpiasymclk = true, + } + }, + .seamless_boot_odm_combine = DML_FAIL_SOURCE_PIXEL_FORMAT, + .enable_z9_disable_interface = true, /* Allow support for the PMFW interface for disable Z9*/ + .using_dml2 = true, + .support_eDP1_5 = true, + .enable_hpo_pg_support = false, + .enable_legacy_fast_update = true, + .enable_single_display_2to1_odm_policy = false, + .disable_idle_power_optimizations = false, + .dmcub_emulation = false, + .disable_boot_optimizations = false, + .disable_unbounded_requesting = false, + .disable_mem_low_power = false, + //must match enable_single_display_2to1_odm_policy to support dynamic ODM transitions + .enable_double_buffered_dsc_pg_support = true, + .enable_dp_dig_pixel_rate_div_policy = 1, + .disable_z10 = false, + .ignore_pg = true, + .psp_disabled_wa = true, + .ips2_eval_delay_us = 200, + .ips2_entry_delay_us = 400, + .static_screen_wait_frames = 2, +}; + +static const struct dc_panel_config panel_config_defaults = { + .psr = { + .disable_psr = false, + .disallow_psrsu = false, + .disallow_replay = false, + }, + .ilr = { + .optimize_edp_link_rate = true, + }, +}; + +static void dcn35_dpp_destroy(struct dpp **dpp) +{ + kfree(TO_DCN20_DPP(*dpp)); + *dpp = NULL; +} + +static struct dpp *dcn35_dpp_create(struct dc_context *ctx, uint32_t inst) +{ + struct dcn3_dpp *dpp = kzalloc(sizeof(struct dcn3_dpp), GFP_KERNEL); + bool success = (dpp != NULL); + + if (!success) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT dpp_regs + dpp_regs_init(0), + dpp_regs_init(1), + dpp_regs_init(2), + dpp_regs_init(3); + + success = dpp35_construct(dpp, ctx, inst, &dpp_regs[inst], &tf_shift, + &tf_mask); + if (success) { + dpp35_set_fgcg( + dpp, + ctx->dc->debug.enable_fine_grain_clock_gating.bits.dpp); + return &dpp->base; + } + + BREAK_TO_DEBUGGER(); + kfree(dpp); + return NULL; +} + +static struct output_pixel_processor *dcn35_opp_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dcn20_opp *opp = + kzalloc(sizeof(struct dcn20_opp), GFP_KERNEL); + + if (!opp) { + BREAK_TO_DEBUGGER(); + return NULL; + } + +#undef REG_STRUCT +#define REG_STRUCT opp_regs + opp_regs_init(0), + opp_regs_init(1), + opp_regs_init(2), + opp_regs_init(3); + + dcn35_opp_construct(opp, ctx, inst, + &opp_regs[inst], &opp_shift, &opp_mask); + + dcn35_opp_set_fgcg(opp, ctx->dc->debug.enable_fine_grain_clock_gating.bits.opp); + + return &opp->base; +} + +static struct dce_aux *dcn31_aux_engine_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct aux_engine_dce110 *aux_engine = + kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL); + + if (!aux_engine) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT aux_engine_regs + aux_engine_regs_init(0), + aux_engine_regs_init(1), + aux_engine_regs_init(2), + aux_engine_regs_init(3), + aux_engine_regs_init(4); + + dce110_aux_engine_construct(aux_engine, ctx, inst, + SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD, + &aux_engine_regs[inst], + &aux_mask, + &aux_shift, + ctx->dc->caps.extended_aux_timeout_support); + + return &aux_engine->base; +} + +#define i2c_inst_regs_init(id)\ + I2C_HW_ENGINE_COMMON_REG_LIST_DCN30_RI(id) + +static struct dce_i2c_registers i2c_hw_regs[5]; + +static const struct dce_i2c_shift i2c_shifts = { + I2C_COMMON_MASK_SH_LIST_DCN35(__SHIFT) +}; + +static const struct dce_i2c_mask i2c_masks = { + I2C_COMMON_MASK_SH_LIST_DCN35(_MASK) +}; + +/* ========================================================== */ + +/* + * DPIA index | Preferred Encoder | Host Router + * 0 | C | 0 + * 1 | First Available | 0 + * 2 | D | 1 + * 3 | First Available | 1 + */ +/* ========================================================== */ +static const enum engine_id dpia_to_preferred_enc_id_table[] = { + ENGINE_ID_DIGC, + ENGINE_ID_DIGC, + ENGINE_ID_DIGD, + ENGINE_ID_DIGD +}; + +static enum engine_id dcn35_get_preferred_eng_id_dpia(unsigned int dpia_index) +{ + return dpia_to_preferred_enc_id_table[dpia_index]; +} + +static struct dce_i2c_hw *dcn31_i2c_hw_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dce_i2c_hw *dce_i2c_hw = + kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL); + + if (!dce_i2c_hw) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT i2c_hw_regs + i2c_inst_regs_init(1), + i2c_inst_regs_init(2), + i2c_inst_regs_init(3), + i2c_inst_regs_init(4), + i2c_inst_regs_init(5); + + dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst, + &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks); + + return dce_i2c_hw; +} +static struct mpc *dcn35_mpc_create( + struct dc_context *ctx, + int num_mpcc, + int num_rmu) +{ + struct dcn30_mpc *mpc30 = kzalloc(sizeof(struct dcn30_mpc), GFP_KERNEL); + + if (!mpc30) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT mpc_regs + dcn_mpc_regs_init(); + + dcn32_mpc_construct(mpc30, ctx, + &mpc_regs, + &mpc_shift, + &mpc_mask, + num_mpcc, + num_rmu); + + return &mpc30->base; +} + +static struct hubbub *dcn35_hubbub_create(struct dc_context *ctx) +{ + int i; + + struct dcn20_hubbub *hubbub3 = kzalloc(sizeof(struct dcn20_hubbub), + GFP_KERNEL); + + if (!hubbub3) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT hubbub_reg + hubbub_reg_init(); + +#undef REG_STRUCT +#define REG_STRUCT vmid_regs + vmid_regs_init(0), + vmid_regs_init(1), + vmid_regs_init(2), + vmid_regs_init(3), + vmid_regs_init(4), + vmid_regs_init(5), + vmid_regs_init(6), + vmid_regs_init(7), + vmid_regs_init(8), + vmid_regs_init(9), + vmid_regs_init(10), + vmid_regs_init(11), + vmid_regs_init(12), + vmid_regs_init(13), + vmid_regs_init(14), + vmid_regs_init(15); + + hubbub35_construct(hubbub3, ctx, + &hubbub_reg, + &hubbub_shift, + &hubbub_mask, + 384,/*ctx->dc->dml.ip.det_buffer_size_kbytes,*/ + 8, /*ctx->dc->dml.ip.pixel_chunk_size_kbytes,*/ + 1792 /*ctx->dc->dml.ip.config_return_buffer_size_in_kbytes*/); + + + for (i = 0; i < res_cap_dcn35.num_vmid; i++) { + struct dcn20_vmid *vmid = &hubbub3->vmid[i]; + + vmid->ctx = ctx; + + vmid->regs = &vmid_regs[i]; + vmid->shifts = &vmid_shifts; + vmid->masks = &vmid_masks; + } + + return &hubbub3->base; +} + +static struct timing_generator *dcn35_timing_generator_create( + struct dc_context *ctx, + uint32_t instance) +{ + struct optc *tgn10 = + kzalloc(sizeof(struct optc), GFP_KERNEL); + + if (!tgn10) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT optc_regs + optc_regs_init(0), + optc_regs_init(1), + optc_regs_init(2), + optc_regs_init(3); + + tgn10->base.inst = instance; + tgn10->base.ctx = ctx; + + tgn10->tg_regs = &optc_regs[instance]; + tgn10->tg_shift = &optc_shift; + tgn10->tg_mask = &optc_mask; + + dcn35_timing_generator_init(tgn10); + + return &tgn10->base; +} + +static const struct encoder_feature_support link_enc_feature = { + .max_hdmi_deep_color = COLOR_DEPTH_121212, + .max_hdmi_pixel_clock = 600000, + .hdmi_ycbcr420_supported = true, + .dp_ycbcr420_supported = true, + .fec_supported = true, + .flags.bits.IS_HBR2_CAPABLE = true, + .flags.bits.IS_HBR3_CAPABLE = true, + .flags.bits.IS_TPS3_CAPABLE = true, + .flags.bits.IS_TPS4_CAPABLE = true +}; + +static struct link_encoder *dcn35_link_encoder_create( + struct dc_context *ctx, + const struct encoder_init_data *enc_init_data) +{ + struct dcn20_link_encoder *enc20 = + kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); + + if (!enc20) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT link_enc_aux_regs + aux_regs_init(0), + aux_regs_init(1), + aux_regs_init(2), + aux_regs_init(3), + aux_regs_init(4); + +#undef REG_STRUCT +#define REG_STRUCT link_enc_hpd_regs + hpd_regs_init(0), + hpd_regs_init(1), + hpd_regs_init(2), + hpd_regs_init(3), + hpd_regs_init(4); + +#undef REG_STRUCT +#define REG_STRUCT link_enc_regs + link_regs_init(0, A), + link_regs_init(1, B), + link_regs_init(2, C), + link_regs_init(3, D), + link_regs_init(4, E); + + dcn35_link_encoder_construct(enc20, + enc_init_data, + &link_enc_feature, + &link_enc_regs[enc_init_data->transmitter], + &link_enc_aux_regs[enc_init_data->channel - 1], + &link_enc_hpd_regs[enc_init_data->hpd_source], + &le_shift, + &le_mask); + + return &enc20->enc10.base; +} + +/* Create a minimal link encoder object not associated with a particular + * physical connector. + * resource_funcs.link_enc_create_minimal + */ +static struct link_encoder *dcn31_link_enc_create_minimal( + struct dc_context *ctx, enum engine_id eng_id) +{ + struct dcn20_link_encoder *enc20; + + if ((eng_id - ENGINE_ID_DIGA) > ctx->dc->res_pool->res_cap->num_dig_link_enc) + return NULL; + + enc20 = kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); + if (!enc20) + return NULL; + + dcn31_link_encoder_construct_minimal( + enc20, + ctx, + &link_enc_feature, + &link_enc_regs[eng_id - ENGINE_ID_DIGA], + eng_id); + + return &enc20->enc10.base; +} + +static struct panel_cntl *dcn31_panel_cntl_create(const struct panel_cntl_init_data *init_data) +{ + struct dcn31_panel_cntl *panel_cntl = + kzalloc(sizeof(struct dcn31_panel_cntl), GFP_KERNEL); + + if (!panel_cntl) + return NULL; + + dcn31_panel_cntl_construct(panel_cntl, init_data); + + return &panel_cntl->base; +} + +static void read_dce_straps( + struct dc_context *ctx, + struct resource_straps *straps) +{ + generic_reg_get(ctx, regDC_PINSTRAPS + BASE(regDC_PINSTRAPS_BASE_IDX), + FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio); + +} + +static struct audio *dcn31_create_audio( + struct dc_context *ctx, unsigned int inst) +{ + +#undef REG_STRUCT +#define REG_STRUCT audio_regs + audio_regs_init(0), + audio_regs_init(1), + audio_regs_init(2), + audio_regs_init(3), + audio_regs_init(4); + audio_regs_init(5); + audio_regs_init(6); + + return dce_audio_create(ctx, inst, + &audio_regs[inst], &audio_shift, &audio_mask); +} + +static struct vpg *dcn31_vpg_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn31_vpg *vpg31 = kzalloc(sizeof(struct dcn31_vpg), GFP_KERNEL); + + if (!vpg31) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT vpg_regs + vpg_regs_init(0), + vpg_regs_init(1), + vpg_regs_init(2), + vpg_regs_init(3), + vpg_regs_init(4), + vpg_regs_init(5), + vpg_regs_init(6), + vpg_regs_init(7), + vpg_regs_init(8), + vpg_regs_init(9); + + vpg31_construct(vpg31, ctx, inst, + &vpg_regs[inst], + &vpg_shift, + &vpg_mask); + + return &vpg31->base; +} + +static struct afmt *dcn31_afmt_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn31_afmt *afmt31 = kzalloc(sizeof(struct dcn31_afmt), GFP_KERNEL); + + if (!afmt31) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT afmt_regs + afmt_regs_init(0), + afmt_regs_init(1), + afmt_regs_init(2), + afmt_regs_init(3), + afmt_regs_init(4), + afmt_regs_init(5); + + afmt31_construct(afmt31, ctx, inst, + &afmt_regs[inst], + &afmt_shift, + &afmt_mask); + + // Light sleep by default, no need to power down here + + return &afmt31->base; +} + +static struct apg *dcn31_apg_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn31_apg *apg31 = kzalloc(sizeof(struct dcn31_apg), GFP_KERNEL); + + if (!apg31) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT apg_regs + apg_regs_init(0), + apg_regs_init(1), + apg_regs_init(2), + apg_regs_init(3); + + apg31_construct(apg31, ctx, inst, + &apg_regs[inst], + &apg_shift, + &apg_mask); + + return &apg31->base; +} + +static struct stream_encoder *dcn35_stream_encoder_create( + enum engine_id eng_id, + struct dc_context *ctx) +{ + struct dcn10_stream_encoder *enc1; + struct vpg *vpg; + struct afmt *afmt; + int vpg_inst; + int afmt_inst; + + /* Mapping of VPG, AFMT, DME register blocks to DIO block instance */ + if (eng_id <= ENGINE_ID_DIGF) { + vpg_inst = eng_id; + afmt_inst = eng_id; + } else + return NULL; + + enc1 = kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL); + vpg = dcn31_vpg_create(ctx, vpg_inst); + afmt = dcn31_afmt_create(ctx, afmt_inst); + + if (!enc1 || !vpg || !afmt) { + kfree(enc1); + kfree(vpg); + kfree(afmt); + return NULL; + } + +#undef REG_STRUCT +#define REG_STRUCT stream_enc_regs + stream_enc_regs_init(0), + stream_enc_regs_init(1), + stream_enc_regs_init(2), + stream_enc_regs_init(3), + stream_enc_regs_init(4); + + dcn35_dio_stream_encoder_construct(enc1, ctx, ctx->dc_bios, + eng_id, vpg, afmt, + &stream_enc_regs[eng_id], + &se_shift, &se_mask); + + return &enc1->base; +} + +static struct hpo_dp_stream_encoder *dcn31_hpo_dp_stream_encoder_create( + enum engine_id eng_id, + struct dc_context *ctx) +{ + struct dcn31_hpo_dp_stream_encoder *hpo_dp_enc31; + struct vpg *vpg; + struct apg *apg; + uint32_t hpo_dp_inst; + uint32_t vpg_inst; + uint32_t apg_inst; + + ASSERT((eng_id >= ENGINE_ID_HPO_DP_0) && (eng_id <= ENGINE_ID_HPO_DP_3)); + hpo_dp_inst = eng_id - ENGINE_ID_HPO_DP_0; + + /* Mapping of VPG register blocks to HPO DP block instance: + * VPG[6] -> HPO_DP[0] + * VPG[7] -> HPO_DP[1] + * VPG[8] -> HPO_DP[2] + * VPG[9] -> HPO_DP[3] + */ + vpg_inst = hpo_dp_inst + 6; + + /* Mapping of APG register blocks to HPO DP block instance: + * APG[0] -> HPO_DP[0] + * APG[1] -> HPO_DP[1] + * APG[2] -> HPO_DP[2] + * APG[3] -> HPO_DP[3] + */ + apg_inst = hpo_dp_inst; + + /* allocate HPO stream encoder and create VPG sub-block */ + hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_stream_encoder), GFP_KERNEL); + vpg = dcn31_vpg_create(ctx, vpg_inst); + apg = dcn31_apg_create(ctx, apg_inst); + + if (!hpo_dp_enc31 || !vpg || !apg) { + kfree(hpo_dp_enc31); + kfree(vpg); + kfree(apg); + return NULL; + } + +#undef REG_STRUCT +#define REG_STRUCT hpo_dp_stream_enc_regs + hpo_dp_stream_encoder_reg_init(0), + hpo_dp_stream_encoder_reg_init(1), + hpo_dp_stream_encoder_reg_init(2), + hpo_dp_stream_encoder_reg_init(3); + + dcn31_hpo_dp_stream_encoder_construct(hpo_dp_enc31, ctx, ctx->dc_bios, + hpo_dp_inst, eng_id, vpg, apg, + &hpo_dp_stream_enc_regs[hpo_dp_inst], + &hpo_dp_se_shift, &hpo_dp_se_mask); + + return &hpo_dp_enc31->base; +} + +static struct hpo_dp_link_encoder *dcn31_hpo_dp_link_encoder_create( + uint8_t inst, + struct dc_context *ctx) +{ + struct dcn31_hpo_dp_link_encoder *hpo_dp_enc31; + + /* allocate HPO link encoder */ + hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_link_encoder), GFP_KERNEL); + +#undef REG_STRUCT +#define REG_STRUCT hpo_dp_link_enc_regs + hpo_dp_link_encoder_reg_init(0), + hpo_dp_link_encoder_reg_init(1); + + hpo_dp_link_encoder31_construct(hpo_dp_enc31, ctx, inst, + &hpo_dp_link_enc_regs[inst], + &hpo_dp_le_shift, &hpo_dp_le_mask); + + return &hpo_dp_enc31->base; +} + +static struct dce_hwseq *dcn35_hwseq_create( + struct dc_context *ctx) +{ + struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); + +#undef REG_STRUCT +#define REG_STRUCT hwseq_reg + hwseq_reg_init(); + + if (hws) { + hws->ctx = ctx; + hws->regs = &hwseq_reg; + hws->shifts = &hwseq_shift; + hws->masks = &hwseq_mask; + } + return hws; +} +static const struct resource_create_funcs res_create_funcs = { + .read_dce_straps = read_dce_straps, + .create_audio = dcn31_create_audio, + .create_stream_encoder = dcn35_stream_encoder_create, + .create_hpo_dp_stream_encoder = dcn31_hpo_dp_stream_encoder_create, + .create_hpo_dp_link_encoder = dcn31_hpo_dp_link_encoder_create, + .create_hwseq = dcn35_hwseq_create, +}; + +static void dcn35_resource_destruct(struct dcn35_resource_pool *pool) +{ + unsigned int i; + + for (i = 0; i < pool->base.stream_enc_count; i++) { + if (pool->base.stream_enc[i] != NULL) { + if (pool->base.stream_enc[i]->vpg != NULL) { + kfree(DCN30_VPG_FROM_VPG(pool->base.stream_enc[i]->vpg)); + pool->base.stream_enc[i]->vpg = NULL; + } + if (pool->base.stream_enc[i]->afmt != NULL) { + kfree(DCN30_AFMT_FROM_AFMT(pool->base.stream_enc[i]->afmt)); + pool->base.stream_enc[i]->afmt = NULL; + } + kfree(DCN10STRENC_FROM_STRENC(pool->base.stream_enc[i])); + pool->base.stream_enc[i] = NULL; + } + } + + for (i = 0; i < pool->base.hpo_dp_stream_enc_count; i++) { + if (pool->base.hpo_dp_stream_enc[i] != NULL) { + if (pool->base.hpo_dp_stream_enc[i]->vpg != NULL) { + kfree(DCN30_VPG_FROM_VPG(pool->base.hpo_dp_stream_enc[i]->vpg)); + pool->base.hpo_dp_stream_enc[i]->vpg = NULL; + } + if (pool->base.hpo_dp_stream_enc[i]->apg != NULL) { + kfree(DCN31_APG_FROM_APG(pool->base.hpo_dp_stream_enc[i]->apg)); + pool->base.hpo_dp_stream_enc[i]->apg = NULL; + } + kfree(DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(pool->base.hpo_dp_stream_enc[i])); + pool->base.hpo_dp_stream_enc[i] = NULL; + } + } + + for (i = 0; i < pool->base.hpo_dp_link_enc_count; i++) { + if (pool->base.hpo_dp_link_enc[i] != NULL) { + kfree(DCN3_1_HPO_DP_LINK_ENC_FROM_HPO_LINK_ENC(pool->base.hpo_dp_link_enc[i])); + pool->base.hpo_dp_link_enc[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_dsc; i++) { + if (pool->base.dscs[i] != NULL) + dcn20_dsc_destroy(&pool->base.dscs[i]); + } + + if (pool->base.mpc != NULL) { + kfree(TO_DCN20_MPC(pool->base.mpc)); + pool->base.mpc = NULL; + } + if (pool->base.hubbub != NULL) { + kfree(pool->base.hubbub); + pool->base.hubbub = NULL; + } + for (i = 0; i < pool->base.pipe_count; i++) { + if (pool->base.dpps[i] != NULL) + dcn35_dpp_destroy(&pool->base.dpps[i]); + + if (pool->base.ipps[i] != NULL) + pool->base.ipps[i]->funcs->ipp_destroy(&pool->base.ipps[i]); + + if (pool->base.hubps[i] != NULL) { + kfree(TO_DCN20_HUBP(pool->base.hubps[i])); + pool->base.hubps[i] = NULL; + } + + if (pool->base.irqs != NULL) { + dal_irq_service_destroy(&pool->base.irqs); + } + } + + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + if (pool->base.engines[i] != NULL) + dce110_engine_destroy(&pool->base.engines[i]); + if (pool->base.hw_i2cs[i] != NULL) { + kfree(pool->base.hw_i2cs[i]); + pool->base.hw_i2cs[i] = NULL; + } + if (pool->base.sw_i2cs[i] != NULL) { + kfree(pool->base.sw_i2cs[i]); + pool->base.sw_i2cs[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_opp; i++) { + if (pool->base.opps[i] != NULL) + pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]); + } + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + if (pool->base.timing_generators[i] != NULL) { + kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i])); + pool->base.timing_generators[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_dwb; i++) { + if (pool->base.dwbc[i] != NULL) { + kfree(TO_DCN30_DWBC(pool->base.dwbc[i])); + pool->base.dwbc[i] = NULL; + } + if (pool->base.mcif_wb[i] != NULL) { + kfree(TO_DCN30_MMHUBBUB(pool->base.mcif_wb[i])); + pool->base.mcif_wb[i] = NULL; + } + } + + for (i = 0; i < pool->base.audio_count; i++) { + if (pool->base.audios[i]) + dce_aud_destroy(&pool->base.audios[i]); + } + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] != NULL) { + dcn20_clock_source_destroy(&pool->base.clock_sources[i]); + pool->base.clock_sources[i] = NULL; + } + } + + for (i = 0; i < pool->base.res_cap->num_mpc_3dlut; i++) { + if (pool->base.mpc_lut[i] != NULL) { + dc_3dlut_func_release(pool->base.mpc_lut[i]); + pool->base.mpc_lut[i] = NULL; + } + if (pool->base.mpc_shaper[i] != NULL) { + dc_transfer_func_release(pool->base.mpc_shaper[i]); + pool->base.mpc_shaper[i] = NULL; + } + } + + if (pool->base.dp_clock_source != NULL) { + dcn20_clock_source_destroy(&pool->base.dp_clock_source); + pool->base.dp_clock_source = NULL; + } + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + if (pool->base.multiple_abms[i] != NULL) + dce_abm_destroy(&pool->base.multiple_abms[i]); + } + + if (pool->base.psr != NULL) + dmub_psr_destroy(&pool->base.psr); + + if (pool->base.replay != NULL) + dmub_replay_destroy(&pool->base.replay); + + if (pool->base.pg_cntl != NULL) + dcn_pg_cntl_destroy(&pool->base.pg_cntl); + + if (pool->base.dccg != NULL) + dcn_dccg_destroy(&pool->base.dccg); +} + +static struct hubp *dcn35_hubp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn20_hubp *hubp2 = + kzalloc(sizeof(struct dcn20_hubp), GFP_KERNEL); + + if (!hubp2) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT hubp_regs + hubp_regs_init(0), + hubp_regs_init(1), + hubp_regs_init(2), + hubp_regs_init(3); + + if (hubp35_construct(hubp2, ctx, inst, + &hubp_regs[inst], &hubp_shift, &hubp_mask)) + return &hubp2->base; + + BREAK_TO_DEBUGGER(); + kfree(hubp2); + return NULL; +} + +static void dcn35_dwbc_init(struct dcn30_dwbc *dwbc30, struct dc_context *ctx) +{ + dcn35_dwbc_set_fgcg( + dwbc30, ctx->dc->debug.enable_fine_grain_clock_gating.bits.dwb); +} + +static bool dcn35_dwbc_create(struct dc_context *ctx, struct resource_pool *pool) +{ + int i; + uint32_t pipe_count = pool->res_cap->num_dwb; + + for (i = 0; i < pipe_count; i++) { + struct dcn30_dwbc *dwbc30 = kzalloc(sizeof(struct dcn30_dwbc), + GFP_KERNEL); + + if (!dwbc30) { + dm_error("DC: failed to create dwbc30!\n"); + return false; + } + +#undef REG_STRUCT +#define REG_STRUCT dwbc35_regs + dwbc_regs_dcn3_init(0); + + dcn35_dwbc_construct(dwbc30, ctx, + &dwbc35_regs[i], + &dwbc35_shift, + &dwbc35_mask, + i); + + pool->dwbc[i] = &dwbc30->base; + + dcn35_dwbc_init(dwbc30, ctx); + } + return true; +} + +static void dcn35_mmhubbub_init(struct dcn30_mmhubbub *mcif_wb30, + struct dc_context *ctx) +{ + dcn35_mmhubbub_set_fgcg( + mcif_wb30, + ctx->dc->debug.enable_fine_grain_clock_gating.bits.mmhubbub); +} + +static bool dcn35_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool) +{ + int i; + uint32_t pipe_count = pool->res_cap->num_dwb; + + for (i = 0; i < pipe_count; i++) { + struct dcn30_mmhubbub *mcif_wb30 = kzalloc(sizeof(struct dcn30_mmhubbub), + GFP_KERNEL); + + if (!mcif_wb30) { + dm_error("DC: failed to create mcif_wb30!\n"); + return false; + } + +#undef REG_STRUCT +#define REG_STRUCT mcif_wb35_regs + mcif_wb_regs_dcn3_init(0); + + dcn35_mmhubbub_construct(mcif_wb30, ctx, + &mcif_wb35_regs[i], + &mcif_wb35_shift, + &mcif_wb35_mask, + i); + + dcn35_mmhubbub_init(mcif_wb30, ctx); + + pool->mcif_wb[i] = &mcif_wb30->base; + } + return true; +} + +static struct display_stream_compressor *dcn35_dsc_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dcn20_dsc *dsc = + kzalloc(sizeof(struct dcn20_dsc), GFP_KERNEL); + + if (!dsc) { + BREAK_TO_DEBUGGER(); + return NULL; + } + +#undef REG_STRUCT +#define REG_STRUCT dsc_regs + dsc_regsDCN35_init(0), + dsc_regsDCN35_init(1), + dsc_regsDCN35_init(2), + dsc_regsDCN35_init(3); + + dsc35_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask); + dsc35_set_fgcg(dsc, + ctx->dc->debug.enable_fine_grain_clock_gating.bits.dsc); + return &dsc->base; +} + +static void dcn35_destroy_resource_pool(struct resource_pool **pool) +{ + struct dcn35_resource_pool *dcn35_pool = TO_DCN35_RES_POOL(*pool); + + dcn35_resource_destruct(dcn35_pool); + kfree(dcn35_pool); + *pool = NULL; +} + +static struct clock_source *dcn35_clock_source_create( + struct dc_context *ctx, + struct dc_bios *bios, + enum clock_source_id id, + const struct dce110_clk_src_regs *regs, + bool dp_clk_src) +{ + struct dce110_clk_src *clk_src = + kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); + + if (!clk_src) + return NULL; + + if (dcn31_clk_src_construct(clk_src, ctx, bios, id, + regs, &cs_shift, &cs_mask)) { + clk_src->base.dp_clk_src = dp_clk_src; + return &clk_src->base; + } + + BREAK_TO_DEBUGGER(); + return NULL; +} + +static struct dc_cap_funcs cap_funcs = { + .get_dcc_compression_cap = dcn20_get_dcc_compression_cap +}; + +static void dcn35_get_panel_config_defaults(struct dc_panel_config *panel_config) +{ + *panel_config = panel_config_defaults; +} + + +static bool dcn35_validate_bandwidth(struct dc *dc, + struct dc_state *context, + bool fast_validate) +{ + bool out = false; + + out = dml2_validate(dc, context, fast_validate); + + if (fast_validate) + return out; + + DC_FP_START(); + dcn35_decide_zstate_support(dc, context); + DC_FP_END(); + + return out; +} + + +static struct resource_funcs dcn35_res_pool_funcs = { + .destroy = dcn35_destroy_resource_pool, + .link_enc_create = dcn35_link_encoder_create, + .link_enc_create_minimal = dcn31_link_enc_create_minimal, + .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 = dcn35_validate_bandwidth, + .calculate_wm_and_dlg = NULL, + .update_soc_for_wm_a = dcn31_update_soc_for_wm_a, + .populate_dml_pipes = dcn35_populate_dml_pipes_from_context_fpu, + .acquire_free_pipe_as_secondary_dpp_pipe = dcn20_acquire_free_pipe_for_layer, + .release_pipe = dcn20_release_pipe, + .add_stream_to_ctx = dcn30_add_stream_to_ctx, + .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource, + .remove_stream_from_ctx = dcn20_remove_stream_from_ctx, + .populate_dml_writeback_from_context = dcn30_populate_dml_writeback_from_context, + .set_mcif_arb_params = dcn30_set_mcif_arb_params, + .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 = dcn35_update_bw_bounding_box_fpu, + .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, + .get_panel_config_defaults = dcn35_get_panel_config_defaults, + .get_preferred_eng_id_dpia = dcn35_get_preferred_eng_id_dpia, +}; + +static bool dcn35_resource_construct( + uint8_t num_virtual_links, + struct dc *dc, + struct dcn35_resource_pool *pool) +{ + int i; + struct dc_context *ctx = dc->ctx; + struct irq_service_init_data init_data; + +#undef REG_STRUCT +#define REG_STRUCT bios_regs + bios_regs_init(); + +#undef REG_STRUCT +#define REG_STRUCT clk_src_regs + clk_src_regs_init(0, A), + clk_src_regs_init(1, B), + clk_src_regs_init(2, C), + clk_src_regs_init(3, D), + clk_src_regs_init(4, E); + +#undef REG_STRUCT +#define REG_STRUCT abm_regs + abm_regs_init(0), + abm_regs_init(1), + abm_regs_init(2), + abm_regs_init(3); + +#undef REG_STRUCT +#define REG_STRUCT dccg_regs + dccg_regs_init(); + + ctx->dc_bios->regs = &bios_regs; + + pool->base.res_cap = &res_cap_dcn35; + + pool->base.funcs = &dcn35_res_pool_funcs; + + /************************************************* + * Resource + asic cap harcoding * + *************************************************/ + pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + pool->base.pipe_count = pool->base.res_cap->num_timing_generator; + 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.max_cursor_size = 256; + dc->caps.min_horizontal_blanking_period = 80; + dc->caps.dmdata_alloc_size = 2048; + dc->caps.max_slave_planes = 2; + dc->caps.max_slave_yuv_planes = 2; + dc->caps.max_slave_rgb_planes = 2; + dc->caps.post_blend_color_processing = true; + dc->caps.force_dp_tps4_for_cp2520 = true; + if (dc->config.forceHBR2CP2520) + dc->caps.force_dp_tps4_for_cp2520 = false; + dc->caps.dp_hpo = true; + dc->caps.dp_hdmi21_pcon_support = true; + + dc->caps.edp_dsc_support = true; + dc->caps.extended_aux_timeout_support = true; + dc->caps.dmcub_support = true; + dc->caps.is_apu = true; + dc->caps.seamless_odm = true; + + dc->caps.zstate_support = true; + dc->caps.ips_support = true; + dc->caps.max_v_total = (1 << 15) - 1; + + /* Color pipeline capabilities */ + dc->caps.color.dpp.dcn_arch = 1; + dc->caps.color.dpp.input_lut_shared = 0; + dc->caps.color.dpp.icsc = 1; + dc->caps.color.dpp.dgam_ram = 0; // must use gamma_corr + dc->caps.color.dpp.dgam_rom_caps.srgb = 1; + dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1; + dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 1; + dc->caps.color.dpp.dgam_rom_caps.pq = 1; + dc->caps.color.dpp.dgam_rom_caps.hlg = 1; + dc->caps.color.dpp.post_csc = 1; + dc->caps.color.dpp.gamma_corr = 1; + dc->caps.color.dpp.dgam_rom_for_yuv = 0; + + dc->caps.color.dpp.hw_3d_lut = 1; + dc->caps.color.dpp.ogam_ram = 0; // no OGAM in DPP since DCN1 + // no OGAM ROM on DCN301 + dc->caps.color.dpp.ogam_rom_caps.srgb = 0; + dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0; + dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0; + dc->caps.color.dpp.ogam_rom_caps.pq = 0; + dc->caps.color.dpp.ogam_rom_caps.hlg = 0; + dc->caps.color.dpp.ocsc = 0; + + dc->caps.color.mpc.gamut_remap = 1; + dc->caps.color.mpc.num_3dluts = pool->base.res_cap->num_mpc_3dlut; //2 + dc->caps.color.mpc.ogam_ram = 1; + dc->caps.color.mpc.ogam_rom_caps.srgb = 0; + dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0; + dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0; + dc->caps.color.mpc.ogam_rom_caps.pq = 0; + dc->caps.color.mpc.ogam_rom_caps.hlg = 0; + dc->caps.color.mpc.ocsc = 1; + + /* max_disp_clock_khz_at_vmin is slightly lower than the STA value in order + * to provide some margin. + * It's expected for furture ASIC to have equal or higher value, in order to + * have determinstic power improvement from generate to genration. + * (i.e., we should not expect new ASIC generation with lower vmin rate) + */ + dc->caps.max_disp_clock_khz_at_vmin = 650000; + + /* Use pipe context based otg sync logic */ + dc->config.use_pipe_ctx_sync_logic = true; + + /* read VBIOS LTTPR caps */ + { + if (ctx->dc_bios->funcs->get_lttpr_caps) { + enum bp_result bp_query_result; + uint8_t is_vbios_lttpr_enable = 0; + + bp_query_result = ctx->dc_bios->funcs->get_lttpr_caps(ctx->dc_bios, &is_vbios_lttpr_enable); + dc->caps.vbios_lttpr_enable = (bp_query_result == BP_RESULT_OK) && !!is_vbios_lttpr_enable; + } + + /* interop bit is implicit */ + { + dc->caps.vbios_lttpr_aware = true; + } + } + + if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) + dc->debug = debug_defaults_drv; + + // Init the vm_helper + if (dc->vm_helper) + vm_helper_init(dc->vm_helper, 16); + + /************************************************* + * Create resources * + *************************************************/ + + /* Clock Sources for Pixel Clock*/ + pool->base.clock_sources[DCN35_CLK_SRC_PLL0] = + dcn35_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL0, + &clk_src_regs[0], false); + pool->base.clock_sources[DCN35_CLK_SRC_PLL1] = + dcn35_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL1, + &clk_src_regs[1], false); + pool->base.clock_sources[DCN35_CLK_SRC_PLL2] = + dcn35_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL2, + &clk_src_regs[2], false); + pool->base.clock_sources[DCN35_CLK_SRC_PLL3] = + dcn35_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL3, + &clk_src_regs[3], false); + pool->base.clock_sources[DCN35_CLK_SRC_PLL4] = + dcn35_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL4, + &clk_src_regs[4], false); + + pool->base.clk_src_count = DCN35_CLK_SRC_TOTAL; + + /* todo: not reuse phy_pll registers */ + pool->base.dp_clock_source = + dcn35_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_ID_DP_DTO, + &clk_src_regs[0], true); + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] == NULL) { + dm_error("DC: failed to create clock sources!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + } + /*temp till dml2 fully work without dml1*/ + dml_init_instance(&dc->dml, &dcn3_5_soc, &dcn3_5_ip, DML_PROJECT_DCN31); + + /* TODO: DCCG */ + pool->base.dccg = dccg35_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask); + if (pool->base.dccg == NULL) { + dm_error("DC: failed to create dccg!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + +#undef REG_STRUCT +#define REG_STRUCT pg_cntl_regs + pg_cntl_dcn35_regs_init(); + + pool->base.pg_cntl = pg_cntl35_create(ctx, &pg_cntl_regs, &pg_cntl_shift, &pg_cntl_mask); + if (pool->base.pg_cntl == NULL) { + dm_error("DC: failed to create power gate control!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + /* TODO: IRQ */ + init_data.ctx = dc->ctx; + pool->base.irqs = dal_irq_service_dcn35_create(&init_data); + if (!pool->base.irqs) + goto create_fail; + + /* HUBBUB */ + pool->base.hubbub = dcn35_hubbub_create(ctx); + if (pool->base.hubbub == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create hubbub!\n"); + goto create_fail; + } + + /* HUBPs, DPPs, OPPs and TGs */ + for (i = 0; i < pool->base.pipe_count; i++) { + pool->base.hubps[i] = dcn35_hubp_create(ctx, i); + if (pool->base.hubps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create hubps!\n"); + goto create_fail; + } + + pool->base.dpps[i] = dcn35_dpp_create(ctx, i); + if (pool->base.dpps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create dpps!\n"); + goto create_fail; + } + } + + for (i = 0; i < pool->base.res_cap->num_opp; i++) { + pool->base.opps[i] = dcn35_opp_create(ctx, i); + if (pool->base.opps[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create output pixel processor!\n"); + goto create_fail; + } + } + + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + pool->base.timing_generators[i] = dcn35_timing_generator_create( + ctx, i); + if (pool->base.timing_generators[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create tg!\n"); + goto create_fail; + } + } + pool->base.timing_generator_count = i; + + /* PSR */ + pool->base.psr = dmub_psr_create(ctx); + if (pool->base.psr == NULL) { + dm_error("DC: failed to create psr obj!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + /* Replay */ + pool->base.replay = dmub_replay_create(ctx); + if (pool->base.replay == NULL) { + dm_error("DC: failed to create replay obj!\n"); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + + /* ABM */ + for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) { + pool->base.multiple_abms[i] = dmub_abm_create(ctx, + &abm_regs[i], + &abm_shift, + &abm_mask); + if (pool->base.multiple_abms[i] == NULL) { + dm_error("DC: failed to create abm for pipe %d!\n", i); + BREAK_TO_DEBUGGER(); + goto create_fail; + } + } + + /* MPC and DSC */ + pool->base.mpc = dcn35_mpc_create(ctx, pool->base.mpcc_count, pool->base.res_cap->num_mpc_3dlut); + if (pool->base.mpc == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create mpc!\n"); + goto create_fail; + } + + for (i = 0; i < pool->base.res_cap->num_dsc; i++) { + pool->base.dscs[i] = dcn35_dsc_create(ctx, i); + if (pool->base.dscs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create display stream compressor %d!\n", i); + goto create_fail; + } + } + + /* DWB and MMHUBBUB */ + if (!dcn35_dwbc_create(ctx, &pool->base)) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dwbc!\n"); + goto create_fail; + } + + if (!dcn35_mmhubbub_create(ctx, &pool->base)) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create mcif_wb!\n"); + goto create_fail; + } + + /* AUX and I2C */ + for (i = 0; i < pool->base.res_cap->num_ddc; i++) { + pool->base.engines[i] = dcn31_aux_engine_create(ctx, i); + if (pool->base.engines[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create aux engine!!\n"); + goto create_fail; + } + pool->base.hw_i2cs[i] = dcn31_i2c_hw_create(ctx, i); + if (pool->base.hw_i2cs[i] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC:failed to create hw i2c!!\n"); + goto create_fail; + } + pool->base.sw_i2cs[i] = NULL; + } + + /* DCN3.5 has 6 DPIA */ + pool->base.usb4_dpia_count = 4; + if (dc->debug.dpia_debug.bits.disable_dpia) + pool->base.usb4_dpia_count = 0; + + /* Audio, Stream Encoders including HPO and virtual, MPC 3D LUTs */ + if (!resource_construct(num_virtual_links, dc, &pool->base, + &res_create_funcs)) + goto create_fail; + + /* HW Sequencer and Plane caps */ + dcn35_hw_sequencer_construct(dc); + + dc->caps.max_planes = pool->base.pipe_count; + + for (i = 0; i < dc->caps.max_planes; ++i) + dc->caps.planes[i] = plane_cap; + + dc->cap_funcs = cap_funcs; + + dc->dcn_ip->max_num_dpp = pool->base.pipe_count; + + dc->dml2_options.dcn_pipe_count = pool->base.pipe_count; + dc->dml2_options.use_native_pstate_optimization = true; + dc->dml2_options.use_native_soc_bb_construction = true; + if (dc->config.EnableMinDispClkODM) + dc->dml2_options.minimize_dispclk_using_odm = true; + dc->dml2_options.enable_windowed_mpo_odm = dc->config.enable_windowed_mpo_odm; + + dc->dml2_options.callbacks.dc = dc; + dc->dml2_options.callbacks.build_scaling_params = &resource_build_scaling_params; + dc->dml2_options.callbacks.can_support_mclk_switch_using_fw_based_vblank_stretch = &dcn30_can_support_mclk_switch_using_fw_based_vblank_stretch; + dc->dml2_options.callbacks.acquire_secondary_pipe_for_mpc_odm = &dc_resource_acquire_secondary_pipe_for_mpc_odm_legacy; + dc->dml2_options.callbacks.update_pipes_for_stream_with_slice_count = &resource_update_pipes_for_stream_with_slice_count; + dc->dml2_options.callbacks.update_pipes_for_plane_with_slice_count = &resource_update_pipes_for_plane_with_slice_count; + dc->dml2_options.callbacks.get_mpc_slice_index = &resource_get_mpc_slice_index; + dc->dml2_options.callbacks.get_odm_slice_index = &resource_get_odm_slice_index; + dc->dml2_options.callbacks.get_opp_head = &resource_get_opp_head; + dc->dml2_options.max_segments_per_hubp = 24; + + dc->dml2_options.det_segment_size = DCN3_2_DET_SEG_SIZE;/*todo*/ + + if (dc->config.sdpif_request_limit_words_per_umc == 0) + dc->config.sdpif_request_limit_words_per_umc = 16;/*todo*/ + + return true; + +create_fail: + + dcn35_resource_destruct(pool); + + return false; +} + +struct resource_pool *dcn35_create_resource_pool( + const struct dc_init_data *init_data, + struct dc *dc) +{ + struct dcn35_resource_pool *pool = + kzalloc(sizeof(struct dcn35_resource_pool), GFP_KERNEL); + + if (!pool) + return NULL; + + if (dcn35_resource_construct(init_data->num_virtual_links, dc, pool)) + return &pool->base; + + BREAK_TO_DEBUGGER(); + kfree(pool); + return NULL; +} diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.h b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.h new file mode 100644 index 00000000000000..a51c4a9eaafe58 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.h @@ -0,0 +1,311 @@ +/* SPDX-License-Identifier: MIT */ +/* + * 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 _DCN35_RESOURCE_H_ +#define _DCN35_RESOURCE_H_ + +#include "core_types.h" + +#define DCN3_5_VMIN_DISPCLK_HZ 717000000 +#define TO_DCN35_RES_POOL(pool)\ + container_of(pool, struct dcn35_resource_pool, base) + +extern struct _vcs_dpi_ip_params_st dcn3_5_ip; +extern struct _vcs_dpi_soc_bounding_box_st dcn3_5_soc; + +struct dcn35_resource_pool { + struct resource_pool base; +}; + +struct resource_pool *dcn35_create_resource_pool( + const struct dc_init_data *init_data, + struct dc *dc); + +/* Defs for runtime init of registers */ + +#define OPP_REG_LIST_DCN20_RI(id) \ + OPP_REG_LIST_DCN10_RI(id), \ + OPP_DPG_REG_LIST_RI(id), \ + SRI_ARR(FMT_422_CONTROL, FMT, id), \ + SRI_ARR(OPPBUF_CONTROL1, OPPBUF, id) + +#define OPP_REG_LIST_DCN35_RI(id) \ + OPP_REG_LIST_DCN20_RI(id), \ + SRI2_ARR(OPP_TOP_CLK_CONTROL, OPP, id) + +#define VPG_DCN31_REG_LIST_RI(id) \ + SRI_ARR(VPG_GENERIC_STATUS, VPG, id), \ + SRI_ARR(VPG_GENERIC_PACKET_ACCESS_CTRL, VPG, id), \ + SRI_ARR(VPG_GENERIC_PACKET_DATA, VPG, id), \ + SRI_ARR(VPG_GSP_FRAME_UPDATE_CTRL, VPG, id), \ + SRI_ARR(VPG_GSP_IMMEDIATE_UPDATE_CTRL, VPG, id), \ + SRI_ARR(VPG_MEM_PWR, VPG, id) + +#define AFMT_DCN31_REG_LIST_RI(id) \ + SRI_ARR(AFMT_INFOFRAME_CONTROL0, AFMT, id), \ + SRI_ARR(AFMT_VBI_PACKET_CONTROL, AFMT, id), \ + SRI_ARR(AFMT_AUDIO_PACKET_CONTROL, AFMT, id), \ + SRI_ARR(AFMT_AUDIO_PACKET_CONTROL2, AFMT, id), \ + SRI_ARR(AFMT_AUDIO_SRC_CONTROL, AFMT, id), \ + SRI_ARR(AFMT_60958_0, AFMT, id), \ + SRI_ARR(AFMT_60958_1, AFMT, id), \ + SRI_ARR(AFMT_60958_2, AFMT, id), \ + SRI_ARR(AFMT_MEM_PWR, AFMT, id) + +/* Stream encoder */ +#define SE_DCN35_REG_LIST_RI(id) \ + SRI_ARR(AFMT_CNTL, DIG, id), \ + SRI_ARR(DIG_FE_CNTL, DIG, id), \ + SRI_ARR(HDMI_CONTROL, DIG, id), \ + SRI_ARR(HDMI_DB_CONTROL, DIG, id), \ + SRI_ARR(HDMI_GC, DIG, id), \ + SRI_ARR(HDMI_GENERIC_PACKET_CONTROL0, DIG, id), \ + SRI_ARR(HDMI_GENERIC_PACKET_CONTROL1, DIG, id), \ + SRI_ARR(HDMI_GENERIC_PACKET_CONTROL2, DIG, id), \ + SRI_ARR(HDMI_GENERIC_PACKET_CONTROL3, DIG, id), \ + SRI_ARR(HDMI_GENERIC_PACKET_CONTROL4, DIG, id), \ + SRI_ARR(HDMI_GENERIC_PACKET_CONTROL5, DIG, id), \ + SRI_ARR(HDMI_GENERIC_PACKET_CONTROL6, DIG, id), \ + SRI_ARR(HDMI_GENERIC_PACKET_CONTROL7, DIG, id), \ + SRI_ARR(HDMI_GENERIC_PACKET_CONTROL8, DIG, id), \ + SRI_ARR(HDMI_GENERIC_PACKET_CONTROL9, DIG, id), \ + SRI_ARR(HDMI_GENERIC_PACKET_CONTROL10, DIG, id), \ + SRI_ARR(HDMI_INFOFRAME_CONTROL0, DIG, id), \ + SRI_ARR(HDMI_INFOFRAME_CONTROL1, DIG, id), \ + SRI_ARR(HDMI_VBI_PACKET_CONTROL, DIG, id), \ + SRI_ARR(HDMI_AUDIO_PACKET_CONTROL, DIG, id),\ + SRI_ARR(HDMI_ACR_PACKET_CONTROL, DIG, id),\ + SRI_ARR(HDMI_ACR_32_0, DIG, id),\ + SRI_ARR(HDMI_ACR_32_1, DIG, id),\ + SRI_ARR(HDMI_ACR_44_0, DIG, id),\ + SRI_ARR(HDMI_ACR_44_1, DIG, id),\ + SRI_ARR(HDMI_ACR_48_0, DIG, id),\ + SRI_ARR(HDMI_ACR_48_1, DIG, id),\ + SRI_ARR(DP_DB_CNTL, DP, id), \ + SRI_ARR(DP_MSA_MISC, DP, id), \ + SRI_ARR(DP_MSA_VBID_MISC, DP, id), \ + SRI_ARR(DP_MSA_COLORIMETRY, DP, id), \ + SRI_ARR(DP_MSA_TIMING_PARAM1, DP, id), \ + SRI_ARR(DP_MSA_TIMING_PARAM2, DP, id), \ + SRI_ARR(DP_MSA_TIMING_PARAM3, DP, id), \ + SRI_ARR(DP_MSA_TIMING_PARAM4, DP, id), \ + SRI_ARR(DP_MSE_RATE_CNTL, DP, id), \ + SRI_ARR(DP_MSE_RATE_UPDATE, DP, id), \ + SRI_ARR(DP_PIXEL_FORMAT, DP, id), \ + SRI_ARR(DP_SEC_CNTL, DP, id), \ + SRI_ARR(DP_SEC_CNTL1, DP, id), \ + SRI_ARR(DP_SEC_CNTL2, DP, id), \ + SRI_ARR(DP_SEC_CNTL5, DP, id), \ + SRI_ARR(DP_SEC_CNTL6, DP, id), \ + SRI_ARR(DP_STEER_FIFO, DP, id), \ + SRI_ARR(DP_VID_M, DP, id), \ + SRI_ARR(DP_VID_N, DP, id), \ + SRI_ARR(DP_VID_STREAM_CNTL, DP, id), \ + SRI_ARR(DP_VID_TIMING, DP, id), \ + SRI_ARR(DP_SEC_AUD_N, DP, id), \ + SRI_ARR(DP_SEC_TIMESTAMP, DP, id), \ + SRI_ARR(DP_DSC_CNTL, DP, id), \ + SRI_ARR(DP_SEC_METADATA_TRANSMISSION, DP, id), \ + SRI_ARR(HDMI_METADATA_PACKET_CONTROL, DIG, id), \ + SRI_ARR(DP_SEC_FRAMING4, DP, id), \ + SRI_ARR(DP_GSP11_CNTL, DP, id), \ + SRI_ARR(DME_CONTROL, DME, id),\ + SRI_ARR(DP_SEC_METADATA_TRANSMISSION, DP, id), \ + SRI_ARR(HDMI_METADATA_PACKET_CONTROL, DIG, id), \ + SRI_ARR(DIG_FE_CNTL, DIG, id), \ + SRI_ARR(DIG_FE_EN_CNTL, DIG, id), \ + SRI_ARR(DIG_FE_CLK_CNTL, DIG, id), \ + SRI_ARR(DIG_CLOCK_PATTERN, DIG, id), \ + SRI_ARR(DIG_FIFO_CTRL0, DIG, id), \ + SRI_ARR(STREAM_MAPPER_CONTROL, DIG, id) + +#define LE_DCN35_REG_LIST_RI(id)\ + LE_DCN3_REG_LIST_RI(id),\ + SRI_ARR(DP_DPHY_INTERNAL_CTRL, DP, id), \ + SR_ARR(DIO_LINKA_CNTL, id), \ + SR_ARR(DIO_LINKB_CNTL, id), \ + SR_ARR(DIO_LINKC_CNTL, id), \ + SR_ARR(DIO_LINKD_CNTL, id), \ + SR_ARR(DIO_LINKE_CNTL, id), \ + SR_ARR(DIO_LINKF_CNTL, id),\ + SRI_ARR(DIG_BE_CLK_CNTL, DIG, id),\ + SR_ARR(DIO_CLK_CNTL, id) + +#define MCIF_WB_COMMON_REG_LIST_DCN3_5_RI(inst) \ + MCIF_WB_COMMON_REG_LIST_DCN32_RI(inst), \ + SRI2_ARR(MMHUBBUB_CLOCK_CNTL, MMHUBBUB, inst) + +#define HWSEQ_DCN35_REG_LIST()\ + SR(DCHUBBUB_GLOBAL_TIMER_CNTL), \ + SR(DCHUBBUB_ARB_HOSTVM_CNTL), \ + SR(DIO_MEM_PWR_CTRL), \ + SR(ODM_MEM_PWR_CTRL3), \ + SR(MMHUBBUB_MEM_PWR_CNTL), \ + SR(DCCG_GATE_DISABLE_CNTL), \ + SR(DCCG_GATE_DISABLE_CNTL2), \ + SR(DCCG_GATE_DISABLE_CNTL4), \ + SR(DCCG_GATE_DISABLE_CNTL5), \ + SR(DCFCLK_CNTL),\ + SR(DC_MEM_GLOBAL_PWR_REQ_CNTL), \ + SRII(PIXEL_RATE_CNTL, OTG, 0), \ + SRII(PIXEL_RATE_CNTL, OTG, 1),\ + SRII(PIXEL_RATE_CNTL, OTG, 2),\ + SRII(PIXEL_RATE_CNTL, OTG, 3),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 0),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 1),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 2),\ + SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 3),\ + SR(MICROSECOND_TIME_BASE_DIV), \ + SR(MILLISECOND_TIME_BASE_DIV), \ + SR(DISPCLK_FREQ_CHANGE_CNTL), \ + SR(RBBMIF_TIMEOUT_DIS), \ + SR(RBBMIF_TIMEOUT_DIS_2), \ + SR(DCHUBBUB_CRC_CTRL), \ + SR(DPP_TOP0_DPP_CRC_CTRL), \ + SR(DPP_TOP0_DPP_CRC_VAL_B_A), \ + SR(DPP_TOP0_DPP_CRC_VAL_R_G), \ + SR(MPC_CRC_CTRL), \ + SR(MPC_CRC_RESULT_GB), \ + SR(MPC_CRC_RESULT_C), \ + SR(MPC_CRC_RESULT_AR), \ + SR(DOMAIN0_PG_CONFIG), \ + SR(DOMAIN1_PG_CONFIG), \ + SR(DOMAIN2_PG_CONFIG), \ + SR(DOMAIN3_PG_CONFIG), \ + SR(DOMAIN16_PG_CONFIG), \ + SR(DOMAIN17_PG_CONFIG), \ + SR(DOMAIN18_PG_CONFIG), \ + SR(DOMAIN19_PG_CONFIG), \ + SR(DOMAIN0_PG_STATUS), \ + SR(DOMAIN1_PG_STATUS), \ + SR(DOMAIN2_PG_STATUS), \ + SR(DOMAIN3_PG_STATUS), \ + SR(DOMAIN16_PG_STATUS), \ + SR(DOMAIN17_PG_STATUS), \ + SR(DOMAIN18_PG_STATUS), \ + SR(DOMAIN19_PG_STATUS), \ + SR(DC_IP_REQUEST_CNTL), \ + SR(AZALIA_AUDIO_DTO), \ + SR(AZALIA_CONTROLLER_CLOCK_GATING), \ + SR(HPO_TOP_HW_CONTROL),\ + SR(DMU_CLK_CNTL) + +/* OPTC */ +#define OPTC_COMMON_REG_LIST_DCN3_5_RI(inst) \ + SRI_ARR(OTG_VSTARTUP_PARAM, OTG, inst),\ + SRI_ARR(OTG_VUPDATE_PARAM, OTG, inst),\ + SRI_ARR(OTG_VREADY_PARAM, OTG, inst),\ + SRI_ARR(OTG_MASTER_UPDATE_LOCK, OTG, inst),\ + SRI_ARR(OTG_GLOBAL_CONTROL0, OTG, inst),\ + SRI_ARR(OTG_GLOBAL_CONTROL1, OTG, inst),\ + SRI_ARR(OTG_GLOBAL_CONTROL2, OTG, inst),\ + SRI_ARR(OTG_GLOBAL_CONTROL4, OTG, inst),\ + SRI_ARR(OTG_DOUBLE_BUFFER_CONTROL, OTG, inst),\ + SRI_ARR(OTG_H_TOTAL, OTG, inst),\ + SRI_ARR(OTG_H_BLANK_START_END, OTG, inst),\ + SRI_ARR(OTG_H_SYNC_A, OTG, inst),\ + SRI_ARR(OTG_H_SYNC_A_CNTL, OTG, inst),\ + SRI_ARR(OTG_H_TIMING_CNTL, OTG, inst),\ + SRI_ARR(OTG_V_TOTAL, OTG, inst),\ + SRI_ARR(OTG_V_BLANK_START_END, OTG, inst),\ + SRI_ARR(OTG_V_SYNC_A, OTG, inst),\ + SRI_ARR(OTG_V_SYNC_A_CNTL, OTG, inst),\ + SRI_ARR(OTG_CONTROL, OTG, inst),\ + SRI_ARR(OTG_STEREO_CONTROL, OTG, inst),\ + SRI_ARR(OTG_3D_STRUCTURE_CONTROL, OTG, inst),\ + SRI_ARR(OTG_STEREO_STATUS, OTG, inst),\ + SRI_ARR(OTG_V_TOTAL_MAX, OTG, inst),\ + SRI_ARR(OTG_V_TOTAL_MIN, OTG, inst),\ + SRI_ARR(OTG_V_TOTAL_CONTROL, OTG, inst),\ + SRI_ARR(OTG_TRIGA_CNTL, OTG, inst),\ + SRI_ARR(OTG_FORCE_COUNT_NOW_CNTL, OTG, inst),\ + SRI_ARR(OTG_STATIC_SCREEN_CONTROL, OTG, inst),\ + SRI_ARR(OTG_STATUS_FRAME_COUNT, OTG, inst),\ + SRI_ARR(OTG_STATUS, OTG, inst),\ + SRI_ARR(OTG_STATUS_POSITION, OTG, inst),\ + SRI_ARR(OTG_NOM_VERT_POSITION, OTG, inst),\ + SRI_ARR(OTG_M_CONST_DTO0, OTG, inst),\ + SRI_ARR(OTG_M_CONST_DTO1, OTG, inst),\ + SRI_ARR(OTG_CLOCK_CONTROL, OTG, inst),\ + SRI_ARR(OTG_VERTICAL_INTERRUPT0_CONTROL, OTG, inst),\ + SRI_ARR(OTG_VERTICAL_INTERRUPT0_POSITION, OTG, inst),\ + SRI_ARR(OTG_VERTICAL_INTERRUPT1_CONTROL, OTG, inst),\ + SRI_ARR(OTG_VERTICAL_INTERRUPT1_POSITION, OTG, inst),\ + SRI_ARR(OTG_VERTICAL_INTERRUPT2_CONTROL, OTG, inst),\ + SRI_ARR(OTG_VERTICAL_INTERRUPT2_POSITION, OTG, inst),\ + SRI_ARR(OPTC_INPUT_CLOCK_CONTROL, ODM, inst),\ + SRI_ARR(OPTC_DATA_SOURCE_SELECT, ODM, inst),\ + SRI_ARR(OPTC_INPUT_GLOBAL_CONTROL, ODM, inst),\ + SRI_ARR(CONTROL, VTG, inst),\ + SRI_ARR(OTG_VERT_SYNC_CONTROL, OTG, inst),\ + SRI_ARR(OTG_GSL_CONTROL, OTG, inst),\ + SRI_ARR(OTG_CRC_CNTL, OTG, inst),\ + SRI_ARR(OTG_CRC0_DATA_RG, OTG, inst),\ + SRI_ARR(OTG_CRC0_DATA_B, OTG, inst),\ + SRI_ARR(OTG_CRC1_DATA_RG, OTG, inst),\ + SRI_ARR(OTG_CRC1_DATA_B, OTG, inst),\ + SRI_ARR(OTG_CRC2_DATA_RG, OTG, inst),\ + SRI_ARR(OTG_CRC2_DATA_B, OTG, inst),\ + SRI_ARR(OTG_CRC3_DATA_RG, OTG, inst),\ + SRI_ARR(OTG_CRC3_DATA_B, OTG, inst),\ + SRI_ARR(OTG_CRC0_WINDOWA_X_CONTROL, OTG, inst),\ + SRI_ARR(OTG_CRC0_WINDOWA_Y_CONTROL, OTG, inst),\ + SRI_ARR(OTG_CRC0_WINDOWB_X_CONTROL, OTG, inst),\ + SRI_ARR(OTG_CRC0_WINDOWB_Y_CONTROL, OTG, inst),\ + SRI_ARR(OTG_CRC1_WINDOWA_X_CONTROL, OTG, inst),\ + SRI_ARR(OTG_CRC1_WINDOWA_Y_CONTROL, OTG, inst),\ + SRI_ARR(OTG_CRC1_WINDOWB_X_CONTROL, OTG, inst),\ + SRI_ARR(OTG_CRC1_WINDOWB_Y_CONTROL, OTG, inst),\ + SRI_ARR(OTG_CRC0_WINDOWA_X_CONTROL_READBACK, OTG, inst),\ + SRI_ARR(OTG_CRC0_WINDOWA_Y_CONTROL_READBACK, OTG, inst),\ + SRI_ARR(OTG_CRC0_WINDOWB_X_CONTROL_READBACK, OTG, inst),\ + SRI_ARR(OTG_CRC0_WINDOWB_Y_CONTROL_READBACK, OTG, inst),\ + SRI_ARR(OTG_CRC1_WINDOWA_X_CONTROL_READBACK, OTG, inst),\ + SRI_ARR(OTG_CRC1_WINDOWA_Y_CONTROL_READBACK, OTG, inst),\ + SRI_ARR(OTG_CRC1_WINDOWB_X_CONTROL_READBACK, OTG, inst),\ + SRI_ARR(OTG_CRC1_WINDOWB_Y_CONTROL_READBACK, OTG, inst),\ + SR_ARR(GSL_SOURCE_SELECT, inst),\ + SRI_ARR(OTG_TRIGA_MANUAL_TRIG, OTG, inst),\ + SRI_ARR(OTG_GLOBAL_CONTROL1, OTG, inst),\ + SRI_ARR(OTG_GLOBAL_CONTROL2, OTG, inst),\ + SRI_ARR(OTG_GSL_WINDOW_X, OTG, inst),\ + SRI_ARR(OTG_GSL_WINDOW_Y, OTG, inst),\ + SRI_ARR(OTG_VUPDATE_KEEPOUT, OTG, inst),\ + SRI_ARR(OTG_DSC_START_POSITION, OTG, inst),\ + SRI_ARR(OTG_DRR_TRIGGER_WINDOW, OTG, inst),\ + SRI_ARR(OTG_DRR_V_TOTAL_CHANGE, OTG, inst),\ + SRI_ARR(OPTC_DATA_FORMAT_CONTROL, ODM, inst),\ + SRI_ARR(OPTC_BYTES_PER_PIXEL, ODM, inst),\ + SRI_ARR(OPTC_WIDTH_CONTROL, ODM, inst),\ + SRI_ARR(OPTC_MEMORY_CONFIG, ODM, inst),\ + SRI_ARR(OTG_DRR_CONTROL, OTG, inst),\ + SRI2_ARR(OPTC_CLOCK_CONTROL, OPTC, inst) + +/* DPP */ +#define DPP_REG_LIST_DCN35_RI(id)\ + DPP_REG_LIST_DCN30_COMMON_RI(id) + +#endif /* _DCN35_RESOURCE_H_ */ diff --git a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h index df63aa8f01e98d..c78c9224ab6060 100644 --- a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h +++ b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h @@ -86,6 +86,7 @@ enum dmub_status { DMUB_STATUS_TIMEOUT, DMUB_STATUS_INVALID, DMUB_STATUS_HW_FAILURE, + DMUB_STATUS_POWER_STATE_D3 }; /* enum dmub_asic - dmub asic identifier */ @@ -150,6 +151,13 @@ enum dmub_memory_access_type { DMUB_MEMORY_ACCESS_DMA }; +/* enum dmub_power_state type - to track DC power state in dmub_srv */ +enum dmub_srv_power_state_type { + DMUB_POWER_STATE_UNDEFINED = 0, + DMUB_POWER_STATE_D0 = 1, + DMUB_POWER_STATE_D3 = 8 +}; + /** * struct dmub_region - dmub hw memory region * @base: base address for region, must be 256 byte aligned @@ -485,6 +493,8 @@ struct dmub_srv { /* Feature capabilities reported by fw */ struct dmub_feature_caps feature_caps; struct dmub_visual_confirm_color visual_confirm_color; + + enum dmub_srv_power_state_type power_state; }; /** @@ -889,6 +899,18 @@ enum dmub_status dmub_srv_clear_inbox0_ack(struct dmub_srv *dmub); */ void dmub_srv_subvp_save_surf_addr(struct dmub_srv *dmub, const struct dc_plane_address *addr, uint8_t subvp_index); +/** + * dmub_srv_set_power_state() - Track DC power state in dmub_srv + * @dmub: The dmub service + * @power_state: DC power state setting + * + * Store DC power state in dmub_srv. If dmub_srv is in D3, then don't send messages to DMUB + * + * Return: + * void + */ +void dmub_srv_set_power_state(struct dmub_srv *dmub, enum dmub_srv_power_state_type dmub_srv_power_state); + #if defined(__cplusplus) } #endif 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 ed4379c047151a..e699731ee68e96 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -185,8 +185,7 @@ union abm_flags { unsigned int disable_abm_requested : 1; /** - * @disable_abm_immediately: Indicates if driver has requested ABM to be disabled - * immediately. + * @disable_abm_immediately: Indicates if driver has requested ABM to be disabled immediately. */ unsigned int disable_abm_immediately : 1; @@ -654,7 +653,7 @@ union dmub_fw_boot_options { uint32_t gpint_scratch8: 1; /* 1 if GPINT is in scratch8*/ uint32_t usb4_cm_version: 1; /**< 1 CM support */ uint32_t dpia_hpd_int_enable_supported: 1; /* 1 if dpia hpd int enable supported */ - uint32_t usb4_dpia_bw_alloc_supported: 1; /* 1 if USB4 dpia BW allocation supported */ + uint32_t reserved0: 1; uint32_t disable_clk_ds: 1; /* 1 if disallow dispclk_ds and dppclk_ds*/ uint32_t disable_timeout_recovery : 1; /* 1 if timeout recovery should be disabled */ uint32_t ips_pg_disable: 1; /* 1 to disable ONO domains power gating*/ @@ -818,18 +817,61 @@ enum dmub_gpint_command { * RETURN: Lower 32-bit mask. */ DMUB_GPINT__UPDATE_TRACE_BUFFER_MASK = 101, + /** - * DESC: Updates the trace buffer lower 32-bit mask. + * DESC: Updates the trace buffer mask bit0~bit15. * ARGS: The new mask * RETURN: Lower 32-bit mask. */ DMUB_GPINT__SET_TRACE_BUFFER_MASK_WORD0 = 102, + /** - * DESC: Updates the trace buffer mask bi0~bit15. + * DESC: Updates the trace buffer mask bit16~bit31. * ARGS: The new mask * RETURN: Lower 32-bit mask. */ DMUB_GPINT__SET_TRACE_BUFFER_MASK_WORD1 = 103, + + /** + * DESC: Updates the trace buffer mask bit32~bit47. + * ARGS: The new mask + * RETURN: Lower 32-bit mask. + */ + DMUB_GPINT__SET_TRACE_BUFFER_MASK_WORD2 = 114, + + /** + * DESC: Updates the trace buffer mask bit48~bit63. + * ARGS: The new mask + * RETURN: Lower 32-bit mask. + */ + DMUB_GPINT__SET_TRACE_BUFFER_MASK_WORD3 = 115, + + /** + * DESC: Read the trace buffer mask bi0~bit15. + */ + DMUB_GPINT__GET_TRACE_BUFFER_MASK_WORD0 = 116, + + /** + * DESC: Read the trace buffer mask bit16~bit31. + */ + DMUB_GPINT__GET_TRACE_BUFFER_MASK_WORD1 = 117, + + /** + * DESC: Read the trace buffer mask bi32~bit47. + */ + DMUB_GPINT__GET_TRACE_BUFFER_MASK_WORD2 = 118, + + /** + * DESC: Updates the trace buffer mask bit32~bit63. + */ + DMUB_GPINT__GET_TRACE_BUFFER_MASK_WORD3 = 119, + + /** + * DESC: Enable measurements for various task duration + * ARGS: 0 - Disable measurement + * 1 - Enable measurement + */ + DMUB_GPINT__TRACE_DMUB_WAKE_ACTIVITY = 123, }; /** @@ -1303,6 +1345,10 @@ enum dmub_cmd_cab_type { * Fit surfaces in CAB (i.e. CAB enable) */ DMUB_CMD__CAB_DCN_SS_FIT_IN_CAB = 2, + /** + * Do not fit surfaces in CAB (i.e. no CAB) + */ + DMUB_CMD__CAB_DCN_SS_NOT_FIT_IN_CAB = 3, }; /** @@ -2786,6 +2832,7 @@ struct dmub_rb_cmd_psr_set_power_opt { #define REPLAY_RESIDENCY_MODE_MASK (0x1 << REPLAY_RESIDENCY_MODE_SHIFT) # define REPLAY_RESIDENCY_MODE_PHY (0x0 << REPLAY_RESIDENCY_MODE_SHIFT) # define REPLAY_RESIDENCY_MODE_ALPM (0x1 << REPLAY_RESIDENCY_MODE_SHIFT) +# define REPLAY_RESIDENCY_MODE_IPS 0x10 #define REPLAY_RESIDENCY_ENABLE_MASK (0x1 << REPLAY_RESIDENCY_ENABLE_SHIFT) # define REPLAY_RESIDENCY_DISABLE (0x0 << REPLAY_RESIDENCY_ENABLE_SHIFT) @@ -2840,6 +2887,18 @@ enum dmub_cmd_replay_type { * Set power opt and coasting vtotal. */ DMUB_CMD__REPLAY_SET_POWER_OPT_AND_COASTING_VTOTAL = 4, + /** + * Set disabled iiming sync. + */ + DMUB_CMD__REPLAY_SET_TIMING_SYNC_SUPPORTED = 5, + /** + * Set Residency Frameupdate Timer. + */ + DMUB_CMD__REPLAY_SET_RESIDENCY_FRAMEUPDATE_TIMER = 6, + /** + * Set pseudo vtotal + */ + DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL = 7, }; /** @@ -3002,6 +3061,46 @@ struct dmub_cmd_replay_set_power_opt_data { uint32_t power_opt; }; +/** + * Data passed from driver to FW in a DMUB_CMD__REPLAY_SET_TIMING_SYNC_SUPPORTED command. + */ +struct dmub_cmd_replay_set_timing_sync_data { + /** + * Panel Instance. + * Panel isntance to identify which replay_state to use + * Currently the support is only for 0 or 1 + */ + uint8_t panel_inst; + /** + * REPLAY set_timing_sync + */ + uint8_t timing_sync_supported; + /** + * Explicit padding to 4 byte boundary. + */ + uint8_t pad[2]; +}; + +/** + * Data passed from driver to FW in a DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL command. + */ +struct dmub_cmd_replay_set_pseudo_vtotal { + /** + * Panel Instance. + * Panel isntance to identify which replay_state to use + * Currently the support is only for 0 or 1 + */ + uint8_t panel_inst; + /** + * Source Vtotal that Replay + IPS + ABM full screen video src vtotal + */ + uint16_t vtotal; + /** + * Explicit padding to 4 byte boundary. + */ + uint8_t pad; +}; + /** * Definition of a DMUB_CMD__SET_REPLAY_POWER_OPT command. */ @@ -3068,6 +3167,91 @@ struct dmub_rb_cmd_replay_set_power_opt_and_coasting_vtotal { struct dmub_cmd_replay_set_coasting_vtotal_data replay_set_coasting_vtotal_data; }; +/** + * Definition of a DMUB_CMD__REPLAY_SET_TIMING_SYNC_SUPPORTED command. + */ +struct dmub_rb_cmd_replay_set_timing_sync { + /** + * Command header. + */ + struct dmub_cmd_header header; + /** + * Definition of DMUB_CMD__REPLAY_SET_TIMING_SYNC_SUPPORTED command. + */ + struct dmub_cmd_replay_set_timing_sync_data replay_set_timing_sync_data; +}; + +/** + * Definition of a DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL command. + */ +struct dmub_rb_cmd_replay_set_pseudo_vtotal { + /** + * Command header. + */ + struct dmub_cmd_header header; + /** + * Definition of DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL command. + */ + struct dmub_cmd_replay_set_pseudo_vtotal data; +}; + +/** + * Data passed from driver to FW in DMUB_CMD__REPLAY_SET_RESIDENCY_FRAMEUPDATE_TIMER command. + */ +struct dmub_cmd_replay_frameupdate_timer_data { + /** + * Panel Instance. + * Panel isntance to identify which replay_state to use + * Currently the support is only for 0 or 1 + */ + uint8_t panel_inst; + /** + * Replay Frameupdate Timer Enable or not + */ + uint8_t enable; + /** + * REPLAY force reflash frame update number + */ + uint16_t frameupdate_count; +}; +/** + * Definition of DMUB_CMD__REPLAY_SET_RESIDENCY_FRAMEUPDATE_TIMER + */ +struct dmub_rb_cmd_replay_set_frameupdate_timer { + /** + * Command header. + */ + struct dmub_cmd_header header; + /** + * Definition of a DMUB_CMD__SET_REPLAY_POWER_OPT command. + */ + struct dmub_cmd_replay_frameupdate_timer_data data; +}; + +/** + * Definition union of replay command set + */ +union dmub_replay_cmd_set { + /** + * Panel Instance. + * Panel isntance to identify which replay_state to use + * Currently the support is only for 0 or 1 + */ + uint8_t panel_inst; + /** + * Definition of DMUB_CMD__REPLAY_SET_TIMING_SYNC_SUPPORTED command data. + */ + struct dmub_cmd_replay_set_timing_sync_data sync_data; + /** + * Definition of DMUB_CMD__REPLAY_SET_RESIDENCY_FRAMEUPDATE_TIMER command data. + */ + struct dmub_cmd_replay_frameupdate_timer_data timer_data; + /** + * Definition of DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL command data. + */ + struct dmub_cmd_replay_set_pseudo_vtotal pseudo_vtotal_data; +}; + /** * Set of HW components that can be locked. * @@ -3357,6 +3541,16 @@ struct dmub_cmd_abm_set_pipe_data { * TODO: Remove. */ uint8_t ramping_boundary; + + /** + * PwrSeq HW Instance. + */ + uint8_t pwrseq_inst; + + /** + * Explicit padding to 4 byte boundary. + */ + uint8_t pad[3]; }; /** @@ -3737,7 +3931,7 @@ enum dmub_cmd_panel_cntl_type { * struct dmub_cmd_panel_cntl_data - Panel control data. */ struct dmub_cmd_panel_cntl_data { - uint32_t inst; /**< panel instance */ + uint32_t pwrseq_inst; /**< pwrseq instance */ uint32_t current_backlight; /* in/out */ uint32_t bl_pwm_cntl; /* in/out */ uint32_t bl_pwm_period_cntl; /* in/out */ @@ -3796,7 +3990,7 @@ struct dmub_cmd_lvtma_control_data { uint8_t uc_pwr_action; /**< LVTMA_ACTION */ uint8_t bypass_panel_control_wait; uint8_t reserved_0[2]; /**< For future use */ - uint8_t panel_inst; /**< LVTMA control instance */ + uint8_t pwrseq_inst; /**< LVTMA control instance */ uint8_t reserved_1[3]; /**< For future use */ }; @@ -4201,6 +4395,16 @@ union dmub_rb_cmd { * Definition of a DMUB_CMD__REPLAY_SET_POWER_OPT_AND_COASTING_VTOTAL command. */ struct dmub_rb_cmd_replay_set_power_opt_and_coasting_vtotal replay_set_power_opt_and_coasting_vtotal; + + struct dmub_rb_cmd_replay_set_timing_sync replay_set_timing_sync; + /** + * Definition of a DMUB_CMD__REPLAY_SET_RESIDENCY_FRAMEUPDATE_TIMER command. + */ + struct dmub_rb_cmd_replay_set_frameupdate_timer replay_set_frameupdate_timer; + /** + * Definition of a DMUB_CMD__REPLAY_SET_PSEUDO_VTOTAL command. + */ + struct dmub_rb_cmd_replay_set_pseudo_vtotal replay_set_pseudo_vtotal; }; /** diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c index 38360adc53d973..9ad738805320de 100644 --- a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c @@ -64,7 +64,7 @@ /* Default scratch mem size. */ -#define DMUB_SCRATCH_MEM_SIZE (256) +#define DMUB_SCRATCH_MEM_SIZE (1024) /* Number of windows in use. */ #define DMUB_NUM_WINDOWS (DMUB_WINDOW_TOTAL) @@ -713,6 +713,7 @@ enum dmub_status dmub_srv_hw_init(struct dmub_srv *dmub, dmub->hw_funcs.reset_release(dmub); dmub->hw_init = true; + dmub->power_state = DMUB_POWER_STATE_D0; return DMUB_STATUS_OK; } @@ -766,6 +767,9 @@ enum dmub_status dmub_srv_cmd_queue(struct dmub_srv *dmub, if (!dmub->hw_init) return DMUB_STATUS_INVALID; + if (dmub->power_state != DMUB_POWER_STATE_D0) + return DMUB_STATUS_POWER_STATE_D3; + if (dmub->inbox1_rb.rptr > dmub->inbox1_rb.capacity || dmub->inbox1_rb.wrpt > dmub->inbox1_rb.capacity) { return DMUB_STATUS_HW_FAILURE; @@ -784,6 +788,9 @@ enum dmub_status dmub_srv_cmd_execute(struct dmub_srv *dmub) if (!dmub->hw_init) return DMUB_STATUS_INVALID; + if (dmub->power_state != DMUB_POWER_STATE_D0) + return DMUB_STATUS_POWER_STATE_D3; + /** * Read back all the queued commands to ensure that they've * been flushed to framebuffer memory. Otherwise DMCUB might @@ -1100,3 +1107,11 @@ void dmub_srv_subvp_save_surf_addr(struct dmub_srv *dmub, const struct dc_plane_ subvp_index); } } + +void dmub_srv_set_power_state(struct dmub_srv *dmub, enum dmub_srv_power_state_type dmub_srv_power_state) +{ + if (!dmub || !dmub->hw_init) + return; + + dmub->power_state = dmub_srv_power_state; +} diff --git a/drivers/gpu/drm/amd/display/include/audio_types.h b/drivers/gpu/drm/amd/display/include/audio_types.h index 66a54da0641ce1..915a031a43cb28 100644 --- a/drivers/gpu/drm/amd/display/include/audio_types.h +++ b/drivers/gpu/drm/amd/display/include/audio_types.h @@ -64,7 +64,7 @@ enum audio_dto_source { /* PLL information required for AZALIA DTO calculation */ struct audio_pll_info { - uint32_t dp_dto_source_clock_in_khz; + uint32_t audio_dto_source_clock_in_khz; uint32_t feed_back_divider; enum audio_dto_source dto_source; bool ss_enabled; diff --git a/drivers/gpu/drm/amd/display/include/hdcp_msg_types.h b/drivers/gpu/drm/amd/display/include/hdcp_msg_types.h index 42229b4effdce7..eced9ad91f1d58 100644 --- a/drivers/gpu/drm/amd/display/include/hdcp_msg_types.h +++ b/drivers/gpu/drm/amd/display/include/hdcp_msg_types.h @@ -69,6 +69,11 @@ enum hdcp_message_id { HDCP_MESSAGE_ID_READ_RXSTATUS, HDCP_MESSAGE_ID_WRITE_CONTENT_STREAM_TYPE, + /* PS175 chip */ + + HDCP_MESSAGE_ID_WRITE_PS175_CMD, + HDCP_MESSAGE_ID_READ_PS175_RSP, + HDCP_MESSAGE_ID_MAX }; diff --git a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c index ccecddafeb05cb..3955b7e4b2e2e4 100644 --- a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c +++ b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c @@ -81,6 +81,7 @@ fail_alloc_context: void mod_freesync_destroy(struct mod_freesync *mod_freesync) { struct core_freesync *core_freesync = NULL; + if (mod_freesync == NULL) return; core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); @@ -278,9 +279,8 @@ static void apply_below_the_range(struct core_freesync *core_freesync, } } else if (last_render_time_in_us > (max_render_time_in_us + in_out_vrr->btr.margin_in_us / 2)) { /* Enter Below the Range */ - if (!in_out_vrr->btr.btr_active) { + if (!in_out_vrr->btr.btr_active) in_out_vrr->btr.btr_active = true; - } } /* BTR set to "not active" so disengage */ @@ -693,10 +693,12 @@ static void build_vrr_infopacket_fs2_data(enum color_transfer_func app_tf, if (app_tf != TRANSFER_FUNC_UNKNOWN) { infopacket->valid = true; - if (app_tf != TRANSFER_FUNC_PQ2084) { + if (app_tf == TRANSFER_FUNC_PQ2084) + infopacket->sb[9] |= 0x20; // PB9 = [Bit 5 = PQ EOTF Active] + else { infopacket->sb[6] |= 0x08; // PB6 = [Bit 3 = Native Color Active] if (app_tf == TRANSFER_FUNC_GAMMA_22) - infopacket->sb[9] |= 0x04; // PB6 = [Bit 2 = Gamma 2.2 EOTF Active] + infopacket->sb[9] |= 0x04; // PB9 = [Bit 2 = Gamma 2.2 EOTF Active] } } } diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp1_execution.c b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp1_execution.c index 1ddb4f5eac8e53..182e7532dda8a1 100644 --- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp1_execution.c +++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp1_execution.c @@ -63,6 +63,7 @@ static inline enum mod_hdcp_status check_hdcp_capable_dp(struct mod_hdcp *hdcp) static inline enum mod_hdcp_status check_r0p_available_dp(struct mod_hdcp *hdcp) { enum mod_hdcp_status status; + if (is_dp_hdcp(hdcp)) { status = (hdcp->auth.msg.hdcp1.bstatus & DP_BSTATUS_R0_PRIME_READY) ? @@ -131,9 +132,8 @@ static inline uint8_t get_device_count(struct mod_hdcp *hdcp) static inline enum mod_hdcp_status check_device_count(struct mod_hdcp *hdcp) { /* Avoid device count == 0 to do authentication */ - if (0 == get_device_count(hdcp)) { + if (get_device_count(hdcp) == 0) return MOD_HDCP_STATUS_HDCP1_DEVICE_COUNT_MISMATCH_FAILURE; - } /* Some MST display may choose to report the internal panel as an HDCP RX. * To update this condition with 1(because the immediate repeater's internal diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp2_execution.c b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp2_execution.c index 91c22b96ebde7f..733f22bed02198 100644 --- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp2_execution.c +++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp2_execution.c @@ -208,9 +208,8 @@ static inline uint8_t get_device_count(struct mod_hdcp *hdcp) static enum mod_hdcp_status check_device_count(struct mod_hdcp *hdcp) { /* Avoid device count == 0 to do authentication */ - if (0 == get_device_count(hdcp)) { + if (get_device_count(hdcp) == 0) return MOD_HDCP_STATUS_HDCP1_DEVICE_COUNT_MISMATCH_FAILURE; - } /* Some MST display may choose to report the internal panel as an HDCP RX. */ /* To update this condition with 1(because the immediate repeater's internal */ @@ -689,9 +688,8 @@ static enum mod_hdcp_status validate_stream_ready(struct mod_hdcp *hdcp, if (is_hdmi_dvi_sl_hdcp(hdcp)) { if (!process_rxstatus(hdcp, event_ctx, input, &status)) goto out; - if (event_ctx->rx_id_list_ready) { + if (event_ctx->rx_id_list_ready) goto out; - } } if (is_hdmi_dvi_sl_hdcp(hdcp)) if (!mod_hdcp_execute_and_set(check_stream_ready_available, diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_log.h b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_log.h index c62df3bcc7cb3c..1d83c1b9da1046 100644 --- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_log.h +++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_log.h @@ -86,10 +86,12 @@ #define HDCP_CPIRQ_TRACE(hdcp) \ HDCP_LOG_FSM(hdcp, "[Link %d] --> CPIRQ", hdcp->config.index) #define HDCP_EVENT_TRACE(hdcp, event) \ - if (event == MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) \ - HDCP_TIMEOUT_TRACE(hdcp); \ - else if (event == MOD_HDCP_EVENT_CPIRQ) \ - HDCP_CPIRQ_TRACE(hdcp) + do { \ + if (event == MOD_HDCP_EVENT_WATCHDOG_TIMEOUT) \ + HDCP_TIMEOUT_TRACE(hdcp); \ + else if (event == MOD_HDCP_EVENT_CPIRQ) \ + HDCP_CPIRQ_TRACE(hdcp); \ + } while (0) /* TODO: find some way to tell if logging is off to save time */ #define HDCP_DDC_READ_TRACE(hdcp, msg_name, msg, msg_size) do { \ mod_hdcp_dump_binary_message(msg, msg_size, hdcp->buf, \ diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c index ee67a35c2a8edd..8c137d7c032e1f 100644 --- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c +++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.c @@ -443,7 +443,7 @@ enum mod_hdcp_status mod_hdcp_hdcp1_enable_dp_stream_encryption(struct mod_hdcp for (i = 0; i < MAX_NUM_OF_DISPLAYS; i++) { if (hdcp->displays[i].adjust.disable || hdcp->displays[i].state != MOD_HDCP_DISPLAY_ACTIVE) - continue; + continue; memset(hdcp_cmd, 0, sizeof(struct ta_hdcp_shared_memory)); @@ -926,7 +926,7 @@ enum mod_hdcp_status mod_hdcp_hdcp2_enable_dp_stream_encryption(struct mod_hdcp for (i = 0; i < MAX_NUM_OF_DISPLAYS; i++) { if (hdcp->displays[i].adjust.disable || hdcp->displays[i].state != MOD_HDCP_DISPLAY_ACTIVE) - continue; + continue; hdcp_cmd->in_msg.hdcp2_enable_dp_stream_encryption.display_handle = hdcp->displays[i].index; hdcp_cmd->in_msg.hdcp2_enable_dp_stream_encryption.session_handle = hdcp->auth.id; diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.h b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.h index 5b71bc96b98c50..7844ea91650bf3 100644 --- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.h +++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_psp.h @@ -98,9 +98,9 @@ enum ta_dtm_encoder_type { * This enum defines software value for dio_output_type */ typedef enum { - TA_DTM_DIO_OUTPUT_TYPE__INVALID, - TA_DTM_DIO_OUTPUT_TYPE__DIRECT, - TA_DTM_DIO_OUTPUT_TYPE__DPIA + TA_DTM_DIO_OUTPUT_TYPE__INVALID, + TA_DTM_DIO_OUTPUT_TYPE__DIRECT, + TA_DTM_DIO_OUTPUT_TYPE__DPIA } ta_dtm_dio_output_type; struct ta_dtm_topology_update_input_v3 { @@ -237,11 +237,11 @@ enum ta_hdcp2_hdcp2_msg_id_max_size { #define TA_HDCP__HDCP1_KSV_LIST_MAX_ENTRIES 127 #define TA_HDCP__HDCP1_V_PRIME_SIZE 20 #define TA_HDCP__HDCP2_TX_BUF_MAX_SIZE \ - TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__AKE_NO_STORED_KM + TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__AKE_STORED_KM + 6 + (TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__AKE_NO_STORED_KM + TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__AKE_STORED_KM + 6) // 64 bits boundaries #define TA_HDCP__HDCP2_RX_BUF_MAX_SIZE \ - TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__AKE_SEND_CERT + TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__AKE_RECEIVER_INFO + 4 + (TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__AKE_SEND_CERT + TA_HDCP_HDCP2_MSG_ID_MAX_SIZE__AKE_RECEIVER_INFO + 4) enum ta_hdcp_status { TA_HDCP_STATUS__SUCCESS = 0x00, diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h b/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h index afe1f6cce5289d..cc3dc9b589f683 100644 --- a/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h +++ b/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h @@ -1,31 +1,3 @@ -/* - * Copyright 2016 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 - * - */ - - - - /* * Copyright 2016 Advanced Micro Devices, Inc. * 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 1675314a3ff208..e304e8435fb8f1 100644 --- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c +++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c @@ -31,7 +31,7 @@ #define DIV_ROUNDUP(a, b) (((a)+((b)/2))/(b)) #define bswap16_based_on_endian(big_endian, value) \ - (big_endian) ? cpu_to_be16(value) : cpu_to_le16(value) + ((big_endian) ? cpu_to_be16(value) : cpu_to_le16(value)) /* Possible Min Reduction config from least aggressive to most aggressive * 0 1 2 3 4 5 6 7 8 9 10 11 12 @@ -973,6 +973,39 @@ bool psr_su_set_dsc_slice_height(struct dc *dc, struct dc_link *link, return true; } +void set_replay_coasting_vtotal(struct dc_link *link, + enum replay_coasting_vtotal_type type, + uint16_t vtotal) +{ + link->replay_settings.coasting_vtotal_table[type] = vtotal; +} + +void set_replay_ips_full_screen_video_src_vtotal(struct dc_link *link, uint16_t vtotal) +{ + link->replay_settings.abm_with_ips_on_full_screen_video_pseudo_vtotal = vtotal; +} + +void calculate_replay_link_off_frame_count(struct dc_link *link, + uint16_t vtotal, uint16_t htotal) +{ + uint8_t max_link_off_frame_count = 0; + uint16_t max_deviation_line = 0, pixel_deviation_per_line = 0; + + max_deviation_line = link->dpcd_caps.pr_info.max_deviation_line; + pixel_deviation_per_line = link->dpcd_caps.pr_info.pixel_deviation_per_line; + + if (htotal != 0 && vtotal != 0) + max_link_off_frame_count = htotal * max_deviation_line / (pixel_deviation_per_line * vtotal); + else + ASSERT(0); + + link->replay_settings.link_off_frame_count_level = + max_link_off_frame_count >= PR_LINK_OFF_FRAME_COUNT_BEST ? PR_LINK_OFF_FRAME_COUNT_BEST : + max_link_off_frame_count >= PR_LINK_OFF_FRAME_COUNT_GOOD ? PR_LINK_OFF_FRAME_COUNT_GOOD : + PR_LINK_OFF_FRAME_COUNT_FAIL; + +} + bool fill_custom_backlight_caps(unsigned int config_no, struct dm_acpi_atif_backlight_caps *caps) { unsigned int data_points_size; 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 d9e0d67d67f703..bef4815e1703d7 100644 --- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.h +++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.h @@ -54,6 +54,12 @@ bool dmub_init_abm_config(struct resource_pool *res_pool, unsigned int inst); void init_replay_config(struct dc_link *link, struct replay_config *pr_config); +void set_replay_coasting_vtotal(struct dc_link *link, + enum replay_coasting_vtotal_type type, + uint16_t vtotal); +void set_replay_ips_full_screen_video_src_vtotal(struct dc_link *link, uint16_t vtotal); +void calculate_replay_link_off_frame_count(struct dc_link *link, + uint16_t vtotal, uint16_t htotal); bool is_psr_su_specific_panel(struct dc_link *link); void mod_power_calc_psr_configs(struct psr_config *psr_config, diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h index 7f98394338c26d..df2c7ffe190f4d 100644 --- a/drivers/gpu/drm/amd/include/amd_shared.h +++ b/drivers/gpu/drm/amd/include/amd_shared.h @@ -244,7 +244,6 @@ 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_REPLAY_MASK = (1 << 9), //0x200, disabled by default for dcn < 3.1.4 }; enum DC_DEBUG_MASK { @@ -255,8 +254,11 @@ enum DC_DEBUG_MASK { DC_DISABLE_PSR = 0x10, DC_FORCE_SUBVP_MCLK_SWITCH = 0x20, DC_DISABLE_MPO = 0x40, - DC_DISABLE_REPLAY = 0x50, DC_ENABLE_DPIA_TRACE = 0x80, + DC_ENABLE_DML2 = 0x100, + DC_DISABLE_PSR_SU = 0x200, + DC_DISABLE_REPLAY = 0x400, + DC_DISABLE_IPS = 0x800, }; enum amd_dpm_forced_level; diff --git a/drivers/gpu/drm/amd/include/amdgpu_reg_state.h b/drivers/gpu/drm/amd/include/amdgpu_reg_state.h new file mode 100644 index 00000000000000..335980e2afbfb8 --- /dev/null +++ b/drivers/gpu/drm/amd/include/amdgpu_reg_state.h @@ -0,0 +1,153 @@ +/* SPDX-License-Identifier: MIT */ +/* + * 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 __AMDGPU_REG_STATE_H__ +#define __AMDGPU_REG_STATE_H__ + +enum amdgpu_reg_state { + AMDGPU_REG_STATE_TYPE_INVALID = 0, + AMDGPU_REG_STATE_TYPE_XGMI = 1, + AMDGPU_REG_STATE_TYPE_WAFL = 2, + AMDGPU_REG_STATE_TYPE_PCIE = 3, + AMDGPU_REG_STATE_TYPE_USR = 4, + AMDGPU_REG_STATE_TYPE_USR_1 = 5 +}; + +enum amdgpu_sysfs_reg_offset { + AMDGPU_SYS_REG_STATE_XGMI = 0x0000, + AMDGPU_SYS_REG_STATE_WAFL = 0x1000, + AMDGPU_SYS_REG_STATE_PCIE = 0x2000, + AMDGPU_SYS_REG_STATE_USR = 0x3000, + AMDGPU_SYS_REG_STATE_USR_1 = 0x4000, + AMDGPU_SYS_REG_STATE_END = 0x5000, +}; + +struct amdgpu_reg_state_header { + uint16_t structure_size; + uint8_t format_revision; + uint8_t content_revision; + uint8_t state_type; + uint8_t num_instances; + uint16_t pad; +}; + +enum amdgpu_reg_inst_state { + AMDGPU_INST_S_OK, + AMDGPU_INST_S_EDISABLED, + AMDGPU_INST_S_EACCESS, +}; + +struct amdgpu_smn_reg_data { + uint64_t addr; + uint32_t value; + uint32_t pad; +}; + +struct amdgpu_reg_inst_header { + uint16_t instance; + uint16_t state; + uint16_t num_smn_regs; + uint16_t pad; +}; + + +struct amdgpu_regs_xgmi_v1_0 { + struct amdgpu_reg_inst_header inst_header; + + struct amdgpu_smn_reg_data smn_reg_values[]; +}; + +struct amdgpu_reg_state_xgmi_v1_0 { + /* common_header.state_type must be AMDGPU_REG_STATE_TYPE_XGMI */ + struct amdgpu_reg_state_header common_header; + + struct amdgpu_regs_xgmi_v1_0 xgmi_state_regs[]; +}; + +struct amdgpu_regs_wafl_v1_0 { + struct amdgpu_reg_inst_header inst_header; + + struct amdgpu_smn_reg_data smn_reg_values[]; +}; + +struct amdgpu_reg_state_wafl_v1_0 { + /* common_header.state_type must be AMDGPU_REG_STATE_TYPE_WAFL */ + struct amdgpu_reg_state_header common_header; + + struct amdgpu_regs_wafl_v1_0 wafl_state_regs[]; +}; + +struct amdgpu_regs_pcie_v1_0 { + struct amdgpu_reg_inst_header inst_header; + + uint16_t device_status; + uint16_t link_status; + uint32_t sub_bus_number_latency; + uint32_t pcie_corr_err_status; + uint32_t pcie_uncorr_err_status; + + struct amdgpu_smn_reg_data smn_reg_values[]; +}; + +struct amdgpu_reg_state_pcie_v1_0 { + /* common_header.state_type must be AMDGPU_REG_STATE_TYPE_PCIE */ + struct amdgpu_reg_state_header common_header; + + struct amdgpu_regs_pcie_v1_0 pci_state_regs[]; +}; + +struct amdgpu_regs_usr_v1_0 { + struct amdgpu_reg_inst_header inst_header; + + struct amdgpu_smn_reg_data smn_reg_values[]; +}; + +struct amdgpu_reg_state_usr_v1_0 { + /* common_header.state_type must be AMDGPU_REG_STATE_TYPE_USR */ + struct amdgpu_reg_state_header common_header; + + struct amdgpu_regs_usr_v1_0 usr_state_regs[]; +}; + +static inline size_t amdgpu_reginst_size(uint16_t num_inst, size_t inst_size, + uint16_t num_regs) +{ + return num_inst * + (inst_size + num_regs * sizeof(struct amdgpu_smn_reg_data)); +} + +#define amdgpu_asic_get_reg_state_supported(adev) \ + (((adev)->asic_funcs && (adev)->asic_funcs->get_reg_state) ? 1 : 0) + +#define amdgpu_asic_get_reg_state(adev, state, buf, size) \ + ((adev)->asic_funcs->get_reg_state ? \ + (adev)->asic_funcs->get_reg_state((adev), (state), (buf), \ + (size)) : \ + 0) + + +int amdgpu_reg_state_sysfs_init(struct amdgpu_device *adev); +void amdgpu_reg_state_sysfs_fini(struct amdgpu_device *adev); + +#endif diff --git a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_5_0_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_5_0_sh_mask.h index b6466487921130..fca72e2ec92947 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_5_0_sh_mask.h +++ b/drivers/gpu/drm/amd/include/asic_reg/dcn/dcn_3_5_0_sh_mask.h @@ -6220,12 +6220,20 @@ #define DCCG_GATE_DISABLE_CNTL4__PHYD_REFCLK_ROOT_GATE_DISABLE__SHIFT 0x3 #define DCCG_GATE_DISABLE_CNTL4__PHYE_REFCLK_ROOT_GATE_DISABLE__SHIFT 0x4 #define DCCG_GATE_DISABLE_CNTL4__HDMICHARCLK0_ROOT_GATE_DISABLE__SHIFT 0x11 +#define DCCG_GATE_DISABLE_CNTL4__DPIASYMCLK0_GATE_DISABLE__SHIFT 0x17 +#define DCCG_GATE_DISABLE_CNTL4__DPIASYMCLK1_GATE_DISABLE__SHIFT 0x18 +#define DCCG_GATE_DISABLE_CNTL4__DPIASYMCLK2_GATE_DISABLE__SHIFT 0x19 +#define DCCG_GATE_DISABLE_CNTL4__DPIASYMCLK3_GATE_DISABLE__SHIFT 0x1a #define DCCG_GATE_DISABLE_CNTL4__PHYA_REFCLK_ROOT_GATE_DISABLE_MASK 0x00000001L #define DCCG_GATE_DISABLE_CNTL4__PHYB_REFCLK_ROOT_GATE_DISABLE_MASK 0x00000002L #define DCCG_GATE_DISABLE_CNTL4__PHYC_REFCLK_ROOT_GATE_DISABLE_MASK 0x00000004L #define DCCG_GATE_DISABLE_CNTL4__PHYD_REFCLK_ROOT_GATE_DISABLE_MASK 0x00000008L #define DCCG_GATE_DISABLE_CNTL4__PHYE_REFCLK_ROOT_GATE_DISABLE_MASK 0x00000010L #define DCCG_GATE_DISABLE_CNTL4__HDMICHARCLK0_ROOT_GATE_DISABLE_MASK 0x00020000L +#define DCCG_GATE_DISABLE_CNTL4__DPIASYMCLK0_GATE_DISABLE_MASK 0x00800000L +#define DCCG_GATE_DISABLE_CNTL4__DPIASYMCLK1_GATE_DISABLE_MASK 0x01000000L +#define DCCG_GATE_DISABLE_CNTL4__DPIASYMCLK2_GATE_DISABLE_MASK 0x02000000L +#define DCCG_GATE_DISABLE_CNTL4__DPIASYMCLK3_GATE_DISABLE_MASK 0x04000000L #define DPSTREAMCLK_CNTL__DPSTREAMCLK0_SRC_SEL__SHIFT 0x0 #define DPSTREAMCLK_CNTL__DPSTREAMCLK0_EN__SHIFT 0x3 #define DPSTREAMCLK_CNTL__DPSTREAMCLK1_SRC_SEL__SHIFT 0x4 diff --git a/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_11_0_offset.h b/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_11_0_offset.h index 7ee3d291120d54..6f80bfa7e41ac9 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_11_0_offset.h +++ b/drivers/gpu/drm/amd/include/asic_reg/nbio/nbio_7_11_0_offset.h @@ -8707,10 +8707,10 @@ #define regBIF_BX1_MM_CFGREGS_CNTL_BASE_IDX 2 #define regBIF_BX1_BX_RESET_CNTL 0x00f0 #define regBIF_BX1_BX_RESET_CNTL_BASE_IDX 2 -#define regBIF_BX1_INTERRUPT_CNTL 0x8e11 -#define regBIF_BX1_INTERRUPT_CNTL_BASE_IDX 5 -#define regBIF_BX1_INTERRUPT_CNTL2 0x8e12 -#define regBIF_BX1_INTERRUPT_CNTL2_BASE_IDX 5 +#define regBIF_BX1_INTERRUPT_CNTL 0x00f1 +#define regBIF_BX1_INTERRUPT_CNTL_BASE_IDX 2 +#define regBIF_BX1_INTERRUPT_CNTL2 0x00f2 +#define regBIF_BX1_INTERRUPT_CNTL2_BASE_IDX 2 #define regBIF_BX1_CLKREQB_PAD_CNTL 0x00f8 #define regBIF_BX1_CLKREQB_PAD_CNTL_BASE_IDX 2 #define regBIF_BX1_BIF_FEATURES_CONTROL_MISC 0x00fb diff --git a/drivers/gpu/drm/amd/include/asic_reg/smuio/smuio_10_0_2_offset.h b/drivers/gpu/drm/amd/include/asic_reg/smuio/smuio_10_0_2_offset.h new file mode 100644 index 00000000000000..a4dd372c05419a --- /dev/null +++ b/drivers/gpu/drm/amd/include/asic_reg/smuio/smuio_10_0_2_offset.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 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) 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 _smuio_10_0_2_OFFSET_HEADER + +// addressBlock: smuio_smuio_misc_SmuSmuioDec +// base address: 0x5a000 +#define mmSMUIO_MCM_CONFIG 0x0023 +#define mmSMUIO_MCM_CONFIG_BASE_IDX 0 +#define mmIP_DISCOVERY_VERSION 0x0000 +#define mmIP_DISCOVERY_VERSION_BASE_IDX 1 +#define mmIO_SMUIO_PINSTRAP 0x01b1 +#define mmIO_SMUIO_PINSTRAP_BASE_IDX 1 +#define mmSCRATCH_REGISTER0 0x01b2 +#define mmSCRATCH_REGISTER0_BASE_IDX 1 +#define mmSCRATCH_REGISTER1 0x01b3 +#define mmSCRATCH_REGISTER1_BASE_IDX 1 +#define mmSCRATCH_REGISTER2 0x01b4 +#define mmSCRATCH_REGISTER2_BASE_IDX 1 +#define mmSCRATCH_REGISTER3 0x01b5 +#define mmSCRATCH_REGISTER3_BASE_IDX 1 +#define mmSCRATCH_REGISTER4 0x01b6 +#define mmSCRATCH_REGISTER4_BASE_IDX 1 +#define mmSCRATCH_REGISTER5 0x01b7 +#define mmSCRATCH_REGISTER5_BASE_IDX 1 +#define mmSCRATCH_REGISTER6 0x01b8 +#define mmSCRATCH_REGISTER6_BASE_IDX 1 +#define mmSCRATCH_REGISTER7 0x01b9 +#define mmSCRATCH_REGISTER7_BASE_IDX 1 + + +// addressBlock: smuio_smuio_reset_SmuSmuioDec +// base address: 0x5a300 +#define mmSMUIO_MP_RESET_INTR 0x00c1 +#define mmSMUIO_MP_RESET_INTR_BASE_IDX 0 +#define mmSMUIO_SOC_HALT 0x00c2 +#define mmSMUIO_SOC_HALT_BASE_IDX 0 +#define mmSMUIO_GFX_MISC_CNTL 0x00c8 +#define mmSMUIO_GFX_MISC_CNTL_BASE_IDX 0 + + +// addressBlock: smuio_smuio_ccxctrl_SmuSmuioDec +// base address: 0x5a000 +#define mmPWROK_REFCLK_GAP_CYCLES 0x0001 +#define mmPWROK_REFCLK_GAP_CYCLES_BASE_IDX 1 +#define mmGOLDEN_TSC_INCREMENT_UPPER 0x0004 +#define mmGOLDEN_TSC_INCREMENT_UPPER_BASE_IDX 1 +#define mmGOLDEN_TSC_INCREMENT_LOWER 0x0005 +#define mmGOLDEN_TSC_INCREMENT_LOWER_BASE_IDX 1 +#define mmGOLDEN_TSC_COUNT_UPPER 0x0025 +#define mmGOLDEN_TSC_COUNT_UPPER_BASE_IDX 1 +#define mmGOLDEN_TSC_COUNT_LOWER 0x0026 +#define mmGOLDEN_TSC_COUNT_LOWER_BASE_IDX 1 +#define mmGFX_GOLDEN_TSC_SHADOW_UPPER 0x0029 +#define mmGFX_GOLDEN_TSC_SHADOW_UPPER_BASE_IDX 1 +#define mmGFX_GOLDEN_TSC_SHADOW_LOWER 0x002a +#define mmGFX_GOLDEN_TSC_SHADOW_LOWER_BASE_IDX 1 +#define mmSOC_GOLDEN_TSC_SHADOW_UPPER 0x002b +#define mmSOC_GOLDEN_TSC_SHADOW_UPPER_BASE_IDX 1 +#define mmSOC_GOLDEN_TSC_SHADOW_LOWER 0x002c +#define mmSOC_GOLDEN_TSC_SHADOW_LOWER_BASE_IDX 1 +#define mmSOC_GAP_PWROK 0x002d +#define mmSOC_GAP_PWROK_BASE_IDX 1 + +// addressBlock: smuio_smuio_swtimer_SmuSmuioDec +// base address: 0x5ac40 +#define mmPWR_VIRT_RESET_REQ 0x0110 +#define mmPWR_VIRT_RESET_REQ_BASE_IDX 1 +#define mmPWR_DISP_TIMER_CONTROL 0x0111 +#define mmPWR_DISP_TIMER_CONTROL_BASE_IDX 1 +#define mmPWR_DISP_TIMER2_CONTROL 0x0113 +#define mmPWR_DISP_TIMER2_CONTROL_BASE_IDX 1 +#define mmPWR_DISP_TIMER_GLOBAL_CONTROL 0x0115 +#define mmPWR_DISP_TIMER_GLOBAL_CONTROL_BASE_IDX 1 +#define mmPWR_IH_CONTROL 0x0116 +#define mmPWR_IH_CONTROL_BASE_IDX 1 + +// addressBlock: smuio_smuio_svi0_SmuSmuioDec +// base address: 0x6f000 +#define mmSMUSVI0_TEL_PLANE0 0x520e +#define mmSMUSVI0_TEL_PLANE0_BASE_IDX 1 +#define mmSMUSVI0_PLANE0_CURRENTVID 0x5217 +#define mmSMUSVI0_PLANE0_CURRENTVID_BASE_IDX 1 + +#endif diff --git a/drivers/gpu/drm/amd/include/asic_reg/smuio/smuio_10_0_2_sh_mask.h b/drivers/gpu/drm/amd/include/asic_reg/smuio/smuio_10_0_2_sh_mask.h new file mode 100644 index 00000000000000..d10ae61c346b28 --- /dev/null +++ b/drivers/gpu/drm/amd/include/asic_reg/smuio/smuio_10_0_2_sh_mask.h @@ -0,0 +1,184 @@ +/* + * Copyright (C) 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) 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 _smuio_10_0_2_SH_MASK_HEADER + +// addressBlock: smuio_smuio_misc_SmuSmuioDec +//SMUIO_MCM_CONFIG +#define SMUIO_MCM_CONFIG__DIE_ID__SHIFT 0x0 +#define SMUIO_MCM_CONFIG__PKG_TYPE__SHIFT 0x2 +#define SMUIO_MCM_CONFIG__SOCKET_ID__SHIFT 0x5 +#define SMUIO_MCM_CONFIG__PKG_SUBTYPE__SHIFT 0x6 +#define SMUIO_MCM_CONFIG__CONSOLE_K__SHIFT 0x10 +#define SMUIO_MCM_CONFIG__CONSOLE_A__SHIFT 0x11 +#define SMUIO_MCM_CONFIG__DIE_ID_MASK 0x00000003L +#define SMUIO_MCM_CONFIG__PKG_TYPE_MASK 0x0000001CL +#define SMUIO_MCM_CONFIG__SOCKET_ID_MASK 0x00000020L +#define SMUIO_MCM_CONFIG__PKG_SUBTYPE_MASK 0x000000C0L +#define SMUIO_MCM_CONFIG__CONSOLE_K_MASK 0x00010000L +#define SMUIO_MCM_CONFIG__CONSOLE_A_MASK 0x00020000L +//IP_DISCOVERY_VERSION +#define IP_DISCOVERY_VERSION__IP_DISCOVERY_VERSION__SHIFT 0x0 +#define IP_DISCOVERY_VERSION__IP_DISCOVERY_VERSION_MASK 0xFFFFFFFFL +//IO_SMUIO_PINSTRAP +#define IO_SMUIO_PINSTRAP__AUD_PORT_CONN__SHIFT 0x0 +#define IO_SMUIO_PINSTRAP__AUD__SHIFT 0x3 +#define IO_SMUIO_PINSTRAP__AUD_PORT_CONN_MASK 0x00000007L +#define IO_SMUIO_PINSTRAP__AUD_MASK 0x00000018L +//SCRATCH_REGISTER0 +#define SCRATCH_REGISTER0__ScratchPad0__SHIFT 0x0 +#define SCRATCH_REGISTER0__ScratchPad0_MASK 0xFFFFFFFFL +//SCRATCH_REGISTER1 +#define SCRATCH_REGISTER1__ScratchPad1__SHIFT 0x0 +#define SCRATCH_REGISTER1__ScratchPad1_MASK 0xFFFFFFFFL +//SCRATCH_REGISTER2 +#define SCRATCH_REGISTER2__ScratchPad2__SHIFT 0x0 +#define SCRATCH_REGISTER2__ScratchPad2_MASK 0xFFFFFFFFL +//SCRATCH_REGISTER3 +#define SCRATCH_REGISTER3__ScratchPad3__SHIFT 0x0 +#define SCRATCH_REGISTER3__ScratchPad3_MASK 0xFFFFFFFFL +//SCRATCH_REGISTER4 +#define SCRATCH_REGISTER4__ScratchPad4__SHIFT 0x0 +#define SCRATCH_REGISTER4__ScratchPad4_MASK 0xFFFFFFFFL +//SCRATCH_REGISTER5 +#define SCRATCH_REGISTER5__ScratchPad5__SHIFT 0x0 +#define SCRATCH_REGISTER5__ScratchPad5_MASK 0xFFFFFFFFL +//SCRATCH_REGISTER6 +#define SCRATCH_REGISTER6__ScratchPad6__SHIFT 0x0 +#define SCRATCH_REGISTER6__ScratchPad6_MASK 0xFFFFFFFFL +//SCRATCH_REGISTER7 +#define SCRATCH_REGISTER7__ScratchPad7__SHIFT 0x0 +#define SCRATCH_REGISTER7__ScratchPad7_MASK 0xFFFFFFFFL + +// addressBlock: smuio_smuio_reset_SmuSmuioDec +//SMUIO_MP_RESET_INTR +#define SMUIO_MP_RESET_INTR__SMUIO_MP_RESET_INTR__SHIFT 0x0 +#define SMUIO_MP_RESET_INTR__SMUIO_MP_RESET_INTR_MASK 0x00000001L +//SMUIO_SOC_HALT +#define SMUIO_SOC_HALT__WDT_FORCE_PWROK_EN__SHIFT 0x2 +#define SMUIO_SOC_HALT__WDT_FORCE_RESETn_EN__SHIFT 0x3 +#define SMUIO_SOC_HALT__WDT_FORCE_PWROK_EN_MASK 0x00000004L +#define SMUIO_SOC_HALT__WDT_FORCE_RESETn_EN_MASK 0x00000008L +//SMUIO_GFX_MISC_CNTL +#define SMUIO_GFX_MISC_CNTL__SMU_GFX_cold_vs_gfxoff__SHIFT 0x0 +#define SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS__SHIFT 0x1 +#define SMUIO_GFX_MISC_CNTL__PWR_GFX_DLDO_CLK_SWITCH__SHIFT 0x3 +#define SMUIO_GFX_MISC_CNTL__PWR_GFX_RLC_CGPG_EN__SHIFT 0x4 +#define SMUIO_GFX_MISC_CNTL__SMU_GFX_cold_vs_gfxoff_MASK 0x00000001L +#define SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS_MASK 0x00000006L +#define SMUIO_GFX_MISC_CNTL__PWR_GFX_DLDO_CLK_SWITCH_MASK 0x00000008L +#define SMUIO_GFX_MISC_CNTL__PWR_GFX_RLC_CGPG_EN_MASK 0x00000010L + +// addressBlock: smuio_smuio_ccxctrl_SmuSmuioDec +//PWROK_REFCLK_GAP_CYCLES +#define PWROK_REFCLK_GAP_CYCLES__Pwrok_PreAssertion_clkgap_cycles__SHIFT 0x0 +#define PWROK_REFCLK_GAP_CYCLES__Pwrok_PostAssertion_clkgap_cycles__SHIFT 0x8 +#define PWROK_REFCLK_GAP_CYCLES__Pwrok_PreAssertion_clkgap_cycles_MASK 0x000000FFL +#define PWROK_REFCLK_GAP_CYCLES__Pwrok_PostAssertion_clkgap_cycles_MASK 0x0000FF00L +//GOLDEN_TSC_INCREMENT_UPPER +#define GOLDEN_TSC_INCREMENT_UPPER__GoldenTscIncrementUpper__SHIFT 0x0 +#define GOLDEN_TSC_INCREMENT_UPPER__GoldenTscIncrementUpper_MASK 0x00FFFFFFL +//GOLDEN_TSC_INCREMENT_LOWER +#define GOLDEN_TSC_INCREMENT_LOWER__GoldenTscIncrementLower__SHIFT 0x0 +#define GOLDEN_TSC_INCREMENT_LOWER__GoldenTscIncrementLower_MASK 0xFFFFFFFFL +//GOLDEN_TSC_COUNT_UPPER +#define GOLDEN_TSC_COUNT_UPPER__GoldenTscCountUpper__SHIFT 0x0 +#define GOLDEN_TSC_COUNT_UPPER__GoldenTscCountUpper_MASK 0x00FFFFFFL +//GOLDEN_TSC_COUNT_LOWER +#define GOLDEN_TSC_COUNT_LOWER__GoldenTscCountLower__SHIFT 0x0 +#define GOLDEN_TSC_COUNT_LOWER__GoldenTscCountLower_MASK 0xFFFFFFFFL +//GFX_GOLDEN_TSC_SHADOW_UPPER +#define GFX_GOLDEN_TSC_SHADOW_UPPER__GfxGoldenTscShadowUpper__SHIFT 0x0 +#define GFX_GOLDEN_TSC_SHADOW_UPPER__GfxGoldenTscShadowUpper_MASK 0x00FFFFFFL +//GFX_GOLDEN_TSC_SHADOW_LOWER +#define GFX_GOLDEN_TSC_SHADOW_LOWER__GfxGoldenTscShadowLower__SHIFT 0x0 +#define GFX_GOLDEN_TSC_SHADOW_LOWER__GfxGoldenTscShadowLower_MASK 0xFFFFFFFFL +//SOC_GOLDEN_TSC_SHADOW_UPPER +#define SOC_GOLDEN_TSC_SHADOW_UPPER__SocGoldenTscShadowUpper__SHIFT 0x0 +#define SOC_GOLDEN_TSC_SHADOW_UPPER__SocGoldenTscShadowUpper_MASK 0x00FFFFFFL +//SOC_GOLDEN_TSC_SHADOW_LOWER +#define SOC_GOLDEN_TSC_SHADOW_LOWER__SocGoldenTscShadowLower__SHIFT 0x0 +#define SOC_GOLDEN_TSC_SHADOW_LOWER__SocGoldenTscShadowLower_MASK 0xFFFFFFFFL +//SOC_GAP_PWROK +#define SOC_GAP_PWROK__soc_gap_pwrok__SHIFT 0x0 +#define SOC_GAP_PWROK__soc_gap_pwrok_MASK 0x00000001L + +// addressBlock: smuio_smuio_swtimer_SmuSmuioDec +//PWR_VIRT_RESET_REQ +#define PWR_VIRT_RESET_REQ__VF_FLR__SHIFT 0x0 +#define PWR_VIRT_RESET_REQ__PF_FLR__SHIFT 0x1f +#define PWR_VIRT_RESET_REQ__VF_FLR_MASK 0x7FFFFFFFL +#define PWR_VIRT_RESET_REQ__PF_FLR_MASK 0x80000000L +//PWR_DISP_TIMER_CONTROL +#define PWR_DISP_TIMER_CONTROL__DISP_TIMER_INT_COUNT__SHIFT 0x0 +#define PWR_DISP_TIMER_CONTROL__DISP_TIMER_INT_ENABLE__SHIFT 0x19 +#define PWR_DISP_TIMER_CONTROL__DISP_TIMER_INT_DISABLE__SHIFT 0x1a +#define PWR_DISP_TIMER_CONTROL__DISP_TIMER_INT_MASK__SHIFT 0x1b +#define PWR_DISP_TIMER_CONTROL__DISP_TIMER_INT_STAT_AK__SHIFT 0x1c +#define PWR_DISP_TIMER_CONTROL__DISP_TIMER_INT_TYPE__SHIFT 0x1d +#define PWR_DISP_TIMER_CONTROL__DISP_TIMER_INT_MODE__SHIFT 0x1e +#define PWR_DISP_TIMER_CONTROL__DISP_TIMER_INT_COUNT_MASK 0x01FFFFFFL +#define PWR_DISP_TIMER_CONTROL__DISP_TIMER_INT_ENABLE_MASK 0x02000000L +#define PWR_DISP_TIMER_CONTROL__DISP_TIMER_INT_DISABLE_MASK 0x04000000L +#define PWR_DISP_TIMER_CONTROL__DISP_TIMER_INT_MASK_MASK 0x08000000L +#define PWR_DISP_TIMER_CONTROL__DISP_TIMER_INT_STAT_AK_MASK 0x10000000L +#define PWR_DISP_TIMER_CONTROL__DISP_TIMER_INT_TYPE_MASK 0x20000000L +#define PWR_DISP_TIMER_CONTROL__DISP_TIMER_INT_MODE_MASK 0x40000000L +//PWR_DISP_TIMER2_CONTROL +#define PWR_DISP_TIMER2_CONTROL__DISP_TIMER_INT_COUNT__SHIFT 0x0 +#define PWR_DISP_TIMER2_CONTROL__DISP_TIMER_INT_ENABLE__SHIFT 0x19 +#define PWR_DISP_TIMER2_CONTROL__DISP_TIMER_INT_DISABLE__SHIFT 0x1a +#define PWR_DISP_TIMER2_CONTROL__DISP_TIMER_INT_MASK__SHIFT 0x1b +#define PWR_DISP_TIMER2_CONTROL__DISP_TIMER_INT_STAT_AK__SHIFT 0x1c +#define PWR_DISP_TIMER2_CONTROL__DISP_TIMER_INT_TYPE__SHIFT 0x1d +#define PWR_DISP_TIMER2_CONTROL__DISP_TIMER_INT_MODE__SHIFT 0x1e +#define PWR_DISP_TIMER2_CONTROL__DISP_TIMER_INT_COUNT_MASK 0x01FFFFFFL +#define PWR_DISP_TIMER2_CONTROL__DISP_TIMER_INT_ENABLE_MASK 0x02000000L +#define PWR_DISP_TIMER2_CONTROL__DISP_TIMER_INT_DISABLE_MASK 0x04000000L +#define PWR_DISP_TIMER2_CONTROL__DISP_TIMER_INT_MASK_MASK 0x08000000L +#define PWR_DISP_TIMER2_CONTROL__DISP_TIMER_INT_STAT_AK_MASK 0x10000000L +#define PWR_DISP_TIMER2_CONTROL__DISP_TIMER_INT_TYPE_MASK 0x20000000L +#define PWR_DISP_TIMER2_CONTROL__DISP_TIMER_INT_MODE_MASK 0x40000000L +//PWR_DISP_TIMER_GLOBAL_CONTROL +#define PWR_DISP_TIMER_GLOBAL_CONTROL__DISP_TIMER_PULSE_WIDTH__SHIFT 0x0 +#define PWR_DISP_TIMER_GLOBAL_CONTROL__DISP_TIMER_PULSE_EN__SHIFT 0xa +#define PWR_DISP_TIMER_GLOBAL_CONTROL__DISP_TIMER_PULSE_WIDTH_MASK 0x000003FFL +#define PWR_DISP_TIMER_GLOBAL_CONTROL__DISP_TIMER_PULSE_EN_MASK 0x00000400L +//PWR_IH_CONTROL +#define PWR_IH_CONTROL__MAX_CREDIT__SHIFT 0x0 +#define PWR_IH_CONTROL__DISP_TIMER_TRIGGER_MASK__SHIFT 0x5 +#define PWR_IH_CONTROL__DISP_TIMER2_TRIGGER_MASK__SHIFT 0x6 +#define PWR_IH_CONTROL__PWR_IH_CLK_GATE_EN__SHIFT 0x1f +#define PWR_IH_CONTROL__MAX_CREDIT_MASK 0x0000001FL +#define PWR_IH_CONTROL__DISP_TIMER_TRIGGER_MASK_MASK 0x00000020L +#define PWR_IH_CONTROL__DISP_TIMER2_TRIGGER_MASK_MASK 0x00000040L +#define PWR_IH_CONTROL__PWR_IH_CLK_GATE_EN_MASK 0x80000000L + +// addressBlock: smuio_smuio_svi0_SmuSmuioDec +//SMUSVI0_TEL_PLANE0 +#define SMUSVI0_TEL_PLANE0__SVI0_PLANE0_IDDCOR__SHIFT 0x0 +#define SMUSVI0_TEL_PLANE0__SVI0_PLANE0_VDDCOR__SHIFT 0x10 +#define SMUSVI0_TEL_PLANE0__SVI0_PLANE0_IDDCOR_MASK 0x000000FFL +#define SMUSVI0_TEL_PLANE0__SVI0_PLANE0_VDDCOR_MASK 0x01FF0000L +//SMUSVI0_PLANE0_CURRENTVID +#define SMUSVI0_PLANE0_CURRENTVID__CURRENT_SVI0_PLANE0_VID__SHIFT 0x18 +#define SMUSVI0_PLANE0_CURRENTVID__CURRENT_SVI0_PLANE0_VID_MASK 0xFF000000L + +#endif diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index c2ccf3724e3780..edcb85560cede5 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -422,7 +422,7 @@ struct amd_pm_funcs { int (*set_hard_min_dcefclk_by_freq)(void *handle, uint32_t clock); int (*set_hard_min_fclk_by_freq)(void *handle, uint32_t clock); int (*set_min_deep_sleep_dcefclk)(void *handle, uint32_t clock); - int (*get_asic_baco_capability)(void *handle, bool *cap); + bool (*get_asic_baco_capability)(void *handle); int (*get_asic_baco_state)(void *handle, int *state); int (*set_asic_baco_state)(void *handle, int state); int (*get_ppfeature_status)(void *handle, char *buf); @@ -432,6 +432,7 @@ struct amd_pm_funcs { 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); + ssize_t (*get_pm_metrics)(void *handle, void *pmmetrics, size_t size); int (*set_watermarks_for_clock_ranges)(void *handle, struct pp_smu_wm_range_sets *ranges); int (*display_disable_memory_clock_switch)(void *handle, @@ -1225,4 +1226,19 @@ struct gpu_metrics_v3_0 { /* Metrics table alpha filter time constant [us] */ uint32_t time_filter_alphavalue; }; + +struct amdgpu_pmmetrics_header { + uint16_t structure_size; + uint16_t pad; + uint32_t mp1_ip_discovery_version; + uint32_t pmfw_version; + uint32_t pmmetrics_version; +}; + +struct amdgpu_pm_metrics { + struct amdgpu_pmmetrics_header common_header; + + uint8_t data[]; +}; + #endif diff --git a/drivers/gpu/drm/amd/include/mes_v11_api_def.h b/drivers/gpu/drm/amd/include/mes_v11_api_def.h index b1db2b19018742..ec5b9ab67c5e44 100644 --- a/drivers/gpu/drm/amd/include/mes_v11_api_def.h +++ b/drivers/gpu/drm/amd/include/mes_v11_api_def.h @@ -232,6 +232,7 @@ union MESAPI_SET_HW_RESOURCES { }; uint32_t oversubscription_timer; uint64_t doorbell_info; + uint64_t event_intr_history_gpu_mc_ptr; }; uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; @@ -571,7 +572,8 @@ struct SET_SHADER_DEBUGGER { struct { uint32_t single_memop : 1; /* SQ_DEBUG.single_memop */ uint32_t single_alu_op : 1; /* SQ_DEBUG.single_alu_op */ - uint32_t reserved : 30; + uint32_t reserved : 29; + uint32_t process_ctx_flush : 1; }; uint32_t u32all; } flags; diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c index 8ec11da0319ffd..6627ee07d52d97 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c @@ -203,8 +203,7 @@ bool amdgpu_dpm_is_baco_supported(struct amdgpu_device *adev) { const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; void *pp_handle = adev->powerplay.pp_handle; - bool baco_cap; - int ret = 0; + bool ret; if (!pp_funcs || !pp_funcs->get_asic_baco_capability) return false; @@ -222,12 +221,11 @@ bool amdgpu_dpm_is_baco_supported(struct amdgpu_device *adev) mutex_lock(&adev->pm.mutex); - ret = pp_funcs->get_asic_baco_capability(pp_handle, - &baco_cap); + ret = pp_funcs->get_asic_baco_capability(pp_handle); mutex_unlock(&adev->pm.mutex); - return ret ? false : baco_cap; + return ret; } int amdgpu_dpm_mode2_reset(struct amdgpu_device *adev) @@ -618,6 +616,16 @@ void amdgpu_dpm_enable_jpeg(struct amdgpu_device *adev, bool enable) enable ? "enable" : "disable", ret); } +void amdgpu_dpm_enable_vpe(struct amdgpu_device *adev, bool enable) +{ + int ret = 0; + + ret = amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_VPE, !enable); + if (ret) + DRM_ERROR("Dpm %s vpe failed, ret = %d.\n", + enable ? "enable" : "disable", ret); +} + int amdgpu_pm_load_smu_firmware(struct amdgpu_device *adev, uint32_t *smu_version) { const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; @@ -1319,6 +1327,23 @@ int amdgpu_dpm_get_gpu_metrics(struct amdgpu_device *adev, void **table) return ret; } +ssize_t amdgpu_dpm_get_pm_metrics(struct amdgpu_device *adev, void *pm_metrics, + size_t size) +{ + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + int ret = 0; + + if (!pp_funcs->get_pm_metrics) + return -EOPNOTSUPP; + + mutex_lock(&adev->pm.mutex); + ret = pp_funcs->get_pm_metrics(adev->powerplay.pp_handle, pm_metrics, + size); + mutex_unlock(&adev->pm.mutex); + + return ret; +} + int amdgpu_dpm_get_fan_control_mode(struct amdgpu_device *adev, uint32_t *fan_mode) { diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index 20c53eefd680f4..087d57850304c4 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -1799,6 +1799,44 @@ static ssize_t amdgpu_set_apu_thermal_cap(struct device *dev, return count; } +static int amdgpu_pm_metrics_attr_update(struct amdgpu_device *adev, + struct amdgpu_device_attr *attr, + uint32_t mask, + enum amdgpu_device_attr_states *states) +{ + if (amdgpu_dpm_get_pm_metrics(adev, NULL, 0) == -EOPNOTSUPP) + *states = ATTR_STATE_UNSUPPORTED; + + return 0; +} + +static ssize_t amdgpu_get_pm_metrics(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(ddev); + ssize_t size = 0; + int ret; + + if (amdgpu_in_reset(adev)) + return -EPERM; + if (adev->in_suspend && !adev->in_runpm) + return -EPERM; + + ret = pm_runtime_get_sync(ddev->dev); + if (ret < 0) { + pm_runtime_put_autosuspend(ddev->dev); + return ret; + } + + size = amdgpu_dpm_get_pm_metrics(adev, buf, PAGE_SIZE); + + pm_runtime_mark_last_busy(ddev->dev); + pm_runtime_put_autosuspend(ddev->dev); + + return size; +} + /** * DOC: gpu_metrics * @@ -2096,6 +2134,8 @@ static struct amdgpu_device_attr amdgpu_device_attrs[] = { AMDGPU_DEVICE_ATTR_RW(smartshift_bias, ATTR_FLAG_BASIC, .attr_update = ss_bias_attr_update), AMDGPU_DEVICE_ATTR_RW(xgmi_plpd_policy, ATTR_FLAG_BASIC), + AMDGPU_DEVICE_ATTR_RO(pm_metrics, ATTR_FLAG_BASIC, + .attr_update = amdgpu_pm_metrics_attr_update), }; static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_attr *attr, @@ -4309,11 +4349,19 @@ static int amdgpu_debugfs_pm_info_pp(struct seq_file *m, struct amdgpu_device *a if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VDDNB, (void *)&value, &size)) seq_printf(m, "\t%u mV (VDDNB)\n", value); size = sizeof(uint32_t); - if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_AVG_POWER, (void *)&query, &size)) - seq_printf(m, "\t%u.%02u W (average GPU)\n", query >> 8, query & 0xff); + if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_AVG_POWER, (void *)&query, &size)) { + if (adev->flags & AMD_IS_APU) + seq_printf(m, "\t%u.%02u W (average SoC including CPU)\n", query >> 8, query & 0xff); + else + seq_printf(m, "\t%u.%02u W (average SoC)\n", query >> 8, query & 0xff); + } size = sizeof(uint32_t); - if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_INPUT_POWER, (void *)&query, &size)) - seq_printf(m, "\t%u.%02u W (current GPU)\n", query >> 8, query & 0xff); + if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_INPUT_POWER, (void *)&query, &size)) { + if (adev->flags & AMD_IS_APU) + seq_printf(m, "\t%u.%02u W (current SoC including CPU)\n", query >> 8, query & 0xff); + else + seq_printf(m, "\t%u.%02u W (current SoC)\n", query >> 8, query & 0xff); + } size = sizeof(value); seq_printf(m, "\n"); @@ -4339,9 +4387,9 @@ static int amdgpu_debugfs_pm_info_pp(struct seq_file *m, struct amdgpu_device *a /* VCN clocks */ if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VCN_POWER_STATE, (void *)&value, &size)) { if (!value) { - seq_printf(m, "VCN: Disabled\n"); + seq_printf(m, "VCN: Powered down\n"); } else { - seq_printf(m, "VCN: Enabled\n"); + seq_printf(m, "VCN: Powered up\n"); if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_UVD_DCLK, (void *)&value, &size)) seq_printf(m, "\t%u MHz (DCLK)\n", value/100); if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_UVD_VCLK, (void *)&value, &size)) @@ -4353,9 +4401,9 @@ static int amdgpu_debugfs_pm_info_pp(struct seq_file *m, struct amdgpu_device *a /* UVD clocks */ if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_UVD_POWER, (void *)&value, &size)) { if (!value) { - seq_printf(m, "UVD: Disabled\n"); + seq_printf(m, "UVD: Powered down\n"); } else { - seq_printf(m, "UVD: Enabled\n"); + seq_printf(m, "UVD: Powered up\n"); if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_UVD_DCLK, (void *)&value, &size)) seq_printf(m, "\t%u MHz (DCLK)\n", value/100); if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_UVD_VCLK, (void *)&value, &size)) @@ -4367,9 +4415,9 @@ static int amdgpu_debugfs_pm_info_pp(struct seq_file *m, struct amdgpu_device *a /* VCE clocks */ if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VCE_POWER, (void *)&value, &size)) { if (!value) { - seq_printf(m, "VCE: Disabled\n"); + seq_printf(m, "VCE: Powered down\n"); } else { - seq_printf(m, "VCE: Enabled\n"); + seq_printf(m, "VCE: Powered up\n"); if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_VCE_ECCLK, (void *)&value, &size)) seq_printf(m, "\t%u MHz (ECCLK)\n", value/100); } diff --git a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h index 482ea30147ab64..3047ffe7f2444b 100644 --- a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h +++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h @@ -445,6 +445,7 @@ void amdgpu_dpm_compute_clocks(struct amdgpu_device *adev); void amdgpu_dpm_enable_uvd(struct amdgpu_device *adev, bool enable); void amdgpu_dpm_enable_vce(struct amdgpu_device *adev, bool enable); void amdgpu_dpm_enable_jpeg(struct amdgpu_device *adev, bool enable); +void amdgpu_dpm_enable_vpe(struct amdgpu_device *adev, bool enable); int amdgpu_pm_load_smu_firmware(struct amdgpu_device *adev, uint32_t *smu_version); int amdgpu_dpm_handle_passthrough_sbr(struct amdgpu_device *adev, bool enable); int amdgpu_dpm_send_hbm_bad_pages_num(struct amdgpu_device *adev, uint32_t size); @@ -513,6 +514,18 @@ int amdgpu_dpm_get_power_profile_mode(struct amdgpu_device *adev, int amdgpu_dpm_set_power_profile_mode(struct amdgpu_device *adev, long *input, uint32_t size); int amdgpu_dpm_get_gpu_metrics(struct amdgpu_device *adev, void **table); + +/** + * @get_pm_metrics: Get one snapshot of power management metrics from PMFW. The + * sample is copied to pm_metrics buffer. It's expected to be allocated by the + * caller and size of the allocated buffer is passed. Max size expected for a + * metrics sample is 4096 bytes. + * + * Return: Actual size of the metrics sample + */ +ssize_t amdgpu_dpm_get_pm_metrics(struct amdgpu_device *adev, void *pm_metrics, + size_t size); + int amdgpu_dpm_get_fan_control_mode(struct amdgpu_device *adev, uint32_t *fan_mode); int amdgpu_dpm_set_fan_speed_pwm(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c b/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c index 5d28c951a31972..5cb4725c773f67 100644 --- a/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c +++ b/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c @@ -2735,10 +2735,8 @@ static int kv_parse_power_table(struct amdgpu_device *adev) non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) &non_clock_info_array->nonClockInfo[non_clock_array_index]; ps = kzalloc(sizeof(struct kv_ps), GFP_KERNEL); - if (ps == NULL) { - kfree(adev->pm.dpm.ps); + if (ps == NULL) return -ENOMEM; - } adev->pm.dpm.ps[i].ps_priv = ps; k = 0; idx = (u8 *)&power_state->v2.clockInfoIndex[0]; diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.c b/drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.c index 81fb4e5dd804bd..60377747bab4fc 100644 --- a/drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.c +++ b/drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.c @@ -272,10 +272,8 @@ int amdgpu_parse_extended_power_table(struct amdgpu_device *adev) le16_to_cpu(power_info->pplib4.usVddcDependencyOnSCLKOffset)); ret = amdgpu_parse_clk_voltage_dep_table(&adev->pm.dpm.dyn_state.vddc_dependency_on_sclk, dep_table); - if (ret) { - amdgpu_free_extended_power_table(adev); + if (ret) return ret; - } } if (power_info->pplib4.usVddciDependencyOnMCLKOffset) { dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *) @@ -283,10 +281,8 @@ int amdgpu_parse_extended_power_table(struct amdgpu_device *adev) le16_to_cpu(power_info->pplib4.usVddciDependencyOnMCLKOffset)); ret = amdgpu_parse_clk_voltage_dep_table(&adev->pm.dpm.dyn_state.vddci_dependency_on_mclk, dep_table); - if (ret) { - amdgpu_free_extended_power_table(adev); + if (ret) return ret; - } } if (power_info->pplib4.usVddcDependencyOnMCLKOffset) { dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *) @@ -294,10 +290,8 @@ int amdgpu_parse_extended_power_table(struct amdgpu_device *adev) le16_to_cpu(power_info->pplib4.usVddcDependencyOnMCLKOffset)); ret = amdgpu_parse_clk_voltage_dep_table(&adev->pm.dpm.dyn_state.vddc_dependency_on_mclk, dep_table); - if (ret) { - amdgpu_free_extended_power_table(adev); + if (ret) return ret; - } } if (power_info->pplib4.usMvddDependencyOnMCLKOffset) { dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *) @@ -305,10 +299,8 @@ int amdgpu_parse_extended_power_table(struct amdgpu_device *adev) le16_to_cpu(power_info->pplib4.usMvddDependencyOnMCLKOffset)); ret = amdgpu_parse_clk_voltage_dep_table(&adev->pm.dpm.dyn_state.mvdd_dependency_on_mclk, dep_table); - if (ret) { - amdgpu_free_extended_power_table(adev); + if (ret) return ret; - } } if (power_info->pplib4.usMaxClockVoltageOnDCOffset) { ATOM_PPLIB_Clock_Voltage_Limit_Table *clk_v = @@ -339,10 +331,8 @@ int amdgpu_parse_extended_power_table(struct amdgpu_device *adev) kcalloc(psl->ucNumEntries, sizeof(struct amdgpu_phase_shedding_limits_entry), GFP_KERNEL); - if (!adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries) { - amdgpu_free_extended_power_table(adev); + if (!adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries) return -ENOMEM; - } entry = &psl->entries[0]; for (i = 0; i < psl->ucNumEntries; i++) { @@ -383,10 +373,8 @@ int amdgpu_parse_extended_power_table(struct amdgpu_device *adev) ATOM_PPLIB_CAC_Leakage_Record *entry; u32 size = cac_table->ucNumEntries * sizeof(struct amdgpu_cac_leakage_table); adev->pm.dpm.dyn_state.cac_leakage_table.entries = kzalloc(size, GFP_KERNEL); - if (!adev->pm.dpm.dyn_state.cac_leakage_table.entries) { - amdgpu_free_extended_power_table(adev); + if (!adev->pm.dpm.dyn_state.cac_leakage_table.entries) return -ENOMEM; - } entry = &cac_table->entries[0]; for (i = 0; i < cac_table->ucNumEntries; i++) { if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_EVV) { @@ -438,10 +426,8 @@ int amdgpu_parse_extended_power_table(struct amdgpu_device *adev) sizeof(struct amdgpu_vce_clock_voltage_dependency_entry); adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries = kzalloc(size, GFP_KERNEL); - if (!adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries) { - amdgpu_free_extended_power_table(adev); + if (!adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries) return -ENOMEM; - } adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.count = limits->numEntries; entry = &limits->entries[0]; @@ -493,10 +479,8 @@ int amdgpu_parse_extended_power_table(struct amdgpu_device *adev) sizeof(struct amdgpu_uvd_clock_voltage_dependency_entry); adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries = kzalloc(size, GFP_KERNEL); - if (!adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries) { - amdgpu_free_extended_power_table(adev); + if (!adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries) return -ENOMEM; - } adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.count = limits->numEntries; entry = &limits->entries[0]; @@ -525,10 +509,8 @@ int amdgpu_parse_extended_power_table(struct amdgpu_device *adev) sizeof(struct amdgpu_clock_voltage_dependency_entry); adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries = kzalloc(size, GFP_KERNEL); - if (!adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries) { - amdgpu_free_extended_power_table(adev); + if (!adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries) return -ENOMEM; - } adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.count = limits->numEntries; entry = &limits->entries[0]; @@ -548,10 +530,8 @@ int amdgpu_parse_extended_power_table(struct amdgpu_device *adev) le16_to_cpu(ext_hdr->usPPMTableOffset)); adev->pm.dpm.dyn_state.ppm_table = kzalloc(sizeof(struct amdgpu_ppm_table), GFP_KERNEL); - if (!adev->pm.dpm.dyn_state.ppm_table) { - amdgpu_free_extended_power_table(adev); + if (!adev->pm.dpm.dyn_state.ppm_table) return -ENOMEM; - } adev->pm.dpm.dyn_state.ppm_table->ppm_design = ppm->ucPpmDesign; adev->pm.dpm.dyn_state.ppm_table->cpu_core_number = le16_to_cpu(ppm->usCpuCoreNumber); @@ -583,10 +563,8 @@ int amdgpu_parse_extended_power_table(struct amdgpu_device *adev) sizeof(struct amdgpu_clock_voltage_dependency_entry); adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries = kzalloc(size, GFP_KERNEL); - if (!adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries) { - amdgpu_free_extended_power_table(adev); + if (!adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries) return -ENOMEM; - } adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.count = limits->numEntries; entry = &limits->entries[0]; @@ -606,10 +584,8 @@ int amdgpu_parse_extended_power_table(struct amdgpu_device *adev) ATOM_PowerTune_Table *pt; adev->pm.dpm.dyn_state.cac_tdp_table = kzalloc(sizeof(struct amdgpu_cac_tdp_table), GFP_KERNEL); - if (!adev->pm.dpm.dyn_state.cac_tdp_table) { - amdgpu_free_extended_power_table(adev); + if (!adev->pm.dpm.dyn_state.cac_tdp_table) return -ENOMEM; - } if (rev > 0) { ATOM_PPLIB_POWERTUNE_Table_V1 *ppt = (ATOM_PPLIB_POWERTUNE_Table_V1 *) (mode_info->atom_context->bios + data_offset + @@ -645,10 +621,8 @@ int amdgpu_parse_extended_power_table(struct amdgpu_device *adev) ret = amdgpu_parse_clk_voltage_dep_table( &adev->pm.dpm.dyn_state.vddgfx_dependency_on_sclk, dep_table); - if (ret) { - kfree(adev->pm.dpm.dyn_state.vddgfx_dependency_on_sclk.entries); + if (ret) return ret; - } } } 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 fc8e4ac6c8e76b..df4f20293c16a3 100644 --- a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c +++ b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c @@ -7379,10 +7379,9 @@ static int si_dpm_init(struct amdgpu_device *adev) kcalloc(4, sizeof(struct amdgpu_clock_voltage_dependency_entry), GFP_KERNEL); - if (!adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries) { - amdgpu_free_extended_power_table(adev); + if (!adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries) return -ENOMEM; - } + adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.count = 4; adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[0].clk = 0; adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[0].v = 0; diff --git a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c index 914c1538715756..aed0e2cefbf990 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c @@ -1371,21 +1371,18 @@ static int pp_set_active_display_count(void *handle, uint32_t count) return phm_set_active_display_count(hwmgr, count); } -static int pp_get_asic_baco_capability(void *handle, bool *cap) +static bool pp_get_asic_baco_capability(void *handle) { struct pp_hwmgr *hwmgr = handle; - *cap = false; if (!hwmgr) - return -EINVAL; + return false; if (!(hwmgr->not_vf && amdgpu_dpm) || !hwmgr->hwmgr_func->get_asic_baco_capability) - return 0; + return false; - hwmgr->hwmgr_func->get_asic_baco_capability(hwmgr, cap); - - return 0; + return hwmgr->hwmgr_func->get_asic_baco_capability(hwmgr); } static int pp_get_asic_baco_state(void *handle, int *state) diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.c index f2a55c1413f597..17882f8dfdd34f 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.c @@ -200,7 +200,7 @@ static int get_platform_power_management_table( struct pp_hwmgr *hwmgr, ATOM_Tonga_PPM_Table *atom_ppm_table) { - struct phm_ppm_table *ptr = kzalloc(sizeof(ATOM_Tonga_PPM_Table), GFP_KERNEL); + struct phm_ppm_table *ptr = kzalloc(sizeof(*ptr), GFP_KERNEL); struct phm_ppt_v1_information *pp_table_information = (struct phm_ppt_v1_information *)(hwmgr->pptable); diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_baco.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_baco.c index 044cda005aed11..e8a9471c1898bc 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_baco.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_baco.c @@ -33,21 +33,20 @@ #include "smu/smu_7_1_2_d.h" #include "smu/smu_7_1_2_sh_mask.h" -int smu7_baco_get_capability(struct pp_hwmgr *hwmgr, bool *cap) +bool smu7_baco_get_capability(struct pp_hwmgr *hwmgr) { struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev); uint32_t reg; - *cap = false; if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_BACO)) return 0; reg = RREG32(mmCC_BIF_BX_FUSESTRAP0); if (reg & CC_BIF_BX_FUSESTRAP0__STRAP_BIF_PX_CAPABLE_MASK) - *cap = true; + return true; - return 0; + return false; } int smu7_baco_get_state(struct pp_hwmgr *hwmgr, enum BACO_STATE *state) diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_baco.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_baco.h index be0d98abb5369c..73a773f4ce2eb1 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_baco.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_baco.h @@ -25,7 +25,7 @@ #include "hwmgr.h" #include "common_baco.h" -extern int smu7_baco_get_capability(struct pp_hwmgr *hwmgr, bool *cap); +extern bool smu7_baco_get_capability(struct pp_hwmgr *hwmgr); extern int smu7_baco_get_state(struct pp_hwmgr *hwmgr, enum BACO_STATE *state); extern int smu7_baco_set_state(struct pp_hwmgr *hwmgr, enum BACO_STATE state); 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 11372fcc59c8fe..aa91730e4eaffd 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c @@ -2974,6 +2974,8 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) result = smu7_get_evv_voltages(hwmgr); if (result) { pr_info("Get EVV Voltage Failed. Abort Driver loading!\n"); + kfree(hwmgr->backend); + hwmgr->backend = NULL; return -EINVAL; } } else { @@ -3019,8 +3021,10 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) } result = smu7_update_edc_leakage_table(hwmgr); - if (result) + if (result) { + smu7_hwmgr_backend_fini(hwmgr); return result; + } return 0; } @@ -3995,6 +3999,7 @@ static int smu7_read_sensor(struct pp_hwmgr *hwmgr, int idx, uint32_t sclk, mclk, activity_percent; uint32_t offset, val_vid; struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); + struct amdgpu_device *adev = hwmgr->adev; /* size must be at least 4 bytes for all sensors */ if (*size < 4) @@ -4038,7 +4043,21 @@ static int smu7_read_sensor(struct pp_hwmgr *hwmgr, int idx, *size = 4; return 0; case AMDGPU_PP_SENSOR_GPU_INPUT_POWER: - return smu7_get_gpu_power(hwmgr, (uint32_t *)value); + if ((adev->asic_type != CHIP_HAWAII) && + (adev->asic_type != CHIP_BONAIRE) && + (adev->asic_type != CHIP_FIJI) && + (adev->asic_type != CHIP_TONGA)) + return smu7_get_gpu_power(hwmgr, (uint32_t *)value); + else + return -EOPNOTSUPP; + case AMDGPU_PP_SENSOR_GPU_AVG_POWER: + if ((adev->asic_type != CHIP_HAWAII) && + (adev->asic_type != CHIP_BONAIRE) && + (adev->asic_type != CHIP_FIJI) && + (adev->asic_type != CHIP_TONGA)) + return -EOPNOTSUPP; + else + return smu7_get_gpu_power(hwmgr, (uint32_t *)value); case AMDGPU_PP_SENSOR_VDDGFX: if ((data->vr_config & VRCONF_VDDGFX_MASK) == (VR_SVI2_PLANE_2 << VRCONF_VDDGFX_SHIFT)) diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu9_baco.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu9_baco.c index de0a37f7c63246..c66ef974153580 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu9_baco.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu9_baco.c @@ -28,14 +28,13 @@ #include "vega10_inc.h" #include "smu9_baco.h" -int smu9_baco_get_capability(struct pp_hwmgr *hwmgr, bool *cap) +bool smu9_baco_get_capability(struct pp_hwmgr *hwmgr) { struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev); uint32_t reg, data; - *cap = false; if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_BACO)) - return 0; + return false; WREG32(0x12074, 0xFFF0003B); data = RREG32(0x12075); @@ -44,10 +43,10 @@ int smu9_baco_get_capability(struct pp_hwmgr *hwmgr, bool *cap) reg = RREG32_SOC15(NBIF, 0, mmRCC_BIF_STRAP0); if (reg & RCC_BIF_STRAP0__STRAP_PX_CAPABLE_MASK) - *cap = true; + return true; } - return 0; + return false; } int smu9_baco_get_state(struct pp_hwmgr *hwmgr, enum BACO_STATE *state) diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu9_baco.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu9_baco.h index 84e90f801ac305..9ff7c2ea1b58d1 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu9_baco.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu9_baco.h @@ -25,7 +25,7 @@ #include "hwmgr.h" #include "common_baco.h" -extern int smu9_baco_get_capability(struct pp_hwmgr *hwmgr, bool *cap); +extern bool smu9_baco_get_capability(struct pp_hwmgr *hwmgr); extern int smu9_baco_get_state(struct pp_hwmgr *hwmgr, enum BACO_STATE *state); #endif diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_baco.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_baco.c index 994c0d374bfaeb..dad4c80aee58a2 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_baco.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_baco.c @@ -36,23 +36,22 @@ static const struct soc15_baco_cmd_entry clean_baco_tbl[] = { {CMD_WRITE, SOC15_REG_ENTRY(NBIF, 0, mmBIOS_SCRATCH_7), 0, 0, 0, 0}, }; -int vega20_baco_get_capability(struct pp_hwmgr *hwmgr, bool *cap) +bool vega20_baco_get_capability(struct pp_hwmgr *hwmgr) { struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev); uint32_t reg; - *cap = false; if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_BACO)) - return 0; + return false; if (((RREG32(0x17569) & 0x20000000) >> 29) == 0x1) { reg = RREG32_SOC15(NBIF, 0, mmRCC_BIF_STRAP0); if (reg & RCC_BIF_STRAP0__STRAP_PX_CAPABLE_MASK) - *cap = true; + return true; } - return 0; + return false; } int vega20_baco_get_state(struct pp_hwmgr *hwmgr, enum BACO_STATE *state) diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_baco.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_baco.h index f06471e712dcba..bdad9c915631b0 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_baco.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_baco.h @@ -25,7 +25,7 @@ #include "hwmgr.h" #include "common_baco.h" -extern int vega20_baco_get_capability(struct pp_hwmgr *hwmgr, bool *cap); +extern bool vega20_baco_get_capability(struct pp_hwmgr *hwmgr); extern int vega20_baco_get_state(struct pp_hwmgr *hwmgr, enum BACO_STATE *state); extern int vega20_baco_set_state(struct pp_hwmgr *hwmgr, enum BACO_STATE state); extern int vega20_baco_apply_vdci_flush_workaround(struct pp_hwmgr *hwmgr); diff --git a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h index 81650727a5defe..6f536159df4d8e 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h @@ -351,7 +351,7 @@ struct pp_hwmgr_func { int (*set_hard_min_fclk_by_freq)(struct pp_hwmgr *hwmgr, uint32_t clock); int (*set_hard_min_gfxclk_by_freq)(struct pp_hwmgr *hwmgr, uint32_t clock); int (*set_soft_max_gfxclk_by_freq)(struct pp_hwmgr *hwmgr, uint32_t clock); - int (*get_asic_baco_capability)(struct pp_hwmgr *hwmgr, bool *cap); + bool (*get_asic_baco_capability)(struct pp_hwmgr *hwmgr); int (*get_asic_baco_state)(struct pp_hwmgr *hwmgr, enum BACO_STATE *state); int (*set_asic_baco_state)(struct pp_hwmgr *hwmgr, enum BACO_STATE state); int (*get_ppfeature_status)(struct pp_hwmgr *hwmgr, char *buf); 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 9e4228232f024e..ad1fd3150d03ed 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/ci_smumgr.c @@ -2298,6 +2298,7 @@ static uint32_t ci_get_mac_definition(uint32_t value) case SMU_MAX_ENTRIES_SMIO: return SMU7_MAX_ENTRIES_SMIO; case SMU_MAX_LEVELS_VDDC: + case SMU_MAX_LEVELS_VDDGFX: return SMU7_MAX_LEVELS_VDDC; case SMU_MAX_LEVELS_VDDCI: return SMU7_MAX_LEVELS_VDDCI; 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 97d9802fe6731f..17d2f5bff4a7e3 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/smumgr/iceland_smumgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/smumgr/iceland_smumgr.c @@ -2263,6 +2263,7 @@ static uint32_t iceland_get_mac_definition(uint32_t value) case SMU_MAX_ENTRIES_SMIO: return SMU71_MAX_ENTRIES_SMIO; case SMU_MAX_LEVELS_VDDC: + case SMU_MAX_LEVELS_VDDGFX: return SMU71_MAX_LEVELS_VDDC; case SMU_MAX_LEVELS_VDDCI: return SMU71_MAX_LEVELS_VDDCI; diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index e1a5ee911dbbc6..7ffad3eb0a0150 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -24,6 +24,7 @@ #include #include +#include #include #include "amdgpu.h" @@ -817,16 +818,8 @@ static int smu_late_init(void *handle) * handle the switch automatically. Driver involvement * is unnecessary. */ - if (!smu->dc_controlled_by_gpio) { - ret = smu_set_power_source(smu, - adev->pm.ac_power ? SMU_POWER_SOURCE_AC : - SMU_POWER_SOURCE_DC); - if (ret) { - dev_err(adev->dev, "Failed to switch to %s mode!\n", - adev->pm.ac_power ? "AC" : "DC"); - return ret; - } - } + adev->pm.ac_power = power_supply_is_system_supplied() > 0; + smu_set_ac_dc(smu); if ((amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 1)) || (amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 3))) @@ -1322,6 +1315,187 @@ static int smu_get_thermal_temperature_range(struct smu_context *smu) return ret; } +/** + * smu_wbrf_handle_exclusion_ranges - consume the wbrf exclusion ranges + * + * @smu: smu_context pointer + * + * Retrieve the wbrf exclusion ranges and send them to PMFW for proper handling. + * Returns 0 on success, error on failure. + */ +static int smu_wbrf_handle_exclusion_ranges(struct smu_context *smu) +{ + struct wbrf_ranges_in_out wbrf_exclusion = {0}; + struct freq_band_range *wifi_bands = wbrf_exclusion.band_list; + struct amdgpu_device *adev = smu->adev; + uint32_t num_of_wbrf_ranges = MAX_NUM_OF_WBRF_RANGES; + uint64_t start, end; + int ret, i, j; + + ret = amd_wbrf_retrieve_freq_band(adev->dev, &wbrf_exclusion); + if (ret) { + dev_err(adev->dev, "Failed to retrieve exclusion ranges!\n"); + return ret; + } + + /* + * The exclusion ranges array we got might be filled with holes and duplicate + * entries. For example: + * {(2400, 2500), (0, 0), (6882, 6962), (2400, 2500), (0, 0), (6117, 6189), (0, 0)...} + * We need to do some sortups to eliminate those holes and duplicate entries. + * Expected output: {(2400, 2500), (6117, 6189), (6882, 6962), (0, 0)...} + */ + for (i = 0; i < num_of_wbrf_ranges; i++) { + start = wifi_bands[i].start; + end = wifi_bands[i].end; + + /* get the last valid entry to fill the intermediate hole */ + if (!start && !end) { + for (j = num_of_wbrf_ranges - 1; j > i; j--) + if (wifi_bands[j].start && wifi_bands[j].end) + break; + + /* no valid entry left */ + if (j <= i) + break; + + start = wifi_bands[i].start = wifi_bands[j].start; + end = wifi_bands[i].end = wifi_bands[j].end; + wifi_bands[j].start = 0; + wifi_bands[j].end = 0; + num_of_wbrf_ranges = j; + } + + /* eliminate duplicate entries */ + for (j = i + 1; j < num_of_wbrf_ranges; j++) { + if ((wifi_bands[j].start == start) && (wifi_bands[j].end == end)) { + wifi_bands[j].start = 0; + wifi_bands[j].end = 0; + } + } + } + + /* Send the sorted wifi_bands to PMFW */ + ret = smu_set_wbrf_exclusion_ranges(smu, wifi_bands); + /* Try to set the wifi_bands again */ + if (unlikely(ret == -EBUSY)) { + mdelay(5); + ret = smu_set_wbrf_exclusion_ranges(smu, wifi_bands); + } + + return ret; +} + +/** + * smu_wbrf_event_handler - handle notify events + * + * @nb: notifier block + * @action: event type + * @_arg: event data + * + * Calls relevant amdgpu function in response to wbrf event + * notification from kernel. + */ +static int smu_wbrf_event_handler(struct notifier_block *nb, + unsigned long action, void *_arg) +{ + struct smu_context *smu = container_of(nb, struct smu_context, wbrf_notifier); + + switch (action) { + case WBRF_CHANGED: + schedule_delayed_work(&smu->wbrf_delayed_work, + msecs_to_jiffies(SMU_WBRF_EVENT_HANDLING_PACE)); + break; + default: + return NOTIFY_DONE; + } + + return NOTIFY_OK; +} + +/** + * smu_wbrf_delayed_work_handler - callback on delayed work timer expired + * + * @work: struct work_struct pointer + * + * Flood is over and driver will consume the latest exclusion ranges. + */ +static void smu_wbrf_delayed_work_handler(struct work_struct *work) +{ + struct smu_context *smu = container_of(work, struct smu_context, wbrf_delayed_work.work); + + smu_wbrf_handle_exclusion_ranges(smu); +} + +/** + * smu_wbrf_support_check - check wbrf support + * + * @smu: smu_context pointer + * + * Verifies the ACPI interface whether wbrf is supported. + */ +static void smu_wbrf_support_check(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + + smu->wbrf_supported = smu_is_asic_wbrf_supported(smu) && amdgpu_wbrf && + acpi_amd_wbrf_supported_consumer(adev->dev); + + if (smu->wbrf_supported) + dev_info(adev->dev, "RF interference mitigation is supported\n"); +} + +/** + * smu_wbrf_init - init driver wbrf support + * + * @smu: smu_context pointer + * + * Verifies the AMD ACPI interfaces and registers with the wbrf + * notifier chain if wbrf feature is supported. + * Returns 0 on success, error on failure. + */ +static int smu_wbrf_init(struct smu_context *smu) +{ + int ret; + + if (!smu->wbrf_supported) + return 0; + + INIT_DELAYED_WORK(&smu->wbrf_delayed_work, smu_wbrf_delayed_work_handler); + + smu->wbrf_notifier.notifier_call = smu_wbrf_event_handler; + ret = amd_wbrf_register_notifier(&smu->wbrf_notifier); + if (ret) + return ret; + + /* + * Some wifiband exclusion ranges may be already there + * before our driver loaded. To make sure our driver + * is awared of those exclusion ranges. + */ + schedule_delayed_work(&smu->wbrf_delayed_work, + msecs_to_jiffies(SMU_WBRF_EVENT_HANDLING_PACE)); + + return 0; +} + +/** + * smu_wbrf_fini - tear down driver wbrf support + * + * @smu: smu_context pointer + * + * Unregisters with the wbrf notifier chain. + */ +static void smu_wbrf_fini(struct smu_context *smu) +{ + if (!smu->wbrf_supported) + return; + + amd_wbrf_unregister_notifier(&smu->wbrf_notifier); + + cancel_delayed_work_sync(&smu->wbrf_delayed_work); +} + static int smu_smc_hw_setup(struct smu_context *smu) { struct smu_feature *feature = &smu->smu_feature; @@ -1414,6 +1588,15 @@ static int smu_smc_hw_setup(struct smu_context *smu) if (ret) return ret; + /* Enable UclkShadow on wbrf supported */ + if (smu->wbrf_supported) { + ret = smu_enable_uclk_shadow(smu, true); + if (ret) { + dev_err(adev->dev, "Failed to enable UclkShadow feature to support wbrf!\n"); + return ret; + } + } + /* * With SCPM enabled, these actions(and relevant messages) are * not needed and permitted. @@ -1512,6 +1695,15 @@ static int smu_smc_hw_setup(struct smu_context *smu) */ ret = smu_set_min_dcef_deep_sleep(smu, smu->smu_table.boot_values.dcefclk / 100); + if (ret) { + dev_err(adev->dev, "Error setting min deepsleep dcefclk\n"); + return ret; + } + + /* Init wbrf support. Properly setup the notifier */ + ret = smu_wbrf_init(smu); + if (ret) + dev_err(adev->dev, "Error during wbrf init call\n"); return ret; } @@ -1567,6 +1759,13 @@ static int smu_hw_init(void *handle) return ret; } + /* + * Check whether wbrf is supported. This needs to be done + * before SMU setup starts since part of SMU configuration + * relies on this. + */ + smu_wbrf_support_check(smu); + if (smu->is_apu) { ret = smu_set_gfx_imu_enable(smu); if (ret) @@ -1733,6 +1932,8 @@ static int smu_smc_hw_cleanup(struct smu_context *smu) struct amdgpu_device *adev = smu->adev; int ret = 0; + smu_wbrf_fini(smu); + cancel_work_sync(&smu->throttling_logging_work); cancel_work_sync(&smu->interrupt_work); @@ -2502,6 +2703,7 @@ int smu_get_power_limit(void *handle, case SMU_PPT_LIMIT_CURRENT: switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) { case IP_VERSION(13, 0, 2): + case IP_VERSION(13, 0, 6): case IP_VERSION(11, 0, 7): case IP_VERSION(11, 0, 11): case IP_VERSION(11, 0, 12): @@ -3015,19 +3217,17 @@ static int smu_set_xgmi_pstate(void *handle, return ret; } -static int smu_get_baco_capability(void *handle, bool *cap) +static bool smu_get_baco_capability(void *handle) { struct smu_context *smu = handle; - *cap = false; - if (!smu->pm_enabled) - return 0; + return false; - if (smu->ppt_funcs && smu->ppt_funcs->baco_is_support) - *cap = smu->ppt_funcs->baco_is_support(smu); + if (!smu->ppt_funcs || !smu->ppt_funcs->baco_is_support) + return false; - return 0; + return smu->ppt_funcs->baco_is_support(smu); } static int smu_baco_set_state(void *handle, int state) @@ -3201,6 +3401,20 @@ static ssize_t smu_sys_get_gpu_metrics(void *handle, void **table) return smu->ppt_funcs->get_gpu_metrics(smu, table); } +static ssize_t smu_sys_get_pm_metrics(void *handle, void *pm_metrics, + size_t size) +{ + struct smu_context *smu = handle; + + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; + + if (!smu->ppt_funcs->get_pm_metrics) + return -EOPNOTSUPP; + + return smu->ppt_funcs->get_pm_metrics(smu, pm_metrics, size); +} + static int smu_enable_mgpu_fan_boost(void *handle) { struct smu_context *smu = handle; @@ -3342,6 +3556,7 @@ static const struct amd_pm_funcs swsmu_pm_funcs = { .set_df_cstate = smu_set_df_cstate, .set_xgmi_pstate = smu_set_xgmi_pstate, .get_gpu_metrics = smu_sys_get_gpu_metrics, + .get_pm_metrics = smu_sys_get_pm_metrics, .set_watermarks_for_clock_ranges = smu_set_watermarks_for_clock_ranges, .display_disable_memory_clock_switch = smu_display_disable_memory_clock_switch, .get_max_sustainable_clocks_by_dc = smu_get_max_sustainable_clocks_by_dc, 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 f8b2e6cc256888..2aa4fea8731475 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h @@ -22,6 +22,9 @@ #ifndef __AMDGPU_SMU_H__ #define __AMDGPU_SMU_H__ +#include +#include + #include "amdgpu.h" #include "kgd_pp_interface.h" #include "dm_pp_interface.h" @@ -253,6 +256,7 @@ struct smu_table { uint64_t mc_address; void *cpu_addr; struct amdgpu_bo *bo; + uint32_t version; }; enum smu_perf_level_designation { @@ -317,6 +321,7 @@ enum smu_table_id { SMU_TABLE_PACE, SMU_TABLE_ECCINFO, SMU_TABLE_COMBO_PPTABLE, + SMU_TABLE_WIFIBAND, SMU_TABLE_COUNT, }; @@ -470,6 +475,12 @@ struct stb_context { #define WORKLOAD_POLICY_MAX 7 +/* + * Configure wbrf event handling pace as there can be only one + * event processed every SMU_WBRF_EVENT_HANDLING_PACE ms. + */ +#define SMU_WBRF_EVENT_HANDLING_PACE 10 + struct smu_context { struct amdgpu_device *adev; struct amdgpu_irq_src irq_source; @@ -569,6 +580,11 @@ struct smu_context { struct delayed_work swctf_delayed_work; enum pp_xgmi_plpd_mode plpd_mode; + + /* data structures for wbrf feature support */ + bool wbrf_supported; + struct notifier_block wbrf_notifier; + struct delayed_work wbrf_delayed_work; }; struct i2c_adapter; @@ -1252,6 +1268,15 @@ struct pptable_funcs { */ ssize_t (*get_gpu_metrics)(struct smu_context *smu, void **table); + /** + * @get_pm_metrics: Get one snapshot of power management metrics from + * PMFW. + * + * Return: Size of the metrics sample + */ + ssize_t (*get_pm_metrics)(struct smu_context *smu, void *pm_metrics, + size_t size); + /** * @enable_mgpu_fan_boost: Enable multi-GPU fan boost. */ @@ -1365,6 +1390,22 @@ struct pptable_funcs { * @notify_rlc_state: Notify RLC power state to SMU. */ int (*notify_rlc_state)(struct smu_context *smu, bool en); + + /** + * @is_asic_wbrf_supported: check whether PMFW supports the wbrf feature + */ + bool (*is_asic_wbrf_supported)(struct smu_context *smu); + + /** + * @enable_uclk_shadow: Enable the uclk shadow feature on wbrf supported + */ + int (*enable_uclk_shadow)(struct smu_context *smu, bool enable); + + /** + * @set_wbrf_exclusion_ranges: notify SMU the wifi bands occupied + */ + int (*set_wbrf_exclusion_ranges)(struct smu_context *smu, + struct freq_band_range *exclusion_ranges); }; typedef enum { @@ -1491,6 +1532,17 @@ enum smu_baco_seq { __dst_size); \ }) +typedef struct { + uint16_t LowFreq; + uint16_t HighFreq; +} WifiOneBand_t; + +typedef struct { + uint32_t WifiBandEntryNum; + WifiOneBand_t WifiBandEntry[11]; + uint32_t MmHubPadding[8]; +} WifiBandEntryTable_t; + #if !defined(SWSMU_CODE_LAYER_L2) && !defined(SWSMU_CODE_LAYER_L3) && !defined(SWSMU_CODE_LAYER_L4) int smu_get_power_limit(void *handle, uint32_t *limit, 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 9dd1ed5b894067..b114d14fc053e7 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 @@ -1615,7 +1615,8 @@ typedef struct { #define TABLE_I2C_COMMANDS 9 #define TABLE_DRIVER_INFO 10 #define TABLE_ECCINFO 11 -#define TABLE_COUNT 12 +#define TABLE_WIFIBAND 12 +#define TABLE_COUNT 13 //IH Interupt ID #define IH_INTERRUPT_ID_TO_DRIVER 0xFE 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 62b7c0daff6873..8b1496f8ce584f 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 @@ -1605,7 +1605,8 @@ typedef struct { #define TABLE_I2C_COMMANDS 9 #define TABLE_DRIVER_INFO 10 #define TABLE_ECCINFO 11 -#define TABLE_COUNT 12 +#define TABLE_WIFIBAND 12 +#define TABLE_COUNT 13 //IH Interupt ID #define IH_INTERRUPT_ID_TO_DRIVER 0xFE diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu14_driver_if_v14_0_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu14_driver_if_v14_0_0.h index 8f42771e1f0a28..5bb7a63c0602b7 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu14_driver_if_v14_0_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu14_driver_if_v14_0_0.h @@ -24,11 +24,6 @@ #ifndef SMU14_DRIVER_IF_V14_0_0_H #define SMU14_DRIVER_IF_V14_0_0_H -// *** IMPORTANT *** -// SMU TEAM: Always increment the interface version if -// any structure is changed in this file -#define PMFW_DRIVER_IF_VERSION 7 - typedef struct { int32_t value; uint32_t numFractionalBits; 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 e2ee855c774880..e862d323caab7f 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 @@ -138,10 +138,9 @@ #define PPSMC_MSG_SetBadMemoryPagesRetiredFlagsPerChannel 0x4A #define PPSMC_MSG_SetPriorityDeltaGain 0x4B #define PPSMC_MSG_AllowIHHostInterrupt 0x4C - #define PPSMC_MSG_DALNotPresent 0x4E - -#define PPSMC_Message_Count 0x4F +#define PPSMC_MSG_EnableUCLKShadow 0x51 +#define PPSMC_Message_Count 0x52 //Debug Dump Message #define DEBUGSMC_MSG_TestMessage 0x1 diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_7_ppsmc.h b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_7_ppsmc.h index 6aaefca9b595c7..a6bf9cdd130ec6 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_7_ppsmc.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/pmfw_if/smu_v13_0_7_ppsmc.h @@ -134,6 +134,7 @@ #define PPSMC_MSG_SetBadMemoryPagesRetiredFlagsPerChannel 0x4A #define PPSMC_MSG_SetPriorityDeltaGain 0x4B #define PPSMC_MSG_AllowIHHostInterrupt 0x4C -#define PPSMC_Message_Count 0x4D +#define PPSMC_MSG_EnableUCLKShadow 0x51 +#define PPSMC_Message_Count 0x52 #endif 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 9dd47d91093eb6..953a767613b11b 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_types.h @@ -259,7 +259,9 @@ __SMU_DUMMY_MAP(PowerUpUmsch), \ __SMU_DUMMY_MAP(PowerDownUmsch), \ __SMU_DUMMY_MAP(SetSoftMaxVpe), \ - __SMU_DUMMY_MAP(SetSoftMinVpe), + __SMU_DUMMY_MAP(SetSoftMinVpe), \ + __SMU_DUMMY_MAP(GetMetricsVersion), \ + __SMU_DUMMY_MAP(EnableUCLKShadow), #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 95cb919718aebe..fbd57fa1a00492 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 @@ -210,15 +210,8 @@ int smu_v13_0_set_azalia_d3_pme(struct smu_context *smu); int smu_v13_0_get_max_sustainable_clocks_by_dc(struct smu_context *smu, struct pp_smu_nv_clock_table *max_clocks); -int smu_v13_0_baco_set_armd3_sequence(struct smu_context *smu, - enum smu_baco_seq baco_seq); - bool smu_v13_0_baco_is_support(struct smu_context *smu); -enum smu_baco_state smu_v13_0_baco_get_state(struct smu_context *smu); - -int smu_v13_0_baco_set_state(struct smu_context *smu, enum smu_baco_state state); - int smu_v13_0_baco_enter(struct smu_context *smu); int smu_v13_0_baco_exit(struct smu_context *smu); @@ -301,5 +294,9 @@ int smu_v13_0_update_pcie_parameters(struct smu_context *smu, int smu_v13_0_disable_pmfw_state(struct smu_context *smu); +int smu_v13_0_enable_uclk_shadow(struct smu_context *smu, bool enable); + +int smu_v13_0_set_wbrf_exclusion_ranges(struct smu_context *smu, + struct freq_band_range *exclusion_ranges); #endif #endif diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h index a5b569976f1928..3f7463c1c1a919 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h @@ -26,8 +26,8 @@ #include "amdgpu_smu.h" #define SMU14_DRIVER_IF_VERSION_INV 0xFFFFFFFF +#define SMU14_DRIVER_IF_VERSION_SMU_V14_0_0 0x7 #define SMU14_DRIVER_IF_VERSION_SMU_V14_0_2 0x1 -#define SMU14_DRIVER_IF_VERSION_SMU_V14_0_0 0x6 #define FEATURE_MASK(feature) (1ULL << feature) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c index 2cb6b68222babf..4cd43bbec910e3 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c @@ -2407,8 +2407,6 @@ static const struct pptable_funcs arcturus_ppt_funcs = { .set_azalia_d3_pme = smu_v11_0_set_azalia_d3_pme, .get_max_sustainable_clocks_by_dc = smu_v11_0_get_max_sustainable_clocks_by_dc, .baco_is_support = smu_v11_0_baco_is_support, - .baco_get_state = smu_v11_0_baco_get_state, - .baco_set_state = smu_v11_0_baco_set_state, .baco_enter = smu_v11_0_baco_enter, .baco_exit = smu_v11_0_baco_exit, .get_dpm_ultimate_freq = smu_v11_0_get_dpm_ultimate_freq, 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 a38233cc5b7ff8..8d1d29ffb0f1c5 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c @@ -3537,8 +3537,6 @@ static const struct pptable_funcs navi10_ppt_funcs = { .set_azalia_d3_pme = smu_v11_0_set_azalia_d3_pme, .get_max_sustainable_clocks_by_dc = smu_v11_0_get_max_sustainable_clocks_by_dc, .baco_is_support = smu_v11_0_baco_is_support, - .baco_get_state = smu_v11_0_baco_get_state, - .baco_set_state = smu_v11_0_baco_set_state, .baco_enter = navi10_baco_enter, .baco_exit = navi10_baco_exit, .get_dpm_ultimate_freq = smu_v11_0_get_dpm_ultimate_freq, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c index 1de9f8b5cc5fa4..21fc033528fa9d 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c @@ -4428,8 +4428,6 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = { .set_azalia_d3_pme = smu_v11_0_set_azalia_d3_pme, .get_max_sustainable_clocks_by_dc = smu_v11_0_get_max_sustainable_clocks_by_dc, .baco_is_support = smu_v11_0_baco_is_support, - .baco_get_state = smu_v11_0_baco_get_state, - .baco_set_state = smu_v11_0_baco_set_state, .baco_enter = sienna_cichlid_baco_enter, .baco_exit = sienna_cichlid_baco_exit, .mode1_reset_is_support = sienna_cichlid_is_mode1_reset_supported, 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 5a314d0316c1c8..c7bfa68bf00f40 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 @@ -1442,10 +1442,12 @@ static int smu_v11_0_irq_process(struct amdgpu_device *adev, case 0x3: dev_dbg(adev->dev, "Switched to AC mode!\n"); schedule_work(&smu->interrupt_work); + adev->pm.ac_power = true; break; case 0x4: dev_dbg(adev->dev, "Switched to DC mode!\n"); schedule_work(&smu->interrupt_work); + adev->pm.ac_power = false; break; case 0x7: /* diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index f1440869d1ce05..dd9bcbd630a1f9 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -1530,7 +1530,6 @@ static int aldebaran_i2c_control_init(struct smu_context *smu) smu_i2c->port = 0; mutex_init(&smu_i2c->mutex); control->owner = THIS_MODULE; - control->class = I2C_CLASS_SPD; control->dev.parent = &adev->pdev->dev; control->algo = &aldebaran_i2c_algo; snprintf(control->name, sizeof(control->name), "AMDGPU SMU 0"); 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 cf1b84060bc3da..c486182ff27522 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 @@ -1379,10 +1379,12 @@ static int smu_v13_0_irq_process(struct amdgpu_device *adev, case 0x3: dev_dbg(adev->dev, "Switched to AC mode!\n"); smu_v13_0_ack_ac_dc_interrupt(smu); + adev->pm.ac_power = true; break; case 0x4: dev_dbg(adev->dev, "Switched to DC mode!\n"); smu_v13_0_ack_ac_dc_interrupt(smu); + adev->pm.ac_power = false; break; case 0x7: /* @@ -2199,7 +2201,7 @@ int smu_v13_0_gfx_ulv_control(struct smu_context *smu, return ret; } -int smu_v13_0_baco_set_armd3_sequence(struct smu_context *smu, +static int smu_v13_0_baco_set_armd3_sequence(struct smu_context *smu, enum smu_baco_seq baco_seq) { struct smu_baco_context *smu_baco = &smu->smu_baco; @@ -2221,33 +2223,14 @@ int smu_v13_0_baco_set_armd3_sequence(struct smu_context *smu, return 0; } -bool smu_v13_0_baco_is_support(struct smu_context *smu) -{ - struct smu_baco_context *smu_baco = &smu->smu_baco; - - if (amdgpu_sriov_vf(smu->adev) || - !smu_baco->platform_support) - return false; - - /* return true if ASIC is in BACO state already */ - if (smu_v13_0_baco_get_state(smu) == SMU_BACO_STATE_ENTER) - return true; - - if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_BACO_BIT) && - !smu_cmn_feature_is_enabled(smu, SMU_FEATURE_BACO_BIT)) - return false; - - return true; -} - -enum smu_baco_state smu_v13_0_baco_get_state(struct smu_context *smu) +static enum smu_baco_state smu_v13_0_baco_get_state(struct smu_context *smu) { struct smu_baco_context *smu_baco = &smu->smu_baco; return smu_baco->state; } -int smu_v13_0_baco_set_state(struct smu_context *smu, +static int smu_v13_0_baco_set_state(struct smu_context *smu, enum smu_baco_state state) { struct smu_baco_context *smu_baco = &smu->smu_baco; @@ -2281,24 +2264,60 @@ int smu_v13_0_baco_set_state(struct smu_context *smu, return ret; } -int smu_v13_0_baco_enter(struct smu_context *smu) +bool smu_v13_0_baco_is_support(struct smu_context *smu) { - int ret = 0; + struct smu_baco_context *smu_baco = &smu->smu_baco; - ret = smu_v13_0_baco_set_state(smu, - SMU_BACO_STATE_ENTER); - if (ret) - return ret; + if (amdgpu_sriov_vf(smu->adev) || !smu_baco->platform_support) + return false; + + /* return true if ASIC is in BACO state already */ + if (smu_v13_0_baco_get_state(smu) == SMU_BACO_STATE_ENTER) + return true; - msleep(10); + if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_BACO_BIT) && + !smu_cmn_feature_is_enabled(smu, SMU_FEATURE_BACO_BIT)) + return false; - return ret; + return true; +} + +int smu_v13_0_baco_enter(struct smu_context *smu) +{ + struct smu_baco_context *smu_baco = &smu->smu_baco; + struct amdgpu_device *adev = smu->adev; + int ret; + + if (adev->in_runpm && smu_cmn_is_audio_func_enabled(adev)) { + return smu_v13_0_baco_set_armd3_sequence(smu, + (smu_baco->maco_support && amdgpu_runtime_pm != 1) ? + BACO_SEQ_BAMACO : BACO_SEQ_BACO); + } else { + ret = smu_v13_0_baco_set_state(smu, SMU_BACO_STATE_ENTER); + if (!ret) + usleep_range(10000, 11000); + + return ret; + } } int smu_v13_0_baco_exit(struct smu_context *smu) { - return smu_v13_0_baco_set_state(smu, - SMU_BACO_STATE_EXIT); + struct amdgpu_device *adev = smu->adev; + int ret; + + if (adev->in_runpm && smu_cmn_is_audio_func_enabled(adev)) { + /* Wait for PMFW handling for the Dstate change */ + usleep_range(10000, 11000); + ret = smu_v13_0_baco_set_armd3_sequence(smu, BACO_SEQ_ULPS); + } else { + ret = smu_v13_0_baco_set_state(smu, SMU_BACO_STATE_EXIT); + } + + if (!ret) + adev->gfx.is_poweron = false; + + return ret; } int smu_v13_0_set_gfx_power_up_by_imu(struct smu_context *smu) @@ -2490,3 +2509,51 @@ int smu_v13_0_disable_pmfw_state(struct smu_context *smu) return ret == 0 ? 0 : -EINVAL; } + +int smu_v13_0_enable_uclk_shadow(struct smu_context *smu, bool enable) +{ + return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_EnableUCLKShadow, enable, NULL); +} + +int smu_v13_0_set_wbrf_exclusion_ranges(struct smu_context *smu, + struct freq_band_range *exclusion_ranges) +{ + WifiBandEntryTable_t wifi_bands; + int valid_entries = 0; + int ret, i; + + memset(&wifi_bands, 0, sizeof(wifi_bands)); + for (i = 0; i < ARRAY_SIZE(wifi_bands.WifiBandEntry); i++) { + if (!exclusion_ranges[i].start && !exclusion_ranges[i].end) + break; + + /* PMFW expects the inputs to be in Mhz unit */ + wifi_bands.WifiBandEntry[valid_entries].LowFreq = + DIV_ROUND_DOWN_ULL(exclusion_ranges[i].start, HZ_PER_MHZ); + wifi_bands.WifiBandEntry[valid_entries++].HighFreq = + DIV_ROUND_UP_ULL(exclusion_ranges[i].end, HZ_PER_MHZ); + } + wifi_bands.WifiBandEntryNum = valid_entries; + + /* + * Per confirm with PMFW team, WifiBandEntryNum = 0 + * is a valid setting. + * + * Considering the scenarios below: + * - At first the wifi device adds an exclusion range e.g. (2400,2500) to + * BIOS and our driver gets notified. We will set WifiBandEntryNum = 1 + * and pass the WifiBandEntry (2400, 2500) to PMFW. + * + * - Later the wifi device removes the wifiband list added above and + * our driver gets notified again. At this time, driver will set + * WifiBandEntryNum = 0 and pass an empty WifiBandEntry list to PMFW. + * + * - PMFW may still need to do some uclk shadow update(e.g. switching + * from shadow clock back to primary clock) on receiving this. + */ + ret = smu_cmn_update_table(smu, SMU_TABLE_WIFIBAND, 0, &wifi_bands, true); + if (ret) + dev_warn(smu->adev->dev, "Failed to set wifiband!"); + + return ret; +} 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 82c4e1f1c6f075..4fdf34fffa9a57 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 @@ -169,6 +169,7 @@ static struct cmn2asic_msg_mapping smu_v13_0_0_message_map[SMU_MSG_MAX_COUNT] = MSG_MAP(AllowIHHostInterrupt, PPSMC_MSG_AllowIHHostInterrupt, 0), MSG_MAP(ReenableAcDcInterrupt, PPSMC_MSG_ReenableAcDcInterrupt, 0), MSG_MAP(DALNotPresent, PPSMC_MSG_DALNotPresent, 0), + MSG_MAP(EnableUCLKShadow, PPSMC_MSG_EnableUCLKShadow, 0), }; static struct cmn2asic_mapping smu_v13_0_0_clk_map[SMU_CLK_COUNT] = { @@ -253,6 +254,7 @@ static struct cmn2asic_mapping smu_v13_0_0_table_map[SMU_TABLE_COUNT] = { TAB_MAP(I2C_COMMANDS), TAB_MAP(ECCINFO), TAB_MAP(OVERDRIVE), + TAB_MAP(WIFIBAND), }; static struct cmn2asic_mapping smu_v13_0_0_pwr_src_map[SMU_POWER_SOURCE_COUNT] = { @@ -498,6 +500,9 @@ static int smu_v13_0_0_tables_init(struct smu_context *smu) PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); SMU_TABLE_INIT(tables, SMU_TABLE_ECCINFO, sizeof(EccInfoTable_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); + SMU_TABLE_INIT(tables, SMU_TABLE_WIFIBAND, + sizeof(WifiBandEntryTable_t), PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM); smu_table->metrics_table = kzalloc(sizeof(SmuMetricsExternal_t), GFP_KERNEL); if (!smu_table->metrics_table) @@ -2352,6 +2357,7 @@ static int smu_v13_0_0_get_power_limit(struct smu_context *smu, PPTable_t *pptable = table_context->driver_pptable; SkuTable_t *skutable = &pptable->SkuTable; uint32_t power_limit, od_percent_upper, od_percent_lower; + uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC]; if (smu_v13_0_get_current_power_limit(smu, &power_limit)) power_limit = smu->adev->pm.ac_power ? @@ -2375,7 +2381,7 @@ static int smu_v13_0_0_get_power_limit(struct smu_context *smu, od_percent_upper, od_percent_lower, power_limit); if (max_power_limit) { - *max_power_limit = power_limit * (100 + od_percent_upper); + *max_power_limit = msg_limit * (100 + od_percent_upper); *max_power_limit /= 100; } @@ -2540,16 +2546,19 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu, workload_mask = 1 << workload_type; - /* Add optimizations for SMU13.0.0. Reuse the power saving profile */ - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE && - (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 0)) && - ((smu->adev->pm.fw_version == 0x004e6601) || - (smu->adev->pm.fw_version >= 0x004e7400))) { - workload_type = smu_cmn_to_asic_specific_index(smu, - CMN2ASIC_MAPPING_WORKLOAD, - PP_SMC_POWER_PROFILE_POWERSAVING); - if (workload_type >= 0) - workload_mask |= 1 << workload_type; + /* Add optimizations for SMU13.0.0/10. Reuse the power saving profile */ + if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE) { + if ((amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 0) && + ((smu->adev->pm.fw_version == 0x004e6601) || + (smu->adev->pm.fw_version >= 0x004e7300))) || + (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 10) && + smu->adev->pm.fw_version >= 0x00504500)) { + workload_type = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_WORKLOAD, + PP_SMC_POWER_PROFILE_POWERSAVING); + if (workload_type >= 0) + workload_mask |= 1 << workload_type; + } } return smu_cmn_send_smc_msg_with_param(smu, @@ -2558,38 +2567,6 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu, NULL); } -static int smu_v13_0_0_baco_enter(struct smu_context *smu) -{ - struct smu_baco_context *smu_baco = &smu->smu_baco; - struct amdgpu_device *adev = smu->adev; - - if (adev->in_runpm && smu_cmn_is_audio_func_enabled(adev)) - return smu_v13_0_baco_set_armd3_sequence(smu, - (smu_baco->maco_support && amdgpu_runtime_pm != 1) ? - BACO_SEQ_BAMACO : BACO_SEQ_BACO); - else - return smu_v13_0_baco_enter(smu); -} - -static int smu_v13_0_0_baco_exit(struct smu_context *smu) -{ - struct amdgpu_device *adev = smu->adev; - int ret; - - if (adev->in_runpm && smu_cmn_is_audio_func_enabled(adev)) { - /* Wait for PMFW handling for the Dstate change */ - usleep_range(10000, 11000); - ret = smu_v13_0_baco_set_armd3_sequence(smu, BACO_SEQ_ULPS); - } else { - ret = smu_v13_0_baco_exit(smu); - } - - if (!ret) - adev->gfx.is_poweron = false; - - return ret; -} - static bool smu_v13_0_0_is_mode1_reset_supported(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; @@ -2720,7 +2697,6 @@ static int smu_v13_0_0_i2c_control_init(struct smu_context *smu) smu_i2c->port = i; mutex_init(&smu_i2c->mutex); control->owner = THIS_MODULE; - control->class = I2C_CLASS_SPD; control->dev.parent = &adev->pdev->dev; control->algo = &smu_v13_0_0_i2c_algo; snprintf(control->name, sizeof(control->name), "AMDGPU SMU %d", i); @@ -2970,6 +2946,69 @@ static ssize_t smu_v13_0_0_get_ecc_info(struct smu_context *smu, return ret; } +static bool smu_v13_0_0_wbrf_support_check(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + + switch (adev->ip_versions[MP1_HWIP][0]) { + case IP_VERSION(13, 0, 0): + return smu->smc_fw_version >= 0x004e6300; + case IP_VERSION(13, 0, 10): + return smu->smc_fw_version >= 0x00503300; + default: + return false; + } +} + +static int smu_v13_0_0_set_power_limit(struct smu_context *smu, + enum smu_ppt_limit_type limit_type, + uint32_t limit) +{ + PPTable_t *pptable = smu->smu_table.driver_pptable; + SkuTable_t *skutable = &pptable->SkuTable; + uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC]; + struct smu_table_context *table_context = &smu->smu_table; + OverDriveTableExternal_t *od_table = + (OverDriveTableExternal_t *)table_context->overdrive_table; + int ret = 0; + + if (limit_type != SMU_DEFAULT_PPT_LIMIT) + return -EINVAL; + + if (limit <= msg_limit) { + if (smu->current_power_limit > msg_limit) { + od_table->OverDriveTable.Ppt = 0; + od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_PPT_BIT; + + ret = smu_v13_0_0_upload_overdrive_table(smu, od_table); + if (ret) { + dev_err(smu->adev->dev, "Failed to upload overdrive table!\n"); + return ret; + } + } + return smu_v13_0_set_power_limit(smu, limit_type, limit); + } else if (smu->od_enabled) { + ret = smu_v13_0_set_power_limit(smu, limit_type, msg_limit); + if (ret) + return ret; + + od_table->OverDriveTable.Ppt = (limit * 100) / msg_limit - 100; + od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_PPT_BIT; + + ret = smu_v13_0_0_upload_overdrive_table(smu, od_table); + if (ret) { + dev_err(smu->adev->dev, "Failed to upload overdrive table!\n"); + return ret; + } + + smu->current_power_limit = limit; + } else { + return -EINVAL; + } + + return 0; +} + static const struct pptable_funcs smu_v13_0_0_ppt_funcs = { .get_allowed_feature_mask = smu_v13_0_0_get_allowed_feature_mask, .set_default_dpm_table = smu_v13_0_0_set_default_dpm_table, @@ -3024,7 +3063,7 @@ static const struct pptable_funcs smu_v13_0_0_ppt_funcs = { .set_fan_control_mode = smu_v13_0_set_fan_control_mode, .enable_mgpu_fan_boost = smu_v13_0_0_enable_mgpu_fan_boost, .get_power_limit = smu_v13_0_0_get_power_limit, - .set_power_limit = smu_v13_0_set_power_limit, + .set_power_limit = smu_v13_0_0_set_power_limit, .set_power_source = smu_v13_0_set_power_source, .get_power_profile_mode = smu_v13_0_0_get_power_profile_mode, .set_power_profile_mode = smu_v13_0_0_set_power_profile_mode, @@ -3035,10 +3074,8 @@ static const struct pptable_funcs smu_v13_0_0_ppt_funcs = { .deep_sleep_control = smu_v13_0_deep_sleep_control, .gfx_ulv_control = smu_v13_0_gfx_ulv_control, .baco_is_support = smu_v13_0_baco_is_support, - .baco_get_state = smu_v13_0_baco_get_state, - .baco_set_state = smu_v13_0_baco_set_state, - .baco_enter = smu_v13_0_0_baco_enter, - .baco_exit = smu_v13_0_0_baco_exit, + .baco_enter = smu_v13_0_baco_enter, + .baco_exit = smu_v13_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, @@ -3050,6 +3087,9 @@ static const struct pptable_funcs smu_v13_0_0_ppt_funcs = { .gpo_control = smu_v13_0_gpo_control, .get_ecc_info = smu_v13_0_0_get_ecc_info, .notify_display_change = smu_v13_0_notify_display_change, + .is_asic_wbrf_supported = smu_v13_0_0_wbrf_support_check, + .enable_uclk_shadow = smu_v13_0_enable_uclk_shadow, + .set_wbrf_exclusion_ranges = smu_v13_0_set_wbrf_exclusion_ranges, }; void smu_v13_0_0_set_ppt_funcs(struct smu_context *smu) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c index b64e07b759374c..7e1941cf17964c 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c @@ -120,6 +120,7 @@ struct mca_ras_info { #define P2S_TABLE_ID_A 0x50325341 #define P2S_TABLE_ID_X 0x50325358 +// clang-format off static const struct cmn2asic_msg_mapping smu_v13_0_6_message_map[SMU_MSG_MAX_COUNT] = { MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 0), MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion, 1), @@ -128,6 +129,7 @@ static const struct cmn2asic_msg_mapping smu_v13_0_6_message_map[SMU_MSG_MAX_COU MSG_MAP(DisableAllSmuFeatures, PPSMC_MSG_DisableAllSmuFeatures, 0), MSG_MAP(RequestI2cTransaction, PPSMC_MSG_RequestI2cTransaction, 0), MSG_MAP(GetMetricsTable, PPSMC_MSG_GetMetricsTable, 1), + MSG_MAP(GetMetricsVersion, PPSMC_MSG_GetMetricsVersion, 1), MSG_MAP(GetEnabledSmuFeaturesHigh, PPSMC_MSG_GetEnabledSmuFeaturesHigh, 1), MSG_MAP(GetEnabledSmuFeaturesLow, PPSMC_MSG_GetEnabledSmuFeaturesLow, 1), MSG_MAP(SetDriverDramAddrHigh, PPSMC_MSG_SetDriverDramAddrHigh, 1), @@ -158,8 +160,8 @@ static const struct cmn2asic_msg_mapping smu_v13_0_6_message_map[SMU_MSG_MAX_COU MSG_MAP(GfxDriverResetRecovery, PPSMC_MSG_GfxDriverResetRecovery, 0), MSG_MAP(GetMinGfxclkFrequency, PPSMC_MSG_GetMinGfxDpmFreq, 1), MSG_MAP(GetMaxGfxclkFrequency, PPSMC_MSG_GetMaxGfxDpmFreq, 1), - MSG_MAP(SetSoftMinGfxclk, PPSMC_MSG_SetSoftMinGfxClk, 0), - MSG_MAP(SetSoftMaxGfxClk, PPSMC_MSG_SetSoftMaxGfxClk, 0), + MSG_MAP(SetSoftMinGfxclk, PPSMC_MSG_SetSoftMinGfxClk, 1), + MSG_MAP(SetSoftMaxGfxClk, PPSMC_MSG_SetSoftMaxGfxClk, 1), MSG_MAP(PrepareMp1ForUnload, PPSMC_MSG_PrepareForDriverUnload, 0), MSG_MAP(GetCTFLimit, PPSMC_MSG_GetCTFLimit, 0), MSG_MAP(GetThermalLimit, PPSMC_MSG_ReadThrottlerLimit, 0), @@ -171,6 +173,7 @@ static const struct cmn2asic_msg_mapping smu_v13_0_6_message_map[SMU_MSG_MAX_COU MSG_MAP(SelectPLPDMode, PPSMC_MSG_SelectPLPDMode, 0), }; +// clang-format on static const struct cmn2asic_mapping smu_v13_0_6_clk_map[SMU_CLK_COUNT] = { CLK_MAP(SOCCLK, PPCLK_SOCCLK), CLK_MAP(FCLK, PPCLK_FCLK), @@ -432,6 +435,41 @@ static int smu_v13_0_6_get_metrics_table(struct smu_context *smu, return 0; } +static ssize_t smu_v13_0_6_get_pm_metrics(struct smu_context *smu, + void *metrics, size_t max_size) +{ + struct smu_table_context *smu_tbl_ctxt = &smu->smu_table; + uint32_t table_version = smu_tbl_ctxt->tables[SMU_TABLE_SMU_METRICS].version; + uint32_t table_size = smu_tbl_ctxt->tables[SMU_TABLE_SMU_METRICS].size; + struct amdgpu_pm_metrics *pm_metrics = metrics; + uint32_t pmfw_version; + int ret; + + if (!pm_metrics || !max_size) + return -EINVAL; + + if (max_size < (table_size + sizeof(pm_metrics->common_header))) + return -EOVERFLOW; + + /* Don't use cached metrics data */ + ret = smu_v13_0_6_get_metrics_table(smu, pm_metrics->data, true); + if (ret) + return ret; + + smu_cmn_get_smc_version(smu, NULL, &pmfw_version); + + memset(&pm_metrics->common_header, 0, + sizeof(pm_metrics->common_header)); + pm_metrics->common_header.mp1_ip_discovery_version = + IP_VERSION(13, 0, 6); + pm_metrics->common_header.pmfw_version = pmfw_version; + pm_metrics->common_header.pmmetrics_version = table_version; + pm_metrics->common_header.structure_size = + sizeof(pm_metrics->common_header) + table_size; + + return pm_metrics->common_header.structure_size; +} + static int smu_v13_0_6_setup_driver_pptable(struct smu_context *smu) { struct smu_table_context *smu_table = &smu->smu_table; @@ -441,6 +479,7 @@ static int smu_v13_0_6_setup_driver_pptable(struct smu_context *smu) (struct PPTable_t *)smu_table->driver_pptable; struct amdgpu_device *adev = smu->adev; int ret, i, retry = 100; + uint32_t table_version; /* Store one-time values in driver PPTable */ if (!pptable->Init) { @@ -459,6 +498,13 @@ static int smu_v13_0_6_setup_driver_pptable(struct smu_context *smu) if (!retry) return -ETIME; + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetMetricsVersion, + &table_version); + if (ret) + return ret; + smu_table->tables[SMU_TABLE_SMU_METRICS].version = + table_version; + pptable->MaxSocketPowerLimit = SMUQ10_ROUND(GET_METRIC_FIELD(MaxSocketPowerLimit)); pptable->MaxGfxclkFrequency = @@ -924,7 +970,9 @@ static int smu_v13_0_6_print_clks(struct smu_context *smu, char *buf, int size, if (i < (clocks.num_levels - 1)) clk2 = clocks.data[i + 1].clocks_in_khz / 1000; - if (curr_clk >= clk1 && curr_clk < clk2) { + if (curr_clk == clk1) { + level = i; + } else if (curr_clk >= clk1 && curr_clk < clk2) { level = (curr_clk - clk1) <= (clk2 - curr_clk) ? i : i + 1; @@ -1477,7 +1525,6 @@ static int smu_v13_0_6_mca_set_debug_mode(struct smu_context *smu, bool enable) if (smu->smc_fw_version < 0x554800) return 0; - amdgpu_ras_set_mca_debug_mode(smu->adev, enable); return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ClearMcaOnRead, enable ? 0 : ClearMcaOnRead_UE_FLAG_MASK | ClearMcaOnRead_CE_POLL_MASK, NULL); @@ -1891,7 +1938,6 @@ static int smu_v13_0_6_i2c_control_init(struct smu_context *smu) smu_i2c->port = i; mutex_init(&smu_i2c->mutex); control->owner = THIS_MODULE; - control->class = I2C_CLASS_SPD; control->dev.parent = &adev->pdev->dev; control->algo = &smu_v13_0_6_i2c_algo; snprintf(control->name, sizeof(control->name), "AMDGPU SMU %d", i); @@ -2190,17 +2236,18 @@ static int smu_v13_0_6_mode2_reset(struct smu_context *smu) continue; } - if (ret) { - dev_err(adev->dev, - "failed to send mode2 message \tparam: 0x%08x error code %d\n", - SMU_RESET_MODE_2, ret); + if (ret) goto out; - } + } while (ret == -ETIME && timeout); out: mutex_unlock(&smu->message_lock); + if (ret) + dev_err(adev->dev, "failed to send mode2 reset, error code %d", + ret); + return ret; } @@ -2329,16 +2376,6 @@ static int smu_v13_0_6_smu_send_hbm_bad_page_num(struct smu_context *smu, return ret; } -static int smu_v13_0_6_post_init(struct smu_context *smu) -{ - struct amdgpu_device *adev = smu->adev; - - if (!amdgpu_sriov_vf(adev) && adev->ras_enabled) - return smu_v13_0_6_mca_set_debug_mode(smu, false); - - return 0; -} - static int mca_smu_set_debug_mode(struct amdgpu_device *adev, bool enable) { struct smu_context *smu = adev->powerplay.pp_handle; @@ -2421,8 +2458,8 @@ static const struct mca_bank_ipid smu_v13_0_6_mca_ipid_table[AMDGPU_MCA_IP_COUNT static void mca_bank_entry_info_decode(struct mca_bank_entry *entry, struct mca_bank_info *info) { - uint64_t ipid = entry->regs[MCA_REG_IDX_IPID]; - uint32_t insthi; + u64 ipid = entry->regs[MCA_REG_IDX_IPID]; + u32 instidhi, instid; /* NOTE: All MCA IPID register share the same format, * so the driver can share the MCMP1 register header file. @@ -2431,9 +2468,15 @@ static void mca_bank_entry_info_decode(struct mca_bank_entry *entry, struct mca_ info->hwid = REG_GET_FIELD(ipid, MCMP1_IPIDT0, HardwareID); info->mcatype = REG_GET_FIELD(ipid, MCMP1_IPIDT0, McaType); - insthi = REG_GET_FIELD(ipid, MCMP1_IPIDT0, InstanceIdHi); - info->aid = ((insthi >> 2) & 0x03); - info->socket_id = insthi & 0x03; + /* + * Unfied DieID Format: SAASS. A:AID, S:Socket. + * Unfied DieID[4] = InstanceId[0] + * Unfied DieID[0:3] = InstanceIdHi[0:3] + */ + instidhi = REG_GET_FIELD(ipid, MCMP1_IPIDT0, InstanceIdHi); + instid = REG_GET_FIELD(ipid, MCMP1_IPIDT0, InstanceIdLo); + info->aid = ((instidhi >> 2) & 0x03); + info->socket_id = ((instid & 0x1) << 2) | (instidhi & 0x03); } static int mca_bank_read_reg(struct amdgpu_device *adev, enum amdgpu_mca_error_type type, @@ -2512,9 +2555,9 @@ static int mca_umc_mca_get_err_count(const struct mca_ras_info *mca_ras, struct return 0; } - if (type == AMDGPU_MCA_ERROR_TYPE_UE && umc_v12_0_is_uncorrectable_error(status0)) + if (type == AMDGPU_MCA_ERROR_TYPE_UE && umc_v12_0_is_uncorrectable_error(adev, status0)) *count = 1; - else if (type == AMDGPU_MCA_ERROR_TYPE_CE && umc_v12_0_is_correctable_error(status0)) + else if (type == AMDGPU_MCA_ERROR_TYPE_CE && umc_v12_0_is_correctable_error(adev, status0)) *count = 1; return 0; @@ -2525,13 +2568,15 @@ static int mca_pcs_xgmi_mca_get_err_count(const struct mca_ras_info *mca_ras, st uint32_t *count) { u32 ext_error_code; + u32 err_cnt; ext_error_code = MCA_REG__STATUS__ERRORCODEEXT(entry->regs[MCA_REG_IDX_STATUS]); + err_cnt = MCA_REG__MISC0__ERRCNT(entry->regs[MCA_REG_IDX_MISC0]); if (type == AMDGPU_MCA_ERROR_TYPE_UE && ext_error_code == 0) - *count = 1; + *count = err_cnt; else if (type == AMDGPU_MCA_ERROR_TYPE_CE && ext_error_code == 6) - *count = 1; + *count = err_cnt; return 0; } @@ -2607,6 +2652,7 @@ static bool mca_gfx_smu_bank_is_valid(const struct mca_ras_info *mca_ras, struct uint32_t instlo; instlo = REG_GET_FIELD(entry->regs[MCA_REG_IDX_IPID], MCMP1_IPIDT0, InstanceIdLo); + instlo &= GENMASK(31, 1); switch (instlo) { case 0x36430400: /* SMNAID XCD 0 */ case 0x38430400: /* SMNAID XCD 1 */ @@ -2626,6 +2672,7 @@ static bool mca_smu_bank_is_valid(const struct mca_ras_info *mca_ras, struct amd uint32_t errcode, instlo; instlo = REG_GET_FIELD(entry->regs[MCA_REG_IDX_IPID], MCMP1_IPIDT0, InstanceIdLo); + instlo &= GENMASK(31, 1); if (instlo != 0x03b30400) return false; @@ -2848,6 +2895,13 @@ static int smu_v13_0_6_select_xgmi_plpd_policy(struct smu_context *smu, return ret; } +static ssize_t smu_v13_0_6_get_ecc_info(struct smu_context *smu, + void *table) +{ + /* Support ecc info by default */ + return 0; +} + static const struct pptable_funcs smu_v13_0_6_ppt_funcs = { /* init dpm */ .get_allowed_feature_mask = smu_v13_0_6_get_allowed_feature_mask, @@ -2892,6 +2946,7 @@ static const struct pptable_funcs smu_v13_0_6_ppt_funcs = { .log_thermal_throttling_event = smu_v13_0_6_log_thermal_throttling_event, .get_pp_feature_mask = smu_cmn_get_pp_feature_mask, .get_gpu_metrics = smu_v13_0_6_get_gpu_metrics, + .get_pm_metrics = smu_v13_0_6_get_pm_metrics, .get_thermal_temperature_range = smu_v13_0_6_get_thermal_temperature_range, .mode1_reset_is_support = smu_v13_0_6_is_mode1_reset_supported, .mode2_reset_is_support = smu_v13_0_6_is_mode2_reset_supported, @@ -2901,7 +2956,7 @@ static const struct pptable_funcs smu_v13_0_6_ppt_funcs = { .i2c_init = smu_v13_0_6_i2c_control_init, .i2c_fini = smu_v13_0_6_i2c_control_fini, .send_hbm_bad_pages_num = smu_v13_0_6_smu_send_hbm_bad_page_num, - .post_init = smu_v13_0_6_post_init, + .get_ecc_info = smu_v13_0_6_get_ecc_info, }; void smu_v13_0_6_set_ppt_funcs(struct smu_context *smu) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c index 81eafed76045e9..7c3e162e2d818f 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c @@ -140,6 +140,7 @@ static struct cmn2asic_msg_mapping smu_v13_0_7_message_map[SMU_MSG_MAX_COUNT] = MSG_MAP(AllowGpo, PPSMC_MSG_SetGpoAllow, 0), MSG_MAP(GetPptLimit, PPSMC_MSG_GetPptLimit, 0), MSG_MAP(NotifyPowerSource, PPSMC_MSG_NotifyPowerSource, 0), + MSG_MAP(EnableUCLKShadow, PPSMC_MSG_EnableUCLKShadow, 0), }; static struct cmn2asic_mapping smu_v13_0_7_clk_map[SMU_CLK_COUNT] = { @@ -222,6 +223,7 @@ static struct cmn2asic_mapping smu_v13_0_7_table_map[SMU_TABLE_COUNT] = { TAB_MAP(ACTIVITY_MONITOR_COEFF), [SMU_TABLE_COMBO_PPTABLE] = {1, TABLE_COMBO_PPTABLE}, TAB_MAP(OVERDRIVE), + TAB_MAP(WIFIBAND), }; static struct cmn2asic_mapping smu_v13_0_7_pwr_src_map[SMU_POWER_SOURCE_COUNT] = { @@ -512,6 +514,9 @@ static int smu_v13_0_7_tables_init(struct smu_context *smu) AMDGPU_GEM_DOMAIN_VRAM); SMU_TABLE_INIT(tables, SMU_TABLE_COMBO_PPTABLE, MP0_MP1_DATA_REGION_SIZE_COMBOPPTABLE, PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); + SMU_TABLE_INIT(tables, SMU_TABLE_WIFIBAND, + sizeof(WifiBandEntryTable_t), PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM); smu_table->metrics_table = kzalloc(sizeof(SmuMetricsExternal_t), GFP_KERNEL); if (!smu_table->metrics_table) @@ -2316,6 +2321,7 @@ static int smu_v13_0_7_get_power_limit(struct smu_context *smu, PPTable_t *pptable = table_context->driver_pptable; SkuTable_t *skutable = &pptable->SkuTable; uint32_t power_limit, od_percent_upper, od_percent_lower; + uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC]; if (smu_v13_0_get_current_power_limit(smu, &power_limit)) power_limit = smu->adev->pm.ac_power ? @@ -2339,7 +2345,7 @@ static int smu_v13_0_7_get_power_limit(struct smu_context *smu, od_percent_upper, od_percent_lower, power_limit); if (max_power_limit) { - *max_power_limit = power_limit * (100 + od_percent_upper); + *max_power_limit = msg_limit * (100 + od_percent_upper); *max_power_limit /= 100; } @@ -2515,38 +2521,6 @@ static int smu_v13_0_7_set_mp1_state(struct smu_context *smu, return ret; } -static int smu_v13_0_7_baco_enter(struct smu_context *smu) -{ - struct smu_baco_context *smu_baco = &smu->smu_baco; - struct amdgpu_device *adev = smu->adev; - - if (adev->in_runpm && smu_cmn_is_audio_func_enabled(adev)) - return smu_v13_0_baco_set_armd3_sequence(smu, - (smu_baco->maco_support && amdgpu_runtime_pm != 1) ? - BACO_SEQ_BAMACO : BACO_SEQ_BACO); - else - return smu_v13_0_baco_enter(smu); -} - -static int smu_v13_0_7_baco_exit(struct smu_context *smu) -{ - struct amdgpu_device *adev = smu->adev; - int ret; - - if (adev->in_runpm && smu_cmn_is_audio_func_enabled(adev)) { - /* Wait for PMFW handling for the Dstate change */ - usleep_range(10000, 11000); - ret = smu_v13_0_baco_set_armd3_sequence(smu, BACO_SEQ_ULPS); - } else { - ret = smu_v13_0_baco_exit(smu); - } - - if (!ret) - adev->gfx.is_poweron = false; - - return ret; -} - static bool smu_v13_0_7_is_mode1_reset_supported(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; @@ -2567,6 +2541,60 @@ static int smu_v13_0_7_set_df_cstate(struct smu_context *smu, NULL); } +static bool smu_v13_0_7_wbrf_support_check(struct smu_context *smu) +{ + return smu->smc_fw_version > 0x00524600; +} + +static int smu_v13_0_7_set_power_limit(struct smu_context *smu, + enum smu_ppt_limit_type limit_type, + uint32_t limit) +{ + PPTable_t *pptable = smu->smu_table.driver_pptable; + SkuTable_t *skutable = &pptable->SkuTable; + uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC]; + struct smu_table_context *table_context = &smu->smu_table; + OverDriveTableExternal_t *od_table = + (OverDriveTableExternal_t *)table_context->overdrive_table; + int ret = 0; + + if (limit_type != SMU_DEFAULT_PPT_LIMIT) + return -EINVAL; + + if (limit <= msg_limit) { + if (smu->current_power_limit > msg_limit) { + od_table->OverDriveTable.Ppt = 0; + od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_PPT_BIT; + + ret = smu_v13_0_7_upload_overdrive_table(smu, od_table); + if (ret) { + dev_err(smu->adev->dev, "Failed to upload overdrive table!\n"); + return ret; + } + } + return smu_v13_0_set_power_limit(smu, limit_type, limit); + } else if (smu->od_enabled) { + ret = smu_v13_0_set_power_limit(smu, limit_type, msg_limit); + if (ret) + return ret; + + od_table->OverDriveTable.Ppt = (limit * 100) / msg_limit - 100; + od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_PPT_BIT; + + ret = smu_v13_0_7_upload_overdrive_table(smu, od_table); + if (ret) { + dev_err(smu->adev->dev, "Failed to upload overdrive table!\n"); + return ret; + } + + smu->current_power_limit = limit; + } else { + return -EINVAL; + } + + return 0; +} + static const struct pptable_funcs smu_v13_0_7_ppt_funcs = { .get_allowed_feature_mask = smu_v13_0_7_get_allowed_feature_mask, .set_default_dpm_table = smu_v13_0_7_set_default_dpm_table, @@ -2618,7 +2646,7 @@ static const struct pptable_funcs smu_v13_0_7_ppt_funcs = { .set_fan_control_mode = smu_v13_0_set_fan_control_mode, .enable_mgpu_fan_boost = smu_v13_0_7_enable_mgpu_fan_boost, .get_power_limit = smu_v13_0_7_get_power_limit, - .set_power_limit = smu_v13_0_set_power_limit, + .set_power_limit = smu_v13_0_7_set_power_limit, .set_power_source = smu_v13_0_set_power_source, .get_power_profile_mode = smu_v13_0_7_get_power_profile_mode, .set_power_profile_mode = smu_v13_0_7_set_power_profile_mode, @@ -2626,15 +2654,16 @@ static const struct pptable_funcs smu_v13_0_7_ppt_funcs = { .get_pp_feature_mask = smu_cmn_get_pp_feature_mask, .set_pp_feature_mask = smu_cmn_set_pp_feature_mask, .baco_is_support = smu_v13_0_baco_is_support, - .baco_get_state = smu_v13_0_baco_get_state, - .baco_set_state = smu_v13_0_baco_set_state, - .baco_enter = smu_v13_0_7_baco_enter, - .baco_exit = smu_v13_0_7_baco_exit, + .baco_enter = smu_v13_0_baco_enter, + .baco_exit = smu_v13_0_baco_exit, .mode1_reset_is_support = smu_v13_0_7_is_mode1_reset_supported, .mode1_reset = smu_v13_0_mode1_reset, .set_mp1_state = smu_v13_0_7_set_mp1_state, .set_df_cstate = smu_v13_0_7_set_df_cstate, .gpo_control = smu_v13_0_gpo_control, + .is_asic_wbrf_supported = smu_v13_0_7_wbrf_support_check, + .enable_uclk_shadow = smu_v13_0_enable_uclk_shadow, + .set_wbrf_exclusion_ranges = smu_v13_0_set_wbrf_exclusion_ranges, }; void smu_v13_0_7_set_ppt_funcs(struct smu_context *smu) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c index d8f8ad0e713751..4894f7ee737b41 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c @@ -224,7 +224,7 @@ int smu_v14_0_check_fw_version(struct smu_context *smu) if (smu->is_apu) adev->pm.fw_version = smu_version; - switch (adev->ip_versions[MP1_HWIP][0]) { + switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) { case IP_VERSION(14, 0, 2): smu->smc_driver_if_version = SMU14_DRIVER_IF_VERSION_SMU_V14_0_2; break; @@ -235,7 +235,7 @@ int smu_v14_0_check_fw_version(struct smu_context *smu) break; default: dev_err(adev->dev, "smu unsupported IP version: 0x%x.\n", - adev->ip_versions[MP1_HWIP][0]); + amdgpu_ip_version(adev, MP1_HWIP, 0)); smu->smc_driver_if_version = SMU14_DRIVER_IF_VERSION_INV; break; } @@ -733,7 +733,7 @@ int smu_v14_0_gfx_off_control(struct smu_context *smu, bool enable) int ret = 0; struct amdgpu_device *adev = smu->adev; - switch (adev->ip_versions[MP1_HWIP][0]) { + switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) { case IP_VERSION(14, 0, 2): case IP_VERSION(14, 0, 0): if (!(adev->pm.pp_feature & PP_GFXOFF_MASK)) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c index 94ccdbfd709092..47fdbae4adfc02 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_0_ppt.c @@ -1085,6 +1085,25 @@ static int smu_v14_0_0_set_umsch_mm_enable(struct smu_context *smu, 0, NULL); } +static int smu_14_0_0_get_dpm_table(struct smu_context *smu, struct dpm_clocks *clock_table) +{ + DpmClocks_t *clk_table = smu->smu_table.clocks_table; + uint8_t idx; + + /* Only the Clock information of SOC and VPE is copied to provide VPE DPM settings for use. */ + for (idx = 0; idx < NUM_SOCCLK_DPM_LEVELS; idx++) { + clock_table->SocClocks[idx].Freq = (idx < clk_table->NumSocClkLevelsEnabled) ? clk_table->SocClocks[idx]:0; + clock_table->SocClocks[idx].Vol = 0; + } + + for (idx = 0; idx < NUM_VPE_DPM_LEVELS; idx++) { + clock_table->VPEClocks[idx].Freq = (idx < clk_table->VpeClkLevelsEnabled) ? clk_table->VPEClocks[idx]:0; + clock_table->VPEClocks[idx].Vol = 0; + } + + return 0; +} + static const struct pptable_funcs smu_v14_0_0_ppt_funcs = { .check_fw_status = smu_v14_0_check_fw_status, .check_fw_version = smu_v14_0_check_fw_version, @@ -1115,6 +1134,7 @@ static const struct pptable_funcs smu_v14_0_0_ppt_funcs = { .set_gfx_power_up_by_imu = smu_v14_0_set_gfx_power_up_by_imu, .dpm_set_vpe_enable = smu_v14_0_0_set_vpe_enable, .dpm_set_umsch_mm_enable = smu_v14_0_0_set_umsch_mm_enable, + .get_dpm_clock_table = smu_14_0_0_get_dpm_table, }; static void smu_v14_0_0_set_smu_mailbox_registers(struct smu_context *smu) diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h b/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h index 64766ac69c53bf..6f4d212607d7f5 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_internal.h @@ -98,6 +98,9 @@ #define smu_set_config_table(smu, config_table) smu_ppt_funcs(set_config_table, -EOPNOTSUPP, smu, config_table) #define smu_init_pptable_microcode(smu) smu_ppt_funcs(init_pptable_microcode, 0, smu) #define smu_notify_rlc_state(smu, en) smu_ppt_funcs(notify_rlc_state, 0, smu, en) +#define smu_is_asic_wbrf_supported(smu) smu_ppt_funcs(is_asic_wbrf_supported, false, smu) +#define smu_enable_uclk_shadow(smu, enable) smu_ppt_funcs(enable_uclk_shadow, 0, smu, enable) +#define smu_set_wbrf_exclusion_ranges(smu, freq_band_range) smu_ppt_funcs(set_wbrf_exclusion_ranges, -EOPNOTSUPP, smu, freq_band_range) #endif #endif diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c index dc01c43f61930b..d72c22dcf6855a 100644 --- a/drivers/gpu/drm/arm/malidp_crtc.c +++ b/drivers/gpu/drm/arm/malidp_crtc.c @@ -221,7 +221,7 @@ static int malidp_crtc_atomic_check_ctm(struct drm_crtc *crtc, /* * The size of the ctm is checked in - * drm_atomic_replace_property_blob_from_id. + * drm_property_replace_blob_from_id. */ ctm = (struct drm_color_ctm *)state->ctm->data; for (i = 0; i < ARRAY_SIZE(ctm->matrix); ++i) { diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 15dd667aa2e768..c78687c755a869 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -7,8 +7,9 @@ #include #include #include -#include +#include #include +#include #include #include @@ -1012,26 +1013,17 @@ armada_lcd_bind(struct device *dev, struct device *master, void *data) int irq = platform_get_irq(pdev, 0); const struct armada_variant *variant; struct device_node *port = NULL; + struct device_node *np, *parent = dev->of_node; if (irq < 0) return irq; - if (!dev->of_node) { - const struct platform_device_id *id; - id = platform_get_device_id(pdev); - if (!id) - return -ENXIO; - - variant = (const struct armada_variant *)id->driver_data; - } else { - const struct of_device_id *match; - struct device_node *np, *parent = dev->of_node; - - match = of_match_device(dev->driver->of_match_table, dev); - if (!match) - return -ENXIO; + variant = device_get_match_data(dev); + if (!variant) + return -ENXIO; + if (parent) { np = of_get_child_by_name(parent, "ports"); if (np) parent = np; @@ -1041,8 +1033,6 @@ armada_lcd_bind(struct device *dev, struct device *master, void *data) dev_err(dev, "no port node found in %pOF\n", parent); return -ENXIO; } - - variant = match->data; } return armada_drm_crtc_create(drm, dev, res, irq, variant, port); @@ -1066,10 +1056,9 @@ static int armada_lcd_probe(struct platform_device *pdev) return component_add(&pdev->dev, &armada_lcd_ops); } -static int armada_lcd_remove(struct platform_device *pdev) +static void armada_lcd_remove(struct platform_device *pdev) { component_del(&pdev->dev, &armada_lcd_ops); - return 0; } static const struct of_device_id armada_lcd_of_match[] = { @@ -1095,7 +1084,7 @@ MODULE_DEVICE_TABLE(platform, armada_lcd_platform_ids); struct platform_driver armada_lcd_platform_driver = { .probe = armada_lcd_probe, - .remove = armada_lcd_remove, + .remove_new = armada_lcd_remove, .driver = { .name = "armada-lcd", .owner = THIS_MODULE, diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c index fa1c67598706da..e51ecc4f7ef448 100644 --- a/drivers/gpu/drm/armada/armada_drv.c +++ b/drivers/gpu/drm/armada/armada_drv.c @@ -226,10 +226,9 @@ static int armada_drm_probe(struct platform_device *pdev) match); } -static int armada_drm_remove(struct platform_device *pdev) +static void armada_drm_remove(struct platform_device *pdev) { component_master_del(&pdev->dev, &armada_master_ops); - return 0; } static void armada_drm_shutdown(struct platform_device *pdev) @@ -249,7 +248,7 @@ MODULE_DEVICE_TABLE(platform, armada_drm_platform_ids); static struct platform_driver armada_drm_platform_driver = { .probe = armada_drm_probe, - .remove = armada_drm_remove, + .remove_new = armada_drm_remove, .shutdown = armada_drm_shutdown, .driver = { .name = "armada-drm", diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c index 78122b35a0cbb3..a7a6b70220eb8c 100644 --- a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c +++ b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c @@ -6,10 +6,10 @@ #include #include #include -#include -#include +#include #include #include +#include #include #include @@ -143,7 +143,6 @@ static int aspeed_gfx_load(struct drm_device *drm) struct aspeed_gfx *priv = to_aspeed_gfx(drm); struct device_node *np = pdev->dev.of_node; const struct aspeed_gfx_config *config; - const struct of_device_id *match; struct resource *res; int ret; @@ -152,10 +151,9 @@ static int aspeed_gfx_load(struct drm_device *drm) if (IS_ERR(priv->base)) return PTR_ERR(priv->base); - match = of_match_device(aspeed_gfx_match, &pdev->dev); - if (!match) + config = device_get_match_data(&pdev->dev); + if (!config) return -EINVAL; - config = match->data; priv->dac_reg = config->dac_reg; priv->int_clr_reg = config->int_clear_reg; diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c index cf5b754f044c76..90bcb1eb9cd94f 100644 --- a/drivers/gpu/drm/ast/ast_drv.c +++ b/drivers/gpu/drm/ast/ast_drv.c @@ -89,11 +89,194 @@ static const struct pci_device_id ast_pciidlist[] = { MODULE_DEVICE_TABLE(pci, ast_pciidlist); +static bool ast_is_vga_enabled(void __iomem *ioregs) +{ + u8 vgaer = __ast_read8(ioregs, AST_IO_VGAER); + + return vgaer & AST_IO_VGAER_VGA_ENABLE; +} + +static void ast_enable_vga(void __iomem *ioregs) +{ + __ast_write8(ioregs, AST_IO_VGAER, AST_IO_VGAER_VGA_ENABLE); + __ast_write8(ioregs, AST_IO_VGAMR_W, AST_IO_VGAMR_IOSEL); +} + +/* + * Run this function as part of the HW device cleanup; not + * when the DRM device gets released. + */ +static void ast_enable_mmio_release(void *data) +{ + void __iomem *ioregs = (void __force __iomem *)data; + + /* enable standard VGA decode */ + __ast_write8_i(ioregs, AST_IO_VGACRI, 0xa1, AST_IO_VGACRA1_MMIO_ENABLED); +} + +static int ast_enable_mmio(struct device *dev, void __iomem *ioregs) +{ + void *data = (void __force *)ioregs; + + __ast_write8_i(ioregs, AST_IO_VGACRI, 0xa1, + AST_IO_VGACRA1_MMIO_ENABLED | + AST_IO_VGACRA1_VGAIO_DISABLED); + + return devm_add_action_or_reset(dev, ast_enable_mmio_release, data); +} + +static void ast_open_key(void __iomem *ioregs) +{ + __ast_write8_i(ioregs, AST_IO_VGACRI, 0x80, AST_IO_VGACR80_PASSWORD); +} + +static int ast_detect_chip(struct pci_dev *pdev, + void __iomem *regs, void __iomem *ioregs, + enum ast_chip *chip_out, + enum ast_config_mode *config_mode_out) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + enum ast_config_mode config_mode = ast_use_defaults; + uint32_t scu_rev = 0xffffffff; + enum ast_chip chip; + u32 data; + u8 vgacrd0, vgacrd1; + + /* + * Find configuration mode and read SCU revision + */ + + /* Check if we have device-tree properties */ + if (np && !of_property_read_u32(np, "aspeed,scu-revision-id", &data)) { + /* We do, disable P2A access */ + config_mode = ast_use_dt; + scu_rev = data; + } else if (pdev->device == PCI_CHIP_AST2000) { // Not all families have a P2A bridge + /* + * The BMC will set SCU 0x40 D[12] to 1 if the P2 bridge + * is disabled. We force using P2A if VGA only mode bit + * is set D[7] + */ + vgacrd0 = __ast_read8_i(ioregs, AST_IO_VGACRI, 0xd0); + vgacrd1 = __ast_read8_i(ioregs, AST_IO_VGACRI, 0xd1); + if (!(vgacrd0 & 0x80) || !(vgacrd1 & 0x10)) { + + /* + * We have a P2A bridge and it is enabled. + */ + + /* Patch AST2500/AST2510 */ + if ((pdev->revision & 0xf0) == 0x40) { + if (!(vgacrd0 & AST_VRAM_INIT_STATUS_MASK)) + ast_patch_ahb_2500(regs); + } + + /* Double check that it's actually working */ + data = __ast_read32(regs, 0xf004); + if ((data != 0xffffffff) && (data != 0x00)) { + config_mode = ast_use_p2a; + + /* Read SCU7c (silicon revision register) */ + __ast_write32(regs, 0xf004, 0x1e6e0000); + __ast_write32(regs, 0xf000, 0x1); + scu_rev = __ast_read32(regs, 0x1207c); + } + } + } + + switch (config_mode) { + case ast_use_defaults: + dev_info(dev, "Using default configuration\n"); + break; + case ast_use_dt: + dev_info(dev, "Using device-tree for configuration\n"); + break; + case ast_use_p2a: + dev_info(dev, "Using P2A bridge for configuration\n"); + break; + } + + /* + * Identify chipset + */ + + if (pdev->revision >= 0x50) { + chip = AST2600; + dev_info(dev, "AST 2600 detected\n"); + } else if (pdev->revision >= 0x40) { + switch (scu_rev & 0x300) { + case 0x0100: + chip = AST2510; + dev_info(dev, "AST 2510 detected\n"); + break; + default: + chip = AST2500; + dev_info(dev, "AST 2500 detected\n"); + break; + } + } else if (pdev->revision >= 0x30) { + switch (scu_rev & 0x300) { + case 0x0100: + chip = AST1400; + dev_info(dev, "AST 1400 detected\n"); + break; + default: + chip = AST2400; + dev_info(dev, "AST 2400 detected\n"); + break; + } + } else if (pdev->revision >= 0x20) { + switch (scu_rev & 0x300) { + case 0x0000: + chip = AST1300; + dev_info(dev, "AST 1300 detected\n"); + break; + default: + chip = AST2300; + dev_info(dev, "AST 2300 detected\n"); + break; + } + } else if (pdev->revision >= 0x10) { + switch (scu_rev & 0x0300) { + case 0x0200: + chip = AST1100; + dev_info(dev, "AST 1100 detected\n"); + break; + case 0x0100: + chip = AST2200; + dev_info(dev, "AST 2200 detected\n"); + break; + case 0x0000: + chip = AST2150; + dev_info(dev, "AST 2150 detected\n"); + break; + default: + chip = AST2100; + dev_info(dev, "AST 2100 detected\n"); + break; + } + } else { + chip = AST2000; + dev_info(dev, "AST 2000 detected\n"); + } + + *chip_out = chip; + *config_mode_out = config_mode; + + return 0; +} + static int ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - struct ast_device *ast; - struct drm_device *dev; + struct device *dev = &pdev->dev; int ret; + void __iomem *regs; + void __iomem *ioregs; + enum ast_config_mode config_mode; + enum ast_chip chip; + struct drm_device *drm; + bool need_post = false; ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, &ast_driver); if (ret) @@ -103,16 +286,80 @@ static int ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (ret) return ret; - ast = ast_device_create(&ast_driver, pdev, ent->driver_data); - if (IS_ERR(ast)) - return PTR_ERR(ast); - dev = &ast->base; + regs = pcim_iomap(pdev, 1, 0); + if (!regs) + return -EIO; + + if (pdev->revision >= 0x40) { + /* + * On AST2500 and later models, MMIO is enabled by + * default. Adopt it to be compatible with ARM. + */ + resource_size_t len = pci_resource_len(pdev, 1); + + if (len < AST_IO_MM_OFFSET) + return -EIO; + if ((len - AST_IO_MM_OFFSET) < AST_IO_MM_LENGTH) + return -EIO; + ioregs = regs + AST_IO_MM_OFFSET; + } else if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) { + /* + * Map I/O registers if we have a PCI BAR for I/O. + */ + resource_size_t len = pci_resource_len(pdev, 2); + + if (len < AST_IO_MM_LENGTH) + return -EIO; + ioregs = pcim_iomap(pdev, 2, 0); + if (!ioregs) + return -EIO; + } else { + /* + * Anything else is best effort. + */ + resource_size_t len = pci_resource_len(pdev, 1); + + if (len < AST_IO_MM_OFFSET) + return -EIO; + if ((len - AST_IO_MM_OFFSET) < AST_IO_MM_LENGTH) + return -EIO; + ioregs = regs + AST_IO_MM_OFFSET; + + dev_info(dev, "Platform has no I/O space, using MMIO\n"); + } + + if (!ast_is_vga_enabled(ioregs)) { + dev_info(dev, "VGA not enabled on entry, requesting chip POST\n"); + need_post = true; + } + + /* + * If VGA isn't enabled, we need to enable now or subsequent + * access to the scratch registers will fail. + */ + if (need_post) + ast_enable_vga(ioregs); + /* Enable extended register access */ + ast_open_key(ioregs); + + ret = ast_enable_mmio(dev, ioregs); + if (ret) + return ret; + + ret = ast_detect_chip(pdev, regs, ioregs, &chip, &config_mode); + if (ret) + return ret; + + drm = ast_device_create(pdev, &ast_driver, chip, config_mode, regs, ioregs, need_post); + if (IS_ERR(drm)) + return PTR_ERR(drm); + pci_set_drvdata(pdev, drm); - ret = drm_dev_register(dev, ent->driver_data); + ret = drm_dev_register(drm, ent->driver_data); if (ret) return ret; - drm_fbdev_generic_setup(dev, 32); + drm_fbdev_generic_setup(drm, 32); return 0; } diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index 772f3b049c1694..3be5ccf1f5f4d5 100644 --- a/drivers/gpu/drm/ast/ast_drv.h +++ b/drivers/gpu/drm/ast/ast_drv.h @@ -98,6 +98,12 @@ enum ast_tx_chip { #define AST_TX_DP501_BIT BIT(AST_TX_DP501) #define AST_TX_ASTDP_BIT BIT(AST_TX_ASTDP) +enum ast_config_mode { + ast_use_p2a, + ast_use_dt, + ast_use_defaults +}; + #define AST_DRAM_512Mx16 0 #define AST_DRAM_1Gx16 1 #define AST_DRAM_512Mx32 2 @@ -192,12 +198,13 @@ to_ast_bmc_connector(struct drm_connector *connector) struct ast_device { struct drm_device base; - struct mutex ioregs_lock; /* Protects access to I/O registers in ioregs */ void __iomem *regs; void __iomem *ioregs; void __iomem *dp501_fw_buf; + enum ast_config_mode config_mode; enum ast_chip chip; + uint32_t dram_bus_width; uint32_t dram_type; uint32_t mclk; @@ -207,6 +214,8 @@ struct ast_device { unsigned long vram_size; unsigned long vram_fb_available; + struct mutex modeset_lock; /* Protects access to modeset I/O registers in ioregs */ + struct ast_plane primary_plane; struct ast_plane cursor_plane; struct drm_crtc crtc; @@ -234,11 +243,6 @@ struct ast_device { } output; bool support_wide_screen; - enum { - ast_use_p2a, - ast_use_dt, - ast_use_defaults - } config_mode; unsigned long tx_chip_types; /* bitfield of enum ast_chip_type */ u8 *dp501_fw_addr; @@ -250,9 +254,13 @@ static inline struct ast_device *to_ast_device(struct drm_device *dev) return container_of(dev, struct ast_device, base); } -struct ast_device *ast_device_create(const struct drm_driver *drv, - struct pci_dev *pdev, - unsigned long flags); +struct drm_device *ast_device_create(struct pci_dev *pdev, + const struct drm_driver *drv, + enum ast_chip chip, + enum ast_config_mode config_mode, + void __iomem *regs, + void __iomem *ioregs, + bool need_post); static inline unsigned long __ast_gen(struct ast_device *ast) { @@ -272,55 +280,94 @@ static inline bool __ast_gen_is_eq(struct ast_device *ast, unsigned long gen) #define IS_AST_GEN6(__ast) __ast_gen_is_eq(__ast, 6) #define IS_AST_GEN7(__ast) __ast_gen_is_eq(__ast, 7) +static inline u8 __ast_read8(const void __iomem *addr, u32 reg) +{ + return ioread8(addr + reg); +} + +static inline u32 __ast_read32(const void __iomem *addr, u32 reg) +{ + return ioread32(addr + reg); +} + +static inline void __ast_write8(void __iomem *addr, u32 reg, u8 val) +{ + iowrite8(val, addr + reg); +} + +static inline void __ast_write32(void __iomem *addr, u32 reg, u32 val) +{ + iowrite32(val, addr + reg); +} + +static inline u8 __ast_read8_i(void __iomem *addr, u32 reg, u8 index) +{ + __ast_write8(addr, reg, index); + return __ast_read8(addr, reg + 1); +} + +static inline u8 __ast_read8_i_masked(void __iomem *addr, u32 reg, u8 index, u8 read_mask) +{ + u8 val = __ast_read8_i(addr, reg, index); + + return val & read_mask; +} + +static inline void __ast_write8_i(void __iomem *addr, u32 reg, u8 index, u8 val) +{ + __ast_write8(addr, reg, index); + __ast_write8(addr, reg + 1, val); +} + +static inline void __ast_write8_i_masked(void __iomem *addr, u32 reg, u8 index, u8 read_mask, + u8 val) +{ + u8 tmp = __ast_read8_i_masked(addr, reg, index, read_mask); + + tmp |= val; + __ast_write8_i(addr, reg, index, tmp); +} + static inline u32 ast_read32(struct ast_device *ast, u32 reg) { - return ioread32(ast->regs + reg); + return __ast_read32(ast->regs, reg); } static inline void ast_write32(struct ast_device *ast, u32 reg, u32 val) { - iowrite32(val, ast->regs + reg); + __ast_write32(ast->regs, reg, val); } static inline u8 ast_io_read8(struct ast_device *ast, u32 reg) { - return ioread8(ast->ioregs + reg); + return __ast_read8(ast->ioregs, reg); } static inline void ast_io_write8(struct ast_device *ast, u32 reg, u8 val) { - iowrite8(val, ast->ioregs + reg); + __ast_write8(ast->ioregs, reg, val); } static inline u8 ast_get_index_reg(struct ast_device *ast, u32 base, u8 index) { - ast_io_write8(ast, base, index); - ++base; - return ast_io_read8(ast, base); + return __ast_read8_i(ast->ioregs, base, index); } static inline u8 ast_get_index_reg_mask(struct ast_device *ast, u32 base, u8 index, u8 preserve_mask) { - u8 val = ast_get_index_reg(ast, base, index); - - return val & preserve_mask; + return __ast_read8_i_masked(ast->ioregs, base, index, preserve_mask); } static inline void ast_set_index_reg(struct ast_device *ast, u32 base, u8 index, u8 val) { - ast_io_write8(ast, base, index); - ++base; - ast_io_write8(ast, base, val); + __ast_write8_i(ast->ioregs, base, index, val); } static inline void ast_set_index_reg_mask(struct ast_device *ast, u32 base, u8 index, u8 preserve_mask, u8 val) { - u8 tmp = ast_get_index_reg_mask(ast, base, index, preserve_mask); - - tmp |= val; - ast_set_index_reg(ast, base, index, tmp); + __ast_write8_i_masked(ast->ioregs, base, index, preserve_mask, val); } #define AST_VIDMEM_SIZE_8M 0x00800000 @@ -442,7 +489,7 @@ int ast_mm_init(struct ast_device *ast); void ast_post_gpu(struct drm_device *dev); u32 ast_mindwm(struct ast_device *ast, u32 r); void ast_moutdwm(struct ast_device *ast, u32 r, u32 v); -void ast_patch_ahb_2500(struct ast_device *ast); +void ast_patch_ahb_2500(void __iomem *regs); /* ast dp501 */ void ast_set_dp501_video_output(struct drm_device *dev, u8 mode); bool ast_backup_fw(struct drm_device *dev, u8 *addr, u32 size); diff --git a/drivers/gpu/drm/ast/ast_i2c.c b/drivers/gpu/drm/ast/ast_i2c.c index 0e845e7acd9b5a..e5d3f7121de420 100644 --- a/drivers/gpu/drm/ast/ast_i2c.c +++ b/drivers/gpu/drm/ast/ast_i2c.c @@ -120,7 +120,6 @@ struct ast_i2c_chan *ast_i2c_create(struct drm_device *dev) return NULL; i2c->adapter.owner = THIS_MODULE; - i2c->adapter.class = I2C_CLASS_DDC; i2c->adapter.dev.parent = dev->dev; i2c->dev = dev; i2c_set_adapdata(&i2c->adapter, i2c); diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index f4ab40e22ceaca..2f3ad5f949fcb0 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -35,180 +35,6 @@ #include "ast_drv.h" -static bool ast_is_vga_enabled(struct drm_device *dev) -{ - struct ast_device *ast = to_ast_device(dev); - u8 ch; - - ch = ast_io_read8(ast, AST_IO_VGAER); - - return !!(ch & 0x01); -} - -static void ast_enable_vga(struct drm_device *dev) -{ - struct ast_device *ast = to_ast_device(dev); - - ast_io_write8(ast, AST_IO_VGAER, 0x01); - ast_io_write8(ast, AST_IO_VGAMR_W, 0x01); -} - -/* - * Run this function as part of the HW device cleanup; not - * when the DRM device gets released. - */ -static void ast_enable_mmio_release(void *data) -{ - struct ast_device *ast = data; - - /* enable standard VGA decode */ - ast_set_index_reg(ast, AST_IO_VGACRI, 0xa1, 0x04); -} - -static int ast_enable_mmio(struct ast_device *ast) -{ - struct drm_device *dev = &ast->base; - - ast_set_index_reg(ast, AST_IO_VGACRI, 0xa1, 0x06); - - return devm_add_action_or_reset(dev->dev, ast_enable_mmio_release, ast); -} - -static void ast_open_key(struct ast_device *ast) -{ - ast_set_index_reg(ast, AST_IO_VGACRI, 0x80, 0xA8); -} - -static int ast_device_config_init(struct ast_device *ast) -{ - struct drm_device *dev = &ast->base; - struct pci_dev *pdev = to_pci_dev(dev->dev); - struct device_node *np = dev->dev->of_node; - uint32_t scu_rev = 0xffffffff; - u32 data; - u8 jregd0, jregd1; - - /* - * Find configuration mode and read SCU revision - */ - - ast->config_mode = ast_use_defaults; - - /* Check if we have device-tree properties */ - if (np && !of_property_read_u32(np, "aspeed,scu-revision-id", &data)) { - /* We do, disable P2A access */ - ast->config_mode = ast_use_dt; - scu_rev = data; - } else if (pdev->device == PCI_CHIP_AST2000) { // Not all families have a P2A bridge - /* - * The BMC will set SCU 0x40 D[12] to 1 if the P2 bridge - * is disabled. We force using P2A if VGA only mode bit - * is set D[7] - */ - jregd0 = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd0, 0xff); - jregd1 = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd1, 0xff); - if (!(jregd0 & 0x80) || !(jregd1 & 0x10)) { - - /* - * We have a P2A bridge and it is enabled. - */ - - /* Patch AST2500/AST2510 */ - if ((pdev->revision & 0xf0) == 0x40) { - if (!(jregd0 & AST_VRAM_INIT_STATUS_MASK)) - ast_patch_ahb_2500(ast); - } - - /* Double check that it's actually working */ - data = ast_read32(ast, 0xf004); - if ((data != 0xffffffff) && (data != 0x00)) { - ast->config_mode = ast_use_p2a; - - /* Read SCU7c (silicon revision register) */ - ast_write32(ast, 0xf004, 0x1e6e0000); - ast_write32(ast, 0xf000, 0x1); - scu_rev = ast_read32(ast, 0x1207c); - } - } - } - - switch (ast->config_mode) { - case ast_use_defaults: - drm_info(dev, "Using default configuration\n"); - break; - case ast_use_dt: - drm_info(dev, "Using device-tree for configuration\n"); - break; - case ast_use_p2a: - drm_info(dev, "Using P2A bridge for configuration\n"); - break; - } - - /* - * Identify chipset - */ - - if (pdev->revision >= 0x50) { - ast->chip = AST2600; - drm_info(dev, "AST 2600 detected\n"); - } else if (pdev->revision >= 0x40) { - switch (scu_rev & 0x300) { - case 0x0100: - ast->chip = AST2510; - drm_info(dev, "AST 2510 detected\n"); - break; - default: - ast->chip = AST2500; - drm_info(dev, "AST 2500 detected\n"); - } - } else if (pdev->revision >= 0x30) { - switch (scu_rev & 0x300) { - case 0x0100: - ast->chip = AST1400; - drm_info(dev, "AST 1400 detected\n"); - break; - default: - ast->chip = AST2400; - drm_info(dev, "AST 2400 detected\n"); - } - } else if (pdev->revision >= 0x20) { - switch (scu_rev & 0x300) { - case 0x0000: - ast->chip = AST1300; - drm_info(dev, "AST 1300 detected\n"); - break; - default: - ast->chip = AST2300; - drm_info(dev, "AST 2300 detected\n"); - break; - } - } else if (pdev->revision >= 0x10) { - switch (scu_rev & 0x0300) { - case 0x0200: - ast->chip = AST1100; - drm_info(dev, "AST 1100 detected\n"); - break; - case 0x0100: - ast->chip = AST2200; - drm_info(dev, "AST 2200 detected\n"); - break; - case 0x0000: - ast->chip = AST2150; - drm_info(dev, "AST 2150 detected\n"); - break; - default: - ast->chip = AST2100; - drm_info(dev, "AST 2100 detected\n"); - break; - } - } else { - ast->chip = AST2000; - drm_info(dev, "AST 2000 detected\n"); - } - - return 0; -} - static void ast_detect_widescreen(struct ast_device *ast) { u8 jreg; @@ -424,69 +250,27 @@ static int ast_get_dram_info(struct drm_device *dev) return 0; } -struct ast_device *ast_device_create(const struct drm_driver *drv, - struct pci_dev *pdev, - unsigned long flags) +struct drm_device *ast_device_create(struct pci_dev *pdev, + const struct drm_driver *drv, + enum ast_chip chip, + enum ast_config_mode config_mode, + void __iomem *regs, + void __iomem *ioregs, + bool need_post) { struct drm_device *dev; struct ast_device *ast; - bool need_post = false; - int ret = 0; + int ret; ast = devm_drm_dev_alloc(&pdev->dev, drv, struct ast_device, base); if (IS_ERR(ast)) - return ast; + return ERR_CAST(ast); dev = &ast->base; - pci_set_drvdata(pdev, dev); - - ret = drmm_mutex_init(dev, &ast->ioregs_lock); - if (ret) - return ERR_PTR(ret); - - ast->regs = pcim_iomap(pdev, 1, 0); - if (!ast->regs) - return ERR_PTR(-EIO); - - /* - * After AST2500, MMIO is enabled by default, and it should be adopted - * to be compatible with Arm. - */ - if (pdev->revision >= 0x40) { - ast->ioregs = ast->regs + AST_IO_MM_OFFSET; - } else if (!(pci_resource_flags(pdev, 2) & IORESOURCE_IO)) { - drm_info(dev, "platform has no IO space, trying MMIO\n"); - ast->ioregs = ast->regs + AST_IO_MM_OFFSET; - } - - /* "map" IO regs if the above hasn't done so already */ - if (!ast->ioregs) { - ast->ioregs = pcim_iomap(pdev, 2, 0); - if (!ast->ioregs) - return ERR_PTR(-EIO); - } - - if (!ast_is_vga_enabled(dev)) { - drm_info(dev, "VGA not enabled on entry, requesting chip POST\n"); - need_post = true; - } - - /* - * If VGA isn't enabled, we need to enable now or subsequent - * access to the scratch registers will fail. - */ - if (need_post) - ast_enable_vga(dev); - - /* Enable extended register access */ - ast_open_key(ast); - ret = ast_enable_mmio(ast); - if (ret) - return ERR_PTR(ret); - - ret = ast_device_config_init(ast); - if (ret) - return ERR_PTR(ret); + ast->chip = chip; + ast->config_mode = config_mode; + ast->regs = regs; + ast->ioregs = ioregs; ast_detect_widescreen(ast); ast_detect_tx_chip(ast, need_post); @@ -517,5 +301,5 @@ struct ast_device *ast_device_create(const struct drm_driver *drv, if (ret) return ERR_PTR(ret); - return ast; + return dev; } diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index c20534d0ef7c8a..a718646a66b8fd 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -1358,13 +1358,13 @@ static int ast_vga_connector_helper_get_modes(struct drm_connector *connector) * Protect access to I/O registers from concurrent modesetting * by acquiring the I/O-register lock. */ - mutex_lock(&ast->ioregs_lock); + mutex_lock(&ast->modeset_lock); edid = drm_get_edid(connector, &ast_vga_connector->i2c->adapter); if (!edid) goto err_mutex_unlock; - mutex_unlock(&ast->ioregs_lock); + mutex_unlock(&ast->modeset_lock); count = drm_add_edid_modes(connector, edid); kfree(edid); @@ -1372,7 +1372,7 @@ static int ast_vga_connector_helper_get_modes(struct drm_connector *connector) return count; err_mutex_unlock: - mutex_unlock(&ast->ioregs_lock); + mutex_unlock(&ast->modeset_lock); err_drm_connector_update_edid_property: drm_connector_update_edid_property(connector, NULL); return 0; @@ -1464,13 +1464,13 @@ static int ast_sil164_connector_helper_get_modes(struct drm_connector *connector * Protect access to I/O registers from concurrent modesetting * by acquiring the I/O-register lock. */ - mutex_lock(&ast->ioregs_lock); + mutex_lock(&ast->modeset_lock); edid = drm_get_edid(connector, &ast_sil164_connector->i2c->adapter); if (!edid) goto err_mutex_unlock; - mutex_unlock(&ast->ioregs_lock); + mutex_unlock(&ast->modeset_lock); count = drm_add_edid_modes(connector, edid); kfree(edid); @@ -1478,7 +1478,7 @@ static int ast_sil164_connector_helper_get_modes(struct drm_connector *connector return count; err_mutex_unlock: - mutex_unlock(&ast->ioregs_lock); + mutex_unlock(&ast->modeset_lock); err_drm_connector_update_edid_property: drm_connector_update_edid_property(connector, NULL); return 0; @@ -1670,13 +1670,13 @@ static int ast_astdp_connector_helper_get_modes(struct drm_connector *connector) * Protect access to I/O registers from concurrent modesetting * by acquiring the I/O-register lock. */ - mutex_lock(&ast->ioregs_lock); + mutex_lock(&ast->modeset_lock); succ = ast_astdp_read_edid(connector->dev, edid); if (succ < 0) goto err_mutex_unlock; - mutex_unlock(&ast->ioregs_lock); + mutex_unlock(&ast->modeset_lock); drm_connector_update_edid_property(connector, edid); count = drm_add_edid_modes(connector, edid); @@ -1685,7 +1685,7 @@ static int ast_astdp_connector_helper_get_modes(struct drm_connector *connector) return count; err_mutex_unlock: - mutex_unlock(&ast->ioregs_lock); + mutex_unlock(&ast->modeset_lock); kfree(edid); err_drm_connector_update_edid_property: drm_connector_update_edid_property(connector, NULL); @@ -1870,9 +1870,9 @@ static void ast_mode_config_helper_atomic_commit_tail(struct drm_atomic_state *s * display modes. Protect access to I/O registers by acquiring * the I/O-register lock. Released in atomic_flush(). */ - mutex_lock(&ast->ioregs_lock); + mutex_lock(&ast->modeset_lock); drm_atomic_helper_commit_tail_rpm(state); - mutex_unlock(&ast->ioregs_lock); + mutex_unlock(&ast->modeset_lock); } static const struct drm_mode_config_helper_funcs ast_mode_config_helper_funcs = { @@ -1910,6 +1910,10 @@ int ast_mode_config_init(struct ast_device *ast) struct drm_connector *physical_connector = NULL; int ret; + ret = drmm_mutex_init(dev, &ast->modeset_lock); + if (ret) + return ret; + ret = drmm_mode_config_init(dev); if (ret) return ret; diff --git a/drivers/gpu/drm/ast/ast_post.c b/drivers/gpu/drm/ast/ast_post.c index 7a993a38431478..22f548805dfb05 100644 --- a/drivers/gpu/drm/ast/ast_post.c +++ b/drivers/gpu/drm/ast/ast_post.c @@ -77,28 +77,42 @@ ast_set_def_ext_reg(struct drm_device *dev) ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xb6, 0xff, reg); } -u32 ast_mindwm(struct ast_device *ast, u32 r) +static u32 __ast_mindwm(void __iomem *regs, u32 r) { - uint32_t data; + u32 data; - ast_write32(ast, 0xf004, r & 0xffff0000); - ast_write32(ast, 0xf000, 0x1); + __ast_write32(regs, 0xf004, r & 0xffff0000); + __ast_write32(regs, 0xf000, 0x1); do { - data = ast_read32(ast, 0xf004) & 0xffff0000; + data = __ast_read32(regs, 0xf004) & 0xffff0000; } while (data != (r & 0xffff0000)); - return ast_read32(ast, 0x10000 + (r & 0x0000ffff)); + + return __ast_read32(regs, 0x10000 + (r & 0x0000ffff)); } -void ast_moutdwm(struct ast_device *ast, u32 r, u32 v) +static void __ast_moutdwm(void __iomem *regs, u32 r, u32 v) { - uint32_t data; - ast_write32(ast, 0xf004, r & 0xffff0000); - ast_write32(ast, 0xf000, 0x1); + u32 data; + + __ast_write32(regs, 0xf004, r & 0xffff0000); + __ast_write32(regs, 0xf000, 0x1); + do { - data = ast_read32(ast, 0xf004) & 0xffff0000; + data = __ast_read32(regs, 0xf004) & 0xffff0000; } while (data != (r & 0xffff0000)); - ast_write32(ast, 0x10000 + (r & 0x0000ffff), v); + + __ast_write32(regs, 0x10000 + (r & 0x0000ffff), v); +} + +u32 ast_mindwm(struct ast_device *ast, u32 r) +{ + return __ast_mindwm(ast->regs, r); +} + +void ast_moutdwm(struct ast_device *ast, u32 r, u32 v) +{ + __ast_moutdwm(ast->regs, r, v); } /* @@ -1987,17 +2001,18 @@ static bool ast_dram_init_2500(struct ast_device *ast) return true; } -void ast_patch_ahb_2500(struct ast_device *ast) +void ast_patch_ahb_2500(void __iomem *regs) { - u32 data; + u32 data; /* Clear bus lock condition */ - ast_moutdwm(ast, 0x1e600000, 0xAEED1A03); - ast_moutdwm(ast, 0x1e600084, 0x00010000); - ast_moutdwm(ast, 0x1e600088, 0x00000000); - ast_moutdwm(ast, 0x1e6e2000, 0x1688A8A8); - data = ast_mindwm(ast, 0x1e6e2070); - if (data & 0x08000000) { /* check fast reset */ + __ast_moutdwm(regs, 0x1e600000, 0xAEED1A03); + __ast_moutdwm(regs, 0x1e600084, 0x00010000); + __ast_moutdwm(regs, 0x1e600088, 0x00000000); + __ast_moutdwm(regs, 0x1e6e2000, 0x1688A8A8); + + data = __ast_mindwm(regs, 0x1e6e2070); + if (data & 0x08000000) { /* check fast reset */ /* * If "Fast restet" is enabled for ARM-ICE debugger, * then WDT needs to enable, that @@ -2009,16 +2024,18 @@ void ast_patch_ahb_2500(struct ast_device *ast) * [1]:= 1:WDT will be cleeared and disabled after timeout occurs * [0]:= 1:WDT enable */ - ast_moutdwm(ast, 0x1E785004, 0x00000010); - ast_moutdwm(ast, 0x1E785008, 0x00004755); - ast_moutdwm(ast, 0x1E78500c, 0x00000033); + __ast_moutdwm(regs, 0x1E785004, 0x00000010); + __ast_moutdwm(regs, 0x1E785008, 0x00004755); + __ast_moutdwm(regs, 0x1E78500c, 0x00000033); udelay(1000); } + do { - ast_moutdwm(ast, 0x1e6e2000, 0x1688A8A8); - data = ast_mindwm(ast, 0x1e6e2000); - } while (data != 1); - ast_moutdwm(ast, 0x1e6e207c, 0x08000000); /* clear fast reset */ + __ast_moutdwm(regs, 0x1e6e2000, 0x1688A8A8); + data = __ast_mindwm(regs, 0x1e6e2000); + } while (data != 1); + + __ast_moutdwm(regs, 0x1e6e207c, 0x08000000); /* clear fast reset */ } void ast_post_chip_2500(struct drm_device *dev) @@ -2030,7 +2047,7 @@ void ast_post_chip_2500(struct drm_device *dev) reg = ast_get_index_reg_mask(ast, AST_IO_VGACRI, 0xd0, 0xff); if ((reg & AST_VRAM_INIT_STATUS_MASK) == 0) {/* vga only */ /* Clear bus lock condition */ - ast_patch_ahb_2500(ast); + ast_patch_ahb_2500(ast->regs); /* Disable watchdog */ ast_moutdwm(ast, 0x1E78502C, 0x00000000); diff --git a/drivers/gpu/drm/ast/ast_reg.h b/drivers/gpu/drm/ast/ast_reg.h index 555286ecf52098..62dddbf3fe569d 100644 --- a/drivers/gpu/drm/ast/ast_reg.h +++ b/drivers/gpu/drm/ast/ast_reg.h @@ -10,10 +10,17 @@ */ #define AST_IO_MM_OFFSET (0x380) +#define AST_IO_MM_LENGTH (128) #define AST_IO_VGAARI_W (0x40) + #define AST_IO_VGAMR_W (0x42) +#define AST_IO_VGAMR_R (0x4c) +#define AST_IO_VGAMR_IOSEL BIT(0) + #define AST_IO_VGAER (0x43) +#define AST_IO_VGAER_VGA_ENABLE BIT(0) + #define AST_IO_VGASRI (0x44) #define AST_IO_VGADRR (0x47) #define AST_IO_VGADWR (0x48) @@ -21,14 +28,15 @@ #define AST_IO_VGAGRI (0x4E) #define AST_IO_VGACRI (0x54) +#define AST_IO_VGACR80_PASSWORD (0xa8) +#define AST_IO_VGACRA1_VGAIO_DISABLED BIT(1) +#define AST_IO_VGACRA1_MMIO_ENABLED BIT(2) #define AST_IO_VGACRCB_HWC_16BPP BIT(0) /* set: ARGB4444, cleared: 2bpp palette */ #define AST_IO_VGACRCB_HWC_ENABLED BIT(1) #define AST_IO_VGAIR1_R (0x5A) #define AST_IO_VGAIR1_VREFRESH BIT(3) -#define AST_IO_VGAMR_R (0x4C) - /* * Display Transmitter Type */ diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index 3e6a4e2044c0eb..efd996f6c13843 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -12,6 +12,23 @@ config DRM_PANEL_BRIDGE help DRM bridge wrapper of DRM panels +config DRM_AUX_BRIDGE + tristate + depends on DRM_BRIDGE && OF + select AUXILIARY_BUS + select DRM_PANEL_BRIDGE + help + Simple transparent bridge that is used by several non-DRM drivers to + build bridges chain. + +config DRM_AUX_HPD_BRIDGE + tristate + depends on DRM_BRIDGE && OF + select AUXILIARY_BUS + help + Simple bridge that terminates the bridge chain and provides HPD + support. + menu "Display Interface Bridges" depends on DRM && DRM_BRIDGE diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index 2b892b7ed59e80..017b5832733b2b 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -1,4 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_DRM_AUX_BRIDGE) += aux-bridge.o +obj-$(CONFIG_DRM_AUX_HPD_BRIDGE) += aux-hpd-bridge.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/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index 8f740154707dbe..29d91493b101ac 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -1298,10 +1298,32 @@ static void anx7625_config(struct anx7625_data *ctx) XTAL_FRQ_SEL, XTAL_FRQ_27M); } +static int anx7625_hpd_timer_config(struct anx7625_data *ctx) +{ + int ret; + + /* Set irq detect window to 2ms */ + ret = anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, + HPD_DET_TIMER_BIT0_7, HPD_TIME & 0xFF); + ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, + HPD_DET_TIMER_BIT8_15, + (HPD_TIME >> 8) & 0xFF); + ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, + HPD_DET_TIMER_BIT16_23, + (HPD_TIME >> 16) & 0xFF); + + return ret; +} + +static int anx7625_read_hpd_gpio_config_status(struct anx7625_data *ctx) +{ + return anx7625_reg_read(ctx, ctx->i2c.rx_p0_client, GPIO_CTRL_2); +} + static void anx7625_disable_pd_protocol(struct anx7625_data *ctx) { struct device *dev = ctx->dev; - int ret; + int ret, val; /* Reset main ocm */ ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, 0x88, 0x40); @@ -1315,6 +1337,19 @@ static void anx7625_disable_pd_protocol(struct anx7625_data *ctx) DRM_DEV_DEBUG_DRIVER(dev, "disable PD feature fail.\n"); else DRM_DEV_DEBUG_DRIVER(dev, "disable PD feature succeeded.\n"); + + /* + * Make sure the HPD GPIO already be configured after OCM release before + * setting HPD detect window register. Here we poll the status register + * at maximum 40ms, then config HPD irq detect window register + */ + readx_poll_timeout(anx7625_read_hpd_gpio_config_status, + ctx, val, + ((val & HPD_SOURCE) || (val < 0)), + 2000, 2000 * 20); + + /* Set HPD irq detect window to 2ms */ + anx7625_hpd_timer_config(ctx); } static int anx7625_ocm_loading_check(struct anx7625_data *ctx) @@ -1437,20 +1472,6 @@ static void anx7625_start_dp_work(struct anx7625_data *ctx) static int anx7625_read_hpd_status_p0(struct anx7625_data *ctx) { - int ret; - - /* Set irq detect window to 2ms */ - ret = anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, - HPD_DET_TIMER_BIT0_7, HPD_TIME & 0xFF); - ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, - HPD_DET_TIMER_BIT8_15, - (HPD_TIME >> 8) & 0xFF); - ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, - HPD_DET_TIMER_BIT16_23, - (HPD_TIME >> 16) & 0xFF); - if (ret < 0) - return ret; - return anx7625_reg_read(ctx, ctx->i2c.rx_p0_client, SYSTEM_STSTUS); } @@ -1464,9 +1485,6 @@ static int _anx7625_hpd_polling(struct anx7625_data *ctx, if (ctx->pdata.intp_irq) return 0; - /* Delay 200ms for FW HPD de-bounce */ - msleep(200); - ret = readx_poll_timeout(anx7625_read_hpd_status_p0, ctx, val, ((val & HPD_STATUS) || (val < 0)), @@ -1744,6 +1762,7 @@ static ssize_t anx7625_aux_transfer(struct drm_dp_aux *aux, u8 request = msg->request & ~DP_AUX_I2C_MOT; int ret = 0; + mutex_lock(&ctx->aux_lock); pm_runtime_get_sync(dev); msg->reply = 0; switch (request) { @@ -1760,6 +1779,7 @@ static ssize_t anx7625_aux_transfer(struct drm_dp_aux *aux, msg->size, msg->buffer); pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); + mutex_unlock(&ctx->aux_lock); return ret; } @@ -2456,7 +2476,9 @@ static void anx7625_bridge_atomic_disable(struct drm_bridge *bridge, ctx->connector = NULL; anx7625_dp_stop(ctx); - pm_runtime_put_sync(dev); + mutex_lock(&ctx->aux_lock); + pm_runtime_put_sync_suspend(dev); + mutex_unlock(&ctx->aux_lock); } static enum drm_connector_status @@ -2650,6 +2672,7 @@ static int anx7625_i2c_probe(struct i2c_client *client) mutex_init(&platform->lock); mutex_init(&platform->hdcp_wq_lock); + mutex_init(&platform->aux_lock); INIT_DELAYED_WORK(&platform->hdcp_work, hdcp_check_work_func); platform->hdcp_workqueue = create_workqueue("hdcp workqueue"); diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.h b/drivers/gpu/drm/bridge/analogix/anx7625.h index 5af819611ebce8..39ed35d3383633 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.h +++ b/drivers/gpu/drm/bridge/analogix/anx7625.h @@ -259,6 +259,10 @@ #define AP_MIPI_RX_EN BIT(5) /* 1: MIPI RX input in 0: no RX in */ #define AP_DISABLE_PD BIT(6) #define AP_DISABLE_DISPLAY BIT(7) + +#define GPIO_CTRL_2 0x49 +#define HPD_SOURCE BIT(6) + /***************************************************************/ /* Register definition of device address 0x84 */ #define MIPI_PHY_CONTROL_3 0x03 @@ -471,6 +475,8 @@ struct anx7625_data { struct workqueue_struct *hdcp_workqueue; /* Lock for hdcp work queue */ struct mutex hdcp_wq_lock; + /* Lock for aux transfer and disable */ + struct mutex aux_lock; char edid_block; struct display_timing dt; u8 display_timing_valid; diff --git a/drivers/gpu/drm/bridge/aux-bridge.c b/drivers/gpu/drm/bridge/aux-bridge.c new file mode 100644 index 00000000000000..b29980f95379ec --- /dev/null +++ b/drivers/gpu/drm/bridge/aux-bridge.c @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2023 Linaro Ltd. + * + * Author: Dmitry Baryshkov + */ +#include +#include +#include + +#include +#include + +static DEFINE_IDA(drm_aux_bridge_ida); + +static void drm_aux_bridge_release(struct device *dev) +{ + struct auxiliary_device *adev = to_auxiliary_dev(dev); + + ida_free(&drm_aux_bridge_ida, adev->id); + + kfree(adev); +} + +static void drm_aux_bridge_unregister_adev(void *_adev) +{ + struct auxiliary_device *adev = _adev; + + auxiliary_device_delete(adev); + auxiliary_device_uninit(adev); +} + +/** + * drm_aux_bridge_register - Create a simple bridge device to link the chain + * @parent: device instance providing this bridge + * + * Creates a simple DRM bridge that doesn't implement any drm_bridge + * operations. Such bridges merely fill a place in the bridge chain linking + * surrounding DRM bridges. + * + * Return: zero on success, negative error code on failure + */ +int drm_aux_bridge_register(struct device *parent) +{ + struct auxiliary_device *adev; + int ret; + + adev = kzalloc(sizeof(*adev), GFP_KERNEL); + if (!adev) + return -ENOMEM; + + ret = ida_alloc(&drm_aux_bridge_ida, GFP_KERNEL); + if (ret < 0) { + kfree(adev); + return ret; + } + + adev->id = ret; + adev->name = "aux_bridge"; + adev->dev.parent = parent; + adev->dev.of_node = of_node_get(parent->of_node); + adev->dev.release = drm_aux_bridge_release; + + ret = auxiliary_device_init(adev); + if (ret) { + ida_free(&drm_aux_bridge_ida, adev->id); + kfree(adev); + return ret; + } + + ret = auxiliary_device_add(adev); + if (ret) { + auxiliary_device_uninit(adev); + return ret; + } + + return devm_add_action_or_reset(parent, drm_aux_bridge_unregister_adev, adev); +} +EXPORT_SYMBOL_GPL(drm_aux_bridge_register); + +struct drm_aux_bridge_data { + struct drm_bridge bridge; + struct drm_bridge *next_bridge; + struct device *dev; +}; + +static int drm_aux_bridge_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) +{ + struct drm_aux_bridge_data *data; + + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) + return -EINVAL; + + data = container_of(bridge, struct drm_aux_bridge_data, bridge); + + return drm_bridge_attach(bridge->encoder, data->next_bridge, bridge, + DRM_BRIDGE_ATTACH_NO_CONNECTOR); +} + +static const struct drm_bridge_funcs drm_aux_bridge_funcs = { + .attach = drm_aux_bridge_attach, +}; + +static int drm_aux_bridge_probe(struct auxiliary_device *auxdev, + const struct auxiliary_device_id *id) +{ + struct drm_aux_bridge_data *data; + + data = devm_kzalloc(&auxdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->dev = &auxdev->dev; + data->next_bridge = devm_drm_of_get_bridge(&auxdev->dev, auxdev->dev.of_node, 0, 0); + if (IS_ERR(data->next_bridge)) + return dev_err_probe(&auxdev->dev, PTR_ERR(data->next_bridge), + "failed to acquire drm_bridge\n"); + + data->bridge.funcs = &drm_aux_bridge_funcs; + data->bridge.of_node = data->dev->of_node; + + return devm_drm_bridge_add(data->dev, &data->bridge); +} + +static const struct auxiliary_device_id drm_aux_bridge_table[] = { + { .name = KBUILD_MODNAME ".aux_bridge" }, + {}, +}; +MODULE_DEVICE_TABLE(auxiliary, drm_aux_bridge_table); + +static struct auxiliary_driver drm_aux_bridge_drv = { + .name = "aux_bridge", + .id_table = drm_aux_bridge_table, + .probe = drm_aux_bridge_probe, +}; +module_auxiliary_driver(drm_aux_bridge_drv); + +MODULE_AUTHOR("Dmitry Baryshkov "); +MODULE_DESCRIPTION("DRM transparent bridge"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/bridge/aux-hpd-bridge.c b/drivers/gpu/drm/bridge/aux-hpd-bridge.c new file mode 100644 index 00000000000000..bb55f697a18192 --- /dev/null +++ b/drivers/gpu/drm/bridge/aux-hpd-bridge.c @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2023 Linaro Ltd. + * + * Author: Dmitry Baryshkov + */ +#include +#include +#include + +#include +#include + +static DEFINE_IDA(drm_aux_hpd_bridge_ida); + +struct drm_aux_hpd_bridge_data { + struct drm_bridge bridge; + struct device *dev; +}; + +static void drm_aux_hpd_bridge_release(struct device *dev) +{ + struct auxiliary_device *adev = to_auxiliary_dev(dev); + + ida_free(&drm_aux_hpd_bridge_ida, adev->id); + + of_node_put(adev->dev.platform_data); + + kfree(adev); +} + +static void drm_aux_hpd_bridge_unregister_adev(void *_adev) +{ + struct auxiliary_device *adev = _adev; + + auxiliary_device_delete(adev); + auxiliary_device_uninit(adev); +} + +/** + * drm_dp_hpd_bridge_register - Create a simple HPD DisplayPort bridge + * @parent: device instance providing this bridge + * @np: device node pointer corresponding to this bridge instance + * + * Creates a simple DRM bridge with the type set to + * DRM_MODE_CONNECTOR_DisplayPort, which terminates the bridge chain and is + * able to send the HPD events. + * + * Return: device instance that will handle created bridge or an error code + * encoded into the pointer. + */ +struct device *drm_dp_hpd_bridge_register(struct device *parent, + struct device_node *np) +{ + struct auxiliary_device *adev; + int ret; + + adev = kzalloc(sizeof(*adev), GFP_KERNEL); + if (!adev) + return ERR_PTR(-ENOMEM); + + ret = ida_alloc(&drm_aux_hpd_bridge_ida, GFP_KERNEL); + if (ret < 0) { + kfree(adev); + return ERR_PTR(ret); + } + + adev->id = ret; + adev->name = "dp_hpd_bridge"; + adev->dev.parent = parent; + adev->dev.of_node = of_node_get(parent->of_node); + adev->dev.release = drm_aux_hpd_bridge_release; + adev->dev.platform_data = of_node_get(np); + + ret = auxiliary_device_init(adev); + if (ret) { + ida_free(&drm_aux_hpd_bridge_ida, adev->id); + kfree(adev); + return ERR_PTR(ret); + } + + ret = auxiliary_device_add(adev); + if (ret) { + auxiliary_device_uninit(adev); + return ERR_PTR(ret); + } + + ret = devm_add_action_or_reset(parent, drm_aux_hpd_bridge_unregister_adev, adev); + if (ret) + return ERR_PTR(ret); + + return &adev->dev; +} +EXPORT_SYMBOL_GPL(drm_dp_hpd_bridge_register); + +/** + * drm_aux_hpd_bridge_notify - notify hot plug detection events + * @dev: device created for the HPD bridge + * @status: output connection status + * + * A wrapper around drm_bridge_hpd_notify() that is used to report hot plug + * detection events for bridges created via drm_dp_hpd_bridge_register(). + * + * This function shall be called in a context that can sleep. + */ +void drm_aux_hpd_bridge_notify(struct device *dev, enum drm_connector_status status) +{ + struct auxiliary_device *adev = to_auxiliary_dev(dev); + struct drm_aux_hpd_bridge_data *data = auxiliary_get_drvdata(adev); + + if (!data) + return; + + drm_bridge_hpd_notify(&data->bridge, status); +} +EXPORT_SYMBOL_GPL(drm_aux_hpd_bridge_notify); + +static int drm_aux_hpd_bridge_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 drm_aux_hpd_bridge_funcs = { + .attach = drm_aux_hpd_bridge_attach, +}; + +static int drm_aux_hpd_bridge_probe(struct auxiliary_device *auxdev, + const struct auxiliary_device_id *id) +{ + struct drm_aux_hpd_bridge_data *data; + + data = devm_kzalloc(&auxdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->dev = &auxdev->dev; + data->bridge.funcs = &drm_aux_hpd_bridge_funcs; + data->bridge.of_node = dev_get_platdata(data->dev); + data->bridge.ops = DRM_BRIDGE_OP_HPD; + data->bridge.type = id->driver_data; + + auxiliary_set_drvdata(auxdev, data); + + return devm_drm_bridge_add(data->dev, &data->bridge); +} + +static const struct auxiliary_device_id drm_aux_hpd_bridge_table[] = { + { .name = KBUILD_MODNAME ".dp_hpd_bridge", .driver_data = DRM_MODE_CONNECTOR_DisplayPort, }, + {}, +}; +MODULE_DEVICE_TABLE(auxiliary, drm_aux_hpd_bridge_table); + +static struct auxiliary_driver drm_aux_hpd_bridge_drv = { + .name = "aux_hpd_bridge", + .id_table = drm_aux_hpd_bridge_table, + .probe = drm_aux_hpd_bridge_probe, +}; +module_auxiliary_driver(drm_aux_hpd_bridge_drv); + +MODULE_AUTHOR("Dmitry Baryshkov "); +MODULE_DESCRIPTION("DRM HPD bridge"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c index 6af565ac307ae3..7d470527455b10 100644 --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c @@ -2596,11 +2596,10 @@ clk_disable: return ret; } -static int cdns_mhdp_remove(struct platform_device *pdev) +static void cdns_mhdp_remove(struct platform_device *pdev) { struct cdns_mhdp_device *mhdp = platform_get_drvdata(pdev); unsigned long timeout = msecs_to_jiffies(100); - bool stop_fw = false; int ret; drm_bridge_remove(&mhdp->bridge); @@ -2608,18 +2607,19 @@ static int cdns_mhdp_remove(struct platform_device *pdev) ret = wait_event_timeout(mhdp->fw_load_wq, mhdp->hw_state == MHDP_HW_READY, timeout); - if (ret == 0) - dev_err(mhdp->dev, "%s: Timeout waiting for fw loading\n", - __func__); - else - stop_fw = true; - spin_lock(&mhdp->start_lock); mhdp->hw_state = MHDP_HW_STOPPED; spin_unlock(&mhdp->start_lock); - if (stop_fw) + if (ret == 0) { + dev_err(mhdp->dev, "%s: Timeout waiting for fw loading\n", + __func__); + } else { ret = cdns_mhdp_set_firmware_active(mhdp, false); + if (ret) + dev_err(mhdp->dev, "Failed to stop firmware (%pe)\n", + ERR_PTR(ret)); + } phy_exit(mhdp->phy); @@ -2634,8 +2634,6 @@ static int cdns_mhdp_remove(struct platform_device *pdev) /* Ignoring mhdp->hdcp.check_work and mhdp->hdcp.prop_work here. */ clk_disable_unprepare(mhdp->clk); - - return ret; } static const struct of_device_id mhdp_ids[] = { @@ -2658,7 +2656,7 @@ static struct platform_driver mhdp_driver = { .of_match_table = mhdp_ids, }, .probe = cdns_mhdp_probe, - .remove = cdns_mhdp_remove, + .remove_new = cdns_mhdp_remove, }; module_platform_driver(mhdp_driver); diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c index 946212a9559814..5e3b8edcf79487 100644 --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-hdcp.c @@ -403,7 +403,8 @@ static int _cdns_mhdp_hdcp_disable(struct cdns_mhdp_device *mhdp) static int _cdns_mhdp_hdcp_enable(struct cdns_mhdp_device *mhdp, u8 content_type) { - int ret, tries = 3; + int ret = -EINVAL; + int tries = 3; u32 i; for (i = 0; i < tries; i++) { diff --git a/drivers/gpu/drm/bridge/imx/imx93-mipi-dsi.c b/drivers/gpu/drm/bridge/imx/imx93-mipi-dsi.c index 3ff30ce80c5b88..2347f8dd632f9e 100644 --- a/drivers/gpu/drm/bridge/imx/imx93-mipi-dsi.c +++ b/drivers/gpu/drm/bridge/imx/imx93-mipi-dsi.c @@ -226,8 +226,8 @@ dphy_pll_get_configure_from_opts(struct imx93_dsi *dsi, unsigned long fout; unsigned long best_fout = 0; unsigned int fvco_div; - unsigned int min_n, max_n, n, best_n; - unsigned long m, best_m; + unsigned int min_n, max_n, n, best_n = UINT_MAX; + unsigned long m, best_m = 0; unsigned long min_delta = ULONG_MAX; unsigned long delta; u64 tmp; diff --git a/drivers/gpu/drm/bridge/lontium-lt8912b.c b/drivers/gpu/drm/bridge/lontium-lt8912b.c index 03532efb893bbc..273157428c8270 100644 --- a/drivers/gpu/drm/bridge/lontium-lt8912b.c +++ b/drivers/gpu/drm/bridge/lontium-lt8912b.c @@ -43,6 +43,8 @@ struct lt8912 { struct videomode mode; + struct regulator_bulk_data supplies[7]; + u8 data_lanes; bool is_power_on; }; @@ -257,6 +259,12 @@ static int lt8912_free_i2c(struct lt8912 *lt) static int lt8912_hard_power_on(struct lt8912 *lt) { + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(lt->supplies), lt->supplies); + if (ret) + return ret; + gpiod_set_value_cansleep(lt->gp_reset, 0); msleep(20); @@ -267,6 +275,9 @@ static void lt8912_hard_power_off(struct lt8912 *lt) { gpiod_set_value_cansleep(lt->gp_reset, 1); msleep(20); + + regulator_bulk_disable(ARRAY_SIZE(lt->supplies), lt->supplies); + lt->is_power_on = false; } @@ -634,6 +645,48 @@ static const struct drm_bridge_funcs lt8912_bridge_funcs = { .get_edid = lt8912_bridge_get_edid, }; +static int lt8912_bridge_resume(struct device *dev) +{ + struct lt8912 *lt = dev_get_drvdata(dev); + int ret; + + ret = lt8912_hard_power_on(lt); + if (ret) + return ret; + + ret = lt8912_soft_power_on(lt); + if (ret) + return ret; + + return lt8912_video_on(lt); +} + +static int lt8912_bridge_suspend(struct device *dev) +{ + struct lt8912 *lt = dev_get_drvdata(dev); + + lt8912_hard_power_off(lt); + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(lt8912_bridge_pm_ops, lt8912_bridge_suspend, lt8912_bridge_resume); + +static int lt8912_get_regulators(struct lt8912 *lt) +{ + unsigned int i; + const char * const supply_names[] = { + "vdd", "vccmipirx", "vccsysclk", "vcclvdstx", + "vcchdmitx", "vcclvdspll", "vcchdmipll" + }; + + for (i = 0; i < ARRAY_SIZE(lt->supplies); i++) + lt->supplies[i].supply = supply_names[i]; + + return devm_regulator_bulk_get(lt->dev, ARRAY_SIZE(lt->supplies), + lt->supplies); +} + static int lt8912_parse_dt(struct lt8912 *lt) { struct gpio_desc *gp_reset; @@ -685,6 +738,10 @@ static int lt8912_parse_dt(struct lt8912 *lt) goto err_free_host_node; } + ret = lt8912_get_regulators(lt); + if (ret) + goto err_free_host_node; + of_node_put(port_node); return 0; @@ -770,6 +827,7 @@ static struct i2c_driver lt8912_i2c_driver = { .driver = { .name = "lt8912", .of_match_table = lt8912_dt_match, + .pm = pm_sleep_ptr(<8912_bridge_pm_ops), }, .probe = lt8912_probe, .remove = lt8912_remove, diff --git a/drivers/gpu/drm/bridge/nxp-ptn3460.c b/drivers/gpu/drm/bridge/nxp-ptn3460.c index d81920227a8aeb..7c0076e499533a 100644 --- a/drivers/gpu/drm/bridge/nxp-ptn3460.c +++ b/drivers/gpu/drm/bridge/nxp-ptn3460.c @@ -54,13 +54,13 @@ static int ptn3460_read_bytes(struct ptn3460_bridge *ptn_bridge, char addr, int ret; ret = i2c_master_send(ptn_bridge->client, &addr, 1); - if (ret <= 0) { + if (ret < 0) { DRM_ERROR("Failed to send i2c command, ret=%d\n", ret); return ret; } ret = i2c_master_recv(ptn_bridge->client, buf, len); - if (ret <= 0) { + if (ret < 0) { DRM_ERROR("Failed to recv i2c data, ret=%d\n", ret); return ret; } @@ -78,7 +78,7 @@ static int ptn3460_write_byte(struct ptn3460_bridge *ptn_bridge, char addr, buf[1] = val; ret = i2c_master_send(ptn_bridge->client, buf, ARRAY_SIZE(buf)); - if (ret <= 0) { + if (ret < 0) { DRM_ERROR("Failed to send i2c command, ret=%d\n", ret); return ret; } diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c index 541e4f5afc4c86..14d4dcf239da83 100644 --- a/drivers/gpu/drm/bridge/parade-ps8640.c +++ b/drivers/gpu/drm/bridge/parade-ps8640.c @@ -107,6 +107,7 @@ struct ps8640 { struct device_link *link; bool pre_enabled; bool need_post_hpd_delay; + struct mutex aux_lock; }; static const struct regmap_config ps8640_regmap_config[] = { @@ -345,11 +346,20 @@ static ssize_t ps8640_aux_transfer(struct drm_dp_aux *aux, struct device *dev = &ps_bridge->page[PAGE0_DP_CNTL]->dev; int ret; + mutex_lock(&ps_bridge->aux_lock); pm_runtime_get_sync(dev); + ret = _ps8640_wait_hpd_asserted(ps_bridge, 200 * 1000); + if (ret) { + pm_runtime_put_sync_suspend(dev); + goto exit; + } ret = ps8640_aux_transfer_msg(aux, msg); pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); +exit: + mutex_unlock(&ps_bridge->aux_lock); + return ret; } @@ -470,7 +480,18 @@ static void ps8640_atomic_post_disable(struct drm_bridge *bridge, ps_bridge->pre_enabled = false; ps8640_bridge_vdo_control(ps_bridge, DISABLE); + + /* + * The bridge seems to expect everything to be power cycled at the + * disable process, so grab a lock here to make sure + * ps8640_aux_transfer() is not holding a runtime PM reference and + * preventing the bridge from suspend. + */ + mutex_lock(&ps_bridge->aux_lock); + pm_runtime_put_sync_suspend(&ps_bridge->page[PAGE0_DP_CNTL]->dev); + + mutex_unlock(&ps_bridge->aux_lock); } static int ps8640_bridge_attach(struct drm_bridge *bridge, @@ -619,6 +640,8 @@ static int ps8640_probe(struct i2c_client *client) if (!ps_bridge) return -ENOMEM; + mutex_init(&ps_bridge->aux_lock); + ps_bridge->supplies[0].supply = "vdd12"; ps_bridge->supplies[1].supply = "vdd33"; ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ps_bridge->supplies), diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c index be5914caa17d54..63a1a0c88be4d9 100644 --- a/drivers/gpu/drm/bridge/samsung-dsim.c +++ b/drivers/gpu/drm/bridge/samsung-dsim.c @@ -969,10 +969,6 @@ static int samsung_dsim_init_link(struct samsung_dsim *dsi) reg = samsung_dsim_read(dsi, DSIM_ESCMODE_REG); reg &= ~DSIM_STOP_STATE_CNT_MASK; reg |= DSIM_STOP_STATE_CNT(driver_data->reg_values[STOP_STATE_CNT]); - - if (!samsung_dsim_hw_is_exynos(dsi->plat_data->hw_type)) - reg |= DSIM_FORCE_STOP_STATE; - samsung_dsim_write(dsi, DSIM_ESCMODE_REG, reg); reg = DSIM_BTA_TIMEOUT(0xff) | DSIM_LPDR_TIMEOUT(0xffff); @@ -1431,18 +1427,6 @@ static void samsung_dsim_disable_irq(struct samsung_dsim *dsi) disable_irq(dsi->irq); } -static void samsung_dsim_set_stop_state(struct samsung_dsim *dsi, bool enable) -{ - u32 reg = samsung_dsim_read(dsi, DSIM_ESCMODE_REG); - - if (enable) - reg |= DSIM_FORCE_STOP_STATE; - else - reg &= ~DSIM_FORCE_STOP_STATE; - - samsung_dsim_write(dsi, DSIM_ESCMODE_REG, reg); -} - static int samsung_dsim_init(struct samsung_dsim *dsi) { const struct samsung_dsim_driver_data *driver_data = dsi->driver_data; @@ -1492,9 +1476,6 @@ static void samsung_dsim_atomic_pre_enable(struct drm_bridge *bridge, ret = samsung_dsim_init(dsi); if (ret) return; - - samsung_dsim_set_display_mode(dsi); - samsung_dsim_set_display_enable(dsi, true); } } @@ -1503,12 +1484,8 @@ static void samsung_dsim_atomic_enable(struct drm_bridge *bridge, { struct samsung_dsim *dsi = bridge_to_dsi(bridge); - if (samsung_dsim_hw_is_exynos(dsi->plat_data->hw_type)) { - samsung_dsim_set_display_mode(dsi); - samsung_dsim_set_display_enable(dsi, true); - } else { - samsung_dsim_set_stop_state(dsi, false); - } + samsung_dsim_set_display_mode(dsi); + samsung_dsim_set_display_enable(dsi, true); dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE; } @@ -1521,9 +1498,6 @@ static void samsung_dsim_atomic_disable(struct drm_bridge *bridge, if (!(dsi->state & DSIM_STATE_ENABLED)) return; - if (!samsung_dsim_hw_is_exynos(dsi->plat_data->hw_type)) - samsung_dsim_set_stop_state(dsi, true); - dsi->state &= ~DSIM_STATE_VIDOUT_AVAILABLE; } @@ -1828,8 +1802,6 @@ static ssize_t samsung_dsim_host_transfer(struct mipi_dsi_host *host, if (ret) return ret; - samsung_dsim_set_stop_state(dsi, false); - ret = mipi_dsi_create_packet(&xfer.packet, msg); if (ret < 0) return ret; diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c index 2bdc5b439bebd5..4560ae9cbce150 100644 --- a/drivers/gpu/drm/bridge/sii902x.c +++ b/drivers/gpu/drm/bridge/sii902x.c @@ -1080,6 +1080,26 @@ static int sii902x_init(struct sii902x *sii902x) return ret; } + ret = sii902x_audio_codec_init(sii902x, dev); + if (ret) + return ret; + + i2c_set_clientdata(sii902x->i2c, sii902x); + + sii902x->i2cmux = i2c_mux_alloc(sii902x->i2c->adapter, dev, + 1, 0, I2C_MUX_GATE, + sii902x_i2c_bypass_select, + sii902x_i2c_bypass_deselect); + if (!sii902x->i2cmux) { + ret = -ENOMEM; + goto err_unreg_audio; + } + + sii902x->i2cmux->priv = sii902x; + ret = i2c_mux_add_adapter(sii902x->i2cmux, 0, 0, 0); + if (ret) + goto err_unreg_audio; + sii902x->bridge.funcs = &sii902x_bridge_funcs; sii902x->bridge.of_node = dev->of_node; sii902x->bridge.timings = &default_sii902x_timings; @@ -1090,19 +1110,13 @@ static int sii902x_init(struct sii902x *sii902x) drm_bridge_add(&sii902x->bridge); - sii902x_audio_codec_init(sii902x, dev); - - i2c_set_clientdata(sii902x->i2c, sii902x); + return 0; - sii902x->i2cmux = i2c_mux_alloc(sii902x->i2c->adapter, dev, - 1, 0, I2C_MUX_GATE, - sii902x_i2c_bypass_select, - sii902x_i2c_bypass_deselect); - if (!sii902x->i2cmux) - return -ENOMEM; +err_unreg_audio: + if (!PTR_ERR_OR_ZERO(sii902x->audio.pdev)) + platform_device_unregister(sii902x->audio.pdev); - sii902x->i2cmux->priv = sii902x; - return i2c_mux_add_adapter(sii902x->i2cmux, 0, 0, 0); + return ret; } static int sii902x_probe(struct i2c_client *client) @@ -1170,12 +1184,14 @@ static int sii902x_probe(struct i2c_client *client) } static void sii902x_remove(struct i2c_client *client) - { struct sii902x *sii902x = i2c_get_clientdata(client); - i2c_mux_del_adapters(sii902x->i2cmux); drm_bridge_remove(&sii902x->bridge); + i2c_mux_del_adapters(sii902x->i2cmux); + + if (!PTR_ERR_OR_ZERO(sii902x->audio.pdev)) + platform_device_unregister(sii902x->audio.pdev); } static const struct of_device_id sii902x_dt_ids[] = { diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index 52d91a0df85e9b..aca5bb0866f886 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -515,7 +515,6 @@ static struct i2c_adapter *dw_hdmi_i2c_adapter(struct dw_hdmi *hdmi) init_completion(&i2c->cmp); adap = &i2c->adap; - adap->class = I2C_CLASS_DDC; adap->owner = THIS_MODULE; adap->dev.parent = hdmi->dev; adap->algo = &dw_hdmi_algorithm; diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index ef2e373606ba32..615cc8f950d7b3 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -2273,7 +2273,7 @@ static int tc_probe(struct i2c_client *client) } else { if (tc->hpd_pin < 0 || tc->hpd_pin > 1) { dev_err(dev, "failed to parse HPD number\n"); - return ret; + return -EINVAL; } } diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c index b5464199b6334e..62cc3893dca5d3 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c @@ -1415,11 +1415,9 @@ static int ti_sn_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, int ret; if (!pdata->pwm_enabled) { - ret = pm_runtime_get_sync(pdata->dev); - if (ret < 0) { - pm_runtime_put_sync(pdata->dev); + ret = pm_runtime_resume_and_get(chip->dev); + if (ret < 0) return ret; - } } if (state->enabled) { @@ -1433,7 +1431,7 @@ static int ti_sn_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, SN_GPIO_MUX_MASK << (2 * SN_PWM_GPIO_IDX), SN_GPIO_MUX_SPECIAL << (2 * SN_PWM_GPIO_IDX)); if (ret) { - dev_err(pdata->dev, "failed to mux in PWM function\n"); + dev_err(chip->dev, "failed to mux in PWM function\n"); goto out; } } @@ -1509,7 +1507,7 @@ static int ti_sn_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, ret = regmap_write(pdata->regmap, SN_PWM_PRE_DIV_REG, pre_div); if (ret) { - dev_err(pdata->dev, "failed to update PWM_PRE_DIV\n"); + dev_err(chip->dev, "failed to update PWM_PRE_DIV\n"); goto out; } @@ -1521,7 +1519,7 @@ static int ti_sn_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, FIELD_PREP(SN_PWM_INV_MASK, state->polarity == PWM_POLARITY_INVERSED); ret = regmap_write(pdata->regmap, SN_PWM_EN_INV_REG, pwm_en_inv); if (ret) { - dev_err(pdata->dev, "failed to update PWM_EN/PWM_INV\n"); + dev_err(chip->dev, "failed to update PWM_EN/PWM_INV\n"); goto out; } @@ -1529,7 +1527,7 @@ static int ti_sn_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, out: if (!pdata->pwm_enabled) - pm_runtime_put_sync(pdata->dev); + pm_runtime_put_sync(chip->dev); return ret; } @@ -1589,12 +1587,14 @@ static int ti_sn_pwm_probe(struct auxiliary_device *adev, { struct ti_sn65dsi86 *pdata = dev_get_drvdata(adev->dev.parent); - pdata->pchip.dev = pdata->dev; + pdata->pchip.dev = &adev->dev; pdata->pchip.ops = &ti_sn_pwm_ops; pdata->pchip.npwm = 1; pdata->pchip.of_xlate = of_pwm_single_xlate; pdata->pchip.of_pwm_n_cells = 1; + devm_pm_runtime_enable(&adev->dev); + return pwmchip_add(&pdata->pchip); } @@ -1605,7 +1605,7 @@ static void ti_sn_pwm_remove(struct auxiliary_device *adev) pwmchip_remove(&pdata->pchip); if (pdata->pwm_enabled) - pm_runtime_put_sync(pdata->dev); + pm_runtime_put_sync(&adev->dev); } static const struct auxiliary_device_id ti_sn_pwm_id_table[] = { diff --git a/drivers/gpu/drm/bridge/ti-tpd12s015.c b/drivers/gpu/drm/bridge/ti-tpd12s015.c index e0e015243a602d..f9fb35683a2739 100644 --- a/drivers/gpu/drm/bridge/ti-tpd12s015.c +++ b/drivers/gpu/drm/bridge/ti-tpd12s015.c @@ -179,13 +179,11 @@ static int tpd12s015_probe(struct platform_device *pdev) return 0; } -static int __exit tpd12s015_remove(struct platform_device *pdev) +static void tpd12s015_remove(struct platform_device *pdev) { struct tpd12s015_device *tpd = platform_get_drvdata(pdev); drm_bridge_remove(&tpd->bridge); - - return 0; } static const struct of_device_id tpd12s015_of_match[] = { @@ -197,7 +195,7 @@ MODULE_DEVICE_TABLE(of, tpd12s015_of_match); static struct platform_driver tpd12s015_driver = { .probe = tpd12s015_probe, - .remove = __exit_p(tpd12s015_remove), + .remove_new = tpd12s015_remove, .driver = { .name = "tpd12s015", .of_match_table = tpd12s015_of_match, diff --git a/drivers/gpu/drm/ci/arm64.config b/drivers/gpu/drm/ci/arm64.config index b4f6534178838b..8dbce9919a57ec 100644 --- a/drivers/gpu/drm/ci/arm64.config +++ b/drivers/gpu/drm/ci/arm64.config @@ -186,6 +186,7 @@ CONFIG_HW_RANDOM_MTK=y CONFIG_MTK_DEVAPC=y CONFIG_PWM_MTK_DISP=y CONFIG_MTK_CMDQ=y +CONFIG_REGULATOR_DA9211=y # For nouveau. Note that DRM must be a module so that it's loaded after NFS is up to provide the firmware. CONFIG_ARCH_TEGRA=y diff --git a/drivers/gpu/drm/ci/build.sh b/drivers/gpu/drm/ci/build.sh index e5c5dcedd1084f..f73f3471e94e82 100644 --- a/drivers/gpu/drm/ci/build.sh +++ b/drivers/gpu/drm/ci/build.sh @@ -19,7 +19,7 @@ if [[ "$KERNEL_ARCH" = "arm64" ]]; then DEVICE_TREES+=" arch/arm64/boot/dts/amlogic/meson-gxl-s805x-libretech-ac.dtb" DEVICE_TREES+=" arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dtb" DEVICE_TREES+=" arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dtb" - DEVICE_TREES+=" arch/arm64/boot/dts/qcom/apq8016-sbc.dtb" + DEVICE_TREES+=" arch/arm64/boot/dts/qcom/apq8016-sbc-usb-host.dtb" DEVICE_TREES+=" arch/arm64/boot/dts/qcom/apq8096-db820c.dtb" DEVICE_TREES+=" arch/arm64/boot/dts/amlogic/meson-g12b-a311d-khadas-vim3.dtb" DEVICE_TREES+=" arch/arm64/boot/dts/mediatek/mt8173-elm-hana.dtb" @@ -58,6 +58,9 @@ git config --global user.email "fdo@example.com" git config --global user.name "freedesktop.org CI" git config --global pull.rebase true +# cleanup git state on the worker +rm -rf .git/rebase-merge + # Try to merge fixes from target repo if [ "$(git ls-remote --exit-code --heads ${UPSTREAM_REPO} ${TARGET_BRANCH}-external-fixes)" ]; then git pull ${UPSTREAM_REPO} ${TARGET_BRANCH}-external-fixes @@ -75,19 +78,19 @@ else fi fi -for opt in $ENABLE_KCONFIGS; do - echo CONFIG_$opt=y >> drivers/gpu/drm/ci/${KERNEL_ARCH}.config -done -for opt in $DISABLE_KCONFIGS; do - echo CONFIG_$opt=n >> drivers/gpu/drm/ci/${KERNEL_ARCH}.config -done - if [[ -n "${MERGE_FRAGMENT}" ]]; then ./scripts/kconfig/merge_config.sh ${DEFCONFIG} drivers/gpu/drm/ci/${MERGE_FRAGMENT} else make `basename ${DEFCONFIG}` fi +for opt in $ENABLE_KCONFIGS; do + ./scripts/config --enable CONFIG_$opt +done +for opt in $DISABLE_KCONFIGS; do + ./scripts/config --disable CONFIG_$opt +done + make ${KERNEL_IMAGE_NAME} mkdir -p /lava-files/ diff --git a/drivers/gpu/drm/ci/gitlab-ci.yml b/drivers/gpu/drm/ci/gitlab-ci.yml index aeb9bab1b06912..dac92cc2777cc3 100644 --- a/drivers/gpu/drm/ci/gitlab-ci.yml +++ b/drivers/gpu/drm/ci/gitlab-ci.yml @@ -5,7 +5,7 @@ variables: UPSTREAM_REPO: git://anongit.freedesktop.org/drm/drm TARGET_BRANCH: drm-next - IGT_VERSION: d1db7333d9c5fbbb05e50b0804123950d9dc1c46 + IGT_VERSION: d2af13d9f5be5ce23d996e4afd3e45990f5ab977 DEQP_RUNNER_GIT_URL: https://gitlab.freedesktop.org/anholt/deqp-runner.git DEQP_RUNNER_GIT_TAG: v0.15.0 diff --git a/drivers/gpu/drm/ci/igt_runner.sh b/drivers/gpu/drm/ci/igt_runner.sh index 2f815ee3a8a369..f1a08b9b146ff2 100755 --- a/drivers/gpu/drm/ci/igt_runner.sh +++ b/drivers/gpu/drm/ci/igt_runner.sh @@ -15,15 +15,21 @@ cat /sys/kernel/debug/device_component/* ' # Dump drm state to confirm that kernel was able to find a connected display: -# TODO this path might not exist for all drivers.. maybe run modetest instead? set +e cat /sys/kernel/debug/dri/*/state set -e case "$DRIVER_NAME" in - rockchip|mediatek|meson) + rockchip|meson) export IGT_FORCE_DRIVER="panfrost" ;; + mediatek) + if [ "$GPU_VERSION" = "mt8173" ]; then + export IGT_FORCE_DRIVER=${DRIVER_NAME} + elif [ "$GPU_VERSION" = "mt8183" ]; then + export IGT_FORCE_DRIVER="panfrost" + fi + ;; amdgpu) # Cannot use HWCI_KERNEL_MODULES as at that point we don't have the module in /lib mv /install/modules/lib/modules/* /lib/modules/. diff --git a/drivers/gpu/drm/ci/test.yml b/drivers/gpu/drm/ci/test.yml index f285ed67eb3d8f..2c9a1838e7284c 100644 --- a/drivers/gpu/drm/ci/test.yml +++ b/drivers/gpu/drm/ci/test.yml @@ -102,15 +102,12 @@ msm:apq8016: stage: msm variables: DRIVER_NAME: msm - BM_DTB: https://${PIPELINE_ARTIFACTS_BASE}/arm64/apq8016-sbc.dtb + BM_DTB: https://${PIPELINE_ARTIFACTS_BASE}/arm64/apq8016-sbc-usb-host.dtb GPU_VERSION: apq8016 BM_CMDLINE: "ip=dhcp console=ttyMSM0,115200n8 $BM_KERNEL_EXTRA_ARGS root=/dev/nfs rw nfsrootdebug nfsroot=,tcp,nfsvers=4.2 init=/init $BM_KERNELARGS" RUNNER_TAG: google-freedreno-db410c script: - ./install/bare-metal/fastboot.sh - rules: - # TODO: current issue: it is not fiding the NFS root. Fix and remove this rule. - - when: never msm:apq8096: extends: @@ -280,9 +277,6 @@ mediatek:mt8173: DEVICE_TYPE: mt8173-elm-hana GPU_VERSION: mt8173 RUNNER_TAG: mesa-ci-x86-64-lava-mt8173-elm-hana - rules: - # TODO: current issue: device is hanging. Fix and remove this rule. - - when: never mediatek:mt8183: extends: @@ -335,11 +329,10 @@ virtio_gpu:none: script: - ln -sf $CI_PROJECT_DIR/install /install - mv install/bzImage /lava-files/bzImage + - mkdir -p $CI_PROJECT_DIR/results + - ln -sf $CI_PROJECT_DIR/results /results - install/crosvm-runner.sh install/igt_runner.sh needs: - debian/x86_64_test-gl - testing:x86_64 - igt:x86_64 - rules: - # TODO: current issue: malloc(): corrupted top size. Fix and remove this rule. - - when: never \ No newline at end of file diff --git a/drivers/gpu/drm/ci/xfails/mediatek-mt8173-fails.txt b/drivers/gpu/drm/ci/xfails/mediatek-mt8173-fails.txt index 671916067dbaf5..ef0cb7c3698cfd 100644 --- a/drivers/gpu/drm/ci/xfails/mediatek-mt8173-fails.txt +++ b/drivers/gpu/drm/ci/xfails/mediatek-mt8173-fails.txt @@ -1,5 +1,4 @@ kms_3d,Fail -kms_addfb_basic@addfb25-bad-modifier,Fail kms_bw@linear-tiling-1-displays-1920x1080p,Fail kms_bw@linear-tiling-1-displays-2560x1440p,Fail kms_bw@linear-tiling-1-displays-3840x2160p,Fail @@ -9,13 +8,19 @@ kms_bw@linear-tiling-2-displays-3840x2160p,Fail kms_bw@linear-tiling-3-displays-1920x1080p,Fail kms_bw@linear-tiling-3-displays-2560x1440p,Fail kms_bw@linear-tiling-3-displays-3840x2160p,Fail +kms_color@invalid-gamma-lut-sizes,Fail kms_color@pipe-A-invalid-gamma-lut-sizes,Fail kms_color@pipe-B-invalid-gamma-lut-sizes,Fail -kms_force_connector_basic@force-connector-state,Fail +kms_cursor_legacy@cursor-vs-flip-atomic,Fail +kms_cursor_legacy@cursor-vs-flip-legacy,Fail +kms_flip@flip-vs-modeset-vs-hang,Fail +kms_flip@flip-vs-panning-vs-hang,Fail +kms_flip@flip-vs-suspend,Fail +kms_flip@flip-vs-suspend-interruptible,Fail kms_force_connector_basic@force-edid,Fail kms_force_connector_basic@force-load-detect,Fail kms_force_connector_basic@prune-stale-modes,Fail -kms_invalid_mode@int-max-clock,Fail +kms_hdmi_inject@inject-4k,Fail kms_plane_scaling@planes-upscale-20x20,Fail kms_plane_scaling@planes-upscale-20x20-downscale-factor-0-25,Fail kms_plane_scaling@planes-upscale-20x20-downscale-factor-0-5,Fail @@ -27,3 +32,5 @@ kms_properties@get_properties-sanity-atomic,Fail kms_properties@plane-properties-atomic,Fail kms_properties@plane-properties-legacy,Fail kms_rmfb@close-fd,Fail +kms_selftest@drm_format,Timeout +kms_selftest@drm_format_helper,Timeout diff --git a/drivers/gpu/drm/ci/xfails/msm-apq8016-fails.txt b/drivers/gpu/drm/ci/xfails/msm-apq8016-fails.txt index 9981682feab281..d39d254c935e9a 100644 --- a/drivers/gpu/drm/ci/xfails/msm-apq8016-fails.txt +++ b/drivers/gpu/drm/ci/xfails/msm-apq8016-fails.txt @@ -6,10 +6,15 @@ kms_cursor_legacy@all-pipes-single-bo,Fail kms_cursor_legacy@all-pipes-single-move,Fail kms_cursor_legacy@all-pipes-torture-bo,Fail kms_cursor_legacy@all-pipes-torture-move,Fail +kms_cursor_legacy@forked-bo,Fail +kms_cursor_legacy@forked-move,Fail kms_cursor_legacy@pipe-A-forked-bo,Fail kms_cursor_legacy@pipe-A-forked-move,Fail kms_cursor_legacy@pipe-A-single-bo,Fail kms_cursor_legacy@pipe-A-single-move,Fail kms_cursor_legacy@pipe-A-torture-bo,Fail kms_cursor_legacy@pipe-A-torture-move,Fail +kms_force_connector_basic@force-edid,Fail kms_hdmi_inject@inject-4k,Fail +kms_selftest@drm_format,Timeout +kms_selftest@drm_format_helper,Timeout diff --git a/drivers/gpu/drm/ci/xfails/virtio_gpu-none-fails.txt b/drivers/gpu/drm/ci/xfails/virtio_gpu-none-fails.txt index 9586b2339f6f69..007f21e56d89c0 100644 --- a/drivers/gpu/drm/ci/xfails/virtio_gpu-none-fails.txt +++ b/drivers/gpu/drm/ci/xfails/virtio_gpu-none-fails.txt @@ -10,6 +10,49 @@ kms_bw@linear-tiling-1-displays-3840x2160p,Fail kms_bw@linear-tiling-2-displays-1920x1080p,Fail kms_bw@linear-tiling-2-displays-2560x1440p,Fail kms_bw@linear-tiling-2-displays-3840x2160p,Fail +kms_bw@linear-tiling-3-displays-1920x1080p,Fail +kms_bw@linear-tiling-3-displays-2560x1440p,Fail +kms_bw@linear-tiling-3-displays-3840x2160p,Fail +kms_bw@linear-tiling-4-displays-1920x1080p,Fail +kms_bw@linear-tiling-4-displays-2560x1440p,Fail +kms_bw@linear-tiling-4-displays-3840x2160p,Fail +kms_bw@linear-tiling-5-displays-1920x1080p,Fail +kms_bw@linear-tiling-5-displays-2560x1440p,Fail +kms_bw@linear-tiling-5-displays-3840x2160p,Fail +kms_bw@linear-tiling-6-displays-1920x1080p,Fail +kms_bw@linear-tiling-6-displays-2560x1440p,Fail +kms_bw@linear-tiling-6-displays-3840x2160p,Fail +kms_bw@linear-tiling-7-displays-1920x1080p,Fail +kms_bw@linear-tiling-7-displays-2560x1440p,Fail +kms_bw@linear-tiling-7-displays-3840x2160p,Fail +kms_bw@linear-tiling-8-displays-1920x1080p,Fail +kms_bw@linear-tiling-8-displays-2560x1440p,Fail +kms_bw@linear-tiling-8-displays-3840x2160p,Fail +kms_flip@absolute-wf_vblank,Fail +kms_flip@absolute-wf_vblank-interruptible,Fail +kms_flip@basic-flip-vs-wf_vblank,Fail +kms_flip@blocking-absolute-wf_vblank,Fail +kms_flip@blocking-absolute-wf_vblank-interruptible,Fail +kms_flip@blocking-wf_vblank,Fail +kms_flip@busy-flip,Fail +kms_flip@dpms-vs-vblank-race,Fail +kms_flip@dpms-vs-vblank-race-interruptible,Fail +kms_flip@flip-vs-absolute-wf_vblank,Fail +kms_flip@flip-vs-absolute-wf_vblank-interruptible,Fail +kms_flip@flip-vs-blocking-wf-vblank,Fail +kms_flip@flip-vs-expired-vblank,Fail +kms_flip@flip-vs-expired-vblank-interruptible,Fail +kms_flip@flip-vs-modeset-vs-hang,Fail +kms_flip@flip-vs-panning-vs-hang,Fail +kms_flip@flip-vs-wf_vblank-interruptible,Fail +kms_flip@modeset-vs-vblank-race,Fail +kms_flip@modeset-vs-vblank-race-interruptible,Fail +kms_flip@plain-flip-fb-recreate,Fail +kms_flip@plain-flip-fb-recreate-interruptible,Fail +kms_flip@plain-flip-ts-check,Fail +kms_flip@plain-flip-ts-check-interruptible,Fail +kms_flip@wf_vblank-ts-check,Fail +kms_flip@wf_vblank-ts-check-interruptible,Fail kms_invalid_mode@int-max-clock,Fail kms_plane_scaling@downscale-with-modifier-factor-0-25,Fail kms_plane_scaling@downscale-with-rotation-factor-0-25,Fail @@ -22,6 +65,9 @@ kms_plane_scaling@upscale-with-modifier-factor-0-25,Fail kms_plane_scaling@upscale-with-pixel-format-20x20,Fail kms_plane_scaling@upscale-with-pixel-format-factor-0-25,Fail kms_plane_scaling@upscale-with-rotation-20x20,Fail +kms_selftest@drm_format,Timeout +kms_selftest@drm_format_helper,Timeout +kms_setmode@basic,Fail kms_vblank@crtc-id,Fail kms_vblank@invalid,Fail kms_vblank@pipe-A-accuracy-idle,Fail diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c index f3680f4e697084..b1ca3a1100dabb 100644 --- a/drivers/gpu/drm/display/drm_dp_helper.c +++ b/drivers/gpu/drm/display/drm_dp_helper.c @@ -2102,7 +2102,6 @@ int drm_dp_aux_register(struct drm_dp_aux *aux) if (!aux->ddc.algo) drm_dp_aux_init(aux); - aux->ddc.class = I2C_CLASS_DDC; aux->ddc.owner = THIS_MODULE; aux->ddc.dev.parent = aux->dev; @@ -2245,6 +2244,8 @@ static const struct dpcd_quirk dpcd_quirk_list[] = { { OUI(0x00, 0x00, 0x00), DEVICE_ID('C', 'H', '7', '5', '1', '1'), false, BIT(DP_DPCD_QUIRK_NO_SINK_COUNT) }, /* Synaptics DP1.4 MST hubs can support DSC without virtual DPCD */ { OUI(0x90, 0xCC, 0x24), DEVICE_ID_ANY, true, BIT(DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD) }, + /* Synaptics DP1.4 MST hubs require DSC for some modes on which it applies HBLANK expansion. */ + { OUI(0x90, 0xCC, 0x24), DEVICE_ID_ANY, true, BIT(DP_DPCD_QUIRK_HBLANK_EXPANSION_REQUIRES_DSC) }, /* Apple MacBookPro 2017 15 inch eDP Retina panel reports too low DP_MAX_LINK_RATE */ { OUI(0x00, 0x10, 0xfa), DEVICE_ID(101, 68, 21, 101, 98, 97), false, BIT(DP_DPCD_QUIRK_CAN_DO_MAX_LINK_RATE_3_24_GBPS) }, }; @@ -2326,6 +2327,33 @@ int drm_dp_read_desc(struct drm_dp_aux *aux, struct drm_dp_desc *desc, } EXPORT_SYMBOL(drm_dp_read_desc); +/** + * drm_dp_dsc_sink_bpp_incr() - Get bits per pixel increment + * @dsc_dpcd: DSC capabilities from DPCD + * + * Returns the bpp precision supported by the DP sink. + */ +u8 drm_dp_dsc_sink_bpp_incr(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE]) +{ + u8 bpp_increment_dpcd = dsc_dpcd[DP_DSC_BITS_PER_PIXEL_INC - DP_DSC_SUPPORT]; + + switch (bpp_increment_dpcd) { + case DP_DSC_BITS_PER_PIXEL_1_16: + return 16; + case DP_DSC_BITS_PER_PIXEL_1_8: + return 8; + case DP_DSC_BITS_PER_PIXEL_1_4: + return 4; + case DP_DSC_BITS_PER_PIXEL_1_2: + return 2; + case DP_DSC_BITS_PER_PIXEL_1_1: + return 1; + } + + return 0; +} +EXPORT_SYMBOL(drm_dp_dsc_sink_bpp_incr); + /** * drm_dp_dsc_sink_max_slice_count() - Get the max slice count * supported by the DSC sink. @@ -3898,3 +3926,135 @@ int drm_panel_dp_aux_backlight(struct drm_panel *panel, struct drm_dp_aux *aux) EXPORT_SYMBOL(drm_panel_dp_aux_backlight); #endif + +/* See DP Standard v2.1 2.6.4.4.1.1, 2.8.4.4, 2.8.7 */ +static int drm_dp_link_symbol_cycles(int lane_count, int pixels, int bpp_x16, + int symbol_size, bool is_mst) +{ + int cycles = DIV_ROUND_UP(pixels * bpp_x16, 16 * symbol_size * lane_count); + int align = is_mst ? 4 / lane_count : 1; + + return ALIGN(cycles, align); +} + +static int drm_dp_link_dsc_symbol_cycles(int lane_count, int pixels, int slice_count, + int bpp_x16, int symbol_size, bool is_mst) +{ + int slice_pixels = DIV_ROUND_UP(pixels, slice_count); + int slice_data_cycles = drm_dp_link_symbol_cycles(lane_count, slice_pixels, + bpp_x16, symbol_size, is_mst); + int slice_eoc_cycles = is_mst ? 4 / lane_count : 1; + + return slice_count * (slice_data_cycles + slice_eoc_cycles); +} + +/** + * drm_dp_bw_overhead - Calculate the BW overhead of a DP link stream + * @lane_count: DP link lane count + * @hactive: pixel count of the active period in one scanline of the stream + * @dsc_slice_count: DSC slice count if @flags/DRM_DP_LINK_BW_OVERHEAD_DSC is set + * @bpp_x16: bits per pixel in .4 binary fixed point + * @flags: DRM_DP_OVERHEAD_x flags + * + * Calculate the BW allocation overhead of a DP link stream, depending + * on the link's + * - @lane_count + * - SST/MST mode (@flags / %DRM_DP_OVERHEAD_MST) + * - symbol size (@flags / %DRM_DP_OVERHEAD_UHBR) + * - FEC mode (@flags / %DRM_DP_OVERHEAD_FEC) + * - SSC/REF_CLK mode (@flags / %DRM_DP_OVERHEAD_SSC_REF_CLK) + * as well as the stream's + * - @hactive timing + * - @bpp_x16 color depth + * - compression mode (@flags / %DRM_DP_OVERHEAD_DSC). + * Note that this overhead doesn't account for the 8b/10b, 128b/132b + * channel coding efficiency, for that see + * @drm_dp_link_bw_channel_coding_efficiency(). + * + * Returns the overhead as 100% + overhead% in 1ppm units. + */ +int drm_dp_bw_overhead(int lane_count, int hactive, + int dsc_slice_count, + int bpp_x16, unsigned long flags) +{ + int symbol_size = flags & DRM_DP_BW_OVERHEAD_UHBR ? 32 : 8; + bool is_mst = flags & DRM_DP_BW_OVERHEAD_MST; + u32 overhead = 1000000; + int symbol_cycles; + + /* + * DP Standard v2.1 2.6.4.1 + * SSC downspread and ref clock variation margin: + * 5300ppm + 300ppm ~ 0.6% + */ + if (flags & DRM_DP_BW_OVERHEAD_SSC_REF_CLK) + overhead += 6000; + + /* + * DP Standard v2.1 2.6.4.1.1, 3.5.1.5.4: + * FEC symbol insertions for 8b/10b channel coding: + * After each 250 data symbols on 2-4 lanes: + * 250 LL + 5 FEC_PARITY_PH + 1 CD_ADJ (256 byte FEC block) + * After each 2 x 250 data symbols on 1 lane: + * 2 * 250 LL + 11 FEC_PARITY_PH + 1 CD_ADJ (512 byte FEC block) + * After 256 (2-4 lanes) or 128 (1 lane) FEC blocks: + * 256 * 256 bytes + 1 FEC_PM + * or + * 128 * 512 bytes + 1 FEC_PM + * (256 * 6 + 1) / (256 * 250) = 2.4015625 % + */ + if (flags & DRM_DP_BW_OVERHEAD_FEC) + overhead += 24016; + + /* + * DP Standard v2.1 2.7.9, 5.9.7 + * The FEC overhead for UHBR is accounted for in its 96.71% channel + * coding efficiency. + */ + WARN_ON((flags & DRM_DP_BW_OVERHEAD_UHBR) && + (flags & DRM_DP_BW_OVERHEAD_FEC)); + + if (flags & DRM_DP_BW_OVERHEAD_DSC) + symbol_cycles = drm_dp_link_dsc_symbol_cycles(lane_count, hactive, + dsc_slice_count, + bpp_x16, symbol_size, + is_mst); + else + symbol_cycles = drm_dp_link_symbol_cycles(lane_count, hactive, + bpp_x16, symbol_size, + is_mst); + + return DIV_ROUND_UP_ULL(mul_u32_u32(symbol_cycles * symbol_size * lane_count, + overhead * 16), + hactive * bpp_x16); +} +EXPORT_SYMBOL(drm_dp_bw_overhead); + +/** + * drm_dp_bw_channel_coding_efficiency - Get a DP link's channel coding efficiency + * @is_uhbr: Whether the link has a 128b/132b channel coding + * + * Return the channel coding efficiency of the given DP link type, which is + * either 8b/10b or 128b/132b (aka UHBR). The corresponding overhead includes + * the 8b -> 10b, 128b -> 132b pixel data to link symbol conversion overhead + * and for 128b/132b any link or PHY level control symbol insertion overhead + * (LLCP, FEC, PHY sync, see DP Standard v2.1 3.5.2.18). For 8b/10b the + * corresponding FEC overhead is BW allocation specific, included in the value + * returned by drm_dp_bw_overhead(). + * + * Returns the efficiency in the 100%/coding-overhead% ratio in + * 1ppm units. + */ +int drm_dp_bw_channel_coding_efficiency(bool is_uhbr) +{ + if (is_uhbr) + return 967100; + else + /* + * Note that on 8b/10b MST the efficiency is only + * 78.75% due to the 1 out of 64 MTPH packet overhead, + * not accounted for here. + */ + return 800000; +} +EXPORT_SYMBOL(drm_dp_bw_channel_coding_efficiency); diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c index 0e0d0e76de0651..f7c6b60629c2ba 100644 --- a/drivers/gpu/drm/display/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -3578,16 +3579,26 @@ static int drm_dp_send_up_ack_reply(struct drm_dp_mst_topology_mgr *mgr, * value is in units of PBNs/(timeslots/1 MTP). This value can be used to * convert the number of PBNs required for a given stream to the number of * timeslots this stream requires in each MTP. + * + * Returns the BW / timeslot value in 20.12 fixed point format. */ -int drm_dp_get_vc_payload_bw(const struct drm_dp_mst_topology_mgr *mgr, - int link_rate, int link_lane_count) +fixed20_12 drm_dp_get_vc_payload_bw(const struct drm_dp_mst_topology_mgr *mgr, + int link_rate, int link_lane_count) { + int ch_coding_efficiency = + drm_dp_bw_channel_coding_efficiency(drm_dp_is_uhbr_rate(link_rate)); + fixed20_12 ret; + if (link_rate == 0 || link_lane_count == 0) drm_dbg_kms(mgr->dev, "invalid link rate/lane count: (%d / %d)\n", link_rate, link_lane_count); - /* See DP v2.0 2.6.4.2, VCPayload_Bandwidth_for_OneTimeSlotPer_MTP_Allocation */ - return link_rate * link_lane_count / 54000; + /* See DP v2.0 2.6.4.2, 2.7.6.3 VCPayload_Bandwidth_for_OneTimeSlotPer_MTP_Allocation */ + ret.full = DIV_ROUND_DOWN_ULL(mul_u32_u32(link_rate * link_lane_count, + ch_coding_efficiency), + (1000000ULL * 8 * 5400) >> 12); + + return ret; } EXPORT_SYMBOL(drm_dp_get_vc_payload_bw); @@ -4335,7 +4346,7 @@ int drm_dp_atomic_find_time_slots(struct drm_atomic_state *state, } } - req_slots = DIV_ROUND_UP(pbn, topology_state->pbn_div); + req_slots = DIV_ROUND_UP(dfixed_const(pbn), topology_state->pbn_div.full); drm_dbg_atomic(mgr->dev, "[CONNECTOR:%d:%s] [MST PORT:%p] TU %d -> %d\n", port->connector->base.id, port->connector->name, @@ -4718,35 +4729,36 @@ EXPORT_SYMBOL(drm_dp_check_act_status); /** * drm_dp_calc_pbn_mode() - Calculate the PBN for a mode. - * @clock: dot clock for the mode - * @bpp: bpp for the mode. - * @dsc: DSC mode. If true, bpp has units of 1/16 of a bit per pixel + * @clock: dot clock + * @bpp: bpp as .4 binary fixed point * * This uses the formula in the spec to calculate the PBN value for a mode. */ -int drm_dp_calc_pbn_mode(int clock, int bpp, bool dsc) +int drm_dp_calc_pbn_mode(int clock, int bpp) { /* - * 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 - * - * If the bpp is in units of 1/16, further divide by 16. Put this - * factor in the numerator rather than the denominator to avoid - * integer overflow + * peak_kbps = clock * bpp / 16 + * peak_kbps *= SSC overhead / 1000000 + * peak_kbps /= 8 convert to Kbytes + * peak_kBps *= (64/54) / 1000 convert to PBN */ + /* + * TODO: Use the actual link and mode parameters to calculate + * the overhead. For now it's assumed that these are + * 4 link lanes, 4096 hactive pixels, which don't add any + * significant data padding overhead and that there is no DSC + * or FEC overhead. + */ + int overhead = drm_dp_bw_overhead(4, 4096, 0, bpp, + DRM_DP_BW_OVERHEAD_MST | + DRM_DP_BW_OVERHEAD_SSC_REF_CLK); - if (dsc) - return DIV_ROUND_UP_ULL(mul_u32_u32(clock * (bpp / 16), 64 * 1006), - 8 * 54 * 1000 * 1000); - - return DIV_ROUND_UP_ULL(mul_u32_u32(clock * bpp, 64 * 1006), - 8 * 54 * 1000 * 1000); + return DIV64_U64_ROUND_UP(mul_u32_u32(clock * bpp, 64 * overhead >> 4), + 1000000ULL * 8 * 54 * 1000); } EXPORT_SYMBOL(drm_dp_calc_pbn_mode); @@ -4871,7 +4883,8 @@ void drm_dp_mst_dump_topology(struct seq_file *m, state = to_drm_dp_mst_topology_state(mgr->base.state); seq_printf(m, "\n*** Atomic state info ***\n"); seq_printf(m, "payload_mask: %x, max_payloads: %d, start_slot: %u, pbn_div: %d\n", - state->payload_mask, mgr->max_payloads, state->start_slot, state->pbn_div); + state->payload_mask, mgr->max_payloads, state->start_slot, + dfixed_trunc(state->pbn_div)); seq_printf(m, "\n| idx | port | vcpi | slots | pbn | dsc | status | sink name |\n"); for (i = 0; i < mgr->max_payloads; i++) { @@ -5136,13 +5149,67 @@ static bool drm_dp_mst_port_downstream_of_branch(struct drm_dp_mst_port *port, return false; } +static bool +drm_dp_mst_port_downstream_of_parent_locked(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port, + struct drm_dp_mst_port *parent) +{ + if (!mgr->mst_primary) + return false; + + port = drm_dp_mst_topology_get_port_validated_locked(mgr->mst_primary, + port); + if (!port) + return false; + + if (!parent) + return true; + + parent = drm_dp_mst_topology_get_port_validated_locked(mgr->mst_primary, + parent); + if (!parent) + return false; + + if (!parent->mstb) + return false; + + return drm_dp_mst_port_downstream_of_branch(port, parent->mstb); +} + +/** + * drm_dp_mst_port_downstream_of_parent - check if a port is downstream of a parent port + * @mgr: MST topology manager + * @port: the port being looked up + * @parent: the parent port + * + * The function returns %true if @port is downstream of @parent. If @parent is + * %NULL - denoting the root port - the function returns %true if @port is in + * @mgr's topology. + */ +bool +drm_dp_mst_port_downstream_of_parent(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port, + struct drm_dp_mst_port *parent) +{ + bool ret; + + mutex_lock(&mgr->lock); + ret = drm_dp_mst_port_downstream_of_parent_locked(mgr, port, parent); + mutex_unlock(&mgr->lock); + + return ret; +} +EXPORT_SYMBOL(drm_dp_mst_port_downstream_of_parent); + static int drm_dp_mst_atomic_check_port_bw_limit(struct drm_dp_mst_port *port, - struct drm_dp_mst_topology_state *state); + struct drm_dp_mst_topology_state *state, + struct drm_dp_mst_port **failing_port); static int drm_dp_mst_atomic_check_mstb_bw_limit(struct drm_dp_mst_branch *mstb, - struct drm_dp_mst_topology_state *state) + struct drm_dp_mst_topology_state *state, + struct drm_dp_mst_port **failing_port) { struct drm_dp_mst_atomic_payload *payload; struct drm_dp_mst_port *port; @@ -5171,7 +5238,7 @@ drm_dp_mst_atomic_check_mstb_bw_limit(struct drm_dp_mst_branch *mstb, drm_dbg_atomic(mstb->mgr->dev, "[MSTB:%p] Checking bandwidth limits\n", mstb); list_for_each_entry(port, &mstb->ports, next) { - ret = drm_dp_mst_atomic_check_port_bw_limit(port, state); + ret = drm_dp_mst_atomic_check_port_bw_limit(port, state, failing_port); if (ret < 0) return ret; @@ -5183,7 +5250,8 @@ drm_dp_mst_atomic_check_mstb_bw_limit(struct drm_dp_mst_branch *mstb, static int drm_dp_mst_atomic_check_port_bw_limit(struct drm_dp_mst_port *port, - struct drm_dp_mst_topology_state *state) + struct drm_dp_mst_topology_state *state, + struct drm_dp_mst_port **failing_port) { struct drm_dp_mst_atomic_payload *payload; int pbn_used = 0; @@ -5204,13 +5272,15 @@ drm_dp_mst_atomic_check_port_bw_limit(struct drm_dp_mst_port *port, drm_dbg_atomic(port->mgr->dev, "[MSTB:%p] [MST PORT:%p] no BW available for the port\n", port->parent, port); + *failing_port = port; return -EINVAL; } pbn_used = payload->pbn; } else { pbn_used = drm_dp_mst_atomic_check_mstb_bw_limit(port->mstb, - state); + state, + failing_port); if (pbn_used <= 0) return pbn_used; } @@ -5219,6 +5289,7 @@ drm_dp_mst_atomic_check_port_bw_limit(struct drm_dp_mst_port *port, drm_dbg_atomic(port->mgr->dev, "[MSTB:%p] [MST PORT:%p] required PBN of %d exceeds port limit of %d\n", port->parent, port, pbn_used, port->full_pbn); + *failing_port = port; return -ENOSPC; } @@ -5271,10 +5342,10 @@ drm_dp_mst_atomic_check_payload_alloc_limits(struct drm_dp_mst_topology_mgr *mgr } if (!payload_count) - mst_state->pbn_div = 0; + mst_state->pbn_div.full = dfixed_const(0); drm_dbg_atomic(mgr->dev, "[MST MGR:%p] mst state %p TU pbn_div=%d avail=%d used=%d\n", - mgr, mst_state, mst_state->pbn_div, avail_slots, + mgr, mst_state, dfixed_trunc(mst_state->pbn_div), avail_slots, mst_state->total_avail_slots - avail_slots); return 0; @@ -5396,20 +5467,84 @@ int drm_dp_mst_atomic_enable_dsc(struct drm_atomic_state *state, } EXPORT_SYMBOL(drm_dp_mst_atomic_enable_dsc); +/** + * drm_dp_mst_atomic_check_mgr - Check the atomic state of an MST topology manager + * @state: The global atomic state + * @mgr: Manager to check + * @mst_state: The MST atomic state for @mgr + * @failing_port: Returns the port with a BW limitation + * + * Checks the given MST manager's topology state for an atomic update to ensure + * that it's valid. This includes checking whether there's enough bandwidth to + * support the new timeslot allocations in the atomic update. + * + * Any atomic drivers supporting DP MST must make sure to call this or + * the drm_dp_mst_atomic_check() function after checking the rest of their state + * in their &drm_mode_config_funcs.atomic_check() callback. + * + * See also: + * drm_dp_mst_atomic_check() + * drm_dp_atomic_find_time_slots() + * drm_dp_atomic_release_time_slots() + * + * Returns: + * - 0 if the new state is valid + * - %-ENOSPC, if the new state is invalid, because of BW limitation + * @failing_port is set to: + * + * - The non-root port where a BW limit check failed + * with all the ports downstream of @failing_port passing + * the BW limit check. + * The returned port pointer is valid until at least + * one payload downstream of it exists. + * - %NULL if the BW limit check failed at the root port + * with all the ports downstream of the root port passing + * the BW limit check. + * + * - %-EINVAL, if the new state is invalid, because the root port has + * too many payloads. + */ +int drm_dp_mst_atomic_check_mgr(struct drm_atomic_state *state, + struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_topology_state *mst_state, + struct drm_dp_mst_port **failing_port) +{ + int ret; + + *failing_port = NULL; + + if (!mgr->mst_state) + return 0; + + mutex_lock(&mgr->lock); + ret = drm_dp_mst_atomic_check_mstb_bw_limit(mgr->mst_primary, + mst_state, + failing_port); + mutex_unlock(&mgr->lock); + + if (ret < 0) + return ret; + + return drm_dp_mst_atomic_check_payload_alloc_limits(mgr, mst_state); +} +EXPORT_SYMBOL(drm_dp_mst_atomic_check_mgr); + /** * drm_dp_mst_atomic_check - Check that the new state of an MST topology in an * atomic update is valid * @state: Pointer to the new &struct drm_dp_mst_topology_state * * Checks the given topology state for an atomic update to ensure that it's - * valid. This includes checking whether there's enough bandwidth to support - * the new timeslot allocations in the atomic update. + * valid, calling drm_dp_mst_atomic_check_mgr() for all MST manager in the + * atomic state. This includes checking whether there's enough bandwidth to + * support the new timeslot allocations in the atomic update. * * Any atomic drivers supporting DP MST must make sure to call this after * checking the rest of their state in their * &drm_mode_config_funcs.atomic_check() callback. * * See also: + * drm_dp_mst_atomic_check_mgr() * drm_dp_atomic_find_time_slots() * drm_dp_atomic_release_time_slots() * @@ -5424,21 +5559,11 @@ int drm_dp_mst_atomic_check(struct drm_atomic_state *state) int i, ret = 0; for_each_new_mst_mgr_in_state(state, mgr, mst_state, i) { - if (!mgr->mst_state) - continue; + struct drm_dp_mst_port *tmp_port; - ret = drm_dp_mst_atomic_check_payload_alloc_limits(mgr, mst_state); + ret = drm_dp_mst_atomic_check_mgr(state, mgr, mst_state, &tmp_port); if (ret) break; - - mutex_lock(&mgr->lock); - ret = drm_dp_mst_atomic_check_mstb_bw_limit(mgr->mst_primary, - mst_state); - mutex_unlock(&mgr->lock); - if (ret < 0) - break; - else - ret = 0; } return ret; @@ -5803,7 +5928,6 @@ static int drm_dp_mst_register_i2c_bus(struct drm_dp_mst_port *port) aux->ddc.algo_data = aux; aux->ddc.retries = 3; - aux->ddc.class = I2C_CLASS_DDC; aux->ddc.owner = THIS_MODULE; /* FIXME: set the kdev of the port's connector as parent */ aux->ddc.dev.parent = parent_dev; @@ -5894,6 +6018,7 @@ static bool drm_dp_mst_is_virtual_dpcd(struct drm_dp_mst_port *port) struct drm_dp_aux *drm_dp_mst_dsc_aux_for_port(struct drm_dp_mst_port *port) { struct drm_dp_mst_port *immediate_upstream_port; + struct drm_dp_aux *immediate_upstream_aux; struct drm_dp_mst_port *fec_port; struct drm_dp_desc desc = {}; u8 endpoint_fec; @@ -5958,21 +6083,25 @@ struct drm_dp_aux *drm_dp_mst_dsc_aux_for_port(struct drm_dp_mst_port *port) * - Port is on primary branch device * - Not a VGA adapter (DP_DWN_STRM_PORT_TYPE_ANALOG) */ - if (drm_dp_read_desc(port->mgr->aux, &desc, true)) + if (immediate_upstream_port) + immediate_upstream_aux = &immediate_upstream_port->aux; + else + immediate_upstream_aux = port->mgr->aux; + + if (drm_dp_read_desc(immediate_upstream_aux, &desc, true)) return NULL; - if (drm_dp_has_quirk(&desc, DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD) && - port->mgr->dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14 && - port->parent == port->mgr->mst_primary) { + if (drm_dp_has_quirk(&desc, DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD)) { u8 dpcd_ext[DP_RECEIVER_CAP_SIZE]; - if (drm_dp_read_dpcd_caps(port->mgr->aux, dpcd_ext) < 0) + if (drm_dp_read_dpcd_caps(immediate_upstream_aux, dpcd_ext) < 0) return NULL; - if ((dpcd_ext[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT) && + if (dpcd_ext[DP_DPCD_REV] >= DP_DPCD_REV_14 && + ((dpcd_ext[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT) && ((dpcd_ext[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_TYPE_MASK) - != DP_DWN_STRM_PORT_TYPE_ANALOG)) - return port->mgr->aux; + != DP_DWN_STRM_PORT_TYPE_ANALOG))) + return immediate_upstream_aux; } /* diff --git a/drivers/gpu/drm/drm_agpsupport.c b/drivers/gpu/drm/drm_agpsupport.c deleted file mode 100644 index a4ad6fd13abcf6..00000000000000 --- a/drivers/gpu/drm/drm_agpsupport.c +++ /dev/null @@ -1,451 +0,0 @@ -/* - * \file drm_agpsupport.c - * DRM support for AGP/GART backend - * - * \author Rickard E. (Rik) Faith - * \author Gareth Hughes - */ - -/* - * 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. - */ - -#include -#include -#include - -#if IS_ENABLED(CONFIG_AGP) -#include -#endif - -#include -#include -#include -#include - -#include "drm_legacy.h" - -#if IS_ENABLED(CONFIG_AGP) - -/* - * Get AGP information. - * - * \return zero on success or a negative number on failure. - * - * Verifies the AGP device has been initialized and acquired and fills in the - * drm_agp_info structure with the information in drm_agp_head::agp_info. - */ -int drm_legacy_agp_info(struct drm_device *dev, struct drm_agp_info *info) -{ - struct agp_kern_info *kern; - - if (!dev->agp || !dev->agp->acquired) - return -EINVAL; - - kern = &dev->agp->agp_info; - info->agp_version_major = kern->version.major; - info->agp_version_minor = kern->version.minor; - info->mode = kern->mode; - info->aperture_base = kern->aper_base; - info->aperture_size = kern->aper_size * 1024 * 1024; - info->memory_allowed = kern->max_memory << PAGE_SHIFT; - info->memory_used = kern->current_memory << PAGE_SHIFT; - info->id_vendor = kern->device->vendor; - info->id_device = kern->device->device; - - return 0; -} -EXPORT_SYMBOL(drm_legacy_agp_info); - -int drm_legacy_agp_info_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_agp_info *info = data; - int err; - - err = drm_legacy_agp_info(dev, info); - if (err) - return err; - - return 0; -} - -/* - * Acquire the AGP device. - * - * \param dev DRM device that is to acquire AGP. - * \return zero on success or a negative number on failure. - * - * Verifies the AGP device hasn't been acquired before and calls - * \c agp_backend_acquire. - */ -int drm_legacy_agp_acquire(struct drm_device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev->dev); - - if (!dev->agp) - return -ENODEV; - if (dev->agp->acquired) - return -EBUSY; - dev->agp->bridge = agp_backend_acquire(pdev); - if (!dev->agp->bridge) - return -ENODEV; - dev->agp->acquired = 1; - return 0; -} -EXPORT_SYMBOL(drm_legacy_agp_acquire); - -/* - * Acquire the AGP device (ioctl). - * - * \return zero on success or a negative number on failure. - * - * Verifies the AGP device hasn't been acquired before and calls - * \c agp_backend_acquire. - */ -int drm_legacy_agp_acquire_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - return drm_legacy_agp_acquire((struct drm_device *)file_priv->minor->dev); -} - -/* - * Release the AGP device. - * - * \param dev DRM device that is to release AGP. - * \return zero on success or a negative number on failure. - * - * Verifies the AGP device has been acquired and calls \c agp_backend_release. - */ -int drm_legacy_agp_release(struct drm_device *dev) -{ - if (!dev->agp || !dev->agp->acquired) - return -EINVAL; - agp_backend_release(dev->agp->bridge); - dev->agp->acquired = 0; - return 0; -} -EXPORT_SYMBOL(drm_legacy_agp_release); - -int drm_legacy_agp_release_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - return drm_legacy_agp_release(dev); -} - -/* - * Enable the AGP bus. - * - * \param dev DRM device that has previously acquired AGP. - * \param mode Requested AGP mode. - * \return zero on success or a negative number on failure. - * - * Verifies the AGP device has been acquired but not enabled, and calls - * \c agp_enable. - */ -int drm_legacy_agp_enable(struct drm_device *dev, struct drm_agp_mode mode) -{ - if (!dev->agp || !dev->agp->acquired) - return -EINVAL; - - dev->agp->mode = mode.mode; - agp_enable(dev->agp->bridge, mode.mode); - dev->agp->enabled = 1; - return 0; -} -EXPORT_SYMBOL(drm_legacy_agp_enable); - -int drm_legacy_agp_enable_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_agp_mode *mode = data; - - return drm_legacy_agp_enable(dev, *mode); -} - -/* - * Allocate AGP memory. - * - * \return zero on success or a negative number on failure. - * - * Verifies the AGP device is present and has been acquired, allocates the - * memory via agp_allocate_memory() and creates a drm_agp_mem entry for it. - */ -int drm_legacy_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request) -{ - struct drm_agp_mem *entry; - struct agp_memory *memory; - unsigned long pages; - u32 type; - - if (!dev->agp || !dev->agp->acquired) - return -EINVAL; - entry = kzalloc(sizeof(*entry), GFP_KERNEL); - if (!entry) - return -ENOMEM; - - pages = DIV_ROUND_UP(request->size, PAGE_SIZE); - type = (u32) request->type; - memory = agp_allocate_memory(dev->agp->bridge, pages, type); - if (!memory) { - kfree(entry); - return -ENOMEM; - } - - entry->handle = (unsigned long)memory->key + 1; - entry->memory = memory; - entry->bound = 0; - entry->pages = pages; - list_add(&entry->head, &dev->agp->memory); - - request->handle = entry->handle; - request->physical = memory->physical; - - return 0; -} -EXPORT_SYMBOL(drm_legacy_agp_alloc); - - -int drm_legacy_agp_alloc_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_agp_buffer *request = data; - - return drm_legacy_agp_alloc(dev, request); -} - -/* - * Search for the AGP memory entry associated with a handle. - * - * \param dev DRM device structure. - * \param handle AGP memory handle. - * \return pointer to the drm_agp_mem structure associated with \p handle. - * - * Walks through drm_agp_head::memory until finding a matching handle. - */ -static struct drm_agp_mem *drm_legacy_agp_lookup_entry(struct drm_device *dev, - unsigned long handle) -{ - struct drm_agp_mem *entry; - - list_for_each_entry(entry, &dev->agp->memory, head) { - if (entry->handle == handle) - return entry; - } - return NULL; -} - -/* - * Unbind AGP memory from the GATT (ioctl). - * - * \return zero on success or a negative number on failure. - * - * Verifies the AGP device is present and acquired, looks-up the AGP memory - * entry and passes it to the unbind_agp() function. - */ -int drm_legacy_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request) -{ - struct drm_agp_mem *entry; - int ret; - - if (!dev->agp || !dev->agp->acquired) - return -EINVAL; - entry = drm_legacy_agp_lookup_entry(dev, request->handle); - if (!entry || !entry->bound) - return -EINVAL; - ret = agp_unbind_memory(entry->memory); - if (ret == 0) - entry->bound = 0; - return ret; -} -EXPORT_SYMBOL(drm_legacy_agp_unbind); - - -int drm_legacy_agp_unbind_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_agp_binding *request = data; - - return drm_legacy_agp_unbind(dev, request); -} - -/* - * Bind AGP memory into the GATT (ioctl) - * - * \return zero on success or a negative number on failure. - * - * Verifies the AGP device is present and has been acquired and that no memory - * is currently bound into the GATT. Looks-up the AGP memory entry and passes - * it to bind_agp() function. - */ -int drm_legacy_agp_bind(struct drm_device *dev, struct drm_agp_binding *request) -{ - struct drm_agp_mem *entry; - int retcode; - int page; - - if (!dev->agp || !dev->agp->acquired) - return -EINVAL; - entry = drm_legacy_agp_lookup_entry(dev, request->handle); - if (!entry || entry->bound) - return -EINVAL; - page = DIV_ROUND_UP(request->offset, PAGE_SIZE); - retcode = agp_bind_memory(entry->memory, page); - if (retcode) - return retcode; - entry->bound = dev->agp->base + (page << PAGE_SHIFT); - DRM_DEBUG("base = 0x%lx entry->bound = 0x%lx\n", - dev->agp->base, entry->bound); - return 0; -} -EXPORT_SYMBOL(drm_legacy_agp_bind); - - -int drm_legacy_agp_bind_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_agp_binding *request = data; - - return drm_legacy_agp_bind(dev, request); -} - -/* - * Free AGP memory (ioctl). - * - * \return zero on success or a negative number on failure. - * - * Verifies the AGP device is present and has been acquired and looks up the - * AGP memory entry. If the memory is currently bound, unbind it via - * unbind_agp(). Frees it via free_agp() as well as the entry itself - * and unlinks from the doubly linked list it's inserted in. - */ -int drm_legacy_agp_free(struct drm_device *dev, struct drm_agp_buffer *request) -{ - struct drm_agp_mem *entry; - - if (!dev->agp || !dev->agp->acquired) - return -EINVAL; - entry = drm_legacy_agp_lookup_entry(dev, request->handle); - if (!entry) - return -EINVAL; - if (entry->bound) - agp_unbind_memory(entry->memory); - - list_del(&entry->head); - - agp_free_memory(entry->memory); - kfree(entry); - return 0; -} -EXPORT_SYMBOL(drm_legacy_agp_free); - - -int drm_legacy_agp_free_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_agp_buffer *request = data; - - return drm_legacy_agp_free(dev, request); -} - -/* - * Initialize the AGP resources. - * - * \return pointer to a drm_agp_head structure. - * - * Gets the drm_agp_t structure which is made available by the agpgart module - * via the inter_module_* functions. Creates and initializes a drm_agp_head - * structure. - * - * Note that final cleanup of the kmalloced structure is directly done in - * drm_pci_agp_destroy. - */ -struct drm_agp_head *drm_legacy_agp_init(struct drm_device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev->dev); - struct drm_agp_head *head = NULL; - - head = kzalloc(sizeof(*head), GFP_KERNEL); - if (!head) - return NULL; - head->bridge = agp_find_bridge(pdev); - if (!head->bridge) { - head->bridge = agp_backend_acquire(pdev); - if (!head->bridge) { - kfree(head); - return NULL; - } - agp_copy_info(head->bridge, &head->agp_info); - agp_backend_release(head->bridge); - } else { - agp_copy_info(head->bridge, &head->agp_info); - } - if (head->agp_info.chipset == NOT_SUPPORTED) { - kfree(head); - return NULL; - } - INIT_LIST_HEAD(&head->memory); - head->cant_use_aperture = head->agp_info.cant_use_aperture; - head->page_mask = head->agp_info.page_mask; - head->base = head->agp_info.aper_base; - return head; -} -/* Only exported for i810.ko */ -EXPORT_SYMBOL(drm_legacy_agp_init); - -/** - * drm_legacy_agp_clear - Clear AGP resource list - * @dev: DRM device - * - * Iterate over all AGP resources and remove them. But keep the AGP head - * intact so it can still be used. It is safe to call this if AGP is disabled or - * was already removed. - * - * Cleanup is only done for drivers who have DRIVER_LEGACY set. - */ -void drm_legacy_agp_clear(struct drm_device *dev) -{ - struct drm_agp_mem *entry, *tempe; - - if (!dev->agp) - return; - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return; - - list_for_each_entry_safe(entry, tempe, &dev->agp->memory, head) { - if (entry->bound) - agp_unbind_memory(entry->memory); - agp_free_memory(entry->memory); - kfree(entry); - } - INIT_LIST_HEAD(&dev->agp->memory); - - if (dev->agp->acquired) - drm_legacy_agp_release(dev); - - dev->agp->acquired = 0; - dev->agp->enabled = 0; -} - -#endif diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index f1a503aafe5aa1..a91737adf8e7b6 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -733,6 +733,7 @@ static void drm_atomic_plane_print_state(struct drm_printer *p, drm_get_color_encoding_name(state->color_encoding)); drm_printf(p, "\tcolor-range=%s\n", drm_get_color_range_name(state->color_range)); + drm_printf(p, "\tcolor_mgmt_changed=%d\n", state->color_mgmt_changed); if (plane->funcs->atomic_print_state) plane->funcs->atomic_print_state(p, state); @@ -1773,6 +1774,7 @@ static void __drm_state_dump(struct drm_device *dev, struct drm_printer *p, struct drm_crtc *crtc; struct drm_connector *connector; struct drm_connector_list_iter conn_iter; + struct drm_private_obj *obj; if (!drm_drv_uses_atomic_modeset(dev)) return; @@ -1801,6 +1803,14 @@ static void __drm_state_dump(struct drm_device *dev, struct drm_printer *p, if (take_locks) drm_modeset_unlock(&dev->mode_config.connection_mutex); drm_connector_list_iter_end(&conn_iter); + + list_for_each_entry(obj, &config->privobj_list, head) { + if (take_locks) + drm_modeset_lock(&obj->lock, NULL); + drm_atomic_private_obj_print_state(p, obj->state); + if (take_locks) + drm_modeset_unlock(&obj->lock); + } } /** diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 68ffcc0b00dca1..39ef0a6addeba8 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -795,9 +795,9 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, EXPORT_SYMBOL(drm_atomic_helper_check_modeset); /** - * drm_atomic_helper_check_wb_encoder_state() - Check writeback encoder state - * @encoder: encoder state to check - * @conn_state: connector state to check + * drm_atomic_helper_check_wb_connector_state() - Check writeback connector state + * @connector: corresponding connector + * @state: the driver state object * * Checks if the writeback connector state is valid, and returns an error if it * isn't. @@ -806,9 +806,11 @@ EXPORT_SYMBOL(drm_atomic_helper_check_modeset); * Zero for success or -errno */ int -drm_atomic_helper_check_wb_encoder_state(struct drm_encoder *encoder, - struct drm_connector_state *conn_state) +drm_atomic_helper_check_wb_connector_state(struct drm_connector *connector, + struct drm_atomic_state *state) { + struct drm_connector_state *conn_state = + drm_atomic_get_new_connector_state(state, connector); struct drm_writeback_job *wb_job = conn_state->writeback_job; struct drm_property_blob *pixel_format_blob; struct drm_framebuffer *fb; @@ -827,11 +829,11 @@ drm_atomic_helper_check_wb_encoder_state(struct drm_encoder *encoder, if (fb->format->format == formats[i]) return 0; - drm_dbg_kms(encoder->dev, "Invalid pixel format %p4cc\n", &fb->format->format); + drm_dbg_kms(connector->dev, "Invalid pixel format %p4cc\n", &fb->format->format); return -EINVAL; } -EXPORT_SYMBOL(drm_atomic_helper_check_wb_encoder_state); +EXPORT_SYMBOL(drm_atomic_helper_check_wb_connector_state); /** * drm_atomic_helper_check_plane_state() - Check plane state for validity @@ -2382,10 +2384,10 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state, EXPORT_SYMBOL(drm_atomic_helper_setup_commit); /** - * drm_atomic_helper_wait_for_dependencies - wait for required preceeding commits + * drm_atomic_helper_wait_for_dependencies - wait for required preceding commits * @old_state: atomic state object with old state structures * - * This function waits for all preceeding commits that touch the same CRTC as + * This function waits for all preceding commits that touch the same CRTC as * @old_state to both be committed to the hardware (as signalled by * drm_atomic_helper_commit_hw_done()) and executed by the hardware (as signalled * by calling drm_crtc_send_vblank_event() on the &drm_crtc_state.event). diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c index 784e63d70a421e..519228eb109533 100644 --- a/drivers/gpu/drm/drm_atomic_state_helper.c +++ b/drivers/gpu/drm/drm_atomic_state_helper.c @@ -275,6 +275,20 @@ void __drm_atomic_helper_plane_state_reset(struct drm_plane_state *plane_state, plane_state->normalized_zpos = val; } } + + if (plane->hotspot_x_property) { + if (!drm_object_property_get_default_value(&plane->base, + plane->hotspot_x_property, + &val)) + plane_state->hotspot_x = val; + } + + if (plane->hotspot_y_property) { + if (!drm_object_property_get_default_value(&plane->base, + plane->hotspot_y_property, + &val)) + plane_state->hotspot_y = val; + } } EXPORT_SYMBOL(__drm_atomic_helper_plane_state_reset); @@ -338,6 +352,7 @@ void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane, state->fence = NULL; state->commit = NULL; state->fb_damage_clips = NULL; + state->color_mgmt_changed = false; } EXPORT_SYMBOL(__drm_atomic_helper_plane_duplicate_state); diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index 98d3b10c08ae19..29d4940188d49b 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -362,48 +362,6 @@ static s32 __user *get_out_fence_for_connector(struct drm_atomic_state *state, return fence_ptr; } -static int -drm_atomic_replace_property_blob_from_id(struct drm_device *dev, - struct drm_property_blob **blob, - uint64_t blob_id, - ssize_t expected_size, - ssize_t expected_elem_size, - bool *replaced) -{ - struct drm_property_blob *new_blob = NULL; - - if (blob_id != 0) { - new_blob = drm_property_lookup_blob(dev, blob_id); - if (new_blob == NULL) { - drm_dbg_atomic(dev, - "cannot find blob ID %llu\n", blob_id); - return -EINVAL; - } - - if (expected_size > 0 && - new_blob->length != expected_size) { - drm_dbg_atomic(dev, - "[BLOB:%d] length %zu different from expected %zu\n", - new_blob->base.id, new_blob->length, expected_size); - drm_property_blob_put(new_blob); - return -EINVAL; - } - if (expected_elem_size > 0 && - new_blob->length % expected_elem_size != 0) { - drm_dbg_atomic(dev, - "[BLOB:%d] length %zu not divisible by element size %zu\n", - new_blob->base.id, new_blob->length, expected_elem_size); - drm_property_blob_put(new_blob); - return -EINVAL; - } - } - - *replaced |= drm_property_replace_blob(blob, new_blob); - drm_property_blob_put(new_blob); - - return 0; -} - static int drm_atomic_crtc_set_property(struct drm_crtc *crtc, struct drm_crtc_state *state, struct drm_property *property, uint64_t val) @@ -424,7 +382,7 @@ static int drm_atomic_crtc_set_property(struct drm_crtc *crtc, } else if (property == config->prop_vrr_enabled) { state->vrr_enabled = val; } else if (property == config->degamma_lut_property) { - ret = drm_atomic_replace_property_blob_from_id(dev, + ret = drm_property_replace_blob_from_id(dev, &state->degamma_lut, val, -1, sizeof(struct drm_color_lut), @@ -432,7 +390,7 @@ static int drm_atomic_crtc_set_property(struct drm_crtc *crtc, state->color_mgmt_changed |= replaced; return ret; } else if (property == config->ctm_property) { - ret = drm_atomic_replace_property_blob_from_id(dev, + ret = drm_property_replace_blob_from_id(dev, &state->ctm, val, sizeof(struct drm_color_ctm), -1, @@ -440,7 +398,7 @@ static int drm_atomic_crtc_set_property(struct drm_crtc *crtc, state->color_mgmt_changed |= replaced; return ret; } else if (property == config->gamma_lut_property) { - ret = drm_atomic_replace_property_blob_from_id(dev, + ret = drm_property_replace_blob_from_id(dev, &state->gamma_lut, val, -1, sizeof(struct drm_color_lut), @@ -581,7 +539,7 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane, } else if (property == plane->color_range_property) { state->color_range = val; } else if (property == config->prop_fb_damage_clips) { - ret = drm_atomic_replace_property_blob_from_id(dev, + ret = drm_property_replace_blob_from_id(dev, &state->fb_damage_clips, val, -1, @@ -593,6 +551,22 @@ static int drm_atomic_plane_set_property(struct drm_plane *plane, } else if (plane->funcs->atomic_set_property) { return plane->funcs->atomic_set_property(plane, state, property, val); + } else if (property == plane->hotspot_x_property) { + if (plane->type != DRM_PLANE_TYPE_CURSOR) { + drm_dbg_atomic(plane->dev, + "[PLANE:%d:%s] is not a cursor plane: 0x%llx\n", + plane->base.id, plane->name, val); + return -EINVAL; + } + state->hotspot_x = val; + } else if (property == plane->hotspot_y_property) { + if (plane->type != DRM_PLANE_TYPE_CURSOR) { + drm_dbg_atomic(plane->dev, + "[PLANE:%d:%s] is not a cursor plane: 0x%llx\n", + plane->base.id, plane->name, val); + return -EINVAL; + } + state->hotspot_y = val; } else { drm_dbg_atomic(plane->dev, "[PLANE:%d:%s] unknown property [PROP:%d:%s]\n", @@ -653,6 +627,10 @@ drm_atomic_plane_get_property(struct drm_plane *plane, *val = state->scaling_filter; } else if (plane->funcs->atomic_get_property) { return plane->funcs->atomic_get_property(plane, state, property, val); + } else if (property == plane->hotspot_x_property) { + *val = state->hotspot_x; + } else if (property == plane->hotspot_y_property) { + *val = state->hotspot_y; } else { drm_dbg_atomic(dev, "[PLANE:%d:%s] unknown property [PROP:%d:%s]\n", @@ -758,7 +736,7 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector, if (state->link_status != DRM_LINK_STATUS_GOOD) state->link_status = val; } else if (property == config->hdr_output_metadata_property) { - ret = drm_atomic_replace_property_blob_from_id(dev, + ret = drm_property_replace_blob_from_id(dev, &state->hdr_output_metadata, val, sizeof(struct hdr_output_metadata), -1, @@ -1006,13 +984,28 @@ out: return ret; } +static int drm_atomic_check_prop_changes(int ret, uint64_t old_val, uint64_t prop_value, + struct drm_property *prop) +{ + if (ret != 0 || old_val != prop_value) { + drm_dbg_atomic(prop->dev, + "[PROP:%d:%s] No prop can be changed during async flip\n", + prop->base.id, prop->name); + return -EINVAL; + } + + return 0; +} + int drm_atomic_set_property(struct drm_atomic_state *state, struct drm_file *file_priv, struct drm_mode_object *obj, struct drm_property *prop, - uint64_t prop_value) + u64 prop_value, + bool async_flip) { struct drm_mode_object *ref; + u64 old_val; int ret; if (!drm_property_change_valid_get(prop, prop_value, &ref)) @@ -1029,6 +1022,13 @@ int drm_atomic_set_property(struct drm_atomic_state *state, break; } + if (async_flip) { + ret = drm_atomic_connector_get_property(connector, connector_state, + prop, &old_val); + ret = drm_atomic_check_prop_changes(ret, old_val, prop_value, prop); + break; + } + ret = drm_atomic_connector_set_property(connector, connector_state, file_priv, prop, prop_value); @@ -1044,6 +1044,13 @@ int drm_atomic_set_property(struct drm_atomic_state *state, break; } + if (async_flip) { + ret = drm_atomic_crtc_get_property(crtc, crtc_state, + prop, &old_val); + ret = drm_atomic_check_prop_changes(ret, old_val, prop_value, prop); + break; + } + ret = drm_atomic_crtc_set_property(crtc, crtc_state, prop, prop_value); break; @@ -1051,6 +1058,7 @@ int drm_atomic_set_property(struct drm_atomic_state *state, case DRM_MODE_OBJECT_PLANE: { struct drm_plane *plane = obj_to_plane(obj); struct drm_plane_state *plane_state; + struct drm_mode_config *config = &plane->dev->mode_config; plane_state = drm_atomic_get_plane_state(state, plane); if (IS_ERR(plane_state)) { @@ -1058,6 +1066,21 @@ int drm_atomic_set_property(struct drm_atomic_state *state, break; } + if (async_flip && prop != config->prop_fb_id) { + ret = drm_atomic_plane_get_property(plane, plane_state, + prop, &old_val); + ret = drm_atomic_check_prop_changes(ret, old_val, prop_value, prop); + break; + } + + if (async_flip && plane_state->plane->type != DRM_PLANE_TYPE_PRIMARY) { + drm_dbg_atomic(prop->dev, + "[OBJECT:%d] Only primary planes can be changed during async flip\n", + obj->id); + ret = -EINVAL; + break; + } + ret = drm_atomic_plane_set_property(plane, plane_state, file_priv, prop, prop_value); @@ -1323,6 +1346,18 @@ static void complete_signaling(struct drm_device *dev, kfree(fence_state); } +static void +set_async_flip(struct drm_atomic_state *state) +{ + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + int i; + + for_each_new_crtc_in_state(state, crtc, crtc_state, i) { + crtc_state->async_flip = true; + } +} + int drm_mode_atomic_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -1337,6 +1372,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, struct drm_out_fence_state *fence_state; int ret = 0; unsigned int i, j, num_fences; + bool async_flip = false; /* disallow for drivers not supporting atomic: */ if (!drm_core_check_feature(dev, DRIVER_ATOMIC)) @@ -1363,9 +1399,13 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, } if (arg->flags & DRM_MODE_PAGE_FLIP_ASYNC) { - drm_dbg_atomic(dev, - "commit failed: invalid flag DRM_MODE_PAGE_FLIP_ASYNC\n"); - return -EINVAL; + if (!dev->mode_config.async_page_flip) { + drm_dbg_atomic(dev, + "commit failed: DRM_MODE_PAGE_FLIP_ASYNC not supported\n"); + return -EINVAL; + } + + async_flip = true; } /* can't test and expect an event at the same time. */ @@ -1450,8 +1490,8 @@ retry: goto out; } - ret = drm_atomic_set_property(state, file_priv, - obj, prop, prop_value); + ret = drm_atomic_set_property(state, file_priv, obj, + prop, prop_value, async_flip); if (ret) { drm_mode_object_put(obj); goto out; @@ -1468,6 +1508,9 @@ retry: if (ret) goto out; + if (arg->flags & DRM_MODE_PAGE_FLIP_ASYNC) + set_async_flip(state); + if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) { ret = drm_atomic_check_only(state); } else if (arg->flags & DRM_MODE_ATOMIC_NONBLOCK) { diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c index 6899b3dc1f12a5..22aa015df387ca 100644 --- a/drivers/gpu/drm/drm_auth.c +++ b/drivers/gpu/drm/drm_auth.c @@ -37,13 +37,12 @@ #include #include "drm_internal.h" -#include "drm_legacy.h" /** * DOC: master and authentication * * &struct drm_master is used to track groups of clients with open - * primary/legacy device nodes. For every &struct drm_file which has had at + * primary device nodes. For every &struct drm_file which has had at * least once successfully became the device master (either through the * SET_MASTER IOCTL, or implicitly through opening the primary device node when * no one else is the current master that time) there exists one &drm_master. @@ -139,7 +138,6 @@ struct drm_master *drm_master_create(struct drm_device *dev) return NULL; kref_init(&master->refcount); - drm_master_legacy_init(master); idr_init_base(&master->magic_map, 1); master->dev = dev; @@ -365,8 +363,6 @@ void drm_master_release(struct drm_file *file_priv) if (!drm_is_current_master_locked(file_priv)) goto out; - drm_legacy_lock_master_cleanup(dev, master); - if (dev->master == file_priv->master) drm_drop_master(dev, file_priv); out: @@ -429,8 +425,6 @@ static void drm_master_destroy(struct kref *kref) if (drm_core_check_feature(dev, DRIVER_MODESET)) drm_lease_destroy(master); - drm_legacy_master_rmmaps(dev, master); - idr_destroy(&master->magic_map); idr_destroy(&master->leases); idr_destroy(&master->lessee_idr); diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 30d66bee0ec6a9..cee3188adf3d54 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -1347,50 +1347,6 @@ struct drm_bridge *of_drm_find_bridge(struct device_node *np) EXPORT_SYMBOL(of_drm_find_bridge); #endif -#ifdef CONFIG_DEBUG_FS -static int drm_bridge_chains_info(struct seq_file *m, void *data) -{ - struct drm_debugfs_entry *entry = m->private; - struct drm_device *dev = entry->dev; - struct drm_printer p = drm_seq_file_printer(m); - struct drm_mode_config *config = &dev->mode_config; - struct drm_encoder *encoder; - unsigned int bridge_idx = 0; - - list_for_each_entry(encoder, &config->encoder_list, head) { - struct drm_bridge *bridge; - - drm_printf(&p, "encoder[%u]\n", encoder->base.id); - - drm_for_each_bridge_in_chain(encoder, bridge) { - drm_printf(&p, "\tbridge[%u] type: %u, ops: %#x", - bridge_idx, bridge->type, bridge->ops); - -#ifdef CONFIG_OF - if (bridge->of_node) - drm_printf(&p, ", OF: %pOFfc", bridge->of_node); -#endif - - drm_printf(&p, "\n"); - - bridge_idx++; - } - } - - return 0; -} - -static const struct drm_debugfs_info drm_bridge_debugfs_list[] = { - { "bridge_chains", drm_bridge_chains_info, 0 }, -}; - -void drm_bridge_debugfs_init(struct drm_device *dev) -{ - drm_debugfs_add_files(dev, drm_bridge_debugfs_list, - ARRAY_SIZE(drm_bridge_debugfs_list)); -} -#endif - MODULE_AUTHOR("Ajay Kumar "); MODULE_DESCRIPTION("DRM bridge infrastructure"); MODULE_LICENSE("GPL and additional rights"); diff --git a/drivers/gpu/drm/drm_bridge_connector.c b/drivers/gpu/drm/drm_bridge_connector.c index 8239ad43aed58c..3acd67021ec62f 100644 --- a/drivers/gpu/drm/drm_bridge_connector.c +++ b/drivers/gpu/drm/drm_bridge_connector.c @@ -198,12 +198,6 @@ static void drm_bridge_connector_destroy(struct drm_connector *connector) struct drm_bridge_connector *bridge_connector = to_drm_bridge_connector(connector); - if (bridge_connector->bridge_hpd) { - struct drm_bridge *hpd = bridge_connector->bridge_hpd; - - drm_bridge_hpd_disable(hpd); - } - drm_connector_unregister(connector); drm_connector_cleanup(connector); diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c deleted file mode 100644 index 86700560fea28d..00000000000000 --- a/drivers/gpu/drm/drm_bufs.c +++ /dev/null @@ -1,1627 +0,0 @@ -/* - * Legacy: Generic DRM Buffer Management - * - * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * All Rights Reserved. - * - * Author: Rickard E. (Rik) Faith - * Author: Gareth Hughes - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include "drm_legacy.h" - - -static struct drm_map_list *drm_find_matching_map(struct drm_device *dev, - struct drm_local_map *map) -{ - struct drm_map_list *entry; - - list_for_each_entry(entry, &dev->maplist, head) { - /* - * Because the kernel-userspace ABI is fixed at a 32-bit offset - * while PCI resources may live above that, we only compare the - * lower 32 bits of the map offset for maps of type - * _DRM_FRAMEBUFFER or _DRM_REGISTERS. - * It is assumed that if a driver have more than one resource - * of each type, the lower 32 bits are different. - */ - if (!entry->map || - map->type != entry->map->type || - entry->master != dev->master) - continue; - switch (map->type) { - case _DRM_SHM: - if (map->flags != _DRM_CONTAINS_LOCK) - break; - return entry; - case _DRM_REGISTERS: - case _DRM_FRAME_BUFFER: - if ((entry->map->offset & 0xffffffff) == - (map->offset & 0xffffffff)) - return entry; - break; - default: /* Make gcc happy */ - break; - } - if (entry->map->offset == map->offset) - return entry; - } - - return NULL; -} - -static int drm_map_handle(struct drm_device *dev, struct drm_hash_item *hash, - unsigned long user_token, int hashed_handle, int shm) -{ - int use_hashed_handle, shift; - unsigned long add; - -#if (BITS_PER_LONG == 64) - use_hashed_handle = ((user_token & 0xFFFFFFFF00000000UL) || hashed_handle); -#elif (BITS_PER_LONG == 32) - use_hashed_handle = hashed_handle; -#else -#error Unsupported long size. Neither 64 nor 32 bits. -#endif - - if (!use_hashed_handle) { - int ret; - - hash->key = user_token >> PAGE_SHIFT; - ret = drm_ht_insert_item(&dev->map_hash, hash); - if (ret != -EINVAL) - return ret; - } - - shift = 0; - add = DRM_MAP_HASH_OFFSET >> PAGE_SHIFT; - if (shm && (SHMLBA > PAGE_SIZE)) { - int bits = ilog2(SHMLBA >> PAGE_SHIFT) + 1; - - /* For shared memory, we have to preserve the SHMLBA - * bits of the eventual vma->vm_pgoff value during - * mmap(). Otherwise we run into cache aliasing problems - * on some platforms. On these platforms, the pgoff of - * a mmap() request is used to pick a suitable virtual - * address for the mmap() region such that it will not - * cause cache aliasing problems. - * - * Therefore, make sure the SHMLBA relevant bits of the - * hash value we use are equal to those in the original - * kernel virtual address. - */ - shift = bits; - add |= ((user_token >> PAGE_SHIFT) & ((1UL << bits) - 1UL)); - } - - return drm_ht_just_insert_please(&dev->map_hash, hash, - user_token, 32 - PAGE_SHIFT - 3, - shift, add); -} - -/* - * Core function to create a range of memory available for mapping by a - * non-root process. - * - * Adjusts the memory offset to its absolute value according to the mapping - * type. Adds the map to the map list drm_device::maplist. Adds MTRR's where - * applicable and if supported by the kernel. - */ -static int drm_addmap_core(struct drm_device *dev, resource_size_t offset, - unsigned int size, enum drm_map_type type, - enum drm_map_flags flags, - struct drm_map_list **maplist) -{ - struct drm_local_map *map; - struct drm_map_list *list; - unsigned long user_token; - int ret; - - map = kmalloc(sizeof(*map), GFP_KERNEL); - if (!map) - return -ENOMEM; - - map->offset = offset; - map->size = size; - map->flags = flags; - map->type = type; - - /* Only allow shared memory to be removable since we only keep enough - * book keeping information about shared memory to allow for removal - * when processes fork. - */ - if ((map->flags & _DRM_REMOVABLE) && map->type != _DRM_SHM) { - kfree(map); - return -EINVAL; - } - DRM_DEBUG("offset = 0x%08llx, size = 0x%08lx, type = %d\n", - (unsigned long long)map->offset, map->size, map->type); - - /* page-align _DRM_SHM maps. They are allocated here so there is no security - * hole created by that and it works around various broken drivers that use - * a non-aligned quantity to map the SAREA. --BenH - */ - if (map->type == _DRM_SHM) - map->size = PAGE_ALIGN(map->size); - - if ((map->offset & (~(resource_size_t)PAGE_MASK)) || (map->size & (~PAGE_MASK))) { - kfree(map); - return -EINVAL; - } - map->mtrr = -1; - map->handle = NULL; - - switch (map->type) { - case _DRM_REGISTERS: - case _DRM_FRAME_BUFFER: -#if !defined(__sparc__) && !defined(__alpha__) && !defined(__ia64__) && !defined(__powerpc64__) && !defined(__x86_64__) && !defined(__arm__) - if (map->offset + (map->size-1) < map->offset || - map->offset < virt_to_phys(high_memory)) { - kfree(map); - return -EINVAL; - } -#endif - /* Some drivers preinitialize some maps, without the X Server - * needing to be aware of it. Therefore, we just return success - * when the server tries to create a duplicate map. - */ - list = drm_find_matching_map(dev, map); - if (list != NULL) { - if (list->map->size != map->size) { - DRM_DEBUG("Matching maps of type %d with " - "mismatched sizes, (%ld vs %ld)\n", - map->type, map->size, - list->map->size); - list->map->size = map->size; - } - - kfree(map); - *maplist = list; - return 0; - } - - if (map->type == _DRM_FRAME_BUFFER || - (map->flags & _DRM_WRITE_COMBINING)) { - map->mtrr = - arch_phys_wc_add(map->offset, map->size); - } - if (map->type == _DRM_REGISTERS) { - if (map->flags & _DRM_WRITE_COMBINING) - map->handle = ioremap_wc(map->offset, - map->size); - else - map->handle = ioremap(map->offset, map->size); - if (!map->handle) { - kfree(map); - return -ENOMEM; - } - } - - break; - case _DRM_SHM: - list = drm_find_matching_map(dev, map); - if (list != NULL) { - if (list->map->size != map->size) { - DRM_DEBUG("Matching maps of type %d with " - "mismatched sizes, (%ld vs %ld)\n", - map->type, map->size, list->map->size); - list->map->size = map->size; - } - - kfree(map); - *maplist = list; - return 0; - } - map->handle = vmalloc_user(map->size); - DRM_DEBUG("%lu %d %p\n", - map->size, order_base_2(map->size), map->handle); - if (!map->handle) { - kfree(map); - return -ENOMEM; - } - map->offset = (unsigned long)map->handle; - if (map->flags & _DRM_CONTAINS_LOCK) { - /* Prevent a 2nd X Server from creating a 2nd lock */ - if (dev->master->lock.hw_lock != NULL) { - vfree(map->handle); - kfree(map); - return -EBUSY; - } - dev->sigdata.lock = dev->master->lock.hw_lock = map->handle; /* Pointer to lock */ - } - break; - case _DRM_AGP: { - struct drm_agp_mem *entry; - int valid = 0; - - if (!dev->agp) { - kfree(map); - return -EINVAL; - } -#ifdef __alpha__ - map->offset += dev->hose->mem_space->start; -#endif - /* In some cases (i810 driver), user space may have already - * added the AGP base itself, because dev->agp->base previously - * only got set during AGP enable. So, only add the base - * address if the map's offset isn't already within the - * aperture. - */ - if (map->offset < dev->agp->base || - map->offset > dev->agp->base + - dev->agp->agp_info.aper_size * 1024 * 1024 - 1) { - map->offset += dev->agp->base; - } - map->mtrr = dev->agp->agp_mtrr; /* for getmap */ - - /* This assumes the DRM is in total control of AGP space. - * It's not always the case as AGP can be in the control - * of user space (i.e. i810 driver). So this loop will get - * skipped and we double check that dev->agp->memory is - * actually set as well as being invalid before EPERM'ing - */ - list_for_each_entry(entry, &dev->agp->memory, head) { - if ((map->offset >= entry->bound) && - (map->offset + map->size <= entry->bound + entry->pages * PAGE_SIZE)) { - valid = 1; - break; - } - } - if (!list_empty(&dev->agp->memory) && !valid) { - kfree(map); - return -EPERM; - } - DRM_DEBUG("AGP offset = 0x%08llx, size = 0x%08lx\n", - (unsigned long long)map->offset, map->size); - - break; - } - case _DRM_SCATTER_GATHER: - if (!dev->sg) { - kfree(map); - return -EINVAL; - } - map->offset += (unsigned long)dev->sg->virtual; - break; - case _DRM_CONSISTENT: - /* dma_addr_t is 64bit on i386 with CONFIG_HIGHMEM64G, - * As we're limiting the address to 2^32-1 (or less), - * casting it down to 32 bits is no problem, but we - * need to point to a 64bit variable first. - */ - map->handle = dma_alloc_coherent(dev->dev, - map->size, - &map->offset, - GFP_KERNEL); - if (!map->handle) { - kfree(map); - return -ENOMEM; - } - break; - default: - kfree(map); - return -EINVAL; - } - - list = kzalloc(sizeof(*list), GFP_KERNEL); - if (!list) { - if (map->type == _DRM_REGISTERS) - iounmap(map->handle); - kfree(map); - return -EINVAL; - } - list->map = map; - - mutex_lock(&dev->struct_mutex); - list_add(&list->head, &dev->maplist); - - /* Assign a 32-bit handle */ - /* We do it here so that dev->struct_mutex protects the increment */ - user_token = (map->type == _DRM_SHM) ? (unsigned long)map->handle : - map->offset; - ret = drm_map_handle(dev, &list->hash, user_token, 0, - (map->type == _DRM_SHM)); - if (ret) { - if (map->type == _DRM_REGISTERS) - iounmap(map->handle); - kfree(map); - kfree(list); - mutex_unlock(&dev->struct_mutex); - return ret; - } - - list->user_token = list->hash.key << PAGE_SHIFT; - mutex_unlock(&dev->struct_mutex); - - if (!(map->flags & _DRM_DRIVER)) - list->master = dev->master; - *maplist = list; - return 0; -} - -int drm_legacy_addmap(struct drm_device *dev, resource_size_t offset, - unsigned int size, enum drm_map_type type, - enum drm_map_flags flags, struct drm_local_map **map_ptr) -{ - struct drm_map_list *list; - int rc; - - rc = drm_addmap_core(dev, offset, size, type, flags, &list); - if (!rc) - *map_ptr = list->map; - return rc; -} -EXPORT_SYMBOL(drm_legacy_addmap); - -struct drm_local_map *drm_legacy_findmap(struct drm_device *dev, - unsigned int token) -{ - struct drm_map_list *_entry; - - list_for_each_entry(_entry, &dev->maplist, head) - if (_entry->user_token == token) - return _entry->map; - return NULL; -} -EXPORT_SYMBOL(drm_legacy_findmap); - -/* - * Ioctl to specify a range of memory that is available for mapping by a - * non-root process. - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg pointer to a drm_map structure. - * \return zero on success or a negative value on error. - * - */ -int drm_legacy_addmap_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_map *map = data; - struct drm_map_list *maplist; - int err; - - if (!(capable(CAP_SYS_ADMIN) || map->type == _DRM_AGP || map->type == _DRM_SHM)) - return -EPERM; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - err = drm_addmap_core(dev, map->offset, map->size, map->type, - map->flags, &maplist); - - if (err) - return err; - - /* avoid a warning on 64-bit, this casting isn't very nice, but the API is set so too late */ - map->handle = (void *)(unsigned long)maplist->user_token; - - /* - * It appears that there are no users of this value whatsoever -- - * drmAddMap just discards it. Let's not encourage its use. - * (Keeping drm_addmap_core's returned mtrr value would be wrong -- - * it's not a real mtrr index anymore.) - */ - map->mtrr = -1; - - return 0; -} - -/* - * Get a mapping information. - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg user argument, pointing to a drm_map structure. - * - * \return zero on success or a negative number on failure. - * - * Searches for the mapping with the specified offset and copies its information - * into userspace - */ -int drm_legacy_getmap_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_map *map = data; - struct drm_map_list *r_list = NULL; - struct list_head *list; - int idx; - int i; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - idx = map->offset; - if (idx < 0) - return -EINVAL; - - i = 0; - mutex_lock(&dev->struct_mutex); - list_for_each(list, &dev->maplist) { - if (i == idx) { - r_list = list_entry(list, struct drm_map_list, head); - break; - } - i++; - } - if (!r_list || !r_list->map) { - mutex_unlock(&dev->struct_mutex); - return -EINVAL; - } - - map->offset = r_list->map->offset; - map->size = r_list->map->size; - map->type = r_list->map->type; - map->flags = r_list->map->flags; - map->handle = (void *)(unsigned long) r_list->user_token; - map->mtrr = arch_phys_wc_index(r_list->map->mtrr); - - mutex_unlock(&dev->struct_mutex); - - return 0; -} - -/* - * Remove a map private from list and deallocate resources if the mapping - * isn't in use. - * - * Searches the map on drm_device::maplist, removes it from the list, see if - * it's being used, and free any associated resource (such as MTRR's) if it's not - * being on use. - * - * \sa drm_legacy_addmap - */ -int drm_legacy_rmmap_locked(struct drm_device *dev, struct drm_local_map *map) -{ - struct drm_map_list *r_list = NULL, *list_t; - int found = 0; - struct drm_master *master; - - /* Find the list entry for the map and remove it */ - list_for_each_entry_safe(r_list, list_t, &dev->maplist, head) { - if (r_list->map == map) { - master = r_list->master; - list_del(&r_list->head); - drm_ht_remove_key(&dev->map_hash, - r_list->user_token >> PAGE_SHIFT); - kfree(r_list); - found = 1; - break; - } - } - - if (!found) - return -EINVAL; - - switch (map->type) { - case _DRM_REGISTERS: - iounmap(map->handle); - fallthrough; - case _DRM_FRAME_BUFFER: - arch_phys_wc_del(map->mtrr); - break; - case _DRM_SHM: - vfree(map->handle); - if (master) { - if (dev->sigdata.lock == master->lock.hw_lock) - dev->sigdata.lock = NULL; - master->lock.hw_lock = NULL; /* SHM removed */ - master->lock.file_priv = NULL; - wake_up_interruptible_all(&master->lock.lock_queue); - } - break; - case _DRM_AGP: - case _DRM_SCATTER_GATHER: - break; - case _DRM_CONSISTENT: - dma_free_coherent(dev->dev, - map->size, - map->handle, - map->offset); - break; - } - kfree(map); - - return 0; -} -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_LEGACY)) - return; - - mutex_lock(&dev->struct_mutex); - drm_legacy_rmmap_locked(dev, map); - mutex_unlock(&dev->struct_mutex); -} -EXPORT_SYMBOL(drm_legacy_rmmap); - -void drm_legacy_master_rmmaps(struct drm_device *dev, struct drm_master *master) -{ - struct drm_map_list *r_list, *list_temp; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return; - - mutex_lock(&dev->struct_mutex); - list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head) { - if (r_list->master == master) { - drm_legacy_rmmap_locked(dev, r_list->map); - r_list = NULL; - } - } - mutex_unlock(&dev->struct_mutex); -} - -void drm_legacy_rmmaps(struct drm_device *dev) -{ - struct drm_map_list *r_list, *list_temp; - - list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head) - drm_legacy_rmmap(dev, r_list->map); -} - -/* The rmmap ioctl appears to be unnecessary. All mappings are torn down on - * the last close of the device, and this is necessary for cleanup when things - * exit uncleanly. Therefore, having userland manually remove mappings seems - * like a pointless exercise since they're going away anyway. - * - * One use case might be after addmap is allowed for normal users for SHM and - * gets used by drivers that the server doesn't need to care about. This seems - * unlikely. - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg pointer to a struct drm_map structure. - * \return zero on success or a negative value on error. - */ -int drm_legacy_rmmap_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_map *request = data; - struct drm_local_map *map = NULL; - struct drm_map_list *r_list; - int ret; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - mutex_lock(&dev->struct_mutex); - list_for_each_entry(r_list, &dev->maplist, head) { - if (r_list->map && - r_list->user_token == (unsigned long)request->handle && - r_list->map->flags & _DRM_REMOVABLE) { - map = r_list->map; - break; - } - } - - /* List has wrapped around to the head pointer, or it's empty we didn't - * find anything. - */ - if (list_empty(&dev->maplist) || !map) { - mutex_unlock(&dev->struct_mutex); - return -EINVAL; - } - - /* Register and framebuffer maps are permanent */ - if ((map->type == _DRM_REGISTERS) || (map->type == _DRM_FRAME_BUFFER)) { - mutex_unlock(&dev->struct_mutex); - return 0; - } - - ret = drm_legacy_rmmap_locked(dev, map); - - mutex_unlock(&dev->struct_mutex); - - return ret; -} - -/* - * Cleanup after an error on one of the addbufs() functions. - * - * \param dev DRM device. - * \param entry buffer entry where the error occurred. - * - * Frees any pages and buffers associated with the given entry. - */ -static void drm_cleanup_buf_error(struct drm_device *dev, - struct drm_buf_entry *entry) -{ - drm_dma_handle_t *dmah; - int i; - - if (entry->seg_count) { - for (i = 0; i < entry->seg_count; i++) { - if (entry->seglist[i]) { - dmah = entry->seglist[i]; - dma_free_coherent(dev->dev, - dmah->size, - dmah->vaddr, - dmah->busaddr); - kfree(dmah); - } - } - kfree(entry->seglist); - - entry->seg_count = 0; - } - - if (entry->buf_count) { - for (i = 0; i < entry->buf_count; i++) { - kfree(entry->buflist[i].dev_private); - } - kfree(entry->buflist); - - entry->buf_count = 0; - } -} - -#if IS_ENABLED(CONFIG_AGP) -/* - * Add AGP buffers for DMA transfers. - * - * \param dev struct drm_device to which the buffers are to be added. - * \param request pointer to a struct drm_buf_desc describing the request. - * \return zero on success or a negative number on failure. - * - * After some sanity checks creates a drm_buf structure for each buffer and - * reallocates the buffer list of the same size order to accommodate the new - * buffers. - */ -int drm_legacy_addbufs_agp(struct drm_device *dev, - struct drm_buf_desc *request) -{ - struct drm_device_dma *dma = dev->dma; - struct drm_buf_entry *entry; - struct drm_agp_mem *agp_entry; - struct drm_buf *buf; - unsigned long offset; - unsigned long agp_offset; - int count; - int order; - int size; - int alignment; - int page_order; - int total; - int byte_count; - int i, valid; - struct drm_buf **temp_buflist; - - if (!dma) - return -EINVAL; - - count = request->count; - order = order_base_2(request->size); - size = 1 << order; - - alignment = (request->flags & _DRM_PAGE_ALIGN) - ? PAGE_ALIGN(size) : size; - page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; - total = PAGE_SIZE << page_order; - - byte_count = 0; - agp_offset = dev->agp->base + request->agp_start; - - DRM_DEBUG("count: %d\n", count); - DRM_DEBUG("order: %d\n", order); - DRM_DEBUG("size: %d\n", size); - DRM_DEBUG("agp_offset: %lx\n", agp_offset); - DRM_DEBUG("alignment: %d\n", alignment); - DRM_DEBUG("page_order: %d\n", page_order); - DRM_DEBUG("total: %d\n", total); - - if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) - return -EINVAL; - - /* Make sure buffers are located in AGP memory that we own */ - valid = 0; - list_for_each_entry(agp_entry, &dev->agp->memory, head) { - if ((agp_offset >= agp_entry->bound) && - (agp_offset + total * count <= agp_entry->bound + agp_entry->pages * PAGE_SIZE)) { - valid = 1; - break; - } - } - if (!list_empty(&dev->agp->memory) && !valid) { - DRM_DEBUG("zone invalid\n"); - return -EINVAL; - } - spin_lock(&dev->buf_lock); - if (dev->buf_use) { - spin_unlock(&dev->buf_lock); - return -EBUSY; - } - atomic_inc(&dev->buf_alloc); - spin_unlock(&dev->buf_lock); - - mutex_lock(&dev->struct_mutex); - entry = &dma->bufs[order]; - if (entry->buf_count) { - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; /* May only call once for each order */ - } - - if (count < 0 || count > 4096) { - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -EINVAL; - } - - entry->buflist = kcalloc(count, sizeof(*entry->buflist), GFP_KERNEL); - if (!entry->buflist) { - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; - } - - entry->buf_size = size; - entry->page_order = page_order; - - offset = 0; - - while (entry->buf_count < count) { - buf = &entry->buflist[entry->buf_count]; - buf->idx = dma->buf_count + entry->buf_count; - buf->total = alignment; - buf->order = order; - buf->used = 0; - - buf->offset = (dma->byte_count + offset); - buf->bus_address = agp_offset + offset; - buf->address = (void *)(agp_offset + offset); - buf->next = NULL; - buf->waiting = 0; - buf->pending = 0; - buf->file_priv = NULL; - - buf->dev_priv_size = dev->driver->dev_priv_size; - buf->dev_private = kzalloc(buf->dev_priv_size, GFP_KERNEL); - if (!buf->dev_private) { - /* Set count correctly so we free the proper amount. */ - entry->buf_count = count; - drm_cleanup_buf_error(dev, entry); - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; - } - - DRM_DEBUG("buffer %d @ %p\n", entry->buf_count, buf->address); - - offset += alignment; - entry->buf_count++; - byte_count += PAGE_SIZE << page_order; - } - - DRM_DEBUG("byte_count: %d\n", byte_count); - - temp_buflist = krealloc(dma->buflist, - (dma->buf_count + entry->buf_count) * - sizeof(*dma->buflist), GFP_KERNEL); - if (!temp_buflist) { - /* Free the entry because it isn't valid */ - drm_cleanup_buf_error(dev, entry); - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; - } - dma->buflist = temp_buflist; - - for (i = 0; i < entry->buf_count; i++) { - dma->buflist[i + dma->buf_count] = &entry->buflist[i]; - } - - dma->buf_count += entry->buf_count; - dma->seg_count += entry->seg_count; - dma->page_count += byte_count >> PAGE_SHIFT; - dma->byte_count += byte_count; - - DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count); - DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count); - - mutex_unlock(&dev->struct_mutex); - - request->count = entry->buf_count; - request->size = size; - - dma->flags = _DRM_DMA_USE_AGP; - - atomic_dec(&dev->buf_alloc); - return 0; -} -EXPORT_SYMBOL(drm_legacy_addbufs_agp); -#endif /* CONFIG_AGP */ - -int drm_legacy_addbufs_pci(struct drm_device *dev, - struct drm_buf_desc *request) -{ - struct drm_device_dma *dma = dev->dma; - int count; - int order; - int size; - int total; - int page_order; - struct drm_buf_entry *entry; - drm_dma_handle_t *dmah; - struct drm_buf *buf; - int alignment; - unsigned long offset; - int i; - int byte_count; - int page_count; - unsigned long *temp_pagelist; - struct drm_buf **temp_buflist; - - if (!drm_core_check_feature(dev, DRIVER_PCI_DMA)) - return -EOPNOTSUPP; - - if (!dma) - return -EINVAL; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - count = request->count; - order = order_base_2(request->size); - size = 1 << order; - - DRM_DEBUG("count=%d, size=%d (%d), order=%d\n", - request->count, request->size, size, order); - - if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) - return -EINVAL; - - alignment = (request->flags & _DRM_PAGE_ALIGN) - ? PAGE_ALIGN(size) : size; - page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; - total = PAGE_SIZE << page_order; - - spin_lock(&dev->buf_lock); - if (dev->buf_use) { - spin_unlock(&dev->buf_lock); - return -EBUSY; - } - atomic_inc(&dev->buf_alloc); - spin_unlock(&dev->buf_lock); - - mutex_lock(&dev->struct_mutex); - entry = &dma->bufs[order]; - if (entry->buf_count) { - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; /* May only call once for each order */ - } - - if (count < 0 || count > 4096) { - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -EINVAL; - } - - entry->buflist = kcalloc(count, sizeof(*entry->buflist), GFP_KERNEL); - if (!entry->buflist) { - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; - } - - entry->seglist = kcalloc(count, sizeof(*entry->seglist), GFP_KERNEL); - if (!entry->seglist) { - kfree(entry->buflist); - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; - } - - /* Keep the original pagelist until we know all the allocations - * have succeeded - */ - temp_pagelist = kmalloc_array(dma->page_count + (count << page_order), - sizeof(*dma->pagelist), - GFP_KERNEL); - if (!temp_pagelist) { - kfree(entry->buflist); - kfree(entry->seglist); - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; - } - memcpy(temp_pagelist, - dma->pagelist, dma->page_count * sizeof(*dma->pagelist)); - DRM_DEBUG("pagelist: %d entries\n", - dma->page_count + (count << page_order)); - - entry->buf_size = size; - entry->page_order = page_order; - byte_count = 0; - page_count = 0; - - while (entry->buf_count < count) { - dmah = kmalloc(sizeof(drm_dma_handle_t), GFP_KERNEL); - if (!dmah) { - /* Set count correctly so we free the proper amount. */ - entry->buf_count = count; - entry->seg_count = count; - drm_cleanup_buf_error(dev, entry); - kfree(temp_pagelist); - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; - } - - dmah->size = total; - dmah->vaddr = dma_alloc_coherent(dev->dev, - dmah->size, - &dmah->busaddr, - GFP_KERNEL); - if (!dmah->vaddr) { - kfree(dmah); - - /* Set count correctly so we free the proper amount. */ - entry->buf_count = count; - entry->seg_count = count; - drm_cleanup_buf_error(dev, entry); - kfree(temp_pagelist); - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; - } - entry->seglist[entry->seg_count++] = dmah; - for (i = 0; i < (1 << page_order); i++) { - DRM_DEBUG("page %d @ 0x%08lx\n", - dma->page_count + page_count, - (unsigned long)dmah->vaddr + PAGE_SIZE * i); - temp_pagelist[dma->page_count + page_count++] - = (unsigned long)dmah->vaddr + PAGE_SIZE * i; - } - for (offset = 0; - offset + size <= total && entry->buf_count < count; - offset += alignment, ++entry->buf_count) { - buf = &entry->buflist[entry->buf_count]; - buf->idx = dma->buf_count + entry->buf_count; - buf->total = alignment; - buf->order = order; - buf->used = 0; - buf->offset = (dma->byte_count + byte_count + offset); - buf->address = (void *)(dmah->vaddr + offset); - buf->bus_address = dmah->busaddr + offset; - buf->next = NULL; - buf->waiting = 0; - buf->pending = 0; - buf->file_priv = NULL; - - buf->dev_priv_size = dev->driver->dev_priv_size; - buf->dev_private = kzalloc(buf->dev_priv_size, - GFP_KERNEL); - if (!buf->dev_private) { - /* Set count correctly so we free the proper amount. */ - entry->buf_count = count; - entry->seg_count = count; - drm_cleanup_buf_error(dev, entry); - kfree(temp_pagelist); - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; - } - - DRM_DEBUG("buffer %d @ %p\n", - entry->buf_count, buf->address); - } - byte_count += PAGE_SIZE << page_order; - } - - temp_buflist = krealloc(dma->buflist, - (dma->buf_count + entry->buf_count) * - sizeof(*dma->buflist), GFP_KERNEL); - if (!temp_buflist) { - /* Free the entry because it isn't valid */ - drm_cleanup_buf_error(dev, entry); - kfree(temp_pagelist); - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; - } - dma->buflist = temp_buflist; - - for (i = 0; i < entry->buf_count; i++) { - dma->buflist[i + dma->buf_count] = &entry->buflist[i]; - } - - /* No allocations failed, so now we can replace the original pagelist - * with the new one. - */ - if (dma->page_count) { - kfree(dma->pagelist); - } - dma->pagelist = temp_pagelist; - - dma->buf_count += entry->buf_count; - dma->seg_count += entry->seg_count; - dma->page_count += entry->seg_count << page_order; - dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order); - - mutex_unlock(&dev->struct_mutex); - - request->count = entry->buf_count; - request->size = size; - - if (request->flags & _DRM_PCI_BUFFER_RO) - dma->flags = _DRM_DMA_USE_PCI_RO; - - atomic_dec(&dev->buf_alloc); - return 0; - -} -EXPORT_SYMBOL(drm_legacy_addbufs_pci); - -static int drm_legacy_addbufs_sg(struct drm_device *dev, - struct drm_buf_desc *request) -{ - struct drm_device_dma *dma = dev->dma; - struct drm_buf_entry *entry; - struct drm_buf *buf; - unsigned long offset; - unsigned long agp_offset; - int count; - int order; - int size; - int alignment; - int page_order; - int total; - int byte_count; - int i; - struct drm_buf **temp_buflist; - - if (!drm_core_check_feature(dev, DRIVER_SG)) - return -EOPNOTSUPP; - - if (!dma) - return -EINVAL; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - count = request->count; - order = order_base_2(request->size); - size = 1 << order; - - alignment = (request->flags & _DRM_PAGE_ALIGN) - ? PAGE_ALIGN(size) : size; - page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; - total = PAGE_SIZE << page_order; - - byte_count = 0; - agp_offset = request->agp_start; - - DRM_DEBUG("count: %d\n", count); - DRM_DEBUG("order: %d\n", order); - DRM_DEBUG("size: %d\n", size); - DRM_DEBUG("agp_offset: %lu\n", agp_offset); - DRM_DEBUG("alignment: %d\n", alignment); - DRM_DEBUG("page_order: %d\n", page_order); - DRM_DEBUG("total: %d\n", total); - - if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) - return -EINVAL; - - spin_lock(&dev->buf_lock); - if (dev->buf_use) { - spin_unlock(&dev->buf_lock); - return -EBUSY; - } - atomic_inc(&dev->buf_alloc); - spin_unlock(&dev->buf_lock); - - mutex_lock(&dev->struct_mutex); - entry = &dma->bufs[order]; - if (entry->buf_count) { - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; /* May only call once for each order */ - } - - if (count < 0 || count > 4096) { - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -EINVAL; - } - - entry->buflist = kcalloc(count, sizeof(*entry->buflist), GFP_KERNEL); - if (!entry->buflist) { - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; - } - - entry->buf_size = size; - entry->page_order = page_order; - - offset = 0; - - while (entry->buf_count < count) { - buf = &entry->buflist[entry->buf_count]; - buf->idx = dma->buf_count + entry->buf_count; - buf->total = alignment; - buf->order = order; - buf->used = 0; - - buf->offset = (dma->byte_count + offset); - buf->bus_address = agp_offset + offset; - buf->address = (void *)(agp_offset + offset - + (unsigned long)dev->sg->virtual); - buf->next = NULL; - buf->waiting = 0; - buf->pending = 0; - buf->file_priv = NULL; - - buf->dev_priv_size = dev->driver->dev_priv_size; - buf->dev_private = kzalloc(buf->dev_priv_size, GFP_KERNEL); - if (!buf->dev_private) { - /* Set count correctly so we free the proper amount. */ - entry->buf_count = count; - drm_cleanup_buf_error(dev, entry); - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; - } - - DRM_DEBUG("buffer %d @ %p\n", entry->buf_count, buf->address); - - offset += alignment; - entry->buf_count++; - byte_count += PAGE_SIZE << page_order; - } - - DRM_DEBUG("byte_count: %d\n", byte_count); - - temp_buflist = krealloc(dma->buflist, - (dma->buf_count + entry->buf_count) * - sizeof(*dma->buflist), GFP_KERNEL); - if (!temp_buflist) { - /* Free the entry because it isn't valid */ - drm_cleanup_buf_error(dev, entry); - mutex_unlock(&dev->struct_mutex); - atomic_dec(&dev->buf_alloc); - return -ENOMEM; - } - dma->buflist = temp_buflist; - - for (i = 0; i < entry->buf_count; i++) { - dma->buflist[i + dma->buf_count] = &entry->buflist[i]; - } - - dma->buf_count += entry->buf_count; - dma->seg_count += entry->seg_count; - dma->page_count += byte_count >> PAGE_SHIFT; - dma->byte_count += byte_count; - - DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count); - DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count); - - mutex_unlock(&dev->struct_mutex); - - request->count = entry->buf_count; - request->size = size; - - dma->flags = _DRM_DMA_USE_SG; - - atomic_dec(&dev->buf_alloc); - return 0; -} - -/* - * Add buffers for DMA transfers (ioctl). - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg pointer to a struct drm_buf_desc request. - * \return zero on success or a negative number on failure. - * - * According with the memory type specified in drm_buf_desc::flags and the - * build options, it dispatches the call either to addbufs_agp(), - * addbufs_sg() or addbufs_pci() for AGP, scatter-gather or consistent - * PCI memory respectively. - */ -int drm_legacy_addbufs(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_buf_desc *request = data; - int ret; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) - return -EOPNOTSUPP; - -#if IS_ENABLED(CONFIG_AGP) - if (request->flags & _DRM_AGP_BUFFER) - ret = drm_legacy_addbufs_agp(dev, request); - else -#endif - if (request->flags & _DRM_SG_BUFFER) - ret = drm_legacy_addbufs_sg(dev, request); - else if (request->flags & _DRM_FB_BUFFER) - ret = -EINVAL; - else - ret = drm_legacy_addbufs_pci(dev, request); - - return ret; -} - -/* - * Get information about the buffer mappings. - * - * This was originally mean for debugging purposes, or by a sophisticated - * client library to determine how best to use the available buffers (e.g., - * large buffers can be used for image transfer). - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg pointer to a drm_buf_info structure. - * \return zero on success or a negative number on failure. - * - * Increments drm_device::buf_use while holding the drm_device::buf_lock - * lock, preventing of allocating more buffers after this call. Information - * about each requested buffer is then copied into user space. - */ -int __drm_legacy_infobufs(struct drm_device *dev, - void *data, int *p, - int (*f)(void *, int, struct drm_buf_entry *)) -{ - struct drm_device_dma *dma = dev->dma; - int i; - int count; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) - return -EOPNOTSUPP; - - if (!dma) - return -EINVAL; - - spin_lock(&dev->buf_lock); - if (atomic_read(&dev->buf_alloc)) { - spin_unlock(&dev->buf_lock); - return -EBUSY; - } - ++dev->buf_use; /* Can't allocate more after this call */ - spin_unlock(&dev->buf_lock); - - for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) { - if (dma->bufs[i].buf_count) - ++count; - } - - DRM_DEBUG("count = %d\n", count); - - if (*p >= count) { - for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) { - struct drm_buf_entry *from = &dma->bufs[i]; - - if (from->buf_count) { - if (f(data, count, from) < 0) - return -EFAULT; - DRM_DEBUG("%d %d %d %d %d\n", - i, - dma->bufs[i].buf_count, - dma->bufs[i].buf_size, - dma->bufs[i].low_mark, - dma->bufs[i].high_mark); - ++count; - } - } - } - *p = count; - - return 0; -} - -static int copy_one_buf(void *data, int count, struct drm_buf_entry *from) -{ - struct drm_buf_info *request = data; - struct drm_buf_desc __user *to = &request->list[count]; - struct drm_buf_desc v = {.count = from->buf_count, - .size = from->buf_size, - .low_mark = from->low_mark, - .high_mark = from->high_mark}; - - if (copy_to_user(to, &v, offsetof(struct drm_buf_desc, flags))) - return -EFAULT; - return 0; -} - -int drm_legacy_infobufs(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_buf_info *request = data; - - return __drm_legacy_infobufs(dev, data, &request->count, copy_one_buf); -} - -/* - * Specifies a low and high water mark for buffer allocation - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg a pointer to a drm_buf_desc structure. - * \return zero on success or a negative number on failure. - * - * Verifies that the size order is bounded between the admissible orders and - * updates the respective drm_device_dma::bufs entry low and high water mark. - * - * \note This ioctl is deprecated and mostly never used. - */ -int drm_legacy_markbufs(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_device_dma *dma = dev->dma; - struct drm_buf_desc *request = data; - int order; - struct drm_buf_entry *entry; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) - return -EOPNOTSUPP; - - if (!dma) - return -EINVAL; - - DRM_DEBUG("%d, %d, %d\n", - request->size, request->low_mark, request->high_mark); - order = order_base_2(request->size); - if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) - return -EINVAL; - entry = &dma->bufs[order]; - - if (request->low_mark < 0 || request->low_mark > entry->buf_count) - return -EINVAL; - if (request->high_mark < 0 || request->high_mark > entry->buf_count) - return -EINVAL; - - entry->low_mark = request->low_mark; - entry->high_mark = request->high_mark; - - return 0; -} - -/* - * Unreserve the buffers in list, previously reserved using drmDMA. - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg pointer to a drm_buf_free structure. - * \return zero on success or a negative number on failure. - * - * Calls free_buffer() for each used buffer. - * This function is primarily used for debugging. - */ -int drm_legacy_freebufs(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_device_dma *dma = dev->dma; - struct drm_buf_free *request = data; - int i; - int idx; - struct drm_buf *buf; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) - return -EOPNOTSUPP; - - if (!dma) - return -EINVAL; - - DRM_DEBUG("%d\n", request->count); - for (i = 0; i < request->count; i++) { - if (copy_from_user(&idx, &request->list[i], sizeof(idx))) - return -EFAULT; - if (idx < 0 || idx >= dma->buf_count) { - DRM_ERROR("Index %d (of %d max)\n", - idx, dma->buf_count - 1); - return -EINVAL; - } - idx = array_index_nospec(idx, dma->buf_count); - buf = dma->buflist[idx]; - if (buf->file_priv != file_priv) { - DRM_ERROR("Process %d freeing buffer not owned\n", - task_pid_nr(current)); - return -EINVAL; - } - drm_legacy_free_buffer(dev, buf); - } - - return 0; -} - -/* - * Maps all of the DMA buffers into client-virtual space (ioctl). - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg pointer to a drm_buf_map structure. - * \return zero on success or a negative number on failure. - * - * Maps the AGP, SG or PCI buffer region with vm_mmap(), and copies information - * about each buffer into user space. For PCI buffers, it calls vm_mmap() with - * offset equal to 0, which drm_mmap() interprets as PCI buffers and calls - * drm_mmap_dma(). - */ -int __drm_legacy_mapbufs(struct drm_device *dev, void *data, int *p, - void __user **v, - int (*f)(void *, int, unsigned long, - struct drm_buf *), - struct drm_file *file_priv) -{ - struct drm_device_dma *dma = dev->dma; - int retcode = 0; - unsigned long virtual; - int i; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA)) - return -EOPNOTSUPP; - - if (!dma) - return -EINVAL; - - spin_lock(&dev->buf_lock); - if (atomic_read(&dev->buf_alloc)) { - spin_unlock(&dev->buf_lock); - return -EBUSY; - } - dev->buf_use++; /* Can't allocate more after this call */ - spin_unlock(&dev->buf_lock); - - if (*p >= dma->buf_count) { - if ((dev->agp && (dma->flags & _DRM_DMA_USE_AGP)) - || (drm_core_check_feature(dev, DRIVER_SG) - && (dma->flags & _DRM_DMA_USE_SG))) { - struct drm_local_map *map = dev->agp_buffer_map; - unsigned long token = dev->agp_buffer_token; - - if (!map) { - retcode = -EINVAL; - goto done; - } - virtual = vm_mmap(file_priv->filp, 0, map->size, - PROT_READ | PROT_WRITE, - MAP_SHARED, - token); - } else { - virtual = vm_mmap(file_priv->filp, 0, dma->byte_count, - PROT_READ | PROT_WRITE, - MAP_SHARED, 0); - } - if (virtual > -1024UL) { - /* Real error */ - retcode = (signed long)virtual; - goto done; - } - *v = (void __user *)virtual; - - for (i = 0; i < dma->buf_count; i++) { - if (f(data, i, virtual, dma->buflist[i]) < 0) { - retcode = -EFAULT; - goto done; - } - } - } - done: - *p = dma->buf_count; - DRM_DEBUG("%d buffers, retcode = %d\n", *p, retcode); - - return retcode; -} - -static int map_one_buf(void *data, int idx, unsigned long virtual, - struct drm_buf *buf) -{ - struct drm_buf_map *request = data; - unsigned long address = virtual + buf->offset; /* *** */ - - if (copy_to_user(&request->list[idx].idx, &buf->idx, - sizeof(request->list[0].idx))) - return -EFAULT; - if (copy_to_user(&request->list[idx].total, &buf->total, - sizeof(request->list[0].total))) - return -EFAULT; - if (clear_user(&request->list[idx].used, sizeof(int))) - return -EFAULT; - if (copy_to_user(&request->list[idx].address, &address, - sizeof(address))) - return -EFAULT; - return 0; -} - -int drm_legacy_mapbufs(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_buf_map *request = data; - - return __drm_legacy_mapbufs(dev, data, &request->count, - &request->virtual, map_one_buf, - file_priv); -} - -int drm_legacy_dma_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - if (dev->driver->dma_ioctl) - return dev->driver->dma_ioctl(dev, data, file_priv); - else - return -EINVAL; -} - -struct drm_local_map *drm_legacy_getsarea(struct drm_device *dev) -{ - struct drm_map_list *entry; - - list_for_each_entry(entry, &dev->maplist, head) { - if (entry->map && entry->map->type == _DRM_SHM && - (entry->map->flags & _DRM_CONTAINS_LOCK)) { - return entry->map; - } - } - return NULL; -} -EXPORT_SYMBOL(drm_legacy_getsarea); diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c index c3027115d05527..9403b3f576f7b8 100644 --- a/drivers/gpu/drm/drm_client.c +++ b/drivers/gpu/drm/drm_client.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include @@ -84,16 +83,13 @@ int drm_client_init(struct drm_device *dev, struct drm_client_dev *client, if (!drm_core_check_feature(dev, DRIVER_MODESET) || !dev->driver->dumb_create) return -EOPNOTSUPP; - if (funcs && !try_module_get(funcs->owner)) - return -ENODEV; - client->dev = dev; client->name = name; client->funcs = funcs; ret = drm_client_modeset_create(client); if (ret) - goto err_put_module; + return ret; ret = drm_client_open(client); if (ret) @@ -105,10 +101,6 @@ int drm_client_init(struct drm_device *dev, struct drm_client_dev *client, err_free: drm_client_modeset_free(client); -err_put_module: - if (funcs) - module_put(funcs->owner); - return ret; } EXPORT_SYMBOL(drm_client_init); @@ -177,8 +169,6 @@ void drm_client_release(struct drm_client_dev *client) drm_client_modeset_free(client); drm_client_close(client); drm_dev_put(dev); - if (client->funcs) - module_put(client->funcs->owner); } EXPORT_SYMBOL(drm_client_release); diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index c3725086f41325..b0516505f7ae92 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -1198,6 +1198,12 @@ static const u32 dp_colorspaces = * drm_connector_set_path_property(), in the case of DP MST with the * path property the MST manager created. Userspace cannot change this * property. + * + * In the case of DP MST, the property has the format + * ``mst:-`` where ```` is the KMS object ID of the + * parent connector and ```` is a hyphen-separated list of DP MST + * port numbers. Note, KMS object IDs are not guaranteed to be stable + * across reboots. * TILE: * Connector tile group property to indicate how a set of DRM connector * compose together into one logical screen. This is used by both high-res diff --git a/drivers/gpu/drm/drm_context.c b/drivers/gpu/drm/drm_context.c deleted file mode 100644 index a0fc779e5e1e8a..00000000000000 --- a/drivers/gpu/drm/drm_context.c +++ /dev/null @@ -1,513 +0,0 @@ -/* - * Legacy: Generic DRM Contexts - * - * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * All Rights Reserved. - * - * Author: Rickard E. (Rik) Faith - * Author: Gareth Hughes - * - * 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. - */ - -#include -#include - -#include -#include -#include - -#include "drm_legacy.h" - -struct drm_ctx_list { - struct list_head head; - drm_context_t handle; - struct drm_file *tag; -}; - -/******************************************************************/ -/** \name Context bitmap support */ -/*@{*/ - -/* - * Free a handle from the context bitmap. - * - * \param dev DRM device. - * \param ctx_handle context handle. - * - * Clears the bit specified by \p ctx_handle in drm_device::ctx_bitmap and the entry - * in drm_device::ctx_idr, while holding the drm_device::struct_mutex - * lock. - */ -void drm_legacy_ctxbitmap_free(struct drm_device * dev, int ctx_handle) -{ - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return; - - mutex_lock(&dev->struct_mutex); - idr_remove(&dev->ctx_idr, ctx_handle); - mutex_unlock(&dev->struct_mutex); -} - -/* - * Context bitmap allocation. - * - * \param dev DRM device. - * \return (non-negative) context handle on success or a negative number on failure. - * - * Allocate a new idr from drm_device::ctx_idr while holding the - * drm_device::struct_mutex lock. - */ -static int drm_legacy_ctxbitmap_next(struct drm_device * dev) -{ - int ret; - - mutex_lock(&dev->struct_mutex); - ret = idr_alloc(&dev->ctx_idr, NULL, DRM_RESERVED_CONTEXTS, 0, - GFP_KERNEL); - mutex_unlock(&dev->struct_mutex); - return ret; -} - -/* - * Context bitmap initialization. - * - * \param dev DRM device. - * - * Initialise the drm_device::ctx_idr - */ -void drm_legacy_ctxbitmap_init(struct drm_device * dev) -{ - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return; - - idr_init(&dev->ctx_idr); -} - -/* - * Context bitmap cleanup. - * - * \param dev DRM device. - * - * Free all idr members using drm_ctx_sarea_free helper function - * while holding the drm_device::struct_mutex lock. - */ -void drm_legacy_ctxbitmap_cleanup(struct drm_device * dev) -{ - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return; - - mutex_lock(&dev->struct_mutex); - idr_destroy(&dev->ctx_idr); - mutex_unlock(&dev->struct_mutex); -} - -/** - * drm_legacy_ctxbitmap_flush() - Flush all contexts owned by a file - * @dev: DRM device to operate on - * @file: Open file to flush contexts for - * - * This iterates over all contexts on @dev and drops them if they're owned by - * @file. Note that after this call returns, new contexts might be added if - * the file is still alive. - */ -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_LEGACY)) - return; - - mutex_lock(&dev->ctxlist_mutex); - - list_for_each_entry_safe(pos, tmp, &dev->ctxlist, head) { - if (pos->tag == file && - pos->handle != DRM_KERNEL_CONTEXT) { - if (dev->driver->context_dtor) - dev->driver->context_dtor(dev, pos->handle); - - drm_legacy_ctxbitmap_free(dev, pos->handle); - list_del(&pos->head); - kfree(pos); - } - } - - mutex_unlock(&dev->ctxlist_mutex); -} - -/*@}*/ - -/******************************************************************/ -/** \name Per Context SAREA Support */ -/*@{*/ - -/* - * Get per-context SAREA. - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg user argument pointing to a drm_ctx_priv_map structure. - * \return zero on success or a negative number on failure. - * - * Gets the map from drm_device::ctx_idr with the handle specified and - * returns its handle. - */ -int drm_legacy_getsareactx(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_ctx_priv_map *request = data; - struct drm_local_map *map; - struct drm_map_list *_entry; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - mutex_lock(&dev->struct_mutex); - - map = idr_find(&dev->ctx_idr, request->ctx_id); - if (!map) { - mutex_unlock(&dev->struct_mutex); - return -EINVAL; - } - - request->handle = NULL; - list_for_each_entry(_entry, &dev->maplist, head) { - if (_entry->map == map) { - request->handle = - (void *)(unsigned long)_entry->user_token; - break; - } - } - - mutex_unlock(&dev->struct_mutex); - - if (request->handle == NULL) - return -EINVAL; - - return 0; -} - -/* - * Set per-context SAREA. - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg user argument pointing to a drm_ctx_priv_map structure. - * \return zero on success or a negative number on failure. - * - * Searches the mapping specified in \p arg and update the entry in - * drm_device::ctx_idr with it. - */ -int drm_legacy_setsareactx(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_ctx_priv_map *request = data; - struct drm_local_map *map = NULL; - struct drm_map_list *r_list = NULL; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - mutex_lock(&dev->struct_mutex); - list_for_each_entry(r_list, &dev->maplist, head) { - if (r_list->map - && r_list->user_token == (unsigned long) request->handle) - goto found; - } - bad: - mutex_unlock(&dev->struct_mutex); - return -EINVAL; - - found: - map = r_list->map; - if (!map) - goto bad; - - if (IS_ERR(idr_replace(&dev->ctx_idr, map, request->ctx_id))) - goto bad; - - mutex_unlock(&dev->struct_mutex); - - return 0; -} - -/*@}*/ - -/******************************************************************/ -/** \name The actual DRM context handling routines */ -/*@{*/ - -/* - * Switch context. - * - * \param dev DRM device. - * \param old old context handle. - * \param new new context handle. - * \return zero on success or a negative number on failure. - * - * Attempt to set drm_device::context_flag. - */ -static int drm_context_switch(struct drm_device * dev, int old, int new) -{ - if (test_and_set_bit(0, &dev->context_flag)) { - DRM_ERROR("Reentering -- FIXME\n"); - return -EBUSY; - } - - DRM_DEBUG("Context switch from %d to %d\n", old, new); - - if (new == dev->last_context) { - clear_bit(0, &dev->context_flag); - return 0; - } - - return 0; -} - -/* - * Complete context switch. - * - * \param dev DRM device. - * \param new new context handle. - * \return zero on success or a negative number on failure. - * - * Updates drm_device::last_context and drm_device::last_switch. Verifies the - * hardware lock is held, clears the drm_device::context_flag and wakes up - * drm_device::context_wait. - */ -static int drm_context_switch_complete(struct drm_device *dev, - struct drm_file *file_priv, int new) -{ - dev->last_context = new; /* PRE/POST: This is the _only_ writer. */ - - if (!_DRM_LOCK_IS_HELD(file_priv->master->lock.hw_lock->lock)) { - DRM_ERROR("Lock isn't held after context switch\n"); - } - - /* If a context switch is ever initiated - when the kernel holds the lock, release - that lock here. - */ - clear_bit(0, &dev->context_flag); - - return 0; -} - -/* - * Reserve contexts. - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg user argument pointing to a drm_ctx_res structure. - * \return zero on success or a negative number on failure. - */ -int drm_legacy_resctx(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_ctx_res *res = data; - struct drm_ctx ctx; - int i; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - if (res->count >= DRM_RESERVED_CONTEXTS) { - memset(&ctx, 0, sizeof(ctx)); - for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { - ctx.handle = i; - if (copy_to_user(&res->contexts[i], &ctx, sizeof(ctx))) - return -EFAULT; - } - } - res->count = DRM_RESERVED_CONTEXTS; - - return 0; -} - -/* - * Add context. - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg user argument pointing to a drm_ctx structure. - * \return zero on success or a negative number on failure. - * - * Get a new handle for the context and copy to userspace. - */ -int drm_legacy_addctx(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_ctx_list *ctx_entry; - struct drm_ctx *ctx = data; - int tmp_handle; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - tmp_handle = drm_legacy_ctxbitmap_next(dev); - if (tmp_handle == DRM_KERNEL_CONTEXT) { - /* Skip kernel's context and get a new one. */ - tmp_handle = drm_legacy_ctxbitmap_next(dev); - } - DRM_DEBUG("%d\n", tmp_handle); - if (tmp_handle < 0) { - DRM_DEBUG("Not enough free contexts.\n"); - /* Should this return -EBUSY instead? */ - return tmp_handle; - } - - ctx->handle = tmp_handle; - - ctx_entry = kmalloc(sizeof(*ctx_entry), GFP_KERNEL); - if (!ctx_entry) { - DRM_DEBUG("out of memory\n"); - return -ENOMEM; - } - - INIT_LIST_HEAD(&ctx_entry->head); - ctx_entry->handle = ctx->handle; - ctx_entry->tag = file_priv; - - mutex_lock(&dev->ctxlist_mutex); - list_add(&ctx_entry->head, &dev->ctxlist); - mutex_unlock(&dev->ctxlist_mutex); - - return 0; -} - -/* - * Get context. - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg user argument pointing to a drm_ctx structure. - * \return zero on success or a negative number on failure. - */ -int drm_legacy_getctx(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_ctx *ctx = data; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - /* This is 0, because we don't handle any context flags */ - ctx->flags = 0; - - return 0; -} - -/* - * Switch context. - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg user argument pointing to a drm_ctx structure. - * \return zero on success or a negative number on failure. - * - * Calls context_switch(). - */ -int drm_legacy_switchctx(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_ctx *ctx = data; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - DRM_DEBUG("%d\n", ctx->handle); - return drm_context_switch(dev, dev->last_context, ctx->handle); -} - -/* - * New context. - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg user argument pointing to a drm_ctx structure. - * \return zero on success or a negative number on failure. - * - * Calls context_switch_complete(). - */ -int drm_legacy_newctx(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_ctx *ctx = data; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - DRM_DEBUG("%d\n", ctx->handle); - drm_context_switch_complete(dev, file_priv, ctx->handle); - - return 0; -} - -/* - * Remove context. - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg user argument pointing to a drm_ctx structure. - * \return zero on success or a negative number on failure. - * - * If not the special kernel context, calls ctxbitmap_free() to free the specified context. - */ -int drm_legacy_rmctx(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_ctx *ctx = data; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - DRM_DEBUG("%d\n", ctx->handle); - if (ctx->handle != DRM_KERNEL_CONTEXT) { - if (dev->driver->context_dtor) - dev->driver->context_dtor(dev, ctx->handle); - drm_legacy_ctxbitmap_free(dev, ctx->handle); - } - - mutex_lock(&dev->ctxlist_mutex); - if (!list_empty(&dev->ctxlist)) { - struct drm_ctx_list *pos, *n; - - list_for_each_entry_safe(pos, n, &dev->ctxlist, head) { - if (pos->handle == ctx->handle) { - list_del(&pos->head); - kfree(pos); - } - } - } - mutex_unlock(&dev->ctxlist_mutex); - - return 0; -} - -/*@}*/ diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index a209659a996c74..2dafc39a27cb93 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -439,11 +439,8 @@ EXPORT_SYMBOL(drm_crtc_helper_set_mode); * @state: atomic state object * * Provides a default CRTC-state check handler for CRTCs that only have - * one primary plane attached to it. - * - * This is often the case for the CRTC of simple framebuffers. See also - * drm_plane_helper_atomic_check() for the respective plane-state check - * helper function. + * one primary plane attached to it. This is often the case for the CRTC + * of simple framebuffers. * * RETURNS: * Zero on success, or an errno code otherwise. diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h index 8556c3b3ff88ac..a514d5207e4197 100644 --- a/drivers/gpu/drm/drm_crtc_internal.h +++ b/drivers/gpu/drm/drm_crtc_internal.h @@ -222,6 +222,8 @@ int drm_mode_addfb2_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_mode_rmfb_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); +int drm_mode_closefb_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv); int drm_mode_getfb(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_mode_getfb2_ioctl(struct drm_device *dev, @@ -251,7 +253,7 @@ int drm_atomic_set_property(struct drm_atomic_state *state, struct drm_file *file_priv, struct drm_mode_object *obj, struct drm_property *prop, - uint64_t prop_value); + u64 prop_value, bool async_flip); int drm_atomic_get_property(struct drm_mode_object *obj, struct drm_property *property, uint64_t *val); diff --git a/drivers/gpu/drm/drm_damage_helper.c b/drivers/gpu/drm/drm_damage_helper.c index d8b2955e88fd0a..afb02aae707b4f 100644 --- a/drivers/gpu/drm/drm_damage_helper.c +++ b/drivers/gpu/drm/drm_damage_helper.c @@ -241,7 +241,8 @@ drm_atomic_helper_damage_iter_init(struct drm_atomic_helper_damage_iter *iter, iter->plane_src.x2 = (src.x2 >> 16) + !!(src.x2 & 0xFFFF); iter->plane_src.y2 = (src.y2 >> 16) + !!(src.y2 & 0xFFFF); - if (!iter->clips || !drm_rect_equals(&state->src, &old_state->src)) { + if (!iter->clips || state->ignore_damage_clips || + !drm_rect_equals(&state->src, &old_state->src)) { iter->clips = NULL; iter->num_clips = 0; iter->full_update = true; diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index f291fb4b359fdf..f4715a67e340d3 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -314,10 +314,8 @@ void drm_debugfs_dev_register(struct drm_device *dev) drm_framebuffer_debugfs_init(dev); drm_client_debugfs_init(dev); } - if (drm_drv_uses_atomic_modeset(dev)) { + if (drm_drv_uses_atomic_modeset(dev)) drm_atomic_debugfs_init(dev); - drm_bridge_debugfs_init(dev); - } } int drm_debugfs_register(struct drm_minor *minor, int minor_id, @@ -589,4 +587,65 @@ void drm_debugfs_crtc_remove(struct drm_crtc *crtc) crtc->debugfs_entry = NULL; } +static int bridges_show(struct seq_file *m, void *data) +{ + struct drm_encoder *encoder = m->private; + struct drm_printer p = drm_seq_file_printer(m); + struct drm_bridge *bridge; + unsigned int idx = 0; + + drm_for_each_bridge_in_chain(encoder, bridge) { + drm_printf(&p, "bridge[%d]: %ps\n", idx++, bridge->funcs); + drm_printf(&p, "\ttype: [%d] %s\n", + bridge->type, + drm_get_connector_type_name(bridge->type)); +#ifdef CONFIG_OF + if (bridge->of_node) + drm_printf(&p, "\tOF: %pOFfc\n", bridge->of_node); +#endif + drm_printf(&p, "\tops: [0x%x]", bridge->ops); + if (bridge->ops & DRM_BRIDGE_OP_DETECT) + drm_puts(&p, " detect"); + if (bridge->ops & DRM_BRIDGE_OP_EDID) + drm_puts(&p, " edid"); + if (bridge->ops & DRM_BRIDGE_OP_HPD) + drm_puts(&p, " hpd"); + if (bridge->ops & DRM_BRIDGE_OP_MODES) + drm_puts(&p, " modes"); + drm_puts(&p, "\n"); + } + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(bridges); + +void drm_debugfs_encoder_add(struct drm_encoder *encoder) +{ + struct drm_minor *minor = encoder->dev->primary; + struct dentry *root; + char *name; + + name = kasprintf(GFP_KERNEL, "encoder-%d", encoder->index); + if (!name) + return; + + root = debugfs_create_dir(name, minor->debugfs_root); + kfree(name); + + encoder->debugfs_entry = root; + + /* bridges list */ + debugfs_create_file("bridges", 0444, root, encoder, + &bridges_fops); + + if (encoder->funcs && encoder->funcs->debugfs_init) + encoder->funcs->debugfs_init(encoder, root); +} + +void drm_debugfs_encoder_remove(struct drm_encoder *encoder) +{ + debugfs_remove_recursive(encoder->debugfs_entry); + encoder->debugfs_entry = NULL; +} + #endif /* CONFIG_DEBUG_FS */ diff --git a/drivers/gpu/drm/drm_dma.c b/drivers/gpu/drm/drm_dma.c deleted file mode 100644 index eb6b741a6f995d..00000000000000 --- a/drivers/gpu/drm/drm_dma.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * \file drm_dma.c - * DMA IOCTL and function support - * - * \author Rickard E. (Rik) Faith - * \author Gareth Hughes - */ - -/* - * Created: Fri Mar 19 14:30:16 1999 by faith@valinux.com - * - * Copyright 1999, 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 - * 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. - */ - -#include -#include - -#include -#include - -#include "drm_legacy.h" - -/** - * drm_legacy_dma_setup() - Initialize the DMA data. - * - * @dev: DRM device. - * Return: zero on success or a negative value on failure. - * - * Allocate and initialize a drm_device_dma structure. - */ -int drm_legacy_dma_setup(struct drm_device *dev) -{ - int i; - - if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA) || - !drm_core_check_feature(dev, DRIVER_LEGACY)) - return 0; - - dev->buf_use = 0; - atomic_set(&dev->buf_alloc, 0); - - dev->dma = kzalloc(sizeof(*dev->dma), GFP_KERNEL); - if (!dev->dma) - return -ENOMEM; - - for (i = 0; i <= DRM_MAX_ORDER; i++) - memset(&dev->dma->bufs[i], 0, sizeof(dev->dma->bufs[0])); - - return 0; -} - -/** - * drm_legacy_dma_takedown() - Cleanup the DMA resources. - * - * @dev: DRM device. - * - * Free all pages associated with DMA buffers, the buffers and pages lists, and - * finally the drm_device::dma structure itself. - */ -void drm_legacy_dma_takedown(struct drm_device *dev) -{ - struct drm_device_dma *dma = dev->dma; - drm_dma_handle_t *dmah; - int i, j; - - if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA) || - !drm_core_check_feature(dev, DRIVER_LEGACY)) - return; - - if (!dma) - return; - - /* Clear dma buffers */ - for (i = 0; i <= DRM_MAX_ORDER; i++) { - if (dma->bufs[i].seg_count) { - DRM_DEBUG("order %d: buf_count = %d," - " seg_count = %d\n", - i, - dma->bufs[i].buf_count, - dma->bufs[i].seg_count); - for (j = 0; j < dma->bufs[i].seg_count; j++) { - if (dma->bufs[i].seglist[j]) { - dmah = dma->bufs[i].seglist[j]; - dma_free_coherent(dev->dev, - dmah->size, - dmah->vaddr, - dmah->busaddr); - kfree(dmah); - } - } - kfree(dma->bufs[i].seglist); - } - if (dma->bufs[i].buf_count) { - for (j = 0; j < dma->bufs[i].buf_count; j++) { - kfree(dma->bufs[i].buflist[j].dev_private); - } - kfree(dma->bufs[i].buflist); - } - } - - kfree(dma->buflist); - kfree(dma->pagelist); - kfree(dev->dma); - dev->dma = NULL; -} - -/** - * drm_legacy_free_buffer() - Free a buffer. - * - * @dev: DRM device. - * @buf: buffer to free. - * - * Resets the fields of \p buf. - */ -void drm_legacy_free_buffer(struct drm_device *dev, struct drm_buf * buf) -{ - if (!buf) - return; - - buf->waiting = 0; - buf->pending = 0; - buf->file_priv = NULL; - buf->used = 0; -} - -/** - * drm_legacy_reclaim_buffers() - Reclaim the buffers. - * - * @dev: DRM device. - * @file_priv: DRM file private. - * - * Frees each buffer associated with \p file_priv not already on the hardware. - */ -void drm_legacy_reclaim_buffers(struct drm_device *dev, - struct drm_file *file_priv) -{ - struct drm_device_dma *dma = dev->dma; - int i; - - if (!dma) - return; - for (i = 0; i < dma->buf_count; i++) { - if (dma->buflist[i]->file_priv == file_priv) { - switch (dma->buflist[i]->list) { - case DRM_LIST_NONE: - drm_legacy_free_buffer(dev, dma->buflist[i]); - break; - case DRM_LIST_WAIT: - dma->buflist[i]->list = DRM_LIST_RECLAIM; - break; - default: - /* Buffer already on hardware. */ - break; - } - } - } -} diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 535f16e7882e70..243cacb3575c08 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -48,7 +48,6 @@ #include "drm_crtc_internal.h" #include "drm_internal.h" -#include "drm_legacy.h" MODULE_AUTHOR("Gareth Hughes, Leif Delgass, José Fonseca, Jon Smirl"); MODULE_DESCRIPTION("DRM shared core routines"); @@ -585,8 +584,6 @@ static void drm_fs_inode_free(struct inode *inode) static void drm_dev_init_release(struct drm_device *dev, void *res) { - drm_legacy_ctxbitmap_cleanup(dev); - drm_legacy_remove_map_hash(dev); drm_fs_inode_free(dev->anon_inode); put_device(dev->dev); @@ -597,7 +594,6 @@ 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); - drm_legacy_destroy_members(dev); } static int drm_dev_init(struct drm_device *dev, @@ -632,7 +628,6 @@ static int drm_dev_init(struct drm_device *dev, return -EINVAL; } - drm_legacy_init_members(dev); INIT_LIST_HEAD(&dev->filelist); INIT_LIST_HEAD(&dev->filelist_internal); INIT_LIST_HEAD(&dev->clientlist); @@ -673,12 +668,6 @@ static int drm_dev_init(struct drm_device *dev, goto err; } - ret = drm_legacy_create_map_hash(dev); - if (ret) - goto err; - - drm_legacy_ctxbitmap_init(dev); - if (drm_core_check_feature(dev, DRIVER_GEM)) { ret = drm_gem_init(dev); if (ret) { @@ -949,8 +938,11 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags) goto err_minors; } - if (drm_core_check_feature(dev, DRIVER_MODESET)) - drm_modeset_register_all(dev); + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + ret = drm_modeset_register_all(dev); + if (ret) + goto err_unload; + } DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n", driver->name, driver->major, driver->minor, @@ -960,6 +952,9 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags) goto out_unlock; +err_unload: + if (dev->driver->unload) + dev->driver->unload(dev); err_minors: remove_compat_control_link(dev); drm_minor_unregister(dev, DRM_MINOR_ACCEL); @@ -990,9 +985,6 @@ EXPORT_SYMBOL(drm_dev_register); */ void drm_dev_unregister(struct drm_device *dev) { - if (drm_core_check_feature(dev, DRIVER_LEGACY)) - drm_lastclose(dev); - dev->registered = false; drm_client_dev_unregister(dev); @@ -1003,9 +995,6 @@ void drm_dev_unregister(struct drm_device *dev) if (dev->driver->unload) dev->driver->unload(dev); - drm_legacy_pci_agp_destroy(dev); - drm_legacy_rmmaps(dev); - remove_compat_control_link(dev); drm_minor_unregister(dev, DRM_MINOR_ACCEL); drm_minor_unregister(dev, DRM_MINOR_PRIMARY); diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 3b40650998728c..69c68804023ff9 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -41,10 +41,12 @@ #include #include #include +#include #include #include #include "drm_crtc_internal.h" +#include "drm_internal.h" static int oui(u8 first, u8 second, u8 third) { @@ -5510,6 +5512,27 @@ static void clear_eld(struct drm_connector *connector) connector->audio_latency[1] = 0; } +/* + * Get 3-byte SAD buffer from struct cea_sad. + */ +void drm_edid_cta_sad_get(const struct cea_sad *cta_sad, u8 *sad) +{ + sad[0] = cta_sad->format << 3 | cta_sad->channels; + sad[1] = cta_sad->freq; + sad[2] = cta_sad->byte2; +} + +/* + * Set struct cea_sad from 3-byte SAD buffer. + */ +void drm_edid_cta_sad_set(struct cea_sad *cta_sad, const u8 *sad) +{ + cta_sad->format = (sad[0] & 0x78) >> 3; + cta_sad->channels = sad[0] & 0x07; + cta_sad->freq = sad[1] & 0x7f; + cta_sad->byte2 = sad[2]; +} + /* * drm_edid_to_eld - build ELD from EDID * @connector: connector corresponding to the HDMI/DP sink @@ -5594,7 +5617,7 @@ static void drm_edid_to_eld(struct drm_connector *connector, } static int _drm_edid_to_sad(const struct drm_edid *drm_edid, - struct cea_sad **sads) + struct cea_sad **psads) { const struct cea_db *db; struct cea_db_iter iter; @@ -5603,20 +5626,16 @@ static int _drm_edid_to_sad(const struct drm_edid *drm_edid, cea_db_iter_edid_begin(drm_edid, &iter); cea_db_iter_for_each(db, &iter) { if (cea_db_tag(db) == CTA_DB_AUDIO) { - int j; + struct cea_sad *sads; + int i; count = cea_db_payload_len(db) / 3; /* SAD is 3B */ - *sads = kcalloc(count, sizeof(**sads), GFP_KERNEL); - if (!*sads) + sads = kcalloc(count, sizeof(*sads), GFP_KERNEL); + *psads = sads; + if (!sads) return -ENOMEM; - for (j = 0; j < count; j++) { - const u8 *sad = &db->data[j * 3]; - - (*sads)[j].format = (sad[0] & 0x78) >> 3; - (*sads)[j].channels = sad[0] & 0x7; - (*sads)[j].freq = sad[1] & 0x7F; - (*sads)[j].byte2 = sad[2]; - } + for (i = 0; i < count; i++) + drm_edid_cta_sad_set(&sads[i], &db->data[i * 3]); break; } } diff --git a/drivers/gpu/drm/drm_edid_load.c b/drivers/gpu/drm/drm_edid_load.c index 5d9ef267ebb3cc..60fcb80bce61ef 100644 --- a/drivers/gpu/drm/drm_edid_load.c +++ b/drivers/gpu/drm/drm_edid_load.c @@ -23,22 +23,6 @@ module_param_string(edid_firmware, edid_firmware, sizeof(edid_firmware), 0644); MODULE_PARM_DESC(edid_firmware, "Do not probe monitor, use specified EDID blob " "from built-in data or /lib/firmware instead. "); -/* Use only for backward compatibility with drm_kms_helper.edid_firmware */ -int __drm_set_edid_firmware_path(const char *path) -{ - scnprintf(edid_firmware, sizeof(edid_firmware), "%s", path); - - return 0; -} -EXPORT_SYMBOL(__drm_set_edid_firmware_path); - -/* Use only for backward compatibility with drm_kms_helper.edid_firmware */ -int __drm_get_edid_firmware_path(char *buf, size_t bufsize) -{ - return scnprintf(buf, bufsize, "%s", edid_firmware); -} -EXPORT_SYMBOL(__drm_get_edid_firmware_path); - #define GENERIC_EDIDS 6 static const char * const generic_edid_name[GENERIC_EDIDS] = { "edid/800x600.bin", diff --git a/drivers/gpu/drm/drm_eld.c b/drivers/gpu/drm/drm_eld.c new file mode 100644 index 00000000000000..5177991aa2726f --- /dev/null +++ b/drivers/gpu/drm/drm_eld.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2023 Intel Corporation + */ + +#include +#include + +#include "drm_internal.h" + +/** + * drm_eld_sad_get - get SAD from ELD to struct cea_sad + * @eld: ELD buffer + * @sad_index: SAD index + * @cta_sad: destination struct cea_sad + * + * @return: 0 on success, or negative on errors + */ +int drm_eld_sad_get(const u8 *eld, int sad_index, struct cea_sad *cta_sad) +{ + const u8 *sad; + + if (sad_index >= drm_eld_sad_count(eld)) + return -EINVAL; + + sad = eld + DRM_ELD_CEA_SAD(drm_eld_mnl(eld), sad_index); + + drm_edid_cta_sad_set(cta_sad, sad); + + return 0; +} +EXPORT_SYMBOL(drm_eld_sad_get); + +/** + * drm_eld_sad_set - set SAD to ELD from struct cea_sad + * @eld: ELD buffer + * @sad_index: SAD index + * @cta_sad: source struct cea_sad + * + * @return: 0 on success, or negative on errors + */ +int drm_eld_sad_set(u8 *eld, int sad_index, const struct cea_sad *cta_sad) +{ + u8 *sad; + + if (sad_index >= drm_eld_sad_count(eld)) + return -EINVAL; + + sad = eld + DRM_ELD_CEA_SAD(drm_eld_mnl(eld), sad_index); + + drm_edid_cta_sad_get(cta_sad, sad); + + return 0; +} +EXPORT_SYMBOL(drm_eld_sad_set); diff --git a/drivers/gpu/drm/drm_encoder.c b/drivers/gpu/drm/drm_encoder.c index 1143bc7f325227..8f2bc6a2848222 100644 --- a/drivers/gpu/drm/drm_encoder.c +++ b/drivers/gpu/drm/drm_encoder.c @@ -30,6 +30,7 @@ #include #include "drm_crtc_internal.h" +#include "drm_internal.h" /** * DOC: overview @@ -74,6 +75,8 @@ int drm_encoder_register_all(struct drm_device *dev) int ret = 0; drm_for_each_encoder(encoder, dev) { + drm_debugfs_encoder_add(encoder); + if (encoder->funcs && encoder->funcs->late_register) ret = encoder->funcs->late_register(encoder); if (ret) @@ -90,6 +93,7 @@ void drm_encoder_unregister_all(struct drm_device *dev) drm_for_each_encoder(encoder, dev) { if (encoder->funcs && encoder->funcs->early_unregister) encoder->funcs->early_unregister(encoder); + drm_debugfs_encoder_remove(encoder); } } diff --git a/drivers/gpu/drm/drm_exec.c b/drivers/gpu/drm/drm_exec.c index 5d2809de4517ca..48ee851b61d904 100644 --- a/drivers/gpu/drm/drm_exec.c +++ b/drivers/gpu/drm/drm_exec.c @@ -69,16 +69,23 @@ static void drm_exec_unlock_all(struct drm_exec *exec) * drm_exec_init - initialize a drm_exec object * @exec: the drm_exec object to initialize * @flags: controls locking behavior, see DRM_EXEC_* defines + * @nr: the initial # of objects * * Initialize the object and make sure that we can track locked objects. + * + * If nr is non-zero then it is used as the initial objects table size. + * In either case, the table will grow (be re-allocated) on demand. */ -void drm_exec_init(struct drm_exec *exec, uint32_t flags) +void drm_exec_init(struct drm_exec *exec, uint32_t flags, unsigned nr) { + if (!nr) + nr = PAGE_SIZE / sizeof(void *); + exec->flags = flags; - exec->objects = kmalloc(PAGE_SIZE, GFP_KERNEL); + exec->objects = kvmalloc_array(nr, sizeof(void *), GFP_KERNEL); /* If allocation here fails, just delay that till the first use */ - exec->max_objects = exec->objects ? PAGE_SIZE / sizeof(void *) : 0; + exec->max_objects = exec->objects ? nr : 0; exec->num_objects = 0; exec->contended = DRM_EXEC_DUMMY; exec->prelocked = NULL; diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c index 446458aca8e99d..8c87287c3e1680 100644 --- a/drivers/gpu/drm/drm_file.c +++ b/drivers/gpu/drm/drm_file.c @@ -47,21 +47,12 @@ #include "drm_crtc_internal.h" #include "drm_internal.h" -#include "drm_legacy.h" /* from BKL pushdown */ DEFINE_MUTEX(drm_global_mutex); bool drm_dev_needs_global_mutex(struct drm_device *dev) { - /* - * Legacy drivers rely on all kinds of BKL locking semantics, don't - * bother. They also still need BKL locking for their ioctls, so better - * safe than sorry. - */ - if (drm_core_check_feature(dev, DRIVER_LEGACY)) - return true; - /* * The deprecated ->load callback must be called after the driver is * already registered. This means such drivers rely on the BKL to make @@ -107,9 +98,7 @@ bool drm_dev_needs_global_mutex(struct drm_device *dev) * drm_send_event() as the main starting points. * * The memory mapping implementation will vary depending on how the driver - * manages memory. Legacy drivers will use the deprecated drm_legacy_mmap() - * function, modern drivers should use one of the provided memory-manager - * specific implementations. For GEM-based drivers this is drm_gem_mmap(). + * manages memory. For GEM-based drivers this is drm_gem_mmap(). * * No other file operations are supported by the DRM userspace API. Overall the * following is an example &file_operations structure:: @@ -254,18 +243,6 @@ void drm_file_free(struct drm_file *file) (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) && - dev->driver->preclose) - dev->driver->preclose(dev, file); -#endif - - if (drm_core_check_feature(dev, DRIVER_LEGACY)) - drm_legacy_lock_release(dev, file->filp); - - if (drm_core_check_feature(dev, DRIVER_HAVE_DMA)) - drm_legacy_reclaim_buffers(dev, file); - drm_events_release(file); if (drm_core_check_feature(dev, DRIVER_MODESET)) { @@ -279,8 +256,6 @@ void drm_file_free(struct drm_file *file) if (drm_core_check_feature(dev, DRIVER_GEM)) drm_gem_release(dev, file); - drm_legacy_ctxbitmap_flush(dev, file); - if (drm_is_primary_client(file)) drm_master_release(file); @@ -367,29 +342,6 @@ int drm_open_helper(struct file *filp, struct drm_minor *minor) list_add(&priv->lhead, &dev->filelist); mutex_unlock(&dev->filelist_mutex); -#ifdef CONFIG_DRM_LEGACY -#ifdef __alpha__ - /* - * Default the hose - */ - if (!dev->hose) { - struct pci_dev *pci_dev; - - pci_dev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, NULL); - if (pci_dev) { - dev->hose = pci_dev->sysdata; - pci_dev_put(pci_dev); - } - if (!dev->hose) { - struct pci_bus *b = list_entry(pci_root_buses.next, - struct pci_bus, node); - if (b) - dev->hose = b->sysdata; - } - } -#endif -#endif - return 0; } @@ -411,7 +363,6 @@ int drm_open(struct inode *inode, struct file *filp) struct drm_device *dev; struct drm_minor *minor; int retcode; - int need_setup = 0; minor = drm_minor_acquire(iminor(inode)); if (IS_ERR(minor)) @@ -421,8 +372,7 @@ int drm_open(struct inode *inode, struct file *filp) if (drm_dev_needs_global_mutex(dev)) mutex_lock(&drm_global_mutex); - if (!atomic_fetch_inc(&dev->open_count)) - need_setup = 1; + atomic_fetch_inc(&dev->open_count); /* share address_space across all char-devs of a single device */ filp->f_mapping = dev->anon_inode->i_mapping; @@ -430,13 +380,6 @@ int drm_open(struct inode *inode, struct file *filp) retcode = drm_open_helper(filp, minor); if (retcode) goto err_undo; - if (need_setup) { - retcode = drm_legacy_setup(dev); - if (retcode) { - drm_close_helper(filp); - goto err_undo; - } - } if (drm_dev_needs_global_mutex(dev)) mutex_unlock(&drm_global_mutex); @@ -460,9 +403,6 @@ void drm_lastclose(struct drm_device * dev) dev->driver->lastclose(dev); drm_dbg_core(dev, "driver lastclose completed\n"); - if (drm_core_check_feature(dev, DRIVER_LEGACY)) - drm_legacy_dev_reinit(dev); - drm_client_dev_restore(dev); } @@ -913,7 +853,7 @@ static void print_size(struct drm_printer *p, const char *stat, unsigned u; for (u = 0; u < ARRAY_SIZE(units) - 1; u++) { - if (sz < SZ_1K) + if (sz == 0 || !IS_ALIGNED(sz, SZ_1K)) break; sz = div_u64(sz, SZ_1K); } @@ -958,7 +898,7 @@ void drm_show_memory_stats(struct drm_printer *p, struct drm_file *file) { struct drm_gem_object *obj; struct drm_memory_stats status = {}; - enum drm_gem_object_status supported_status; + enum drm_gem_object_status supported_status = 0; int id; spin_lock(&file->table_lock); diff --git a/drivers/gpu/drm/drm_flip_work.c b/drivers/gpu/drm/drm_flip_work.c index 060b753881a279..8c6090a90d5641 100644 --- a/drivers/gpu/drm/drm_flip_work.c +++ b/drivers/gpu/drm/drm_flip_work.c @@ -27,14 +27,12 @@ #include #include -/** - * drm_flip_work_allocate_task - allocate a flip-work task - * @data: data associated to the task - * @flags: allocator flags - * - * Allocate a drm_flip_task object and attach private data to it. - */ -struct drm_flip_task *drm_flip_work_allocate_task(void *data, gfp_t flags) +struct drm_flip_task { + struct list_head node; + void *data; +}; + +static struct drm_flip_task *drm_flip_work_allocate_task(void *data, gfp_t flags) { struct drm_flip_task *task; @@ -44,18 +42,8 @@ struct drm_flip_task *drm_flip_work_allocate_task(void *data, gfp_t flags) return task; } -EXPORT_SYMBOL(drm_flip_work_allocate_task); -/** - * drm_flip_work_queue_task - queue a specific task - * @work: the flip-work - * @task: the task to handle - * - * Queues task, that will later be run (passed back to drm_flip_func_t - * func) on a work queue after drm_flip_work_commit() is called. - */ -void drm_flip_work_queue_task(struct drm_flip_work *work, - struct drm_flip_task *task) +static void drm_flip_work_queue_task(struct drm_flip_work *work, struct drm_flip_task *task) { unsigned long flags; @@ -63,7 +51,6 @@ void drm_flip_work_queue_task(struct drm_flip_work *work, list_add_tail(&task->node, &work->queued); spin_unlock_irqrestore(&work->lock, flags); } -EXPORT_SYMBOL(drm_flip_work_queue_task); /** * drm_flip_work_queue - queue work diff --git a/drivers/gpu/drm/drm_format_helper.c b/drivers/gpu/drm/drm_format_helper.c index f93a4efcee9097..b1be458ed4dda5 100644 --- a/drivers/gpu/drm/drm_format_helper.c +++ b/drivers/gpu/drm/drm_format_helper.c @@ -20,6 +20,97 @@ #include #include +/** + * drm_format_conv_state_init - Initialize format-conversion state + * @state: The state to initialize + * + * Clears all fields in struct drm_format_conv_state. The state will + * be empty with no preallocated resources. + */ +void drm_format_conv_state_init(struct drm_format_conv_state *state) +{ + state->tmp.mem = NULL; + state->tmp.size = 0; + state->tmp.preallocated = false; +} +EXPORT_SYMBOL(drm_format_conv_state_init); + +/** + * drm_format_conv_state_copy - Copy format-conversion state + * @state: Destination state + * @old_state: Source state + * + * Copies format-conversion state from @old_state to @state; except for + * temporary storage. + */ +void drm_format_conv_state_copy(struct drm_format_conv_state *state, + const struct drm_format_conv_state *old_state) +{ + /* + * So far, there's only temporary storage here, which we don't + * duplicate. Just clear the fields. + */ + state->tmp.mem = NULL; + state->tmp.size = 0; + state->tmp.preallocated = false; +} +EXPORT_SYMBOL(drm_format_conv_state_copy); + +/** + * drm_format_conv_state_reserve - Allocates storage for format conversion + * @state: The format-conversion state + * @new_size: The minimum allocation size + * @flags: Flags for kmalloc() + * + * Allocates at least @new_size bytes and returns a pointer to the memory + * range. After calling this function, previously returned memory blocks + * are invalid. It's best to collect all memory requirements of a format + * conversion and call this function once to allocate the range. + * + * Returns: + * A pointer to the allocated memory range, or NULL otherwise. + */ +void *drm_format_conv_state_reserve(struct drm_format_conv_state *state, + size_t new_size, gfp_t flags) +{ + void *mem; + + if (new_size <= state->tmp.size) + goto out; + else if (state->tmp.preallocated) + return NULL; + + mem = krealloc(state->tmp.mem, new_size, flags); + if (!mem) + return NULL; + + state->tmp.mem = mem; + state->tmp.size = new_size; + +out: + return state->tmp.mem; +} +EXPORT_SYMBOL(drm_format_conv_state_reserve); + +/** + * drm_format_conv_state_release - Releases an format-conversion storage + * @state: The format-conversion state + * + * Releases the memory range references by the format-conversion state. + * After this call, all pointers to the memory are invalid. Prefer + * drm_format_conv_state_init() for cleaning up and unloading a driver. + */ +void drm_format_conv_state_release(struct drm_format_conv_state *state) +{ + if (state->tmp.preallocated) + return; + + kfree(state->tmp.mem); + state->tmp.mem = NULL; + state->tmp.size = 0; +} +EXPORT_SYMBOL(drm_format_conv_state_release); + static unsigned int clip_offset(const struct drm_rect *clip, unsigned int pitch, unsigned int cpp) { return clip->y1 * pitch + clip->x1 * cpp; @@ -45,6 +136,7 @@ EXPORT_SYMBOL(drm_fb_clip_offset); static int __drm_fb_xfrm(void *dst, unsigned long dst_pitch, unsigned long dst_pixsize, const void *vaddr, const struct drm_framebuffer *fb, const struct drm_rect *clip, bool vaddr_cached_hint, + struct drm_format_conv_state *state, void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels)) { unsigned long linepixels = drm_rect_width(clip); @@ -60,7 +152,7 @@ static int __drm_fb_xfrm(void *dst, unsigned long dst_pitch, unsigned long dst_p * one line at a time. */ if (!vaddr_cached_hint) { - stmp = kmalloc(sbuf_len, GFP_KERNEL); + stmp = drm_format_conv_state_reserve(state, sbuf_len, GFP_KERNEL); if (!stmp) return -ENOMEM; } @@ -79,8 +171,6 @@ static int __drm_fb_xfrm(void *dst, unsigned long dst_pitch, unsigned long dst_p dst += dst_pitch; } - kfree(stmp); - return 0; } @@ -88,6 +178,7 @@ static int __drm_fb_xfrm(void *dst, unsigned long dst_pitch, unsigned long dst_p static int __drm_fb_xfrm_toio(void __iomem *dst, unsigned long dst_pitch, unsigned long dst_pixsize, const void *vaddr, const struct drm_framebuffer *fb, const struct drm_rect *clip, bool vaddr_cached_hint, + struct drm_format_conv_state *state, void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels)) { unsigned long linepixels = drm_rect_width(clip); @@ -101,9 +192,9 @@ static int __drm_fb_xfrm_toio(void __iomem *dst, unsigned long dst_pitch, unsign void *dbuf; if (vaddr_cached_hint) { - dbuf = kmalloc(dbuf_len, GFP_KERNEL); + dbuf = drm_format_conv_state_reserve(state, dbuf_len, GFP_KERNEL); } else { - dbuf = kmalloc(stmp_off + sbuf_len, GFP_KERNEL); + dbuf = drm_format_conv_state_reserve(state, stmp_off + sbuf_len, GFP_KERNEL); stmp = dbuf + stmp_off; } if (!dbuf) @@ -124,8 +215,6 @@ static int __drm_fb_xfrm_toio(void __iomem *dst, unsigned long dst_pitch, unsign dst += dst_pitch; } - kfree(dbuf); - return 0; } @@ -134,6 +223,7 @@ static int drm_fb_xfrm(struct iosys_map *dst, const unsigned int *dst_pitch, const u8 *dst_pixsize, const struct iosys_map *src, const struct drm_framebuffer *fb, const struct drm_rect *clip, bool vaddr_cached_hint, + struct drm_format_conv_state *state, void (*xfrm_line)(void *dbuf, const void *sbuf, unsigned int npixels)) { static const unsigned int default_dst_pitch[DRM_FORMAT_MAX_PLANES] = { @@ -146,10 +236,12 @@ static int drm_fb_xfrm(struct iosys_map *dst, /* TODO: handle src in I/O memory here */ if (dst[0].is_iomem) return __drm_fb_xfrm_toio(dst[0].vaddr_iomem, dst_pitch[0], dst_pixsize[0], - src[0].vaddr, fb, clip, vaddr_cached_hint, xfrm_line); + src[0].vaddr, fb, clip, vaddr_cached_hint, state, + xfrm_line); else return __drm_fb_xfrm(dst[0].vaddr, dst_pitch[0], dst_pixsize[0], - src[0].vaddr, fb, clip, vaddr_cached_hint, xfrm_line); + src[0].vaddr, fb, clip, vaddr_cached_hint, state, + xfrm_line); } /** @@ -235,6 +327,7 @@ static void drm_fb_swab32_line(void *dbuf, const void *sbuf, unsigned int pixels * @fb: DRM framebuffer * @clip: Clip rectangle area to copy * @cached: Source buffer is mapped cached (eg. not write-combined) + * @state: Transform and conversion state * * This function copies parts of a framebuffer to display memory and swaps per-pixel * bytes during the process. Destination and framebuffer formats must match. The @@ -249,7 +342,8 @@ static void drm_fb_swab32_line(void *dbuf, const void *sbuf, unsigned int pixels */ void drm_fb_swab(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip, bool cached) + const struct drm_rect *clip, bool cached, + struct drm_format_conv_state *state) { const struct drm_format_info *format = fb->format; u8 cpp = DIV_ROUND_UP(drm_format_info_bpp(format, 0), 8); @@ -268,7 +362,7 @@ void drm_fb_swab(struct iosys_map *dst, const unsigned int *dst_pitch, return; } - drm_fb_xfrm(dst, dst_pitch, &cpp, src, fb, clip, cached, swab_line); + drm_fb_xfrm(dst, dst_pitch, &cpp, src, fb, clip, cached, state, swab_line); } EXPORT_SYMBOL(drm_fb_swab); @@ -295,6 +389,7 @@ static void drm_fb_xrgb8888_to_rgb332_line(void *dbuf, const void *sbuf, unsigne * @src: Array of XRGB8888 source buffers * @fb: DRM framebuffer * @clip: Clip rectangle area to copy + * @state: Transform and conversion state * * This function copies parts of a framebuffer to display memory and converts the * color format during the process. Destination and framebuffer formats must match. The @@ -309,13 +404,13 @@ static void drm_fb_xrgb8888_to_rgb332_line(void *dbuf, const void *sbuf, unsigne */ void drm_fb_xrgb8888_to_rgb332(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip) + const struct drm_rect *clip, struct drm_format_conv_state *state) { static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 1, }; - drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, drm_fb_xrgb8888_to_rgb332_line); } EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb332); @@ -364,6 +459,7 @@ static void drm_fb_xrgb8888_to_rgb565_swab_line(void *dbuf, const void *sbuf, * @src: Array of XRGB8888 source buffer * @fb: DRM framebuffer * @clip: Clip rectangle area to copy + * @state: Transform and conversion state * @swab: Swap bytes * * This function copies parts of a framebuffer to display memory and converts the @@ -379,7 +475,8 @@ static void drm_fb_xrgb8888_to_rgb565_swab_line(void *dbuf, const void *sbuf, */ void drm_fb_xrgb8888_to_rgb565(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip, bool swab) + const struct drm_rect *clip, struct drm_format_conv_state *state, + bool swab) { static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 2, @@ -392,7 +489,7 @@ void drm_fb_xrgb8888_to_rgb565(struct iosys_map *dst, const unsigned int *dst_pi else xfrm_line = drm_fb_xrgb8888_to_rgb565_line; - drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, xfrm_line); + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, xfrm_line); } EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb565); @@ -421,6 +518,7 @@ static void drm_fb_xrgb8888_to_xrgb1555_line(void *dbuf, const void *sbuf, unsig * @src: Array of XRGB8888 source buffer * @fb: DRM framebuffer * @clip: Clip rectangle area to copy + * @state: Transform and conversion state * * This function copies parts of a framebuffer to display memory and converts * the color format during the process. The parameters @dst, @dst_pitch and @@ -436,13 +534,13 @@ static void drm_fb_xrgb8888_to_xrgb1555_line(void *dbuf, const void *sbuf, unsig */ 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) + const struct drm_rect *clip, struct drm_format_conv_state *state) { static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 2, }; - drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, drm_fb_xrgb8888_to_xrgb1555_line); } EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb1555); @@ -473,6 +571,7 @@ static void drm_fb_xrgb8888_to_argb1555_line(void *dbuf, const void *sbuf, unsig * @src: Array of XRGB8888 source buffer * @fb: DRM framebuffer * @clip: Clip rectangle area to copy + * @state: Transform and conversion state * * This function copies parts of a framebuffer to display memory and converts * the color format during the process. The parameters @dst, @dst_pitch and @@ -488,13 +587,13 @@ static void drm_fb_xrgb8888_to_argb1555_line(void *dbuf, const void *sbuf, unsig */ 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) + const struct drm_rect *clip, struct drm_format_conv_state *state) { static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 2, }; - drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, drm_fb_xrgb8888_to_argb1555_line); } EXPORT_SYMBOL(drm_fb_xrgb8888_to_argb1555); @@ -525,6 +624,7 @@ static void drm_fb_xrgb8888_to_rgba5551_line(void *dbuf, const void *sbuf, unsig * @src: Array of XRGB8888 source buffer * @fb: DRM framebuffer * @clip: Clip rectangle area to copy + * @state: Transform and conversion state * * This function copies parts of a framebuffer to display memory and converts * the color format during the process. The parameters @dst, @dst_pitch and @@ -540,13 +640,13 @@ static void drm_fb_xrgb8888_to_rgba5551_line(void *dbuf, const void *sbuf, unsig */ 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) + const struct drm_rect *clip, struct drm_format_conv_state *state) { static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 2, }; - drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, drm_fb_xrgb8888_to_rgba5551_line); } EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgba5551); @@ -575,6 +675,7 @@ static void drm_fb_xrgb8888_to_rgb888_line(void *dbuf, const void *sbuf, unsigne * @src: Array of XRGB8888 source buffers * @fb: DRM framebuffer * @clip: Clip rectangle area to copy + * @state: Transform and conversion state * * This function copies parts of a framebuffer to display memory and converts the * color format during the process. Destination and framebuffer formats must match. The @@ -590,13 +691,13 @@ static void drm_fb_xrgb8888_to_rgb888_line(void *dbuf, const void *sbuf, unsigne */ void drm_fb_xrgb8888_to_rgb888(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip) + const struct drm_rect *clip, struct drm_format_conv_state *state) { static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 3, }; - drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, drm_fb_xrgb8888_to_rgb888_line); } EXPORT_SYMBOL(drm_fb_xrgb8888_to_rgb888); @@ -623,6 +724,7 @@ static void drm_fb_xrgb8888_to_argb8888_line(void *dbuf, const void *sbuf, unsig * @src: Array of XRGB8888 source buffer * @fb: DRM framebuffer * @clip: Clip rectangle area to copy + * @state: Transform and conversion state * * 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 @@ -638,13 +740,13 @@ static void drm_fb_xrgb8888_to_argb8888_line(void *dbuf, const void *sbuf, unsig */ 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) + const struct drm_rect *clip, struct drm_format_conv_state *state) { static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 4, }; - drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, drm_fb_xrgb8888_to_argb8888_line); } EXPORT_SYMBOL(drm_fb_xrgb8888_to_argb8888); @@ -669,13 +771,14 @@ static void drm_fb_xrgb8888_to_abgr8888_line(void *dbuf, const void *sbuf, unsig 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) + const struct drm_rect *clip, + struct drm_format_conv_state *state) { static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 4, }; - drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, drm_fb_xrgb8888_to_abgr8888_line); } @@ -699,13 +802,14 @@ static void drm_fb_xrgb8888_to_xbgr8888_line(void *dbuf, const void *sbuf, unsig 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) + const struct drm_rect *clip, + struct drm_format_conv_state *state) { static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 4, }; - drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, drm_fb_xrgb8888_to_xbgr8888_line); } @@ -735,6 +839,7 @@ static void drm_fb_xrgb8888_to_xrgb2101010_line(void *dbuf, const void *sbuf, un * @src: Array of XRGB8888 source buffers * @fb: DRM framebuffer * @clip: Clip rectangle area to copy + * @state: Transform and conversion state * * This function copies parts of a framebuffer to display memory and converts the * color format during the process. Destination and framebuffer formats must match. The @@ -750,13 +855,14 @@ static void drm_fb_xrgb8888_to_xrgb2101010_line(void *dbuf, const void *sbuf, un */ void drm_fb_xrgb8888_to_xrgb2101010(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip) + const struct drm_rect *clip, + struct drm_format_conv_state *state) { static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 4, }; - drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, drm_fb_xrgb8888_to_xrgb2101010_line); } EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb2101010); @@ -788,6 +894,7 @@ static void drm_fb_xrgb8888_to_argb2101010_line(void *dbuf, const void *sbuf, un * @src: Array of XRGB8888 source buffers * @fb: DRM framebuffer * @clip: Clip rectangle area to copy + * @state: Transform and conversion state * * This function copies parts of a framebuffer to display memory and converts * the color format during the process. The parameters @dst, @dst_pitch and @@ -803,13 +910,14 @@ static void drm_fb_xrgb8888_to_argb2101010_line(void *dbuf, const void *sbuf, un */ 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) + const struct drm_rect *clip, + struct drm_format_conv_state *state) { static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 4, }; - drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, drm_fb_xrgb8888_to_argb2101010_line); } EXPORT_SYMBOL(drm_fb_xrgb8888_to_argb2101010); @@ -839,6 +947,7 @@ static void drm_fb_xrgb8888_to_gray8_line(void *dbuf, const void *sbuf, unsigned * @src: Array of XRGB8888 source buffers * @fb: DRM framebuffer * @clip: Clip rectangle area to copy + * @state: Transform and conversion state * * This function copies parts of a framebuffer to display memory and converts the * color format during the process. Destination and framebuffer formats must match. The @@ -858,13 +967,13 @@ static void drm_fb_xrgb8888_to_gray8_line(void *dbuf, const void *sbuf, unsigned */ void drm_fb_xrgb8888_to_gray8(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip) + const struct drm_rect *clip, struct drm_format_conv_state *state) { static const u8 dst_pixsize[DRM_FORMAT_MAX_PLANES] = { 1, }; - drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, + drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false, state, drm_fb_xrgb8888_to_gray8_line); } EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8); @@ -878,6 +987,7 @@ EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8); * @src: The framebuffer memory to copy from * @fb: The framebuffer to copy from * @clip: Clip rectangle area to copy + * @state: Transform and conversion state * * This function copies parts of a framebuffer to display memory. If the * formats of the display and the framebuffer mismatch, the blit function @@ -896,7 +1006,7 @@ EXPORT_SYMBOL(drm_fb_xrgb8888_to_gray8); */ int drm_fb_blit(struct iosys_map *dst, const unsigned int *dst_pitch, uint32_t dst_format, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip) + const struct drm_rect *clip, struct drm_format_conv_state *state) { uint32_t fb_format = fb->format->format; @@ -904,44 +1014,44 @@ int drm_fb_blit(struct iosys_map *dst, const unsigned int *dst_pitch, uint32_t d drm_fb_memcpy(dst, dst_pitch, src, fb, clip); return 0; } else if (fb_format == (dst_format | DRM_FORMAT_BIG_ENDIAN)) { - drm_fb_swab(dst, dst_pitch, src, fb, clip, false); + drm_fb_swab(dst, dst_pitch, src, fb, clip, false, state); return 0; } else if (fb_format == (dst_format & ~DRM_FORMAT_BIG_ENDIAN)) { - drm_fb_swab(dst, dst_pitch, src, fb, clip, false); + drm_fb_swab(dst, dst_pitch, src, fb, clip, false, state); 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); + drm_fb_xrgb8888_to_rgb565(dst, dst_pitch, src, fb, clip, state, false); return 0; } else if (dst_format == DRM_FORMAT_XRGB1555) { - drm_fb_xrgb8888_to_xrgb1555(dst, dst_pitch, src, fb, clip); + drm_fb_xrgb8888_to_xrgb1555(dst, dst_pitch, src, fb, clip, state); return 0; } else if (dst_format == DRM_FORMAT_ARGB1555) { - drm_fb_xrgb8888_to_argb1555(dst, dst_pitch, src, fb, clip); + drm_fb_xrgb8888_to_argb1555(dst, dst_pitch, src, fb, clip, state); return 0; } else if (dst_format == DRM_FORMAT_RGBA5551) { - drm_fb_xrgb8888_to_rgba5551(dst, dst_pitch, src, fb, clip); + drm_fb_xrgb8888_to_rgba5551(dst, dst_pitch, src, fb, clip, state); return 0; } else if (dst_format == DRM_FORMAT_RGB888) { - drm_fb_xrgb8888_to_rgb888(dst, dst_pitch, src, fb, clip); + drm_fb_xrgb8888_to_rgb888(dst, dst_pitch, src, fb, clip, state); return 0; } else if (dst_format == DRM_FORMAT_ARGB8888) { - drm_fb_xrgb8888_to_argb8888(dst, dst_pitch, src, fb, clip); + drm_fb_xrgb8888_to_argb8888(dst, dst_pitch, src, fb, clip, state); return 0; } else if (dst_format == DRM_FORMAT_XBGR8888) { - drm_fb_xrgb8888_to_xbgr8888(dst, dst_pitch, src, fb, clip); + drm_fb_xrgb8888_to_xbgr8888(dst, dst_pitch, src, fb, clip, state); return 0; } else if (dst_format == DRM_FORMAT_ABGR8888) { - drm_fb_xrgb8888_to_abgr8888(dst, dst_pitch, src, fb, clip); + drm_fb_xrgb8888_to_abgr8888(dst, dst_pitch, src, fb, clip, state); return 0; } else if (dst_format == DRM_FORMAT_XRGB2101010) { - drm_fb_xrgb8888_to_xrgb2101010(dst, dst_pitch, src, fb, clip); + drm_fb_xrgb8888_to_xrgb2101010(dst, dst_pitch, src, fb, clip, state); return 0; } else if (dst_format == DRM_FORMAT_ARGB2101010) { - drm_fb_xrgb8888_to_argb2101010(dst, dst_pitch, src, fb, clip); + drm_fb_xrgb8888_to_argb2101010(dst, dst_pitch, src, fb, clip, state); return 0; } else if (dst_format == DRM_FORMAT_BGRX8888) { - drm_fb_swab(dst, dst_pitch, src, fb, clip, false); + drm_fb_swab(dst, dst_pitch, src, fb, clip, false, state); return 0; } } @@ -978,6 +1088,7 @@ static void drm_fb_gray8_to_mono_line(void *dbuf, const void *sbuf, unsigned int * @src: Array of XRGB8888 source buffers * @fb: DRM framebuffer * @clip: Clip rectangle area to copy + * @state: Transform and conversion state * * This function copies parts of a framebuffer to display memory and converts the * color format during the process. Destination and framebuffer formats must match. The @@ -1002,7 +1113,7 @@ static void drm_fb_gray8_to_mono_line(void *dbuf, const void *sbuf, unsigned int */ void drm_fb_xrgb8888_to_mono(struct iosys_map *dst, const unsigned int *dst_pitch, const struct iosys_map *src, const struct drm_framebuffer *fb, - const struct drm_rect *clip) + const struct drm_rect *clip, struct drm_format_conv_state *state) { static const unsigned int default_dst_pitch[DRM_FORMAT_MAX_PLANES] = { 0, 0, 0, 0 @@ -1042,7 +1153,7 @@ void drm_fb_xrgb8888_to_mono(struct iosys_map *dst, const unsigned int *dst_pitc * Allocate a buffer to be used for both copying from the cma * memory and to store the intermediate grayscale line pixels. */ - src32 = kmalloc(len_src32 + linepixels, GFP_KERNEL); + src32 = drm_format_conv_state_reserve(state, len_src32 + linepixels, GFP_KERNEL); if (!src32) return; @@ -1056,8 +1167,6 @@ void drm_fb_xrgb8888_to_mono(struct iosys_map *dst, const unsigned int *dst_pitc vaddr += fb->pitches[0]; mono += dst_pitch_0; } - - kfree(src32); } EXPORT_SYMBOL(drm_fb_xrgb8888_to_mono); diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index d3ba0698b84b42..888aadb6a4acbb 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -394,6 +394,31 @@ static void drm_mode_rmfb_work_fn(struct work_struct *w) } } +static int drm_mode_closefb(struct drm_framebuffer *fb, + struct drm_file *file_priv) +{ + struct drm_framebuffer *fbl; + bool found = false; + + mutex_lock(&file_priv->fbs_lock); + list_for_each_entry(fbl, &file_priv->fbs, filp_head) + if (fb == fbl) + found = true; + + if (!found) { + mutex_unlock(&file_priv->fbs_lock); + return -ENOENT; + } + + list_del_init(&fb->filp_head); + mutex_unlock(&file_priv->fbs_lock); + + /* Drop the reference that was stored in the fbs list */ + drm_framebuffer_put(fb); + + return 0; +} + /** * drm_mode_rmfb - remove an FB from the configuration * @dev: drm device @@ -410,9 +435,8 @@ static void drm_mode_rmfb_work_fn(struct work_struct *w) int drm_mode_rmfb(struct drm_device *dev, u32 fb_id, struct drm_file *file_priv) { - struct drm_framebuffer *fb = NULL; - struct drm_framebuffer *fbl = NULL; - int found = 0; + struct drm_framebuffer *fb; + int ret; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EOPNOTSUPP; @@ -421,24 +445,13 @@ int drm_mode_rmfb(struct drm_device *dev, u32 fb_id, if (!fb) return -ENOENT; - mutex_lock(&file_priv->fbs_lock); - list_for_each_entry(fbl, &file_priv->fbs, filp_head) - if (fb == fbl) - found = 1; - if (!found) { - mutex_unlock(&file_priv->fbs_lock); - goto fail_unref; + ret = drm_mode_closefb(fb, file_priv); + if (ret != 0) { + drm_framebuffer_put(fb); + return ret; } - list_del_init(&fb->filp_head); - mutex_unlock(&file_priv->fbs_lock); - - /* drop the reference we picked up in framebuffer lookup */ - drm_framebuffer_put(fb); - /* - * we now own the reference that was stored in the fbs list - * * drm_framebuffer_remove may fail with -EINTR on pending signals, * so run this in a separate stack as there's no way to correctly * handle this after the fb is already removed from the lookup table. @@ -448,6 +461,7 @@ int drm_mode_rmfb(struct drm_device *dev, u32 fb_id, INIT_WORK_ONSTACK(&arg.work, drm_mode_rmfb_work_fn); INIT_LIST_HEAD(&arg.fbs); + drm_WARN_ON(dev, !list_empty(&fb->filp_head)); list_add_tail(&fb->filp_head, &arg.fbs); schedule_work(&arg.work); @@ -457,10 +471,6 @@ int drm_mode_rmfb(struct drm_device *dev, u32 fb_id, drm_framebuffer_put(fb); return 0; - -fail_unref: - drm_framebuffer_put(fb); - return -ENOENT; } int drm_mode_rmfb_ioctl(struct drm_device *dev, @@ -471,6 +481,28 @@ int drm_mode_rmfb_ioctl(struct drm_device *dev, return drm_mode_rmfb(dev, *fb_id, file_priv); } +int drm_mode_closefb_ioctl(struct drm_device *dev, + void *data, struct drm_file *file_priv) +{ + struct drm_mode_closefb *r = data; + struct drm_framebuffer *fb; + int ret; + + if (!drm_core_check_feature(dev, DRIVER_MODESET)) + return -EOPNOTSUPP; + + if (r->pad) + return -EINVAL; + + fb = drm_framebuffer_lookup(dev, file_priv, r->fb_id); + if (!fb) + return -ENOENT; + + ret = drm_mode_closefb(fb, file_priv); + drm_framebuffer_put(fb); + return ret; +} + /** * drm_mode_getfb - get FB info * @dev: drm device for the ioctl @@ -552,7 +584,7 @@ int drm_mode_getfb2_ioctl(struct drm_device *dev, struct drm_mode_fb_cmd2 *r = data; struct drm_framebuffer *fb; unsigned int i; - int ret; + int ret = 0; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; @@ -796,6 +828,8 @@ void drm_framebuffer_free(struct kref *kref) container_of(kref, struct drm_framebuffer, base.refcount); struct drm_device *dev = fb->dev; + drm_WARN_ON(dev, !list_empty(&fb->filp_head)); + /* * The lookup idr holds a weak reference, which has not necessarily been * removed at this point. Check for that. @@ -1088,7 +1122,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) dev = fb->dev; - WARN_ON(!list_empty(&fb->filp_head)); + drm_WARN_ON(dev, !list_empty(&fb->filp_head)); /* * drm ABI mandates that we remove any deleted framebuffers from active diff --git a/drivers/gpu/drm/drm_gem_atomic_helper.c b/drivers/gpu/drm/drm_gem_atomic_helper.c index 5d4b9cd077f7a6..e440f458b6633d 100644 --- a/drivers/gpu/drm/drm_gem_atomic_helper.c +++ b/drivers/gpu/drm/drm_gem_atomic_helper.c @@ -218,7 +218,14 @@ void __drm_gem_duplicate_shadow_plane_state(struct drm_plane *plane, struct drm_shadow_plane_state *new_shadow_plane_state) { + struct drm_plane_state *plane_state = plane->state; + struct drm_shadow_plane_state *shadow_plane_state = + to_drm_shadow_plane_state(plane_state); + __drm_atomic_helper_plane_duplicate_state(plane, &new_shadow_plane_state->base); + + drm_format_conv_state_copy(&shadow_plane_state->fmtcnv_state, + &new_shadow_plane_state->fmtcnv_state); } EXPORT_SYMBOL(__drm_gem_duplicate_shadow_plane_state); @@ -266,6 +273,7 @@ EXPORT_SYMBOL(drm_gem_duplicate_shadow_plane_state); */ void __drm_gem_destroy_shadow_plane_state(struct drm_shadow_plane_state *shadow_plane_state) { + drm_format_conv_state_release(&shadow_plane_state->fmtcnv_state); __drm_atomic_helper_plane_destroy_state(&shadow_plane_state->base); } EXPORT_SYMBOL(__drm_gem_destroy_shadow_plane_state); @@ -302,6 +310,7 @@ void __drm_gem_reset_shadow_plane(struct drm_plane *plane, struct drm_shadow_plane_state *shadow_plane_state) { __drm_atomic_helper_plane_reset(plane, &shadow_plane_state->base); + drm_format_conv_state_init(&shadow_plane_state->fmtcnv_state); } EXPORT_SYMBOL(__drm_gem_reset_shadow_plane); diff --git a/drivers/gpu/drm/drm_gpuvm.c b/drivers/gpu/drm/drm_gpuvm.c index b80d4e1cc9b7f1..f9eb56f24bef29 100644 --- a/drivers/gpu/drm/drm_gpuvm.c +++ b/drivers/gpu/drm/drm_gpuvm.c @@ -61,6 +61,42 @@ * contained within struct drm_gpuva already. Hence, for inserting &drm_gpuva * entries from within dma-fence signalling critical sections it is enough to * pre-allocate the &drm_gpuva structures. + * + * &drm_gem_objects which are private to a single VM can share a common + * &dma_resv in order to improve locking efficiency (e.g. with &drm_exec). + * For this purpose drivers must pass a &drm_gem_object to drm_gpuvm_init(), in + * the following called 'resv object', which serves as the container of the + * GPUVM's shared &dma_resv. This resv object can be a driver specific + * &drm_gem_object, such as the &drm_gem_object containing the root page table, + * but it can also be a 'dummy' object, which can be allocated with + * drm_gpuvm_resv_object_alloc(). + * + * In order to connect a struct drm_gpuva its backing &drm_gem_object each + * &drm_gem_object maintains a list of &drm_gpuvm_bo structures, and each + * &drm_gpuvm_bo contains a list of &drm_gpuva structures. + * + * A &drm_gpuvm_bo is an abstraction that represents a combination of a + * &drm_gpuvm and a &drm_gem_object. Every such combination should be unique. + * This is ensured by the API through drm_gpuvm_bo_obtain() and + * drm_gpuvm_bo_obtain_prealloc() which first look into the corresponding + * &drm_gem_object list of &drm_gpuvm_bos for an existing instance of this + * particular combination. If not existent a new instance is created and linked + * to the &drm_gem_object. + * + * &drm_gpuvm_bo structures, since unique for a given &drm_gpuvm, are also used + * as entry for the &drm_gpuvm's lists of external and evicted objects. Those + * lists are maintained in order to accelerate locking of dma-resv locks and + * validation of evicted objects bound in a &drm_gpuvm. For instance, all + * &drm_gem_object's &dma_resv of a given &drm_gpuvm can be locked by calling + * drm_gpuvm_exec_lock(). Once locked drivers can call drm_gpuvm_validate() in + * order to validate all evicted &drm_gem_objects. It is also possible to lock + * additional &drm_gem_objects by providing the corresponding parameters to + * drm_gpuvm_exec_lock() as well as open code the &drm_exec loop while making + * use of helper functions such as drm_gpuvm_prepare_range() or + * drm_gpuvm_prepare_objects(). + * + * Every bound &drm_gem_object is treated as external object when its &dma_resv + * structure is different than the &drm_gpuvm's common &dma_resv structure. */ /** @@ -386,21 +422,42 @@ /** * DOC: Locking * - * Generally, the GPU VA manager does not take care of locking itself, it is - * the drivers responsibility to take care about locking. Drivers might want to - * protect the following operations: inserting, removing and iterating - * &drm_gpuva objects as well as generating all kinds of operations, such as - * split / merge or prefetch. - * - * The GPU VA manager also does not take care of the locking of the backing - * &drm_gem_object buffers GPU VA lists by itself; drivers are responsible to - * enforce mutual exclusion using either the GEMs dma_resv lock or alternatively - * a driver specific external lock. For the latter see also - * drm_gem_gpuva_set_lock(). - * - * However, the GPU VA manager contains lockdep checks to ensure callers of its - * API hold the corresponding lock whenever the &drm_gem_objects GPU VA list is - * accessed by functions such as drm_gpuva_link() or drm_gpuva_unlink(). + * In terms of managing &drm_gpuva entries DRM GPUVM does not take care of + * locking itself, it is the drivers responsibility to take care about locking. + * Drivers might want to protect the following operations: inserting, removing + * and iterating &drm_gpuva objects as well as generating all kinds of + * operations, such as split / merge or prefetch. + * + * DRM GPUVM also does not take care of the locking of the backing + * &drm_gem_object buffers GPU VA lists and &drm_gpuvm_bo abstractions by + * itself; drivers are responsible to enforce mutual exclusion using either the + * GEMs dma_resv lock or alternatively a driver specific external lock. For the + * latter see also drm_gem_gpuva_set_lock(). + * + * However, DRM GPUVM contains lockdep checks to ensure callers of its API hold + * the corresponding lock whenever the &drm_gem_objects GPU VA list is accessed + * by functions such as drm_gpuva_link() or drm_gpuva_unlink(), but also + * drm_gpuvm_bo_obtain() and drm_gpuvm_bo_put(). + * + * The latter is required since on creation and destruction of a &drm_gpuvm_bo + * the &drm_gpuvm_bo is attached / removed from the &drm_gem_objects gpuva list. + * Subsequent calls to drm_gpuvm_bo_obtain() for the same &drm_gpuvm and + * &drm_gem_object must be able to observe previous creations and destructions + * of &drm_gpuvm_bos in order to keep instances unique. + * + * The &drm_gpuvm's lists for keeping track of external and evicted objects are + * protected against concurrent insertion / removal and iteration internally. + * + * However, drivers still need ensure to protect concurrent calls to functions + * iterating those lists, namely drm_gpuvm_prepare_objects() and + * drm_gpuvm_validate(). + * + * Alternatively, drivers can set the &DRM_GPUVM_RESV_PROTECTED flag to indicate + * that the corresponding &dma_resv locks are held in order to protect the + * lists. If &DRM_GPUVM_RESV_PROTECTED is set, internal locking is disabled and + * the corresponding lockdep checks are enabled. This is an optimization for + * drivers which are capable of taking the corresponding &dma_resv locks and + * hence do not require internal locking. */ /** @@ -430,6 +487,7 @@ * { * struct drm_gpuva_ops *ops; * struct drm_gpuva_op *op + * struct drm_gpuvm_bo *vm_bo; * * driver_lock_va_space(); * ops = drm_gpuvm_sm_map_ops_create(gpuvm, addr, range, @@ -437,6 +495,10 @@ * if (IS_ERR(ops)) * return PTR_ERR(ops); * + * vm_bo = drm_gpuvm_bo_obtain(gpuvm, obj); + * if (IS_ERR(vm_bo)) + * return PTR_ERR(vm_bo); + * * drm_gpuva_for_each_op(op, ops) { * struct drm_gpuva *va; * @@ -449,7 +511,7 @@ * * driver_vm_map(); * drm_gpuva_map(gpuvm, va, &op->map); - * drm_gpuva_link(va); + * drm_gpuva_link(va, vm_bo); * * break; * case DRM_GPUVA_OP_REMAP: { @@ -476,11 +538,11 @@ * driver_vm_remap(); * drm_gpuva_remap(prev, next, &op->remap); * - * drm_gpuva_unlink(va); * if (prev) - * drm_gpuva_link(prev); + * drm_gpuva_link(prev, va->vm_bo); * if (next) - * drm_gpuva_link(next); + * drm_gpuva_link(next, va->vm_bo); + * drm_gpuva_unlink(va); * * break; * } @@ -496,6 +558,7 @@ * break; * } * } + * drm_gpuvm_bo_put(vm_bo); * driver_unlock_va_space(); * * return 0; @@ -505,6 +568,7 @@ * * struct driver_context { * struct drm_gpuvm *gpuvm; + * struct drm_gpuvm_bo *vm_bo; * struct drm_gpuva *new_va; * struct drm_gpuva *prev_va; * struct drm_gpuva *next_va; @@ -525,6 +589,7 @@ * struct drm_gem_object *obj, u64 offset) * { * struct driver_context ctx; + * struct drm_gpuvm_bo *vm_bo; * struct drm_gpuva_ops *ops; * struct drm_gpuva_op *op; * int ret = 0; @@ -534,16 +599,23 @@ * ctx.new_va = kzalloc(sizeof(*ctx.new_va), GFP_KERNEL); * ctx.prev_va = kzalloc(sizeof(*ctx.prev_va), GFP_KERNEL); * ctx.next_va = kzalloc(sizeof(*ctx.next_va), GFP_KERNEL); - * if (!ctx.new_va || !ctx.prev_va || !ctx.next_va) { + * ctx.vm_bo = drm_gpuvm_bo_create(gpuvm, obj); + * if (!ctx.new_va || !ctx.prev_va || !ctx.next_va || !vm_bo) { * ret = -ENOMEM; * goto out; * } * + * // Typically protected with a driver specific GEM gpuva lock + * // used in the fence signaling path for drm_gpuva_link() and + * // drm_gpuva_unlink(), hence pre-allocate. + * ctx.vm_bo = drm_gpuvm_bo_obtain_prealloc(ctx.vm_bo); + * * driver_lock_va_space(); * ret = drm_gpuvm_sm_map(gpuvm, &ctx, addr, range, obj, offset); * driver_unlock_va_space(); * * out: + * drm_gpuvm_bo_put(ctx.vm_bo); * kfree(ctx.new_va); * kfree(ctx.prev_va); * kfree(ctx.next_va); @@ -556,7 +628,7 @@ * * drm_gpuva_map(ctx->vm, ctx->new_va, &op->map); * - * drm_gpuva_link(ctx->new_va); + * drm_gpuva_link(ctx->new_va, ctx->vm_bo); * * // prevent the new GPUVA from being freed in * // driver_mapping_create() @@ -568,22 +640,23 @@ * int driver_gpuva_remap(struct drm_gpuva_op *op, void *__ctx) * { * struct driver_context *ctx = __ctx; + * struct drm_gpuva *va = op->remap.unmap->va; * * drm_gpuva_remap(ctx->prev_va, ctx->next_va, &op->remap); * - * drm_gpuva_unlink(op->remap.unmap->va); - * kfree(op->remap.unmap->va); - * * if (op->remap.prev) { - * drm_gpuva_link(ctx->prev_va); + * drm_gpuva_link(ctx->prev_va, va->vm_bo); * ctx->prev_va = NULL; * } * * if (op->remap.next) { - * drm_gpuva_link(ctx->next_va); + * drm_gpuva_link(ctx->next_va, va->vm_bo); * ctx->next_va = NULL; * } * + * drm_gpuva_unlink(va); + * kfree(va); + * * return 0; * } * @@ -597,6 +670,201 @@ * } */ +/** + * get_next_vm_bo_from_list() - get the next vm_bo element + * @__gpuvm: the &drm_gpuvm + * @__list_name: the name of the list we're iterating on + * @__local_list: a pointer to the local list used to store already iterated items + * @__prev_vm_bo: the previous element we got from get_next_vm_bo_from_list() + * + * This helper is here to provide lockless list iteration. Lockless as in, the + * iterator releases the lock immediately after picking the first element from + * the list, so list insertion deletion can happen concurrently. + * + * Elements popped from the original list are kept in a local list, so removal + * and is_empty checks can still happen while we're iterating the list. + */ +#define get_next_vm_bo_from_list(__gpuvm, __list_name, __local_list, __prev_vm_bo) \ + ({ \ + struct drm_gpuvm_bo *__vm_bo = NULL; \ + \ + drm_gpuvm_bo_put(__prev_vm_bo); \ + \ + spin_lock(&(__gpuvm)->__list_name.lock); \ + if (!(__gpuvm)->__list_name.local_list) \ + (__gpuvm)->__list_name.local_list = __local_list; \ + else \ + drm_WARN_ON((__gpuvm)->drm, \ + (__gpuvm)->__list_name.local_list != __local_list); \ + \ + while (!list_empty(&(__gpuvm)->__list_name.list)) { \ + __vm_bo = list_first_entry(&(__gpuvm)->__list_name.list, \ + struct drm_gpuvm_bo, \ + list.entry.__list_name); \ + if (kref_get_unless_zero(&__vm_bo->kref)) { \ + list_move_tail(&(__vm_bo)->list.entry.__list_name, \ + __local_list); \ + break; \ + } else { \ + list_del_init(&(__vm_bo)->list.entry.__list_name); \ + __vm_bo = NULL; \ + } \ + } \ + spin_unlock(&(__gpuvm)->__list_name.lock); \ + \ + __vm_bo; \ + }) + +/** + * for_each_vm_bo_in_list() - internal vm_bo list iterator + * @__gpuvm: the &drm_gpuvm + * @__list_name: the name of the list we're iterating on + * @__local_list: a pointer to the local list used to store already iterated items + * @__vm_bo: the struct drm_gpuvm_bo to assign in each iteration step + * + * This helper is here to provide lockless list iteration. Lockless as in, the + * iterator releases the lock immediately after picking the first element from the + * list, hence list insertion and deletion can happen concurrently. + * + * It is not allowed to re-assign the vm_bo pointer from inside this loop. + * + * Typical use: + * + * struct drm_gpuvm_bo *vm_bo; + * LIST_HEAD(my_local_list); + * + * ret = 0; + * for_each_vm_bo_in_list(gpuvm, , &my_local_list, vm_bo) { + * ret = do_something_with_vm_bo(..., vm_bo); + * if (ret) + * break; + * } + * // Drop ref in case we break out of the loop. + * drm_gpuvm_bo_put(vm_bo); + * restore_vm_bo_list(gpuvm, , &my_local_list); + * + * + * Only used for internal list iterations, not meant to be exposed to the outside + * world. + */ +#define for_each_vm_bo_in_list(__gpuvm, __list_name, __local_list, __vm_bo) \ + for (__vm_bo = get_next_vm_bo_from_list(__gpuvm, __list_name, \ + __local_list, NULL); \ + __vm_bo; \ + __vm_bo = get_next_vm_bo_from_list(__gpuvm, __list_name, \ + __local_list, __vm_bo)) + +static void +__restore_vm_bo_list(struct drm_gpuvm *gpuvm, spinlock_t *lock, + struct list_head *list, struct list_head **local_list) +{ + /* Merge back the two lists, moving local list elements to the + * head to preserve previous ordering, in case it matters. + */ + spin_lock(lock); + if (*local_list) { + list_splice(*local_list, list); + *local_list = NULL; + } + spin_unlock(lock); +} + +/** + * restore_vm_bo_list() - move vm_bo elements back to their original list + * @__gpuvm: the &drm_gpuvm + * @__list_name: the name of the list we're iterating on + * + * When we're done iterating a vm_bo list, we should call restore_vm_bo_list() + * to restore the original state and let new iterations take place. + */ +#define restore_vm_bo_list(__gpuvm, __list_name) \ + __restore_vm_bo_list((__gpuvm), &(__gpuvm)->__list_name.lock, \ + &(__gpuvm)->__list_name.list, \ + &(__gpuvm)->__list_name.local_list) + +static void +cond_spin_lock(spinlock_t *lock, bool cond) +{ + if (cond) + spin_lock(lock); +} + +static void +cond_spin_unlock(spinlock_t *lock, bool cond) +{ + if (cond) + spin_unlock(lock); +} + +static void +__drm_gpuvm_bo_list_add(struct drm_gpuvm *gpuvm, spinlock_t *lock, + struct list_head *entry, struct list_head *list) +{ + cond_spin_lock(lock, !!lock); + if (list_empty(entry)) + list_add_tail(entry, list); + cond_spin_unlock(lock, !!lock); +} + +/** + * drm_gpuvm_bo_list_add() - insert a vm_bo into the given list + * @__vm_bo: the &drm_gpuvm_bo + * @__list_name: the name of the list to insert into + * @__lock: whether to lock with the internal spinlock + * + * Inserts the given @__vm_bo into the list specified by @__list_name. + */ +#define drm_gpuvm_bo_list_add(__vm_bo, __list_name, __lock) \ + __drm_gpuvm_bo_list_add((__vm_bo)->vm, \ + __lock ? &(__vm_bo)->vm->__list_name.lock : \ + NULL, \ + &(__vm_bo)->list.entry.__list_name, \ + &(__vm_bo)->vm->__list_name.list) + +static void +__drm_gpuvm_bo_list_del(struct drm_gpuvm *gpuvm, spinlock_t *lock, + struct list_head *entry, bool init) +{ + cond_spin_lock(lock, !!lock); + if (init) { + if (!list_empty(entry)) + list_del_init(entry); + } else { + list_del(entry); + } + cond_spin_unlock(lock, !!lock); +} + +/** + * drm_gpuvm_bo_list_del_init() - remove a vm_bo from the given list + * @__vm_bo: the &drm_gpuvm_bo + * @__list_name: the name of the list to insert into + * @__lock: whether to lock with the internal spinlock + * + * Removes the given @__vm_bo from the list specified by @__list_name. + */ +#define drm_gpuvm_bo_list_del_init(__vm_bo, __list_name, __lock) \ + __drm_gpuvm_bo_list_del((__vm_bo)->vm, \ + __lock ? &(__vm_bo)->vm->__list_name.lock : \ + NULL, \ + &(__vm_bo)->list.entry.__list_name, \ + true) + +/** + * drm_gpuvm_bo_list_del() - remove a vm_bo from the given list + * @__vm_bo: the &drm_gpuvm_bo + * @__list_name: the name of the list to insert into + * @__lock: whether to lock with the internal spinlock + * + * Removes the given @__vm_bo from the list specified by @__list_name. + */ +#define drm_gpuvm_bo_list_del(__vm_bo, __list_name, __lock) \ + __drm_gpuvm_bo_list_del((__vm_bo)->vm, \ + __lock ? &(__vm_bo)->vm->__list_name.lock : \ + NULL, \ + &(__vm_bo)->list.entry.__list_name, \ + false) + #define to_drm_gpuva(__node) container_of((__node), struct drm_gpuva, rb.node) #define GPUVA_START(node) ((node)->va.addr) @@ -618,8 +886,14 @@ drm_gpuvm_check_overflow(u64 addr, u64 range) { u64 end; - return WARN(check_add_overflow(addr, range, &end), - "GPUVA address limited to %zu bytes.\n", sizeof(end)); + return check_add_overflow(addr, range, &end); +} + +static bool +drm_gpuvm_warn_check_overflow(struct drm_gpuvm *gpuvm, u64 addr, u64 range) +{ + return drm_WARN(gpuvm->drm, drm_gpuvm_check_overflow(addr, range), + "GPUVA address limited to %zu bytes.\n", sizeof(addr)); } static bool @@ -643,7 +917,18 @@ drm_gpuvm_in_kernel_node(struct drm_gpuvm *gpuvm, u64 addr, u64 range) return krange && addr < kend && kstart < end; } -static bool +/** + * drm_gpuvm_range_valid() - checks whether the given range is valid for the + * given &drm_gpuvm + * @gpuvm: the GPUVM to check the range for + * @addr: the base address + * @range: the range starting from the base address + * + * Checks whether the range is within the GPUVM's managed boundaries. + * + * Returns: true for a valid range, false otherwise + */ +bool drm_gpuvm_range_valid(struct drm_gpuvm *gpuvm, u64 addr, u64 range) { @@ -651,11 +936,52 @@ drm_gpuvm_range_valid(struct drm_gpuvm *gpuvm, drm_gpuvm_in_mm_range(gpuvm, addr, range) && !drm_gpuvm_in_kernel_node(gpuvm, addr, range); } +EXPORT_SYMBOL_GPL(drm_gpuvm_range_valid); + +static void +drm_gpuvm_gem_object_free(struct drm_gem_object *obj) +{ + drm_gem_object_release(obj); + kfree(obj); +} + +static const struct drm_gem_object_funcs drm_gpuvm_object_funcs = { + .free = drm_gpuvm_gem_object_free, +}; + +/** + * drm_gpuvm_resv_object_alloc() - allocate a dummy &drm_gem_object + * @drm: the drivers &drm_device + * + * Allocates a dummy &drm_gem_object which can be passed to drm_gpuvm_init() in + * order to serve as root GEM object providing the &drm_resv shared across + * &drm_gem_objects local to a single GPUVM. + * + * Returns: the &drm_gem_object on success, NULL on failure + */ +struct drm_gem_object * +drm_gpuvm_resv_object_alloc(struct drm_device *drm) +{ + struct drm_gem_object *obj; + + obj = kzalloc(sizeof(*obj), GFP_KERNEL); + if (!obj) + return NULL; + + obj->funcs = &drm_gpuvm_object_funcs; + drm_gem_private_object_init(drm, obj, 0); + + return obj; +} +EXPORT_SYMBOL_GPL(drm_gpuvm_resv_object_alloc); /** * drm_gpuvm_init() - initialize a &drm_gpuvm * @gpuvm: pointer to the &drm_gpuvm to initialize * @name: the name of the GPU VA space + * @flags: the &drm_gpuvm_flags for this GPUVM + * @drm: the &drm_device this VM resides in + * @r_obj: the resv &drm_gem_object providing the GPUVM's common &dma_resv * @start_offset: the start offset of the GPU VA space * @range: the size of the GPU VA space * @reserve_offset: the start of the kernel reserved GPU VA area @@ -668,8 +994,10 @@ drm_gpuvm_range_valid(struct drm_gpuvm *gpuvm, * &name is expected to be managed by the surrounding driver structures. */ void -drm_gpuvm_init(struct drm_gpuvm *gpuvm, - const char *name, +drm_gpuvm_init(struct drm_gpuvm *gpuvm, const char *name, + enum drm_gpuvm_flags flags, + struct drm_device *drm, + struct drm_gem_object *r_obj, u64 start_offset, u64 range, u64 reserve_offset, u64 reserve_range, const struct drm_gpuvm_ops *ops) @@ -677,45 +1005,713 @@ drm_gpuvm_init(struct drm_gpuvm *gpuvm, gpuvm->rb.tree = RB_ROOT_CACHED; INIT_LIST_HEAD(&gpuvm->rb.list); - drm_gpuvm_check_overflow(start_offset, range); - gpuvm->mm_start = start_offset; - gpuvm->mm_range = range; + INIT_LIST_HEAD(&gpuvm->extobj.list); + spin_lock_init(&gpuvm->extobj.lock); + + INIT_LIST_HEAD(&gpuvm->evict.list); + spin_lock_init(&gpuvm->evict.lock); + + kref_init(&gpuvm->kref); gpuvm->name = name ? name : "unknown"; + gpuvm->flags = flags; gpuvm->ops = ops; + gpuvm->drm = drm; + gpuvm->r_obj = r_obj; - memset(&gpuvm->kernel_alloc_node, 0, sizeof(struct drm_gpuva)); + drm_gem_object_get(r_obj); + + drm_gpuvm_warn_check_overflow(gpuvm, start_offset, range); + gpuvm->mm_start = start_offset; + gpuvm->mm_range = range; + memset(&gpuvm->kernel_alloc_node, 0, sizeof(struct drm_gpuva)); if (reserve_range) { gpuvm->kernel_alloc_node.va.addr = reserve_offset; gpuvm->kernel_alloc_node.va.range = reserve_range; - if (likely(!drm_gpuvm_check_overflow(reserve_offset, - reserve_range))) + if (likely(!drm_gpuvm_warn_check_overflow(gpuvm, reserve_offset, + reserve_range))) __drm_gpuva_insert(gpuvm, &gpuvm->kernel_alloc_node); } } EXPORT_SYMBOL_GPL(drm_gpuvm_init); +static void +drm_gpuvm_fini(struct drm_gpuvm *gpuvm) +{ + gpuvm->name = NULL; + + if (gpuvm->kernel_alloc_node.va.range) + __drm_gpuva_remove(&gpuvm->kernel_alloc_node); + + drm_WARN(gpuvm->drm, !RB_EMPTY_ROOT(&gpuvm->rb.tree.rb_root), + "GPUVA tree is not empty, potentially leaking memory.\n"); + + drm_WARN(gpuvm->drm, !list_empty(&gpuvm->extobj.list), + "Extobj list should be empty.\n"); + drm_WARN(gpuvm->drm, !list_empty(&gpuvm->evict.list), + "Evict list should be empty.\n"); + + drm_gem_object_put(gpuvm->r_obj); +} + +static void +drm_gpuvm_free(struct kref *kref) +{ + struct drm_gpuvm *gpuvm = container_of(kref, struct drm_gpuvm, kref); + + drm_gpuvm_fini(gpuvm); + + if (drm_WARN_ON(gpuvm->drm, !gpuvm->ops->vm_free)) + return; + + gpuvm->ops->vm_free(gpuvm); +} + /** - * drm_gpuvm_destroy() - cleanup a &drm_gpuvm - * @gpuvm: pointer to the &drm_gpuvm to clean up + * drm_gpuvm_put() - drop a struct drm_gpuvm reference + * @gpuvm: the &drm_gpuvm to release the reference of + * + * This releases a reference to @gpuvm. * - * Note that it is a bug to call this function on a manager that still - * holds GPU VA mappings. + * This function may be called from atomic context. */ void -drm_gpuvm_destroy(struct drm_gpuvm *gpuvm) +drm_gpuvm_put(struct drm_gpuvm *gpuvm) { - gpuvm->name = NULL; + if (gpuvm) + kref_put(&gpuvm->kref, drm_gpuvm_free); +} +EXPORT_SYMBOL_GPL(drm_gpuvm_put); - if (gpuvm->kernel_alloc_node.va.range) - __drm_gpuva_remove(&gpuvm->kernel_alloc_node); +static int +exec_prepare_obj(struct drm_exec *exec, struct drm_gem_object *obj, + unsigned int num_fences) +{ + return num_fences ? drm_exec_prepare_obj(exec, obj, num_fences) : + drm_exec_lock_obj(exec, obj); +} - WARN(!RB_EMPTY_ROOT(&gpuvm->rb.tree.rb_root), - "GPUVA tree is not empty, potentially leaking memory."); +/** + * drm_gpuvm_prepare_vm() - prepare the GPUVMs common dma-resv + * @gpuvm: the &drm_gpuvm + * @exec: the &drm_exec context + * @num_fences: the amount of &dma_fences to reserve + * + * Calls drm_exec_prepare_obj() for the GPUVMs dummy &drm_gem_object; if + * @num_fences is zero drm_exec_lock_obj() is called instead. + * + * Using this function directly, it is the drivers responsibility to call + * drm_exec_init() and drm_exec_fini() accordingly. + * + * Returns: 0 on success, negative error code on failure. + */ +int +drm_gpuvm_prepare_vm(struct drm_gpuvm *gpuvm, + struct drm_exec *exec, + unsigned int num_fences) +{ + return exec_prepare_obj(exec, gpuvm->r_obj, num_fences); +} +EXPORT_SYMBOL_GPL(drm_gpuvm_prepare_vm); + +static int +__drm_gpuvm_prepare_objects(struct drm_gpuvm *gpuvm, + struct drm_exec *exec, + unsigned int num_fences) +{ + struct drm_gpuvm_bo *vm_bo; + LIST_HEAD(extobjs); + int ret = 0; + + for_each_vm_bo_in_list(gpuvm, extobj, &extobjs, vm_bo) { + ret = exec_prepare_obj(exec, vm_bo->obj, num_fences); + if (ret) + break; + } + /* Drop ref in case we break out of the loop. */ + drm_gpuvm_bo_put(vm_bo); + restore_vm_bo_list(gpuvm, extobj); + + return ret; } -EXPORT_SYMBOL_GPL(drm_gpuvm_destroy); + +static int +drm_gpuvm_prepare_objects_locked(struct drm_gpuvm *gpuvm, + struct drm_exec *exec, + unsigned int num_fences) +{ + struct drm_gpuvm_bo *vm_bo; + int ret = 0; + + drm_gpuvm_resv_assert_held(gpuvm); + list_for_each_entry(vm_bo, &gpuvm->extobj.list, list.entry.extobj) { + ret = exec_prepare_obj(exec, vm_bo->obj, num_fences); + if (ret) + break; + + if (vm_bo->evicted) + drm_gpuvm_bo_list_add(vm_bo, evict, false); + } + + return ret; +} + +/** + * drm_gpuvm_prepare_objects() - prepare all assoiciated BOs + * @gpuvm: the &drm_gpuvm + * @exec: the &drm_exec locking context + * @num_fences: the amount of &dma_fences to reserve + * + * Calls drm_exec_prepare_obj() for all &drm_gem_objects the given + * &drm_gpuvm contains mappings of; if @num_fences is zero drm_exec_lock_obj() + * is called instead. + * + * Using this function directly, it is the drivers responsibility to call + * drm_exec_init() and drm_exec_fini() accordingly. + * + * Note: This function is safe against concurrent insertion and removal of + * external objects, however it is not safe against concurrent usage itself. + * + * Drivers need to make sure to protect this case with either an outer VM lock + * or by calling drm_gpuvm_prepare_vm() before this function within the + * drm_exec_until_all_locked() loop, such that the GPUVM's dma-resv lock ensures + * mutual exclusion. + * + * Returns: 0 on success, negative error code on failure. + */ +int +drm_gpuvm_prepare_objects(struct drm_gpuvm *gpuvm, + struct drm_exec *exec, + unsigned int num_fences) +{ + if (drm_gpuvm_resv_protected(gpuvm)) + return drm_gpuvm_prepare_objects_locked(gpuvm, exec, + num_fences); + else + return __drm_gpuvm_prepare_objects(gpuvm, exec, num_fences); +} +EXPORT_SYMBOL_GPL(drm_gpuvm_prepare_objects); + +/** + * drm_gpuvm_prepare_range() - prepare all BOs mapped within a given range + * @gpuvm: the &drm_gpuvm + * @exec: the &drm_exec locking context + * @addr: the start address within the VA space + * @range: the range to iterate within the VA space + * @num_fences: the amount of &dma_fences to reserve + * + * Calls drm_exec_prepare_obj() for all &drm_gem_objects mapped between @addr + * and @addr + @range; if @num_fences is zero drm_exec_lock_obj() is called + * instead. + * + * Returns: 0 on success, negative error code on failure. + */ +int +drm_gpuvm_prepare_range(struct drm_gpuvm *gpuvm, struct drm_exec *exec, + u64 addr, u64 range, unsigned int num_fences) +{ + struct drm_gpuva *va; + u64 end = addr + range; + int ret; + + drm_gpuvm_for_each_va_range(va, gpuvm, addr, end) { + struct drm_gem_object *obj = va->gem.obj; + + ret = exec_prepare_obj(exec, obj, num_fences); + if (ret) + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(drm_gpuvm_prepare_range); + +/** + * drm_gpuvm_exec_lock() - lock all dma-resv of all assoiciated BOs + * @vm_exec: the &drm_gpuvm_exec wrapper + * + * Acquires all dma-resv locks of all &drm_gem_objects the given + * &drm_gpuvm contains mappings of. + * + * Addionally, when calling this function with struct drm_gpuvm_exec::extra + * being set the driver receives the given @fn callback to lock additional + * dma-resv in the context of the &drm_gpuvm_exec instance. Typically, drivers + * would call drm_exec_prepare_obj() from within this callback. + * + * Returns: 0 on success, negative error code on failure. + */ +int +drm_gpuvm_exec_lock(struct drm_gpuvm_exec *vm_exec) +{ + struct drm_gpuvm *gpuvm = vm_exec->vm; + struct drm_exec *exec = &vm_exec->exec; + unsigned int num_fences = vm_exec->num_fences; + int ret; + + drm_exec_init(exec, vm_exec->flags, 0); + + drm_exec_until_all_locked(exec) { + ret = drm_gpuvm_prepare_vm(gpuvm, exec, num_fences); + drm_exec_retry_on_contention(exec); + if (ret) + goto err; + + ret = drm_gpuvm_prepare_objects(gpuvm, exec, num_fences); + drm_exec_retry_on_contention(exec); + if (ret) + goto err; + + if (vm_exec->extra.fn) { + ret = vm_exec->extra.fn(vm_exec); + drm_exec_retry_on_contention(exec); + if (ret) + goto err; + } + } + + return 0; + +err: + drm_exec_fini(exec); + return ret; +} +EXPORT_SYMBOL_GPL(drm_gpuvm_exec_lock); + +static int +fn_lock_array(struct drm_gpuvm_exec *vm_exec) +{ + struct { + struct drm_gem_object **objs; + unsigned int num_objs; + } *args = vm_exec->extra.priv; + + return drm_exec_prepare_array(&vm_exec->exec, args->objs, + args->num_objs, vm_exec->num_fences); +} + +/** + * drm_gpuvm_exec_lock_array() - lock all dma-resv of all assoiciated BOs + * @vm_exec: the &drm_gpuvm_exec wrapper + * @objs: additional &drm_gem_objects to lock + * @num_objs: the number of additional &drm_gem_objects to lock + * + * Acquires all dma-resv locks of all &drm_gem_objects the given &drm_gpuvm + * contains mappings of, plus the ones given through @objs. + * + * Returns: 0 on success, negative error code on failure. + */ +int +drm_gpuvm_exec_lock_array(struct drm_gpuvm_exec *vm_exec, + struct drm_gem_object **objs, + unsigned int num_objs) +{ + struct { + struct drm_gem_object **objs; + unsigned int num_objs; + } args; + + args.objs = objs; + args.num_objs = num_objs; + + vm_exec->extra.fn = fn_lock_array; + vm_exec->extra.priv = &args; + + return drm_gpuvm_exec_lock(vm_exec); +} +EXPORT_SYMBOL_GPL(drm_gpuvm_exec_lock_array); + +/** + * drm_gpuvm_exec_lock_range() - prepare all BOs mapped within a given range + * @vm_exec: the &drm_gpuvm_exec wrapper + * @addr: the start address within the VA space + * @range: the range to iterate within the VA space + * + * Acquires all dma-resv locks of all &drm_gem_objects mapped between @addr and + * @addr + @range. + * + * Returns: 0 on success, negative error code on failure. + */ +int +drm_gpuvm_exec_lock_range(struct drm_gpuvm_exec *vm_exec, + u64 addr, u64 range) +{ + struct drm_gpuvm *gpuvm = vm_exec->vm; + struct drm_exec *exec = &vm_exec->exec; + int ret; + + drm_exec_init(exec, vm_exec->flags, 0); + + drm_exec_until_all_locked(exec) { + ret = drm_gpuvm_prepare_range(gpuvm, exec, addr, range, + vm_exec->num_fences); + drm_exec_retry_on_contention(exec); + if (ret) + goto err; + } + + return ret; + +err: + drm_exec_fini(exec); + return ret; +} +EXPORT_SYMBOL_GPL(drm_gpuvm_exec_lock_range); + +static int +__drm_gpuvm_validate(struct drm_gpuvm *gpuvm, struct drm_exec *exec) +{ + const struct drm_gpuvm_ops *ops = gpuvm->ops; + struct drm_gpuvm_bo *vm_bo; + LIST_HEAD(evict); + int ret = 0; + + for_each_vm_bo_in_list(gpuvm, evict, &evict, vm_bo) { + ret = ops->vm_bo_validate(vm_bo, exec); + if (ret) + break; + } + /* Drop ref in case we break out of the loop. */ + drm_gpuvm_bo_put(vm_bo); + restore_vm_bo_list(gpuvm, evict); + + return ret; +} + +static int +drm_gpuvm_validate_locked(struct drm_gpuvm *gpuvm, struct drm_exec *exec) +{ + const struct drm_gpuvm_ops *ops = gpuvm->ops; + struct drm_gpuvm_bo *vm_bo, *next; + int ret = 0; + + drm_gpuvm_resv_assert_held(gpuvm); + + list_for_each_entry_safe(vm_bo, next, &gpuvm->evict.list, + list.entry.evict) { + ret = ops->vm_bo_validate(vm_bo, exec); + if (ret) + break; + + dma_resv_assert_held(vm_bo->obj->resv); + if (!vm_bo->evicted) + drm_gpuvm_bo_list_del_init(vm_bo, evict, false); + } + + return ret; +} + +/** + * drm_gpuvm_validate() - validate all BOs marked as evicted + * @gpuvm: the &drm_gpuvm to validate evicted BOs + * @exec: the &drm_exec instance used for locking the GPUVM + * + * Calls the &drm_gpuvm_ops::vm_bo_validate callback for all evicted buffer + * objects being mapped in the given &drm_gpuvm. + * + * Returns: 0 on success, negative error code on failure. + */ +int +drm_gpuvm_validate(struct drm_gpuvm *gpuvm, struct drm_exec *exec) +{ + const struct drm_gpuvm_ops *ops = gpuvm->ops; + + if (unlikely(!ops || !ops->vm_bo_validate)) + return -EOPNOTSUPP; + + if (drm_gpuvm_resv_protected(gpuvm)) + return drm_gpuvm_validate_locked(gpuvm, exec); + else + return __drm_gpuvm_validate(gpuvm, exec); +} +EXPORT_SYMBOL_GPL(drm_gpuvm_validate); + +/** + * drm_gpuvm_resv_add_fence - add fence to private and all extobj + * dma-resv + * @gpuvm: the &drm_gpuvm to add a fence to + * @exec: the &drm_exec locking context + * @fence: fence to add + * @private_usage: private dma-resv usage + * @extobj_usage: extobj dma-resv usage + */ +void +drm_gpuvm_resv_add_fence(struct drm_gpuvm *gpuvm, + struct drm_exec *exec, + struct dma_fence *fence, + enum dma_resv_usage private_usage, + enum dma_resv_usage extobj_usage) +{ + struct drm_gem_object *obj; + unsigned long index; + + drm_exec_for_each_locked_object(exec, index, obj) { + dma_resv_assert_held(obj->resv); + dma_resv_add_fence(obj->resv, fence, + drm_gpuvm_is_extobj(gpuvm, obj) ? + extobj_usage : private_usage); + } +} +EXPORT_SYMBOL_GPL(drm_gpuvm_resv_add_fence); + +/** + * drm_gpuvm_bo_create() - create a new instance of struct drm_gpuvm_bo + * @gpuvm: The &drm_gpuvm the @obj is mapped in. + * @obj: The &drm_gem_object being mapped in the @gpuvm. + * + * If provided by the driver, this function uses the &drm_gpuvm_ops + * vm_bo_alloc() callback to allocate. + * + * Returns: a pointer to the &drm_gpuvm_bo on success, NULL on failure + */ +struct drm_gpuvm_bo * +drm_gpuvm_bo_create(struct drm_gpuvm *gpuvm, + struct drm_gem_object *obj) +{ + const struct drm_gpuvm_ops *ops = gpuvm->ops; + struct drm_gpuvm_bo *vm_bo; + + if (ops && ops->vm_bo_alloc) + vm_bo = ops->vm_bo_alloc(); + else + vm_bo = kzalloc(sizeof(*vm_bo), GFP_KERNEL); + + if (unlikely(!vm_bo)) + return NULL; + + vm_bo->vm = drm_gpuvm_get(gpuvm); + vm_bo->obj = obj; + drm_gem_object_get(obj); + + kref_init(&vm_bo->kref); + INIT_LIST_HEAD(&vm_bo->list.gpuva); + INIT_LIST_HEAD(&vm_bo->list.entry.gem); + + INIT_LIST_HEAD(&vm_bo->list.entry.extobj); + INIT_LIST_HEAD(&vm_bo->list.entry.evict); + + return vm_bo; +} +EXPORT_SYMBOL_GPL(drm_gpuvm_bo_create); + +static void +drm_gpuvm_bo_destroy(struct kref *kref) +{ + struct drm_gpuvm_bo *vm_bo = container_of(kref, struct drm_gpuvm_bo, + kref); + struct drm_gpuvm *gpuvm = vm_bo->vm; + const struct drm_gpuvm_ops *ops = gpuvm->ops; + struct drm_gem_object *obj = vm_bo->obj; + bool lock = !drm_gpuvm_resv_protected(gpuvm); + + if (!lock) + drm_gpuvm_resv_assert_held(gpuvm); + + drm_gpuvm_bo_list_del(vm_bo, extobj, lock); + drm_gpuvm_bo_list_del(vm_bo, evict, lock); + + drm_gem_gpuva_assert_lock_held(obj); + list_del(&vm_bo->list.entry.gem); + + if (ops && ops->vm_bo_free) + ops->vm_bo_free(vm_bo); + else + kfree(vm_bo); + + drm_gpuvm_put(gpuvm); + drm_gem_object_put(obj); +} + +/** + * drm_gpuvm_bo_put() - drop a struct drm_gpuvm_bo reference + * @vm_bo: the &drm_gpuvm_bo to release the reference of + * + * This releases a reference to @vm_bo. + * + * If the reference count drops to zero, the &gpuvm_bo is destroyed, which + * includes removing it from the GEMs gpuva list. Hence, if a call to this + * function can potentially let the reference count drop to zero the caller must + * hold the dma-resv or driver specific GEM gpuva lock. + * + * This function may only be called from non-atomic context. + * + * Returns: true if vm_bo was destroyed, false otherwise. + */ +bool +drm_gpuvm_bo_put(struct drm_gpuvm_bo *vm_bo) +{ + might_sleep(); + + if (vm_bo) + return !!kref_put(&vm_bo->kref, drm_gpuvm_bo_destroy); + + return false; +} +EXPORT_SYMBOL_GPL(drm_gpuvm_bo_put); + +static struct drm_gpuvm_bo * +__drm_gpuvm_bo_find(struct drm_gpuvm *gpuvm, + struct drm_gem_object *obj) +{ + struct drm_gpuvm_bo *vm_bo; + + drm_gem_gpuva_assert_lock_held(obj); + drm_gem_for_each_gpuvm_bo(vm_bo, obj) + if (vm_bo->vm == gpuvm) + return vm_bo; + + return NULL; +} + +/** + * drm_gpuvm_bo_find() - find the &drm_gpuvm_bo for the given + * &drm_gpuvm and &drm_gem_object + * @gpuvm: The &drm_gpuvm the @obj is mapped in. + * @obj: The &drm_gem_object being mapped in the @gpuvm. + * + * Find the &drm_gpuvm_bo representing the combination of the given + * &drm_gpuvm and &drm_gem_object. If found, increases the reference + * count of the &drm_gpuvm_bo accordingly. + * + * Returns: a pointer to the &drm_gpuvm_bo on success, NULL on failure + */ +struct drm_gpuvm_bo * +drm_gpuvm_bo_find(struct drm_gpuvm *gpuvm, + struct drm_gem_object *obj) +{ + struct drm_gpuvm_bo *vm_bo = __drm_gpuvm_bo_find(gpuvm, obj); + + return vm_bo ? drm_gpuvm_bo_get(vm_bo) : NULL; +} +EXPORT_SYMBOL_GPL(drm_gpuvm_bo_find); + +/** + * drm_gpuvm_bo_obtain() - obtains and instance of the &drm_gpuvm_bo for the + * given &drm_gpuvm and &drm_gem_object + * @gpuvm: The &drm_gpuvm the @obj is mapped in. + * @obj: The &drm_gem_object being mapped in the @gpuvm. + * + * Find the &drm_gpuvm_bo representing the combination of the given + * &drm_gpuvm and &drm_gem_object. If found, increases the reference + * count of the &drm_gpuvm_bo accordingly. If not found, allocates a new + * &drm_gpuvm_bo. + * + * A new &drm_gpuvm_bo is added to the GEMs gpuva list. + * + * Returns: a pointer to the &drm_gpuvm_bo on success, an ERR_PTR on failure + */ +struct drm_gpuvm_bo * +drm_gpuvm_bo_obtain(struct drm_gpuvm *gpuvm, + struct drm_gem_object *obj) +{ + struct drm_gpuvm_bo *vm_bo; + + vm_bo = drm_gpuvm_bo_find(gpuvm, obj); + if (vm_bo) + return vm_bo; + + vm_bo = drm_gpuvm_bo_create(gpuvm, obj); + if (!vm_bo) + return ERR_PTR(-ENOMEM); + + drm_gem_gpuva_assert_lock_held(obj); + list_add_tail(&vm_bo->list.entry.gem, &obj->gpuva.list); + + return vm_bo; +} +EXPORT_SYMBOL_GPL(drm_gpuvm_bo_obtain); + +/** + * drm_gpuvm_bo_obtain_prealloc() - obtains and instance of the &drm_gpuvm_bo + * for the given &drm_gpuvm and &drm_gem_object + * @__vm_bo: A pre-allocated struct drm_gpuvm_bo. + * + * Find the &drm_gpuvm_bo representing the combination of the given + * &drm_gpuvm and &drm_gem_object. If found, increases the reference + * count of the found &drm_gpuvm_bo accordingly, while the @__vm_bo reference + * count is decreased. If not found @__vm_bo is returned without further + * increase of the reference count. + * + * A new &drm_gpuvm_bo is added to the GEMs gpuva list. + * + * Returns: a pointer to the found &drm_gpuvm_bo or @__vm_bo if no existing + * &drm_gpuvm_bo was found + */ +struct drm_gpuvm_bo * +drm_gpuvm_bo_obtain_prealloc(struct drm_gpuvm_bo *__vm_bo) +{ + struct drm_gpuvm *gpuvm = __vm_bo->vm; + struct drm_gem_object *obj = __vm_bo->obj; + struct drm_gpuvm_bo *vm_bo; + + vm_bo = drm_gpuvm_bo_find(gpuvm, obj); + if (vm_bo) { + drm_gpuvm_bo_put(__vm_bo); + return vm_bo; + } + + drm_gem_gpuva_assert_lock_held(obj); + list_add_tail(&__vm_bo->list.entry.gem, &obj->gpuva.list); + + return __vm_bo; +} +EXPORT_SYMBOL_GPL(drm_gpuvm_bo_obtain_prealloc); + +/** + * drm_gpuvm_bo_extobj_add() - adds the &drm_gpuvm_bo to its &drm_gpuvm's + * extobj list + * @vm_bo: The &drm_gpuvm_bo to add to its &drm_gpuvm's the extobj list. + * + * Adds the given @vm_bo to its &drm_gpuvm's extobj list if not on the list + * already and if the corresponding &drm_gem_object is an external object, + * actually. + */ +void +drm_gpuvm_bo_extobj_add(struct drm_gpuvm_bo *vm_bo) +{ + struct drm_gpuvm *gpuvm = vm_bo->vm; + bool lock = !drm_gpuvm_resv_protected(gpuvm); + + if (!lock) + drm_gpuvm_resv_assert_held(gpuvm); + + if (drm_gpuvm_is_extobj(gpuvm, vm_bo->obj)) + drm_gpuvm_bo_list_add(vm_bo, extobj, lock); +} +EXPORT_SYMBOL_GPL(drm_gpuvm_bo_extobj_add); + +/** + * drm_gpuvm_bo_evict() - add / remove a &drm_gpuvm_bo to / from the &drm_gpuvms + * evicted list + * @vm_bo: the &drm_gpuvm_bo to add or remove + * @evict: indicates whether the object is evicted + * + * Adds a &drm_gpuvm_bo to or removes it from the &drm_gpuvms evicted list. + */ +void +drm_gpuvm_bo_evict(struct drm_gpuvm_bo *vm_bo, bool evict) +{ + struct drm_gpuvm *gpuvm = vm_bo->vm; + struct drm_gem_object *obj = vm_bo->obj; + bool lock = !drm_gpuvm_resv_protected(gpuvm); + + dma_resv_assert_held(obj->resv); + vm_bo->evicted = evict; + + /* Can't add external objects to the evicted list directly if not using + * internal spinlocks, since in this case the evicted list is protected + * with the VM's common dma-resv lock. + */ + if (drm_gpuvm_is_extobj(gpuvm, obj) && !lock) + return; + + if (evict) + drm_gpuvm_bo_list_add(vm_bo, evict, lock); + else + drm_gpuvm_bo_list_del_init(vm_bo, evict, lock); +} +EXPORT_SYMBOL_GPL(drm_gpuvm_bo_evict); static int __drm_gpuva_insert(struct drm_gpuvm *gpuvm, @@ -764,11 +1760,21 @@ drm_gpuva_insert(struct drm_gpuvm *gpuvm, { u64 addr = va->va.addr; u64 range = va->va.range; + int ret; if (unlikely(!drm_gpuvm_range_valid(gpuvm, addr, range))) return -EINVAL; - return __drm_gpuva_insert(gpuvm, va); + ret = __drm_gpuva_insert(gpuvm, va); + if (likely(!ret)) + /* Take a reference of the GPUVM for the successfully inserted + * drm_gpuva. We can't take the reference in + * __drm_gpuva_insert() itself, since we don't want to increse + * the reference count for the GPUVM's kernel_alloc_node. + */ + drm_gpuvm_get(gpuvm); + + return ret; } EXPORT_SYMBOL_GPL(drm_gpuva_insert); @@ -795,35 +1801,46 @@ drm_gpuva_remove(struct drm_gpuva *va) struct drm_gpuvm *gpuvm = va->vm; if (unlikely(va == &gpuvm->kernel_alloc_node)) { - WARN(1, "Can't destroy kernel reserved node.\n"); + drm_WARN(gpuvm->drm, 1, + "Can't destroy kernel reserved node.\n"); return; } __drm_gpuva_remove(va); + drm_gpuvm_put(va->vm); } EXPORT_SYMBOL_GPL(drm_gpuva_remove); /** * drm_gpuva_link() - link a &drm_gpuva * @va: the &drm_gpuva to link + * @vm_bo: the &drm_gpuvm_bo to add the &drm_gpuva to * - * This adds the given &va to the GPU VA list of the &drm_gem_object it is - * associated with. + * This adds the given &va to the GPU VA list of the &drm_gpuvm_bo and the + * &drm_gpuvm_bo to the &drm_gem_object it is associated with. + * + * For every &drm_gpuva entry added to the &drm_gpuvm_bo an additional + * reference of the latter is taken. * * This function expects the caller to protect the GEM's GPUVA list against - * concurrent access using the GEMs dma_resv lock. + * concurrent access using either the GEMs dma_resv lock or a driver specific + * lock set through drm_gem_gpuva_set_lock(). */ void -drm_gpuva_link(struct drm_gpuva *va) +drm_gpuva_link(struct drm_gpuva *va, struct drm_gpuvm_bo *vm_bo) { struct drm_gem_object *obj = va->gem.obj; + struct drm_gpuvm *gpuvm = va->vm; if (unlikely(!obj)) return; - drm_gem_gpuva_assert_lock_held(obj); + drm_WARN_ON(gpuvm->drm, obj != vm_bo->obj); - list_add_tail(&va->gem.entry, &obj->gpuva.list); + va->vm_bo = drm_gpuvm_bo_get(vm_bo); + + drm_gem_gpuva_assert_lock_held(obj); + list_add_tail(&va->gem.entry, &vm_bo->list.gpuva); } EXPORT_SYMBOL_GPL(drm_gpuva_link); @@ -834,20 +1851,31 @@ EXPORT_SYMBOL_GPL(drm_gpuva_link); * This removes the given &va from the GPU VA list of the &drm_gem_object it is * associated with. * + * This removes the given &va from the GPU VA list of the &drm_gpuvm_bo and + * the &drm_gpuvm_bo from the &drm_gem_object it is associated with in case + * this call unlinks the last &drm_gpuva from the &drm_gpuvm_bo. + * + * For every &drm_gpuva entry removed from the &drm_gpuvm_bo a reference of + * the latter is dropped. + * * This function expects the caller to protect the GEM's GPUVA list against - * concurrent access using the GEMs dma_resv lock. + * concurrent access using either the GEMs dma_resv lock or a driver specific + * lock set through drm_gem_gpuva_set_lock(). */ void drm_gpuva_unlink(struct drm_gpuva *va) { struct drm_gem_object *obj = va->gem.obj; + struct drm_gpuvm_bo *vm_bo = va->vm_bo; if (unlikely(!obj)) return; drm_gem_gpuva_assert_lock_held(obj); - list_del_init(&va->gem.entry); + + va->vm_bo = NULL; + drm_gpuvm_bo_put(vm_bo); } EXPORT_SYMBOL_GPL(drm_gpuva_unlink); @@ -992,10 +2020,10 @@ drm_gpuva_remap(struct drm_gpuva *prev, struct drm_gpuva *next, struct drm_gpuva_op_remap *op) { - struct drm_gpuva *curr = op->unmap->va; - struct drm_gpuvm *gpuvm = curr->vm; + struct drm_gpuva *va = op->unmap->va; + struct drm_gpuvm *gpuvm = va->vm; - drm_gpuva_remove(curr); + drm_gpuva_remove(va); if (op->prev) { drm_gpuva_init_from_op(prev, op->prev); @@ -1637,9 +2665,8 @@ err_free_ops: EXPORT_SYMBOL_GPL(drm_gpuvm_prefetch_ops_create); /** - * drm_gpuvm_gem_unmap_ops_create() - creates the &drm_gpuva_ops to unmap a GEM - * @gpuvm: the &drm_gpuvm representing the GPU VA space - * @obj: the &drm_gem_object to unmap + * drm_gpuvm_bo_unmap_ops_create() - creates the &drm_gpuva_ops to unmap a GEM + * @vm_bo: the &drm_gpuvm_bo abstraction * * This function creates a list of operations to perform unmapping for every * GPUVA attached to a GEM. @@ -1656,15 +2683,14 @@ EXPORT_SYMBOL_GPL(drm_gpuvm_prefetch_ops_create); * Returns: a pointer to the &drm_gpuva_ops on success, an ERR_PTR on failure */ struct drm_gpuva_ops * -drm_gpuvm_gem_unmap_ops_create(struct drm_gpuvm *gpuvm, - struct drm_gem_object *obj) +drm_gpuvm_bo_unmap_ops_create(struct drm_gpuvm_bo *vm_bo) { struct drm_gpuva_ops *ops; struct drm_gpuva_op *op; struct drm_gpuva *va; int ret; - drm_gem_gpuva_assert_lock_held(obj); + drm_gem_gpuva_assert_lock_held(vm_bo->obj); ops = kzalloc(sizeof(*ops), GFP_KERNEL); if (!ops) @@ -1672,8 +2698,8 @@ drm_gpuvm_gem_unmap_ops_create(struct drm_gpuvm *gpuvm, INIT_LIST_HEAD(&ops->list); - drm_gem_for_each_gpuva(va, obj) { - op = gpuva_op_alloc(gpuvm); + drm_gpuvm_bo_for_each_va(va, vm_bo) { + op = gpuva_op_alloc(vm_bo->vm); if (!op) { ret = -ENOMEM; goto err_free_ops; @@ -1687,10 +2713,10 @@ drm_gpuvm_gem_unmap_ops_create(struct drm_gpuvm *gpuvm, return ops; err_free_ops: - drm_gpuva_ops_free(gpuvm, ops); + drm_gpuva_ops_free(vm_bo->vm, ops); return ERR_PTR(ret); } -EXPORT_SYMBOL_GPL(drm_gpuvm_gem_unmap_ops_create); +EXPORT_SYMBOL_GPL(drm_gpuvm_bo_unmap_ops_create); /** * drm_gpuva_ops_free() - free the given &drm_gpuva_ops diff --git a/drivers/gpu/drm/drm_hashtab.c b/drivers/gpu/drm/drm_hashtab.c deleted file mode 100644 index 60afa186555994..00000000000000 --- a/drivers/gpu/drm/drm_hashtab.c +++ /dev/null @@ -1,203 +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. - * - * - **************************************************************************/ -/* - * Simple open hash tab implementation. - * - * Authors: - * Thomas Hellström - */ - -#include -#include -#include -#include -#include - -#include - -#include "drm_legacy.h" - -int drm_ht_create(struct drm_open_hash *ht, unsigned int order) -{ - unsigned int size = 1 << order; - - ht->order = order; - ht->table = NULL; - if (size <= PAGE_SIZE / sizeof(*ht->table)) - ht->table = kcalloc(size, sizeof(*ht->table), GFP_KERNEL); - else - ht->table = vzalloc(array_size(size, sizeof(*ht->table))); - if (!ht->table) { - DRM_ERROR("Out of memory for hash table\n"); - return -ENOMEM; - } - return 0; -} - -void drm_ht_verbose_list(struct drm_open_hash *ht, unsigned long key) -{ - struct drm_hash_item *entry; - struct hlist_head *h_list; - unsigned int hashed_key; - int count = 0; - - hashed_key = hash_long(key, ht->order); - DRM_DEBUG("Key is 0x%08lx, Hashed key is 0x%08x\n", key, hashed_key); - h_list = &ht->table[hashed_key]; - hlist_for_each_entry(entry, h_list, head) - DRM_DEBUG("count %d, key: 0x%08lx\n", count++, entry->key); -} - -static struct hlist_node *drm_ht_find_key(struct drm_open_hash *ht, - unsigned long key) -{ - struct drm_hash_item *entry; - struct hlist_head *h_list; - unsigned int hashed_key; - - hashed_key = hash_long(key, ht->order); - h_list = &ht->table[hashed_key]; - hlist_for_each_entry(entry, h_list, head) { - if (entry->key == key) - return &entry->head; - if (entry->key > key) - break; - } - return NULL; -} - -static struct hlist_node *drm_ht_find_key_rcu(struct drm_open_hash *ht, - unsigned long key) -{ - struct drm_hash_item *entry; - struct hlist_head *h_list; - unsigned int hashed_key; - - hashed_key = hash_long(key, ht->order); - h_list = &ht->table[hashed_key]; - hlist_for_each_entry_rcu(entry, h_list, head) { - if (entry->key == key) - return &entry->head; - if (entry->key > key) - break; - } - return NULL; -} - -int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item) -{ - struct drm_hash_item *entry; - struct hlist_head *h_list; - struct hlist_node *parent; - unsigned int hashed_key; - unsigned long key = item->key; - - hashed_key = hash_long(key, ht->order); - h_list = &ht->table[hashed_key]; - parent = NULL; - hlist_for_each_entry(entry, h_list, head) { - if (entry->key == key) - return -EINVAL; - if (entry->key > key) - break; - parent = &entry->head; - } - if (parent) { - hlist_add_behind_rcu(&item->head, parent); - } else { - hlist_add_head_rcu(&item->head, h_list); - } - return 0; -} - -/* - * Just insert an item and return any "bits" bit key that hasn't been - * used before. - */ -int drm_ht_just_insert_please(struct drm_open_hash *ht, struct drm_hash_item *item, - unsigned long seed, int bits, int shift, - unsigned long add) -{ - int ret; - unsigned long mask = (1UL << bits) - 1; - unsigned long first, unshifted_key; - - unshifted_key = hash_long(seed, bits); - first = unshifted_key; - do { - item->key = (unshifted_key << shift) + add; - ret = drm_ht_insert_item(ht, item); - if (ret) - unshifted_key = (unshifted_key + 1) & mask; - } while(ret && (unshifted_key != first)); - - if (ret) { - DRM_ERROR("Available key bit space exhausted\n"); - return -EINVAL; - } - return 0; -} - -int drm_ht_find_item(struct drm_open_hash *ht, unsigned long key, - struct drm_hash_item **item) -{ - struct hlist_node *list; - - list = drm_ht_find_key_rcu(ht, key); - if (!list) - return -EINVAL; - - *item = hlist_entry(list, struct drm_hash_item, head); - return 0; -} - -int drm_ht_remove_key(struct drm_open_hash *ht, unsigned long key) -{ - struct hlist_node *list; - - list = drm_ht_find_key(ht, key); - if (list) { - hlist_del_init_rcu(list); - return 0; - } - return -EINVAL; -} - -int drm_ht_remove_item(struct drm_open_hash *ht, struct drm_hash_item *item) -{ - hlist_del_init_rcu(&item->head); - return 0; -} - -void drm_ht_remove(struct drm_open_hash *ht) -{ - if (ht->table) { - kvfree(ht->table); - ht->table = NULL; - } -} diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index 8462b657c37586..8e4faf0a28e6cf 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -22,6 +22,7 @@ */ #include +#include #include #include @@ -31,6 +32,7 @@ #define DRM_IF_VERSION(maj, min) (maj << 16 | min) +struct cea_sad; struct dentry; struct dma_buf; struct iosys_map; @@ -115,17 +117,10 @@ void drm_handle_vblank_works(struct drm_vblank_crtc *vblank); /* IOCTLS */ int drm_wait_vblank_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); -int drm_legacy_modeset_ctl_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); /* drm_irq.c */ /* IOCTLS */ -#if IS_ENABLED(CONFIG_DRM_LEGACY) -int drm_legacy_irq_control(struct drm_device *dev, void *data, - struct drm_file *file_priv); -#endif - int drm_crtc_get_sequence_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); @@ -192,6 +187,8 @@ void drm_debugfs_connector_remove(struct drm_connector *connector); void drm_debugfs_crtc_add(struct drm_crtc *crtc); void drm_debugfs_crtc_remove(struct drm_crtc *crtc); void drm_debugfs_crtc_crc_add(struct drm_crtc *crtc); +void drm_debugfs_encoder_add(struct drm_encoder *encoder); +void drm_debugfs_encoder_remove(struct drm_encoder *encoder); #else static inline void drm_debugfs_dev_fini(struct drm_device *dev) { @@ -229,6 +226,14 @@ static inline void drm_debugfs_crtc_crc_add(struct drm_crtc *crtc) { } +static inline void drm_debugfs_encoder_add(struct drm_encoder *encoder) +{ +} + +static inline void drm_debugfs_encoder_remove(struct drm_encoder *encoder) +{ +} + #endif drm_ioctl_t drm_version; @@ -267,3 +272,7 @@ int drm_syncobj_query_ioctl(struct drm_device *dev, void *data, void drm_framebuffer_print_info(struct drm_printer *p, unsigned int indent, const struct drm_framebuffer *fb); void drm_framebuffer_debugfs_init(struct drm_device *dev); + +/* drm_edid.c */ +void drm_edid_cta_sad_get(const struct cea_sad *cta_sad, u8 *sad); +void drm_edid_cta_sad_set(struct cea_sad *cta_sad, const u8 *sad); diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c index 025dc558c94ee1..129e2b91dbfe7f 100644 --- a/drivers/gpu/drm/drm_ioc32.c +++ b/drivers/gpu/drm/drm_ioc32.c @@ -31,12 +31,12 @@ #include #include +#include #include #include #include "drm_crtc_internal.h" #include "drm_internal.h" -#include "drm_legacy.h" #define DRM_IOCTL_VERSION32 DRM_IOWR(0x00, drm_version32_t) #define DRM_IOCTL_GET_UNIQUE32 DRM_IOWR(0x01, drm_unique32_t) @@ -163,92 +163,6 @@ static int compat_drm_setunique(struct file *file, unsigned int cmd, return -EINVAL; } -#if IS_ENABLED(CONFIG_DRM_LEGACY) -typedef struct drm_map32 { - u32 offset; /* Requested physical address (0 for SAREA) */ - u32 size; /* Requested physical size (bytes) */ - enum drm_map_type type; /* Type of memory to map */ - enum drm_map_flags flags; /* Flags */ - u32 handle; /* User-space: "Handle" to pass to mmap() */ - int mtrr; /* MTRR slot used */ -} drm_map32_t; - -static int compat_drm_getmap(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_map32_t __user *argp = (void __user *)arg; - drm_map32_t m32; - struct drm_map map; - int err; - - if (copy_from_user(&m32, argp, sizeof(m32))) - return -EFAULT; - - map.offset = m32.offset; - err = drm_ioctl_kernel(file, drm_legacy_getmap_ioctl, &map, 0); - if (err) - return err; - - m32.offset = map.offset; - m32.size = map.size; - m32.type = map.type; - m32.flags = map.flags; - m32.handle = ptr_to_compat((void __user *)map.handle); - m32.mtrr = map.mtrr; - if (copy_to_user(argp, &m32, sizeof(m32))) - return -EFAULT; - return 0; - -} - -static int compat_drm_addmap(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_map32_t __user *argp = (void __user *)arg; - drm_map32_t m32; - struct drm_map map; - int err; - - if (copy_from_user(&m32, argp, sizeof(m32))) - return -EFAULT; - - map.offset = m32.offset; - map.size = m32.size; - map.type = m32.type; - map.flags = m32.flags; - - err = drm_ioctl_kernel(file, drm_legacy_addmap_ioctl, &map, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY); - if (err) - return err; - - m32.offset = map.offset; - m32.mtrr = map.mtrr; - m32.handle = ptr_to_compat((void __user *)map.handle); - if (map.handle != compat_ptr(m32.handle)) - pr_err_ratelimited("compat_drm_addmap truncated handle %p for type %d offset %x\n", - map.handle, m32.type, m32.offset); - - if (copy_to_user(argp, &m32, sizeof(m32))) - return -EFAULT; - - return 0; -} - -static int compat_drm_rmmap(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_map32_t __user *argp = (void __user *)arg; - struct drm_map map; - u32 handle; - - if (get_user(handle, &argp->handle)) - return -EFAULT; - map.handle = compat_ptr(handle); - return drm_ioctl_kernel(file, drm_legacy_rmmap_ioctl, &map, DRM_AUTH); -} -#endif - typedef struct drm_client32 { int idx; /* Which client desired? */ int auth; /* Is client authenticated? */ @@ -308,501 +222,6 @@ static int compat_drm_getstats(struct file *file, unsigned int cmd, return 0; } -#if IS_ENABLED(CONFIG_DRM_LEGACY) -typedef struct drm_buf_desc32 { - int count; /* Number of buffers of this size */ - int size; /* Size in bytes */ - int low_mark; /* Low water mark */ - int high_mark; /* High water mark */ - int flags; - u32 agp_start; /* Start address in the AGP aperture */ -} drm_buf_desc32_t; - -static int compat_drm_addbufs(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_buf_desc32_t __user *argp = (void __user *)arg; - drm_buf_desc32_t desc32; - struct drm_buf_desc desc; - int err; - - if (copy_from_user(&desc32, argp, sizeof(drm_buf_desc32_t))) - return -EFAULT; - - desc = (struct drm_buf_desc){ - desc32.count, desc32.size, desc32.low_mark, desc32.high_mark, - desc32.flags, desc32.agp_start - }; - - err = drm_ioctl_kernel(file, drm_legacy_addbufs, &desc, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY); - if (err) - return err; - - desc32 = (drm_buf_desc32_t){ - desc.count, desc.size, desc.low_mark, desc.high_mark, - desc.flags, desc.agp_start - }; - if (copy_to_user(argp, &desc32, sizeof(drm_buf_desc32_t))) - return -EFAULT; - - return 0; -} - -static int compat_drm_markbufs(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_buf_desc32_t b32; - drm_buf_desc32_t __user *argp = (void __user *)arg; - struct drm_buf_desc buf; - - if (copy_from_user(&b32, argp, sizeof(b32))) - return -EFAULT; - - buf.size = b32.size; - buf.low_mark = b32.low_mark; - buf.high_mark = b32.high_mark; - - return drm_ioctl_kernel(file, drm_legacy_markbufs, &buf, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY); -} - -typedef struct drm_buf_info32 { - int count; /**< Entries in list */ - u32 list; -} drm_buf_info32_t; - -static int copy_one_buf32(void *data, int count, struct drm_buf_entry *from) -{ - drm_buf_info32_t *request = data; - drm_buf_desc32_t __user *to = compat_ptr(request->list); - drm_buf_desc32_t v = {.count = from->buf_count, - .size = from->buf_size, - .low_mark = from->low_mark, - .high_mark = from->high_mark}; - - if (copy_to_user(to + count, &v, offsetof(drm_buf_desc32_t, flags))) - return -EFAULT; - return 0; -} - -static int drm_legacy_infobufs32(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - drm_buf_info32_t *request = data; - - return __drm_legacy_infobufs(dev, data, &request->count, copy_one_buf32); -} - -static int compat_drm_infobufs(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_buf_info32_t req32; - drm_buf_info32_t __user *argp = (void __user *)arg; - int err; - - if (copy_from_user(&req32, argp, sizeof(req32))) - return -EFAULT; - - if (req32.count < 0) - req32.count = 0; - - err = drm_ioctl_kernel(file, drm_legacy_infobufs32, &req32, DRM_AUTH); - if (err) - return err; - - if (put_user(req32.count, &argp->count)) - return -EFAULT; - - return 0; -} - -typedef struct drm_buf_pub32 { - int idx; /**< Index into the master buffer list */ - int total; /**< Buffer size */ - int used; /**< Amount of buffer in use (for DMA) */ - u32 address; /**< Address of buffer */ -} drm_buf_pub32_t; - -typedef struct drm_buf_map32 { - int count; /**< Length of the buffer list */ - u32 virtual; /**< Mmap'd area in user-virtual */ - u32 list; /**< Buffer information */ -} drm_buf_map32_t; - -static int map_one_buf32(void *data, int idx, unsigned long virtual, - struct drm_buf *buf) -{ - drm_buf_map32_t *request = data; - drm_buf_pub32_t __user *to = compat_ptr(request->list) + idx; - drm_buf_pub32_t v; - - v.idx = buf->idx; - v.total = buf->total; - v.used = 0; - v.address = virtual + buf->offset; - if (copy_to_user(to, &v, sizeof(v))) - return -EFAULT; - return 0; -} - -static int drm_legacy_mapbufs32(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - drm_buf_map32_t *request = data; - void __user *v; - int err = __drm_legacy_mapbufs(dev, data, &request->count, - &v, map_one_buf32, - file_priv); - request->virtual = ptr_to_compat(v); - return err; -} - -static int compat_drm_mapbufs(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_buf_map32_t __user *argp = (void __user *)arg; - drm_buf_map32_t req32; - int err; - - if (copy_from_user(&req32, argp, sizeof(req32))) - return -EFAULT; - if (req32.count < 0) - return -EINVAL; - - err = drm_ioctl_kernel(file, drm_legacy_mapbufs32, &req32, DRM_AUTH); - if (err) - return err; - - if (put_user(req32.count, &argp->count) - || put_user(req32.virtual, &argp->virtual)) - return -EFAULT; - - return 0; -} - -typedef struct drm_buf_free32 { - int count; - u32 list; -} drm_buf_free32_t; - -static int compat_drm_freebufs(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_buf_free32_t req32; - struct drm_buf_free request; - drm_buf_free32_t __user *argp = (void __user *)arg; - - if (copy_from_user(&req32, argp, sizeof(req32))) - return -EFAULT; - - request.count = req32.count; - request.list = compat_ptr(req32.list); - return drm_ioctl_kernel(file, drm_legacy_freebufs, &request, DRM_AUTH); -} - -typedef struct drm_ctx_priv_map32 { - unsigned int ctx_id; /**< Context requesting private mapping */ - u32 handle; /**< Handle of map */ -} drm_ctx_priv_map32_t; - -static int compat_drm_setsareactx(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_ctx_priv_map32_t req32; - struct drm_ctx_priv_map request; - drm_ctx_priv_map32_t __user *argp = (void __user *)arg; - - if (copy_from_user(&req32, argp, sizeof(req32))) - return -EFAULT; - - request.ctx_id = req32.ctx_id; - request.handle = compat_ptr(req32.handle); - return drm_ioctl_kernel(file, drm_legacy_setsareactx, &request, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY); -} - -static int compat_drm_getsareactx(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct drm_ctx_priv_map req; - drm_ctx_priv_map32_t req32; - drm_ctx_priv_map32_t __user *argp = (void __user *)arg; - int err; - - if (copy_from_user(&req32, argp, sizeof(req32))) - return -EFAULT; - - req.ctx_id = req32.ctx_id; - err = drm_ioctl_kernel(file, drm_legacy_getsareactx, &req, DRM_AUTH); - if (err) - return err; - - req32.handle = ptr_to_compat((void __user *)req.handle); - if (copy_to_user(argp, &req32, sizeof(req32))) - return -EFAULT; - - return 0; -} - -typedef struct drm_ctx_res32 { - int count; - u32 contexts; -} drm_ctx_res32_t; - -static int compat_drm_resctx(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_ctx_res32_t __user *argp = (void __user *)arg; - drm_ctx_res32_t res32; - struct drm_ctx_res res; - int err; - - if (copy_from_user(&res32, argp, sizeof(res32))) - return -EFAULT; - - res.count = res32.count; - res.contexts = compat_ptr(res32.contexts); - err = drm_ioctl_kernel(file, drm_legacy_resctx, &res, DRM_AUTH); - if (err) - return err; - - res32.count = res.count; - if (copy_to_user(argp, &res32, sizeof(res32))) - return -EFAULT; - - return 0; -} - -typedef struct drm_dma32 { - int context; /**< Context handle */ - int send_count; /**< Number of buffers to send */ - u32 send_indices; /**< List of handles to buffers */ - u32 send_sizes; /**< Lengths of data to send */ - enum drm_dma_flags flags; /**< Flags */ - int request_count; /**< Number of buffers requested */ - int request_size; /**< Desired size for buffers */ - u32 request_indices; /**< Buffer information */ - u32 request_sizes; - int granted_count; /**< Number of buffers granted */ -} drm_dma32_t; - -static int compat_drm_dma(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_dma32_t d32; - drm_dma32_t __user *argp = (void __user *)arg; - struct drm_dma d; - int err; - - if (copy_from_user(&d32, argp, sizeof(d32))) - return -EFAULT; - - d.context = d32.context; - d.send_count = d32.send_count; - d.send_indices = compat_ptr(d32.send_indices); - d.send_sizes = compat_ptr(d32.send_sizes); - d.flags = d32.flags; - d.request_count = d32.request_count; - d.request_indices = compat_ptr(d32.request_indices); - d.request_sizes = compat_ptr(d32.request_sizes); - err = drm_ioctl_kernel(file, drm_legacy_dma_ioctl, &d, DRM_AUTH); - if (err) - return err; - - if (put_user(d.request_size, &argp->request_size) - || put_user(d.granted_count, &argp->granted_count)) - return -EFAULT; - - return 0; -} -#endif - -#if IS_ENABLED(CONFIG_DRM_LEGACY) -#if IS_ENABLED(CONFIG_AGP) -typedef struct drm_agp_mode32 { - u32 mode; /**< AGP mode */ -} drm_agp_mode32_t; - -static int compat_drm_agp_enable(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_agp_mode32_t __user *argp = (void __user *)arg; - struct drm_agp_mode mode; - - if (get_user(mode.mode, &argp->mode)) - return -EFAULT; - - return drm_ioctl_kernel(file, drm_legacy_agp_enable_ioctl, &mode, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY); -} - -typedef struct drm_agp_info32 { - int agp_version_major; - int agp_version_minor; - u32 mode; - u32 aperture_base; /* physical address */ - u32 aperture_size; /* bytes */ - u32 memory_allowed; /* bytes */ - u32 memory_used; - - /* PCI information */ - unsigned short id_vendor; - unsigned short id_device; -} drm_agp_info32_t; - -static int compat_drm_agp_info(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_agp_info32_t __user *argp = (void __user *)arg; - drm_agp_info32_t i32; - struct drm_agp_info info; - int err; - - err = drm_ioctl_kernel(file, drm_legacy_agp_info_ioctl, &info, DRM_AUTH); - if (err) - return err; - - i32.agp_version_major = info.agp_version_major; - i32.agp_version_minor = info.agp_version_minor; - i32.mode = info.mode; - i32.aperture_base = info.aperture_base; - i32.aperture_size = info.aperture_size; - i32.memory_allowed = info.memory_allowed; - i32.memory_used = info.memory_used; - i32.id_vendor = info.id_vendor; - i32.id_device = info.id_device; - if (copy_to_user(argp, &i32, sizeof(i32))) - return -EFAULT; - - return 0; -} - -typedef struct drm_agp_buffer32 { - u32 size; /**< In bytes -- will round to page boundary */ - u32 handle; /**< Used for binding / unbinding */ - u32 type; /**< Type of memory to allocate */ - u32 physical; /**< Physical used by i810 */ -} drm_agp_buffer32_t; - -static int compat_drm_agp_alloc(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_agp_buffer32_t __user *argp = (void __user *)arg; - drm_agp_buffer32_t req32; - struct drm_agp_buffer request; - int err; - - if (copy_from_user(&req32, argp, sizeof(req32))) - return -EFAULT; - - request.size = req32.size; - request.type = req32.type; - err = drm_ioctl_kernel(file, drm_legacy_agp_alloc_ioctl, &request, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY); - if (err) - return err; - - req32.handle = request.handle; - req32.physical = request.physical; - if (copy_to_user(argp, &req32, sizeof(req32))) { - drm_ioctl_kernel(file, drm_legacy_agp_free_ioctl, &request, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY); - return -EFAULT; - } - - return 0; -} - -static int compat_drm_agp_free(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_agp_buffer32_t __user *argp = (void __user *)arg; - struct drm_agp_buffer request; - - if (get_user(request.handle, &argp->handle)) - return -EFAULT; - - return drm_ioctl_kernel(file, drm_legacy_agp_free_ioctl, &request, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY); -} - -typedef struct drm_agp_binding32 { - u32 handle; /**< From drm_agp_buffer */ - u32 offset; /**< In bytes -- will round to page boundary */ -} drm_agp_binding32_t; - -static int compat_drm_agp_bind(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_agp_binding32_t __user *argp = (void __user *)arg; - drm_agp_binding32_t req32; - struct drm_agp_binding request; - - if (copy_from_user(&req32, argp, sizeof(req32))) - return -EFAULT; - - request.handle = req32.handle; - request.offset = req32.offset; - return drm_ioctl_kernel(file, drm_legacy_agp_bind_ioctl, &request, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY); -} - -static int compat_drm_agp_unbind(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_agp_binding32_t __user *argp = (void __user *)arg; - struct drm_agp_binding request; - - if (get_user(request.handle, &argp->handle)) - return -EFAULT; - - return drm_ioctl_kernel(file, drm_legacy_agp_unbind_ioctl, &request, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY); -} -#endif /* CONFIG_AGP */ - -typedef struct drm_scatter_gather32 { - u32 size; /**< In bytes -- will round to page boundary */ - u32 handle; /**< Used for mapping / unmapping */ -} drm_scatter_gather32_t; - -static int compat_drm_sg_alloc(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_scatter_gather32_t __user *argp = (void __user *)arg; - struct drm_scatter_gather request; - int err; - - if (get_user(request.size, &argp->size)) - return -EFAULT; - - err = drm_ioctl_kernel(file, drm_legacy_sg_alloc, &request, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY); - if (err) - return err; - - /* XXX not sure about the handle conversion here... */ - if (put_user(request.handle >> PAGE_SHIFT, &argp->handle)) - return -EFAULT; - - return 0; -} - -static int compat_drm_sg_free(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_scatter_gather32_t __user *argp = (void __user *)arg; - struct drm_scatter_gather request; - unsigned long x; - - if (get_user(x, &argp->handle)) - return -EFAULT; - request.handle = x << PAGE_SHIFT; - return drm_ioctl_kernel(file, drm_legacy_sg_free, &request, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY); -} -#endif #if defined(CONFIG_X86) typedef struct drm_update_draw32 { drm_drawable_t handle; @@ -854,7 +273,7 @@ static int compat_drm_wait_vblank(struct file *file, unsigned int cmd, req.request.type = req32.request.type; req.request.sequence = req32.request.sequence; req.request.signal = req32.request.signal; - err = drm_ioctl_kernel(file, drm_wait_vblank_ioctl, &req, DRM_UNLOCKED); + err = drm_ioctl_kernel(file, drm_wait_vblank_ioctl, &req, 0); req32.reply.type = req.reply.type; req32.reply.sequence = req.reply.sequence; @@ -914,37 +333,9 @@ static struct { #define DRM_IOCTL32_DEF(n, f) [DRM_IOCTL_NR(n##32)] = {.fn = f, .name = #n} DRM_IOCTL32_DEF(DRM_IOCTL_VERSION, compat_drm_version), DRM_IOCTL32_DEF(DRM_IOCTL_GET_UNIQUE, compat_drm_getunique), -#if IS_ENABLED(CONFIG_DRM_LEGACY) - DRM_IOCTL32_DEF(DRM_IOCTL_GET_MAP, compat_drm_getmap), -#endif DRM_IOCTL32_DEF(DRM_IOCTL_GET_CLIENT, compat_drm_getclient), DRM_IOCTL32_DEF(DRM_IOCTL_GET_STATS, compat_drm_getstats), DRM_IOCTL32_DEF(DRM_IOCTL_SET_UNIQUE, compat_drm_setunique), -#if IS_ENABLED(CONFIG_DRM_LEGACY) - DRM_IOCTL32_DEF(DRM_IOCTL_ADD_MAP, compat_drm_addmap), - DRM_IOCTL32_DEF(DRM_IOCTL_ADD_BUFS, compat_drm_addbufs), - DRM_IOCTL32_DEF(DRM_IOCTL_MARK_BUFS, compat_drm_markbufs), - DRM_IOCTL32_DEF(DRM_IOCTL_INFO_BUFS, compat_drm_infobufs), - DRM_IOCTL32_DEF(DRM_IOCTL_MAP_BUFS, compat_drm_mapbufs), - DRM_IOCTL32_DEF(DRM_IOCTL_FREE_BUFS, compat_drm_freebufs), - DRM_IOCTL32_DEF(DRM_IOCTL_RM_MAP, compat_drm_rmmap), - DRM_IOCTL32_DEF(DRM_IOCTL_SET_SAREA_CTX, compat_drm_setsareactx), - DRM_IOCTL32_DEF(DRM_IOCTL_GET_SAREA_CTX, compat_drm_getsareactx), - DRM_IOCTL32_DEF(DRM_IOCTL_RES_CTX, compat_drm_resctx), - DRM_IOCTL32_DEF(DRM_IOCTL_DMA, compat_drm_dma), -#if IS_ENABLED(CONFIG_AGP) - DRM_IOCTL32_DEF(DRM_IOCTL_AGP_ENABLE, compat_drm_agp_enable), - DRM_IOCTL32_DEF(DRM_IOCTL_AGP_INFO, compat_drm_agp_info), - DRM_IOCTL32_DEF(DRM_IOCTL_AGP_ALLOC, compat_drm_agp_alloc), - DRM_IOCTL32_DEF(DRM_IOCTL_AGP_FREE, compat_drm_agp_free), - DRM_IOCTL32_DEF(DRM_IOCTL_AGP_BIND, compat_drm_agp_bind), - DRM_IOCTL32_DEF(DRM_IOCTL_AGP_UNBIND, compat_drm_agp_unbind), -#endif -#endif -#if IS_ENABLED(CONFIG_DRM_LEGACY) - DRM_IOCTL32_DEF(DRM_IOCTL_SG_ALLOC, compat_drm_sg_alloc), - DRM_IOCTL32_DEF(DRM_IOCTL_SG_FREE, compat_drm_sg_free), -#endif #if defined(CONFIG_X86) DRM_IOCTL32_DEF(DRM_IOCTL_UPDATE_DRAW, compat_drm_update_draw), #endif diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 77590b0f38fa38..e368fc084c77d4 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -42,7 +42,6 @@ #include "drm_crtc_internal.h" #include "drm_internal.h" -#include "drm_legacy.h" /** * DOC: getunique and setversion story @@ -301,6 +300,10 @@ static int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_ case DRM_CAP_CRTC_IN_VBLANK_EVENT: req->value = 1; break; + case DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP: + req->value = drm_core_check_feature(dev, DRIVER_ATOMIC) && + dev->mode_config.async_page_flip; + break; default: return -EINVAL; } @@ -361,6 +364,15 @@ drm_setclientcap(struct drm_device *dev, void *data, struct drm_file *file_priv) return -EINVAL; file_priv->writeback_connectors = req->value; break; + case DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT: + if (!drm_core_check_feature(dev, DRIVER_CURSOR_HOTSPOT)) + return -EOPNOTSUPP; + if (!file_priv->atomic) + return -EINVAL; + if (req->value > 1) + return -EINVAL; + file_priv->supports_virtualized_cursor_plane = req->value; + break; default: return -EINVAL; } @@ -559,21 +571,11 @@ static int drm_ioctl_permit(u32 flags, struct drm_file *file_priv) .name = #ioctl \ } -#if IS_ENABLED(CONFIG_DRM_LEGACY) -#define DRM_LEGACY_IOCTL_DEF(ioctl, _func, _flags) DRM_IOCTL_DEF(ioctl, _func, _flags) -#else -#define DRM_LEGACY_IOCTL_DEF(ioctl, _func, _flags) DRM_IOCTL_DEF(ioctl, drm_invalid_op, _flags) -#endif - /* Ioctl table */ static const struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, DRM_RENDER_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_GET_UNIQUE, drm_getunique, 0), DRM_IOCTL_DEF(DRM_IOCTL_GET_MAGIC, drm_getmagic, 0), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_IRQ_BUSID, drm_legacy_irq_by_busid, - DRM_MASTER|DRM_ROOT_ONLY), - - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_GET_MAP, drm_legacy_getmap_ioctl, 0), DRM_IOCTL_DEF(DRM_IOCTL_GET_CLIENT, drm_getclient, 0), DRM_IOCTL_DEF(DRM_IOCTL_GET_STATS, drm_getstats, 0), @@ -586,63 +588,15 @@ static const struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_UNBLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_AUTH_MAGIC, drm_authmagic, DRM_MASTER), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_ADD_MAP, drm_legacy_addmap_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_RM_MAP, drm_legacy_rmmap_ioctl, DRM_AUTH), - - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_SET_SAREA_CTX, drm_legacy_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_GET_SAREA_CTX, drm_legacy_getsareactx, DRM_AUTH), - DRM_IOCTL_DEF(DRM_IOCTL_SET_MASTER, drm_setmaster_ioctl, 0), DRM_IOCTL_DEF(DRM_IOCTL_DROP_MASTER, drm_dropmaster_ioctl, 0), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_ADD_CTX, drm_legacy_addctx, DRM_AUTH|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_RM_CTX, drm_legacy_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_MOD_CTX, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_GET_CTX, drm_legacy_getctx, DRM_AUTH), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_SWITCH_CTX, drm_legacy_switchctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_NEW_CTX, drm_legacy_newctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_RES_CTX, drm_legacy_resctx, DRM_AUTH), - DRM_IOCTL_DEF(DRM_IOCTL_ADD_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_RM_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_LOCK, drm_legacy_lock, DRM_AUTH), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_UNLOCK, drm_legacy_unlock, DRM_AUTH), - DRM_IOCTL_DEF(DRM_IOCTL_FINISH, drm_noop, DRM_AUTH), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_ADD_BUFS, drm_legacy_addbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_MARK_BUFS, drm_legacy_markbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_INFO_BUFS, drm_legacy_infobufs, DRM_AUTH), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_MAP_BUFS, drm_legacy_mapbufs, DRM_AUTH), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_FREE_BUFS, drm_legacy_freebufs, DRM_AUTH), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_DMA, drm_legacy_dma_ioctl, DRM_AUTH), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_CONTROL, drm_legacy_irq_control, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - -#if IS_ENABLED(CONFIG_AGP) - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_ACQUIRE, drm_legacy_agp_acquire_ioctl, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_RELEASE, drm_legacy_agp_release_ioctl, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_ENABLE, drm_legacy_agp_enable_ioctl, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_INFO, drm_legacy_agp_info_ioctl, DRM_AUTH), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_ALLOC, drm_legacy_agp_alloc_ioctl, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_FREE, drm_legacy_agp_free_ioctl, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_BIND, drm_legacy_agp_bind_ioctl, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_UNBIND, drm_legacy_agp_unbind_ioctl, - DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), -#endif - - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_SG_ALLOC, drm_legacy_sg_alloc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_SG_FREE, drm_legacy_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - - DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank_ioctl, DRM_UNLOCKED), - - DRM_IOCTL_DEF(DRM_IOCTL_MODESET_CTL, drm_legacy_modeset_ctl_ioctl, 0), + DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank_ioctl, 0), DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), @@ -675,6 +629,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb_ioctl, 0), DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2_ioctl, 0), DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb_ioctl, 0), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_CLOSEFB, drm_mode_closefb_ioctl, 0), DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER), DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER), DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, 0), @@ -774,7 +729,7 @@ long drm_ioctl_kernel(struct file *file, drm_ioctl_t *func, void *kdata, { struct drm_file *file_priv = file->private_data; struct drm_device *dev = file_priv->minor->dev; - int retcode; + int ret; /* Update drm_file owner if fd was passed along. */ drm_file_update_pid(file_priv); @@ -782,20 +737,11 @@ long drm_ioctl_kernel(struct file *file, drm_ioctl_t *func, void *kdata, if (drm_dev_is_unplugged(dev)) return -ENODEV; - retcode = drm_ioctl_permit(flags, file_priv); - if (unlikely(retcode)) - return retcode; - - /* Enforce sane locking for modern driver ioctls. */ - if (likely(!drm_core_check_feature(dev, DRIVER_LEGACY)) || - (flags & DRM_UNLOCKED)) - retcode = func(dev, kdata, file_priv); - else { - mutex_lock(&drm_global_mutex); - retcode = func(dev, kdata, file_priv); - mutex_unlock(&drm_global_mutex); - } - return retcode; + ret = drm_ioctl_permit(flags, file_priv); + if (unlikely(ret)) + return ret; + + return func(dev, kdata, file_priv); } EXPORT_SYMBOL(drm_ioctl_kernel); diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c deleted file mode 100644 index d327638e15ee74..00000000000000 --- a/drivers/gpu/drm/drm_irq.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * drm_irq.c IRQ and vblank support - * - * \author Rickard E. (Rik) Faith - * \author Gareth Hughes - * - * 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. - */ - -/* - * Created: Fri Mar 19 14:30:16 1999 by faith@valinux.com - * - * Copyright 1999, 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 - * 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. - */ - - -#include -#include /* For task queue support */ -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "drm_internal.h" - -static int drm_legacy_irq_install(struct drm_device *dev, int irq) -{ - int ret; - unsigned long sh_flags = 0; - - if (irq == 0) - return -EINVAL; - - if (dev->irq_enabled) - return -EBUSY; - dev->irq_enabled = true; - - DRM_DEBUG("irq=%d\n", irq); - - /* Before installing handler */ - if (dev->driver->irq_preinstall) - dev->driver->irq_preinstall(dev); - - /* PCI devices require shared interrupts. */ - if (dev_is_pci(dev->dev)) - sh_flags = IRQF_SHARED; - - ret = request_irq(irq, dev->driver->irq_handler, - sh_flags, dev->driver->name, dev); - - if (ret < 0) { - dev->irq_enabled = false; - return ret; - } - - /* After installing handler */ - if (dev->driver->irq_postinstall) - ret = dev->driver->irq_postinstall(dev); - - if (ret < 0) { - dev->irq_enabled = false; - if (drm_core_check_feature(dev, DRIVER_LEGACY)) - vga_client_unregister(to_pci_dev(dev->dev)); - free_irq(irq, dev); - } else { - dev->irq = irq; - } - - return ret; -} - -int drm_legacy_irq_uninstall(struct drm_device *dev) -{ - unsigned long irqflags; - bool irq_enabled; - int i; - - irq_enabled = dev->irq_enabled; - dev->irq_enabled = false; - - /* - * Wake up any waiters so they don't hang. This is just to paper over - * issues for UMS drivers which aren't in full control of their - * vblank/irq handling. KMS drivers must ensure that vblanks are all - * disabled when uninstalling the irq handler. - */ - if (drm_dev_has_vblank(dev)) { - spin_lock_irqsave(&dev->vbl_lock, irqflags); - for (i = 0; i < dev->num_crtcs; i++) { - struct drm_vblank_crtc *vblank = &dev->vblank[i]; - - if (!vblank->enabled) - continue; - - WARN_ON(drm_core_check_feature(dev, DRIVER_MODESET)); - - drm_vblank_disable_and_save(dev, i); - wake_up(&vblank->queue); - } - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); - } - - if (!irq_enabled) - return -EINVAL; - - DRM_DEBUG("irq=%d\n", dev->irq); - - if (drm_core_check_feature(dev, DRIVER_LEGACY)) - vga_client_unregister(to_pci_dev(dev->dev)); - - if (dev->driver->irq_uninstall) - dev->driver->irq_uninstall(dev); - - free_irq(dev->irq, dev); - - return 0; -} -EXPORT_SYMBOL(drm_legacy_irq_uninstall); - -int drm_legacy_irq_control(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_control *ctl = data; - int ret = 0, irq; - struct pci_dev *pdev; - - /* if we haven't irq we fallback for compatibility reasons - - * this used to be a separate function in drm_dma.h - */ - - if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) - return 0; - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return 0; - /* UMS was only ever supported on pci devices. */ - if (WARN_ON(!dev_is_pci(dev->dev))) - return -EINVAL; - - switch (ctl->func) { - case DRM_INST_HANDLER: - pdev = to_pci_dev(dev->dev); - irq = pdev->irq; - - if (dev->if_version < DRM_IF_VERSION(1, 2) && - ctl->irq != irq) - return -EINVAL; - mutex_lock(&dev->struct_mutex); - ret = drm_legacy_irq_install(dev, irq); - mutex_unlock(&dev->struct_mutex); - - return ret; - case DRM_UNINST_HANDLER: - mutex_lock(&dev->struct_mutex); - ret = drm_legacy_irq_uninstall(dev); - mutex_unlock(&dev->struct_mutex); - - return ret; - default: - return -EINVAL; - } -} diff --git a/drivers/gpu/drm/drm_kms_helper_common.c b/drivers/gpu/drm/drm_kms_helper_common.c index 0bf0fc1abf54c7..0c7550c0462b5f 100644 --- a/drivers/gpu/drm/drm_kms_helper_common.c +++ b/drivers/gpu/drm/drm_kms_helper_common.c @@ -27,38 +27,6 @@ #include -#include -#include - -#include "drm_crtc_helper_internal.h" - MODULE_AUTHOR("David Airlie, Jesse Barnes"); MODULE_DESCRIPTION("DRM KMS helper"); MODULE_LICENSE("GPL and additional rights"); - -#if IS_ENABLED(CONFIG_DRM_LOAD_EDID_FIRMWARE) - -/* Backward compatibility for drm_kms_helper.edid_firmware */ -static int edid_firmware_set(const char *val, const struct kernel_param *kp) -{ - DRM_NOTE("drm_kms_helper.edid_firmware is deprecated, please use drm.edid_firmware instead.\n"); - - return __drm_set_edid_firmware_path(val); -} - -static int edid_firmware_get(char *buffer, const struct kernel_param *kp) -{ - return __drm_get_edid_firmware_path(buffer, PAGE_SIZE); -} - -static const struct kernel_param_ops edid_firmware_ops = { - .set = edid_firmware_set, - .get = edid_firmware_get, -}; - -module_param_cb(edid_firmware, &edid_firmware_ops, NULL, 0644); -__MODULE_PARM_TYPE(edid_firmware, "charp"); -MODULE_PARM_DESC(edid_firmware, - "DEPRECATED. Use drm.edid_firmware module parameter instead."); - -#endif diff --git a/drivers/gpu/drm/drm_legacy.h b/drivers/gpu/drm/drm_legacy.h deleted file mode 100644 index 70c9dba114a61a..00000000000000 --- a/drivers/gpu/drm/drm_legacy.h +++ /dev/null @@ -1,290 +0,0 @@ -#ifndef __DRM_LEGACY_H__ -#define __DRM_LEGACY_H__ - -/* - * Copyright (c) 2014 David Herrmann - * - * 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. - */ - -/* - * This file contains legacy interfaces that modern drm drivers - * should no longer be using. They cannot be removed as legacy - * drivers use them, and removing them are API breaks. - */ -#include - -#include -#include -#include - -struct agp_memory; -struct drm_buf_desc; -struct drm_device; -struct drm_file; -struct drm_hash_item; -struct drm_open_hash; - -/* - * Hash-table Support - */ - -#define drm_hash_entry(_ptr, _type, _member) container_of(_ptr, _type, _member) - -/* drm_hashtab.c */ -#if IS_ENABLED(CONFIG_DRM_LEGACY) -int drm_ht_create(struct drm_open_hash *ht, unsigned int order); -int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item); -int drm_ht_just_insert_please(struct drm_open_hash *ht, struct drm_hash_item *item, - unsigned long seed, int bits, int shift, - unsigned long add); -int drm_ht_find_item(struct drm_open_hash *ht, unsigned long key, struct drm_hash_item **item); - -void drm_ht_verbose_list(struct drm_open_hash *ht, unsigned long key); -int drm_ht_remove_key(struct drm_open_hash *ht, unsigned long key); -int drm_ht_remove_item(struct drm_open_hash *ht, struct drm_hash_item *item); -void drm_ht_remove(struct drm_open_hash *ht); -#endif - -/* - * RCU-safe interface - * - * The user of this API needs to make sure that two or more instances of the - * hash table manipulation functions are never run simultaneously. - * The lookup function drm_ht_find_item_rcu may, however, run simultaneously - * with any of the manipulation functions as long as it's called from within - * an RCU read-locked section. - */ -#define drm_ht_insert_item_rcu drm_ht_insert_item -#define drm_ht_just_insert_please_rcu drm_ht_just_insert_please -#define drm_ht_remove_key_rcu drm_ht_remove_key -#define drm_ht_remove_item_rcu drm_ht_remove_item -#define drm_ht_find_item_rcu drm_ht_find_item - -/* - * Generic DRM Contexts - */ - -#define DRM_KERNEL_CONTEXT 0 -#define DRM_RESERVED_CONTEXTS 1 - -#if IS_ENABLED(CONFIG_DRM_LEGACY) -void drm_legacy_ctxbitmap_init(struct drm_device *dev); -void drm_legacy_ctxbitmap_cleanup(struct drm_device *dev); -void drm_legacy_ctxbitmap_flush(struct drm_device *dev, struct drm_file *file); -#else -static inline void drm_legacy_ctxbitmap_init(struct drm_device *dev) {} -static inline void drm_legacy_ctxbitmap_cleanup(struct drm_device *dev) {} -static inline void drm_legacy_ctxbitmap_flush(struct drm_device *dev, struct drm_file *file) {} -#endif - -void drm_legacy_ctxbitmap_free(struct drm_device *dev, int ctx_handle); - -#if IS_ENABLED(CONFIG_DRM_LEGACY) -int drm_legacy_resctx(struct drm_device *d, void *v, struct drm_file *f); -int drm_legacy_addctx(struct drm_device *d, void *v, struct drm_file *f); -int drm_legacy_getctx(struct drm_device *d, void *v, struct drm_file *f); -int drm_legacy_switchctx(struct drm_device *d, void *v, struct drm_file *f); -int drm_legacy_newctx(struct drm_device *d, void *v, struct drm_file *f); -int drm_legacy_rmctx(struct drm_device *d, void *v, struct drm_file *f); - -int drm_legacy_setsareactx(struct drm_device *d, void *v, struct drm_file *f); -int drm_legacy_getsareactx(struct drm_device *d, void *v, struct drm_file *f); -#endif - -/* - * Generic Buffer Management - */ - -#define DRM_MAP_HASH_OFFSET 0x10000000 - -#if IS_ENABLED(CONFIG_DRM_LEGACY) -static inline int drm_legacy_create_map_hash(struct drm_device *dev) -{ - return drm_ht_create(&dev->map_hash, 12); -} - -static inline void drm_legacy_remove_map_hash(struct drm_device *dev) -{ - drm_ht_remove(&dev->map_hash); -} -#else -static inline int drm_legacy_create_map_hash(struct drm_device *dev) -{ - return 0; -} - -static inline void drm_legacy_remove_map_hash(struct drm_device *dev) {} -#endif - - -#if IS_ENABLED(CONFIG_DRM_LEGACY) -int drm_legacy_getmap_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -int drm_legacy_addmap_ioctl(struct drm_device *d, void *v, struct drm_file *f); -int drm_legacy_rmmap_ioctl(struct drm_device *d, void *v, struct drm_file *f); - -int drm_legacy_addbufs(struct drm_device *d, void *v, struct drm_file *f); -int drm_legacy_infobufs(struct drm_device *d, void *v, struct drm_file *f); -int drm_legacy_markbufs(struct drm_device *d, void *v, struct drm_file *f); -int drm_legacy_freebufs(struct drm_device *d, void *v, struct drm_file *f); -int drm_legacy_mapbufs(struct drm_device *d, void *v, struct drm_file *f); -int drm_legacy_dma_ioctl(struct drm_device *d, void *v, struct drm_file *f); -#endif - -int __drm_legacy_infobufs(struct drm_device *, void *, int *, - int (*)(void *, int, struct drm_buf_entry *)); -int __drm_legacy_mapbufs(struct drm_device *, void *, int *, - void __user **, - int (*)(void *, int, unsigned long, struct drm_buf *), - struct drm_file *); - -#if IS_ENABLED(CONFIG_DRM_LEGACY) -void drm_legacy_master_rmmaps(struct drm_device *dev, - struct drm_master *master); -void drm_legacy_rmmaps(struct drm_device *dev); -#else -static inline void drm_legacy_master_rmmaps(struct drm_device *dev, - struct drm_master *master) {} -static inline void drm_legacy_rmmaps(struct drm_device *dev) {} -#endif - -#if IS_ENABLED(CONFIG_DRM_LEGACY) -void drm_legacy_vma_flush(struct drm_device *d); -#else -static inline void drm_legacy_vma_flush(struct drm_device *d) -{ - /* do nothing */ -} -#endif - -/* - * AGP Support - */ - -struct drm_agp_mem { - unsigned long handle; - struct agp_memory *memory; - unsigned long bound; - int pages; - struct list_head head; -}; - -/* drm_agpsupport.c */ -#if IS_ENABLED(CONFIG_DRM_LEGACY) && IS_ENABLED(CONFIG_AGP) -void drm_legacy_agp_clear(struct drm_device *dev); - -int drm_legacy_agp_acquire_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -int drm_legacy_agp_release_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -int drm_legacy_agp_enable_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -int drm_legacy_agp_info_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -int drm_legacy_agp_alloc_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -int drm_legacy_agp_free_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -int drm_legacy_agp_unbind_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -int drm_legacy_agp_bind_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -#else -static inline void drm_legacy_agp_clear(struct drm_device *dev) {} -#endif - -/* drm_lock.c */ -#if IS_ENABLED(CONFIG_DRM_LEGACY) -int drm_legacy_lock(struct drm_device *d, void *v, struct drm_file *f); -int drm_legacy_unlock(struct drm_device *d, void *v, struct drm_file *f); -void drm_legacy_lock_release(struct drm_device *dev, struct file *filp); -#else -static inline void drm_legacy_lock_release(struct drm_device *dev, struct file *filp) {} -#endif - -/* DMA support */ -#if IS_ENABLED(CONFIG_DRM_LEGACY) -int drm_legacy_dma_setup(struct drm_device *dev); -void drm_legacy_dma_takedown(struct drm_device *dev); -#else -static inline int drm_legacy_dma_setup(struct drm_device *dev) -{ - return 0; -} -#endif - -void drm_legacy_free_buffer(struct drm_device *dev, - struct drm_buf * buf); -#if IS_ENABLED(CONFIG_DRM_LEGACY) -void drm_legacy_reclaim_buffers(struct drm_device *dev, - struct drm_file *filp); -#else -static inline void drm_legacy_reclaim_buffers(struct drm_device *dev, - struct drm_file *filp) {} -#endif - -/* Scatter Gather Support */ -#if IS_ENABLED(CONFIG_DRM_LEGACY) -void drm_legacy_sg_cleanup(struct drm_device *dev); -int drm_legacy_sg_alloc(struct drm_device *dev, void *data, - struct drm_file *file_priv); -int drm_legacy_sg_free(struct drm_device *dev, void *data, - struct drm_file *file_priv); -#endif - -#if IS_ENABLED(CONFIG_DRM_LEGACY) -void drm_legacy_init_members(struct drm_device *dev); -void drm_legacy_destroy_members(struct drm_device *dev); -void drm_legacy_dev_reinit(struct drm_device *dev); -int drm_legacy_setup(struct drm_device * dev); -#else -static inline void drm_legacy_init_members(struct drm_device *dev) {} -static inline void drm_legacy_destroy_members(struct drm_device *dev) {} -static inline void drm_legacy_dev_reinit(struct drm_device *dev) {} -static inline int drm_legacy_setup(struct drm_device * dev) { return 0; } -#endif - -#if IS_ENABLED(CONFIG_DRM_LEGACY) -void drm_legacy_lock_master_cleanup(struct drm_device *dev, struct drm_master *master); -#else -static inline void drm_legacy_lock_master_cleanup(struct drm_device *dev, struct drm_master *master) {} -#endif - -#if IS_ENABLED(CONFIG_DRM_LEGACY) -void drm_master_legacy_init(struct drm_master *master); -#else -static inline void drm_master_legacy_init(struct drm_master *master) {} -#endif - -/* drm_pci.c */ -#if IS_ENABLED(CONFIG_DRM_LEGACY) && IS_ENABLED(CONFIG_PCI) -int drm_legacy_irq_by_busid(struct drm_device *dev, void *data, struct drm_file *file_priv); -void drm_legacy_pci_agp_destroy(struct drm_device *dev); -#else -static inline int drm_legacy_irq_by_busid(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - return -EINVAL; -} - -static inline void drm_legacy_pci_agp_destroy(struct drm_device *dev) {} -#endif - -#endif /* __DRM_LEGACY_H__ */ diff --git a/drivers/gpu/drm/drm_legacy_misc.c b/drivers/gpu/drm/drm_legacy_misc.c deleted file mode 100644 index d4c5434062d7c3..00000000000000 --- a/drivers/gpu/drm/drm_legacy_misc.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * \file drm_legacy_misc.c - * Misc legacy support functions. - * - * \author Rickard E. (Rik) Faith - * \author Gareth Hughes - */ - -/* - * Created: Tue Feb 2 08:37:54 1999 by faith@valinux.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. - */ - -#include -#include -#include - -#include "drm_internal.h" -#include "drm_legacy.h" - -void drm_legacy_init_members(struct drm_device *dev) -{ - INIT_LIST_HEAD(&dev->ctxlist); - INIT_LIST_HEAD(&dev->vmalist); - INIT_LIST_HEAD(&dev->maplist); - spin_lock_init(&dev->buf_lock); - mutex_init(&dev->ctxlist_mutex); -} - -void drm_legacy_destroy_members(struct drm_device *dev) -{ - mutex_destroy(&dev->ctxlist_mutex); -} - -int drm_legacy_setup(struct drm_device * dev) -{ - int ret; - - if (dev->driver->firstopen && - drm_core_check_feature(dev, DRIVER_LEGACY)) { - ret = dev->driver->firstopen(dev); - if (ret != 0) - return ret; - } - - ret = drm_legacy_dma_setup(dev); - if (ret < 0) - return ret; - - - DRM_DEBUG("\n"); - return 0; -} - -void drm_legacy_dev_reinit(struct drm_device *dev) -{ - if (dev->irq_enabled) - drm_legacy_irq_uninstall(dev); - - mutex_lock(&dev->struct_mutex); - - drm_legacy_agp_clear(dev); - - drm_legacy_sg_cleanup(dev); - drm_legacy_vma_flush(dev); - drm_legacy_dma_takedown(dev); - - mutex_unlock(&dev->struct_mutex); - - dev->sigdata.lock = NULL; - - dev->context_flag = 0; - dev->last_context = 0; - dev->if_version = 0; - - DRM_DEBUG("lastclose completed\n"); -} - -void drm_master_legacy_init(struct drm_master *master) -{ - spin_lock_init(&master->lock.spinlock); - init_waitqueue_head(&master->lock.lock_queue); -} diff --git a/drivers/gpu/drm/drm_lock.c b/drivers/gpu/drm/drm_lock.c deleted file mode 100644 index 1efbd5389d8930..00000000000000 --- a/drivers/gpu/drm/drm_lock.c +++ /dev/null @@ -1,373 +0,0 @@ -/* - * \file drm_lock.c - * IOCTLs for locking - * - * \author Rickard E. (Rik) Faith - * \author Gareth Hughes - */ - -/* - * Created: Tue Feb 2 08:37:54 1999 by faith@valinux.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. - */ - -#include -#include - -#include -#include -#include -#include - -#include "drm_internal.h" -#include "drm_legacy.h" - -static int drm_lock_take(struct drm_lock_data *lock_data, unsigned int context); - -/* - * Take the heavyweight lock. - * - * \param lock lock pointer. - * \param context locking context. - * \return one if the lock is held, or zero otherwise. - * - * Attempt to mark the lock as held by the given context, via the \p cmpxchg instruction. - */ -static -int drm_lock_take(struct drm_lock_data *lock_data, - unsigned int context) -{ - unsigned int old, new, prev; - volatile unsigned int *lock = &lock_data->hw_lock->lock; - - spin_lock_bh(&lock_data->spinlock); - do { - old = *lock; - if (old & _DRM_LOCK_HELD) - new = old | _DRM_LOCK_CONT; - else { - new = context | _DRM_LOCK_HELD | - ((lock_data->user_waiters + lock_data->kernel_waiters > 1) ? - _DRM_LOCK_CONT : 0); - } - prev = cmpxchg(lock, old, new); - } while (prev != old); - spin_unlock_bh(&lock_data->spinlock); - - if (_DRM_LOCKING_CONTEXT(old) == context) { - if (old & _DRM_LOCK_HELD) { - if (context != DRM_KERNEL_CONTEXT) { - DRM_ERROR("%d holds heavyweight lock\n", - context); - } - return 0; - } - } - - if ((_DRM_LOCKING_CONTEXT(new)) == context && (new & _DRM_LOCK_HELD)) { - /* Have lock */ - return 1; - } - return 0; -} - -/* - * This takes a lock forcibly and hands it to context. Should ONLY be used - * inside *_unlock to give lock to kernel before calling *_dma_schedule. - * - * \param dev DRM device. - * \param lock lock pointer. - * \param context locking context. - * \return always one. - * - * Resets the lock file pointer. - * Marks the lock as held by the given context, via the \p cmpxchg instruction. - */ -static int drm_lock_transfer(struct drm_lock_data *lock_data, - unsigned int context) -{ - unsigned int old, new, prev; - volatile unsigned int *lock = &lock_data->hw_lock->lock; - - lock_data->file_priv = NULL; - do { - old = *lock; - new = context | _DRM_LOCK_HELD; - prev = cmpxchg(lock, old, new); - } while (prev != old); - return 1; -} - -static int drm_legacy_lock_free(struct drm_lock_data *lock_data, - unsigned int context) -{ - unsigned int old, new, prev; - volatile unsigned int *lock = &lock_data->hw_lock->lock; - - spin_lock_bh(&lock_data->spinlock); - if (lock_data->kernel_waiters != 0) { - drm_lock_transfer(lock_data, 0); - lock_data->idle_has_lock = 1; - spin_unlock_bh(&lock_data->spinlock); - return 1; - } - spin_unlock_bh(&lock_data->spinlock); - - do { - old = *lock; - new = _DRM_LOCKING_CONTEXT(old); - prev = cmpxchg(lock, old, new); - } while (prev != old); - - if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) { - DRM_ERROR("%d freed heavyweight lock held by %d\n", - context, _DRM_LOCKING_CONTEXT(old)); - return 1; - } - wake_up_interruptible(&lock_data->lock_queue); - return 0; -} - -/* - * Lock ioctl. - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg user argument, pointing to a drm_lock structure. - * \return zero on success or negative number on failure. - * - * Add the current task to the lock wait queue, and attempt to take to lock. - */ -int drm_legacy_lock(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - DECLARE_WAITQUEUE(entry, current); - struct drm_lock *lock = data; - struct drm_master *master = file_priv->master; - int ret = 0; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - ++file_priv->lock_count; - - if (lock->context == DRM_KERNEL_CONTEXT) { - DRM_ERROR("Process %d using kernel context %d\n", - task_pid_nr(current), lock->context); - return -EINVAL; - } - - DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n", - lock->context, task_pid_nr(current), - master->lock.hw_lock ? master->lock.hw_lock->lock : -1, - lock->flags); - - add_wait_queue(&master->lock.lock_queue, &entry); - spin_lock_bh(&master->lock.spinlock); - master->lock.user_waiters++; - spin_unlock_bh(&master->lock.spinlock); - - for (;;) { - __set_current_state(TASK_INTERRUPTIBLE); - if (!master->lock.hw_lock) { - /* Device has been unregistered */ - send_sig(SIGTERM, current, 0); - ret = -EINTR; - break; - } - if (drm_lock_take(&master->lock, lock->context)) { - master->lock.file_priv = file_priv; - master->lock.lock_time = jiffies; - break; /* Got lock */ - } - - /* Contention */ - mutex_unlock(&drm_global_mutex); - schedule(); - mutex_lock(&drm_global_mutex); - if (signal_pending(current)) { - ret = -EINTR; - break; - } - } - spin_lock_bh(&master->lock.spinlock); - master->lock.user_waiters--; - spin_unlock_bh(&master->lock.spinlock); - __set_current_state(TASK_RUNNING); - remove_wait_queue(&master->lock.lock_queue, &entry); - - DRM_DEBUG("%d %s\n", lock->context, - ret ? "interrupted" : "has lock"); - if (ret) return ret; - - /* don't set the block all signals on the master process for now - * really probably not the correct answer but lets us debug xkb - * xserver for now */ - if (!drm_is_current_master(file_priv)) { - dev->sigdata.context = lock->context; - dev->sigdata.lock = master->lock.hw_lock; - } - - if (dev->driver->dma_quiescent && (lock->flags & _DRM_LOCK_QUIESCENT)) - { - if (dev->driver->dma_quiescent(dev)) { - DRM_DEBUG("%d waiting for DMA quiescent\n", - lock->context); - return -EBUSY; - } - } - - return 0; -} - -/* - * Unlock ioctl. - * - * \param inode device inode. - * \param file_priv DRM file private. - * \param cmd command. - * \param arg user argument, pointing to a drm_lock structure. - * \return zero on success or negative number on failure. - * - * Transfer and free the lock. - */ -int drm_legacy_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv) -{ - struct drm_lock *lock = data; - struct drm_master *master = file_priv->master; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - if (lock->context == DRM_KERNEL_CONTEXT) { - DRM_ERROR("Process %d using kernel context %d\n", - task_pid_nr(current), lock->context); - return -EINVAL; - } - - if (drm_legacy_lock_free(&master->lock, lock->context)) { - /* FIXME: Should really bail out here. */ - } - - return 0; -} - -/* - * This function returns immediately and takes the hw lock - * with the kernel context if it is free, otherwise it gets the highest priority when and if - * it is eventually released. - * - * This guarantees that the kernel will _eventually_ have the lock _unless_ it is held - * by a blocked process. (In the latter case an explicit wait for the hardware lock would cause - * a deadlock, which is why the "idlelock" was invented). - * - * This should be sufficient to wait for GPU idle without - * having to worry about starvation. - */ -void drm_legacy_idlelock_take(struct drm_lock_data *lock_data) -{ - int ret; - - spin_lock_bh(&lock_data->spinlock); - lock_data->kernel_waiters++; - if (!lock_data->idle_has_lock) { - - spin_unlock_bh(&lock_data->spinlock); - ret = drm_lock_take(lock_data, DRM_KERNEL_CONTEXT); - spin_lock_bh(&lock_data->spinlock); - - if (ret == 1) - lock_data->idle_has_lock = 1; - } - spin_unlock_bh(&lock_data->spinlock); -} -EXPORT_SYMBOL(drm_legacy_idlelock_take); - -void drm_legacy_idlelock_release(struct drm_lock_data *lock_data) -{ - unsigned int old, prev; - volatile unsigned int *lock = &lock_data->hw_lock->lock; - - spin_lock_bh(&lock_data->spinlock); - if (--lock_data->kernel_waiters == 0) { - if (lock_data->idle_has_lock) { - do { - old = *lock; - prev = cmpxchg(lock, old, DRM_KERNEL_CONTEXT); - } while (prev != old); - wake_up_interruptible(&lock_data->lock_queue); - lock_data->idle_has_lock = 0; - } - } - spin_unlock_bh(&lock_data->spinlock); -} -EXPORT_SYMBOL(drm_legacy_idlelock_release); - -static int drm_legacy_i_have_hw_lock(struct drm_device *dev, - struct drm_file *file_priv) -{ - struct drm_master *master = file_priv->master; - - return (file_priv->lock_count && master->lock.hw_lock && - _DRM_LOCK_IS_HELD(master->lock.hw_lock->lock) && - master->lock.file_priv == file_priv); -} - -void drm_legacy_lock_release(struct drm_device *dev, struct file *filp) -{ - struct drm_file *file_priv = filp->private_data; - - /* if the master has gone away we can't do anything with the lock */ - if (!dev->master) - return; - - if (drm_legacy_i_have_hw_lock(dev, file_priv)) { - DRM_DEBUG("File %p released, freeing lock for context %d\n", - filp, _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock)); - drm_legacy_lock_free(&file_priv->master->lock, - _DRM_LOCKING_CONTEXT(file_priv->master->lock.hw_lock->lock)); - } -} - -void drm_legacy_lock_master_cleanup(struct drm_device *dev, struct drm_master *master) -{ - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return; - - /* - * Since the master is disappearing, so is the - * possibility to lock. - */ - mutex_lock(&dev->struct_mutex); - if (master->lock.hw_lock) { - if (dev->sigdata.lock == master->lock.hw_lock) - dev->sigdata.lock = NULL; - master->lock.hw_lock = NULL; - master->lock.file_priv = NULL; - wake_up_interruptible_all(&master->lock.lock_queue); - } - mutex_unlock(&dev->struct_mutex); -} diff --git a/drivers/gpu/drm/drm_memory.c b/drivers/gpu/drm/drm_memory.c deleted file mode 100644 index d2e1dccd8113e0..00000000000000 --- a/drivers/gpu/drm/drm_memory.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * \file drm_memory.c - * Memory management wrappers for DRM - * - * \author Rickard E. (Rik) Faith - * \author Gareth Hughes - */ - -/* - * Created: Thu Feb 4 14:00:34 1999 by faith@valinux.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. - */ - -#include -#include -#include -#include - -#include -#include - -#include "drm_legacy.h" - -#if IS_ENABLED(CONFIG_AGP) - -#ifdef HAVE_PAGE_AGP -# include -#else -# ifdef __powerpc__ -# define PAGE_AGP pgprot_noncached_wc(PAGE_KERNEL) -# else -# define PAGE_AGP PAGE_KERNEL -# endif -#endif - -static void *agp_remap(unsigned long offset, unsigned long size, - struct drm_device *dev) -{ - unsigned long i, num_pages = - PAGE_ALIGN(size) / PAGE_SIZE; - struct drm_agp_mem *agpmem; - struct page **page_map; - struct page **phys_page_map; - void *addr; - - size = PAGE_ALIGN(size); - -#ifdef __alpha__ - offset -= dev->hose->mem_space->start; -#endif - - list_for_each_entry(agpmem, &dev->agp->memory, head) - if (agpmem->bound <= offset - && (agpmem->bound + (agpmem->pages << PAGE_SHIFT)) >= - (offset + size)) - break; - if (&agpmem->head == &dev->agp->memory) - return NULL; - - /* - * OK, we're mapping AGP space on a chipset/platform on which memory accesses by - * the CPU do not get remapped by the GART. We fix this by using the kernel's - * page-table instead (that's probably faster anyhow...). - */ - /* note: use vmalloc() because num_pages could be large... */ - page_map = vmalloc(array_size(num_pages, sizeof(struct page *))); - if (!page_map) - return NULL; - - phys_page_map = (agpmem->memory->pages + (offset - agpmem->bound) / PAGE_SIZE); - for (i = 0; i < num_pages; ++i) - page_map[i] = phys_page_map[i]; - addr = vmap(page_map, num_pages, VM_IOREMAP, PAGE_AGP); - vfree(page_map); - - return addr; -} - -#else /* CONFIG_AGP */ -static inline void *agp_remap(unsigned long offset, unsigned long size, - struct drm_device *dev) -{ - return NULL; -} - -#endif /* CONFIG_AGP */ - -void drm_legacy_ioremap(struct drm_local_map *map, struct drm_device *dev) -{ - if (dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP) - map->handle = agp_remap(map->offset, map->size, dev); - else - map->handle = ioremap(map->offset, map->size); -} -EXPORT_SYMBOL(drm_legacy_ioremap); - -void drm_legacy_ioremap_wc(struct drm_local_map *map, struct drm_device *dev) -{ - if (dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP) - map->handle = agp_remap(map->offset, map->size, dev); - else - map->handle = ioremap_wc(map->offset, map->size); -} -EXPORT_SYMBOL(drm_legacy_ioremap_wc); - -void drm_legacy_ioremapfree(struct drm_local_map *map, struct drm_device *dev) -{ - if (!map->handle || !map->size) - return; - - if (dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP) - vunmap(map->handle); - else - iounmap(map->handle); -} -EXPORT_SYMBOL(drm_legacy_ioremapfree); diff --git a/drivers/gpu/drm/drm_mipi_dbi.c b/drivers/gpu/drm/drm_mipi_dbi.c index e90f0bf895b33e..daac649aabdbe8 100644 --- a/drivers/gpu/drm/drm_mipi_dbi.c +++ b/drivers/gpu/drm/drm_mipi_dbi.c @@ -197,12 +197,14 @@ EXPORT_SYMBOL(mipi_dbi_command_stackbuf); * @fb: The source framebuffer * @clip: Clipping rectangle of the area to be copied * @swap: When true, swap MSB/LSB of 16-bit values + * @fmtcnv_state: Format-conversion state * * Returns: * Zero on success, negative error code on failure. */ int mipi_dbi_buf_copy(void *dst, struct iosys_map *src, struct drm_framebuffer *fb, - struct drm_rect *clip, bool swap) + struct drm_rect *clip, bool swap, + struct drm_format_conv_state *fmtcnv_state) { struct drm_gem_object *gem = drm_gem_fb_get_obj(fb, 0); struct iosys_map dst_map = IOSYS_MAP_INIT_VADDR(dst); @@ -215,12 +217,13 @@ int mipi_dbi_buf_copy(void *dst, struct iosys_map *src, struct drm_framebuffer * switch (fb->format->format) { case DRM_FORMAT_RGB565: if (swap) - drm_fb_swab(&dst_map, NULL, src, fb, clip, !gem->import_attach); + drm_fb_swab(&dst_map, NULL, src, fb, clip, !gem->import_attach, + fmtcnv_state); else drm_fb_memcpy(&dst_map, NULL, src, fb, clip); break; case DRM_FORMAT_XRGB8888: - drm_fb_xrgb8888_to_rgb565(&dst_map, NULL, src, fb, clip, swap); + drm_fb_xrgb8888_to_rgb565(&dst_map, NULL, src, fb, clip, fmtcnv_state, swap); break; default: drm_err_once(fb->dev, "Format is not supported: %p4cc\n", @@ -252,7 +255,7 @@ static void mipi_dbi_set_window_address(struct mipi_dbi_dev *dbidev, } static void mipi_dbi_fb_dirty(struct iosys_map *src, struct drm_framebuffer *fb, - struct drm_rect *rect) + struct drm_rect *rect, struct drm_format_conv_state *fmtcnv_state) { struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(fb->dev); unsigned int height = rect->y2 - rect->y1; @@ -270,7 +273,7 @@ static void mipi_dbi_fb_dirty(struct iosys_map *src, struct drm_framebuffer *fb, if (!dbi->dc || !full || swap || fb->format->format == DRM_FORMAT_XRGB8888) { tr = dbidev->tx_buf; - ret = mipi_dbi_buf_copy(tr, src, fb, rect, swap); + ret = mipi_dbi_buf_copy(tr, src, fb, rect, swap, fmtcnv_state); if (ret) goto err_msg; } else { @@ -332,7 +335,8 @@ void mipi_dbi_pipe_update(struct drm_simple_display_pipe *pipe, return; if (drm_atomic_helper_damage_merged(old_state, state, &rect)) - mipi_dbi_fb_dirty(&shadow_plane_state->data[0], fb, &rect); + mipi_dbi_fb_dirty(&shadow_plane_state->data[0], fb, &rect, + &shadow_plane_state->fmtcnv_state); drm_dev_exit(idx); } @@ -368,7 +372,8 @@ void mipi_dbi_enable_flush(struct mipi_dbi_dev *dbidev, if (!drm_dev_enter(&dbidev->drm, &idx)) return; - mipi_dbi_fb_dirty(&shadow_plane_state->data[0], fb, &rect); + mipi_dbi_fb_dirty(&shadow_plane_state->data[0], fb, &rect, + &shadow_plane_state->fmtcnv_state); backlight_enable(dbidev->backlight); drm_dev_exit(idx); diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 14201f73aab134..843a6dbda93a07 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -347,7 +347,8 @@ static int mipi_dsi_remove_device_fn(struct device *dev, void *priv) { struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); - mipi_dsi_detach(dsi); + if (dsi->attached) + mipi_dsi_detach(dsi); mipi_dsi_device_unregister(dsi); return 0; @@ -370,11 +371,18 @@ EXPORT_SYMBOL(mipi_dsi_host_unregister); int mipi_dsi_attach(struct mipi_dsi_device *dsi) { const struct mipi_dsi_host_ops *ops = dsi->host->ops; + int ret; if (!ops || !ops->attach) return -ENOSYS; - return ops->attach(dsi->host, dsi); + ret = ops->attach(dsi->host, dsi); + if (ret) + return ret; + + dsi->attached = true; + + return 0; } EXPORT_SYMBOL(mipi_dsi_attach); @@ -386,9 +394,14 @@ int mipi_dsi_detach(struct mipi_dsi_device *dsi) { const struct mipi_dsi_host_ops *ops = dsi->host->ops; + if (WARN_ON(!dsi->attached)) + return -EINVAL; + if (!ops || !ops->detach) return -ENOSYS; + dsi->attached = false; + return ops->detach(dsi->host, dsi); } EXPORT_SYMBOL(mipi_dsi_detach); diff --git a/drivers/gpu/drm/drm_mode_object.c b/drivers/gpu/drm/drm_mode_object.c index ac0d2ce3f87041..0e8355063eee36 100644 --- a/drivers/gpu/drm/drm_mode_object.c +++ b/drivers/gpu/drm/drm_mode_object.c @@ -538,7 +538,7 @@ retry: obj_to_connector(obj), prop_value); } else { - ret = drm_atomic_set_property(state, file_priv, obj, prop, prop_value); + ret = drm_atomic_set_property(state, file_priv, obj, prop, prop_value, false); if (ret) goto out; ret = drm_atomic_commit(state); diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index ac9a406250c561..893f52ee492610 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -2617,8 +2617,7 @@ void drm_mode_convert_to_umode(struct drm_mode_modeinfo *out, break; } - strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); - out->name[DRM_DISPLAY_MODE_LEN-1] = 0; + strscpy_pad(out->name, in->name, sizeof(out->name)); } /** @@ -2659,8 +2658,7 @@ int drm_mode_convert_umode(struct drm_device *dev, * useful for the kernel->userspace direction anyway. */ out->type = in->type & DRM_MODE_TYPE_ALL; - strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); - out->name[DRM_DISPLAY_MODE_LEN-1] = 0; + strscpy_pad(out->name, in->name, sizeof(out->name)); /* Clearing picture aspect ratio bits from out flags, * as the aspect-ratio information is not stored in diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index 39d35fc3a43bcf..c585f1e8803ec2 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -29,18 +29,12 @@ #include #include +#include #include #include #include #include "drm_internal.h" -#include "drm_legacy.h" - -#ifdef CONFIG_DRM_LEGACY -/* List of devices hanging off drivers with stealth attach. */ -static LIST_HEAD(legacy_dev_list); -static DEFINE_MUTEX(legacy_dev_list_lock); -#endif static int drm_get_pci_domain(struct drm_device *dev) { @@ -71,199 +65,3 @@ int drm_pci_set_busid(struct drm_device *dev, struct drm_master *master) master->unique_len = strlen(master->unique); return 0; } - -#ifdef CONFIG_DRM_LEGACY - -static int drm_legacy_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *p) -{ - struct pci_dev *pdev = to_pci_dev(dev->dev); - - if ((p->busnum >> 8) != drm_get_pci_domain(dev) || - (p->busnum & 0xff) != pdev->bus->number || - p->devnum != PCI_SLOT(pdev->devfn) || p->funcnum != PCI_FUNC(pdev->devfn)) - return -EINVAL; - - p->irq = pdev->irq; - - DRM_DEBUG("%d:%d:%d => IRQ %d\n", p->busnum, p->devnum, p->funcnum, - p->irq); - return 0; -} - -/** - * drm_legacy_irq_by_busid - Get interrupt from bus ID - * @dev: DRM device - * @data: IOCTL parameter pointing to a drm_irq_busid structure - * @file_priv: DRM file private. - * - * Finds the PCI device with the specified bus id and gets its IRQ number. - * This IOCTL is deprecated, and will now return EINVAL for any busid not equal - * to that of the device that this DRM instance attached to. - * - * Return: 0 on success or a negative error code on failure. - */ -int drm_legacy_irq_by_busid(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_irq_busid *p = data; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - /* UMS was only ever support on PCI devices. */ - if (WARN_ON(!dev_is_pci(dev->dev))) - return -EINVAL; - - if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) - return -EOPNOTSUPP; - - return drm_legacy_pci_irq_by_busid(dev, p); -} - -void drm_legacy_pci_agp_destroy(struct drm_device *dev) -{ - if (dev->agp) { - arch_phys_wc_del(dev->agp->agp_mtrr); - drm_legacy_agp_clear(dev); - kfree(dev->agp); - dev->agp = NULL; - } -} - -static void drm_legacy_pci_agp_init(struct drm_device *dev) -{ - if (drm_core_check_feature(dev, DRIVER_USE_AGP)) { - if (pci_find_capability(to_pci_dev(dev->dev), PCI_CAP_ID_AGP)) - 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); - } - } -} - -static int drm_legacy_get_pci_dev(struct pci_dev *pdev, - const struct pci_device_id *ent, - const struct drm_driver *driver) -{ - struct drm_device *dev; - int ret; - - DRM_DEBUG("\n"); - - dev = drm_dev_alloc(driver, &pdev->dev); - if (IS_ERR(dev)) - return PTR_ERR(dev); - - ret = pci_enable_device(pdev); - if (ret) - goto err_free; - -#ifdef __alpha__ - dev->hose = pdev->sysdata; -#endif - - drm_legacy_pci_agp_init(dev); - - ret = drm_dev_register(dev, ent->driver_data); - if (ret) - goto err_agp; - - if (drm_core_check_feature(dev, DRIVER_LEGACY)) { - mutex_lock(&legacy_dev_list_lock); - list_add_tail(&dev->legacy_dev_list, &legacy_dev_list); - mutex_unlock(&legacy_dev_list_lock); - } - - return 0; - -err_agp: - drm_legacy_pci_agp_destroy(dev); - pci_disable_device(pdev); -err_free: - drm_dev_put(dev); - return ret; -} - -/** - * drm_legacy_pci_init - shadow-attach a legacy DRM PCI driver - * @driver: DRM device driver - * @pdriver: PCI device driver - * - * This is only used by legacy dri1 drivers and deprecated. - * - * Return: 0 on success or a negative error code on failure. - */ -int drm_legacy_pci_init(const struct drm_driver *driver, - struct pci_driver *pdriver) -{ - struct pci_dev *pdev = NULL; - const struct pci_device_id *pid; - int i; - - DRM_DEBUG("\n"); - - if (WARN_ON(!(driver->driver_features & DRIVER_LEGACY))) - return -EINVAL; - - /* If not using KMS, fall back to stealth mode manual scanning. */ - for (i = 0; pdriver->id_table[i].vendor != 0; i++) { - pid = &pdriver->id_table[i]; - - /* Loop around setting up a DRM device for each PCI device - * matching our ID and device class. If we had the internal - * function that pci_get_subsys and pci_get_class used, we'd - * be able to just pass pid in instead of doing a two-stage - * thing. - */ - pdev = NULL; - while ((pdev = - pci_get_subsys(pid->vendor, pid->device, pid->subvendor, - pid->subdevice, pdev)) != NULL) { - if ((pdev->class & pid->class_mask) != pid->class) - continue; - - /* stealth mode requires a manual probe */ - pci_dev_get(pdev); - drm_legacy_get_pci_dev(pdev, pid, driver); - } - } - return 0; -} -EXPORT_SYMBOL(drm_legacy_pci_init); - -/** - * drm_legacy_pci_exit - unregister shadow-attach legacy DRM driver - * @driver: DRM device driver - * @pdriver: PCI device driver - * - * Unregister a DRM driver shadow-attached through drm_legacy_pci_init(). This - * is deprecated and only used by dri1 drivers. - */ -void drm_legacy_pci_exit(const struct drm_driver *driver, - struct pci_driver *pdriver) -{ - struct drm_device *dev, *tmp; - - DRM_DEBUG("\n"); - - if (!(driver->driver_features & DRIVER_LEGACY)) { - WARN_ON(1); - } else { - mutex_lock(&legacy_dev_list_lock); - list_for_each_entry_safe(dev, tmp, &legacy_dev_list, - legacy_dev_list) { - if (dev->driver == driver) { - list_del(&dev->legacy_dev_list); - drm_put_dev(dev); - } - } - mutex_unlock(&legacy_dev_list_lock); - } - DRM_INFO("Module unloaded\n"); -} -EXPORT_SYMBOL(drm_legacy_pci_exit); - -#endif diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index 24e7998d17313e..672c655c7a8e7e 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -230,6 +230,103 @@ static int create_in_format_blob(struct drm_device *dev, struct drm_plane *plane return 0; } +/** + * DOC: hotspot properties + * + * HOTSPOT_X: property to set mouse hotspot x offset. + * HOTSPOT_Y: property to set mouse hotspot y offset. + * + * When the plane is being used as a cursor image to display a mouse pointer, + * the "hotspot" is the offset within the cursor image where mouse events + * are expected to go. + * + * Positive values move the hotspot from the top-left corner of the cursor + * plane towards the right and bottom. + * + * Most display drivers do not need this information because the + * hotspot is not actually connected to anything visible on screen. + * However, this is necessary for display drivers like the para-virtualized + * drivers (eg qxl, vbox, virtio, vmwgfx), that are attached to a user console + * with a mouse pointer. Since these consoles are often being remoted over a + * network, they would otherwise have to wait to display the pointer movement to + * the user until a full network round-trip has occurred. New mouse events have + * to be sent from the user's console, over the network to the virtual input + * devices, forwarded to the desktop for processing, and then the cursor plane's + * position can be updated and sent back to the user's console over the network. + * Instead, with the hotspot information, the console can anticipate the new + * location, and draw the mouse cursor there before the confirmation comes in. + * To do that correctly, the user's console must be able predict how the + * desktop will process mouse events, which normally requires the desktop's + * mouse topology information, ie where each CRTC sits in the mouse coordinate + * space. This is typically sent to the para-virtualized drivers using some + * driver-specific method, and the driver then forwards it to the console by + * way of the virtual display device or hypervisor. + * + * The assumption is generally made that there is only one cursor plane being + * used this way at a time, and that the desktop is feeding all mouse devices + * into the same global pointer. Para-virtualized drivers that require this + * should only be exposing a single cursor plane, or find some other way + * to coordinate with a userspace desktop that supports multiple pointers. + * If the hotspot properties are set, the cursor plane is therefore assumed to be + * used only for displaying a mouse cursor image, and the position of the combined + * cursor plane + offset can therefore be used for coordinating with input from a + * mouse device. + * + * The cursor will then be drawn either at the location of the plane in the CRTC + * console, or as a free-floating cursor plane on the user's console + * corresponding to their desktop mouse position. + * + * DRM clients which would like to work correctly on drivers which expose + * hotspot properties should advertise DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT. + * Setting this property on drivers which do not special case + * cursor planes will return EOPNOTSUPP, which can be used by userspace to + * gauge requirements of the hardware/drivers they're running on. Advertising + * DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT implies that the userspace client will be + * correctly setting the hotspot properties. + */ + +/** + * drm_plane_create_hotspot_properties - creates the mouse hotspot + * properties and attaches them to the given cursor plane + * + * @plane: drm cursor plane + * + * This function enables the mouse hotspot property on a given + * cursor plane. Look at the documentation for hotspot properties + * to get a better understanding for what they're used for. + * + * RETURNS: + * Zero for success or -errno + */ +static int drm_plane_create_hotspot_properties(struct drm_plane *plane) +{ + struct drm_property *prop_x; + struct drm_property *prop_y; + + drm_WARN_ON(plane->dev, + !drm_core_check_feature(plane->dev, + DRIVER_CURSOR_HOTSPOT)); + + prop_x = drm_property_create_signed_range(plane->dev, 0, "HOTSPOT_X", + INT_MIN, INT_MAX); + if (IS_ERR(prop_x)) + return PTR_ERR(prop_x); + + prop_y = drm_property_create_signed_range(plane->dev, 0, "HOTSPOT_Y", + INT_MIN, INT_MAX); + if (IS_ERR(prop_y)) { + drm_property_destroy(plane->dev, prop_x); + return PTR_ERR(prop_y); + } + + drm_object_attach_property(&plane->base, prop_x, 0); + drm_object_attach_property(&plane->base, prop_y, 0); + plane->hotspot_x_property = prop_x; + plane->hotspot_y_property = prop_y; + + return 0; +} + __printf(9, 0) static int __drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, @@ -348,6 +445,10 @@ static int __drm_universal_plane_init(struct drm_device *dev, drm_object_attach_property(&plane->base, config->prop_src_w, 0); drm_object_attach_property(&plane->base, config->prop_src_h, 0); } + if (drm_core_check_feature(dev, DRIVER_CURSOR_HOTSPOT) && + type == DRM_PLANE_TYPE_CURSOR) { + drm_plane_create_hotspot_properties(plane); + } if (format_modifier_count) create_in_format_blob(dev, plane); @@ -678,6 +779,19 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data, !file_priv->universal_planes) continue; + /* + * If we're running on a virtualized driver then, + * unless userspace advertizes support for the + * virtualized cursor plane, disable cursor planes + * because they'll be broken due to missing cursor + * hotspot info. + */ + if (plane->type == DRM_PLANE_TYPE_CURSOR && + drm_core_check_feature(dev, DRIVER_CURSOR_HOTSPOT) && + file_priv->atomic && + !file_priv->supports_virtualized_cursor_plane) + continue; + if (drm_lease_held(file_priv, plane->base.id)) { if (count < plane_resp->count_planes && put_user(plane->base.id, plane_ptr + count)) @@ -1052,8 +1166,10 @@ static int drm_mode_cursor_universal(struct drm_crtc *crtc, return PTR_ERR(fb); } - fb->hot_x = req->hot_x; - fb->hot_y = req->hot_y; + if (plane->hotspot_x_property && plane->state) + plane->state->hotspot_x = req->hot_x; + if (plane->hotspot_y_property && plane->state) + plane->state->hotspot_y = req->hot_y; } else { fb = NULL; } @@ -1387,6 +1503,7 @@ retry: out: if (fb) drm_framebuffer_put(fb); + fb = NULL; if (plane->old_fb) drm_framebuffer_put(plane->old_fb); plane->old_fb = NULL; @@ -1442,6 +1559,36 @@ out: * Drivers implementing damage can use drm_atomic_helper_damage_iter_init() and * drm_atomic_helper_damage_iter_next() helper iterator function to get damage * rectangles clipped to &drm_plane_state.src. + * + * Note that there are two types of damage handling: frame damage and buffer + * damage, the type of damage handling implemented depends on a driver's upload + * target. Drivers implementing a per-plane or per-CRTC upload target need to + * handle frame damage, while drivers implementing a per-buffer upload target + * need to handle buffer damage. + * + * The existing damage helpers only support the frame damage type, there is no + * buffer age support or similar damage accumulation algorithm implemented yet. + * + * Only drivers handling frame damage can use the mentioned damage helpers to + * iterate over the damaged regions. Drivers that handle buffer damage, must set + * &drm_plane_state.ignore_damage_clips for drm_atomic_helper_damage_iter_init() + * to know that damage clips should be ignored and return &drm_plane_state.src + * as the damage rectangle, to force a full plane update. + * + * Drivers with a per-buffer upload target could compare the &drm_plane_state.fb + * of the old and new plane states to determine if the framebuffer attached to a + * plane has changed or not since the last plane update. If &drm_plane_state.fb + * has changed, then &drm_plane_state.ignore_damage_clips must be set to true. + * + * That is because drivers with a per-plane upload target, expect the backing + * storage buffer to not change for a given plane. If the upload buffer changes + * between page flips, the new upload buffer has to be updated as a whole. This + * can be improved in the future if support for frame damage is added to the DRM + * damage helpers, similarly to how user-space already handle this case as it is + * explained in the following documents: + * + * https://registry.khronos.org/EGL/extensions/KHR/EGL_KHR_swap_buffers_with_damage.txt + * https://emersion.fr/blog/2019/intro-to-damage-tracking/ */ /** diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 5e95089676ff81..7982be4b0306d5 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -279,35 +279,3 @@ void drm_plane_helper_destroy(struct drm_plane *plane) kfree(plane); } EXPORT_SYMBOL(drm_plane_helper_destroy); - -/** - * drm_plane_helper_atomic_check() - Helper to check plane atomic-state - * @plane: plane to check - * @state: atomic state object - * - * Provides a default plane-state check handler for planes whose atomic-state - * scale and positioning are not expected to change since the plane is always - * a fullscreen scanout buffer. - * - * This is often the case for the primary plane of simple framebuffers. See - * also drm_crtc_helper_atomic_check() for the respective CRTC-state check - * helper function. - * - * RETURNS: - * Zero on success, or an errno code otherwise. - */ -int drm_plane_helper_atomic_check(struct drm_plane *plane, struct drm_atomic_state *state) -{ - struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, plane); - struct drm_crtc *new_crtc = new_plane_state->crtc; - struct drm_crtc_state *new_crtc_state = NULL; - - if (new_crtc) - new_crtc_state = drm_atomic_get_new_crtc_state(state, new_crtc); - - return drm_atomic_helper_check_plane_state(new_plane_state, new_crtc_state, - DRM_PLANE_NO_SCALING, - DRM_PLANE_NO_SCALING, - false, false); -} -EXPORT_SYMBOL(drm_plane_helper_atomic_check); diff --git a/drivers/gpu/drm/drm_property.c b/drivers/gpu/drm/drm_property.c index dfec479830e496..596272149a3599 100644 --- a/drivers/gpu/drm/drm_property.c +++ b/drivers/gpu/drm/drm_property.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include "drm_crtc_internal.h" @@ -751,6 +752,64 @@ bool drm_property_replace_blob(struct drm_property_blob **blob, } EXPORT_SYMBOL(drm_property_replace_blob); +/** + * drm_property_replace_blob_from_id - replace a blob property taking a reference + * @dev: DRM device + * @blob: a pointer to the member blob to be replaced + * @blob_id: the id of the new blob to replace with + * @expected_size: expected size of the blob property + * @expected_elem_size: expected size of an element in the blob property + * @replaced: if the blob was in fact replaced + * + * Look up the new blob from id, take its reference, check expected sizes of + * the blob and its element and replace the old blob by the new one. Advertise + * if the replacement operation was successful. + * + * Return: true if the blob was in fact replaced. -EINVAL if the new blob was + * not found or sizes don't match. + */ +int drm_property_replace_blob_from_id(struct drm_device *dev, + struct drm_property_blob **blob, + uint64_t blob_id, + ssize_t expected_size, + ssize_t expected_elem_size, + bool *replaced) +{ + struct drm_property_blob *new_blob = NULL; + + if (blob_id != 0) { + new_blob = drm_property_lookup_blob(dev, blob_id); + if (new_blob == NULL) { + drm_dbg_atomic(dev, + "cannot find blob ID %llu\n", blob_id); + return -EINVAL; + } + + if (expected_size > 0 && + new_blob->length != expected_size) { + drm_dbg_atomic(dev, + "[BLOB:%d] length %zu different from expected %zu\n", + new_blob->base.id, new_blob->length, expected_size); + drm_property_blob_put(new_blob); + return -EINVAL; + } + if (expected_elem_size > 0 && + new_blob->length % expected_elem_size != 0) { + drm_dbg_atomic(dev, + "[BLOB:%d] length %zu not divisible by element size %zu\n", + new_blob->base.id, new_blob->length, expected_elem_size); + drm_property_blob_put(new_blob); + return -EINVAL; + } + } + + *replaced |= drm_property_replace_blob(blob, new_blob); + drm_property_blob_put(new_blob); + + return 0; +} +EXPORT_SYMBOL(drm_property_replace_blob_from_id); + int drm_mode_getblob_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { diff --git a/drivers/gpu/drm/drm_scatter.c b/drivers/gpu/drm/drm_scatter.c deleted file mode 100644 index f4e6184d187721..00000000000000 --- a/drivers/gpu/drm/drm_scatter.c +++ /dev/null @@ -1,220 +0,0 @@ -/* - * \file drm_scatter.c - * IOCTLs to manage scatter/gather memory - * - * \author Gareth Hughes - */ - -/* - * Created: Mon Dec 18 23:20:54 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 -#include -#include - -#include -#include -#include - -#include "drm_legacy.h" - -#define DEBUG_SCATTER 0 - -static void drm_sg_cleanup(struct drm_sg_mem * entry) -{ - struct page *page; - int i; - - for (i = 0; i < entry->pages; i++) { - page = entry->pagelist[i]; - if (page) - ClearPageReserved(page); - } - - vfree(entry->virtual); - - kfree(entry->busaddr); - kfree(entry->pagelist); - kfree(entry); -} - -void drm_legacy_sg_cleanup(struct drm_device *dev) -{ - if (drm_core_check_feature(dev, DRIVER_SG) && dev->sg && - drm_core_check_feature(dev, DRIVER_LEGACY)) { - drm_sg_cleanup(dev->sg); - dev->sg = NULL; - } -} -#ifdef _LP64 -# define ScatterHandle(x) (unsigned int)((x >> 32) + (x & ((1L << 32) - 1))) -#else -# define ScatterHandle(x) (unsigned int)(x) -#endif - -int drm_legacy_sg_alloc(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_scatter_gather *request = data; - struct drm_sg_mem *entry; - unsigned long pages, i, j; - - DRM_DEBUG("\n"); - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - if (!drm_core_check_feature(dev, DRIVER_SG)) - return -EOPNOTSUPP; - - if (request->size > SIZE_MAX - PAGE_SIZE) - return -EINVAL; - - if (dev->sg) - return -EINVAL; - - entry = kzalloc(sizeof(*entry), GFP_KERNEL); - if (!entry) - return -ENOMEM; - - pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE; - DRM_DEBUG("size=%ld pages=%ld\n", request->size, pages); - - entry->pages = pages; - entry->pagelist = kcalloc(pages, sizeof(*entry->pagelist), GFP_KERNEL); - if (!entry->pagelist) { - kfree(entry); - return -ENOMEM; - } - - entry->busaddr = kcalloc(pages, sizeof(*entry->busaddr), GFP_KERNEL); - if (!entry->busaddr) { - kfree(entry->pagelist); - kfree(entry); - return -ENOMEM; - } - - entry->virtual = vmalloc_32(pages << PAGE_SHIFT); - if (!entry->virtual) { - kfree(entry->busaddr); - kfree(entry->pagelist); - kfree(entry); - return -ENOMEM; - } - - /* This also forces the mapping of COW pages, so our page list - * will be valid. Please don't remove it... - */ - memset(entry->virtual, 0, pages << PAGE_SHIFT); - - entry->handle = ScatterHandle((unsigned long)entry->virtual); - - DRM_DEBUG("handle = %08lx\n", entry->handle); - DRM_DEBUG("virtual = %p\n", entry->virtual); - - for (i = (unsigned long)entry->virtual, j = 0; j < pages; - i += PAGE_SIZE, j++) { - entry->pagelist[j] = vmalloc_to_page((void *)i); - if (!entry->pagelist[j]) - goto failed; - SetPageReserved(entry->pagelist[j]); - } - - request->handle = entry->handle; - - dev->sg = entry; - -#if DEBUG_SCATTER - /* Verify that each page points to its virtual address, and vice - * versa. - */ - { - int error = 0; - - for (i = 0; i < pages; i++) { - unsigned long *tmp; - - tmp = page_address(entry->pagelist[i]); - for (j = 0; - j < PAGE_SIZE / sizeof(unsigned long); - j++, tmp++) { - *tmp = 0xcafebabe; - } - tmp = (unsigned long *)((u8 *) entry->virtual + - (PAGE_SIZE * i)); - for (j = 0; - j < PAGE_SIZE / sizeof(unsigned long); - j++, tmp++) { - if (*tmp != 0xcafebabe && error == 0) { - error = 1; - DRM_ERROR("Scatter allocation error, " - "pagelist does not match " - "virtual mapping\n"); - } - } - tmp = page_address(entry->pagelist[i]); - for (j = 0; - j < PAGE_SIZE / sizeof(unsigned long); - j++, tmp++) { - *tmp = 0; - } - } - if (error == 0) - DRM_ERROR("Scatter allocation matches pagelist\n"); - } -#endif - - return 0; - - failed: - drm_sg_cleanup(entry); - return -ENOMEM; -} - -int drm_legacy_sg_free(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_scatter_gather *request = data; - struct drm_sg_mem *entry; - - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return -EOPNOTSUPP; - - if (!drm_core_check_feature(dev, DRIVER_SG)) - return -EOPNOTSUPP; - - entry = dev->sg; - dev->sg = NULL; - - if (!entry || entry->handle != request->handle) - return -EINVAL; - - DRM_DEBUG("virtual = %p\n", entry->virtual); - - drm_sg_cleanup(entry); - - return 0; -} diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index 01da6789d04409..84101baeecc6e6 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -126,6 +126,11 @@ * synchronize between the two. * This requirement is inherited from the Vulkan fence API. * + * If &DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE is set, the ioctl will also set + * a fence deadline hint on the backing fences before waiting, to provide the + * fence signaler with an appropriate sense of urgency. The deadline is + * specified as an absolute &CLOCK_MONOTONIC value in units of ns. + * * Similarly, &DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT takes an array of syncobj * handles as well as an array of u64 points and does a host-side wait on all * of syncobj fences at the given points simultaneously. @@ -1027,7 +1032,8 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs, uint32_t count, uint32_t flags, signed long timeout, - uint32_t *idx) + uint32_t *idx, + ktime_t *deadline) { struct syncobj_wait_entry *entries; struct dma_fence *fence; @@ -1108,6 +1114,15 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs, drm_syncobj_fence_add_wait(syncobjs[i], &entries[i]); } + if (deadline) { + for (i = 0; i < count; ++i) { + fence = entries[i].fence; + if (!fence) + continue; + dma_fence_set_deadline(fence, *deadline); + } + } + do { set_current_state(TASK_INTERRUPTIBLE); @@ -1206,7 +1221,8 @@ static int drm_syncobj_array_wait(struct drm_device *dev, struct drm_file *file_private, struct drm_syncobj_wait *wait, struct drm_syncobj_timeline_wait *timeline_wait, - struct drm_syncobj **syncobjs, bool timeline) + struct drm_syncobj **syncobjs, bool timeline, + ktime_t *deadline) { signed long timeout = 0; uint32_t first = ~0; @@ -1217,7 +1233,8 @@ static int drm_syncobj_array_wait(struct drm_device *dev, NULL, wait->count_handles, wait->flags, - timeout, &first); + timeout, &first, + deadline); if (timeout < 0) return timeout; wait->first_signaled = first; @@ -1227,7 +1244,8 @@ static int drm_syncobj_array_wait(struct drm_device *dev, u64_to_user_ptr(timeline_wait->points), timeline_wait->count_handles, timeline_wait->flags, - timeout, &first); + timeout, &first, + deadline); if (timeout < 0) return timeout; timeline_wait->first_signaled = first; @@ -1298,17 +1316,22 @@ drm_syncobj_wait_ioctl(struct drm_device *dev, void *data, { struct drm_syncobj_wait *args = data; struct drm_syncobj **syncobjs; + unsigned int possible_flags; + ktime_t t, *tp = NULL; int ret = 0; if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ)) return -EOPNOTSUPP; - if (args->flags & ~(DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL | - DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT)) + possible_flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL | + DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT | + DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE; + + if (args->flags & ~possible_flags) return -EINVAL; if (args->count_handles == 0) - return -EINVAL; + return 0; ret = drm_syncobj_array_find(file_private, u64_to_user_ptr(args->handles), @@ -1317,8 +1340,13 @@ drm_syncobj_wait_ioctl(struct drm_device *dev, void *data, if (ret < 0) return ret; + if (args->flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE) { + t = ns_to_ktime(args->deadline_nsec); + tp = &t; + } + ret = drm_syncobj_array_wait(dev, file_private, - args, NULL, syncobjs, false); + args, NULL, syncobjs, false, tp); drm_syncobj_array_free(syncobjs, args->count_handles); @@ -1331,18 +1359,23 @@ drm_syncobj_timeline_wait_ioctl(struct drm_device *dev, void *data, { struct drm_syncobj_timeline_wait *args = data; struct drm_syncobj **syncobjs; + unsigned int possible_flags; + ktime_t t, *tp = NULL; int ret = 0; if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE)) return -EOPNOTSUPP; - if (args->flags & ~(DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL | - DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT | - DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE)) + possible_flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL | + DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT | + DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE | + DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE; + + if (args->flags & ~possible_flags) return -EINVAL; if (args->count_handles == 0) - return -EINVAL; + return 0; ret = drm_syncobj_array_find(file_private, u64_to_user_ptr(args->handles), @@ -1351,8 +1384,13 @@ drm_syncobj_timeline_wait_ioctl(struct drm_device *dev, void *data, if (ret < 0) return ret; + if (args->flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_DEADLINE) { + t = ns_to_ktime(args->deadline_nsec); + tp = &t; + } + ret = drm_syncobj_array_wait(dev, file_private, - NULL, args, syncobjs, true); + NULL, args, syncobjs, true, tp); drm_syncobj_array_free(syncobjs, args->count_handles); @@ -1365,7 +1403,7 @@ static void syncobj_eventfd_entry_fence_func(struct dma_fence *fence, struct syncobj_eventfd_entry *entry = container_of(cb, struct syncobj_eventfd_entry, fence_cb); - eventfd_signal(entry->ev_fd_ctx, 1); + eventfd_signal(entry->ev_fd_ctx); syncobj_eventfd_entry_free(entry); } @@ -1388,13 +1426,13 @@ syncobj_eventfd_entry_func(struct drm_syncobj *syncobj, entry->fence = fence; if (entry->flags & DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE) { - eventfd_signal(entry->ev_fd_ctx, 1); + eventfd_signal(entry->ev_fd_ctx); syncobj_eventfd_entry_free(entry); } else { ret = dma_fence_add_callback(fence, &entry->fence_cb, syncobj_eventfd_entry_fence_func); if (ret == -ENOENT) { - eventfd_signal(entry->ev_fd_ctx, 1); + eventfd_signal(entry->ev_fd_ctx); syncobj_eventfd_entry_free(entry); } } diff --git a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c index 877e2067534fa2..702a12bc93bd9b 100644 --- a/drivers/gpu/drm/drm_vblank.c +++ b/drivers/gpu/drm/drm_vblank.c @@ -210,11 +210,6 @@ static u32 __get_vblank_counter(struct drm_device *dev, unsigned int pipe) if (crtc->funcs->get_vblank_counter) return crtc->funcs->get_vblank_counter(crtc); } -#ifdef CONFIG_DRM_LEGACY - else if (dev->driver->get_vblank_counter) { - return dev->driver->get_vblank_counter(dev, pipe); - } -#endif return drm_vblank_no_hw_counter(dev, pipe); } @@ -433,11 +428,6 @@ static void __disable_vblank(struct drm_device *dev, unsigned int pipe) if (crtc->funcs->disable_vblank) crtc->funcs->disable_vblank(crtc); } -#ifdef CONFIG_DRM_LEGACY - else { - dev->driver->disable_vblank(dev, pipe); - } -#endif } /* @@ -1151,11 +1141,6 @@ static int __enable_vblank(struct drm_device *dev, unsigned int pipe) if (crtc->funcs->enable_vblank) return crtc->funcs->enable_vblank(crtc); } -#ifdef CONFIG_DRM_LEGACY - else if (dev->driver->enable_vblank) { - return dev->driver->enable_vblank(dev, pipe); - } -#endif return -EINVAL; } @@ -1574,88 +1559,6 @@ void drm_crtc_vblank_restore(struct drm_crtc *crtc) } EXPORT_SYMBOL(drm_crtc_vblank_restore); -static void drm_legacy_vblank_pre_modeset(struct drm_device *dev, - unsigned int pipe) -{ - struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; - - /* vblank is not initialized (IRQ not installed ?), or has been freed */ - if (!drm_dev_has_vblank(dev)) - return; - - if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) - return; - - /* - * To avoid all the problems that might happen if interrupts - * were enabled/disabled around or between these calls, we just - * have the kernel take a reference on the CRTC (just once though - * to avoid corrupting the count if multiple, mismatch calls occur), - * so that interrupts remain enabled in the interim. - */ - if (!vblank->inmodeset) { - vblank->inmodeset = 0x1; - if (drm_vblank_get(dev, pipe) == 0) - vblank->inmodeset |= 0x2; - } -} - -static void drm_legacy_vblank_post_modeset(struct drm_device *dev, - unsigned int pipe) -{ - struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; - - /* vblank is not initialized (IRQ not installed ?), or has been freed */ - if (!drm_dev_has_vblank(dev)) - return; - - if (drm_WARN_ON(dev, pipe >= dev->num_crtcs)) - return; - - if (vblank->inmodeset) { - spin_lock_irq(&dev->vbl_lock); - drm_reset_vblank_timestamp(dev, pipe); - spin_unlock_irq(&dev->vbl_lock); - - if (vblank->inmodeset & 0x2) - drm_vblank_put(dev, pipe); - - vblank->inmodeset = 0; - } -} - -int drm_legacy_modeset_ctl_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_modeset_ctl *modeset = data; - unsigned int pipe; - - /* If drm_vblank_init() hasn't been called yet, just no-op */ - if (!drm_dev_has_vblank(dev)) - return 0; - - /* KMS drivers handle this internally */ - if (!drm_core_check_feature(dev, DRIVER_LEGACY)) - return 0; - - pipe = modeset->crtc; - if (pipe >= dev->num_crtcs) - return -EINVAL; - - switch (modeset->cmd) { - case _DRM_PRE_MODESET: - drm_legacy_vblank_pre_modeset(dev, pipe); - break; - case _DRM_POST_MODESET: - drm_legacy_vblank_post_modeset(dev, pipe); - break; - default: - return -EINVAL; - } - - return 0; -} - static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe, u64 req_seq, union drm_wait_vblank *vblwait, @@ -1780,10 +1683,6 @@ static void drm_wait_vblank_reply(struct drm_device *dev, unsigned int pipe, static bool drm_wait_vblank_supported(struct drm_device *dev) { -#if IS_ENABLED(CONFIG_DRM_LEGACY) - if (unlikely(drm_core_check_feature(dev, DRIVER_LEGACY))) - return dev->irq_enabled; -#endif return drm_dev_has_vblank(dev); } diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c deleted file mode 100644 index 87c9fe55dec76a..00000000000000 --- a/drivers/gpu/drm/drm_vm.c +++ /dev/null @@ -1,665 +0,0 @@ -/* - * \file drm_vm.c - * Memory mapping for DRM - * - * \author Rickard E. (Rik) Faith - * \author Gareth Hughes - */ - -/* - * Created: Mon Jan 4 08:58:31 1999 by faith@valinux.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. - */ - -#include -#include -#include -#include -#include - -#if defined(__ia64__) -#include -#include -#endif -#include - -#include -#include -#include -#include -#include - -#include "drm_internal.h" -#include "drm_legacy.h" - -struct drm_vma_entry { - struct list_head head; - struct vm_area_struct *vma; - pid_t pid; -}; - -static void drm_vm_open(struct vm_area_struct *vma); -static void drm_vm_close(struct vm_area_struct *vma); - -static pgprot_t drm_io_prot(struct drm_local_map *map, - struct vm_area_struct *vma) -{ - pgprot_t tmp = vm_get_page_prot(vma->vm_flags); - -#if defined(__i386__) || defined(__x86_64__) || defined(__powerpc__) || \ - defined(__mips__) || defined(__loongarch__) - if (map->type == _DRM_REGISTERS && !(map->flags & _DRM_WRITE_COMBINING)) - tmp = pgprot_noncached(tmp); - else - tmp = pgprot_writecombine(tmp); -#elif defined(__ia64__) - if (efi_range_is_wc(vma->vm_start, vma->vm_end - - vma->vm_start)) - tmp = pgprot_writecombine(tmp); - else - tmp = pgprot_noncached(tmp); -#elif defined(__sparc__) || defined(__arm__) - tmp = pgprot_noncached(tmp); -#endif - return tmp; -} - -static pgprot_t drm_dma_prot(uint32_t map_type, struct vm_area_struct *vma) -{ - pgprot_t tmp = vm_get_page_prot(vma->vm_flags); - -#if defined(__powerpc__) && defined(CONFIG_NOT_COHERENT_CACHE) - tmp = pgprot_noncached_wc(tmp); -#endif - return tmp; -} - -/* - * \c fault method for AGP virtual memory. - * - * \param vma virtual memory area. - * \param address access address. - * \return pointer to the page structure. - * - * Find the right map and if it's AGP memory find the real physical page to - * map, get the page, increment the use count and return it. - */ -#if IS_ENABLED(CONFIG_AGP) -static vm_fault_t drm_vm_fault(struct vm_fault *vmf) -{ - struct vm_area_struct *vma = vmf->vma; - struct drm_file *priv = vma->vm_file->private_data; - struct drm_device *dev = priv->minor->dev; - struct drm_local_map *map = NULL; - struct drm_map_list *r_list; - struct drm_hash_item *hash; - - /* - * Find the right map - */ - if (!dev->agp) - goto vm_fault_error; - - if (!dev->agp || !dev->agp->cant_use_aperture) - goto vm_fault_error; - - if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff, &hash)) - goto vm_fault_error; - - r_list = drm_hash_entry(hash, struct drm_map_list, hash); - map = r_list->map; - - if (map && map->type == _DRM_AGP) { - /* - * Using vm_pgoff as a selector forces us to use this unusual - * addressing scheme. - */ - resource_size_t offset = vmf->address - vma->vm_start; - resource_size_t baddr = map->offset + offset; - struct drm_agp_mem *agpmem; - struct page *page; - -#ifdef __alpha__ - /* - * Adjust to a bus-relative address - */ - baddr -= dev->hose->mem_space->start; -#endif - - /* - * It's AGP memory - find the real physical page to map - */ - list_for_each_entry(agpmem, &dev->agp->memory, head) { - if (agpmem->bound <= baddr && - agpmem->bound + agpmem->pages * PAGE_SIZE > baddr) - break; - } - - if (&agpmem->head == &dev->agp->memory) - goto vm_fault_error; - - /* - * Get the page, inc the use count, and return it - */ - offset = (baddr - agpmem->bound) >> PAGE_SHIFT; - page = agpmem->memory->pages[offset]; - get_page(page); - vmf->page = page; - - DRM_DEBUG - ("baddr = 0x%llx page = 0x%p, offset = 0x%llx, count=%d\n", - (unsigned long long)baddr, - agpmem->memory->pages[offset], - (unsigned long long)offset, - page_count(page)); - return 0; - } -vm_fault_error: - return VM_FAULT_SIGBUS; /* Disallow mremap */ -} -#else -static vm_fault_t drm_vm_fault(struct vm_fault *vmf) -{ - return VM_FAULT_SIGBUS; -} -#endif - -/* - * \c nopage method for shared virtual memory. - * - * \param vma virtual memory area. - * \param address access address. - * \return pointer to the page structure. - * - * Get the mapping, find the real physical page to map, get the page, and - * return it. - */ -static vm_fault_t drm_vm_shm_fault(struct vm_fault *vmf) -{ - struct vm_area_struct *vma = vmf->vma; - struct drm_local_map *map = vma->vm_private_data; - unsigned long offset; - unsigned long i; - struct page *page; - - if (!map) - return VM_FAULT_SIGBUS; /* Nothing allocated */ - - offset = vmf->address - vma->vm_start; - i = (unsigned long)map->handle + offset; - page = vmalloc_to_page((void *)i); - if (!page) - return VM_FAULT_SIGBUS; - get_page(page); - vmf->page = page; - - DRM_DEBUG("shm_fault 0x%lx\n", offset); - return 0; -} - -/* - * \c close method for shared virtual memory. - * - * \param vma virtual memory area. - * - * Deletes map information if we are the last - * person to close a mapping and it's not in the global maplist. - */ -static void drm_vm_shm_close(struct vm_area_struct *vma) -{ - struct drm_file *priv = vma->vm_file->private_data; - struct drm_device *dev = priv->minor->dev; - struct drm_vma_entry *pt, *temp; - struct drm_local_map *map; - struct drm_map_list *r_list; - int found_maps = 0; - - DRM_DEBUG("0x%08lx,0x%08lx\n", - vma->vm_start, vma->vm_end - vma->vm_start); - - map = vma->vm_private_data; - - mutex_lock(&dev->struct_mutex); - list_for_each_entry_safe(pt, temp, &dev->vmalist, head) { - if (pt->vma->vm_private_data == map) - found_maps++; - if (pt->vma == vma) { - list_del(&pt->head); - kfree(pt); - } - } - - /* We were the only map that was found */ - if (found_maps == 1 && map->flags & _DRM_REMOVABLE) { - /* Check to see if we are in the maplist, if we are not, then - * we delete this mappings information. - */ - found_maps = 0; - list_for_each_entry(r_list, &dev->maplist, head) { - if (r_list->map == map) - found_maps++; - } - - if (!found_maps) { - switch (map->type) { - case _DRM_REGISTERS: - case _DRM_FRAME_BUFFER: - arch_phys_wc_del(map->mtrr); - iounmap(map->handle); - break; - case _DRM_SHM: - vfree(map->handle); - break; - case _DRM_AGP: - case _DRM_SCATTER_GATHER: - break; - case _DRM_CONSISTENT: - dma_free_coherent(dev->dev, - map->size, - map->handle, - map->offset); - break; - } - kfree(map); - } - } - mutex_unlock(&dev->struct_mutex); -} - -/* - * \c fault method for DMA virtual memory. - * - * \param address access address. - * \return pointer to the page structure. - * - * Determine the page number from the page offset and get it from drm_device_dma::pagelist. - */ -static vm_fault_t drm_vm_dma_fault(struct vm_fault *vmf) -{ - struct vm_area_struct *vma = vmf->vma; - struct drm_file *priv = vma->vm_file->private_data; - struct drm_device *dev = priv->minor->dev; - struct drm_device_dma *dma = dev->dma; - unsigned long offset; - unsigned long page_nr; - struct page *page; - - if (!dma) - return VM_FAULT_SIGBUS; /* Error */ - if (!dma->pagelist) - return VM_FAULT_SIGBUS; /* Nothing allocated */ - - offset = vmf->address - vma->vm_start; - /* vm_[pg]off[set] should be 0 */ - page_nr = offset >> PAGE_SHIFT; /* page_nr could just be vmf->pgoff */ - page = virt_to_page((void *)dma->pagelist[page_nr]); - - get_page(page); - vmf->page = page; - - DRM_DEBUG("dma_fault 0x%lx (page %lu)\n", offset, page_nr); - return 0; -} - -/* - * \c fault method for scatter-gather virtual memory. - * - * \param address access address. - * \return pointer to the page structure. - * - * Determine the map offset from the page offset and get it from drm_sg_mem::pagelist. - */ -static vm_fault_t drm_vm_sg_fault(struct vm_fault *vmf) -{ - struct vm_area_struct *vma = vmf->vma; - struct drm_local_map *map = vma->vm_private_data; - struct drm_file *priv = vma->vm_file->private_data; - struct drm_device *dev = priv->minor->dev; - struct drm_sg_mem *entry = dev->sg; - unsigned long offset; - unsigned long map_offset; - unsigned long page_offset; - struct page *page; - - if (!entry) - return VM_FAULT_SIGBUS; /* Error */ - if (!entry->pagelist) - return VM_FAULT_SIGBUS; /* Nothing allocated */ - - offset = vmf->address - vma->vm_start; - map_offset = map->offset - (unsigned long)dev->sg->virtual; - page_offset = (offset >> PAGE_SHIFT) + (map_offset >> PAGE_SHIFT); - page = entry->pagelist[page_offset]; - get_page(page); - vmf->page = page; - - return 0; -} - -/** AGP virtual memory operations */ -static const struct vm_operations_struct drm_vm_ops = { - .fault = drm_vm_fault, - .open = drm_vm_open, - .close = drm_vm_close, -}; - -/** Shared virtual memory operations */ -static const struct vm_operations_struct drm_vm_shm_ops = { - .fault = drm_vm_shm_fault, - .open = drm_vm_open, - .close = drm_vm_shm_close, -}; - -/** DMA virtual memory operations */ -static const struct vm_operations_struct drm_vm_dma_ops = { - .fault = drm_vm_dma_fault, - .open = drm_vm_open, - .close = drm_vm_close, -}; - -/** Scatter-gather virtual memory operations */ -static const struct vm_operations_struct drm_vm_sg_ops = { - .fault = drm_vm_sg_fault, - .open = drm_vm_open, - .close = drm_vm_close, -}; - -static void drm_vm_open_locked(struct drm_device *dev, - struct vm_area_struct *vma) -{ - struct drm_vma_entry *vma_entry; - - DRM_DEBUG("0x%08lx,0x%08lx\n", - vma->vm_start, vma->vm_end - vma->vm_start); - - vma_entry = kmalloc(sizeof(*vma_entry), GFP_KERNEL); - if (vma_entry) { - vma_entry->vma = vma; - vma_entry->pid = current->pid; - list_add(&vma_entry->head, &dev->vmalist); - } -} - -static void drm_vm_open(struct vm_area_struct *vma) -{ - struct drm_file *priv = vma->vm_file->private_data; - struct drm_device *dev = priv->minor->dev; - - mutex_lock(&dev->struct_mutex); - drm_vm_open_locked(dev, vma); - mutex_unlock(&dev->struct_mutex); -} - -static void drm_vm_close_locked(struct drm_device *dev, - struct vm_area_struct *vma) -{ - struct drm_vma_entry *pt, *temp; - - DRM_DEBUG("0x%08lx,0x%08lx\n", - vma->vm_start, vma->vm_end - vma->vm_start); - - list_for_each_entry_safe(pt, temp, &dev->vmalist, head) { - if (pt->vma == vma) { - list_del(&pt->head); - kfree(pt); - break; - } - } -} - -/* - * \c close method for all virtual memory types. - * - * \param vma virtual memory area. - * - * Search the \p vma private data entry in drm_device::vmalist, unlink it, and - * free it. - */ -static void drm_vm_close(struct vm_area_struct *vma) -{ - struct drm_file *priv = vma->vm_file->private_data; - struct drm_device *dev = priv->minor->dev; - - mutex_lock(&dev->struct_mutex); - drm_vm_close_locked(dev, vma); - mutex_unlock(&dev->struct_mutex); -} - -/* - * mmap DMA memory. - * - * \param file_priv DRM file private. - * \param vma virtual memory area. - * \return zero on success or a negative number on failure. - * - * Sets the virtual memory area operations structure to vm_dma_ops, the file - * pointer, and calls vm_open(). - */ -static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma) -{ - struct drm_file *priv = filp->private_data; - struct drm_device *dev; - struct drm_device_dma *dma; - unsigned long length = vma->vm_end - vma->vm_start; - - dev = priv->minor->dev; - dma = dev->dma; - DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n", - vma->vm_start, vma->vm_end, vma->vm_pgoff); - - /* Length must match exact page count */ - if (!dma || (length >> PAGE_SHIFT) != dma->page_count) { - return -EINVAL; - } - - if (!capable(CAP_SYS_ADMIN) && - (dma->flags & _DRM_DMA_USE_PCI_RO)) { - vm_flags_clear(vma, VM_WRITE | VM_MAYWRITE); -#if defined(__i386__) || defined(__x86_64__) - pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW; -#else - /* Ye gads this is ugly. With more thought - we could move this up higher and use - `protection_map' instead. */ - vma->vm_page_prot = - __pgprot(pte_val - (pte_wrprotect - (__pte(pgprot_val(vma->vm_page_prot))))); -#endif - } - - vma->vm_ops = &drm_vm_dma_ops; - - vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP); - - drm_vm_open_locked(dev, vma); - return 0; -} - -static resource_size_t drm_core_get_reg_ofs(struct drm_device *dev) -{ -#ifdef __alpha__ - return dev->hose->dense_mem_base; -#else - return 0; -#endif -} - -/* - * mmap DMA memory. - * - * \param file_priv DRM file private. - * \param vma virtual memory area. - * \return zero on success or a negative number on failure. - * - * If the virtual memory area has no offset associated with it then it's a DMA - * area, so calls mmap_dma(). Otherwise searches the map in drm_device::maplist, - * checks that the restricted flag is not set, sets the virtual memory operations - * according to the mapping type and remaps the pages. Finally sets the file - * pointer and calls vm_open(). - */ -static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma) -{ - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->minor->dev; - struct drm_local_map *map = NULL; - resource_size_t offset = 0; - struct drm_hash_item *hash; - - DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n", - vma->vm_start, vma->vm_end, vma->vm_pgoff); - - if (!priv->authenticated) - return -EACCES; - - /* We check for "dma". On Apple's UniNorth, it's valid to have - * the AGP mapped at physical address 0 - * --BenH. - */ - if (!vma->vm_pgoff -#if IS_ENABLED(CONFIG_AGP) - && (!dev->agp - || dev->agp->agp_info.device->vendor != PCI_VENDOR_ID_APPLE) -#endif - ) - return drm_mmap_dma(filp, vma); - - if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff, &hash)) { - DRM_ERROR("Could not find map\n"); - return -EINVAL; - } - - map = drm_hash_entry(hash, struct drm_map_list, hash)->map; - if (!map || ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) - return -EPERM; - - /* Check for valid size. */ - if (map->size < vma->vm_end - vma->vm_start) - return -EINVAL; - - if (!capable(CAP_SYS_ADMIN) && (map->flags & _DRM_READ_ONLY)) { - vm_flags_clear(vma, VM_WRITE | VM_MAYWRITE); -#if defined(__i386__) || defined(__x86_64__) - pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW; -#else - /* Ye gads this is ugly. With more thought - we could move this up higher and use - `protection_map' instead. */ - vma->vm_page_prot = - __pgprot(pte_val - (pte_wrprotect - (__pte(pgprot_val(vma->vm_page_prot))))); -#endif - } - - switch (map->type) { -#if !defined(__arm__) - case _DRM_AGP: - if (dev->agp && dev->agp->cant_use_aperture) { - /* - * On some platforms we can't talk to bus dma address from the CPU, so for - * memory of type DRM_AGP, we'll deal with sorting out the real physical - * pages and mappings in fault() - */ -#if defined(__powerpc__) - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); -#endif - vma->vm_ops = &drm_vm_ops; - break; - } - fallthrough; /* to _DRM_FRAME_BUFFER... */ -#endif - case _DRM_FRAME_BUFFER: - case _DRM_REGISTERS: - offset = drm_core_get_reg_ofs(dev); - vma->vm_page_prot = drm_io_prot(map, vma); - if (io_remap_pfn_range(vma, vma->vm_start, - (map->offset + offset) >> PAGE_SHIFT, - vma->vm_end - vma->vm_start, - vma->vm_page_prot)) - return -EAGAIN; - DRM_DEBUG(" Type = %d; start = 0x%lx, end = 0x%lx," - " offset = 0x%llx\n", - map->type, - vma->vm_start, vma->vm_end, (unsigned long long)(map->offset + offset)); - - vma->vm_ops = &drm_vm_ops; - break; - case _DRM_CONSISTENT: - /* Consistent memory is really like shared memory. But - * it's allocated in a different way, so avoid fault */ - if (remap_pfn_range(vma, vma->vm_start, - page_to_pfn(virt_to_page(map->handle)), - vma->vm_end - vma->vm_start, vma->vm_page_prot)) - return -EAGAIN; - vma->vm_page_prot = drm_dma_prot(map->type, vma); - fallthrough; /* to _DRM_SHM */ - case _DRM_SHM: - vma->vm_ops = &drm_vm_shm_ops; - vma->vm_private_data = (void *)map; - break; - case _DRM_SCATTER_GATHER: - vma->vm_ops = &drm_vm_sg_ops; - vma->vm_private_data = (void *)map; - vma->vm_page_prot = drm_dma_prot(map->type, vma); - break; - default: - return -EINVAL; /* This should never happen. */ - } - vm_flags_set(vma, VM_DONTEXPAND | VM_DONTDUMP); - - drm_vm_open_locked(dev, vma); - return 0; -} - -int drm_legacy_mmap(struct file *filp, struct vm_area_struct *vma) -{ - struct drm_file *priv = filp->private_data; - struct drm_device *dev = priv->minor->dev; - int ret; - - if (drm_dev_is_unplugged(dev)) - return -ENODEV; - - mutex_lock(&dev->struct_mutex); - ret = drm_mmap_locked(filp, vma); - mutex_unlock(&dev->struct_mutex); - - return ret; -} -EXPORT_SYMBOL(drm_legacy_mmap); - -#if IS_ENABLED(CONFIG_DRM_LEGACY) -void drm_legacy_vma_flush(struct drm_device *dev) -{ - struct drm_vma_entry *vma, *vma_temp; - - /* Clear vma list (only needed for legacy drivers) */ - list_for_each_entry_safe(vma, vma_temp, &dev->vmalist, head) { - list_del(&vma->head); - kfree(vma); - } -} -#endif diff --git a/drivers/gpu/drm/etnaviv/etnaviv_drv.c b/drivers/gpu/drm/etnaviv/etnaviv_drv.c index a8d3fa81e4ec5d..6228ce6032482f 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_drv.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_drv.c @@ -640,16 +640,14 @@ static int etnaviv_pdev_probe(struct platform_device *pdev) return component_master_add_with_match(dev, &etnaviv_master_ops, match); } -static int etnaviv_pdev_remove(struct platform_device *pdev) +static void etnaviv_pdev_remove(struct platform_device *pdev) { component_master_del(&pdev->dev, &etnaviv_master_ops); - - return 0; } static struct platform_driver etnaviv_platform_driver = { .probe = etnaviv_pdev_probe, - .remove = etnaviv_pdev_remove, + .remove_new = etnaviv_pdev_remove, .driver = { .name = "etnaviv", }, diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c index 2416c526f9b067..3d0f8d182506e4 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c @@ -535,7 +535,7 @@ int etnaviv_ioctl_gem_submit(struct drm_device *dev, void *data, ret = drm_sched_job_init(&submit->sched_job, &ctx->sched_entity[args->pipe], - submit->ctx); + 1, submit->ctx); if (ret) goto err_submit_put; diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index 9276756e1397d3..9b8445d2a128ff 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -1904,11 +1904,10 @@ static int etnaviv_gpu_platform_probe(struct platform_device *pdev) return 0; } -static int etnaviv_gpu_platform_remove(struct platform_device *pdev) +static void etnaviv_gpu_platform_remove(struct platform_device *pdev) { component_del(&pdev->dev, &gpu_ops); pm_runtime_disable(&pdev->dev); - return 0; } static int etnaviv_gpu_rpm_suspend(struct device *dev) @@ -1917,7 +1916,7 @@ static int etnaviv_gpu_rpm_suspend(struct device *dev) u32 idle, mask; /* If there are any jobs in the HW queue, we're not idle */ - if (atomic_read(&gpu->sched.hw_rq_count)) + if (atomic_read(&gpu->sched.credit_count)) return -EBUSY; /* Check whether the hardware (except FE and MC) is idle */ @@ -1970,6 +1969,6 @@ struct platform_driver etnaviv_gpu_driver = { .of_match_table = etnaviv_gpu_match, }, .probe = etnaviv_gpu_platform_probe, - .remove = etnaviv_gpu_platform_remove, + .remove_new = etnaviv_gpu_platform_remove, .id_table = gpu_ids, }; diff --git a/drivers/gpu/drm/etnaviv/etnaviv_sched.c b/drivers/gpu/drm/etnaviv/etnaviv_sched.c index 9b79f218e21afc..c4b04b0dee16aa 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_sched.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_sched.c @@ -134,7 +134,7 @@ int etnaviv_sched_init(struct etnaviv_gpu *gpu) { int ret; - ret = drm_sched_init(&gpu->sched, &etnaviv_sched_ops, + ret = drm_sched_init(&gpu->sched, &etnaviv_sched_ops, NULL, DRM_SCHED_PRIORITY_COUNT, etnaviv_hw_jobs_limit, etnaviv_job_hang_limit, msecs_to_jiffies(500), NULL, NULL, diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index 4d986077738b9b..0ef7bc8848b079 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -319,9 +319,9 @@ static void decon_win_set_bldmod(struct decon_context *ctx, unsigned int win, static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win, struct drm_framebuffer *fb) { - struct exynos_drm_plane plane = ctx->planes[win]; + struct exynos_drm_plane *plane = &ctx->planes[win]; struct exynos_drm_plane_state *state = - to_exynos_plane_state(plane.base.state); + to_exynos_plane_state(plane->base.state); unsigned int alpha = state->base.alpha; unsigned int pixel_alpha; unsigned long val; @@ -862,18 +862,16 @@ err_disable_pm_runtime: return ret; } -static int exynos5433_decon_remove(struct platform_device *pdev) +static void exynos5433_decon_remove(struct platform_device *pdev) { pm_runtime_disable(&pdev->dev); component_del(&pdev->dev, &decon_component_ops); - - return 0; } struct platform_driver exynos5433_decon_driver = { .probe = exynos5433_decon_probe, - .remove = exynos5433_decon_remove, + .remove_new = exynos5433_decon_remove, .driver = { .name = "exynos5433-decon", .pm = pm_ptr(&exynos5433_decon_pm_ops), diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index 0156a5e9443594..0d185c0564b911 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -765,7 +765,7 @@ err_iounmap: return ret; } -static int decon_remove(struct platform_device *pdev) +static void decon_remove(struct platform_device *pdev) { struct decon_context *ctx = dev_get_drvdata(&pdev->dev); @@ -774,8 +774,6 @@ static int decon_remove(struct platform_device *pdev) iounmap(ctx->regs); component_del(&pdev->dev, &decon_component_ops); - - return 0; } static int exynos7_decon_suspend(struct device *dev) @@ -840,7 +838,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(exynos7_decon_pm_ops, exynos7_decon_suspend, struct platform_driver decon_driver = { .probe = decon_probe, - .remove = decon_remove, + .remove_new = decon_remove, .driver = { .name = "exynos-decon", .pm = pm_ptr(&exynos7_decon_pm_ops), diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c index 3404ec1367fb92..ca31bad6c5760d 100644 --- a/drivers/gpu/drm/exynos/exynos_dp.c +++ b/drivers/gpu/drm/exynos/exynos_dp.c @@ -250,14 +250,12 @@ out: return component_add(&pdev->dev, &exynos_dp_ops); } -static int exynos_dp_remove(struct platform_device *pdev) +static void exynos_dp_remove(struct platform_device *pdev) { struct exynos_dp_device *dp = platform_get_drvdata(pdev); component_del(&pdev->dev, &exynos_dp_ops); analogix_dp_remove(dp->adp); - - return 0; } static int exynos_dp_suspend(struct device *dev) @@ -285,7 +283,7 @@ MODULE_DEVICE_TABLE(of, exynos_dp_match); struct platform_driver dp_driver = { .probe = exynos_dp_probe, - .remove = exynos_dp_remove, + .remove_new = exynos_dp_remove, .driver = { .name = "exynos-dp", .owner = THIS_MODULE, diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c index 378e5381978fa9..0dc36df6ada34c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c @@ -101,7 +101,7 @@ static int exynos_dpi_create_connector(struct drm_encoder *encoder) ret = drm_connector_init(encoder->dev, connector, &exynos_dpi_connector_funcs, - DRM_MODE_CONNECTOR_VGA); + DRM_MODE_CONNECTOR_DPI); if (ret) { DRM_DEV_ERROR(ctx->dev, "failed to initialize connector with drm\n"); diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 8399256cb5c9d7..7c59e1164a4836 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -300,6 +300,7 @@ err_mode_config_cleanup: drm_mode_config_cleanup(drm); exynos_drm_cleanup_dma(drm); kfree(private); + dev_set_drvdata(dev, NULL); err_free_drm: drm_dev_put(drm); @@ -313,6 +314,7 @@ static void exynos_drm_unbind(struct device *dev) drm_dev_unregister(drm); drm_kms_helper_poll_fini(drm); + drm_atomic_helper_shutdown(drm); component_unbind_all(drm->dev, drm); drm_mode_config_cleanup(drm); @@ -344,15 +346,23 @@ static int exynos_drm_platform_probe(struct platform_device *pdev) match); } -static int exynos_drm_platform_remove(struct platform_device *pdev) +static void exynos_drm_platform_remove(struct platform_device *pdev) { component_master_del(&pdev->dev, &exynos_drm_ops); - return 0; +} + +static void exynos_drm_platform_shutdown(struct platform_device *pdev) +{ + struct drm_device *drm = platform_get_drvdata(pdev); + + if (drm) + drm_atomic_helper_shutdown(drm); } static struct platform_driver exynos_drm_platform_driver = { .probe = exynos_drm_platform_probe, - .remove = exynos_drm_platform_remove, + .remove_new = exynos_drm_platform_remove, + .shutdown = exynos_drm_platform_shutdown, .driver = { .name = "exynos-drm", .pm = &exynos_drm_pm_ops, diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimc.c b/drivers/gpu/drm/exynos/exynos_drm_fimc.c index 8de2714599fc54..e81a576de3983a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c @@ -1367,7 +1367,7 @@ err_pm_dis: return ret; } -static int fimc_remove(struct platform_device *pdev) +static void fimc_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct fimc_context *ctx = get_fimc_context(dev); @@ -1377,8 +1377,6 @@ static int fimc_remove(struct platform_device *pdev) pm_runtime_disable(dev); fimc_put_clocks(ctx); - - return 0; } static int fimc_runtime_suspend(struct device *dev) @@ -1410,7 +1408,7 @@ MODULE_DEVICE_TABLE(of, fimc_of_match); struct platform_driver fimc_driver = { .probe = fimc_probe, - .remove = fimc_remove, + .remove_new = fimc_remove, .driver = { .of_match_table = fimc_of_match, .name = "exynos-drm-fimc", diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 8dde7b1e9b35d9..f2145227a1e0ce 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -480,7 +480,7 @@ static void fimd_commit(struct exynos_drm_crtc *crtc) struct fimd_context *ctx = crtc->ctx; struct drm_display_mode *mode = &crtc->base.state->adjusted_mode; const struct fimd_driver_data *driver_data = ctx->driver_data; - void *timing_base = ctx->regs + driver_data->timing_base; + void __iomem *timing_base = ctx->regs + driver_data->timing_base; u32 val; if (ctx->suspended) @@ -661,9 +661,9 @@ static void fimd_win_set_bldmod(struct fimd_context *ctx, unsigned int win, static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win, struct drm_framebuffer *fb, int width) { - struct exynos_drm_plane plane = ctx->planes[win]; + struct exynos_drm_plane *plane = &ctx->planes[win]; struct exynos_drm_plane_state *state = - to_exynos_plane_state(plane.base.state); + to_exynos_plane_state(plane->base.state); uint32_t pixel_format = fb->format->format; unsigned int alpha = state->base.alpha; u32 val = WINCONx_ENWIN; @@ -1277,13 +1277,11 @@ err_disable_pm_runtime: return ret; } -static int fimd_remove(struct platform_device *pdev) +static void fimd_remove(struct platform_device *pdev) { pm_runtime_disable(&pdev->dev); component_del(&pdev->dev, &fimd_component_ops); - - return 0; } static int exynos_fimd_suspend(struct device *dev) @@ -1325,7 +1323,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(exynos_fimd_pm_ops, exynos_fimd_suspend, struct platform_driver fimd_driver = { .probe = fimd_probe, - .remove = fimd_remove, + .remove_new = fimd_remove, .driver = { .name = "exynos4-fb", .owner = THIS_MODULE, diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 414e585ec7dd0b..f3138423612e61 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -1530,7 +1530,7 @@ err_destroy_slab: return ret; } -static int g2d_remove(struct platform_device *pdev) +static void g2d_remove(struct platform_device *pdev) { struct g2d_data *g2d = platform_get_drvdata(pdev); @@ -1545,8 +1545,6 @@ static int g2d_remove(struct platform_device *pdev) g2d_fini_cmdlist(g2d); destroy_workqueue(g2d->g2d_workq); kmem_cache_destroy(g2d->runqueue_slab); - - return 0; } static int g2d_suspend(struct device *dev) @@ -1609,7 +1607,7 @@ MODULE_DEVICE_TABLE(of, exynos_g2d_match); struct platform_driver g2d_driver = { .probe = g2d_probe, - .remove = g2d_remove, + .remove_new = g2d_remove, .driver = { .name = "exynos-drm-g2d", .owner = THIS_MODULE, diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c index 34cdabc30b4f5e..180507a477009d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c @@ -11,9 +11,10 @@ #include #include #include -#include +#include #include #include +#include #include #include @@ -103,7 +104,7 @@ struct gsc_context { unsigned int num_formats; void __iomem *regs; - const char **clk_names; + const char *const *clk_names; struct clk *clocks[GSC_MAX_CLOCKS]; int num_clocks; struct gsc_scaler sc; @@ -1217,7 +1218,7 @@ static const unsigned int gsc_tiled_formats[] = { static int gsc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct gsc_driverdata *driver_data; + const struct gsc_driverdata *driver_data; struct exynos_drm_ipp_formats *formats; struct gsc_context *ctx; int num_formats, ret, i, j; @@ -1226,7 +1227,7 @@ static int gsc_probe(struct platform_device *pdev) if (!ctx) return -ENOMEM; - driver_data = (struct gsc_driverdata *)of_device_get_match_data(dev); + driver_data = device_get_match_data(dev); ctx->dev = dev; ctx->num_clocks = driver_data->num_clocks; ctx->clk_names = driver_data->clk_names; @@ -1308,15 +1309,13 @@ err_pm_dis: return ret; } -static int gsc_remove(struct platform_device *pdev) +static void gsc_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; component_del(dev, &gsc_component_ops); pm_runtime_dont_use_autosuspend(dev); pm_runtime_disable(dev); - - return 0; } static int __maybe_unused gsc_runtime_suspend(struct device *dev) @@ -1342,7 +1341,7 @@ static int __maybe_unused gsc_runtime_resume(struct device *dev) for (i = 0; i < ctx->num_clocks; i++) { ret = clk_prepare_enable(ctx->clocks[i]); if (ret) { - while (--i > 0) + while (--i >= 0) clk_disable_unprepare(ctx->clocks[i]); return ret; } @@ -1421,7 +1420,7 @@ MODULE_DEVICE_TABLE(of, exynos_drm_gsc_of_match); struct platform_driver gsc_driver = { .probe = gsc_probe, - .remove = gsc_remove, + .remove_new = gsc_remove, .driver = { .name = "exynos-drm-gsc", .owner = THIS_MODULE, diff --git a/drivers/gpu/drm/exynos/exynos_drm_mic.c b/drivers/gpu/drm/exynos/exynos_drm_mic.c index 17bab5b1663ffa..e2920960180fd3 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_mic.c +++ b/drivers/gpu/drm/exynos/exynos_drm_mic.c @@ -442,7 +442,7 @@ err: return ret; } -static int exynos_mic_remove(struct platform_device *pdev) +static void exynos_mic_remove(struct platform_device *pdev) { struct exynos_mic *mic = platform_get_drvdata(pdev); @@ -450,8 +450,6 @@ static int exynos_mic_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); drm_bridge_remove(&mic->bridge); - - return 0; } static const struct of_device_id exynos_mic_of_match[] = { @@ -462,7 +460,7 @@ MODULE_DEVICE_TABLE(of, exynos_mic_of_match); struct platform_driver mic_driver = { .probe = exynos_mic_probe, - .remove = exynos_mic_remove, + .remove_new = exynos_mic_remove, .driver = { .name = "exynos-mic", .pm = pm_ptr(&exynos_mic_pm_ops), diff --git a/drivers/gpu/drm/exynos/exynos_drm_rotator.c b/drivers/gpu/drm/exynos/exynos_drm_rotator.c index ffb327c5139ece..5f7516655b08f4 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_rotator.c +++ b/drivers/gpu/drm/exynos/exynos_drm_rotator.c @@ -329,15 +329,13 @@ err_component: return ret; } -static int rotator_remove(struct platform_device *pdev) +static void rotator_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; component_del(dev, &rotator_component_ops); pm_runtime_dont_use_autosuspend(dev); pm_runtime_disable(dev); - - return 0; } static int rotator_runtime_suspend(struct device *dev) @@ -453,7 +451,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(rotator_pm_ops, rotator_runtime_suspend, struct platform_driver rotator_driver = { .probe = rotator_probe, - .remove = rotator_remove, + .remove_new = rotator_remove, .driver = { .name = "exynos-rotator", .owner = THIS_MODULE, diff --git a/drivers/gpu/drm/exynos/exynos_drm_scaler.c b/drivers/gpu/drm/exynos/exynos_drm_scaler.c index f2b8b09a6b4eca..392f721f13ab79 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_scaler.c +++ b/drivers/gpu/drm/exynos/exynos_drm_scaler.c @@ -539,15 +539,13 @@ err_ippdrv_register: return ret; } -static int scaler_remove(struct platform_device *pdev) +static void scaler_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; component_del(dev, &scaler_component_ops); pm_runtime_dont_use_autosuspend(dev); pm_runtime_disable(dev); - - return 0; } static int clk_disable_unprepare_wrapper(struct clk *clk) @@ -721,7 +719,7 @@ MODULE_DEVICE_TABLE(of, exynos_scaler_match); struct platform_driver scaler_driver = { .probe = scaler_probe, - .remove = scaler_remove, + .remove_new = scaler_remove, .driver = { .name = "exynos-scaler", .owner = THIS_MODULE, diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index f5e1adfcaa514e..00382f28748ac0 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -462,7 +462,7 @@ static int vidi_probe(struct platform_device *pdev) return component_add(dev, &vidi_component_ops); } -static int vidi_remove(struct platform_device *pdev) +static void vidi_remove(struct platform_device *pdev) { struct vidi_context *ctx = platform_get_drvdata(pdev); @@ -472,13 +472,11 @@ static int vidi_remove(struct platform_device *pdev) } component_del(&pdev->dev, &vidi_component_ops); - - return 0; } struct platform_driver vidi_driver = { .probe = vidi_probe, - .remove = vidi_remove, + .remove_new = vidi_remove, .driver = { .name = "exynos-drm-vidi", .owner = THIS_MODULE, diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index dd9903eab563ee..43bed6cbaaea07 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -2069,7 +2069,7 @@ err_ddc: return ret; } -static int hdmi_remove(struct platform_device *pdev) +static void hdmi_remove(struct platform_device *pdev) { struct hdmi_context *hdata = platform_get_drvdata(pdev); @@ -2092,8 +2092,6 @@ static int hdmi_remove(struct platform_device *pdev) put_device(&hdata->ddc_adpt->dev); mutex_destroy(&hdata->mutex); - - return 0; } static int __maybe_unused exynos_hdmi_suspend(struct device *dev) @@ -2125,7 +2123,7 @@ static const struct dev_pm_ops exynos_hdmi_pm_ops = { struct platform_driver hdmi_driver = { .probe = hdmi_probe, - .remove = hdmi_remove, + .remove_new = hdmi_remove, .driver = { .name = "exynos-hdmi", .owner = THIS_MODULE, diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index b302392ff0d7fb..6822333fd0e654 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -1258,13 +1258,11 @@ static int mixer_probe(struct platform_device *pdev) return ret; } -static int mixer_remove(struct platform_device *pdev) +static void mixer_remove(struct platform_device *pdev) { pm_runtime_disable(&pdev->dev); component_del(&pdev->dev, &mixer_component_ops); - - return 0; } static int __maybe_unused exynos_mixer_suspend(struct device *dev) @@ -1338,5 +1336,5 @@ struct platform_driver mixer_driver = { .of_match_table = mixer_match_types, }, .probe = mixer_probe, - .remove = mixer_remove, + .remove_new = mixer_remove, }; diff --git a/drivers/gpu/drm/gma500/cdv_intel_dp.c b/drivers/gpu/drm/gma500/cdv_intel_dp.c index 8992a95076f29e..dd1eb7e9877d46 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_dp.c +++ b/drivers/gpu/drm/gma500/cdv_intel_dp.c @@ -855,7 +855,6 @@ cdv_intel_dp_i2c_init(struct gma_connector *connector, memset(&intel_dp->adapter, '\0', sizeof (intel_dp->adapter)); intel_dp->adapter.owner = THIS_MODULE; - intel_dp->adapter.class = I2C_CLASS_DDC; strncpy (intel_dp->adapter.name, name, sizeof(intel_dp->adapter.name) - 1); intel_dp->adapter.name[sizeof(intel_dp->adapter.name) - 1] = '\0'; intel_dp->adapter.algo_data = &intel_dp->algo; diff --git a/drivers/gpu/drm/gma500/intel_gmbus.c b/drivers/gpu/drm/gma500/intel_gmbus.c index 09cedabf4776df..aa45509859f21a 100644 --- a/drivers/gpu/drm/gma500/intel_gmbus.c +++ b/drivers/gpu/drm/gma500/intel_gmbus.c @@ -411,7 +411,6 @@ int gma_intel_setup_gmbus(struct drm_device *dev) struct intel_gmbus *bus = &dev_priv->gmbus[i]; bus->adapter.owner = THIS_MODULE; - bus->adapter.class = I2C_CLASS_DDC; snprintf(bus->adapter.name, sizeof(bus->adapter.name), "gma500 gmbus %s", diff --git a/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c b/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c index fc9a34ed58bd13..6daa6669ed2374 100644 --- a/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c +++ b/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c @@ -168,7 +168,6 @@ static struct i2c_adapter oaktrail_hdmi_i2c_adapter = { .name = "oaktrail_hdmi_i2c", .nr = 3, .owner = THIS_MODULE, - .class = I2C_CLASS_DDC, .algo = &oaktrail_hdmi_i2c_algorithm, }; diff --git a/drivers/gpu/drm/gma500/psb_intel_sdvo.c b/drivers/gpu/drm/gma500/psb_intel_sdvo.c index d6fd5d72621609..e4f914decebaec 100644 --- a/drivers/gpu/drm/gma500/psb_intel_sdvo.c +++ b/drivers/gpu/drm/gma500/psb_intel_sdvo.c @@ -2426,7 +2426,6 @@ psb_intel_sdvo_init_ddc_proxy(struct psb_intel_sdvo *sdvo, struct drm_device *dev) { sdvo->ddc.owner = THIS_MODULE; - sdvo->ddc.class = I2C_CLASS_DDC; snprintf(sdvo->ddc.name, I2C_NAME_SIZE, "SDVO DDC proxy"); sdvo->ddc.dev.parent = dev->dev; sdvo->ddc.algo_data = sdvo; diff --git a/drivers/gpu/drm/gud/gud_pipe.c b/drivers/gpu/drm/gud/gud_pipe.c index a02f75be81f03e..e163649816d502 100644 --- a/drivers/gpu/drm/gud/gud_pipe.c +++ b/drivers/gpu/drm/gud/gud_pipe.c @@ -51,7 +51,8 @@ static bool gud_is_big_endian(void) static size_t gud_xrgb8888_to_r124(u8 *dst, const struct drm_format_info *format, void *src, struct drm_framebuffer *fb, - struct drm_rect *rect) + struct drm_rect *rect, + struct drm_format_conv_state *fmtcnv_state) { unsigned int block_width = drm_format_info_block_width(format, 0); unsigned int bits_per_pixel = 8 / block_width; @@ -75,7 +76,7 @@ static size_t gud_xrgb8888_to_r124(u8 *dst, const struct drm_format_info *format iosys_map_set_vaddr(&dst_map, buf); iosys_map_set_vaddr(&vmap, src); - drm_fb_xrgb8888_to_gray8(&dst_map, NULL, &vmap, fb, rect); + drm_fb_xrgb8888_to_gray8(&dst_map, NULL, &vmap, fb, rect, fmtcnv_state); pix8 = buf; for (y = 0; y < height; y++) { @@ -152,7 +153,8 @@ 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 gud_set_buffer_req *req, + struct drm_format_conv_state *fmtcnv_state) { u8 compression = gdrm->compression; struct iosys_map dst; @@ -178,23 +180,23 @@ retry: */ if (format != fb->format) { if (format->format == GUD_DRM_FORMAT_R1) { - len = gud_xrgb8888_to_r124(buf, format, vaddr, fb, rect); + len = gud_xrgb8888_to_r124(buf, format, vaddr, fb, rect, fmtcnv_state); if (!len) return -ENOMEM; } else if (format->format == DRM_FORMAT_R8) { - drm_fb_xrgb8888_to_gray8(&dst, NULL, src, fb, rect); + drm_fb_xrgb8888_to_gray8(&dst, NULL, src, fb, rect, fmtcnv_state); } else if (format->format == DRM_FORMAT_RGB332) { - drm_fb_xrgb8888_to_rgb332(&dst, NULL, src, fb, rect); + drm_fb_xrgb8888_to_rgb332(&dst, NULL, src, fb, rect, fmtcnv_state); } else if (format->format == DRM_FORMAT_RGB565) { - drm_fb_xrgb8888_to_rgb565(&dst, NULL, src, fb, rect, + drm_fb_xrgb8888_to_rgb565(&dst, NULL, src, fb, rect, fmtcnv_state, gud_is_big_endian()); } else if (format->format == DRM_FORMAT_RGB888) { - drm_fb_xrgb8888_to_rgb888(&dst, NULL, src, fb, rect); + drm_fb_xrgb8888_to_rgb888(&dst, NULL, src, fb, rect, fmtcnv_state); } 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, src, fb, rect, cached_reads); + drm_fb_swab(&dst, NULL, src, fb, rect, cached_reads, fmtcnv_state); } else if (compression && cached_reads && pitch == fb->pitches[0]) { /* can compress directly from the framebuffer */ buf = vaddr + rect->y1 * pitch; @@ -266,7 +268,8 @@ 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) + const struct drm_format_info *format, struct drm_rect *rect, + struct drm_format_conv_state *fmtcnv_state) { struct gud_set_buffer_req req; size_t len, trlen; @@ -274,7 +277,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, src, cached_reads, format, rect, &req); + ret = gud_prep_flush(gdrm, fb, src, cached_reads, format, rect, &req, fmtcnv_state); if (ret) return ret; @@ -318,6 +321,7 @@ 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) { + struct drm_format_conv_state fmtcnv_state = DRM_FORMAT_CONV_STATE_INIT; const struct drm_format_info *format; unsigned int i, lines; size_t pitch; @@ -340,7 +344,7 @@ static void gud_flush_damage(struct gud_device *gdrm, struct drm_framebuffer *fb 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); + ret = gud_flush_rect(gdrm, fb, src, cached_reads, format, &rect, &fmtcnv_state); if (ret) { if (ret != -ENODEV && ret != -ECONNRESET && ret != -ESHUTDOWN && ret != -EPROTO) @@ -350,6 +354,8 @@ static void gud_flush_damage(struct gud_device *gdrm, struct drm_framebuffer *fb break; } } + + drm_format_conv_state_release(&fmtcnv_state); } void gud_flush_work(struct work_struct *work) diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_i2c.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_i2c.c index 410bd019bb3572..e6e48651c15c63 100644 --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_i2c.c +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_i2c.c @@ -81,7 +81,6 @@ int hibmc_ddc_create(struct drm_device *drm_dev, struct hibmc_connector *connector) { connector->adapter.owner = THIS_MODULE; - connector->adapter.class = I2C_CLASS_DDC; snprintf(connector->adapter.name, I2C_NAME_SIZE, "HIS i2c bit bus"); connector->adapter.dev.parent = drm_dev->dev; i2c_set_adapdata(&connector->adapter, connector); diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_drv.c b/drivers/gpu/drm/hyperv/hyperv_drm_drv.c index d511d17c5bdfcb..cff85086f2d665 100644 --- a/drivers/gpu/drm/hyperv/hyperv_drm_drv.c +++ b/drivers/gpu/drm/hyperv/hyperv_drm_drv.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include @@ -73,11 +72,6 @@ static int hyperv_setup_vram(struct hyperv_drm_device *hv, struct drm_device *dev = &hv->dev; int ret; - if (IS_ENABLED(CONFIG_SYSFB)) - drm_aperture_remove_conflicting_framebuffers(screen_info.lfb_base, - screen_info.lfb_size, - &hyperv_driver); - hv->fb_size = (unsigned long)hv->mmio_megabytes * 1024 * 1024; ret = vmbus_allocate_mmio(&hv->mem, hdev, 0, -1, hv->fb_size, 0x100000, @@ -130,6 +124,8 @@ static int hyperv_vmbus_probe(struct hv_device *hdev, goto err_hv_set_drv_data; } + drm_aperture_remove_framebuffers(&hyperv_driver); + ret = hyperv_setup_vram(hv, hdev); if (ret) goto err_vmbus_close; diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig index ce397a8797f7b6..b5d6e3352071f5 100644 --- a/drivers/gpu/drm/i915/Kconfig +++ b/drivers/gpu/drm/i915/Kconfig @@ -94,7 +94,7 @@ config DRM_I915_CAPTURE_ERROR This option enables capturing the GPU state when a hang is detected. This information is vital for triaging hangs and assists in debugging. Please report any hang for triaging according to: - https://gitlab.freedesktop.org/drm/intel/-/wikis/How-to-file-i915-bugs + https://drm.pages.freedesktop.org/intel-docs/how-to-file-i915-bugs.html If in doubt, say "Y". diff --git a/drivers/gpu/drm/i915/Kconfig.debug b/drivers/gpu/drm/i915/Kconfig.debug index 2d21930d550158..5b7162076850c6 100644 --- a/drivers/gpu/drm/i915/Kconfig.debug +++ b/drivers/gpu/drm/i915/Kconfig.debug @@ -24,7 +24,9 @@ config DRM_I915_DEBUG select DEBUG_FS select PREEMPT_COUNT select I2C_CHARDEV + select REF_TRACKER select STACKDEPOT + select STACKTRACE select DRM_DP_AUX_CHARDEV select X86_MSR # used by igt/pm_rpm select DRM_VGEM # used by igt/prime_vgem (dmabuf interop checks) @@ -38,6 +40,7 @@ config DRM_I915_DEBUG select DRM_I915_DEBUG_GEM_ONCE select DRM_I915_DEBUG_MMIO select DRM_I915_DEBUG_RUNTIME_PM + select DRM_I915_DEBUG_WAKEREF select DRM_I915_SW_FENCE_DEBUG_OBJECTS select DRM_I915_SELFTEST default n @@ -231,7 +234,9 @@ config DRM_I915_DEBUG_RUNTIME_PM bool "Enable extra state checking for runtime PM" depends on DRM_I915 default n + select REF_TRACKER select STACKDEPOT + select STACKTRACE help Choose this option to turn on extra state checking for the runtime PM functionality. This may introduce overhead during @@ -240,3 +245,16 @@ config DRM_I915_DEBUG_RUNTIME_PM Recommended for driver developers only. If in doubt, say "N" + +config DRM_I915_DEBUG_WAKEREF + bool "Enable extra tracking for wakerefs" + depends on DRM_I915 + select REF_TRACKER + select STACKDEPOT + select STACKTRACE + help + Choose this option to turn on extra state checking and usage + tracking for the wakerefPM functionality. This may introduce + overhead during driver runtime. + + If in doubt, say "N" diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 88b2bb005014af..c13f14edb50889 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -17,7 +17,6 @@ subdir-ccflags-y += $(call cc-option, -Wunused-const-variable) subdir-ccflags-y += $(call cc-option, -Wpacked-not-aligned) subdir-ccflags-y += $(call cc-option, -Wformat-overflow) subdir-ccflags-y += $(call cc-option, -Wformat-truncation) -subdir-ccflags-y += $(call cc-option, -Wstringop-overflow) subdir-ccflags-y += $(call cc-option, -Wstringop-truncation) # The following turn off the warnings enabled by -Wextra ifeq ($(findstring 2, $(KBUILD_EXTRA_WARN)),) @@ -47,33 +46,34 @@ subdir-ccflags-y += -I$(srctree)/$(src) # Please keep these build lists sorted! # core driver code -i915-y += i915_driver.o \ - i915_drm_client.o \ - i915_config.o \ - i915_getparam.o \ - i915_ioctl.o \ - i915_irq.o \ - i915_mitigations.o \ - i915_module.o \ - i915_params.o \ - i915_pci.o \ - i915_scatterlist.o \ - i915_suspend.o \ - i915_switcheroo.o \ - i915_sysfs.o \ - i915_utils.o \ - intel_clock_gating.o \ - intel_device_info.o \ - intel_memory_region.o \ - intel_pcode.o \ - intel_region_ttm.o \ - intel_runtime_pm.o \ - intel_sbi.o \ - intel_step.o \ - intel_uncore.o \ - intel_wakeref.o \ - vlv_sideband.o \ - vlv_suspend.o +i915-y += \ + i915_config.o \ + i915_driver.o \ + i915_drm_client.o \ + i915_getparam.o \ + i915_ioctl.o \ + i915_irq.o \ + i915_mitigations.o \ + i915_module.o \ + i915_params.o \ + i915_pci.o \ + i915_scatterlist.o \ + i915_suspend.o \ + i915_switcheroo.o \ + i915_sysfs.o \ + i915_utils.o \ + intel_clock_gating.o \ + intel_device_info.o \ + intel_memory_region.o \ + intel_pcode.o \ + intel_region_ttm.o \ + intel_runtime_pm.o \ + intel_sbi.o \ + intel_step.o \ + intel_uncore.o \ + intel_wakeref.o \ + vlv_sideband.o \ + vlv_suspend.o # core peripheral code i915-y += \ @@ -90,13 +90,13 @@ i915-y += \ i915_syncmap.o \ i915_user_extensions.o -i915-$(CONFIG_COMPAT) += i915_ioc32.o +i915-$(CONFIG_COMPAT) += \ + i915_ioc32.o i915-$(CONFIG_DEBUG_FS) += \ i915_debugfs.o \ - i915_debugfs_params.o \ - display/intel_display_debugfs.o \ - display/intel_pipe_crc.o -i915-$(CONFIG_PERF_EVENTS) += i915_pmu.o + i915_debugfs_params.o +i915-$(CONFIG_PERF_EVENTS) += \ + i915_pmu.o # "Graphics Technology" (aka we talk to the gpu) gt-y += \ @@ -153,7 +153,8 @@ gt-y += \ gt/sysfs_engines.o # x86 intel-gtt module support -gt-$(CONFIG_X86) += gt/intel_ggtt_gmch.o +gt-$(CONFIG_X86) += \ + gt/intel_ggtt_gmch.o # autogenerated null render state gt-y += \ gt/gen6_renderstate.o \ @@ -172,9 +173,9 @@ gem-y += \ gem/i915_gem_domain.o \ gem/i915_gem_execbuffer.o \ gem/i915_gem_internal.o \ - gem/i915_gem_object.o \ gem/i915_gem_lmem.o \ gem/i915_gem_mman.o \ + gem/i915_gem_object.o \ gem/i915_gem_pages.o \ gem/i915_gem_phys.o \ gem/i915_gem_pm.o \ @@ -191,57 +192,61 @@ gem-y += \ gem/i915_gem_wait.o \ gem/i915_gemfs.o i915-y += \ - $(gem-y) \ - i915_active.o \ - i915_cmd_parser.o \ - i915_deps.o \ - i915_gem_evict.o \ - i915_gem_gtt.o \ - i915_gem_ww.o \ - i915_gem.o \ - i915_query.o \ - i915_request.o \ - i915_scheduler.o \ - i915_trace_points.o \ - i915_ttm_buddy_manager.o \ - i915_vma.o \ - i915_vma_resource.o + $(gem-y) \ + i915_active.o \ + i915_cmd_parser.o \ + i915_deps.o \ + i915_gem.o \ + i915_gem_evict.o \ + i915_gem_gtt.o \ + i915_gem_ww.o \ + i915_query.o \ + i915_request.o \ + i915_scheduler.o \ + i915_trace_points.o \ + i915_ttm_buddy_manager.o \ + i915_vma.o \ + i915_vma_resource.o # general-purpose microcontroller (GuC) support i915-y += \ - gt/uc/intel_gsc_fw.o \ - gt/uc/intel_gsc_proxy.o \ - gt/uc/intel_gsc_uc.o \ - gt/uc/intel_gsc_uc_debugfs.o \ - gt/uc/intel_gsc_uc_heci_cmd_submit.o \ - gt/uc/intel_guc.o \ - gt/uc/intel_guc_ads.o \ - gt/uc/intel_guc_capture.o \ - gt/uc/intel_guc_ct.o \ - gt/uc/intel_guc_debugfs.o \ - gt/uc/intel_guc_fw.o \ - gt/uc/intel_guc_hwconfig.o \ - gt/uc/intel_guc_log.o \ - gt/uc/intel_guc_log_debugfs.o \ - gt/uc/intel_guc_rc.o \ - gt/uc/intel_guc_slpc.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_uc.o \ - gt/uc/intel_uc_debugfs.o \ - gt/uc/intel_uc_fw.o + gt/uc/intel_gsc_fw.o \ + gt/uc/intel_gsc_proxy.o \ + gt/uc/intel_gsc_uc.o \ + gt/uc/intel_gsc_uc_debugfs.o \ + gt/uc/intel_gsc_uc_heci_cmd_submit.o\ + gt/uc/intel_guc.o \ + gt/uc/intel_guc_ads.o \ + gt/uc/intel_guc_capture.o \ + gt/uc/intel_guc_ct.o \ + gt/uc/intel_guc_debugfs.o \ + gt/uc/intel_guc_fw.o \ + gt/uc/intel_guc_hwconfig.o \ + gt/uc/intel_guc_log.o \ + gt/uc/intel_guc_log_debugfs.o \ + gt/uc/intel_guc_rc.o \ + gt/uc/intel_guc_slpc.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_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 +i915-y += \ + gt/intel_gsc.o # graphics hardware monitoring (HWMON) support -i915-$(CONFIG_HWMON) += i915_hwmon.o +i915-$(CONFIG_HWMON) += \ + i915_hwmon.o # modesetting core code i915-y += \ display/hsw_ips.o \ + display/i9xx_plane.o \ + display/i9xx_wm.o \ display/intel_atomic.o \ display/intel_atomic_plane.o \ display/intel_audio.o \ @@ -257,6 +262,7 @@ i915-y += \ display/intel_display.o \ display/intel_display_driver.o \ display/intel_display_irq.o \ + display/intel_display_params.o \ display/intel_display_power.o \ display/intel_display_power_map.o \ display/intel_display_power_well.o \ @@ -268,9 +274,12 @@ i915-y += \ display/intel_dpll.o \ display/intel_dpll_mgr.o \ display/intel_dpt.o \ + display/intel_dpt_common.o \ display/intel_drrs.o \ display/intel_dsb.o \ + display/intel_dsb_buffer.o \ display/intel_fb.o \ + display/intel_fb_bo.o \ display/intel_fb_pin.o \ display/intel_fbc.o \ display/intel_fdi.o \ @@ -287,8 +296,8 @@ i915-y += \ display/intel_load_detect.o \ display/intel_lpe_audio.o \ display/intel_modeset_lock.o \ - display/intel_modeset_verify.o \ display/intel_modeset_setup.o \ + display/intel_modeset_verify.o \ display/intel_overlay.o \ display/intel_pch_display.o \ display/intel_pch_refclk.o \ @@ -302,8 +311,6 @@ i915-y += \ display/intel_vblank.o \ display/intel_vga.o \ display/intel_wm.o \ - display/i9xx_plane.o \ - display/i9xx_wm.o \ display/skl_scaler.o \ display/skl_universal_plane.o \ display/skl_watermark.o @@ -311,7 +318,12 @@ i915-$(CONFIG_ACPI) += \ display/intel_acpi.o \ display/intel_opregion.o i915-$(CONFIG_DRM_FBDEV_EMULATION) += \ - display/intel_fbdev.o + display/intel_fbdev.o \ + display/intel_fbdev_fb.o +i915-$(CONFIG_DEBUG_FS) += \ + display/intel_display_debugfs.o \ + display/intel_display_debugfs_params.o \ + display/intel_pipe_crc.o # modesetting output/encoder code i915-y += \ @@ -357,13 +369,14 @@ i915-y += \ display/vlv_dsi.o \ display/vlv_dsi_pll.o -i915-y += i915_perf.o +i915-y += \ + i915_perf.o # Protected execution platform (PXP) support. Base support is required for HuC i915-y += \ pxp/intel_pxp.o \ - pxp/intel_pxp_tee.o \ - pxp/intel_pxp_huc.o + pxp/intel_pxp_huc.o \ + pxp/intel_pxp_tee.o i915-$(CONFIG_DRM_I915_PXP) += \ pxp/intel_pxp_cmd.o \ @@ -374,11 +387,11 @@ i915-$(CONFIG_DRM_I915_PXP) += \ pxp/intel_pxp_session.o # Post-mortem debug and GPU hang state capture -i915-$(CONFIG_DRM_I915_CAPTURE_ERROR) += i915_gpu_error.o +i915-$(CONFIG_DRM_I915_CAPTURE_ERROR) += \ + i915_gpu_error.o i915-$(CONFIG_DRM_I915_SELFTEST) += \ gem/selftests/i915_gem_client_blt.o \ gem/selftests/igt_gem_utils.o \ - selftests/intel_scheduler_helpers.o \ selftests/i915_random.o \ selftests/i915_selftest.o \ selftests/igt_atomic.o \ @@ -387,10 +400,12 @@ i915-$(CONFIG_DRM_I915_SELFTEST) += \ selftests/igt_mmap.o \ selftests/igt_reset.o \ selftests/igt_spinner.o \ + selftests/intel_scheduler_helpers.o \ selftests/librapl.o # virtual gpu code -i915-y += i915_vgpu.o +i915-y += \ + i915_vgpu.o i915-$(CONFIG_DRM_I915_GVT) += \ intel_gvt.o \ diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c index e8ee0a08947e8f..dfe0b07a122d15 100644 --- a/drivers/gpu/drm/i915/display/g4x_dp.c +++ b/drivers/gpu/drm/i915/display/g4x_dp.c @@ -432,7 +432,7 @@ intel_dp_link_down(struct intel_encoder *encoder, intel_de_write(dev_priv, intel_dp->output_reg, intel_dp->DP); intel_de_posting_read(dev_priv, intel_dp->output_reg); - intel_dp->DP &= ~(DP_PORT_EN | DP_AUDIO_OUTPUT_ENABLE); + intel_dp->DP &= ~DP_PORT_EN; intel_de_write(dev_priv, intel_dp->output_reg, intel_dp->DP); intel_de_posting_read(dev_priv, intel_dp->output_reg); @@ -475,6 +475,40 @@ intel_dp_link_down(struct intel_encoder *encoder, } } +static void g4x_dp_audio_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_dp *intel_dp = enc_to_intel_dp(encoder); + + if (!crtc_state->has_audio) + return; + + /* Enable audio presence detect */ + intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE; + intel_de_write(i915, intel_dp->output_reg, intel_dp->DP); + + intel_audio_codec_enable(encoder, crtc_state, conn_state); +} + +static void g4x_dp_audio_disable(struct intel_encoder *encoder, + const struct intel_crtc_state *old_crtc_state, + const struct drm_connector_state *old_conn_state) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + + if (!old_crtc_state->has_audio) + return; + + intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); + + /* Disable audio presence detect */ + intel_dp->DP &= ~DP_AUDIO_OUTPUT_ENABLE; + intel_de_write(i915, intel_dp->output_reg, intel_dp->DP); +} + static void intel_disable_dp(struct intel_atomic_state *state, struct intel_encoder *encoder, const struct intel_crtc_state *old_crtc_state, @@ -484,8 +518,6 @@ static void intel_disable_dp(struct intel_atomic_state *state, intel_dp->link_trained = false; - intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); - /* * Make sure the panel is off before trying to change the mode. * But also ensure that we have vdd while we switch off the panel. @@ -631,8 +663,6 @@ static void intel_dp_enable_port(struct intel_dp *intel_dp, * fail when the power sequencer is freshly used for this port. */ intel_dp->DP |= DP_PORT_EN; - if (crtc_state->has_audio) - intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE; intel_de_write(dev_priv, intel_dp->output_reg, intel_dp->DP); intel_de_posting_read(dev_priv, intel_dp->output_reg); @@ -686,8 +716,8 @@ static void g4x_enable_dp(struct intel_atomic_state *state, const struct drm_connector_state *conn_state) { intel_enable_dp(state, encoder, pipe_config, conn_state); - intel_audio_codec_enable(encoder, pipe_config, conn_state); intel_edp_backlight_on(pipe_config, conn_state); + encoder->audio_enable(encoder, pipe_config, conn_state); } static void vlv_enable_dp(struct intel_atomic_state *state, @@ -695,8 +725,8 @@ static void vlv_enable_dp(struct intel_atomic_state *state, const struct intel_crtc_state *pipe_config, const struct drm_connector_state *conn_state) { - intel_audio_codec_enable(encoder, pipe_config, conn_state); intel_edp_backlight_on(pipe_config, conn_state); + encoder->audio_enable(encoder, pipe_config, conn_state); } static void g4x_pre_enable_dp(struct intel_atomic_state *state, @@ -1325,6 +1355,8 @@ bool g4x_dp_init(struct drm_i915_private *dev_priv, intel_encoder->disable = g4x_disable_dp; intel_encoder->post_disable = g4x_post_disable_dp; } + intel_encoder->audio_enable = g4x_dp_audio_enable; + intel_encoder->audio_disable = g4x_dp_audio_disable; if ((IS_IVYBRIDGE(dev_priv) && port == PORT_A) || (HAS_PCH_CPT(dev_priv) && port != PORT_A)) diff --git a/drivers/gpu/drm/i915/display/g4x_hdmi.c b/drivers/gpu/drm/i915/display/g4x_hdmi.c index 45e044b4a88dbf..8096492b3faded 100644 --- a/drivers/gpu/drm/i915/display/g4x_hdmi.c +++ b/drivers/gpu/drm/i915/display/g4x_hdmi.c @@ -228,25 +228,51 @@ static void g4x_hdmi_enable_port(struct intel_encoder *encoder, temp = intel_de_read(dev_priv, intel_hdmi->hdmi_reg); temp |= SDVO_ENABLE; - if (pipe_config->has_audio) - temp |= HDMI_AUDIO_ENABLE; intel_de_write(dev_priv, intel_hdmi->hdmi_reg, temp); intel_de_posting_read(dev_priv, intel_hdmi->hdmi_reg); } +static void g4x_hdmi_audio_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_hdmi *hdmi = enc_to_intel_hdmi(encoder); + + if (!crtc_state->has_audio) + return; + + drm_WARN_ON(&i915->drm, !crtc_state->has_hdmi_sink); + + /* Enable audio presence detect */ + intel_de_rmw(i915, hdmi->hdmi_reg, 0, HDMI_AUDIO_ENABLE); + + intel_audio_codec_enable(encoder, crtc_state, conn_state); +} + +static void g4x_hdmi_audio_disable(struct intel_encoder *encoder, + const struct intel_crtc_state *old_crtc_state, + const struct drm_connector_state *old_conn_state) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + struct intel_hdmi *hdmi = enc_to_intel_hdmi(encoder); + + if (!old_crtc_state->has_audio) + return; + + intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); + + /* Disable audio presence detect */ + intel_de_rmw(i915, hdmi->hdmi_reg, HDMI_AUDIO_ENABLE, 0); +} + static void g4x_enable_hdmi(struct intel_atomic_state *state, struct intel_encoder *encoder, 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); - g4x_hdmi_enable_port(encoder, pipe_config); - - drm_WARN_ON(&dev_priv->drm, pipe_config->has_audio && - !pipe_config->has_hdmi_sink); - intel_audio_codec_enable(encoder, pipe_config, conn_state); } static void ibx_enable_hdmi(struct intel_atomic_state *state, @@ -262,8 +288,6 @@ static void ibx_enable_hdmi(struct intel_atomic_state *state, temp = intel_de_read(dev_priv, intel_hdmi->hdmi_reg); temp |= SDVO_ENABLE; - if (pipe_config->has_audio) - temp |= HDMI_AUDIO_ENABLE; /* * HW workaround, need to write this twice for issue @@ -296,10 +320,6 @@ static void ibx_enable_hdmi(struct intel_atomic_state *state, intel_de_write(dev_priv, intel_hdmi->hdmi_reg, temp); intel_de_posting_read(dev_priv, intel_hdmi->hdmi_reg); } - - drm_WARN_ON(&dev_priv->drm, pipe_config->has_audio && - !pipe_config->has_hdmi_sink); - intel_audio_codec_enable(encoder, pipe_config, conn_state); } static void cpt_enable_hdmi(struct intel_atomic_state *state, @@ -317,8 +337,6 @@ static void cpt_enable_hdmi(struct intel_atomic_state *state, temp = intel_de_read(dev_priv, intel_hdmi->hdmi_reg); temp |= SDVO_ENABLE; - if (pipe_config->has_audio) - temp |= HDMI_AUDIO_ENABLE; /* * WaEnableHDMI8bpcBefore12bpc:snb,ivb @@ -351,10 +369,6 @@ static void cpt_enable_hdmi(struct intel_atomic_state *state, intel_de_rmw(dev_priv, TRANS_CHICKEN1(pipe), TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE, 0); } - - drm_WARN_ON(&dev_priv->drm, pipe_config->has_audio && - !pipe_config->has_hdmi_sink); - intel_audio_codec_enable(encoder, pipe_config, conn_state); } static void vlv_enable_hdmi(struct intel_atomic_state *state, @@ -362,11 +376,6 @@ static void vlv_enable_hdmi(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); - - drm_WARN_ON(&dev_priv->drm, pipe_config->has_audio && - !pipe_config->has_hdmi_sink); - intel_audio_codec_enable(encoder, pipe_config, conn_state); } static void intel_disable_hdmi(struct intel_atomic_state *state, @@ -384,7 +393,7 @@ static void intel_disable_hdmi(struct intel_atomic_state *state, temp = intel_de_read(dev_priv, intel_hdmi->hdmi_reg); - temp &= ~(SDVO_ENABLE | HDMI_AUDIO_ENABLE); + temp &= ~SDVO_ENABLE; intel_de_write(dev_priv, intel_hdmi->hdmi_reg, temp); intel_de_posting_read(dev_priv, intel_hdmi->hdmi_reg); @@ -433,8 +442,6 @@ static void g4x_disable_hdmi(struct intel_atomic_state *state, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state) { - intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); - intel_disable_hdmi(state, encoder, old_crtc_state, old_conn_state); } @@ -443,7 +450,6 @@ static void pch_disable_hdmi(struct intel_atomic_state *state, const struct intel_crtc_state *old_crtc_state, const struct drm_connector_state *old_conn_state) { - intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); } static void pch_post_disable_hdmi(struct intel_atomic_state *state, @@ -750,6 +756,8 @@ void g4x_hdmi_init(struct drm_i915_private *dev_priv, else intel_encoder->enable = g4x_enable_hdmi; } + intel_encoder->audio_enable = g4x_hdmi_audio_enable; + intel_encoder->audio_disable = g4x_hdmi_audio_disable; intel_encoder->shutdown = intel_hdmi_encoder_shutdown; intel_encoder->type = INTEL_OUTPUT_HDMI; diff --git a/drivers/gpu/drm/i915/display/hsw_ips.c b/drivers/gpu/drm/i915/display/hsw_ips.c index 7dc38ac0209277..611a7d6ef80c23 100644 --- a/drivers/gpu/drm/i915/display/hsw_ips.c +++ b/drivers/gpu/drm/i915/display/hsw_ips.c @@ -193,7 +193,7 @@ bool hsw_crtc_state_ips_capable(const struct intel_crtc_state *crtc_state) if (!hsw_crtc_supports_ips(crtc)) return false; - if (!i915->params.enable_ips) + if (!i915->display.params.enable_ips) return false; if (crtc_state->pipe_bpp > 24) @@ -329,7 +329,7 @@ static int hsw_ips_debugfs_status_show(struct seq_file *m, void *unused) wakeref = intel_runtime_pm_get(&i915->runtime_pm); seq_printf(m, "Enabled by kernel parameter: %s\n", - str_yes_no(i915->params.enable_ips)); + str_yes_no(i915->display.params.enable_ips)); if (DISPLAY_VER(i915) >= 8) { seq_puts(m, "Currently: unknown\n"); diff --git a/drivers/gpu/drm/i915/display/i9xx_wm.c b/drivers/gpu/drm/i915/display/i9xx_wm.c index af0c79a4c9a4f5..11ca9572e8b3c5 100644 --- a/drivers/gpu/drm/i915/display/i9xx_wm.c +++ b/drivers/gpu/drm/i915/display/i9xx_wm.c @@ -608,7 +608,7 @@ static bool intel_crtc_active(struct intel_crtc *crtc) * crtc->state->active once we have proper CRTC states wired up * for atomic. */ - return crtc && crtc->active && crtc->base.primary->state->fb && + return crtc->active && crtc->base.primary->state->fb && crtc->config->hw.adjusted_mode.crtc_clock; } @@ -2477,7 +2477,7 @@ static unsigned int ilk_plane_wm_max(const struct drm_i915_private *dev_priv, * FIFO size is only half of the self * refresh FIFO size on ILK/SNB. */ - if (DISPLAY_VER(dev_priv) <= 6) + if (DISPLAY_VER(dev_priv) < 7) fifo_size /= 2; } @@ -2818,7 +2818,7 @@ static int ilk_compute_pipe_wm(struct intel_atomic_state *state, usable_level = dev_priv->display.wm.num_levels - 1; /* ILK/SNB: LP2+ watermarks only w/o sprites */ - if (DISPLAY_VER(dev_priv) <= 6 && pipe_wm->sprites_enabled) + if (DISPLAY_VER(dev_priv) < 7 && pipe_wm->sprites_enabled) usable_level = 1; /* ILK/SNB/IVB: LP1+ watermarks only w/o scaling */ @@ -2961,7 +2961,7 @@ static void ilk_wm_merge(struct drm_i915_private *dev_priv, int last_enabled_level = num_levels - 1; /* ILK/SNB/IVB: LP1+ watermarks only w/ single pipe */ - if ((DISPLAY_VER(dev_priv) <= 6 || IS_IVYBRIDGE(dev_priv)) && + if ((DISPLAY_VER(dev_priv) < 7 || IS_IVYBRIDGE(dev_priv)) && config->num_pipes_active > 1) last_enabled_level = 0; @@ -2993,7 +2993,7 @@ static void ilk_wm_merge(struct drm_i915_private *dev_priv, /* ILK: LP2+ must be disabled when FBC WM is disabled but FBC enabled */ if (DISPLAY_VER(dev_priv) == 5 && HAS_FBC(dev_priv) && - dev_priv->params.enable_fbc && !merged->fbc_wm_enabled) { + dev_priv->display.params.enable_fbc && !merged->fbc_wm_enabled) { for (level = 2; level < num_levels; level++) { struct intel_wm_level *wm = &merged->wm[level]; @@ -3060,7 +3060,7 @@ static void ilk_compute_wm_results(struct drm_i915_private *dev_priv, * Always set WM_LP_SPRITE_EN when spr_val != 0, even if the * level is disabled. Doing otherwise could cause underruns. */ - if (DISPLAY_VER(dev_priv) <= 6 && r->spr_val) { + if (DISPLAY_VER(dev_priv) < 7 && r->spr_val) { drm_WARN_ON(&dev_priv->drm, wm_lp != 1); results->wm_lp_spr[wm_lp - 1] |= WM_LP_SPRITE_ENABLE; } diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index 67143a0f518930..eda4a8b885904d 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -330,7 +330,7 @@ static int afe_clk(struct intel_encoder *encoder, int bpp; if (crtc_state->dsc.compression_enable) - bpp = crtc_state->dsc.compressed_bpp; + bpp = to_bpp_int(crtc_state->dsc.compressed_bpp_x16); else bpp = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format); @@ -860,7 +860,7 @@ gen11_dsi_set_transcoder_timings(struct intel_encoder *encoder, * compressed and non-compressed bpp. */ if (crtc_state->dsc.compression_enable) { - mul = crtc_state->dsc.compressed_bpp; + mul = to_bpp_int(crtc_state->dsc.compressed_bpp_x16); div = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format); } @@ -884,7 +884,7 @@ gen11_dsi_set_transcoder_timings(struct intel_encoder *encoder, int bpp, line_time_us, byte_clk_period_ns; if (crtc_state->dsc.compression_enable) - bpp = crtc_state->dsc.compressed_bpp; + bpp = to_bpp_int(crtc_state->dsc.compressed_bpp_x16); else bpp = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format); @@ -1155,6 +1155,7 @@ static void gen11_dsi_powerup_panel(struct intel_encoder *encoder) } intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_INIT_OTP); + intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_ON); /* ensure all panel commands dispatched before enabling transcoder */ wait_for_cmds_dispatched_to_panel(encoder); @@ -1255,8 +1256,6 @@ static void gen11_dsi_enable(struct intel_atomic_state *state, /* step6d: enable dsi transcoder */ gen11_dsi_enable_transcoder(encoder); - intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_DISPLAY_ON); - /* step7: enable backlight */ intel_backlight_enable(crtc_state, conn_state); intel_dsi_vbt_exec_sequence(intel_dsi, MIPI_SEQ_BACKLIGHT_ON); @@ -1458,8 +1457,8 @@ static void gen11_dsi_get_timings(struct intel_encoder *encoder, struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; - if (pipe_config->dsc.compressed_bpp) { - int div = pipe_config->dsc.compressed_bpp; + if (pipe_config->dsc.compressed_bpp_x16) { + int div = to_bpp_int(pipe_config->dsc.compressed_bpp_x16); int mul = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format); adjusted_mode->crtc_htotal = diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c b/drivers/gpu/drm/i915/display/intel_atomic.c index 5d18145da27900..ec0d5168b50352 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic.c +++ b/drivers/gpu/drm/i915/display/intel_atomic.c @@ -331,9 +331,6 @@ void intel_atomic_state_free(struct drm_atomic_state *_state) drm_atomic_state_default_release(&state->base); kfree(state->global_objs); - - i915_sw_fence_fini(&state->commit_ready); - kfree(state); } diff --git a/drivers/gpu/drm/i915/display/intel_atomic_plane.c b/drivers/gpu/drm/i915/display/intel_atomic_plane.c index b1074350616cc0..06c2455bdd788f 100644 --- a/drivers/gpu/drm/i915/display/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/display/intel_atomic_plane.c @@ -31,7 +31,10 @@ * prepare/check/commit/cleanup steps. */ +#include + #include +#include #include #include @@ -1012,6 +1015,41 @@ int intel_plane_check_src_coordinates(struct intel_plane_state *plane_state) return 0; } +static int add_dma_resv_fences(struct dma_resv *resv, + struct drm_plane_state *new_plane_state) +{ + struct dma_fence *fence = dma_fence_get(new_plane_state->fence); + struct dma_fence *new; + int ret; + + ret = dma_resv_get_singleton(resv, dma_resv_usage_rw(false), &new); + if (ret) + goto error; + + if (new && fence) { + struct dma_fence_chain *chain = dma_fence_chain_alloc(); + + if (!chain) { + ret = -ENOMEM; + goto error; + } + + dma_fence_chain_init(chain, fence, new, 1); + fence = &chain->base; + + } else if (new) { + fence = new; + } + + dma_fence_put(new_plane_state->fence); + new_plane_state->fence = fence; + return 0; + +error: + dma_fence_put(fence); + return ret; +} + /** * intel_prepare_plane_fb - Prepare fb for usage on plane * @_plane: drm plane to prepare for @@ -1035,7 +1073,7 @@ intel_prepare_plane_fb(struct drm_plane *_plane, struct intel_atomic_state *state = to_intel_atomic_state(new_plane_state->uapi.state); struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - const struct intel_plane_state *old_plane_state = + struct intel_plane_state *old_plane_state = intel_atomic_get_old_plane_state(state, plane); struct drm_i915_gem_object *obj = intel_fb_obj(new_plane_state->hw.fb); struct drm_i915_gem_object *old_obj = intel_fb_obj(old_plane_state->hw.fb); @@ -1058,55 +1096,28 @@ intel_prepare_plane_fb(struct drm_plane *_plane, * can safely continue. */ if (new_crtc_state && intel_crtc_needs_modeset(new_crtc_state)) { - ret = i915_sw_fence_await_reservation(&state->commit_ready, - old_obj->base.resv, - false, 0, - GFP_KERNEL); + ret = add_dma_resv_fences(intel_bo_to_drm_bo(old_obj)->resv, + &new_plane_state->uapi); if (ret < 0) return ret; } } - if (new_plane_state->uapi.fence) { /* explicit fencing */ - i915_gem_fence_wait_priority(new_plane_state->uapi.fence, - &attr); - ret = i915_sw_fence_await_dma_fence(&state->commit_ready, - new_plane_state->uapi.fence, - i915_fence_timeout(dev_priv), - GFP_KERNEL); - if (ret < 0) - return ret; - } - if (!obj) return 0; - ret = intel_plane_pin_fb(new_plane_state); if (ret) return ret; - i915_gem_object_wait_priority(obj, 0, &attr); + ret = drm_gem_plane_helper_prepare_fb(&plane->base, &new_plane_state->uapi); + if (ret < 0) + goto unpin_fb; - if (!new_plane_state->uapi.fence) { /* implicit fencing */ - struct dma_resv_iter cursor; - struct dma_fence *fence; - - ret = i915_sw_fence_await_reservation(&state->commit_ready, - obj->base.resv, false, - i915_fence_timeout(dev_priv), - GFP_KERNEL); - if (ret < 0) - goto unpin_fb; + if (new_plane_state->uapi.fence) { + i915_gem_fence_wait_priority(new_plane_state->uapi.fence, + &attr); - dma_resv_iter_begin(&cursor, obj->base.resv, - DMA_RESV_USAGE_WRITE); - dma_resv_for_each_fence_unlocked(&cursor, fence) { - intel_display_rps_boost_after_vblank(new_plane_state->hw.crtc, - fence); - } - dma_resv_iter_end(&cursor); - } else { intel_display_rps_boost_after_vblank(new_plane_state->hw.crtc, new_plane_state->uapi.fence); } diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index 19605264a35c3a..07e0c73204f309 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -25,6 +25,7 @@ #include #include +#include #include #include "i915_drv.h" @@ -521,25 +522,25 @@ static unsigned int calc_hblank_early_prog(struct intel_encoder *encoder, unsigned int link_clks_available, link_clks_required; unsigned int tu_data, tu_line, link_clks_active; unsigned int h_active, h_total, hblank_delta, pixel_clk; - unsigned int fec_coeff, cdclk, vdsc_bpp; + unsigned int fec_coeff, cdclk, vdsc_bppx16; unsigned int link_clk, lanes; unsigned int hblank_rise; h_active = crtc_state->hw.adjusted_mode.crtc_hdisplay; h_total = crtc_state->hw.adjusted_mode.crtc_htotal; pixel_clk = crtc_state->hw.adjusted_mode.crtc_clock; - vdsc_bpp = crtc_state->dsc.compressed_bpp; + vdsc_bppx16 = crtc_state->dsc.compressed_bpp_x16; cdclk = i915->display.cdclk.hw.cdclk; /* fec= 0.972261, using rounding multiplier of 1000000 */ fec_coeff = 972261; link_clk = crtc_state->port_clock; lanes = crtc_state->lane_count; - drm_dbg_kms(&i915->drm, "h_active = %u link_clk = %u :" - "lanes = %u vdsc_bpp = %u cdclk = %u\n", - h_active, link_clk, lanes, vdsc_bpp, cdclk); + drm_dbg_kms(&i915->drm, + "h_active = %u link_clk = %u : lanes = %u vdsc_bpp = " BPP_X16_FMT " cdclk = %u\n", + h_active, link_clk, lanes, BPP_X16_ARGS(vdsc_bppx16), cdclk); - if (WARN_ON(!link_clk || !pixel_clk || !lanes || !vdsc_bpp || !cdclk)) + if (WARN_ON(!link_clk || !pixel_clk || !lanes || !vdsc_bppx16 || !cdclk)) return 0; link_clks_available = (h_total - h_active) * link_clk / pixel_clk - 28; @@ -551,8 +552,8 @@ static unsigned int calc_hblank_early_prog(struct intel_encoder *encoder, hblank_delta = DIV64_U64_ROUND_UP(mul_u32_u32(5 * (link_clk + cdclk), pixel_clk), mul_u32_u32(link_clk, cdclk)); - tu_data = div64_u64(mul_u32_u32(pixel_clk * vdsc_bpp * 8, 1000000), - mul_u32_u32(link_clk * lanes, fec_coeff)); + tu_data = div64_u64(mul_u32_u32(pixel_clk * vdsc_bppx16 * 8, 1000000), + mul_u32_u32(link_clk * lanes * 16, fec_coeff)); tu_line = div64_u64(h_active * mul_u32_u32(link_clk, fec_coeff), mul_u32_u32(64 * pixel_clk, 1000000)); link_clks_active = (tu_line - 1) * 64 + tu_data; diff --git a/drivers/gpu/drm/i915/display/intel_backlight.c b/drivers/gpu/drm/i915/display/intel_backlight.c index 2e8f17c0452223..3f3cd944a1c5bf 100644 --- a/drivers/gpu/drm/i915/display/intel_backlight.c +++ b/drivers/gpu/drm/i915/display/intel_backlight.c @@ -88,10 +88,10 @@ u32 intel_backlight_invert_pwm_level(struct intel_connector *connector, u32 val) drm_WARN_ON(&i915->drm, panel->backlight.pwm_level_max == 0); - if (i915->params.invert_brightness < 0) + if (i915->display.params.invert_brightness < 0) return val; - if (i915->params.invert_brightness > 0 || + if (i915->display.params.invert_brightness > 0 || intel_has_quirk(i915, QUIRK_INVERT_BRIGHTNESS)) { return panel->backlight.pwm_level_max - val + panel->backlight.pwm_level_min; } @@ -132,8 +132,9 @@ u32 intel_backlight_level_from_pwm(struct intel_connector *connector, u32 val) drm_WARN_ON_ONCE(&i915->drm, panel->backlight.max == 0 || panel->backlight.pwm_level_max == 0); - if (i915->params.invert_brightness > 0 || - (i915->params.invert_brightness == 0 && intel_has_quirk(i915, QUIRK_INVERT_BRIGHTNESS))) + if (i915->display.params.invert_brightness > 0 || + (i915->display.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, @@ -274,7 +275,7 @@ static void ext_pwm_set_backlight(const struct drm_connector_state *conn_state, struct intel_panel *panel = &to_intel_connector(conn_state->connector)->panel; pwm_set_relative_duty_cycle(&panel->backlight.pwm_state, level, 100); - pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state); + pwm_apply_might_sleep(panel->backlight.pwm, &panel->backlight.pwm_state); } static void @@ -427,7 +428,7 @@ static void ext_pwm_disable_backlight(const struct drm_connector_state *old_conn intel_backlight_set_pwm_level(old_conn_state, level); panel->backlight.pwm_state.enabled = false; - pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state); + pwm_apply_might_sleep(panel->backlight.pwm, &panel->backlight.pwm_state); } void intel_backlight_disable(const struct drm_connector_state *old_conn_state) @@ -749,7 +750,7 @@ static void ext_pwm_enable_backlight(const struct intel_crtc_state *crtc_state, pwm_set_relative_duty_cycle(&panel->backlight.pwm_state, level, 100); panel->backlight.pwm_state.enabled = true; - pwm_apply_state(panel->backlight.pwm, &panel->backlight.pwm_state); + pwm_apply_might_sleep(panel->backlight.pwm, &panel->backlight.pwm_state); } static void __intel_backlight_enable(const struct intel_crtc_state *crtc_state, diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index 4e8f1e91bb0899..aa169b0055e97d 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -1116,7 +1116,7 @@ parse_sdvo_panel_data(struct drm_i915_private *i915, struct drm_display_mode *panel_fixed_mode; int index; - index = i915->params.vbt_sdvo_panel_type; + index = i915->display.params.vbt_sdvo_panel_type; if (index == -2) { drm_dbg_kms(&i915->drm, "Ignore SDVO panel mode from BIOS VBT tables.\n"); @@ -1514,9 +1514,9 @@ parse_edp(struct drm_i915_private *i915, u8 vswing; /* Don't read from VBT if module parameter has valid value*/ - if (i915->params.edp_vswing) { + if (i915->display.params.edp_vswing) { panel->vbt.edp.low_vswing = - i915->params.edp_vswing == 1; + i915->display.params.edp_vswing == 1; } else { vswing = (edp->edp_vswing_preemph >> (panel_type * 4)) & 0xF; panel->vbt.edp.low_vswing = vswing == 0; @@ -2201,6 +2201,9 @@ static u8 map_ddc_pin(struct drm_i915_private *i915, u8 vbt_pin) const u8 *ddc_pin_map; int i, n_entries; + if (IS_DGFX(i915)) + return vbt_pin; + if (INTEL_PCH_TYPE(i915) >= PCH_LNL || HAS_PCH_MTP(i915) || IS_ALDERLAKE_P(i915)) { ddc_pin_map = adlp_ddc_pin_map; @@ -2208,8 +2211,6 @@ static u8 map_ddc_pin(struct drm_i915_private *i915, u8 vbt_pin) } else if (IS_ALDERLAKE_S(i915)) { ddc_pin_map = adls_ddc_pin_map; n_entries = ARRAY_SIZE(adls_ddc_pin_map); - } else if (INTEL_PCH_TYPE(i915) >= PCH_DG1) { - return vbt_pin; } else if (IS_ROCKETLAKE(i915) && INTEL_PCH_TYPE(i915) == PCH_TGP) { ddc_pin_map = rkl_pch_tgp_ddc_pin_map; n_entries = ARRAY_SIZE(rkl_pch_tgp_ddc_pin_map); @@ -2473,6 +2474,27 @@ static void sanitize_device_type(struct intel_bios_encoder_data *devdata, devdata->child.device_type |= DEVICE_TYPE_NOT_HDMI_OUTPUT; } +static void sanitize_hdmi_level_shift(struct intel_bios_encoder_data *devdata, + enum port port) +{ + struct drm_i915_private *i915 = devdata->i915; + + if (!intel_bios_encoder_supports_dvi(devdata)) + return; + + /* + * Some BDW machines (eg. HP Pavilion 15-ab) shipped + * with a HSW VBT where the level shifter value goes + * up to 11, whereas the BDW max is 9. + */ + if (IS_BROADWELL(i915) && devdata->child.hdmi_level_shifter_value > 9) { + drm_dbg_kms(&i915->drm, "Bogus port %c VBT HDMI level shift %d, adjusting to %d\n", + port_name(port), devdata->child.hdmi_level_shifter_value, 9); + + devdata->child.hdmi_level_shifter_value = 9; + } +} + static bool intel_bios_encoder_supports_crt(const struct intel_bios_encoder_data *devdata) { @@ -2652,6 +2674,7 @@ static void parse_ddi_port(struct intel_bios_encoder_data *devdata) } sanitize_device_type(devdata, port); + sanitize_hdmi_level_shift(devdata, port); } static bool has_ddi_port_info(struct drm_i915_private *i915) @@ -3392,8 +3415,8 @@ static void fill_dsc(struct intel_crtc_state *crtc_state, crtc_state->pipe_bpp = bpc * 3; - crtc_state->dsc.compressed_bpp = min(crtc_state->pipe_bpp, - VBT_DSC_MAX_BPP(dsc->max_bpp)); + crtc_state->dsc.compressed_bpp_x16 = to_bpp_x16(min(crtc_state->pipe_bpp, + VBT_DSC_MAX_BPP(dsc->max_bpp))); /* * FIXME: This is ugly, and slice count should take DSC engine @@ -3452,8 +3475,7 @@ bool intel_bios_get_dsc_params(struct intel_encoder *encoder, if (!devdata->dsc) return false; - if (crtc_state) - fill_dsc(crtc_state, devdata->dsc, dsc_max_bpc); + fill_dsc(crtc_state, devdata->dsc, dsc_max_bpc); return true; } diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915/display/intel_bw.c index bef96db62c8075..7f2a50b4f49400 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.c +++ b/drivers/gpu/drm/i915/display/intel_bw.c @@ -87,7 +87,8 @@ static int icl_pcode_read_qgv_point_info(struct drm_i915_private *dev_priv, return ret; dclk = val & 0xffff; - sp->dclk = DIV_ROUND_UP((16667 * dclk) + (DISPLAY_VER(dev_priv) > 11 ? 500 : 0), 1000); + sp->dclk = DIV_ROUND_UP((16667 * dclk) + (DISPLAY_VER(dev_priv) >= 12 ? 500 : 0), + 1000); sp->t_rp = (val & 0xff0000) >> 16; sp->t_rcd = (val & 0xff000000) >> 24; @@ -480,7 +481,7 @@ static int tgl_get_bw_info(struct drm_i915_private *dev_priv, const struct intel if (num_channels < qi.max_numchannels && DISPLAY_VER(dev_priv) >= 12) qi.deinterleave = max(DIV_ROUND_UP(qi.deinterleave, 2), 1); - if (DISPLAY_VER(dev_priv) > 11 && num_channels > qi.max_numchannels) + if (DISPLAY_VER(dev_priv) >= 12 && num_channels > qi.max_numchannels) drm_warn(&dev_priv->drm, "Number of channels exceeds max number of channels."); if (qi.max_numchannels != 0) num_channels = min_t(u8, num_channels, qi.max_numchannels); @@ -897,7 +898,7 @@ static int icl_find_qgv_points(struct drm_i915_private *i915, unsigned int idx; unsigned int max_data_rate; - if (DISPLAY_VER(i915) > 11) + if (DISPLAY_VER(i915) >= 12) idx = tgl_max_bw_index(i915, num_active_planes, i); else idx = icl_max_bw_index(i915, num_active_planes, i); diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index c4839c67cb0f06..c985ebb6831a37 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -1180,7 +1180,7 @@ sanitize: /* force cdclk programming */ dev_priv->display.cdclk.hw.cdclk = 0; /* force full PLL disable + enable */ - dev_priv->display.cdclk.hw.vco = -1; + dev_priv->display.cdclk.hw.vco = ~0; } static void skl_cdclk_init_hw(struct drm_i915_private *dev_priv) @@ -1446,50 +1446,77 @@ static u8 bxt_calc_voltage_level(int cdclk) return DIV_ROUND_UP(cdclk, 25000); } +static u8 calc_voltage_level(int cdclk, int num_voltage_levels, + const int voltage_level_max_cdclk[]) +{ + int voltage_level; + + for (voltage_level = 0; voltage_level < num_voltage_levels; voltage_level++) { + if (cdclk <= voltage_level_max_cdclk[voltage_level]) + return voltage_level; + } + + MISSING_CASE(cdclk); + return num_voltage_levels - 1; +} + static u8 icl_calc_voltage_level(int cdclk) { - if (cdclk > 556800) - return 2; - else if (cdclk > 312000) - return 1; - else - return 0; + static const int icl_voltage_level_max_cdclk[] = { + [0] = 312000, + [1] = 556800, + [2] = 652800, + }; + + return calc_voltage_level(cdclk, + ARRAY_SIZE(icl_voltage_level_max_cdclk), + icl_voltage_level_max_cdclk); } static u8 ehl_calc_voltage_level(int cdclk) { - if (cdclk > 326400) - return 3; - else if (cdclk > 312000) - return 2; - else if (cdclk > 180000) - return 1; - else - return 0; + static const int ehl_voltage_level_max_cdclk[] = { + [0] = 180000, + [1] = 312000, + [2] = 326400, + /* + * Bspec lists the limit as 556.8 MHz, but some JSL + * development boards (at least) boot with 652.8 MHz + */ + [3] = 652800, + }; + + return calc_voltage_level(cdclk, + ARRAY_SIZE(ehl_voltage_level_max_cdclk), + ehl_voltage_level_max_cdclk); } static u8 tgl_calc_voltage_level(int cdclk) { - if (cdclk > 556800) - return 3; - else if (cdclk > 326400) - return 2; - else if (cdclk > 312000) - return 1; - else - return 0; + static const int tgl_voltage_level_max_cdclk[] = { + [0] = 312000, + [1] = 326400, + [2] = 556800, + [3] = 652800, + }; + + return calc_voltage_level(cdclk, + ARRAY_SIZE(tgl_voltage_level_max_cdclk), + tgl_voltage_level_max_cdclk); } static u8 rplu_calc_voltage_level(int cdclk) { - if (cdclk > 556800) - return 3; - else if (cdclk > 480000) - return 2; - else if (cdclk > 312000) - return 1; - else - return 0; + static const int rplu_voltage_level_max_cdclk[] = { + [0] = 312000, + [1] = 480000, + [2] = 556800, + [3] = 652800, + }; + + return calc_voltage_level(cdclk, + ARRAY_SIZE(rplu_voltage_level_max_cdclk), + rplu_voltage_level_max_cdclk); } static void icl_readout_refclk(struct drm_i915_private *dev_priv, @@ -1800,6 +1827,8 @@ static bool cdclk_pll_is_unknown(unsigned int vco) return vco == ~0; } +static const int cdclk_squash_len = 16; + static int cdclk_squash_divider(u16 waveform) { return hweight16(waveform ?: 0xffff); @@ -1811,7 +1840,6 @@ static bool cdclk_compute_crawl_and_squash_midpoint(struct drm_i915_private *i91 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. */ @@ -1850,7 +1878,8 @@ static bool cdclk_compute_crawl_and_squash_midpoint(struct drm_i915_private *i91 } mid_cdclk_config->cdclk = DIV_ROUND_CLOSEST(cdclk_squash_divider(mid_waveform) * - mid_cdclk_config->vco, size * div); + mid_cdclk_config->vco, + cdclk_squash_len * div); /* make sure the mid clock came out sane */ @@ -1878,9 +1907,9 @@ static void _bxt_set_cdclk(struct drm_i915_private *dev_priv, { int cdclk = cdclk_config->cdclk; int vco = cdclk_config->vco; - u32 val; + int unsquashed_cdclk; u16 waveform; - int clock; + u32 val; 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)) { @@ -1897,15 +1926,13 @@ static void _bxt_set_cdclk(struct drm_i915_private *dev_priv, waveform = cdclk_squash_waveform(dev_priv, cdclk); - if (waveform) - clock = vco / 2; - else - clock = cdclk; + unsquashed_cdclk = DIV_ROUND_CLOSEST(cdclk * cdclk_squash_len, + cdclk_squash_divider(waveform)); if (HAS_CDCLK_SQUASH(dev_priv)) dg2_cdclk_squash_program(dev_priv, waveform); - val = bxt_cdclk_cd2x_div_sel(dev_priv, clock, vco) | + val = bxt_cdclk_cd2x_div_sel(dev_priv, unsquashed_cdclk, vco) | bxt_cdclk_cd2x_pipe(dev_priv, pipe); /* @@ -2075,7 +2102,7 @@ sanitize: dev_priv->display.cdclk.hw.cdclk = 0; /* force full PLL disable + enable */ - dev_priv->display.cdclk.hw.vco = -1; + dev_priv->display.cdclk.hw.vco = ~0; } static void bxt_cdclk_init_hw(struct drm_i915_private *dev_priv) @@ -2597,9 +2624,10 @@ static int intel_vdsc_min_cdclk(const struct intel_crtc_state *crtc_state) * Since PPC = 2 with bigjoiner * => CDCLK >= compressed_bpp * Pixel clock / 2 * Bigjoiner Interface bits */ - int bigjoiner_interface_bits = DISPLAY_VER(i915) > 13 ? 36 : 24; - int min_cdclk_bj = (crtc_state->dsc.compressed_bpp * pixel_clock) / - (2 * bigjoiner_interface_bits); + int bigjoiner_interface_bits = DISPLAY_VER(i915) >= 14 ? 36 : 24; + int min_cdclk_bj = + (to_bpp_int_roundup(crtc_state->dsc.compressed_bpp_x16) * + pixel_clock) / (2 * bigjoiner_interface_bits); min_cdclk = max(min_cdclk, min_cdclk_bj); } @@ -3488,7 +3516,7 @@ 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, + .calc_voltage_level = rplu_calc_voltage_level, }; static const struct intel_cdclk_funcs rplu_cdclk_funcs = { diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index 1d26be54ddfc2a..c5092b7e87d52b 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -785,14 +785,12 @@ static void chv_assign_csc(struct intel_crtc_state *crtc_state) /* convert hw value with given bit_precision to lut property val */ static u32 intel_color_lut_pack(u32 val, int bit_precision) { - u32 max = 0xffff >> (16 - bit_precision); - - val = clamp_val(val, 0, max); - - if (bit_precision < 16) - val <<= 16 - bit_precision; - - return val; + if (bit_precision > 16) + return DIV_ROUND_CLOSEST_ULL(mul_u32_u32(val, (1 << 16) - 1), + (1 << bit_precision) - 1); + else + return DIV_ROUND_CLOSEST(val * ((1 << 16) - 1), + (1 << bit_precision) - 1); } static u32 i9xx_lut_8(const struct drm_color_lut *color) @@ -911,7 +909,7 @@ static void i965_lut_10p6_pack(struct drm_color_lut *entry, u32 ldw, u32 udw) static u16 i965_lut_11p6_max_pack(u32 val) { /* PIPEGCMAX is 11.6, clamp to 10.6 */ - return clamp_val(val, 0, 0xffff); + return min(val, 0xffffu); } static u32 ilk_lut_10(const struct drm_color_lut *color) @@ -1528,14 +1526,27 @@ static int glk_degamma_lut_size(struct drm_i915_private *i915) return 35; } -/* - * change_lut_val_precision: helper function to upscale or downscale lut values. - * Parameters 'to' and 'from' needs to be less than 32. This should be sufficient - * as currently there are no lut values exceeding 32 bit. - */ -static u32 change_lut_val_precision(u32 lut_val, int to, int from) +static u32 glk_degamma_lut(const struct drm_color_lut *color) +{ + return color->green; +} + +static void glk_degamma_lut_pack(struct drm_color_lut *entry, u32 val) +{ + /* PRE_CSC_GAMC_DATA is 3.16, clamp to 0.16 */ + entry->red = entry->green = entry->blue = min(val, 0xffffu); +} + +static u32 mtl_degamma_lut(const struct drm_color_lut *color) +{ + return drm_color_lut_extract(color->green, 24); +} + +static void mtl_degamma_lut_pack(struct drm_color_lut *entry, u32 val) { - return mul_u32_u32(lut_val, (1 << to)) / (1 << from); + /* PRE_CSC_GAMC_DATA is 3.24, clamp to 0.16 */ + entry->red = entry->green = entry->blue = + intel_color_lut_pack(min(val, 0xffffffu), 24); } static void glk_load_degamma_lut(const struct intel_crtc_state *crtc_state, @@ -1572,20 +1583,16 @@ 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. */ - u32 lut_val; - - if (DISPLAY_VER(i915) >= 14) - lut_val = change_lut_val_precision(lut[i].green, 24, 16); - else - lut_val = lut[i].green; - ilk_lut_write(crtc_state, PRE_CSC_GAMC_DATA(pipe), - lut_val); + DISPLAY_VER(i915) >= 14 ? + mtl_degamma_lut(&lut[i]) : glk_degamma_lut(&lut[i])); } /* Clamp values > 1.0. */ while (i++ < glk_degamma_lut_size(i915)) - ilk_lut_write(crtc_state, PRE_CSC_GAMC_DATA(pipe), 1 << 16); + ilk_lut_write(crtc_state, PRE_CSC_GAMC_DATA(pipe), + DISPLAY_VER(i915) >= 14 ? + 1 << 24 : 1 << 16); ilk_lut_write(crtc_state, PRE_CSC_GAMC_INDEX(pipe), 0); } @@ -3572,17 +3579,10 @@ static struct drm_property_blob *glk_read_degamma_lut(struct intel_crtc *crtc) for (i = 0; i < lut_size; i++) { u32 val = intel_de_read_fw(dev_priv, PRE_CSC_GAMC_DATA(pipe)); - /* - * For MTL and beyond, convert back the 24 bit lut values - * read from HW to 16 bit values to maintain parity with - * userspace values - */ if (DISPLAY_VER(dev_priv) >= 14) - val = change_lut_val_precision(val, 16, 24); - - lut[i].red = val; - lut[i].green = val; - lut[i].blue = val; + mtl_degamma_lut_pack(&lut[i], val); + else + glk_degamma_lut_pack(&lut[i], val); } intel_de_write_fw(dev_priv, PRE_CSC_GAMC_INDEX(pipe), diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c index 6f6b348b8a4054..abaacea5c2cc45 100644 --- a/drivers/gpu/drm/i915/display/intel_crt.c +++ b/drivers/gpu/drm/i915/display/intel_crt.c @@ -846,7 +846,7 @@ intel_crt_detect(struct drm_connector *connector, if (!intel_display_device_enabled(dev_priv)) return connector_status_disconnected; - if (dev_priv->params.load_detect_test) { + if (dev_priv->display.params.load_detect_test) { wakeref = intel_display_power_get(dev_priv, intel_encoder->power_domain); goto load_detect; @@ -906,7 +906,7 @@ load_detect: else if (DISPLAY_VER(dev_priv) < 4) status = intel_crt_load_detect(crt, to_intel_crtc(connector->state->crtc)->pipe); - else if (dev_priv->params.load_detect_test) + else if (dev_priv->display.params.load_detect_test) status = connector_status_disconnected; else status = connector_status_unknown; diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c index 1fd068e6e26ca6..8a84a31c7b48a2 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc.c +++ b/drivers/gpu/drm/i915/display/intel_crtc.c @@ -553,8 +553,15 @@ void intel_pipe_update_start(struct intel_atomic_state *state, intel_psr_lock(new_crtc_state); - if (new_crtc_state->do_async_flip) + if (new_crtc_state->do_async_flip) { + spin_lock_irq(&crtc->base.dev->event_lock); + /* arm the event for the flip done irq handler */ + crtc->flip_done_event = new_crtc_state->uapi.event; + spin_unlock_irq(&crtc->base.dev->event_lock); + + new_crtc_state->uapi.event = NULL; return; + } if (intel_crtc_needs_vblank_work(new_crtc_state)) intel_crtc_vblank_work_init(new_crtc_state); 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 66fe880af8f3f0..49fd100ec98a02 100644 --- a/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c +++ b/drivers/gpu/drm/i915/display/intel_crtc_state_dump.c @@ -4,6 +4,7 @@ */ #include +#include #include "i915_drv.h" #include "intel_crtc_state_dump.h" @@ -261,6 +262,15 @@ void intel_crtc_state_dump(const struct intel_crtc_state *pipe_config, drm_dbg_kms(&i915->drm, "fec: %s, enhanced framing: %s\n", str_enabled_disabled(pipe_config->fec_enable), str_enabled_disabled(pipe_config->enhanced_framing)); + + drm_dbg_kms(&i915->drm, "sdp split: %s\n", + str_enabled_disabled(pipe_config->sdp_split_enable)); + + drm_dbg_kms(&i915->drm, "psr: %s, psr2: %s, panel replay: %s, selective fetch: %s\n", + str_enabled_disabled(pipe_config->has_psr), + str_enabled_disabled(pipe_config->has_psr2), + str_enabled_disabled(pipe_config->has_panel_replay), + str_enabled_disabled(pipe_config->enable_psr2_sel_fetch)); } drm_dbg_kms(&i915->drm, "framestart delay: %d, MSA timing delay: %d\n", diff --git a/drivers/gpu/drm/i915/display/intel_cursor.c b/drivers/gpu/drm/i915/display/intel_cursor.c index b342fad180ca5b..926e2de00eb582 100644 --- a/drivers/gpu/drm/i915/display/intel_cursor.c +++ b/drivers/gpu/drm/i915/display/intel_cursor.c @@ -21,8 +21,11 @@ #include "intel_fb_pin.h" #include "intel_frontbuffer.h" #include "intel_psr.h" +#include "intel_psr_regs.h" #include "skl_watermark.h" +#include "gem/i915_gem_object.h" + /* Cursor formats */ static const u32 intel_cursor_formats[] = { DRM_FORMAT_ARGB8888, @@ -33,11 +36,11 @@ static u32 intel_cursor_base(const struct intel_plane_state *plane_state) struct drm_i915_private *dev_priv = to_i915(plane_state->uapi.plane->dev); const struct drm_framebuffer *fb = plane_state->hw.fb; - const struct drm_i915_gem_object *obj = intel_fb_obj(fb); + struct drm_i915_gem_object *obj = intel_fb_obj(fb); u32 base; if (DISPLAY_INFO(dev_priv)->cursor_needs_physical) - base = sg_dma_address(obj->mm.pages->sgl); + base = i915_gem_object_get_dma_address(obj, 0); else base = intel_plane_ggtt_offset(plane_state); @@ -484,6 +487,35 @@ static int i9xx_check_cursor(struct intel_crtc_state *crtc_state, return 0; } +static void i9xx_cursor_disable_sel_fetch_arm(struct intel_plane *plane, + const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + enum pipe pipe = plane->pipe; + + if (!crtc_state->enable_psr2_sel_fetch) + return; + + intel_de_write_fw(dev_priv, PLANE_SEL_FETCH_CTL(pipe, plane->id), 0); +} + +static void i9xx_cursor_update_sel_fetch_arm(struct intel_plane *plane, + const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state) +{ + struct drm_i915_private *i915 = to_i915(plane->base.dev); + enum pipe pipe = plane->pipe; + + if (!crtc_state->enable_psr2_sel_fetch) + return; + + if (drm_rect_height(&plane_state->psr2_sel_fetch_area) > 0) + intel_de_write_fw(i915, PLANE_SEL_FETCH_CTL(pipe, plane->id), + plane_state->ctl); + else + i9xx_cursor_disable_sel_fetch_arm(plane, crtc_state); +} + /* TODO: split into noarm+arm pair */ static void i9xx_cursor_update_arm(struct intel_plane *plane, const struct intel_crtc_state *crtc_state, @@ -531,10 +563,10 @@ static void i9xx_cursor_update_arm(struct intel_plane *plane, skl_write_cursor_wm(plane, crtc_state); if (plane_state) - intel_psr2_program_plane_sel_fetch_arm(plane, crtc_state, - plane_state); + i9xx_cursor_update_sel_fetch_arm(plane, crtc_state, + plane_state); else - intel_psr2_disable_plane_sel_fetch_arm(plane, crtc_state); + i9xx_cursor_disable_sel_fetch_arm(plane, crtc_state); if (plane->cursor.base != base || plane->cursor.size != fbc_ctl || diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index ccf225afeb2ad3..6b25e195232f13 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -31,7 +31,7 @@ bool intel_is_c10phy(struct drm_i915_private *i915, enum phy phy) { - if (DISPLAY_VER_FULL(i915) == IP_VER(14, 0) && phy < PHY_C) + if ((IS_LUNARLAKE(i915) || IS_METEORLAKE(i915)) && phy < PHY_C) return true; return false; @@ -206,6 +206,13 @@ static int __intel_cx0_read_once(struct drm_i915_private *i915, enum port port, intel_clear_response_ready_flag(i915, port, lane); + /* + * FIXME: Workaround to let HW to settle + * down and let the message bus to end up + * in a known state + */ + intel_cx0_bus_reset(i915, port, lane); + return REG_FIELD_GET(XELPDP_PORT_P2M_DATA_MASK, val); } @@ -285,6 +292,13 @@ static int __intel_cx0_write_once(struct drm_i915_private *i915, enum port port, intel_clear_response_ready_flag(i915, port, lane); + /* + * FIXME: Workaround to let HW to settle + * down and let the message bus to end up + * in a known state + */ + intel_cx0_bus_reset(i915, port, lane); + return 0; } @@ -401,9 +415,15 @@ void intel_cx0_phy_set_signal_levels(struct intel_encoder *encoder, struct drm_i915_private *i915 = to_i915(encoder->base.dev); const struct intel_ddi_buf_trans *trans; enum phy phy = intel_port_to_phy(i915, encoder->port); - u8 owned_lane_mask = intel_cx0_get_owned_lane_mask(i915, encoder); + u8 owned_lane_mask; intel_wakeref_t wakeref; int n_entries, ln; + struct intel_digital_port *dig_port = enc_to_dig_port(encoder); + + if (intel_tc_port_in_tbt_alt_mode(dig_port)) + return; + + owned_lane_mask = intel_cx0_get_owned_lane_mask(i915, encoder); wakeref = intel_cx0_phy_transaction_begin(encoder); @@ -725,7 +745,6 @@ static const struct intel_c10pll_state * const mtl_c10_edp_tables[] = { /* C20 basic DP 1.4 tables */ static const struct intel_c20pll_state mtl_c20_dp_rbr = { - .link_bit_rate = 162000, .clock = 162000, .tx = { 0xbe88, /* tx cfg0 */ 0x5800, /* tx cfg1 */ @@ -751,7 +770,6 @@ static const struct intel_c20pll_state mtl_c20_dp_rbr = { }; static const struct intel_c20pll_state mtl_c20_dp_hbr1 = { - .link_bit_rate = 270000, .clock = 270000, .tx = { 0xbe88, /* tx cfg0 */ 0x4800, /* tx cfg1 */ @@ -777,7 +795,6 @@ static const struct intel_c20pll_state mtl_c20_dp_hbr1 = { }; static const struct intel_c20pll_state mtl_c20_dp_hbr2 = { - .link_bit_rate = 540000, .clock = 540000, .tx = { 0xbe88, /* tx cfg0 */ 0x4800, /* tx cfg1 */ @@ -803,7 +820,6 @@ static const struct intel_c20pll_state mtl_c20_dp_hbr2 = { }; static const struct intel_c20pll_state mtl_c20_dp_hbr3 = { - .link_bit_rate = 810000, .clock = 810000, .tx = { 0xbe88, /* tx cfg0 */ 0x4800, /* tx cfg1 */ @@ -830,8 +846,7 @@ static const struct intel_c20pll_state mtl_c20_dp_hbr3 = { /* C20 basic DP 2.0 tables */ static const struct intel_c20pll_state mtl_c20_dp_uhbr10 = { - .link_bit_rate = 1000000, /* 10 Gbps */ - .clock = 312500, + .clock = 1000000, /* 10 Gbps */ .tx = { 0xbe21, /* tx cfg0 */ 0x4800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -855,8 +870,7 @@ static const struct intel_c20pll_state mtl_c20_dp_uhbr10 = { }; static const struct intel_c20pll_state mtl_c20_dp_uhbr13_5 = { - .link_bit_rate = 1350000, /* 13.5 Gbps */ - .clock = 421875, + .clock = 1350000, /* 13.5 Gbps */ .tx = { 0xbea0, /* tx cfg0 */ 0x4800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -881,8 +895,7 @@ static const struct intel_c20pll_state mtl_c20_dp_uhbr13_5 = { }; static const struct intel_c20pll_state mtl_c20_dp_uhbr20 = { - .link_bit_rate = 2000000, /* 20 Gbps */ - .clock = 625000, + .clock = 2000000, /* 20 Gbps */ .tx = { 0xbe20, /* tx cfg0 */ 0x4800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1501,7 +1514,6 @@ static const struct intel_c10pll_state * const mtl_c10_hdmi_tables[] = { }; static const struct intel_c20pll_state mtl_c20_hdmi_25_175 = { - .link_bit_rate = 25175, .clock = 25175, .tx = { 0xbe88, /* tx cfg0 */ 0x9800, /* tx cfg1 */ @@ -1527,7 +1539,6 @@ static const struct intel_c20pll_state mtl_c20_hdmi_25_175 = { }; static const struct intel_c20pll_state mtl_c20_hdmi_27_0 = { - .link_bit_rate = 27000, .clock = 27000, .tx = { 0xbe88, /* tx cfg0 */ 0x9800, /* tx cfg1 */ @@ -1553,7 +1564,6 @@ static const struct intel_c20pll_state mtl_c20_hdmi_27_0 = { }; static const struct intel_c20pll_state mtl_c20_hdmi_74_25 = { - .link_bit_rate = 74250, .clock = 74250, .tx = { 0xbe88, /* tx cfg0 */ 0x9800, /* tx cfg1 */ @@ -1579,7 +1589,6 @@ static const struct intel_c20pll_state mtl_c20_hdmi_74_25 = { }; static const struct intel_c20pll_state mtl_c20_hdmi_148_5 = { - .link_bit_rate = 148500, .clock = 148500, .tx = { 0xbe88, /* tx cfg0 */ 0x9800, /* tx cfg1 */ @@ -1605,7 +1614,6 @@ static const struct intel_c20pll_state mtl_c20_hdmi_148_5 = { }; static const struct intel_c20pll_state mtl_c20_hdmi_594 = { - .link_bit_rate = 594000, .clock = 594000, .tx = { 0xbe88, /* tx cfg0 */ 0x9800, /* tx cfg1 */ @@ -1631,8 +1639,7 @@ static const struct intel_c20pll_state mtl_c20_hdmi_594 = { }; static const struct intel_c20pll_state mtl_c20_hdmi_300 = { - .link_bit_rate = 3000000, - .clock = 166670, + .clock = 3000000, .tx = { 0xbe98, /* tx cfg0 */ 0x9800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1657,8 +1664,7 @@ static const struct intel_c20pll_state mtl_c20_hdmi_300 = { }; static const struct intel_c20pll_state mtl_c20_hdmi_600 = { - .link_bit_rate = 6000000, - .clock = 333330, + .clock = 6000000, .tx = { 0xbe98, /* tx cfg0 */ 0x9800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1683,8 +1689,7 @@ static const struct intel_c20pll_state mtl_c20_hdmi_600 = { }; static const struct intel_c20pll_state mtl_c20_hdmi_800 = { - .link_bit_rate = 8000000, - .clock = 444440, + .clock = 8000000, .tx = { 0xbe98, /* tx cfg0 */ 0x9800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1709,8 +1714,7 @@ static const struct intel_c20pll_state mtl_c20_hdmi_800 = { }; static const struct intel_c20pll_state mtl_c20_hdmi_1000 = { - .link_bit_rate = 10000000, - .clock = 555560, + .clock = 10000000, .tx = { 0xbe98, /* tx cfg0 */ 0x9800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1735,8 +1739,7 @@ static const struct intel_c20pll_state mtl_c20_hdmi_1000 = { }; static const struct intel_c20pll_state mtl_c20_hdmi_1200 = { - .link_bit_rate = 12000000, - .clock = 666670, + .clock = 12000000, .tx = { 0xbe98, /* tx cfg0 */ 0x9800, /* tx cfg1 */ 0x0000, /* tx cfg2 */ @@ -1850,8 +1853,8 @@ static int intel_c10pll_calc_state(struct intel_crtc_state *crtc_state, return -EINVAL; } -void intel_c10pll_readout_hw_state(struct intel_encoder *encoder, - struct intel_c10pll_state *pll_state) +static void intel_c10pll_readout_hw_state(struct intel_encoder *encoder, + struct intel_c10pll_state *pll_state) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); u8 lane = INTEL_CX0_LANE0; @@ -1985,7 +1988,6 @@ static int intel_c20_compute_hdmi_tmds_pll(u64 pixel_clock, struct intel_c20pll_ else mpllb_ana_freq_vco = MPLLB_ANA_FREQ_VCO_0; - pll_state->link_bit_rate = pixel_clock; pll_state->clock = pixel_clock; pll_state->tx[0] = 0xbe88; pll_state->tx[1] = 0x9800; @@ -2022,7 +2024,7 @@ static int intel_c20_phy_check_hdmi_link_rate(int clock) int i; for (i = 0; tables[i]; i++) { - if (clock == tables[i]->link_bit_rate) + if (clock == tables[i]->clock) return MODE_OK; } @@ -2074,7 +2076,7 @@ static int intel_c20pll_calc_state(struct intel_crtc_state *crtc_state, return -EINVAL; for (i = 0; tables[i]; i++) { - if (crtc_state->port_clock == tables[i]->link_bit_rate) { + if (crtc_state->port_clock == tables[i]->clock) { crtc_state->cx0pll_state.c20 = *tables[i]; return 0; } @@ -2097,14 +2099,14 @@ int intel_cx0pll_calc_state(struct intel_crtc_state *crtc_state, static bool intel_c20_use_mplla(u32 clock) { /* 10G and 20G rates use MPLLA */ - if (clock == 312500 || clock == 625000) + if (clock == 1000000 || clock == 2000000) return true; return false; } -void intel_c20pll_readout_hw_state(struct intel_encoder *encoder, - struct intel_c20pll_state *pll_state) +static void intel_c20pll_readout_hw_state(struct intel_encoder *encoder, + struct intel_c20pll_state *pll_state) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); bool cntx; @@ -2200,11 +2202,11 @@ static u8 intel_c20_get_dp_rate(u32 clock) return 6; case 432000: /* 4.32 Gbps eDP */ return 7; - case 312500: /* 10 Gbps DP2.0 */ + case 1000000: /* 10 Gbps DP2.0 */ return 8; - case 421875: /* 13.5 Gbps DP2.0 */ + case 1350000: /* 13.5 Gbps DP2.0 */ return 9; - case 625000: /* 20 Gbps DP2.0*/ + case 2000000: /* 20 Gbps DP2.0 */ return 10; case 648000: /* 6.48 Gbps eDP*/ return 11; @@ -2222,13 +2224,13 @@ static u8 intel_c20_get_hdmi_rate(u32 clock) return 0; switch (clock) { - case 166670: /* 3 Gbps */ - case 333330: /* 6 Gbps */ - case 666670: /* 12 Gbps */ + case 300000: /* 3 Gbps */ + case 600000: /* 6 Gbps */ + case 1200000: /* 12 Gbps */ return 1; - case 444440: /* 8 Gbps */ + case 800000: /* 8 Gbps */ return 2; - case 555560: /* 10 Gbps */ + case 1000000: /* 10 Gbps */ return 3; default: MISSING_CASE(clock); @@ -2239,7 +2241,7 @@ static u8 intel_c20_get_hdmi_rate(u32 clock) static bool is_dp2(u32 clock) { /* DP2.0 clock rates */ - if (clock == 312500 || clock == 421875 || clock == 625000) + if (clock == 1000000 || clock == 1350000 || clock == 2000000) return true; return false; @@ -2248,11 +2250,11 @@ static bool is_dp2(u32 clock) static bool is_hdmi_frl(u32 clock) { switch (clock) { - case 166670: /* 3 Gbps */ - case 333330: /* 6 Gbps */ - case 444440: /* 8 Gbps */ - case 555560: /* 10 Gbps */ - case 666670: /* 12 Gbps */ + case 300000: /* 3 Gbps */ + case 600000: /* 6 Gbps */ + case 800000: /* 8 Gbps */ + case 1000000: /* 10 Gbps */ + case 1200000: /* 12 Gbps */ return true; default: return false; @@ -2285,6 +2287,7 @@ static void intel_c20_pll_program(struct drm_i915_private *i915, const struct intel_c20pll_state *pll_state = &crtc_state->cx0pll_state.c20; bool dp = false; int lane = crtc_state->lane_count > 2 ? INTEL_CX0_BOTH_LANES : INTEL_CX0_LANE0; + u32 clock = crtc_state->port_clock; bool cntx; int i; @@ -2323,7 +2326,7 @@ static void intel_c20_pll_program(struct drm_i915_private *i915, } /* 3.3 mpllb or mplla configuration */ - if (intel_c20_use_mplla(pll_state->clock)) { + if (intel_c20_use_mplla(clock)) { for (i = 0; i < ARRAY_SIZE(pll_state->mplla); i++) { if (cntx) intel_c20_sram_write(i915, encoder->port, INTEL_CX0_LANE0, @@ -2350,23 +2353,23 @@ static void intel_c20_pll_program(struct drm_i915_private *i915, /* 4. Program custom width to match the link protocol */ intel_cx0_rmw(i915, encoder->port, lane, PHY_C20_VDR_CUSTOM_WIDTH, PHY_C20_CUSTOM_WIDTH_MASK, - PHY_C20_CUSTOM_WIDTH(intel_get_c20_custom_width(pll_state->clock, dp)), + PHY_C20_CUSTOM_WIDTH(intel_get_c20_custom_width(clock, dp)), MB_WRITE_COMMITTED); /* 5. For DP or 6. For HDMI */ if (dp) { intel_cx0_rmw(i915, encoder->port, lane, PHY_C20_VDR_CUSTOM_SERDES_RATE, BIT(6) | PHY_C20_CUSTOM_SERDES_MASK, - BIT(6) | PHY_C20_CUSTOM_SERDES(intel_c20_get_dp_rate(pll_state->clock)), + BIT(6) | PHY_C20_CUSTOM_SERDES(intel_c20_get_dp_rate(clock)), MB_WRITE_COMMITTED); } else { intel_cx0_rmw(i915, encoder->port, lane, PHY_C20_VDR_CUSTOM_SERDES_RATE, BIT(7) | PHY_C20_CUSTOM_SERDES_MASK, - is_hdmi_frl(pll_state->clock) ? BIT(7) : 0, + is_hdmi_frl(clock) ? BIT(7) : 0, MB_WRITE_COMMITTED); intel_cx0_write(i915, encoder->port, INTEL_CX0_BOTH_LANES, PHY_C20_VDR_HDMI_RATE, - intel_c20_get_hdmi_rate(pll_state->clock), + intel_c20_get_hdmi_rate(clock), MB_WRITE_COMMITTED); } @@ -2378,8 +2381,8 @@ static void intel_c20_pll_program(struct drm_i915_private *i915, BIT(0), cntx ? 0 : 1, MB_WRITE_COMMITTED); } -int intel_c10pll_calc_port_clock(struct intel_encoder *encoder, - const struct intel_c10pll_state *pll_state) +static int intel_c10pll_calc_port_clock(struct intel_encoder *encoder, + const struct intel_c10pll_state *pll_state) { unsigned int frac_quot = 0, frac_rem = 0, frac_den = 1; unsigned int multiplier, tx_clk_div, hdmi_div, refclk = 38400; @@ -2405,8 +2408,8 @@ int intel_c10pll_calc_port_clock(struct intel_encoder *encoder, return tmpclk; } -int intel_c20pll_calc_port_clock(struct intel_encoder *encoder, - const struct intel_c20pll_state *pll_state) +static int intel_c20pll_calc_port_clock(struct intel_encoder *encoder, + const struct intel_c20pll_state *pll_state) { unsigned int frac, frac_en, frac_quot, frac_rem, frac_den; unsigned int multiplier, refclk = 38400; @@ -3004,17 +3007,115 @@ intel_mtl_port_pll_type(struct intel_encoder *encoder, return ICL_PORT_DPLL_DEFAULT; } -void intel_c10pll_state_verify(struct intel_atomic_state *state, +static void intel_c10pll_state_verify(const struct intel_crtc_state *state, + struct intel_crtc *crtc, + struct intel_encoder *encoder, + struct intel_c10pll_state *mpllb_hw_state) +{ + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + const struct intel_c10pll_state *mpllb_sw_state = &state->cx0pll_state.c10; + int i; + + for (i = 0; i < ARRAY_SIZE(mpllb_sw_state->pll); i++) { + u8 expected = mpllb_sw_state->pll[i]; + + I915_STATE_WARN(i915, mpllb_hw_state->pll[i] != expected, + "[CRTC:%d:%s] mismatch in C10MPLLB: Register[%d] (expected 0x%02x, found 0x%02x)", + crtc->base.base.id, crtc->base.name, i, + expected, mpllb_hw_state->pll[i]); + } + + I915_STATE_WARN(i915, mpllb_hw_state->tx != mpllb_sw_state->tx, + "[CRTC:%d:%s] mismatch in C10MPLLB: Register TX0 (expected 0x%02x, found 0x%02x)", + crtc->base.base.id, crtc->base.name, + mpllb_sw_state->tx, mpllb_hw_state->tx); + + I915_STATE_WARN(i915, mpllb_hw_state->cmn != mpllb_sw_state->cmn, + "[CRTC:%d:%s] mismatch in C10MPLLB: Register CMN0 (expected 0x%02x, found 0x%02x)", + crtc->base.base.id, crtc->base.name, + mpllb_sw_state->cmn, mpllb_hw_state->cmn); +} + +void intel_cx0pll_readout_hw_state(struct intel_encoder *encoder, + struct intel_cx0pll_state *pll_state) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum phy phy = intel_port_to_phy(i915, encoder->port); + + if (intel_is_c10phy(i915, phy)) + intel_c10pll_readout_hw_state(encoder, &pll_state->c10); + else + intel_c20pll_readout_hw_state(encoder, &pll_state->c20); +} + +int intel_cx0pll_calc_port_clock(struct intel_encoder *encoder, + const struct intel_cx0pll_state *pll_state) +{ + struct drm_i915_private *i915 = to_i915(encoder->base.dev); + enum phy phy = intel_port_to_phy(i915, encoder->port); + + if (intel_is_c10phy(i915, phy)) + return intel_c10pll_calc_port_clock(encoder, &pll_state->c10); + + return intel_c20pll_calc_port_clock(encoder, &pll_state->c20); +} + +static void intel_c20pll_state_verify(const struct intel_crtc_state *state, + struct intel_crtc *crtc, + struct intel_encoder *encoder, + struct intel_c20pll_state *mpll_hw_state) +{ + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + const struct intel_c20pll_state *mpll_sw_state = &state->cx0pll_state.c20; + bool sw_use_mpllb = mpll_sw_state->tx[0] & C20_PHY_USE_MPLLB; + bool hw_use_mpllb = mpll_hw_state->tx[0] & C20_PHY_USE_MPLLB; + int i; + + I915_STATE_WARN(i915, sw_use_mpllb != hw_use_mpllb, + "[CRTC:%d:%s] mismatch in C20: Register MPLLB selection (expected %d, found %d)", + crtc->base.base.id, crtc->base.name, + sw_use_mpllb, hw_use_mpllb); + + if (hw_use_mpllb) { + for (i = 0; i < ARRAY_SIZE(mpll_sw_state->mpllb); i++) { + I915_STATE_WARN(i915, mpll_hw_state->mpllb[i] != mpll_sw_state->mpllb[i], + "[CRTC:%d:%s] mismatch in C20MPLLB: Register[%d] (expected 0x%04x, found 0x%04x)", + crtc->base.base.id, crtc->base.name, i, + mpll_sw_state->mpllb[i], mpll_hw_state->mpllb[i]); + } + } else { + for (i = 0; i < ARRAY_SIZE(mpll_sw_state->mplla); i++) { + I915_STATE_WARN(i915, mpll_hw_state->mplla[i] != mpll_sw_state->mplla[i], + "[CRTC:%d:%s] mismatch in C20MPLLA: Register[%d] (expected 0x%04x, found 0x%04x)", + crtc->base.base.id, crtc->base.name, i, + mpll_sw_state->mplla[i], mpll_hw_state->mplla[i]); + } + } + + for (i = 0; i < ARRAY_SIZE(mpll_sw_state->tx); i++) { + I915_STATE_WARN(i915, mpll_hw_state->tx[i] != mpll_sw_state->tx[i], + "[CRTC:%d:%s] mismatch in C20: Register TX[%i] (expected 0x%04x, found 0x%04x)", + crtc->base.base.id, crtc->base.name, i, + mpll_sw_state->tx[i], mpll_hw_state->tx[i]); + } + + for (i = 0; i < ARRAY_SIZE(mpll_sw_state->cmn); i++) { + I915_STATE_WARN(i915, mpll_hw_state->cmn[i] != mpll_sw_state->cmn[i], + "[CRTC:%d:%s] mismatch in C20: Register CMN[%i] (expected 0x%04x, found 0x%04x)", + crtc->base.base.id, crtc->base.name, i, + mpll_sw_state->cmn[i], mpll_hw_state->cmn[i]); + } +} + +void intel_cx0pll_state_verify(struct intel_atomic_state *state, struct intel_crtc *crtc) { struct drm_i915_private *i915 = to_i915(state->base.dev); const struct intel_crtc_state *new_crtc_state = intel_atomic_get_new_crtc_state(state, crtc); - struct intel_c10pll_state mpllb_hw_state = {}; - const struct intel_c10pll_state *mpllb_sw_state = &new_crtc_state->cx0pll_state.c10; struct intel_encoder *encoder; + struct intel_cx0pll_state mpll_hw_state = {}; enum phy phy; - int i; if (DISPLAY_VER(i915) < 14) return; @@ -3030,27 +3131,13 @@ void intel_c10pll_state_verify(struct intel_atomic_state *state, encoder = intel_get_crtc_new_encoder(state, new_crtc_state); phy = intel_port_to_phy(i915, encoder->port); - if (!intel_is_c10phy(i915, phy)) + if (intel_tc_port_in_tbt_alt_mode(enc_to_dig_port(encoder))) return; - intel_c10pll_readout_hw_state(encoder, &mpllb_hw_state); + intel_cx0pll_readout_hw_state(encoder, &mpll_hw_state); - for (i = 0; i < ARRAY_SIZE(mpllb_sw_state->pll); i++) { - u8 expected = mpllb_sw_state->pll[i]; - - I915_STATE_WARN(i915, mpllb_hw_state.pll[i] != expected, - "[CRTC:%d:%s] mismatch in C10MPLLB: Register[%d] (expected 0x%02x, found 0x%02x)", - crtc->base.base.id, crtc->base.name, i, - expected, mpllb_hw_state.pll[i]); - } - - I915_STATE_WARN(i915, mpllb_hw_state.tx != mpllb_sw_state->tx, - "[CRTC:%d:%s] mismatch in C10MPLLB: Register TX0 (expected 0x%02x, found 0x%02x)", - crtc->base.base.id, crtc->base.name, - mpllb_sw_state->tx, mpllb_hw_state.tx); - - I915_STATE_WARN(i915, mpllb_hw_state.cmn != mpllb_sw_state->cmn, - "[CRTC:%d:%s] mismatch in C10MPLLB: Register CMN0 (expected 0x%02x, found 0x%02x)", - crtc->base.base.id, crtc->base.name, - mpllb_sw_state->cmn, mpllb_hw_state.cmn); + if (intel_is_c10phy(i915, phy)) + intel_c10pll_state_verify(new_crtc_state, crtc, encoder, &mpll_hw_state.c10); + else + intel_c20pll_state_verify(new_crtc_state, crtc, encoder, &mpll_hw_state.c20); } diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.h b/drivers/gpu/drm/i915/display/intel_cx0_phy.h index 0e0a38dac8cdd9..c6682677253a84 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.h +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.h @@ -16,6 +16,7 @@ struct drm_i915_private; struct intel_atomic_state; struct intel_c10pll_state; struct intel_c20pll_state; +struct intel_cx0pll_state; struct intel_crtc; struct intel_crtc_state; struct intel_encoder; @@ -28,20 +29,19 @@ void intel_mtl_pll_disable(struct intel_encoder *encoder); enum icl_port_dpll_id intel_mtl_port_pll_type(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); -void intel_c10pll_readout_hw_state(struct intel_encoder *encoder, struct intel_c10pll_state *pll_state); + int intel_cx0pll_calc_state(struct intel_crtc_state *crtc_state, struct intel_encoder *encoder); +void intel_cx0pll_readout_hw_state(struct intel_encoder *encoder, + struct intel_cx0pll_state *pll_state); +int intel_cx0pll_calc_port_clock(struct intel_encoder *encoder, + const struct intel_cx0pll_state *pll_state); + void intel_c10pll_dump_hw_state(struct drm_i915_private *dev_priv, const struct intel_c10pll_state *hw_state); -int intel_c10pll_calc_port_clock(struct intel_encoder *encoder, - const struct intel_c10pll_state *pll_state); -void intel_c10pll_state_verify(struct intel_atomic_state *state, +void intel_cx0pll_state_verify(struct intel_atomic_state *state, struct intel_crtc *crtc); -void intel_c20pll_readout_hw_state(struct intel_encoder *encoder, - struct intel_c20pll_state *pll_state); void intel_c20pll_dump_hw_state(struct drm_i915_private *i915, const struct intel_c20pll_state *hw_state); -int intel_c20pll_calc_port_clock(struct intel_encoder *encoder, - const struct intel_c20pll_state *pll_state); void intel_cx0_phy_set_signal_levels(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); int intel_cx0_phy_check_hdmi_link_rate(struct intel_hdmi *hdmi, int clock); diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 9151d5add9605f..12a29363e5dfe4 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -25,6 +25,7 @@ * */ +#include #include #include @@ -2210,16 +2211,87 @@ static void intel_dp_sink_set_msa_timing_par_ignore_state(struct intel_dp *intel } static void intel_dp_sink_set_fec_ready(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state) + const struct intel_crtc_state *crtc_state, + bool enable) { struct drm_i915_private *i915 = dp_to_i915(intel_dp); if (!crtc_state->fec_enable) return; - if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_FEC_CONFIGURATION, DP_FEC_READY) <= 0) - drm_dbg_kms(&i915->drm, - "Failed to set FEC_READY in the sink\n"); + if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_FEC_CONFIGURATION, + enable ? DP_FEC_READY : 0) <= 0) + drm_dbg_kms(&i915->drm, "Failed to set FEC_READY to %s in the sink\n", + enable ? "enabled" : "disabled"); + + if (enable && + drm_dp_dpcd_writeb(&intel_dp->aux, DP_FEC_STATUS, + DP_FEC_DECODE_EN_DETECTED | DP_FEC_DECODE_DIS_DETECTED) <= 0) + drm_dbg_kms(&i915->drm, "Failed to clear FEC detected flags\n"); +} + +static int read_fec_detected_status(struct drm_dp_aux *aux) +{ + int ret; + u8 status; + + ret = drm_dp_dpcd_readb(aux, DP_FEC_STATUS, &status); + if (ret < 0) + return ret; + + return status; +} + +static void wait_for_fec_detected(struct drm_dp_aux *aux, bool enabled) +{ + struct drm_i915_private *i915 = to_i915(aux->drm_dev); + int mask = enabled ? DP_FEC_DECODE_EN_DETECTED : DP_FEC_DECODE_DIS_DETECTED; + int status; + int err; + + err = readx_poll_timeout(read_fec_detected_status, aux, status, + status & mask || status < 0, + 10000, 200000); + + if (!err && status >= 0) + return; + + if (err == -ETIMEDOUT) + drm_dbg_kms(&i915->drm, "Timeout waiting for FEC %s to get detected\n", + str_enabled_disabled(enabled)); + else + drm_dbg_kms(&i915->drm, "FEC detected status read error: %d\n", status); +} + +void intel_ddi_wait_for_fec_status(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + bool enabled) +{ + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + int ret; + + if (!crtc_state->fec_enable) + return; + + if (enabled) + ret = intel_de_wait_for_set(i915, dp_tp_status_reg(encoder, crtc_state), + DP_TP_STATUS_FEC_ENABLE_LIVE, 1); + else + ret = intel_de_wait_for_clear(i915, dp_tp_status_reg(encoder, crtc_state), + DP_TP_STATUS_FEC_ENABLE_LIVE, 1); + + if (ret) + drm_err(&i915->drm, + "Timeout waiting for FEC live state to get %s\n", + str_enabled_disabled(enabled)); + + /* + * At least the Synoptics MST hub doesn't set the detected flag for + * FEC decoding disabling so skip waiting for that. + */ + if (enabled) + wait_for_fec_detected(&intel_dp->aux, enabled); } static void intel_ddi_enable_fec(struct intel_encoder *encoder, @@ -2234,8 +2306,8 @@ static void intel_ddi_enable_fec(struct intel_encoder *encoder, 0, DP_TP_CTL_FEC_ENABLE); } -static void intel_ddi_disable_fec_state(struct intel_encoder *encoder, - const struct intel_crtc_state *crtc_state) +static void intel_ddi_disable_fec(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); @@ -2466,13 +2538,17 @@ static void mtl_ddi_pre_enable_dp(struct intel_atomic_state *state, intel_dp_set_power(intel_dp, DP_SET_POWER_D0); intel_dp_configure_protocol_converter(intel_dp, crtc_state); - intel_dp_sink_set_decompression_state(intel_dp, crtc_state, true); + if (!is_mst) + intel_dp_sink_enable_decompression(state, + to_intel_connector(conn_state->connector), + crtc_state); + /* * DDI FEC: "anticipates enabling FEC encoding sets the FEC_READY bit * in the FEC_CONFIGURATION register to 1 before initiating link * training */ - intel_dp_sink_set_fec_ready(intel_dp, crtc_state); + intel_dp_sink_set_fec_ready(intel_dp, crtc_state, true); intel_dp_check_frl_training(intel_dp); intel_dp_pcon_dsc_configure(intel_dp, crtc_state); @@ -2505,7 +2581,8 @@ static void mtl_ddi_pre_enable_dp(struct intel_atomic_state *state, /* 6.o Configure and enable FEC if needed */ intel_ddi_enable_fec(encoder, crtc_state); - intel_dsc_dp_pps_write(encoder, crtc_state); + if (!is_mst) + intel_dsc_dp_pps_write(encoder, crtc_state); } static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state, @@ -2616,13 +2693,16 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state, intel_dp_set_power(intel_dp, DP_SET_POWER_D0); intel_dp_configure_protocol_converter(intel_dp, crtc_state); - intel_dp_sink_set_decompression_state(intel_dp, crtc_state, true); + if (!is_mst) + intel_dp_sink_enable_decompression(state, + to_intel_connector(conn_state->connector), + crtc_state); /* * DDI FEC: "anticipates enabling FEC encoding sets the FEC_READY bit * in the FEC_CONFIGURATION register to 1 before initiating link * training */ - intel_dp_sink_set_fec_ready(intel_dp, crtc_state); + intel_dp_sink_set_fec_ready(intel_dp, crtc_state, true); intel_dp_check_frl_training(intel_dp); intel_dp_pcon_dsc_configure(intel_dp, crtc_state); @@ -2643,7 +2723,8 @@ static void tgl_ddi_pre_enable_dp(struct intel_atomic_state *state, /* 7.l Configure and enable FEC if needed */ intel_ddi_enable_fec(encoder, crtc_state); - intel_dsc_dp_pps_write(encoder, crtc_state); + if (!is_mst) + intel_dsc_dp_pps_write(encoder, crtc_state); } static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state, @@ -2695,9 +2776,11 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state, if (!is_mst) intel_dp_set_power(intel_dp, DP_SET_POWER_D0); intel_dp_configure_protocol_converter(intel_dp, crtc_state); - intel_dp_sink_set_decompression_state(intel_dp, crtc_state, - true); - intel_dp_sink_set_fec_ready(intel_dp, crtc_state); + if (!is_mst) + intel_dp_sink_enable_decompression(state, + to_intel_connector(conn_state->connector), + crtc_state); + intel_dp_sink_set_fec_ready(intel_dp, crtc_state, true); intel_dp_start_link_train(intel_dp, crtc_state); if ((port != PORT_A || DISPLAY_VER(dev_priv) >= 9) && !is_trans_port_sync_mode(crtc_state)) @@ -2705,10 +2788,10 @@ static void hsw_ddi_pre_enable_dp(struct intel_atomic_state *state, intel_ddi_enable_fec(encoder, crtc_state); - if (!is_mst) + if (!is_mst) { intel_ddi_enable_transcoder_clock(encoder, crtc_state); - - intel_dsc_dp_pps_write(encoder, crtc_state); + intel_dsc_dp_pps_write(encoder, crtc_state); + } } static void intel_ddi_pre_enable_dp(struct intel_atomic_state *state, @@ -2717,10 +2800,15 @@ static void intel_ddi_pre_enable_dp(struct intel_atomic_state *state, const struct drm_connector_state *conn_state) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - if (HAS_DP20(dev_priv)) + if (HAS_DP20(dev_priv)) { intel_dp_128b132b_sdp_crc16(enc_to_intel_dp(encoder), crtc_state); + if (crtc_state->has_panel_replay) + drm_dp_dpcd_writeb(&intel_dp->aux, PANEL_REPLAY_CONFIG, + DP_PANEL_REPLAY_ENABLE); + } if (DISPLAY_VER(dev_priv) >= 14) mtl_ddi_pre_enable_dp(state, encoder, crtc_state, conn_state); @@ -2866,8 +2954,7 @@ static void disable_ddi_buf(struct intel_encoder *encoder, intel_de_rmw(dev_priv, dp_tp_ctl_reg(encoder, crtc_state), DP_TP_CTL_ENABLE, 0); - /* Disable FEC in DP Sink */ - intel_ddi_disable_fec_state(encoder, crtc_state); + intel_ddi_disable_fec(encoder, crtc_state); if (wait) intel_wait_ddi_buf_idle(dev_priv, port); @@ -2882,10 +2969,12 @@ static void intel_disable_ddi_buf(struct intel_encoder *encoder, mtl_disable_ddi_buf(encoder, crtc_state); /* 3.f Disable DP_TP_CTL FEC Enable if it is needed */ - intel_ddi_disable_fec_state(encoder, crtc_state); + intel_ddi_disable_fec(encoder, crtc_state); } else { disable_ddi_buf(encoder, crtc_state); } + + intel_ddi_wait_for_fec_status(encoder, crtc_state, false); } static void intel_ddi_post_disable_dp(struct intel_atomic_state *state, @@ -2925,6 +3014,8 @@ static void intel_ddi_post_disable_dp(struct intel_atomic_state *state, intel_disable_ddi_buf(encoder, old_crtc_state); + intel_dp_sink_set_fec_ready(intel_dp, old_crtc_state, false); + /* * From TGL spec: "If single stream or multi-stream master transcoder: * Configure Transcoder Clock select to direct no clock to the @@ -3110,11 +3201,18 @@ static void intel_enable_ddi_dp(struct intel_atomic_state *state, if (!dig_port->lspcon.active || intel_dp_has_hdmi_sink(&dig_port->dp)) intel_dp_set_infoframes(encoder, true, crtc_state, conn_state); - intel_audio_codec_enable(encoder, crtc_state, conn_state); - trans_port_sync_stop_link_train(state, encoder, crtc_state); } +/* FIXME bad home for this function */ +i915_reg_t hsw_chicken_trans_reg(struct drm_i915_private *i915, + enum transcoder cpu_transcoder) +{ + return DISPLAY_VER(i915) >= 14 ? + MTL_CHICKEN_TRANS(cpu_transcoder) : + CHICKEN_TRANS(cpu_transcoder); +} + static i915_reg_t gen9_chicken_trans_reg_by_port(struct drm_i915_private *dev_priv, enum port port) @@ -3233,8 +3331,6 @@ 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); } static void intel_enable_ddi(struct intel_atomic_state *state, @@ -3252,6 +3348,8 @@ static void intel_enable_ddi(struct intel_atomic_state *state, intel_enable_transcoder(crtc_state); + intel_ddi_wait_for_fec_status(encoder, crtc_state, true); + intel_crtc_vblank_on(crtc_state); if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) @@ -3259,10 +3357,8 @@ static void intel_enable_ddi(struct intel_atomic_state *state, else intel_enable_ddi_dp(state, encoder, crtc_state, conn_state); - /* Enable hdcp if it's desired */ - if (conn_state->content_protection == - DRM_MODE_CONTENT_PROTECTION_DESIRED) - intel_hdcp_enable(state, encoder, crtc_state, conn_state); + intel_hdcp_enable(state, encoder, crtc_state, conn_state); + } static void intel_disable_ddi_dp(struct intel_atomic_state *state, @@ -3271,16 +3367,16 @@ static void intel_disable_ddi_dp(struct intel_atomic_state *state, const struct drm_connector_state *old_conn_state) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + struct intel_connector *connector = + to_intel_connector(old_conn_state->connector); intel_dp->link_trained = false; - intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); - intel_psr_disable(intel_dp, old_crtc_state); intel_edp_backlight_off(old_conn_state); /* Disable the decompression in DP Sink */ - intel_dp_sink_set_decompression_state(intel_dp, old_crtc_state, - false); + intel_dp_sink_disable_decompression(state, + connector, old_crtc_state); /* Disable Ignore_MSA bit in DP Sink */ intel_dp_sink_set_msa_timing_par_ignore_state(intel_dp, old_crtc_state, false); @@ -3294,8 +3390,6 @@ static void intel_disable_ddi_hdmi(struct intel_atomic_state *state, struct drm_i915_private *i915 = to_i915(encoder->base.dev); struct drm_connector *connector = old_conn_state->connector; - intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); - if (!intel_hdmi_handle_sink_scrambling(encoder, connector, false, false)) drm_dbg_kms(&i915->drm, @@ -3578,16 +3672,42 @@ static bool intel_ddi_is_audio_enabled(struct drm_i915_private *dev_priv, AUDIO_OUTPUT_ENABLE(cpu_transcoder); } -void intel_ddi_compute_min_voltage_level(struct drm_i915_private *dev_priv, - struct intel_crtc_state *crtc_state) +static int tgl_ddi_min_voltage_level(const struct intel_crtc_state *crtc_state) +{ + if (crtc_state->port_clock > 594000) + return 2; + else + return 0; +} + +static int jsl_ddi_min_voltage_level(const struct intel_crtc_state *crtc_state) +{ + if (crtc_state->port_clock > 594000) + return 3; + else + return 0; +} + +static int icl_ddi_min_voltage_level(const struct intel_crtc_state *crtc_state) +{ + if (crtc_state->port_clock > 594000) + return 1; + else + return 0; +} + +void intel_ddi_compute_min_voltage_level(struct intel_crtc_state *crtc_state) { - if (DISPLAY_VER(dev_priv) >= 12 && crtc_state->port_clock > 594000) - crtc_state->min_voltage_level = 2; - else if ((IS_JASPERLAKE(dev_priv) || IS_ELKHARTLAKE(dev_priv)) && - crtc_state->port_clock > 594000) - crtc_state->min_voltage_level = 3; - else if (DISPLAY_VER(dev_priv) >= 11 && crtc_state->port_clock > 594000) - crtc_state->min_voltage_level = 1; + struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); + + if (DISPLAY_VER(dev_priv) >= 14) + crtc_state->min_voltage_level = icl_ddi_min_voltage_level(crtc_state); + else if (DISPLAY_VER(dev_priv) >= 12) + crtc_state->min_voltage_level = tgl_ddi_min_voltage_level(crtc_state); + else if (IS_JASPERLAKE(dev_priv) || IS_ELKHARTLAKE(dev_priv)) + crtc_state->min_voltage_level = jsl_ddi_min_voltage_level(crtc_state); + else if (DISPLAY_VER(dev_priv) >= 11) + crtc_state->min_voltage_level = icl_ddi_min_voltage_level(crtc_state); } static enum transcoder bdw_transcoder_master_readout(struct drm_i915_private *dev_priv, @@ -3801,7 +3921,7 @@ static void intel_ddi_get_config(struct intel_encoder *encoder, pipe_config->lane_lat_optim_mask = bxt_ddi_phy_get_lane_lat_optim_mask(encoder); - intel_ddi_compute_min_voltage_level(dev_priv, pipe_config); + intel_ddi_compute_min_voltage_level(pipe_config); intel_hdmi_read_gcp_infoframe(encoder, pipe_config); @@ -3854,18 +3974,13 @@ void intel_ddi_get_clock(struct intel_encoder *encoder, static void mtl_ddi_get_config(struct intel_encoder *encoder, struct intel_crtc_state *crtc_state) { - struct drm_i915_private *i915 = to_i915(encoder->base.dev); - enum phy phy = intel_port_to_phy(i915, encoder->port); struct intel_digital_port *dig_port = enc_to_dig_port(encoder); if (intel_tc_port_in_tbt_alt_mode(dig_port)) { crtc_state->port_clock = intel_mtl_tbt_calc_port_clock(encoder); - } else if (intel_is_c10phy(i915, phy)) { - intel_c10pll_readout_hw_state(encoder, &crtc_state->cx0pll_state.c10); - crtc_state->port_clock = intel_c10pll_calc_port_clock(encoder, &crtc_state->cx0pll_state.c10); } else { - intel_c20pll_readout_hw_state(encoder, &crtc_state->cx0pll_state.c20); - crtc_state->port_clock = intel_c20pll_calc_port_clock(encoder, &crtc_state->cx0pll_state.c20); + intel_cx0pll_readout_hw_state(encoder, &crtc_state->cx0pll_state); + crtc_state->port_clock = intel_cx0pll_calc_port_clock(encoder, &crtc_state->cx0pll_state); } intel_ddi_get_config(encoder, crtc_state); @@ -4086,7 +4201,7 @@ static int intel_ddi_compute_config(struct intel_encoder *encoder, pipe_config->lane_lat_optim_mask = bxt_ddi_phy_calc_lane_lat_optim_mask(pipe_config->lane_count); - intel_ddi_compute_min_voltage_level(dev_priv, pipe_config); + intel_ddi_compute_min_voltage_level(pipe_config); return 0; } @@ -4844,6 +4959,8 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, encoder->post_pll_disable = intel_ddi_post_pll_disable; encoder->post_disable = intel_ddi_post_disable; encoder->update_pipe = intel_ddi_update_pipe; + encoder->audio_enable = intel_audio_codec_enable; + encoder->audio_disable = intel_audio_codec_disable; encoder->get_hw_state = intel_ddi_get_hw_state; encoder->sync_state = intel_ddi_sync_state; encoder->initial_fastset_check = intel_ddi_initial_fastset_check; diff --git a/drivers/gpu/drm/i915/display/intel_ddi.h b/drivers/gpu/drm/i915/display/intel_ddi.h index 4999c0ee229bd3..434de7196875ae 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.h +++ b/drivers/gpu/drm/i915/display/intel_ddi.h @@ -27,6 +27,8 @@ i915_reg_t dp_tp_ctl_reg(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); i915_reg_t dp_tp_status_reg(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); +i915_reg_t hsw_chicken_trans_reg(struct drm_i915_private *i915, + enum transcoder cpu_transcoder); void intel_ddi_fdi_post_disable(struct intel_atomic_state *state, struct intel_encoder *intel_encoder, const struct intel_crtc_state *old_crtc_state, @@ -60,13 +62,15 @@ void intel_ddi_disable_transcoder_func(const struct intel_crtc_state *crtc_state void intel_ddi_enable_transcoder_clock(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); void intel_ddi_disable_transcoder_clock(const struct intel_crtc_state *crtc_state); +void intel_ddi_wait_for_fec_status(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + bool enabled); void intel_ddi_set_dp_msa(const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state); bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector); void intel_ddi_set_vc_payload_alloc(const struct intel_crtc_state *crtc_state, bool state); -void intel_ddi_compute_min_voltage_level(struct drm_i915_private *dev_priv, - struct intel_crtc_state *crtc_state); +void intel_ddi_compute_min_voltage_level(struct intel_crtc_state *crtc_state); int intel_ddi_toggle_hdcp_bits(struct intel_encoder *intel_encoder, enum transcoder cpu_transcoder, bool enable, u32 hdcp_mask); diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index df582ff81b45fa..b10aad15a63d91 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -48,6 +48,7 @@ #include "g4x_dp.h" #include "g4x_hdmi.h" #include "hsw_ips.h" +#include "i915_config.h" #include "i915_drv.h" #include "i915_reg.h" #include "i915_utils.h" @@ -72,10 +73,10 @@ #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_dpt_common.h" #include "intel_drrs.h" #include "intel_dsb.h" #include "intel_dsi.h" @@ -193,12 +194,9 @@ static bool is_hdr_mode(const struct intel_crtc_state *crtc_state) static void skl_wa_827(struct drm_i915_private *dev_priv, enum pipe pipe, bool enable) { - if (enable) - intel_de_rmw(dev_priv, CLKGATE_DIS_PSL(pipe), - 0, DUPS1_GATING_DIS | DUPS2_GATING_DIS); - else - intel_de_rmw(dev_priv, CLKGATE_DIS_PSL(pipe), - DUPS1_GATING_DIS | DUPS2_GATING_DIS, 0); + intel_de_rmw(dev_priv, CLKGATE_DIS_PSL(pipe), + DUPS1_GATING_DIS | DUPS2_GATING_DIS, + enable ? DUPS1_GATING_DIS | DUPS2_GATING_DIS : 0); } /* Wa_2006604312:icl,ehl */ @@ -206,10 +204,9 @@ static void icl_wa_scalerclkgating(struct drm_i915_private *dev_priv, enum pipe pipe, bool enable) { - if (enable) - intel_de_rmw(dev_priv, CLKGATE_DIS_PSL(pipe), 0, DPFR_GATING_DIS); - else - intel_de_rmw(dev_priv, CLKGATE_DIS_PSL(pipe), DPFR_GATING_DIS, 0); + intel_de_rmw(dev_priv, CLKGATE_DIS_PSL(pipe), + DPFR_GATING_DIS, + enable ? DPFR_GATING_DIS : 0); } /* Wa_1604331009:icl,jsl,ehl */ @@ -217,7 +214,8 @@ static void icl_wa_cursorclkgating(struct drm_i915_private *dev_priv, enum pipe pipe, bool enable) { - intel_de_rmw(dev_priv, CLKGATE_DIS_PSL(pipe), CURSOR_GATING_DIS, + intel_de_rmw(dev_priv, CLKGATE_DIS_PSL(pipe), + CURSOR_GATING_DIS, enable ? CURSOR_GATING_DIS : 0); } @@ -397,7 +395,6 @@ void intel_enable_transcoder(const struct intel_crtc_state *new_crtc_state) struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); enum transcoder cpu_transcoder = new_crtc_state->cpu_transcoder; enum pipe pipe = crtc->pipe; - i915_reg_t reg; u32 val; drm_dbg_kms(&dev_priv->drm, "enabling pipe %c\n", pipe_name(pipe)); @@ -430,16 +427,16 @@ void intel_enable_transcoder(const struct intel_crtc_state *new_crtc_state) intel_de_rmw(dev_priv, PIPE_ARB_CTL(pipe), 0, PIPE_ARB_USE_PROG_SLOTS); - reg = TRANSCONF(cpu_transcoder); - val = intel_de_read(dev_priv, reg); + val = intel_de_read(dev_priv, TRANSCONF(cpu_transcoder)); if (val & TRANSCONF_ENABLE) { /* we keep both pipes enabled on 830 */ drm_WARN_ON(&dev_priv->drm, !IS_I830(dev_priv)); return; } - intel_de_write(dev_priv, reg, val | TRANSCONF_ENABLE); - intel_de_posting_read(dev_priv, reg); + intel_de_write(dev_priv, TRANSCONF(cpu_transcoder), + val | TRANSCONF_ENABLE); + intel_de_posting_read(dev_priv, TRANSCONF(cpu_transcoder)); /* * Until the pipe starts PIPEDSL reads will return a stale value, @@ -458,7 +455,6 @@ void intel_disable_transcoder(const struct intel_crtc_state *old_crtc_state) struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); enum transcoder cpu_transcoder = old_crtc_state->cpu_transcoder; enum pipe pipe = crtc->pipe; - i915_reg_t reg; u32 val; drm_dbg_kms(&dev_priv->drm, "disabling pipe %c\n", pipe_name(pipe)); @@ -469,8 +465,7 @@ void intel_disable_transcoder(const struct intel_crtc_state *old_crtc_state) */ assert_planes_disabled(crtc); - reg = TRANSCONF(cpu_transcoder); - val = intel_de_read(dev_priv, reg); + val = intel_de_read(dev_priv, TRANSCONF(cpu_transcoder)); if ((val & TRANSCONF_ENABLE) == 0) return; @@ -485,14 +480,12 @@ void intel_disable_transcoder(const struct intel_crtc_state *old_crtc_state) if (!IS_I830(dev_priv)) val &= ~TRANSCONF_ENABLE; - if (DISPLAY_VER(dev_priv) >= 14) - intel_de_rmw(dev_priv, MTL_CHICKEN_TRANS(cpu_transcoder), - FECSTALL_DIS_DPTSTREAM_DPTTG, 0); - else if (DISPLAY_VER(dev_priv) >= 12) - intel_de_rmw(dev_priv, CHICKEN_TRANS(cpu_transcoder), + intel_de_write(dev_priv, TRANSCONF(cpu_transcoder), val); + + if (DISPLAY_VER(dev_priv) >= 12) + intel_de_rmw(dev_priv, hsw_chicken_trans_reg(dev_priv, cpu_transcoder), FECSTALL_DIS_DPTSTREAM_DPTTG, 0); - intel_de_write(dev_priv, reg, val); if ((val & TRANSCONF_ENABLE) == 0) intel_wait_for_pipe_off(old_crtc_state); } @@ -896,6 +889,48 @@ static bool needs_async_flip_vtd_wa(const struct intel_crtc_state *crtc_state) (DISPLAY_VER(i915) == 9 || IS_BROADWELL(i915) || IS_HASWELL(i915)); } +static void intel_encoders_audio_enable(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ + const struct intel_crtc_state *crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); + const struct drm_connector_state *conn_state; + struct drm_connector *conn; + int i; + + for_each_new_connector_in_state(&state->base, conn, conn_state, i) { + struct intel_encoder *encoder = + to_intel_encoder(conn_state->best_encoder); + + if (conn_state->crtc != &crtc->base) + continue; + + if (encoder->audio_enable) + encoder->audio_enable(encoder, crtc_state, conn_state); + } +} + +static void intel_encoders_audio_disable(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ + const struct intel_crtc_state *old_crtc_state = + intel_atomic_get_old_crtc_state(state, crtc); + const struct drm_connector_state *old_conn_state; + struct drm_connector *conn; + int i; + + for_each_old_connector_in_state(&state->base, conn, old_conn_state, i) { + struct intel_encoder *encoder = + to_intel_encoder(old_conn_state->best_encoder); + + if (old_conn_state->crtc != &crtc->base) + continue; + + if (encoder->audio_disable) + encoder->audio_disable(encoder, old_crtc_state, old_conn_state); + } +} + #define is_enabling(feature, old_crtc_state, new_crtc_state) \ ((!(old_crtc_state)->feature || intel_crtc_needs_modeset(new_crtc_state)) && \ (new_crtc_state)->feature) @@ -955,6 +990,28 @@ static bool vrr_disabling(const struct intel_crtc_state *old_crtc_state, vrr_params_changed(old_crtc_state, new_crtc_state))); } +static bool audio_enabling(const struct intel_crtc_state *old_crtc_state, + const struct intel_crtc_state *new_crtc_state) +{ + if (!new_crtc_state->hw.active) + return false; + + return is_enabling(has_audio, old_crtc_state, new_crtc_state) || + (new_crtc_state->has_audio && + memcmp(old_crtc_state->eld, new_crtc_state->eld, MAX_ELD_BYTES) != 0); +} + +static bool audio_disabling(const struct intel_crtc_state *old_crtc_state, + const struct intel_crtc_state *new_crtc_state) +{ + if (!old_crtc_state->hw.active) + return false; + + return is_disabling(has_audio, old_crtc_state, new_crtc_state) || + (old_crtc_state->has_audio && + memcmp(old_crtc_state->eld, new_crtc_state->eld, MAX_ELD_BYTES) != 0); +} + #undef is_disabling #undef is_enabling @@ -995,6 +1052,9 @@ static void intel_post_plane_update(struct intel_atomic_state *state, if (intel_crtc_needs_color_update(new_crtc_state)) intel_color_post_update(new_crtc_state); + + if (audio_enabling(old_crtc_state, new_crtc_state)) + intel_encoders_audio_enable(state, crtc); } static void intel_crtc_enable_flip_done(struct intel_atomic_state *state, @@ -1078,6 +1138,9 @@ static void intel_pre_plane_update(struct intel_atomic_state *state, intel_crtc_update_active_timings(old_crtc_state, false); } + if (audio_disabling(old_crtc_state, new_crtc_state)) + intel_encoders_audio_disable(state, crtc); + intel_drrs_deactivate(old_crtc_state); intel_psr_pre_plane_update(state, crtc); @@ -1513,12 +1576,9 @@ static void hsw_set_linetime_wm(const struct intel_crtc_state *crtc_state) static void hsw_set_frame_start_delay(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - enum transcoder transcoder = crtc_state->cpu_transcoder; - i915_reg_t reg = DISPLAY_VER(dev_priv) >= 14 ? MTL_CHICKEN_TRANS(transcoder) : - CHICKEN_TRANS(transcoder); + struct drm_i915_private *i915 = to_i915(crtc->base.dev); - intel_de_rmw(dev_priv, reg, + intel_de_rmw(i915, hsw_chicken_trans_reg(i915, crtc_state->cpu_transcoder), HSW_FRAME_START_DELAY_MASK, HSW_FRAME_START_DELAY(crtc_state->framestart_delay - 1)); } @@ -1796,31 +1856,31 @@ bool intel_phy_is_combo(struct drm_i915_private *dev_priv, enum phy phy) bool intel_phy_is_tc(struct drm_i915_private *dev_priv, enum phy phy) { + /* + * DG2's "TC1", although TC-capable output, doesn't share the same flow + * as other platforms on the display engine side and rather rely on the + * SNPS PHY, that is programmed separately + */ if (IS_DG2(dev_priv)) - /* DG2's "TC1" output uses a SNPS PHY */ return false; - else if (IS_ALDERLAKE_P(dev_priv) || DISPLAY_VER_FULL(dev_priv) == IP_VER(14, 0)) + + if (DISPLAY_VER(dev_priv) >= 13) return phy >= PHY_F && phy <= PHY_I; else if (IS_TIGERLAKE(dev_priv)) return phy >= PHY_D && phy <= PHY_I; else if (IS_ICELAKE(dev_priv)) return phy >= PHY_C && phy <= PHY_F; - else - return false; + + return false; } bool intel_phy_is_snps(struct drm_i915_private *dev_priv, enum phy phy) { - if (phy == PHY_NONE) - return false; - else if (IS_DG2(dev_priv)) - /* - * All four "combo" ports and the TC1 port (PHY E) use - * Synopsis PHYs. - */ - return phy <= PHY_E; - - return false; + /* + * For DG2, and for DG2 only, all four "combo" ports and the TC1 port + * (PHY E) use Synopsis PHYs. See intel_phy_is_tc(). + */ + return IS_DG2(dev_priv) && phy > PHY_NONE && phy <= PHY_E; } enum phy intel_port_to_phy(struct drm_i915_private *i915, enum port port) @@ -2409,15 +2469,15 @@ static void compute_m_n(u32 *ret_m, u32 *ret_n, } void -intel_link_compute_m_n(u16 bits_per_pixel, int nlanes, +intel_link_compute_m_n(u16 bits_per_pixel_x16, int nlanes, int pixel_clock, int link_clock, - struct intel_link_m_n *m_n, - bool fec_enable) + int bw_overhead, + struct intel_link_m_n *m_n) { - u32 data_clock = bits_per_pixel * pixel_clock; - - if (fec_enable) - data_clock = intel_dp_mode_to_fec_clock(data_clock); + u32 link_symbol_clock = intel_dp_link_symbol_clock(link_clock); + u32 data_m = intel_dp_effective_data_rate(pixel_clock, bits_per_pixel_x16, + bw_overhead); + u32 data_n = intel_dp_max_data_rate(link_clock, nlanes); /* * Windows/BIOS uses fixed M/N values always. Follow suit. @@ -2428,11 +2488,11 @@ intel_link_compute_m_n(u16 bits_per_pixel, int nlanes, */ m_n->tu = 64; compute_m_n(&m_n->data_m, &m_n->data_n, - data_clock, link_clock * nlanes * 8, + data_m, data_n, 0x8000000); compute_m_n(&m_n->link_m, &m_n->link_n, - pixel_clock, link_clock, + pixel_clock, link_symbol_clock, 0x80000); } @@ -2567,7 +2627,7 @@ static void intel_set_transcoder_timings(const struct intel_crtc_state *crtc_sta crtc_vblank_start = 1; } - if (DISPLAY_VER(dev_priv) > 3) + if (DISPLAY_VER(dev_priv) >= 4) intel_de_write(dev_priv, TRANS_VSYNCSHIFT(cpu_transcoder), vsyncshift); @@ -2850,67 +2910,6 @@ static void i9xx_get_pfit_config(struct intel_crtc_state *crtc_state) intel_de_read(dev_priv, PFIT_PGM_RATIOS); } -static void vlv_crtc_clock_get(struct intel_crtc *crtc, - struct intel_crtc_state *pipe_config) -{ - struct drm_device *dev = crtc->base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); - enum pipe pipe = crtc->pipe; - struct dpll clock; - u32 mdiv; - int refclk = 100000; - - /* In case of DSI, DPLL will not be used */ - if ((pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) == 0) - return; - - vlv_dpio_get(dev_priv); - mdiv = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW3(pipe)); - vlv_dpio_put(dev_priv); - - clock.m1 = (mdiv >> DPIO_M1DIV_SHIFT) & 7; - clock.m2 = mdiv & DPIO_M2DIV_MASK; - clock.n = (mdiv >> DPIO_N_SHIFT) & 0xf; - clock.p1 = (mdiv >> DPIO_P1_SHIFT) & 7; - clock.p2 = (mdiv >> DPIO_P2_SHIFT) & 0x1f; - - pipe_config->port_clock = vlv_calc_dpll_params(refclk, &clock); -} - -static void chv_crtc_clock_get(struct intel_crtc *crtc, - struct intel_crtc_state *pipe_config) -{ - struct drm_device *dev = crtc->base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); - enum pipe pipe = crtc->pipe; - enum dpio_channel port = vlv_pipe_to_channel(pipe); - struct dpll clock; - u32 cmn_dw13, pll_dw0, pll_dw1, pll_dw2, pll_dw3; - int refclk = 100000; - - /* In case of DSI, DPLL will not be used */ - if ((pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) == 0) - return; - - vlv_dpio_get(dev_priv); - cmn_dw13 = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW13(port)); - pll_dw0 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW0(port)); - pll_dw1 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW1(port)); - pll_dw2 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW2(port)); - pll_dw3 = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW3(port)); - vlv_dpio_put(dev_priv); - - clock.m1 = (pll_dw1 & 0x7) == DPIO_CHV_M1_DIV_BY_2 ? 2 : 0; - clock.m2 = (pll_dw0 & 0xff) << 22; - if (pll_dw3 & DPIO_CHV_FRAC_DIV_EN) - clock.m2 |= pll_dw2 & 0x3fffff; - clock.n = (pll_dw1 >> DPIO_CHV_N_DIV_SHIFT) & 0xf; - clock.p1 = (cmn_dw13 >> DPIO_CHV_P1_DIV_SHIFT) & 0x7; - clock.p2 = (cmn_dw13 >> DPIO_CHV_P2_DIV_SHIFT) & 0x1f; - - pipe_config->port_clock = chv_calc_dpll_params(refclk, &clock); -} - static enum intel_output_format bdw_get_pipe_misc_output_format(struct intel_crtc *crtc) { @@ -3168,7 +3167,7 @@ static void bdw_set_pipe_misc(const struct intel_crtc_state *crtc_state) break; case 36: /* Port output 12BPC defined for ADLP+ */ - if (DISPLAY_VER(dev_priv) > 12) + if (DISPLAY_VER(dev_priv) >= 13) val |= PIPE_MISC_BPC_12_ADLP; break; default: @@ -3225,7 +3224,7 @@ int bdw_get_pipe_misc_bpp(struct intel_crtc *crtc) * MIPI DSI HW readout. */ case PIPE_MISC_BPC_12_ADLP: - if (DISPLAY_VER(dev_priv) > 12) + if (DISPLAY_VER(dev_priv) >= 13) return 36; fallthrough; default: @@ -3802,9 +3801,7 @@ static bool hsw_get_pipe_config(struct intel_crtc *crtc, } if (!transcoder_is_dsi(pipe_config->cpu_transcoder)) { - tmp = intel_de_read(dev_priv, DISPLAY_VER(dev_priv) >= 14 ? - MTL_CHICKEN_TRANS(pipe_config->cpu_transcoder) : - CHICKEN_TRANS(pipe_config->cpu_transcoder)); + tmp = intel_de_read(dev_priv, hsw_chicken_trans_reg(dev_priv, pipe_config->cpu_transcoder)); pipe_config->framestart_delay = REG_FIELD_GET(HSW_FRAME_START_DELAY_MASK, tmp) + 1; } else { @@ -3833,133 +3830,27 @@ bool intel_crtc_get_pipe_config(struct intel_crtc_state *crtc_state) return true; } -static int i9xx_pll_refclk(struct drm_device *dev, - const struct intel_crtc_state *pipe_config) -{ - struct drm_i915_private *dev_priv = to_i915(dev); - u32 dpll = pipe_config->dpll_hw_state.dpll; - - if ((dpll & PLL_REF_INPUT_MASK) == PLLB_REF_INPUT_SPREADSPECTRUMIN) - return dev_priv->display.vbt.lvds_ssc_freq; - else if (HAS_PCH_SPLIT(dev_priv)) - return 120000; - else if (DISPLAY_VER(dev_priv) != 2) - return 96000; - else - return 48000; -} - -/* Returns the clock of the currently programmed mode of the given pipe. */ -void i9xx_crtc_clock_get(struct intel_crtc *crtc, - struct intel_crtc_state *pipe_config) -{ - struct drm_device *dev = crtc->base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); - u32 dpll = pipe_config->dpll_hw_state.dpll; - u32 fp; - struct dpll clock; - int port_clock; - int refclk = i9xx_pll_refclk(dev, pipe_config); - - if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0) - fp = pipe_config->dpll_hw_state.fp0; - else - fp = pipe_config->dpll_hw_state.fp1; - - clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT; - if (IS_PINEVIEW(dev_priv)) { - clock.n = ffs((fp & FP_N_PINEVIEW_DIV_MASK) >> FP_N_DIV_SHIFT) - 1; - clock.m2 = (fp & FP_M2_PINEVIEW_DIV_MASK) >> FP_M2_DIV_SHIFT; - } else { - clock.n = (fp & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT; - clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT; - } - - if (DISPLAY_VER(dev_priv) != 2) { - if (IS_PINEVIEW(dev_priv)) - clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_PINEVIEW) >> - DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW); - else - clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK) >> - DPLL_FPA01_P1_POST_DIV_SHIFT); - - switch (dpll & DPLL_MODE_MASK) { - case DPLLB_MODE_DAC_SERIAL: - clock.p2 = dpll & DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 ? - 5 : 10; - break; - case DPLLB_MODE_LVDS: - clock.p2 = dpll & DPLLB_LVDS_P2_CLOCK_DIV_7 ? - 7 : 14; - break; - default: - drm_dbg_kms(&dev_priv->drm, - "Unknown DPLL mode %08x in programmed " - "mode\n", (int)(dpll & DPLL_MODE_MASK)); - return; - } - - if (IS_PINEVIEW(dev_priv)) - port_clock = pnv_calc_dpll_params(refclk, &clock); - else - port_clock = i9xx_calc_dpll_params(refclk, &clock); - } else { - enum pipe lvds_pipe; - - if (IS_I85X(dev_priv) && - intel_lvds_port_enabled(dev_priv, LVDS, &lvds_pipe) && - lvds_pipe == crtc->pipe) { - u32 lvds = intel_de_read(dev_priv, LVDS); - - clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS) >> - DPLL_FPA01_P1_POST_DIV_SHIFT); - - if (lvds & LVDS_CLKB_POWER_UP) - clock.p2 = 7; - else - clock.p2 = 14; - } else { - if (dpll & PLL_P1_DIVIDE_BY_TWO) - clock.p1 = 2; - else { - clock.p1 = ((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830) >> - DPLL_FPA01_P1_POST_DIV_SHIFT) + 2; - } - if (dpll & PLL_P2_DIVIDE_BY_4) - clock.p2 = 4; - else - clock.p2 = 2; - } - - port_clock = i9xx_calc_dpll_params(refclk, &clock); - } - - /* - * This value includes pixel_multiplier. We will use - * port_clock to compute adjusted_mode.crtc_clock in the - * encoder's get_config() function. - */ - pipe_config->port_clock = port_clock; -} - int intel_dotclock_calculate(int link_freq, const struct intel_link_m_n *m_n) { /* - * The calculation for the data clock is: + * The calculation for the data clock -> pixel clock is: * pixel_clock = ((m/n)*(link_clock * nr_lanes))/bpp * But we want to avoid losing precison if possible, so: * pixel_clock = ((m * link_clock * nr_lanes)/(n*bpp)) * - * and the link clock is simpler: - * link_clock = (m * link_clock) / n + * and for link freq (10kbs units) -> pixel clock it is: + * link_symbol_clock = link_freq * 10 / link_symbol_size + * pixel_clock = (m * link_symbol_clock) / n + * or for more precision: + * pixel_clock = (m * link_freq * 10) / (n * link_symbol_size) */ if (!m_n->link_n) return 0; - return DIV_ROUND_UP_ULL(mul_u32_u32(m_n->link_m, link_freq), - m_n->link_n); + return DIV_ROUND_UP_ULL(mul_u32_u32(m_n->link_m, link_freq * 10), + m_n->link_n * intel_dp_link_symbol_size(link_freq)); } int intel_crtc_dotclock(const struct intel_crtc_state *pipe_config) @@ -4691,6 +4582,7 @@ intel_modeset_pipe_config(struct intel_atomic_state *state, if (ret) return ret; + crtc_state->fec_enable = limits->force_fec_pipes & BIT(crtc->pipe); crtc_state->max_link_bpp_x16 = limits->max_bpp_x16[crtc->pipe]; if (crtc_state->pipe_bpp > to_bpp_int(crtc_state->max_link_bpp_x16)) { @@ -5031,6 +4923,8 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, #define PIPE_CONF_CHECK_X(name) do { \ if (current_config->name != pipe_config->name) { \ + BUILD_BUG_ON_MSG(__same_type(current_config->name, bool), \ + __stringify(name) " is bool"); \ pipe_config_mismatch(fastset, crtc, __stringify(name), \ "(expected 0x%08x, found 0x%08x)", \ current_config->name, \ @@ -5041,6 +4935,8 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, #define PIPE_CONF_CHECK_X_WITH_MASK(name, mask) do { \ if ((current_config->name & (mask)) != (pipe_config->name & (mask))) { \ + BUILD_BUG_ON_MSG(__same_type(current_config->name, bool), \ + __stringify(name) " is bool"); \ pipe_config_mismatch(fastset, crtc, __stringify(name), \ "(expected 0x%08x, found 0x%08x)", \ current_config->name & (mask), \ @@ -5051,6 +4947,8 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, #define PIPE_CONF_CHECK_I(name) do { \ if (current_config->name != pipe_config->name) { \ + BUILD_BUG_ON_MSG(__same_type(current_config->name, bool), \ + __stringify(name) " is bool"); \ pipe_config_mismatch(fastset, crtc, __stringify(name), \ "(expected %i, found %i)", \ current_config->name, \ @@ -5061,6 +4959,8 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, #define PIPE_CONF_CHECK_BOOL(name) do { \ if (current_config->name != pipe_config->name) { \ + BUILD_BUG_ON_MSG(!__same_type(current_config->name, bool), \ + __stringify(name) " is not bool"); \ pipe_config_mismatch(fastset, crtc, __stringify(name), \ "(expected %s, found %s)", \ str_yes_no(current_config->name), \ @@ -5069,23 +4969,6 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, } \ } while (0) -/* - * Checks state where we only read out the enabling, but not the entire - * state itself (like full infoframes or ELD for audio). These states - * require a full modeset on bootup to fix up. - */ -#define PIPE_CONF_CHECK_BOOL_INCOMPLETE(name) do { \ - if (!fixup_inherited || (!current_config->name && !pipe_config->name)) { \ - PIPE_CONF_CHECK_BOOL(name); \ - } else { \ - pipe_config_mismatch(fastset, crtc, __stringify(name), \ - "unable to verify whether state matches exactly, forcing modeset (expected %s, found %s)", \ - str_yes_no(current_config->name), \ - str_yes_no(pipe_config->name)); \ - ret = false; \ - } \ -} while (0) - #define PIPE_CONF_CHECK_P(name) do { \ if (current_config->name != pipe_config->name) { \ pipe_config_mismatch(fastset, crtc, __stringify(name), \ @@ -5216,8 +5099,8 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, #define PIPE_CONF_QUIRK(quirk) \ ((current_config->quirks | pipe_config->quirks) & (quirk)) - PIPE_CONF_CHECK_I(hw.enable); - PIPE_CONF_CHECK_I(hw.active); + PIPE_CONF_CHECK_BOOL(hw.enable); + PIPE_CONF_CHECK_BOOL(hw.active); PIPE_CONF_CHECK_I(cpu_transcoder); PIPE_CONF_CHECK_I(mst_master_transcoder); @@ -5273,8 +5156,10 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, PIPE_CONF_CHECK_BOOL(enhanced_framing); PIPE_CONF_CHECK_BOOL(fec_enable); - PIPE_CONF_CHECK_BOOL_INCOMPLETE(has_audio); - PIPE_CONF_CHECK_BUFFER(eld, MAX_ELD_BYTES); + if (!fastset) { + PIPE_CONF_CHECK_BOOL(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+ */ @@ -5424,9 +5309,9 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, PIPE_CONF_CHECK_I(dsc.config.second_line_bpg_offset); PIPE_CONF_CHECK_I(dsc.config.nsl_bpg_offset); - PIPE_CONF_CHECK_I(dsc.compression_enable); - PIPE_CONF_CHECK_I(dsc.dsc_split); - PIPE_CONF_CHECK_I(dsc.compressed_bpp); + PIPE_CONF_CHECK_BOOL(dsc.compression_enable); + PIPE_CONF_CHECK_BOOL(dsc.dsc_split); + PIPE_CONF_CHECK_I(dsc.compressed_bpp_x16); PIPE_CONF_CHECK_BOOL(splitter.enable); PIPE_CONF_CHECK_I(splitter.link_count); @@ -5444,7 +5329,6 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, #undef PIPE_CONF_CHECK_X #undef PIPE_CONF_CHECK_I #undef PIPE_CONF_CHECK_BOOL -#undef PIPE_CONF_CHECK_BOOL_INCOMPLETE #undef PIPE_CONF_CHECK_P #undef PIPE_CONF_CHECK_FLAGS #undef PIPE_CONF_CHECK_COLOR_LUT @@ -5535,6 +5419,16 @@ int intel_modeset_pipes_in_mask_early(struct intel_atomic_state *state, return 0; } +static void +intel_crtc_flag_modeset(struct intel_crtc_state *crtc_state) +{ + crtc_state->uapi.mode_changed = true; + + crtc_state->update_pipe = false; + crtc_state->update_m_n = false; + crtc_state->update_lrr = false; +} + /** * intel_modeset_all_pipes_late - force a full modeset on all pipes * @state: intel atomic state @@ -5568,9 +5462,8 @@ int intel_modeset_all_pipes_late(struct intel_atomic_state *state, if (ret) return ret; - crtc_state->update_pipe = false; - crtc_state->update_m_n = false; - crtc_state->update_lrr = false; + intel_crtc_flag_modeset(crtc_state); + crtc_state->update_planes |= crtc_state->active_planes; crtc_state->async_flip_planes = 0; crtc_state->do_async_flip = false; @@ -5683,17 +5576,17 @@ static void intel_crtc_check_fastset(const struct intel_crtc_state *old_crtc_sta else new_crtc_state->uapi.mode_changed = false; - if (intel_crtc_needs_modeset(new_crtc_state) || - intel_compare_link_m_n(&old_crtc_state->dp_m_n, + if (intel_compare_link_m_n(&old_crtc_state->dp_m_n, &new_crtc_state->dp_m_n)) new_crtc_state->update_m_n = false; - if (intel_crtc_needs_modeset(new_crtc_state) || - (old_crtc_state->hw.adjusted_mode.crtc_vtotal == new_crtc_state->hw.adjusted_mode.crtc_vtotal && + if ((old_crtc_state->hw.adjusted_mode.crtc_vtotal == new_crtc_state->hw.adjusted_mode.crtc_vtotal && old_crtc_state->hw.adjusted_mode.crtc_vblank_end == new_crtc_state->hw.adjusted_mode.crtc_vblank_end)) new_crtc_state->update_lrr = false; - if (!intel_crtc_needs_modeset(new_crtc_state)) + if (intel_crtc_needs_modeset(new_crtc_state)) + intel_crtc_flag_modeset(new_crtc_state); + else new_crtc_state->update_pipe = true; } @@ -6476,15 +6369,14 @@ int intel_atomic_check(struct drm_device *dev, if (!new_crtc_state->hw.enable || intel_crtc_needs_modeset(new_crtc_state)) continue; + if (intel_dp_mst_crtc_needs_modeset(state, crtc)) + intel_crtc_flag_modeset(new_crtc_state); + if (intel_dp_mst_is_slave_trans(new_crtc_state)) { enum transcoder master = new_crtc_state->mst_master_transcoder; - if (intel_cpu_transcoders_need_modeset(state, BIT(master))) { - new_crtc_state->uapi.mode_changed = true; - new_crtc_state->update_pipe = false; - new_crtc_state->update_m_n = false; - new_crtc_state->update_lrr = false; - } + if (intel_cpu_transcoders_need_modeset(state, BIT(master))) + intel_crtc_flag_modeset(new_crtc_state); } if (is_trans_port_sync_mode(new_crtc_state)) { @@ -6493,21 +6385,13 @@ int intel_atomic_check(struct drm_device *dev, if (new_crtc_state->master_transcoder != INVALID_TRANSCODER) trans |= BIT(new_crtc_state->master_transcoder); - if (intel_cpu_transcoders_need_modeset(state, trans)) { - new_crtc_state->uapi.mode_changed = true; - new_crtc_state->update_pipe = false; - new_crtc_state->update_m_n = false; - new_crtc_state->update_lrr = false; - } + if (intel_cpu_transcoders_need_modeset(state, trans)) + intel_crtc_flag_modeset(new_crtc_state); } if (new_crtc_state->bigjoiner_pipes) { - if (intel_pipes_need_modeset(state, new_crtc_state->bigjoiner_pipes)) { - new_crtc_state->uapi.mode_changed = true; - new_crtc_state->update_pipe = false; - new_crtc_state->update_m_n = false; - new_crtc_state->update_lrr = false; - } + if (intel_pipes_need_modeset(state, new_crtc_state->bigjoiner_pipes)) + intel_crtc_flag_modeset(new_crtc_state); } } @@ -6528,10 +6412,6 @@ int intel_atomic_check(struct drm_device *dev, goto fail; } - ret = drm_dp_mst_atomic_check(&state->base); - if (ret) - goto fail; - ret = intel_atomic_check_planes(state); if (ret) goto fail; @@ -6767,8 +6647,8 @@ static void intel_enable_crtc(struct intel_atomic_state *state, intel_crtc_enable_pipe_crc(crtc); } -static void intel_update_crtc(struct intel_atomic_state *state, - struct intel_crtc *crtc) +static void intel_pre_update_crtc(struct intel_atomic_state *state, + struct intel_crtc *crtc) { struct drm_i915_private *i915 = to_i915(state->base.dev); const struct intel_crtc_state *old_crtc_state = @@ -6810,6 +6690,15 @@ static void intel_update_crtc(struct intel_atomic_state *state, intel_color_commit_noarm(new_crtc_state); intel_crtc_planes_update_noarm(state, crtc); +} + +static void intel_update_crtc(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ + const struct intel_crtc_state *old_crtc_state = + intel_atomic_get_old_crtc_state(state, crtc); + struct intel_crtc_state *new_crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); /* Perform vblank evasion around commit operation */ intel_pipe_update_start(state, crtc); @@ -6838,7 +6727,7 @@ static void intel_update_crtc(struct intel_atomic_state *state, * valid pipe configuration from the BIOS we need to take care * of enabling them on the CRTC's first fastset. */ - if (intel_crtc_needs_fastset(new_crtc_state) && !modeset && + if (intel_crtc_needs_fastset(new_crtc_state) && old_crtc_state->inherited) intel_crtc_arm_fifo_underrun(crtc, new_crtc_state); } @@ -6934,6 +6823,13 @@ static void intel_commit_modeset_enables(struct intel_atomic_state *state) continue; intel_enable_crtc(state, crtc); + intel_pre_update_crtc(state, crtc); + } + + for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { + if (!new_crtc_state->hw.active) + continue; + intel_update_crtc(state, crtc); } } @@ -6971,6 +6867,15 @@ static void skl_commit_modeset_enables(struct intel_atomic_state *state) * So first lets enable all pipes that do not need a fullmodeset as * those don't have any external dependency. */ + for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { + enum pipe pipe = crtc->pipe; + + if ((update_pipes & BIT(pipe)) == 0) + continue; + + intel_pre_update_crtc(state, crtc); + } + while (update_pipes) { for_each_oldnew_intel_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { @@ -7041,6 +6946,15 @@ static void skl_commit_modeset_enables(struct intel_atomic_state *state) /* * Finally we do the plane updates/etc. for all pipes that got enabled. */ + for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { + enum pipe pipe = crtc->pipe; + + if ((update_pipes & BIT(pipe)) == 0) + continue; + + intel_pre_update_crtc(state, crtc); + } + for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) { enum pipe pipe = crtc->pipe; @@ -7060,49 +6974,24 @@ static void skl_commit_modeset_enables(struct intel_atomic_state *state) drm_WARN_ON(&dev_priv->drm, update_pipes); } -static void intel_atomic_helper_free_state(struct drm_i915_private *dev_priv) -{ - struct intel_atomic_state *state, *next; - struct llist_node *freed; - - freed = llist_del_all(&dev_priv->display.atomic_helper.free_list); - llist_for_each_entry_safe(state, next, freed, freed) - drm_atomic_state_put(&state->base); -} - -void intel_atomic_helper_free_state_worker(struct work_struct *work) -{ - struct drm_i915_private *dev_priv = - container_of(work, typeof(*dev_priv), display.atomic_helper.free_work); - - intel_atomic_helper_free_state(dev_priv); -} - static void intel_atomic_commit_fence_wait(struct intel_atomic_state *intel_state) { - struct wait_queue_entry wait_fence, wait_reset; - struct drm_i915_private *dev_priv = to_i915(intel_state->base.dev); - - init_wait_entry(&wait_fence, 0); - init_wait_entry(&wait_reset, 0); - for (;;) { - prepare_to_wait(&intel_state->commit_ready.wait, - &wait_fence, TASK_UNINTERRUPTIBLE); - prepare_to_wait(bit_waitqueue(&to_gt(dev_priv)->reset.flags, - I915_RESET_MODESET), - &wait_reset, TASK_UNINTERRUPTIBLE); - + struct drm_i915_private *i915 = to_i915(intel_state->base.dev); + struct drm_plane *plane; + struct drm_plane_state *new_plane_state; + int ret, i; - if (i915_sw_fence_done(&intel_state->commit_ready) || - test_bit(I915_RESET_MODESET, &to_gt(dev_priv)->reset.flags)) - break; + for_each_new_plane_in_state(&intel_state->base, plane, new_plane_state, i) { + if (new_plane_state->fence) { + ret = dma_fence_wait_timeout(new_plane_state->fence, false, + i915_fence_timeout(i915)); + if (ret <= 0) + break; - schedule(); + dma_fence_put(new_plane_state->fence); + new_plane_state->fence = NULL; + } } - finish_wait(&intel_state->commit_ready.wait, &wait_fence); - finish_wait(bit_waitqueue(&to_gt(dev_priv)->reset.flags, - I915_RESET_MODESET), - &wait_reset); } static void intel_atomic_cleanup_work(struct work_struct *work) @@ -7120,8 +7009,6 @@ static void intel_atomic_cleanup_work(struct work_struct *work) drm_atomic_helper_cleanup_planes(&i915->drm, &state->base); drm_atomic_helper_commit_cleanup_done(&state->base); drm_atomic_state_put(&state->base); - - intel_atomic_helper_free_state(i915); } static void intel_atomic_prepare_plane_clear_colors(struct intel_atomic_state *state) @@ -7394,32 +7281,6 @@ static void intel_atomic_commit_work(struct work_struct *work) intel_atomic_commit_tail(state); } -static int -intel_atomic_commit_ready(struct i915_sw_fence *fence, - enum i915_sw_fence_notify notify) -{ - struct intel_atomic_state *state = - container_of(fence, struct intel_atomic_state, commit_ready); - - switch (notify) { - case FENCE_COMPLETE: - /* we do blocking waits in the worker, nothing to do here */ - break; - case FENCE_FREE: - { - struct drm_i915_private *i915 = to_i915(state->base.dev); - struct intel_atomic_helper *helper = - &i915->display.atomic_helper; - - if (llist_add(&state->freed, &helper->free_list)) - queue_work(i915->unordered_wq, &helper->free_work); - break; - } - } - - return NOTIFY_DONE; -} - static void intel_atomic_track_fbs(struct intel_atomic_state *state) { struct intel_plane_state *old_plane_state, *new_plane_state; @@ -7442,10 +7303,6 @@ int intel_atomic_commit(struct drm_device *dev, struct drm_atomic_state *_state, state->wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm); - drm_atomic_state_get(&state->base); - i915_sw_fence_init(&state->commit_ready, - intel_atomic_commit_ready); - /* * The intel_legacy_cursor_update() fast path takes care * of avoiding the vblank waits for simple cursor @@ -7478,7 +7335,6 @@ int intel_atomic_commit(struct drm_device *dev, struct drm_atomic_state *_state, if (ret) { drm_dbg_atomic(&dev_priv->drm, "Preparing state failed with %i\n", ret); - i915_sw_fence_commit(&state->commit_ready); intel_runtime_pm_put(&dev_priv->runtime_pm, state->wakeref); return ret; } @@ -7494,8 +7350,6 @@ int intel_atomic_commit(struct drm_device *dev, struct drm_atomic_state *_state, struct intel_crtc *crtc; int i; - i915_sw_fence_commit(&state->commit_ready); - for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) intel_color_cleanup_commit(new_crtc_state); @@ -7509,7 +7363,6 @@ int intel_atomic_commit(struct drm_device *dev, struct drm_atomic_state *_state, drm_atomic_state_get(&state->base); INIT_WORK(&state->base.commit_work, intel_atomic_commit_work); - i915_sw_fence_commit(&state->commit_ready); if (nonblock && state->modeset) { queue_work(dev_priv->display.wq.modeset, &state->base.commit_work); } else if (nonblock) { @@ -7909,7 +7762,7 @@ enum drm_mode_status intel_cpu_transcoder_mode_valid(struct drm_i915_private *de * Cantiga+ cannot handle modes with a hsync front porch of 0. * WaPruneModeWithIncorrectHsyncOffset:ctg,elk,ilk,snb,ivb,vlv,hsw. */ - if ((DISPLAY_VER(dev_priv) > 4 || IS_G4X(dev_priv)) && + if ((DISPLAY_VER(dev_priv) >= 5 || IS_G4X(dev_priv)) && mode->hsync_start == mode->hdisplay) return MODE_H_ILLEGAL; diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index a05c7e2b782eac..f4a0773f0fca8d 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -105,7 +105,6 @@ enum i9xx_plane_id { }; #define plane_name(p) ((p) + 'A') -#define sprite_name(p, s) ((p) * DISPLAY_RUNTIME_INFO(dev_priv)->num_sprites[(p)] + (s) + 'A') #define for_each_plane_id_on_crtc(__crtc, __p) \ for ((__p) = PLANE_PRIMARY; (__p) < I915_MAX_PLANES; (__p)++) \ @@ -395,8 +394,8 @@ u8 intel_calc_active_pipes(struct intel_atomic_state *state, u8 active_pipes); void intel_link_compute_m_n(u16 bpp, int nlanes, int pixel_clock, int link_clock, - struct intel_link_m_n *m_n, - bool fec_enable); + int bw_overhead, + struct intel_link_m_n *m_n); u32 intel_plane_fb_max_stride(struct drm_i915_private *dev_priv, u32 pixel_format, u64 modifier); enum drm_mode_status @@ -485,8 +484,6 @@ void intel_cpu_transcoder_get_m1_n1(struct intel_crtc *crtc, void intel_cpu_transcoder_get_m2_n2(struct intel_crtc *crtc, enum transcoder cpu_transcoder, struct intel_link_m_n *m_n); -void i9xx_crtc_clock_get(struct intel_crtc *crtc, - struct intel_crtc_state *pipe_config); int intel_dotclock_calculate(int link_freq, const struct intel_link_m_n *m_n); int intel_crtc_dotclock(const struct intel_crtc_state *pipe_config); enum intel_display_power_domain intel_port_to_power_domain(struct intel_digital_port *dig_port); @@ -555,7 +552,7 @@ bool assert_port_valid(struct drm_i915_private *i915, enum port port); struct drm_device *drm = &(__i915)->drm; \ int __ret_warn_on = !!(condition); \ if (unlikely(__ret_warn_on)) \ - if (!drm_WARN(drm, i915_modparams.verbose_state_checks, format)) \ + if (!drm_WARN(drm, __i915->display.params.verbose_state_checks, format)) \ drm_err(drm, format); \ unlikely(__ret_warn_on); \ }) diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h index ccfe27630fb661..47297ed8582237 100644 --- a/drivers/gpu/drm/i915/display/intel_display_core.h +++ b/drivers/gpu/drm/i915/display/intel_display_core.h @@ -19,6 +19,7 @@ #include "intel_cdclk.h" #include "intel_display_device.h" #include "intel_display_limits.h" +#include "intel_display_params.h" #include "intel_display_power.h" #include "intel_dpll_mgr.h" #include "intel_fbc.h" @@ -297,12 +298,6 @@ struct intel_display { const struct intel_audio_funcs *audio; } funcs; - /* Grouping using anonymous structs. Keep sorted. */ - struct intel_atomic_helper { - struct llist_head free_list; - struct work_struct free_work; - } atomic_helper; - struct { /* backlight registers and fields in struct intel_panel */ struct mutex lock; @@ -347,15 +342,6 @@ struct intel_display { struct intel_global_obj obj; } dbuf; - struct { - wait_queue_head_t waitqueue; - - /* mutex to protect pmdemand programming sequence */ - struct mutex lock; - - struct intel_global_obj obj; - } pmdemand; - struct { /* * dkl.phy_lock protects against concurrent access of the @@ -443,6 +429,15 @@ struct intel_display { bool false_color; } ips; + struct { + wait_queue_head_t waitqueue; + + /* mutex to protect pmdemand programming sequence */ + struct mutex lock; + + struct intel_global_obj obj; + } pmdemand; + struct { struct i915_power_domains domains; @@ -520,6 +515,7 @@ struct intel_display { struct intel_hotplug hotplug; struct intel_opregion opregion; struct intel_overlay *overlay; + struct intel_display_params params; struct intel_vbt_data vbt; struct intel_wm wm; }; diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index 2836826f8c05fc..d951edb3668714 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -17,6 +17,7 @@ #include "intel_de.h" #include "intel_crtc_state_dump.h" #include "intel_display_debugfs.h" +#include "intel_display_debugfs_params.h" #include "intel_display_power.h" #include "intel_display_power_well.h" #include "intel_display_types.h" @@ -641,6 +642,17 @@ static int i915_display_info(struct seq_file *m, void *unused) return 0; } +static int i915_display_capabilities(struct seq_file *m, void *unused) +{ + struct drm_i915_private *i915 = node_to_i915(m->private); + struct drm_printer p = drm_seq_file_printer(m); + + intel_display_device_info_print(DISPLAY_INFO(i915), + DISPLAY_RUNTIME_INFO(i915), &p); + + return 0; +} + static int i915_shared_dplls_info(struct seq_file *m, void *unused) { struct drm_i915_private *dev_priv = node_to_i915(m->private); @@ -1059,6 +1071,7 @@ static const struct drm_info_list intel_display_debugfs_list[] = { {"i915_gem_framebuffer", i915_gem_framebuffer_info, 0}, {"i915_power_domain_info", i915_power_domain_info, 0}, {"i915_display_info", i915_display_info, 0}, + {"i915_display_capabilities", i915_display_capabilities, 0}, {"i915_shared_dplls_info", i915_shared_dplls_info, 0}, {"i915_dp_mst_info", i915_dp_mst_info, 0}, {"i915_ddb_info", i915_ddb_info, 0}, @@ -1082,7 +1095,7 @@ void intel_display_debugfs_register(struct drm_i915_private *i915) for (i = 0; i < ARRAY_SIZE(intel_display_debugfs_files); i++) { debugfs_create_file(intel_display_debugfs_files[i].name, - S_IRUGO | S_IWUSR, + 0644, minor->debugfs_root, to_i915(minor->dev), intel_display_debugfs_files[i].fops); @@ -1098,15 +1111,15 @@ void intel_display_debugfs_register(struct drm_i915_private *i915) intel_hpd_debugfs_register(i915); intel_psr_debugfs_register(i915); intel_wm_debugfs_register(i915); + intel_display_debugfs_params(i915); } static int i915_panel_show(struct seq_file *m, void *data) { - struct drm_connector *connector = m->private; - struct intel_dp *intel_dp = - intel_attached_dp(to_intel_connector(connector)); + struct intel_connector *connector = m->private; + struct intel_dp *intel_dp = intel_attached_dp(connector); - if (connector->status != connector_status_connected) + if (connector->base.status != connector_status_connected) return -ENODEV; seq_printf(m, "Panel power up delay: %d\n", @@ -1124,23 +1137,23 @@ DEFINE_SHOW_ATTRIBUTE(i915_panel); static int i915_hdcp_sink_capability_show(struct seq_file *m, void *data) { - struct drm_connector *connector = m->private; - struct drm_i915_private *i915 = to_i915(connector->dev); - struct intel_connector *intel_connector = to_intel_connector(connector); + struct intel_connector *connector = m->private; + struct drm_i915_private *i915 = to_i915(connector->base.dev); int ret; ret = drm_modeset_lock_single_interruptible(&i915->drm.mode_config.connection_mutex); if (ret) return ret; - if (!connector->encoder || connector->status != connector_status_connected) { + if (!connector->base.encoder || + connector->base.status != connector_status_connected) { ret = -ENODEV; goto out; } - seq_printf(m, "%s:%d HDCP version: ", connector->name, - connector->base.id); - intel_hdcp_info(m, intel_connector); + seq_printf(m, "%s:%d HDCP version: ", connector->base.name, + connector->base.base.id); + intel_hdcp_info(m, connector); out: drm_modeset_unlock(&i915->drm.mode_config.connection_mutex); @@ -1151,16 +1164,16 @@ DEFINE_SHOW_ATTRIBUTE(i915_hdcp_sink_capability); static int i915_lpsp_capability_show(struct seq_file *m, void *data) { - struct drm_connector *connector = m->private; - struct drm_i915_private *i915 = to_i915(connector->dev); - struct intel_encoder *encoder; + struct intel_connector *connector = m->private; + struct drm_i915_private *i915 = to_i915(connector->base.dev); + struct intel_encoder *encoder = intel_attached_encoder(connector); + int connector_type = connector->base.connector_type; bool lpsp_capable = false; - encoder = intel_attached_encoder(to_intel_connector(connector)); if (!encoder) return -ENODEV; - if (connector->status != connector_status_connected) + if (connector->base.status != connector_status_connected) return -ENODEV; if (DISPLAY_VER(i915) >= 13) @@ -1173,15 +1186,15 @@ static int i915_lpsp_capability_show(struct seq_file *m, void *data) */ lpsp_capable = encoder->port <= PORT_B; else if (DISPLAY_VER(i915) == 11) - lpsp_capable = (connector->connector_type == DRM_MODE_CONNECTOR_DSI || - connector->connector_type == DRM_MODE_CONNECTOR_eDP); + lpsp_capable = (connector_type == DRM_MODE_CONNECTOR_DSI || + connector_type == DRM_MODE_CONNECTOR_eDP); else if (IS_DISPLAY_VER(i915, 9, 10)) lpsp_capable = (encoder->port == PORT_A && - (connector->connector_type == DRM_MODE_CONNECTOR_DSI || - connector->connector_type == DRM_MODE_CONNECTOR_eDP || - connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort)); + (connector_type == DRM_MODE_CONNECTOR_DSI || + connector_type == DRM_MODE_CONNECTOR_eDP || + connector_type == DRM_MODE_CONNECTOR_DisplayPort)); else if (IS_HASWELL(i915) || IS_BROADWELL(i915)) - lpsp_capable = connector->connector_type == DRM_MODE_CONNECTOR_eDP; + lpsp_capable = connector_type == DRM_MODE_CONNECTOR_eDP; seq_printf(m, "LPSP: %s\n", lpsp_capable ? "capable" : "incapable"); @@ -1191,7 +1204,7 @@ DEFINE_SHOW_ATTRIBUTE(i915_lpsp_capability); static int i915_dsc_fec_support_show(struct seq_file *m, void *data) { - struct intel_connector *connector = to_intel_connector(m->private); + struct intel_connector *connector = m->private; struct drm_i915_private *i915 = to_i915(connector->base.dev); struct drm_crtc *crtc; struct intel_dp *intel_dp; @@ -1242,6 +1255,8 @@ static int i915_dsc_fec_support_show(struct seq_file *m, void *data) DP_DSC_YCbCr420_Native)), str_yes_no(drm_dp_dsc_sink_supports_format(connector->dp.dsc_dpcd, DP_DSC_YCbCr444))); + seq_printf(m, "DSC_Sink_BPP_Precision: %d\n", + drm_dp_dsc_sink_bpp_incr(connector->dp.dsc_dpcd)); seq_printf(m, "Force_DSC_Enable: %s\n", str_yes_no(intel_dp->force_dsc_en)); if (!intel_dp_is_edp(intel_dp)) @@ -1259,13 +1274,13 @@ static ssize_t i915_dsc_fec_support_write(struct file *file, const char __user *ubuf, size_t len, loff_t *offp) { + struct seq_file *m = file->private_data; + struct intel_connector *connector = m->private; + struct drm_i915_private *i915 = to_i915(connector->base.dev); + struct intel_encoder *encoder = intel_attached_encoder(connector); + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); bool dsc_enable = false; int ret; - struct drm_connector *connector = - ((struct seq_file *)file->private_data)->private; - struct intel_encoder *encoder = intel_attached_encoder(to_intel_connector(connector)); - struct drm_i915_private *i915 = to_i915(encoder->base.dev); - struct intel_dp *intel_dp = enc_to_intel_dp(encoder); if (len == 0) return 0; @@ -1303,22 +1318,22 @@ static const struct file_operations i915_dsc_fec_support_fops = { static int i915_dsc_bpc_show(struct seq_file *m, void *data) { - struct drm_connector *connector = m->private; - struct drm_device *dev = connector->dev; + struct intel_connector *connector = m->private; + struct drm_i915_private *i915 = to_i915(connector->base.dev); + struct intel_encoder *encoder = intel_attached_encoder(connector); struct drm_crtc *crtc; struct intel_crtc_state *crtc_state; - struct intel_encoder *encoder = intel_attached_encoder(to_intel_connector(connector)); int ret; if (!encoder) return -ENODEV; - ret = drm_modeset_lock_single_interruptible(&dev->mode_config.connection_mutex); + ret = drm_modeset_lock_single_interruptible(&i915->drm.mode_config.connection_mutex); if (ret) return ret; - crtc = connector->state->crtc; - if (connector->status != connector_status_connected || !crtc) { + crtc = connector->base.state->crtc; + if (connector->base.status != connector_status_connected || !crtc) { ret = -ENODEV; goto out; } @@ -1326,7 +1341,7 @@ static int i915_dsc_bpc_show(struct seq_file *m, void *data) crtc_state = to_intel_crtc_state(crtc->state); seq_printf(m, "Input_BPC: %d\n", crtc_state->dsc.config.bits_per_component); -out: drm_modeset_unlock(&dev->mode_config.connection_mutex); +out: drm_modeset_unlock(&i915->drm.mode_config.connection_mutex); return ret; } @@ -1335,9 +1350,9 @@ static ssize_t i915_dsc_bpc_write(struct file *file, const char __user *ubuf, size_t len, loff_t *offp) { - struct drm_connector *connector = - ((struct seq_file *)file->private_data)->private; - struct intel_encoder *encoder = intel_attached_encoder(to_intel_connector(connector)); + struct seq_file *m = file->private_data; + struct intel_connector *connector = m->private; + struct intel_encoder *encoder = intel_attached_encoder(connector); struct intel_dp *intel_dp = enc_to_intel_dp(encoder); int dsc_bpc = 0; int ret; @@ -1369,22 +1384,22 @@ static const struct file_operations i915_dsc_bpc_fops = { static int i915_dsc_output_format_show(struct seq_file *m, void *data) { - struct drm_connector *connector = m->private; - struct drm_device *dev = connector->dev; + struct intel_connector *connector = m->private; + struct drm_i915_private *i915 = to_i915(connector->base.dev); + struct intel_encoder *encoder = intel_attached_encoder(connector); struct drm_crtc *crtc; struct intel_crtc_state *crtc_state; - struct intel_encoder *encoder = intel_attached_encoder(to_intel_connector(connector)); int ret; if (!encoder) return -ENODEV; - ret = drm_modeset_lock_single_interruptible(&dev->mode_config.connection_mutex); + ret = drm_modeset_lock_single_interruptible(&i915->drm.mode_config.connection_mutex); if (ret) return ret; - crtc = connector->state->crtc; - if (connector->status != connector_status_connected || !crtc) { + crtc = connector->base.state->crtc; + if (connector->base.status != connector_status_connected || !crtc) { ret = -ENODEV; goto out; } @@ -1393,7 +1408,7 @@ static int i915_dsc_output_format_show(struct seq_file *m, void *data) seq_printf(m, "DSC_Output_Format: %s\n", intel_output_format_name(crtc_state->output_format)); -out: drm_modeset_unlock(&dev->mode_config.connection_mutex); +out: drm_modeset_unlock(&i915->drm.mode_config.connection_mutex); return ret; } @@ -1402,9 +1417,9 @@ static ssize_t i915_dsc_output_format_write(struct file *file, const char __user *ubuf, size_t len, loff_t *offp) { - struct drm_connector *connector = - ((struct seq_file *)file->private_data)->private; - struct intel_encoder *encoder = intel_attached_encoder(to_intel_connector(connector)); + struct seq_file *m = file->private_data; + struct intel_connector *connector = m->private; + struct intel_encoder *encoder = intel_attached_encoder(connector); struct intel_dp *intel_dp = enc_to_intel_dp(encoder); int dsc_output_format = 0; int ret; @@ -1434,6 +1449,84 @@ static const struct file_operations i915_dsc_output_format_fops = { .write = i915_dsc_output_format_write }; +static int i915_dsc_fractional_bpp_show(struct seq_file *m, void *data) +{ + struct intel_connector *connector = m->private; + struct drm_i915_private *i915 = to_i915(connector->base.dev); + struct intel_encoder *encoder = intel_attached_encoder(connector); + struct drm_crtc *crtc; + struct intel_dp *intel_dp; + int ret; + + if (!encoder) + return -ENODEV; + + ret = drm_modeset_lock_single_interruptible(&i915->drm.mode_config.connection_mutex); + if (ret) + return ret; + + crtc = connector->base.state->crtc; + if (connector->base.status != connector_status_connected || !crtc) { + ret = -ENODEV; + goto out; + } + + intel_dp = intel_attached_dp(connector); + seq_printf(m, "Force_DSC_Fractional_BPP_Enable: %s\n", + str_yes_no(intel_dp->force_dsc_fractional_bpp_en)); + +out: + drm_modeset_unlock(&i915->drm.mode_config.connection_mutex); + + return ret; +} + +static ssize_t i915_dsc_fractional_bpp_write(struct file *file, + const char __user *ubuf, + size_t len, loff_t *offp) +{ + struct seq_file *m = file->private_data; + struct intel_connector *connector = m->private; + struct intel_encoder *encoder = intel_attached_encoder(connector); + struct drm_i915_private *i915 = to_i915(connector->base.dev); + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + bool dsc_fractional_bpp_enable = false; + int ret; + + if (len == 0) + return 0; + + drm_dbg(&i915->drm, + "Copied %zu bytes from user to force fractional bpp for DSC\n", len); + + ret = kstrtobool_from_user(ubuf, len, &dsc_fractional_bpp_enable); + if (ret < 0) + return ret; + + drm_dbg(&i915->drm, "Got %s for DSC Fractional BPP Enable\n", + (dsc_fractional_bpp_enable) ? "true" : "false"); + intel_dp->force_dsc_fractional_bpp_en = dsc_fractional_bpp_enable; + + *offp += len; + + return len; +} + +static int i915_dsc_fractional_bpp_open(struct inode *inode, + struct file *file) +{ + return single_open(file, i915_dsc_fractional_bpp_show, inode->i_private); +} + +static const struct file_operations i915_dsc_fractional_bpp_fops = { + .owner = THIS_MODULE, + .open = i915_dsc_fractional_bpp_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = i915_dsc_fractional_bpp_write +}; + /* * Returns the Current CRTC's bpc. * Example usage: cat /sys/kernel/debug/dri/0/crtc-0/i915_current_bpc @@ -1470,39 +1563,38 @@ DEFINE_SHOW_ATTRIBUTE(intel_crtc_pipe); /** * intel_connector_debugfs_add - add i915 specific connector debugfs files - * @intel_connector: pointer to a registered drm_connector + * @connector: pointer to a registered intel_connector * * Cleanup will be done by drm_connector_unregister() through a call to * drm_debugfs_connector_remove(). */ -void intel_connector_debugfs_add(struct intel_connector *intel_connector) +void intel_connector_debugfs_add(struct intel_connector *connector) { - struct drm_connector *connector = &intel_connector->base; - struct dentry *root = connector->debugfs_entry; - struct drm_i915_private *dev_priv = to_i915(connector->dev); + struct drm_i915_private *i915 = to_i915(connector->base.dev); + struct dentry *root = connector->base.debugfs_entry; + int connector_type = connector->base.connector_type; /* The connector must have been registered beforehands. */ if (!root) return; - intel_drrs_connector_debugfs_add(intel_connector); - intel_psr_connector_debugfs_add(intel_connector); + intel_drrs_connector_debugfs_add(connector); + intel_psr_connector_debugfs_add(connector); - if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) - debugfs_create_file("i915_panel_timings", S_IRUGO, root, + if (connector_type == DRM_MODE_CONNECTOR_eDP) + debugfs_create_file("i915_panel_timings", 0444, root, connector, &i915_panel_fops); - if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort || - connector->connector_type == DRM_MODE_CONNECTOR_HDMIA || - connector->connector_type == DRM_MODE_CONNECTOR_HDMIB) { - debugfs_create_file("i915_hdcp_sink_capability", S_IRUGO, root, + if (connector_type == DRM_MODE_CONNECTOR_DisplayPort || + connector_type == DRM_MODE_CONNECTOR_HDMIA || + connector_type == DRM_MODE_CONNECTOR_HDMIB) { + debugfs_create_file("i915_hdcp_sink_capability", 0444, root, connector, &i915_hdcp_sink_capability_fops); } - if (DISPLAY_VER(dev_priv) >= 11 && - ((connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort && - !to_intel_connector(connector)->mst_port) || - connector->connector_type == DRM_MODE_CONNECTOR_eDP)) { + if (DISPLAY_VER(i915) >= 11 && + ((connector_type == DRM_MODE_CONNECTOR_DisplayPort && !connector->mst_port) || + connector_type == DRM_MODE_CONNECTOR_eDP)) { debugfs_create_file("i915_dsc_fec_support", 0644, root, connector, &i915_dsc_fec_support_fops); @@ -1511,13 +1603,16 @@ void intel_connector_debugfs_add(struct intel_connector *intel_connector) debugfs_create_file("i915_dsc_output_format", 0644, root, connector, &i915_dsc_output_format_fops); + + debugfs_create_file("i915_dsc_fractional_bpp", 0644, root, + connector, &i915_dsc_fractional_bpp_fops); } - if (connector->connector_type == DRM_MODE_CONNECTOR_DSI || - connector->connector_type == DRM_MODE_CONNECTOR_eDP || - connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort || - connector->connector_type == DRM_MODE_CONNECTOR_HDMIA || - connector->connector_type == DRM_MODE_CONNECTOR_HDMIB) + if (connector_type == DRM_MODE_CONNECTOR_DSI || + connector_type == DRM_MODE_CONNECTOR_eDP || + connector_type == DRM_MODE_CONNECTOR_DisplayPort || + connector_type == DRM_MODE_CONNECTOR_HDMIA || + connector_type == DRM_MODE_CONNECTOR_HDMIB) debugfs_create_file("i915_lpsp_capability", 0444, root, connector, &i915_lpsp_capability_fops); } diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs_params.c b/drivers/gpu/drm/i915/display/intel_display_debugfs_params.c new file mode 100644 index 00000000000000..b7e68eb6245225 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs_params.c @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2023 Intel Corporation + */ + +#include + +#include + +#include "intel_display_debugfs_params.h" +#include "i915_drv.h" +#include "intel_display_params.h" + +/* int param */ +static int intel_display_param_int_show(struct seq_file *m, void *data) +{ + int *value = m->private; + + seq_printf(m, "%d\n", *value); + + return 0; +} + +static int intel_display_param_int_open(struct inode *inode, struct file *file) +{ + return single_open(file, intel_display_param_int_show, inode->i_private); +} + +static ssize_t intel_display_param_int_write(struct file *file, + const char __user *ubuf, size_t len, + loff_t *offp) +{ + struct seq_file *m = file->private_data; + int *value = m->private; + int ret; + + ret = kstrtoint_from_user(ubuf, len, 0, value); + if (ret) { + /* support boolean values too */ + bool b; + + ret = kstrtobool_from_user(ubuf, len, &b); + if (!ret) + *value = b; + } + + return ret ?: len; +} + +static const struct file_operations intel_display_param_int_fops = { + .owner = THIS_MODULE, + .open = intel_display_param_int_open, + .read = seq_read, + .write = intel_display_param_int_write, + .llseek = default_llseek, + .release = single_release, +}; + +static const struct file_operations intel_display_param_int_fops_ro = { + .owner = THIS_MODULE, + .open = intel_display_param_int_open, + .read = seq_read, + .llseek = default_llseek, + .release = single_release, +}; + +/* unsigned int param */ +static int intel_display_param_uint_show(struct seq_file *m, void *data) +{ + unsigned int *value = m->private; + + seq_printf(m, "%u\n", *value); + + return 0; +} + +static int intel_display_param_uint_open(struct inode *inode, struct file *file) +{ + return single_open(file, intel_display_param_uint_show, inode->i_private); +} + +static ssize_t intel_display_param_uint_write(struct file *file, + const char __user *ubuf, size_t len, + loff_t *offp) +{ + struct seq_file *m = file->private_data; + unsigned int *value = m->private; + int ret; + + ret = kstrtouint_from_user(ubuf, len, 0, value); + if (ret) { + /* support boolean values too */ + bool b; + + ret = kstrtobool_from_user(ubuf, len, &b); + if (!ret) + *value = b; + } + + return ret ?: len; +} + +static const struct file_operations intel_display_param_uint_fops = { + .owner = THIS_MODULE, + .open = intel_display_param_uint_open, + .read = seq_read, + .write = intel_display_param_uint_write, + .llseek = default_llseek, + .release = single_release, +}; + +static const struct file_operations intel_display_param_uint_fops_ro = { + .owner = THIS_MODULE, + .open = intel_display_param_uint_open, + .read = seq_read, + .llseek = default_llseek, + .release = single_release, +}; + +#define RO(mode) (((mode) & 0222) == 0) + +__maybe_unused static struct dentry * +intel_display_debugfs_create_int(const char *name, umode_t mode, + struct dentry *parent, int *value) +{ + return debugfs_create_file_unsafe(name, mode, parent, value, + RO(mode) ? &intel_display_param_int_fops_ro : + &intel_display_param_int_fops); +} + +__maybe_unused static struct dentry * +intel_display_debugfs_create_uint(const char *name, umode_t mode, + struct dentry *parent, unsigned int *value) +{ + return debugfs_create_file_unsafe(name, mode, parent, value, + RO(mode) ? &intel_display_param_uint_fops_ro : + &intel_display_param_uint_fops); +} + +#define _intel_display_param_create_file(parent, name, mode, valp) \ + do { \ + if (mode) \ + _Generic(valp, \ + bool * : debugfs_create_bool, \ + int * : intel_display_debugfs_create_int, \ + unsigned int * : intel_display_debugfs_create_uint, \ + unsigned long * : debugfs_create_ulong, \ + char ** : debugfs_create_str) \ + (name, mode, parent, valp); \ + } while (0) + +/* add a subdirectory with files for each intel display param */ +void intel_display_debugfs_params(struct drm_i915_private *i915) +{ + struct drm_minor *minor = i915->drm.primary; + struct dentry *dir; + char dirname[16]; + + snprintf(dirname, sizeof(dirname), "%s_params", i915->drm.driver->name); + dir = debugfs_lookup(dirname, minor->debugfs_root); + if (!dir) + dir = debugfs_create_dir(dirname, minor->debugfs_root); + if (IS_ERR(dir)) + return; + + /* + * Note: We could create files for params needing special handling + * here. Set mode in params to 0 to skip the generic create file, or + * just let the generic create file fail silently with -EEXIST. + */ + +#define REGISTER(T, x, unused, mode, ...) _intel_display_param_create_file( \ + dir, #x, mode, &i915->display.params.x); + INTEL_DISPLAY_PARAMS_FOR_EACH(REGISTER); +#undef REGISTER +} diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs_params.h b/drivers/gpu/drm/i915/display/intel_display_debugfs_params.h new file mode 100644 index 00000000000000..1e9945a4044c07 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs_params.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef __INTEL_DISPLAY_DEBUGFS_PARAMS__ +#define __INTEL_DISPLAY_DEBUGFS_PARAMS__ + +struct drm_i915_private; + +void intel_display_debugfs_params(struct drm_i915_private *i915); + +#endif /* __INTEL_DISPLAY_DEBUGFS_PARAMS__ */ diff --git a/drivers/gpu/drm/i915/display/intel_display_device.c b/drivers/gpu/drm/i915/display/intel_display_device.c index 2b1ec23ba9c33f..0b522c6a8d6f5f 100644 --- a/drivers/gpu/drm/i915/display/intel_display_device.c +++ b/drivers/gpu/drm/i915/display/intel_display_device.c @@ -12,6 +12,7 @@ #include "intel_de.h" #include "intel_display.h" #include "intel_display_device.h" +#include "intel_display_params.h" #include "intel_display_power.h" #include "intel_display_reg_defs.h" #include "intel_fbc.h" @@ -937,6 +938,13 @@ void intel_display_device_probe(struct drm_i915_private *i915) DISPLAY_RUNTIME_INFO(i915)->ip.rel = rel; DISPLAY_RUNTIME_INFO(i915)->ip.step = step; } + + intel_display_params_copy(&i915->display.params); +} + +void intel_display_device_remove(struct drm_i915_private *i915) +{ + intel_display_params_free(&i915->display.params); } static void __intel_display_device_info_runtime_init(struct drm_i915_private *i915) @@ -1105,7 +1113,7 @@ void intel_display_device_info_runtime_init(struct drm_i915_private *i915) } /* Disable nuclear pageflip by default on pre-g4x */ - if (!i915->params.nuclear_pageflip && + if (!i915->display.params.nuclear_pageflip && DISPLAY_VER(i915) < 5 && !IS_G4X(i915)) i915->drm.driver_features &= ~DRIVER_ATOMIC; } @@ -1145,5 +1153,6 @@ bool intel_display_device_enabled(struct drm_i915_private *i915) /* Only valid when HAS_DISPLAY() is true */ drm_WARN_ON(&i915->drm, !HAS_DISPLAY(i915)); - return !i915->params.disable_display && !intel_opregion_headless_sku(i915); + return !i915->display.params.disable_display && + !intel_opregion_headless_sku(i915); } diff --git a/drivers/gpu/drm/i915/display/intel_display_device.h b/drivers/gpu/drm/i915/display/intel_display_device.h index 5b5c0e53307fa5..fe42688137863c 100644 --- a/drivers/gpu/drm/i915/display/intel_display_device.h +++ b/drivers/gpu/drm/i915/display/intel_display_device.h @@ -36,7 +36,7 @@ struct drm_printer; #define HAS_ASYNC_FLIPS(i915) (DISPLAY_VER(i915) >= 5) #define HAS_CDCLK_CRAWL(i915) (DISPLAY_INFO(i915)->has_cdclk_crawl) #define HAS_CDCLK_SQUASH(i915) (DISPLAY_INFO(i915)->has_cdclk_squash) -#define HAS_CUR_FBC(i915) (!HAS_GMCH(i915) && DISPLAY_VER(i915) >= 7) +#define HAS_CUR_FBC(i915) (!HAS_GMCH(i915) && IS_DISPLAY_VER(i915, 7, 13)) #define HAS_D12_PLANE_MINIMIZATION(i915) (IS_ROCKETLAKE(i915) || IS_ALDERLAKE_S(i915)) #define HAS_DDI(i915) (DISPLAY_INFO(i915)->has_ddi) #define HAS_DISPLAY(i915) (DISPLAY_RUNTIME_INFO(i915)->pipe_mask != 0) @@ -49,7 +49,7 @@ struct drm_printer; #define HAS_DSC(__i915) (DISPLAY_RUNTIME_INFO(__i915)->has_dsc) #define HAS_FBC(i915) (DISPLAY_RUNTIME_INFO(i915)->fbc_mask != 0) #define HAS_FPGA_DBG_UNCLAIMED(i915) (DISPLAY_INFO(i915)->has_fpga_dbg) -#define HAS_FW_BLC(i915) (DISPLAY_VER(i915) > 2) +#define HAS_FW_BLC(i915) (DISPLAY_VER(i915) >= 3) #define HAS_GMBUS_IRQ(i915) (DISPLAY_VER(i915) >= 4) #define HAS_GMBUS_BURST_READ(i915) (DISPLAY_VER(i915) >= 10 || IS_KABYLAKE(i915)) #define HAS_GMCH(i915) (DISPLAY_INFO(i915)->has_gmch) @@ -161,6 +161,7 @@ struct intel_display_device_info { bool intel_display_device_enabled(struct drm_i915_private *i915); void intel_display_device_probe(struct drm_i915_private *i915); +void intel_display_device_remove(struct drm_i915_private *i915); void intel_display_device_info_runtime_init(struct drm_i915_private *i915); void intel_display_device_info_print(const struct intel_display_device_info *info, diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.c b/drivers/gpu/drm/i915/display/intel_display_driver.c index 44b59ac301e690..9df9097a0255af 100644 --- a/drivers/gpu/drm/i915/display/intel_display_driver.c +++ b/drivers/gpu/drm/i915/display/intel_display_driver.c @@ -181,6 +181,13 @@ void intel_display_driver_early_probe(struct drm_i915_private *i915) if (!HAS_DISPLAY(i915)) return; + spin_lock_init(&i915->display.fb_tracking.lock); + mutex_init(&i915->display.backlight.lock); + mutex_init(&i915->display.audio.mutex); + mutex_init(&i915->display.wm.wm_mutex); + mutex_init(&i915->display.pps.mutex); + mutex_init(&i915->display.hdcp.hdcp_mutex); + intel_display_irq_init(i915); intel_dkl_phy_init(i915); intel_color_init_hooks(i915); @@ -252,10 +259,6 @@ int intel_display_driver_probe_noirq(struct drm_i915_private *i915) if (ret) goto cleanup_vga_client_pw_domain_dmc; - init_llist_head(&i915->display.atomic_helper.free_list); - INIT_WORK(&i915->display.atomic_helper.free_work, - intel_atomic_helper_free_state_worker); - intel_init_quirks(i915); intel_fbc_init(i915); @@ -423,9 +426,6 @@ void intel_display_driver_remove(struct drm_i915_private *i915) flush_workqueue(i915->display.wq.flip); flush_workqueue(i915->display.wq.modeset); - flush_work(&i915->display.atomic_helper.free_work); - drm_WARN_ON(&i915->drm, !llist_empty(&i915->display.atomic_helper.free_list)); - /* * MST topology needs to be suspended so we don't have any calls to * fbdev after it's finalized. MST will be destroyed later as part of diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.c b/drivers/gpu/drm/i915/display/intel_display_irq.c index bff4a76310c0e9..a7d8f3fc98de91 100644 --- a/drivers/gpu/drm/i915/display/intel_display_irq.c +++ b/drivers/gpu/drm/i915/display/intel_display_irq.c @@ -340,18 +340,15 @@ static void flip_done_handler(struct drm_i915_private *i915, enum pipe pipe) { struct intel_crtc *crtc = intel_crtc_for_pipe(i915, pipe); - struct drm_crtc_state *crtc_state = crtc->base.state; - struct drm_pending_vblank_event *e = crtc_state->event; - struct drm_device *dev = &i915->drm; - unsigned long irqflags; - - spin_lock_irqsave(&dev->event_lock, irqflags); - crtc_state->event = NULL; + spin_lock(&i915->drm.event_lock); - drm_crtc_send_vblank_event(&crtc->base, e); + if (crtc->flip_done_event) { + drm_crtc_send_vblank_event(&crtc->base, crtc->flip_done_event); + crtc->flip_done_event = NULL; + } - spin_unlock_irqrestore(&dev->event_lock, irqflags); + spin_unlock(&i915->drm.event_lock); } static void hsw_pipe_crc_irq_handler(struct drm_i915_private *dev_priv, @@ -896,7 +893,7 @@ gen8_de_misc_irq_handler(struct drm_i915_private *dev_priv, u32 iir) } if (!found) - drm_err(&dev_priv->drm, "Unexpected DE Misc interrupt\n"); + drm_err(&dev_priv->drm, "Unexpected DE Misc interrupt: 0x%08x\n", iir); } static void gen11_dsi_te_interrupt_handler(struct drm_i915_private *dev_priv, @@ -1653,7 +1650,7 @@ void gen8_de_irq_postinstall(struct drm_i915_private *dev_priv) else if (HAS_PCH_SPLIT(dev_priv)) ibx_irq_postinstall(dev_priv); - if (DISPLAY_VER(dev_priv) <= 10) + if (DISPLAY_VER(dev_priv) < 11) de_misc_masked |= GEN8_DE_MISC_GSE; if (IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv)) diff --git a/drivers/gpu/drm/i915/display/intel_display_params.c b/drivers/gpu/drm/i915/display/intel_display_params.c new file mode 100644 index 00000000000000..11e03cfb774d50 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_display_params.c @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2023 Intel Corporation + */ + +#include "intel_display_params.h" +#include "i915_drv.h" + +#define intel_display_param_named(name, T, perm, desc) \ + module_param_named(name, intel_display_modparams.name, T, perm); \ + MODULE_PARM_DESC(name, desc) +#define intel_display_param_named_unsafe(name, T, perm, desc) \ + module_param_named_unsafe(name, intel_display_modparams.name, T, perm); \ + MODULE_PARM_DESC(name, desc) + +static struct intel_display_params intel_display_modparams __read_mostly = { +#define MEMBER(T, member, value, ...) .member = (value), + INTEL_DISPLAY_PARAMS_FOR_EACH(MEMBER) +#undef MEMBER +}; +/* + * Note: As a rule, keep module parameter sysfs permissions read-only + * 0400. Runtime changes are only supported through i915 debugfs. + * + * For any exceptions requiring write access and runtime changes through module + * parameter sysfs, prevent debugfs file creation by setting the parameter's + * debugfs mode to 0. + */ + +intel_display_param_named_unsafe(vbt_firmware, charp, 0400, + "Load VBT from specified file under /lib/firmware"); + +intel_display_param_named_unsafe(lvds_channel_mode, int, 0400, + "Specify LVDS channel mode " + "(0=probe BIOS [default], 1=single-channel, 2=dual-channel)"); + +intel_display_param_named_unsafe(panel_use_ssc, int, 0400, + "Use Spread Spectrum Clock with panels [LVDS/eDP] " + "(default: auto from VBT)"); + +intel_display_param_named_unsafe(vbt_sdvo_panel_type, int, 0400, + "Override/Ignore selection of SDVO panel mode in the VBT " + "(-2=ignore, -1=auto [default], index in VBT BIOS table)"); + +intel_display_param_named_unsafe(enable_dc, int, 0400, + "Enable power-saving display C-states. " + "(-1=auto [default]; 0=disable; 1=up to DC5; 2=up to DC6; " + "3=up to DC5 with DC3CO; 4=up to DC6 with DC3CO)"); + +intel_display_param_named_unsafe(enable_dpt, bool, 0400, + "Enable display page table (DPT) (default: true)"); + +intel_display_param_named_unsafe(enable_sagv, bool, 0400, + "Enable system agent voltage/frequency scaling (SAGV) (default: true)"); + +intel_display_param_named_unsafe(disable_power_well, int, 0400, + "Disable display power wells when possible " + "(-1=auto [default], 0=power wells always on, 1=power wells disabled when possible)"); + +intel_display_param_named_unsafe(enable_ips, bool, 0400, "Enable IPS (default: true)"); + +intel_display_param_named_unsafe(invert_brightness, int, 0400, + "Invert backlight brightness " + "(-1 force normal, 0 machine defaults, 1 force inversion), please " + "report PCI device ID, subsystem vendor and subsystem device ID " + "to dri-devel@lists.freedesktop.org, if your machine needs it. " + "It will then be included in an upcoming module version."); + +/* WA to get away with the default setting in VBT for early platforms.Will be removed */ +intel_display_param_named_unsafe(edp_vswing, int, 0400, + "Ignore/Override vswing pre-emph table selection from VBT " + "(0=use value from vbt [default], 1=low power swing(200mV)," + "2=default swing(400mV))"); + +intel_display_param_named(enable_dpcd_backlight, int, 0400, + "Enable support for DPCD backlight control" + "(-1=use per-VBT LFP backlight type setting [default], 0=disabled, 1=enable, 2=force VESA interface, 3=force Intel interface)"); + +intel_display_param_named_unsafe(load_detect_test, bool, 0400, + "Force-enable the VGA load detect code for testing (default:false). " + "For developers only."); + +intel_display_param_named_unsafe(force_reset_modeset_test, bool, 0400, + "Force a modeset during gpu reset for testing (default:false). " + "For developers only."); + +intel_display_param_named(disable_display, bool, 0400, + "Disable display (default: false)"); + +intel_display_param_named(verbose_state_checks, bool, 0400, + "Enable verbose logs (ie. WARN_ON()) in case of unexpected hw state conditions."); + +intel_display_param_named_unsafe(nuclear_pageflip, bool, 0400, + "Force enable atomic functionality on platforms that don't have full support yet."); + +intel_display_param_named_unsafe(enable_dp_mst, bool, 0400, + "Enable multi-stream transport (MST) for new DisplayPort sinks. (default: true)"); + +intel_display_param_named_unsafe(enable_fbc, int, 0400, + "Enable frame buffer compression for power savings " + "(default: -1 (use per-chip default))"); + +intel_display_param_named_unsafe(enable_psr, int, 0400, + "Enable PSR " + "(0=disabled, 1=enable up to PSR1, 2=enable up to PSR2) " + "Default: -1 (use per-chip default)"); + +intel_display_param_named(psr_safest_params, bool, 0400, + "Replace PSR VBT parameters by the safest and not optimal ones. This " + "is helpful to detect if PSR issues are related to bad values set in " + " VBT. (0=use VBT parameters, 1=use safest parameters)" + "Default: 0"); + +intel_display_param_named_unsafe(enable_psr2_sel_fetch, bool, 0400, + "Enable PSR2 selective fetch " + "(0=disabled, 1=enabled) " + "Default: 1"); + +__maybe_unused +static void _param_print_bool(struct drm_printer *p, const char *driver_name, + const char *name, bool val) +{ + drm_printf(p, "%s.%s=%s\n", driver_name, name, str_yes_no(val)); +} + +__maybe_unused +static void _param_print_int(struct drm_printer *p, const char *driver_name, + const char *name, int val) +{ + drm_printf(p, "%s.%s=%d\n", driver_name, name, val); +} + +__maybe_unused +static void _param_print_uint(struct drm_printer *p, const char *driver_name, + const char *name, unsigned int val) +{ + drm_printf(p, "%s.%s=%u\n", driver_name, name, val); +} + +__maybe_unused +static void _param_print_ulong(struct drm_printer *p, const char *driver_name, + const char *name, unsigned long val) +{ + drm_printf(p, "%s.%s=%lu\n", driver_name, name, val); +} + +__maybe_unused +static void _param_print_charp(struct drm_printer *p, const char *driver_name, + const char *name, const char *val) +{ + drm_printf(p, "%s.%s=%s\n", driver_name, name, val); +} + +#define _param_print(p, driver_name, 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, driver_name, name, val) + +/** + * intel_display_params_dump - dump intel display modparams + * @i915: i915 device + * @p: the &drm_printer + * + * Pretty printer for i915 modparams. + */ +void intel_display_params_dump(struct drm_i915_private *i915, struct drm_printer *p) +{ +#define PRINT(T, x, ...) _param_print(p, i915->drm.driver->name, #x, i915->display.params.x); + INTEL_DISPLAY_PARAMS_FOR_EACH(PRINT); +#undef PRINT +} + +__maybe_unused static void _param_dup_charp(char **valp) +{ + *valp = kstrdup(*valp ? *valp : "", GFP_ATOMIC); +} + +__maybe_unused static void _param_nop(void *valp) +{ +} + +#define _param_dup(valp) \ + _Generic(valp, \ + char ** : _param_dup_charp, \ + default : _param_nop) \ + (valp) + +void intel_display_params_copy(struct intel_display_params *dest) +{ + *dest = intel_display_modparams; +#define DUP(T, x, ...) _param_dup(&dest->x); + INTEL_DISPLAY_PARAMS_FOR_EACH(DUP); +#undef DUP +} + +__maybe_unused static void _param_free_charp(char **valp) +{ + 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 intel_display_params_free(struct intel_display_params *params) +{ +#define FREE(T, x, ...) _param_free(¶ms->x); + INTEL_DISPLAY_PARAMS_FOR_EACH(FREE); +#undef FREE +} diff --git a/drivers/gpu/drm/i915/display/intel_display_params.h b/drivers/gpu/drm/i915/display/intel_display_params.h new file mode 100644 index 00000000000000..6206cc51df0493 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_display_params.h @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef _INTEL_DISPLAY_PARAMS_H_ +#define _INTEL_DISPLAY_PARAMS_H_ + +#include + +struct drm_printer; +struct drm_i915_private; + +/* + * Invoke param, a function-like macro, for each intel display param, with + * arguments: + * + * param(type, name, value, mode) + * + * type: parameter type, one of {bool, int, unsigned int, unsigned long, char *} + * name: name of the parameter + * value: initial/default value of the parameter + * mode: debugfs file permissions, one of {0400, 0600, 0}, use 0 to not create + * debugfs file + */ +#define INTEL_DISPLAY_PARAMS_FOR_EACH(param) \ + param(char *, vbt_firmware, NULL, 0400) \ + param(int, lvds_channel_mode, 0, 0400) \ + param(int, panel_use_ssc, -1, 0600) \ + param(int, vbt_sdvo_panel_type, -1, 0400) \ + param(int, enable_dc, -1, 0400) \ + param(bool, enable_dpt, true, 0400) \ + param(bool, enable_sagv, true, 0600) \ + param(int, disable_power_well, -1, 0400) \ + param(bool, enable_ips, true, 0600) \ + param(int, invert_brightness, 0, 0600) \ + param(int, edp_vswing, 0, 0400) \ + param(int, enable_dpcd_backlight, -1, 0600) \ + param(bool, load_detect_test, false, 0600) \ + param(bool, force_reset_modeset_test, false, 0600) \ + param(bool, disable_display, false, 0400) \ + param(bool, verbose_state_checks, true, 0400) \ + param(bool, nuclear_pageflip, false, 0400) \ + param(bool, enable_dp_mst, true, 0600) \ + param(int, enable_fbc, -1, 0600) \ + param(int, enable_psr, -1, 0600) \ + param(bool, psr_safest_params, false, 0400) \ + param(bool, enable_psr2_sel_fetch, true, 0400) \ + +#define MEMBER(T, member, ...) T member; +struct intel_display_params { + INTEL_DISPLAY_PARAMS_FOR_EACH(MEMBER); +}; +#undef MEMBER + +void intel_display_params_dump(struct drm_i915_private *i915, + struct drm_printer *p); +void intel_display_params_copy(struct intel_display_params *dest); +void intel_display_params_free(struct intel_display_params *params); + +#endif diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index e25785ae1c20ce..6fd4fa52253a35 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -405,8 +405,8 @@ print_async_put_domains_state(struct i915_power_domains *power_domains) struct drm_i915_private, display.power.domains); - drm_dbg(&i915->drm, "async_put_wakeref %u\n", - power_domains->async_put_wakeref); + drm_dbg(&i915->drm, "async_put_wakeref: %s\n", + str_yes_no(power_domains->async_put_wakeref)); print_power_domains(power_domains, "async_put_domains[0]", &power_domains->async_put_domains[0]); @@ -967,7 +967,7 @@ static u32 get_allowed_dc_mask(const struct drm_i915_private *dev_priv, DISPLAY_VER(dev_priv) >= 11 ? DC_STATE_EN_DC9 : 0; - if (!dev_priv->params.disable_power_well) + if (!dev_priv->display.params.disable_power_well) max_dc = 0; if (enable_dc >= 0 && enable_dc <= max_dc) { @@ -1016,11 +1016,11 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv) { struct i915_power_domains *power_domains = &dev_priv->display.power.domains; - dev_priv->params.disable_power_well = + dev_priv->display.params.disable_power_well = sanitize_disable_power_well_option(dev_priv, - dev_priv->params.disable_power_well); + dev_priv->display.params.disable_power_well); power_domains->allowed_dc_mask = - get_allowed_dc_mask(dev_priv, dev_priv->params.enable_dc); + get_allowed_dc_mask(dev_priv, dev_priv->display.params.enable_dc); power_domains->target_dc_state = sanitize_target_dc_state(dev_priv, DC_STATE_EN_UPTO_DC6); @@ -1697,14 +1697,14 @@ static void icl_display_core_init(struct drm_i915_private *dev_priv, if (resume) intel_dmc_load_program(dev_priv); - /* Wa_14011508470:tgl,dg1,rkl,adl-s,adl-p */ - if (DISPLAY_VER(dev_priv) >= 12) + /* Wa_14011508470:tgl,dg1,rkl,adl-s,adl-p,dg2 */ + if (IS_DISPLAY_IP_RANGE(dev_priv, IP_VER(12, 0), IP_VER(13, 0))) intel_de_rmw(dev_priv, GEN11_CHICKEN_DCPR_2, 0, DCPR_CLEAR_MEMSTAT_DIS | DCPR_SEND_RESP_IMM | DCPR_MASK_LPMODE | DCPR_MASK_MAXLATENCY_MEMUP_CLR); /* Wa_14011503030:xelpd */ - if (DISPLAY_VER(dev_priv) >= 13) + if (DISPLAY_VER(dev_priv) == 13) intel_de_write(dev_priv, XELPD_DISPLAY_ERR_FATAL_MASK, ~0); } @@ -1950,7 +1950,7 @@ void intel_power_domains_init_hw(struct drm_i915_private *i915, bool resume) intel_display_power_get(i915, POWER_DOMAIN_INIT); /* Disable power support if the user asked so. */ - if (!i915->params.disable_power_well) { + if (!i915->display.params.disable_power_well) { drm_WARN_ON(&i915->drm, power_domains->disable_wakeref); i915->display.power.domains.disable_wakeref = intel_display_power_get(i915, POWER_DOMAIN_INIT); @@ -1977,7 +1977,7 @@ void intel_power_domains_driver_remove(struct drm_i915_private *i915) fetch_and_zero(&i915->display.power.domains.init_wakeref); /* Remove the refcount we took to keep power well support disabled. */ - if (!i915->params.disable_power_well) + if (!i915->display.params.disable_power_well) intel_display_power_put(i915, POWER_DOMAIN_INIT, fetch_and_zero(&i915->display.power.domains.disable_wakeref)); @@ -2096,7 +2096,7 @@ void intel_power_domains_suspend(struct drm_i915_private *i915, bool s2idle) * Even if power well support was disabled we still want to disable * power wells if power domains must be deinitialized for suspend. */ - if (!i915->params.disable_power_well) + if (!i915->display.params.disable_power_well) intel_display_power_put(i915, POWER_DOMAIN_INIT, fetch_and_zero(&i915->display.power.domains.disable_wakeref)); diff --git a/drivers/gpu/drm/i915/display/intel_display_power_well.c b/drivers/gpu/drm/i915/display/intel_display_power_well.c index 07d6500500992f..47cd6bb04366f3 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power_well.c +++ b/drivers/gpu/drm/i915/display/intel_display_power_well.c @@ -1400,20 +1400,16 @@ static void chv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv, { enum i915_power_well_id id = i915_power_well_instance(power_well)->id; enum dpio_phy phy; - enum pipe pipe; u32 tmp; drm_WARN_ON_ONCE(&dev_priv->drm, id != VLV_DISP_PW_DPIO_CMN_BC && id != CHV_DISP_PW_DPIO_CMN_D); - if (id == VLV_DISP_PW_DPIO_CMN_BC) { - pipe = PIPE_A; + if (id == VLV_DISP_PW_DPIO_CMN_BC) phy = DPIO_PHY0; - } else { - pipe = PIPE_C; + else phy = DPIO_PHY1; - } /* since ref/cri clock was enabled */ udelay(1); /* >10ns for cmnreset, >0ns for sidereset */ @@ -1428,24 +1424,24 @@ static void chv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv, vlv_dpio_get(dev_priv); /* Enable dynamic power down */ - tmp = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW28); + tmp = vlv_dpio_read(dev_priv, phy, CHV_CMN_DW28); tmp |= DPIO_DYNPWRDOWNEN_CH0 | DPIO_CL1POWERDOWNEN | DPIO_SUS_CLK_CONFIG_GATE_CLKREQ; - vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW28, tmp); + vlv_dpio_write(dev_priv, phy, CHV_CMN_DW28, tmp); if (id == VLV_DISP_PW_DPIO_CMN_BC) { - tmp = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW6_CH1); + tmp = vlv_dpio_read(dev_priv, phy, _CHV_CMN_DW6_CH1); tmp |= DPIO_DYNPWRDOWNEN_CH1; - vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW6_CH1, tmp); + vlv_dpio_write(dev_priv, phy, _CHV_CMN_DW6_CH1, tmp); } else { /* * Force the non-existing CL2 off. BXT does this * too, so maybe it saves some power even though * CL2 doesn't exist? */ - tmp = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW30); + tmp = vlv_dpio_read(dev_priv, phy, CHV_CMN_DW30); tmp |= DPIO_CL2_LDOFUSE_PWRENB; - vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW30, tmp); + vlv_dpio_write(dev_priv, phy, CHV_CMN_DW30, tmp); } vlv_dpio_put(dev_priv); @@ -1499,7 +1495,6 @@ static void chv_dpio_cmn_power_well_disable(struct drm_i915_private *dev_priv, static void assert_chv_phy_powergate(struct drm_i915_private *dev_priv, enum dpio_phy phy, enum dpio_channel ch, bool override, unsigned int mask) { - enum pipe pipe = phy == DPIO_PHY0 ? PIPE_A : PIPE_C; u32 reg, val, expected, actual; /* @@ -1518,7 +1513,7 @@ static void assert_chv_phy_powergate(struct drm_i915_private *dev_priv, enum dpi reg = _CHV_CMN_DW6_CH1; vlv_dpio_get(dev_priv); - val = vlv_dpio_read(dev_priv, pipe, reg); + val = vlv_dpio_read(dev_priv, phy, reg); vlv_dpio_put(dev_priv); /* diff --git a/drivers/gpu/drm/i915/display/intel_display_reset.c b/drivers/gpu/drm/i915/display/intel_display_reset.c index 17178d5d7788a9..c2c347b22448ac 100644 --- a/drivers/gpu/drm/i915/display/intel_display_reset.c +++ b/drivers/gpu/drm/i915/display/intel_display_reset.c @@ -29,7 +29,7 @@ void intel_display_reset_prepare(struct drm_i915_private *dev_priv) return; /* reset doesn't touch the display */ - if (!dev_priv->params.force_reset_modeset_test && + if (!dev_priv->display.params.force_reset_modeset_test && !gpu_reset_clobbers_display(dev_priv)) return; diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 65ea37fe8cff32..3fdd8a51798312 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -198,6 +198,12 @@ struct intel_encoder { struct intel_encoder *, const struct intel_crtc_state *, const struct drm_connector_state *); + void (*audio_enable)(struct intel_encoder *encoder, + const struct intel_crtc_state *crtc_state, + const struct drm_connector_state *conn_state); + void (*audio_disable)(struct intel_encoder *encoder, + const struct intel_crtc_state *old_crtc_state, + const struct drm_connector_state *old_conn_state); /* Read out the current hw state of this connector, returning true if * the encoder is active. If the encoder is enabled it also set the pipe * it is connected to in the pipe parameter. */ @@ -624,6 +630,9 @@ struct intel_connector { struct drm_dp_aux *dsc_decompression_aux; u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE]; u8 fec_capability; + + u8 dsc_hblank_expansion_quirk:1; + u8 dsc_decompression_enabled:1; } dp; /* Work struct to schedule a uevent on link train failure */ @@ -675,10 +684,6 @@ struct intel_atomic_state { bool skip_intermediate_wm; bool rps_interactive; - - struct i915_sw_fence commit_ready; - - struct llist_node freed; }; struct intel_plane_state { @@ -1015,7 +1020,6 @@ struct intel_c10pll_state { }; struct intel_c20pll_state { - u32 link_bit_rate; u32 clock; /* in kHz */ u16 tx[3]; u16 cmn[4]; @@ -1210,6 +1214,7 @@ struct intel_crtc_state { bool has_psr2; bool enable_psr2_sel_fetch; bool req_psr2_sdp_prior_scanline; + bool has_panel_replay; bool wm_level_disabled; u32 dc3co_exitline; u16 su_y_granularity; @@ -1361,7 +1366,8 @@ struct intel_crtc_state { struct { bool compression_enable; bool dsc_split; - u16 compressed_bpp; + /* Compressed Bpp in U6.4 format (first 4 bits for fractional part) */ + u16 compressed_bpp_x16; u8 slice_count; struct drm_dsc_config config; } dsc; @@ -1467,6 +1473,9 @@ struct intel_crtc { struct intel_crtc_state *config; + /* armed event for async flip */ + struct drm_pending_vblank_event *flip_done_event; + /* Access to these should be protected by dev_priv->irq_lock. */ bool cpu_fifo_underrun_disabled; bool pch_fifo_underrun_disabled; @@ -1707,9 +1716,13 @@ struct intel_psr { bool irq_aux_error; u16 su_w_granularity; u16 su_y_granularity; + bool source_panel_replay_support; + bool sink_panel_replay_support; + bool panel_replay_enabled; u32 dc3co_exitline; u32 dc3co_exit_delay; struct delayed_work dc3co_work; + u8 entry_setup_frames; }; struct intel_dp { @@ -1808,6 +1821,7 @@ struct intel_dp { /* Display stream compression testing */ bool force_dsc_en; int force_dsc_output_format; + bool force_dsc_fractional_bpp_en; int force_dsc_bpc; bool hobl_failed; @@ -1992,17 +2006,6 @@ dp_to_lspcon(struct intel_dp *intel_dp) #define dp_to_i915(__intel_dp) to_i915(dp_to_dig_port(__intel_dp)->base.base.dev) -#define CAN_PSR(intel_dp) ((intel_dp)->psr.sink_support && \ - (intel_dp)->psr.source_support) - -static inline bool intel_encoder_can_psr(struct intel_encoder *encoder) -{ - if (!intel_encoder_is_dp(encoder)) - return false; - - return CAN_PSR(enc_to_intel_dp(encoder)); -} - static inline struct intel_digital_port * hdmi_to_dig_port(struct intel_hdmi *intel_hdmi) { diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c b/drivers/gpu/drm/i915/display/intel_dmc.c index 073b85b57679a5..b70502586ab985 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc.c +++ b/drivers/gpu/drm/i915/display/intel_dmc.c @@ -335,77 +335,6 @@ static void disable_event_handler(struct drm_i915_private *i915, intel_de_write(i915, htp_reg, 0); } -static void -disable_flip_queue_event(struct drm_i915_private *i915, - i915_reg_t ctl_reg, i915_reg_t htp_reg) -{ - u32 event_ctl; - u32 event_htp; - - event_ctl = intel_de_read(i915, ctl_reg); - event_htp = intel_de_read(i915, htp_reg); - if (event_ctl != (DMC_EVT_CTL_ENABLE | - DMC_EVT_CTL_RECURRING | - REG_FIELD_PREP(DMC_EVT_CTL_TYPE_MASK, - DMC_EVT_CTL_TYPE_EDGE_0_1) | - REG_FIELD_PREP(DMC_EVT_CTL_EVENT_ID_MASK, - DMC_EVT_CTL_EVENT_ID_CLK_MSEC)) || - !event_htp) { - drm_dbg_kms(&i915->drm, - "Unexpected DMC event configuration (control %08x htp %08x)\n", - event_ctl, event_htp); - return; - } - - disable_event_handler(i915, ctl_reg, htp_reg); -} - -static bool -get_flip_queue_event_regs(struct drm_i915_private *i915, enum intel_dmc_id dmc_id, - i915_reg_t *ctl_reg, i915_reg_t *htp_reg) -{ - if (dmc_id == DMC_FW_MAIN) { - if (DISPLAY_VER(i915) == 12) { - *ctl_reg = DMC_EVT_CTL(i915, dmc_id, 3); - *htp_reg = DMC_EVT_HTP(i915, dmc_id, 3); - - return true; - } - } else if (dmc_id >= DMC_FW_PIPEA && dmc_id <= DMC_FW_PIPED) { - if (IS_DG2(i915)) { - *ctl_reg = DMC_EVT_CTL(i915, dmc_id, 2); - *htp_reg = DMC_EVT_HTP(i915, dmc_id, 2); - - return true; - } - } - - return false; -} - -static void -disable_all_flip_queue_events(struct drm_i915_private *i915) -{ - enum intel_dmc_id dmc_id; - - /* TODO: check if the following applies to all D13+ platforms. */ - if (!IS_TIGERLAKE(i915)) - return; - - for_each_dmc_id(dmc_id) { - i915_reg_t ctl_reg; - i915_reg_t htp_reg; - - if (!has_dmc_id_fw(i915, dmc_id)) - continue; - - if (!get_flip_queue_event_regs(i915, dmc_id, &ctl_reg, &htp_reg)) - continue; - - disable_flip_queue_event(i915, ctl_reg, htp_reg); - } -} - static void disable_all_event_handlers(struct drm_i915_private *i915) { enum intel_dmc_id dmc_id; @@ -503,6 +432,16 @@ static bool is_dmc_evt_ctl_reg(struct drm_i915_private *i915, return offset >= start && offset < end; } +static bool is_dmc_evt_htp_reg(struct drm_i915_private *i915, + enum intel_dmc_id dmc_id, i915_reg_t reg) +{ + u32 offset = i915_mmio_reg_offset(reg); + u32 start = i915_mmio_reg_offset(DMC_EVT_HTP(i915, dmc_id, 0)); + u32 end = i915_mmio_reg_offset(DMC_EVT_HTP(i915, dmc_id, DMC_EVENT_HANDLER_COUNT_GEN12)); + + return offset >= start && offset < end; +} + static bool disable_dmc_evt(struct drm_i915_private *i915, enum intel_dmc_id dmc_id, i915_reg_t reg, u32 data) @@ -514,6 +453,16 @@ static bool disable_dmc_evt(struct drm_i915_private *i915, if (dmc_id != DMC_FW_MAIN) return true; + /* also disable the flip queue event on the main DMC on TGL */ + if (IS_TIGERLAKE(i915) && + REG_FIELD_GET(DMC_EVT_CTL_EVENT_ID_MASK, data) == DMC_EVT_CTL_EVENT_ID_CLK_MSEC) + return true; + + /* also disable the HRR event on the main DMC on TGL/ADLS */ + if ((IS_TIGERLAKE(i915) || IS_ALDERLAKE_S(i915)) && + REG_FIELD_GET(DMC_EVT_CTL_EVENT_ID_MASK, data) == DMC_EVT_CTL_EVENT_ID_VBLANK_A) + return true; + return false; } @@ -579,13 +528,6 @@ void intel_dmc_load_program(struct drm_i915_private *i915) gen9_set_dc_state_debugmask(i915); - /* - * Flip queue events need to be disabled before enabling DC5/6. - * i915 doesn't use the flip queue feature, so disable it already - * here. - */ - disable_all_flip_queue_events(i915); - pipedmc_clock_gating_wa(i915, false); } @@ -781,9 +723,17 @@ static u32 parse_dmc_fw_header(struct intel_dmc *dmc, return 0; } + drm_dbg_kms(&i915->drm, "DMC %d:\n", dmc_id); for (i = 0; i < mmio_count; i++) { dmc_info->mmioaddr[i] = _MMIO(mmioaddr[i]); dmc_info->mmiodata[i] = mmiodata[i]; + + drm_dbg_kms(&i915->drm, " mmio[%d]: 0x%x = 0x%x%s%s\n", + i, mmioaddr[i], mmiodata[i], + is_dmc_evt_ctl_reg(i915, dmc_id, dmc_info->mmioaddr[i]) ? " (EVT_CTL)" : + is_dmc_evt_htp_reg(i915, dmc_id, dmc_info->mmioaddr[i]) ? " (EVT_HTP)" : "", + disable_dmc_evt(i915, dmc_id, dmc_info->mmioaddr[i], + dmc_info->mmiodata[i]) ? " (disabling)" : ""); } dmc_info->mmio_count = mmio_count; dmc_info->start_mmioaddr = start_mmioaddr; diff --git a/drivers/gpu/drm/i915/display/intel_dmc_regs.h b/drivers/gpu/drm/i915/display/intel_dmc_regs.h index cf10094acae3d4..90d0dbb41cfe6c 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc_regs.h +++ b/drivers/gpu/drm/i915/display/intel_dmc_regs.h @@ -60,6 +60,7 @@ #define DMC_EVT_CTL_EVENT_ID_MASK REG_GENMASK(15, 8) #define DMC_EVT_CTL_EVENT_ID_FALSE 0x01 +#define DMC_EVT_CTL_EVENT_ID_VBLANK_A 0x32 /* main DMC */ /* An event handler scheduled to run at a 1 kHz frequency. */ #define DMC_EVT_CTL_EVENT_ID_CLK_MSEC 0xbf diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 62ce92772367f6..f5ef95da55346f 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -85,8 +85,8 @@ #define DP_DSC_MAX_ENC_THROUGHPUT_0 340000 #define DP_DSC_MAX_ENC_THROUGHPUT_1 400000 -/* DP DSC FEC Overhead factor = 1/(0.972261) */ -#define DP_DSC_FEC_OVERHEAD_FACTOR 972261 +/* DP DSC FEC Overhead factor in ppm = 1/(0.972261) = 1.028530 */ +#define DP_DSC_FEC_OVERHEAD_FACTOR 1028530 /* Compliance test status bits */ #define INTEL_DP_RESOLUTION_SHIFT_MASK 0 @@ -124,7 +124,31 @@ static void intel_dp_unset_edid(struct intel_dp *intel_dp); /* Is link rate UHBR and thus 128b/132b? */ bool intel_dp_is_uhbr(const struct intel_crtc_state *crtc_state) { - return crtc_state->port_clock >= 1000000; + return drm_dp_is_uhbr_rate(crtc_state->port_clock); +} + +/** + * intel_dp_link_symbol_size - get the link symbol size for a given link rate + * @rate: link rate in 10kbit/s units + * + * Returns the link symbol size in bits/symbol units depending on the link + * rate -> channel coding. + */ +int intel_dp_link_symbol_size(int rate) +{ + return drm_dp_is_uhbr_rate(rate) ? 32 : 10; +} + +/** + * intel_dp_link_symbol_clock - convert link rate to link symbol clock + * @rate: link rate in 10kbit/s units + * + * Returns the link symbol clock frequency in kHz units depending on the + * link rate and channel coding. + */ +int intel_dp_link_symbol_clock(int rate) +{ + return DIV_ROUND_CLOSEST(rate * 10, intel_dp_link_symbol_size(rate)); } static void intel_dp_set_default_sink_rates(struct intel_dp *intel_dp) @@ -331,6 +355,9 @@ int intel_dp_max_lane_count(struct intel_dp *intel_dp) /* * The required data bandwidth for a mode with given pixel clock and bpp. This * is the required net bandwidth independent of the data bandwidth efficiency. + * + * TODO: check if callers of this functions should use + * intel_dp_effective_data_rate() instead. */ int intel_dp_link_required(int pixel_clock, int bpp) @@ -339,6 +366,22 @@ intel_dp_link_required(int pixel_clock, int bpp) return DIV_ROUND_UP(pixel_clock * bpp, 8); } +/** + * intel_dp_effective_data_rate - Return the pixel data rate accounting for BW allocation overhead + * @pixel_clock: pixel clock in kHz + * @bpp_x16: bits per pixel .4 fixed point format + * @bw_overhead: BW allocation overhead in 1ppm units + * + * Return the effective pixel data rate in kB/sec units taking into account + * the provided SSC, FEC, DSC BW allocation overhead. + */ +int intel_dp_effective_data_rate(int pixel_clock, int bpp_x16, + int bw_overhead) +{ + return DIV_ROUND_UP_ULL(mul_u32_u32(pixel_clock * bpp_x16, bw_overhead), + 1000000 * 16 * 8); +} + /* * Given a link rate and lanes, get the data bandwidth. * @@ -362,29 +405,27 @@ intel_dp_link_required(int pixel_clock, int bpp) int intel_dp_max_data_rate(int max_link_rate, int max_lanes) { - if (max_link_rate >= 1000000) { - /* - * UHBR rates always use 128b/132b channel encoding, and have - * 97.71% data bandwidth efficiency. Consider max_link_rate the - * link bit rate in units of 10000 bps. - */ - int max_link_rate_kbps = max_link_rate * 10; - - max_link_rate_kbps = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(max_link_rate_kbps, 9671), 10000); - max_link_rate = max_link_rate_kbps / 8; - } + int ch_coding_efficiency = + drm_dp_bw_channel_coding_efficiency(drm_dp_is_uhbr_rate(max_link_rate)); + int max_link_rate_kbps = max_link_rate * 10; + /* + * UHBR rates always use 128b/132b channel encoding, and have + * 97.71% data bandwidth efficiency. Consider max_link_rate the + * link bit rate in units of 10000 bps. + */ /* * Lower than UHBR rates always use 8b/10b channel encoding, and have * 80% data bandwidth efficiency for SST non-FEC. However, this turns - * out to be a nop by coincidence, and can be skipped: + * out to be a nop by coincidence: * * int max_link_rate_kbps = max_link_rate * 10; - * max_link_rate_kbps = DIV_ROUND_CLOSEST_ULL(max_link_rate_kbps * 8, 10); + * max_link_rate_kbps = DIV_ROUND_DOWN_ULL(max_link_rate_kbps * 8, 10); * max_link_rate = max_link_rate_kbps / 8; */ - - return max_link_rate * max_lanes; + return DIV_ROUND_DOWN_ULL(mul_u32_u32(max_link_rate_kbps * max_lanes, + ch_coding_efficiency), + 1000000 * 8); } bool intel_dp_can_bigjoiner(struct intel_dp *intel_dp) @@ -680,8 +721,22 @@ int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp, u32 intel_dp_mode_to_fec_clock(u32 mode_clock) { - return div_u64(mul_u32_u32(mode_clock, 1000000U), - DP_DSC_FEC_OVERHEAD_FACTOR); + return div_u64(mul_u32_u32(mode_clock, DP_DSC_FEC_OVERHEAD_FACTOR), + 1000000U); +} + +int intel_dp_bw_fec_overhead(bool fec_enabled) +{ + /* + * TODO: Calculate the actual overhead for a given mode. + * The hard-coded 1/0.972261=2.853% overhead factor + * corresponds (for instance) to the 8b/10b DP FEC 2.4% + + * 0.453% DSC overhead. This is enough for a 3840 width mode, + * which has a DSC overhead of up to ~0.2%, but may not be + * enough for a 1024 width mode where this is ~0.8% (on a 4 + * lane DP link, with 2 DSC slices and 8 bpp color depth). + */ + return fec_enabled ? DP_DSC_FEC_OVERHEAD_FACTOR : 1000000; } static int @@ -1373,9 +1428,9 @@ static bool intel_dp_source_supports_fec(struct intel_dp *intel_dp, return false; } -static bool intel_dp_supports_fec(struct intel_dp *intel_dp, - const struct intel_connector *connector, - const struct intel_crtc_state *pipe_config) +bool intel_dp_supports_fec(struct intel_dp *intel_dp, + const struct intel_connector *connector, + const struct intel_crtc_state *pipe_config) { return intel_dp_source_supports_fec(intel_dp, pipe_config) && drm_dp_sink_supports_fec(connector->dp.fec_capability); @@ -1388,6 +1443,7 @@ static bool intel_dp_supports_dsc(const struct intel_connector *connector, return false; return intel_dsc_source_support(crtc_state) && + connector->dp.dsc_decompression_aux && drm_dp_sink_supports_dsc(connector->dp.dsc_dpcd); } @@ -1721,15 +1777,15 @@ static bool intel_dp_dsc_supports_format(const struct intel_connector *connector return drm_dp_dsc_sink_supports_format(connector->dp.dsc_dpcd, sink_dsc_format); } -static bool is_bw_sufficient_for_dsc_config(u16 compressed_bpp, u32 link_clock, +static bool is_bw_sufficient_for_dsc_config(u16 compressed_bppx16, u32 link_clock, u32 lane_count, u32 mode_clock, enum intel_output_format output_format, int timeslots) { u32 available_bw, required_bw; - available_bw = (link_clock * lane_count * timeslots) / 8; - required_bw = compressed_bpp * (intel_dp_mode_to_fec_clock(mode_clock)); + available_bw = (link_clock * lane_count * timeslots * 16) / 8; + required_bw = compressed_bppx16 * (intel_dp_mode_to_fec_clock(mode_clock)); return available_bw > required_bw; } @@ -1737,7 +1793,7 @@ static bool is_bw_sufficient_for_dsc_config(u16 compressed_bpp, u32 link_clock, static int dsc_compute_link_config(struct intel_dp *intel_dp, struct intel_crtc_state *pipe_config, struct link_config_limits *limits, - u16 compressed_bpp, + u16 compressed_bppx16, int timeslots) { const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; @@ -1752,8 +1808,8 @@ static int dsc_compute_link_config(struct intel_dp *intel_dp, for (lane_count = limits->min_lane_count; lane_count <= limits->max_lane_count; lane_count <<= 1) { - if (!is_bw_sufficient_for_dsc_config(compressed_bpp, link_rate, lane_count, - adjusted_mode->clock, + if (!is_bw_sufficient_for_dsc_config(compressed_bppx16, link_rate, + lane_count, adjusted_mode->clock, pipe_config->output_format, timeslots)) continue; @@ -1795,7 +1851,7 @@ u16 intel_dp_dsc_max_sink_compressed_bppx16(const struct intel_connector *connec return 0; } -static int dsc_sink_min_compressed_bpp(struct intel_crtc_state *pipe_config) +int intel_dp_dsc_sink_min_compressed_bpp(struct intel_crtc_state *pipe_config) { /* From Mandatory bit rate range Support Table 2-157 (DP v2.0) */ switch (pipe_config->output_format) { @@ -1812,9 +1868,9 @@ static int dsc_sink_min_compressed_bpp(struct intel_crtc_state *pipe_config) return 0; } -static int dsc_sink_max_compressed_bpp(const struct intel_connector *connector, - struct intel_crtc_state *pipe_config, - int bpc) +int intel_dp_dsc_sink_max_compressed_bpp(const struct intel_connector *connector, + struct intel_crtc_state *pipe_config, + int bpc) { return intel_dp_dsc_max_sink_compressed_bppx16(connector, pipe_config, bpc) >> 4; @@ -1834,7 +1890,7 @@ static int dsc_src_max_compressed_bpp(struct intel_dp *intel_dp) * Max Compressed bpp for Gen 13+ is 27bpp. * For earlier platform is 23bpp. (Bspec:49259). */ - if (DISPLAY_VER(i915) <= 12) + if (DISPLAY_VER(i915) < 13) return 23; else return 27; @@ -1866,10 +1922,11 @@ icl_dsc_compute_link_config(struct intel_dp *intel_dp, ret = dsc_compute_link_config(intel_dp, pipe_config, limits, - valid_dsc_bpp[i], + valid_dsc_bpp[i] << 4, timeslots); if (ret == 0) { - pipe_config->dsc.compressed_bpp = valid_dsc_bpp[i]; + pipe_config->dsc.compressed_bpp_x16 = + to_bpp_x16(valid_dsc_bpp[i]); return 0; } } @@ -1885,6 +1942,7 @@ icl_dsc_compute_link_config(struct intel_dp *intel_dp, */ static int xelpd_dsc_compute_link_config(struct intel_dp *intel_dp, + const struct intel_connector *connector, struct intel_crtc_state *pipe_config, struct link_config_limits *limits, int dsc_max_bpp, @@ -1892,22 +1950,38 @@ xelpd_dsc_compute_link_config(struct intel_dp *intel_dp, int pipe_bpp, int timeslots) { - u16 compressed_bpp; + u8 bppx16_incr = drm_dp_dsc_sink_bpp_incr(connector->dp.dsc_dpcd); + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + u16 compressed_bppx16; + u8 bppx16_step; int ret; - /* Compressed BPP should be less than the Input DSC bpp */ - dsc_max_bpp = min(dsc_max_bpp, pipe_bpp - 1); + if (DISPLAY_VER(i915) < 14 || bppx16_incr <= 1) + bppx16_step = 16; + else + bppx16_step = 16 / bppx16_incr; - for (compressed_bpp = dsc_max_bpp; - compressed_bpp >= dsc_min_bpp; - compressed_bpp--) { + /* Compressed BPP should be less than the Input DSC bpp */ + dsc_max_bpp = min(dsc_max_bpp << 4, (pipe_bpp << 4) - bppx16_step); + dsc_min_bpp = dsc_min_bpp << 4; + + for (compressed_bppx16 = dsc_max_bpp; + compressed_bppx16 >= dsc_min_bpp; + compressed_bppx16 -= bppx16_step) { + if (intel_dp->force_dsc_fractional_bpp_en && + !to_bpp_frac(compressed_bppx16)) + continue; ret = dsc_compute_link_config(intel_dp, pipe_config, limits, - compressed_bpp, + compressed_bppx16, timeslots); if (ret == 0) { - pipe_config->dsc.compressed_bpp = compressed_bpp; + pipe_config->dsc.compressed_bpp_x16 = compressed_bppx16; + if (intel_dp->force_dsc_fractional_bpp_en && + to_bpp_frac(compressed_bppx16)) + drm_dbg_kms(&i915->drm, "Forcing DSC fractional bpp\n"); + return 0; } } @@ -1928,12 +2002,14 @@ static int dsc_compute_compressed_bpp(struct intel_dp *intel_dp, int dsc_joiner_max_bpp; dsc_src_min_bpp = dsc_src_min_compressed_bpp(); - dsc_sink_min_bpp = dsc_sink_min_compressed_bpp(pipe_config); + dsc_sink_min_bpp = intel_dp_dsc_sink_min_compressed_bpp(pipe_config); dsc_min_bpp = max(dsc_src_min_bpp, dsc_sink_min_bpp); dsc_min_bpp = max(dsc_min_bpp, to_bpp_int_roundup(limits->link.min_bpp_x16)); dsc_src_max_bpp = dsc_src_max_compressed_bpp(intel_dp); - dsc_sink_max_bpp = dsc_sink_max_compressed_bpp(connector, pipe_config, pipe_bpp / 3); + dsc_sink_max_bpp = intel_dp_dsc_sink_max_compressed_bpp(connector, + pipe_config, + pipe_bpp / 3); dsc_max_bpp = dsc_sink_max_bpp ? min(dsc_sink_max_bpp, dsc_src_max_bpp) : dsc_src_max_bpp; dsc_joiner_max_bpp = get_max_compressed_bpp_with_joiner(i915, adjusted_mode->clock, @@ -1943,7 +2019,7 @@ static int dsc_compute_compressed_bpp(struct intel_dp *intel_dp, dsc_max_bpp = min(dsc_max_bpp, to_bpp_int(limits->link.max_bpp_x16)); if (DISPLAY_VER(i915) >= 13) - return xelpd_dsc_compute_link_config(intel_dp, pipe_config, limits, + return xelpd_dsc_compute_link_config(intel_dp, connector, pipe_config, limits, dsc_max_bpp, dsc_min_bpp, pipe_bpp, timeslots); return icl_dsc_compute_link_config(intel_dp, pipe_config, limits, dsc_max_bpp, dsc_min_bpp, pipe_bpp, timeslots); @@ -2025,7 +2101,7 @@ static int intel_dp_dsc_compute_pipe_bpp(struct intel_dp *intel_dp, } } - dsc_max_bpc = intel_dp_dsc_min_src_input_bpc(i915); + dsc_max_bpc = intel_dp_dsc_max_src_input_bpc(i915); if (!dsc_max_bpc) return -EINVAL; @@ -2088,19 +2164,22 @@ static int intel_edp_dsc_compute_pipe_bpp(struct intel_dp *intel_dp, pipe_config->lane_count = limits->max_lane_count; dsc_src_min_bpp = dsc_src_min_compressed_bpp(); - dsc_sink_min_bpp = dsc_sink_min_compressed_bpp(pipe_config); + dsc_sink_min_bpp = intel_dp_dsc_sink_min_compressed_bpp(pipe_config); dsc_min_bpp = max(dsc_src_min_bpp, dsc_sink_min_bpp); dsc_min_bpp = max(dsc_min_bpp, to_bpp_int_roundup(limits->link.min_bpp_x16)); dsc_src_max_bpp = dsc_src_max_compressed_bpp(intel_dp); - dsc_sink_max_bpp = dsc_sink_max_compressed_bpp(connector, pipe_config, pipe_bpp / 3); + dsc_sink_max_bpp = intel_dp_dsc_sink_max_compressed_bpp(connector, + pipe_config, + pipe_bpp / 3); dsc_max_bpp = dsc_sink_max_bpp ? min(dsc_sink_max_bpp, dsc_src_max_bpp) : dsc_src_max_bpp; dsc_max_bpp = min(dsc_max_bpp, to_bpp_int(limits->link.max_bpp_x16)); /* Compressed BPP should be less than the Input DSC bpp */ dsc_max_bpp = min(dsc_max_bpp, pipe_bpp - 1); - pipe_config->dsc.compressed_bpp = max(dsc_min_bpp, dsc_max_bpp); + pipe_config->dsc.compressed_bpp_x16 = + to_bpp_x16(max(dsc_min_bpp, dsc_max_bpp)); pipe_config->pipe_bpp = pipe_bpp; @@ -2122,8 +2201,9 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, &pipe_config->hw.adjusted_mode; int ret; - pipe_config->fec_enable = !intel_dp_is_edp(intel_dp) && - intel_dp_supports_fec(intel_dp, connector, pipe_config); + pipe_config->fec_enable = pipe_config->fec_enable || + (!intel_dp_is_edp(intel_dp) && + intel_dp_supports_fec(intel_dp, connector, pipe_config)); if (!intel_dp_supports_dsc(connector, pipe_config)) return -EINVAL; @@ -2188,18 +2268,18 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, ret = intel_dp_dsc_compute_params(connector, pipe_config); if (ret < 0) { drm_dbg_kms(&dev_priv->drm, - "Cannot compute valid DSC parameters for Input Bpp = %d " - "Compressed BPP = %d\n", + "Cannot compute valid DSC parameters for Input Bpp = %d" + "Compressed BPP = " BPP_X16_FMT "\n", pipe_config->pipe_bpp, - pipe_config->dsc.compressed_bpp); + BPP_X16_ARGS(pipe_config->dsc.compressed_bpp_x16)); return ret; } pipe_config->dsc.compression_enable = true; drm_dbg_kms(&dev_priv->drm, "DP DSC computed with Input Bpp = %d " - "Compressed Bpp = %d Slice Count = %d\n", + "Compressed Bpp = " BPP_X16_FMT " Slice Count = %d\n", pipe_config->pipe_bpp, - pipe_config->dsc.compressed_bpp, + BPP_X16_ARGS(pipe_config->dsc.compressed_bpp_x16), pipe_config->dsc.slice_count); return 0; @@ -2311,6 +2391,8 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, { struct drm_i915_private *i915 = to_i915(encoder->base.dev); struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc); + const struct intel_connector *connector = + to_intel_connector(conn_state->connector); const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; struct intel_dp *intel_dp = enc_to_intel_dp(encoder); @@ -2319,6 +2401,10 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, bool dsc_needed; int ret = 0; + if (pipe_config->fec_enable && + !intel_dp_supports_fec(intel_dp, connector, pipe_config)) + return -EINVAL; + if (intel_dp_need_bigjoiner(intel_dp, adjusted_mode->crtc_hdisplay, adjusted_mode->crtc_clock)) pipe_config->bigjoiner_pipes = GENMASK(crtc->pipe + 1, crtc->pipe); @@ -2366,15 +2452,15 @@ intel_dp_compute_link_config(struct intel_encoder *encoder, if (pipe_config->dsc.compression_enable) { drm_dbg_kms(&i915->drm, - "DP lane count %d clock %d Input bpp %d Compressed bpp %d\n", + "DP lane count %d clock %d Input bpp %d Compressed bpp " BPP_X16_FMT "\n", pipe_config->lane_count, pipe_config->port_clock, pipe_config->pipe_bpp, - pipe_config->dsc.compressed_bpp); + BPP_X16_ARGS(pipe_config->dsc.compressed_bpp_x16)); drm_dbg_kms(&i915->drm, "DP link rate required %i available %i\n", intel_dp_link_required(adjusted_mode->crtc_clock, - pipe_config->dsc.compressed_bpp), + to_bpp_int_roundup(pipe_config->dsc.compressed_bpp_x16)), intel_dp_max_data_rate(pipe_config->port_clock, pipe_config->lane_count)); } else { @@ -2443,12 +2529,22 @@ static void intel_dp_compute_vsc_colorimetry(const struct intel_crtc_state *crtc struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - /* - * Prepare VSC Header for SU as per DP 1.4 spec, Table 2-118 - * VSC SDP supporting 3D stereo, PSR2, and Pixel Encoding/ - * Colorimetry Format indication. - */ - vsc->revision = 0x5; + if (crtc_state->has_panel_replay) { + /* + * Prepare VSC Header for SU as per DP 2.0 spec, Table 2-223 + * VSC SDP supporting 3D stereo, Panel Replay, and Pixel + * Encoding/Colorimetry Format indication. + */ + vsc->revision = 0x7; + } else { + /* + * Prepare VSC Header for SU as per DP 1.4 spec, Table 2-118 + * VSC SDP supporting 3D stereo, PSR2, and Pixel Encoding/ + * Colorimetry Format indication. + */ + vsc->revision = 0x5; + } + vsc->length = 0x13; /* DP 1.4a spec, Table 2-120 */ @@ -2557,6 +2653,21 @@ void intel_dp_compute_psr_vsc_sdp(struct intel_dp *intel_dp, vsc->revision = 0x4; vsc->length = 0xe; } + } else if (crtc_state->has_panel_replay) { + if (intel_dp->psr.colorimetry_support && + intel_dp_needs_vsc_sdp(crtc_state, conn_state)) { + /* [Panel Replay with colorimetry info] */ + intel_dp_compute_vsc_colorimetry(crtc_state, conn_state, + vsc); + } else { + /* + * [Panel Replay without colorimetry info] + * Prepare VSC Header for SU as per DP 2.0 spec, Table 2-223 + * VSC SDP supporting 3D stereo + Panel Replay. + */ + vsc->revision = 0x6; + vsc->length = 0x10; + } } else { /* * [PSR1] @@ -2633,7 +2744,7 @@ static bool can_enable_drrs(struct intel_connector *connector, static void intel_dp_drrs_compute_config(struct intel_connector *connector, struct intel_crtc_state *pipe_config, - int link_bpp) + int link_bpp_x16) { struct drm_i915_private *i915 = to_i915(connector->base.dev); const struct drm_display_mode *downclock_mode = @@ -2658,9 +2769,10 @@ intel_dp_drrs_compute_config(struct intel_connector *connector, if (pipe_config->splitter.enable) pixel_clock /= pipe_config->splitter.link_count; - intel_link_compute_m_n(link_bpp, pipe_config->lane_count, pixel_clock, - pipe_config->port_clock, &pipe_config->dp_m2_n2, - pipe_config->fec_enable); + intel_link_compute_m_n(link_bpp_x16, pipe_config->lane_count, pixel_clock, + pipe_config->port_clock, + intel_dp_bw_fec_overhead(pipe_config->fec_enable), + &pipe_config->dp_m2_n2); /* FIXME: abstract this better */ if (pipe_config->splitter.enable) @@ -2736,19 +2848,12 @@ 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->has_audio = intel_dp_has_audio(encoder, pipe_config, conn_state) && intel_audio_compute_config(encoder, pipe_config, conn_state); pipe_config->sdp_split_enable = pipe_config->has_audio && 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 @@ -2761,7 +2866,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, struct intel_dp *intel_dp = enc_to_intel_dp(encoder); const struct drm_display_mode *fixed_mode; struct intel_connector *connector = intel_dp->attached_connector; - int ret = 0, link_bpp; + int ret = 0, link_bpp_x16; if (HAS_PCH_SPLIT(dev_priv) && !HAS_DDI(dev_priv) && encoder->port != PORT_A) pipe_config->has_pch_encoder = true; @@ -2810,10 +2915,10 @@ intel_dp_compute_config(struct intel_encoder *encoder, drm_dp_enhanced_frame_cap(intel_dp->dpcd); if (pipe_config->dsc.compression_enable) - link_bpp = pipe_config->dsc.compressed_bpp; + link_bpp_x16 = pipe_config->dsc.compressed_bpp_x16; else - link_bpp = intel_dp_output_bpp(pipe_config->output_format, - pipe_config->pipe_bpp); + link_bpp_x16 = to_bpp_x16(intel_dp_output_bpp(pipe_config->output_format, + pipe_config->pipe_bpp)); if (intel_dp->mso_link_count) { int n = intel_dp->mso_link_count; @@ -2837,12 +2942,12 @@ intel_dp_compute_config(struct intel_encoder *encoder, intel_dp_audio_compute_config(encoder, pipe_config, conn_state); - intel_link_compute_m_n(link_bpp, + intel_link_compute_m_n(link_bpp_x16, pipe_config->lane_count, adjusted_mode->crtc_clock, pipe_config->port_clock, - &pipe_config->dp_m_n, - pipe_config->fec_enable); + intel_dp_bw_fec_overhead(pipe_config->fec_enable), + &pipe_config->dp_m_n); /* FIXME: abstract this better */ if (pipe_config->splitter.enable) @@ -2853,7 +2958,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, intel_vrr_compute_config(pipe_config, conn_state); intel_psr_compute_config(intel_dp, pipe_config, conn_state); - intel_dp_drrs_compute_config(connector, pipe_config, link_bpp); + intel_dp_drrs_compute_config(connector, pipe_config, link_bpp_x16); intel_dp_compute_vsc_sdp(intel_dp, pipe_config, conn_state); intel_dp_compute_hdr_metadata_infoframe_sdp(intel_dp, pipe_config, conn_state); @@ -2921,24 +3026,179 @@ static bool downstream_hpd_needs_d0(struct intel_dp *intel_dp) intel_dp->downstream_ports[0] & DP_DS_PORT_HPD; } -void intel_dp_sink_set_decompression_state(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state, - bool enable) +static int +write_dsc_decompression_flag(struct drm_dp_aux *aux, u8 flag, bool set) { - struct drm_i915_private *i915 = dp_to_i915(intel_dp); - int ret; + int err; + u8 val; - if (!crtc_state->dsc.compression_enable) - return; + err = drm_dp_dpcd_readb(aux, DP_DSC_ENABLE, &val); + if (err < 0) + return err; - ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_DSC_ENABLE, - enable ? DP_DECOMPRESSION_EN : 0); - if (ret < 0) + if (set) + val |= flag; + else + val &= ~flag; + + return drm_dp_dpcd_writeb(aux, DP_DSC_ENABLE, val); +} + +static void +intel_dp_sink_set_dsc_decompression(struct intel_connector *connector, + bool enable) +{ + struct drm_i915_private *i915 = to_i915(connector->base.dev); + + if (write_dsc_decompression_flag(connector->dp.dsc_decompression_aux, + DP_DECOMPRESSION_EN, enable) < 0) drm_dbg_kms(&i915->drm, "Failed to %s sink decompression state\n", str_enable_disable(enable)); } +static void +intel_dp_sink_set_dsc_passthrough(const struct intel_connector *connector, + bool enable) +{ + struct drm_i915_private *i915 = to_i915(connector->base.dev); + struct drm_dp_aux *aux = connector->port ? + connector->port->passthrough_aux : NULL; + + if (!aux) + return; + + if (write_dsc_decompression_flag(aux, + DP_DSC_PASSTHROUGH_EN, enable) < 0) + drm_dbg_kms(&i915->drm, + "Failed to %s sink compression passthrough state\n", + str_enable_disable(enable)); +} + +static int intel_dp_dsc_aux_ref_count(struct intel_atomic_state *state, + const struct intel_connector *connector, + bool for_get_ref) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + struct drm_connector *_connector_iter; + struct drm_connector_state *old_conn_state; + struct drm_connector_state *new_conn_state; + int ref_count = 0; + int i; + + /* + * On SST the decompression AUX device won't be shared, each connector + * uses for this its own AUX targeting the sink device. + */ + if (!connector->mst_port) + return connector->dp.dsc_decompression_enabled ? 1 : 0; + + for_each_oldnew_connector_in_state(&state->base, _connector_iter, + old_conn_state, new_conn_state, i) { + const struct intel_connector * + connector_iter = to_intel_connector(_connector_iter); + + if (connector_iter->mst_port != connector->mst_port) + continue; + + if (!connector_iter->dp.dsc_decompression_enabled) + continue; + + drm_WARN_ON(&i915->drm, + (for_get_ref && !new_conn_state->crtc) || + (!for_get_ref && !old_conn_state->crtc)); + + if (connector_iter->dp.dsc_decompression_aux == + connector->dp.dsc_decompression_aux) + ref_count++; + } + + return ref_count; +} + +static bool intel_dp_dsc_aux_get_ref(struct intel_atomic_state *state, + struct intel_connector *connector) +{ + bool ret = intel_dp_dsc_aux_ref_count(state, connector, true) == 0; + + connector->dp.dsc_decompression_enabled = true; + + return ret; +} + +static bool intel_dp_dsc_aux_put_ref(struct intel_atomic_state *state, + struct intel_connector *connector) +{ + connector->dp.dsc_decompression_enabled = false; + + return intel_dp_dsc_aux_ref_count(state, connector, false) == 0; +} + +/** + * intel_dp_sink_enable_decompression - Enable DSC decompression in sink/last branch device + * @state: atomic state + * @connector: connector to enable the decompression for + * @new_crtc_state: new state for the CRTC driving @connector + * + * Enable the DSC decompression if required in the %DP_DSC_ENABLE DPCD + * register of the appropriate sink/branch device. On SST this is always the + * sink device, whereas on MST based on each device's DSC capabilities it's + * either the last branch device (enabling decompression in it) or both the + * last branch device (enabling passthrough in it) and the sink device + * (enabling decompression in it). + */ +void intel_dp_sink_enable_decompression(struct intel_atomic_state *state, + struct intel_connector *connector, + const struct intel_crtc_state *new_crtc_state) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + + if (!new_crtc_state->dsc.compression_enable) + return; + + if (drm_WARN_ON(&i915->drm, + !connector->dp.dsc_decompression_aux || + connector->dp.dsc_decompression_enabled)) + return; + + if (!intel_dp_dsc_aux_get_ref(state, connector)) + return; + + intel_dp_sink_set_dsc_passthrough(connector, true); + intel_dp_sink_set_dsc_decompression(connector, true); +} + +/** + * intel_dp_sink_disable_decompression - Disable DSC decompression in sink/last branch device + * @state: atomic state + * @connector: connector to disable the decompression for + * @old_crtc_state: old state for the CRTC driving @connector + * + * Disable the DSC decompression if required in the %DP_DSC_ENABLE DPCD + * register of the appropriate sink/branch device, corresponding to the + * sequence in intel_dp_sink_enable_decompression(). + */ +void intel_dp_sink_disable_decompression(struct intel_atomic_state *state, + struct intel_connector *connector, + const struct intel_crtc_state *old_crtc_state) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + + if (!old_crtc_state->dsc.compression_enable) + return; + + if (drm_WARN_ON(&i915->drm, + !connector->dp.dsc_decompression_aux || + !connector->dp.dsc_decompression_enabled)) + return; + + if (!intel_dp_dsc_aux_put_ref(state, connector)) + return; + + intel_dp_sink_set_dsc_decompression(connector, false); + intel_dp_sink_set_dsc_passthrough(connector, false); +} + static void intel_edp_init_source_oui(struct intel_dp *intel_dp, bool careful) { @@ -3775,7 +4035,7 @@ intel_dp_can_mst(struct intel_dp *intel_dp) { struct drm_i915_private *i915 = dp_to_i915(intel_dp); - return i915->params.enable_dp_mst && + return i915->display.params.enable_dp_mst && intel_dp_mst_source_support(intel_dp) && drm_dp_read_mst_cap(&intel_dp->aux, intel_dp->dpcd); } @@ -3793,13 +4053,13 @@ intel_dp_configure_mst(struct intel_dp *intel_dp) encoder->base.base.id, encoder->base.name, str_yes_no(intel_dp_mst_source_support(intel_dp)), str_yes_no(sink_can_mst), - str_yes_no(i915->params.enable_dp_mst)); + str_yes_no(i915->display.params.enable_dp_mst)); if (!intel_dp_mst_source_support(intel_dp)) return; intel_dp->is_mst = sink_can_mst && - i915->params.enable_dp_mst; + i915->display.params.enable_dp_mst; drm_dp_mst_topology_mgr_set_mst(&intel_dp->mst_mgr, intel_dp->is_mst); @@ -3869,11 +4129,16 @@ static ssize_t intel_dp_vsc_sdp_pack(const struct drm_dp_vsc_sdp *vsc, sdp->sdp_header.HB2 = vsc->revision; /* Revision Number */ sdp->sdp_header.HB3 = vsc->length; /* Number of Valid Data Bytes */ + if (vsc->revision == 0x6) { + sdp->db[0] = 1; + sdp->db[3] = 1; + } + /* - * Only revision 0x5 supports Pixel Encoding/Colorimetry Format as - * per DP 1.4a spec. + * Revision 0x5 and revision 0x7 supports Pixel Encoding/Colorimetry + * Format as per DP 1.4a spec and DP 2.0 respectively. */ - if (vsc->revision != 0x5) + if (!(vsc->revision == 0x5 || vsc->revision == 0x7)) goto out; /* VSC SDP Payload for DB16 through DB18 */ @@ -4053,7 +4318,10 @@ void intel_dp_set_infoframes(struct intel_encoder *encoder, VIDEO_DIP_ENABLE_SPD_HSW | VIDEO_DIP_ENABLE_DRM_GLK; u32 val = intel_de_read(dev_priv, reg) & ~dip_enable; - /* TODO: Add DSC case (DIP_ENABLE_PPS) */ + /* TODO: Sanitize DSC enabling wrt. intel_dsc_dp_pps_write(). */ + if (!enable && HAS_DSC(dev_priv)) + val &= ~VDIP_ENABLE_PPS; + /* When PSR is enabled, this routine doesn't disable VSC DIP */ if (!crtc_state->has_psr) val &= ~VIDEO_DIP_ENABLE_VSC_HSW; @@ -5413,6 +5681,7 @@ intel_dp_detect(struct drm_connector *connector, if (status == connector_status_disconnected) { memset(&intel_dp->compliance, 0, sizeof(intel_dp->compliance)); memset(intel_connector->dp.dsc_dpcd, 0, sizeof(intel_connector->dp.dsc_dpcd)); + intel_dp->psr.sink_panel_replay_support = false; if (intel_dp->is_mst) { drm_dbg_kms(&dev_priv->drm, @@ -6258,16 +6527,6 @@ intel_dp_init_connector(struct intel_digital_port *dig_port, "HDCP init failed, skipping.\n"); } - /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written - * 0xd. Failure to do so will result in spurious interrupts being - * generated on the port when a cable is not attached. - */ - if (IS_G45(dev_priv)) { - u32 temp = intel_de_read(dev_priv, PEG_BAND_GAP_DATA); - intel_de_write(dev_priv, PEG_BAND_GAP_DATA, - (temp & ~0xf) | 0xd); - } - intel_dp->frl.is_trained = false; intel_dp->frl.trained_rate_gbps = 0; diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index 484aea215a2512..05db46b111f216 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -57,9 +57,12 @@ int intel_dp_retrain_link(struct intel_encoder *encoder, void intel_dp_set_power(struct intel_dp *intel_dp, u8 mode); void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state); -void intel_dp_sink_set_decompression_state(struct intel_dp *intel_dp, - const struct intel_crtc_state *crtc_state, - bool enable); +void intel_dp_sink_enable_decompression(struct intel_atomic_state *state, + struct intel_connector *connector, + const struct intel_crtc_state *new_crtc_state); +void intel_dp_sink_disable_decompression(struct intel_atomic_state *state, + struct intel_connector *connector, + const struct intel_crtc_state *old_crtc_state); void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder); void intel_dp_encoder_shutdown(struct intel_encoder *intel_encoder); void intel_dp_encoder_flush_work(struct drm_encoder *encoder); @@ -78,6 +81,8 @@ void intel_dp_audio_compute_config(struct intel_encoder *encoder, bool intel_dp_has_hdmi_sink(struct intel_dp *intel_dp); bool intel_dp_is_edp(struct intel_dp *intel_dp); bool intel_dp_is_uhbr(const struct intel_crtc_state *crtc_state); +int intel_dp_link_symbol_size(int rate); +int intel_dp_link_symbol_clock(int rate); bool intel_dp_is_port_edp(struct drm_i915_private *dev_priv, enum port port); enum irqreturn intel_dp_hpd_pulse(struct intel_digital_port *dig_port, bool long_hpd); @@ -98,6 +103,8 @@ bool intel_dp_source_supports_tps4(struct drm_i915_private *i915); bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp); int intel_dp_link_required(int pixel_clock, int bpp); +int intel_dp_effective_data_rate(int pixel_clock, int bpp_x16, + int bw_overhead); int intel_dp_max_data_rate(int max_link_rate, int max_lanes); bool intel_dp_can_bigjoiner(struct intel_dp *intel_dp); bool intel_dp_needs_vsc_sdp(const struct intel_crtc_state *crtc_state, @@ -125,6 +132,10 @@ u16 intel_dp_dsc_get_max_compressed_bpp(struct drm_i915_private *i915, enum intel_output_format output_format, u32 pipe_bpp, u32 timeslots); +int intel_dp_dsc_sink_min_compressed_bpp(struct intel_crtc_state *pipe_config); +int intel_dp_dsc_sink_max_compressed_bpp(const struct intel_connector *connector, + struct intel_crtc_state *pipe_config, + int bpc); u8 intel_dp_dsc_get_slice_count(const struct intel_connector *connector, int mode_clock, int mode_hdisplay, bool bigjoiner); @@ -136,7 +147,16 @@ static inline unsigned int intel_dp_unused_lane_mask(int lane_count) return ~((1 << lane_count) - 1) & 0xf; } +bool intel_dp_supports_fec(struct intel_dp *intel_dp, + const struct intel_connector *connector, + const struct intel_crtc_state *pipe_config); u32 intel_dp_mode_to_fec_clock(u32 mode_clock); +int intel_dp_bw_fec_overhead(bool fec_enabled); + +bool intel_dp_supports_fec(struct intel_dp *intel_dp, + const struct intel_connector *connector, + const struct intel_crtc_state *pipe_config); + 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, diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux.c b/drivers/gpu/drm/i915/display/intel_dp_aux.c index 4431b6290c4cfc..2e2af71bcd5a82 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_aux.c +++ b/drivers/gpu/drm/i915/display/intel_dp_aux.c @@ -74,7 +74,7 @@ intel_dp_aux_wait_done(struct intel_dp *intel_dp) static u32 g4x_get_aux_clock_divider(struct intel_dp *intel_dp, int index) { - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + struct drm_i915_private *i915 = dp_to_i915(intel_dp); if (index) return 0; @@ -83,12 +83,12 @@ static u32 g4x_get_aux_clock_divider(struct intel_dp *intel_dp, int index) * The clock divider is based off the hrawclk, and would like to run at * 2MHz. So, take the hrawclk value and divide by 2000 and use that */ - return DIV_ROUND_CLOSEST(RUNTIME_INFO(dev_priv)->rawclk_freq, 2000); + return DIV_ROUND_CLOSEST(RUNTIME_INFO(i915)->rawclk_freq, 2000); } static u32 ilk_get_aux_clock_divider(struct intel_dp *intel_dp, int index) { - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + struct drm_i915_private *i915 = dp_to_i915(intel_dp); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); u32 freq; @@ -101,18 +101,18 @@ static u32 ilk_get_aux_clock_divider(struct intel_dp *intel_dp, int index) * divide by 2000 and use that */ if (dig_port->aux_ch == AUX_CH_A) - freq = dev_priv->display.cdclk.hw.cdclk; + freq = i915->display.cdclk.hw.cdclk; else - freq = RUNTIME_INFO(dev_priv)->rawclk_freq; + freq = RUNTIME_INFO(i915)->rawclk_freq; return DIV_ROUND_CLOSEST(freq, 2000); } static u32 hsw_get_aux_clock_divider(struct intel_dp *intel_dp, int index) { - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + struct drm_i915_private *i915 = dp_to_i915(intel_dp); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); - if (dig_port->aux_ch != AUX_CH_A && HAS_PCH_LPT_H(dev_priv)) { + if (dig_port->aux_ch != AUX_CH_A && HAS_PCH_LPT_H(i915)) { /* Workaround for non-ULT HSW */ switch (index) { case 0: return 63; @@ -165,12 +165,11 @@ static u32 g4x_get_aux_send_ctl(struct intel_dp *intel_dp, u32 aux_clock_divider) { 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); + struct drm_i915_private *i915 = to_i915(dig_port->base.base.dev); u32 timeout; /* Max timeout value on G4x-BDW: 1.6ms */ - if (IS_BROADWELL(dev_priv)) + if (IS_BROADWELL(i915)) timeout = DP_AUX_CH_CTL_TIME_OUT_600us; else timeout = DP_AUX_CH_CTL_TIME_OUT_400us; @@ -229,8 +228,7 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp, u32 aux_send_ctl_flags) { 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 drm_i915_private *i915 = to_i915(dig_port->base.base.dev); 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]; @@ -531,9 +529,40 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) return ret; } +static i915_reg_t vlv_aux_ctl_reg(struct intel_dp *intel_dp) +{ + struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); + enum aux_ch aux_ch = dig_port->aux_ch; + + switch (aux_ch) { + case AUX_CH_B: + case AUX_CH_C: + case AUX_CH_D: + return VLV_DP_AUX_CH_CTL(aux_ch); + default: + MISSING_CASE(aux_ch); + return VLV_DP_AUX_CH_CTL(AUX_CH_B); + } +} + +static i915_reg_t vlv_aux_data_reg(struct intel_dp *intel_dp, int index) +{ + struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); + enum aux_ch aux_ch = dig_port->aux_ch; + + switch (aux_ch) { + case AUX_CH_B: + case AUX_CH_C: + case AUX_CH_D: + return VLV_DP_AUX_CH_DATA(aux_ch, index); + default: + MISSING_CASE(aux_ch); + return VLV_DP_AUX_CH_DATA(AUX_CH_B, index); + } +} + static i915_reg_t g4x_aux_ctl_reg(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); enum aux_ch aux_ch = dig_port->aux_ch; @@ -550,7 +579,6 @@ static i915_reg_t g4x_aux_ctl_reg(struct intel_dp *intel_dp) static i915_reg_t g4x_aux_data_reg(struct intel_dp *intel_dp, int index) { - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); enum aux_ch aux_ch = dig_port->aux_ch; @@ -567,7 +595,6 @@ static i915_reg_t g4x_aux_data_reg(struct intel_dp *intel_dp, int index) static i915_reg_t ilk_aux_ctl_reg(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); enum aux_ch aux_ch = dig_port->aux_ch; @@ -586,7 +613,6 @@ static i915_reg_t ilk_aux_ctl_reg(struct intel_dp *intel_dp) static i915_reg_t ilk_aux_data_reg(struct intel_dp *intel_dp, int index) { - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); enum aux_ch aux_ch = dig_port->aux_ch; @@ -605,7 +631,6 @@ static i915_reg_t ilk_aux_data_reg(struct intel_dp *intel_dp, int index) static i915_reg_t skl_aux_ctl_reg(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); enum aux_ch aux_ch = dig_port->aux_ch; @@ -625,7 +650,6 @@ static i915_reg_t skl_aux_ctl_reg(struct intel_dp *intel_dp) static i915_reg_t skl_aux_data_reg(struct intel_dp *intel_dp, int index) { - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); enum aux_ch aux_ch = dig_port->aux_ch; @@ -645,7 +669,6 @@ static i915_reg_t skl_aux_data_reg(struct intel_dp *intel_dp, int index) static i915_reg_t tgl_aux_ctl_reg(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); enum aux_ch aux_ch = dig_port->aux_ch; @@ -668,7 +691,6 @@ static i915_reg_t tgl_aux_ctl_reg(struct intel_dp *intel_dp) static i915_reg_t tgl_aux_data_reg(struct intel_dp *intel_dp, int index) { - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); enum aux_ch aux_ch = dig_port->aux_ch; @@ -691,7 +713,7 @@ static i915_reg_t tgl_aux_data_reg(struct intel_dp *intel_dp, int index) static i915_reg_t xelpdp_aux_ctl_reg(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + struct drm_i915_private *i915 = dp_to_i915(intel_dp); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); enum aux_ch aux_ch = dig_port->aux_ch; @@ -702,16 +724,16 @@ static i915_reg_t xelpdp_aux_ctl_reg(struct intel_dp *intel_dp) case AUX_CH_USBC2: case AUX_CH_USBC3: case AUX_CH_USBC4: - return XELPDP_DP_AUX_CH_CTL(dev_priv, aux_ch); + return XELPDP_DP_AUX_CH_CTL(i915, aux_ch); default: MISSING_CASE(aux_ch); - return XELPDP_DP_AUX_CH_CTL(dev_priv, AUX_CH_A); + return XELPDP_DP_AUX_CH_CTL(i915, AUX_CH_A); } } static i915_reg_t xelpdp_aux_data_reg(struct intel_dp *intel_dp, int index) { - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + struct drm_i915_private *i915 = dp_to_i915(intel_dp); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); enum aux_ch aux_ch = dig_port->aux_ch; @@ -722,10 +744,10 @@ static i915_reg_t xelpdp_aux_data_reg(struct intel_dp *intel_dp, int index) case AUX_CH_USBC2: case AUX_CH_USBC3: case AUX_CH_USBC4: - return XELPDP_DP_AUX_CH_DATA(dev_priv, aux_ch, index); + return XELPDP_DP_AUX_CH_DATA(i915, aux_ch, index); default: MISSING_CASE(aux_ch); - return XELPDP_DP_AUX_CH_DATA(dev_priv, AUX_CH_A, index); + return XELPDP_DP_AUX_CH_DATA(i915, AUX_CH_A, index); } } @@ -739,49 +761,52 @@ void intel_dp_aux_fini(struct intel_dp *intel_dp) void intel_dp_aux_init(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + struct drm_i915_private *i915 = dp_to_i915(intel_dp); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct intel_encoder *encoder = &dig_port->base; enum aux_ch aux_ch = dig_port->aux_ch; char buf[AUX_CH_NAME_BUFSIZE]; - if (DISPLAY_VER(dev_priv) >= 14) { + if (DISPLAY_VER(i915) >= 14) { intel_dp->aux_ch_ctl_reg = xelpdp_aux_ctl_reg; intel_dp->aux_ch_data_reg = xelpdp_aux_data_reg; - } else if (DISPLAY_VER(dev_priv) >= 12) { + } else if (DISPLAY_VER(i915) >= 12) { intel_dp->aux_ch_ctl_reg = tgl_aux_ctl_reg; intel_dp->aux_ch_data_reg = tgl_aux_data_reg; - } else if (DISPLAY_VER(dev_priv) >= 9) { + } else if (DISPLAY_VER(i915) >= 9) { intel_dp->aux_ch_ctl_reg = skl_aux_ctl_reg; intel_dp->aux_ch_data_reg = skl_aux_data_reg; - } else if (HAS_PCH_SPLIT(dev_priv)) { + } else if (HAS_PCH_SPLIT(i915)) { intel_dp->aux_ch_ctl_reg = ilk_aux_ctl_reg; intel_dp->aux_ch_data_reg = ilk_aux_data_reg; + } else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) { + intel_dp->aux_ch_ctl_reg = vlv_aux_ctl_reg; + intel_dp->aux_ch_data_reg = vlv_aux_data_reg; } else { intel_dp->aux_ch_ctl_reg = g4x_aux_ctl_reg; intel_dp->aux_ch_data_reg = g4x_aux_data_reg; } - if (DISPLAY_VER(dev_priv) >= 9) + if (DISPLAY_VER(i915) >= 9) intel_dp->get_aux_clock_divider = skl_get_aux_clock_divider; - else if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv)) + else if (IS_BROADWELL(i915) || IS_HASWELL(i915)) intel_dp->get_aux_clock_divider = hsw_get_aux_clock_divider; - else if (HAS_PCH_SPLIT(dev_priv)) + else if (HAS_PCH_SPLIT(i915)) intel_dp->get_aux_clock_divider = ilk_get_aux_clock_divider; else intel_dp->get_aux_clock_divider = g4x_get_aux_clock_divider; - if (DISPLAY_VER(dev_priv) >= 9) + if (DISPLAY_VER(i915) >= 9) intel_dp->get_aux_send_ctl = skl_get_aux_send_ctl; else intel_dp->get_aux_send_ctl = g4x_get_aux_send_ctl; - intel_dp->aux.drm_dev = &dev_priv->drm; + intel_dp->aux.drm_dev = &i915->drm; drm_dp_aux_init(&intel_dp->aux); /* Failure to allocate our preferred name is not critical */ intel_dp->aux.name = kasprintf(GFP_KERNEL, "AUX %s/%s", - aux_ch_name(dev_priv, buf, sizeof(buf), aux_ch), + aux_ch_name(i915, buf, sizeof(buf), aux_ch), encoder->base.name); intel_dp->aux.transfer = intel_dp_aux_transfer; diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c index 26ea7e9f1b8999..4f58efdc688af0 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c +++ b/drivers/gpu/drm/i915/display/intel_dp_aux_backlight.c @@ -146,7 +146,7 @@ intel_dp_aux_supports_hdr_backlight(struct intel_connector *connector) * HDR static metadata we need to start maintaining table of * ranges for such panels. */ - if (i915->params.enable_dpcd_backlight != INTEL_DP_AUX_BACKLIGHT_FORCE_INTEL && + if (i915->display.params.enable_dpcd_backlight != INTEL_DP_AUX_BACKLIGHT_FORCE_INTEL && !(connector->base.hdr_sink_metadata.hdmi_type1.metadata_type & BIT(HDMI_STATIC_METADATA_TYPE1))) { drm_info(&i915->drm, @@ -489,7 +489,7 @@ int intel_dp_aux_init_backlight_funcs(struct intel_connector *connector) /* Check the VBT and user's module parameters to figure out which * interfaces to probe */ - switch (i915->params.enable_dpcd_backlight) { + switch (i915->display.params.enable_dpcd_backlight) { case INTEL_DP_AUX_BACKLIGHT_OFF: return -ENODEV; case INTEL_DP_AUX_BACKLIGHT_AUTO: diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux_regs.h b/drivers/gpu/drm/i915/display/intel_dp_aux_regs.h index 34f6e0a48ed20a..e642445364d27e 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_aux_regs.h +++ b/drivers/gpu/drm/i915/display/intel_dp_aux_regs.h @@ -21,13 +21,14 @@ #define __xe2lpd_aux_ch_idx(aux_ch) \ (aux_ch >= AUX_CH_USBC1 ? aux_ch : AUX_CH_USBC4 + 1 + (aux_ch) - AUX_CH_A) -/* TODO: Remove implicit dev_priv */ -#define _DPA_AUX_CH_CTL (DISPLAY_MMIO_BASE(dev_priv) + 0x64010) -#define _DPB_AUX_CH_CTL (DISPLAY_MMIO_BASE(dev_priv) + 0x64110) +#define _DPA_AUX_CH_CTL 0x64010 +#define _DPB_AUX_CH_CTL 0x64110 #define _XELPDP_USBC1_AUX_CH_CTL 0x16f210 #define _XELPDP_USBC2_AUX_CH_CTL 0x16f410 #define DP_AUX_CH_CTL(aux_ch) _MMIO_PORT(aux_ch, _DPA_AUX_CH_CTL, \ _DPB_AUX_CH_CTL) +#define VLV_DP_AUX_CH_CTL(aux_ch) _MMIO(VLV_DISPLAY_BASE + \ + _PORT(aux_ch, _DPA_AUX_CH_CTL, _DPB_AUX_CH_CTL)) #define _XELPDP_DP_AUX_CH_CTL(aux_ch) \ _MMIO(_PICK_EVEN_2RANGES(aux_ch, AUX_CH_USBC1, \ _DPA_AUX_CH_CTL, _DPB_AUX_CH_CTL, \ @@ -69,13 +70,14 @@ #define DP_AUX_CH_CTL_SYNC_PULSE_SKL_MASK REG_GENMASK(4, 0) /* skl+ */ #define DP_AUX_CH_CTL_SYNC_PULSE_SKL(c) REG_FIELD_PREP(DP_AUX_CH_CTL_SYNC_PULSE_SKL_MASK, (c) - 1) -/* TODO: Remove implicit dev_priv */ -#define _DPA_AUX_CH_DATA1 (DISPLAY_MMIO_BASE(dev_priv) + 0x64014) -#define _DPB_AUX_CH_DATA1 (DISPLAY_MMIO_BASE(dev_priv) + 0x64114) +#define _DPA_AUX_CH_DATA1 0x64014 +#define _DPB_AUX_CH_DATA1 0x64114 #define _XELPDP_USBC1_AUX_CH_DATA1 0x16f214 #define _XELPDP_USBC2_AUX_CH_DATA1 0x16f414 #define DP_AUX_CH_DATA(aux_ch, i) _MMIO(_PORT(aux_ch, _DPA_AUX_CH_DATA1, \ _DPB_AUX_CH_DATA1) + (i) * 4) /* 5 registers */ +#define VLV_DP_AUX_CH_DATA(aux_ch, i) _MMIO(VLV_DISPLAY_BASE + _PORT(aux_ch, _DPA_AUX_CH_DATA1, \ + _DPB_AUX_CH_DATA1) + (i) * 4) /* 5 registers */ #define _XELPDP_DP_AUX_CH_DATA(aux_ch, i) \ _MMIO(_PICK_EVEN_2RANGES(aux_ch, AUX_CH_USBC1, \ _DPA_AUX_CH_DATA1, _DPB_AUX_CH_DATA1, \ diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index aa10612626136d..8a943233503034 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "i915_drv.h" @@ -43,6 +44,9 @@ #include "intel_dpio_phy.h" #include "intel_hdcp.h" #include "intel_hotplug.h" +#include "intel_link_bw.h" +#include "intel_psr.h" +#include "intel_vdsc.h" #include "skl_scaler.h" static int intel_dp_mst_check_constraints(struct drm_i915_private *i915, int bpp, @@ -50,7 +54,7 @@ static int intel_dp_mst_check_constraints(struct drm_i915_private *i915, int bpp struct intel_crtc_state *crtc_state, bool dsc) { - if (intel_dp_is_uhbr(crtc_state) && DISPLAY_VER(i915) <= 13 && dsc) { + if (intel_dp_is_uhbr(crtc_state) && DISPLAY_VER(i915) < 14 && dsc) { int output_bpp = bpp; /* DisplayPort 2 128b/132b, bits per lane is always 32 */ int symbol_clock = crtc_state->port_clock / 32; @@ -66,6 +70,73 @@ static int intel_dp_mst_check_constraints(struct drm_i915_private *i915, int bpp return 0; } +static int intel_dp_mst_bw_overhead(const struct intel_crtc_state *crtc_state, + const struct intel_connector *connector, + bool ssc, bool dsc, int bpp_x16) +{ + const struct drm_display_mode *adjusted_mode = + &crtc_state->hw.adjusted_mode; + unsigned long flags = DRM_DP_BW_OVERHEAD_MST; + int dsc_slice_count = 0; + int overhead; + + flags |= intel_dp_is_uhbr(crtc_state) ? DRM_DP_BW_OVERHEAD_UHBR : 0; + flags |= ssc ? DRM_DP_BW_OVERHEAD_SSC_REF_CLK : 0; + flags |= crtc_state->fec_enable ? DRM_DP_BW_OVERHEAD_FEC : 0; + + if (dsc) { + flags |= DRM_DP_BW_OVERHEAD_DSC; + /* TODO: add support for bigjoiner */ + dsc_slice_count = intel_dp_dsc_get_slice_count(connector, + adjusted_mode->clock, + adjusted_mode->hdisplay, + false); + } + + overhead = drm_dp_bw_overhead(crtc_state->lane_count, + adjusted_mode->hdisplay, + dsc_slice_count, + bpp_x16, + flags); + + /* + * TODO: clarify whether a minimum required by the fixed FEC overhead + * in the bspec audio programming sequence is required here. + */ + return max(overhead, intel_dp_bw_fec_overhead(crtc_state->fec_enable)); +} + +static void intel_dp_mst_compute_m_n(const struct intel_crtc_state *crtc_state, + const struct intel_connector *connector, + int overhead, + int bpp_x16, + struct intel_link_m_n *m_n) +{ + const struct drm_display_mode *adjusted_mode = + &crtc_state->hw.adjusted_mode; + + /* TODO: Check WA 14013163432 to set data M/N for full BW utilization. */ + intel_link_compute_m_n(bpp_x16, crtc_state->lane_count, + adjusted_mode->crtc_clock, + crtc_state->port_clock, + overhead, + m_n); + + m_n->tu = DIV_ROUND_UP_ULL(mul_u32_u32(m_n->data_m, 64), m_n->data_n); +} + +static int intel_dp_mst_calc_pbn(int pixel_clock, int bpp_x16, int bw_overhead) +{ + int effective_data_rate = + intel_dp_effective_data_rate(pixel_clock, bpp_x16, bw_overhead); + + /* + * TODO: Use drm_dp_calc_pbn_mode() instead, once it's converted + * to calculate PBN with the BW overhead passed to it. + */ + return DIV_ROUND_UP(effective_data_rate * 64, 54 * 1000); +} + static int intel_dp_mst_find_vcpi_slots_for_bpp(struct intel_encoder *encoder, struct intel_crtc_state *crtc_state, int max_bpp, @@ -94,20 +165,67 @@ static int intel_dp_mst_find_vcpi_slots_for_bpp(struct intel_encoder *encoder, crtc_state->lane_count = limits->max_lane_count; crtc_state->port_clock = limits->max_rate; + if (dsc) { + if (!intel_dp_supports_fec(intel_dp, connector, crtc_state)) + return -EINVAL; + + crtc_state->fec_enable = !intel_dp_is_uhbr(crtc_state); + } + mst_state->pbn_div = drm_dp_get_vc_payload_bw(&intel_dp->mst_mgr, crtc_state->port_clock, crtc_state->lane_count); + drm_dbg_kms(&i915->drm, "Looking for slots in range min bpp %d max bpp %d\n", + min_bpp, max_bpp); + for (bpp = max_bpp; bpp >= min_bpp; bpp -= step) { + int local_bw_overhead; + int remote_bw_overhead; + int link_bpp_x16; + int remote_tu; + drm_dbg_kms(&i915->drm, "Trying bpp %d\n", bpp); ret = intel_dp_mst_check_constraints(i915, bpp, adjusted_mode, crtc_state, dsc); if (ret) continue; - crtc_state->pbn = drm_dp_calc_pbn_mode(adjusted_mode->crtc_clock, - dsc ? bpp << 4 : bpp, - dsc); + link_bpp_x16 = to_bpp_x16(dsc ? bpp : + intel_dp_output_bpp(crtc_state->output_format, bpp)); + + local_bw_overhead = intel_dp_mst_bw_overhead(crtc_state, connector, + false, dsc, link_bpp_x16); + remote_bw_overhead = intel_dp_mst_bw_overhead(crtc_state, connector, + true, dsc, link_bpp_x16); + + intel_dp_mst_compute_m_n(crtc_state, connector, + local_bw_overhead, + link_bpp_x16, + &crtc_state->dp_m_n); + + /* + * The TU size programmed to the HW determines which slots in + * an MTP frame are used for this stream, which needs to match + * the payload size programmed to the first downstream branch + * device's payload table. + * + * Note that atm the payload's PBN value DRM core sends via + * the ALLOCATE_PAYLOAD side-band message matches the payload + * size (which it calculates from the PBN value) it programs + * to the first branch device's payload table. The allocation + * in the payload table could be reduced though (to + * crtc_state->dp_m_n.tu), provided that the driver doesn't + * enable SSC on the corresponding link. + */ + crtc_state->pbn = intel_dp_mst_calc_pbn(adjusted_mode->crtc_clock, + link_bpp_x16, + remote_bw_overhead); + + remote_tu = DIV_ROUND_UP(dfixed_const(crtc_state->pbn), mst_state->pbn_div.full); + + drm_WARN_ON(&i915->drm, remote_tu < crtc_state->dp_m_n.tu); + crtc_state->dp_m_n.tu = remote_tu; slots = drm_dp_atomic_find_time_slots(state, &intel_dp->mst_mgr, connector->port, @@ -116,13 +234,9 @@ static int intel_dp_mst_find_vcpi_slots_for_bpp(struct intel_encoder *encoder, return slots; 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; + drm_WARN_ON(&i915->drm, slots != crtc_state->dp_m_n.tu); + + break; } } @@ -137,7 +251,7 @@ static int intel_dp_mst_find_vcpi_slots_for_bpp(struct intel_encoder *encoder, if (!dsc) crtc_state->pipe_bpp = bpp; else - crtc_state->dsc.compressed_bpp = bpp; + crtc_state->dsc.compressed_bpp_x16 = to_bpp_x16(bpp); drm_dbg_kms(&i915->drm, "Got %d slots for pipe bpp %d dsc %d\n", slots, bpp, dsc); } @@ -149,10 +263,7 @@ static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder, 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; - int link_bpp; /* * FIXME: allocate the BW according to link_bpp, which in the case of @@ -167,16 +278,6 @@ static int intel_dp_mst_compute_link_config(struct intel_encoder *encoder, if (slots < 0) return slots; - link_bpp = intel_dp_output_bpp(crtc_state->output_format, crtc_state->pipe_bpp); - - intel_link_compute_m_n(link_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; } @@ -188,15 +289,12 @@ static int intel_dp_dsc_mst_compute_link_config(struct intel_encoder *encoder, 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] = {}; int min_bpp, max_bpp, sink_min_bpp, sink_max_bpp; u8 dsc_max_bpc; - bool need_timeslot_recalc = false; - u32 last_compressed_bpp; + int min_compressed_bpp, max_compressed_bpp; /* Max DSC Input BPC for ICL is 10 and for TGL+ is 12 */ if (DISPLAY_VER(i915) >= 12) @@ -232,45 +330,31 @@ static int intel_dp_dsc_mst_compute_link_config(struct intel_encoder *encoder, if (max_bpp > sink_max_bpp) max_bpp = sink_max_bpp; - min_bpp = max(min_bpp, to_bpp_int_roundup(limits->link.min_bpp_x16)); - max_bpp = min(max_bpp, to_bpp_int(limits->link.max_bpp_x16)); + max_compressed_bpp = intel_dp_dsc_sink_max_compressed_bpp(connector, + crtc_state, + max_bpp / 3); + max_compressed_bpp = min(max_compressed_bpp, + to_bpp_int(limits->link.max_bpp_x16)); - slots = intel_dp_mst_find_vcpi_slots_for_bpp(encoder, crtc_state, max_bpp, - min_bpp, limits, - conn_state, 2 * 3, true); + min_compressed_bpp = intel_dp_dsc_sink_min_compressed_bpp(crtc_state); + min_compressed_bpp = max(min_compressed_bpp, + to_bpp_int_roundup(limits->link.min_bpp_x16)); - if (slots < 0) - return slots; + drm_dbg_kms(&i915->drm, "DSC Sink supported compressed min bpp %d compressed max bpp %d\n", + min_compressed_bpp, max_compressed_bpp); - last_compressed_bpp = crtc_state->dsc.compressed_bpp; + /* Align compressed bpps according to our own constraints */ + max_compressed_bpp = intel_dp_dsc_nearest_valid_bpp(i915, max_compressed_bpp, + crtc_state->pipe_bpp); + min_compressed_bpp = intel_dp_dsc_nearest_valid_bpp(i915, min_compressed_bpp, + crtc_state->pipe_bpp); - crtc_state->dsc.compressed_bpp = intel_dp_dsc_nearest_valid_bpp(i915, - last_compressed_bpp, - crtc_state->pipe_bpp); + slots = intel_dp_mst_find_vcpi_slots_for_bpp(encoder, crtc_state, max_compressed_bpp, + min_compressed_bpp, limits, + conn_state, 1, true); - 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->dsc.compressed_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; + if (slots < 0) + return slots; return 0; } @@ -297,8 +381,103 @@ static int intel_dp_mst_update_slots(struct intel_encoder *encoder, return 0; } +static bool +intel_dp_mst_dsc_source_support(const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev); + + /* + * FIXME: Enabling DSC on ICL results in blank screen and FIFO pipe / + * transcoder underruns, re-enable DSC after fixing this issue. + */ + return DISPLAY_VER(i915) >= 12 && intel_dsc_source_support(crtc_state); +} + +static int mode_hblank_period_ns(const struct drm_display_mode *mode) +{ + return DIV_ROUND_CLOSEST_ULL(mul_u32_u32(mode->htotal - mode->hdisplay, + NSEC_PER_SEC / 1000), + mode->crtc_clock); +} + +static bool +hblank_expansion_quirk_needs_dsc(const struct intel_connector *connector, + const struct intel_crtc_state *crtc_state) +{ + const struct drm_display_mode *adjusted_mode = + &crtc_state->hw.adjusted_mode; + + if (!connector->dp.dsc_hblank_expansion_quirk) + return false; + + if (mode_hblank_period_ns(adjusted_mode) > 300) + return false; + + return true; +} + +static bool +adjust_limits_for_dsc_hblank_expansion_quirk(const struct intel_connector *connector, + const struct intel_crtc_state *crtc_state, + struct link_config_limits *limits, + bool dsc) +{ + struct drm_i915_private *i915 = to_i915(connector->base.dev); + const struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + int min_bpp_x16 = limits->link.min_bpp_x16; + + if (!hblank_expansion_quirk_needs_dsc(connector, crtc_state)) + return true; + + if (!dsc) { + if (intel_dp_mst_dsc_source_support(crtc_state)) { + drm_dbg_kms(&i915->drm, + "[CRTC:%d:%s][CONNECTOR:%d:%s] DSC needed by hblank expansion quirk\n", + crtc->base.base.id, crtc->base.name, + connector->base.base.id, connector->base.name); + return false; + } + + drm_dbg_kms(&i915->drm, + "[CRTC:%d:%s][CONNECTOR:%d:%s] Increasing link min bpp to 24 due to hblank expansion quirk\n", + crtc->base.base.id, crtc->base.name, + connector->base.base.id, connector->base.name); + + if (limits->link.max_bpp_x16 < to_bpp_x16(24)) + return false; + + limits->link.min_bpp_x16 = to_bpp_x16(24); + + return true; + } + + drm_WARN_ON(&i915->drm, limits->min_rate != limits->max_rate); + + if (limits->max_rate < 540000) + min_bpp_x16 = to_bpp_x16(13); + else if (limits->max_rate < 810000) + min_bpp_x16 = to_bpp_x16(10); + + if (limits->link.min_bpp_x16 >= min_bpp_x16) + return true; + + drm_dbg_kms(&i915->drm, + "[CRTC:%d:%s][CONNECTOR:%d:%s] Increasing link min bpp to " BPP_X16_FMT " in DSC mode due to hblank expansion quirk\n", + crtc->base.base.id, crtc->base.name, + connector->base.base.id, connector->base.name, + BPP_X16_ARGS(min_bpp_x16)); + + if (limits->link.max_bpp_x16 < min_bpp_x16) + return false; + + limits->link.min_bpp_x16 = min_bpp_x16; + + return true; +} + static bool intel_dp_mst_compute_config_limits(struct intel_dp *intel_dp, + const struct intel_connector *connector, struct intel_crtc_state *crtc_state, bool dsc, struct link_config_limits *limits) @@ -326,10 +505,16 @@ intel_dp_mst_compute_config_limits(struct intel_dp *intel_dp, intel_dp_adjust_compliance_config(intel_dp, crtc_state, limits); - return intel_dp_compute_config_link_bpp_limits(intel_dp, - crtc_state, - dsc, - limits); + if (!intel_dp_compute_config_link_bpp_limits(intel_dp, + crtc_state, + dsc, + limits)) + return false; + + return adjust_limits_for_dsc_hblank_expansion_quirk(connector, + crtc_state, + limits, + dsc); } static int intel_dp_mst_compute_config(struct intel_encoder *encoder, @@ -339,12 +524,18 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_dp_mst_encoder *intel_mst = enc_to_mst(encoder); struct intel_dp *intel_dp = &intel_mst->primary->dp; + const struct intel_connector *connector = + to_intel_connector(conn_state->connector); const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; struct link_config_limits limits; bool dsc_needed; int ret = 0; + if (pipe_config->fec_enable && + !intel_dp_supports_fec(intel_dp, connector, pipe_config)) + return -EINVAL; + if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) return -EINVAL; @@ -354,6 +545,7 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder, dsc_needed = intel_dp->force_dsc_en || !intel_dp_mst_compute_config_limits(intel_dp, + connector, pipe_config, false, &limits); @@ -375,7 +567,11 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder, str_yes_no(ret), str_yes_no(intel_dp->force_dsc_en)); + if (!intel_dp_mst_dsc_source_support(pipe_config)) + return -EINVAL; + if (!intel_dp_mst_compute_config_limits(intel_dp, + connector, pipe_config, true, &limits)) @@ -418,7 +614,9 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder, intel_dp_audio_compute_config(encoder, pipe_config, conn_state); - intel_ddi_compute_min_voltage_level(dev_priv, pipe_config); + intel_ddi_compute_min_voltage_level(pipe_config); + + intel_psr_compute_config(intel_dp, pipe_config, conn_state); return 0; } @@ -459,6 +657,130 @@ intel_dp_mst_transcoder_mask(struct intel_atomic_state *state, return transcoders; } +static u8 get_pipes_downstream_of_mst_port(struct intel_atomic_state *state, + struct drm_dp_mst_topology_mgr *mst_mgr, + struct drm_dp_mst_port *parent_port) +{ + const struct intel_digital_connector_state *conn_state; + struct intel_connector *connector; + u8 mask = 0; + int i; + + for_each_new_intel_connector_in_state(state, connector, conn_state, i) { + if (!conn_state->base.crtc) + continue; + + if (&connector->mst_port->mst_mgr != mst_mgr) + continue; + + if (connector->port != parent_port && + !drm_dp_mst_port_downstream_of_parent(mst_mgr, + connector->port, + parent_port)) + continue; + + mask |= BIT(to_intel_crtc(conn_state->base.crtc)->pipe); + } + + return mask; +} + +static int intel_dp_mst_check_fec_change(struct intel_atomic_state *state, + struct drm_dp_mst_topology_mgr *mst_mgr, + struct intel_link_bw_limits *limits) +{ + struct drm_i915_private *i915 = to_i915(state->base.dev); + struct intel_crtc *crtc; + u8 mst_pipe_mask; + u8 fec_pipe_mask = 0; + int ret; + + mst_pipe_mask = get_pipes_downstream_of_mst_port(state, mst_mgr, NULL); + + for_each_intel_crtc_in_pipe_mask(&i915->drm, crtc, mst_pipe_mask) { + struct intel_crtc_state *crtc_state = + intel_atomic_get_new_crtc_state(state, crtc); + + /* Atomic connector check should've added all the MST CRTCs. */ + if (drm_WARN_ON(&i915->drm, !crtc_state)) + return -EINVAL; + + if (crtc_state->fec_enable) + fec_pipe_mask |= BIT(crtc->pipe); + } + + if (!fec_pipe_mask || mst_pipe_mask == fec_pipe_mask) + return 0; + + limits->force_fec_pipes |= mst_pipe_mask; + + ret = intel_modeset_pipes_in_mask_early(state, "MST FEC", + mst_pipe_mask); + + return ret ? : -EAGAIN; +} + +static int intel_dp_mst_check_bw(struct intel_atomic_state *state, + struct drm_dp_mst_topology_mgr *mst_mgr, + struct drm_dp_mst_topology_state *mst_state, + struct intel_link_bw_limits *limits) +{ + struct drm_dp_mst_port *mst_port; + u8 mst_port_pipes; + int ret; + + ret = drm_dp_mst_atomic_check_mgr(&state->base, mst_mgr, mst_state, &mst_port); + if (ret != -ENOSPC) + return ret; + + mst_port_pipes = get_pipes_downstream_of_mst_port(state, mst_mgr, mst_port); + + ret = intel_link_bw_reduce_bpp(state, limits, + mst_port_pipes, "MST link BW"); + + return ret ? : -EAGAIN; +} + +/** + * intel_dp_mst_atomic_check_link - check all modeset MST link configuration + * @state: intel atomic state + * @limits: link BW limits + * + * Check the link configuration for all modeset MST outputs. If the + * configuration is invalid @limits will be updated if possible to + * reduce the total BW, after which the configuration for all CRTCs in + * @state must be recomputed with the updated @limits. + * + * Returns: + * - 0 if the confugration is valid + * - %-EAGAIN, if the configuration is invalid and @limits got updated + * with fallback values with which the configuration of all CRTCs in + * @state must be recomputed + * - Other negative error, if the configuration is invalid without a + * fallback possibility, or the check failed for another reason + */ +int intel_dp_mst_atomic_check_link(struct intel_atomic_state *state, + struct intel_link_bw_limits *limits) +{ + struct drm_dp_mst_topology_mgr *mgr; + struct drm_dp_mst_topology_state *mst_state; + int ret; + int i; + + for_each_new_mst_mgr_in_state(&state->base, mgr, mst_state, i) { + ret = intel_dp_mst_check_fec_change(state, mgr, limits); + if (ret) + return ret; + + ret = intel_dp_mst_check_bw(state, mgr, mst_state, + limits); + if (ret) + return ret; + } + + return 0; +} + static int intel_dp_mst_compute_config_late(struct intel_encoder *encoder, struct intel_crtc_state *crtc_state, struct drm_connector_state *conn_state) @@ -479,19 +801,23 @@ static int intel_dp_mst_compute_config_late(struct intel_encoder *encoder, * that shares the same MST stream as mode changed, * intel_modeset_pipe_config()+intel_crtc_check_fastset() will take care to do * a fastset when possible. + * + * On TGL+ this is required since each stream go through a master transcoder, + * so if the master transcoder needs modeset, all other streams in the + * topology need a modeset. All platforms need to add the atomic state + * for all streams in the topology, since a modeset on one may require + * changing the MST link BW usage of the others, which in turn needs a + * recomputation of the corresponding CRTC states. */ static int -intel_dp_mst_atomic_master_trans_check(struct intel_connector *connector, - struct intel_atomic_state *state) +intel_dp_mst_atomic_topology_check(struct intel_connector *connector, + struct intel_atomic_state *state) { struct drm_i915_private *dev_priv = to_i915(state->base.dev); struct drm_connector_list_iter connector_list_iter; struct intel_connector *connector_iter; int ret = 0; - if (DISPLAY_VER(dev_priv) < 12) - return 0; - if (!intel_connector_needs_modeset(state, &connector->base)) return 0; @@ -545,7 +871,7 @@ intel_dp_mst_atomic_check(struct drm_connector *connector, if (ret) return ret; - ret = intel_dp_mst_atomic_master_trans_check(intel_connector, state); + ret = intel_dp_mst_atomic_topology_check(intel_connector, state); if (ret) return ret; @@ -587,10 +913,6 @@ 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 *new_mst_state = - drm_atomic_get_new_mst_topology_state(&state->base, &intel_dp->mst_mgr); - 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", @@ -598,9 +920,7 @@ static void intel_mst_disable_dp(struct intel_atomic_state *state, intel_hdcp_disable(intel_mst->connector); - drm_dp_remove_payload_part1(&intel_dp->mst_mgr, new_mst_state, new_payload); - - intel_audio_codec_disable(encoder, old_crtc_state, old_conn_state); + intel_dp_sink_disable_decompression(state, connector, old_crtc_state); } static void intel_mst_post_disable_dp(struct intel_atomic_state *state, @@ -634,6 +954,8 @@ static void intel_mst_post_disable_dp(struct intel_atomic_state *state, intel_disable_transcoder(old_crtc_state); + drm_dp_remove_payload_part1(&intel_dp->mst_mgr, new_mst_state, new_payload); + clear_act_sent(encoder, old_crtc_state); intel_de_rmw(dev_priv, TRANS_DDI_FUNC_CTL(old_crtc_state->cpu_transcoder), @@ -646,6 +968,8 @@ static void intel_mst_post_disable_dp(struct intel_atomic_state *state, intel_ddi_disable_transcoder_func(old_crtc_state); + intel_dsc_disable(old_crtc_state); + if (DISPLAY_VER(dev_priv) >= 9) skl_scaler_disable(old_crtc_state); else @@ -662,9 +986,8 @@ static void intel_mst_post_disable_dp(struct intel_atomic_state *state, * BSpec 4287: disable DIP after the transcoder is disabled and before * the transcoder clock select is set to none. */ - if (last_mst_stream) - intel_dp_set_infoframes(&dig_port->base, false, - old_crtc_state, NULL); + intel_dp_set_infoframes(&dig_port->base, false, + old_crtc_state, NULL); /* * From TGL spec: "If multi-stream slave transcoder: Configure * Transcoder Clock Select to direct no clock to the transcoder" @@ -754,6 +1077,8 @@ static void intel_mst_pre_enable_dp(struct intel_atomic_state *state, drm_dp_send_power_updown_phy(&intel_dp->mst_mgr, connector->port, true); + intel_dp_sink_enable_decompression(state, connector, pipe_config); + if (first_mst_stream) dig_port->base.pre_enable(state, &dig_port->base, pipe_config, NULL); @@ -776,6 +1101,7 @@ static void intel_mst_pre_enable_dp(struct intel_atomic_state *state, if (DISPLAY_VER(dev_priv) < 12 || !first_mst_stream) intel_ddi_enable_transcoder_clock(encoder, pipe_config); + intel_dsc_dp_pps_write(&dig_port->base, pipe_config); intel_ddi_set_dp_msa(pipe_config, conn_state); } @@ -792,11 +1118,10 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state, struct drm_dp_mst_topology_state *mst_state = drm_atomic_get_new_mst_topology_state(&state->base, &intel_dp->mst_mgr); enum transcoder trans = pipe_config->cpu_transcoder; + bool first_mst_stream = intel_dp->active_mst_links == 1; drm_WARN_ON(&dev_priv->drm, pipe_config->has_pch_encoder); - clear_act_sent(encoder, pipe_config); - if (intel_dp_is_uhbr(pipe_config)) { const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; @@ -810,6 +1135,8 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state, intel_ddi_enable_transcoder_func(encoder, pipe_config); + clear_act_sent(encoder, pipe_config); + intel_de_rmw(dev_priv, TRANS_DDI_FUNC_CTL(trans), 0, TRANS_DDI_DP_VC_PAYLOAD_ALLOC); @@ -818,15 +1145,16 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state, wait_for_act_sent(encoder, pipe_config); + if (first_mst_stream) + intel_ddi_wait_for_fec_status(encoder, pipe_config, true); + drm_dp_add_payload_part2(&intel_dp->mst_mgr, &state->base, drm_atomic_get_mst_payload_state(mst_state, connector->port)); - if (DISPLAY_VER(dev_priv) >= 14 && pipe_config->fec_enable) - intel_de_rmw(dev_priv, MTL_CHICKEN_TRANS(trans), 0, - FECSTALL_DIS_DPTSTREAM_DPTTG); - else if (DISPLAY_VER(dev_priv) >= 12 && pipe_config->fec_enable) - intel_de_rmw(dev_priv, CHICKEN_TRANS(trans), 0, - FECSTALL_DIS_DPTSTREAM_DPTTG); + if (DISPLAY_VER(dev_priv) >= 12) + intel_de_rmw(dev_priv, hsw_chicken_trans_reg(dev_priv, trans), + FECSTALL_DIS_DPTSTREAM_DPTTG, + pipe_config->fec_enable ? FECSTALL_DIS_DPTSTREAM_DPTTG : 0); intel_audio_sdp_split_update(pipe_config); @@ -834,12 +1162,7 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state, intel_crtc_vblank_on(pipe_config); - intel_audio_codec_enable(encoder, pipe_config, conn_state); - - /* Enable hdcp if it's desired */ - if (conn_state->content_protection == - DRM_MODE_CONTENT_PROTECTION_DESIRED) - intel_hdcp_enable(state, encoder, pipe_config, conn_state); + intel_hdcp_enable(state, encoder, pipe_config, conn_state); } static bool intel_dp_mst_enc_get_hw_state(struct intel_encoder *encoder, @@ -978,8 +1301,20 @@ intel_dp_mst_mode_valid_ctx(struct drm_connector *connector, if (ret) return ret; + /* + * TODO: + * - Also check if compression would allow for the mode + * - Calculate the overhead using drm_dp_bw_overhead() / + * drm_dp_bw_channel_coding_efficiency(), similarly to the + * compute config code, as drm_dp_calc_pbn_mode() doesn't + * account with all the overheads. + * - Check here and during compute config the BW reported by + * DFP_Link_Available_Payload_Bandwidth_Number (or the + * corresponding link capabilities of the sink) in case the + * stream is uncompressed for it by the last branch device. + */ if (mode_rate > max_rate || mode->clock > max_dotclk || - drm_dp_calc_pbn_mode(mode->clock, min_bpp, false) > port->full_pbn) { + drm_dp_calc_pbn_mode(mode->clock, min_bpp << 4) > port->full_pbn) { *status = MODE_CLOCK_HIGH; return 0; } @@ -1151,6 +1486,36 @@ intel_dp_mst_read_decompression_port_dsc_caps(struct intel_dp *intel_dp, intel_dp_get_dsc_sink_cap(dpcd_caps[DP_DPCD_REV], connector); } +static bool detect_dsc_hblank_expansion_quirk(const struct intel_connector *connector) +{ + struct drm_i915_private *i915 = to_i915(connector->base.dev); + struct drm_dp_desc desc; + u8 dpcd[DP_RECEIVER_CAP_SIZE]; + + if (!connector->dp.dsc_decompression_aux) + return false; + + if (drm_dp_read_desc(connector->dp.dsc_decompression_aux, + &desc, true) < 0) + return false; + + if (!drm_dp_has_quirk(&desc, + DP_DPCD_QUIRK_HBLANK_EXPANSION_REQUIRES_DSC)) + return false; + + if (drm_dp_read_dpcd_caps(connector->dp.dsc_decompression_aux, dpcd) < 0) + return false; + + if (!(dpcd[DP_RECEIVE_PORT_0_CAP_0] & DP_HBLANK_EXPANSION_CAPABLE)) + return false; + + drm_dbg_kms(&i915->drm, + "[CONNECTOR:%d:%s] DSC HBLANK expansion quirk detected\n", + connector->base.base.id, connector->base.name); + + return true; +} + static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, const char *pathprop) @@ -1173,13 +1538,10 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo intel_connector->port = port; drm_dp_mst_get_port_malloc(port); - /* - * TODO: set the AUX for the actual MST port decompressing the stream. - * At the moment the driver only supports enabling this globally in the - * first downstream MST branch, via intel_dp's (root port) AUX. - */ - intel_connector->dp.dsc_decompression_aux = &intel_dp->aux; + intel_connector->dp.dsc_decompression_aux = drm_dp_mst_dsc_aux_for_port(port); intel_dp_mst_read_decompression_port_dsc_caps(intel_dp, intel_connector); + intel_connector->dp.dsc_hblank_expansion_quirk = + detect_dsc_hblank_expansion_quirk(intel_connector); connector = &intel_connector->base; ret = drm_connector_init(dev, connector, &intel_dp_mst_connector_funcs, @@ -1272,6 +1634,8 @@ intel_dp_create_fake_mst_encoder(struct intel_digital_port *dig_port, enum pipe intel_encoder->pre_pll_enable = intel_mst_pre_pll_enable_dp; intel_encoder->pre_enable = intel_mst_pre_enable_dp; intel_encoder->enable = intel_mst_enable_dp; + intel_encoder->audio_enable = intel_audio_codec_enable; + intel_encoder->audio_disable = intel_audio_codec_disable; intel_encoder->get_hw_state = intel_dp_mst_enc_get_hw_state; intel_encoder->get_config = intel_dp_mst_enc_get_config; intel_encoder->initial_fastset_check = intel_dp_mst_initial_fastset_check; @@ -1419,3 +1783,91 @@ int intel_dp_mst_add_topology_state_for_crtc(struct intel_atomic_state *state, return 0; } + +static struct intel_connector * +get_connector_in_state_for_crtc(struct intel_atomic_state *state, + const struct intel_crtc *crtc) +{ + struct drm_connector_state *old_conn_state; + struct drm_connector_state *new_conn_state; + struct drm_connector *_connector; + int i; + + for_each_oldnew_connector_in_state(&state->base, _connector, + old_conn_state, new_conn_state, i) { + struct intel_connector *connector = + to_intel_connector(_connector); + + if (old_conn_state->crtc == &crtc->base || + new_conn_state->crtc == &crtc->base) + return connector; + } + + return NULL; +} + +/** + * intel_dp_mst_crtc_needs_modeset - check if changes in topology need to modeset the given CRTC + * @state: atomic state + * @crtc: CRTC for which to check the modeset requirement + * + * Check if any change in a MST topology requires a forced modeset on @crtc in + * this topology. One such change is enabling/disabling the DSC decompression + * state in the first branch device's UFP DPCD as required by one CRTC, while + * the other @crtc in the same topology is still active, requiring a full modeset + * on @crtc. + */ +bool intel_dp_mst_crtc_needs_modeset(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ + const struct intel_connector *crtc_connector; + const struct drm_connector_state *conn_state; + const struct drm_connector *_connector; + int i; + + if (!intel_crtc_has_type(intel_atomic_get_new_crtc_state(state, crtc), + INTEL_OUTPUT_DP_MST)) + return false; + + crtc_connector = get_connector_in_state_for_crtc(state, crtc); + + if (!crtc_connector) + /* None of the connectors in the topology needs modeset */ + return false; + + for_each_new_connector_in_state(&state->base, _connector, conn_state, i) { + const struct intel_connector *connector = + to_intel_connector(_connector); + const struct intel_crtc_state *new_crtc_state; + const struct intel_crtc_state *old_crtc_state; + struct intel_crtc *crtc_iter; + + if (connector->mst_port != crtc_connector->mst_port || + !conn_state->crtc) + continue; + + crtc_iter = to_intel_crtc(conn_state->crtc); + + new_crtc_state = intel_atomic_get_new_crtc_state(state, crtc_iter); + old_crtc_state = intel_atomic_get_old_crtc_state(state, crtc_iter); + + if (!intel_crtc_needs_modeset(new_crtc_state)) + continue; + + if (old_crtc_state->dsc.compression_enable == + new_crtc_state->dsc.compression_enable) + continue; + /* + * Toggling the decompression flag because of this stream in + * the first downstream branch device's UFP DPCD may reset the + * whole branch device. To avoid the reset while other streams + * are also active modeset the whole MST topology in this + * case. + */ + if (connector->dp.dsc_decompression_aux == + &connector->mst_port->aux) + return true; + } + + return false; +} diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.h b/drivers/gpu/drm/i915/display/intel_dp_mst.h index f1815bb722672d..8ca1d599091c69 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.h +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.h @@ -13,6 +13,7 @@ struct intel_crtc; struct intel_crtc_state; struct intel_digital_port; struct intel_dp; +struct intel_link_bw_limits; int intel_dp_mst_encoder_init(struct intel_digital_port *dig_port, int conn_id); void intel_dp_mst_encoder_cleanup(struct intel_digital_port *dig_port); @@ -22,5 +23,9 @@ 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); +int intel_dp_mst_atomic_check_link(struct intel_atomic_state *state, + struct intel_link_bw_limits *limits); +bool intel_dp_mst_crtc_needs_modeset(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 62b93d097e4478..4ca910874a4fd6 100644 --- a/drivers/gpu/drm/i915/display/intel_dpio_phy.c +++ b/drivers/gpu/drm/i915/display/intel_dpio_phy.c @@ -666,6 +666,20 @@ enum dpio_phy vlv_dig_port_to_phy(struct intel_digital_port *dig_port) } } +enum dpio_phy vlv_pipe_to_phy(enum pipe pipe) +{ + switch (pipe) { + default: + MISSING_CASE(pipe); + fallthrough; + case PIPE_A: + case PIPE_B: + return DPIO_PHY0; + case PIPE_C: + return DPIO_PHY1; + } +} + enum dpio_channel vlv_pipe_to_channel(enum pipe pipe) { switch (pipe) { @@ -689,50 +703,50 @@ void chv_set_phy_signal_level(struct intel_encoder *encoder, struct intel_digital_port *dig_port = enc_to_dig_port(encoder); struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); enum dpio_channel ch = vlv_dig_port_to_channel(dig_port); - enum pipe pipe = crtc->pipe; + enum dpio_phy phy = vlv_pipe_to_phy(crtc->pipe); u32 val; int i; vlv_dpio_get(dev_priv); /* Clear calc init */ - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW10(ch)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS01_DW10(ch)); val &= ~(DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3); val &= ~(DPIO_PCS_TX1DEEMP_MASK | DPIO_PCS_TX2DEEMP_MASK); val |= DPIO_PCS_TX1DEEMP_9P5 | DPIO_PCS_TX2DEEMP_9P5; - vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW10(ch), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS01_DW10(ch), val); if (crtc_state->lane_count > 2) { - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW10(ch)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS23_DW10(ch)); val &= ~(DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3); val &= ~(DPIO_PCS_TX1DEEMP_MASK | DPIO_PCS_TX2DEEMP_MASK); val |= DPIO_PCS_TX1DEEMP_9P5 | DPIO_PCS_TX2DEEMP_9P5; - vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS23_DW10(ch), val); } - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW9(ch)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS01_DW9(ch)); val &= ~(DPIO_PCS_TX1MARGIN_MASK | DPIO_PCS_TX2MARGIN_MASK); val |= DPIO_PCS_TX1MARGIN_000 | DPIO_PCS_TX2MARGIN_000; - vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW9(ch), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS01_DW9(ch), val); if (crtc_state->lane_count > 2) { - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW9(ch)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS23_DW9(ch)); val &= ~(DPIO_PCS_TX1MARGIN_MASK | DPIO_PCS_TX2MARGIN_MASK); val |= DPIO_PCS_TX1MARGIN_000 | DPIO_PCS_TX2MARGIN_000; - vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW9(ch), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS23_DW9(ch), val); } /* Program swing deemph */ for (i = 0; i < crtc_state->lane_count; i++) { - val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW4(ch, i)); + val = vlv_dpio_read(dev_priv, phy, CHV_TX_DW4(ch, i)); val &= ~DPIO_SWING_DEEMPH9P5_MASK; val |= deemph_reg_value << DPIO_SWING_DEEMPH9P5_SHIFT; - vlv_dpio_write(dev_priv, pipe, CHV_TX_DW4(ch, i), val); + vlv_dpio_write(dev_priv, phy, CHV_TX_DW4(ch, i), val); } /* Program swing margin */ for (i = 0; i < crtc_state->lane_count; i++) { - val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW2(ch, i)); + val = vlv_dpio_read(dev_priv, phy, CHV_TX_DW2(ch, i)); val &= ~DPIO_SWING_MARGIN000_MASK; val |= margin_reg_value << DPIO_SWING_MARGIN000_SHIFT; @@ -745,7 +759,7 @@ void chv_set_phy_signal_level(struct intel_encoder *encoder, val &= ~(0xff << DPIO_UNIQ_TRANS_SCALE_SHIFT); val |= 0x9a << DPIO_UNIQ_TRANS_SCALE_SHIFT; - vlv_dpio_write(dev_priv, pipe, CHV_TX_DW2(ch, i), val); + vlv_dpio_write(dev_priv, phy, CHV_TX_DW2(ch, i), val); } /* @@ -755,23 +769,23 @@ void chv_set_phy_signal_level(struct intel_encoder *encoder, * 27 for ch0 and ch1. */ for (i = 0; i < crtc_state->lane_count; i++) { - val = vlv_dpio_read(dev_priv, pipe, CHV_TX_DW3(ch, i)); + val = vlv_dpio_read(dev_priv, phy, CHV_TX_DW3(ch, i)); if (uniq_trans_scale) val |= DPIO_TX_UNIQ_TRANS_SCALE_EN; else val &= ~DPIO_TX_UNIQ_TRANS_SCALE_EN; - vlv_dpio_write(dev_priv, pipe, CHV_TX_DW3(ch, i), val); + vlv_dpio_write(dev_priv, phy, CHV_TX_DW3(ch, i), val); } /* Start swing calculation */ - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW10(ch)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS01_DW10(ch)); val |= DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3; - vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW10(ch), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS01_DW10(ch), val); if (crtc_state->lane_count > 2) { - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW10(ch)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS23_DW10(ch)); val |= DPIO_PCS_SWING_CALC_TX0_TX2 | DPIO_PCS_SWING_CALC_TX1_TX3; - vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW10(ch), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS23_DW10(ch), val); } vlv_dpio_put(dev_priv); @@ -782,43 +796,43 @@ void chv_data_lane_soft_reset(struct intel_encoder *encoder, bool reset) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); - enum dpio_channel ch = vlv_dig_port_to_channel(enc_to_dig_port(encoder)); struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); - enum pipe pipe = crtc->pipe; + enum dpio_channel ch = vlv_dig_port_to_channel(enc_to_dig_port(encoder)); + enum dpio_phy phy = vlv_pipe_to_phy(crtc->pipe); u32 val; - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW0(ch)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS01_DW0(ch)); if (reset) val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); else val |= DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET; - vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW0(ch), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS01_DW0(ch), val); if (crtc_state->lane_count > 2) { - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW0(ch)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS23_DW0(ch)); if (reset) val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); else val |= DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET; - vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW0(ch), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS23_DW0(ch), val); } - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW1(ch)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS01_DW1(ch)); val |= CHV_PCS_REQ_SOFTRESET_EN; if (reset) val &= ~DPIO_PCS_CLK_SOFT_RESET; else val |= DPIO_PCS_CLK_SOFT_RESET; - vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW1(ch), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS01_DW1(ch), val); if (crtc_state->lane_count > 2) { - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW1(ch)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS23_DW1(ch)); val |= CHV_PCS_REQ_SOFTRESET_EN; if (reset) val &= ~DPIO_PCS_CLK_SOFT_RESET; else val |= DPIO_PCS_CLK_SOFT_RESET; - vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW1(ch), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS23_DW1(ch), val); } } @@ -829,6 +843,7 @@ void chv_phy_pre_pll_enable(struct intel_encoder *encoder, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); enum dpio_channel ch = vlv_dig_port_to_channel(dig_port); + enum dpio_phy phy = vlv_pipe_to_phy(crtc->pipe); enum pipe pipe = crtc->pipe; unsigned int lane_mask = intel_dp_unused_lane_mask(crtc_state->lane_count); @@ -851,40 +866,40 @@ void chv_phy_pre_pll_enable(struct intel_encoder *encoder, /* program left/right clock distribution */ if (pipe != PIPE_B) { - val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW5_CH0); + val = vlv_dpio_read(dev_priv, phy, _CHV_CMN_DW5_CH0); val &= ~(CHV_BUFLEFTENA1_MASK | CHV_BUFRIGHTENA1_MASK); if (ch == DPIO_CH0) val |= CHV_BUFLEFTENA1_FORCE; if (ch == DPIO_CH1) val |= CHV_BUFRIGHTENA1_FORCE; - vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW5_CH0, val); + vlv_dpio_write(dev_priv, phy, _CHV_CMN_DW5_CH0, val); } else { - val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW1_CH1); + val = vlv_dpio_read(dev_priv, phy, _CHV_CMN_DW1_CH1); val &= ~(CHV_BUFLEFTENA2_MASK | CHV_BUFRIGHTENA2_MASK); if (ch == DPIO_CH0) val |= CHV_BUFLEFTENA2_FORCE; if (ch == DPIO_CH1) val |= CHV_BUFRIGHTENA2_FORCE; - vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW1_CH1, val); + vlv_dpio_write(dev_priv, phy, _CHV_CMN_DW1_CH1, val); } /* program clock channel usage */ - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW8(ch)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS01_DW8(ch)); val |= CHV_PCS_USEDCLKCHANNEL_OVRRIDE; if (pipe != PIPE_B) val &= ~CHV_PCS_USEDCLKCHANNEL; else val |= CHV_PCS_USEDCLKCHANNEL; - vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW8(ch), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS01_DW8(ch), val); if (crtc_state->lane_count > 2) { - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW8(ch)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS23_DW8(ch)); val |= CHV_PCS_USEDCLKCHANNEL_OVRRIDE; if (pipe != PIPE_B) val &= ~CHV_PCS_USEDCLKCHANNEL; else val |= CHV_PCS_USEDCLKCHANNEL; - vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW8(ch), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS23_DW8(ch), val); } /* @@ -892,12 +907,12 @@ void chv_phy_pre_pll_enable(struct intel_encoder *encoder, * matches the pipe, but here we need to * pick the CL based on the port. */ - val = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW19(ch)); + val = vlv_dpio_read(dev_priv, phy, CHV_CMN_DW19(ch)); if (pipe != PIPE_B) val &= ~CHV_CMN_USEDCLKCHANNEL; else val |= CHV_CMN_USEDCLKCHANNEL; - vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW19(ch), val); + vlv_dpio_write(dev_priv, phy, CHV_CMN_DW19(ch), val); vlv_dpio_put(dev_priv); } @@ -910,21 +925,21 @@ void chv_phy_pre_encoder_enable(struct intel_encoder *encoder, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); enum dpio_channel ch = vlv_dig_port_to_channel(dig_port); - enum pipe pipe = crtc->pipe; + enum dpio_phy phy = vlv_pipe_to_phy(crtc->pipe); int data, i, stagger; u32 val; vlv_dpio_get(dev_priv); /* allow hardware to manage TX FIFO reset source */ - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW11(ch)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS01_DW11(ch)); val &= ~DPIO_LANEDESKEW_STRAP_OVRD; - vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW11(ch), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS01_DW11(ch), val); if (crtc_state->lane_count > 2) { - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW11(ch)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS23_DW11(ch)); val &= ~DPIO_LANEDESKEW_STRAP_OVRD; - vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW11(ch), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS23_DW11(ch), val); } /* Program Tx lane latency optimal setting*/ @@ -934,7 +949,7 @@ void chv_phy_pre_encoder_enable(struct intel_encoder *encoder, data = 0x0; else data = (i == 1) ? 0x0 : 0x1; - vlv_dpio_write(dev_priv, pipe, CHV_TX_DW14(ch, i), + vlv_dpio_write(dev_priv, phy, CHV_TX_DW14(ch, i), data << DPIO_UPAR_SHIFT); } @@ -950,17 +965,17 @@ void chv_phy_pre_encoder_enable(struct intel_encoder *encoder, else stagger = 0x2; - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW11(ch)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS01_DW11(ch)); val |= DPIO_TX2_STAGGER_MASK(0x1f); - vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW11(ch), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS01_DW11(ch), val); if (crtc_state->lane_count > 2) { - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS23_DW11(ch)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS23_DW11(ch)); val |= DPIO_TX2_STAGGER_MASK(0x1f); - vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW11(ch), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS23_DW11(ch), val); } - vlv_dpio_write(dev_priv, pipe, VLV_PCS01_DW12(ch), + vlv_dpio_write(dev_priv, phy, VLV_PCS01_DW12(ch), DPIO_LANESTAGGER_STRAP(stagger) | DPIO_LANESTAGGER_STRAP_OVRD | DPIO_TX1_STAGGER_MASK(0x1f) | @@ -968,7 +983,7 @@ void chv_phy_pre_encoder_enable(struct intel_encoder *encoder, DPIO_TX2_STAGGER_MULT(0)); if (crtc_state->lane_count > 2) { - vlv_dpio_write(dev_priv, pipe, VLV_PCS23_DW12(ch), + vlv_dpio_write(dev_priv, phy, VLV_PCS23_DW12(ch), DPIO_LANESTAGGER_STRAP(stagger) | DPIO_LANESTAGGER_STRAP_OVRD | DPIO_TX1_STAGGER_MASK(0x1f) | @@ -998,19 +1013,20 @@ void chv_phy_post_pll_disable(struct intel_encoder *encoder, { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); enum pipe pipe = to_intel_crtc(old_crtc_state->uapi.crtc)->pipe; + enum dpio_phy phy = vlv_pipe_to_phy(pipe); u32 val; vlv_dpio_get(dev_priv); /* disable left/right clock distribution */ if (pipe != PIPE_B) { - val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW5_CH0); + val = vlv_dpio_read(dev_priv, phy, _CHV_CMN_DW5_CH0); val &= ~(CHV_BUFLEFTENA1_MASK | CHV_BUFRIGHTENA1_MASK); - vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW5_CH0, val); + vlv_dpio_write(dev_priv, phy, _CHV_CMN_DW5_CH0, val); } else { - val = vlv_dpio_read(dev_priv, pipe, _CHV_CMN_DW1_CH1); + val = vlv_dpio_read(dev_priv, phy, _CHV_CMN_DW1_CH1); val &= ~(CHV_BUFLEFTENA2_MASK | CHV_BUFRIGHTENA2_MASK); - vlv_dpio_write(dev_priv, pipe, _CHV_CMN_DW1_CH1, val); + vlv_dpio_write(dev_priv, phy, _CHV_CMN_DW1_CH1, val); } vlv_dpio_put(dev_priv); @@ -1036,22 +1052,22 @@ void vlv_set_phy_signal_level(struct intel_encoder *encoder, struct intel_digital_port *dig_port = enc_to_dig_port(encoder); struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); enum dpio_channel port = vlv_dig_port_to_channel(dig_port); - enum pipe pipe = crtc->pipe; + enum dpio_phy phy = vlv_pipe_to_phy(crtc->pipe); vlv_dpio_get(dev_priv); - vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), 0x00000000); - vlv_dpio_write(dev_priv, pipe, VLV_TX_DW4(port), demph_reg_value); - vlv_dpio_write(dev_priv, pipe, VLV_TX_DW2(port), + vlv_dpio_write(dev_priv, phy, VLV_TX_DW5(port), 0x00000000); + vlv_dpio_write(dev_priv, phy, VLV_TX_DW4(port), demph_reg_value); + vlv_dpio_write(dev_priv, phy, VLV_TX_DW2(port), uniqtranscale_reg_value); - vlv_dpio_write(dev_priv, pipe, VLV_TX_DW3(port), 0x0C782040); + vlv_dpio_write(dev_priv, phy, VLV_TX_DW3(port), 0x0C782040); if (tx3_demph) - vlv_dpio_write(dev_priv, pipe, VLV_TX3_DW4(port), tx3_demph); + vlv_dpio_write(dev_priv, phy, VLV_TX3_DW4(port), tx3_demph); - vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW11(port), 0x00030000); - vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW9(port), preemph_reg_value); - vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), DPIO_TX_OCALINIT_EN); + vlv_dpio_write(dev_priv, phy, VLV_PCS_DW11(port), 0x00030000); + vlv_dpio_write(dev_priv, phy, VLV_PCS_DW9(port), preemph_reg_value); + vlv_dpio_write(dev_priv, phy, VLV_TX_DW5(port), DPIO_TX_OCALINIT_EN); vlv_dpio_put(dev_priv); } @@ -1063,24 +1079,24 @@ void vlv_phy_pre_pll_enable(struct intel_encoder *encoder, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); enum dpio_channel port = vlv_dig_port_to_channel(dig_port); - enum pipe pipe = crtc->pipe; + enum dpio_phy phy = vlv_pipe_to_phy(crtc->pipe); /* Program Tx lane resets to default */ vlv_dpio_get(dev_priv); - vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW0(port), + vlv_dpio_write(dev_priv, phy, VLV_PCS_DW0(port), DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET); - vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW1(port), + vlv_dpio_write(dev_priv, phy, VLV_PCS_DW1(port), DPIO_PCS_CLK_CRI_RXEB_EIOS_EN | DPIO_PCS_CLK_CRI_RXDIGFILTSG_EN | (1<uapi.crtc); enum dpio_channel port = vlv_dig_port_to_channel(dig_port); enum pipe pipe = crtc->pipe; + enum dpio_phy phy = vlv_pipe_to_phy(pipe); u32 val; vlv_dpio_get(dev_priv); /* Enable clock channels for this port */ - val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW8(port)); + val = vlv_dpio_read(dev_priv, phy, VLV_PCS01_DW8(port)); val = 0; if (pipe) val |= (1<<21); else val &= ~(1<<21); val |= 0x001000c4; - vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW8(port), val); + vlv_dpio_write(dev_priv, phy, VLV_PCS_DW8(port), val); /* Program lane clock */ - vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW14(port), 0x00760018); - vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW23(port), 0x00400888); + vlv_dpio_write(dev_priv, phy, VLV_PCS_DW14(port), 0x00760018); + vlv_dpio_write(dev_priv, phy, VLV_PCS_DW23(port), 0x00400888); vlv_dpio_put(dev_priv); } @@ -1122,10 +1139,10 @@ void vlv_phy_reset_lanes(struct intel_encoder *encoder, struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc); enum dpio_channel port = vlv_dig_port_to_channel(dig_port); - enum pipe pipe = crtc->pipe; + enum dpio_phy phy = vlv_pipe_to_phy(crtc->pipe); vlv_dpio_get(dev_priv); - vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW0(port), 0x00000000); - vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW1(port), 0x00e00060); + vlv_dpio_write(dev_priv, phy, VLV_PCS_DW0(port), 0x00000000); + vlv_dpio_write(dev_priv, phy, VLV_PCS_DW1(port), 0x00e00060); vlv_dpio_put(dev_priv); } diff --git a/drivers/gpu/drm/i915/display/intel_dpio_phy.h b/drivers/gpu/drm/i915/display/intel_dpio_phy.h index 4d43dbbdf81cec..9adc4e8c173816 100644 --- a/drivers/gpu/drm/i915/display/intel_dpio_phy.h +++ b/drivers/gpu/drm/i915/display/intel_dpio_phy.h @@ -44,6 +44,7 @@ u8 bxt_ddi_phy_get_lane_lat_optim_mask(struct intel_encoder *encoder); enum dpio_channel vlv_dig_port_to_channel(struct intel_digital_port *dig_port); enum dpio_phy vlv_dig_port_to_phy(struct intel_digital_port *dig_port); +enum dpio_phy vlv_pipe_to_phy(enum pipe pipe); enum dpio_channel vlv_pipe_to_channel(enum pipe pipe); void chv_set_phy_signal_level(struct intel_encoder *encoder, @@ -116,6 +117,10 @@ static inline enum dpio_phy vlv_dig_port_to_phy(struct intel_digital_port *dig_p { return DPIO_PHY0; } +static inline enum dpio_phy vlv_pipe_to_phy(enum pipe pipe) +{ + return DPIO_PHY0; +} static inline enum dpio_channel vlv_pipe_to_channel(enum pipe pipe) { return DPIO_CH0; diff --git a/drivers/gpu/drm/i915/display/intel_dpll.c b/drivers/gpu/drm/i915/display/intel_dpll.c index d41c1dc9f66c65..3038655377ea49 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll.c +++ b/drivers/gpu/drm/i915/display/intel_dpll.c @@ -16,6 +16,7 @@ #include "intel_dpio_phy.h" #include "intel_dpll.h" #include "intel_lvds.h" +#include "intel_lvds_regs.h" #include "intel_panel.h" #include "intel_pps.h" #include "intel_snps_phy.h" @@ -311,7 +312,7 @@ static const struct intel_limit intel_limits_bxt = { * divided-down version of it. */ /* m1 is reserved as 0 in Pineview, n is a ring counter */ -int pnv_calc_dpll_params(int refclk, struct dpll *clock) +static int pnv_calc_dpll_params(int refclk, struct dpll *clock) { clock->m = clock->m2 + 2; clock->p = clock->p1 * clock->p2; @@ -342,7 +343,7 @@ int i9xx_calc_dpll_params(int refclk, struct dpll *clock) return clock->dot; } -int vlv_calc_dpll_params(int refclk, struct dpll *clock) +static int vlv_calc_dpll_params(int refclk, struct dpll *clock) { clock->m = clock->m1 * clock->m2; clock->p = clock->p1 * clock->p2 * 5; @@ -368,6 +369,176 @@ int chv_calc_dpll_params(int refclk, struct dpll *clock) return clock->dot; } +static int i9xx_pll_refclk(struct drm_device *dev, + const struct intel_crtc_state *pipe_config) +{ + struct drm_i915_private *dev_priv = to_i915(dev); + u32 dpll = pipe_config->dpll_hw_state.dpll; + + if ((dpll & PLL_REF_INPUT_MASK) == PLLB_REF_INPUT_SPREADSPECTRUMIN) + return dev_priv->display.vbt.lvds_ssc_freq; + else if (HAS_PCH_SPLIT(dev_priv)) + return 120000; + else if (DISPLAY_VER(dev_priv) != 2) + return 96000; + else + return 48000; +} + +/* Returns the clock of the currently programmed mode of the given pipe. */ +void i9xx_crtc_clock_get(struct intel_crtc *crtc, + struct intel_crtc_state *pipe_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); + u32 dpll = pipe_config->dpll_hw_state.dpll; + u32 fp; + struct dpll clock; + int port_clock; + int refclk = i9xx_pll_refclk(dev, pipe_config); + + if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0) + fp = pipe_config->dpll_hw_state.fp0; + else + fp = pipe_config->dpll_hw_state.fp1; + + clock.m1 = (fp & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT; + if (IS_PINEVIEW(dev_priv)) { + clock.n = ffs((fp & FP_N_PINEVIEW_DIV_MASK) >> FP_N_DIV_SHIFT) - 1; + clock.m2 = (fp & FP_M2_PINEVIEW_DIV_MASK) >> FP_M2_DIV_SHIFT; + } else { + clock.n = (fp & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT; + clock.m2 = (fp & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT; + } + + if (DISPLAY_VER(dev_priv) != 2) { + if (IS_PINEVIEW(dev_priv)) + clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_PINEVIEW) >> + DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW); + else + clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK) >> + DPLL_FPA01_P1_POST_DIV_SHIFT); + + switch (dpll & DPLL_MODE_MASK) { + case DPLLB_MODE_DAC_SERIAL: + clock.p2 = dpll & DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 ? + 5 : 10; + break; + case DPLLB_MODE_LVDS: + clock.p2 = dpll & DPLLB_LVDS_P2_CLOCK_DIV_7 ? + 7 : 14; + break; + default: + drm_dbg_kms(&dev_priv->drm, + "Unknown DPLL mode %08x in programmed " + "mode\n", (int)(dpll & DPLL_MODE_MASK)); + return; + } + + if (IS_PINEVIEW(dev_priv)) + port_clock = pnv_calc_dpll_params(refclk, &clock); + else + port_clock = i9xx_calc_dpll_params(refclk, &clock); + } else { + enum pipe lvds_pipe; + + if (IS_I85X(dev_priv) && + intel_lvds_port_enabled(dev_priv, LVDS, &lvds_pipe) && + lvds_pipe == crtc->pipe) { + u32 lvds = intel_de_read(dev_priv, LVDS); + + clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS) >> + DPLL_FPA01_P1_POST_DIV_SHIFT); + + if (lvds & LVDS_CLKB_POWER_UP) + clock.p2 = 7; + else + clock.p2 = 14; + } else { + if (dpll & PLL_P1_DIVIDE_BY_TWO) + clock.p1 = 2; + else { + clock.p1 = ((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830) >> + DPLL_FPA01_P1_POST_DIV_SHIFT) + 2; + } + if (dpll & PLL_P2_DIVIDE_BY_4) + clock.p2 = 4; + else + clock.p2 = 2; + } + + port_clock = i9xx_calc_dpll_params(refclk, &clock); + } + + /* + * This value includes pixel_multiplier. We will use + * port_clock to compute adjusted_mode.crtc_clock in the + * encoder's get_config() function. + */ + pipe_config->port_clock = port_clock; +} + +void vlv_crtc_clock_get(struct intel_crtc *crtc, + struct intel_crtc_state *pipe_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); + enum dpio_phy phy = vlv_pipe_to_phy(crtc->pipe); + struct dpll clock; + u32 mdiv; + int refclk = 100000; + + /* In case of DSI, DPLL will not be used */ + if ((pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) == 0) + return; + + vlv_dpio_get(dev_priv); + mdiv = vlv_dpio_read(dev_priv, phy, VLV_PLL_DW3(crtc->pipe)); + vlv_dpio_put(dev_priv); + + clock.m1 = (mdiv >> DPIO_M1DIV_SHIFT) & 7; + clock.m2 = mdiv & DPIO_M2DIV_MASK; + clock.n = (mdiv >> DPIO_N_SHIFT) & 0xf; + clock.p1 = (mdiv >> DPIO_P1_SHIFT) & 7; + clock.p2 = (mdiv >> DPIO_P2_SHIFT) & 0x1f; + + pipe_config->port_clock = vlv_calc_dpll_params(refclk, &clock); +} + +void chv_crtc_clock_get(struct intel_crtc *crtc, + struct intel_crtc_state *pipe_config) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); + enum dpio_channel port = vlv_pipe_to_channel(crtc->pipe); + enum dpio_phy phy = vlv_pipe_to_phy(crtc->pipe); + struct dpll clock; + u32 cmn_dw13, pll_dw0, pll_dw1, pll_dw2, pll_dw3; + int refclk = 100000; + + /* In case of DSI, DPLL will not be used */ + if ((pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) == 0) + return; + + vlv_dpio_get(dev_priv); + cmn_dw13 = vlv_dpio_read(dev_priv, phy, CHV_CMN_DW13(port)); + pll_dw0 = vlv_dpio_read(dev_priv, phy, CHV_PLL_DW0(port)); + pll_dw1 = vlv_dpio_read(dev_priv, phy, CHV_PLL_DW1(port)); + pll_dw2 = vlv_dpio_read(dev_priv, phy, CHV_PLL_DW2(port)); + pll_dw3 = vlv_dpio_read(dev_priv, phy, CHV_PLL_DW3(port)); + vlv_dpio_put(dev_priv); + + clock.m1 = (pll_dw1 & 0x7) == DPIO_CHV_M1_DIV_BY_2 ? 2 : 0; + clock.m2 = (pll_dw0 & 0xff) << 22; + if (pll_dw3 & DPIO_CHV_FRAC_DIV_EN) + clock.m2 |= pll_dw2 & 0x3fffff; + clock.n = (pll_dw1 >> DPIO_CHV_N_DIV_SHIFT) & 0xf; + clock.p1 = (cmn_dw13 >> DPIO_CHV_P1_DIV_SHIFT) & 0x7; + clock.p2 = (cmn_dw13 >> DPIO_CHV_P2_DIV_SHIFT) & 0x1f; + + pipe_config->port_clock = chv_calc_dpll_params(refclk, &clock); +} + /* * Returns whether the given set of divisors are valid for a given refclk with * the given connectors. @@ -1003,12 +1174,10 @@ static int dg2_crtc_compute_clock(struct intel_atomic_state *state, static int mtl_crtc_compute_clock(struct intel_atomic_state *state, struct intel_crtc *crtc) { - struct drm_i915_private *i915 = to_i915(state->base.dev); struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc); struct intel_encoder *encoder = intel_get_crtc_new_encoder(state, crtc_state); - enum phy phy = intel_port_to_phy(i915, encoder->port); int ret; ret = intel_cx0pll_calc_state(crtc_state, encoder); @@ -1016,10 +1185,7 @@ static int mtl_crtc_compute_clock(struct intel_atomic_state *state, return ret; /* TODO: Do the readback via intel_compute_shared_dplls() */ - if (intel_is_c10phy(i915, phy)) - crtc_state->port_clock = intel_c10pll_calc_port_clock(encoder, &crtc_state->cx0pll_state.c10); - else - crtc_state->port_clock = intel_c20pll_calc_port_clock(encoder, &crtc_state->cx0pll_state.c20); + crtc_state->port_clock = intel_cx0pll_calc_port_clock(encoder, &crtc_state->cx0pll_state); crtc_state->hw.adjusted_mode.crtc_clock = intel_crtc_dotclock(crtc_state); @@ -1645,7 +1811,7 @@ void i9xx_enable_pll(const struct intel_crtc_state *crtc_state) } static void vlv_pllb_recal_opamp(struct drm_i915_private *dev_priv, - enum pipe pipe) + enum dpio_phy phy) { u32 reg_val; @@ -1653,30 +1819,31 @@ static void vlv_pllb_recal_opamp(struct drm_i915_private *dev_priv, * PLLB opamp always calibrates to max value of 0x3f, force enable it * and set it to a reasonable value instead. */ - reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW9(1)); + reg_val = vlv_dpio_read(dev_priv, phy, VLV_PLL_DW9(1)); reg_val &= 0xffffff00; reg_val |= 0x00000030; - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9(1), reg_val); + vlv_dpio_write(dev_priv, phy, VLV_PLL_DW9(1), reg_val); - reg_val = vlv_dpio_read(dev_priv, pipe, VLV_REF_DW13); + reg_val = vlv_dpio_read(dev_priv, phy, VLV_REF_DW13); reg_val &= 0x00ffffff; reg_val |= 0x8c000000; - vlv_dpio_write(dev_priv, pipe, VLV_REF_DW13, reg_val); + vlv_dpio_write(dev_priv, phy, VLV_REF_DW13, reg_val); - reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW9(1)); + reg_val = vlv_dpio_read(dev_priv, phy, VLV_PLL_DW9(1)); reg_val &= 0xffffff00; - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9(1), reg_val); + vlv_dpio_write(dev_priv, phy, VLV_PLL_DW9(1), reg_val); - reg_val = vlv_dpio_read(dev_priv, pipe, VLV_REF_DW13); + reg_val = vlv_dpio_read(dev_priv, phy, VLV_REF_DW13); reg_val &= 0x00ffffff; reg_val |= 0xb0000000; - vlv_dpio_write(dev_priv, pipe, VLV_REF_DW13, reg_val); + vlv_dpio_write(dev_priv, phy, VLV_REF_DW13, reg_val); } static void vlv_prepare_pll(const struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + enum dpio_phy phy = vlv_pipe_to_phy(crtc->pipe); enum pipe pipe = crtc->pipe; u32 mdiv; u32 bestn, bestm1, bestm2, bestp1, bestp2; @@ -1694,18 +1861,18 @@ static void vlv_prepare_pll(const struct intel_crtc_state *crtc_state) /* PLL B needs special handling */ if (pipe == PIPE_B) - vlv_pllb_recal_opamp(dev_priv, pipe); + vlv_pllb_recal_opamp(dev_priv, phy); /* Set up Tx target for periodic Rcomp update */ - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9_BCAST, 0x0100000f); + vlv_dpio_write(dev_priv, phy, VLV_PLL_DW9_BCAST, 0x0100000f); /* Disable target IRef on PLL */ - reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW8(pipe)); + reg_val = vlv_dpio_read(dev_priv, phy, VLV_PLL_DW8(pipe)); reg_val &= 0x00ffffff; - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW8(pipe), reg_val); + vlv_dpio_write(dev_priv, phy, VLV_PLL_DW8(pipe), reg_val); /* Disable fast lock */ - vlv_dpio_write(dev_priv, pipe, VLV_CMN_DW0, 0x610); + vlv_dpio_write(dev_priv, phy, VLV_CMN_DW0, 0x610); /* Set idtafcrecal before PLL is enabled */ mdiv = ((bestm1 << DPIO_M1DIV_SHIFT) | (bestm2 & DPIO_M2DIV_MASK)); @@ -1719,46 +1886,46 @@ static void vlv_prepare_pll(const struct intel_crtc_state *crtc_state) * Note: don't use the DAC post divider as it seems unstable. */ mdiv |= (DPIO_POST_DIV_HDMIDP << DPIO_POST_DIV_SHIFT); - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW3(pipe), mdiv); + vlv_dpio_write(dev_priv, phy, VLV_PLL_DW3(pipe), mdiv); mdiv |= DPIO_ENABLE_CALIBRATION; - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW3(pipe), mdiv); + vlv_dpio_write(dev_priv, phy, VLV_PLL_DW3(pipe), mdiv); /* Set HBR and RBR LPF coefficients */ if (crtc_state->port_clock == 162000 || intel_crtc_has_type(crtc_state, INTEL_OUTPUT_ANALOG) || intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW10(pipe), + vlv_dpio_write(dev_priv, phy, VLV_PLL_DW10(pipe), 0x009f0003); else - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW10(pipe), + vlv_dpio_write(dev_priv, phy, VLV_PLL_DW10(pipe), 0x00d0000f); if (intel_crtc_has_dp_encoder(crtc_state)) { /* Use SSC source */ if (pipe == PIPE_A) - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), + vlv_dpio_write(dev_priv, phy, VLV_PLL_DW5(pipe), 0x0df40000); else - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), + vlv_dpio_write(dev_priv, phy, VLV_PLL_DW5(pipe), 0x0df70000); } else { /* HDMI or VGA */ /* Use bend source */ if (pipe == PIPE_A) - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), + vlv_dpio_write(dev_priv, phy, VLV_PLL_DW5(pipe), 0x0df70000); else - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe), + vlv_dpio_write(dev_priv, phy, VLV_PLL_DW5(pipe), 0x0df40000); } - coreclk = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW7(pipe)); + coreclk = vlv_dpio_read(dev_priv, phy, VLV_PLL_DW7(pipe)); coreclk = (coreclk & 0x0000ff00) | 0x01c00000; if (intel_crtc_has_dp_encoder(crtc_state)) coreclk |= 0x01000000; - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW7(pipe), coreclk); + vlv_dpio_write(dev_priv, phy, VLV_PLL_DW7(pipe), coreclk); - vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW11(pipe), 0x87871000); + vlv_dpio_write(dev_priv, phy, VLV_PLL_DW11(pipe), 0x87871000); vlv_dpio_put(dev_priv); } @@ -1809,6 +1976,7 @@ static void chv_prepare_pll(const struct intel_crtc_state *crtc_state) struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); enum pipe pipe = crtc->pipe; enum dpio_channel port = vlv_pipe_to_channel(pipe); + enum dpio_phy phy = vlv_pipe_to_phy(crtc->pipe); u32 loopfilter, tribuf_calcntr; u32 bestm2, bestp1, bestp2, bestm2_frac; u32 dpio_val; @@ -1825,39 +1993,39 @@ static void chv_prepare_pll(const struct intel_crtc_state *crtc_state) vlv_dpio_get(dev_priv); /* p1 and p2 divider */ - vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW13(port), + vlv_dpio_write(dev_priv, phy, CHV_CMN_DW13(port), 5 << DPIO_CHV_S1_DIV_SHIFT | bestp1 << DPIO_CHV_P1_DIV_SHIFT | bestp2 << DPIO_CHV_P2_DIV_SHIFT | 1 << DPIO_CHV_K_DIV_SHIFT); /* Feedback post-divider - m2 */ - vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW0(port), bestm2); + vlv_dpio_write(dev_priv, phy, CHV_PLL_DW0(port), bestm2); /* Feedback refclk divider - n and m1 */ - vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW1(port), + vlv_dpio_write(dev_priv, phy, CHV_PLL_DW1(port), DPIO_CHV_M1_DIV_BY_2 | 1 << DPIO_CHV_N_DIV_SHIFT); /* M2 fraction division */ - vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW2(port), bestm2_frac); + vlv_dpio_write(dev_priv, phy, CHV_PLL_DW2(port), bestm2_frac); /* M2 fraction division enable */ - dpio_val = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW3(port)); + dpio_val = vlv_dpio_read(dev_priv, phy, CHV_PLL_DW3(port)); dpio_val &= ~(DPIO_CHV_FEEDFWD_GAIN_MASK | DPIO_CHV_FRAC_DIV_EN); dpio_val |= (2 << DPIO_CHV_FEEDFWD_GAIN_SHIFT); if (bestm2_frac) dpio_val |= DPIO_CHV_FRAC_DIV_EN; - vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW3(port), dpio_val); + vlv_dpio_write(dev_priv, phy, CHV_PLL_DW3(port), dpio_val); /* Program digital lock detect threshold */ - dpio_val = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW9(port)); + dpio_val = vlv_dpio_read(dev_priv, phy, CHV_PLL_DW9(port)); dpio_val &= ~(DPIO_CHV_INT_LOCK_THRESHOLD_MASK | DPIO_CHV_INT_LOCK_THRESHOLD_SEL_COARSE); dpio_val |= (0x5 << DPIO_CHV_INT_LOCK_THRESHOLD_SHIFT); if (!bestm2_frac) dpio_val |= DPIO_CHV_INT_LOCK_THRESHOLD_SEL_COARSE; - vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW9(port), dpio_val); + vlv_dpio_write(dev_priv, phy, CHV_PLL_DW9(port), dpio_val); /* Loop filter */ if (vco == 5400000) { @@ -1882,16 +2050,16 @@ static void chv_prepare_pll(const struct intel_crtc_state *crtc_state) loopfilter |= (0x3 << DPIO_CHV_GAIN_CTRL_SHIFT); tribuf_calcntr = 0; } - vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW6(port), loopfilter); + vlv_dpio_write(dev_priv, phy, CHV_PLL_DW6(port), loopfilter); - dpio_val = vlv_dpio_read(dev_priv, pipe, CHV_PLL_DW8(port)); + dpio_val = vlv_dpio_read(dev_priv, phy, CHV_PLL_DW8(port)); dpio_val &= ~DPIO_CHV_TDC_TARGET_CNT_MASK; dpio_val |= (tribuf_calcntr << DPIO_CHV_TDC_TARGET_CNT_SHIFT); - vlv_dpio_write(dev_priv, pipe, CHV_PLL_DW8(port), dpio_val); + vlv_dpio_write(dev_priv, phy, CHV_PLL_DW8(port), dpio_val); /* AFC Recal */ - vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port), - vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port)) | + vlv_dpio_write(dev_priv, phy, CHV_CMN_DW14(port), + vlv_dpio_read(dev_priv, phy, CHV_CMN_DW14(port)) | DPIO_AFC_RECAL); vlv_dpio_put(dev_priv); @@ -1903,14 +2071,15 @@ static void _chv_enable_pll(const struct intel_crtc_state *crtc_state) struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); enum pipe pipe = crtc->pipe; enum dpio_channel port = vlv_pipe_to_channel(pipe); + enum dpio_phy phy = vlv_pipe_to_phy(crtc->pipe); u32 tmp; vlv_dpio_get(dev_priv); /* Enable back the 10bit clock to display controller */ - tmp = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port)); + tmp = vlv_dpio_read(dev_priv, phy, CHV_CMN_DW14(port)); tmp |= DPIO_DCLKP_EN; - vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port), tmp); + vlv_dpio_write(dev_priv, phy, CHV_CMN_DW14(port), tmp); vlv_dpio_put(dev_priv); @@ -2031,6 +2200,7 @@ void vlv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) void chv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) { enum dpio_channel port = vlv_pipe_to_channel(pipe); + enum dpio_phy phy = vlv_pipe_to_phy(pipe); u32 val; /* Make sure the pipe isn't still relying on us */ @@ -2047,9 +2217,9 @@ void chv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) vlv_dpio_get(dev_priv); /* Disable 10bit clock to display controller */ - val = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port)); + val = vlv_dpio_read(dev_priv, phy, CHV_CMN_DW14(port)); val &= ~DPIO_DCLKP_EN; - vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port), val); + vlv_dpio_write(dev_priv, phy, CHV_CMN_DW14(port), val); vlv_dpio_put(dev_priv); } diff --git a/drivers/gpu/drm/i915/display/intel_dpll.h b/drivers/gpu/drm/i915/display/intel_dpll.h index bbc30542f29fa6..ac01bb19cc6c33 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll.h +++ b/drivers/gpu/drm/i915/display/intel_dpll.h @@ -20,8 +20,6 @@ int intel_dpll_crtc_compute_clock(struct intel_atomic_state *state, struct intel_crtc *crtc); int intel_dpll_crtc_get_shared_dpll(struct intel_atomic_state *state, struct intel_crtc *crtc); -int vlv_calc_dpll_params(int refclk, struct dpll *clock); -int pnv_calc_dpll_params(int refclk, struct dpll *clock); int i9xx_calc_dpll_params(int refclk, struct dpll *clock); u32 i9xx_dpll_compute_fp(const struct dpll *dpll); void vlv_compute_dpll(struct intel_crtc_state *crtc_state); @@ -41,6 +39,13 @@ bool bxt_find_best_dpll(struct intel_crtc_state *crtc_state, struct dpll *best_clock); int chv_calc_dpll_params(int refclk, struct dpll *pll_clock); +void i9xx_crtc_clock_get(struct intel_crtc *crtc, + struct intel_crtc_state *pipe_config); +void vlv_crtc_clock_get(struct intel_crtc *crtc, + struct intel_crtc_state *pipe_config); +void chv_crtc_clock_get(struct intel_crtc *crtc, + struct intel_crtc_state *pipe_config); + void assert_pll_enabled(struct drm_i915_private *i915, enum pipe pipe); void assert_pll_disabled(struct drm_i915_private *i915, enum pipe pipe); diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c index 399653a20f987d..ef57dad1a9cb79 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.c @@ -219,6 +219,26 @@ intel_tc_pll_enable_reg(struct drm_i915_private *i915, return MG_PLL_ENABLE(tc_port); } +static void _intel_enable_shared_dpll(struct drm_i915_private *i915, + struct intel_shared_dpll *pll) +{ + if (pll->info->power_domain) + pll->wakeref = intel_display_power_get(i915, pll->info->power_domain); + + pll->info->funcs->enable(i915, pll); + pll->on = true; +} + +static void _intel_disable_shared_dpll(struct drm_i915_private *i915, + struct intel_shared_dpll *pll) +{ + pll->info->funcs->disable(i915, pll); + pll->on = false; + + if (pll->info->power_domain) + intel_display_power_put(i915, pll->info->power_domain, pll->wakeref); +} + /** * intel_enable_shared_dpll - enable a CRTC's shared DPLL * @crtc_state: CRTC, and its state, which has a shared DPLL @@ -258,8 +278,8 @@ void intel_enable_shared_dpll(const struct intel_crtc_state *crtc_state) drm_WARN_ON(&i915->drm, pll->on); drm_dbg_kms(&i915->drm, "enabling %s\n", pll->info->name); - pll->info->funcs->enable(i915, pll); - pll->on = true; + + _intel_enable_shared_dpll(i915, pll); out: mutex_unlock(&i915->display.dpll.lock); @@ -304,8 +324,8 @@ void intel_disable_shared_dpll(const struct intel_crtc_state *crtc_state) goto out; drm_dbg_kms(&i915->drm, "disabling %s\n", pll->info->name); - pll->info->funcs->disable(i915, pll); - pll->on = false; + + _intel_disable_shared_dpll(i915, pll); out: mutex_unlock(&i915->display.dpll.lock); @@ -631,9 +651,9 @@ static const struct intel_shared_dpll_funcs ibx_pch_dpll_funcs = { }; static const struct dpll_info pch_plls[] = { - { "PCH DPLL A", &ibx_pch_dpll_funcs, DPLL_ID_PCH_PLL_A, 0 }, - { "PCH DPLL B", &ibx_pch_dpll_funcs, DPLL_ID_PCH_PLL_B, 0 }, - { }, + { .name = "PCH DPLL A", .funcs = &ibx_pch_dpll_funcs, .id = DPLL_ID_PCH_PLL_A, }, + { .name = "PCH DPLL B", .funcs = &ibx_pch_dpll_funcs, .id = DPLL_ID_PCH_PLL_B, }, + {} }; static const struct intel_dpll_mgr pch_pll_mgr = { @@ -1239,13 +1259,16 @@ static const struct intel_shared_dpll_funcs hsw_ddi_lcpll_funcs = { }; static const struct dpll_info hsw_plls[] = { - { "WRPLL 1", &hsw_ddi_wrpll_funcs, DPLL_ID_WRPLL1, 0 }, - { "WRPLL 2", &hsw_ddi_wrpll_funcs, DPLL_ID_WRPLL2, 0 }, - { "SPLL", &hsw_ddi_spll_funcs, DPLL_ID_SPLL, 0 }, - { "LCPLL 810", &hsw_ddi_lcpll_funcs, DPLL_ID_LCPLL_810, INTEL_DPLL_ALWAYS_ON }, - { "LCPLL 1350", &hsw_ddi_lcpll_funcs, DPLL_ID_LCPLL_1350, INTEL_DPLL_ALWAYS_ON }, - { "LCPLL 2700", &hsw_ddi_lcpll_funcs, DPLL_ID_LCPLL_2700, INTEL_DPLL_ALWAYS_ON }, - { }, + { .name = "WRPLL 1", .funcs = &hsw_ddi_wrpll_funcs, .id = DPLL_ID_WRPLL1, }, + { .name = "WRPLL 2", .funcs = &hsw_ddi_wrpll_funcs, .id = DPLL_ID_WRPLL2, }, + { .name = "SPLL", .funcs = &hsw_ddi_spll_funcs, .id = DPLL_ID_SPLL, }, + { .name = "LCPLL 810", .funcs = &hsw_ddi_lcpll_funcs, .id = DPLL_ID_LCPLL_810, + .flags = INTEL_DPLL_ALWAYS_ON, }, + { .name = "LCPLL 1350", .funcs = &hsw_ddi_lcpll_funcs, .id = DPLL_ID_LCPLL_1350, + .flags = INTEL_DPLL_ALWAYS_ON, }, + { .name = "LCPLL 2700", .funcs = &hsw_ddi_lcpll_funcs, .id = DPLL_ID_LCPLL_2700, + .flags = INTEL_DPLL_ALWAYS_ON, }, + {} }; static const struct intel_dpll_mgr hsw_pll_mgr = { @@ -1921,11 +1944,12 @@ static const struct intel_shared_dpll_funcs skl_ddi_dpll0_funcs = { }; static const struct dpll_info skl_plls[] = { - { "DPLL 0", &skl_ddi_dpll0_funcs, DPLL_ID_SKL_DPLL0, INTEL_DPLL_ALWAYS_ON }, - { "DPLL 1", &skl_ddi_pll_funcs, DPLL_ID_SKL_DPLL1, 0 }, - { "DPLL 2", &skl_ddi_pll_funcs, DPLL_ID_SKL_DPLL2, 0 }, - { "DPLL 3", &skl_ddi_pll_funcs, DPLL_ID_SKL_DPLL3, 0 }, - { }, + { .name = "DPLL 0", .funcs = &skl_ddi_dpll0_funcs, .id = DPLL_ID_SKL_DPLL0, + .flags = INTEL_DPLL_ALWAYS_ON, }, + { .name = "DPLL 1", .funcs = &skl_ddi_pll_funcs, .id = DPLL_ID_SKL_DPLL1, }, + { .name = "DPLL 2", .funcs = &skl_ddi_pll_funcs, .id = DPLL_ID_SKL_DPLL2, }, + { .name = "DPLL 3", .funcs = &skl_ddi_pll_funcs, .id = DPLL_ID_SKL_DPLL3, }, + {} }; static const struct intel_dpll_mgr skl_pll_mgr = { @@ -2376,10 +2400,10 @@ static const struct intel_shared_dpll_funcs bxt_ddi_pll_funcs = { }; static const struct dpll_info bxt_plls[] = { - { "PORT PLL A", &bxt_ddi_pll_funcs, DPLL_ID_SKL_DPLL0, 0 }, - { "PORT PLL B", &bxt_ddi_pll_funcs, DPLL_ID_SKL_DPLL1, 0 }, - { "PORT PLL C", &bxt_ddi_pll_funcs, DPLL_ID_SKL_DPLL2, 0 }, - { }, + { .name = "PORT PLL A", .funcs = &bxt_ddi_pll_funcs, .id = DPLL_ID_SKL_DPLL0, }, + { .name = "PORT PLL B", .funcs = &bxt_ddi_pll_funcs, .id = DPLL_ID_SKL_DPLL1, }, + { .name = "PORT PLL C", .funcs = &bxt_ddi_pll_funcs, .id = DPLL_ID_SKL_DPLL2, }, + {} }; static const struct intel_dpll_mgr bxt_pll_mgr = { @@ -3834,18 +3858,6 @@ static void combo_pll_enable(struct drm_i915_private *i915, { i915_reg_t enable_reg = intel_combo_pll_enable_reg(i915, pll); - if ((IS_JASPERLAKE(i915) || IS_ELKHARTLAKE(i915)) && - pll->info->id == DPLL_ID_EHL_DPLL4) { - - /* - * We need to disable DC states when this DPLL is enabled. - * This can be done by taking a reference on DPLL4 power - * domain. - */ - pll->wakeref = intel_display_power_get(i915, - POWER_DOMAIN_DC_OFF); - } - icl_pll_power_enable(i915, pll, enable_reg); icl_dpll_write(i915, pll); @@ -3941,11 +3953,6 @@ static void combo_pll_disable(struct drm_i915_private *i915, i915_reg_t enable_reg = intel_combo_pll_enable_reg(i915, pll); icl_pll_disable(i915, pll, enable_reg); - - if ((IS_JASPERLAKE(i915) || IS_ELKHARTLAKE(i915)) && - pll->info->id == DPLL_ID_EHL_DPLL4) - intel_display_power_put(i915, POWER_DOMAIN_DC_OFF, - pll->wakeref); } static void tbt_pll_disable(struct drm_i915_private *i915, @@ -4014,14 +4021,14 @@ static const struct intel_shared_dpll_funcs mg_pll_funcs = { }; static const struct dpll_info icl_plls[] = { - { "DPLL 0", &combo_pll_funcs, DPLL_ID_ICL_DPLL0, 0 }, - { "DPLL 1", &combo_pll_funcs, DPLL_ID_ICL_DPLL1, 0 }, - { "TBT PLL", &tbt_pll_funcs, DPLL_ID_ICL_TBTPLL, 0 }, - { "MG PLL 1", &mg_pll_funcs, DPLL_ID_ICL_MGPLL1, 0 }, - { "MG PLL 2", &mg_pll_funcs, DPLL_ID_ICL_MGPLL2, 0 }, - { "MG PLL 3", &mg_pll_funcs, DPLL_ID_ICL_MGPLL3, 0 }, - { "MG PLL 4", &mg_pll_funcs, DPLL_ID_ICL_MGPLL4, 0 }, - { }, + { .name = "DPLL 0", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL0, }, + { .name = "DPLL 1", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL1, }, + { .name = "TBT PLL", .funcs = &tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL, }, + { .name = "MG PLL 1", .funcs = &mg_pll_funcs, .id = DPLL_ID_ICL_MGPLL1, }, + { .name = "MG PLL 2", .funcs = &mg_pll_funcs, .id = DPLL_ID_ICL_MGPLL2, }, + { .name = "MG PLL 3", .funcs = &mg_pll_funcs, .id = DPLL_ID_ICL_MGPLL3, }, + { .name = "MG PLL 4", .funcs = &mg_pll_funcs, .id = DPLL_ID_ICL_MGPLL4, }, + {} }; static const struct intel_dpll_mgr icl_pll_mgr = { @@ -4035,10 +4042,11 @@ static const struct intel_dpll_mgr icl_pll_mgr = { }; static const struct dpll_info ehl_plls[] = { - { "DPLL 0", &combo_pll_funcs, DPLL_ID_ICL_DPLL0, 0 }, - { "DPLL 1", &combo_pll_funcs, DPLL_ID_ICL_DPLL1, 0 }, - { "DPLL 4", &combo_pll_funcs, DPLL_ID_EHL_DPLL4, 0 }, - { }, + { .name = "DPLL 0", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL0, }, + { .name = "DPLL 1", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL1, }, + { .name = "DPLL 4", .funcs = &combo_pll_funcs, .id = DPLL_ID_EHL_DPLL4, + .power_domain = POWER_DOMAIN_DC_OFF, }, + {} }; static const struct intel_dpll_mgr ehl_pll_mgr = { @@ -4058,16 +4066,16 @@ static const struct intel_shared_dpll_funcs dkl_pll_funcs = { }; static const struct dpll_info tgl_plls[] = { - { "DPLL 0", &combo_pll_funcs, DPLL_ID_ICL_DPLL0, 0 }, - { "DPLL 1", &combo_pll_funcs, DPLL_ID_ICL_DPLL1, 0 }, - { "TBT PLL", &tbt_pll_funcs, DPLL_ID_ICL_TBTPLL, 0 }, - { "TC PLL 1", &dkl_pll_funcs, DPLL_ID_ICL_MGPLL1, 0 }, - { "TC PLL 2", &dkl_pll_funcs, DPLL_ID_ICL_MGPLL2, 0 }, - { "TC PLL 3", &dkl_pll_funcs, DPLL_ID_ICL_MGPLL3, 0 }, - { "TC PLL 4", &dkl_pll_funcs, DPLL_ID_ICL_MGPLL4, 0 }, - { "TC PLL 5", &dkl_pll_funcs, DPLL_ID_TGL_MGPLL5, 0 }, - { "TC PLL 6", &dkl_pll_funcs, DPLL_ID_TGL_MGPLL6, 0 }, - { }, + { .name = "DPLL 0", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL0, }, + { .name = "DPLL 1", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL1, }, + { .name = "TBT PLL", .funcs = &tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL, }, + { .name = "TC PLL 1", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL1, }, + { .name = "TC PLL 2", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL2, }, + { .name = "TC PLL 3", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL3, }, + { .name = "TC PLL 4", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL4, }, + { .name = "TC PLL 5", .funcs = &dkl_pll_funcs, .id = DPLL_ID_TGL_MGPLL5, }, + { .name = "TC PLL 6", .funcs = &dkl_pll_funcs, .id = DPLL_ID_TGL_MGPLL6, }, + {} }; static const struct intel_dpll_mgr tgl_pll_mgr = { @@ -4081,10 +4089,10 @@ static const struct intel_dpll_mgr tgl_pll_mgr = { }; static const struct dpll_info rkl_plls[] = { - { "DPLL 0", &combo_pll_funcs, DPLL_ID_ICL_DPLL0, 0 }, - { "DPLL 1", &combo_pll_funcs, DPLL_ID_ICL_DPLL1, 0 }, - { "DPLL 4", &combo_pll_funcs, DPLL_ID_EHL_DPLL4, 0 }, - { }, + { .name = "DPLL 0", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL0, }, + { .name = "DPLL 1", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL1, }, + { .name = "DPLL 4", .funcs = &combo_pll_funcs, .id = DPLL_ID_EHL_DPLL4, }, + {} }; static const struct intel_dpll_mgr rkl_pll_mgr = { @@ -4097,11 +4105,11 @@ static const struct intel_dpll_mgr rkl_pll_mgr = { }; static const struct dpll_info dg1_plls[] = { - { "DPLL 0", &combo_pll_funcs, DPLL_ID_DG1_DPLL0, 0 }, - { "DPLL 1", &combo_pll_funcs, DPLL_ID_DG1_DPLL1, 0 }, - { "DPLL 2", &combo_pll_funcs, DPLL_ID_DG1_DPLL2, 0 }, - { "DPLL 3", &combo_pll_funcs, DPLL_ID_DG1_DPLL3, 0 }, - { }, + { .name = "DPLL 0", .funcs = &combo_pll_funcs, .id = DPLL_ID_DG1_DPLL0, }, + { .name = "DPLL 1", .funcs = &combo_pll_funcs, .id = DPLL_ID_DG1_DPLL1, }, + { .name = "DPLL 2", .funcs = &combo_pll_funcs, .id = DPLL_ID_DG1_DPLL2, }, + { .name = "DPLL 3", .funcs = &combo_pll_funcs, .id = DPLL_ID_DG1_DPLL3, }, + {} }; static const struct intel_dpll_mgr dg1_pll_mgr = { @@ -4114,11 +4122,11 @@ static const struct intel_dpll_mgr dg1_pll_mgr = { }; static const struct dpll_info adls_plls[] = { - { "DPLL 0", &combo_pll_funcs, DPLL_ID_ICL_DPLL0, 0 }, - { "DPLL 1", &combo_pll_funcs, DPLL_ID_ICL_DPLL1, 0 }, - { "DPLL 2", &combo_pll_funcs, DPLL_ID_DG1_DPLL2, 0 }, - { "DPLL 3", &combo_pll_funcs, DPLL_ID_DG1_DPLL3, 0 }, - { }, + { .name = "DPLL 0", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL0, }, + { .name = "DPLL 1", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL1, }, + { .name = "DPLL 2", .funcs = &combo_pll_funcs, .id = DPLL_ID_DG1_DPLL2, }, + { .name = "DPLL 3", .funcs = &combo_pll_funcs, .id = DPLL_ID_DG1_DPLL3, }, + {} }; static const struct intel_dpll_mgr adls_pll_mgr = { @@ -4131,14 +4139,14 @@ static const struct intel_dpll_mgr adls_pll_mgr = { }; static const struct dpll_info adlp_plls[] = { - { "DPLL 0", &combo_pll_funcs, DPLL_ID_ICL_DPLL0, 0 }, - { "DPLL 1", &combo_pll_funcs, DPLL_ID_ICL_DPLL1, 0 }, - { "TBT PLL", &tbt_pll_funcs, DPLL_ID_ICL_TBTPLL, 0 }, - { "TC PLL 1", &dkl_pll_funcs, DPLL_ID_ICL_MGPLL1, 0 }, - { "TC PLL 2", &dkl_pll_funcs, DPLL_ID_ICL_MGPLL2, 0 }, - { "TC PLL 3", &dkl_pll_funcs, DPLL_ID_ICL_MGPLL3, 0 }, - { "TC PLL 4", &dkl_pll_funcs, DPLL_ID_ICL_MGPLL4, 0 }, - { }, + { .name = "DPLL 0", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL0, }, + { .name = "DPLL 1", .funcs = &combo_pll_funcs, .id = DPLL_ID_ICL_DPLL1, }, + { .name = "TBT PLL", .funcs = &tbt_pll_funcs, .id = DPLL_ID_ICL_TBTPLL, }, + { .name = "TC PLL 1", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL1, }, + { .name = "TC PLL 2", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL2, }, + { .name = "TC PLL 3", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL3, }, + { .name = "TC PLL 4", .funcs = &dkl_pll_funcs, .id = DPLL_ID_ICL_MGPLL4, }, + {} }; static const struct intel_dpll_mgr adlp_pll_mgr = { @@ -4365,12 +4373,8 @@ static void readout_dpll_hw_state(struct drm_i915_private *i915, pll->on = intel_dpll_get_hw_state(i915, pll, &pll->state.hw_state); - if ((IS_JASPERLAKE(i915) || IS_ELKHARTLAKE(i915)) && - pll->on && - pll->info->id == DPLL_ID_EHL_DPLL4) { - pll->wakeref = intel_display_power_get(i915, - POWER_DOMAIN_DC_OFF); - } + if (pll->on && pll->info->power_domain) + pll->wakeref = intel_display_power_get(i915, pll->info->power_domain); pll->state.pipe_mask = 0; for_each_intel_crtc(&i915->drm, crtc) { @@ -4417,8 +4421,7 @@ static void sanitize_dpll_state(struct drm_i915_private *i915, "%s enabled but not in use, disabling\n", pll->info->name); - pll->info->funcs->disable(i915, pll); - pll->on = false; + _intel_disable_shared_dpll(i915, pll); } void intel_dpll_sanitize_state(struct drm_i915_private *i915) @@ -4534,7 +4537,7 @@ void intel_shared_dpll_state_verify(struct intel_atomic_state *state, "pll active mismatch (didn't expect pipe %c in active mask (0x%x))\n", pipe_name(crtc->pipe), pll->active_mask); I915_STATE_WARN(i915, pll->state.pipe_mask & pipe_mask, - "pll enabled crtcs mismatch (found %x in enabled mask (0x%x))\n", + "pll enabled crtcs mismatch (found pipe %c in enabled mask (0x%x))\n", pipe_name(crtc->pipe), pll->state.pipe_mask); } } diff --git a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h index dd4796a61751f0..2e7ea0d8d3ffb3 100644 --- a/drivers/gpu/drm/i915/display/intel_dpll_mgr.h +++ b/drivers/gpu/drm/i915/display/intel_dpll_mgr.h @@ -27,6 +27,7 @@ #include +#include "intel_display_power.h" #include "intel_wakeref.h" #define for_each_shared_dpll(__i915, __pll, __i) \ @@ -270,6 +271,11 @@ struct dpll_info { */ enum intel_dpll_id id; + /** + * @power_domain: extra power domain required by the DPLL + */ + enum intel_display_power_domain power_domain; + #define INTEL_DPLL_ALWAYS_ON (1 << 0) /** * @flags: diff --git a/drivers/gpu/drm/i915/display/intel_dpt.c b/drivers/gpu/drm/i915/display/intel_dpt.c index 48582b31b7f7f9..b29bceff73f23f 100644 --- a/drivers/gpu/drm/i915/display/intel_dpt.c +++ b/drivers/gpu/drm/i915/display/intel_dpt.c @@ -9,8 +9,6 @@ #include "gt/gen8_ppgtt.h" #include "i915_drv.h" -#include "i915_reg.h" -#include "intel_de.h" #include "intel_display_types.h" #include "intel_dpt.h" #include "intel_fb.h" @@ -318,25 +316,3 @@ void intel_dpt_destroy(struct i915_address_space *vm) i915_vm_put(&dpt->vm); } -void intel_dpt_configure(struct intel_crtc *crtc) -{ - struct drm_i915_private *i915 = to_i915(crtc->base.dev); - - if (DISPLAY_VER(i915) == 14) { - enum pipe pipe = crtc->pipe; - enum plane_id plane_id; - - for_each_plane_id_on_crtc(crtc, plane_id) { - if (plane_id == PLANE_CURSOR) - continue; - - intel_de_rmw(i915, PLANE_CHICKEN(pipe, plane_id), - PLANE_CHICKEN_DISABLE_DPT, - i915->params.enable_dpt ? 0 : PLANE_CHICKEN_DISABLE_DPT); - } - } else if (DISPLAY_VER(i915) == 13) { - intel_de_rmw(i915, CHICKEN_MISC_2, - CHICKEN_MISC_DISABLE_DPT, - i915->params.enable_dpt ? 0 : CHICKEN_MISC_DISABLE_DPT); - } -} diff --git a/drivers/gpu/drm/i915/display/intel_dpt.h b/drivers/gpu/drm/i915/display/intel_dpt.h index d9a16655018514..e18a9f767b112a 100644 --- a/drivers/gpu/drm/i915/display/intel_dpt.h +++ b/drivers/gpu/drm/i915/display/intel_dpt.h @@ -10,7 +10,6 @@ struct drm_i915_private; struct i915_address_space; struct i915_vma; -struct intel_crtc; struct intel_framebuffer; void intel_dpt_destroy(struct i915_address_space *vm); @@ -20,6 +19,5 @@ void intel_dpt_suspend(struct drm_i915_private *i915); void intel_dpt_resume(struct drm_i915_private *i915); struct i915_address_space * intel_dpt_create(struct intel_framebuffer *fb); -void intel_dpt_configure(struct intel_crtc *crtc); #endif /* __INTEL_DPT_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_dpt_common.c b/drivers/gpu/drm/i915/display/intel_dpt_common.c new file mode 100644 index 00000000000000..cdba47165c04c9 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_dpt_common.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2023 Intel Corporation + */ + +#include "i915_reg.h" +#include "intel_de.h" +#include "intel_display_types.h" +#include "intel_dpt_common.h" + +void intel_dpt_configure(struct intel_crtc *crtc) +{ + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + + if (DISPLAY_VER(i915) == 14) { + enum pipe pipe = crtc->pipe; + enum plane_id plane_id; + + for_each_plane_id_on_crtc(crtc, plane_id) { + if (plane_id == PLANE_CURSOR) + continue; + + intel_de_rmw(i915, PLANE_CHICKEN(pipe, plane_id), + PLANE_CHICKEN_DISABLE_DPT, + i915->display.params.enable_dpt ? 0 : + PLANE_CHICKEN_DISABLE_DPT); + } + } else if (DISPLAY_VER(i915) == 13) { + intel_de_rmw(i915, CHICKEN_MISC_2, + CHICKEN_MISC_DISABLE_DPT, + i915->display.params.enable_dpt ? 0 : + CHICKEN_MISC_DISABLE_DPT); + } +} diff --git a/drivers/gpu/drm/i915/display/intel_dpt_common.h b/drivers/gpu/drm/i915/display/intel_dpt_common.h new file mode 100644 index 00000000000000..6d7de405126a58 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_dpt_common.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef __INTEL_DPT_COMMON_H__ +#define __INTEL_DPT_COMMON_H__ + +struct intel_crtc; + +void intel_dpt_configure(struct intel_crtc *crtc); + +#endif /* __INTEL_DPT_COMMON_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_dsb.c b/drivers/gpu/drm/i915/display/intel_dsb.c index 7fd6280c54a79a..482c28b5c2de54 100644 --- a/drivers/gpu/drm/i915/display/intel_dsb.c +++ b/drivers/gpu/drm/i915/display/intel_dsb.c @@ -4,9 +4,6 @@ * */ -#include "gem/i915_gem_internal.h" -#include "gem/i915_gem_lmem.h" - #include "i915_drv.h" #include "i915_irq.h" #include "i915_reg.h" @@ -14,12 +11,13 @@ #include "intel_de.h" #include "intel_display_types.h" #include "intel_dsb.h" +#include "intel_dsb_buffer.h" #include "intel_dsb_regs.h" #include "intel_vblank.h" #include "intel_vrr.h" #include "skl_watermark.h" -struct i915_vma; +#define CACHELINE_BYTES 64 enum dsb_id { INVALID_DSB = -1, @@ -32,8 +30,7 @@ enum dsb_id { struct intel_dsb { enum dsb_id id; - u32 *cmd_buf; - struct i915_vma *vma; + struct intel_dsb_buffer dsb_buf; struct intel_crtc *crtc; /* @@ -109,15 +106,17 @@ static void intel_dsb_dump(struct intel_dsb *dsb) { struct intel_crtc *crtc = dsb->crtc; struct drm_i915_private *i915 = to_i915(crtc->base.dev); - const u32 *buf = dsb->cmd_buf; int i; drm_dbg_kms(&i915->drm, "[CRTC:%d:%s] DSB %d commands {\n", crtc->base.base.id, crtc->base.name, dsb->id); for (i = 0; i < ALIGN(dsb->free_pos, 64 / 4); i += 4) drm_dbg_kms(&i915->drm, - " 0x%08x: 0x%08x 0x%08x 0x%08x 0x%08x\n", - i * 4, buf[i], buf[i+1], buf[i+2], buf[i+3]); + " 0x%08x: 0x%08x 0x%08x 0x%08x 0x%08x\n", i * 4, + intel_dsb_buffer_read(&dsb->dsb_buf, i), + intel_dsb_buffer_read(&dsb->dsb_buf, i + 1), + intel_dsb_buffer_read(&dsb->dsb_buf, i + 2), + intel_dsb_buffer_read(&dsb->dsb_buf, i + 3)); drm_dbg_kms(&i915->drm, "}\n"); } @@ -129,8 +128,6 @@ static bool is_dsb_busy(struct drm_i915_private *i915, enum pipe pipe, static void intel_dsb_emit(struct intel_dsb *dsb, u32 ldw, u32 udw) { - u32 *buf = dsb->cmd_buf; - if (!assert_dsb_has_room(dsb)) return; @@ -139,14 +136,13 @@ static void intel_dsb_emit(struct intel_dsb *dsb, u32 ldw, u32 udw) dsb->ins_start_offset = dsb->free_pos; - buf[dsb->free_pos++] = ldw; - buf[dsb->free_pos++] = udw; + intel_dsb_buffer_write(&dsb->dsb_buf, dsb->free_pos++, ldw); + intel_dsb_buffer_write(&dsb->dsb_buf, dsb->free_pos++, udw); } static bool intel_dsb_prev_ins_is_write(struct intel_dsb *dsb, u32 opcode, i915_reg_t reg) { - const u32 *buf = dsb->cmd_buf; u32 prev_opcode, prev_reg; /* @@ -157,8 +153,10 @@ static bool intel_dsb_prev_ins_is_write(struct intel_dsb *dsb, if (dsb->free_pos == 0) return false; - prev_opcode = buf[dsb->ins_start_offset + 1] & ~DSB_REG_VALUE_MASK; - prev_reg = buf[dsb->ins_start_offset + 1] & DSB_REG_VALUE_MASK; + prev_opcode = intel_dsb_buffer_read(&dsb->dsb_buf, + dsb->ins_start_offset + 1) & ~DSB_REG_VALUE_MASK; + prev_reg = intel_dsb_buffer_read(&dsb->dsb_buf, + dsb->ins_start_offset + 1) & DSB_REG_VALUE_MASK; return prev_opcode == opcode && prev_reg == i915_mmio_reg_offset(reg); } @@ -191,6 +189,8 @@ static bool intel_dsb_prev_ins_is_indexed_write(struct intel_dsb *dsb, i915_reg_ void intel_dsb_reg_write(struct intel_dsb *dsb, i915_reg_t reg, u32 val) { + u32 old_val; + /* * For example the buffer will look like below for 3 dwords for auto * increment register: @@ -214,31 +214,32 @@ void intel_dsb_reg_write(struct intel_dsb *dsb, (DSB_BYTE_EN << DSB_BYTE_EN_SHIFT) | i915_mmio_reg_offset(reg)); } else { - u32 *buf = dsb->cmd_buf; - if (!assert_dsb_has_room(dsb)) return; /* convert to indexed write? */ if (intel_dsb_prev_ins_is_mmio_write(dsb, reg)) { - u32 prev_val = buf[dsb->ins_start_offset + 0]; + u32 prev_val = intel_dsb_buffer_read(&dsb->dsb_buf, + dsb->ins_start_offset + 0); - 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; + intel_dsb_buffer_write(&dsb->dsb_buf, + dsb->ins_start_offset + 0, 1); /* count */ + intel_dsb_buffer_write(&dsb->dsb_buf, dsb->ins_start_offset + 1, + (DSB_OPCODE_INDEXED_WRITE << DSB_OPCODE_SHIFT) | + i915_mmio_reg_offset(reg)); + intel_dsb_buffer_write(&dsb->dsb_buf, dsb->ins_start_offset + 2, prev_val); dsb->free_pos++; } - buf[dsb->free_pos++] = val; + intel_dsb_buffer_write(&dsb->dsb_buf, dsb->free_pos++, val); /* Update the count */ - buf[dsb->ins_start_offset]++; + old_val = intel_dsb_buffer_read(&dsb->dsb_buf, dsb->ins_start_offset); + intel_dsb_buffer_write(&dsb->dsb_buf, dsb->ins_start_offset, old_val + 1); /* 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_buffer_write(&dsb->dsb_buf, dsb->free_pos, 0); } } @@ -297,8 +298,8 @@ static void intel_dsb_align_tail(struct intel_dsb *dsb) aligned_tail = ALIGN(tail, CACHELINE_BYTES); if (aligned_tail > tail) - memset(&dsb->cmd_buf[dsb->free_pos], 0, - aligned_tail - tail); + intel_dsb_buffer_memset(&dsb->dsb_buf, dsb->free_pos, 0, + aligned_tail - tail); dsb->free_pos = aligned_tail / 4; } @@ -317,7 +318,7 @@ void intel_dsb_finish(struct intel_dsb *dsb) intel_dsb_align_tail(dsb); - i915_gem_object_flush_map(dsb->vma->obj); + intel_dsb_buffer_flush_map(&dsb->dsb_buf); } static int intel_dsb_dewake_scanline(const struct intel_crtc_state *crtc_state) @@ -361,7 +362,7 @@ static void _intel_dsb_commit(struct intel_dsb *dsb, u32 ctrl, ctrl | DSB_ENABLE); intel_de_write_fw(dev_priv, DSB_HEAD(pipe, dsb->id), - i915_ggtt_offset(dsb->vma)); + intel_dsb_buffer_ggtt_offset(&dsb->dsb_buf)); if (dewake_scanline >= 0) { int diff, hw_dewake_scanline; @@ -383,7 +384,7 @@ static void _intel_dsb_commit(struct intel_dsb *dsb, u32 ctrl, } intel_de_write_fw(dev_priv, DSB_TAIL(pipe, dsb->id), - i915_ggtt_offset(dsb->vma) + tail); + intel_dsb_buffer_ggtt_offset(&dsb->dsb_buf) + tail); } /** @@ -408,7 +409,7 @@ void intel_dsb_wait(struct intel_dsb *dsb) enum pipe pipe = crtc->pipe; if (wait_for(!is_dsb_busy(dev_priv, pipe, dsb->id), 1)) { - u32 offset = i915_ggtt_offset(dsb->vma); + u32 offset = intel_dsb_buffer_ggtt_offset(&dsb->dsb_buf); intel_de_write_fw(dev_priv, DSB_CTRL(pipe, dsb->id), DSB_ENABLE | DSB_HALT); @@ -445,12 +446,9 @@ struct intel_dsb *intel_dsb_prepare(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); - struct drm_i915_gem_object *obj; intel_wakeref_t wakeref; struct intel_dsb *dsb; - struct i915_vma *vma; unsigned int size; - u32 *buf; if (!HAS_DSB(i915)) return NULL; @@ -464,37 +462,13 @@ struct intel_dsb *intel_dsb_prepare(const struct intel_crtc_state *crtc_state, /* ~1 qword per instruction, full cachelines */ size = ALIGN(max_cmds * 8, CACHELINE_BYTES); - if (HAS_LMEM(i915)) { - obj = i915_gem_object_create_lmem(i915, PAGE_ALIGN(size), - I915_BO_ALLOC_CONTIGUOUS); - if (IS_ERR(obj)) - goto out_put_rpm; - } else { - obj = i915_gem_object_create_internal(i915, PAGE_ALIGN(size)); - if (IS_ERR(obj)) - goto out_put_rpm; - - i915_gem_object_set_cache_coherency(obj, I915_CACHE_NONE); - } - - vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, 0); - if (IS_ERR(vma)) { - i915_gem_object_put(obj); - 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); + if (!intel_dsb_buffer_create(crtc, &dsb->dsb_buf, size)) 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; @@ -522,6 +496,6 @@ out: */ void intel_dsb_cleanup(struct intel_dsb *dsb) { - i915_vma_unpin_and_release(&dsb->vma, I915_VMA_RELEASE_MAP); + intel_dsb_buffer_cleanup(&dsb->dsb_buf); kfree(dsb); } diff --git a/drivers/gpu/drm/i915/display/intel_dsb_buffer.c b/drivers/gpu/drm/i915/display/intel_dsb_buffer.c new file mode 100644 index 00000000000000..c77d48bda26ac6 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_dsb_buffer.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright 2023, Intel Corporation. + */ + +#include "gem/i915_gem_internal.h" +#include "gem/i915_gem_lmem.h" +#include "i915_drv.h" +#include "i915_vma.h" +#include "intel_display_types.h" +#include "intel_dsb_buffer.h" + +u32 intel_dsb_buffer_ggtt_offset(struct intel_dsb_buffer *dsb_buf) +{ + return i915_ggtt_offset(dsb_buf->vma); +} + +void intel_dsb_buffer_write(struct intel_dsb_buffer *dsb_buf, u32 idx, u32 val) +{ + dsb_buf->cmd_buf[idx] = val; +} + +u32 intel_dsb_buffer_read(struct intel_dsb_buffer *dsb_buf, u32 idx) +{ + return dsb_buf->cmd_buf[idx]; +} + +void intel_dsb_buffer_memset(struct intel_dsb_buffer *dsb_buf, u32 idx, u32 val, size_t size) +{ + WARN_ON(idx > (dsb_buf->buf_size - size) / sizeof(*dsb_buf->cmd_buf)); + + memset(&dsb_buf->cmd_buf[idx], val, size); +} + +bool intel_dsb_buffer_create(struct intel_crtc *crtc, struct intel_dsb_buffer *dsb_buf, size_t size) +{ + struct drm_i915_private *i915 = to_i915(crtc->base.dev); + struct drm_i915_gem_object *obj; + struct i915_vma *vma; + u32 *buf; + + if (HAS_LMEM(i915)) { + obj = i915_gem_object_create_lmem(i915, PAGE_ALIGN(size), + I915_BO_ALLOC_CONTIGUOUS); + if (IS_ERR(obj)) + return false; + } else { + obj = i915_gem_object_create_internal(i915, PAGE_ALIGN(size)); + if (IS_ERR(obj)) + return false; + + i915_gem_object_set_cache_coherency(obj, I915_CACHE_NONE); + } + + vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, 0); + if (IS_ERR(vma)) { + i915_gem_object_put(obj); + return false; + } + + 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); + return false; + } + + dsb_buf->vma = vma; + dsb_buf->cmd_buf = buf; + dsb_buf->buf_size = size; + + return true; +} + +void intel_dsb_buffer_cleanup(struct intel_dsb_buffer *dsb_buf) +{ + i915_vma_unpin_and_release(&dsb_buf->vma, I915_VMA_RELEASE_MAP); +} + +void intel_dsb_buffer_flush_map(struct intel_dsb_buffer *dsb_buf) +{ + i915_gem_object_flush_map(dsb_buf->vma->obj); +} diff --git a/drivers/gpu/drm/i915/display/intel_dsb_buffer.h b/drivers/gpu/drm/i915/display/intel_dsb_buffer.h new file mode 100644 index 00000000000000..425acd39390596 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_dsb_buffer.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright © 2023 Intel Corporation + */ + +#ifndef _INTEL_DSB_BUFFER_H +#define _INTEL_DSB_BUFFER_H + +#include + +struct intel_crtc; +struct i915_vma; + +struct intel_dsb_buffer { + u32 *cmd_buf; + struct i915_vma *vma; + size_t buf_size; +}; + +u32 intel_dsb_buffer_ggtt_offset(struct intel_dsb_buffer *dsb_buf); +void intel_dsb_buffer_write(struct intel_dsb_buffer *dsb_buf, u32 idx, u32 val); +u32 intel_dsb_buffer_read(struct intel_dsb_buffer *dsb_buf, u32 idx); +void intel_dsb_buffer_memset(struct intel_dsb_buffer *dsb_buf, u32 idx, u32 val, size_t size); +bool intel_dsb_buffer_create(struct intel_crtc *crtc, struct intel_dsb_buffer *dsb_buf, + size_t size); +void intel_dsb_buffer_cleanup(struct intel_dsb_buffer *dsb_buf); +void intel_dsb_buffer_flush_map(struct intel_dsb_buffer *dsb_buf); + +#endif diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c index 24b2cbcfc1effb..a5d7fc8418c976 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.c +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.c @@ -55,43 +55,6 @@ #define MIPI_VIRTUAL_CHANNEL_SHIFT 1 #define MIPI_PORT_SHIFT 3 -/* base offsets for gpio pads */ -#define VLV_GPIO_NC_0_HV_DDI0_HPD 0x4130 -#define VLV_GPIO_NC_1_HV_DDI0_DDC_SDA 0x4120 -#define VLV_GPIO_NC_2_HV_DDI0_DDC_SCL 0x4110 -#define VLV_GPIO_NC_3_PANEL0_VDDEN 0x4140 -#define VLV_GPIO_NC_4_PANEL0_BKLTEN 0x4150 -#define VLV_GPIO_NC_5_PANEL0_BKLTCTL 0x4160 -#define VLV_GPIO_NC_6_HV_DDI1_HPD 0x4180 -#define VLV_GPIO_NC_7_HV_DDI1_DDC_SDA 0x4190 -#define VLV_GPIO_NC_8_HV_DDI1_DDC_SCL 0x4170 -#define VLV_GPIO_NC_9_PANEL1_VDDEN 0x4100 -#define VLV_GPIO_NC_10_PANEL1_BKLTEN 0x40E0 -#define VLV_GPIO_NC_11_PANEL1_BKLTCTL 0x40F0 - -#define VLV_GPIO_PCONF0(base_offset) (base_offset) -#define VLV_GPIO_PAD_VAL(base_offset) ((base_offset) + 8) - -struct gpio_map { - u16 base_offset; - bool init; -}; - -static struct gpio_map vlv_gpio_table[] = { - { VLV_GPIO_NC_0_HV_DDI0_HPD }, - { VLV_GPIO_NC_1_HV_DDI0_DDC_SDA }, - { VLV_GPIO_NC_2_HV_DDI0_DDC_SCL }, - { VLV_GPIO_NC_3_PANEL0_VDDEN }, - { VLV_GPIO_NC_4_PANEL0_BKLTEN }, - { VLV_GPIO_NC_5_PANEL0_BKLTCTL }, - { VLV_GPIO_NC_6_HV_DDI1_HPD }, - { VLV_GPIO_NC_7_HV_DDI1_DDC_SDA }, - { VLV_GPIO_NC_8_HV_DDI1_DDC_SCL }, - { VLV_GPIO_NC_9_PANEL1_VDDEN }, - { VLV_GPIO_NC_10_PANEL1_BKLTEN }, - { VLV_GPIO_NC_11_PANEL1_BKLTCTL }, -}; - struct i2c_adapter_lookup { u16 slave_addr; struct intel_dsi *intel_dsi; @@ -103,19 +66,6 @@ struct i2c_adapter_lookup { #define CHV_GPIO_IDX_START_SW 100 #define CHV_GPIO_IDX_START_SE 198 -#define CHV_VBT_MAX_PINS_PER_FMLY 15 - -#define CHV_GPIO_PAD_CFG0(f, i) (0x4400 + (f) * 0x400 + (i) * 8) -#define CHV_GPIO_GPIOEN (1 << 15) -#define CHV_GPIO_GPIOCFG_GPIO (0 << 8) -#define CHV_GPIO_GPIOCFG_GPO (1 << 8) -#define CHV_GPIO_GPIOCFG_GPI (2 << 8) -#define CHV_GPIO_GPIOCFG_HIZ (3 << 8) -#define CHV_GPIO_GPIOTXSTATE(state) ((!!(state)) << 1) - -#define CHV_GPIO_PAD_CFG1(f, i) (0x4400 + (f) * 0x400 + (i) * 8 + 4) -#define CHV_GPIO_CFGLOCK (1 << 31) - /* ICL DSI Display GPIO Pins */ #define ICL_GPIO_DDSP_HPD_A 0 #define ICL_GPIO_L_VDDEN_1 1 @@ -142,7 +92,7 @@ static enum port intel_dsi_seq_port_to_port(struct intel_dsi *intel_dsi, if (seq_port) { if (intel_dsi->ports & BIT(PORT_B)) return PORT_B; - else if (intel_dsi->ports & BIT(PORT_C)) + if (intel_dsi->ports & BIT(PORT_C)) return PORT_C; } @@ -243,75 +193,93 @@ static const u8 *mipi_exec_delay(struct intel_dsi *intel_dsi, const u8 *data) return data; } -static void vlv_exec_gpio(struct intel_connector *connector, - u8 gpio_source, u8 gpio_index, bool value) +static void soc_gpio_set_value(struct intel_connector *connector, u8 gpio_index, + const char *con_id, u8 idx, bool value) { struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - struct gpio_map *map; - u16 pconf0, padval; - u32 tmp; - u8 port; - - if (gpio_index >= ARRAY_SIZE(vlv_gpio_table)) { - drm_dbg_kms(&dev_priv->drm, "unknown gpio index %u\n", - gpio_index); - return; + /* XXX: this table is a quick ugly hack. */ + static struct gpio_desc *soc_gpio_table[U8_MAX + 1]; + struct gpio_desc *gpio_desc = soc_gpio_table[gpio_index]; + + if (gpio_desc) { + gpiod_set_value(gpio_desc, value); + } else { + gpio_desc = devm_gpiod_get_index(dev_priv->drm.dev, con_id, idx, + value ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW); + if (IS_ERR(gpio_desc)) { + drm_err(&dev_priv->drm, + "GPIO index %u request failed (%pe)\n", + gpio_index, gpio_desc); + return; + } + + soc_gpio_table[gpio_index] = gpio_desc; } +} - map = &vlv_gpio_table[gpio_index]; +static void soc_opaque_gpio_set_value(struct intel_connector *connector, + u8 gpio_index, const char *chip, + const char *con_id, u8 idx, bool value) +{ + struct gpiod_lookup_table *lookup; - if (connector->panel.vbt.dsi.seq_version >= 3) { - /* XXX: this assumes vlv_gpio_table only has NC GPIOs. */ - port = IOSF_PORT_GPIO_NC; - } else { - if (gpio_source == 0) { - port = IOSF_PORT_GPIO_NC; - } else if (gpio_source == 1) { + lookup = kzalloc(struct_size(lookup, table, 2), GFP_KERNEL); + if (!lookup) + return; + + lookup->dev_id = "0000:00:02.0"; + lookup->table[0] = + GPIO_LOOKUP_IDX(chip, idx, con_id, idx, GPIO_ACTIVE_HIGH); + + gpiod_add_lookup_table(lookup); + + soc_gpio_set_value(connector, gpio_index, con_id, idx, value); + + gpiod_remove_lookup_table(lookup); + kfree(lookup); +} + +static void vlv_gpio_set_value(struct intel_connector *connector, + u8 gpio_source, u8 gpio_index, bool value) +{ + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + + /* XXX: this assumes vlv_gpio_table only has NC GPIOs. */ + if (connector->panel.vbt.dsi.seq_version < 3) { + if (gpio_source == 1) { drm_dbg_kms(&dev_priv->drm, "SC gpio not supported\n"); return; - } else { + } + if (gpio_source > 1) { drm_dbg_kms(&dev_priv->drm, "unknown gpio source %u\n", gpio_source); return; } } - pconf0 = VLV_GPIO_PCONF0(map->base_offset); - padval = VLV_GPIO_PAD_VAL(map->base_offset); - - vlv_iosf_sb_get(dev_priv, BIT(VLV_IOSF_SB_GPIO)); - if (!map->init) { - /* FIXME: remove constant below */ - vlv_iosf_sb_write(dev_priv, port, pconf0, 0x2000CC00); - map->init = true; - } - - tmp = 0x4 | value; - vlv_iosf_sb_write(dev_priv, port, padval, tmp); - vlv_iosf_sb_put(dev_priv, BIT(VLV_IOSF_SB_GPIO)); + soc_opaque_gpio_set_value(connector, gpio_index, + "INT33FC:01", "Panel N", gpio_index, value); } -static void chv_exec_gpio(struct intel_connector *connector, - u8 gpio_source, u8 gpio_index, bool value) +static void chv_gpio_set_value(struct intel_connector *connector, + u8 gpio_source, u8 gpio_index, bool value) { struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - u16 cfg0, cfg1; - u16 family_num; - u8 port; if (connector->panel.vbt.dsi.seq_version >= 3) { if (gpio_index >= CHV_GPIO_IDX_START_SE) { /* XXX: it's unclear whether 255->57 is part of SE. */ - gpio_index -= CHV_GPIO_IDX_START_SE; - port = CHV_IOSF_PORT_GPIO_SE; + soc_opaque_gpio_set_value(connector, gpio_index, "INT33FF:03", "Panel SE", + gpio_index - CHV_GPIO_IDX_START_SE, value); } else if (gpio_index >= CHV_GPIO_IDX_START_SW) { - gpio_index -= CHV_GPIO_IDX_START_SW; - port = CHV_IOSF_PORT_GPIO_SW; + soc_opaque_gpio_set_value(connector, gpio_index, "INT33FF:00", "Panel SW", + gpio_index - CHV_GPIO_IDX_START_SW, value); } else if (gpio_index >= CHV_GPIO_IDX_START_E) { - gpio_index -= CHV_GPIO_IDX_START_E; - port = CHV_IOSF_PORT_GPIO_E; + soc_opaque_gpio_set_value(connector, gpio_index, "INT33FF:02", "Panel E", + gpio_index - CHV_GPIO_IDX_START_E, value); } else { - port = CHV_IOSF_PORT_GPIO_N; + soc_opaque_gpio_set_value(connector, gpio_index, "INT33FF:01", "Panel N", + gpio_index - CHV_GPIO_IDX_START_N, value); } } else { /* XXX: The spec is unclear about CHV GPIO on seq v2 */ @@ -328,56 +296,15 @@ static void chv_exec_gpio(struct intel_connector *connector, return; } - port = CHV_IOSF_PORT_GPIO_N; - } - - family_num = gpio_index / CHV_VBT_MAX_PINS_PER_FMLY; - gpio_index = gpio_index % CHV_VBT_MAX_PINS_PER_FMLY; - - cfg0 = CHV_GPIO_PAD_CFG0(family_num, gpio_index); - cfg1 = CHV_GPIO_PAD_CFG1(family_num, gpio_index); - - vlv_iosf_sb_get(dev_priv, BIT(VLV_IOSF_SB_GPIO)); - vlv_iosf_sb_write(dev_priv, port, cfg1, 0); - vlv_iosf_sb_write(dev_priv, port, cfg0, - CHV_GPIO_GPIOEN | CHV_GPIO_GPIOCFG_GPO | - CHV_GPIO_GPIOTXSTATE(value)); - vlv_iosf_sb_put(dev_priv, BIT(VLV_IOSF_SB_GPIO)); -} - -static void bxt_exec_gpio(struct intel_connector *connector, - u8 gpio_source, u8 gpio_index, bool value) -{ - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - /* XXX: this table is a quick ugly hack. */ - static struct gpio_desc *bxt_gpio_table[U8_MAX + 1]; - struct gpio_desc *gpio_desc = bxt_gpio_table[gpio_index]; - - if (!gpio_desc) { - gpio_desc = devm_gpiod_get_index(dev_priv->drm.dev, - NULL, gpio_index, - value ? GPIOD_OUT_LOW : - GPIOD_OUT_HIGH); - - if (IS_ERR_OR_NULL(gpio_desc)) { - drm_err(&dev_priv->drm, - "GPIO index %u request failed (%ld)\n", - gpio_index, PTR_ERR(gpio_desc)); - return; - } - - bxt_gpio_table[gpio_index] = gpio_desc; + soc_opaque_gpio_set_value(connector, gpio_index, "INT33FF:01", "Panel N", + gpio_index - CHV_GPIO_IDX_START_N, value); } - - gpiod_set_value(gpio_desc, value); } -static void icl_exec_gpio(struct intel_connector *connector, - u8 gpio_source, u8 gpio_index, bool value) +static void bxt_gpio_set_value(struct intel_connector *connector, + u8 gpio_index, bool value) { - struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - - drm_dbg_kms(&dev_priv->drm, "Skipping ICL GPIO element execution\n"); + soc_gpio_set_value(connector, gpio_index, NULL, gpio_index, value); } enum { @@ -462,44 +389,45 @@ static void icl_native_gpio_set_value(struct drm_i915_private *dev_priv, static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data) { struct drm_device *dev = intel_dsi->base.base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_i915_private *i915 = to_i915(dev); struct intel_connector *connector = intel_dsi->attached_connector; - u8 gpio_source, gpio_index = 0, gpio_number; + u8 gpio_source = 0, gpio_index = 0, gpio_number; bool value; - bool native = DISPLAY_VER(dev_priv) >= 11; + int size; + bool native = DISPLAY_VER(i915) >= 11; - if (connector->panel.vbt.dsi.seq_version >= 3) - gpio_index = *data++; + if (connector->panel.vbt.dsi.seq_version >= 3) { + size = 3; - gpio_number = *data++; + gpio_index = data[0]; + gpio_number = data[1]; + value = data[2] & BIT(0); - /* gpio source in sequence v2 only */ - if (connector->panel.vbt.dsi.seq_version == 2) - gpio_source = (*data >> 1) & 3; - else - gpio_source = 0; + if (connector->panel.vbt.dsi.seq_version >= 4 && data[2] & BIT(1)) + native = false; + } else { + size = 2; - if (connector->panel.vbt.dsi.seq_version >= 4 && *data & BIT(1)) - native = false; + gpio_number = data[0]; + value = data[1] & BIT(0); - /* pull up/down */ - value = *data++ & 1; + if (connector->panel.vbt.dsi.seq_version == 2) + gpio_source = (data[1] >> 1) & 3; + } - drm_dbg_kms(&dev_priv->drm, "GPIO index %u, number %u, source %u, native %s, set to %s\n", + drm_dbg_kms(&i915->drm, "GPIO index %u, number %u, source %u, native %s, set to %s\n", gpio_index, gpio_number, gpio_source, str_yes_no(native), str_on_off(value)); if (native) - icl_native_gpio_set_value(dev_priv, gpio_number, value); - else if (DISPLAY_VER(dev_priv) >= 11) - icl_exec_gpio(connector, gpio_source, gpio_index, value); - else if (IS_VALLEYVIEW(dev_priv)) - vlv_exec_gpio(connector, gpio_source, gpio_number, value); - else if (IS_CHERRYVIEW(dev_priv)) - chv_exec_gpio(connector, gpio_source, gpio_number, value); - else - bxt_exec_gpio(connector, gpio_source, gpio_index, value); - - return data; + icl_native_gpio_set_value(i915, gpio_number, value); + else if (DISPLAY_VER(i915) >= 9) + bxt_gpio_set_value(connector, gpio_index, value); + else if (IS_VALLEYVIEW(i915)) + vlv_gpio_set_value(connector, gpio_source, gpio_number, value); + else if (IS_CHERRYVIEW(i915)) + chv_gpio_set_value(connector, gpio_source, gpio_number, value); + + return data + size; } #ifdef CONFIG_ACPI @@ -658,6 +586,7 @@ static const fn_mipi_elem_exec exec_elem[] = { */ static const char * const seq_name[] = { + [MIPI_SEQ_END] = "MIPI_SEQ_END", [MIPI_SEQ_DEASSERT_RESET] = "MIPI_SEQ_DEASSERT_RESET", [MIPI_SEQ_INIT_OTP] = "MIPI_SEQ_INIT_OTP", [MIPI_SEQ_DISPLAY_ON] = "MIPI_SEQ_DISPLAY_ON", @@ -673,10 +602,10 @@ static const char * const seq_name[] = { static const char *sequence_name(enum mipi_seq seq_id) { - if (seq_id < ARRAY_SIZE(seq_name) && seq_name[seq_id]) + if (seq_id < ARRAY_SIZE(seq_name)) return seq_name[seq_id]; - else - return "(unknown)"; + + return "(unknown)"; } static void intel_dsi_vbt_exec(struct intel_dsi *intel_dsi, @@ -707,13 +636,10 @@ static void intel_dsi_vbt_exec(struct intel_dsi *intel_dsi, if (connector->panel.vbt.dsi.seq_version >= 3) data += 4; - while (1) { + while (*data != MIPI_SEQ_ELEM_END) { u8 operation_byte = *data++; u8 operation_size = 0; - if (operation_byte == MIPI_SEQ_ELEM_END) - break; - if (operation_byte < ARRAY_SIZE(exec_elem)) mipi_elem_exec = exec_elem[operation_byte]; else @@ -873,36 +799,34 @@ bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id) * multiply by 100 to preserve remainder */ if (intel_dsi->video_mode == BURST_MODE) { - if (mipi_config->target_burst_mode_freq) { - u32 bitrate = intel_dsi_bitrate(intel_dsi); - - /* - * Sometimes the VBT contains a slightly lower clock, - * then the bitrate we have calculated, in this case - * just replace it with the calculated bitrate. - */ - if (mipi_config->target_burst_mode_freq < bitrate && - intel_fuzzy_clock_check( - mipi_config->target_burst_mode_freq, - bitrate)) - mipi_config->target_burst_mode_freq = bitrate; - - if (mipi_config->target_burst_mode_freq < bitrate) { - drm_err(&dev_priv->drm, - "Burst mode freq is less than computed\n"); - return false; - } + u32 bitrate; - burst_mode_ratio = DIV_ROUND_UP( - mipi_config->target_burst_mode_freq * 100, - bitrate); + if (mipi_config->target_burst_mode_freq == 0) { + drm_err(&dev_priv->drm, "Burst mode target is not set\n"); + return false; + } - intel_dsi->pclk = DIV_ROUND_UP(intel_dsi->pclk * burst_mode_ratio, 100); - } else { - drm_err(&dev_priv->drm, - "Burst mode target is not set\n"); + bitrate = intel_dsi_bitrate(intel_dsi); + + /* + * Sometimes the VBT contains a slightly lower clock, then + * the bitrate we have calculated, in this case just replace it + * with the calculated bitrate. + */ + if (mipi_config->target_burst_mode_freq < bitrate && + intel_fuzzy_clock_check(mipi_config->target_burst_mode_freq, + bitrate)) + mipi_config->target_burst_mode_freq = bitrate; + + if (mipi_config->target_burst_mode_freq < bitrate) { + drm_err(&dev_priv->drm, "Burst mode freq is less than computed\n"); return false; } + + burst_mode_ratio = + DIV_ROUND_UP(mipi_config->target_burst_mode_freq * 100, bitrate); + + intel_dsi->pclk = DIV_ROUND_UP(intel_dsi->pclk * burst_mode_ratio, 100); } else burst_mode_ratio = 100; @@ -964,6 +888,7 @@ void intel_dsi_vbt_gpio_init(struct intel_dsi *intel_dsi, bool panel_is_on) struct intel_connector *connector = intel_dsi->attached_connector; struct mipi_config *mipi_config = connector->panel.vbt.dsi.config; enum gpiod_flags flags = panel_is_on ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW; + struct gpiod_lookup_table *gpiod_lookup_table = NULL; bool want_backlight_gpio = false; bool want_panel_gpio = false; struct pinctrl *pinctrl; @@ -971,12 +896,12 @@ void intel_dsi_vbt_gpio_init(struct intel_dsi *intel_dsi, bool panel_is_on) if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) && mipi_config->pwm_blc == PPS_BLC_PMIC) { - gpiod_add_lookup_table(&pmic_panel_gpio_table); + gpiod_lookup_table = &pmic_panel_gpio_table; want_panel_gpio = true; } if (IS_VALLEYVIEW(dev_priv) && mipi_config->pwm_blc == PPS_BLC_SOC) { - gpiod_add_lookup_table(&soc_panel_gpio_table); + gpiod_lookup_table = &soc_panel_gpio_table; want_panel_gpio = true; want_backlight_gpio = true; @@ -993,8 +918,11 @@ void intel_dsi_vbt_gpio_init(struct intel_dsi *intel_dsi, bool panel_is_on) "Failed to set pinmux to PWM\n"); } + if (gpiod_lookup_table) + gpiod_add_lookup_table(gpiod_lookup_table); + if (want_panel_gpio) { - intel_dsi->gpio_panel = gpiod_get(dev->dev, "panel", flags); + intel_dsi->gpio_panel = devm_gpiod_get(dev->dev, "panel", flags); if (IS_ERR(intel_dsi->gpio_panel)) { drm_err(&dev_priv->drm, "Failed to own gpio for panel control\n"); @@ -1004,38 +932,14 @@ void intel_dsi_vbt_gpio_init(struct intel_dsi *intel_dsi, bool panel_is_on) if (want_backlight_gpio) { intel_dsi->gpio_backlight = - gpiod_get(dev->dev, "backlight", flags); + devm_gpiod_get(dev->dev, "backlight", flags); if (IS_ERR(intel_dsi->gpio_backlight)) { drm_err(&dev_priv->drm, "Failed to own gpio for backlight control\n"); intel_dsi->gpio_backlight = NULL; } } -} -void intel_dsi_vbt_gpio_cleanup(struct intel_dsi *intel_dsi) -{ - struct drm_device *dev = intel_dsi->base.base.dev; - struct drm_i915_private *dev_priv = to_i915(dev); - struct intel_connector *connector = intel_dsi->attached_connector; - struct mipi_config *mipi_config = connector->panel.vbt.dsi.config; - - if (intel_dsi->gpio_panel) { - gpiod_put(intel_dsi->gpio_panel); - intel_dsi->gpio_panel = NULL; - } - - if (intel_dsi->gpio_backlight) { - gpiod_put(intel_dsi->gpio_backlight); - intel_dsi->gpio_backlight = NULL; - } - - if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) && - mipi_config->pwm_blc == PPS_BLC_PMIC) - gpiod_remove_lookup_table(&pmic_panel_gpio_table); - - if (IS_VALLEYVIEW(dev_priv) && mipi_config->pwm_blc == PPS_BLC_SOC) { - pinctrl_unregister_mappings(soc_pwm_pinctrl_map); - gpiod_remove_lookup_table(&soc_panel_gpio_table); - } + if (gpiod_lookup_table) + gpiod_remove_lookup_table(gpiod_lookup_table); } diff --git a/drivers/gpu/drm/i915/display/intel_dsi_vbt.h b/drivers/gpu/drm/i915/display/intel_dsi_vbt.h index 468d873fab1aea..3462fcc760e64a 100644 --- a/drivers/gpu/drm/i915/display/intel_dsi_vbt.h +++ b/drivers/gpu/drm/i915/display/intel_dsi_vbt.h @@ -13,7 +13,6 @@ struct intel_dsi; bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id); void intel_dsi_vbt_gpio_init(struct intel_dsi *intel_dsi, bool panel_is_on); -void intel_dsi_vbt_gpio_cleanup(struct intel_dsi *intel_dsi); void intel_dsi_vbt_exec_sequence(struct intel_dsi *intel_dsi, enum mipi_seq seq_id); void intel_dsi_log_params(struct intel_dsi *intel_dsi); diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c index 646f367a13f5a0..0c0144eaa8faa1 100644 --- a/drivers/gpu/drm/i915/display/intel_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fb.c @@ -4,7 +4,6 @@ */ #include -#include #include #include @@ -15,6 +14,7 @@ #include "intel_display_types.h" #include "intel_dpt.h" #include "intel_fb.h" +#include "intel_fb_bo.h" #include "intel_frontbuffer.h" #define check_array_bounds(i915, a, i) drm_WARN_ON(&(i915)->drm, (i) >= ARRAY_SIZE(a)) @@ -301,6 +301,33 @@ lookup_format_info(const struct drm_format_info formats[], return NULL; } +unsigned int intel_fb_modifier_to_tiling(u64 fb_modifier) +{ + const struct intel_modifier_desc *md; + u8 tiling_caps; + + md = lookup_modifier_or_null(fb_modifier); + if (!md) + return I915_TILING_NONE; + + tiling_caps = lookup_modifier_or_null(fb_modifier)->plane_caps & + INTEL_PLANE_CAP_TILING_MASK; + + switch (tiling_caps) { + case INTEL_PLANE_CAP_TILING_Y: + return I915_TILING_Y; + case INTEL_PLANE_CAP_TILING_X: + return I915_TILING_X; + case INTEL_PLANE_CAP_TILING_4: + case INTEL_PLANE_CAP_TILING_Yf: + case INTEL_PLANE_CAP_TILING_NONE: + return I915_TILING_NONE; + default: + MISSING_CASE(tiling_caps); + return I915_TILING_NONE; + } +} + /** * intel_fb_get_format_info: Get a modifier specific format information * @cmd: FB add command structure @@ -737,26 +764,6 @@ intel_fb_align_height(const struct drm_framebuffer *fb, return ALIGN(height, tile_height); } -static unsigned int intel_fb_modifier_to_tiling(u64 fb_modifier) -{ - u8 tiling_caps = lookup_modifier(fb_modifier)->plane_caps & - INTEL_PLANE_CAP_TILING_MASK; - - switch (tiling_caps) { - case INTEL_PLANE_CAP_TILING_Y: - return I915_TILING_Y; - case INTEL_PLANE_CAP_TILING_X: - return I915_TILING_X; - case INTEL_PLANE_CAP_TILING_4: - case INTEL_PLANE_CAP_TILING_Yf: - case INTEL_PLANE_CAP_TILING_NONE: - return I915_TILING_NONE; - default: - MISSING_CASE(tiling_caps); - return I915_TILING_NONE; - } -} - bool intel_fb_modifier_uses_dpt(struct drm_i915_private *i915, u64 modifier) { return HAS_DPT(i915) && modifier != DRM_FORMAT_MOD_LINEAR; @@ -764,7 +771,7 @@ bool intel_fb_modifier_uses_dpt(struct drm_i915_private *i915, u64 modifier) bool intel_fb_uses_dpt(const struct drm_framebuffer *fb) { - return fb && to_i915(fb->dev)->params.enable_dpt && + return to_i915(fb->dev)->display.params.enable_dpt && intel_fb_modifier_uses_dpt(to_i915(fb->dev), fb->modifier); } @@ -1670,10 +1677,10 @@ int intel_fill_fb_info(struct drm_i915_private *i915, struct intel_framebuffer * max_size = max(max_size, offset + size); } - if (mul_u32_u32(max_size, tile_size) > obj->base.size) { + if (mul_u32_u32(max_size, tile_size) > intel_bo_to_drm_bo(obj)->size) { drm_dbg_kms(&i915->drm, "fb too big for bo (need %llu bytes, have %zu bytes)\n", - mul_u32_u32(max_size, tile_size), obj->base.size); + mul_u32_u32(max_size, tile_size), intel_bo_to_drm_bo(obj)->size); return -EINVAL; } @@ -1894,6 +1901,8 @@ static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb) intel_frontbuffer_put(intel_fb->frontbuffer); + intel_fb_bo_framebuffer_fini(intel_fb_obj(fb)); + kfree(intel_fb); } @@ -1902,7 +1911,7 @@ static int intel_user_framebuffer_create_handle(struct drm_framebuffer *fb, unsigned int *handle) { struct drm_i915_gem_object *obj = intel_fb_obj(fb); - struct drm_i915_private *i915 = to_i915(obj->base.dev); + struct drm_i915_private *i915 = to_i915(intel_bo_to_drm_bo(obj)->dev); if (i915_gem_object_is_userptr(obj)) { drm_dbg(&i915->drm, @@ -1910,7 +1919,7 @@ static int intel_user_framebuffer_create_handle(struct drm_framebuffer *fb, return -EINVAL; } - return drm_gem_handle_create(file, &obj->base, handle); + return drm_gem_handle_create(file, intel_bo_to_drm_bo(obj), handle); } struct frontbuffer_fence_cb { @@ -1943,10 +1952,10 @@ static int intel_user_framebuffer_dirty(struct drm_framebuffer *fb, if (!atomic_read(&front->bits)) return 0; - if (dma_resv_test_signaled(obj->base.resv, dma_resv_usage_rw(false))) + if (dma_resv_test_signaled(intel_bo_to_drm_bo(obj)->resv, dma_resv_usage_rw(false))) goto flush; - ret = dma_resv_get_singleton(obj->base.resv, dma_resv_usage_rw(false), + ret = dma_resv_get_singleton(intel_bo_to_drm_bo(obj)->resv, dma_resv_usage_rw(false), &fence); if (ret || !fence) goto flush; @@ -1988,61 +1997,30 @@ int intel_framebuffer_init(struct intel_framebuffer *intel_fb, struct drm_i915_gem_object *obj, struct drm_mode_fb_cmd2 *mode_cmd) { - struct drm_i915_private *dev_priv = to_i915(obj->base.dev); + struct drm_i915_private *dev_priv = to_i915(intel_bo_to_drm_bo(obj)->dev); struct drm_framebuffer *fb = &intel_fb->base; u32 max_stride; - unsigned int tiling, stride; int ret = -EINVAL; int i; - intel_fb->frontbuffer = intel_frontbuffer_get(obj); - if (!intel_fb->frontbuffer) - return -ENOMEM; - - i915_gem_object_lock(obj, NULL); - tiling = i915_gem_object_get_tiling(obj); - stride = i915_gem_object_get_stride(obj); - i915_gem_object_unlock(obj); + ret = intel_fb_bo_framebuffer_init(intel_fb, obj, mode_cmd); + if (ret) + return ret; - if (mode_cmd->flags & DRM_MODE_FB_MODIFIERS) { - /* - * If there's a fence, enforce that - * the fb modifier and tiling mode match. - */ - if (tiling != I915_TILING_NONE && - tiling != intel_fb_modifier_to_tiling(mode_cmd->modifier[0])) { - drm_dbg_kms(&dev_priv->drm, - "tiling_mode doesn't match fb modifier\n"); - goto err; - } - } else { - if (tiling == I915_TILING_X) { - mode_cmd->modifier[0] = I915_FORMAT_MOD_X_TILED; - } else if (tiling == I915_TILING_Y) { - drm_dbg_kms(&dev_priv->drm, - "No Y tiling for legacy addfb\n"); - goto err; - } + intel_fb->frontbuffer = intel_frontbuffer_get(obj); + if (!intel_fb->frontbuffer) { + ret = -ENOMEM; + goto err; } + ret = -EINVAL; if (!drm_any_plane_has_format(&dev_priv->drm, mode_cmd->pixel_format, mode_cmd->modifier[0])) { drm_dbg_kms(&dev_priv->drm, "unsupported pixel format %p4cc / modifier 0x%llx\n", &mode_cmd->pixel_format, mode_cmd->modifier[0]); - goto err; - } - - /* - * gen2/3 display engine uses the fence if present, - * so the tiling mode must match the fb modifier exactly. - */ - if (DISPLAY_VER(dev_priv) < 4 && - tiling != intel_fb_modifier_to_tiling(mode_cmd->modifier[0])) { - drm_dbg_kms(&dev_priv->drm, - "tiling_mode must match fb modifier exactly on gen2/3\n"); - goto err; + goto err_frontbuffer_put; } max_stride = intel_fb_max_stride(dev_priv, mode_cmd->pixel_format, @@ -2053,18 +2031,7 @@ int intel_framebuffer_init(struct intel_framebuffer *intel_fb, mode_cmd->modifier[0] != DRM_FORMAT_MOD_LINEAR ? "tiled" : "linear", mode_cmd->pitches[0], max_stride); - goto err; - } - - /* - * If there's a fence, enforce that - * the fb pitch and fence stride match. - */ - if (tiling != I915_TILING_NONE && mode_cmd->pitches[0] != stride) { - drm_dbg_kms(&dev_priv->drm, - "pitch (%d) must match tiling stride (%d)\n", - mode_cmd->pitches[0], stride); - goto err; + goto err_frontbuffer_put; } /* FIXME need to adjust LINOFF/TILEOFF accordingly. */ @@ -2072,7 +2039,7 @@ int intel_framebuffer_init(struct intel_framebuffer *intel_fb, drm_dbg_kms(&dev_priv->drm, "plane 0 offset (0x%08x) must be 0\n", mode_cmd->offsets[0]); - goto err; + goto err_frontbuffer_put; } drm_helper_mode_fill_fb_struct(&dev_priv->drm, fb, mode_cmd); @@ -2083,7 +2050,7 @@ int intel_framebuffer_init(struct intel_framebuffer *intel_fb, if (mode_cmd->handles[i] != mode_cmd->handles[0]) { drm_dbg_kms(&dev_priv->drm, "bad plane %d handle\n", i); - goto err; + goto err_frontbuffer_put; } stride_alignment = intel_fb_stride_alignment(fb, i); @@ -2091,7 +2058,7 @@ int intel_framebuffer_init(struct intel_framebuffer *intel_fb, drm_dbg_kms(&dev_priv->drm, "plane %d pitch (%d) must be at least %u byte aligned\n", i, fb->pitches[i], stride_alignment); - goto err; + goto err_frontbuffer_put; } if (intel_fb_is_gen12_ccs_aux_plane(fb, i)) { @@ -2102,16 +2069,16 @@ int intel_framebuffer_init(struct intel_framebuffer *intel_fb, "ccs aux plane %d pitch (%d) must be %d\n", i, fb->pitches[i], ccs_aux_stride); - goto err; + goto err_frontbuffer_put; } } - fb->obj[i] = &obj->base; + fb->obj[i] = intel_bo_to_drm_bo(obj); } ret = intel_fill_fb_info(dev_priv, intel_fb); if (ret) - goto err; + goto err_frontbuffer_put; if (intel_fb_uses_dpt(fb)) { struct i915_address_space *vm; @@ -2120,7 +2087,7 @@ int intel_framebuffer_init(struct intel_framebuffer *intel_fb, if (IS_ERR(vm)) { drm_dbg_kms(&dev_priv->drm, "failed to create DPT\n"); ret = PTR_ERR(vm); - goto err; + goto err_frontbuffer_put; } intel_fb->dpt_vm = vm; @@ -2137,8 +2104,10 @@ int intel_framebuffer_init(struct intel_framebuffer *intel_fb, err_free_dpt: if (intel_fb_uses_dpt(fb)) intel_dpt_destroy(intel_fb->dpt_vm); -err: +err_frontbuffer_put: intel_frontbuffer_put(intel_fb->frontbuffer); +err: + intel_fb_bo_framebuffer_fini(obj); return ret; } @@ -2150,23 +2119,14 @@ intel_user_framebuffer_create(struct drm_device *dev, struct drm_framebuffer *fb; struct drm_i915_gem_object *obj; struct drm_mode_fb_cmd2 mode_cmd = *user_mode_cmd; - struct drm_i915_private *i915; - - obj = i915_gem_object_lookup(filp, mode_cmd.handles[0]); - if (!obj) - return ERR_PTR(-ENOENT); - - /* object is backed with LMEM for discrete */ - i915 = to_i915(obj->base.dev); - if (HAS_LMEM(i915) && !i915_gem_object_can_migrate(obj, INTEL_REGION_LMEM_0)) { - /* object is "remote", not in local memory */ - i915_gem_object_put(obj); - drm_dbg_kms(&i915->drm, "framebuffer must reside in local memory\n"); - return ERR_PTR(-EREMOTE); - } + struct drm_i915_private *i915 = to_i915(dev); + + obj = intel_fb_bo_lookup_valid_bo(i915, filp, &mode_cmd); + if (IS_ERR(obj)) + return ERR_CAST(obj); fb = intel_framebuffer_create(obj, &mode_cmd); - i915_gem_object_put(obj); + drm_gem_object_put(intel_bo_to_drm_bo(obj)); return fb; } diff --git a/drivers/gpu/drm/i915/display/intel_fb.h b/drivers/gpu/drm/i915/display/intel_fb.h index e85167d6bc347b..23db6628f53e75 100644 --- a/drivers/gpu/drm/i915/display/intel_fb.h +++ b/drivers/gpu/drm/i915/display/intel_fb.h @@ -95,4 +95,6 @@ intel_user_framebuffer_create(struct drm_device *dev, bool intel_fb_modifier_uses_dpt(struct drm_i915_private *i915, u64 modifier); bool intel_fb_uses_dpt(const struct drm_framebuffer *fb); +unsigned int intel_fb_modifier_to_tiling(u64 fb_modifier); + #endif /* __INTEL_FB_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_fb_bo.c b/drivers/gpu/drm/i915/display/intel_fb_bo.c new file mode 100644 index 00000000000000..4be09541e50950 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_fb_bo.c @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2021 Intel Corporation + */ + +#include + +#include "gem/i915_gem_object.h" + +#include "i915_drv.h" +#include "intel_fb.h" +#include "intel_fb_bo.h" + +void intel_fb_bo_framebuffer_fini(struct drm_i915_gem_object *obj) +{ + /* Nothing to do for i915 */ +} + +int intel_fb_bo_framebuffer_init(struct intel_framebuffer *intel_fb, + struct drm_i915_gem_object *obj, + struct drm_mode_fb_cmd2 *mode_cmd) +{ + struct drm_i915_private *i915 = to_i915(obj->base.dev); + unsigned int tiling, stride; + + i915_gem_object_lock(obj, NULL); + tiling = i915_gem_object_get_tiling(obj); + stride = i915_gem_object_get_stride(obj); + i915_gem_object_unlock(obj); + + if (mode_cmd->flags & DRM_MODE_FB_MODIFIERS) { + /* + * If there's a fence, enforce that + * the fb modifier and tiling mode match. + */ + if (tiling != I915_TILING_NONE && + tiling != intel_fb_modifier_to_tiling(mode_cmd->modifier[0])) { + drm_dbg_kms(&i915->drm, + "tiling_mode doesn't match fb modifier\n"); + return -EINVAL; + } + } else { + if (tiling == I915_TILING_X) { + mode_cmd->modifier[0] = I915_FORMAT_MOD_X_TILED; + } else if (tiling == I915_TILING_Y) { + drm_dbg_kms(&i915->drm, + "No Y tiling for legacy addfb\n"); + return -EINVAL; + } + } + + /* + * gen2/3 display engine uses the fence if present, + * so the tiling mode must match the fb modifier exactly. + */ + if (DISPLAY_VER(i915) < 4 && + tiling != intel_fb_modifier_to_tiling(mode_cmd->modifier[0])) { + drm_dbg_kms(&i915->drm, + "tiling_mode must match fb modifier exactly on gen2/3\n"); + return -EINVAL; + } + + /* + * If there's a fence, enforce that + * the fb pitch and fence stride match. + */ + if (tiling != I915_TILING_NONE && mode_cmd->pitches[0] != stride) { + drm_dbg_kms(&i915->drm, + "pitch (%d) must match tiling stride (%d)\n", + mode_cmd->pitches[0], stride); + return -EINVAL; + } + + return 0; +} + +struct drm_i915_gem_object * +intel_fb_bo_lookup_valid_bo(struct drm_i915_private *i915, + struct drm_file *filp, + const struct drm_mode_fb_cmd2 *mode_cmd) +{ + struct drm_i915_gem_object *obj; + + obj = i915_gem_object_lookup(filp, mode_cmd->handles[0]); + if (!obj) + return ERR_PTR(-ENOENT); + + /* object is backed with LMEM for discrete */ + if (HAS_LMEM(i915) && !i915_gem_object_can_migrate(obj, INTEL_REGION_LMEM_0)) { + /* object is "remote", not in local memory */ + i915_gem_object_put(obj); + drm_dbg_kms(&i915->drm, "framebuffer must reside in local memory\n"); + return ERR_PTR(-EREMOTE); + } + + return obj; +} diff --git a/drivers/gpu/drm/i915/display/intel_fb_bo.h b/drivers/gpu/drm/i915/display/intel_fb_bo.h new file mode 100644 index 00000000000000..232bf898b01389 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_fb_bo.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2021 Intel Corporation + */ + +#ifndef __INTEL_FB_BO_H__ +#define __INTEL_FB_BO_H__ + +struct drm_file; +struct drm_mode_fb_cmd2; +struct drm_i915_gem_object; +struct drm_i915_private; +struct intel_framebuffer; + +void intel_fb_bo_framebuffer_fini(struct drm_i915_gem_object *obj); + +int intel_fb_bo_framebuffer_init(struct intel_framebuffer *intel_fb, + struct drm_i915_gem_object *obj, + struct drm_mode_fb_cmd2 *mode_cmd); + +struct drm_i915_gem_object * +intel_fb_bo_lookup_valid_bo(struct drm_i915_private *i915, + struct drm_file *filp, + const struct drm_mode_fb_cmd2 *user_mode_cmd); + +#endif diff --git a/drivers/gpu/drm/i915/display/intel_fbc.c b/drivers/gpu/drm/i915/display/intel_fbc.c index 4820d21cc942a0..f17a1afb4929ec 100644 --- a/drivers/gpu/drm/i915/display/intel_fbc.c +++ b/drivers/gpu/drm/i915/display/intel_fbc.c @@ -608,6 +608,7 @@ static u32 ivb_dpfc_ctl(struct intel_fbc *fbc) static void ivb_fbc_activate(struct intel_fbc *fbc) { struct drm_i915_private *i915 = fbc->i915; + u32 dpfc_ctl; if (DISPLAY_VER(i915) >= 10) glk_fbc_program_cfb_stride(fbc); @@ -617,8 +618,13 @@ static void ivb_fbc_activate(struct intel_fbc *fbc) if (intel_gt_support_legacy_fencing(to_gt(i915))) snb_fbc_program_fence(fbc); + /* wa_14019417088 Alternative WA*/ + dpfc_ctl = ivb_dpfc_ctl(fbc); + if (DISPLAY_VER(i915) >= 20) + intel_de_write(i915, ILK_DPFC_CONTROL(fbc->id), dpfc_ctl); + intel_de_write(i915, ILK_DPFC_CONTROL(fbc->id), - DPFC_CTL_EN | ivb_dpfc_ctl(fbc)); + DPFC_CTL_EN | dpfc_ctl); } static bool ivb_fbc_is_compressing(struct intel_fbc *fbc) @@ -1022,10 +1028,13 @@ static bool intel_fbc_hw_tracking_covers_screen(const struct intel_plane_state * struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev); unsigned int effective_w, effective_h, max_w, max_h; - if (DISPLAY_VER(i915) >= 10) { + if (DISPLAY_VER(i915) >= 11) { + max_w = 8192; + max_h = 4096; + } else if (DISPLAY_VER(i915) >= 10) { max_w = 5120; max_h = 4096; - } else if (DISPLAY_VER(i915) >= 8 || IS_HASWELL(i915)) { + } else if (DISPLAY_VER(i915) >= 7) { max_w = 4096; max_h = 4096; } else if (IS_G4X(i915) || DISPLAY_VER(i915) >= 5) { @@ -1044,6 +1053,31 @@ static bool intel_fbc_hw_tracking_covers_screen(const struct intel_plane_state * return effective_w <= max_w && effective_h <= max_h; } +static bool intel_fbc_plane_size_valid(const struct intel_plane_state *plane_state) +{ + struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev); + unsigned int w, h, max_w, max_h; + + if (DISPLAY_VER(i915) >= 10) { + max_w = 5120; + max_h = 4096; + } else if (DISPLAY_VER(i915) >= 8 || IS_HASWELL(i915)) { + max_w = 4096; + max_h = 4096; + } else if (IS_G4X(i915) || DISPLAY_VER(i915) >= 5) { + max_w = 4096; + max_h = 2048; + } else { + max_w = 2048; + max_h = 1536; + } + + w = drm_rect_width(&plane_state->uapi.src) >> 16; + h = drm_rect_height(&plane_state->uapi.src) >> 16; + + return w <= max_w && h <= max_h; +} + static bool i8xx_fbc_tiling_valid(const struct intel_plane_state *plane_state) { const struct drm_framebuffer *fb = plane_state->hw.fb; @@ -1174,7 +1208,7 @@ static int intel_fbc_check_plane(struct intel_atomic_state *state, return 0; } - if (!i915->params.enable_fbc) { + if (!i915->display.params.enable_fbc) { plane_state->no_fbc_reason = "disabled per module param or by default"; return 0; } @@ -1201,7 +1235,7 @@ static int intel_fbc_check_plane(struct intel_atomic_state *state, * Recommendation is to keep this combination disabled * Bspec: 50422 HSD: 14010260002 */ - if (DISPLAY_VER(i915) >= 12 && crtc_state->has_psr2) { + if (IS_DISPLAY_VER(i915, 12, 14) && crtc_state->has_psr2) { plane_state->no_fbc_reason = "PSR2 enabled"; return 0; } @@ -1241,11 +1275,16 @@ static int intel_fbc_check_plane(struct intel_atomic_state *state, return 0; } - if (!intel_fbc_hw_tracking_covers_screen(plane_state)) { + if (!intel_fbc_plane_size_valid(plane_state)) { plane_state->no_fbc_reason = "plane size too big"; return 0; } + if (!intel_fbc_hw_tracking_covers_screen(plane_state)) { + plane_state->no_fbc_reason = "surface size too big"; + return 0; + } + /* * Work around a problem on GEN9+ HW, where enabling FBC on a plane * having a Y offset that isn't divisible by 4 causes FIFO underrun @@ -1751,8 +1790,8 @@ void intel_fbc_handle_fifo_underrun_irq(struct drm_i915_private *i915) */ static int intel_sanitize_fbc_option(struct drm_i915_private *i915) { - if (i915->params.enable_fbc >= 0) - return !!i915->params.enable_fbc; + if (i915->display.params.enable_fbc >= 0) + return !!i915->display.params.enable_fbc; if (!HAS_FBC(i915)) return 0; @@ -1824,9 +1863,9 @@ void intel_fbc_init(struct drm_i915_private *i915) if (need_fbc_vtd_wa(i915)) DISPLAY_RUNTIME_INFO(i915)->fbc_mask = 0; - i915->params.enable_fbc = intel_sanitize_fbc_option(i915); + i915->display.params.enable_fbc = intel_sanitize_fbc_option(i915); drm_dbg_kms(&i915->drm, "Sanitized enable_fbc value: %d\n", - i915->params.enable_fbc); + i915->display.params.enable_fbc); for_each_fbc_id(i915, fbc_id) i915->display.fbc[fbc_id] = intel_fbc_create(i915, fbc_id); diff --git a/drivers/gpu/drm/i915/display/intel_fbdev.c b/drivers/gpu/drm/i915/display/intel_fbdev.c index 31d0d695d5671b..99894a855ef053 100644 --- a/drivers/gpu/drm/i915/display/intel_fbdev.c +++ b/drivers/gpu/drm/i915/display/intel_fbdev.c @@ -43,7 +43,6 @@ #include #include -#include "gem/i915_gem_lmem.h" #include "gem/i915_gem_mman.h" #include "i915_drv.h" @@ -51,6 +50,7 @@ #include "intel_fb.h" #include "intel_fb_pin.h" #include "intel_fbdev.h" +#include "intel_fbdev_fb.h" #include "intel_frontbuffer.h" struct intel_fbdev { @@ -146,65 +146,6 @@ static const struct fb_ops intelfb_ops = { .fb_mmap = intel_fbdev_mmap, }; -static int intelfb_alloc(struct drm_fb_helper *helper, - struct drm_fb_helper_surface_size *sizes) -{ - struct intel_fbdev *ifbdev = to_intel_fbdev(helper); - struct drm_framebuffer *fb; - struct drm_device *dev = helper->dev; - struct drm_i915_private *dev_priv = to_i915(dev); - struct drm_mode_fb_cmd2 mode_cmd = {}; - struct drm_i915_gem_object *obj; - int size; - - /* we don't do packed 24bpp */ - if (sizes->surface_bpp == 24) - sizes->surface_bpp = 32; - - mode_cmd.width = sizes->surface_width; - mode_cmd.height = sizes->surface_height; - - mode_cmd.pitches[0] = ALIGN(mode_cmd.width * - DIV_ROUND_UP(sizes->surface_bpp, 8), 64); - mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, - sizes->surface_depth); - - size = mode_cmd.pitches[0] * mode_cmd.height; - size = PAGE_ALIGN(size); - - obj = ERR_PTR(-ENODEV); - if (HAS_LMEM(dev_priv)) { - obj = i915_gem_object_create_lmem(dev_priv, size, - I915_BO_ALLOC_CONTIGUOUS | - I915_BO_ALLOC_USER); - } else { - /* - * If the FB is too big, just don't use it since fbdev is not very - * important and we should probably use that space with FBC or other - * features. - * - * Also skip stolen on MTL as Wa_22018444074 mitigation. - */ - if (!(IS_METEORLAKE(dev_priv)) && 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); - } - - if (IS_ERR(obj)) { - drm_err(&dev_priv->drm, "failed to allocate framebuffer (%pe)\n", obj); - return PTR_ERR(obj); - } - - fb = intel_framebuffer_create(obj, &mode_cmd); - i915_gem_object_put(obj); - if (IS_ERR(fb)) - return PTR_ERR(fb); - - ifbdev->fb = to_intel_framebuffer(fb); - return 0; -} - static int intelfb_create(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes) { @@ -213,7 +154,6 @@ static int intelfb_create(struct drm_fb_helper *helper, struct drm_device *dev = helper->dev; struct drm_i915_private *dev_priv = to_i915(dev); struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); - struct i915_ggtt *ggtt = to_gt(dev_priv)->ggtt; const struct i915_gtt_view view = { .type = I915_GTT_VIEW_NORMAL, }; @@ -222,9 +162,7 @@ static int intelfb_create(struct drm_fb_helper *helper, struct i915_vma *vma; unsigned long flags = 0; bool prealloc = false; - void __iomem *vaddr; struct drm_i915_gem_object *obj; - struct i915_gem_ww_ctx ww; int ret; mutex_lock(&ifbdev->hpd_lock); @@ -245,12 +183,13 @@ static int intelfb_create(struct drm_fb_helper *helper, intel_fb = ifbdev->fb = NULL; } if (!intel_fb || drm_WARN_ON(dev, !intel_fb_obj(&intel_fb->base))) { + struct drm_framebuffer *fb; drm_dbg_kms(&dev_priv->drm, "no BIOS fb, allocating a new one\n"); - ret = intelfb_alloc(helper, sizes); - if (ret) - return ret; - intel_fb = ifbdev->fb; + fb = intel_fbdev_fb_alloc(helper, sizes); + if (IS_ERR(fb)) + return PTR_ERR(fb); + intel_fb = ifbdev->fb = to_intel_framebuffer(fb); } else { drm_dbg_kms(&dev_priv->drm, "re-using BIOS fb\n"); prealloc = true; @@ -283,49 +222,18 @@ static int intelfb_create(struct drm_fb_helper *helper, info->fbops = &intelfb_ops; obj = intel_fb_obj(&intel_fb->base); - if (i915_gem_object_is_lmem(obj)) { - struct intel_memory_region *mem = obj->mm.region; - - /* 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 { - /* Our framebuffer is the entirety of fbdev's system memory */ - info->fix.smem_start = - (unsigned long)(ggtt->gmadr.start + i915_ggtt_offset(vma)); - info->fix.smem_len = vma->size; - } - - for_i915_gem_ww(&ww, ret, false) { - ret = i915_gem_object_lock(vma->obj, &ww); - - if (ret) - continue; - - vaddr = i915_vma_pin_iomap(vma); - if (IS_ERR(vaddr)) { - drm_err(&dev_priv->drm, - "Failed to remap framebuffer into virtual memory (%pe)\n", vaddr); - ret = PTR_ERR(vaddr); - continue; - } - } + ret = intel_fbdev_fb_fill_info(dev_priv, info, obj, vma); if (ret) goto out_unpin; - info->screen_base = vaddr; - info->screen_size = vma->size; - drm_fb_helper_fill_info(info, &ifbdev->helper, sizes); /* If the object is shmemfs backed, it will have given us zeroed pages. * If the object is stolen however, it will be full of whatever * garbage was left in there. */ - if (!i915_gem_object_is_shmem(vma->obj) && !prealloc) + if (!i915_gem_object_is_shmem(obj) && !prealloc) memset_io(info->screen_base, 0, info->screen_size); /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */ @@ -424,12 +332,12 @@ static bool intel_fbdev_init_bios(struct drm_device *dev, continue; } - if (obj->base.size > max_size) { + if (intel_bo_to_drm_bo(obj)->size > max_size) { drm_dbg_kms(&i915->drm, "found possible fb from [PLANE:%d:%s]\n", plane->base.base.id, plane->base.name); fb = to_intel_framebuffer(plane_state->uapi.fb); - max_size = obj->base.size; + max_size = intel_bo_to_drm_bo(obj)->size; } } diff --git a/drivers/gpu/drm/i915/display/intel_fbdev_fb.c b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c new file mode 100644 index 00000000000000..717c3a3237c481 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_fbdev_fb.c @@ -0,0 +1,115 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#include + +#include "gem/i915_gem_lmem.h" + +#include "i915_drv.h" +#include "intel_display_types.h" +#include "intel_fbdev_fb.h" + +struct drm_framebuffer *intel_fbdev_fb_alloc(struct drm_fb_helper *helper, + struct drm_fb_helper_surface_size *sizes) +{ + struct drm_framebuffer *fb; + struct drm_device *dev = helper->dev; + struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_mode_fb_cmd2 mode_cmd = {}; + struct drm_i915_gem_object *obj; + int size; + + /* we don't do packed 24bpp */ + if (sizes->surface_bpp == 24) + sizes->surface_bpp = 32; + + mode_cmd.width = sizes->surface_width; + mode_cmd.height = sizes->surface_height; + + mode_cmd.pitches[0] = ALIGN(mode_cmd.width * + DIV_ROUND_UP(sizes->surface_bpp, 8), 64); + mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, + sizes->surface_depth); + + size = mode_cmd.pitches[0] * mode_cmd.height; + size = PAGE_ALIGN(size); + + obj = ERR_PTR(-ENODEV); + if (HAS_LMEM(dev_priv)) { + obj = i915_gem_object_create_lmem(dev_priv, size, + I915_BO_ALLOC_CONTIGUOUS | + I915_BO_ALLOC_USER); + } else { + /* + * If the FB is too big, just don't use it since fbdev is not very + * important and we should probably use that space with FBC or other + * features. + * + * Also skip stolen on MTL as Wa_22018444074 mitigation. + */ + if (!(IS_METEORLAKE(dev_priv)) && 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); + } + + if (IS_ERR(obj)) { + drm_err(&dev_priv->drm, "failed to allocate framebuffer (%pe)\n", obj); + return ERR_PTR(-ENOMEM); + } + + fb = intel_framebuffer_create(obj, &mode_cmd); + i915_gem_object_put(obj); + + return fb; +} + +int intel_fbdev_fb_fill_info(struct drm_i915_private *i915, struct fb_info *info, + struct drm_i915_gem_object *obj, struct i915_vma *vma) +{ + struct i915_gem_ww_ctx ww; + void __iomem *vaddr; + int ret; + + if (i915_gem_object_is_lmem(obj)) { + struct intel_memory_region *mem = obj->mm.region; + + /* 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 { + struct i915_ggtt *ggtt = to_gt(i915)->ggtt; + + /* Our framebuffer is the entirety of fbdev's system memory */ + info->fix.smem_start = + (unsigned long)(ggtt->gmadr.start + i915_ggtt_offset(vma)); + info->fix.smem_len = vma->size; + } + + for_i915_gem_ww(&ww, ret, false) { + ret = i915_gem_object_lock(vma->obj, &ww); + + if (ret) + continue; + + vaddr = i915_vma_pin_iomap(vma); + if (IS_ERR(vaddr)) { + drm_err(&i915->drm, + "Failed to remap framebuffer into virtual memory (%pe)\n", vaddr); + ret = PTR_ERR(vaddr); + continue; + } + } + + if (ret) + return ret; + + info->screen_base = vaddr; + info->screen_size = intel_bo_to_drm_bo(obj)->size; + + return 0; +} diff --git a/drivers/gpu/drm/i915/display/intel_fbdev_fb.h b/drivers/gpu/drm/i915/display/intel_fbdev_fb.h new file mode 100644 index 00000000000000..a395b2c65d33b7 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_fbdev_fb.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2023 Intel Corporation + */ + +#ifndef __INTEL_FBDEV_FB_H__ +#define __INTEL_FBDEV_FB_H__ + +struct drm_fb_helper; +struct drm_fb_helper_surface_size; +struct drm_i915_gem_object; +struct drm_i915_private; +struct fb_info; +struct i915_vma; + +struct drm_framebuffer *intel_fbdev_fb_alloc(struct drm_fb_helper *helper, + struct drm_fb_helper_surface_size *sizes); +int intel_fbdev_fb_fill_info(struct drm_i915_private *i915, struct fb_info *info, + struct drm_i915_gem_object *obj, struct i915_vma *vma); + +#endif diff --git a/drivers/gpu/drm/i915/display/intel_fdi.c b/drivers/gpu/drm/i915/display/intel_fdi.c index e6429dfebe159b..295a0f24ebbf78 100644 --- a/drivers/gpu/drm/i915/display/intel_fdi.c +++ b/drivers/gpu/drm/i915/display/intel_fdi.c @@ -10,6 +10,7 @@ #include "intel_crtc.h" #include "intel_ddi.h" #include "intel_de.h" +#include "intel_dp.h" #include "intel_display_types.h" #include "intel_fdi.h" #include "intel_fdi_regs.h" @@ -338,8 +339,11 @@ int ilk_fdi_compute_config(struct intel_crtc *crtc, pipe_config->fdi_lanes = lane; - intel_link_compute_m_n(pipe_config->pipe_bpp, lane, fdi_dotclock, - link_bw, &pipe_config->fdi_m_n, false); + intel_link_compute_m_n(to_bpp_x16(pipe_config->pipe_bpp), + lane, fdi_dotclock, + link_bw, + intel_dp_bw_fec_overhead(false), + &pipe_config->fdi_m_n); return 0; } diff --git a/drivers/gpu/drm/i915/display/intel_frontbuffer.c b/drivers/gpu/drm/i915/display/intel_frontbuffer.c index ec46716b2f49ec..2ea37c0414a958 100644 --- a/drivers/gpu/drm/i915/display/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/display/intel_frontbuffer.c @@ -265,8 +265,6 @@ static void frontbuffer_release(struct kref *ref) spin_unlock(&intel_bo_to_i915(obj)->display.fb_tracking.lock); i915_active_fini(&front->write); - - i915_gem_object_put(obj); kfree_rcu(front, rcu); } diff --git a/drivers/gpu/drm/i915/display/intel_gmbus.c b/drivers/gpu/drm/i915/display/intel_gmbus.c index 40d7b6f3f4891c..e9e4dcf345f957 100644 --- a/drivers/gpu/drm/i915/display/intel_gmbus.c +++ b/drivers/gpu/drm/i915/display/intel_gmbus.c @@ -899,7 +899,6 @@ int intel_gmbus_setup(struct drm_i915_private *i915) } bus->adapter.owner = THIS_MODULE; - bus->adapter.class = I2C_CLASS_DDC; snprintf(bus->adapter.name, sizeof(bus->adapter.name), "i915 gmbus %s", gmbus_pin->name); diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c index c89da3568ebdb3..39b3f7c0c77c99 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp.c +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c @@ -923,7 +923,7 @@ static int _intel_hdcp_disable(struct intel_connector *connector) return 0; } -static int _intel_hdcp_enable(struct intel_connector *connector) +static int intel_hdcp1_enable(struct intel_connector *connector) { struct drm_i915_private *i915 = to_i915(connector->base.dev); struct intel_hdcp *hdcp = &connector->hdcp; @@ -1058,7 +1058,7 @@ static int intel_hdcp_check_link(struct intel_connector *connector) goto out; } - ret = _intel_hdcp_enable(connector); + ret = intel_hdcp1_enable(connector); if (ret) { drm_err(&i915->drm, "Failed to enable hdcp (%d)\n", ret); intel_hdcp_update_value(connector, @@ -2324,10 +2324,10 @@ intel_hdcp_set_streams(struct intel_digital_port *dig_port, return 0; } -int intel_hdcp_enable(struct intel_atomic_state *state, - struct intel_encoder *encoder, - const struct intel_crtc_state *pipe_config, - const struct drm_connector_state *conn_state) +static int _intel_hdcp_enable(struct intel_atomic_state *state, + struct intel_encoder *encoder, + const struct intel_crtc_state *pipe_config, + const struct drm_connector_state *conn_state) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); struct intel_connector *connector = @@ -2388,7 +2388,7 @@ int intel_hdcp_enable(struct intel_atomic_state *state, */ if (ret && intel_hdcp_capable(connector) && hdcp->content_type != DRM_MODE_HDCP_CONTENT_TYPE1) { - ret = _intel_hdcp_enable(connector); + ret = intel_hdcp1_enable(connector); } if (!ret) { @@ -2404,6 +2404,27 @@ int intel_hdcp_enable(struct intel_atomic_state *state, return ret; } +void intel_hdcp_enable(struct intel_atomic_state *state, + struct intel_encoder *encoder, + 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 intel_hdcp *hdcp = &connector->hdcp; + + /* + * Enable hdcp if it's desired or if userspace is enabled and + * driver set its state to undesired + */ + if (conn_state->content_protection == + DRM_MODE_CONTENT_PROTECTION_DESIRED || + (conn_state->content_protection == + DRM_MODE_CONTENT_PROTECTION_ENABLED && hdcp->value == + DRM_MODE_CONTENT_PROTECTION_UNDESIRED)) + _intel_hdcp_enable(state, encoder, crtc_state, conn_state); +} + int intel_hdcp_disable(struct intel_connector *connector) { struct intel_digital_port *dig_port = intel_attached_dig_port(connector); @@ -2491,7 +2512,7 @@ void intel_hdcp_update_pipe(struct intel_atomic_state *state, } if (desired_and_not_enabled || content_protection_type_changed) - intel_hdcp_enable(state, encoder, crtc_state, conn_state); + _intel_hdcp_enable(state, encoder, crtc_state, conn_state); } void intel_hdcp_component_fini(struct drm_i915_private *i915) diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.h b/drivers/gpu/drm/i915/display/intel_hdcp.h index 5997c52a095897..a9c784fd9ba507 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp.h +++ b/drivers/gpu/drm/i915/display/intel_hdcp.h @@ -28,10 +28,10 @@ void intel_hdcp_atomic_check(struct drm_connector *connector, int intel_hdcp_init(struct intel_connector *connector, struct intel_digital_port *dig_port, const struct intel_hdcp_shim *hdcp_shim); -int intel_hdcp_enable(struct intel_atomic_state *state, - struct intel_encoder *encoder, - const struct intel_crtc_state *pipe_config, - const struct drm_connector_state *conn_state); +void intel_hdcp_enable(struct intel_atomic_state *state, + struct intel_encoder *encoder, + const struct intel_crtc_state *pipe_config, + const struct drm_connector_state *conn_state); int intel_hdcp_disable(struct intel_connector *connector); void intel_hdcp_update_pipe(struct intel_atomic_state *state, struct intel_encoder *encoder, diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index bfa456fa7d25c9..39e4f5f7c81715 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -3034,16 +3034,6 @@ void intel_hdmi_init_connector(struct intel_digital_port *dig_port, "HDCP init failed, skipping.\n"); } - /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written - * 0xd. Failure to do so will result in spurious interrupts being - * generated on the port when a cable is not attached. - */ - if (IS_G45(dev_priv)) { - u32 temp = intel_de_read(dev_priv, PEG_BAND_GAP_DATA); - intel_de_write(dev_priv, PEG_BAND_GAP_DATA, - (temp & ~0xf) | 0xd); - } - cec_fill_conn_info_from_drm(&conn_info, connector); intel_hdmi->cec_notifier = diff --git a/drivers/gpu/drm/i915/display/intel_hotplug_irq.c b/drivers/gpu/drm/i915/display/intel_hotplug_irq.c index f07047e9cb301d..04f62f27ad74b1 100644 --- a/drivers/gpu/drm/i915/display/intel_hotplug_irq.c +++ b/drivers/gpu/drm/i915/display/intel_hotplug_irq.c @@ -1361,11 +1361,24 @@ static void bxt_hpd_irq_setup(struct drm_i915_private *dev_priv) bxt_hpd_detection_setup(dev_priv); } +static void g45_hpd_peg_band_gap_wa(struct drm_i915_private *i915) +{ + /* + * For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written + * 0xd. Failure to do so will result in spurious interrupts being + * generated on the port when a cable is not attached. + */ + intel_de_rmw(i915, PEG_BAND_GAP_DATA, 0xf, 0xd); +} + static void i915_hpd_enable_detection(struct intel_encoder *encoder) { struct drm_i915_private *i915 = to_i915(encoder->base.dev); u32 hotplug_en = hpd_mask_i915[encoder->hpd_pin]; + if (IS_G45(i915)) + g45_hpd_peg_band_gap_wa(i915); + /* HPD sense and interrupt enable are one and the same */ i915_hotplug_interrupt_update(i915, hotplug_en, hotplug_en); } @@ -1389,6 +1402,9 @@ static void i915_hpd_irq_setup(struct drm_i915_private *dev_priv) hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64; hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50; + if (IS_G45(dev_priv)) + g45_hpd_peg_band_gap_wa(dev_priv); + /* Ignore TV since it's buggy */ i915_hotplug_interrupt_update_locked(dev_priv, HOTPLUG_INT_EN_MASK | diff --git a/drivers/gpu/drm/i915/display/intel_link_bw.c b/drivers/gpu/drm/i915/display/intel_link_bw.c index c5eb5f24253616..9c6d35a405a182 100644 --- a/drivers/gpu/drm/i915/display/intel_link_bw.c +++ b/drivers/gpu/drm/i915/display/intel_link_bw.c @@ -7,6 +7,7 @@ #include "intel_atomic.h" #include "intel_display_types.h" +#include "intel_dp_mst.h" #include "intel_fdi.h" #include "intel_link_bw.h" @@ -21,6 +22,7 @@ void intel_link_bw_init_limits(struct drm_i915_private *i915, struct intel_link_ { enum pipe pipe; + limits->force_fec_pipes = 0; limits->bpp_limit_reached_pipes = 0; for_each_pipe(i915, pipe) limits->max_bpp_x16[pipe] = INT_MAX; @@ -53,11 +55,11 @@ int intel_link_bw_reduce_bpp(struct intel_atomic_state *state, struct drm_i915_private *i915 = to_i915(state->base.dev); enum pipe max_bpp_pipe = INVALID_PIPE; struct intel_crtc *crtc; - int max_bpp = 0; + int max_bpp_x16 = 0; for_each_intel_crtc_in_pipe_mask(&i915->drm, crtc, pipe_mask) { struct intel_crtc_state *crtc_state; - int link_bpp; + int link_bpp_x16; if (limits->bpp_limit_reached_pipes & BIT(crtc->pipe)) continue; @@ -68,7 +70,7 @@ int intel_link_bw_reduce_bpp(struct intel_atomic_state *state, return PTR_ERR(crtc_state); if (crtc_state->dsc.compression_enable) - link_bpp = crtc_state->dsc.compressed_bpp; + link_bpp_x16 = crtc_state->dsc.compressed_bpp_x16; else /* * TODO: for YUV420 the actual link bpp is only half @@ -76,10 +78,10 @@ int intel_link_bw_reduce_bpp(struct intel_atomic_state *state, * is based on the pipe bpp value, set the actual link bpp * limit here once the MST BW allocation is fixed. */ - link_bpp = crtc_state->pipe_bpp; + link_bpp_x16 = to_bpp_x16(crtc_state->pipe_bpp); - if (link_bpp > max_bpp) { - max_bpp = link_bpp; + if (link_bpp_x16 > max_bpp_x16) { + max_bpp_x16 = link_bpp_x16; max_bpp_pipe = crtc->pipe; } } @@ -87,7 +89,7 @@ int intel_link_bw_reduce_bpp(struct intel_atomic_state *state, if (max_bpp_pipe == INVALID_PIPE) return -ENOSPC; - limits->max_bpp_x16[max_bpp_pipe] = to_bpp_x16(max_bpp) - 1; + limits->max_bpp_x16[max_bpp_pipe] = max_bpp_x16 - 1; return intel_modeset_pipes_in_mask_early(state, reason, BIT(max_bpp_pipe)); @@ -143,6 +145,10 @@ static int check_all_link_config(struct intel_atomic_state *state, /* TODO: Check additional shared display link configurations like MST */ int ret; + ret = intel_dp_mst_atomic_check_link(state, limits); + if (ret) + return ret; + ret = intel_fdi_atomic_check_link(state, limits); if (ret) return ret; @@ -158,6 +164,12 @@ assert_link_limit_change_valid(struct drm_i915_private *i915, bool bpps_changed = false; enum pipe pipe; + /* FEC can't be forced off after it was forced on. */ + if (drm_WARN_ON(&i915->drm, + (old_limits->force_fec_pipes & new_limits->force_fec_pipes) != + old_limits->force_fec_pipes)) + return false; + for_each_pipe(i915, pipe) { /* The bpp limit can only decrease. */ if (drm_WARN_ON(&i915->drm, @@ -172,7 +184,9 @@ assert_link_limit_change_valid(struct drm_i915_private *i915, /* At least one limit must change. */ if (drm_WARN_ON(&i915->drm, - !bpps_changed)) + !bpps_changed && + new_limits->force_fec_pipes == + old_limits->force_fec_pipes)) return false; return true; diff --git a/drivers/gpu/drm/i915/display/intel_link_bw.h b/drivers/gpu/drm/i915/display/intel_link_bw.h index e07df22a779a2e..2cf57307cc2491 100644 --- a/drivers/gpu/drm/i915/display/intel_link_bw.h +++ b/drivers/gpu/drm/i915/display/intel_link_bw.h @@ -16,6 +16,7 @@ struct intel_atomic_state; struct intel_crtc_state; struct intel_link_bw_limits { + u8 force_fec_pipes; u8 bpp_limit_reached_pipes; /* in 1/16 bpp units */ int max_bpp_x16[I915_MAX_PIPES]; diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c index bcbdd1984fd908..221f5c6c871b12 100644 --- a/drivers/gpu/drm/i915/display/intel_lvds.c +++ b/drivers/gpu/drm/i915/display/intel_lvds.c @@ -185,7 +185,7 @@ static void intel_lvds_pps_get_hw_state(struct drm_i915_private *dev_priv, /* Convert from 100ms to 100us units */ pps->t4 = val * 1000; - if (DISPLAY_VER(dev_priv) <= 4 && + if (DISPLAY_VER(dev_priv) < 5 && pps->t1_t2 == 0 && pps->t5 == 0 && pps->t3 == 0 && pps->tx == 0) { drm_dbg_kms(&dev_priv->drm, "Panel power timings uninitialized, " @@ -799,8 +799,8 @@ static bool compute_is_dual_link_lvds(struct intel_lvds_encoder *lvds_encoder) unsigned int val; /* use the module option value if specified */ - if (i915->params.lvds_channel_mode > 0) - return i915->params.lvds_channel_mode == 2; + if (i915->display.params.lvds_channel_mode > 0) + return i915->display.params.lvds_channel_mode == 2; /* single channel LVDS is limited to 112 MHz */ if (fixed_mode->clock > 112999) diff --git a/drivers/gpu/drm/i915/display/intel_modeset_setup.c b/drivers/gpu/drm/i915/display/intel_modeset_setup.c index b8f43efb0ab5a2..94eece7f63be33 100644 --- a/drivers/gpu/drm/i915/display/intel_modeset_setup.c +++ b/drivers/gpu/drm/i915/display/intel_modeset_setup.c @@ -318,6 +318,12 @@ static void intel_modeset_update_connector_atomic_state(struct drm_i915_private const struct intel_crtc_state *crtc_state = to_intel_crtc_state(crtc->base.state); + if (crtc_state->dsc.compression_enable) { + drm_WARN_ON(&i915->drm, !connector->dp.dsc_decompression_aux); + connector->dp.dsc_decompression_enabled = true; + } else { + connector->dp.dsc_decompression_enabled = false; + } conn_state->max_bpc = (crtc_state->pipe_bpp ?: 24) / 3; } } diff --git a/drivers/gpu/drm/i915/display/intel_modeset_verify.c b/drivers/gpu/drm/i915/display/intel_modeset_verify.c index 5e1c2c78041263..076298a8d40585 100644 --- a/drivers/gpu/drm/i915/display/intel_modeset_verify.c +++ b/drivers/gpu/drm/i915/display/intel_modeset_verify.c @@ -244,7 +244,7 @@ void intel_modeset_verify_crtc(struct intel_atomic_state *state, verify_crtc_state(state, crtc); intel_shared_dpll_state_verify(state, crtc); intel_mpllb_state_verify(state, crtc); - intel_c10pll_state_verify(state, crtc); + intel_cx0pll_state_verify(state, crtc); } void intel_modeset_verify_disabled(struct intel_atomic_state *state) diff --git a/drivers/gpu/drm/i915/display/intel_opregion.c b/drivers/gpu/drm/i915/display/intel_opregion.c index 84078fb82b2f74..1ce785db6a5e19 100644 --- a/drivers/gpu/drm/i915/display/intel_opregion.c +++ b/drivers/gpu/drm/i915/display/intel_opregion.c @@ -841,7 +841,7 @@ static int intel_load_vbt_firmware(struct drm_i915_private *dev_priv) { struct intel_opregion *opregion = &dev_priv->display.opregion; const struct firmware *fw = NULL; - const char *name = dev_priv->params.vbt_firmware; + const char *name = dev_priv->display.params.vbt_firmware; int ret; if (!name || !*name) diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c index 483beedac5b830..0d8e5320a4f88e 100644 --- a/drivers/gpu/drm/i915/display/intel_panel.c +++ b/drivers/gpu/drm/i915/display/intel_panel.c @@ -46,8 +46,8 @@ bool intel_panel_use_ssc(struct drm_i915_private *i915) { - if (i915->params.panel_use_ssc >= 0) - return i915->params.panel_use_ssc != 0; + if (i915->display.params.panel_use_ssc >= 0) + return i915->display.params.panel_use_ssc != 0; return i915->display.vbt.lvds_use_ssc && !intel_has_quirk(i915, QUIRK_LVDS_SSC_DISABLE); } diff --git a/drivers/gpu/drm/i915/display/intel_pch_display.c b/drivers/gpu/drm/i915/display/intel_pch_display.c index 866786e6b32f62..baf679759e0042 100644 --- a/drivers/gpu/drm/i915/display/intel_pch_display.c +++ b/drivers/gpu/drm/i915/display/intel_pch_display.c @@ -8,6 +8,7 @@ #include "intel_crt.h" #include "intel_de.h" #include "intel_display_types.h" +#include "intel_dpll.h" #include "intel_fdi.h" #include "intel_fdi_regs.h" #include "intel_lvds.h" diff --git a/drivers/gpu/drm/i915/display/intel_pps.c b/drivers/gpu/drm/i915/display/intel_pps.c index 73f0f1714b3778..a8fa3a20990e76 100644 --- a/drivers/gpu/drm/i915/display/intel_pps.c +++ b/drivers/gpu/drm/i915/display/intel_pps.c @@ -90,7 +90,7 @@ vlv_power_sequencer_kick(struct intel_dp *intel_dp) struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); enum pipe pipe = intel_dp->pps.pps_pipe; bool pll_enabled, release_cl_override = false; - enum dpio_phy phy = DPIO_PHY(pipe); + enum dpio_phy phy = vlv_pipe_to_phy(pipe); enum dpio_channel ch = vlv_pipe_to_channel(pipe); u32 DP; diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 4f1f31fc9529d7..57bbf3e3af92fb 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -29,6 +29,7 @@ #include "i915_reg.h" #include "intel_atomic.h" #include "intel_crtc.h" +#include "intel_ddi.h" #include "intel_de.h" #include "intel_display_types.h" #include "intel_dp.h" @@ -172,6 +173,15 @@ * irrelevant for normal operation. */ +bool intel_encoder_can_psr(struct intel_encoder *encoder) +{ + if (intel_encoder_is_dp(encoder) || encoder->type == INTEL_OUTPUT_DP_MST) + return CAN_PSR(enc_to_intel_dp(encoder)) || + CAN_PANEL_REPLAY(enc_to_intel_dp(encoder)); + else + return false; +} + static bool psr_global_enabled(struct intel_dp *intel_dp) { struct intel_connector *connector = intel_dp->attached_connector; @@ -179,9 +189,9 @@ static bool psr_global_enabled(struct intel_dp *intel_dp) switch (intel_dp->psr.debug & I915_PSR_DEBUG_MODE_MASK) { case I915_PSR_DEBUG_DEFAULT: - if (i915->params.enable_psr == -1) + if (i915->display.params.enable_psr == -1) return connector->panel.vbt.psr.enable; - return i915->params.enable_psr; + return i915->display.params.enable_psr; case I915_PSR_DEBUG_DISABLE: return false; default: @@ -198,7 +208,7 @@ static bool psr2_global_enabled(struct intel_dp *intel_dp) case I915_PSR_DEBUG_FORCE_PSR1: return false; default: - if (i915->params.enable_psr == 1) + if (i915->display.params.enable_psr == 1) return false; return true; } @@ -474,27 +484,41 @@ exit: intel_dp->psr.su_y_granularity = y; } -void intel_psr_init_dpcd(struct intel_dp *intel_dp) +static void _panel_replay_init_dpcd(struct intel_dp *intel_dp) { - struct drm_i915_private *dev_priv = - to_i915(dp_to_dig_port(intel_dp)->base.base.dev); + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + u8 pr_dpcd = 0; - drm_dp_dpcd_read(&intel_dp->aux, DP_PSR_SUPPORT, intel_dp->psr_dpcd, - sizeof(intel_dp->psr_dpcd)); + intel_dp->psr.sink_panel_replay_support = false; + drm_dp_dpcd_readb(&intel_dp->aux, DP_PANEL_REPLAY_CAP, &pr_dpcd); - if (!intel_dp->psr_dpcd[0]) + if (!(pr_dpcd & DP_PANEL_REPLAY_SUPPORT)) { + drm_dbg_kms(&i915->drm, + "Panel replay is not supported by panel\n"); return; - drm_dbg_kms(&dev_priv->drm, "eDP panel supports PSR version %x\n", + } + + drm_dbg_kms(&i915->drm, + "Panel replay is supported by panel\n"); + intel_dp->psr.sink_panel_replay_support = true; +} + +static void _psr_init_dpcd(struct intel_dp *intel_dp) +{ + struct drm_i915_private *i915 = + to_i915(dp_to_dig_port(intel_dp)->base.base.dev); + + drm_dbg_kms(&i915->drm, "eDP panel supports PSR version %x\n", intel_dp->psr_dpcd[0]); if (drm_dp_has_quirk(&intel_dp->desc, DP_DPCD_QUIRK_NO_PSR)) { - drm_dbg_kms(&dev_priv->drm, + drm_dbg_kms(&i915->drm, "PSR support not currently available for this panel\n"); return; } if (!(intel_dp->edp_dpcd[1] & DP_EDP_SET_POWER_CAP)) { - drm_dbg_kms(&dev_priv->drm, + drm_dbg_kms(&i915->drm, "Panel lacks power state control, PSR cannot be enabled\n"); return; } @@ -503,8 +527,8 @@ void intel_psr_init_dpcd(struct intel_dp *intel_dp) intel_dp->psr.sink_sync_latency = intel_dp_get_sink_sync_latency(intel_dp); - if (DISPLAY_VER(dev_priv) >= 9 && - (intel_dp->psr_dpcd[0] == DP_PSR2_WITH_Y_COORD_IS_SUPPORTED)) { + if (DISPLAY_VER(i915) >= 9 && + intel_dp->psr_dpcd[0] == DP_PSR2_WITH_Y_COORD_IS_SUPPORTED) { bool y_req = intel_dp->psr_dpcd[1] & DP_PSR2_SU_Y_COORDINATE_REQUIRED; bool alpm = intel_dp_get_alpm_status(intel_dp); @@ -521,14 +545,25 @@ void intel_psr_init_dpcd(struct intel_dp *intel_dp) * GTC first. */ intel_dp->psr.sink_psr2_support = y_req && alpm; - drm_dbg_kms(&dev_priv->drm, "PSR2 %ssupported\n", + drm_dbg_kms(&i915->drm, "PSR2 %ssupported\n", intel_dp->psr.sink_psr2_support ? "" : "not "); + } +} - if (intel_dp->psr.sink_psr2_support) { - intel_dp->psr.colorimetry_support = - intel_dp_get_colorimetry_status(intel_dp); - intel_dp_get_su_granularity(intel_dp); - } +void intel_psr_init_dpcd(struct intel_dp *intel_dp) +{ + _panel_replay_init_dpcd(intel_dp); + + drm_dp_dpcd_read(&intel_dp->aux, DP_PSR_SUPPORT, intel_dp->psr_dpcd, + sizeof(intel_dp->psr_dpcd)); + + if (intel_dp->psr_dpcd[0]) + _psr_init_dpcd(intel_dp); + + if (intel_dp->psr.sink_psr2_support) { + intel_dp->psr.colorimetry_support = + intel_dp_get_colorimetry_status(intel_dp); + intel_dp_get_su_granularity(intel_dp); } } @@ -574,8 +609,11 @@ static void intel_psr_enable_sink(struct intel_dp *intel_dp) struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); u8 dpcd_val = DP_PSR_ENABLE; - /* Enable ALPM at sink for psr2 */ + if (intel_dp->psr.panel_replay_enabled) + return; + if (intel_dp->psr.psr2_enabled) { + /* Enable ALPM at sink for psr2 */ drm_dp_dpcd_writeb(&intel_dp->aux, DP_RECEIVER_ALPM_CONFIG, DP_ALPM_ENABLE | DP_ALPM_LOCK_ERROR_IRQ_HPD_ENABLE); @@ -592,6 +630,9 @@ static void intel_psr_enable_sink(struct intel_dp *intel_dp) if (intel_dp->psr.req_psr2_sdp_prior_scanline) dpcd_val |= DP_PSR_SU_REGION_SCANLINE_CAPTURE; + if (intel_dp->psr.entry_setup_frames > 0) + dpcd_val |= DP_PSR_FRAME_CAPTURE; + drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG, dpcd_val); drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER, DP_SET_POWER_D0); @@ -606,7 +647,7 @@ static u32 intel_psr1_get_tp_time(struct intel_dp *intel_dp) if (DISPLAY_VER(dev_priv) >= 11) val |= EDP_PSR_TP4_TIME_0us; - if (dev_priv->params.psr_safest_params) { + if (dev_priv->display.params.psr_safest_params) { val |= EDP_PSR_TP1_TIME_2500us; val |= EDP_PSR_TP2_TP3_TIME_2500us; goto check_tp3_sel; @@ -690,6 +731,9 @@ static void hsw_activate_psr1(struct intel_dp *intel_dp) if (DISPLAY_VER(dev_priv) >= 8) val |= EDP_PSR_CRC_ENABLE; + if (DISPLAY_VER(dev_priv) >= 20) + val |= LNL_EDP_PSR_ENTRY_SETUP_FRAMES(intel_dp->psr.entry_setup_frames); + intel_de_rmw(dev_priv, psr_ctl_reg(dev_priv, cpu_transcoder), ~EDP_PSR_RESTORE_PSR_ACTIVE_CTX_MASK, val); } @@ -700,7 +744,7 @@ static u32 intel_psr2_get_tp_time(struct intel_dp *intel_dp) struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); u32 val = 0; - if (dev_priv->params.psr_safest_params) + if (dev_priv->display.params.psr_safest_params) return EDP_PSR2_TP2_TIME_2500us; if (connector->panel.vbt.psr.psr2_tp2_tp3_wakeup_time_us >= 0 && @@ -727,21 +771,49 @@ static int psr2_block_count(struct intel_dp *intel_dp) return psr2_block_count_lines(intel_dp) / 4; } +static u8 frames_before_su_entry(struct intel_dp *intel_dp) +{ + u8 frames_before_su_entry; + + frames_before_su_entry = max_t(u8, + intel_dp->psr.sink_sync_latency + 1, + 2); + + /* Entry setup frames must be at least 1 less than frames before SU entry */ + if (intel_dp->psr.entry_setup_frames >= frames_before_su_entry) + frames_before_su_entry = intel_dp->psr.entry_setup_frames + 1; + + return frames_before_su_entry; +} + +static void dg2_activate_panel_replay(struct intel_dp *intel_dp) +{ + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + + intel_de_rmw(dev_priv, PSR2_MAN_TRK_CTL(intel_dp->psr.transcoder), + 0, ADLP_PSR2_MAN_TRK_CTL_SF_CONTINUOS_FULL_FRAME); + + intel_de_rmw(dev_priv, TRANS_DP2_CTL(intel_dp->psr.transcoder), 0, + TRANS_DP2_PANEL_REPLAY_ENABLE); +} + static void hsw_activate_psr2(struct intel_dp *intel_dp) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); enum transcoder cpu_transcoder = intel_dp->psr.transcoder; u32 val = EDP_PSR2_ENABLE; + u32 psr_val = 0; val |= EDP_PSR2_IDLE_FRAMES(psr_compute_idle_frames(intel_dp)); - if (DISPLAY_VER(dev_priv) <= 13 && !IS_ALDERLAKE_P(dev_priv)) + if (DISPLAY_VER(dev_priv) < 14 && !IS_ALDERLAKE_P(dev_priv)) val |= EDP_SU_TRACK_ENABLE; - if (DISPLAY_VER(dev_priv) >= 10 && DISPLAY_VER(dev_priv) <= 12) + if (DISPLAY_VER(dev_priv) >= 10 && DISPLAY_VER(dev_priv) < 13) val |= EDP_Y_COORDINATE_ENABLE; - val |= EDP_PSR2_FRAME_BEFORE_SU(max_t(u8, intel_dp->psr.sink_sync_latency + 1, 2)); + val |= EDP_PSR2_FRAME_BEFORE_SU(frames_before_su_entry(intel_dp)); + val |= intel_psr2_get_tp_time(intel_dp); if (DISPLAY_VER(dev_priv) >= 12) { @@ -785,6 +857,9 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp) if (intel_dp->psr.req_psr2_sdp_prior_scanline) val |= EDP_PSR2_SU_SDP_SCANLINE; + if (DISPLAY_VER(dev_priv) >= 20) + psr_val |= LNL_EDP_PSR_ENTRY_SETUP_FRAMES(intel_dp->psr.entry_setup_frames); + if (intel_dp->psr.psr2_sel_fetch_enabled) { u32 tmp; @@ -798,7 +873,7 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp) * PSR2 HW is incorrectly using EDP_PSR_TP1_TP3_SEL and BSpec is * recommending keep this bit unset while PSR2 is enabled. */ - intel_de_write(dev_priv, psr_ctl_reg(dev_priv, cpu_transcoder), 0); + intel_de_write(dev_priv, psr_ctl_reg(dev_priv, cpu_transcoder), psr_val); intel_de_write(dev_priv, EDP_PSR2_CTL(cpu_transcoder), val); } @@ -816,13 +891,13 @@ transcoder_has_psr2(struct drm_i915_private *dev_priv, enum transcoder cpu_trans return false; } -static u32 intel_get_frame_time_us(const struct intel_crtc_state *cstate) +static u32 intel_get_frame_time_us(const struct intel_crtc_state *crtc_state) { - if (!cstate || !cstate->hw.active) + if (!crtc_state->hw.active) return 0; return DIV_ROUND_UP(1000 * 1000, - drm_mode_vrefresh(&cstate->hw.adjusted_mode)); + drm_mode_vrefresh(&crtc_state->hw.adjusted_mode)); } static void psr2_program_idle_frames(struct intel_dp *intel_dp, @@ -943,7 +1018,7 @@ static bool intel_psr2_sel_fetch_config_valid(struct intel_dp *intel_dp, { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); - if (!dev_priv->params.enable_psr2_sel_fetch && + if (!dev_priv->display.params.enable_psr2_sel_fetch && intel_dp->psr.debug != I915_PSR_DEBUG_ENABLE_SEL_FETCH) { drm_dbg_kms(&dev_priv->drm, "PSR2 sel fetch not enabled, disabled by parameter\n"); @@ -1019,7 +1094,7 @@ static bool _compute_psr2_sdp_prior_scanline_indication(struct intel_dp *intel_d return true; /* Not supported <13 / Wa_22012279113:adl-p */ - if (DISPLAY_VER(dev_priv) <= 13 || intel_dp->edp_dpcd[0] < DP_EDP_14b) + if (DISPLAY_VER(dev_priv) < 14 || intel_dp->edp_dpcd[0] < DP_EDP_14b) return false; crtc_state->req_psr2_sdp_prior_scanline = true; @@ -1056,7 +1131,7 @@ static bool _compute_psr2_wake_times(struct intel_dp *intel_dp, fast_wake_lines > max_wake_lines) return false; - if (i915->params.psr_safest_params) + if (i915->display.params.psr_safest_params) io_wake_lines = fast_wake_lines = max_wake_lines; /* According to Bspec lower limit should be set as 7 lines. */ @@ -1066,6 +1141,39 @@ static bool _compute_psr2_wake_times(struct intel_dp *intel_dp, return true; } +static int intel_psr_entry_setup_frames(struct intel_dp *intel_dp, + const struct drm_display_mode *adjusted_mode) +{ + struct drm_i915_private *i915 = dp_to_i915(intel_dp); + int psr_setup_time = drm_dp_psr_setup_time(intel_dp->psr_dpcd); + int entry_setup_frames = 0; + + if (psr_setup_time < 0) { + drm_dbg_kms(&i915->drm, + "PSR condition failed: Invalid PSR setup time (0x%02x)\n", + intel_dp->psr_dpcd[1]); + return -ETIME; + } + + if (intel_usecs_to_scanlines(adjusted_mode, psr_setup_time) > + adjusted_mode->crtc_vtotal - adjusted_mode->crtc_vdisplay - 1) { + if (DISPLAY_VER(i915) >= 20) { + /* setup entry frames can be up to 3 frames */ + entry_setup_frames = 1; + drm_dbg_kms(&i915->drm, + "PSR setup entry frames %d\n", + entry_setup_frames); + } else { + drm_dbg_kms(&i915->drm, + "PSR condition failed: PSR setup time (%d us) too long\n", + psr_setup_time); + return -ETIME; + } + } + + return entry_setup_frames; +} + static bool intel_psr2_config_valid(struct intel_dp *intel_dp, struct intel_crtc_state *crtc_state) { @@ -1113,7 +1221,7 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp, * over PSR2. */ if (crtc_state->dsc.compression_enable && - (DISPLAY_VER(dev_priv) <= 13 && !IS_ALDERLAKE_P(dev_priv))) { + (DISPLAY_VER(dev_priv) < 14 && !IS_ALDERLAKE_P(dev_priv))) { drm_dbg_kms(&dev_priv->drm, "PSR2 cannot be enabled since DSC is enabled\n"); return false; @@ -1206,24 +1314,42 @@ unsupported: return false; } -void intel_psr_compute_config(struct intel_dp *intel_dp, - struct intel_crtc_state *crtc_state, - struct drm_connector_state *conn_state) +static bool _psr_compute_config(struct intel_dp *intel_dp, + struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); - const struct drm_display_mode *adjusted_mode = - &crtc_state->hw.adjusted_mode; - int psr_setup_time; + const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; + int entry_setup_frames; /* * Current PSR panels don't work reliably with VRR enabled * So if VRR is enabled, do not enable PSR. */ if (crtc_state->vrr.enable) - return; + return false; if (!CAN_PSR(intel_dp)) - return; + return false; + + entry_setup_frames = intel_psr_entry_setup_frames(intel_dp, adjusted_mode); + + if (entry_setup_frames >= 0) { + intel_dp->psr.entry_setup_frames = entry_setup_frames; + } else { + drm_dbg_kms(&dev_priv->drm, + "PSR condition failed: PSR setup timing not met\n"); + return false; + } + + return true; +} + +void intel_psr_compute_config(struct intel_dp *intel_dp, + struct intel_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); + const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; if (!psr_global_enabled(intel_dp)) { drm_dbg_kms(&dev_priv->drm, "PSR disabled by flag\n"); @@ -1242,23 +1368,14 @@ void intel_psr_compute_config(struct intel_dp *intel_dp, return; } - psr_setup_time = drm_dp_psr_setup_time(intel_dp->psr_dpcd); - if (psr_setup_time < 0) { - drm_dbg_kms(&dev_priv->drm, - "PSR condition failed: Invalid PSR setup time (0x%02x)\n", - intel_dp->psr_dpcd[1]); - return; - } + if (CAN_PANEL_REPLAY(intel_dp)) + crtc_state->has_panel_replay = true; + else + crtc_state->has_psr = _psr_compute_config(intel_dp, crtc_state); - if (intel_usecs_to_scanlines(adjusted_mode, psr_setup_time) > - adjusted_mode->crtc_vtotal - adjusted_mode->crtc_vdisplay - 1) { - drm_dbg_kms(&dev_priv->drm, - "PSR condition failed: PSR setup time (%d us) too long\n", - psr_setup_time); + if (!(crtc_state->has_panel_replay || crtc_state->has_psr)) return; - } - crtc_state->has_psr = true; crtc_state->has_psr2 = intel_psr2_config_valid(intel_dp, crtc_state); crtc_state->infoframes.enable |= intel_hdmi_infoframe_enable(DP_SDP_VSC); @@ -1279,18 +1396,23 @@ void intel_psr_get_config(struct intel_encoder *encoder, return; intel_dp = &dig_port->dp; - if (!CAN_PSR(intel_dp)) + if (!(CAN_PSR(intel_dp) || CAN_PANEL_REPLAY(intel_dp))) return; mutex_lock(&intel_dp->psr.lock); if (!intel_dp->psr.enabled) goto unlock; - /* - * Not possible to read EDP_PSR/PSR2_CTL registers as it is - * enabled/disabled because of frontbuffer tracking and others. - */ - pipe_config->has_psr = true; + if (intel_dp->psr.panel_replay_enabled) { + pipe_config->has_panel_replay = true; + } else { + /* + * Not possible to read EDP_PSR/PSR2_CTL registers as it is + * enabled/disabled because of frontbuffer tracking and others. + */ + pipe_config->has_psr = true; + } + pipe_config->has_psr2 = intel_dp->psr.psr2_enabled; pipe_config->infoframes.enable |= intel_hdmi_infoframe_enable(DP_SDP_VSC); @@ -1327,8 +1449,10 @@ static void intel_psr_activate(struct intel_dp *intel_dp) lockdep_assert_held(&intel_dp->psr.lock); - /* psr1 and psr2 are mutually exclusive.*/ - if (intel_dp->psr.psr2_enabled) + /* psr1, psr2 and panel-replay are mutually exclusive.*/ + if (intel_dp->psr.panel_replay_enabled) + dg2_activate_panel_replay(intel_dp); + else if (intel_dp->psr.psr2_enabled) hsw_activate_psr2(intel_dp); else hsw_activate_psr1(intel_dp); @@ -1401,8 +1525,18 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp, * can rely on frontbuffer tracking. */ mask = EDP_PSR_DEBUG_MASK_MEMUP | - EDP_PSR_DEBUG_MASK_HPD | - EDP_PSR_DEBUG_MASK_LPSP; + EDP_PSR_DEBUG_MASK_HPD; + + /* + * For some unknown reason on HSW non-ULT (or at least on + * Dell Latitude E6540) external displays start to flicker + * when PSR is enabled on the eDP. SR/PC6 residency is much + * higher than should be possible with an external display. + * As a workaround leave LPSP unmasked to prevent PSR entry + * when external displays are active. + */ + if (DISPLAY_VER(dev_priv) >= 8 || IS_HASWELL_ULT(dev_priv)) + mask |= EDP_PSR_DEBUG_MASK_LPSP; if (DISPLAY_VER(dev_priv) < 20) mask |= EDP_PSR_DEBUG_MASK_MAX_SLEEP; @@ -1452,12 +1586,10 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp, * All supported adlp panels have 1-based X granularity, this may * cause issues if non-supported panels are used. */ - if (IS_DISPLAY_IP_STEP(dev_priv, IP_VER(14, 0), 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); + if (IS_DISPLAY_IP_STEP(dev_priv, IP_VER(14, 0), STEP_A0, STEP_B0) || + IS_ALDERLAKE_P(dev_priv)) + intel_de_rmw(dev_priv, hsw_chicken_trans_reg(dev_priv, cpu_transcoder), + 0, ADLP_1_BASED_X_GRANULARITY); /* Wa_16012604467:adlp,mtl[a0,b0] */ if (IS_DISPLAY_IP_STEP(dev_priv, IP_VER(14, 0), STEP_A0, STEP_B0)) @@ -1508,6 +1640,7 @@ static void intel_psr_enable_locked(struct intel_dp *intel_dp, drm_WARN_ON(&dev_priv->drm, intel_dp->psr.enabled); intel_dp->psr.psr2_enabled = crtc_state->has_psr2; + intel_dp->psr.panel_replay_enabled = crtc_state->has_panel_replay; intel_dp->psr.busy_frontbuffer_bits = 0; intel_dp->psr.pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe; intel_dp->psr.transcoder = crtc_state->cpu_transcoder; @@ -1523,8 +1656,12 @@ static void intel_psr_enable_locked(struct intel_dp *intel_dp, if (!psr_interrupt_error_check(intel_dp)) return; - drm_dbg_kms(&dev_priv->drm, "Enabling PSR%s\n", - intel_dp->psr.psr2_enabled ? "2" : "1"); + if (intel_dp->psr.panel_replay_enabled) + drm_dbg_kms(&dev_priv->drm, "Enabling Panel Replay\n"); + else + drm_dbg_kms(&dev_priv->drm, "Enabling PSR%s\n", + intel_dp->psr.psr2_enabled ? "2" : "1"); + intel_write_dp_vsc_sdp(encoder, crtc_state, &crtc_state->psr_vsc); intel_snps_phy_update_psr_power_state(dev_priv, phy, true); intel_psr_enable_sink(intel_dp); @@ -1553,7 +1690,10 @@ static void intel_psr_exit(struct intel_dp *intel_dp) return; } - if (intel_dp->psr.psr2_enabled) { + if (intel_dp->psr.panel_replay_enabled) { + intel_de_rmw(dev_priv, TRANS_DP2_CTL(intel_dp->psr.transcoder), + TRANS_DP2_PANEL_REPLAY_ENABLE, 0); + } else if (intel_dp->psr.psr2_enabled) { tgl_disallow_dc3co_on_psr2_exit(intel_dp); val = intel_de_rmw(dev_priv, EDP_PSR2_CTL(cpu_transcoder), @@ -1602,8 +1742,11 @@ static void intel_psr_disable_locked(struct intel_dp *intel_dp) if (!intel_dp->psr.enabled) return; - drm_dbg_kms(&dev_priv->drm, "Disabling PSR%s\n", - intel_dp->psr.psr2_enabled ? "2" : "1"); + if (intel_dp->psr.panel_replay_enabled) + drm_dbg_kms(&dev_priv->drm, "Disabling Panel Replay\n"); + else + drm_dbg_kms(&dev_priv->drm, "Disabling PSR%s\n", + intel_dp->psr.psr2_enabled ? "2" : "1"); intel_psr_exit(intel_dp); intel_psr_wait_exit_locked(intel_dp); @@ -1636,6 +1779,7 @@ static void intel_psr_disable_locked(struct intel_dp *intel_dp) drm_dp_dpcd_writeb(&intel_dp->aux, DP_RECEIVER_ALPM_CONFIG, 0); intel_dp->psr.enabled = false; + intel_dp->psr.panel_replay_enabled = false; intel_dp->psr.psr2_enabled = false; intel_dp->psr.psr2_sel_fetch_enabled = false; intel_dp->psr.psr2_sel_fetch_cff_enabled = false; @@ -1783,81 +1927,6 @@ static void psr_force_hw_tracking_exit(struct intel_dp *intel_dp) intel_de_write(dev_priv, CURSURFLIVE(intel_dp->psr.pipe), 0); } -void intel_psr2_disable_plane_sel_fetch_arm(struct intel_plane *plane, - const struct intel_crtc_state *crtc_state) -{ - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - enum pipe pipe = plane->pipe; - - if (!crtc_state->enable_psr2_sel_fetch) - return; - - intel_de_write_fw(dev_priv, PLANE_SEL_FETCH_CTL(pipe, plane->id), 0); -} - -void intel_psr2_program_plane_sel_fetch_arm(struct intel_plane *plane, - const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state) -{ - struct drm_i915_private *i915 = to_i915(plane->base.dev); - enum pipe pipe = plane->pipe; - - if (!crtc_state->enable_psr2_sel_fetch) - return; - - if (plane->id == PLANE_CURSOR) - intel_de_write_fw(i915, PLANE_SEL_FETCH_CTL(pipe, plane->id), - plane_state->ctl); - else - intel_de_write_fw(i915, PLANE_SEL_FETCH_CTL(pipe, plane->id), - PLANE_SEL_FETCH_CTL_ENABLE); -} - -void intel_psr2_program_plane_sel_fetch_noarm(struct intel_plane *plane, - const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state, - int color_plane) -{ - struct drm_i915_private *dev_priv = to_i915(plane->base.dev); - enum pipe pipe = plane->pipe; - const struct drm_rect *clip; - u32 val; - int x, y; - - if (!crtc_state->enable_psr2_sel_fetch) - return; - - if (plane->id == PLANE_CURSOR) - return; - - clip = &plane_state->psr2_sel_fetch_area; - - val = (clip->y1 + plane_state->uapi.dst.y1) << 16; - val |= plane_state->uapi.dst.x1; - intel_de_write_fw(dev_priv, PLANE_SEL_FETCH_POS(pipe, plane->id), val); - - x = plane_state->view.color_plane[color_plane].x; - - /* - * From Bspec: UV surface Start Y Position = half of Y plane Y - * start position. - */ - if (!color_plane) - y = plane_state->view.color_plane[color_plane].y + clip->y1; - else - y = plane_state->view.color_plane[color_plane].y + clip->y1 / 2; - - val = y << 16 | x; - - intel_de_write_fw(dev_priv, PLANE_SEL_FETCH_OFFSET(pipe, plane->id), - val); - - /* Sizes are 0 based */ - val = (drm_rect_height(clip) - 1) << 16; - val |= (drm_rect_width(&plane_state->uapi.src) >> 16) - 1; - intel_de_write_fw(dev_priv, PLANE_SEL_FETCH_SIZE(pipe, plane->id), val); -} - void intel_psr2_program_trans_man_trk_ctl(const struct intel_crtc_state *crtc_state) { struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); @@ -2117,8 +2186,19 @@ int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, continue; inter = pipe_clip; - if (!drm_rect_intersect(&inter, &new_plane_state->uapi.dst)) + sel_fetch_area = &new_plane_state->psr2_sel_fetch_area; + if (!drm_rect_intersect(&inter, &new_plane_state->uapi.dst)) { + sel_fetch_area->y1 = -1; + sel_fetch_area->y2 = -1; + /* + * if plane sel fetch was previously enabled -> + * disable it + */ + if (drm_rect_height(&old_plane_state->psr2_sel_fetch_area) > 0) + crtc_state->update_planes |= BIT(plane->id); + continue; + } if (!psr2_sel_fetch_plane_state_supported(new_plane_state)) { full_update = true; @@ -2207,7 +2287,7 @@ void intel_psr_post_plane_update(struct intel_atomic_state *state, intel_atomic_get_new_crtc_state(state, crtc); struct intel_encoder *encoder; - if (!crtc_state->has_psr) + if (!(crtc_state->has_psr || crtc_state->has_panel_replay)) return; for_each_intel_encoder_mask_with_psr(state->base.dev, encoder, @@ -2693,9 +2773,12 @@ void intel_psr_init(struct intel_dp *intel_dp) struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct drm_i915_private *dev_priv = dp_to_i915(intel_dp); - if (!HAS_PSR(dev_priv)) + if (!(HAS_PSR(dev_priv) || HAS_DP20(dev_priv))) return; + if (!intel_dp_is_edp(intel_dp)) + intel_psr_init_dpcd(intel_dp); + /* * HSW spec explicitly says PSR is tied to port A. * BDW+ platforms have a instance of PSR registers per transcoder but @@ -2711,7 +2794,10 @@ void intel_psr_init(struct intel_dp *intel_dp) return; } - intel_dp->psr.source_support = true; + if (HAS_DP20(dev_priv) && !intel_dp_is_edp(intel_dp)) + intel_dp->psr.source_panel_replay_support = true; + else + intel_dp->psr.source_support = true; /* Set link_standby x link_off defaults */ if (DISPLAY_VER(dev_priv) < 12) @@ -2728,12 +2814,19 @@ static int psr_get_status_and_error_status(struct intel_dp *intel_dp, { struct drm_dp_aux *aux = &intel_dp->aux; int ret; + unsigned int offset; + + offset = intel_dp->psr.panel_replay_enabled ? + DP_SINK_DEVICE_PR_AND_FRAME_LOCK_STATUS : DP_PSR_STATUS; - ret = drm_dp_dpcd_readb(aux, DP_PSR_STATUS, status); + ret = drm_dp_dpcd_readb(aux, offset, status); if (ret != 1) return ret; - ret = drm_dp_dpcd_readb(aux, DP_PSR_ERROR_STATUS, error_status); + offset = intel_dp->psr.panel_replay_enabled ? + DP_PANEL_REPLAY_ERROR_STATUS : DP_PSR_ERROR_STATUS; + + ret = drm_dp_dpcd_readb(aux, offset, error_status); if (ret != 1) return ret; @@ -2954,7 +3047,7 @@ psr_source_status(struct intel_dp *intel_dp, struct seq_file *m) status = live_status[status_val]; } - seq_printf(m, "Source PSR status: %s [0x%08x]\n", status, val); + seq_printf(m, "Source PSR/PanelReplay status: %s [0x%08x]\n", status, val); } static int intel_psr_status(struct seq_file *m, struct intel_dp *intel_dp) @@ -2967,18 +3060,22 @@ static int intel_psr_status(struct seq_file *m, struct intel_dp *intel_dp) bool enabled; u32 val; - seq_printf(m, "Sink support: %s", str_yes_no(psr->sink_support)); + seq_printf(m, "Sink support: PSR = %s", + str_yes_no(psr->sink_support)); + if (psr->sink_support) seq_printf(m, " [0x%02x]", intel_dp->psr_dpcd[0]); - seq_puts(m, "\n"); + seq_printf(m, ", Panel Replay = %s\n", str_yes_no(psr->sink_panel_replay_support)); - if (!psr->sink_support) + if (!(psr->sink_support || psr->sink_panel_replay_support)) return 0; wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm); mutex_lock(&psr->lock); - if (psr->enabled) + if (psr->panel_replay_enabled) + status = "Panel Replay Enabled"; + else if (psr->enabled) status = psr->psr2_enabled ? "PSR2 enabled" : "PSR1 enabled"; else status = "disabled"; @@ -2991,14 +3088,17 @@ static int intel_psr_status(struct seq_file *m, struct intel_dp *intel_dp) goto unlock; } - if (psr->psr2_enabled) { + if (psr->panel_replay_enabled) { + val = intel_de_read(dev_priv, TRANS_DP2_CTL(cpu_transcoder)); + enabled = val & TRANS_DP2_PANEL_REPLAY_ENABLE; + } else if (psr->psr2_enabled) { val = intel_de_read(dev_priv, EDP_PSR2_CTL(cpu_transcoder)); enabled = val & EDP_PSR2_ENABLE; } else { val = intel_de_read(dev_priv, psr_ctl_reg(dev_priv, cpu_transcoder)); enabled = val & EDP_PSR_ENABLE; } - seq_printf(m, "Source PSR ctl: %s [0x%08x]\n", + seq_printf(m, "Source PSR/PanelReplay ctl: %s [0x%08x]\n", str_enabled_disabled(enabled), val); psr_source_status(intel_dp, m); seq_printf(m, "Busy frontbuffer bits: 0x%08x\n", @@ -3136,6 +3236,16 @@ void intel_psr_debugfs_register(struct drm_i915_private *i915) i915, &i915_edp_psr_status_fops); } +static const char *psr_mode_str(struct intel_dp *intel_dp) +{ + if (intel_dp->psr.panel_replay_enabled) + return "PANEL-REPLAY"; + else if (intel_dp->psr.enabled) + return "PSR"; + + return "unknown"; +} + static int i915_psr_sink_status_show(struct seq_file *m, void *data) { struct intel_connector *connector = m->private; @@ -3150,12 +3260,19 @@ static int i915_psr_sink_status_show(struct seq_file *m, void *data) "reserved", "sink internal error", }; + static const char * const panel_replay_status[] = { + "Sink device frame is locked to the Source device", + "Sink device is coasting, using the VTotal target", + "Sink device is governing the frame rate (frame rate unlock is granted)", + "Sink device in the process of re-locking with the Source device", + }; const char *str; int ret; u8 status, error_status; + u32 idx; - if (!CAN_PSR(intel_dp)) { - seq_puts(m, "PSR Unsupported\n"); + if (!(CAN_PSR(intel_dp) || CAN_PANEL_REPLAY(intel_dp))) { + seq_puts(m, "PSR/Panel-Replay Unsupported\n"); return -ENODEV; } @@ -3166,15 +3283,20 @@ static int i915_psr_sink_status_show(struct seq_file *m, void *data) if (ret) return ret; - status &= DP_PSR_SINK_STATE_MASK; - if (status < ARRAY_SIZE(sink_status)) - str = sink_status[status]; - else - str = "unknown"; + str = "unknown"; + if (intel_dp->psr.panel_replay_enabled) { + idx = (status & DP_SINK_FRAME_LOCKED_MASK) >> DP_SINK_FRAME_LOCKED_SHIFT; + if (idx < ARRAY_SIZE(panel_replay_status)) + str = panel_replay_status[idx]; + } else if (intel_dp->psr.enabled) { + idx = status & DP_PSR_SINK_STATE_MASK; + if (idx < ARRAY_SIZE(sink_status)) + str = sink_status[idx]; + } - seq_printf(m, "Sink PSR status: 0x%x [%s]\n", status, str); + seq_printf(m, "Sink %s status: 0x%x [%s]\n", psr_mode_str(intel_dp), status, str); - seq_printf(m, "Sink PSR error status: 0x%x", error_status); + seq_printf(m, "Sink %s error status: 0x%x", psr_mode_str(intel_dp), error_status); if (error_status & (DP_PSR_RFB_STORAGE_ERROR | DP_PSR_VSC_SDP_UNCORRECTABLE_ERROR | @@ -3183,11 +3305,11 @@ static int i915_psr_sink_status_show(struct seq_file *m, void *data) else seq_puts(m, "\n"); if (error_status & DP_PSR_RFB_STORAGE_ERROR) - seq_puts(m, "\tPSR RFB storage error\n"); + seq_printf(m, "\t%s RFB storage error\n", psr_mode_str(intel_dp)); if (error_status & DP_PSR_VSC_SDP_UNCORRECTABLE_ERROR) - seq_puts(m, "\tPSR VSC SDP uncorrectable error\n"); + seq_printf(m, "\t%s VSC SDP uncorrectable error\n", psr_mode_str(intel_dp)); if (error_status & DP_PSR_LINK_CRC_ERROR) - seq_puts(m, "\tPSR Link CRC error\n"); + seq_printf(m, "\t%s Link CRC error\n", psr_mode_str(intel_dp)); return ret; } @@ -3207,13 +3329,16 @@ void intel_psr_connector_debugfs_add(struct intel_connector *connector) struct drm_i915_private *i915 = to_i915(connector->base.dev); struct dentry *root = connector->base.debugfs_entry; - if (connector->base.connector_type != DRM_MODE_CONNECTOR_eDP) + /* TODO: Add support for MST connectors as well. */ + if ((connector->base.connector_type != DRM_MODE_CONNECTOR_eDP && + connector->base.connector_type != DRM_MODE_CONNECTOR_DisplayPort) || + connector->mst_port) return; debugfs_create_file("i915_psr_sink_status", 0444, root, connector, &i915_psr_sink_status_fops); - if (HAS_PSR(i915)) + if (HAS_PSR(i915) || HAS_DP20(i915)) debugfs_create_file("i915_psr_status", 0444, root, connector, &i915_psr_status_fops); } diff --git a/drivers/gpu/drm/i915/display/intel_psr.h b/drivers/gpu/drm/i915/display/intel_psr.h index bf35f42df6bc49..143e0595c09773 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.h +++ b/drivers/gpu/drm/i915/display/intel_psr.h @@ -21,6 +21,13 @@ struct intel_encoder; struct intel_plane; struct intel_plane_state; +#define CAN_PSR(intel_dp) ((intel_dp)->psr.sink_support && \ + (intel_dp)->psr.source_support) + +#define CAN_PANEL_REPLAY(intel_dp) ((intel_dp)->psr.sink_panel_replay_support && \ + (intel_dp)->psr.source_panel_replay_support) + +bool intel_encoder_can_psr(struct intel_encoder *encoder); void intel_psr_init_dpcd(struct intel_dp *intel_dp); void intel_psr_pre_plane_update(struct intel_atomic_state *state, struct intel_crtc *crtc); @@ -48,16 +55,6 @@ bool intel_psr_enabled(struct intel_dp *intel_dp); int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, struct intel_crtc *crtc); void intel_psr2_program_trans_man_trk_ctl(const struct intel_crtc_state *crtc_state); -void intel_psr2_program_plane_sel_fetch_noarm(struct intel_plane *plane, - const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state, - int color_plane); -void intel_psr2_program_plane_sel_fetch_arm(struct intel_plane *plane, - const struct intel_crtc_state *crtc_state, - const struct intel_plane_state *plane_state); - -void intel_psr2_disable_plane_sel_fetch_arm(struct intel_plane *plane, - const struct intel_crtc_state *crtc_state); void intel_psr_pause(struct intel_dp *intel_dp); void intel_psr_resume(struct intel_dp *intel_dp); diff --git a/drivers/gpu/drm/i915/display/intel_psr_regs.h b/drivers/gpu/drm/i915/display/intel_psr_regs.h index d39951383c929d..efe4306b37e0c2 100644 --- a/drivers/gpu/drm/i915/display/intel_psr_regs.h +++ b/drivers/gpu/drm/i915/display/intel_psr_regs.h @@ -35,6 +35,8 @@ #define EDP_PSR_MIN_LINK_ENTRY_TIME_0_LINES REG_FIELD_PREP(EDP_PSR_MIN_LINK_ENTRY_TIME_MASK, 3) #define EDP_PSR_MAX_SLEEP_TIME_MASK REG_GENMASK(24, 20) #define EDP_PSR_MAX_SLEEP_TIME(x) REG_FIELD_PREP(EDP_PSR_MAX_SLEEP_TIME_MASK, (x)) +#define LNL_EDP_PSR_ENTRY_SETUP_FRAMES_MASK REG_GENMASK(17, 16) +#define LNL_EDP_PSR_ENTRY_SETUP_FRAMES(x) REG_FIELD_PREP(LNL_EDP_PSR_ENTRY_SETUP_FRAMES_MASK, (x)) #define EDP_PSR_SKIP_AUX_EXIT REG_BIT(12) #define EDP_PSR_TP_MASK REG_BIT(11) #define EDP_PSR_TP_TP1_TP2 REG_FIELD_PREP(EDP_PSR_TP_MASK, 0) diff --git a/drivers/gpu/drm/i915/display/intel_qp_tables.c b/drivers/gpu/drm/i915/display/intel_qp_tables.c index 543cdc46aa1dfc..600c815e37e4e9 100644 --- a/drivers/gpu/drm/i915/display/intel_qp_tables.c +++ b/drivers/gpu/drm/i915/display/intel_qp_tables.c @@ -34,9 +34,6 @@ * These qp tables are as per the C model * and it has the rows pointing to bpps which increment * in steps of 0.5 - * We do not support fractional bpps as of today, - * hence we would skip the fractional bpps during - * our references for qp calclulations. */ static const u8 rc_range_minqp444_8bpc[DSC_NUM_BUF_RANGES][RC_RANGE_QP444_8BPC_MAX_NUM_BPP] = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c index a9ac7d45d1f332..acc6b680410510 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.c +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "i915_drv.h" #include "i915_reg.h" @@ -1787,17 +1788,28 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder, intel_sdvo_get_eld(intel_sdvo, pipe_config); } -static void intel_sdvo_disable_audio(struct intel_sdvo *intel_sdvo) +static void intel_sdvo_disable_audio(struct intel_encoder *encoder, + const struct intel_crtc_state *old_crtc_state, + const struct drm_connector_state *old_conn_state) { + struct intel_sdvo *intel_sdvo = to_sdvo(encoder); + + if (!old_crtc_state->has_audio) + return; + intel_sdvo_set_audio_state(intel_sdvo, 0); } -static void intel_sdvo_enable_audio(struct intel_sdvo *intel_sdvo, +static void intel_sdvo_enable_audio(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state, const struct drm_connector_state *conn_state) { + struct intel_sdvo *intel_sdvo = to_sdvo(encoder); const u8 *eld = crtc_state->eld; + if (!crtc_state->has_audio) + return; + intel_sdvo_set_audio_state(intel_sdvo, 0); intel_sdvo_write_infoframe(intel_sdvo, SDVO_HBUF_INDEX_ELD, @@ -1818,8 +1830,7 @@ static void intel_disable_sdvo(struct intel_atomic_state *state, struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc); u32 temp; - if (old_crtc_state->has_audio) - intel_sdvo_disable_audio(intel_sdvo); + encoder->audio_disable(encoder, old_crtc_state, conn_state); intel_sdvo_set_active_outputs(intel_sdvo, 0); if (0) @@ -1913,8 +1924,7 @@ static void intel_enable_sdvo(struct intel_atomic_state *state, DRM_MODE_DPMS_ON); intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo_connector->output_flag); - if (pipe_config->has_audio) - intel_sdvo_enable_audio(intel_sdvo, pipe_config, conn_state); + encoder->audio_enable(encoder, pipe_config, conn_state); } static enum drm_mode_status @@ -3317,7 +3327,6 @@ intel_sdvo_init_ddc_proxy(struct intel_sdvo_ddc *ddc, ddc->ddc_bus = ddc_bus; ddc->ddc.owner = THIS_MODULE; - ddc->ddc.class = I2C_CLASS_DDC; snprintf(ddc->ddc.name, I2C_NAME_SIZE, "SDVO %c DDC%d", port_name(sdvo->base.port), ddc_bus); ddc->ddc.dev.parent = &pdev->dev; @@ -3396,6 +3405,8 @@ bool intel_sdvo_init(struct drm_i915_private *dev_priv, } intel_encoder->pre_enable = intel_sdvo_pre_enable; intel_encoder->enable = intel_enable_sdvo; + intel_encoder->audio_enable = intel_sdvo_enable_audio; + intel_encoder->audio_disable = intel_sdvo_disable_audio; intel_encoder->get_hw_state = intel_sdvo_get_hw_state; intel_encoder->get_config = intel_sdvo_get_config; diff --git a/drivers/gpu/drm/i915/display/intel_snps_phy.c b/drivers/gpu/drm/i915/display/intel_snps_phy.c index ce5a73a4cc8934..bc61e736f9b32e 100644 --- a/drivers/gpu/drm/i915/display/intel_snps_phy.c +++ b/drivers/gpu/drm/i915/display/intel_snps_phy.c @@ -3,7 +3,7 @@ * Copyright © 2019 Intel Corporation */ -#include +#include #include "i915_reg.h" #include "intel_ddi.h" diff --git a/drivers/gpu/drm/i915/display/intel_sprite.c b/drivers/gpu/drm/i915/display/intel_sprite.c index 1fb16510f7501f..d7b440c8caefe1 100644 --- a/drivers/gpu/drm/i915/display/intel_sprite.c +++ b/drivers/gpu/drm/i915/display/intel_sprite.c @@ -48,6 +48,11 @@ #include "intel_frontbuffer.h" #include "intel_sprite.h" +static char sprite_name(struct drm_i915_private *i915, enum pipe pipe, int sprite) +{ + return pipe * DISPLAY_RUNTIME_INFO(i915)->num_sprites[pipe] + sprite + 'A'; +} + static void i9xx_plane_linear_gamma(u16 gamma[8]) { /* The points are not evenly spaced. */ @@ -1636,7 +1641,7 @@ intel_sprite_plane_create(struct drm_i915_private *dev_priv, 0, plane_funcs, formats, num_formats, modifiers, DRM_PLANE_TYPE_OVERLAY, - "sprite %c", sprite_name(pipe, sprite)); + "sprite %c", sprite_name(dev_priv, pipe, sprite)); kfree(modifiers); if (ret) diff --git a/drivers/gpu/drm/i915/display/intel_tc.c b/drivers/gpu/drm/i915/display/intel_tc.c index f64d348a969efa..dcf05e00e50524 100644 --- a/drivers/gpu/drm/i915/display/intel_tc.c +++ b/drivers/gpu/drm/i915/display/intel_tc.c @@ -1030,18 +1030,25 @@ static bool xelpdp_tc_phy_enable_tcss_power(struct intel_tc_port *tc, bool enabl __xelpdp_tc_phy_enable_tcss_power(tc, enable); - if ((!tc_phy_wait_for_ready(tc) || - !xelpdp_tc_phy_wait_for_tcss_power(tc, enable)) && - !drm_WARN_ON(&i915->drm, tc->mode == TC_PORT_LEGACY)) { - if (enable) { - __xelpdp_tc_phy_enable_tcss_power(tc, false); - xelpdp_tc_phy_wait_for_tcss_power(tc, false); - } + if (enable && !tc_phy_wait_for_ready(tc)) + goto out_disable; - return false; - } + if (!xelpdp_tc_phy_wait_for_tcss_power(tc, enable)) + goto out_disable; return true; + +out_disable: + if (drm_WARN_ON(&i915->drm, tc->mode == TC_PORT_LEGACY)) + return false; + + if (!enable) + return false; + + __xelpdp_tc_phy_enable_tcss_power(tc, false); + xelpdp_tc_phy_wait_for_tcss_power(tc, false); + + return false; } static void xelpdp_tc_phy_take_ownership(struct intel_tc_port *tc, bool take) diff --git a/drivers/gpu/drm/i915/display/intel_tv.c b/drivers/gpu/drm/i915/display/intel_tv.c index 2ee4f0d9585136..d4386cb3569e09 100644 --- a/drivers/gpu/drm/i915/display/intel_tv.c +++ b/drivers/gpu/drm/i915/display/intel_tv.c @@ -1417,9 +1417,6 @@ set_tv_mode_timings(struct drm_i915_private *dev_priv, static void set_color_conversion(struct drm_i915_private *dev_priv, const struct color_conversion *color_conversion) { - if (!color_conversion) - return; - intel_de_write(dev_priv, TV_CSC_Y, (color_conversion->ry << 16) | color_conversion->gy); intel_de_write(dev_priv, TV_CSC_Y2, @@ -1454,9 +1451,6 @@ static void intel_tv_pre_enable(struct intel_atomic_state *state, int xpos, ypos; unsigned int xsize, ysize; - if (!tv_mode) - return; /* can't happen (mode_prepare prevents this) */ - tv_ctl = intel_de_read(dev_priv, TV_CTL); tv_ctl &= TV_CTL_SAVE; diff --git a/drivers/gpu/drm/i915/display/intel_vblank.c b/drivers/gpu/drm/i915/display/intel_vblank.c index 2cec2abf97466c..fe256bf7b485b9 100644 --- a/drivers/gpu/drm/i915/display/intel_vblank.c +++ b/drivers/gpu/drm/i915/display/intel_vblank.c @@ -265,6 +265,32 @@ int intel_crtc_scanline_to_hw(struct intel_crtc *crtc, int scanline) return (scanline + vtotal - crtc->scanline_offset) % vtotal; } +/* + * The uncore version of the spin lock functions is used to decide + * whether we need to lock the uncore lock or not. This is only + * needed in i915, not in Xe. + * + * This lock in i915 is needed because some old platforms (at least + * IVB and possibly HSW as well), which are not supported in Xe, need + * all register accesses to the same cacheline to be serialized, + * otherwise they may hang. + */ +static void intel_vblank_section_enter(struct drm_i915_private *i915) + __acquires(i915->uncore.lock) +{ +#ifdef I915 + spin_lock(&i915->uncore.lock); +#endif +} + +static void intel_vblank_section_exit(struct drm_i915_private *i915) + __releases(i915->uncore.lock) +{ +#ifdef I915 + spin_unlock(&i915->uncore.lock); +#endif +} + static bool i915_get_crtc_scanoutpos(struct drm_crtc *_crtc, bool in_vblank_irq, int *vpos, int *hpos, @@ -302,11 +328,12 @@ static bool i915_get_crtc_scanoutpos(struct drm_crtc *_crtc, } /* - * 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. + * Enter vblank critical section, as we will do multiple + * timing critical raw register reads, potentially with + * preemption disabled, so the following code must not block. */ - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); + local_irq_save(irqflags); + intel_vblank_section_enter(dev_priv); /* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */ @@ -374,7 +401,8 @@ static bool i915_get_crtc_scanoutpos(struct drm_crtc *_crtc, /* preempt_enable_rt() should go right here in PREEMPT_RT patchset. */ - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); + intel_vblank_section_exit(dev_priv); + local_irq_restore(irqflags); /* * While in vblank, position will be negative @@ -412,9 +440,13 @@ int intel_get_crtc_scanline(struct intel_crtc *crtc) unsigned long irqflags; int position; - spin_lock_irqsave(&dev_priv->uncore.lock, irqflags); + local_irq_save(irqflags); + intel_vblank_section_enter(dev_priv); + position = __intel_get_crtc_scanline(crtc); - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); + + intel_vblank_section_exit(dev_priv); + local_irq_restore(irqflags); return position; } @@ -537,7 +569,7 @@ void intel_crtc_update_active_timings(const struct intel_crtc_state *crtc_state, * Need to audit everything to make sure it's safe. */ spin_lock_irqsave(&i915->drm.vblank_time_lock, irqflags); - spin_lock(&i915->uncore.lock); + intel_vblank_section_enter(i915); drm_calc_timestamping_constants(&crtc->base, &adjusted_mode); @@ -546,7 +578,6 @@ void intel_crtc_update_active_timings(const struct intel_crtc_state *crtc_state, crtc->mode_flags = mode_flags; crtc->scanline_offset = intel_crtc_scanline_offset(crtc_state); - - spin_unlock(&i915->uncore.lock); + intel_vblank_section_exit(i915); spin_unlock_irqrestore(&i915->drm.vblank_time_lock, irqflags); } diff --git a/drivers/gpu/drm/i915/display/intel_vdsc.c b/drivers/gpu/drm/i915/display/intel_vdsc.c index 6757dbae9ee5e9..17d6572f9d0a09 100644 --- a/drivers/gpu/drm/i915/display/intel_vdsc.c +++ b/drivers/gpu/drm/i915/display/intel_vdsc.c @@ -77,8 +77,8 @@ intel_vdsc_set_min_max_qp(struct drm_dsc_config *vdsc_cfg, int buf, static void calculate_rc_params(struct drm_dsc_config *vdsc_cfg) { + int bpp = to_bpp_int(vdsc_cfg->bits_per_pixel); int bpc = vdsc_cfg->bits_per_component; - int bpp = vdsc_cfg->bits_per_pixel >> 4; int qp_bpc_modifier = (bpc - 8) * 2; int uncompressed_bpg_rate; int first_line_bpg_offset; @@ -148,7 +148,13 @@ calculate_rc_params(struct drm_dsc_config *vdsc_cfg) static const s8 ofs_und8[] = { 10, 8, 6, 4, 2, 0, -2, -4, -6, -8, -10, -10, -12, -12, -12 }; - + /* + * For 420 format since bits_per_pixel (bpp) is set to target bpp * 2, + * QP table values for target bpp 4.0 to 4.4375 (rounded to 4.0) are + * actually for bpp 8 to 8.875 (rounded to 4.0 * 2 i.e 8). + * Similarly values for target bpp 4.5 to 4.8375 (rounded to 4.5) + * are for bpp 9 to 9.875 (rounded to 4.5 * 2 i.e 9), and so on. + */ bpp_i = bpp - 8; for (buf_i = 0; buf_i < DSC_NUM_BUF_RANGES; buf_i++) { u8 range_bpg_offset; @@ -178,6 +184,9 @@ calculate_rc_params(struct drm_dsc_config *vdsc_cfg) range_bpg_offset & DSC_RANGE_BPG_OFFSET_MASK; } } else { + /* fractional bpp part * 10000 (for precision up to 4 decimal places) */ + int fractional_bits = to_bpp_frac(vdsc_cfg->bits_per_pixel); + static const s8 ofs_und6[] = { 0, -2, -2, -4, -6, -6, -8, -8, -8, -10, -10, -12, -12, -12, -12 }; @@ -191,7 +200,14 @@ calculate_rc_params(struct drm_dsc_config *vdsc_cfg) 10, 8, 6, 4, 2, 0, -2, -4, -6, -8, -10, -10, -12, -12, -12 }; - bpp_i = (2 * (bpp - 6)); + /* + * QP table rows have values in increment of 0.5. + * So 6.0 bpp to 6.4375 will have index 0, 6.5 to 6.9375 will have index 1, + * and so on. + * 0.5 fractional part with 4 decimal precision becomes 5000 + */ + bpp_i = ((bpp - 6) + (fractional_bits < 5000 ? 0 : 1)); + for (buf_i = 0; buf_i < DSC_NUM_BUF_RANGES; buf_i++) { u8 range_bpg_offset; @@ -248,7 +264,7 @@ int intel_dsc_compute_params(struct intel_crtc_state *pipe_config) struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc); struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); struct drm_dsc_config *vdsc_cfg = &pipe_config->dsc.config; - u16 compressed_bpp = pipe_config->dsc.compressed_bpp; + u16 compressed_bpp = to_bpp_int(pipe_config->dsc.compressed_bpp_x16); int err; int ret; @@ -279,8 +295,7 @@ int intel_dsc_compute_params(struct intel_crtc_state *pipe_config) /* Gen 11 does not support VBR */ vdsc_cfg->vbr_enable = false; - /* Gen 11 only supports integral values of bpp */ - vdsc_cfg->bits_per_pixel = compressed_bpp << 4; + vdsc_cfg->bits_per_pixel = pipe_config->dsc.compressed_bpp_x16; /* * According to DSC 1.2 specs in Section 4.1 if native_420 is set @@ -797,13 +812,13 @@ void intel_dsc_disable(const struct intel_crtc_state *old_crtc_state) } static u32 intel_dsc_pps_read(struct intel_crtc_state *crtc_state, int pps, - bool *check_equal) + bool *all_equal) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct drm_i915_private *i915 = to_i915(crtc->base.dev); i915_reg_t dsc_reg[2]; int i, vdsc_per_pipe, dsc_reg_num; - u32 val = 0; + u32 val; vdsc_per_pipe = intel_dsc_get_vdsc_per_pipe(crtc_state); dsc_reg_num = min_t(int, ARRAY_SIZE(dsc_reg), vdsc_per_pipe); @@ -812,20 +827,13 @@ static u32 intel_dsc_pps_read(struct intel_crtc_state *crtc_state, int pps, intel_dsc_get_pps_reg(crtc_state, pps, dsc_reg, dsc_reg_num); - if (check_equal) - *check_equal = true; - - for (i = 0; i < dsc_reg_num; i++) { - u32 tmp; + *all_equal = true; - tmp = intel_de_read(i915, dsc_reg[i]); + val = intel_de_read(i915, dsc_reg[0]); - if (i == 0) { - val = tmp; - } else if (check_equal && tmp != val) { - *check_equal = false; - break; - } else if (!check_equal) { + for (i = 1; i < dsc_reg_num; i++) { + if (intel_de_read(i915, dsc_reg[i]) != val) { + *all_equal = false; break; } } @@ -874,7 +882,7 @@ static void intel_dsc_get_pps_config(struct intel_crtc_state *crtc_state) if (vdsc_cfg->native_420) vdsc_cfg->bits_per_pixel >>= 1; - crtc_state->dsc.compressed_bpp = vdsc_cfg->bits_per_pixel >> 4; + crtc_state->dsc.compressed_bpp_x16 = vdsc_cfg->bits_per_pixel; /* PPS 2 */ pps_temp = intel_dsc_pps_read_and_verify(crtc_state, 2); diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c index 245a64332cc739..511dc1544854f4 100644 --- a/drivers/gpu/drm/i915/display/skl_universal_plane.c +++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c @@ -18,10 +18,10 @@ #include "intel_fbc.h" #include "intel_frontbuffer.h" #include "intel_psr.h" +#include "intel_psr_regs.h" #include "skl_scaler.h" #include "skl_universal_plane.h" #include "skl_watermark.h" -#include "gt/intel_gt.h" #include "pxp/intel_pxp.h" static const u32 skl_plane_formats[] = { @@ -630,6 +630,18 @@ skl_plane_disable_arm(struct intel_plane *plane, intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), 0); } +static void icl_plane_disable_sel_fetch_arm(struct intel_plane *plane, + const struct intel_crtc_state *crtc_state) +{ + struct drm_i915_private *i915 = to_i915(plane->base.dev); + enum pipe pipe = plane->pipe; + + if (!crtc_state->enable_psr2_sel_fetch) + return; + + intel_de_write_fw(i915, PLANE_SEL_FETCH_CTL(pipe, plane->id), 0); +} + static void icl_plane_disable_arm(struct intel_plane *plane, const struct intel_crtc_state *crtc_state) @@ -643,7 +655,7 @@ icl_plane_disable_arm(struct intel_plane *plane, skl_write_plane_wm(plane, crtc_state); - intel_psr2_disable_plane_sel_fetch_arm(plane, crtc_state); + icl_plane_disable_sel_fetch_arm(plane, crtc_state); intel_de_write_fw(dev_priv, PLANE_CTL(pipe, plane_id), 0); intel_de_write_fw(dev_priv, PLANE_SURF(pipe, plane_id), 0); } @@ -1007,7 +1019,8 @@ static u32 skl_surf_address(const struct intel_plane_state *plane_state, * The DPT object contains only one vma, so the VMA's offset * within the DPT is always 0. */ - drm_WARN_ON(&i915->drm, plane_state->dpt_vma->node.start); + drm_WARN_ON(&i915->drm, plane_state->dpt_vma && + plane_state->dpt_vma->node.start); drm_WARN_ON(&i915->drm, offset & 0x1fffff); return offset >> 9; } else { @@ -1197,6 +1210,48 @@ skl_plane_update_arm(struct intel_plane *plane, skl_plane_surf(plane_state, 0)); } +static void icl_plane_update_sel_fetch_noarm(struct intel_plane *plane, + const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state, + int color_plane) +{ + struct drm_i915_private *i915 = to_i915(plane->base.dev); + enum pipe pipe = plane->pipe; + const struct drm_rect *clip; + u32 val; + int x, y; + + if (!crtc_state->enable_psr2_sel_fetch) + return; + + clip = &plane_state->psr2_sel_fetch_area; + + val = (clip->y1 + plane_state->uapi.dst.y1) << 16; + val |= plane_state->uapi.dst.x1; + intel_de_write_fw(i915, PLANE_SEL_FETCH_POS(pipe, plane->id), val); + + x = plane_state->view.color_plane[color_plane].x; + + /* + * From Bspec: UV surface Start Y Position = half of Y plane Y + * start position. + */ + if (!color_plane) + y = plane_state->view.color_plane[color_plane].y + clip->y1; + else + y = plane_state->view.color_plane[color_plane].y + clip->y1 / 2; + + val = y << 16 | x; + + intel_de_write_fw(i915, PLANE_SEL_FETCH_OFFSET(pipe, plane->id), + val); + + /* Sizes are 0 based */ + val = (drm_rect_height(clip) - 1) << 16; + val |= (drm_rect_width(&plane_state->uapi.src) >> 16) - 1; + intel_de_write_fw(i915, PLANE_SEL_FETCH_SIZE(pipe, plane->id), val); +} + static void icl_plane_update_noarm(struct intel_plane *plane, const struct intel_crtc_state *crtc_state, @@ -1269,7 +1324,24 @@ icl_plane_update_noarm(struct intel_plane *plane, if (plane_state->force_black) icl_plane_csc_load_black(plane); - intel_psr2_program_plane_sel_fetch_noarm(plane, crtc_state, plane_state, color_plane); + icl_plane_update_sel_fetch_noarm(plane, crtc_state, plane_state, color_plane); +} + +static void icl_plane_update_sel_fetch_arm(struct intel_plane *plane, + const struct intel_crtc_state *crtc_state, + const struct intel_plane_state *plane_state) +{ + struct drm_i915_private *i915 = to_i915(plane->base.dev); + enum pipe pipe = plane->pipe; + + if (!crtc_state->enable_psr2_sel_fetch) + return; + + if (drm_rect_height(&plane_state->psr2_sel_fetch_area) > 0) + intel_de_write_fw(i915, PLANE_SEL_FETCH_CTL(pipe, plane->id), + PLANE_SEL_FETCH_CTL_ENABLE); + else + icl_plane_disable_sel_fetch_arm(plane, crtc_state); } static void @@ -1296,7 +1368,7 @@ icl_plane_update_arm(struct intel_plane *plane, if (plane_state->scaler_id >= 0) skl_program_plane_scaler(plane, crtc_state, plane_state); - intel_psr2_program_plane_sel_fetch_arm(plane, crtc_state, plane_state); + icl_plane_update_sel_fetch_arm(plane, crtc_state, plane_state); /* * The control register self-arms if the plane was previously @@ -1855,16 +1927,19 @@ static bool skl_fb_scalable(const struct drm_framebuffer *fb) } } -static bool bo_has_valid_encryption(struct drm_i915_gem_object *obj) +static void check_protection(struct intel_plane_state *plane_state) { - struct drm_i915_private *i915 = to_i915(obj->base.dev); + struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); + struct drm_i915_private *i915 = to_i915(plane->base.dev); + const struct drm_framebuffer *fb = plane_state->hw.fb; + struct drm_i915_gem_object *obj = intel_fb_obj(fb); - return intel_pxp_key_check(i915->pxp, obj, false) == 0; -} + if (DISPLAY_VER(i915) < 11) + return; -static bool pxp_is_borked(struct drm_i915_gem_object *obj) -{ - return i915_gem_object_is_protected(obj) && !bo_has_valid_encryption(obj); + plane_state->decrypt = intel_pxp_key_check(i915->pxp, obj, false) == 0; + plane_state->force_black = i915_gem_object_is_protected(obj) && + !plane_state->decrypt; } static int skl_plane_check(struct intel_crtc_state *crtc_state, @@ -1911,10 +1986,7 @@ static int skl_plane_check(struct intel_crtc_state *crtc_state, if (ret) return ret; - if (DISPLAY_VER(dev_priv) >= 11) { - plane_state->decrypt = bo_has_valid_encryption(intel_fb_obj(fb)); - plane_state->force_black = pxp_is_borked(intel_fb_obj(fb)); - } + check_protection(plane_state); /* HW only has 8 bits pixel precision, disable plane if invisible */ if (!(plane_state->hw.alpha >> 8)) @@ -2489,7 +2561,7 @@ skl_get_initial_plane_config(struct intel_crtc *crtc, goto error; } - if (!dev_priv->params.enable_dpt && + if (!dev_priv->display.params.enable_dpt && intel_fb_modifier_uses_dpt(dev_priv, fb->modifier)) { drm_dbg_kms(&dev_priv->drm, "DPT disabled, skipping initial FB\n"); goto error; diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index 99b8ccdc3dfa22..56588d6e24ae6b 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -412,7 +412,7 @@ static bool intel_crtc_can_enable_sagv(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 (!i915->params.enable_sagv) + if (!i915->display.params.enable_sagv) return false; if (DISPLAY_VER(i915) >= 12) @@ -3702,7 +3702,8 @@ static int intel_sagv_status_show(struct seq_file *m, void *unused) }; seq_printf(m, "SAGV available: %s\n", str_yes_no(intel_has_sagv(i915))); - seq_printf(m, "SAGV modparam: %s\n", str_enabled_disabled(i915->params.enable_sagv)); + seq_printf(m, "SAGV modparam: %s\n", + str_enabled_disabled(i915->display.params.enable_sagv)); seq_printf(m, "SAGV status: %s\n", sagv_status[i915->display.sagv.status]); seq_printf(m, "SAGV block time: %d usec\n", i915->display.sagv.block_time_us); diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c index f488394d3108e4..9b33b8a74d6434 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi.c +++ b/drivers/gpu/drm/i915/display/vlv_dsi.c @@ -561,6 +561,12 @@ static void glk_dsi_clear_device_ready(struct intel_encoder *encoder) glk_dsi_disable_mipi_io(encoder); } +static i915_reg_t port_ctrl_reg(struct drm_i915_private *i915, enum port port) +{ + return IS_GEMINILAKE(i915) || IS_BROXTON(i915) ? + BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(port); +} + static void vlv_dsi_clear_device_ready(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); @@ -570,7 +576,7 @@ static void vlv_dsi_clear_device_ready(struct intel_encoder *encoder) drm_dbg_kms(&dev_priv->drm, "\n"); for_each_dsi_port(port, intel_dsi->ports) { /* Common bit for both MIPI Port A & MIPI Port C on VLV/CHV */ - i915_reg_t port_ctrl = IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv) ? + i915_reg_t port_ctrl = IS_BROXTON(dev_priv) ? BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(PORT_A); intel_de_write(dev_priv, MIPI_DEVICE_READY(port), @@ -589,7 +595,7 @@ static void vlv_dsi_clear_device_ready(struct intel_encoder *encoder) * On VLV/CHV, wait till Clock lanes are in LP-00 state for MIPI * Port A only. MIPI Port C has no similar bit for checking. */ - if ((IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv) || port == PORT_A) && + if ((IS_BROXTON(dev_priv) || port == PORT_A) && intel_de_wait_for_clear(dev_priv, port_ctrl, AFE_LATCHOUT, 30)) drm_err(&dev_priv->drm, "DSI LP not going Low\n"); @@ -627,8 +633,7 @@ static void intel_dsi_port_enable(struct intel_encoder *encoder, } for_each_dsi_port(port, intel_dsi->ports) { - i915_reg_t port_ctrl = IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv) ? - BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(port); + i915_reg_t port_ctrl = port_ctrl_reg(dev_priv, port); u32 temp; temp = intel_de_read(dev_priv, port_ctrl); @@ -664,8 +669,7 @@ static void intel_dsi_port_disable(struct intel_encoder *encoder) enum port port; for_each_dsi_port(port, intel_dsi->ports) { - i915_reg_t port_ctrl = IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv) ? - BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(port); + i915_reg_t port_ctrl = port_ctrl_reg(dev_priv, port); /* de-assert ip_tg_enable signal */ intel_de_rmw(dev_priv, port_ctrl, DPI_ENABLE, 0); @@ -955,9 +959,8 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder, /* XXX: this only works for one DSI output */ for_each_dsi_port(port, intel_dsi->ports) { - i915_reg_t ctrl_reg = IS_GEMINILAKE(dev_priv) || IS_BROXTON(dev_priv) ? - BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(port); - bool enabled = intel_de_read(dev_priv, ctrl_reg) & DPI_ENABLE; + i915_reg_t port_ctrl = port_ctrl_reg(dev_priv, port); + bool enabled = intel_de_read(dev_priv, port_ctrl) & DPI_ENABLE; /* * Due to some hardware limitations on VLV/CHV, the DPI enable @@ -1529,16 +1532,8 @@ static void intel_dsi_unprepare(struct intel_encoder *encoder) } } -static void intel_dsi_encoder_destroy(struct drm_encoder *encoder) -{ - struct intel_dsi *intel_dsi = enc_to_intel_dsi(to_intel_encoder(encoder)); - - intel_dsi_vbt_gpio_cleanup(intel_dsi); - intel_encoder_destroy(encoder); -} - static const struct drm_encoder_funcs intel_dsi_funcs = { - .destroy = intel_dsi_encoder_destroy, + .destroy = intel_encoder_destroy, }; static enum drm_mode_status vlv_dsi_mode_valid(struct drm_connector *connector, diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c index e38f06a6e56ebc..dcbfe32fd30c3b 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_context.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c @@ -279,7 +279,8 @@ static int proto_context_set_protected(struct drm_i915_private *i915, } static struct i915_gem_proto_context * -proto_context_create(struct drm_i915_private *i915, unsigned int flags) +proto_context_create(struct drm_i915_file_private *fpriv, + struct drm_i915_private *i915, unsigned int flags) { struct i915_gem_proto_context *pc, *err; @@ -287,6 +288,7 @@ proto_context_create(struct drm_i915_private *i915, unsigned int flags) if (!pc) return ERR_PTR(-ENOMEM); + pc->fpriv = fpriv; pc->num_user_engines = -1; pc->user_engines = NULL; pc->user_flags = BIT(UCONTEXT_BANNABLE) | @@ -1622,6 +1624,7 @@ i915_gem_create_context(struct drm_i915_private *i915, err = PTR_ERR(ppgtt); goto err_ctx; } + ppgtt->vm.fpriv = pc->fpriv; vm = &ppgtt->vm; } if (vm) @@ -1741,7 +1744,7 @@ int i915_gem_context_open(struct drm_i915_private *i915, /* 0 reserved for invalid/unassigned ppgtt */ xa_init_flags(&file_priv->vm_xa, XA_FLAGS_ALLOC1); - pc = proto_context_create(i915, 0); + pc = proto_context_create(file_priv, i915, 0); if (IS_ERR(pc)) { err = PTR_ERR(pc); goto err; @@ -1823,6 +1826,7 @@ int i915_gem_vm_create_ioctl(struct drm_device *dev, void *data, GEM_BUG_ON(id == 0); /* reserved for invalid/unassigned ppgtt */ args->vm_id = id; + ppgtt->vm.fpriv = file_priv; return 0; err_put: @@ -2285,7 +2289,8 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, return -EIO; } - ext_data.pc = proto_context_create(i915, args->flags); + ext_data.pc = proto_context_create(file->driver_priv, i915, + args->flags); if (IS_ERR(ext_data.pc)) return PTR_ERR(ext_data.pc); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h index cb78214a7dcdbb..03bc7f9d191b98 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_context_types.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_context_types.h @@ -188,6 +188,9 @@ struct i915_gem_proto_engine { * CONTEXT_CREATE_SET_PARAM during GEM_CONTEXT_CREATE. */ struct i915_gem_proto_context { + /** @fpriv: Client which creates the context */ + struct drm_i915_file_private *fpriv; + /** @vm: See &i915_gem_context.vm */ struct i915_address_space *vm; @@ -409,9 +412,9 @@ struct i915_gem_context { /** @stale: tracks stale engines to be destroyed */ struct { - /** @lock: guards engines */ + /** @stale.lock: guards engines */ spinlock_t lock; - /** @engines: list of stale engines */ + /** @stale.engines: list of stale engines */ struct list_head engines; } stale; }; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c index 683fd8d3151c36..555022c0652c80 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -9,6 +9,7 @@ #include #include +#include #include #include "display/intel_frontbuffer.h" @@ -253,6 +254,8 @@ struct i915_execbuffer { struct intel_gt *gt; /* gt for the execbuf */ struct intel_context *context; /* logical state for the request */ struct i915_gem_context *gem_context; /** caller's context */ + intel_wakeref_t wakeref; + intel_wakeref_t wakeref_gt0; /** our requests to build */ struct i915_request *requests[MAX_ENGINE_INSTANCE + 1]; @@ -1156,7 +1159,7 @@ static void reloc_cache_unmap(struct reloc_cache *cache) vaddr = unmask_page(cache->vaddr); if (cache->vaddr & KMAP) - kunmap_atomic(vaddr); + kunmap_local(vaddr); else io_mapping_unmap_atomic((void __iomem *)vaddr); } @@ -1172,7 +1175,7 @@ static void reloc_cache_remap(struct reloc_cache *cache, if (cache->vaddr & KMAP) { struct page *page = i915_gem_object_get_page(obj, cache->page); - vaddr = kmap_atomic(page); + vaddr = kmap_local_page(page); cache->vaddr = unmask_flags(cache->vaddr) | (unsigned long)vaddr; } else { @@ -1202,7 +1205,7 @@ static void reloc_cache_reset(struct reloc_cache *cache, struct i915_execbuffer if (cache->vaddr & CLFLUSH_AFTER) mb(); - kunmap_atomic(vaddr); + kunmap_local(vaddr); i915_gem_object_finish_access(obj); } else { struct i915_ggtt *ggtt = cache_to_ggtt(cache); @@ -1234,7 +1237,7 @@ static void *reloc_kmap(struct drm_i915_gem_object *obj, struct page *page; if (cache->vaddr) { - kunmap_atomic(unmask_page(cache->vaddr)); + kunmap_local(unmask_page(cache->vaddr)); } else { unsigned int flushes; int err; @@ -1256,7 +1259,7 @@ static void *reloc_kmap(struct drm_i915_gem_object *obj, if (!obj->mm.dirty) set_page_dirty(page); - vaddr = kmap_atomic(page); + vaddr = kmap_local_page(page); cache->vaddr = unmask_flags(cache->vaddr) | (unsigned long)vaddr; cache->page = pageno; @@ -1678,7 +1681,7 @@ static int eb_copy_relocations(const struct i915_execbuffer *eb) urelocs = u64_to_user_ptr(eb->exec[i].relocs_ptr); size = nreloc * sizeof(*relocs); - relocs = kvmalloc_array(size, 1, GFP_KERNEL); + relocs = kvmalloc_array(1, size, GFP_KERNEL); if (!relocs) { err = -ENOMEM; goto err; @@ -2719,13 +2722,13 @@ eb_select_engine(struct i915_execbuffer *eb) for_each_child(ce, child) intel_context_get(child); - intel_gt_pm_get(gt); + eb->wakeref = intel_gt_pm_get(ce->engine->gt); /* * Keep GT0 active on MTL so that i915_vma_parked() doesn't * free VMAs while execbuf ioctl is validating VMAs. */ if (gt->info.id) - intel_gt_pm_get(to_gt(gt->i915)); + eb->wakeref_gt0 = intel_gt_pm_get(to_gt(gt->i915)); if (!test_bit(CONTEXT_ALLOC_BIT, &ce->flags)) { err = intel_context_alloc_state(ce); @@ -2765,9 +2768,9 @@ eb_select_engine(struct i915_execbuffer *eb) err: if (gt->info.id) - intel_gt_pm_put(to_gt(gt->i915)); + intel_gt_pm_put(to_gt(gt->i915), eb->wakeref_gt0); - intel_gt_pm_put(gt); + intel_gt_pm_put(ce->engine->gt, eb->wakeref); for_each_child(ce, child) intel_context_put(child); intel_context_put(ce); @@ -2785,8 +2788,8 @@ eb_put_engine(struct i915_execbuffer *eb) * i915_vma_parked() from interfering while execbuf validates vmas. */ if (eb->gt->info.id) - intel_gt_pm_put(to_gt(eb->gt->i915)); - intel_gt_pm_put(eb->gt); + intel_gt_pm_put(to_gt(eb->gt->i915), eb->wakeref_gt0); + intel_gt_pm_put(eb->context->engine->gt, eb->wakeref); for_each_child(eb->context, child) intel_context_put(child); intel_context_put(eb->context); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_internal.c b/drivers/gpu/drm/i915/gem/i915_gem_internal.c index 6bc26b4b06b860..ea7561ae6e136f 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_internal.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_internal.c @@ -36,7 +36,7 @@ static int i915_gem_object_get_pages_internal(struct drm_i915_gem_object *obj) struct sg_table *st; struct scatterlist *sg; unsigned int npages; /* restricted by sg_alloc_table */ - int max_order = MAX_ORDER; + int max_order = MAX_PAGE_ORDER; unsigned int max_segment; gfp_t gfp; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c index c26d8755582506..58e6c680fe0df6 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c @@ -106,6 +106,10 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj, INIT_LIST_HEAD(&obj->mm.link); +#ifdef CONFIG_PROC_FS + INIT_LIST_HEAD(&obj->client_link); +#endif + INIT_LIST_HEAD(&obj->lut_list); spin_lock_init(&obj->lut_lock); @@ -293,6 +297,10 @@ void __i915_gem_free_object_rcu(struct rcu_head *head) container_of(head, typeof(*obj), rcu); struct drm_i915_private *i915 = to_i915(obj->base.dev); + /* We need to keep this alive for RCU read access from fdinfo. */ + if (obj->mm.n_placements > 1) + kfree(obj->mm.placements); + i915_gem_object_free(obj); GEM_BUG_ON(!atomic_read(&i915->mm.free_count)); @@ -389,9 +397,6 @@ void __i915_gem_free_object(struct drm_i915_gem_object *obj) if (obj->ops->release) obj->ops->release(obj); - if (obj->mm.n_placements > 1) - kfree(obj->mm.placements); - if (obj->shares_resv_from) i915_vm_resv_put(obj->shares_resv_from); @@ -442,6 +447,8 @@ static void i915_gem_free_object(struct drm_gem_object *gem_obj) GEM_BUG_ON(i915_gem_object_is_framebuffer(obj)); + i915_drm_client_remove_object(obj); + /* * Before we free the object, make sure any pure RCU-only * read-side critical sections are complete, e.g. @@ -493,17 +500,15 @@ 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, idx)); - - src_ptr = src_map + offset_in_page(offset); + src_ptr = kmap_local_page(i915_gem_object_get_page(obj, idx)) + + offset_in_page(offset); if (!(obj->cache_coherent & I915_BO_CACHE_COHERENT_FOR_READ)) drm_clflush_virt_range(src_ptr, size); memcpy(dst, src_ptr, size); - kunmap_atomic(src_map); + kunmap_local(src_ptr); } static void diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object_frontbuffer.h b/drivers/gpu/drm/i915/gem/i915_gem_object_frontbuffer.h index e5e870b6f186c9..9fbf14867a2a64 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object_frontbuffer.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object_frontbuffer.h @@ -89,6 +89,7 @@ i915_gem_object_set_frontbuffer(struct drm_i915_gem_object *obj, if (!front) { RCU_INIT_POINTER(obj->frontbuffer, NULL); + drm_gem_object_put(intel_bo_to_drm_bo(obj)); } else if (rcu_access_pointer(obj->frontbuffer)) { cur = rcu_dereference_protected(obj->frontbuffer, true); kref_get(&cur->ref); 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 2292404007c815..0c5cdab278b69e 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object_types.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object_types.h @@ -302,6 +302,18 @@ struct drm_i915_gem_object { */ struct i915_address_space *shares_resv_from; +#ifdef CONFIG_PROC_FS + /** + * @client: @i915_drm_client which created the object + */ + struct i915_drm_client *client; + + /** + * @client_link: Link into @i915_drm_client.objects_list + */ + struct list_head client_link; +#endif + union { struct rcu_head rcu; struct llist_node freed; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_phys.c b/drivers/gpu/drm/i915/gem/i915_gem_phys.c index 5df128e2f4dc20..ef85c6dc9fd592 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_phys.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_phys.c @@ -65,16 +65,13 @@ static int i915_gem_object_get_pages_phys(struct drm_i915_gem_object *obj) dst = vaddr; for (i = 0; i < obj->base.size / PAGE_SIZE; i++) { struct page *page; - void *src; page = shmem_read_mapping_page(mapping, i); if (IS_ERR(page)) goto err_st; - src = kmap_atomic(page); - memcpy(dst, src, PAGE_SIZE); + memcpy_from_page(dst, page, 0, PAGE_SIZE); drm_clflush_virt_range(dst, PAGE_SIZE); - kunmap_atomic(src); put_page(page); dst += PAGE_SIZE; @@ -113,16 +110,13 @@ i915_gem_object_put_pages_phys(struct drm_i915_gem_object *obj, for (i = 0; i < obj->base.size / PAGE_SIZE; i++) { struct page *page; - char *dst; page = shmem_read_mapping_page(mapping, i); if (IS_ERR(page)) continue; - dst = kmap_atomic(page); drm_clflush_virt_range(src, PAGE_SIZE); - memcpy(dst, src, PAGE_SIZE); - kunmap_atomic(dst); + memcpy_to_page(page, 0, src, PAGE_SIZE); set_page_dirty(page); if (obj->mm.madv == I915_MADV_WILLNEED) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c index 73a4a4eb29e086..38b72d86560f05 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c @@ -485,11 +485,13 @@ shmem_pwrite(struct drm_i915_gem_object *obj, if (err < 0) return err; - vaddr = kmap_atomic(page); + vaddr = kmap_local_page(page); + pagefault_disable(); unwritten = __copy_from_user_inatomic(vaddr + pg, user_data, len); - kunmap_atomic(vaddr); + pagefault_enable(); + kunmap_local(vaddr); err = aops->write_end(obj->base.filp, mapping, offset, len, len - unwritten, page, data); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c index 1a766d8e7ccecd..8c88075eeab237 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c @@ -386,6 +386,27 @@ static void icl_get_stolen_reserved(struct drm_i915_private *i915, drm_dbg(&i915->drm, "GEN6_STOLEN_RESERVED = 0x%016llx\n", reg_val); + /* Wa_14019821291 */ + if (MEDIA_VER_FULL(i915) == IP_VER(13, 0)) { + /* + * This workaround is primarily implemented by the BIOS. We + * just need to figure out whether the BIOS has applied the + * workaround (meaning the programmed address falls within + * the DSM) and, if so, reserve that part of the DSM to + * prevent accidental reuse. The DSM location should be just + * below the WOPCM. + */ + u64 gscpsmi_base = intel_uncore_read64_2x32(uncore, + MTL_GSCPSMI_BASEADDR_LSB, + MTL_GSCPSMI_BASEADDR_MSB); + if (gscpsmi_base >= i915->dsm.stolen.start && + gscpsmi_base < i915->dsm.stolen.end) { + *base = gscpsmi_base; + *size = i915->dsm.stolen.end - gscpsmi_base; + return; + } + } + switch (reg_val & GEN8_STOLEN_RESERVED_SIZE_MASK) { case GEN8_STOLEN_RESERVED_1M: *size = 1024 * 1024; diff --git a/drivers/gpu/drm/i915/gem/selftests/huge_pages.c b/drivers/gpu/drm/i915/gem/selftests/huge_pages.c index 6b9f6cf50bf6b2..3ff3d8889c6cc0 100644 --- a/drivers/gpu/drm/i915/gem/selftests/huge_pages.c +++ b/drivers/gpu/drm/i915/gem/selftests/huge_pages.c @@ -115,7 +115,7 @@ static int get_huge_pages(struct drm_i915_gem_object *obj) do { struct page *page; - GEM_BUG_ON(order > MAX_ORDER); + GEM_BUG_ON(order > MAX_PAGE_ORDER); page = alloc_pages(GFP | __GFP_ZERO, order); if (!page) goto err; @@ -1082,7 +1082,7 @@ __cpu_check_shmem(struct drm_i915_gem_object *obj, u32 dword, u32 val) goto err_unlock; for (n = 0; n < obj->base.size >> PAGE_SHIFT; ++n) { - u32 *ptr = kmap_atomic(i915_gem_object_get_page(obj, n)); + u32 *ptr = kmap_local_page(i915_gem_object_get_page(obj, n)); if (needs_flush & CLFLUSH_BEFORE) drm_clflush_virt_range(ptr, PAGE_SIZE); @@ -1090,12 +1090,12 @@ __cpu_check_shmem(struct drm_i915_gem_object *obj, u32 dword, u32 val) if (ptr[dword] != val) { pr_err("n=%lu ptr[%u]=%u, val=%u\n", n, dword, ptr[dword], val); - kunmap_atomic(ptr); + kunmap_local(ptr); err = -EINVAL; break; } - kunmap_atomic(ptr); + kunmap_local(ptr); } i915_gem_object_finish_access(obj); 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 3bef1beec7cbb5..2a0c0634d446ed 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_coherency.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_coherency.c @@ -24,7 +24,6 @@ static int cpu_set(struct context *ctx, unsigned long offset, u32 v) { unsigned int needs_clflush; struct page *page; - void *map; u32 *cpu; int err; @@ -34,8 +33,7 @@ static int cpu_set(struct context *ctx, unsigned long offset, u32 v) goto out; page = i915_gem_object_get_page(ctx->obj, offset >> PAGE_SHIFT); - map = kmap_atomic(page); - cpu = map + offset_in_page(offset); + cpu = kmap_local_page(page) + offset_in_page(offset); if (needs_clflush & CLFLUSH_BEFORE) drm_clflush_virt_range(cpu, sizeof(*cpu)); @@ -45,7 +43,7 @@ static int cpu_set(struct context *ctx, unsigned long offset, u32 v) if (needs_clflush & CLFLUSH_AFTER) drm_clflush_virt_range(cpu, sizeof(*cpu)); - kunmap_atomic(map); + kunmap_local(cpu); i915_gem_object_finish_access(ctx->obj); out: @@ -57,7 +55,6 @@ static int cpu_get(struct context *ctx, unsigned long offset, u32 *v) { unsigned int needs_clflush; struct page *page; - void *map; u32 *cpu; int err; @@ -67,15 +64,14 @@ static int cpu_get(struct context *ctx, unsigned long offset, u32 *v) goto out; page = i915_gem_object_get_page(ctx->obj, offset >> PAGE_SHIFT); - map = kmap_atomic(page); - cpu = map + offset_in_page(offset); + cpu = kmap_local_page(page) + offset_in_page(offset); if (needs_clflush & CLFLUSH_BEFORE) drm_clflush_virt_range(cpu, sizeof(*cpu)); *v = *cpu; - kunmap_atomic(map); + kunmap_local(cpu); i915_gem_object_finish_access(ctx->obj); out: @@ -85,6 +81,7 @@ out: static int gtt_set(struct context *ctx, unsigned long offset, u32 v) { + intel_wakeref_t wakeref; struct i915_vma *vma; u32 __iomem *map; int err = 0; @@ -99,7 +96,7 @@ static int gtt_set(struct context *ctx, unsigned long offset, u32 v) if (IS_ERR(vma)) return PTR_ERR(vma); - intel_gt_pm_get(vma->vm->gt); + wakeref = intel_gt_pm_get(vma->vm->gt); map = i915_vma_pin_iomap(vma); i915_vma_unpin(vma); @@ -112,12 +109,13 @@ static int gtt_set(struct context *ctx, unsigned long offset, u32 v) i915_vma_unpin_iomap(vma); out_rpm: - intel_gt_pm_put(vma->vm->gt); + intel_gt_pm_put(vma->vm->gt, wakeref); return err; } static int gtt_get(struct context *ctx, unsigned long offset, u32 *v) { + intel_wakeref_t wakeref; struct i915_vma *vma; u32 __iomem *map; int err = 0; @@ -132,7 +130,7 @@ static int gtt_get(struct context *ctx, unsigned long offset, u32 *v) if (IS_ERR(vma)) return PTR_ERR(vma); - intel_gt_pm_get(vma->vm->gt); + wakeref = intel_gt_pm_get(vma->vm->gt); map = i915_vma_pin_iomap(vma); i915_vma_unpin(vma); @@ -145,7 +143,7 @@ static int gtt_get(struct context *ctx, unsigned long offset, u32 *v) i915_vma_unpin_iomap(vma); out_rpm: - intel_gt_pm_put(vma->vm->gt); + intel_gt_pm_put(vma->vm->gt, wakeref); return err; } 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 7021b6e9b219ef..89d4dc8b60c6a2 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c @@ -489,12 +489,12 @@ static int cpu_fill(struct drm_i915_gem_object *obj, u32 value) for (n = 0; n < real_page_count(obj); n++) { u32 *map; - map = kmap_atomic(i915_gem_object_get_page(obj, n)); + map = kmap_local_page(i915_gem_object_get_page(obj, n)); for (m = 0; m < DW_PER_PAGE; m++) map[m] = value; if (!has_llc) drm_clflush_virt_range(map, PAGE_SIZE); - kunmap_atomic(map); + kunmap_local(map); } i915_gem_object_finish_access(obj); @@ -520,7 +520,7 @@ static noinline int cpu_check(struct drm_i915_gem_object *obj, for (n = 0; n < real_page_count(obj); n++) { u32 *map, m; - map = kmap_atomic(i915_gem_object_get_page(obj, n)); + map = kmap_local_page(i915_gem_object_get_page(obj, n)); if (needs_flush & CLFLUSH_BEFORE) drm_clflush_virt_range(map, PAGE_SIZE); @@ -546,7 +546,7 @@ static noinline int cpu_check(struct drm_i915_gem_object *obj, } out_unmap: - kunmap_atomic(map); + kunmap_local(map); if (err) break; } diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c index e57f9390076c55..d684a70f2c0422 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_dmabuf.c @@ -504,7 +504,7 @@ static int igt_dmabuf_export_vmap(void *arg) } if (memchr_inv(ptr, 0, dmabuf->size)) { - pr_err("Exported object not initialiased to zero!\n"); + pr_err("Exported object not initialised to zero!\n"); err = -EINVAL; goto out; } 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 72957a36a36be3..2c51a2c452fc5c 100644 --- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c +++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c @@ -630,14 +630,14 @@ static bool assert_mmap_offset(struct drm_i915_private *i915, static void disable_retire_worker(struct drm_i915_private *i915) { i915_gem_driver_unregister__shrinker(i915); - intel_gt_pm_get(to_gt(i915)); + intel_gt_pm_get_untracked(to_gt(i915)); cancel_delayed_work_sync(&to_gt(i915)->requests.retire_work); } static void restore_retire_worker(struct drm_i915_private *i915) { igt_flush_test(i915); - intel_gt_pm_put(to_gt(i915)); + intel_gt_pm_put_untracked(to_gt(i915)); i915_gem_driver_register__shrinker(i915); } @@ -778,6 +778,7 @@ err_obj: static int gtt_set(struct drm_i915_gem_object *obj) { + intel_wakeref_t wakeref; struct i915_vma *vma; void __iomem *map; int err = 0; @@ -786,7 +787,7 @@ static int gtt_set(struct drm_i915_gem_object *obj) if (IS_ERR(vma)) return PTR_ERR(vma); - intel_gt_pm_get(vma->vm->gt); + wakeref = intel_gt_pm_get(vma->vm->gt); map = i915_vma_pin_iomap(vma); i915_vma_unpin(vma); if (IS_ERR(map)) { @@ -798,12 +799,13 @@ static int gtt_set(struct drm_i915_gem_object *obj) i915_vma_unpin_iomap(vma); out: - intel_gt_pm_put(vma->vm->gt); + intel_gt_pm_put(vma->vm->gt, wakeref); return err; } static int gtt_check(struct drm_i915_gem_object *obj) { + intel_wakeref_t wakeref; struct i915_vma *vma; void __iomem *map; int err = 0; @@ -812,7 +814,7 @@ static int gtt_check(struct drm_i915_gem_object *obj) if (IS_ERR(vma)) return PTR_ERR(vma); - intel_gt_pm_get(vma->vm->gt); + wakeref = intel_gt_pm_get(vma->vm->gt); map = i915_vma_pin_iomap(vma); i915_vma_unpin(vma); if (IS_ERR(map)) { @@ -828,7 +830,7 @@ static int gtt_check(struct drm_i915_gem_object *obj) i915_vma_unpin_iomap(vma); out: - intel_gt_pm_put(vma->vm->gt); + intel_gt_pm_put(vma->vm->gt, wakeref); return err; } diff --git a/drivers/gpu/drm/i915/gem/selftests/mock_context.c b/drivers/gpu/drm/i915/gem/selftests/mock_context.c index e199d7dbb87690..2b0327cc47c2de 100644 --- a/drivers/gpu/drm/i915/gem/selftests/mock_context.c +++ b/drivers/gpu/drm/i915/gem/selftests/mock_context.c @@ -83,7 +83,7 @@ live_context(struct drm_i915_private *i915, struct file *file) int err; u32 id; - pc = proto_context_create(i915, 0); + pc = proto_context_create(fpriv, i915, 0); if (IS_ERR(pc)) return ERR_CAST(pc); @@ -152,7 +152,7 @@ kernel_context(struct drm_i915_private *i915, struct i915_gem_context *ctx; struct i915_gem_proto_context *pc; - pc = proto_context_create(i915, 0); + pc = proto_context_create(NULL, i915, 0); if (IS_ERR(pc)) return ERR_CAST(pc); diff --git a/drivers/gpu/drm/i915/gt/gen8_ppgtt.c b/drivers/gpu/drm/i915/gt/gen8_ppgtt.c index 9895e18df0435a..fa46d2308b0ed3 100644 --- a/drivers/gpu/drm/i915/gt/gen8_ppgtt.c +++ b/drivers/gpu/drm/i915/gt/gen8_ppgtt.c @@ -5,6 +5,7 @@ #include +#include "gem/i915_gem_internal.h" #include "gem/i915_gem_lmem.h" #include "gen8_ppgtt.h" @@ -222,6 +223,9 @@ static void gen8_ppgtt_cleanup(struct i915_address_space *vm) { struct i915_ppgtt *ppgtt = i915_vm_to_ppgtt(vm); + if (vm->rsvd.obj) + i915_gem_object_put(vm->rsvd.obj); + if (intel_vgpu_active(vm->i915)) gen8_ppgtt_notify_vgt(ppgtt, false); @@ -950,6 +954,41 @@ err_pd: return ERR_PTR(err); } +static int gen8_init_rsvd(struct i915_address_space *vm) +{ + struct drm_i915_private *i915 = vm->i915; + struct drm_i915_gem_object *obj; + struct i915_vma *vma; + int ret; + + /* The memory will be used only by GPU. */ + obj = i915_gem_object_create_lmem(i915, PAGE_SIZE, + I915_BO_ALLOC_VOLATILE | + I915_BO_ALLOC_GPU_ONLY); + if (IS_ERR(obj)) + obj = i915_gem_object_create_internal(i915, PAGE_SIZE); + if (IS_ERR(obj)) + return PTR_ERR(obj); + + vma = i915_vma_instance(obj, vm, NULL); + if (IS_ERR(vma)) { + ret = PTR_ERR(vma); + goto unref; + } + + ret = i915_vma_pin(vma, 0, 0, PIN_USER | PIN_HIGH); + if (ret) + goto unref; + + vm->rsvd.vma = i915_vma_make_unshrinkable(vma); + vm->rsvd.obj = obj; + vm->total -= vma->node.size; + return 0; +unref: + i915_gem_object_put(obj); + return ret; +} + /* * GEN8 legacy ppgtt programming is accomplished through a max 4 PDP registers * with a net effect resembling a 2-level page table in normal x86 terms. Each @@ -1031,6 +1070,10 @@ struct i915_ppgtt *gen8_ppgtt_create(struct intel_gt *gt, if (intel_vgpu_active(gt->i915)) gen8_ppgtt_notify_vgt(ppgtt, true); + err = gen8_init_rsvd(&ppgtt->vm); + if (err) + goto err_put; + return ppgtt; err_put: diff --git a/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c b/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c index ecc990ec1b9526..d650beb8ed22f6 100644 --- a/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c +++ b/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c @@ -28,11 +28,14 @@ static void irq_disable(struct intel_breadcrumbs *b) static void __intel_breadcrumbs_arm_irq(struct intel_breadcrumbs *b) { + intel_wakeref_t wakeref; + /* * Since we are waiting on a request, the GPU should be busy * and should have its own rpm reference. */ - if (GEM_WARN_ON(!intel_gt_pm_get_if_awake(b->irq_engine->gt))) + wakeref = intel_gt_pm_get_if_awake(b->irq_engine->gt); + if (GEM_WARN_ON(!wakeref)) return; /* @@ -41,7 +44,7 @@ static void __intel_breadcrumbs_arm_irq(struct intel_breadcrumbs *b) * which we can add a new waiter and avoid the cost of re-enabling * the irq. */ - WRITE_ONCE(b->irq_armed, true); + WRITE_ONCE(b->irq_armed, wakeref); /* Requests may have completed before we could enable the interrupt. */ if (!b->irq_enabled++ && b->irq_enable(b)) @@ -61,12 +64,14 @@ static void intel_breadcrumbs_arm_irq(struct intel_breadcrumbs *b) static void __intel_breadcrumbs_disarm_irq(struct intel_breadcrumbs *b) { + intel_wakeref_t wakeref = b->irq_armed; + GEM_BUG_ON(!b->irq_enabled); if (!--b->irq_enabled) b->irq_disable(b); - WRITE_ONCE(b->irq_armed, false); - intel_gt_pm_put_async(b->irq_engine->gt); + WRITE_ONCE(b->irq_armed, 0); + intel_gt_pm_put_async(b->irq_engine->gt, wakeref); } static void intel_breadcrumbs_disarm_irq(struct intel_breadcrumbs *b) diff --git a/drivers/gpu/drm/i915/gt/intel_breadcrumbs_types.h b/drivers/gpu/drm/i915/gt/intel_breadcrumbs_types.h index 72dfd3748c4c33..bdf09fd67b6e70 100644 --- a/drivers/gpu/drm/i915/gt/intel_breadcrumbs_types.h +++ b/drivers/gpu/drm/i915/gt/intel_breadcrumbs_types.h @@ -13,6 +13,7 @@ #include #include "intel_engine_types.h" +#include "intel_wakeref.h" /* * Rather than have every client wait upon all user interrupts, @@ -43,7 +44,7 @@ struct intel_breadcrumbs { spinlock_t irq_lock; /* protects the interrupt from hardirq context */ struct irq_work irq_work; /* for use from inside irq_lock */ unsigned int irq_enabled; - bool irq_armed; + intel_wakeref_t irq_armed; /* Not all breadcrumbs are attached to physical HW */ intel_engine_mask_t engine_mask; diff --git a/drivers/gpu/drm/i915/gt/intel_context.c b/drivers/gpu/drm/i915/gt/intel_context.c index a53b26178f0adf..a2f1245741bbf2 100644 --- a/drivers/gpu/drm/i915/gt/intel_context.c +++ b/drivers/gpu/drm/i915/gt/intel_context.c @@ -6,6 +6,7 @@ #include "gem/i915_gem_context.h" #include "gem/i915_gem_pm.h" +#include "i915_drm_client.h" #include "i915_drv.h" #include "i915_trace.h" @@ -50,6 +51,7 @@ intel_context_create(struct intel_engine_cs *engine) int intel_context_alloc_state(struct intel_context *ce) { + struct i915_gem_context *ctx; int err = 0; if (mutex_lock_interruptible(&ce->pin_mutex)) @@ -66,6 +68,18 @@ int intel_context_alloc_state(struct intel_context *ce) goto unlock; set_bit(CONTEXT_ALLOC_BIT, &ce->flags); + + rcu_read_lock(); + ctx = rcu_dereference(ce->gem_context); + if (ctx && !kref_get_unless_zero(&ctx->ref)) + ctx = NULL; + rcu_read_unlock(); + if (ctx) { + if (ctx->client) + i915_drm_client_add_context_objects(ctx->client, + ce); + i915_gem_context_put(ctx); + } } unlock: diff --git a/drivers/gpu/drm/i915/gt/intel_context.h b/drivers/gpu/drm/i915/gt/intel_context.h index a80e3b7c24ff98..25564c01507e49 100644 --- a/drivers/gpu/drm/i915/gt/intel_context.h +++ b/drivers/gpu/drm/i915/gt/intel_context.h @@ -212,7 +212,7 @@ static inline void intel_context_enter(struct intel_context *ce) return; ce->ops->enter(ce); - intel_gt_pm_get(ce->vm->gt); + ce->wakeref = intel_gt_pm_get(ce->vm->gt); } static inline void intel_context_mark_active(struct intel_context *ce) @@ -229,7 +229,7 @@ static inline void intel_context_exit(struct intel_context *ce) if (--ce->active_count) return; - intel_gt_pm_put_async(ce->vm->gt); + intel_gt_pm_put_async(ce->vm->gt, ce->wakeref); ce->ops->exit(ce); } diff --git a/drivers/gpu/drm/i915/gt/intel_context_types.h b/drivers/gpu/drm/i915/gt/intel_context_types.h index aceaac28a33eb0..7eccbd70d89fce 100644 --- a/drivers/gpu/drm/i915/gt/intel_context_types.h +++ b/drivers/gpu/drm/i915/gt/intel_context_types.h @@ -17,6 +17,7 @@ #include "i915_utils.h" #include "intel_engine_types.h" #include "intel_sseu.h" +#include "intel_wakeref.h" #include "uc/intel_guc_fwif.h" @@ -112,6 +113,7 @@ struct intel_context { u32 ring_size; struct intel_ring *ring; struct intel_timeline *timeline; + intel_wakeref_t wakeref; unsigned long flags; #define CONTEXT_BARRIER_BIT 0 diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index 4a11219e560e08..40687806d22a6d 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -47,7 +47,7 @@ #define GEN9_LR_CONTEXT_RENDER_SIZE (22 * PAGE_SIZE) #define GEN11_LR_CONTEXT_RENDER_SIZE (14 * PAGE_SIZE) -#define GEN8_LR_CONTEXT_OTHER_SIZE ( 2 * PAGE_SIZE) +#define GEN8_LR_CONTEXT_OTHER_SIZE (2 * PAGE_SIZE) #define MAX_MMIO_BASES 3 struct engine_info { diff --git a/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c b/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c index 9a527e1f5be655..1a8e2b7db0138f 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c @@ -188,7 +188,7 @@ static void heartbeat(struct work_struct *wrk) * low latency and no jitter] the chance to naturally * complete before being preempted. */ - attr.priority = 0; + attr.priority = I915_PRIORITY_NORMAL; if (rq->sched.attr.priority >= attr.priority) attr.priority = I915_PRIORITY_HEARTBEAT; if (rq->sched.attr.priority >= attr.priority) diff --git a/drivers/gpu/drm/i915/gt/intel_engine_pm.c b/drivers/gpu/drm/i915/gt/intel_engine_pm.c index e91fc881dbf18b..96bdb93a948d1b 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_pm.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_pm.c @@ -63,7 +63,7 @@ static int __engine_unpark(struct intel_wakeref *wf) ENGINE_TRACE(engine, "\n"); - intel_gt_pm_get(engine->gt); + engine->wakeref_track = intel_gt_pm_get(engine->gt); /* Discard stale context state from across idling */ ce = engine->kernel_context; @@ -122,6 +122,7 @@ __queue_and_release_pm(struct i915_request *rq, */ GEM_BUG_ON(rq->context->active_count != 1); __intel_gt_pm_get(engine->gt); + rq->context->wakeref = intel_wakeref_track(&engine->gt->wakeref); /* * We have to serialise all potential retirement paths with our @@ -285,7 +286,7 @@ static int __engine_park(struct intel_wakeref *wf) engine->park(engine); /* While gt calls i915_vma_parked(), we have to break the lock cycle */ - intel_gt_pm_put_async(engine->gt); + intel_gt_pm_put_async(engine->gt, engine->wakeref_track); return 0; } @@ -296,7 +297,7 @@ static const struct intel_wakeref_ops wf_ops = { void intel_engine_init__pm(struct intel_engine_cs *engine) { - intel_wakeref_init(&engine->wakeref, engine->i915, &wf_ops); + intel_wakeref_init(&engine->wakeref, engine->i915, &wf_ops, engine->name); intel_engine_init_heartbeat(engine); intel_gsc_idle_msg_enable(engine); diff --git a/drivers/gpu/drm/i915/gt/intel_engine_pm.h b/drivers/gpu/drm/i915/gt/intel_engine_pm.h index d68675925b79e5..1d97c435a01528 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_pm.h +++ b/drivers/gpu/drm/i915/gt/intel_engine_pm.h @@ -10,6 +10,7 @@ #include "i915_request.h" #include "intel_engine_types.h" #include "intel_wakeref.h" +#include "intel_gt.h" #include "intel_gt_pm.h" static inline bool diff --git a/drivers/gpu/drm/i915/gt/intel_engine_regs.h b/drivers/gpu/drm/i915/gt/intel_engine_regs.h index fdd4ddd3a978a2..a8eac59e377938 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_regs.h +++ b/drivers/gpu/drm/i915/gt/intel_engine_regs.h @@ -118,9 +118,15 @@ #define CCID_EXTENDED_STATE_RESTORE BIT(2) #define CCID_EXTENDED_STATE_SAVE BIT(3) #define RING_BB_PER_CTX_PTR(base) _MMIO((base) + 0x1c0) /* gen8+ */ +#define PER_CTX_BB_FORCE BIT(2) +#define PER_CTX_BB_VALID BIT(0) + #define RING_INDIRECT_CTX(base) _MMIO((base) + 0x1c4) /* gen8+ */ #define RING_INDIRECT_CTX_OFFSET(base) _MMIO((base) + 0x1c8) /* gen8+ */ #define ECOSKPD(base) _MMIO((base) + 0x1d0) +#define XEHP_BLITTER_SCHEDULING_MODE_MASK REG_GENMASK(12, 11) +#define XEHP_BLITTER_ROUND_ROBIN_MODE \ + REG_FIELD_PREP(XEHP_BLITTER_SCHEDULING_MODE_MASK, 1) #define ECO_CONSTANT_BUFFER_SR_DISABLE REG_BIT(4) #define ECO_GATING_CX_ONLY REG_BIT(3) #define GEN6_BLITTER_FBC_NOTIFY REG_BIT(3) @@ -257,5 +263,7 @@ #define VDBOX_CGCTL3F18(base) _MMIO((base) + 0x3f18) #define ALNUNIT_CLKGATE_DIS REG_BIT(13) +#define VDBOX_CGCTL3F1C(base) _MMIO((base) + 0x3f1c) +#define MFXPIPE_CLKGATE_DIS REG_BIT(3) #endif /* __INTEL_ENGINE_REGS__ */ diff --git a/drivers/gpu/drm/i915/gt/intel_engine_types.h b/drivers/gpu/drm/i915/gt/intel_engine_types.h index 8769760257fd9e..960e6be2042fe0 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_types.h +++ b/drivers/gpu/drm/i915/gt/intel_engine_types.h @@ -446,7 +446,9 @@ struct intel_engine_cs { unsigned long serial; unsigned long wakeref_serial; + intel_wakeref_t wakeref_track; struct intel_wakeref wakeref; + struct file *default_state; struct { diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c index e8f42ec6b1b471..42aade0faf2d14 100644 --- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c +++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c @@ -630,7 +630,7 @@ static void __execlists_schedule_out(struct i915_request * const rq, execlists_context_status_change(rq, INTEL_CONTEXT_SCHEDULE_OUT); if (engine->fw_domain && !--engine->fw_active) intel_uncore_forcewake_put(engine->uncore, engine->fw_domain); - intel_gt_pm_put_async(engine->gt); + intel_gt_pm_put_async_untracked(engine->gt); /* * If this is part of a virtual engine, its next request may diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c b/drivers/gpu/drm/i915/gt/intel_ggtt.c index 15fc8e4703f483..21a7e3191c1827 100644 --- a/drivers/gpu/drm/i915/gt/intel_ggtt.c +++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c @@ -245,16 +245,15 @@ static void guc_ggtt_invalidate(struct i915_ggtt *ggtt) gen8_ggtt_invalidate(ggtt); list_for_each_entry(gt, &ggtt->gt_list, ggtt_link) { - if (intel_guc_tlb_invalidation_is_available(>->uc.guc)) { + if (intel_guc_tlb_invalidation_is_available(>->uc.guc)) guc_ggtt_ct_invalidate(gt); - } else if (GRAPHICS_VER(i915) >= 12) { + else if (GRAPHICS_VER(i915) >= 12) intel_uncore_write_fw(gt->uncore, GEN12_GUC_TLB_INV_CR, GEN12_GUC_TLB_INV_CR_INVALIDATE); - } else { + else intel_uncore_write_fw(gt->uncore, GEN8_GTCR, GEN8_GTCR_INVALIDATE); - } } } @@ -297,7 +296,7 @@ static bool should_update_ggtt_with_bind(struct i915_ggtt *ggtt) return intel_gt_is_bind_context_ready(gt); } -static struct intel_context *gen8_ggtt_bind_get_ce(struct i915_ggtt *ggtt) +static struct intel_context *gen8_ggtt_bind_get_ce(struct i915_ggtt *ggtt, intel_wakeref_t *wakeref) { struct intel_context *ce; struct intel_gt *gt = ggtt->vm.gt; @@ -314,7 +313,8 @@ static struct intel_context *gen8_ggtt_bind_get_ce(struct i915_ggtt *ggtt) * would conflict with fs_reclaim trying to allocate memory while * doing rpm_resume(). */ - if (!intel_gt_pm_get_if_awake(gt)) + *wakeref = intel_gt_pm_get_if_awake(gt); + if (!*wakeref) return NULL; intel_engine_pm_get(ce->engine); @@ -322,10 +322,10 @@ static struct intel_context *gen8_ggtt_bind_get_ce(struct i915_ggtt *ggtt) return ce; } -static void gen8_ggtt_bind_put_ce(struct intel_context *ce) +static void gen8_ggtt_bind_put_ce(struct intel_context *ce, intel_wakeref_t wakeref) { intel_engine_pm_put(ce->engine); - intel_gt_pm_put(ce->engine->gt); + intel_gt_pm_put(ce->engine->gt, wakeref); } static bool gen8_ggtt_bind_ptes(struct i915_ggtt *ggtt, u32 offset, @@ -338,12 +338,13 @@ static bool gen8_ggtt_bind_ptes(struct i915_ggtt *ggtt, u32 offset, struct sgt_iter iter; struct i915_request *rq; struct intel_context *ce; + intel_wakeref_t wakeref; u32 *cs; if (!num_entries) return true; - ce = gen8_ggtt_bind_get_ce(ggtt); + ce = gen8_ggtt_bind_get_ce(ggtt, &wakeref); if (!ce) return false; @@ -419,13 +420,13 @@ queue_err_rq: offset += n_ptes; } - gen8_ggtt_bind_put_ce(ce); + gen8_ggtt_bind_put_ce(ce, wakeref); return true; err_rq: i915_request_put(rq); put_ce: - gen8_ggtt_bind_put_ce(ce); + gen8_ggtt_bind_put_ce(ce, wakeref); return false; } diff --git a/drivers/gpu/drm/i915/gt/intel_gsc.h b/drivers/gpu/drm/i915/gt/intel_gsc.h index 7ab3ca0f9f268d..013c642514486a 100644 --- a/drivers/gpu/drm/i915/gt/intel_gsc.h +++ b/drivers/gpu/drm/i915/gt/intel_gsc.h @@ -21,8 +21,11 @@ struct mei_aux_device; /** * struct intel_gsc - graphics security controller * - * @gem_obj: scratch memory GSC operations - * @intf : gsc interface + * @intf: gsc interface + * @intf.adev: MEI aux. device for this @intf + * @intf.gem_obj: scratch memory GSC operations + * @intf.irq: IRQ for this device (%-1 for no IRQ) + * @intf.id: this interface's id number/index */ struct intel_gsc { struct intel_gsc_intf { diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c b/drivers/gpu/drm/i915/gt/intel_gt.c index ba1186fc524f84..a425db5ed3a22c 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt.c +++ b/drivers/gpu/drm/i915/gt/intel_gt.c @@ -451,7 +451,7 @@ void intel_gt_flush_ggtt_writes(struct intel_gt *gt) spin_lock_irqsave(&uncore->lock, flags); intel_uncore_posting_read_fw(uncore, - RING_HEAD(RENDER_RING_BASE)); + RING_TAIL(RENDER_RING_BASE)); spin_unlock_irqrestore(&uncore->lock, flags); } } diff --git a/drivers/gpu/drm/i915/gt/intel_gt.h b/drivers/gpu/drm/i915/gt/intel_gt.h index 970bedf6b78a7b..608f5c87292857 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt.h +++ b/drivers/gpu/drm/i915/gt/intel_gt.h @@ -82,6 +82,10 @@ struct drm_printer; ##__VA_ARGS__); \ } while (0) +#define NEEDS_FASTCOLOR_BLT_WABB(engine) ( \ + IS_GFX_GT_IP_RANGE(engine->gt, IP_VER(12, 55), IP_VER(12, 71)) && \ + engine->class == COPY_ENGINE_CLASS && engine->instance == 0) + static inline bool gt_is_root(struct intel_gt *gt) { return !gt->info.id; @@ -114,6 +118,11 @@ static inline struct intel_gt *gsc_to_gt(struct intel_gsc *gsc) return container_of(gsc, struct intel_gt, gsc); } +static inline struct drm_i915_private *guc_to_i915(struct intel_guc *guc) +{ + return guc_to_gt(guc)->i915; +} + void intel_gt_common_init_early(struct intel_gt *gt); int intel_root_gt_init_early(struct drm_i915_private *i915); int intel_gt_assign_ggtt(struct intel_gt *gt); @@ -167,6 +176,20 @@ void intel_gt_release_all(struct drm_i915_private *i915); (id__)++) \ for_each_if(((gt__) = (i915__)->gt[(id__)])) +/* Simple iterator over all initialised engines */ +#define for_each_engine(engine__, gt__, id__) \ + for ((id__) = 0; \ + (id__) < I915_NUM_ENGINES; \ + (id__)++) \ + for_each_if ((engine__) = (gt__)->engine[(id__)]) + +/* Iterator over subset of engines selected by mask */ +#define for_each_engine_masked(engine__, gt__, mask__, tmp__) \ + for ((tmp__) = (mask__) & (gt__)->info.engine_mask; \ + (tmp__) ? \ + ((engine__) = (gt__)->engine[__mask_next_bit(tmp__)]), 1 : \ + 0;) + void intel_gt_info_print(const struct intel_gt_info *info, struct drm_printer *p); diff --git a/drivers/gpu/drm/i915/gt/intel_gt_engines_debugfs.c b/drivers/gpu/drm/i915/gt/intel_gt_engines_debugfs.c index 8f9b874fdc9c80..3aa1d014c14dfe 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_engines_debugfs.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_engines_debugfs.c @@ -6,8 +6,8 @@ #include -#include "i915_drv.h" /* for_each_engine! */ #include "intel_engine.h" +#include "intel_gt.h" #include "intel_gt_debugfs.h" #include "intel_gt_engines_debugfs.h" diff --git a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c index 34913912d8ae29..e253750a51c568 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c @@ -388,8 +388,7 @@ void intel_gt_mcr_lock(struct intel_gt *gt, unsigned long *flags) * registers. This wakeref will be released in the unlock * routine. * - * This is expected to become a formally documented/numbered - * workaround soon. + * Wa_22018931422 */ intel_uncore_forcewake_get(gt->uncore, FORCEWAKE_GT); diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm.c b/drivers/gpu/drm/i915/gt/intel_gt_pm.c index f5899d503e234b..220ac4f92edfc2 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm.c @@ -28,19 +28,20 @@ static void user_forcewake(struct intel_gt *gt, bool suspend) { int count = atomic_read(>->user_wakeref); + intel_wakeref_t wakeref; /* Inside suspend/resume so single threaded, no races to worry about. */ if (likely(!count)) return; - intel_gt_pm_get(gt); + wakeref = intel_gt_pm_get(gt); if (suspend) { GEM_BUG_ON(count > atomic_read(>->wakeref.count)); atomic_sub(count, >->wakeref.count); } else { atomic_add(count, >->wakeref.count); } - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); } static void runtime_begin(struct intel_gt *gt) @@ -138,7 +139,7 @@ void intel_gt_pm_init_early(struct intel_gt *gt) * runtime_pm is per-device rather than per-tile, so this is still the * correct structure. */ - intel_wakeref_init(>->wakeref, gt->i915, &wf_ops); + intel_wakeref_init(>->wakeref, gt->i915, &wf_ops, "GT"); seqcount_mutex_init(>->stats.lock, >->wakeref.mutex); } @@ -167,7 +168,7 @@ static void gt_sanitize(struct intel_gt *gt, bool force) enum intel_engine_id id; intel_wakeref_t wakeref; - GT_TRACE(gt, "force:%s", str_yes_no(force)); + GT_TRACE(gt, "force:%s\n", str_yes_no(force)); /* Use a raw wakeref to avoid calling intel_display_power_get early */ wakeref = intel_runtime_pm_get(gt->uncore->rpm); @@ -236,6 +237,7 @@ int intel_gt_resume(struct intel_gt *gt) { struct intel_engine_cs *engine; enum intel_engine_id id; + intel_wakeref_t wakeref; int err; err = intel_gt_has_unrecoverable_error(gt); @@ -252,7 +254,7 @@ int intel_gt_resume(struct intel_gt *gt) */ gt_sanitize(gt, true); - intel_gt_pm_get(gt); + wakeref = intel_gt_pm_get(gt); intel_uncore_forcewake_get(gt->uncore, FORCEWAKE_ALL); intel_rc6_sanitize(>->rc6); @@ -295,7 +297,7 @@ int intel_gt_resume(struct intel_gt *gt) out_fw: intel_uncore_forcewake_put(gt->uncore, FORCEWAKE_ALL); - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); intel_gt_bind_context_set_ready(gt); return err; diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm.h b/drivers/gpu/drm/i915/gt/intel_gt_pm.h index b1eeb5b33918ca..911fd0160221ba 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm.h @@ -16,19 +16,28 @@ static inline bool intel_gt_pm_is_awake(const struct intel_gt *gt) return intel_wakeref_is_active(>->wakeref); } -static inline void intel_gt_pm_get(struct intel_gt *gt) +static inline void intel_gt_pm_get_untracked(struct intel_gt *gt) { intel_wakeref_get(>->wakeref); } +static inline intel_wakeref_t intel_gt_pm_get(struct intel_gt *gt) +{ + intel_gt_pm_get_untracked(gt); + return intel_wakeref_track(>->wakeref); +} + static inline void __intel_gt_pm_get(struct intel_gt *gt) { __intel_wakeref_get(>->wakeref); } -static inline bool intel_gt_pm_get_if_awake(struct intel_gt *gt) +static inline intel_wakeref_t intel_gt_pm_get_if_awake(struct intel_gt *gt) { - return intel_wakeref_get_if_active(>->wakeref); + if (!intel_wakeref_get_if_active(>->wakeref)) + return 0; + + return intel_wakeref_track(>->wakeref); } static inline void intel_gt_pm_might_get(struct intel_gt *gt) @@ -36,12 +45,18 @@ static inline void intel_gt_pm_might_get(struct intel_gt *gt) intel_wakeref_might_get(>->wakeref); } -static inline void intel_gt_pm_put(struct intel_gt *gt) +static inline void intel_gt_pm_put_untracked(struct intel_gt *gt) { intel_wakeref_put(>->wakeref); } -static inline void intel_gt_pm_put_async(struct intel_gt *gt) +static inline void intel_gt_pm_put(struct intel_gt *gt, intel_wakeref_t handle) +{ + intel_wakeref_untrack(>->wakeref, handle); + intel_gt_pm_put_untracked(gt); +} + +static inline void intel_gt_pm_put_async_untracked(struct intel_gt *gt) { intel_wakeref_put_async(>->wakeref); } @@ -51,9 +66,14 @@ static inline void intel_gt_pm_might_put(struct intel_gt *gt) intel_wakeref_might_put(>->wakeref); } -#define with_intel_gt_pm(gt, tmp) \ - for (tmp = 1, intel_gt_pm_get(gt); tmp; \ - intel_gt_pm_put(gt), tmp = 0) +static inline void intel_gt_pm_put_async(struct intel_gt *gt, intel_wakeref_t handle) +{ + intel_wakeref_untrack(>->wakeref, handle); + intel_gt_pm_put_async_untracked(gt); +} + +#define with_intel_gt_pm(gt, wf) \ + for (wf = intel_gt_pm_get(gt); wf; intel_gt_pm_put(gt, wf), wf = 0) /** * with_intel_gt_pm_if_awake - if GT is PM awake, get a reference to prevent @@ -64,7 +84,7 @@ static inline void intel_gt_pm_might_put(struct intel_gt *gt) * @wf: pointer to a temporary wakeref. */ #define with_intel_gt_pm_if_awake(gt, wf) \ - for (wf = intel_gt_pm_get_if_awake(gt); wf; intel_gt_pm_put_async(gt), wf = 0) + for (wf = intel_gt_pm_get_if_awake(gt); wf; intel_gt_pm_put_async(gt, wf), wf = 0) static inline int intel_gt_pm_wait_for_idle(struct intel_gt *gt) { diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c index f900cc68d6d98a..7114c116e9284a 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm_debugfs.c @@ -27,7 +27,7 @@ void intel_gt_pm_debugfs_forcewake_user_open(struct intel_gt *gt) { atomic_inc(>->user_wakeref); - intel_gt_pm_get(gt); + intel_gt_pm_get_untracked(gt); if (GRAPHICS_VER(gt->i915) >= 6) intel_uncore_forcewake_user_get(gt->uncore); } @@ -36,7 +36,7 @@ void intel_gt_pm_debugfs_forcewake_user_release(struct intel_gt *gt) { if (GRAPHICS_VER(gt->i915) >= 6) intel_uncore_forcewake_user_put(gt->uncore); - intel_gt_pm_put(gt); + intel_gt_pm_put_untracked(gt); atomic_dec(>->user_wakeref); } diff --git a/drivers/gpu/drm/i915/gt/intel_gt_regs.h b/drivers/gpu/drm/i915/gt/intel_gt_regs.h index eecd0a87a64785..50962cfd1353ae 100644 --- a/drivers/gpu/drm/i915/gt/intel_gt_regs.h +++ b/drivers/gpu/drm/i915/gt/intel_gt_regs.h @@ -469,6 +469,9 @@ #define XEHP_PSS_MODE2 MCR_REG(0x703c) #define SCOREBOARD_STALL_FLUSH_CONTROL REG_BIT(5) +#define XEHP_PSS_CHICKEN MCR_REG(0x7044) +#define FD_END_COLLECT REG_BIT(5) + #define GEN7_SC_INSTDONE _MMIO(0x7100) #define GEN12_SC_INSTDONE_EXTRA _MMIO(0x7104) #define GEN12_SC_INSTDONE_EXTRA2 _MMIO(0x7108) @@ -537,6 +540,9 @@ #define XEHP_SQCM MCR_REG(0x8724) #define EN_32B_ACCESS REG_BIT(30) +#define MTL_GSCPSMI_BASEADDR_LSB _MMIO(0x880c) +#define MTL_GSCPSMI_BASEADDR_MSB _MMIO(0x8810) + #define HSW_IDICR _MMIO(0x9008) #define IDIHASHMSK(x) (((x) & 0x3f) << 16) diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.c b/drivers/gpu/drm/i915/gt/intel_gtt.c index 4fbed27ef0eccb..86f73fe558ca6e 100644 --- a/drivers/gpu/drm/i915/gt/intel_gtt.c +++ b/drivers/gpu/drm/i915/gt/intel_gtt.c @@ -63,6 +63,9 @@ struct drm_i915_gem_object *alloc_pt_lmem(struct i915_address_space *vm, int sz) if (!IS_ERR(obj)) { obj->base.resv = i915_vm_resv_get(vm); obj->shares_resv_from = vm; + + if (vm->fpriv) + i915_drm_client_add_object(vm->fpriv->client, obj); } return obj; @@ -84,6 +87,9 @@ struct drm_i915_gem_object *alloc_pt_dma(struct i915_address_space *vm, int sz) if (!IS_ERR(obj)) { obj->base.resv = i915_vm_resv_get(vm); obj->shares_resv_from = vm; + + if (vm->fpriv) + i915_drm_client_add_object(vm->fpriv->client, obj); } return obj; @@ -95,6 +101,16 @@ int map_pt_dma(struct i915_address_space *vm, struct drm_i915_gem_object *obj) void *vaddr; type = intel_gt_coherent_map_type(vm->gt, obj, true); + /* + * FIXME: It is suspected that some Address Translation Service (ATS) + * issue on IOMMU is causing CAT errors to occur on some MTL workloads. + * Applying a write barrier to the ppgtt set entry functions appeared + * to have no effect, so we must temporarily use I915_MAP_WC here on + * MTL until a proper ATS solution is found. + */ + if (IS_METEORLAKE(vm->i915)) + type = I915_MAP_WC; + vaddr = i915_gem_object_pin_map_unlocked(obj, type); if (IS_ERR(vaddr)) return PTR_ERR(vaddr); @@ -109,6 +125,16 @@ int map_pt_dma_locked(struct i915_address_space *vm, struct drm_i915_gem_object void *vaddr; type = intel_gt_coherent_map_type(vm->gt, obj, true); + /* + * FIXME: It is suspected that some Address Translation Service (ATS) + * issue on IOMMU is causing CAT errors to occur on some MTL workloads. + * Applying a write barrier to the ppgtt set entry functions appeared + * to have no effect, so we must temporarily use I915_MAP_WC here on + * MTL until a proper ATS solution is found. + */ + if (IS_METEORLAKE(vm->i915)) + type = I915_MAP_WC; + vaddr = i915_gem_object_pin_map(obj, type); if (IS_ERR(vaddr)) return PTR_ERR(vaddr); diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.h b/drivers/gpu/drm/i915/gt/intel_gtt.h index b471edac269920..6b85222ee3ea68 100644 --- a/drivers/gpu/drm/i915/gt/intel_gtt.h +++ b/drivers/gpu/drm/i915/gt/intel_gtt.h @@ -249,8 +249,13 @@ struct i915_address_space { struct work_struct release_work; struct drm_mm mm; + struct { + struct drm_i915_gem_object *obj; + struct i915_vma *vma; + } rsvd; struct intel_gt *gt; struct drm_i915_private *i915; + struct drm_i915_file_private *fpriv; struct device *dma; u64 total; /* size addr space maps (ex. 2GB for ggtt) */ u64 reserved; /* size addr space reserved */ diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c index eaf66d90316655..7c367ba8d9dcf1 100644 --- a/drivers/gpu/drm/i915/gt/intel_lrc.c +++ b/drivers/gpu/drm/i915/gt/intel_lrc.c @@ -828,6 +828,18 @@ lrc_ring_indirect_offset_default(const struct intel_engine_cs *engine) return 0; } +static void +lrc_setup_bb_per_ctx(u32 *regs, + const struct intel_engine_cs *engine, + u32 ctx_bb_ggtt_addr) +{ + GEM_BUG_ON(lrc_ring_wa_bb_per_ctx(engine) == -1); + regs[lrc_ring_wa_bb_per_ctx(engine) + 1] = + ctx_bb_ggtt_addr | + PER_CTX_BB_FORCE | + PER_CTX_BB_VALID; +} + static void lrc_setup_indirect_ctx(u32 *regs, const struct intel_engine_cs *engine, @@ -1020,7 +1032,13 @@ static u32 context_wa_bb_offset(const struct intel_context *ce) return PAGE_SIZE * ce->wa_bb_page; } -static u32 *context_indirect_bb(const struct intel_context *ce) +/* + * per_ctx below determines which WABB section is used. + * When true, the function returns the location of the + * PER_CTX_BB. When false, the function returns the + * location of the INDIRECT_CTX. + */ +static u32 *context_wabb(const struct intel_context *ce, bool per_ctx) { void *ptr; @@ -1029,6 +1047,7 @@ static u32 *context_indirect_bb(const struct intel_context *ce) ptr = ce->lrc_reg_state; ptr -= LRC_STATE_OFFSET; /* back to start of context image */ ptr += context_wa_bb_offset(ce); + ptr += per_ctx ? PAGE_SIZE : 0; return ptr; } @@ -1105,7 +1124,8 @@ __lrc_alloc_state(struct intel_context *ce, struct intel_engine_cs *engine) if (GRAPHICS_VER(engine->i915) >= 12) { ce->wa_bb_page = context_size / PAGE_SIZE; - context_size += PAGE_SIZE; + /* INDIRECT_CTX and PER_CTX_BB need separate pages. */ + context_size += PAGE_SIZE * 2; } if (intel_context_is_parent(ce) && intel_engine_uses_guc(engine)) { @@ -1407,12 +1427,85 @@ gen12_emit_indirect_ctx_xcs(const struct intel_context *ce, u32 *cs) return gen12_emit_aux_table_inv(ce->engine, cs); } +static u32 *xehp_emit_fastcolor_blt_wabb(const struct intel_context *ce, u32 *cs) +{ + struct intel_gt *gt = ce->engine->gt; + int mocs = gt->mocs.uc_index << 1; + + /** + * Wa_16018031267 / Wa_16018063123 requires that SW forces the + * main copy engine arbitration into round robin mode. We + * additionally need to submit the following WABB blt command + * to produce 4 subblits with each subblit generating 0 byte + * write requests as WABB: + * + * XY_FASTCOLOR_BLT + * BG0 -> 5100000E + * BG1 -> 0000003F (Dest pitch) + * BG2 -> 00000000 (X1, Y1) = (0, 0) + * BG3 -> 00040001 (X2, Y2) = (1, 4) + * BG4 -> scratch + * BG5 -> scratch + * BG6-12 -> 00000000 + * BG13 -> 20004004 (Surf. Width= 2,Surf. Height = 5 ) + * BG14 -> 00000010 (Qpitch = 4) + * BG15 -> 00000000 + */ + *cs++ = XY_FAST_COLOR_BLT_CMD | (16 - 2); + *cs++ = FIELD_PREP(XY_FAST_COLOR_BLT_MOCS_MASK, mocs) | 0x3f; + *cs++ = 0; + *cs++ = 4 << 16 | 1; + *cs++ = lower_32_bits(i915_vma_offset(ce->vm->rsvd.vma)); + *cs++ = upper_32_bits(i915_vma_offset(ce->vm->rsvd.vma)); + *cs++ = 0; + *cs++ = 0; + *cs++ = 0; + *cs++ = 0; + *cs++ = 0; + *cs++ = 0; + *cs++ = 0; + *cs++ = 0x20004004; + *cs++ = 0x10; + *cs++ = 0; + + return cs; +} + +static u32 * +xehp_emit_per_ctx_bb(const struct intel_context *ce, u32 *cs) +{ + /* Wa_16018031267, Wa_16018063123 */ + if (NEEDS_FASTCOLOR_BLT_WABB(ce->engine)) + cs = xehp_emit_fastcolor_blt_wabb(ce, cs); + + return cs; +} + +static void +setup_per_ctx_bb(const struct intel_context *ce, + const struct intel_engine_cs *engine, + u32 *(*emit)(const struct intel_context *, u32 *)) +{ + /* Place PER_CTX_BB on next page after INDIRECT_CTX */ + u32 * const start = context_wabb(ce, true); + u32 *cs; + + cs = emit(ce, start); + + /* PER_CTX_BB must manually terminate */ + *cs++ = MI_BATCH_BUFFER_END; + + GEM_BUG_ON(cs - start > I915_GTT_PAGE_SIZE / sizeof(*cs)); + lrc_setup_bb_per_ctx(ce->lrc_reg_state, engine, + lrc_indirect_bb(ce) + PAGE_SIZE); +} + static void setup_indirect_ctx_bb(const struct intel_context *ce, const struct intel_engine_cs *engine, u32 *(*emit)(const struct intel_context *, u32 *)) { - u32 * const start = context_indirect_bb(ce); + u32 * const start = context_wabb(ce, false); u32 *cs; cs = emit(ce, start); @@ -1511,6 +1604,7 @@ u32 lrc_update_regs(const struct intel_context *ce, /* Mutually exclusive wrt to global indirect bb */ GEM_BUG_ON(engine->wa_ctx.indirect_ctx.size); setup_indirect_ctx_bb(ce, engine, fn); + setup_per_ctx_bb(ce, engine, xehp_emit_per_ctx_bb); } return lrc_descriptor(ce) | CTX_DESC_FORCE_RESTORE; diff --git a/drivers/gpu/drm/i915/gt/intel_sseu.c b/drivers/gpu/drm/i915/gt/intel_sseu.c index f602895f6d0dfe..6a3246240e81de 100644 --- a/drivers/gpu/drm/i915/gt/intel_sseu.c +++ b/drivers/gpu/drm/i915/gt/intel_sseu.c @@ -849,13 +849,12 @@ void intel_sseu_print_topology(struct drm_i915_private *i915, const struct sseu_dev_info *sseu, struct drm_printer *p) { - if (sseu->max_slices == 0) { + if (sseu->max_slices == 0) drm_printf(p, "Unavailable\n"); - } else if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50)) { + else if (GRAPHICS_VER_FULL(i915) >= IP_VER(12, 50)) sseu_print_xehp_topology(sseu, p); - } else { + else sseu_print_hsw_topology(sseu, p); - } } void intel_sseu_print_ss_info(const char *type, diff --git a/drivers/gpu/drm/i915/gt/intel_workarounds.c b/drivers/gpu/drm/i915/gt/intel_workarounds.c index 192ac0e59afa13..3eacbc50caf8d9 100644 --- a/drivers/gpu/drm/i915/gt/intel_workarounds.c +++ b/drivers/gpu/drm/i915/gt/intel_workarounds.c @@ -777,6 +777,9 @@ static void dg2_ctx_workarounds_init(struct intel_engine_cs *engine, /* Wa_18019271663:dg2 */ wa_masked_en(wal, CACHE_MODE_1, MSAA_OPTIMIZATION_REDUC_DISABLE); + + /* Wa_14019877138:dg2 */ + wa_mcr_masked_en(wal, XEHP_PSS_CHICKEN, FD_END_COLLECT); } static void xelpg_ctx_gt_tuning_init(struct intel_engine_cs *engine, @@ -1662,9 +1665,23 @@ xelpg_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) debug_dump_steering(gt); } +static void +wa_16021867713(struct intel_gt *gt, struct i915_wa_list *wal) +{ + struct intel_engine_cs *engine; + int id; + + for_each_engine(engine, gt, id) + if (engine->class == VIDEO_DECODE_CLASS) + wa_write_or(wal, VDBOX_CGCTL3F1C(engine->mmio_base), + MFXPIPE_CLKGATE_DIS); +} + static void xelpmp_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) { + wa_16021867713(gt, wal); + /* * Wa_14018778641 * Wa_18018781329 @@ -1674,6 +1691,9 @@ xelpmp_gt_workarounds_init(struct intel_gt *gt, struct i915_wa_list *wal) */ wa_write_or(wal, XELPMP_GSC_MOD_CTRL, FORCE_MISS_FTLB); + /* Wa_22016670082 */ + wa_write_or(wal, GEN12_SQCNT1, GEN12_STRICT_RAR_ENABLE); + debug_dump_steering(gt); } @@ -2340,14 +2360,6 @@ rcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) 0, true); } - if (IS_DG2_G11(i915) || IS_DG2_G10(i915)) { - /* Wa_22014600077:dg2 */ - wa_mcr_add(wal, GEN10_CACHE_MODE_SS, 0, - _MASKED_BIT_ENABLE(ENABLE_EU_COUNT_FOR_TDL_FLUSH), - 0 /* Wa_14012342262 write-only reg, so skip verification */, - true); - } - if (IS_DG2(i915) || IS_ALDERLAKE_P(i915) || IS_ALDERLAKE_S(i915) || IS_DG1(i915) || IS_ROCKETLAKE(i915) || IS_TIGERLAKE(i915)) { /* @@ -2782,6 +2794,11 @@ xcs_engine_wa_init(struct intel_engine_cs *engine, struct i915_wa_list *wal) RING_SEMA_WAIT_POLL(engine->mmio_base), 1); } + /* Wa_16018031267, Wa_16018063123 */ + if (NEEDS_FASTCOLOR_BLT_WABB(engine)) + wa_masked_field_set(wal, ECOSKPD(engine->mmio_base), + XEHP_BLITTER_SCHEDULING_MODE_MASK, + XEHP_BLITTER_ROUND_ROBIN_MODE); } static void @@ -2915,6 +2932,9 @@ 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_18028616096 */ + wa_mcr_write_or(wal, LSC_CHICKEN_BIT_0_UDW, UGM_FRAGMENT_THRESHOLD_TO_3); } if (IS_DG2_G11(i915)) { @@ -2943,11 +2963,6 @@ general_render_compute_wa_init(struct intel_engine_cs *engine, struct i915_wa_li true); } - if (IS_DG2_G10(i915) || IS_DG2_G12(i915)) { - /* Wa_18028616096 */ - wa_mcr_write_or(wal, LSC_CHICKEN_BIT_0_UDW, UGM_FRAGMENT_THRESHOLD_TO_3); - } - if (IS_XEHPSDV(i915)) { /* Wa_1409954639 */ wa_mcr_masked_en(wal, diff --git a/drivers/gpu/drm/i915/gt/selftest_engine_cs.c b/drivers/gpu/drm/i915/gt/selftest_engine_cs.c index 86cecf7a110540..5ffa5e30f41929 100644 --- a/drivers/gpu/drm/i915/gt/selftest_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/selftest_engine_cs.c @@ -21,20 +21,22 @@ static int cmp_u32(const void *A, const void *B) return *a - *b; } -static void perf_begin(struct intel_gt *gt) +static intel_wakeref_t perf_begin(struct intel_gt *gt) { - intel_gt_pm_get(gt); + intel_wakeref_t wakeref = intel_gt_pm_get(gt); /* Boost gpufreq to max [waitboost] and keep it fixed */ atomic_inc(>->rps.num_waiters); queue_work(gt->i915->unordered_wq, >->rps.work); flush_work(>->rps.work); + + return wakeref; } -static int perf_end(struct intel_gt *gt) +static int perf_end(struct intel_gt *gt, intel_wakeref_t wakeref) { atomic_dec(>->rps.num_waiters); - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); return igt_flush_test(gt->i915); } @@ -133,12 +135,13 @@ static int perf_mi_bb_start(void *arg) struct intel_gt *gt = arg; struct intel_engine_cs *engine; enum intel_engine_id id; + intel_wakeref_t wakeref; int err = 0; if (GRAPHICS_VER(gt->i915) < 4) /* Any CS_TIMESTAMP? */ return 0; - perf_begin(gt); + wakeref = perf_begin(gt); for_each_engine(engine, gt, id) { struct intel_context *ce = engine->kernel_context; struct i915_vma *batch; @@ -207,7 +210,7 @@ out: pr_info("%s: MI_BB_START cycles: %u\n", engine->name, trifilter(cycles)); } - if (perf_end(gt)) + if (perf_end(gt, wakeref)) err = -EIO; return err; @@ -260,12 +263,13 @@ static int perf_mi_noop(void *arg) struct intel_gt *gt = arg; struct intel_engine_cs *engine; enum intel_engine_id id; + intel_wakeref_t wakeref; int err = 0; if (GRAPHICS_VER(gt->i915) < 4) /* Any CS_TIMESTAMP? */ return 0; - perf_begin(gt); + wakeref = perf_begin(gt); for_each_engine(engine, gt, id) { struct intel_context *ce = engine->kernel_context; struct i915_vma *base, *nop; @@ -364,7 +368,7 @@ out: pr_info("%s: 16K MI_NOOP cycles: %u\n", engine->name, trifilter(cycles)); } - if (perf_end(gt)) + if (perf_end(gt, wakeref)) err = -EIO; return err; diff --git a/drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c b/drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c index 273d440a53e3f4..bc441ce7b380d3 100644 --- a/drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c +++ b/drivers/gpu/drm/i915/gt/selftest_engine_heartbeat.c @@ -84,7 +84,7 @@ static struct pulse *pulse_create(void) static void pulse_unlock_wait(struct pulse *p) { - i915_active_unlock_wait(&p->active); + wait_var_event_timeout(&p->active, i915_active_is_idle(&p->active), HZ); } static int __live_idle_pulse(struct intel_engine_cs *engine, diff --git a/drivers/gpu/drm/i915/gt/selftest_gt_pm.c b/drivers/gpu/drm/i915/gt/selftest_gt_pm.c index 0971241707ce83..33351deeea4f0b 100644 --- a/drivers/gpu/drm/i915/gt/selftest_gt_pm.c +++ b/drivers/gpu/drm/i915/gt/selftest_gt_pm.c @@ -81,6 +81,7 @@ static int live_gt_clocks(void *arg) struct intel_gt *gt = arg; struct intel_engine_cs *engine; enum intel_engine_id id; + intel_wakeref_t wakeref; int err = 0; if (!gt->clock_frequency) { /* unknown */ @@ -91,7 +92,7 @@ static int live_gt_clocks(void *arg) if (GRAPHICS_VER(gt->i915) < 4) /* Any CS_TIMESTAMP? */ return 0; - intel_gt_pm_get(gt); + wakeref = intel_gt_pm_get(gt); intel_uncore_forcewake_get(gt->uncore, FORCEWAKE_ALL); for_each_engine(engine, gt, id) { @@ -128,7 +129,7 @@ static int live_gt_clocks(void *arg) } intel_uncore_forcewake_put(gt->uncore, FORCEWAKE_ALL); - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); return err; } diff --git a/drivers/gpu/drm/i915/gt/selftest_lrc.c b/drivers/gpu/drm/i915/gt/selftest_lrc.c index 5f826b6dcf5d6f..e17b8777d21dc9 100644 --- a/drivers/gpu/drm/i915/gt/selftest_lrc.c +++ b/drivers/gpu/drm/i915/gt/selftest_lrc.c @@ -1555,7 +1555,7 @@ static int live_lrc_isolation(void *arg) return err; } -static int indirect_ctx_submit_req(struct intel_context *ce) +static int wabb_ctx_submit_req(struct intel_context *ce) { struct i915_request *rq; int err = 0; @@ -1579,7 +1579,8 @@ static int indirect_ctx_submit_req(struct intel_context *ce) #define CTX_BB_CANARY_INDEX (CTX_BB_CANARY_OFFSET / sizeof(u32)) static u32 * -emit_indirect_ctx_bb_canary(const struct intel_context *ce, u32 *cs) +emit_wabb_ctx_canary(const struct intel_context *ce, + u32 *cs, bool per_ctx) { *cs++ = MI_STORE_REGISTER_MEM_GEN8 | MI_SRM_LRM_GLOBAL_GTT | @@ -1587,26 +1588,43 @@ emit_indirect_ctx_bb_canary(const struct intel_context *ce, u32 *cs) *cs++ = i915_mmio_reg_offset(RING_START(0)); *cs++ = i915_ggtt_offset(ce->state) + context_wa_bb_offset(ce) + - CTX_BB_CANARY_OFFSET; + CTX_BB_CANARY_OFFSET + + (per_ctx ? PAGE_SIZE : 0); *cs++ = 0; return cs; } +static u32 * +emit_indirect_ctx_bb_canary(const struct intel_context *ce, u32 *cs) +{ + return emit_wabb_ctx_canary(ce, cs, false); +} + +static u32 * +emit_per_ctx_bb_canary(const struct intel_context *ce, u32 *cs) +{ + return emit_wabb_ctx_canary(ce, cs, true); +} + static void -indirect_ctx_bb_setup(struct intel_context *ce) +wabb_ctx_setup(struct intel_context *ce, bool per_ctx) { - u32 *cs = context_indirect_bb(ce); + u32 *cs = context_wabb(ce, per_ctx); cs[CTX_BB_CANARY_INDEX] = 0xdeadf00d; - setup_indirect_ctx_bb(ce, ce->engine, emit_indirect_ctx_bb_canary); + if (per_ctx) + setup_per_ctx_bb(ce, ce->engine, emit_per_ctx_bb_canary); + else + setup_indirect_ctx_bb(ce, ce->engine, emit_indirect_ctx_bb_canary); } -static bool check_ring_start(struct intel_context *ce) +static bool check_ring_start(struct intel_context *ce, bool per_ctx) { const u32 * const ctx_bb = (void *)(ce->lrc_reg_state) - - LRC_STATE_OFFSET + context_wa_bb_offset(ce); + LRC_STATE_OFFSET + context_wa_bb_offset(ce) + + (per_ctx ? PAGE_SIZE : 0); if (ctx_bb[CTX_BB_CANARY_INDEX] == ce->lrc_reg_state[CTX_RING_START]) return true; @@ -1618,21 +1636,21 @@ static bool check_ring_start(struct intel_context *ce) return false; } -static int indirect_ctx_bb_check(struct intel_context *ce) +static int wabb_ctx_check(struct intel_context *ce, bool per_ctx) { int err; - err = indirect_ctx_submit_req(ce); + err = wabb_ctx_submit_req(ce); if (err) return err; - if (!check_ring_start(ce)) + if (!check_ring_start(ce, per_ctx)) return -EINVAL; return 0; } -static int __live_lrc_indirect_ctx_bb(struct intel_engine_cs *engine) +static int __lrc_wabb_ctx(struct intel_engine_cs *engine, bool per_ctx) { struct intel_context *a, *b; int err; @@ -1667,14 +1685,14 @@ static int __live_lrc_indirect_ctx_bb(struct intel_engine_cs *engine) * As ring start is restored apriori of starting the indirect ctx bb and * as it will be different for each context, it fits to this purpose. */ - indirect_ctx_bb_setup(a); - indirect_ctx_bb_setup(b); + wabb_ctx_setup(a, per_ctx); + wabb_ctx_setup(b, per_ctx); - err = indirect_ctx_bb_check(a); + err = wabb_ctx_check(a, per_ctx); if (err) goto unpin_b; - err = indirect_ctx_bb_check(b); + err = wabb_ctx_check(b, per_ctx); unpin_b: intel_context_unpin(b); @@ -1688,7 +1706,7 @@ put_a: return err; } -static int live_lrc_indirect_ctx_bb(void *arg) +static int lrc_wabb_ctx(void *arg, bool per_ctx) { struct intel_gt *gt = arg; struct intel_engine_cs *engine; @@ -1697,7 +1715,7 @@ static int live_lrc_indirect_ctx_bb(void *arg) for_each_engine(engine, gt, id) { intel_engine_pm_get(engine); - err = __live_lrc_indirect_ctx_bb(engine); + err = __lrc_wabb_ctx(engine, per_ctx); intel_engine_pm_put(engine); if (igt_flush_test(gt->i915)) @@ -1710,6 +1728,16 @@ static int live_lrc_indirect_ctx_bb(void *arg) return err; } +static int live_lrc_indirect_ctx_bb(void *arg) +{ + return lrc_wabb_ctx(arg, false); +} + +static int live_lrc_per_ctx_bb(void *arg) +{ + return lrc_wabb_ctx(arg, true); +} + static void garbage_reset(struct intel_engine_cs *engine, struct i915_request *rq) { @@ -1947,6 +1975,7 @@ int intel_lrc_live_selftests(struct drm_i915_private *i915) SUBTEST(live_lrc_garbage), SUBTEST(live_pphwsp_runtime), SUBTEST(live_lrc_indirect_ctx_bb), + SUBTEST(live_lrc_per_ctx_bb), }; if (!HAS_LOGICAL_RING_CONTEXTS(i915)) diff --git a/drivers/gpu/drm/i915/gt/selftest_reset.c b/drivers/gpu/drm/i915/gt/selftest_reset.c index 79aa6ac66ad2f7..f40de408cd3a98 100644 --- a/drivers/gpu/drm/i915/gt/selftest_reset.c +++ b/drivers/gpu/drm/i915/gt/selftest_reset.c @@ -261,11 +261,12 @@ static int igt_atomic_reset(void *arg) { struct intel_gt *gt = arg; const typeof(*igt_atomic_phases) *p; + intel_wakeref_t wakeref; int err = 0; /* Check that the resets are usable from atomic context */ - intel_gt_pm_get(gt); + wakeref = intel_gt_pm_get(gt); igt_global_reset_lock(gt); /* Flush any requests before we get started and check basics */ @@ -296,7 +297,7 @@ static int igt_atomic_reset(void *arg) unlock: igt_global_reset_unlock(gt); - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); return err; } @@ -307,6 +308,7 @@ static int igt_atomic_engine_reset(void *arg) const typeof(*igt_atomic_phases) *p; struct intel_engine_cs *engine; enum intel_engine_id id; + intel_wakeref_t wakeref; int err = 0; /* Check that the resets are usable from atomic context */ @@ -317,7 +319,7 @@ static int igt_atomic_engine_reset(void *arg) if (intel_uc_uses_guc_submission(>->uc)) return 0; - intel_gt_pm_get(gt); + wakeref = intel_gt_pm_get(gt); igt_global_reset_lock(gt); /* Flush any requests before we get started and check basics */ @@ -365,7 +367,7 @@ static int igt_atomic_engine_reset(void *arg) out_unlock: igt_global_reset_unlock(gt); - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); return err; } diff --git a/drivers/gpu/drm/i915/gt/selftest_rps.c b/drivers/gpu/drm/i915/gt/selftest_rps.c index fb30f733b03665..dcef8d49891972 100644 --- a/drivers/gpu/drm/i915/gt/selftest_rps.c +++ b/drivers/gpu/drm/i915/gt/selftest_rps.c @@ -224,6 +224,7 @@ int live_rps_clock_interval(void *arg) struct intel_engine_cs *engine; enum intel_engine_id id; struct igt_spinner spin; + intel_wakeref_t wakeref; int err = 0; if (!intel_rps_is_enabled(rps) || GRAPHICS_VER(gt->i915) < 6) @@ -236,7 +237,7 @@ int live_rps_clock_interval(void *arg) saved_work = rps->work.func; rps->work.func = dummy_rps_work; - intel_gt_pm_get(gt); + wakeref = intel_gt_pm_get(gt); intel_rps_disable(>->rps); intel_gt_check_clock_frequency(gt); @@ -355,7 +356,7 @@ int live_rps_clock_interval(void *arg) } intel_rps_enable(>->rps); - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); igt_spinner_fini(&spin); @@ -376,6 +377,7 @@ int live_rps_control(void *arg) struct intel_engine_cs *engine; enum intel_engine_id id; struct igt_spinner spin; + intel_wakeref_t wakeref; int err = 0; /* @@ -398,7 +400,7 @@ int live_rps_control(void *arg) saved_work = rps->work.func; rps->work.func = dummy_rps_work; - intel_gt_pm_get(gt); + wakeref = intel_gt_pm_get(gt); for_each_engine(engine, gt, id) { struct i915_request *rq; ktime_t min_dt, max_dt; @@ -488,7 +490,7 @@ int live_rps_control(void *arg) break; } } - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); igt_spinner_fini(&spin); @@ -1023,6 +1025,7 @@ int live_rps_interrupt(void *arg) struct intel_engine_cs *engine; enum intel_engine_id id; struct igt_spinner spin; + intel_wakeref_t wakeref; u32 pm_events; int err = 0; @@ -1033,9 +1036,9 @@ int live_rps_interrupt(void *arg) if (!intel_rps_has_interrupts(rps) || GRAPHICS_VER(gt->i915) < 6) return 0; - intel_gt_pm_get(gt); - pm_events = rps->pm_events; - intel_gt_pm_put(gt); + pm_events = 0; + with_intel_gt_pm(gt, wakeref) + pm_events = rps->pm_events; if (!pm_events) { pr_err("No RPS PM events registered, but RPS is enabled?\n"); return -ENODEV; diff --git a/drivers/gpu/drm/i915/gt/selftest_slpc.c b/drivers/gpu/drm/i915/gt/selftest_slpc.c index 952c8d52d68a2c..302d0540295d7c 100644 --- a/drivers/gpu/drm/i915/gt/selftest_slpc.c +++ b/drivers/gpu/drm/i915/gt/selftest_slpc.c @@ -266,6 +266,7 @@ static int run_test(struct intel_gt *gt, int test_type) struct intel_rps *rps = >->rps; struct intel_engine_cs *engine; enum intel_engine_id id; + intel_wakeref_t wakeref; struct igt_spinner spin; u32 slpc_min_freq, slpc_max_freq; int err = 0; @@ -311,7 +312,7 @@ static int run_test(struct intel_gt *gt, int test_type) } intel_gt_pm_wait_for_idle(gt); - intel_gt_pm_get(gt); + wakeref = intel_gt_pm_get(gt); for_each_engine(engine, gt, id) { struct i915_request *rq; u32 max_act_freq; @@ -397,7 +398,7 @@ static int run_test(struct intel_gt *gt, int test_type) if (igt_flush_test(gt->i915)) err = -EIO; - intel_gt_pm_put(gt); + intel_gt_pm_put(gt, wakeref); igt_spinner_fini(&spin); intel_gt_pm_wait_for_idle(gt); diff --git a/drivers/gpu/drm/i915/gt/uc/intel_gsc_proxy.c b/drivers/gpu/drm/i915/gt/uc/intel_gsc_proxy.c index 5f138de3c14f93..40817ebcca71f7 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_gsc_proxy.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_gsc_proxy.c @@ -322,6 +322,7 @@ static int i915_gsc_proxy_component_bind(struct device *i915_kdev, gsc->proxy.component = data; gsc->proxy.component->mei_dev = mei_kdev; mutex_unlock(&gsc->proxy.mutex); + gt_dbg(gt, "GSC proxy mei component bound\n"); return 0; } @@ -342,6 +343,7 @@ static void i915_gsc_proxy_component_unbind(struct device *i915_kdev, with_intel_runtime_pm(&i915->runtime_pm, wakeref) intel_uncore_rmw(gt->uncore, HECI_H_CSR(MTL_GSC_HECI2_BASE), HECI_H_CSR_IE | HECI_H_CSR_RST, 0); + gt_dbg(gt, "GSC proxy mei component unbound\n"); } static const struct component_ops i915_gsc_proxy_component_ops = { diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.c b/drivers/gpu/drm/i915/gt/uc/intel_guc.c index 3f3df1166b8604..2b450c43bbd7f1 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.c @@ -330,7 +330,7 @@ static u32 guc_ctl_wa_flags(struct intel_guc *guc) static u32 guc_ctl_devid(struct intel_guc *guc) { - struct drm_i915_private *i915 = guc_to_gt(guc)->i915; + struct drm_i915_private *i915 = guc_to_i915(guc); return (INTEL_DEVID(i915) << 16) | INTEL_REVID(i915); } diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.h b/drivers/gpu/drm/i915/gt/uc/intel_guc.h index 2b6dfe62c8f2a7..813cc888e6fae3 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.h @@ -105,61 +105,67 @@ struct intel_guc { */ struct { /** - * @lock: protects everything in submission_state, - * ce->guc_id.id, and ce->guc_id.ref when transitioning in and - * out of zero + * @submission_state.lock: protects everything in + * submission_state, ce->guc_id.id, and ce->guc_id.ref + * when transitioning in and out of zero */ spinlock_t lock; /** - * @guc_ids: used to allocate new guc_ids, single-lrc + * @submission_state.guc_ids: used to allocate new + * guc_ids, single-lrc */ struct ida guc_ids; /** - * @num_guc_ids: Number of guc_ids, selftest feature to be able - * to reduce this number while testing. + * @submission_state.num_guc_ids: Number of guc_ids, selftest + * feature to be able to reduce this number while testing. */ int num_guc_ids; /** - * @guc_ids_bitmap: used to allocate new guc_ids, multi-lrc + * @submission_state.guc_ids_bitmap: used to allocate + * new guc_ids, multi-lrc */ unsigned long *guc_ids_bitmap; /** - * @guc_id_list: list of intel_context with valid guc_ids but no - * refs + * @submission_state.guc_id_list: list of intel_context + * with valid guc_ids but no refs */ struct list_head guc_id_list; /** - * @guc_ids_in_use: Number single-lrc guc_ids in use + * @submission_state.guc_ids_in_use: Number single-lrc + * guc_ids in use */ unsigned int guc_ids_in_use; /** - * @destroyed_contexts: list of contexts waiting to be destroyed - * (deregistered with the GuC) + * @submission_state.destroyed_contexts: list of contexts + * waiting to be destroyed (deregistered with the GuC) */ struct list_head destroyed_contexts; /** - * @destroyed_worker: worker to deregister contexts, need as we - * need to take a GT PM reference and can't from destroy - * function as it might be in an atomic context (no sleeping) + * @submission_state.destroyed_worker: worker to deregister + * contexts, need as we need to take a GT PM reference and + * can't from destroy function as it might be in an atomic + * context (no sleeping) */ struct work_struct destroyed_worker; /** - * @reset_fail_worker: worker to trigger a GT reset after an - * engine reset fails + * @submission_state.reset_fail_worker: worker to trigger + * a GT reset after an engine reset fails */ struct work_struct reset_fail_worker; /** - * @reset_fail_mask: mask of engines that failed to reset + * @submission_state.reset_fail_mask: mask of engines that + * failed to reset */ intel_engine_mask_t reset_fail_mask; /** - * @sched_disable_delay_ms: schedule disable delay, in ms, for - * contexts + * @submission_state.sched_disable_delay_ms: schedule + * disable delay, in ms, for contexts */ unsigned int sched_disable_delay_ms; /** - * @sched_disable_gucid_threshold: threshold of min remaining available - * guc_ids before we start bypassing the schedule disable delay + * @submission_state.sched_disable_gucid_threshold: + * threshold of min remaining available guc_ids before + * we start bypassing the schedule disable delay */ unsigned int sched_disable_gucid_threshold; } submission_state; @@ -243,37 +249,40 @@ struct intel_guc { */ struct { /** - * @lock: Lock protecting the below fields and the engine stats. + * @timestamp.lock: Lock protecting the below fields and + * the engine stats. */ spinlock_t lock; /** - * @gt_stamp: 64 bit extended value of the GT timestamp. + * @timestamp.gt_stamp: 64-bit extended value of the GT + * timestamp. */ u64 gt_stamp; /** - * @ping_delay: Period for polling the GT timestamp for - * overflow. + * @timestamp.ping_delay: Period for polling the GT + * timestamp for overflow. */ unsigned long ping_delay; /** - * @work: Periodic work to adjust GT timestamp, engine and - * context usage for overflows. + * @timestamp.work: Periodic work to adjust GT timestamp, + * engine and context usage for overflows. */ struct delayed_work work; /** - * @shift: Right shift value for the gpm timestamp + * @timestamp.shift: Right shift value for the gpm timestamp */ u32 shift; /** - * @last_stat_jiffies: jiffies at last actual stats collection time - * We use this timestamp to ensure we don't oversample the - * stats because runtime power management events can trigger - * stats collection at much higher rates than required. + * @timestamp.last_stat_jiffies: jiffies at last actual + * stats collection time. We use this timestamp to ensure + * we don't oversample the stats because runtime power + * management events can trigger stats collection at much + * higher rates than required. */ unsigned long last_stat_jiffies; } timestamp; @@ -297,6 +306,10 @@ struct intel_guc { * @number_guc_id_stolen: The number of guc_ids that have been stolen */ int number_guc_id_stolen; + /** + * @fast_response_selftest: Backdoor to CT handler for fast response selftest + */ + u32 fast_response_selftest; #endif }; 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 a4da0208c8838d..a1cd40d8051786 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_capture.c @@ -355,7 +355,7 @@ guc_capture_alloc_steered_lists(struct intel_guc *guc, static const struct __guc_mmio_reg_descr_group * guc_capture_get_device_reglist(struct intel_guc *guc) { - struct drm_i915_private *i915 = guc_to_gt(guc)->i915; + struct drm_i915_private *i915 = guc_to_i915(guc); const struct __guc_mmio_reg_descr_group *lists; if (GRAPHICS_VER(i915) >= 12) 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 89e314b3756bba..0d5197c0824a91 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_ct.c @@ -265,7 +265,7 @@ int intel_guc_ct_init(struct intel_guc_ct *ct) u32 *cmds; int err; - err = i915_inject_probe_error(guc_to_gt(guc)->i915, -ENXIO); + err = i915_inject_probe_error(guc_to_i915(guc), -ENXIO); if (err) return err; @@ -1076,6 +1076,15 @@ static int ct_handle_response(struct intel_guc_ct *ct, struct ct_incoming_msg *r found = true; break; } + +#ifdef CONFIG_DRM_I915_SELFTEST + if (!found && ct_to_guc(ct)->fast_response_selftest) { + CT_DEBUG(ct, "Assuming unsolicited response due to FAST_REQUEST selftest\n"); + ct_to_guc(ct)->fast_response_selftest++; + found = true; + } +#endif + if (!found) { CT_ERROR(ct, "Unsolicited response message: len %u, data %#x (fence %u, last %u)\n", len, hxg[0], fence, ct->requests.last_fence); 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 55bc8b55fbc05a..bf16351c934994 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c @@ -520,7 +520,7 @@ void intel_guc_log_init_early(struct intel_guc_log *log) static int guc_log_relay_create(struct intel_guc_log *log) { struct intel_guc *guc = log_to_guc(log); - struct drm_i915_private *i915 = guc_to_gt(guc)->i915; + struct drm_i915_private *i915 = guc_to_i915(guc); struct rchan *guc_log_relay_chan; size_t n_subbufs, subbuf_size; int ret; @@ -573,7 +573,7 @@ static void guc_log_relay_destroy(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); - struct drm_i915_private *i915 = guc_to_gt(guc)->i915; + struct drm_i915_private *i915 = guc_to_i915(guc); intel_wakeref_t wakeref; _guc_log_copy_debuglogs_for_relay(log); @@ -589,7 +589,7 @@ static void guc_log_copy_debuglogs_for_relay(struct intel_guc_log *log) static u32 __get_default_log_level(struct intel_guc_log *log) { struct intel_guc *guc = log_to_guc(log); - struct drm_i915_private *i915 = guc_to_gt(guc)->i915; + struct drm_i915_private *i915 = guc_to_i915(guc); /* A negative value means "use platform/config default" */ if (i915->params.guc_log_level < 0) { @@ -664,7 +664,7 @@ void intel_guc_log_destroy(struct intel_guc_log *log) int intel_guc_log_set_level(struct intel_guc_log *log, u32 level) { struct intel_guc *guc = log_to_guc(log); - struct drm_i915_private *i915 = guc_to_gt(guc)->i915; + struct drm_i915_private *i915 = guc_to_i915(guc); intel_wakeref_t wakeref; int ret = 0; @@ -796,7 +796,7 @@ void intel_guc_log_relay_flush(struct intel_guc_log *log) static void guc_log_relay_stop(struct intel_guc_log *log) { struct intel_guc *guc = log_to_guc(log); - struct drm_i915_private *i915 = guc_to_gt(guc)->i915; + struct drm_i915_private *i915 = guc_to_i915(guc); if (!log->relay.started) return; diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_rc.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_rc.c index 1adec6de223c75..9df7927304aec0 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_rc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_rc.c @@ -14,7 +14,7 @@ static bool __guc_rc_supported(struct intel_guc *guc) { /* GuC RC is unavailable for pre-Gen12 */ return guc->submission_supported && - GRAPHICS_VER(guc_to_gt(guc)->i915) >= 12; + GRAPHICS_VER(guc_to_i915(guc)) >= 12; } static bool __guc_rc_selected(struct intel_guc *guc) diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c index 2dfb07cc4b33b9..3e681ab6fbf9fb 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c @@ -34,7 +34,7 @@ static bool __detect_slpc_supported(struct intel_guc *guc) { /* GuC SLPC is unavailable for pre-Gen12 */ return guc->submission_supported && - GRAPHICS_VER(guc_to_gt(guc)->i915) >= 12; + GRAPHICS_VER(guc_to_i915(guc)) >= 12; } static bool __guc_slpc_selected(struct intel_guc *guc) 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 17df71117cc70d..a259f1118c5ab1 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -1107,7 +1107,7 @@ static void scrub_guc_desc_for_outstanding_g2h(struct intel_guc *guc) if (deregister) guc_signal_context_fence(ce); if (destroyed) { - intel_gt_pm_put_async(guc_to_gt(guc)); + intel_gt_pm_put_async_untracked(guc_to_gt(guc)); release_guc_id(guc, ce); __guc_context_destroy(ce); } @@ -1303,6 +1303,7 @@ static ktime_t guc_engine_busyness(struct intel_engine_cs *engine, ktime_t *now) unsigned long flags; u32 reset_count; bool in_reset; + intel_wakeref_t wakeref; spin_lock_irqsave(&guc->timestamp.lock, flags); @@ -1325,7 +1326,8 @@ static ktime_t guc_engine_busyness(struct intel_engine_cs *engine, ktime_t *now) * start_gt_clk is derived from GuC state. To get a consistent * view of activity, we query the GuC state only if gt is awake. */ - if (!in_reset && intel_gt_pm_get_if_awake(gt)) { + wakeref = in_reset ? 0 : intel_gt_pm_get_if_awake(gt); + if (wakeref) { stats_saved = *stats; gt_stamp_saved = guc->timestamp.gt_stamp; /* @@ -1334,7 +1336,7 @@ static ktime_t guc_engine_busyness(struct intel_engine_cs *engine, ktime_t *now) */ guc_update_engine_gt_clks(engine); guc_update_pm_timestamp(guc, now); - intel_gt_pm_put_async(gt); + intel_gt_pm_put_async(gt, wakeref); if (i915_reset_count(gpu_error) != reset_count) { *stats = stats_saved; guc->timestamp.gt_stamp = gt_stamp_saved; @@ -3385,9 +3387,9 @@ static void destroyed_worker_func(struct work_struct *w) struct intel_guc *guc = container_of(w, struct intel_guc, submission_state.destroyed_worker); struct intel_gt *gt = guc_to_gt(guc); - int tmp; + intel_wakeref_t wakeref; - with_intel_gt_pm(gt, tmp) + with_intel_gt_pm(gt, wakeref) deregister_destroyed_contexts(guc); } @@ -4624,12 +4626,12 @@ static bool __guc_submission_supported(struct intel_guc *guc) { /* GuC submission is unavailable for pre-Gen11 */ return intel_guc_is_supported(guc) && - GRAPHICS_VER(guc_to_gt(guc)->i915) >= 11; + GRAPHICS_VER(guc_to_i915(guc)) >= 11; } static bool __guc_submission_selected(struct intel_guc *guc) { - struct drm_i915_private *i915 = guc_to_gt(guc)->i915; + struct drm_i915_private *i915 = guc_to_i915(guc); if (!intel_guc_submission_is_supported(guc)) return false; @@ -4894,7 +4896,7 @@ int intel_guc_deregister_done_process_msg(struct intel_guc *guc, intel_context_put(ce); } else if (context_destroyed(ce)) { /* Context has been destroyed */ - intel_gt_pm_put_async(guc_to_gt(guc)); + intel_gt_pm_put_async_untracked(guc_to_gt(guc)); release_guc_id(guc, ce); __guc_context_destroy(ce); } diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc.c b/drivers/gpu/drm/i915/gt/uc/intel_uc.c index 27f6561dd73190..3872d309ed31fa 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_uc.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc.c @@ -106,11 +106,6 @@ static void __confirm_options(struct intel_uc *uc) gt_info(gt, "Incompatible option enable_guc=%d - %s\n", i915->params.enable_guc, "GuC is not supported!"); - if (i915->params.enable_guc & ENABLE_GUC_LOAD_HUC && - !intel_uc_supports_huc(uc)) - gt_info(gt, "Incompatible option enable_guc=%d - %s\n", - i915->params.enable_guc, "HuC is not supported!"); - if (i915->params.enable_guc & ENABLE_GUC_SUBMISSION && !intel_uc_supports_guc_submission(uc)) gt_info(gt, "Incompatible option enable_guc=%d - %s\n", 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 362639162ed603..756093eaf2ad18 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c @@ -1343,16 +1343,13 @@ size_t intel_uc_fw_copy_rsa(struct intel_uc_fw *uc_fw, void *dst, u32 max_len) for_each_sgt_page(page, iter, uc_fw->obj->mm.pages) { u32 len = min_t(u32, size, PAGE_SIZE - offset); - void *vaddr; if (idx > 0) { idx--; continue; } - vaddr = kmap_atomic(page); - memcpy(dst, vaddr + offset, len); - kunmap_atomic(vaddr); + memcpy_from_page(dst, page, offset, len); offset = 0; dst += len; diff --git a/drivers/gpu/drm/i915/gt/uc/selftest_guc.c b/drivers/gpu/drm/i915/gt/uc/selftest_guc.c index bfb72143566f6e..c900aac85adba1 100644 --- a/drivers/gpu/drm/i915/gt/uc/selftest_guc.c +++ b/drivers/gpu/drm/i915/gt/uc/selftest_guc.c @@ -286,11 +286,126 @@ err_wakeref: return ret; } +/* + * Send a context schedule H2G message with an invalid context id. + * This should generate a GUC_RESULT_INVALID_CONTEXT response. + */ +static int bad_h2g(struct intel_guc *guc) +{ + u32 action[] = { + INTEL_GUC_ACTION_SCHED_CONTEXT, + 0x12345678, + }; + + return intel_guc_send_nb(guc, action, ARRAY_SIZE(action), 0); +} + +/* + * Set a spinner running to make sure the system is alive and active, + * then send a bad but asynchronous H2G command and wait to see if an + * error response is returned. If no response is received or if the + * spinner dies then the test will fail. + */ +#define FAST_RESPONSE_TIMEOUT_MS 1000 +static int intel_guc_fast_request(void *arg) +{ + struct intel_gt *gt = arg; + struct intel_context *ce; + struct igt_spinner spin; + struct i915_request *rq; + intel_wakeref_t wakeref; + struct intel_engine_cs *engine = intel_selftest_find_any_engine(gt); + bool spinning = false; + int ret = 0; + + if (!engine) + return 0; + + wakeref = intel_runtime_pm_get(gt->uncore->rpm); + + ce = intel_context_create(engine); + if (IS_ERR(ce)) { + ret = PTR_ERR(ce); + gt_err(gt, "Failed to create spinner request: %pe\n", ce); + goto err_pm; + } + + ret = igt_spinner_init(&spin, engine->gt); + if (ret) { + gt_err(gt, "Failed to create spinner: %pe\n", ERR_PTR(ret)); + goto err_pm; + } + spinning = true; + + rq = igt_spinner_create_request(&spin, ce, MI_ARB_CHECK); + intel_context_put(ce); + if (IS_ERR(rq)) { + ret = PTR_ERR(rq); + gt_err(gt, "Failed to create spinner request: %pe\n", rq); + goto err_spin; + } + + ret = request_add_spin(rq, &spin); + if (ret) { + gt_err(gt, "Failed to add Spinner request: %pe\n", ERR_PTR(ret)); + goto err_rq; + } + + gt->uc.guc.fast_response_selftest = 1; + + ret = bad_h2g(>->uc.guc); + if (ret) { + gt_err(gt, "Failed to send H2G: %pe\n", ERR_PTR(ret)); + goto err_rq; + } + + ret = wait_for(gt->uc.guc.fast_response_selftest != 1 || i915_request_completed(rq), + FAST_RESPONSE_TIMEOUT_MS); + if (ret) { + gt_err(gt, "Request wait failed: %pe\n", ERR_PTR(ret)); + goto err_rq; + } + + if (i915_request_completed(rq)) { + gt_err(gt, "Spinner died waiting for fast request error!\n"); + ret = -EIO; + goto err_rq; + } + + if (gt->uc.guc.fast_response_selftest != 2) { + gt_err(gt, "Unexpected fast response count: %d\n", + gt->uc.guc.fast_response_selftest); + goto err_rq; + } + + igt_spinner_end(&spin); + spinning = false; + + ret = intel_selftest_wait_for_rq(rq); + if (ret) { + gt_err(gt, "Request failed to complete: %pe\n", ERR_PTR(ret)); + goto err_rq; + } + +err_rq: + i915_request_put(rq); + +err_spin: + if (spinning) + igt_spinner_end(&spin); + igt_spinner_fini(&spin); + +err_pm: + intel_runtime_pm_put(gt->uncore->rpm, wakeref); + return ret; +} + int intel_guc_live_selftests(struct drm_i915_private *i915) { static const struct i915_subtest tests[] = { SUBTEST(intel_guc_scrub_ctbs), SUBTEST(intel_guc_steal_guc_ids), + SUBTEST(intel_guc_fast_request), }; struct intel_gt *gt = to_gt(i915); diff --git a/drivers/gpu/drm/i915/gt/uc/selftest_guc_hangcheck.c b/drivers/gpu/drm/i915/gt/uc/selftest_guc_hangcheck.c index 34b5d952e2bcba..26fdc392fce6ce 100644 --- a/drivers/gpu/drm/i915/gt/uc/selftest_guc_hangcheck.c +++ b/drivers/gpu/drm/i915/gt/uc/selftest_guc_hangcheck.c @@ -74,7 +74,7 @@ static int intel_hang_guc(void *arg) goto err; } - rq = igt_spinner_create_request(&spin, ce, MI_NOOP); + rq = igt_spinner_create_request(&spin, ce, MI_ARB_CHECK); intel_context_put(ce); if (IS_ERR(rq)) { ret = PTR_ERR(rq); diff --git a/drivers/gpu/drm/i915/gvt/cmd_parser.c b/drivers/gpu/drm/i915/gvt/cmd_parser.c index 05f9348b7a9d8e..d4a3f3e093b0bc 100644 --- a/drivers/gpu/drm/i915/gvt/cmd_parser.c +++ b/drivers/gpu/drm/i915/gvt/cmd_parser.c @@ -3047,7 +3047,7 @@ put_obj: static int combine_wa_ctx(struct intel_shadow_wa_ctx *wa_ctx) { - u32 per_ctx_start[CACHELINE_DWORDS] = {0}; + u32 per_ctx_start[CACHELINE_DWORDS] = {}; unsigned char *bb_start_sva; if (!wa_ctx->per_ctx.valid) diff --git a/drivers/gpu/drm/i915/gvt/fb_decoder.c b/drivers/gpu/drm/i915/gvt/fb_decoder.c index 835c3fde8a202d..313efdabee5729 100644 --- a/drivers/gpu/drm/i915/gvt/fb_decoder.c +++ b/drivers/gpu/drm/i915/gvt/fb_decoder.c @@ -56,7 +56,7 @@ static const struct pixel_format bdw_pixel_formats[] = { {DRM_FORMAT_XBGR8888, 32, "32-bit RGBX (8:8:8:8 MSB-X:B:G:R)"}, /* non-supported format has bpp default to 0 */ - {0, 0, NULL}, + {} }; static const struct pixel_format skl_pixel_formats[] = { @@ -76,7 +76,7 @@ static const struct pixel_format skl_pixel_formats[] = { {DRM_FORMAT_XRGB2101010, 32, "32-bit BGRX (2:10:10:10 MSB-X:R:G:B)"}, /* non-supported format has bpp default to 0 */ - {0, 0, NULL}, + {} }; static int bdw_format_to_drm(int format) @@ -293,7 +293,7 @@ static const struct cursor_mode_format cursor_pixel_formats[] = { {DRM_FORMAT_ARGB8888, 32, 64, 64, "64x64 32bpp ARGB"}, /* non-supported format has bpp default to 0 */ - {0, 0, 0, 0, NULL}, + {} }; static int cursor_mode_to_drm(int mode) diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c index a9f7fa9b90bdad..90f6c1ece57d44 100644 --- a/drivers/gpu/drm/i915/gvt/handlers.c +++ b/drivers/gpu/drm/i915/gvt/handlers.c @@ -538,7 +538,7 @@ static u32 bxt_vgpu_get_dp_bitrate(struct intel_vgpu *vgpu, enum port port) int refclk = vgpu->gvt->gt->i915->display.dpll.ref_clks.nssc; enum dpio_phy phy = DPIO_PHY0; enum dpio_channel ch = DPIO_CH0; - struct dpll clock = {0}; + struct dpll clock = {}; u32 temp; /* Port to PHY mapping is fixed, see bxt_ddi_phy_info{} */ @@ -2576,7 +2576,6 @@ static int init_bdw_mmio_info(struct intel_gvt *gvt) static int init_skl_mmio_info(struct intel_gvt *gvt) { - struct drm_i915_private *dev_priv = gvt->gt->i915; int ret; MMIO_DH(FORCEWAKE_RENDER_GEN9, D_SKL_PLUS, NULL, mul_force_wake_write); diff --git a/drivers/gpu/drm/i915/gvt/interrupt.c b/drivers/gpu/drm/i915/gvt/interrupt.c index de3f5903d1a7a2..c8e7dfc9f79109 100644 --- a/drivers/gpu/drm/i915/gvt/interrupt.c +++ b/drivers/gpu/drm/i915/gvt/interrupt.c @@ -422,7 +422,7 @@ static void init_irq_map(struct intel_gvt_irq *irq) #define MSI_CAP_DATA(offset) (offset + 8) #define MSI_CAP_EN 0x1 -static int inject_virtual_interrupt(struct intel_vgpu *vgpu) +static void inject_virtual_interrupt(struct intel_vgpu *vgpu) { unsigned long offset = vgpu->gvt->device_info.msi_cap_offset; u16 control, data; @@ -434,10 +434,10 @@ static int inject_virtual_interrupt(struct intel_vgpu *vgpu) /* Do not generate MSI if MSIEN is disabled */ if (!(control & MSI_CAP_EN)) - return 0; + return; if (WARN(control & GENMASK(15, 1), "only support one MSI format\n")) - return -EINVAL; + return; trace_inject_msi(vgpu->id, addr, data); @@ -451,10 +451,9 @@ static int inject_virtual_interrupt(struct intel_vgpu *vgpu) * returned and don't inject interrupt into guest. */ if (!test_bit(INTEL_VGPU_STATUS_ATTACHED, vgpu->status)) - return -ESRCH; - if (vgpu->msi_trigger && eventfd_signal(vgpu->msi_trigger, 1) != 1) - return -EFAULT; - return 0; + return; + if (vgpu->msi_trigger) + eventfd_signal(vgpu->msi_trigger); } static void propagate_event(struct intel_gvt_irq *irq, diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index ddf49c2dbb917c..2905df83e180ed 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -1211,11 +1211,11 @@ static u32 *copy_batch(struct drm_i915_gem_object *dst_obj, for (n = offset >> PAGE_SHIFT; remain; n++) { int len = min(remain, PAGE_SIZE - x); - src = kmap_atomic(i915_gem_object_get_page(src_obj, n)); + src = kmap_local_page(i915_gem_object_get_page(src_obj, n)); if (src_needs_clflush) drm_clflush_virt_range(src + x, len); memcpy(ptr, src + x, len); - kunmap_atomic(src); + kunmap_local(src); ptr += len; remain -= len; diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index e9b79c2c37d847..db99c2ef66db84 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -32,6 +32,8 @@ #include +#include "display/intel_display_params.h" + #include "gem/i915_gem_context.h" #include "gt/intel_gt.h" #include "gt/intel_gt_buffer_pool.h" @@ -49,6 +51,7 @@ #include "i915_debugfs.h" #include "i915_debugfs_params.h" #include "i915_driver.h" +#include "i915_gpu_error.h" #include "i915_irq.h" #include "i915_reg.h" #include "i915_scheduler.h" @@ -67,13 +70,13 @@ static int i915_capabilities(struct seq_file *m, void *data) seq_printf(m, "pch: %d\n", INTEL_PCH_TYPE(i915)); intel_device_info_print(INTEL_INFO(i915), RUNTIME_INFO(i915), &p); - intel_display_device_info_print(DISPLAY_INFO(i915), DISPLAY_RUNTIME_INFO(i915), &p); i915_print_iommu_status(i915, &p); intel_gt_info_print(&to_gt(i915)->info, &p); intel_driver_caps_print(&i915->caps, &p); kernel_param_lock(THIS_MODULE); i915_params_dump(&i915->params, &p); + intel_display_params_dump(i915, &p); kernel_param_unlock(THIS_MODULE); return 0; @@ -297,107 +300,6 @@ static int i915_gem_object_info(struct seq_file *m, void *data) return 0; } -#if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) -static ssize_t gpu_state_read(struct file *file, char __user *ubuf, - size_t count, loff_t *pos) -{ - struct i915_gpu_coredump *error; - ssize_t ret; - void *buf; - - error = file->private_data; - if (!error) - return 0; - - /* Bounce buffer required because of kernfs __user API convenience. */ - buf = kmalloc(count, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - ret = i915_gpu_coredump_copy_to_buffer(error, buf, *pos, count); - if (ret <= 0) - goto out; - - if (!copy_to_user(ubuf, buf, ret)) - *pos += ret; - else - ret = -EFAULT; - -out: - kfree(buf); - return ret; -} - -static int gpu_state_release(struct inode *inode, struct file *file) -{ - i915_gpu_coredump_put(file->private_data); - return 0; -} - -static int i915_gpu_info_open(struct inode *inode, struct file *file) -{ - struct drm_i915_private *i915 = inode->i_private; - struct i915_gpu_coredump *gpu; - intel_wakeref_t wakeref; - - gpu = NULL; - with_intel_runtime_pm(&i915->runtime_pm, wakeref) - gpu = i915_gpu_coredump(to_gt(i915), ALL_ENGINES, CORE_DUMP_FLAG_NONE); - - if (IS_ERR(gpu)) - return PTR_ERR(gpu); - - file->private_data = gpu; - return 0; -} - -static const struct file_operations i915_gpu_info_fops = { - .owner = THIS_MODULE, - .open = i915_gpu_info_open, - .read = gpu_state_read, - .llseek = default_llseek, - .release = gpu_state_release, -}; - -static ssize_t -i915_error_state_write(struct file *filp, - const char __user *ubuf, - size_t cnt, - loff_t *ppos) -{ - struct i915_gpu_coredump *error = filp->private_data; - - if (!error) - return 0; - - drm_dbg(&error->i915->drm, "Resetting error state\n"); - i915_reset_error_state(error->i915); - - return cnt; -} - -static int i915_error_state_open(struct inode *inode, struct file *file) -{ - struct i915_gpu_coredump *error; - - error = i915_first_error_state(inode->i_private); - if (IS_ERR(error)) - return PTR_ERR(error); - - file->private_data = error; - return 0; -} - -static const struct file_operations i915_error_state_fops = { - .owner = THIS_MODULE, - .open = i915_error_state_open, - .read = gpu_state_read, - .write = i915_error_state_write, - .llseek = default_llseek, - .release = gpu_state_release, -}; -#endif - static int i915_frequency_info(struct seq_file *m, void *unused) { struct drm_i915_private *i915 = node_to_i915(m->private); @@ -837,10 +739,6 @@ static const struct i915_debugfs_files { {"i915_perf_noa_delay", &i915_perf_noa_delay_fops}, {"i915_wedged", &i915_wedged_fops}, {"i915_gem_drop_caches", &i915_drop_caches_fops}, -#if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) - {"i915_error_state", &i915_error_state_fops}, - {"i915_gpu_info", &i915_gpu_info_fops}, -#endif }; void i915_debugfs_register(struct drm_i915_private *dev_priv) @@ -863,4 +761,6 @@ void i915_debugfs_register(struct drm_i915_private *dev_priv) drm_debugfs_create_files(i915_debugfs_list, ARRAY_SIZE(i915_debugfs_list), minor->debugfs_root, minor); + + i915_gpu_error_debugfs_register(dev_priv); } diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index 802de2c6decb7b..c7d7c3b7ecc638 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -231,16 +231,10 @@ static int i915_driver_early_probe(struct drm_i915_private *dev_priv) spin_lock_init(&dev_priv->irq_lock); spin_lock_init(&dev_priv->gpu_error.lock); - mutex_init(&dev_priv->display.backlight.lock); mutex_init(&dev_priv->sb_lock); cpu_latency_qos_add_request(&dev_priv->sb_qos, PM_QOS_DEFAULT_VALUE); - mutex_init(&dev_priv->display.audio.mutex); - mutex_init(&dev_priv->display.wm.wm_mutex); - mutex_init(&dev_priv->display.pps.mutex); - mutex_init(&dev_priv->display.hdcp.hdcp_mutex); - i915_memcpy_init_early(dev_priv); intel_runtime_pm_init_early(&dev_priv->runtime_pm); @@ -804,7 +798,9 @@ 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_pxp_init(i915); + if (ret != -ENODEV) + drm_dbg(&i915->drm, "pxp init failed with %d\n", ret); ret = intel_display_driver_probe(i915); if (ret) @@ -907,6 +903,8 @@ static void i915_driver_release(struct drm_device *dev) intel_runtime_pm_driver_release(rpm); i915_driver_late_release(dev_priv); + + intel_display_device_remove(dev_priv); } static int i915_driver_open(struct drm_device *dev, struct drm_file *file) @@ -1037,7 +1035,7 @@ void i915_driver_shutdown(struct drm_i915_private *i915) intel_power_domains_driver_remove(i915); enable_rpm_wakeref_asserts(&i915->runtime_pm); - intel_runtime_pm_driver_release(&i915->runtime_pm); + intel_runtime_pm_driver_last_release(&i915->runtime_pm); } static bool suspend_to_idle(struct drm_i915_private *dev_priv) diff --git a/drivers/gpu/drm/i915/i915_drm_client.c b/drivers/gpu/drm/i915/i915_drm_client.c index 2a44b3876cb510..fa6852713beede 100644 --- a/drivers/gpu/drm/i915/i915_drm_client.c +++ b/drivers/gpu/drm/i915/i915_drm_client.c @@ -28,6 +28,10 @@ struct i915_drm_client *i915_drm_client_alloc(void) kref_init(&client->kref); spin_lock_init(&client->ctx_lock); INIT_LIST_HEAD(&client->ctx_list); +#ifdef CONFIG_PROC_FS + spin_lock_init(&client->objects_lock); + INIT_LIST_HEAD(&client->objects_list); +#endif return client; } @@ -41,6 +45,68 @@ void __i915_drm_client_free(struct kref *kref) } #ifdef CONFIG_PROC_FS +static void +obj_meminfo(struct drm_i915_gem_object *obj, + struct drm_memory_stats stats[INTEL_REGION_UNKNOWN]) +{ + const enum intel_region_id id = obj->mm.region ? + obj->mm.region->id : INTEL_REGION_SMEM; + const u64 sz = obj->base.size; + + if (obj->base.handle_count > 1) + stats[id].shared += sz; + else + stats[id].private += sz; + + if (i915_gem_object_has_pages(obj)) { + stats[id].resident += sz; + + if (!dma_resv_test_signaled(obj->base.resv, + DMA_RESV_USAGE_BOOKKEEP)) + stats[id].active += sz; + else if (i915_gem_object_is_shrinkable(obj) && + obj->mm.madv == I915_MADV_DONTNEED) + stats[id].purgeable += sz; + } +} + +static void show_meminfo(struct drm_printer *p, struct drm_file *file) +{ + struct drm_memory_stats stats[INTEL_REGION_UNKNOWN] = {}; + struct drm_i915_file_private *fpriv = file->driver_priv; + struct i915_drm_client *client = fpriv->client; + struct drm_i915_private *i915 = fpriv->i915; + struct drm_i915_gem_object *obj; + struct intel_memory_region *mr; + struct list_head __rcu *pos; + unsigned int id; + + /* Public objects. */ + spin_lock(&file->table_lock); + idr_for_each_entry(&file->object_idr, obj, id) + obj_meminfo(obj, stats); + spin_unlock(&file->table_lock); + + /* Internal objects. */ + rcu_read_lock(); + list_for_each_rcu(pos, &client->objects_list) { + obj = i915_gem_object_get_rcu(list_entry(pos, typeof(*obj), + client_link)); + if (!obj) + continue; + obj_meminfo(obj, stats); + i915_gem_object_put(obj); + } + rcu_read_unlock(); + + for_each_memory_region(mr, i915, id) + drm_print_memory_stats(p, + &stats[id], + DRM_GEM_OBJECT_RESIDENT | + DRM_GEM_OBJECT_PURGEABLE, + mr->uabi_name); +} + static const char * const uabi_class_names[] = { [I915_ENGINE_CLASS_RENDER] = "render", [I915_ENGINE_CLASS_COPY] = "copy", @@ -102,10 +168,52 @@ void i915_drm_client_fdinfo(struct drm_printer *p, struct drm_file *file) * ****************************************************************** */ + show_meminfo(p, file); + if (GRAPHICS_VER(i915) < 8) return; for (i = 0; i < ARRAY_SIZE(uabi_class_names); i++) show_client_class(p, i915, file_priv->client, i); } + +void i915_drm_client_add_object(struct i915_drm_client *client, + struct drm_i915_gem_object *obj) +{ + unsigned long flags; + + GEM_WARN_ON(obj->client); + GEM_WARN_ON(!list_empty(&obj->client_link)); + + spin_lock_irqsave(&client->objects_lock, flags); + obj->client = i915_drm_client_get(client); + list_add_tail_rcu(&obj->client_link, &client->objects_list); + spin_unlock_irqrestore(&client->objects_lock, flags); +} + +void i915_drm_client_remove_object(struct drm_i915_gem_object *obj) +{ + struct i915_drm_client *client = fetch_and_zero(&obj->client); + unsigned long flags; + + /* Object may not be associated with a client. */ + if (!client) + return; + + spin_lock_irqsave(&client->objects_lock, flags); + list_del_rcu(&obj->client_link); + spin_unlock_irqrestore(&client->objects_lock, flags); + + i915_drm_client_put(client); +} + +void i915_drm_client_add_context_objects(struct i915_drm_client *client, + struct intel_context *ce) +{ + if (ce->state) + i915_drm_client_add_object(client, ce->state->obj); + + if (ce->ring != ce->engine->legacy.ring && ce->ring->vma) + i915_drm_client_add_object(client, ce->ring->vma->obj); +} #endif diff --git a/drivers/gpu/drm/i915/i915_drm_client.h b/drivers/gpu/drm/i915/i915_drm_client.h index 67816c912bca13..a439dd78993660 100644 --- a/drivers/gpu/drm/i915/i915_drm_client.h +++ b/drivers/gpu/drm/i915/i915_drm_client.h @@ -12,6 +12,10 @@ #include +#include "i915_file_private.h" +#include "gem/i915_gem_object_types.h" +#include "gt/intel_context_types.h" + #define I915_LAST_UABI_ENGINE_CLASS I915_ENGINE_CLASS_COMPUTE struct drm_file; @@ -25,6 +29,20 @@ struct i915_drm_client { spinlock_t ctx_lock; /* For add/remove from ctx_list. */ struct list_head ctx_list; /* List of contexts belonging to client. */ +#ifdef CONFIG_PROC_FS + /** + * @objects_lock: lock protecting @objects_list + */ + spinlock_t objects_lock; + + /** + * @objects_list: list of objects created by this client + * + * Protected by @objects_lock. + */ + struct list_head objects_list; +#endif + /** * @past_runtime: Accumulation of pphwsp runtimes from closed contexts. */ @@ -49,4 +67,28 @@ struct i915_drm_client *i915_drm_client_alloc(void); void i915_drm_client_fdinfo(struct drm_printer *p, struct drm_file *file); +#ifdef CONFIG_PROC_FS +void i915_drm_client_add_object(struct i915_drm_client *client, + struct drm_i915_gem_object *obj); +void i915_drm_client_remove_object(struct drm_i915_gem_object *obj); +void i915_drm_client_add_context_objects(struct i915_drm_client *client, + struct intel_context *ce); +#else +static inline void i915_drm_client_add_object(struct i915_drm_client *client, + struct drm_i915_gem_object *obj) +{ +} + +static inline void +i915_drm_client_remove_object(struct drm_i915_gem_object *obj) +{ +} + +static inline void +i915_drm_client_add_context_objects(struct i915_drm_client *client, + struct intel_context *ce) +{ +} +#endif + #endif /* !__I915_DRM_CLIENT_H__ */ diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index dd452c220df72e..861567362abd10 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -396,20 +396,6 @@ static inline struct intel_gt *to_gt(const struct drm_i915_private *i915) return i915->gt[0]; } -/* Simple iterator over all initialised engines */ -#define for_each_engine(engine__, gt__, id__) \ - for ((id__) = 0; \ - (id__) < I915_NUM_ENGINES; \ - (id__)++) \ - for_each_if ((engine__) = (gt__)->engine[(id__)]) - -/* Iterator over subset of engines selected by mask */ -#define for_each_engine_masked(engine__, gt__, mask__, tmp__) \ - for ((tmp__) = (mask__) & (gt__)->info.engine_mask; \ - (tmp__) ? \ - ((engine__) = (gt__)->engine[__mask_next_bit(tmp__)]), 1 : \ - 0;) - #define rb_to_uabi_engine(rb) \ rb_entry_safe(rb, struct intel_engine_cs, uabi_node) @@ -418,11 +404,6 @@ static inline struct intel_gt *to_gt(const struct drm_i915_private *i915) (engine__); \ (engine__) = rb_to_uabi_engine(rb_next(&(engine__)->uabi_node))) -#define for_each_uabi_class_engine(engine__, class__, i915__) \ - for ((engine__) = intel_engine_lookup_user((i915__), (class__), 0); \ - (engine__) && (engine__)->uabi_class == (class__); \ - (engine__) = rb_to_uabi_engine(rb_next(&(engine__)->uabi_node))) - #define INTEL_INFO(i915) ((i915)->__info) #define RUNTIME_INFO(i915) (&(i915)->__runtime) #define DRIVER_CAPS(i915) (&(i915)->caps) @@ -575,6 +556,7 @@ IS_SUBPLATFORM(const struct drm_i915_private *i915, #define IS_DG2(i915) IS_PLATFORM(i915, INTEL_DG2) #define IS_PONTEVECCHIO(i915) IS_PLATFORM(i915, INTEL_PONTEVECCHIO) #define IS_METEORLAKE(i915) IS_PLATFORM(i915, INTEL_METEORLAKE) +#define IS_LUNARLAKE(i915) 0 #define IS_DG2_G10(i915) \ IS_SUBPLATFORM(i915, INTEL_DG2, INTEL_SUBPLATFORM_G10) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c166ad5e187a37..92758b6b41f011 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1306,8 +1306,6 @@ void i915_gem_init_early(struct drm_i915_private *dev_priv) { i915_gem_init__mm(dev_priv); i915_gem_init__contexts(dev_priv); - - spin_lock_init(&dev_priv->display.fb_tracking.lock); } void i915_gem_cleanup_early(struct drm_i915_private *dev_priv) diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index b4e31e59c79916..d04660b6004637 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -57,6 +57,7 @@ #include "i915_memcpy.h" #include "i915_reg.h" #include "i915_scatterlist.h" +#include "i915_sysfs.h" #include "i915_utils.h" #define ALLOW_FAIL (__GFP_KSWAPD_RECLAIM | __GFP_RETRY_MAYFAIL | __GFP_NOWARN) @@ -520,7 +521,7 @@ __find_vma(struct i915_vma_coredump *vma, const char *name) return NULL; } -struct i915_vma_coredump * +static struct i915_vma_coredump * intel_gpu_error_find_batch(const struct intel_engine_coredump *ee) { return __find_vma(ee->vma, "batch"); @@ -609,9 +610,9 @@ void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...) va_end(args); } -void intel_gpu_error_print_vma(struct drm_i915_error_state_buf *m, - const struct intel_engine_cs *engine, - const struct i915_vma_coredump *vma) +static void intel_gpu_error_print_vma(struct drm_i915_error_state_buf *m, + const struct intel_engine_cs *engine, + const struct i915_vma_coredump *vma) { char out[ASCII85_BUFSZ]; struct page *page; @@ -660,6 +661,7 @@ static void err_print_params(struct drm_i915_error_state_buf *m, struct drm_printer p = i915_error_printer(m); i915_params_dump(params, &p); + intel_display_params_dump(m->i915, &p); } static void err_print_pciid(struct drm_i915_error_state_buf *m, @@ -1027,6 +1029,7 @@ static void i915_vma_coredump_free(struct i915_vma_coredump *vma) static void cleanup_params(struct i915_gpu_coredump *error) { i915_params_free(&error->params); + intel_display_params_free(&error->display_params); } static void cleanup_uc(struct intel_uc_coredump *uc) @@ -1988,6 +1991,7 @@ static void capture_gen(struct i915_gpu_coredump *error) error->suspend_count = i915->suspend_count; i915_params_copy(&error->params, &i915->params); + intel_display_params_copy(&error->display_params); memcpy(&error->device_info, INTEL_INFO(i915), sizeof(error->device_info)); @@ -2137,7 +2141,7 @@ __i915_gpu_coredump(struct intel_gt *gt, intel_engine_mask_t engine_mask, u32 du return error; } -struct i915_gpu_coredump * +static struct i915_gpu_coredump * i915_gpu_coredump(struct intel_gt *gt, intel_engine_mask_t engine_mask, u32 dump_flags) { static DEFINE_MUTEX(capture_mutex); @@ -2174,7 +2178,7 @@ void i915_error_state_store(struct i915_gpu_coredump *error) ktime_get_real_seconds() - DRIVER_TIMESTAMP < DAY_AS_SECONDS(180)) { pr_info("GPU hangs can indicate a bug anywhere in the entire gfx stack, including userspace.\n"); pr_info("Please file a _new_ bug report at https://gitlab.freedesktop.org/drm/intel/issues/new.\n"); - pr_info("Please see https://gitlab.freedesktop.org/drm/intel/-/wikis/How-to-file-i915-bugs for details.\n"); + pr_info("Please see https://drm.pages.freedesktop.org/intel-docs/how-to-file-i915-bugs.html for details.\n"); pr_info("drm/i915 developers can then reassign to the right component if it's not a kernel issue.\n"); pr_info("The GPU crash dump is required to analyze GPU hangs, so please always attach it.\n"); pr_info("GPU crash dump saved to /sys/class/drm/card%d/error\n", @@ -2208,7 +2212,7 @@ void i915_capture_error_state(struct intel_gt *gt, i915_gpu_coredump_put(error); } -struct i915_gpu_coredump * +static struct i915_gpu_coredump * i915_first_error_state(struct drm_i915_private *i915) { struct i915_gpu_coredump *error; @@ -2375,3 +2379,184 @@ void intel_klog_error_capture(struct intel_gt *gt, drm_info(&i915->drm, "[Capture/%d.%d] Dumped %zd bytes\n", l_count, line++, pos_err); } #endif + +static ssize_t gpu_state_read(struct file *file, char __user *ubuf, + size_t count, loff_t *pos) +{ + struct i915_gpu_coredump *error; + ssize_t ret; + void *buf; + + error = file->private_data; + if (!error) + return 0; + + /* Bounce buffer required because of kernfs __user API convenience. */ + buf = kmalloc(count, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret = i915_gpu_coredump_copy_to_buffer(error, buf, *pos, count); + if (ret <= 0) + goto out; + + if (!copy_to_user(ubuf, buf, ret)) + *pos += ret; + else + ret = -EFAULT; + +out: + kfree(buf); + return ret; +} + +static int gpu_state_release(struct inode *inode, struct file *file) +{ + i915_gpu_coredump_put(file->private_data); + return 0; +} + +static int i915_gpu_info_open(struct inode *inode, struct file *file) +{ + struct drm_i915_private *i915 = inode->i_private; + struct i915_gpu_coredump *gpu; + intel_wakeref_t wakeref; + + gpu = NULL; + with_intel_runtime_pm(&i915->runtime_pm, wakeref) + gpu = i915_gpu_coredump(to_gt(i915), ALL_ENGINES, CORE_DUMP_FLAG_NONE); + + if (IS_ERR(gpu)) + return PTR_ERR(gpu); + + file->private_data = gpu; + return 0; +} + +static const struct file_operations i915_gpu_info_fops = { + .owner = THIS_MODULE, + .open = i915_gpu_info_open, + .read = gpu_state_read, + .llseek = default_llseek, + .release = gpu_state_release, +}; + +static ssize_t +i915_error_state_write(struct file *filp, + const char __user *ubuf, + size_t cnt, + loff_t *ppos) +{ + struct i915_gpu_coredump *error = filp->private_data; + + if (!error) + return 0; + + drm_dbg(&error->i915->drm, "Resetting error state\n"); + i915_reset_error_state(error->i915); + + return cnt; +} + +static int i915_error_state_open(struct inode *inode, struct file *file) +{ + struct i915_gpu_coredump *error; + + error = i915_first_error_state(inode->i_private); + if (IS_ERR(error)) + return PTR_ERR(error); + + file->private_data = error; + return 0; +} + +static const struct file_operations i915_error_state_fops = { + .owner = THIS_MODULE, + .open = i915_error_state_open, + .read = gpu_state_read, + .write = i915_error_state_write, + .llseek = default_llseek, + .release = gpu_state_release, +}; + +void i915_gpu_error_debugfs_register(struct drm_i915_private *i915) +{ + struct drm_minor *minor = i915->drm.primary; + + debugfs_create_file("i915_error_state", 0644, minor->debugfs_root, i915, + &i915_error_state_fops); + debugfs_create_file("i915_gpu_info", 0644, minor->debugfs_root, i915, + &i915_gpu_info_fops); +} + +static ssize_t error_state_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t off, size_t count) +{ + + struct device *kdev = kobj_to_dev(kobj); + struct drm_i915_private *i915 = kdev_minor_to_i915(kdev); + struct i915_gpu_coredump *gpu; + ssize_t ret = 0; + + /* + * FIXME: Concurrent clients triggering resets and reading + clearing + * dumps can cause inconsistent sysfs reads when a user calls in with a + * non-zero offset to complete a prior partial read but the + * gpu_coredump has been cleared or replaced. + */ + + gpu = i915_first_error_state(i915); + if (IS_ERR(gpu)) { + ret = PTR_ERR(gpu); + } else if (gpu) { + ret = i915_gpu_coredump_copy_to_buffer(gpu, buf, off, count); + i915_gpu_coredump_put(gpu); + } else { + const char *str = "No error state collected\n"; + size_t len = strlen(str); + + if (off < len) { + ret = min_t(size_t, count, len - off); + memcpy(buf, str + off, ret); + } + } + + return ret; +} + +static ssize_t error_state_write(struct file *file, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t off, size_t count) +{ + struct device *kdev = kobj_to_dev(kobj); + struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev); + + drm_dbg(&dev_priv->drm, "Resetting error state\n"); + i915_reset_error_state(dev_priv); + + return count; +} + +static const struct bin_attribute error_state_attr = { + .attr.name = "error", + .attr.mode = S_IRUSR | S_IWUSR, + .size = 0, + .read = error_state_read, + .write = error_state_write, +}; + +void i915_gpu_error_sysfs_setup(struct drm_i915_private *i915) +{ + struct device *kdev = i915->drm.primary->kdev; + + if (sysfs_create_bin_file(&kdev->kobj, &error_state_attr)) + drm_err(&i915->drm, "error_state sysfs setup failed\n"); +} + +void i915_gpu_error_sysfs_teardown(struct drm_i915_private *i915) +{ + struct device *kdev = i915->drm.primary->kdev; + + sysfs_remove_bin_file(&kdev->kobj, &error_state_attr); +} diff --git a/drivers/gpu/drm/i915/i915_gpu_error.h b/drivers/gpu/drm/i915/i915_gpu_error.h index 48f6c00402c47a..7c255bb1c3190d 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.h +++ b/drivers/gpu/drm/i915/i915_gpu_error.h @@ -15,6 +15,7 @@ #include #include "display/intel_display_device.h" +#include "display/intel_display_params.h" #include "gt/intel_engine.h" #include "gt/intel_engine_types.h" #include "gt/intel_gt_types.h" @@ -215,6 +216,7 @@ struct i915_gpu_coredump { struct intel_display_runtime_info display_runtime_info; struct intel_driver_caps driver_caps; struct i915_params params; + struct intel_display_params display_params; struct intel_overlay_error_state *overlay; @@ -283,14 +285,7 @@ static inline void intel_klog_error_capture(struct intel_gt *gt, __printf(2, 3) void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...); -void intel_gpu_error_print_vma(struct drm_i915_error_state_buf *m, - const struct intel_engine_cs *engine, - const struct i915_vma_coredump *vma); -struct i915_vma_coredump * -intel_gpu_error_find_batch(const struct intel_engine_coredump *ee); - -struct i915_gpu_coredump *i915_gpu_coredump(struct intel_gt *gt, - intel_engine_mask_t engine_mask, u32 dump_flags); + void i915_capture_error_state(struct intel_gt *gt, intel_engine_mask_t engine_mask, u32 dump_flags); @@ -338,10 +333,13 @@ static inline void i915_gpu_coredump_put(struct i915_gpu_coredump *gpu) kref_put(&gpu->ref, __i915_gpu_coredump_free); } -struct i915_gpu_coredump *i915_first_error_state(struct drm_i915_private *i915); void i915_reset_error_state(struct drm_i915_private *i915); void i915_disable_error_state(struct drm_i915_private *i915, int err); +void i915_gpu_error_debugfs_register(struct drm_i915_private *i915); +void i915_gpu_error_sysfs_setup(struct drm_i915_private *i915); +void i915_gpu_error_sysfs_teardown(struct drm_i915_private *i915); + #else __printf(2, 3) @@ -409,12 +407,6 @@ static inline void i915_gpu_coredump_put(struct i915_gpu_coredump *gpu) { } -static inline struct i915_gpu_coredump * -i915_first_error_state(struct drm_i915_private *i915) -{ - return ERR_PTR(-ENODEV); -} - static inline void i915_reset_error_state(struct drm_i915_private *i915) { } @@ -424,6 +416,18 @@ static inline void i915_disable_error_state(struct drm_i915_private *i915, { } +static inline void i915_gpu_error_debugfs_register(struct drm_i915_private *i915) +{ +} + +static inline void i915_gpu_error_sysfs_setup(struct drm_i915_private *i915) +{ +} + +static inline void i915_gpu_error_sysfs_teardown(struct drm_i915_private *i915) +{ +} + #endif /* IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) */ #endif /* _I915_GPU_ERROR_H_ */ diff --git a/drivers/gpu/drm/i915/i915_memcpy.c b/drivers/gpu/drm/i915/i915_memcpy.c index 1b021a4902de34..ba82277254b762 100644 --- a/drivers/gpu/drm/i915/i915_memcpy.c +++ b/drivers/gpu/drm/i915/i915_memcpy.c @@ -23,6 +23,8 @@ */ #include +#include +#include #include #include "i915_memcpy.h" diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 036c4c3ed6ed61..de43048543e8b5 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -67,33 +67,9 @@ i915_param_named(modeset, int, 0400, "Use kernel modesetting [KMS] (0=disable, " "1=on, -1=force vga console preference [default])"); -i915_param_named_unsafe(enable_dc, int, 0400, - "Enable power-saving display C-states. " - "(-1=auto [default]; 0=disable; 1=up to DC5; 2=up to DC6; " - "3=up to DC5 with DC3CO; 4=up to DC6 with DC3CO)"); - -i915_param_named_unsafe(enable_fbc, int, 0400, - "Enable frame buffer compression for power savings " - "(default: -1 (use per-chip default))"); - -i915_param_named_unsafe(lvds_channel_mode, int, 0400, - "Specify LVDS channel mode " - "(0=probe BIOS [default], 1=single-channel, 2=dual-channel)"); - -i915_param_named_unsafe(panel_use_ssc, int, 0400, - "Use Spread Spectrum Clock with panels [LVDS/eDP] " - "(default: auto from VBT)"); - -i915_param_named_unsafe(vbt_sdvo_panel_type, int, 0400, - "Override/Ignore selection of SDVO panel mode in the VBT " - "(-2=ignore, -1=auto [default], index in VBT BIOS table)"); - i915_param_named_unsafe(reset, uint, 0400, "Attempt GPU resets (0=disabled, 1=full gpu reset, 2=engine reset [default])"); -i915_param_named_unsafe(vbt_firmware, charp, 0400, - "Load VBT from specified file under /lib/firmware"); - #if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) i915_param_named(error_capture, bool, 0400, "Record the GPU state following a hang. " @@ -106,55 +82,10 @@ i915_param_named_unsafe(enable_hangcheck, bool, 0400, "WARNING: Disabling this can cause system wide hangs. " "(default: true)"); -i915_param_named_unsafe(enable_psr, int, 0400, - "Enable PSR " - "(0=disabled, 1=enable up to PSR1, 2=enable up to PSR2) " - "Default: -1 (use per-chip default)"); - -i915_param_named(psr_safest_params, bool, 0400, - "Replace PSR VBT parameters by the safest and not optimal ones. This " - "is helpful to detect if PSR issues are related to bad values set in " - " VBT. (0=use VBT parameters, 1=use safest parameters)"); - -i915_param_named_unsafe(enable_psr2_sel_fetch, bool, 0400, - "Enable PSR2 selective fetch " - "(0=disabled, 1=enabled) " - "Default: 0"); - -i915_param_named_unsafe(enable_sagv, bool, 0600, - "Enable system agent voltage/frequency scaling (SAGV) (default: true)"); - i915_param_named_unsafe(force_probe, charp, 0400, "Force probe options for specified supported devices. " "See CONFIG_DRM_I915_FORCE_PROBE for details."); -i915_param_named_unsafe(disable_power_well, int, 0400, - "Disable display power wells when possible " - "(-1=auto [default], 0=power wells always on, 1=power wells disabled when possible)"); - -i915_param_named_unsafe(enable_ips, int, 0400, "Enable IPS (default: true)"); - -i915_param_named_unsafe(enable_dpt, bool, 0400, - "Enable display page table (DPT) (default: true)"); - -i915_param_named_unsafe(load_detect_test, bool, 0400, - "Force-enable the VGA load detect code for testing (default:false). " - "For developers only."); - -i915_param_named_unsafe(force_reset_modeset_test, bool, 0400, - "Force a modeset during gpu reset for testing (default:false). " - "For developers only."); - -i915_param_named_unsafe(invert_brightness, int, 0400, - "Invert backlight brightness " - "(-1 force normal, 0 machine defaults, 1 force inversion), please " - "report PCI device ID, subsystem vendor and subsystem device ID " - "to dri-devel@lists.freedesktop.org, if your machine needs it. " - "It will then be included in an upcoming module version."); - -i915_param_named(disable_display, bool, 0400, - "Disable display (default: false)"); - i915_param_named(memtest, bool, 0400, "Perform a read/write test of all device memory on module load (default: off)"); @@ -162,19 +93,6 @@ i915_param_named(mmio_debug, int, 0400, "Enable the MMIO debug code for the first N failures (default: off). " "This may negatively affect performance."); -/* Special case writable file */ -i915_param_named(verbose_state_checks, bool, 0600, - "Enable verbose logs (ie. WARN_ON()) in case of unexpected hw state conditions."); - -i915_param_named_unsafe(nuclear_pageflip, bool, 0400, - "Force enable atomic functionality on platforms that don't have full support yet."); - -/* WA to get away with the default setting in VBT for early platforms.Will be removed */ -i915_param_named_unsafe(edp_vswing, int, 0400, - "Ignore/Override vswing pre-emph table selection from VBT " - "(0=use value from vbt [default], 1=low power swing(200mV)," - "2=default swing(400mV))"); - i915_param_named_unsafe(enable_guc, int, 0400, "Enable GuC load for GuC submission and/or HuC load. " "Required functionality can be selected using bitmask values. " @@ -196,18 +114,11 @@ i915_param_named_unsafe(dmc_firmware_path, charp, 0400, 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)"); - #if IS_ENABLED(CONFIG_DRM_I915_DEBUG) i915_param_named_unsafe(inject_probe_failure, uint, 0400, "Force an error after a number of failure check points (0:disabled (default), N:force failure at the Nth failure check point)"); #endif -i915_param_named(enable_dpcd_backlight, int, 0400, - "Enable support for DPCD backlight control" - "(-1=use per-VBT LFP backlight type setting [default], 0=disabled, 1=enable, 2=force VESA interface, 3=force Intel interface)"); - #if IS_ENABLED(CONFIG_DRM_I915_GVT) i915_param_named(enable_gvt, bool, 0400, "Enable support for Intel GVT-g graphics virtualization host support(default:false)"); diff --git a/drivers/gpu/drm/i915/i915_params.h b/drivers/gpu/drm/i915/i915_params.h index d5194b039aaba3..1315d7fac850f7 100644 --- a/drivers/gpu/drm/i915/i915_params.h +++ b/drivers/gpu/drm/i915/i915_params.h @@ -46,21 +46,7 @@ struct drm_printer; * debugfs file */ #define I915_PARAMS_FOR_EACH(param) \ - param(char *, vbt_firmware, NULL, 0400) \ param(int, modeset, -1, 0400) \ - param(int, lvds_channel_mode, 0, 0400) \ - param(int, panel_use_ssc, -1, 0600) \ - param(int, vbt_sdvo_panel_type, -1, 0400) \ - param(int, enable_dc, -1, 0400) \ - param(int, enable_fbc, -1, 0600) \ - param(int, enable_psr, -1, 0600) \ - param(bool, enable_dpt, true, 0400) \ - param(bool, psr_safest_params, false, 0400) \ - param(bool, enable_psr2_sel_fetch, true, 0400) \ - param(bool, enable_sagv, true, 0600) \ - param(int, disable_power_well, -1, 0400) \ - param(int, enable_ips, 1, 0600) \ - param(int, invert_brightness, 0, 0600) \ param(int, enable_guc, -1, 0400) \ param(int, guc_log_level, -1, 0400) \ param(char *, guc_firmware_path, NULL, 0400) \ @@ -69,23 +55,15 @@ struct drm_printer; 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) \ param(unsigned int, reset, 3, 0600) \ param(unsigned int, inject_probe_failure, 0, 0) \ - param(int, enable_dpcd_backlight, -1, 0600) \ param(char *, force_probe, CONFIG_DRM_I915_FORCE_PROBE, 0400) \ param(unsigned int, request_timeout_ms, CONFIG_DRM_I915_REQUEST_TIMEOUT, CONFIG_DRM_I915_REQUEST_TIMEOUT ? 0600 : 0) \ param(unsigned int, lmem_size, 0, 0400) \ param(unsigned int, lmem_bar_size, 0, 0400) \ /* leave bools at the end to not create holes */ \ param(bool, enable_hangcheck, true, 0600) \ - param(bool, load_detect_test, false, 0600) \ - param(bool, force_reset_modeset_test, false, 0600) \ param(bool, error_capture, true, IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) ? 0600 : 0) \ - param(bool, disable_display, false, 0400) \ - param(bool, verbose_state_checks, true, 0) \ - param(bool, nuclear_pageflip, false, 0400) \ - param(bool, enable_dp_mst, true, 0600) \ param(bool, enable_gvt, false, IS_ENABLED(CONFIG_DRM_I915_GVT) ? 0400 : 0) #define MEMBER(T, member, ...) T member; diff --git a/drivers/gpu/drm/i915/i915_perf_types.h b/drivers/gpu/drm/i915/i915_perf_types.h index 13b1ae9b96c7fd..46445248d193e6 100644 --- a/drivers/gpu/drm/i915/i915_perf_types.h +++ b/drivers/gpu/drm/i915/i915_perf_types.h @@ -291,7 +291,8 @@ struct i915_perf_stream { int size_exponent; /** - * @ptr_lock: Locks reads and writes to all head/tail state + * @oa_buffer.ptr_lock: Locks reads and writes to all + * head/tail state * * Consider: the head and tail pointer state needs to be read * consistently from a hrtimer callback (atomic context) and @@ -313,7 +314,8 @@ struct i915_perf_stream { spinlock_t ptr_lock; /** - * @head: Although we can always read back the head pointer register, + * @oa_buffer.head: Although we can always read back + * the head pointer register, * we prefer to avoid trusting the HW state, just to avoid any * risk that some hardware condition could * somehow bump the * head pointer unpredictably and cause us to forward the wrong @@ -322,7 +324,8 @@ struct i915_perf_stream { u32 head; /** - * @tail: The last verified tail that can be read by userspace. + * @oa_buffer.tail: The last verified tail that can be + * read by userspace. */ u32 tail; } oa_buffer; diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c index f861863eb7c15a..21eb0c5b320d5f 100644 --- a/drivers/gpu/drm/i915/i915_pmu.c +++ b/drivers/gpu/drm/i915/i915_pmu.c @@ -31,6 +31,16 @@ static cpumask_t i915_pmu_cpumask; static unsigned int i915_pmu_target_cpu = -1; +static struct i915_pmu *event_to_pmu(struct perf_event *event) +{ + return container_of(event->pmu, struct i915_pmu, base); +} + +static struct drm_i915_private *pmu_to_i915(struct i915_pmu *pmu) +{ + return container_of(pmu, struct drm_i915_private, pmu); +} + static u8 engine_config_sample(u64 config) { return config & I915_PMU_SAMPLE_MASK; @@ -141,7 +151,7 @@ static u32 frequency_enabled_mask(void) static bool pmu_needs_timer(struct i915_pmu *pmu) { - struct drm_i915_private *i915 = container_of(pmu, typeof(*i915), pmu); + struct drm_i915_private *i915 = pmu_to_i915(pmu); u32 enable; /* @@ -213,19 +223,19 @@ static u64 get_rc6(struct intel_gt *gt) struct drm_i915_private *i915 = gt->i915; const unsigned int gt_id = gt->info.id; struct i915_pmu *pmu = &i915->pmu; + intel_wakeref_t wakeref; unsigned long flags; - bool awake = false; u64 val; - if (intel_gt_pm_get_if_awake(gt)) { + wakeref = intel_gt_pm_get_if_awake(gt); + if (wakeref) { val = __get_rc6(gt); - intel_gt_pm_put_async(gt); - awake = true; + intel_gt_pm_put_async(gt, wakeref); } spin_lock_irqsave(&pmu->lock, flags); - if (awake) { + if (wakeref) { store_sample(pmu, gt_id, __I915_SAMPLE_RC6, val); } else { /* @@ -251,7 +261,7 @@ static u64 get_rc6(struct intel_gt *gt) static void init_rc6(struct i915_pmu *pmu) { - struct drm_i915_private *i915 = container_of(pmu, typeof(*i915), pmu); + struct drm_i915_private *i915 = pmu_to_i915(pmu); struct intel_gt *gt; unsigned int i; @@ -429,12 +439,14 @@ frequency_sample(struct intel_gt *gt, unsigned int period_ns) const unsigned int gt_id = gt->info.id; struct i915_pmu *pmu = &i915->pmu; struct intel_rps *rps = >->rps; + intel_wakeref_t wakeref; if (!frequency_sampling_enabled(pmu, gt_id)) return; /* Report 0/0 (actual/requested) frequency while parked. */ - if (!intel_gt_pm_get_if_awake(gt)) + wakeref = intel_gt_pm_get_if_awake(gt); + if (!wakeref) return; if (pmu->enable & config_mask(__I915_PMU_ACTUAL_FREQUENCY(gt_id))) { @@ -463,14 +475,13 @@ frequency_sample(struct intel_gt *gt, unsigned int period_ns) period_ns / 1000); } - intel_gt_pm_put_async(gt); + intel_gt_pm_put_async(gt, wakeref); } static enum hrtimer_restart i915_sample(struct hrtimer *hrtimer) { - struct drm_i915_private *i915 = - container_of(hrtimer, struct drm_i915_private, pmu.timer); - struct i915_pmu *pmu = &i915->pmu; + struct i915_pmu *pmu = container_of(hrtimer, struct i915_pmu, timer); + struct drm_i915_private *i915 = pmu_to_i915(pmu); unsigned int period_ns; struct intel_gt *gt; unsigned int i; @@ -505,8 +516,8 @@ static enum hrtimer_restart i915_sample(struct hrtimer *hrtimer) static void i915_pmu_event_destroy(struct perf_event *event) { - struct drm_i915_private *i915 = - container_of(event->pmu, typeof(*i915), pmu.base); + struct i915_pmu *pmu = event_to_pmu(event); + struct drm_i915_private *i915 = pmu_to_i915(pmu); drm_WARN_ON(&i915->drm, event->parent); @@ -572,8 +583,8 @@ config_status(struct drm_i915_private *i915, u64 config) static int engine_event_init(struct perf_event *event) { - struct drm_i915_private *i915 = - container_of(event->pmu, typeof(*i915), pmu.base); + struct i915_pmu *pmu = event_to_pmu(event); + struct drm_i915_private *i915 = pmu_to_i915(pmu); struct intel_engine_cs *engine; engine = intel_engine_lookup_user(i915, engine_event_class(event), @@ -586,9 +597,8 @@ static int engine_event_init(struct perf_event *event) static int i915_pmu_event_init(struct perf_event *event) { - struct drm_i915_private *i915 = - container_of(event->pmu, typeof(*i915), pmu.base); - struct i915_pmu *pmu = &i915->pmu; + struct i915_pmu *pmu = event_to_pmu(event); + struct drm_i915_private *i915 = pmu_to_i915(pmu); int ret; if (pmu->closed) @@ -628,9 +638,8 @@ static int i915_pmu_event_init(struct perf_event *event) static u64 __i915_pmu_event_read(struct perf_event *event) { - struct drm_i915_private *i915 = - container_of(event->pmu, typeof(*i915), pmu.base); - struct i915_pmu *pmu = &i915->pmu; + struct i915_pmu *pmu = event_to_pmu(event); + struct drm_i915_private *i915 = pmu_to_i915(pmu); u64 val = 0; if (is_engine_event(event)) { @@ -686,10 +695,8 @@ static u64 __i915_pmu_event_read(struct perf_event *event) static void i915_pmu_event_read(struct perf_event *event) { - struct drm_i915_private *i915 = - container_of(event->pmu, typeof(*i915), pmu.base); + struct i915_pmu *pmu = event_to_pmu(event); struct hw_perf_event *hwc = &event->hw; - struct i915_pmu *pmu = &i915->pmu; u64 prev, new; if (pmu->closed) { @@ -707,10 +714,9 @@ static void i915_pmu_event_read(struct perf_event *event) static void i915_pmu_enable(struct perf_event *event) { - struct drm_i915_private *i915 = - container_of(event->pmu, typeof(*i915), pmu.base); + struct i915_pmu *pmu = event_to_pmu(event); + struct drm_i915_private *i915 = pmu_to_i915(pmu); const unsigned int bit = event_bit(event); - struct i915_pmu *pmu = &i915->pmu; unsigned long flags; if (bit == -1) @@ -771,10 +777,9 @@ update: static void i915_pmu_disable(struct perf_event *event) { - struct drm_i915_private *i915 = - container_of(event->pmu, typeof(*i915), pmu.base); + struct i915_pmu *pmu = event_to_pmu(event); + struct drm_i915_private *i915 = pmu_to_i915(pmu); const unsigned int bit = event_bit(event); - struct i915_pmu *pmu = &i915->pmu; unsigned long flags; if (bit == -1) @@ -818,9 +823,7 @@ static void i915_pmu_disable(struct perf_event *event) static void i915_pmu_event_start(struct perf_event *event, int flags) { - struct drm_i915_private *i915 = - container_of(event->pmu, typeof(*i915), pmu.base); - struct i915_pmu *pmu = &i915->pmu; + struct i915_pmu *pmu = event_to_pmu(event); if (pmu->closed) return; @@ -848,9 +851,7 @@ out: static int i915_pmu_event_add(struct perf_event *event, int flags) { - struct drm_i915_private *i915 = - container_of(event->pmu, typeof(*i915), pmu.base); - struct i915_pmu *pmu = &i915->pmu; + struct i915_pmu *pmu = event_to_pmu(event); if (pmu->closed) return -ENODEV; @@ -982,7 +983,7 @@ add_pmu_attr(struct perf_pmu_events_attr *attr, const char *name, static struct attribute ** create_event_attributes(struct i915_pmu *pmu) { - struct drm_i915_private *i915 = container_of(pmu, typeof(*i915), pmu); + struct drm_i915_private *i915 = pmu_to_i915(pmu); static const struct { unsigned int counter; const char *name; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 135e8d8dbdf06a..27dc903f0553c0 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -195,8 +195,6 @@ #define DPIO_SFR_BYPASS (1 << 1) #define DPIO_CMNRST (1 << 0) -#define DPIO_PHY(pipe) ((pipe) >> 1) - /* * Per pipe/PLL DPIO regs */ diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index e88bb4f0430502..613decd4776053 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -155,81 +155,6 @@ static const struct bin_attribute dpf_attrs_1 = { .private = (void *)1 }; -#if IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) - -static ssize_t error_state_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, char *buf, - loff_t off, size_t count) -{ - - struct device *kdev = kobj_to_dev(kobj); - struct drm_i915_private *i915 = kdev_minor_to_i915(kdev); - struct i915_gpu_coredump *gpu; - ssize_t ret = 0; - - /* - * FIXME: Concurrent clients triggering resets and reading + clearing - * dumps can cause inconsistent sysfs reads when a user calls in with a - * non-zero offset to complete a prior partial read but the - * gpu_coredump has been cleared or replaced. - */ - - gpu = i915_first_error_state(i915); - if (IS_ERR(gpu)) { - ret = PTR_ERR(gpu); - } else if (gpu) { - ret = i915_gpu_coredump_copy_to_buffer(gpu, buf, off, count); - i915_gpu_coredump_put(gpu); - } else { - const char *str = "No error state collected\n"; - size_t len = strlen(str); - - if (off < len) { - ret = min_t(size_t, count, len - off); - memcpy(buf, str + off, ret); - } - } - - return ret; -} - -static ssize_t error_state_write(struct file *file, struct kobject *kobj, - struct bin_attribute *attr, char *buf, - loff_t off, size_t count) -{ - struct device *kdev = kobj_to_dev(kobj); - struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev); - - drm_dbg(&dev_priv->drm, "Resetting error state\n"); - i915_reset_error_state(dev_priv); - - return count; -} - -static const struct bin_attribute error_state_attr = { - .attr.name = "error", - .attr.mode = S_IRUSR | S_IWUSR, - .size = 0, - .read = error_state_read, - .write = error_state_write, -}; - -static void i915_setup_error_capture(struct device *kdev) -{ - if (sysfs_create_bin_file(&kdev->kobj, &error_state_attr)) - drm_err(&kdev_minor_to_i915(kdev)->drm, - "error_state sysfs setup failed\n"); -} - -static void i915_teardown_error_capture(struct device *kdev) -{ - sysfs_remove_bin_file(&kdev->kobj, &error_state_attr); -} -#else -static void i915_setup_error_capture(struct device *kdev) {} -static void i915_teardown_error_capture(struct device *kdev) {} -#endif - void i915_setup_sysfs(struct drm_i915_private *dev_priv) { struct device *kdev = dev_priv->drm.primary->kdev; @@ -255,7 +180,7 @@ void i915_setup_sysfs(struct drm_i915_private *dev_priv) drm_warn(&dev_priv->drm, "failed to register GT sysfs directory\n"); - i915_setup_error_capture(kdev); + i915_gpu_error_sysfs_setup(dev_priv); intel_engines_add_sysfs(dev_priv); } @@ -264,7 +189,7 @@ void i915_teardown_sysfs(struct drm_i915_private *dev_priv) { struct device *kdev = dev_priv->drm.primary->kdev; - i915_teardown_error_capture(kdev); + i915_gpu_error_sysfs_teardown(dev_priv); device_remove_bin_file(kdev, &dpf_attrs_1); device_remove_bin_file(kdev, &dpf_attrs); diff --git a/drivers/gpu/drm/i915/i915_utils.h b/drivers/gpu/drm/i915/i915_utils.h index c61066498bf2fb..f98577967b7fc9 100644 --- a/drivers/gpu/drm/i915/i915_utils.h +++ b/drivers/gpu/drm/i915/i915_utils.h @@ -40,7 +40,7 @@ struct drm_i915_private; struct timer_list; -#define FDO_BUG_URL "https://gitlab.freedesktop.org/drm/intel/-/wikis/How-to-file-i915-bugs" +#define FDO_BUG_URL "https://drm.pages.freedesktop.org/intel-docs/how-to-file-i915-bugs.html" #define MISSING_CASE(x) WARN(1, "Missing case (%s == %ld)\n", \ __stringify(x), (long)(x)) diff --git a/drivers/gpu/drm/i915/intel_memory_region.c b/drivers/gpu/drm/i915/intel_memory_region.c index 3d1fdea9811d09..60a03340bbd43f 100644 --- a/drivers/gpu/drm/i915/intel_memory_region.c +++ b/drivers/gpu/drm/i915/intel_memory_region.c @@ -216,6 +216,22 @@ static int intel_memory_region_memtest(struct intel_memory_region *mem, return err; } +static const char *region_type_str(u16 type) +{ + switch (type) { + case INTEL_MEMORY_SYSTEM: + return "system"; + case INTEL_MEMORY_LOCAL: + return "local"; + case INTEL_MEMORY_STOLEN_LOCAL: + return "stolen-local"; + case INTEL_MEMORY_STOLEN_SYSTEM: + return "stolen-system"; + default: + return "unknown"; + } +} + struct intel_memory_region * intel_memory_region_create(struct drm_i915_private *i915, resource_size_t start, @@ -244,6 +260,9 @@ intel_memory_region_create(struct drm_i915_private *i915, mem->type = type; mem->instance = instance; + snprintf(mem->uabi_name, sizeof(mem->uabi_name), "%s%u", + region_type_str(type), instance); + mutex_init(&mem->objects.lock); INIT_LIST_HEAD(&mem->objects.list); diff --git a/drivers/gpu/drm/i915/intel_memory_region.h b/drivers/gpu/drm/i915/intel_memory_region.h index 2953ed5c32486c..9ba36454e51b0a 100644 --- a/drivers/gpu/drm/i915/intel_memory_region.h +++ b/drivers/gpu/drm/i915/intel_memory_region.h @@ -80,6 +80,7 @@ struct intel_memory_region { u16 instance; enum intel_region_id id; char name[16]; + char uabi_name[16]; bool private; /* not for userspace */ struct { diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 8743153fad878f..860b51b56a92be 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -50,184 +50,44 @@ * present for a given platform. */ -#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM) - -#include - -#define STACKDEPTH 8 - -static noinline depot_stack_handle_t __save_depot_stack(void) +static struct drm_i915_private *rpm_to_i915(struct intel_runtime_pm *rpm) { - unsigned long entries[STACKDEPTH]; - unsigned int n; - - n = stack_trace_save(entries, ARRAY_SIZE(entries), 1); - return stack_depot_save(entries, n, GFP_NOWAIT | __GFP_NOWARN); + return container_of(rpm, struct drm_i915_private, runtime_pm); } +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_RUNTIME_PM) + static void init_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm) { - spin_lock_init(&rpm->debug.lock); - stack_depot_init(); + ref_tracker_dir_init(&rpm->debug, INTEL_REFTRACK_DEAD_COUNT, dev_name(rpm->kdev)); } -static noinline depot_stack_handle_t +static intel_wakeref_t track_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm) { - depot_stack_handle_t stack, *stacks; - unsigned long flags; - - if (rpm->no_wakeref_tracking) + if (!rpm->available || rpm->no_wakeref_tracking) return -1; - stack = __save_depot_stack(); - if (!stack) - return -1; - - spin_lock_irqsave(&rpm->debug.lock, flags); - - if (!rpm->debug.count) - rpm->debug.last_acquire = stack; - - stacks = krealloc(rpm->debug.owners, - (rpm->debug.count + 1) * sizeof(*stacks), - GFP_NOWAIT | __GFP_NOWARN); - if (stacks) { - stacks[rpm->debug.count++] = stack; - rpm->debug.owners = stacks; - } else { - stack = -1; - } - - spin_unlock_irqrestore(&rpm->debug.lock, flags); - - return stack; + return intel_ref_tracker_alloc(&rpm->debug); } static void untrack_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm, - depot_stack_handle_t stack) + intel_wakeref_t wakeref) { - struct drm_i915_private *i915 = container_of(rpm, - struct drm_i915_private, - runtime_pm); - unsigned long flags, n; - bool found = false; - - if (unlikely(stack == -1)) + if (!rpm->available || rpm->no_wakeref_tracking) return; - spin_lock_irqsave(&rpm->debug.lock, flags); - for (n = rpm->debug.count; n--; ) { - if (rpm->debug.owners[n] == stack) { - memmove(rpm->debug.owners + n, - rpm->debug.owners + n + 1, - (--rpm->debug.count - n) * sizeof(stack)); - found = true; - break; - } - } - spin_unlock_irqrestore(&rpm->debug.lock, flags); - - if (drm_WARN(&i915->drm, !found, - "Unmatched wakeref (tracking %lu), count %u\n", - rpm->debug.count, atomic_read(&rpm->wakeref_count))) { - char *buf; - - buf = kmalloc(PAGE_SIZE, GFP_NOWAIT | __GFP_NOWARN); - if (!buf) - return; - - stack_depot_snprint(stack, buf, PAGE_SIZE, 2); - DRM_DEBUG_DRIVER("wakeref %x from\n%s", stack, buf); - - stack = READ_ONCE(rpm->debug.last_release); - if (stack) { - stack_depot_snprint(stack, buf, PAGE_SIZE, 2); - DRM_DEBUG_DRIVER("wakeref last released at\n%s", buf); - } - - kfree(buf); - } + intel_ref_tracker_free(&rpm->debug, wakeref); } -static int cmphandle(const void *_a, const void *_b) +static void untrack_all_intel_runtime_pm_wakerefs(struct intel_runtime_pm *rpm) { - const depot_stack_handle_t * const a = _a, * const b = _b; - - if (*a < *b) - return -1; - else if (*a > *b) - return 1; - else - return 0; -} - -static void -__print_intel_runtime_pm_wakeref(struct drm_printer *p, - const struct intel_runtime_pm_debug *dbg) -{ - unsigned long i; - char *buf; - - buf = kmalloc(PAGE_SIZE, GFP_NOWAIT | __GFP_NOWARN); - if (!buf) - return; - - if (dbg->last_acquire) { - stack_depot_snprint(dbg->last_acquire, buf, PAGE_SIZE, 2); - drm_printf(p, "Wakeref last acquired:\n%s", buf); - } - - if (dbg->last_release) { - stack_depot_snprint(dbg->last_release, buf, PAGE_SIZE, 2); - drm_printf(p, "Wakeref last released:\n%s", buf); - } - - drm_printf(p, "Wakeref count: %lu\n", dbg->count); - - sort(dbg->owners, dbg->count, sizeof(*dbg->owners), cmphandle, NULL); - - for (i = 0; i < dbg->count; i++) { - depot_stack_handle_t stack = dbg->owners[i]; - unsigned long rep; - - rep = 1; - while (i + 1 < dbg->count && dbg->owners[i + 1] == stack) - rep++, i++; - stack_depot_snprint(stack, buf, PAGE_SIZE, 2); - drm_printf(p, "Wakeref x%lu taken at:\n%s", rep, buf); - } - - kfree(buf); -} - -static noinline void -__untrack_all_wakerefs(struct intel_runtime_pm_debug *debug, - struct intel_runtime_pm_debug *saved) -{ - *saved = *debug; - - debug->owners = NULL; - debug->count = 0; - debug->last_release = __save_depot_stack(); -} - -static void -dump_and_free_wakeref_tracking(struct intel_runtime_pm_debug *debug) -{ - if (debug->count) { - struct drm_printer p = drm_debug_printer("i915"); - - __print_intel_runtime_pm_wakeref(&p, debug); - } - - kfree(debug->owners); + ref_tracker_dir_exit(&rpm->debug); } static noinline void __intel_wakeref_dec_and_check_tracking(struct intel_runtime_pm *rpm) { - struct intel_runtime_pm_debug dbg = {}; unsigned long flags; if (!atomic_dec_and_lock_irqsave(&rpm->wakeref_count, @@ -235,60 +95,14 @@ __intel_wakeref_dec_and_check_tracking(struct intel_runtime_pm *rpm) flags)) return; - __untrack_all_wakerefs(&rpm->debug, &dbg); + ref_tracker_dir_print_locked(&rpm->debug, INTEL_REFTRACK_PRINT_LIMIT); spin_unlock_irqrestore(&rpm->debug.lock, flags); - - dump_and_free_wakeref_tracking(&dbg); -} - -static noinline void -untrack_all_intel_runtime_pm_wakerefs(struct intel_runtime_pm *rpm) -{ - struct intel_runtime_pm_debug dbg = {}; - unsigned long flags; - - spin_lock_irqsave(&rpm->debug.lock, flags); - __untrack_all_wakerefs(&rpm->debug, &dbg); - spin_unlock_irqrestore(&rpm->debug.lock, flags); - - dump_and_free_wakeref_tracking(&dbg); } void print_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm, struct drm_printer *p) { - struct intel_runtime_pm_debug dbg = {}; - - do { - unsigned long alloc = dbg.count; - depot_stack_handle_t *s; - - spin_lock_irq(&rpm->debug.lock); - dbg.count = rpm->debug.count; - if (dbg.count <= alloc) { - memcpy(dbg.owners, - rpm->debug.owners, - dbg.count * sizeof(*s)); - } - dbg.last_acquire = rpm->debug.last_acquire; - dbg.last_release = rpm->debug.last_release; - spin_unlock_irq(&rpm->debug.lock); - if (dbg.count <= alloc) - break; - - s = krealloc(dbg.owners, - dbg.count * sizeof(*s), - GFP_NOWAIT | __GFP_NOWARN); - if (!s) - goto out; - - dbg.owners = s; - } while (1); - - __print_intel_runtime_pm_wakeref(p, &dbg); - -out: - kfree(dbg.owners); + intel_ref_tracker_show(&rpm->debug, p); } #else @@ -297,14 +111,14 @@ static void init_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm) { } -static depot_stack_handle_t +static intel_wakeref_t track_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm) { return -1; } static void untrack_intel_runtime_pm_wakeref(struct intel_runtime_pm *rpm, - intel_wakeref_t wref) + intel_wakeref_t wakeref) { } @@ -349,9 +163,7 @@ intel_runtime_pm_release(struct intel_runtime_pm *rpm, int wakelock) static intel_wakeref_t __intel_runtime_pm_get(struct intel_runtime_pm *rpm, bool wakelock) { - struct drm_i915_private *i915 = container_of(rpm, - struct drm_i915_private, - runtime_pm); + struct drm_i915_private *i915 = rpm_to_i915(rpm); int ret; ret = pm_runtime_get_sync(rpm->kdev); @@ -556,9 +368,7 @@ void intel_runtime_pm_put(struct intel_runtime_pm *rpm, intel_wakeref_t wref) */ void intel_runtime_pm_enable(struct intel_runtime_pm *rpm) { - struct drm_i915_private *i915 = container_of(rpm, - struct drm_i915_private, - runtime_pm); + struct drm_i915_private *i915 = rpm_to_i915(rpm); struct device *kdev = rpm->kdev; /* @@ -611,9 +421,7 @@ void intel_runtime_pm_enable(struct intel_runtime_pm *rpm) void intel_runtime_pm_disable(struct intel_runtime_pm *rpm) { - struct drm_i915_private *i915 = container_of(rpm, - struct drm_i915_private, - runtime_pm); + struct drm_i915_private *i915 = rpm_to_i915(rpm); struct device *kdev = rpm->kdev; /* Transfer rpm ownership back to core */ @@ -628,9 +436,7 @@ void intel_runtime_pm_disable(struct intel_runtime_pm *rpm) void intel_runtime_pm_driver_release(struct intel_runtime_pm *rpm) { - struct drm_i915_private *i915 = container_of(rpm, - struct drm_i915_private, - runtime_pm); + struct drm_i915_private *i915 = rpm_to_i915(rpm); int count = atomic_read(&rpm->wakeref_count); intel_wakeref_auto_fini(&rpm->userfault_wakeref); @@ -639,14 +445,17 @@ void intel_runtime_pm_driver_release(struct intel_runtime_pm *rpm) "i915 raw-wakerefs=%d wakelocks=%d on cleanup\n", intel_rpm_raw_wakeref_count(count), intel_rpm_wakelock_count(count)); +} +void intel_runtime_pm_driver_last_release(struct intel_runtime_pm *rpm) +{ + intel_runtime_pm_driver_release(rpm); untrack_all_intel_runtime_pm_wakerefs(rpm); } void intel_runtime_pm_init_early(struct intel_runtime_pm *rpm) { - struct drm_i915_private *i915 = - container_of(rpm, struct drm_i915_private, runtime_pm); + struct drm_i915_private *i915 = rpm_to_i915(rpm); struct pci_dev *pdev = to_pci_dev(i915->drm.dev); struct device *kdev = &pdev->dev; diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.h b/drivers/gpu/drm/i915/intel_runtime_pm.h index f79cda7a2503dc..de3579d399e18d 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.h +++ b/drivers/gpu/drm/i915/intel_runtime_pm.h @@ -11,8 +11,6 @@ #include "intel_wakeref.h" -#include "i915_utils.h" - struct device; struct drm_i915_private; struct drm_printer; @@ -77,15 +75,7 @@ struct intel_runtime_pm { * paired rpm_put) we can remove corresponding pairs of and keep * the array trimmed to active wakerefs. */ - struct intel_runtime_pm_debug { - spinlock_t lock; - - depot_stack_handle_t last_acquire; - depot_stack_handle_t last_release; - - depot_stack_handle_t *owners; - unsigned long count; - } debug; + struct ref_tracker_dir debug; #endif }; @@ -189,6 +179,7 @@ void intel_runtime_pm_init_early(struct intel_runtime_pm *rpm); void intel_runtime_pm_enable(struct intel_runtime_pm *rpm); void intel_runtime_pm_disable(struct intel_runtime_pm *rpm); void intel_runtime_pm_driver_release(struct intel_runtime_pm *rpm); +void intel_runtime_pm_driver_last_release(struct intel_runtime_pm *rpm); intel_wakeref_t intel_runtime_pm_get(struct intel_runtime_pm *rpm); intel_wakeref_t intel_runtime_pm_get_if_in_use(struct intel_runtime_pm *rpm); diff --git a/drivers/gpu/drm/i915/intel_wakeref.c b/drivers/gpu/drm/i915/intel_wakeref.c index 623a690893868d..dea2f63184f893 100644 --- a/drivers/gpu/drm/i915/intel_wakeref.c +++ b/drivers/gpu/drm/i915/intel_wakeref.c @@ -99,7 +99,8 @@ static void __intel_wakeref_put_work(struct work_struct *wrk) void __intel_wakeref_init(struct intel_wakeref *wf, struct drm_i915_private *i915, const struct intel_wakeref_ops *ops, - struct intel_wakeref_lockclass *key) + struct intel_wakeref_lockclass *key, + const char *name) { wf->i915 = i915; wf->ops = ops; @@ -111,6 +112,10 @@ void __intel_wakeref_init(struct intel_wakeref *wf, INIT_DELAYED_WORK(&wf->work, __intel_wakeref_put_work); lockdep_init_map(&wf->work.work.lockdep_map, "wakeref.work", &key->work, 0); + +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_WAKEREF) + ref_tracker_dir_init(&wf->debug, INTEL_REFTRACK_DEAD_COUNT, name); +#endif } int intel_wakeref_wait_for_idle(struct intel_wakeref *wf) @@ -191,3 +196,31 @@ void intel_wakeref_auto_fini(struct intel_wakeref_auto *wf) intel_wakeref_auto(wf, 0); INTEL_WAKEREF_BUG_ON(wf->wakeref); } + +void intel_ref_tracker_show(struct ref_tracker_dir *dir, + struct drm_printer *p) +{ + const size_t buf_size = PAGE_SIZE; + char *buf, *sb, *se; + size_t count; + + buf = kmalloc(buf_size, GFP_NOWAIT); + if (!buf) + return; + + count = ref_tracker_dir_snprint(dir, buf, buf_size); + if (!count) + goto free; + /* printk does not like big buffers, so we split it */ + for (sb = buf; *sb; sb = se + 1) { + se = strchrnul(sb, '\n'); + drm_printf(p, "%.*s", (int)(se - sb + 1), sb); + if (!*se) + break; + } + if (count >= buf_size) + drm_printf(p, "\n...dropped %zd extra bytes of leak report.\n", + count + 1 - buf_size); +free: + kfree(buf); +} diff --git a/drivers/gpu/drm/i915/intel_wakeref.h b/drivers/gpu/drm/i915/intel_wakeref.h index ec881b09736896..68aa3be4825153 100644 --- a/drivers/gpu/drm/i915/intel_wakeref.h +++ b/drivers/gpu/drm/i915/intel_wakeref.h @@ -7,16 +7,25 @@ #ifndef INTEL_WAKEREF_H #define INTEL_WAKEREF_H +#include + #include #include #include #include #include #include +#include +#include #include #include #include +typedef unsigned long intel_wakeref_t; + +#define INTEL_REFTRACK_DEAD_COUNT 16 +#define INTEL_REFTRACK_PRINT_LIMIT 16 + #if IS_ENABLED(CONFIG_DRM_I915_DEBUG) #define INTEL_WAKEREF_BUG_ON(expr) BUG_ON(expr) #else @@ -26,8 +35,6 @@ struct intel_runtime_pm; struct intel_wakeref; -typedef depot_stack_handle_t intel_wakeref_t; - struct intel_wakeref_ops { int (*get)(struct intel_wakeref *wf); int (*put)(struct intel_wakeref *wf); @@ -43,6 +50,10 @@ struct intel_wakeref { const struct intel_wakeref_ops *ops; struct delayed_work work; + +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_WAKEREF) + struct ref_tracker_dir debug; +#endif }; struct intel_wakeref_lockclass { @@ -53,11 +64,12 @@ struct intel_wakeref_lockclass { void __intel_wakeref_init(struct intel_wakeref *wf, struct drm_i915_private *i915, const struct intel_wakeref_ops *ops, - struct intel_wakeref_lockclass *key); -#define intel_wakeref_init(wf, i915, ops) do { \ + struct intel_wakeref_lockclass *key, + const char *name); +#define intel_wakeref_init(wf, i915, ops, name) do { \ static struct intel_wakeref_lockclass __key; \ \ - __intel_wakeref_init((wf), (i915), (ops), &__key); \ + __intel_wakeref_init((wf), (i915), (ops), &__key, name); \ } while (0) int __intel_wakeref_get_first(struct intel_wakeref *wf); @@ -261,6 +273,57 @@ __intel_wakeref_defer_park(struct intel_wakeref *wf) */ int intel_wakeref_wait_for_idle(struct intel_wakeref *wf); +#define INTEL_WAKEREF_DEF ((intel_wakeref_t)(-1)) + +static inline intel_wakeref_t intel_ref_tracker_alloc(struct ref_tracker_dir *dir) +{ + struct ref_tracker *user = NULL; + + ref_tracker_alloc(dir, &user, GFP_NOWAIT); + + return (intel_wakeref_t)user ?: INTEL_WAKEREF_DEF; +} + +static inline void intel_ref_tracker_free(struct ref_tracker_dir *dir, + intel_wakeref_t handle) +{ + struct ref_tracker *user; + + user = (handle == INTEL_WAKEREF_DEF) ? NULL : (void *)handle; + + ref_tracker_free(dir, &user); +} + +void intel_ref_tracker_show(struct ref_tracker_dir *dir, + struct drm_printer *p); + +#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_WAKEREF) + +static inline intel_wakeref_t intel_wakeref_track(struct intel_wakeref *wf) +{ + return intel_ref_tracker_alloc(&wf->debug); +} + +static inline void intel_wakeref_untrack(struct intel_wakeref *wf, + intel_wakeref_t handle) +{ + intel_ref_tracker_free(&wf->debug, handle); +} + +#else + +static inline intel_wakeref_t intel_wakeref_track(struct intel_wakeref *wf) +{ + return -1; +} + +static inline void intel_wakeref_untrack(struct intel_wakeref *wf, + intel_wakeref_t handle) +{ +} + +#endif + struct intel_wakeref_auto { struct drm_i915_private *i915; struct timer_list timer; diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp.c b/drivers/gpu/drm/i915/pxp/intel_pxp.c index dc327cf40b5aab..75278e78ca90e6 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp.c @@ -199,6 +199,9 @@ int intel_pxp_init(struct drm_i915_private *i915) struct intel_gt *gt; bool is_full_feature = false; + if (intel_gt_is_wedged(to_gt(i915))) + return -ENOTCONN; + /* * NOTE: Get the ctrl_gt before checking intel_pxp_is_supported since * we still need it if PXP's backend tee transport is needed. @@ -303,6 +306,8 @@ static int __pxp_global_teardown_final(struct intel_pxp *pxp) if (!pxp->arb_is_valid) return 0; + + drm_dbg(&pxp->ctrl_gt->i915->drm, "PXP: teardown for suspend/fini"); /* * To ensure synchronous and coherent session teardown completion * in response to suspend or shutdown triggers, don't use a worker. @@ -324,6 +329,8 @@ static int __pxp_global_teardown_restart(struct intel_pxp *pxp) if (pxp->arb_is_valid) return 0; + + drm_dbg(&pxp->ctrl_gt->i915->drm, "PXP: teardown for restart"); /* * The arb-session is currently inactive and we are doing a reset and restart * due to a runtime event. Use the worker that was designed for this. @@ -332,8 +339,11 @@ static int __pxp_global_teardown_restart(struct intel_pxp *pxp) timeout = intel_pxp_get_backend_timeout_ms(pxp); - if (!wait_for_completion_timeout(&pxp->termination, msecs_to_jiffies(timeout))) + if (!wait_for_completion_timeout(&pxp->termination, msecs_to_jiffies(timeout))) { + drm_dbg(&pxp->ctrl_gt->i915->drm, "PXP: restart backend timed out (%d ms)", + timeout); return -ETIMEDOUT; + } return 0; } @@ -414,10 +424,12 @@ int intel_pxp_start(struct intel_pxp *pxp) int ret = 0; ret = intel_pxp_get_readiness_status(pxp, PXP_READINESS_TIMEOUT); - if (ret < 0) + if (ret < 0) { + drm_dbg(&pxp->ctrl_gt->i915->drm, "PXP: tried but not-avail (%d)", ret); return ret; - else if (ret > 1) + } else if (ret > 1) { return -EIO; /* per UAPI spec, user may retry later */ + } mutex_lock(&pxp->arb_mutex); diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_irq.c b/drivers/gpu/drm/i915/pxp/intel_pxp_irq.c index 91e9622c07d091..d81750b9bddaa2 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_irq.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_irq.c @@ -40,11 +40,12 @@ void intel_pxp_irq_handler(struct intel_pxp *pxp, u16 iir) GEN12_DISPLAY_APP_TERMINATED_PER_FW_REQ_INTERRUPT)) { /* immediately mark PXP as inactive on termination */ intel_pxp_mark_termination_in_progress(pxp); - pxp->session_events |= PXP_TERMINATION_REQUEST | PXP_INVAL_REQUIRED; + pxp->session_events |= PXP_TERMINATION_REQUEST | PXP_INVAL_REQUIRED | + PXP_EVENT_TYPE_IRQ; } if (iir & GEN12_DISPLAY_STATE_RESET_COMPLETE_INTERRUPT) - pxp->session_events |= PXP_TERMINATION_COMPLETE; + pxp->session_events |= PXP_TERMINATION_COMPLETE | PXP_EVENT_TYPE_IRQ; if (pxp->session_events) queue_work(system_unbound_wq, &pxp->session_work); diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_session.c b/drivers/gpu/drm/i915/pxp/intel_pxp_session.c index 0a3e66b0265e8e..091c86e03d1a55 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_session.c +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_session.c @@ -137,8 +137,10 @@ void intel_pxp_terminate(struct intel_pxp *pxp, bool post_invalidation_needs_res static void pxp_terminate_complete(struct intel_pxp *pxp) { /* Re-create the arb session after teardown handle complete */ - if (fetch_and_zero(&pxp->hw_state_invalidated)) + if (fetch_and_zero(&pxp->hw_state_invalidated)) { + drm_dbg(&pxp->ctrl_gt->i915->drm, "PXP: creating arb_session after invalidation"); pxp_create_arb_session(pxp); + } complete_all(&pxp->termination); } @@ -157,6 +159,8 @@ static void pxp_session_work(struct work_struct *work) if (!events) return; + drm_dbg(>->i915->drm, "PXP: processing event-flags 0x%08x", events); + if (events & PXP_INVAL_REQUIRED) intel_pxp_invalidate(pxp); diff --git a/drivers/gpu/drm/i915/pxp/intel_pxp_types.h b/drivers/gpu/drm/i915/pxp/intel_pxp_types.h index 7e11fa8034b243..07864b584cf4c2 100644 --- a/drivers/gpu/drm/i915/pxp/intel_pxp_types.h +++ b/drivers/gpu/drm/i915/pxp/intel_pxp_types.h @@ -124,6 +124,7 @@ struct intel_pxp { #define PXP_TERMINATION_REQUEST BIT(0) #define PXP_TERMINATION_COMPLETE BIT(1) #define PXP_INVAL_REQUIRED BIT(2) +#define PXP_EVENT_TYPE_IRQ BIT(3) }; #endif /* __INTEL_PXP_TYPES_H__ */ diff --git a/drivers/gpu/drm/i915/selftests/i915_syncmap.c b/drivers/gpu/drm/i915/selftests/i915_syncmap.c index 47f4ae18a1ef04..88fa845e9f4a0e 100644 --- a/drivers/gpu/drm/i915/selftests/i915_syncmap.c +++ b/drivers/gpu/drm/i915/selftests/i915_syncmap.c @@ -77,7 +77,7 @@ __sync_print(struct i915_syncmap *p, for_each_set_bit(i, (unsigned long *)&p->bitmap, KSYNCMAP) { buf = __sync_print(__sync_child(p)[i], buf, sz, depth + 1, - last << 1 | !!(p->bitmap >> (i + 1)), + last << 1 | ((p->bitmap >> (i + 1)) ? 1 : 0), i); } } diff --git a/drivers/gpu/drm/i915/selftests/intel_uncore.c b/drivers/gpu/drm/i915/selftests/intel_uncore.c index 03ea75cd84dd5c..4f98aa8a861ea7 100644 --- a/drivers/gpu/drm/i915/selftests/intel_uncore.c +++ b/drivers/gpu/drm/i915/selftests/intel_uncore.c @@ -24,6 +24,8 @@ #include "../i915_selftest.h" +#include "gt/intel_gt.h" + static int intel_fw_table_check(const struct intel_forcewake_range *ranges, unsigned int num_ranges, bool is_watertight) diff --git a/drivers/gpu/drm/i915/soc/intel_gmch.c b/drivers/gpu/drm/i915/soc/intel_gmch.c index f32e9f78770a29..40874ebfb64c7c 100644 --- a/drivers/gpu/drm/i915/soc/intel_gmch.c +++ b/drivers/gpu/drm/i915/soc/intel_gmch.c @@ -33,18 +33,22 @@ int intel_gmch_bridge_setup(struct drm_i915_private *i915) i915->gmch.pdev); } +static int mchbar_reg(struct drm_i915_private *i915) +{ + return GRAPHICS_VER(i915) >= 4 ? MCHBAR_I965 : MCHBAR_I915; +} + /* 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); + pci_read_config_dword(i915->gmch.pdev, mchbar_reg(i915) + 4, &temp_hi); + pci_read_config_dword(i915->gmch.pdev, mchbar_reg(i915), &temp_lo); mchbar_addr = ((u64)temp_hi << 32) | temp_lo; /* If ACPI doesn't have it, assume we need to allocate it ourselves */ @@ -68,10 +72,10 @@ intel_alloc_mchbar_resource(struct drm_i915_private *i915) } if (GRAPHICS_VER(i915) >= 4) - pci_write_config_dword(i915->gmch.pdev, reg + 4, + pci_write_config_dword(i915->gmch.pdev, mchbar_reg(i915) + 4, upper_32_bits(i915->gmch.mch_res.start)); - pci_write_config_dword(i915->gmch.pdev, reg, + pci_write_config_dword(i915->gmch.pdev, mchbar_reg(i915), lower_32_bits(i915->gmch.mch_res.start)); return 0; } @@ -79,7 +83,6 @@ intel_alloc_mchbar_resource(struct drm_i915_private *i915) /* 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; @@ -92,7 +95,7 @@ void intel_gmch_bar_setup(struct drm_i915_private *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); + pci_read_config_dword(i915->gmch.pdev, mchbar_reg(i915), &temp); enabled = temp & 1; } @@ -110,15 +113,13 @@ void intel_gmch_bar_setup(struct drm_i915_private *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); + pci_read_config_dword(i915->gmch.pdev, mchbar_reg(i915), &temp); + pci_write_config_dword(i915->gmch.pdev, mchbar_reg(i915), 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; @@ -131,10 +132,10 @@ void intel_gmch_bar_teardown(struct drm_i915_private *i915) } else { u32 mchbar_val; - pci_read_config_dword(i915->gmch.pdev, mchbar_reg, + pci_read_config_dword(i915->gmch.pdev, mchbar_reg(i915), &mchbar_val); mchbar_val &= ~1; - pci_write_config_dword(i915->gmch.pdev, mchbar_reg, + pci_write_config_dword(i915->gmch.pdev, mchbar_reg(i915), mchbar_val); } } diff --git a/drivers/gpu/drm/i915/vlv_sideband.c b/drivers/gpu/drm/i915/vlv_sideband.c index b98dec3ad817a6..ffa195560d0ddd 100644 --- a/drivers/gpu/drm/i915/vlv_sideband.c +++ b/drivers/gpu/drm/i915/vlv_sideband.c @@ -166,23 +166,6 @@ u32 vlv_nc_read(struct drm_i915_private *i915, u8 addr) return val; } -u32 vlv_iosf_sb_read(struct drm_i915_private *i915, u8 port, u32 reg) -{ - u32 val = 0; - - vlv_sideband_rw(i915, PCI_DEVFN(0, 0), port, - SB_CRRDDA_NP, reg, &val); - - return val; -} - -void vlv_iosf_sb_write(struct drm_i915_private *i915, - u8 port, u32 reg, u32 val) -{ - vlv_sideband_rw(i915, PCI_DEVFN(0, 0), port, - SB_CRWRDA_NP, reg, &val); -} - u32 vlv_cck_read(struct drm_i915_private *i915, u32 reg) { u32 val = 0; @@ -227,9 +210,9 @@ static u32 vlv_dpio_phy_iosf_port(struct drm_i915_private *i915, enum dpio_phy p return IOSF_PORT_DPIO; } -u32 vlv_dpio_read(struct drm_i915_private *i915, enum pipe pipe, int reg) +u32 vlv_dpio_read(struct drm_i915_private *i915, enum dpio_phy phy, int reg) { - u32 port = vlv_dpio_phy_iosf_port(i915, DPIO_PHY(pipe)); + u32 port = vlv_dpio_phy_iosf_port(i915, phy); u32 val = 0; vlv_sideband_rw(i915, DPIO_DEVFN, port, SB_MRD_NP, reg, &val); @@ -239,16 +222,16 @@ u32 vlv_dpio_read(struct drm_i915_private *i915, enum pipe pipe, int reg) * so ideally we should check the register offset instead... */ drm_WARN(&i915->drm, val == 0xffffffff, - "DPIO read pipe %c reg 0x%x == 0x%x\n", - pipe_name(pipe), reg, val); + "DPIO PHY%d read reg 0x%x == 0x%x\n", + phy, reg, val); return val; } void vlv_dpio_write(struct drm_i915_private *i915, - enum pipe pipe, int reg, u32 val) + enum dpio_phy phy, int reg, u32 val) { - u32 port = vlv_dpio_phy_iosf_port(i915, DPIO_PHY(pipe)); + u32 port = vlv_dpio_phy_iosf_port(i915, phy); vlv_sideband_rw(i915, DPIO_DEVFN, port, SB_MWR_NP, reg, &val); } diff --git a/drivers/gpu/drm/i915/vlv_sideband.h b/drivers/gpu/drm/i915/vlv_sideband.h index 9ce283d96b80a0..c20cf41b2d39b3 100644 --- a/drivers/gpu/drm/i915/vlv_sideband.h +++ b/drivers/gpu/drm/i915/vlv_sideband.h @@ -11,7 +11,7 @@ #include "vlv_sideband_reg.h" -enum pipe; +enum dpio_phy; struct drm_i915_private; enum { @@ -26,9 +26,6 @@ enum { }; void vlv_iosf_sb_get(struct drm_i915_private *i915, unsigned long ports); -u32 vlv_iosf_sb_read(struct drm_i915_private *i915, u8 port, u32 reg); -void vlv_iosf_sb_write(struct drm_i915_private *i915, - u8 port, u32 reg, u32 val); void vlv_iosf_sb_put(struct drm_i915_private *i915, unsigned long ports); static inline void vlv_bunit_get(struct drm_i915_private *i915) @@ -75,9 +72,9 @@ static inline void vlv_dpio_get(struct drm_i915_private *i915) vlv_iosf_sb_get(i915, BIT(VLV_IOSF_SB_DPIO)); } -u32 vlv_dpio_read(struct drm_i915_private *i915, enum pipe pipe, int reg); +u32 vlv_dpio_read(struct drm_i915_private *i915, enum dpio_phy phy, int reg); void vlv_dpio_write(struct drm_i915_private *i915, - enum pipe pipe, int reg, u32 val); + enum dpio_phy phy, int reg, u32 val); static inline void vlv_dpio_put(struct drm_i915_private *i915) { diff --git a/drivers/gpu/drm/imagination/Kconfig b/drivers/gpu/drm/imagination/Kconfig new file mode 100644 index 00000000000000..3bfa2ac212dccb --- /dev/null +++ b/drivers/gpu/drm/imagination/Kconfig @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-only OR MIT +# Copyright (c) 2023 Imagination Technologies Ltd. + +config DRM_POWERVR + tristate "Imagination Technologies PowerVR (Series 6 and later) & IMG Graphics" + depends on ARM64 + depends on DRM + depends on PM + select DRM_EXEC + select DRM_GEM_SHMEM_HELPER + select DRM_SCHED + select DRM_GPUVM + select FW_LOADER + help + Choose this option if you have a system that has an Imagination + Technologies PowerVR (Series 6 or later) or IMG GPU. + + If "M" is selected, the module will be called powervr. diff --git a/drivers/gpu/drm/imagination/Makefile b/drivers/gpu/drm/imagination/Makefile new file mode 100644 index 00000000000000..ec6db8e9b40375 --- /dev/null +++ b/drivers/gpu/drm/imagination/Makefile @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: GPL-2.0-only OR MIT +# Copyright (c) 2023 Imagination Technologies Ltd. + +subdir-ccflags-y := -I$(srctree)/$(src) + +powervr-y := \ + pvr_ccb.o \ + pvr_cccb.o \ + pvr_context.o \ + pvr_device.o \ + pvr_device_info.o \ + pvr_drv.o \ + pvr_free_list.o \ + pvr_fw.o \ + pvr_fw_meta.o \ + pvr_fw_mips.o \ + pvr_fw_startstop.o \ + pvr_fw_trace.o \ + pvr_gem.o \ + pvr_hwrt.o \ + pvr_job.o \ + pvr_mmu.o \ + pvr_params.o \ + pvr_power.o \ + pvr_queue.o \ + pvr_stream.o \ + pvr_stream_defs.o \ + pvr_sync.o \ + pvr_vm.o \ + pvr_vm_mips.o + +powervr-$(CONFIG_DEBUG_FS) += \ + pvr_debugfs.o + +obj-$(CONFIG_DRM_POWERVR) += powervr.o diff --git a/drivers/gpu/drm/imagination/pvr_ccb.c b/drivers/gpu/drm/imagination/pvr_ccb.c new file mode 100644 index 00000000000000..4deeac7ed40a4d --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_ccb.c @@ -0,0 +1,645 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_ccb.h" +#include "pvr_device.h" +#include "pvr_drv.h" +#include "pvr_free_list.h" +#include "pvr_fw.h" +#include "pvr_gem.h" +#include "pvr_power.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#define RESERVE_SLOT_TIMEOUT (1 * HZ) /* 1s */ +#define RESERVE_SLOT_MIN_RETRIES 10 + +static void +ccb_ctrl_init(void *cpu_ptr, void *priv) +{ + struct rogue_fwif_ccb_ctl *ctrl = cpu_ptr; + struct pvr_ccb *pvr_ccb = priv; + + ctrl->write_offset = 0; + ctrl->read_offset = 0; + ctrl->wrap_mask = pvr_ccb->num_cmds - 1; + ctrl->cmd_size = pvr_ccb->cmd_size; +} + +/** + * pvr_ccb_init() - Initialise a CCB + * @pvr_dev: Device pointer. + * @pvr_ccb: Pointer to CCB structure to initialise. + * @num_cmds_log2: Log2 of number of commands in this CCB. + * @cmd_size: Command size for this CCB. + * + * Return: + * * Zero on success, or + * * Any error code returned by pvr_fw_object_create_and_map(). + */ +static int +pvr_ccb_init(struct pvr_device *pvr_dev, struct pvr_ccb *pvr_ccb, + u32 num_cmds_log2, size_t cmd_size) +{ + u32 num_cmds = 1 << num_cmds_log2; + u32 ccb_size = num_cmds * cmd_size; + int err; + + pvr_ccb->num_cmds = num_cmds; + pvr_ccb->cmd_size = cmd_size; + + err = drmm_mutex_init(from_pvr_device(pvr_dev), &pvr_ccb->lock); + if (err) + return err; + + /* + * Map CCB and control structure as uncached, so we don't have to flush + * CPU cache repeatedly when polling for space. + */ + pvr_ccb->ctrl = pvr_fw_object_create_and_map(pvr_dev, sizeof(*pvr_ccb->ctrl), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + ccb_ctrl_init, pvr_ccb, &pvr_ccb->ctrl_obj); + if (IS_ERR(pvr_ccb->ctrl)) + return PTR_ERR(pvr_ccb->ctrl); + + pvr_ccb->ccb = pvr_fw_object_create_and_map(pvr_dev, ccb_size, + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + NULL, NULL, &pvr_ccb->ccb_obj); + if (IS_ERR(pvr_ccb->ccb)) { + err = PTR_ERR(pvr_ccb->ccb); + goto err_free_ctrl; + } + + pvr_fw_object_get_fw_addr(pvr_ccb->ctrl_obj, &pvr_ccb->ctrl_fw_addr); + pvr_fw_object_get_fw_addr(pvr_ccb->ccb_obj, &pvr_ccb->ccb_fw_addr); + + WRITE_ONCE(pvr_ccb->ctrl->write_offset, 0); + WRITE_ONCE(pvr_ccb->ctrl->read_offset, 0); + WRITE_ONCE(pvr_ccb->ctrl->wrap_mask, num_cmds - 1); + WRITE_ONCE(pvr_ccb->ctrl->cmd_size, cmd_size); + + return 0; + +err_free_ctrl: + pvr_fw_object_unmap_and_destroy(pvr_ccb->ctrl_obj); + + return err; +} + +/** + * pvr_ccb_fini() - Release CCB structure + * @pvr_ccb: CCB to release. + */ +void +pvr_ccb_fini(struct pvr_ccb *pvr_ccb) +{ + pvr_fw_object_unmap_and_destroy(pvr_ccb->ccb_obj); + pvr_fw_object_unmap_and_destroy(pvr_ccb->ctrl_obj); +} + +/** + * pvr_ccb_slot_available_locked() - Test whether any slots are available in CCB + * @pvr_ccb: CCB to test. + * @write_offset: Address to store number of next available slot. May be %NULL. + * + * Caller must hold @pvr_ccb->lock. + * + * Return: + * * %true if a slot is available, or + * * %false if no slot is available. + */ +static __always_inline bool +pvr_ccb_slot_available_locked(struct pvr_ccb *pvr_ccb, u32 *write_offset) +{ + struct rogue_fwif_ccb_ctl *ctrl = pvr_ccb->ctrl; + u32 next_write_offset = (READ_ONCE(ctrl->write_offset) + 1) & READ_ONCE(ctrl->wrap_mask); + + lockdep_assert_held(&pvr_ccb->lock); + + if (READ_ONCE(ctrl->read_offset) != next_write_offset) { + if (write_offset) + *write_offset = next_write_offset; + return true; + } + + return false; +} + +static void +process_fwccb_command(struct pvr_device *pvr_dev, struct rogue_fwif_fwccb_cmd *cmd) +{ + switch (cmd->cmd_type) { + case ROGUE_FWIF_FWCCB_CMD_REQUEST_GPU_RESTART: + pvr_power_reset(pvr_dev, false); + break; + + case ROGUE_FWIF_FWCCB_CMD_FREELISTS_RECONSTRUCTION: + pvr_free_list_process_reconstruct_req(pvr_dev, + &cmd->cmd_data.cmd_freelists_reconstruction); + break; + + case ROGUE_FWIF_FWCCB_CMD_FREELIST_GROW: + pvr_free_list_process_grow_req(pvr_dev, &cmd->cmd_data.cmd_free_list_gs); + break; + + default: + drm_info(from_pvr_device(pvr_dev), "Received unknown FWCCB command %x\n", + cmd->cmd_type); + break; + } +} + +/** + * pvr_fwccb_process() - Process any pending FWCCB commands + * @pvr_dev: Target PowerVR device + */ +void pvr_fwccb_process(struct pvr_device *pvr_dev) +{ + struct rogue_fwif_fwccb_cmd *fwccb = pvr_dev->fwccb.ccb; + struct rogue_fwif_ccb_ctl *ctrl = pvr_dev->fwccb.ctrl; + u32 read_offset; + + mutex_lock(&pvr_dev->fwccb.lock); + + while ((read_offset = READ_ONCE(ctrl->read_offset)) != READ_ONCE(ctrl->write_offset)) { + struct rogue_fwif_fwccb_cmd cmd = fwccb[read_offset]; + + WRITE_ONCE(ctrl->read_offset, (read_offset + 1) & READ_ONCE(ctrl->wrap_mask)); + + /* Drop FWCCB lock while we process command. */ + mutex_unlock(&pvr_dev->fwccb.lock); + + process_fwccb_command(pvr_dev, &cmd); + + mutex_lock(&pvr_dev->fwccb.lock); + } + + mutex_unlock(&pvr_dev->fwccb.lock); +} + +/** + * pvr_kccb_capacity() - Returns the maximum number of usable KCCB slots. + * @pvr_dev: Target PowerVR device + * + * Return: + * * The maximum number of active slots. + */ +static u32 pvr_kccb_capacity(struct pvr_device *pvr_dev) +{ + /* Capacity is the number of slot minus one to cope with the wrapping + * mechanisms. If we were to use all slots, we might end up with + * read_offset == write_offset, which the FW considers as a KCCB-is-empty + * condition. + */ + return pvr_dev->kccb.slot_count - 1; +} + +/** + * pvr_kccb_used_slot_count_locked() - Get the number of used slots + * @pvr_dev: Device pointer. + * + * KCCB lock must be held. + * + * Return: + * * The number of slots currently used. + */ +static u32 +pvr_kccb_used_slot_count_locked(struct pvr_device *pvr_dev) +{ + struct pvr_ccb *pvr_ccb = &pvr_dev->kccb.ccb; + struct rogue_fwif_ccb_ctl *ctrl = pvr_ccb->ctrl; + u32 wr_offset = READ_ONCE(ctrl->write_offset); + u32 rd_offset = READ_ONCE(ctrl->read_offset); + u32 used_count; + + lockdep_assert_held(&pvr_ccb->lock); + + if (wr_offset >= rd_offset) + used_count = wr_offset - rd_offset; + else + used_count = wr_offset + pvr_dev->kccb.slot_count - rd_offset; + + return used_count; +} + +/** + * pvr_kccb_send_cmd_reserved_powered() - Send command to the KCCB, with the PM ref + * held and a slot pre-reserved + * @pvr_dev: Device pointer. + * @cmd: Command to sent. + * @kccb_slot: Address to store the KCCB slot for this command. May be %NULL. + */ +void +pvr_kccb_send_cmd_reserved_powered(struct pvr_device *pvr_dev, + struct rogue_fwif_kccb_cmd *cmd, + u32 *kccb_slot) +{ + struct pvr_ccb *pvr_ccb = &pvr_dev->kccb.ccb; + struct rogue_fwif_kccb_cmd *kccb = pvr_ccb->ccb; + struct rogue_fwif_ccb_ctl *ctrl = pvr_ccb->ctrl; + u32 old_write_offset; + u32 new_write_offset; + + WARN_ON(pvr_dev->lost); + + mutex_lock(&pvr_ccb->lock); + + if (WARN_ON(!pvr_dev->kccb.reserved_count)) + goto out_unlock; + + old_write_offset = READ_ONCE(ctrl->write_offset); + + /* We reserved the slot, we should have one available. */ + if (WARN_ON(!pvr_ccb_slot_available_locked(pvr_ccb, &new_write_offset))) + goto out_unlock; + + memcpy(&kccb[old_write_offset], cmd, + sizeof(struct rogue_fwif_kccb_cmd)); + if (kccb_slot) { + *kccb_slot = old_write_offset; + /* Clear return status for this slot. */ + WRITE_ONCE(pvr_dev->kccb.rtn[old_write_offset], + ROGUE_FWIF_KCCB_RTN_SLOT_NO_RESPONSE); + } + mb(); /* memory barrier */ + WRITE_ONCE(ctrl->write_offset, new_write_offset); + pvr_dev->kccb.reserved_count--; + + /* Kick MTS */ + pvr_fw_mts_schedule(pvr_dev, + PVR_FWIF_DM_GP & ~ROGUE_CR_MTS_SCHEDULE_DM_CLRMSK); + +out_unlock: + mutex_unlock(&pvr_ccb->lock); +} + +/** + * pvr_kccb_try_reserve_slot() - Try to reserve a KCCB slot + * @pvr_dev: Device pointer. + * + * Return: + * * true if a KCCB slot was reserved, or + * * false otherwise. + */ +static bool pvr_kccb_try_reserve_slot(struct pvr_device *pvr_dev) +{ + bool reserved = false; + u32 used_count; + + mutex_lock(&pvr_dev->kccb.ccb.lock); + + used_count = pvr_kccb_used_slot_count_locked(pvr_dev); + if (pvr_dev->kccb.reserved_count < pvr_kccb_capacity(pvr_dev) - used_count) { + pvr_dev->kccb.reserved_count++; + reserved = true; + } + + mutex_unlock(&pvr_dev->kccb.ccb.lock); + + return reserved; +} + +/** + * pvr_kccb_reserve_slot_sync() - Try to reserve a slot synchronously + * @pvr_dev: Device pointer. + * + * Return: + * * 0 on success, or + * * -EBUSY if no slots were reserved after %RESERVE_SLOT_TIMEOUT, with a minimum of + * %RESERVE_SLOT_MIN_RETRIES retries. + */ +static int pvr_kccb_reserve_slot_sync(struct pvr_device *pvr_dev) +{ + unsigned long start_timestamp = jiffies; + bool reserved = false; + u32 retries = 0; + + while ((jiffies - start_timestamp) < (u32)RESERVE_SLOT_TIMEOUT || + retries < RESERVE_SLOT_MIN_RETRIES) { + reserved = pvr_kccb_try_reserve_slot(pvr_dev); + if (reserved) + break; + + usleep_range(1, 50); + + if (retries < U32_MAX) + retries++; + } + + return reserved ? 0 : -EBUSY; +} + +/** + * pvr_kccb_send_cmd_powered() - Send command to the KCCB, with a PM ref held + * @pvr_dev: Device pointer. + * @cmd: Command to sent. + * @kccb_slot: Address to store the KCCB slot for this command. May be %NULL. + * + * Returns: + * * Zero on success, or + * * -EBUSY if timeout while waiting for a free KCCB slot. + */ +int +pvr_kccb_send_cmd_powered(struct pvr_device *pvr_dev, struct rogue_fwif_kccb_cmd *cmd, + u32 *kccb_slot) +{ + int err; + + err = pvr_kccb_reserve_slot_sync(pvr_dev); + if (err) + return err; + + pvr_kccb_send_cmd_reserved_powered(pvr_dev, cmd, kccb_slot); + return 0; +} + +/** + * pvr_kccb_send_cmd() - Send command to the KCCB + * @pvr_dev: Device pointer. + * @cmd: Command to sent. + * @kccb_slot: Address to store the KCCB slot for this command. May be %NULL. + * + * Returns: + * * Zero on success, or + * * -EBUSY if timeout while waiting for a free KCCB slot. + */ +int +pvr_kccb_send_cmd(struct pvr_device *pvr_dev, struct rogue_fwif_kccb_cmd *cmd, + u32 *kccb_slot) +{ + int err; + + err = pvr_power_get(pvr_dev); + if (err) + return err; + + err = pvr_kccb_send_cmd_powered(pvr_dev, cmd, kccb_slot); + + pvr_power_put(pvr_dev); + + return err; +} + +/** + * pvr_kccb_wait_for_completion() - Wait for a KCCB command to complete + * @pvr_dev: Device pointer. + * @slot_nr: KCCB slot to wait on. + * @timeout: Timeout length (in jiffies). + * @rtn_out: Location to store KCCB command result. May be %NULL. + * + * Returns: + * * Zero on success, or + * * -ETIMEDOUT on timeout. + */ +int +pvr_kccb_wait_for_completion(struct pvr_device *pvr_dev, u32 slot_nr, + u32 timeout, u32 *rtn_out) +{ + int ret = wait_event_timeout(pvr_dev->kccb.rtn_q, READ_ONCE(pvr_dev->kccb.rtn[slot_nr]) & + ROGUE_FWIF_KCCB_RTN_SLOT_CMD_EXECUTED, timeout); + + if (ret && rtn_out) + *rtn_out = READ_ONCE(pvr_dev->kccb.rtn[slot_nr]); + + return ret ? 0 : -ETIMEDOUT; +} + +/** + * pvr_kccb_is_idle() - Returns whether the device's KCCB is idle + * @pvr_dev: Device pointer + * + * Returns: + * * %true if the KCCB is idle (contains no commands), or + * * %false if the KCCB contains pending commands. + */ +bool +pvr_kccb_is_idle(struct pvr_device *pvr_dev) +{ + struct rogue_fwif_ccb_ctl *ctrl = pvr_dev->kccb.ccb.ctrl; + bool idle; + + mutex_lock(&pvr_dev->kccb.ccb.lock); + + idle = (READ_ONCE(ctrl->write_offset) == READ_ONCE(ctrl->read_offset)); + + mutex_unlock(&pvr_dev->kccb.ccb.lock); + + return idle; +} + +static const char * +pvr_kccb_fence_get_driver_name(struct dma_fence *f) +{ + return PVR_DRIVER_NAME; +} + +static const char * +pvr_kccb_fence_get_timeline_name(struct dma_fence *f) +{ + return "kccb"; +} + +static const struct dma_fence_ops pvr_kccb_fence_ops = { + .get_driver_name = pvr_kccb_fence_get_driver_name, + .get_timeline_name = pvr_kccb_fence_get_timeline_name, +}; + +/** + * struct pvr_kccb_fence - Fence object used to wait for a KCCB slot + */ +struct pvr_kccb_fence { + /** @base: Base dma_fence object. */ + struct dma_fence base; + + /** @node: Node used to insert the fence in the pvr_device::kccb::waiters list. */ + struct list_head node; +}; + +/** + * pvr_kccb_wake_up_waiters() - Check the KCCB waiters + * @pvr_dev: Target PowerVR device + * + * Signal as many KCCB fences as we have slots available. + */ +void pvr_kccb_wake_up_waiters(struct pvr_device *pvr_dev) +{ + struct pvr_kccb_fence *fence, *tmp_fence; + u32 used_count, available_count; + + /* Wake up those waiting for KCCB slot execution. */ + wake_up_all(&pvr_dev->kccb.rtn_q); + + /* Then iterate over all KCCB fences and signal as many as we can. */ + mutex_lock(&pvr_dev->kccb.ccb.lock); + used_count = pvr_kccb_used_slot_count_locked(pvr_dev); + + if (WARN_ON(used_count + pvr_dev->kccb.reserved_count > pvr_kccb_capacity(pvr_dev))) + goto out_unlock; + + available_count = pvr_kccb_capacity(pvr_dev) - used_count - pvr_dev->kccb.reserved_count; + list_for_each_entry_safe(fence, tmp_fence, &pvr_dev->kccb.waiters, node) { + if (!available_count) + break; + + list_del(&fence->node); + pvr_dev->kccb.reserved_count++; + available_count--; + dma_fence_signal(&fence->base); + dma_fence_put(&fence->base); + } + +out_unlock: + mutex_unlock(&pvr_dev->kccb.ccb.lock); +} + +/** + * pvr_kccb_fini() - Cleanup device KCCB + * @pvr_dev: Target PowerVR device + */ +void pvr_kccb_fini(struct pvr_device *pvr_dev) +{ + pvr_ccb_fini(&pvr_dev->kccb.ccb); + WARN_ON(!list_empty(&pvr_dev->kccb.waiters)); + WARN_ON(pvr_dev->kccb.reserved_count); +} + +/** + * pvr_kccb_init() - Initialise device KCCB + * @pvr_dev: Target PowerVR device + * + * Returns: + * * 0 on success, or + * * Any error returned by pvr_ccb_init(). + */ +int +pvr_kccb_init(struct pvr_device *pvr_dev) +{ + pvr_dev->kccb.slot_count = 1 << ROGUE_FWIF_KCCB_NUMCMDS_LOG2_DEFAULT; + INIT_LIST_HEAD(&pvr_dev->kccb.waiters); + pvr_dev->kccb.fence_ctx.id = dma_fence_context_alloc(1); + spin_lock_init(&pvr_dev->kccb.fence_ctx.lock); + + return pvr_ccb_init(pvr_dev, &pvr_dev->kccb.ccb, + ROGUE_FWIF_KCCB_NUMCMDS_LOG2_DEFAULT, + sizeof(struct rogue_fwif_kccb_cmd)); +} + +/** + * pvr_kccb_fence_alloc() - Allocate a pvr_kccb_fence object + * + * Return: + * * NULL if the allocation fails, or + * * A valid dma_fence pointer otherwise. + */ +struct dma_fence *pvr_kccb_fence_alloc(void) +{ + struct pvr_kccb_fence *kccb_fence; + + kccb_fence = kzalloc(sizeof(*kccb_fence), GFP_KERNEL); + if (!kccb_fence) + return NULL; + + return &kccb_fence->base; +} + +/** + * pvr_kccb_fence_put() - Drop a KCCB fence reference + * @fence: The fence to drop the reference on. + * + * If the fence hasn't been initialized yet, dma_fence_free() is called. This + * way we have a single function taking care of both cases. + */ +void pvr_kccb_fence_put(struct dma_fence *fence) +{ + if (!fence) + return; + + if (!fence->ops) { + dma_fence_free(fence); + } else { + WARN_ON(fence->ops != &pvr_kccb_fence_ops); + dma_fence_put(fence); + } +} + +/** + * pvr_kccb_reserve_slot() - Reserve a KCCB slot for later use + * @pvr_dev: Target PowerVR device + * @f: KCCB fence object previously allocated with pvr_kccb_fence_alloc() + * + * Try to reserve a KCCB slot, and if there's no slot available, + * initializes the fence object and queue it to the waiters list. + * + * If NULL is returned, that means the slot is reserved. In that case, + * the @f is freed and shouldn't be accessed after that point. + * + * Return: + * * NULL if a slot was available directly, or + * * A valid dma_fence object to wait on if no slot was available. + */ +struct dma_fence * +pvr_kccb_reserve_slot(struct pvr_device *pvr_dev, struct dma_fence *f) +{ + struct pvr_kccb_fence *fence = container_of(f, struct pvr_kccb_fence, base); + struct dma_fence *out_fence = NULL; + u32 used_count; + + mutex_lock(&pvr_dev->kccb.ccb.lock); + + used_count = pvr_kccb_used_slot_count_locked(pvr_dev); + if (pvr_dev->kccb.reserved_count >= pvr_kccb_capacity(pvr_dev) - used_count) { + dma_fence_init(&fence->base, &pvr_kccb_fence_ops, + &pvr_dev->kccb.fence_ctx.lock, + pvr_dev->kccb.fence_ctx.id, + atomic_inc_return(&pvr_dev->kccb.fence_ctx.seqno)); + out_fence = dma_fence_get(&fence->base); + list_add_tail(&fence->node, &pvr_dev->kccb.waiters); + } else { + pvr_kccb_fence_put(f); + pvr_dev->kccb.reserved_count++; + } + + mutex_unlock(&pvr_dev->kccb.ccb.lock); + + return out_fence; +} + +/** + * pvr_kccb_release_slot() - Release a KCCB slot reserved with + * pvr_kccb_reserve_slot() + * @pvr_dev: Target PowerVR device + * + * Should only be called if something failed after the + * pvr_kccb_reserve_slot() call and you know you won't call + * pvr_kccb_send_cmd_reserved(). + */ +void pvr_kccb_release_slot(struct pvr_device *pvr_dev) +{ + mutex_lock(&pvr_dev->kccb.ccb.lock); + if (!WARN_ON(!pvr_dev->kccb.reserved_count)) + pvr_dev->kccb.reserved_count--; + mutex_unlock(&pvr_dev->kccb.ccb.lock); +} + +/** + * pvr_fwccb_init() - Initialise device FWCCB + * @pvr_dev: Target PowerVR device + * + * Returns: + * * 0 on success, or + * * Any error returned by pvr_ccb_init(). + */ +int +pvr_fwccb_init(struct pvr_device *pvr_dev) +{ + return pvr_ccb_init(pvr_dev, &pvr_dev->fwccb, + ROGUE_FWIF_FWCCB_NUMCMDS_LOG2, + sizeof(struct rogue_fwif_fwccb_cmd)); +} diff --git a/drivers/gpu/drm/imagination/pvr_ccb.h b/drivers/gpu/drm/imagination/pvr_ccb.h new file mode 100644 index 00000000000000..4c8aef31eeb049 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_ccb.h @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_CCB_H +#define PVR_CCB_H + +#include "pvr_rogue_fwif.h" + +#include +#include + +/* Forward declaration from pvr_device.h. */ +struct pvr_device; + +/* Forward declaration from pvr_gem.h. */ +struct pvr_fw_object; + +struct pvr_ccb { + /** @ctrl_obj: FW object representing CCB control structure. */ + struct pvr_fw_object *ctrl_obj; + /** @ccb_obj: FW object representing CCB. */ + struct pvr_fw_object *ccb_obj; + + /** @ctrl_fw_addr: FW virtual address of CCB control structure. */ + u32 ctrl_fw_addr; + /** @ccb_fw_addr: FW virtual address of CCB. */ + u32 ccb_fw_addr; + + /** @num_cmds: Number of commands in this CCB. */ + u32 num_cmds; + + /** @cmd_size: Size of each command in this CCB, in bytes. */ + u32 cmd_size; + + /** @lock: Mutex protecting @ctrl and @ccb. */ + struct mutex lock; + /** + * @ctrl: Kernel mapping of CCB control structure. @lock must be held + * when accessing. + */ + struct rogue_fwif_ccb_ctl *ctrl; + /** @ccb: Kernel mapping of CCB. @lock must be held when accessing. */ + void *ccb; +}; + +int pvr_kccb_init(struct pvr_device *pvr_dev); +void pvr_kccb_fini(struct pvr_device *pvr_dev); +int pvr_fwccb_init(struct pvr_device *pvr_dev); +void pvr_ccb_fini(struct pvr_ccb *ccb); + +void pvr_fwccb_process(struct pvr_device *pvr_dev); + +struct dma_fence *pvr_kccb_fence_alloc(void); +void pvr_kccb_fence_put(struct dma_fence *fence); +struct dma_fence * +pvr_kccb_reserve_slot(struct pvr_device *pvr_dev, struct dma_fence *f); +void pvr_kccb_release_slot(struct pvr_device *pvr_dev); +int pvr_kccb_send_cmd(struct pvr_device *pvr_dev, + struct rogue_fwif_kccb_cmd *cmd, u32 *kccb_slot); +int pvr_kccb_send_cmd_powered(struct pvr_device *pvr_dev, + struct rogue_fwif_kccb_cmd *cmd, + u32 *kccb_slot); +void pvr_kccb_send_cmd_reserved_powered(struct pvr_device *pvr_dev, + struct rogue_fwif_kccb_cmd *cmd, + u32 *kccb_slot); +int pvr_kccb_wait_for_completion(struct pvr_device *pvr_dev, u32 slot_nr, u32 timeout, + u32 *rtn_out); +bool pvr_kccb_is_idle(struct pvr_device *pvr_dev); +void pvr_kccb_wake_up_waiters(struct pvr_device *pvr_dev); + +#endif /* PVR_CCB_H */ diff --git a/drivers/gpu/drm/imagination/pvr_cccb.c b/drivers/gpu/drm/imagination/pvr_cccb.c new file mode 100644 index 00000000000000..4fabab41bea790 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_cccb.c @@ -0,0 +1,267 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_ccb.h" +#include "pvr_cccb.h" +#include "pvr_device.h" +#include "pvr_gem.h" +#include "pvr_hwrt.h" + +#include +#include +#include +#include +#include + +static __always_inline u32 +get_ccb_space(u32 w_off, u32 r_off, u32 ccb_size) +{ + return (((r_off) - (w_off)) + ((ccb_size) - 1)) & ((ccb_size) - 1); +} + +static void +cccb_ctrl_init(void *cpu_ptr, void *priv) +{ + struct rogue_fwif_cccb_ctl *ctrl = cpu_ptr; + struct pvr_cccb *pvr_cccb = priv; + + WRITE_ONCE(ctrl->write_offset, 0); + WRITE_ONCE(ctrl->read_offset, 0); + WRITE_ONCE(ctrl->dep_offset, 0); + WRITE_ONCE(ctrl->wrap_mask, pvr_cccb->wrap_mask); +} + +/** + * pvr_cccb_init() - Initialise a Client CCB + * @pvr_dev: Device pointer. + * @pvr_cccb: Pointer to Client CCB structure to initialise. + * @size_log2: Log2 size of Client CCB in bytes. + * @name: Name of owner of Client CCB. Used for fence context. + * + * Return: + * * Zero on success, or + * * Any error code returned by pvr_fw_object_create_and_map(). + */ +int +pvr_cccb_init(struct pvr_device *pvr_dev, struct pvr_cccb *pvr_cccb, + u32 size_log2, const char *name) +{ + size_t size = 1 << size_log2; + int err; + + pvr_cccb->size = size; + pvr_cccb->write_offset = 0; + pvr_cccb->wrap_mask = size - 1; + + /* + * Map CCCB and control structure as uncached, so we don't have to flush + * CPU cache repeatedly when polling for space. + */ + pvr_cccb->ctrl = pvr_fw_object_create_and_map(pvr_dev, sizeof(*pvr_cccb->ctrl), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + cccb_ctrl_init, pvr_cccb, + &pvr_cccb->ctrl_obj); + if (IS_ERR(pvr_cccb->ctrl)) + return PTR_ERR(pvr_cccb->ctrl); + + pvr_cccb->cccb = pvr_fw_object_create_and_map(pvr_dev, size, + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + NULL, NULL, &pvr_cccb->cccb_obj); + if (IS_ERR(pvr_cccb->cccb)) { + err = PTR_ERR(pvr_cccb->cccb); + goto err_free_ctrl; + } + + pvr_fw_object_get_fw_addr(pvr_cccb->ctrl_obj, &pvr_cccb->ctrl_fw_addr); + pvr_fw_object_get_fw_addr(pvr_cccb->cccb_obj, &pvr_cccb->cccb_fw_addr); + + return 0; + +err_free_ctrl: + pvr_fw_object_unmap_and_destroy(pvr_cccb->ctrl_obj); + + return err; +} + +/** + * pvr_cccb_fini() - Release Client CCB structure + * @pvr_cccb: Client CCB to release. + */ +void +pvr_cccb_fini(struct pvr_cccb *pvr_cccb) +{ + pvr_fw_object_unmap_and_destroy(pvr_cccb->cccb_obj); + pvr_fw_object_unmap_and_destroy(pvr_cccb->ctrl_obj); +} + +/** + * pvr_cccb_cmdseq_fits() - Check if a command sequence fits in the CCCB + * @pvr_cccb: Target Client CCB. + * @size: Size of the command sequence. + * + * Check if a command sequence fits in the CCCB we have at hand. + * + * Return: + * * true if the command sequence fits in the CCCB, or + * * false otherwise. + */ +bool pvr_cccb_cmdseq_fits(struct pvr_cccb *pvr_cccb, size_t size) +{ + struct rogue_fwif_cccb_ctl *ctrl = pvr_cccb->ctrl; + u32 read_offset, remaining; + bool fits = false; + + read_offset = READ_ONCE(ctrl->read_offset); + remaining = pvr_cccb->size - pvr_cccb->write_offset; + + /* Always ensure we have enough room for a padding command at the end of the CCCB. + * If our command sequence does not fit, reserve the remaining space for a padding + * command. + */ + if (size + PADDING_COMMAND_SIZE > remaining) + size += remaining; + + if (get_ccb_space(pvr_cccb->write_offset, read_offset, pvr_cccb->size) >= size) + fits = true; + + return fits; +} + +/** + * pvr_cccb_write_command_with_header() - Write a command + command header to a + * Client CCB + * @pvr_cccb: Target Client CCB. + * @cmd_type: Client CCB command type. Must be one of %ROGUE_FWIF_CCB_CMD_TYPE_*. + * @cmd_size: Size of command in bytes. + * @cmd_data: Pointer to command to write. + * @ext_job_ref: External job reference. + * @int_job_ref: Internal job reference. + * + * Caller must make sure there's enough space in CCCB to queue this command. This + * can be done by calling pvr_cccb_cmdseq_fits(). + * + * This function is not protected by any lock. The caller must ensure there's + * no concurrent caller, which should be guaranteed by the drm_sched model (job + * submission is serialized in drm_sched_main()). + */ +void +pvr_cccb_write_command_with_header(struct pvr_cccb *pvr_cccb, u32 cmd_type, u32 cmd_size, + void *cmd_data, u32 ext_job_ref, u32 int_job_ref) +{ + u32 sz_with_hdr = pvr_cccb_get_size_of_cmd_with_hdr(cmd_size); + struct rogue_fwif_ccb_cmd_header cmd_header = { + .cmd_type = cmd_type, + .cmd_size = ALIGN(cmd_size, 8), + .ext_job_ref = ext_job_ref, + .int_job_ref = int_job_ref, + }; + struct rogue_fwif_cccb_ctl *ctrl = pvr_cccb->ctrl; + u32 remaining = pvr_cccb->size - pvr_cccb->write_offset; + u32 required_size, cccb_space, read_offset; + + /* + * Always ensure we have enough room for a padding command at the end of + * the CCCB. + */ + if (remaining < sz_with_hdr + PADDING_COMMAND_SIZE) { + /* + * Command would need to wrap, so we need to pad the remainder + * of the CCCB. + */ + required_size = sz_with_hdr + remaining; + } else { + required_size = sz_with_hdr; + } + + read_offset = READ_ONCE(ctrl->read_offset); + cccb_space = get_ccb_space(pvr_cccb->write_offset, read_offset, pvr_cccb->size); + if (WARN_ON(cccb_space < required_size)) + return; + + if (required_size != sz_with_hdr) { + /* Add padding command */ + struct rogue_fwif_ccb_cmd_header pad_cmd = { + .cmd_type = ROGUE_FWIF_CCB_CMD_TYPE_PADDING, + .cmd_size = remaining - sizeof(pad_cmd), + }; + + memcpy(&pvr_cccb->cccb[pvr_cccb->write_offset], &pad_cmd, sizeof(pad_cmd)); + pvr_cccb->write_offset = 0; + } + + memcpy(&pvr_cccb->cccb[pvr_cccb->write_offset], &cmd_header, sizeof(cmd_header)); + memcpy(&pvr_cccb->cccb[pvr_cccb->write_offset + sizeof(cmd_header)], cmd_data, cmd_size); + pvr_cccb->write_offset += sz_with_hdr; +} + +static void fill_cmd_kick_data(struct pvr_cccb *cccb, u32 ctx_fw_addr, + struct pvr_hwrt_data *hwrt, + struct rogue_fwif_kccb_cmd_kick_data *k) +{ + k->context_fw_addr = ctx_fw_addr; + k->client_woff_update = cccb->write_offset; + k->client_wrap_mask_update = cccb->wrap_mask; + + if (hwrt) { + u32 cleanup_state_offset = offsetof(struct rogue_fwif_hwrtdata, cleanup_state); + + pvr_fw_object_get_fw_addr_offset(hwrt->fw_obj, cleanup_state_offset, + &k->cleanup_ctl_fw_addr[k->num_cleanup_ctl++]); + } +} + +/** + * pvr_cccb_send_kccb_kick: Send KCCB kick to trigger command processing + * @pvr_dev: Device pointer. + * @pvr_cccb: Pointer to CCCB to process. + * @cctx_fw_addr: FW virtual address for context owning this Client CCB. + * @hwrt: HWRT data set associated with this kick. May be %NULL. + * + * You must call pvr_kccb_reserve_slot() and wait for the returned fence to + * signal (if this function didn't return NULL) before calling + * pvr_cccb_send_kccb_kick(). + */ +void +pvr_cccb_send_kccb_kick(struct pvr_device *pvr_dev, + struct pvr_cccb *pvr_cccb, u32 cctx_fw_addr, + struct pvr_hwrt_data *hwrt) +{ + struct rogue_fwif_kccb_cmd cmd_kick = { + .cmd_type = ROGUE_FWIF_KCCB_CMD_KICK, + }; + + fill_cmd_kick_data(pvr_cccb, cctx_fw_addr, hwrt, &cmd_kick.cmd_data.cmd_kick_data); + + /* Make sure the writes to the CCCB are flushed before sending the KICK. */ + wmb(); + + pvr_kccb_send_cmd_reserved_powered(pvr_dev, &cmd_kick, NULL); +} + +void +pvr_cccb_send_kccb_combined_kick(struct pvr_device *pvr_dev, + struct pvr_cccb *geom_cccb, + struct pvr_cccb *frag_cccb, + u32 geom_ctx_fw_addr, + u32 frag_ctx_fw_addr, + struct pvr_hwrt_data *hwrt, + bool frag_is_pr) +{ + struct rogue_fwif_kccb_cmd cmd_kick = { + .cmd_type = ROGUE_FWIF_KCCB_CMD_COMBINED_GEOM_FRAG_KICK, + }; + + fill_cmd_kick_data(geom_cccb, geom_ctx_fw_addr, hwrt, + &cmd_kick.cmd_data.combined_geom_frag_cmd_kick_data.geom_cmd_kick_data); + + /* If this is a partial-render job, we don't attach resources to cleanup-ctl array, + * because the resources are already retained by the geometry job. + */ + fill_cmd_kick_data(frag_cccb, frag_ctx_fw_addr, frag_is_pr ? NULL : hwrt, + &cmd_kick.cmd_data.combined_geom_frag_cmd_kick_data.frag_cmd_kick_data); + + /* Make sure the writes to the CCCB are flushed before sending the KICK. */ + wmb(); + + pvr_kccb_send_cmd_reserved_powered(pvr_dev, &cmd_kick, NULL); +} diff --git a/drivers/gpu/drm/imagination/pvr_cccb.h b/drivers/gpu/drm/imagination/pvr_cccb.h new file mode 100644 index 00000000000000..943fe8f2c963be --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_cccb.h @@ -0,0 +1,110 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_CCCB_H +#define PVR_CCCB_H + +#include "pvr_rogue_fwif.h" +#include "pvr_rogue_fwif_shared.h" + +#include +#include + +#define PADDING_COMMAND_SIZE sizeof(struct rogue_fwif_ccb_cmd_header) + +/* Forward declaration from pvr_device.h. */ +struct pvr_device; + +/* Forward declaration from pvr_gem.h. */ +struct pvr_fw_object; + +/* Forward declaration from pvr_hwrt.h. */ +struct pvr_hwrt_data; + +struct pvr_cccb { + /** @ctrl_obj: FW object representing CCCB control structure. */ + struct pvr_fw_object *ctrl_obj; + + /** @ccb_obj: FW object representing CCCB. */ + struct pvr_fw_object *cccb_obj; + + /** + * @ctrl: Kernel mapping of CCCB control structure. @lock must be held + * when accessing. + */ + struct rogue_fwif_cccb_ctl *ctrl; + + /** @cccb: Kernel mapping of CCCB. @lock must be held when accessing.*/ + u8 *cccb; + + /** @ctrl_fw_addr: FW virtual address of CCCB control structure. */ + u32 ctrl_fw_addr; + /** @ccb_fw_addr: FW virtual address of CCCB. */ + u32 cccb_fw_addr; + + /** @size: Size of CCCB in bytes. */ + size_t size; + + /** @write_offset: CCCB write offset. */ + u32 write_offset; + + /** @wrap_mask: CCCB wrap mask. */ + u32 wrap_mask; +}; + +int pvr_cccb_init(struct pvr_device *pvr_dev, struct pvr_cccb *cccb, + u32 size_log2, const char *name); +void pvr_cccb_fini(struct pvr_cccb *cccb); + +void pvr_cccb_write_command_with_header(struct pvr_cccb *pvr_cccb, + u32 cmd_type, u32 cmd_size, void *cmd_data, + u32 ext_job_ref, u32 int_job_ref); +void pvr_cccb_send_kccb_kick(struct pvr_device *pvr_dev, + struct pvr_cccb *pvr_cccb, u32 cctx_fw_addr, + struct pvr_hwrt_data *hwrt); +void pvr_cccb_send_kccb_combined_kick(struct pvr_device *pvr_dev, + struct pvr_cccb *geom_cccb, + struct pvr_cccb *frag_cccb, + u32 geom_ctx_fw_addr, + u32 frag_ctx_fw_addr, + struct pvr_hwrt_data *hwrt, + bool frag_is_pr); +bool pvr_cccb_cmdseq_fits(struct pvr_cccb *pvr_cccb, size_t size); + +/** + * pvr_cccb_get_size_of_cmd_with_hdr() - Get the size of a command and its header. + * @cmd_size: Command size. + * + * Returns the size of the command and its header. + */ +static __always_inline u32 +pvr_cccb_get_size_of_cmd_with_hdr(u32 cmd_size) +{ + WARN_ON(!IS_ALIGNED(cmd_size, 8)); + return sizeof(struct rogue_fwif_ccb_cmd_header) + ALIGN(cmd_size, 8); +} + +/** + * pvr_cccb_cmdseq_can_fit() - Check if a command sequence can fit in the CCCB. + * @pvr_cccb: Target Client CCB. + * @size: Command sequence size. + * + * Returns: + * * true it the CCCB is big enough to contain a command sequence, or + * * false otherwise. + */ +static __always_inline bool +pvr_cccb_cmdseq_can_fit(struct pvr_cccb *pvr_cccb, size_t size) +{ + /* We divide the capacity by two to simplify our CCCB fencing logic: + * we want to be sure that, no matter what we had queued before, we + * are able to either queue our command sequence at the end or add a + * padding command and queue the command sequence at the beginning + * of the CCCB. If the command sequence size is bigger than half the + * CCCB capacity, we'd have to queue the padding command and make sure + * the FW is done processing it before queueing our command sequence. + */ + return size + PADDING_COMMAND_SIZE <= pvr_cccb->size / 2; +} + +#endif /* PVR_CCCB_H */ diff --git a/drivers/gpu/drm/imagination/pvr_context.c b/drivers/gpu/drm/imagination/pvr_context.c new file mode 100644 index 00000000000000..eded5e955cc0ac --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_context.c @@ -0,0 +1,464 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_cccb.h" +#include "pvr_context.h" +#include "pvr_device.h" +#include "pvr_drv.h" +#include "pvr_gem.h" +#include "pvr_job.h" +#include "pvr_power.h" +#include "pvr_rogue_fwif.h" +#include "pvr_rogue_fwif_common.h" +#include "pvr_rogue_fwif_resetframework.h" +#include "pvr_stream.h" +#include "pvr_stream_defs.h" +#include "pvr_vm.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int +remap_priority(struct pvr_file *pvr_file, s32 uapi_priority, + enum pvr_context_priority *priority_out) +{ + switch (uapi_priority) { + case DRM_PVR_CTX_PRIORITY_LOW: + *priority_out = PVR_CTX_PRIORITY_LOW; + break; + case DRM_PVR_CTX_PRIORITY_NORMAL: + *priority_out = PVR_CTX_PRIORITY_MEDIUM; + break; + case DRM_PVR_CTX_PRIORITY_HIGH: + if (!capable(CAP_SYS_NICE) && !drm_is_current_master(from_pvr_file(pvr_file))) + return -EACCES; + *priority_out = PVR_CTX_PRIORITY_HIGH; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int get_fw_obj_size(enum drm_pvr_ctx_type type) +{ + switch (type) { + case DRM_PVR_CTX_TYPE_RENDER: + return sizeof(struct rogue_fwif_fwrendercontext); + case DRM_PVR_CTX_TYPE_COMPUTE: + return sizeof(struct rogue_fwif_fwcomputecontext); + case DRM_PVR_CTX_TYPE_TRANSFER_FRAG: + return sizeof(struct rogue_fwif_fwtransfercontext); + } + + return -EINVAL; +} + +static int +process_static_context_state(struct pvr_device *pvr_dev, const struct pvr_stream_cmd_defs *cmd_defs, + u64 stream_user_ptr, u32 stream_size, void *dest) +{ + void *stream; + int err; + + stream = kzalloc(stream_size, GFP_KERNEL); + if (!stream) + return -ENOMEM; + + if (copy_from_user(stream, u64_to_user_ptr(stream_user_ptr), stream_size)) { + err = -EFAULT; + goto err_free; + } + + err = pvr_stream_process(pvr_dev, cmd_defs, stream, stream_size, dest); + if (err) + goto err_free; + + kfree(stream); + + return 0; + +err_free: + kfree(stream); + + return err; +} + +static int init_render_fw_objs(struct pvr_context *ctx, + struct drm_pvr_ioctl_create_context_args *args, + void *fw_ctx_map) +{ + struct rogue_fwif_static_rendercontext_state *static_rendercontext_state; + struct rogue_fwif_fwrendercontext *fw_render_context = fw_ctx_map; + + if (!args->static_context_state_len) + return -EINVAL; + + static_rendercontext_state = &fw_render_context->static_render_context_state; + + /* Copy static render context state from userspace. */ + return process_static_context_state(ctx->pvr_dev, + &pvr_static_render_context_state_stream, + args->static_context_state, + args->static_context_state_len, + &static_rendercontext_state->ctxswitch_regs[0]); +} + +static int init_compute_fw_objs(struct pvr_context *ctx, + struct drm_pvr_ioctl_create_context_args *args, + void *fw_ctx_map) +{ + struct rogue_fwif_fwcomputecontext *fw_compute_context = fw_ctx_map; + struct rogue_fwif_cdm_registers_cswitch *ctxswitch_regs; + + if (!args->static_context_state_len) + return -EINVAL; + + ctxswitch_regs = &fw_compute_context->static_compute_context_state.ctxswitch_regs; + + /* Copy static render context state from userspace. */ + return process_static_context_state(ctx->pvr_dev, + &pvr_static_compute_context_state_stream, + args->static_context_state, + args->static_context_state_len, + ctxswitch_regs); +} + +static int init_transfer_fw_objs(struct pvr_context *ctx, + struct drm_pvr_ioctl_create_context_args *args, + void *fw_ctx_map) +{ + if (args->static_context_state_len) + return -EINVAL; + + return 0; +} + +static int init_fw_objs(struct pvr_context *ctx, + struct drm_pvr_ioctl_create_context_args *args, + void *fw_ctx_map) +{ + switch (ctx->type) { + case DRM_PVR_CTX_TYPE_RENDER: + return init_render_fw_objs(ctx, args, fw_ctx_map); + case DRM_PVR_CTX_TYPE_COMPUTE: + return init_compute_fw_objs(ctx, args, fw_ctx_map); + case DRM_PVR_CTX_TYPE_TRANSFER_FRAG: + return init_transfer_fw_objs(ctx, args, fw_ctx_map); + } + + return -EINVAL; +} + +static void +ctx_fw_data_init(void *cpu_ptr, void *priv) +{ + struct pvr_context *ctx = priv; + + memcpy(cpu_ptr, ctx->data, ctx->data_size); +} + +/** + * pvr_context_destroy_queues() - Destroy all queues attached to a context. + * @ctx: Context to destroy queues on. + * + * Should be called when the last reference to a context object is dropped. + * It releases all resources attached to the queues bound to this context. + */ +static void pvr_context_destroy_queues(struct pvr_context *ctx) +{ + switch (ctx->type) { + case DRM_PVR_CTX_TYPE_RENDER: + pvr_queue_destroy(ctx->queues.fragment); + pvr_queue_destroy(ctx->queues.geometry); + break; + case DRM_PVR_CTX_TYPE_COMPUTE: + pvr_queue_destroy(ctx->queues.compute); + break; + case DRM_PVR_CTX_TYPE_TRANSFER_FRAG: + pvr_queue_destroy(ctx->queues.transfer); + break; + } +} + +/** + * pvr_context_create_queues() - Create all queues attached to a context. + * @ctx: Context to create queues on. + * @args: Context creation arguments passed by userspace. + * @fw_ctx_map: CPU mapping of the FW context object. + * + * Return: + * * 0 on success, or + * * A negative error code otherwise. + */ +static int pvr_context_create_queues(struct pvr_context *ctx, + struct drm_pvr_ioctl_create_context_args *args, + void *fw_ctx_map) +{ + int err; + + switch (ctx->type) { + case DRM_PVR_CTX_TYPE_RENDER: + ctx->queues.geometry = pvr_queue_create(ctx, DRM_PVR_JOB_TYPE_GEOMETRY, + args, fw_ctx_map); + if (IS_ERR(ctx->queues.geometry)) { + err = PTR_ERR(ctx->queues.geometry); + ctx->queues.geometry = NULL; + goto err_destroy_queues; + } + + ctx->queues.fragment = pvr_queue_create(ctx, DRM_PVR_JOB_TYPE_FRAGMENT, + args, fw_ctx_map); + if (IS_ERR(ctx->queues.fragment)) { + err = PTR_ERR(ctx->queues.fragment); + ctx->queues.fragment = NULL; + goto err_destroy_queues; + } + return 0; + + case DRM_PVR_CTX_TYPE_COMPUTE: + ctx->queues.compute = pvr_queue_create(ctx, DRM_PVR_JOB_TYPE_COMPUTE, + args, fw_ctx_map); + if (IS_ERR(ctx->queues.compute)) { + err = PTR_ERR(ctx->queues.compute); + ctx->queues.compute = NULL; + goto err_destroy_queues; + } + return 0; + + case DRM_PVR_CTX_TYPE_TRANSFER_FRAG: + ctx->queues.transfer = pvr_queue_create(ctx, DRM_PVR_JOB_TYPE_TRANSFER_FRAG, + args, fw_ctx_map); + if (IS_ERR(ctx->queues.transfer)) { + err = PTR_ERR(ctx->queues.transfer); + ctx->queues.transfer = NULL; + goto err_destroy_queues; + } + return 0; + } + + return -EINVAL; + +err_destroy_queues: + pvr_context_destroy_queues(ctx); + return err; +} + +/** + * pvr_context_kill_queues() - Kill queues attached to context. + * @ctx: Context to kill queues on. + * + * Killing the queues implies making them unusable for future jobs, while still + * letting the currently submitted jobs a chance to finish. Queue resources will + * stay around until pvr_context_destroy_queues() is called. + */ +static void pvr_context_kill_queues(struct pvr_context *ctx) +{ + switch (ctx->type) { + case DRM_PVR_CTX_TYPE_RENDER: + pvr_queue_kill(ctx->queues.fragment); + pvr_queue_kill(ctx->queues.geometry); + break; + case DRM_PVR_CTX_TYPE_COMPUTE: + pvr_queue_kill(ctx->queues.compute); + break; + case DRM_PVR_CTX_TYPE_TRANSFER_FRAG: + pvr_queue_kill(ctx->queues.transfer); + break; + } +} + +/** + * pvr_context_create() - Create a context. + * @pvr_file: File to attach the created context to. + * @args: Context creation arguments. + * + * Return: + * * 0 on success, or + * * A negative error code on failure. + */ +int pvr_context_create(struct pvr_file *pvr_file, struct drm_pvr_ioctl_create_context_args *args) +{ + struct pvr_device *pvr_dev = pvr_file->pvr_dev; + struct pvr_context *ctx; + int ctx_size; + int err; + + /* Context creation flags are currently unused and must be zero. */ + if (args->flags) + return -EINVAL; + + ctx_size = get_fw_obj_size(args->type); + if (ctx_size < 0) + return ctx_size; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->data_size = ctx_size; + ctx->type = args->type; + ctx->flags = args->flags; + ctx->pvr_dev = pvr_dev; + kref_init(&ctx->ref_count); + + err = remap_priority(pvr_file, args->priority, &ctx->priority); + if (err) + goto err_free_ctx; + + ctx->vm_ctx = pvr_vm_context_lookup(pvr_file, args->vm_context_handle); + if (IS_ERR(ctx->vm_ctx)) { + err = PTR_ERR(ctx->vm_ctx); + goto err_free_ctx; + } + + ctx->data = kzalloc(ctx_size, GFP_KERNEL); + if (!ctx->data) { + err = -ENOMEM; + goto err_put_vm; + } + + err = pvr_context_create_queues(ctx, args, ctx->data); + if (err) + goto err_free_ctx_data; + + err = init_fw_objs(ctx, args, ctx->data); + if (err) + goto err_destroy_queues; + + err = pvr_fw_object_create(pvr_dev, ctx_size, PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + ctx_fw_data_init, ctx, &ctx->fw_obj); + if (err) + goto err_free_ctx_data; + + err = xa_alloc(&pvr_dev->ctx_ids, &ctx->ctx_id, ctx, xa_limit_32b, GFP_KERNEL); + if (err) + goto err_destroy_fw_obj; + + err = xa_alloc(&pvr_file->ctx_handles, &args->handle, ctx, xa_limit_32b, GFP_KERNEL); + if (err) { + /* + * It's possible that another thread could have taken a reference on the context at + * this point as it is in the ctx_ids xarray. Therefore instead of directly + * destroying the context, drop a reference instead. + */ + pvr_context_put(ctx); + return err; + } + + return 0; + +err_destroy_fw_obj: + pvr_fw_object_destroy(ctx->fw_obj); + +err_destroy_queues: + pvr_context_destroy_queues(ctx); + +err_free_ctx_data: + kfree(ctx->data); + +err_put_vm: + pvr_vm_context_put(ctx->vm_ctx); + +err_free_ctx: + kfree(ctx); + return err; +} + +static void +pvr_context_release(struct kref *ref_count) +{ + struct pvr_context *ctx = + container_of(ref_count, struct pvr_context, ref_count); + struct pvr_device *pvr_dev = ctx->pvr_dev; + + xa_erase(&pvr_dev->ctx_ids, ctx->ctx_id); + pvr_context_destroy_queues(ctx); + pvr_fw_object_destroy(ctx->fw_obj); + kfree(ctx->data); + pvr_vm_context_put(ctx->vm_ctx); + kfree(ctx); +} + +/** + * pvr_context_put() - Release reference on context + * @ctx: Target context. + */ +void +pvr_context_put(struct pvr_context *ctx) +{ + if (ctx) + kref_put(&ctx->ref_count, pvr_context_release); +} + +/** + * pvr_context_destroy() - Destroy context + * @pvr_file: Pointer to pvr_file structure. + * @handle: Userspace context handle. + * + * Removes context from context list and drops initial reference. Context will + * then be destroyed once all outstanding references are dropped. + * + * Return: + * * 0 on success, or + * * -%EINVAL if context not in context list. + */ +int +pvr_context_destroy(struct pvr_file *pvr_file, u32 handle) +{ + struct pvr_context *ctx = xa_erase(&pvr_file->ctx_handles, handle); + + if (!ctx) + return -EINVAL; + + /* Make sure nothing can be queued to the queues after that point. */ + pvr_context_kill_queues(ctx); + + /* Release the reference held by the handle set. */ + pvr_context_put(ctx); + + return 0; +} + +/** + * pvr_destroy_contexts_for_file: Destroy any contexts associated with the given file + * @pvr_file: Pointer to pvr_file structure. + * + * Removes all contexts associated with @pvr_file from the device context list and drops initial + * references. Contexts will then be destroyed once all outstanding references are dropped. + */ +void pvr_destroy_contexts_for_file(struct pvr_file *pvr_file) +{ + struct pvr_context *ctx; + unsigned long handle; + + xa_for_each(&pvr_file->ctx_handles, handle, ctx) + pvr_context_destroy(pvr_file, handle); +} + +/** + * pvr_context_device_init() - Device level initialization for queue related resources. + * @pvr_dev: The device to initialize. + */ +void pvr_context_device_init(struct pvr_device *pvr_dev) +{ + xa_init_flags(&pvr_dev->ctx_ids, XA_FLAGS_ALLOC1); +} + +/** + * pvr_context_device_fini() - Device level cleanup for queue related resources. + * @pvr_dev: The device to cleanup. + */ +void pvr_context_device_fini(struct pvr_device *pvr_dev) +{ + WARN_ON(!xa_empty(&pvr_dev->ctx_ids)); + xa_destroy(&pvr_dev->ctx_ids); +} diff --git a/drivers/gpu/drm/imagination/pvr_context.h b/drivers/gpu/drm/imagination/pvr_context.h new file mode 100644 index 00000000000000..0c7b97dfa6bafd --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_context.h @@ -0,0 +1,205 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_CONTEXT_H +#define PVR_CONTEXT_H + +#include + +#include +#include +#include +#include +#include +#include + +#include "pvr_cccb.h" +#include "pvr_device.h" +#include "pvr_queue.h" + +/* Forward declaration from pvr_gem.h. */ +struct pvr_fw_object; + +enum pvr_context_priority { + PVR_CTX_PRIORITY_LOW = 0, + PVR_CTX_PRIORITY_MEDIUM, + PVR_CTX_PRIORITY_HIGH, +}; + +/** + * struct pvr_context - Context data + */ +struct pvr_context { + /** @ref_count: Refcount for context. */ + struct kref ref_count; + + /** @pvr_dev: Pointer to owning device. */ + struct pvr_device *pvr_dev; + + /** @vm_ctx: Pointer to associated VM context. */ + struct pvr_vm_context *vm_ctx; + + /** @type: Type of context. */ + enum drm_pvr_ctx_type type; + + /** @flags: Context flags. */ + u32 flags; + + /** @priority: Context priority*/ + enum pvr_context_priority priority; + + /** @fw_obj: FW object representing FW-side context data. */ + struct pvr_fw_object *fw_obj; + + /** @data: Pointer to local copy of FW context data. */ + void *data; + + /** @data_size: Size of FW context data, in bytes. */ + u32 data_size; + + /** @ctx_id: FW context ID. */ + u32 ctx_id; + + /** + * @faulty: Set to 1 when the context queues had unfinished job when + * a GPU reset happened. + * + * In that case, the context is in an inconsistent state and can't be + * used anymore. + */ + atomic_t faulty; + + /** @queues: Union containing all kind of queues. */ + union { + struct { + /** @geometry: Geometry queue. */ + struct pvr_queue *geometry; + + /** @fragment: Fragment queue. */ + struct pvr_queue *fragment; + }; + + /** @compute: Compute queue. */ + struct pvr_queue *compute; + + /** @compute: Transfer queue. */ + struct pvr_queue *transfer; + } queues; +}; + +static __always_inline struct pvr_queue * +pvr_context_get_queue_for_job(struct pvr_context *ctx, enum drm_pvr_job_type type) +{ + switch (type) { + case DRM_PVR_JOB_TYPE_GEOMETRY: + return ctx->type == DRM_PVR_CTX_TYPE_RENDER ? ctx->queues.geometry : NULL; + case DRM_PVR_JOB_TYPE_FRAGMENT: + return ctx->type == DRM_PVR_CTX_TYPE_RENDER ? ctx->queues.fragment : NULL; + case DRM_PVR_JOB_TYPE_COMPUTE: + return ctx->type == DRM_PVR_CTX_TYPE_COMPUTE ? ctx->queues.compute : NULL; + case DRM_PVR_JOB_TYPE_TRANSFER_FRAG: + return ctx->type == DRM_PVR_CTX_TYPE_TRANSFER_FRAG ? ctx->queues.transfer : NULL; + } + + return NULL; +} + +/** + * pvr_context_get() - Take additional reference on context. + * @ctx: Context pointer. + * + * Call pvr_context_put() to release. + * + * Returns: + * * The requested context on success, or + * * %NULL if no context pointer passed. + */ +static __always_inline struct pvr_context * +pvr_context_get(struct pvr_context *ctx) +{ + if (ctx) + kref_get(&ctx->ref_count); + + return ctx; +} + +/** + * pvr_context_lookup() - Lookup context pointer from handle and file. + * @pvr_file: Pointer to pvr_file structure. + * @handle: Context handle. + * + * Takes reference on context. Call pvr_context_put() to release. + * + * Return: + * * The requested context on success, or + * * %NULL on failure (context does not exist, or does not belong to @pvr_file). + */ +static __always_inline struct pvr_context * +pvr_context_lookup(struct pvr_file *pvr_file, u32 handle) +{ + struct pvr_context *ctx; + + /* Take the array lock to protect against context removal. */ + xa_lock(&pvr_file->ctx_handles); + ctx = pvr_context_get(xa_load(&pvr_file->ctx_handles, handle)); + xa_unlock(&pvr_file->ctx_handles); + + return ctx; +} + +/** + * pvr_context_lookup_id() - Lookup context pointer from ID. + * @pvr_dev: Device pointer. + * @id: FW context ID. + * + * Takes reference on context. Call pvr_context_put() to release. + * + * Return: + * * The requested context on success, or + * * %NULL on failure (context does not exist). + */ +static __always_inline struct pvr_context * +pvr_context_lookup_id(struct pvr_device *pvr_dev, u32 id) +{ + struct pvr_context *ctx; + + /* Take the array lock to protect against context removal. */ + xa_lock(&pvr_dev->ctx_ids); + + /* Contexts are removed from the ctx_ids set in the context release path, + * meaning the ref_count reached zero before they get removed. We need + * to make sure we're not trying to acquire a context that's being + * destroyed. + */ + ctx = xa_load(&pvr_dev->ctx_ids, id); + if (!kref_get_unless_zero(&ctx->ref_count)) + ctx = NULL; + + xa_unlock(&pvr_dev->ctx_ids); + + return ctx; +} + +static __always_inline u32 +pvr_context_get_fw_addr(struct pvr_context *ctx) +{ + u32 ctx_fw_addr = 0; + + pvr_fw_object_get_fw_addr(ctx->fw_obj, &ctx_fw_addr); + + return ctx_fw_addr; +} + +void pvr_context_put(struct pvr_context *ctx); + +int pvr_context_create(struct pvr_file *pvr_file, struct drm_pvr_ioctl_create_context_args *args); + +int pvr_context_destroy(struct pvr_file *pvr_file, u32 handle); + +void pvr_destroy_contexts_for_file(struct pvr_file *pvr_file); + +void pvr_context_device_init(struct pvr_device *pvr_dev); + +void pvr_context_device_fini(struct pvr_device *pvr_dev); + +#endif /* PVR_CONTEXT_H */ diff --git a/drivers/gpu/drm/imagination/pvr_debugfs.c b/drivers/gpu/drm/imagination/pvr_debugfs.c new file mode 100644 index 00000000000000..6b77c9b4bde880 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_debugfs.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_debugfs.h" + +#include "pvr_device.h" +#include "pvr_fw_trace.h" +#include "pvr_params.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +static const struct pvr_debugfs_entry pvr_debugfs_entries[] = { + {"pvr_params", pvr_params_debugfs_init}, + {"pvr_fw", pvr_fw_trace_debugfs_init}, +}; + +void +pvr_debugfs_init(struct drm_minor *minor) +{ + struct drm_device *drm_dev = minor->dev; + struct pvr_device *pvr_dev = to_pvr_device(drm_dev); + struct dentry *root = minor->debugfs_root; + size_t i; + + for (i = 0; i < ARRAY_SIZE(pvr_debugfs_entries); ++i) { + const struct pvr_debugfs_entry *entry = &pvr_debugfs_entries[i]; + struct dentry *dir; + + dir = debugfs_create_dir(entry->name, root); + if (IS_ERR(dir)) { + drm_warn(drm_dev, + "failed to create debugfs dir '%s' (err=%d)", + entry->name, (int)PTR_ERR(dir)); + continue; + } + + entry->init(pvr_dev, dir); + } +} + +/* + * Since all entries are created under &drm_minor->debugfs_root, there's no + * need for a pvr_debugfs_fini() as DRM will clean up everything under its root + * automatically. + */ diff --git a/drivers/gpu/drm/imagination/pvr_debugfs.h b/drivers/gpu/drm/imagination/pvr_debugfs.h new file mode 100644 index 00000000000000..ebacbd13b84a00 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_debugfs.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_DEBUGFS_H +#define PVR_DEBUGFS_H + +/* Forward declaration from . */ +struct drm_minor; + +#if defined(CONFIG_DEBUG_FS) +/* Forward declaration from "pvr_device.h". */ +struct pvr_device; + +/* Forward declaration from . */ +struct dentry; + +struct pvr_debugfs_entry { + const char *name; + void (*init)(struct pvr_device *pvr_dev, struct dentry *dir); +}; + +void pvr_debugfs_init(struct drm_minor *minor); +#else /* defined(CONFIG_DEBUG_FS) */ +#include + +static __always_inline void pvr_debugfs_init(struct drm_minor *minor) {} +#endif /* defined(CONFIG_DEBUG_FS) */ + +#endif /* PVR_DEBUGFS_H */ diff --git a/drivers/gpu/drm/imagination/pvr_device.c b/drivers/gpu/drm/imagination/pvr_device.c new file mode 100644 index 00000000000000..1704c0268589bd --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_device.c @@ -0,0 +1,658 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_device.h" +#include "pvr_device_info.h" + +#include "pvr_fw.h" +#include "pvr_params.h" +#include "pvr_power.h" +#include "pvr_queue.h" +#include "pvr_rogue_cr_defs.h" +#include "pvr_stream.h" +#include "pvr_vm.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Major number for the supported version of the firmware. */ +#define PVR_FW_VERSION_MAJOR 1 + +/** + * pvr_device_reg_init() - Initialize kernel access to a PowerVR device's + * control registers. + * @pvr_dev: Target PowerVR device. + * + * Sets struct pvr_device->regs. + * + * This method of mapping the device control registers into memory ensures that + * they are unmapped when the driver is detached (i.e. no explicit cleanup is + * required). + * + * Return: + * * 0 on success, or + * * Any error returned by devm_platform_ioremap_resource(). + */ +static int +pvr_device_reg_init(struct pvr_device *pvr_dev) +{ + struct drm_device *drm_dev = from_pvr_device(pvr_dev); + struct platform_device *plat_dev = to_platform_device(drm_dev->dev); + struct resource *regs_resource; + void __iomem *regs; + + pvr_dev->regs_resource = NULL; + pvr_dev->regs = NULL; + + regs = devm_platform_get_and_ioremap_resource(plat_dev, 0, ®s_resource); + if (IS_ERR(regs)) + return dev_err_probe(drm_dev->dev, PTR_ERR(regs), + "failed to ioremap gpu registers\n"); + + pvr_dev->regs = regs; + pvr_dev->regs_resource = regs_resource; + + return 0; +} + +/** + * pvr_device_clk_init() - Initialize clocks required by a PowerVR device + * @pvr_dev: Target PowerVR device. + * + * Sets struct pvr_device->core_clk, struct pvr_device->sys_clk and + * struct pvr_device->mem_clk. + * + * Three clocks are required by the PowerVR device: core, sys and mem. On + * return, this function guarantees that the clocks are in one of the following + * states: + * + * * All successfully initialized, + * * Core errored, sys and mem uninitialized, + * * Core deinitialized, sys errored, mem uninitialized, or + * * Core and sys deinitialized, mem errored. + * + * Return: + * * 0 on success, + * * Any error returned by devm_clk_get(), or + * * Any error returned by devm_clk_get_optional(). + */ +static int pvr_device_clk_init(struct pvr_device *pvr_dev) +{ + struct drm_device *drm_dev = from_pvr_device(pvr_dev); + struct clk *core_clk; + struct clk *sys_clk; + struct clk *mem_clk; + + core_clk = devm_clk_get(drm_dev->dev, "core"); + if (IS_ERR(core_clk)) + return dev_err_probe(drm_dev->dev, PTR_ERR(core_clk), + "failed to get core clock\n"); + + sys_clk = devm_clk_get_optional(drm_dev->dev, "sys"); + if (IS_ERR(sys_clk)) + return dev_err_probe(drm_dev->dev, PTR_ERR(sys_clk), + "failed to get sys clock\n"); + + mem_clk = devm_clk_get_optional(drm_dev->dev, "mem"); + if (IS_ERR(mem_clk)) + return dev_err_probe(drm_dev->dev, PTR_ERR(mem_clk), + "failed to get mem clock\n"); + + pvr_dev->core_clk = core_clk; + pvr_dev->sys_clk = sys_clk; + pvr_dev->mem_clk = mem_clk; + + return 0; +} + +/** + * pvr_device_process_active_queues() - Process all queue related events. + * @pvr_dev: PowerVR device to check + * + * This is called any time we receive a FW event. It iterates over all + * active queues and calls pvr_queue_process() on them. + */ +static void pvr_device_process_active_queues(struct pvr_device *pvr_dev) +{ + struct pvr_queue *queue, *tmp_queue; + LIST_HEAD(active_queues); + + mutex_lock(&pvr_dev->queues.lock); + + /* Move all active queues to a temporary list. Queues that remain + * active after we're done processing them are re-inserted to + * the queues.active list by pvr_queue_process(). + */ + list_splice_init(&pvr_dev->queues.active, &active_queues); + + list_for_each_entry_safe(queue, tmp_queue, &active_queues, node) + pvr_queue_process(queue); + + mutex_unlock(&pvr_dev->queues.lock); +} + +static irqreturn_t pvr_device_irq_thread_handler(int irq, void *data) +{ + struct pvr_device *pvr_dev = data; + irqreturn_t ret = IRQ_NONE; + + /* We are in the threaded handler, we can keep dequeuing events until we + * don't see any. This should allow us to reduce the number of interrupts + * when the GPU is receiving a massive amount of short jobs. + */ + while (pvr_fw_irq_pending(pvr_dev)) { + pvr_fw_irq_clear(pvr_dev); + + if (pvr_dev->fw_dev.booted) { + pvr_fwccb_process(pvr_dev); + pvr_kccb_wake_up_waiters(pvr_dev); + pvr_device_process_active_queues(pvr_dev); + } + + pm_runtime_mark_last_busy(from_pvr_device(pvr_dev)->dev); + + ret = IRQ_HANDLED; + } + + /* Unmask FW irqs before returning, so new interrupts can be received. */ + pvr_fw_irq_enable(pvr_dev); + return ret; +} + +static irqreturn_t pvr_device_irq_handler(int irq, void *data) +{ + struct pvr_device *pvr_dev = data; + + if (!pvr_fw_irq_pending(pvr_dev)) + return IRQ_NONE; /* Spurious IRQ - ignore. */ + + /* Mask the FW interrupts before waking up the thread. Will be unmasked + * when the thread handler is done processing events. + */ + pvr_fw_irq_disable(pvr_dev); + return IRQ_WAKE_THREAD; +} + +/** + * pvr_device_irq_init() - Initialise IRQ required by a PowerVR device + * @pvr_dev: Target PowerVR device. + * + * Returns: + * * 0 on success, + * * Any error returned by platform_get_irq_byname(), or + * * Any error returned by request_irq(). + */ +static int +pvr_device_irq_init(struct pvr_device *pvr_dev) +{ + struct drm_device *drm_dev = from_pvr_device(pvr_dev); + struct platform_device *plat_dev = to_platform_device(drm_dev->dev); + + init_waitqueue_head(&pvr_dev->kccb.rtn_q); + + pvr_dev->irq = platform_get_irq(plat_dev, 0); + if (pvr_dev->irq < 0) + return pvr_dev->irq; + + /* Clear any pending events before requesting the IRQ line. */ + pvr_fw_irq_clear(pvr_dev); + pvr_fw_irq_enable(pvr_dev); + + return request_threaded_irq(pvr_dev->irq, pvr_device_irq_handler, + pvr_device_irq_thread_handler, + IRQF_SHARED, "gpu", pvr_dev); +} + +/** + * pvr_device_irq_fini() - Deinitialise IRQ required by a PowerVR device + * @pvr_dev: Target PowerVR device. + */ +static void +pvr_device_irq_fini(struct pvr_device *pvr_dev) +{ + free_irq(pvr_dev->irq, pvr_dev); +} + +/** + * pvr_build_firmware_filename() - Construct a PowerVR firmware filename + * @pvr_dev: Target PowerVR device. + * @base: First part of the filename. + * @major: Major version number. + * + * A PowerVR firmware filename consists of three parts separated by underscores + * (``'_'``) along with a '.fw' file suffix. The first part is the exact value + * of @base, the second part is the hardware version string derived from @pvr_fw + * and the final part is the firmware version number constructed from @major with + * a 'v' prefix, e.g. powervr/rogue_4.40.2.51_v1.fw. + * + * The returned string will have been slab allocated and must be freed with + * kfree(). + * + * Return: + * * The constructed filename on success, or + * * Any error returned by kasprintf(). + */ +static char * +pvr_build_firmware_filename(struct pvr_device *pvr_dev, const char *base, + u8 major) +{ + struct pvr_gpu_id *gpu_id = &pvr_dev->gpu_id; + + return kasprintf(GFP_KERNEL, "%s_%d.%d.%d.%d_v%d.fw", base, gpu_id->b, + gpu_id->v, gpu_id->n, gpu_id->c, major); +} + +static void +pvr_release_firmware(void *data) +{ + struct pvr_device *pvr_dev = data; + + release_firmware(pvr_dev->fw_dev.firmware); +} + +/** + * pvr_request_firmware() - Load firmware for a PowerVR device + * @pvr_dev: Target PowerVR device. + * + * See pvr_build_firmware_filename() for details on firmware file naming. + * + * Return: + * * 0 on success, + * * Any error returned by pvr_build_firmware_filename(), or + * * Any error returned by request_firmware(). + */ +static int +pvr_request_firmware(struct pvr_device *pvr_dev) +{ + struct drm_device *drm_dev = &pvr_dev->base; + char *filename; + const struct firmware *fw; + int err; + + filename = pvr_build_firmware_filename(pvr_dev, "powervr/rogue", + PVR_FW_VERSION_MAJOR); + if (!filename) + return -ENOMEM; + + /* + * This function takes a copy of &filename, meaning we can free our + * instance before returning. + */ + err = request_firmware(&fw, filename, pvr_dev->base.dev); + if (err) { + drm_err(drm_dev, "failed to load firmware %s (err=%d)\n", + filename, err); + goto err_free_filename; + } + + drm_info(drm_dev, "loaded firmware %s\n", filename); + kfree(filename); + + pvr_dev->fw_dev.firmware = fw; + + return devm_add_action_or_reset(drm_dev->dev, pvr_release_firmware, pvr_dev); + +err_free_filename: + kfree(filename); + + return err; +} + +/** + * pvr_load_gpu_id() - Load a PowerVR device's GPU ID (BVNC) from control registers. + * + * Sets struct pvr_dev.gpu_id. + * + * @pvr_dev: Target PowerVR device. + */ +static void +pvr_load_gpu_id(struct pvr_device *pvr_dev) +{ + struct pvr_gpu_id *gpu_id = &pvr_dev->gpu_id; + u64 bvnc; + + /* + * Try reading the BVNC using the newer (cleaner) method first. If the + * B value is zero, fall back to the older method. + */ + bvnc = pvr_cr_read64(pvr_dev, ROGUE_CR_CORE_ID__PBVNC); + + gpu_id->b = PVR_CR_FIELD_GET(bvnc, CORE_ID__PBVNC__BRANCH_ID); + if (gpu_id->b != 0) { + gpu_id->v = PVR_CR_FIELD_GET(bvnc, CORE_ID__PBVNC__VERSION_ID); + gpu_id->n = PVR_CR_FIELD_GET(bvnc, CORE_ID__PBVNC__NUMBER_OF_SCALABLE_UNITS); + gpu_id->c = PVR_CR_FIELD_GET(bvnc, CORE_ID__PBVNC__CONFIG_ID); + } else { + u32 core_rev = pvr_cr_read32(pvr_dev, ROGUE_CR_CORE_REVISION); + u32 core_id = pvr_cr_read32(pvr_dev, ROGUE_CR_CORE_ID); + u16 core_id_config = PVR_CR_FIELD_GET(core_id, CORE_ID_CONFIG); + + gpu_id->b = PVR_CR_FIELD_GET(core_rev, CORE_REVISION_MAJOR); + gpu_id->v = PVR_CR_FIELD_GET(core_rev, CORE_REVISION_MINOR); + gpu_id->n = FIELD_GET(0xFF00, core_id_config); + gpu_id->c = FIELD_GET(0x00FF, core_id_config); + } +} + +/** + * pvr_set_dma_info() - Set PowerVR device DMA information + * @pvr_dev: Target PowerVR device. + * + * Sets the DMA mask and max segment size for the PowerVR device. + * + * Return: + * * 0 on success, + * * Any error returned by PVR_FEATURE_VALUE(), or + * * Any error returned by dma_set_mask(). + */ + +static int +pvr_set_dma_info(struct pvr_device *pvr_dev) +{ + struct drm_device *drm_dev = from_pvr_device(pvr_dev); + u16 phys_bus_width; + int err; + + err = PVR_FEATURE_VALUE(pvr_dev, phys_bus_width, &phys_bus_width); + if (err) { + drm_err(drm_dev, "Failed to get device physical bus width\n"); + return err; + } + + err = dma_set_mask(drm_dev->dev, DMA_BIT_MASK(phys_bus_width)); + if (err) { + drm_err(drm_dev, "Failed to set DMA mask (err=%d)\n", err); + return err; + } + + dma_set_max_seg_size(drm_dev->dev, UINT_MAX); + + return 0; +} + +/** + * pvr_device_gpu_init() - GPU-specific initialization for a PowerVR device + * @pvr_dev: Target PowerVR device. + * + * The following steps are taken to ensure the device is ready: + * + * 1. Read the hardware version information from control registers, + * 2. Initialise the hardware feature information, + * 3. Setup the device DMA information, + * 4. Setup the device-scoped memory context, and + * 5. Load firmware into the device. + * + * Return: + * * 0 on success, + * * -%ENODEV if the GPU is not supported, + * * Any error returned by pvr_set_dma_info(), + * * Any error returned by pvr_memory_context_init(), or + * * Any error returned by pvr_request_firmware(). + */ +static int +pvr_device_gpu_init(struct pvr_device *pvr_dev) +{ + int err; + + pvr_load_gpu_id(pvr_dev); + + err = pvr_request_firmware(pvr_dev); + if (err) + return err; + + err = pvr_fw_validate_init_device_info(pvr_dev); + if (err) + return err; + + if (PVR_HAS_FEATURE(pvr_dev, meta)) + pvr_dev->fw_dev.processor_type = PVR_FW_PROCESSOR_TYPE_META; + else if (PVR_HAS_FEATURE(pvr_dev, mips)) + pvr_dev->fw_dev.processor_type = PVR_FW_PROCESSOR_TYPE_MIPS; + else if (PVR_HAS_FEATURE(pvr_dev, riscv_fw_processor)) + pvr_dev->fw_dev.processor_type = PVR_FW_PROCESSOR_TYPE_RISCV; + else + return -EINVAL; + + pvr_stream_create_musthave_masks(pvr_dev); + + err = pvr_set_dma_info(pvr_dev); + if (err) + return err; + + if (pvr_dev->fw_dev.processor_type != PVR_FW_PROCESSOR_TYPE_MIPS) { + pvr_dev->kernel_vm_ctx = pvr_vm_create_context(pvr_dev, false); + if (IS_ERR(pvr_dev->kernel_vm_ctx)) + return PTR_ERR(pvr_dev->kernel_vm_ctx); + } + + err = pvr_fw_init(pvr_dev); + if (err) + goto err_vm_ctx_put; + + return 0; + +err_vm_ctx_put: + if (pvr_dev->fw_dev.processor_type != PVR_FW_PROCESSOR_TYPE_MIPS) { + pvr_vm_context_put(pvr_dev->kernel_vm_ctx); + pvr_dev->kernel_vm_ctx = NULL; + } + + return err; +} + +/** + * pvr_device_gpu_fini() - GPU-specific deinitialization for a PowerVR device + * @pvr_dev: Target PowerVR device. + */ +static void +pvr_device_gpu_fini(struct pvr_device *pvr_dev) +{ + pvr_fw_fini(pvr_dev); + + if (pvr_dev->fw_dev.processor_type != PVR_FW_PROCESSOR_TYPE_MIPS) { + WARN_ON(!pvr_vm_context_put(pvr_dev->kernel_vm_ctx)); + pvr_dev->kernel_vm_ctx = NULL; + } +} + +/** + * pvr_device_init() - Initialize a PowerVR device + * @pvr_dev: Target PowerVR device. + * + * If this function returns successfully, the device will have been fully + * initialized. Otherwise, any parts of the device initialized before an error + * occurs will be de-initialized before returning. + * + * NOTE: The initialization steps currently taken are the bare minimum required + * to read from the control registers. The device is unlikely to function + * until further initialization steps are added. [This note should be + * removed when that happens.] + * + * Return: + * * 0 on success, + * * Any error returned by pvr_device_reg_init(), + * * Any error returned by pvr_device_clk_init(), or + * * Any error returned by pvr_device_gpu_init(). + */ +int +pvr_device_init(struct pvr_device *pvr_dev) +{ + struct drm_device *drm_dev = from_pvr_device(pvr_dev); + struct device *dev = drm_dev->dev; + int err; + + /* + * Setup device parameters. We do this first in case other steps + * depend on them. + */ + err = pvr_device_params_init(&pvr_dev->params); + if (err) + return err; + + /* Enable and initialize clocks required for the device to operate. */ + err = pvr_device_clk_init(pvr_dev); + if (err) + return err; + + /* Explicitly power the GPU so we can access control registers before the FW is booted. */ + err = pm_runtime_resume_and_get(dev); + if (err) + return err; + + /* Map the control registers into memory. */ + err = pvr_device_reg_init(pvr_dev); + if (err) + goto err_pm_runtime_put; + + /* Perform GPU-specific initialization steps. */ + err = pvr_device_gpu_init(pvr_dev); + if (err) + goto err_pm_runtime_put; + + err = pvr_device_irq_init(pvr_dev); + if (err) + goto err_device_gpu_fini; + + pm_runtime_put(dev); + + return 0; + +err_device_gpu_fini: + pvr_device_gpu_fini(pvr_dev); + +err_pm_runtime_put: + pm_runtime_put_sync_suspend(dev); + + return err; +} + +/** + * pvr_device_fini() - Deinitialize a PowerVR device + * @pvr_dev: Target PowerVR device. + */ +void +pvr_device_fini(struct pvr_device *pvr_dev) +{ + /* + * Deinitialization stages are performed in reverse order compared to + * the initialization stages in pvr_device_init(). + */ + pvr_device_irq_fini(pvr_dev); + pvr_device_gpu_fini(pvr_dev); +} + +bool +pvr_device_has_uapi_quirk(struct pvr_device *pvr_dev, u32 quirk) +{ + switch (quirk) { + case 47217: + return PVR_HAS_QUIRK(pvr_dev, 47217); + case 48545: + return PVR_HAS_QUIRK(pvr_dev, 48545); + case 49927: + return PVR_HAS_QUIRK(pvr_dev, 49927); + case 51764: + return PVR_HAS_QUIRK(pvr_dev, 51764); + case 62269: + return PVR_HAS_QUIRK(pvr_dev, 62269); + default: + return false; + }; +} + +bool +pvr_device_has_uapi_enhancement(struct pvr_device *pvr_dev, u32 enhancement) +{ + switch (enhancement) { + case 35421: + return PVR_HAS_ENHANCEMENT(pvr_dev, 35421); + case 42064: + return PVR_HAS_ENHANCEMENT(pvr_dev, 42064); + default: + return false; + }; +} + +/** + * pvr_device_has_feature() - Look up device feature based on feature definition + * @pvr_dev: Device pointer. + * @feature: Feature to look up. Should be one of %PVR_FEATURE_*. + * + * Returns: + * * %true if feature is present on device, or + * * %false if feature is not present on device. + */ +bool +pvr_device_has_feature(struct pvr_device *pvr_dev, u32 feature) +{ + switch (feature) { + case PVR_FEATURE_CLUSTER_GROUPING: + return PVR_HAS_FEATURE(pvr_dev, cluster_grouping); + + case PVR_FEATURE_COMPUTE_MORTON_CAPABLE: + return PVR_HAS_FEATURE(pvr_dev, compute_morton_capable); + + case PVR_FEATURE_FB_CDC_V4: + return PVR_HAS_FEATURE(pvr_dev, fb_cdc_v4); + + case PVR_FEATURE_GPU_MULTICORE_SUPPORT: + return PVR_HAS_FEATURE(pvr_dev, gpu_multicore_support); + + case PVR_FEATURE_ISP_ZLS_D24_S8_PACKING_OGL_MODE: + return PVR_HAS_FEATURE(pvr_dev, isp_zls_d24_s8_packing_ogl_mode); + + case PVR_FEATURE_S7_TOP_INFRASTRUCTURE: + return PVR_HAS_FEATURE(pvr_dev, s7_top_infrastructure); + + case PVR_FEATURE_TESSELLATION: + return PVR_HAS_FEATURE(pvr_dev, tessellation); + + case PVR_FEATURE_TPU_DM_GLOBAL_REGISTERS: + return PVR_HAS_FEATURE(pvr_dev, tpu_dm_global_registers); + + case PVR_FEATURE_VDM_DRAWINDIRECT: + return PVR_HAS_FEATURE(pvr_dev, vdm_drawindirect); + + case PVR_FEATURE_VDM_OBJECT_LEVEL_LLS: + return PVR_HAS_FEATURE(pvr_dev, vdm_object_level_lls); + + case PVR_FEATURE_ZLS_SUBTILE: + return PVR_HAS_FEATURE(pvr_dev, zls_subtile); + + /* Derived features. */ + case PVR_FEATURE_CDM_USER_MODE_QUEUE: { + u8 cdm_control_stream_format = 0; + + PVR_FEATURE_VALUE(pvr_dev, cdm_control_stream_format, &cdm_control_stream_format); + return (cdm_control_stream_format >= 2 && cdm_control_stream_format <= 4); + } + + case PVR_FEATURE_REQUIRES_FB_CDC_ZLS_SETUP: + if (PVR_HAS_FEATURE(pvr_dev, fbcdc_algorithm)) { + u8 fbcdc_algorithm = 0; + + PVR_FEATURE_VALUE(pvr_dev, fbcdc_algorithm, &fbcdc_algorithm); + return (fbcdc_algorithm < 3 || PVR_HAS_FEATURE(pvr_dev, fb_cdc_v4)); + } + return false; + + default: + WARN(true, "Looking up undefined feature %u\n", feature); + return false; + } +} diff --git a/drivers/gpu/drm/imagination/pvr_device.h b/drivers/gpu/drm/imagination/pvr_device.h new file mode 100644 index 00000000000000..ecdd5767d8ef53 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_device.h @@ -0,0 +1,725 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_DEVICE_H +#define PVR_DEVICE_H + +#include "pvr_ccb.h" +#include "pvr_device_info.h" +#include "pvr_fw.h" +#include "pvr_params.h" +#include "pvr_rogue_fwif_stream.h" +#include "pvr_stream.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Forward declaration from . */ +struct clk; + +/* Forward declaration from . */ +struct firmware; + +/** + * struct pvr_gpu_id - Hardware GPU ID information for a PowerVR device + * @b: Branch ID. + * @v: Version ID. + * @n: Number of scalable units. + * @c: Config ID. + */ +struct pvr_gpu_id { + u16 b, v, n, c; +}; + +/** + * struct pvr_fw_version - Firmware version information + * @major: Major version number. + * @minor: Minor version number. + */ +struct pvr_fw_version { + u16 major, minor; +}; + +/** + * struct pvr_device - powervr-specific wrapper for &struct drm_device + */ +struct pvr_device { + /** + * @base: The underlying &struct drm_device. + * + * Do not access this member directly, instead call + * from_pvr_device(). + */ + struct drm_device base; + + /** @gpu_id: GPU ID detected at runtime. */ + struct pvr_gpu_id gpu_id; + + /** + * @features: Hardware feature information. + * + * Do not access this member directly, instead use PVR_HAS_FEATURE() + * or PVR_FEATURE_VALUE() macros. + */ + struct pvr_device_features features; + + /** + * @quirks: Hardware quirk information. + * + * Do not access this member directly, instead use PVR_HAS_QUIRK(). + */ + struct pvr_device_quirks quirks; + + /** + * @enhancements: Hardware enhancement information. + * + * Do not access this member directly, instead use + * PVR_HAS_ENHANCEMENT(). + */ + struct pvr_device_enhancements enhancements; + + /** @fw_version: Firmware version detected at runtime. */ + struct pvr_fw_version fw_version; + + /** @regs_resource: Resource representing device control registers. */ + struct resource *regs_resource; + + /** + * @regs: Device control registers. + * + * These are mapped into memory when the device is initialized; that + * location is where this pointer points. + */ + void __iomem *regs; + + /** + * @core_clk: General core clock. + * + * This is the primary clock used by the entire GPU core. + */ + struct clk *core_clk; + + /** + * @sys_clk: Optional system bus clock. + * + * This may be used on some platforms to provide an independent clock to the SoC Interface + * (SOCIF). If present, this needs to be enabled/disabled together with @core_clk. + */ + struct clk *sys_clk; + + /** + * @mem_clk: Optional memory clock. + * + * This may be used on some platforms to provide an independent clock to the Memory + * Interface (MEMIF). If present, this needs to be enabled/disabled together with @core_clk. + */ + struct clk *mem_clk; + + /** @irq: IRQ number. */ + int irq; + + /** @fwccb: Firmware CCB. */ + struct pvr_ccb fwccb; + + /** + * @kernel_vm_ctx: Virtual memory context used for kernel mappings. + * + * This is used for mappings in the firmware address region when a META firmware processor + * is in use. + * + * When a MIPS firmware processor is in use, this will be %NULL. + */ + struct pvr_vm_context *kernel_vm_ctx; + + /** @fw_dev: Firmware related data. */ + struct pvr_fw_device fw_dev; + + /** + * @params: Device-specific parameters. + * + * The values of these parameters are initialized from the + * defaults specified as module parameters. They may be + * modified at runtime via debugfs (if enabled). + */ + struct pvr_device_params params; + + /** @stream_musthave_quirks: Bit array of "must-have" quirks for stream commands. */ + u32 stream_musthave_quirks[PVR_STREAM_TYPE_MAX][PVR_STREAM_EXTHDR_TYPE_MAX]; + + /** + * @mmu_flush_cache_flags: Records which MMU caches require flushing + * before submitting the next job. + */ + atomic_t mmu_flush_cache_flags; + + /** + * @ctx_ids: Array of contexts belonging to this device. Array members + * are of type "struct pvr_context *". + * + * This array is used to allocate IDs used by the firmware. + */ + struct xarray ctx_ids; + + /** + * @free_list_ids: Array of free lists belonging to this device. Array members + * are of type "struct pvr_free_list *". + * + * This array is used to allocate IDs used by the firmware. + */ + struct xarray free_list_ids; + + /** + * @job_ids: Array of jobs belonging to this device. Array members + * are of type "struct pvr_job *". + */ + struct xarray job_ids; + + /** + * @queues: Queue-related fields. + */ + struct { + /** @queues.active: Active queue list. */ + struct list_head active; + + /** @queues.idle: Idle queue list. */ + struct list_head idle; + + /** @queues.lock: Lock protecting access to the active/idle + * lists. */ + struct mutex lock; + } queues; + + /** + * @watchdog: Watchdog for communications with firmware. + */ + struct { + /** @watchdog.work: Work item for watchdog callback. */ + struct delayed_work work; + + /** + * @watchdog.old_kccb_cmds_executed: KCCB command execution + * count at last watchdog poll. + */ + u32 old_kccb_cmds_executed; + + /** + * @watchdog.kccb_stall_count: Number of watchdog polls + * KCCB has been stalled for. + */ + u32 kccb_stall_count; + } watchdog; + + /** + * @kccb: Circular buffer for communications with firmware. + */ + struct { + /** @kccb.ccb: Kernel CCB. */ + struct pvr_ccb ccb; + + /** @kccb.rtn_q: Waitqueue for KCCB command return waiters. */ + wait_queue_head_t rtn_q; + + /** @kccb.rtn_obj: Object representing KCCB return slots. */ + struct pvr_fw_object *rtn_obj; + + /** + * @kccb.rtn: Pointer to CPU mapping of KCCB return slots. + * Must be accessed by READ_ONCE()/WRITE_ONCE(). + */ + u32 *rtn; + + /** @kccb.slot_count: Total number of KCCB slots available. */ + u32 slot_count; + + /** @kccb.reserved_count: Number of KCCB slots reserved for + * future use. */ + u32 reserved_count; + + /** + * @kccb.waiters: List of KCCB slot waiters. + */ + struct list_head waiters; + + /** @kccb.fence_ctx: KCCB fence context. */ + struct { + /** @kccb.fence_ctx.id: KCCB fence context ID + * allocated with dma_fence_context_alloc(). */ + u64 id; + + /** @kccb.fence_ctx.seqno: Sequence number incremented + * each time a fence is created. */ + atomic_t seqno; + + /** + * @kccb.fence_ctx.lock: Lock used to synchronize + * access to fences allocated by this context. + */ + spinlock_t lock; + } fence_ctx; + } kccb; + + /** + * @lost: %true if the device has been lost. + * + * This variable is set if the device has become irretrievably unavailable, e.g. if the + * firmware processor has stopped responding and can not be revived via a hard reset. + */ + bool lost; + + /** + * @reset_sem: Reset semaphore. + * + * GPU reset code will lock this for writing. Any code that submits commands to the firmware + * that isn't in an IRQ handler or on the scheduler workqueue must lock this for reading. + * Once this has been successfully locked, &pvr_dev->lost _must_ be checked, and -%EIO must + * be returned if it is set. + */ + struct rw_semaphore reset_sem; + + /** @sched_wq: Workqueue for schedulers. */ + struct workqueue_struct *sched_wq; +}; + +/** + * struct pvr_file - powervr-specific data to be assigned to &struct + * drm_file.driver_priv + */ +struct pvr_file { + /** + * @file: A reference to the parent &struct drm_file. + * + * Do not access this member directly, instead call from_pvr_file(). + */ + struct drm_file *file; + + /** + * @pvr_dev: A reference to the powervr-specific wrapper for the + * associated device. Saves on repeated calls to to_pvr_device(). + */ + struct pvr_device *pvr_dev; + + /** + * @ctx_handles: Array of contexts belonging to this file. Array members + * are of type "struct pvr_context *". + * + * This array is used to allocate handles returned to userspace. + */ + struct xarray ctx_handles; + + /** + * @free_list_handles: Array of free lists belonging to this file. Array + * members are of type "struct pvr_free_list *". + * + * This array is used to allocate handles returned to userspace. + */ + struct xarray free_list_handles; + + /** + * @hwrt_handles: Array of HWRT datasets belonging to this file. Array + * members are of type "struct pvr_hwrt_dataset *". + * + * This array is used to allocate handles returned to userspace. + */ + struct xarray hwrt_handles; + + /** + * @vm_ctx_handles: Array of VM contexts belonging to this file. Array + * members are of type "struct pvr_vm_context *". + * + * This array is used to allocate handles returned to userspace. + */ + struct xarray vm_ctx_handles; +}; + +/** + * PVR_HAS_FEATURE() - Tests whether a PowerVR device has a given feature + * @pvr_dev: [IN] Target PowerVR device. + * @feature: [IN] Hardware feature name. + * + * Feature names are derived from those found in &struct pvr_device_features by + * dropping the 'has_' prefix, which is applied by this macro. + * + * Return: + * * true if the named feature is present in the hardware + * * false if the named feature is not present in the hardware + */ +#define PVR_HAS_FEATURE(pvr_dev, feature) ((pvr_dev)->features.has_##feature) + +/** + * PVR_FEATURE_VALUE() - Gets a PowerVR device feature value + * @pvr_dev: [IN] Target PowerVR device. + * @feature: [IN] Feature name. + * @value_out: [OUT] Feature value. + * + * This macro will get a feature value for those features that have values. + * If the feature is not present, nothing will be stored to @value_out. + * + * Feature names are derived from those found in &struct pvr_device_features by + * dropping the 'has_' prefix. + * + * Return: + * * 0 on success, or + * * -%EINVAL if the named feature is not present in the hardware + */ +#define PVR_FEATURE_VALUE(pvr_dev, feature, value_out) \ + ({ \ + struct pvr_device *_pvr_dev = pvr_dev; \ + int _ret = -EINVAL; \ + if (_pvr_dev->features.has_##feature) { \ + *(value_out) = _pvr_dev->features.feature; \ + _ret = 0; \ + } \ + _ret; \ + }) + +/** + * PVR_HAS_QUIRK() - Tests whether a physical device has a given quirk + * @pvr_dev: [IN] Target PowerVR device. + * @quirk: [IN] Hardware quirk name. + * + * Quirk numbers are derived from those found in #pvr_device_quirks by + * dropping the 'has_brn' prefix, which is applied by this macro. + * + * Returns + * * true if the quirk is present in the hardware, or + * * false if the quirk is not present in the hardware. + */ +#define PVR_HAS_QUIRK(pvr_dev, quirk) ((pvr_dev)->quirks.has_brn##quirk) + +/** + * PVR_HAS_ENHANCEMENT() - Tests whether a physical device has a given + * enhancement + * @pvr_dev: [IN] Target PowerVR device. + * @enhancement: [IN] Hardware enhancement name. + * + * Enhancement numbers are derived from those found in #pvr_device_enhancements + * by dropping the 'has_ern' prefix, which is applied by this macro. + * + * Returns + * * true if the enhancement is present in the hardware, or + * * false if the enhancement is not present in the hardware. + */ +#define PVR_HAS_ENHANCEMENT(pvr_dev, enhancement) ((pvr_dev)->enhancements.has_ern##enhancement) + +#define from_pvr_device(pvr_dev) (&(pvr_dev)->base) + +#define to_pvr_device(drm_dev) container_of_const(drm_dev, struct pvr_device, base) + +#define from_pvr_file(pvr_file) ((pvr_file)->file) + +#define to_pvr_file(file) ((file)->driver_priv) + +/** + * PVR_PACKED_BVNC() - Packs B, V, N and C values into a 64-bit unsigned integer + * @b: Branch ID. + * @v: Version ID. + * @n: Number of scalable units. + * @c: Config ID. + * + * The packed layout is as follows: + * + * +--------+--------+--------+-------+ + * | 63..48 | 47..32 | 31..16 | 15..0 | + * +========+========+========+=======+ + * | B | V | N | C | + * +--------+--------+--------+-------+ + * + * pvr_gpu_id_to_packed_bvnc() should be used instead of this macro when a + * &struct pvr_gpu_id is available in order to ensure proper type checking. + * + * Return: Packed BVNC. + */ +/* clang-format off */ +#define PVR_PACKED_BVNC(b, v, n, c) \ + ((((u64)(b) & GENMASK_ULL(15, 0)) << 48) | \ + (((u64)(v) & GENMASK_ULL(15, 0)) << 32) | \ + (((u64)(n) & GENMASK_ULL(15, 0)) << 16) | \ + (((u64)(c) & GENMASK_ULL(15, 0)) << 0)) +/* clang-format on */ + +/** + * pvr_gpu_id_to_packed_bvnc() - Packs B, V, N and C values into a 64-bit + * unsigned integer + * @gpu_id: GPU ID. + * + * The packed layout is as follows: + * + * +--------+--------+--------+-------+ + * | 63..48 | 47..32 | 31..16 | 15..0 | + * +========+========+========+=======+ + * | B | V | N | C | + * +--------+--------+--------+-------+ + * + * This should be used in preference to PVR_PACKED_BVNC() when a &struct + * pvr_gpu_id is available in order to ensure proper type checking. + * + * Return: Packed BVNC. + */ +static __always_inline u64 +pvr_gpu_id_to_packed_bvnc(struct pvr_gpu_id *gpu_id) +{ + return PVR_PACKED_BVNC(gpu_id->b, gpu_id->v, gpu_id->n, gpu_id->c); +} + +static __always_inline void +packed_bvnc_to_pvr_gpu_id(u64 bvnc, struct pvr_gpu_id *gpu_id) +{ + gpu_id->b = (bvnc & GENMASK_ULL(63, 48)) >> 48; + gpu_id->v = (bvnc & GENMASK_ULL(47, 32)) >> 32; + gpu_id->n = (bvnc & GENMASK_ULL(31, 16)) >> 16; + gpu_id->c = bvnc & GENMASK_ULL(15, 0); +} + +int pvr_device_init(struct pvr_device *pvr_dev); +void pvr_device_fini(struct pvr_device *pvr_dev); +void pvr_device_reset(struct pvr_device *pvr_dev); + +bool +pvr_device_has_uapi_quirk(struct pvr_device *pvr_dev, u32 quirk); +bool +pvr_device_has_uapi_enhancement(struct pvr_device *pvr_dev, u32 enhancement); +bool +pvr_device_has_feature(struct pvr_device *pvr_dev, u32 feature); + +/** + * PVR_CR_FIELD_GET() - Extract a single field from a PowerVR control register + * @val: Value of the target register. + * @field: Field specifier, as defined in "pvr_rogue_cr_defs.h". + * + * Return: The extracted field. + */ +#define PVR_CR_FIELD_GET(val, field) FIELD_GET(~ROGUE_CR_##field##_CLRMSK, val) + +/** + * pvr_cr_read32() - Read a 32-bit register from a PowerVR device + * @pvr_dev: Target PowerVR device. + * @reg: Target register. + * + * Return: The value of the requested register. + */ +static __always_inline u32 +pvr_cr_read32(struct pvr_device *pvr_dev, u32 reg) +{ + return ioread32(pvr_dev->regs + reg); +} + +/** + * pvr_cr_read64() - Read a 64-bit register from a PowerVR device + * @pvr_dev: Target PowerVR device. + * @reg: Target register. + * + * Return: The value of the requested register. + */ +static __always_inline u64 +pvr_cr_read64(struct pvr_device *pvr_dev, u32 reg) +{ + return ioread64(pvr_dev->regs + reg); +} + +/** + * pvr_cr_write32() - Write to a 32-bit register in a PowerVR device + * @pvr_dev: Target PowerVR device. + * @reg: Target register. + * @val: Value to write. + */ +static __always_inline void +pvr_cr_write32(struct pvr_device *pvr_dev, u32 reg, u32 val) +{ + iowrite32(val, pvr_dev->regs + reg); +} + +/** + * pvr_cr_write64() - Write to a 64-bit register in a PowerVR device + * @pvr_dev: Target PowerVR device. + * @reg: Target register. + * @val: Value to write. + */ +static __always_inline void +pvr_cr_write64(struct pvr_device *pvr_dev, u32 reg, u64 val) +{ + iowrite64(val, pvr_dev->regs + reg); +} + +/** + * pvr_cr_poll_reg32() - Wait for a 32-bit register to match a given value by + * polling + * @pvr_dev: Target PowerVR device. + * @reg_addr: Address of register. + * @reg_value: Expected register value (after masking). + * @reg_mask: Mask of bits valid for comparison with @reg_value. + * @timeout_usec: Timeout length, in us. + * + * Returns: + * * 0 on success, or + * * -%ETIMEDOUT on timeout. + */ +static __always_inline int +pvr_cr_poll_reg32(struct pvr_device *pvr_dev, u32 reg_addr, u32 reg_value, + u32 reg_mask, u64 timeout_usec) +{ + u32 value; + + return readl_poll_timeout(pvr_dev->regs + reg_addr, value, + (value & reg_mask) == reg_value, 0, timeout_usec); +} + +/** + * pvr_cr_poll_reg64() - Wait for a 64-bit register to match a given value by + * polling + * @pvr_dev: Target PowerVR device. + * @reg_addr: Address of register. + * @reg_value: Expected register value (after masking). + * @reg_mask: Mask of bits valid for comparison with @reg_value. + * @timeout_usec: Timeout length, in us. + * + * Returns: + * * 0 on success, or + * * -%ETIMEDOUT on timeout. + */ +static __always_inline int +pvr_cr_poll_reg64(struct pvr_device *pvr_dev, u32 reg_addr, u64 reg_value, + u64 reg_mask, u64 timeout_usec) +{ + u64 value; + + return readq_poll_timeout(pvr_dev->regs + reg_addr, value, + (value & reg_mask) == reg_value, 0, timeout_usec); +} + +/** + * pvr_round_up_to_cacheline_size() - Round up a provided size to be cacheline + * aligned + * @pvr_dev: Target PowerVR device. + * @size: Initial size, in bytes. + * + * Returns: + * * Size aligned to cacheline size. + */ +static __always_inline size_t +pvr_round_up_to_cacheline_size(struct pvr_device *pvr_dev, size_t size) +{ + u16 slc_cacheline_size_bits = 0; + u16 slc_cacheline_size_bytes; + + WARN_ON(!PVR_HAS_FEATURE(pvr_dev, slc_cache_line_size_bits)); + PVR_FEATURE_VALUE(pvr_dev, slc_cache_line_size_bits, + &slc_cacheline_size_bits); + slc_cacheline_size_bytes = slc_cacheline_size_bits / 8; + + return round_up(size, slc_cacheline_size_bytes); +} + +/** + * DOC: IOCTL validation helpers + * + * To validate the constraints imposed on IOCTL argument structs, a collection + * of macros and helper functions exist in ``pvr_device.h``. + * + * Of the current helpers, it should only be necessary to call + * PVR_IOCTL_UNION_PADDING_CHECK() directly. This macro should be used once in + * every code path which extracts a union member from a struct passed from + * userspace. + */ + +/** + * pvr_ioctl_union_padding_check() - Validate that the implicit padding between + * the end of a union member and the end of the union itself is zeroed. + * @instance: Pointer to the instance of the struct to validate. + * @union_offset: Offset into the type of @instance of the target union. Must + * be 64-bit aligned. + * @union_size: Size of the target union in the type of @instance. Must be + * 64-bit aligned. + * @member_size: Size of the target member in the target union specified by + * @union_offset and @union_size. It is assumed that the offset of the target + * member is zero relative to @union_offset. Must be 64-bit aligned. + * + * You probably want to use PVR_IOCTL_UNION_PADDING_CHECK() instead of calling + * this function directly, since that macro abstracts away much of the setup, + * and also provides some static validation. See its docs for details. + * + * Return: + * * %true if every byte between the end of the used member of the union and + * the end of that union is zeroed, or + * * %false otherwise. + */ +static __always_inline bool +pvr_ioctl_union_padding_check(void *instance, size_t union_offset, + size_t union_size, size_t member_size) +{ + /* + * void pointer arithmetic is technically illegal - cast to a byte + * pointer so this addition works safely. + */ + void *padding_start = ((u8 *)instance) + union_offset + member_size; + size_t padding_size = union_size - member_size; + + return !memchr_inv(padding_start, 0, padding_size); +} + +/** + * PVR_STATIC_ASSERT_64BIT_ALIGNED() - Inline assertion for 64-bit alignment. + * @static_expr_: Target expression to evaluate. + * + * If @static_expr_ does not evaluate to a constant integer which would be a + * 64-bit aligned address (i.e. a multiple of 8), compilation will fail. + * + * Return: + * The value of @static_expr_. + */ +#define PVR_STATIC_ASSERT_64BIT_ALIGNED(static_expr_) \ + ({ \ + static_assert(((static_expr_) & (sizeof(u64) - 1)) == 0); \ + (static_expr_); \ + }) + +/** + * PVR_IOCTL_UNION_PADDING_CHECK() - Validate that the implicit padding between + * the end of a union member and the end of the union itself is zeroed. + * @struct_instance_: An expression which evaluates to a pointer to a UAPI data + * struct. + * @union_: The name of the union member of @struct_instance_ to check. If the + * union member is nested within the type of @struct_instance_, this may + * contain the member access operator ("."). + * @member_: The name of the member of @union_ to assess. + * + * This is a wrapper around pvr_ioctl_union_padding_check() which performs + * alignment checks and simplifies things for the caller. + * + * Return: + * * %true if every byte in @struct_instance_ between the end of @member_ and + * the end of @union_ is zeroed, or + * * %false otherwise. + */ +#define PVR_IOCTL_UNION_PADDING_CHECK(struct_instance_, union_, member_) \ + ({ \ + typeof(struct_instance_) __instance = (struct_instance_); \ + size_t __union_offset = PVR_STATIC_ASSERT_64BIT_ALIGNED( \ + offsetof(typeof(*__instance), union_)); \ + size_t __union_size = PVR_STATIC_ASSERT_64BIT_ALIGNED( \ + sizeof(__instance->union_)); \ + size_t __member_size = PVR_STATIC_ASSERT_64BIT_ALIGNED( \ + sizeof(__instance->union_.member_)); \ + pvr_ioctl_union_padding_check(__instance, __union_offset, \ + __union_size, __member_size); \ + }) + +#define PVR_FW_PROCESSOR_TYPE_META 0 +#define PVR_FW_PROCESSOR_TYPE_MIPS 1 +#define PVR_FW_PROCESSOR_TYPE_RISCV 2 + +#endif /* PVR_DEVICE_H */ diff --git a/drivers/gpu/drm/imagination/pvr_device_info.c b/drivers/gpu/drm/imagination/pvr_device_info.c new file mode 100644 index 00000000000000..d3301cde7d119e --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_device_info.c @@ -0,0 +1,255 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_device.h" +#include "pvr_device_info.h" +#include "pvr_rogue_fwif_dev_info.h" + +#include + +#include +#include +#include +#include + +#define QUIRK_MAPPING(quirk) \ + [PVR_FW_HAS_BRN_##quirk] = offsetof(struct pvr_device, quirks.has_brn##quirk) + +static const uintptr_t quirks_mapping[] = { + QUIRK_MAPPING(44079), + QUIRK_MAPPING(47217), + QUIRK_MAPPING(48492), + QUIRK_MAPPING(48545), + QUIRK_MAPPING(49927), + QUIRK_MAPPING(50767), + QUIRK_MAPPING(51764), + QUIRK_MAPPING(62269), + QUIRK_MAPPING(63142), + QUIRK_MAPPING(63553), + QUIRK_MAPPING(66011), + QUIRK_MAPPING(71242), +}; + +#undef QUIRK_MAPPING + +#define ENHANCEMENT_MAPPING(enhancement) \ + [PVR_FW_HAS_ERN_##enhancement] = offsetof(struct pvr_device, \ + enhancements.has_ern##enhancement) + +static const uintptr_t enhancements_mapping[] = { + ENHANCEMENT_MAPPING(35421), + ENHANCEMENT_MAPPING(38020), + ENHANCEMENT_MAPPING(38748), + ENHANCEMENT_MAPPING(42064), + ENHANCEMENT_MAPPING(42290), + ENHANCEMENT_MAPPING(42606), + ENHANCEMENT_MAPPING(47025), + ENHANCEMENT_MAPPING(57596), +}; + +#undef ENHANCEMENT_MAPPING + +static void pvr_device_info_set_common(struct pvr_device *pvr_dev, const u64 *bitmask, + u32 bitmask_size, const uintptr_t *mapping, u32 mapping_max) +{ + const u32 mapping_max_size = (mapping_max + 63) >> 6; + const u32 nr_bits = min(bitmask_size * 64, mapping_max); + + /* Warn if any unsupported values in the bitmask. */ + if (bitmask_size > mapping_max_size) { + if (mapping == quirks_mapping) + drm_warn(from_pvr_device(pvr_dev), "Unsupported quirks in firmware image"); + else + drm_warn(from_pvr_device(pvr_dev), + "Unsupported enhancements in firmware image"); + } else if (bitmask_size == mapping_max_size && (mapping_max & 63)) { + u64 invalid_mask = ~0ull << (mapping_max & 63); + + if (bitmask[bitmask_size - 1] & invalid_mask) { + if (mapping == quirks_mapping) + drm_warn(from_pvr_device(pvr_dev), + "Unsupported quirks in firmware image"); + else + drm_warn(from_pvr_device(pvr_dev), + "Unsupported enhancements in firmware image"); + } + } + + for (u32 i = 0; i < nr_bits; i++) { + if (bitmask[i >> 6] & BIT_ULL(i & 63)) + *(bool *)((u8 *)pvr_dev + mapping[i]) = true; + } +} + +/** + * pvr_device_info_set_quirks() - Set device quirks from device information in firmware + * @pvr_dev: Device pointer. + * @quirks: Pointer to quirks mask in device information. + * @quirks_size: Size of quirks mask, in u64s. + */ +void pvr_device_info_set_quirks(struct pvr_device *pvr_dev, const u64 *quirks, u32 quirks_size) +{ + BUILD_BUG_ON(ARRAY_SIZE(quirks_mapping) != PVR_FW_HAS_BRN_MAX); + + pvr_device_info_set_common(pvr_dev, quirks, quirks_size, quirks_mapping, + ARRAY_SIZE(quirks_mapping)); +} + +/** + * pvr_device_info_set_enhancements() - Set device enhancements from device information in firmware + * @pvr_dev: Device pointer. + * @enhancements: Pointer to enhancements mask in device information. + * @enhancements_size: Size of enhancements mask, in u64s. + */ +void pvr_device_info_set_enhancements(struct pvr_device *pvr_dev, const u64 *enhancements, + u32 enhancements_size) +{ + BUILD_BUG_ON(ARRAY_SIZE(enhancements_mapping) != PVR_FW_HAS_ERN_MAX); + + pvr_device_info_set_common(pvr_dev, enhancements, enhancements_size, + enhancements_mapping, ARRAY_SIZE(enhancements_mapping)); +} + +#define FEATURE_MAPPING(fw_feature, feature) \ + [PVR_FW_HAS_FEATURE_##fw_feature] = { \ + .flag_offset = offsetof(struct pvr_device, features.has_##feature), \ + .value_offset = 0 \ + } + +#define FEATURE_MAPPING_VALUE(fw_feature, feature) \ + [PVR_FW_HAS_FEATURE_##fw_feature] = { \ + .flag_offset = offsetof(struct pvr_device, features.has_##feature), \ + .value_offset = offsetof(struct pvr_device, features.feature) \ + } + +static const struct { + uintptr_t flag_offset; + uintptr_t value_offset; +} features_mapping[] = { + FEATURE_MAPPING(AXI_ACELITE, axi_acelite), + FEATURE_MAPPING_VALUE(CDM_CONTROL_STREAM_FORMAT, cdm_control_stream_format), + FEATURE_MAPPING(CLUSTER_GROUPING, cluster_grouping), + FEATURE_MAPPING_VALUE(COMMON_STORE_SIZE_IN_DWORDS, common_store_size_in_dwords), + FEATURE_MAPPING(COMPUTE, compute), + FEATURE_MAPPING(COMPUTE_MORTON_CAPABLE, compute_morton_capable), + FEATURE_MAPPING(COMPUTE_OVERLAP, compute_overlap), + FEATURE_MAPPING(COREID_PER_OS, coreid_per_os), + FEATURE_MAPPING(DYNAMIC_DUST_POWER, dynamic_dust_power), + FEATURE_MAPPING_VALUE(ECC_RAMS, ecc_rams), + FEATURE_MAPPING_VALUE(FBCDC, fbcdc), + FEATURE_MAPPING_VALUE(FBCDC_ALGORITHM, fbcdc_algorithm), + FEATURE_MAPPING_VALUE(FBCDC_ARCHITECTURE, fbcdc_architecture), + FEATURE_MAPPING_VALUE(FBC_MAX_DEFAULT_DESCRIPTORS, fbc_max_default_descriptors), + FEATURE_MAPPING_VALUE(FBC_MAX_LARGE_DESCRIPTORS, fbc_max_large_descriptors), + FEATURE_MAPPING(FB_CDC_V4, fb_cdc_v4), + FEATURE_MAPPING(GPU_MULTICORE_SUPPORT, gpu_multicore_support), + FEATURE_MAPPING(GPU_VIRTUALISATION, gpu_virtualisation), + FEATURE_MAPPING(GS_RTA_SUPPORT, gs_rta_support), + FEATURE_MAPPING(IRQ_PER_OS, irq_per_os), + FEATURE_MAPPING_VALUE(ISP_MAX_TILES_IN_FLIGHT, isp_max_tiles_in_flight), + FEATURE_MAPPING_VALUE(ISP_SAMPLES_PER_PIXEL, isp_samples_per_pixel), + FEATURE_MAPPING(ISP_ZLS_D24_S8_PACKING_OGL_MODE, isp_zls_d24_s8_packing_ogl_mode), + FEATURE_MAPPING_VALUE(LAYOUT_MARS, layout_mars), + FEATURE_MAPPING_VALUE(MAX_PARTITIONS, max_partitions), + FEATURE_MAPPING_VALUE(META, meta), + FEATURE_MAPPING_VALUE(META_COREMEM_SIZE, meta_coremem_size), + FEATURE_MAPPING(MIPS, mips), + FEATURE_MAPPING_VALUE(NUM_CLUSTERS, num_clusters), + FEATURE_MAPPING_VALUE(NUM_ISP_IPP_PIPES, num_isp_ipp_pipes), + FEATURE_MAPPING_VALUE(NUM_OSIDS, num_osids), + FEATURE_MAPPING_VALUE(NUM_RASTER_PIPES, num_raster_pipes), + FEATURE_MAPPING(PBE2_IN_XE, pbe2_in_xe), + FEATURE_MAPPING(PBVNC_COREID_REG, pbvnc_coreid_reg), + FEATURE_MAPPING(PERFBUS, perfbus), + FEATURE_MAPPING(PERF_COUNTER_BATCH, perf_counter_batch), + FEATURE_MAPPING_VALUE(PHYS_BUS_WIDTH, phys_bus_width), + FEATURE_MAPPING(RISCV_FW_PROCESSOR, riscv_fw_processor), + FEATURE_MAPPING(ROGUEXE, roguexe), + FEATURE_MAPPING(S7_TOP_INFRASTRUCTURE, s7_top_infrastructure), + FEATURE_MAPPING(SIMPLE_INTERNAL_PARAMETER_FORMAT, simple_internal_parameter_format), + FEATURE_MAPPING(SIMPLE_INTERNAL_PARAMETER_FORMAT_V2, simple_internal_parameter_format_v2), + FEATURE_MAPPING_VALUE(SIMPLE_PARAMETER_FORMAT_VERSION, simple_parameter_format_version), + FEATURE_MAPPING_VALUE(SLC_BANKS, slc_banks), + FEATURE_MAPPING_VALUE(SLC_CACHE_LINE_SIZE_BITS, slc_cache_line_size_bits), + FEATURE_MAPPING(SLC_SIZE_CONFIGURABLE, slc_size_configurable), + FEATURE_MAPPING_VALUE(SLC_SIZE_IN_KILOBYTES, slc_size_in_kilobytes), + FEATURE_MAPPING(SOC_TIMER, soc_timer), + FEATURE_MAPPING(SYS_BUS_SECURE_RESET, sys_bus_secure_reset), + FEATURE_MAPPING(TESSELLATION, tessellation), + FEATURE_MAPPING(TILE_REGION_PROTECTION, tile_region_protection), + FEATURE_MAPPING_VALUE(TILE_SIZE_X, tile_size_x), + FEATURE_MAPPING_VALUE(TILE_SIZE_Y, tile_size_y), + FEATURE_MAPPING(TLA, tla), + FEATURE_MAPPING(TPU_CEM_DATAMASTER_GLOBAL_REGISTERS, tpu_cem_datamaster_global_registers), + FEATURE_MAPPING(TPU_DM_GLOBAL_REGISTERS, tpu_dm_global_registers), + FEATURE_MAPPING(TPU_FILTERING_MODE_CONTROL, tpu_filtering_mode_control), + FEATURE_MAPPING_VALUE(USC_MIN_OUTPUT_REGISTERS_PER_PIX, usc_min_output_registers_per_pix), + FEATURE_MAPPING(VDM_DRAWINDIRECT, vdm_drawindirect), + FEATURE_MAPPING(VDM_OBJECT_LEVEL_LLS, vdm_object_level_lls), + FEATURE_MAPPING_VALUE(VIRTUAL_ADDRESS_SPACE_BITS, virtual_address_space_bits), + FEATURE_MAPPING(WATCHDOG_TIMER, watchdog_timer), + FEATURE_MAPPING(WORKGROUP_PROTECTION, workgroup_protection), + FEATURE_MAPPING_VALUE(XE_ARCHITECTURE, xe_architecture), + FEATURE_MAPPING(XE_MEMORY_HIERARCHY, xe_memory_hierarchy), + FEATURE_MAPPING(XE_TPU2, xe_tpu2), + FEATURE_MAPPING_VALUE(XPU_MAX_REGBANKS_ADDR_WIDTH, xpu_max_regbanks_addr_width), + FEATURE_MAPPING_VALUE(XPU_MAX_SLAVES, xpu_max_slaves), + FEATURE_MAPPING_VALUE(XPU_REGISTER_BROADCAST, xpu_register_broadcast), + FEATURE_MAPPING(XT_TOP_INFRASTRUCTURE, xt_top_infrastructure), + FEATURE_MAPPING(ZLS_SUBTILE, zls_subtile), +}; + +#undef FEATURE_MAPPING_VALUE +#undef FEATURE_MAPPING + +/** + * pvr_device_info_set_features() - Set device features from device information in firmware + * @pvr_dev: Device pointer. + * @features: Pointer to features mask in device information. + * @features_size: Size of features mask, in u64s. + * @feature_param_size: Size of feature parameters, in u64s. + * + * Returns: + * * 0 on success, or + * * -%EINVAL on malformed stream. + */ +int pvr_device_info_set_features(struct pvr_device *pvr_dev, const u64 *features, u32 features_size, + u32 feature_param_size) +{ + const u32 mapping_max = ARRAY_SIZE(features_mapping); + const u32 mapping_max_size = (mapping_max + 63) >> 6; + const u32 nr_bits = min(features_size * 64, mapping_max); + const u64 *feature_params = features + features_size; + u32 param_idx = 0; + + BUILD_BUG_ON(ARRAY_SIZE(features_mapping) != PVR_FW_HAS_FEATURE_MAX); + + /* Verify no unsupported values in the bitmask. */ + if (features_size > mapping_max_size) { + drm_warn(from_pvr_device(pvr_dev), "Unsupported features in firmware image"); + } else if (features_size == mapping_max_size && + ((mapping_max & 63) != 0)) { + u64 invalid_mask = ~0ull << (mapping_max & 63); + + if (features[features_size - 1] & invalid_mask) + drm_warn(from_pvr_device(pvr_dev), + "Unsupported features in firmware image"); + } + + for (u32 i = 0; i < nr_bits; i++) { + if (features[i >> 6] & BIT_ULL(i & 63)) { + *(bool *)((u8 *)pvr_dev + features_mapping[i].flag_offset) = true; + + if (features_mapping[i].value_offset) { + if (param_idx >= feature_param_size) + return -EINVAL; + + *(u64 *)((u8 *)pvr_dev + features_mapping[i].value_offset) = + feature_params[param_idx]; + param_idx++; + } + } + } + + return 0; +} diff --git a/drivers/gpu/drm/imagination/pvr_device_info.h b/drivers/gpu/drm/imagination/pvr_device_info.h new file mode 100644 index 00000000000000..f61fb988b55392 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_device_info.h @@ -0,0 +1,186 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_DEVICE_INFO_H +#define PVR_DEVICE_INFO_H + +#include + +struct pvr_device; + +/* + * struct pvr_device_features - Hardware feature information + */ +struct pvr_device_features { + bool has_axi_acelite; + bool has_cdm_control_stream_format; + bool has_cluster_grouping; + bool has_common_store_size_in_dwords; + bool has_compute; + bool has_compute_morton_capable; + bool has_compute_overlap; + bool has_coreid_per_os; + bool has_dynamic_dust_power; + bool has_ecc_rams; + bool has_fb_cdc_v4; + bool has_fbc_max_default_descriptors; + bool has_fbc_max_large_descriptors; + bool has_fbcdc; + bool has_fbcdc_algorithm; + bool has_fbcdc_architecture; + bool has_gpu_multicore_support; + bool has_gpu_virtualisation; + bool has_gs_rta_support; + bool has_irq_per_os; + bool has_isp_max_tiles_in_flight; + bool has_isp_samples_per_pixel; + bool has_isp_zls_d24_s8_packing_ogl_mode; + bool has_layout_mars; + bool has_max_partitions; + bool has_meta; + bool has_meta_coremem_size; + bool has_mips; + bool has_num_clusters; + bool has_num_isp_ipp_pipes; + bool has_num_osids; + bool has_num_raster_pipes; + bool has_pbe2_in_xe; + bool has_pbvnc_coreid_reg; + bool has_perfbus; + bool has_perf_counter_batch; + bool has_phys_bus_width; + bool has_riscv_fw_processor; + bool has_roguexe; + bool has_s7_top_infrastructure; + bool has_simple_internal_parameter_format; + bool has_simple_internal_parameter_format_v2; + bool has_simple_parameter_format_version; + bool has_slc_banks; + bool has_slc_cache_line_size_bits; + bool has_slc_size_configurable; + bool has_slc_size_in_kilobytes; + bool has_soc_timer; + bool has_sys_bus_secure_reset; + bool has_tessellation; + bool has_tile_region_protection; + bool has_tile_size_x; + bool has_tile_size_y; + bool has_tla; + bool has_tpu_cem_datamaster_global_registers; + bool has_tpu_dm_global_registers; + bool has_tpu_filtering_mode_control; + bool has_usc_min_output_registers_per_pix; + bool has_vdm_drawindirect; + bool has_vdm_object_level_lls; + bool has_virtual_address_space_bits; + bool has_watchdog_timer; + bool has_workgroup_protection; + bool has_xe_architecture; + bool has_xe_memory_hierarchy; + bool has_xe_tpu2; + bool has_xpu_max_regbanks_addr_width; + bool has_xpu_max_slaves; + bool has_xpu_register_broadcast; + bool has_xt_top_infrastructure; + bool has_zls_subtile; + + u64 cdm_control_stream_format; + u64 common_store_size_in_dwords; + u64 ecc_rams; + u64 fbc_max_default_descriptors; + u64 fbc_max_large_descriptors; + u64 fbcdc; + u64 fbcdc_algorithm; + u64 fbcdc_architecture; + u64 isp_max_tiles_in_flight; + u64 isp_samples_per_pixel; + u64 layout_mars; + u64 max_partitions; + u64 meta; + u64 meta_coremem_size; + u64 num_clusters; + u64 num_isp_ipp_pipes; + u64 num_osids; + u64 num_raster_pipes; + u64 phys_bus_width; + u64 simple_parameter_format_version; + u64 slc_banks; + u64 slc_cache_line_size_bits; + u64 slc_size_in_kilobytes; + u64 tile_size_x; + u64 tile_size_y; + u64 usc_min_output_registers_per_pix; + u64 virtual_address_space_bits; + u64 xe_architecture; + u64 xpu_max_regbanks_addr_width; + u64 xpu_max_slaves; + u64 xpu_register_broadcast; +}; + +/* + * struct pvr_device_quirks - Hardware quirk information + */ +struct pvr_device_quirks { + bool has_brn44079; + bool has_brn47217; + bool has_brn48492; + bool has_brn48545; + bool has_brn49927; + bool has_brn50767; + bool has_brn51764; + bool has_brn62269; + bool has_brn63142; + bool has_brn63553; + bool has_brn66011; + bool has_brn71242; +}; + +/* + * struct pvr_device_enhancements - Hardware enhancement information + */ +struct pvr_device_enhancements { + bool has_ern35421; + bool has_ern38020; + bool has_ern38748; + bool has_ern42064; + bool has_ern42290; + bool has_ern42606; + bool has_ern47025; + bool has_ern57596; +}; + +void pvr_device_info_set_quirks(struct pvr_device *pvr_dev, const u64 *bitmask, + u32 bitmask_len); +void pvr_device_info_set_enhancements(struct pvr_device *pvr_dev, const u64 *bitmask, + u32 bitmask_len); +int pvr_device_info_set_features(struct pvr_device *pvr_dev, const u64 *features, u32 features_size, + u32 feature_param_size); + +/* + * Meta cores + * + * These are the values for the 'meta' feature when the feature is present + * (as per &struct pvr_device_features)/ + */ +#define PVR_META_MTP218 (1) +#define PVR_META_MTP219 (2) +#define PVR_META_LTP218 (3) +#define PVR_META_LTP217 (4) + +enum { + PVR_FEATURE_CDM_USER_MODE_QUEUE, + PVR_FEATURE_CLUSTER_GROUPING, + PVR_FEATURE_COMPUTE_MORTON_CAPABLE, + PVR_FEATURE_FB_CDC_V4, + PVR_FEATURE_GPU_MULTICORE_SUPPORT, + PVR_FEATURE_ISP_ZLS_D24_S8_PACKING_OGL_MODE, + PVR_FEATURE_REQUIRES_FB_CDC_ZLS_SETUP, + PVR_FEATURE_S7_TOP_INFRASTRUCTURE, + PVR_FEATURE_TESSELLATION, + PVR_FEATURE_TPU_DM_GLOBAL_REGISTERS, + PVR_FEATURE_VDM_DRAWINDIRECT, + PVR_FEATURE_VDM_OBJECT_LEVEL_LLS, + PVR_FEATURE_ZLS_SUBTILE, +}; + +#endif /* PVR_DEVICE_INFO_H */ diff --git a/drivers/gpu/drm/imagination/pvr_drv.c b/drivers/gpu/drm/imagination/pvr_drv.c new file mode 100644 index 00000000000000..5c3b2d58d766bb --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_drv.c @@ -0,0 +1,1501 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_context.h" +#include "pvr_debugfs.h" +#include "pvr_device.h" +#include "pvr_drv.h" +#include "pvr_free_list.h" +#include "pvr_gem.h" +#include "pvr_hwrt.h" +#include "pvr_job.h" +#include "pvr_mmu.h" +#include "pvr_power.h" +#include "pvr_rogue_defs.h" +#include "pvr_rogue_fwif_client.h" +#include "pvr_rogue_fwif_shared.h" +#include "pvr_vm.h" + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * DOC: PowerVR (Series 6 and later) and IMG Graphics Driver + * + * This driver supports the following PowerVR/IMG graphics cores from Imagination Technologies: + * + * * AXE-1-16M (found in Texas Instruments AM62) + */ + +/** + * pvr_ioctl_create_bo() - IOCTL to create a GEM buffer object. + * @drm_dev: [IN] Target DRM device. + * @raw_args: [IN/OUT] Arguments passed to this IOCTL. This must be of type + * &struct drm_pvr_ioctl_create_bo_args. + * @file: [IN] DRM file-private data. + * + * Called from userspace with %DRM_IOCTL_PVR_CREATE_BO. + * + * Return: + * * 0 on success, + * * -%EINVAL if the value of &drm_pvr_ioctl_create_bo_args.size is zero + * or wider than &typedef size_t, + * * -%EINVAL if any bits in &drm_pvr_ioctl_create_bo_args.flags that are + * reserved or undefined are set, + * * -%EINVAL if any padding fields in &drm_pvr_ioctl_create_bo_args are not + * zero, + * * Any error encountered while creating the object (see + * pvr_gem_object_create()), or + * * Any error encountered while transferring ownership of the object into a + * userspace-accessible handle (see pvr_gem_object_into_handle()). + */ +static int +pvr_ioctl_create_bo(struct drm_device *drm_dev, void *raw_args, + struct drm_file *file) +{ + struct drm_pvr_ioctl_create_bo_args *args = raw_args; + struct pvr_device *pvr_dev = to_pvr_device(drm_dev); + struct pvr_file *pvr_file = to_pvr_file(file); + + struct pvr_gem_object *pvr_obj; + size_t sanitized_size; + + int idx; + int err; + + if (!drm_dev_enter(drm_dev, &idx)) + return -EIO; + + /* All padding fields must be zeroed. */ + if (args->_padding_c != 0) { + err = -EINVAL; + goto err_drm_dev_exit; + } + + /* + * On 64-bit platforms (our primary target), size_t is a u64. However, + * on other architectures we have to check for overflow when casting + * down to size_t from u64. + * + * We also disallow zero-sized allocations, and reserved (kernel-only) + * flags. + */ + if (args->size > SIZE_MAX || args->size == 0 || args->flags & + ~DRM_PVR_BO_FLAGS_MASK || args->size & (PVR_DEVICE_PAGE_SIZE - 1)) { + err = -EINVAL; + goto err_drm_dev_exit; + } + + sanitized_size = (size_t)args->size; + + /* + * Create a buffer object and transfer ownership to a userspace- + * accessible handle. + */ + pvr_obj = pvr_gem_object_create(pvr_dev, sanitized_size, args->flags); + if (IS_ERR(pvr_obj)) { + err = PTR_ERR(pvr_obj); + goto err_drm_dev_exit; + } + + /* This function will not modify &args->handle unless it succeeds. */ + err = pvr_gem_object_into_handle(pvr_obj, pvr_file, &args->handle); + if (err) + goto err_destroy_obj; + + drm_dev_exit(idx); + + return 0; + +err_destroy_obj: + /* + * GEM objects are refcounted, so there is no explicit destructor + * function. Instead, we release the singular reference we currently + * hold on the object and let GEM take care of the rest. + */ + pvr_gem_object_put(pvr_obj); + +err_drm_dev_exit: + drm_dev_exit(idx); + + return err; +} + +/** + * pvr_ioctl_get_bo_mmap_offset() - IOCTL to generate a "fake" offset to be + * used when calling mmap() from userspace to map the given GEM buffer object + * @drm_dev: [IN] DRM device (unused). + * @raw_args: [IN/OUT] Arguments passed to this IOCTL. This must be of type + * &struct drm_pvr_ioctl_get_bo_mmap_offset_args. + * @file: [IN] DRM file private data. + * + * Called from userspace with %DRM_IOCTL_PVR_GET_BO_MMAP_OFFSET. + * + * This IOCTL does *not* perform an mmap. See the docs on + * &struct drm_pvr_ioctl_get_bo_mmap_offset_args for details. + * + * Return: + * * 0 on success, + * * -%ENOENT if the handle does not reference a valid GEM buffer object, + * * -%EINVAL if any padding fields in &struct + * drm_pvr_ioctl_get_bo_mmap_offset_args are not zero, or + * * Any error returned by drm_gem_create_mmap_offset(). + */ +static int +pvr_ioctl_get_bo_mmap_offset(struct drm_device *drm_dev, void *raw_args, + struct drm_file *file) +{ + struct drm_pvr_ioctl_get_bo_mmap_offset_args *args = raw_args; + struct pvr_file *pvr_file = to_pvr_file(file); + struct pvr_gem_object *pvr_obj; + struct drm_gem_object *gem_obj; + int idx; + int ret; + + if (!drm_dev_enter(drm_dev, &idx)) + return -EIO; + + /* All padding fields must be zeroed. */ + if (args->_padding_4 != 0) { + ret = -EINVAL; + goto err_drm_dev_exit; + } + + /* + * Obtain a kernel reference to the buffer object. This reference is + * counted and must be manually dropped before returning. If a buffer + * object cannot be found for the specified handle, return -%ENOENT (No + * such file or directory). + */ + pvr_obj = pvr_gem_object_from_handle(pvr_file, args->handle); + if (!pvr_obj) { + ret = -ENOENT; + goto err_drm_dev_exit; + } + + gem_obj = gem_from_pvr_gem(pvr_obj); + + /* + * Allocate a fake offset which can be used in userspace calls to mmap + * on the DRM device file. If this fails, return the error code. This + * operation is idempotent. + */ + ret = drm_gem_create_mmap_offset(gem_obj); + if (ret != 0) { + /* Drop our reference to the buffer object. */ + drm_gem_object_put(gem_obj); + goto err_drm_dev_exit; + } + + /* + * Read out the fake offset allocated by the earlier call to + * drm_gem_create_mmap_offset. + */ + args->offset = drm_vma_node_offset_addr(&gem_obj->vma_node); + + /* Drop our reference to the buffer object. */ + pvr_gem_object_put(pvr_obj); + +err_drm_dev_exit: + drm_dev_exit(idx); + + return ret; +} + +static __always_inline u64 +pvr_fw_version_packed(u32 major, u32 minor) +{ + return ((u64)major << 32) | minor; +} + +static u32 +rogue_get_common_store_partition_space_size(struct pvr_device *pvr_dev) +{ + u32 max_partitions = 0; + u32 tile_size_x = 0; + u32 tile_size_y = 0; + + PVR_FEATURE_VALUE(pvr_dev, tile_size_x, &tile_size_x); + PVR_FEATURE_VALUE(pvr_dev, tile_size_y, &tile_size_y); + PVR_FEATURE_VALUE(pvr_dev, max_partitions, &max_partitions); + + if (tile_size_x == 16 && tile_size_y == 16) { + u32 usc_min_output_registers_per_pix = 0; + + PVR_FEATURE_VALUE(pvr_dev, usc_min_output_registers_per_pix, + &usc_min_output_registers_per_pix); + + return tile_size_x * tile_size_y * max_partitions * + usc_min_output_registers_per_pix; + } + + return max_partitions * 1024; +} + +static u32 +rogue_get_common_store_alloc_region_size(struct pvr_device *pvr_dev) +{ + u32 common_store_size_in_dwords = 512 * 4 * 4; + u32 alloc_region_size; + + PVR_FEATURE_VALUE(pvr_dev, common_store_size_in_dwords, &common_store_size_in_dwords); + + alloc_region_size = common_store_size_in_dwords - (256U * 4U) - + rogue_get_common_store_partition_space_size(pvr_dev); + + if (PVR_HAS_QUIRK(pvr_dev, 44079)) { + u32 common_store_split_point = (768U * 4U * 4U); + + return min(common_store_split_point - (256U * 4U), alloc_region_size); + } + + return alloc_region_size; +} + +static inline u32 +rogue_get_num_phantoms(struct pvr_device *pvr_dev) +{ + u32 num_clusters = 1; + + PVR_FEATURE_VALUE(pvr_dev, num_clusters, &num_clusters); + + return ROGUE_REQ_NUM_PHANTOMS(num_clusters); +} + +static inline u32 +rogue_get_max_coeffs(struct pvr_device *pvr_dev) +{ + u32 max_coeff_additional_portion = ROGUE_MAX_VERTEX_SHARED_REGISTERS; + u32 pending_allocation_shared_regs = 2U * 1024U; + u32 pending_allocation_coeff_regs = 0U; + u32 num_phantoms = rogue_get_num_phantoms(pvr_dev); + u32 tiles_in_flight = 0; + u32 max_coeff_pixel_portion; + + PVR_FEATURE_VALUE(pvr_dev, isp_max_tiles_in_flight, &tiles_in_flight); + max_coeff_pixel_portion = DIV_ROUND_UP(tiles_in_flight, num_phantoms); + max_coeff_pixel_portion *= ROGUE_MAX_PIXEL_SHARED_REGISTERS; + + /* + * Compute tasks on cores with BRN48492 and without compute overlap may lock + * up without two additional lines of coeffs. + */ + if (PVR_HAS_QUIRK(pvr_dev, 48492) && !PVR_HAS_FEATURE(pvr_dev, compute_overlap)) + pending_allocation_coeff_regs = 2U * 1024U; + + if (PVR_HAS_ENHANCEMENT(pvr_dev, 38748)) + pending_allocation_shared_regs = 0; + + if (PVR_HAS_ENHANCEMENT(pvr_dev, 38020)) + max_coeff_additional_portion += ROGUE_MAX_COMPUTE_SHARED_REGISTERS; + + return rogue_get_common_store_alloc_region_size(pvr_dev) + pending_allocation_coeff_regs - + (max_coeff_pixel_portion + max_coeff_additional_portion + + pending_allocation_shared_regs); +} + +static inline u32 +rogue_get_cdm_max_local_mem_size_regs(struct pvr_device *pvr_dev) +{ + u32 available_coeffs_in_dwords = rogue_get_max_coeffs(pvr_dev); + + if (PVR_HAS_QUIRK(pvr_dev, 48492) && PVR_HAS_FEATURE(pvr_dev, roguexe) && + !PVR_HAS_FEATURE(pvr_dev, compute_overlap)) { + /* Driver must not use the 2 reserved lines. */ + available_coeffs_in_dwords -= ROGUE_CSRM_LINE_SIZE_IN_DWORDS * 2; + } + + /* + * The maximum amount of local memory available to a kernel is the minimum + * of the total number of coefficient registers available and the max common + * store allocation size which can be made by the CDM. + * + * If any coeff lines are reserved for tessellation or pixel then we need to + * subtract those too. + */ + return min(available_coeffs_in_dwords, (u32)ROGUE_MAX_PER_KERNEL_LOCAL_MEM_SIZE_REGS); +} + +/** + * pvr_dev_query_gpu_info_get() + * @pvr_dev: Device pointer. + * @args: [IN] Device query arguments containing a pointer to a userspace + * struct drm_pvr_dev_query_gpu_info. + * + * If the query object pointer is NULL, the size field is updated with the + * expected size of the query object. + * + * Returns: + * * 0 on success, or if size is requested using a NULL pointer, or + * * -%E2BIG if the indicated length of the allocation is less than is + * required to contain the copied data, or + * * -%EFAULT if local memory could not be copied to userspace. + */ +static int +pvr_dev_query_gpu_info_get(struct pvr_device *pvr_dev, + struct drm_pvr_ioctl_dev_query_args *args) +{ + struct drm_pvr_dev_query_gpu_info gpu_info = {0}; + int err; + + if (!args->pointer) { + args->size = sizeof(struct drm_pvr_dev_query_gpu_info); + return 0; + } + + gpu_info.gpu_id = + pvr_gpu_id_to_packed_bvnc(&pvr_dev->gpu_id); + gpu_info.num_phantoms = rogue_get_num_phantoms(pvr_dev); + + err = PVR_UOBJ_SET(args->pointer, args->size, gpu_info); + if (err < 0) + return err; + + if (args->size > sizeof(gpu_info)) + args->size = sizeof(gpu_info); + return 0; +} + +/** + * pvr_dev_query_runtime_info_get() + * @pvr_dev: Device pointer. + * @args: [IN] Device query arguments containing a pointer to a userspace + * struct drm_pvr_dev_query_runtime_info. + * + * If the query object pointer is NULL, the size field is updated with the + * expected size of the query object. + * + * Returns: + * * 0 on success, or if size is requested using a NULL pointer, or + * * -%E2BIG if the indicated length of the allocation is less than is + * required to contain the copied data, or + * * -%EFAULT if local memory could not be copied to userspace. + */ +static int +pvr_dev_query_runtime_info_get(struct pvr_device *pvr_dev, + struct drm_pvr_ioctl_dev_query_args *args) +{ + struct drm_pvr_dev_query_runtime_info runtime_info = {0}; + int err; + + if (!args->pointer) { + args->size = sizeof(struct drm_pvr_dev_query_runtime_info); + return 0; + } + + runtime_info.free_list_min_pages = + pvr_get_free_list_min_pages(pvr_dev); + runtime_info.free_list_max_pages = + ROGUE_PM_MAX_FREELIST_SIZE / ROGUE_PM_PAGE_SIZE; + runtime_info.common_store_alloc_region_size = + rogue_get_common_store_alloc_region_size(pvr_dev); + runtime_info.common_store_partition_space_size = + rogue_get_common_store_partition_space_size(pvr_dev); + runtime_info.max_coeffs = rogue_get_max_coeffs(pvr_dev); + runtime_info.cdm_max_local_mem_size_regs = + rogue_get_cdm_max_local_mem_size_regs(pvr_dev); + + err = PVR_UOBJ_SET(args->pointer, args->size, runtime_info); + if (err < 0) + return err; + + if (args->size > sizeof(runtime_info)) + args->size = sizeof(runtime_info); + return 0; +} + +/** + * pvr_dev_query_quirks_get() - Unpack array of quirks at the address given + * in a struct drm_pvr_dev_query_quirks, or gets the amount of space required + * for it. + * @pvr_dev: Device pointer. + * @args: [IN] Device query arguments containing a pointer to a userspace + * struct drm_pvr_dev_query_query_quirks. + * + * If the query object pointer is NULL, the size field is updated with the + * expected size of the query object. + * If the userspace pointer in the query object is NULL, or the count is + * short, no data is copied. + * The count field will be updated to that copied, or if either pointer is + * NULL, that which would have been copied. + * The size field in the query object will be updated to the size copied. + * + * Returns: + * * 0 on success, or if size/count is requested using a NULL pointer, or + * * -%EINVAL if args contained non-zero reserved fields, or + * * -%E2BIG if the indicated length of the allocation is less than is + * required to contain the copied data, or + * * -%EFAULT if local memory could not be copied to userspace. + */ +static int +pvr_dev_query_quirks_get(struct pvr_device *pvr_dev, + struct drm_pvr_ioctl_dev_query_args *args) +{ + /* + * @FIXME - hardcoding of numbers here is intended as an + * intermediate step so the UAPI can be fixed, but requires a + * a refactor in the future to store them in a more appropriate + * location + */ + static const u32 umd_quirks_musthave[] = { + 47217, + 49927, + 62269, + }; + static const u32 umd_quirks[] = { + 48545, + 51764, + }; + struct drm_pvr_dev_query_quirks query; + u32 out[ARRAY_SIZE(umd_quirks_musthave) + ARRAY_SIZE(umd_quirks)]; + size_t out_musthave_count = 0; + size_t out_count = 0; + int err; + + if (!args->pointer) { + args->size = sizeof(struct drm_pvr_dev_query_quirks); + return 0; + } + + err = PVR_UOBJ_GET(query, args->size, args->pointer); + + if (err < 0) + return err; + if (query._padding_c) + return -EINVAL; + + for (int i = 0; i < ARRAY_SIZE(umd_quirks_musthave); i++) { + if (pvr_device_has_uapi_quirk(pvr_dev, umd_quirks_musthave[i])) { + out[out_count++] = umd_quirks_musthave[i]; + out_musthave_count++; + } + } + + for (int i = 0; i < ARRAY_SIZE(umd_quirks); i++) { + if (pvr_device_has_uapi_quirk(pvr_dev, umd_quirks[i])) + out[out_count++] = umd_quirks[i]; + } + + if (!query.quirks) + goto copy_out; + if (query.count < out_count) + return -E2BIG; + + if (copy_to_user(u64_to_user_ptr(query.quirks), out, + out_count * sizeof(u32))) { + return -EFAULT; + } + + query.musthave_count = out_musthave_count; + +copy_out: + query.count = out_count; + err = PVR_UOBJ_SET(args->pointer, args->size, query); + if (err < 0) + return err; + + args->size = sizeof(query); + return 0; +} + +/** + * pvr_dev_query_enhancements_get() - Unpack array of enhancements at the + * address given in a struct drm_pvr_dev_query_enhancements, or gets the amount + * of space required for it. + * @pvr_dev: Device pointer. + * @args: [IN] Device query arguments containing a pointer to a userspace + * struct drm_pvr_dev_query_enhancements. + * + * If the query object pointer is NULL, the size field is updated with the + * expected size of the query object. + * If the userspace pointer in the query object is NULL, or the count is + * short, no data is copied. + * The count field will be updated to that copied, or if either pointer is + * NULL, that which would have been copied. + * The size field in the query object will be updated to the size copied. + * + * Returns: + * * 0 on success, or if size/count is requested using a NULL pointer, or + * * -%EINVAL if args contained non-zero reserved fields, or + * * -%E2BIG if the indicated length of the allocation is less than is + * required to contain the copied data, or + * * -%EFAULT if local memory could not be copied to userspace. + */ +static int +pvr_dev_query_enhancements_get(struct pvr_device *pvr_dev, + struct drm_pvr_ioctl_dev_query_args *args) +{ + /* + * @FIXME - hardcoding of numbers here is intended as an + * intermediate step so the UAPI can be fixed, but requires a + * a refactor in the future to store them in a more appropriate + * location + */ + const u32 umd_enhancements[] = { + 35421, + 42064, + }; + struct drm_pvr_dev_query_enhancements query; + u32 out[ARRAY_SIZE(umd_enhancements)]; + size_t out_idx = 0; + int err; + + if (!args->pointer) { + args->size = sizeof(struct drm_pvr_dev_query_enhancements); + return 0; + } + + err = PVR_UOBJ_GET(query, args->size, args->pointer); + + if (err < 0) + return err; + if (query._padding_a) + return -EINVAL; + if (query._padding_c) + return -EINVAL; + + for (int i = 0; i < ARRAY_SIZE(umd_enhancements); i++) { + if (pvr_device_has_uapi_enhancement(pvr_dev, umd_enhancements[i])) + out[out_idx++] = umd_enhancements[i]; + } + + if (!query.enhancements) + goto copy_out; + if (query.count < out_idx) + return -E2BIG; + + if (copy_to_user(u64_to_user_ptr(query.enhancements), out, + out_idx * sizeof(u32))) { + return -EFAULT; + } + +copy_out: + query.count = out_idx; + err = PVR_UOBJ_SET(args->pointer, args->size, query); + if (err < 0) + return err; + + args->size = sizeof(query); + return 0; +} + +/** + * pvr_ioctl_dev_query() - IOCTL to copy information about a device + * @drm_dev: [IN] DRM device. + * @raw_args: [IN/OUT] Arguments passed to this IOCTL. This must be of type + * &struct drm_pvr_ioctl_dev_query_args. + * @file: [IN] DRM file private data. + * + * Called from userspace with %DRM_IOCTL_PVR_DEV_QUERY. + * If the given receiving struct pointer is NULL, or the indicated size is too + * small, the expected size of the struct type will be returned in the size + * argument field. + * + * Return: + * * 0 on success or when fetching the size with args->pointer == NULL, or + * * -%E2BIG if the indicated size of the receiving struct is less than is + * required to contain the copied data, or + * * -%EINVAL if the indicated struct type is unknown, or + * * -%ENOMEM if local memory could not be allocated, or + * * -%EFAULT if local memory could not be copied to userspace. + */ +static int +pvr_ioctl_dev_query(struct drm_device *drm_dev, void *raw_args, + struct drm_file *file) +{ + struct pvr_device *pvr_dev = to_pvr_device(drm_dev); + struct drm_pvr_ioctl_dev_query_args *args = raw_args; + int idx; + int ret = -EINVAL; + + if (!drm_dev_enter(drm_dev, &idx)) + return -EIO; + + switch ((enum drm_pvr_dev_query)args->type) { + case DRM_PVR_DEV_QUERY_GPU_INFO_GET: + ret = pvr_dev_query_gpu_info_get(pvr_dev, args); + break; + + case DRM_PVR_DEV_QUERY_RUNTIME_INFO_GET: + ret = pvr_dev_query_runtime_info_get(pvr_dev, args); + break; + + case DRM_PVR_DEV_QUERY_QUIRKS_GET: + ret = pvr_dev_query_quirks_get(pvr_dev, args); + break; + + case DRM_PVR_DEV_QUERY_ENHANCEMENTS_GET: + ret = pvr_dev_query_enhancements_get(pvr_dev, args); + break; + + case DRM_PVR_DEV_QUERY_HEAP_INFO_GET: + ret = pvr_heap_info_get(pvr_dev, args); + break; + + case DRM_PVR_DEV_QUERY_STATIC_DATA_AREAS_GET: + ret = pvr_static_data_areas_get(pvr_dev, args); + break; + } + + drm_dev_exit(idx); + + return ret; +} + +/** + * pvr_ioctl_create_context() - IOCTL to create a context + * @drm_dev: [IN] DRM device. + * @raw_args: [IN/OUT] Arguments passed to this IOCTL. This must be of type + * &struct drm_pvr_ioctl_create_context_args. + * @file: [IN] DRM file private data. + * + * Called from userspace with %DRM_IOCTL_PVR_CREATE_CONTEXT. + * + * Return: + * * 0 on success, or + * * -%EINVAL if provided arguments are invalid, or + * * -%EFAULT if arguments can't be copied from userspace, or + * * Any error returned by pvr_create_render_context(). + */ +static int +pvr_ioctl_create_context(struct drm_device *drm_dev, void *raw_args, + struct drm_file *file) +{ + struct drm_pvr_ioctl_create_context_args *args = raw_args; + struct pvr_file *pvr_file = file->driver_priv; + int idx; + int ret; + + if (!drm_dev_enter(drm_dev, &idx)) + return -EIO; + + ret = pvr_context_create(pvr_file, args); + + drm_dev_exit(idx); + + return ret; +} + +/** + * pvr_ioctl_destroy_context() - IOCTL to destroy a context + * @drm_dev: [IN] DRM device. + * @raw_args: [IN/OUT] Arguments passed to this IOCTL. This must be of type + * &struct drm_pvr_ioctl_destroy_context_args. + * @file: [IN] DRM file private data. + * + * Called from userspace with %DRM_IOCTL_PVR_DESTROY_CONTEXT. + * + * Return: + * * 0 on success, or + * * -%EINVAL if context not in context list. + */ +static int +pvr_ioctl_destroy_context(struct drm_device *drm_dev, void *raw_args, + struct drm_file *file) +{ + struct drm_pvr_ioctl_destroy_context_args *args = raw_args; + struct pvr_file *pvr_file = file->driver_priv; + + if (args->_padding_4) + return -EINVAL; + + return pvr_context_destroy(pvr_file, args->handle); +} + +/** + * pvr_ioctl_create_free_list() - IOCTL to create a free list + * @drm_dev: [IN] DRM device. + * @raw_args: [IN/OUT] Arguments passed to this IOCTL. This must be of type + * &struct drm_pvr_ioctl_create_free_list_args. + * @file: [IN] DRM file private data. + * + * Called from userspace with %DRM_IOCTL_PVR_CREATE_FREE_LIST. + * + * Return: + * * 0 on success, or + * * Any error returned by pvr_free_list_create(). + */ +static int +pvr_ioctl_create_free_list(struct drm_device *drm_dev, void *raw_args, + struct drm_file *file) +{ + struct drm_pvr_ioctl_create_free_list_args *args = raw_args; + struct pvr_file *pvr_file = to_pvr_file(file); + struct pvr_free_list *free_list; + int idx; + int err; + + if (!drm_dev_enter(drm_dev, &idx)) + return -EIO; + + free_list = pvr_free_list_create(pvr_file, args); + if (IS_ERR(free_list)) { + err = PTR_ERR(free_list); + goto err_drm_dev_exit; + } + + /* Allocate object handle for userspace. */ + err = xa_alloc(&pvr_file->free_list_handles, + &args->handle, + free_list, + xa_limit_32b, + GFP_KERNEL); + if (err < 0) + goto err_cleanup; + + drm_dev_exit(idx); + + return 0; + +err_cleanup: + pvr_free_list_put(free_list); + +err_drm_dev_exit: + drm_dev_exit(idx); + + return err; +} + +/** + * pvr_ioctl_destroy_free_list() - IOCTL to destroy a free list + * @drm_dev: [IN] DRM device. + * @raw_args: [IN] Arguments passed to this IOCTL. This must be of type + * &struct drm_pvr_ioctl_destroy_free_list_args. + * @file: [IN] DRM file private data. + * + * Called from userspace with %DRM_IOCTL_PVR_DESTROY_FREE_LIST. + * + * Return: + * * 0 on success, or + * * -%EINVAL if free list not in object list. + */ +static int +pvr_ioctl_destroy_free_list(struct drm_device *drm_dev, void *raw_args, + struct drm_file *file) +{ + struct drm_pvr_ioctl_destroy_free_list_args *args = raw_args; + struct pvr_file *pvr_file = to_pvr_file(file); + struct pvr_free_list *free_list; + + if (args->_padding_4) + return -EINVAL; + + free_list = xa_erase(&pvr_file->free_list_handles, args->handle); + if (!free_list) + return -EINVAL; + + pvr_free_list_put(free_list); + return 0; +} + +/** + * pvr_ioctl_create_hwrt_dataset() - IOCTL to create a HWRT dataset + * @drm_dev: [IN] DRM device. + * @raw_args: [IN/OUT] Arguments passed to this IOCTL. This must be of type + * &struct drm_pvr_ioctl_create_hwrt_dataset_args. + * @file: [IN] DRM file private data. + * + * Called from userspace with %DRM_IOCTL_PVR_CREATE_HWRT_DATASET. + * + * Return: + * * 0 on success, or + * * Any error returned by pvr_hwrt_dataset_create(). + */ +static int +pvr_ioctl_create_hwrt_dataset(struct drm_device *drm_dev, void *raw_args, + struct drm_file *file) +{ + struct drm_pvr_ioctl_create_hwrt_dataset_args *args = raw_args; + struct pvr_file *pvr_file = to_pvr_file(file); + struct pvr_hwrt_dataset *hwrt; + int idx; + int err; + + if (!drm_dev_enter(drm_dev, &idx)) + return -EIO; + + hwrt = pvr_hwrt_dataset_create(pvr_file, args); + if (IS_ERR(hwrt)) { + err = PTR_ERR(hwrt); + goto err_drm_dev_exit; + } + + /* Allocate object handle for userspace. */ + err = xa_alloc(&pvr_file->hwrt_handles, + &args->handle, + hwrt, + xa_limit_32b, + GFP_KERNEL); + if (err < 0) + goto err_cleanup; + + drm_dev_exit(idx); + + return 0; + +err_cleanup: + pvr_hwrt_dataset_put(hwrt); + +err_drm_dev_exit: + drm_dev_exit(idx); + + return err; +} + +/** + * pvr_ioctl_destroy_hwrt_dataset() - IOCTL to destroy a HWRT dataset + * @drm_dev: [IN] DRM device. + * @raw_args: [IN] Arguments passed to this IOCTL. This must be of type + * &struct drm_pvr_ioctl_destroy_hwrt_dataset_args. + * @file: [IN] DRM file private data. + * + * Called from userspace with %DRM_IOCTL_PVR_DESTROY_HWRT_DATASET. + * + * Return: + * * 0 on success, or + * * -%EINVAL if HWRT dataset not in object list. + */ +static int +pvr_ioctl_destroy_hwrt_dataset(struct drm_device *drm_dev, void *raw_args, + struct drm_file *file) +{ + struct drm_pvr_ioctl_destroy_hwrt_dataset_args *args = raw_args; + struct pvr_file *pvr_file = to_pvr_file(file); + struct pvr_hwrt_dataset *hwrt; + + if (args->_padding_4) + return -EINVAL; + + hwrt = xa_erase(&pvr_file->hwrt_handles, args->handle); + if (!hwrt) + return -EINVAL; + + pvr_hwrt_dataset_put(hwrt); + return 0; +} + +/** + * pvr_ioctl_create_vm_context() - IOCTL to create a VM context + * @drm_dev: [IN] DRM device. + * @raw_args: [IN/OUT] Arguments passed to this IOCTL. This must be of type + * &struct drm_pvr_ioctl_create_vm_context_args. + * @file: [IN] DRM file private data. + * + * Called from userspace with %DRM_IOCTL_PVR_CREATE_VM_CONTEXT. + * + * Return: + * * 0 on success, or + * * Any error returned by pvr_vm_create_context(). + */ +static int +pvr_ioctl_create_vm_context(struct drm_device *drm_dev, void *raw_args, + struct drm_file *file) +{ + struct drm_pvr_ioctl_create_vm_context_args *args = raw_args; + struct pvr_file *pvr_file = to_pvr_file(file); + struct pvr_vm_context *vm_ctx; + int idx; + int err; + + if (!drm_dev_enter(drm_dev, &idx)) + return -EIO; + + if (args->_padding_4) { + err = -EINVAL; + goto err_drm_dev_exit; + } + + vm_ctx = pvr_vm_create_context(pvr_file->pvr_dev, true); + if (IS_ERR(vm_ctx)) { + err = PTR_ERR(vm_ctx); + goto err_drm_dev_exit; + } + + /* Allocate object handle for userspace. */ + err = xa_alloc(&pvr_file->vm_ctx_handles, + &args->handle, + vm_ctx, + xa_limit_32b, + GFP_KERNEL); + if (err < 0) + goto err_cleanup; + + drm_dev_exit(idx); + + return 0; + +err_cleanup: + pvr_vm_context_put(vm_ctx); + +err_drm_dev_exit: + drm_dev_exit(idx); + + return err; +} + +/** + * pvr_ioctl_destroy_vm_context() - IOCTL to destroy a VM context +* @drm_dev: [IN] DRM device. +* @raw_args: [IN] Arguments passed to this IOCTL. This must be of type +* &struct drm_pvr_ioctl_destroy_vm_context_args. +* @file: [IN] DRM file private data. +* +* Called from userspace with %DRM_IOCTL_PVR_DESTROY_VM_CONTEXT. +* +* Return: +* * 0 on success, or +* * -%EINVAL if object not in object list. + */ +static int +pvr_ioctl_destroy_vm_context(struct drm_device *drm_dev, void *raw_args, + struct drm_file *file) +{ + struct drm_pvr_ioctl_destroy_vm_context_args *args = raw_args; + struct pvr_file *pvr_file = to_pvr_file(file); + struct pvr_vm_context *vm_ctx; + + if (args->_padding_4) + return -EINVAL; + + vm_ctx = xa_erase(&pvr_file->vm_ctx_handles, args->handle); + if (!vm_ctx) + return -EINVAL; + + pvr_vm_context_put(vm_ctx); + return 0; +} + +/** + * pvr_ioctl_vm_map() - IOCTL to map buffer to GPU address space. + * @drm_dev: [IN] DRM device. + * @raw_args: [IN] Arguments passed to this IOCTL. This must be of type + * &struct drm_pvr_ioctl_vm_map_args. + * @file: [IN] DRM file private data. + * + * Called from userspace with %DRM_IOCTL_PVR_VM_MAP. + * + * Return: + * * 0 on success, + * * -%EINVAL if &drm_pvr_ioctl_vm_op_map_args.flags is not zero, + * * -%EINVAL if the bounds specified by &drm_pvr_ioctl_vm_op_map_args.offset + * and &drm_pvr_ioctl_vm_op_map_args.size are not valid or do not fall + * within the buffer object specified by + * &drm_pvr_ioctl_vm_op_map_args.handle, + * * -%EINVAL if the bounds specified by + * &drm_pvr_ioctl_vm_op_map_args.device_addr and + * &drm_pvr_ioctl_vm_op_map_args.size do not form a valid device-virtual + * address range which falls entirely within a single heap, or + * * -%ENOENT if &drm_pvr_ioctl_vm_op_map_args.handle does not refer to a + * valid PowerVR buffer object. + */ +static int +pvr_ioctl_vm_map(struct drm_device *drm_dev, void *raw_args, + struct drm_file *file) +{ + struct pvr_device *pvr_dev = to_pvr_device(drm_dev); + struct drm_pvr_ioctl_vm_map_args *args = raw_args; + struct pvr_file *pvr_file = to_pvr_file(file); + struct pvr_vm_context *vm_ctx; + + struct pvr_gem_object *pvr_obj; + size_t pvr_obj_size; + + u64 offset_plus_size; + int idx; + int err; + + if (!drm_dev_enter(drm_dev, &idx)) + return -EIO; + + /* Initial validation of args. */ + if (args->_padding_14) { + err = -EINVAL; + goto err_drm_dev_exit; + } + + if (args->flags != 0 || + check_add_overflow(args->offset, args->size, &offset_plus_size) || + !pvr_find_heap_containing(pvr_dev, args->device_addr, args->size)) { + err = -EINVAL; + goto err_drm_dev_exit; + } + + vm_ctx = pvr_vm_context_lookup(pvr_file, args->vm_context_handle); + if (!vm_ctx) { + err = -EINVAL; + goto err_drm_dev_exit; + } + + pvr_obj = pvr_gem_object_from_handle(pvr_file, args->handle); + if (!pvr_obj) { + err = -ENOENT; + goto err_put_vm_context; + } + + pvr_obj_size = pvr_gem_object_size(pvr_obj); + + /* + * Validate offset and size args. The alignment of these will be + * checked when mapping; for now just check that they're within valid + * bounds + */ + if (args->offset >= pvr_obj_size || offset_plus_size > pvr_obj_size) { + err = -EINVAL; + goto err_put_pvr_object; + } + + err = pvr_vm_map(vm_ctx, pvr_obj, args->offset, + args->device_addr, args->size); + if (err) + goto err_put_pvr_object; + + /* + * In order to set up the mapping, we needed a reference to &pvr_obj. + * However, pvr_vm_map() obtains and stores its own reference, so we + * must release ours before returning. + */ + +err_put_pvr_object: + pvr_gem_object_put(pvr_obj); + +err_put_vm_context: + pvr_vm_context_put(vm_ctx); + +err_drm_dev_exit: + drm_dev_exit(idx); + + return err; +} + +/** + * pvr_ioctl_vm_unmap() - IOCTL to unmap buffer from GPU address space. + * @drm_dev: [IN] DRM device. + * @raw_args: [IN] Arguments passed to this IOCTL. This must be of type + * &struct drm_pvr_ioctl_vm_unmap_args. + * @file: [IN] DRM file private data. + * + * Called from userspace with %DRM_IOCTL_PVR_VM_UNMAP. + * + * Return: + * * 0 on success, + * * -%EINVAL if &drm_pvr_ioctl_vm_op_unmap_args.device_addr is not a valid + * device page-aligned device-virtual address, or + * * -%ENOENT if there is currently no PowerVR buffer object mapped at + * &drm_pvr_ioctl_vm_op_unmap_args.device_addr. + */ +static int +pvr_ioctl_vm_unmap(struct drm_device *drm_dev, void *raw_args, + struct drm_file *file) +{ + struct drm_pvr_ioctl_vm_unmap_args *args = raw_args; + struct pvr_file *pvr_file = to_pvr_file(file); + struct pvr_vm_context *vm_ctx; + int err; + + /* Initial validation of args. */ + if (args->_padding_4) + return -EINVAL; + + vm_ctx = pvr_vm_context_lookup(pvr_file, args->vm_context_handle); + if (!vm_ctx) + return -EINVAL; + + err = pvr_vm_unmap(vm_ctx, args->device_addr, args->size); + + pvr_vm_context_put(vm_ctx); + + return err; +} + +/* + * pvr_ioctl_submit_job() - IOCTL to submit a job to the GPU + * @drm_dev: [IN] DRM device. + * @raw_args: [IN] Arguments passed to this IOCTL. This must be of type + * &struct drm_pvr_ioctl_submit_job_args. + * @file: [IN] DRM file private data. + * + * Called from userspace with %DRM_IOCTL_PVR_SUBMIT_JOB. + * + * Return: + * * 0 on success, or + * * -%EINVAL if arguments are invalid. + */ +static int +pvr_ioctl_submit_jobs(struct drm_device *drm_dev, void *raw_args, + struct drm_file *file) +{ + struct drm_pvr_ioctl_submit_jobs_args *args = raw_args; + struct pvr_device *pvr_dev = to_pvr_device(drm_dev); + struct pvr_file *pvr_file = to_pvr_file(file); + int idx; + int err; + + if (!drm_dev_enter(drm_dev, &idx)) + return -EIO; + + err = pvr_submit_jobs(pvr_dev, pvr_file, args); + + drm_dev_exit(idx); + + return err; +} + +int +pvr_get_uobj(u64 usr_ptr, u32 usr_stride, u32 min_stride, u32 obj_size, void *out) +{ + if (usr_stride < min_stride) + return -EINVAL; + + return copy_struct_from_user(out, obj_size, u64_to_user_ptr(usr_ptr), usr_stride); +} + +int +pvr_set_uobj(u64 usr_ptr, u32 usr_stride, u32 min_stride, u32 obj_size, const void *in) +{ + if (usr_stride < min_stride) + return -EINVAL; + + if (copy_to_user(u64_to_user_ptr(usr_ptr), in, min_t(u32, usr_stride, obj_size))) + return -EFAULT; + + if (usr_stride > obj_size && + clear_user(u64_to_user_ptr(usr_ptr + obj_size), usr_stride - obj_size)) { + return -EFAULT; + } + + return 0; +} + +int +pvr_get_uobj_array(const struct drm_pvr_obj_array *in, u32 min_stride, u32 obj_size, void **out) +{ + int ret = 0; + void *out_alloc; + + if (in->stride < min_stride) + return -EINVAL; + + if (!in->count) + return 0; + + out_alloc = kvmalloc_array(in->count, obj_size, GFP_KERNEL); + if (!out_alloc) + return -ENOMEM; + + if (obj_size == in->stride) { + if (copy_from_user(out_alloc, u64_to_user_ptr(in->array), + (unsigned long)obj_size * in->count)) + ret = -EFAULT; + } else { + void __user *in_ptr = u64_to_user_ptr(in->array); + void *out_ptr = out_alloc; + + for (u32 i = 0; i < in->count; i++) { + ret = copy_struct_from_user(out_ptr, obj_size, in_ptr, in->stride); + if (ret) + break; + + out_ptr += obj_size; + in_ptr += in->stride; + } + } + + if (ret) { + kvfree(out_alloc); + return ret; + } + + *out = out_alloc; + return 0; +} + +int +pvr_set_uobj_array(const struct drm_pvr_obj_array *out, u32 min_stride, u32 obj_size, + const void *in) +{ + if (out->stride < min_stride) + return -EINVAL; + + if (!out->count) + return 0; + + if (obj_size == out->stride) { + if (copy_to_user(u64_to_user_ptr(out->array), in, + (unsigned long)obj_size * out->count)) + return -EFAULT; + } else { + u32 cpy_elem_size = min_t(u32, out->stride, obj_size); + void __user *out_ptr = u64_to_user_ptr(out->array); + const void *in_ptr = in; + + for (u32 i = 0; i < out->count; i++) { + if (copy_to_user(out_ptr, in_ptr, cpy_elem_size)) + return -EFAULT; + + out_ptr += obj_size; + in_ptr += out->stride; + } + + if (out->stride > obj_size && + clear_user(u64_to_user_ptr(out->array + obj_size), + out->stride - obj_size)) { + return -EFAULT; + } + } + + return 0; +} + +#define DRM_PVR_IOCTL(_name, _func, _flags) \ + DRM_IOCTL_DEF_DRV(PVR_##_name, pvr_ioctl_##_func, _flags) + +/* clang-format off */ + +static const struct drm_ioctl_desc pvr_drm_driver_ioctls[] = { + DRM_PVR_IOCTL(DEV_QUERY, dev_query, DRM_RENDER_ALLOW), + DRM_PVR_IOCTL(CREATE_BO, create_bo, DRM_RENDER_ALLOW), + DRM_PVR_IOCTL(GET_BO_MMAP_OFFSET, get_bo_mmap_offset, DRM_RENDER_ALLOW), + DRM_PVR_IOCTL(CREATE_VM_CONTEXT, create_vm_context, DRM_RENDER_ALLOW), + DRM_PVR_IOCTL(DESTROY_VM_CONTEXT, destroy_vm_context, DRM_RENDER_ALLOW), + DRM_PVR_IOCTL(VM_MAP, vm_map, DRM_RENDER_ALLOW), + DRM_PVR_IOCTL(VM_UNMAP, vm_unmap, DRM_RENDER_ALLOW), + DRM_PVR_IOCTL(CREATE_CONTEXT, create_context, DRM_RENDER_ALLOW), + DRM_PVR_IOCTL(DESTROY_CONTEXT, destroy_context, DRM_RENDER_ALLOW), + DRM_PVR_IOCTL(CREATE_FREE_LIST, create_free_list, DRM_RENDER_ALLOW), + DRM_PVR_IOCTL(DESTROY_FREE_LIST, destroy_free_list, DRM_RENDER_ALLOW), + DRM_PVR_IOCTL(CREATE_HWRT_DATASET, create_hwrt_dataset, DRM_RENDER_ALLOW), + DRM_PVR_IOCTL(DESTROY_HWRT_DATASET, destroy_hwrt_dataset, DRM_RENDER_ALLOW), + DRM_PVR_IOCTL(SUBMIT_JOBS, submit_jobs, DRM_RENDER_ALLOW), +}; + +/* clang-format on */ + +#undef DRM_PVR_IOCTL + +/** + * pvr_drm_driver_open() - Driver callback when a new &struct drm_file is opened + * @drm_dev: [IN] DRM device. + * @file: [IN] DRM file private data. + * + * Allocates powervr-specific file private data (&struct pvr_file). + * + * Registered in &pvr_drm_driver. + * + * Return: + * * 0 on success, + * * -%ENOMEM if the allocation of a &struct ipvr_file fails, or + * * Any error returned by pvr_memory_context_init(). + */ +static int +pvr_drm_driver_open(struct drm_device *drm_dev, struct drm_file *file) +{ + struct pvr_device *pvr_dev = to_pvr_device(drm_dev); + struct pvr_file *pvr_file; + + pvr_file = kzalloc(sizeof(*pvr_file), GFP_KERNEL); + if (!pvr_file) + return -ENOMEM; + + /* + * Store reference to base DRM file private data for use by + * from_pvr_file. + */ + pvr_file->file = file; + + /* + * Store reference to powervr-specific outer device struct in file + * private data for convenient access. + */ + pvr_file->pvr_dev = pvr_dev; + + xa_init_flags(&pvr_file->ctx_handles, XA_FLAGS_ALLOC1); + xa_init_flags(&pvr_file->free_list_handles, XA_FLAGS_ALLOC1); + xa_init_flags(&pvr_file->hwrt_handles, XA_FLAGS_ALLOC1); + xa_init_flags(&pvr_file->vm_ctx_handles, XA_FLAGS_ALLOC1); + + /* + * Store reference to powervr-specific file private data in DRM file + * private data. + */ + file->driver_priv = pvr_file; + + return 0; +} + +/** + * pvr_drm_driver_postclose() - One of the driver callbacks when a &struct + * drm_file is closed. + * @drm_dev: [IN] DRM device (unused). + * @file: [IN] DRM file private data. + * + * Frees powervr-specific file private data (&struct pvr_file). + * + * Registered in &pvr_drm_driver. + */ +static void +pvr_drm_driver_postclose(__always_unused struct drm_device *drm_dev, + struct drm_file *file) +{ + struct pvr_file *pvr_file = to_pvr_file(file); + + /* Kill remaining contexts. */ + pvr_destroy_contexts_for_file(pvr_file); + + /* Drop references on any remaining objects. */ + pvr_destroy_free_lists_for_file(pvr_file); + pvr_destroy_hwrt_datasets_for_file(pvr_file); + pvr_destroy_vm_contexts_for_file(pvr_file); + + kfree(pvr_file); + file->driver_priv = NULL; +} + +DEFINE_DRM_GEM_FOPS(pvr_drm_driver_fops); + +static struct drm_driver pvr_drm_driver = { + .driver_features = DRIVER_GEM | DRIVER_GEM_GPUVA | DRIVER_RENDER | + DRIVER_SYNCOBJ | DRIVER_SYNCOBJ_TIMELINE, + .open = pvr_drm_driver_open, + .postclose = pvr_drm_driver_postclose, + .ioctls = pvr_drm_driver_ioctls, + .num_ioctls = ARRAY_SIZE(pvr_drm_driver_ioctls), + .fops = &pvr_drm_driver_fops, +#if defined(CONFIG_DEBUG_FS) + .debugfs_init = pvr_debugfs_init, +#endif + + .name = PVR_DRIVER_NAME, + .desc = PVR_DRIVER_DESC, + .date = PVR_DRIVER_DATE, + .major = PVR_DRIVER_MAJOR, + .minor = PVR_DRIVER_MINOR, + .patchlevel = PVR_DRIVER_PATCHLEVEL, + + .gem_prime_import_sg_table = drm_gem_shmem_prime_import_sg_table, + .gem_create_object = pvr_gem_create_object, +}; + +static int +pvr_probe(struct platform_device *plat_dev) +{ + struct pvr_device *pvr_dev; + struct drm_device *drm_dev; + int err; + + pvr_dev = devm_drm_dev_alloc(&plat_dev->dev, &pvr_drm_driver, + struct pvr_device, base); + if (IS_ERR(pvr_dev)) + return PTR_ERR(pvr_dev); + + drm_dev = &pvr_dev->base; + + platform_set_drvdata(plat_dev, drm_dev); + + init_rwsem(&pvr_dev->reset_sem); + + pvr_context_device_init(pvr_dev); + + err = pvr_queue_device_init(pvr_dev); + if (err) + goto err_context_fini; + + devm_pm_runtime_enable(&plat_dev->dev); + pm_runtime_mark_last_busy(&plat_dev->dev); + + pm_runtime_set_autosuspend_delay(&plat_dev->dev, 50); + pm_runtime_use_autosuspend(&plat_dev->dev); + pvr_watchdog_init(pvr_dev); + + err = pvr_device_init(pvr_dev); + if (err) + goto err_watchdog_fini; + + err = drm_dev_register(drm_dev, 0); + if (err) + goto err_device_fini; + + xa_init_flags(&pvr_dev->free_list_ids, XA_FLAGS_ALLOC1); + xa_init_flags(&pvr_dev->job_ids, XA_FLAGS_ALLOC1); + + return 0; + +err_device_fini: + pvr_device_fini(pvr_dev); + +err_watchdog_fini: + pvr_watchdog_fini(pvr_dev); + + pvr_queue_device_fini(pvr_dev); + +err_context_fini: + pvr_context_device_fini(pvr_dev); + + return err; +} + +static int +pvr_remove(struct platform_device *plat_dev) +{ + struct drm_device *drm_dev = platform_get_drvdata(plat_dev); + struct pvr_device *pvr_dev = to_pvr_device(drm_dev); + + WARN_ON(!xa_empty(&pvr_dev->job_ids)); + WARN_ON(!xa_empty(&pvr_dev->free_list_ids)); + + xa_destroy(&pvr_dev->job_ids); + xa_destroy(&pvr_dev->free_list_ids); + + pm_runtime_suspend(drm_dev->dev); + pvr_device_fini(pvr_dev); + drm_dev_unplug(drm_dev); + pvr_watchdog_fini(pvr_dev); + pvr_queue_device_fini(pvr_dev); + pvr_context_device_fini(pvr_dev); + + return 0; +} + +static const struct of_device_id dt_match[] = { + { .compatible = "img,img-axe", .data = NULL }, + {} +}; +MODULE_DEVICE_TABLE(of, dt_match); + +static const struct dev_pm_ops pvr_pm_ops = { + RUNTIME_PM_OPS(pvr_power_device_suspend, pvr_power_device_resume, pvr_power_device_idle) +}; + +static struct platform_driver pvr_driver = { + .probe = pvr_probe, + .remove = pvr_remove, + .driver = { + .name = PVR_DRIVER_NAME, + .pm = &pvr_pm_ops, + .of_match_table = dt_match, + }, +}; +module_platform_driver(pvr_driver); + +MODULE_AUTHOR("Imagination Technologies Ltd."); +MODULE_DESCRIPTION(PVR_DRIVER_DESC); +MODULE_LICENSE("Dual MIT/GPL"); +MODULE_IMPORT_NS(DMA_BUF); +MODULE_FIRMWARE("powervr/rogue_33.15.11.3_v1.fw"); diff --git a/drivers/gpu/drm/imagination/pvr_drv.h b/drivers/gpu/drm/imagination/pvr_drv.h new file mode 100644 index 00000000000000..378fe477b75967 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_drv.h @@ -0,0 +1,129 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_DRV_H +#define PVR_DRV_H + +#include "linux/compiler_attributes.h" +#include + +#define PVR_DRIVER_NAME "powervr" +#define PVR_DRIVER_DESC "Imagination PowerVR (Series 6 and later) & IMG Graphics" +#define PVR_DRIVER_DATE "20230904" + +/* + * Driver interface version: + * - 1.0: Initial interface + */ +#define PVR_DRIVER_MAJOR 1 +#define PVR_DRIVER_MINOR 0 +#define PVR_DRIVER_PATCHLEVEL 0 + +int pvr_get_uobj(u64 usr_ptr, u32 usr_size, u32 min_size, u32 obj_size, void *out); +int pvr_set_uobj(u64 usr_ptr, u32 usr_size, u32 min_size, u32 obj_size, const void *in); +int pvr_get_uobj_array(const struct drm_pvr_obj_array *in, u32 min_stride, u32 obj_size, + void **out); +int pvr_set_uobj_array(const struct drm_pvr_obj_array *out, u32 min_stride, u32 obj_size, + const void *in); + +#define PVR_UOBJ_MIN_SIZE_INTERNAL(_typename, _last_mandatory_field) \ + (offsetof(_typename, _last_mandatory_field) + \ + sizeof(((_typename *)NULL)->_last_mandatory_field)) + +/* NOLINTBEGIN(bugprone-macro-parentheses) */ +#define PVR_UOBJ_DECL(_typename, _last_mandatory_field) \ + , _typename : PVR_UOBJ_MIN_SIZE_INTERNAL(_typename, _last_mandatory_field) +/* NOLINTEND(bugprone-macro-parentheses) */ + +/** + * DOC: PVR user objects. + * + * Macros used to aid copying structured and array data to and from + * userspace. Objects can differ in size, provided the minimum size + * allowed is specified (using the last mandatory field in the struct). + * All types used with PVR_UOBJ_GET/SET macros must be listed here under + * PVR_UOBJ_MIN_SIZE, with the last mandatory struct field specified. + */ + +/** + * PVR_UOBJ_MIN_SIZE() - Fetch the minimum copy size of a compatible type object. + * @_obj_name: The name of the object. Cannot be a typename - this is deduced. + * + * This cannot fail. Using the macro with an incompatible type will result in a + * compiler error. + * + * To add compatibility for a type, list it within the macro in an orderly + * fashion. The second argument is the name of the last mandatory field of the + * struct type, which is used to calculate the size. See also PVR_UOBJ_DECL(). + * + * Return: The minimum copy size. + */ +#define PVR_UOBJ_MIN_SIZE(_obj_name) _Generic(_obj_name \ + PVR_UOBJ_DECL(struct drm_pvr_job, hwrt) \ + PVR_UOBJ_DECL(struct drm_pvr_sync_op, value) \ + PVR_UOBJ_DECL(struct drm_pvr_dev_query_gpu_info, num_phantoms) \ + PVR_UOBJ_DECL(struct drm_pvr_dev_query_runtime_info, cdm_max_local_mem_size_regs) \ + PVR_UOBJ_DECL(struct drm_pvr_dev_query_quirks, _padding_c) \ + PVR_UOBJ_DECL(struct drm_pvr_dev_query_enhancements, _padding_c) \ + PVR_UOBJ_DECL(struct drm_pvr_heap, page_size_log2) \ + PVR_UOBJ_DECL(struct drm_pvr_dev_query_heap_info, heaps) \ + PVR_UOBJ_DECL(struct drm_pvr_static_data_area, offset) \ + PVR_UOBJ_DECL(struct drm_pvr_dev_query_static_data_areas, static_data_areas) \ + ) + +/** + * PVR_UOBJ_GET() - Copies from _src_usr_ptr to &_dest_obj. + * @_dest_obj: The destination container object in kernel space. + * @_usr_size: The size of the source container in user space. + * @_src_usr_ptr: __u64 raw pointer to the source container in user space. + * + * Return: Error code. See pvr_get_uobj(). + */ +#define PVR_UOBJ_GET(_dest_obj, _usr_size, _src_usr_ptr) \ + pvr_get_uobj(_src_usr_ptr, _usr_size, \ + PVR_UOBJ_MIN_SIZE(_dest_obj), \ + sizeof(_dest_obj), &(_dest_obj)) + +/** + * PVR_UOBJ_SET() - Copies from &_src_obj to _dest_usr_ptr. + * @_dest_usr_ptr: __u64 raw pointer to the destination container in user space. + * @_usr_size: The size of the destination container in user space. + * @_src_obj: The source container object in kernel space. + * + * Return: Error code. See pvr_set_uobj(). + */ +#define PVR_UOBJ_SET(_dest_usr_ptr, _usr_size, _src_obj) \ + pvr_set_uobj(_dest_usr_ptr, _usr_size, \ + PVR_UOBJ_MIN_SIZE(_src_obj), \ + sizeof(_src_obj), &(_src_obj)) + +/** + * PVR_UOBJ_GET_ARRAY() - Copies from @_src_drm_pvr_obj_array.array to + * alloced memory and returns a pointer in _dest_array. + * @_dest_array: The destination C array object in kernel space. + * @_src_drm_pvr_obj_array: The &struct drm_pvr_obj_array containing a __u64 raw + * pointer to the source C array in user space and the size of each array + * element in user space (the 'stride'). + * + * Return: Error code. See pvr_get_uobj_array(). + */ +#define PVR_UOBJ_GET_ARRAY(_dest_array, _src_drm_pvr_obj_array) \ + pvr_get_uobj_array(_src_drm_pvr_obj_array, \ + PVR_UOBJ_MIN_SIZE((_dest_array)[0]), \ + sizeof((_dest_array)[0]), (void **)&(_dest_array)) + +/** + * PVR_UOBJ_SET_ARRAY() - Copies from _src_array to @_dest_drm_pvr_obj_array.array. + * @_dest_drm_pvr_obj_array: The &struct drm_pvr_obj_array containing a __u64 raw + * pointer to the destination C array in user space and the size of each array + * element in user space (the 'stride'). + * @_src_array: The source C array object in kernel space. + * + * Return: Error code. See pvr_set_uobj_array(). + */ +#define PVR_UOBJ_SET_ARRAY(_dest_drm_pvr_obj_array, _src_array) \ + pvr_set_uobj_array(_dest_drm_pvr_obj_array, \ + PVR_UOBJ_MIN_SIZE((_src_array)[0]), \ + sizeof((_src_array)[0]), _src_array) + +#endif /* PVR_DRV_H */ diff --git a/drivers/gpu/drm/imagination/pvr_free_list.c b/drivers/gpu/drm/imagination/pvr_free_list.c new file mode 100644 index 00000000000000..5e51bc980751c9 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_free_list.c @@ -0,0 +1,625 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_free_list.h" +#include "pvr_gem.h" +#include "pvr_hwrt.h" +#include "pvr_rogue_fwif.h" +#include "pvr_vm.h" + +#include +#include +#include +#include + +#define FREE_LIST_ENTRY_SIZE sizeof(u32) + +#define FREE_LIST_ALIGNMENT \ + ((ROGUE_BIF_PM_FREELIST_BASE_ADDR_ALIGNSIZE / FREE_LIST_ENTRY_SIZE) - 1) + +#define FREE_LIST_MIN_PAGES 50 +#define FREE_LIST_MIN_PAGES_BRN66011 40 +#define FREE_LIST_MIN_PAGES_ROGUEXE 25 + +/** + * pvr_get_free_list_min_pages() - Get minimum free list size for this device + * @pvr_dev: Device pointer. + * + * Returns: + * * Minimum free list size, in PM physical pages. + */ +u32 +pvr_get_free_list_min_pages(struct pvr_device *pvr_dev) +{ + u32 value; + + if (PVR_HAS_FEATURE(pvr_dev, roguexe)) { + if (PVR_HAS_QUIRK(pvr_dev, 66011)) + value = FREE_LIST_MIN_PAGES_BRN66011; + else + value = FREE_LIST_MIN_PAGES_ROGUEXE; + } else { + value = FREE_LIST_MIN_PAGES; + } + + return value; +} + +static int +free_list_create_kernel_structure(struct pvr_file *pvr_file, + struct drm_pvr_ioctl_create_free_list_args *args, + struct pvr_free_list *free_list) +{ + struct pvr_gem_object *free_list_obj; + struct pvr_vm_context *vm_ctx; + u64 free_list_size; + int err; + + if (args->grow_threshold > 100 || + args->initial_num_pages > args->max_num_pages || + args->grow_num_pages > args->max_num_pages || + args->max_num_pages == 0 || + (args->initial_num_pages < args->max_num_pages && !args->grow_num_pages) || + (args->initial_num_pages == args->max_num_pages && args->grow_num_pages)) + return -EINVAL; + + if ((args->initial_num_pages & FREE_LIST_ALIGNMENT) || + (args->max_num_pages & FREE_LIST_ALIGNMENT) || + (args->grow_num_pages & FREE_LIST_ALIGNMENT)) + return -EINVAL; + + vm_ctx = pvr_vm_context_lookup(pvr_file, args->vm_context_handle); + if (!vm_ctx) + return -EINVAL; + + free_list_obj = pvr_vm_find_gem_object(vm_ctx, args->free_list_gpu_addr, + NULL, &free_list_size); + if (!free_list_obj) { + err = -EINVAL; + goto err_put_vm_context; + } + + if ((free_list_obj->flags & DRM_PVR_BO_ALLOW_CPU_USERSPACE_ACCESS) || + !(free_list_obj->flags & DRM_PVR_BO_PM_FW_PROTECT) || + free_list_size < (args->max_num_pages * FREE_LIST_ENTRY_SIZE)) { + err = -EINVAL; + goto err_put_free_list_obj; + } + + free_list->pvr_dev = pvr_file->pvr_dev; + free_list->current_pages = 0; + free_list->max_pages = args->max_num_pages; + free_list->grow_pages = args->grow_num_pages; + free_list->grow_threshold = args->grow_threshold; + free_list->obj = free_list_obj; + free_list->free_list_gpu_addr = args->free_list_gpu_addr; + free_list->initial_num_pages = args->initial_num_pages; + + pvr_vm_context_put(vm_ctx); + + return 0; + +err_put_free_list_obj: + pvr_gem_object_put(free_list_obj); + +err_put_vm_context: + pvr_vm_context_put(vm_ctx); + + return err; +} + +static void +free_list_destroy_kernel_structure(struct pvr_free_list *free_list) +{ + WARN_ON(!list_empty(&free_list->hwrt_list)); + + pvr_gem_object_put(free_list->obj); +} + +/** + * calculate_free_list_ready_pages_locked() - Function to work out the number of free + * list pages to reserve for growing within + * the FW without having to wait for the + * host to progress a grow request + * @free_list: Pointer to free list. + * @pages: Total pages currently in free list. + * + * If the threshold or grow size means less than the alignment size (4 pages on + * Rogue), then the feature is not used. + * + * Caller must hold &free_list->lock. + * + * Return: number of pages to reserve. + */ +static u32 +calculate_free_list_ready_pages_locked(struct pvr_free_list *free_list, u32 pages) +{ + u32 ready_pages; + + lockdep_assert_held(&free_list->lock); + + ready_pages = ((pages * free_list->grow_threshold) / 100); + + /* The number of pages must be less than the grow size. */ + ready_pages = min(ready_pages, free_list->grow_pages); + + /* + * The number of pages must be a multiple of the free list align size. + */ + ready_pages &= ~FREE_LIST_ALIGNMENT; + + return ready_pages; +} + +static u32 +calculate_free_list_ready_pages(struct pvr_free_list *free_list, u32 pages) +{ + u32 ret; + + mutex_lock(&free_list->lock); + + ret = calculate_free_list_ready_pages_locked(free_list, pages); + + mutex_unlock(&free_list->lock); + + return ret; +} + +static void +free_list_fw_init(void *cpu_ptr, void *priv) +{ + struct rogue_fwif_freelist *fw_data = cpu_ptr; + struct pvr_free_list *free_list = priv; + u32 ready_pages; + + /* Fill out FW structure */ + ready_pages = calculate_free_list_ready_pages(free_list, + free_list->initial_num_pages); + + fw_data->max_pages = free_list->max_pages; + fw_data->current_pages = free_list->initial_num_pages - ready_pages; + fw_data->grow_pages = free_list->grow_pages; + fw_data->ready_pages = ready_pages; + fw_data->freelist_id = free_list->fw_id; + fw_data->grow_pending = false; + fw_data->current_stack_top = fw_data->current_pages - 1; + fw_data->freelist_dev_addr = free_list->free_list_gpu_addr; + fw_data->current_dev_addr = (fw_data->freelist_dev_addr + + ((fw_data->max_pages - fw_data->current_pages) * + FREE_LIST_ENTRY_SIZE)) & + ~((u64)ROGUE_BIF_PM_FREELIST_BASE_ADDR_ALIGNSIZE - 1); +} + +static int +free_list_create_fw_structure(struct pvr_file *pvr_file, + struct drm_pvr_ioctl_create_free_list_args *args, + struct pvr_free_list *free_list) +{ + struct pvr_device *pvr_dev = pvr_file->pvr_dev; + + /* + * Create and map the FW structure so we can initialise it. This is not + * accessed on the CPU side post-initialisation so the mapping lifetime + * is only for this function. + */ + free_list->fw_data = pvr_fw_object_create_and_map(pvr_dev, sizeof(*free_list->fw_data), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + free_list_fw_init, free_list, + &free_list->fw_obj); + if (IS_ERR(free_list->fw_data)) + return PTR_ERR(free_list->fw_data); + + return 0; +} + +static void +free_list_destroy_fw_structure(struct pvr_free_list *free_list) +{ + pvr_fw_object_unmap_and_destroy(free_list->fw_obj); +} + +static int +pvr_free_list_insert_pages_locked(struct pvr_free_list *free_list, + struct sg_table *sgt, u32 offset, u32 num_pages) +{ + struct sg_dma_page_iter dma_iter; + u32 *page_list; + + lockdep_assert_held(&free_list->lock); + + page_list = pvr_gem_object_vmap(free_list->obj); + if (IS_ERR(page_list)) + return PTR_ERR(page_list); + + offset /= FREE_LIST_ENTRY_SIZE; + /* clang-format off */ + for_each_sgtable_dma_page(sgt, &dma_iter, 0) { + dma_addr_t dma_addr = sg_page_iter_dma_address(&dma_iter); + u64 dma_pfn = dma_addr >> + ROGUE_BIF_PM_PHYSICAL_PAGE_ALIGNSHIFT; + u32 dma_addr_offset; + + BUILD_BUG_ON(ROGUE_BIF_PM_PHYSICAL_PAGE_SIZE > PAGE_SIZE); + + for (dma_addr_offset = 0; dma_addr_offset < PAGE_SIZE; + dma_addr_offset += ROGUE_BIF_PM_PHYSICAL_PAGE_SIZE) { + WARN_ON_ONCE(dma_pfn >> 32); + + page_list[offset++] = (u32)dma_pfn; + dma_pfn++; + + num_pages--; + if (!num_pages) + break; + } + + if (!num_pages) + break; + } + /* clang-format on */ + + /* Make sure our free_list update is flushed. */ + wmb(); + + pvr_gem_object_vunmap(free_list->obj); + + return 0; +} + +static int +pvr_free_list_insert_node_locked(struct pvr_free_list_node *free_list_node) +{ + struct pvr_free_list *free_list = free_list_node->free_list; + struct sg_table *sgt; + u32 start_page; + u32 offset; + int err; + + lockdep_assert_held(&free_list->lock); + + start_page = free_list->max_pages - free_list->current_pages - + free_list_node->num_pages; + offset = (start_page * FREE_LIST_ENTRY_SIZE) & + ~((u64)ROGUE_BIF_PM_FREELIST_BASE_ADDR_ALIGNSIZE - 1); + + sgt = drm_gem_shmem_get_pages_sgt(&free_list_node->mem_obj->base); + if (WARN_ON(IS_ERR(sgt))) + return PTR_ERR(sgt); + + err = pvr_free_list_insert_pages_locked(free_list, sgt, + offset, free_list_node->num_pages); + if (!err) + free_list->current_pages += free_list_node->num_pages; + + return err; +} + +static int +pvr_free_list_grow(struct pvr_free_list *free_list, u32 num_pages) +{ + struct pvr_device *pvr_dev = free_list->pvr_dev; + struct pvr_free_list_node *free_list_node; + int err; + + mutex_lock(&free_list->lock); + + if (num_pages & FREE_LIST_ALIGNMENT) { + err = -EINVAL; + goto err_unlock; + } + + free_list_node = kzalloc(sizeof(*free_list_node), GFP_KERNEL); + if (!free_list_node) { + err = -ENOMEM; + goto err_unlock; + } + + free_list_node->num_pages = num_pages; + free_list_node->free_list = free_list; + + free_list_node->mem_obj = pvr_gem_object_create(pvr_dev, + num_pages << + ROGUE_BIF_PM_PHYSICAL_PAGE_ALIGNSHIFT, + PVR_BO_FW_FLAGS_DEVICE_CACHED); + if (IS_ERR(free_list_node->mem_obj)) { + err = PTR_ERR(free_list_node->mem_obj); + goto err_free; + } + + err = pvr_free_list_insert_node_locked(free_list_node); + if (err) + goto err_destroy_gem_object; + + list_add_tail(&free_list_node->node, &free_list->mem_block_list); + + /* + * Reserve a number ready pages to allow the FW to process OOM quickly + * and asynchronously request a grow. + */ + free_list->ready_pages = + calculate_free_list_ready_pages_locked(free_list, + free_list->current_pages); + free_list->current_pages -= free_list->ready_pages; + + mutex_unlock(&free_list->lock); + + return 0; + +err_destroy_gem_object: + pvr_gem_object_put(free_list_node->mem_obj); + +err_free: + kfree(free_list_node); + +err_unlock: + mutex_unlock(&free_list->lock); + + return err; +} + +void pvr_free_list_process_grow_req(struct pvr_device *pvr_dev, + struct rogue_fwif_fwccb_cmd_freelist_gs_data *req) +{ + struct pvr_free_list *free_list = pvr_free_list_lookup_id(pvr_dev, req->freelist_id); + struct rogue_fwif_kccb_cmd resp_cmd = { + .cmd_type = ROGUE_FWIF_KCCB_CMD_FREELIST_GROW_UPDATE, + }; + struct rogue_fwif_freelist_gs_data *resp = &resp_cmd.cmd_data.free_list_gs_data; + u32 grow_pages = 0; + + /* If we don't have a freelist registered for this ID, we can't do much. */ + if (WARN_ON(!free_list)) + return; + + /* Since the FW made the request, it has already consumed the ready pages, + * update the host struct. + */ + free_list->current_pages += free_list->ready_pages; + free_list->ready_pages = 0; + + /* If the grow succeeds, update the grow_pages argument. */ + if (!pvr_free_list_grow(free_list, free_list->grow_pages)) + grow_pages = free_list->grow_pages; + + /* Now prepare the response and send it back to the FW. */ + pvr_fw_object_get_fw_addr(free_list->fw_obj, &resp->freelist_fw_addr); + resp->delta_pages = grow_pages; + resp->new_pages = free_list->current_pages + free_list->ready_pages; + resp->ready_pages = free_list->ready_pages; + pvr_free_list_put(free_list); + + WARN_ON(pvr_kccb_send_cmd(pvr_dev, &resp_cmd, NULL)); +} + +static void +pvr_free_list_free_node(struct pvr_free_list_node *free_list_node) +{ + pvr_gem_object_put(free_list_node->mem_obj); + + kfree(free_list_node); +} + +/** + * pvr_free_list_create() - Create a new free list and return an object pointer + * @pvr_file: Pointer to pvr_file structure. + * @args: Creation arguments from userspace. + * + * Return: + * * Pointer to new free_list, or + * * ERR_PTR(-%ENOMEM) on out of memory. + */ +struct pvr_free_list * +pvr_free_list_create(struct pvr_file *pvr_file, + struct drm_pvr_ioctl_create_free_list_args *args) +{ + struct pvr_free_list *free_list; + int err; + + /* Create and fill out the kernel structure */ + free_list = kzalloc(sizeof(*free_list), GFP_KERNEL); + + if (!free_list) + return ERR_PTR(-ENOMEM); + + kref_init(&free_list->ref_count); + INIT_LIST_HEAD(&free_list->mem_block_list); + INIT_LIST_HEAD(&free_list->hwrt_list); + mutex_init(&free_list->lock); + + err = free_list_create_kernel_structure(pvr_file, args, free_list); + if (err < 0) + goto err_free; + + /* Allocate global object ID for firmware. */ + err = xa_alloc(&pvr_file->pvr_dev->free_list_ids, + &free_list->fw_id, + free_list, + xa_limit_32b, + GFP_KERNEL); + if (err) + goto err_destroy_kernel_structure; + + err = free_list_create_fw_structure(pvr_file, args, free_list); + if (err < 0) + goto err_free_fw_id; + + err = pvr_free_list_grow(free_list, args->initial_num_pages); + if (err < 0) + goto err_fw_struct_cleanup; + + return free_list; + +err_fw_struct_cleanup: + WARN_ON(pvr_fw_structure_cleanup(free_list->pvr_dev, + ROGUE_FWIF_CLEANUP_FREELIST, + free_list->fw_obj, 0)); + +err_free_fw_id: + xa_erase(&free_list->pvr_dev->free_list_ids, free_list->fw_id); + +err_destroy_kernel_structure: + free_list_destroy_kernel_structure(free_list); + +err_free: + mutex_destroy(&free_list->lock); + kfree(free_list); + + return ERR_PTR(err); +} + +static void +pvr_free_list_release(struct kref *ref_count) +{ + struct pvr_free_list *free_list = + container_of(ref_count, struct pvr_free_list, ref_count); + struct list_head *pos, *n; + int err; + + xa_erase(&free_list->pvr_dev->free_list_ids, free_list->fw_id); + + err = pvr_fw_structure_cleanup(free_list->pvr_dev, + ROGUE_FWIF_CLEANUP_FREELIST, + free_list->fw_obj, 0); + if (err == -EBUSY) { + /* Flush the FWCCB to process any HWR or freelist reconstruction + * request that might keep the freelist busy, and try again. + */ + pvr_fwccb_process(free_list->pvr_dev); + err = pvr_fw_structure_cleanup(free_list->pvr_dev, + ROGUE_FWIF_CLEANUP_FREELIST, + free_list->fw_obj, 0); + } + + WARN_ON(err); + + /* clang-format off */ + list_for_each_safe(pos, n, &free_list->mem_block_list) { + struct pvr_free_list_node *free_list_node = + container_of(pos, struct pvr_free_list_node, node); + + list_del(pos); + pvr_free_list_free_node(free_list_node); + } + /* clang-format on */ + + free_list_destroy_kernel_structure(free_list); + free_list_destroy_fw_structure(free_list); + mutex_destroy(&free_list->lock); + kfree(free_list); +} + +/** + * pvr_destroy_free_lists_for_file: Destroy any free lists associated with the + * given file. + * @pvr_file: Pointer to pvr_file structure. + * + * Removes all free lists associated with @pvr_file from the device free_list + * list and drops initial references. Free lists will then be destroyed once + * all outstanding references are dropped. + */ +void pvr_destroy_free_lists_for_file(struct pvr_file *pvr_file) +{ + struct pvr_free_list *free_list; + unsigned long handle; + + xa_for_each(&pvr_file->free_list_handles, handle, free_list) { + (void)free_list; + pvr_free_list_put(xa_erase(&pvr_file->free_list_handles, handle)); + } +} + +/** + * pvr_free_list_put() - Release reference on free list + * @free_list: Pointer to list to release reference on + */ +void +pvr_free_list_put(struct pvr_free_list *free_list) +{ + if (free_list) + kref_put(&free_list->ref_count, pvr_free_list_release); +} + +void pvr_free_list_add_hwrt(struct pvr_free_list *free_list, struct pvr_hwrt_data *hwrt_data) +{ + mutex_lock(&free_list->lock); + + list_add_tail(&hwrt_data->freelist_node, &free_list->hwrt_list); + + mutex_unlock(&free_list->lock); +} + +void pvr_free_list_remove_hwrt(struct pvr_free_list *free_list, struct pvr_hwrt_data *hwrt_data) +{ + mutex_lock(&free_list->lock); + + list_del(&hwrt_data->freelist_node); + + mutex_unlock(&free_list->lock); +} + +static void +pvr_free_list_reconstruct(struct pvr_device *pvr_dev, u32 freelist_id) +{ + struct pvr_free_list *free_list = pvr_free_list_lookup_id(pvr_dev, freelist_id); + struct pvr_free_list_node *free_list_node; + struct rogue_fwif_freelist *fw_data; + struct pvr_hwrt_data *hwrt_data; + + if (!free_list) + return; + + mutex_lock(&free_list->lock); + + /* Rebuild the free list based on the memory block list. */ + free_list->current_pages = 0; + + list_for_each_entry(free_list_node, &free_list->mem_block_list, node) + WARN_ON(pvr_free_list_insert_node_locked(free_list_node)); + + /* + * Remove the ready pages, which are reserved to allow the FW to process OOM quickly and + * asynchronously request a grow. + */ + free_list->current_pages -= free_list->ready_pages; + + fw_data = free_list->fw_data; + fw_data->current_stack_top = fw_data->current_pages - 1; + fw_data->allocated_page_count = 0; + fw_data->allocated_mmu_page_count = 0; + + /* Reset the state of any associated HWRTs. */ + list_for_each_entry(hwrt_data, &free_list->hwrt_list, freelist_node) { + struct rogue_fwif_hwrtdata *hwrt_fw_data = pvr_fw_object_vmap(hwrt_data->fw_obj); + + if (!WARN_ON(IS_ERR(hwrt_fw_data))) { + hwrt_fw_data->state = ROGUE_FWIF_RTDATA_STATE_HWR; + hwrt_fw_data->hwrt_data_flags &= ~HWRTDATA_HAS_LAST_GEOM; + } + + pvr_fw_object_vunmap(hwrt_data->fw_obj); + } + + mutex_unlock(&free_list->lock); + + pvr_free_list_put(free_list); +} + +void +pvr_free_list_process_reconstruct_req(struct pvr_device *pvr_dev, + struct rogue_fwif_fwccb_cmd_freelists_reconstruction_data *req) +{ + struct rogue_fwif_kccb_cmd resp_cmd = { + .cmd_type = ROGUE_FWIF_KCCB_CMD_FREELISTS_RECONSTRUCTION_UPDATE, + }; + struct rogue_fwif_freelists_reconstruction_data *resp = + &resp_cmd.cmd_data.free_lists_reconstruction_data; + + for (u32 i = 0; i < req->freelist_count; i++) + pvr_free_list_reconstruct(pvr_dev, req->freelist_ids[i]); + + resp->freelist_count = req->freelist_count; + memcpy(resp->freelist_ids, req->freelist_ids, + req->freelist_count * sizeof(resp->freelist_ids[0])); + + WARN_ON(pvr_kccb_send_cmd(pvr_dev, &resp_cmd, NULL)); +} diff --git a/drivers/gpu/drm/imagination/pvr_free_list.h b/drivers/gpu/drm/imagination/pvr_free_list.h new file mode 100644 index 00000000000000..bfb4f5fc622c9c --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_free_list.h @@ -0,0 +1,195 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_FREE_LIST_H +#define PVR_FREE_LIST_H + +#include +#include +#include +#include +#include +#include +#include + +#include "pvr_device.h" + +/* Forward declaration from pvr_gem.h. */ +struct pvr_fw_object; + +/* Forward declaration from pvr_gem.h. */ +struct pvr_gem_object; + +/* Forward declaration from pvr_hwrt.h. */ +struct pvr_hwrt_data; + +/** + * struct pvr_free_list_node - structure representing an allocation in the free + * list + */ +struct pvr_free_list_node { + /** @node: List node for &pvr_free_list.mem_block_list. */ + struct list_head node; + + /** @free_list: Pointer to owning free list. */ + struct pvr_free_list *free_list; + + /** @num_pages: Number of pages in this node. */ + u32 num_pages; + + /** @mem_obj: GEM object representing the pages in this node. */ + struct pvr_gem_object *mem_obj; +}; + +/** + * struct pvr_free_list - structure representing a free list + */ +struct pvr_free_list { + /** @ref_count: Reference count of object. */ + struct kref ref_count; + + /** @pvr_dev: Pointer to device that owns this object. */ + struct pvr_device *pvr_dev; + + /** @obj: GEM object representing the free list. */ + struct pvr_gem_object *obj; + + /** @fw_obj: FW object representing the FW-side structure. */ + struct pvr_fw_object *fw_obj; + + /** @fw_data: Pointer to CPU mapping of the FW-side structure. */ + struct rogue_fwif_freelist *fw_data; + + /** + * @lock: Mutex protecting modification of the free list. Must be held when accessing any + * of the members below. + */ + struct mutex lock; + + /** @fw_id: Firmware ID for this object. */ + u32 fw_id; + + /** @current_pages: Current number of pages in free list. */ + u32 current_pages; + + /** @max_pages: Maximum number of pages in free list. */ + u32 max_pages; + + /** @grow_pages: Pages to grow free list by per request. */ + u32 grow_pages; + + /** + * @grow_threshold: Percentage of FL memory used that should trigger a + * new grow request. + */ + u32 grow_threshold; + + /** + * @ready_pages: Number of pages reserved for FW to use while a grow + * request is being processed. + */ + u32 ready_pages; + + /** @mem_block_list: List of memory blocks in this free list. */ + struct list_head mem_block_list; + + /** @hwrt_list: List of HWRTs using this free list. */ + struct list_head hwrt_list; + + /** @initial_num_pages: Initial number of pages in free list. */ + u32 initial_num_pages; + + /** @free_list_gpu_addr: Address of free list in GPU address space. */ + u64 free_list_gpu_addr; +}; + +struct pvr_free_list * +pvr_free_list_create(struct pvr_file *pvr_file, + struct drm_pvr_ioctl_create_free_list_args *args); + +void +pvr_destroy_free_lists_for_file(struct pvr_file *pvr_file); + +u32 +pvr_get_free_list_min_pages(struct pvr_device *pvr_dev); + +static __always_inline struct pvr_free_list * +pvr_free_list_get(struct pvr_free_list *free_list) +{ + if (free_list) + kref_get(&free_list->ref_count); + + return free_list; +} + +/** + * pvr_free_list_lookup() - Lookup free list pointer from handle and file + * @pvr_file: Pointer to pvr_file structure. + * @handle: Object handle. + * + * Takes reference on free list object. Call pvr_free_list_put() to release. + * + * Returns: + * * The requested object on success, or + * * %NULL on failure (object does not exist in list, is not a free list, or + * does not belong to @pvr_file) + */ +static __always_inline struct pvr_free_list * +pvr_free_list_lookup(struct pvr_file *pvr_file, u32 handle) +{ + struct pvr_free_list *free_list; + + xa_lock(&pvr_file->free_list_handles); + free_list = pvr_free_list_get(xa_load(&pvr_file->free_list_handles, handle)); + xa_unlock(&pvr_file->free_list_handles); + + return free_list; +} + +/** + * pvr_free_list_lookup_id() - Lookup free list pointer from FW ID + * @pvr_dev: Device pointer. + * @id: FW object ID. + * + * Takes reference on free list object. Call pvr_free_list_put() to release. + * + * Returns: + * * The requested object on success, or + * * %NULL on failure (object does not exist in list, or is not a free list) + */ +static __always_inline struct pvr_free_list * +pvr_free_list_lookup_id(struct pvr_device *pvr_dev, u32 id) +{ + struct pvr_free_list *free_list; + + xa_lock(&pvr_dev->free_list_ids); + + /* Contexts are removed from the ctx_ids set in the context release path, + * meaning the ref_count reached zero before they get removed. We need + * to make sure we're not trying to acquire a context that's being + * destroyed. + */ + free_list = xa_load(&pvr_dev->free_list_ids, id); + if (free_list && !kref_get_unless_zero(&free_list->ref_count)) + free_list = NULL; + xa_unlock(&pvr_dev->free_list_ids); + + return free_list; +} + +void +pvr_free_list_put(struct pvr_free_list *free_list); + +void +pvr_free_list_add_hwrt(struct pvr_free_list *free_list, struct pvr_hwrt_data *hwrt_data); +void +pvr_free_list_remove_hwrt(struct pvr_free_list *free_list, struct pvr_hwrt_data *hwrt_data); + +void pvr_free_list_process_grow_req(struct pvr_device *pvr_dev, + struct rogue_fwif_fwccb_cmd_freelist_gs_data *req); + +void +pvr_free_list_process_reconstruct_req(struct pvr_device *pvr_dev, + struct rogue_fwif_fwccb_cmd_freelists_reconstruction_data *req); + +#endif /* PVR_FREE_LIST_H */ diff --git a/drivers/gpu/drm/imagination/pvr_fw.c b/drivers/gpu/drm/imagination/pvr_fw.c new file mode 100644 index 00000000000000..3debc9870a82ae --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_fw.c @@ -0,0 +1,1489 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_ccb.h" +#include "pvr_device.h" +#include "pvr_device_info.h" +#include "pvr_fw.h" +#include "pvr_fw_info.h" +#include "pvr_fw_startstop.h" +#include "pvr_fw_trace.h" +#include "pvr_gem.h" +#include "pvr_power.h" +#include "pvr_rogue_fwif_dev_info.h" +#include "pvr_rogue_heap_config.h" +#include "pvr_vm.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#define FW_MAX_SUPPORTED_MAJOR_VERSION 1 + +#define FW_BOOT_TIMEOUT_USEC 5000000 + +/* Config heap occupies top 192k of the firmware heap. */ +#define PVR_ROGUE_FW_CONFIG_HEAP_GRANULARITY SZ_64K +#define PVR_ROGUE_FW_CONFIG_HEAP_SIZE (3 * PVR_ROGUE_FW_CONFIG_HEAP_GRANULARITY) + +/* Main firmware allocations should come from the remainder of the heap. */ +#define PVR_ROGUE_FW_MAIN_HEAP_BASE ROGUE_FW_HEAP_BASE + +/* Offsets from start of configuration area of FW heap. */ +#define PVR_ROGUE_FWIF_CONNECTION_CTL_OFFSET 0 +#define PVR_ROGUE_FWIF_OSINIT_OFFSET \ + (PVR_ROGUE_FWIF_CONNECTION_CTL_OFFSET + PVR_ROGUE_FW_CONFIG_HEAP_GRANULARITY) +#define PVR_ROGUE_FWIF_SYSINIT_OFFSET \ + (PVR_ROGUE_FWIF_OSINIT_OFFSET + PVR_ROGUE_FW_CONFIG_HEAP_GRANULARITY) + +#define PVR_ROGUE_FAULT_PAGE_SIZE SZ_4K + +#define PVR_SYNC_OBJ_SIZE sizeof(u32) + +const struct pvr_fw_layout_entry * +pvr_fw_find_layout_entry(struct pvr_device *pvr_dev, enum pvr_fw_section_id id) +{ + const struct pvr_fw_layout_entry *layout_entries = pvr_dev->fw_dev.layout_entries; + u32 num_layout_entries = pvr_dev->fw_dev.header->layout_entry_num; + u32 entry; + + for (entry = 0; entry < num_layout_entries; entry++) { + if (layout_entries[entry].id == id) + return &layout_entries[entry]; + } + + return NULL; +} + +static const struct pvr_fw_layout_entry * +pvr_fw_find_private_data(struct pvr_device *pvr_dev) +{ + const struct pvr_fw_layout_entry *layout_entries = pvr_dev->fw_dev.layout_entries; + u32 num_layout_entries = pvr_dev->fw_dev.header->layout_entry_num; + u32 entry; + + for (entry = 0; entry < num_layout_entries; entry++) { + if (layout_entries[entry].id == META_PRIVATE_DATA || + layout_entries[entry].id == MIPS_PRIVATE_DATA || + layout_entries[entry].id == RISCV_PRIVATE_DATA) + return &layout_entries[entry]; + } + + return NULL; +} + +#define DEV_INFO_MASK_SIZE(x) DIV_ROUND_UP(x, 64) + +/** + * pvr_fw_validate() - Parse firmware header and check compatibility + * @pvr_dev: Device pointer. + * + * Returns: + * * 0 on success, or + * * -EINVAL if firmware is incompatible. + */ +static int +pvr_fw_validate(struct pvr_device *pvr_dev) +{ + struct drm_device *drm_dev = from_pvr_device(pvr_dev); + const struct firmware *firmware = pvr_dev->fw_dev.firmware; + const struct pvr_fw_layout_entry *layout_entries; + const struct pvr_fw_info_header *header; + const u8 *fw = firmware->data; + u32 fw_offset = firmware->size - SZ_4K; + u32 layout_table_size; + u32 entry; + + if (firmware->size < SZ_4K || (firmware->size % FW_BLOCK_SIZE)) + return -EINVAL; + + header = (const struct pvr_fw_info_header *)&fw[fw_offset]; + + if (header->info_version != PVR_FW_INFO_VERSION) { + drm_err(drm_dev, "Unsupported fw info version %u\n", + header->info_version); + return -EINVAL; + } + + if (header->header_len != sizeof(struct pvr_fw_info_header) || + header->layout_entry_size != sizeof(struct pvr_fw_layout_entry) || + header->layout_entry_num > PVR_FW_INFO_MAX_NUM_ENTRIES) { + drm_err(drm_dev, "FW info format mismatch\n"); + return -EINVAL; + } + + if (!(header->flags & PVR_FW_FLAGS_OPEN_SOURCE) || + header->fw_version_major > FW_MAX_SUPPORTED_MAJOR_VERSION || + header->fw_version_major == 0) { + drm_err(drm_dev, "Unsupported FW version %u.%u (build: %u%s)\n", + header->fw_version_major, header->fw_version_minor, + header->fw_version_build, + (header->flags & PVR_FW_FLAGS_OPEN_SOURCE) ? " OS" : ""); + return -EINVAL; + } + + if (pvr_gpu_id_to_packed_bvnc(&pvr_dev->gpu_id) != header->bvnc) { + struct pvr_gpu_id fw_gpu_id; + + packed_bvnc_to_pvr_gpu_id(header->bvnc, &fw_gpu_id); + drm_err(drm_dev, "FW built for incorrect GPU ID %i.%i.%i.%i (expected %i.%i.%i.%i)\n", + fw_gpu_id.b, fw_gpu_id.v, fw_gpu_id.n, fw_gpu_id.c, + pvr_dev->gpu_id.b, pvr_dev->gpu_id.v, pvr_dev->gpu_id.n, pvr_dev->gpu_id.c); + return -EINVAL; + } + + fw_offset += header->header_len; + layout_table_size = + header->layout_entry_size * header->layout_entry_num; + if ((fw_offset + layout_table_size) > firmware->size) + return -EINVAL; + + layout_entries = (const struct pvr_fw_layout_entry *)&fw[fw_offset]; + for (entry = 0; entry < header->layout_entry_num; entry++) { + u32 start_addr = layout_entries[entry].base_addr; + u32 end_addr = start_addr + layout_entries[entry].alloc_size; + + if (start_addr >= end_addr) + return -EINVAL; + } + + fw_offset = (firmware->size - SZ_4K) - header->device_info_size; + + drm_info(drm_dev, "FW version v%u.%u (build %u OS)\n", header->fw_version_major, + header->fw_version_minor, header->fw_version_build); + + pvr_dev->fw_version.major = header->fw_version_major; + pvr_dev->fw_version.minor = header->fw_version_minor; + + pvr_dev->fw_dev.header = header; + pvr_dev->fw_dev.layout_entries = layout_entries; + + return 0; +} + +static int +pvr_fw_get_device_info(struct pvr_device *pvr_dev) +{ + const struct firmware *firmware = pvr_dev->fw_dev.firmware; + struct pvr_fw_device_info_header *header; + const u8 *fw = firmware->data; + const u64 *dev_info; + u32 fw_offset; + + fw_offset = (firmware->size - SZ_4K) - pvr_dev->fw_dev.header->device_info_size; + + header = (struct pvr_fw_device_info_header *)&fw[fw_offset]; + dev_info = (u64 *)(header + 1); + + pvr_device_info_set_quirks(pvr_dev, dev_info, header->brn_mask_size); + dev_info += header->brn_mask_size; + + pvr_device_info_set_enhancements(pvr_dev, dev_info, header->ern_mask_size); + dev_info += header->ern_mask_size; + + return pvr_device_info_set_features(pvr_dev, dev_info, header->feature_mask_size, + header->feature_param_size); +} + +static void +layout_get_sizes(struct pvr_device *pvr_dev) +{ + const struct pvr_fw_layout_entry *layout_entries = pvr_dev->fw_dev.layout_entries; + u32 num_layout_entries = pvr_dev->fw_dev.header->layout_entry_num; + struct pvr_fw_mem *fw_mem = &pvr_dev->fw_dev.mem; + + fw_mem->code_alloc_size = 0; + fw_mem->data_alloc_size = 0; + fw_mem->core_code_alloc_size = 0; + fw_mem->core_data_alloc_size = 0; + + /* Extract section sizes from FW layout table. */ + for (u32 entry = 0; entry < num_layout_entries; entry++) { + switch (layout_entries[entry].type) { + case FW_CODE: + fw_mem->code_alloc_size += layout_entries[entry].alloc_size; + break; + case FW_DATA: + fw_mem->data_alloc_size += layout_entries[entry].alloc_size; + break; + case FW_COREMEM_CODE: + fw_mem->core_code_alloc_size += + layout_entries[entry].alloc_size; + break; + case FW_COREMEM_DATA: + fw_mem->core_data_alloc_size += + layout_entries[entry].alloc_size; + break; + case NONE: + break; + } + } +} + +int +pvr_fw_find_mmu_segment(struct pvr_device *pvr_dev, u32 addr, u32 size, void *fw_code_ptr, + void *fw_data_ptr, void *fw_core_code_ptr, void *fw_core_data_ptr, + void **host_addr_out) +{ + const struct pvr_fw_layout_entry *layout_entries = pvr_dev->fw_dev.layout_entries; + u32 num_layout_entries = pvr_dev->fw_dev.header->layout_entry_num; + u32 end_addr = addr + size; + int entry = 0; + + /* Ensure requested range is not zero, and size is not causing addr to overflow. */ + if (end_addr <= addr) + return -EINVAL; + + for (entry = 0; entry < num_layout_entries; entry++) { + u32 entry_start_addr = layout_entries[entry].base_addr; + u32 entry_end_addr = entry_start_addr + layout_entries[entry].alloc_size; + + if (addr >= entry_start_addr && addr < entry_end_addr && + end_addr > entry_start_addr && end_addr <= entry_end_addr) { + switch (layout_entries[entry].type) { + case FW_CODE: + *host_addr_out = fw_code_ptr; + break; + + case FW_DATA: + *host_addr_out = fw_data_ptr; + break; + + case FW_COREMEM_CODE: + *host_addr_out = fw_core_code_ptr; + break; + + case FW_COREMEM_DATA: + *host_addr_out = fw_core_data_ptr; + break; + + default: + return -EINVAL; + } + /* Direct Mem write to mapped memory */ + addr -= layout_entries[entry].base_addr; + addr += layout_entries[entry].alloc_offset; + + /* + * Add offset to pointer to FW allocation only if that + * allocation is available + */ + *(u8 **)host_addr_out += addr; + return 0; + } + } + + return -EINVAL; +} + +static int +pvr_fw_create_fwif_connection_ctl(struct pvr_device *pvr_dev) +{ + struct drm_device *drm_dev = from_pvr_device(pvr_dev); + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + + fw_dev->fwif_connection_ctl = + pvr_fw_object_create_and_map_offset(pvr_dev, + fw_dev->fw_heap_info.config_offset + + PVR_ROGUE_FWIF_CONNECTION_CTL_OFFSET, + sizeof(*fw_dev->fwif_connection_ctl), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + NULL, NULL, + &fw_dev->mem.fwif_connection_ctl_obj); + if (IS_ERR(fw_dev->fwif_connection_ctl)) { + drm_err(drm_dev, + "Unable to allocate FWIF connection control memory\n"); + return PTR_ERR(fw_dev->fwif_connection_ctl); + } + + return 0; +} + +static void +pvr_fw_fini_fwif_connection_ctl(struct pvr_device *pvr_dev) +{ + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + + pvr_fw_object_unmap_and_destroy(fw_dev->mem.fwif_connection_ctl_obj); +} + +static void +fw_osinit_init(void *cpu_ptr, void *priv) +{ + struct rogue_fwif_osinit *fwif_osinit = cpu_ptr; + struct pvr_device *pvr_dev = priv; + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + struct pvr_fw_mem *fw_mem = &fw_dev->mem; + + fwif_osinit->kernel_ccbctl_fw_addr = pvr_dev->kccb.ccb.ctrl_fw_addr; + fwif_osinit->kernel_ccb_fw_addr = pvr_dev->kccb.ccb.ccb_fw_addr; + pvr_fw_object_get_fw_addr(pvr_dev->kccb.rtn_obj, + &fwif_osinit->kernel_ccb_rtn_slots_fw_addr); + + fwif_osinit->firmware_ccbctl_fw_addr = pvr_dev->fwccb.ctrl_fw_addr; + fwif_osinit->firmware_ccb_fw_addr = pvr_dev->fwccb.ccb_fw_addr; + + fwif_osinit->work_est_firmware_ccbctl_fw_addr = 0; + fwif_osinit->work_est_firmware_ccb_fw_addr = 0; + + pvr_fw_object_get_fw_addr(fw_mem->hwrinfobuf_obj, + &fwif_osinit->rogue_fwif_hwr_info_buf_ctl_fw_addr); + pvr_fw_object_get_fw_addr(fw_mem->osdata_obj, &fwif_osinit->fw_os_data_fw_addr); + + fwif_osinit->hwr_debug_dump_limit = 0; + + rogue_fwif_compchecks_bvnc_init(&fwif_osinit->rogue_comp_checks.hw_bvnc); + rogue_fwif_compchecks_bvnc_init(&fwif_osinit->rogue_comp_checks.fw_bvnc); +} + +static void +fw_osdata_init(void *cpu_ptr, void *priv) +{ + struct rogue_fwif_osdata *fwif_osdata = cpu_ptr; + struct pvr_device *pvr_dev = priv; + struct pvr_fw_mem *fw_mem = &pvr_dev->fw_dev.mem; + + pvr_fw_object_get_fw_addr(fw_mem->power_sync_obj, &fwif_osdata->power_sync_fw_addr); +} + +static void +fw_fault_page_init(void *cpu_ptr, void *priv) +{ + u32 *fault_page = cpu_ptr; + + for (int i = 0; i < PVR_ROGUE_FAULT_PAGE_SIZE / sizeof(*fault_page); i++) + fault_page[i] = 0xdeadbee0; +} + +static void +fw_sysinit_init(void *cpu_ptr, void *priv) +{ + struct rogue_fwif_sysinit *fwif_sysinit = cpu_ptr; + struct pvr_device *pvr_dev = priv; + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + struct pvr_fw_mem *fw_mem = &fw_dev->mem; + dma_addr_t fault_dma_addr = 0; + u32 clock_speed_hz = clk_get_rate(pvr_dev->core_clk); + + WARN_ON(!clock_speed_hz); + + WARN_ON(pvr_fw_object_get_dma_addr(fw_mem->fault_page_obj, 0, &fault_dma_addr)); + fwif_sysinit->fault_phys_addr = (u64)fault_dma_addr; + + fwif_sysinit->pds_exec_base = ROGUE_PDSCODEDATA_HEAP_BASE; + fwif_sysinit->usc_exec_base = ROGUE_USCCODE_HEAP_BASE; + + pvr_fw_object_get_fw_addr(fw_mem->runtime_cfg_obj, &fwif_sysinit->runtime_cfg_fw_addr); + pvr_fw_object_get_fw_addr(fw_dev->fw_trace.tracebuf_ctrl_obj, + &fwif_sysinit->trace_buf_ctl_fw_addr); + pvr_fw_object_get_fw_addr(fw_mem->sysdata_obj, &fwif_sysinit->fw_sys_data_fw_addr); + pvr_fw_object_get_fw_addr(fw_mem->gpu_util_fwcb_obj, + &fwif_sysinit->gpu_util_fw_cb_ctl_fw_addr); + if (fw_mem->core_data_obj) { + pvr_fw_object_get_fw_addr(fw_mem->core_data_obj, + &fwif_sysinit->coremem_data_store.fw_addr); + } + + /* Currently unsupported. */ + fwif_sysinit->counter_dump_ctl.buffer_fw_addr = 0; + fwif_sysinit->counter_dump_ctl.size_in_dwords = 0; + + /* Skip alignment checks. */ + fwif_sysinit->align_checks = 0; + + fwif_sysinit->filter_flags = 0; + fwif_sysinit->hw_perf_filter = 0; + fwif_sysinit->firmware_perf = FW_PERF_CONF_NONE; + fwif_sysinit->initial_core_clock_speed = clock_speed_hz; + fwif_sysinit->active_pm_latency_ms = 0; + fwif_sysinit->gpio_validation_mode = ROGUE_FWIF_GPIO_VAL_OFF; + fwif_sysinit->firmware_started = false; + fwif_sysinit->marker_val = 1; + + memset(&fwif_sysinit->bvnc_km_feature_flags, 0, + sizeof(fwif_sysinit->bvnc_km_feature_flags)); +} + +#define ROGUE_FWIF_SLC_MIN_SIZE_FOR_DM_OVERLAP_KB 4 + +static void +fw_sysdata_init(void *cpu_ptr, void *priv) +{ + struct rogue_fwif_sysdata *fwif_sysdata = cpu_ptr; + struct pvr_device *pvr_dev = priv; + u32 slc_size_in_kilobytes = 0; + u32 config_flags = 0; + + WARN_ON(PVR_FEATURE_VALUE(pvr_dev, slc_size_in_kilobytes, &slc_size_in_kilobytes)); + + if (slc_size_in_kilobytes < ROGUE_FWIF_SLC_MIN_SIZE_FOR_DM_OVERLAP_KB) + config_flags |= ROGUE_FWIF_INICFG_DISABLE_DM_OVERLAP; + + fwif_sysdata->config_flags = config_flags; +} + +static void +fw_runtime_cfg_init(void *cpu_ptr, void *priv) +{ + struct rogue_fwif_runtime_cfg *runtime_cfg = cpu_ptr; + struct pvr_device *pvr_dev = priv; + u32 clock_speed_hz = clk_get_rate(pvr_dev->core_clk); + + WARN_ON(!clock_speed_hz); + + runtime_cfg->core_clock_speed = clock_speed_hz; + runtime_cfg->active_pm_latency_ms = 0; + runtime_cfg->active_pm_latency_persistant = true; + WARN_ON(PVR_FEATURE_VALUE(pvr_dev, num_clusters, + &runtime_cfg->default_dusts_num_init) != 0); +} + +static void +fw_gpu_util_fwcb_init(void *cpu_ptr, void *priv) +{ + struct rogue_fwif_gpu_util_fwcb *gpu_util_fwcb = cpu_ptr; + + gpu_util_fwcb->last_word = PVR_FWIF_GPU_UTIL_STATE_IDLE; +} + +static int +pvr_fw_create_structures(struct pvr_device *pvr_dev) +{ + struct drm_device *drm_dev = from_pvr_device(pvr_dev); + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + struct pvr_fw_mem *fw_mem = &fw_dev->mem; + int err; + + fw_dev->power_sync = pvr_fw_object_create_and_map(pvr_dev, sizeof(*fw_dev->power_sync), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + NULL, NULL, &fw_mem->power_sync_obj); + if (IS_ERR(fw_dev->power_sync)) { + drm_err(drm_dev, "Unable to allocate FW power_sync structure\n"); + return PTR_ERR(fw_dev->power_sync); + } + + fw_dev->hwrinfobuf = pvr_fw_object_create_and_map(pvr_dev, sizeof(*fw_dev->hwrinfobuf), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + NULL, NULL, &fw_mem->hwrinfobuf_obj); + if (IS_ERR(fw_dev->hwrinfobuf)) { + drm_err(drm_dev, + "Unable to allocate FW hwrinfobuf structure\n"); + err = PTR_ERR(fw_dev->hwrinfobuf); + goto err_release_power_sync; + } + + err = pvr_fw_object_create(pvr_dev, PVR_SYNC_OBJ_SIZE, + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + NULL, NULL, &fw_mem->mmucache_sync_obj); + if (err) { + drm_err(drm_dev, + "Unable to allocate MMU cache sync object\n"); + goto err_release_hwrinfobuf; + } + + fw_dev->fwif_sysdata = pvr_fw_object_create_and_map(pvr_dev, + sizeof(*fw_dev->fwif_sysdata), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + fw_sysdata_init, pvr_dev, + &fw_mem->sysdata_obj); + if (IS_ERR(fw_dev->fwif_sysdata)) { + drm_err(drm_dev, "Unable to allocate FW SYSDATA structure\n"); + err = PTR_ERR(fw_dev->fwif_sysdata); + goto err_release_mmucache_sync_obj; + } + + err = pvr_fw_object_create(pvr_dev, PVR_ROGUE_FAULT_PAGE_SIZE, + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + fw_fault_page_init, NULL, &fw_mem->fault_page_obj); + if (err) { + drm_err(drm_dev, "Unable to allocate FW fault page\n"); + goto err_release_sysdata; + } + + err = pvr_fw_object_create(pvr_dev, sizeof(struct rogue_fwif_gpu_util_fwcb), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + fw_gpu_util_fwcb_init, pvr_dev, &fw_mem->gpu_util_fwcb_obj); + if (err) { + drm_err(drm_dev, "Unable to allocate GPU util FWCB\n"); + goto err_release_fault_page; + } + + err = pvr_fw_object_create(pvr_dev, sizeof(struct rogue_fwif_runtime_cfg), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + fw_runtime_cfg_init, pvr_dev, &fw_mem->runtime_cfg_obj); + if (err) { + drm_err(drm_dev, "Unable to allocate FW runtime config\n"); + goto err_release_gpu_util_fwcb; + } + + err = pvr_fw_trace_init(pvr_dev); + if (err) + goto err_release_runtime_cfg; + + fw_dev->fwif_osdata = pvr_fw_object_create_and_map(pvr_dev, + sizeof(*fw_dev->fwif_osdata), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + fw_osdata_init, pvr_dev, + &fw_mem->osdata_obj); + if (IS_ERR(fw_dev->fwif_osdata)) { + drm_err(drm_dev, "Unable to allocate FW OSDATA structure\n"); + err = PTR_ERR(fw_dev->fwif_osdata); + goto err_fw_trace_fini; + } + + fw_dev->fwif_osinit = + pvr_fw_object_create_and_map_offset(pvr_dev, + fw_dev->fw_heap_info.config_offset + + PVR_ROGUE_FWIF_OSINIT_OFFSET, + sizeof(*fw_dev->fwif_osinit), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + fw_osinit_init, pvr_dev, &fw_mem->osinit_obj); + if (IS_ERR(fw_dev->fwif_osinit)) { + drm_err(drm_dev, "Unable to allocate FW OSINIT structure\n"); + err = PTR_ERR(fw_dev->fwif_osinit); + goto err_release_osdata; + } + + fw_dev->fwif_sysinit = + pvr_fw_object_create_and_map_offset(pvr_dev, + fw_dev->fw_heap_info.config_offset + + PVR_ROGUE_FWIF_SYSINIT_OFFSET, + sizeof(*fw_dev->fwif_sysinit), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + fw_sysinit_init, pvr_dev, &fw_mem->sysinit_obj); + if (IS_ERR(fw_dev->fwif_sysinit)) { + drm_err(drm_dev, "Unable to allocate FW SYSINIT structure\n"); + err = PTR_ERR(fw_dev->fwif_sysinit); + goto err_release_osinit; + } + + return 0; + +err_release_osinit: + pvr_fw_object_unmap_and_destroy(fw_mem->osinit_obj); + +err_release_osdata: + pvr_fw_object_unmap_and_destroy(fw_mem->osdata_obj); + +err_fw_trace_fini: + pvr_fw_trace_fini(pvr_dev); + +err_release_runtime_cfg: + pvr_fw_object_destroy(fw_mem->runtime_cfg_obj); + +err_release_gpu_util_fwcb: + pvr_fw_object_destroy(fw_mem->gpu_util_fwcb_obj); + +err_release_fault_page: + pvr_fw_object_destroy(fw_mem->fault_page_obj); + +err_release_sysdata: + pvr_fw_object_unmap_and_destroy(fw_mem->sysdata_obj); + +err_release_mmucache_sync_obj: + pvr_fw_object_destroy(fw_mem->mmucache_sync_obj); + +err_release_hwrinfobuf: + pvr_fw_object_unmap_and_destroy(fw_mem->hwrinfobuf_obj); + +err_release_power_sync: + pvr_fw_object_unmap_and_destroy(fw_mem->power_sync_obj); + + return err; +} + +static void +pvr_fw_destroy_structures(struct pvr_device *pvr_dev) +{ + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + struct pvr_fw_mem *fw_mem = &fw_dev->mem; + + pvr_fw_trace_fini(pvr_dev); + pvr_fw_object_destroy(fw_mem->runtime_cfg_obj); + pvr_fw_object_destroy(fw_mem->gpu_util_fwcb_obj); + pvr_fw_object_destroy(fw_mem->fault_page_obj); + pvr_fw_object_unmap_and_destroy(fw_mem->sysdata_obj); + pvr_fw_object_unmap_and_destroy(fw_mem->sysinit_obj); + + pvr_fw_object_destroy(fw_mem->mmucache_sync_obj); + pvr_fw_object_unmap_and_destroy(fw_mem->hwrinfobuf_obj); + pvr_fw_object_unmap_and_destroy(fw_mem->power_sync_obj); + pvr_fw_object_unmap_and_destroy(fw_mem->osdata_obj); + pvr_fw_object_unmap_and_destroy(fw_mem->osinit_obj); +} + +/** + * pvr_fw_process() - Process firmware image, allocate FW memory and create boot + * arguments + * @pvr_dev: Device pointer. + * + * Returns: + * * 0 on success, or + * * Any error returned by pvr_fw_object_create_and_map_offset(), or + * * Any error returned by pvr_fw_object_create_and_map(). + */ +static int +pvr_fw_process(struct pvr_device *pvr_dev) +{ + struct drm_device *drm_dev = from_pvr_device(pvr_dev); + struct pvr_fw_mem *fw_mem = &pvr_dev->fw_dev.mem; + const u8 *fw = pvr_dev->fw_dev.firmware->data; + const struct pvr_fw_layout_entry *private_data; + u8 *fw_code_ptr; + u8 *fw_data_ptr; + u8 *fw_core_code_ptr; + u8 *fw_core_data_ptr; + int err; + + layout_get_sizes(pvr_dev); + + private_data = pvr_fw_find_private_data(pvr_dev); + if (!private_data) + return -EINVAL; + + /* Allocate and map memory for firmware sections. */ + + /* + * Code allocation must be at the start of the firmware heap, otherwise + * firmware processor will be unable to boot. + * + * This has the useful side-effect that for every other object in the + * driver, a firmware address of 0 is invalid. + */ + fw_code_ptr = pvr_fw_object_create_and_map_offset(pvr_dev, 0, fw_mem->code_alloc_size, + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + NULL, NULL, &fw_mem->code_obj); + if (IS_ERR(fw_code_ptr)) { + drm_err(drm_dev, "Unable to allocate FW code memory\n"); + return PTR_ERR(fw_code_ptr); + } + + if (pvr_dev->fw_dev.defs->has_fixed_data_addr()) { + u32 base_addr = private_data->base_addr & pvr_dev->fw_dev.fw_heap_info.offset_mask; + + fw_data_ptr = + pvr_fw_object_create_and_map_offset(pvr_dev, base_addr, + fw_mem->data_alloc_size, + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + NULL, NULL, &fw_mem->data_obj); + } else { + fw_data_ptr = pvr_fw_object_create_and_map(pvr_dev, fw_mem->data_alloc_size, + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + NULL, NULL, &fw_mem->data_obj); + } + if (IS_ERR(fw_data_ptr)) { + drm_err(drm_dev, "Unable to allocate FW data memory\n"); + err = PTR_ERR(fw_data_ptr); + goto err_free_fw_code_obj; + } + + /* Core code and data sections are optional. */ + if (fw_mem->core_code_alloc_size) { + fw_core_code_ptr = + pvr_fw_object_create_and_map(pvr_dev, fw_mem->core_code_alloc_size, + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + NULL, NULL, &fw_mem->core_code_obj); + if (IS_ERR(fw_core_code_ptr)) { + drm_err(drm_dev, + "Unable to allocate FW core code memory\n"); + err = PTR_ERR(fw_core_code_ptr); + goto err_free_fw_data_obj; + } + } else { + fw_core_code_ptr = NULL; + } + + if (fw_mem->core_data_alloc_size) { + fw_core_data_ptr = + pvr_fw_object_create_and_map(pvr_dev, fw_mem->core_data_alloc_size, + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + NULL, NULL, &fw_mem->core_data_obj); + if (IS_ERR(fw_core_data_ptr)) { + drm_err(drm_dev, + "Unable to allocate FW core data memory\n"); + err = PTR_ERR(fw_core_data_ptr); + goto err_free_fw_core_code_obj; + } + } else { + fw_core_data_ptr = NULL; + } + + fw_mem->code = kzalloc(fw_mem->code_alloc_size, GFP_KERNEL); + fw_mem->data = kzalloc(fw_mem->data_alloc_size, GFP_KERNEL); + if (fw_mem->core_code_alloc_size) + fw_mem->core_code = kzalloc(fw_mem->core_code_alloc_size, GFP_KERNEL); + if (fw_mem->core_data_alloc_size) + fw_mem->core_data = kzalloc(fw_mem->core_data_alloc_size, GFP_KERNEL); + + if (!fw_mem->code || !fw_mem->data || + (!fw_mem->core_code && fw_mem->core_code_alloc_size) || + (!fw_mem->core_data && fw_mem->core_data_alloc_size)) { + err = -ENOMEM; + goto err_free_kdata; + } + + err = pvr_dev->fw_dev.defs->fw_process(pvr_dev, fw, + fw_mem->code, fw_mem->data, fw_mem->core_code, + fw_mem->core_data, fw_mem->core_code_alloc_size); + + if (err) + goto err_free_fw_core_data_obj; + + memcpy(fw_code_ptr, fw_mem->code, fw_mem->code_alloc_size); + memcpy(fw_data_ptr, fw_mem->data, fw_mem->data_alloc_size); + if (fw_mem->core_code) + memcpy(fw_core_code_ptr, fw_mem->core_code, fw_mem->core_code_alloc_size); + if (fw_mem->core_data) + memcpy(fw_core_data_ptr, fw_mem->core_data, fw_mem->core_data_alloc_size); + + /* We're finished with the firmware section memory on the CPU, unmap. */ + if (fw_core_data_ptr) + pvr_fw_object_vunmap(fw_mem->core_data_obj); + if (fw_core_code_ptr) + pvr_fw_object_vunmap(fw_mem->core_code_obj); + pvr_fw_object_vunmap(fw_mem->data_obj); + fw_data_ptr = NULL; + pvr_fw_object_vunmap(fw_mem->code_obj); + fw_code_ptr = NULL; + + err = pvr_fw_create_fwif_connection_ctl(pvr_dev); + if (err) + goto err_free_fw_core_data_obj; + + return 0; + +err_free_kdata: + kfree(fw_mem->core_data); + kfree(fw_mem->core_code); + kfree(fw_mem->data); + kfree(fw_mem->code); + +err_free_fw_core_data_obj: + if (fw_core_data_ptr) + pvr_fw_object_unmap_and_destroy(fw_mem->core_data_obj); + +err_free_fw_core_code_obj: + if (fw_core_code_ptr) + pvr_fw_object_unmap_and_destroy(fw_mem->core_code_obj); + +err_free_fw_data_obj: + if (fw_data_ptr) + pvr_fw_object_vunmap(fw_mem->data_obj); + pvr_fw_object_destroy(fw_mem->data_obj); + +err_free_fw_code_obj: + if (fw_code_ptr) + pvr_fw_object_vunmap(fw_mem->code_obj); + pvr_fw_object_destroy(fw_mem->code_obj); + + return err; +} + +static int +pvr_copy_to_fw(struct pvr_fw_object *dest_obj, u8 *src_ptr, u32 size) +{ + u8 *dest_ptr = pvr_fw_object_vmap(dest_obj); + + if (IS_ERR(dest_ptr)) + return PTR_ERR(dest_ptr); + + memcpy(dest_ptr, src_ptr, size); + + pvr_fw_object_vunmap(dest_obj); + + return 0; +} + +static int +pvr_fw_reinit_code_data(struct pvr_device *pvr_dev) +{ + struct pvr_fw_mem *fw_mem = &pvr_dev->fw_dev.mem; + int err; + + err = pvr_copy_to_fw(fw_mem->code_obj, fw_mem->code, fw_mem->code_alloc_size); + if (err) + return err; + + err = pvr_copy_to_fw(fw_mem->data_obj, fw_mem->data, fw_mem->data_alloc_size); + if (err) + return err; + + if (fw_mem->core_code) { + err = pvr_copy_to_fw(fw_mem->core_code_obj, fw_mem->core_code, + fw_mem->core_code_alloc_size); + if (err) + return err; + } + + if (fw_mem->core_data) { + err = pvr_copy_to_fw(fw_mem->core_data_obj, fw_mem->core_data, + fw_mem->core_data_alloc_size); + if (err) + return err; + } + + return 0; +} + +static void +pvr_fw_cleanup(struct pvr_device *pvr_dev) +{ + struct pvr_fw_mem *fw_mem = &pvr_dev->fw_dev.mem; + + pvr_fw_fini_fwif_connection_ctl(pvr_dev); + if (fw_mem->core_code_obj) + pvr_fw_object_destroy(fw_mem->core_code_obj); + if (fw_mem->core_data_obj) + pvr_fw_object_destroy(fw_mem->core_data_obj); + pvr_fw_object_destroy(fw_mem->code_obj); + pvr_fw_object_destroy(fw_mem->data_obj); +} + +/** + * pvr_wait_for_fw_boot() - Wait for firmware to finish booting + * @pvr_dev: Target PowerVR device. + * + * Returns: + * * 0 on success, or + * * -%ETIMEDOUT if firmware fails to boot within timeout. + */ +int +pvr_wait_for_fw_boot(struct pvr_device *pvr_dev) +{ + ktime_t deadline = ktime_add_us(ktime_get(), FW_BOOT_TIMEOUT_USEC); + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + + while (ktime_to_ns(ktime_sub(deadline, ktime_get())) > 0) { + if (READ_ONCE(fw_dev->fwif_sysinit->firmware_started)) + return 0; + } + + return -ETIMEDOUT; +} + +/* + * pvr_fw_heap_info_init() - Calculate size and masks for FW heap + * @pvr_dev: Target PowerVR device. + * @log2_size: Log2 of raw heap size. + * @reserved_size: Size of reserved area of heap, in bytes. May be zero. + */ +void +pvr_fw_heap_info_init(struct pvr_device *pvr_dev, u32 log2_size, u32 reserved_size) +{ + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + + fw_dev->fw_heap_info.gpu_addr = PVR_ROGUE_FW_MAIN_HEAP_BASE; + fw_dev->fw_heap_info.log2_size = log2_size; + fw_dev->fw_heap_info.reserved_size = reserved_size; + fw_dev->fw_heap_info.raw_size = 1 << fw_dev->fw_heap_info.log2_size; + fw_dev->fw_heap_info.offset_mask = fw_dev->fw_heap_info.raw_size - 1; + fw_dev->fw_heap_info.config_offset = fw_dev->fw_heap_info.raw_size - + PVR_ROGUE_FW_CONFIG_HEAP_SIZE; + fw_dev->fw_heap_info.size = fw_dev->fw_heap_info.raw_size - + (PVR_ROGUE_FW_CONFIG_HEAP_SIZE + reserved_size); +} + +/** + * pvr_fw_validate_init_device_info() - Validate firmware and initialise device information + * @pvr_dev: Target PowerVR device. + * + * This function must be called before querying device information. + * + * Returns: + * * 0 on success, or + * * -%EINVAL if firmware validation fails. + */ +int +pvr_fw_validate_init_device_info(struct pvr_device *pvr_dev) +{ + int err; + + err = pvr_fw_validate(pvr_dev); + if (err) + return err; + + return pvr_fw_get_device_info(pvr_dev); +} + +/** + * pvr_fw_init() - Initialise and boot firmware + * @pvr_dev: Target PowerVR device + * + * On successful completion of the function the PowerVR device will be + * initialised and ready to use. + * + * Returns: + * * 0 on success, + * * -%EINVAL on invalid firmware image, + * * -%ENOMEM on out of memory, or + * * -%ETIMEDOUT if firmware processor fails to boot or on register poll timeout. + */ +int +pvr_fw_init(struct pvr_device *pvr_dev) +{ + u32 kccb_size_log2 = ROGUE_FWIF_KCCB_NUMCMDS_LOG2_DEFAULT; + u32 kccb_rtn_size = (1 << kccb_size_log2) * sizeof(*pvr_dev->kccb.rtn); + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + int err; + + if (fw_dev->processor_type == PVR_FW_PROCESSOR_TYPE_META) + fw_dev->defs = &pvr_fw_defs_meta; + else if (fw_dev->processor_type == PVR_FW_PROCESSOR_TYPE_MIPS) + fw_dev->defs = &pvr_fw_defs_mips; + else + return -EINVAL; + + err = fw_dev->defs->init(pvr_dev); + if (err) + return err; + + drm_mm_init(&fw_dev->fw_mm, ROGUE_FW_HEAP_BASE, fw_dev->fw_heap_info.raw_size); + fw_dev->fw_mm_base = ROGUE_FW_HEAP_BASE; + spin_lock_init(&fw_dev->fw_mm_lock); + + INIT_LIST_HEAD(&fw_dev->fw_objs.list); + err = drmm_mutex_init(from_pvr_device(pvr_dev), &fw_dev->fw_objs.lock); + if (err) + goto err_mm_takedown; + + err = pvr_fw_process(pvr_dev); + if (err) + goto err_mm_takedown; + + /* Initialise KCCB and FWCCB. */ + err = pvr_kccb_init(pvr_dev); + if (err) + goto err_fw_cleanup; + + err = pvr_fwccb_init(pvr_dev); + if (err) + goto err_kccb_fini; + + /* Allocate memory for KCCB return slots. */ + pvr_dev->kccb.rtn = pvr_fw_object_create_and_map(pvr_dev, kccb_rtn_size, + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + NULL, NULL, &pvr_dev->kccb.rtn_obj); + if (IS_ERR(pvr_dev->kccb.rtn)) { + err = PTR_ERR(pvr_dev->kccb.rtn); + goto err_fwccb_fini; + } + + err = pvr_fw_create_structures(pvr_dev); + if (err) + goto err_kccb_rtn_release; + + err = pvr_fw_start(pvr_dev); + if (err) + goto err_destroy_structures; + + err = pvr_wait_for_fw_boot(pvr_dev); + if (err) { + drm_err(from_pvr_device(pvr_dev), "Firmware failed to boot\n"); + goto err_fw_stop; + } + + fw_dev->booted = true; + + return 0; + +err_fw_stop: + pvr_fw_stop(pvr_dev); + +err_destroy_structures: + pvr_fw_destroy_structures(pvr_dev); + +err_kccb_rtn_release: + pvr_fw_object_unmap_and_destroy(pvr_dev->kccb.rtn_obj); + +err_fwccb_fini: + pvr_ccb_fini(&pvr_dev->fwccb); + +err_kccb_fini: + pvr_kccb_fini(pvr_dev); + +err_fw_cleanup: + pvr_fw_cleanup(pvr_dev); + +err_mm_takedown: + drm_mm_takedown(&fw_dev->fw_mm); + + if (fw_dev->defs->fini) + fw_dev->defs->fini(pvr_dev); + + return err; +} + +/** + * pvr_fw_fini() - Shutdown firmware processor and free associated memory + * @pvr_dev: Target PowerVR device + */ +void +pvr_fw_fini(struct pvr_device *pvr_dev) +{ + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + + fw_dev->booted = false; + + pvr_fw_destroy_structures(pvr_dev); + pvr_fw_object_unmap_and_destroy(pvr_dev->kccb.rtn_obj); + + /* + * Ensure FWCCB worker has finished executing before destroying FWCCB. The IRQ handler has + * been unregistered at this point so no new work should be being submitted. + */ + pvr_ccb_fini(&pvr_dev->fwccb); + pvr_kccb_fini(pvr_dev); + pvr_fw_cleanup(pvr_dev); + + mutex_lock(&pvr_dev->fw_dev.fw_objs.lock); + WARN_ON(!list_empty(&pvr_dev->fw_dev.fw_objs.list)); + mutex_unlock(&pvr_dev->fw_dev.fw_objs.lock); + + drm_mm_takedown(&fw_dev->fw_mm); + + if (fw_dev->defs->fini) + fw_dev->defs->fini(pvr_dev); +} + +/** + * pvr_fw_mts_schedule() - Schedule work via an MTS kick + * @pvr_dev: Target PowerVR device + * @val: Kick mask. Should be a combination of %ROGUE_CR_MTS_SCHEDULE_* + */ +void +pvr_fw_mts_schedule(struct pvr_device *pvr_dev, u32 val) +{ + /* Ensure memory is flushed before kicking MTS. */ + wmb(); + + pvr_cr_write32(pvr_dev, ROGUE_CR_MTS_SCHEDULE, val); + + /* Ensure the MTS kick goes through before continuing. */ + mb(); +} + +/** + * pvr_fw_structure_cleanup() - Send FW cleanup request for an object + * @pvr_dev: Target PowerVR device. + * @type: Type of object to cleanup. Must be one of &enum rogue_fwif_cleanup_type. + * @fw_obj: Pointer to FW object containing object to cleanup. + * @offset: Offset within FW object of object to cleanup. + * + * Returns: + * * 0 on success, + * * -EBUSY if object is busy, + * * -ETIMEDOUT on timeout, or + * * -EIO if device is lost. + */ +int +pvr_fw_structure_cleanup(struct pvr_device *pvr_dev, u32 type, struct pvr_fw_object *fw_obj, + u32 offset) +{ + struct rogue_fwif_kccb_cmd cmd; + int slot_nr; + int idx; + int err; + u32 rtn; + + struct rogue_fwif_cleanup_request *cleanup_req = &cmd.cmd_data.cleanup_data; + + down_read(&pvr_dev->reset_sem); + + if (!drm_dev_enter(from_pvr_device(pvr_dev), &idx)) { + err = -EIO; + goto err_up_read; + } + + cmd.cmd_type = ROGUE_FWIF_KCCB_CMD_CLEANUP; + cmd.kccb_flags = 0; + cleanup_req->cleanup_type = type; + + switch (type) { + case ROGUE_FWIF_CLEANUP_FWCOMMONCONTEXT: + pvr_fw_object_get_fw_addr_offset(fw_obj, offset, + &cleanup_req->cleanup_data.context_fw_addr); + break; + case ROGUE_FWIF_CLEANUP_HWRTDATA: + pvr_fw_object_get_fw_addr_offset(fw_obj, offset, + &cleanup_req->cleanup_data.hwrt_data_fw_addr); + break; + case ROGUE_FWIF_CLEANUP_FREELIST: + pvr_fw_object_get_fw_addr_offset(fw_obj, offset, + &cleanup_req->cleanup_data.freelist_fw_addr); + break; + default: + err = -EINVAL; + goto err_drm_dev_exit; + } + + err = pvr_kccb_send_cmd(pvr_dev, &cmd, &slot_nr); + if (err) + goto err_drm_dev_exit; + + err = pvr_kccb_wait_for_completion(pvr_dev, slot_nr, HZ, &rtn); + if (err) + goto err_drm_dev_exit; + + if (rtn & ROGUE_FWIF_KCCB_RTN_SLOT_CLEANUP_BUSY) + err = -EBUSY; + +err_drm_dev_exit: + drm_dev_exit(idx); + +err_up_read: + up_read(&pvr_dev->reset_sem); + + return err; +} + +/** + * pvr_fw_object_fw_map() - Map a FW object in firmware address space + * @pvr_dev: Device pointer. + * @fw_obj: FW object to map. + * @dev_addr: Desired address in device space, if a specific address is + * required. 0 otherwise. + * + * Returns: + * * 0 on success, or + * * -%EINVAL if @fw_obj is already mapped but has no references, or + * * Any error returned by DRM. + */ +static int +pvr_fw_object_fw_map(struct pvr_device *pvr_dev, struct pvr_fw_object *fw_obj, u64 dev_addr) +{ + struct pvr_gem_object *pvr_obj = fw_obj->gem; + struct drm_gem_object *gem_obj = gem_from_pvr_gem(pvr_obj); + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + + int err; + + spin_lock(&fw_dev->fw_mm_lock); + + if (drm_mm_node_allocated(&fw_obj->fw_mm_node)) { + err = -EINVAL; + goto err_unlock; + } + + if (!dev_addr) { + /* + * Allocate from the main heap only (firmware heap minus + * config space). + */ + err = drm_mm_insert_node_in_range(&fw_dev->fw_mm, &fw_obj->fw_mm_node, + gem_obj->size, 0, 0, + fw_dev->fw_heap_info.gpu_addr, + fw_dev->fw_heap_info.gpu_addr + + fw_dev->fw_heap_info.size, 0); + if (err) + goto err_unlock; + } else { + fw_obj->fw_mm_node.start = dev_addr; + fw_obj->fw_mm_node.size = gem_obj->size; + err = drm_mm_reserve_node(&fw_dev->fw_mm, &fw_obj->fw_mm_node); + if (err) + goto err_unlock; + } + + spin_unlock(&fw_dev->fw_mm_lock); + + /* Map object on GPU. */ + err = fw_dev->defs->vm_map(pvr_dev, fw_obj); + if (err) + goto err_remove_node; + + fw_obj->fw_addr_offset = (u32)(fw_obj->fw_mm_node.start - fw_dev->fw_mm_base); + + return 0; + +err_remove_node: + spin_lock(&fw_dev->fw_mm_lock); + drm_mm_remove_node(&fw_obj->fw_mm_node); + +err_unlock: + spin_unlock(&fw_dev->fw_mm_lock); + + return err; +} + +/** + * pvr_fw_object_fw_unmap() - Unmap a previously mapped FW object + * @fw_obj: FW object to unmap. + * + * Returns: + * * 0 on success, or + * * -%EINVAL if object is not currently mapped. + */ +static int +pvr_fw_object_fw_unmap(struct pvr_fw_object *fw_obj) +{ + struct pvr_gem_object *pvr_obj = fw_obj->gem; + struct drm_gem_object *gem_obj = gem_from_pvr_gem(pvr_obj); + struct pvr_device *pvr_dev = to_pvr_device(gem_obj->dev); + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + + fw_dev->defs->vm_unmap(pvr_dev, fw_obj); + + spin_lock(&fw_dev->fw_mm_lock); + + if (!drm_mm_node_allocated(&fw_obj->fw_mm_node)) { + spin_unlock(&fw_dev->fw_mm_lock); + return -EINVAL; + } + + drm_mm_remove_node(&fw_obj->fw_mm_node); + + spin_unlock(&fw_dev->fw_mm_lock); + + return 0; +} + +static void * +pvr_fw_object_create_and_map_common(struct pvr_device *pvr_dev, size_t size, + u64 flags, u64 dev_addr, + void (*init)(void *cpu_ptr, void *priv), + void *init_priv, struct pvr_fw_object **fw_obj_out) +{ + struct pvr_fw_object *fw_obj; + void *cpu_ptr; + int err; + + /* %DRM_PVR_BO_PM_FW_PROTECT is implicit for FW objects. */ + flags |= DRM_PVR_BO_PM_FW_PROTECT; + + fw_obj = kzalloc(sizeof(*fw_obj), GFP_KERNEL); + if (!fw_obj) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD(&fw_obj->node); + fw_obj->init = init; + fw_obj->init_priv = init_priv; + + fw_obj->gem = pvr_gem_object_create(pvr_dev, size, flags); + if (IS_ERR(fw_obj->gem)) { + err = PTR_ERR(fw_obj->gem); + fw_obj->gem = NULL; + goto err_put_object; + } + + err = pvr_fw_object_fw_map(pvr_dev, fw_obj, dev_addr); + if (err) + goto err_put_object; + + cpu_ptr = pvr_fw_object_vmap(fw_obj); + if (IS_ERR(cpu_ptr)) { + err = PTR_ERR(cpu_ptr); + goto err_put_object; + } + + *fw_obj_out = fw_obj; + + if (fw_obj->init) + fw_obj->init(cpu_ptr, fw_obj->init_priv); + + mutex_lock(&pvr_dev->fw_dev.fw_objs.lock); + list_add_tail(&fw_obj->node, &pvr_dev->fw_dev.fw_objs.list); + mutex_unlock(&pvr_dev->fw_dev.fw_objs.lock); + + return cpu_ptr; + +err_put_object: + pvr_fw_object_destroy(fw_obj); + + return ERR_PTR(err); +} + +/** + * pvr_fw_object_create() - Create a FW object and map to firmware + * @pvr_dev: PowerVR device pointer. + * @size: Size of object, in bytes. + * @flags: Options which affect both this operation and future mapping + * operations performed on the returned object. Must be a combination of + * DRM_PVR_BO_* and/or PVR_BO_* flags. + * @init: Initialisation callback. + * @init_priv: Private pointer to pass to initialisation callback. + * @fw_obj_out: Pointer to location to store created object pointer. + * + * %DRM_PVR_BO_DEVICE_PM_FW_PROTECT is implied for all FW objects. Consequently, + * this function will fail if @flags has %DRM_PVR_BO_CPU_ALLOW_USERSPACE_ACCESS + * set. + * + * Returns: + * * 0 on success, or + * * Any error returned by pvr_fw_object_create_common(). + */ +int +pvr_fw_object_create(struct pvr_device *pvr_dev, size_t size, u64 flags, + void (*init)(void *cpu_ptr, void *priv), void *init_priv, + struct pvr_fw_object **fw_obj_out) +{ + void *cpu_ptr; + + cpu_ptr = pvr_fw_object_create_and_map_common(pvr_dev, size, flags, 0, init, init_priv, + fw_obj_out); + if (IS_ERR(cpu_ptr)) + return PTR_ERR(cpu_ptr); + + pvr_fw_object_vunmap(*fw_obj_out); + + return 0; +} + +/** + * pvr_fw_object_create_and_map() - Create a FW object and map to firmware and CPU + * @pvr_dev: PowerVR device pointer. + * @size: Size of object, in bytes. + * @flags: Options which affect both this operation and future mapping + * operations performed on the returned object. Must be a combination of + * DRM_PVR_BO_* and/or PVR_BO_* flags. + * @init: Initialisation callback. + * @init_priv: Private pointer to pass to initialisation callback. + * @fw_obj_out: Pointer to location to store created object pointer. + * + * %DRM_PVR_BO_DEVICE_PM_FW_PROTECT is implied for all FW objects. Consequently, + * this function will fail if @flags has %DRM_PVR_BO_CPU_ALLOW_USERSPACE_ACCESS + * set. + * + * Caller is responsible for calling pvr_fw_object_vunmap() to release the CPU + * mapping. + * + * Returns: + * * Pointer to CPU mapping of newly created object, or + * * Any error returned by pvr_fw_object_create(), or + * * Any error returned by pvr_fw_object_vmap(). + */ +void * +pvr_fw_object_create_and_map(struct pvr_device *pvr_dev, size_t size, u64 flags, + void (*init)(void *cpu_ptr, void *priv), + void *init_priv, struct pvr_fw_object **fw_obj_out) +{ + return pvr_fw_object_create_and_map_common(pvr_dev, size, flags, 0, init, init_priv, + fw_obj_out); +} + +/** + * pvr_fw_object_create_and_map_offset() - Create a FW object and map to + * firmware at the provided offset and to the CPU. + * @pvr_dev: PowerVR device pointer. + * @dev_offset: Base address of desired FW mapping, offset from start of FW heap. + * @size: Size of object, in bytes. + * @flags: Options which affect both this operation and future mapping + * operations performed on the returned object. Must be a combination of + * DRM_PVR_BO_* and/or PVR_BO_* flags. + * @init: Initialisation callback. + * @init_priv: Private pointer to pass to initialisation callback. + * @fw_obj_out: Pointer to location to store created object pointer. + * + * %DRM_PVR_BO_DEVICE_PM_FW_PROTECT is implied for all FW objects. Consequently, + * this function will fail if @flags has %DRM_PVR_BO_CPU_ALLOW_USERSPACE_ACCESS + * set. + * + * Caller is responsible for calling pvr_fw_object_vunmap() to release the CPU + * mapping. + * + * Returns: + * * Pointer to CPU mapping of newly created object, or + * * Any error returned by pvr_fw_object_create(), or + * * Any error returned by pvr_fw_object_vmap(). + */ +void * +pvr_fw_object_create_and_map_offset(struct pvr_device *pvr_dev, + u32 dev_offset, size_t size, u64 flags, + void (*init)(void *cpu_ptr, void *priv), + void *init_priv, struct pvr_fw_object **fw_obj_out) +{ + u64 dev_addr = pvr_dev->fw_dev.fw_mm_base + dev_offset; + + return pvr_fw_object_create_and_map_common(pvr_dev, size, flags, dev_addr, init, init_priv, + fw_obj_out); +} + +/** + * pvr_fw_object_destroy() - Destroy a pvr_fw_object + * @fw_obj: Pointer to object to destroy. + */ +void pvr_fw_object_destroy(struct pvr_fw_object *fw_obj) +{ + struct pvr_gem_object *pvr_obj = fw_obj->gem; + struct drm_gem_object *gem_obj = gem_from_pvr_gem(pvr_obj); + struct pvr_device *pvr_dev = to_pvr_device(gem_obj->dev); + + mutex_lock(&pvr_dev->fw_dev.fw_objs.lock); + list_del(&fw_obj->node); + mutex_unlock(&pvr_dev->fw_dev.fw_objs.lock); + + if (drm_mm_node_allocated(&fw_obj->fw_mm_node)) { + /* If we can't unmap, leak the memory. */ + if (WARN_ON(pvr_fw_object_fw_unmap(fw_obj))) + return; + } + + if (fw_obj->gem) + pvr_gem_object_put(fw_obj->gem); + + kfree(fw_obj); +} + +/** + * pvr_fw_object_get_fw_addr_offset() - Return address of object in firmware address space, with + * given offset. + * @fw_obj: Pointer to object. + * @offset: Desired offset from start of object. + * @fw_addr_out: Location to store address to. + */ +void pvr_fw_object_get_fw_addr_offset(struct pvr_fw_object *fw_obj, u32 offset, u32 *fw_addr_out) +{ + struct pvr_gem_object *pvr_obj = fw_obj->gem; + struct pvr_device *pvr_dev = to_pvr_device(gem_from_pvr_gem(pvr_obj)->dev); + + *fw_addr_out = pvr_dev->fw_dev.defs->get_fw_addr_with_offset(fw_obj, offset); +} + +/* + * pvr_fw_hard_reset() - Re-initialise the FW code and data segments, and reset all global FW + * structures + * @pvr_dev: Device pointer + * + * If this function returns an error then the caller must regard the device as lost. + * + * Returns: + * * 0 on success, or + * * Any error returned by pvr_fw_init_dev_structures() or pvr_fw_reset_all(). + */ +int +pvr_fw_hard_reset(struct pvr_device *pvr_dev) +{ + struct list_head *pos; + int err; + + /* Reset all FW objects */ + mutex_lock(&pvr_dev->fw_dev.fw_objs.lock); + + list_for_each(pos, &pvr_dev->fw_dev.fw_objs.list) { + struct pvr_fw_object *fw_obj = container_of(pos, struct pvr_fw_object, node); + void *cpu_ptr = pvr_fw_object_vmap(fw_obj); + + WARN_ON(IS_ERR(cpu_ptr)); + + if (!(fw_obj->gem->flags & PVR_BO_FW_NO_CLEAR_ON_RESET)) { + memset(cpu_ptr, 0, pvr_gem_object_size(fw_obj->gem)); + + if (fw_obj->init) + fw_obj->init(cpu_ptr, fw_obj->init_priv); + } + + pvr_fw_object_vunmap(fw_obj); + } + + mutex_unlock(&pvr_dev->fw_dev.fw_objs.lock); + + err = pvr_fw_reinit_code_data(pvr_dev); + if (err) + return err; + + return 0; +} diff --git a/drivers/gpu/drm/imagination/pvr_fw.h b/drivers/gpu/drm/imagination/pvr_fw.h new file mode 100644 index 00000000000000..b7966bd574a924 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_fw.h @@ -0,0 +1,509 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_FW_H +#define PVR_FW_H + +#include "pvr_fw_info.h" +#include "pvr_fw_trace.h" +#include "pvr_gem.h" + +#include + +#include + +/* Forward declarations from "pvr_device.h". */ +struct pvr_device; +struct pvr_file; + +/* Forward declaration from "pvr_vm.h". */ +struct pvr_vm_context; + +#define ROGUE_FWIF_FWCCB_NUMCMDS_LOG2 5 + +#define ROGUE_FWIF_KCCB_NUMCMDS_LOG2_DEFAULT 7 + +/** + * struct pvr_fw_object - container for firmware memory allocations + */ +struct pvr_fw_object { + /** @ref_count: FW object reference counter. */ + struct kref ref_count; + + /** @gem: GEM object backing the FW object. */ + struct pvr_gem_object *gem; + + /** + * @fw_mm_node: Node representing mapping in FW address space. @pvr_obj->lock must + * be held when writing. + */ + struct drm_mm_node fw_mm_node; + + /** + * @fw_addr_offset: Virtual address offset of firmware mapping. Only + * valid if @flags has %PVR_GEM_OBJECT_FLAGS_FW_MAPPED + * set. + */ + u32 fw_addr_offset; + + /** + * @init: Initialisation callback. Will be called on object creation and FW hard reset. + * Object will have been zeroed before this is called. + */ + void (*init)(void *cpu_ptr, void *priv); + + /** @init_priv: Private data for initialisation callback. */ + void *init_priv; + + /** @node: Node for firmware object list. */ + struct list_head node; +}; + +/** + * struct pvr_fw_defs - FW processor function table and static definitions + */ +struct pvr_fw_defs { + /** + * @init: + * + * FW processor specific initialisation. + * @pvr_dev: Target PowerVR device. + * + * This function must call pvr_fw_heap_calculate() to initialise the firmware heap for this + * FW processor. + * + * This function is mandatory. + * + * Returns: + * * 0 on success, or + * * Any appropriate error on failure. + */ + int (*init)(struct pvr_device *pvr_dev); + + /** + * @fini: + * + * FW processor specific finalisation. + * @pvr_dev: Target PowerVR device. + * + * This function is optional. + */ + void (*fini)(struct pvr_device *pvr_dev); + + /** + * @fw_process: + * + * Load and process firmware image. + * @pvr_dev: Target PowerVR device. + * @fw: Pointer to firmware image. + * @fw_code_ptr: Pointer to firmware code section. + * @fw_data_ptr: Pointer to firmware data section. + * @fw_core_code_ptr: Pointer to firmware core code section. May be %NULL. + * @fw_core_data_ptr: Pointer to firmware core data section. May be %NULL. + * @core_code_alloc_size: Total allocation size of core code section. + * + * This function is mandatory. + * + * Returns: + * * 0 on success, or + * * Any appropriate error on failure. + */ + int (*fw_process)(struct pvr_device *pvr_dev, const u8 *fw, + u8 *fw_code_ptr, u8 *fw_data_ptr, u8 *fw_core_code_ptr, + u8 *fw_core_data_ptr, u32 core_code_alloc_size); + + /** + * @vm_map: + * + * Map FW object into FW processor address space. + * @pvr_dev: Target PowerVR device. + * @fw_obj: FW object to map. + * + * This function is mandatory. + * + * Returns: + * * 0 on success, or + * * Any appropriate error on failure. + */ + int (*vm_map)(struct pvr_device *pvr_dev, struct pvr_fw_object *fw_obj); + + /** + * @vm_unmap: + * + * Unmap FW object from FW processor address space. + * @pvr_dev: Target PowerVR device. + * @fw_obj: FW object to map. + * + * This function is mandatory. + */ + void (*vm_unmap)(struct pvr_device *pvr_dev, struct pvr_fw_object *fw_obj); + + /** + * @get_fw_addr_with_offset: + * + * Called to get address of object in firmware address space, with offset. + * @fw_obj: Pointer to object. + * @offset: Desired offset from start of object. + * + * This function is mandatory. + * + * Returns: + * * Address in firmware address space. + */ + u32 (*get_fw_addr_with_offset)(struct pvr_fw_object *fw_obj, u32 offset); + + /** + * @wrapper_init: + * + * Called to initialise FW wrapper. + * @pvr_dev: Target PowerVR device. + * + * This function is mandatory. + * + * Returns: + * * 0 on success. + * * Any appropriate error on failure. + */ + int (*wrapper_init)(struct pvr_device *pvr_dev); + + /** + * @has_fixed_data_addr: + * + * Called to check if firmware fixed data must be loaded at the address given by the + * firmware layout table. + * + * This function is mandatory. + * + * Returns: + * * %true if firmware fixed data must be loaded at the address given by the firmware + * layout table. + * * %false otherwise. + */ + bool (*has_fixed_data_addr)(void); + + /** + * @irq: FW Interrupt information. + * + * Those are processor dependent, and should be initialized by the + * processor backend in pvr_fw_funcs::init(). + */ + struct { + /** @enable_reg: FW interrupt enable register. */ + u32 enable_reg; + + /** @status_reg: FW interrupt status register. */ + u32 status_reg; + + /** + * @clear_reg: FW interrupt clear register. + * + * If @status_reg == @clear_reg, we clear by write a bit to zero, + * otherwise we clear by writing a bit to one. + */ + u32 clear_reg; + + /** @event_mask: Bitmask of events to listen for. */ + u32 event_mask; + + /** @clear_mask: Value to write to the clear_reg in order to clear FW IRQs. */ + u32 clear_mask; + } irq; +}; + +/** + * struct pvr_fw_mem - FW memory allocations + */ +struct pvr_fw_mem { + /** @code_obj: Object representing firmware code. */ + struct pvr_fw_object *code_obj; + + /** @data_obj: Object representing firmware data. */ + struct pvr_fw_object *data_obj; + + /** + * @core_code_obj: Object representing firmware core code. May be + * %NULL if firmware does not contain this section. + */ + struct pvr_fw_object *core_code_obj; + + /** + * @core_data_obj: Object representing firmware core data. May be + * %NULL if firmware does not contain this section. + */ + struct pvr_fw_object *core_data_obj; + + /** @code: Driver-side copy of firmware code. */ + u8 *code; + + /** @data: Driver-side copy of firmware data. */ + u8 *data; + + /** + * @core_code: Driver-side copy of firmware core code. May be %NULL if firmware does not + * contain this section. + */ + u8 *core_code; + + /** + * @core_data: Driver-side copy of firmware core data. May be %NULL if firmware does not + * contain this section. + */ + u8 *core_data; + + /** @code_alloc_size: Allocation size of firmware code section. */ + u32 code_alloc_size; + + /** @data_alloc_size: Allocation size of firmware data section. */ + u32 data_alloc_size; + + /** @core_code_alloc_size: Allocation size of firmware core code section. */ + u32 core_code_alloc_size; + + /** @core_data_alloc_size: Allocation size of firmware core data section. */ + u32 core_data_alloc_size; + + /** + * @fwif_connection_ctl_obj: Object representing FWIF connection control + * structure. + */ + struct pvr_fw_object *fwif_connection_ctl_obj; + + /** @osinit_obj: Object representing FW OSINIT structure. */ + struct pvr_fw_object *osinit_obj; + + /** @sysinit_obj: Object representing FW SYSINIT structure. */ + struct pvr_fw_object *sysinit_obj; + + /** @osdata_obj: Object representing FW OSDATA structure. */ + struct pvr_fw_object *osdata_obj; + + /** @hwrinfobuf_obj: Object representing FW hwrinfobuf structure. */ + struct pvr_fw_object *hwrinfobuf_obj; + + /** @sysdata_obj: Object representing FW SYSDATA structure. */ + struct pvr_fw_object *sysdata_obj; + + /** @power_sync_obj: Object representing power sync state. */ + struct pvr_fw_object *power_sync_obj; + + /** @fault_page_obj: Object representing FW fault page. */ + struct pvr_fw_object *fault_page_obj; + + /** @gpu_util_fwcb_obj: Object representing FW GPU utilisation control structure. */ + struct pvr_fw_object *gpu_util_fwcb_obj; + + /** @runtime_cfg_obj: Object representing FW runtime config structure. */ + struct pvr_fw_object *runtime_cfg_obj; + + /** @mmucache_sync_obj: Object used as the sync parameter in an MMU cache operation. */ + struct pvr_fw_object *mmucache_sync_obj; +}; + +struct pvr_fw_device { + /** @firmware: Handle to the firmware loaded into the device. */ + const struct firmware *firmware; + + /** @header: Pointer to firmware header. */ + const struct pvr_fw_info_header *header; + + /** @layout_entries: Pointer to firmware layout. */ + const struct pvr_fw_layout_entry *layout_entries; + + /** @mem: Structure containing objects representing firmware memory allocations. */ + struct pvr_fw_mem mem; + + /** @booted: %true if the firmware has been booted, %false otherwise. */ + bool booted; + + /** + * @processor_type: FW processor type for this device. Must be one of + * %PVR_FW_PROCESSOR_TYPE_*. + */ + u16 processor_type; + + /** @funcs: Function table for the FW processor used by this device. */ + const struct pvr_fw_defs *defs; + + /** @processor_data: Pointer to data specific to FW processor. */ + union { + /** @mips_data: Pointer to MIPS-specific data. */ + struct pvr_fw_mips_data *mips_data; + } processor_data; + + /** @fw_heap_info: Firmware heap information. */ + struct { + /** @gpu_addr: Base address of firmware heap in GPU address space. */ + u64 gpu_addr; + + /** @size: Size of main area of heap. */ + u32 size; + + /** @offset_mask: Mask for offsets within FW heap. */ + u32 offset_mask; + + /** @raw_size: Raw size of heap, including reserved areas. */ + u32 raw_size; + + /** @log2_size: Log2 of raw size of heap. */ + u32 log2_size; + + /** @config_offset: Offset of config area within heap. */ + u32 config_offset; + + /** @reserved_size: Size of reserved area in heap. */ + u32 reserved_size; + } fw_heap_info; + + /** @fw_mm: Firmware address space allocator. */ + struct drm_mm fw_mm; + + /** @fw_mm_lock: Lock protecting access to &fw_mm. */ + spinlock_t fw_mm_lock; + + /** @fw_mm_base: Base address of address space managed by @fw_mm. */ + u64 fw_mm_base; + + /** + * @fwif_connection_ctl: Pointer to CPU mapping of FWIF connection + * control structure. + */ + struct rogue_fwif_connection_ctl *fwif_connection_ctl; + + /** @fwif_sysinit: Pointer to CPU mapping of FW SYSINIT structure. */ + struct rogue_fwif_sysinit *fwif_sysinit; + + /** @fwif_sysdata: Pointer to CPU mapping of FW SYSDATA structure. */ + struct rogue_fwif_sysdata *fwif_sysdata; + + /** @fwif_osinit: Pointer to CPU mapping of FW OSINIT structure. */ + struct rogue_fwif_osinit *fwif_osinit; + + /** @fwif_osdata: Pointer to CPU mapping of FW OSDATA structure. */ + struct rogue_fwif_osdata *fwif_osdata; + + /** @power_sync: Pointer to CPU mapping of power sync state. */ + u32 *power_sync; + + /** @hwrinfobuf: Pointer to CPU mapping of FW HWR info buffer. */ + struct rogue_fwif_hwrinfobuf *hwrinfobuf; + + /** @fw_trace: Device firmware trace buffer state. */ + struct pvr_fw_trace fw_trace; + + /** @fw_objs: Structure tracking FW objects. */ + struct { + /** @list: Head of FW object list. */ + struct list_head list; + + /** @lock: Lock protecting access to FW object list. */ + struct mutex lock; + } fw_objs; +}; + +#define pvr_fw_irq_read_reg(pvr_dev, name) \ + pvr_cr_read32((pvr_dev), (pvr_dev)->fw_dev.defs->irq.name ## _reg) + +#define pvr_fw_irq_write_reg(pvr_dev, name, value) \ + pvr_cr_write32((pvr_dev), (pvr_dev)->fw_dev.defs->irq.name ## _reg, value) + +#define pvr_fw_irq_pending(pvr_dev) \ + (pvr_fw_irq_read_reg(pvr_dev, status) & (pvr_dev)->fw_dev.defs->irq.event_mask) + +#define pvr_fw_irq_clear(pvr_dev) \ + pvr_fw_irq_write_reg(pvr_dev, clear, (pvr_dev)->fw_dev.defs->irq.clear_mask) + +#define pvr_fw_irq_enable(pvr_dev) \ + pvr_fw_irq_write_reg(pvr_dev, enable, (pvr_dev)->fw_dev.defs->irq.event_mask) + +#define pvr_fw_irq_disable(pvr_dev) \ + pvr_fw_irq_write_reg(pvr_dev, enable, 0) + +extern const struct pvr_fw_defs pvr_fw_defs_meta; +extern const struct pvr_fw_defs pvr_fw_defs_mips; + +int pvr_fw_validate_init_device_info(struct pvr_device *pvr_dev); +int pvr_fw_init(struct pvr_device *pvr_dev); +void pvr_fw_fini(struct pvr_device *pvr_dev); + +int pvr_wait_for_fw_boot(struct pvr_device *pvr_dev); + +int +pvr_fw_hard_reset(struct pvr_device *pvr_dev); + +void pvr_fw_mts_schedule(struct pvr_device *pvr_dev, u32 val); + +void +pvr_fw_heap_info_init(struct pvr_device *pvr_dev, u32 log2_size, u32 reserved_size); + +const struct pvr_fw_layout_entry * +pvr_fw_find_layout_entry(struct pvr_device *pvr_dev, enum pvr_fw_section_id id); +int +pvr_fw_find_mmu_segment(struct pvr_device *pvr_dev, u32 addr, u32 size, void *fw_code_ptr, + void *fw_data_ptr, void *fw_core_code_ptr, void *fw_core_data_ptr, + void **host_addr_out); + +int +pvr_fw_structure_cleanup(struct pvr_device *pvr_dev, u32 type, struct pvr_fw_object *fw_obj, + u32 offset); + +int pvr_fw_object_create(struct pvr_device *pvr_dev, size_t size, u64 flags, + void (*init)(void *cpu_ptr, void *priv), void *init_priv, + struct pvr_fw_object **pvr_obj_out); + +void *pvr_fw_object_create_and_map(struct pvr_device *pvr_dev, size_t size, u64 flags, + void (*init)(void *cpu_ptr, void *priv), + void *init_priv, struct pvr_fw_object **pvr_obj_out); + +void * +pvr_fw_object_create_and_map_offset(struct pvr_device *pvr_dev, u32 dev_offset, size_t size, + u64 flags, void (*init)(void *cpu_ptr, void *priv), + void *init_priv, struct pvr_fw_object **pvr_obj_out); + +static __always_inline void * +pvr_fw_object_vmap(struct pvr_fw_object *fw_obj) +{ + return pvr_gem_object_vmap(fw_obj->gem); +} + +static __always_inline void +pvr_fw_object_vunmap(struct pvr_fw_object *fw_obj) +{ + pvr_gem_object_vunmap(fw_obj->gem); +} + +void pvr_fw_object_destroy(struct pvr_fw_object *fw_obj); + +static __always_inline void +pvr_fw_object_unmap_and_destroy(struct pvr_fw_object *fw_obj) +{ + pvr_fw_object_vunmap(fw_obj); + pvr_fw_object_destroy(fw_obj); +} + +/** + * pvr_fw_object_get_dma_addr() - Get DMA address for given offset in firmware + * object. + * @fw_obj: Pointer to object to lookup address in. + * @offset: Offset within object to lookup address at. + * @dma_addr_out: Pointer to location to store DMA address. + * + * Returns: + * * 0 on success, or + * * -%EINVAL if object is not currently backed, or if @offset is out of valid + * range for this object. + */ +static __always_inline int +pvr_fw_object_get_dma_addr(struct pvr_fw_object *fw_obj, u32 offset, dma_addr_t *dma_addr_out) +{ + return pvr_gem_get_dma_addr(fw_obj->gem, offset, dma_addr_out); +} + +void pvr_fw_object_get_fw_addr_offset(struct pvr_fw_object *fw_obj, u32 offset, u32 *fw_addr_out); + +static __always_inline void +pvr_fw_object_get_fw_addr(struct pvr_fw_object *fw_obj, u32 *fw_addr_out) +{ + pvr_fw_object_get_fw_addr_offset(fw_obj, 0, fw_addr_out); +} + +#endif /* PVR_FW_H */ diff --git a/drivers/gpu/drm/imagination/pvr_fw_info.h b/drivers/gpu/drm/imagination/pvr_fw_info.h new file mode 100644 index 00000000000000..c3639440610eb1 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_fw_info.h @@ -0,0 +1,135 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_FW_INFO_H +#define PVR_FW_INFO_H + +#include +#include +#include + +/* + * Firmware binary block unit in bytes. + * Raw data stored in FW binary will be aligned to this size. + */ +#define FW_BLOCK_SIZE SZ_4K + +/* Maximum number of entries in firmware layout table. */ +#define PVR_FW_INFO_MAX_NUM_ENTRIES 8 + +enum pvr_fw_section_id { + META_CODE = 0, + META_PRIVATE_DATA, + META_COREMEM_CODE, + META_COREMEM_DATA, + MIPS_CODE, + MIPS_EXCEPTIONS_CODE, + MIPS_BOOT_CODE, + MIPS_PRIVATE_DATA, + MIPS_BOOT_DATA, + MIPS_STACK, + RISCV_UNCACHED_CODE, + RISCV_CACHED_CODE, + RISCV_PRIVATE_DATA, + RISCV_COREMEM_CODE, + RISCV_COREMEM_DATA, +}; + +enum pvr_fw_section_type { + NONE = 0, + FW_CODE, + FW_DATA, + FW_COREMEM_CODE, + FW_COREMEM_DATA, +}; + +/* + * FW binary format with FW info attached: + * + * Contents Offset + * +-----------------+ + * | | 0 + * | | + * | Original binary | + * | file | + * | (.ldr/.elf) | + * | | + * | | + * +-----------------+ + * | Device info | FILE_SIZE - 4K - device_info_size + * +-----------------+ + * | FW info header | FILE_SIZE - 4K + * +-----------------+ + * | | + * | FW layout table | + * | | + * +-----------------+ + * FILE_SIZE + */ + +#define PVR_FW_INFO_VERSION 3 + +#define PVR_FW_FLAGS_OPEN_SOURCE BIT(0) + +/** struct pvr_fw_info_header - Firmware header */ +struct pvr_fw_info_header { + /** @info_version: FW info header version. */ + u32 info_version; + /** @header_len: Header length. */ + u32 header_len; + /** @layout_entry_num: Number of entries in the layout table. */ + u32 layout_entry_num; + /** @layout_entry_size: Size of an entry in the layout table. */ + u32 layout_entry_size; + /** @bvnc: GPU ID supported by firmware. */ + aligned_u64 bvnc; + /** @fw_page_size: Page size of processor on which firmware executes. */ + u32 fw_page_size; + /** @flags: Compatibility flags. */ + u32 flags; + /** @fw_version_major: Firmware major version number. */ + u16 fw_version_major; + /** @fw_version_minor: Firmware minor version number. */ + u16 fw_version_minor; + /** @fw_version_build: Firmware build number. */ + u32 fw_version_build; + /** @device_info_size: Size of device info structure. */ + u32 device_info_size; + /** @padding: Padding. */ + u32 padding; +}; + +/** + * struct pvr_fw_layout_entry - Entry in firmware layout table, describing a + * section of the firmware image + */ +struct pvr_fw_layout_entry { + /** @id: Section ID. */ + enum pvr_fw_section_id id; + /** @type: Section type. */ + enum pvr_fw_section_type type; + /** @base_addr: Base address of section in FW address space. */ + u32 base_addr; + /** @max_size: Maximum size of section, in bytes. */ + u32 max_size; + /** @alloc_size: Allocation size of section, in bytes. */ + u32 alloc_size; + /** @alloc_offset: Allocation offset of section. */ + u32 alloc_offset; +}; + +/** + * struct pvr_fw_device_info_header - Device information header. + */ +struct pvr_fw_device_info_header { + /** @brn_mask_size: BRN mask size (in u64s). */ + u64 brn_mask_size; + /** @ern_mask_size: ERN mask size (in u64s). */ + u64 ern_mask_size; + /** @feature_mask_size: Feature mask size (in u64s). */ + u64 feature_mask_size; + /** @feature_param_size: Feature parameter size (in u64s). */ + u64 feature_param_size; +}; + +#endif /* PVR_FW_INFO_H */ diff --git a/drivers/gpu/drm/imagination/pvr_fw_meta.c b/drivers/gpu/drm/imagination/pvr_fw_meta.c new file mode 100644 index 00000000000000..c39beb70c3173e --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_fw_meta.c @@ -0,0 +1,555 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_device.h" +#include "pvr_fw.h" +#include "pvr_fw_info.h" +#include "pvr_fw_meta.h" +#include "pvr_gem.h" +#include "pvr_rogue_cr_defs.h" +#include "pvr_rogue_meta.h" +#include "pvr_vm.h" + +#include +#include +#include +#include +#include + +#define ROGUE_FW_HEAP_META_SHIFT 25 /* 32 MB */ + +#define POLL_TIMEOUT_USEC 1000000 + +/** + * pvr_meta_cr_read32() - Read a META register via the Slave Port + * @pvr_dev: Device pointer. + * @reg_addr: Address of register to read. + * @reg_value_out: Pointer to location to store register value. + * + * Returns: + * * 0 on success, or + * * Any error returned by pvr_cr_poll_reg32(). + */ +int +pvr_meta_cr_read32(struct pvr_device *pvr_dev, u32 reg_addr, u32 *reg_value_out) +{ + int err; + + /* Wait for Slave Port to be Ready. */ + err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_META_SP_MSLVCTRL1, + ROGUE_CR_META_SP_MSLVCTRL1_READY_EN | + ROGUE_CR_META_SP_MSLVCTRL1_GBLPORT_IDLE_EN, + ROGUE_CR_META_SP_MSLVCTRL1_READY_EN | + ROGUE_CR_META_SP_MSLVCTRL1_GBLPORT_IDLE_EN, + POLL_TIMEOUT_USEC); + if (err) + return err; + + /* Issue a Read. */ + pvr_cr_write32(pvr_dev, ROGUE_CR_META_SP_MSLVCTRL0, + reg_addr | ROGUE_CR_META_SP_MSLVCTRL0_RD_EN); + (void)pvr_cr_read32(pvr_dev, ROGUE_CR_META_SP_MSLVCTRL0); /* Fence write. */ + + /* Wait for Slave Port to be Ready. */ + err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_META_SP_MSLVCTRL1, + ROGUE_CR_META_SP_MSLVCTRL1_READY_EN | + ROGUE_CR_META_SP_MSLVCTRL1_GBLPORT_IDLE_EN, + ROGUE_CR_META_SP_MSLVCTRL1_READY_EN | + ROGUE_CR_META_SP_MSLVCTRL1_GBLPORT_IDLE_EN, + POLL_TIMEOUT_USEC); + if (err) + return err; + + *reg_value_out = pvr_cr_read32(pvr_dev, ROGUE_CR_META_SP_MSLVDATAX); + + return 0; +} + +static int +pvr_meta_wrapper_init(struct pvr_device *pvr_dev) +{ + u64 garten_config; + + /* Configure META to Master boot. */ + pvr_cr_write64(pvr_dev, ROGUE_CR_META_BOOT, ROGUE_CR_META_BOOT_MODE_EN); + + /* Set Garten IDLE to META idle and Set the Garten Wrapper BIF Fence address. */ + + /* Garten IDLE bit controlled by META. */ + garten_config = ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_IDLE_CTRL_META; + + /* The fence addr is set during the fw init sequence. */ + + /* Set PC = 0 for fences. */ + garten_config &= + ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_FENCE_PC_BASE_CLRMSK; + garten_config |= + (u64)MMU_CONTEXT_MAPPING_FWPRIV + << ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_FENCE_PC_BASE_SHIFT; + + /* Set SLC DM=META. */ + garten_config |= ((u64)ROGUE_FW_SEGMMU_META_BIFDM_ID) + << ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_FENCE_DM_SHIFT; + + pvr_cr_write64(pvr_dev, ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG, garten_config); + + return 0; +} + +static __always_inline void +add_boot_arg(u32 **boot_conf, u32 param, u32 data) +{ + *(*boot_conf)++ = param; + *(*boot_conf)++ = data; +} + +static int +meta_ldr_cmd_loadmem(struct drm_device *drm_dev, const u8 *fw, + struct rogue_meta_ldr_l1_data_blk *l1_data, u32 coremem_size, u8 *fw_code_ptr, + u8 *fw_data_ptr, u8 *fw_core_code_ptr, u8 *fw_core_data_ptr, const u32 fw_size) +{ + struct rogue_meta_ldr_l2_data_blk *l2_block = + (struct rogue_meta_ldr_l2_data_blk *)(fw + + l1_data->cmd_data[1]); + struct pvr_device *pvr_dev = to_pvr_device(drm_dev); + u32 offset = l1_data->cmd_data[0]; + u32 data_size; + void *write_addr; + int err; + + /* Verify header is within bounds. */ + if (((u8 *)l2_block - fw) >= fw_size || ((u8 *)(l2_block + 1) - fw) >= fw_size) + return -EINVAL; + + data_size = l2_block->length - 6 /* L2 Tag length and checksum */; + + /* Verify data is within bounds. */ + if (((u8 *)l2_block->block_data - fw) >= fw_size || + ((((u8 *)l2_block->block_data) + data_size) - fw) >= fw_size) + return -EINVAL; + + if (!ROGUE_META_IS_COREMEM_CODE(offset, coremem_size) && + !ROGUE_META_IS_COREMEM_DATA(offset, coremem_size)) { + /* Global range is aliased to local range */ + offset &= ~META_MEM_GLOBAL_RANGE_BIT; + } + + err = pvr_fw_find_mmu_segment(pvr_dev, offset, data_size, fw_code_ptr, fw_data_ptr, + fw_core_code_ptr, fw_core_data_ptr, &write_addr); + if (err) { + drm_err(drm_dev, + "Addr 0x%x (size: %d) not found in any firmware segment", + offset, data_size); + return err; + } + + memcpy(write_addr, l2_block->block_data, data_size); + + return 0; +} + +static int +meta_ldr_cmd_zeromem(struct drm_device *drm_dev, + struct rogue_meta_ldr_l1_data_blk *l1_data, u32 coremem_size, + u8 *fw_code_ptr, u8 *fw_data_ptr, u8 *fw_core_code_ptr, u8 *fw_core_data_ptr) +{ + struct pvr_device *pvr_dev = to_pvr_device(drm_dev); + u32 offset = l1_data->cmd_data[0]; + u32 byte_count = l1_data->cmd_data[1]; + void *write_addr; + int err; + + if (ROGUE_META_IS_COREMEM_DATA(offset, coremem_size)) { + /* cannot zero coremem directly */ + return 0; + } + + /* Global range is aliased to local range */ + offset &= ~META_MEM_GLOBAL_RANGE_BIT; + + err = pvr_fw_find_mmu_segment(pvr_dev, offset, byte_count, fw_code_ptr, fw_data_ptr, + fw_core_code_ptr, fw_core_data_ptr, &write_addr); + if (err) { + drm_err(drm_dev, + "Addr 0x%x (size: %d) not found in any firmware segment", + offset, byte_count); + return err; + } + + memset(write_addr, 0, byte_count); + + return 0; +} + +static int +meta_ldr_cmd_config(struct drm_device *drm_dev, const u8 *fw, + struct rogue_meta_ldr_l1_data_blk *l1_data, + const u32 fw_size, u32 **boot_conf_ptr) +{ + struct rogue_meta_ldr_l2_data_blk *l2_block = + (struct rogue_meta_ldr_l2_data_blk *)(fw + + l1_data->cmd_data[0]); + struct rogue_meta_ldr_cfg_blk *config_command; + u32 l2_block_size; + u32 curr_block_size = 0; + u32 *boot_conf = boot_conf_ptr ? *boot_conf_ptr : NULL; + + /* Verify block header is within bounds. */ + if (((u8 *)l2_block - fw) >= fw_size || ((u8 *)(l2_block + 1) - fw) >= fw_size) + return -EINVAL; + + l2_block_size = l2_block->length - 6 /* L2 Tag length and checksum */; + config_command = (struct rogue_meta_ldr_cfg_blk *)l2_block->block_data; + + if (((u8 *)config_command - fw) >= fw_size || + ((((u8 *)config_command) + l2_block_size) - fw) >= fw_size) + return -EINVAL; + + while (l2_block_size >= 12) { + if (config_command->type != ROGUE_META_LDR_CFG_WRITE) + return -EINVAL; + + /* + * Only write to bootloader if we got a valid pointer to the FW + * code allocation. + */ + if (boot_conf) { + u32 register_offset = config_command->block_data[0]; + u32 register_value = config_command->block_data[1]; + + /* Do register write */ + add_boot_arg(&boot_conf, register_offset, + register_value); + } + + curr_block_size = 12; + l2_block_size -= curr_block_size; + config_command = (struct rogue_meta_ldr_cfg_blk + *)((uintptr_t)config_command + + curr_block_size); + } + + if (boot_conf_ptr) + *boot_conf_ptr = boot_conf; + + return 0; +} + +/** + * process_ldr_command_stream() - Process LDR firmware image and populate + * firmware sections + * @pvr_dev: Device pointer. + * @fw: Pointer to firmware image. + * @fw_code_ptr: Pointer to FW code section. + * @fw_data_ptr: Pointer to FW data section. + * @fw_core_code_ptr: Pointer to FW coremem code section. + * @fw_core_data_ptr: Pointer to FW coremem data section. + * @boot_conf_ptr: Pointer to boot config argument pointer. + * + * Returns : + * * 0 on success, or + * * -EINVAL on any error in LDR command stream. + */ +static int +process_ldr_command_stream(struct pvr_device *pvr_dev, const u8 *fw, u8 *fw_code_ptr, + u8 *fw_data_ptr, u8 *fw_core_code_ptr, + u8 *fw_core_data_ptr, u32 **boot_conf_ptr) +{ + struct drm_device *drm_dev = from_pvr_device(pvr_dev); + struct rogue_meta_ldr_block_hdr *ldr_header = + (struct rogue_meta_ldr_block_hdr *)fw; + struct rogue_meta_ldr_l1_data_blk *l1_data = + (struct rogue_meta_ldr_l1_data_blk *)(fw + ldr_header->sl_data); + const u32 fw_size = pvr_dev->fw_dev.firmware->size; + int err; + + u32 *boot_conf = boot_conf_ptr ? *boot_conf_ptr : NULL; + u32 coremem_size; + + err = PVR_FEATURE_VALUE(pvr_dev, meta_coremem_size, &coremem_size); + if (err) + return err; + + coremem_size *= SZ_1K; + + while (l1_data) { + /* Verify block header is within bounds. */ + if (((u8 *)l1_data - fw) >= fw_size || ((u8 *)(l1_data + 1) - fw) >= fw_size) + return -EINVAL; + + if (ROGUE_META_LDR_BLK_IS_COMMENT(l1_data->cmd)) { + /* Don't process comment blocks */ + goto next_block; + } + + switch (l1_data->cmd & ROGUE_META_LDR_CMD_MASK) + case ROGUE_META_LDR_CMD_LOADMEM: { + err = meta_ldr_cmd_loadmem(drm_dev, fw, l1_data, + coremem_size, + fw_code_ptr, fw_data_ptr, + fw_core_code_ptr, + fw_core_data_ptr, fw_size); + if (err) + return err; + break; + + case ROGUE_META_LDR_CMD_START_THREADS: + /* Don't process this block */ + break; + + case ROGUE_META_LDR_CMD_ZEROMEM: + err = meta_ldr_cmd_zeromem(drm_dev, l1_data, + coremem_size, + fw_code_ptr, fw_data_ptr, + fw_core_code_ptr, + fw_core_data_ptr); + if (err) + return err; + break; + + case ROGUE_META_LDR_CMD_CONFIG: + err = meta_ldr_cmd_config(drm_dev, fw, l1_data, fw_size, + &boot_conf); + if (err) + return err; + break; + + default: + return -EINVAL; + } + +next_block: + if (l1_data->next == 0xFFFFFFFF) + break; + + l1_data = (struct rogue_meta_ldr_l1_data_blk *)(fw + + l1_data->next); + } + + if (boot_conf_ptr) + *boot_conf_ptr = boot_conf; + + return 0; +} + +static void +configure_seg_id(u64 seg_out_addr, u32 seg_base, u32 seg_limit, u32 seg_id, + u32 **boot_conf_ptr) +{ + u32 seg_out_addr0 = seg_out_addr & 0x00000000FFFFFFFFUL; + u32 seg_out_addr1 = (seg_out_addr >> 32) & 0x00000000FFFFFFFFUL; + u32 *boot_conf = *boot_conf_ptr; + + /* META segments have a minimum size. */ + u32 limit_off = max(seg_limit, ROGUE_FW_SEGMMU_ALIGN); + + /* The limit is an offset, therefore off = size - 1. */ + limit_off -= 1; + + seg_base |= ROGUE_FW_SEGMMU_ALLTHRS_WRITEABLE; + + add_boot_arg(&boot_conf, META_CR_MMCU_SEGMENT_N_BASE(seg_id), seg_base); + add_boot_arg(&boot_conf, META_CR_MMCU_SEGMENT_N_LIMIT(seg_id), limit_off); + add_boot_arg(&boot_conf, META_CR_MMCU_SEGMENT_N_OUTA0(seg_id), seg_out_addr0); + add_boot_arg(&boot_conf, META_CR_MMCU_SEGMENT_N_OUTA1(seg_id), seg_out_addr1); + + *boot_conf_ptr = boot_conf; +} + +static u64 get_fw_obj_gpu_addr(struct pvr_fw_object *fw_obj) +{ + struct pvr_device *pvr_dev = to_pvr_device(gem_from_pvr_gem(fw_obj->gem)->dev); + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + + return fw_obj->fw_addr_offset + fw_dev->fw_heap_info.gpu_addr; +} + +static void +configure_seg_mmu(struct pvr_device *pvr_dev, u32 **boot_conf_ptr) +{ + const struct pvr_fw_layout_entry *layout_entries = pvr_dev->fw_dev.layout_entries; + u32 num_layout_entries = pvr_dev->fw_dev.header->layout_entry_num; + u64 seg_out_addr_top; + u32 i; + + seg_out_addr_top = + ROGUE_FW_SEGMMU_OUTADDR_TOP_SLC(MMU_CONTEXT_MAPPING_FWPRIV, + ROGUE_FW_SEGMMU_META_BIFDM_ID); + + for (i = 0; i < num_layout_entries; i++) { + /* + * FW code is using the bootloader segment which is already + * configured on boot. FW coremem code and data don't use the + * segment MMU. Only the FW data segment needs to be configured. + */ + if (layout_entries[i].type == FW_DATA) { + u32 seg_id = ROGUE_FW_SEGMMU_DATA_ID; + u64 seg_out_addr = get_fw_obj_gpu_addr(pvr_dev->fw_dev.mem.data_obj); + + seg_out_addr += layout_entries[i].alloc_offset; + seg_out_addr |= seg_out_addr_top; + + /* Write the sequence to the bootldr. */ + configure_seg_id(seg_out_addr, + layout_entries[i].base_addr, + layout_entries[i].alloc_size, seg_id, + boot_conf_ptr); + + break; + } + } +} + +static void +configure_meta_caches(u32 **boot_conf_ptr) +{ + u32 *boot_conf = *boot_conf_ptr; + u32 d_cache_t0, i_cache_t0; + u32 d_cache_t1, i_cache_t1; + u32 d_cache_t2, i_cache_t2; + u32 d_cache_t3, i_cache_t3; + + /* Initialise I/Dcache settings */ + d_cache_t0 = META_CR_SYSC_DCPARTX_CACHED_WRITE_ENABLE; + d_cache_t1 = META_CR_SYSC_DCPARTX_CACHED_WRITE_ENABLE; + d_cache_t2 = META_CR_SYSC_DCPARTX_CACHED_WRITE_ENABLE; + d_cache_t3 = META_CR_SYSC_DCPARTX_CACHED_WRITE_ENABLE; + i_cache_t0 = 0; + i_cache_t1 = 0; + i_cache_t2 = 0; + i_cache_t3 = 0; + + d_cache_t0 |= META_CR_SYSC_XCPARTX_LOCAL_ADDR_FULL_CACHE; + i_cache_t0 |= META_CR_SYSC_XCPARTX_LOCAL_ADDR_FULL_CACHE; + + /* Local region MMU enhanced bypass: WIN-3 mode for code and data caches */ + add_boot_arg(&boot_conf, META_CR_MMCU_LOCAL_EBCTRL, + META_CR_MMCU_LOCAL_EBCTRL_ICWIN | + META_CR_MMCU_LOCAL_EBCTRL_DCWIN); + + /* Data cache partitioning thread 0 to 3 */ + add_boot_arg(&boot_conf, META_CR_SYSC_DCPART(0), d_cache_t0); + add_boot_arg(&boot_conf, META_CR_SYSC_DCPART(1), d_cache_t1); + add_boot_arg(&boot_conf, META_CR_SYSC_DCPART(2), d_cache_t2); + add_boot_arg(&boot_conf, META_CR_SYSC_DCPART(3), d_cache_t3); + + /* Enable data cache hits */ + add_boot_arg(&boot_conf, META_CR_MMCU_DCACHE_CTRL, + META_CR_MMCU_XCACHE_CTRL_CACHE_HITS_EN); + + /* Instruction cache partitioning thread 0 to 3 */ + add_boot_arg(&boot_conf, META_CR_SYSC_ICPART(0), i_cache_t0); + add_boot_arg(&boot_conf, META_CR_SYSC_ICPART(1), i_cache_t1); + add_boot_arg(&boot_conf, META_CR_SYSC_ICPART(2), i_cache_t2); + add_boot_arg(&boot_conf, META_CR_SYSC_ICPART(3), i_cache_t3); + + /* Enable instruction cache hits */ + add_boot_arg(&boot_conf, META_CR_MMCU_ICACHE_CTRL, + META_CR_MMCU_XCACHE_CTRL_CACHE_HITS_EN); + + add_boot_arg(&boot_conf, 0x040000C0, 0); + + *boot_conf_ptr = boot_conf; +} + +static int +pvr_meta_fw_process(struct pvr_device *pvr_dev, const u8 *fw, + u8 *fw_code_ptr, u8 *fw_data_ptr, u8 *fw_core_code_ptr, u8 *fw_core_data_ptr, + u32 core_code_alloc_size) +{ + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + u32 *boot_conf; + int err; + + boot_conf = ((u32 *)fw_code_ptr) + ROGUE_FW_BOOTLDR_CONF_OFFSET; + + /* Slave port and JTAG accesses are privileged. */ + add_boot_arg(&boot_conf, META_CR_SYSC_JTAG_THREAD, + META_CR_SYSC_JTAG_THREAD_PRIV_EN); + + configure_seg_mmu(pvr_dev, &boot_conf); + + /* Populate FW sections from LDR image. */ + err = process_ldr_command_stream(pvr_dev, fw, fw_code_ptr, fw_data_ptr, fw_core_code_ptr, + fw_core_data_ptr, &boot_conf); + if (err) + return err; + + configure_meta_caches(&boot_conf); + + /* End argument list. */ + add_boot_arg(&boot_conf, 0, 0); + + if (fw_dev->mem.core_code_obj) { + u32 core_code_fw_addr; + + pvr_fw_object_get_fw_addr(fw_dev->mem.core_code_obj, &core_code_fw_addr); + add_boot_arg(&boot_conf, core_code_fw_addr, core_code_alloc_size); + } else { + add_boot_arg(&boot_conf, 0, 0); + } + /* None of the cores supported by this driver have META DMA. */ + add_boot_arg(&boot_conf, 0, 0); + + return 0; +} + +static int +pvr_meta_init(struct pvr_device *pvr_dev) +{ + pvr_fw_heap_info_init(pvr_dev, ROGUE_FW_HEAP_META_SHIFT, 0); + + return 0; +} + +static u32 +pvr_meta_get_fw_addr_with_offset(struct pvr_fw_object *fw_obj, u32 offset) +{ + u32 fw_addr = fw_obj->fw_addr_offset + offset + ROGUE_FW_SEGMMU_DATA_BASE_ADDRESS; + + /* META cacheability is determined by address. */ + if (fw_obj->gem->flags & PVR_BO_FW_FLAGS_DEVICE_UNCACHED) + fw_addr |= ROGUE_FW_SEGMMU_DATA_META_UNCACHED | + ROGUE_FW_SEGMMU_DATA_VIVT_SLC_UNCACHED; + + return fw_addr; +} + +static int +pvr_meta_vm_map(struct pvr_device *pvr_dev, struct pvr_fw_object *fw_obj) +{ + struct pvr_gem_object *pvr_obj = fw_obj->gem; + + return pvr_vm_map(pvr_dev->kernel_vm_ctx, pvr_obj, 0, fw_obj->fw_mm_node.start, + pvr_gem_object_size(pvr_obj)); +} + +static void +pvr_meta_vm_unmap(struct pvr_device *pvr_dev, struct pvr_fw_object *fw_obj) +{ + pvr_vm_unmap(pvr_dev->kernel_vm_ctx, fw_obj->fw_mm_node.start, + fw_obj->fw_mm_node.size); +} + +static bool +pvr_meta_has_fixed_data_addr(void) +{ + return false; +} + +const struct pvr_fw_defs pvr_fw_defs_meta = { + .init = pvr_meta_init, + .fw_process = pvr_meta_fw_process, + .vm_map = pvr_meta_vm_map, + .vm_unmap = pvr_meta_vm_unmap, + .get_fw_addr_with_offset = pvr_meta_get_fw_addr_with_offset, + .wrapper_init = pvr_meta_wrapper_init, + .has_fixed_data_addr = pvr_meta_has_fixed_data_addr, + .irq = { + .enable_reg = ROGUE_CR_META_SP_MSLVIRQENABLE, + .status_reg = ROGUE_CR_META_SP_MSLVIRQSTATUS, + .clear_reg = ROGUE_CR_META_SP_MSLVIRQSTATUS, + .event_mask = ROGUE_CR_META_SP_MSLVIRQSTATUS_TRIGVECT2_EN, + .clear_mask = ROGUE_CR_META_SP_MSLVIRQSTATUS_TRIGVECT2_CLRMSK, + }, +}; diff --git a/drivers/gpu/drm/imagination/pvr_fw_meta.h b/drivers/gpu/drm/imagination/pvr_fw_meta.h new file mode 100644 index 00000000000000..911ad700cba662 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_fw_meta.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_FW_META_H +#define PVR_FW_META_H + +#include + +/* Forward declaration from pvr_device.h */ +struct pvr_device; + +int pvr_meta_cr_read32(struct pvr_device *pvr_dev, u32 reg_addr, u32 *reg_value_out); + +#endif /* PVR_FW_META_H */ diff --git a/drivers/gpu/drm/imagination/pvr_fw_mips.c b/drivers/gpu/drm/imagination/pvr_fw_mips.c new file mode 100644 index 00000000000000..0bed0257e2ab75 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_fw_mips.c @@ -0,0 +1,252 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_device.h" +#include "pvr_fw.h" +#include "pvr_fw_mips.h" +#include "pvr_gem.h" +#include "pvr_rogue_mips.h" +#include "pvr_vm_mips.h" + +#include +#include +#include + +#define ROGUE_FW_HEAP_MIPS_BASE 0xC0000000 +#define ROGUE_FW_HEAP_MIPS_SHIFT 24 /* 16 MB */ +#define ROGUE_FW_HEAP_MIPS_RESERVED_SIZE SZ_1M + +/** + * process_elf_command_stream() - Process ELF firmware image and populate + * firmware sections + * @pvr_dev: Device pointer. + * @fw: Pointer to firmware image. + * @fw_code_ptr: Pointer to FW code section. + * @fw_data_ptr: Pointer to FW data section. + * @fw_core_code_ptr: Pointer to FW coremem code section. + * @fw_core_data_ptr: Pointer to FW coremem data section. + * + * Returns : + * * 0 on success, or + * * -EINVAL on any error in ELF command stream. + */ +static int +process_elf_command_stream(struct pvr_device *pvr_dev, const u8 *fw, u8 *fw_code_ptr, + u8 *fw_data_ptr, u8 *fw_core_code_ptr, u8 *fw_core_data_ptr) +{ + struct elf32_hdr *header = (struct elf32_hdr *)fw; + struct elf32_phdr *program_header = (struct elf32_phdr *)(fw + header->e_phoff); + struct drm_device *drm_dev = from_pvr_device(pvr_dev); + u32 entry; + int err; + + for (entry = 0; entry < header->e_phnum; entry++, program_header++) { + void *write_addr; + + /* Only consider loadable entries in the ELF segment table */ + if (program_header->p_type != PT_LOAD) + continue; + + err = pvr_fw_find_mmu_segment(pvr_dev, program_header->p_vaddr, + program_header->p_memsz, fw_code_ptr, fw_data_ptr, + fw_core_code_ptr, fw_core_data_ptr, &write_addr); + if (err) { + drm_err(drm_dev, + "Addr 0x%x (size: %d) not found in any firmware segment", + program_header->p_vaddr, program_header->p_memsz); + return err; + } + + /* Write to FW allocation only if available */ + if (write_addr) { + memcpy(write_addr, fw + program_header->p_offset, + program_header->p_filesz); + + memset((u8 *)write_addr + program_header->p_filesz, 0, + program_header->p_memsz - program_header->p_filesz); + } + } + + return 0; +} + +static int +pvr_mips_init(struct pvr_device *pvr_dev) +{ + pvr_fw_heap_info_init(pvr_dev, ROGUE_FW_HEAP_MIPS_SHIFT, ROGUE_FW_HEAP_MIPS_RESERVED_SIZE); + + return pvr_vm_mips_init(pvr_dev); +} + +static void +pvr_mips_fini(struct pvr_device *pvr_dev) +{ + pvr_vm_mips_fini(pvr_dev); +} + +static int +pvr_mips_fw_process(struct pvr_device *pvr_dev, const u8 *fw, + u8 *fw_code_ptr, u8 *fw_data_ptr, u8 *fw_core_code_ptr, u8 *fw_core_data_ptr, + u32 core_code_alloc_size) +{ + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + struct pvr_fw_mips_data *mips_data = fw_dev->processor_data.mips_data; + const struct pvr_fw_layout_entry *boot_code_entry; + const struct pvr_fw_layout_entry *boot_data_entry; + const struct pvr_fw_layout_entry *exception_code_entry; + const struct pvr_fw_layout_entry *stack_entry; + struct rogue_mipsfw_boot_data *boot_data; + dma_addr_t dma_addr; + u32 page_nr; + int err; + + err = process_elf_command_stream(pvr_dev, fw, fw_code_ptr, fw_data_ptr, fw_core_code_ptr, + fw_core_data_ptr); + if (err) + return err; + + boot_code_entry = pvr_fw_find_layout_entry(pvr_dev, MIPS_BOOT_CODE); + boot_data_entry = pvr_fw_find_layout_entry(pvr_dev, MIPS_BOOT_DATA); + exception_code_entry = pvr_fw_find_layout_entry(pvr_dev, MIPS_EXCEPTIONS_CODE); + if (!boot_code_entry || !boot_data_entry || !exception_code_entry) + return -EINVAL; + + WARN_ON(pvr_gem_get_dma_addr(fw_dev->mem.code_obj->gem, boot_code_entry->alloc_offset, + &mips_data->boot_code_dma_addr)); + WARN_ON(pvr_gem_get_dma_addr(fw_dev->mem.data_obj->gem, boot_data_entry->alloc_offset, + &mips_data->boot_data_dma_addr)); + WARN_ON(pvr_gem_get_dma_addr(fw_dev->mem.code_obj->gem, + exception_code_entry->alloc_offset, + &mips_data->exception_code_dma_addr)); + + stack_entry = pvr_fw_find_layout_entry(pvr_dev, MIPS_STACK); + if (!stack_entry) + return -EINVAL; + + boot_data = (struct rogue_mipsfw_boot_data *)(fw_data_ptr + boot_data_entry->alloc_offset + + ROGUE_MIPSFW_BOOTLDR_CONF_OFFSET); + + WARN_ON(pvr_fw_object_get_dma_addr(fw_dev->mem.data_obj, stack_entry->alloc_offset, + &dma_addr)); + boot_data->stack_phys_addr = dma_addr; + + boot_data->reg_base = pvr_dev->regs_resource->start; + + for (page_nr = 0; page_nr < ARRAY_SIZE(boot_data->pt_phys_addr); page_nr++) { + /* Firmware expects 4k pages, but host page size might be different. */ + u32 src_page_nr = (page_nr * ROGUE_MIPSFW_PAGE_SIZE_4K) >> PAGE_SHIFT; + u32 page_offset = (page_nr * ROGUE_MIPSFW_PAGE_SIZE_4K) & ~PAGE_MASK; + + boot_data->pt_phys_addr[page_nr] = mips_data->pt_dma_addr[src_page_nr] + + page_offset; + } + + boot_data->pt_log2_page_size = ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K; + boot_data->pt_num_pages = ROGUE_MIPSFW_MAX_NUM_PAGETABLE_PAGES; + boot_data->reserved1 = 0; + boot_data->reserved2 = 0; + + return 0; +} + +static int +pvr_mips_wrapper_init(struct pvr_device *pvr_dev) +{ + struct pvr_fw_mips_data *mips_data = pvr_dev->fw_dev.processor_data.mips_data; + const u64 remap_settings = ROGUE_MIPSFW_BOOT_REMAP_LOG2_SEGMENT_SIZE; + u32 phys_bus_width; + + int err = PVR_FEATURE_VALUE(pvr_dev, phys_bus_width, &phys_bus_width); + + if (WARN_ON(err)) + return err; + + /* Currently MIPS FW only supported with physical bus width > 32 bits. */ + if (WARN_ON(phys_bus_width <= 32)) + return -EINVAL; + + pvr_cr_write32(pvr_dev, ROGUE_CR_MIPS_WRAPPER_CONFIG, + (ROGUE_MIPSFW_REGISTERS_VIRTUAL_BASE >> + ROGUE_MIPSFW_WRAPPER_CONFIG_REGBANK_ADDR_ALIGN) | + ROGUE_CR_MIPS_WRAPPER_CONFIG_BOOT_ISA_MODE_MICROMIPS); + + /* Configure remap for boot code, boot data and exceptions code areas. */ + pvr_cr_write64(pvr_dev, ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG1, + ROGUE_MIPSFW_BOOT_REMAP_PHYS_ADDR_IN | + ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG1_MODE_ENABLE_EN); + pvr_cr_write64(pvr_dev, ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG2, + (mips_data->boot_code_dma_addr & + ~ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG2_ADDR_OUT_CLRMSK) | remap_settings); + + if (PVR_HAS_QUIRK(pvr_dev, 63553)) { + /* + * WA always required on 36 bit cores, to avoid continuous unmapped memory accesses + * to address 0x0. + */ + WARN_ON(phys_bus_width != 36); + + pvr_cr_write64(pvr_dev, ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG1, + ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG1_MODE_ENABLE_EN); + pvr_cr_write64(pvr_dev, ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG2, + (mips_data->boot_code_dma_addr & + ~ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG2_ADDR_OUT_CLRMSK) | + remap_settings); + } + + pvr_cr_write64(pvr_dev, ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG1, + ROGUE_MIPSFW_DATA_REMAP_PHYS_ADDR_IN | + ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG1_MODE_ENABLE_EN); + pvr_cr_write64(pvr_dev, ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG2, + (mips_data->boot_data_dma_addr & + ~ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG2_ADDR_OUT_CLRMSK) | remap_settings); + + pvr_cr_write64(pvr_dev, ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG1, + ROGUE_MIPSFW_CODE_REMAP_PHYS_ADDR_IN | + ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG1_MODE_ENABLE_EN); + pvr_cr_write64(pvr_dev, ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG2, + (mips_data->exception_code_dma_addr & + ~ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG2_ADDR_OUT_CLRMSK) | remap_settings); + + /* Garten IDLE bit controlled by MIPS. */ + pvr_cr_write64(pvr_dev, ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG, + ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_IDLE_CTRL_META); + + /* Turn on the EJTAG probe. */ + pvr_cr_write32(pvr_dev, ROGUE_CR_MIPS_DEBUG_CONFIG, 0); + + return 0; +} + +static u32 +pvr_mips_get_fw_addr_with_offset(struct pvr_fw_object *fw_obj, u32 offset) +{ + struct pvr_device *pvr_dev = to_pvr_device(gem_from_pvr_gem(fw_obj->gem)->dev); + + /* MIPS cacheability is determined by page table. */ + return ((fw_obj->fw_addr_offset + offset) & pvr_dev->fw_dev.fw_heap_info.offset_mask) | + ROGUE_FW_HEAP_MIPS_BASE; +} + +static bool +pvr_mips_has_fixed_data_addr(void) +{ + return true; +} + +const struct pvr_fw_defs pvr_fw_defs_mips = { + .init = pvr_mips_init, + .fini = pvr_mips_fini, + .fw_process = pvr_mips_fw_process, + .vm_map = pvr_vm_mips_map, + .vm_unmap = pvr_vm_mips_unmap, + .get_fw_addr_with_offset = pvr_mips_get_fw_addr_with_offset, + .wrapper_init = pvr_mips_wrapper_init, + .has_fixed_data_addr = pvr_mips_has_fixed_data_addr, + .irq = { + .enable_reg = ROGUE_CR_MIPS_WRAPPER_IRQ_ENABLE, + .status_reg = ROGUE_CR_MIPS_WRAPPER_IRQ_STATUS, + .clear_reg = ROGUE_CR_MIPS_WRAPPER_IRQ_CLEAR, + .event_mask = ROGUE_CR_MIPS_WRAPPER_IRQ_STATUS_EVENT_EN, + .clear_mask = ROGUE_CR_MIPS_WRAPPER_IRQ_CLEAR_EVENT_EN, + }, +}; diff --git a/drivers/gpu/drm/imagination/pvr_fw_mips.h b/drivers/gpu/drm/imagination/pvr_fw_mips.h new file mode 100644 index 00000000000000..408dbe63a90cfd --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_fw_mips.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_FW_MIPS_H +#define PVR_FW_MIPS_H + +#include "pvr_rogue_mips.h" + +#include +#include + +/* Forward declaration from pvr_gem.h. */ +struct pvr_gem_object; + +#define PVR_MIPS_PT_PAGE_COUNT ((ROGUE_MIPSFW_MAX_NUM_PAGETABLE_PAGES * ROGUE_MIPSFW_PAGE_SIZE_4K) \ + >> PAGE_SHIFT) +/** + * struct pvr_fw_mips_data - MIPS-specific data + */ +struct pvr_fw_mips_data { + /** + * @pt_pages: Pages containing MIPS pagetable. + */ + struct page *pt_pages[PVR_MIPS_PT_PAGE_COUNT]; + + /** @pt: Pointer to CPU mapping of MIPS pagetable. */ + u32 *pt; + + /** @pt_dma_addr: DMA mappings of MIPS pagetable. */ + dma_addr_t pt_dma_addr[PVR_MIPS_PT_PAGE_COUNT]; + + /** @boot_code_dma_addr: DMA address of MIPS boot code. */ + dma_addr_t boot_code_dma_addr; + + /** @boot_data_dma_addr: DMA address of MIPS boot data. */ + dma_addr_t boot_data_dma_addr; + + /** @exception_code_dma_addr: DMA address of MIPS exception code. */ + dma_addr_t exception_code_dma_addr; + + /** @cache_policy: Cache policy for this processor. */ + u32 cache_policy; + + /** @pfn_mask: PFN mask for MIPS pagetable. */ + u32 pfn_mask; +}; + +#endif /* PVR_FW_MIPS_H */ diff --git a/drivers/gpu/drm/imagination/pvr_fw_startstop.c b/drivers/gpu/drm/imagination/pvr_fw_startstop.c new file mode 100644 index 00000000000000..36cec227cfe3cf --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_fw_startstop.c @@ -0,0 +1,306 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_device.h" +#include "pvr_fw.h" +#include "pvr_fw_meta.h" +#include "pvr_fw_startstop.h" +#include "pvr_rogue_cr_defs.h" +#include "pvr_rogue_meta.h" +#include "pvr_vm.h" + +#include +#include +#include +#include + +#define POLL_TIMEOUT_USEC 1000000 + +static void +rogue_axi_ace_list_init(struct pvr_device *pvr_dev) +{ + /* Setup AXI-ACE config. Set everything to outer cache. */ + u64 reg_val = + (3U << ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_AWDOMAIN_NON_SNOOPING_SHIFT) | + (3U << ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARDOMAIN_NON_SNOOPING_SHIFT) | + (2U << ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARDOMAIN_CACHE_MAINTENANCE_SHIFT) | + (2U << ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_AWDOMAIN_COHERENT_SHIFT) | + (2U << ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARDOMAIN_COHERENT_SHIFT) | + (2U << ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_AWCACHE_COHERENT_SHIFT) | + (2U << ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARCACHE_COHERENT_SHIFT) | + (2U << ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARCACHE_CACHE_MAINTENANCE_SHIFT); + + pvr_cr_write64(pvr_dev, ROGUE_CR_AXI_ACE_LITE_CONFIGURATION, reg_val); +} + +static void +rogue_bif_init(struct pvr_device *pvr_dev) +{ + dma_addr_t pc_dma_addr; + u64 pc_addr; + + /* Acquire the address of the Kernel Page Catalogue. */ + pc_dma_addr = pvr_vm_get_page_table_root_addr(pvr_dev->kernel_vm_ctx); + + /* Write the kernel catalogue base. */ + pc_addr = ((((u64)pc_dma_addr >> ROGUE_CR_BIF_CAT_BASE0_ADDR_ALIGNSHIFT) + << ROGUE_CR_BIF_CAT_BASE0_ADDR_SHIFT) & + ~ROGUE_CR_BIF_CAT_BASE0_ADDR_CLRMSK); + + pvr_cr_write64(pvr_dev, BIF_CAT_BASEX(MMU_CONTEXT_MAPPING_FWPRIV), + pc_addr); +} + +static int +rogue_slc_init(struct pvr_device *pvr_dev) +{ + u16 slc_cache_line_size_bits; + u32 reg_val; + int err; + + /* + * SLC Misc control. + * + * Note: This is a 64bit register and we set only the lower 32bits + * leaving the top 32bits (ROGUE_CR_SLC_CTRL_MISC_SCRAMBLE_BITS) + * unchanged from the HW default. + */ + reg_val = (pvr_cr_read32(pvr_dev, ROGUE_CR_SLC_CTRL_MISC) & + ROGUE_CR_SLC_CTRL_MISC_ENABLE_PSG_HAZARD_CHECK_EN) | + ROGUE_CR_SLC_CTRL_MISC_ADDR_DECODE_MODE_PVR_HASH1; + + err = PVR_FEATURE_VALUE(pvr_dev, slc_cache_line_size_bits, &slc_cache_line_size_bits); + if (err) + return err; + + /* Bypass burst combiner if SLC line size is smaller than 1024 bits. */ + if (slc_cache_line_size_bits < 1024) + reg_val |= ROGUE_CR_SLC_CTRL_MISC_BYPASS_BURST_COMBINER_EN; + + if (PVR_HAS_QUIRK(pvr_dev, 71242) && !PVR_HAS_FEATURE(pvr_dev, gpu_multicore_support)) + reg_val |= ROGUE_CR_SLC_CTRL_MISC_LAZYWB_OVERRIDE_EN; + + pvr_cr_write32(pvr_dev, ROGUE_CR_SLC_CTRL_MISC, reg_val); + + return 0; +} + +/** + * pvr_fw_start() - Start FW processor and boot firmware + * @pvr_dev: Target PowerVR device. + * + * Returns: + * * 0 on success, or + * * Any error returned by rogue_slc_init(). + */ +int +pvr_fw_start(struct pvr_device *pvr_dev) +{ + bool has_reset2 = PVR_HAS_FEATURE(pvr_dev, xe_tpu2); + u64 soft_reset_mask; + int err; + + if (PVR_HAS_FEATURE(pvr_dev, pbe2_in_xe)) + soft_reset_mask = ROGUE_CR_SOFT_RESET__PBE2_XE__MASKFULL; + else + soft_reset_mask = ROGUE_CR_SOFT_RESET_MASKFULL; + + if (PVR_HAS_FEATURE(pvr_dev, sys_bus_secure_reset)) { + /* + * Disable the default sys_bus_secure protection to perform + * minimal setup. + */ + pvr_cr_write32(pvr_dev, ROGUE_CR_SYS_BUS_SECURE, 0); + (void)pvr_cr_read32(pvr_dev, ROGUE_CR_SYS_BUS_SECURE); /* Fence write */ + } + + /* Set Rogue in soft-reset. */ + pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET, soft_reset_mask); + if (has_reset2) + pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET2, ROGUE_CR_SOFT_RESET2_MASKFULL); + + /* Read soft-reset to fence previous write in order to clear the SOCIF pipeline. */ + (void)pvr_cr_read64(pvr_dev, ROGUE_CR_SOFT_RESET); + if (has_reset2) + (void)pvr_cr_read64(pvr_dev, ROGUE_CR_SOFT_RESET2); + + /* Take Rascal and Dust out of reset. */ + pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET, + soft_reset_mask ^ ROGUE_CR_SOFT_RESET_RASCALDUSTS_EN); + if (has_reset2) + pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET2, 0); + + (void)pvr_cr_read64(pvr_dev, ROGUE_CR_SOFT_RESET); + if (has_reset2) + (void)pvr_cr_read64(pvr_dev, ROGUE_CR_SOFT_RESET2); + + /* Take everything out of reset but the FW processor. */ + pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET, ROGUE_CR_SOFT_RESET_GARTEN_EN); + if (has_reset2) + pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET2, 0); + + (void)pvr_cr_read64(pvr_dev, ROGUE_CR_SOFT_RESET); + if (has_reset2) + (void)pvr_cr_read64(pvr_dev, ROGUE_CR_SOFT_RESET2); + + err = rogue_slc_init(pvr_dev); + if (err) + goto err_reset; + + /* Initialise Firmware wrapper. */ + pvr_dev->fw_dev.defs->wrapper_init(pvr_dev); + + /* We must init the AXI-ACE interface before first BIF transaction. */ + rogue_axi_ace_list_init(pvr_dev); + + if (pvr_dev->fw_dev.processor_type != PVR_FW_PROCESSOR_TYPE_MIPS) { + /* Initialise BIF. */ + rogue_bif_init(pvr_dev); + } + + /* Need to wait for at least 16 cycles before taking the FW processor out of reset ... */ + udelay(3); + + pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET, 0x0); + (void)pvr_cr_read64(pvr_dev, ROGUE_CR_SOFT_RESET); + + /* ... and afterwards. */ + udelay(3); + + return 0; + +err_reset: + /* Put everything back into soft-reset. */ + pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET, soft_reset_mask); + + return err; +} + +/** + * pvr_fw_stop() - Stop FW processor + * @pvr_dev: Target PowerVR device. + * + * Returns: + * * 0 on success, or + * * Any error returned by pvr_cr_poll_reg32(). + */ +int +pvr_fw_stop(struct pvr_device *pvr_dev) +{ + const u32 sidekick_idle_mask = ROGUE_CR_SIDEKICK_IDLE_MASKFULL & + ~(ROGUE_CR_SIDEKICK_IDLE_GARTEN_EN | + ROGUE_CR_SIDEKICK_IDLE_SOCIF_EN | + ROGUE_CR_SIDEKICK_IDLE_HOSTIF_EN); + bool skip_garten_idle = false; + u32 reg_value; + int err; + + /* + * Wait for Sidekick/Jones to signal IDLE except for the Garten Wrapper. + * For cores with the LAYOUT_MARS feature, SIDEKICK would have been + * powered down by the FW. + */ + err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_SIDEKICK_IDLE, sidekick_idle_mask, + sidekick_idle_mask, POLL_TIMEOUT_USEC); + if (err) + return err; + + /* Unset MTS DM association with threads. */ + pvr_cr_write32(pvr_dev, ROGUE_CR_MTS_INTCTX_THREAD0_DM_ASSOC, + ROGUE_CR_MTS_INTCTX_THREAD0_DM_ASSOC_MASKFULL & + ROGUE_CR_MTS_INTCTX_THREAD0_DM_ASSOC_DM_ASSOC_CLRMSK); + pvr_cr_write32(pvr_dev, ROGUE_CR_MTS_BGCTX_THREAD0_DM_ASSOC, + ROGUE_CR_MTS_BGCTX_THREAD0_DM_ASSOC_MASKFULL & + ROGUE_CR_MTS_BGCTX_THREAD0_DM_ASSOC_DM_ASSOC_CLRMSK); + pvr_cr_write32(pvr_dev, ROGUE_CR_MTS_INTCTX_THREAD1_DM_ASSOC, + ROGUE_CR_MTS_INTCTX_THREAD1_DM_ASSOC_MASKFULL & + ROGUE_CR_MTS_INTCTX_THREAD1_DM_ASSOC_DM_ASSOC_CLRMSK); + pvr_cr_write32(pvr_dev, ROGUE_CR_MTS_BGCTX_THREAD1_DM_ASSOC, + ROGUE_CR_MTS_BGCTX_THREAD1_DM_ASSOC_MASKFULL & + ROGUE_CR_MTS_BGCTX_THREAD1_DM_ASSOC_DM_ASSOC_CLRMSK); + + /* Extra Idle checks. */ + err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_BIF_STATUS_MMU, 0, + ROGUE_CR_BIF_STATUS_MMU_MASKFULL, + POLL_TIMEOUT_USEC); + if (err) + return err; + + err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_BIFPM_STATUS_MMU, 0, + ROGUE_CR_BIFPM_STATUS_MMU_MASKFULL, + POLL_TIMEOUT_USEC); + if (err) + return err; + + if (!PVR_HAS_FEATURE(pvr_dev, xt_top_infrastructure)) { + err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_BIF_READS_EXT_STATUS, 0, + ROGUE_CR_BIF_READS_EXT_STATUS_MASKFULL, + POLL_TIMEOUT_USEC); + if (err) + return err; + } + + err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_BIFPM_READS_EXT_STATUS, 0, + ROGUE_CR_BIFPM_READS_EXT_STATUS_MASKFULL, + POLL_TIMEOUT_USEC); + if (err) + return err; + + err = pvr_cr_poll_reg64(pvr_dev, ROGUE_CR_SLC_STATUS1, 0, + ROGUE_CR_SLC_STATUS1_MASKFULL, + POLL_TIMEOUT_USEC); + if (err) + return err; + + /* + * Wait for SLC to signal IDLE. + * For cores with the LAYOUT_MARS feature, SLC would have been powered + * down by the FW. + */ + err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_SLC_IDLE, + ROGUE_CR_SLC_IDLE_MASKFULL, + ROGUE_CR_SLC_IDLE_MASKFULL, POLL_TIMEOUT_USEC); + if (err) + return err; + + /* + * Wait for Sidekick/Jones to signal IDLE except for the Garten Wrapper. + * For cores with the LAYOUT_MARS feature, SIDEKICK would have been powered + * down by the FW. + */ + err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_SIDEKICK_IDLE, sidekick_idle_mask, + sidekick_idle_mask, POLL_TIMEOUT_USEC); + if (err) + return err; + + if (pvr_dev->fw_dev.processor_type == PVR_FW_PROCESSOR_TYPE_META) { + err = pvr_meta_cr_read32(pvr_dev, META_CR_TxVECINT_BHALT, ®_value); + if (err) + return err; + + /* + * Wait for Sidekick/Jones to signal IDLE including the Garten + * Wrapper if there is no debugger attached (TxVECINT_BHALT = + * 0x0). + */ + if (reg_value) + skip_garten_idle = true; + } + + if (!skip_garten_idle) { + err = pvr_cr_poll_reg32(pvr_dev, ROGUE_CR_SIDEKICK_IDLE, + ROGUE_CR_SIDEKICK_IDLE_GARTEN_EN, + ROGUE_CR_SIDEKICK_IDLE_GARTEN_EN, + POLL_TIMEOUT_USEC); + if (err) + return err; + } + + if (PVR_HAS_FEATURE(pvr_dev, pbe2_in_xe)) + pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET, + ROGUE_CR_SOFT_RESET__PBE2_XE__MASKFULL); + else + pvr_cr_write64(pvr_dev, ROGUE_CR_SOFT_RESET, ROGUE_CR_SOFT_RESET_MASKFULL); + + return 0; +} diff --git a/drivers/gpu/drm/imagination/pvr_fw_startstop.h b/drivers/gpu/drm/imagination/pvr_fw_startstop.h new file mode 100644 index 00000000000000..a3cef061bd601f --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_fw_startstop.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_FW_STARTSTOP_H +#define PVR_FW_STARTSTOP_H + +/* Forward declaration from pvr_device.h. */ +struct pvr_device; + +int pvr_fw_start(struct pvr_device *pvr_dev); +int pvr_fw_stop(struct pvr_device *pvr_dev); + +#endif /* PVR_FW_STARTSTOP_H */ diff --git a/drivers/gpu/drm/imagination/pvr_fw_trace.c b/drivers/gpu/drm/imagination/pvr_fw_trace.c new file mode 100644 index 00000000000000..31199e45b72ead --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_fw_trace.c @@ -0,0 +1,471 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_device.h" +#include "pvr_gem.h" +#include "pvr_rogue_fwif.h" +#include "pvr_rogue_fwif_sf.h" +#include "pvr_fw_trace.h" + +#include +#include + +#include +#include +#include +#include + +static void +tracebuf_ctrl_init(void *cpu_ptr, void *priv) +{ + struct rogue_fwif_tracebuf *tracebuf_ctrl = cpu_ptr; + struct pvr_fw_trace *fw_trace = priv; + u32 thread_nr; + + tracebuf_ctrl->tracebuf_size_in_dwords = ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS; + tracebuf_ctrl->tracebuf_flags = 0; + + if (fw_trace->group_mask) + tracebuf_ctrl->log_type = fw_trace->group_mask | ROGUE_FWIF_LOG_TYPE_TRACE; + else + tracebuf_ctrl->log_type = ROGUE_FWIF_LOG_TYPE_NONE; + + for (thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); thread_nr++) { + struct rogue_fwif_tracebuf_space *tracebuf_space = + &tracebuf_ctrl->tracebuf[thread_nr]; + struct pvr_fw_trace_buffer *trace_buffer = &fw_trace->buffers[thread_nr]; + + pvr_fw_object_get_fw_addr(trace_buffer->buf_obj, + &tracebuf_space->trace_buffer_fw_addr); + + tracebuf_space->trace_buffer = trace_buffer->buf; + tracebuf_space->trace_pointer = 0; + } +} + +int pvr_fw_trace_init(struct pvr_device *pvr_dev) +{ + struct pvr_fw_trace *fw_trace = &pvr_dev->fw_dev.fw_trace; + struct drm_device *drm_dev = from_pvr_device(pvr_dev); + u32 thread_nr; + int err; + + for (thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); thread_nr++) { + struct pvr_fw_trace_buffer *trace_buffer = &fw_trace->buffers[thread_nr]; + + trace_buffer->buf = + pvr_fw_object_create_and_map(pvr_dev, + ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS * + sizeof(*trace_buffer->buf), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED | + PVR_BO_FW_NO_CLEAR_ON_RESET, + NULL, NULL, &trace_buffer->buf_obj); + if (IS_ERR(trace_buffer->buf)) { + drm_err(drm_dev, "Unable to allocate trace buffer\n"); + err = PTR_ERR(trace_buffer->buf); + trace_buffer->buf = NULL; + goto err_free_buf; + } + } + + /* TODO: Provide control of group mask. */ + fw_trace->group_mask = 0; + + fw_trace->tracebuf_ctrl = + pvr_fw_object_create_and_map(pvr_dev, + sizeof(*fw_trace->tracebuf_ctrl), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED | + PVR_BO_FW_NO_CLEAR_ON_RESET, + tracebuf_ctrl_init, fw_trace, + &fw_trace->tracebuf_ctrl_obj); + if (IS_ERR(fw_trace->tracebuf_ctrl)) { + drm_err(drm_dev, "Unable to allocate trace buffer control structure\n"); + err = PTR_ERR(fw_trace->tracebuf_ctrl); + goto err_free_buf; + } + + BUILD_BUG_ON(ARRAY_SIZE(fw_trace->tracebuf_ctrl->tracebuf) != + ARRAY_SIZE(fw_trace->buffers)); + + for (thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); thread_nr++) { + struct rogue_fwif_tracebuf_space *tracebuf_space = + &fw_trace->tracebuf_ctrl->tracebuf[thread_nr]; + struct pvr_fw_trace_buffer *trace_buffer = &fw_trace->buffers[thread_nr]; + + trace_buffer->tracebuf_space = tracebuf_space; + } + + return 0; + +err_free_buf: + for (thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); thread_nr++) { + struct pvr_fw_trace_buffer *trace_buffer = &fw_trace->buffers[thread_nr]; + + if (trace_buffer->buf) + pvr_fw_object_unmap_and_destroy(trace_buffer->buf_obj); + } + + return err; +} + +void pvr_fw_trace_fini(struct pvr_device *pvr_dev) +{ + struct pvr_fw_trace *fw_trace = &pvr_dev->fw_dev.fw_trace; + u32 thread_nr; + + for (thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); thread_nr++) { + struct pvr_fw_trace_buffer *trace_buffer = &fw_trace->buffers[thread_nr]; + + pvr_fw_object_unmap_and_destroy(trace_buffer->buf_obj); + } + pvr_fw_object_unmap_and_destroy(fw_trace->tracebuf_ctrl_obj); +} + +#if defined(CONFIG_DEBUG_FS) + +/** + * update_logtype() - Send KCCB command to trigger FW to update logtype + * @pvr_dev: Target PowerVR device + * @group_mask: New log group mask. + * + * Returns: + * * 0 on success, + * * Any error returned by pvr_kccb_send_cmd(), or + * * -%EIO if the device is lost. + */ +static int +update_logtype(struct pvr_device *pvr_dev, u32 group_mask) +{ + struct pvr_fw_trace *fw_trace = &pvr_dev->fw_dev.fw_trace; + struct rogue_fwif_kccb_cmd cmd; + int idx; + int err; + + if (group_mask) + fw_trace->tracebuf_ctrl->log_type = ROGUE_FWIF_LOG_TYPE_TRACE | group_mask; + else + fw_trace->tracebuf_ctrl->log_type = ROGUE_FWIF_LOG_TYPE_NONE; + + fw_trace->group_mask = group_mask; + + down_read(&pvr_dev->reset_sem); + if (!drm_dev_enter(from_pvr_device(pvr_dev), &idx)) { + err = -EIO; + goto err_up_read; + } + + cmd.cmd_type = ROGUE_FWIF_KCCB_CMD_LOGTYPE_UPDATE; + cmd.kccb_flags = 0; + + err = pvr_kccb_send_cmd(pvr_dev, &cmd, NULL); + + drm_dev_exit(idx); + +err_up_read: + up_read(&pvr_dev->reset_sem); + + return err; +} + +struct pvr_fw_trace_seq_data { + /** @buffer: Pointer to copy of trace data. */ + u32 *buffer; + + /** @start_offset: Starting offset in trace data, as reported by FW. */ + u32 start_offset; + + /** @idx: Current index into trace data. */ + u32 idx; + + /** @assert_buf: Trace assert buffer, as reported by FW. */ + struct rogue_fwif_file_info_buf assert_buf; +}; + +static u32 find_sfid(u32 id) +{ + u32 i; + + for (i = 0; i < ARRAY_SIZE(stid_fmts); i++) { + if (stid_fmts[i].id == id) + return i; + } + + return ROGUE_FW_SF_LAST; +} + +static u32 read_fw_trace(struct pvr_fw_trace_seq_data *trace_seq_data, u32 offset) +{ + u32 idx; + + idx = trace_seq_data->idx + offset; + if (idx >= ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS) + return 0; + + idx = (idx + trace_seq_data->start_offset) % ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS; + return trace_seq_data->buffer[idx]; +} + +/** + * fw_trace_get_next() - Advance trace index to next entry + * @trace_seq_data: Trace sequence data. + * + * Returns: + * * %true if trace index is now pointing to a valid entry, or + * * %false if trace index is pointing to an invalid entry, or has hit the end + * of the trace. + */ +static bool fw_trace_get_next(struct pvr_fw_trace_seq_data *trace_seq_data) +{ + u32 id, sf_id; + + while (trace_seq_data->idx < ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS) { + id = read_fw_trace(trace_seq_data, 0); + trace_seq_data->idx++; + if (!ROGUE_FW_LOG_VALIDID(id)) + continue; + if (id == ROGUE_FW_SF_MAIN_ASSERT_FAILED) { + /* Assertion failure marks the end of the trace. */ + return false; + } + + sf_id = find_sfid(id); + if (sf_id == ROGUE_FW_SF_FIRST) + continue; + if (sf_id == ROGUE_FW_SF_LAST) { + /* + * Could not match with an ID in the SF table, trace is + * most likely corrupt from this point. + */ + return false; + } + + /* Skip over the timestamp, and any parameters. */ + trace_seq_data->idx += 2 + ROGUE_FW_SF_PARAMNUM(id); + + /* Ensure index is now pointing to a valid trace entry. */ + id = read_fw_trace(trace_seq_data, 0); + if (!ROGUE_FW_LOG_VALIDID(id)) + continue; + + return true; + } + + /* Hit end of trace data. */ + return false; +} + +/** + * fw_trace_get_first() - Find first valid entry in trace + * @trace_seq_data: Trace sequence data. + * + * Skips over invalid (usually zero) and ROGUE_FW_SF_FIRST entries. + * + * If the trace has no valid entries, this function will exit with the trace + * index pointing to the end of the trace. trace_seq_show() will return an error + * in this state. + */ +static void fw_trace_get_first(struct pvr_fw_trace_seq_data *trace_seq_data) +{ + trace_seq_data->idx = 0; + + while (trace_seq_data->idx < ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS) { + u32 id = read_fw_trace(trace_seq_data, 0); + + if (ROGUE_FW_LOG_VALIDID(id)) { + u32 sf_id = find_sfid(id); + + if (sf_id != ROGUE_FW_SF_FIRST) + break; + } + trace_seq_data->idx++; + } +} + +static void *fw_trace_seq_start(struct seq_file *s, loff_t *pos) +{ + struct pvr_fw_trace_seq_data *trace_seq_data = s->private; + u32 i; + + /* Reset trace index, then advance to *pos. */ + fw_trace_get_first(trace_seq_data); + + for (i = 0; i < *pos; i++) { + if (!fw_trace_get_next(trace_seq_data)) + return NULL; + } + + return (trace_seq_data->idx < ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS) ? pos : NULL; +} + +static void *fw_trace_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + struct pvr_fw_trace_seq_data *trace_seq_data = s->private; + + (*pos)++; + if (!fw_trace_get_next(trace_seq_data)) + return NULL; + + return (trace_seq_data->idx < ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS) ? pos : NULL; +} + +static void fw_trace_seq_stop(struct seq_file *s, void *v) +{ +} + +static int fw_trace_seq_show(struct seq_file *s, void *v) +{ + struct pvr_fw_trace_seq_data *trace_seq_data = s->private; + u64 timestamp; + u32 id; + u32 sf_id; + + if (trace_seq_data->idx >= ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS) + return -EINVAL; + + id = read_fw_trace(trace_seq_data, 0); + /* Index is not pointing at a valid entry. */ + if (!ROGUE_FW_LOG_VALIDID(id)) + return -EINVAL; + + sf_id = find_sfid(id); + /* Index is not pointing at a valid entry. */ + if (sf_id == ROGUE_FW_SF_LAST) + return -EINVAL; + + timestamp = read_fw_trace(trace_seq_data, 1) | + ((u64)read_fw_trace(trace_seq_data, 2) << 32); + timestamp = (timestamp & ~ROGUE_FWT_TIMESTAMP_TIME_CLRMSK) >> + ROGUE_FWT_TIMESTAMP_TIME_SHIFT; + + seq_printf(s, "[%llu] : ", timestamp); + if (id == ROGUE_FW_SF_MAIN_ASSERT_FAILED) { + seq_printf(s, "ASSERTION %s failed at %s:%u", + trace_seq_data->assert_buf.info, + trace_seq_data->assert_buf.path, + trace_seq_data->assert_buf.line_num); + } else { + seq_printf(s, stid_fmts[sf_id].name, + read_fw_trace(trace_seq_data, 3), + read_fw_trace(trace_seq_data, 4), + read_fw_trace(trace_seq_data, 5), + read_fw_trace(trace_seq_data, 6), + read_fw_trace(trace_seq_data, 7), + read_fw_trace(trace_seq_data, 8), + read_fw_trace(trace_seq_data, 9), + read_fw_trace(trace_seq_data, 10), + read_fw_trace(trace_seq_data, 11), + read_fw_trace(trace_seq_data, 12), + read_fw_trace(trace_seq_data, 13), + read_fw_trace(trace_seq_data, 14), + read_fw_trace(trace_seq_data, 15), + read_fw_trace(trace_seq_data, 16), + read_fw_trace(trace_seq_data, 17), + read_fw_trace(trace_seq_data, 18), + read_fw_trace(trace_seq_data, 19), + read_fw_trace(trace_seq_data, 20), + read_fw_trace(trace_seq_data, 21), + read_fw_trace(trace_seq_data, 22)); + } + seq_puts(s, "\n"); + return 0; +} + +static const struct seq_operations pvr_fw_trace_seq_ops = { + .start = fw_trace_seq_start, + .next = fw_trace_seq_next, + .stop = fw_trace_seq_stop, + .show = fw_trace_seq_show +}; + +static int fw_trace_open(struct inode *inode, struct file *file) +{ + struct pvr_fw_trace_buffer *trace_buffer = inode->i_private; + struct rogue_fwif_tracebuf_space *tracebuf_space = + trace_buffer->tracebuf_space; + struct pvr_fw_trace_seq_data *trace_seq_data; + int err; + + trace_seq_data = kzalloc(sizeof(*trace_seq_data), GFP_KERNEL); + if (!trace_seq_data) + return -ENOMEM; + + trace_seq_data->buffer = kcalloc(ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS, + sizeof(*trace_seq_data->buffer), GFP_KERNEL); + if (!trace_seq_data->buffer) { + err = -ENOMEM; + goto err_free_data; + } + + /* + * Take a local copy of the trace buffer, as firmware may still be + * writing to it. This will exist as long as this file is open. + */ + memcpy(trace_seq_data->buffer, trace_buffer->buf, + ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS * sizeof(u32)); + trace_seq_data->start_offset = READ_ONCE(tracebuf_space->trace_pointer); + trace_seq_data->assert_buf = tracebuf_space->assert_buf; + fw_trace_get_first(trace_seq_data); + + err = seq_open(file, &pvr_fw_trace_seq_ops); + if (err) + goto err_free_buffer; + + ((struct seq_file *)file->private_data)->private = trace_seq_data; + + return 0; + +err_free_buffer: + kfree(trace_seq_data->buffer); + +err_free_data: + kfree(trace_seq_data); + + return err; +} + +static int fw_trace_release(struct inode *inode, struct file *file) +{ + struct pvr_fw_trace_seq_data *trace_seq_data = + ((struct seq_file *)file->private_data)->private; + + seq_release(inode, file); + kfree(trace_seq_data->buffer); + kfree(trace_seq_data); + + return 0; +} + +static const struct file_operations pvr_fw_trace_fops = { + .owner = THIS_MODULE, + .open = fw_trace_open, + .read = seq_read, + .llseek = seq_lseek, + .release = fw_trace_release, +}; + +void +pvr_fw_trace_mask_update(struct pvr_device *pvr_dev, u32 old_mask, u32 new_mask) +{ + if (old_mask != new_mask) + update_logtype(pvr_dev, new_mask); +} + +void +pvr_fw_trace_debugfs_init(struct pvr_device *pvr_dev, struct dentry *dir) +{ + struct pvr_fw_trace *fw_trace = &pvr_dev->fw_dev.fw_trace; + u32 thread_nr; + + static_assert(ARRAY_SIZE(fw_trace->buffers) <= 10, + "The filename buffer is only large enough for a single-digit thread count"); + + for (thread_nr = 0; thread_nr < ARRAY_SIZE(fw_trace->buffers); ++thread_nr) { + char filename[8]; + + snprintf(filename, ARRAY_SIZE(filename), "trace_%u", thread_nr); + debugfs_create_file(filename, 0400, dir, + &fw_trace->buffers[thread_nr], + &pvr_fw_trace_fops); + } +} +#endif diff --git a/drivers/gpu/drm/imagination/pvr_fw_trace.h b/drivers/gpu/drm/imagination/pvr_fw_trace.h new file mode 100644 index 00000000000000..0074d2b18da0b8 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_fw_trace.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_FW_TRACE_H +#define PVR_FW_TRACE_H + +#include +#include + +#include "pvr_rogue_fwif.h" + +/* Forward declaration from pvr_device.h. */ +struct pvr_device; + +/* Forward declaration from pvr_gem.h. */ +struct pvr_fw_object; + +/* Forward declarations from pvr_rogue_fwif.h */ +struct rogue_fwif_tracebuf; +struct rogue_fwif_tracebuf_space; + +/** + * struct pvr_fw_trace_buffer - Structure representing a trace buffer + */ +struct pvr_fw_trace_buffer { + /** @buf_obj: FW buffer object representing trace buffer. */ + struct pvr_fw_object *buf_obj; + + /** @buf: Pointer to CPU mapping of trace buffer. */ + u32 *buf; + + /** + * @tracebuf_space: Pointer to FW tracebuf_space structure for this + * trace buffer. + */ + struct rogue_fwif_tracebuf_space *tracebuf_space; +}; + +/** + * struct pvr_fw_trace - Device firmware trace data + */ +struct pvr_fw_trace { + /** + * @tracebuf_ctrl_obj: Object representing FW trace buffer control + * structure. + */ + struct pvr_fw_object *tracebuf_ctrl_obj; + + /** + * @tracebuf_ctrl: Pointer to CPU mapping of FW trace buffer control + * structure. + */ + struct rogue_fwif_tracebuf *tracebuf_ctrl; + + /** + * @buffers: Array representing the actual trace buffers owned by this + * device. + */ + struct pvr_fw_trace_buffer buffers[ROGUE_FW_THREAD_MAX]; + + /** @group_mask: Mask of enabled trace groups. */ + u32 group_mask; +}; + +int pvr_fw_trace_init(struct pvr_device *pvr_dev); +void pvr_fw_trace_fini(struct pvr_device *pvr_dev); + +#if defined(CONFIG_DEBUG_FS) +/* Forward declaration from . */ +struct dentry; + +void pvr_fw_trace_mask_update(struct pvr_device *pvr_dev, u32 old_mask, + u32 new_mask); + +void pvr_fw_trace_debugfs_init(struct pvr_device *pvr_dev, struct dentry *dir); +#endif /* defined(CONFIG_DEBUG_FS) */ + +#endif /* PVR_FW_TRACE_H */ diff --git a/drivers/gpu/drm/imagination/pvr_gem.c b/drivers/gpu/drm/imagination/pvr_gem.c new file mode 100644 index 00000000000000..6a8c81fe8c1e85 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_gem.c @@ -0,0 +1,414 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_device.h" +#include "pvr_gem.h" +#include "pvr_vm.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void pvr_gem_object_free(struct drm_gem_object *obj) +{ + drm_gem_shmem_object_free(obj); +} + +static int pvr_gem_mmap(struct drm_gem_object *gem_obj, struct vm_area_struct *vma) +{ + struct pvr_gem_object *pvr_obj = gem_to_pvr_gem(gem_obj); + struct drm_gem_shmem_object *shmem_obj = shmem_gem_from_pvr_gem(pvr_obj); + + if (!(pvr_obj->flags & DRM_PVR_BO_ALLOW_CPU_USERSPACE_ACCESS)) + return -EINVAL; + + return drm_gem_shmem_mmap(shmem_obj, vma); +} + +static const struct drm_gem_object_funcs pvr_gem_object_funcs = { + .free = pvr_gem_object_free, + .print_info = drm_gem_shmem_object_print_info, + .pin = drm_gem_shmem_object_pin, + .unpin = drm_gem_shmem_object_unpin, + .get_sg_table = drm_gem_shmem_object_get_sg_table, + .vmap = drm_gem_shmem_object_vmap, + .vunmap = drm_gem_shmem_object_vunmap, + .mmap = pvr_gem_mmap, + .vm_ops = &drm_gem_shmem_vm_ops, +}; + +/** + * pvr_gem_object_flags_validate() - Verify that a collection of PowerVR GEM + * mapping and/or creation flags form a valid combination. + * @flags: PowerVR GEM mapping/creation flags to validate. + * + * This function explicitly allows kernel-only flags. All ioctl entrypoints + * should do their own validation as well as relying on this function. + * + * Return: + * * %true if @flags contains valid mapping and/or creation flags, or + * * %false otherwise. + */ +static bool +pvr_gem_object_flags_validate(u64 flags) +{ + static const u64 invalid_combinations[] = { + /* + * Memory flagged as PM/FW-protected cannot be mapped to + * userspace. To make this explicit, we require that the two + * flags allowing each of these respective features are never + * specified together. + */ + (DRM_PVR_BO_PM_FW_PROTECT | + DRM_PVR_BO_ALLOW_CPU_USERSPACE_ACCESS), + }; + + int i; + + /* + * Check for bits set in undefined regions. Reserved regions refer to + * options that can only be set by the kernel. These are explicitly + * allowed in most cases, and must be checked specifically in IOCTL + * callback code. + */ + if ((flags & PVR_BO_UNDEFINED_MASK) != 0) + return false; + + /* + * Check for all combinations of flags marked as invalid in the array + * above. + */ + for (i = 0; i < ARRAY_SIZE(invalid_combinations); ++i) { + u64 combo = invalid_combinations[i]; + + if ((flags & combo) == combo) + return false; + } + + return true; +} + +/** + * pvr_gem_object_into_handle() - Convert a reference to an object into a + * userspace-accessible handle. + * @pvr_obj: [IN] Target PowerVR-specific object. + * @pvr_file: [IN] File to associate the handle with. + * @handle: [OUT] Pointer to store the created handle in. Remains unmodified if + * an error is encountered. + * + * If an error is encountered, ownership of @pvr_obj will not have been + * transferred. If this function succeeds, however, further use of @pvr_obj is + * considered undefined behaviour unless another reference to it is explicitly + * held. + * + * Return: + * * 0 on success, or + * * Any error encountered while attempting to allocate a handle on @pvr_file. + */ +int +pvr_gem_object_into_handle(struct pvr_gem_object *pvr_obj, + struct pvr_file *pvr_file, u32 *handle) +{ + struct drm_gem_object *gem_obj = gem_from_pvr_gem(pvr_obj); + struct drm_file *file = from_pvr_file(pvr_file); + + u32 new_handle; + int err; + + err = drm_gem_handle_create(file, gem_obj, &new_handle); + if (err) + return err; + + /* + * Release our reference to @pvr_obj, effectively transferring + * ownership to the handle. + */ + pvr_gem_object_put(pvr_obj); + + /* + * Do not store the new handle in @handle until no more errors can + * occur. + */ + *handle = new_handle; + + return 0; +} + +/** + * pvr_gem_object_from_handle() - Obtain a reference to an object from a + * userspace handle. + * @pvr_file: PowerVR-specific file to which @handle is associated. + * @handle: Userspace handle referencing the target object. + * + * On return, @handle always maintains its reference to the requested object + * (if it had one in the first place). If this function succeeds, the returned + * object will hold an additional reference. When the caller is finished with + * the returned object, they should call pvr_gem_object_put() on it to release + * this reference. + * + * Return: + * * A pointer to the requested PowerVR-specific object on success, or + * * %NULL otherwise. + */ +struct pvr_gem_object * +pvr_gem_object_from_handle(struct pvr_file *pvr_file, u32 handle) +{ + struct drm_file *file = from_pvr_file(pvr_file); + struct drm_gem_object *gem_obj; + + gem_obj = drm_gem_object_lookup(file, handle); + if (!gem_obj) + return NULL; + + return gem_to_pvr_gem(gem_obj); +} + +/** + * pvr_gem_object_vmap() - Map a PowerVR GEM object into CPU virtual address + * space. + * @pvr_obj: Target PowerVR GEM object. + * + * Once the caller is finished with the CPU mapping, they must call + * pvr_gem_object_vunmap() on @pvr_obj. + * + * If @pvr_obj is CPU-cached, dma_sync_sgtable_for_cpu() is called to make + * sure the CPU mapping is consistent. + * + * Return: + * * A pointer to the CPU mapping on success, + * * -%ENOMEM if the mapping fails, or + * * Any error encountered while attempting to acquire a reference to the + * backing pages for @pvr_obj. + */ +void * +pvr_gem_object_vmap(struct pvr_gem_object *pvr_obj) +{ + struct drm_gem_shmem_object *shmem_obj = shmem_gem_from_pvr_gem(pvr_obj); + struct drm_gem_object *obj = gem_from_pvr_gem(pvr_obj); + struct iosys_map map; + int err; + + dma_resv_lock(obj->resv, NULL); + + err = drm_gem_shmem_vmap(shmem_obj, &map); + if (err) + goto err_unlock; + + if (pvr_obj->flags & PVR_BO_CPU_CACHED) { + struct device *dev = shmem_obj->base.dev->dev; + + /* If shmem_obj->sgt is NULL, that means the buffer hasn't been mapped + * in GPU space yet. + */ + if (shmem_obj->sgt) + dma_sync_sgtable_for_cpu(dev, shmem_obj->sgt, DMA_BIDIRECTIONAL); + } + + dma_resv_unlock(obj->resv); + + return map.vaddr; + +err_unlock: + dma_resv_unlock(obj->resv); + + return ERR_PTR(err); +} + +/** + * pvr_gem_object_vunmap() - Unmap a PowerVR memory object from CPU virtual + * address space. + * @pvr_obj: Target PowerVR GEM object. + * + * If @pvr_obj is CPU-cached, dma_sync_sgtable_for_device() is called to make + * sure the GPU mapping is consistent. + */ +void +pvr_gem_object_vunmap(struct pvr_gem_object *pvr_obj) +{ + struct drm_gem_shmem_object *shmem_obj = shmem_gem_from_pvr_gem(pvr_obj); + struct iosys_map map = IOSYS_MAP_INIT_VADDR(shmem_obj->vaddr); + struct drm_gem_object *obj = gem_from_pvr_gem(pvr_obj); + + if (WARN_ON(!map.vaddr)) + return; + + dma_resv_lock(obj->resv, NULL); + + if (pvr_obj->flags & PVR_BO_CPU_CACHED) { + struct device *dev = shmem_obj->base.dev->dev; + + /* If shmem_obj->sgt is NULL, that means the buffer hasn't been mapped + * in GPU space yet. + */ + if (shmem_obj->sgt) + dma_sync_sgtable_for_device(dev, shmem_obj->sgt, DMA_BIDIRECTIONAL); + } + + drm_gem_shmem_vunmap(shmem_obj, &map); + + dma_resv_unlock(obj->resv); +} + +/** + * pvr_gem_object_zero() - Zeroes the physical memory behind an object. + * @pvr_obj: Target PowerVR GEM object. + * + * Return: + * * 0 on success, or + * * Any error encountered while attempting to map @pvr_obj to the CPU (see + * pvr_gem_object_vmap()). + */ +static int +pvr_gem_object_zero(struct pvr_gem_object *pvr_obj) +{ + void *cpu_ptr; + + cpu_ptr = pvr_gem_object_vmap(pvr_obj); + if (IS_ERR(cpu_ptr)) + return PTR_ERR(cpu_ptr); + + memset(cpu_ptr, 0, pvr_gem_object_size(pvr_obj)); + + /* Make sure the zero-ing is done before vumap-ing the object. */ + wmb(); + + pvr_gem_object_vunmap(pvr_obj); + + return 0; +} + +/** + * pvr_gem_create_object() - Allocate and pre-initializes a pvr_gem_object + * @drm_dev: DRM device creating this object. + * @size: Size of the object to allocate in bytes. + * + * Return: + * * The new pre-initialized GEM object on success, + * * -ENOMEM if the allocation failed. + */ +struct drm_gem_object *pvr_gem_create_object(struct drm_device *drm_dev, size_t size) +{ + struct drm_gem_object *gem_obj; + struct pvr_gem_object *pvr_obj; + + pvr_obj = kzalloc(sizeof(*pvr_obj), GFP_KERNEL); + if (!pvr_obj) + return ERR_PTR(-ENOMEM); + + gem_obj = gem_from_pvr_gem(pvr_obj); + gem_obj->funcs = &pvr_gem_object_funcs; + + return gem_obj; +} + +/** + * pvr_gem_object_create() - Creates a PowerVR-specific buffer object. + * @pvr_dev: Target PowerVR device. + * @size: Size of the object to allocate in bytes. Must be greater than zero. + * Any value which is not an exact multiple of the system page size will be + * rounded up to satisfy this condition. + * @flags: Options which affect both this operation and future mapping + * operations performed on the returned object. Must be a combination of + * DRM_PVR_BO_* and/or PVR_BO_* flags. + * + * The created object may be larger than @size, but can never be smaller. To + * get the exact size, call pvr_gem_object_size() on the returned pointer. + * + * Return: + * * The newly-minted PowerVR-specific buffer object on success, + * * -%EINVAL if @size is zero or @flags is not valid, + * * -%ENOMEM if sufficient physical memory cannot be allocated, or + * * Any other error returned by drm_gem_create_mmap_offset(). + */ +struct pvr_gem_object * +pvr_gem_object_create(struct pvr_device *pvr_dev, size_t size, u64 flags) +{ + struct drm_gem_shmem_object *shmem_obj; + struct pvr_gem_object *pvr_obj; + struct sg_table *sgt; + int err; + + /* Verify @size and @flags before continuing. */ + if (size == 0 || !pvr_gem_object_flags_validate(flags)) + return ERR_PTR(-EINVAL); + + shmem_obj = drm_gem_shmem_create(from_pvr_device(pvr_dev), size); + if (IS_ERR(shmem_obj)) + return ERR_CAST(shmem_obj); + + shmem_obj->pages_mark_dirty_on_put = true; + shmem_obj->map_wc = !(flags & PVR_BO_CPU_CACHED); + pvr_obj = shmem_gem_to_pvr_gem(shmem_obj); + pvr_obj->flags = flags; + + sgt = drm_gem_shmem_get_pages_sgt(shmem_obj); + if (IS_ERR(sgt)) { + err = PTR_ERR(sgt); + goto err_shmem_object_free; + } + + dma_sync_sgtable_for_device(shmem_obj->base.dev->dev, sgt, + DMA_BIDIRECTIONAL); + + /* + * Do this last because pvr_gem_object_zero() requires a fully + * configured instance of struct pvr_gem_object. + */ + pvr_gem_object_zero(pvr_obj); + + return pvr_obj; + +err_shmem_object_free: + drm_gem_shmem_free(shmem_obj); + + return ERR_PTR(err); +} + +/** + * pvr_gem_get_dma_addr() - Get DMA address for given offset in object + * @pvr_obj: Pointer to object to lookup address in. + * @offset: Offset within object to lookup address at. + * @dma_addr_out: Pointer to location to store DMA address. + * + * Returns: + * * 0 on success, or + * * -%EINVAL if object is not currently backed, or if @offset is out of valid + * range for this object. + */ +int +pvr_gem_get_dma_addr(struct pvr_gem_object *pvr_obj, u32 offset, + dma_addr_t *dma_addr_out) +{ + struct drm_gem_shmem_object *shmem_obj = shmem_gem_from_pvr_gem(pvr_obj); + u32 accumulated_offset = 0; + struct scatterlist *sgl; + unsigned int sgt_idx; + + WARN_ON(!shmem_obj->sgt); + for_each_sgtable_dma_sg(shmem_obj->sgt, sgl, sgt_idx) { + u32 new_offset = accumulated_offset + sg_dma_len(sgl); + + if (offset >= accumulated_offset && offset < new_offset) { + *dma_addr_out = sg_dma_address(sgl) + + (offset - accumulated_offset); + return 0; + } + + accumulated_offset = new_offset; + } + + return -EINVAL; +} diff --git a/drivers/gpu/drm/imagination/pvr_gem.h b/drivers/gpu/drm/imagination/pvr_gem.h new file mode 100644 index 00000000000000..e0e5ea509a2e88 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_gem.h @@ -0,0 +1,170 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_GEM_H +#define PVR_GEM_H + +#include "pvr_rogue_heap_config.h" +#include "pvr_rogue_meta.h" + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Forward declaration from "pvr_device.h". */ +struct pvr_device; +struct pvr_file; + +/** + * DOC: Flags for DRM_IOCTL_PVR_CREATE_BO (kernel-only) + * + * Kernel-only values allowed in &pvr_gem_object->flags. The majority of options + * for this field are specified in the UAPI header "pvr_drm.h" with a + * DRM_PVR_BO_ prefix. To distinguish these internal options (which must exist + * in ranges marked as "reserved" in the UAPI header), we drop the DRM prefix. + * The public options should be used directly, DRM prefix and all. + * + * To avoid potentially confusing gaps in the UAPI options, these kernel-only + * options are specified "in reverse", starting at bit 63. + * + * We use "reserved" to refer to bits defined here and not exposed in the UAPI. + * Bits not defined anywhere are "undefined". + * + * CPU mapping options + * :PVR_BO_CPU_CACHED: By default, all GEM objects are mapped write-combined on the CPU. Set this + * flag to override this behaviour and map the object cached. + * + * Firmware options + * :PVR_BO_FW_NO_CLEAR_ON_RESET: By default, all FW objects are cleared and reinitialised on hard + * reset. Set this flag to override this behaviour and preserve buffer contents on reset. + */ +#define PVR_BO_CPU_CACHED BIT_ULL(63) + +#define PVR_BO_FW_NO_CLEAR_ON_RESET BIT_ULL(62) + +#define PVR_BO_KERNEL_FLAGS_MASK (PVR_BO_CPU_CACHED | PVR_BO_FW_NO_CLEAR_ON_RESET) + +/* Bits 61..3 are undefined. */ +/* Bits 2..0 are defined in the UAPI. */ + +/* Other utilities. */ +#define PVR_BO_UNDEFINED_MASK ~(PVR_BO_KERNEL_FLAGS_MASK | DRM_PVR_BO_FLAGS_MASK) + +/* + * All firmware-mapped memory uses (mostly) the same flags. Specifically, + * firmware-mapped memory should be: + * * Read/write on the device, + * * Read/write on the CPU, and + * * Write-combined on the CPU. + * + * The only variation is in caching on the device. + */ +#define PVR_BO_FW_FLAGS_DEVICE_CACHED (ULL(0)) +#define PVR_BO_FW_FLAGS_DEVICE_UNCACHED DRM_PVR_BO_BYPASS_DEVICE_CACHE + +/** + * struct pvr_gem_object - powervr-specific wrapper for &struct drm_gem_object + */ +struct pvr_gem_object { + /** + * @base: The underlying &struct drm_gem_shmem_object. + * + * Do not access this member directly, instead call + * shem_gem_from_pvr_gem(). + */ + struct drm_gem_shmem_object base; + + /** + * @flags: Options set at creation-time. Some of these options apply to + * the creation operation itself (which are stored here for reference) + * with the remainder used for mapping options to both the device and + * CPU. These are used every time this object is mapped, but may be + * changed after creation. + * + * Must be a combination of DRM_PVR_BO_* and/or PVR_BO_* flags. + * + * .. note:: + * + * This member is declared const to indicate that none of these + * options may change or be changed throughout the object's + * lifetime. + */ + u64 flags; + +}; + +static_assert(offsetof(struct pvr_gem_object, base) == 0, + "offsetof(struct pvr_gem_object, base) not zero"); + +#define shmem_gem_from_pvr_gem(pvr_obj) (&(pvr_obj)->base) + +#define shmem_gem_to_pvr_gem(shmem_obj) container_of_const(shmem_obj, struct pvr_gem_object, base) + +#define gem_from_pvr_gem(pvr_obj) (&(pvr_obj)->base.base) + +#define gem_to_pvr_gem(gem_obj) container_of_const(gem_obj, struct pvr_gem_object, base.base) + +/* Functions defined in pvr_gem.c */ + +struct drm_gem_object *pvr_gem_create_object(struct drm_device *drm_dev, size_t size); + +struct pvr_gem_object *pvr_gem_object_create(struct pvr_device *pvr_dev, + size_t size, u64 flags); + +int pvr_gem_object_into_handle(struct pvr_gem_object *pvr_obj, + struct pvr_file *pvr_file, u32 *handle); +struct pvr_gem_object *pvr_gem_object_from_handle(struct pvr_file *pvr_file, + u32 handle); + +static __always_inline struct sg_table * +pvr_gem_object_get_pages_sgt(struct pvr_gem_object *pvr_obj) +{ + return drm_gem_shmem_get_pages_sgt(shmem_gem_from_pvr_gem(pvr_obj)); +} + +void *pvr_gem_object_vmap(struct pvr_gem_object *pvr_obj); +void pvr_gem_object_vunmap(struct pvr_gem_object *pvr_obj); + +int pvr_gem_get_dma_addr(struct pvr_gem_object *pvr_obj, u32 offset, + dma_addr_t *dma_addr_out); + +/** + * pvr_gem_object_get() - Acquire reference on pvr_gem_object + * @pvr_obj: Pointer to object to acquire reference on. + */ +static __always_inline void +pvr_gem_object_get(struct pvr_gem_object *pvr_obj) +{ + drm_gem_object_get(gem_from_pvr_gem(pvr_obj)); +} + +/** + * pvr_gem_object_put() - Release reference on pvr_gem_object + * @pvr_obj: Pointer to object to release reference on. + */ +static __always_inline void +pvr_gem_object_put(struct pvr_gem_object *pvr_obj) +{ + drm_gem_object_put(gem_from_pvr_gem(pvr_obj)); +} + +static __always_inline size_t +pvr_gem_object_size(struct pvr_gem_object *pvr_obj) +{ + return gem_from_pvr_gem(pvr_obj)->size; +} + +#endif /* PVR_GEM_H */ diff --git a/drivers/gpu/drm/imagination/pvr_hwrt.c b/drivers/gpu/drm/imagination/pvr_hwrt.c new file mode 100644 index 00000000000000..54f88d6c01e565 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_hwrt.c @@ -0,0 +1,550 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_free_list.h" +#include "pvr_hwrt.h" +#include "pvr_gem.h" +#include "pvr_rogue_cr_defs_client.h" +#include "pvr_rogue_fwif.h" + +#include +#include +#include +#include +#include +#include + +static_assert(ROGUE_FWIF_NUM_RTDATAS == 2); +static_assert(ROGUE_FWIF_NUM_GEOMDATAS == 1); +static_assert(ROGUE_FWIF_NUM_RTDATA_FREELISTS == 2); + +/* + * struct pvr_rt_mtile_info - Render target macrotile information + */ +struct pvr_rt_mtile_info { + u32 mtile_x[3]; + u32 mtile_y[3]; + u32 tile_max_x; + u32 tile_max_y; + u32 tile_size_x; + u32 tile_size_y; + u32 num_tiles_x; + u32 num_tiles_y; +}; + +/* Size of Shadow Render Target Cache entry */ +#define SRTC_ENTRY_SIZE sizeof(u32) +/* Size of Renders Accumulation Array entry */ +#define RAA_ENTRY_SIZE sizeof(u32) + +static int +hwrt_init_kernel_structure(struct pvr_file *pvr_file, + struct drm_pvr_ioctl_create_hwrt_dataset_args *args, + struct pvr_hwrt_dataset *hwrt) +{ + struct pvr_device *pvr_dev = pvr_file->pvr_dev; + int err; + int i; + + hwrt->pvr_dev = pvr_dev; + hwrt->max_rts = args->layers; + + /* Get pointers to the free lists */ + for (i = 0; i < ARRAY_SIZE(hwrt->free_lists); i++) { + hwrt->free_lists[i] = pvr_free_list_lookup(pvr_file, args->free_list_handles[i]); + if (!hwrt->free_lists[i]) { + err = -EINVAL; + goto err_put_free_lists; + } + } + + if (hwrt->free_lists[ROGUE_FW_LOCAL_FREELIST]->current_pages < + pvr_get_free_list_min_pages(pvr_dev)) { + err = -EINVAL; + goto err_put_free_lists; + } + + return 0; + +err_put_free_lists: + for (i = 0; i < ARRAY_SIZE(hwrt->free_lists); i++) { + pvr_free_list_put(hwrt->free_lists[i]); + hwrt->free_lists[i] = NULL; + } + + return err; +} + +static void +hwrt_fini_kernel_structure(struct pvr_hwrt_dataset *hwrt) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(hwrt->free_lists); i++) { + pvr_free_list_put(hwrt->free_lists[i]); + hwrt->free_lists[i] = NULL; + } +} + +static void +hwrt_fini_common_fw_structure(struct pvr_hwrt_dataset *hwrt) +{ + pvr_fw_object_destroy(hwrt->common_fw_obj); +} + +static int +get_cr_isp_mtile_size_val(struct pvr_device *pvr_dev, u32 samples, + struct pvr_rt_mtile_info *info, u32 *value_out) +{ + u32 x = info->mtile_x[0]; + u32 y = info->mtile_y[0]; + u32 samples_per_pixel; + int err; + + err = PVR_FEATURE_VALUE(pvr_dev, isp_samples_per_pixel, &samples_per_pixel); + if (err) + return err; + + if (samples_per_pixel == 1) { + if (samples >= 4) + x <<= 1; + if (samples >= 2) + y <<= 1; + } else if (samples_per_pixel == 2) { + if (samples >= 8) + x <<= 1; + if (samples >= 4) + y <<= 1; + } else if (samples_per_pixel == 4) { + if (samples >= 8) + y <<= 1; + } else { + WARN(true, "Unsupported ISP samples per pixel value"); + return -EINVAL; + } + + *value_out = ((x << ROGUE_CR_ISP_MTILE_SIZE_X_SHIFT) & ~ROGUE_CR_ISP_MTILE_SIZE_X_CLRMSK) | + ((y << ROGUE_CR_ISP_MTILE_SIZE_Y_SHIFT) & ~ROGUE_CR_ISP_MTILE_SIZE_Y_CLRMSK); + + return 0; +} + +static int +get_cr_multisamplectl_val(u32 samples, bool y_flip, u64 *value_out) +{ + static const struct { + u8 x[8]; + u8 y[8]; + } sample_positions[4] = { + /* 1 sample */ + { + .x = { 8 }, + .y = { 8 }, + }, + /* 2 samples */ + { + .x = { 12, 4 }, + .y = { 12, 4 }, + }, + /* 4 samples */ + { + .x = { 6, 14, 2, 10 }, + .y = { 2, 6, 10, 14 }, + }, + /* 8 samples */ + { + .x = { 9, 7, 13, 5, 3, 1, 11, 15 }, + .y = { 5, 11, 9, 3, 13, 7, 15, 1 }, + }, + }; + const int idx = fls(samples) - 1; + u64 value = 0; + + if (idx < 0 || idx > 3) + return -EINVAL; + + for (u32 i = 0; i < 8; i++) { + value |= ((u64)sample_positions[idx].x[i]) << (i * 8); + if (y_flip) + value |= (((u64)(16 - sample_positions[idx].y[i]) & 0xf)) << (i * 8 + 4); + else + value |= ((u64)sample_positions[idx].y[i]) << (i * 8 + 4); + } + + *value_out = value; + + return 0; +} + +static int +get_cr_te_aa_val(struct pvr_device *pvr_dev, u32 samples, u32 *value_out) +{ + u32 samples_per_pixel; + u32 value = 0; + int err = 0; + + err = PVR_FEATURE_VALUE(pvr_dev, isp_samples_per_pixel, &samples_per_pixel); + if (err) + return err; + + switch (samples_per_pixel) { + case 1: + if (samples >= 2) + value |= ROGUE_CR_TE_AA_Y_EN; + if (samples >= 4) + value |= ROGUE_CR_TE_AA_X_EN; + break; + case 2: + if (samples >= 2) + value |= ROGUE_CR_TE_AA_X2_EN; + if (samples >= 4) + value |= ROGUE_CR_TE_AA_Y_EN; + if (samples >= 8) + value |= ROGUE_CR_TE_AA_X_EN; + break; + case 4: + if (samples >= 2) + value |= ROGUE_CR_TE_AA_X2_EN; + if (samples >= 4) + value |= ROGUE_CR_TE_AA_Y2_EN; + if (samples >= 8) + value |= ROGUE_CR_TE_AA_Y_EN; + break; + default: + WARN(true, "Unsupported ISP samples per pixel value"); + return -EINVAL; + } + + *value_out = value; + + return 0; +} + +static void +hwrtdata_common_init(void *cpu_ptr, void *priv) +{ + struct pvr_hwrt_dataset *hwrt = priv; + + memcpy(cpu_ptr, &hwrt->common, sizeof(hwrt->common)); +} + +static int +hwrt_init_common_fw_structure(struct pvr_file *pvr_file, + struct drm_pvr_ioctl_create_hwrt_dataset_args *args, + struct pvr_hwrt_dataset *hwrt) +{ + struct drm_pvr_create_hwrt_geom_data_args *geom_data_args = &args->geom_data_args; + struct pvr_device *pvr_dev = pvr_file->pvr_dev; + struct pvr_rt_mtile_info info; + int err; + + err = PVR_FEATURE_VALUE(pvr_dev, tile_size_x, &info.tile_size_x); + if (WARN_ON(err)) + return err; + + err = PVR_FEATURE_VALUE(pvr_dev, tile_size_y, &info.tile_size_y); + if (WARN_ON(err)) + return err; + + info.num_tiles_x = DIV_ROUND_UP(args->width, info.tile_size_x); + info.num_tiles_y = DIV_ROUND_UP(args->height, info.tile_size_y); + + if (PVR_HAS_FEATURE(pvr_dev, simple_parameter_format_version)) { + u32 parameter_format; + + err = PVR_FEATURE_VALUE(pvr_dev, simple_parameter_format_version, + ¶meter_format); + if (WARN_ON(err)) + return err; + + WARN_ON(parameter_format != 2); + + /* + * Set up 16 macrotiles with a multiple of 2x2 tiles per macrotile, which is + * aligned to a tile group. + */ + info.mtile_x[0] = DIV_ROUND_UP(info.num_tiles_x, 8) * 2; + info.mtile_y[0] = DIV_ROUND_UP(info.num_tiles_y, 8) * 2; + info.mtile_x[1] = 0; + info.mtile_y[1] = 0; + info.mtile_x[2] = 0; + info.mtile_y[2] = 0; + info.tile_max_x = round_up(info.num_tiles_x, 2) - 1; + info.tile_max_y = round_up(info.num_tiles_y, 2) - 1; + } else { + /* Set up 16 macrotiles with a multiple of 4x4 tiles per macrotile. */ + info.mtile_x[0] = round_up(DIV_ROUND_UP(info.num_tiles_x, 4), 4); + info.mtile_y[0] = round_up(DIV_ROUND_UP(info.num_tiles_y, 4), 4); + info.mtile_x[1] = info.mtile_x[0] * 2; + info.mtile_y[1] = info.mtile_y[0] * 2; + info.mtile_x[2] = info.mtile_x[0] * 3; + info.mtile_y[2] = info.mtile_y[0] * 3; + info.tile_max_x = info.num_tiles_x - 1; + info.tile_max_y = info.num_tiles_y - 1; + } + + hwrt->common.geom_caches_need_zeroing = false; + + hwrt->common.isp_merge_lower_x = args->isp_merge_lower_x; + hwrt->common.isp_merge_lower_y = args->isp_merge_lower_y; + hwrt->common.isp_merge_upper_x = args->isp_merge_upper_x; + hwrt->common.isp_merge_upper_y = args->isp_merge_upper_y; + hwrt->common.isp_merge_scale_x = args->isp_merge_scale_x; + hwrt->common.isp_merge_scale_y = args->isp_merge_scale_y; + + err = get_cr_multisamplectl_val(args->samples, false, + &hwrt->common.multi_sample_ctl); + if (err) + return err; + + err = get_cr_multisamplectl_val(args->samples, true, + &hwrt->common.flipped_multi_sample_ctl); + if (err) + return err; + + hwrt->common.mtile_stride = info.mtile_x[0] * info.mtile_y[0]; + + err = get_cr_te_aa_val(pvr_dev, args->samples, &hwrt->common.teaa); + if (err) + return err; + + hwrt->common.screen_pixel_max = + (((args->width - 1) << ROGUE_CR_PPP_SCREEN_PIXXMAX_SHIFT) & + ~ROGUE_CR_PPP_SCREEN_PIXXMAX_CLRMSK) | + (((args->height - 1) << ROGUE_CR_PPP_SCREEN_PIXYMAX_SHIFT) & + ~ROGUE_CR_PPP_SCREEN_PIXYMAX_CLRMSK); + + hwrt->common.te_screen = + ((info.tile_max_x << ROGUE_CR_TE_SCREEN_XMAX_SHIFT) & + ~ROGUE_CR_TE_SCREEN_XMAX_CLRMSK) | + ((info.tile_max_y << ROGUE_CR_TE_SCREEN_YMAX_SHIFT) & + ~ROGUE_CR_TE_SCREEN_YMAX_CLRMSK); + hwrt->common.te_mtile1 = + ((info.mtile_x[0] << ROGUE_CR_TE_MTILE1_X1_SHIFT) & ~ROGUE_CR_TE_MTILE1_X1_CLRMSK) | + ((info.mtile_x[1] << ROGUE_CR_TE_MTILE1_X2_SHIFT) & ~ROGUE_CR_TE_MTILE1_X2_CLRMSK) | + ((info.mtile_x[2] << ROGUE_CR_TE_MTILE1_X3_SHIFT) & ~ROGUE_CR_TE_MTILE1_X3_CLRMSK); + hwrt->common.te_mtile2 = + ((info.mtile_y[0] << ROGUE_CR_TE_MTILE2_Y1_SHIFT) & ~ROGUE_CR_TE_MTILE2_Y1_CLRMSK) | + ((info.mtile_y[1] << ROGUE_CR_TE_MTILE2_Y2_SHIFT) & ~ROGUE_CR_TE_MTILE2_Y2_CLRMSK) | + ((info.mtile_y[2] << ROGUE_CR_TE_MTILE2_Y3_SHIFT) & ~ROGUE_CR_TE_MTILE2_Y3_CLRMSK); + + err = get_cr_isp_mtile_size_val(pvr_dev, args->samples, &info, + &hwrt->common.isp_mtile_size); + if (err) + return err; + + hwrt->common.tpc_stride = geom_data_args->tpc_stride; + hwrt->common.tpc_size = geom_data_args->tpc_size; + + hwrt->common.rgn_header_size = args->region_header_size; + + err = pvr_fw_object_create(pvr_dev, sizeof(struct rogue_fwif_hwrtdata_common), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, hwrtdata_common_init, hwrt, + &hwrt->common_fw_obj); + + return err; +} + +static void +hwrt_fw_data_init(void *cpu_ptr, void *priv) +{ + struct pvr_hwrt_data *hwrt_data = priv; + + memcpy(cpu_ptr, &hwrt_data->data, sizeof(hwrt_data->data)); +} + +static int +hwrt_data_init_fw_structure(struct pvr_file *pvr_file, + struct pvr_hwrt_dataset *hwrt, + struct drm_pvr_ioctl_create_hwrt_dataset_args *args, + struct drm_pvr_create_hwrt_rt_data_args *rt_data_args, + struct pvr_hwrt_data *hwrt_data) +{ + struct drm_pvr_create_hwrt_geom_data_args *geom_data_args = &args->geom_data_args; + struct pvr_device *pvr_dev = pvr_file->pvr_dev; + struct rogue_fwif_rta_ctl *rta_ctl; + int free_list_i; + int err; + + pvr_fw_object_get_fw_addr(hwrt->common_fw_obj, + &hwrt_data->data.hwrt_data_common_fw_addr); + + for (free_list_i = 0; free_list_i < ARRAY_SIZE(hwrt->free_lists); free_list_i++) { + pvr_fw_object_get_fw_addr(hwrt->free_lists[free_list_i]->fw_obj, + &hwrt_data->data.freelists_fw_addr[free_list_i]); + } + + hwrt_data->data.tail_ptrs_dev_addr = geom_data_args->tpc_dev_addr; + hwrt_data->data.vheap_table_dev_addr = geom_data_args->vheap_table_dev_addr; + hwrt_data->data.rtc_dev_addr = geom_data_args->rtc_dev_addr; + + hwrt_data->data.pm_mlist_dev_addr = rt_data_args->pm_mlist_dev_addr; + hwrt_data->data.macrotile_array_dev_addr = rt_data_args->macrotile_array_dev_addr; + hwrt_data->data.rgn_header_dev_addr = rt_data_args->region_header_dev_addr; + + rta_ctl = &hwrt_data->data.rta_ctl; + + rta_ctl->render_target_index = 0; + rta_ctl->active_render_targets = 0; + rta_ctl->valid_render_targets_fw_addr = 0; + rta_ctl->rta_num_partial_renders_fw_addr = 0; + rta_ctl->max_rts = args->layers; + + if (args->layers > 1) { + err = pvr_fw_object_create(pvr_dev, args->layers * SRTC_ENTRY_SIZE, + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + NULL, NULL, &hwrt_data->srtc_obj); + if (err) + return err; + pvr_fw_object_get_fw_addr(hwrt_data->srtc_obj, + &rta_ctl->valid_render_targets_fw_addr); + + err = pvr_fw_object_create(pvr_dev, args->layers * RAA_ENTRY_SIZE, + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + NULL, NULL, &hwrt_data->raa_obj); + if (err) + goto err_put_shadow_rt_cache; + pvr_fw_object_get_fw_addr(hwrt_data->raa_obj, + &rta_ctl->rta_num_partial_renders_fw_addr); + } + + err = pvr_fw_object_create(pvr_dev, sizeof(struct rogue_fwif_hwrtdata), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + hwrt_fw_data_init, hwrt_data, &hwrt_data->fw_obj); + if (err) + goto err_put_raa_obj; + + pvr_free_list_add_hwrt(hwrt->free_lists[0], hwrt_data); + + return 0; + +err_put_raa_obj: + if (args->layers > 1) + pvr_fw_object_destroy(hwrt_data->raa_obj); + +err_put_shadow_rt_cache: + if (args->layers > 1) + pvr_fw_object_destroy(hwrt_data->srtc_obj); + + return err; +} + +static void +hwrt_data_fini_fw_structure(struct pvr_hwrt_dataset *hwrt, int hwrt_nr) +{ + struct pvr_hwrt_data *hwrt_data = &hwrt->data[hwrt_nr]; + + pvr_free_list_remove_hwrt(hwrt->free_lists[0], hwrt_data); + + if (hwrt->max_rts > 1) { + pvr_fw_object_destroy(hwrt_data->raa_obj); + pvr_fw_object_destroy(hwrt_data->srtc_obj); + } + + pvr_fw_object_destroy(hwrt_data->fw_obj); +} + +/** + * pvr_hwrt_dataset_create() - Create a new HWRT dataset + * @pvr_file: Pointer to pvr_file structure. + * @args: Creation arguments from userspace. + * + * Return: + * * Pointer to new HWRT, or + * * ERR_PTR(-%ENOMEM) on out of memory. + */ +struct pvr_hwrt_dataset * +pvr_hwrt_dataset_create(struct pvr_file *pvr_file, + struct drm_pvr_ioctl_create_hwrt_dataset_args *args) +{ + struct pvr_hwrt_dataset *hwrt; + int err, i = 0; + + /* Create and fill out the kernel structure */ + hwrt = kzalloc(sizeof(*hwrt), GFP_KERNEL); + + if (!hwrt) + return ERR_PTR(-ENOMEM); + + err = hwrt_init_kernel_structure(pvr_file, args, hwrt); + if (err < 0) + goto err_free; + + err = hwrt_init_common_fw_structure(pvr_file, args, hwrt); + if (err < 0) + goto err_fini_kernel_structure; + + for (; i < ARRAY_SIZE(hwrt->data); i++) { + err = hwrt_data_init_fw_structure(pvr_file, hwrt, args, + &args->rt_data_args[i], + &hwrt->data[i]); + if (err < 0) + goto err_fini_data_structures; + + hwrt->data[i].hwrt_dataset = hwrt; + } + + kref_init(&hwrt->ref_count); + return hwrt; + +err_fini_data_structures: + while (--i >= 0) + hwrt_data_fini_fw_structure(hwrt, i); + +err_fini_kernel_structure: + hwrt_fini_kernel_structure(hwrt); + +err_free: + kfree(hwrt); + + return ERR_PTR(err); +} + +static void +pvr_hwrt_dataset_release(struct kref *ref_count) +{ + struct pvr_hwrt_dataset *hwrt = + container_of(ref_count, struct pvr_hwrt_dataset, ref_count); + + for (int i = ARRAY_SIZE(hwrt->data) - 1; i >= 0; i--) { + WARN_ON(pvr_fw_structure_cleanup(hwrt->pvr_dev, ROGUE_FWIF_CLEANUP_HWRTDATA, + hwrt->data[i].fw_obj, 0)); + hwrt_data_fini_fw_structure(hwrt, i); + } + + hwrt_fini_common_fw_structure(hwrt); + hwrt_fini_kernel_structure(hwrt); + + kfree(hwrt); +} + +/** + * pvr_destroy_hwrt_datasets_for_file: Destroy any HWRT datasets associated + * with the given file. + * @pvr_file: Pointer to pvr_file structure. + * + * Removes all HWRT datasets associated with @pvr_file from the device + * hwrt_dataset list and drops initial references. HWRT datasets will then be + * destroyed once all outstanding references are dropped. + */ +void pvr_destroy_hwrt_datasets_for_file(struct pvr_file *pvr_file) +{ + struct pvr_hwrt_dataset *hwrt; + unsigned long handle; + + xa_for_each(&pvr_file->hwrt_handles, handle, hwrt) { + (void)hwrt; + pvr_hwrt_dataset_put(xa_erase(&pvr_file->hwrt_handles, handle)); + } +} + +/** + * pvr_hwrt_dataset_put() - Release reference on HWRT dataset + * @hwrt: Pointer to HWRT dataset to release reference on + */ +void +pvr_hwrt_dataset_put(struct pvr_hwrt_dataset *hwrt) +{ + if (hwrt) + kref_put(&hwrt->ref_count, pvr_hwrt_dataset_release); +} diff --git a/drivers/gpu/drm/imagination/pvr_hwrt.h b/drivers/gpu/drm/imagination/pvr_hwrt.h new file mode 100644 index 00000000000000..676070b20c3ba5 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_hwrt.h @@ -0,0 +1,166 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_HWRT_H +#define PVR_HWRT_H + +#include +#include +#include +#include +#include +#include + +#include "pvr_device.h" +#include "pvr_rogue_fwif_shared.h" + +/* Forward declaration from pvr_free_list.h. */ +struct pvr_free_list; + +/* Forward declaration from pvr_gem.h. */ +struct pvr_fw_object; + +/** + * struct pvr_hwrt_data - structure representing HWRT data + */ +struct pvr_hwrt_data { + /** @fw_obj: FW object representing the FW-side structure. */ + struct pvr_fw_object *fw_obj; + + /** @data: Local copy of FW-side structure. */ + struct rogue_fwif_hwrtdata data; + + /** @freelist_node: List node connecting this HWRT to the local freelist. */ + struct list_head freelist_node; + + /** + * @srtc_obj: FW object representing shadow render target cache. + * + * Only valid if @max_rts > 1. + */ + struct pvr_fw_object *srtc_obj; + + /** + * @raa_obj: FW object representing renders accumulation array. + * + * Only valid if @max_rts > 1. + */ + struct pvr_fw_object *raa_obj; + + /** @hwrt_dataset: Back pointer to owning HWRT dataset. */ + struct pvr_hwrt_dataset *hwrt_dataset; +}; + +/** + * struct pvr_hwrt_dataset - structure representing a HWRT data set. + */ +struct pvr_hwrt_dataset { + /** @ref_count: Reference count of object. */ + struct kref ref_count; + + /** @pvr_dev: Pointer to device that owns this object. */ + struct pvr_device *pvr_dev; + + /** @common_fw_obj: FW object representing common FW-side structure. */ + struct pvr_fw_object *common_fw_obj; + + /** @common: Common HWRT data. */ + struct rogue_fwif_hwrtdata_common common; + + /** @data: HWRT data structures belonging to this set. */ + struct pvr_hwrt_data data[ROGUE_FWIF_NUM_RTDATAS]; + + /** @free_lists: Free lists used by HWRT data set. */ + struct pvr_free_list *free_lists[ROGUE_FWIF_NUM_RTDATA_FREELISTS]; + + /** @max_rts: Maximum render targets for this HWRT data set. */ + u16 max_rts; +}; + +struct pvr_hwrt_dataset * +pvr_hwrt_dataset_create(struct pvr_file *pvr_file, + struct drm_pvr_ioctl_create_hwrt_dataset_args *args); + +void +pvr_destroy_hwrt_datasets_for_file(struct pvr_file *pvr_file); + +/** + * pvr_hwrt_dataset_lookup() - Lookup HWRT dataset pointer from handle + * @pvr_file: Pointer to pvr_file structure. + * @handle: Object handle. + * + * Takes reference on dataset object. Call pvr_hwrt_dataset_put() to release. + * + * Returns: + * * The requested object on success, or + * * %NULL on failure (object does not exist in list, or is not a HWRT + * dataset) + */ +static __always_inline struct pvr_hwrt_dataset * +pvr_hwrt_dataset_lookup(struct pvr_file *pvr_file, u32 handle) +{ + struct pvr_hwrt_dataset *hwrt; + + xa_lock(&pvr_file->hwrt_handles); + hwrt = xa_load(&pvr_file->hwrt_handles, handle); + + if (hwrt) + kref_get(&hwrt->ref_count); + + xa_unlock(&pvr_file->hwrt_handles); + + return hwrt; +} + +void +pvr_hwrt_dataset_put(struct pvr_hwrt_dataset *hwrt); + +/** + * pvr_hwrt_data_lookup() - Lookup HWRT data pointer from handle and index + * @pvr_file: Pointer to pvr_file structure. + * @handle: Object handle. + * @index: Index of RT data within dataset. + * + * Takes reference on dataset object. Call pvr_hwrt_data_put() to release. + * + * Returns: + * * The requested object on success, or + * * %NULL on failure (object does not exist in list, or is not a HWRT + * dataset, or index is out of range) + */ +static __always_inline struct pvr_hwrt_data * +pvr_hwrt_data_lookup(struct pvr_file *pvr_file, u32 handle, u32 index) +{ + struct pvr_hwrt_dataset *hwrt_dataset = pvr_hwrt_dataset_lookup(pvr_file, handle); + + if (hwrt_dataset) { + if (index < ARRAY_SIZE(hwrt_dataset->data)) + return &hwrt_dataset->data[index]; + + pvr_hwrt_dataset_put(hwrt_dataset); + } + + return NULL; +} + +/** + * pvr_hwrt_data_put() - Release reference on HWRT data + * @hwrt: Pointer to HWRT data to release reference on + */ +static __always_inline void +pvr_hwrt_data_put(struct pvr_hwrt_data *hwrt) +{ + if (hwrt) + pvr_hwrt_dataset_put(hwrt->hwrt_dataset); +} + +static __always_inline struct pvr_hwrt_data * +pvr_hwrt_data_get(struct pvr_hwrt_data *hwrt) +{ + if (hwrt) + kref_get(&hwrt->hwrt_dataset->ref_count); + + return hwrt; +} + +#endif /* PVR_HWRT_H */ diff --git a/drivers/gpu/drm/imagination/pvr_job.c b/drivers/gpu/drm/imagination/pvr_job.c new file mode 100644 index 00000000000000..78c2f3c6dce019 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_job.c @@ -0,0 +1,786 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_context.h" +#include "pvr_device.h" +#include "pvr_drv.h" +#include "pvr_gem.h" +#include "pvr_hwrt.h" +#include "pvr_job.h" +#include "pvr_mmu.h" +#include "pvr_power.h" +#include "pvr_rogue_fwif.h" +#include "pvr_rogue_fwif_client.h" +#include "pvr_stream.h" +#include "pvr_stream_defs.h" +#include "pvr_sync.h" + +#include +#include +#include +#include + +static void pvr_job_release(struct kref *kref) +{ + struct pvr_job *job = container_of(kref, struct pvr_job, ref_count); + + xa_erase(&job->pvr_dev->job_ids, job->id); + + pvr_hwrt_data_put(job->hwrt); + pvr_context_put(job->ctx); + + WARN_ON(job->paired_job); + + pvr_queue_job_cleanup(job); + pvr_job_release_pm_ref(job); + + kfree(job->cmd); + kfree(job); +} + +/** + * pvr_job_put() - Release reference on job + * @job: Target job. + */ +void +pvr_job_put(struct pvr_job *job) +{ + if (job) + kref_put(&job->ref_count, pvr_job_release); +} + +/** + * pvr_job_process_stream() - Build job FW structure from stream + * @pvr_dev: Device pointer. + * @cmd_defs: Stream definition. + * @stream: Pointer to command stream. + * @stream_size: Size of command stream, in bytes. + * @job: Pointer to job. + * + * Caller is responsible for freeing the output structure. + * + * Returns: + * * 0 on success, + * * -%ENOMEM on out of memory, or + * * -%EINVAL on malformed stream. + */ +static int +pvr_job_process_stream(struct pvr_device *pvr_dev, const struct pvr_stream_cmd_defs *cmd_defs, + void *stream, u32 stream_size, struct pvr_job *job) +{ + int err; + + job->cmd = kzalloc(cmd_defs->dest_size, GFP_KERNEL); + if (!job->cmd) + return -ENOMEM; + + job->cmd_len = cmd_defs->dest_size; + + err = pvr_stream_process(pvr_dev, cmd_defs, stream, stream_size, job->cmd); + if (err) + kfree(job->cmd); + + return err; +} + +static int pvr_fw_cmd_init(struct pvr_device *pvr_dev, struct pvr_job *job, + const struct pvr_stream_cmd_defs *stream_def, + u64 stream_userptr, u32 stream_len) +{ + void *stream; + int err; + + stream = kzalloc(stream_len, GFP_KERNEL); + if (!stream) + return -ENOMEM; + + if (copy_from_user(stream, u64_to_user_ptr(stream_userptr), stream_len)) { + err = -EFAULT; + goto err_free_stream; + } + + err = pvr_job_process_stream(pvr_dev, stream_def, stream, stream_len, job); + +err_free_stream: + kfree(stream); + + return err; +} + +static u32 +convert_geom_flags(u32 in_flags) +{ + u32 out_flags = 0; + + if (in_flags & DRM_PVR_SUBMIT_JOB_GEOM_CMD_FIRST) + out_flags |= ROGUE_GEOM_FLAGS_FIRSTKICK; + if (in_flags & DRM_PVR_SUBMIT_JOB_GEOM_CMD_LAST) + out_flags |= ROGUE_GEOM_FLAGS_LASTKICK; + if (in_flags & DRM_PVR_SUBMIT_JOB_GEOM_CMD_SINGLE_CORE) + out_flags |= ROGUE_GEOM_FLAGS_SINGLE_CORE; + + return out_flags; +} + +static u32 +convert_frag_flags(u32 in_flags) +{ + u32 out_flags = 0; + + if (in_flags & DRM_PVR_SUBMIT_JOB_FRAG_CMD_SINGLE_CORE) + out_flags |= ROGUE_FRAG_FLAGS_SINGLE_CORE; + if (in_flags & DRM_PVR_SUBMIT_JOB_FRAG_CMD_DEPTHBUFFER) + out_flags |= ROGUE_FRAG_FLAGS_DEPTHBUFFER; + if (in_flags & DRM_PVR_SUBMIT_JOB_FRAG_CMD_STENCILBUFFER) + out_flags |= ROGUE_FRAG_FLAGS_STENCILBUFFER; + if (in_flags & DRM_PVR_SUBMIT_JOB_FRAG_CMD_PREVENT_CDM_OVERLAP) + out_flags |= ROGUE_FRAG_FLAGS_PREVENT_CDM_OVERLAP; + if (in_flags & DRM_PVR_SUBMIT_JOB_FRAG_CMD_SCRATCHBUFFER) + out_flags |= ROGUE_FRAG_FLAGS_SCRATCHBUFFER; + if (in_flags & DRM_PVR_SUBMIT_JOB_FRAG_CMD_GET_VIS_RESULTS) + out_flags |= ROGUE_FRAG_FLAGS_GET_VIS_RESULTS; + if (in_flags & DRM_PVR_SUBMIT_JOB_FRAG_CMD_DISABLE_PIXELMERGE) + out_flags |= ROGUE_FRAG_FLAGS_DISABLE_PIXELMERGE; + + return out_flags; +} + +static int +pvr_geom_job_fw_cmd_init(struct pvr_job *job, + struct drm_pvr_job *args) +{ + struct rogue_fwif_cmd_geom *cmd; + int err; + + if (args->flags & ~DRM_PVR_SUBMIT_JOB_GEOM_CMD_FLAGS_MASK) + return -EINVAL; + + if (job->ctx->type != DRM_PVR_CTX_TYPE_RENDER) + return -EINVAL; + + if (!job->hwrt) + return -EINVAL; + + job->fw_ccb_cmd_type = ROGUE_FWIF_CCB_CMD_TYPE_GEOM; + err = pvr_fw_cmd_init(job->pvr_dev, job, &pvr_cmd_geom_stream, + args->cmd_stream, args->cmd_stream_len); + if (err) + return err; + + cmd = job->cmd; + cmd->cmd_shared.cmn.frame_num = 0; + cmd->flags = convert_geom_flags(args->flags); + pvr_fw_object_get_fw_addr(job->hwrt->fw_obj, &cmd->cmd_shared.hwrt_data_fw_addr); + return 0; +} + +static int +pvr_frag_job_fw_cmd_init(struct pvr_job *job, + struct drm_pvr_job *args) +{ + struct rogue_fwif_cmd_frag *cmd; + int err; + + if (args->flags & ~DRM_PVR_SUBMIT_JOB_FRAG_CMD_FLAGS_MASK) + return -EINVAL; + + if (job->ctx->type != DRM_PVR_CTX_TYPE_RENDER) + return -EINVAL; + + if (!job->hwrt) + return -EINVAL; + + job->fw_ccb_cmd_type = (args->flags & DRM_PVR_SUBMIT_JOB_FRAG_CMD_PARTIAL_RENDER) ? + ROGUE_FWIF_CCB_CMD_TYPE_FRAG_PR : + ROGUE_FWIF_CCB_CMD_TYPE_FRAG; + err = pvr_fw_cmd_init(job->pvr_dev, job, &pvr_cmd_frag_stream, + args->cmd_stream, args->cmd_stream_len); + if (err) + return err; + + cmd = job->cmd; + cmd->cmd_shared.cmn.frame_num = 0; + cmd->flags = convert_frag_flags(args->flags); + pvr_fw_object_get_fw_addr(job->hwrt->fw_obj, &cmd->cmd_shared.hwrt_data_fw_addr); + return 0; +} + +static u32 +convert_compute_flags(u32 in_flags) +{ + u32 out_flags = 0; + + if (in_flags & DRM_PVR_SUBMIT_JOB_COMPUTE_CMD_PREVENT_ALL_OVERLAP) + out_flags |= ROGUE_COMPUTE_FLAG_PREVENT_ALL_OVERLAP; + if (in_flags & DRM_PVR_SUBMIT_JOB_COMPUTE_CMD_SINGLE_CORE) + out_flags |= ROGUE_COMPUTE_FLAG_SINGLE_CORE; + + return out_flags; +} + +static int +pvr_compute_job_fw_cmd_init(struct pvr_job *job, + struct drm_pvr_job *args) +{ + struct rogue_fwif_cmd_compute *cmd; + int err; + + if (args->flags & ~DRM_PVR_SUBMIT_JOB_COMPUTE_CMD_FLAGS_MASK) + return -EINVAL; + + if (job->ctx->type != DRM_PVR_CTX_TYPE_COMPUTE) + return -EINVAL; + + job->fw_ccb_cmd_type = ROGUE_FWIF_CCB_CMD_TYPE_CDM; + err = pvr_fw_cmd_init(job->pvr_dev, job, &pvr_cmd_compute_stream, + args->cmd_stream, args->cmd_stream_len); + if (err) + return err; + + cmd = job->cmd; + cmd->common.frame_num = 0; + cmd->flags = convert_compute_flags(args->flags); + return 0; +} + +static u32 +convert_transfer_flags(u32 in_flags) +{ + u32 out_flags = 0; + + if (in_flags & DRM_PVR_SUBMIT_JOB_TRANSFER_CMD_SINGLE_CORE) + out_flags |= ROGUE_TRANSFER_FLAGS_SINGLE_CORE; + + return out_flags; +} + +static int +pvr_transfer_job_fw_cmd_init(struct pvr_job *job, + struct drm_pvr_job *args) +{ + struct rogue_fwif_cmd_transfer *cmd; + int err; + + if (args->flags & ~DRM_PVR_SUBMIT_JOB_TRANSFER_CMD_FLAGS_MASK) + return -EINVAL; + + if (job->ctx->type != DRM_PVR_CTX_TYPE_TRANSFER_FRAG) + return -EINVAL; + + job->fw_ccb_cmd_type = ROGUE_FWIF_CCB_CMD_TYPE_TQ_3D; + err = pvr_fw_cmd_init(job->pvr_dev, job, &pvr_cmd_transfer_stream, + args->cmd_stream, args->cmd_stream_len); + if (err) + return err; + + cmd = job->cmd; + cmd->common.frame_num = 0; + cmd->flags = convert_transfer_flags(args->flags); + return 0; +} + +static int +pvr_job_fw_cmd_init(struct pvr_job *job, + struct drm_pvr_job *args) +{ + switch (args->type) { + case DRM_PVR_JOB_TYPE_GEOMETRY: + return pvr_geom_job_fw_cmd_init(job, args); + + case DRM_PVR_JOB_TYPE_FRAGMENT: + return pvr_frag_job_fw_cmd_init(job, args); + + case DRM_PVR_JOB_TYPE_COMPUTE: + return pvr_compute_job_fw_cmd_init(job, args); + + case DRM_PVR_JOB_TYPE_TRANSFER_FRAG: + return pvr_transfer_job_fw_cmd_init(job, args); + + default: + return -EINVAL; + } +} + +/** + * struct pvr_job_data - Helper container for pairing jobs with the + * sync_ops supplied for them by the user. + */ +struct pvr_job_data { + /** @job: Pointer to the job. */ + struct pvr_job *job; + + /** @sync_ops: Pointer to the sync_ops associated with @job. */ + struct drm_pvr_sync_op *sync_ops; + + /** @sync_op_count: Number of members of @sync_ops. */ + u32 sync_op_count; +}; + +/** + * prepare_job_syncs() - Prepare all sync objects for a single job. + * @pvr_file: PowerVR file. + * @job_data: Precreated job and sync_ops array. + * @signal_array: xarray to receive signal sync objects. + * + * Returns: + * * 0 on success, or + * * Any error code returned by pvr_sync_signal_array_collect_ops(), + * pvr_sync_add_deps_to_job(), drm_sched_job_add_resv_dependencies() or + * pvr_sync_signal_array_update_fences(). + */ +static int +prepare_job_syncs(struct pvr_file *pvr_file, + struct pvr_job_data *job_data, + struct xarray *signal_array) +{ + struct dma_fence *done_fence; + int err = pvr_sync_signal_array_collect_ops(signal_array, + from_pvr_file(pvr_file), + job_data->sync_op_count, + job_data->sync_ops); + + if (err) + return err; + + err = pvr_sync_add_deps_to_job(pvr_file, &job_data->job->base, + job_data->sync_op_count, + job_data->sync_ops, signal_array); + if (err) + return err; + + if (job_data->job->hwrt) { + /* The geometry job writes the HWRT region headers, which are + * then read by the fragment job. + */ + struct drm_gem_object *obj = + gem_from_pvr_gem(job_data->job->hwrt->fw_obj->gem); + enum dma_resv_usage usage = + dma_resv_usage_rw(job_data->job->type == + DRM_PVR_JOB_TYPE_GEOMETRY); + + dma_resv_lock(obj->resv, NULL); + err = drm_sched_job_add_resv_dependencies(&job_data->job->base, + obj->resv, usage); + dma_resv_unlock(obj->resv); + if (err) + return err; + } + + /* We need to arm the job to get the job done fence. */ + done_fence = pvr_queue_job_arm(job_data->job); + + err = pvr_sync_signal_array_update_fences(signal_array, + job_data->sync_op_count, + job_data->sync_ops, + done_fence); + return err; +} + +/** + * prepare_job_syncs_for_each() - Prepare all sync objects for an array of jobs. + * @pvr_file: PowerVR file. + * @job_data: Array of precreated jobs and their sync_ops. + * @job_count: Number of jobs. + * @signal_array: xarray to receive signal sync objects. + * + * Returns: + * * 0 on success, or + * * Any error code returned by pvr_vm_bind_job_prepare_syncs(). + */ +static int +prepare_job_syncs_for_each(struct pvr_file *pvr_file, + struct pvr_job_data *job_data, + u32 *job_count, + struct xarray *signal_array) +{ + for (u32 i = 0; i < *job_count; i++) { + int err = prepare_job_syncs(pvr_file, &job_data[i], + signal_array); + + if (err) { + *job_count = i; + return err; + } + } + + return 0; +} + +static struct pvr_job * +create_job(struct pvr_device *pvr_dev, + struct pvr_file *pvr_file, + struct drm_pvr_job *args) +{ + struct pvr_job *job = NULL; + int err; + + if (!args->cmd_stream || !args->cmd_stream_len) + return ERR_PTR(-EINVAL); + + if (args->type != DRM_PVR_JOB_TYPE_GEOMETRY && + args->type != DRM_PVR_JOB_TYPE_FRAGMENT && + (args->hwrt.set_handle || args->hwrt.data_index)) + return ERR_PTR(-EINVAL); + + job = kzalloc(sizeof(*job), GFP_KERNEL); + if (!job) + return ERR_PTR(-ENOMEM); + + kref_init(&job->ref_count); + job->type = args->type; + job->pvr_dev = pvr_dev; + + err = xa_alloc(&pvr_dev->job_ids, &job->id, job, xa_limit_32b, GFP_KERNEL); + if (err) + goto err_put_job; + + job->ctx = pvr_context_lookup(pvr_file, args->context_handle); + if (!job->ctx) { + err = -EINVAL; + goto err_put_job; + } + + if (args->hwrt.set_handle) { + job->hwrt = pvr_hwrt_data_lookup(pvr_file, args->hwrt.set_handle, + args->hwrt.data_index); + if (!job->hwrt) { + err = -EINVAL; + goto err_put_job; + } + } + + err = pvr_job_fw_cmd_init(job, args); + if (err) + goto err_put_job; + + err = pvr_queue_job_init(job); + if (err) + goto err_put_job; + + return job; + +err_put_job: + pvr_job_put(job); + return ERR_PTR(err); +} + +/** + * pvr_job_data_fini() - Cleanup all allocs used to set up job submission. + * @job_data: Job data array. + * @job_count: Number of members of @job_data. + */ +static void +pvr_job_data_fini(struct pvr_job_data *job_data, u32 job_count) +{ + for (u32 i = 0; i < job_count; i++) { + pvr_job_put(job_data[i].job); + kvfree(job_data[i].sync_ops); + } +} + +/** + * pvr_job_data_init() - Init an array of created jobs, associating them with + * the appropriate sync_ops args, which will be copied in. + * @pvr_dev: Target PowerVR device. + * @pvr_file: Pointer to PowerVR file structure. + * @job_args: Job args array copied from user. + * @job_count: Number of members of @job_args. + * @job_data_out: Job data array. + */ +static int pvr_job_data_init(struct pvr_device *pvr_dev, + struct pvr_file *pvr_file, + struct drm_pvr_job *job_args, + u32 *job_count, + struct pvr_job_data *job_data_out) +{ + int err = 0, i = 0; + + for (; i < *job_count; i++) { + job_data_out[i].job = + create_job(pvr_dev, pvr_file, &job_args[i]); + err = PTR_ERR_OR_ZERO(job_data_out[i].job); + + if (err) { + *job_count = i; + job_data_out[i].job = NULL; + goto err_cleanup; + } + + err = PVR_UOBJ_GET_ARRAY(job_data_out[i].sync_ops, + &job_args[i].sync_ops); + if (err) { + *job_count = i; + + /* Ensure the job created above is also cleaned up. */ + i++; + goto err_cleanup; + } + + job_data_out[i].sync_op_count = job_args[i].sync_ops.count; + } + + return 0; + +err_cleanup: + pvr_job_data_fini(job_data_out, i); + + return err; +} + +static void +push_jobs(struct pvr_job_data *job_data, u32 job_count) +{ + for (u32 i = 0; i < job_count; i++) + pvr_queue_job_push(job_data[i].job); +} + +static int +prepare_fw_obj_resv(struct drm_exec *exec, struct pvr_fw_object *fw_obj) +{ + return drm_exec_prepare_obj(exec, gem_from_pvr_gem(fw_obj->gem), 1); +} + +static int +jobs_lock_all_objs(struct drm_exec *exec, struct pvr_job_data *job_data, + u32 job_count) +{ + for (u32 i = 0; i < job_count; i++) { + struct pvr_job *job = job_data[i].job; + + /* Grab a lock on a the context, to guard against + * concurrent submission to the same queue. + */ + int err = drm_exec_lock_obj(exec, + gem_from_pvr_gem(job->ctx->fw_obj->gem)); + + if (err) + return err; + + if (job->hwrt) { + err = prepare_fw_obj_resv(exec, + job->hwrt->fw_obj); + if (err) + return err; + } + } + + return 0; +} + +static int +prepare_job_resvs_for_each(struct drm_exec *exec, struct pvr_job_data *job_data, + u32 job_count) +{ + drm_exec_until_all_locked(exec) { + int err = jobs_lock_all_objs(exec, job_data, job_count); + + drm_exec_retry_on_contention(exec); + if (err) + return err; + } + + return 0; +} + +static void +update_job_resvs(struct pvr_job *job) +{ + if (job->hwrt) { + enum dma_resv_usage usage = job->type == DRM_PVR_JOB_TYPE_GEOMETRY ? + DMA_RESV_USAGE_WRITE : DMA_RESV_USAGE_READ; + struct drm_gem_object *obj = gem_from_pvr_gem(job->hwrt->fw_obj->gem); + + dma_resv_add_fence(obj->resv, &job->base.s_fence->finished, usage); + } +} + +static void +update_job_resvs_for_each(struct pvr_job_data *job_data, u32 job_count) +{ + for (u32 i = 0; i < job_count; i++) + update_job_resvs(job_data[i].job); +} + +static bool can_combine_jobs(struct pvr_job *a, struct pvr_job *b) +{ + struct pvr_job *geom_job = a, *frag_job = b; + struct dma_fence *fence; + unsigned long index; + + /* Geometry and fragment jobs can be combined if they are queued to the + * same context and targeting the same HWRT. + */ + if (a->type != DRM_PVR_JOB_TYPE_GEOMETRY || + b->type != DRM_PVR_JOB_TYPE_FRAGMENT || + a->ctx != b->ctx || + a->hwrt != b->hwrt) + return false; + + xa_for_each(&frag_job->base.dependencies, index, fence) { + /* We combine when we see an explicit geom -> frag dep. */ + if (&geom_job->base.s_fence->scheduled == fence) + return true; + } + + return false; +} + +static struct dma_fence * +get_last_queued_job_scheduled_fence(struct pvr_queue *queue, + struct pvr_job_data *job_data, + u32 cur_job_pos) +{ + /* We iterate over the current job array in reverse order to grab the + * last to-be-queued job targeting the same queue. + */ + for (u32 i = cur_job_pos; i > 0; i--) { + struct pvr_job *job = job_data[i - 1].job; + + if (job->ctx == queue->ctx && job->type == queue->type) + return dma_fence_get(&job->base.s_fence->scheduled); + } + + /* If we didn't find any, we just return the last queued job scheduled + * fence attached to the queue. + */ + return dma_fence_get(queue->last_queued_job_scheduled_fence); +} + +static int +pvr_jobs_link_geom_frag(struct pvr_job_data *job_data, u32 *job_count) +{ + for (u32 i = 0; i < *job_count - 1; i++) { + struct pvr_job *geom_job = job_data[i].job; + struct pvr_job *frag_job = job_data[i + 1].job; + struct pvr_queue *frag_queue; + struct dma_fence *f; + + if (!can_combine_jobs(job_data[i].job, job_data[i + 1].job)) + continue; + + /* The fragment job will be submitted by the geometry queue. We + * need to make sure it comes after all the other fragment jobs + * queued before it. + */ + frag_queue = pvr_context_get_queue_for_job(frag_job->ctx, + frag_job->type); + f = get_last_queued_job_scheduled_fence(frag_queue, job_data, + i); + if (f) { + int err = drm_sched_job_add_dependency(&geom_job->base, + f); + if (err) { + *job_count = i; + return err; + } + } + + /* The KCCB slot will be reserved by the geometry job, so we can + * drop the KCCB fence on the fragment job. + */ + pvr_kccb_fence_put(frag_job->kccb_fence); + frag_job->kccb_fence = NULL; + + geom_job->paired_job = frag_job; + frag_job->paired_job = geom_job; + + /* Skip the fragment job we just paired to the geometry job. */ + i++; + } + + return 0; +} + +/** + * pvr_submit_jobs() - Submit jobs to the GPU + * @pvr_dev: Target PowerVR device. + * @pvr_file: Pointer to PowerVR file structure. + * @args: Ioctl args. + * + * This initial implementation is entirely synchronous; on return the GPU will + * be idle. This will not be the case for future implementations. + * + * Returns: + * * 0 on success, + * * -%EFAULT if arguments can not be copied from user space, or + * * -%EINVAL on invalid arguments, or + * * Any other error. + */ +int +pvr_submit_jobs(struct pvr_device *pvr_dev, struct pvr_file *pvr_file, + struct drm_pvr_ioctl_submit_jobs_args *args) +{ + struct pvr_job_data *job_data = NULL; + struct drm_pvr_job *job_args; + struct xarray signal_array; + u32 jobs_alloced = 0; + struct drm_exec exec; + int err; + + if (!args->jobs.count) + return -EINVAL; + + err = PVR_UOBJ_GET_ARRAY(job_args, &args->jobs); + if (err) + return err; + + job_data = kvmalloc_array(args->jobs.count, sizeof(*job_data), + GFP_KERNEL | __GFP_ZERO); + if (!job_data) { + err = -ENOMEM; + goto out_free; + } + + err = pvr_job_data_init(pvr_dev, pvr_file, job_args, &args->jobs.count, + job_data); + if (err) + goto out_free; + + jobs_alloced = args->jobs.count; + + /* + * Flush MMU if needed - this has been deferred until now to avoid + * overuse of this expensive operation. + */ + err = pvr_mmu_flush_exec(pvr_dev, false); + if (err) + goto out_job_data_cleanup; + + drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT | DRM_EXEC_IGNORE_DUPLICATES, 0); + + xa_init_flags(&signal_array, XA_FLAGS_ALLOC); + + err = prepare_job_syncs_for_each(pvr_file, job_data, &args->jobs.count, + &signal_array); + if (err) + goto out_exec_fini; + + err = prepare_job_resvs_for_each(&exec, job_data, args->jobs.count); + if (err) + goto out_exec_fini; + + err = pvr_jobs_link_geom_frag(job_data, &args->jobs.count); + if (err) + goto out_exec_fini; + + /* Anything after that point must succeed because we start exposing job + * finished fences to the outside world. + */ + update_job_resvs_for_each(job_data, args->jobs.count); + push_jobs(job_data, args->jobs.count); + pvr_sync_signal_array_push_fences(&signal_array); + err = 0; + +out_exec_fini: + drm_exec_fini(&exec); + pvr_sync_signal_array_cleanup(&signal_array); + +out_job_data_cleanup: + pvr_job_data_fini(job_data, jobs_alloced); + +out_free: + kvfree(job_data); + kvfree(job_args); + + return err; +} diff --git a/drivers/gpu/drm/imagination/pvr_job.h b/drivers/gpu/drm/imagination/pvr_job.h new file mode 100644 index 00000000000000..0ca003c5c4751e --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_job.h @@ -0,0 +1,161 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_JOB_H +#define PVR_JOB_H + +#include + +#include +#include + +#include +#include + +#include "pvr_power.h" + +/* Forward declaration from "pvr_context.h". */ +struct pvr_context; + +/* Forward declarations from "pvr_device.h". */ +struct pvr_device; +struct pvr_file; + +/* Forward declarations from "pvr_hwrt.h". */ +struct pvr_hwrt_data; + +/* Forward declaration from "pvr_queue.h". */ +struct pvr_queue; + +struct pvr_job { + /** @base: drm_sched_job object. */ + struct drm_sched_job base; + + /** @ref_count: Refcount for job. */ + struct kref ref_count; + + /** @type: Type of job. */ + enum drm_pvr_job_type type; + + /** @id: Job ID number. */ + u32 id; + + /** + * @paired_job: Job paired to this job. + * + * This field is only meaningful for geometry and fragment jobs. + * + * Paired jobs are executed on the same context, and need to be submitted + * atomically to the FW, to make sure the partial render logic has a + * fragment job to execute when the Parameter Manager runs out of memory. + * + * The geometry job should point to the fragment job it's paired with, + * and the fragment job should point to the geometry job it's paired with. + */ + struct pvr_job *paired_job; + + /** @cccb_fence: Fence used to wait for CCCB space. */ + struct dma_fence *cccb_fence; + + /** @kccb_fence: Fence used to wait for KCCB space. */ + struct dma_fence *kccb_fence; + + /** @done_fence: Fence to signal when the job is done. */ + struct dma_fence *done_fence; + + /** @pvr_dev: Device pointer. */ + struct pvr_device *pvr_dev; + + /** @ctx: Pointer to owning context. */ + struct pvr_context *ctx; + + /** @cmd: Command data. Format depends on @type. */ + void *cmd; + + /** @cmd_len: Length of command data, in bytes. */ + u32 cmd_len; + + /** + * @fw_ccb_cmd_type: Firmware CCB command type. Must be one of %ROGUE_FWIF_CCB_CMD_TYPE_*. + */ + u32 fw_ccb_cmd_type; + + /** @hwrt: HWRT object. Will be NULL for compute and transfer jobs. */ + struct pvr_hwrt_data *hwrt; + + /** + * @has_pm_ref: True if the job has a power ref, thus forcing the GPU to stay on until + * the job is done. + */ + bool has_pm_ref; +}; + +/** + * pvr_job_get() - Take additional reference on job. + * @job: Job pointer. + * + * Call pvr_job_put() to release. + * + * Returns: + * * The requested job on success, or + * * %NULL if no job pointer passed. + */ +static __always_inline struct pvr_job * +pvr_job_get(struct pvr_job *job) +{ + if (job) + kref_get(&job->ref_count); + + return job; +} + +void pvr_job_put(struct pvr_job *job); + +/** + * pvr_job_release_pm_ref() - Release the PM ref if the job acquired it. + * @job: The job to release the PM ref on. + */ +static __always_inline void +pvr_job_release_pm_ref(struct pvr_job *job) +{ + if (job->has_pm_ref) { + pvr_power_put(job->pvr_dev); + job->has_pm_ref = false; + } +} + +/** + * pvr_job_get_pm_ref() - Get a PM ref and attach it to the job. + * @job: The job to attach the PM ref to. + * + * Return: + * * 0 on success, or + * * Any error returned by pvr_power_get() otherwise. + */ +static __always_inline int +pvr_job_get_pm_ref(struct pvr_job *job) +{ + int err; + + if (job->has_pm_ref) + return 0; + + err = pvr_power_get(job->pvr_dev); + if (!err) + job->has_pm_ref = true; + + return err; +} + +int pvr_job_wait_first_non_signaled_native_dep(struct pvr_job *job); + +bool pvr_job_non_native_deps_done(struct pvr_job *job); + +int pvr_job_fits_in_cccb(struct pvr_job *job, unsigned long native_dep_count); + +void pvr_job_submit(struct pvr_job *job); + +int pvr_submit_jobs(struct pvr_device *pvr_dev, struct pvr_file *pvr_file, + struct drm_pvr_ioctl_submit_jobs_args *args); + +#endif /* PVR_JOB_H */ diff --git a/drivers/gpu/drm/imagination/pvr_mmu.c b/drivers/gpu/drm/imagination/pvr_mmu.c new file mode 100644 index 00000000000000..4fe70610ed94cf --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_mmu.c @@ -0,0 +1,2640 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_mmu.h" + +#include "pvr_ccb.h" +#include "pvr_device.h" +#include "pvr_fw.h" +#include "pvr_gem.h" +#include "pvr_power.h" +#include "pvr_rogue_fwif.h" +#include "pvr_rogue_mmu_defs.h" + +#include +#include +#include +#include +#include +#include +#include + +#define PVR_SHIFT_FROM_SIZE(size_) (__builtin_ctzll(size_)) +#define PVR_MASK_FROM_SIZE(size_) (~((size_) - U64_C(1))) + +/* + * The value of the device page size (%PVR_DEVICE_PAGE_SIZE) is currently + * pegged to the host page size (%PAGE_SIZE). This chunk of macro goodness both + * ensures that the selected host page size corresponds to a valid device page + * size and sets up values needed by the MMU code below. + */ +#if (PVR_DEVICE_PAGE_SIZE == SZ_4K) +# define ROGUE_MMUCTRL_PAGE_SIZE_X ROGUE_MMUCTRL_PAGE_SIZE_4KB +# define ROGUE_MMUCTRL_PAGE_X_RANGE_SHIFT ROGUE_MMUCTRL_PAGE_4KB_RANGE_SHIFT +# define ROGUE_MMUCTRL_PAGE_X_RANGE_CLRMSK ROGUE_MMUCTRL_PAGE_4KB_RANGE_CLRMSK +#elif (PVR_DEVICE_PAGE_SIZE == SZ_16K) +# define ROGUE_MMUCTRL_PAGE_SIZE_X ROGUE_MMUCTRL_PAGE_SIZE_16KB +# define ROGUE_MMUCTRL_PAGE_X_RANGE_SHIFT ROGUE_MMUCTRL_PAGE_16KB_RANGE_SHIFT +# define ROGUE_MMUCTRL_PAGE_X_RANGE_CLRMSK ROGUE_MMUCTRL_PAGE_16KB_RANGE_CLRMSK +#elif (PVR_DEVICE_PAGE_SIZE == SZ_64K) +# define ROGUE_MMUCTRL_PAGE_SIZE_X ROGUE_MMUCTRL_PAGE_SIZE_64KB +# define ROGUE_MMUCTRL_PAGE_X_RANGE_SHIFT ROGUE_MMUCTRL_PAGE_64KB_RANGE_SHIFT +# define ROGUE_MMUCTRL_PAGE_X_RANGE_CLRMSK ROGUE_MMUCTRL_PAGE_64KB_RANGE_CLRMSK +#elif (PVR_DEVICE_PAGE_SIZE == SZ_256K) +# define ROGUE_MMUCTRL_PAGE_SIZE_X ROGUE_MMUCTRL_PAGE_SIZE_256KB +# define ROGUE_MMUCTRL_PAGE_X_RANGE_SHIFT ROGUE_MMUCTRL_PAGE_256KB_RANGE_SHIFT +# define ROGUE_MMUCTRL_PAGE_X_RANGE_CLRMSK ROGUE_MMUCTRL_PAGE_256KB_RANGE_CLRMSK +#elif (PVR_DEVICE_PAGE_SIZE == SZ_1M) +# define ROGUE_MMUCTRL_PAGE_SIZE_X ROGUE_MMUCTRL_PAGE_SIZE_1MB +# define ROGUE_MMUCTRL_PAGE_X_RANGE_SHIFT ROGUE_MMUCTRL_PAGE_1MB_RANGE_SHIFT +# define ROGUE_MMUCTRL_PAGE_X_RANGE_CLRMSK ROGUE_MMUCTRL_PAGE_1MB_RANGE_CLRMSK +#elif (PVR_DEVICE_PAGE_SIZE == SZ_2M) +# define ROGUE_MMUCTRL_PAGE_SIZE_X ROGUE_MMUCTRL_PAGE_SIZE_2MB +# define ROGUE_MMUCTRL_PAGE_X_RANGE_SHIFT ROGUE_MMUCTRL_PAGE_2MB_RANGE_SHIFT +# define ROGUE_MMUCTRL_PAGE_X_RANGE_CLRMSK ROGUE_MMUCTRL_PAGE_2MB_RANGE_CLRMSK +#else +# error Unsupported device page size PVR_DEVICE_PAGE_SIZE +#endif + +#define ROGUE_MMUCTRL_ENTRIES_PT_VALUE_X \ + (ROGUE_MMUCTRL_ENTRIES_PT_VALUE >> \ + (PVR_DEVICE_PAGE_SHIFT - PVR_SHIFT_FROM_SIZE(SZ_4K))) + +enum pvr_mmu_sync_level { + PVR_MMU_SYNC_LEVEL_NONE = -1, + PVR_MMU_SYNC_LEVEL_0 = 0, + PVR_MMU_SYNC_LEVEL_1 = 1, + PVR_MMU_SYNC_LEVEL_2 = 2, +}; + +#define PVR_MMU_SYNC_LEVEL_0_FLAGS (ROGUE_FWIF_MMUCACHEDATA_FLAGS_PT | \ + ROGUE_FWIF_MMUCACHEDATA_FLAGS_INTERRUPT | \ + ROGUE_FWIF_MMUCACHEDATA_FLAGS_TLB) +#define PVR_MMU_SYNC_LEVEL_1_FLAGS (PVR_MMU_SYNC_LEVEL_0_FLAGS | ROGUE_FWIF_MMUCACHEDATA_FLAGS_PD) +#define PVR_MMU_SYNC_LEVEL_2_FLAGS (PVR_MMU_SYNC_LEVEL_1_FLAGS | ROGUE_FWIF_MMUCACHEDATA_FLAGS_PC) + +/** + * pvr_mmu_set_flush_flags() - Set MMU cache flush flags for next call to + * pvr_mmu_flush_exec(). + * @pvr_dev: Target PowerVR device. + * @flags: MMU flush flags. Must be one of %PVR_MMU_SYNC_LEVEL_*_FLAGS. + * + * This function must be called following any possible change to the MMU page + * tables. + */ +static void pvr_mmu_set_flush_flags(struct pvr_device *pvr_dev, u32 flags) +{ + atomic_fetch_or(flags, &pvr_dev->mmu_flush_cache_flags); +} + +/** + * pvr_mmu_flush_request_all() - Request flush of all MMU caches when + * subsequently calling pvr_mmu_flush_exec(). + * @pvr_dev: Target PowerVR device. + * + * This function must be called following any possible change to the MMU page + * tables. + */ +void pvr_mmu_flush_request_all(struct pvr_device *pvr_dev) +{ + pvr_mmu_set_flush_flags(pvr_dev, PVR_MMU_SYNC_LEVEL_2_FLAGS); +} + +/** + * pvr_mmu_flush_exec() - Execute a flush of all MMU caches previously + * requested. + * @pvr_dev: Target PowerVR device. + * @wait: Do not return until the flush is completed. + * + * This function must be called prior to submitting any new GPU job. The flush + * will complete before the jobs are scheduled, so this can be called once after + * a series of maps. However, a single unmap should always be immediately + * followed by a flush and it should be explicitly waited by setting @wait. + * + * As a failure to flush the MMU caches could risk memory corruption, if the + * flush fails (implying the firmware is not responding) then the GPU device is + * marked as lost. + * + * Returns: + * * 0 on success when @wait is true, or + * * -%EIO if the device is unavailable, or + * * Any error encountered while submitting the flush command via the KCCB. + */ +int pvr_mmu_flush_exec(struct pvr_device *pvr_dev, bool wait) +{ + struct rogue_fwif_kccb_cmd cmd_mmu_cache = {}; + struct rogue_fwif_mmucachedata *cmd_mmu_cache_data = + &cmd_mmu_cache.cmd_data.mmu_cache_data; + int err = 0; + u32 slot; + int idx; + + if (!drm_dev_enter(from_pvr_device(pvr_dev), &idx)) + return -EIO; + + /* Can't flush MMU if the firmware hasn't booted yet. */ + if (!pvr_dev->fw_dev.booted) + goto err_drm_dev_exit; + + cmd_mmu_cache_data->cache_flags = + atomic_xchg(&pvr_dev->mmu_flush_cache_flags, 0); + + if (!cmd_mmu_cache_data->cache_flags) + goto err_drm_dev_exit; + + cmd_mmu_cache.cmd_type = ROGUE_FWIF_KCCB_CMD_MMUCACHE; + + pvr_fw_object_get_fw_addr(pvr_dev->fw_dev.mem.mmucache_sync_obj, + &cmd_mmu_cache_data->mmu_cache_sync_fw_addr); + cmd_mmu_cache_data->mmu_cache_sync_update_value = 0; + + err = pvr_kccb_send_cmd(pvr_dev, &cmd_mmu_cache, &slot); + if (err) + goto err_reset_and_retry; + + err = pvr_kccb_wait_for_completion(pvr_dev, slot, HZ, NULL); + if (err) + goto err_reset_and_retry; + + drm_dev_exit(idx); + + return 0; + +err_reset_and_retry: + /* + * Flush command failure is most likely the result of a firmware lockup. Hard + * reset the GPU and retry. + */ + err = pvr_power_reset(pvr_dev, true); + if (err) + goto err_drm_dev_exit; /* Device is lost. */ + + /* Retry sending flush request. */ + err = pvr_kccb_send_cmd(pvr_dev, &cmd_mmu_cache, &slot); + if (err) { + pvr_device_lost(pvr_dev); + goto err_drm_dev_exit; + } + + if (wait) { + err = pvr_kccb_wait_for_completion(pvr_dev, slot, HZ, NULL); + if (err) + pvr_device_lost(pvr_dev); + } + +err_drm_dev_exit: + drm_dev_exit(idx); + + return err; +} + +/** + * DOC: PowerVR Virtual Memory Handling + */ +/** + * DOC: PowerVR Virtual Memory Handling (constants) + * + * .. c:macro:: PVR_IDX_INVALID + * + * Default value for a u16-based index. + * + * This value cannot be zero, since zero is a valid index value. + */ +#define PVR_IDX_INVALID ((u16)(-1)) + +/** + * DOC: MMU backing pages + */ +/** + * DOC: MMU backing pages (constants) + * + * .. c:macro:: PVR_MMU_BACKING_PAGE_SIZE + * + * Page size of a PowerVR device's integrated MMU. The CPU page size must be + * at least as large as this value for the current implementation; this is + * checked at compile-time. + */ +#define PVR_MMU_BACKING_PAGE_SIZE SZ_4K +static_assert(PAGE_SIZE >= PVR_MMU_BACKING_PAGE_SIZE); + +/** + * struct pvr_mmu_backing_page - Represents a single page used to back a page + * table of any level. + * @dma_addr: DMA address of this page. + * @host_ptr: CPU address of this page. + * @pvr_dev: The PowerVR device to which this page is associated. **For + * internal use only.** + */ +struct pvr_mmu_backing_page { + dma_addr_t dma_addr; + void *host_ptr; +/* private: internal use only */ + struct page *raw_page; + struct pvr_device *pvr_dev; +}; + +/** + * pvr_mmu_backing_page_init() - Initialize a MMU backing page. + * @page: Target backing page. + * @pvr_dev: Target PowerVR device. + * + * This function performs three distinct operations: + * + * 1. Allocate a single page, + * 2. Map the page to the CPU, and + * 3. Map the page to DMA-space. + * + * It is expected that @page be zeroed (e.g. from kzalloc()) before calling + * this function. + * + * Return: + * * 0 on success, or + * * -%ENOMEM if allocation of the backing page or mapping of the backing + * page to DMA fails. + */ +static int +pvr_mmu_backing_page_init(struct pvr_mmu_backing_page *page, + struct pvr_device *pvr_dev) +{ + struct device *dev = from_pvr_device(pvr_dev)->dev; + + struct page *raw_page; + int err; + + dma_addr_t dma_addr; + void *host_ptr; + + raw_page = alloc_page(__GFP_ZERO | GFP_KERNEL); + if (!raw_page) + return -ENOMEM; + + host_ptr = vmap(&raw_page, 1, VM_MAP, pgprot_writecombine(PAGE_KERNEL)); + if (!host_ptr) { + err = -ENOMEM; + goto err_free_page; + } + + dma_addr = dma_map_page(dev, raw_page, 0, PVR_MMU_BACKING_PAGE_SIZE, + DMA_TO_DEVICE); + if (dma_mapping_error(dev, dma_addr)) { + err = -ENOMEM; + goto err_unmap_page; + } + + page->dma_addr = dma_addr; + page->host_ptr = host_ptr; + page->pvr_dev = pvr_dev; + page->raw_page = raw_page; + kmemleak_alloc(page->host_ptr, PAGE_SIZE, 1, GFP_KERNEL); + + return 0; + +err_unmap_page: + vunmap(host_ptr); + +err_free_page: + __free_page(raw_page); + + return err; +} + +/** + * pvr_mmu_backing_page_fini() - Teardown a MMU backing page. + * @page: Target backing page. + * + * This function performs the mirror operations to pvr_mmu_backing_page_init(), + * in reverse order: + * + * 1. Unmap the page from DMA-space, + * 2. Unmap the page from the CPU, and + * 3. Free the page. + * + * It also zeros @page. + * + * It is a no-op to call this function a second (or further) time on any @page. + */ +static void +pvr_mmu_backing_page_fini(struct pvr_mmu_backing_page *page) +{ + struct device *dev; + + /* Do nothing if no allocation is present. */ + if (!page->pvr_dev) + return; + + dev = from_pvr_device(page->pvr_dev)->dev; + + dma_unmap_page(dev, page->dma_addr, PVR_MMU_BACKING_PAGE_SIZE, + DMA_TO_DEVICE); + + kmemleak_free(page->host_ptr); + vunmap(page->host_ptr); + + __free_page(page->raw_page); + + memset(page, 0, sizeof(*page)); +} + +/** + * pvr_mmu_backing_page_sync() - Flush a MMU backing page from the CPU to the + * device. + * @page: Target backing page. + * @flags: MMU flush flags. Must be one of %PVR_MMU_SYNC_LEVEL_*_FLAGS. + * + * .. caution:: + * + * **This is potentially an expensive function call.** Only call + * pvr_mmu_backing_page_sync() once you're sure you have no more changes to + * make to the backing page in the immediate future. + */ +static void +pvr_mmu_backing_page_sync(struct pvr_mmu_backing_page *page, u32 flags) +{ + struct pvr_device *pvr_dev = page->pvr_dev; + struct device *dev; + + /* + * Do nothing if no allocation is present. This may be the case if + * we are unmapping pages. + */ + if (!pvr_dev) + return; + + dev = from_pvr_device(pvr_dev)->dev; + + dma_sync_single_for_device(dev, page->dma_addr, + PVR_MMU_BACKING_PAGE_SIZE, DMA_TO_DEVICE); + + pvr_mmu_set_flush_flags(pvr_dev, flags); +} + +/** + * DOC: Raw page tables + */ + +#define PVR_PAGE_TABLE_TYPEOF_ENTRY(level_) \ + typeof_member(struct pvr_page_table_l##level_##_entry_raw, val) + +#define PVR_PAGE_TABLE_FIELD_GET(level_, name_, field_, entry_) \ + (((entry_).val & \ + ~ROGUE_MMUCTRL_##name_##_DATA_##field_##_CLRMSK) >> \ + ROGUE_MMUCTRL_##name_##_DATA_##field_##_SHIFT) + +#define PVR_PAGE_TABLE_FIELD_PREP(level_, name_, field_, val_) \ + ((((PVR_PAGE_TABLE_TYPEOF_ENTRY(level_))(val_)) \ + << ROGUE_MMUCTRL_##name_##_DATA_##field_##_SHIFT) & \ + ~ROGUE_MMUCTRL_##name_##_DATA_##field_##_CLRMSK) + +/** + * struct pvr_page_table_l2_entry_raw - A single entry in a level 2 page table. + * @val: The raw value of this entry. + * + * This type is a structure for type-checking purposes. At compile-time, its + * size is checked against %ROGUE_MMUCTRL_ENTRY_SIZE_PC_VALUE. + * + * The value stored in this structure can be decoded using the following bitmap: + * + * .. flat-table:: + * :widths: 1 5 + * :stub-columns: 1 + * + * * - 31..4 + * - **Level 1 Page Table Base Address:** Bits 39..12 of the L1 + * page table base address, which is 4KiB aligned. + * + * * - 3..2 + * - *(reserved)* + * + * * - 1 + * - **Pending:** When valid bit is not set, indicates that a valid + * entry is pending and the MMU should wait for the driver to map + * the entry. This is used to support page demand mapping of + * memory. + * + * * - 0 + * - **Valid:** Indicates that the entry contains a valid L1 page + * table. If the valid bit is not set, then an attempted use of + * the page would result in a page fault. + */ +struct pvr_page_table_l2_entry_raw { + u32 val; +} __packed; +static_assert(sizeof(struct pvr_page_table_l2_entry_raw) * 8 == + ROGUE_MMUCTRL_ENTRY_SIZE_PC_VALUE); + +static bool +pvr_page_table_l2_entry_raw_is_valid(struct pvr_page_table_l2_entry_raw entry) +{ + return PVR_PAGE_TABLE_FIELD_GET(2, PC, VALID, entry); +} + +/** + * pvr_page_table_l2_entry_raw_set() - Write a valid entry into a raw level 2 + * page table. + * @entry: Target raw level 2 page table entry. + * @child_table_dma_addr: DMA address of the level 1 page table to be + * associated with @entry. + * + * When calling this function, @child_table_dma_addr must be a valid DMA + * address and a multiple of %ROGUE_MMUCTRL_PC_DATA_PD_BASE_ALIGNSIZE. + */ +static void +pvr_page_table_l2_entry_raw_set(struct pvr_page_table_l2_entry_raw *entry, + dma_addr_t child_table_dma_addr) +{ + child_table_dma_addr >>= ROGUE_MMUCTRL_PC_DATA_PD_BASE_ALIGNSHIFT; + + WRITE_ONCE(entry->val, + PVR_PAGE_TABLE_FIELD_PREP(2, PC, VALID, true) | + PVR_PAGE_TABLE_FIELD_PREP(2, PC, ENTRY_PENDING, false) | + PVR_PAGE_TABLE_FIELD_PREP(2, PC, PD_BASE, child_table_dma_addr)); +} + +static void +pvr_page_table_l2_entry_raw_clear(struct pvr_page_table_l2_entry_raw *entry) +{ + WRITE_ONCE(entry->val, 0); +} + +/** + * struct pvr_page_table_l1_entry_raw - A single entry in a level 1 page table. + * @val: The raw value of this entry. + * + * This type is a structure for type-checking purposes. At compile-time, its + * size is checked against %ROGUE_MMUCTRL_ENTRY_SIZE_PD_VALUE. + * + * The value stored in this structure can be decoded using the following bitmap: + * + * .. flat-table:: + * :widths: 1 5 + * :stub-columns: 1 + * + * * - 63..41 + * - *(reserved)* + * + * * - 40 + * - **Pending:** When valid bit is not set, indicates that a valid entry + * is pending and the MMU should wait for the driver to map the entry. + * This is used to support page demand mapping of memory. + * + * * - 39..5 + * - **Level 0 Page Table Base Address:** The way this value is + * interpreted depends on the page size. Bits not specified in the + * table below (e.g. bits 11..5 for page size 4KiB) should be + * considered reserved. + * + * This table shows the bits used in an L1 page table entry to + * represent the Physical Table Base Address for a given Page Size. + * Since each L1 page table entry covers 2MiB of address space, the + * maximum page size is 2MiB. + * + * .. flat-table:: + * :widths: 1 1 1 1 + * :header-rows: 1 + * :stub-columns: 1 + * + * * - Page size + * - L0 page table base address bits + * - Number of L0 page table entries + * - Size of L0 page table + * + * * - 4KiB + * - 39..12 + * - 512 + * - 4KiB + * + * * - 16KiB + * - 39..10 + * - 128 + * - 1KiB + * + * * - 64KiB + * - 39..8 + * - 32 + * - 256B + * + * * - 256KiB + * - 39..6 + * - 8 + * - 64B + * + * * - 1MiB + * - 39..5 (4 = '0') + * - 2 + * - 16B + * + * * - 2MiB + * - 39..5 (4..3 = '00') + * - 1 + * - 8B + * + * * - 4 + * - *(reserved)* + * + * * - 3..1 + * - **Page Size:** Sets the page size, from 4KiB to 2MiB. + * + * * - 0 + * - **Valid:** Indicates that the entry contains a valid L0 page table. + * If the valid bit is not set, then an attempted use of the page would + * result in a page fault. + */ +struct pvr_page_table_l1_entry_raw { + u64 val; +} __packed; +static_assert(sizeof(struct pvr_page_table_l1_entry_raw) * 8 == + ROGUE_MMUCTRL_ENTRY_SIZE_PD_VALUE); + +static bool +pvr_page_table_l1_entry_raw_is_valid(struct pvr_page_table_l1_entry_raw entry) +{ + return PVR_PAGE_TABLE_FIELD_GET(1, PD, VALID, entry); +} + +/** + * pvr_page_table_l1_entry_raw_set() - Write a valid entry into a raw level 1 + * page table. + * @entry: Target raw level 1 page table entry. + * @child_table_dma_addr: DMA address of the level 0 page table to be + * associated with @entry. + * + * When calling this function, @child_table_dma_addr must be a valid DMA + * address and a multiple of 4 KiB. + */ +static void +pvr_page_table_l1_entry_raw_set(struct pvr_page_table_l1_entry_raw *entry, + dma_addr_t child_table_dma_addr) +{ + WRITE_ONCE(entry->val, + PVR_PAGE_TABLE_FIELD_PREP(1, PD, VALID, true) | + PVR_PAGE_TABLE_FIELD_PREP(1, PD, ENTRY_PENDING, false) | + PVR_PAGE_TABLE_FIELD_PREP(1, PD, PAGE_SIZE, ROGUE_MMUCTRL_PAGE_SIZE_X) | + /* + * The use of a 4K-specific macro here is correct. It is + * a future optimization to allocate sub-host-page-sized + * blocks for individual tables, so the condition that any + * page table address is aligned to the size of the + * largest (a 4KB) table currently holds. + */ + (child_table_dma_addr & ~ROGUE_MMUCTRL_PT_BASE_4KB_RANGE_CLRMSK)); +} + +static void +pvr_page_table_l1_entry_raw_clear(struct pvr_page_table_l1_entry_raw *entry) +{ + WRITE_ONCE(entry->val, 0); +} + +/** + * struct pvr_page_table_l0_entry_raw - A single entry in a level 0 page table. + * @val: The raw value of this entry. + * + * This type is a structure for type-checking purposes. At compile-time, its + * size is checked against %ROGUE_MMUCTRL_ENTRY_SIZE_PT_VALUE. + * + * The value stored in this structure can be decoded using the following bitmap: + * + * .. flat-table:: + * :widths: 1 5 + * :stub-columns: 1 + * + * * - 63 + * - *(reserved)* + * + * * - 62 + * - **PM/FW Protect:** Indicates a protected region which only the + * Parameter Manager (PM) or firmware processor can write to. + * + * * - 61..40 + * - **VP Page (High):** Virtual-physical page used for Parameter Manager + * (PM) memory. This field is only used if the additional level of PB + * virtualization is enabled. The VP Page field is needed by the PM in + * order to correctly reconstitute the free lists after render + * completion. This (High) field holds bits 39..18 of the value; the + * Low field holds bits 17..12. Bits 11..0 are always zero because the + * value is always aligned to the 4KiB page size. + * + * * - 39..12 + * - **Physical Page Address:** The way this value is interpreted depends + * on the page size. Bits not specified in the table below (e.g. bits + * 20..12 for page size 2MiB) should be considered reserved. + * + * This table shows the bits used in an L0 page table entry to represent + * the Physical Page Address for a given page size (as defined in the + * associated L1 page table entry). + * + * .. flat-table:: + * :widths: 1 1 + * :header-rows: 1 + * :stub-columns: 1 + * + * * - Page size + * - Physical address bits + * + * * - 4KiB + * - 39..12 + * + * * - 16KiB + * - 39..14 + * + * * - 64KiB + * - 39..16 + * + * * - 256KiB + * - 39..18 + * + * * - 1MiB + * - 39..20 + * + * * - 2MiB + * - 39..21 + * + * * - 11..6 + * - **VP Page (Low):** Continuation of VP Page (High). + * + * * - 5 + * - **Pending:** When valid bit is not set, indicates that a valid entry + * is pending and the MMU should wait for the driver to map the entry. + * This is used to support page demand mapping of memory. + * + * * - 4 + * - **PM Src:** Set on Parameter Manager (PM) allocated page table + * entries when indicated by the PM. Note that this bit will only be set + * by the PM, not by the device driver. + * + * * - 3 + * - **SLC Bypass Control:** Specifies requests to this page should bypass + * the System Level Cache (SLC), if enabled in SLC configuration. + * + * * - 2 + * - **Cache Coherency:** Indicates that the page is coherent (i.e. it + * does not require a cache flush between operations on the CPU and the + * device). + * + * * - 1 + * - **Read Only:** If set, this bit indicates that the page is read only. + * An attempted write to this page would result in a write-protection + * fault. + * + * * - 0 + * - **Valid:** Indicates that the entry contains a valid page. If the + * valid bit is not set, then an attempted use of the page would result + * in a page fault. + */ +struct pvr_page_table_l0_entry_raw { + u64 val; +} __packed; +static_assert(sizeof(struct pvr_page_table_l0_entry_raw) * 8 == + ROGUE_MMUCTRL_ENTRY_SIZE_PT_VALUE); + +/** + * struct pvr_page_flags_raw - The configurable flags from a single entry in a + * level 0 page table. + * @val: The raw value of these flags. Since these are a strict subset of + * &struct pvr_page_table_l0_entry_raw; use that type for our member here. + * + * The flags stored in this type are: PM/FW Protect; SLC Bypass Control; Cache + * Coherency, and Read Only (bits 62, 3, 2 and 1 respectively). + * + * This type should never be instantiated directly; instead use + * pvr_page_flags_raw_create() to ensure only valid bits of @val are set. + */ +struct pvr_page_flags_raw { + struct pvr_page_table_l0_entry_raw val; +} __packed; +static_assert(sizeof(struct pvr_page_flags_raw) == + sizeof(struct pvr_page_table_l0_entry_raw)); + +static bool +pvr_page_table_l0_entry_raw_is_valid(struct pvr_page_table_l0_entry_raw entry) +{ + return PVR_PAGE_TABLE_FIELD_GET(0, PT, VALID, entry); +} + +/** + * pvr_page_table_l0_entry_raw_set() - Write a valid entry into a raw level 0 + * page table. + * @entry: Target raw level 0 page table entry. + * @dma_addr: DMA address of the physical page to be associated with @entry. + * @flags: Options to be set on @entry. + * + * When calling this function, @child_table_dma_addr must be a valid DMA + * address and a multiple of %PVR_DEVICE_PAGE_SIZE. + * + * The @flags parameter is directly assigned into @entry. It is the callers + * responsibility to ensure that only bits specified in + * &struct pvr_page_flags_raw are set in @flags. + */ +static void +pvr_page_table_l0_entry_raw_set(struct pvr_page_table_l0_entry_raw *entry, + dma_addr_t dma_addr, + struct pvr_page_flags_raw flags) +{ + WRITE_ONCE(entry->val, PVR_PAGE_TABLE_FIELD_PREP(0, PT, VALID, true) | + PVR_PAGE_TABLE_FIELD_PREP(0, PT, ENTRY_PENDING, false) | + (dma_addr & ~ROGUE_MMUCTRL_PAGE_X_RANGE_CLRMSK) | + flags.val.val); +} + +static void +pvr_page_table_l0_entry_raw_clear(struct pvr_page_table_l0_entry_raw *entry) +{ + WRITE_ONCE(entry->val, 0); +} + +/** + * pvr_page_flags_raw_create() - Initialize the flag bits of a raw level 0 page + * table entry. + * @read_only: This page is read-only (see: Read Only). + * @cache_coherent: This page does not require cache flushes (see: Cache + * Coherency). + * @slc_bypass: This page bypasses the device cache (see: SLC Bypass Control). + * @pm_fw_protect: This page is only for use by the firmware or Parameter + * Manager (see PM/FW Protect). + * + * For more details on the use of these four options, see their respective + * entries in the table under &struct pvr_page_table_l0_entry_raw. + * + * Return: + * A new &struct pvr_page_flags_raw instance which can be passed directly to + * pvr_page_table_l0_entry_raw_set() or pvr_page_table_l0_insert(). + */ +static struct pvr_page_flags_raw +pvr_page_flags_raw_create(bool read_only, bool cache_coherent, bool slc_bypass, + bool pm_fw_protect) +{ + struct pvr_page_flags_raw flags; + + flags.val.val = + PVR_PAGE_TABLE_FIELD_PREP(0, PT, READ_ONLY, read_only) | + PVR_PAGE_TABLE_FIELD_PREP(0, PT, CC, cache_coherent) | + PVR_PAGE_TABLE_FIELD_PREP(0, PT, SLC_BYPASS_CTRL, slc_bypass) | + PVR_PAGE_TABLE_FIELD_PREP(0, PT, PM_META_PROTECT, pm_fw_protect); + + return flags; +} + +/** + * struct pvr_page_table_l2_raw - The raw data of a level 2 page table. + * + * This type is a structure for type-checking purposes. At compile-time, its + * size is checked against %PVR_MMU_BACKING_PAGE_SIZE. + */ +struct pvr_page_table_l2_raw { + /** @entries: The raw values of this table. */ + struct pvr_page_table_l2_entry_raw + entries[ROGUE_MMUCTRL_ENTRIES_PC_VALUE]; +} __packed; +static_assert(sizeof(struct pvr_page_table_l2_raw) == PVR_MMU_BACKING_PAGE_SIZE); + +/** + * struct pvr_page_table_l1_raw - The raw data of a level 1 page table. + * + * This type is a structure for type-checking purposes. At compile-time, its + * size is checked against %PVR_MMU_BACKING_PAGE_SIZE. + */ +struct pvr_page_table_l1_raw { + /** @entries: The raw values of this table. */ + struct pvr_page_table_l1_entry_raw + entries[ROGUE_MMUCTRL_ENTRIES_PD_VALUE]; +} __packed; +static_assert(sizeof(struct pvr_page_table_l1_raw) == PVR_MMU_BACKING_PAGE_SIZE); + +/** + * struct pvr_page_table_l0_raw - The raw data of a level 0 page table. + * + * This type is a structure for type-checking purposes. At compile-time, its + * size is checked against %PVR_MMU_BACKING_PAGE_SIZE. + * + * .. caution:: + * + * The size of level 0 page tables is variable depending on the page size + * specified in the associated level 1 page table entry. Since the device + * page size in use is pegged to the host page size, it cannot vary at + * runtime. This structure is therefore only defined to contain the required + * number of entries for the current device page size. **You should never + * read or write beyond the last supported entry.** + */ +struct pvr_page_table_l0_raw { + /** @entries: The raw values of this table. */ + struct pvr_page_table_l0_entry_raw + entries[ROGUE_MMUCTRL_ENTRIES_PT_VALUE_X]; +} __packed; +static_assert(sizeof(struct pvr_page_table_l0_raw) <= PVR_MMU_BACKING_PAGE_SIZE); + +/** + * DOC: Mirror page tables + */ + +/* + * We pre-declare these types because they cross-depend on pointers to each + * other. + */ +struct pvr_page_table_l1; +struct pvr_page_table_l0; + +/** + * struct pvr_page_table_l2 - A wrapped level 2 page table. + * + * To access the raw part of this table, use pvr_page_table_l2_get_raw(). + * Alternatively to access a raw entry directly, use + * pvr_page_table_l2_get_entry_raw(). + * + * A level 2 page table forms the root of the page table tree structure, so + * this type has no &parent or &parent_idx members. + */ +struct pvr_page_table_l2 { + /** + * @entries: The children of this node in the page table tree + * structure. These are also mirror tables. The indexing of this array + * is identical to that of the raw equivalent + * (&pvr_page_table_l1_raw.entries). + */ + struct pvr_page_table_l1 *entries[ROGUE_MMUCTRL_ENTRIES_PC_VALUE]; + + /** + * @backing_page: A handle to the memory which holds the raw + * equivalent of this table. **For internal use only.** + */ + struct pvr_mmu_backing_page backing_page; + + /** + * @entry_count: The current number of valid entries (that we know of) + * in this table. This value is essentially a refcount - the table is + * destroyed when this value is decremented to zero by + * pvr_page_table_l2_remove(). + */ + u16 entry_count; +}; + +/** + * pvr_page_table_l2_init() - Initialize a level 2 page table. + * @table: Target level 2 page table. + * @pvr_dev: Target PowerVR device + * + * It is expected that @table be zeroed (e.g. from kzalloc()) before calling + * this function. + * + * Return: + * * 0 on success, or + * * Any error encountered while intializing &table->backing_page using + * pvr_mmu_backing_page_init(). + */ +static int +pvr_page_table_l2_init(struct pvr_page_table_l2 *table, + struct pvr_device *pvr_dev) +{ + return pvr_mmu_backing_page_init(&table->backing_page, pvr_dev); +} + +/** + * pvr_page_table_l2_fini() - Teardown a level 2 page table. + * @table: Target level 2 page table. + * + * It is an error to attempt to use @table after calling this function. + */ +static void +pvr_page_table_l2_fini(struct pvr_page_table_l2 *table) +{ + pvr_mmu_backing_page_fini(&table->backing_page); +} + +/** + * pvr_page_table_l2_sync() - Flush a level 2 page table from the CPU to the + * device. + * @table: Target level 2 page table. + * + * This is just a thin wrapper around pvr_mmu_backing_page_sync(), so the + * warning there applies here too: **Only call pvr_page_table_l2_sync() once + * you're sure you have no more changes to make to** @table **in the immediate + * future.** + * + * If child level 1 page tables of @table also need to be flushed, this should + * be done first using pvr_page_table_l1_sync() *before* calling this function. + */ +static void +pvr_page_table_l2_sync(struct pvr_page_table_l2 *table) +{ + pvr_mmu_backing_page_sync(&table->backing_page, PVR_MMU_SYNC_LEVEL_2_FLAGS); +} + +/** + * pvr_page_table_l2_get_raw() - Access the raw equivalent of a mirror level 2 + * page table. + * @table: Target level 2 page table. + * + * Essentially returns the CPU address of the raw equivalent of @table, cast to + * a &struct pvr_page_table_l2_raw pointer. + * + * You probably want to call pvr_page_table_l2_get_entry_raw() instead. + * + * Return: + * The raw equivalent of @table. + */ +static struct pvr_page_table_l2_raw * +pvr_page_table_l2_get_raw(struct pvr_page_table_l2 *table) +{ + return table->backing_page.host_ptr; +} + +/** + * pvr_page_table_l2_get_entry_raw() - Access an entry from the raw equivalent + * of a mirror level 2 page table. + * @table: Target level 2 page table. + * @idx: Index of the entry to access. + * + * Technically this function returns a pointer to a slot in a raw level 2 page + * table, since the returned "entry" is not guaranteed to be valid. The caller + * must verify the validity of the entry at the returned address (perhaps using + * pvr_page_table_l2_entry_raw_is_valid()) before reading or overwriting it. + * + * The value of @idx is not checked here; it is the callers responsibility to + * ensure @idx refers to a valid index within @table before dereferencing the + * returned pointer. + * + * Return: + * A pointer to the requested raw level 2 page table entry. + */ +static struct pvr_page_table_l2_entry_raw * +pvr_page_table_l2_get_entry_raw(struct pvr_page_table_l2 *table, u16 idx) +{ + return &pvr_page_table_l2_get_raw(table)->entries[idx]; +} + +/** + * pvr_page_table_l2_entry_is_valid() - Check if a level 2 page table entry is + * marked as valid. + * @table: Target level 2 page table. + * @idx: Index of the entry to check. + * + * The value of @idx is not checked here; it is the callers responsibility to + * ensure @idx refers to a valid index within @table before calling this + * function. + */ +static bool +pvr_page_table_l2_entry_is_valid(struct pvr_page_table_l2 *table, u16 idx) +{ + struct pvr_page_table_l2_entry_raw entry_raw = + *pvr_page_table_l2_get_entry_raw(table, idx); + + return pvr_page_table_l2_entry_raw_is_valid(entry_raw); +} + +/** + * struct pvr_page_table_l1 - A wrapped level 1 page table. + * + * To access the raw part of this table, use pvr_page_table_l1_get_raw(). + * Alternatively to access a raw entry directly, use + * pvr_page_table_l1_get_entry_raw(). + */ +struct pvr_page_table_l1 { + /** + * @entries: The children of this node in the page table tree + * structure. These are also mirror tables. The indexing of this array + * is identical to that of the raw equivalent + * (&pvr_page_table_l0_raw.entries). + */ + struct pvr_page_table_l0 *entries[ROGUE_MMUCTRL_ENTRIES_PD_VALUE]; + + /** + * @backing_page: A handle to the memory which holds the raw + * equivalent of this table. **For internal use only.** + */ + struct pvr_mmu_backing_page backing_page; + + union { + /** + * @parent: The parent of this node in the page table tree structure. + * + * This is also a mirror table. + * + * Only valid when the L1 page table is active. When the L1 page table + * has been removed and queued for destruction, the next_free field + * should be used instead. + */ + struct pvr_page_table_l2 *parent; + + /** + * @next_free: Pointer to the next L1 page table to take/free. + * + * Used to form a linked list of L1 page tables. This is used + * when preallocating tables and when the page table has been + * removed and queued for destruction. + */ + struct pvr_page_table_l1 *next_free; + }; + + /** + * @parent_idx: The index of the entry in the parent table (see + * @parent) which corresponds to this table. + */ + u16 parent_idx; + + /** + * @entry_count: The current number of valid entries (that we know of) + * in this table. This value is essentially a refcount - the table is + * destroyed when this value is decremented to zero by + * pvr_page_table_l1_remove(). + */ + u16 entry_count; +}; + +/** + * pvr_page_table_l1_init() - Initialize a level 1 page table. + * @table: Target level 1 page table. + * @pvr_dev: Target PowerVR device + * + * When this function returns successfully, @table is still not considered + * valid. It must be inserted into the page table tree structure with + * pvr_page_table_l2_insert() before it is ready for use. + * + * It is expected that @table be zeroed (e.g. from kzalloc()) before calling + * this function. + * + * Return: + * * 0 on success, or + * * Any error encountered while intializing &table->backing_page using + * pvr_mmu_backing_page_init(). + */ +static int +pvr_page_table_l1_init(struct pvr_page_table_l1 *table, + struct pvr_device *pvr_dev) +{ + table->parent_idx = PVR_IDX_INVALID; + + return pvr_mmu_backing_page_init(&table->backing_page, pvr_dev); +} + +/** + * pvr_page_table_l1_free() - Teardown a level 1 page table. + * @table: Target level 1 page table. + * + * It is an error to attempt to use @table after calling this function, even + * indirectly. This includes calling pvr_page_table_l2_remove(), which must + * be called *before* pvr_page_table_l1_free(). + */ +static void +pvr_page_table_l1_free(struct pvr_page_table_l1 *table) +{ + pvr_mmu_backing_page_fini(&table->backing_page); + kfree(table); +} + +/** + * pvr_page_table_l1_sync() - Flush a level 1 page table from the CPU to the + * device. + * @table: Target level 1 page table. + * + * This is just a thin wrapper around pvr_mmu_backing_page_sync(), so the + * warning there applies here too: **Only call pvr_page_table_l1_sync() once + * you're sure you have no more changes to make to** @table **in the immediate + * future.** + * + * If child level 0 page tables of @table also need to be flushed, this should + * be done first using pvr_page_table_l0_sync() *before* calling this function. + */ +static void +pvr_page_table_l1_sync(struct pvr_page_table_l1 *table) +{ + pvr_mmu_backing_page_sync(&table->backing_page, PVR_MMU_SYNC_LEVEL_1_FLAGS); +} + +/** + * pvr_page_table_l1_get_raw() - Access the raw equivalent of a mirror level 1 + * page table. + * @table: Target level 1 page table. + * + * Essentially returns the CPU address of the raw equivalent of @table, cast to + * a &struct pvr_page_table_l1_raw pointer. + * + * You probably want to call pvr_page_table_l1_get_entry_raw() instead. + * + * Return: + * The raw equivalent of @table. + */ +static struct pvr_page_table_l1_raw * +pvr_page_table_l1_get_raw(struct pvr_page_table_l1 *table) +{ + return table->backing_page.host_ptr; +} + +/** + * pvr_page_table_l1_get_entry_raw() - Access an entry from the raw equivalent + * of a mirror level 1 page table. + * @table: Target level 1 page table. + * @idx: Index of the entry to access. + * + * Technically this function returns a pointer to a slot in a raw level 1 page + * table, since the returned "entry" is not guaranteed to be valid. The caller + * must verify the validity of the entry at the returned address (perhaps using + * pvr_page_table_l1_entry_raw_is_valid()) before reading or overwriting it. + * + * The value of @idx is not checked here; it is the callers responsibility to + * ensure @idx refers to a valid index within @table before dereferencing the + * returned pointer. + * + * Return: + * A pointer to the requested raw level 1 page table entry. + */ +static struct pvr_page_table_l1_entry_raw * +pvr_page_table_l1_get_entry_raw(struct pvr_page_table_l1 *table, u16 idx) +{ + return &pvr_page_table_l1_get_raw(table)->entries[idx]; +} + +/** + * pvr_page_table_l1_entry_is_valid() - Check if a level 1 page table entry is + * marked as valid. + * @table: Target level 1 page table. + * @idx: Index of the entry to check. + * + * The value of @idx is not checked here; it is the callers responsibility to + * ensure @idx refers to a valid index within @table before calling this + * function. + */ +static bool +pvr_page_table_l1_entry_is_valid(struct pvr_page_table_l1 *table, u16 idx) +{ + struct pvr_page_table_l1_entry_raw entry_raw = + *pvr_page_table_l1_get_entry_raw(table, idx); + + return pvr_page_table_l1_entry_raw_is_valid(entry_raw); +} + +/** + * struct pvr_page_table_l0 - A wrapped level 0 page table. + * + * To access the raw part of this table, use pvr_page_table_l0_get_raw(). + * Alternatively to access a raw entry directly, use + * pvr_page_table_l0_get_entry_raw(). + * + * There is no mirror representation of an individual page, so this type has no + * &entries member. + */ +struct pvr_page_table_l0 { + /** + * @backing_page: A handle to the memory which holds the raw + * equivalent of this table. **For internal use only.** + */ + struct pvr_mmu_backing_page backing_page; + + union { + /** + * @parent: The parent of this node in the page table tree structure. + * + * This is also a mirror table. + * + * Only valid when the L0 page table is active. When the L0 page table + * has been removed and queued for destruction, the next_free field + * should be used instead. + */ + struct pvr_page_table_l1 *parent; + + /** + * @next_free: Pointer to the next L0 page table to take/free. + * + * Used to form a linked list of L0 page tables. This is used + * when preallocating tables and when the page table has been + * removed and queued for destruction. + */ + struct pvr_page_table_l0 *next_free; + }; + + /** + * @parent_idx: The index of the entry in the parent table (see + * @parent) which corresponds to this table. + */ + u16 parent_idx; + + /** + * @entry_count: The current number of valid entries (that we know of) + * in this table. This value is essentially a refcount - the table is + * destroyed when this value is decremented to zero by + * pvr_page_table_l0_remove(). + */ + u16 entry_count; +}; + +/** + * pvr_page_table_l0_init() - Initialize a level 0 page table. + * @table: Target level 0 page table. + * @pvr_dev: Target PowerVR device + * + * When this function returns successfully, @table is still not considered + * valid. It must be inserted into the page table tree structure with + * pvr_page_table_l1_insert() before it is ready for use. + * + * It is expected that @table be zeroed (e.g. from kzalloc()) before calling + * this function. + * + * Return: + * * 0 on success, or + * * Any error encountered while intializing &table->backing_page using + * pvr_mmu_backing_page_init(). + */ +static int +pvr_page_table_l0_init(struct pvr_page_table_l0 *table, + struct pvr_device *pvr_dev) +{ + table->parent_idx = PVR_IDX_INVALID; + + return pvr_mmu_backing_page_init(&table->backing_page, pvr_dev); +} + +/** + * pvr_page_table_l0_free() - Teardown a level 0 page table. + * @table: Target level 0 page table. + * + * It is an error to attempt to use @table after calling this function, even + * indirectly. This includes calling pvr_page_table_l1_remove(), which must + * be called *before* pvr_page_table_l0_free(). + */ +static void +pvr_page_table_l0_free(struct pvr_page_table_l0 *table) +{ + pvr_mmu_backing_page_fini(&table->backing_page); + kfree(table); +} + +/** + * pvr_page_table_l0_sync() - Flush a level 0 page table from the CPU to the + * device. + * @table: Target level 0 page table. + * + * This is just a thin wrapper around pvr_mmu_backing_page_sync(), so the + * warning there applies here too: **Only call pvr_page_table_l0_sync() once + * you're sure you have no more changes to make to** @table **in the immediate + * future.** + * + * If child pages of @table also need to be flushed, this should be done first + * using a DMA sync function (e.g. dma_sync_sg_for_device()) *before* calling + * this function. + */ +static void +pvr_page_table_l0_sync(struct pvr_page_table_l0 *table) +{ + pvr_mmu_backing_page_sync(&table->backing_page, PVR_MMU_SYNC_LEVEL_0_FLAGS); +} + +/** + * pvr_page_table_l0_get_raw() - Access the raw equivalent of a mirror level 0 + * page table. + * @table: Target level 0 page table. + * + * Essentially returns the CPU address of the raw equivalent of @table, cast to + * a &struct pvr_page_table_l0_raw pointer. + * + * You probably want to call pvr_page_table_l0_get_entry_raw() instead. + * + * Return: + * The raw equivalent of @table. + */ +static struct pvr_page_table_l0_raw * +pvr_page_table_l0_get_raw(struct pvr_page_table_l0 *table) +{ + return table->backing_page.host_ptr; +} + +/** + * pvr_page_table_l0_get_entry_raw() - Access an entry from the raw equivalent + * of a mirror level 0 page table. + * @table: Target level 0 page table. + * @idx: Index of the entry to access. + * + * Technically this function returns a pointer to a slot in a raw level 0 page + * table, since the returned "entry" is not guaranteed to be valid. The caller + * must verify the validity of the entry at the returned address (perhaps using + * pvr_page_table_l0_entry_raw_is_valid()) before reading or overwriting it. + * + * The value of @idx is not checked here; it is the callers responsibility to + * ensure @idx refers to a valid index within @table before dereferencing the + * returned pointer. This is espcially important for level 0 page tables, which + * can have a variable number of entries. + * + * Return: + * A pointer to the requested raw level 0 page table entry. + */ +static struct pvr_page_table_l0_entry_raw * +pvr_page_table_l0_get_entry_raw(struct pvr_page_table_l0 *table, u16 idx) +{ + return &pvr_page_table_l0_get_raw(table)->entries[idx]; +} + +/** + * pvr_page_table_l0_entry_is_valid() - Check if a level 0 page table entry is + * marked as valid. + * @table: Target level 0 page table. + * @idx: Index of the entry to check. + * + * The value of @idx is not checked here; it is the callers responsibility to + * ensure @idx refers to a valid index within @table before calling this + * function. + */ +static bool +pvr_page_table_l0_entry_is_valid(struct pvr_page_table_l0 *table, u16 idx) +{ + struct pvr_page_table_l0_entry_raw entry_raw = + *pvr_page_table_l0_get_entry_raw(table, idx); + + return pvr_page_table_l0_entry_raw_is_valid(entry_raw); +} + +/** + * struct pvr_mmu_context - context holding data for operations at page + * catalogue level, intended for use with a VM context. + */ +struct pvr_mmu_context { + /** @pvr_dev: The PVR device associated with the owning VM context. */ + struct pvr_device *pvr_dev; + + /** @page_table_l2: The MMU table root. */ + struct pvr_page_table_l2 page_table_l2; +}; + +/** + * struct pvr_page_table_ptr - A reference to a single physical page as indexed + * by the page table structure. + * + * Intended for embedding in a &struct pvr_mmu_op_context. + */ +struct pvr_page_table_ptr { + /** + * @l1_table: A cached handle to the level 1 page table the + * context is currently traversing. + */ + struct pvr_page_table_l1 *l1_table; + + /** + * @l0_table: A cached handle to the level 0 page table the + * context is currently traversing. + */ + struct pvr_page_table_l0 *l0_table; + + /** + * @l2_idx: Index into the level 2 page table the context is + * currently referencing. + */ + u16 l2_idx; + + /** + * @l1_idx: Index into the level 1 page table the context is + * currently referencing. + */ + u16 l1_idx; + + /** + * @l0_idx: Index into the level 0 page table the context is + * currently referencing. + */ + u16 l0_idx; +}; + +/** + * struct pvr_mmu_op_context - context holding data for individual + * device-virtual mapping operations. Intended for use with a VM bind operation. + */ +struct pvr_mmu_op_context { + /** @mmu_ctx: The MMU context associated with the owning VM context. */ + struct pvr_mmu_context *mmu_ctx; + + /** @map: Data specifically for map operations. */ + struct { + /** + * @sgt: Scatter gather table containing pages pinned for use by + * this context - these are currently pinned when initialising + * the VM bind operation. + */ + struct sg_table *sgt; + + /** @sgt_offset: Start address of the device-virtual mapping. */ + u64 sgt_offset; + + /** + * @l1_prealloc_tables: Preallocated l1 page table objects + * use by this context when creating a page mapping. Linked list + * fully created during initialisation. + */ + struct pvr_page_table_l1 *l1_prealloc_tables; + + /** + * @l0_prealloc_tables: Preallocated l0 page table objects + * use by this context when creating a page mapping. Linked list + * fully created during initialisation. + */ + struct pvr_page_table_l0 *l0_prealloc_tables; + } map; + + /** @unmap: Data specifically for unmap operations. */ + struct { + /** + * @l1_free_tables: Collects page table objects freed by unmap + * ops. Linked list empty at creation. + */ + struct pvr_page_table_l1 *l1_free_tables; + + /** + * @l0_free_tables: Collects page table objects freed by unmap + * ops. Linked list empty at creation. + */ + struct pvr_page_table_l0 *l0_free_tables; + } unmap; + + /** + * @curr_page: A reference to a single physical page as indexed by the + * page table structure. + */ + struct pvr_page_table_ptr curr_page; + + /** + * @sync_level_required: The maximum level of the page table tree + * structure which has (possibly) been modified since it was last + * flushed to the device. + * + * This field should only be set with pvr_mmu_op_context_require_sync() + * or indirectly by pvr_mmu_op_context_sync_partial(). + */ + enum pvr_mmu_sync_level sync_level_required; +}; + +/** + * pvr_page_table_l2_insert() - Insert an entry referring to a level 1 page + * table into a level 2 page table. + * @op_ctx: Target MMU op context pointing at the entry to insert the L1 page + * table into. + * @child_table: Target level 1 page table to be referenced by the new entry. + * + * It is the caller's responsibility to ensure @op_ctx.curr_page points to a + * valid L2 entry. + * + * It is the caller's responsibility to execute any memory barries to ensure + * that the creation of @child_table is ordered before the L2 entry is inserted. + */ +static void +pvr_page_table_l2_insert(struct pvr_mmu_op_context *op_ctx, + struct pvr_page_table_l1 *child_table) +{ + struct pvr_page_table_l2 *l2_table = + &op_ctx->mmu_ctx->page_table_l2; + struct pvr_page_table_l2_entry_raw *entry_raw = + pvr_page_table_l2_get_entry_raw(l2_table, + op_ctx->curr_page.l2_idx); + + pvr_page_table_l2_entry_raw_set(entry_raw, + child_table->backing_page.dma_addr); + + child_table->parent = l2_table; + child_table->parent_idx = op_ctx->curr_page.l2_idx; + l2_table->entries[op_ctx->curr_page.l2_idx] = child_table; + ++l2_table->entry_count; + op_ctx->curr_page.l1_table = child_table; +} + +/** + * pvr_page_table_l2_remove() - Remove a level 1 page table from a level 2 page + * table. + * @op_ctx: Target MMU op context pointing at the L2 entry to remove. + * + * It is the caller's responsibility to ensure @op_ctx.curr_page points to a + * valid L2 entry. + */ +static void +pvr_page_table_l2_remove(struct pvr_mmu_op_context *op_ctx) +{ + struct pvr_page_table_l2 *l2_table = + &op_ctx->mmu_ctx->page_table_l2; + struct pvr_page_table_l2_entry_raw *entry_raw = + pvr_page_table_l2_get_entry_raw(l2_table, + op_ctx->curr_page.l1_table->parent_idx); + + WARN_ON(op_ctx->curr_page.l1_table->parent != l2_table); + + pvr_page_table_l2_entry_raw_clear(entry_raw); + + l2_table->entries[op_ctx->curr_page.l1_table->parent_idx] = NULL; + op_ctx->curr_page.l1_table->parent_idx = PVR_IDX_INVALID; + op_ctx->curr_page.l1_table->next_free = op_ctx->unmap.l1_free_tables; + op_ctx->unmap.l1_free_tables = op_ctx->curr_page.l1_table; + op_ctx->curr_page.l1_table = NULL; + + --l2_table->entry_count; +} + +/** + * pvr_page_table_l1_insert() - Insert an entry referring to a level 0 page + * table into a level 1 page table. + * @op_ctx: Target MMU op context pointing at the entry to insert the L0 page + * table into. + * @child_table: L0 page table to insert. + * + * It is the caller's responsibility to ensure @op_ctx.curr_page points to a + * valid L1 entry. + * + * It is the caller's responsibility to execute any memory barries to ensure + * that the creation of @child_table is ordered before the L1 entry is inserted. + */ +static void +pvr_page_table_l1_insert(struct pvr_mmu_op_context *op_ctx, + struct pvr_page_table_l0 *child_table) +{ + struct pvr_page_table_l1_entry_raw *entry_raw = + pvr_page_table_l1_get_entry_raw(op_ctx->curr_page.l1_table, + op_ctx->curr_page.l1_idx); + + pvr_page_table_l1_entry_raw_set(entry_raw, + child_table->backing_page.dma_addr); + + child_table->parent = op_ctx->curr_page.l1_table; + child_table->parent_idx = op_ctx->curr_page.l1_idx; + op_ctx->curr_page.l1_table->entries[op_ctx->curr_page.l1_idx] = child_table; + ++op_ctx->curr_page.l1_table->entry_count; + op_ctx->curr_page.l0_table = child_table; +} + +/** + * pvr_page_table_l1_remove() - Remove a level 0 page table from a level 1 page + * table. + * @op_ctx: Target MMU op context pointing at the L1 entry to remove. + * + * If this function results in the L1 table becoming empty, it will be removed + * from its parent level 2 page table and destroyed. + * + * It is the caller's responsibility to ensure @op_ctx.curr_page points to a + * valid L1 entry. + */ +static void +pvr_page_table_l1_remove(struct pvr_mmu_op_context *op_ctx) +{ + struct pvr_page_table_l1_entry_raw *entry_raw = + pvr_page_table_l1_get_entry_raw(op_ctx->curr_page.l0_table->parent, + op_ctx->curr_page.l0_table->parent_idx); + + WARN_ON(op_ctx->curr_page.l0_table->parent != + op_ctx->curr_page.l1_table); + + pvr_page_table_l1_entry_raw_clear(entry_raw); + + op_ctx->curr_page.l1_table->entries[op_ctx->curr_page.l0_table->parent_idx] = NULL; + op_ctx->curr_page.l0_table->parent_idx = PVR_IDX_INVALID; + op_ctx->curr_page.l0_table->next_free = op_ctx->unmap.l0_free_tables; + op_ctx->unmap.l0_free_tables = op_ctx->curr_page.l0_table; + op_ctx->curr_page.l0_table = NULL; + + if (--op_ctx->curr_page.l1_table->entry_count == 0) { + /* Clear the parent L2 page table entry. */ + if (op_ctx->curr_page.l1_table->parent_idx != PVR_IDX_INVALID) + pvr_page_table_l2_remove(op_ctx); + } +} + +/** + * pvr_page_table_l0_insert() - Insert an entry referring to a physical page + * into a level 0 page table. + * @op_ctx: Target MMU op context pointing at the L0 entry to insert. + * @dma_addr: Target DMA address to be referenced by the new entry. + * @flags: Page options to be stored in the new entry. + * + * It is the caller's responsibility to ensure @op_ctx.curr_page points to a + * valid L0 entry. + */ +static void +pvr_page_table_l0_insert(struct pvr_mmu_op_context *op_ctx, + dma_addr_t dma_addr, struct pvr_page_flags_raw flags) +{ + struct pvr_page_table_l0_entry_raw *entry_raw = + pvr_page_table_l0_get_entry_raw(op_ctx->curr_page.l0_table, + op_ctx->curr_page.l0_idx); + + pvr_page_table_l0_entry_raw_set(entry_raw, dma_addr, flags); + + /* + * There is no entry to set here - we don't keep a mirror of + * individual pages. + */ + + ++op_ctx->curr_page.l0_table->entry_count; +} + +/** + * pvr_page_table_l0_remove() - Remove a physical page from a level 0 page + * table. + * @op_ctx: Target MMU op context pointing at the L0 entry to remove. + * + * If this function results in the L0 table becoming empty, it will be removed + * from its parent L1 page table and destroyed. + * + * It is the caller's responsibility to ensure @op_ctx.curr_page points to a + * valid L0 entry. + */ +static void +pvr_page_table_l0_remove(struct pvr_mmu_op_context *op_ctx) +{ + struct pvr_page_table_l0_entry_raw *entry_raw = + pvr_page_table_l0_get_entry_raw(op_ctx->curr_page.l0_table, + op_ctx->curr_page.l0_idx); + + pvr_page_table_l0_entry_raw_clear(entry_raw); + + /* + * There is no entry to clear here - we don't keep a mirror of + * individual pages. + */ + + if (--op_ctx->curr_page.l0_table->entry_count == 0) { + /* Clear the parent L1 page table entry. */ + if (op_ctx->curr_page.l0_table->parent_idx != PVR_IDX_INVALID) + pvr_page_table_l1_remove(op_ctx); + } +} + +/** + * DOC: Page table index utilities + */ + +/** + * pvr_page_table_l2_idx() - Calculate the level 2 page table index for a + * device-virtual address. + * @device_addr: Target device-virtual address. + * + * This function does not perform any bounds checking - it is the caller's + * responsibility to ensure that @device_addr is valid before interpreting + * the result. + * + * Return: + * The index into a level 2 page table corresponding to @device_addr. + */ +static u16 +pvr_page_table_l2_idx(u64 device_addr) +{ + return (device_addr & ~ROGUE_MMUCTRL_VADDR_PC_INDEX_CLRMSK) >> + ROGUE_MMUCTRL_VADDR_PC_INDEX_SHIFT; +} + +/** + * pvr_page_table_l1_idx() - Calculate the level 1 page table index for a + * device-virtual address. + * @device_addr: Target device-virtual address. + * + * This function does not perform any bounds checking - it is the caller's + * responsibility to ensure that @device_addr is valid before interpreting + * the result. + * + * Return: + * The index into a level 1 page table corresponding to @device_addr. + */ +static u16 +pvr_page_table_l1_idx(u64 device_addr) +{ + return (device_addr & ~ROGUE_MMUCTRL_VADDR_PD_INDEX_CLRMSK) >> + ROGUE_MMUCTRL_VADDR_PD_INDEX_SHIFT; +} + +/** + * pvr_page_table_l0_idx() - Calculate the level 0 page table index for a + * device-virtual address. + * @device_addr: Target device-virtual address. + * + * This function does not perform any bounds checking - it is the caller's + * responsibility to ensure that @device_addr is valid before interpreting + * the result. + * + * Return: + * The index into a level 0 page table corresponding to @device_addr. + */ +static u16 +pvr_page_table_l0_idx(u64 device_addr) +{ + return (device_addr & ~ROGUE_MMUCTRL_VADDR_PT_INDEX_CLRMSK) >> + ROGUE_MMUCTRL_PAGE_X_RANGE_SHIFT; +} + +/** + * DOC: High-level page table operations + */ + +/** + * pvr_page_table_l1_get_or_insert() - Retrieves (optionally inserting if + * necessary) a level 1 page table from the specified level 2 page table entry. + * @op_ctx: Target MMU op context. + * @should_insert: [IN] Specifies whether new page tables should be inserted + * when empty page table entries are encountered during traversal. + * + * Return: + * * 0 on success, or + * + * If @should_insert is %false: + * * -%ENXIO if a level 1 page table would have been inserted. + * + * If @should_insert is %true: + * * Any error encountered while inserting the level 1 page table. + */ +static int +pvr_page_table_l1_get_or_insert(struct pvr_mmu_op_context *op_ctx, + bool should_insert) +{ + struct pvr_page_table_l2 *l2_table = + &op_ctx->mmu_ctx->page_table_l2; + struct pvr_page_table_l1 *table; + + if (pvr_page_table_l2_entry_is_valid(l2_table, + op_ctx->curr_page.l2_idx)) { + op_ctx->curr_page.l1_table = + l2_table->entries[op_ctx->curr_page.l2_idx]; + return 0; + } + + if (!should_insert) + return -ENXIO; + + /* Take a prealloced table. */ + table = op_ctx->map.l1_prealloc_tables; + if (!table) + return -ENOMEM; + + /* Pop */ + op_ctx->map.l1_prealloc_tables = table->next_free; + table->next_free = NULL; + + /* Ensure new table is fully written out before adding to L2 page table. */ + wmb(); + + pvr_page_table_l2_insert(op_ctx, table); + + return 0; +} + +/** + * pvr_page_table_l0_get_or_insert() - Retrieves (optionally inserting if + * necessary) a level 0 page table from the specified level 1 page table entry. + * @op_ctx: Target MMU op context. + * @should_insert: [IN] Specifies whether new page tables should be inserted + * when empty page table entries are encountered during traversal. + * + * Return: + * * 0 on success, + * + * If @should_insert is %false: + * * -%ENXIO if a level 0 page table would have been inserted. + * + * If @should_insert is %true: + * * Any error encountered while inserting the level 0 page table. + */ +static int +pvr_page_table_l0_get_or_insert(struct pvr_mmu_op_context *op_ctx, + bool should_insert) +{ + struct pvr_page_table_l0 *table; + + if (pvr_page_table_l1_entry_is_valid(op_ctx->curr_page.l1_table, + op_ctx->curr_page.l1_idx)) { + op_ctx->curr_page.l0_table = + op_ctx->curr_page.l1_table->entries[op_ctx->curr_page.l1_idx]; + return 0; + } + + if (!should_insert) + return -ENXIO; + + /* Take a prealloced table. */ + table = op_ctx->map.l0_prealloc_tables; + if (!table) + return -ENOMEM; + + /* Pop */ + op_ctx->map.l0_prealloc_tables = table->next_free; + table->next_free = NULL; + + /* Ensure new table is fully written out before adding to L1 page table. */ + wmb(); + + pvr_page_table_l1_insert(op_ctx, table); + + return 0; +} + +/** + * pvr_mmu_context_create() - Create an MMU context. + * @pvr_dev: PVR device associated with owning VM context. + * + * Returns: + * * Newly created MMU context object on success, or + * * -%ENOMEM if no memory is available, + * * Any error code returned by pvr_page_table_l2_init(). + */ +struct pvr_mmu_context *pvr_mmu_context_create(struct pvr_device *pvr_dev) +{ + struct pvr_mmu_context *ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + int err; + + if (!ctx) + return ERR_PTR(-ENOMEM); + + err = pvr_page_table_l2_init(&ctx->page_table_l2, pvr_dev); + if (err) + return ERR_PTR(err); + + ctx->pvr_dev = pvr_dev; + + return ctx; +} + +/** + * pvr_mmu_context_destroy() - Destroy an MMU context. + * @ctx: Target MMU context. + */ +void pvr_mmu_context_destroy(struct pvr_mmu_context *ctx) +{ + pvr_page_table_l2_fini(&ctx->page_table_l2); + kfree(ctx); +} + +/** + * pvr_mmu_get_root_table_dma_addr() - Get the DMA address of the root of the + * page table structure behind a VM context. + * @ctx: Target MMU context. + */ +dma_addr_t pvr_mmu_get_root_table_dma_addr(struct pvr_mmu_context *ctx) +{ + return ctx->page_table_l2.backing_page.dma_addr; +} + +/** + * pvr_page_table_l1_alloc() - Allocate a l1 page_table object. + * @ctx: MMU context of owning VM context. + * + * Returns: + * * Newly created page table object on success, or + * * -%ENOMEM if no memory is available, + * * Any error code returned by pvr_page_table_l1_init(). + */ +static struct pvr_page_table_l1 * +pvr_page_table_l1_alloc(struct pvr_mmu_context *ctx) +{ + int err; + + struct pvr_page_table_l1 *table = + kzalloc(sizeof(*table), GFP_KERNEL); + + if (!table) + return ERR_PTR(-ENOMEM); + + err = pvr_page_table_l1_init(table, ctx->pvr_dev); + if (err) { + kfree(table); + return ERR_PTR(err); + } + + return table; +} + +/** + * pvr_page_table_l0_alloc() - Allocate a l0 page_table object. + * @ctx: MMU context of owning VM context. + * + * Returns: + * * Newly created page table object on success, or + * * -%ENOMEM if no memory is available, + * * Any error code returned by pvr_page_table_l0_init(). + */ +static struct pvr_page_table_l0 * +pvr_page_table_l0_alloc(struct pvr_mmu_context *ctx) +{ + int err; + + struct pvr_page_table_l0 *table = + kzalloc(sizeof(*table), GFP_KERNEL); + + if (!table) + return ERR_PTR(-ENOMEM); + + err = pvr_page_table_l0_init(table, ctx->pvr_dev); + if (err) { + kfree(table); + return ERR_PTR(err); + } + + return table; +} + +/** + * pvr_mmu_op_context_require_sync() - Mark an MMU op context as requiring a + * sync operation for the referenced page tables up to a specified level. + * @op_ctx: Target MMU op context. + * @level: Maximum page table level for which a sync is required. + */ +static void +pvr_mmu_op_context_require_sync(struct pvr_mmu_op_context *op_ctx, + enum pvr_mmu_sync_level level) +{ + if (op_ctx->sync_level_required < level) + op_ctx->sync_level_required = level; +} + +/** + * pvr_mmu_op_context_sync_manual() - Trigger a sync of some or all of the + * page tables referenced by a MMU op context. + * @op_ctx: Target MMU op context. + * @level: Maximum page table level to sync. + * + * Do not call this function directly. Instead use + * pvr_mmu_op_context_sync_partial() which is checked against the current + * value of &op_ctx->sync_level_required as set by + * pvr_mmu_op_context_require_sync(). + */ +static void +pvr_mmu_op_context_sync_manual(struct pvr_mmu_op_context *op_ctx, + enum pvr_mmu_sync_level level) +{ + /* + * We sync the page table levels in ascending order (starting from the + * leaf node) to ensure consistency. + */ + + WARN_ON(level < PVR_MMU_SYNC_LEVEL_NONE); + + if (level <= PVR_MMU_SYNC_LEVEL_NONE) + return; + + if (op_ctx->curr_page.l0_table) + pvr_page_table_l0_sync(op_ctx->curr_page.l0_table); + + if (level < PVR_MMU_SYNC_LEVEL_1) + return; + + if (op_ctx->curr_page.l1_table) + pvr_page_table_l1_sync(op_ctx->curr_page.l1_table); + + if (level < PVR_MMU_SYNC_LEVEL_2) + return; + + pvr_page_table_l2_sync(&op_ctx->mmu_ctx->page_table_l2); +} + +/** + * pvr_mmu_op_context_sync_partial() - Trigger a sync of some or all of the + * page tables referenced by a MMU op context. + * @op_ctx: Target MMU op context. + * @level: Requested page table level to sync up to (inclusive). + * + * If @level is greater than the maximum level recorded by @op_ctx as requiring + * a sync operation, only the previously recorded maximum will be used. + * + * Additionally, if @level is greater than or equal to the maximum level + * recorded by @op_ctx as requiring a sync operation, that maximum level will be + * reset as a full sync will be performed. This is equivalent to calling + * pvr_mmu_op_context_sync(). + */ +static void +pvr_mmu_op_context_sync_partial(struct pvr_mmu_op_context *op_ctx, + enum pvr_mmu_sync_level level) +{ + /* + * If the requested sync level is greater than or equal to the + * currently required sync level, we do two things: + * * Don't waste time syncing levels we haven't previously marked as + * requiring a sync, and + * * Reset the required sync level since we are about to sync + * everything that was previously marked as requiring a sync. + */ + if (level >= op_ctx->sync_level_required) { + level = op_ctx->sync_level_required; + op_ctx->sync_level_required = PVR_MMU_SYNC_LEVEL_NONE; + } + + pvr_mmu_op_context_sync_manual(op_ctx, level); +} + +/** + * pvr_mmu_op_context_sync() - Trigger a sync of every page table referenced by + * a MMU op context. + * @op_ctx: Target MMU op context. + * + * The maximum level marked internally as requiring a sync will be reset so + * that subsequent calls to this function will be no-ops unless @op_ctx is + * otherwise updated. + */ +static void +pvr_mmu_op_context_sync(struct pvr_mmu_op_context *op_ctx) +{ + pvr_mmu_op_context_sync_manual(op_ctx, op_ctx->sync_level_required); + + op_ctx->sync_level_required = PVR_MMU_SYNC_LEVEL_NONE; +} + +/** + * pvr_mmu_op_context_load_tables() - Load pointers to tables in each level of + * the page table tree structure needed to reference the physical page + * referenced by a MMU op context. + * @op_ctx: Target MMU op context. + * @should_create: Specifies whether new page tables should be created when + * empty page table entries are encountered during traversal. + * @load_level_required: Maximum page table level to load. + * + * If @should_create is %true, this function may modify the stored required + * sync level of @op_ctx as new page tables are created and inserted into their + * respective parents. + * + * Since there is only one root page table, it is technically incorrect to call + * this function with a value of @load_level_required greater than or equal to + * the root level number. However, this is not explicitly disallowed here. + * + * Return: + * * 0 on success, + * * Any error returned by pvr_page_table_l1_get_or_create() if + * @load_level_required >= 1 except -%ENXIO, or + * * Any error returned by pvr_page_table_l0_get_or_create() if + * @load_level_required >= 0 except -%ENXIO. + */ +static int +pvr_mmu_op_context_load_tables(struct pvr_mmu_op_context *op_ctx, + bool should_create, + enum pvr_mmu_sync_level load_level_required) +{ + const struct pvr_page_table_l1 *l1_head_before = + op_ctx->map.l1_prealloc_tables; + const struct pvr_page_table_l0 *l0_head_before = + op_ctx->map.l0_prealloc_tables; + int err; + + /* Clear tables we're about to fetch in case of error states. */ + if (load_level_required >= PVR_MMU_SYNC_LEVEL_1) + op_ctx->curr_page.l1_table = NULL; + + if (load_level_required >= PVR_MMU_SYNC_LEVEL_0) + op_ctx->curr_page.l0_table = NULL; + + /* Get or create L1 page table. */ + if (load_level_required >= PVR_MMU_SYNC_LEVEL_1) { + err = pvr_page_table_l1_get_or_insert(op_ctx, should_create); + if (err) { + /* + * If @should_create is %false and no L1 page table was + * found, return early but without an error. Since + * pvr_page_table_l1_get_or_create() can only return + * -%ENXIO if @should_create is %false, there is no + * need to check it here. + */ + if (err == -ENXIO) + err = 0; + + return err; + } + } + + /* Get or create L0 page table. */ + if (load_level_required >= PVR_MMU_SYNC_LEVEL_0) { + err = pvr_page_table_l0_get_or_insert(op_ctx, should_create); + if (err) { + /* + * If @should_create is %false and no L0 page table was + * found, return early but without an error. Since + * pvr_page_table_l0_get_or_insert() can only return + * -%ENXIO if @should_create is %false, there is no + * need to check it here. + */ + if (err == -ENXIO) + err = 0; + + /* + * At this point, an L1 page table could have been + * inserted but is now empty due to the failed attempt + * at inserting an L0 page table. In this instance, we + * must remove the empty L1 page table ourselves as + * pvr_page_table_l1_remove() is never called as part + * of the error path in + * pvr_page_table_l0_get_or_insert(). + */ + if (l1_head_before != op_ctx->map.l1_prealloc_tables) { + pvr_page_table_l2_remove(op_ctx); + pvr_mmu_op_context_require_sync(op_ctx, PVR_MMU_SYNC_LEVEL_2); + } + + return err; + } + } + + /* + * A sync is only needed if table objects were inserted. This can be + * inferred by checking if the pointer at the head of the linked list + * has changed. + */ + if (l1_head_before != op_ctx->map.l1_prealloc_tables) + pvr_mmu_op_context_require_sync(op_ctx, PVR_MMU_SYNC_LEVEL_2); + else if (l0_head_before != op_ctx->map.l0_prealloc_tables) + pvr_mmu_op_context_require_sync(op_ctx, PVR_MMU_SYNC_LEVEL_1); + + return 0; +} + +/** + * pvr_mmu_op_context_set_curr_page() - Reassign the current page of an MMU op + * context, syncing any page tables previously assigned to it which are no + * longer relevant. + * @op_ctx: Target MMU op context. + * @device_addr: New pointer target. + * @should_create: Specify whether new page tables should be created when + * empty page table entries are encountered during traversal. + * + * This function performs a full sync on the pointer, regardless of which + * levels are modified. + * + * Return: + * * 0 on success, or + * * Any error returned by pvr_mmu_op_context_load_tables(). + */ +static int +pvr_mmu_op_context_set_curr_page(struct pvr_mmu_op_context *op_ctx, + u64 device_addr, bool should_create) +{ + pvr_mmu_op_context_sync(op_ctx); + + op_ctx->curr_page.l2_idx = pvr_page_table_l2_idx(device_addr); + op_ctx->curr_page.l1_idx = pvr_page_table_l1_idx(device_addr); + op_ctx->curr_page.l0_idx = pvr_page_table_l0_idx(device_addr); + op_ctx->curr_page.l1_table = NULL; + op_ctx->curr_page.l0_table = NULL; + + return pvr_mmu_op_context_load_tables(op_ctx, should_create, + PVR_MMU_SYNC_LEVEL_1); +} + +/** + * pvr_mmu_op_context_next_page() - Advance the current page of an MMU op + * context. + * @op_ctx: Target MMU op context. + * @should_create: Specify whether new page tables should be created when + * empty page table entries are encountered during traversal. + * + * If @should_create is %false, it is the caller's responsibility to verify that + * the state of the table references in @op_ctx is valid on return. If -%ENXIO + * is returned, at least one of the table references is invalid. It should be + * noted that @op_ctx as a whole will be left in a valid state if -%ENXIO is + * returned, unlike other error codes. The caller should check which references + * are invalid by comparing them to %NULL. Only &@ptr->l2_table is guaranteed + * to be valid, since it represents the root of the page table tree structure. + * + * Return: + * * 0 on success, + * * -%EPERM if the operation would wrap at the top of the page table + * hierarchy, + * * -%ENXIO if @should_create is %false and a page table of any level would + * have otherwise been created, or + * * Any error returned while attempting to create missing page tables if + * @should_create is %true. + */ +static int +pvr_mmu_op_context_next_page(struct pvr_mmu_op_context *op_ctx, + bool should_create) +{ + s8 load_level_required = PVR_MMU_SYNC_LEVEL_NONE; + + if (++op_ctx->curr_page.l0_idx != ROGUE_MMUCTRL_ENTRIES_PT_VALUE_X) + goto load_tables; + + op_ctx->curr_page.l0_idx = 0; + load_level_required = PVR_MMU_SYNC_LEVEL_0; + + if (++op_ctx->curr_page.l1_idx != ROGUE_MMUCTRL_ENTRIES_PD_VALUE) + goto load_tables; + + op_ctx->curr_page.l1_idx = 0; + load_level_required = PVR_MMU_SYNC_LEVEL_1; + + if (++op_ctx->curr_page.l2_idx != ROGUE_MMUCTRL_ENTRIES_PC_VALUE) + goto load_tables; + + /* + * If the pattern continued, we would set &op_ctx->curr_page.l2_idx to + * zero here. However, that would wrap the top layer of the page table + * hierarchy which is not a valid operation. Instead, we warn and return + * an error. + */ + WARN(true, + "%s(%p) attempted to loop the top of the page table hierarchy", + __func__, op_ctx); + return -EPERM; + + /* If indices have wrapped, we need to load new tables. */ +load_tables: + /* First, flush tables which will be unloaded. */ + pvr_mmu_op_context_sync_partial(op_ctx, load_level_required); + + /* Then load tables from the required level down. */ + return pvr_mmu_op_context_load_tables(op_ctx, should_create, + load_level_required); +} + +/** + * DOC: Single page operations + */ + +/** + * pvr_page_create() - Create a device-virtual memory page and insert it into + * a level 0 page table. + * @op_ctx: Target MMU op context pointing at the device-virtual address of the + * target page. + * @dma_addr: DMA address of the physical page backing the created page. + * @flags: Page options saved on the level 0 page table entry for reading by + * the device. + * + * Return: + * * 0 on success, or + * * -%EEXIST if the requested page already exists. + */ +static int +pvr_page_create(struct pvr_mmu_op_context *op_ctx, dma_addr_t dma_addr, + struct pvr_page_flags_raw flags) +{ + /* Do not create a new page if one already exists. */ + if (pvr_page_table_l0_entry_is_valid(op_ctx->curr_page.l0_table, + op_ctx->curr_page.l0_idx)) { + return -EEXIST; + } + + pvr_page_table_l0_insert(op_ctx, dma_addr, flags); + + pvr_mmu_op_context_require_sync(op_ctx, PVR_MMU_SYNC_LEVEL_0); + + return 0; +} + +/** + * pvr_page_destroy() - Destroy a device page after removing it from its + * parent level 0 page table. + * @op_ctx: Target MMU op context. + */ +static void +pvr_page_destroy(struct pvr_mmu_op_context *op_ctx) +{ + /* Do nothing if the page does not exist. */ + if (!pvr_page_table_l0_entry_is_valid(op_ctx->curr_page.l0_table, + op_ctx->curr_page.l0_idx)) { + return; + } + + /* Clear the parent L0 page table entry. */ + pvr_page_table_l0_remove(op_ctx); + + pvr_mmu_op_context_require_sync(op_ctx, PVR_MMU_SYNC_LEVEL_0); +} + +/** + * pvr_mmu_op_context_destroy() - Destroy an MMU op context. + * @op_ctx: Target MMU op context. + */ +void pvr_mmu_op_context_destroy(struct pvr_mmu_op_context *op_ctx) +{ + const bool flush_caches = + op_ctx->sync_level_required != PVR_MMU_SYNC_LEVEL_NONE; + + pvr_mmu_op_context_sync(op_ctx); + + /* Unmaps should be flushed immediately. Map flushes can be deferred. */ + if (flush_caches && !op_ctx->map.sgt) + pvr_mmu_flush_exec(op_ctx->mmu_ctx->pvr_dev, true); + + while (op_ctx->map.l0_prealloc_tables) { + struct pvr_page_table_l0 *tmp = op_ctx->map.l0_prealloc_tables; + + op_ctx->map.l0_prealloc_tables = + op_ctx->map.l0_prealloc_tables->next_free; + pvr_page_table_l0_free(tmp); + } + + while (op_ctx->map.l1_prealloc_tables) { + struct pvr_page_table_l1 *tmp = op_ctx->map.l1_prealloc_tables; + + op_ctx->map.l1_prealloc_tables = + op_ctx->map.l1_prealloc_tables->next_free; + pvr_page_table_l1_free(tmp); + } + + while (op_ctx->unmap.l0_free_tables) { + struct pvr_page_table_l0 *tmp = op_ctx->unmap.l0_free_tables; + + op_ctx->unmap.l0_free_tables = + op_ctx->unmap.l0_free_tables->next_free; + pvr_page_table_l0_free(tmp); + } + + while (op_ctx->unmap.l1_free_tables) { + struct pvr_page_table_l1 *tmp = op_ctx->unmap.l1_free_tables; + + op_ctx->unmap.l1_free_tables = + op_ctx->unmap.l1_free_tables->next_free; + pvr_page_table_l1_free(tmp); + } + + kfree(op_ctx); +} + +/** + * pvr_mmu_op_context_create() - Create an MMU op context. + * @ctx: MMU context associated with owning VM context. + * @sgt: Scatter gather table containing pages pinned for use by this context. + * @sgt_offset: Start offset of the requested device-virtual memory mapping. + * @size: Size in bytes of the requested device-virtual memory mapping. For an + * unmapping, this should be zero so that no page tables are allocated. + * + * Returns: + * * Newly created MMU op context object on success, or + * * -%ENOMEM if no memory is available, + * * Any error code returned by pvr_page_table_l2_init(). + */ +struct pvr_mmu_op_context * +pvr_mmu_op_context_create(struct pvr_mmu_context *ctx, struct sg_table *sgt, + u64 sgt_offset, u64 size) +{ + int err; + + struct pvr_mmu_op_context *op_ctx = + kzalloc(sizeof(*op_ctx), GFP_KERNEL); + + if (!op_ctx) + return ERR_PTR(-ENOMEM); + + op_ctx->mmu_ctx = ctx; + op_ctx->map.sgt = sgt; + op_ctx->map.sgt_offset = sgt_offset; + op_ctx->sync_level_required = PVR_MMU_SYNC_LEVEL_NONE; + + if (size) { + /* + * The number of page table objects we need to prealloc is + * indicated by the mapping size, start offset and the sizes + * of the areas mapped per PT or PD. The range calculation is + * identical to that for the index into a table for a device + * address, so we reuse those functions here. + */ + const u32 l1_start_idx = pvr_page_table_l2_idx(sgt_offset); + const u32 l1_end_idx = pvr_page_table_l2_idx(sgt_offset + size); + const u32 l1_count = l1_end_idx - l1_start_idx + 1; + const u32 l0_start_idx = pvr_page_table_l1_idx(sgt_offset); + const u32 l0_end_idx = pvr_page_table_l1_idx(sgt_offset + size); + const u32 l0_count = l0_end_idx - l0_start_idx + 1; + + /* + * Alloc and push page table entries until we have enough of + * each type, ending with linked lists of l0 and l1 entries in + * reverse order. + */ + for (int i = 0; i < l1_count; i++) { + struct pvr_page_table_l1 *l1_tmp = + pvr_page_table_l1_alloc(ctx); + + err = PTR_ERR_OR_ZERO(l1_tmp); + if (err) + goto err_cleanup; + + l1_tmp->next_free = op_ctx->map.l1_prealloc_tables; + op_ctx->map.l1_prealloc_tables = l1_tmp; + } + + for (int i = 0; i < l0_count; i++) { + struct pvr_page_table_l0 *l0_tmp = + pvr_page_table_l0_alloc(ctx); + + err = PTR_ERR_OR_ZERO(l0_tmp); + if (err) + goto err_cleanup; + + l0_tmp->next_free = op_ctx->map.l0_prealloc_tables; + op_ctx->map.l0_prealloc_tables = l0_tmp; + } + } + + return op_ctx; + +err_cleanup: + pvr_mmu_op_context_destroy(op_ctx); + + return ERR_PTR(err); +} + +/** + * pvr_mmu_op_context_unmap_curr_page() - Unmap pages from a memory context + * starting from the current page of an MMU op context. + * @op_ctx: Target MMU op context pointing at the first page to unmap. + * @nr_pages: Number of pages to unmap. + * + * Return: + * * 0 on success, or + * * Any error encountered while advancing @op_ctx.curr_page with + * pvr_mmu_op_context_next_page() (except -%ENXIO). + */ +static int +pvr_mmu_op_context_unmap_curr_page(struct pvr_mmu_op_context *op_ctx, + u64 nr_pages) +{ + int err; + + if (nr_pages == 0) + return 0; + + /* + * Destroy first page outside loop, as it doesn't require a page + * advance beforehand. If the L0 page table reference in + * @op_ctx.curr_page is %NULL, there cannot be a mapped page at + * @op_ctx.curr_page (so skip ahead). + */ + if (op_ctx->curr_page.l0_table) + pvr_page_destroy(op_ctx); + + for (u64 page = 1; page < nr_pages; ++page) { + err = pvr_mmu_op_context_next_page(op_ctx, false); + /* + * If the page table tree structure at @op_ctx.curr_page is + * incomplete, skip ahead. We don't care about unmapping pages + * that cannot exist. + * + * FIXME: This could be made more efficient by jumping ahead + * using pvr_mmu_op_context_set_curr_page(). + */ + if (err == -ENXIO) + continue; + else if (err) + return err; + + pvr_page_destroy(op_ctx); + } + + return 0; +} + +/** + * pvr_mmu_unmap() - Unmap pages from a memory context. + * @op_ctx: Target MMU op context. + * @device_addr: First device-virtual address to unmap. + * @size: Size in bytes to unmap. + * + * The total amount of device-virtual memory unmapped is + * @nr_pages * %PVR_DEVICE_PAGE_SIZE. + * + * Returns: + * * 0 on success, or + * * Any error code returned by pvr_page_table_ptr_init(), or + * * Any error code returned by pvr_page_table_ptr_unmap(). + */ +int pvr_mmu_unmap(struct pvr_mmu_op_context *op_ctx, u64 device_addr, u64 size) +{ + int err = pvr_mmu_op_context_set_curr_page(op_ctx, device_addr, false); + + if (err) + return err; + + return pvr_mmu_op_context_unmap_curr_page(op_ctx, + size >> PVR_DEVICE_PAGE_SHIFT); +} + +/** + * pvr_mmu_map_sgl() - Map part of a scatter-gather table entry to + * device-virtual memory. + * @op_ctx: Target MMU op context pointing to the first page that should be + * mapped. + * @sgl: Target scatter-gather table entry. + * @offset: Offset into @sgl to map from. Must result in a starting address + * from @sgl which is CPU page-aligned. + * @size: Size of the memory to be mapped in bytes. Must be a non-zero multiple + * of the device page size. + * @page_flags: Page options to be applied to every device-virtual memory page + * in the created mapping. + * + * Return: + * * 0 on success, + * * -%EINVAL if the range specified by @offset and @size is not completely + * within @sgl, or + * * Any error encountered while creating a page with pvr_page_create(), or + * * Any error encountered while advancing @op_ctx.curr_page with + * pvr_mmu_op_context_next_page(). + */ +static int +pvr_mmu_map_sgl(struct pvr_mmu_op_context *op_ctx, struct scatterlist *sgl, + u64 offset, u64 size, struct pvr_page_flags_raw page_flags) +{ + const unsigned int pages = size >> PVR_DEVICE_PAGE_SHIFT; + dma_addr_t dma_addr = sg_dma_address(sgl) + offset; + const unsigned int dma_len = sg_dma_len(sgl); + struct pvr_page_table_ptr ptr_copy; + unsigned int page; + int err; + + if (size > dma_len || offset > dma_len - size) + return -EINVAL; + + /* + * Before progressing, save a copy of the start pointer so we can use + * it again if we enter an error state and have to destroy pages. + */ + memcpy(&ptr_copy, &op_ctx->curr_page, sizeof(ptr_copy)); + + /* + * Create first page outside loop, as it doesn't require a page advance + * beforehand. + */ + err = pvr_page_create(op_ctx, dma_addr, page_flags); + if (err) + return err; + + for (page = 1; page < pages; ++page) { + err = pvr_mmu_op_context_next_page(op_ctx, true); + if (err) + goto err_destroy_pages; + + dma_addr += PVR_DEVICE_PAGE_SIZE; + + err = pvr_page_create(op_ctx, dma_addr, page_flags); + if (err) + goto err_destroy_pages; + } + + return 0; + +err_destroy_pages: + memcpy(&op_ctx->curr_page, &ptr_copy, sizeof(op_ctx->curr_page)); + err = pvr_mmu_op_context_unmap_curr_page(op_ctx, page); + + return err; +} + +/** + * pvr_mmu_map() - Map an object's virtual memory to physical memory. + * @op_ctx: Target MMU op context. + * @size: Size of memory to be mapped in bytes. Must be a non-zero multiple + * of the device page size. + * @flags: Flags from pvr_gem_object associated with the mapping. + * @device_addr: Virtual device address to map to. Must be device page-aligned. + * + * Returns: + * * 0 on success, or + * * Any error code returned by pvr_page_table_ptr_init(), or + * * Any error code returned by pvr_mmu_map_sgl(), or + * * Any error code returned by pvr_page_table_ptr_next_page(). + */ +int pvr_mmu_map(struct pvr_mmu_op_context *op_ctx, u64 size, u64 flags, + u64 device_addr) +{ + struct pvr_page_table_ptr ptr_copy; + struct pvr_page_flags_raw flags_raw; + struct scatterlist *sgl; + u64 mapped_size = 0; + unsigned int count; + int err; + + if (!size) + return 0; + + if ((op_ctx->map.sgt_offset | size) & ~PVR_DEVICE_PAGE_MASK) + return -EINVAL; + + err = pvr_mmu_op_context_set_curr_page(op_ctx, device_addr, true); + if (err) + return -EINVAL; + + memcpy(&ptr_copy, &op_ctx->curr_page, sizeof(ptr_copy)); + + flags_raw = pvr_page_flags_raw_create(false, false, + flags & DRM_PVR_BO_BYPASS_DEVICE_CACHE, + flags & DRM_PVR_BO_PM_FW_PROTECT); + + /* Map scatter gather table */ + for_each_sgtable_dma_sg(op_ctx->map.sgt, sgl, count) { + const size_t sgl_len = sg_dma_len(sgl); + u64 sgl_offset, map_sgl_len; + + if (sgl_len <= op_ctx->map.sgt_offset) { + op_ctx->map.sgt_offset -= sgl_len; + continue; + } + + sgl_offset = op_ctx->map.sgt_offset; + map_sgl_len = min_t(u64, sgl_len - sgl_offset, size - mapped_size); + + err = pvr_mmu_map_sgl(op_ctx, sgl, sgl_offset, map_sgl_len, + flags_raw); + if (err) + break; + + /* + * Flag the L0 page table as requiring a flush when the MMU op + * context is destroyed. + */ + pvr_mmu_op_context_require_sync(op_ctx, PVR_MMU_SYNC_LEVEL_0); + + op_ctx->map.sgt_offset = 0; + mapped_size += map_sgl_len; + + if (mapped_size >= size) + break; + + err = pvr_mmu_op_context_next_page(op_ctx, true); + if (err) + break; + } + + if (err && mapped_size) { + memcpy(&op_ctx->curr_page, &ptr_copy, sizeof(op_ctx->curr_page)); + pvr_mmu_op_context_unmap_curr_page(op_ctx, + mapped_size >> PVR_DEVICE_PAGE_SHIFT); + } + + return err; +} diff --git a/drivers/gpu/drm/imagination/pvr_mmu.h b/drivers/gpu/drm/imagination/pvr_mmu.h new file mode 100644 index 00000000000000..a8ecd460168dcd --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_mmu.h @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_MMU_H +#define PVR_MMU_H + +#include +#include + +/* Forward declaration from "pvr_device.h" */ +struct pvr_device; + +/* Forward declaration from "pvr_mmu.c" */ +struct pvr_mmu_context; +struct pvr_mmu_op_context; + +/* Forward declaration from "pvr_vm.c" */ +struct pvr_vm_context; + +/* Forward declaration from */ +struct sg_table; + +/** + * DOC: Public API (constants) + * + * .. c:macro:: PVR_DEVICE_PAGE_SIZE + * + * Fixed page size referenced by leaf nodes in the page table tree + * structure. In the current implementation, this value is pegged to the + * CPU page size (%PAGE_SIZE). It is therefore an error to specify a CPU + * page size which is not also a supported device page size. The supported + * device page sizes are: 4KiB, 16KiB, 64KiB, 256KiB, 1MiB and 2MiB. + * + * .. c:macro:: PVR_DEVICE_PAGE_SHIFT + * + * Shift value used to efficiently multiply or divide by + * %PVR_DEVICE_PAGE_SIZE. + * + * This value is derived from %PVR_DEVICE_PAGE_SIZE. + * + * .. c:macro:: PVR_DEVICE_PAGE_MASK + * + * Mask used to round a value down to the nearest multiple of + * %PVR_DEVICE_PAGE_SIZE. When bitwise negated, it will indicate whether a + * value is already a multiple of %PVR_DEVICE_PAGE_SIZE. + * + * This value is derived from %PVR_DEVICE_PAGE_SIZE. + */ + +/* PVR_DEVICE_PAGE_SIZE determines the page size */ +#define PVR_DEVICE_PAGE_SIZE (PAGE_SIZE) +#define PVR_DEVICE_PAGE_SHIFT (PAGE_SHIFT) +#define PVR_DEVICE_PAGE_MASK (PAGE_MASK) + +/** + * DOC: Page table index utilities (constants) + * + * .. c:macro:: PVR_PAGE_TABLE_ADDR_SPACE_SIZE + * + * Size of device-virtual address space which can be represented in the page + * table structure. + * + * This value is checked at runtime against + * &pvr_device_features.virtual_address_space_bits by + * pvr_vm_create_context(), which will return an error if the feature value + * does not match this constant. + * + * .. admonition:: Future work + * + * It should be possible to support other values of + * &pvr_device_features.virtual_address_space_bits, but so far no + * hardware has been created which advertises an unsupported value. + * + * .. c:macro:: PVR_PAGE_TABLE_ADDR_BITS + * + * Number of bits needed to represent any value less than + * %PVR_PAGE_TABLE_ADDR_SPACE_SIZE exactly. + * + * .. c:macro:: PVR_PAGE_TABLE_ADDR_MASK + * + * Bitmask of device-virtual addresses which are valid in the page table + * structure. + * + * This value is derived from %PVR_PAGE_TABLE_ADDR_SPACE_SIZE, so the same + * notes on that constant apply here. + */ +#define PVR_PAGE_TABLE_ADDR_SPACE_SIZE SZ_1T +#define PVR_PAGE_TABLE_ADDR_BITS __ffs(PVR_PAGE_TABLE_ADDR_SPACE_SIZE) +#define PVR_PAGE_TABLE_ADDR_MASK (PVR_PAGE_TABLE_ADDR_SPACE_SIZE - 1) + +void pvr_mmu_flush_request_all(struct pvr_device *pvr_dev); +int pvr_mmu_flush_exec(struct pvr_device *pvr_dev, bool wait); + +struct pvr_mmu_context *pvr_mmu_context_create(struct pvr_device *pvr_dev); +void pvr_mmu_context_destroy(struct pvr_mmu_context *ctx); + +dma_addr_t pvr_mmu_get_root_table_dma_addr(struct pvr_mmu_context *ctx); + +void pvr_mmu_op_context_destroy(struct pvr_mmu_op_context *op_ctx); +struct pvr_mmu_op_context * +pvr_mmu_op_context_create(struct pvr_mmu_context *ctx, + struct sg_table *sgt, u64 sgt_offset, u64 size); + +int pvr_mmu_map(struct pvr_mmu_op_context *op_ctx, u64 size, u64 flags, + u64 device_addr); +int pvr_mmu_unmap(struct pvr_mmu_op_context *op_ctx, u64 device_addr, u64 size); + +#endif /* PVR_MMU_H */ diff --git a/drivers/gpu/drm/imagination/pvr_params.c b/drivers/gpu/drm/imagination/pvr_params.c new file mode 100644 index 00000000000000..b91759f362c571 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_params.c @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_params.h" + +#include +#include + +static struct pvr_device_params pvr_device_param_defaults __read_mostly = { +#define X(type_, name_, value_, desc_, ...) .name_ = (value_), + PVR_DEVICE_PARAMS +#undef X +}; + +#define PVR_DEVICE_PARAM_NAMED(name_, type_, desc_) \ + module_param_named(name_, pvr_device_param_defaults.name_, type_, \ + 0400); \ + MODULE_PARM_DESC(name_, desc_); + +/* + * This list of defines must contain every type specified in "pvr_params.h" as + * ``PVR_PARAM_TYPE_*_C``. + */ +#define PVR_PARAM_TYPE_X32_MODPARAM uint + +#define X(type_, name_, value_, desc_, ...) \ + PVR_DEVICE_PARAM_NAMED(name_, PVR_PARAM_TYPE_##type_##_MODPARAM, desc_); +PVR_DEVICE_PARAMS +#undef X + +int +pvr_device_params_init(struct pvr_device_params *params) +{ + /* + * If heap-allocated parameters are added in the future (e.g. + * modparam's charp type), they must be handled specially here (via + * kstrdup() in the case of charp). Since that's not necessary yet, + * a straight copy will do for now. This change will also require a + * pvr_device_params_fini() function to free any heap-allocated copies. + */ + + *params = pvr_device_param_defaults; + + return 0; +} + +#if defined(CONFIG_DEBUG_FS) +#include "pvr_device.h" + +#include +#include +#include +#include +#include + +/* + * This list of defines must contain every type specified in "pvr_params.h" as + * ``PVR_PARAM_TYPE_*_C``. + */ +#define PVR_PARAM_TYPE_X32_FMT "0x%08llx" + +#define X_SET(name_, mode_) X_SET_##mode_(name_) +#define X_SET_DEF(name_, update_, mode_) X_SET_DEF_##mode_(name_, update_) + +#define X_SET_RO(name_) NULL +#define X_SET_RW(name_) __pvr_device_param_##name_##set + +#define X_SET_DEF_RO(name_, update_) +#define X_SET_DEF_RW(name_, update_) \ + static int \ + X_SET_RW(name_)(void *data, u64 val) \ + { \ + struct pvr_device *pvr_dev = data; \ + /* This is not just (update_) to suppress -Waddress. */ \ + if ((void *)(update_) != NULL) \ + (update_)(pvr_dev, pvr_dev->params.name_, val); \ + pvr_dev->params.name_ = val; \ + return 0; \ + } + +#define X(type_, name_, value_, desc_, mode_, update_) \ + static int \ + __pvr_device_param_##name_##_get(void *data, u64 *val) \ + { \ + struct pvr_device *pvr_dev = data; \ + *val = pvr_dev->params.name_; \ + return 0; \ + } \ + X_SET_DEF(name_, update_, mode_) \ + static int \ + __pvr_device_param_##name_##_open(struct inode *inode, \ + struct file *file) \ + { \ + __simple_attr_check_format(PVR_PARAM_TYPE_##type_##_FMT, \ + 0ull); \ + return simple_attr_open(inode, file, \ + __pvr_device_param_##name_##_get, \ + X_SET(name_, mode_), \ + PVR_PARAM_TYPE_##type_##_FMT); \ + } +PVR_DEVICE_PARAMS +#undef X + +#undef X_SET +#undef X_SET_RO +#undef X_SET_RW +#undef X_SET_DEF +#undef X_SET_DEF_RO +#undef X_SET_DEF_RW + +static struct { +#define X(type_, name_, value_, desc_, mode_, update_) \ + const struct file_operations name_; + PVR_DEVICE_PARAMS +#undef X +} pvr_device_param_debugfs_fops = { +#define X(type_, name_, value_, desc_, mode_, update_) \ + .name_ = { \ + .owner = THIS_MODULE, \ + .open = __pvr_device_param_##name_##_open, \ + .release = simple_attr_release, \ + .read = simple_attr_read, \ + .write = simple_attr_write, \ + .llseek = generic_file_llseek, \ + }, + PVR_DEVICE_PARAMS +#undef X +}; + +void +pvr_params_debugfs_init(struct pvr_device *pvr_dev, struct dentry *dir) +{ +#define X_MODE(mode_) X_MODE_##mode_ +#define X_MODE_RO 0400 +#define X_MODE_RW 0600 + +#define X(type_, name_, value_, desc_, mode_, update_) \ + debugfs_create_file(#name_, X_MODE(mode_), dir, pvr_dev, \ + &pvr_device_param_debugfs_fops.name_); + PVR_DEVICE_PARAMS +#undef X + +#undef X_MODE +#undef X_MODE_RO +#undef X_MODE_RW +} +#endif diff --git a/drivers/gpu/drm/imagination/pvr_params.h b/drivers/gpu/drm/imagination/pvr_params.h new file mode 100644 index 00000000000000..5807915b456bf2 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_params.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_PARAMS_H +#define PVR_PARAMS_H + +#include "pvr_rogue_fwif.h" + +#include +#include + +/* + * This is the definitive list of types allowed in the definition of + * %PVR_DEVICE_PARAMS. + */ +#define PVR_PARAM_TYPE_X32_C u32 + +/* + * This macro defines all device-specific parameters; that is parameters which + * are set independently per device. + * + * The X-macro accepts the following arguments. Arguments marked with [debugfs] + * are ignored when debugfs is disabled; values used for these arguments may + * safely be gated behind CONFIG_DEBUG_FS. + * + * @type_: The definitive list of allowed values is PVR_PARAM_TYPE_*_C. + * @name_: Name of the parameter. This is used both as the field name in C and + * stringified as the parameter name. + * @value_: Initial/default value. + * @desc_: String literal used as help text to describe the usage of this + * parameter. + * @mode_: [debugfs] One of {RO,RW}. The access mode of the debugfs entry for + * this parameter. + * @update_: [debugfs] When debugfs support is enabled, parameters may be + * updated at runtime. When this happens, this function will be + * called to allow changes to propagate. The signature of this + * function is: + * + * void (*)(struct pvr_device *pvr_dev, T old_val, T new_val) + * + * Where T is the C type associated with @type_. + * + * If @mode_ does not allow write access, this function will never be + * called. In this case, or if no update callback is required, you + * should specify NULL for this argument. + */ +#define PVR_DEVICE_PARAMS \ + X(X32, fw_trace_mask, ROGUE_FWIF_LOG_TYPE_NONE, \ + "Enable FW trace for the specified groups. Specifying 0 disables " \ + "all FW tracing.", \ + RW, pvr_fw_trace_mask_update) + +struct pvr_device_params { +#define X(type_, name_, value_, desc_, ...) \ + PVR_PARAM_TYPE_##type_##_C name_; + PVR_DEVICE_PARAMS +#undef X +}; + +int pvr_device_params_init(struct pvr_device_params *params); + +#if defined(CONFIG_DEBUG_FS) +/* Forward declaration from "pvr_device.h". */ +struct pvr_device; + +/* Forward declaration from . */ +struct dentry; + +void pvr_params_debugfs_init(struct pvr_device *pvr_dev, struct dentry *dir); +#endif /* defined(CONFIG_DEBUG_FS) */ + +#endif /* PVR_PARAMS_H */ diff --git a/drivers/gpu/drm/imagination/pvr_power.c b/drivers/gpu/drm/imagination/pvr_power.c new file mode 100644 index 00000000000000..ba7816fd28ec77 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_power.c @@ -0,0 +1,433 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_device.h" +#include "pvr_fw.h" +#include "pvr_fw_startstop.h" +#include "pvr_power.h" +#include "pvr_queue.h" +#include "pvr_rogue_fwif.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define POWER_SYNC_TIMEOUT_US (1000000) /* 1s */ + +#define WATCHDOG_TIME_MS (500) + +/** + * pvr_device_lost() - Mark GPU device as lost + * @pvr_dev: Target PowerVR device. + * + * This will cause the DRM device to be unplugged. + */ +void +pvr_device_lost(struct pvr_device *pvr_dev) +{ + if (!pvr_dev->lost) { + pvr_dev->lost = true; + drm_dev_unplug(from_pvr_device(pvr_dev)); + } +} + +static int +pvr_power_send_command(struct pvr_device *pvr_dev, struct rogue_fwif_kccb_cmd *pow_cmd) +{ + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + u32 slot_nr; + u32 value; + int err; + + WRITE_ONCE(*fw_dev->power_sync, 0); + + err = pvr_kccb_send_cmd_powered(pvr_dev, pow_cmd, &slot_nr); + if (err) + return err; + + /* Wait for FW to acknowledge. */ + return readl_poll_timeout(pvr_dev->fw_dev.power_sync, value, value != 0, 100, + POWER_SYNC_TIMEOUT_US); +} + +static int +pvr_power_request_idle(struct pvr_device *pvr_dev) +{ + struct rogue_fwif_kccb_cmd pow_cmd; + + /* Send FORCED_IDLE request to FW. */ + pow_cmd.cmd_type = ROGUE_FWIF_KCCB_CMD_POW; + pow_cmd.cmd_data.pow_data.pow_type = ROGUE_FWIF_POW_FORCED_IDLE_REQ; + pow_cmd.cmd_data.pow_data.power_req_data.pow_request_type = ROGUE_FWIF_POWER_FORCE_IDLE; + + return pvr_power_send_command(pvr_dev, &pow_cmd); +} + +static int +pvr_power_request_pwr_off(struct pvr_device *pvr_dev) +{ + struct rogue_fwif_kccb_cmd pow_cmd; + + /* Send POW_OFF request to firmware. */ + pow_cmd.cmd_type = ROGUE_FWIF_KCCB_CMD_POW; + pow_cmd.cmd_data.pow_data.pow_type = ROGUE_FWIF_POW_OFF_REQ; + pow_cmd.cmd_data.pow_data.power_req_data.forced = true; + + return pvr_power_send_command(pvr_dev, &pow_cmd); +} + +static int +pvr_power_fw_disable(struct pvr_device *pvr_dev, bool hard_reset) +{ + if (!hard_reset) { + int err; + + cancel_delayed_work_sync(&pvr_dev->watchdog.work); + + err = pvr_power_request_idle(pvr_dev); + if (err) + return err; + + err = pvr_power_request_pwr_off(pvr_dev); + if (err) + return err; + } + + return pvr_fw_stop(pvr_dev); +} + +static int +pvr_power_fw_enable(struct pvr_device *pvr_dev) +{ + int err; + + err = pvr_fw_start(pvr_dev); + if (err) + return err; + + err = pvr_wait_for_fw_boot(pvr_dev); + if (err) { + drm_err(from_pvr_device(pvr_dev), "Firmware failed to boot\n"); + pvr_fw_stop(pvr_dev); + return err; + } + + queue_delayed_work(pvr_dev->sched_wq, &pvr_dev->watchdog.work, + msecs_to_jiffies(WATCHDOG_TIME_MS)); + + return 0; +} + +bool +pvr_power_is_idle(struct pvr_device *pvr_dev) +{ + /* + * FW power state can be out of date if a KCCB command has been submitted but the FW hasn't + * started processing it yet. So also check the KCCB status. + */ + enum rogue_fwif_pow_state pow_state = READ_ONCE(pvr_dev->fw_dev.fwif_sysdata->pow_state); + bool kccb_idle = pvr_kccb_is_idle(pvr_dev); + + return (pow_state == ROGUE_FWIF_POW_IDLE) && kccb_idle; +} + +static bool +pvr_watchdog_kccb_stalled(struct pvr_device *pvr_dev) +{ + /* Check KCCB commands are progressing. */ + u32 kccb_cmds_executed = pvr_dev->fw_dev.fwif_osdata->kccb_cmds_executed; + bool kccb_is_idle = pvr_kccb_is_idle(pvr_dev); + + if (pvr_dev->watchdog.old_kccb_cmds_executed == kccb_cmds_executed && !kccb_is_idle) { + pvr_dev->watchdog.kccb_stall_count++; + + /* + * If we have commands pending with no progress for 2 consecutive polls then + * consider KCCB command processing stalled. + */ + if (pvr_dev->watchdog.kccb_stall_count == 2) { + pvr_dev->watchdog.kccb_stall_count = 0; + return true; + } + } else if (pvr_dev->watchdog.old_kccb_cmds_executed == kccb_cmds_executed) { + bool has_active_contexts; + + mutex_lock(&pvr_dev->queues.lock); + has_active_contexts = list_empty(&pvr_dev->queues.active); + mutex_unlock(&pvr_dev->queues.lock); + + if (has_active_contexts) { + /* Send a HEALTH_CHECK command so we can verify FW is still alive. */ + struct rogue_fwif_kccb_cmd health_check_cmd; + + health_check_cmd.cmd_type = ROGUE_FWIF_KCCB_CMD_HEALTH_CHECK; + + pvr_kccb_send_cmd_powered(pvr_dev, &health_check_cmd, NULL); + } + } else { + pvr_dev->watchdog.old_kccb_cmds_executed = kccb_cmds_executed; + pvr_dev->watchdog.kccb_stall_count = 0; + } + + return false; +} + +static void +pvr_watchdog_worker(struct work_struct *work) +{ + struct pvr_device *pvr_dev = container_of(work, struct pvr_device, + watchdog.work.work); + bool stalled; + + if (pvr_dev->lost) + return; + + if (pm_runtime_get_if_in_use(from_pvr_device(pvr_dev)->dev) <= 0) + goto out_requeue; + + if (!pvr_dev->fw_dev.booted) + goto out_pm_runtime_put; + + stalled = pvr_watchdog_kccb_stalled(pvr_dev); + + if (stalled) { + drm_err(from_pvr_device(pvr_dev), "FW stalled, trying hard reset"); + + pvr_power_reset(pvr_dev, true); + /* Device may be lost at this point. */ + } + +out_pm_runtime_put: + pm_runtime_put(from_pvr_device(pvr_dev)->dev); + +out_requeue: + if (!pvr_dev->lost) { + queue_delayed_work(pvr_dev->sched_wq, &pvr_dev->watchdog.work, + msecs_to_jiffies(WATCHDOG_TIME_MS)); + } +} + +/** + * pvr_watchdog_init() - Initialise watchdog for device + * @pvr_dev: Target PowerVR device. + * + * Returns: + * * 0 on success, or + * * -%ENOMEM on out of memory. + */ +int +pvr_watchdog_init(struct pvr_device *pvr_dev) +{ + INIT_DELAYED_WORK(&pvr_dev->watchdog.work, pvr_watchdog_worker); + + return 0; +} + +int +pvr_power_device_suspend(struct device *dev) +{ + struct platform_device *plat_dev = to_platform_device(dev); + struct drm_device *drm_dev = platform_get_drvdata(plat_dev); + struct pvr_device *pvr_dev = to_pvr_device(drm_dev); + int err = 0; + int idx; + + if (!drm_dev_enter(drm_dev, &idx)) + return -EIO; + + if (pvr_dev->fw_dev.booted) { + err = pvr_power_fw_disable(pvr_dev, false); + if (err) + goto err_drm_dev_exit; + } + + clk_disable_unprepare(pvr_dev->mem_clk); + clk_disable_unprepare(pvr_dev->sys_clk); + clk_disable_unprepare(pvr_dev->core_clk); + +err_drm_dev_exit: + drm_dev_exit(idx); + + return err; +} + +int +pvr_power_device_resume(struct device *dev) +{ + struct platform_device *plat_dev = to_platform_device(dev); + struct drm_device *drm_dev = platform_get_drvdata(plat_dev); + struct pvr_device *pvr_dev = to_pvr_device(drm_dev); + int idx; + int err; + + if (!drm_dev_enter(drm_dev, &idx)) + return -EIO; + + err = clk_prepare_enable(pvr_dev->core_clk); + if (err) + goto err_drm_dev_exit; + + err = clk_prepare_enable(pvr_dev->sys_clk); + if (err) + goto err_core_clk_disable; + + err = clk_prepare_enable(pvr_dev->mem_clk); + if (err) + goto err_sys_clk_disable; + + if (pvr_dev->fw_dev.booted) { + err = pvr_power_fw_enable(pvr_dev); + if (err) + goto err_mem_clk_disable; + } + + drm_dev_exit(idx); + + return 0; + +err_mem_clk_disable: + clk_disable_unprepare(pvr_dev->mem_clk); + +err_sys_clk_disable: + clk_disable_unprepare(pvr_dev->sys_clk); + +err_core_clk_disable: + clk_disable_unprepare(pvr_dev->core_clk); + +err_drm_dev_exit: + drm_dev_exit(idx); + + return err; +} + +int +pvr_power_device_idle(struct device *dev) +{ + struct platform_device *plat_dev = to_platform_device(dev); + struct drm_device *drm_dev = platform_get_drvdata(plat_dev); + struct pvr_device *pvr_dev = to_pvr_device(drm_dev); + + return pvr_power_is_idle(pvr_dev) ? 0 : -EBUSY; +} + +/** + * pvr_power_reset() - Reset the GPU + * @pvr_dev: Device pointer + * @hard_reset: %true for hard reset, %false for soft reset + * + * If @hard_reset is %false and the FW processor fails to respond during the reset process, this + * function will attempt a hard reset. + * + * If a hard reset fails then the GPU device is reported as lost. + * + * Returns: + * * 0 on success, or + * * Any error code returned by pvr_power_get, pvr_power_fw_disable or pvr_power_fw_enable(). + */ +int +pvr_power_reset(struct pvr_device *pvr_dev, bool hard_reset) +{ + bool queues_disabled = false; + int err; + + /* + * Take a power reference during the reset. This should prevent any interference with the + * power state during reset. + */ + WARN_ON(pvr_power_get(pvr_dev)); + + down_write(&pvr_dev->reset_sem); + + if (pvr_dev->lost) { + err = -EIO; + goto err_up_write; + } + + /* Disable IRQs for the duration of the reset. */ + disable_irq(pvr_dev->irq); + + do { + if (hard_reset) { + pvr_queue_device_pre_reset(pvr_dev); + queues_disabled = true; + } + + err = pvr_power_fw_disable(pvr_dev, hard_reset); + if (!err) { + if (hard_reset) { + pvr_dev->fw_dev.booted = false; + WARN_ON(pm_runtime_force_suspend(from_pvr_device(pvr_dev)->dev)); + + err = pvr_fw_hard_reset(pvr_dev); + if (err) + goto err_device_lost; + + err = pm_runtime_force_resume(from_pvr_device(pvr_dev)->dev); + pvr_dev->fw_dev.booted = true; + if (err) + goto err_device_lost; + } else { + /* Clear the FW faulted flags. */ + pvr_dev->fw_dev.fwif_sysdata->hwr_state_flags &= + ~(ROGUE_FWIF_HWR_FW_FAULT | + ROGUE_FWIF_HWR_RESTART_REQUESTED); + } + + pvr_fw_irq_clear(pvr_dev); + + err = pvr_power_fw_enable(pvr_dev); + } + + if (err && hard_reset) + goto err_device_lost; + + if (err && !hard_reset) { + drm_err(from_pvr_device(pvr_dev), "FW stalled, trying hard reset"); + hard_reset = true; + } + } while (err); + + if (queues_disabled) + pvr_queue_device_post_reset(pvr_dev); + + enable_irq(pvr_dev->irq); + + up_write(&pvr_dev->reset_sem); + + pvr_power_put(pvr_dev); + + return 0; + +err_device_lost: + drm_err(from_pvr_device(pvr_dev), "GPU device lost"); + pvr_device_lost(pvr_dev); + + /* Leave IRQs disabled if the device is lost. */ + + if (queues_disabled) + pvr_queue_device_post_reset(pvr_dev); + +err_up_write: + up_write(&pvr_dev->reset_sem); + + pvr_power_put(pvr_dev); + + return err; +} + +/** + * pvr_watchdog_fini() - Shutdown watchdog for device + * @pvr_dev: Target PowerVR device. + */ +void +pvr_watchdog_fini(struct pvr_device *pvr_dev) +{ + cancel_delayed_work_sync(&pvr_dev->watchdog.work); +} diff --git a/drivers/gpu/drm/imagination/pvr_power.h b/drivers/gpu/drm/imagination/pvr_power.h new file mode 100644 index 00000000000000..9a9312dcb2dab7 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_power.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_POWER_H +#define PVR_POWER_H + +#include "pvr_device.h" + +#include +#include + +int pvr_watchdog_init(struct pvr_device *pvr_dev); +void pvr_watchdog_fini(struct pvr_device *pvr_dev); + +void pvr_device_lost(struct pvr_device *pvr_dev); + +bool pvr_power_is_idle(struct pvr_device *pvr_dev); + +int pvr_power_device_suspend(struct device *dev); +int pvr_power_device_resume(struct device *dev); +int pvr_power_device_idle(struct device *dev); + +int pvr_power_reset(struct pvr_device *pvr_dev, bool hard_reset); + +static __always_inline int +pvr_power_get(struct pvr_device *pvr_dev) +{ + struct drm_device *drm_dev = from_pvr_device(pvr_dev); + + return pm_runtime_resume_and_get(drm_dev->dev); +} + +static __always_inline int +pvr_power_put(struct pvr_device *pvr_dev) +{ + struct drm_device *drm_dev = from_pvr_device(pvr_dev); + + return pm_runtime_put(drm_dev->dev); +} + +#endif /* PVR_POWER_H */ diff --git a/drivers/gpu/drm/imagination/pvr_queue.c b/drivers/gpu/drm/imagination/pvr_queue.c new file mode 100644 index 00000000000000..5ed9c98fb599c8 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_queue.c @@ -0,0 +1,1432 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include +#include + +#include "pvr_cccb.h" +#include "pvr_context.h" +#include "pvr_device.h" +#include "pvr_drv.h" +#include "pvr_job.h" +#include "pvr_queue.h" +#include "pvr_vm.h" + +#include "pvr_rogue_fwif_client.h" + +#define MAX_DEADLINE_MS 30000 + +#define CTX_COMPUTE_CCCB_SIZE_LOG2 15 +#define CTX_FRAG_CCCB_SIZE_LOG2 15 +#define CTX_GEOM_CCCB_SIZE_LOG2 15 +#define CTX_TRANSFER_CCCB_SIZE_LOG2 15 + +static int get_xfer_ctx_state_size(struct pvr_device *pvr_dev) +{ + u32 num_isp_store_registers; + + if (PVR_HAS_FEATURE(pvr_dev, xe_memory_hierarchy)) { + num_isp_store_registers = 1; + } else { + int err; + + err = PVR_FEATURE_VALUE(pvr_dev, num_isp_ipp_pipes, &num_isp_store_registers); + if (WARN_ON(err)) + return err; + } + + return sizeof(struct rogue_fwif_frag_ctx_state) + + (num_isp_store_registers * + sizeof(((struct rogue_fwif_frag_ctx_state *)0)->frag_reg_isp_store[0])); +} + +static int get_frag_ctx_state_size(struct pvr_device *pvr_dev) +{ + u32 num_isp_store_registers; + int err; + + if (PVR_HAS_FEATURE(pvr_dev, xe_memory_hierarchy)) { + err = PVR_FEATURE_VALUE(pvr_dev, num_raster_pipes, &num_isp_store_registers); + if (WARN_ON(err)) + return err; + + if (PVR_HAS_FEATURE(pvr_dev, gpu_multicore_support)) { + u32 xpu_max_slaves; + + err = PVR_FEATURE_VALUE(pvr_dev, xpu_max_slaves, &xpu_max_slaves); + if (WARN_ON(err)) + return err; + + num_isp_store_registers *= (1 + xpu_max_slaves); + } + } else { + err = PVR_FEATURE_VALUE(pvr_dev, num_isp_ipp_pipes, &num_isp_store_registers); + if (WARN_ON(err)) + return err; + } + + return sizeof(struct rogue_fwif_frag_ctx_state) + + (num_isp_store_registers * + sizeof(((struct rogue_fwif_frag_ctx_state *)0)->frag_reg_isp_store[0])); +} + +static int get_ctx_state_size(struct pvr_device *pvr_dev, enum drm_pvr_job_type type) +{ + switch (type) { + case DRM_PVR_JOB_TYPE_GEOMETRY: + return sizeof(struct rogue_fwif_geom_ctx_state); + case DRM_PVR_JOB_TYPE_FRAGMENT: + return get_frag_ctx_state_size(pvr_dev); + case DRM_PVR_JOB_TYPE_COMPUTE: + return sizeof(struct rogue_fwif_compute_ctx_state); + case DRM_PVR_JOB_TYPE_TRANSFER_FRAG: + return get_xfer_ctx_state_size(pvr_dev); + } + + WARN(1, "Invalid queue type"); + return -EINVAL; +} + +static u32 get_ctx_offset(enum drm_pvr_job_type type) +{ + switch (type) { + case DRM_PVR_JOB_TYPE_GEOMETRY: + return offsetof(struct rogue_fwif_fwrendercontext, geom_context); + case DRM_PVR_JOB_TYPE_FRAGMENT: + return offsetof(struct rogue_fwif_fwrendercontext, frag_context); + case DRM_PVR_JOB_TYPE_COMPUTE: + return offsetof(struct rogue_fwif_fwcomputecontext, cdm_context); + case DRM_PVR_JOB_TYPE_TRANSFER_FRAG: + return offsetof(struct rogue_fwif_fwtransfercontext, tq_context); + } + + return 0; +} + +static const char * +pvr_queue_fence_get_driver_name(struct dma_fence *f) +{ + return PVR_DRIVER_NAME; +} + +static void pvr_queue_fence_release(struct dma_fence *f) +{ + struct pvr_queue_fence *fence = container_of(f, struct pvr_queue_fence, base); + + pvr_context_put(fence->queue->ctx); + dma_fence_free(f); +} + +static const char * +pvr_queue_job_fence_get_timeline_name(struct dma_fence *f) +{ + struct pvr_queue_fence *fence = container_of(f, struct pvr_queue_fence, base); + + switch (fence->queue->type) { + case DRM_PVR_JOB_TYPE_GEOMETRY: + return "geometry"; + + case DRM_PVR_JOB_TYPE_FRAGMENT: + return "fragment"; + + case DRM_PVR_JOB_TYPE_COMPUTE: + return "compute"; + + case DRM_PVR_JOB_TYPE_TRANSFER_FRAG: + return "transfer"; + } + + WARN(1, "Invalid queue type"); + return "invalid"; +} + +static const char * +pvr_queue_cccb_fence_get_timeline_name(struct dma_fence *f) +{ + struct pvr_queue_fence *fence = container_of(f, struct pvr_queue_fence, base); + + switch (fence->queue->type) { + case DRM_PVR_JOB_TYPE_GEOMETRY: + return "geometry-cccb"; + + case DRM_PVR_JOB_TYPE_FRAGMENT: + return "fragment-cccb"; + + case DRM_PVR_JOB_TYPE_COMPUTE: + return "compute-cccb"; + + case DRM_PVR_JOB_TYPE_TRANSFER_FRAG: + return "transfer-cccb"; + } + + WARN(1, "Invalid queue type"); + return "invalid"; +} + +static const struct dma_fence_ops pvr_queue_job_fence_ops = { + .get_driver_name = pvr_queue_fence_get_driver_name, + .get_timeline_name = pvr_queue_job_fence_get_timeline_name, + .release = pvr_queue_fence_release, +}; + +/** + * to_pvr_queue_job_fence() - Return a pvr_queue_fence object if the fence is + * backed by a UFO. + * @f: The dma_fence to turn into a pvr_queue_fence. + * + * Return: + * * A non-NULL pvr_queue_fence object if the dma_fence is backed by a UFO, or + * * NULL otherwise. + */ +static struct pvr_queue_fence * +to_pvr_queue_job_fence(struct dma_fence *f) +{ + struct drm_sched_fence *sched_fence = to_drm_sched_fence(f); + + if (sched_fence) + f = sched_fence->parent; + + if (f && f->ops == &pvr_queue_job_fence_ops) + return container_of(f, struct pvr_queue_fence, base); + + return NULL; +} + +static const struct dma_fence_ops pvr_queue_cccb_fence_ops = { + .get_driver_name = pvr_queue_fence_get_driver_name, + .get_timeline_name = pvr_queue_cccb_fence_get_timeline_name, + .release = pvr_queue_fence_release, +}; + +/** + * pvr_queue_fence_put() - Put wrapper for pvr_queue_fence objects. + * @f: The dma_fence object to put. + * + * If the pvr_queue_fence has been initialized, we call dma_fence_put(), + * otherwise we free the object with dma_fence_free(). This allows us + * to do the right thing before and after pvr_queue_fence_init() had been + * called. + */ +static void pvr_queue_fence_put(struct dma_fence *f) +{ + if (!f) + return; + + if (WARN_ON(f->ops && + f->ops != &pvr_queue_cccb_fence_ops && + f->ops != &pvr_queue_job_fence_ops)) + return; + + /* If the fence hasn't been initialized yet, free the object directly. */ + if (f->ops) + dma_fence_put(f); + else + dma_fence_free(f); +} + +/** + * pvr_queue_fence_alloc() - Allocate a pvr_queue_fence fence object + * + * Call this function to allocate job CCCB and done fences. This only + * allocates the objects. Initialization happens when the underlying + * dma_fence object is to be returned to drm_sched (in prepare_job() or + * run_job()). + * + * Return: + * * A valid pointer if the allocation succeeds, or + * * NULL if the allocation fails. + */ +static struct dma_fence * +pvr_queue_fence_alloc(void) +{ + struct pvr_queue_fence *fence; + + fence = kzalloc(sizeof(*fence), GFP_KERNEL); + if (!fence) + return NULL; + + return &fence->base; +} + +/** + * pvr_queue_fence_init() - Initializes a pvr_queue_fence object. + * @f: The fence to initialize + * @queue: The queue this fence belongs to. + * @fence_ops: The fence operations. + * @fence_ctx: The fence context. + * + * Wrapper around dma_fence_init() that takes care of initializing the + * pvr_queue_fence::queue field too. + */ +static void +pvr_queue_fence_init(struct dma_fence *f, + struct pvr_queue *queue, + const struct dma_fence_ops *fence_ops, + struct pvr_queue_fence_ctx *fence_ctx) +{ + struct pvr_queue_fence *fence = container_of(f, struct pvr_queue_fence, base); + + pvr_context_get(queue->ctx); + fence->queue = queue; + dma_fence_init(&fence->base, fence_ops, + &fence_ctx->lock, fence_ctx->id, + atomic_inc_return(&fence_ctx->seqno)); +} + +/** + * pvr_queue_cccb_fence_init() - Initializes a CCCB fence object. + * @fence: The fence to initialize. + * @queue: The queue this fence belongs to. + * + * Initializes a fence that can be used to wait for CCCB space. + * + * Should be called in the ::prepare_job() path, so the fence returned to + * drm_sched is valid. + */ +static void +pvr_queue_cccb_fence_init(struct dma_fence *fence, struct pvr_queue *queue) +{ + pvr_queue_fence_init(fence, queue, &pvr_queue_cccb_fence_ops, + &queue->cccb_fence_ctx.base); +} + +/** + * pvr_queue_job_fence_init() - Initializes a job done fence object. + * @fence: The fence to initialize. + * @queue: The queue this fence belongs to. + * + * Initializes a fence that will be signaled when the GPU is done executing + * a job. + * + * Should be called *before* the ::run_job() path, so the fence is initialised + * before being placed in the pending_list. + */ +static void +pvr_queue_job_fence_init(struct dma_fence *fence, struct pvr_queue *queue) +{ + pvr_queue_fence_init(fence, queue, &pvr_queue_job_fence_ops, + &queue->job_fence_ctx); +} + +/** + * pvr_queue_fence_ctx_init() - Queue fence context initialization. + * @fence_ctx: The context to initialize + */ +static void +pvr_queue_fence_ctx_init(struct pvr_queue_fence_ctx *fence_ctx) +{ + spin_lock_init(&fence_ctx->lock); + fence_ctx->id = dma_fence_context_alloc(1); + atomic_set(&fence_ctx->seqno, 0); +} + +static u32 ufo_cmds_size(u32 elem_count) +{ + /* We can pass at most ROGUE_FWIF_CCB_CMD_MAX_UFOS per UFO-related command. */ + u32 full_cmd_count = elem_count / ROGUE_FWIF_CCB_CMD_MAX_UFOS; + u32 remaining_elems = elem_count % ROGUE_FWIF_CCB_CMD_MAX_UFOS; + u32 size = full_cmd_count * + pvr_cccb_get_size_of_cmd_with_hdr(ROGUE_FWIF_CCB_CMD_MAX_UFOS * + sizeof(struct rogue_fwif_ufo)); + + if (remaining_elems) { + size += pvr_cccb_get_size_of_cmd_with_hdr(remaining_elems * + sizeof(struct rogue_fwif_ufo)); + } + + return size; +} + +static u32 job_cmds_size(struct pvr_job *job, u32 ufo_wait_count) +{ + /* One UFO cmd for the fence signaling, one UFO cmd per native fence native, + * and a command for the job itself. + */ + return ufo_cmds_size(1) + ufo_cmds_size(ufo_wait_count) + + pvr_cccb_get_size_of_cmd_with_hdr(job->cmd_len); +} + +/** + * job_count_remaining_native_deps() - Count the number of non-signaled native dependencies. + * @job: Job to operate on. + * + * Returns: Number of non-signaled native deps remaining. + */ +static unsigned long job_count_remaining_native_deps(struct pvr_job *job) +{ + unsigned long remaining_count = 0; + struct dma_fence *fence = NULL; + unsigned long index; + + xa_for_each(&job->base.dependencies, index, fence) { + struct pvr_queue_fence *jfence; + + jfence = to_pvr_queue_job_fence(fence); + if (!jfence) + continue; + + if (!dma_fence_is_signaled(&jfence->base)) + remaining_count++; + } + + return remaining_count; +} + +/** + * pvr_queue_get_job_cccb_fence() - Get the CCCB fence attached to a job. + * @queue: The queue this job will be submitted to. + * @job: The job to get the CCCB fence on. + * + * The CCCB fence is a synchronization primitive allowing us to delay job + * submission until there's enough space in the CCCB to submit the job. + * + * Return: + * * NULL if there's enough space in the CCCB to submit this job, or + * * A valid dma_fence object otherwise. + */ +static struct dma_fence * +pvr_queue_get_job_cccb_fence(struct pvr_queue *queue, struct pvr_job *job) +{ + struct pvr_queue_fence *cccb_fence; + unsigned int native_deps_remaining; + + /* If the fence is NULL, that means we already checked that we had + * enough space in the cccb for our job. + */ + if (!job->cccb_fence) + return NULL; + + mutex_lock(&queue->cccb_fence_ctx.job_lock); + + /* Count remaining native dependencies and check if the job fits in the CCCB. */ + native_deps_remaining = job_count_remaining_native_deps(job); + if (pvr_cccb_cmdseq_fits(&queue->cccb, job_cmds_size(job, native_deps_remaining))) { + pvr_queue_fence_put(job->cccb_fence); + job->cccb_fence = NULL; + goto out_unlock; + } + + /* There should be no job attached to the CCCB fence context: + * drm_sched_entity guarantees that jobs are submitted one at a time. + */ + if (WARN_ON(queue->cccb_fence_ctx.job)) + pvr_job_put(queue->cccb_fence_ctx.job); + + queue->cccb_fence_ctx.job = pvr_job_get(job); + + /* Initialize the fence before returning it. */ + cccb_fence = container_of(job->cccb_fence, struct pvr_queue_fence, base); + if (!WARN_ON(cccb_fence->queue)) + pvr_queue_cccb_fence_init(job->cccb_fence, queue); + +out_unlock: + mutex_unlock(&queue->cccb_fence_ctx.job_lock); + + return dma_fence_get(job->cccb_fence); +} + +/** + * pvr_queue_get_job_kccb_fence() - Get the KCCB fence attached to a job. + * @queue: The queue this job will be submitted to. + * @job: The job to get the KCCB fence on. + * + * The KCCB fence is a synchronization primitive allowing us to delay job + * submission until there's enough space in the KCCB to submit the job. + * + * Return: + * * NULL if there's enough space in the KCCB to submit this job, or + * * A valid dma_fence object otherwise. + */ +static struct dma_fence * +pvr_queue_get_job_kccb_fence(struct pvr_queue *queue, struct pvr_job *job) +{ + struct pvr_device *pvr_dev = queue->ctx->pvr_dev; + struct dma_fence *kccb_fence = NULL; + + /* If the fence is NULL, that means we already checked that we had + * enough space in the KCCB for our job. + */ + if (!job->kccb_fence) + return NULL; + + if (!WARN_ON(job->kccb_fence->ops)) { + kccb_fence = pvr_kccb_reserve_slot(pvr_dev, job->kccb_fence); + job->kccb_fence = NULL; + } + + return kccb_fence; +} + +static struct dma_fence * +pvr_queue_get_paired_frag_job_dep(struct pvr_queue *queue, struct pvr_job *job) +{ + struct pvr_job *frag_job = job->type == DRM_PVR_JOB_TYPE_GEOMETRY ? + job->paired_job : NULL; + struct dma_fence *f; + unsigned long index; + + if (!frag_job) + return NULL; + + xa_for_each(&frag_job->base.dependencies, index, f) { + /* Skip already signaled fences. */ + if (dma_fence_is_signaled(f)) + continue; + + /* Skip our own fence. */ + if (f == &job->base.s_fence->scheduled) + continue; + + return dma_fence_get(f); + } + + return frag_job->base.sched->ops->prepare_job(&frag_job->base, &queue->entity); +} + +/** + * pvr_queue_prepare_job() - Return the next internal dependencies expressed as a dma_fence. + * @sched_job: The job to query the next internal dependency on + * @s_entity: The entity this job is queue on. + * + * After iterating over drm_sched_job::dependencies, drm_sched let the driver return + * its own internal dependencies. We use this function to return our internal dependencies. + */ +static struct dma_fence * +pvr_queue_prepare_job(struct drm_sched_job *sched_job, + struct drm_sched_entity *s_entity) +{ + struct pvr_job *job = container_of(sched_job, struct pvr_job, base); + struct pvr_queue *queue = container_of(s_entity, struct pvr_queue, entity); + struct dma_fence *internal_dep = NULL; + + /* + * Initialize the done_fence, so we can signal it. This must be done + * here because otherwise by the time of run_job() the job will end up + * in the pending list without a valid fence. + */ + if (job->type == DRM_PVR_JOB_TYPE_FRAGMENT && job->paired_job) { + /* + * This will be called on a paired fragment job after being + * submitted to firmware. We can tell if this is the case and + * bail early from whether run_job() has been called on the + * geometry job, which would issue a pm ref. + */ + if (job->paired_job->has_pm_ref) + return NULL; + + /* + * In this case we need to use the job's own ctx to initialise + * the done_fence. The other steps are done in the ctx of the + * paired geometry job. + */ + pvr_queue_job_fence_init(job->done_fence, + job->ctx->queues.fragment); + } else { + pvr_queue_job_fence_init(job->done_fence, queue); + } + + /* CCCB fence is used to make sure we have enough space in the CCCB to + * submit our commands. + */ + internal_dep = pvr_queue_get_job_cccb_fence(queue, job); + + /* KCCB fence is used to make sure we have a KCCB slot to queue our + * CMD_KICK. + */ + if (!internal_dep) + internal_dep = pvr_queue_get_job_kccb_fence(queue, job); + + /* Any extra internal dependency should be added here, using the following + * pattern: + * + * if (!internal_dep) + * internal_dep = pvr_queue_get_job_xxxx_fence(queue, job); + */ + + /* The paired job fence should come last, when everything else is ready. */ + if (!internal_dep) + internal_dep = pvr_queue_get_paired_frag_job_dep(queue, job); + + return internal_dep; +} + +/** + * pvr_queue_update_active_state_locked() - Update the queue active state. + * @queue: Queue to update the state on. + * + * Locked version of pvr_queue_update_active_state(). Must be called with + * pvr_device::queue::lock held. + */ +static void pvr_queue_update_active_state_locked(struct pvr_queue *queue) +{ + struct pvr_device *pvr_dev = queue->ctx->pvr_dev; + + lockdep_assert_held(&pvr_dev->queues.lock); + + /* The queue is temporary out of any list when it's being reset, + * we don't want a call to pvr_queue_update_active_state_locked() + * to re-insert it behind our back. + */ + if (list_empty(&queue->node)) + return; + + if (!atomic_read(&queue->in_flight_job_count)) + list_move_tail(&queue->node, &pvr_dev->queues.idle); + else + list_move_tail(&queue->node, &pvr_dev->queues.active); +} + +/** + * pvr_queue_update_active_state() - Update the queue active state. + * @queue: Queue to update the state on. + * + * Active state is based on the in_flight_job_count value. + * + * Updating the active state implies moving the queue in or out of the + * active queue list, which also defines whether the queue is checked + * or not when a FW event is received. + * + * This function should be called any time a job is submitted or it done + * fence is signaled. + */ +static void pvr_queue_update_active_state(struct pvr_queue *queue) +{ + struct pvr_device *pvr_dev = queue->ctx->pvr_dev; + + mutex_lock(&pvr_dev->queues.lock); + pvr_queue_update_active_state_locked(queue); + mutex_unlock(&pvr_dev->queues.lock); +} + +static void pvr_queue_submit_job_to_cccb(struct pvr_job *job) +{ + struct pvr_queue *queue = container_of(job->base.sched, struct pvr_queue, scheduler); + struct rogue_fwif_ufo ufos[ROGUE_FWIF_CCB_CMD_MAX_UFOS]; + struct pvr_cccb *cccb = &queue->cccb; + struct pvr_queue_fence *jfence; + struct dma_fence *fence; + unsigned long index; + u32 ufo_count = 0; + + /* We need to add the queue to the active list before updating the CCCB, + * otherwise we might miss the FW event informing us that something + * happened on this queue. + */ + atomic_inc(&queue->in_flight_job_count); + pvr_queue_update_active_state(queue); + + xa_for_each(&job->base.dependencies, index, fence) { + jfence = to_pvr_queue_job_fence(fence); + if (!jfence) + continue; + + /* Skip the partial render fence, we will place it at the end. */ + if (job->type == DRM_PVR_JOB_TYPE_FRAGMENT && job->paired_job && + &job->paired_job->base.s_fence->scheduled == fence) + continue; + + if (dma_fence_is_signaled(&jfence->base)) + continue; + + pvr_fw_object_get_fw_addr(jfence->queue->timeline_ufo.fw_obj, + &ufos[ufo_count].addr); + ufos[ufo_count++].value = jfence->base.seqno; + + if (ufo_count == ARRAY_SIZE(ufos)) { + pvr_cccb_write_command_with_header(cccb, ROGUE_FWIF_CCB_CMD_TYPE_FENCE_PR, + sizeof(ufos), ufos, 0, 0); + ufo_count = 0; + } + } + + /* Partial render fence goes last. */ + if (job->type == DRM_PVR_JOB_TYPE_FRAGMENT && job->paired_job) { + jfence = to_pvr_queue_job_fence(job->paired_job->done_fence); + if (!WARN_ON(!jfence)) { + pvr_fw_object_get_fw_addr(jfence->queue->timeline_ufo.fw_obj, + &ufos[ufo_count].addr); + ufos[ufo_count++].value = job->paired_job->done_fence->seqno; + } + } + + if (ufo_count) { + pvr_cccb_write_command_with_header(cccb, ROGUE_FWIF_CCB_CMD_TYPE_FENCE_PR, + sizeof(ufos[0]) * ufo_count, ufos, 0, 0); + } + + if (job->type == DRM_PVR_JOB_TYPE_GEOMETRY && job->paired_job) { + struct rogue_fwif_cmd_geom *cmd = job->cmd; + + /* Reference value for the partial render test is the current queue fence + * seqno minus one. + */ + pvr_fw_object_get_fw_addr(queue->timeline_ufo.fw_obj, + &cmd->partial_render_geom_frag_fence.addr); + cmd->partial_render_geom_frag_fence.value = job->done_fence->seqno - 1; + } + + /* Submit job to FW */ + pvr_cccb_write_command_with_header(cccb, job->fw_ccb_cmd_type, job->cmd_len, job->cmd, + job->id, job->id); + + /* Signal the job fence. */ + pvr_fw_object_get_fw_addr(queue->timeline_ufo.fw_obj, &ufos[0].addr); + ufos[0].value = job->done_fence->seqno; + pvr_cccb_write_command_with_header(cccb, ROGUE_FWIF_CCB_CMD_TYPE_UPDATE, + sizeof(ufos[0]), ufos, 0, 0); +} + +/** + * pvr_queue_run_job() - Submit a job to the FW. + * @sched_job: The job to submit. + * + * This function is called when all non-native dependencies have been met and + * when the commands resulting from this job are guaranteed to fit in the CCCB. + */ +static struct dma_fence *pvr_queue_run_job(struct drm_sched_job *sched_job) +{ + struct pvr_job *job = container_of(sched_job, struct pvr_job, base); + struct pvr_device *pvr_dev = job->pvr_dev; + int err; + + /* The fragment job is issued along the geometry job when we use combined + * geom+frag kicks. When we get there, we should simply return the + * done_fence that's been initialized earlier. + */ + if (job->paired_job && job->type == DRM_PVR_JOB_TYPE_FRAGMENT && + job->done_fence->ops) { + return dma_fence_get(job->done_fence); + } + + /* The only kind of jobs that can be paired are geometry and fragment, and + * we bail out early if we see a fragment job that's paired with a geomtry + * job. + * Paired jobs must also target the same context and point to the same + * HWRT. + */ + if (WARN_ON(job->paired_job && + (job->type != DRM_PVR_JOB_TYPE_GEOMETRY || + job->paired_job->type != DRM_PVR_JOB_TYPE_FRAGMENT || + job->hwrt != job->paired_job->hwrt || + job->ctx != job->paired_job->ctx))) + return ERR_PTR(-EINVAL); + + err = pvr_job_get_pm_ref(job); + if (WARN_ON(err)) + return ERR_PTR(err); + + if (job->paired_job) { + err = pvr_job_get_pm_ref(job->paired_job); + if (WARN_ON(err)) + return ERR_PTR(err); + } + + /* Submit our job to the CCCB */ + pvr_queue_submit_job_to_cccb(job); + + if (job->paired_job) { + struct pvr_job *geom_job = job; + struct pvr_job *frag_job = job->paired_job; + struct pvr_queue *geom_queue = job->ctx->queues.geometry; + struct pvr_queue *frag_queue = job->ctx->queues.fragment; + + /* Submit the fragment job along the geometry job and send a combined kick. */ + pvr_queue_submit_job_to_cccb(frag_job); + pvr_cccb_send_kccb_combined_kick(pvr_dev, + &geom_queue->cccb, &frag_queue->cccb, + pvr_context_get_fw_addr(geom_job->ctx) + + geom_queue->ctx_offset, + pvr_context_get_fw_addr(frag_job->ctx) + + frag_queue->ctx_offset, + job->hwrt, + frag_job->fw_ccb_cmd_type == + ROGUE_FWIF_CCB_CMD_TYPE_FRAG_PR); + } else { + struct pvr_queue *queue = container_of(job->base.sched, + struct pvr_queue, scheduler); + + pvr_cccb_send_kccb_kick(pvr_dev, &queue->cccb, + pvr_context_get_fw_addr(job->ctx) + queue->ctx_offset, + job->hwrt); + } + + return dma_fence_get(job->done_fence); +} + +static void pvr_queue_stop(struct pvr_queue *queue, struct pvr_job *bad_job) +{ + drm_sched_stop(&queue->scheduler, bad_job ? &bad_job->base : NULL); +} + +static void pvr_queue_start(struct pvr_queue *queue) +{ + struct pvr_job *job; + + /* Make sure we CPU-signal the UFO object, so other queues don't get + * blocked waiting on it. + */ + *queue->timeline_ufo.value = atomic_read(&queue->job_fence_ctx.seqno); + + list_for_each_entry(job, &queue->scheduler.pending_list, base.list) { + if (dma_fence_is_signaled(job->done_fence)) { + /* Jobs might have completed after drm_sched_stop() was called. + * In that case, re-assign the parent field to the done_fence. + */ + WARN_ON(job->base.s_fence->parent); + job->base.s_fence->parent = dma_fence_get(job->done_fence); + } else { + /* If we had unfinished jobs, flag the entity as guilty so no + * new job can be submitted. + */ + atomic_set(&queue->ctx->faulty, 1); + } + } + + drm_sched_start(&queue->scheduler, true); +} + +/** + * pvr_queue_timedout_job() - Handle a job timeout event. + * @s_job: The job this timeout occurred on. + * + * FIXME: We don't do anything here to unblock the situation, we just stop+start + * the scheduler, and re-assign parent fences in the middle. + * + * Return: + * * DRM_GPU_SCHED_STAT_NOMINAL. + */ +static enum drm_gpu_sched_stat +pvr_queue_timedout_job(struct drm_sched_job *s_job) +{ + struct drm_gpu_scheduler *sched = s_job->sched; + struct pvr_queue *queue = container_of(sched, struct pvr_queue, scheduler); + struct pvr_device *pvr_dev = queue->ctx->pvr_dev; + struct pvr_job *job; + u32 job_count = 0; + + dev_err(sched->dev, "Job timeout\n"); + + /* Before we stop the scheduler, make sure the queue is out of any list, so + * any call to pvr_queue_update_active_state_locked() that might happen + * until the scheduler is really stopped doesn't end up re-inserting the + * queue in the active list. This would cause + * pvr_queue_signal_done_fences() and drm_sched_stop() to race with each + * other when accessing the pending_list, since drm_sched_stop() doesn't + * grab the job_list_lock when modifying the list (it's assuming the + * only other accessor is the scheduler, and it's safe to not grab the + * lock since it's stopped). + */ + mutex_lock(&pvr_dev->queues.lock); + list_del_init(&queue->node); + mutex_unlock(&pvr_dev->queues.lock); + + drm_sched_stop(sched, s_job); + + /* Re-assign job parent fences. */ + list_for_each_entry(job, &sched->pending_list, base.list) { + job->base.s_fence->parent = dma_fence_get(job->done_fence); + job_count++; + } + WARN_ON(atomic_read(&queue->in_flight_job_count) != job_count); + + /* Re-insert the queue in the proper list, and kick a queue processing + * operation if there were jobs pending. + */ + mutex_lock(&pvr_dev->queues.lock); + if (!job_count) { + list_move_tail(&queue->node, &pvr_dev->queues.idle); + } else { + atomic_set(&queue->in_flight_job_count, job_count); + list_move_tail(&queue->node, &pvr_dev->queues.active); + pvr_queue_process(queue); + } + mutex_unlock(&pvr_dev->queues.lock); + + drm_sched_start(sched, true); + + return DRM_GPU_SCHED_STAT_NOMINAL; +} + +/** + * pvr_queue_free_job() - Release the reference the scheduler had on a job object. + * @sched_job: Job object to free. + */ +static void pvr_queue_free_job(struct drm_sched_job *sched_job) +{ + struct pvr_job *job = container_of(sched_job, struct pvr_job, base); + + drm_sched_job_cleanup(sched_job); + job->paired_job = NULL; + pvr_job_put(job); +} + +static const struct drm_sched_backend_ops pvr_queue_sched_ops = { + .prepare_job = pvr_queue_prepare_job, + .run_job = pvr_queue_run_job, + .timedout_job = pvr_queue_timedout_job, + .free_job = pvr_queue_free_job, +}; + +/** + * pvr_queue_fence_is_ufo_backed() - Check if a dma_fence is backed by a UFO object + * @f: Fence to test. + * + * A UFO-backed fence is a fence that can be signaled or waited upon FW-side. + * pvr_job::done_fence objects are backed by the timeline UFO attached to the queue + * they are pushed to, but those fences are not directly exposed to the outside + * world, so we also need to check if the fence we're being passed is a + * drm_sched_fence that was coming from our driver. + */ +bool pvr_queue_fence_is_ufo_backed(struct dma_fence *f) +{ + struct drm_sched_fence *sched_fence = f ? to_drm_sched_fence(f) : NULL; + + if (sched_fence && + sched_fence->sched->ops == &pvr_queue_sched_ops) + return true; + + if (f && f->ops == &pvr_queue_job_fence_ops) + return true; + + return false; +} + +/** + * pvr_queue_signal_done_fences() - Signal done fences. + * @queue: Queue to check. + * + * Signal done fences of jobs whose seqno is less than the current value of + * the UFO object attached to the queue. + */ +static void +pvr_queue_signal_done_fences(struct pvr_queue *queue) +{ + struct pvr_job *job, *tmp_job; + u32 cur_seqno; + + spin_lock(&queue->scheduler.job_list_lock); + cur_seqno = *queue->timeline_ufo.value; + list_for_each_entry_safe(job, tmp_job, &queue->scheduler.pending_list, base.list) { + if ((int)(cur_seqno - lower_32_bits(job->done_fence->seqno)) < 0) + break; + + if (!dma_fence_is_signaled(job->done_fence)) { + dma_fence_signal(job->done_fence); + pvr_job_release_pm_ref(job); + atomic_dec(&queue->in_flight_job_count); + } + } + spin_unlock(&queue->scheduler.job_list_lock); +} + +/** + * pvr_queue_check_job_waiting_for_cccb_space() - Check if the job waiting for CCCB space + * can be unblocked + * pushed to the CCCB + * @queue: Queue to check + * + * If we have a job waiting for CCCB, and this job now fits in the CCCB, we signal + * its CCCB fence, which should kick drm_sched. + */ +static void +pvr_queue_check_job_waiting_for_cccb_space(struct pvr_queue *queue) +{ + struct pvr_queue_fence *cccb_fence; + u32 native_deps_remaining; + struct pvr_job *job; + + mutex_lock(&queue->cccb_fence_ctx.job_lock); + job = queue->cccb_fence_ctx.job; + if (!job) + goto out_unlock; + + /* If we have a job attached to the CCCB fence context, its CCCB fence + * shouldn't be NULL. + */ + if (WARN_ON(!job->cccb_fence)) { + job = NULL; + goto out_unlock; + } + + /* If we get there, CCCB fence has to be initialized. */ + cccb_fence = container_of(job->cccb_fence, struct pvr_queue_fence, base); + if (WARN_ON(!cccb_fence->queue)) { + job = NULL; + goto out_unlock; + } + + /* Evict signaled dependencies before checking for CCCB space. + * If the job fits, signal the CCCB fence, this should unblock + * the drm_sched_entity. + */ + native_deps_remaining = job_count_remaining_native_deps(job); + if (!pvr_cccb_cmdseq_fits(&queue->cccb, job_cmds_size(job, native_deps_remaining))) { + job = NULL; + goto out_unlock; + } + + dma_fence_signal(job->cccb_fence); + pvr_queue_fence_put(job->cccb_fence); + job->cccb_fence = NULL; + queue->cccb_fence_ctx.job = NULL; + +out_unlock: + mutex_unlock(&queue->cccb_fence_ctx.job_lock); + + pvr_job_put(job); +} + +/** + * pvr_queue_process() - Process events that happened on a queue. + * @queue: Queue to check + * + * Signal job fences and check if jobs waiting for CCCB space can be unblocked. + */ +void pvr_queue_process(struct pvr_queue *queue) +{ + lockdep_assert_held(&queue->ctx->pvr_dev->queues.lock); + + pvr_queue_check_job_waiting_for_cccb_space(queue); + pvr_queue_signal_done_fences(queue); + pvr_queue_update_active_state_locked(queue); +} + +static u32 get_dm_type(struct pvr_queue *queue) +{ + switch (queue->type) { + case DRM_PVR_JOB_TYPE_GEOMETRY: + return PVR_FWIF_DM_GEOM; + case DRM_PVR_JOB_TYPE_TRANSFER_FRAG: + case DRM_PVR_JOB_TYPE_FRAGMENT: + return PVR_FWIF_DM_FRAG; + case DRM_PVR_JOB_TYPE_COMPUTE: + return PVR_FWIF_DM_CDM; + } + + return ~0; +} + +/** + * init_fw_context() - Initializes the queue part of a FW context. + * @queue: Queue object to initialize the FW context for. + * @fw_ctx_map: The FW context CPU mapping. + * + * FW contexts are containing various states, one of them being a per-queue state + * that needs to be initialized for each queue being exposed by a context. This + * function takes care of that. + */ +static void init_fw_context(struct pvr_queue *queue, void *fw_ctx_map) +{ + struct pvr_context *ctx = queue->ctx; + struct pvr_fw_object *fw_mem_ctx_obj = pvr_vm_get_fw_mem_context(ctx->vm_ctx); + struct rogue_fwif_fwcommoncontext *cctx_fw; + struct pvr_cccb *cccb = &queue->cccb; + + cctx_fw = fw_ctx_map + queue->ctx_offset; + cctx_fw->ccbctl_fw_addr = cccb->ctrl_fw_addr; + cctx_fw->ccb_fw_addr = cccb->cccb_fw_addr; + + cctx_fw->dm = get_dm_type(queue); + cctx_fw->priority = ctx->priority; + cctx_fw->priority_seq_num = 0; + cctx_fw->max_deadline_ms = MAX_DEADLINE_MS; + cctx_fw->pid = task_tgid_nr(current); + cctx_fw->server_common_context_id = ctx->ctx_id; + + pvr_fw_object_get_fw_addr(fw_mem_ctx_obj, &cctx_fw->fw_mem_context_fw_addr); + + pvr_fw_object_get_fw_addr(queue->reg_state_obj, &cctx_fw->context_state_addr); +} + +/** + * pvr_queue_cleanup_fw_context() - Wait for the FW context to be idle and clean it up. + * @queue: Queue on FW context to clean up. + * + * Return: + * * 0 on success, + * * Any error returned by pvr_fw_structure_cleanup() otherwise. + */ +static int pvr_queue_cleanup_fw_context(struct pvr_queue *queue) +{ + if (!queue->ctx->fw_obj) + return 0; + + return pvr_fw_structure_cleanup(queue->ctx->pvr_dev, + ROGUE_FWIF_CLEANUP_FWCOMMONCONTEXT, + queue->ctx->fw_obj, queue->ctx_offset); +} + +/** + * pvr_queue_job_init() - Initialize queue related fields in a pvr_job object. + * @job: The job to initialize. + * + * Bind the job to a queue and allocate memory to guarantee pvr_queue_job_arm() + * and pvr_queue_job_push() can't fail. We also make sure the context type is + * valid and the job can fit in the CCCB. + * + * Return: + * * 0 on success, or + * * An error code if something failed. + */ +int pvr_queue_job_init(struct pvr_job *job) +{ + /* Fragment jobs need at least one native fence wait on the geometry job fence. */ + u32 min_native_dep_count = job->type == DRM_PVR_JOB_TYPE_FRAGMENT ? 1 : 0; + struct pvr_queue *queue; + int err; + + if (atomic_read(&job->ctx->faulty)) + return -EIO; + + queue = pvr_context_get_queue_for_job(job->ctx, job->type); + if (!queue) + return -EINVAL; + + if (!pvr_cccb_cmdseq_can_fit(&queue->cccb, job_cmds_size(job, min_native_dep_count))) + return -E2BIG; + + err = drm_sched_job_init(&job->base, &queue->entity, 1, THIS_MODULE); + if (err) + return err; + + job->cccb_fence = pvr_queue_fence_alloc(); + job->kccb_fence = pvr_kccb_fence_alloc(); + job->done_fence = pvr_queue_fence_alloc(); + if (!job->cccb_fence || !job->kccb_fence || !job->done_fence) + return -ENOMEM; + + return 0; +} + +/** + * pvr_queue_job_arm() - Arm a job object. + * @job: The job to arm. + * + * Initializes fences and return the drm_sched finished fence so it can + * be exposed to the outside world. Once this function is called, you should + * make sure the job is pushed using pvr_queue_job_push(), or guarantee that + * no one grabbed a reference to the returned fence. The latter can happen if + * we do multi-job submission, and something failed when creating/initializing + * a job. In that case, we know the fence didn't leave the driver, and we + * can thus guarantee nobody will wait on an dead fence object. + * + * Return: + * * A dma_fence object. + */ +struct dma_fence *pvr_queue_job_arm(struct pvr_job *job) +{ + drm_sched_job_arm(&job->base); + + return &job->base.s_fence->finished; +} + +/** + * pvr_queue_job_cleanup() - Cleanup fence/scheduler related fields in the job object. + * @job: The job to cleanup. + * + * Should be called in the job release path. + */ +void pvr_queue_job_cleanup(struct pvr_job *job) +{ + pvr_queue_fence_put(job->done_fence); + pvr_queue_fence_put(job->cccb_fence); + pvr_kccb_fence_put(job->kccb_fence); + + if (job->base.s_fence) + drm_sched_job_cleanup(&job->base); +} + +/** + * pvr_queue_job_push() - Push a job to its queue. + * @job: The job to push. + * + * Must be called after pvr_queue_job_init() and after all dependencies + * have been added to the job. This will effectively queue the job to + * the drm_sched_entity attached to the queue. We grab a reference on + * the job object, so the caller is free to drop its reference when it's + * done accessing the job object. + */ +void pvr_queue_job_push(struct pvr_job *job) +{ + struct pvr_queue *queue = container_of(job->base.sched, struct pvr_queue, scheduler); + + /* Keep track of the last queued job scheduled fence for combined submit. */ + dma_fence_put(queue->last_queued_job_scheduled_fence); + queue->last_queued_job_scheduled_fence = dma_fence_get(&job->base.s_fence->scheduled); + + pvr_job_get(job); + drm_sched_entity_push_job(&job->base); +} + +static void reg_state_init(void *cpu_ptr, void *priv) +{ + struct pvr_queue *queue = priv; + + if (queue->type == DRM_PVR_JOB_TYPE_GEOMETRY) { + struct rogue_fwif_geom_ctx_state *geom_ctx_state_fw = cpu_ptr; + + geom_ctx_state_fw->geom_core[0].geom_reg_vdm_call_stack_pointer_init = + queue->callstack_addr; + } +} + +/** + * pvr_queue_create() - Create a queue object. + * @ctx: The context this queue will be attached to. + * @type: The type of jobs being pushed to this queue. + * @args: The arguments passed to the context creation function. + * @fw_ctx_map: CPU mapping of the FW context object. + * + * Create a queue object that will be used to queue and track jobs. + * + * Return: + * * A valid pointer to a pvr_queue object, or + * * An error pointer if the creation/initialization failed. + */ +struct pvr_queue *pvr_queue_create(struct pvr_context *ctx, + enum drm_pvr_job_type type, + struct drm_pvr_ioctl_create_context_args *args, + void *fw_ctx_map) +{ + static const struct { + u32 cccb_size; + const char *name; + } props[] = { + [DRM_PVR_JOB_TYPE_GEOMETRY] = { + .cccb_size = CTX_GEOM_CCCB_SIZE_LOG2, + .name = "geometry", + }, + [DRM_PVR_JOB_TYPE_FRAGMENT] = { + .cccb_size = CTX_FRAG_CCCB_SIZE_LOG2, + .name = "fragment" + }, + [DRM_PVR_JOB_TYPE_COMPUTE] = { + .cccb_size = CTX_COMPUTE_CCCB_SIZE_LOG2, + .name = "compute" + }, + [DRM_PVR_JOB_TYPE_TRANSFER_FRAG] = { + .cccb_size = CTX_TRANSFER_CCCB_SIZE_LOG2, + .name = "transfer_frag" + }, + }; + struct pvr_device *pvr_dev = ctx->pvr_dev; + struct drm_gpu_scheduler *sched; + struct pvr_queue *queue; + int ctx_state_size, err; + void *cpu_map; + + if (WARN_ON(type >= sizeof(props))) + return ERR_PTR(-EINVAL); + + switch (ctx->type) { + case DRM_PVR_CTX_TYPE_RENDER: + if (type != DRM_PVR_JOB_TYPE_GEOMETRY && + type != DRM_PVR_JOB_TYPE_FRAGMENT) + return ERR_PTR(-EINVAL); + break; + case DRM_PVR_CTX_TYPE_COMPUTE: + if (type != DRM_PVR_JOB_TYPE_COMPUTE) + return ERR_PTR(-EINVAL); + break; + case DRM_PVR_CTX_TYPE_TRANSFER_FRAG: + if (type != DRM_PVR_JOB_TYPE_TRANSFER_FRAG) + return ERR_PTR(-EINVAL); + break; + default: + return ERR_PTR(-EINVAL); + } + + ctx_state_size = get_ctx_state_size(pvr_dev, type); + if (ctx_state_size < 0) + return ERR_PTR(ctx_state_size); + + queue = kzalloc(sizeof(*queue), GFP_KERNEL); + if (!queue) + return ERR_PTR(-ENOMEM); + + queue->type = type; + queue->ctx_offset = get_ctx_offset(type); + queue->ctx = ctx; + queue->callstack_addr = args->callstack_addr; + sched = &queue->scheduler; + INIT_LIST_HEAD(&queue->node); + mutex_init(&queue->cccb_fence_ctx.job_lock); + pvr_queue_fence_ctx_init(&queue->cccb_fence_ctx.base); + pvr_queue_fence_ctx_init(&queue->job_fence_ctx); + + err = pvr_cccb_init(pvr_dev, &queue->cccb, props[type].cccb_size, props[type].name); + if (err) + goto err_free_queue; + + err = pvr_fw_object_create(pvr_dev, ctx_state_size, + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + reg_state_init, queue, &queue->reg_state_obj); + if (err) + goto err_cccb_fini; + + init_fw_context(queue, fw_ctx_map); + + if (type != DRM_PVR_JOB_TYPE_GEOMETRY && type != DRM_PVR_JOB_TYPE_FRAGMENT && + args->callstack_addr) { + err = -EINVAL; + goto err_release_reg_state; + } + + cpu_map = pvr_fw_object_create_and_map(pvr_dev, sizeof(*queue->timeline_ufo.value), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + NULL, NULL, &queue->timeline_ufo.fw_obj); + if (IS_ERR(cpu_map)) { + err = PTR_ERR(cpu_map); + goto err_release_reg_state; + } + + queue->timeline_ufo.value = cpu_map; + + err = drm_sched_init(&queue->scheduler, + &pvr_queue_sched_ops, + pvr_dev->sched_wq, 1, 64 * 1024, 1, + msecs_to_jiffies(500), + pvr_dev->sched_wq, NULL, "pvr-queue", + pvr_dev->base.dev); + if (err) + goto err_release_ufo; + + err = drm_sched_entity_init(&queue->entity, + DRM_SCHED_PRIORITY_KERNEL, + &sched, 1, &ctx->faulty); + if (err) + goto err_sched_fini; + + mutex_lock(&pvr_dev->queues.lock); + list_add_tail(&queue->node, &pvr_dev->queues.idle); + mutex_unlock(&pvr_dev->queues.lock); + + return queue; + +err_sched_fini: + drm_sched_fini(&queue->scheduler); + +err_release_ufo: + pvr_fw_object_unmap_and_destroy(queue->timeline_ufo.fw_obj); + +err_release_reg_state: + pvr_fw_object_destroy(queue->reg_state_obj); + +err_cccb_fini: + pvr_cccb_fini(&queue->cccb); + +err_free_queue: + mutex_destroy(&queue->cccb_fence_ctx.job_lock); + kfree(queue); + + return ERR_PTR(err); +} + +void pvr_queue_device_pre_reset(struct pvr_device *pvr_dev) +{ + struct pvr_queue *queue; + + mutex_lock(&pvr_dev->queues.lock); + list_for_each_entry(queue, &pvr_dev->queues.idle, node) + pvr_queue_stop(queue, NULL); + list_for_each_entry(queue, &pvr_dev->queues.active, node) + pvr_queue_stop(queue, NULL); + mutex_unlock(&pvr_dev->queues.lock); +} + +void pvr_queue_device_post_reset(struct pvr_device *pvr_dev) +{ + struct pvr_queue *queue; + + mutex_lock(&pvr_dev->queues.lock); + list_for_each_entry(queue, &pvr_dev->queues.active, node) + pvr_queue_start(queue); + list_for_each_entry(queue, &pvr_dev->queues.idle, node) + pvr_queue_start(queue); + mutex_unlock(&pvr_dev->queues.lock); +} + +/** + * pvr_queue_kill() - Kill a queue. + * @queue: The queue to kill. + * + * Kill the queue so no new jobs can be pushed. Should be called when the + * context handle is destroyed. The queue object might last longer if jobs + * are still in flight and holding a reference to the context this queue + * belongs to. + */ +void pvr_queue_kill(struct pvr_queue *queue) +{ + drm_sched_entity_destroy(&queue->entity); + dma_fence_put(queue->last_queued_job_scheduled_fence); + queue->last_queued_job_scheduled_fence = NULL; +} + +/** + * pvr_queue_destroy() - Destroy a queue. + * @queue: The queue to destroy. + * + * Cleanup the queue and free the resources attached to it. Should be + * called from the context release function. + */ +void pvr_queue_destroy(struct pvr_queue *queue) +{ + if (!queue) + return; + + mutex_lock(&queue->ctx->pvr_dev->queues.lock); + list_del_init(&queue->node); + mutex_unlock(&queue->ctx->pvr_dev->queues.lock); + + drm_sched_fini(&queue->scheduler); + drm_sched_entity_fini(&queue->entity); + + if (WARN_ON(queue->last_queued_job_scheduled_fence)) + dma_fence_put(queue->last_queued_job_scheduled_fence); + + pvr_queue_cleanup_fw_context(queue); + + pvr_fw_object_unmap_and_destroy(queue->timeline_ufo.fw_obj); + pvr_fw_object_destroy(queue->reg_state_obj); + pvr_cccb_fini(&queue->cccb); + mutex_destroy(&queue->cccb_fence_ctx.job_lock); + kfree(queue); +} + +/** + * pvr_queue_device_init() - Device-level initialization of queue related fields. + * @pvr_dev: The device to initialize. + * + * Initializes all fields related to queue management in pvr_device. + * + * Return: + * * 0 on success, or + * * An error code on failure. + */ +int pvr_queue_device_init(struct pvr_device *pvr_dev) +{ + int err; + + INIT_LIST_HEAD(&pvr_dev->queues.active); + INIT_LIST_HEAD(&pvr_dev->queues.idle); + err = drmm_mutex_init(from_pvr_device(pvr_dev), &pvr_dev->queues.lock); + if (err) + return err; + + pvr_dev->sched_wq = alloc_workqueue("powervr-sched", WQ_UNBOUND, 0); + if (!pvr_dev->sched_wq) + return -ENOMEM; + + return 0; +} + +/** + * pvr_queue_device_fini() - Device-level cleanup of queue related fields. + * @pvr_dev: The device to cleanup. + * + * Cleanup/free all queue-related resources attached to a pvr_device object. + */ +void pvr_queue_device_fini(struct pvr_device *pvr_dev) +{ + destroy_workqueue(pvr_dev->sched_wq); +} diff --git a/drivers/gpu/drm/imagination/pvr_queue.h b/drivers/gpu/drm/imagination/pvr_queue.h new file mode 100644 index 00000000000000..e06ced69302fca --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_queue.h @@ -0,0 +1,169 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_QUEUE_H +#define PVR_QUEUE_H + +#include + +#include "pvr_cccb.h" +#include "pvr_device.h" + +struct pvr_context; +struct pvr_queue; + +/** + * struct pvr_queue_fence_ctx - Queue fence context + * + * Used to implement dma_fence_ops for pvr_job::{done,cccb}_fence. + */ +struct pvr_queue_fence_ctx { + /** @id: Fence context ID allocated with dma_fence_context_alloc(). */ + u64 id; + + /** @seqno: Sequence number incremented each time a fence is created. */ + atomic_t seqno; + + /** @lock: Lock used to synchronize access to fences allocated by this context. */ + spinlock_t lock; +}; + +/** + * struct pvr_queue_cccb_fence_ctx - CCCB fence context + * + * Context used to manage fences controlling access to the CCCB. No fences are + * issued if there's enough space in the CCCB to push job commands. + */ +struct pvr_queue_cccb_fence_ctx { + /** @base: Base queue fence context. */ + struct pvr_queue_fence_ctx base; + + /** + * @job: Job waiting for CCCB space. + * + * Thanks to the serializationg done at the drm_sched_entity level, + * there's no more than one job waiting for CCCB at a given time. + * + * This field is NULL if no jobs are currently waiting for CCCB space. + * + * Must be accessed with @job_lock held. + */ + struct pvr_job *job; + + /** @job_lock: Lock protecting access to the job object. */ + struct mutex job_lock; +}; + +/** + * struct pvr_queue_fence - Queue fence object + */ +struct pvr_queue_fence { + /** @base: Base dma_fence. */ + struct dma_fence base; + + /** @queue: Queue that created this fence. */ + struct pvr_queue *queue; +}; + +/** + * struct pvr_queue - Job queue + * + * Used to queue and track execution of pvr_job objects. + */ +struct pvr_queue { + /** @scheduler: Single entity scheduler use to push jobs to this queue. */ + struct drm_gpu_scheduler scheduler; + + /** @entity: Scheduling entity backing this queue. */ + struct drm_sched_entity entity; + + /** @type: Type of jobs queued to this queue. */ + enum drm_pvr_job_type type; + + /** @ctx: Context object this queue is bound to. */ + struct pvr_context *ctx; + + /** @node: Used to add the queue to the active/idle queue list. */ + struct list_head node; + + /** + * @in_flight_job_count: Number of jobs submitted to the CCCB that + * have not been processed yet. + */ + atomic_t in_flight_job_count; + + /** + * @cccb_fence_ctx: CCCB fence context. + * + * Used to control access to the CCCB is full, such that we don't + * end up trying to push commands to the CCCB if there's not enough + * space to receive all commands needed for a job to complete. + */ + struct pvr_queue_cccb_fence_ctx cccb_fence_ctx; + + /** @job_fence_ctx: Job fence context object. */ + struct pvr_queue_fence_ctx job_fence_ctx; + + /** @timeline_ufo: Timeline UFO for the context queue. */ + struct { + /** @fw_obj: FW object representing the UFO value. */ + struct pvr_fw_object *fw_obj; + + /** @value: CPU mapping of the UFO value. */ + u32 *value; + } timeline_ufo; + + /** + * @last_queued_job_scheduled_fence: The scheduled fence of the last + * job queued to this queue. + * + * We use it to insert frag -> geom dependencies when issuing combined + * geom+frag jobs, to guarantee that the fragment job that's part of + * the combined operation comes after all fragment jobs that were queued + * before it. + */ + struct dma_fence *last_queued_job_scheduled_fence; + + /** @cccb: Client Circular Command Buffer. */ + struct pvr_cccb cccb; + + /** @reg_state_obj: FW object representing the register state of this queue. */ + struct pvr_fw_object *reg_state_obj; + + /** @ctx_offset: Offset of the queue context in the FW context object. */ + u32 ctx_offset; + + /** @callstack_addr: Initial call stack address for register state object. */ + u64 callstack_addr; +}; + +bool pvr_queue_fence_is_ufo_backed(struct dma_fence *f); + +int pvr_queue_job_init(struct pvr_job *job); + +void pvr_queue_job_cleanup(struct pvr_job *job); + +void pvr_queue_job_push(struct pvr_job *job); + +struct dma_fence *pvr_queue_job_arm(struct pvr_job *job); + +struct pvr_queue *pvr_queue_create(struct pvr_context *ctx, + enum drm_pvr_job_type type, + struct drm_pvr_ioctl_create_context_args *args, + void *fw_ctx_map); + +void pvr_queue_kill(struct pvr_queue *queue); + +void pvr_queue_destroy(struct pvr_queue *queue); + +void pvr_queue_process(struct pvr_queue *queue); + +void pvr_queue_device_pre_reset(struct pvr_device *pvr_dev); + +void pvr_queue_device_post_reset(struct pvr_device *pvr_dev); + +int pvr_queue_device_init(struct pvr_device *pvr_dev); + +void pvr_queue_device_fini(struct pvr_device *pvr_dev); + +#endif /* PVR_QUEUE_H */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_cr_defs.h b/drivers/gpu/drm/imagination/pvr_rogue_cr_defs.h new file mode 100644 index 00000000000000..2a90d02796d3e0 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_cr_defs.h @@ -0,0 +1,6193 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +/* *** Autogenerated C -- do not edit *** */ + +#ifndef PVR_ROGUE_CR_DEFS_H +#define PVR_ROGUE_CR_DEFS_H + +/* clang-format off */ + +#define ROGUE_CR_DEFS_REVISION 1 + +/* Register ROGUE_CR_RASTERISATION_INDIRECT */ +#define ROGUE_CR_RASTERISATION_INDIRECT 0x8238U +#define ROGUE_CR_RASTERISATION_INDIRECT_MASKFULL 0x000000000000000FULL +#define ROGUE_CR_RASTERISATION_INDIRECT_ADDRESS_SHIFT 0U +#define ROGUE_CR_RASTERISATION_INDIRECT_ADDRESS_CLRMSK 0xFFFFFFF0U + +/* Register ROGUE_CR_PBE_INDIRECT */ +#define ROGUE_CR_PBE_INDIRECT 0x83E0U +#define ROGUE_CR_PBE_INDIRECT_MASKFULL 0x000000000000000FULL +#define ROGUE_CR_PBE_INDIRECT_ADDRESS_SHIFT 0U +#define ROGUE_CR_PBE_INDIRECT_ADDRESS_CLRMSK 0xFFFFFFF0U + +/* Register ROGUE_CR_PBE_PERF_INDIRECT */ +#define ROGUE_CR_PBE_PERF_INDIRECT 0x83D8U +#define ROGUE_CR_PBE_PERF_INDIRECT_MASKFULL 0x000000000000000FULL +#define ROGUE_CR_PBE_PERF_INDIRECT_ADDRESS_SHIFT 0U +#define ROGUE_CR_PBE_PERF_INDIRECT_ADDRESS_CLRMSK 0xFFFFFFF0U + +/* Register ROGUE_CR_TPU_PERF_INDIRECT */ +#define ROGUE_CR_TPU_PERF_INDIRECT 0x83F0U +#define ROGUE_CR_TPU_PERF_INDIRECT_MASKFULL 0x0000000000000007ULL +#define ROGUE_CR_TPU_PERF_INDIRECT_ADDRESS_SHIFT 0U +#define ROGUE_CR_TPU_PERF_INDIRECT_ADDRESS_CLRMSK 0xFFFFFFF8U + +/* Register ROGUE_CR_RASTERISATION_PERF_INDIRECT */ +#define ROGUE_CR_RASTERISATION_PERF_INDIRECT 0x8318U +#define ROGUE_CR_RASTERISATION_PERF_INDIRECT_MASKFULL 0x000000000000000FULL +#define ROGUE_CR_RASTERISATION_PERF_INDIRECT_ADDRESS_SHIFT 0U +#define ROGUE_CR_RASTERISATION_PERF_INDIRECT_ADDRESS_CLRMSK 0xFFFFFFF0U + +/* Register ROGUE_CR_TPU_MCU_L0_PERF_INDIRECT */ +#define ROGUE_CR_TPU_MCU_L0_PERF_INDIRECT 0x8028U +#define ROGUE_CR_TPU_MCU_L0_PERF_INDIRECT_MASKFULL 0x0000000000000007ULL +#define ROGUE_CR_TPU_MCU_L0_PERF_INDIRECT_ADDRESS_SHIFT 0U +#define ROGUE_CR_TPU_MCU_L0_PERF_INDIRECT_ADDRESS_CLRMSK 0xFFFFFFF8U + +/* Register ROGUE_CR_USC_PERF_INDIRECT */ +#define ROGUE_CR_USC_PERF_INDIRECT 0x8030U +#define ROGUE_CR_USC_PERF_INDIRECT_MASKFULL 0x000000000000000FULL +#define ROGUE_CR_USC_PERF_INDIRECT_ADDRESS_SHIFT 0U +#define ROGUE_CR_USC_PERF_INDIRECT_ADDRESS_CLRMSK 0xFFFFFFF0U + +/* Register ROGUE_CR_BLACKPEARL_INDIRECT */ +#define ROGUE_CR_BLACKPEARL_INDIRECT 0x8388U +#define ROGUE_CR_BLACKPEARL_INDIRECT_MASKFULL 0x0000000000000003ULL +#define ROGUE_CR_BLACKPEARL_INDIRECT_ADDRESS_SHIFT 0U +#define ROGUE_CR_BLACKPEARL_INDIRECT_ADDRESS_CLRMSK 0xFFFFFFFCU + +/* Register ROGUE_CR_BLACKPEARL_PERF_INDIRECT */ +#define ROGUE_CR_BLACKPEARL_PERF_INDIRECT 0x83F8U +#define ROGUE_CR_BLACKPEARL_PERF_INDIRECT_MASKFULL 0x0000000000000003ULL +#define ROGUE_CR_BLACKPEARL_PERF_INDIRECT_ADDRESS_SHIFT 0U +#define ROGUE_CR_BLACKPEARL_PERF_INDIRECT_ADDRESS_CLRMSK 0xFFFFFFFCU + +/* Register ROGUE_CR_TEXAS3_PERF_INDIRECT */ +#define ROGUE_CR_TEXAS3_PERF_INDIRECT 0x83D0U +#define ROGUE_CR_TEXAS3_PERF_INDIRECT_MASKFULL 0x0000000000000007ULL +#define ROGUE_CR_TEXAS3_PERF_INDIRECT_ADDRESS_SHIFT 0U +#define ROGUE_CR_TEXAS3_PERF_INDIRECT_ADDRESS_CLRMSK 0xFFFFFFF8U + +/* Register ROGUE_CR_TEXAS_PERF_INDIRECT */ +#define ROGUE_CR_TEXAS_PERF_INDIRECT 0x8288U +#define ROGUE_CR_TEXAS_PERF_INDIRECT_MASKFULL 0x0000000000000003ULL +#define ROGUE_CR_TEXAS_PERF_INDIRECT_ADDRESS_SHIFT 0U +#define ROGUE_CR_TEXAS_PERF_INDIRECT_ADDRESS_CLRMSK 0xFFFFFFFCU + +/* Register ROGUE_CR_BX_TU_PERF_INDIRECT */ +#define ROGUE_CR_BX_TU_PERF_INDIRECT 0xC900U +#define ROGUE_CR_BX_TU_PERF_INDIRECT_MASKFULL 0x0000000000000003ULL +#define ROGUE_CR_BX_TU_PERF_INDIRECT_ADDRESS_SHIFT 0U +#define ROGUE_CR_BX_TU_PERF_INDIRECT_ADDRESS_CLRMSK 0xFFFFFFFCU + +/* Register ROGUE_CR_CLK_CTRL */ +#define ROGUE_CR_CLK_CTRL 0x0000U +#define ROGUE_CR_CLK_CTRL__PBE2_XE__MASKFULL 0xFFFFFF003F3FFFFFULL +#define ROGUE_CR_CLK_CTRL__S7_TOP__MASKFULL 0xCFCF03000F3F3F0FULL +#define ROGUE_CR_CLK_CTRL_MASKFULL 0xFFFFFF003F3FFFFFULL +#define ROGUE_CR_CLK_CTRL_BIF_TEXAS_SHIFT 62U +#define ROGUE_CR_CLK_CTRL_BIF_TEXAS_CLRMSK 0x3FFFFFFFFFFFFFFFULL +#define ROGUE_CR_CLK_CTRL_BIF_TEXAS_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_BIF_TEXAS_ON 0x4000000000000000ULL +#define ROGUE_CR_CLK_CTRL_BIF_TEXAS_AUTO 0x8000000000000000ULL +#define ROGUE_CR_CLK_CTRL_IPP_SHIFT 60U +#define ROGUE_CR_CLK_CTRL_IPP_CLRMSK 0xCFFFFFFFFFFFFFFFULL +#define ROGUE_CR_CLK_CTRL_IPP_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_IPP_ON 0x1000000000000000ULL +#define ROGUE_CR_CLK_CTRL_IPP_AUTO 0x2000000000000000ULL +#define ROGUE_CR_CLK_CTRL_FBC_SHIFT 58U +#define ROGUE_CR_CLK_CTRL_FBC_CLRMSK 0xF3FFFFFFFFFFFFFFULL +#define ROGUE_CR_CLK_CTRL_FBC_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_FBC_ON 0x0400000000000000ULL +#define ROGUE_CR_CLK_CTRL_FBC_AUTO 0x0800000000000000ULL +#define ROGUE_CR_CLK_CTRL_FBDC_SHIFT 56U +#define ROGUE_CR_CLK_CTRL_FBDC_CLRMSK 0xFCFFFFFFFFFFFFFFULL +#define ROGUE_CR_CLK_CTRL_FBDC_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_FBDC_ON 0x0100000000000000ULL +#define ROGUE_CR_CLK_CTRL_FBDC_AUTO 0x0200000000000000ULL +#define ROGUE_CR_CLK_CTRL_FB_TLCACHE_SHIFT 54U +#define ROGUE_CR_CLK_CTRL_FB_TLCACHE_CLRMSK 0xFF3FFFFFFFFFFFFFULL +#define ROGUE_CR_CLK_CTRL_FB_TLCACHE_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_FB_TLCACHE_ON 0x0040000000000000ULL +#define ROGUE_CR_CLK_CTRL_FB_TLCACHE_AUTO 0x0080000000000000ULL +#define ROGUE_CR_CLK_CTRL_USCS_SHIFT 52U +#define ROGUE_CR_CLK_CTRL_USCS_CLRMSK 0xFFCFFFFFFFFFFFFFULL +#define ROGUE_CR_CLK_CTRL_USCS_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_USCS_ON 0x0010000000000000ULL +#define ROGUE_CR_CLK_CTRL_USCS_AUTO 0x0020000000000000ULL +#define ROGUE_CR_CLK_CTRL_PBE_SHIFT 50U +#define ROGUE_CR_CLK_CTRL_PBE_CLRMSK 0xFFF3FFFFFFFFFFFFULL +#define ROGUE_CR_CLK_CTRL_PBE_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_PBE_ON 0x0004000000000000ULL +#define ROGUE_CR_CLK_CTRL_PBE_AUTO 0x0008000000000000ULL +#define ROGUE_CR_CLK_CTRL_MCU_L1_SHIFT 48U +#define ROGUE_CR_CLK_CTRL_MCU_L1_CLRMSK 0xFFFCFFFFFFFFFFFFULL +#define ROGUE_CR_CLK_CTRL_MCU_L1_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_MCU_L1_ON 0x0001000000000000ULL +#define ROGUE_CR_CLK_CTRL_MCU_L1_AUTO 0x0002000000000000ULL +#define ROGUE_CR_CLK_CTRL_CDM_SHIFT 46U +#define ROGUE_CR_CLK_CTRL_CDM_CLRMSK 0xFFFF3FFFFFFFFFFFULL +#define ROGUE_CR_CLK_CTRL_CDM_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_CDM_ON 0x0000400000000000ULL +#define ROGUE_CR_CLK_CTRL_CDM_AUTO 0x0000800000000000ULL +#define ROGUE_CR_CLK_CTRL_SIDEKICK_SHIFT 44U +#define ROGUE_CR_CLK_CTRL_SIDEKICK_CLRMSK 0xFFFFCFFFFFFFFFFFULL +#define ROGUE_CR_CLK_CTRL_SIDEKICK_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_SIDEKICK_ON 0x0000100000000000ULL +#define ROGUE_CR_CLK_CTRL_SIDEKICK_AUTO 0x0000200000000000ULL +#define ROGUE_CR_CLK_CTRL_BIF_SIDEKICK_SHIFT 42U +#define ROGUE_CR_CLK_CTRL_BIF_SIDEKICK_CLRMSK 0xFFFFF3FFFFFFFFFFULL +#define ROGUE_CR_CLK_CTRL_BIF_SIDEKICK_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_BIF_SIDEKICK_ON 0x0000040000000000ULL +#define ROGUE_CR_CLK_CTRL_BIF_SIDEKICK_AUTO 0x0000080000000000ULL +#define ROGUE_CR_CLK_CTRL_BIF_SHIFT 40U +#define ROGUE_CR_CLK_CTRL_BIF_CLRMSK 0xFFFFFCFFFFFFFFFFULL +#define ROGUE_CR_CLK_CTRL_BIF_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_BIF_ON 0x0000010000000000ULL +#define ROGUE_CR_CLK_CTRL_BIF_AUTO 0x0000020000000000ULL +#define ROGUE_CR_CLK_CTRL_TPU_MCU_DEMUX_SHIFT 28U +#define ROGUE_CR_CLK_CTRL_TPU_MCU_DEMUX_CLRMSK 0xFFFFFFFFCFFFFFFFULL +#define ROGUE_CR_CLK_CTRL_TPU_MCU_DEMUX_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_TPU_MCU_DEMUX_ON 0x0000000010000000ULL +#define ROGUE_CR_CLK_CTRL_TPU_MCU_DEMUX_AUTO 0x0000000020000000ULL +#define ROGUE_CR_CLK_CTRL_MCU_L0_SHIFT 26U +#define ROGUE_CR_CLK_CTRL_MCU_L0_CLRMSK 0xFFFFFFFFF3FFFFFFULL +#define ROGUE_CR_CLK_CTRL_MCU_L0_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_MCU_L0_ON 0x0000000004000000ULL +#define ROGUE_CR_CLK_CTRL_MCU_L0_AUTO 0x0000000008000000ULL +#define ROGUE_CR_CLK_CTRL_TPU_SHIFT 24U +#define ROGUE_CR_CLK_CTRL_TPU_CLRMSK 0xFFFFFFFFFCFFFFFFULL +#define ROGUE_CR_CLK_CTRL_TPU_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_TPU_ON 0x0000000001000000ULL +#define ROGUE_CR_CLK_CTRL_TPU_AUTO 0x0000000002000000ULL +#define ROGUE_CR_CLK_CTRL_USC_SHIFT 20U +#define ROGUE_CR_CLK_CTRL_USC_CLRMSK 0xFFFFFFFFFFCFFFFFULL +#define ROGUE_CR_CLK_CTRL_USC_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_USC_ON 0x0000000000100000ULL +#define ROGUE_CR_CLK_CTRL_USC_AUTO 0x0000000000200000ULL +#define ROGUE_CR_CLK_CTRL_TLA_SHIFT 18U +#define ROGUE_CR_CLK_CTRL_TLA_CLRMSK 0xFFFFFFFFFFF3FFFFULL +#define ROGUE_CR_CLK_CTRL_TLA_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_TLA_ON 0x0000000000040000ULL +#define ROGUE_CR_CLK_CTRL_TLA_AUTO 0x0000000000080000ULL +#define ROGUE_CR_CLK_CTRL_SLC_SHIFT 16U +#define ROGUE_CR_CLK_CTRL_SLC_CLRMSK 0xFFFFFFFFFFFCFFFFULL +#define ROGUE_CR_CLK_CTRL_SLC_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_SLC_ON 0x0000000000010000ULL +#define ROGUE_CR_CLK_CTRL_SLC_AUTO 0x0000000000020000ULL +#define ROGUE_CR_CLK_CTRL_UVS_SHIFT 14U +#define ROGUE_CR_CLK_CTRL_UVS_CLRMSK 0xFFFFFFFFFFFF3FFFULL +#define ROGUE_CR_CLK_CTRL_UVS_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_UVS_ON 0x0000000000004000ULL +#define ROGUE_CR_CLK_CTRL_UVS_AUTO 0x0000000000008000ULL +#define ROGUE_CR_CLK_CTRL_PDS_SHIFT 12U +#define ROGUE_CR_CLK_CTRL_PDS_CLRMSK 0xFFFFFFFFFFFFCFFFULL +#define ROGUE_CR_CLK_CTRL_PDS_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_PDS_ON 0x0000000000001000ULL +#define ROGUE_CR_CLK_CTRL_PDS_AUTO 0x0000000000002000ULL +#define ROGUE_CR_CLK_CTRL_VDM_SHIFT 10U +#define ROGUE_CR_CLK_CTRL_VDM_CLRMSK 0xFFFFFFFFFFFFF3FFULL +#define ROGUE_CR_CLK_CTRL_VDM_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_VDM_ON 0x0000000000000400ULL +#define ROGUE_CR_CLK_CTRL_VDM_AUTO 0x0000000000000800ULL +#define ROGUE_CR_CLK_CTRL_PM_SHIFT 8U +#define ROGUE_CR_CLK_CTRL_PM_CLRMSK 0xFFFFFFFFFFFFFCFFULL +#define ROGUE_CR_CLK_CTRL_PM_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_PM_ON 0x0000000000000100ULL +#define ROGUE_CR_CLK_CTRL_PM_AUTO 0x0000000000000200ULL +#define ROGUE_CR_CLK_CTRL_GPP_SHIFT 6U +#define ROGUE_CR_CLK_CTRL_GPP_CLRMSK 0xFFFFFFFFFFFFFF3FULL +#define ROGUE_CR_CLK_CTRL_GPP_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_GPP_ON 0x0000000000000040ULL +#define ROGUE_CR_CLK_CTRL_GPP_AUTO 0x0000000000000080ULL +#define ROGUE_CR_CLK_CTRL_TE_SHIFT 4U +#define ROGUE_CR_CLK_CTRL_TE_CLRMSK 0xFFFFFFFFFFFFFFCFULL +#define ROGUE_CR_CLK_CTRL_TE_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_TE_ON 0x0000000000000010ULL +#define ROGUE_CR_CLK_CTRL_TE_AUTO 0x0000000000000020ULL +#define ROGUE_CR_CLK_CTRL_TSP_SHIFT 2U +#define ROGUE_CR_CLK_CTRL_TSP_CLRMSK 0xFFFFFFFFFFFFFFF3ULL +#define ROGUE_CR_CLK_CTRL_TSP_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_TSP_ON 0x0000000000000004ULL +#define ROGUE_CR_CLK_CTRL_TSP_AUTO 0x0000000000000008ULL +#define ROGUE_CR_CLK_CTRL_ISP_SHIFT 0U +#define ROGUE_CR_CLK_CTRL_ISP_CLRMSK 0xFFFFFFFFFFFFFFFCULL +#define ROGUE_CR_CLK_CTRL_ISP_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL_ISP_ON 0x0000000000000001ULL +#define ROGUE_CR_CLK_CTRL_ISP_AUTO 0x0000000000000002ULL + +/* Register ROGUE_CR_CLK_STATUS */ +#define ROGUE_CR_CLK_STATUS 0x0008U +#define ROGUE_CR_CLK_STATUS__PBE2_XE__MASKFULL 0x00000001FFF077FFULL +#define ROGUE_CR_CLK_STATUS__S7_TOP__MASKFULL 0x00000001B3101773ULL +#define ROGUE_CR_CLK_STATUS_MASKFULL 0x00000001FFF077FFULL +#define ROGUE_CR_CLK_STATUS_MCU_FBTC_SHIFT 32U +#define ROGUE_CR_CLK_STATUS_MCU_FBTC_CLRMSK 0xFFFFFFFEFFFFFFFFULL +#define ROGUE_CR_CLK_STATUS_MCU_FBTC_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_MCU_FBTC_RUNNING 0x0000000100000000ULL +#define ROGUE_CR_CLK_STATUS_BIF_TEXAS_SHIFT 31U +#define ROGUE_CR_CLK_STATUS_BIF_TEXAS_CLRMSK 0xFFFFFFFF7FFFFFFFULL +#define ROGUE_CR_CLK_STATUS_BIF_TEXAS_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_BIF_TEXAS_RUNNING 0x0000000080000000ULL +#define ROGUE_CR_CLK_STATUS_IPP_SHIFT 30U +#define ROGUE_CR_CLK_STATUS_IPP_CLRMSK 0xFFFFFFFFBFFFFFFFULL +#define ROGUE_CR_CLK_STATUS_IPP_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_IPP_RUNNING 0x0000000040000000ULL +#define ROGUE_CR_CLK_STATUS_FBC_SHIFT 29U +#define ROGUE_CR_CLK_STATUS_FBC_CLRMSK 0xFFFFFFFFDFFFFFFFULL +#define ROGUE_CR_CLK_STATUS_FBC_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_FBC_RUNNING 0x0000000020000000ULL +#define ROGUE_CR_CLK_STATUS_FBDC_SHIFT 28U +#define ROGUE_CR_CLK_STATUS_FBDC_CLRMSK 0xFFFFFFFFEFFFFFFFULL +#define ROGUE_CR_CLK_STATUS_FBDC_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_FBDC_RUNNING 0x0000000010000000ULL +#define ROGUE_CR_CLK_STATUS_FB_TLCACHE_SHIFT 27U +#define ROGUE_CR_CLK_STATUS_FB_TLCACHE_CLRMSK 0xFFFFFFFFF7FFFFFFULL +#define ROGUE_CR_CLK_STATUS_FB_TLCACHE_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_FB_TLCACHE_RUNNING 0x0000000008000000ULL +#define ROGUE_CR_CLK_STATUS_USCS_SHIFT 26U +#define ROGUE_CR_CLK_STATUS_USCS_CLRMSK 0xFFFFFFFFFBFFFFFFULL +#define ROGUE_CR_CLK_STATUS_USCS_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_USCS_RUNNING 0x0000000004000000ULL +#define ROGUE_CR_CLK_STATUS_PBE_SHIFT 25U +#define ROGUE_CR_CLK_STATUS_PBE_CLRMSK 0xFFFFFFFFFDFFFFFFULL +#define ROGUE_CR_CLK_STATUS_PBE_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_PBE_RUNNING 0x0000000002000000ULL +#define ROGUE_CR_CLK_STATUS_MCU_L1_SHIFT 24U +#define ROGUE_CR_CLK_STATUS_MCU_L1_CLRMSK 0xFFFFFFFFFEFFFFFFULL +#define ROGUE_CR_CLK_STATUS_MCU_L1_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_MCU_L1_RUNNING 0x0000000001000000ULL +#define ROGUE_CR_CLK_STATUS_CDM_SHIFT 23U +#define ROGUE_CR_CLK_STATUS_CDM_CLRMSK 0xFFFFFFFFFF7FFFFFULL +#define ROGUE_CR_CLK_STATUS_CDM_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_CDM_RUNNING 0x0000000000800000ULL +#define ROGUE_CR_CLK_STATUS_SIDEKICK_SHIFT 22U +#define ROGUE_CR_CLK_STATUS_SIDEKICK_CLRMSK 0xFFFFFFFFFFBFFFFFULL +#define ROGUE_CR_CLK_STATUS_SIDEKICK_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_SIDEKICK_RUNNING 0x0000000000400000ULL +#define ROGUE_CR_CLK_STATUS_BIF_SIDEKICK_SHIFT 21U +#define ROGUE_CR_CLK_STATUS_BIF_SIDEKICK_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define ROGUE_CR_CLK_STATUS_BIF_SIDEKICK_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_BIF_SIDEKICK_RUNNING 0x0000000000200000ULL +#define ROGUE_CR_CLK_STATUS_BIF_SHIFT 20U +#define ROGUE_CR_CLK_STATUS_BIF_CLRMSK 0xFFFFFFFFFFEFFFFFULL +#define ROGUE_CR_CLK_STATUS_BIF_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_BIF_RUNNING 0x0000000000100000ULL +#define ROGUE_CR_CLK_STATUS_TPU_MCU_DEMUX_SHIFT 14U +#define ROGUE_CR_CLK_STATUS_TPU_MCU_DEMUX_CLRMSK 0xFFFFFFFFFFFFBFFFULL +#define ROGUE_CR_CLK_STATUS_TPU_MCU_DEMUX_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_TPU_MCU_DEMUX_RUNNING 0x0000000000004000ULL +#define ROGUE_CR_CLK_STATUS_MCU_L0_SHIFT 13U +#define ROGUE_CR_CLK_STATUS_MCU_L0_CLRMSK 0xFFFFFFFFFFFFDFFFULL +#define ROGUE_CR_CLK_STATUS_MCU_L0_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_MCU_L0_RUNNING 0x0000000000002000ULL +#define ROGUE_CR_CLK_STATUS_TPU_SHIFT 12U +#define ROGUE_CR_CLK_STATUS_TPU_CLRMSK 0xFFFFFFFFFFFFEFFFULL +#define ROGUE_CR_CLK_STATUS_TPU_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_TPU_RUNNING 0x0000000000001000ULL +#define ROGUE_CR_CLK_STATUS_USC_SHIFT 10U +#define ROGUE_CR_CLK_STATUS_USC_CLRMSK 0xFFFFFFFFFFFFFBFFULL +#define ROGUE_CR_CLK_STATUS_USC_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_USC_RUNNING 0x0000000000000400ULL +#define ROGUE_CR_CLK_STATUS_TLA_SHIFT 9U +#define ROGUE_CR_CLK_STATUS_TLA_CLRMSK 0xFFFFFFFFFFFFFDFFULL +#define ROGUE_CR_CLK_STATUS_TLA_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_TLA_RUNNING 0x0000000000000200ULL +#define ROGUE_CR_CLK_STATUS_SLC_SHIFT 8U +#define ROGUE_CR_CLK_STATUS_SLC_CLRMSK 0xFFFFFFFFFFFFFEFFULL +#define ROGUE_CR_CLK_STATUS_SLC_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_SLC_RUNNING 0x0000000000000100ULL +#define ROGUE_CR_CLK_STATUS_UVS_SHIFT 7U +#define ROGUE_CR_CLK_STATUS_UVS_CLRMSK 0xFFFFFFFFFFFFFF7FULL +#define ROGUE_CR_CLK_STATUS_UVS_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_UVS_RUNNING 0x0000000000000080ULL +#define ROGUE_CR_CLK_STATUS_PDS_SHIFT 6U +#define ROGUE_CR_CLK_STATUS_PDS_CLRMSK 0xFFFFFFFFFFFFFFBFULL +#define ROGUE_CR_CLK_STATUS_PDS_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_PDS_RUNNING 0x0000000000000040ULL +#define ROGUE_CR_CLK_STATUS_VDM_SHIFT 5U +#define ROGUE_CR_CLK_STATUS_VDM_CLRMSK 0xFFFFFFFFFFFFFFDFULL +#define ROGUE_CR_CLK_STATUS_VDM_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_VDM_RUNNING 0x0000000000000020ULL +#define ROGUE_CR_CLK_STATUS_PM_SHIFT 4U +#define ROGUE_CR_CLK_STATUS_PM_CLRMSK 0xFFFFFFFFFFFFFFEFULL +#define ROGUE_CR_CLK_STATUS_PM_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_PM_RUNNING 0x0000000000000010ULL +#define ROGUE_CR_CLK_STATUS_GPP_SHIFT 3U +#define ROGUE_CR_CLK_STATUS_GPP_CLRMSK 0xFFFFFFFFFFFFFFF7ULL +#define ROGUE_CR_CLK_STATUS_GPP_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_GPP_RUNNING 0x0000000000000008ULL +#define ROGUE_CR_CLK_STATUS_TE_SHIFT 2U +#define ROGUE_CR_CLK_STATUS_TE_CLRMSK 0xFFFFFFFFFFFFFFFBULL +#define ROGUE_CR_CLK_STATUS_TE_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_TE_RUNNING 0x0000000000000004ULL +#define ROGUE_CR_CLK_STATUS_TSP_SHIFT 1U +#define ROGUE_CR_CLK_STATUS_TSP_CLRMSK 0xFFFFFFFFFFFFFFFDULL +#define ROGUE_CR_CLK_STATUS_TSP_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_TSP_RUNNING 0x0000000000000002ULL +#define ROGUE_CR_CLK_STATUS_ISP_SHIFT 0U +#define ROGUE_CR_CLK_STATUS_ISP_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_CLK_STATUS_ISP_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS_ISP_RUNNING 0x0000000000000001ULL + +/* Register ROGUE_CR_CORE_ID */ +#define ROGUE_CR_CORE_ID__PBVNC 0x0020U +#define ROGUE_CR_CORE_ID__PBVNC__MASKFULL 0xFFFFFFFFFFFFFFFFULL +#define ROGUE_CR_CORE_ID__PBVNC__BRANCH_ID_SHIFT 48U +#define ROGUE_CR_CORE_ID__PBVNC__BRANCH_ID_CLRMSK 0x0000FFFFFFFFFFFFULL +#define ROGUE_CR_CORE_ID__PBVNC__VERSION_ID_SHIFT 32U +#define ROGUE_CR_CORE_ID__PBVNC__VERSION_ID_CLRMSK 0xFFFF0000FFFFFFFFULL +#define ROGUE_CR_CORE_ID__PBVNC__NUMBER_OF_SCALABLE_UNITS_SHIFT 16U +#define ROGUE_CR_CORE_ID__PBVNC__NUMBER_OF_SCALABLE_UNITS_CLRMSK 0xFFFFFFFF0000FFFFULL +#define ROGUE_CR_CORE_ID__PBVNC__CONFIG_ID_SHIFT 0U +#define ROGUE_CR_CORE_ID__PBVNC__CONFIG_ID_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_CORE_ID */ +#define ROGUE_CR_CORE_ID 0x0018U +#define ROGUE_CR_CORE_ID_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_CORE_ID_ID_SHIFT 16U +#define ROGUE_CR_CORE_ID_ID_CLRMSK 0x0000FFFFU +#define ROGUE_CR_CORE_ID_CONFIG_SHIFT 0U +#define ROGUE_CR_CORE_ID_CONFIG_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_CORE_REVISION */ +#define ROGUE_CR_CORE_REVISION 0x0020U +#define ROGUE_CR_CORE_REVISION_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_CORE_REVISION_DESIGNER_SHIFT 24U +#define ROGUE_CR_CORE_REVISION_DESIGNER_CLRMSK 0x00FFFFFFU +#define ROGUE_CR_CORE_REVISION_MAJOR_SHIFT 16U +#define ROGUE_CR_CORE_REVISION_MAJOR_CLRMSK 0xFF00FFFFU +#define ROGUE_CR_CORE_REVISION_MINOR_SHIFT 8U +#define ROGUE_CR_CORE_REVISION_MINOR_CLRMSK 0xFFFF00FFU +#define ROGUE_CR_CORE_REVISION_MAINTENANCE_SHIFT 0U +#define ROGUE_CR_CORE_REVISION_MAINTENANCE_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_DESIGNER_REV_FIELD1 */ +#define ROGUE_CR_DESIGNER_REV_FIELD1 0x0028U +#define ROGUE_CR_DESIGNER_REV_FIELD1_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_DESIGNER_REV_FIELD1_DESIGNER_REV_FIELD1_SHIFT 0U +#define ROGUE_CR_DESIGNER_REV_FIELD1_DESIGNER_REV_FIELD1_CLRMSK 0x00000000U + +/* Register ROGUE_CR_DESIGNER_REV_FIELD2 */ +#define ROGUE_CR_DESIGNER_REV_FIELD2 0x0030U +#define ROGUE_CR_DESIGNER_REV_FIELD2_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_DESIGNER_REV_FIELD2_DESIGNER_REV_FIELD2_SHIFT 0U +#define ROGUE_CR_DESIGNER_REV_FIELD2_DESIGNER_REV_FIELD2_CLRMSK 0x00000000U + +/* Register ROGUE_CR_CHANGESET_NUMBER */ +#define ROGUE_CR_CHANGESET_NUMBER 0x0040U +#define ROGUE_CR_CHANGESET_NUMBER_MASKFULL 0xFFFFFFFFFFFFFFFFULL +#define ROGUE_CR_CHANGESET_NUMBER_CHANGESET_NUMBER_SHIFT 0U +#define ROGUE_CR_CHANGESET_NUMBER_CHANGESET_NUMBER_CLRMSK 0x0000000000000000ULL + +/* Register ROGUE_CR_CLK_XTPLUS_CTRL */ +#define ROGUE_CR_CLK_XTPLUS_CTRL 0x0080U +#define ROGUE_CR_CLK_XTPLUS_CTRL_MASKFULL 0x0000003FFFFF0000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_TDM_SHIFT 36U +#define ROGUE_CR_CLK_XTPLUS_CTRL_TDM_CLRMSK 0xFFFFFFCFFFFFFFFFULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_TDM_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_TDM_ON 0x0000001000000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_TDM_AUTO 0x0000002000000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_ASTC_SHIFT 34U +#define ROGUE_CR_CLK_XTPLUS_CTRL_ASTC_CLRMSK 0xFFFFFFF3FFFFFFFFULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_ASTC_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_ASTC_ON 0x0000000400000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_ASTC_AUTO 0x0000000800000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_IPF_SHIFT 32U +#define ROGUE_CR_CLK_XTPLUS_CTRL_IPF_CLRMSK 0xFFFFFFFCFFFFFFFFULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_IPF_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_IPF_ON 0x0000000100000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_IPF_AUTO 0x0000000200000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_COMPUTE_SHIFT 30U +#define ROGUE_CR_CLK_XTPLUS_CTRL_COMPUTE_CLRMSK 0xFFFFFFFF3FFFFFFFULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_COMPUTE_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_COMPUTE_ON 0x0000000040000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_COMPUTE_AUTO 0x0000000080000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_PIXEL_SHIFT 28U +#define ROGUE_CR_CLK_XTPLUS_CTRL_PIXEL_CLRMSK 0xFFFFFFFFCFFFFFFFULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_PIXEL_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_PIXEL_ON 0x0000000010000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_PIXEL_AUTO 0x0000000020000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_VERTEX_SHIFT 26U +#define ROGUE_CR_CLK_XTPLUS_CTRL_VERTEX_CLRMSK 0xFFFFFFFFF3FFFFFFULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_VERTEX_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_VERTEX_ON 0x0000000004000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_VERTEX_AUTO 0x0000000008000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_USCPS_SHIFT 24U +#define ROGUE_CR_CLK_XTPLUS_CTRL_USCPS_CLRMSK 0xFFFFFFFFFCFFFFFFULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_USCPS_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_USCPS_ON 0x0000000001000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_USCPS_AUTO 0x0000000002000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_PDS_SHARED_SHIFT 22U +#define ROGUE_CR_CLK_XTPLUS_CTRL_PDS_SHARED_CLRMSK 0xFFFFFFFFFF3FFFFFULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_PDS_SHARED_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_PDS_SHARED_ON 0x0000000000400000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_PDS_SHARED_AUTO 0x0000000000800000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_BIF_BLACKPEARL_SHIFT 20U +#define ROGUE_CR_CLK_XTPLUS_CTRL_BIF_BLACKPEARL_CLRMSK 0xFFFFFFFFFFCFFFFFULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_BIF_BLACKPEARL_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_BIF_BLACKPEARL_ON 0x0000000000100000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_BIF_BLACKPEARL_AUTO 0x0000000000200000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_USC_SHARED_SHIFT 18U +#define ROGUE_CR_CLK_XTPLUS_CTRL_USC_SHARED_CLRMSK 0xFFFFFFFFFFF3FFFFULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_USC_SHARED_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_USC_SHARED_ON 0x0000000000040000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_USC_SHARED_AUTO 0x0000000000080000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_GEOMETRY_SHIFT 16U +#define ROGUE_CR_CLK_XTPLUS_CTRL_GEOMETRY_CLRMSK 0xFFFFFFFFFFFCFFFFULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_GEOMETRY_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_GEOMETRY_ON 0x0000000000010000ULL +#define ROGUE_CR_CLK_XTPLUS_CTRL_GEOMETRY_AUTO 0x0000000000020000ULL + +/* Register ROGUE_CR_CLK_XTPLUS_STATUS */ +#define ROGUE_CR_CLK_XTPLUS_STATUS 0x0088U +#define ROGUE_CR_CLK_XTPLUS_STATUS_MASKFULL 0x00000000000007FFULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_TDM_SHIFT 10U +#define ROGUE_CR_CLK_XTPLUS_STATUS_TDM_CLRMSK 0xFFFFFFFFFFFFFBFFULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_TDM_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_TDM_RUNNING 0x0000000000000400ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_IPF_SHIFT 9U +#define ROGUE_CR_CLK_XTPLUS_STATUS_IPF_CLRMSK 0xFFFFFFFFFFFFFDFFULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_IPF_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_IPF_RUNNING 0x0000000000000200ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_COMPUTE_SHIFT 8U +#define ROGUE_CR_CLK_XTPLUS_STATUS_COMPUTE_CLRMSK 0xFFFFFFFFFFFFFEFFULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_COMPUTE_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_COMPUTE_RUNNING 0x0000000000000100ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_ASTC_SHIFT 7U +#define ROGUE_CR_CLK_XTPLUS_STATUS_ASTC_CLRMSK 0xFFFFFFFFFFFFFF7FULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_ASTC_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_ASTC_RUNNING 0x0000000000000080ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_PIXEL_SHIFT 6U +#define ROGUE_CR_CLK_XTPLUS_STATUS_PIXEL_CLRMSK 0xFFFFFFFFFFFFFFBFULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_PIXEL_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_PIXEL_RUNNING 0x0000000000000040ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_VERTEX_SHIFT 5U +#define ROGUE_CR_CLK_XTPLUS_STATUS_VERTEX_CLRMSK 0xFFFFFFFFFFFFFFDFULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_VERTEX_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_VERTEX_RUNNING 0x0000000000000020ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_USCPS_SHIFT 4U +#define ROGUE_CR_CLK_XTPLUS_STATUS_USCPS_CLRMSK 0xFFFFFFFFFFFFFFEFULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_USCPS_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_USCPS_RUNNING 0x0000000000000010ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_PDS_SHARED_SHIFT 3U +#define ROGUE_CR_CLK_XTPLUS_STATUS_PDS_SHARED_CLRMSK 0xFFFFFFFFFFFFFFF7ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_PDS_SHARED_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_PDS_SHARED_RUNNING 0x0000000000000008ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_BIF_BLACKPEARL_SHIFT 2U +#define ROGUE_CR_CLK_XTPLUS_STATUS_BIF_BLACKPEARL_CLRMSK 0xFFFFFFFFFFFFFFFBULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_BIF_BLACKPEARL_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_BIF_BLACKPEARL_RUNNING 0x0000000000000004ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_USC_SHARED_SHIFT 1U +#define ROGUE_CR_CLK_XTPLUS_STATUS_USC_SHARED_CLRMSK 0xFFFFFFFFFFFFFFFDULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_USC_SHARED_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_USC_SHARED_RUNNING 0x0000000000000002ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_GEOMETRY_SHIFT 0U +#define ROGUE_CR_CLK_XTPLUS_STATUS_GEOMETRY_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_GEOMETRY_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_XTPLUS_STATUS_GEOMETRY_RUNNING 0x0000000000000001ULL + +/* Register ROGUE_CR_SOFT_RESET */ +#define ROGUE_CR_SOFT_RESET 0x0100U +#define ROGUE_CR_SOFT_RESET__PBE2_XE__MASKFULL 0xFFEFFFFFFFFFFC3DULL +#define ROGUE_CR_SOFT_RESET_MASKFULL 0x00E7FFFFFFFFFC3DULL +#define ROGUE_CR_SOFT_RESET_PHANTOM3_CORE_SHIFT 63U +#define ROGUE_CR_SOFT_RESET_PHANTOM3_CORE_CLRMSK 0x7FFFFFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_PHANTOM3_CORE_EN 0x8000000000000000ULL +#define ROGUE_CR_SOFT_RESET_PHANTOM2_CORE_SHIFT 62U +#define ROGUE_CR_SOFT_RESET_PHANTOM2_CORE_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_PHANTOM2_CORE_EN 0x4000000000000000ULL +#define ROGUE_CR_SOFT_RESET_BERNADO2_CORE_SHIFT 61U +#define ROGUE_CR_SOFT_RESET_BERNADO2_CORE_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_BERNADO2_CORE_EN 0x2000000000000000ULL +#define ROGUE_CR_SOFT_RESET_JONES_CORE_SHIFT 60U +#define ROGUE_CR_SOFT_RESET_JONES_CORE_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_JONES_CORE_EN 0x1000000000000000ULL +#define ROGUE_CR_SOFT_RESET_TILING_CORE_SHIFT 59U +#define ROGUE_CR_SOFT_RESET_TILING_CORE_CLRMSK 0xF7FFFFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_TILING_CORE_EN 0x0800000000000000ULL +#define ROGUE_CR_SOFT_RESET_TE3_SHIFT 58U +#define ROGUE_CR_SOFT_RESET_TE3_CLRMSK 0xFBFFFFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_TE3_EN 0x0400000000000000ULL +#define ROGUE_CR_SOFT_RESET_VCE_SHIFT 57U +#define ROGUE_CR_SOFT_RESET_VCE_CLRMSK 0xFDFFFFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_VCE_EN 0x0200000000000000ULL +#define ROGUE_CR_SOFT_RESET_VBS_SHIFT 56U +#define ROGUE_CR_SOFT_RESET_VBS_CLRMSK 0xFEFFFFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_VBS_EN 0x0100000000000000ULL +#define ROGUE_CR_SOFT_RESET_DPX1_CORE_SHIFT 55U +#define ROGUE_CR_SOFT_RESET_DPX1_CORE_CLRMSK 0xFF7FFFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_DPX1_CORE_EN 0x0080000000000000ULL +#define ROGUE_CR_SOFT_RESET_DPX0_CORE_SHIFT 54U +#define ROGUE_CR_SOFT_RESET_DPX0_CORE_CLRMSK 0xFFBFFFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_DPX0_CORE_EN 0x0040000000000000ULL +#define ROGUE_CR_SOFT_RESET_FBA_SHIFT 53U +#define ROGUE_CR_SOFT_RESET_FBA_CLRMSK 0xFFDFFFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_FBA_EN 0x0020000000000000ULL +#define ROGUE_CR_SOFT_RESET_FB_CDC_SHIFT 51U +#define ROGUE_CR_SOFT_RESET_FB_CDC_CLRMSK 0xFFF7FFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_FB_CDC_EN 0x0008000000000000ULL +#define ROGUE_CR_SOFT_RESET_SH_SHIFT 50U +#define ROGUE_CR_SOFT_RESET_SH_CLRMSK 0xFFFBFFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_SH_EN 0x0004000000000000ULL +#define ROGUE_CR_SOFT_RESET_VRDM_SHIFT 49U +#define ROGUE_CR_SOFT_RESET_VRDM_CLRMSK 0xFFFDFFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_VRDM_EN 0x0002000000000000ULL +#define ROGUE_CR_SOFT_RESET_MCU_FBTC_SHIFT 48U +#define ROGUE_CR_SOFT_RESET_MCU_FBTC_CLRMSK 0xFFFEFFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_MCU_FBTC_EN 0x0001000000000000ULL +#define ROGUE_CR_SOFT_RESET_PHANTOM1_CORE_SHIFT 47U +#define ROGUE_CR_SOFT_RESET_PHANTOM1_CORE_CLRMSK 0xFFFF7FFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_PHANTOM1_CORE_EN 0x0000800000000000ULL +#define ROGUE_CR_SOFT_RESET_PHANTOM0_CORE_SHIFT 46U +#define ROGUE_CR_SOFT_RESET_PHANTOM0_CORE_CLRMSK 0xFFFFBFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_PHANTOM0_CORE_EN 0x0000400000000000ULL +#define ROGUE_CR_SOFT_RESET_BERNADO1_CORE_SHIFT 45U +#define ROGUE_CR_SOFT_RESET_BERNADO1_CORE_CLRMSK 0xFFFFDFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_BERNADO1_CORE_EN 0x0000200000000000ULL +#define ROGUE_CR_SOFT_RESET_BERNADO0_CORE_SHIFT 44U +#define ROGUE_CR_SOFT_RESET_BERNADO0_CORE_CLRMSK 0xFFFFEFFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_BERNADO0_CORE_EN 0x0000100000000000ULL +#define ROGUE_CR_SOFT_RESET_IPP_SHIFT 43U +#define ROGUE_CR_SOFT_RESET_IPP_CLRMSK 0xFFFFF7FFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_IPP_EN 0x0000080000000000ULL +#define ROGUE_CR_SOFT_RESET_BIF_TEXAS_SHIFT 42U +#define ROGUE_CR_SOFT_RESET_BIF_TEXAS_CLRMSK 0xFFFFFBFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_BIF_TEXAS_EN 0x0000040000000000ULL +#define ROGUE_CR_SOFT_RESET_TORNADO_CORE_SHIFT 41U +#define ROGUE_CR_SOFT_RESET_TORNADO_CORE_CLRMSK 0xFFFFFDFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_TORNADO_CORE_EN 0x0000020000000000ULL +#define ROGUE_CR_SOFT_RESET_DUST_H_CORE_SHIFT 40U +#define ROGUE_CR_SOFT_RESET_DUST_H_CORE_CLRMSK 0xFFFFFEFFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_DUST_H_CORE_EN 0x0000010000000000ULL +#define ROGUE_CR_SOFT_RESET_DUST_G_CORE_SHIFT 39U +#define ROGUE_CR_SOFT_RESET_DUST_G_CORE_CLRMSK 0xFFFFFF7FFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_DUST_G_CORE_EN 0x0000008000000000ULL +#define ROGUE_CR_SOFT_RESET_DUST_F_CORE_SHIFT 38U +#define ROGUE_CR_SOFT_RESET_DUST_F_CORE_CLRMSK 0xFFFFFFBFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_DUST_F_CORE_EN 0x0000004000000000ULL +#define ROGUE_CR_SOFT_RESET_DUST_E_CORE_SHIFT 37U +#define ROGUE_CR_SOFT_RESET_DUST_E_CORE_CLRMSK 0xFFFFFFDFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_DUST_E_CORE_EN 0x0000002000000000ULL +#define ROGUE_CR_SOFT_RESET_DUST_D_CORE_SHIFT 36U +#define ROGUE_CR_SOFT_RESET_DUST_D_CORE_CLRMSK 0xFFFFFFEFFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_DUST_D_CORE_EN 0x0000001000000000ULL +#define ROGUE_CR_SOFT_RESET_DUST_C_CORE_SHIFT 35U +#define ROGUE_CR_SOFT_RESET_DUST_C_CORE_CLRMSK 0xFFFFFFF7FFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_DUST_C_CORE_EN 0x0000000800000000ULL +#define ROGUE_CR_SOFT_RESET_MMU_SHIFT 34U +#define ROGUE_CR_SOFT_RESET_MMU_CLRMSK 0xFFFFFFFBFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_MMU_EN 0x0000000400000000ULL +#define ROGUE_CR_SOFT_RESET_BIF1_SHIFT 33U +#define ROGUE_CR_SOFT_RESET_BIF1_CLRMSK 0xFFFFFFFDFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_BIF1_EN 0x0000000200000000ULL +#define ROGUE_CR_SOFT_RESET_GARTEN_SHIFT 32U +#define ROGUE_CR_SOFT_RESET_GARTEN_CLRMSK 0xFFFFFFFEFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_GARTEN_EN 0x0000000100000000ULL +#define ROGUE_CR_SOFT_RESET_CPU_SHIFT 32U +#define ROGUE_CR_SOFT_RESET_CPU_CLRMSK 0xFFFFFFFEFFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_CPU_EN 0x0000000100000000ULL +#define ROGUE_CR_SOFT_RESET_RASCAL_CORE_SHIFT 31U +#define ROGUE_CR_SOFT_RESET_RASCAL_CORE_CLRMSK 0xFFFFFFFF7FFFFFFFULL +#define ROGUE_CR_SOFT_RESET_RASCAL_CORE_EN 0x0000000080000000ULL +#define ROGUE_CR_SOFT_RESET_DUST_B_CORE_SHIFT 30U +#define ROGUE_CR_SOFT_RESET_DUST_B_CORE_CLRMSK 0xFFFFFFFFBFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_DUST_B_CORE_EN 0x0000000040000000ULL +#define ROGUE_CR_SOFT_RESET_DUST_A_CORE_SHIFT 29U +#define ROGUE_CR_SOFT_RESET_DUST_A_CORE_CLRMSK 0xFFFFFFFFDFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_DUST_A_CORE_EN 0x0000000020000000ULL +#define ROGUE_CR_SOFT_RESET_FB_TLCACHE_SHIFT 28U +#define ROGUE_CR_SOFT_RESET_FB_TLCACHE_CLRMSK 0xFFFFFFFFEFFFFFFFULL +#define ROGUE_CR_SOFT_RESET_FB_TLCACHE_EN 0x0000000010000000ULL +#define ROGUE_CR_SOFT_RESET_SLC_SHIFT 27U +#define ROGUE_CR_SOFT_RESET_SLC_CLRMSK 0xFFFFFFFFF7FFFFFFULL +#define ROGUE_CR_SOFT_RESET_SLC_EN 0x0000000008000000ULL +#define ROGUE_CR_SOFT_RESET_TLA_SHIFT 26U +#define ROGUE_CR_SOFT_RESET_TLA_CLRMSK 0xFFFFFFFFFBFFFFFFULL +#define ROGUE_CR_SOFT_RESET_TLA_EN 0x0000000004000000ULL +#define ROGUE_CR_SOFT_RESET_UVS_SHIFT 25U +#define ROGUE_CR_SOFT_RESET_UVS_CLRMSK 0xFFFFFFFFFDFFFFFFULL +#define ROGUE_CR_SOFT_RESET_UVS_EN 0x0000000002000000ULL +#define ROGUE_CR_SOFT_RESET_TE_SHIFT 24U +#define ROGUE_CR_SOFT_RESET_TE_CLRMSK 0xFFFFFFFFFEFFFFFFULL +#define ROGUE_CR_SOFT_RESET_TE_EN 0x0000000001000000ULL +#define ROGUE_CR_SOFT_RESET_GPP_SHIFT 23U +#define ROGUE_CR_SOFT_RESET_GPP_CLRMSK 0xFFFFFFFFFF7FFFFFULL +#define ROGUE_CR_SOFT_RESET_GPP_EN 0x0000000000800000ULL +#define ROGUE_CR_SOFT_RESET_FBDC_SHIFT 22U +#define ROGUE_CR_SOFT_RESET_FBDC_CLRMSK 0xFFFFFFFFFFBFFFFFULL +#define ROGUE_CR_SOFT_RESET_FBDC_EN 0x0000000000400000ULL +#define ROGUE_CR_SOFT_RESET_FBC_SHIFT 21U +#define ROGUE_CR_SOFT_RESET_FBC_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define ROGUE_CR_SOFT_RESET_FBC_EN 0x0000000000200000ULL +#define ROGUE_CR_SOFT_RESET_PM_SHIFT 20U +#define ROGUE_CR_SOFT_RESET_PM_CLRMSK 0xFFFFFFFFFFEFFFFFULL +#define ROGUE_CR_SOFT_RESET_PM_EN 0x0000000000100000ULL +#define ROGUE_CR_SOFT_RESET_PBE_SHIFT 19U +#define ROGUE_CR_SOFT_RESET_PBE_CLRMSK 0xFFFFFFFFFFF7FFFFULL +#define ROGUE_CR_SOFT_RESET_PBE_EN 0x0000000000080000ULL +#define ROGUE_CR_SOFT_RESET_USC_SHARED_SHIFT 18U +#define ROGUE_CR_SOFT_RESET_USC_SHARED_CLRMSK 0xFFFFFFFFFFFBFFFFULL +#define ROGUE_CR_SOFT_RESET_USC_SHARED_EN 0x0000000000040000ULL +#define ROGUE_CR_SOFT_RESET_MCU_L1_SHIFT 17U +#define ROGUE_CR_SOFT_RESET_MCU_L1_CLRMSK 0xFFFFFFFFFFFDFFFFULL +#define ROGUE_CR_SOFT_RESET_MCU_L1_EN 0x0000000000020000ULL +#define ROGUE_CR_SOFT_RESET_BIF_SHIFT 16U +#define ROGUE_CR_SOFT_RESET_BIF_CLRMSK 0xFFFFFFFFFFFEFFFFULL +#define ROGUE_CR_SOFT_RESET_BIF_EN 0x0000000000010000ULL +#define ROGUE_CR_SOFT_RESET_CDM_SHIFT 15U +#define ROGUE_CR_SOFT_RESET_CDM_CLRMSK 0xFFFFFFFFFFFF7FFFULL +#define ROGUE_CR_SOFT_RESET_CDM_EN 0x0000000000008000ULL +#define ROGUE_CR_SOFT_RESET_VDM_SHIFT 14U +#define ROGUE_CR_SOFT_RESET_VDM_CLRMSK 0xFFFFFFFFFFFFBFFFULL +#define ROGUE_CR_SOFT_RESET_VDM_EN 0x0000000000004000ULL +#define ROGUE_CR_SOFT_RESET_TESS_SHIFT 13U +#define ROGUE_CR_SOFT_RESET_TESS_CLRMSK 0xFFFFFFFFFFFFDFFFULL +#define ROGUE_CR_SOFT_RESET_TESS_EN 0x0000000000002000ULL +#define ROGUE_CR_SOFT_RESET_PDS_SHIFT 12U +#define ROGUE_CR_SOFT_RESET_PDS_CLRMSK 0xFFFFFFFFFFFFEFFFULL +#define ROGUE_CR_SOFT_RESET_PDS_EN 0x0000000000001000ULL +#define ROGUE_CR_SOFT_RESET_ISP_SHIFT 11U +#define ROGUE_CR_SOFT_RESET_ISP_CLRMSK 0xFFFFFFFFFFFFF7FFULL +#define ROGUE_CR_SOFT_RESET_ISP_EN 0x0000000000000800ULL +#define ROGUE_CR_SOFT_RESET_TSP_SHIFT 10U +#define ROGUE_CR_SOFT_RESET_TSP_CLRMSK 0xFFFFFFFFFFFFFBFFULL +#define ROGUE_CR_SOFT_RESET_TSP_EN 0x0000000000000400ULL +#define ROGUE_CR_SOFT_RESET_SYSARB_SHIFT 5U +#define ROGUE_CR_SOFT_RESET_SYSARB_CLRMSK 0xFFFFFFFFFFFFFFDFULL +#define ROGUE_CR_SOFT_RESET_SYSARB_EN 0x0000000000000020ULL +#define ROGUE_CR_SOFT_RESET_TPU_MCU_DEMUX_SHIFT 4U +#define ROGUE_CR_SOFT_RESET_TPU_MCU_DEMUX_CLRMSK 0xFFFFFFFFFFFFFFEFULL +#define ROGUE_CR_SOFT_RESET_TPU_MCU_DEMUX_EN 0x0000000000000010ULL +#define ROGUE_CR_SOFT_RESET_MCU_L0_SHIFT 3U +#define ROGUE_CR_SOFT_RESET_MCU_L0_CLRMSK 0xFFFFFFFFFFFFFFF7ULL +#define ROGUE_CR_SOFT_RESET_MCU_L0_EN 0x0000000000000008ULL +#define ROGUE_CR_SOFT_RESET_TPU_SHIFT 2U +#define ROGUE_CR_SOFT_RESET_TPU_CLRMSK 0xFFFFFFFFFFFFFFFBULL +#define ROGUE_CR_SOFT_RESET_TPU_EN 0x0000000000000004ULL +#define ROGUE_CR_SOFT_RESET_USC_SHIFT 0U +#define ROGUE_CR_SOFT_RESET_USC_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_SOFT_RESET_USC_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_SOFT_RESET2 */ +#define ROGUE_CR_SOFT_RESET2 0x0108U +#define ROGUE_CR_SOFT_RESET2_MASKFULL 0x00000000001FFFFFULL +#define ROGUE_CR_SOFT_RESET2_SPFILTER_SHIFT 12U +#define ROGUE_CR_SOFT_RESET2_SPFILTER_CLRMSK 0xFFE00FFFU +#define ROGUE_CR_SOFT_RESET2_TDM_SHIFT 11U +#define ROGUE_CR_SOFT_RESET2_TDM_CLRMSK 0xFFFFF7FFU +#define ROGUE_CR_SOFT_RESET2_TDM_EN 0x00000800U +#define ROGUE_CR_SOFT_RESET2_ASTC_SHIFT 10U +#define ROGUE_CR_SOFT_RESET2_ASTC_CLRMSK 0xFFFFFBFFU +#define ROGUE_CR_SOFT_RESET2_ASTC_EN 0x00000400U +#define ROGUE_CR_SOFT_RESET2_BLACKPEARL_SHIFT 9U +#define ROGUE_CR_SOFT_RESET2_BLACKPEARL_CLRMSK 0xFFFFFDFFU +#define ROGUE_CR_SOFT_RESET2_BLACKPEARL_EN 0x00000200U +#define ROGUE_CR_SOFT_RESET2_USCPS_SHIFT 8U +#define ROGUE_CR_SOFT_RESET2_USCPS_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_SOFT_RESET2_USCPS_EN 0x00000100U +#define ROGUE_CR_SOFT_RESET2_IPF_SHIFT 7U +#define ROGUE_CR_SOFT_RESET2_IPF_CLRMSK 0xFFFFFF7FU +#define ROGUE_CR_SOFT_RESET2_IPF_EN 0x00000080U +#define ROGUE_CR_SOFT_RESET2_GEOMETRY_SHIFT 6U +#define ROGUE_CR_SOFT_RESET2_GEOMETRY_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_SOFT_RESET2_GEOMETRY_EN 0x00000040U +#define ROGUE_CR_SOFT_RESET2_USC_SHARED_SHIFT 5U +#define ROGUE_CR_SOFT_RESET2_USC_SHARED_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_SOFT_RESET2_USC_SHARED_EN 0x00000020U +#define ROGUE_CR_SOFT_RESET2_PDS_SHARED_SHIFT 4U +#define ROGUE_CR_SOFT_RESET2_PDS_SHARED_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_SOFT_RESET2_PDS_SHARED_EN 0x00000010U +#define ROGUE_CR_SOFT_RESET2_BIF_BLACKPEARL_SHIFT 3U +#define ROGUE_CR_SOFT_RESET2_BIF_BLACKPEARL_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_SOFT_RESET2_BIF_BLACKPEARL_EN 0x00000008U +#define ROGUE_CR_SOFT_RESET2_PIXEL_SHIFT 2U +#define ROGUE_CR_SOFT_RESET2_PIXEL_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_SOFT_RESET2_PIXEL_EN 0x00000004U +#define ROGUE_CR_SOFT_RESET2_CDM_SHIFT 1U +#define ROGUE_CR_SOFT_RESET2_CDM_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_SOFT_RESET2_CDM_EN 0x00000002U +#define ROGUE_CR_SOFT_RESET2_VERTEX_SHIFT 0U +#define ROGUE_CR_SOFT_RESET2_VERTEX_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_SOFT_RESET2_VERTEX_EN 0x00000001U + +/* Register ROGUE_CR_EVENT_STATUS */ +#define ROGUE_CR_EVENT_STATUS 0x0130U +#define ROGUE_CR_EVENT_STATUS__ROGUEXE__MASKFULL 0x00000000E01DFFFFULL +#define ROGUE_CR_EVENT_STATUS__SIGNALS__MASKFULL 0x00000000E007FFFFULL +#define ROGUE_CR_EVENT_STATUS_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_EVENT_STATUS_TDM_FENCE_FINISHED_SHIFT 31U +#define ROGUE_CR_EVENT_STATUS_TDM_FENCE_FINISHED_CLRMSK 0x7FFFFFFFU +#define ROGUE_CR_EVENT_STATUS_TDM_FENCE_FINISHED_EN 0x80000000U +#define ROGUE_CR_EVENT_STATUS_TDM_BUFFER_STALL_SHIFT 30U +#define ROGUE_CR_EVENT_STATUS_TDM_BUFFER_STALL_CLRMSK 0xBFFFFFFFU +#define ROGUE_CR_EVENT_STATUS_TDM_BUFFER_STALL_EN 0x40000000U +#define ROGUE_CR_EVENT_STATUS_COMPUTE_SIGNAL_FAILURE_SHIFT 29U +#define ROGUE_CR_EVENT_STATUS_COMPUTE_SIGNAL_FAILURE_CLRMSK 0xDFFFFFFFU +#define ROGUE_CR_EVENT_STATUS_COMPUTE_SIGNAL_FAILURE_EN 0x20000000U +#define ROGUE_CR_EVENT_STATUS_DPX_OUT_OF_MEMORY_SHIFT 28U +#define ROGUE_CR_EVENT_STATUS_DPX_OUT_OF_MEMORY_CLRMSK 0xEFFFFFFFU +#define ROGUE_CR_EVENT_STATUS_DPX_OUT_OF_MEMORY_EN 0x10000000U +#define ROGUE_CR_EVENT_STATUS_DPX_MMU_PAGE_FAULT_SHIFT 27U +#define ROGUE_CR_EVENT_STATUS_DPX_MMU_PAGE_FAULT_CLRMSK 0xF7FFFFFFU +#define ROGUE_CR_EVENT_STATUS_DPX_MMU_PAGE_FAULT_EN 0x08000000U +#define ROGUE_CR_EVENT_STATUS_RPM_OUT_OF_MEMORY_SHIFT 26U +#define ROGUE_CR_EVENT_STATUS_RPM_OUT_OF_MEMORY_CLRMSK 0xFBFFFFFFU +#define ROGUE_CR_EVENT_STATUS_RPM_OUT_OF_MEMORY_EN 0x04000000U +#define ROGUE_CR_EVENT_STATUS_FBA_FC3_FINISHED_SHIFT 25U +#define ROGUE_CR_EVENT_STATUS_FBA_FC3_FINISHED_CLRMSK 0xFDFFFFFFU +#define ROGUE_CR_EVENT_STATUS_FBA_FC3_FINISHED_EN 0x02000000U +#define ROGUE_CR_EVENT_STATUS_FBA_FC2_FINISHED_SHIFT 24U +#define ROGUE_CR_EVENT_STATUS_FBA_FC2_FINISHED_CLRMSK 0xFEFFFFFFU +#define ROGUE_CR_EVENT_STATUS_FBA_FC2_FINISHED_EN 0x01000000U +#define ROGUE_CR_EVENT_STATUS_FBA_FC1_FINISHED_SHIFT 23U +#define ROGUE_CR_EVENT_STATUS_FBA_FC1_FINISHED_CLRMSK 0xFF7FFFFFU +#define ROGUE_CR_EVENT_STATUS_FBA_FC1_FINISHED_EN 0x00800000U +#define ROGUE_CR_EVENT_STATUS_FBA_FC0_FINISHED_SHIFT 22U +#define ROGUE_CR_EVENT_STATUS_FBA_FC0_FINISHED_CLRMSK 0xFFBFFFFFU +#define ROGUE_CR_EVENT_STATUS_FBA_FC0_FINISHED_EN 0x00400000U +#define ROGUE_CR_EVENT_STATUS_RDM_FC3_FINISHED_SHIFT 21U +#define ROGUE_CR_EVENT_STATUS_RDM_FC3_FINISHED_CLRMSK 0xFFDFFFFFU +#define ROGUE_CR_EVENT_STATUS_RDM_FC3_FINISHED_EN 0x00200000U +#define ROGUE_CR_EVENT_STATUS_RDM_FC2_FINISHED_SHIFT 20U +#define ROGUE_CR_EVENT_STATUS_RDM_FC2_FINISHED_CLRMSK 0xFFEFFFFFU +#define ROGUE_CR_EVENT_STATUS_RDM_FC2_FINISHED_EN 0x00100000U +#define ROGUE_CR_EVENT_STATUS_SAFETY_SHIFT 20U +#define ROGUE_CR_EVENT_STATUS_SAFETY_CLRMSK 0xFFEFFFFFU +#define ROGUE_CR_EVENT_STATUS_SAFETY_EN 0x00100000U +#define ROGUE_CR_EVENT_STATUS_RDM_FC1_FINISHED_SHIFT 19U +#define ROGUE_CR_EVENT_STATUS_RDM_FC1_FINISHED_CLRMSK 0xFFF7FFFFU +#define ROGUE_CR_EVENT_STATUS_RDM_FC1_FINISHED_EN 0x00080000U +#define ROGUE_CR_EVENT_STATUS_SLAVE_REQ_SHIFT 19U +#define ROGUE_CR_EVENT_STATUS_SLAVE_REQ_CLRMSK 0xFFF7FFFFU +#define ROGUE_CR_EVENT_STATUS_SLAVE_REQ_EN 0x00080000U +#define ROGUE_CR_EVENT_STATUS_RDM_FC0_FINISHED_SHIFT 18U +#define ROGUE_CR_EVENT_STATUS_RDM_FC0_FINISHED_CLRMSK 0xFFFBFFFFU +#define ROGUE_CR_EVENT_STATUS_RDM_FC0_FINISHED_EN 0x00040000U +#define ROGUE_CR_EVENT_STATUS_TDM_CONTEXT_STORE_FINISHED_SHIFT 18U +#define ROGUE_CR_EVENT_STATUS_TDM_CONTEXT_STORE_FINISHED_CLRMSK 0xFFFBFFFFU +#define ROGUE_CR_EVENT_STATUS_TDM_CONTEXT_STORE_FINISHED_EN 0x00040000U +#define ROGUE_CR_EVENT_STATUS_SHG_FINISHED_SHIFT 17U +#define ROGUE_CR_EVENT_STATUS_SHG_FINISHED_CLRMSK 0xFFFDFFFFU +#define ROGUE_CR_EVENT_STATUS_SHG_FINISHED_EN 0x00020000U +#define ROGUE_CR_EVENT_STATUS_SPFILTER_SIGNAL_UPDATE_SHIFT 17U +#define ROGUE_CR_EVENT_STATUS_SPFILTER_SIGNAL_UPDATE_CLRMSK 0xFFFDFFFFU +#define ROGUE_CR_EVENT_STATUS_SPFILTER_SIGNAL_UPDATE_EN 0x00020000U +#define ROGUE_CR_EVENT_STATUS_COMPUTE_BUFFER_STALL_SHIFT 16U +#define ROGUE_CR_EVENT_STATUS_COMPUTE_BUFFER_STALL_CLRMSK 0xFFFEFFFFU +#define ROGUE_CR_EVENT_STATUS_COMPUTE_BUFFER_STALL_EN 0x00010000U +#define ROGUE_CR_EVENT_STATUS_USC_TRIGGER_SHIFT 15U +#define ROGUE_CR_EVENT_STATUS_USC_TRIGGER_CLRMSK 0xFFFF7FFFU +#define ROGUE_CR_EVENT_STATUS_USC_TRIGGER_EN 0x00008000U +#define ROGUE_CR_EVENT_STATUS_ZLS_FINISHED_SHIFT 14U +#define ROGUE_CR_EVENT_STATUS_ZLS_FINISHED_CLRMSK 0xFFFFBFFFU +#define ROGUE_CR_EVENT_STATUS_ZLS_FINISHED_EN 0x00004000U +#define ROGUE_CR_EVENT_STATUS_GPIO_ACK_SHIFT 13U +#define ROGUE_CR_EVENT_STATUS_GPIO_ACK_CLRMSK 0xFFFFDFFFU +#define ROGUE_CR_EVENT_STATUS_GPIO_ACK_EN 0x00002000U +#define ROGUE_CR_EVENT_STATUS_GPIO_REQ_SHIFT 12U +#define ROGUE_CR_EVENT_STATUS_GPIO_REQ_CLRMSK 0xFFFFEFFFU +#define ROGUE_CR_EVENT_STATUS_GPIO_REQ_EN 0x00001000U +#define ROGUE_CR_EVENT_STATUS_POWER_ABORT_SHIFT 11U +#define ROGUE_CR_EVENT_STATUS_POWER_ABORT_CLRMSK 0xFFFFF7FFU +#define ROGUE_CR_EVENT_STATUS_POWER_ABORT_EN 0x00000800U +#define ROGUE_CR_EVENT_STATUS_POWER_COMPLETE_SHIFT 10U +#define ROGUE_CR_EVENT_STATUS_POWER_COMPLETE_CLRMSK 0xFFFFFBFFU +#define ROGUE_CR_EVENT_STATUS_POWER_COMPLETE_EN 0x00000400U +#define ROGUE_CR_EVENT_STATUS_MMU_PAGE_FAULT_SHIFT 9U +#define ROGUE_CR_EVENT_STATUS_MMU_PAGE_FAULT_CLRMSK 0xFFFFFDFFU +#define ROGUE_CR_EVENT_STATUS_MMU_PAGE_FAULT_EN 0x00000200U +#define ROGUE_CR_EVENT_STATUS_PM_3D_MEM_FREE_SHIFT 8U +#define ROGUE_CR_EVENT_STATUS_PM_3D_MEM_FREE_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_EVENT_STATUS_PM_3D_MEM_FREE_EN 0x00000100U +#define ROGUE_CR_EVENT_STATUS_PM_OUT_OF_MEMORY_SHIFT 7U +#define ROGUE_CR_EVENT_STATUS_PM_OUT_OF_MEMORY_CLRMSK 0xFFFFFF7FU +#define ROGUE_CR_EVENT_STATUS_PM_OUT_OF_MEMORY_EN 0x00000080U +#define ROGUE_CR_EVENT_STATUS_TA_TERMINATE_SHIFT 6U +#define ROGUE_CR_EVENT_STATUS_TA_TERMINATE_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_EVENT_STATUS_TA_TERMINATE_EN 0x00000040U +#define ROGUE_CR_EVENT_STATUS_TA_FINISHED_SHIFT 5U +#define ROGUE_CR_EVENT_STATUS_TA_FINISHED_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_EVENT_STATUS_TA_FINISHED_EN 0x00000020U +#define ROGUE_CR_EVENT_STATUS_ISP_END_MACROTILE_SHIFT 4U +#define ROGUE_CR_EVENT_STATUS_ISP_END_MACROTILE_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_EVENT_STATUS_ISP_END_MACROTILE_EN 0x00000010U +#define ROGUE_CR_EVENT_STATUS_PIXELBE_END_RENDER_SHIFT 3U +#define ROGUE_CR_EVENT_STATUS_PIXELBE_END_RENDER_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_EVENT_STATUS_PIXELBE_END_RENDER_EN 0x00000008U +#define ROGUE_CR_EVENT_STATUS_COMPUTE_FINISHED_SHIFT 2U +#define ROGUE_CR_EVENT_STATUS_COMPUTE_FINISHED_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_EVENT_STATUS_COMPUTE_FINISHED_EN 0x00000004U +#define ROGUE_CR_EVENT_STATUS_KERNEL_FINISHED_SHIFT 1U +#define ROGUE_CR_EVENT_STATUS_KERNEL_FINISHED_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_EVENT_STATUS_KERNEL_FINISHED_EN 0x00000002U +#define ROGUE_CR_EVENT_STATUS_TLA_COMPLETE_SHIFT 0U +#define ROGUE_CR_EVENT_STATUS_TLA_COMPLETE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_EVENT_STATUS_TLA_COMPLETE_EN 0x00000001U + +/* Register ROGUE_CR_TIMER */ +#define ROGUE_CR_TIMER 0x0160U +#define ROGUE_CR_TIMER_MASKFULL 0x8000FFFFFFFFFFFFULL +#define ROGUE_CR_TIMER_BIT31_SHIFT 63U +#define ROGUE_CR_TIMER_BIT31_CLRMSK 0x7FFFFFFFFFFFFFFFULL +#define ROGUE_CR_TIMER_BIT31_EN 0x8000000000000000ULL +#define ROGUE_CR_TIMER_VALUE_SHIFT 0U +#define ROGUE_CR_TIMER_VALUE_CLRMSK 0xFFFF000000000000ULL + +/* Register ROGUE_CR_TLA_STATUS */ +#define ROGUE_CR_TLA_STATUS 0x0178U +#define ROGUE_CR_TLA_STATUS_MASKFULL 0xFFFFFFFFFFFFFFFFULL +#define ROGUE_CR_TLA_STATUS_BLIT_COUNT_SHIFT 39U +#define ROGUE_CR_TLA_STATUS_BLIT_COUNT_CLRMSK 0x0000007FFFFFFFFFULL +#define ROGUE_CR_TLA_STATUS_REQUEST_SHIFT 7U +#define ROGUE_CR_TLA_STATUS_REQUEST_CLRMSK 0xFFFFFF800000007FULL +#define ROGUE_CR_TLA_STATUS_FIFO_FULLNESS_SHIFT 1U +#define ROGUE_CR_TLA_STATUS_FIFO_FULLNESS_CLRMSK 0xFFFFFFFFFFFFFF81ULL +#define ROGUE_CR_TLA_STATUS_BUSY_SHIFT 0U +#define ROGUE_CR_TLA_STATUS_BUSY_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_TLA_STATUS_BUSY_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_PM_PARTIAL_RENDER_ENABLE */ +#define ROGUE_CR_PM_PARTIAL_RENDER_ENABLE 0x0338U +#define ROGUE_CR_PM_PARTIAL_RENDER_ENABLE_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_PM_PARTIAL_RENDER_ENABLE_OP_SHIFT 0U +#define ROGUE_CR_PM_PARTIAL_RENDER_ENABLE_OP_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_PM_PARTIAL_RENDER_ENABLE_OP_EN 0x00000001U + +/* Register ROGUE_CR_SIDEKICK_IDLE */ +#define ROGUE_CR_SIDEKICK_IDLE 0x03C8U +#define ROGUE_CR_SIDEKICK_IDLE_MASKFULL 0x000000000000007FULL +#define ROGUE_CR_SIDEKICK_IDLE_FB_CDC_SHIFT 6U +#define ROGUE_CR_SIDEKICK_IDLE_FB_CDC_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_SIDEKICK_IDLE_FB_CDC_EN 0x00000040U +#define ROGUE_CR_SIDEKICK_IDLE_MMU_SHIFT 5U +#define ROGUE_CR_SIDEKICK_IDLE_MMU_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_SIDEKICK_IDLE_MMU_EN 0x00000020U +#define ROGUE_CR_SIDEKICK_IDLE_BIF128_SHIFT 4U +#define ROGUE_CR_SIDEKICK_IDLE_BIF128_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_SIDEKICK_IDLE_BIF128_EN 0x00000010U +#define ROGUE_CR_SIDEKICK_IDLE_TLA_SHIFT 3U +#define ROGUE_CR_SIDEKICK_IDLE_TLA_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_SIDEKICK_IDLE_TLA_EN 0x00000008U +#define ROGUE_CR_SIDEKICK_IDLE_GARTEN_SHIFT 2U +#define ROGUE_CR_SIDEKICK_IDLE_GARTEN_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_SIDEKICK_IDLE_GARTEN_EN 0x00000004U +#define ROGUE_CR_SIDEKICK_IDLE_HOSTIF_SHIFT 1U +#define ROGUE_CR_SIDEKICK_IDLE_HOSTIF_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_SIDEKICK_IDLE_HOSTIF_EN 0x00000002U +#define ROGUE_CR_SIDEKICK_IDLE_SOCIF_SHIFT 0U +#define ROGUE_CR_SIDEKICK_IDLE_SOCIF_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_SIDEKICK_IDLE_SOCIF_EN 0x00000001U + +/* Register ROGUE_CR_MARS_IDLE */ +#define ROGUE_CR_MARS_IDLE 0x08F8U +#define ROGUE_CR_MARS_IDLE_MASKFULL 0x0000000000000007ULL +#define ROGUE_CR_MARS_IDLE_MH_SYSARB0_SHIFT 2U +#define ROGUE_CR_MARS_IDLE_MH_SYSARB0_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_MARS_IDLE_MH_SYSARB0_EN 0x00000004U +#define ROGUE_CR_MARS_IDLE_CPU_SHIFT 1U +#define ROGUE_CR_MARS_IDLE_CPU_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_MARS_IDLE_CPU_EN 0x00000002U +#define ROGUE_CR_MARS_IDLE_SOCIF_SHIFT 0U +#define ROGUE_CR_MARS_IDLE_SOCIF_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_MARS_IDLE_SOCIF_EN 0x00000001U + +/* Register ROGUE_CR_VDM_CONTEXT_STORE_STATUS */ +#define ROGUE_CR_VDM_CONTEXT_STORE_STATUS 0x0430U +#define ROGUE_CR_VDM_CONTEXT_STORE_STATUS_MASKFULL 0x00000000000000F3ULL +#define ROGUE_CR_VDM_CONTEXT_STORE_STATUS_LAST_PIPE_SHIFT 4U +#define ROGUE_CR_VDM_CONTEXT_STORE_STATUS_LAST_PIPE_CLRMSK 0xFFFFFF0FU +#define ROGUE_CR_VDM_CONTEXT_STORE_STATUS_NEED_RESUME_SHIFT 1U +#define ROGUE_CR_VDM_CONTEXT_STORE_STATUS_NEED_RESUME_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_VDM_CONTEXT_STORE_STATUS_NEED_RESUME_EN 0x00000002U +#define ROGUE_CR_VDM_CONTEXT_STORE_STATUS_COMPLETE_SHIFT 0U +#define ROGUE_CR_VDM_CONTEXT_STORE_STATUS_COMPLETE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_VDM_CONTEXT_STORE_STATUS_COMPLETE_EN 0x00000001U + +/* Register ROGUE_CR_VDM_CONTEXT_STORE_TASK0 */ +#define ROGUE_CR_VDM_CONTEXT_STORE_TASK0 0x0438U +#define ROGUE_CR_VDM_CONTEXT_STORE_TASK0_MASKFULL 0xFFFFFFFFFFFFFFFFULL +#define ROGUE_CR_VDM_CONTEXT_STORE_TASK0_PDS_STATE1_SHIFT 32U +#define ROGUE_CR_VDM_CONTEXT_STORE_TASK0_PDS_STATE1_CLRMSK 0x00000000FFFFFFFFULL +#define ROGUE_CR_VDM_CONTEXT_STORE_TASK0_PDS_STATE0_SHIFT 0U +#define ROGUE_CR_VDM_CONTEXT_STORE_TASK0_PDS_STATE0_CLRMSK 0xFFFFFFFF00000000ULL + +/* Register ROGUE_CR_VDM_CONTEXT_STORE_TASK1 */ +#define ROGUE_CR_VDM_CONTEXT_STORE_TASK1 0x0440U +#define ROGUE_CR_VDM_CONTEXT_STORE_TASK1_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_VDM_CONTEXT_STORE_TASK1_PDS_STATE2_SHIFT 0U +#define ROGUE_CR_VDM_CONTEXT_STORE_TASK1_PDS_STATE2_CLRMSK 0x00000000U + +/* Register ROGUE_CR_VDM_CONTEXT_STORE_TASK2 */ +#define ROGUE_CR_VDM_CONTEXT_STORE_TASK2 0x0448U +#define ROGUE_CR_VDM_CONTEXT_STORE_TASK2_MASKFULL 0xFFFFFFFFFFFFFFFFULL +#define ROGUE_CR_VDM_CONTEXT_STORE_TASK2_STREAM_OUT2_SHIFT 32U +#define ROGUE_CR_VDM_CONTEXT_STORE_TASK2_STREAM_OUT2_CLRMSK 0x00000000FFFFFFFFULL +#define ROGUE_CR_VDM_CONTEXT_STORE_TASK2_STREAM_OUT1_SHIFT 0U +#define ROGUE_CR_VDM_CONTEXT_STORE_TASK2_STREAM_OUT1_CLRMSK 0xFFFFFFFF00000000ULL + +/* Register ROGUE_CR_VDM_CONTEXT_RESUME_TASK0 */ +#define ROGUE_CR_VDM_CONTEXT_RESUME_TASK0 0x0450U +#define ROGUE_CR_VDM_CONTEXT_RESUME_TASK0_MASKFULL 0xFFFFFFFFFFFFFFFFULL +#define ROGUE_CR_VDM_CONTEXT_RESUME_TASK0_PDS_STATE1_SHIFT 32U +#define ROGUE_CR_VDM_CONTEXT_RESUME_TASK0_PDS_STATE1_CLRMSK 0x00000000FFFFFFFFULL +#define ROGUE_CR_VDM_CONTEXT_RESUME_TASK0_PDS_STATE0_SHIFT 0U +#define ROGUE_CR_VDM_CONTEXT_RESUME_TASK0_PDS_STATE0_CLRMSK 0xFFFFFFFF00000000ULL + +/* Register ROGUE_CR_VDM_CONTEXT_RESUME_TASK1 */ +#define ROGUE_CR_VDM_CONTEXT_RESUME_TASK1 0x0458U +#define ROGUE_CR_VDM_CONTEXT_RESUME_TASK1_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_VDM_CONTEXT_RESUME_TASK1_PDS_STATE2_SHIFT 0U +#define ROGUE_CR_VDM_CONTEXT_RESUME_TASK1_PDS_STATE2_CLRMSK 0x00000000U + +/* Register ROGUE_CR_VDM_CONTEXT_RESUME_TASK2 */ +#define ROGUE_CR_VDM_CONTEXT_RESUME_TASK2 0x0460U +#define ROGUE_CR_VDM_CONTEXT_RESUME_TASK2_MASKFULL 0xFFFFFFFFFFFFFFFFULL +#define ROGUE_CR_VDM_CONTEXT_RESUME_TASK2_STREAM_OUT2_SHIFT 32U +#define ROGUE_CR_VDM_CONTEXT_RESUME_TASK2_STREAM_OUT2_CLRMSK 0x00000000FFFFFFFFULL +#define ROGUE_CR_VDM_CONTEXT_RESUME_TASK2_STREAM_OUT1_SHIFT 0U +#define ROGUE_CR_VDM_CONTEXT_RESUME_TASK2_STREAM_OUT1_CLRMSK 0xFFFFFFFF00000000ULL + +/* Register ROGUE_CR_CDM_CONTEXT_STORE_STATUS */ +#define ROGUE_CR_CDM_CONTEXT_STORE_STATUS 0x04A0U +#define ROGUE_CR_CDM_CONTEXT_STORE_STATUS_MASKFULL 0x0000000000000003ULL +#define ROGUE_CR_CDM_CONTEXT_STORE_STATUS_NEED_RESUME_SHIFT 1U +#define ROGUE_CR_CDM_CONTEXT_STORE_STATUS_NEED_RESUME_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_CDM_CONTEXT_STORE_STATUS_NEED_RESUME_EN 0x00000002U +#define ROGUE_CR_CDM_CONTEXT_STORE_STATUS_COMPLETE_SHIFT 0U +#define ROGUE_CR_CDM_CONTEXT_STORE_STATUS_COMPLETE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_CDM_CONTEXT_STORE_STATUS_COMPLETE_EN 0x00000001U + +/* Register ROGUE_CR_CDM_CONTEXT_PDS0 */ +#define ROGUE_CR_CDM_CONTEXT_PDS0 0x04A8U +#define ROGUE_CR_CDM_CONTEXT_PDS0_MASKFULL 0xFFFFFFF0FFFFFFF0ULL +#define ROGUE_CR_CDM_CONTEXT_PDS0_DATA_ADDR_SHIFT 36U +#define ROGUE_CR_CDM_CONTEXT_PDS0_DATA_ADDR_CLRMSK 0x0000000FFFFFFFFFULL +#define ROGUE_CR_CDM_CONTEXT_PDS0_DATA_ADDR_ALIGNSHIFT 4U +#define ROGUE_CR_CDM_CONTEXT_PDS0_DATA_ADDR_ALIGNSIZE 16U +#define ROGUE_CR_CDM_CONTEXT_PDS0_CODE_ADDR_SHIFT 4U +#define ROGUE_CR_CDM_CONTEXT_PDS0_CODE_ADDR_CLRMSK 0xFFFFFFFF0000000FULL +#define ROGUE_CR_CDM_CONTEXT_PDS0_CODE_ADDR_ALIGNSHIFT 4U +#define ROGUE_CR_CDM_CONTEXT_PDS0_CODE_ADDR_ALIGNSIZE 16U + +/* Register ROGUE_CR_CDM_CONTEXT_PDS1 */ +#define ROGUE_CR_CDM_CONTEXT_PDS1 0x04B0U +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__MASKFULL 0x000000007FFFFFFFULL +#define ROGUE_CR_CDM_CONTEXT_PDS1_MASKFULL 0x000000003FFFFFFFULL +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__PDS_SEQ_DEP_SHIFT 30U +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__PDS_SEQ_DEP_CLRMSK 0xBFFFFFFFU +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__PDS_SEQ_DEP_EN 0x40000000U +#define ROGUE_CR_CDM_CONTEXT_PDS1_PDS_SEQ_DEP_SHIFT 29U +#define ROGUE_CR_CDM_CONTEXT_PDS1_PDS_SEQ_DEP_CLRMSK 0xDFFFFFFFU +#define ROGUE_CR_CDM_CONTEXT_PDS1_PDS_SEQ_DEP_EN 0x20000000U +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__USC_SEQ_DEP_SHIFT 29U +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__USC_SEQ_DEP_CLRMSK 0xDFFFFFFFU +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__USC_SEQ_DEP_EN 0x20000000U +#define ROGUE_CR_CDM_CONTEXT_PDS1_USC_SEQ_DEP_SHIFT 28U +#define ROGUE_CR_CDM_CONTEXT_PDS1_USC_SEQ_DEP_CLRMSK 0xEFFFFFFFU +#define ROGUE_CR_CDM_CONTEXT_PDS1_USC_SEQ_DEP_EN 0x10000000U +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__TARGET_SHIFT 28U +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__TARGET_CLRMSK 0xEFFFFFFFU +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__TARGET_EN 0x10000000U +#define ROGUE_CR_CDM_CONTEXT_PDS1_TARGET_SHIFT 27U +#define ROGUE_CR_CDM_CONTEXT_PDS1_TARGET_CLRMSK 0xF7FFFFFFU +#define ROGUE_CR_CDM_CONTEXT_PDS1_TARGET_EN 0x08000000U +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__UNIFIED_SIZE_SHIFT 22U +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__UNIFIED_SIZE_CLRMSK 0xF03FFFFFU +#define ROGUE_CR_CDM_CONTEXT_PDS1_UNIFIED_SIZE_SHIFT 21U +#define ROGUE_CR_CDM_CONTEXT_PDS1_UNIFIED_SIZE_CLRMSK 0xF81FFFFFU +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__COMMON_SHARED_SHIFT 21U +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__COMMON_SHARED_CLRMSK 0xFFDFFFFFU +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__COMMON_SHARED_EN 0x00200000U +#define ROGUE_CR_CDM_CONTEXT_PDS1_COMMON_SHARED_SHIFT 20U +#define ROGUE_CR_CDM_CONTEXT_PDS1_COMMON_SHARED_CLRMSK 0xFFEFFFFFU +#define ROGUE_CR_CDM_CONTEXT_PDS1_COMMON_SHARED_EN 0x00100000U +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__COMMON_SIZE_SHIFT 12U +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__COMMON_SIZE_CLRMSK 0xFFE00FFFU +#define ROGUE_CR_CDM_CONTEXT_PDS1_COMMON_SIZE_SHIFT 11U +#define ROGUE_CR_CDM_CONTEXT_PDS1_COMMON_SIZE_CLRMSK 0xFFF007FFU +#define ROGUE_CR_CDM_CONTEXT_PDS1_TEMP_SIZE_SHIFT 7U +#define ROGUE_CR_CDM_CONTEXT_PDS1_TEMP_SIZE_CLRMSK 0xFFFFF87FU +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__TEMP_SIZE_SHIFT 7U +#define ROGUE_CR_CDM_CONTEXT_PDS1__TEMPSIZE8__TEMP_SIZE_CLRMSK 0xFFFFF07FU +#define ROGUE_CR_CDM_CONTEXT_PDS1_DATA_SIZE_SHIFT 1U +#define ROGUE_CR_CDM_CONTEXT_PDS1_DATA_SIZE_CLRMSK 0xFFFFFF81U +#define ROGUE_CR_CDM_CONTEXT_PDS1_FENCE_SHIFT 0U +#define ROGUE_CR_CDM_CONTEXT_PDS1_FENCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_CDM_CONTEXT_PDS1_FENCE_EN 0x00000001U + +/* Register ROGUE_CR_CDM_TERMINATE_PDS */ +#define ROGUE_CR_CDM_TERMINATE_PDS 0x04B8U +#define ROGUE_CR_CDM_TERMINATE_PDS_MASKFULL 0xFFFFFFF0FFFFFFF0ULL +#define ROGUE_CR_CDM_TERMINATE_PDS_DATA_ADDR_SHIFT 36U +#define ROGUE_CR_CDM_TERMINATE_PDS_DATA_ADDR_CLRMSK 0x0000000FFFFFFFFFULL +#define ROGUE_CR_CDM_TERMINATE_PDS_DATA_ADDR_ALIGNSHIFT 4U +#define ROGUE_CR_CDM_TERMINATE_PDS_DATA_ADDR_ALIGNSIZE 16U +#define ROGUE_CR_CDM_TERMINATE_PDS_CODE_ADDR_SHIFT 4U +#define ROGUE_CR_CDM_TERMINATE_PDS_CODE_ADDR_CLRMSK 0xFFFFFFFF0000000FULL +#define ROGUE_CR_CDM_TERMINATE_PDS_CODE_ADDR_ALIGNSHIFT 4U +#define ROGUE_CR_CDM_TERMINATE_PDS_CODE_ADDR_ALIGNSIZE 16U + +/* Register ROGUE_CR_CDM_TERMINATE_PDS1 */ +#define ROGUE_CR_CDM_TERMINATE_PDS1 0x04C0U +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__MASKFULL 0x000000007FFFFFFFULL +#define ROGUE_CR_CDM_TERMINATE_PDS1_MASKFULL 0x000000003FFFFFFFULL +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__PDS_SEQ_DEP_SHIFT 30U +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__PDS_SEQ_DEP_CLRMSK 0xBFFFFFFFU +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__PDS_SEQ_DEP_EN 0x40000000U +#define ROGUE_CR_CDM_TERMINATE_PDS1_PDS_SEQ_DEP_SHIFT 29U +#define ROGUE_CR_CDM_TERMINATE_PDS1_PDS_SEQ_DEP_CLRMSK 0xDFFFFFFFU +#define ROGUE_CR_CDM_TERMINATE_PDS1_PDS_SEQ_DEP_EN 0x20000000U +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__USC_SEQ_DEP_SHIFT 29U +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__USC_SEQ_DEP_CLRMSK 0xDFFFFFFFU +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__USC_SEQ_DEP_EN 0x20000000U +#define ROGUE_CR_CDM_TERMINATE_PDS1_USC_SEQ_DEP_SHIFT 28U +#define ROGUE_CR_CDM_TERMINATE_PDS1_USC_SEQ_DEP_CLRMSK 0xEFFFFFFFU +#define ROGUE_CR_CDM_TERMINATE_PDS1_USC_SEQ_DEP_EN 0x10000000U +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__TARGET_SHIFT 28U +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__TARGET_CLRMSK 0xEFFFFFFFU +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__TARGET_EN 0x10000000U +#define ROGUE_CR_CDM_TERMINATE_PDS1_TARGET_SHIFT 27U +#define ROGUE_CR_CDM_TERMINATE_PDS1_TARGET_CLRMSK 0xF7FFFFFFU +#define ROGUE_CR_CDM_TERMINATE_PDS1_TARGET_EN 0x08000000U +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__UNIFIED_SIZE_SHIFT 22U +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__UNIFIED_SIZE_CLRMSK 0xF03FFFFFU +#define ROGUE_CR_CDM_TERMINATE_PDS1_UNIFIED_SIZE_SHIFT 21U +#define ROGUE_CR_CDM_TERMINATE_PDS1_UNIFIED_SIZE_CLRMSK 0xF81FFFFFU +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__COMMON_SHARED_SHIFT 21U +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__COMMON_SHARED_CLRMSK 0xFFDFFFFFU +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__COMMON_SHARED_EN 0x00200000U +#define ROGUE_CR_CDM_TERMINATE_PDS1_COMMON_SHARED_SHIFT 20U +#define ROGUE_CR_CDM_TERMINATE_PDS1_COMMON_SHARED_CLRMSK 0xFFEFFFFFU +#define ROGUE_CR_CDM_TERMINATE_PDS1_COMMON_SHARED_EN 0x00100000U +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__COMMON_SIZE_SHIFT 12U +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__COMMON_SIZE_CLRMSK 0xFFE00FFFU +#define ROGUE_CR_CDM_TERMINATE_PDS1_COMMON_SIZE_SHIFT 11U +#define ROGUE_CR_CDM_TERMINATE_PDS1_COMMON_SIZE_CLRMSK 0xFFF007FFU +#define ROGUE_CR_CDM_TERMINATE_PDS1_TEMP_SIZE_SHIFT 7U +#define ROGUE_CR_CDM_TERMINATE_PDS1_TEMP_SIZE_CLRMSK 0xFFFFF87FU +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__TEMP_SIZE_SHIFT 7U +#define ROGUE_CR_CDM_TERMINATE_PDS1__TEMPSIZE8__TEMP_SIZE_CLRMSK 0xFFFFF07FU +#define ROGUE_CR_CDM_TERMINATE_PDS1_DATA_SIZE_SHIFT 1U +#define ROGUE_CR_CDM_TERMINATE_PDS1_DATA_SIZE_CLRMSK 0xFFFFFF81U +#define ROGUE_CR_CDM_TERMINATE_PDS1_FENCE_SHIFT 0U +#define ROGUE_CR_CDM_TERMINATE_PDS1_FENCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_CDM_TERMINATE_PDS1_FENCE_EN 0x00000001U + +/* Register ROGUE_CR_CDM_CONTEXT_LOAD_PDS0 */ +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS0 0x04D8U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS0_MASKFULL 0xFFFFFFF0FFFFFFF0ULL +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS0_DATA_ADDR_SHIFT 36U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS0_DATA_ADDR_CLRMSK 0x0000000FFFFFFFFFULL +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS0_DATA_ADDR_ALIGNSHIFT 4U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS0_DATA_ADDR_ALIGNSIZE 16U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS0_CODE_ADDR_SHIFT 4U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS0_CODE_ADDR_CLRMSK 0xFFFFFFFF0000000FULL +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS0_CODE_ADDR_ALIGNSHIFT 4U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS0_CODE_ADDR_ALIGNSIZE 16U + +/* Register ROGUE_CR_CDM_CONTEXT_LOAD_PDS1 */ +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1 0x04E0U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__MASKFULL 0x000000007FFFFFFFULL +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_MASKFULL 0x000000003FFFFFFFULL +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__PDS_SEQ_DEP_SHIFT 30U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__PDS_SEQ_DEP_CLRMSK 0xBFFFFFFFU +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__PDS_SEQ_DEP_EN 0x40000000U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_PDS_SEQ_DEP_SHIFT 29U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_PDS_SEQ_DEP_CLRMSK 0xDFFFFFFFU +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_PDS_SEQ_DEP_EN 0x20000000U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__USC_SEQ_DEP_SHIFT 29U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__USC_SEQ_DEP_CLRMSK 0xDFFFFFFFU +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__USC_SEQ_DEP_EN 0x20000000U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_USC_SEQ_DEP_SHIFT 28U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_USC_SEQ_DEP_CLRMSK 0xEFFFFFFFU +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_USC_SEQ_DEP_EN 0x10000000U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__TARGET_SHIFT 28U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__TARGET_CLRMSK 0xEFFFFFFFU +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__TARGET_EN 0x10000000U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_TARGET_SHIFT 27U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_TARGET_CLRMSK 0xF7FFFFFFU +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_TARGET_EN 0x08000000U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__UNIFIED_SIZE_SHIFT 22U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__UNIFIED_SIZE_CLRMSK 0xF03FFFFFU +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_UNIFIED_SIZE_SHIFT 21U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_UNIFIED_SIZE_CLRMSK 0xF81FFFFFU +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__COMMON_SHARED_SHIFT 21U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__COMMON_SHARED_CLRMSK 0xFFDFFFFFU +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__COMMON_SHARED_EN 0x00200000U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_COMMON_SHARED_SHIFT 20U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_COMMON_SHARED_CLRMSK 0xFFEFFFFFU +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_COMMON_SHARED_EN 0x00100000U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__COMMON_SIZE_SHIFT 12U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__COMMON_SIZE_CLRMSK 0xFFE00FFFU +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_COMMON_SIZE_SHIFT 11U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_COMMON_SIZE_CLRMSK 0xFFF007FFU +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_TEMP_SIZE_SHIFT 7U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_TEMP_SIZE_CLRMSK 0xFFFFF87FU +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__TEMP_SIZE_SHIFT 7U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1__TEMPSIZE8__TEMP_SIZE_CLRMSK 0xFFFFF07FU +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_DATA_SIZE_SHIFT 1U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_DATA_SIZE_CLRMSK 0xFFFFFF81U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_FENCE_SHIFT 0U +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_FENCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_CDM_CONTEXT_LOAD_PDS1_FENCE_EN 0x00000001U + +/* Register ROGUE_CR_MIPS_WRAPPER_CONFIG */ +#define ROGUE_CR_MIPS_WRAPPER_CONFIG 0x0810U +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_MASKFULL 0x000001030F01FFFFULL +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_FW_IDLE_ENABLE_SHIFT 40U +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_FW_IDLE_ENABLE_CLRMSK 0xFFFFFEFFFFFFFFFFULL +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_FW_IDLE_ENABLE_EN 0x0000010000000000ULL +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_DISABLE_BOOT_SHIFT 33U +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_DISABLE_BOOT_CLRMSK 0xFFFFFFFDFFFFFFFFULL +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_DISABLE_BOOT_EN 0x0000000200000000ULL +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_L2_CACHE_OFF_SHIFT 32U +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_L2_CACHE_OFF_CLRMSK 0xFFFFFFFEFFFFFFFFULL +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_L2_CACHE_OFF_EN 0x0000000100000000ULL +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_OS_ID_SHIFT 25U +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_OS_ID_CLRMSK 0xFFFFFFFFF1FFFFFFULL +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_TRUSTED_SHIFT 24U +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_TRUSTED_CLRMSK 0xFFFFFFFFFEFFFFFFULL +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_TRUSTED_EN 0x0000000001000000ULL +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_BOOT_ISA_MODE_SHIFT 16U +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_BOOT_ISA_MODE_CLRMSK 0xFFFFFFFFFFFEFFFFULL +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_BOOT_ISA_MODE_MIPS32 0x0000000000000000ULL +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_BOOT_ISA_MODE_MICROMIPS 0x0000000000010000ULL +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_REGBANK_BASE_ADDR_SHIFT 0U +#define ROGUE_CR_MIPS_WRAPPER_CONFIG_REGBANK_BASE_ADDR_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG1 */ +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG1 0x0818U +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG1_MASKFULL 0x00000000FFFFF001ULL +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG1_BASE_ADDR_IN_SHIFT 12U +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG1_BASE_ADDR_IN_CLRMSK 0xFFFFFFFF00000FFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG1_MODE_ENABLE_SHIFT 0U +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG1_MODE_ENABLE_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG1_MODE_ENABLE_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG2 */ +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG2 0x0820U +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG2_MASKFULL 0x000000FFFFFFF1FFULL +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG2_ADDR_OUT_SHIFT 12U +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG2_ADDR_OUT_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG2_OS_ID_SHIFT 6U +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG2_OS_ID_CLRMSK 0xFFFFFFFFFFFFFE3FULL +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG2_TRUSTED_SHIFT 5U +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG2_TRUSTED_CLRMSK 0xFFFFFFFFFFFFFFDFULL +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG2_TRUSTED_EN 0x0000000000000020ULL +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG2_REGION_SIZE_POW2_SHIFT 0U +#define ROGUE_CR_MIPS_ADDR_REMAP1_CONFIG2_REGION_SIZE_POW2_CLRMSK 0xFFFFFFFFFFFFFFE0ULL + +/* Register ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG1 */ +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG1 0x0828U +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG1_MASKFULL 0x00000000FFFFF001ULL +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG1_BASE_ADDR_IN_SHIFT 12U +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG1_BASE_ADDR_IN_CLRMSK 0xFFFFFFFF00000FFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG1_MODE_ENABLE_SHIFT 0U +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG1_MODE_ENABLE_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG1_MODE_ENABLE_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG2 */ +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG2 0x0830U +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG2_MASKFULL 0x000000FFFFFFF1FFULL +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG2_ADDR_OUT_SHIFT 12U +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG2_ADDR_OUT_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG2_OS_ID_SHIFT 6U +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG2_OS_ID_CLRMSK 0xFFFFFFFFFFFFFE3FULL +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG2_TRUSTED_SHIFT 5U +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG2_TRUSTED_CLRMSK 0xFFFFFFFFFFFFFFDFULL +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG2_TRUSTED_EN 0x0000000000000020ULL +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG2_REGION_SIZE_POW2_SHIFT 0U +#define ROGUE_CR_MIPS_ADDR_REMAP2_CONFIG2_REGION_SIZE_POW2_CLRMSK 0xFFFFFFFFFFFFFFE0ULL + +/* Register ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG1 */ +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG1 0x0838U +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG1_MASKFULL 0x00000000FFFFF001ULL +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG1_BASE_ADDR_IN_SHIFT 12U +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG1_BASE_ADDR_IN_CLRMSK 0xFFFFFFFF00000FFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG1_MODE_ENABLE_SHIFT 0U +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG1_MODE_ENABLE_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG1_MODE_ENABLE_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG2 */ +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG2 0x0840U +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG2_MASKFULL 0x000000FFFFFFF1FFULL +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG2_ADDR_OUT_SHIFT 12U +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG2_ADDR_OUT_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG2_OS_ID_SHIFT 6U +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG2_OS_ID_CLRMSK 0xFFFFFFFFFFFFFE3FULL +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG2_TRUSTED_SHIFT 5U +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG2_TRUSTED_CLRMSK 0xFFFFFFFFFFFFFFDFULL +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG2_TRUSTED_EN 0x0000000000000020ULL +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG2_REGION_SIZE_POW2_SHIFT 0U +#define ROGUE_CR_MIPS_ADDR_REMAP3_CONFIG2_REGION_SIZE_POW2_CLRMSK 0xFFFFFFFFFFFFFFE0ULL + +/* Register ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG1 */ +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG1 0x0848U +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG1_MASKFULL 0x00000000FFFFF001ULL +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG1_BASE_ADDR_IN_SHIFT 12U +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG1_BASE_ADDR_IN_CLRMSK 0xFFFFFFFF00000FFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG1_MODE_ENABLE_SHIFT 0U +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG1_MODE_ENABLE_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG1_MODE_ENABLE_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG2 */ +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG2 0x0850U +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG2_MASKFULL 0x000000FFFFFFF1FFULL +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG2_ADDR_OUT_SHIFT 12U +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG2_ADDR_OUT_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG2_OS_ID_SHIFT 6U +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG2_OS_ID_CLRMSK 0xFFFFFFFFFFFFFE3FULL +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG2_TRUSTED_SHIFT 5U +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG2_TRUSTED_CLRMSK 0xFFFFFFFFFFFFFFDFULL +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG2_TRUSTED_EN 0x0000000000000020ULL +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG2_REGION_SIZE_POW2_SHIFT 0U +#define ROGUE_CR_MIPS_ADDR_REMAP4_CONFIG2_REGION_SIZE_POW2_CLRMSK 0xFFFFFFFFFFFFFFE0ULL + +/* Register ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG1 */ +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG1 0x0858U +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG1_MASKFULL 0x00000000FFFFF001ULL +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG1_BASE_ADDR_IN_SHIFT 12U +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG1_BASE_ADDR_IN_CLRMSK 0xFFFFFFFF00000FFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG1_MODE_ENABLE_SHIFT 0U +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG1_MODE_ENABLE_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG1_MODE_ENABLE_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG2 */ +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG2 0x0860U +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG2_MASKFULL 0x000000FFFFFFF1FFULL +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG2_ADDR_OUT_SHIFT 12U +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG2_ADDR_OUT_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG2_OS_ID_SHIFT 6U +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG2_OS_ID_CLRMSK 0xFFFFFFFFFFFFFE3FULL +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG2_TRUSTED_SHIFT 5U +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG2_TRUSTED_CLRMSK 0xFFFFFFFFFFFFFFDFULL +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG2_TRUSTED_EN 0x0000000000000020ULL +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG2_REGION_SIZE_POW2_SHIFT 0U +#define ROGUE_CR_MIPS_ADDR_REMAP5_CONFIG2_REGION_SIZE_POW2_CLRMSK 0xFFFFFFFFFFFFFFE0ULL + +/* Register ROGUE_CR_MIPS_ADDR_REMAP_UNMAPPED_STATUS */ +#define ROGUE_CR_MIPS_ADDR_REMAP_UNMAPPED_STATUS 0x0868U +#define ROGUE_CR_MIPS_ADDR_REMAP_UNMAPPED_STATUS_MASKFULL 0x00000001FFFFFFFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP_UNMAPPED_STATUS_EVENT_SHIFT 32U +#define ROGUE_CR_MIPS_ADDR_REMAP_UNMAPPED_STATUS_EVENT_CLRMSK 0xFFFFFFFEFFFFFFFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP_UNMAPPED_STATUS_EVENT_EN 0x0000000100000000ULL +#define ROGUE_CR_MIPS_ADDR_REMAP_UNMAPPED_STATUS_ADDRESS_SHIFT 0U +#define ROGUE_CR_MIPS_ADDR_REMAP_UNMAPPED_STATUS_ADDRESS_CLRMSK 0xFFFFFFFF00000000ULL + +/* Register ROGUE_CR_MIPS_ADDR_REMAP_UNMAPPED_CLEAR */ +#define ROGUE_CR_MIPS_ADDR_REMAP_UNMAPPED_CLEAR 0x0870U +#define ROGUE_CR_MIPS_ADDR_REMAP_UNMAPPED_CLEAR_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_MIPS_ADDR_REMAP_UNMAPPED_CLEAR_EVENT_SHIFT 0U +#define ROGUE_CR_MIPS_ADDR_REMAP_UNMAPPED_CLEAR_EVENT_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_MIPS_ADDR_REMAP_UNMAPPED_CLEAR_EVENT_EN 0x00000001U + +/* Register ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG */ +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG 0x0878U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_MASKFULL 0xFFFFFFF7FFFFFFBFULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_ADDR_OUT_SHIFT 36U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_ADDR_OUT_CLRMSK 0x0000000FFFFFFFFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_OS_ID_SHIFT 32U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_OS_ID_CLRMSK 0xFFFFFFF8FFFFFFFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_BASE_ADDR_IN_SHIFT 12U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_BASE_ADDR_IN_CLRMSK 0xFFFFFFFF00000FFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_TRUSTED_SHIFT 11U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_TRUSTED_CLRMSK 0xFFFFFFFFFFFFF7FFULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_TRUSTED_EN 0x0000000000000800ULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_REGION_SIZE_SHIFT 7U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_REGION_SIZE_CLRMSK 0xFFFFFFFFFFFFF87FULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_REGION_SIZE_4KB 0x0000000000000000ULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_REGION_SIZE_16KB 0x0000000000000080ULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_REGION_SIZE_64KB 0x0000000000000100ULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_REGION_SIZE_256KB 0x0000000000000180ULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_REGION_SIZE_1MB 0x0000000000000200ULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_REGION_SIZE_4MB 0x0000000000000280ULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_REGION_SIZE_16MB 0x0000000000000300ULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_REGION_SIZE_64MB 0x0000000000000380ULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_REGION_SIZE_256MB 0x0000000000000400ULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_ENTRY_SHIFT 1U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_ENTRY_CLRMSK 0xFFFFFFFFFFFFFFC1ULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_MODE_ENABLE_SHIFT 0U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_MODE_ENABLE_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_CONFIG_MODE_ENABLE_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_MIPS_ADDR_REMAP_RANGE_READ */ +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_READ 0x0880U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_READ_MASKFULL 0x000000000000003FULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_READ_ENTRY_SHIFT 1U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_READ_ENTRY_CLRMSK 0xFFFFFFC1U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_READ_REQUEST_SHIFT 0U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_READ_REQUEST_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_READ_REQUEST_EN 0x00000001U + +/* Register ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA */ +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA 0x0888U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA_MASKFULL 0xFFFFFFF7FFFFFF81ULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA_ADDR_OUT_SHIFT 36U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA_ADDR_OUT_CLRMSK 0x0000000FFFFFFFFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA_OS_ID_SHIFT 32U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA_OS_ID_CLRMSK 0xFFFFFFF8FFFFFFFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA_BASE_ADDR_IN_SHIFT 12U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA_BASE_ADDR_IN_CLRMSK 0xFFFFFFFF00000FFFULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA_TRUSTED_SHIFT 11U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA_TRUSTED_CLRMSK 0xFFFFFFFFFFFFF7FFULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA_TRUSTED_EN 0x0000000000000800ULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA_REGION_SIZE_SHIFT 7U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA_REGION_SIZE_CLRMSK 0xFFFFFFFFFFFFF87FULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA_MODE_ENABLE_SHIFT 0U +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA_MODE_ENABLE_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_MIPS_ADDR_REMAP_RANGE_DATA_MODE_ENABLE_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_MIPS_WRAPPER_IRQ_ENABLE */ +#define ROGUE_CR_MIPS_WRAPPER_IRQ_ENABLE 0x08A0U +#define ROGUE_CR_MIPS_WRAPPER_IRQ_ENABLE_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_MIPS_WRAPPER_IRQ_ENABLE_EVENT_SHIFT 0U +#define ROGUE_CR_MIPS_WRAPPER_IRQ_ENABLE_EVENT_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_MIPS_WRAPPER_IRQ_ENABLE_EVENT_EN 0x00000001U + +/* Register ROGUE_CR_MIPS_WRAPPER_IRQ_STATUS */ +#define ROGUE_CR_MIPS_WRAPPER_IRQ_STATUS 0x08A8U +#define ROGUE_CR_MIPS_WRAPPER_IRQ_STATUS_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_MIPS_WRAPPER_IRQ_STATUS_EVENT_SHIFT 0U +#define ROGUE_CR_MIPS_WRAPPER_IRQ_STATUS_EVENT_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_MIPS_WRAPPER_IRQ_STATUS_EVENT_EN 0x00000001U + +/* Register ROGUE_CR_MIPS_WRAPPER_IRQ_CLEAR */ +#define ROGUE_CR_MIPS_WRAPPER_IRQ_CLEAR 0x08B0U +#define ROGUE_CR_MIPS_WRAPPER_IRQ_CLEAR_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_MIPS_WRAPPER_IRQ_CLEAR_EVENT_SHIFT 0U +#define ROGUE_CR_MIPS_WRAPPER_IRQ_CLEAR_EVENT_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_MIPS_WRAPPER_IRQ_CLEAR_EVENT_EN 0x00000001U + +/* Register ROGUE_CR_MIPS_WRAPPER_NMI_ENABLE */ +#define ROGUE_CR_MIPS_WRAPPER_NMI_ENABLE 0x08B8U +#define ROGUE_CR_MIPS_WRAPPER_NMI_ENABLE_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_MIPS_WRAPPER_NMI_ENABLE_EVENT_SHIFT 0U +#define ROGUE_CR_MIPS_WRAPPER_NMI_ENABLE_EVENT_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_MIPS_WRAPPER_NMI_ENABLE_EVENT_EN 0x00000001U + +/* Register ROGUE_CR_MIPS_WRAPPER_NMI_EVENT */ +#define ROGUE_CR_MIPS_WRAPPER_NMI_EVENT 0x08C0U +#define ROGUE_CR_MIPS_WRAPPER_NMI_EVENT_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_MIPS_WRAPPER_NMI_EVENT_TRIGGER_SHIFT 0U +#define ROGUE_CR_MIPS_WRAPPER_NMI_EVENT_TRIGGER_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_MIPS_WRAPPER_NMI_EVENT_TRIGGER_EN 0x00000001U + +/* Register ROGUE_CR_MIPS_DEBUG_CONFIG */ +#define ROGUE_CR_MIPS_DEBUG_CONFIG 0x08C8U +#define ROGUE_CR_MIPS_DEBUG_CONFIG_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_MIPS_DEBUG_CONFIG_DISABLE_PROBE_DEBUG_SHIFT 0U +#define ROGUE_CR_MIPS_DEBUG_CONFIG_DISABLE_PROBE_DEBUG_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_MIPS_DEBUG_CONFIG_DISABLE_PROBE_DEBUG_EN 0x00000001U + +/* Register ROGUE_CR_MIPS_EXCEPTION_STATUS */ +#define ROGUE_CR_MIPS_EXCEPTION_STATUS 0x08D0U +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_MASKFULL 0x000000000000003FULL +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_SLEEP_SHIFT 5U +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_SLEEP_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_SLEEP_EN 0x00000020U +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_NMI_TAKEN_SHIFT 4U +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_NMI_TAKEN_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_NMI_TAKEN_EN 0x00000010U +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_NEST_EXL_SHIFT 3U +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_NEST_EXL_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_NEST_EXL_EN 0x00000008U +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_NEST_ERL_SHIFT 2U +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_NEST_ERL_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_NEST_ERL_EN 0x00000004U +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_EXL_SHIFT 1U +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_EXL_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_EXL_EN 0x00000002U +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_ERL_SHIFT 0U +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_ERL_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_MIPS_EXCEPTION_STATUS_SI_ERL_EN 0x00000001U + +/* Register ROGUE_CR_MIPS_WRAPPER_STATUS */ +#define ROGUE_CR_MIPS_WRAPPER_STATUS 0x08E8U +#define ROGUE_CR_MIPS_WRAPPER_STATUS_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_MIPS_WRAPPER_STATUS_OUTSTANDING_REQUESTS_SHIFT 0U +#define ROGUE_CR_MIPS_WRAPPER_STATUS_OUTSTANDING_REQUESTS_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_XPU_BROADCAST */ +#define ROGUE_CR_XPU_BROADCAST 0x0890U +#define ROGUE_CR_XPU_BROADCAST_MASKFULL 0x00000000000001FFULL +#define ROGUE_CR_XPU_BROADCAST_MASK_SHIFT 0U +#define ROGUE_CR_XPU_BROADCAST_MASK_CLRMSK 0xFFFFFE00U + +/* Register ROGUE_CR_META_SP_MSLVDATAX */ +#define ROGUE_CR_META_SP_MSLVDATAX 0x0A00U +#define ROGUE_CR_META_SP_MSLVDATAX_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_META_SP_MSLVDATAX_MSLVDATAX_SHIFT 0U +#define ROGUE_CR_META_SP_MSLVDATAX_MSLVDATAX_CLRMSK 0x00000000U + +/* Register ROGUE_CR_META_SP_MSLVDATAT */ +#define ROGUE_CR_META_SP_MSLVDATAT 0x0A08U +#define ROGUE_CR_META_SP_MSLVDATAT_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_META_SP_MSLVDATAT_MSLVDATAT_SHIFT 0U +#define ROGUE_CR_META_SP_MSLVDATAT_MSLVDATAT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_META_SP_MSLVCTRL0 */ +#define ROGUE_CR_META_SP_MSLVCTRL0 0x0A10U +#define ROGUE_CR_META_SP_MSLVCTRL0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_META_SP_MSLVCTRL0_ADDR_SHIFT 2U +#define ROGUE_CR_META_SP_MSLVCTRL0_ADDR_CLRMSK 0x00000003U +#define ROGUE_CR_META_SP_MSLVCTRL0_AUTOINCR_SHIFT 1U +#define ROGUE_CR_META_SP_MSLVCTRL0_AUTOINCR_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_META_SP_MSLVCTRL0_AUTOINCR_EN 0x00000002U +#define ROGUE_CR_META_SP_MSLVCTRL0_RD_SHIFT 0U +#define ROGUE_CR_META_SP_MSLVCTRL0_RD_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_META_SP_MSLVCTRL0_RD_EN 0x00000001U + +/* Register ROGUE_CR_META_SP_MSLVCTRL1 */ +#define ROGUE_CR_META_SP_MSLVCTRL1 0x0A18U +#define ROGUE_CR_META_SP_MSLVCTRL1_MASKFULL 0x00000000F7F4003FULL +#define ROGUE_CR_META_SP_MSLVCTRL1_DEFERRTHREAD_SHIFT 30U +#define ROGUE_CR_META_SP_MSLVCTRL1_DEFERRTHREAD_CLRMSK 0x3FFFFFFFU +#define ROGUE_CR_META_SP_MSLVCTRL1_LOCK2_INTERLOCK_SHIFT 29U +#define ROGUE_CR_META_SP_MSLVCTRL1_LOCK2_INTERLOCK_CLRMSK 0xDFFFFFFFU +#define ROGUE_CR_META_SP_MSLVCTRL1_LOCK2_INTERLOCK_EN 0x20000000U +#define ROGUE_CR_META_SP_MSLVCTRL1_ATOMIC_INTERLOCK_SHIFT 28U +#define ROGUE_CR_META_SP_MSLVCTRL1_ATOMIC_INTERLOCK_CLRMSK 0xEFFFFFFFU +#define ROGUE_CR_META_SP_MSLVCTRL1_ATOMIC_INTERLOCK_EN 0x10000000U +#define ROGUE_CR_META_SP_MSLVCTRL1_GBLPORT_IDLE_SHIFT 26U +#define ROGUE_CR_META_SP_MSLVCTRL1_GBLPORT_IDLE_CLRMSK 0xFBFFFFFFU +#define ROGUE_CR_META_SP_MSLVCTRL1_GBLPORT_IDLE_EN 0x04000000U +#define ROGUE_CR_META_SP_MSLVCTRL1_COREMEM_IDLE_SHIFT 25U +#define ROGUE_CR_META_SP_MSLVCTRL1_COREMEM_IDLE_CLRMSK 0xFDFFFFFFU +#define ROGUE_CR_META_SP_MSLVCTRL1_COREMEM_IDLE_EN 0x02000000U +#define ROGUE_CR_META_SP_MSLVCTRL1_READY_SHIFT 24U +#define ROGUE_CR_META_SP_MSLVCTRL1_READY_CLRMSK 0xFEFFFFFFU +#define ROGUE_CR_META_SP_MSLVCTRL1_READY_EN 0x01000000U +#define ROGUE_CR_META_SP_MSLVCTRL1_DEFERRID_SHIFT 21U +#define ROGUE_CR_META_SP_MSLVCTRL1_DEFERRID_CLRMSK 0xFF1FFFFFU +#define ROGUE_CR_META_SP_MSLVCTRL1_DEFERR_SHIFT 20U +#define ROGUE_CR_META_SP_MSLVCTRL1_DEFERR_CLRMSK 0xFFEFFFFFU +#define ROGUE_CR_META_SP_MSLVCTRL1_DEFERR_EN 0x00100000U +#define ROGUE_CR_META_SP_MSLVCTRL1_WR_ACTIVE_SHIFT 18U +#define ROGUE_CR_META_SP_MSLVCTRL1_WR_ACTIVE_CLRMSK 0xFFFBFFFFU +#define ROGUE_CR_META_SP_MSLVCTRL1_WR_ACTIVE_EN 0x00040000U +#define ROGUE_CR_META_SP_MSLVCTRL1_THREAD_SHIFT 4U +#define ROGUE_CR_META_SP_MSLVCTRL1_THREAD_CLRMSK 0xFFFFFFCFU +#define ROGUE_CR_META_SP_MSLVCTRL1_TRANS_SIZE_SHIFT 2U +#define ROGUE_CR_META_SP_MSLVCTRL1_TRANS_SIZE_CLRMSK 0xFFFFFFF3U +#define ROGUE_CR_META_SP_MSLVCTRL1_BYTE_ROUND_SHIFT 0U +#define ROGUE_CR_META_SP_MSLVCTRL1_BYTE_ROUND_CLRMSK 0xFFFFFFFCU + +/* Register ROGUE_CR_META_SP_MSLVHANDSHKE */ +#define ROGUE_CR_META_SP_MSLVHANDSHKE 0x0A50U +#define ROGUE_CR_META_SP_MSLVHANDSHKE_MASKFULL 0x000000000000000FULL +#define ROGUE_CR_META_SP_MSLVHANDSHKE_INPUT_SHIFT 2U +#define ROGUE_CR_META_SP_MSLVHANDSHKE_INPUT_CLRMSK 0xFFFFFFF3U +#define ROGUE_CR_META_SP_MSLVHANDSHKE_OUTPUT_SHIFT 0U +#define ROGUE_CR_META_SP_MSLVHANDSHKE_OUTPUT_CLRMSK 0xFFFFFFFCU + +/* Register ROGUE_CR_META_SP_MSLVT0KICK */ +#define ROGUE_CR_META_SP_MSLVT0KICK 0x0A80U +#define ROGUE_CR_META_SP_MSLVT0KICK_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_META_SP_MSLVT0KICK_MSLVT0KICK_SHIFT 0U +#define ROGUE_CR_META_SP_MSLVT0KICK_MSLVT0KICK_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_META_SP_MSLVT0KICKI */ +#define ROGUE_CR_META_SP_MSLVT0KICKI 0x0A88U +#define ROGUE_CR_META_SP_MSLVT0KICKI_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_META_SP_MSLVT0KICKI_MSLVT0KICKI_SHIFT 0U +#define ROGUE_CR_META_SP_MSLVT0KICKI_MSLVT0KICKI_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_META_SP_MSLVT1KICK */ +#define ROGUE_CR_META_SP_MSLVT1KICK 0x0A90U +#define ROGUE_CR_META_SP_MSLVT1KICK_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_META_SP_MSLVT1KICK_MSLVT1KICK_SHIFT 0U +#define ROGUE_CR_META_SP_MSLVT1KICK_MSLVT1KICK_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_META_SP_MSLVT1KICKI */ +#define ROGUE_CR_META_SP_MSLVT1KICKI 0x0A98U +#define ROGUE_CR_META_SP_MSLVT1KICKI_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_META_SP_MSLVT1KICKI_MSLVT1KICKI_SHIFT 0U +#define ROGUE_CR_META_SP_MSLVT1KICKI_MSLVT1KICKI_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_META_SP_MSLVT2KICK */ +#define ROGUE_CR_META_SP_MSLVT2KICK 0x0AA0U +#define ROGUE_CR_META_SP_MSLVT2KICK_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_META_SP_MSLVT2KICK_MSLVT2KICK_SHIFT 0U +#define ROGUE_CR_META_SP_MSLVT2KICK_MSLVT2KICK_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_META_SP_MSLVT2KICKI */ +#define ROGUE_CR_META_SP_MSLVT2KICKI 0x0AA8U +#define ROGUE_CR_META_SP_MSLVT2KICKI_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_META_SP_MSLVT2KICKI_MSLVT2KICKI_SHIFT 0U +#define ROGUE_CR_META_SP_MSLVT2KICKI_MSLVT2KICKI_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_META_SP_MSLVT3KICK */ +#define ROGUE_CR_META_SP_MSLVT3KICK 0x0AB0U +#define ROGUE_CR_META_SP_MSLVT3KICK_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_META_SP_MSLVT3KICK_MSLVT3KICK_SHIFT 0U +#define ROGUE_CR_META_SP_MSLVT3KICK_MSLVT3KICK_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_META_SP_MSLVT3KICKI */ +#define ROGUE_CR_META_SP_MSLVT3KICKI 0x0AB8U +#define ROGUE_CR_META_SP_MSLVT3KICKI_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_META_SP_MSLVT3KICKI_MSLVT3KICKI_SHIFT 0U +#define ROGUE_CR_META_SP_MSLVT3KICKI_MSLVT3KICKI_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_META_SP_MSLVRST */ +#define ROGUE_CR_META_SP_MSLVRST 0x0AC0U +#define ROGUE_CR_META_SP_MSLVRST_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_META_SP_MSLVRST_SOFTRESET_SHIFT 0U +#define ROGUE_CR_META_SP_MSLVRST_SOFTRESET_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_META_SP_MSLVRST_SOFTRESET_EN 0x00000001U + +/* Register ROGUE_CR_META_SP_MSLVIRQSTATUS */ +#define ROGUE_CR_META_SP_MSLVIRQSTATUS 0x0AC8U +#define ROGUE_CR_META_SP_MSLVIRQSTATUS_MASKFULL 0x000000000000000CULL +#define ROGUE_CR_META_SP_MSLVIRQSTATUS_TRIGVECT3_SHIFT 3U +#define ROGUE_CR_META_SP_MSLVIRQSTATUS_TRIGVECT3_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_META_SP_MSLVIRQSTATUS_TRIGVECT3_EN 0x00000008U +#define ROGUE_CR_META_SP_MSLVIRQSTATUS_TRIGVECT2_SHIFT 2U +#define ROGUE_CR_META_SP_MSLVIRQSTATUS_TRIGVECT2_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_META_SP_MSLVIRQSTATUS_TRIGVECT2_EN 0x00000004U + +/* Register ROGUE_CR_META_SP_MSLVIRQENABLE */ +#define ROGUE_CR_META_SP_MSLVIRQENABLE 0x0AD0U +#define ROGUE_CR_META_SP_MSLVIRQENABLE_MASKFULL 0x000000000000000CULL +#define ROGUE_CR_META_SP_MSLVIRQENABLE_EVENT1_SHIFT 3U +#define ROGUE_CR_META_SP_MSLVIRQENABLE_EVENT1_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_META_SP_MSLVIRQENABLE_EVENT1_EN 0x00000008U +#define ROGUE_CR_META_SP_MSLVIRQENABLE_EVENT0_SHIFT 2U +#define ROGUE_CR_META_SP_MSLVIRQENABLE_EVENT0_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_META_SP_MSLVIRQENABLE_EVENT0_EN 0x00000004U + +/* Register ROGUE_CR_META_SP_MSLVIRQLEVEL */ +#define ROGUE_CR_META_SP_MSLVIRQLEVEL 0x0AD8U +#define ROGUE_CR_META_SP_MSLVIRQLEVEL_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_META_SP_MSLVIRQLEVEL_MODE_SHIFT 0U +#define ROGUE_CR_META_SP_MSLVIRQLEVEL_MODE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_META_SP_MSLVIRQLEVEL_MODE_EN 0x00000001U + +/* Register ROGUE_CR_MTS_SCHEDULE */ +#define ROGUE_CR_MTS_SCHEDULE 0x0B00U +#define ROGUE_CR_MTS_SCHEDULE_MASKFULL 0x00000000000001FFULL +#define ROGUE_CR_MTS_SCHEDULE_HOST_SHIFT 8U +#define ROGUE_CR_MTS_SCHEDULE_HOST_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_MTS_SCHEDULE_HOST_BG_TIMER 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE_HOST_HOST 0x00000100U +#define ROGUE_CR_MTS_SCHEDULE_PRIORITY_SHIFT 6U +#define ROGUE_CR_MTS_SCHEDULE_PRIORITY_CLRMSK 0xFFFFFF3FU +#define ROGUE_CR_MTS_SCHEDULE_PRIORITY_PRT0 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE_PRIORITY_PRT1 0x00000040U +#define ROGUE_CR_MTS_SCHEDULE_PRIORITY_PRT2 0x00000080U +#define ROGUE_CR_MTS_SCHEDULE_PRIORITY_PRT3 0x000000C0U +#define ROGUE_CR_MTS_SCHEDULE_CONTEXT_SHIFT 5U +#define ROGUE_CR_MTS_SCHEDULE_CONTEXT_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_MTS_SCHEDULE_CONTEXT_BGCTX 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE_CONTEXT_INTCTX 0x00000020U +#define ROGUE_CR_MTS_SCHEDULE_TASK_SHIFT 4U +#define ROGUE_CR_MTS_SCHEDULE_TASK_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_MTS_SCHEDULE_TASK_NON_COUNTED 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE_TASK_COUNTED 0x00000010U +#define ROGUE_CR_MTS_SCHEDULE_DM_SHIFT 0U +#define ROGUE_CR_MTS_SCHEDULE_DM_CLRMSK 0xFFFFFFF0U +#define ROGUE_CR_MTS_SCHEDULE_DM_DM0 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE_DM_DM1 0x00000001U +#define ROGUE_CR_MTS_SCHEDULE_DM_DM2 0x00000002U +#define ROGUE_CR_MTS_SCHEDULE_DM_DM3 0x00000003U +#define ROGUE_CR_MTS_SCHEDULE_DM_DM4 0x00000004U +#define ROGUE_CR_MTS_SCHEDULE_DM_DM5 0x00000005U +#define ROGUE_CR_MTS_SCHEDULE_DM_DM6 0x00000006U +#define ROGUE_CR_MTS_SCHEDULE_DM_DM7 0x00000007U +#define ROGUE_CR_MTS_SCHEDULE_DM_DM_ALL 0x0000000FU + +/* Register ROGUE_CR_MTS_SCHEDULE1 */ +#define ROGUE_CR_MTS_SCHEDULE1 0x10B00U +#define ROGUE_CR_MTS_SCHEDULE1_MASKFULL 0x00000000000001FFULL +#define ROGUE_CR_MTS_SCHEDULE1_HOST_SHIFT 8U +#define ROGUE_CR_MTS_SCHEDULE1_HOST_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_MTS_SCHEDULE1_HOST_BG_TIMER 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE1_HOST_HOST 0x00000100U +#define ROGUE_CR_MTS_SCHEDULE1_PRIORITY_SHIFT 6U +#define ROGUE_CR_MTS_SCHEDULE1_PRIORITY_CLRMSK 0xFFFFFF3FU +#define ROGUE_CR_MTS_SCHEDULE1_PRIORITY_PRT0 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE1_PRIORITY_PRT1 0x00000040U +#define ROGUE_CR_MTS_SCHEDULE1_PRIORITY_PRT2 0x00000080U +#define ROGUE_CR_MTS_SCHEDULE1_PRIORITY_PRT3 0x000000C0U +#define ROGUE_CR_MTS_SCHEDULE1_CONTEXT_SHIFT 5U +#define ROGUE_CR_MTS_SCHEDULE1_CONTEXT_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_MTS_SCHEDULE1_CONTEXT_BGCTX 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE1_CONTEXT_INTCTX 0x00000020U +#define ROGUE_CR_MTS_SCHEDULE1_TASK_SHIFT 4U +#define ROGUE_CR_MTS_SCHEDULE1_TASK_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_MTS_SCHEDULE1_TASK_NON_COUNTED 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE1_TASK_COUNTED 0x00000010U +#define ROGUE_CR_MTS_SCHEDULE1_DM_SHIFT 0U +#define ROGUE_CR_MTS_SCHEDULE1_DM_CLRMSK 0xFFFFFFF0U +#define ROGUE_CR_MTS_SCHEDULE1_DM_DM0 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE1_DM_DM1 0x00000001U +#define ROGUE_CR_MTS_SCHEDULE1_DM_DM2 0x00000002U +#define ROGUE_CR_MTS_SCHEDULE1_DM_DM3 0x00000003U +#define ROGUE_CR_MTS_SCHEDULE1_DM_DM4 0x00000004U +#define ROGUE_CR_MTS_SCHEDULE1_DM_DM5 0x00000005U +#define ROGUE_CR_MTS_SCHEDULE1_DM_DM6 0x00000006U +#define ROGUE_CR_MTS_SCHEDULE1_DM_DM7 0x00000007U +#define ROGUE_CR_MTS_SCHEDULE1_DM_DM_ALL 0x0000000FU + +/* Register ROGUE_CR_MTS_SCHEDULE2 */ +#define ROGUE_CR_MTS_SCHEDULE2 0x20B00U +#define ROGUE_CR_MTS_SCHEDULE2_MASKFULL 0x00000000000001FFULL +#define ROGUE_CR_MTS_SCHEDULE2_HOST_SHIFT 8U +#define ROGUE_CR_MTS_SCHEDULE2_HOST_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_MTS_SCHEDULE2_HOST_BG_TIMER 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE2_HOST_HOST 0x00000100U +#define ROGUE_CR_MTS_SCHEDULE2_PRIORITY_SHIFT 6U +#define ROGUE_CR_MTS_SCHEDULE2_PRIORITY_CLRMSK 0xFFFFFF3FU +#define ROGUE_CR_MTS_SCHEDULE2_PRIORITY_PRT0 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE2_PRIORITY_PRT1 0x00000040U +#define ROGUE_CR_MTS_SCHEDULE2_PRIORITY_PRT2 0x00000080U +#define ROGUE_CR_MTS_SCHEDULE2_PRIORITY_PRT3 0x000000C0U +#define ROGUE_CR_MTS_SCHEDULE2_CONTEXT_SHIFT 5U +#define ROGUE_CR_MTS_SCHEDULE2_CONTEXT_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_MTS_SCHEDULE2_CONTEXT_BGCTX 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE2_CONTEXT_INTCTX 0x00000020U +#define ROGUE_CR_MTS_SCHEDULE2_TASK_SHIFT 4U +#define ROGUE_CR_MTS_SCHEDULE2_TASK_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_MTS_SCHEDULE2_TASK_NON_COUNTED 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE2_TASK_COUNTED 0x00000010U +#define ROGUE_CR_MTS_SCHEDULE2_DM_SHIFT 0U +#define ROGUE_CR_MTS_SCHEDULE2_DM_CLRMSK 0xFFFFFFF0U +#define ROGUE_CR_MTS_SCHEDULE2_DM_DM0 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE2_DM_DM1 0x00000001U +#define ROGUE_CR_MTS_SCHEDULE2_DM_DM2 0x00000002U +#define ROGUE_CR_MTS_SCHEDULE2_DM_DM3 0x00000003U +#define ROGUE_CR_MTS_SCHEDULE2_DM_DM4 0x00000004U +#define ROGUE_CR_MTS_SCHEDULE2_DM_DM5 0x00000005U +#define ROGUE_CR_MTS_SCHEDULE2_DM_DM6 0x00000006U +#define ROGUE_CR_MTS_SCHEDULE2_DM_DM7 0x00000007U +#define ROGUE_CR_MTS_SCHEDULE2_DM_DM_ALL 0x0000000FU + +/* Register ROGUE_CR_MTS_SCHEDULE3 */ +#define ROGUE_CR_MTS_SCHEDULE3 0x30B00U +#define ROGUE_CR_MTS_SCHEDULE3_MASKFULL 0x00000000000001FFULL +#define ROGUE_CR_MTS_SCHEDULE3_HOST_SHIFT 8U +#define ROGUE_CR_MTS_SCHEDULE3_HOST_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_MTS_SCHEDULE3_HOST_BG_TIMER 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE3_HOST_HOST 0x00000100U +#define ROGUE_CR_MTS_SCHEDULE3_PRIORITY_SHIFT 6U +#define ROGUE_CR_MTS_SCHEDULE3_PRIORITY_CLRMSK 0xFFFFFF3FU +#define ROGUE_CR_MTS_SCHEDULE3_PRIORITY_PRT0 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE3_PRIORITY_PRT1 0x00000040U +#define ROGUE_CR_MTS_SCHEDULE3_PRIORITY_PRT2 0x00000080U +#define ROGUE_CR_MTS_SCHEDULE3_PRIORITY_PRT3 0x000000C0U +#define ROGUE_CR_MTS_SCHEDULE3_CONTEXT_SHIFT 5U +#define ROGUE_CR_MTS_SCHEDULE3_CONTEXT_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_MTS_SCHEDULE3_CONTEXT_BGCTX 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE3_CONTEXT_INTCTX 0x00000020U +#define ROGUE_CR_MTS_SCHEDULE3_TASK_SHIFT 4U +#define ROGUE_CR_MTS_SCHEDULE3_TASK_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_MTS_SCHEDULE3_TASK_NON_COUNTED 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE3_TASK_COUNTED 0x00000010U +#define ROGUE_CR_MTS_SCHEDULE3_DM_SHIFT 0U +#define ROGUE_CR_MTS_SCHEDULE3_DM_CLRMSK 0xFFFFFFF0U +#define ROGUE_CR_MTS_SCHEDULE3_DM_DM0 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE3_DM_DM1 0x00000001U +#define ROGUE_CR_MTS_SCHEDULE3_DM_DM2 0x00000002U +#define ROGUE_CR_MTS_SCHEDULE3_DM_DM3 0x00000003U +#define ROGUE_CR_MTS_SCHEDULE3_DM_DM4 0x00000004U +#define ROGUE_CR_MTS_SCHEDULE3_DM_DM5 0x00000005U +#define ROGUE_CR_MTS_SCHEDULE3_DM_DM6 0x00000006U +#define ROGUE_CR_MTS_SCHEDULE3_DM_DM7 0x00000007U +#define ROGUE_CR_MTS_SCHEDULE3_DM_DM_ALL 0x0000000FU + +/* Register ROGUE_CR_MTS_SCHEDULE4 */ +#define ROGUE_CR_MTS_SCHEDULE4 0x40B00U +#define ROGUE_CR_MTS_SCHEDULE4_MASKFULL 0x00000000000001FFULL +#define ROGUE_CR_MTS_SCHEDULE4_HOST_SHIFT 8U +#define ROGUE_CR_MTS_SCHEDULE4_HOST_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_MTS_SCHEDULE4_HOST_BG_TIMER 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE4_HOST_HOST 0x00000100U +#define ROGUE_CR_MTS_SCHEDULE4_PRIORITY_SHIFT 6U +#define ROGUE_CR_MTS_SCHEDULE4_PRIORITY_CLRMSK 0xFFFFFF3FU +#define ROGUE_CR_MTS_SCHEDULE4_PRIORITY_PRT0 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE4_PRIORITY_PRT1 0x00000040U +#define ROGUE_CR_MTS_SCHEDULE4_PRIORITY_PRT2 0x00000080U +#define ROGUE_CR_MTS_SCHEDULE4_PRIORITY_PRT3 0x000000C0U +#define ROGUE_CR_MTS_SCHEDULE4_CONTEXT_SHIFT 5U +#define ROGUE_CR_MTS_SCHEDULE4_CONTEXT_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_MTS_SCHEDULE4_CONTEXT_BGCTX 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE4_CONTEXT_INTCTX 0x00000020U +#define ROGUE_CR_MTS_SCHEDULE4_TASK_SHIFT 4U +#define ROGUE_CR_MTS_SCHEDULE4_TASK_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_MTS_SCHEDULE4_TASK_NON_COUNTED 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE4_TASK_COUNTED 0x00000010U +#define ROGUE_CR_MTS_SCHEDULE4_DM_SHIFT 0U +#define ROGUE_CR_MTS_SCHEDULE4_DM_CLRMSK 0xFFFFFFF0U +#define ROGUE_CR_MTS_SCHEDULE4_DM_DM0 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE4_DM_DM1 0x00000001U +#define ROGUE_CR_MTS_SCHEDULE4_DM_DM2 0x00000002U +#define ROGUE_CR_MTS_SCHEDULE4_DM_DM3 0x00000003U +#define ROGUE_CR_MTS_SCHEDULE4_DM_DM4 0x00000004U +#define ROGUE_CR_MTS_SCHEDULE4_DM_DM5 0x00000005U +#define ROGUE_CR_MTS_SCHEDULE4_DM_DM6 0x00000006U +#define ROGUE_CR_MTS_SCHEDULE4_DM_DM7 0x00000007U +#define ROGUE_CR_MTS_SCHEDULE4_DM_DM_ALL 0x0000000FU + +/* Register ROGUE_CR_MTS_SCHEDULE5 */ +#define ROGUE_CR_MTS_SCHEDULE5 0x50B00U +#define ROGUE_CR_MTS_SCHEDULE5_MASKFULL 0x00000000000001FFULL +#define ROGUE_CR_MTS_SCHEDULE5_HOST_SHIFT 8U +#define ROGUE_CR_MTS_SCHEDULE5_HOST_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_MTS_SCHEDULE5_HOST_BG_TIMER 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE5_HOST_HOST 0x00000100U +#define ROGUE_CR_MTS_SCHEDULE5_PRIORITY_SHIFT 6U +#define ROGUE_CR_MTS_SCHEDULE5_PRIORITY_CLRMSK 0xFFFFFF3FU +#define ROGUE_CR_MTS_SCHEDULE5_PRIORITY_PRT0 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE5_PRIORITY_PRT1 0x00000040U +#define ROGUE_CR_MTS_SCHEDULE5_PRIORITY_PRT2 0x00000080U +#define ROGUE_CR_MTS_SCHEDULE5_PRIORITY_PRT3 0x000000C0U +#define ROGUE_CR_MTS_SCHEDULE5_CONTEXT_SHIFT 5U +#define ROGUE_CR_MTS_SCHEDULE5_CONTEXT_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_MTS_SCHEDULE5_CONTEXT_BGCTX 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE5_CONTEXT_INTCTX 0x00000020U +#define ROGUE_CR_MTS_SCHEDULE5_TASK_SHIFT 4U +#define ROGUE_CR_MTS_SCHEDULE5_TASK_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_MTS_SCHEDULE5_TASK_NON_COUNTED 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE5_TASK_COUNTED 0x00000010U +#define ROGUE_CR_MTS_SCHEDULE5_DM_SHIFT 0U +#define ROGUE_CR_MTS_SCHEDULE5_DM_CLRMSK 0xFFFFFFF0U +#define ROGUE_CR_MTS_SCHEDULE5_DM_DM0 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE5_DM_DM1 0x00000001U +#define ROGUE_CR_MTS_SCHEDULE5_DM_DM2 0x00000002U +#define ROGUE_CR_MTS_SCHEDULE5_DM_DM3 0x00000003U +#define ROGUE_CR_MTS_SCHEDULE5_DM_DM4 0x00000004U +#define ROGUE_CR_MTS_SCHEDULE5_DM_DM5 0x00000005U +#define ROGUE_CR_MTS_SCHEDULE5_DM_DM6 0x00000006U +#define ROGUE_CR_MTS_SCHEDULE5_DM_DM7 0x00000007U +#define ROGUE_CR_MTS_SCHEDULE5_DM_DM_ALL 0x0000000FU + +/* Register ROGUE_CR_MTS_SCHEDULE6 */ +#define ROGUE_CR_MTS_SCHEDULE6 0x60B00U +#define ROGUE_CR_MTS_SCHEDULE6_MASKFULL 0x00000000000001FFULL +#define ROGUE_CR_MTS_SCHEDULE6_HOST_SHIFT 8U +#define ROGUE_CR_MTS_SCHEDULE6_HOST_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_MTS_SCHEDULE6_HOST_BG_TIMER 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE6_HOST_HOST 0x00000100U +#define ROGUE_CR_MTS_SCHEDULE6_PRIORITY_SHIFT 6U +#define ROGUE_CR_MTS_SCHEDULE6_PRIORITY_CLRMSK 0xFFFFFF3FU +#define ROGUE_CR_MTS_SCHEDULE6_PRIORITY_PRT0 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE6_PRIORITY_PRT1 0x00000040U +#define ROGUE_CR_MTS_SCHEDULE6_PRIORITY_PRT2 0x00000080U +#define ROGUE_CR_MTS_SCHEDULE6_PRIORITY_PRT3 0x000000C0U +#define ROGUE_CR_MTS_SCHEDULE6_CONTEXT_SHIFT 5U +#define ROGUE_CR_MTS_SCHEDULE6_CONTEXT_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_MTS_SCHEDULE6_CONTEXT_BGCTX 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE6_CONTEXT_INTCTX 0x00000020U +#define ROGUE_CR_MTS_SCHEDULE6_TASK_SHIFT 4U +#define ROGUE_CR_MTS_SCHEDULE6_TASK_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_MTS_SCHEDULE6_TASK_NON_COUNTED 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE6_TASK_COUNTED 0x00000010U +#define ROGUE_CR_MTS_SCHEDULE6_DM_SHIFT 0U +#define ROGUE_CR_MTS_SCHEDULE6_DM_CLRMSK 0xFFFFFFF0U +#define ROGUE_CR_MTS_SCHEDULE6_DM_DM0 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE6_DM_DM1 0x00000001U +#define ROGUE_CR_MTS_SCHEDULE6_DM_DM2 0x00000002U +#define ROGUE_CR_MTS_SCHEDULE6_DM_DM3 0x00000003U +#define ROGUE_CR_MTS_SCHEDULE6_DM_DM4 0x00000004U +#define ROGUE_CR_MTS_SCHEDULE6_DM_DM5 0x00000005U +#define ROGUE_CR_MTS_SCHEDULE6_DM_DM6 0x00000006U +#define ROGUE_CR_MTS_SCHEDULE6_DM_DM7 0x00000007U +#define ROGUE_CR_MTS_SCHEDULE6_DM_DM_ALL 0x0000000FU + +/* Register ROGUE_CR_MTS_SCHEDULE7 */ +#define ROGUE_CR_MTS_SCHEDULE7 0x70B00U +#define ROGUE_CR_MTS_SCHEDULE7_MASKFULL 0x00000000000001FFULL +#define ROGUE_CR_MTS_SCHEDULE7_HOST_SHIFT 8U +#define ROGUE_CR_MTS_SCHEDULE7_HOST_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_MTS_SCHEDULE7_HOST_BG_TIMER 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE7_HOST_HOST 0x00000100U +#define ROGUE_CR_MTS_SCHEDULE7_PRIORITY_SHIFT 6U +#define ROGUE_CR_MTS_SCHEDULE7_PRIORITY_CLRMSK 0xFFFFFF3FU +#define ROGUE_CR_MTS_SCHEDULE7_PRIORITY_PRT0 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE7_PRIORITY_PRT1 0x00000040U +#define ROGUE_CR_MTS_SCHEDULE7_PRIORITY_PRT2 0x00000080U +#define ROGUE_CR_MTS_SCHEDULE7_PRIORITY_PRT3 0x000000C0U +#define ROGUE_CR_MTS_SCHEDULE7_CONTEXT_SHIFT 5U +#define ROGUE_CR_MTS_SCHEDULE7_CONTEXT_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_MTS_SCHEDULE7_CONTEXT_BGCTX 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE7_CONTEXT_INTCTX 0x00000020U +#define ROGUE_CR_MTS_SCHEDULE7_TASK_SHIFT 4U +#define ROGUE_CR_MTS_SCHEDULE7_TASK_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_MTS_SCHEDULE7_TASK_NON_COUNTED 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE7_TASK_COUNTED 0x00000010U +#define ROGUE_CR_MTS_SCHEDULE7_DM_SHIFT 0U +#define ROGUE_CR_MTS_SCHEDULE7_DM_CLRMSK 0xFFFFFFF0U +#define ROGUE_CR_MTS_SCHEDULE7_DM_DM0 0x00000000U +#define ROGUE_CR_MTS_SCHEDULE7_DM_DM1 0x00000001U +#define ROGUE_CR_MTS_SCHEDULE7_DM_DM2 0x00000002U +#define ROGUE_CR_MTS_SCHEDULE7_DM_DM3 0x00000003U +#define ROGUE_CR_MTS_SCHEDULE7_DM_DM4 0x00000004U +#define ROGUE_CR_MTS_SCHEDULE7_DM_DM5 0x00000005U +#define ROGUE_CR_MTS_SCHEDULE7_DM_DM6 0x00000006U +#define ROGUE_CR_MTS_SCHEDULE7_DM_DM7 0x00000007U +#define ROGUE_CR_MTS_SCHEDULE7_DM_DM_ALL 0x0000000FU + +/* Register ROGUE_CR_MTS_BGCTX_THREAD0_DM_ASSOC */ +#define ROGUE_CR_MTS_BGCTX_THREAD0_DM_ASSOC 0x0B30U +#define ROGUE_CR_MTS_BGCTX_THREAD0_DM_ASSOC_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_MTS_BGCTX_THREAD0_DM_ASSOC_DM_ASSOC_SHIFT 0U +#define ROGUE_CR_MTS_BGCTX_THREAD0_DM_ASSOC_DM_ASSOC_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_MTS_BGCTX_THREAD1_DM_ASSOC */ +#define ROGUE_CR_MTS_BGCTX_THREAD1_DM_ASSOC 0x0B38U +#define ROGUE_CR_MTS_BGCTX_THREAD1_DM_ASSOC_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_MTS_BGCTX_THREAD1_DM_ASSOC_DM_ASSOC_SHIFT 0U +#define ROGUE_CR_MTS_BGCTX_THREAD1_DM_ASSOC_DM_ASSOC_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_MTS_INTCTX_THREAD0_DM_ASSOC */ +#define ROGUE_CR_MTS_INTCTX_THREAD0_DM_ASSOC 0x0B40U +#define ROGUE_CR_MTS_INTCTX_THREAD0_DM_ASSOC_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_MTS_INTCTX_THREAD0_DM_ASSOC_DM_ASSOC_SHIFT 0U +#define ROGUE_CR_MTS_INTCTX_THREAD0_DM_ASSOC_DM_ASSOC_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_MTS_INTCTX_THREAD1_DM_ASSOC */ +#define ROGUE_CR_MTS_INTCTX_THREAD1_DM_ASSOC 0x0B48U +#define ROGUE_CR_MTS_INTCTX_THREAD1_DM_ASSOC_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_MTS_INTCTX_THREAD1_DM_ASSOC_DM_ASSOC_SHIFT 0U +#define ROGUE_CR_MTS_INTCTX_THREAD1_DM_ASSOC_DM_ASSOC_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG */ +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG 0x0B50U +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG__S7_TOP__MASKFULL 0x000FF0FFFFFFF701ULL +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_MASKFULL 0x0000FFFFFFFFF001ULL +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_FENCE_PC_BASE_SHIFT 44U +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_FENCE_PC_BASE_CLRMSK 0xFFFF0FFFFFFFFFFFULL +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG__S7_TOP__FENCE_PC_BASE_SHIFT 44U +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG__S7_TOP__FENCE_PC_BASE_CLRMSK 0xFFF00FFFFFFFFFFFULL +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_FENCE_DM_SHIFT 40U +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_FENCE_DM_CLRMSK 0xFFFFF0FFFFFFFFFFULL +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_FENCE_ADDR_SHIFT 12U +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_FENCE_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_FENCE_PERSISTENCE_SHIFT 9U +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_FENCE_PERSISTENCE_CLRMSK 0xFFFFFFFFFFFFF9FFULL +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_FENCE_SLC_COHERENT_SHIFT 8U +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_FENCE_SLC_COHERENT_CLRMSK 0xFFFFFFFFFFFFFEFFULL +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_FENCE_SLC_COHERENT_EN 0x0000000000000100ULL +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_IDLE_CTRL_SHIFT 0U +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_IDLE_CTRL_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_IDLE_CTRL_META 0x0000000000000000ULL +#define ROGUE_CR_MTS_GARTEN_WRAPPER_CONFIG_IDLE_CTRL_MTS 0x0000000000000001ULL + +/* Register ROGUE_CR_MTS_DM0_INTERRUPT_ENABLE */ +#define ROGUE_CR_MTS_DM0_INTERRUPT_ENABLE 0x0B58U +#define ROGUE_CR_MTS_DM0_INTERRUPT_ENABLE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_MTS_DM0_INTERRUPT_ENABLE_INT_ENABLE_SHIFT 0U +#define ROGUE_CR_MTS_DM0_INTERRUPT_ENABLE_INT_ENABLE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_MTS_DM1_INTERRUPT_ENABLE */ +#define ROGUE_CR_MTS_DM1_INTERRUPT_ENABLE 0x0B60U +#define ROGUE_CR_MTS_DM1_INTERRUPT_ENABLE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_MTS_DM1_INTERRUPT_ENABLE_INT_ENABLE_SHIFT 0U +#define ROGUE_CR_MTS_DM1_INTERRUPT_ENABLE_INT_ENABLE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_MTS_DM2_INTERRUPT_ENABLE */ +#define ROGUE_CR_MTS_DM2_INTERRUPT_ENABLE 0x0B68U +#define ROGUE_CR_MTS_DM2_INTERRUPT_ENABLE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_MTS_DM2_INTERRUPT_ENABLE_INT_ENABLE_SHIFT 0U +#define ROGUE_CR_MTS_DM2_INTERRUPT_ENABLE_INT_ENABLE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_MTS_DM3_INTERRUPT_ENABLE */ +#define ROGUE_CR_MTS_DM3_INTERRUPT_ENABLE 0x0B70U +#define ROGUE_CR_MTS_DM3_INTERRUPT_ENABLE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_MTS_DM3_INTERRUPT_ENABLE_INT_ENABLE_SHIFT 0U +#define ROGUE_CR_MTS_DM3_INTERRUPT_ENABLE_INT_ENABLE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_MTS_DM4_INTERRUPT_ENABLE */ +#define ROGUE_CR_MTS_DM4_INTERRUPT_ENABLE 0x0B78U +#define ROGUE_CR_MTS_DM4_INTERRUPT_ENABLE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_MTS_DM4_INTERRUPT_ENABLE_INT_ENABLE_SHIFT 0U +#define ROGUE_CR_MTS_DM4_INTERRUPT_ENABLE_INT_ENABLE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_MTS_DM5_INTERRUPT_ENABLE */ +#define ROGUE_CR_MTS_DM5_INTERRUPT_ENABLE 0x0B80U +#define ROGUE_CR_MTS_DM5_INTERRUPT_ENABLE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_MTS_DM5_INTERRUPT_ENABLE_INT_ENABLE_SHIFT 0U +#define ROGUE_CR_MTS_DM5_INTERRUPT_ENABLE_INT_ENABLE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_MTS_INTCTX */ +#define ROGUE_CR_MTS_INTCTX 0x0B98U +#define ROGUE_CR_MTS_INTCTX_MASKFULL 0x000000003FFFFFFFULL +#define ROGUE_CR_MTS_INTCTX_DM_HOST_SCHEDULE_SHIFT 22U +#define ROGUE_CR_MTS_INTCTX_DM_HOST_SCHEDULE_CLRMSK 0xC03FFFFFU +#define ROGUE_CR_MTS_INTCTX_DM_PTR_SHIFT 18U +#define ROGUE_CR_MTS_INTCTX_DM_PTR_CLRMSK 0xFFC3FFFFU +#define ROGUE_CR_MTS_INTCTX_THREAD_ACTIVE_SHIFT 16U +#define ROGUE_CR_MTS_INTCTX_THREAD_ACTIVE_CLRMSK 0xFFFCFFFFU +#define ROGUE_CR_MTS_INTCTX_DM_TIMER_SCHEDULE_SHIFT 8U +#define ROGUE_CR_MTS_INTCTX_DM_TIMER_SCHEDULE_CLRMSK 0xFFFF00FFU +#define ROGUE_CR_MTS_INTCTX_DM_INTERRUPT_SCHEDULE_SHIFT 0U +#define ROGUE_CR_MTS_INTCTX_DM_INTERRUPT_SCHEDULE_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_MTS_BGCTX */ +#define ROGUE_CR_MTS_BGCTX 0x0BA0U +#define ROGUE_CR_MTS_BGCTX_MASKFULL 0x0000000000003FFFULL +#define ROGUE_CR_MTS_BGCTX_DM_PTR_SHIFT 10U +#define ROGUE_CR_MTS_BGCTX_DM_PTR_CLRMSK 0xFFFFC3FFU +#define ROGUE_CR_MTS_BGCTX_THREAD_ACTIVE_SHIFT 8U +#define ROGUE_CR_MTS_BGCTX_THREAD_ACTIVE_CLRMSK 0xFFFFFCFFU +#define ROGUE_CR_MTS_BGCTX_DM_NONCOUNTED_SCHEDULE_SHIFT 0U +#define ROGUE_CR_MTS_BGCTX_DM_NONCOUNTED_SCHEDULE_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE */ +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE 0x0BA8U +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_MASKFULL 0xFFFFFFFFFFFFFFFFULL +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_DM7_SHIFT 56U +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_DM7_CLRMSK 0x00FFFFFFFFFFFFFFULL +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_DM6_SHIFT 48U +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_DM6_CLRMSK 0xFF00FFFFFFFFFFFFULL +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_DM5_SHIFT 40U +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_DM5_CLRMSK 0xFFFF00FFFFFFFFFFULL +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_DM4_SHIFT 32U +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_DM4_CLRMSK 0xFFFFFF00FFFFFFFFULL +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_DM3_SHIFT 24U +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_DM3_CLRMSK 0xFFFFFFFF00FFFFFFULL +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_DM2_SHIFT 16U +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_DM2_CLRMSK 0xFFFFFFFFFF00FFFFULL +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_DM1_SHIFT 8U +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_DM1_CLRMSK 0xFFFFFFFFFFFF00FFULL +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_DM0_SHIFT 0U +#define ROGUE_CR_MTS_BGCTX_COUNTED_SCHEDULE_DM0_CLRMSK 0xFFFFFFFFFFFFFF00ULL + +/* Register ROGUE_CR_MTS_GPU_INT_STATUS */ +#define ROGUE_CR_MTS_GPU_INT_STATUS 0x0BB0U +#define ROGUE_CR_MTS_GPU_INT_STATUS_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_MTS_GPU_INT_STATUS_STATUS_SHIFT 0U +#define ROGUE_CR_MTS_GPU_INT_STATUS_STATUS_CLRMSK 0x00000000U + +/* Register ROGUE_CR_MTS_SCHEDULE_ENABLE */ +#define ROGUE_CR_MTS_SCHEDULE_ENABLE 0x0BC8U +#define ROGUE_CR_MTS_SCHEDULE_ENABLE_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_MTS_SCHEDULE_ENABLE_MASK_SHIFT 0U +#define ROGUE_CR_MTS_SCHEDULE_ENABLE_MASK_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_IRQ_OS0_EVENT_STATUS */ +#define ROGUE_CR_IRQ_OS0_EVENT_STATUS 0x0BD8U +#define ROGUE_CR_IRQ_OS0_EVENT_STATUS_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_IRQ_OS0_EVENT_STATUS_SOURCE_SHIFT 0U +#define ROGUE_CR_IRQ_OS0_EVENT_STATUS_SOURCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_IRQ_OS0_EVENT_STATUS_SOURCE_EN 0x00000001U + +/* Register ROGUE_CR_IRQ_OS0_EVENT_CLEAR */ +#define ROGUE_CR_IRQ_OS0_EVENT_CLEAR 0x0BE8U +#define ROGUE_CR_IRQ_OS0_EVENT_CLEAR_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_IRQ_OS0_EVENT_CLEAR_SOURCE_SHIFT 0U +#define ROGUE_CR_IRQ_OS0_EVENT_CLEAR_SOURCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_IRQ_OS0_EVENT_CLEAR_SOURCE_EN 0x00000001U + +/* Register ROGUE_CR_IRQ_OS1_EVENT_STATUS */ +#define ROGUE_CR_IRQ_OS1_EVENT_STATUS 0x10BD8U +#define ROGUE_CR_IRQ_OS1_EVENT_STATUS_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_IRQ_OS1_EVENT_STATUS_SOURCE_SHIFT 0U +#define ROGUE_CR_IRQ_OS1_EVENT_STATUS_SOURCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_IRQ_OS1_EVENT_STATUS_SOURCE_EN 0x00000001U + +/* Register ROGUE_CR_IRQ_OS1_EVENT_CLEAR */ +#define ROGUE_CR_IRQ_OS1_EVENT_CLEAR 0x10BE8U +#define ROGUE_CR_IRQ_OS1_EVENT_CLEAR_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_IRQ_OS1_EVENT_CLEAR_SOURCE_SHIFT 0U +#define ROGUE_CR_IRQ_OS1_EVENT_CLEAR_SOURCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_IRQ_OS1_EVENT_CLEAR_SOURCE_EN 0x00000001U + +/* Register ROGUE_CR_IRQ_OS2_EVENT_STATUS */ +#define ROGUE_CR_IRQ_OS2_EVENT_STATUS 0x20BD8U +#define ROGUE_CR_IRQ_OS2_EVENT_STATUS_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_IRQ_OS2_EVENT_STATUS_SOURCE_SHIFT 0U +#define ROGUE_CR_IRQ_OS2_EVENT_STATUS_SOURCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_IRQ_OS2_EVENT_STATUS_SOURCE_EN 0x00000001U + +/* Register ROGUE_CR_IRQ_OS2_EVENT_CLEAR */ +#define ROGUE_CR_IRQ_OS2_EVENT_CLEAR 0x20BE8U +#define ROGUE_CR_IRQ_OS2_EVENT_CLEAR_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_IRQ_OS2_EVENT_CLEAR_SOURCE_SHIFT 0U +#define ROGUE_CR_IRQ_OS2_EVENT_CLEAR_SOURCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_IRQ_OS2_EVENT_CLEAR_SOURCE_EN 0x00000001U + +/* Register ROGUE_CR_IRQ_OS3_EVENT_STATUS */ +#define ROGUE_CR_IRQ_OS3_EVENT_STATUS 0x30BD8U +#define ROGUE_CR_IRQ_OS3_EVENT_STATUS_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_IRQ_OS3_EVENT_STATUS_SOURCE_SHIFT 0U +#define ROGUE_CR_IRQ_OS3_EVENT_STATUS_SOURCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_IRQ_OS3_EVENT_STATUS_SOURCE_EN 0x00000001U + +/* Register ROGUE_CR_IRQ_OS3_EVENT_CLEAR */ +#define ROGUE_CR_IRQ_OS3_EVENT_CLEAR 0x30BE8U +#define ROGUE_CR_IRQ_OS3_EVENT_CLEAR_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_IRQ_OS3_EVENT_CLEAR_SOURCE_SHIFT 0U +#define ROGUE_CR_IRQ_OS3_EVENT_CLEAR_SOURCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_IRQ_OS3_EVENT_CLEAR_SOURCE_EN 0x00000001U + +/* Register ROGUE_CR_IRQ_OS4_EVENT_STATUS */ +#define ROGUE_CR_IRQ_OS4_EVENT_STATUS 0x40BD8U +#define ROGUE_CR_IRQ_OS4_EVENT_STATUS_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_IRQ_OS4_EVENT_STATUS_SOURCE_SHIFT 0U +#define ROGUE_CR_IRQ_OS4_EVENT_STATUS_SOURCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_IRQ_OS4_EVENT_STATUS_SOURCE_EN 0x00000001U + +/* Register ROGUE_CR_IRQ_OS4_EVENT_CLEAR */ +#define ROGUE_CR_IRQ_OS4_EVENT_CLEAR 0x40BE8U +#define ROGUE_CR_IRQ_OS4_EVENT_CLEAR_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_IRQ_OS4_EVENT_CLEAR_SOURCE_SHIFT 0U +#define ROGUE_CR_IRQ_OS4_EVENT_CLEAR_SOURCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_IRQ_OS4_EVENT_CLEAR_SOURCE_EN 0x00000001U + +/* Register ROGUE_CR_IRQ_OS5_EVENT_STATUS */ +#define ROGUE_CR_IRQ_OS5_EVENT_STATUS 0x50BD8U +#define ROGUE_CR_IRQ_OS5_EVENT_STATUS_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_IRQ_OS5_EVENT_STATUS_SOURCE_SHIFT 0U +#define ROGUE_CR_IRQ_OS5_EVENT_STATUS_SOURCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_IRQ_OS5_EVENT_STATUS_SOURCE_EN 0x00000001U + +/* Register ROGUE_CR_IRQ_OS5_EVENT_CLEAR */ +#define ROGUE_CR_IRQ_OS5_EVENT_CLEAR 0x50BE8U +#define ROGUE_CR_IRQ_OS5_EVENT_CLEAR_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_IRQ_OS5_EVENT_CLEAR_SOURCE_SHIFT 0U +#define ROGUE_CR_IRQ_OS5_EVENT_CLEAR_SOURCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_IRQ_OS5_EVENT_CLEAR_SOURCE_EN 0x00000001U + +/* Register ROGUE_CR_IRQ_OS6_EVENT_STATUS */ +#define ROGUE_CR_IRQ_OS6_EVENT_STATUS 0x60BD8U +#define ROGUE_CR_IRQ_OS6_EVENT_STATUS_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_IRQ_OS6_EVENT_STATUS_SOURCE_SHIFT 0U +#define ROGUE_CR_IRQ_OS6_EVENT_STATUS_SOURCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_IRQ_OS6_EVENT_STATUS_SOURCE_EN 0x00000001U + +/* Register ROGUE_CR_IRQ_OS6_EVENT_CLEAR */ +#define ROGUE_CR_IRQ_OS6_EVENT_CLEAR 0x60BE8U +#define ROGUE_CR_IRQ_OS6_EVENT_CLEAR_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_IRQ_OS6_EVENT_CLEAR_SOURCE_SHIFT 0U +#define ROGUE_CR_IRQ_OS6_EVENT_CLEAR_SOURCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_IRQ_OS6_EVENT_CLEAR_SOURCE_EN 0x00000001U + +/* Register ROGUE_CR_IRQ_OS7_EVENT_STATUS */ +#define ROGUE_CR_IRQ_OS7_EVENT_STATUS 0x70BD8U +#define ROGUE_CR_IRQ_OS7_EVENT_STATUS_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_IRQ_OS7_EVENT_STATUS_SOURCE_SHIFT 0U +#define ROGUE_CR_IRQ_OS7_EVENT_STATUS_SOURCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_IRQ_OS7_EVENT_STATUS_SOURCE_EN 0x00000001U + +/* Register ROGUE_CR_IRQ_OS7_EVENT_CLEAR */ +#define ROGUE_CR_IRQ_OS7_EVENT_CLEAR 0x70BE8U +#define ROGUE_CR_IRQ_OS7_EVENT_CLEAR_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_IRQ_OS7_EVENT_CLEAR_SOURCE_SHIFT 0U +#define ROGUE_CR_IRQ_OS7_EVENT_CLEAR_SOURCE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_IRQ_OS7_EVENT_CLEAR_SOURCE_EN 0x00000001U + +/* Register ROGUE_CR_META_BOOT */ +#define ROGUE_CR_META_BOOT 0x0BF8U +#define ROGUE_CR_META_BOOT_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_META_BOOT_MODE_SHIFT 0U +#define ROGUE_CR_META_BOOT_MODE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_META_BOOT_MODE_EN 0x00000001U + +/* Register ROGUE_CR_GARTEN_SLC */ +#define ROGUE_CR_GARTEN_SLC 0x0BB8U +#define ROGUE_CR_GARTEN_SLC_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_GARTEN_SLC_FORCE_COHERENCY_SHIFT 0U +#define ROGUE_CR_GARTEN_SLC_FORCE_COHERENCY_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_GARTEN_SLC_FORCE_COHERENCY_EN 0x00000001U + +/* Register ROGUE_CR_PPP */ +#define ROGUE_CR_PPP 0x0CD0U +#define ROGUE_CR_PPP_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PPP_CHECKSUM_SHIFT 0U +#define ROGUE_CR_PPP_CHECKSUM_CLRMSK 0x00000000U + +#define ROGUE_CR_ISP_RENDER_DIR_TYPE_MASK 0x00000003U +/* Top-left to bottom-right */ +#define ROGUE_CR_ISP_RENDER_DIR_TYPE_TL2BR 0x00000000U +/* Top-right to bottom-left */ +#define ROGUE_CR_ISP_RENDER_DIR_TYPE_TR2BL 0x00000001U +/* Bottom-left to top-right */ +#define ROGUE_CR_ISP_RENDER_DIR_TYPE_BL2TR 0x00000002U +/* Bottom-right to top-left */ +#define ROGUE_CR_ISP_RENDER_DIR_TYPE_BR2TL 0x00000003U + +#define ROGUE_CR_ISP_RENDER_MODE_TYPE_MASK 0x00000003U +/* Normal render */ +#define ROGUE_CR_ISP_RENDER_MODE_TYPE_NORM 0x00000000U +/* Fast 2D render */ +#define ROGUE_CR_ISP_RENDER_MODE_TYPE_FAST_2D 0x00000002U +/* Fast scale render */ +#define ROGUE_CR_ISP_RENDER_MODE_TYPE_FAST_SCALE 0x00000003U + +/* Register ROGUE_CR_ISP_RENDER */ +#define ROGUE_CR_ISP_RENDER 0x0F08U +#define ROGUE_CR_ISP_RENDER_MASKFULL 0x00000000000001FFULL +#define ROGUE_CR_ISP_RENDER_FAST_RENDER_FORCE_PROTECT_SHIFT 8U +#define ROGUE_CR_ISP_RENDER_FAST_RENDER_FORCE_PROTECT_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_ISP_RENDER_FAST_RENDER_FORCE_PROTECT_EN 0x00000100U +#define ROGUE_CR_ISP_RENDER_PROCESS_PROTECTED_TILES_SHIFT 7U +#define ROGUE_CR_ISP_RENDER_PROCESS_PROTECTED_TILES_CLRMSK 0xFFFFFF7FU +#define ROGUE_CR_ISP_RENDER_PROCESS_PROTECTED_TILES_EN 0x00000080U +#define ROGUE_CR_ISP_RENDER_PROCESS_UNPROTECTED_TILES_SHIFT 6U +#define ROGUE_CR_ISP_RENDER_PROCESS_UNPROTECTED_TILES_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_ISP_RENDER_PROCESS_UNPROTECTED_TILES_EN 0x00000040U +#define ROGUE_CR_ISP_RENDER_DISABLE_EOMT_SHIFT 5U +#define ROGUE_CR_ISP_RENDER_DISABLE_EOMT_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_ISP_RENDER_DISABLE_EOMT_EN 0x00000020U +#define ROGUE_CR_ISP_RENDER_RESUME_SHIFT 4U +#define ROGUE_CR_ISP_RENDER_RESUME_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_ISP_RENDER_RESUME_EN 0x00000010U +#define ROGUE_CR_ISP_RENDER_DIR_SHIFT 2U +#define ROGUE_CR_ISP_RENDER_DIR_CLRMSK 0xFFFFFFF3U +#define ROGUE_CR_ISP_RENDER_DIR_TL2BR 0x00000000U +#define ROGUE_CR_ISP_RENDER_DIR_TR2BL 0x00000004U +#define ROGUE_CR_ISP_RENDER_DIR_BL2TR 0x00000008U +#define ROGUE_CR_ISP_RENDER_DIR_BR2TL 0x0000000CU +#define ROGUE_CR_ISP_RENDER_MODE_SHIFT 0U +#define ROGUE_CR_ISP_RENDER_MODE_CLRMSK 0xFFFFFFFCU +#define ROGUE_CR_ISP_RENDER_MODE_NORM 0x00000000U +#define ROGUE_CR_ISP_RENDER_MODE_FAST_2D 0x00000002U +#define ROGUE_CR_ISP_RENDER_MODE_FAST_SCALE 0x00000003U + +/* Register ROGUE_CR_ISP_CTL */ +#define ROGUE_CR_ISP_CTL 0x0F38U +#define ROGUE_CR_ISP_CTL_MASKFULL 0x00000000FFFFF3FFULL +#define ROGUE_CR_ISP_CTL_SKIP_INIT_HDRS_SHIFT 31U +#define ROGUE_CR_ISP_CTL_SKIP_INIT_HDRS_CLRMSK 0x7FFFFFFFU +#define ROGUE_CR_ISP_CTL_SKIP_INIT_HDRS_EN 0x80000000U +#define ROGUE_CR_ISP_CTL_LINE_STYLE_SHIFT 30U +#define ROGUE_CR_ISP_CTL_LINE_STYLE_CLRMSK 0xBFFFFFFFU +#define ROGUE_CR_ISP_CTL_LINE_STYLE_EN 0x40000000U +#define ROGUE_CR_ISP_CTL_LINE_STYLE_PIX_SHIFT 29U +#define ROGUE_CR_ISP_CTL_LINE_STYLE_PIX_CLRMSK 0xDFFFFFFFU +#define ROGUE_CR_ISP_CTL_LINE_STYLE_PIX_EN 0x20000000U +#define ROGUE_CR_ISP_CTL_PAIR_TILES_VERT_SHIFT 28U +#define ROGUE_CR_ISP_CTL_PAIR_TILES_VERT_CLRMSK 0xEFFFFFFFU +#define ROGUE_CR_ISP_CTL_PAIR_TILES_VERT_EN 0x10000000U +#define ROGUE_CR_ISP_CTL_PAIR_TILES_SHIFT 27U +#define ROGUE_CR_ISP_CTL_PAIR_TILES_CLRMSK 0xF7FFFFFFU +#define ROGUE_CR_ISP_CTL_PAIR_TILES_EN 0x08000000U +#define ROGUE_CR_ISP_CTL_CREQ_BUF_EN_SHIFT 26U +#define ROGUE_CR_ISP_CTL_CREQ_BUF_EN_CLRMSK 0xFBFFFFFFU +#define ROGUE_CR_ISP_CTL_CREQ_BUF_EN_EN 0x04000000U +#define ROGUE_CR_ISP_CTL_TILE_AGE_EN_SHIFT 25U +#define ROGUE_CR_ISP_CTL_TILE_AGE_EN_CLRMSK 0xFDFFFFFFU +#define ROGUE_CR_ISP_CTL_TILE_AGE_EN_EN 0x02000000U +#define ROGUE_CR_ISP_CTL_ISP_SAMPLE_POS_MODE_SHIFT 23U +#define ROGUE_CR_ISP_CTL_ISP_SAMPLE_POS_MODE_CLRMSK 0xFE7FFFFFU +#define ROGUE_CR_ISP_CTL_ISP_SAMPLE_POS_MODE_DX9 0x00000000U +#define ROGUE_CR_ISP_CTL_ISP_SAMPLE_POS_MODE_DX10 0x00800000U +#define ROGUE_CR_ISP_CTL_ISP_SAMPLE_POS_MODE_OGL 0x01000000U +#define ROGUE_CR_ISP_CTL_NUM_TILES_PER_USC_SHIFT 21U +#define ROGUE_CR_ISP_CTL_NUM_TILES_PER_USC_CLRMSK 0xFF9FFFFFU +#define ROGUE_CR_ISP_CTL_DBIAS_IS_INT_SHIFT 20U +#define ROGUE_CR_ISP_CTL_DBIAS_IS_INT_CLRMSK 0xFFEFFFFFU +#define ROGUE_CR_ISP_CTL_DBIAS_IS_INT_EN 0x00100000U +#define ROGUE_CR_ISP_CTL_OVERLAP_CHECK_MODE_SHIFT 19U +#define ROGUE_CR_ISP_CTL_OVERLAP_CHECK_MODE_CLRMSK 0xFFF7FFFFU +#define ROGUE_CR_ISP_CTL_OVERLAP_CHECK_MODE_EN 0x00080000U +#define ROGUE_CR_ISP_CTL_PT_UPFRONT_DEPTH_DISABLE_SHIFT 18U +#define ROGUE_CR_ISP_CTL_PT_UPFRONT_DEPTH_DISABLE_CLRMSK 0xFFFBFFFFU +#define ROGUE_CR_ISP_CTL_PT_UPFRONT_DEPTH_DISABLE_EN 0x00040000U +#define ROGUE_CR_ISP_CTL_PROCESS_EMPTY_TILES_SHIFT 17U +#define ROGUE_CR_ISP_CTL_PROCESS_EMPTY_TILES_CLRMSK 0xFFFDFFFFU +#define ROGUE_CR_ISP_CTL_PROCESS_EMPTY_TILES_EN 0x00020000U +#define ROGUE_CR_ISP_CTL_SAMPLE_POS_SHIFT 16U +#define ROGUE_CR_ISP_CTL_SAMPLE_POS_CLRMSK 0xFFFEFFFFU +#define ROGUE_CR_ISP_CTL_SAMPLE_POS_EN 0x00010000U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_SHIFT 12U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_CLRMSK 0xFFFF0FFFU +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_PIPE_ONE 0x00000000U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_PIPE_TWO 0x00001000U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_PIPE_THREE 0x00002000U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_PIPE_FOUR 0x00003000U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_PIPE_FIVE 0x00004000U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_PIPE_SIX 0x00005000U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_PIPE_SEVEN 0x00006000U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_PIPE_EIGHT 0x00007000U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_PIPE_NINE 0x00008000U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_PIPE_TEN 0x00009000U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_PIPE_ELEVEN 0x0000A000U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_PIPE_TWELVE 0x0000B000U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_PIPE_THIRTEEN 0x0000C000U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_PIPE_FOURTEEN 0x0000D000U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_PIPE_FIFTEEN 0x0000E000U +#define ROGUE_CR_ISP_CTL_PIPE_ENABLE_PIPE_SIXTEEN 0x0000F000U +#define ROGUE_CR_ISP_CTL_VALID_ID_SHIFT 4U +#define ROGUE_CR_ISP_CTL_VALID_ID_CLRMSK 0xFFFFFC0FU +#define ROGUE_CR_ISP_CTL_UPASS_START_SHIFT 0U +#define ROGUE_CR_ISP_CTL_UPASS_START_CLRMSK 0xFFFFFFF0U + +/* Register ROGUE_CR_ISP_STATUS */ +#define ROGUE_CR_ISP_STATUS 0x1038U +#define ROGUE_CR_ISP_STATUS_MASKFULL 0x0000000000000007ULL +#define ROGUE_CR_ISP_STATUS_SPLIT_MAX_SHIFT 2U +#define ROGUE_CR_ISP_STATUS_SPLIT_MAX_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_ISP_STATUS_SPLIT_MAX_EN 0x00000004U +#define ROGUE_CR_ISP_STATUS_ACTIVE_SHIFT 1U +#define ROGUE_CR_ISP_STATUS_ACTIVE_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_ISP_STATUS_ACTIVE_EN 0x00000002U +#define ROGUE_CR_ISP_STATUS_EOR_SHIFT 0U +#define ROGUE_CR_ISP_STATUS_EOR_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_ISP_STATUS_EOR_EN 0x00000001U + +/* Register group: ROGUE_CR_ISP_XTP_RESUME, with 64 repeats */ +#define ROGUE_CR_ISP_XTP_RESUME_REPEATCOUNT 64U +/* Register ROGUE_CR_ISP_XTP_RESUME0 */ +#define ROGUE_CR_ISP_XTP_RESUME0 0x3A00U +#define ROGUE_CR_ISP_XTP_RESUME0_MASKFULL 0x00000000003FF3FFULL +#define ROGUE_CR_ISP_XTP_RESUME0_TILE_X_SHIFT 12U +#define ROGUE_CR_ISP_XTP_RESUME0_TILE_X_CLRMSK 0xFFC00FFFU +#define ROGUE_CR_ISP_XTP_RESUME0_TILE_Y_SHIFT 0U +#define ROGUE_CR_ISP_XTP_RESUME0_TILE_Y_CLRMSK 0xFFFFFC00U + +/* Register group: ROGUE_CR_ISP_XTP_STORE, with 32 repeats */ +#define ROGUE_CR_ISP_XTP_STORE_REPEATCOUNT 32U +/* Register ROGUE_CR_ISP_XTP_STORE0 */ +#define ROGUE_CR_ISP_XTP_STORE0 0x3C00U +#define ROGUE_CR_ISP_XTP_STORE0_MASKFULL 0x000000007F3FF3FFULL +#define ROGUE_CR_ISP_XTP_STORE0_ACTIVE_SHIFT 30U +#define ROGUE_CR_ISP_XTP_STORE0_ACTIVE_CLRMSK 0xBFFFFFFFU +#define ROGUE_CR_ISP_XTP_STORE0_ACTIVE_EN 0x40000000U +#define ROGUE_CR_ISP_XTP_STORE0_EOR_SHIFT 29U +#define ROGUE_CR_ISP_XTP_STORE0_EOR_CLRMSK 0xDFFFFFFFU +#define ROGUE_CR_ISP_XTP_STORE0_EOR_EN 0x20000000U +#define ROGUE_CR_ISP_XTP_STORE0_TILE_LAST_SHIFT 28U +#define ROGUE_CR_ISP_XTP_STORE0_TILE_LAST_CLRMSK 0xEFFFFFFFU +#define ROGUE_CR_ISP_XTP_STORE0_TILE_LAST_EN 0x10000000U +#define ROGUE_CR_ISP_XTP_STORE0_MT_SHIFT 24U +#define ROGUE_CR_ISP_XTP_STORE0_MT_CLRMSK 0xF0FFFFFFU +#define ROGUE_CR_ISP_XTP_STORE0_TILE_X_SHIFT 12U +#define ROGUE_CR_ISP_XTP_STORE0_TILE_X_CLRMSK 0xFFC00FFFU +#define ROGUE_CR_ISP_XTP_STORE0_TILE_Y_SHIFT 0U +#define ROGUE_CR_ISP_XTP_STORE0_TILE_Y_CLRMSK 0xFFFFFC00U + +/* Register group: ROGUE_CR_BIF_CAT_BASE, with 8 repeats */ +#define ROGUE_CR_BIF_CAT_BASE_REPEATCOUNT 8U +/* Register ROGUE_CR_BIF_CAT_BASE0 */ +#define ROGUE_CR_BIF_CAT_BASE0 0x1200U +#define ROGUE_CR_BIF_CAT_BASE0_MASKFULL 0x000000FFFFFFF000ULL +#define ROGUE_CR_BIF_CAT_BASE0_ADDR_SHIFT 12U +#define ROGUE_CR_BIF_CAT_BASE0_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_BIF_CAT_BASE0_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_CAT_BASE0_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_BIF_CAT_BASE1 */ +#define ROGUE_CR_BIF_CAT_BASE1 0x1208U +#define ROGUE_CR_BIF_CAT_BASE1_MASKFULL 0x000000FFFFFFF000ULL +#define ROGUE_CR_BIF_CAT_BASE1_ADDR_SHIFT 12U +#define ROGUE_CR_BIF_CAT_BASE1_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_BIF_CAT_BASE1_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_CAT_BASE1_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_BIF_CAT_BASE2 */ +#define ROGUE_CR_BIF_CAT_BASE2 0x1210U +#define ROGUE_CR_BIF_CAT_BASE2_MASKFULL 0x000000FFFFFFF000ULL +#define ROGUE_CR_BIF_CAT_BASE2_ADDR_SHIFT 12U +#define ROGUE_CR_BIF_CAT_BASE2_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_BIF_CAT_BASE2_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_CAT_BASE2_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_BIF_CAT_BASE3 */ +#define ROGUE_CR_BIF_CAT_BASE3 0x1218U +#define ROGUE_CR_BIF_CAT_BASE3_MASKFULL 0x000000FFFFFFF000ULL +#define ROGUE_CR_BIF_CAT_BASE3_ADDR_SHIFT 12U +#define ROGUE_CR_BIF_CAT_BASE3_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_BIF_CAT_BASE3_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_CAT_BASE3_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_BIF_CAT_BASE4 */ +#define ROGUE_CR_BIF_CAT_BASE4 0x1220U +#define ROGUE_CR_BIF_CAT_BASE4_MASKFULL 0x000000FFFFFFF000ULL +#define ROGUE_CR_BIF_CAT_BASE4_ADDR_SHIFT 12U +#define ROGUE_CR_BIF_CAT_BASE4_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_BIF_CAT_BASE4_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_CAT_BASE4_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_BIF_CAT_BASE5 */ +#define ROGUE_CR_BIF_CAT_BASE5 0x1228U +#define ROGUE_CR_BIF_CAT_BASE5_MASKFULL 0x000000FFFFFFF000ULL +#define ROGUE_CR_BIF_CAT_BASE5_ADDR_SHIFT 12U +#define ROGUE_CR_BIF_CAT_BASE5_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_BIF_CAT_BASE5_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_CAT_BASE5_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_BIF_CAT_BASE6 */ +#define ROGUE_CR_BIF_CAT_BASE6 0x1230U +#define ROGUE_CR_BIF_CAT_BASE6_MASKFULL 0x000000FFFFFFF000ULL +#define ROGUE_CR_BIF_CAT_BASE6_ADDR_SHIFT 12U +#define ROGUE_CR_BIF_CAT_BASE6_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_BIF_CAT_BASE6_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_CAT_BASE6_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_BIF_CAT_BASE7 */ +#define ROGUE_CR_BIF_CAT_BASE7 0x1238U +#define ROGUE_CR_BIF_CAT_BASE7_MASKFULL 0x000000FFFFFFF000ULL +#define ROGUE_CR_BIF_CAT_BASE7_ADDR_SHIFT 12U +#define ROGUE_CR_BIF_CAT_BASE7_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_BIF_CAT_BASE7_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_CAT_BASE7_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_BIF_CAT_BASE_INDEX */ +#define ROGUE_CR_BIF_CAT_BASE_INDEX 0x1240U +#define ROGUE_CR_BIF_CAT_BASE_INDEX_MASKFULL 0x00070707073F0707ULL +#define ROGUE_CR_BIF_CAT_BASE_INDEX_RVTX_SHIFT 48U +#define ROGUE_CR_BIF_CAT_BASE_INDEX_RVTX_CLRMSK 0xFFF8FFFFFFFFFFFFULL +#define ROGUE_CR_BIF_CAT_BASE_INDEX_RAY_SHIFT 40U +#define ROGUE_CR_BIF_CAT_BASE_INDEX_RAY_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_BIF_CAT_BASE_INDEX_HOST_SHIFT 32U +#define ROGUE_CR_BIF_CAT_BASE_INDEX_HOST_CLRMSK 0xFFFFFFF8FFFFFFFFULL +#define ROGUE_CR_BIF_CAT_BASE_INDEX_TLA_SHIFT 24U +#define ROGUE_CR_BIF_CAT_BASE_INDEX_TLA_CLRMSK 0xFFFFFFFFF8FFFFFFULL +#define ROGUE_CR_BIF_CAT_BASE_INDEX_TDM_SHIFT 19U +#define ROGUE_CR_BIF_CAT_BASE_INDEX_TDM_CLRMSK 0xFFFFFFFFFFC7FFFFULL +#define ROGUE_CR_BIF_CAT_BASE_INDEX_CDM_SHIFT 16U +#define ROGUE_CR_BIF_CAT_BASE_INDEX_CDM_CLRMSK 0xFFFFFFFFFFF8FFFFULL +#define ROGUE_CR_BIF_CAT_BASE_INDEX_PIXEL_SHIFT 8U +#define ROGUE_CR_BIF_CAT_BASE_INDEX_PIXEL_CLRMSK 0xFFFFFFFFFFFFF8FFULL +#define ROGUE_CR_BIF_CAT_BASE_INDEX_TA_SHIFT 0U +#define ROGUE_CR_BIF_CAT_BASE_INDEX_TA_CLRMSK 0xFFFFFFFFFFFFFFF8ULL + +/* Register ROGUE_CR_BIF_PM_CAT_BASE_VCE0 */ +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE0 0x1248U +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE0_MASKFULL 0x0FFFFFFFFFFFF003ULL +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE0_INIT_PAGE_SHIFT 40U +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE0_INIT_PAGE_CLRMSK 0xF00000FFFFFFFFFFULL +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE0_ADDR_SHIFT 12U +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE0_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE0_WRAP_SHIFT 1U +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE0_WRAP_CLRMSK 0xFFFFFFFFFFFFFFFDULL +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE0_WRAP_EN 0x0000000000000002ULL +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE0_VALID_SHIFT 0U +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE0_VALID_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE0_VALID_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_BIF_PM_CAT_BASE_TE0 */ +#define ROGUE_CR_BIF_PM_CAT_BASE_TE0 0x1250U +#define ROGUE_CR_BIF_PM_CAT_BASE_TE0_MASKFULL 0x0FFFFFFFFFFFF003ULL +#define ROGUE_CR_BIF_PM_CAT_BASE_TE0_INIT_PAGE_SHIFT 40U +#define ROGUE_CR_BIF_PM_CAT_BASE_TE0_INIT_PAGE_CLRMSK 0xF00000FFFFFFFFFFULL +#define ROGUE_CR_BIF_PM_CAT_BASE_TE0_ADDR_SHIFT 12U +#define ROGUE_CR_BIF_PM_CAT_BASE_TE0_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_BIF_PM_CAT_BASE_TE0_WRAP_SHIFT 1U +#define ROGUE_CR_BIF_PM_CAT_BASE_TE0_WRAP_CLRMSK 0xFFFFFFFFFFFFFFFDULL +#define ROGUE_CR_BIF_PM_CAT_BASE_TE0_WRAP_EN 0x0000000000000002ULL +#define ROGUE_CR_BIF_PM_CAT_BASE_TE0_VALID_SHIFT 0U +#define ROGUE_CR_BIF_PM_CAT_BASE_TE0_VALID_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_BIF_PM_CAT_BASE_TE0_VALID_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_BIF_PM_CAT_BASE_ALIST0 */ +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST0 0x1260U +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST0_MASKFULL 0x0FFFFFFFFFFFF003ULL +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST0_INIT_PAGE_SHIFT 40U +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST0_INIT_PAGE_CLRMSK 0xF00000FFFFFFFFFFULL +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST0_ADDR_SHIFT 12U +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST0_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST0_WRAP_SHIFT 1U +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST0_WRAP_CLRMSK 0xFFFFFFFFFFFFFFFDULL +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST0_WRAP_EN 0x0000000000000002ULL +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST0_VALID_SHIFT 0U +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST0_VALID_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST0_VALID_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_BIF_PM_CAT_BASE_VCE1 */ +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE1 0x1268U +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE1_MASKFULL 0x0FFFFFFFFFFFF003ULL +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE1_INIT_PAGE_SHIFT 40U +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE1_INIT_PAGE_CLRMSK 0xF00000FFFFFFFFFFULL +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE1_ADDR_SHIFT 12U +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE1_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE1_WRAP_SHIFT 1U +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE1_WRAP_CLRMSK 0xFFFFFFFFFFFFFFFDULL +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE1_WRAP_EN 0x0000000000000002ULL +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE1_VALID_SHIFT 0U +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE1_VALID_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_BIF_PM_CAT_BASE_VCE1_VALID_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_BIF_PM_CAT_BASE_TE1 */ +#define ROGUE_CR_BIF_PM_CAT_BASE_TE1 0x1270U +#define ROGUE_CR_BIF_PM_CAT_BASE_TE1_MASKFULL 0x0FFFFFFFFFFFF003ULL +#define ROGUE_CR_BIF_PM_CAT_BASE_TE1_INIT_PAGE_SHIFT 40U +#define ROGUE_CR_BIF_PM_CAT_BASE_TE1_INIT_PAGE_CLRMSK 0xF00000FFFFFFFFFFULL +#define ROGUE_CR_BIF_PM_CAT_BASE_TE1_ADDR_SHIFT 12U +#define ROGUE_CR_BIF_PM_CAT_BASE_TE1_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_BIF_PM_CAT_BASE_TE1_WRAP_SHIFT 1U +#define ROGUE_CR_BIF_PM_CAT_BASE_TE1_WRAP_CLRMSK 0xFFFFFFFFFFFFFFFDULL +#define ROGUE_CR_BIF_PM_CAT_BASE_TE1_WRAP_EN 0x0000000000000002ULL +#define ROGUE_CR_BIF_PM_CAT_BASE_TE1_VALID_SHIFT 0U +#define ROGUE_CR_BIF_PM_CAT_BASE_TE1_VALID_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_BIF_PM_CAT_BASE_TE1_VALID_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_BIF_PM_CAT_BASE_ALIST1 */ +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST1 0x1280U +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST1_MASKFULL 0x0FFFFFFFFFFFF003ULL +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST1_INIT_PAGE_SHIFT 40U +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST1_INIT_PAGE_CLRMSK 0xF00000FFFFFFFFFFULL +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST1_ADDR_SHIFT 12U +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST1_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST1_WRAP_SHIFT 1U +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST1_WRAP_CLRMSK 0xFFFFFFFFFFFFFFFDULL +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST1_WRAP_EN 0x0000000000000002ULL +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST1_VALID_SHIFT 0U +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST1_VALID_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_BIF_PM_CAT_BASE_ALIST1_VALID_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_BIF_MMU_ENTRY_STATUS */ +#define ROGUE_CR_BIF_MMU_ENTRY_STATUS 0x1288U +#define ROGUE_CR_BIF_MMU_ENTRY_STATUS_MASKFULL 0x000000FFFFFFF0F3ULL +#define ROGUE_CR_BIF_MMU_ENTRY_STATUS_ADDRESS_SHIFT 12U +#define ROGUE_CR_BIF_MMU_ENTRY_STATUS_ADDRESS_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_BIF_MMU_ENTRY_STATUS_CAT_BASE_SHIFT 4U +#define ROGUE_CR_BIF_MMU_ENTRY_STATUS_CAT_BASE_CLRMSK 0xFFFFFFFFFFFFFF0FULL +#define ROGUE_CR_BIF_MMU_ENTRY_STATUS_DATA_TYPE_SHIFT 0U +#define ROGUE_CR_BIF_MMU_ENTRY_STATUS_DATA_TYPE_CLRMSK 0xFFFFFFFFFFFFFFFCULL + +/* Register ROGUE_CR_BIF_MMU_ENTRY */ +#define ROGUE_CR_BIF_MMU_ENTRY 0x1290U +#define ROGUE_CR_BIF_MMU_ENTRY_MASKFULL 0x0000000000000003ULL +#define ROGUE_CR_BIF_MMU_ENTRY_ENABLE_SHIFT 1U +#define ROGUE_CR_BIF_MMU_ENTRY_ENABLE_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_BIF_MMU_ENTRY_ENABLE_EN 0x00000002U +#define ROGUE_CR_BIF_MMU_ENTRY_PENDING_SHIFT 0U +#define ROGUE_CR_BIF_MMU_ENTRY_PENDING_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_BIF_MMU_ENTRY_PENDING_EN 0x00000001U + +/* Register ROGUE_CR_BIF_CTRL_INVAL */ +#define ROGUE_CR_BIF_CTRL_INVAL 0x12A0U +#define ROGUE_CR_BIF_CTRL_INVAL_MASKFULL 0x000000000000000FULL +#define ROGUE_CR_BIF_CTRL_INVAL_TLB1_SHIFT 3U +#define ROGUE_CR_BIF_CTRL_INVAL_TLB1_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_BIF_CTRL_INVAL_TLB1_EN 0x00000008U +#define ROGUE_CR_BIF_CTRL_INVAL_PC_SHIFT 2U +#define ROGUE_CR_BIF_CTRL_INVAL_PC_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_BIF_CTRL_INVAL_PC_EN 0x00000004U +#define ROGUE_CR_BIF_CTRL_INVAL_PD_SHIFT 1U +#define ROGUE_CR_BIF_CTRL_INVAL_PD_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_BIF_CTRL_INVAL_PD_EN 0x00000002U +#define ROGUE_CR_BIF_CTRL_INVAL_PT_SHIFT 0U +#define ROGUE_CR_BIF_CTRL_INVAL_PT_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_BIF_CTRL_INVAL_PT_EN 0x00000001U + +/* Register ROGUE_CR_BIF_CTRL */ +#define ROGUE_CR_BIF_CTRL 0x12A8U +#define ROGUE_CR_BIF_CTRL__XE_MEM__MASKFULL 0x000000000000033FULL +#define ROGUE_CR_BIF_CTRL_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_CPU_SHIFT 9U +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_CPU_CLRMSK 0xFFFFFDFFU +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_CPU_EN 0x00000200U +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_BIF4_SHIFT 8U +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_BIF4_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_BIF4_EN 0x00000100U +#define ROGUE_CR_BIF_CTRL_ENABLE_MMU_QUEUE_BYPASS_SHIFT 7U +#define ROGUE_CR_BIF_CTRL_ENABLE_MMU_QUEUE_BYPASS_CLRMSK 0xFFFFFF7FU +#define ROGUE_CR_BIF_CTRL_ENABLE_MMU_QUEUE_BYPASS_EN 0x00000080U +#define ROGUE_CR_BIF_CTRL_ENABLE_MMU_AUTO_PREFETCH_SHIFT 6U +#define ROGUE_CR_BIF_CTRL_ENABLE_MMU_AUTO_PREFETCH_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_BIF_CTRL_ENABLE_MMU_AUTO_PREFETCH_EN 0x00000040U +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_BIF3_SHIFT 5U +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_BIF3_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_BIF3_EN 0x00000020U +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_BIF2_SHIFT 4U +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_BIF2_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_BIF2_EN 0x00000010U +#define ROGUE_CR_BIF_CTRL_PAUSE_BIF1_SHIFT 3U +#define ROGUE_CR_BIF_CTRL_PAUSE_BIF1_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_BIF_CTRL_PAUSE_BIF1_EN 0x00000008U +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_PM_SHIFT 2U +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_PM_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_PM_EN 0x00000004U +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_BIF1_SHIFT 1U +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_BIF1_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_BIF1_EN 0x00000002U +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_BIF0_SHIFT 0U +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_BIF0_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_BIF_CTRL_PAUSE_MMU_BIF0_EN 0x00000001U + +/* Register ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS */ +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS 0x12B0U +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS_MASKFULL 0x000000000000F775ULL +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS_CAT_BASE_SHIFT 12U +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS_CAT_BASE_CLRMSK 0xFFFF0FFFU +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS_PAGE_SIZE_SHIFT 8U +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS_PAGE_SIZE_CLRMSK 0xFFFFF8FFU +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS_DATA_TYPE_SHIFT 5U +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS_DATA_TYPE_CLRMSK 0xFFFFFF9FU +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS_FAULT_RO_SHIFT 4U +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS_FAULT_RO_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS_FAULT_RO_EN 0x00000010U +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS_FAULT_PM_META_RO_SHIFT 2U +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS_FAULT_PM_META_RO_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS_FAULT_PM_META_RO_EN 0x00000004U +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS_FAULT_SHIFT 0U +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS_FAULT_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_BIF_FAULT_BANK0_MMU_STATUS_FAULT_EN 0x00000001U + +/* Register ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS */ +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS 0x12B8U +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS__XE_MEM__MASKFULL 0x001FFFFFFFFFFFF0ULL +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS_MASKFULL 0x0007FFFFFFFFFFF0ULL +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS__XE_MEM__RNW_SHIFT 52U +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS__XE_MEM__RNW_CLRMSK 0xFFEFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS__XE_MEM__RNW_EN 0x0010000000000000ULL +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS_RNW_SHIFT 50U +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS_RNW_CLRMSK 0xFFFBFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS_RNW_EN 0x0004000000000000ULL +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS__XE_MEM__TAG_SB_SHIFT 46U +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS__XE_MEM__TAG_SB_CLRMSK 0xFFF03FFFFFFFFFFFULL +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS_TAG_SB_SHIFT 44U +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS_TAG_SB_CLRMSK 0xFFFC0FFFFFFFFFFFULL +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS_TAG_ID_SHIFT 40U +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS_TAG_ID_CLRMSK 0xFFFFF0FFFFFFFFFFULL +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS__XE_MEM__TAG_ID_SHIFT 40U +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS__XE_MEM__TAG_ID_CLRMSK 0xFFFFC0FFFFFFFFFFULL +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS_ADDRESS_SHIFT 4U +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS_ADDRESS_CLRMSK 0xFFFFFF000000000FULL +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS_ADDRESS_ALIGNSHIFT 4U +#define ROGUE_CR_BIF_FAULT_BANK0_REQ_STATUS_ADDRESS_ALIGNSIZE 16U + +/* Register ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS */ +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS 0x12C0U +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS_MASKFULL 0x000000000000F775ULL +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS_CAT_BASE_SHIFT 12U +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS_CAT_BASE_CLRMSK 0xFFFF0FFFU +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS_PAGE_SIZE_SHIFT 8U +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS_PAGE_SIZE_CLRMSK 0xFFFFF8FFU +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS_DATA_TYPE_SHIFT 5U +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS_DATA_TYPE_CLRMSK 0xFFFFFF9FU +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS_FAULT_RO_SHIFT 4U +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS_FAULT_RO_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS_FAULT_RO_EN 0x00000010U +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS_FAULT_PM_META_RO_SHIFT 2U +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS_FAULT_PM_META_RO_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS_FAULT_PM_META_RO_EN 0x00000004U +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS_FAULT_SHIFT 0U +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS_FAULT_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_BIF_FAULT_BANK1_MMU_STATUS_FAULT_EN 0x00000001U + +/* Register ROGUE_CR_BIF_FAULT_BANK1_REQ_STATUS */ +#define ROGUE_CR_BIF_FAULT_BANK1_REQ_STATUS 0x12C8U +#define ROGUE_CR_BIF_FAULT_BANK1_REQ_STATUS_MASKFULL 0x0007FFFFFFFFFFF0ULL +#define ROGUE_CR_BIF_FAULT_BANK1_REQ_STATUS_RNW_SHIFT 50U +#define ROGUE_CR_BIF_FAULT_BANK1_REQ_STATUS_RNW_CLRMSK 0xFFFBFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_FAULT_BANK1_REQ_STATUS_RNW_EN 0x0004000000000000ULL +#define ROGUE_CR_BIF_FAULT_BANK1_REQ_STATUS_TAG_SB_SHIFT 44U +#define ROGUE_CR_BIF_FAULT_BANK1_REQ_STATUS_TAG_SB_CLRMSK 0xFFFC0FFFFFFFFFFFULL +#define ROGUE_CR_BIF_FAULT_BANK1_REQ_STATUS_TAG_ID_SHIFT 40U +#define ROGUE_CR_BIF_FAULT_BANK1_REQ_STATUS_TAG_ID_CLRMSK 0xFFFFF0FFFFFFFFFFULL +#define ROGUE_CR_BIF_FAULT_BANK1_REQ_STATUS_ADDRESS_SHIFT 4U +#define ROGUE_CR_BIF_FAULT_BANK1_REQ_STATUS_ADDRESS_CLRMSK 0xFFFFFF000000000FULL +#define ROGUE_CR_BIF_FAULT_BANK1_REQ_STATUS_ADDRESS_ALIGNSHIFT 4U +#define ROGUE_CR_BIF_FAULT_BANK1_REQ_STATUS_ADDRESS_ALIGNSIZE 16U + +/* Register ROGUE_CR_BIF_MMU_STATUS */ +#define ROGUE_CR_BIF_MMU_STATUS 0x12D0U +#define ROGUE_CR_BIF_MMU_STATUS__XE_MEM__MASKFULL 0x000000001FFFFFF7ULL +#define ROGUE_CR_BIF_MMU_STATUS_MASKFULL 0x000000001FFFFFF7ULL +#define ROGUE_CR_BIF_MMU_STATUS_PM_FAULT_SHIFT 28U +#define ROGUE_CR_BIF_MMU_STATUS_PM_FAULT_CLRMSK 0xEFFFFFFFU +#define ROGUE_CR_BIF_MMU_STATUS_PM_FAULT_EN 0x10000000U +#define ROGUE_CR_BIF_MMU_STATUS_PC_DATA_SHIFT 20U +#define ROGUE_CR_BIF_MMU_STATUS_PC_DATA_CLRMSK 0xF00FFFFFU +#define ROGUE_CR_BIF_MMU_STATUS_PD_DATA_SHIFT 12U +#define ROGUE_CR_BIF_MMU_STATUS_PD_DATA_CLRMSK 0xFFF00FFFU +#define ROGUE_CR_BIF_MMU_STATUS_PT_DATA_SHIFT 4U +#define ROGUE_CR_BIF_MMU_STATUS_PT_DATA_CLRMSK 0xFFFFF00FU +#define ROGUE_CR_BIF_MMU_STATUS_STALLED_SHIFT 2U +#define ROGUE_CR_BIF_MMU_STATUS_STALLED_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_BIF_MMU_STATUS_STALLED_EN 0x00000004U +#define ROGUE_CR_BIF_MMU_STATUS_PAUSED_SHIFT 1U +#define ROGUE_CR_BIF_MMU_STATUS_PAUSED_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_BIF_MMU_STATUS_PAUSED_EN 0x00000002U +#define ROGUE_CR_BIF_MMU_STATUS_BUSY_SHIFT 0U +#define ROGUE_CR_BIF_MMU_STATUS_BUSY_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_BIF_MMU_STATUS_BUSY_EN 0x00000001U + +/* Register group: ROGUE_CR_BIF_TILING_CFG, with 8 repeats */ +#define ROGUE_CR_BIF_TILING_CFG_REPEATCOUNT 8U +/* Register ROGUE_CR_BIF_TILING_CFG0 */ +#define ROGUE_CR_BIF_TILING_CFG0 0x12D8U +#define ROGUE_CR_BIF_TILING_CFG0_MASKFULL 0xFFFFFFFF0FFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG0_XSTRIDE_SHIFT 61U +#define ROGUE_CR_BIF_TILING_CFG0_XSTRIDE_CLRMSK 0x1FFFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG0_ENABLE_SHIFT 60U +#define ROGUE_CR_BIF_TILING_CFG0_ENABLE_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG0_ENABLE_EN 0x1000000000000000ULL +#define ROGUE_CR_BIF_TILING_CFG0_MAX_ADDRESS_SHIFT 32U +#define ROGUE_CR_BIF_TILING_CFG0_MAX_ADDRESS_CLRMSK 0xF0000000FFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG0_MAX_ADDRESS_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_TILING_CFG0_MAX_ADDRESS_ALIGNSIZE 4096U +#define ROGUE_CR_BIF_TILING_CFG0_MIN_ADDRESS_SHIFT 0U +#define ROGUE_CR_BIF_TILING_CFG0_MIN_ADDRESS_CLRMSK 0xFFFFFFFFF0000000ULL +#define ROGUE_CR_BIF_TILING_CFG0_MIN_ADDRESS_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_TILING_CFG0_MIN_ADDRESS_ALIGNSIZE 4096U + +/* Register ROGUE_CR_BIF_TILING_CFG1 */ +#define ROGUE_CR_BIF_TILING_CFG1 0x12E0U +#define ROGUE_CR_BIF_TILING_CFG1_MASKFULL 0xFFFFFFFF0FFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG1_XSTRIDE_SHIFT 61U +#define ROGUE_CR_BIF_TILING_CFG1_XSTRIDE_CLRMSK 0x1FFFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG1_ENABLE_SHIFT 60U +#define ROGUE_CR_BIF_TILING_CFG1_ENABLE_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG1_ENABLE_EN 0x1000000000000000ULL +#define ROGUE_CR_BIF_TILING_CFG1_MAX_ADDRESS_SHIFT 32U +#define ROGUE_CR_BIF_TILING_CFG1_MAX_ADDRESS_CLRMSK 0xF0000000FFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG1_MAX_ADDRESS_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_TILING_CFG1_MAX_ADDRESS_ALIGNSIZE 4096U +#define ROGUE_CR_BIF_TILING_CFG1_MIN_ADDRESS_SHIFT 0U +#define ROGUE_CR_BIF_TILING_CFG1_MIN_ADDRESS_CLRMSK 0xFFFFFFFFF0000000ULL +#define ROGUE_CR_BIF_TILING_CFG1_MIN_ADDRESS_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_TILING_CFG1_MIN_ADDRESS_ALIGNSIZE 4096U + +/* Register ROGUE_CR_BIF_TILING_CFG2 */ +#define ROGUE_CR_BIF_TILING_CFG2 0x12E8U +#define ROGUE_CR_BIF_TILING_CFG2_MASKFULL 0xFFFFFFFF0FFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG2_XSTRIDE_SHIFT 61U +#define ROGUE_CR_BIF_TILING_CFG2_XSTRIDE_CLRMSK 0x1FFFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG2_ENABLE_SHIFT 60U +#define ROGUE_CR_BIF_TILING_CFG2_ENABLE_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG2_ENABLE_EN 0x1000000000000000ULL +#define ROGUE_CR_BIF_TILING_CFG2_MAX_ADDRESS_SHIFT 32U +#define ROGUE_CR_BIF_TILING_CFG2_MAX_ADDRESS_CLRMSK 0xF0000000FFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG2_MAX_ADDRESS_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_TILING_CFG2_MAX_ADDRESS_ALIGNSIZE 4096U +#define ROGUE_CR_BIF_TILING_CFG2_MIN_ADDRESS_SHIFT 0U +#define ROGUE_CR_BIF_TILING_CFG2_MIN_ADDRESS_CLRMSK 0xFFFFFFFFF0000000ULL +#define ROGUE_CR_BIF_TILING_CFG2_MIN_ADDRESS_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_TILING_CFG2_MIN_ADDRESS_ALIGNSIZE 4096U + +/* Register ROGUE_CR_BIF_TILING_CFG3 */ +#define ROGUE_CR_BIF_TILING_CFG3 0x12F0U +#define ROGUE_CR_BIF_TILING_CFG3_MASKFULL 0xFFFFFFFF0FFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG3_XSTRIDE_SHIFT 61U +#define ROGUE_CR_BIF_TILING_CFG3_XSTRIDE_CLRMSK 0x1FFFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG3_ENABLE_SHIFT 60U +#define ROGUE_CR_BIF_TILING_CFG3_ENABLE_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG3_ENABLE_EN 0x1000000000000000ULL +#define ROGUE_CR_BIF_TILING_CFG3_MAX_ADDRESS_SHIFT 32U +#define ROGUE_CR_BIF_TILING_CFG3_MAX_ADDRESS_CLRMSK 0xF0000000FFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG3_MAX_ADDRESS_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_TILING_CFG3_MAX_ADDRESS_ALIGNSIZE 4096U +#define ROGUE_CR_BIF_TILING_CFG3_MIN_ADDRESS_SHIFT 0U +#define ROGUE_CR_BIF_TILING_CFG3_MIN_ADDRESS_CLRMSK 0xFFFFFFFFF0000000ULL +#define ROGUE_CR_BIF_TILING_CFG3_MIN_ADDRESS_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_TILING_CFG3_MIN_ADDRESS_ALIGNSIZE 4096U + +/* Register ROGUE_CR_BIF_TILING_CFG4 */ +#define ROGUE_CR_BIF_TILING_CFG4 0x12F8U +#define ROGUE_CR_BIF_TILING_CFG4_MASKFULL 0xFFFFFFFF0FFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG4_XSTRIDE_SHIFT 61U +#define ROGUE_CR_BIF_TILING_CFG4_XSTRIDE_CLRMSK 0x1FFFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG4_ENABLE_SHIFT 60U +#define ROGUE_CR_BIF_TILING_CFG4_ENABLE_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG4_ENABLE_EN 0x1000000000000000ULL +#define ROGUE_CR_BIF_TILING_CFG4_MAX_ADDRESS_SHIFT 32U +#define ROGUE_CR_BIF_TILING_CFG4_MAX_ADDRESS_CLRMSK 0xF0000000FFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG4_MAX_ADDRESS_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_TILING_CFG4_MAX_ADDRESS_ALIGNSIZE 4096U +#define ROGUE_CR_BIF_TILING_CFG4_MIN_ADDRESS_SHIFT 0U +#define ROGUE_CR_BIF_TILING_CFG4_MIN_ADDRESS_CLRMSK 0xFFFFFFFFF0000000ULL +#define ROGUE_CR_BIF_TILING_CFG4_MIN_ADDRESS_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_TILING_CFG4_MIN_ADDRESS_ALIGNSIZE 4096U + +/* Register ROGUE_CR_BIF_TILING_CFG5 */ +#define ROGUE_CR_BIF_TILING_CFG5 0x1300U +#define ROGUE_CR_BIF_TILING_CFG5_MASKFULL 0xFFFFFFFF0FFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG5_XSTRIDE_SHIFT 61U +#define ROGUE_CR_BIF_TILING_CFG5_XSTRIDE_CLRMSK 0x1FFFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG5_ENABLE_SHIFT 60U +#define ROGUE_CR_BIF_TILING_CFG5_ENABLE_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG5_ENABLE_EN 0x1000000000000000ULL +#define ROGUE_CR_BIF_TILING_CFG5_MAX_ADDRESS_SHIFT 32U +#define ROGUE_CR_BIF_TILING_CFG5_MAX_ADDRESS_CLRMSK 0xF0000000FFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG5_MAX_ADDRESS_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_TILING_CFG5_MAX_ADDRESS_ALIGNSIZE 4096U +#define ROGUE_CR_BIF_TILING_CFG5_MIN_ADDRESS_SHIFT 0U +#define ROGUE_CR_BIF_TILING_CFG5_MIN_ADDRESS_CLRMSK 0xFFFFFFFFF0000000ULL +#define ROGUE_CR_BIF_TILING_CFG5_MIN_ADDRESS_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_TILING_CFG5_MIN_ADDRESS_ALIGNSIZE 4096U + +/* Register ROGUE_CR_BIF_TILING_CFG6 */ +#define ROGUE_CR_BIF_TILING_CFG6 0x1308U +#define ROGUE_CR_BIF_TILING_CFG6_MASKFULL 0xFFFFFFFF0FFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG6_XSTRIDE_SHIFT 61U +#define ROGUE_CR_BIF_TILING_CFG6_XSTRIDE_CLRMSK 0x1FFFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG6_ENABLE_SHIFT 60U +#define ROGUE_CR_BIF_TILING_CFG6_ENABLE_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG6_ENABLE_EN 0x1000000000000000ULL +#define ROGUE_CR_BIF_TILING_CFG6_MAX_ADDRESS_SHIFT 32U +#define ROGUE_CR_BIF_TILING_CFG6_MAX_ADDRESS_CLRMSK 0xF0000000FFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG6_MAX_ADDRESS_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_TILING_CFG6_MAX_ADDRESS_ALIGNSIZE 4096U +#define ROGUE_CR_BIF_TILING_CFG6_MIN_ADDRESS_SHIFT 0U +#define ROGUE_CR_BIF_TILING_CFG6_MIN_ADDRESS_CLRMSK 0xFFFFFFFFF0000000ULL +#define ROGUE_CR_BIF_TILING_CFG6_MIN_ADDRESS_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_TILING_CFG6_MIN_ADDRESS_ALIGNSIZE 4096U + +/* Register ROGUE_CR_BIF_TILING_CFG7 */ +#define ROGUE_CR_BIF_TILING_CFG7 0x1310U +#define ROGUE_CR_BIF_TILING_CFG7_MASKFULL 0xFFFFFFFF0FFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG7_XSTRIDE_SHIFT 61U +#define ROGUE_CR_BIF_TILING_CFG7_XSTRIDE_CLRMSK 0x1FFFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG7_ENABLE_SHIFT 60U +#define ROGUE_CR_BIF_TILING_CFG7_ENABLE_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG7_ENABLE_EN 0x1000000000000000ULL +#define ROGUE_CR_BIF_TILING_CFG7_MAX_ADDRESS_SHIFT 32U +#define ROGUE_CR_BIF_TILING_CFG7_MAX_ADDRESS_CLRMSK 0xF0000000FFFFFFFFULL +#define ROGUE_CR_BIF_TILING_CFG7_MAX_ADDRESS_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_TILING_CFG7_MAX_ADDRESS_ALIGNSIZE 4096U +#define ROGUE_CR_BIF_TILING_CFG7_MIN_ADDRESS_SHIFT 0U +#define ROGUE_CR_BIF_TILING_CFG7_MIN_ADDRESS_CLRMSK 0xFFFFFFFFF0000000ULL +#define ROGUE_CR_BIF_TILING_CFG7_MIN_ADDRESS_ALIGNSHIFT 12U +#define ROGUE_CR_BIF_TILING_CFG7_MIN_ADDRESS_ALIGNSIZE 4096U + +/* Register ROGUE_CR_BIF_READS_EXT_STATUS */ +#define ROGUE_CR_BIF_READS_EXT_STATUS 0x1320U +#define ROGUE_CR_BIF_READS_EXT_STATUS_MASKFULL 0x000000000FFFFFFFULL +#define ROGUE_CR_BIF_READS_EXT_STATUS_MMU_SHIFT 16U +#define ROGUE_CR_BIF_READS_EXT_STATUS_MMU_CLRMSK 0xF000FFFFU +#define ROGUE_CR_BIF_READS_EXT_STATUS_BANK1_SHIFT 0U +#define ROGUE_CR_BIF_READS_EXT_STATUS_BANK1_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_BIF_READS_INT_STATUS */ +#define ROGUE_CR_BIF_READS_INT_STATUS 0x1328U +#define ROGUE_CR_BIF_READS_INT_STATUS_MASKFULL 0x0000000007FFFFFFULL +#define ROGUE_CR_BIF_READS_INT_STATUS_MMU_SHIFT 16U +#define ROGUE_CR_BIF_READS_INT_STATUS_MMU_CLRMSK 0xF800FFFFU +#define ROGUE_CR_BIF_READS_INT_STATUS_BANK1_SHIFT 0U +#define ROGUE_CR_BIF_READS_INT_STATUS_BANK1_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_BIFPM_READS_INT_STATUS */ +#define ROGUE_CR_BIFPM_READS_INT_STATUS 0x1330U +#define ROGUE_CR_BIFPM_READS_INT_STATUS_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_BIFPM_READS_INT_STATUS_BANK0_SHIFT 0U +#define ROGUE_CR_BIFPM_READS_INT_STATUS_BANK0_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_BIFPM_READS_EXT_STATUS */ +#define ROGUE_CR_BIFPM_READS_EXT_STATUS 0x1338U +#define ROGUE_CR_BIFPM_READS_EXT_STATUS_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_BIFPM_READS_EXT_STATUS_BANK0_SHIFT 0U +#define ROGUE_CR_BIFPM_READS_EXT_STATUS_BANK0_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_BIFPM_STATUS_MMU */ +#define ROGUE_CR_BIFPM_STATUS_MMU 0x1350U +#define ROGUE_CR_BIFPM_STATUS_MMU_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_BIFPM_STATUS_MMU_REQUESTS_SHIFT 0U +#define ROGUE_CR_BIFPM_STATUS_MMU_REQUESTS_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_BIF_STATUS_MMU */ +#define ROGUE_CR_BIF_STATUS_MMU 0x1358U +#define ROGUE_CR_BIF_STATUS_MMU_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_BIF_STATUS_MMU_REQUESTS_SHIFT 0U +#define ROGUE_CR_BIF_STATUS_MMU_REQUESTS_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_BIF_FAULT_READ */ +#define ROGUE_CR_BIF_FAULT_READ 0x13E0U +#define ROGUE_CR_BIF_FAULT_READ_MASKFULL 0x000000FFFFFFFFF0ULL +#define ROGUE_CR_BIF_FAULT_READ_ADDRESS_SHIFT 4U +#define ROGUE_CR_BIF_FAULT_READ_ADDRESS_CLRMSK 0xFFFFFF000000000FULL +#define ROGUE_CR_BIF_FAULT_READ_ADDRESS_ALIGNSHIFT 4U +#define ROGUE_CR_BIF_FAULT_READ_ADDRESS_ALIGNSIZE 16U + +/* Register ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS */ +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS 0x1430U +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS_MASKFULL 0x000000000000F775ULL +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS_CAT_BASE_SHIFT 12U +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS_CAT_BASE_CLRMSK 0xFFFF0FFFU +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS_PAGE_SIZE_SHIFT 8U +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS_PAGE_SIZE_CLRMSK 0xFFFFF8FFU +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS_DATA_TYPE_SHIFT 5U +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS_DATA_TYPE_CLRMSK 0xFFFFFF9FU +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS_FAULT_RO_SHIFT 4U +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS_FAULT_RO_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS_FAULT_RO_EN 0x00000010U +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS_FAULT_PM_META_RO_SHIFT 2U +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS_FAULT_PM_META_RO_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS_FAULT_PM_META_RO_EN 0x00000004U +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS_FAULT_SHIFT 0U +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS_FAULT_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_MMU_STATUS_FAULT_EN 0x00000001U + +/* Register ROGUE_CR_TEXAS_BIF_FAULT_BANK0_REQ_STATUS */ +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_REQ_STATUS 0x1438U +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_REQ_STATUS_MASKFULL 0x0007FFFFFFFFFFF0ULL +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_REQ_STATUS_RNW_SHIFT 50U +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_REQ_STATUS_RNW_CLRMSK 0xFFFBFFFFFFFFFFFFULL +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_REQ_STATUS_RNW_EN 0x0004000000000000ULL +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_REQ_STATUS_TAG_SB_SHIFT 44U +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_REQ_STATUS_TAG_SB_CLRMSK 0xFFFC0FFFFFFFFFFFULL +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_REQ_STATUS_TAG_ID_SHIFT 40U +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_REQ_STATUS_TAG_ID_CLRMSK 0xFFFFF0FFFFFFFFFFULL +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_REQ_STATUS_ADDRESS_SHIFT 4U +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_REQ_STATUS_ADDRESS_CLRMSK 0xFFFFFF000000000FULL +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_REQ_STATUS_ADDRESS_ALIGNSHIFT 4U +#define ROGUE_CR_TEXAS_BIF_FAULT_BANK0_REQ_STATUS_ADDRESS_ALIGNSIZE 16U + +/* Register ROGUE_CR_MCU_FENCE */ +#define ROGUE_CR_MCU_FENCE 0x1740U +#define ROGUE_CR_MCU_FENCE_MASKFULL 0x000007FFFFFFFFE0ULL +#define ROGUE_CR_MCU_FENCE_DM_SHIFT 40U +#define ROGUE_CR_MCU_FENCE_DM_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_MCU_FENCE_DM_VERTEX 0x0000000000000000ULL +#define ROGUE_CR_MCU_FENCE_DM_PIXEL 0x0000010000000000ULL +#define ROGUE_CR_MCU_FENCE_DM_COMPUTE 0x0000020000000000ULL +#define ROGUE_CR_MCU_FENCE_DM_RAY_VERTEX 0x0000030000000000ULL +#define ROGUE_CR_MCU_FENCE_DM_RAY 0x0000040000000000ULL +#define ROGUE_CR_MCU_FENCE_DM_FASTRENDER 0x0000050000000000ULL +#define ROGUE_CR_MCU_FENCE_ADDR_SHIFT 5U +#define ROGUE_CR_MCU_FENCE_ADDR_CLRMSK 0xFFFFFF000000001FULL +#define ROGUE_CR_MCU_FENCE_ADDR_ALIGNSHIFT 5U +#define ROGUE_CR_MCU_FENCE_ADDR_ALIGNSIZE 32U + +/* Register group: ROGUE_CR_SCRATCH, with 16 repeats */ +#define ROGUE_CR_SCRATCH_REPEATCOUNT 16U +/* Register ROGUE_CR_SCRATCH0 */ +#define ROGUE_CR_SCRATCH0 0x1A00U +#define ROGUE_CR_SCRATCH0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SCRATCH0_DATA_SHIFT 0U +#define ROGUE_CR_SCRATCH0_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SCRATCH1 */ +#define ROGUE_CR_SCRATCH1 0x1A08U +#define ROGUE_CR_SCRATCH1_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SCRATCH1_DATA_SHIFT 0U +#define ROGUE_CR_SCRATCH1_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SCRATCH2 */ +#define ROGUE_CR_SCRATCH2 0x1A10U +#define ROGUE_CR_SCRATCH2_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SCRATCH2_DATA_SHIFT 0U +#define ROGUE_CR_SCRATCH2_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SCRATCH3 */ +#define ROGUE_CR_SCRATCH3 0x1A18U +#define ROGUE_CR_SCRATCH3_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SCRATCH3_DATA_SHIFT 0U +#define ROGUE_CR_SCRATCH3_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SCRATCH4 */ +#define ROGUE_CR_SCRATCH4 0x1A20U +#define ROGUE_CR_SCRATCH4_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SCRATCH4_DATA_SHIFT 0U +#define ROGUE_CR_SCRATCH4_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SCRATCH5 */ +#define ROGUE_CR_SCRATCH5 0x1A28U +#define ROGUE_CR_SCRATCH5_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SCRATCH5_DATA_SHIFT 0U +#define ROGUE_CR_SCRATCH5_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SCRATCH6 */ +#define ROGUE_CR_SCRATCH6 0x1A30U +#define ROGUE_CR_SCRATCH6_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SCRATCH6_DATA_SHIFT 0U +#define ROGUE_CR_SCRATCH6_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SCRATCH7 */ +#define ROGUE_CR_SCRATCH7 0x1A38U +#define ROGUE_CR_SCRATCH7_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SCRATCH7_DATA_SHIFT 0U +#define ROGUE_CR_SCRATCH7_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SCRATCH8 */ +#define ROGUE_CR_SCRATCH8 0x1A40U +#define ROGUE_CR_SCRATCH8_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SCRATCH8_DATA_SHIFT 0U +#define ROGUE_CR_SCRATCH8_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SCRATCH9 */ +#define ROGUE_CR_SCRATCH9 0x1A48U +#define ROGUE_CR_SCRATCH9_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SCRATCH9_DATA_SHIFT 0U +#define ROGUE_CR_SCRATCH9_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SCRATCH10 */ +#define ROGUE_CR_SCRATCH10 0x1A50U +#define ROGUE_CR_SCRATCH10_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SCRATCH10_DATA_SHIFT 0U +#define ROGUE_CR_SCRATCH10_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SCRATCH11 */ +#define ROGUE_CR_SCRATCH11 0x1A58U +#define ROGUE_CR_SCRATCH11_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SCRATCH11_DATA_SHIFT 0U +#define ROGUE_CR_SCRATCH11_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SCRATCH12 */ +#define ROGUE_CR_SCRATCH12 0x1A60U +#define ROGUE_CR_SCRATCH12_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SCRATCH12_DATA_SHIFT 0U +#define ROGUE_CR_SCRATCH12_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SCRATCH13 */ +#define ROGUE_CR_SCRATCH13 0x1A68U +#define ROGUE_CR_SCRATCH13_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SCRATCH13_DATA_SHIFT 0U +#define ROGUE_CR_SCRATCH13_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SCRATCH14 */ +#define ROGUE_CR_SCRATCH14 0x1A70U +#define ROGUE_CR_SCRATCH14_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SCRATCH14_DATA_SHIFT 0U +#define ROGUE_CR_SCRATCH14_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SCRATCH15 */ +#define ROGUE_CR_SCRATCH15 0x1A78U +#define ROGUE_CR_SCRATCH15_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SCRATCH15_DATA_SHIFT 0U +#define ROGUE_CR_SCRATCH15_DATA_CLRMSK 0x00000000U + +/* Register group: ROGUE_CR_OS0_SCRATCH, with 2 repeats */ +#define ROGUE_CR_OS0_SCRATCH_REPEATCOUNT 2U +/* Register ROGUE_CR_OS0_SCRATCH0 */ +#define ROGUE_CR_OS0_SCRATCH0 0x1A80U +#define ROGUE_CR_OS0_SCRATCH0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_OS0_SCRATCH0_DATA_SHIFT 0U +#define ROGUE_CR_OS0_SCRATCH0_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OS0_SCRATCH1 */ +#define ROGUE_CR_OS0_SCRATCH1 0x1A88U +#define ROGUE_CR_OS0_SCRATCH1_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_OS0_SCRATCH1_DATA_SHIFT 0U +#define ROGUE_CR_OS0_SCRATCH1_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OS0_SCRATCH2 */ +#define ROGUE_CR_OS0_SCRATCH2 0x1A90U +#define ROGUE_CR_OS0_SCRATCH2_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_OS0_SCRATCH2_DATA_SHIFT 0U +#define ROGUE_CR_OS0_SCRATCH2_DATA_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_OS0_SCRATCH3 */ +#define ROGUE_CR_OS0_SCRATCH3 0x1A98U +#define ROGUE_CR_OS0_SCRATCH3_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_OS0_SCRATCH3_DATA_SHIFT 0U +#define ROGUE_CR_OS0_SCRATCH3_DATA_CLRMSK 0xFFFFFF00U + +/* Register group: ROGUE_CR_OS1_SCRATCH, with 2 repeats */ +#define ROGUE_CR_OS1_SCRATCH_REPEATCOUNT 2U +/* Register ROGUE_CR_OS1_SCRATCH0 */ +#define ROGUE_CR_OS1_SCRATCH0 0x11A80U +#define ROGUE_CR_OS1_SCRATCH0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_OS1_SCRATCH0_DATA_SHIFT 0U +#define ROGUE_CR_OS1_SCRATCH0_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OS1_SCRATCH1 */ +#define ROGUE_CR_OS1_SCRATCH1 0x11A88U +#define ROGUE_CR_OS1_SCRATCH1_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_OS1_SCRATCH1_DATA_SHIFT 0U +#define ROGUE_CR_OS1_SCRATCH1_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OS1_SCRATCH2 */ +#define ROGUE_CR_OS1_SCRATCH2 0x11A90U +#define ROGUE_CR_OS1_SCRATCH2_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_OS1_SCRATCH2_DATA_SHIFT 0U +#define ROGUE_CR_OS1_SCRATCH2_DATA_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_OS1_SCRATCH3 */ +#define ROGUE_CR_OS1_SCRATCH3 0x11A98U +#define ROGUE_CR_OS1_SCRATCH3_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_OS1_SCRATCH3_DATA_SHIFT 0U +#define ROGUE_CR_OS1_SCRATCH3_DATA_CLRMSK 0xFFFFFF00U + +/* Register group: ROGUE_CR_OS2_SCRATCH, with 2 repeats */ +#define ROGUE_CR_OS2_SCRATCH_REPEATCOUNT 2U +/* Register ROGUE_CR_OS2_SCRATCH0 */ +#define ROGUE_CR_OS2_SCRATCH0 0x21A80U +#define ROGUE_CR_OS2_SCRATCH0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_OS2_SCRATCH0_DATA_SHIFT 0U +#define ROGUE_CR_OS2_SCRATCH0_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OS2_SCRATCH1 */ +#define ROGUE_CR_OS2_SCRATCH1 0x21A88U +#define ROGUE_CR_OS2_SCRATCH1_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_OS2_SCRATCH1_DATA_SHIFT 0U +#define ROGUE_CR_OS2_SCRATCH1_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OS2_SCRATCH2 */ +#define ROGUE_CR_OS2_SCRATCH2 0x21A90U +#define ROGUE_CR_OS2_SCRATCH2_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_OS2_SCRATCH2_DATA_SHIFT 0U +#define ROGUE_CR_OS2_SCRATCH2_DATA_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_OS2_SCRATCH3 */ +#define ROGUE_CR_OS2_SCRATCH3 0x21A98U +#define ROGUE_CR_OS2_SCRATCH3_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_OS2_SCRATCH3_DATA_SHIFT 0U +#define ROGUE_CR_OS2_SCRATCH3_DATA_CLRMSK 0xFFFFFF00U + +/* Register group: ROGUE_CR_OS3_SCRATCH, with 2 repeats */ +#define ROGUE_CR_OS3_SCRATCH_REPEATCOUNT 2U +/* Register ROGUE_CR_OS3_SCRATCH0 */ +#define ROGUE_CR_OS3_SCRATCH0 0x31A80U +#define ROGUE_CR_OS3_SCRATCH0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_OS3_SCRATCH0_DATA_SHIFT 0U +#define ROGUE_CR_OS3_SCRATCH0_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OS3_SCRATCH1 */ +#define ROGUE_CR_OS3_SCRATCH1 0x31A88U +#define ROGUE_CR_OS3_SCRATCH1_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_OS3_SCRATCH1_DATA_SHIFT 0U +#define ROGUE_CR_OS3_SCRATCH1_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OS3_SCRATCH2 */ +#define ROGUE_CR_OS3_SCRATCH2 0x31A90U +#define ROGUE_CR_OS3_SCRATCH2_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_OS3_SCRATCH2_DATA_SHIFT 0U +#define ROGUE_CR_OS3_SCRATCH2_DATA_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_OS3_SCRATCH3 */ +#define ROGUE_CR_OS3_SCRATCH3 0x31A98U +#define ROGUE_CR_OS3_SCRATCH3_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_OS3_SCRATCH3_DATA_SHIFT 0U +#define ROGUE_CR_OS3_SCRATCH3_DATA_CLRMSK 0xFFFFFF00U + +/* Register group: ROGUE_CR_OS4_SCRATCH, with 2 repeats */ +#define ROGUE_CR_OS4_SCRATCH_REPEATCOUNT 2U +/* Register ROGUE_CR_OS4_SCRATCH0 */ +#define ROGUE_CR_OS4_SCRATCH0 0x41A80U +#define ROGUE_CR_OS4_SCRATCH0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_OS4_SCRATCH0_DATA_SHIFT 0U +#define ROGUE_CR_OS4_SCRATCH0_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OS4_SCRATCH1 */ +#define ROGUE_CR_OS4_SCRATCH1 0x41A88U +#define ROGUE_CR_OS4_SCRATCH1_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_OS4_SCRATCH1_DATA_SHIFT 0U +#define ROGUE_CR_OS4_SCRATCH1_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OS4_SCRATCH2 */ +#define ROGUE_CR_OS4_SCRATCH2 0x41A90U +#define ROGUE_CR_OS4_SCRATCH2_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_OS4_SCRATCH2_DATA_SHIFT 0U +#define ROGUE_CR_OS4_SCRATCH2_DATA_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_OS4_SCRATCH3 */ +#define ROGUE_CR_OS4_SCRATCH3 0x41A98U +#define ROGUE_CR_OS4_SCRATCH3_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_OS4_SCRATCH3_DATA_SHIFT 0U +#define ROGUE_CR_OS4_SCRATCH3_DATA_CLRMSK 0xFFFFFF00U + +/* Register group: ROGUE_CR_OS5_SCRATCH, with 2 repeats */ +#define ROGUE_CR_OS5_SCRATCH_REPEATCOUNT 2U +/* Register ROGUE_CR_OS5_SCRATCH0 */ +#define ROGUE_CR_OS5_SCRATCH0 0x51A80U +#define ROGUE_CR_OS5_SCRATCH0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_OS5_SCRATCH0_DATA_SHIFT 0U +#define ROGUE_CR_OS5_SCRATCH0_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OS5_SCRATCH1 */ +#define ROGUE_CR_OS5_SCRATCH1 0x51A88U +#define ROGUE_CR_OS5_SCRATCH1_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_OS5_SCRATCH1_DATA_SHIFT 0U +#define ROGUE_CR_OS5_SCRATCH1_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OS5_SCRATCH2 */ +#define ROGUE_CR_OS5_SCRATCH2 0x51A90U +#define ROGUE_CR_OS5_SCRATCH2_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_OS5_SCRATCH2_DATA_SHIFT 0U +#define ROGUE_CR_OS5_SCRATCH2_DATA_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_OS5_SCRATCH3 */ +#define ROGUE_CR_OS5_SCRATCH3 0x51A98U +#define ROGUE_CR_OS5_SCRATCH3_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_OS5_SCRATCH3_DATA_SHIFT 0U +#define ROGUE_CR_OS5_SCRATCH3_DATA_CLRMSK 0xFFFFFF00U + +/* Register group: ROGUE_CR_OS6_SCRATCH, with 2 repeats */ +#define ROGUE_CR_OS6_SCRATCH_REPEATCOUNT 2U +/* Register ROGUE_CR_OS6_SCRATCH0 */ +#define ROGUE_CR_OS6_SCRATCH0 0x61A80U +#define ROGUE_CR_OS6_SCRATCH0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_OS6_SCRATCH0_DATA_SHIFT 0U +#define ROGUE_CR_OS6_SCRATCH0_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OS6_SCRATCH1 */ +#define ROGUE_CR_OS6_SCRATCH1 0x61A88U +#define ROGUE_CR_OS6_SCRATCH1_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_OS6_SCRATCH1_DATA_SHIFT 0U +#define ROGUE_CR_OS6_SCRATCH1_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OS6_SCRATCH2 */ +#define ROGUE_CR_OS6_SCRATCH2 0x61A90U +#define ROGUE_CR_OS6_SCRATCH2_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_OS6_SCRATCH2_DATA_SHIFT 0U +#define ROGUE_CR_OS6_SCRATCH2_DATA_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_OS6_SCRATCH3 */ +#define ROGUE_CR_OS6_SCRATCH3 0x61A98U +#define ROGUE_CR_OS6_SCRATCH3_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_OS6_SCRATCH3_DATA_SHIFT 0U +#define ROGUE_CR_OS6_SCRATCH3_DATA_CLRMSK 0xFFFFFF00U + +/* Register group: ROGUE_CR_OS7_SCRATCH, with 2 repeats */ +#define ROGUE_CR_OS7_SCRATCH_REPEATCOUNT 2U +/* Register ROGUE_CR_OS7_SCRATCH0 */ +#define ROGUE_CR_OS7_SCRATCH0 0x71A80U +#define ROGUE_CR_OS7_SCRATCH0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_OS7_SCRATCH0_DATA_SHIFT 0U +#define ROGUE_CR_OS7_SCRATCH0_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OS7_SCRATCH1 */ +#define ROGUE_CR_OS7_SCRATCH1 0x71A88U +#define ROGUE_CR_OS7_SCRATCH1_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_OS7_SCRATCH1_DATA_SHIFT 0U +#define ROGUE_CR_OS7_SCRATCH1_DATA_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OS7_SCRATCH2 */ +#define ROGUE_CR_OS7_SCRATCH2 0x71A90U +#define ROGUE_CR_OS7_SCRATCH2_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_OS7_SCRATCH2_DATA_SHIFT 0U +#define ROGUE_CR_OS7_SCRATCH2_DATA_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_OS7_SCRATCH3 */ +#define ROGUE_CR_OS7_SCRATCH3 0x71A98U +#define ROGUE_CR_OS7_SCRATCH3_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_OS7_SCRATCH3_DATA_SHIFT 0U +#define ROGUE_CR_OS7_SCRATCH3_DATA_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_SPFILTER_SIGNAL_DESCR */ +#define ROGUE_CR_SPFILTER_SIGNAL_DESCR 0x2700U +#define ROGUE_CR_SPFILTER_SIGNAL_DESCR_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_SPFILTER_SIGNAL_DESCR_SIZE_SHIFT 0U +#define ROGUE_CR_SPFILTER_SIGNAL_DESCR_SIZE_CLRMSK 0xFFFF0000U +#define ROGUE_CR_SPFILTER_SIGNAL_DESCR_SIZE_ALIGNSHIFT 4U +#define ROGUE_CR_SPFILTER_SIGNAL_DESCR_SIZE_ALIGNSIZE 16U + +/* Register ROGUE_CR_SPFILTER_SIGNAL_DESCR_MIN */ +#define ROGUE_CR_SPFILTER_SIGNAL_DESCR_MIN 0x2708U +#define ROGUE_CR_SPFILTER_SIGNAL_DESCR_MIN_MASKFULL 0x000000FFFFFFFFF0ULL +#define ROGUE_CR_SPFILTER_SIGNAL_DESCR_MIN_ADDR_SHIFT 4U +#define ROGUE_CR_SPFILTER_SIGNAL_DESCR_MIN_ADDR_CLRMSK 0xFFFFFF000000000FULL +#define ROGUE_CR_SPFILTER_SIGNAL_DESCR_MIN_ADDR_ALIGNSHIFT 4U +#define ROGUE_CR_SPFILTER_SIGNAL_DESCR_MIN_ADDR_ALIGNSIZE 16U + +/* Register group: ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG, with 16 repeats */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG_REPEATCOUNT 16U +/* Register ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0 */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0 0x3000U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_MASKFULL 0x7FFFF7FFFFFFF000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_TRUSTED_SHIFT 62U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_TRUSTED_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_TRUSTED_EN 0x4000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_LOAD_STORE_EN_SHIFT 61U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_LOAD_STORE_EN_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_LOAD_STORE_EN_EN 0x2000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_FETCH_EN_SHIFT 60U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_FETCH_EN_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_FETCH_EN_EN 0x1000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_SIZE_SHIFT 44U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_SIZE_CLRMSK 0xF0000FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_CBASE_SHIFT 40U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_CBASE_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_DEVVADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_DEVVADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_DEVVADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_DEVVADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1 */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1 0x3008U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_MASKFULL 0x7FFFF7FFFFFFF000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_TRUSTED_SHIFT 62U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_TRUSTED_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_TRUSTED_EN 0x4000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_LOAD_STORE_EN_SHIFT 61U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_LOAD_STORE_EN_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_LOAD_STORE_EN_EN 0x2000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_FETCH_EN_SHIFT 60U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_FETCH_EN_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_FETCH_EN_EN 0x1000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_SIZE_SHIFT 44U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_SIZE_CLRMSK 0xF0000FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_CBASE_SHIFT 40U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_CBASE_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_DEVVADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_DEVVADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_DEVVADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG1_DEVVADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2 */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2 0x3010U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_MASKFULL 0x7FFFF7FFFFFFF000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_TRUSTED_SHIFT 62U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_TRUSTED_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_TRUSTED_EN 0x4000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_LOAD_STORE_EN_SHIFT 61U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_LOAD_STORE_EN_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_LOAD_STORE_EN_EN 0x2000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_FETCH_EN_SHIFT 60U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_FETCH_EN_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_FETCH_EN_EN 0x1000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_SIZE_SHIFT 44U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_SIZE_CLRMSK 0xF0000FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_CBASE_SHIFT 40U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_CBASE_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_DEVVADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_DEVVADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_DEVVADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG2_DEVVADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3 */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3 0x3018U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_MASKFULL 0x7FFFF7FFFFFFF000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_TRUSTED_SHIFT 62U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_TRUSTED_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_TRUSTED_EN 0x4000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_LOAD_STORE_EN_SHIFT 61U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_LOAD_STORE_EN_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_LOAD_STORE_EN_EN 0x2000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_FETCH_EN_SHIFT 60U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_FETCH_EN_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_FETCH_EN_EN 0x1000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_SIZE_SHIFT 44U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_SIZE_CLRMSK 0xF0000FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_CBASE_SHIFT 40U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_CBASE_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_DEVVADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_DEVVADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_DEVVADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG3_DEVVADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4 */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4 0x3020U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_MASKFULL 0x7FFFF7FFFFFFF000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_TRUSTED_SHIFT 62U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_TRUSTED_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_TRUSTED_EN 0x4000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_LOAD_STORE_EN_SHIFT 61U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_LOAD_STORE_EN_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_LOAD_STORE_EN_EN 0x2000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_FETCH_EN_SHIFT 60U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_FETCH_EN_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_FETCH_EN_EN 0x1000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_SIZE_SHIFT 44U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_SIZE_CLRMSK 0xF0000FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_CBASE_SHIFT 40U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_CBASE_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_DEVVADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_DEVVADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_DEVVADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG4_DEVVADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5 */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5 0x3028U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_MASKFULL 0x7FFFF7FFFFFFF000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_TRUSTED_SHIFT 62U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_TRUSTED_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_TRUSTED_EN 0x4000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_LOAD_STORE_EN_SHIFT 61U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_LOAD_STORE_EN_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_LOAD_STORE_EN_EN 0x2000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_FETCH_EN_SHIFT 60U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_FETCH_EN_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_FETCH_EN_EN 0x1000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_SIZE_SHIFT 44U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_SIZE_CLRMSK 0xF0000FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_CBASE_SHIFT 40U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_CBASE_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_DEVVADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_DEVVADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_DEVVADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG5_DEVVADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6 */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6 0x3030U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_MASKFULL 0x7FFFF7FFFFFFF000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_TRUSTED_SHIFT 62U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_TRUSTED_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_TRUSTED_EN 0x4000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_LOAD_STORE_EN_SHIFT 61U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_LOAD_STORE_EN_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_LOAD_STORE_EN_EN 0x2000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_FETCH_EN_SHIFT 60U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_FETCH_EN_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_FETCH_EN_EN 0x1000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_SIZE_SHIFT 44U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_SIZE_CLRMSK 0xF0000FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_CBASE_SHIFT 40U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_CBASE_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_DEVVADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_DEVVADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_DEVVADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG6_DEVVADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7 */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7 0x3038U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_MASKFULL 0x7FFFF7FFFFFFF000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_TRUSTED_SHIFT 62U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_TRUSTED_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_TRUSTED_EN 0x4000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_LOAD_STORE_EN_SHIFT 61U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_LOAD_STORE_EN_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_LOAD_STORE_EN_EN 0x2000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_FETCH_EN_SHIFT 60U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_FETCH_EN_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_FETCH_EN_EN 0x1000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_SIZE_SHIFT 44U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_SIZE_CLRMSK 0xF0000FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_CBASE_SHIFT 40U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_CBASE_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_DEVVADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_DEVVADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_DEVVADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG7_DEVVADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8 */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8 0x3040U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_MASKFULL 0x7FFFF7FFFFFFF000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_TRUSTED_SHIFT 62U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_TRUSTED_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_TRUSTED_EN 0x4000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_LOAD_STORE_EN_SHIFT 61U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_LOAD_STORE_EN_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_LOAD_STORE_EN_EN 0x2000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_FETCH_EN_SHIFT 60U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_FETCH_EN_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_FETCH_EN_EN 0x1000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_SIZE_SHIFT 44U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_SIZE_CLRMSK 0xF0000FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_CBASE_SHIFT 40U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_CBASE_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_DEVVADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_DEVVADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_DEVVADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG8_DEVVADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9 */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9 0x3048U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_MASKFULL 0x7FFFF7FFFFFFF000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_TRUSTED_SHIFT 62U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_TRUSTED_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_TRUSTED_EN 0x4000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_LOAD_STORE_EN_SHIFT 61U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_LOAD_STORE_EN_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_LOAD_STORE_EN_EN 0x2000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_FETCH_EN_SHIFT 60U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_FETCH_EN_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_FETCH_EN_EN 0x1000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_SIZE_SHIFT 44U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_SIZE_CLRMSK 0xF0000FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_CBASE_SHIFT 40U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_CBASE_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_DEVVADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_DEVVADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_DEVVADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG9_DEVVADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10 */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10 0x3050U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_MASKFULL 0x7FFFF7FFFFFFF000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_TRUSTED_SHIFT 62U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_TRUSTED_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_TRUSTED_EN 0x4000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_LOAD_STORE_EN_SHIFT 61U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_LOAD_STORE_EN_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_LOAD_STORE_EN_EN 0x2000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_FETCH_EN_SHIFT 60U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_FETCH_EN_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_FETCH_EN_EN 0x1000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_SIZE_SHIFT 44U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_SIZE_CLRMSK 0xF0000FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_CBASE_SHIFT 40U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_CBASE_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_DEVVADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_DEVVADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_DEVVADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG10_DEVVADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11 */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11 0x3058U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_MASKFULL 0x7FFFF7FFFFFFF000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_TRUSTED_SHIFT 62U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_TRUSTED_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_TRUSTED_EN 0x4000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_LOAD_STORE_EN_SHIFT 61U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_LOAD_STORE_EN_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_LOAD_STORE_EN_EN 0x2000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_FETCH_EN_SHIFT 60U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_FETCH_EN_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_FETCH_EN_EN 0x1000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_SIZE_SHIFT 44U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_SIZE_CLRMSK 0xF0000FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_CBASE_SHIFT 40U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_CBASE_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_DEVVADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_DEVVADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_DEVVADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG11_DEVVADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12 */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12 0x3060U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_MASKFULL 0x7FFFF7FFFFFFF000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_TRUSTED_SHIFT 62U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_TRUSTED_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_TRUSTED_EN 0x4000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_LOAD_STORE_EN_SHIFT 61U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_LOAD_STORE_EN_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_LOAD_STORE_EN_EN 0x2000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_FETCH_EN_SHIFT 60U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_FETCH_EN_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_FETCH_EN_EN 0x1000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_SIZE_SHIFT 44U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_SIZE_CLRMSK 0xF0000FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_CBASE_SHIFT 40U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_CBASE_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_DEVVADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_DEVVADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_DEVVADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG12_DEVVADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13 */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13 0x3068U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_MASKFULL 0x7FFFF7FFFFFFF000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_TRUSTED_SHIFT 62U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_TRUSTED_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_TRUSTED_EN 0x4000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_LOAD_STORE_EN_SHIFT 61U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_LOAD_STORE_EN_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_LOAD_STORE_EN_EN 0x2000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_FETCH_EN_SHIFT 60U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_FETCH_EN_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_FETCH_EN_EN 0x1000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_SIZE_SHIFT 44U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_SIZE_CLRMSK 0xF0000FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_CBASE_SHIFT 40U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_CBASE_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_DEVVADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_DEVVADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_DEVVADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG13_DEVVADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14 */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14 0x3070U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_MASKFULL 0x7FFFF7FFFFFFF000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_TRUSTED_SHIFT 62U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_TRUSTED_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_TRUSTED_EN 0x4000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_LOAD_STORE_EN_SHIFT 61U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_LOAD_STORE_EN_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_LOAD_STORE_EN_EN 0x2000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_FETCH_EN_SHIFT 60U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_FETCH_EN_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_FETCH_EN_EN 0x1000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_SIZE_SHIFT 44U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_SIZE_CLRMSK 0xF0000FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_CBASE_SHIFT 40U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_CBASE_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_DEVVADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_DEVVADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_DEVVADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG14_DEVVADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15 */ +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15 0x3078U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_MASKFULL 0x7FFFF7FFFFFFF000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_TRUSTED_SHIFT 62U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_TRUSTED_CLRMSK 0xBFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_TRUSTED_EN 0x4000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_LOAD_STORE_EN_SHIFT 61U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_LOAD_STORE_EN_CLRMSK 0xDFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_LOAD_STORE_EN_EN 0x2000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_FETCH_EN_SHIFT 60U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_FETCH_EN_CLRMSK 0xEFFFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_FETCH_EN_EN 0x1000000000000000ULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_SIZE_SHIFT 44U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_SIZE_CLRMSK 0xF0000FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_CBASE_SHIFT 40U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_CBASE_CLRMSK 0xFFFFF8FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_DEVVADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_DEVVADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_DEVVADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG15_DEVVADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_BOOT */ +#define ROGUE_CR_FWCORE_BOOT 0x3090U +#define ROGUE_CR_FWCORE_BOOT_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_FWCORE_BOOT_ENABLE_SHIFT 0U +#define ROGUE_CR_FWCORE_BOOT_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_FWCORE_BOOT_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_FWCORE_RESET_ADDR */ +#define ROGUE_CR_FWCORE_RESET_ADDR 0x3098U +#define ROGUE_CR_FWCORE_RESET_ADDR_MASKFULL 0x00000000FFFFFFFEULL +#define ROGUE_CR_FWCORE_RESET_ADDR_ADDR_SHIFT 1U +#define ROGUE_CR_FWCORE_RESET_ADDR_ADDR_CLRMSK 0x00000001U +#define ROGUE_CR_FWCORE_RESET_ADDR_ADDR_ALIGNSHIFT 1U +#define ROGUE_CR_FWCORE_RESET_ADDR_ADDR_ALIGNSIZE 2U + +/* Register ROGUE_CR_FWCORE_WRAPPER_NMI_ADDR */ +#define ROGUE_CR_FWCORE_WRAPPER_NMI_ADDR 0x30A0U +#define ROGUE_CR_FWCORE_WRAPPER_NMI_ADDR_MASKFULL 0x00000000FFFFFFFEULL +#define ROGUE_CR_FWCORE_WRAPPER_NMI_ADDR_ADDR_SHIFT 1U +#define ROGUE_CR_FWCORE_WRAPPER_NMI_ADDR_ADDR_CLRMSK 0x00000001U +#define ROGUE_CR_FWCORE_WRAPPER_NMI_ADDR_ADDR_ALIGNSHIFT 1U +#define ROGUE_CR_FWCORE_WRAPPER_NMI_ADDR_ADDR_ALIGNSIZE 2U + +/* Register ROGUE_CR_FWCORE_WRAPPER_NMI_EVENT */ +#define ROGUE_CR_FWCORE_WRAPPER_NMI_EVENT 0x30A8U +#define ROGUE_CR_FWCORE_WRAPPER_NMI_EVENT_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_FWCORE_WRAPPER_NMI_EVENT_TRIGGER_EN_SHIFT 0U +#define ROGUE_CR_FWCORE_WRAPPER_NMI_EVENT_TRIGGER_EN_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_FWCORE_WRAPPER_NMI_EVENT_TRIGGER_EN_EN 0x00000001U + +/* Register ROGUE_CR_FWCORE_MEM_FAULT_MMU_STATUS */ +#define ROGUE_CR_FWCORE_MEM_FAULT_MMU_STATUS 0x30B0U +#define ROGUE_CR_FWCORE_MEM_FAULT_MMU_STATUS_MASKFULL 0x000000000000F771ULL +#define ROGUE_CR_FWCORE_MEM_FAULT_MMU_STATUS_CAT_BASE_SHIFT 12U +#define ROGUE_CR_FWCORE_MEM_FAULT_MMU_STATUS_CAT_BASE_CLRMSK 0xFFFF0FFFU +#define ROGUE_CR_FWCORE_MEM_FAULT_MMU_STATUS_PAGE_SIZE_SHIFT 8U +#define ROGUE_CR_FWCORE_MEM_FAULT_MMU_STATUS_PAGE_SIZE_CLRMSK 0xFFFFF8FFU +#define ROGUE_CR_FWCORE_MEM_FAULT_MMU_STATUS_DATA_TYPE_SHIFT 5U +#define ROGUE_CR_FWCORE_MEM_FAULT_MMU_STATUS_DATA_TYPE_CLRMSK 0xFFFFFF9FU +#define ROGUE_CR_FWCORE_MEM_FAULT_MMU_STATUS_FAULT_RO_SHIFT 4U +#define ROGUE_CR_FWCORE_MEM_FAULT_MMU_STATUS_FAULT_RO_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_FWCORE_MEM_FAULT_MMU_STATUS_FAULT_RO_EN 0x00000010U +#define ROGUE_CR_FWCORE_MEM_FAULT_MMU_STATUS_FAULT_SHIFT 0U +#define ROGUE_CR_FWCORE_MEM_FAULT_MMU_STATUS_FAULT_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_FWCORE_MEM_FAULT_MMU_STATUS_FAULT_EN 0x00000001U + +/* Register ROGUE_CR_FWCORE_MEM_FAULT_REQ_STATUS */ +#define ROGUE_CR_FWCORE_MEM_FAULT_REQ_STATUS 0x30B8U +#define ROGUE_CR_FWCORE_MEM_FAULT_REQ_STATUS_MASKFULL 0x001FFFFFFFFFFFF0ULL +#define ROGUE_CR_FWCORE_MEM_FAULT_REQ_STATUS_RNW_SHIFT 52U +#define ROGUE_CR_FWCORE_MEM_FAULT_REQ_STATUS_RNW_CLRMSK 0xFFEFFFFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_MEM_FAULT_REQ_STATUS_RNW_EN 0x0010000000000000ULL +#define ROGUE_CR_FWCORE_MEM_FAULT_REQ_STATUS_TAG_SB_SHIFT 46U +#define ROGUE_CR_FWCORE_MEM_FAULT_REQ_STATUS_TAG_SB_CLRMSK 0xFFF03FFFFFFFFFFFULL +#define ROGUE_CR_FWCORE_MEM_FAULT_REQ_STATUS_TAG_ID_SHIFT 40U +#define ROGUE_CR_FWCORE_MEM_FAULT_REQ_STATUS_TAG_ID_CLRMSK 0xFFFFC0FFFFFFFFFFULL +#define ROGUE_CR_FWCORE_MEM_FAULT_REQ_STATUS_ADDRESS_SHIFT 4U +#define ROGUE_CR_FWCORE_MEM_FAULT_REQ_STATUS_ADDRESS_CLRMSK 0xFFFFFF000000000FULL +#define ROGUE_CR_FWCORE_MEM_FAULT_REQ_STATUS_ADDRESS_ALIGNSHIFT 4U +#define ROGUE_CR_FWCORE_MEM_FAULT_REQ_STATUS_ADDRESS_ALIGNSIZE 16U + +/* Register ROGUE_CR_FWCORE_MEM_CTRL_INVAL */ +#define ROGUE_CR_FWCORE_MEM_CTRL_INVAL 0x30C0U +#define ROGUE_CR_FWCORE_MEM_CTRL_INVAL_MASKFULL 0x000000000000000FULL +#define ROGUE_CR_FWCORE_MEM_CTRL_INVAL_TLB_SHIFT 3U +#define ROGUE_CR_FWCORE_MEM_CTRL_INVAL_TLB_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_FWCORE_MEM_CTRL_INVAL_TLB_EN 0x00000008U +#define ROGUE_CR_FWCORE_MEM_CTRL_INVAL_PC_SHIFT 2U +#define ROGUE_CR_FWCORE_MEM_CTRL_INVAL_PC_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_FWCORE_MEM_CTRL_INVAL_PC_EN 0x00000004U +#define ROGUE_CR_FWCORE_MEM_CTRL_INVAL_PD_SHIFT 1U +#define ROGUE_CR_FWCORE_MEM_CTRL_INVAL_PD_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_FWCORE_MEM_CTRL_INVAL_PD_EN 0x00000002U +#define ROGUE_CR_FWCORE_MEM_CTRL_INVAL_PT_SHIFT 0U +#define ROGUE_CR_FWCORE_MEM_CTRL_INVAL_PT_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_FWCORE_MEM_CTRL_INVAL_PT_EN 0x00000001U + +/* Register ROGUE_CR_FWCORE_MEM_MMU_STATUS */ +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS 0x30C8U +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS_MASKFULL 0x000000000FFFFFF7ULL +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS_PC_DATA_SHIFT 20U +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS_PC_DATA_CLRMSK 0xF00FFFFFU +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS_PD_DATA_SHIFT 12U +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS_PD_DATA_CLRMSK 0xFFF00FFFU +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS_PT_DATA_SHIFT 4U +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS_PT_DATA_CLRMSK 0xFFFFF00FU +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS_STALLED_SHIFT 2U +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS_STALLED_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS_STALLED_EN 0x00000004U +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS_PAUSED_SHIFT 1U +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS_PAUSED_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS_PAUSED_EN 0x00000002U +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS_BUSY_SHIFT 0U +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS_BUSY_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_FWCORE_MEM_MMU_STATUS_BUSY_EN 0x00000001U + +/* Register ROGUE_CR_FWCORE_MEM_READS_EXT_STATUS */ +#define ROGUE_CR_FWCORE_MEM_READS_EXT_STATUS 0x30D8U +#define ROGUE_CR_FWCORE_MEM_READS_EXT_STATUS_MASKFULL 0x0000000000000FFFULL +#define ROGUE_CR_FWCORE_MEM_READS_EXT_STATUS_MMU_SHIFT 0U +#define ROGUE_CR_FWCORE_MEM_READS_EXT_STATUS_MMU_CLRMSK 0xFFFFF000U + +/* Register ROGUE_CR_FWCORE_MEM_READS_INT_STATUS */ +#define ROGUE_CR_FWCORE_MEM_READS_INT_STATUS 0x30E0U +#define ROGUE_CR_FWCORE_MEM_READS_INT_STATUS_MASKFULL 0x00000000000007FFULL +#define ROGUE_CR_FWCORE_MEM_READS_INT_STATUS_MMU_SHIFT 0U +#define ROGUE_CR_FWCORE_MEM_READS_INT_STATUS_MMU_CLRMSK 0xFFFFF800U + +/* Register ROGUE_CR_FWCORE_WRAPPER_FENCE */ +#define ROGUE_CR_FWCORE_WRAPPER_FENCE 0x30E8U +#define ROGUE_CR_FWCORE_WRAPPER_FENCE_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_FWCORE_WRAPPER_FENCE_ID_SHIFT 0U +#define ROGUE_CR_FWCORE_WRAPPER_FENCE_ID_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_FWCORE_WRAPPER_FENCE_ID_EN 0x00000001U + +/* Register group: ROGUE_CR_FWCORE_MEM_CAT_BASE, with 8 repeats */ +#define ROGUE_CR_FWCORE_MEM_CAT_BASE_REPEATCOUNT 8U +/* Register ROGUE_CR_FWCORE_MEM_CAT_BASE0 */ +#define ROGUE_CR_FWCORE_MEM_CAT_BASE0 0x30F0U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE0_MASKFULL 0x000000FFFFFFF000ULL +#define ROGUE_CR_FWCORE_MEM_CAT_BASE0_ADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE0_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_MEM_CAT_BASE0_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE0_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_MEM_CAT_BASE1 */ +#define ROGUE_CR_FWCORE_MEM_CAT_BASE1 0x30F8U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE1_MASKFULL 0x000000FFFFFFF000ULL +#define ROGUE_CR_FWCORE_MEM_CAT_BASE1_ADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE1_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_MEM_CAT_BASE1_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE1_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_MEM_CAT_BASE2 */ +#define ROGUE_CR_FWCORE_MEM_CAT_BASE2 0x3100U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE2_MASKFULL 0x000000FFFFFFF000ULL +#define ROGUE_CR_FWCORE_MEM_CAT_BASE2_ADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE2_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_MEM_CAT_BASE2_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE2_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_MEM_CAT_BASE3 */ +#define ROGUE_CR_FWCORE_MEM_CAT_BASE3 0x3108U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE3_MASKFULL 0x000000FFFFFFF000ULL +#define ROGUE_CR_FWCORE_MEM_CAT_BASE3_ADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE3_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_MEM_CAT_BASE3_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE3_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_MEM_CAT_BASE4 */ +#define ROGUE_CR_FWCORE_MEM_CAT_BASE4 0x3110U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE4_MASKFULL 0x000000FFFFFFF000ULL +#define ROGUE_CR_FWCORE_MEM_CAT_BASE4_ADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE4_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_MEM_CAT_BASE4_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE4_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_MEM_CAT_BASE5 */ +#define ROGUE_CR_FWCORE_MEM_CAT_BASE5 0x3118U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE5_MASKFULL 0x000000FFFFFFF000ULL +#define ROGUE_CR_FWCORE_MEM_CAT_BASE5_ADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE5_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_MEM_CAT_BASE5_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE5_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_MEM_CAT_BASE6 */ +#define ROGUE_CR_FWCORE_MEM_CAT_BASE6 0x3120U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE6_MASKFULL 0x000000FFFFFFF000ULL +#define ROGUE_CR_FWCORE_MEM_CAT_BASE6_ADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE6_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_MEM_CAT_BASE6_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE6_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_MEM_CAT_BASE7 */ +#define ROGUE_CR_FWCORE_MEM_CAT_BASE7 0x3128U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE7_MASKFULL 0x000000FFFFFFF000ULL +#define ROGUE_CR_FWCORE_MEM_CAT_BASE7_ADDR_SHIFT 12U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE7_ADDR_CLRMSK 0xFFFFFF0000000FFFULL +#define ROGUE_CR_FWCORE_MEM_CAT_BASE7_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_FWCORE_MEM_CAT_BASE7_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_FWCORE_WDT_RESET */ +#define ROGUE_CR_FWCORE_WDT_RESET 0x3130U +#define ROGUE_CR_FWCORE_WDT_RESET_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_FWCORE_WDT_RESET_EN_SHIFT 0U +#define ROGUE_CR_FWCORE_WDT_RESET_EN_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_FWCORE_WDT_RESET_EN_EN 0x00000001U + +/* Register ROGUE_CR_FWCORE_WDT_CTRL */ +#define ROGUE_CR_FWCORE_WDT_CTRL 0x3138U +#define ROGUE_CR_FWCORE_WDT_CTRL_MASKFULL 0x00000000FFFF1F01ULL +#define ROGUE_CR_FWCORE_WDT_CTRL_PROT_SHIFT 16U +#define ROGUE_CR_FWCORE_WDT_CTRL_PROT_CLRMSK 0x0000FFFFU +#define ROGUE_CR_FWCORE_WDT_CTRL_THRESHOLD_SHIFT 8U +#define ROGUE_CR_FWCORE_WDT_CTRL_THRESHOLD_CLRMSK 0xFFFFE0FFU +#define ROGUE_CR_FWCORE_WDT_CTRL_ENABLE_SHIFT 0U +#define ROGUE_CR_FWCORE_WDT_CTRL_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_FWCORE_WDT_CTRL_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_FWCORE_WDT_COUNT */ +#define ROGUE_CR_FWCORE_WDT_COUNT 0x3140U +#define ROGUE_CR_FWCORE_WDT_COUNT_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_FWCORE_WDT_COUNT_VALUE_SHIFT 0U +#define ROGUE_CR_FWCORE_WDT_COUNT_VALUE_CLRMSK 0x00000000U + +/* Register group: ROGUE_CR_FWCORE_DMI_RESERVED0, with 4 repeats */ +#define ROGUE_CR_FWCORE_DMI_RESERVED0_REPEATCOUNT 4U +/* Register ROGUE_CR_FWCORE_DMI_RESERVED00 */ +#define ROGUE_CR_FWCORE_DMI_RESERVED00 0x3400U +#define ROGUE_CR_FWCORE_DMI_RESERVED00_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_RESERVED01 */ +#define ROGUE_CR_FWCORE_DMI_RESERVED01 0x3408U +#define ROGUE_CR_FWCORE_DMI_RESERVED01_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_RESERVED02 */ +#define ROGUE_CR_FWCORE_DMI_RESERVED02 0x3410U +#define ROGUE_CR_FWCORE_DMI_RESERVED02_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_RESERVED03 */ +#define ROGUE_CR_FWCORE_DMI_RESERVED03 0x3418U +#define ROGUE_CR_FWCORE_DMI_RESERVED03_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_DATA0 */ +#define ROGUE_CR_FWCORE_DMI_DATA0 0x3420U +#define ROGUE_CR_FWCORE_DMI_DATA0_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_DATA1 */ +#define ROGUE_CR_FWCORE_DMI_DATA1 0x3428U +#define ROGUE_CR_FWCORE_DMI_DATA1_MASKFULL 0x0000000000000000ULL + +/* Register group: ROGUE_CR_FWCORE_DMI_RESERVED1, with 5 repeats */ +#define ROGUE_CR_FWCORE_DMI_RESERVED1_REPEATCOUNT 5U +/* Register ROGUE_CR_FWCORE_DMI_RESERVED10 */ +#define ROGUE_CR_FWCORE_DMI_RESERVED10 0x3430U +#define ROGUE_CR_FWCORE_DMI_RESERVED10_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_RESERVED11 */ +#define ROGUE_CR_FWCORE_DMI_RESERVED11 0x3438U +#define ROGUE_CR_FWCORE_DMI_RESERVED11_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_RESERVED12 */ +#define ROGUE_CR_FWCORE_DMI_RESERVED12 0x3440U +#define ROGUE_CR_FWCORE_DMI_RESERVED12_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_RESERVED13 */ +#define ROGUE_CR_FWCORE_DMI_RESERVED13 0x3448U +#define ROGUE_CR_FWCORE_DMI_RESERVED13_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_RESERVED14 */ +#define ROGUE_CR_FWCORE_DMI_RESERVED14 0x3450U +#define ROGUE_CR_FWCORE_DMI_RESERVED14_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_DMCONTROL */ +#define ROGUE_CR_FWCORE_DMI_DMCONTROL 0x3480U +#define ROGUE_CR_FWCORE_DMI_DMCONTROL_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_DMSTATUS */ +#define ROGUE_CR_FWCORE_DMI_DMSTATUS 0x3488U +#define ROGUE_CR_FWCORE_DMI_DMSTATUS_MASKFULL 0x0000000000000000ULL + +/* Register group: ROGUE_CR_FWCORE_DMI_RESERVED2, with 4 repeats */ +#define ROGUE_CR_FWCORE_DMI_RESERVED2_REPEATCOUNT 4U +/* Register ROGUE_CR_FWCORE_DMI_RESERVED20 */ +#define ROGUE_CR_FWCORE_DMI_RESERVED20 0x3490U +#define ROGUE_CR_FWCORE_DMI_RESERVED20_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_RESERVED21 */ +#define ROGUE_CR_FWCORE_DMI_RESERVED21 0x3498U +#define ROGUE_CR_FWCORE_DMI_RESERVED21_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_RESERVED22 */ +#define ROGUE_CR_FWCORE_DMI_RESERVED22 0x34A0U +#define ROGUE_CR_FWCORE_DMI_RESERVED22_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_RESERVED23 */ +#define ROGUE_CR_FWCORE_DMI_RESERVED23 0x34A8U +#define ROGUE_CR_FWCORE_DMI_RESERVED23_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_ABSTRACTCS */ +#define ROGUE_CR_FWCORE_DMI_ABSTRACTCS 0x34B0U +#define ROGUE_CR_FWCORE_DMI_ABSTRACTCS_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_COMMAND */ +#define ROGUE_CR_FWCORE_DMI_COMMAND 0x34B8U +#define ROGUE_CR_FWCORE_DMI_COMMAND_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_SBCS */ +#define ROGUE_CR_FWCORE_DMI_SBCS 0x35C0U +#define ROGUE_CR_FWCORE_DMI_SBCS_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_SBADDRESS0 */ +#define ROGUE_CR_FWCORE_DMI_SBADDRESS0 0x35C8U +#define ROGUE_CR_FWCORE_DMI_SBADDRESS0_MASKFULL 0x0000000000000000ULL + +/* Register group: ROGUE_CR_FWCORE_DMI_RESERVED3, with 2 repeats */ +#define ROGUE_CR_FWCORE_DMI_RESERVED3_REPEATCOUNT 2U +/* Register ROGUE_CR_FWCORE_DMI_RESERVED30 */ +#define ROGUE_CR_FWCORE_DMI_RESERVED30 0x34D0U +#define ROGUE_CR_FWCORE_DMI_RESERVED30_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_RESERVED31 */ +#define ROGUE_CR_FWCORE_DMI_RESERVED31 0x34D8U +#define ROGUE_CR_FWCORE_DMI_RESERVED31_MASKFULL 0x0000000000000000ULL + +/* Register group: ROGUE_CR_FWCORE_DMI_SBDATA, with 4 repeats */ +#define ROGUE_CR_FWCORE_DMI_SBDATA_REPEATCOUNT 4U +/* Register ROGUE_CR_FWCORE_DMI_SBDATA0 */ +#define ROGUE_CR_FWCORE_DMI_SBDATA0 0x35E0U +#define ROGUE_CR_FWCORE_DMI_SBDATA0_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_SBDATA1 */ +#define ROGUE_CR_FWCORE_DMI_SBDATA1 0x35E8U +#define ROGUE_CR_FWCORE_DMI_SBDATA1_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_SBDATA2 */ +#define ROGUE_CR_FWCORE_DMI_SBDATA2 0x35F0U +#define ROGUE_CR_FWCORE_DMI_SBDATA2_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_SBDATA3 */ +#define ROGUE_CR_FWCORE_DMI_SBDATA3 0x35F8U +#define ROGUE_CR_FWCORE_DMI_SBDATA3_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_FWCORE_DMI_HALTSUM0 */ +#define ROGUE_CR_FWCORE_DMI_HALTSUM0 0x3600U +#define ROGUE_CR_FWCORE_DMI_HALTSUM0_MASKFULL 0x0000000000000000ULL + +/* Register ROGUE_CR_SLC_CTRL_MISC */ +#define ROGUE_CR_SLC_CTRL_MISC 0x3800U +#define ROGUE_CR_SLC_CTRL_MISC_MASKFULL 0xFFFFFFFF01FF010FULL +#define ROGUE_CR_SLC_CTRL_MISC_SCRAMBLE_BITS_SHIFT 32U +#define ROGUE_CR_SLC_CTRL_MISC_SCRAMBLE_BITS_CLRMSK 0x00000000FFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_MISC_LAZYWB_OVERRIDE_SHIFT 24U +#define ROGUE_CR_SLC_CTRL_MISC_LAZYWB_OVERRIDE_CLRMSK 0xFFFFFFFFFEFFFFFFULL +#define ROGUE_CR_SLC_CTRL_MISC_LAZYWB_OVERRIDE_EN 0x0000000001000000ULL +#define ROGUE_CR_SLC_CTRL_MISC_ADDR_DECODE_MODE_SHIFT 16U +#define ROGUE_CR_SLC_CTRL_MISC_ADDR_DECODE_MODE_CLRMSK 0xFFFFFFFFFF00FFFFULL +#define ROGUE_CR_SLC_CTRL_MISC_ADDR_DECODE_MODE_INTERLEAVED_64_BYTE 0x0000000000000000ULL +#define ROGUE_CR_SLC_CTRL_MISC_ADDR_DECODE_MODE_INTERLEAVED_128_BYTE 0x0000000000010000ULL +#define ROGUE_CR_SLC_CTRL_MISC_ADDR_DECODE_MODE_SIMPLE_HASH1 0x0000000000100000ULL +#define ROGUE_CR_SLC_CTRL_MISC_ADDR_DECODE_MODE_SIMPLE_HASH2 0x0000000000110000ULL +#define ROGUE_CR_SLC_CTRL_MISC_ADDR_DECODE_MODE_PVR_HASH1 0x0000000000200000ULL +#define ROGUE_CR_SLC_CTRL_MISC_ADDR_DECODE_MODE_PVR_HASH2_SCRAMBLE 0x0000000000210000ULL +#define ROGUE_CR_SLC_CTRL_MISC_PAUSE_SHIFT 8U +#define ROGUE_CR_SLC_CTRL_MISC_PAUSE_CLRMSK 0xFFFFFFFFFFFFFEFFULL +#define ROGUE_CR_SLC_CTRL_MISC_PAUSE_EN 0x0000000000000100ULL +#define ROGUE_CR_SLC_CTRL_MISC_RESP_PRIORITY_SHIFT 3U +#define ROGUE_CR_SLC_CTRL_MISC_RESP_PRIORITY_CLRMSK 0xFFFFFFFFFFFFFFF7ULL +#define ROGUE_CR_SLC_CTRL_MISC_RESP_PRIORITY_EN 0x0000000000000008ULL +#define ROGUE_CR_SLC_CTRL_MISC_ENABLE_LINE_USE_LIMIT_SHIFT 2U +#define ROGUE_CR_SLC_CTRL_MISC_ENABLE_LINE_USE_LIMIT_CLRMSK 0xFFFFFFFFFFFFFFFBULL +#define ROGUE_CR_SLC_CTRL_MISC_ENABLE_LINE_USE_LIMIT_EN 0x0000000000000004ULL +#define ROGUE_CR_SLC_CTRL_MISC_ENABLE_PSG_HAZARD_CHECK_SHIFT 1U +#define ROGUE_CR_SLC_CTRL_MISC_ENABLE_PSG_HAZARD_CHECK_CLRMSK 0xFFFFFFFFFFFFFFFDULL +#define ROGUE_CR_SLC_CTRL_MISC_ENABLE_PSG_HAZARD_CHECK_EN 0x0000000000000002ULL +#define ROGUE_CR_SLC_CTRL_MISC_BYPASS_BURST_COMBINER_SHIFT 0U +#define ROGUE_CR_SLC_CTRL_MISC_BYPASS_BURST_COMBINER_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_SLC_CTRL_MISC_BYPASS_BURST_COMBINER_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_SLC_CTRL_FLUSH_INVAL */ +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL 0x3818U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_MASKFULL 0x0000000080000FFFULL +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_LAZY_SHIFT 31U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_LAZY_CLRMSK 0x7FFFFFFFU +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_LAZY_EN 0x80000000U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_FASTRENDER_SHIFT 11U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_FASTRENDER_CLRMSK 0xFFFFF7FFU +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_FASTRENDER_EN 0x00000800U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_RAY_VERTEX_SHIFT 10U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_RAY_VERTEX_CLRMSK 0xFFFFFBFFU +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_RAY_VERTEX_EN 0x00000400U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_RAY_SHIFT 9U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_RAY_CLRMSK 0xFFFFFDFFU +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_RAY_EN 0x00000200U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_FRC_SHIFT 8U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_FRC_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_FRC_EN 0x00000100U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_VXE_SHIFT 7U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_VXE_CLRMSK 0xFFFFFF7FU +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_VXE_EN 0x00000080U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_VXD_SHIFT 6U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_VXD_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_VXD_EN 0x00000040U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_HOST_META_SHIFT 5U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_HOST_META_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_HOST_META_EN 0x00000020U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_MMU_SHIFT 4U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_MMU_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_MMU_EN 0x00000010U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_COMPUTE_SHIFT 3U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_COMPUTE_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_COMPUTE_EN 0x00000008U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_PIXEL_SHIFT 2U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_PIXEL_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_PIXEL_EN 0x00000004U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_TA_SHIFT 1U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_TA_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_DM_TA_EN 0x00000002U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_ALL_SHIFT 0U +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_ALL_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_SLC_CTRL_FLUSH_INVAL_ALL_EN 0x00000001U + +/* Register ROGUE_CR_SLC_STATUS0 */ +#define ROGUE_CR_SLC_STATUS0 0x3820U +#define ROGUE_CR_SLC_STATUS0_MASKFULL 0x0000000000000007ULL +#define ROGUE_CR_SLC_STATUS0_FLUSH_INVAL_PENDING_SHIFT 2U +#define ROGUE_CR_SLC_STATUS0_FLUSH_INVAL_PENDING_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_SLC_STATUS0_FLUSH_INVAL_PENDING_EN 0x00000004U +#define ROGUE_CR_SLC_STATUS0_INVAL_PENDING_SHIFT 1U +#define ROGUE_CR_SLC_STATUS0_INVAL_PENDING_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_SLC_STATUS0_INVAL_PENDING_EN 0x00000002U +#define ROGUE_CR_SLC_STATUS0_FLUSH_PENDING_SHIFT 0U +#define ROGUE_CR_SLC_STATUS0_FLUSH_PENDING_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_SLC_STATUS0_FLUSH_PENDING_EN 0x00000001U + +/* Register ROGUE_CR_SLC_CTRL_BYPASS */ +#define ROGUE_CR_SLC_CTRL_BYPASS 0x3828U +#define ROGUE_CR_SLC_CTRL_BYPASS__XE_MEM__MASKFULL 0x0FFFFFFFFFFF7FFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_MASKFULL 0x000000000FFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_COMP_ZLS_SHIFT 59U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_COMP_ZLS_CLRMSK 0xF7FFFFFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_COMP_ZLS_EN 0x0800000000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_DECOMP_ZLS_HEADER_SHIFT 58U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_DECOMP_ZLS_HEADER_CLRMSK 0xFBFFFFFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_DECOMP_ZLS_HEADER_EN 0x0400000000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_DECOMP_TCU_HEADER_SHIFT 57U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_DECOMP_TCU_HEADER_CLRMSK 0xFDFFFFFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_DECOMP_TCU_HEADER_EN 0x0200000000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_DECOMP_ZLS_DATA_SHIFT 56U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_DECOMP_ZLS_DATA_CLRMSK 0xFEFFFFFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_DECOMP_ZLS_DATA_EN 0x0100000000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_DECOMP_TCU_DATA_SHIFT 55U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_DECOMP_TCU_DATA_CLRMSK 0xFF7FFFFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_DECOMP_TCU_DATA_EN 0x0080000000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_COMP_PBE_SHIFT 54U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_COMP_PBE_CLRMSK 0xFFBFFFFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TFBC_COMP_PBE_EN 0x0040000000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TCU_DM_COMPUTE_SHIFT 53U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TCU_DM_COMPUTE_CLRMSK 0xFFDFFFFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TCU_DM_COMPUTE_EN 0x0020000000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_PDSRW_NOLINEFILL_SHIFT 52U +#define ROGUE_CR_SLC_CTRL_BYPASS_PDSRW_NOLINEFILL_CLRMSK 0xFFEFFFFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_PDSRW_NOLINEFILL_EN 0x0010000000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_PBE_NOLINEFILL_SHIFT 51U +#define ROGUE_CR_SLC_CTRL_BYPASS_PBE_NOLINEFILL_CLRMSK 0xFFF7FFFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_PBE_NOLINEFILL_EN 0x0008000000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_FBC_SHIFT 50U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_FBC_CLRMSK 0xFFFBFFFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_FBC_EN 0x0004000000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_RREQ_SHIFT 49U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_RREQ_CLRMSK 0xFFFDFFFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_RREQ_EN 0x0002000000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_CREQ_SHIFT 48U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_CREQ_CLRMSK 0xFFFEFFFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_CREQ_EN 0x0001000000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_PREQ_SHIFT 47U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_PREQ_CLRMSK 0xFFFF7FFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_PREQ_EN 0x0000800000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_DBSC_SHIFT 46U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_DBSC_CLRMSK 0xFFFFBFFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_DBSC_EN 0x0000400000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TCU_SHIFT 45U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TCU_CLRMSK 0xFFFFDFFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TCU_EN 0x0000200000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_PBE_SHIFT 44U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_PBE_CLRMSK 0xFFFFEFFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_PBE_EN 0x0000100000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_ISP_SHIFT 43U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_ISP_CLRMSK 0xFFFFF7FFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_ISP_EN 0x0000080000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_PM_SHIFT 42U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_PM_CLRMSK 0xFFFFFBFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_PM_EN 0x0000040000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TDM_SHIFT 41U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TDM_CLRMSK 0xFFFFFDFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TDM_EN 0x0000020000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_CDM_SHIFT 40U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_CDM_CLRMSK 0xFFFFFEFFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_CDM_EN 0x0000010000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TSPF_PDS_STATE_SHIFT 39U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TSPF_PDS_STATE_CLRMSK 0xFFFFFF7FFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TSPF_PDS_STATE_EN 0x0000008000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TSPF_DB_SHIFT 38U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TSPF_DB_CLRMSK 0xFFFFFFBFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TSPF_DB_EN 0x0000004000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TSPF_VTX_VAR_SHIFT 37U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TSPF_VTX_VAR_CLRMSK 0xFFFFFFDFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TSPF_VTX_VAR_EN 0x0000002000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_VDM_SHIFT 36U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_VDM_CLRMSK 0xFFFFFFEFFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_VDM_EN 0x0000001000000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TA_PSG_STREAM_SHIFT 35U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TA_PSG_STREAM_CLRMSK 0xFFFFFFF7FFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TA_PSG_STREAM_EN 0x0000000800000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TA_PSG_REGION_SHIFT 34U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TA_PSG_REGION_CLRMSK 0xFFFFFFFBFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TA_PSG_REGION_EN 0x0000000400000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TA_VCE_SHIFT 33U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TA_VCE_CLRMSK 0xFFFFFFFDFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TA_VCE_EN 0x0000000200000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TA_PPP_SHIFT 32U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TA_PPP_CLRMSK 0xFFFFFFFEFFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TA_PPP_EN 0x0000000100000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_FASTRENDER_SHIFT 31U +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_FASTRENDER_CLRMSK 0xFFFFFFFF7FFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_FASTRENDER_EN 0x0000000080000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_PM_ALIST_SHIFT 30U +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_PM_ALIST_CLRMSK 0xFFFFFFFFBFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_PM_ALIST_EN 0x0000000040000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_PB_TE_SHIFT 29U +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_PB_TE_CLRMSK 0xFFFFFFFFDFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_PB_TE_EN 0x0000000020000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_PB_VCE_SHIFT 28U +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_PB_VCE_CLRMSK 0xFFFFFFFFEFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_PB_VCE_EN 0x0000000010000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_RAY_VERTEX_SHIFT 27U +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_RAY_VERTEX_CLRMSK 0xFFFFFFFFF7FFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_RAY_VERTEX_EN 0x0000000008000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_RAY_SHIFT 26U +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_RAY_CLRMSK 0xFFFFFFFFFBFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_RAY_EN 0x0000000004000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_CPF_SHIFT 25U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_CPF_CLRMSK 0xFFFFFFFFFDFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_CPF_EN 0x0000000002000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TPU_SHIFT 24U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TPU_CLRMSK 0xFFFFFFFFFEFFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TPU_EN 0x0000000001000000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_FBDC_SHIFT 23U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_FBDC_CLRMSK 0xFFFFFFFFFF7FFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_FBDC_EN 0x0000000000800000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TLA_SHIFT 22U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TLA_CLRMSK 0xFFFFFFFFFFBFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TLA_EN 0x0000000000400000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_BYP_CC_N_SHIFT 21U +#define ROGUE_CR_SLC_CTRL_BYPASS_BYP_CC_N_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_BYP_CC_N_EN 0x0000000000200000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_BYP_CC_SHIFT 20U +#define ROGUE_CR_SLC_CTRL_BYPASS_BYP_CC_CLRMSK 0xFFFFFFFFFFEFFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_BYP_CC_EN 0x0000000000100000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_MCU_SHIFT 19U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_MCU_CLRMSK 0xFFFFFFFFFFF7FFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_MCU_EN 0x0000000000080000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_PDS_SHIFT 18U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_PDS_CLRMSK 0xFFFFFFFFFFFBFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_PDS_EN 0x0000000000040000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TPF_SHIFT 17U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TPF_CLRMSK 0xFFFFFFFFFFFDFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TPF_EN 0x0000000000020000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TA_TPC_SHIFT 16U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TA_TPC_CLRMSK 0xFFFFFFFFFFFEFFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_TA_TPC_EN 0x0000000000010000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_OBJ_SHIFT 15U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_OBJ_CLRMSK 0xFFFFFFFFFFFF7FFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_IPF_OBJ_EN 0x0000000000008000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_USC_SHIFT 14U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_USC_CLRMSK 0xFFFFFFFFFFFFBFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_USC_EN 0x0000000000004000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_META_SHIFT 13U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_META_CLRMSK 0xFFFFFFFFFFFFDFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_META_EN 0x0000000000002000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_HOST_SHIFT 12U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_HOST_CLRMSK 0xFFFFFFFFFFFFEFFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_HOST_EN 0x0000000000001000ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_MMU_PT_SHIFT 11U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_MMU_PT_CLRMSK 0xFFFFFFFFFFFFF7FFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_MMU_PT_EN 0x0000000000000800ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_MMU_PD_SHIFT 10U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_MMU_PD_CLRMSK 0xFFFFFFFFFFFFFBFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_MMU_PD_EN 0x0000000000000400ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_MMU_PC_SHIFT 9U +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_MMU_PC_CLRMSK 0xFFFFFFFFFFFFFDFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_REQ_MMU_PC_EN 0x0000000000000200ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_FRC_SHIFT 8U +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_FRC_CLRMSK 0xFFFFFFFFFFFFFEFFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_FRC_EN 0x0000000000000100ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_VXE_SHIFT 7U +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_VXE_CLRMSK 0xFFFFFFFFFFFFFF7FULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_VXE_EN 0x0000000000000080ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_VXD_SHIFT 6U +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_VXD_CLRMSK 0xFFFFFFFFFFFFFFBFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_VXD_EN 0x0000000000000040ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_HOST_META_SHIFT 5U +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_HOST_META_CLRMSK 0xFFFFFFFFFFFFFFDFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_HOST_META_EN 0x0000000000000020ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_MMU_SHIFT 4U +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_MMU_CLRMSK 0xFFFFFFFFFFFFFFEFULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_MMU_EN 0x0000000000000010ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_COMPUTE_SHIFT 3U +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_COMPUTE_CLRMSK 0xFFFFFFFFFFFFFFF7ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_COMPUTE_EN 0x0000000000000008ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_PIXEL_SHIFT 2U +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_PIXEL_CLRMSK 0xFFFFFFFFFFFFFFFBULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_PIXEL_EN 0x0000000000000004ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_TA_SHIFT 1U +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_TA_CLRMSK 0xFFFFFFFFFFFFFFFDULL +#define ROGUE_CR_SLC_CTRL_BYPASS_DM_TA_EN 0x0000000000000002ULL +#define ROGUE_CR_SLC_CTRL_BYPASS_ALL_SHIFT 0U +#define ROGUE_CR_SLC_CTRL_BYPASS_ALL_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_SLC_CTRL_BYPASS_ALL_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_SLC_STATUS1 */ +#define ROGUE_CR_SLC_STATUS1 0x3870U +#define ROGUE_CR_SLC_STATUS1_MASKFULL 0x800003FF03FFFFFFULL +#define ROGUE_CR_SLC_STATUS1_PAUSED_SHIFT 63U +#define ROGUE_CR_SLC_STATUS1_PAUSED_CLRMSK 0x7FFFFFFFFFFFFFFFULL +#define ROGUE_CR_SLC_STATUS1_PAUSED_EN 0x8000000000000000ULL +#define ROGUE_CR_SLC_STATUS1_READS1_SHIFT 32U +#define ROGUE_CR_SLC_STATUS1_READS1_CLRMSK 0xFFFFFC00FFFFFFFFULL +#define ROGUE_CR_SLC_STATUS1_READS0_SHIFT 16U +#define ROGUE_CR_SLC_STATUS1_READS0_CLRMSK 0xFFFFFFFFFC00FFFFULL +#define ROGUE_CR_SLC_STATUS1_READS1_EXT_SHIFT 8U +#define ROGUE_CR_SLC_STATUS1_READS1_EXT_CLRMSK 0xFFFFFFFFFFFF00FFULL +#define ROGUE_CR_SLC_STATUS1_READS0_EXT_SHIFT 0U +#define ROGUE_CR_SLC_STATUS1_READS0_EXT_CLRMSK 0xFFFFFFFFFFFFFF00ULL + +/* Register ROGUE_CR_SLC_IDLE */ +#define ROGUE_CR_SLC_IDLE 0x3898U +#define ROGUE_CR_SLC_IDLE__XE_MEM__MASKFULL 0x00000000000003FFULL +#define ROGUE_CR_SLC_IDLE_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_SLC_IDLE_MH_SYSARB1_SHIFT 9U +#define ROGUE_CR_SLC_IDLE_MH_SYSARB1_CLRMSK 0xFFFFFDFFU +#define ROGUE_CR_SLC_IDLE_MH_SYSARB1_EN 0x00000200U +#define ROGUE_CR_SLC_IDLE_MH_SYSARB0_SHIFT 8U +#define ROGUE_CR_SLC_IDLE_MH_SYSARB0_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_SLC_IDLE_MH_SYSARB0_EN 0x00000100U +#define ROGUE_CR_SLC_IDLE_IMGBV4_SHIFT 7U +#define ROGUE_CR_SLC_IDLE_IMGBV4_CLRMSK 0xFFFFFF7FU +#define ROGUE_CR_SLC_IDLE_IMGBV4_EN 0x00000080U +#define ROGUE_CR_SLC_IDLE_CACHE_BANKS_SHIFT 6U +#define ROGUE_CR_SLC_IDLE_CACHE_BANKS_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_SLC_IDLE_CACHE_BANKS_EN 0x00000040U +#define ROGUE_CR_SLC_IDLE_RBOFIFO_SHIFT 5U +#define ROGUE_CR_SLC_IDLE_RBOFIFO_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_SLC_IDLE_RBOFIFO_EN 0x00000020U +#define ROGUE_CR_SLC_IDLE_FRC_CONV_SHIFT 4U +#define ROGUE_CR_SLC_IDLE_FRC_CONV_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_SLC_IDLE_FRC_CONV_EN 0x00000010U +#define ROGUE_CR_SLC_IDLE_VXE_CONV_SHIFT 3U +#define ROGUE_CR_SLC_IDLE_VXE_CONV_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_SLC_IDLE_VXE_CONV_EN 0x00000008U +#define ROGUE_CR_SLC_IDLE_VXD_CONV_SHIFT 2U +#define ROGUE_CR_SLC_IDLE_VXD_CONV_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_SLC_IDLE_VXD_CONV_EN 0x00000004U +#define ROGUE_CR_SLC_IDLE_BIF1_CONV_SHIFT 1U +#define ROGUE_CR_SLC_IDLE_BIF1_CONV_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_SLC_IDLE_BIF1_CONV_EN 0x00000002U +#define ROGUE_CR_SLC_IDLE_CBAR_SHIFT 0U +#define ROGUE_CR_SLC_IDLE_CBAR_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_SLC_IDLE_CBAR_EN 0x00000001U + +/* Register ROGUE_CR_SLC_STATUS2 */ +#define ROGUE_CR_SLC_STATUS2 0x3908U +#define ROGUE_CR_SLC_STATUS2_MASKFULL 0x000003FF03FFFFFFULL +#define ROGUE_CR_SLC_STATUS2_READS3_SHIFT 32U +#define ROGUE_CR_SLC_STATUS2_READS3_CLRMSK 0xFFFFFC00FFFFFFFFULL +#define ROGUE_CR_SLC_STATUS2_READS2_SHIFT 16U +#define ROGUE_CR_SLC_STATUS2_READS2_CLRMSK 0xFFFFFFFFFC00FFFFULL +#define ROGUE_CR_SLC_STATUS2_READS3_EXT_SHIFT 8U +#define ROGUE_CR_SLC_STATUS2_READS3_EXT_CLRMSK 0xFFFFFFFFFFFF00FFULL +#define ROGUE_CR_SLC_STATUS2_READS2_EXT_SHIFT 0U +#define ROGUE_CR_SLC_STATUS2_READS2_EXT_CLRMSK 0xFFFFFFFFFFFFFF00ULL + +/* Register ROGUE_CR_SLC_CTRL_MISC2 */ +#define ROGUE_CR_SLC_CTRL_MISC2 0x3930U +#define ROGUE_CR_SLC_CTRL_MISC2_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SLC_CTRL_MISC2_SCRAMBLE_BITS_SHIFT 0U +#define ROGUE_CR_SLC_CTRL_MISC2_SCRAMBLE_BITS_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SLC_CROSSBAR_LOAD_BALANCE */ +#define ROGUE_CR_SLC_CROSSBAR_LOAD_BALANCE 0x3938U +#define ROGUE_CR_SLC_CROSSBAR_LOAD_BALANCE_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_SLC_CROSSBAR_LOAD_BALANCE_BYPASS_SHIFT 0U +#define ROGUE_CR_SLC_CROSSBAR_LOAD_BALANCE_BYPASS_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_SLC_CROSSBAR_LOAD_BALANCE_BYPASS_EN 0x00000001U + +/* Register ROGUE_CR_USC_UVS0_CHECKSUM */ +#define ROGUE_CR_USC_UVS0_CHECKSUM 0x5000U +#define ROGUE_CR_USC_UVS0_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_USC_UVS0_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_USC_UVS0_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_USC_UVS1_CHECKSUM */ +#define ROGUE_CR_USC_UVS1_CHECKSUM 0x5008U +#define ROGUE_CR_USC_UVS1_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_USC_UVS1_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_USC_UVS1_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_USC_UVS2_CHECKSUM */ +#define ROGUE_CR_USC_UVS2_CHECKSUM 0x5010U +#define ROGUE_CR_USC_UVS2_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_USC_UVS2_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_USC_UVS2_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_USC_UVS3_CHECKSUM */ +#define ROGUE_CR_USC_UVS3_CHECKSUM 0x5018U +#define ROGUE_CR_USC_UVS3_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_USC_UVS3_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_USC_UVS3_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PPP_SIGNATURE */ +#define ROGUE_CR_PPP_SIGNATURE 0x5020U +#define ROGUE_CR_PPP_SIGNATURE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PPP_SIGNATURE_VALUE_SHIFT 0U +#define ROGUE_CR_PPP_SIGNATURE_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_TE_SIGNATURE */ +#define ROGUE_CR_TE_SIGNATURE 0x5028U +#define ROGUE_CR_TE_SIGNATURE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_TE_SIGNATURE_VALUE_SHIFT 0U +#define ROGUE_CR_TE_SIGNATURE_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_TE_CHECKSUM */ +#define ROGUE_CR_TE_CHECKSUM 0x5110U +#define ROGUE_CR_TE_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_TE_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_TE_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_USC_UVB_CHECKSUM */ +#define ROGUE_CR_USC_UVB_CHECKSUM 0x5118U +#define ROGUE_CR_USC_UVB_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_USC_UVB_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_USC_UVB_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_VCE_CHECKSUM */ +#define ROGUE_CR_VCE_CHECKSUM 0x5030U +#define ROGUE_CR_VCE_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_VCE_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_VCE_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_ISP_PDS_CHECKSUM */ +#define ROGUE_CR_ISP_PDS_CHECKSUM 0x5038U +#define ROGUE_CR_ISP_PDS_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_ISP_PDS_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_ISP_PDS_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_ISP_TPF_CHECKSUM */ +#define ROGUE_CR_ISP_TPF_CHECKSUM 0x5040U +#define ROGUE_CR_ISP_TPF_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_ISP_TPF_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_ISP_TPF_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_TFPU_PLANE0_CHECKSUM */ +#define ROGUE_CR_TFPU_PLANE0_CHECKSUM 0x5048U +#define ROGUE_CR_TFPU_PLANE0_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_TFPU_PLANE0_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_TFPU_PLANE0_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_TFPU_PLANE1_CHECKSUM */ +#define ROGUE_CR_TFPU_PLANE1_CHECKSUM 0x5050U +#define ROGUE_CR_TFPU_PLANE1_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_TFPU_PLANE1_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_TFPU_PLANE1_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PBE_CHECKSUM */ +#define ROGUE_CR_PBE_CHECKSUM 0x5058U +#define ROGUE_CR_PBE_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PBE_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_PBE_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PDS_DOUTM_STM_SIGNATURE */ +#define ROGUE_CR_PDS_DOUTM_STM_SIGNATURE 0x5060U +#define ROGUE_CR_PDS_DOUTM_STM_SIGNATURE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PDS_DOUTM_STM_SIGNATURE_VALUE_SHIFT 0U +#define ROGUE_CR_PDS_DOUTM_STM_SIGNATURE_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_IFPU_ISP_CHECKSUM */ +#define ROGUE_CR_IFPU_ISP_CHECKSUM 0x5068U +#define ROGUE_CR_IFPU_ISP_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_IFPU_ISP_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_IFPU_ISP_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_USC_UVS4_CHECKSUM */ +#define ROGUE_CR_USC_UVS4_CHECKSUM 0x5100U +#define ROGUE_CR_USC_UVS4_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_USC_UVS4_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_USC_UVS4_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_USC_UVS5_CHECKSUM */ +#define ROGUE_CR_USC_UVS5_CHECKSUM 0x5108U +#define ROGUE_CR_USC_UVS5_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_USC_UVS5_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_USC_UVS5_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PPP_CLIP_CHECKSUM */ +#define ROGUE_CR_PPP_CLIP_CHECKSUM 0x5120U +#define ROGUE_CR_PPP_CLIP_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PPP_CLIP_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_PPP_CLIP_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_TA_PHASE */ +#define ROGUE_CR_PERF_TA_PHASE 0x6008U +#define ROGUE_CR_PERF_TA_PHASE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_TA_PHASE_COUNT_SHIFT 0U +#define ROGUE_CR_PERF_TA_PHASE_COUNT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_3D_PHASE */ +#define ROGUE_CR_PERF_3D_PHASE 0x6010U +#define ROGUE_CR_PERF_3D_PHASE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_3D_PHASE_COUNT_SHIFT 0U +#define ROGUE_CR_PERF_3D_PHASE_COUNT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_COMPUTE_PHASE */ +#define ROGUE_CR_PERF_COMPUTE_PHASE 0x6018U +#define ROGUE_CR_PERF_COMPUTE_PHASE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_COMPUTE_PHASE_COUNT_SHIFT 0U +#define ROGUE_CR_PERF_COMPUTE_PHASE_COUNT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_TA_CYCLE */ +#define ROGUE_CR_PERF_TA_CYCLE 0x6020U +#define ROGUE_CR_PERF_TA_CYCLE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_TA_CYCLE_COUNT_SHIFT 0U +#define ROGUE_CR_PERF_TA_CYCLE_COUNT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_3D_CYCLE */ +#define ROGUE_CR_PERF_3D_CYCLE 0x6028U +#define ROGUE_CR_PERF_3D_CYCLE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_3D_CYCLE_COUNT_SHIFT 0U +#define ROGUE_CR_PERF_3D_CYCLE_COUNT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_COMPUTE_CYCLE */ +#define ROGUE_CR_PERF_COMPUTE_CYCLE 0x6030U +#define ROGUE_CR_PERF_COMPUTE_CYCLE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_COMPUTE_CYCLE_COUNT_SHIFT 0U +#define ROGUE_CR_PERF_COMPUTE_CYCLE_COUNT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_TA_OR_3D_CYCLE */ +#define ROGUE_CR_PERF_TA_OR_3D_CYCLE 0x6038U +#define ROGUE_CR_PERF_TA_OR_3D_CYCLE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_TA_OR_3D_CYCLE_COUNT_SHIFT 0U +#define ROGUE_CR_PERF_TA_OR_3D_CYCLE_COUNT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_INITIAL_TA_CYCLE */ +#define ROGUE_CR_PERF_INITIAL_TA_CYCLE 0x6040U +#define ROGUE_CR_PERF_INITIAL_TA_CYCLE_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_INITIAL_TA_CYCLE_COUNT_SHIFT 0U +#define ROGUE_CR_PERF_INITIAL_TA_CYCLE_COUNT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_SLC0_READ_STALL */ +#define ROGUE_CR_PERF_SLC0_READ_STALL 0x60B8U +#define ROGUE_CR_PERF_SLC0_READ_STALL_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_SLC0_READ_STALL_COUNT_SHIFT 0U +#define ROGUE_CR_PERF_SLC0_READ_STALL_COUNT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_SLC0_WRITE_STALL */ +#define ROGUE_CR_PERF_SLC0_WRITE_STALL 0x60C0U +#define ROGUE_CR_PERF_SLC0_WRITE_STALL_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_SLC0_WRITE_STALL_COUNT_SHIFT 0U +#define ROGUE_CR_PERF_SLC0_WRITE_STALL_COUNT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_SLC1_READ_STALL */ +#define ROGUE_CR_PERF_SLC1_READ_STALL 0x60E0U +#define ROGUE_CR_PERF_SLC1_READ_STALL_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_SLC1_READ_STALL_COUNT_SHIFT 0U +#define ROGUE_CR_PERF_SLC1_READ_STALL_COUNT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_SLC1_WRITE_STALL */ +#define ROGUE_CR_PERF_SLC1_WRITE_STALL 0x60E8U +#define ROGUE_CR_PERF_SLC1_WRITE_STALL_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_SLC1_WRITE_STALL_COUNT_SHIFT 0U +#define ROGUE_CR_PERF_SLC1_WRITE_STALL_COUNT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_SLC2_READ_STALL */ +#define ROGUE_CR_PERF_SLC2_READ_STALL 0x6158U +#define ROGUE_CR_PERF_SLC2_READ_STALL_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_SLC2_READ_STALL_COUNT_SHIFT 0U +#define ROGUE_CR_PERF_SLC2_READ_STALL_COUNT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_SLC2_WRITE_STALL */ +#define ROGUE_CR_PERF_SLC2_WRITE_STALL 0x6160U +#define ROGUE_CR_PERF_SLC2_WRITE_STALL_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_SLC2_WRITE_STALL_COUNT_SHIFT 0U +#define ROGUE_CR_PERF_SLC2_WRITE_STALL_COUNT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_SLC3_READ_STALL */ +#define ROGUE_CR_PERF_SLC3_READ_STALL 0x6180U +#define ROGUE_CR_PERF_SLC3_READ_STALL_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_SLC3_READ_STALL_COUNT_SHIFT 0U +#define ROGUE_CR_PERF_SLC3_READ_STALL_COUNT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_SLC3_WRITE_STALL */ +#define ROGUE_CR_PERF_SLC3_WRITE_STALL 0x6188U +#define ROGUE_CR_PERF_SLC3_WRITE_STALL_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_SLC3_WRITE_STALL_COUNT_SHIFT 0U +#define ROGUE_CR_PERF_SLC3_WRITE_STALL_COUNT_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PERF_3D_SPINUP */ +#define ROGUE_CR_PERF_3D_SPINUP 0x6220U +#define ROGUE_CR_PERF_3D_SPINUP_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PERF_3D_SPINUP_CYCLES_SHIFT 0U +#define ROGUE_CR_PERF_3D_SPINUP_CYCLES_CLRMSK 0x00000000U + +/* Register ROGUE_CR_AXI_ACE_LITE_CONFIGURATION */ +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION 0x38C0U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_MASKFULL 0x00003FFFFFFFFFFFULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ENABLE_FENCE_OUT_SHIFT 45U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ENABLE_FENCE_OUT_CLRMSK 0xFFFFDFFFFFFFFFFFULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ENABLE_FENCE_OUT_EN 0x0000200000000000ULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_OSID_SECURITY_SHIFT 37U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_OSID_SECURITY_CLRMSK 0xFFFFE01FFFFFFFFFULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_DISABLE_COHERENT_WRITELINEUNIQUE_SHIFT 36U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_DISABLE_COHERENT_WRITELINEUNIQUE_CLRMSK \ + 0xFFFFFFEFFFFFFFFFULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_DISABLE_COHERENT_WRITELINEUNIQUE_EN \ + 0x0000001000000000ULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_DISABLE_COHERENT_WRITE_SHIFT 35U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_DISABLE_COHERENT_WRITE_CLRMSK 0xFFFFFFF7FFFFFFFFULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_DISABLE_COHERENT_WRITE_EN 0x0000000800000000ULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_DISABLE_COHERENT_READ_SHIFT 34U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_DISABLE_COHERENT_READ_CLRMSK 0xFFFFFFFBFFFFFFFFULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_DISABLE_COHERENT_READ_EN 0x0000000400000000ULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARCACHE_CACHE_MAINTENANCE_SHIFT 30U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARCACHE_CACHE_MAINTENANCE_CLRMSK 0xFFFFFFFC3FFFFFFFULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARCACHE_COHERENT_SHIFT 26U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARCACHE_COHERENT_CLRMSK 0xFFFFFFFFC3FFFFFFULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_AWCACHE_COHERENT_SHIFT 22U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_AWCACHE_COHERENT_CLRMSK 0xFFFFFFFFFC3FFFFFULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARDOMAIN_BARRIER_SHIFT 20U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARDOMAIN_BARRIER_CLRMSK 0xFFFFFFFFFFCFFFFFULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_AWDOMAIN_BARRIER_SHIFT 18U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_AWDOMAIN_BARRIER_CLRMSK 0xFFFFFFFFFFF3FFFFULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARDOMAIN_CACHE_MAINTENANCE_SHIFT 16U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARDOMAIN_CACHE_MAINTENANCE_CLRMSK 0xFFFFFFFFFFFCFFFFULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_AWDOMAIN_COHERENT_SHIFT 14U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_AWDOMAIN_COHERENT_CLRMSK 0xFFFFFFFFFFFF3FFFULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARDOMAIN_COHERENT_SHIFT 12U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARDOMAIN_COHERENT_CLRMSK 0xFFFFFFFFFFFFCFFFULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARDOMAIN_NON_SNOOPING_SHIFT 10U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARDOMAIN_NON_SNOOPING_CLRMSK 0xFFFFFFFFFFFFF3FFULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_AWDOMAIN_NON_SNOOPING_SHIFT 8U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_AWDOMAIN_NON_SNOOPING_CLRMSK 0xFFFFFFFFFFFFFCFFULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARCACHE_NON_SNOOPING_SHIFT 4U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_ARCACHE_NON_SNOOPING_CLRMSK 0xFFFFFFFFFFFFFF0FULL +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_AWCACHE_NON_SNOOPING_SHIFT 0U +#define ROGUE_CR_AXI_ACE_LITE_CONFIGURATION_AWCACHE_NON_SNOOPING_CLRMSK 0xFFFFFFFFFFFFFFF0ULL + +/* Register ROGUE_CR_POWER_ESTIMATE_RESULT */ +#define ROGUE_CR_POWER_ESTIMATE_RESULT 0x6328U +#define ROGUE_CR_POWER_ESTIMATE_RESULT_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_POWER_ESTIMATE_RESULT_VALUE_SHIFT 0U +#define ROGUE_CR_POWER_ESTIMATE_RESULT_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_TA_PERF */ +#define ROGUE_CR_TA_PERF 0x7600U +#define ROGUE_CR_TA_PERF_MASKFULL 0x000000000000001FULL +#define ROGUE_CR_TA_PERF_CLR_3_SHIFT 4U +#define ROGUE_CR_TA_PERF_CLR_3_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_TA_PERF_CLR_3_EN 0x00000010U +#define ROGUE_CR_TA_PERF_CLR_2_SHIFT 3U +#define ROGUE_CR_TA_PERF_CLR_2_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_TA_PERF_CLR_2_EN 0x00000008U +#define ROGUE_CR_TA_PERF_CLR_1_SHIFT 2U +#define ROGUE_CR_TA_PERF_CLR_1_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_TA_PERF_CLR_1_EN 0x00000004U +#define ROGUE_CR_TA_PERF_CLR_0_SHIFT 1U +#define ROGUE_CR_TA_PERF_CLR_0_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_TA_PERF_CLR_0_EN 0x00000002U +#define ROGUE_CR_TA_PERF_CTRL_ENABLE_SHIFT 0U +#define ROGUE_CR_TA_PERF_CTRL_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_TA_PERF_CTRL_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_TA_PERF_SELECT0 */ +#define ROGUE_CR_TA_PERF_SELECT0 0x7608U +#define ROGUE_CR_TA_PERF_SELECT0_MASKFULL 0x3FFF3FFF003FFFFFULL +#define ROGUE_CR_TA_PERF_SELECT0_BATCH_MAX_SHIFT 48U +#define ROGUE_CR_TA_PERF_SELECT0_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define ROGUE_CR_TA_PERF_SELECT0_BATCH_MIN_SHIFT 32U +#define ROGUE_CR_TA_PERF_SELECT0_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define ROGUE_CR_TA_PERF_SELECT0_MODE_SHIFT 21U +#define ROGUE_CR_TA_PERF_SELECT0_MODE_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define ROGUE_CR_TA_PERF_SELECT0_MODE_EN 0x0000000000200000ULL +#define ROGUE_CR_TA_PERF_SELECT0_GROUP_SELECT_SHIFT 16U +#define ROGUE_CR_TA_PERF_SELECT0_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFE0FFFFULL +#define ROGUE_CR_TA_PERF_SELECT0_BIT_SELECT_SHIFT 0U +#define ROGUE_CR_TA_PERF_SELECT0_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_TA_PERF_SELECT1 */ +#define ROGUE_CR_TA_PERF_SELECT1 0x7610U +#define ROGUE_CR_TA_PERF_SELECT1_MASKFULL 0x3FFF3FFF003FFFFFULL +#define ROGUE_CR_TA_PERF_SELECT1_BATCH_MAX_SHIFT 48U +#define ROGUE_CR_TA_PERF_SELECT1_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define ROGUE_CR_TA_PERF_SELECT1_BATCH_MIN_SHIFT 32U +#define ROGUE_CR_TA_PERF_SELECT1_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define ROGUE_CR_TA_PERF_SELECT1_MODE_SHIFT 21U +#define ROGUE_CR_TA_PERF_SELECT1_MODE_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define ROGUE_CR_TA_PERF_SELECT1_MODE_EN 0x0000000000200000ULL +#define ROGUE_CR_TA_PERF_SELECT1_GROUP_SELECT_SHIFT 16U +#define ROGUE_CR_TA_PERF_SELECT1_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFE0FFFFULL +#define ROGUE_CR_TA_PERF_SELECT1_BIT_SELECT_SHIFT 0U +#define ROGUE_CR_TA_PERF_SELECT1_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_TA_PERF_SELECT2 */ +#define ROGUE_CR_TA_PERF_SELECT2 0x7618U +#define ROGUE_CR_TA_PERF_SELECT2_MASKFULL 0x3FFF3FFF003FFFFFULL +#define ROGUE_CR_TA_PERF_SELECT2_BATCH_MAX_SHIFT 48U +#define ROGUE_CR_TA_PERF_SELECT2_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define ROGUE_CR_TA_PERF_SELECT2_BATCH_MIN_SHIFT 32U +#define ROGUE_CR_TA_PERF_SELECT2_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define ROGUE_CR_TA_PERF_SELECT2_MODE_SHIFT 21U +#define ROGUE_CR_TA_PERF_SELECT2_MODE_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define ROGUE_CR_TA_PERF_SELECT2_MODE_EN 0x0000000000200000ULL +#define ROGUE_CR_TA_PERF_SELECT2_GROUP_SELECT_SHIFT 16U +#define ROGUE_CR_TA_PERF_SELECT2_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFE0FFFFULL +#define ROGUE_CR_TA_PERF_SELECT2_BIT_SELECT_SHIFT 0U +#define ROGUE_CR_TA_PERF_SELECT2_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_TA_PERF_SELECT3 */ +#define ROGUE_CR_TA_PERF_SELECT3 0x7620U +#define ROGUE_CR_TA_PERF_SELECT3_MASKFULL 0x3FFF3FFF003FFFFFULL +#define ROGUE_CR_TA_PERF_SELECT3_BATCH_MAX_SHIFT 48U +#define ROGUE_CR_TA_PERF_SELECT3_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define ROGUE_CR_TA_PERF_SELECT3_BATCH_MIN_SHIFT 32U +#define ROGUE_CR_TA_PERF_SELECT3_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define ROGUE_CR_TA_PERF_SELECT3_MODE_SHIFT 21U +#define ROGUE_CR_TA_PERF_SELECT3_MODE_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define ROGUE_CR_TA_PERF_SELECT3_MODE_EN 0x0000000000200000ULL +#define ROGUE_CR_TA_PERF_SELECT3_GROUP_SELECT_SHIFT 16U +#define ROGUE_CR_TA_PERF_SELECT3_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFE0FFFFULL +#define ROGUE_CR_TA_PERF_SELECT3_BIT_SELECT_SHIFT 0U +#define ROGUE_CR_TA_PERF_SELECT3_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_TA_PERF_SELECTED_BITS */ +#define ROGUE_CR_TA_PERF_SELECTED_BITS 0x7648U +#define ROGUE_CR_TA_PERF_SELECTED_BITS_MASKFULL 0xFFFFFFFFFFFFFFFFULL +#define ROGUE_CR_TA_PERF_SELECTED_BITS_REG3_SHIFT 48U +#define ROGUE_CR_TA_PERF_SELECTED_BITS_REG3_CLRMSK 0x0000FFFFFFFFFFFFULL +#define ROGUE_CR_TA_PERF_SELECTED_BITS_REG2_SHIFT 32U +#define ROGUE_CR_TA_PERF_SELECTED_BITS_REG2_CLRMSK 0xFFFF0000FFFFFFFFULL +#define ROGUE_CR_TA_PERF_SELECTED_BITS_REG1_SHIFT 16U +#define ROGUE_CR_TA_PERF_SELECTED_BITS_REG1_CLRMSK 0xFFFFFFFF0000FFFFULL +#define ROGUE_CR_TA_PERF_SELECTED_BITS_REG0_SHIFT 0U +#define ROGUE_CR_TA_PERF_SELECTED_BITS_REG0_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_TA_PERF_COUNTER_0 */ +#define ROGUE_CR_TA_PERF_COUNTER_0 0x7650U +#define ROGUE_CR_TA_PERF_COUNTER_0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_TA_PERF_COUNTER_0_REG_SHIFT 0U +#define ROGUE_CR_TA_PERF_COUNTER_0_REG_CLRMSK 0x00000000U + +/* Register ROGUE_CR_TA_PERF_COUNTER_1 */ +#define ROGUE_CR_TA_PERF_COUNTER_1 0x7658U +#define ROGUE_CR_TA_PERF_COUNTER_1_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_TA_PERF_COUNTER_1_REG_SHIFT 0U +#define ROGUE_CR_TA_PERF_COUNTER_1_REG_CLRMSK 0x00000000U + +/* Register ROGUE_CR_TA_PERF_COUNTER_2 */ +#define ROGUE_CR_TA_PERF_COUNTER_2 0x7660U +#define ROGUE_CR_TA_PERF_COUNTER_2_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_TA_PERF_COUNTER_2_REG_SHIFT 0U +#define ROGUE_CR_TA_PERF_COUNTER_2_REG_CLRMSK 0x00000000U + +/* Register ROGUE_CR_TA_PERF_COUNTER_3 */ +#define ROGUE_CR_TA_PERF_COUNTER_3 0x7668U +#define ROGUE_CR_TA_PERF_COUNTER_3_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_TA_PERF_COUNTER_3_REG_SHIFT 0U +#define ROGUE_CR_TA_PERF_COUNTER_3_REG_CLRMSK 0x00000000U + +/* Register ROGUE_CR_RASTERISATION_PERF */ +#define ROGUE_CR_RASTERISATION_PERF 0x7700U +#define ROGUE_CR_RASTERISATION_PERF_MASKFULL 0x000000000000001FULL +#define ROGUE_CR_RASTERISATION_PERF_CLR_3_SHIFT 4U +#define ROGUE_CR_RASTERISATION_PERF_CLR_3_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_RASTERISATION_PERF_CLR_3_EN 0x00000010U +#define ROGUE_CR_RASTERISATION_PERF_CLR_2_SHIFT 3U +#define ROGUE_CR_RASTERISATION_PERF_CLR_2_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_RASTERISATION_PERF_CLR_2_EN 0x00000008U +#define ROGUE_CR_RASTERISATION_PERF_CLR_1_SHIFT 2U +#define ROGUE_CR_RASTERISATION_PERF_CLR_1_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_RASTERISATION_PERF_CLR_1_EN 0x00000004U +#define ROGUE_CR_RASTERISATION_PERF_CLR_0_SHIFT 1U +#define ROGUE_CR_RASTERISATION_PERF_CLR_0_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_RASTERISATION_PERF_CLR_0_EN 0x00000002U +#define ROGUE_CR_RASTERISATION_PERF_CTRL_ENABLE_SHIFT 0U +#define ROGUE_CR_RASTERISATION_PERF_CTRL_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_RASTERISATION_PERF_CTRL_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_RASTERISATION_PERF_SELECT0 */ +#define ROGUE_CR_RASTERISATION_PERF_SELECT0 0x7708U +#define ROGUE_CR_RASTERISATION_PERF_SELECT0_MASKFULL 0x3FFF3FFF003FFFFFULL +#define ROGUE_CR_RASTERISATION_PERF_SELECT0_BATCH_MAX_SHIFT 48U +#define ROGUE_CR_RASTERISATION_PERF_SELECT0_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define ROGUE_CR_RASTERISATION_PERF_SELECT0_BATCH_MIN_SHIFT 32U +#define ROGUE_CR_RASTERISATION_PERF_SELECT0_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define ROGUE_CR_RASTERISATION_PERF_SELECT0_MODE_SHIFT 21U +#define ROGUE_CR_RASTERISATION_PERF_SELECT0_MODE_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define ROGUE_CR_RASTERISATION_PERF_SELECT0_MODE_EN 0x0000000000200000ULL +#define ROGUE_CR_RASTERISATION_PERF_SELECT0_GROUP_SELECT_SHIFT 16U +#define ROGUE_CR_RASTERISATION_PERF_SELECT0_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFE0FFFFULL +#define ROGUE_CR_RASTERISATION_PERF_SELECT0_BIT_SELECT_SHIFT 0U +#define ROGUE_CR_RASTERISATION_PERF_SELECT0_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_RASTERISATION_PERF_COUNTER_0 */ +#define ROGUE_CR_RASTERISATION_PERF_COUNTER_0 0x7750U +#define ROGUE_CR_RASTERISATION_PERF_COUNTER_0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_RASTERISATION_PERF_COUNTER_0_REG_SHIFT 0U +#define ROGUE_CR_RASTERISATION_PERF_COUNTER_0_REG_CLRMSK 0x00000000U + +/* Register ROGUE_CR_HUB_BIFPMCACHE_PERF */ +#define ROGUE_CR_HUB_BIFPMCACHE_PERF 0x7800U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_MASKFULL 0x000000000000001FULL +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_CLR_3_SHIFT 4U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_CLR_3_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_CLR_3_EN 0x00000010U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_CLR_2_SHIFT 3U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_CLR_2_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_CLR_2_EN 0x00000008U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_CLR_1_SHIFT 2U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_CLR_1_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_CLR_1_EN 0x00000004U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_CLR_0_SHIFT 1U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_CLR_0_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_CLR_0_EN 0x00000002U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_CTRL_ENABLE_SHIFT 0U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_CTRL_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_CTRL_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_HUB_BIFPMCACHE_PERF_SELECT0 */ +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_SELECT0 0x7808U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_SELECT0_MASKFULL 0x3FFF3FFF003FFFFFULL +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_SELECT0_BATCH_MAX_SHIFT 48U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_SELECT0_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_SELECT0_BATCH_MIN_SHIFT 32U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_SELECT0_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_SELECT0_MODE_SHIFT 21U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_SELECT0_MODE_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_SELECT0_MODE_EN 0x0000000000200000ULL +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_SELECT0_GROUP_SELECT_SHIFT 16U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_SELECT0_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFE0FFFFULL +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_SELECT0_BIT_SELECT_SHIFT 0U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_SELECT0_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_HUB_BIFPMCACHE_PERF_COUNTER_0 */ +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_COUNTER_0 0x7850U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_COUNTER_0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_COUNTER_0_REG_SHIFT 0U +#define ROGUE_CR_HUB_BIFPMCACHE_PERF_COUNTER_0_REG_CLRMSK 0x00000000U + +/* Register ROGUE_CR_TPU_MCU_L0_PERF */ +#define ROGUE_CR_TPU_MCU_L0_PERF 0x7900U +#define ROGUE_CR_TPU_MCU_L0_PERF_MASKFULL 0x000000000000001FULL +#define ROGUE_CR_TPU_MCU_L0_PERF_CLR_3_SHIFT 4U +#define ROGUE_CR_TPU_MCU_L0_PERF_CLR_3_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_TPU_MCU_L0_PERF_CLR_3_EN 0x00000010U +#define ROGUE_CR_TPU_MCU_L0_PERF_CLR_2_SHIFT 3U +#define ROGUE_CR_TPU_MCU_L0_PERF_CLR_2_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_TPU_MCU_L0_PERF_CLR_2_EN 0x00000008U +#define ROGUE_CR_TPU_MCU_L0_PERF_CLR_1_SHIFT 2U +#define ROGUE_CR_TPU_MCU_L0_PERF_CLR_1_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_TPU_MCU_L0_PERF_CLR_1_EN 0x00000004U +#define ROGUE_CR_TPU_MCU_L0_PERF_CLR_0_SHIFT 1U +#define ROGUE_CR_TPU_MCU_L0_PERF_CLR_0_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_TPU_MCU_L0_PERF_CLR_0_EN 0x00000002U +#define ROGUE_CR_TPU_MCU_L0_PERF_CTRL_ENABLE_SHIFT 0U +#define ROGUE_CR_TPU_MCU_L0_PERF_CTRL_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_TPU_MCU_L0_PERF_CTRL_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_TPU_MCU_L0_PERF_SELECT0 */ +#define ROGUE_CR_TPU_MCU_L0_PERF_SELECT0 0x7908U +#define ROGUE_CR_TPU_MCU_L0_PERF_SELECT0_MASKFULL 0x3FFF3FFF003FFFFFULL +#define ROGUE_CR_TPU_MCU_L0_PERF_SELECT0_BATCH_MAX_SHIFT 48U +#define ROGUE_CR_TPU_MCU_L0_PERF_SELECT0_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define ROGUE_CR_TPU_MCU_L0_PERF_SELECT0_BATCH_MIN_SHIFT 32U +#define ROGUE_CR_TPU_MCU_L0_PERF_SELECT0_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define ROGUE_CR_TPU_MCU_L0_PERF_SELECT0_MODE_SHIFT 21U +#define ROGUE_CR_TPU_MCU_L0_PERF_SELECT0_MODE_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define ROGUE_CR_TPU_MCU_L0_PERF_SELECT0_MODE_EN 0x0000000000200000ULL +#define ROGUE_CR_TPU_MCU_L0_PERF_SELECT0_GROUP_SELECT_SHIFT 16U +#define ROGUE_CR_TPU_MCU_L0_PERF_SELECT0_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFE0FFFFULL +#define ROGUE_CR_TPU_MCU_L0_PERF_SELECT0_BIT_SELECT_SHIFT 0U +#define ROGUE_CR_TPU_MCU_L0_PERF_SELECT0_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_TPU_MCU_L0_PERF_COUNTER_0 */ +#define ROGUE_CR_TPU_MCU_L0_PERF_COUNTER_0 0x7950U +#define ROGUE_CR_TPU_MCU_L0_PERF_COUNTER_0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_TPU_MCU_L0_PERF_COUNTER_0_REG_SHIFT 0U +#define ROGUE_CR_TPU_MCU_L0_PERF_COUNTER_0_REG_CLRMSK 0x00000000U + +/* Register ROGUE_CR_USC_PERF */ +#define ROGUE_CR_USC_PERF 0x8100U +#define ROGUE_CR_USC_PERF_MASKFULL 0x000000000000001FULL +#define ROGUE_CR_USC_PERF_CLR_3_SHIFT 4U +#define ROGUE_CR_USC_PERF_CLR_3_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_USC_PERF_CLR_3_EN 0x00000010U +#define ROGUE_CR_USC_PERF_CLR_2_SHIFT 3U +#define ROGUE_CR_USC_PERF_CLR_2_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_USC_PERF_CLR_2_EN 0x00000008U +#define ROGUE_CR_USC_PERF_CLR_1_SHIFT 2U +#define ROGUE_CR_USC_PERF_CLR_1_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_USC_PERF_CLR_1_EN 0x00000004U +#define ROGUE_CR_USC_PERF_CLR_0_SHIFT 1U +#define ROGUE_CR_USC_PERF_CLR_0_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_USC_PERF_CLR_0_EN 0x00000002U +#define ROGUE_CR_USC_PERF_CTRL_ENABLE_SHIFT 0U +#define ROGUE_CR_USC_PERF_CTRL_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_USC_PERF_CTRL_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_USC_PERF_SELECT0 */ +#define ROGUE_CR_USC_PERF_SELECT0 0x8108U +#define ROGUE_CR_USC_PERF_SELECT0_MASKFULL 0x3FFF3FFF003FFFFFULL +#define ROGUE_CR_USC_PERF_SELECT0_BATCH_MAX_SHIFT 48U +#define ROGUE_CR_USC_PERF_SELECT0_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define ROGUE_CR_USC_PERF_SELECT0_BATCH_MIN_SHIFT 32U +#define ROGUE_CR_USC_PERF_SELECT0_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define ROGUE_CR_USC_PERF_SELECT0_MODE_SHIFT 21U +#define ROGUE_CR_USC_PERF_SELECT0_MODE_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define ROGUE_CR_USC_PERF_SELECT0_MODE_EN 0x0000000000200000ULL +#define ROGUE_CR_USC_PERF_SELECT0_GROUP_SELECT_SHIFT 16U +#define ROGUE_CR_USC_PERF_SELECT0_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFE0FFFFULL +#define ROGUE_CR_USC_PERF_SELECT0_BIT_SELECT_SHIFT 0U +#define ROGUE_CR_USC_PERF_SELECT0_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_USC_PERF_COUNTER_0 */ +#define ROGUE_CR_USC_PERF_COUNTER_0 0x8150U +#define ROGUE_CR_USC_PERF_COUNTER_0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_USC_PERF_COUNTER_0_REG_SHIFT 0U +#define ROGUE_CR_USC_PERF_COUNTER_0_REG_CLRMSK 0x00000000U + +/* Register ROGUE_CR_JONES_IDLE */ +#define ROGUE_CR_JONES_IDLE 0x8328U +#define ROGUE_CR_JONES_IDLE_MASKFULL 0x0000000000007FFFULL +#define ROGUE_CR_JONES_IDLE_TDM_SHIFT 14U +#define ROGUE_CR_JONES_IDLE_TDM_CLRMSK 0xFFFFBFFFU +#define ROGUE_CR_JONES_IDLE_TDM_EN 0x00004000U +#define ROGUE_CR_JONES_IDLE_FB_CDC_TLA_SHIFT 13U +#define ROGUE_CR_JONES_IDLE_FB_CDC_TLA_CLRMSK 0xFFFFDFFFU +#define ROGUE_CR_JONES_IDLE_FB_CDC_TLA_EN 0x00002000U +#define ROGUE_CR_JONES_IDLE_FB_CDC_SHIFT 12U +#define ROGUE_CR_JONES_IDLE_FB_CDC_CLRMSK 0xFFFFEFFFU +#define ROGUE_CR_JONES_IDLE_FB_CDC_EN 0x00001000U +#define ROGUE_CR_JONES_IDLE_MMU_SHIFT 11U +#define ROGUE_CR_JONES_IDLE_MMU_CLRMSK 0xFFFFF7FFU +#define ROGUE_CR_JONES_IDLE_MMU_EN 0x00000800U +#define ROGUE_CR_JONES_IDLE_TLA_SHIFT 10U +#define ROGUE_CR_JONES_IDLE_TLA_CLRMSK 0xFFFFFBFFU +#define ROGUE_CR_JONES_IDLE_TLA_EN 0x00000400U +#define ROGUE_CR_JONES_IDLE_GARTEN_SHIFT 9U +#define ROGUE_CR_JONES_IDLE_GARTEN_CLRMSK 0xFFFFFDFFU +#define ROGUE_CR_JONES_IDLE_GARTEN_EN 0x00000200U +#define ROGUE_CR_JONES_IDLE_HOSTIF_SHIFT 8U +#define ROGUE_CR_JONES_IDLE_HOSTIF_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_JONES_IDLE_HOSTIF_EN 0x00000100U +#define ROGUE_CR_JONES_IDLE_SOCIF_SHIFT 7U +#define ROGUE_CR_JONES_IDLE_SOCIF_CLRMSK 0xFFFFFF7FU +#define ROGUE_CR_JONES_IDLE_SOCIF_EN 0x00000080U +#define ROGUE_CR_JONES_IDLE_TILING_SHIFT 6U +#define ROGUE_CR_JONES_IDLE_TILING_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_JONES_IDLE_TILING_EN 0x00000040U +#define ROGUE_CR_JONES_IDLE_IPP_SHIFT 5U +#define ROGUE_CR_JONES_IDLE_IPP_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_JONES_IDLE_IPP_EN 0x00000020U +#define ROGUE_CR_JONES_IDLE_USCS_SHIFT 4U +#define ROGUE_CR_JONES_IDLE_USCS_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_JONES_IDLE_USCS_EN 0x00000010U +#define ROGUE_CR_JONES_IDLE_PM_SHIFT 3U +#define ROGUE_CR_JONES_IDLE_PM_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_JONES_IDLE_PM_EN 0x00000008U +#define ROGUE_CR_JONES_IDLE_CDM_SHIFT 2U +#define ROGUE_CR_JONES_IDLE_CDM_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_JONES_IDLE_CDM_EN 0x00000004U +#define ROGUE_CR_JONES_IDLE_VDM_SHIFT 1U +#define ROGUE_CR_JONES_IDLE_VDM_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_JONES_IDLE_VDM_EN 0x00000002U +#define ROGUE_CR_JONES_IDLE_BIF_SHIFT 0U +#define ROGUE_CR_JONES_IDLE_BIF_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_JONES_IDLE_BIF_EN 0x00000001U + +/* Register ROGUE_CR_TORNADO_PERF */ +#define ROGUE_CR_TORNADO_PERF 0x8228U +#define ROGUE_CR_TORNADO_PERF_MASKFULL 0x000000000000001FULL +#define ROGUE_CR_TORNADO_PERF_CLR_3_SHIFT 4U +#define ROGUE_CR_TORNADO_PERF_CLR_3_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_TORNADO_PERF_CLR_3_EN 0x00000010U +#define ROGUE_CR_TORNADO_PERF_CLR_2_SHIFT 3U +#define ROGUE_CR_TORNADO_PERF_CLR_2_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_TORNADO_PERF_CLR_2_EN 0x00000008U +#define ROGUE_CR_TORNADO_PERF_CLR_1_SHIFT 2U +#define ROGUE_CR_TORNADO_PERF_CLR_1_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_TORNADO_PERF_CLR_1_EN 0x00000004U +#define ROGUE_CR_TORNADO_PERF_CLR_0_SHIFT 1U +#define ROGUE_CR_TORNADO_PERF_CLR_0_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_TORNADO_PERF_CLR_0_EN 0x00000002U +#define ROGUE_CR_TORNADO_PERF_CTRL_ENABLE_SHIFT 0U +#define ROGUE_CR_TORNADO_PERF_CTRL_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_TORNADO_PERF_CTRL_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_TORNADO_PERF_SELECT0 */ +#define ROGUE_CR_TORNADO_PERF_SELECT0 0x8230U +#define ROGUE_CR_TORNADO_PERF_SELECT0_MASKFULL 0x3FFF3FFF003FFFFFULL +#define ROGUE_CR_TORNADO_PERF_SELECT0_BATCH_MAX_SHIFT 48U +#define ROGUE_CR_TORNADO_PERF_SELECT0_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define ROGUE_CR_TORNADO_PERF_SELECT0_BATCH_MIN_SHIFT 32U +#define ROGUE_CR_TORNADO_PERF_SELECT0_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define ROGUE_CR_TORNADO_PERF_SELECT0_MODE_SHIFT 21U +#define ROGUE_CR_TORNADO_PERF_SELECT0_MODE_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define ROGUE_CR_TORNADO_PERF_SELECT0_MODE_EN 0x0000000000200000ULL +#define ROGUE_CR_TORNADO_PERF_SELECT0_GROUP_SELECT_SHIFT 16U +#define ROGUE_CR_TORNADO_PERF_SELECT0_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFE0FFFFULL +#define ROGUE_CR_TORNADO_PERF_SELECT0_BIT_SELECT_SHIFT 0U +#define ROGUE_CR_TORNADO_PERF_SELECT0_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_TORNADO_PERF_COUNTER_0 */ +#define ROGUE_CR_TORNADO_PERF_COUNTER_0 0x8268U +#define ROGUE_CR_TORNADO_PERF_COUNTER_0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_TORNADO_PERF_COUNTER_0_REG_SHIFT 0U +#define ROGUE_CR_TORNADO_PERF_COUNTER_0_REG_CLRMSK 0x00000000U + +/* Register ROGUE_CR_TEXAS_PERF */ +#define ROGUE_CR_TEXAS_PERF 0x8290U +#define ROGUE_CR_TEXAS_PERF_MASKFULL 0x000000000000007FULL +#define ROGUE_CR_TEXAS_PERF_CLR_5_SHIFT 6U +#define ROGUE_CR_TEXAS_PERF_CLR_5_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_TEXAS_PERF_CLR_5_EN 0x00000040U +#define ROGUE_CR_TEXAS_PERF_CLR_4_SHIFT 5U +#define ROGUE_CR_TEXAS_PERF_CLR_4_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_TEXAS_PERF_CLR_4_EN 0x00000020U +#define ROGUE_CR_TEXAS_PERF_CLR_3_SHIFT 4U +#define ROGUE_CR_TEXAS_PERF_CLR_3_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_TEXAS_PERF_CLR_3_EN 0x00000010U +#define ROGUE_CR_TEXAS_PERF_CLR_2_SHIFT 3U +#define ROGUE_CR_TEXAS_PERF_CLR_2_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_TEXAS_PERF_CLR_2_EN 0x00000008U +#define ROGUE_CR_TEXAS_PERF_CLR_1_SHIFT 2U +#define ROGUE_CR_TEXAS_PERF_CLR_1_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_TEXAS_PERF_CLR_1_EN 0x00000004U +#define ROGUE_CR_TEXAS_PERF_CLR_0_SHIFT 1U +#define ROGUE_CR_TEXAS_PERF_CLR_0_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_TEXAS_PERF_CLR_0_EN 0x00000002U +#define ROGUE_CR_TEXAS_PERF_CTRL_ENABLE_SHIFT 0U +#define ROGUE_CR_TEXAS_PERF_CTRL_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_TEXAS_PERF_CTRL_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_TEXAS_PERF_SELECT0 */ +#define ROGUE_CR_TEXAS_PERF_SELECT0 0x8298U +#define ROGUE_CR_TEXAS_PERF_SELECT0_MASKFULL 0x3FFF3FFF803FFFFFULL +#define ROGUE_CR_TEXAS_PERF_SELECT0_BATCH_MAX_SHIFT 48U +#define ROGUE_CR_TEXAS_PERF_SELECT0_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define ROGUE_CR_TEXAS_PERF_SELECT0_BATCH_MIN_SHIFT 32U +#define ROGUE_CR_TEXAS_PERF_SELECT0_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define ROGUE_CR_TEXAS_PERF_SELECT0_MODE_SHIFT 31U +#define ROGUE_CR_TEXAS_PERF_SELECT0_MODE_CLRMSK 0xFFFFFFFF7FFFFFFFULL +#define ROGUE_CR_TEXAS_PERF_SELECT0_MODE_EN 0x0000000080000000ULL +#define ROGUE_CR_TEXAS_PERF_SELECT0_GROUP_SELECT_SHIFT 16U +#define ROGUE_CR_TEXAS_PERF_SELECT0_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFC0FFFFULL +#define ROGUE_CR_TEXAS_PERF_SELECT0_BIT_SELECT_SHIFT 0U +#define ROGUE_CR_TEXAS_PERF_SELECT0_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_TEXAS_PERF_COUNTER_0 */ +#define ROGUE_CR_TEXAS_PERF_COUNTER_0 0x82D8U +#define ROGUE_CR_TEXAS_PERF_COUNTER_0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_TEXAS_PERF_COUNTER_0_REG_SHIFT 0U +#define ROGUE_CR_TEXAS_PERF_COUNTER_0_REG_CLRMSK 0x00000000U + +/* Register ROGUE_CR_JONES_PERF */ +#define ROGUE_CR_JONES_PERF 0x8330U +#define ROGUE_CR_JONES_PERF_MASKFULL 0x000000000000001FULL +#define ROGUE_CR_JONES_PERF_CLR_3_SHIFT 4U +#define ROGUE_CR_JONES_PERF_CLR_3_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_JONES_PERF_CLR_3_EN 0x00000010U +#define ROGUE_CR_JONES_PERF_CLR_2_SHIFT 3U +#define ROGUE_CR_JONES_PERF_CLR_2_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_JONES_PERF_CLR_2_EN 0x00000008U +#define ROGUE_CR_JONES_PERF_CLR_1_SHIFT 2U +#define ROGUE_CR_JONES_PERF_CLR_1_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_JONES_PERF_CLR_1_EN 0x00000004U +#define ROGUE_CR_JONES_PERF_CLR_0_SHIFT 1U +#define ROGUE_CR_JONES_PERF_CLR_0_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_JONES_PERF_CLR_0_EN 0x00000002U +#define ROGUE_CR_JONES_PERF_CTRL_ENABLE_SHIFT 0U +#define ROGUE_CR_JONES_PERF_CTRL_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_JONES_PERF_CTRL_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_JONES_PERF_SELECT0 */ +#define ROGUE_CR_JONES_PERF_SELECT0 0x8338U +#define ROGUE_CR_JONES_PERF_SELECT0_MASKFULL 0x3FFF3FFF003FFFFFULL +#define ROGUE_CR_JONES_PERF_SELECT0_BATCH_MAX_SHIFT 48U +#define ROGUE_CR_JONES_PERF_SELECT0_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define ROGUE_CR_JONES_PERF_SELECT0_BATCH_MIN_SHIFT 32U +#define ROGUE_CR_JONES_PERF_SELECT0_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define ROGUE_CR_JONES_PERF_SELECT0_MODE_SHIFT 21U +#define ROGUE_CR_JONES_PERF_SELECT0_MODE_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define ROGUE_CR_JONES_PERF_SELECT0_MODE_EN 0x0000000000200000ULL +#define ROGUE_CR_JONES_PERF_SELECT0_GROUP_SELECT_SHIFT 16U +#define ROGUE_CR_JONES_PERF_SELECT0_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFE0FFFFULL +#define ROGUE_CR_JONES_PERF_SELECT0_BIT_SELECT_SHIFT 0U +#define ROGUE_CR_JONES_PERF_SELECT0_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_JONES_PERF_COUNTER_0 */ +#define ROGUE_CR_JONES_PERF_COUNTER_0 0x8368U +#define ROGUE_CR_JONES_PERF_COUNTER_0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_JONES_PERF_COUNTER_0_REG_SHIFT 0U +#define ROGUE_CR_JONES_PERF_COUNTER_0_REG_CLRMSK 0x00000000U + +/* Register ROGUE_CR_BLACKPEARL_PERF */ +#define ROGUE_CR_BLACKPEARL_PERF 0x8400U +#define ROGUE_CR_BLACKPEARL_PERF_MASKFULL 0x000000000000007FULL +#define ROGUE_CR_BLACKPEARL_PERF_CLR_5_SHIFT 6U +#define ROGUE_CR_BLACKPEARL_PERF_CLR_5_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_BLACKPEARL_PERF_CLR_5_EN 0x00000040U +#define ROGUE_CR_BLACKPEARL_PERF_CLR_4_SHIFT 5U +#define ROGUE_CR_BLACKPEARL_PERF_CLR_4_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_BLACKPEARL_PERF_CLR_4_EN 0x00000020U +#define ROGUE_CR_BLACKPEARL_PERF_CLR_3_SHIFT 4U +#define ROGUE_CR_BLACKPEARL_PERF_CLR_3_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_BLACKPEARL_PERF_CLR_3_EN 0x00000010U +#define ROGUE_CR_BLACKPEARL_PERF_CLR_2_SHIFT 3U +#define ROGUE_CR_BLACKPEARL_PERF_CLR_2_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_BLACKPEARL_PERF_CLR_2_EN 0x00000008U +#define ROGUE_CR_BLACKPEARL_PERF_CLR_1_SHIFT 2U +#define ROGUE_CR_BLACKPEARL_PERF_CLR_1_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_BLACKPEARL_PERF_CLR_1_EN 0x00000004U +#define ROGUE_CR_BLACKPEARL_PERF_CLR_0_SHIFT 1U +#define ROGUE_CR_BLACKPEARL_PERF_CLR_0_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_BLACKPEARL_PERF_CLR_0_EN 0x00000002U +#define ROGUE_CR_BLACKPEARL_PERF_CTRL_ENABLE_SHIFT 0U +#define ROGUE_CR_BLACKPEARL_PERF_CTRL_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_BLACKPEARL_PERF_CTRL_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_BLACKPEARL_PERF_SELECT0 */ +#define ROGUE_CR_BLACKPEARL_PERF_SELECT0 0x8408U +#define ROGUE_CR_BLACKPEARL_PERF_SELECT0_MASKFULL 0x3FFF3FFF803FFFFFULL +#define ROGUE_CR_BLACKPEARL_PERF_SELECT0_BATCH_MAX_SHIFT 48U +#define ROGUE_CR_BLACKPEARL_PERF_SELECT0_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define ROGUE_CR_BLACKPEARL_PERF_SELECT0_BATCH_MIN_SHIFT 32U +#define ROGUE_CR_BLACKPEARL_PERF_SELECT0_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define ROGUE_CR_BLACKPEARL_PERF_SELECT0_MODE_SHIFT 31U +#define ROGUE_CR_BLACKPEARL_PERF_SELECT0_MODE_CLRMSK 0xFFFFFFFF7FFFFFFFULL +#define ROGUE_CR_BLACKPEARL_PERF_SELECT0_MODE_EN 0x0000000080000000ULL +#define ROGUE_CR_BLACKPEARL_PERF_SELECT0_GROUP_SELECT_SHIFT 16U +#define ROGUE_CR_BLACKPEARL_PERF_SELECT0_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFC0FFFFULL +#define ROGUE_CR_BLACKPEARL_PERF_SELECT0_BIT_SELECT_SHIFT 0U +#define ROGUE_CR_BLACKPEARL_PERF_SELECT0_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_BLACKPEARL_PERF_COUNTER_0 */ +#define ROGUE_CR_BLACKPEARL_PERF_COUNTER_0 0x8448U +#define ROGUE_CR_BLACKPEARL_PERF_COUNTER_0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_BLACKPEARL_PERF_COUNTER_0_REG_SHIFT 0U +#define ROGUE_CR_BLACKPEARL_PERF_COUNTER_0_REG_CLRMSK 0x00000000U + +/* Register ROGUE_CR_PBE_PERF */ +#define ROGUE_CR_PBE_PERF 0x8478U +#define ROGUE_CR_PBE_PERF_MASKFULL 0x000000000000001FULL +#define ROGUE_CR_PBE_PERF_CLR_3_SHIFT 4U +#define ROGUE_CR_PBE_PERF_CLR_3_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_PBE_PERF_CLR_3_EN 0x00000010U +#define ROGUE_CR_PBE_PERF_CLR_2_SHIFT 3U +#define ROGUE_CR_PBE_PERF_CLR_2_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_PBE_PERF_CLR_2_EN 0x00000008U +#define ROGUE_CR_PBE_PERF_CLR_1_SHIFT 2U +#define ROGUE_CR_PBE_PERF_CLR_1_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_PBE_PERF_CLR_1_EN 0x00000004U +#define ROGUE_CR_PBE_PERF_CLR_0_SHIFT 1U +#define ROGUE_CR_PBE_PERF_CLR_0_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_PBE_PERF_CLR_0_EN 0x00000002U +#define ROGUE_CR_PBE_PERF_CTRL_ENABLE_SHIFT 0U +#define ROGUE_CR_PBE_PERF_CTRL_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_PBE_PERF_CTRL_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_PBE_PERF_SELECT0 */ +#define ROGUE_CR_PBE_PERF_SELECT0 0x8480U +#define ROGUE_CR_PBE_PERF_SELECT0_MASKFULL 0x3FFF3FFF003FFFFFULL +#define ROGUE_CR_PBE_PERF_SELECT0_BATCH_MAX_SHIFT 48U +#define ROGUE_CR_PBE_PERF_SELECT0_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define ROGUE_CR_PBE_PERF_SELECT0_BATCH_MIN_SHIFT 32U +#define ROGUE_CR_PBE_PERF_SELECT0_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define ROGUE_CR_PBE_PERF_SELECT0_MODE_SHIFT 21U +#define ROGUE_CR_PBE_PERF_SELECT0_MODE_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define ROGUE_CR_PBE_PERF_SELECT0_MODE_EN 0x0000000000200000ULL +#define ROGUE_CR_PBE_PERF_SELECT0_GROUP_SELECT_SHIFT 16U +#define ROGUE_CR_PBE_PERF_SELECT0_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFE0FFFFULL +#define ROGUE_CR_PBE_PERF_SELECT0_BIT_SELECT_SHIFT 0U +#define ROGUE_CR_PBE_PERF_SELECT0_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_PBE_PERF_COUNTER_0 */ +#define ROGUE_CR_PBE_PERF_COUNTER_0 0x84B0U +#define ROGUE_CR_PBE_PERF_COUNTER_0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_PBE_PERF_COUNTER_0_REG_SHIFT 0U +#define ROGUE_CR_PBE_PERF_COUNTER_0_REG_CLRMSK 0x00000000U + +/* Register ROGUE_CR_OCP_REVINFO */ +#define ROGUE_CR_OCP_REVINFO 0x9000U +#define ROGUE_CR_OCP_REVINFO_MASKFULL 0x00000007FFFFFFFFULL +#define ROGUE_CR_OCP_REVINFO_HWINFO_SYSBUS_SHIFT 33U +#define ROGUE_CR_OCP_REVINFO_HWINFO_SYSBUS_CLRMSK 0xFFFFFFF9FFFFFFFFULL +#define ROGUE_CR_OCP_REVINFO_HWINFO_MEMBUS_SHIFT 32U +#define ROGUE_CR_OCP_REVINFO_HWINFO_MEMBUS_CLRMSK 0xFFFFFFFEFFFFFFFFULL +#define ROGUE_CR_OCP_REVINFO_HWINFO_MEMBUS_EN 0x0000000100000000ULL +#define ROGUE_CR_OCP_REVINFO_REVISION_SHIFT 0U +#define ROGUE_CR_OCP_REVINFO_REVISION_CLRMSK 0xFFFFFFFF00000000ULL + +/* Register ROGUE_CR_OCP_SYSCONFIG */ +#define ROGUE_CR_OCP_SYSCONFIG 0x9010U +#define ROGUE_CR_OCP_SYSCONFIG_MASKFULL 0x0000000000000FFFULL +#define ROGUE_CR_OCP_SYSCONFIG_DUST2_STANDBY_MODE_SHIFT 10U +#define ROGUE_CR_OCP_SYSCONFIG_DUST2_STANDBY_MODE_CLRMSK 0xFFFFF3FFU +#define ROGUE_CR_OCP_SYSCONFIG_DUST1_STANDBY_MODE_SHIFT 8U +#define ROGUE_CR_OCP_SYSCONFIG_DUST1_STANDBY_MODE_CLRMSK 0xFFFFFCFFU +#define ROGUE_CR_OCP_SYSCONFIG_DUST0_STANDBY_MODE_SHIFT 6U +#define ROGUE_CR_OCP_SYSCONFIG_DUST0_STANDBY_MODE_CLRMSK 0xFFFFFF3FU +#define ROGUE_CR_OCP_SYSCONFIG_RASCAL_STANDBYMODE_SHIFT 4U +#define ROGUE_CR_OCP_SYSCONFIG_RASCAL_STANDBYMODE_CLRMSK 0xFFFFFFCFU +#define ROGUE_CR_OCP_SYSCONFIG_STANDBY_MODE_SHIFT 2U +#define ROGUE_CR_OCP_SYSCONFIG_STANDBY_MODE_CLRMSK 0xFFFFFFF3U +#define ROGUE_CR_OCP_SYSCONFIG_IDLE_MODE_SHIFT 0U +#define ROGUE_CR_OCP_SYSCONFIG_IDLE_MODE_CLRMSK 0xFFFFFFFCU + +/* Register ROGUE_CR_OCP_IRQSTATUS_RAW_0 */ +#define ROGUE_CR_OCP_IRQSTATUS_RAW_0 0x9020U +#define ROGUE_CR_OCP_IRQSTATUS_RAW_0_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_OCP_IRQSTATUS_RAW_0_INIT_MINTERRUPT_RAW_SHIFT 0U +#define ROGUE_CR_OCP_IRQSTATUS_RAW_0_INIT_MINTERRUPT_RAW_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_OCP_IRQSTATUS_RAW_0_INIT_MINTERRUPT_RAW_EN 0x00000001U + +/* Register ROGUE_CR_OCP_IRQSTATUS_RAW_1 */ +#define ROGUE_CR_OCP_IRQSTATUS_RAW_1 0x9028U +#define ROGUE_CR_OCP_IRQSTATUS_RAW_1_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_OCP_IRQSTATUS_RAW_1_TARGET_SINTERRUPT_RAW_SHIFT 0U +#define ROGUE_CR_OCP_IRQSTATUS_RAW_1_TARGET_SINTERRUPT_RAW_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_OCP_IRQSTATUS_RAW_1_TARGET_SINTERRUPT_RAW_EN 0x00000001U + +/* Register ROGUE_CR_OCP_IRQSTATUS_RAW_2 */ +#define ROGUE_CR_OCP_IRQSTATUS_RAW_2 0x9030U +#define ROGUE_CR_OCP_IRQSTATUS_RAW_2_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_OCP_IRQSTATUS_RAW_2_RGX_IRQ_RAW_SHIFT 0U +#define ROGUE_CR_OCP_IRQSTATUS_RAW_2_RGX_IRQ_RAW_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_OCP_IRQSTATUS_RAW_2_RGX_IRQ_RAW_EN 0x00000001U + +/* Register ROGUE_CR_OCP_IRQSTATUS_0 */ +#define ROGUE_CR_OCP_IRQSTATUS_0 0x9038U +#define ROGUE_CR_OCP_IRQSTATUS_0_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_OCP_IRQSTATUS_0_INIT_MINTERRUPT_STATUS_SHIFT 0U +#define ROGUE_CR_OCP_IRQSTATUS_0_INIT_MINTERRUPT_STATUS_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_OCP_IRQSTATUS_0_INIT_MINTERRUPT_STATUS_EN 0x00000001U + +/* Register ROGUE_CR_OCP_IRQSTATUS_1 */ +#define ROGUE_CR_OCP_IRQSTATUS_1 0x9040U +#define ROGUE_CR_OCP_IRQSTATUS_1_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_OCP_IRQSTATUS_1_TARGET_SINTERRUPT_STATUS_SHIFT 0U +#define ROGUE_CR_OCP_IRQSTATUS_1_TARGET_SINTERRUPT_STATUS_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_OCP_IRQSTATUS_1_TARGET_SINTERRUPT_STATUS_EN 0x00000001U + +/* Register ROGUE_CR_OCP_IRQSTATUS_2 */ +#define ROGUE_CR_OCP_IRQSTATUS_2 0x9048U +#define ROGUE_CR_OCP_IRQSTATUS_2_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_OCP_IRQSTATUS_2_RGX_IRQ_STATUS_SHIFT 0U +#define ROGUE_CR_OCP_IRQSTATUS_2_RGX_IRQ_STATUS_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_OCP_IRQSTATUS_2_RGX_IRQ_STATUS_EN 0x00000001U + +/* Register ROGUE_CR_OCP_IRQENABLE_SET_0 */ +#define ROGUE_CR_OCP_IRQENABLE_SET_0 0x9050U +#define ROGUE_CR_OCP_IRQENABLE_SET_0_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_OCP_IRQENABLE_SET_0_INIT_MINTERRUPT_ENABLE_SHIFT 0U +#define ROGUE_CR_OCP_IRQENABLE_SET_0_INIT_MINTERRUPT_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_OCP_IRQENABLE_SET_0_INIT_MINTERRUPT_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_OCP_IRQENABLE_SET_1 */ +#define ROGUE_CR_OCP_IRQENABLE_SET_1 0x9058U +#define ROGUE_CR_OCP_IRQENABLE_SET_1_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_OCP_IRQENABLE_SET_1_TARGET_SINTERRUPT_ENABLE_SHIFT 0U +#define ROGUE_CR_OCP_IRQENABLE_SET_1_TARGET_SINTERRUPT_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_OCP_IRQENABLE_SET_1_TARGET_SINTERRUPT_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_OCP_IRQENABLE_SET_2 */ +#define ROGUE_CR_OCP_IRQENABLE_SET_2 0x9060U +#define ROGUE_CR_OCP_IRQENABLE_SET_2_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_OCP_IRQENABLE_SET_2_RGX_IRQ_ENABLE_SHIFT 0U +#define ROGUE_CR_OCP_IRQENABLE_SET_2_RGX_IRQ_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_OCP_IRQENABLE_SET_2_RGX_IRQ_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_OCP_IRQENABLE_CLR_0 */ +#define ROGUE_CR_OCP_IRQENABLE_CLR_0 0x9068U +#define ROGUE_CR_OCP_IRQENABLE_CLR_0_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_OCP_IRQENABLE_CLR_0_INIT_MINTERRUPT_DISABLE_SHIFT 0U +#define ROGUE_CR_OCP_IRQENABLE_CLR_0_INIT_MINTERRUPT_DISABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_OCP_IRQENABLE_CLR_0_INIT_MINTERRUPT_DISABLE_EN 0x00000001U + +/* Register ROGUE_CR_OCP_IRQENABLE_CLR_1 */ +#define ROGUE_CR_OCP_IRQENABLE_CLR_1 0x9070U +#define ROGUE_CR_OCP_IRQENABLE_CLR_1_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_OCP_IRQENABLE_CLR_1_TARGET_SINTERRUPT_DISABLE_SHIFT 0U +#define ROGUE_CR_OCP_IRQENABLE_CLR_1_TARGET_SINTERRUPT_DISABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_OCP_IRQENABLE_CLR_1_TARGET_SINTERRUPT_DISABLE_EN 0x00000001U + +/* Register ROGUE_CR_OCP_IRQENABLE_CLR_2 */ +#define ROGUE_CR_OCP_IRQENABLE_CLR_2 0x9078U +#define ROGUE_CR_OCP_IRQENABLE_CLR_2_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_OCP_IRQENABLE_CLR_2_RGX_IRQ_DISABLE_SHIFT 0U +#define ROGUE_CR_OCP_IRQENABLE_CLR_2_RGX_IRQ_DISABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_OCP_IRQENABLE_CLR_2_RGX_IRQ_DISABLE_EN 0x00000001U + +/* Register ROGUE_CR_OCP_IRQ_EVENT */ +#define ROGUE_CR_OCP_IRQ_EVENT 0x9080U +#define ROGUE_CR_OCP_IRQ_EVENT_MASKFULL 0x00000000000FFFFFULL +#define ROGUE_CR_OCP_IRQ_EVENT_TARGETH_RCVD_UNEXPECTED_RDATA_SHIFT 19U +#define ROGUE_CR_OCP_IRQ_EVENT_TARGETH_RCVD_UNEXPECTED_RDATA_CLRMSK 0xFFFFFFFFFFF7FFFFULL +#define ROGUE_CR_OCP_IRQ_EVENT_TARGETH_RCVD_UNEXPECTED_RDATA_EN 0x0000000000080000ULL +#define ROGUE_CR_OCP_IRQ_EVENT_TARGETH_RCVD_UNSUPPORTED_MCMD_SHIFT 18U +#define ROGUE_CR_OCP_IRQ_EVENT_TARGETH_RCVD_UNSUPPORTED_MCMD_CLRMSK 0xFFFFFFFFFFFBFFFFULL +#define ROGUE_CR_OCP_IRQ_EVENT_TARGETH_RCVD_UNSUPPORTED_MCMD_EN 0x0000000000040000ULL +#define ROGUE_CR_OCP_IRQ_EVENT_TARGETS_RCVD_UNEXPECTED_RDATA_SHIFT 17U +#define ROGUE_CR_OCP_IRQ_EVENT_TARGETS_RCVD_UNEXPECTED_RDATA_CLRMSK 0xFFFFFFFFFFFDFFFFULL +#define ROGUE_CR_OCP_IRQ_EVENT_TARGETS_RCVD_UNEXPECTED_RDATA_EN 0x0000000000020000ULL +#define ROGUE_CR_OCP_IRQ_EVENT_TARGETS_RCVD_UNSUPPORTED_MCMD_SHIFT 16U +#define ROGUE_CR_OCP_IRQ_EVENT_TARGETS_RCVD_UNSUPPORTED_MCMD_CLRMSK 0xFFFFFFFFFFFEFFFFULL +#define ROGUE_CR_OCP_IRQ_EVENT_TARGETS_RCVD_UNSUPPORTED_MCMD_EN 0x0000000000010000ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT3_IMG_PAGE_BOUNDARY_CROSS_SHIFT 15U +#define ROGUE_CR_OCP_IRQ_EVENT_INIT3_IMG_PAGE_BOUNDARY_CROSS_CLRMSK 0xFFFFFFFFFFFF7FFFULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT3_IMG_PAGE_BOUNDARY_CROSS_EN 0x0000000000008000ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT3_RCVD_RESP_ERR_FAIL_SHIFT 14U +#define ROGUE_CR_OCP_IRQ_EVENT_INIT3_RCVD_RESP_ERR_FAIL_CLRMSK 0xFFFFFFFFFFFFBFFFULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT3_RCVD_RESP_ERR_FAIL_EN 0x0000000000004000ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT3_RCVD_UNUSED_TAGID_SHIFT 13U +#define ROGUE_CR_OCP_IRQ_EVENT_INIT3_RCVD_UNUSED_TAGID_CLRMSK 0xFFFFFFFFFFFFDFFFULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT3_RCVD_UNUSED_TAGID_EN 0x0000000000002000ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT3_RDATA_FIFO_OVERFILL_SHIFT 12U +#define ROGUE_CR_OCP_IRQ_EVENT_INIT3_RDATA_FIFO_OVERFILL_CLRMSK 0xFFFFFFFFFFFFEFFFULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT3_RDATA_FIFO_OVERFILL_EN 0x0000000000001000ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT2_IMG_PAGE_BOUNDARY_CROSS_SHIFT 11U +#define ROGUE_CR_OCP_IRQ_EVENT_INIT2_IMG_PAGE_BOUNDARY_CROSS_CLRMSK 0xFFFFFFFFFFFFF7FFULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT2_IMG_PAGE_BOUNDARY_CROSS_EN 0x0000000000000800ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT2_RCVD_RESP_ERR_FAIL_SHIFT 10U +#define ROGUE_CR_OCP_IRQ_EVENT_INIT2_RCVD_RESP_ERR_FAIL_CLRMSK 0xFFFFFFFFFFFFFBFFULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT2_RCVD_RESP_ERR_FAIL_EN 0x0000000000000400ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT2_RCVD_UNUSED_TAGID_SHIFT 9U +#define ROGUE_CR_OCP_IRQ_EVENT_INIT2_RCVD_UNUSED_TAGID_CLRMSK 0xFFFFFFFFFFFFFDFFULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT2_RCVD_UNUSED_TAGID_EN 0x0000000000000200ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT2_RDATA_FIFO_OVERFILL_SHIFT 8U +#define ROGUE_CR_OCP_IRQ_EVENT_INIT2_RDATA_FIFO_OVERFILL_CLRMSK 0xFFFFFFFFFFFFFEFFULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT2_RDATA_FIFO_OVERFILL_EN 0x0000000000000100ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT1_IMG_PAGE_BOUNDARY_CROSS_SHIFT 7U +#define ROGUE_CR_OCP_IRQ_EVENT_INIT1_IMG_PAGE_BOUNDARY_CROSS_CLRMSK 0xFFFFFFFFFFFFFF7FULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT1_IMG_PAGE_BOUNDARY_CROSS_EN 0x0000000000000080ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT1_RCVD_RESP_ERR_FAIL_SHIFT 6U +#define ROGUE_CR_OCP_IRQ_EVENT_INIT1_RCVD_RESP_ERR_FAIL_CLRMSK 0xFFFFFFFFFFFFFFBFULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT1_RCVD_RESP_ERR_FAIL_EN 0x0000000000000040ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT1_RCVD_UNUSED_TAGID_SHIFT 5U +#define ROGUE_CR_OCP_IRQ_EVENT_INIT1_RCVD_UNUSED_TAGID_CLRMSK 0xFFFFFFFFFFFFFFDFULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT1_RCVD_UNUSED_TAGID_EN 0x0000000000000020ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT1_RDATA_FIFO_OVERFILL_SHIFT 4U +#define ROGUE_CR_OCP_IRQ_EVENT_INIT1_RDATA_FIFO_OVERFILL_CLRMSK 0xFFFFFFFFFFFFFFEFULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT1_RDATA_FIFO_OVERFILL_EN 0x0000000000000010ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT0_IMG_PAGE_BOUNDARY_CROSS_SHIFT 3U +#define ROGUE_CR_OCP_IRQ_EVENT_INIT0_IMG_PAGE_BOUNDARY_CROSS_CLRMSK 0xFFFFFFFFFFFFFFF7ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT0_IMG_PAGE_BOUNDARY_CROSS_EN 0x0000000000000008ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT0_RCVD_RESP_ERR_FAIL_SHIFT 2U +#define ROGUE_CR_OCP_IRQ_EVENT_INIT0_RCVD_RESP_ERR_FAIL_CLRMSK 0xFFFFFFFFFFFFFFFBULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT0_RCVD_RESP_ERR_FAIL_EN 0x0000000000000004ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT0_RCVD_UNUSED_TAGID_SHIFT 1U +#define ROGUE_CR_OCP_IRQ_EVENT_INIT0_RCVD_UNUSED_TAGID_CLRMSK 0xFFFFFFFFFFFFFFFDULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT0_RCVD_UNUSED_TAGID_EN 0x0000000000000002ULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT0_RDATA_FIFO_OVERFILL_SHIFT 0U +#define ROGUE_CR_OCP_IRQ_EVENT_INIT0_RDATA_FIFO_OVERFILL_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_OCP_IRQ_EVENT_INIT0_RDATA_FIFO_OVERFILL_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_OCP_DEBUG_CONFIG */ +#define ROGUE_CR_OCP_DEBUG_CONFIG 0x9088U +#define ROGUE_CR_OCP_DEBUG_CONFIG_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_OCP_DEBUG_CONFIG_REG_SHIFT 0U +#define ROGUE_CR_OCP_DEBUG_CONFIG_REG_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_OCP_DEBUG_CONFIG_REG_EN 0x00000001U + +/* Register ROGUE_CR_OCP_DEBUG_STATUS */ +#define ROGUE_CR_OCP_DEBUG_STATUS 0x9090U +#define ROGUE_CR_OCP_DEBUG_STATUS_MASKFULL 0x001F1F77FFFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETH_SDISCACK_SHIFT 51U +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETH_SDISCACK_CLRMSK 0xFFE7FFFFFFFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETH_SCONNECT_SHIFT 50U +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETH_SCONNECT_CLRMSK 0xFFFBFFFFFFFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETH_SCONNECT_EN 0x0004000000000000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETH_MCONNECT_SHIFT 48U +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETH_MCONNECT_CLRMSK 0xFFFCFFFFFFFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETS_SDISCACK_SHIFT 43U +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETS_SDISCACK_CLRMSK 0xFFFFE7FFFFFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETS_SCONNECT_SHIFT 42U +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETS_SCONNECT_CLRMSK 0xFFFFFBFFFFFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETS_SCONNECT_EN 0x0000040000000000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETS_MCONNECT_SHIFT 40U +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETS_MCONNECT_CLRMSK 0xFFFFFCFFFFFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETH_BUSY_SHIFT 38U +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETH_BUSY_CLRMSK 0xFFFFFFBFFFFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETH_BUSY_EN 0x0000004000000000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETH_CMD_FIFO_FULL_SHIFT 37U +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETH_CMD_FIFO_FULL_CLRMSK 0xFFFFFFDFFFFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETH_CMD_FIFO_FULL_EN 0x0000002000000000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETH_SRESP_ERROR_SHIFT 36U +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETH_SRESP_ERROR_CLRMSK 0xFFFFFFEFFFFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETH_SRESP_ERROR_EN 0x0000001000000000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETS_BUSY_SHIFT 34U +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETS_BUSY_CLRMSK 0xFFFFFFFBFFFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETS_BUSY_EN 0x0000000400000000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETS_CMD_FIFO_FULL_SHIFT 33U +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETS_CMD_FIFO_FULL_CLRMSK 0xFFFFFFFDFFFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETS_CMD_FIFO_FULL_EN 0x0000000200000000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETS_SRESP_ERROR_SHIFT 32U +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETS_SRESP_ERROR_CLRMSK 0xFFFFFFFEFFFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_TARGETS_SRESP_ERROR_EN 0x0000000100000000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT3_RESERVED_SHIFT 31U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT3_RESERVED_CLRMSK 0xFFFFFFFF7FFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT3_RESERVED_EN 0x0000000080000000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT3_SWAIT_SHIFT 30U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT3_SWAIT_CLRMSK 0xFFFFFFFFBFFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT3_SWAIT_EN 0x0000000040000000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT3_MDISCREQ_SHIFT 29U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT3_MDISCREQ_CLRMSK 0xFFFFFFFFDFFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT3_MDISCREQ_EN 0x0000000020000000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT3_MDISCACK_SHIFT 27U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT3_MDISCACK_CLRMSK 0xFFFFFFFFE7FFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT3_SCONNECT_SHIFT 26U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT3_SCONNECT_CLRMSK 0xFFFFFFFFFBFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT3_SCONNECT_EN 0x0000000004000000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT3_MCONNECT_SHIFT 24U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT3_MCONNECT_CLRMSK 0xFFFFFFFFFCFFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT2_RESERVED_SHIFT 23U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT2_RESERVED_CLRMSK 0xFFFFFFFFFF7FFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT2_RESERVED_EN 0x0000000000800000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT2_SWAIT_SHIFT 22U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT2_SWAIT_CLRMSK 0xFFFFFFFFFFBFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT2_SWAIT_EN 0x0000000000400000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT2_MDISCREQ_SHIFT 21U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT2_MDISCREQ_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT2_MDISCREQ_EN 0x0000000000200000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT2_MDISCACK_SHIFT 19U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT2_MDISCACK_CLRMSK 0xFFFFFFFFFFE7FFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT2_SCONNECT_SHIFT 18U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT2_SCONNECT_CLRMSK 0xFFFFFFFFFFFBFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT2_SCONNECT_EN 0x0000000000040000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT2_MCONNECT_SHIFT 16U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT2_MCONNECT_CLRMSK 0xFFFFFFFFFFFCFFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT1_RESERVED_SHIFT 15U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT1_RESERVED_CLRMSK 0xFFFFFFFFFFFF7FFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT1_RESERVED_EN 0x0000000000008000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT1_SWAIT_SHIFT 14U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT1_SWAIT_CLRMSK 0xFFFFFFFFFFFFBFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT1_SWAIT_EN 0x0000000000004000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT1_MDISCREQ_SHIFT 13U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT1_MDISCREQ_CLRMSK 0xFFFFFFFFFFFFDFFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT1_MDISCREQ_EN 0x0000000000002000ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT1_MDISCACK_SHIFT 11U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT1_MDISCACK_CLRMSK 0xFFFFFFFFFFFFE7FFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT1_SCONNECT_SHIFT 10U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT1_SCONNECT_CLRMSK 0xFFFFFFFFFFFFFBFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT1_SCONNECT_EN 0x0000000000000400ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT1_MCONNECT_SHIFT 8U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT1_MCONNECT_CLRMSK 0xFFFFFFFFFFFFFCFFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT0_RESERVED_SHIFT 7U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT0_RESERVED_CLRMSK 0xFFFFFFFFFFFFFF7FULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT0_RESERVED_EN 0x0000000000000080ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT0_SWAIT_SHIFT 6U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT0_SWAIT_CLRMSK 0xFFFFFFFFFFFFFFBFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT0_SWAIT_EN 0x0000000000000040ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT0_MDISCREQ_SHIFT 5U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT0_MDISCREQ_CLRMSK 0xFFFFFFFFFFFFFFDFULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT0_MDISCREQ_EN 0x0000000000000020ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT0_MDISCACK_SHIFT 3U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT0_MDISCACK_CLRMSK 0xFFFFFFFFFFFFFFE7ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT0_SCONNECT_SHIFT 2U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT0_SCONNECT_CLRMSK 0xFFFFFFFFFFFFFFFBULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT0_SCONNECT_EN 0x0000000000000004ULL +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT0_MCONNECT_SHIFT 0U +#define ROGUE_CR_OCP_DEBUG_STATUS_INIT0_MCONNECT_CLRMSK 0xFFFFFFFFFFFFFFFCULL + +#define ROGUE_CR_BIF_TRUST_DM_TYPE_PM_ALIST_SHIFT 6U +#define ROGUE_CR_BIF_TRUST_DM_TYPE_PM_ALIST_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_BIF_TRUST_DM_TYPE_PM_ALIST_EN 0x00000040U +#define ROGUE_CR_BIF_TRUST_DM_TYPE_HOST_SHIFT 5U +#define ROGUE_CR_BIF_TRUST_DM_TYPE_HOST_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_BIF_TRUST_DM_TYPE_HOST_EN 0x00000020U +#define ROGUE_CR_BIF_TRUST_DM_TYPE_META_SHIFT 4U +#define ROGUE_CR_BIF_TRUST_DM_TYPE_META_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_BIF_TRUST_DM_TYPE_META_EN 0x00000010U +#define ROGUE_CR_BIF_TRUST_DM_TYPE_PB_ZLS_SHIFT 3U +#define ROGUE_CR_BIF_TRUST_DM_TYPE_PB_ZLS_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_BIF_TRUST_DM_TYPE_PB_ZLS_EN 0x00000008U +#define ROGUE_CR_BIF_TRUST_DM_TYPE_PB_TE_SHIFT 2U +#define ROGUE_CR_BIF_TRUST_DM_TYPE_PB_TE_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_BIF_TRUST_DM_TYPE_PB_TE_EN 0x00000004U +#define ROGUE_CR_BIF_TRUST_DM_TYPE_PB_VCE_SHIFT 1U +#define ROGUE_CR_BIF_TRUST_DM_TYPE_PB_VCE_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_BIF_TRUST_DM_TYPE_PB_VCE_EN 0x00000002U +#define ROGUE_CR_BIF_TRUST_DM_TYPE_TLA_SHIFT 0U +#define ROGUE_CR_BIF_TRUST_DM_TYPE_TLA_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_BIF_TRUST_DM_TYPE_TLA_EN 0x00000001U + +#define ROGUE_CR_BIF_TRUST_DM_MASK 0x0000007FU + +/* Register ROGUE_CR_BIF_TRUST */ +#define ROGUE_CR_BIF_TRUST 0xA000U +#define ROGUE_CR_BIF_TRUST_MASKFULL 0x00000000001FFFFFULL +#define ROGUE_CR_BIF_TRUST_OTHER_RAY_VERTEX_DM_TRUSTED_SHIFT 20U +#define ROGUE_CR_BIF_TRUST_OTHER_RAY_VERTEX_DM_TRUSTED_CLRMSK 0xFFEFFFFFU +#define ROGUE_CR_BIF_TRUST_OTHER_RAY_VERTEX_DM_TRUSTED_EN 0x00100000U +#define ROGUE_CR_BIF_TRUST_MCU_RAY_VERTEX_DM_TRUSTED_SHIFT 19U +#define ROGUE_CR_BIF_TRUST_MCU_RAY_VERTEX_DM_TRUSTED_CLRMSK 0xFFF7FFFFU +#define ROGUE_CR_BIF_TRUST_MCU_RAY_VERTEX_DM_TRUSTED_EN 0x00080000U +#define ROGUE_CR_BIF_TRUST_OTHER_RAY_DM_TRUSTED_SHIFT 18U +#define ROGUE_CR_BIF_TRUST_OTHER_RAY_DM_TRUSTED_CLRMSK 0xFFFBFFFFU +#define ROGUE_CR_BIF_TRUST_OTHER_RAY_DM_TRUSTED_EN 0x00040000U +#define ROGUE_CR_BIF_TRUST_MCU_RAY_DM_TRUSTED_SHIFT 17U +#define ROGUE_CR_BIF_TRUST_MCU_RAY_DM_TRUSTED_CLRMSK 0xFFFDFFFFU +#define ROGUE_CR_BIF_TRUST_MCU_RAY_DM_TRUSTED_EN 0x00020000U +#define ROGUE_CR_BIF_TRUST_ENABLE_SHIFT 16U +#define ROGUE_CR_BIF_TRUST_ENABLE_CLRMSK 0xFFFEFFFFU +#define ROGUE_CR_BIF_TRUST_ENABLE_EN 0x00010000U +#define ROGUE_CR_BIF_TRUST_DM_TRUSTED_SHIFT 9U +#define ROGUE_CR_BIF_TRUST_DM_TRUSTED_CLRMSK 0xFFFF01FFU +#define ROGUE_CR_BIF_TRUST_OTHER_COMPUTE_DM_TRUSTED_SHIFT 8U +#define ROGUE_CR_BIF_TRUST_OTHER_COMPUTE_DM_TRUSTED_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_BIF_TRUST_OTHER_COMPUTE_DM_TRUSTED_EN 0x00000100U +#define ROGUE_CR_BIF_TRUST_MCU_COMPUTE_DM_TRUSTED_SHIFT 7U +#define ROGUE_CR_BIF_TRUST_MCU_COMPUTE_DM_TRUSTED_CLRMSK 0xFFFFFF7FU +#define ROGUE_CR_BIF_TRUST_MCU_COMPUTE_DM_TRUSTED_EN 0x00000080U +#define ROGUE_CR_BIF_TRUST_PBE_COMPUTE_DM_TRUSTED_SHIFT 6U +#define ROGUE_CR_BIF_TRUST_PBE_COMPUTE_DM_TRUSTED_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_BIF_TRUST_PBE_COMPUTE_DM_TRUSTED_EN 0x00000040U +#define ROGUE_CR_BIF_TRUST_OTHER_PIXEL_DM_TRUSTED_SHIFT 5U +#define ROGUE_CR_BIF_TRUST_OTHER_PIXEL_DM_TRUSTED_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_BIF_TRUST_OTHER_PIXEL_DM_TRUSTED_EN 0x00000020U +#define ROGUE_CR_BIF_TRUST_MCU_PIXEL_DM_TRUSTED_SHIFT 4U +#define ROGUE_CR_BIF_TRUST_MCU_PIXEL_DM_TRUSTED_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_BIF_TRUST_MCU_PIXEL_DM_TRUSTED_EN 0x00000010U +#define ROGUE_CR_BIF_TRUST_PBE_PIXEL_DM_TRUSTED_SHIFT 3U +#define ROGUE_CR_BIF_TRUST_PBE_PIXEL_DM_TRUSTED_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_BIF_TRUST_PBE_PIXEL_DM_TRUSTED_EN 0x00000008U +#define ROGUE_CR_BIF_TRUST_OTHER_VERTEX_DM_TRUSTED_SHIFT 2U +#define ROGUE_CR_BIF_TRUST_OTHER_VERTEX_DM_TRUSTED_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_BIF_TRUST_OTHER_VERTEX_DM_TRUSTED_EN 0x00000004U +#define ROGUE_CR_BIF_TRUST_MCU_VERTEX_DM_TRUSTED_SHIFT 1U +#define ROGUE_CR_BIF_TRUST_MCU_VERTEX_DM_TRUSTED_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_BIF_TRUST_MCU_VERTEX_DM_TRUSTED_EN 0x00000002U +#define ROGUE_CR_BIF_TRUST_PBE_VERTEX_DM_TRUSTED_SHIFT 0U +#define ROGUE_CR_BIF_TRUST_PBE_VERTEX_DM_TRUSTED_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_BIF_TRUST_PBE_VERTEX_DM_TRUSTED_EN 0x00000001U + +/* Register ROGUE_CR_SYS_BUS_SECURE */ +#define ROGUE_CR_SYS_BUS_SECURE 0xA100U +#define ROGUE_CR_SYS_BUS_SECURE__SECR__MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_SYS_BUS_SECURE_MASKFULL 0x0000000000000001ULL +#define ROGUE_CR_SYS_BUS_SECURE_ENABLE_SHIFT 0U +#define ROGUE_CR_SYS_BUS_SECURE_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_SYS_BUS_SECURE_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_FBA_FC0_CHECKSUM */ +#define ROGUE_CR_FBA_FC0_CHECKSUM 0xD170U +#define ROGUE_CR_FBA_FC0_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_FBA_FC0_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_FBA_FC0_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_FBA_FC1_CHECKSUM */ +#define ROGUE_CR_FBA_FC1_CHECKSUM 0xD178U +#define ROGUE_CR_FBA_FC1_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_FBA_FC1_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_FBA_FC1_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_FBA_FC2_CHECKSUM */ +#define ROGUE_CR_FBA_FC2_CHECKSUM 0xD180U +#define ROGUE_CR_FBA_FC2_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_FBA_FC2_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_FBA_FC2_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_FBA_FC3_CHECKSUM */ +#define ROGUE_CR_FBA_FC3_CHECKSUM 0xD188U +#define ROGUE_CR_FBA_FC3_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_FBA_FC3_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_FBA_FC3_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_CLK_CTRL2 */ +#define ROGUE_CR_CLK_CTRL2 0xD200U +#define ROGUE_CR_CLK_CTRL2_MASKFULL 0x0000000000000F33ULL +#define ROGUE_CR_CLK_CTRL2_MCU_FBTC_SHIFT 10U +#define ROGUE_CR_CLK_CTRL2_MCU_FBTC_CLRMSK 0xFFFFFFFFFFFFF3FFULL +#define ROGUE_CR_CLK_CTRL2_MCU_FBTC_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL2_MCU_FBTC_ON 0x0000000000000400ULL +#define ROGUE_CR_CLK_CTRL2_MCU_FBTC_AUTO 0x0000000000000800ULL +#define ROGUE_CR_CLK_CTRL2_VRDM_SHIFT 8U +#define ROGUE_CR_CLK_CTRL2_VRDM_CLRMSK 0xFFFFFFFFFFFFFCFFULL +#define ROGUE_CR_CLK_CTRL2_VRDM_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL2_VRDM_ON 0x0000000000000100ULL +#define ROGUE_CR_CLK_CTRL2_VRDM_AUTO 0x0000000000000200ULL +#define ROGUE_CR_CLK_CTRL2_SH_SHIFT 4U +#define ROGUE_CR_CLK_CTRL2_SH_CLRMSK 0xFFFFFFFFFFFFFFCFULL +#define ROGUE_CR_CLK_CTRL2_SH_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL2_SH_ON 0x0000000000000010ULL +#define ROGUE_CR_CLK_CTRL2_SH_AUTO 0x0000000000000020ULL +#define ROGUE_CR_CLK_CTRL2_FBA_SHIFT 0U +#define ROGUE_CR_CLK_CTRL2_FBA_CLRMSK 0xFFFFFFFFFFFFFFFCULL +#define ROGUE_CR_CLK_CTRL2_FBA_OFF 0x0000000000000000ULL +#define ROGUE_CR_CLK_CTRL2_FBA_ON 0x0000000000000001ULL +#define ROGUE_CR_CLK_CTRL2_FBA_AUTO 0x0000000000000002ULL + +/* Register ROGUE_CR_CLK_STATUS2 */ +#define ROGUE_CR_CLK_STATUS2 0xD208U +#define ROGUE_CR_CLK_STATUS2_MASKFULL 0x0000000000000015ULL +#define ROGUE_CR_CLK_STATUS2_VRDM_SHIFT 4U +#define ROGUE_CR_CLK_STATUS2_VRDM_CLRMSK 0xFFFFFFFFFFFFFFEFULL +#define ROGUE_CR_CLK_STATUS2_VRDM_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS2_VRDM_RUNNING 0x0000000000000010ULL +#define ROGUE_CR_CLK_STATUS2_SH_SHIFT 2U +#define ROGUE_CR_CLK_STATUS2_SH_CLRMSK 0xFFFFFFFFFFFFFFFBULL +#define ROGUE_CR_CLK_STATUS2_SH_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS2_SH_RUNNING 0x0000000000000004ULL +#define ROGUE_CR_CLK_STATUS2_FBA_SHIFT 0U +#define ROGUE_CR_CLK_STATUS2_FBA_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_CLK_STATUS2_FBA_GATED 0x0000000000000000ULL +#define ROGUE_CR_CLK_STATUS2_FBA_RUNNING 0x0000000000000001ULL + +/* Register ROGUE_CR_RPM_SHF_FPL */ +#define ROGUE_CR_RPM_SHF_FPL 0xD520U +#define ROGUE_CR_RPM_SHF_FPL_MASKFULL 0x3FFFFFFFFFFFFFFCULL +#define ROGUE_CR_RPM_SHF_FPL_SIZE_SHIFT 40U +#define ROGUE_CR_RPM_SHF_FPL_SIZE_CLRMSK 0xC00000FFFFFFFFFFULL +#define ROGUE_CR_RPM_SHF_FPL_BASE_SHIFT 2U +#define ROGUE_CR_RPM_SHF_FPL_BASE_CLRMSK 0xFFFFFF0000000003ULL +#define ROGUE_CR_RPM_SHF_FPL_BASE_ALIGNSHIFT 2U +#define ROGUE_CR_RPM_SHF_FPL_BASE_ALIGNSIZE 4U + +/* Register ROGUE_CR_RPM_SHF_FPL_READ */ +#define ROGUE_CR_RPM_SHF_FPL_READ 0xD528U +#define ROGUE_CR_RPM_SHF_FPL_READ_MASKFULL 0x00000000007FFFFFULL +#define ROGUE_CR_RPM_SHF_FPL_READ_TOGGLE_SHIFT 22U +#define ROGUE_CR_RPM_SHF_FPL_READ_TOGGLE_CLRMSK 0xFFBFFFFFU +#define ROGUE_CR_RPM_SHF_FPL_READ_TOGGLE_EN 0x00400000U +#define ROGUE_CR_RPM_SHF_FPL_READ_OFFSET_SHIFT 0U +#define ROGUE_CR_RPM_SHF_FPL_READ_OFFSET_CLRMSK 0xFFC00000U + +/* Register ROGUE_CR_RPM_SHF_FPL_WRITE */ +#define ROGUE_CR_RPM_SHF_FPL_WRITE 0xD530U +#define ROGUE_CR_RPM_SHF_FPL_WRITE_MASKFULL 0x00000000007FFFFFULL +#define ROGUE_CR_RPM_SHF_FPL_WRITE_TOGGLE_SHIFT 22U +#define ROGUE_CR_RPM_SHF_FPL_WRITE_TOGGLE_CLRMSK 0xFFBFFFFFU +#define ROGUE_CR_RPM_SHF_FPL_WRITE_TOGGLE_EN 0x00400000U +#define ROGUE_CR_RPM_SHF_FPL_WRITE_OFFSET_SHIFT 0U +#define ROGUE_CR_RPM_SHF_FPL_WRITE_OFFSET_CLRMSK 0xFFC00000U + +/* Register ROGUE_CR_RPM_SHG_FPL */ +#define ROGUE_CR_RPM_SHG_FPL 0xD538U +#define ROGUE_CR_RPM_SHG_FPL_MASKFULL 0x3FFFFFFFFFFFFFFCULL +#define ROGUE_CR_RPM_SHG_FPL_SIZE_SHIFT 40U +#define ROGUE_CR_RPM_SHG_FPL_SIZE_CLRMSK 0xC00000FFFFFFFFFFULL +#define ROGUE_CR_RPM_SHG_FPL_BASE_SHIFT 2U +#define ROGUE_CR_RPM_SHG_FPL_BASE_CLRMSK 0xFFFFFF0000000003ULL +#define ROGUE_CR_RPM_SHG_FPL_BASE_ALIGNSHIFT 2U +#define ROGUE_CR_RPM_SHG_FPL_BASE_ALIGNSIZE 4U + +/* Register ROGUE_CR_RPM_SHG_FPL_READ */ +#define ROGUE_CR_RPM_SHG_FPL_READ 0xD540U +#define ROGUE_CR_RPM_SHG_FPL_READ_MASKFULL 0x00000000007FFFFFULL +#define ROGUE_CR_RPM_SHG_FPL_READ_TOGGLE_SHIFT 22U +#define ROGUE_CR_RPM_SHG_FPL_READ_TOGGLE_CLRMSK 0xFFBFFFFFU +#define ROGUE_CR_RPM_SHG_FPL_READ_TOGGLE_EN 0x00400000U +#define ROGUE_CR_RPM_SHG_FPL_READ_OFFSET_SHIFT 0U +#define ROGUE_CR_RPM_SHG_FPL_READ_OFFSET_CLRMSK 0xFFC00000U + +/* Register ROGUE_CR_RPM_SHG_FPL_WRITE */ +#define ROGUE_CR_RPM_SHG_FPL_WRITE 0xD548U +#define ROGUE_CR_RPM_SHG_FPL_WRITE_MASKFULL 0x00000000007FFFFFULL +#define ROGUE_CR_RPM_SHG_FPL_WRITE_TOGGLE_SHIFT 22U +#define ROGUE_CR_RPM_SHG_FPL_WRITE_TOGGLE_CLRMSK 0xFFBFFFFFU +#define ROGUE_CR_RPM_SHG_FPL_WRITE_TOGGLE_EN 0x00400000U +#define ROGUE_CR_RPM_SHG_FPL_WRITE_OFFSET_SHIFT 0U +#define ROGUE_CR_RPM_SHG_FPL_WRITE_OFFSET_CLRMSK 0xFFC00000U + +/* Register ROGUE_CR_SH_PERF */ +#define ROGUE_CR_SH_PERF 0xD5F8U +#define ROGUE_CR_SH_PERF_MASKFULL 0x000000000000001FULL +#define ROGUE_CR_SH_PERF_CLR_3_SHIFT 4U +#define ROGUE_CR_SH_PERF_CLR_3_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_SH_PERF_CLR_3_EN 0x00000010U +#define ROGUE_CR_SH_PERF_CLR_2_SHIFT 3U +#define ROGUE_CR_SH_PERF_CLR_2_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_SH_PERF_CLR_2_EN 0x00000008U +#define ROGUE_CR_SH_PERF_CLR_1_SHIFT 2U +#define ROGUE_CR_SH_PERF_CLR_1_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_SH_PERF_CLR_1_EN 0x00000004U +#define ROGUE_CR_SH_PERF_CLR_0_SHIFT 1U +#define ROGUE_CR_SH_PERF_CLR_0_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_SH_PERF_CLR_0_EN 0x00000002U +#define ROGUE_CR_SH_PERF_CTRL_ENABLE_SHIFT 0U +#define ROGUE_CR_SH_PERF_CTRL_ENABLE_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_SH_PERF_CTRL_ENABLE_EN 0x00000001U + +/* Register ROGUE_CR_SH_PERF_SELECT0 */ +#define ROGUE_CR_SH_PERF_SELECT0 0xD600U +#define ROGUE_CR_SH_PERF_SELECT0_MASKFULL 0x3FFF3FFF003FFFFFULL +#define ROGUE_CR_SH_PERF_SELECT0_BATCH_MAX_SHIFT 48U +#define ROGUE_CR_SH_PERF_SELECT0_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define ROGUE_CR_SH_PERF_SELECT0_BATCH_MIN_SHIFT 32U +#define ROGUE_CR_SH_PERF_SELECT0_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define ROGUE_CR_SH_PERF_SELECT0_MODE_SHIFT 21U +#define ROGUE_CR_SH_PERF_SELECT0_MODE_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define ROGUE_CR_SH_PERF_SELECT0_MODE_EN 0x0000000000200000ULL +#define ROGUE_CR_SH_PERF_SELECT0_GROUP_SELECT_SHIFT 16U +#define ROGUE_CR_SH_PERF_SELECT0_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFE0FFFFULL +#define ROGUE_CR_SH_PERF_SELECT0_BIT_SELECT_SHIFT 0U +#define ROGUE_CR_SH_PERF_SELECT0_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_SH_PERF_COUNTER_0 */ +#define ROGUE_CR_SH_PERF_COUNTER_0 0xD628U +#define ROGUE_CR_SH_PERF_COUNTER_0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SH_PERF_COUNTER_0_REG_SHIFT 0U +#define ROGUE_CR_SH_PERF_COUNTER_0_REG_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SHF_SHG_CHECKSUM */ +#define ROGUE_CR_SHF_SHG_CHECKSUM 0xD1C0U +#define ROGUE_CR_SHF_SHG_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SHF_SHG_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_SHF_SHG_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SHF_VERTEX_BIF_CHECKSUM */ +#define ROGUE_CR_SHF_VERTEX_BIF_CHECKSUM 0xD1C8U +#define ROGUE_CR_SHF_VERTEX_BIF_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SHF_VERTEX_BIF_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_SHF_VERTEX_BIF_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SHF_VARY_BIF_CHECKSUM */ +#define ROGUE_CR_SHF_VARY_BIF_CHECKSUM 0xD1D0U +#define ROGUE_CR_SHF_VARY_BIF_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SHF_VARY_BIF_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_SHF_VARY_BIF_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_RPM_BIF_CHECKSUM */ +#define ROGUE_CR_RPM_BIF_CHECKSUM 0xD1D8U +#define ROGUE_CR_RPM_BIF_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_RPM_BIF_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_RPM_BIF_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SHG_BIF_CHECKSUM */ +#define ROGUE_CR_SHG_BIF_CHECKSUM 0xD1E0U +#define ROGUE_CR_SHG_BIF_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SHG_BIF_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_SHG_BIF_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register ROGUE_CR_SHG_FE_BE_CHECKSUM */ +#define ROGUE_CR_SHG_FE_BE_CHECKSUM 0xD1E8U +#define ROGUE_CR_SHG_FE_BE_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_SHG_FE_BE_CHECKSUM_VALUE_SHIFT 0U +#define ROGUE_CR_SHG_FE_BE_CHECKSUM_VALUE_CLRMSK 0x00000000U + +/* Register DPX_CR_BF_PERF */ +#define DPX_CR_BF_PERF 0xC458U +#define DPX_CR_BF_PERF_MASKFULL 0x000000000000001FULL +#define DPX_CR_BF_PERF_CLR_3_SHIFT 4U +#define DPX_CR_BF_PERF_CLR_3_CLRMSK 0xFFFFFFEFU +#define DPX_CR_BF_PERF_CLR_3_EN 0x00000010U +#define DPX_CR_BF_PERF_CLR_2_SHIFT 3U +#define DPX_CR_BF_PERF_CLR_2_CLRMSK 0xFFFFFFF7U +#define DPX_CR_BF_PERF_CLR_2_EN 0x00000008U +#define DPX_CR_BF_PERF_CLR_1_SHIFT 2U +#define DPX_CR_BF_PERF_CLR_1_CLRMSK 0xFFFFFFFBU +#define DPX_CR_BF_PERF_CLR_1_EN 0x00000004U +#define DPX_CR_BF_PERF_CLR_0_SHIFT 1U +#define DPX_CR_BF_PERF_CLR_0_CLRMSK 0xFFFFFFFDU +#define DPX_CR_BF_PERF_CLR_0_EN 0x00000002U +#define DPX_CR_BF_PERF_CTRL_ENABLE_SHIFT 0U +#define DPX_CR_BF_PERF_CTRL_ENABLE_CLRMSK 0xFFFFFFFEU +#define DPX_CR_BF_PERF_CTRL_ENABLE_EN 0x00000001U + +/* Register DPX_CR_BF_PERF_SELECT0 */ +#define DPX_CR_BF_PERF_SELECT0 0xC460U +#define DPX_CR_BF_PERF_SELECT0_MASKFULL 0x3FFF3FFF003FFFFFULL +#define DPX_CR_BF_PERF_SELECT0_BATCH_MAX_SHIFT 48U +#define DPX_CR_BF_PERF_SELECT0_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define DPX_CR_BF_PERF_SELECT0_BATCH_MIN_SHIFT 32U +#define DPX_CR_BF_PERF_SELECT0_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define DPX_CR_BF_PERF_SELECT0_MODE_SHIFT 21U +#define DPX_CR_BF_PERF_SELECT0_MODE_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define DPX_CR_BF_PERF_SELECT0_MODE_EN 0x0000000000200000ULL +#define DPX_CR_BF_PERF_SELECT0_GROUP_SELECT_SHIFT 16U +#define DPX_CR_BF_PERF_SELECT0_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFE0FFFFULL +#define DPX_CR_BF_PERF_SELECT0_BIT_SELECT_SHIFT 0U +#define DPX_CR_BF_PERF_SELECT0_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register DPX_CR_BF_PERF_COUNTER_0 */ +#define DPX_CR_BF_PERF_COUNTER_0 0xC488U +#define DPX_CR_BF_PERF_COUNTER_0_MASKFULL 0x00000000FFFFFFFFULL +#define DPX_CR_BF_PERF_COUNTER_0_REG_SHIFT 0U +#define DPX_CR_BF_PERF_COUNTER_0_REG_CLRMSK 0x00000000U + +/* Register DPX_CR_BT_PERF */ +#define DPX_CR_BT_PERF 0xC3D0U +#define DPX_CR_BT_PERF_MASKFULL 0x000000000000001FULL +#define DPX_CR_BT_PERF_CLR_3_SHIFT 4U +#define DPX_CR_BT_PERF_CLR_3_CLRMSK 0xFFFFFFEFU +#define DPX_CR_BT_PERF_CLR_3_EN 0x00000010U +#define DPX_CR_BT_PERF_CLR_2_SHIFT 3U +#define DPX_CR_BT_PERF_CLR_2_CLRMSK 0xFFFFFFF7U +#define DPX_CR_BT_PERF_CLR_2_EN 0x00000008U +#define DPX_CR_BT_PERF_CLR_1_SHIFT 2U +#define DPX_CR_BT_PERF_CLR_1_CLRMSK 0xFFFFFFFBU +#define DPX_CR_BT_PERF_CLR_1_EN 0x00000004U +#define DPX_CR_BT_PERF_CLR_0_SHIFT 1U +#define DPX_CR_BT_PERF_CLR_0_CLRMSK 0xFFFFFFFDU +#define DPX_CR_BT_PERF_CLR_0_EN 0x00000002U +#define DPX_CR_BT_PERF_CTRL_ENABLE_SHIFT 0U +#define DPX_CR_BT_PERF_CTRL_ENABLE_CLRMSK 0xFFFFFFFEU +#define DPX_CR_BT_PERF_CTRL_ENABLE_EN 0x00000001U + +/* Register DPX_CR_BT_PERF_SELECT0 */ +#define DPX_CR_BT_PERF_SELECT0 0xC3D8U +#define DPX_CR_BT_PERF_SELECT0_MASKFULL 0x3FFF3FFF003FFFFFULL +#define DPX_CR_BT_PERF_SELECT0_BATCH_MAX_SHIFT 48U +#define DPX_CR_BT_PERF_SELECT0_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define DPX_CR_BT_PERF_SELECT0_BATCH_MIN_SHIFT 32U +#define DPX_CR_BT_PERF_SELECT0_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define DPX_CR_BT_PERF_SELECT0_MODE_SHIFT 21U +#define DPX_CR_BT_PERF_SELECT0_MODE_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define DPX_CR_BT_PERF_SELECT0_MODE_EN 0x0000000000200000ULL +#define DPX_CR_BT_PERF_SELECT0_GROUP_SELECT_SHIFT 16U +#define DPX_CR_BT_PERF_SELECT0_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFE0FFFFULL +#define DPX_CR_BT_PERF_SELECT0_BIT_SELECT_SHIFT 0U +#define DPX_CR_BT_PERF_SELECT0_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register DPX_CR_BT_PERF_COUNTER_0 */ +#define DPX_CR_BT_PERF_COUNTER_0 0xC420U +#define DPX_CR_BT_PERF_COUNTER_0_MASKFULL 0x00000000FFFFFFFFULL +#define DPX_CR_BT_PERF_COUNTER_0_REG_SHIFT 0U +#define DPX_CR_BT_PERF_COUNTER_0_REG_CLRMSK 0x00000000U + +/* Register DPX_CR_RQ_USC_DEBUG */ +#define DPX_CR_RQ_USC_DEBUG 0xC110U +#define DPX_CR_RQ_USC_DEBUG_MASKFULL 0x00000000FFFFFFFFULL +#define DPX_CR_RQ_USC_DEBUG_CHECKSUM_SHIFT 0U +#define DPX_CR_RQ_USC_DEBUG_CHECKSUM_CLRMSK 0xFFFFFFFF00000000ULL + +/* Register DPX_CR_BIF_FAULT_BANK_MMU_STATUS */ +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS 0xC5C8U +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS_MASKFULL 0x000000000000F775ULL +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS_CAT_BASE_SHIFT 12U +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS_CAT_BASE_CLRMSK 0xFFFF0FFFU +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS_PAGE_SIZE_SHIFT 8U +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS_PAGE_SIZE_CLRMSK 0xFFFFF8FFU +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS_DATA_TYPE_SHIFT 5U +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS_DATA_TYPE_CLRMSK 0xFFFFFF9FU +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS_FAULT_RO_SHIFT 4U +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS_FAULT_RO_CLRMSK 0xFFFFFFEFU +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS_FAULT_RO_EN 0x00000010U +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS_FAULT_PM_META_RO_SHIFT 2U +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS_FAULT_PM_META_RO_CLRMSK 0xFFFFFFFBU +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS_FAULT_PM_META_RO_EN 0x00000004U +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS_FAULT_SHIFT 0U +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS_FAULT_CLRMSK 0xFFFFFFFEU +#define DPX_CR_BIF_FAULT_BANK_MMU_STATUS_FAULT_EN 0x00000001U + +/* Register DPX_CR_BIF_FAULT_BANK_REQ_STATUS */ +#define DPX_CR_BIF_FAULT_BANK_REQ_STATUS 0xC5D0U +#define DPX_CR_BIF_FAULT_BANK_REQ_STATUS_MASKFULL 0x03FFFFFFFFFFFFF0ULL +#define DPX_CR_BIF_FAULT_BANK_REQ_STATUS_RNW_SHIFT 57U +#define DPX_CR_BIF_FAULT_BANK_REQ_STATUS_RNW_CLRMSK 0xFDFFFFFFFFFFFFFFULL +#define DPX_CR_BIF_FAULT_BANK_REQ_STATUS_RNW_EN 0x0200000000000000ULL +#define DPX_CR_BIF_FAULT_BANK_REQ_STATUS_TAG_SB_SHIFT 44U +#define DPX_CR_BIF_FAULT_BANK_REQ_STATUS_TAG_SB_CLRMSK 0xFE000FFFFFFFFFFFULL +#define DPX_CR_BIF_FAULT_BANK_REQ_STATUS_TAG_ID_SHIFT 40U +#define DPX_CR_BIF_FAULT_BANK_REQ_STATUS_TAG_ID_CLRMSK 0xFFFFF0FFFFFFFFFFULL +#define DPX_CR_BIF_FAULT_BANK_REQ_STATUS_ADDRESS_SHIFT 4U +#define DPX_CR_BIF_FAULT_BANK_REQ_STATUS_ADDRESS_CLRMSK 0xFFFFFF000000000FULL +#define DPX_CR_BIF_FAULT_BANK_REQ_STATUS_ADDRESS_ALIGNSHIFT 4U +#define DPX_CR_BIF_FAULT_BANK_REQ_STATUS_ADDRESS_ALIGNSIZE 16U + +/* Register DPX_CR_BIF_MMU_STATUS */ +#define DPX_CR_BIF_MMU_STATUS 0xC5D8U +#define DPX_CR_BIF_MMU_STATUS_MASKFULL 0x000000000FFFFFF7ULL +#define DPX_CR_BIF_MMU_STATUS_PC_DATA_SHIFT 20U +#define DPX_CR_BIF_MMU_STATUS_PC_DATA_CLRMSK 0xF00FFFFFU +#define DPX_CR_BIF_MMU_STATUS_PD_DATA_SHIFT 12U +#define DPX_CR_BIF_MMU_STATUS_PD_DATA_CLRMSK 0xFFF00FFFU +#define DPX_CR_BIF_MMU_STATUS_PT_DATA_SHIFT 4U +#define DPX_CR_BIF_MMU_STATUS_PT_DATA_CLRMSK 0xFFFFF00FU +#define DPX_CR_BIF_MMU_STATUS_STALLED_SHIFT 2U +#define DPX_CR_BIF_MMU_STATUS_STALLED_CLRMSK 0xFFFFFFFBU +#define DPX_CR_BIF_MMU_STATUS_STALLED_EN 0x00000004U +#define DPX_CR_BIF_MMU_STATUS_PAUSED_SHIFT 1U +#define DPX_CR_BIF_MMU_STATUS_PAUSED_CLRMSK 0xFFFFFFFDU +#define DPX_CR_BIF_MMU_STATUS_PAUSED_EN 0x00000002U +#define DPX_CR_BIF_MMU_STATUS_BUSY_SHIFT 0U +#define DPX_CR_BIF_MMU_STATUS_BUSY_CLRMSK 0xFFFFFFFEU +#define DPX_CR_BIF_MMU_STATUS_BUSY_EN 0x00000001U + +/* Register DPX_CR_RT_PERF */ +#define DPX_CR_RT_PERF 0xC700U +#define DPX_CR_RT_PERF_MASKFULL 0x000000000000001FULL +#define DPX_CR_RT_PERF_CLR_3_SHIFT 4U +#define DPX_CR_RT_PERF_CLR_3_CLRMSK 0xFFFFFFEFU +#define DPX_CR_RT_PERF_CLR_3_EN 0x00000010U +#define DPX_CR_RT_PERF_CLR_2_SHIFT 3U +#define DPX_CR_RT_PERF_CLR_2_CLRMSK 0xFFFFFFF7U +#define DPX_CR_RT_PERF_CLR_2_EN 0x00000008U +#define DPX_CR_RT_PERF_CLR_1_SHIFT 2U +#define DPX_CR_RT_PERF_CLR_1_CLRMSK 0xFFFFFFFBU +#define DPX_CR_RT_PERF_CLR_1_EN 0x00000004U +#define DPX_CR_RT_PERF_CLR_0_SHIFT 1U +#define DPX_CR_RT_PERF_CLR_0_CLRMSK 0xFFFFFFFDU +#define DPX_CR_RT_PERF_CLR_0_EN 0x00000002U +#define DPX_CR_RT_PERF_CTRL_ENABLE_SHIFT 0U +#define DPX_CR_RT_PERF_CTRL_ENABLE_CLRMSK 0xFFFFFFFEU +#define DPX_CR_RT_PERF_CTRL_ENABLE_EN 0x00000001U + +/* Register DPX_CR_RT_PERF_SELECT0 */ +#define DPX_CR_RT_PERF_SELECT0 0xC708U +#define DPX_CR_RT_PERF_SELECT0_MASKFULL 0x3FFF3FFF003FFFFFULL +#define DPX_CR_RT_PERF_SELECT0_BATCH_MAX_SHIFT 48U +#define DPX_CR_RT_PERF_SELECT0_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define DPX_CR_RT_PERF_SELECT0_BATCH_MIN_SHIFT 32U +#define DPX_CR_RT_PERF_SELECT0_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define DPX_CR_RT_PERF_SELECT0_MODE_SHIFT 21U +#define DPX_CR_RT_PERF_SELECT0_MODE_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define DPX_CR_RT_PERF_SELECT0_MODE_EN 0x0000000000200000ULL +#define DPX_CR_RT_PERF_SELECT0_GROUP_SELECT_SHIFT 16U +#define DPX_CR_RT_PERF_SELECT0_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFE0FFFFULL +#define DPX_CR_RT_PERF_SELECT0_BIT_SELECT_SHIFT 0U +#define DPX_CR_RT_PERF_SELECT0_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register DPX_CR_RT_PERF_COUNTER_0 */ +#define DPX_CR_RT_PERF_COUNTER_0 0xC730U +#define DPX_CR_RT_PERF_COUNTER_0_MASKFULL 0x00000000FFFFFFFFULL +#define DPX_CR_RT_PERF_COUNTER_0_REG_SHIFT 0U +#define DPX_CR_RT_PERF_COUNTER_0_REG_CLRMSK 0x00000000U + +/* Register DPX_CR_BX_TU_PERF */ +#define DPX_CR_BX_TU_PERF 0xC908U +#define DPX_CR_BX_TU_PERF_MASKFULL 0x000000000000001FULL +#define DPX_CR_BX_TU_PERF_CLR_3_SHIFT 4U +#define DPX_CR_BX_TU_PERF_CLR_3_CLRMSK 0xFFFFFFEFU +#define DPX_CR_BX_TU_PERF_CLR_3_EN 0x00000010U +#define DPX_CR_BX_TU_PERF_CLR_2_SHIFT 3U +#define DPX_CR_BX_TU_PERF_CLR_2_CLRMSK 0xFFFFFFF7U +#define DPX_CR_BX_TU_PERF_CLR_2_EN 0x00000008U +#define DPX_CR_BX_TU_PERF_CLR_1_SHIFT 2U +#define DPX_CR_BX_TU_PERF_CLR_1_CLRMSK 0xFFFFFFFBU +#define DPX_CR_BX_TU_PERF_CLR_1_EN 0x00000004U +#define DPX_CR_BX_TU_PERF_CLR_0_SHIFT 1U +#define DPX_CR_BX_TU_PERF_CLR_0_CLRMSK 0xFFFFFFFDU +#define DPX_CR_BX_TU_PERF_CLR_0_EN 0x00000002U +#define DPX_CR_BX_TU_PERF_CTRL_ENABLE_SHIFT 0U +#define DPX_CR_BX_TU_PERF_CTRL_ENABLE_CLRMSK 0xFFFFFFFEU +#define DPX_CR_BX_TU_PERF_CTRL_ENABLE_EN 0x00000001U + +/* Register DPX_CR_BX_TU_PERF_SELECT0 */ +#define DPX_CR_BX_TU_PERF_SELECT0 0xC910U +#define DPX_CR_BX_TU_PERF_SELECT0_MASKFULL 0x3FFF3FFF003FFFFFULL +#define DPX_CR_BX_TU_PERF_SELECT0_BATCH_MAX_SHIFT 48U +#define DPX_CR_BX_TU_PERF_SELECT0_BATCH_MAX_CLRMSK 0xC000FFFFFFFFFFFFULL +#define DPX_CR_BX_TU_PERF_SELECT0_BATCH_MIN_SHIFT 32U +#define DPX_CR_BX_TU_PERF_SELECT0_BATCH_MIN_CLRMSK 0xFFFFC000FFFFFFFFULL +#define DPX_CR_BX_TU_PERF_SELECT0_MODE_SHIFT 21U +#define DPX_CR_BX_TU_PERF_SELECT0_MODE_CLRMSK 0xFFFFFFFFFFDFFFFFULL +#define DPX_CR_BX_TU_PERF_SELECT0_MODE_EN 0x0000000000200000ULL +#define DPX_CR_BX_TU_PERF_SELECT0_GROUP_SELECT_SHIFT 16U +#define DPX_CR_BX_TU_PERF_SELECT0_GROUP_SELECT_CLRMSK 0xFFFFFFFFFFE0FFFFULL +#define DPX_CR_BX_TU_PERF_SELECT0_BIT_SELECT_SHIFT 0U +#define DPX_CR_BX_TU_PERF_SELECT0_BIT_SELECT_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register DPX_CR_BX_TU_PERF_COUNTER_0 */ +#define DPX_CR_BX_TU_PERF_COUNTER_0 0xC938U +#define DPX_CR_BX_TU_PERF_COUNTER_0_MASKFULL 0x00000000FFFFFFFFULL +#define DPX_CR_BX_TU_PERF_COUNTER_0_REG_SHIFT 0U +#define DPX_CR_BX_TU_PERF_COUNTER_0_REG_CLRMSK 0x00000000U + +/* Register DPX_CR_RS_PDS_RR_CHECKSUM */ +#define DPX_CR_RS_PDS_RR_CHECKSUM 0xC0F0U +#define DPX_CR_RS_PDS_RR_CHECKSUM_MASKFULL 0x00000000FFFFFFFFULL +#define DPX_CR_RS_PDS_RR_CHECKSUM_VALUE_SHIFT 0U +#define DPX_CR_RS_PDS_RR_CHECKSUM_VALUE_CLRMSK 0xFFFFFFFF00000000ULL + +/* Register ROGUE_CR_MMU_CBASE_MAPPING_CONTEXT */ +#define ROGUE_CR_MMU_CBASE_MAPPING_CONTEXT 0xE140U +#define ROGUE_CR_MMU_CBASE_MAPPING_CONTEXT_MASKFULL 0x00000000000000FFULL +#define ROGUE_CR_MMU_CBASE_MAPPING_CONTEXT_ID_SHIFT 0U +#define ROGUE_CR_MMU_CBASE_MAPPING_CONTEXT_ID_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_MMU_CBASE_MAPPING */ +#define ROGUE_CR_MMU_CBASE_MAPPING 0xE148U +#define ROGUE_CR_MMU_CBASE_MAPPING_MASKFULL 0x000000000FFFFFFFULL +#define ROGUE_CR_MMU_CBASE_MAPPING_BASE_ADDR_SHIFT 0U +#define ROGUE_CR_MMU_CBASE_MAPPING_BASE_ADDR_CLRMSK 0xF0000000U +#define ROGUE_CR_MMU_CBASE_MAPPING_BASE_ADDR_ALIGNSHIFT 12U +#define ROGUE_CR_MMU_CBASE_MAPPING_BASE_ADDR_ALIGNSIZE 4096U + +/* Register ROGUE_CR_MMU_FAULT_STATUS */ +#define ROGUE_CR_MMU_FAULT_STATUS 0xE150U +#define ROGUE_CR_MMU_FAULT_STATUS_MASKFULL 0xFFFFFFFFFFFFFFFFULL +#define ROGUE_CR_MMU_FAULT_STATUS_ADDRESS_SHIFT 28U +#define ROGUE_CR_MMU_FAULT_STATUS_ADDRESS_CLRMSK 0x000000000FFFFFFFULL +#define ROGUE_CR_MMU_FAULT_STATUS_CONTEXT_SHIFT 20U +#define ROGUE_CR_MMU_FAULT_STATUS_CONTEXT_CLRMSK 0xFFFFFFFFF00FFFFFULL +#define ROGUE_CR_MMU_FAULT_STATUS_TAG_SB_SHIFT 12U +#define ROGUE_CR_MMU_FAULT_STATUS_TAG_SB_CLRMSK 0xFFFFFFFFFFF00FFFULL +#define ROGUE_CR_MMU_FAULT_STATUS_REQ_ID_SHIFT 6U +#define ROGUE_CR_MMU_FAULT_STATUS_REQ_ID_CLRMSK 0xFFFFFFFFFFFFF03FULL +#define ROGUE_CR_MMU_FAULT_STATUS_LEVEL_SHIFT 4U +#define ROGUE_CR_MMU_FAULT_STATUS_LEVEL_CLRMSK 0xFFFFFFFFFFFFFFCFULL +#define ROGUE_CR_MMU_FAULT_STATUS_RNW_SHIFT 3U +#define ROGUE_CR_MMU_FAULT_STATUS_RNW_CLRMSK 0xFFFFFFFFFFFFFFF7ULL +#define ROGUE_CR_MMU_FAULT_STATUS_RNW_EN 0x0000000000000008ULL +#define ROGUE_CR_MMU_FAULT_STATUS_TYPE_SHIFT 1U +#define ROGUE_CR_MMU_FAULT_STATUS_TYPE_CLRMSK 0xFFFFFFFFFFFFFFF9ULL +#define ROGUE_CR_MMU_FAULT_STATUS_FAULT_SHIFT 0U +#define ROGUE_CR_MMU_FAULT_STATUS_FAULT_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_MMU_FAULT_STATUS_FAULT_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_MMU_FAULT_STATUS_META */ +#define ROGUE_CR_MMU_FAULT_STATUS_META 0xE158U +#define ROGUE_CR_MMU_FAULT_STATUS_META_MASKFULL 0xFFFFFFFFFFFFFFFFULL +#define ROGUE_CR_MMU_FAULT_STATUS_META_ADDRESS_SHIFT 28U +#define ROGUE_CR_MMU_FAULT_STATUS_META_ADDRESS_CLRMSK 0x000000000FFFFFFFULL +#define ROGUE_CR_MMU_FAULT_STATUS_META_CONTEXT_SHIFT 20U +#define ROGUE_CR_MMU_FAULT_STATUS_META_CONTEXT_CLRMSK 0xFFFFFFFFF00FFFFFULL +#define ROGUE_CR_MMU_FAULT_STATUS_META_TAG_SB_SHIFT 12U +#define ROGUE_CR_MMU_FAULT_STATUS_META_TAG_SB_CLRMSK 0xFFFFFFFFFFF00FFFULL +#define ROGUE_CR_MMU_FAULT_STATUS_META_REQ_ID_SHIFT 6U +#define ROGUE_CR_MMU_FAULT_STATUS_META_REQ_ID_CLRMSK 0xFFFFFFFFFFFFF03FULL +#define ROGUE_CR_MMU_FAULT_STATUS_META_LEVEL_SHIFT 4U +#define ROGUE_CR_MMU_FAULT_STATUS_META_LEVEL_CLRMSK 0xFFFFFFFFFFFFFFCFULL +#define ROGUE_CR_MMU_FAULT_STATUS_META_RNW_SHIFT 3U +#define ROGUE_CR_MMU_FAULT_STATUS_META_RNW_CLRMSK 0xFFFFFFFFFFFFFFF7ULL +#define ROGUE_CR_MMU_FAULT_STATUS_META_RNW_EN 0x0000000000000008ULL +#define ROGUE_CR_MMU_FAULT_STATUS_META_TYPE_SHIFT 1U +#define ROGUE_CR_MMU_FAULT_STATUS_META_TYPE_CLRMSK 0xFFFFFFFFFFFFFFF9ULL +#define ROGUE_CR_MMU_FAULT_STATUS_META_FAULT_SHIFT 0U +#define ROGUE_CR_MMU_FAULT_STATUS_META_FAULT_CLRMSK 0xFFFFFFFFFFFFFFFEULL +#define ROGUE_CR_MMU_FAULT_STATUS_META_FAULT_EN 0x0000000000000001ULL + +/* Register ROGUE_CR_SLC3_CTRL_MISC */ +#define ROGUE_CR_SLC3_CTRL_MISC 0xE200U +#define ROGUE_CR_SLC3_CTRL_MISC_MASKFULL 0x0000000000000107ULL +#define ROGUE_CR_SLC3_CTRL_MISC_WRITE_COMBINER_SHIFT 8U +#define ROGUE_CR_SLC3_CTRL_MISC_WRITE_COMBINER_CLRMSK 0xFFFFFEFFU +#define ROGUE_CR_SLC3_CTRL_MISC_WRITE_COMBINER_EN 0x00000100U +#define ROGUE_CR_SLC3_CTRL_MISC_ADDR_DECODE_MODE_SHIFT 0U +#define ROGUE_CR_SLC3_CTRL_MISC_ADDR_DECODE_MODE_CLRMSK 0xFFFFFFF8U +#define ROGUE_CR_SLC3_CTRL_MISC_ADDR_DECODE_MODE_LINEAR 0x00000000U +#define ROGUE_CR_SLC3_CTRL_MISC_ADDR_DECODE_MODE_IN_PAGE_HASH 0x00000001U +#define ROGUE_CR_SLC3_CTRL_MISC_ADDR_DECODE_MODE_FIXED_PVR_HASH 0x00000002U +#define ROGUE_CR_SLC3_CTRL_MISC_ADDR_DECODE_MODE_SCRAMBLE_PVR_HASH 0x00000003U +#define ROGUE_CR_SLC3_CTRL_MISC_ADDR_DECODE_MODE_WEAVED_HASH 0x00000004U + +/* Register ROGUE_CR_SLC3_SCRAMBLE */ +#define ROGUE_CR_SLC3_SCRAMBLE 0xE208U +#define ROGUE_CR_SLC3_SCRAMBLE_MASKFULL 0xFFFFFFFFFFFFFFFFULL +#define ROGUE_CR_SLC3_SCRAMBLE_BITS_SHIFT 0U +#define ROGUE_CR_SLC3_SCRAMBLE_BITS_CLRMSK 0x0000000000000000ULL + +/* Register ROGUE_CR_SLC3_SCRAMBLE2 */ +#define ROGUE_CR_SLC3_SCRAMBLE2 0xE210U +#define ROGUE_CR_SLC3_SCRAMBLE2_MASKFULL 0xFFFFFFFFFFFFFFFFULL +#define ROGUE_CR_SLC3_SCRAMBLE2_BITS_SHIFT 0U +#define ROGUE_CR_SLC3_SCRAMBLE2_BITS_CLRMSK 0x0000000000000000ULL + +/* Register ROGUE_CR_SLC3_SCRAMBLE3 */ +#define ROGUE_CR_SLC3_SCRAMBLE3 0xE218U +#define ROGUE_CR_SLC3_SCRAMBLE3_MASKFULL 0xFFFFFFFFFFFFFFFFULL +#define ROGUE_CR_SLC3_SCRAMBLE3_BITS_SHIFT 0U +#define ROGUE_CR_SLC3_SCRAMBLE3_BITS_CLRMSK 0x0000000000000000ULL + +/* Register ROGUE_CR_SLC3_SCRAMBLE4 */ +#define ROGUE_CR_SLC3_SCRAMBLE4 0xE260U +#define ROGUE_CR_SLC3_SCRAMBLE4_MASKFULL 0xFFFFFFFFFFFFFFFFULL +#define ROGUE_CR_SLC3_SCRAMBLE4_BITS_SHIFT 0U +#define ROGUE_CR_SLC3_SCRAMBLE4_BITS_CLRMSK 0x0000000000000000ULL + +/* Register ROGUE_CR_SLC3_STATUS */ +#define ROGUE_CR_SLC3_STATUS 0xE220U +#define ROGUE_CR_SLC3_STATUS_MASKFULL 0xFFFFFFFFFFFFFFFFULL +#define ROGUE_CR_SLC3_STATUS_WRITES1_SHIFT 48U +#define ROGUE_CR_SLC3_STATUS_WRITES1_CLRMSK 0x0000FFFFFFFFFFFFULL +#define ROGUE_CR_SLC3_STATUS_WRITES0_SHIFT 32U +#define ROGUE_CR_SLC3_STATUS_WRITES0_CLRMSK 0xFFFF0000FFFFFFFFULL +#define ROGUE_CR_SLC3_STATUS_READS1_SHIFT 16U +#define ROGUE_CR_SLC3_STATUS_READS1_CLRMSK 0xFFFFFFFF0000FFFFULL +#define ROGUE_CR_SLC3_STATUS_READS0_SHIFT 0U +#define ROGUE_CR_SLC3_STATUS_READS0_CLRMSK 0xFFFFFFFFFFFF0000ULL + +/* Register ROGUE_CR_SLC3_IDLE */ +#define ROGUE_CR_SLC3_IDLE 0xE228U +#define ROGUE_CR_SLC3_IDLE_MASKFULL 0x00000000000FFFFFULL +#define ROGUE_CR_SLC3_IDLE_ORDERQ_DUST2_SHIFT 18U +#define ROGUE_CR_SLC3_IDLE_ORDERQ_DUST2_CLRMSK 0xFFF3FFFFU +#define ROGUE_CR_SLC3_IDLE_MMU_SHIFT 17U +#define ROGUE_CR_SLC3_IDLE_MMU_CLRMSK 0xFFFDFFFFU +#define ROGUE_CR_SLC3_IDLE_MMU_EN 0x00020000U +#define ROGUE_CR_SLC3_IDLE_RDI_SHIFT 16U +#define ROGUE_CR_SLC3_IDLE_RDI_CLRMSK 0xFFFEFFFFU +#define ROGUE_CR_SLC3_IDLE_RDI_EN 0x00010000U +#define ROGUE_CR_SLC3_IDLE_IMGBV4_SHIFT 12U +#define ROGUE_CR_SLC3_IDLE_IMGBV4_CLRMSK 0xFFFF0FFFU +#define ROGUE_CR_SLC3_IDLE_CACHE_BANKS_SHIFT 4U +#define ROGUE_CR_SLC3_IDLE_CACHE_BANKS_CLRMSK 0xFFFFF00FU +#define ROGUE_CR_SLC3_IDLE_ORDERQ_DUST_SHIFT 2U +#define ROGUE_CR_SLC3_IDLE_ORDERQ_DUST_CLRMSK 0xFFFFFFF3U +#define ROGUE_CR_SLC3_IDLE_ORDERQ_JONES_SHIFT 1U +#define ROGUE_CR_SLC3_IDLE_ORDERQ_JONES_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_SLC3_IDLE_ORDERQ_JONES_EN 0x00000002U +#define ROGUE_CR_SLC3_IDLE_XBAR_SHIFT 0U +#define ROGUE_CR_SLC3_IDLE_XBAR_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_SLC3_IDLE_XBAR_EN 0x00000001U + +/* Register ROGUE_CR_SLC3_FAULT_STOP_STATUS */ +#define ROGUE_CR_SLC3_FAULT_STOP_STATUS 0xE248U +#define ROGUE_CR_SLC3_FAULT_STOP_STATUS_MASKFULL 0x0000000000001FFFULL +#define ROGUE_CR_SLC3_FAULT_STOP_STATUS_BIF_SHIFT 0U +#define ROGUE_CR_SLC3_FAULT_STOP_STATUS_BIF_CLRMSK 0xFFFFE000U + +/* Register ROGUE_CR_VDM_CONTEXT_STORE_MODE */ +#define ROGUE_CR_VDM_CONTEXT_STORE_MODE 0xF048U +#define ROGUE_CR_VDM_CONTEXT_STORE_MODE_MASKFULL 0x0000000000000003ULL +#define ROGUE_CR_VDM_CONTEXT_STORE_MODE_MODE_SHIFT 0U +#define ROGUE_CR_VDM_CONTEXT_STORE_MODE_MODE_CLRMSK 0xFFFFFFFCU +#define ROGUE_CR_VDM_CONTEXT_STORE_MODE_MODE_INDEX 0x00000000U +#define ROGUE_CR_VDM_CONTEXT_STORE_MODE_MODE_INSTANCE 0x00000001U +#define ROGUE_CR_VDM_CONTEXT_STORE_MODE_MODE_LIST 0x00000002U + +/* Register ROGUE_CR_CONTEXT_MAPPING0 */ +#define ROGUE_CR_CONTEXT_MAPPING0 0xF078U +#define ROGUE_CR_CONTEXT_MAPPING0_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_CONTEXT_MAPPING0_2D_SHIFT 24U +#define ROGUE_CR_CONTEXT_MAPPING0_2D_CLRMSK 0x00FFFFFFU +#define ROGUE_CR_CONTEXT_MAPPING0_CDM_SHIFT 16U +#define ROGUE_CR_CONTEXT_MAPPING0_CDM_CLRMSK 0xFF00FFFFU +#define ROGUE_CR_CONTEXT_MAPPING0_3D_SHIFT 8U +#define ROGUE_CR_CONTEXT_MAPPING0_3D_CLRMSK 0xFFFF00FFU +#define ROGUE_CR_CONTEXT_MAPPING0_TA_SHIFT 0U +#define ROGUE_CR_CONTEXT_MAPPING0_TA_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_CONTEXT_MAPPING1 */ +#define ROGUE_CR_CONTEXT_MAPPING1 0xF080U +#define ROGUE_CR_CONTEXT_MAPPING1_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_CONTEXT_MAPPING1_HOST_SHIFT 8U +#define ROGUE_CR_CONTEXT_MAPPING1_HOST_CLRMSK 0xFFFF00FFU +#define ROGUE_CR_CONTEXT_MAPPING1_TLA_SHIFT 0U +#define ROGUE_CR_CONTEXT_MAPPING1_TLA_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_CONTEXT_MAPPING2 */ +#define ROGUE_CR_CONTEXT_MAPPING2 0xF088U +#define ROGUE_CR_CONTEXT_MAPPING2_MASKFULL 0x0000000000FFFFFFULL +#define ROGUE_CR_CONTEXT_MAPPING2_ALIST0_SHIFT 16U +#define ROGUE_CR_CONTEXT_MAPPING2_ALIST0_CLRMSK 0xFF00FFFFU +#define ROGUE_CR_CONTEXT_MAPPING2_TE0_SHIFT 8U +#define ROGUE_CR_CONTEXT_MAPPING2_TE0_CLRMSK 0xFFFF00FFU +#define ROGUE_CR_CONTEXT_MAPPING2_VCE0_SHIFT 0U +#define ROGUE_CR_CONTEXT_MAPPING2_VCE0_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_CONTEXT_MAPPING3 */ +#define ROGUE_CR_CONTEXT_MAPPING3 0xF090U +#define ROGUE_CR_CONTEXT_MAPPING3_MASKFULL 0x0000000000FFFFFFULL +#define ROGUE_CR_CONTEXT_MAPPING3_ALIST1_SHIFT 16U +#define ROGUE_CR_CONTEXT_MAPPING3_ALIST1_CLRMSK 0xFF00FFFFU +#define ROGUE_CR_CONTEXT_MAPPING3_TE1_SHIFT 8U +#define ROGUE_CR_CONTEXT_MAPPING3_TE1_CLRMSK 0xFFFF00FFU +#define ROGUE_CR_CONTEXT_MAPPING3_VCE1_SHIFT 0U +#define ROGUE_CR_CONTEXT_MAPPING3_VCE1_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_BIF_JONES_OUTSTANDING_READ */ +#define ROGUE_CR_BIF_JONES_OUTSTANDING_READ 0xF098U +#define ROGUE_CR_BIF_JONES_OUTSTANDING_READ_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_BIF_JONES_OUTSTANDING_READ_COUNTER_SHIFT 0U +#define ROGUE_CR_BIF_JONES_OUTSTANDING_READ_COUNTER_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_BIF_BLACKPEARL_OUTSTANDING_READ */ +#define ROGUE_CR_BIF_BLACKPEARL_OUTSTANDING_READ 0xF0A0U +#define ROGUE_CR_BIF_BLACKPEARL_OUTSTANDING_READ_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_BIF_BLACKPEARL_OUTSTANDING_READ_COUNTER_SHIFT 0U +#define ROGUE_CR_BIF_BLACKPEARL_OUTSTANDING_READ_COUNTER_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_BIF_DUST_OUTSTANDING_READ */ +#define ROGUE_CR_BIF_DUST_OUTSTANDING_READ 0xF0A8U +#define ROGUE_CR_BIF_DUST_OUTSTANDING_READ_MASKFULL 0x000000000000FFFFULL +#define ROGUE_CR_BIF_DUST_OUTSTANDING_READ_COUNTER_SHIFT 0U +#define ROGUE_CR_BIF_DUST_OUTSTANDING_READ_COUNTER_CLRMSK 0xFFFF0000U + +/* Register ROGUE_CR_CONTEXT_MAPPING4 */ +#define ROGUE_CR_CONTEXT_MAPPING4 0xF210U +#define ROGUE_CR_CONTEXT_MAPPING4_MASKFULL 0x0000FFFFFFFFFFFFULL +#define ROGUE_CR_CONTEXT_MAPPING4_3D_MMU_STACK_SHIFT 40U +#define ROGUE_CR_CONTEXT_MAPPING4_3D_MMU_STACK_CLRMSK 0xFFFF00FFFFFFFFFFULL +#define ROGUE_CR_CONTEXT_MAPPING4_3D_UFSTACK_SHIFT 32U +#define ROGUE_CR_CONTEXT_MAPPING4_3D_UFSTACK_CLRMSK 0xFFFFFF00FFFFFFFFULL +#define ROGUE_CR_CONTEXT_MAPPING4_3D_FSTACK_SHIFT 24U +#define ROGUE_CR_CONTEXT_MAPPING4_3D_FSTACK_CLRMSK 0xFFFFFFFF00FFFFFFULL +#define ROGUE_CR_CONTEXT_MAPPING4_TA_MMU_STACK_SHIFT 16U +#define ROGUE_CR_CONTEXT_MAPPING4_TA_MMU_STACK_CLRMSK 0xFFFFFFFFFF00FFFFULL +#define ROGUE_CR_CONTEXT_MAPPING4_TA_UFSTACK_SHIFT 8U +#define ROGUE_CR_CONTEXT_MAPPING4_TA_UFSTACK_CLRMSK 0xFFFFFFFFFFFF00FFULL +#define ROGUE_CR_CONTEXT_MAPPING4_TA_FSTACK_SHIFT 0U +#define ROGUE_CR_CONTEXT_MAPPING4_TA_FSTACK_CLRMSK 0xFFFFFFFFFFFFFF00ULL + +/* Register ROGUE_CR_MULTICORE_GPU */ +#define ROGUE_CR_MULTICORE_GPU 0xF300U +#define ROGUE_CR_MULTICORE_GPU_MASKFULL 0x000000000000007FULL +#define ROGUE_CR_MULTICORE_GPU_CAPABILITY_FRAGMENT_SHIFT 6U +#define ROGUE_CR_MULTICORE_GPU_CAPABILITY_FRAGMENT_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_MULTICORE_GPU_CAPABILITY_FRAGMENT_EN 0x00000040U +#define ROGUE_CR_MULTICORE_GPU_CAPABILITY_GEOMETRY_SHIFT 5U +#define ROGUE_CR_MULTICORE_GPU_CAPABILITY_GEOMETRY_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_MULTICORE_GPU_CAPABILITY_GEOMETRY_EN 0x00000020U +#define ROGUE_CR_MULTICORE_GPU_CAPABILITY_COMPUTE_SHIFT 4U +#define ROGUE_CR_MULTICORE_GPU_CAPABILITY_COMPUTE_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_MULTICORE_GPU_CAPABILITY_COMPUTE_EN 0x00000010U +#define ROGUE_CR_MULTICORE_GPU_CAPABILITY_PRIMARY_SHIFT 3U +#define ROGUE_CR_MULTICORE_GPU_CAPABILITY_PRIMARY_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_MULTICORE_GPU_CAPABILITY_PRIMARY_EN 0x00000008U +#define ROGUE_CR_MULTICORE_GPU_ID_SHIFT 0U +#define ROGUE_CR_MULTICORE_GPU_ID_CLRMSK 0xFFFFFFF8U + +/* Register ROGUE_CR_MULTICORE_SYSTEM */ +#define ROGUE_CR_MULTICORE_SYSTEM 0xF308U +#define ROGUE_CR_MULTICORE_SYSTEM_MASKFULL 0x000000000000000FULL +#define ROGUE_CR_MULTICORE_SYSTEM_GPU_COUNT_SHIFT 0U +#define ROGUE_CR_MULTICORE_SYSTEM_GPU_COUNT_CLRMSK 0xFFFFFFF0U + +/* Register ROGUE_CR_MULTICORE_FRAGMENT_CTRL_COMMON */ +#define ROGUE_CR_MULTICORE_FRAGMENT_CTRL_COMMON 0xF310U +#define ROGUE_CR_MULTICORE_FRAGMENT_CTRL_COMMON_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_MULTICORE_FRAGMENT_CTRL_COMMON_WORKLOAD_TYPE_SHIFT 30U +#define ROGUE_CR_MULTICORE_FRAGMENT_CTRL_COMMON_WORKLOAD_TYPE_CLRMSK 0x3FFFFFFFU +#define ROGUE_CR_MULTICORE_FRAGMENT_CTRL_COMMON_WORKLOAD_EXECUTE_COUNT_SHIFT 8U +#define ROGUE_CR_MULTICORE_FRAGMENT_CTRL_COMMON_WORKLOAD_EXECUTE_COUNT_CLRMSK 0xC00000FFU +#define ROGUE_CR_MULTICORE_FRAGMENT_CTRL_COMMON_GPU_ENABLE_SHIFT 0U +#define ROGUE_CR_MULTICORE_FRAGMENT_CTRL_COMMON_GPU_ENABLE_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_MULTICORE_GEOMETRY_CTRL_COMMON */ +#define ROGUE_CR_MULTICORE_GEOMETRY_CTRL_COMMON 0xF320U +#define ROGUE_CR_MULTICORE_GEOMETRY_CTRL_COMMON_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_MULTICORE_GEOMETRY_CTRL_COMMON_WORKLOAD_TYPE_SHIFT 30U +#define ROGUE_CR_MULTICORE_GEOMETRY_CTRL_COMMON_WORKLOAD_TYPE_CLRMSK 0x3FFFFFFFU +#define ROGUE_CR_MULTICORE_GEOMETRY_CTRL_COMMON_WORKLOAD_EXECUTE_COUNT_SHIFT 8U +#define ROGUE_CR_MULTICORE_GEOMETRY_CTRL_COMMON_WORKLOAD_EXECUTE_COUNT_CLRMSK 0xC00000FFU +#define ROGUE_CR_MULTICORE_GEOMETRY_CTRL_COMMON_GPU_ENABLE_SHIFT 0U +#define ROGUE_CR_MULTICORE_GEOMETRY_CTRL_COMMON_GPU_ENABLE_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_MULTICORE_COMPUTE_CTRL_COMMON */ +#define ROGUE_CR_MULTICORE_COMPUTE_CTRL_COMMON 0xF330U +#define ROGUE_CR_MULTICORE_COMPUTE_CTRL_COMMON_MASKFULL 0x00000000FFFFFFFFULL +#define ROGUE_CR_MULTICORE_COMPUTE_CTRL_COMMON_WORKLOAD_TYPE_SHIFT 30U +#define ROGUE_CR_MULTICORE_COMPUTE_CTRL_COMMON_WORKLOAD_TYPE_CLRMSK 0x3FFFFFFFU +#define ROGUE_CR_MULTICORE_COMPUTE_CTRL_COMMON_WORKLOAD_EXECUTE_COUNT_SHIFT 8U +#define ROGUE_CR_MULTICORE_COMPUTE_CTRL_COMMON_WORKLOAD_EXECUTE_COUNT_CLRMSK 0xC00000FFU +#define ROGUE_CR_MULTICORE_COMPUTE_CTRL_COMMON_GPU_ENABLE_SHIFT 0U +#define ROGUE_CR_MULTICORE_COMPUTE_CTRL_COMMON_GPU_ENABLE_CLRMSK 0xFFFFFF00U + +/* Register ROGUE_CR_ECC_RAM_ERR_INJ */ +#define ROGUE_CR_ECC_RAM_ERR_INJ 0xF340U +#define ROGUE_CR_ECC_RAM_ERR_INJ_MASKFULL 0x000000000000001FULL +#define ROGUE_CR_ECC_RAM_ERR_INJ_SLC_SIDEKICK_SHIFT 4U +#define ROGUE_CR_ECC_RAM_ERR_INJ_SLC_SIDEKICK_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_ECC_RAM_ERR_INJ_SLC_SIDEKICK_EN 0x00000010U +#define ROGUE_CR_ECC_RAM_ERR_INJ_USC_SHIFT 3U +#define ROGUE_CR_ECC_RAM_ERR_INJ_USC_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_ECC_RAM_ERR_INJ_USC_EN 0x00000008U +#define ROGUE_CR_ECC_RAM_ERR_INJ_TPU_MCU_L0_SHIFT 2U +#define ROGUE_CR_ECC_RAM_ERR_INJ_TPU_MCU_L0_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_ECC_RAM_ERR_INJ_TPU_MCU_L0_EN 0x00000004U +#define ROGUE_CR_ECC_RAM_ERR_INJ_RASCAL_SHIFT 1U +#define ROGUE_CR_ECC_RAM_ERR_INJ_RASCAL_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_ECC_RAM_ERR_INJ_RASCAL_EN 0x00000002U +#define ROGUE_CR_ECC_RAM_ERR_INJ_MARS_SHIFT 0U +#define ROGUE_CR_ECC_RAM_ERR_INJ_MARS_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_ECC_RAM_ERR_INJ_MARS_EN 0x00000001U + +/* Register ROGUE_CR_ECC_RAM_INIT_KICK */ +#define ROGUE_CR_ECC_RAM_INIT_KICK 0xF348U +#define ROGUE_CR_ECC_RAM_INIT_KICK_MASKFULL 0x000000000000001FULL +#define ROGUE_CR_ECC_RAM_INIT_KICK_SLC_SIDEKICK_SHIFT 4U +#define ROGUE_CR_ECC_RAM_INIT_KICK_SLC_SIDEKICK_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_ECC_RAM_INIT_KICK_SLC_SIDEKICK_EN 0x00000010U +#define ROGUE_CR_ECC_RAM_INIT_KICK_USC_SHIFT 3U +#define ROGUE_CR_ECC_RAM_INIT_KICK_USC_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_ECC_RAM_INIT_KICK_USC_EN 0x00000008U +#define ROGUE_CR_ECC_RAM_INIT_KICK_TPU_MCU_L0_SHIFT 2U +#define ROGUE_CR_ECC_RAM_INIT_KICK_TPU_MCU_L0_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_ECC_RAM_INIT_KICK_TPU_MCU_L0_EN 0x00000004U +#define ROGUE_CR_ECC_RAM_INIT_KICK_RASCAL_SHIFT 1U +#define ROGUE_CR_ECC_RAM_INIT_KICK_RASCAL_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_ECC_RAM_INIT_KICK_RASCAL_EN 0x00000002U +#define ROGUE_CR_ECC_RAM_INIT_KICK_MARS_SHIFT 0U +#define ROGUE_CR_ECC_RAM_INIT_KICK_MARS_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_ECC_RAM_INIT_KICK_MARS_EN 0x00000001U + +/* Register ROGUE_CR_ECC_RAM_INIT_DONE */ +#define ROGUE_CR_ECC_RAM_INIT_DONE 0xF350U +#define ROGUE_CR_ECC_RAM_INIT_DONE_MASKFULL 0x000000000000001FULL +#define ROGUE_CR_ECC_RAM_INIT_DONE_SLC_SIDEKICK_SHIFT 4U +#define ROGUE_CR_ECC_RAM_INIT_DONE_SLC_SIDEKICK_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_ECC_RAM_INIT_DONE_SLC_SIDEKICK_EN 0x00000010U +#define ROGUE_CR_ECC_RAM_INIT_DONE_USC_SHIFT 3U +#define ROGUE_CR_ECC_RAM_INIT_DONE_USC_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_ECC_RAM_INIT_DONE_USC_EN 0x00000008U +#define ROGUE_CR_ECC_RAM_INIT_DONE_TPU_MCU_L0_SHIFT 2U +#define ROGUE_CR_ECC_RAM_INIT_DONE_TPU_MCU_L0_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_ECC_RAM_INIT_DONE_TPU_MCU_L0_EN 0x00000004U +#define ROGUE_CR_ECC_RAM_INIT_DONE_RASCAL_SHIFT 1U +#define ROGUE_CR_ECC_RAM_INIT_DONE_RASCAL_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_ECC_RAM_INIT_DONE_RASCAL_EN 0x00000002U +#define ROGUE_CR_ECC_RAM_INIT_DONE_MARS_SHIFT 0U +#define ROGUE_CR_ECC_RAM_INIT_DONE_MARS_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_ECC_RAM_INIT_DONE_MARS_EN 0x00000001U + +/* Register ROGUE_CR_SAFETY_EVENT_ENABLE */ +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE 0xF390U +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__MASKFULL 0x000000000000007FULL +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__CPU_PAGE_FAULT_SHIFT 6U +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__CPU_PAGE_FAULT_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__CPU_PAGE_FAULT_EN 0x00000040U +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__SAFE_COMPUTE_FAIL_SHIFT 5U +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__SAFE_COMPUTE_FAIL_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__SAFE_COMPUTE_FAIL_EN 0x00000020U +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__WATCHDOG_TIMEOUT_SHIFT 4U +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__WATCHDOG_TIMEOUT_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__WATCHDOG_TIMEOUT_EN 0x00000010U +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__TRP_FAIL_SHIFT 3U +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__TRP_FAIL_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__TRP_FAIL_EN 0x00000008U +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__FAULT_FW_SHIFT 2U +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__FAULT_FW_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__FAULT_FW_EN 0x00000004U +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__FAULT_GPU_SHIFT 1U +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__FAULT_GPU_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__FAULT_GPU_EN 0x00000002U +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__GPU_PAGE_FAULT_SHIFT 0U +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__GPU_PAGE_FAULT_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_SAFETY_EVENT_ENABLE__ROGUEXE__GPU_PAGE_FAULT_EN 0x00000001U + +/* Register ROGUE_CR_SAFETY_EVENT_STATUS */ +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE 0xF398U +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__MASKFULL 0x000000000000007FULL +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__CPU_PAGE_FAULT_SHIFT 6U +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__CPU_PAGE_FAULT_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__CPU_PAGE_FAULT_EN 0x00000040U +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__SAFE_COMPUTE_FAIL_SHIFT 5U +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__SAFE_COMPUTE_FAIL_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__SAFE_COMPUTE_FAIL_EN 0x00000020U +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__WATCHDOG_TIMEOUT_SHIFT 4U +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__WATCHDOG_TIMEOUT_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__WATCHDOG_TIMEOUT_EN 0x00000010U +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__TRP_FAIL_SHIFT 3U +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__TRP_FAIL_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__TRP_FAIL_EN 0x00000008U +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__FAULT_FW_SHIFT 2U +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__FAULT_FW_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__FAULT_FW_EN 0x00000004U +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__FAULT_GPU_SHIFT 1U +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__FAULT_GPU_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__FAULT_GPU_EN 0x00000002U +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__GPU_PAGE_FAULT_SHIFT 0U +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__GPU_PAGE_FAULT_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_SAFETY_EVENT_STATUS__ROGUEXE__GPU_PAGE_FAULT_EN 0x00000001U + +/* Register ROGUE_CR_SAFETY_EVENT_CLEAR */ +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE 0xF3A0U +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__MASKFULL 0x000000000000007FULL +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__CPU_PAGE_FAULT_SHIFT 6U +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__CPU_PAGE_FAULT_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__CPU_PAGE_FAULT_EN 0x00000040U +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__SAFE_COMPUTE_FAIL_SHIFT 5U +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__SAFE_COMPUTE_FAIL_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__SAFE_COMPUTE_FAIL_EN 0x00000020U +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__WATCHDOG_TIMEOUT_SHIFT 4U +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__WATCHDOG_TIMEOUT_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__WATCHDOG_TIMEOUT_EN 0x00000010U +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__TRP_FAIL_SHIFT 3U +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__TRP_FAIL_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__TRP_FAIL_EN 0x00000008U +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__FAULT_FW_SHIFT 2U +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__FAULT_FW_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__FAULT_FW_EN 0x00000004U +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__FAULT_GPU_SHIFT 1U +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__FAULT_GPU_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__FAULT_GPU_EN 0x00000002U +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__GPU_PAGE_FAULT_SHIFT 0U +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__GPU_PAGE_FAULT_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_SAFETY_EVENT_CLEAR__ROGUEXE__GPU_PAGE_FAULT_EN 0x00000001U + +/* Register ROGUE_CR_MTS_SAFETY_EVENT_ENABLE */ +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE 0xF3D8U +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__MASKFULL 0x000000000000007FULL +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__CPU_PAGE_FAULT_SHIFT 6U +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__CPU_PAGE_FAULT_CLRMSK 0xFFFFFFBFU +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__CPU_PAGE_FAULT_EN 0x00000040U +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__SAFE_COMPUTE_FAIL_SHIFT 5U +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__SAFE_COMPUTE_FAIL_CLRMSK 0xFFFFFFDFU +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__SAFE_COMPUTE_FAIL_EN 0x00000020U +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__WATCHDOG_TIMEOUT_SHIFT 4U +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__WATCHDOG_TIMEOUT_CLRMSK 0xFFFFFFEFU +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__WATCHDOG_TIMEOUT_EN 0x00000010U +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__TRP_FAIL_SHIFT 3U +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__TRP_FAIL_CLRMSK 0xFFFFFFF7U +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__TRP_FAIL_EN 0x00000008U +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__FAULT_FW_SHIFT 2U +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__FAULT_FW_CLRMSK 0xFFFFFFFBU +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__FAULT_FW_EN 0x00000004U +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__FAULT_GPU_SHIFT 1U +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__FAULT_GPU_CLRMSK 0xFFFFFFFDU +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__FAULT_GPU_EN 0x00000002U +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__GPU_PAGE_FAULT_SHIFT 0U +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__GPU_PAGE_FAULT_CLRMSK 0xFFFFFFFEU +#define ROGUE_CR_MTS_SAFETY_EVENT_ENABLE__ROGUEXE__GPU_PAGE_FAULT_EN 0x00000001U + +/* clang-format on */ + +#endif /* PVR_ROGUE_CR_DEFS_H */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_cr_defs_client.h b/drivers/gpu/drm/imagination/pvr_rogue_cr_defs_client.h new file mode 100644 index 00000000000000..46186b56effc97 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_cr_defs_client.h @@ -0,0 +1,159 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_ROGUE_CR_DEFS_CLIENT_H +#define PVR_ROGUE_CR_DEFS_CLIENT_H + +/* clang-format off */ + +/* + * This register controls the anti-aliasing mode of the Tiling Co-Processor, independent control is + * provided in both X & Y axis. + * This register needs to be set based on the ISP Samples Per Pixel a core supports. + * + * When ISP Samples Per Pixel = 1: + * 2xmsaa is achieved by enabling Y - TE does AA on Y plane only + * 4xmsaa is achieved by enabling Y and X - TE does AA on X and Y plane + * 8xmsaa not supported by XE cores + * + * When ISP Samples Per Pixel = 2: + * 2xmsaa is achieved by enabling X2 - does not affect TE + * 4xmsaa is achieved by enabling Y and X2 - TE does AA on Y plane only + * 8xmsaa is achieved by enabling Y, X and X2 - TE does AA on X and Y plane + * 8xmsaa not supported by XE cores + * + * When ISP Samples Per Pixel = 4: + * 2xmsaa is achieved by enabling X2 - does not affect TE + * 4xmsaa is achieved by enabling Y2 and X2 - TE does AA on Y plane only + * 8xmsaa not supported by XE cores + */ +/* Register ROGUE_CR_TE_AA */ +#define ROGUE_CR_TE_AA 0x0C00U +#define ROGUE_CR_TE_AA_MASKFULL 0x000000000000000Full +/* Y2 + * Indicates 4xmsaa when X2 and Y2 are set to 1. This does not affect TE and is only used within + * TPW. + */ +#define ROGUE_CR_TE_AA_Y2_SHIFT 3 +#define ROGUE_CR_TE_AA_Y2_CLRMSK 0xFFFFFFF7 +#define ROGUE_CR_TE_AA_Y2_EN 0x00000008 +/* Y + * Anti-Aliasing in Y Plane Enabled + */ +#define ROGUE_CR_TE_AA_Y_SHIFT 2 +#define ROGUE_CR_TE_AA_Y_CLRMSK 0xFFFFFFFB +#define ROGUE_CR_TE_AA_Y_EN 0x00000004 +/* X + * Anti-Aliasing in X Plane Enabled + */ +#define ROGUE_CR_TE_AA_X_SHIFT 1 +#define ROGUE_CR_TE_AA_X_CLRMSK 0xFFFFFFFD +#define ROGUE_CR_TE_AA_X_EN 0x00000002 +/* X2 + * 2x Anti-Aliasing Enabled, affects PPP only + */ +#define ROGUE_CR_TE_AA_X2_SHIFT (0U) +#define ROGUE_CR_TE_AA_X2_CLRMSK (0xFFFFFFFEU) +#define ROGUE_CR_TE_AA_X2_EN (0x00000001U) + +/* MacroTile Boundaries X Plane */ +/* Register ROGUE_CR_TE_MTILE1 */ +#define ROGUE_CR_TE_MTILE1 0x0C08 +#define ROGUE_CR_TE_MTILE1_MASKFULL 0x0000000007FFFFFFull +/* X1 default: 0x00000004 + * X1 MacroTile boundary, left tile X for second column of macrotiles (16MT mode) - 32 pixels across + * tile + */ +#define ROGUE_CR_TE_MTILE1_X1_SHIFT 18 +#define ROGUE_CR_TE_MTILE1_X1_CLRMSK 0xF803FFFF +/* X2 default: 0x00000008 + * X2 MacroTile boundary, left tile X for third(16MT) column of macrotiles - 32 pixels across tile + */ +#define ROGUE_CR_TE_MTILE1_X2_SHIFT 9U +#define ROGUE_CR_TE_MTILE1_X2_CLRMSK 0xFFFC01FF +/* X3 default: 0x0000000c + * X3 MacroTile boundary, left tile X for fourth column of macrotiles (16MT) - 32 pixels across tile + */ +#define ROGUE_CR_TE_MTILE1_X3_SHIFT 0 +#define ROGUE_CR_TE_MTILE1_X3_CLRMSK 0xFFFFFE00 + +/* MacroTile Boundaries Y Plane. */ +/* Register ROGUE_CR_TE_MTILE2 */ +#define ROGUE_CR_TE_MTILE2 0x0C10 +#define ROGUE_CR_TE_MTILE2_MASKFULL 0x0000000007FFFFFFull +/* Y1 default: 0x00000004 + * X1 MacroTile boundary, ltop tile Y for second column of macrotiles (16MT mode) - 32 pixels tile + * height + */ +#define ROGUE_CR_TE_MTILE2_Y1_SHIFT 18 +#define ROGUE_CR_TE_MTILE2_Y1_CLRMSK 0xF803FFFF +/* Y2 default: 0x00000008 + * X2 MacroTile boundary, top tile Y for third(16MT) column of macrotiles - 32 pixels tile height + */ +#define ROGUE_CR_TE_MTILE2_Y2_SHIFT 9 +#define ROGUE_CR_TE_MTILE2_Y2_CLRMSK 0xFFFC01FF +/* Y3 default: 0x0000000c + * X3 MacroTile boundary, top tile Y for fourth column of macrotiles (16MT) - 32 pixels tile height + */ +#define ROGUE_CR_TE_MTILE2_Y3_SHIFT 0 +#define ROGUE_CR_TE_MTILE2_Y3_CLRMSK 0xFFFFFE00 + +/* + * In order to perform the tiling operation and generate the display list the maximum screen size + * must be configured in terms of the number of tiles in X & Y axis. + */ + +/* Register ROGUE_CR_TE_SCREEN */ +#define ROGUE_CR_TE_SCREEN 0x0C18U +#define ROGUE_CR_TE_SCREEN_MASKFULL 0x00000000001FF1FFull +/* YMAX default: 0x00000010 + * Maximum Y tile address visible on screen, 32 pixel tile height, 16Kx16K max screen size + */ +#define ROGUE_CR_TE_SCREEN_YMAX_SHIFT 12 +#define ROGUE_CR_TE_SCREEN_YMAX_CLRMSK 0xFFE00FFF +/* XMAX default: 0x00000010 + * Maximum X tile address visible on screen, 32 pixel tile width, 16Kx16K max screen size + */ +#define ROGUE_CR_TE_SCREEN_XMAX_SHIFT 0 +#define ROGUE_CR_TE_SCREEN_XMAX_CLRMSK 0xFFFFFE00 + +/* + * In order to perform the tiling operation and generate the display list the maximum screen size + * must be configured in terms of the number of pixels in X & Y axis since this may not be the same + * as the number of tiles defined in the RGX_CR_TE_SCREEN register. + */ +/* Register ROGUE_CR_PPP_SCREEN */ +#define ROGUE_CR_PPP_SCREEN 0x0C98 +#define ROGUE_CR_PPP_SCREEN_MASKFULL 0x000000007FFF7FFFull +/* PIXYMAX + * Screen height in pixels. (16K x 16K max screen size) + */ +#define ROGUE_CR_PPP_SCREEN_PIXYMAX_SHIFT 16 +#define ROGUE_CR_PPP_SCREEN_PIXYMAX_CLRMSK 0x8000FFFF +/* PIXXMAX + * Screen width in pixels.(16K x 16K max screen size) + */ +#define ROGUE_CR_PPP_SCREEN_PIXXMAX_SHIFT 0 +#define ROGUE_CR_PPP_SCREEN_PIXXMAX_CLRMSK 0xFFFF8000 + +/* Register ROGUE_CR_ISP_MTILE_SIZE */ +#define ROGUE_CR_ISP_MTILE_SIZE 0x0F18 +#define ROGUE_CR_ISP_MTILE_SIZE_MASKFULL 0x0000000003FF03FFull +/* X + * Macrotile width, in tiles. A value of zero corresponds to the maximum size + */ +#define ROGUE_CR_ISP_MTILE_SIZE_X_SHIFT 16 +#define ROGUE_CR_ISP_MTILE_SIZE_X_CLRMSK 0xFC00FFFF +#define ROGUE_CR_ISP_MTILE_SIZE_X_ALIGNSHIFT 0 +#define ROGUE_CR_ISP_MTILE_SIZE_X_ALIGNSIZE 1 +/* Y + * Macrotile height, in tiles. A value of zero corresponds to the maximum size + */ +#define ROGUE_CR_ISP_MTILE_SIZE_Y_SHIFT 0 +#define ROGUE_CR_ISP_MTILE_SIZE_Y_CLRMSK 0xFFFFFC00 +#define ROGUE_CR_ISP_MTILE_SIZE_Y_ALIGNSHIFT 0 +#define ROGUE_CR_ISP_MTILE_SIZE_Y_ALIGNSIZE 1 + +/* clang-format on */ + +#endif /* PVR_ROGUE_CR_DEFS_CLIENT_H */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_defs.h b/drivers/gpu/drm/imagination/pvr_rogue_defs.h new file mode 100644 index 00000000000000..932b0168600896 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_defs.h @@ -0,0 +1,179 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_ROGUE_DEFS_H +#define PVR_ROGUE_DEFS_H + +#include "pvr_rogue_cr_defs.h" + +#include + +/* + ****************************************************************************** + * ROGUE Defines + ****************************************************************************** + */ + +#define ROGUE_FW_MAX_NUM_OS (8U) +#define ROGUE_FW_HOST_OS (0U) +#define ROGUE_FW_GUEST_OSID_START (1U) + +#define ROGUE_FW_THREAD_0 (0U) +#define ROGUE_FW_THREAD_1 (1U) + +#define GET_ROGUE_CACHE_LINE_SIZE(x) ((((s32)(x)) > 0) ? ((x) / 8) : (0)) + +#define MAX_HW_GEOM_FRAG_CONTEXTS 2U + +#define ROGUE_CR_CLK_CTRL_ALL_ON \ + (0x5555555555555555ull & ROGUE_CR_CLK_CTRL_MASKFULL) +#define ROGUE_CR_CLK_CTRL_ALL_AUTO \ + (0xaaaaaaaaaaaaaaaaull & ROGUE_CR_CLK_CTRL_MASKFULL) +#define ROGUE_CR_CLK_CTRL2_ALL_ON \ + (0x5555555555555555ull & ROGUE_CR_CLK_CTRL2_MASKFULL) +#define ROGUE_CR_CLK_CTRL2_ALL_AUTO \ + (0xaaaaaaaaaaaaaaaaull & ROGUE_CR_CLK_CTRL2_MASKFULL) + +#define ROGUE_CR_SOFT_RESET_DUST_n_CORE_EN \ + (ROGUE_CR_SOFT_RESET_DUST_A_CORE_EN | \ + ROGUE_CR_SOFT_RESET_DUST_B_CORE_EN | \ + ROGUE_CR_SOFT_RESET_DUST_C_CORE_EN | \ + ROGUE_CR_SOFT_RESET_DUST_D_CORE_EN | \ + ROGUE_CR_SOFT_RESET_DUST_E_CORE_EN | \ + ROGUE_CR_SOFT_RESET_DUST_F_CORE_EN | \ + ROGUE_CR_SOFT_RESET_DUST_G_CORE_EN | \ + ROGUE_CR_SOFT_RESET_DUST_H_CORE_EN) + +/* SOFT_RESET Rascal and DUSTs bits */ +#define ROGUE_CR_SOFT_RESET_RASCALDUSTS_EN \ + (ROGUE_CR_SOFT_RESET_RASCAL_CORE_EN | \ + ROGUE_CR_SOFT_RESET_DUST_n_CORE_EN) + +/* SOFT_RESET steps as defined in the TRM */ +#define ROGUE_S7_SOFT_RESET_DUSTS (ROGUE_CR_SOFT_RESET_DUST_n_CORE_EN) + +#define ROGUE_S7_SOFT_RESET_JONES \ + (ROGUE_CR_SOFT_RESET_PM_EN | ROGUE_CR_SOFT_RESET_VDM_EN | \ + ROGUE_CR_SOFT_RESET_ISP_EN) + +#define ROGUE_S7_SOFT_RESET_JONES_ALL \ + (ROGUE_S7_SOFT_RESET_JONES | ROGUE_CR_SOFT_RESET_BIF_EN | \ + ROGUE_CR_SOFT_RESET_SLC_EN | ROGUE_CR_SOFT_RESET_GARTEN_EN) + +#define ROGUE_S7_SOFT_RESET2 \ + (ROGUE_CR_SOFT_RESET2_BLACKPEARL_EN | ROGUE_CR_SOFT_RESET2_PIXEL_EN | \ + ROGUE_CR_SOFT_RESET2_CDM_EN | ROGUE_CR_SOFT_RESET2_VERTEX_EN) + +#define ROGUE_BIF_PM_PHYSICAL_PAGE_ALIGNSHIFT (12U) +#define ROGUE_BIF_PM_PHYSICAL_PAGE_SIZE \ + BIT(ROGUE_BIF_PM_PHYSICAL_PAGE_ALIGNSHIFT) + +#define ROGUE_BIF_PM_VIRTUAL_PAGE_ALIGNSHIFT (14U) +#define ROGUE_BIF_PM_VIRTUAL_PAGE_SIZE BIT(ROGUE_BIF_PM_VIRTUAL_PAGE_ALIGNSHIFT) + +#define ROGUE_BIF_PM_FREELIST_BASE_ADDR_ALIGNSIZE (16U) + +/* + * To get the number of required Dusts, divide the number of + * clusters by 2 and round up + */ +#define ROGUE_REQ_NUM_DUSTS(CLUSTERS) (((CLUSTERS) + 1U) / 2U) + +/* + * To get the number of required Bernado/Phantom(s), divide + * the number of clusters by 4 and round up + */ +#define ROGUE_REQ_NUM_PHANTOMS(CLUSTERS) (((CLUSTERS) + 3U) / 4U) +#define ROGUE_REQ_NUM_BERNADOS(CLUSTERS) (((CLUSTERS) + 3U) / 4U) +#define ROGUE_REQ_NUM_BLACKPEARLS(CLUSTERS) (((CLUSTERS) + 3U) / 4U) + +/* + * FW MMU contexts + */ +#define MMU_CONTEXT_MAPPING_FWPRIV (0x0) /* FW code/private data */ +#define MMU_CONTEXT_MAPPING_FWIF (0x0) /* Host/FW data */ + +/* + * Utility macros to calculate CAT_BASE register addresses + */ +#define BIF_CAT_BASEX(n) \ + (ROGUE_CR_BIF_CAT_BASE0 + \ + (n) * (ROGUE_CR_BIF_CAT_BASE1 - ROGUE_CR_BIF_CAT_BASE0)) + +#define FWCORE_MEM_CAT_BASEX(n) \ + (ROGUE_CR_FWCORE_MEM_CAT_BASE0 + \ + (n) * (ROGUE_CR_FWCORE_MEM_CAT_BASE1 - \ + ROGUE_CR_FWCORE_MEM_CAT_BASE0)) + +/* + * FWCORE wrapper register defines + */ +#define FWCORE_ADDR_REMAP_CONFIG0_MMU_CONTEXT_SHIFT \ + ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_CBASE_SHIFT +#define FWCORE_ADDR_REMAP_CONFIG0_MMU_CONTEXT_CLRMSK \ + ROGUE_CR_FWCORE_ADDR_REMAP_CONFIG0_CBASE_CLRMSK +#define FWCORE_ADDR_REMAP_CONFIG0_SIZE_ALIGNSHIFT (12U) + +#define ROGUE_MAX_COMPUTE_SHARED_REGISTERS (2 * 1024) +#define ROGUE_MAX_VERTEX_SHARED_REGISTERS 1024 +#define ROGUE_MAX_PIXEL_SHARED_REGISTERS 1024 +#define ROGUE_CSRM_LINE_SIZE_IN_DWORDS (64 * 4 * 4) + +#define ROGUE_CDMCTRL_USC_COMMON_SIZE_ALIGNSIZE 64 +#define ROGUE_CDMCTRL_USC_COMMON_SIZE_UPPER 256 + +/* + * The maximum amount of local memory which can be allocated by a single kernel + * (in dwords/32-bit registers). + * + * ROGUE_CDMCTRL_USC_COMMON_SIZE_ALIGNSIZE is in bytes so we divide by four. + */ +#define ROGUE_MAX_PER_KERNEL_LOCAL_MEM_SIZE_REGS ((ROGUE_CDMCTRL_USC_COMMON_SIZE_ALIGNSIZE * \ + ROGUE_CDMCTRL_USC_COMMON_SIZE_UPPER) >> 2) + +/* + ****************************************************************************** + * WA HWBRNs + ****************************************************************************** + */ + +/* GPU CR timer tick in GPU cycles */ +#define ROGUE_CRTIME_TICK_IN_CYCLES (256U) + +/* for nohw multicore return max cores possible to client */ +#define ROGUE_MULTICORE_MAX_NOHW_CORES (4U) + +/* + * If the size of the SLC is less than this value then the TPU bypasses the SLC. + */ +#define ROGUE_TPU_CACHED_SLC_SIZE_THRESHOLD (128U * 1024U) + +/* + * If the size of the SLC is bigger than this value then the TCU must not be + * bypassed in the SLC. + * In XE_MEMORY_HIERARCHY cores, the TCU is bypassed by default. + */ +#define ROGUE_TCU_CACHED_SLC_SIZE_THRESHOLD (32U * 1024U) + +/* + * Register used by the FW to track the current boot stage (not used in MIPS) + */ +#define ROGUE_FW_BOOT_STAGE_REGISTER (ROGUE_CR_POWER_ESTIMATE_RESULT) + +/* + * Virtualisation definitions + */ +#define ROGUE_VIRTUALISATION_REG_SIZE_PER_OS \ + (ROGUE_CR_MTS_SCHEDULE1 - ROGUE_CR_MTS_SCHEDULE) + +/* + * Macro used to indicate which version of HWPerf is active + */ +#define ROGUE_FEATURE_HWPERF_ROGUE + +/* + * Maximum number of cores supported by TRP + */ +#define ROGUE_TRP_MAX_NUM_CORES (4U) + +#endif /* PVR_ROGUE_DEFS_H */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif.h new file mode 100644 index 00000000000000..172886be4c820a --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif.h @@ -0,0 +1,2188 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_ROGUE_FWIF_H +#define PVR_ROGUE_FWIF_H + +#include +#include +#include +#include +#include + +#include "pvr_rogue_defs.h" +#include "pvr_rogue_fwif_common.h" +#include "pvr_rogue_fwif_shared.h" + +/* + **************************************************************************** + * Logging type + **************************************************************************** + */ +#define ROGUE_FWIF_LOG_TYPE_NONE 0x00000000U +#define ROGUE_FWIF_LOG_TYPE_TRACE 0x00000001U +#define ROGUE_FWIF_LOG_TYPE_GROUP_MAIN 0x00000002U +#define ROGUE_FWIF_LOG_TYPE_GROUP_MTS 0x00000004U +#define ROGUE_FWIF_LOG_TYPE_GROUP_CLEANUP 0x00000008U +#define ROGUE_FWIF_LOG_TYPE_GROUP_CSW 0x00000010U +#define ROGUE_FWIF_LOG_TYPE_GROUP_BIF 0x00000020U +#define ROGUE_FWIF_LOG_TYPE_GROUP_PM 0x00000040U +#define ROGUE_FWIF_LOG_TYPE_GROUP_RTD 0x00000080U +#define ROGUE_FWIF_LOG_TYPE_GROUP_SPM 0x00000100U +#define ROGUE_FWIF_LOG_TYPE_GROUP_POW 0x00000200U +#define ROGUE_FWIF_LOG_TYPE_GROUP_HWR 0x00000400U +#define ROGUE_FWIF_LOG_TYPE_GROUP_HWP 0x00000800U +#define ROGUE_FWIF_LOG_TYPE_GROUP_RPM 0x00001000U +#define ROGUE_FWIF_LOG_TYPE_GROUP_DMA 0x00002000U +#define ROGUE_FWIF_LOG_TYPE_GROUP_MISC 0x00004000U +#define ROGUE_FWIF_LOG_TYPE_GROUP_DEBUG 0x80000000U +#define ROGUE_FWIF_LOG_TYPE_GROUP_MASK 0x80007FFEU +#define ROGUE_FWIF_LOG_TYPE_MASK 0x80007FFFU + +/* String used in pvrdebug -h output */ +#define ROGUE_FWIF_LOG_GROUPS_STRING_LIST \ + "main,mts,cleanup,csw,bif,pm,rtd,spm,pow,hwr,hwp,rpm,dma,misc,debug" + +/* Table entry to map log group strings to log type value */ +struct rogue_fwif_log_group_map_entry { + const char *log_group_name; + u32 log_group_type; +}; + +/* + **************************************************************************** + * ROGUE FW signature checks + **************************************************************************** + */ +#define ROGUE_FW_SIG_BUFFER_SIZE_MIN (8192) + +#define ROGUE_FWIF_TIMEDIFF_ID ((0x1UL << 28) | ROGUE_CR_TIMER) + +/* + **************************************************************************** + * Trace Buffer + **************************************************************************** + */ + +/* Default size of ROGUE_FWIF_TRACEBUF_SPACE in DWords */ +#define ROGUE_FW_TRACE_BUF_DEFAULT_SIZE_IN_DWORDS 12000U +#define ROGUE_FW_TRACE_BUFFER_ASSERT_SIZE 200U +#define ROGUE_FW_THREAD_NUM 1U +#define ROGUE_FW_THREAD_MAX 2U + +#define ROGUE_FW_POLL_TYPE_SET 0x80000000U + +struct rogue_fwif_file_info_buf { + char path[ROGUE_FW_TRACE_BUFFER_ASSERT_SIZE]; + char info[ROGUE_FW_TRACE_BUFFER_ASSERT_SIZE]; + u32 line_num; + u32 padding; +} __aligned(8); + +struct rogue_fwif_tracebuf_space { + u32 trace_pointer; + + u32 trace_buffer_fw_addr; + + /* To be used by host when reading from trace buffer */ + u32 *trace_buffer; + + struct rogue_fwif_file_info_buf assert_buf; +} __aligned(8); + +/* Total number of FW fault logs stored */ +#define ROGUE_FWIF_FWFAULTINFO_MAX (8U) + +struct rogue_fw_fault_info { + aligned_u64 cr_timer; + aligned_u64 os_timer; + + u32 data __aligned(8); + u32 reserved; + struct rogue_fwif_file_info_buf fault_buf; +} __aligned(8); + +enum rogue_fwif_pow_state { + ROGUE_FWIF_POW_OFF, /* idle and ready to full power down */ + ROGUE_FWIF_POW_ON, /* running HW commands */ + ROGUE_FWIF_POW_FORCED_IDLE, /* forced idle */ + ROGUE_FWIF_POW_IDLE, /* idle waiting for host handshake */ +}; + +/* Firmware HWR states */ +/* The HW state is ok or locked up */ +#define ROGUE_FWIF_HWR_HARDWARE_OK BIT(0) +/* Tells if a HWR reset is in progress */ +#define ROGUE_FWIF_HWR_RESET_IN_PROGRESS BIT(1) +/* A DM unrelated lockup has been detected */ +#define ROGUE_FWIF_HWR_GENERAL_LOCKUP BIT(3) +/* At least one DM is running without being close to a lockup */ +#define ROGUE_FWIF_HWR_DM_RUNNING_OK BIT(4) +/* At least one DM is close to lockup */ +#define ROGUE_FWIF_HWR_DM_STALLING BIT(5) +/* The FW has faulted and needs to restart */ +#define ROGUE_FWIF_HWR_FW_FAULT BIT(6) +/* The FW has requested the host to restart it */ +#define ROGUE_FWIF_HWR_RESTART_REQUESTED BIT(7) + +#define ROGUE_FWIF_PHR_STATE_SHIFT (8U) +/* The FW has requested the host to restart it, per PHR configuration */ +#define ROGUE_FWIF_PHR_RESTART_REQUESTED ((1) << ROGUE_FWIF_PHR_STATE_SHIFT) +/* A PHR triggered GPU reset has just finished */ +#define ROGUE_FWIF_PHR_RESTART_FINISHED ((2) << ROGUE_FWIF_PHR_STATE_SHIFT) +#define ROGUE_FWIF_PHR_RESTART_MASK \ + (ROGUE_FWIF_PHR_RESTART_REQUESTED | ROGUE_FWIF_PHR_RESTART_FINISHED) + +#define ROGUE_FWIF_PHR_MODE_OFF (0UL) +#define ROGUE_FWIF_PHR_MODE_RD_RESET (1UL) +#define ROGUE_FWIF_PHR_MODE_FULL_RESET (2UL) + +/* Firmware per-DM HWR states */ +/* DM is working if all flags are cleared */ +#define ROGUE_FWIF_DM_STATE_WORKING (0) +/* DM is idle and ready for HWR */ +#define ROGUE_FWIF_DM_STATE_READY_FOR_HWR BIT(0) +/* DM need to skip to next cmd before resuming processing */ +#define ROGUE_FWIF_DM_STATE_NEEDS_SKIP BIT(2) +/* DM need partial render cleanup before resuming processing */ +#define ROGUE_FWIF_DM_STATE_NEEDS_PR_CLEANUP BIT(3) +/* DM need to increment Recovery Count once fully recovered */ +#define ROGUE_FWIF_DM_STATE_NEEDS_TRACE_CLEAR BIT(4) +/* DM was identified as locking up and causing HWR */ +#define ROGUE_FWIF_DM_STATE_GUILTY_LOCKUP BIT(5) +/* DM was innocently affected by another lockup which caused HWR */ +#define ROGUE_FWIF_DM_STATE_INNOCENT_LOCKUP BIT(6) +/* DM was identified as over-running and causing HWR */ +#define ROGUE_FWIF_DM_STATE_GUILTY_OVERRUNING BIT(7) +/* DM was innocently affected by another DM over-running which caused HWR */ +#define ROGUE_FWIF_DM_STATE_INNOCENT_OVERRUNING BIT(8) +/* DM was forced into HWR as it delayed more important workloads */ +#define ROGUE_FWIF_DM_STATE_HARD_CONTEXT_SWITCH BIT(9) +/* DM was forced into HWR due to an uncorrected GPU ECC error */ +#define ROGUE_FWIF_DM_STATE_GPU_ECC_HWR BIT(10) + +/* Firmware's connection state */ +enum rogue_fwif_connection_fw_state { + /* Firmware is offline */ + ROGUE_FW_CONNECTION_FW_OFFLINE = 0, + /* Firmware is initialised */ + ROGUE_FW_CONNECTION_FW_READY, + /* Firmware connection is fully established */ + ROGUE_FW_CONNECTION_FW_ACTIVE, + /* Firmware is clearing up connection data*/ + ROGUE_FW_CONNECTION_FW_OFFLOADING, + ROGUE_FW_CONNECTION_FW_STATE_COUNT +}; + +/* OS' connection state */ +enum rogue_fwif_connection_os_state { + /* OS is offline */ + ROGUE_FW_CONNECTION_OS_OFFLINE = 0, + /* OS's KM driver is setup and waiting */ + ROGUE_FW_CONNECTION_OS_READY, + /* OS connection is fully established */ + ROGUE_FW_CONNECTION_OS_ACTIVE, + ROGUE_FW_CONNECTION_OS_STATE_COUNT +}; + +struct rogue_fwif_os_runtime_flags { + unsigned int os_state : 3; + unsigned int fl_ok : 1; + unsigned int fl_grow_pending : 1; + unsigned int isolated_os : 1; + unsigned int reserved : 26; +}; + +#define PVR_SLR_LOG_ENTRIES 10 +/* MAX_CLIENT_CCB_NAME not visible to this header */ +#define PVR_SLR_LOG_STRLEN 30 + +struct rogue_fwif_slr_entry { + aligned_u64 timestamp; + u32 fw_ctx_addr; + u32 num_ufos; + char ccb_name[PVR_SLR_LOG_STRLEN]; + char padding[2]; +} __aligned(8); + +#define MAX_THREAD_NUM 2 + +/* firmware trace control data */ +struct rogue_fwif_tracebuf { + u32 log_type; + struct rogue_fwif_tracebuf_space tracebuf[MAX_THREAD_NUM]; + /* + * Member initialised only when sTraceBuf is actually allocated (in + * ROGUETraceBufferInitOnDemandResources) + */ + u32 tracebuf_size_in_dwords; + /* Compatibility and other flags */ + u32 tracebuf_flags; +} __aligned(8); + +/* firmware system data shared with the Host driver */ +struct rogue_fwif_sysdata { + /* Configuration flags from host */ + u32 config_flags; + /* Extended configuration flags from host */ + u32 config_flags_ext; + enum rogue_fwif_pow_state pow_state; + u32 hw_perf_ridx; + u32 hw_perf_widx; + u32 hw_perf_wrap_count; + /* Constant after setup, needed in FW */ + u32 hw_perf_size; + /* The number of times the FW drops a packet due to buffer full */ + u32 hw_perf_drop_count; + + /* + * ui32HWPerfUt, ui32FirstDropOrdinal, ui32LastDropOrdinal only valid + * when FW is built with ROGUE_HWPERF_UTILIZATION & + * ROGUE_HWPERF_DROP_TRACKING defined in rogue_fw_hwperf.c + */ + /* Buffer utilisation, high watermark of bytes in use */ + u32 hw_perf_ut; + /* The ordinal of the first packet the FW dropped */ + u32 first_drop_ordinal; + /* The ordinal of the last packet the FW dropped */ + u32 last_drop_ordinal; + /* State flags for each Operating System mirrored from Fw coremem */ + struct rogue_fwif_os_runtime_flags + os_runtime_flags_mirror[ROGUE_FW_MAX_NUM_OS]; + + struct rogue_fw_fault_info fault_info[ROGUE_FWIF_FWFAULTINFO_MAX]; + u32 fw_faults; + u32 cr_poll_addr[MAX_THREAD_NUM]; + u32 cr_poll_mask[MAX_THREAD_NUM]; + u32 cr_poll_count[MAX_THREAD_NUM]; + aligned_u64 start_idle_time; + +#if defined(SUPPORT_ROGUE_FW_STATS_FRAMEWORK) +# define ROGUE_FWIF_STATS_FRAMEWORK_LINESIZE (8) +# define ROGUE_FWIF_STATS_FRAMEWORK_MAX \ + (2048 * ROGUE_FWIF_STATS_FRAMEWORK_LINESIZE) + u32 fw_stats_buf[ROGUE_FWIF_STATS_FRAMEWORK_MAX] __aligned(8); +#endif + u32 hwr_state_flags; + u32 hwr_recovery_flags[PVR_FWIF_DM_MAX]; + /* Compatibility and other flags */ + u32 fw_sys_data_flags; + /* Identify whether MC config is P-P or P-S */ + u32 mc_config; +} __aligned(8); + +/* per-os firmware shared data */ +struct rogue_fwif_osdata { + /* Configuration flags from an OS */ + u32 fw_os_config_flags; + /* Markers to signal that the host should perform a full sync check */ + u32 fw_sync_check_mark; + u32 host_sync_check_mark; + + u32 forced_updates_requested; + u8 slr_log_wp; + struct rogue_fwif_slr_entry slr_log_first; + struct rogue_fwif_slr_entry slr_log[PVR_SLR_LOG_ENTRIES]; + aligned_u64 last_forced_update_time; + + /* Interrupt count from Threads > */ + u32 interrupt_count[MAX_THREAD_NUM]; + u32 kccb_cmds_executed; + u32 power_sync_fw_addr; + /* Compatibility and other flags */ + u32 fw_os_data_flags; + u32 padding; +} __aligned(8); + +/* Firmware trace time-stamp field breakup */ + +/* ROGUE_CR_TIMER register read (48 bits) value*/ +#define ROGUE_FWT_TIMESTAMP_TIME_SHIFT (0U) +#define ROGUE_FWT_TIMESTAMP_TIME_CLRMSK (0xFFFF000000000000ull) + +/* Extra debug-info (16 bits) */ +#define ROGUE_FWT_TIMESTAMP_DEBUG_INFO_SHIFT (48U) +#define ROGUE_FWT_TIMESTAMP_DEBUG_INFO_CLRMSK ~ROGUE_FWT_TIMESTAMP_TIME_CLRMSK + +/* Debug-info sub-fields */ +/* + * Bit 0: ROGUE_CR_EVENT_STATUS_MMU_PAGE_FAULT bit from ROGUE_CR_EVENT_STATUS + * register + */ +#define ROGUE_FWT_DEBUG_INFO_MMU_PAGE_FAULT_SHIFT (0U) +#define ROGUE_FWT_DEBUG_INFO_MMU_PAGE_FAULT_SET \ + BIT(ROGUE_FWT_DEBUG_INFO_MMU_PAGE_FAULT_SHIFT) + +/* Bit 1: ROGUE_CR_BIF_MMU_ENTRY_PENDING bit from ROGUE_CR_BIF_MMU_ENTRY register */ +#define ROGUE_FWT_DEBUG_INFO_MMU_ENTRY_PENDING_SHIFT (1U) +#define ROGUE_FWT_DEBUG_INFO_MMU_ENTRY_PENDING_SET \ + BIT(ROGUE_FWT_DEBUG_INFO_MMU_ENTRY_PENDING_SHIFT) + +/* Bit 2: ROGUE_CR_SLAVE_EVENT register is non-zero */ +#define ROGUE_FWT_DEBUG_INFO_SLAVE_EVENTS_SHIFT (2U) +#define ROGUE_FWT_DEBUG_INFO_SLAVE_EVENTS_SET \ + BIT(ROGUE_FWT_DEBUG_INFO_SLAVE_EVENTS_SHIFT) + +/* Bit 3-15: Unused bits */ + +#define ROGUE_FWT_DEBUG_INFO_STR_MAXLEN 64 +#define ROGUE_FWT_DEBUG_INFO_STR_PREPEND " (debug info: " +#define ROGUE_FWT_DEBUG_INFO_STR_APPEND ")" + +/* + ****************************************************************************** + * HWR Data + ****************************************************************************** + */ +enum rogue_hwrtype { + ROGUE_HWRTYPE_UNKNOWNFAILURE = 0, + ROGUE_HWRTYPE_OVERRUN = 1, + ROGUE_HWRTYPE_POLLFAILURE = 2, + ROGUE_HWRTYPE_BIF0FAULT = 3, + ROGUE_HWRTYPE_BIF1FAULT = 4, + ROGUE_HWRTYPE_TEXASBIF0FAULT = 5, + ROGUE_HWRTYPE_MMUFAULT = 6, + ROGUE_HWRTYPE_MMUMETAFAULT = 7, + ROGUE_HWRTYPE_MIPSTLBFAULT = 8, + ROGUE_HWRTYPE_ECCFAULT = 9, + ROGUE_HWRTYPE_MMURISCVFAULT = 10, +}; + +#define ROGUE_FWIF_HWRTYPE_BIF_BANK_GET(hwr_type) \ + (((hwr_type) == ROGUE_HWRTYPE_BIF0FAULT) ? 0 : 1) + +#define ROGUE_FWIF_HWRTYPE_PAGE_FAULT_GET(hwr_type) \ + ((((hwr_type) == ROGUE_HWRTYPE_BIF0FAULT) || \ + ((hwr_type) == ROGUE_HWRTYPE_BIF1FAULT) || \ + ((hwr_type) == ROGUE_HWRTYPE_TEXASBIF0FAULT) || \ + ((hwr_type) == ROGUE_HWRTYPE_MMUFAULT) || \ + ((hwr_type) == ROGUE_HWRTYPE_MMUMETAFAULT) || \ + ((hwr_type) == ROGUE_HWRTYPE_MIPSTLBFAULT) || \ + ((hwr_type) == ROGUE_HWRTYPE_MMURISCVFAULT)) \ + ? true \ + : false) + +struct rogue_bifinfo { + aligned_u64 bif_req_status; + aligned_u64 bif_mmu_status; + aligned_u64 pc_address; /* phys address of the page catalogue */ + aligned_u64 reserved; +}; + +struct rogue_eccinfo { + u32 fault_gpu; +}; + +struct rogue_mmuinfo { + aligned_u64 mmu_status[2]; + aligned_u64 pc_address; /* phys address of the page catalogue */ + aligned_u64 reserved; +}; + +struct rogue_pollinfo { + u32 thread_num; + u32 cr_poll_addr; + u32 cr_poll_mask; + u32 cr_poll_last_value; + aligned_u64 reserved; +} __aligned(8); + +struct rogue_tlbinfo { + u32 bad_addr; + u32 entry_lo; +}; + +struct rogue_hwrinfo { + union { + struct rogue_bifinfo bif_info; + struct rogue_mmuinfo mmu_info; + struct rogue_pollinfo poll_info; + struct rogue_tlbinfo tlb_info; + struct rogue_eccinfo ecc_info; + } hwr_data; + + aligned_u64 cr_timer; + aligned_u64 os_timer; + u32 frame_num; + u32 pid; + u32 active_hwrt_data; + u32 hwr_number; + u32 event_status; + u32 hwr_recovery_flags; + enum rogue_hwrtype hwr_type; + u32 dm; + u32 core_id; + aligned_u64 cr_time_of_kick; + aligned_u64 cr_time_hw_reset_start; + aligned_u64 cr_time_hw_reset_finish; + aligned_u64 cr_time_freelist_ready; + aligned_u64 reserved[2]; +} __aligned(8); + +/* Number of first HWR logs recorded (never overwritten by newer logs) */ +#define ROGUE_FWIF_HWINFO_MAX_FIRST 8U +/* Number of latest HWR logs (older logs are overwritten by newer logs) */ +#define ROGUE_FWIF_HWINFO_MAX_LAST 8U +/* Total number of HWR logs stored in a buffer */ +#define ROGUE_FWIF_HWINFO_MAX \ + (ROGUE_FWIF_HWINFO_MAX_FIRST + ROGUE_FWIF_HWINFO_MAX_LAST) +/* Index of the last log in the HWR log buffer */ +#define ROGUE_FWIF_HWINFO_LAST_INDEX (ROGUE_FWIF_HWINFO_MAX - 1U) + +struct rogue_fwif_hwrinfobuf { + struct rogue_hwrinfo hwr_info[ROGUE_FWIF_HWINFO_MAX]; + u32 hwr_counter; + u32 write_index; + u32 dd_req_count; + u32 hwr_info_buf_flags; /* Compatibility and other flags */ + u32 hwr_dm_locked_up_count[PVR_FWIF_DM_MAX]; + u32 hwr_dm_overran_count[PVR_FWIF_DM_MAX]; + u32 hwr_dm_recovered_count[PVR_FWIF_DM_MAX]; + u32 hwr_dm_false_detect_count[PVR_FWIF_DM_MAX]; +} __aligned(8); + +#define ROGUE_FWIF_CTXSWITCH_PROFILE_FAST_EN (1) +#define ROGUE_FWIF_CTXSWITCH_PROFILE_MEDIUM_EN (2) +#define ROGUE_FWIF_CTXSWITCH_PROFILE_SLOW_EN (3) +#define ROGUE_FWIF_CTXSWITCH_PROFILE_NODELAY_EN (4) + +#define ROGUE_FWIF_CDM_ARBITRATION_TASK_DEMAND_EN (1) +#define ROGUE_FWIF_CDM_ARBITRATION_ROUND_ROBIN_EN (2) + +#define ROGUE_FWIF_ISP_SCHEDMODE_VER1_IPP (1) +#define ROGUE_FWIF_ISP_SCHEDMODE_VER2_ISP (2) +/* + ****************************************************************************** + * ROGUE firmware Init Config Data + ****************************************************************************** + */ + +/* Flag definitions affecting the firmware globally */ +#define ROGUE_FWIF_INICFG_CTXSWITCH_MODE_RAND BIT(0) +#define ROGUE_FWIF_INICFG_CTXSWITCH_SRESET_EN BIT(1) +#define ROGUE_FWIF_INICFG_HWPERF_EN BIT(2) +#define ROGUE_FWIF_INICFG_DM_KILL_MODE_RAND_EN BIT(3) +#define ROGUE_FWIF_INICFG_POW_RASCALDUST BIT(4) +/* Bit 5 is reserved. */ +#define ROGUE_FWIF_INICFG_FBCDC_V3_1_EN BIT(6) +#define ROGUE_FWIF_INICFG_CHECK_MLIST_EN BIT(7) +#define ROGUE_FWIF_INICFG_DISABLE_CLKGATING_EN BIT(8) +/* Bit 9 is reserved. */ +/* Bit 10 is reserved. */ +/* Bit 11 is reserved. */ +#define ROGUE_FWIF_INICFG_REGCONFIG_EN BIT(12) +#define ROGUE_FWIF_INICFG_ASSERT_ON_OUTOFMEMORY BIT(13) +#define ROGUE_FWIF_INICFG_HWP_DISABLE_FILTER BIT(14) +/* Bit 15 is reserved. */ +#define ROGUE_FWIF_INICFG_CTXSWITCH_PROFILE_SHIFT (16) +#define ROGUE_FWIF_INICFG_CTXSWITCH_PROFILE_FAST \ + (ROGUE_FWIF_CTXSWITCH_PROFILE_FAST_EN \ + << ROGUE_FWIF_INICFG_CTXSWITCH_PROFILE_SHIFT) +#define ROGUE_FWIF_INICFG_CTXSWITCH_PROFILE_MEDIUM \ + (ROGUE_FWIF_CTXSWITCH_PROFILE_MEDIUM_EN \ + << ROGUE_FWIF_INICFG_CTXSWITCH_PROFILE_SHIFT) +#define ROGUE_FWIF_INICFG_CTXSWITCH_PROFILE_SLOW \ + (ROGUE_FWIF_CTXSWITCH_PROFILE_SLOW_EN \ + << ROGUE_FWIF_INICFG_CTXSWITCH_PROFILE_SHIFT) +#define ROGUE_FWIF_INICFG_CTXSWITCH_PROFILE_NODELAY \ + (ROGUE_FWIF_CTXSWITCH_PROFILE_NODELAY_EN \ + << ROGUE_FWIF_INICFG_CTXSWITCH_PROFILE_SHIFT) +#define ROGUE_FWIF_INICFG_CTXSWITCH_PROFILE_MASK \ + (7 << ROGUE_FWIF_INICFG_CTXSWITCH_PROFILE_SHIFT) +#define ROGUE_FWIF_INICFG_DISABLE_DM_OVERLAP BIT(19) +#define ROGUE_FWIF_INICFG_ASSERT_ON_HWR_TRIGGER BIT(20) +#define ROGUE_FWIF_INICFG_FABRIC_COHERENCY_ENABLED BIT(21) +#define ROGUE_FWIF_INICFG_VALIDATE_IRQ BIT(22) +#define ROGUE_FWIF_INICFG_DISABLE_PDP_EN BIT(23) +#define ROGUE_FWIF_INICFG_SPU_POWER_STATE_MASK_CHANGE_EN BIT(24) +#define ROGUE_FWIF_INICFG_WORKEST BIT(25) +#define ROGUE_FWIF_INICFG_PDVFS BIT(26) +#define ROGUE_FWIF_INICFG_CDM_ARBITRATION_SHIFT (27) +#define ROGUE_FWIF_INICFG_CDM_ARBITRATION_TASK_DEMAND \ + (ROGUE_FWIF_CDM_ARBITRATION_TASK_DEMAND_EN \ + << ROGUE_FWIF_INICFG_CDM_ARBITRATION_SHIFT) +#define ROGUE_FWIF_INICFG_CDM_ARBITRATION_ROUND_ROBIN \ + (ROGUE_FWIF_CDM_ARBITRATION_ROUND_ROBIN_EN \ + << ROGUE_FWIF_INICFG_CDM_ARBITRATION_SHIFT) +#define ROGUE_FWIF_INICFG_CDM_ARBITRATION_MASK \ + (3 << ROGUE_FWIF_INICFG_CDM_ARBITRATION_SHIFT) +#define ROGUE_FWIF_INICFG_ISPSCHEDMODE_SHIFT (29) +#define ROGUE_FWIF_INICFG_ISPSCHEDMODE_NONE (0) +#define ROGUE_FWIF_INICFG_ISPSCHEDMODE_VER1_IPP \ + (ROGUE_FWIF_ISP_SCHEDMODE_VER1_IPP \ + << ROGUE_FWIF_INICFG_ISPSCHEDMODE_SHIFT) +#define ROGUE_FWIF_INICFG_ISPSCHEDMODE_VER2_ISP \ + (ROGUE_FWIF_ISP_SCHEDMODE_VER2_ISP \ + << ROGUE_FWIF_INICFG_ISPSCHEDMODE_SHIFT) +#define ROGUE_FWIF_INICFG_ISPSCHEDMODE_MASK \ + (ROGUE_FWIF_INICFG_ISPSCHEDMODE_VER1_IPP | \ + ROGUE_FWIF_INICFG_ISPSCHEDMODE_VER2_ISP) +#define ROGUE_FWIF_INICFG_VALIDATE_SOCUSC_TIMER BIT(31) + +#define ROGUE_FWIF_INICFG_ALL (0xFFFFFFFFU) + +/* Extended Flag definitions affecting the firmware globally */ +#define ROGUE_FWIF_INICFG_EXT_TFBC_CONTROL_SHIFT (0) +/* [7] YUV10 override + * [6:4] Quality + * [3] Quality enable + * [2:1] Compression scheme + * [0] Lossy group + */ +#define ROGUE_FWIF_INICFG_EXT_TFBC_CONTROL_MASK (0xFF) +#define ROGUE_FWIF_INICFG_EXT_ALL (ROGUE_FWIF_INICFG_EXT_TFBC_CONTROL_MASK) + +/* Flag definitions affecting only workloads submitted by a particular OS */ +#define ROGUE_FWIF_INICFG_OS_CTXSWITCH_TDM_EN BIT(0) +#define ROGUE_FWIF_INICFG_OS_CTXSWITCH_GEOM_EN BIT(1) +#define ROGUE_FWIF_INICFG_OS_CTXSWITCH_FRAG_EN BIT(2) +#define ROGUE_FWIF_INICFG_OS_CTXSWITCH_CDM_EN BIT(3) + +#define ROGUE_FWIF_INICFG_OS_LOW_PRIO_CS_TDM BIT(4) +#define ROGUE_FWIF_INICFG_OS_LOW_PRIO_CS_GEOM BIT(5) +#define ROGUE_FWIF_INICFG_OS_LOW_PRIO_CS_FRAG BIT(6) +#define ROGUE_FWIF_INICFG_OS_LOW_PRIO_CS_CDM BIT(7) + +#define ROGUE_FWIF_INICFG_OS_ALL (0xFF) + +#define ROGUE_FWIF_INICFG_OS_CTXSWITCH_DM_ALL \ + (ROGUE_FWIF_INICFG_OS_CTXSWITCH_TDM_EN | \ + ROGUE_FWIF_INICFG_OS_CTXSWITCH_GEOM_EN | \ + ROGUE_FWIF_INICFG_OS_CTXSWITCH_FRAG_EN | \ + ROGUE_FWIF_INICFG_OS_CTXSWITCH_CDM_EN) + +#define ROGUE_FWIF_INICFG_OS_CTXSWITCH_CLRMSK \ + ~(ROGUE_FWIF_INICFG_OS_CTXSWITCH_DM_ALL) + +#define ROGUE_FWIF_FILTCFG_TRUNCATE_HALF BIT(3) +#define ROGUE_FWIF_FILTCFG_TRUNCATE_INT BIT(2) +#define ROGUE_FWIF_FILTCFG_NEW_FILTER_MODE BIT(1) + +enum rogue_activepm_conf { + ROGUE_ACTIVEPM_FORCE_OFF = 0, + ROGUE_ACTIVEPM_FORCE_ON = 1, + ROGUE_ACTIVEPM_DEFAULT = 2 +}; + +enum rogue_rd_power_island_conf { + ROGUE_RD_POWER_ISLAND_FORCE_OFF = 0, + ROGUE_RD_POWER_ISLAND_FORCE_ON = 1, + ROGUE_RD_POWER_ISLAND_DEFAULT = 2 +}; + +struct rogue_fw_register_list { + /* Register number */ + u16 reg_num; + /* Indirect register number (or 0 if not used) */ + u16 indirect_reg_num; + /* Start value for indirect register */ + u16 indirect_start_val; + /* End value for indirect register */ + u16 indirect_end_val; +}; + +struct rogue_fwif_dllist_node { + u32 p; + u32 n; +}; + +/* + * This number is used to represent an invalid page catalogue physical address + */ +#define ROGUE_FWIF_INVALID_PC_PHYADDR 0xFFFFFFFFFFFFFFFFLLU + +/* This number is used to represent unallocated page catalog base register */ +#define ROGUE_FW_BIF_INVALID_PCSET 0xFFFFFFFFU + +/* Firmware memory context. */ +struct rogue_fwif_fwmemcontext { + /* device physical address of context's page catalogue */ + aligned_u64 pc_dev_paddr; + /* + * associated page catalog base register (ROGUE_FW_BIF_INVALID_PCSET == + * unallocated) + */ + u32 page_cat_base_reg_set; + /* breakpoint address */ + u32 breakpoint_addr; + /* breakpoint handler address */ + u32 bp_handler_addr; + /* DM and enable control for BP */ + u32 breakpoint_ctl; + /* Compatibility and other flags */ + u32 fw_mem_ctx_flags; + u32 padding; +} __aligned(8); + +/* + * FW context state flags + */ +#define ROGUE_FWIF_CONTEXT_FLAGS_NEED_RESUME (0x00000001U) +#define ROGUE_FWIF_CONTEXT_FLAGS_MC_NEED_RESUME_MASKFULL (0x000000FFU) +#define ROGUE_FWIF_CONTEXT_FLAGS_TDM_HEADER_STALE (0x00000100U) +#define ROGUE_FWIF_CONTEXT_FLAGS_LAST_KICK_SECURE (0x00000200U) + +#define ROGUE_NUM_GEOM_CORES_MAX 4 + +/* + * FW-accessible TA state which must be written out to memory on context store + */ +struct rogue_fwif_geom_ctx_state_per_geom { + /* To store in mid-TA */ + aligned_u64 geom_reg_vdm_call_stack_pointer; + /* Initial value (in case is 'lost' due to a lock-up */ + aligned_u64 geom_reg_vdm_call_stack_pointer_init; + u32 geom_reg_vbs_so_prim[4]; + u16 geom_current_idx; + u16 padding[3]; +} __aligned(8); + +struct rogue_fwif_geom_ctx_state { + /* FW-accessible TA state which must be written out to memory on context store */ + struct rogue_fwif_geom_ctx_state_per_geom geom_core[ROGUE_NUM_GEOM_CORES_MAX]; +} __aligned(8); + +/* + * FW-accessible ISP state which must be written out to memory on context store + */ +struct rogue_fwif_frag_ctx_state { + u32 frag_reg_pm_deallocated_mask_status; + u32 frag_reg_dm_pds_mtilefree_status; + /* Compatibility and other flags */ + u32 ctx_state_flags; + /* + * frag_reg_isp_store should be the last element of the structure as this + * is an array whose size is determined at runtime after detecting the + * ROGUE core + */ + u32 frag_reg_isp_store[]; +} __aligned(8); + +#define ROGUE_FWIF_CTX_USING_BUFFER_A (0) +#define ROGUE_FWIF_CTX_USING_BUFFER_B (1U) + +struct rogue_fwif_compute_ctx_state { + u32 ctx_state_flags; /* Target buffer and other flags */ +}; + +struct rogue_fwif_fwcommoncontext { + /* CCB details for this firmware context */ + u32 ccbctl_fw_addr; /* CCB control */ + u32 ccb_fw_addr; /* CCB base */ + struct rogue_fwif_dma_addr ccb_meta_dma_addr; + + /* Context suspend state */ + /* geom/frag context suspend state, read/written by FW */ + u32 context_state_addr __aligned(8); + + /* Flags e.g. for context switching */ + u32 fw_com_ctx_flags; + u32 priority; + u32 priority_seq_num; + + /* Framework state */ + /* Register updates for Framework */ + u32 rf_cmd_addr __aligned(8); + + /* Statistic updates waiting to be passed back to the host... */ + /* True when some stats are pending */ + bool stats_pending __aligned(4); + /* Number of stores on this context since last update */ + s32 stats_num_stores; + /* Number of OOMs on this context since last update */ + s32 stats_num_out_of_memory; + /* Number of PRs on this context since last update */ + s32 stats_num_partial_renders; + /* Data Master type */ + u32 dm; + /* Device Virtual Address of the signal the context is waiting on */ + aligned_u64 wait_signal_address; + /* List entry for the wait-signal list */ + struct rogue_fwif_dllist_node wait_signal_node __aligned(8); + /* List entry for the buffer stalled list */ + struct rogue_fwif_dllist_node buf_stalled_node __aligned(8); + /* Address of the circular buffer queue pointers */ + aligned_u64 cbuf_queue_ctrl_addr; + + aligned_u64 robustness_address; + /* Max HWR deadline limit in ms */ + u32 max_deadline_ms; + /* Following HWR circular buffer read-offset needs resetting */ + bool read_offset_needs_reset; + + /* List entry for the waiting list */ + struct rogue_fwif_dllist_node waiting_node __aligned(8); + /* List entry for the run list */ + struct rogue_fwif_dllist_node run_node __aligned(8); + /* UFO that last failed (or NULL) */ + struct rogue_fwif_ufo last_failed_ufo; + + /* Memory context */ + u32 fw_mem_context_fw_addr; + + /* References to the host side originators */ + /* the Server Common Context */ + u32 server_common_context_id; + /* associated process ID */ + u32 pid; + + /* True when Geom DM OOM is not allowed */ + bool geom_oom_disabled __aligned(4); +} __aligned(8); + +/* Firmware render context. */ +struct rogue_fwif_fwrendercontext { + /* Geometry firmware context. */ + struct rogue_fwif_fwcommoncontext geom_context; + /* Fragment firmware context. */ + struct rogue_fwif_fwcommoncontext frag_context; + + struct rogue_fwif_static_rendercontext_state static_render_context_state; + + /* Number of commands submitted to the WorkEst FW CCB */ + u32 work_est_ccb_submitted; + + /* Compatibility and other flags */ + u32 fw_render_ctx_flags; +} __aligned(8); + +/* Firmware compute context. */ +struct rogue_fwif_fwcomputecontext { + /* Firmware context for the CDM */ + struct rogue_fwif_fwcommoncontext cdm_context; + + struct rogue_fwif_static_computecontext_state + static_compute_context_state; + + /* Number of commands submitted to the WorkEst FW CCB */ + u32 work_est_ccb_submitted; + + /* Compatibility and other flags */ + u32 compute_ctx_flags; + + u32 wgp_state; + u32 wgp_checksum; + u32 core_mask_a; + u32 core_mask_b; +} __aligned(8); + +/* Firmware TDM context. */ +struct rogue_fwif_fwtdmcontext { + /* Firmware context for the TDM */ + struct rogue_fwif_fwcommoncontext tdm_context; + + /* Number of commands submitted to the WorkEst FW CCB */ + u32 work_est_ccb_submitted; +} __aligned(8); + +/* Firmware TQ3D context. */ +struct rogue_fwif_fwtransfercontext { + /* Firmware context for TQ3D. */ + struct rogue_fwif_fwcommoncontext tq_context; +} __aligned(8); + +/* + ****************************************************************************** + * Defines for CMD_TYPE corruption detection and forward compatibility check + ****************************************************************************** + */ + +/* + * CMD_TYPE 32bit contains: + * 31:16 Reserved for magic value to detect corruption (16 bits) + * 15 Reserved for ROGUE_CCB_TYPE_TASK (1 bit) + * 14:0 Bits available for CMD_TYPEs (15 bits) + */ + +/* Magic value to detect corruption */ +#define ROGUE_CMD_MAGIC_DWORD (0x2ABC) +#define ROGUE_CMD_MAGIC_DWORD_MASK (0xFFFF0000U) +#define ROGUE_CMD_MAGIC_DWORD_SHIFT (16U) +#define ROGUE_CMD_MAGIC_DWORD_SHIFTED \ + (ROGUE_CMD_MAGIC_DWORD << ROGUE_CMD_MAGIC_DWORD_SHIFT) + +/* Kernel CCB control for ROGUE */ +struct rogue_fwif_ccb_ctl { + /* write offset into array of commands (MUST be aligned to 16 bytes!) */ + u32 write_offset; + /* Padding to ensure read and write offsets are in separate cache lines. */ + u8 padding[128 - sizeof(u32)]; + /* read offset into array of commands */ + u32 read_offset; + /* Offset wrapping mask (Total capacity of the CCB - 1) */ + u32 wrap_mask; + /* size of each command in bytes */ + u32 cmd_size; + u32 padding2; +} __aligned(8); + +/* Kernel CCB command structure for ROGUE */ + +#define ROGUE_FWIF_MMUCACHEDATA_FLAGS_PT (0x1U) /* MMU_CTRL_INVAL_PT_EN */ +#define ROGUE_FWIF_MMUCACHEDATA_FLAGS_PD (0x2U) /* MMU_CTRL_INVAL_PD_EN */ +#define ROGUE_FWIF_MMUCACHEDATA_FLAGS_PC (0x4U) /* MMU_CTRL_INVAL_PC_EN */ + +/* + * can't use PM_TLB0 bit from BIFPM_CTRL reg because it collides with PT + * bit from BIF_CTRL reg + */ +#define ROGUE_FWIF_MMUCACHEDATA_FLAGS_PMTLB (0x10) +/* BIF_CTRL_INVAL_TLB1_EN */ +#define ROGUE_FWIF_MMUCACHEDATA_FLAGS_TLB \ + (ROGUE_FWIF_MMUCACHEDATA_FLAGS_PMTLB | 0x8) +/* MMU_CTRL_INVAL_ALL_CONTEXTS_EN */ +#define ROGUE_FWIF_MMUCACHEDATA_FLAGS_CTX_ALL (0x800) + +/* indicates FW should interrupt the host */ +#define ROGUE_FWIF_MMUCACHEDATA_FLAGS_INTERRUPT (0x4000000U) + +struct rogue_fwif_mmucachedata { + u32 cache_flags; + u32 mmu_cache_sync_fw_addr; + u32 mmu_cache_sync_update_value; +}; + +#define ROGUE_FWIF_BPDATA_FLAGS_ENABLE BIT(0) +#define ROGUE_FWIF_BPDATA_FLAGS_WRITE BIT(1) +#define ROGUE_FWIF_BPDATA_FLAGS_CTL BIT(2) +#define ROGUE_FWIF_BPDATA_FLAGS_REGS BIT(3) + +struct rogue_fwif_bpdata { + /* Memory context */ + u32 fw_mem_context_fw_addr; + /* Breakpoint address */ + u32 bp_addr; + /* Breakpoint handler */ + u32 bp_handler_addr; + /* Breakpoint control */ + u32 bp_dm; + u32 bp_data_flags; + /* Number of temporary registers to overallocate */ + u32 temp_regs; + /* Number of shared registers to overallocate */ + u32 shared_regs; + /* DM associated with the breakpoint */ + u32 dm; +}; + +#define ROGUE_FWIF_KCCB_CMD_KICK_DATA_MAX_NUM_CLEANUP_CTLS \ + (ROGUE_FWIF_PRBUFFER_MAXSUPPORTED + 1U) /* +1 is RTDATASET cleanup */ + +struct rogue_fwif_kccb_cmd_kick_data { + /* address of the firmware context */ + u32 context_fw_addr; + /* Client CCB woff update */ + u32 client_woff_update; + /* Client CCB wrap mask update after CCCB growth */ + u32 client_wrap_mask_update; + /* number of CleanupCtl pointers attached */ + u32 num_cleanup_ctl; + /* CleanupCtl structures associated with command */ + u32 cleanup_ctl_fw_addr + [ROGUE_FWIF_KCCB_CMD_KICK_DATA_MAX_NUM_CLEANUP_CTLS]; + /* + * offset to the CmdHeader which houses the workload estimation kick + * data. + */ + u32 work_est_cmd_header_offset; +}; + +struct rogue_fwif_kccb_cmd_combined_geom_frag_kick_data { + struct rogue_fwif_kccb_cmd_kick_data geom_cmd_kick_data; + struct rogue_fwif_kccb_cmd_kick_data frag_cmd_kick_data; +}; + +struct rogue_fwif_kccb_cmd_force_update_data { + /* address of the firmware context */ + u32 context_fw_addr; + /* Client CCB fence offset */ + u32 ccb_fence_offset; +}; + +enum rogue_fwif_cleanup_type { + /* FW common context cleanup */ + ROGUE_FWIF_CLEANUP_FWCOMMONCONTEXT, + /* FW HW RT data cleanup */ + ROGUE_FWIF_CLEANUP_HWRTDATA, + /* FW freelist cleanup */ + ROGUE_FWIF_CLEANUP_FREELIST, + /* FW ZS Buffer cleanup */ + ROGUE_FWIF_CLEANUP_ZSBUFFER, +}; + +struct rogue_fwif_cleanup_request { + /* Cleanup type */ + enum rogue_fwif_cleanup_type cleanup_type; + union { + /* FW common context to cleanup */ + u32 context_fw_addr; + /* HW RT to cleanup */ + u32 hwrt_data_fw_addr; + /* Freelist to cleanup */ + u32 freelist_fw_addr; + /* ZS Buffer to cleanup */ + u32 zs_buffer_fw_addr; + } cleanup_data; +}; + +enum rogue_fwif_power_type { + ROGUE_FWIF_POW_OFF_REQ = 1, + ROGUE_FWIF_POW_FORCED_IDLE_REQ, + ROGUE_FWIF_POW_NUM_UNITS_CHANGE, + ROGUE_FWIF_POW_APM_LATENCY_CHANGE +}; + +enum rogue_fwif_power_force_idle_type { + ROGUE_FWIF_POWER_FORCE_IDLE = 1, + ROGUE_FWIF_POWER_CANCEL_FORCED_IDLE, + ROGUE_FWIF_POWER_HOST_TIMEOUT, +}; + +struct rogue_fwif_power_request { + /* Type of power request */ + enum rogue_fwif_power_type pow_type; + union { + /* Number of active Dusts */ + u32 num_of_dusts; + /* If the operation is mandatory */ + bool forced __aligned(4); + /* + * Type of Request. Consolidating Force Idle, Cancel Forced + * Idle, Host Timeout + */ + enum rogue_fwif_power_force_idle_type pow_request_type; + } power_req_data; +}; + +struct rogue_fwif_slcflushinvaldata { + /* Context to fence on (only useful when bDMContext == TRUE) */ + u32 context_fw_addr; + /* Invalidate the cache as well as flushing */ + bool inval __aligned(4); + /* The data to flush/invalidate belongs to a specific DM context */ + bool dm_context __aligned(4); + /* Optional address of range (only useful when bDMContext == FALSE) */ + aligned_u64 address; + /* Optional size of range (only useful when bDMContext == FALSE) */ + aligned_u64 size; +}; + +enum rogue_fwif_hwperf_update_config { + ROGUE_FWIF_HWPERF_CTRL_TOGGLE = 0, + ROGUE_FWIF_HWPERF_CTRL_SET = 1, + ROGUE_FWIF_HWPERF_CTRL_EMIT_FEATURES_EV = 2 +}; + +struct rogue_fwif_hwperf_ctrl { + enum rogue_fwif_hwperf_update_config opcode; /* Control operation code */ + aligned_u64 mask; /* Mask of events to toggle */ +}; + +struct rogue_fwif_hwperf_config_enable_blks { + /* Number of ROGUE_HWPERF_CONFIG_MUX_CNTBLK in the array */ + u32 num_blocks; + /* Address of the ROGUE_HWPERF_CONFIG_MUX_CNTBLK array */ + u32 block_configs_fw_addr; +}; + +struct rogue_fwif_hwperf_config_da_blks { + /* Number of ROGUE_HWPERF_CONFIG_CNTBLK in the array */ + u32 num_blocks; + /* Address of the ROGUE_HWPERF_CONFIG_CNTBLK array */ + u32 block_configs_fw_addr; +}; + +struct rogue_fwif_coreclkspeedchange_data { + u32 new_clock_speed; /* New clock speed */ +}; + +#define ROGUE_FWIF_HWPERF_CTRL_BLKS_MAX 16 + +struct rogue_fwif_hwperf_ctrl_blks { + bool enable; + /* Number of block IDs in the array */ + u32 num_blocks; + /* Array of ROGUE_HWPERF_CNTBLK_ID values */ + u16 block_ids[ROGUE_FWIF_HWPERF_CTRL_BLKS_MAX]; +}; + +struct rogue_fwif_hwperf_select_custom_cntrs { + u16 custom_block; + u16 num_counters; + u32 custom_counter_ids_fw_addr; +}; + +struct rogue_fwif_zsbuffer_backing_data { + u32 zs_buffer_fw_addr; /* ZS-Buffer FW address */ + + bool done __aligned(4); /* action backing/unbacking succeeded */ +}; + +struct rogue_fwif_freelist_gs_data { + /* Freelist FW address */ + u32 freelist_fw_addr; + /* Amount of the Freelist change */ + u32 delta_pages; + /* New amount of pages on the freelist (including ready pages) */ + u32 new_pages; + /* Number of ready pages to be held in reserve until OOM */ + u32 ready_pages; +}; + +#define MAX_FREELISTS_SIZE 3 +#define MAX_HW_GEOM_FRAG_CONTEXTS_SIZE 3 + +#define ROGUE_FWIF_MAX_FREELISTS_TO_RECONSTRUCT \ + (MAX_HW_GEOM_FRAG_CONTEXTS_SIZE * MAX_FREELISTS_SIZE * 2U) +#define ROGUE_FWIF_FREELISTS_RECONSTRUCTION_FAILED_FLAG 0x80000000U + +struct rogue_fwif_freelists_reconstruction_data { + u32 freelist_count; + u32 freelist_ids[ROGUE_FWIF_MAX_FREELISTS_TO_RECONSTRUCT]; +}; + +struct rogue_fwif_write_offset_update_data { + /* + * Context to that may need to be resumed following write offset update + */ + u32 context_fw_addr; +} __aligned(8); + +/* + ****************************************************************************** + * Proactive DVFS Structures + ****************************************************************************** + */ +#define NUM_OPP_VALUES 16 + +struct pdvfs_opp { + u32 volt; /* V */ + u32 freq; /* Hz */ +} __aligned(8); + +struct rogue_fwif_pdvfs_opp { + struct pdvfs_opp opp_values[NUM_OPP_VALUES]; + u32 min_opp_point; + u32 max_opp_point; +} __aligned(8); + +struct rogue_fwif_pdvfs_max_freq_data { + u32 max_opp_point; +} __aligned(8); + +struct rogue_fwif_pdvfs_min_freq_data { + u32 min_opp_point; +} __aligned(8); + +/* + ****************************************************************************** + * Register configuration structures + ****************************************************************************** + */ + +#define ROGUE_FWIF_REG_CFG_MAX_SIZE 512 + +enum rogue_fwif_regdata_cmd_type { + ROGUE_FWIF_REGCFG_CMD_ADD = 101, + ROGUE_FWIF_REGCFG_CMD_CLEAR = 102, + ROGUE_FWIF_REGCFG_CMD_ENABLE = 103, + ROGUE_FWIF_REGCFG_CMD_DISABLE = 104 +}; + +enum rogue_fwif_reg_cfg_type { + /* Sidekick power event */ + ROGUE_FWIF_REG_CFG_TYPE_PWR_ON = 0, + /* Rascal / dust power event */ + ROGUE_FWIF_REG_CFG_TYPE_DUST_CHANGE, + /* Geometry kick */ + ROGUE_FWIF_REG_CFG_TYPE_GEOM, + /* Fragment kick */ + ROGUE_FWIF_REG_CFG_TYPE_FRAG, + /* Compute kick */ + ROGUE_FWIF_REG_CFG_TYPE_CDM, + /* TLA kick */ + ROGUE_FWIF_REG_CFG_TYPE_TLA, + /* TDM kick */ + ROGUE_FWIF_REG_CFG_TYPE_TDM, + /* Applies to all types. Keep as last element */ + ROGUE_FWIF_REG_CFG_TYPE_ALL +}; + +struct rogue_fwif_reg_cfg_rec { + u64 sddr; + u64 mask; + u64 value; +}; + +struct rogue_fwif_regconfig_data { + enum rogue_fwif_regdata_cmd_type cmd_type; + enum rogue_fwif_reg_cfg_type reg_config_type; + struct rogue_fwif_reg_cfg_rec reg_config __aligned(8); +}; + +struct rogue_fwif_reg_cfg { + /* + * PDump WRW command write granularity is 32 bits. + * Add padding to ensure array size is 32 bit granular. + */ + u8 num_regs_type[ALIGN((u32)ROGUE_FWIF_REG_CFG_TYPE_ALL, + sizeof(u32))] __aligned(8); + struct rogue_fwif_reg_cfg_rec + reg_configs[ROGUE_FWIF_REG_CFG_MAX_SIZE] __aligned(8); +} __aligned(8); + +enum rogue_fwif_os_state_change { + ROGUE_FWIF_OS_ONLINE = 1, + ROGUE_FWIF_OS_OFFLINE +}; + +struct rogue_fwif_os_state_change_data { + u32 osid; + enum rogue_fwif_os_state_change new_os_state; +} __aligned(8); + +enum rogue_fwif_counter_dump_request { + ROGUE_FWIF_PWR_COUNTER_DUMP_START = 1, + ROGUE_FWIF_PWR_COUNTER_DUMP_STOP, + ROGUE_FWIF_PWR_COUNTER_DUMP_SAMPLE, +}; + +struct rogue_fwif_counter_dump_data { + enum rogue_fwif_counter_dump_request counter_dump_request; +} __aligned(8); + +enum rogue_fwif_kccb_cmd_type { + /* Common commands */ + ROGUE_FWIF_KCCB_CMD_KICK = 101U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + ROGUE_FWIF_KCCB_CMD_MMUCACHE = 102U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + ROGUE_FWIF_KCCB_CMD_BP = 103U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* SLC flush and invalidation request */ + ROGUE_FWIF_KCCB_CMD_SLCFLUSHINVAL = 105U | + ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* + * Requests cleanup of a FW resource (type specified in the command + * data) + */ + ROGUE_FWIF_KCCB_CMD_CLEANUP = 106U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Power request */ + ROGUE_FWIF_KCCB_CMD_POW = 107U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Backing for on-demand ZS-Buffer done */ + ROGUE_FWIF_KCCB_CMD_ZSBUFFER_BACKING_UPDATE = + 108U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Unbacking for on-demand ZS-Buffer done */ + ROGUE_FWIF_KCCB_CMD_ZSBUFFER_UNBACKING_UPDATE = + 109U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Freelist Grow done */ + ROGUE_FWIF_KCCB_CMD_FREELIST_GROW_UPDATE = + 110U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Freelists Reconstruction done */ + ROGUE_FWIF_KCCB_CMD_FREELISTS_RECONSTRUCTION_UPDATE = + 112U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* + * Informs the firmware that the host has added more data to a CDM2 + * Circular Buffer + */ + ROGUE_FWIF_KCCB_CMD_NOTIFY_WRITE_OFFSET_UPDATE = + 114U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Health check request */ + ROGUE_FWIF_KCCB_CMD_HEALTH_CHECK = 115U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Forcing signalling of all unmet UFOs for a given CCB offset */ + ROGUE_FWIF_KCCB_CMD_FORCE_UPDATE = 116U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + + /* There is a geometry and a fragment command in this single kick */ + ROGUE_FWIF_KCCB_CMD_COMBINED_GEOM_FRAG_KICK = 117U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Informs the FW that a Guest OS has come online / offline. */ + ROGUE_FWIF_KCCB_CMD_OS_ONLINE_STATE_CONFIGURE = 118U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + + /* Commands only permitted to the native or host OS */ + ROGUE_FWIF_KCCB_CMD_REGCONFIG = 200U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + + /* Configure HWPerf events (to be generated) and HWPerf buffer address (if required) */ + ROGUE_FWIF_KCCB_CMD_HWPERF_UPDATE_CONFIG = 201U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + + /* Enable or disable multiple HWPerf blocks (reusing existing configuration) */ + ROGUE_FWIF_KCCB_CMD_HWPERF_CTRL_BLKS = 203U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Core clock speed change event */ + ROGUE_FWIF_KCCB_CMD_CORECLKSPEEDCHANGE = 204U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + + /* + * Ask the firmware to update its cached ui32LogType value from the (shared) + * tracebuf control structure + */ + ROGUE_FWIF_KCCB_CMD_LOGTYPE_UPDATE = 206U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Set a maximum frequency/OPP point */ + ROGUE_FWIF_KCCB_CMD_PDVFS_LIMIT_MAX_FREQ = 207U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* + * Changes the relative scheduling priority for a particular OSid. It can + * only be serviced for the Host DDK + */ + ROGUE_FWIF_KCCB_CMD_OSID_PRIORITY_CHANGE = 208U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Set or clear firmware state flags */ + ROGUE_FWIF_KCCB_CMD_STATEFLAGS_CTRL = 209U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + + /* Set a minimum frequency/OPP point */ + ROGUE_FWIF_KCCB_CMD_PDVFS_LIMIT_MIN_FREQ = 212U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Configure Periodic Hardware Reset behaviour */ + ROGUE_FWIF_KCCB_CMD_PHR_CFG = 213U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + + /* Configure Safety Firmware Watchdog */ + ROGUE_FWIF_KCCB_CMD_WDG_CFG = 215U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Controls counter dumping in the FW */ + ROGUE_FWIF_KCCB_CMD_COUNTER_DUMP = 216U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Configure, clear and enable multiple HWPerf blocks */ + ROGUE_FWIF_KCCB_CMD_HWPERF_CONFIG_ENABLE_BLKS = 217U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Configure the custom counters for HWPerf */ + ROGUE_FWIF_KCCB_CMD_HWPERF_SELECT_CUSTOM_CNTRS = 218U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + + /* Configure directly addressable counters for HWPerf */ + ROGUE_FWIF_KCCB_CMD_HWPERF_CONFIG_BLKS = 220U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, +}; + +#define ROGUE_FWIF_LAST_ALLOWED_GUEST_KCCB_CMD \ + (ROGUE_FWIF_KCCB_CMD_REGCONFIG - 1) + +/* Kernel CCB command packet */ +struct rogue_fwif_kccb_cmd { + /* Command type */ + enum rogue_fwif_kccb_cmd_type cmd_type; + /* Compatibility and other flags */ + u32 kccb_flags; + + /* + * NOTE: Make sure that uCmdData is the last member of this struct + * This is to calculate actual command size for device mem copy. + * (Refer ROGUEGetCmdMemCopySize()) + */ + union { + /* Data for Kick command */ + struct rogue_fwif_kccb_cmd_kick_data cmd_kick_data; + /* Data for combined geom/frag Kick command */ + struct rogue_fwif_kccb_cmd_combined_geom_frag_kick_data + combined_geom_frag_cmd_kick_data; + /* Data for MMU cache command */ + struct rogue_fwif_mmucachedata mmu_cache_data; + /* Data for Breakpoint Commands */ + struct rogue_fwif_bpdata bp_data; + /* Data for SLC Flush/Inval commands */ + struct rogue_fwif_slcflushinvaldata slc_flush_inval_data; + /* Data for cleanup commands */ + struct rogue_fwif_cleanup_request cleanup_data; + /* Data for power request commands */ + struct rogue_fwif_power_request pow_data; + /* Data for HWPerf control command */ + struct rogue_fwif_hwperf_ctrl hw_perf_ctrl; + /* + * Data for HWPerf configure, clear and enable performance + * counter block command + */ + struct rogue_fwif_hwperf_config_enable_blks + hw_perf_cfg_enable_blks; + /* + * Data for HWPerf enable or disable performance counter block + * commands + */ + struct rogue_fwif_hwperf_ctrl_blks hw_perf_ctrl_blks; + /* Data for HWPerf configure the custom counters to read */ + struct rogue_fwif_hwperf_select_custom_cntrs + hw_perf_select_cstm_cntrs; + /* Data for HWPerf configure Directly Addressable blocks */ + struct rogue_fwif_hwperf_config_da_blks hw_perf_cfg_da_blks; + /* Data for core clock speed change */ + struct rogue_fwif_coreclkspeedchange_data + core_clk_speed_change_data; + /* Feedback for Z/S Buffer backing/unbacking */ + struct rogue_fwif_zsbuffer_backing_data zs_buffer_backing_data; + /* Feedback for Freelist grow/shrink */ + struct rogue_fwif_freelist_gs_data free_list_gs_data; + /* Feedback for Freelists reconstruction*/ + struct rogue_fwif_freelists_reconstruction_data + free_lists_reconstruction_data; + /* Data for custom register configuration */ + struct rogue_fwif_regconfig_data reg_config_data; + /* Data for informing the FW about the write offset update */ + struct rogue_fwif_write_offset_update_data + write_offset_update_data; + /* Data for setting the max frequency/OPP */ + struct rogue_fwif_pdvfs_max_freq_data pdvfs_max_freq_data; + /* Data for setting the min frequency/OPP */ + struct rogue_fwif_pdvfs_min_freq_data pdvfs_min_freq_data; + /* Data for updating the Guest Online states */ + struct rogue_fwif_os_state_change_data cmd_os_online_state_data; + /* Dev address for TBI buffer allocated on demand */ + u32 tbi_buffer_fw_addr; + /* Data for dumping of register ranges */ + struct rogue_fwif_counter_dump_data counter_dump_config_data; + /* Data for signalling all unmet fences for a given CCB */ + struct rogue_fwif_kccb_cmd_force_update_data force_update_data; + } cmd_data __aligned(8); +} __aligned(8); + +PVR_FW_STRUCT_SIZE_ASSERT(struct rogue_fwif_kccb_cmd); + +/* + ****************************************************************************** + * Firmware CCB command structure for ROGUE + ****************************************************************************** + */ + +struct rogue_fwif_fwccb_cmd_zsbuffer_backing_data { + u32 zs_buffer_id; +}; + +struct rogue_fwif_fwccb_cmd_freelist_gs_data { + u32 freelist_id; +}; + +struct rogue_fwif_fwccb_cmd_freelists_reconstruction_data { + u32 freelist_count; + u32 hwr_counter; + u32 freelist_ids[ROGUE_FWIF_MAX_FREELISTS_TO_RECONSTRUCT]; +}; + +/* 1 if a page fault happened */ +#define ROGUE_FWIF_FWCCB_CMD_CONTEXT_RESET_FLAG_PF BIT(0) +/* 1 if applicable to all contexts */ +#define ROGUE_FWIF_FWCCB_CMD_CONTEXT_RESET_FLAG_ALL_CTXS BIT(1) + +struct rogue_fwif_fwccb_cmd_context_reset_data { + /* Context affected by the reset */ + u32 server_common_context_id; + /* Reason for reset */ + enum rogue_context_reset_reason reset_reason; + /* Data Master affected by the reset */ + u32 dm; + /* Job ref running at the time of reset */ + u32 reset_job_ref; + /* ROGUE_FWIF_FWCCB_CMD_CONTEXT_RESET_FLAG bitfield */ + u32 flags; + /* At what page catalog address */ + aligned_u64 pc_address; + /* Page fault address (only when applicable) */ + aligned_u64 fault_address; +}; + +struct rogue_fwif_fwccb_cmd_fw_pagefault_data { + /* Page fault address */ + u64 fw_fault_addr; +}; + +enum rogue_fwif_fwccb_cmd_type { + /* Requests ZSBuffer to be backed with physical pages */ + ROGUE_FWIF_FWCCB_CMD_ZSBUFFER_BACKING = 101U | + ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Requests ZSBuffer to be unbacked */ + ROGUE_FWIF_FWCCB_CMD_ZSBUFFER_UNBACKING = 102U | + ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Requests an on-demand freelist grow/shrink */ + ROGUE_FWIF_FWCCB_CMD_FREELIST_GROW = 103U | + ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Requests freelists reconstruction */ + ROGUE_FWIF_FWCCB_CMD_FREELISTS_RECONSTRUCTION = + 104U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Notifies host of a HWR event on a context */ + ROGUE_FWIF_FWCCB_CMD_CONTEXT_RESET_NOTIFICATION = + 105U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Requests an on-demand debug dump */ + ROGUE_FWIF_FWCCB_CMD_DEBUG_DUMP = 106U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + /* Requests an on-demand update on process stats */ + ROGUE_FWIF_FWCCB_CMD_UPDATE_STATS = 107U | + ROGUE_CMD_MAGIC_DWORD_SHIFTED, + + ROGUE_FWIF_FWCCB_CMD_CORE_CLK_RATE_CHANGE = + 108U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + ROGUE_FWIF_FWCCB_CMD_REQUEST_GPU_RESTART = + 109U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, + + /* Notifies host of a FW pagefault */ + ROGUE_FWIF_FWCCB_CMD_CONTEXT_FW_PF_NOTIFICATION = + 112U | ROGUE_CMD_MAGIC_DWORD_SHIFTED, +}; + +enum rogue_fwif_fwccb_cmd_update_stats_type { + /* + * PVRSRVStatsUpdateRenderContextStats should increase the value of the + * ui32TotalNumPartialRenders stat + */ + ROGUE_FWIF_FWCCB_CMD_UPDATE_NUM_PARTIAL_RENDERS = 1, + /* + * PVRSRVStatsUpdateRenderContextStats should increase the value of the + * ui32TotalNumOutOfMemory stat + */ + ROGUE_FWIF_FWCCB_CMD_UPDATE_NUM_OUT_OF_MEMORY, + /* + * PVRSRVStatsUpdateRenderContextStats should increase the value of the + * ui32NumGeomStores stat + */ + ROGUE_FWIF_FWCCB_CMD_UPDATE_NUM_GEOM_STORES, + /* + * PVRSRVStatsUpdateRenderContextStats should increase the value of the + * ui32NumFragStores stat + */ + ROGUE_FWIF_FWCCB_CMD_UPDATE_NUM_FRAG_STORES, + /* + * PVRSRVStatsUpdateRenderContextStats should increase the value of the + * ui32NumCDMStores stat + */ + ROGUE_FWIF_FWCCB_CMD_UPDATE_NUM_CDM_STORES, + /* + * PVRSRVStatsUpdateRenderContextStats should increase the value of the + * ui32NumTDMStores stat + */ + ROGUE_FWIF_FWCCB_CMD_UPDATE_NUM_TDM_STORES +}; + +struct rogue_fwif_fwccb_cmd_update_stats_data { + /* Element to update */ + enum rogue_fwif_fwccb_cmd_update_stats_type element_to_update; + /* The pid of the process whose stats are being updated */ + u32 pid_owner; + /* Adjustment to be made to the statistic */ + s32 adjustment_value; +}; + +struct rogue_fwif_fwccb_cmd_core_clk_rate_change_data { + u32 core_clk_rate; +} __aligned(8); + +struct rogue_fwif_fwccb_cmd { + /* Command type */ + enum rogue_fwif_fwccb_cmd_type cmd_type; + /* Compatibility and other flags */ + u32 fwccb_flags; + + union { + /* Data for Z/S-Buffer on-demand (un)backing*/ + struct rogue_fwif_fwccb_cmd_zsbuffer_backing_data + cmd_zs_buffer_backing; + /* Data for on-demand freelist grow/shrink */ + struct rogue_fwif_fwccb_cmd_freelist_gs_data cmd_free_list_gs; + /* Data for freelists reconstruction */ + struct rogue_fwif_fwccb_cmd_freelists_reconstruction_data + cmd_freelists_reconstruction; + /* Data for context reset notification */ + struct rogue_fwif_fwccb_cmd_context_reset_data + cmd_context_reset_notification; + /* Data for updating process stats */ + struct rogue_fwif_fwccb_cmd_update_stats_data + cmd_update_stats_data; + struct rogue_fwif_fwccb_cmd_core_clk_rate_change_data + cmd_core_clk_rate_change; + struct rogue_fwif_fwccb_cmd_fw_pagefault_data cmd_fw_pagefault; + } cmd_data __aligned(8); +} __aligned(8); + +PVR_FW_STRUCT_SIZE_ASSERT(struct rogue_fwif_fwccb_cmd); + +/* + ****************************************************************************** + * Workload estimation Firmware CCB command structure for ROGUE + ****************************************************************************** + */ +struct rogue_fwif_workest_fwccb_cmd { + /* Index for return data array */ + u16 return_data_index; + /* The cycles the workload took on the hardware */ + u32 cycles_taken; +}; + +/* + ****************************************************************************** + * Client CCB commands for ROGUE + ****************************************************************************** + */ + +/* + * Required memory alignment for 64-bit variables accessible by Meta + * (The gcc meta aligns 64-bit variables to 64-bit; therefore, memory shared + * between the host and meta that contains 64-bit variables has to maintain + * this alignment) + */ +#define ROGUE_FWIF_FWALLOC_ALIGN sizeof(u64) + +#define ROGUE_CCB_TYPE_TASK BIT(15) +#define ROGUE_CCB_FWALLOC_ALIGN(size) \ + (((size) + (ROGUE_FWIF_FWALLOC_ALIGN - 1)) & \ + ~(ROGUE_FWIF_FWALLOC_ALIGN - 1)) + +#define ROGUE_FWIF_CCB_CMD_TYPE_GEOM \ + (201U | ROGUE_CMD_MAGIC_DWORD_SHIFTED | ROGUE_CCB_TYPE_TASK) +#define ROGUE_FWIF_CCB_CMD_TYPE_TQ_3D \ + (202U | ROGUE_CMD_MAGIC_DWORD_SHIFTED | ROGUE_CCB_TYPE_TASK) +#define ROGUE_FWIF_CCB_CMD_TYPE_FRAG \ + (203U | ROGUE_CMD_MAGIC_DWORD_SHIFTED | ROGUE_CCB_TYPE_TASK) +#define ROGUE_FWIF_CCB_CMD_TYPE_FRAG_PR \ + (204U | ROGUE_CMD_MAGIC_DWORD_SHIFTED | ROGUE_CCB_TYPE_TASK) +#define ROGUE_FWIF_CCB_CMD_TYPE_CDM \ + (205U | ROGUE_CMD_MAGIC_DWORD_SHIFTED | ROGUE_CCB_TYPE_TASK) +#define ROGUE_FWIF_CCB_CMD_TYPE_TQ_TDM \ + (206U | ROGUE_CMD_MAGIC_DWORD_SHIFTED | ROGUE_CCB_TYPE_TASK) +#define ROGUE_FWIF_CCB_CMD_TYPE_FBSC_INVALIDATE \ + (207U | ROGUE_CMD_MAGIC_DWORD_SHIFTED | ROGUE_CCB_TYPE_TASK) +#define ROGUE_FWIF_CCB_CMD_TYPE_TQ_2D \ + (208U | ROGUE_CMD_MAGIC_DWORD_SHIFTED | ROGUE_CCB_TYPE_TASK) +#define ROGUE_FWIF_CCB_CMD_TYPE_PRE_TIMESTAMP \ + (209U | ROGUE_CMD_MAGIC_DWORD_SHIFTED | ROGUE_CCB_TYPE_TASK) +#define ROGUE_FWIF_CCB_CMD_TYPE_NULL \ + (210U | ROGUE_CMD_MAGIC_DWORD_SHIFTED | ROGUE_CCB_TYPE_TASK) +#define ROGUE_FWIF_CCB_CMD_TYPE_ABORT \ + (211U | ROGUE_CMD_MAGIC_DWORD_SHIFTED | ROGUE_CCB_TYPE_TASK) + +/* Leave a gap between CCB specific commands and generic commands */ +#define ROGUE_FWIF_CCB_CMD_TYPE_FENCE (212U | ROGUE_CMD_MAGIC_DWORD_SHIFTED) +#define ROGUE_FWIF_CCB_CMD_TYPE_UPDATE (213U | ROGUE_CMD_MAGIC_DWORD_SHIFTED) +#define ROGUE_FWIF_CCB_CMD_TYPE_RMW_UPDATE \ + (214U | ROGUE_CMD_MAGIC_DWORD_SHIFTED) +#define ROGUE_FWIF_CCB_CMD_TYPE_FENCE_PR (215U | ROGUE_CMD_MAGIC_DWORD_SHIFTED) +#define ROGUE_FWIF_CCB_CMD_TYPE_PRIORITY (216U | ROGUE_CMD_MAGIC_DWORD_SHIFTED) +/* + * Pre and Post timestamp commands are supposed to sandwich the DM cmd. The + * padding code with the CCB wrap upsets the FW if we don't have the task type + * bit cleared for POST_TIMESTAMPs. That's why we have 2 different cmd types. + */ +#define ROGUE_FWIF_CCB_CMD_TYPE_POST_TIMESTAMP \ + (217U | ROGUE_CMD_MAGIC_DWORD_SHIFTED) +#define ROGUE_FWIF_CCB_CMD_TYPE_UNFENCED_UPDATE \ + (218U | ROGUE_CMD_MAGIC_DWORD_SHIFTED) +#define ROGUE_FWIF_CCB_CMD_TYPE_UNFENCED_RMW_UPDATE \ + (219U | ROGUE_CMD_MAGIC_DWORD_SHIFTED) + +#define ROGUE_FWIF_CCB_CMD_TYPE_PADDING (221U | ROGUE_CMD_MAGIC_DWORD_SHIFTED) + +struct rogue_fwif_workest_kick_data { + /* Index for the KM Workload estimation return data array */ + u16 return_data_index __aligned(8); + /* Predicted time taken to do the work in cycles */ + u32 cycles_prediction __aligned(8); + /* Deadline for the workload */ + aligned_u64 deadline; +}; + +struct rogue_fwif_ccb_cmd_header { + u32 cmd_type; + u32 cmd_size; + /* + * external job reference - provided by client and used in debug for + * tracking submitted work + */ + u32 ext_job_ref; + /* + * internal job reference - generated by services and used in debug for + * tracking submitted work + */ + u32 int_job_ref; + /* Workload Estimation - Workload Estimation Data */ + struct rogue_fwif_workest_kick_data work_est_kick_data __aligned(8); +}; + +/* + ****************************************************************************** + * Client CCB commands which are only required by the kernel + ****************************************************************************** + */ +struct rogue_fwif_cmd_priority { + s32 priority; +}; + +/* + ****************************************************************************** + * Signature and Checksums Buffer + ****************************************************************************** + */ +struct rogue_fwif_sigbuf_ctl { + /* Ptr to Signature Buffer memory */ + u32 buffer_fw_addr; + /* Amount of space left for storing regs in the buffer */ + u32 left_size_in_regs; +} __aligned(8); + +struct rogue_fwif_counter_dump_ctl { + /* Ptr to counter dump buffer */ + u32 buffer_fw_addr; + /* Amount of space for storing in the buffer */ + u32 size_in_dwords; +} __aligned(8); + +struct rogue_fwif_firmware_gcov_ctl { + /* Ptr to firmware gcov buffer */ + u32 buffer_fw_addr; + /* Amount of space for storing in the buffer */ + u32 size; +} __aligned(8); + +/* + ***************************************************************************** + * ROGUE Compatibility checks + ***************************************************************************** + */ + +/* + * WARNING: Whenever the layout of ROGUE_FWIF_COMPCHECKS_BVNC changes, the + * following define should be increased by 1 to indicate to the compatibility + * logic that layout has changed. + */ +#define ROGUE_FWIF_COMPCHECKS_LAYOUT_VERSION 3 + +struct rogue_fwif_compchecks_bvnc { + /* WARNING: This field must be defined as first one in this structure */ + u32 layout_version; + aligned_u64 bvnc; +} __aligned(8); + +struct rogue_fwif_init_options { + u8 os_count_support; + u8 padding[7]; +} __aligned(8); + +#define ROGUE_FWIF_COMPCHECKS_BVNC_DECLARE_AND_INIT(name) \ + struct rogue_fwif_compchecks_bvnc(name) = { \ + ROGUE_FWIF_COMPCHECKS_LAYOUT_VERSION, \ + 0, \ + } + +static inline void rogue_fwif_compchecks_bvnc_init(struct rogue_fwif_compchecks_bvnc *compchecks) +{ + compchecks->layout_version = ROGUE_FWIF_COMPCHECKS_LAYOUT_VERSION; + compchecks->bvnc = 0; +} + +struct rogue_fwif_compchecks { + /* hardware BVNC (from the ROGUE registers) */ + struct rogue_fwif_compchecks_bvnc hw_bvnc; + /* firmware BVNC */ + struct rogue_fwif_compchecks_bvnc fw_bvnc; + /* identifier of the FW processor version */ + u32 fw_processor_version; + /* software DDK version */ + u32 ddk_version; + /* software DDK build no. */ + u32 ddk_build; + /* build options bit-field */ + u32 build_options; + /* initialisation options bit-field */ + struct rogue_fwif_init_options init_options; + /* Information is valid */ + bool updated __aligned(4); + u32 padding; +} __aligned(8); + +/* + ****************************************************************************** + * Updated configuration post FW data init. + ****************************************************************************** + */ +struct rogue_fwif_runtime_cfg { + /* APM latency in ms before signalling IDLE to the host */ + u32 active_pm_latency_ms; + /* Compatibility and other flags */ + u32 runtime_cfg_flags; + /* + * If set, APM latency does not reset to system default each GPU power + * transition + */ + bool active_pm_latency_persistant __aligned(4); + /* Core clock speed, currently only used to calculate timer ticks */ + u32 core_clock_speed; + /* Last number of dusts change requested by the host */ + u32 default_dusts_num_init; + /* Periodic Hardware Reset configuration values */ + u32 phr_mode; + /* New number of milliseconds C/S is allowed to last */ + u32 hcs_deadline_ms; + /* The watchdog period in microseconds */ + u32 wdg_period_us; + /* Array of priorities per OS */ + u32 osid_priority[ROGUE_FW_MAX_NUM_OS]; + /* On-demand allocated HWPerf buffer address, to be passed to the FW */ + u32 hwperf_buf_fw_addr; + + bool padding __aligned(4); +}; + +/* + ***************************************************************************** + * Control data for ROGUE + ***************************************************************************** + */ + +#define ROGUE_FWIF_HWR_DEBUG_DUMP_ALL (99999U) + +enum rogue_fwif_tpu_dm { + ROGUE_FWIF_TPU_DM_PDM = 0, + ROGUE_FWIF_TPU_DM_VDM = 1, + ROGUE_FWIF_TPU_DM_CDM = 2, + ROGUE_FWIF_TPU_DM_TDM = 3, + ROGUE_FWIF_TPU_DM_LAST +}; + +enum rogue_fwif_gpio_val_mode { + /* No GPIO validation */ + ROGUE_FWIF_GPIO_VAL_OFF = 0, + /* + * Simple test case that initiates by sending data via the GPIO and then + * sends back any data received over the GPIO + */ + ROGUE_FWIF_GPIO_VAL_GENERAL = 1, + /* + * More complex test case that writes and reads data across the entire + * GPIO AP address range. + */ + ROGUE_FWIF_GPIO_VAL_AP = 2, + /* Validates the GPIO Testbench. */ + ROGUE_FWIF_GPIO_VAL_TESTBENCH = 5, + /* Send and then receive each byte in the range 0-255. */ + ROGUE_FWIF_GPIO_VAL_LOOPBACK = 6, + /* Send and then receive each power-of-2 byte in the range 0-255. */ + ROGUE_FWIF_GPIO_VAL_LOOPBACK_LITE = 7, + ROGUE_FWIF_GPIO_VAL_LAST +}; + +enum fw_perf_conf { + FW_PERF_CONF_NONE = 0, + FW_PERF_CONF_ICACHE = 1, + FW_PERF_CONF_DCACHE = 2, + FW_PERF_CONF_JTLB_INSTR = 5, + FW_PERF_CONF_INSTRUCTIONS = 6 +}; + +enum fw_boot_stage { + FW_BOOT_STAGE_TLB_INIT_FAILURE = -2, + FW_BOOT_STAGE_NOT_AVAILABLE = -1, + FW_BOOT_NOT_STARTED = 0, + FW_BOOT_BLDR_STARTED = 1, + FW_BOOT_CACHE_DONE, + FW_BOOT_TLB_DONE, + FW_BOOT_MAIN_STARTED, + FW_BOOT_ALIGNCHECKS_DONE, + FW_BOOT_INIT_DONE, +}; + +/* + * Kernel CCB return slot responses. Usage of bit-fields instead of bare + * integers allows FW to possibly pack-in several responses for each single kCCB + * command. + */ +/* Command executed (return status from FW) */ +#define ROGUE_FWIF_KCCB_RTN_SLOT_CMD_EXECUTED BIT(0) +/* A cleanup was requested but resource busy */ +#define ROGUE_FWIF_KCCB_RTN_SLOT_CLEANUP_BUSY BIT(1) +/* Poll failed in FW for a HW operation to complete */ +#define ROGUE_FWIF_KCCB_RTN_SLOT_POLL_FAILURE BIT(2) +/* Reset value of a kCCB return slot (set by host) */ +#define ROGUE_FWIF_KCCB_RTN_SLOT_NO_RESPONSE 0x0U + +struct rogue_fwif_connection_ctl { + /* Fw-Os connection states */ + enum rogue_fwif_connection_fw_state connection_fw_state; + enum rogue_fwif_connection_os_state connection_os_state; + u32 alive_fw_token; + u32 alive_os_token; +} __aligned(8); + +struct rogue_fwif_osinit { + /* Kernel CCB */ + u32 kernel_ccbctl_fw_addr; + u32 kernel_ccb_fw_addr; + u32 kernel_ccb_rtn_slots_fw_addr; + + /* Firmware CCB */ + u32 firmware_ccbctl_fw_addr; + u32 firmware_ccb_fw_addr; + + /* Workload Estimation Firmware CCB */ + u32 work_est_firmware_ccbctl_fw_addr; + u32 work_est_firmware_ccb_fw_addr; + + u32 rogue_fwif_hwr_info_buf_ctl_fw_addr; + + u32 hwr_debug_dump_limit; + + u32 fw_os_data_fw_addr; + + /* Compatibility checks to be populated by the Firmware */ + struct rogue_fwif_compchecks rogue_comp_checks; +} __aligned(8); + +/* BVNC Features */ +struct rogue_hwperf_bvnc_block { + /* Counter block ID, see ROGUE_HWPERF_CNTBLK_ID */ + u16 block_id; + + /* Number of counters in this block type */ + u16 num_counters; + + /* Number of blocks of this type */ + u16 num_blocks; + + u16 reserved; +}; + +#define ROGUE_HWPERF_MAX_BVNC_LEN (24) + +#define ROGUE_HWPERF_MAX_BVNC_BLOCK_LEN (16U) + +/* BVNC Features */ +struct rogue_hwperf_bvnc { + /* BVNC string */ + char bvnc_string[ROGUE_HWPERF_MAX_BVNC_LEN]; + /* See ROGUE_HWPERF_FEATURE_FLAGS */ + u32 bvnc_km_feature_flags; + /* Number of blocks described in aBvncBlocks */ + u16 num_bvnc_blocks; + /* Number of GPU cores present */ + u16 bvnc_gpu_cores; + /* Supported Performance Blocks for BVNC */ + struct rogue_hwperf_bvnc_block + bvnc_blocks[ROGUE_HWPERF_MAX_BVNC_BLOCK_LEN]; +}; + +PVR_FW_STRUCT_SIZE_ASSERT(struct rogue_hwperf_bvnc); + +struct rogue_fwif_sysinit { + /* Fault read address */ + aligned_u64 fault_phys_addr; + + /* PDS execution base */ + aligned_u64 pds_exec_base; + /* UCS execution base */ + aligned_u64 usc_exec_base; + /* FBCDC bindless texture state table base */ + aligned_u64 fbcdc_state_table_base; + aligned_u64 fbcdc_large_state_table_base; + /* Texture state base */ + aligned_u64 texture_heap_base; + + /* Event filter for Firmware events */ + u64 hw_perf_filter; + + aligned_u64 slc3_fence_dev_addr; + + u32 tpu_trilinear_frac_mask[ROGUE_FWIF_TPU_DM_LAST] __aligned(8); + + /* Signature and Checksum Buffers for DMs */ + struct rogue_fwif_sigbuf_ctl sigbuf_ctl[PVR_FWIF_DM_MAX]; + + struct rogue_fwif_pdvfs_opp pdvfs_opp_info; + + struct rogue_fwif_dma_addr coremem_data_store; + + struct rogue_fwif_counter_dump_ctl counter_dump_ctl; + + u32 filter_flags; + + u32 runtime_cfg_fw_addr; + + u32 trace_buf_ctl_fw_addr; + u32 fw_sys_data_fw_addr; + + u32 gpu_util_fw_cb_ctl_fw_addr; + u32 reg_cfg_fw_addr; + u32 hwperf_ctl_fw_addr; + + u32 align_checks; + + /* Core clock speed at FW boot time */ + u32 initial_core_clock_speed; + + /* APM latency in ms before signalling IDLE to the host */ + u32 active_pm_latency_ms; + + /* Flag to be set by the Firmware after successful start */ + bool firmware_started __aligned(4); + + /* Host/FW Trace synchronisation Partition Marker */ + u32 marker_val; + + /* Firmware initialization complete time */ + u32 firmware_started_timestamp; + + u32 jones_disable_mask; + + /* Firmware performance counter config */ + enum fw_perf_conf firmware_perf; + + /* + * FW Pointer to memory containing core clock rate in Hz. + * Firmware (PDVFS) updates the memory when running on non primary FW + * thread to communicate to host driver. + */ + u32 core_clock_rate_fw_addr; + + enum rogue_fwif_gpio_val_mode gpio_validation_mode; + + /* Used in HWPerf for decoding BVNC Features */ + struct rogue_hwperf_bvnc bvnc_km_feature_flags; + + /* Value to write into ROGUE_CR_TFBC_COMPRESSION_CONTROL */ + u32 tfbc_compression_control; +} __aligned(8); + +/* + ***************************************************************************** + * Timer correlation shared data and defines + ***************************************************************************** + */ + +struct rogue_fwif_time_corr { + aligned_u64 os_timestamp; + aligned_u64 os_mono_timestamp; + aligned_u64 cr_timestamp; + + /* + * Utility variable used to convert CR timer deltas to OS timer deltas + * (nS), where the deltas are relative to the timestamps above: + * deltaOS = (deltaCR * K) >> decimal_shift, see full explanation below + */ + aligned_u64 cr_delta_to_os_delta_kns; + + u32 core_clock_speed; + u32 reserved; +} __aligned(8); + +/* + * The following macros are used to help converting FW timestamps to the Host + * time domain. On the FW the ROGUE_CR_TIMER counter is used to keep track of + * time; it increments by 1 every 256 GPU clock ticks, so the general + * formula to perform the conversion is: + * + * [ GPU clock speed in Hz, if (scale == 10^9) then deltaOS is in nS, + * otherwise if (scale == 10^6) then deltaOS is in uS ] + * + * deltaCR * 256 256 * scale + * deltaOS = --------------- * scale = deltaCR * K [ K = --------------- ] + * GPUclockspeed GPUclockspeed + * + * The actual K is multiplied by 2^20 (and deltaCR * K is divided by 2^20) + * to get some better accuracy and to avoid returning 0 in the integer + * division 256000000/GPUfreq if GPUfreq is greater than 256MHz. + * This is the same as keeping K as a decimal number. + * + * The maximum deltaOS is slightly more than 5hrs for all GPU frequencies + * (deltaCR * K is more or less a constant), and it's relative to the base + * OS timestamp sampled as a part of the timer correlation data. + * This base is refreshed on GPU power-on, DVFS transition and periodic + * frequency calibration (executed every few seconds if the FW is doing + * some work), so as long as the GPU is doing something and one of these + * events is triggered then deltaCR * K will not overflow and deltaOS will be + * correct. + */ + +#define ROGUE_FWIF_CRDELTA_TO_OSDELTA_ACCURACY_SHIFT (20) + +#define ROGUE_FWIF_GET_DELTA_OSTIME_NS(delta_cr, k) \ + (((delta_cr) * (k)) >> ROGUE_FWIF_CRDELTA_TO_OSDELTA_ACCURACY_SHIFT) + +/* + ****************************************************************************** + * GPU Utilisation + ****************************************************************************** + */ + +/* See rogue_common.h for a list of GPU states */ +#define ROGUE_FWIF_GPU_UTIL_TIME_MASK \ + (0xFFFFFFFFFFFFFFFFull & ~ROGUE_FWIF_GPU_UTIL_STATE_MASK) + +#define ROGUE_FWIF_GPU_UTIL_GET_TIME(word) \ + ((word)(&ROGUE_FWIF_GPU_UTIL_TIME_MASK)) +#define ROGUE_FWIF_GPU_UTIL_GET_STATE(word) \ + ((word)(&ROGUE_FWIF_GPU_UTIL_STATE_MASK)) + +/* + * The OS timestamps computed by the FW are approximations of the real time, + * which means they could be slightly behind or ahead the real timer on the + * Host. In some cases we can perform subtractions between FW approximated + * timestamps and real OS timestamps, so we need a form of protection against + * negative results if for instance the FW one is a bit ahead of time. + */ +#define ROGUE_FWIF_GPU_UTIL_GET_PERIOD(newtime, oldtime) \ + (((newtime) > (oldtime)) ? ((newtime) - (oldtime)) : 0U) + +#define ROGUE_FWIF_GPU_UTIL_MAKE_WORD(time, state) \ + (ROGUE_FWIF_GPU_UTIL_GET_TIME(time) | \ + ROGUE_FWIF_GPU_UTIL_GET_STATE(state)) + +/* + * The timer correlation array must be big enough to ensure old entries won't be + * overwritten before all the HWPerf events linked to those entries are + * processed by the MISR. The update frequency of this array depends on how fast + * the system can change state (basically how small the APM latency is) and + * perform DVFS transitions. + * + * The minimum size is 2 (not 1) to avoid race conditions between the FW reading + * an entry while the Host is updating it. With 2 entries in the worst case the + * FW will read old data, which is still quite ok if the Host is updating the + * timer correlation at that time. + */ +#define ROGUE_FWIF_TIME_CORR_ARRAY_SIZE 256U +#define ROGUE_FWIF_TIME_CORR_CURR_INDEX(seqcount) \ + ((seqcount) % ROGUE_FWIF_TIME_CORR_ARRAY_SIZE) + +/* Make sure the timer correlation array size is a power of 2 */ +static_assert((ROGUE_FWIF_TIME_CORR_ARRAY_SIZE & + (ROGUE_FWIF_TIME_CORR_ARRAY_SIZE - 1U)) == 0U, + "ROGUE_FWIF_TIME_CORR_ARRAY_SIZE must be a power of two"); + +struct rogue_fwif_gpu_util_fwcb { + struct rogue_fwif_time_corr time_corr[ROGUE_FWIF_TIME_CORR_ARRAY_SIZE]; + u32 time_corr_seq_count; + + /* Compatibility and other flags */ + u32 gpu_util_flags; + + /* Last GPU state + OS time of the last state update */ + aligned_u64 last_word; + + /* Counters for the amount of time the GPU was active/idle/blocked */ + aligned_u64 stats_counters[PVR_FWIF_GPU_UTIL_STATE_NUM]; +} __aligned(8); + +struct rogue_fwif_rta_ctl { + /* Render number */ + u32 render_target_index; + /* index in RTA */ + u32 current_render_target; + /* total active RTs */ + u32 active_render_targets; + /* total active RTs from the first TA kick, for OOM */ + u32 cumul_active_render_targets; + /* Array of valid RT indices */ + u32 valid_render_targets_fw_addr; + /* Array of number of occurred partial renders per render target */ + u32 rta_num_partial_renders_fw_addr; + /* Number of render targets in the array */ + u32 max_rts; + /* Compatibility and other flags */ + u32 rta_ctl_flags; +} __aligned(8); + +struct rogue_fwif_freelist { + aligned_u64 freelist_dev_addr; + aligned_u64 current_dev_addr; + u32 current_stack_top; + u32 max_pages; + u32 grow_pages; + /* HW pages */ + u32 current_pages; + u32 allocated_page_count; + u32 allocated_mmu_page_count; + u32 freelist_id; + + bool grow_pending __aligned(4); + /* Pages that should be used only when OOM is reached */ + u32 ready_pages; + /* Compatibility and other flags */ + u32 freelist_flags; + /* PM Global PB on which Freelist is loaded */ + u32 pm_global_pb; + u32 padding; +} __aligned(8); + +/* + ****************************************************************************** + * HWRTData + ****************************************************************************** + */ + +/* HWRTData flags */ +/* Deprecated flags 1:0 */ +#define HWRTDATA_HAS_LAST_GEOM BIT(2) +#define HWRTDATA_PARTIAL_RENDERED BIT(3) +#define HWRTDATA_DISABLE_TILE_REORDERING BIT(4) +#define HWRTDATA_NEED_BRN65101_BLIT BIT(5) +#define HWRTDATA_FIRST_BRN65101_STRIP BIT(6) +#define HWRTDATA_NEED_BRN67182_2ND_RENDER BIT(7) + +enum rogue_fwif_rtdata_state { + ROGUE_FWIF_RTDATA_STATE_NONE = 0, + ROGUE_FWIF_RTDATA_STATE_KICK_GEOM, + ROGUE_FWIF_RTDATA_STATE_KICK_GEOM_FIRST, + ROGUE_FWIF_RTDATA_STATE_GEOM_FINISHED, + ROGUE_FWIF_RTDATA_STATE_KICK_FRAG, + ROGUE_FWIF_RTDATA_STATE_FRAG_FINISHED, + ROGUE_FWIF_RTDATA_STATE_FRAG_CONTEXT_STORED, + ROGUE_FWIF_RTDATA_STATE_GEOM_OUTOFMEM, + ROGUE_FWIF_RTDATA_STATE_PARTIALRENDERFINISHED, + /* + * In case of HWR, we can't set the RTDATA state to NONE, as this will + * cause any TA to become a first TA. To ensure all related TA's are + * skipped, we use the HWR state + */ + ROGUE_FWIF_RTDATA_STATE_HWR, + ROGUE_FWIF_RTDATA_STATE_UNKNOWN = 0x7FFFFFFFU +}; + +struct rogue_fwif_hwrtdata_common { + bool geom_caches_need_zeroing __aligned(4); + + u32 screen_pixel_max; + aligned_u64 multi_sample_ctl; + u64 flipped_multi_sample_ctl; + u32 tpc_stride; + u32 tpc_size; + u32 te_screen; + u32 mtile_stride; + u32 teaa; + u32 te_mtile1; + u32 te_mtile2; + u32 isp_merge_lower_x; + u32 isp_merge_lower_y; + u32 isp_merge_upper_x; + u32 isp_merge_upper_y; + u32 isp_merge_scale_x; + u32 isp_merge_scale_y; + u32 rgn_header_size; + u32 isp_mtile_size; + u32 padding; +} __aligned(8); + +struct rogue_fwif_hwrtdata { + /* MList Data Store */ + aligned_u64 pm_mlist_dev_addr; + + aligned_u64 vce_cat_base[4]; + aligned_u64 vce_last_cat_base[4]; + aligned_u64 te_cat_base[4]; + aligned_u64 te_last_cat_base[4]; + aligned_u64 alist_cat_base; + aligned_u64 alist_last_cat_base; + + aligned_u64 pm_alist_stack_pointer; + u32 pm_mlist_stack_pointer; + + u32 hwrt_data_common_fw_addr; + + u32 hwrt_data_flags; + enum rogue_fwif_rtdata_state state; + + u32 freelists_fw_addr[MAX_FREELISTS_SIZE] __aligned(8); + u32 freelist_hwr_snapshot[MAX_FREELISTS_SIZE]; + + aligned_u64 vheap_table_dev_addr; + + struct rogue_fwif_rta_ctl rta_ctl; + + aligned_u64 tail_ptrs_dev_addr; + aligned_u64 macrotile_array_dev_addr; + aligned_u64 rgn_header_dev_addr; + aligned_u64 rtc_dev_addr; + + u32 owner_geom_not_used_by_host __aligned(8); + + bool geom_caches_need_zeroing __aligned(4); + + struct rogue_fwif_cleanup_ctl cleanup_state __aligned(64); +} __aligned(8); + +/* + ****************************************************************************** + * Sync checkpoints + ****************************************************************************** + */ + +#define PVR_SYNC_CHECKPOINT_UNDEF 0x000 +#define PVR_SYNC_CHECKPOINT_ACTIVE 0xac1 /* Checkpoint has not signaled. */ +#define PVR_SYNC_CHECKPOINT_SIGNALED 0x519 /* Checkpoint has signaled. */ +#define PVR_SYNC_CHECKPOINT_ERRORED 0xeff /* Checkpoint has been errored. */ + +#include "pvr_rogue_fwif_check.h" + +#endif /* PVR_ROGUE_FWIF_H */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif_check.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif_check.h new file mode 100644 index 00000000000000..51dc37e78f41d7 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif_check.h @@ -0,0 +1,493 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_ROGUE_FWIF_CHECK_H +#define PVR_ROGUE_FWIF_CHECK_H + +#include + +#define OFFSET_CHECK(type, member, offset) \ + static_assert(offsetof(type, member) == (offset), \ + "offsetof(" #type ", " #member ") incorrect") + +#define SIZE_CHECK(type, size) \ + static_assert(sizeof(type) == (size), #type " is incorrect size") + +OFFSET_CHECK(struct rogue_fwif_file_info_buf, path, 0); +OFFSET_CHECK(struct rogue_fwif_file_info_buf, info, 200); +OFFSET_CHECK(struct rogue_fwif_file_info_buf, line_num, 400); +SIZE_CHECK(struct rogue_fwif_file_info_buf, 408); + +OFFSET_CHECK(struct rogue_fwif_tracebuf_space, trace_pointer, 0); +OFFSET_CHECK(struct rogue_fwif_tracebuf_space, trace_buffer_fw_addr, 4); +OFFSET_CHECK(struct rogue_fwif_tracebuf_space, trace_buffer, 8); +OFFSET_CHECK(struct rogue_fwif_tracebuf_space, assert_buf, 16); +SIZE_CHECK(struct rogue_fwif_tracebuf_space, 424); + +OFFSET_CHECK(struct rogue_fwif_tracebuf, log_type, 0); +OFFSET_CHECK(struct rogue_fwif_tracebuf, tracebuf, 8); +OFFSET_CHECK(struct rogue_fwif_tracebuf, tracebuf_size_in_dwords, 856); +OFFSET_CHECK(struct rogue_fwif_tracebuf, tracebuf_flags, 860); +SIZE_CHECK(struct rogue_fwif_tracebuf, 864); + +OFFSET_CHECK(struct rogue_fw_fault_info, cr_timer, 0); +OFFSET_CHECK(struct rogue_fw_fault_info, os_timer, 8); +OFFSET_CHECK(struct rogue_fw_fault_info, data, 16); +OFFSET_CHECK(struct rogue_fw_fault_info, reserved, 20); +OFFSET_CHECK(struct rogue_fw_fault_info, fault_buf, 24); +SIZE_CHECK(struct rogue_fw_fault_info, 432); + +OFFSET_CHECK(struct rogue_fwif_sysdata, config_flags, 0); +OFFSET_CHECK(struct rogue_fwif_sysdata, config_flags_ext, 4); +OFFSET_CHECK(struct rogue_fwif_sysdata, pow_state, 8); +OFFSET_CHECK(struct rogue_fwif_sysdata, hw_perf_ridx, 12); +OFFSET_CHECK(struct rogue_fwif_sysdata, hw_perf_widx, 16); +OFFSET_CHECK(struct rogue_fwif_sysdata, hw_perf_wrap_count, 20); +OFFSET_CHECK(struct rogue_fwif_sysdata, hw_perf_size, 24); +OFFSET_CHECK(struct rogue_fwif_sysdata, hw_perf_drop_count, 28); +OFFSET_CHECK(struct rogue_fwif_sysdata, hw_perf_ut, 32); +OFFSET_CHECK(struct rogue_fwif_sysdata, first_drop_ordinal, 36); +OFFSET_CHECK(struct rogue_fwif_sysdata, last_drop_ordinal, 40); +OFFSET_CHECK(struct rogue_fwif_sysdata, os_runtime_flags_mirror, 44); +OFFSET_CHECK(struct rogue_fwif_sysdata, fault_info, 80); +OFFSET_CHECK(struct rogue_fwif_sysdata, fw_faults, 3536); +OFFSET_CHECK(struct rogue_fwif_sysdata, cr_poll_addr, 3540); +OFFSET_CHECK(struct rogue_fwif_sysdata, cr_poll_mask, 3548); +OFFSET_CHECK(struct rogue_fwif_sysdata, cr_poll_count, 3556); +OFFSET_CHECK(struct rogue_fwif_sysdata, start_idle_time, 3568); +OFFSET_CHECK(struct rogue_fwif_sysdata, hwr_state_flags, 3576); +OFFSET_CHECK(struct rogue_fwif_sysdata, hwr_recovery_flags, 3580); +OFFSET_CHECK(struct rogue_fwif_sysdata, fw_sys_data_flags, 3616); +OFFSET_CHECK(struct rogue_fwif_sysdata, mc_config, 3620); +SIZE_CHECK(struct rogue_fwif_sysdata, 3624); + +OFFSET_CHECK(struct rogue_fwif_slr_entry, timestamp, 0); +OFFSET_CHECK(struct rogue_fwif_slr_entry, fw_ctx_addr, 8); +OFFSET_CHECK(struct rogue_fwif_slr_entry, num_ufos, 12); +OFFSET_CHECK(struct rogue_fwif_slr_entry, ccb_name, 16); +SIZE_CHECK(struct rogue_fwif_slr_entry, 48); + +OFFSET_CHECK(struct rogue_fwif_osdata, fw_os_config_flags, 0); +OFFSET_CHECK(struct rogue_fwif_osdata, fw_sync_check_mark, 4); +OFFSET_CHECK(struct rogue_fwif_osdata, host_sync_check_mark, 8); +OFFSET_CHECK(struct rogue_fwif_osdata, forced_updates_requested, 12); +OFFSET_CHECK(struct rogue_fwif_osdata, slr_log_wp, 16); +OFFSET_CHECK(struct rogue_fwif_osdata, slr_log_first, 24); +OFFSET_CHECK(struct rogue_fwif_osdata, slr_log, 72); +OFFSET_CHECK(struct rogue_fwif_osdata, last_forced_update_time, 552); +OFFSET_CHECK(struct rogue_fwif_osdata, interrupt_count, 560); +OFFSET_CHECK(struct rogue_fwif_osdata, kccb_cmds_executed, 568); +OFFSET_CHECK(struct rogue_fwif_osdata, power_sync_fw_addr, 572); +OFFSET_CHECK(struct rogue_fwif_osdata, fw_os_data_flags, 576); +SIZE_CHECK(struct rogue_fwif_osdata, 584); + +OFFSET_CHECK(struct rogue_bifinfo, bif_req_status, 0); +OFFSET_CHECK(struct rogue_bifinfo, bif_mmu_status, 8); +OFFSET_CHECK(struct rogue_bifinfo, pc_address, 16); +OFFSET_CHECK(struct rogue_bifinfo, reserved, 24); +SIZE_CHECK(struct rogue_bifinfo, 32); + +OFFSET_CHECK(struct rogue_eccinfo, fault_gpu, 0); +SIZE_CHECK(struct rogue_eccinfo, 4); + +OFFSET_CHECK(struct rogue_mmuinfo, mmu_status, 0); +OFFSET_CHECK(struct rogue_mmuinfo, pc_address, 16); +OFFSET_CHECK(struct rogue_mmuinfo, reserved, 24); +SIZE_CHECK(struct rogue_mmuinfo, 32); + +OFFSET_CHECK(struct rogue_pollinfo, thread_num, 0); +OFFSET_CHECK(struct rogue_pollinfo, cr_poll_addr, 4); +OFFSET_CHECK(struct rogue_pollinfo, cr_poll_mask, 8); +OFFSET_CHECK(struct rogue_pollinfo, cr_poll_last_value, 12); +OFFSET_CHECK(struct rogue_pollinfo, reserved, 16); +SIZE_CHECK(struct rogue_pollinfo, 24); + +OFFSET_CHECK(struct rogue_tlbinfo, bad_addr, 0); +OFFSET_CHECK(struct rogue_tlbinfo, entry_lo, 4); +SIZE_CHECK(struct rogue_tlbinfo, 8); + +OFFSET_CHECK(struct rogue_hwrinfo, hwr_data, 0); +OFFSET_CHECK(struct rogue_hwrinfo, cr_timer, 32); +OFFSET_CHECK(struct rogue_hwrinfo, os_timer, 40); +OFFSET_CHECK(struct rogue_hwrinfo, frame_num, 48); +OFFSET_CHECK(struct rogue_hwrinfo, pid, 52); +OFFSET_CHECK(struct rogue_hwrinfo, active_hwrt_data, 56); +OFFSET_CHECK(struct rogue_hwrinfo, hwr_number, 60); +OFFSET_CHECK(struct rogue_hwrinfo, event_status, 64); +OFFSET_CHECK(struct rogue_hwrinfo, hwr_recovery_flags, 68); +OFFSET_CHECK(struct rogue_hwrinfo, hwr_type, 72); +OFFSET_CHECK(struct rogue_hwrinfo, dm, 76); +OFFSET_CHECK(struct rogue_hwrinfo, core_id, 80); +OFFSET_CHECK(struct rogue_hwrinfo, cr_time_of_kick, 88); +OFFSET_CHECK(struct rogue_hwrinfo, cr_time_hw_reset_start, 96); +OFFSET_CHECK(struct rogue_hwrinfo, cr_time_hw_reset_finish, 104); +OFFSET_CHECK(struct rogue_hwrinfo, cr_time_freelist_ready, 112); +OFFSET_CHECK(struct rogue_hwrinfo, reserved, 120); +SIZE_CHECK(struct rogue_hwrinfo, 136); + +OFFSET_CHECK(struct rogue_fwif_hwrinfobuf, hwr_info, 0); +OFFSET_CHECK(struct rogue_fwif_hwrinfobuf, hwr_counter, 2176); +OFFSET_CHECK(struct rogue_fwif_hwrinfobuf, write_index, 2180); +OFFSET_CHECK(struct rogue_fwif_hwrinfobuf, dd_req_count, 2184); +OFFSET_CHECK(struct rogue_fwif_hwrinfobuf, hwr_info_buf_flags, 2188); +OFFSET_CHECK(struct rogue_fwif_hwrinfobuf, hwr_dm_locked_up_count, 2192); +OFFSET_CHECK(struct rogue_fwif_hwrinfobuf, hwr_dm_overran_count, 2228); +OFFSET_CHECK(struct rogue_fwif_hwrinfobuf, hwr_dm_recovered_count, 2264); +OFFSET_CHECK(struct rogue_fwif_hwrinfobuf, hwr_dm_false_detect_count, 2300); +SIZE_CHECK(struct rogue_fwif_hwrinfobuf, 2336); + +OFFSET_CHECK(struct rogue_fwif_fwmemcontext, pc_dev_paddr, 0); +OFFSET_CHECK(struct rogue_fwif_fwmemcontext, page_cat_base_reg_set, 8); +OFFSET_CHECK(struct rogue_fwif_fwmemcontext, breakpoint_addr, 12); +OFFSET_CHECK(struct rogue_fwif_fwmemcontext, bp_handler_addr, 16); +OFFSET_CHECK(struct rogue_fwif_fwmemcontext, breakpoint_ctl, 20); +OFFSET_CHECK(struct rogue_fwif_fwmemcontext, fw_mem_ctx_flags, 24); +SIZE_CHECK(struct rogue_fwif_fwmemcontext, 32); + +OFFSET_CHECK(struct rogue_fwif_geom_ctx_state_per_geom, geom_reg_vdm_call_stack_pointer, 0); +OFFSET_CHECK(struct rogue_fwif_geom_ctx_state_per_geom, geom_reg_vdm_call_stack_pointer_init, 8); +OFFSET_CHECK(struct rogue_fwif_geom_ctx_state_per_geom, geom_reg_vbs_so_prim, 16); +OFFSET_CHECK(struct rogue_fwif_geom_ctx_state_per_geom, geom_current_idx, 32); +SIZE_CHECK(struct rogue_fwif_geom_ctx_state_per_geom, 40); + +OFFSET_CHECK(struct rogue_fwif_geom_ctx_state, geom_core, 0); +SIZE_CHECK(struct rogue_fwif_geom_ctx_state, 160); + +OFFSET_CHECK(struct rogue_fwif_frag_ctx_state, frag_reg_pm_deallocated_mask_status, 0); +OFFSET_CHECK(struct rogue_fwif_frag_ctx_state, frag_reg_dm_pds_mtilefree_status, 4); +OFFSET_CHECK(struct rogue_fwif_frag_ctx_state, ctx_state_flags, 8); +OFFSET_CHECK(struct rogue_fwif_frag_ctx_state, frag_reg_isp_store, 12); +SIZE_CHECK(struct rogue_fwif_frag_ctx_state, 16); + +OFFSET_CHECK(struct rogue_fwif_compute_ctx_state, ctx_state_flags, 0); +SIZE_CHECK(struct rogue_fwif_compute_ctx_state, 4); + +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, ccbctl_fw_addr, 0); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, ccb_fw_addr, 4); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, ccb_meta_dma_addr, 8); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, context_state_addr, 24); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, fw_com_ctx_flags, 28); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, priority, 32); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, priority_seq_num, 36); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, rf_cmd_addr, 40); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, stats_pending, 44); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, stats_num_stores, 48); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, stats_num_out_of_memory, 52); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, stats_num_partial_renders, 56); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, dm, 60); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, wait_signal_address, 64); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, wait_signal_node, 72); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, buf_stalled_node, 80); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, cbuf_queue_ctrl_addr, 88); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, robustness_address, 96); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, max_deadline_ms, 104); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, read_offset_needs_reset, 108); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, waiting_node, 112); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, run_node, 120); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, last_failed_ufo, 128); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, fw_mem_context_fw_addr, 136); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, server_common_context_id, 140); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, pid, 144); +OFFSET_CHECK(struct rogue_fwif_fwcommoncontext, geom_oom_disabled, 148); +SIZE_CHECK(struct rogue_fwif_fwcommoncontext, 152); + +OFFSET_CHECK(struct rogue_fwif_ccb_ctl, write_offset, 0); +OFFSET_CHECK(struct rogue_fwif_ccb_ctl, padding, 4); +OFFSET_CHECK(struct rogue_fwif_ccb_ctl, read_offset, 128); +OFFSET_CHECK(struct rogue_fwif_ccb_ctl, wrap_mask, 132); +OFFSET_CHECK(struct rogue_fwif_ccb_ctl, cmd_size, 136); +OFFSET_CHECK(struct rogue_fwif_ccb_ctl, padding2, 140); +SIZE_CHECK(struct rogue_fwif_ccb_ctl, 144); + +OFFSET_CHECK(struct rogue_fwif_kccb_cmd_kick_data, context_fw_addr, 0); +OFFSET_CHECK(struct rogue_fwif_kccb_cmd_kick_data, client_woff_update, 4); +OFFSET_CHECK(struct rogue_fwif_kccb_cmd_kick_data, client_wrap_mask_update, 8); +OFFSET_CHECK(struct rogue_fwif_kccb_cmd_kick_data, num_cleanup_ctl, 12); +OFFSET_CHECK(struct rogue_fwif_kccb_cmd_kick_data, cleanup_ctl_fw_addr, 16); +OFFSET_CHECK(struct rogue_fwif_kccb_cmd_kick_data, work_est_cmd_header_offset, 28); +SIZE_CHECK(struct rogue_fwif_kccb_cmd_kick_data, 32); + +OFFSET_CHECK(struct rogue_fwif_kccb_cmd_combined_geom_frag_kick_data, geom_cmd_kick_data, 0); +OFFSET_CHECK(struct rogue_fwif_kccb_cmd_combined_geom_frag_kick_data, frag_cmd_kick_data, 32); +SIZE_CHECK(struct rogue_fwif_kccb_cmd_combined_geom_frag_kick_data, 64); + +OFFSET_CHECK(struct rogue_fwif_kccb_cmd_force_update_data, context_fw_addr, 0); +OFFSET_CHECK(struct rogue_fwif_kccb_cmd_force_update_data, ccb_fence_offset, 4); +SIZE_CHECK(struct rogue_fwif_kccb_cmd_force_update_data, 8); + +OFFSET_CHECK(struct rogue_fwif_cleanup_request, cleanup_type, 0); +OFFSET_CHECK(struct rogue_fwif_cleanup_request, cleanup_data, 4); +SIZE_CHECK(struct rogue_fwif_cleanup_request, 8); + +OFFSET_CHECK(struct rogue_fwif_power_request, pow_type, 0); +OFFSET_CHECK(struct rogue_fwif_power_request, power_req_data, 4); +SIZE_CHECK(struct rogue_fwif_power_request, 8); + +OFFSET_CHECK(struct rogue_fwif_slcflushinvaldata, context_fw_addr, 0); +OFFSET_CHECK(struct rogue_fwif_slcflushinvaldata, inval, 4); +OFFSET_CHECK(struct rogue_fwif_slcflushinvaldata, dm_context, 8); +OFFSET_CHECK(struct rogue_fwif_slcflushinvaldata, address, 16); +OFFSET_CHECK(struct rogue_fwif_slcflushinvaldata, size, 24); +SIZE_CHECK(struct rogue_fwif_slcflushinvaldata, 32); + +OFFSET_CHECK(struct rogue_fwif_hwperf_ctrl, opcode, 0); +OFFSET_CHECK(struct rogue_fwif_hwperf_ctrl, mask, 8); +SIZE_CHECK(struct rogue_fwif_hwperf_ctrl, 16); + +OFFSET_CHECK(struct rogue_fwif_hwperf_config_enable_blks, num_blocks, 0); +OFFSET_CHECK(struct rogue_fwif_hwperf_config_enable_blks, block_configs_fw_addr, 4); +SIZE_CHECK(struct rogue_fwif_hwperf_config_enable_blks, 8); + +OFFSET_CHECK(struct rogue_fwif_hwperf_config_da_blks, num_blocks, 0); +OFFSET_CHECK(struct rogue_fwif_hwperf_config_da_blks, block_configs_fw_addr, 4); +SIZE_CHECK(struct rogue_fwif_hwperf_config_da_blks, 8); + +OFFSET_CHECK(struct rogue_fwif_coreclkspeedchange_data, new_clock_speed, 0); +SIZE_CHECK(struct rogue_fwif_coreclkspeedchange_data, 4); + +OFFSET_CHECK(struct rogue_fwif_hwperf_ctrl_blks, enable, 0); +OFFSET_CHECK(struct rogue_fwif_hwperf_ctrl_blks, num_blocks, 4); +OFFSET_CHECK(struct rogue_fwif_hwperf_ctrl_blks, block_ids, 8); +SIZE_CHECK(struct rogue_fwif_hwperf_ctrl_blks, 40); + +OFFSET_CHECK(struct rogue_fwif_hwperf_select_custom_cntrs, custom_block, 0); +OFFSET_CHECK(struct rogue_fwif_hwperf_select_custom_cntrs, num_counters, 2); +OFFSET_CHECK(struct rogue_fwif_hwperf_select_custom_cntrs, custom_counter_ids_fw_addr, 4); +SIZE_CHECK(struct rogue_fwif_hwperf_select_custom_cntrs, 8); + +OFFSET_CHECK(struct rogue_fwif_zsbuffer_backing_data, zs_buffer_fw_addr, 0); +OFFSET_CHECK(struct rogue_fwif_zsbuffer_backing_data, done, 4); +SIZE_CHECK(struct rogue_fwif_zsbuffer_backing_data, 8); + +OFFSET_CHECK(struct rogue_fwif_freelist_gs_data, freelist_fw_addr, 0); +OFFSET_CHECK(struct rogue_fwif_freelist_gs_data, delta_pages, 4); +OFFSET_CHECK(struct rogue_fwif_freelist_gs_data, new_pages, 8); +OFFSET_CHECK(struct rogue_fwif_freelist_gs_data, ready_pages, 12); +SIZE_CHECK(struct rogue_fwif_freelist_gs_data, 16); + +OFFSET_CHECK(struct rogue_fwif_freelists_reconstruction_data, freelist_count, 0); +OFFSET_CHECK(struct rogue_fwif_freelists_reconstruction_data, freelist_ids, 4); +SIZE_CHECK(struct rogue_fwif_freelists_reconstruction_data, 76); + +OFFSET_CHECK(struct rogue_fwif_write_offset_update_data, context_fw_addr, 0); +SIZE_CHECK(struct rogue_fwif_write_offset_update_data, 8); + +OFFSET_CHECK(struct rogue_fwif_kccb_cmd, cmd_type, 0); +OFFSET_CHECK(struct rogue_fwif_kccb_cmd, kccb_flags, 4); +OFFSET_CHECK(struct rogue_fwif_kccb_cmd, cmd_data, 8); +SIZE_CHECK(struct rogue_fwif_kccb_cmd, 88); + +OFFSET_CHECK(struct rogue_fwif_fwccb_cmd_context_reset_data, server_common_context_id, 0); +OFFSET_CHECK(struct rogue_fwif_fwccb_cmd_context_reset_data, reset_reason, 4); +OFFSET_CHECK(struct rogue_fwif_fwccb_cmd_context_reset_data, dm, 8); +OFFSET_CHECK(struct rogue_fwif_fwccb_cmd_context_reset_data, reset_job_ref, 12); +OFFSET_CHECK(struct rogue_fwif_fwccb_cmd_context_reset_data, flags, 16); +OFFSET_CHECK(struct rogue_fwif_fwccb_cmd_context_reset_data, pc_address, 24); +OFFSET_CHECK(struct rogue_fwif_fwccb_cmd_context_reset_data, fault_address, 32); +SIZE_CHECK(struct rogue_fwif_fwccb_cmd_context_reset_data, 40); + +OFFSET_CHECK(struct rogue_fwif_fwccb_cmd_fw_pagefault_data, fw_fault_addr, 0); +SIZE_CHECK(struct rogue_fwif_fwccb_cmd_fw_pagefault_data, 8); + +OFFSET_CHECK(struct rogue_fwif_fwccb_cmd, cmd_type, 0); +OFFSET_CHECK(struct rogue_fwif_fwccb_cmd, fwccb_flags, 4); +OFFSET_CHECK(struct rogue_fwif_fwccb_cmd, cmd_data, 8); +SIZE_CHECK(struct rogue_fwif_fwccb_cmd, 88); + +OFFSET_CHECK(struct rogue_fwif_ccb_cmd_header, cmd_type, 0); +OFFSET_CHECK(struct rogue_fwif_ccb_cmd_header, cmd_size, 4); +OFFSET_CHECK(struct rogue_fwif_ccb_cmd_header, ext_job_ref, 8); +OFFSET_CHECK(struct rogue_fwif_ccb_cmd_header, int_job_ref, 12); +OFFSET_CHECK(struct rogue_fwif_ccb_cmd_header, work_est_kick_data, 16); +SIZE_CHECK(struct rogue_fwif_ccb_cmd_header, 40); + +OFFSET_CHECK(struct rogue_fwif_runtime_cfg, active_pm_latency_ms, 0); +OFFSET_CHECK(struct rogue_fwif_runtime_cfg, runtime_cfg_flags, 4); +OFFSET_CHECK(struct rogue_fwif_runtime_cfg, active_pm_latency_persistant, 8); +OFFSET_CHECK(struct rogue_fwif_runtime_cfg, core_clock_speed, 12); +OFFSET_CHECK(struct rogue_fwif_runtime_cfg, default_dusts_num_init, 16); +OFFSET_CHECK(struct rogue_fwif_runtime_cfg, phr_mode, 20); +OFFSET_CHECK(struct rogue_fwif_runtime_cfg, hcs_deadline_ms, 24); +OFFSET_CHECK(struct rogue_fwif_runtime_cfg, wdg_period_us, 28); +OFFSET_CHECK(struct rogue_fwif_runtime_cfg, osid_priority, 32); +OFFSET_CHECK(struct rogue_fwif_runtime_cfg, hwperf_buf_fw_addr, 64); +OFFSET_CHECK(struct rogue_fwif_runtime_cfg, padding, 68); +SIZE_CHECK(struct rogue_fwif_runtime_cfg, 72); + +OFFSET_CHECK(struct rogue_fwif_connection_ctl, connection_fw_state, 0); +OFFSET_CHECK(struct rogue_fwif_connection_ctl, connection_os_state, 4); +OFFSET_CHECK(struct rogue_fwif_connection_ctl, alive_fw_token, 8); +OFFSET_CHECK(struct rogue_fwif_connection_ctl, alive_os_token, 12); +SIZE_CHECK(struct rogue_fwif_connection_ctl, 16); + +OFFSET_CHECK(struct rogue_fwif_compchecks_bvnc, layout_version, 0); +OFFSET_CHECK(struct rogue_fwif_compchecks_bvnc, bvnc, 8); +SIZE_CHECK(struct rogue_fwif_compchecks_bvnc, 16); + +OFFSET_CHECK(struct rogue_fwif_init_options, os_count_support, 0); +SIZE_CHECK(struct rogue_fwif_init_options, 8); + +OFFSET_CHECK(struct rogue_fwif_compchecks, hw_bvnc, 0); +OFFSET_CHECK(struct rogue_fwif_compchecks, fw_bvnc, 16); +OFFSET_CHECK(struct rogue_fwif_compchecks, fw_processor_version, 32); +OFFSET_CHECK(struct rogue_fwif_compchecks, ddk_version, 36); +OFFSET_CHECK(struct rogue_fwif_compchecks, ddk_build, 40); +OFFSET_CHECK(struct rogue_fwif_compchecks, build_options, 44); +OFFSET_CHECK(struct rogue_fwif_compchecks, init_options, 48); +OFFSET_CHECK(struct rogue_fwif_compchecks, updated, 56); +SIZE_CHECK(struct rogue_fwif_compchecks, 64); + +OFFSET_CHECK(struct rogue_fwif_osinit, kernel_ccbctl_fw_addr, 0); +OFFSET_CHECK(struct rogue_fwif_osinit, kernel_ccb_fw_addr, 4); +OFFSET_CHECK(struct rogue_fwif_osinit, kernel_ccb_rtn_slots_fw_addr, 8); +OFFSET_CHECK(struct rogue_fwif_osinit, firmware_ccbctl_fw_addr, 12); +OFFSET_CHECK(struct rogue_fwif_osinit, firmware_ccb_fw_addr, 16); +OFFSET_CHECK(struct rogue_fwif_osinit, work_est_firmware_ccbctl_fw_addr, 20); +OFFSET_CHECK(struct rogue_fwif_osinit, work_est_firmware_ccb_fw_addr, 24); +OFFSET_CHECK(struct rogue_fwif_osinit, rogue_fwif_hwr_info_buf_ctl_fw_addr, 28); +OFFSET_CHECK(struct rogue_fwif_osinit, hwr_debug_dump_limit, 32); +OFFSET_CHECK(struct rogue_fwif_osinit, fw_os_data_fw_addr, 36); +OFFSET_CHECK(struct rogue_fwif_osinit, rogue_comp_checks, 40); +SIZE_CHECK(struct rogue_fwif_osinit, 104); + +OFFSET_CHECK(struct rogue_fwif_sigbuf_ctl, buffer_fw_addr, 0); +OFFSET_CHECK(struct rogue_fwif_sigbuf_ctl, left_size_in_regs, 4); +SIZE_CHECK(struct rogue_fwif_sigbuf_ctl, 8); + +OFFSET_CHECK(struct pdvfs_opp, volt, 0); +OFFSET_CHECK(struct pdvfs_opp, freq, 4); +SIZE_CHECK(struct pdvfs_opp, 8); + +OFFSET_CHECK(struct rogue_fwif_pdvfs_opp, opp_values, 0); +OFFSET_CHECK(struct rogue_fwif_pdvfs_opp, min_opp_point, 128); +OFFSET_CHECK(struct rogue_fwif_pdvfs_opp, max_opp_point, 132); +SIZE_CHECK(struct rogue_fwif_pdvfs_opp, 136); + +OFFSET_CHECK(struct rogue_fwif_counter_dump_ctl, buffer_fw_addr, 0); +OFFSET_CHECK(struct rogue_fwif_counter_dump_ctl, size_in_dwords, 4); +SIZE_CHECK(struct rogue_fwif_counter_dump_ctl, 8); + +OFFSET_CHECK(struct rogue_hwperf_bvnc, bvnc_string, 0); +OFFSET_CHECK(struct rogue_hwperf_bvnc, bvnc_km_feature_flags, 24); +OFFSET_CHECK(struct rogue_hwperf_bvnc, num_bvnc_blocks, 28); +OFFSET_CHECK(struct rogue_hwperf_bvnc, bvnc_gpu_cores, 30); +OFFSET_CHECK(struct rogue_hwperf_bvnc, bvnc_blocks, 32); +SIZE_CHECK(struct rogue_hwperf_bvnc, 160); + +OFFSET_CHECK(struct rogue_fwif_sysinit, fault_phys_addr, 0); +OFFSET_CHECK(struct rogue_fwif_sysinit, pds_exec_base, 8); +OFFSET_CHECK(struct rogue_fwif_sysinit, usc_exec_base, 16); +OFFSET_CHECK(struct rogue_fwif_sysinit, fbcdc_state_table_base, 24); +OFFSET_CHECK(struct rogue_fwif_sysinit, fbcdc_large_state_table_base, 32); +OFFSET_CHECK(struct rogue_fwif_sysinit, texture_heap_base, 40); +OFFSET_CHECK(struct rogue_fwif_sysinit, hw_perf_filter, 48); +OFFSET_CHECK(struct rogue_fwif_sysinit, slc3_fence_dev_addr, 56); +OFFSET_CHECK(struct rogue_fwif_sysinit, tpu_trilinear_frac_mask, 64); +OFFSET_CHECK(struct rogue_fwif_sysinit, sigbuf_ctl, 80); +OFFSET_CHECK(struct rogue_fwif_sysinit, pdvfs_opp_info, 152); +OFFSET_CHECK(struct rogue_fwif_sysinit, coremem_data_store, 288); +OFFSET_CHECK(struct rogue_fwif_sysinit, counter_dump_ctl, 304); +OFFSET_CHECK(struct rogue_fwif_sysinit, filter_flags, 312); +OFFSET_CHECK(struct rogue_fwif_sysinit, runtime_cfg_fw_addr, 316); +OFFSET_CHECK(struct rogue_fwif_sysinit, trace_buf_ctl_fw_addr, 320); +OFFSET_CHECK(struct rogue_fwif_sysinit, fw_sys_data_fw_addr, 324); +OFFSET_CHECK(struct rogue_fwif_sysinit, gpu_util_fw_cb_ctl_fw_addr, 328); +OFFSET_CHECK(struct rogue_fwif_sysinit, reg_cfg_fw_addr, 332); +OFFSET_CHECK(struct rogue_fwif_sysinit, hwperf_ctl_fw_addr, 336); +OFFSET_CHECK(struct rogue_fwif_sysinit, align_checks, 340); +OFFSET_CHECK(struct rogue_fwif_sysinit, initial_core_clock_speed, 344); +OFFSET_CHECK(struct rogue_fwif_sysinit, active_pm_latency_ms, 348); +OFFSET_CHECK(struct rogue_fwif_sysinit, firmware_started, 352); +OFFSET_CHECK(struct rogue_fwif_sysinit, marker_val, 356); +OFFSET_CHECK(struct rogue_fwif_sysinit, firmware_started_timestamp, 360); +OFFSET_CHECK(struct rogue_fwif_sysinit, jones_disable_mask, 364); +OFFSET_CHECK(struct rogue_fwif_sysinit, firmware_perf, 368); +OFFSET_CHECK(struct rogue_fwif_sysinit, core_clock_rate_fw_addr, 372); +OFFSET_CHECK(struct rogue_fwif_sysinit, gpio_validation_mode, 376); +OFFSET_CHECK(struct rogue_fwif_sysinit, bvnc_km_feature_flags, 380); +OFFSET_CHECK(struct rogue_fwif_sysinit, tfbc_compression_control, 540); +SIZE_CHECK(struct rogue_fwif_sysinit, 544); + +OFFSET_CHECK(struct rogue_fwif_gpu_util_fwcb, time_corr, 0); +OFFSET_CHECK(struct rogue_fwif_gpu_util_fwcb, time_corr_seq_count, 10240); +OFFSET_CHECK(struct rogue_fwif_gpu_util_fwcb, gpu_util_flags, 10244); +OFFSET_CHECK(struct rogue_fwif_gpu_util_fwcb, last_word, 10248); +OFFSET_CHECK(struct rogue_fwif_gpu_util_fwcb, stats_counters, 10256); +SIZE_CHECK(struct rogue_fwif_gpu_util_fwcb, 10280); + +OFFSET_CHECK(struct rogue_fwif_rta_ctl, render_target_index, 0); +OFFSET_CHECK(struct rogue_fwif_rta_ctl, current_render_target, 4); +OFFSET_CHECK(struct rogue_fwif_rta_ctl, active_render_targets, 8); +OFFSET_CHECK(struct rogue_fwif_rta_ctl, cumul_active_render_targets, 12); +OFFSET_CHECK(struct rogue_fwif_rta_ctl, valid_render_targets_fw_addr, 16); +OFFSET_CHECK(struct rogue_fwif_rta_ctl, rta_num_partial_renders_fw_addr, 20); +OFFSET_CHECK(struct rogue_fwif_rta_ctl, max_rts, 24); +OFFSET_CHECK(struct rogue_fwif_rta_ctl, rta_ctl_flags, 28); +SIZE_CHECK(struct rogue_fwif_rta_ctl, 32); + +OFFSET_CHECK(struct rogue_fwif_freelist, freelist_dev_addr, 0); +OFFSET_CHECK(struct rogue_fwif_freelist, current_dev_addr, 8); +OFFSET_CHECK(struct rogue_fwif_freelist, current_stack_top, 16); +OFFSET_CHECK(struct rogue_fwif_freelist, max_pages, 20); +OFFSET_CHECK(struct rogue_fwif_freelist, grow_pages, 24); +OFFSET_CHECK(struct rogue_fwif_freelist, current_pages, 28); +OFFSET_CHECK(struct rogue_fwif_freelist, allocated_page_count, 32); +OFFSET_CHECK(struct rogue_fwif_freelist, allocated_mmu_page_count, 36); +OFFSET_CHECK(struct rogue_fwif_freelist, freelist_id, 40); +OFFSET_CHECK(struct rogue_fwif_freelist, grow_pending, 44); +OFFSET_CHECK(struct rogue_fwif_freelist, ready_pages, 48); +OFFSET_CHECK(struct rogue_fwif_freelist, freelist_flags, 52); +OFFSET_CHECK(struct rogue_fwif_freelist, pm_global_pb, 56); +SIZE_CHECK(struct rogue_fwif_freelist, 64); + +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, geom_caches_need_zeroing, 0); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, screen_pixel_max, 4); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, multi_sample_ctl, 8); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, flipped_multi_sample_ctl, 16); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, tpc_stride, 24); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, tpc_size, 28); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, te_screen, 32); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, mtile_stride, 36); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, teaa, 40); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, te_mtile1, 44); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, te_mtile2, 48); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, isp_merge_lower_x, 52); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, isp_merge_lower_y, 56); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, isp_merge_upper_x, 60); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, isp_merge_upper_y, 64); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, isp_merge_scale_x, 68); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, isp_merge_scale_y, 72); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, rgn_header_size, 76); +OFFSET_CHECK(struct rogue_fwif_hwrtdata_common, isp_mtile_size, 80); +SIZE_CHECK(struct rogue_fwif_hwrtdata_common, 88); + +OFFSET_CHECK(struct rogue_fwif_hwrtdata, pm_mlist_dev_addr, 0); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, vce_cat_base, 8); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, vce_last_cat_base, 40); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, te_cat_base, 72); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, te_last_cat_base, 104); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, alist_cat_base, 136); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, alist_last_cat_base, 144); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, pm_alist_stack_pointer, 152); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, pm_mlist_stack_pointer, 160); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, hwrt_data_common_fw_addr, 164); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, hwrt_data_flags, 168); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, state, 172); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, freelists_fw_addr, 176); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, freelist_hwr_snapshot, 188); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, vheap_table_dev_addr, 200); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, rta_ctl, 208); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, tail_ptrs_dev_addr, 240); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, macrotile_array_dev_addr, 248); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, rgn_header_dev_addr, 256); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, rtc_dev_addr, 264); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, owner_geom_not_used_by_host, 272); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, geom_caches_need_zeroing, 276); +OFFSET_CHECK(struct rogue_fwif_hwrtdata, cleanup_state, 320); +SIZE_CHECK(struct rogue_fwif_hwrtdata, 384); + +OFFSET_CHECK(struct rogue_fwif_sync_checkpoint, state, 0); +OFFSET_CHECK(struct rogue_fwif_sync_checkpoint, fw_ref_count, 4); +SIZE_CHECK(struct rogue_fwif_sync_checkpoint, 8); + +#endif /* PVR_ROGUE_FWIF_CHECK_H */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif_client.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif_client.h new file mode 100644 index 00000000000000..6e224400083a2c --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif_client.h @@ -0,0 +1,373 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_ROGUE_FWIF_CLIENT_H +#define PVR_ROGUE_FWIF_CLIENT_H + +#include +#include +#include +#include + +#include "pvr_rogue_fwif_shared.h" + +/* + * Page size used for Parameter Management. + */ +#define ROGUE_PM_PAGE_SIZE SZ_4K + +/* + * Minimum/Maximum PB size. + * + * Base page size is dependent on core: + * S6/S6XT/S7 = 50 pages + * S8XE = 40 pages + * S8XE with BRN66011 fixed = 25 pages + * + * Minimum PB = Base Pages + (NUM_TE_PIPES-1)*16K + (NUM_VCE_PIPES-1)*64K + + * IF_PM_PREALLOC(NUM_TE_PIPES*16K + NUM_VCE_PIPES*16K) + * + * Maximum PB size must ensure that no PM address space can be fully used, + * because if the full address space was used it would wrap and corrupt itself. + * Since there are two freelists (local is always minimum sized) this can be + * described as following three conditions being met: + * + * (Minimum PB + Maximum PB) < ALIST PM address space size (16GB) + * (Minimum PB + Maximum PB) < TE PM address space size (16GB) / NUM_TE_PIPES + * (Minimum PB + Maximum PB) < VCE PM address space size (16GB) / NUM_VCE_PIPES + * + * Since the max of NUM_TE_PIPES and NUM_VCE_PIPES is 4, we have a hard limit + * of 4GB minus the Minimum PB. For convenience we take the smaller power-of-2 + * value of 2GB. This is far more than any current applications use. + */ +#define ROGUE_PM_MAX_FREELIST_SIZE SZ_2G + +/* + * Flags supported by the geometry DM command i.e. &struct rogue_fwif_cmd_geom. + */ + +#define ROGUE_GEOM_FLAGS_FIRSTKICK BIT_MASK(0) +#define ROGUE_GEOM_FLAGS_LASTKICK BIT_MASK(1) +/* Use single core in a multi core setup. */ +#define ROGUE_GEOM_FLAGS_SINGLE_CORE BIT_MASK(3) + +/* + * Flags supported by the fragment DM command i.e. &struct rogue_fwif_cmd_frag. + */ + +/* Use single core in a multi core setup. */ +#define ROGUE_FRAG_FLAGS_SINGLE_CORE BIT_MASK(3) +/* Indicates whether this render produces visibility results. */ +#define ROGUE_FRAG_FLAGS_GET_VIS_RESULTS BIT_MASK(5) +/* Indicates whether a depth buffer is present. */ +#define ROGUE_FRAG_FLAGS_DEPTHBUFFER BIT_MASK(7) +/* Indicates whether a stencil buffer is present. */ +#define ROGUE_FRAG_FLAGS_STENCILBUFFER BIT_MASK(8) +/* Disable pixel merging for this render. */ +#define ROGUE_FRAG_FLAGS_DISABLE_PIXELMERGE BIT_MASK(15) +/* Indicates whether a scratch buffer is present. */ +#define ROGUE_FRAG_FLAGS_SCRATCHBUFFER BIT_MASK(19) +/* Disallow compute overlapped with this render. */ +#define ROGUE_FRAG_FLAGS_PREVENT_CDM_OVERLAP BIT_MASK(26) + +/* + * Flags supported by the compute DM command i.e. &struct rogue_fwif_cmd_compute. + */ + +#define ROGUE_COMPUTE_FLAG_PREVENT_ALL_OVERLAP BIT_MASK(2) +/*!< Use single core in a multi core setup. */ +#define ROGUE_COMPUTE_FLAG_SINGLE_CORE BIT_MASK(5) + +/* + * Flags supported by the transfer DM command i.e. &struct rogue_fwif_cmd_transfer. + */ + +/*!< Use single core in a multi core setup. */ +#define ROGUE_TRANSFER_FLAGS_SINGLE_CORE BIT_MASK(1) + +/* + ************************************************ + * Parameter/HWRTData control structures. + ************************************************ + */ + +/* + * Configuration registers which need to be loaded by the firmware before a geometry + * job can be started. + */ +struct rogue_fwif_geom_regs { + u64 vdm_ctrl_stream_base; + u64 tpu_border_colour_table; + + /* Only used when feature VDM_DRAWINDIRECT present. */ + u64 vdm_draw_indirect0; + /* Only used when feature VDM_DRAWINDIRECT present. */ + u32 vdm_draw_indirect1; + + u32 ppp_ctrl; + u32 te_psg; + /* Only used when BRN 49927 present. */ + u32 tpu; + + u32 vdm_context_resume_task0_size; + /* Only used when feature VDM_OBJECT_LEVEL_LLS present. */ + u32 vdm_context_resume_task3_size; + + /* Only used when BRN 56279 or BRN 67381 present. */ + u32 pds_ctrl; + + u32 view_idx; + + /* Only used when feature TESSELLATION present */ + u32 pds_coeff_free_prog; + + u32 padding; +}; + +/* Only used when BRN 44455 or BRN 63027 present. */ +struct rogue_fwif_dummy_rgnhdr_init_geom_regs { + u64 te_psgregion_addr; +}; + +/* + * Represents a geometry command that can be used to tile a whole scene's objects as + * per TA behavior. + */ +struct rogue_fwif_cmd_geom { + /* + * rogue_fwif_cmd_geom_frag_shared field must always be at the beginning of the + * struct. + * + * The command struct (rogue_fwif_cmd_geom) is shared between Client and + * Firmware. Kernel is unable to perform read/write operations on the + * command struct, the SHARED region is the only exception from this rule. + * This region must be the first member so that Kernel can easily access it. + * For more info, see rogue_fwif_cmd_geom_frag_shared definition. + */ + struct rogue_fwif_cmd_geom_frag_shared cmd_shared; + + struct rogue_fwif_geom_regs regs __aligned(8); + u32 flags __aligned(8); + + /* + * Holds the geometry/fragment fence value to allow the fragment partial render command + * to go through. + */ + struct rogue_fwif_ufo partial_render_geom_frag_fence; + + /* Only used when BRN 44455 or BRN 63027 present. */ + struct rogue_fwif_dummy_rgnhdr_init_geom_regs dummy_rgnhdr_init_geom_regs __aligned(8); + + /* Only used when BRN 61484 or BRN 66333 present. */ + u32 brn61484_66333_live_rt; + + u32 padding; +}; + +/* + * Configuration registers which need to be loaded by the firmware before ISP + * can be started. + */ +struct rogue_fwif_frag_regs { + u32 usc_pixel_output_ctrl; + +#define ROGUE_MAXIMUM_OUTPUT_REGISTERS_PER_PIXEL 8U + u32 usc_clear_register[ROGUE_MAXIMUM_OUTPUT_REGISTERS_PER_PIXEL]; + + u32 isp_bgobjdepth; + u32 isp_bgobjvals; + u32 isp_aa; + /* Only used when feature S7_TOP_INFRASTRUCTURE present. */ + u32 isp_xtp_pipe_enable; + + u32 isp_ctl; + + /* Only used when BRN 49927 present. */ + u32 tpu; + + u32 event_pixel_pds_info; + + /* Only used when feature CLUSTER_GROUPING present. */ + u32 pixel_phantom; + + u32 view_idx; + + u32 event_pixel_pds_data; + + /* Only used when BRN 65101 present. */ + u32 brn65101_event_pixel_pds_data; + + /* Only used when feature GPU_MULTICORE_SUPPORT or BRN 47217 present. */ + u32 isp_oclqry_stride; + + /* Only used when feature ZLS_SUBTILE present. */ + u32 isp_zls_pixels; + + /* Only used when feature ISP_ZLS_D24_S8_PACKING_OGL_MODE present. */ + u32 rgx_cr_blackpearl_fix; + + /* All values below the ALIGN(8) must be 64 bit. */ + aligned_u64 isp_scissor_base; + u64 isp_dbias_base; + u64 isp_oclqry_base; + u64 isp_zlsctl; + u64 isp_zload_store_base; + u64 isp_stencil_load_store_base; + + /* + * Only used when feature FBCDC_ALGORITHM present and value < 3 or feature + * FB_CDC_V4 present. Additionally, BRNs 48754, 60227, 72310 and 72311 must + * not be present. + */ + u64 fb_cdc_zls; + +#define ROGUE_PBE_WORDS_REQUIRED_FOR_RENDERS 3U + u64 pbe_word[8U][ROGUE_PBE_WORDS_REQUIRED_FOR_RENDERS]; + u64 tpu_border_colour_table; + u64 pds_bgnd[3U]; + + /* Only used when BRN 65101 present. */ + u64 pds_bgnd_brn65101[3U]; + + u64 pds_pr_bgnd[3U]; + + /* Only used when BRN 62850 or 62865 present. */ + u64 isp_dummy_stencil_store_base; + + /* Only used when BRN 66193 present. */ + u64 isp_dummy_depth_store_base; + + /* Only used when BRN 67182 present. */ + u32 rgnhdr_single_rt_size; + /* Only used when BRN 67182 present. */ + u32 rgnhdr_scratch_offset; +}; + +struct rogue_fwif_cmd_frag { + struct rogue_fwif_cmd_geom_frag_shared cmd_shared __aligned(8); + + struct rogue_fwif_frag_regs regs __aligned(8); + /* command control flags. */ + u32 flags; + /* Stride IN BYTES for Z-Buffer in case of RTAs. */ + u32 zls_stride; + /* Stride IN BYTES for S-Buffer in case of RTAs. */ + u32 sls_stride; + + /* Only used if feature GPU_MULTICORE_SUPPORT present. */ + u32 execute_count; +}; + +/* + * Configuration registers which need to be loaded by the firmware before CDM + * can be started. + */ +struct rogue_fwif_compute_regs { + u64 tpu_border_colour_table; + + /* Only used when feature CDM_USER_MODE_QUEUE present. */ + u64 cdm_cb_queue; + + /* Only used when feature CDM_USER_MODE_QUEUE present. */ + u64 cdm_cb_base; + /* Only used when feature CDM_USER_MODE_QUEUE present. */ + u64 cdm_cb; + + /* Only used when feature CDM_USER_MODE_QUEUE is not present. */ + u64 cdm_ctrl_stream_base; + + u64 cdm_context_state_base_addr; + + /* Only used when BRN 49927 is present. */ + u32 tpu; + u32 cdm_resume_pds1; + + /* Only used when feature COMPUTE_MORTON_CAPABLE present. */ + u32 cdm_item; + + /* Only used when feature CLUSTER_GROUPING present. */ + u32 compute_cluster; + + /* Only used when feature TPU_DM_GLOBAL_REGISTERS present. */ + u32 tpu_tag_cdm_ctrl; + + u32 padding; +}; + +struct rogue_fwif_cmd_compute { + /* Common command attributes */ + struct rogue_fwif_cmd_common common __aligned(8); + + /* CDM registers */ + struct rogue_fwif_compute_regs regs; + + /* Control flags */ + u32 flags __aligned(8); + + /* Only used when feature UNIFIED_STORE_VIRTUAL_PARTITIONING present. */ + u32 num_temp_regions; + + /* Only used when feature CDM_USER_MODE_QUEUE present. */ + u32 stream_start_offset; + + /* Only used when feature GPU_MULTICORE_SUPPORT present. */ + u32 execute_count; +}; + +struct rogue_fwif_transfer_regs { + /* + * All 32 bit values should be added in the top section. This then requires only a + * single RGXFW_ALIGN to align all the 64 bit values in the second section. + */ + u32 isp_bgobjvals; + + u32 usc_pixel_output_ctrl; + u32 usc_clear_register0; + u32 usc_clear_register1; + u32 usc_clear_register2; + u32 usc_clear_register3; + + u32 isp_mtile_size; + u32 isp_render_origin; + u32 isp_ctl; + + /* Only used when feature S7_TOP_INFRASTRUCTURE present. */ + u32 isp_xtp_pipe_enable; + u32 isp_aa; + + u32 event_pixel_pds_info; + + u32 event_pixel_pds_code; + u32 event_pixel_pds_data; + + u32 isp_render; + u32 isp_rgn; + + /* Only used when feature GPU_MULTICORE_SUPPORT present. */ + u32 frag_screen; + + /* All values below the aligned_u64 must be 64 bit. */ + aligned_u64 pds_bgnd0_base; + u64 pds_bgnd1_base; + u64 pds_bgnd3_sizeinfo; + + u64 isp_mtile_base; +#define ROGUE_PBE_WORDS_REQUIRED_FOR_TQS 3 + /* TQ_MAX_RENDER_TARGETS * PBE_STATE_SIZE */ + u64 pbe_wordx_mrty[3U * ROGUE_PBE_WORDS_REQUIRED_FOR_TQS]; +}; + +struct rogue_fwif_cmd_transfer { + /* Common command attributes */ + struct rogue_fwif_cmd_common common __aligned(8); + + struct rogue_fwif_transfer_regs regs __aligned(8); + + u32 flags; + + u32 padding; +}; + +#include "pvr_rogue_fwif_client_check.h" + +#endif /* PVR_ROGUE_FWIF_CLIENT_H */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif_client_check.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif_client_check.h new file mode 100644 index 00000000000000..54aa4474163e67 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif_client_check.h @@ -0,0 +1,133 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_ROGUE_FWIF_CLIENT_CHECK_H +#define PVR_ROGUE_FWIF_CLIENT_CHECK_H + +#include + +#define OFFSET_CHECK(type, member, offset) \ + static_assert(offsetof(type, member) == (offset), \ + "offsetof(" #type ", " #member ") incorrect") + +#define SIZE_CHECK(type, size) \ + static_assert(sizeof(type) == (size), #type " is incorrect size") + +OFFSET_CHECK(struct rogue_fwif_geom_regs, vdm_ctrl_stream_base, 0); +OFFSET_CHECK(struct rogue_fwif_geom_regs, tpu_border_colour_table, 8); +OFFSET_CHECK(struct rogue_fwif_geom_regs, vdm_draw_indirect0, 16); +OFFSET_CHECK(struct rogue_fwif_geom_regs, vdm_draw_indirect1, 24); +OFFSET_CHECK(struct rogue_fwif_geom_regs, ppp_ctrl, 28); +OFFSET_CHECK(struct rogue_fwif_geom_regs, te_psg, 32); +OFFSET_CHECK(struct rogue_fwif_geom_regs, tpu, 36); +OFFSET_CHECK(struct rogue_fwif_geom_regs, vdm_context_resume_task0_size, 40); +OFFSET_CHECK(struct rogue_fwif_geom_regs, vdm_context_resume_task3_size, 44); +OFFSET_CHECK(struct rogue_fwif_geom_regs, pds_ctrl, 48); +OFFSET_CHECK(struct rogue_fwif_geom_regs, view_idx, 52); +OFFSET_CHECK(struct rogue_fwif_geom_regs, pds_coeff_free_prog, 56); +SIZE_CHECK(struct rogue_fwif_geom_regs, 64); + +OFFSET_CHECK(struct rogue_fwif_dummy_rgnhdr_init_geom_regs, te_psgregion_addr, 0); +SIZE_CHECK(struct rogue_fwif_dummy_rgnhdr_init_geom_regs, 8); + +OFFSET_CHECK(struct rogue_fwif_cmd_geom, cmd_shared, 0); +OFFSET_CHECK(struct rogue_fwif_cmd_geom, regs, 16); +OFFSET_CHECK(struct rogue_fwif_cmd_geom, flags, 80); +OFFSET_CHECK(struct rogue_fwif_cmd_geom, partial_render_geom_frag_fence, 84); +OFFSET_CHECK(struct rogue_fwif_cmd_geom, dummy_rgnhdr_init_geom_regs, 96); +OFFSET_CHECK(struct rogue_fwif_cmd_geom, brn61484_66333_live_rt, 104); +SIZE_CHECK(struct rogue_fwif_cmd_geom, 112); + +OFFSET_CHECK(struct rogue_fwif_frag_regs, usc_pixel_output_ctrl, 0); +OFFSET_CHECK(struct rogue_fwif_frag_regs, usc_clear_register, 4); +OFFSET_CHECK(struct rogue_fwif_frag_regs, isp_bgobjdepth, 36); +OFFSET_CHECK(struct rogue_fwif_frag_regs, isp_bgobjvals, 40); +OFFSET_CHECK(struct rogue_fwif_frag_regs, isp_aa, 44); +OFFSET_CHECK(struct rogue_fwif_frag_regs, isp_xtp_pipe_enable, 48); +OFFSET_CHECK(struct rogue_fwif_frag_regs, isp_ctl, 52); +OFFSET_CHECK(struct rogue_fwif_frag_regs, tpu, 56); +OFFSET_CHECK(struct rogue_fwif_frag_regs, event_pixel_pds_info, 60); +OFFSET_CHECK(struct rogue_fwif_frag_regs, pixel_phantom, 64); +OFFSET_CHECK(struct rogue_fwif_frag_regs, view_idx, 68); +OFFSET_CHECK(struct rogue_fwif_frag_regs, event_pixel_pds_data, 72); +OFFSET_CHECK(struct rogue_fwif_frag_regs, brn65101_event_pixel_pds_data, 76); +OFFSET_CHECK(struct rogue_fwif_frag_regs, isp_oclqry_stride, 80); +OFFSET_CHECK(struct rogue_fwif_frag_regs, isp_zls_pixels, 84); +OFFSET_CHECK(struct rogue_fwif_frag_regs, rgx_cr_blackpearl_fix, 88); +OFFSET_CHECK(struct rogue_fwif_frag_regs, isp_scissor_base, 96); +OFFSET_CHECK(struct rogue_fwif_frag_regs, isp_dbias_base, 104); +OFFSET_CHECK(struct rogue_fwif_frag_regs, isp_oclqry_base, 112); +OFFSET_CHECK(struct rogue_fwif_frag_regs, isp_zlsctl, 120); +OFFSET_CHECK(struct rogue_fwif_frag_regs, isp_zload_store_base, 128); +OFFSET_CHECK(struct rogue_fwif_frag_regs, isp_stencil_load_store_base, 136); +OFFSET_CHECK(struct rogue_fwif_frag_regs, fb_cdc_zls, 144); +OFFSET_CHECK(struct rogue_fwif_frag_regs, pbe_word, 152); +OFFSET_CHECK(struct rogue_fwif_frag_regs, tpu_border_colour_table, 344); +OFFSET_CHECK(struct rogue_fwif_frag_regs, pds_bgnd, 352); +OFFSET_CHECK(struct rogue_fwif_frag_regs, pds_bgnd_brn65101, 376); +OFFSET_CHECK(struct rogue_fwif_frag_regs, pds_pr_bgnd, 400); +OFFSET_CHECK(struct rogue_fwif_frag_regs, isp_dummy_stencil_store_base, 424); +OFFSET_CHECK(struct rogue_fwif_frag_regs, isp_dummy_depth_store_base, 432); +OFFSET_CHECK(struct rogue_fwif_frag_regs, rgnhdr_single_rt_size, 440); +OFFSET_CHECK(struct rogue_fwif_frag_regs, rgnhdr_scratch_offset, 444); +SIZE_CHECK(struct rogue_fwif_frag_regs, 448); + +OFFSET_CHECK(struct rogue_fwif_cmd_frag, cmd_shared, 0); +OFFSET_CHECK(struct rogue_fwif_cmd_frag, regs, 16); +OFFSET_CHECK(struct rogue_fwif_cmd_frag, flags, 464); +OFFSET_CHECK(struct rogue_fwif_cmd_frag, zls_stride, 468); +OFFSET_CHECK(struct rogue_fwif_cmd_frag, sls_stride, 472); +OFFSET_CHECK(struct rogue_fwif_cmd_frag, execute_count, 476); +SIZE_CHECK(struct rogue_fwif_cmd_frag, 480); + +OFFSET_CHECK(struct rogue_fwif_compute_regs, tpu_border_colour_table, 0); +OFFSET_CHECK(struct rogue_fwif_compute_regs, cdm_cb_queue, 8); +OFFSET_CHECK(struct rogue_fwif_compute_regs, cdm_cb_base, 16); +OFFSET_CHECK(struct rogue_fwif_compute_regs, cdm_cb, 24); +OFFSET_CHECK(struct rogue_fwif_compute_regs, cdm_ctrl_stream_base, 32); +OFFSET_CHECK(struct rogue_fwif_compute_regs, cdm_context_state_base_addr, 40); +OFFSET_CHECK(struct rogue_fwif_compute_regs, tpu, 48); +OFFSET_CHECK(struct rogue_fwif_compute_regs, cdm_resume_pds1, 52); +OFFSET_CHECK(struct rogue_fwif_compute_regs, cdm_item, 56); +OFFSET_CHECK(struct rogue_fwif_compute_regs, compute_cluster, 60); +OFFSET_CHECK(struct rogue_fwif_compute_regs, tpu_tag_cdm_ctrl, 64); +SIZE_CHECK(struct rogue_fwif_compute_regs, 72); + +OFFSET_CHECK(struct rogue_fwif_cmd_compute, common, 0); +OFFSET_CHECK(struct rogue_fwif_cmd_compute, regs, 8); +OFFSET_CHECK(struct rogue_fwif_cmd_compute, flags, 80); +OFFSET_CHECK(struct rogue_fwif_cmd_compute, num_temp_regions, 84); +OFFSET_CHECK(struct rogue_fwif_cmd_compute, stream_start_offset, 88); +OFFSET_CHECK(struct rogue_fwif_cmd_compute, execute_count, 92); +SIZE_CHECK(struct rogue_fwif_cmd_compute, 96); + +OFFSET_CHECK(struct rogue_fwif_transfer_regs, isp_bgobjvals, 0); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, usc_pixel_output_ctrl, 4); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, usc_clear_register0, 8); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, usc_clear_register1, 12); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, usc_clear_register2, 16); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, usc_clear_register3, 20); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, isp_mtile_size, 24); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, isp_render_origin, 28); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, isp_ctl, 32); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, isp_xtp_pipe_enable, 36); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, isp_aa, 40); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, event_pixel_pds_info, 44); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, event_pixel_pds_code, 48); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, event_pixel_pds_data, 52); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, isp_render, 56); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, isp_rgn, 60); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, frag_screen, 64); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, pds_bgnd0_base, 72); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, pds_bgnd1_base, 80); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, pds_bgnd3_sizeinfo, 88); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, isp_mtile_base, 96); +OFFSET_CHECK(struct rogue_fwif_transfer_regs, pbe_wordx_mrty, 104); +SIZE_CHECK(struct rogue_fwif_transfer_regs, 176); + +OFFSET_CHECK(struct rogue_fwif_cmd_transfer, common, 0); +OFFSET_CHECK(struct rogue_fwif_cmd_transfer, regs, 8); +OFFSET_CHECK(struct rogue_fwif_cmd_transfer, flags, 184); +SIZE_CHECK(struct rogue_fwif_cmd_transfer, 192); + +#endif /* PVR_ROGUE_FWIF_CLIENT_CHECK_H */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif_common.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif_common.h new file mode 100644 index 00000000000000..6ebb95ba98a60f --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif_common.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_ROGUE_FWIF_COMMON_H +#define PVR_ROGUE_FWIF_COMMON_H + +#include + +/* + * This macro represents a mask of LSBs that must be zero on data structure + * sizes and offsets to ensure they are 8-byte granular on types shared between + * the FW and host driver. + */ +#define PVR_FW_ALIGNMENT_LSB 7U + +/* Macro to test structure size alignment. */ +#define PVR_FW_STRUCT_SIZE_ASSERT(_a) \ + static_assert((sizeof(_a) & PVR_FW_ALIGNMENT_LSB) == 0U, \ + "Size of " #_a " is not properly aligned") + +/* The master definition for data masters known to the firmware. */ + +#define PVR_FWIF_DM_GP (0) +/* Either TDM or 2D DM is present. */ +/* When the 'tla' feature is present in the hw (as per @pvr_device_features). */ +#define PVR_FWIF_DM_2D (1) +/* + * When the 'fastrender_dm' feature is present in the hw (as per + * @pvr_device_features). + */ +#define PVR_FWIF_DM_TDM (1) + +#define PVR_FWIF_DM_GEOM (2) +#define PVR_FWIF_DM_FRAG (3) +#define PVR_FWIF_DM_CDM (4) +#define PVR_FWIF_DM_RAY (5) +#define PVR_FWIF_DM_GEOM2 (6) +#define PVR_FWIF_DM_GEOM3 (7) +#define PVR_FWIF_DM_GEOM4 (8) + +#define PVR_FWIF_DM_LAST PVR_FWIF_DM_GEOM4 + +/* Maximum number of DM in use: GP, 2D/TDM, GEOM, 3D, CDM, RAY, GEOM2, GEOM3, GEOM4 */ +#define PVR_FWIF_DM_MAX (PVR_FWIF_DM_LAST + 1U) + +/* GPU Utilisation states */ +#define PVR_FWIF_GPU_UTIL_STATE_IDLE 0U +#define PVR_FWIF_GPU_UTIL_STATE_ACTIVE 1U +#define PVR_FWIF_GPU_UTIL_STATE_BLOCKED 2U +#define PVR_FWIF_GPU_UTIL_STATE_NUM 3U +#define PVR_FWIF_GPU_UTIL_STATE_MASK 0x3ULL + +/* + * Maximum amount of register writes that can be done by the register + * programmer (FW or META DMA). This is not a HW limitation, it is only + * a protection against malformed inputs to the register programmer. + */ +#define PVR_MAX_NUM_REGISTER_PROGRAMMER_WRITES 128U + +#endif /* PVR_ROGUE_FWIF_COMMON_H */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif_dev_info.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif_dev_info.h new file mode 100644 index 00000000000000..168277bce9485c --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif_dev_info.h @@ -0,0 +1,113 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef __PVR_ROGUE_FWIF_DEV_INFO_H__ +#define __PVR_ROGUE_FWIF_DEV_INFO_H__ + +enum { + PVR_FW_HAS_BRN_44079 = 0, + PVR_FW_HAS_BRN_47217, + PVR_FW_HAS_BRN_48492, + PVR_FW_HAS_BRN_48545, + PVR_FW_HAS_BRN_49927, + PVR_FW_HAS_BRN_50767, + PVR_FW_HAS_BRN_51764, + PVR_FW_HAS_BRN_62269, + PVR_FW_HAS_BRN_63142, + PVR_FW_HAS_BRN_63553, + PVR_FW_HAS_BRN_66011, + PVR_FW_HAS_BRN_71242, + + PVR_FW_HAS_BRN_MAX +}; + +enum { + PVR_FW_HAS_ERN_35421 = 0, + PVR_FW_HAS_ERN_38020, + PVR_FW_HAS_ERN_38748, + PVR_FW_HAS_ERN_42064, + PVR_FW_HAS_ERN_42290, + PVR_FW_HAS_ERN_42606, + PVR_FW_HAS_ERN_47025, + PVR_FW_HAS_ERN_57596, + + PVR_FW_HAS_ERN_MAX +}; + +enum { + PVR_FW_HAS_FEATURE_AXI_ACELITE = 0, + PVR_FW_HAS_FEATURE_CDM_CONTROL_STREAM_FORMAT, + PVR_FW_HAS_FEATURE_CLUSTER_GROUPING, + PVR_FW_HAS_FEATURE_COMMON_STORE_SIZE_IN_DWORDS, + PVR_FW_HAS_FEATURE_COMPUTE, + PVR_FW_HAS_FEATURE_COMPUTE_MORTON_CAPABLE, + PVR_FW_HAS_FEATURE_COMPUTE_OVERLAP, + PVR_FW_HAS_FEATURE_COREID_PER_OS, + PVR_FW_HAS_FEATURE_DYNAMIC_DUST_POWER, + PVR_FW_HAS_FEATURE_ECC_RAMS, + PVR_FW_HAS_FEATURE_FBCDC, + PVR_FW_HAS_FEATURE_FBCDC_ALGORITHM, + PVR_FW_HAS_FEATURE_FBCDC_ARCHITECTURE, + PVR_FW_HAS_FEATURE_FBC_MAX_DEFAULT_DESCRIPTORS, + PVR_FW_HAS_FEATURE_FBC_MAX_LARGE_DESCRIPTORS, + PVR_FW_HAS_FEATURE_FB_CDC_V4, + PVR_FW_HAS_FEATURE_GPU_MULTICORE_SUPPORT, + PVR_FW_HAS_FEATURE_GPU_VIRTUALISATION, + PVR_FW_HAS_FEATURE_GS_RTA_SUPPORT, + PVR_FW_HAS_FEATURE_IRQ_PER_OS, + PVR_FW_HAS_FEATURE_ISP_MAX_TILES_IN_FLIGHT, + PVR_FW_HAS_FEATURE_ISP_SAMPLES_PER_PIXEL, + PVR_FW_HAS_FEATURE_ISP_ZLS_D24_S8_PACKING_OGL_MODE, + PVR_FW_HAS_FEATURE_LAYOUT_MARS, + PVR_FW_HAS_FEATURE_MAX_PARTITIONS, + PVR_FW_HAS_FEATURE_META, + PVR_FW_HAS_FEATURE_META_COREMEM_SIZE, + PVR_FW_HAS_FEATURE_MIPS, + PVR_FW_HAS_FEATURE_NUM_CLUSTERS, + PVR_FW_HAS_FEATURE_NUM_ISP_IPP_PIPES, + PVR_FW_HAS_FEATURE_NUM_OSIDS, + PVR_FW_HAS_FEATURE_NUM_RASTER_PIPES, + PVR_FW_HAS_FEATURE_PBE2_IN_XE, + PVR_FW_HAS_FEATURE_PBVNC_COREID_REG, + PVR_FW_HAS_FEATURE_PERFBUS, + PVR_FW_HAS_FEATURE_PERF_COUNTER_BATCH, + PVR_FW_HAS_FEATURE_PHYS_BUS_WIDTH, + PVR_FW_HAS_FEATURE_RISCV_FW_PROCESSOR, + PVR_FW_HAS_FEATURE_ROGUEXE, + PVR_FW_HAS_FEATURE_S7_TOP_INFRASTRUCTURE, + PVR_FW_HAS_FEATURE_SIMPLE_INTERNAL_PARAMETER_FORMAT, + PVR_FW_HAS_FEATURE_SIMPLE_INTERNAL_PARAMETER_FORMAT_V2, + PVR_FW_HAS_FEATURE_SIMPLE_PARAMETER_FORMAT_VERSION, + PVR_FW_HAS_FEATURE_SLC_BANKS, + PVR_FW_HAS_FEATURE_SLC_CACHE_LINE_SIZE_BITS, + PVR_FW_HAS_FEATURE_SLC_SIZE_CONFIGURABLE, + PVR_FW_HAS_FEATURE_SLC_SIZE_IN_KILOBYTES, + PVR_FW_HAS_FEATURE_SOC_TIMER, + PVR_FW_HAS_FEATURE_SYS_BUS_SECURE_RESET, + PVR_FW_HAS_FEATURE_TESSELLATION, + PVR_FW_HAS_FEATURE_TILE_REGION_PROTECTION, + PVR_FW_HAS_FEATURE_TILE_SIZE_X, + PVR_FW_HAS_FEATURE_TILE_SIZE_Y, + PVR_FW_HAS_FEATURE_TLA, + PVR_FW_HAS_FEATURE_TPU_CEM_DATAMASTER_GLOBAL_REGISTERS, + PVR_FW_HAS_FEATURE_TPU_DM_GLOBAL_REGISTERS, + PVR_FW_HAS_FEATURE_TPU_FILTERING_MODE_CONTROL, + PVR_FW_HAS_FEATURE_USC_MIN_OUTPUT_REGISTERS_PER_PIX, + PVR_FW_HAS_FEATURE_VDM_DRAWINDIRECT, + PVR_FW_HAS_FEATURE_VDM_OBJECT_LEVEL_LLS, + PVR_FW_HAS_FEATURE_VIRTUAL_ADDRESS_SPACE_BITS, + PVR_FW_HAS_FEATURE_WATCHDOG_TIMER, + PVR_FW_HAS_FEATURE_WORKGROUP_PROTECTION, + PVR_FW_HAS_FEATURE_XE_ARCHITECTURE, + PVR_FW_HAS_FEATURE_XE_MEMORY_HIERARCHY, + PVR_FW_HAS_FEATURE_XE_TPU2, + PVR_FW_HAS_FEATURE_XPU_MAX_REGBANKS_ADDR_WIDTH, + PVR_FW_HAS_FEATURE_XPU_MAX_SLAVES, + PVR_FW_HAS_FEATURE_XPU_REGISTER_BROADCAST, + PVR_FW_HAS_FEATURE_XT_TOP_INFRASTRUCTURE, + PVR_FW_HAS_FEATURE_ZLS_SUBTILE, + + PVR_FW_HAS_FEATURE_MAX +}; + +#endif /* __PVR_ROGUE_FWIF_DEV_INFO_H__ */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif_resetframework.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif_resetframework.h new file mode 100644 index 00000000000000..1db1f4c532bc6b --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif_resetframework.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_ROGUE_FWIF_RESETFRAMEWORK_H +#define PVR_ROGUE_FWIF_RESETFRAMEWORK_H + +#include +#include + +#include "pvr_rogue_fwif_shared.h" + +struct rogue_fwif_rf_registers { + union { + u64 cdmreg_cdm_cb_base; + u64 cdmreg_cdm_ctrl_stream_base; + }; + u64 cdmreg_cdm_cb_queue; + u64 cdmreg_cdm_cb; +}; + +struct rogue_fwif_rf_cmd { + /* THIS MUST BE THE LAST MEMBER OF THE CONTAINING STRUCTURE */ + struct rogue_fwif_rf_registers fw_registers __aligned(8); +}; + +#define ROGUE_FWIF_RF_CMD_SIZE sizeof(struct rogue_fwif_rf_cmd) + +#endif /* PVR_ROGUE_FWIF_RESETFRAMEWORK_H */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif_sf.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif_sf.h new file mode 100644 index 00000000000000..56e11009e1230a --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif_sf.h @@ -0,0 +1,1648 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_ROGUE_FWIF_SF_H +#define PVR_ROGUE_FWIF_SF_H + +/* + ****************************************************************************** + * *DO*NOT* rearrange or delete lines in rogue_fw_log_sfgroups or stid_fmts + * WILL BREAK fw tracing message compatibility with previous + * fw versions. Only add new ones, if so required. + ****************************************************************************** + */ + +/* Available log groups. */ +enum rogue_fw_log_sfgroups { + ROGUE_FW_GROUP_NULL, + ROGUE_FW_GROUP_MAIN, + ROGUE_FW_GROUP_CLEANUP, + ROGUE_FW_GROUP_CSW, + ROGUE_FW_GROUP_PM, + ROGUE_FW_GROUP_RTD, + ROGUE_FW_GROUP_SPM, + ROGUE_FW_GROUP_MTS, + ROGUE_FW_GROUP_BIF, + ROGUE_FW_GROUP_MISC, + ROGUE_FW_GROUP_POW, + ROGUE_FW_GROUP_HWR, + ROGUE_FW_GROUP_HWP, + ROGUE_FW_GROUP_RPM, + ROGUE_FW_GROUP_DMA, + ROGUE_FW_GROUP_DBG, +}; + +#define PVR_SF_STRING_MAX_SIZE 256U + +/* pair of string format id and string formats */ +struct rogue_fw_stid_fmt { + u32 id; + char name[PVR_SF_STRING_MAX_SIZE]; +}; + +/* + * The symbolic names found in the table above are assigned an u32 value of + * the following format: + * 31 30 28 27 20 19 16 15 12 11 0 bits + * - --- ---- ---- ---- ---- ---- ---- ---- + * 0-11: id number + * 12-15: group id number + * 16-19: number of parameters + * 20-27: unused + * 28-30: active: identify SF packet, otherwise regular int32 + * 31: reserved for signed/unsigned compatibility + * + * The following macro assigns those values to the enum generated SF ids list. + */ +#define ROGUE_FW_LOG_IDMARKER (0x70000000U) +#define ROGUE_FW_LOG_CREATESFID(a, b, e) ((u32)(a) | ((u32)(b) << 12) | ((u32)(e) << 16) | \ + ROGUE_FW_LOG_IDMARKER) + +#define ROGUE_FW_LOG_IDMASK (0xFFF00000) +#define ROGUE_FW_LOG_VALIDID(I) (((I) & ROGUE_FW_LOG_IDMASK) == ROGUE_FW_LOG_IDMARKER) + +/* Return the group id that the given (enum generated) id belongs to */ +#define ROGUE_FW_SF_GID(x) (((u32)(x) >> 12) & 0xfU) +/* Returns how many arguments the SF(string format) for the given (enum generated) id requires */ +#define ROGUE_FW_SF_PARAMNUM(x) (((u32)(x) >> 16) & 0xfU) + +/* pair of string format id and string formats */ +struct rogue_km_stid_fmt { + u32 id; + const char *name; +}; + +static const struct rogue_km_stid_fmt stid_fmts[] = { + { ROGUE_FW_LOG_CREATESFID(0, ROGUE_FW_GROUP_NULL, 0), + "You should not use this string" }, + + { ROGUE_FW_LOG_CREATESFID(1, ROGUE_FW_GROUP_MAIN, 6), + "Kick 3D: FWCtx 0x%08.8x @ %d, RTD 0x%08x. Partial render:%d, CSW resume:%d, prio:%d" }, + { ROGUE_FW_LOG_CREATESFID(2, ROGUE_FW_GROUP_MAIN, 2), + "3D finished, HWRTData0State=%x, HWRTData1State=%x" }, + { ROGUE_FW_LOG_CREATESFID(3, ROGUE_FW_GROUP_MAIN, 4), + "Kick 3D TQ: FWCtx 0x%08.8x @ %d, CSW resume:%d, prio: %d" }, + { ROGUE_FW_LOG_CREATESFID(4, ROGUE_FW_GROUP_MAIN, 0), + "3D Transfer finished" }, + { ROGUE_FW_LOG_CREATESFID(5, ROGUE_FW_GROUP_MAIN, 3), + "Kick Compute: FWCtx 0x%08.8x @ %d, prio: %d" }, + { ROGUE_FW_LOG_CREATESFID(6, ROGUE_FW_GROUP_MAIN, 0), + "Compute finished" }, + { ROGUE_FW_LOG_CREATESFID(7, ROGUE_FW_GROUP_MAIN, 7), + "Kick TA: FWCtx 0x%08.8x @ %d, RTD 0x%08x. First kick:%d, Last kick:%d, CSW resume:%d, prio:%d" }, + { ROGUE_FW_LOG_CREATESFID(8, ROGUE_FW_GROUP_MAIN, 0), + "TA finished" }, + { ROGUE_FW_LOG_CREATESFID(9, ROGUE_FW_GROUP_MAIN, 0), + "Restart TA after partial render" }, + { ROGUE_FW_LOG_CREATESFID(10, ROGUE_FW_GROUP_MAIN, 0), + "Resume TA without partial render" }, + { ROGUE_FW_LOG_CREATESFID(11, ROGUE_FW_GROUP_MAIN, 2), + "Out of memory! Context 0x%08x, HWRTData 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(12, ROGUE_FW_GROUP_MAIN, 3), + "Kick TLA: FWCtx 0x%08.8x @ %d, prio:%d" }, + { ROGUE_FW_LOG_CREATESFID(13, ROGUE_FW_GROUP_MAIN, 0), + "TLA finished" }, + { ROGUE_FW_LOG_CREATESFID(14, ROGUE_FW_GROUP_MAIN, 3), + "cCCB Woff update = %d, DM = %d, FWCtx = 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(16, ROGUE_FW_GROUP_MAIN, 2), + "UFO Checks for FWCtx 0x%08.8x @ %d" }, + { ROGUE_FW_LOG_CREATESFID(17, ROGUE_FW_GROUP_MAIN, 3), + "UFO Check: [0x%08.8x] is 0x%08.8x requires 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(18, ROGUE_FW_GROUP_MAIN, 0), + "UFO Checks succeeded" }, + { ROGUE_FW_LOG_CREATESFID(19, ROGUE_FW_GROUP_MAIN, 3), + "UFO PR-Check: [0x%08.8x] is 0x%08.8x requires >= 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(20, ROGUE_FW_GROUP_MAIN, 1), + "UFO SPM PR-Checks for FWCtx 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(21, ROGUE_FW_GROUP_MAIN, 4), + "UFO SPM special PR-Check: [0x%08.8x] is 0x%08.8x requires >= ????????, [0x%08.8x] is ???????? requires 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(22, ROGUE_FW_GROUP_MAIN, 2), + "UFO Updates for FWCtx 0x%08.8x @ %d" }, + { ROGUE_FW_LOG_CREATESFID(23, ROGUE_FW_GROUP_MAIN, 2), + "UFO Update: [0x%08.8x] = 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(24, ROGUE_FW_GROUP_MAIN, 1), + "ASSERT Failed: line %d of:" }, + { ROGUE_FW_LOG_CREATESFID(25, ROGUE_FW_GROUP_MAIN, 2), + "HWR: Lockup detected on DM%d, FWCtx: 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(26, ROGUE_FW_GROUP_MAIN, 3), + "HWR: Reset fw state for DM%d, FWCtx: 0x%08.8x, MemCtx: 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(27, ROGUE_FW_GROUP_MAIN, 0), + "HWR: Reset HW" }, + { ROGUE_FW_LOG_CREATESFID(28, ROGUE_FW_GROUP_MAIN, 0), + "HWR: Lockup recovered." }, + { ROGUE_FW_LOG_CREATESFID(29, ROGUE_FW_GROUP_MAIN, 1), + "HWR: False lockup detected for DM%u" }, + { ROGUE_FW_LOG_CREATESFID(30, ROGUE_FW_GROUP_MAIN, 3), + "Alignment check %d failed: host = 0x%x, fw = 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(31, ROGUE_FW_GROUP_MAIN, 0), + "GP USC triggered" }, + { ROGUE_FW_LOG_CREATESFID(32, ROGUE_FW_GROUP_MAIN, 2), + "Overallocating %u temporary registers and %u shared registers for breakpoint handler" }, + { ROGUE_FW_LOG_CREATESFID(33, ROGUE_FW_GROUP_MAIN, 1), + "Setting breakpoint: Addr 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(34, ROGUE_FW_GROUP_MAIN, 0), + "Store breakpoint state" }, + { ROGUE_FW_LOG_CREATESFID(35, ROGUE_FW_GROUP_MAIN, 0), + "Unsetting BP Registers" }, + { ROGUE_FW_LOG_CREATESFID(36, ROGUE_FW_GROUP_MAIN, 1), + "Active RTs expected to be zero, actually %u" }, + { ROGUE_FW_LOG_CREATESFID(37, ROGUE_FW_GROUP_MAIN, 1), + "RTC present, %u active render targets" }, + { ROGUE_FW_LOG_CREATESFID(38, ROGUE_FW_GROUP_MAIN, 1), + "Estimated Power 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(39, ROGUE_FW_GROUP_MAIN, 1), + "RTA render target %u" }, + { ROGUE_FW_LOG_CREATESFID(40, ROGUE_FW_GROUP_MAIN, 2), + "Kick RTA render %u of %u" }, + { ROGUE_FW_LOG_CREATESFID(41, ROGUE_FW_GROUP_MAIN, 3), + "HWR sizes check %d failed: addresses = %d, sizes = %d" }, + { ROGUE_FW_LOG_CREATESFID(42, ROGUE_FW_GROUP_MAIN, 1), + "Pow: DUSTS_ENABLE = 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(43, ROGUE_FW_GROUP_MAIN, 2), + "Pow: On(1)/Off(0): %d, Units: 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(44, ROGUE_FW_GROUP_MAIN, 2), + "Pow: Changing number of dusts from %d to %d" }, + { ROGUE_FW_LOG_CREATESFID(45, ROGUE_FW_GROUP_MAIN, 0), + "Pow: Sidekick ready to be powered down" }, + { ROGUE_FW_LOG_CREATESFID(46, ROGUE_FW_GROUP_MAIN, 2), + "Pow: Request to change num of dusts to %d (bPowRascalDust=%d)" }, + { ROGUE_FW_LOG_CREATESFID(47, ROGUE_FW_GROUP_MAIN, 0), + "No ZS Buffer used for partial render (store)" }, + { ROGUE_FW_LOG_CREATESFID(48, ROGUE_FW_GROUP_MAIN, 0), + "No Depth/Stencil Buffer used for partial render (load)" }, + { ROGUE_FW_LOG_CREATESFID(49, ROGUE_FW_GROUP_MAIN, 2), + "HWR: Lock-up DM%d FWCtx: 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(50, ROGUE_FW_GROUP_MAIN, 7), + "MLIST%d checker: CatBase TE=0x%08x (%d Pages), VCE=0x%08x (%d Pages), ALIST=0x%08x, IsTA=%d" }, + { ROGUE_FW_LOG_CREATESFID(51, ROGUE_FW_GROUP_MAIN, 3), + "MLIST%d checker: MList[%d] = 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(52, ROGUE_FW_GROUP_MAIN, 1), + "MLIST%d OK" }, + { ROGUE_FW_LOG_CREATESFID(53, ROGUE_FW_GROUP_MAIN, 1), + "MLIST%d is empty" }, + { ROGUE_FW_LOG_CREATESFID(54, ROGUE_FW_GROUP_MAIN, 8), + "MLIST%d checker: CatBase TE=0x%08x%08x, VCE=0x%08x%08x, ALIST=0x%08x%08x, IsTA=%d" }, + { ROGUE_FW_LOG_CREATESFID(55, ROGUE_FW_GROUP_MAIN, 0), + "3D OQ flush kick" }, + { ROGUE_FW_LOG_CREATESFID(56, ROGUE_FW_GROUP_MAIN, 1), + "HWPerf block ID (0x%x) unsupported by device" }, + { ROGUE_FW_LOG_CREATESFID(57, ROGUE_FW_GROUP_MAIN, 2), + "Setting breakpoint: Addr 0x%08.8x DM%u" }, + { ROGUE_FW_LOG_CREATESFID(58, ROGUE_FW_GROUP_MAIN, 3), + "Kick RTU: FWCtx 0x%08.8x @ %d, prio: %d" }, + { ROGUE_FW_LOG_CREATESFID(59, ROGUE_FW_GROUP_MAIN, 1), + "RDM finished on context %u" }, + { ROGUE_FW_LOG_CREATESFID(60, ROGUE_FW_GROUP_MAIN, 3), + "Kick SHG: FWCtx 0x%08.8x @ %d, prio: %d" }, + { ROGUE_FW_LOG_CREATESFID(61, ROGUE_FW_GROUP_MAIN, 0), + "SHG finished" }, + { ROGUE_FW_LOG_CREATESFID(62, ROGUE_FW_GROUP_MAIN, 1), + "FBA finished on context %u" }, + { ROGUE_FW_LOG_CREATESFID(63, ROGUE_FW_GROUP_MAIN, 0), + "UFO Checks failed" }, + { ROGUE_FW_LOG_CREATESFID(64, ROGUE_FW_GROUP_MAIN, 1), + "Kill DM%d start" }, + { ROGUE_FW_LOG_CREATESFID(65, ROGUE_FW_GROUP_MAIN, 1), + "Kill DM%d complete" }, + { ROGUE_FW_LOG_CREATESFID(66, ROGUE_FW_GROUP_MAIN, 2), + "FC%u cCCB Woff update = %u" }, + { ROGUE_FW_LOG_CREATESFID(67, ROGUE_FW_GROUP_MAIN, 4), + "Kick RTU: FWCtx 0x%08.8x @ %d, prio: %d, Frame Context: %d" }, + { ROGUE_FW_LOG_CREATESFID(68, ROGUE_FW_GROUP_MAIN, 0), + "GPU init" }, + { ROGUE_FW_LOG_CREATESFID(69, ROGUE_FW_GROUP_MAIN, 1), + "GPU Units init (# mask: 0x%x)" }, + { ROGUE_FW_LOG_CREATESFID(70, ROGUE_FW_GROUP_MAIN, 3), + "Register access cycles: read: %d cycles, write: %d cycles, iterations: %d" }, + { ROGUE_FW_LOG_CREATESFID(71, ROGUE_FW_GROUP_MAIN, 3), + "Register configuration added. Address: 0x%x Value: 0x%x%x" }, + { ROGUE_FW_LOG_CREATESFID(72, ROGUE_FW_GROUP_MAIN, 1), + "Register configuration applied to type %d. (0:pow on, 1:Rascal/dust init, 2-5: TA,3D,CDM,TLA, 6:All)" }, + { ROGUE_FW_LOG_CREATESFID(73, ROGUE_FW_GROUP_MAIN, 0), + "Perform TPC flush." }, + { ROGUE_FW_LOG_CREATESFID(74, ROGUE_FW_GROUP_MAIN, 0), + "GPU has locked up (see HWR logs for more info)" }, + { ROGUE_FW_LOG_CREATESFID(75, ROGUE_FW_GROUP_MAIN, 0), + "HWR has been triggered - GPU has overrun its deadline (see HWR logs)" }, + { ROGUE_FW_LOG_CREATESFID(76, ROGUE_FW_GROUP_MAIN, 0), + "HWR has been triggered - GPU has failed a poll (see HWR logs)" }, + { ROGUE_FW_LOG_CREATESFID(77, ROGUE_FW_GROUP_MAIN, 1), + "Doppler out of memory event for FC %u" }, + { ROGUE_FW_LOG_CREATESFID(78, ROGUE_FW_GROUP_MAIN, 3), + "UFO SPM special PR-Check: [0x%08.8x] is 0x%08.8x requires >= 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(79, ROGUE_FW_GROUP_MAIN, 3), + "UFO SPM special PR-Check: [0x%08.8x] is 0x%08.8x requires 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(80, ROGUE_FW_GROUP_MAIN, 1), + "TIMESTAMP -> [0x%08.8x]" }, + { ROGUE_FW_LOG_CREATESFID(81, ROGUE_FW_GROUP_MAIN, 2), + "UFO RMW Updates for FWCtx 0x%08.8x @ %d" }, + { ROGUE_FW_LOG_CREATESFID(82, ROGUE_FW_GROUP_MAIN, 2), + "UFO Update: [0x%08.8x] = 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(83, ROGUE_FW_GROUP_MAIN, 2), + "Kick Null cmd: FWCtx 0x%08.8x @ %d" }, + { ROGUE_FW_LOG_CREATESFID(84, ROGUE_FW_GROUP_MAIN, 2), + "RPM Out of memory! Context 0x%08x, SH requestor %d" }, + { ROGUE_FW_LOG_CREATESFID(85, ROGUE_FW_GROUP_MAIN, 4), + "Discard RTU due to RPM abort: FWCtx 0x%08.8x @ %d, prio: %d, Frame Context: %d" }, + { ROGUE_FW_LOG_CREATESFID(86, ROGUE_FW_GROUP_MAIN, 4), + "Deferring DM%u from running context 0x%08x @ %d (deferred DMs = 0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(87, ROGUE_FW_GROUP_MAIN, 4), + "Deferring DM%u from running context 0x%08x @ %d to let other deferred DMs run (deferred DMs = 0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(88, ROGUE_FW_GROUP_MAIN, 4), + "No longer deferring DM%u from running context = 0x%08x @ %d (deferred DMs = 0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(89, ROGUE_FW_GROUP_MAIN, 3), + "FWCCB for DM%u is full, we will have to wait for space! (Roff = %u, Woff = %u)" }, + { ROGUE_FW_LOG_CREATESFID(90, ROGUE_FW_GROUP_MAIN, 3), + "FWCCB for OSid %u is full, we will have to wait for space! (Roff = %u, Woff = %u)" }, + { ROGUE_FW_LOG_CREATESFID(91, ROGUE_FW_GROUP_MAIN, 1), + "Host Sync Partition marker: %d" }, + { ROGUE_FW_LOG_CREATESFID(92, ROGUE_FW_GROUP_MAIN, 1), + "Host Sync Partition repeat: %d" }, + { ROGUE_FW_LOG_CREATESFID(93, ROGUE_FW_GROUP_MAIN, 1), + "Core clock set to %d Hz" }, + { ROGUE_FW_LOG_CREATESFID(94, ROGUE_FW_GROUP_MAIN, 7), + "Compute Queue: FWCtx 0x%08.8x, prio: %d, queue: 0x%08x%08x (Roff = %u, Woff = %u, Size = %u)" }, + { ROGUE_FW_LOG_CREATESFID(95, ROGUE_FW_GROUP_MAIN, 3), + "Signal check failed, Required Data: 0x%x, Address: 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(96, ROGUE_FW_GROUP_MAIN, 5), + "Signal update, Snoop Filter: %u, MMU Ctx: %u, Signal Id: %u, Signals Base: 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(97, ROGUE_FW_GROUP_MAIN, 4), + "Signalled the previously waiting FWCtx: 0x%08.8x, OSId: %u, Signal Address: 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(98, ROGUE_FW_GROUP_MAIN, 0), + "Compute stalled" }, + { ROGUE_FW_LOG_CREATESFID(99, ROGUE_FW_GROUP_MAIN, 3), + "Compute stalled (Roff = %u, Woff = %u, Size = %u)" }, + { ROGUE_FW_LOG_CREATESFID(100, ROGUE_FW_GROUP_MAIN, 3), + "Compute resumed (Roff = %u, Woff = %u, Size = %u)" }, + { ROGUE_FW_LOG_CREATESFID(101, ROGUE_FW_GROUP_MAIN, 4), + "Signal update notification from the host, PC Physical Address: 0x%08x%08x, Signal Virtual Address: 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(102, ROGUE_FW_GROUP_MAIN, 4), + "Signal update from DM: %u, OSId: %u, PC Physical Address: 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(103, ROGUE_FW_GROUP_MAIN, 1), + "DM: %u signal check failed" }, + { ROGUE_FW_LOG_CREATESFID(104, ROGUE_FW_GROUP_MAIN, 3), + "Kick TDM: FWCtx 0x%08.8x @ %d, prio:%d" }, + { ROGUE_FW_LOG_CREATESFID(105, ROGUE_FW_GROUP_MAIN, 0), + "TDM finished" }, + { ROGUE_FW_LOG_CREATESFID(106, ROGUE_FW_GROUP_MAIN, 4), + "MMU_PM_CAT_BASE_TE[%d]_PIPE[%d]: 0x%08x 0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(107, ROGUE_FW_GROUP_MAIN, 0), + "BRN 54141 HIT" }, + { ROGUE_FW_LOG_CREATESFID(108, ROGUE_FW_GROUP_MAIN, 0), + "BRN 54141 Dummy TA kicked" }, + { ROGUE_FW_LOG_CREATESFID(109, ROGUE_FW_GROUP_MAIN, 0), + "BRN 54141 resume TA" }, + { ROGUE_FW_LOG_CREATESFID(110, ROGUE_FW_GROUP_MAIN, 0), + "BRN 54141 double hit after applying WA" }, + { ROGUE_FW_LOG_CREATESFID(111, ROGUE_FW_GROUP_MAIN, 2), + "BRN 54141 Dummy TA VDM base address: 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(112, ROGUE_FW_GROUP_MAIN, 4), + "Signal check failed, Required Data: 0x%x, Current Data: 0x%x, Address: 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(113, ROGUE_FW_GROUP_MAIN, 2), + "TDM stalled (Roff = %u, Woff = %u)" }, + { ROGUE_FW_LOG_CREATESFID(114, ROGUE_FW_GROUP_MAIN, 1), + "Write Offset update notification for stalled FWCtx 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(115, ROGUE_FW_GROUP_MAIN, 3), + "Changing OSid %d's priority from %u to %u" }, + { ROGUE_FW_LOG_CREATESFID(116, ROGUE_FW_GROUP_MAIN, 0), + "Compute resumed" }, + { ROGUE_FW_LOG_CREATESFID(117, ROGUE_FW_GROUP_MAIN, 7), + "Kick TLA: FWCtx 0x%08.8x @ %d. (PID:%d, prio:%d, frame:%d, ext:0x%08x, int:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(118, ROGUE_FW_GROUP_MAIN, 7), + "Kick TDM: FWCtx 0x%08.8x @ %d. (PID:%d, prio:%d, frame:%d, ext:0x%08x, int:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(119, ROGUE_FW_GROUP_MAIN, 11), + "Kick TA: FWCtx 0x%08.8x @ %d, RTD 0x%08x, First kick:%d, Last kick:%d, CSW resume:%d. (PID:%d, prio:%d, frame:%d, ext:0x%08x, int:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(120, ROGUE_FW_GROUP_MAIN, 10), + "Kick 3D: FWCtx 0x%08.8x @ %d, RTD 0x%08x, Partial render:%d, CSW resume:%d. (PID:%d, prio:%d, frame:%d, ext:0x%08x, int:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(121, ROGUE_FW_GROUP_MAIN, 8), + "Kick 3D TQ: FWCtx 0x%08.8x @ %d, CSW resume:%d. (PID:%d, prio:%d, frame:%d, ext:0x%08x, int:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(122, ROGUE_FW_GROUP_MAIN, 6), + "Kick Compute: FWCtx 0x%08.8x @ %d. (PID:%d, prio:%d, ext:0x%08x, int:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(123, ROGUE_FW_GROUP_MAIN, 8), + "Kick RTU: FWCtx 0x%08.8x @ %d, Frame Context:%d. (PID:%d, prio:%d, frame:%d, ext:0x%08x, int:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(124, ROGUE_FW_GROUP_MAIN, 7), + "Kick SHG: FWCtx 0x%08.8x @ %d. (PID:%d, prio:%d, frame:%d, ext:0x%08x, int:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(125, ROGUE_FW_GROUP_MAIN, 1), + "Reconfigure CSRM: special coeff support enable %d." }, + { ROGUE_FW_LOG_CREATESFID(127, ROGUE_FW_GROUP_MAIN, 1), + "TA requires max coeff mode, deferring: %d." }, + { ROGUE_FW_LOG_CREATESFID(128, ROGUE_FW_GROUP_MAIN, 1), + "3D requires max coeff mode, deferring: %d." }, + { ROGUE_FW_LOG_CREATESFID(129, ROGUE_FW_GROUP_MAIN, 1), + "Kill DM%d failed" }, + { ROGUE_FW_LOG_CREATESFID(130, ROGUE_FW_GROUP_MAIN, 2), + "Thread Queue is full, we will have to wait for space! (Roff = %u, Woff = %u)" }, + { ROGUE_FW_LOG_CREATESFID(131, ROGUE_FW_GROUP_MAIN, 3), + "Thread Queue is fencing, we are waiting for Roff = %d (Roff = %u, Woff = %u)" }, + { ROGUE_FW_LOG_CREATESFID(132, ROGUE_FW_GROUP_MAIN, 1), + "DM %d failed to Context Switch on time. Triggered HCS (see HWR logs)." }, + { ROGUE_FW_LOG_CREATESFID(133, ROGUE_FW_GROUP_MAIN, 1), + "HCS changed to %d ms" }, + { ROGUE_FW_LOG_CREATESFID(134, ROGUE_FW_GROUP_MAIN, 4), + "Updating Tiles In Flight (Dusts=%d, PartitionMask=0x%08x, ISPCtl=0x%08x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(135, ROGUE_FW_GROUP_MAIN, 2), + " Phantom %d: USCTiles=%d" }, + { ROGUE_FW_LOG_CREATESFID(136, ROGUE_FW_GROUP_MAIN, 0), + "Isolation grouping is disabled" }, + { ROGUE_FW_LOG_CREATESFID(137, ROGUE_FW_GROUP_MAIN, 1), + "Isolation group configured with a priority threshold of %d" }, + { ROGUE_FW_LOG_CREATESFID(138, ROGUE_FW_GROUP_MAIN, 1), + "OS %d has come online" }, + { ROGUE_FW_LOG_CREATESFID(139, ROGUE_FW_GROUP_MAIN, 1), + "OS %d has gone offline" }, + { ROGUE_FW_LOG_CREATESFID(140, ROGUE_FW_GROUP_MAIN, 4), + "Signalled the previously stalled FWCtx: 0x%08.8x, OSId: %u, Signal Address: 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(141, ROGUE_FW_GROUP_MAIN, 7), + "TDM Queue: FWCtx 0x%08.8x, prio: %d, queue: 0x%08x%08x (Roff = %u, Woff = %u, Size = %u)" }, + { ROGUE_FW_LOG_CREATESFID(142, ROGUE_FW_GROUP_MAIN, 6), + "Reset TDM Queue Read Offset: FWCtx 0x%08.8x, queue: 0x%08x%08x (Roff = %u becomes 0, Woff = %u, Size = %u)" }, + { ROGUE_FW_LOG_CREATESFID(143, ROGUE_FW_GROUP_MAIN, 5), + "User Mode Queue mismatched stream start: FWCtx 0x%08.8x, queue: 0x%08x%08x (Roff = %u, StreamStartOffset = %u)" }, + { ROGUE_FW_LOG_CREATESFID(144, ROGUE_FW_GROUP_MAIN, 0), + "GPU deinit" }, + { ROGUE_FW_LOG_CREATESFID(145, ROGUE_FW_GROUP_MAIN, 0), + "GPU units deinit" }, + { ROGUE_FW_LOG_CREATESFID(146, ROGUE_FW_GROUP_MAIN, 2), + "Initialised OS %d with config flags 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(147, ROGUE_FW_GROUP_MAIN, 2), + "UFO limit exceeded %d/%d" }, + { ROGUE_FW_LOG_CREATESFID(148, ROGUE_FW_GROUP_MAIN, 0), + "3D Dummy stencil store" }, + { ROGUE_FW_LOG_CREATESFID(149, ROGUE_FW_GROUP_MAIN, 3), + "Initialised OS %d with config flags 0x%08x and extended config flags 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(150, ROGUE_FW_GROUP_MAIN, 1), + "Unknown Command (eCmdType=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(151, ROGUE_FW_GROUP_MAIN, 4), + "UFO forced update: FWCtx 0x%08.8x @ %d [0x%08.8x] = 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(152, ROGUE_FW_GROUP_MAIN, 5), + "UFO forced update NOP: FWCtx 0x%08.8x @ %d [0x%08.8x] = 0x%08.8x, reason %d" }, + { ROGUE_FW_LOG_CREATESFID(153, ROGUE_FW_GROUP_MAIN, 3), + "TDM context switch check: Roff %u points to 0x%08x, Match=%u" }, + { ROGUE_FW_LOG_CREATESFID(154, ROGUE_FW_GROUP_MAIN, 6), + "OSid %d CCB init status: %d (1-ok 0-fail): kCCBCtl@0x%x kCCB@0x%x fwCCBCtl@0x%x fwCCB@0x%x" }, + { ROGUE_FW_LOG_CREATESFID(155, ROGUE_FW_GROUP_MAIN, 2), + "FW IRQ # %u @ %u" }, + { ROGUE_FW_LOG_CREATESFID(156, ROGUE_FW_GROUP_MAIN, 3), + "Setting breakpoint: Addr 0x%08.8x DM%u usc_breakpoint_ctrl_dm = %u" }, + { ROGUE_FW_LOG_CREATESFID(157, ROGUE_FW_GROUP_MAIN, 3), + "Invalid KCCB setup for OSid %u: KCCB 0x%08x, KCCB Ctrl 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(158, ROGUE_FW_GROUP_MAIN, 3), + "Invalid KCCB cmd (%u) for OSid %u @ KCCB 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(159, ROGUE_FW_GROUP_MAIN, 4), + "FW FAULT: At line %d in file 0x%08x%08x, additional data=0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(160, ROGUE_FW_GROUP_MAIN, 4), + "Invalid breakpoint: MemCtx 0x%08x Addr 0x%08.8x DM%u usc_breakpoint_ctrl_dm = %u" }, + { ROGUE_FW_LOG_CREATESFID(161, ROGUE_FW_GROUP_MAIN, 3), + "Discarding invalid SLC flushinval command for OSid %u: DM %u, FWCtx 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(162, ROGUE_FW_GROUP_MAIN, 4), + "Invalid Write Offset update notification from OSid %u to DM %u: FWCtx 0x%08x, MemCtx 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(163, ROGUE_FW_GROUP_MAIN, 4), + "Null FWCtx in KCCB kick cmd for OSid %u: KCCB 0x%08x, ROff %u, WOff %u" }, + { ROGUE_FW_LOG_CREATESFID(164, ROGUE_FW_GROUP_MAIN, 3), + "Checkpoint CCB for OSid %u is full, signalling host for full check state (Roff = %u, Woff = %u)" }, + { ROGUE_FW_LOG_CREATESFID(165, ROGUE_FW_GROUP_MAIN, 8), + "OSid %d CCB init status: %d (1-ok 0-fail): kCCBCtl@0x%x kCCB@0x%x fwCCBCtl@0x%x fwCCB@0x%x chptCCBCtl@0x%x chptCCB@0x%x" }, + { ROGUE_FW_LOG_CREATESFID(166, ROGUE_FW_GROUP_MAIN, 4), + "OSid %d fw state transition request: from %d to %d (0-offline 1-ready 2-active 3-offloading). Status %d (1-ok 0-fail)" }, + { ROGUE_FW_LOG_CREATESFID(167, ROGUE_FW_GROUP_MAIN, 2), + "OSid %u has %u stale commands in its KCCB" }, + { ROGUE_FW_LOG_CREATESFID(168, ROGUE_FW_GROUP_MAIN, 0), + "Applying VCE pause" }, + { ROGUE_FW_LOG_CREATESFID(169, ROGUE_FW_GROUP_MAIN, 3), + "OSid %u KCCB slot %u value updated to %u" }, + { ROGUE_FW_LOG_CREATESFID(170, ROGUE_FW_GROUP_MAIN, 7), + "Unknown KCCB Command: KCCBCtl=0x%08x, KCCB=0x%08x, Roff=%u, Woff=%u, Wrap=%u, Cmd=0x%08x, CmdType=0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(171, ROGUE_FW_GROUP_MAIN, 10), + "Unknown Client CCB Command processing fences: FWCtx=0x%08x, CCBCtl=0x%08x, CCB=0x%08x, Roff=%u, Doff=%u, Woff=%u, Wrap=%u, CmdHdr=0x%08x, CmdType=0x%08x, CmdSize=%u" }, + { ROGUE_FW_LOG_CREATESFID(172, ROGUE_FW_GROUP_MAIN, 10), + "Unknown Client CCB Command executing kick: FWCtx=0x%08x, CCBCtl=0x%08x, CCB=0x%08x, Roff=%u, Doff=%u, Woff=%u, Wrap=%u, CmdHdr=0x%08x, CmdType=0x%08x, CmdSize=%u" }, + { ROGUE_FW_LOG_CREATESFID(173, ROGUE_FW_GROUP_MAIN, 2), + "Null FWCtx in KCCB kick cmd for OSid %u with WOff %u" }, + { ROGUE_FW_LOG_CREATESFID(174, ROGUE_FW_GROUP_MAIN, 2), + "Discarding invalid SLC flushinval command for OSid %u, FWCtx 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(175, ROGUE_FW_GROUP_MAIN, 3), + "Invalid Write Offset update notification from OSid %u: FWCtx 0x%08x, MemCtx 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(176, ROGUE_FW_GROUP_MAIN, 2), + "Initialised Firmware with config flags 0x%08x and extended config flags 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(177, ROGUE_FW_GROUP_MAIN, 1), + "Set Periodic Hardware Reset Mode: %d" }, + { ROGUE_FW_LOG_CREATESFID(179, ROGUE_FW_GROUP_MAIN, 3), + "PHR mode %d, FW state: 0x%08x, HWR flags: 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(180, ROGUE_FW_GROUP_MAIN, 1), + "PHR mode %d triggered a reset" }, + { ROGUE_FW_LOG_CREATESFID(181, ROGUE_FW_GROUP_MAIN, 2), + "Signal update, Snoop Filter: %u, Signal Id: %u" }, + { ROGUE_FW_LOG_CREATESFID(182, ROGUE_FW_GROUP_MAIN, 1), + "WARNING: Skipping FW KCCB Cmd type %d which is not yet supported on Series8." }, + { ROGUE_FW_LOG_CREATESFID(183, ROGUE_FW_GROUP_MAIN, 4), + "MMU context cache data NULL, but cache flags=0x%x (sync counter=%u, update value=%u) OSId=%u" }, + { ROGUE_FW_LOG_CREATESFID(184, ROGUE_FW_GROUP_MAIN, 5), + "SLC range based flush: Context=%u VAddr=0x%02x%08x, Size=0x%08x, Invalidate=%d" }, + { ROGUE_FW_LOG_CREATESFID(185, ROGUE_FW_GROUP_MAIN, 3), + "FBSC invalidate for Context Set [0x%08x]: Entry mask 0x%08x%08x." }, + { ROGUE_FW_LOG_CREATESFID(186, ROGUE_FW_GROUP_MAIN, 3), + "TDM context switch check: Roff %u was not valid for kick starting at %u, moving back to %u" }, + { ROGUE_FW_LOG_CREATESFID(187, ROGUE_FW_GROUP_MAIN, 2), + "Signal updates: FIFO: %u, Signals: 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(188, ROGUE_FW_GROUP_MAIN, 2), + "Invalid FBSC cmd: FWCtx 0x%08x, MemCtx 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(189, ROGUE_FW_GROUP_MAIN, 0), + "Insert BRN68497 WA blit after TDM Context store." }, + { ROGUE_FW_LOG_CREATESFID(190, ROGUE_FW_GROUP_MAIN, 1), + "UFO Updates for previously finished FWCtx 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(191, ROGUE_FW_GROUP_MAIN, 1), + "RTC with RTA present, %u active render targets" }, + { ROGUE_FW_LOG_CREATESFID(192, ROGUE_FW_GROUP_MAIN, 0), + "Invalid RTA Set-up. The ValidRenderTargets array in RTACtl is Null!" }, + { ROGUE_FW_LOG_CREATESFID(193, ROGUE_FW_GROUP_MAIN, 2), + "Block 0x%x / Counter 0x%x INVALID and ignored" }, + { ROGUE_FW_LOG_CREATESFID(194, ROGUE_FW_GROUP_MAIN, 2), + "ECC fault GPU=0x%08x FW=0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(195, ROGUE_FW_GROUP_MAIN, 1), + "Processing XPU event on DM = %d" }, + { ROGUE_FW_LOG_CREATESFID(196, ROGUE_FW_GROUP_MAIN, 2), + "OSid %u failed to respond to the virtualisation watchdog in time. Timestamp of its last input = %u" }, + { ROGUE_FW_LOG_CREATESFID(197, ROGUE_FW_GROUP_MAIN, 1), + "GPU-%u has locked up (see HWR logs for more info)" }, + { ROGUE_FW_LOG_CREATESFID(198, ROGUE_FW_GROUP_MAIN, 3), + "Updating Tiles In Flight (Dusts=%d, PartitionMask=0x%08x, ISPCtl=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(199, ROGUE_FW_GROUP_MAIN, 0), + "GPU has locked up (see HWR logs for more info)" }, + { ROGUE_FW_LOG_CREATESFID(200, ROGUE_FW_GROUP_MAIN, 1), + "Reprocessing outstanding XPU events from cores 0x%02x" }, + { ROGUE_FW_LOG_CREATESFID(201, ROGUE_FW_GROUP_MAIN, 3), + "Secondary XPU event on DM=%d, CoreMask=0x%02x, Raised=0x%02x" }, + { ROGUE_FW_LOG_CREATESFID(202, ROGUE_FW_GROUP_MAIN, 8), + "TDM Queue: Core %u, FWCtx 0x%08.8x, prio: %d, queue: 0x%08x%08x (Roff = %u, Woff = %u, Size = %u)" }, + { ROGUE_FW_LOG_CREATESFID(203, ROGUE_FW_GROUP_MAIN, 3), + "TDM stalled Core %u (Roff = %u, Woff = %u)" }, + { ROGUE_FW_LOG_CREATESFID(204, ROGUE_FW_GROUP_MAIN, 8), + "Compute Queue: Core %u, FWCtx 0x%08.8x, prio: %d, queue: 0x%08x%08x (Roff = %u, Woff = %u, Size = %u)" }, + { ROGUE_FW_LOG_CREATESFID(205, ROGUE_FW_GROUP_MAIN, 4), + "Compute stalled core %u (Roff = %u, Woff = %u, Size = %u)" }, + { ROGUE_FW_LOG_CREATESFID(206, ROGUE_FW_GROUP_MAIN, 6), + "User Mode Queue mismatched stream start: Core %u, FWCtx 0x%08.8x, queue: 0x%08x%08x (Roff = %u, StreamStartOffset = %u)" }, + { ROGUE_FW_LOG_CREATESFID(207, ROGUE_FW_GROUP_MAIN, 3), + "TDM resumed core %u (Roff = %u, Woff = %u)" }, + { ROGUE_FW_LOG_CREATESFID(208, ROGUE_FW_GROUP_MAIN, 4), + "Compute resumed core %u (Roff = %u, Woff = %u, Size = %u)" }, + { ROGUE_FW_LOG_CREATESFID(209, ROGUE_FW_GROUP_MAIN, 2), + " Updated permission for OSid %u to perform MTS kicks: %u (1 = allowed, 0 = not allowed)" }, + { ROGUE_FW_LOG_CREATESFID(210, ROGUE_FW_GROUP_MAIN, 2), + "Mask = 0x%X, mask2 = 0x%X" }, + { ROGUE_FW_LOG_CREATESFID(211, ROGUE_FW_GROUP_MAIN, 3), + " core %u, reg = %u, mask = 0x%X)" }, + { ROGUE_FW_LOG_CREATESFID(212, ROGUE_FW_GROUP_MAIN, 1), + "ECC fault received from safety bus: 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(213, ROGUE_FW_GROUP_MAIN, 1), + "Safety Watchdog threshold period set to 0x%x clock cycles" }, + { ROGUE_FW_LOG_CREATESFID(214, ROGUE_FW_GROUP_MAIN, 0), + "MTS Safety Event triggered by the safety watchdog." }, + { ROGUE_FW_LOG_CREATESFID(215, ROGUE_FW_GROUP_MAIN, 3), + "DM%d USC tasks range limit 0 - %d, stride %d" }, + { ROGUE_FW_LOG_CREATESFID(216, ROGUE_FW_GROUP_MAIN, 1), + "ECC fault GPU=0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(217, ROGUE_FW_GROUP_MAIN, 0), + "GPU Hardware units reset to prevent transient faults." }, + { ROGUE_FW_LOG_CREATESFID(218, ROGUE_FW_GROUP_MAIN, 2), + "Kick Abort cmd: FWCtx 0x%08.8x @ %d" }, + { ROGUE_FW_LOG_CREATESFID(219, ROGUE_FW_GROUP_MAIN, 7), + "Kick Ray: FWCtx 0x%08.8x @ %d. (PID:%d, prio:%d, frame:%d, ext:0x%08x, int:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(220, ROGUE_FW_GROUP_MAIN, 0), + "Ray finished" }, + { ROGUE_FW_LOG_CREATESFID(221, ROGUE_FW_GROUP_MAIN, 2), + "State of firmware's private data at boot time: %d (0 = uninitialised, 1 = initialised); Fw State Flags = 0x%08X" }, + { ROGUE_FW_LOG_CREATESFID(222, ROGUE_FW_GROUP_MAIN, 2), + "CFI Timeout detected (%d increasing to %d)" }, + { ROGUE_FW_LOG_CREATESFID(223, ROGUE_FW_GROUP_MAIN, 2), + "CFI Timeout detected for FBM (%d increasing to %d)" }, + { ROGUE_FW_LOG_CREATESFID(224, ROGUE_FW_GROUP_MAIN, 0), + "Geom OOM event not allowed" }, + { ROGUE_FW_LOG_CREATESFID(225, ROGUE_FW_GROUP_MAIN, 4), + "Changing OSid %d's priority from %u to %u; Isolation = %u (0 = off; 1 = on)" }, + { ROGUE_FW_LOG_CREATESFID(226, ROGUE_FW_GROUP_MAIN, 2), + "Skipping already executed TA FWCtx 0x%08.8x @ %d" }, + { ROGUE_FW_LOG_CREATESFID(227, ROGUE_FW_GROUP_MAIN, 2), + "Attempt to execute TA FWCtx 0x%08.8x @ %d ahead of time on other GEOM" }, + { ROGUE_FW_LOG_CREATESFID(228, ROGUE_FW_GROUP_MAIN, 8), + "Kick TDM: Kick ID %u FWCtx 0x%08.8x @ %d. (PID:%d, prio:%d, frame:%d, ext:0x%08x, int:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(229, ROGUE_FW_GROUP_MAIN, 12), + "Kick TA: Kick ID %u FWCtx 0x%08.8x @ %d, RTD 0x%08x, First kick:%d, Last kick:%d, CSW resume:%d. (PID:%d, prio:%d, frame:%d, ext:0x%08x, int:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(230, ROGUE_FW_GROUP_MAIN, 11), + "Kick 3D: Kick ID %u FWCtx 0x%08.8x @ %d, RTD 0x%08x, Partial render:%d, CSW resume:%d. (PID:%d, prio:%d, frame:%d, ext:0x%08x, int:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(231, ROGUE_FW_GROUP_MAIN, 7), + "Kick Compute: Kick ID %u FWCtx 0x%08.8x @ %d. (PID:%d, prio:%d, ext:0x%08x, int:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(232, ROGUE_FW_GROUP_MAIN, 1), + "TDM finished: Kick ID %u " }, + { ROGUE_FW_LOG_CREATESFID(233, ROGUE_FW_GROUP_MAIN, 1), + "TA finished: Kick ID %u " }, + { ROGUE_FW_LOG_CREATESFID(234, ROGUE_FW_GROUP_MAIN, 3), + "3D finished: Kick ID %u , HWRTData0State=%x, HWRTData1State=%x" }, + { ROGUE_FW_LOG_CREATESFID(235, ROGUE_FW_GROUP_MAIN, 1), + "Compute finished: Kick ID %u " }, + { ROGUE_FW_LOG_CREATESFID(236, ROGUE_FW_GROUP_MAIN, 10), + "Kick TDM: Kick ID %u FWCtx 0x%08.8x @ %d, Base 0x%08x%08x. (PID:%d, prio:%d, frame:%d, ext:0x%08x, int:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(237, ROGUE_FW_GROUP_MAIN, 8), + "Kick Ray: Kick ID %u FWCtx 0x%08.8x @ %d. (PID:%d, prio:%d, frame:%d, ext:0x%08x, int:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(238, ROGUE_FW_GROUP_MAIN, 1), + "Ray finished: Kick ID %u " }, + + { ROGUE_FW_LOG_CREATESFID(1, ROGUE_FW_GROUP_MTS, 2), + "Bg Task DM = %u, counted = %d" }, + { ROGUE_FW_LOG_CREATESFID(2, ROGUE_FW_GROUP_MTS, 1), + "Bg Task complete DM = %u" }, + { ROGUE_FW_LOG_CREATESFID(3, ROGUE_FW_GROUP_MTS, 3), + "Irq Task DM = %u, Breq = %d, SBIrq = 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(4, ROGUE_FW_GROUP_MTS, 1), + "Irq Task complete DM = %u" }, + { ROGUE_FW_LOG_CREATESFID(5, ROGUE_FW_GROUP_MTS, 0), + "Kick MTS Bg task DM=All" }, + { ROGUE_FW_LOG_CREATESFID(6, ROGUE_FW_GROUP_MTS, 1), + "Kick MTS Irq task DM=%d" }, + { ROGUE_FW_LOG_CREATESFID(7, ROGUE_FW_GROUP_MTS, 2), + "Ready queue debug DM = %u, celltype = %d" }, + { ROGUE_FW_LOG_CREATESFID(8, ROGUE_FW_GROUP_MTS, 2), + "Ready-to-run debug DM = %u, item = 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(9, ROGUE_FW_GROUP_MTS, 3), + "Client command header DM = %u, client CCB = 0x%x, cmd = 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(10, ROGUE_FW_GROUP_MTS, 3), + "Ready-to-run debug OSid = %u, DM = %u, item = 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(11, ROGUE_FW_GROUP_MTS, 3), + "Ready queue debug DM = %u, celltype = %d, OSid = %u" }, + { ROGUE_FW_LOG_CREATESFID(12, ROGUE_FW_GROUP_MTS, 3), + "Bg Task DM = %u, counted = %d, OSid = %u" }, + { ROGUE_FW_LOG_CREATESFID(13, ROGUE_FW_GROUP_MTS, 1), + "Bg Task complete DM Bitfield: %u" }, + { ROGUE_FW_LOG_CREATESFID(14, ROGUE_FW_GROUP_MTS, 0), + "Irq Task complete." }, + { ROGUE_FW_LOG_CREATESFID(15, ROGUE_FW_GROUP_MTS, 7), + "Discarded Command Type: %d OS ID = %d PID = %d context = 0x%08x cccb ROff = 0x%x, due to USC breakpoint hit by OS ID = %d PID = %d." }, + { ROGUE_FW_LOG_CREATESFID(16, ROGUE_FW_GROUP_MTS, 4), + "KCCB Slot %u: DM=%u, Cmd=0x%08x, OSid=%u" }, + { ROGUE_FW_LOG_CREATESFID(17, ROGUE_FW_GROUP_MTS, 2), + "KCCB Slot %u: Return value %u" }, + { ROGUE_FW_LOG_CREATESFID(18, ROGUE_FW_GROUP_MTS, 1), + "Bg Task OSid = %u" }, + { ROGUE_FW_LOG_CREATESFID(19, ROGUE_FW_GROUP_MTS, 3), + "KCCB Slot %u: Cmd=0x%08x, OSid=%u" }, + { ROGUE_FW_LOG_CREATESFID(20, ROGUE_FW_GROUP_MTS, 1), + "Irq Task (EVENT_STATUS=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(21, ROGUE_FW_GROUP_MTS, 2), + "VZ sideband test, kicked with OSid=%u from MTS, OSid for test=%u" }, + + { ROGUE_FW_LOG_CREATESFID(1, ROGUE_FW_GROUP_CLEANUP, 1), + "FwCommonContext [0x%08x] cleaned" }, + { ROGUE_FW_LOG_CREATESFID(2, ROGUE_FW_GROUP_CLEANUP, 3), + "FwCommonContext [0x%08x] is busy: ReadOffset = %d, WriteOffset = %d" }, + { ROGUE_FW_LOG_CREATESFID(3, ROGUE_FW_GROUP_CLEANUP, 2), + "HWRTData [0x%08x] for DM=%d, received cleanup request" }, + { ROGUE_FW_LOG_CREATESFID(4, ROGUE_FW_GROUP_CLEANUP, 3), + "HWRTData [0x%08x] HW Context cleaned for DM%u, executed commands = %d" }, + { ROGUE_FW_LOG_CREATESFID(5, ROGUE_FW_GROUP_CLEANUP, 2), + "HWRTData [0x%08x] HW Context for DM%u is busy" }, + { ROGUE_FW_LOG_CREATESFID(6, ROGUE_FW_GROUP_CLEANUP, 2), + "HWRTData [0x%08x] HW Context %u cleaned" }, + { ROGUE_FW_LOG_CREATESFID(7, ROGUE_FW_GROUP_CLEANUP, 1), + "Freelist [0x%08x] cleaned" }, + { ROGUE_FW_LOG_CREATESFID(8, ROGUE_FW_GROUP_CLEANUP, 1), + "ZSBuffer [0x%08x] cleaned" }, + { ROGUE_FW_LOG_CREATESFID(9, ROGUE_FW_GROUP_CLEANUP, 3), + "ZSBuffer [0x%08x] is busy: submitted = %d, executed = %d" }, + { ROGUE_FW_LOG_CREATESFID(10, ROGUE_FW_GROUP_CLEANUP, 4), + "HWRTData [0x%08x] HW Context for DM%u is busy: submitted = %d, executed = %d" }, + { ROGUE_FW_LOG_CREATESFID(11, ROGUE_FW_GROUP_CLEANUP, 2), + "HW Ray Frame data [0x%08x] for DM=%d, received cleanup request" }, + { ROGUE_FW_LOG_CREATESFID(12, ROGUE_FW_GROUP_CLEANUP, 3), + "HW Ray Frame Data [0x%08x] cleaned for DM%u, executed commands = %d" }, + { ROGUE_FW_LOG_CREATESFID(13, ROGUE_FW_GROUP_CLEANUP, 4), + "HW Ray Frame Data [0x%08x] for DM%u is busy: submitted = %d, executed = %d" }, + { ROGUE_FW_LOG_CREATESFID(14, ROGUE_FW_GROUP_CLEANUP, 2), + "HW Ray Frame Data [0x%08x] HW Context %u cleaned" }, + { ROGUE_FW_LOG_CREATESFID(15, ROGUE_FW_GROUP_CLEANUP, 1), + "Discarding invalid cleanup request of type 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(16, ROGUE_FW_GROUP_CLEANUP, 1), + "Received cleanup request for HWRTData [0x%08x]" }, + { ROGUE_FW_LOG_CREATESFID(17, ROGUE_FW_GROUP_CLEANUP, 3), + "HWRTData [0x%08x] HW Context is busy: submitted = %d, executed = %d" }, + { ROGUE_FW_LOG_CREATESFID(18, ROGUE_FW_GROUP_CLEANUP, 3), + "HWRTData [0x%08x] HW Context %u cleaned, executed commands = %d" }, + + { ROGUE_FW_LOG_CREATESFID(1, ROGUE_FW_GROUP_CSW, 1), + "CDM FWCtx 0x%08.8x needs resume" }, + { ROGUE_FW_LOG_CREATESFID(2, ROGUE_FW_GROUP_CSW, 3), + "*** CDM FWCtx 0x%08.8x resume from snapshot buffer 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(3, ROGUE_FW_GROUP_CSW, 1), + "CDM FWCtx shared alloc size load 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(4, ROGUE_FW_GROUP_CSW, 0), + "*** CDM FWCtx store complete" }, + { ROGUE_FW_LOG_CREATESFID(5, ROGUE_FW_GROUP_CSW, 0), + "*** CDM FWCtx store start" }, + { ROGUE_FW_LOG_CREATESFID(6, ROGUE_FW_GROUP_CSW, 0), + "CDM Soft Reset" }, + { ROGUE_FW_LOG_CREATESFID(7, ROGUE_FW_GROUP_CSW, 1), + "3D FWCtx 0x%08.8x needs resume" }, + { ROGUE_FW_LOG_CREATESFID(8, ROGUE_FW_GROUP_CSW, 1), + "*** 3D FWCtx 0x%08.8x resume" }, + { ROGUE_FW_LOG_CREATESFID(9, ROGUE_FW_GROUP_CSW, 0), + "*** 3D context store complete" }, + { ROGUE_FW_LOG_CREATESFID(10, ROGUE_FW_GROUP_CSW, 3), + "3D context store pipe state: 0x%08.8x 0x%08.8x 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(11, ROGUE_FW_GROUP_CSW, 0), + "*** 3D context store start" }, + { ROGUE_FW_LOG_CREATESFID(12, ROGUE_FW_GROUP_CSW, 1), + "*** 3D TQ FWCtx 0x%08.8x resume" }, + { ROGUE_FW_LOG_CREATESFID(13, ROGUE_FW_GROUP_CSW, 1), + "TA FWCtx 0x%08.8x needs resume" }, + { ROGUE_FW_LOG_CREATESFID(14, ROGUE_FW_GROUP_CSW, 3), + "*** TA FWCtx 0x%08.8x resume from snapshot buffer 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(15, ROGUE_FW_GROUP_CSW, 2), + "TA context shared alloc size store 0x%x, load 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(16, ROGUE_FW_GROUP_CSW, 0), + "*** TA context store complete" }, + { ROGUE_FW_LOG_CREATESFID(17, ROGUE_FW_GROUP_CSW, 0), + "*** TA context store start" }, + { ROGUE_FW_LOG_CREATESFID(18, ROGUE_FW_GROUP_CSW, 3), + "Higher priority context scheduled for DM %u, old prio:%d, new prio:%d" }, + { ROGUE_FW_LOG_CREATESFID(19, ROGUE_FW_GROUP_CSW, 2), + "Set FWCtx 0x%x priority to %u" }, + { ROGUE_FW_LOG_CREATESFID(20, ROGUE_FW_GROUP_CSW, 2), + "3D context store pipe%d state: 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(21, ROGUE_FW_GROUP_CSW, 2), + "3D context resume pipe%d state: 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(22, ROGUE_FW_GROUP_CSW, 1), + "SHG FWCtx 0x%08.8x needs resume" }, + { ROGUE_FW_LOG_CREATESFID(23, ROGUE_FW_GROUP_CSW, 3), + "*** SHG FWCtx 0x%08.8x resume from snapshot buffer 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(24, ROGUE_FW_GROUP_CSW, 2), + "SHG context shared alloc size store 0x%x, load 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(25, ROGUE_FW_GROUP_CSW, 0), + "*** SHG context store complete" }, + { ROGUE_FW_LOG_CREATESFID(26, ROGUE_FW_GROUP_CSW, 0), + "*** SHG context store start" }, + { ROGUE_FW_LOG_CREATESFID(27, ROGUE_FW_GROUP_CSW, 1), + "Performing TA indirection, last used pipe %d" }, + { ROGUE_FW_LOG_CREATESFID(28, ROGUE_FW_GROUP_CSW, 0), + "CDM context store hit ctrl stream terminate. Skip resume." }, + { ROGUE_FW_LOG_CREATESFID(29, ROGUE_FW_GROUP_CSW, 4), + "*** CDM FWCtx 0x%08.8x resume from snapshot buffer 0x%08x%08x, shader state %u" }, + { ROGUE_FW_LOG_CREATESFID(30, ROGUE_FW_GROUP_CSW, 2), + "TA PDS/USC state buffer flip (%d->%d)" }, + { ROGUE_FW_LOG_CREATESFID(31, ROGUE_FW_GROUP_CSW, 0), + "TA context store hit BRN 52563: vertex store tasks outstanding" }, + { ROGUE_FW_LOG_CREATESFID(32, ROGUE_FW_GROUP_CSW, 1), + "TA USC poll failed (USC vertex task count: %d)" }, + { ROGUE_FW_LOG_CREATESFID(33, ROGUE_FW_GROUP_CSW, 0), + "TA context store deferred due to BRN 54141." }, + { ROGUE_FW_LOG_CREATESFID(34, ROGUE_FW_GROUP_CSW, 7), + "Higher priority context scheduled for DM %u. Prios (OSid, OSid Prio, Context Prio): Current: %u, %u, %u New: %u, %u, %u" }, + { ROGUE_FW_LOG_CREATESFID(35, ROGUE_FW_GROUP_CSW, 0), + "*** TDM context store start" }, + { ROGUE_FW_LOG_CREATESFID(36, ROGUE_FW_GROUP_CSW, 0), + "*** TDM context store complete" }, + { ROGUE_FW_LOG_CREATESFID(37, ROGUE_FW_GROUP_CSW, 2), + "TDM context needs resume, header [0x%08.8x, 0x%08.8x]" }, + { ROGUE_FW_LOG_CREATESFID(38, ROGUE_FW_GROUP_CSW, 8), + "Higher priority context scheduled for DM %u. Prios (OSid, OSid Prio, Context Prio): Current: %u, %u, %u New: %u, %u, %u. Hard Context Switching: %u" }, + { ROGUE_FW_LOG_CREATESFID(39, ROGUE_FW_GROUP_CSW, 3), + "3D context store pipe %2d (%2d) state: 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(40, ROGUE_FW_GROUP_CSW, 3), + "3D context resume pipe %2d (%2d) state: 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(41, ROGUE_FW_GROUP_CSW, 1), + "*** 3D context store start version %d (1=IPP_TILE, 2=ISP_TILE)" }, + { ROGUE_FW_LOG_CREATESFID(42, ROGUE_FW_GROUP_CSW, 3), + "3D context store pipe%d state: 0x%08.8x%08x" }, + { ROGUE_FW_LOG_CREATESFID(43, ROGUE_FW_GROUP_CSW, 3), + "3D context resume pipe%d state: 0x%08.8x%08x" }, + { ROGUE_FW_LOG_CREATESFID(44, ROGUE_FW_GROUP_CSW, 2), + "3D context resume IPP state: 0x%08.8x%08x" }, + { ROGUE_FW_LOG_CREATESFID(45, ROGUE_FW_GROUP_CSW, 1), + "All 3D pipes empty after ISP tile mode store! IPP_status: 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(46, ROGUE_FW_GROUP_CSW, 3), + "TDM context resume pipe%d state: 0x%08.8x%08x" }, + { ROGUE_FW_LOG_CREATESFID(47, ROGUE_FW_GROUP_CSW, 0), + "*** 3D context store start version 4" }, + { ROGUE_FW_LOG_CREATESFID(48, ROGUE_FW_GROUP_CSW, 2), + "Multicore context resume on DM%d active core mask 0x%04.4x" }, + { ROGUE_FW_LOG_CREATESFID(49, ROGUE_FW_GROUP_CSW, 2), + "Multicore context store on DM%d active core mask 0x%04.4x" }, + { ROGUE_FW_LOG_CREATESFID(50, ROGUE_FW_GROUP_CSW, 5), + "TDM context resume Core %d, pipe%d state: 0x%08.8x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(51, ROGUE_FW_GROUP_CSW, 0), + "*** RDM FWCtx store complete" }, + { ROGUE_FW_LOG_CREATESFID(52, ROGUE_FW_GROUP_CSW, 0), + "*** RDM FWCtx store start" }, + { ROGUE_FW_LOG_CREATESFID(53, ROGUE_FW_GROUP_CSW, 1), + "RDM FWCtx 0x%08.8x needs resume" }, + { ROGUE_FW_LOG_CREATESFID(54, ROGUE_FW_GROUP_CSW, 1), + "RDM FWCtx 0x%08.8x resume" }, + + { ROGUE_FW_LOG_CREATESFID(1, ROGUE_FW_GROUP_BIF, 3), + "Activate MemCtx=0x%08x BIFreq=%d secure=%d" }, + { ROGUE_FW_LOG_CREATESFID(2, ROGUE_FW_GROUP_BIF, 1), + "Deactivate MemCtx=0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(3, ROGUE_FW_GROUP_BIF, 1), + "Alloc PC reg %d" }, + { ROGUE_FW_LOG_CREATESFID(4, ROGUE_FW_GROUP_BIF, 2), + "Grab reg set %d refcount now %d" }, + { ROGUE_FW_LOG_CREATESFID(5, ROGUE_FW_GROUP_BIF, 2), + "Ungrab reg set %d refcount now %d" }, + { ROGUE_FW_LOG_CREATESFID(6, ROGUE_FW_GROUP_BIF, 6), + "Setup reg=%d BIFreq=%d, expect=0x%08x%08x, actual=0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(7, ROGUE_FW_GROUP_BIF, 2), + "Trust enabled:%d, for BIFreq=%d" }, + { ROGUE_FW_LOG_CREATESFID(8, ROGUE_FW_GROUP_BIF, 9), + "BIF Tiling Cfg %d base 0x%08x%08x len 0x%08x%08x enable %d stride %d --> 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(9, ROGUE_FW_GROUP_BIF, 4), + "Wrote the Value %d to OSID0, Cat Base %d, Register's contents are now 0x%08x 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(10, ROGUE_FW_GROUP_BIF, 3), + "Wrote the Value %d to OSID1, Context %d, Register's contents are now 0x%04x" }, + { ROGUE_FW_LOG_CREATESFID(11, ROGUE_FW_GROUP_BIF, 7), + "ui32OSid = %u, Catbase = %u, Reg Address = 0x%x, Reg index = %u, Bitshift index = %u, Val = 0x%08x%08x" }, \ + { ROGUE_FW_LOG_CREATESFID(12, ROGUE_FW_GROUP_BIF, 5), + "Map GPU memory DevVAddr 0x%x%08x, Size %u, Context ID %u, BIFREQ %u" }, + { ROGUE_FW_LOG_CREATESFID(13, ROGUE_FW_GROUP_BIF, 1), + "Unmap GPU memory (event status 0x%x)" }, + { ROGUE_FW_LOG_CREATESFID(14, ROGUE_FW_GROUP_BIF, 3), + "Activate MemCtx=0x%08x DM=%d secure=%d" }, + { ROGUE_FW_LOG_CREATESFID(15, ROGUE_FW_GROUP_BIF, 6), + "Setup reg=%d DM=%d, expect=0x%08x%08x, actual=0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(16, ROGUE_FW_GROUP_BIF, 4), + "Map GPU memory DevVAddr 0x%x%08x, Size %u, Context ID %u" }, + { ROGUE_FW_LOG_CREATESFID(17, ROGUE_FW_GROUP_BIF, 2), + "Trust enabled:%d, for DM=%d" }, + { ROGUE_FW_LOG_CREATESFID(18, ROGUE_FW_GROUP_BIF, 5), + "Map GPU memory DevVAddr 0x%x%08x, Size %u, Context ID %u, DM %u" }, + { ROGUE_FW_LOG_CREATESFID(19, ROGUE_FW_GROUP_BIF, 6), + "Setup register set=%d DM=%d, PC address=0x%08x%08x, OSid=%u, NewPCRegRequired=%d" }, + { ROGUE_FW_LOG_CREATESFID(20, ROGUE_FW_GROUP_BIF, 3), + "Alloc PC set %d as register range [%u - %u]" }, + + { ROGUE_FW_LOG_CREATESFID(1, ROGUE_FW_GROUP_MISC, 1), + "GPIO write 0x%02x" }, + { ROGUE_FW_LOG_CREATESFID(2, ROGUE_FW_GROUP_MISC, 1), + "GPIO read 0x%02x" }, + { ROGUE_FW_LOG_CREATESFID(3, ROGUE_FW_GROUP_MISC, 0), + "GPIO enabled" }, + { ROGUE_FW_LOG_CREATESFID(4, ROGUE_FW_GROUP_MISC, 0), + "GPIO disabled" }, + { ROGUE_FW_LOG_CREATESFID(5, ROGUE_FW_GROUP_MISC, 1), + "GPIO status=%d (0=OK, 1=Disabled)" }, + { ROGUE_FW_LOG_CREATESFID(6, ROGUE_FW_GROUP_MISC, 2), + "GPIO_AP: Read address=0x%02x (%d byte(s))" }, + { ROGUE_FW_LOG_CREATESFID(7, ROGUE_FW_GROUP_MISC, 2), + "GPIO_AP: Write address=0x%02x (%d byte(s))" }, + { ROGUE_FW_LOG_CREATESFID(8, ROGUE_FW_GROUP_MISC, 0), + "GPIO_AP timeout!" }, + { ROGUE_FW_LOG_CREATESFID(9, ROGUE_FW_GROUP_MISC, 1), + "GPIO_AP error. GPIO status=%d (0=OK, 1=Disabled)" }, + { ROGUE_FW_LOG_CREATESFID(10, ROGUE_FW_GROUP_MISC, 1), + "GPIO already read 0x%02x" }, + { ROGUE_FW_LOG_CREATESFID(11, ROGUE_FW_GROUP_MISC, 2), + "SR: Check buffer %d available returned %d" }, + { ROGUE_FW_LOG_CREATESFID(12, ROGUE_FW_GROUP_MISC, 1), + "SR: Waiting for buffer %d" }, + { ROGUE_FW_LOG_CREATESFID(13, ROGUE_FW_GROUP_MISC, 2), + "SR: Timeout waiting for buffer %d (after %d ticks)" }, + { ROGUE_FW_LOG_CREATESFID(14, ROGUE_FW_GROUP_MISC, 2), + "SR: Skip frame check for strip %d returned %d (0=No skip, 1=Skip frame)" }, + { ROGUE_FW_LOG_CREATESFID(15, ROGUE_FW_GROUP_MISC, 1), + "SR: Skip remaining strip %d in frame" }, + { ROGUE_FW_LOG_CREATESFID(16, ROGUE_FW_GROUP_MISC, 1), + "SR: Inform HW that strip %d is a new frame" }, + { ROGUE_FW_LOG_CREATESFID(17, ROGUE_FW_GROUP_MISC, 1), + "SR: Timeout waiting for INTERRUPT_FRAME_SKIP (after %d ticks)" }, + { ROGUE_FW_LOG_CREATESFID(18, ROGUE_FW_GROUP_MISC, 1), + "SR: Strip mode is %d" }, + { ROGUE_FW_LOG_CREATESFID(19, ROGUE_FW_GROUP_MISC, 1), + "SR: Strip Render start (strip %d)" }, + { ROGUE_FW_LOG_CREATESFID(20, ROGUE_FW_GROUP_MISC, 1), + "SR: Strip Render complete (buffer %d)" }, + { ROGUE_FW_LOG_CREATESFID(21, ROGUE_FW_GROUP_MISC, 1), + "SR: Strip Render fault (buffer %d)" }, + { ROGUE_FW_LOG_CREATESFID(22, ROGUE_FW_GROUP_MISC, 1), + "TRP state: %d" }, + { ROGUE_FW_LOG_CREATESFID(23, ROGUE_FW_GROUP_MISC, 1), + "TRP failure: %d" }, + { ROGUE_FW_LOG_CREATESFID(24, ROGUE_FW_GROUP_MISC, 1), + "SW TRP State: %d" }, + { ROGUE_FW_LOG_CREATESFID(25, ROGUE_FW_GROUP_MISC, 1), + "SW TRP failure: %d" }, + { ROGUE_FW_LOG_CREATESFID(26, ROGUE_FW_GROUP_MISC, 1), + "HW kick event (%u)" }, + { ROGUE_FW_LOG_CREATESFID(27, ROGUE_FW_GROUP_MISC, 4), + "GPU core (%u/%u): checksum 0x%08x vs. 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(28, ROGUE_FW_GROUP_MISC, 6), + "GPU core (%u/%u), unit (%u,%u): checksum 0x%08x vs. 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(29, ROGUE_FW_GROUP_MISC, 6), + "HWR: Core%u, Register=0x%08x, OldValue=0x%08x%08x, CurrValue=0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(30, ROGUE_FW_GROUP_MISC, 4), + "HWR: USC Core%u, ui32TotalSlotsUsedByDM=0x%08x, psDMHWCtl->ui32USCSlotsUsedByDM=0x%08x, bHWRNeeded=%u" }, + { ROGUE_FW_LOG_CREATESFID(31, ROGUE_FW_GROUP_MISC, 6), + "HWR: USC Core%u, Register=0x%08x, OldValue=0x%08x%08x, CurrValue=0x%08x%08x" }, + + { ROGUE_FW_LOG_CREATESFID(1, ROGUE_FW_GROUP_PM, 10), + "ALIST%d SP = %u, MLIST%d SP = %u (VCE 0x%08x%08x, TE 0x%08x%08x, ALIST 0x%08x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(2, ROGUE_FW_GROUP_PM, 8), + "Is TA: %d, finished: %d on HW %u (HWRTData = 0x%08x, MemCtx = 0x%08x). FL different between TA/3D: global:%d, local:%d, mmu:%d" }, + { ROGUE_FW_LOG_CREATESFID(3, ROGUE_FW_GROUP_PM, 14), + "UFL-3D-Base: 0x%08x%08x (SP = %u, 4PB = %u, 4PT = %u), FL-3D-Base: 0x%08x%08x (SP = %u, 4PB = %u, 4PT = %u), MFL-3D-Base: 0x%08x%08x (SP = %u, 4PT = %u)" }, + { ROGUE_FW_LOG_CREATESFID(4, ROGUE_FW_GROUP_PM, 14), + "UFL-TA-Base: 0x%08x%08x (SP = %u, 4PB = %u, 4PT = %u), FL-TA-Base: 0x%08x%08x (SP = %u, 4PB = %u, 4PT = %u), MFL-TA-Base: 0x%08x%08x (SP = %u, 4PT = %u)" }, + { ROGUE_FW_LOG_CREATESFID(5, ROGUE_FW_GROUP_PM, 5), + "Freelist grow completed [0x%08x]: added pages 0x%08x, total pages 0x%08x, new DevVirtAddr 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(6, ROGUE_FW_GROUP_PM, 1), + "Grow for freelist ID=0x%08x denied by host" }, + { ROGUE_FW_LOG_CREATESFID(7, ROGUE_FW_GROUP_PM, 5), + "Freelist update completed [0x%08x]: old total pages 0x%08x, new total pages 0x%08x, new DevVirtAddr 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(8, ROGUE_FW_GROUP_PM, 1), + "Reconstruction of freelist ID=0x%08x failed" }, + { ROGUE_FW_LOG_CREATESFID(9, ROGUE_FW_GROUP_PM, 2), + "Ignored attempt to pause or unpause the DM while there is no relevant operation in progress (0-TA,1-3D): %d, operation(0-unpause, 1-pause): %d" }, + { ROGUE_FW_LOG_CREATESFID(10, ROGUE_FW_GROUP_PM, 2), + "Force free 3D Context memory, FWCtx: 0x%08x, status(1:success, 0:fail): %d" }, + { ROGUE_FW_LOG_CREATESFID(11, ROGUE_FW_GROUP_PM, 1), + "PM pause TA ALLOC: PM_PAGE_MANAGEOP set to 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(12, ROGUE_FW_GROUP_PM, 1), + "PM unpause TA ALLOC: PM_PAGE_MANAGEOP set to 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(13, ROGUE_FW_GROUP_PM, 1), + "PM pause 3D DALLOC: PM_PAGE_MANAGEOP set to 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(14, ROGUE_FW_GROUP_PM, 1), + "PM unpause 3D DALLOC: PM_PAGE_MANAGEOP set to 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(15, ROGUE_FW_GROUP_PM, 1), + "PM ALLOC/DALLOC change was not actioned: PM_PAGE_MANAGEOP_STATUS=0x%x" }, + { ROGUE_FW_LOG_CREATESFID(16, ROGUE_FW_GROUP_PM, 7), + "Is TA: %d, finished: %d on HW %u (HWRTData = 0x%08x, MemCtx = 0x%08x). FL different between TA/3D: global:%d, local:%d" }, + { ROGUE_FW_LOG_CREATESFID(17, ROGUE_FW_GROUP_PM, 10), + "UFL-3D-Base: 0x%08x%08x (SP = %u, 4PB = %u, 4PT = %u), FL-3D-Base: 0x%08x%08x (SP = %u, 4PB = %u, 4PT = %u)" }, + { ROGUE_FW_LOG_CREATESFID(18, ROGUE_FW_GROUP_PM, 10), + "UFL-TA-Base: 0x%08x%08x (SP = %u, 4PB = %u, 4PT = %u), FL-TA-Base: 0x%08x%08x (SP = %u, 4PB = %u, 4PT = %u)" }, + { ROGUE_FW_LOG_CREATESFID(19, ROGUE_FW_GROUP_PM, 7), + "Freelist update completed [0x%08x / FL State 0x%08x%08x]: old total pages 0x%08x, new total pages 0x%08x, new DevVirtAddr 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(20, ROGUE_FW_GROUP_PM, 7), + "Freelist update failed [0x%08x / FL State 0x%08x%08x]: old total pages 0x%08x, new total pages 0x%08x, new DevVirtAddr 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(21, ROGUE_FW_GROUP_PM, 10), + "UFL-3D-State-Base: 0x%08x%08x (SP = %u, 4PB = %u, 4PT = %u), FL-3D-State-Base: 0x%08x%08x (SP = %u, 4PB = %u, 4PT = %u)" }, + { ROGUE_FW_LOG_CREATESFID(22, ROGUE_FW_GROUP_PM, 10), + "UFL-TA-State-Base: 0x%08x%08x (SP = %u, 4PB = %u, 4PT = %u), FL-TA-State-Base: 0x%08x%08x (SP = %u, 4PB = %u, 4PT = %u)" }, + { ROGUE_FW_LOG_CREATESFID(23, ROGUE_FW_GROUP_PM, 5), + "Freelist 0x%08x base address from HW: 0x%02x%08x (expected value: 0x%02x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(24, ROGUE_FW_GROUP_PM, 5), + "Analysis of FL grow: Pause=(%u,%u) Paused+Valid(%u,%u) PMStateBuffer=0x%x" }, + { ROGUE_FW_LOG_CREATESFID(25, ROGUE_FW_GROUP_PM, 5), + "Attempt FL grow for FL: 0x%08x, new dev address: 0x%02x%08x, new page count: %u, new ready count: %u" }, + { ROGUE_FW_LOG_CREATESFID(26, ROGUE_FW_GROUP_PM, 5), + "Deferring FL grow for non-loaded FL: 0x%08x, new dev address: 0x%02x%08x, new page count: %u, new ready count: %u" }, + { ROGUE_FW_LOG_CREATESFID(27, ROGUE_FW_GROUP_PM, 4), + "Is GEOM: %d, finished: %d (HWRTData = 0x%08x, MemCtx = 0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(28, ROGUE_FW_GROUP_PM, 1), + "3D Timeout Now for FWCtx 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(29, ROGUE_FW_GROUP_PM, 1), + "GEOM PM Recycle for FWCtx 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(30, ROGUE_FW_GROUP_PM, 1), + "PM running primary config (Core %d)" }, + { ROGUE_FW_LOG_CREATESFID(31, ROGUE_FW_GROUP_PM, 1), + "PM running secondary config (Core %d)" }, + { ROGUE_FW_LOG_CREATESFID(32, ROGUE_FW_GROUP_PM, 1), + "PM running tertiary config (Core %d)" }, + { ROGUE_FW_LOG_CREATESFID(33, ROGUE_FW_GROUP_PM, 1), + "PM running quaternary config (Core %d)" }, + + { ROGUE_FW_LOG_CREATESFID(1, ROGUE_FW_GROUP_RPM, 3), + "Global link list dynamic page count: vertex 0x%x, varying 0x%x, node 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(2, ROGUE_FW_GROUP_RPM, 3), + "Global link list static page count: vertex 0x%x, varying 0x%x, node 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(3, ROGUE_FW_GROUP_RPM, 0), + "RPM request failed. Waiting for freelist grow." }, + { ROGUE_FW_LOG_CREATESFID(4, ROGUE_FW_GROUP_RPM, 0), + "RPM request failed. Aborting the current frame." }, + { ROGUE_FW_LOG_CREATESFID(5, ROGUE_FW_GROUP_RPM, 1), + "RPM waiting for pending grow on freelist 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(6, ROGUE_FW_GROUP_RPM, 3), + "Request freelist grow [0x%08x] current pages %d, grow size %d" }, + { ROGUE_FW_LOG_CREATESFID(7, ROGUE_FW_GROUP_RPM, 2), + "Freelist load: SHF = 0x%08x, SHG = 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(8, ROGUE_FW_GROUP_RPM, 2), + "SHF FPL register: 0x%08x.0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(9, ROGUE_FW_GROUP_RPM, 2), + "SHG FPL register: 0x%08x.0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(10, ROGUE_FW_GROUP_RPM, 5), + "Kernel requested RPM grow on freelist (type %d) at 0x%08x from current size %d to new size %d, RPM restart: %d (1=Yes)" }, + { ROGUE_FW_LOG_CREATESFID(11, ROGUE_FW_GROUP_RPM, 0), + "Restarting SHG" }, + { ROGUE_FW_LOG_CREATESFID(12, ROGUE_FW_GROUP_RPM, 0), + "Grow failed, aborting the current frame." }, + { ROGUE_FW_LOG_CREATESFID(13, ROGUE_FW_GROUP_RPM, 1), + "RPM abort complete on HWFrameData [0x%08x]." }, + { ROGUE_FW_LOG_CREATESFID(14, ROGUE_FW_GROUP_RPM, 1), + "RPM freelist cleanup [0x%08x] requires abort to proceed." }, + { ROGUE_FW_LOG_CREATESFID(15, ROGUE_FW_GROUP_RPM, 2), + "RPM page table base register: 0x%08x.0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(16, ROGUE_FW_GROUP_RPM, 0), + "Issuing RPM abort." }, + { ROGUE_FW_LOG_CREATESFID(17, ROGUE_FW_GROUP_RPM, 0), + "RPM OOM received but toggle bits indicate free pages available" }, + { ROGUE_FW_LOG_CREATESFID(18, ROGUE_FW_GROUP_RPM, 0), + "RPM hardware timeout. Unable to process OOM event." }, + { ROGUE_FW_LOG_CREATESFID(19, ROGUE_FW_GROUP_RPM, 5), + "SHF FL (0x%08x) load, FPL: 0x%08x.0x%08x, roff: 0x%08x, woff: 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(20, ROGUE_FW_GROUP_RPM, 5), + "SHG FL (0x%08x) load, FPL: 0x%08x.0x%08x, roff: 0x%08x, woff: 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(21, ROGUE_FW_GROUP_RPM, 3), + "SHF FL (0x%08x) store, roff: 0x%08x, woff: 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(22, ROGUE_FW_GROUP_RPM, 3), + "SHG FL (0x%08x) store, roff: 0x%08x, woff: 0x%08x" }, + + { ROGUE_FW_LOG_CREATESFID(1, ROGUE_FW_GROUP_RTD, 2), + "3D RTData 0x%08x finished on HW context %u" }, + { ROGUE_FW_LOG_CREATESFID(2, ROGUE_FW_GROUP_RTD, 2), + "3D RTData 0x%08x ready on HW context %u" }, + { ROGUE_FW_LOG_CREATESFID(3, ROGUE_FW_GROUP_RTD, 4), + "CONTEXT_PB_BASE set to 0x%x, FL different between TA/3D: local: %d, global: %d, mmu: %d" }, + { ROGUE_FW_LOG_CREATESFID(4, ROGUE_FW_GROUP_RTD, 2), + "Loading VFP table 0x%08x%08x for 3D" }, + { ROGUE_FW_LOG_CREATESFID(5, ROGUE_FW_GROUP_RTD, 2), + "Loading VFP table 0x%08x%08x for TA" }, + { ROGUE_FW_LOG_CREATESFID(6, ROGUE_FW_GROUP_RTD, 10), + "Load Freelist 0x%x type: %d (0:local,1:global,2:mmu) for DM%d: TotalPMPages = %d, FL-addr = 0x%08x%08x, stacktop = 0x%08x%08x, Alloc Page Count = %u, Alloc MMU Page Count = %u" }, + { ROGUE_FW_LOG_CREATESFID(7, ROGUE_FW_GROUP_RTD, 0), + "Perform VHEAP table store" }, + { ROGUE_FW_LOG_CREATESFID(8, ROGUE_FW_GROUP_RTD, 2), + "RTData 0x%08x: found match in Context=%d: Load=No, Store=No" }, + { ROGUE_FW_LOG_CREATESFID(9, ROGUE_FW_GROUP_RTD, 2), + "RTData 0x%08x: found NULL in Context=%d: Load=Yes, Store=No" }, + { ROGUE_FW_LOG_CREATESFID(10, ROGUE_FW_GROUP_RTD, 3), + "RTData 0x%08x: found state 3D finished (0x%08x) in Context=%d: Load=Yes, Store=Yes" }, + { ROGUE_FW_LOG_CREATESFID(11, ROGUE_FW_GROUP_RTD, 3), + "RTData 0x%08x: found state TA finished (0x%08x) in Context=%d: Load=Yes, Store=Yes" }, + { ROGUE_FW_LOG_CREATESFID(12, ROGUE_FW_GROUP_RTD, 5), + "Loading stack-pointers for %d (0:MidTA,1:3D) on context %d, MLIST = 0x%08x, ALIST = 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(13, ROGUE_FW_GROUP_RTD, 10), + "Store Freelist 0x%x type: %d (0:local,1:global,2:mmu) for DM%d: TotalPMPages = %d, FL-addr = 0x%08x%08x, stacktop = 0x%08x%08x, Alloc Page Count = %u, Alloc MMU Page Count = %u" }, + { ROGUE_FW_LOG_CREATESFID(14, ROGUE_FW_GROUP_RTD, 2), + "TA RTData 0x%08x finished on HW context %u" }, + { ROGUE_FW_LOG_CREATESFID(15, ROGUE_FW_GROUP_RTD, 2), + "TA RTData 0x%08x loaded on HW context %u" }, + { ROGUE_FW_LOG_CREATESFID(16, ROGUE_FW_GROUP_RTD, 12), + "Store Freelist 0x%x type: %d (0:local,1:global,2:mmu) for DM%d: FL Total Pages %u (max=%u,grow size=%u), FL-addr = 0x%08x%08x, stacktop = 0x%08x%08x, Alloc Page Count = %u, Alloc MMU Page Count = %u" }, + { ROGUE_FW_LOG_CREATESFID(17, ROGUE_FW_GROUP_RTD, 12), + "Load Freelist 0x%x type: %d (0:local,1:global,2:mmu) for DM%d: FL Total Pages %u (max=%u,grow size=%u), FL-addr = 0x%08x%08x, stacktop = 0x%08x%08x, Alloc Page Count = %u, Alloc MMU Page Count = %u" }, + { ROGUE_FW_LOG_CREATESFID(18, ROGUE_FW_GROUP_RTD, 1), + "Freelist 0x%x RESET!!!!!!!!" }, + { ROGUE_FW_LOG_CREATESFID(19, ROGUE_FW_GROUP_RTD, 5), + "Freelist 0x%x stacktop = 0x%08x%08x, Alloc Page Count = %u, Alloc MMU Page Count = %u" }, + { ROGUE_FW_LOG_CREATESFID(20, ROGUE_FW_GROUP_RTD, 3), + "Request reconstruction of Freelist 0x%x type: %d (0:local,1:global,2:mmu) on HW context %u" }, + { ROGUE_FW_LOG_CREATESFID(21, ROGUE_FW_GROUP_RTD, 1), + "Freelist reconstruction ACK from host (HWR state :%u)" }, + { ROGUE_FW_LOG_CREATESFID(22, ROGUE_FW_GROUP_RTD, 0), + "Freelist reconstruction completed" }, + { ROGUE_FW_LOG_CREATESFID(23, ROGUE_FW_GROUP_RTD, 3), + "TA RTData 0x%08x loaded on HW context %u HWRTDataNeedsLoading=%d" }, + { ROGUE_FW_LOG_CREATESFID(24, ROGUE_FW_GROUP_RTD, 3), + "TE Region headers base 0x%08x%08x (RGNHDR Init: %d)" }, + { ROGUE_FW_LOG_CREATESFID(25, ROGUE_FW_GROUP_RTD, 8), + "TA Buffers: FWCtx 0x%08x, RT 0x%08x, RTData 0x%08x, VHeap 0x%08x%08x, TPC 0x%08x%08x (MemCtx 0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(26, ROGUE_FW_GROUP_RTD, 2), + "3D RTData 0x%08x loaded on HW context %u" }, + { ROGUE_FW_LOG_CREATESFID(27, ROGUE_FW_GROUP_RTD, 4), + "3D Buffers: FWCtx 0x%08x, RT 0x%08x, RTData 0x%08x (MemCtx 0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(28, ROGUE_FW_GROUP_RTD, 2), + "Restarting TA after partial render, HWRTData0State=0x%x, HWRTData1State=0x%x" }, + { ROGUE_FW_LOG_CREATESFID(29, ROGUE_FW_GROUP_RTD, 3), + "CONTEXT_PB_BASE set to 0x%x, FL different between TA/3D: local: %d, global: %d" }, + { ROGUE_FW_LOG_CREATESFID(30, ROGUE_FW_GROUP_RTD, 12), + "Store Freelist 0x%x type: %d (0:local,1:global) for PMDM%d: FL Total Pages %u (max=%u,grow size=%u), FL-addr = 0x%08x%08x, stacktop = 0x%08x%08x, Alloc Page Count = %u, Alloc MMU Page Count = %u" }, + { ROGUE_FW_LOG_CREATESFID(31, ROGUE_FW_GROUP_RTD, 12), + "Load Freelist 0x%x type: %d (0:local,1:global) for PMDM%d: FL Total Pages %u (max=%u,grow size=%u), FL-addr = 0x%08x%08x, stacktop = 0x%08x%08x, Alloc Page Count = %u, Alloc MMU Page Count = %u" }, + { ROGUE_FW_LOG_CREATESFID(32, ROGUE_FW_GROUP_RTD, 5), + "3D Buffers: FWCtx 0x%08x, parent RT 0x%08x, RTData 0x%08x on ctx %d, (MemCtx 0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(33, ROGUE_FW_GROUP_RTD, 7), + "TA Buffers: FWCtx 0x%08x, RTData 0x%08x, VHeap 0x%08x%08x, TPC 0x%08x%08x (MemCtx 0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(34, ROGUE_FW_GROUP_RTD, 4), + "3D Buffers: FWCtx 0x%08x, RTData 0x%08x on ctx %d, (MemCtx 0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(35, ROGUE_FW_GROUP_RTD, 6), + "Load Freelist 0x%x type: %d (0:local,1:global) for PMDM%d: FL Total Pages %u (max=%u,grow size=%u)" }, + { ROGUE_FW_LOG_CREATESFID(36, ROGUE_FW_GROUP_RTD, 1), + "TA RTData 0x%08x marked as killed." }, + { ROGUE_FW_LOG_CREATESFID(37, ROGUE_FW_GROUP_RTD, 1), + "3D RTData 0x%08x marked as killed." }, + { ROGUE_FW_LOG_CREATESFID(38, ROGUE_FW_GROUP_RTD, 1), + "RTData 0x%08x will be killed after TA restart." }, + { ROGUE_FW_LOG_CREATESFID(39, ROGUE_FW_GROUP_RTD, 3), + "RTData 0x%08x Render State Buffer 0x%02x%08x will be reset." }, + { ROGUE_FW_LOG_CREATESFID(40, ROGUE_FW_GROUP_RTD, 3), + "GEOM RTData 0x%08x using Render State Buffer 0x%02x%08x." }, + { ROGUE_FW_LOG_CREATESFID(41, ROGUE_FW_GROUP_RTD, 3), + "FRAG RTData 0x%08x using Render State Buffer 0x%02x%08x." }, + + { ROGUE_FW_LOG_CREATESFID(1, ROGUE_FW_GROUP_SPM, 0), + "Force Z-Load for partial render" }, + { ROGUE_FW_LOG_CREATESFID(2, ROGUE_FW_GROUP_SPM, 0), + "Force Z-Store for partial render" }, + { ROGUE_FW_LOG_CREATESFID(3, ROGUE_FW_GROUP_SPM, 1), + "3D MemFree: Local FL 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(4, ROGUE_FW_GROUP_SPM, 1), + "3D MemFree: MMU FL 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(5, ROGUE_FW_GROUP_SPM, 1), + "3D MemFree: Global FL 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(6, ROGUE_FW_GROUP_SPM, 6), + "OOM TA/3D PR Check: [0x%08.8x] is 0x%08.8x requires 0x%08.8x, HardwareSync Fence [0x%08.8x] is 0x%08.8x requires 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(7, ROGUE_FW_GROUP_SPM, 3), + "OOM TA_cmd=0x%08x, U-FL 0x%08x, N-FL 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(8, ROGUE_FW_GROUP_SPM, 5), + "OOM TA_cmd=0x%08x, OOM MMU:%d, U-FL 0x%08x, N-FL 0x%08x, MMU-FL 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(9, ROGUE_FW_GROUP_SPM, 0), + "Partial render avoided" }, + { ROGUE_FW_LOG_CREATESFID(10, ROGUE_FW_GROUP_SPM, 0), + "Partial render discarded" }, + { ROGUE_FW_LOG_CREATESFID(11, ROGUE_FW_GROUP_SPM, 0), + "Partial Render finished" }, + { ROGUE_FW_LOG_CREATESFID(12, ROGUE_FW_GROUP_SPM, 0), + "SPM Owner = 3D-BG" }, + { ROGUE_FW_LOG_CREATESFID(13, ROGUE_FW_GROUP_SPM, 0), + "SPM Owner = 3D-IRQ" }, + { ROGUE_FW_LOG_CREATESFID(14, ROGUE_FW_GROUP_SPM, 0), + "SPM Owner = NONE" }, + { ROGUE_FW_LOG_CREATESFID(15, ROGUE_FW_GROUP_SPM, 0), + "SPM Owner = TA-BG" }, + { ROGUE_FW_LOG_CREATESFID(16, ROGUE_FW_GROUP_SPM, 0), + "SPM Owner = TA-IRQ" }, + { ROGUE_FW_LOG_CREATESFID(17, ROGUE_FW_GROUP_SPM, 2), + "ZStore address 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(18, ROGUE_FW_GROUP_SPM, 2), + "SStore address 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(19, ROGUE_FW_GROUP_SPM, 2), + "ZLoad address 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(20, ROGUE_FW_GROUP_SPM, 2), + "SLoad address 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(21, ROGUE_FW_GROUP_SPM, 0), + "No deferred ZS Buffer provided" }, + { ROGUE_FW_LOG_CREATESFID(22, ROGUE_FW_GROUP_SPM, 1), + "ZS Buffer successfully populated (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(23, ROGUE_FW_GROUP_SPM, 1), + "No need to populate ZS Buffer (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(24, ROGUE_FW_GROUP_SPM, 1), + "ZS Buffer successfully unpopulated (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(25, ROGUE_FW_GROUP_SPM, 1), + "No need to unpopulate ZS Buffer (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(26, ROGUE_FW_GROUP_SPM, 1), + "Send ZS-Buffer backing request to host (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(27, ROGUE_FW_GROUP_SPM, 1), + "Send ZS-Buffer unbacking request to host (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(28, ROGUE_FW_GROUP_SPM, 1), + "Don't send ZS-Buffer backing request. Previous request still pending (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(29, ROGUE_FW_GROUP_SPM, 1), + "Don't send ZS-Buffer unbacking request. Previous request still pending (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(30, ROGUE_FW_GROUP_SPM, 1), + "Partial Render waiting for ZBuffer to be backed (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(31, ROGUE_FW_GROUP_SPM, 1), + "Partial Render waiting for SBuffer to be backed (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(32, ROGUE_FW_GROUP_SPM, 0), + "SPM State = none" }, + { ROGUE_FW_LOG_CREATESFID(33, ROGUE_FW_GROUP_SPM, 0), + "SPM State = PR blocked" }, + { ROGUE_FW_LOG_CREATESFID(34, ROGUE_FW_GROUP_SPM, 0), + "SPM State = wait for grow" }, + { ROGUE_FW_LOG_CREATESFID(35, ROGUE_FW_GROUP_SPM, 0), + "SPM State = wait for HW" }, + { ROGUE_FW_LOG_CREATESFID(36, ROGUE_FW_GROUP_SPM, 0), + "SPM State = PR running" }, + { ROGUE_FW_LOG_CREATESFID(37, ROGUE_FW_GROUP_SPM, 0), + "SPM State = PR avoided" }, + { ROGUE_FW_LOG_CREATESFID(38, ROGUE_FW_GROUP_SPM, 0), + "SPM State = PR executed" }, + { ROGUE_FW_LOG_CREATESFID(39, ROGUE_FW_GROUP_SPM, 2), + "3DMemFree matches freelist 0x%08x (FL type = %u)" }, + { ROGUE_FW_LOG_CREATESFID(40, ROGUE_FW_GROUP_SPM, 0), + "Raise the 3DMemFreeDetected flag" }, + { ROGUE_FW_LOG_CREATESFID(41, ROGUE_FW_GROUP_SPM, 1), + "Wait for pending grow on Freelist 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(42, ROGUE_FW_GROUP_SPM, 1), + "ZS Buffer failed to be populated (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(43, ROGUE_FW_GROUP_SPM, 5), + "Grow update inconsistency: FL addr: 0x%02x%08x, curr pages: %u, ready: %u, new: %u" }, + { ROGUE_FW_LOG_CREATESFID(44, ROGUE_FW_GROUP_SPM, 4), + "OOM: Resumed TA with ready pages, FL addr: 0x%02x%08x, current pages: %u, SP : %u" }, + { ROGUE_FW_LOG_CREATESFID(45, ROGUE_FW_GROUP_SPM, 5), + "Received grow update, FL addr: 0x%02x%08x, current pages: %u, ready pages: %u, threshold: %u" }, + { ROGUE_FW_LOG_CREATESFID(46, ROGUE_FW_GROUP_SPM, 1), + "No deferred partial render FW (Type=%d) Buffer provided" }, + { ROGUE_FW_LOG_CREATESFID(47, ROGUE_FW_GROUP_SPM, 1), + "No need to populate PR Buffer (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(48, ROGUE_FW_GROUP_SPM, 1), + "No need to unpopulate PR Buffer (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(49, ROGUE_FW_GROUP_SPM, 1), + "Send PR Buffer backing request to host (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(50, ROGUE_FW_GROUP_SPM, 1), + "Send PR Buffer unbacking request to host (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(51, ROGUE_FW_GROUP_SPM, 1), + "Don't send PR Buffer backing request. Previous request still pending (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(52, ROGUE_FW_GROUP_SPM, 1), + "Don't send PR Buffer unbacking request. Previous request still pending (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(53, ROGUE_FW_GROUP_SPM, 2), + "Partial Render waiting for Buffer %d type to be backed (ID=0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(54, ROGUE_FW_GROUP_SPM, 4), + "Received grow update, FL addr: 0x%02x%08x, new pages: %u, ready pages: %u" }, + { ROGUE_FW_LOG_CREATESFID(66, ROGUE_FW_GROUP_SPM, 3), + "OOM TA/3D PR Check: [0x%08.8x] is 0x%08.8x requires 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(67, ROGUE_FW_GROUP_SPM, 3), + "OOM: Resumed TA with ready pages, FL addr: 0x%02x%08x, current pages: %u" }, + { ROGUE_FW_LOG_CREATESFID(68, ROGUE_FW_GROUP_SPM, 3), + "OOM TA/3D PR deadlock unblocked reordering DM%d runlist head from Context 0x%08x to 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(69, ROGUE_FW_GROUP_SPM, 0), + "SPM State = PR force free" }, + + { ROGUE_FW_LOG_CREATESFID(1, ROGUE_FW_GROUP_POW, 4), + "Check Pow state DM%d int: 0x%x, ext: 0x%x, pow flags: 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(2, ROGUE_FW_GROUP_POW, 3), + "GPU idle (might be powered down). Pow state int: 0x%x, ext: 0x%x, flags: 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(3, ROGUE_FW_GROUP_POW, 3), + "OS requested pow off (forced = %d), DM%d, pow flags: 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(4, ROGUE_FW_GROUP_POW, 4), + "Initiate powoff query. Inactive DMs: %d %d %d %d" }, + { ROGUE_FW_LOG_CREATESFID(5, ROGUE_FW_GROUP_POW, 2), + "Any RD-DM pending? %d, Any RD-DM Active? %d" }, + { ROGUE_FW_LOG_CREATESFID(6, ROGUE_FW_GROUP_POW, 3), + "GPU ready to be powered down. Pow state int: 0x%x, ext: 0x%x, flags: 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(7, ROGUE_FW_GROUP_POW, 2), + "HW Request On(1)/Off(0): %d, Units: 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(8, ROGUE_FW_GROUP_POW, 2), + "Request to change num of dusts to %d (Power flags=%d)" }, + { ROGUE_FW_LOG_CREATESFID(9, ROGUE_FW_GROUP_POW, 2), + "Changing number of dusts from %d to %d" }, + { ROGUE_FW_LOG_CREATESFID(11, ROGUE_FW_GROUP_POW, 0), + "Sidekick init" }, + { ROGUE_FW_LOG_CREATESFID(12, ROGUE_FW_GROUP_POW, 1), + "Rascal+Dusts init (# dusts mask: 0x%x)" }, + { ROGUE_FW_LOG_CREATESFID(13, ROGUE_FW_GROUP_POW, 0), + "Initiate powoff query for RD-DMs." }, + { ROGUE_FW_LOG_CREATESFID(14, ROGUE_FW_GROUP_POW, 0), + "Initiate powoff query for TLA-DM." }, + { ROGUE_FW_LOG_CREATESFID(15, ROGUE_FW_GROUP_POW, 2), + "Any RD-DM pending? %d, Any RD-DM Active? %d" }, + { ROGUE_FW_LOG_CREATESFID(16, ROGUE_FW_GROUP_POW, 2), + "TLA-DM pending? %d, TLA-DM Active? %d" }, + { ROGUE_FW_LOG_CREATESFID(17, ROGUE_FW_GROUP_POW, 1), + "Request power up due to BRN37270. Pow stat int: 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(18, ROGUE_FW_GROUP_POW, 3), + "Cancel power off request int: 0x%x, ext: 0x%x, pow flags: 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(19, ROGUE_FW_GROUP_POW, 1), + "OS requested forced IDLE, pow flags: 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(20, ROGUE_FW_GROUP_POW, 1), + "OS cancelled forced IDLE, pow flags: 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(21, ROGUE_FW_GROUP_POW, 3), + "Idle timer start. Pow state int: 0x%x, ext: 0x%x, flags: 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(22, ROGUE_FW_GROUP_POW, 3), + "Cancel idle timer. Pow state int: 0x%x, ext: 0x%x, flags: 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(23, ROGUE_FW_GROUP_POW, 2), + "Active PM latency set to %dms. Core clock: %d Hz" }, + { ROGUE_FW_LOG_CREATESFID(24, ROGUE_FW_GROUP_POW, 2), + "Compute cluster mask change to 0x%x, %d dusts powered." }, + { ROGUE_FW_LOG_CREATESFID(25, ROGUE_FW_GROUP_POW, 0), + "Null command executed, repeating initiate powoff query for RD-DMs." }, + { ROGUE_FW_LOG_CREATESFID(26, ROGUE_FW_GROUP_POW, 1), + "Power monitor: Estimate of dynamic energy %u" }, + { ROGUE_FW_LOG_CREATESFID(27, ROGUE_FW_GROUP_POW, 3), + "Check Pow state: Int: 0x%x, Ext: 0x%x, Pow flags: 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(28, ROGUE_FW_GROUP_POW, 2), + "Proactive DVFS: New deadline, time = 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(29, ROGUE_FW_GROUP_POW, 2), + "Proactive DVFS: New workload, cycles = 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(30, ROGUE_FW_GROUP_POW, 1), + "Proactive DVFS: Proactive frequency calculated = %u" }, + { ROGUE_FW_LOG_CREATESFID(31, ROGUE_FW_GROUP_POW, 1), + "Proactive DVFS: Reactive utilisation = %u percent" }, + { ROGUE_FW_LOG_CREATESFID(32, ROGUE_FW_GROUP_POW, 2), + "Proactive DVFS: Reactive frequency calculated = %u.%u" }, + { ROGUE_FW_LOG_CREATESFID(33, ROGUE_FW_GROUP_POW, 1), + "Proactive DVFS: OPP Point Sent = 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(34, ROGUE_FW_GROUP_POW, 2), + "Proactive DVFS: Deadline removed = 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(35, ROGUE_FW_GROUP_POW, 2), + "Proactive DVFS: Workload removed = 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(36, ROGUE_FW_GROUP_POW, 1), + "Proactive DVFS: Throttle to a maximum = 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(37, ROGUE_FW_GROUP_POW, 0), + "Proactive DVFS: Failed to pass OPP point via GPIO." }, + { ROGUE_FW_LOG_CREATESFID(38, ROGUE_FW_GROUP_POW, 0), + "Proactive DVFS: Invalid node passed to function." }, + { ROGUE_FW_LOG_CREATESFID(39, ROGUE_FW_GROUP_POW, 1), + "Proactive DVFS: Guest OS attempted to do a privileged action. OSid = %u" }, + { ROGUE_FW_LOG_CREATESFID(40, ROGUE_FW_GROUP_POW, 1), + "Proactive DVFS: Unprofiled work started. Total unprofiled work present: %u" }, + { ROGUE_FW_LOG_CREATESFID(41, ROGUE_FW_GROUP_POW, 1), + "Proactive DVFS: Unprofiled work finished. Total unprofiled work present: %u" }, + { ROGUE_FW_LOG_CREATESFID(42, ROGUE_FW_GROUP_POW, 0), + "Proactive DVFS: Disabled: Not enabled by host." }, + { ROGUE_FW_LOG_CREATESFID(43, ROGUE_FW_GROUP_POW, 2), + "HW Request Completed(1)/Aborted(0): %d, Ticks: %d" }, + { ROGUE_FW_LOG_CREATESFID(44, ROGUE_FW_GROUP_POW, 1), + "Allowed number of dusts is %d due to BRN59042." }, + { ROGUE_FW_LOG_CREATESFID(45, ROGUE_FW_GROUP_POW, 3), + "Host timed out while waiting for a forced idle state. Pow state int: 0x%x, ext: 0x%x, flags: 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(46, ROGUE_FW_GROUP_POW, 5), + "Check Pow state: Int: 0x%x, Ext: 0x%x, Pow flags: 0x%x, Fence Counters: Check: %u - Update: %u" }, + { ROGUE_FW_LOG_CREATESFID(47, ROGUE_FW_GROUP_POW, 2), + "Proactive DVFS: OPP Point Sent = 0x%x, Success = 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(48, ROGUE_FW_GROUP_POW, 0), + "Proactive DVFS: GPU transitioned to idle" }, + { ROGUE_FW_LOG_CREATESFID(49, ROGUE_FW_GROUP_POW, 0), + "Proactive DVFS: GPU transitioned to active" }, + { ROGUE_FW_LOG_CREATESFID(50, ROGUE_FW_GROUP_POW, 1), + "Power counter dumping: Data truncated writing register %u. Buffer too small." }, + { ROGUE_FW_LOG_CREATESFID(51, ROGUE_FW_GROUP_POW, 0), + "Power controller returned ABORT for last request so retrying." }, + { ROGUE_FW_LOG_CREATESFID(52, ROGUE_FW_GROUP_POW, 2), + "Discarding invalid power request: type 0x%x, DM %u" }, + { ROGUE_FW_LOG_CREATESFID(53, ROGUE_FW_GROUP_POW, 2), + "Detected attempt to cancel forced idle while not forced idle (pow state 0x%x, pow flags 0x%x)" }, + { ROGUE_FW_LOG_CREATESFID(54, ROGUE_FW_GROUP_POW, 2), + "Detected attempt to force power off while not forced idle (pow state 0x%x, pow flags 0x%x)" }, + { ROGUE_FW_LOG_CREATESFID(55, ROGUE_FW_GROUP_POW, 1), + "Detected attempt to change dust count while not forced idle (pow state 0x%x)" }, + { ROGUE_FW_LOG_CREATESFID(56, ROGUE_FW_GROUP_POW, 3), + "Power monitor: Type = %d (0 = power, 1 = energy), Estimate result = 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(57, ROGUE_FW_GROUP_POW, 2), + "Conflicting clock frequency range: OPP min = %u, max = %u" }, + { ROGUE_FW_LOG_CREATESFID(58, ROGUE_FW_GROUP_POW, 1), + "Proactive DVFS: Set floor to a minimum = 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(59, ROGUE_FW_GROUP_POW, 2), + "OS requested pow off (forced = %d), pow flags: 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(60, ROGUE_FW_GROUP_POW, 1), + "Discarding invalid power request: type 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(61, ROGUE_FW_GROUP_POW, 3), + "Request to change SPU power state mask from 0x%x to 0x%x. Pow flags: 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(62, ROGUE_FW_GROUP_POW, 2), + "Changing SPU power state mask from 0x%x to 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(63, ROGUE_FW_GROUP_POW, 1), + "Detected attempt to change SPU power state mask while not forced idle (pow state 0x%x)" }, + { ROGUE_FW_LOG_CREATESFID(64, ROGUE_FW_GROUP_POW, 1), + "Invalid SPU power mask 0x%x! Changing to 1" }, + { ROGUE_FW_LOG_CREATESFID(65, ROGUE_FW_GROUP_POW, 2), + "Proactive DVFS: Send OPP %u with clock divider value %u" }, + { ROGUE_FW_LOG_CREATESFID(66, ROGUE_FW_GROUP_POW, 0), + "PPA block started in perf validation mode." }, + { ROGUE_FW_LOG_CREATESFID(67, ROGUE_FW_GROUP_POW, 1), + "Reset PPA block state %u (1=reset, 0=recalculate)." }, + { ROGUE_FW_LOG_CREATESFID(68, ROGUE_FW_GROUP_POW, 1), + "Power controller returned ABORT for Core-%d last request so retrying." }, + { ROGUE_FW_LOG_CREATESFID(69, ROGUE_FW_GROUP_POW, 3), + "HW Request On(1)/Off(0): %d, Units: 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(70, ROGUE_FW_GROUP_POW, 5), + "Request to change SPU power state mask from 0x%x to 0x%x and RAC from 0x%x to 0x%x. Pow flags: 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(71, ROGUE_FW_GROUP_POW, 4), + "Changing SPU power state mask from 0x%x to 0x%x and RAC from 0x%x to 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(72, ROGUE_FW_GROUP_POW, 2), + "RAC pending? %d, RAC Active? %d" }, + { ROGUE_FW_LOG_CREATESFID(73, ROGUE_FW_GROUP_POW, 0), + "Initiate powoff query for RAC." }, + + { ROGUE_FW_LOG_CREATESFID(1, ROGUE_FW_GROUP_HWR, 2), + "Lockup detected on DM%d, FWCtx: 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(2, ROGUE_FW_GROUP_HWR, 3), + "Reset fw state for DM%d, FWCtx: 0x%08.8x, MemCtx: 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(3, ROGUE_FW_GROUP_HWR, 0), + "Reset HW" }, + { ROGUE_FW_LOG_CREATESFID(4, ROGUE_FW_GROUP_HWR, 0), + "Lockup recovered." }, + { ROGUE_FW_LOG_CREATESFID(5, ROGUE_FW_GROUP_HWR, 2), + "Lock-up DM%d FWCtx: 0x%08.8x" }, + { ROGUE_FW_LOG_CREATESFID(6, ROGUE_FW_GROUP_HWR, 4), + "Lockup detected: GLB(%d->%d), PER-DM(0x%08x->0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(7, ROGUE_FW_GROUP_HWR, 3), + "Early fault detection: GLB(%d->%d), PER-DM(0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(8, ROGUE_FW_GROUP_HWR, 3), + "Hold scheduling due lockup: GLB(%d), PER-DM(0x%08x->0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(9, ROGUE_FW_GROUP_HWR, 4), + "False lockup detected: GLB(%d->%d), PER-DM(0x%08x->0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(10, ROGUE_FW_GROUP_HWR, 4), + "BRN37729: GLB(%d->%d), PER-DM(0x%08x->0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(11, ROGUE_FW_GROUP_HWR, 3), + "Freelists reconstructed: GLB(%d->%d), PER-DM(0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(12, ROGUE_FW_GROUP_HWR, 4), + "Reconstructing freelists: %u (0-No, 1-Yes): GLB(%d->%d), PER-DM(0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(13, ROGUE_FW_GROUP_HWR, 3), + "HW poll %u (0-Unset 1-Set) failed (reg:0x%08x val:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(14, ROGUE_FW_GROUP_HWR, 2), + "Discarded cmd on DM%u FWCtx=0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(15, ROGUE_FW_GROUP_HWR, 6), + "Discarded cmd on DM%u (reason=%u) HWRTData=0x%08x (st: %d), FWCtx 0x%08x @ %d" }, + { ROGUE_FW_LOG_CREATESFID(16, ROGUE_FW_GROUP_HWR, 2), + "PM fence WA could not be applied, Valid TA Setup: %d, RD powered off: %d" }, + { ROGUE_FW_LOG_CREATESFID(17, ROGUE_FW_GROUP_HWR, 5), + "FL snapshot RTD 0x%08.8x - local (0x%08.8x): %d, global (0x%08.8x): %d" }, + { ROGUE_FW_LOG_CREATESFID(18, ROGUE_FW_GROUP_HWR, 8), + "FL check RTD 0x%08.8x, discard: %d - local (0x%08.8x): s%d?=c%d, global (0x%08.8x): s%d?=c%d" }, + { ROGUE_FW_LOG_CREATESFID(19, ROGUE_FW_GROUP_HWR, 2), + "FL reconstruction 0x%08.8x c%d" }, + { ROGUE_FW_LOG_CREATESFID(20, ROGUE_FW_GROUP_HWR, 3), + "3D check: missing TA FWCtx 0x%08.8x @ %d, RTD 0x%08x." }, + { ROGUE_FW_LOG_CREATESFID(21, ROGUE_FW_GROUP_HWR, 2), + "Reset HW (mmu:%d, extmem: %d)" }, + { ROGUE_FW_LOG_CREATESFID(22, ROGUE_FW_GROUP_HWR, 4), + "Zero TA caches for FWCtx: 0x%08.8x (TPC addr: 0x%08x%08x, size: %d bytes)" }, + { ROGUE_FW_LOG_CREATESFID(23, ROGUE_FW_GROUP_HWR, 2), + "Recovery DM%u: Freelists reconstructed. New R-Flags=0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(24, ROGUE_FW_GROUP_HWR, 5), + "Recovery DM%u: FWCtx 0x%08x skipped to command @ %u. PR=%u. New R-Flags=0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(25, ROGUE_FW_GROUP_HWR, 1), + "Recovery DM%u: DM fully recovered" }, + { ROGUE_FW_LOG_CREATESFID(26, ROGUE_FW_GROUP_HWR, 2), + "DM%u: Hold scheduling due to R-Flag = 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(27, ROGUE_FW_GROUP_HWR, 0), + "Analysis: Need freelist reconstruction" }, + { ROGUE_FW_LOG_CREATESFID(28, ROGUE_FW_GROUP_HWR, 2), + "Analysis DM%u: Lockup FWCtx: 0x%08.8x. Need to skip to next command" }, + { ROGUE_FW_LOG_CREATESFID(29, ROGUE_FW_GROUP_HWR, 2), + "Analysis DM%u: Lockup while TA is OOM FWCtx: 0x%08.8x. Need to skip to next command" }, + { ROGUE_FW_LOG_CREATESFID(30, ROGUE_FW_GROUP_HWR, 2), + "Analysis DM%u: Lockup while partial render FWCtx: 0x%08.8x. Need PR cleanup" }, + { ROGUE_FW_LOG_CREATESFID(31, ROGUE_FW_GROUP_HWR, 0), + "GPU has locked up" }, + { ROGUE_FW_LOG_CREATESFID(32, ROGUE_FW_GROUP_HWR, 1), + "DM%u ready for HWR" }, + { ROGUE_FW_LOG_CREATESFID(33, ROGUE_FW_GROUP_HWR, 2), + "Recovery DM%u: Updated Recovery counter. New R-Flags=0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(34, ROGUE_FW_GROUP_HWR, 1), + "Analysis: BRN37729 detected, reset TA and re-kicked 0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(35, ROGUE_FW_GROUP_HWR, 1), + "DM%u timed out" }, + { ROGUE_FW_LOG_CREATESFID(36, ROGUE_FW_GROUP_HWR, 1), + "RGX_CR_EVENT_STATUS=0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(37, ROGUE_FW_GROUP_HWR, 2), + "DM%u lockup falsely detected, R-Flags=0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(38, ROGUE_FW_GROUP_HWR, 0), + "GPU has overrun its deadline" }, + { ROGUE_FW_LOG_CREATESFID(39, ROGUE_FW_GROUP_HWR, 0), + "GPU has failed a poll" }, + { ROGUE_FW_LOG_CREATESFID(40, ROGUE_FW_GROUP_HWR, 2), + "RGX DM%u phase count=0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(41, ROGUE_FW_GROUP_HWR, 2), + "Reset HW (loop:%d, poll failures: 0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(42, ROGUE_FW_GROUP_HWR, 1), + "MMU fault event: 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(43, ROGUE_FW_GROUP_HWR, 1), + "BIF1 page fault detected (Bank1 MMU Status: 0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(44, ROGUE_FW_GROUP_HWR, 1), + "Fast CRC Failed. Proceeding to full register checking (DM: %u)." }, + { ROGUE_FW_LOG_CREATESFID(45, ROGUE_FW_GROUP_HWR, 2), + "Meta MMU page fault detected (Meta MMU Status: 0x%08x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(46, ROGUE_FW_GROUP_HWR, 2), + "Fast CRC Check result for DM%u is HWRNeeded=%u" }, + { ROGUE_FW_LOG_CREATESFID(47, ROGUE_FW_GROUP_HWR, 2), + "Full Signature Check result for DM%u is HWRNeeded=%u" }, + { ROGUE_FW_LOG_CREATESFID(48, ROGUE_FW_GROUP_HWR, 3), + "Final result for DM%u is HWRNeeded=%u with HWRChecksToGo=%u" }, + { ROGUE_FW_LOG_CREATESFID(49, ROGUE_FW_GROUP_HWR, 3), + "USC Slots result for DM%u is HWRNeeded=%u USCSlotsUsedByDM=%d" }, + { ROGUE_FW_LOG_CREATESFID(50, ROGUE_FW_GROUP_HWR, 2), + "Deadline counter for DM%u is HWRDeadline=%u" }, + { ROGUE_FW_LOG_CREATESFID(51, ROGUE_FW_GROUP_HWR, 1), + "Holding Scheduling on OSid %u due to pending freelist reconstruction" }, + { ROGUE_FW_LOG_CREATESFID(52, ROGUE_FW_GROUP_HWR, 2), + "Requesting reconstruction for freelist 0x%x (ID=%d)" }, + { ROGUE_FW_LOG_CREATESFID(53, ROGUE_FW_GROUP_HWR, 1), + "Reconstruction of freelist ID=%d complete" }, + { ROGUE_FW_LOG_CREATESFID(54, ROGUE_FW_GROUP_HWR, 4), + "Reconstruction needed for freelist 0x%x (ID=%d) type: %d (0:local,1:global,2:mmu) on HW context %u" }, + { ROGUE_FW_LOG_CREATESFID(55, ROGUE_FW_GROUP_HWR, 1), + "Reconstruction of freelist ID=%d failed" }, + { ROGUE_FW_LOG_CREATESFID(56, ROGUE_FW_GROUP_HWR, 4), + "Restricting PDS Tasks to help other stalling DMs (RunningMask=0x%02x, StallingMask=0x%02x, PDS_CTRL=0x%08x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(57, ROGUE_FW_GROUP_HWR, 4), + "Unrestricting PDS Tasks again (RunningMask=0x%02x, StallingMask=0x%02x, PDS_CTRL=0x%08x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(58, ROGUE_FW_GROUP_HWR, 2), + "USC slots: %u used by DM%u" }, + { ROGUE_FW_LOG_CREATESFID(59, ROGUE_FW_GROUP_HWR, 1), + "USC slots: %u empty" }, + { ROGUE_FW_LOG_CREATESFID(60, ROGUE_FW_GROUP_HWR, 5), + "HCS DM%d's Context Switch failed to meet deadline. Current time: 0x%08x%08x, deadline: 0x%08x%08x" }, + { ROGUE_FW_LOG_CREATESFID(61, ROGUE_FW_GROUP_HWR, 1), + "Begin hardware reset (HWR Counter=%d)" }, + { ROGUE_FW_LOG_CREATESFID(62, ROGUE_FW_GROUP_HWR, 1), + "Finished hardware reset (HWR Counter=%d)" }, + { ROGUE_FW_LOG_CREATESFID(63, ROGUE_FW_GROUP_HWR, 2), + "Holding Scheduling on DM %u for OSid %u due to pending freelist reconstruction" }, + { ROGUE_FW_LOG_CREATESFID(64, ROGUE_FW_GROUP_HWR, 5), + "User Mode Queue ROff reset: FWCtx 0x%08.8x, queue: 0x%08x%08x (Roff = %u becomes StreamStartOffset = %u)" }, + { ROGUE_FW_LOG_CREATESFID(65, ROGUE_FW_GROUP_HWR, 4), + "Reconstruction needed for freelist 0x%x (ID=%d) type: %d (0:local,1:global) on HW context %u" }, + { ROGUE_FW_LOG_CREATESFID(66, ROGUE_FW_GROUP_HWR, 3), + "Mips page fault detected (BadVAddr: 0x%08x, EntryLo0: 0x%08x, EntryLo1: 0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(67, ROGUE_FW_GROUP_HWR, 1), + "At least one other DM is running okay so DM%u will get another chance" }, + { ROGUE_FW_LOG_CREATESFID(68, ROGUE_FW_GROUP_HWR, 2), + "Reconstructing in FW, FL: 0x%x (ID=%d)" }, + { ROGUE_FW_LOG_CREATESFID(69, ROGUE_FW_GROUP_HWR, 4), + "Zero RTC for FWCtx: 0x%08.8x (RTC addr: 0x%08x%08x, size: %d bytes)" }, + { ROGUE_FW_LOG_CREATESFID(70, ROGUE_FW_GROUP_HWR, 5), + "Reconstruction needed for freelist 0x%x (ID=%d) type: %d (0:local,1:global) phase: %d (0:TA, 1:3D) on HW context %u" }, + { ROGUE_FW_LOG_CREATESFID(71, ROGUE_FW_GROUP_HWR, 3), + "Start long HW poll %u (0-Unset 1-Set) for (reg:0x%08x val:0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(72, ROGUE_FW_GROUP_HWR, 1), + "End long HW poll (result=%d)" }, + { ROGUE_FW_LOG_CREATESFID(73, ROGUE_FW_GROUP_HWR, 3), + "DM%u has taken %d ticks and deadline is %d ticks" }, + { ROGUE_FW_LOG_CREATESFID(74, ROGUE_FW_GROUP_HWR, 5), + "USC Watchdog result for DM%u is HWRNeeded=%u Status=%u USCs={0x%x} with HWRChecksToGo=%u" }, + { ROGUE_FW_LOG_CREATESFID(75, ROGUE_FW_GROUP_HWR, 6), + "Reconstruction needed for freelist 0x%x (ID=%d) OSid: %d type: %d (0:local,1:global) phase: %d (0:TA, 1:3D) on HW context %u" }, + { ROGUE_FW_LOG_CREATESFID(76, ROGUE_FW_GROUP_HWR, 1), + "GPU-%u has locked up" }, + { ROGUE_FW_LOG_CREATESFID(77, ROGUE_FW_GROUP_HWR, 1), + "DM%u has locked up" }, + { ROGUE_FW_LOG_CREATESFID(78, ROGUE_FW_GROUP_HWR, 2), + "Core %d RGX_CR_EVENT_STATUS=0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(79, ROGUE_FW_GROUP_HWR, 2), + "RGX_CR_MULTICORE_EVENT_STATUS%u=0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(80, ROGUE_FW_GROUP_HWR, 5), + "BIF0 page fault detected (Core %d MMU Status: 0x%08x%08x Req Status: 0x%08x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(81, ROGUE_FW_GROUP_HWR, 3), + "MMU page fault detected (Core %d MMU Status: 0x%08x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(82, ROGUE_FW_GROUP_HWR, 4), + "MMU page fault detected (Core %d MMU Status: 0x%08x%08x 0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(83, ROGUE_FW_GROUP_HWR, 4), + "Reset HW (core:%d of %d, loop:%d, poll failures: 0x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(84, ROGUE_FW_GROUP_HWR, 3), + "Fast CRC Check result for Core%u, DM%u is HWRNeeded=%u" }, + { ROGUE_FW_LOG_CREATESFID(85, ROGUE_FW_GROUP_HWR, 3), + "Full Signature Check result for Core%u, DM%u is HWRNeeded=%u" }, + { ROGUE_FW_LOG_CREATESFID(86, ROGUE_FW_GROUP_HWR, 4), + "USC Slots result for Core%u, DM%u is HWRNeeded=%u USCSlotsUsedByDM=%d" }, + { ROGUE_FW_LOG_CREATESFID(87, ROGUE_FW_GROUP_HWR, 6), + "USC Watchdog result for Core%u DM%u is HWRNeeded=%u Status=%u USCs={0x%x} with HWRChecksToGo=%u" }, + { ROGUE_FW_LOG_CREATESFID(88, ROGUE_FW_GROUP_HWR, 3), + "RISC-V MMU page fault detected (FWCORE MMU Status 0x%08x Req Status 0x%08x%08x)" }, + { ROGUE_FW_LOG_CREATESFID(89, ROGUE_FW_GROUP_HWR, 2), + "TEXAS1_PFS poll failed on core %d with value 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(90, ROGUE_FW_GROUP_HWR, 2), + "BIF_PFS poll failed on core %d with value 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(91, ROGUE_FW_GROUP_HWR, 2), + "MMU_ABORT_PM_STATUS set poll failed on core %d with value 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(92, ROGUE_FW_GROUP_HWR, 2), + "MMU_ABORT_PM_STATUS unset poll failed on core %d with value 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(93, ROGUE_FW_GROUP_HWR, 2), + "MMU_CTRL_INVAL poll (all but fw) failed on core %d with value 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(94, ROGUE_FW_GROUP_HWR, 2), + "MMU_CTRL_INVAL poll (all) failed on core %d with value 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(95, ROGUE_FW_GROUP_HWR, 3), + "TEXAS%d_PFS poll failed on core %d with value 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(96, ROGUE_FW_GROUP_HWR, 3), + "Extra Registers Check result for Core%u, DM%u is HWRNeeded=%u" }, + { ROGUE_FW_LOG_CREATESFID(97, ROGUE_FW_GROUP_HWR, 1), + "FW attempted to write to read-only GPU address 0x%08x" }, + + { ROGUE_FW_LOG_CREATESFID(1, ROGUE_FW_GROUP_HWP, 2), + "Block 0x%x mapped to Config Idx %u" }, + { ROGUE_FW_LOG_CREATESFID(2, ROGUE_FW_GROUP_HWP, 1), + "Block 0x%x omitted from event - not enabled in HW" }, + { ROGUE_FW_LOG_CREATESFID(3, ROGUE_FW_GROUP_HWP, 1), + "Block 0x%x included in event - enabled in HW" }, + { ROGUE_FW_LOG_CREATESFID(4, ROGUE_FW_GROUP_HWP, 2), + "Select register state hi_0x%x lo_0x%x" }, + { ROGUE_FW_LOG_CREATESFID(5, ROGUE_FW_GROUP_HWP, 1), + "Counter stream block header word 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(6, ROGUE_FW_GROUP_HWP, 1), + "Counter register offset 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(7, ROGUE_FW_GROUP_HWP, 1), + "Block 0x%x config unset, skipping" }, + { ROGUE_FW_LOG_CREATESFID(8, ROGUE_FW_GROUP_HWP, 1), + "Accessing Indirect block 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(9, ROGUE_FW_GROUP_HWP, 1), + "Accessing Direct block 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(10, ROGUE_FW_GROUP_HWP, 1), + "Programmed counter select register at offset 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(11, ROGUE_FW_GROUP_HWP, 2), + "Block register offset 0x%x and value 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(12, ROGUE_FW_GROUP_HWP, 1), + "Reading config block from driver 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(13, ROGUE_FW_GROUP_HWP, 2), + "Reading block range 0x%x to 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(14, ROGUE_FW_GROUP_HWP, 1), + "Recording block 0x%x config from driver" }, + { ROGUE_FW_LOG_CREATESFID(15, ROGUE_FW_GROUP_HWP, 0), + "Finished reading config block from driver" }, + { ROGUE_FW_LOG_CREATESFID(16, ROGUE_FW_GROUP_HWP, 2), + "Custom Counter offset: 0x%x value: 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(17, ROGUE_FW_GROUP_HWP, 2), + "Select counter n:%u ID:0x%x" }, + { ROGUE_FW_LOG_CREATESFID(18, ROGUE_FW_GROUP_HWP, 3), + "The counter ID 0x%x is not allowed. The package [b:%u, n:%u] will be discarded" }, + { ROGUE_FW_LOG_CREATESFID(19, ROGUE_FW_GROUP_HWP, 1), + "Custom Counters filter status %d" }, + { ROGUE_FW_LOG_CREATESFID(20, ROGUE_FW_GROUP_HWP, 2), + "The Custom block %d is not allowed. Use only blocks lower than %d. The package will be discarded" }, + { ROGUE_FW_LOG_CREATESFID(21, ROGUE_FW_GROUP_HWP, 2), + "The package will be discarded because it contains %d counters IDs while the upper limit is %d" }, + { ROGUE_FW_LOG_CREATESFID(22, ROGUE_FW_GROUP_HWP, 2), + "Check Filter 0x%x is 0x%x ?" }, + { ROGUE_FW_LOG_CREATESFID(23, ROGUE_FW_GROUP_HWP, 1), + "The custom block %u is reset" }, + { ROGUE_FW_LOG_CREATESFID(24, ROGUE_FW_GROUP_HWP, 1), + "Encountered an invalid command (%d)" }, + { ROGUE_FW_LOG_CREATESFID(25, ROGUE_FW_GROUP_HWP, 2), + "HWPerf Queue is full, we will have to wait for space! (Roff = %u, Woff = %u)" }, + { ROGUE_FW_LOG_CREATESFID(26, ROGUE_FW_GROUP_HWP, 3), + "HWPerf Queue is fencing, we are waiting for Roff = %d (Roff = %u, Woff = %u)" }, + { ROGUE_FW_LOG_CREATESFID(27, ROGUE_FW_GROUP_HWP, 1), + "Custom Counter block: %d" }, + { ROGUE_FW_LOG_CREATESFID(28, ROGUE_FW_GROUP_HWP, 1), + "Block 0x%x ENABLED" }, + { ROGUE_FW_LOG_CREATESFID(29, ROGUE_FW_GROUP_HWP, 1), + "Block 0x%x DISABLED" }, + { ROGUE_FW_LOG_CREATESFID(30, ROGUE_FW_GROUP_HWP, 2), + "Accessing Indirect block 0x%x, instance %u" }, + { ROGUE_FW_LOG_CREATESFID(31, ROGUE_FW_GROUP_HWP, 2), + "Counter register 0x%x, Value 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(32, ROGUE_FW_GROUP_HWP, 1), + "Counters filter status %d" }, + { ROGUE_FW_LOG_CREATESFID(33, ROGUE_FW_GROUP_HWP, 2), + "Block 0x%x mapped to Ctl Idx %u" }, + { ROGUE_FW_LOG_CREATESFID(34, ROGUE_FW_GROUP_HWP, 0), + "Block(s) in use for workload estimation." }, + { ROGUE_FW_LOG_CREATESFID(35, ROGUE_FW_GROUP_HWP, 3), + "GPU %u Cycle counter 0x%x, Value 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(36, ROGUE_FW_GROUP_HWP, 3), + "GPU Mask 0x%x Cycle counter 0x%x, Value 0x%x" }, + { ROGUE_FW_LOG_CREATESFID(37, ROGUE_FW_GROUP_HWP, 1), + "Blocks IGNORED for GPU %u" }, + + { ROGUE_FW_LOG_CREATESFID(1, ROGUE_FW_GROUP_DMA, 5), + "Transfer 0x%02x request: 0x%02x%08x -> 0x%08x, size %u" }, + { ROGUE_FW_LOG_CREATESFID(2, ROGUE_FW_GROUP_DMA, 4), + "Transfer of type 0x%02x expected on channel %u, 0x%02x found, status %u" }, + { ROGUE_FW_LOG_CREATESFID(3, ROGUE_FW_GROUP_DMA, 1), + "DMA Interrupt register 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(4, ROGUE_FW_GROUP_DMA, 1), + "Waiting for transfer of type 0x%02x completion..." }, + { ROGUE_FW_LOG_CREATESFID(5, ROGUE_FW_GROUP_DMA, 3), + "Loading of cCCB data from FW common context 0x%08x (offset: %u, size: %u) failed" }, + { ROGUE_FW_LOG_CREATESFID(6, ROGUE_FW_GROUP_DMA, 3), + "Invalid load of cCCB data from FW common context 0x%08x (offset: %u, size: %u)" }, + { ROGUE_FW_LOG_CREATESFID(7, ROGUE_FW_GROUP_DMA, 1), + "Transfer 0x%02x request poll failure" }, + { ROGUE_FW_LOG_CREATESFID(8, ROGUE_FW_GROUP_DMA, 2), + "Boot transfer(s) failed (code? %u, data? %u), used slower memcpy instead" }, + { ROGUE_FW_LOG_CREATESFID(9, ROGUE_FW_GROUP_DMA, 7), + "Transfer 0x%02x request on ch. %u: system 0x%02x%08x, coremem 0x%08x, flags 0x%x, size %u" }, + + { ROGUE_FW_LOG_CREATESFID(1, ROGUE_FW_GROUP_DBG, 2), + "0x%08x 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(2, ROGUE_FW_GROUP_DBG, 1), + "0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(3, ROGUE_FW_GROUP_DBG, 2), + "0x%08x 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(4, ROGUE_FW_GROUP_DBG, 3), + "0x%08x 0x%08x 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(5, ROGUE_FW_GROUP_DBG, 4), + "0x%08x 0x%08x 0x%08x 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(6, ROGUE_FW_GROUP_DBG, 5), + "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(7, ROGUE_FW_GROUP_DBG, 6), + "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(8, ROGUE_FW_GROUP_DBG, 7), + "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(9, ROGUE_FW_GROUP_DBG, 8), + "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x" }, + { ROGUE_FW_LOG_CREATESFID(10, ROGUE_FW_GROUP_DBG, 1), + "%d" }, + { ROGUE_FW_LOG_CREATESFID(11, ROGUE_FW_GROUP_DBG, 2), + "%d %d" }, + { ROGUE_FW_LOG_CREATESFID(12, ROGUE_FW_GROUP_DBG, 3), + "%d %d %d" }, + { ROGUE_FW_LOG_CREATESFID(13, ROGUE_FW_GROUP_DBG, 4), + "%d %d %d %d" }, + { ROGUE_FW_LOG_CREATESFID(14, ROGUE_FW_GROUP_DBG, 5), + "%d %d %d %d %d" }, + { ROGUE_FW_LOG_CREATESFID(15, ROGUE_FW_GROUP_DBG, 6), + "%d %d %d %d %d %d" }, + { ROGUE_FW_LOG_CREATESFID(16, ROGUE_FW_GROUP_DBG, 7), + "%d %d %d %d %d %d %d" }, + { ROGUE_FW_LOG_CREATESFID(17, ROGUE_FW_GROUP_DBG, 8), + "%d %d %d %d %d %d %d %d" }, + { ROGUE_FW_LOG_CREATESFID(18, ROGUE_FW_GROUP_DBG, 1), + "%u" }, + { ROGUE_FW_LOG_CREATESFID(19, ROGUE_FW_GROUP_DBG, 2), + "%u %u" }, + { ROGUE_FW_LOG_CREATESFID(20, ROGUE_FW_GROUP_DBG, 3), + "%u %u %u" }, + { ROGUE_FW_LOG_CREATESFID(21, ROGUE_FW_GROUP_DBG, 4), + "%u %u %u %u" }, + { ROGUE_FW_LOG_CREATESFID(22, ROGUE_FW_GROUP_DBG, 5), + "%u %u %u %u %u" }, + { ROGUE_FW_LOG_CREATESFID(23, ROGUE_FW_GROUP_DBG, 6), + "%u %u %u %u %u %u" }, + { ROGUE_FW_LOG_CREATESFID(24, ROGUE_FW_GROUP_DBG, 7), + "%u %u %u %u %u %u %u" }, + { ROGUE_FW_LOG_CREATESFID(25, ROGUE_FW_GROUP_DBG, 8), + "%u %u %u %u %u %u %u %u" }, + + { ROGUE_FW_LOG_CREATESFID(65535, ROGUE_FW_GROUP_NULL, 15), + "You should not use this string" }, +}; + +#define ROGUE_FW_SF_FIRST ROGUE_FW_LOG_CREATESFID(0, ROGUE_FW_GROUP_NULL, 0) +#define ROGUE_FW_SF_MAIN_ASSERT_FAILED ROGUE_FW_LOG_CREATESFID(24, ROGUE_FW_GROUP_MAIN, 1) +#define ROGUE_FW_SF_LAST ROGUE_FW_LOG_CREATESFID(65535, ROGUE_FW_GROUP_NULL, 15) + +#endif /* PVR_ROGUE_FWIF_SF_H */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h new file mode 100644 index 00000000000000..6c09c15bf9bd8d --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared.h @@ -0,0 +1,258 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_ROGUE_FWIF_SHARED_H +#define PVR_ROGUE_FWIF_SHARED_H + +#include +#include + +#define ROGUE_FWIF_NUM_RTDATAS 2U +#define ROGUE_FWIF_NUM_GEOMDATAS 1U +#define ROGUE_FWIF_NUM_RTDATA_FREELISTS 2U +#define ROGUE_NUM_GEOM_CORES 1U + +#define ROGUE_NUM_GEOM_CORES_SIZE 2U + +/* + * Maximum number of UFOs in a CCB command. + * The number is based on having 32 sync prims (as originally), plus 32 sync + * checkpoints. + * Once the use of sync prims is no longer supported, we will retain + * the same total (64) as the number of sync checkpoints which may be + * supporting a fence is not visible to the client driver and has to + * allow for the number of different timelines involved in fence merges. + */ +#define ROGUE_FWIF_CCB_CMD_MAX_UFOS (32U + 32U) + +/* + * This is a generic limit imposed on any DM (GEOMETRY,FRAGMENT,CDM,TDM,2D,TRANSFER) + * command passed through the bridge. + * Just across the bridge in the server, any incoming kick command size is + * checked against this maximum limit. + * In case the incoming command size is larger than the specified limit, + * the bridge call is retired with error. + */ +#define ROGUE_FWIF_DM_INDEPENDENT_KICK_CMD_SIZE (1024U) + +#define ROGUE_FWIF_PRBUFFER_START (0) +#define ROGUE_FWIF_PRBUFFER_ZSBUFFER (0) +#define ROGUE_FWIF_PRBUFFER_MSAABUFFER (1) +#define ROGUE_FWIF_PRBUFFER_MAXSUPPORTED (2) + +struct rogue_fwif_dma_addr { + aligned_u64 dev_addr; + u32 fw_addr; + u32 padding; +} __aligned(8); + +struct rogue_fwif_ufo { + u32 addr; + u32 value; +}; + +#define ROGUE_FWIF_UFO_ADDR_IS_SYNC_CHECKPOINT (1) + +struct rogue_fwif_sync_checkpoint { + u32 state; + u32 fw_ref_count; +}; + +struct rogue_fwif_cleanup_ctl { + /* Number of commands received by the FW */ + u32 submitted_commands; + /* Number of commands executed by the FW */ + u32 executed_commands; +} __aligned(8); + +/* + * Used to share frame numbers across UM-KM-FW, + * frame number is set in UM, + * frame number is required in both KM for HTB and FW for FW trace. + * + * May be used to house Kick flags in the future. + */ +struct rogue_fwif_cmd_common { + /* associated frame number */ + u32 frame_num; +}; + +/* + * Geometry and fragment commands require set of firmware addresses that are stored in the Kernel. + * Client has handle(s) to Kernel containers storing these addresses, instead of raw addresses. We + * have to patch/write these addresses in KM to prevent UM from controlling FW addresses directly. + * Typedefs for geometry and fragment commands are shared between Client and Firmware (both + * single-BVNC). Kernel is implemented in a multi-BVNC manner, so it can't use geometry|fragment + * CMD type definitions directly. Therefore we have a SHARED block that is shared between UM-KM-FW + * across all BVNC configurations. + */ +struct rogue_fwif_cmd_geom_frag_shared { + /* Common command attributes */ + struct rogue_fwif_cmd_common cmn; + + /* + * RTData associated with this command, this is used for context + * selection and for storing out HW-context, when TA is switched out for + * continuing later + */ + u32 hwrt_data_fw_addr; + + /* Supported PR Buffers like Z/S/MSAA Scratch */ + u32 pr_buffer_fw_addr[ROGUE_FWIF_PRBUFFER_MAXSUPPORTED]; +}; + +/* + * Client Circular Command Buffer (CCCB) control structure. + * This is shared between the Server and the Firmware and holds byte offsets + * into the CCCB as well as the wrapping mask to aid wrap around. A given + * snapshot of this queue with Cmd 1 running on the GPU might be: + * + * Roff Doff Woff + * [..........|-1----------|=2===|=3===|=4===|~5~~~~|~6~~~~|~7~~~~|..........] + * < runnable commands >< !ready to run > + * + * Cmd 1 : Currently executing on the GPU data master. + * Cmd 2,3,4: Fence dependencies met, commands runnable. + * Cmd 5... : Fence dependency not met yet. + */ +struct rogue_fwif_cccb_ctl { + /* Host write offset into CCB. This must be aligned to 16 bytes. */ + u32 write_offset; + /* + * Firmware read offset into CCB. Points to the command that is runnable + * on GPU, if R!=W + */ + u32 read_offset; + /* + * Firmware fence dependency offset. Points to commands not ready, i.e. + * fence dependencies are not met. + */ + u32 dep_offset; + /* Offset wrapping mask, total capacity in bytes of the CCB-1 */ + u32 wrap_mask; + + /* Only used if SUPPORT_AGP is present. */ + u32 read_offset2; + + /* Only used if SUPPORT_AGP4 is present. */ + u32 read_offset3; + /* Only used if SUPPORT_AGP4 is present. */ + u32 read_offset4; + + u32 padding; +} __aligned(8); + +#define ROGUE_FW_LOCAL_FREELIST (0) +#define ROGUE_FW_GLOBAL_FREELIST (1) +#define ROGUE_FW_FREELIST_TYPE_LAST ROGUE_FW_GLOBAL_FREELIST +#define ROGUE_FW_MAX_FREELISTS (ROGUE_FW_FREELIST_TYPE_LAST + 1U) + +struct rogue_fwif_geom_registers_caswitch { + u64 geom_reg_vdm_context_state_base_addr; + u64 geom_reg_vdm_context_state_resume_addr; + u64 geom_reg_ta_context_state_base_addr; + + struct { + u64 geom_reg_vdm_context_store_task0; + u64 geom_reg_vdm_context_store_task1; + u64 geom_reg_vdm_context_store_task2; + + /* VDM resume state update controls */ + u64 geom_reg_vdm_context_resume_task0; + u64 geom_reg_vdm_context_resume_task1; + u64 geom_reg_vdm_context_resume_task2; + + u64 geom_reg_vdm_context_store_task3; + u64 geom_reg_vdm_context_store_task4; + + u64 geom_reg_vdm_context_resume_task3; + u64 geom_reg_vdm_context_resume_task4; + } geom_state[2]; +}; + +#define ROGUE_FWIF_GEOM_REGISTERS_CSWITCH_SIZE \ + sizeof(struct rogue_fwif_geom_registers_caswitch) + +struct rogue_fwif_cdm_registers_cswitch { + u64 cdmreg_cdm_context_pds0; + u64 cdmreg_cdm_context_pds1; + u64 cdmreg_cdm_terminate_pds; + u64 cdmreg_cdm_terminate_pds1; + + /* CDM resume controls */ + u64 cdmreg_cdm_resume_pds0; + u64 cdmreg_cdm_context_pds0_b; + u64 cdmreg_cdm_resume_pds0_b; +}; + +struct rogue_fwif_static_rendercontext_state { + /* Geom registers for ctx switch */ + struct rogue_fwif_geom_registers_caswitch ctxswitch_regs[ROGUE_NUM_GEOM_CORES_SIZE] + __aligned(8); +}; + +#define ROGUE_FWIF_STATIC_RENDERCONTEXT_SIZE \ + sizeof(struct rogue_fwif_static_rendercontext_state) + +struct rogue_fwif_static_computecontext_state { + /* CDM registers for ctx switch */ + struct rogue_fwif_cdm_registers_cswitch ctxswitch_regs __aligned(8); +}; + +#define ROGUE_FWIF_STATIC_COMPUTECONTEXT_SIZE \ + sizeof(struct rogue_fwif_static_computecontext_state) + +enum rogue_fwif_prbuffer_state { + ROGUE_FWIF_PRBUFFER_UNBACKED = 0, + ROGUE_FWIF_PRBUFFER_BACKED, + ROGUE_FWIF_PRBUFFER_BACKING_PENDING, + ROGUE_FWIF_PRBUFFER_UNBACKING_PENDING, +}; + +struct rogue_fwif_prbuffer { + /* Buffer ID*/ + u32 buffer_id; + /* Needs On-demand Z/S/MSAA Buffer allocation */ + bool on_demand __aligned(4); + /* Z/S/MSAA -Buffer state */ + enum rogue_fwif_prbuffer_state state; + /* Cleanup state */ + struct rogue_fwif_cleanup_ctl cleanup_sate; + /* Compatibility and other flags */ + u32 prbuffer_flags; +} __aligned(8); + +/* Last reset reason for a context. */ +enum rogue_context_reset_reason { + /* No reset reason recorded */ + ROGUE_CONTEXT_RESET_REASON_NONE = 0, + /* Caused a reset due to locking up */ + ROGUE_CONTEXT_RESET_REASON_GUILTY_LOCKUP = 1, + /* Affected by another context locking up */ + ROGUE_CONTEXT_RESET_REASON_INNOCENT_LOCKUP = 2, + /* Overran the global deadline */ + ROGUE_CONTEXT_RESET_REASON_GUILTY_OVERRUNING = 3, + /* Affected by another context overrunning */ + ROGUE_CONTEXT_RESET_REASON_INNOCENT_OVERRUNING = 4, + /* Forced reset to ensure scheduling requirements */ + ROGUE_CONTEXT_RESET_REASON_HARD_CONTEXT_SWITCH = 5, + /* FW Safety watchdog triggered */ + ROGUE_CONTEXT_RESET_REASON_FW_WATCHDOG = 12, + /* FW page fault (no HWR) */ + ROGUE_CONTEXT_RESET_REASON_FW_PAGEFAULT = 13, + /* FW execution error (GPU reset requested) */ + ROGUE_CONTEXT_RESET_REASON_FW_EXEC_ERR = 14, + /* Host watchdog detected FW error */ + ROGUE_CONTEXT_RESET_REASON_HOST_WDG_FW_ERR = 15, + /* Geometry DM OOM event is not allowed */ + ROGUE_CONTEXT_GEOM_OOM_DISABLED = 16, +}; + +struct rogue_context_reset_reason_data { + enum rogue_context_reset_reason reset_reason; + u32 reset_ext_job_ref; +}; + +#include "pvr_rogue_fwif_shared_check.h" + +#endif /* PVR_ROGUE_FWIF_SHARED_H */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared_check.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared_check.h new file mode 100644 index 00000000000000..597ed54bbd3af5 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif_shared_check.h @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_ROGUE_FWIF_SHARED_CHECK_H +#define PVR_ROGUE_FWIF_SHARED_CHECK_H + +#include + +#define OFFSET_CHECK(type, member, offset) \ + static_assert(offsetof(type, member) == (offset), \ + "offsetof(" #type ", " #member ") incorrect") + +#define SIZE_CHECK(type, size) \ + static_assert(sizeof(type) == (size), #type " is incorrect size") + +OFFSET_CHECK(struct rogue_fwif_dma_addr, dev_addr, 0); +OFFSET_CHECK(struct rogue_fwif_dma_addr, fw_addr, 8); +SIZE_CHECK(struct rogue_fwif_dma_addr, 16); + +OFFSET_CHECK(struct rogue_fwif_ufo, addr, 0); +OFFSET_CHECK(struct rogue_fwif_ufo, value, 4); +SIZE_CHECK(struct rogue_fwif_ufo, 8); + +OFFSET_CHECK(struct rogue_fwif_cleanup_ctl, submitted_commands, 0); +OFFSET_CHECK(struct rogue_fwif_cleanup_ctl, executed_commands, 4); +SIZE_CHECK(struct rogue_fwif_cleanup_ctl, 8); + +OFFSET_CHECK(struct rogue_fwif_cccb_ctl, write_offset, 0); +OFFSET_CHECK(struct rogue_fwif_cccb_ctl, read_offset, 4); +OFFSET_CHECK(struct rogue_fwif_cccb_ctl, dep_offset, 8); +OFFSET_CHECK(struct rogue_fwif_cccb_ctl, wrap_mask, 12); +OFFSET_CHECK(struct rogue_fwif_cccb_ctl, read_offset2, 16); +OFFSET_CHECK(struct rogue_fwif_cccb_ctl, read_offset3, 20); +OFFSET_CHECK(struct rogue_fwif_cccb_ctl, read_offset4, 24); +SIZE_CHECK(struct rogue_fwif_cccb_ctl, 32); + +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_reg_vdm_context_state_base_addr, 0); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_reg_vdm_context_state_resume_addr, 8); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_reg_ta_context_state_base_addr, 16); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_store_task0, 24); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_store_task1, 32); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_store_task2, 40); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_resume_task0, 48); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_resume_task1, 56); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_resume_task2, 64); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_store_task3, 72); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_store_task4, 80); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_resume_task3, 88); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_resume_task4, 96); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_store_task0, 104); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_store_task1, 112); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_store_task2, 120); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_resume_task0, 128); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_resume_task1, 136); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_resume_task2, 144); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_store_task3, 152); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_store_task4, 160); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_resume_task3, 168); +OFFSET_CHECK(struct rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_resume_task4, 176); +SIZE_CHECK(struct rogue_fwif_geom_registers_caswitch, 184); + +OFFSET_CHECK(struct rogue_fwif_cdm_registers_cswitch, cdmreg_cdm_context_pds0, 0); +OFFSET_CHECK(struct rogue_fwif_cdm_registers_cswitch, cdmreg_cdm_context_pds1, 8); +OFFSET_CHECK(struct rogue_fwif_cdm_registers_cswitch, cdmreg_cdm_terminate_pds, 16); +OFFSET_CHECK(struct rogue_fwif_cdm_registers_cswitch, cdmreg_cdm_terminate_pds1, 24); +OFFSET_CHECK(struct rogue_fwif_cdm_registers_cswitch, cdmreg_cdm_resume_pds0, 32); +OFFSET_CHECK(struct rogue_fwif_cdm_registers_cswitch, cdmreg_cdm_context_pds0_b, 40); +OFFSET_CHECK(struct rogue_fwif_cdm_registers_cswitch, cdmreg_cdm_resume_pds0_b, 48); +SIZE_CHECK(struct rogue_fwif_cdm_registers_cswitch, 56); + +OFFSET_CHECK(struct rogue_fwif_static_rendercontext_state, ctxswitch_regs, 0); +SIZE_CHECK(struct rogue_fwif_static_rendercontext_state, 368); + +OFFSET_CHECK(struct rogue_fwif_static_computecontext_state, ctxswitch_regs, 0); +SIZE_CHECK(struct rogue_fwif_static_computecontext_state, 56); + +OFFSET_CHECK(struct rogue_fwif_cmd_common, frame_num, 0); +SIZE_CHECK(struct rogue_fwif_cmd_common, 4); + +OFFSET_CHECK(struct rogue_fwif_cmd_geom_frag_shared, cmn, 0); +OFFSET_CHECK(struct rogue_fwif_cmd_geom_frag_shared, hwrt_data_fw_addr, 4); +OFFSET_CHECK(struct rogue_fwif_cmd_geom_frag_shared, pr_buffer_fw_addr, 8); +SIZE_CHECK(struct rogue_fwif_cmd_geom_frag_shared, 16); + +#endif /* PVR_ROGUE_FWIF_SHARED_CHECK_H */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_fwif_stream.h b/drivers/gpu/drm/imagination/pvr_rogue_fwif_stream.h new file mode 100644 index 00000000000000..1c2c4ebedc2575 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_fwif_stream.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_ROGUE_FWIF_STREAM_H +#define PVR_ROGUE_FWIF_STREAM_H + +/** + * DOC: Streams + * + * Commands are submitted to the kernel driver in the form of streams. + * + * A command stream has the following layout : + * - A 64-bit header containing: + * * A u32 containing the length of the main stream inclusive of the length of the header. + * * A u32 for padding. + * - The main stream data. + * - The extension stream (optional), which is composed of: + * * One or more headers. + * * The extension stream data, corresponding to the extension headers. + * + * The main stream provides the base command data. This has a fixed layout based on the features + * supported by a given GPU. + * + * The extension stream provides the command parameters that are required for BRNs & ERNs for the + * current GPU. This stream is comprised of one or more headers, followed by data for each given + * BRN/ERN. + * + * Each header is a u32 containing a bitmask of quirks & enhancements in the extension stream, a + * "type" field determining the set of quirks & enhancements the bitmask represents, and a + * continuation bit determining whether any more headers are present. The headers are then followed + * by command data; this is specific to each quirk/enhancement. All unused / reserved bits in the + * header must be set to 0. + * + * All parameters and headers in the main and extension streams must be naturally aligned. + * + * If a parameter appears in both the main and extension streams, then the extension parameter is + * used. + */ + +/* + * Stream extension header definition + */ +#define PVR_STREAM_EXTHDR_TYPE_SHIFT 29U +#define PVR_STREAM_EXTHDR_TYPE_MASK (7U << PVR_STREAM_EXTHDR_TYPE_SHIFT) +#define PVR_STREAM_EXTHDR_TYPE_MAX 8U +#define PVR_STREAM_EXTHDR_CONTINUATION BIT(28U) + +#define PVR_STREAM_EXTHDR_DATA_MASK ~(PVR_STREAM_EXTHDR_TYPE_MASK | PVR_STREAM_EXTHDR_CONTINUATION) + +/* + * Stream extension header - Geometry 0 + */ +#define PVR_STREAM_EXTHDR_TYPE_GEOM0 0U + +#define PVR_STREAM_EXTHDR_GEOM0_BRN49927 BIT(0U) + +#define PVR_STREAM_EXTHDR_GEOM0_VALID PVR_STREAM_EXTHDR_GEOM0_BRN49927 + +/* + * Stream extension header - Fragment 0 + */ +#define PVR_STREAM_EXTHDR_TYPE_FRAG0 0U + +#define PVR_STREAM_EXTHDR_FRAG0_BRN47217 BIT(0U) +#define PVR_STREAM_EXTHDR_FRAG0_BRN49927 BIT(1U) + +#define PVR_STREAM_EXTHDR_FRAG0_VALID PVR_STREAM_EXTHDR_FRAG0_BRN49927 + +/* + * Stream extension header - Compute 0 + */ +#define PVR_STREAM_EXTHDR_TYPE_COMPUTE0 0U + +#define PVR_STREAM_EXTHDR_COMPUTE0_BRN49927 BIT(0U) + +#define PVR_STREAM_EXTHDR_COMPUTE0_VALID PVR_STREAM_EXTHDR_COMPUTE0_BRN49927 + +#endif /* PVR_ROGUE_FWIF_STREAM_H */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_heap_config.h b/drivers/gpu/drm/imagination/pvr_rogue_heap_config.h new file mode 100644 index 00000000000000..68476600670337 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_heap_config.h @@ -0,0 +1,113 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_ROGUE_HEAP_CONFIG_H +#define PVR_ROGUE_HEAP_CONFIG_H + +#include + +/* + * ROGUE Device Virtual Address Space Definitions + * + * This file defines the ROGUE virtual address heaps that are used in + * application memory contexts. It also shows where the Firmware memory heap + * fits into this, but the firmware heap is only ever created in the + * kernel driver and never exposed to userspace. + * + * ROGUE_PDSCODEDATA_HEAP_BASE and ROGUE_USCCODE_HEAP_BASE will be programmed, + * on a global basis, into ROGUE_CR_PDS_EXEC_BASE and ROGUE_CR_USC_CODE_BASE_* + * respectively. Therefore if client drivers use multiple configs they must + * still be consistent with their definitions for these heaps. + * + * Base addresses have to be a multiple of 4MiB. + * Heaps must not start at 0x0000000000, as this is reserved for internal + * use within the driver. + * Range comments, those starting in column 0 below are a section heading of + * sorts and are above the heaps in that range. Often this is the reserved + * size of the heap within the range. + */ + +/* 0x00_0000_0000 ************************************************************/ + +/* 0x00_0000_0000 - 0x00_0040_0000 */ +/* 0 MiB to 4 MiB, size of 4 MiB : RESERVED */ + +/* 0x00_0040_0000 - 0x7F_FFC0_0000 **/ +/* 4 MiB to 512 GiB, size of 512 GiB less 4 MiB : RESERVED **/ + +/* 0x80_0000_0000 ************************************************************/ + +/* 0x80_0000_0000 - 0x9F_FFFF_FFFF **/ +/* 512 GiB to 640 GiB, size of 128 GiB : GENERAL_HEAP **/ +#define ROGUE_GENERAL_HEAP_BASE 0x8000000000ull +#define ROGUE_GENERAL_HEAP_SIZE SZ_128G + +/* 0xA0_0000_0000 - 0xAF_FFFF_FFFF */ +/* 640 GiB to 704 GiB, size of 64 GiB : FREE */ + +/* B0_0000_0000 - 0xB7_FFFF_FFFF */ +/* 704 GiB to 736 GiB, size of 32 GiB : FREE */ + +/* 0xB8_0000_0000 - 0xBF_FFFF_FFFF */ +/* 736 GiB to 768 GiB, size of 32 GiB : RESERVED */ + +/* 0xC0_0000_0000 ************************************************************/ + +/* 0xC0_0000_0000 - 0xD9_FFFF_FFFF */ +/* 768 GiB to 872 GiB, size of 104 GiB : FREE */ + +/* 0xDA_0000_0000 - 0xDA_FFFF_FFFF */ +/* 872 GiB to 876 GiB, size of 4 GiB : PDSCODEDATA_HEAP */ +#define ROGUE_PDSCODEDATA_HEAP_BASE 0xDA00000000ull +#define ROGUE_PDSCODEDATA_HEAP_SIZE SZ_4G + +/* 0xDB_0000_0000 - 0xDB_FFFF_FFFF */ +/* 876 GiB to 880 GiB, size of 256 MiB (reserved 4GiB) : BRN **/ +/* + * The BRN63142 quirk workaround requires Region Header memory to be at the top + * of a 16GiB aligned range. This is so when masked with 0x03FFFFFFFF the + * address will avoid aliasing PB addresses. Start at 879.75GiB. Size of 256MiB. + */ +#define ROGUE_RGNHDR_HEAP_BASE 0xDBF0000000ull +#define ROGUE_RGNHDR_HEAP_SIZE SZ_256M + +/* 0xDC_0000_0000 - 0xDF_FFFF_FFFF */ +/* 880 GiB to 896 GiB, size of 16 GiB : FREE */ + +/* 0xE0_0000_0000 - 0xE0_FFFF_FFFF */ +/* 896 GiB to 900 GiB, size of 4 GiB : USCCODE_HEAP */ +#define ROGUE_USCCODE_HEAP_BASE 0xE000000000ull +#define ROGUE_USCCODE_HEAP_SIZE SZ_4G + +/* 0xE1_0000_0000 - 0xE1_BFFF_FFFF */ +/* 900 GiB to 903 GiB, size of 3 GiB : RESERVED */ + +/* 0xE1_C000_000 - 0xE1_FFFF_FFFF */ +/* 903 GiB to 904 GiB, reserved 1 GiB, : FIRMWARE_HEAP */ +#define ROGUE_FW_HEAP_BASE 0xE1C0000000ull + +/* 0xE2_0000_0000 - 0xE3_FFFF_FFFF */ +/* 904 GiB to 912 GiB, size of 8 GiB : FREE */ + +/* 0xE4_0000_0000 - 0xE7_FFFF_FFFF */ +/* 912 GiB to 968 GiB, size of 16 GiB : TRANSFER_FRAG */ +#define ROGUE_TRANSFER_FRAG_HEAP_BASE 0xE400000000ull +#define ROGUE_TRANSFER_FRAG_HEAP_SIZE SZ_16G + +/* 0xE8_0000_0000 - 0xF1_FFFF_FFFF */ +/* 928 GiB to 968 GiB, size of 40 GiB : RESERVED */ + +/* 0xF2_0000_0000 - 0xF2_001F_FFFF **/ +/* 968 GiB to 969 GiB, size of 2 MiB : VISTEST_HEAP */ +#define ROGUE_VISTEST_HEAP_BASE 0xF200000000ull +#define ROGUE_VISTEST_HEAP_SIZE SZ_2M + +/* 0xF2_4000_0000 - 0xF2_FFFF_FFFF */ +/* 969 GiB to 972 GiB, size of 3 GiB : FREE */ + +/* 0xF3_0000_0000 - 0xFF_FFFF_FFFF */ +/* 972 GiB to 1024 GiB, size of 52 GiB : FREE */ + +/* 0xFF_FFFF_FFFF ************************************************************/ + +#endif /* PVR_ROGUE_HEAP_CONFIG_H */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_meta.h b/drivers/gpu/drm/imagination/pvr_rogue_meta.h new file mode 100644 index 00000000000000..3020e6582daab4 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_meta.h @@ -0,0 +1,356 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_ROGUE_META_H +#define PVR_ROGUE_META_H + +/***** The META HW register definitions in the file are updated manually *****/ + +#include +#include + +/* + ****************************************************************************** + * META registers and MACROS + ***************************************************************************** + */ +#define META_CR_CTRLREG_BASE(t) (0x04800000U + (0x1000U * (t))) + +#define META_CR_TXPRIVEXT (0x048000E8) +#define META_CR_TXPRIVEXT_MINIM_EN BIT(7) + +#define META_CR_SYSC_JTAG_THREAD (0x04830030) +#define META_CR_SYSC_JTAG_THREAD_PRIV_EN (0x00000004) + +#define META_CR_PERF_COUNT0 (0x0480FFE0) +#define META_CR_PERF_COUNT1 (0x0480FFE8) +#define META_CR_PERF_COUNT_CTRL_SHIFT (28) +#define META_CR_PERF_COUNT_CTRL_MASK (0xF0000000) +#define META_CR_PERF_COUNT_CTRL_DCACHEHITS (8 << META_CR_PERF_COUNT_CTRL_SHIFT) +#define META_CR_PERF_COUNT_CTRL_ICACHEHITS (9 << META_CR_PERF_COUNT_CTRL_SHIFT) +#define META_CR_PERF_COUNT_CTRL_ICACHEMISS \ + (0xA << META_CR_PERF_COUNT_CTRL_SHIFT) +#define META_CR_PERF_COUNT_CTRL_ICORE (0xD << META_CR_PERF_COUNT_CTRL_SHIFT) +#define META_CR_PERF_COUNT_THR_SHIFT (24) +#define META_CR_PERF_COUNT_THR_MASK (0x0F000000) +#define META_CR_PERF_COUNT_THR_0 (0x1 << META_CR_PERF_COUNT_THR_SHIFT) +#define META_CR_PERF_COUNT_THR_1 (0x2 << META_CR_PERF_COUNT_THR_1) + +#define META_CR_TxVECINT_BHALT (0x04820500) +#define META_CR_PERF_ICORE0 (0x0480FFD0) +#define META_CR_PERF_ICORE1 (0x0480FFD8) +#define META_CR_PERF_ICORE_DCACHEMISS (0x8) + +#define META_CR_PERF_COUNT(ctrl, thr) \ + ((META_CR_PERF_COUNT_CTRL_##ctrl << META_CR_PERF_COUNT_CTRL_SHIFT) | \ + ((thr) << META_CR_PERF_COUNT_THR_SHIFT)) + +#define META_CR_TXUXXRXDT_OFFSET (META_CR_CTRLREG_BASE(0U) + 0x0000FFF0U) +#define META_CR_TXUXXRXRQ_OFFSET (META_CR_CTRLREG_BASE(0U) + 0x0000FFF8U) + +/* Poll for done. */ +#define META_CR_TXUXXRXRQ_DREADY_BIT (0x80000000U) +/* Set for read. */ +#define META_CR_TXUXXRXRQ_RDnWR_BIT (0x00010000U) +#define META_CR_TXUXXRXRQ_TX_S (12) +#define META_CR_TXUXXRXRQ_RX_S (4) +#define META_CR_TXUXXRXRQ_UXX_S (0) + +/* Internal ctrl regs. */ +#define META_CR_TXUIN_ID (0x0) +/* Data unit regs. */ +#define META_CR_TXUD0_ID (0x1) +/* Data unit regs. */ +#define META_CR_TXUD1_ID (0x2) +/* Address unit regs. */ +#define META_CR_TXUA0_ID (0x3) +/* Address unit regs. */ +#define META_CR_TXUA1_ID (0x4) +/* PC registers. */ +#define META_CR_TXUPC_ID (0x5) + +/* Macros to calculate register access values. */ +#define META_CR_CORE_REG(thr, reg_num, unit) \ + (((u32)(thr) << META_CR_TXUXXRXRQ_TX_S) | \ + ((u32)(reg_num) << META_CR_TXUXXRXRQ_RX_S) | \ + ((u32)(unit) << META_CR_TXUXXRXRQ_UXX_S)) + +#define META_CR_THR0_PC META_CR_CORE_REG(0, 0, META_CR_TXUPC_ID) +#define META_CR_THR0_PCX META_CR_CORE_REG(0, 1, META_CR_TXUPC_ID) +#define META_CR_THR0_SP META_CR_CORE_REG(0, 0, META_CR_TXUA0_ID) + +#define META_CR_THR1_PC META_CR_CORE_REG(1, 0, META_CR_TXUPC_ID) +#define META_CR_THR1_PCX META_CR_CORE_REG(1, 1, META_CR_TXUPC_ID) +#define META_CR_THR1_SP META_CR_CORE_REG(1, 0, META_CR_TXUA0_ID) + +#define SP_ACCESS(thread) META_CR_CORE_REG(thread, 0, META_CR_TXUA0_ID) +#define PC_ACCESS(thread) META_CR_CORE_REG(thread, 0, META_CR_TXUPC_ID) + +#define META_CR_COREREG_ENABLE (0x0000000U) +#define META_CR_COREREG_STATUS (0x0000010U) +#define META_CR_COREREG_DEFR (0x00000A0U) +#define META_CR_COREREG_PRIVEXT (0x00000E8U) + +#define META_CR_T0ENABLE_OFFSET \ + (META_CR_CTRLREG_BASE(0U) + META_CR_COREREG_ENABLE) +#define META_CR_T0STATUS_OFFSET \ + (META_CR_CTRLREG_BASE(0U) + META_CR_COREREG_STATUS) +#define META_CR_T0DEFR_OFFSET (META_CR_CTRLREG_BASE(0U) + META_CR_COREREG_DEFR) +#define META_CR_T0PRIVEXT_OFFSET \ + (META_CR_CTRLREG_BASE(0U) + META_CR_COREREG_PRIVEXT) + +#define META_CR_T1ENABLE_OFFSET \ + (META_CR_CTRLREG_BASE(1U) + META_CR_COREREG_ENABLE) +#define META_CR_T1STATUS_OFFSET \ + (META_CR_CTRLREG_BASE(1U) + META_CR_COREREG_STATUS) +#define META_CR_T1DEFR_OFFSET (META_CR_CTRLREG_BASE(1U) + META_CR_COREREG_DEFR) +#define META_CR_T1PRIVEXT_OFFSET \ + (META_CR_CTRLREG_BASE(1U) + META_CR_COREREG_PRIVEXT) + +#define META_CR_TXENABLE_ENABLE_BIT (0x00000001U) /* Set if running */ +#define META_CR_TXSTATUS_PRIV (0x00020000U) +#define META_CR_TXPRIVEXT_MINIM (0x00000080U) + +#define META_MEM_GLOBAL_RANGE_BIT (0x80000000U) + +#define META_CR_TXCLKCTRL (0x048000B0) +#define META_CR_TXCLKCTRL_ALL_ON (0x55111111) +#define META_CR_TXCLKCTRL_ALL_AUTO (0xAA222222) + +#define META_CR_MMCU_LOCAL_EBCTRL (0x04830600) +#define META_CR_MMCU_LOCAL_EBCTRL_ICWIN (0x3 << 14) +#define META_CR_MMCU_LOCAL_EBCTRL_DCWIN (0x3 << 6) +#define META_CR_SYSC_DCPART(n) (0x04830200 + (n) * 0x8) +#define META_CR_SYSC_DCPARTX_CACHED_WRITE_ENABLE (0x1 << 31) +#define META_CR_SYSC_ICPART(n) (0x04830220 + (n) * 0x8) +#define META_CR_SYSC_XCPARTX_LOCAL_ADDR_OFFSET_TOP_HALF (0x8 << 16) +#define META_CR_SYSC_XCPARTX_LOCAL_ADDR_FULL_CACHE (0xF) +#define META_CR_SYSC_XCPARTX_LOCAL_ADDR_HALF_CACHE (0x7) +#define META_CR_MMCU_DCACHE_CTRL (0x04830018) +#define META_CR_MMCU_ICACHE_CTRL (0x04830020) +#define META_CR_MMCU_XCACHE_CTRL_CACHE_HITS_EN (0x1) + +/* + ****************************************************************************** + * META LDR Format + ****************************************************************************** + */ +/* Block header structure. */ +struct rogue_meta_ldr_block_hdr { + u32 dev_id; + u32 sl_code; + u32 sl_data; + u16 pc_ctrl; + u16 crc; +}; + +/* High level data stream block structure. */ +struct rogue_meta_ldr_l1_data_blk { + u16 cmd; + u16 length; + u32 next; + u32 cmd_data[4]; +}; + +/* High level data stream block structure. */ +struct rogue_meta_ldr_l2_data_blk { + u16 tag; + u16 length; + u32 block_data[4]; +}; + +/* Config command structure. */ +struct rogue_meta_ldr_cfg_blk { + u32 type; + u32 block_data[4]; +}; + +/* Block type definitions */ +#define ROGUE_META_LDR_COMMENT_TYPE_MASK (0x0010U) +#define ROGUE_META_LDR_BLK_IS_COMMENT(x) (((x) & ROGUE_META_LDR_COMMENT_TYPE_MASK) != 0U) + +/* + * Command definitions + * Value Name Description + * 0 LoadMem Load memory with binary data. + * 1 LoadCore Load a set of core registers. + * 2 LoadMMReg Load a set of memory mapped registers. + * 3 StartThreads Set each thread PC and SP, then enable threads. + * 4 ZeroMem Zeros a memory region. + * 5 Config Perform a configuration command. + */ +#define ROGUE_META_LDR_CMD_MASK (0x000FU) + +#define ROGUE_META_LDR_CMD_LOADMEM (0x0000U) +#define ROGUE_META_LDR_CMD_LOADCORE (0x0001U) +#define ROGUE_META_LDR_CMD_LOADMMREG (0x0002U) +#define ROGUE_META_LDR_CMD_START_THREADS (0x0003U) +#define ROGUE_META_LDR_CMD_ZEROMEM (0x0004U) +#define ROGUE_META_LDR_CMD_CONFIG (0x0005U) + +/* + * Config Command definitions + * Value Name Description + * 0 Pause Pause for x times 100 instructions + * 1 Read Read a value from register - No value return needed. + * Utilises effects of issuing reads to certain registers + * 2 Write Write to mem location + * 3 MemSet Set mem to value + * 4 MemCheck check mem for specific value. + */ +#define ROGUE_META_LDR_CFG_PAUSE (0x0000) +#define ROGUE_META_LDR_CFG_READ (0x0001) +#define ROGUE_META_LDR_CFG_WRITE (0x0002) +#define ROGUE_META_LDR_CFG_MEMSET (0x0003) +#define ROGUE_META_LDR_CFG_MEMCHECK (0x0004) + +/* + ****************************************************************************** + * ROGUE FW segmented MMU definitions + ****************************************************************************** + */ +/* All threads can access the segment. */ +#define ROGUE_FW_SEGMMU_ALLTHRS (0xf << 8U) +/* Writable. */ +#define ROGUE_FW_SEGMMU_WRITEABLE (0x1U << 1U) +/* All threads can access and writable. */ +#define ROGUE_FW_SEGMMU_ALLTHRS_WRITEABLE \ + (ROGUE_FW_SEGMMU_ALLTHRS | ROGUE_FW_SEGMMU_WRITEABLE) + +/* Direct map region 10 used for mapping GPU memory - max 8MB. */ +#define ROGUE_FW_SEGMMU_DMAP_GPU_ID (10U) +#define ROGUE_FW_SEGMMU_DMAP_GPU_ADDR_START (0x07000000U) +#define ROGUE_FW_SEGMMU_DMAP_GPU_MAX_SIZE (0x00800000U) + +/* Segment IDs. */ +#define ROGUE_FW_SEGMMU_DATA_ID (1U) +#define ROGUE_FW_SEGMMU_BOOTLDR_ID (2U) +#define ROGUE_FW_SEGMMU_TEXT_ID (ROGUE_FW_SEGMMU_BOOTLDR_ID) + +/* + * SLC caching strategy in S7 and volcanic is emitted through the segment MMU. + * All the segments configured through the macro ROGUE_FW_SEGMMU_OUTADDR_TOP are + * CACHED in the SLC. + * The interface has been kept the same to simplify the code changes. + * The bifdm argument is ignored (no longer relevant) in S7 and volcanic. + */ +#define ROGUE_FW_SEGMMU_OUTADDR_TOP_VIVT_SLC(pers, slc_policy, mmu_ctx) \ + ((((u64)((pers) & 0x3)) << 52) | (((u64)((mmu_ctx) & 0xFF)) << 44) | \ + (((u64)((slc_policy) & 0x1)) << 40)) +#define ROGUE_FW_SEGMMU_OUTADDR_TOP_VIVT_SLC_CACHED(mmu_ctx) \ + ROGUE_FW_SEGMMU_OUTADDR_TOP_VIVT_SLC(0x3, 0x0, mmu_ctx) +#define ROGUE_FW_SEGMMU_OUTADDR_TOP_VIVT_SLC_UNCACHED(mmu_ctx) \ + ROGUE_FW_SEGMMU_OUTADDR_TOP_VIVT_SLC(0x0, 0x1, mmu_ctx) + +/* + * To configure the Page Catalog and BIF-DM fed into the BIF for Garten + * accesses through this segment. + */ +#define ROGUE_FW_SEGMMU_OUTADDR_TOP_SLC(pc, bifdm) \ + (((u64)((u64)(pc) & 0xFU) << 44U) | ((u64)((u64)(bifdm) & 0xFU) << 40U)) + +#define ROGUE_FW_SEGMMU_META_BIFDM_ID (0x7U) + +/* META segments have 4kB minimum size. */ +#define ROGUE_FW_SEGMMU_ALIGN (0x1000U) + +/* Segmented MMU registers (n = segment id). */ +#define META_CR_MMCU_SEGMENT_N_BASE(n) (0x04850000U + ((n) * 0x10U)) +#define META_CR_MMCU_SEGMENT_N_LIMIT(n) (0x04850004U + ((n) * 0x10U)) +#define META_CR_MMCU_SEGMENT_N_OUTA0(n) (0x04850008U + ((n) * 0x10U)) +#define META_CR_MMCU_SEGMENT_N_OUTA1(n) (0x0485000CU + ((n) * 0x10U)) + +/* + * The following defines must be recalculated if the Meta MMU segments used + * to access Host-FW data are changed + * Current combinations are: + * - SLC uncached, META cached, FW base address 0x70000000 + * - SLC uncached, META uncached, FW base address 0xF0000000 + * - SLC cached, META cached, FW base address 0x10000000 + * - SLC cached, META uncached, FW base address 0x90000000 + */ +#define ROGUE_FW_SEGMMU_DATA_BASE_ADDRESS (0x10000000U) +#define ROGUE_FW_SEGMMU_DATA_META_CACHED (0x0U) +#define ROGUE_FW_SEGMMU_DATA_META_UNCACHED (META_MEM_GLOBAL_RANGE_BIT) +#define ROGUE_FW_SEGMMU_DATA_META_CACHE_MASK (META_MEM_GLOBAL_RANGE_BIT) +/* + * For non-VIVT SLCs the cacheability of the FW data in the SLC is selected in + * the PTEs for the FW data, not in the Meta Segment MMU, which means these + * defines have no real effect in those cases. + */ +#define ROGUE_FW_SEGMMU_DATA_VIVT_SLC_CACHED (0x0U) +#define ROGUE_FW_SEGMMU_DATA_VIVT_SLC_UNCACHED (0x60000000U) +#define ROGUE_FW_SEGMMU_DATA_VIVT_SLC_CACHE_MASK (0x60000000U) + +/* + ****************************************************************************** + * ROGUE FW Bootloader defaults + ****************************************************************************** + */ +#define ROGUE_FW_BOOTLDR_META_ADDR (0x40000000U) +#define ROGUE_FW_BOOTLDR_DEVV_ADDR_0 (0xC0000000U) +#define ROGUE_FW_BOOTLDR_DEVV_ADDR_1 (0x000000E1) +#define ROGUE_FW_BOOTLDR_DEVV_ADDR \ + ((((u64)ROGUE_FW_BOOTLDR_DEVV_ADDR_1) << 32) | \ + ROGUE_FW_BOOTLDR_DEVV_ADDR_0) +#define ROGUE_FW_BOOTLDR_LIMIT (0x1FFFF000) +#define ROGUE_FW_MAX_BOOTLDR_OFFSET (0x1000) + +/* Bootloader configuration offset is in dwords (512 bytes) */ +#define ROGUE_FW_BOOTLDR_CONF_OFFSET (0x80) + +/* + ****************************************************************************** + * ROGUE META Stack + ****************************************************************************** + */ +#define ROGUE_META_STACK_SIZE (0x1000U) + +/* + ****************************************************************************** + * ROGUE META Core memory + ****************************************************************************** + */ +/* Code and data both map to the same physical memory. */ +#define ROGUE_META_COREMEM_CODE_ADDR (0x80000000U) +#define ROGUE_META_COREMEM_DATA_ADDR (0x82000000U) +#define ROGUE_META_COREMEM_OFFSET_MASK (0x01ffffffU) + +#define ROGUE_META_IS_COREMEM_CODE(a, b) \ + ({ \ + u32 _a = (a), _b = (b); \ + ((_a) >= ROGUE_META_COREMEM_CODE_ADDR) && \ + ((_a) < (ROGUE_META_COREMEM_CODE_ADDR + (_b))); \ + }) +#define ROGUE_META_IS_COREMEM_DATA(a, b) \ + ({ \ + u32 _a = (a), _b = (b); \ + ((_a) >= ROGUE_META_COREMEM_DATA_ADDR) && \ + ((_a) < (ROGUE_META_COREMEM_DATA_ADDR + (_b))); \ + }) +/* + ****************************************************************************** + * 2nd thread + ****************************************************************************** + */ +#define ROGUE_FW_THR1_PC (0x18930000) +#define ROGUE_FW_THR1_SP (0x78890000) + +/* + ****************************************************************************** + * META compatibility + ****************************************************************************** + */ + +#define META_CR_CORE_ID (0x04831000) +#define META_CR_CORE_ID_VER_SHIFT (16U) +#define META_CR_CORE_ID_VER_CLRMSK (0XFF00FFFFU) + +#define ROGUE_CR_META_MTP218_CORE_ID_VALUE 0x19 +#define ROGUE_CR_META_MTP219_CORE_ID_VALUE 0x1E +#define ROGUE_CR_META_LTP218_CORE_ID_VALUE 0x1C +#define ROGUE_CR_META_LTP217_CORE_ID_VALUE 0x1F + +#define ROGUE_FW_PROCESSOR_META "META" + +#endif /* PVR_ROGUE_META_H */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_mips.h b/drivers/gpu/drm/imagination/pvr_rogue_mips.h new file mode 100644 index 00000000000000..41ed618fda3f9d --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_mips.h @@ -0,0 +1,335 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_ROGUE_MIPS_H +#define PVR_ROGUE_MIPS_H + +#include +#include + +/* Utility defines for memory management. */ +#define ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K (12) +#define ROGUE_MIPSFW_PAGE_SIZE_4K (0x1 << ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K) +#define ROGUE_MIPSFW_PAGE_MASK_4K (ROGUE_MIPSFW_PAGE_SIZE_4K - 1) +#define ROGUE_MIPSFW_LOG2_PAGE_SIZE_64K (16) +#define ROGUE_MIPSFW_PAGE_SIZE_64K (0x1 << ROGUE_MIPSFW_LOG2_PAGE_SIZE_64K) +#define ROGUE_MIPSFW_PAGE_MASK_64K (ROGUE_MIPSFW_PAGE_SIZE_64K - 1) +#define ROGUE_MIPSFW_LOG2_PAGE_SIZE_256K (18) +#define ROGUE_MIPSFW_PAGE_SIZE_256K (0x1 << ROGUE_MIPSFW_LOG2_PAGE_SIZE_256K) +#define ROGUE_MIPSFW_PAGE_MASK_256K (ROGUE_MIPSFW_PAGE_SIZE_256K - 1) +#define ROGUE_MIPSFW_LOG2_PAGE_SIZE_1MB (20) +#define ROGUE_MIPSFW_PAGE_SIZE_1MB (0x1 << ROGUE_MIPSFW_LOG2_PAGE_SIZE_1MB) +#define ROGUE_MIPSFW_PAGE_MASK_1MB (ROGUE_MIPSFW_PAGE_SIZE_1MB - 1) +#define ROGUE_MIPSFW_LOG2_PAGE_SIZE_4MB (22) +#define ROGUE_MIPSFW_PAGE_SIZE_4MB (0x1 << ROGUE_MIPSFW_LOG2_PAGE_SIZE_4MB) +#define ROGUE_MIPSFW_PAGE_MASK_4MB (ROGUE_MIPSFW_PAGE_SIZE_4MB - 1) +#define ROGUE_MIPSFW_LOG2_PTE_ENTRY_SIZE (2) +/* log2 page table sizes dependent on FW heap size and page size (for each OS). */ +#define ROGUE_MIPSFW_LOG2_PAGETABLE_SIZE_4K(pvr_dev) ((pvr_dev)->fw_dev.fw_heap_info.log2_size - \ + ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K + \ + ROGUE_MIPSFW_LOG2_PTE_ENTRY_SIZE) +#define ROGUE_MIPSFW_LOG2_PAGETABLE_SIZE_64K(pvr_dev) ((pvr_dev)->fw_dev.fw_heap_info.log2_size - \ + ROGUE_MIPSFW_LOG2_PAGE_SIZE_64K + \ + ROGUE_MIPSFW_LOG2_PTE_ENTRY_SIZE) +/* Maximum number of page table pages (both Host and MIPS pages). */ +#define ROGUE_MIPSFW_MAX_NUM_PAGETABLE_PAGES (4) +/* Total number of TLB entries. */ +#define ROGUE_MIPSFW_NUMBER_OF_TLB_ENTRIES (16) +/* "Uncached" caching policy. */ +#define ROGUE_MIPSFW_UNCACHED_CACHE_POLICY (2) +/* "Write-back write-allocate" caching policy. */ +#define ROGUE_MIPSFW_WRITEBACK_CACHE_POLICY (3) +/* "Write-through no write-allocate" caching policy. */ +#define ROGUE_MIPSFW_WRITETHROUGH_CACHE_POLICY (1) +/* Cached policy used by MIPS in case of physical bus on 32 bit. */ +#define ROGUE_MIPSFW_CACHED_POLICY (ROGUE_MIPSFW_WRITEBACK_CACHE_POLICY) +/* Cached policy used by MIPS in case of physical bus on more than 32 bit. */ +#define ROGUE_MIPSFW_CACHED_POLICY_ABOVE_32BIT (ROGUE_MIPSFW_WRITETHROUGH_CACHE_POLICY) +/* Total number of Remap entries. */ +#define ROGUE_MIPSFW_NUMBER_OF_REMAP_ENTRIES (2 * ROGUE_MIPSFW_NUMBER_OF_TLB_ENTRIES) + +/* MIPS EntryLo/PTE format. */ + +#define ROGUE_MIPSFW_ENTRYLO_READ_INHIBIT_SHIFT (31U) +#define ROGUE_MIPSFW_ENTRYLO_READ_INHIBIT_CLRMSK (0X7FFFFFFF) +#define ROGUE_MIPSFW_ENTRYLO_READ_INHIBIT_EN (0X80000000) + +#define ROGUE_MIPSFW_ENTRYLO_EXEC_INHIBIT_SHIFT (30U) +#define ROGUE_MIPSFW_ENTRYLO_EXEC_INHIBIT_CLRMSK (0XBFFFFFFF) +#define ROGUE_MIPSFW_ENTRYLO_EXEC_INHIBIT_EN (0X40000000) + +/* Page Frame Number */ +#define ROGUE_MIPSFW_ENTRYLO_PFN_SHIFT (6) +#define ROGUE_MIPSFW_ENTRYLO_PFN_ALIGNSHIFT (12) +/* Mask used for the MIPS Page Table in case of physical bus on 32 bit. */ +#define ROGUE_MIPSFW_ENTRYLO_PFN_MASK (0x03FFFFC0) +#define ROGUE_MIPSFW_ENTRYLO_PFN_SIZE (20) +/* Mask used for the MIPS Page Table in case of physical bus on more than 32 bit. */ +#define ROGUE_MIPSFW_ENTRYLO_PFN_MASK_ABOVE_32BIT (0x3FFFFFC0) +#define ROGUE_MIPSFW_ENTRYLO_PFN_SIZE_ABOVE_32BIT (24) +#define ROGUE_MIPSFW_ADDR_TO_ENTRYLO_PFN_RSHIFT (ROGUE_MIPSFW_ENTRYLO_PFN_ALIGNSHIFT - \ + ROGUE_MIPSFW_ENTRYLO_PFN_SHIFT) + +#define ROGUE_MIPSFW_ENTRYLO_CACHE_POLICY_SHIFT (3U) +#define ROGUE_MIPSFW_ENTRYLO_CACHE_POLICY_CLRMSK (0XFFFFFFC7) + +#define ROGUE_MIPSFW_ENTRYLO_DIRTY_SHIFT (2U) +#define ROGUE_MIPSFW_ENTRYLO_DIRTY_CLRMSK (0XFFFFFFFB) +#define ROGUE_MIPSFW_ENTRYLO_DIRTY_EN (0X00000004) + +#define ROGUE_MIPSFW_ENTRYLO_VALID_SHIFT (1U) +#define ROGUE_MIPSFW_ENTRYLO_VALID_CLRMSK (0XFFFFFFFD) +#define ROGUE_MIPSFW_ENTRYLO_VALID_EN (0X00000002) + +#define ROGUE_MIPSFW_ENTRYLO_GLOBAL_SHIFT (0U) +#define ROGUE_MIPSFW_ENTRYLO_GLOBAL_CLRMSK (0XFFFFFFFE) +#define ROGUE_MIPSFW_ENTRYLO_GLOBAL_EN (0X00000001) + +#define ROGUE_MIPSFW_ENTRYLO_DVG (ROGUE_MIPSFW_ENTRYLO_DIRTY_EN | \ + ROGUE_MIPSFW_ENTRYLO_VALID_EN | \ + ROGUE_MIPSFW_ENTRYLO_GLOBAL_EN) +#define ROGUE_MIPSFW_ENTRYLO_UNCACHED (ROGUE_MIPSFW_UNCACHED_CACHE_POLICY << \ + ROGUE_MIPSFW_ENTRYLO_CACHE_POLICY_SHIFT) +#define ROGUE_MIPSFW_ENTRYLO_DVG_UNCACHED (ROGUE_MIPSFW_ENTRYLO_DVG | \ + ROGUE_MIPSFW_ENTRYLO_UNCACHED) + +/* Remap Range Config Addr Out. */ +/* These defines refer to the upper half of the Remap Range Config register. */ +#define ROGUE_MIPSFW_REMAP_RANGE_ADDR_OUT_MASK (0x0FFFFFF0) +#define ROGUE_MIPSFW_REMAP_RANGE_ADDR_OUT_SHIFT (4) /* wrt upper half of the register. */ +#define ROGUE_MIPSFW_REMAP_RANGE_ADDR_OUT_ALIGNSHIFT (12) +#define ROGUE_MIPSFW_ADDR_TO_RR_ADDR_OUT_RSHIFT (ROGUE_MIPSFW_REMAP_RANGE_ADDR_OUT_ALIGNSHIFT - \ + ROGUE_MIPSFW_REMAP_RANGE_ADDR_OUT_SHIFT) + +/* + * Pages to trampoline problematic physical addresses: + * - ROGUE_MIPSFW_BOOT_REMAP_PHYS_ADDR_IN : 0x1FC0_0000 + * - ROGUE_MIPSFW_DATA_REMAP_PHYS_ADDR_IN : 0x1FC0_1000 + * - ROGUE_MIPSFW_CODE_REMAP_PHYS_ADDR_IN : 0x1FC0_2000 + * - (benign trampoline) : 0x1FC0_3000 + * that would otherwise be erroneously remapped by the MIPS wrapper. + * (see "Firmware virtual layout and remap configuration" section below) + */ + +#define ROGUE_MIPSFW_TRAMPOLINE_LOG2_NUMPAGES (2) +#define ROGUE_MIPSFW_TRAMPOLINE_NUMPAGES BIT(ROGUE_MIPSFW_TRAMPOLINE_LOG2_NUMPAGES) +#define ROGUE_MIPSFW_TRAMPOLINE_SIZE (ROGUE_MIPSFW_TRAMPOLINE_NUMPAGES << \ + ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K) +#define ROGUE_MIPSFW_TRAMPOLINE_LOG2_SEGMENT_SIZE (ROGUE_MIPSFW_TRAMPOLINE_LOG2_NUMPAGES + \ + ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K) + +#define ROGUE_MIPSFW_TRAMPOLINE_TARGET_PHYS_ADDR (ROGUE_MIPSFW_BOOT_REMAP_PHYS_ADDR_IN) +#define ROGUE_MIPSFW_TRAMPOLINE_OFFSET(a) ((a) - ROGUE_MIPSFW_BOOT_REMAP_PHYS_ADDR_IN) + +#define ROGUE_MIPSFW_SENSITIVE_ADDR(a) (ROGUE_MIPSFW_BOOT_REMAP_PHYS_ADDR_IN == \ + (~((1 << ROGUE_MIPSFW_TRAMPOLINE_LOG2_SEGMENT_SIZE) - 1) \ + & (a))) + +/* Firmware virtual layout and remap configuration. */ +/* + * For each remap region we define: + * - the virtual base used by the Firmware to access code/data through that region + * - the microAptivAP physical address correspondent to the virtual base address, + * used as input address and remapped to the actual physical address + * - log2 of size of the region remapped by the MIPS wrapper, i.e. number of bits from + * the bottom of the base input address that survive onto the output address + * (this defines both the alignment and the maximum size of the remapped region) + * - one or more code/data segments within the remapped region. + */ + +/* Boot remap setup. */ +#define ROGUE_MIPSFW_BOOT_REMAP_VIRTUAL_BASE (0xBFC00000) +#define ROGUE_MIPSFW_BOOT_REMAP_PHYS_ADDR_IN (0x1FC00000) +#define ROGUE_MIPSFW_BOOT_REMAP_LOG2_SEGMENT_SIZE (12) +#define ROGUE_MIPSFW_BOOT_NMI_CODE_VIRTUAL_BASE (ROGUE_MIPSFW_BOOT_REMAP_VIRTUAL_BASE) + +/* Data remap setup. */ +#define ROGUE_MIPSFW_DATA_REMAP_VIRTUAL_BASE (0xBFC01000) +#define ROGUE_MIPSFW_DATA_CACHED_REMAP_VIRTUAL_BASE (0x9FC01000) +#define ROGUE_MIPSFW_DATA_REMAP_PHYS_ADDR_IN (0x1FC01000) +#define ROGUE_MIPSFW_DATA_REMAP_LOG2_SEGMENT_SIZE (12) +#define ROGUE_MIPSFW_BOOT_NMI_DATA_VIRTUAL_BASE (ROGUE_MIPSFW_DATA_REMAP_VIRTUAL_BASE) + +/* Code remap setup. */ +#define ROGUE_MIPSFW_CODE_REMAP_VIRTUAL_BASE (0x9FC02000) +#define ROGUE_MIPSFW_CODE_REMAP_PHYS_ADDR_IN (0x1FC02000) +#define ROGUE_MIPSFW_CODE_REMAP_LOG2_SEGMENT_SIZE (12) +#define ROGUE_MIPSFW_EXCEPTIONS_VIRTUAL_BASE (ROGUE_MIPSFW_CODE_REMAP_VIRTUAL_BASE) + +/* Permanent mappings setup. */ +#define ROGUE_MIPSFW_PT_VIRTUAL_BASE (0xCF000000) +#define ROGUE_MIPSFW_REGISTERS_VIRTUAL_BASE (0xCF800000) +#define ROGUE_MIPSFW_STACK_VIRTUAL_BASE (0xCF600000) + +/* Bootloader configuration data. */ +/* + * Bootloader configuration offset (where ROGUE_MIPSFW_BOOT_DATA lives) + * within the bootloader/NMI data page. + */ +#define ROGUE_MIPSFW_BOOTLDR_CONF_OFFSET (0x0) + +/* NMI shared data. */ +/* Base address of the shared data within the bootloader/NMI data page. */ +#define ROGUE_MIPSFW_NMI_SHARED_DATA_BASE (0x100) +/* Size used by Debug dump data. */ +#define ROGUE_MIPSFW_NMI_SHARED_SIZE (0x2B0) +/* Offsets in the NMI shared area in 32-bit words. */ +#define ROGUE_MIPSFW_NMI_SYNC_FLAG_OFFSET (0x0) +#define ROGUE_MIPSFW_NMI_STATE_OFFSET (0x1) +#define ROGUE_MIPSFW_NMI_ERROR_STATE_SET (0x1) + +/* MIPS boot stage. */ +#define ROGUE_MIPSFW_BOOT_STAGE_OFFSET (0x400) + +/* + * MIPS private data in the bootloader data page. + * Memory below this offset is used by the FW only, no interface data allowed. + */ +#define ROGUE_MIPSFW_PRIVATE_DATA_OFFSET (0x800) + +struct rogue_mipsfw_boot_data { + u64 stack_phys_addr; + u64 reg_base; + u64 pt_phys_addr[ROGUE_MIPSFW_MAX_NUM_PAGETABLE_PAGES]; + u32 pt_log2_page_size; + u32 pt_num_pages; + u32 reserved1; + u32 reserved2; +}; + +#define ROGUE_MIPSFW_GET_OFFSET_IN_DWORDS(offset) ((offset) / sizeof(u32)) +#define ROGUE_MIPSFW_GET_OFFSET_IN_QWORDS(offset) ((offset) / sizeof(u64)) + +/* Used for compatibility checks. */ +#define ROGUE_MIPSFW_ARCHTYPE_VER_CLRMSK (0xFFFFE3FFU) +#define ROGUE_MIPSFW_ARCHTYPE_VER_SHIFT (10U) +#define ROGUE_MIPSFW_CORE_ID_VALUE (0x001U) +#define ROGUE_FW_PROCESSOR_MIPS "MIPS" + +/* microAptivAP cache line size. */ +#define ROGUE_MIPSFW_MICROAPTIVEAP_CACHELINE_SIZE (16U) + +/* + * The SOCIF transactions are identified with the top 16 bits of the physical address emitted by + * the MIPS. + */ +#define ROGUE_MIPSFW_WRAPPER_CONFIG_REGBANK_ADDR_ALIGN (16U) + +/* Values to put in the MIPS selectors for performance counters. */ +/* Icache accesses in COUNTER0. */ +#define ROGUE_MIPSFW_PERF_COUNT_CTRL_ICACHE_ACCESSES_C0 (9U) +/* Icache misses in COUNTER1. */ +#define ROGUE_MIPSFW_PERF_COUNT_CTRL_ICACHE_MISSES_C1 (9U) + +/* Dcache accesses in COUNTER0. */ +#define ROGUE_MIPSFW_PERF_COUNT_CTRL_DCACHE_ACCESSES_C0 (10U) +/* Dcache misses in COUNTER1. */ +#define ROGUE_MIPSFW_PERF_COUNT_CTRL_DCACHE_MISSES_C1 (11U) + +/* ITLB instruction accesses in COUNTER0. */ +#define ROGUE_MIPSFW_PERF_COUNT_CTRL_ITLB_INSTR_ACCESSES_C0 (5U) +/* JTLB instruction accesses misses in COUNTER1. */ +#define ROGUE_MIPSFW_PERF_COUNT_CTRL_JTLB_INSTR_MISSES_C1 (7U) + + /* Instructions completed in COUNTER0. */ +#define ROGUE_MIPSFW_PERF_COUNT_CTRL_INSTR_COMPLETED_C0 (1U) +/* JTLB data misses in COUNTER1. */ +#define ROGUE_MIPSFW_PERF_COUNT_CTRL_JTLB_DATA_MISSES_C1 (8U) + +/* Shift for the Event field in the MIPS perf ctrl registers. */ +#define ROGUE_MIPSFW_PERF_COUNT_CTRL_EVENT_SHIFT (5U) + +/* Additional flags for performance counters. See MIPS manual for further reference. */ +#define ROGUE_MIPSFW_PERF_COUNT_CTRL_COUNT_USER_MODE (8U) +#define ROGUE_MIPSFW_PERF_COUNT_CTRL_COUNT_KERNEL_MODE (2U) +#define ROGUE_MIPSFW_PERF_COUNT_CTRL_COUNT_EXL (1U) + +#define ROGUE_MIPSFW_C0_NBHWIRQ 8 + +/* Macros to decode C0_Cause register. */ +#define ROGUE_MIPSFW_C0_CAUSE_EXCCODE(cause) (((cause) & 0x7c) >> 2) +#define ROGUE_MIPSFW_C0_CAUSE_EXCCODE_FWERROR 9 +/* Use only when Coprocessor Unusable exception. */ +#define ROGUE_MIPSFW_C0_CAUSE_UNUSABLE_UNIT(cause) (((cause) >> 28) & 0x3) +#define ROGUE_MIPSFW_C0_CAUSE_PENDING_HWIRQ(cause) (((cause) & 0x3fc00) >> 10) +#define ROGUE_MIPSFW_C0_CAUSE_FDCIPENDING BIT(21) +#define ROGUE_MIPSFW_C0_CAUSE_IV BIT(23) +#define ROGUE_MIPSFW_C0_CAUSE_IC BIT(25) +#define ROGUE_MIPSFW_C0_CAUSE_PCIPENDING BIT(26) +#define ROGUE_MIPSFW_C0_CAUSE_TIPENDING BIT(30) +#define ROGUE_MIPSFW_C0_CAUSE_BRANCH_DELAY BIT(31) + +/* Macros to decode C0_Debug register. */ +#define ROGUE_MIPSFW_C0_DEBUG_EXCCODE(debug) (((debug) >> 10) & 0x1f) +#define ROGUE_MIPSFW_C0_DEBUG_DSS BIT(0) +#define ROGUE_MIPSFW_C0_DEBUG_DBP BIT(1) +#define ROGUE_MIPSFW_C0_DEBUG_DDBL BIT(2) +#define ROGUE_MIPSFW_C0_DEBUG_DDBS BIT(3) +#define ROGUE_MIPSFW_C0_DEBUG_DIB BIT(4) +#define ROGUE_MIPSFW_C0_DEBUG_DINT BIT(5) +#define ROGUE_MIPSFW_C0_DEBUG_DIBIMPR BIT(6) +#define ROGUE_MIPSFW_C0_DEBUG_DDBLIMPR BIT(18) +#define ROGUE_MIPSFW_C0_DEBUG_DDBSIMPR BIT(19) +#define ROGUE_MIPSFW_C0_DEBUG_IEXI BIT(20) +#define ROGUE_MIPSFW_C0_DEBUG_DBUSEP BIT(21) +#define ROGUE_MIPSFW_C0_DEBUG_CACHEEP BIT(22) +#define ROGUE_MIPSFW_C0_DEBUG_MCHECKP BIT(23) +#define ROGUE_MIPSFW_C0_DEBUG_IBUSEP BIT(24) +#define ROGUE_MIPSFW_C0_DEBUG_DM BIT(30) +#define ROGUE_MIPSFW_C0_DEBUG_DBD BIT(31) + +/* Macros to decode TLB entries. */ +#define ROGUE_MIPSFW_TLB_GET_MASK(page_mask) (((page_mask) >> 13) & 0XFFFFU) +/* Page size in KB. */ +#define ROGUE_MIPSFW_TLB_GET_PAGE_SIZE(page_mask) ((((page_mask) | 0x1FFF) + 1) >> 11) +/* Page size in KB. */ +#define ROGUE_MIPSFW_TLB_GET_PAGE_MASK(page_size) ((((page_size) << 11) - 1) & ~0x7FF) +#define ROGUE_MIPSFW_TLB_GET_VPN2(entry_hi) ((entry_hi) >> 13) +#define ROGUE_MIPSFW_TLB_GET_COHERENCY(entry_lo) (((entry_lo) >> 3) & 0x7U) +#define ROGUE_MIPSFW_TLB_GET_PFN(entry_lo) (((entry_lo) >> 6) & 0XFFFFFU) +/* GET_PA uses a non-standard PFN mask for 36 bit addresses. */ +#define ROGUE_MIPSFW_TLB_GET_PA(entry_lo) (((u64)(entry_lo) & \ + ROGUE_MIPSFW_ENTRYLO_PFN_MASK_ABOVE_32BIT) << 6) +#define ROGUE_MIPSFW_TLB_GET_INHIBIT(entry_lo) (((entry_lo) >> 30) & 0x3U) +#define ROGUE_MIPSFW_TLB_GET_DGV(entry_lo) ((entry_lo) & 0x7U) +#define ROGUE_MIPSFW_TLB_GLOBAL BIT(0) +#define ROGUE_MIPSFW_TLB_VALID BIT(1) +#define ROGUE_MIPSFW_TLB_DIRTY BIT(2) +#define ROGUE_MIPSFW_TLB_XI BIT(30) +#define ROGUE_MIPSFW_TLB_RI BIT(31) + +#define ROGUE_MIPSFW_REMAP_GET_REGION_SIZE(region_size_encoding) (1 << (((region_size_encoding) \ + + 1) << 1)) + +struct rogue_mips_tlb_entry { + u32 tlb_page_mask; + u32 tlb_hi; + u32 tlb_lo0; + u32 tlb_lo1; +}; + +struct rogue_mips_remap_entry { + u32 remap_addr_in; /* Always 4k aligned. */ + u32 remap_addr_out; /* Always 4k aligned. */ + u32 remap_region_size; +}; + +struct rogue_mips_state { + u32 error_state; /* This must come first in the structure. */ + u32 error_epc; + u32 status_register; + u32 cause_register; + u32 bad_register; + u32 epc; + u32 sp; + u32 debug; + u32 depc; + u32 bad_instr; + u32 unmapped_address; + struct rogue_mips_tlb_entry tlb[ROGUE_MIPSFW_NUMBER_OF_TLB_ENTRIES]; + struct rogue_mips_remap_entry remap[ROGUE_MIPSFW_NUMBER_OF_REMAP_ENTRIES]; +}; + +#include "pvr_rogue_mips_check.h" + +#endif /* PVR_ROGUE_MIPS_H */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_mips_check.h b/drivers/gpu/drm/imagination/pvr_rogue_mips_check.h new file mode 100644 index 00000000000000..824b4bf33ac140 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_mips_check.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_ROGUE_MIPS_CHECK_H +#define PVR_ROGUE_MIPS_CHECK_H + +#include + +static_assert(offsetof(struct rogue_mips_tlb_entry, tlb_page_mask) == 0, + "offsetof(struct rogue_mips_tlb_entry, tlb_page_mask) incorrect"); +static_assert(offsetof(struct rogue_mips_tlb_entry, tlb_hi) == 4, + "offsetof(struct rogue_mips_tlb_entry, tlb_hi) incorrect"); +static_assert(offsetof(struct rogue_mips_tlb_entry, tlb_lo0) == 8, + "offsetof(struct rogue_mips_tlb_entry, tlb_lo0) incorrect"); +static_assert(offsetof(struct rogue_mips_tlb_entry, tlb_lo1) == 12, + "offsetof(struct rogue_mips_tlb_entry, tlb_lo1) incorrect"); +static_assert(sizeof(struct rogue_mips_tlb_entry) == 16, + "struct rogue_mips_tlb_entry is incorrect size"); + +static_assert(offsetof(struct rogue_mips_remap_entry, remap_addr_in) == 0, + "offsetof(struct rogue_mips_remap_entry, remap_addr_in) incorrect"); +static_assert(offsetof(struct rogue_mips_remap_entry, remap_addr_out) == 4, + "offsetof(struct rogue_mips_remap_entry, remap_addr_out) incorrect"); +static_assert(offsetof(struct rogue_mips_remap_entry, remap_region_size) == 8, + "offsetof(struct rogue_mips_remap_entry, remap_region_size) incorrect"); +static_assert(sizeof(struct rogue_mips_remap_entry) == 12, + "struct rogue_mips_remap_entry is incorrect size"); + +static_assert(offsetof(struct rogue_mips_state, error_state) == 0, + "offsetof(struct rogue_mips_state, error_state) incorrect"); +static_assert(offsetof(struct rogue_mips_state, error_epc) == 4, + "offsetof(struct rogue_mips_state, error_epc) incorrect"); +static_assert(offsetof(struct rogue_mips_state, status_register) == 8, + "offsetof(struct rogue_mips_state, status_register) incorrect"); +static_assert(offsetof(struct rogue_mips_state, cause_register) == 12, + "offsetof(struct rogue_mips_state, cause_register) incorrect"); +static_assert(offsetof(struct rogue_mips_state, bad_register) == 16, + "offsetof(struct rogue_mips_state, bad_register) incorrect"); +static_assert(offsetof(struct rogue_mips_state, epc) == 20, + "offsetof(struct rogue_mips_state, epc) incorrect"); +static_assert(offsetof(struct rogue_mips_state, sp) == 24, + "offsetof(struct rogue_mips_state, sp) incorrect"); +static_assert(offsetof(struct rogue_mips_state, debug) == 28, + "offsetof(struct rogue_mips_state, debug) incorrect"); +static_assert(offsetof(struct rogue_mips_state, depc) == 32, + "offsetof(struct rogue_mips_state, depc) incorrect"); +static_assert(offsetof(struct rogue_mips_state, bad_instr) == 36, + "offsetof(struct rogue_mips_state, bad_instr) incorrect"); +static_assert(offsetof(struct rogue_mips_state, unmapped_address) == 40, + "offsetof(struct rogue_mips_state, unmapped_address) incorrect"); +static_assert(offsetof(struct rogue_mips_state, tlb) == 44, + "offsetof(struct rogue_mips_state, tlb) incorrect"); +static_assert(offsetof(struct rogue_mips_state, remap) == 300, + "offsetof(struct rogue_mips_state, remap) incorrect"); +static_assert(sizeof(struct rogue_mips_state) == 684, + "struct rogue_mips_state is incorrect size"); + +#endif /* PVR_ROGUE_MIPS_CHECK_H */ diff --git a/drivers/gpu/drm/imagination/pvr_rogue_mmu_defs.h b/drivers/gpu/drm/imagination/pvr_rogue_mmu_defs.h new file mode 100644 index 00000000000000..f361ccdd540517 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_rogue_mmu_defs.h @@ -0,0 +1,136 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +/* *** Autogenerated C -- do not edit *** */ + +#ifndef PVR_ROGUE_MMU_DEFS_H +#define PVR_ROGUE_MMU_DEFS_H + +#define ROGUE_MMU_DEFS_REVISION 0 + +#define ROGUE_BIF_DM_ENCODING_VERTEX (0x00000000U) +#define ROGUE_BIF_DM_ENCODING_PIXEL (0x00000001U) +#define ROGUE_BIF_DM_ENCODING_COMPUTE (0x00000002U) +#define ROGUE_BIF_DM_ENCODING_TLA (0x00000003U) +#define ROGUE_BIF_DM_ENCODING_PB_VCE (0x00000004U) +#define ROGUE_BIF_DM_ENCODING_PB_TE (0x00000005U) +#define ROGUE_BIF_DM_ENCODING_META (0x00000007U) +#define ROGUE_BIF_DM_ENCODING_HOST (0x00000008U) +#define ROGUE_BIF_DM_ENCODING_PM_ALIST (0x00000009U) + +#define ROGUE_MMUCTRL_VADDR_PC_INDEX_SHIFT (30U) +#define ROGUE_MMUCTRL_VADDR_PC_INDEX_CLRMSK (0xFFFFFF003FFFFFFFULL) +#define ROGUE_MMUCTRL_VADDR_PD_INDEX_SHIFT (21U) +#define ROGUE_MMUCTRL_VADDR_PD_INDEX_CLRMSK (0xFFFFFFFFC01FFFFFULL) +#define ROGUE_MMUCTRL_VADDR_PT_INDEX_SHIFT (12U) +#define ROGUE_MMUCTRL_VADDR_PT_INDEX_CLRMSK (0xFFFFFFFFFFE00FFFULL) + +#define ROGUE_MMUCTRL_ENTRIES_PC_VALUE (0x00000400U) +#define ROGUE_MMUCTRL_ENTRIES_PD_VALUE (0x00000200U) +#define ROGUE_MMUCTRL_ENTRIES_PT_VALUE (0x00000200U) + +#define ROGUE_MMUCTRL_ENTRY_SIZE_PC_VALUE (0x00000020U) +#define ROGUE_MMUCTRL_ENTRY_SIZE_PD_VALUE (0x00000040U) +#define ROGUE_MMUCTRL_ENTRY_SIZE_PT_VALUE (0x00000040U) + +#define ROGUE_MMUCTRL_PAGE_SIZE_MASK (0x00000007U) +#define ROGUE_MMUCTRL_PAGE_SIZE_4KB (0x00000000U) +#define ROGUE_MMUCTRL_PAGE_SIZE_16KB (0x00000001U) +#define ROGUE_MMUCTRL_PAGE_SIZE_64KB (0x00000002U) +#define ROGUE_MMUCTRL_PAGE_SIZE_256KB (0x00000003U) +#define ROGUE_MMUCTRL_PAGE_SIZE_1MB (0x00000004U) +#define ROGUE_MMUCTRL_PAGE_SIZE_2MB (0x00000005U) + +#define ROGUE_MMUCTRL_PAGE_4KB_RANGE_SHIFT (12U) +#define ROGUE_MMUCTRL_PAGE_4KB_RANGE_CLRMSK (0xFFFFFF0000000FFFULL) + +#define ROGUE_MMUCTRL_PAGE_16KB_RANGE_SHIFT (14U) +#define ROGUE_MMUCTRL_PAGE_16KB_RANGE_CLRMSK (0xFFFFFF0000003FFFULL) + +#define ROGUE_MMUCTRL_PAGE_64KB_RANGE_SHIFT (16U) +#define ROGUE_MMUCTRL_PAGE_64KB_RANGE_CLRMSK (0xFFFFFF000000FFFFULL) + +#define ROGUE_MMUCTRL_PAGE_256KB_RANGE_SHIFT (18U) +#define ROGUE_MMUCTRL_PAGE_256KB_RANGE_CLRMSK (0xFFFFFF000003FFFFULL) + +#define ROGUE_MMUCTRL_PAGE_1MB_RANGE_SHIFT (20U) +#define ROGUE_MMUCTRL_PAGE_1MB_RANGE_CLRMSK (0xFFFFFF00000FFFFFULL) + +#define ROGUE_MMUCTRL_PAGE_2MB_RANGE_SHIFT (21U) +#define ROGUE_MMUCTRL_PAGE_2MB_RANGE_CLRMSK (0xFFFFFF00001FFFFFULL) + +#define ROGUE_MMUCTRL_PT_BASE_4KB_RANGE_SHIFT (12U) +#define ROGUE_MMUCTRL_PT_BASE_4KB_RANGE_CLRMSK (0xFFFFFF0000000FFFULL) + +#define ROGUE_MMUCTRL_PT_BASE_16KB_RANGE_SHIFT (10U) +#define ROGUE_MMUCTRL_PT_BASE_16KB_RANGE_CLRMSK (0xFFFFFF00000003FFULL) + +#define ROGUE_MMUCTRL_PT_BASE_64KB_RANGE_SHIFT (8U) +#define ROGUE_MMUCTRL_PT_BASE_64KB_RANGE_CLRMSK (0xFFFFFF00000000FFULL) + +#define ROGUE_MMUCTRL_PT_BASE_256KB_RANGE_SHIFT (6U) +#define ROGUE_MMUCTRL_PT_BASE_256KB_RANGE_CLRMSK (0xFFFFFF000000003FULL) + +#define ROGUE_MMUCTRL_PT_BASE_1MB_RANGE_SHIFT (5U) +#define ROGUE_MMUCTRL_PT_BASE_1MB_RANGE_CLRMSK (0xFFFFFF000000001FULL) + +#define ROGUE_MMUCTRL_PT_BASE_2MB_RANGE_SHIFT (5U) +#define ROGUE_MMUCTRL_PT_BASE_2MB_RANGE_CLRMSK (0xFFFFFF000000001FULL) + +#define ROGUE_MMUCTRL_PT_DATA_PM_META_PROTECT_SHIFT (62U) +#define ROGUE_MMUCTRL_PT_DATA_PM_META_PROTECT_CLRMSK (0xBFFFFFFFFFFFFFFFULL) +#define ROGUE_MMUCTRL_PT_DATA_PM_META_PROTECT_EN (0x4000000000000000ULL) +#define ROGUE_MMUCTRL_PT_DATA_VP_PAGE_HI_SHIFT (40U) +#define ROGUE_MMUCTRL_PT_DATA_VP_PAGE_HI_CLRMSK (0xC00000FFFFFFFFFFULL) +#define ROGUE_MMUCTRL_PT_DATA_PAGE_SHIFT (12U) +#define ROGUE_MMUCTRL_PT_DATA_PAGE_CLRMSK (0xFFFFFF0000000FFFULL) +#define ROGUE_MMUCTRL_PT_DATA_VP_PAGE_LO_SHIFT (6U) +#define ROGUE_MMUCTRL_PT_DATA_VP_PAGE_LO_CLRMSK (0xFFFFFFFFFFFFF03FULL) +#define ROGUE_MMUCTRL_PT_DATA_ENTRY_PENDING_SHIFT (5U) +#define ROGUE_MMUCTRL_PT_DATA_ENTRY_PENDING_CLRMSK (0xFFFFFFFFFFFFFFDFULL) +#define ROGUE_MMUCTRL_PT_DATA_ENTRY_PENDING_EN (0x0000000000000020ULL) +#define ROGUE_MMUCTRL_PT_DATA_PM_SRC_SHIFT (4U) +#define ROGUE_MMUCTRL_PT_DATA_PM_SRC_CLRMSK (0xFFFFFFFFFFFFFFEFULL) +#define ROGUE_MMUCTRL_PT_DATA_PM_SRC_EN (0x0000000000000010ULL) +#define ROGUE_MMUCTRL_PT_DATA_SLC_BYPASS_CTRL_SHIFT (3U) +#define ROGUE_MMUCTRL_PT_DATA_SLC_BYPASS_CTRL_CLRMSK (0xFFFFFFFFFFFFFFF7ULL) +#define ROGUE_MMUCTRL_PT_DATA_SLC_BYPASS_CTRL_EN (0x0000000000000008ULL) +#define ROGUE_MMUCTRL_PT_DATA_CC_SHIFT (2U) +#define ROGUE_MMUCTRL_PT_DATA_CC_CLRMSK (0xFFFFFFFFFFFFFFFBULL) +#define ROGUE_MMUCTRL_PT_DATA_CC_EN (0x0000000000000004ULL) +#define ROGUE_MMUCTRL_PT_DATA_READ_ONLY_SHIFT (1U) +#define ROGUE_MMUCTRL_PT_DATA_READ_ONLY_CLRMSK (0xFFFFFFFFFFFFFFFDULL) +#define ROGUE_MMUCTRL_PT_DATA_READ_ONLY_EN (0x0000000000000002ULL) +#define ROGUE_MMUCTRL_PT_DATA_VALID_SHIFT (0U) +#define ROGUE_MMUCTRL_PT_DATA_VALID_CLRMSK (0xFFFFFFFFFFFFFFFEULL) +#define ROGUE_MMUCTRL_PT_DATA_VALID_EN (0x0000000000000001ULL) + +#define ROGUE_MMUCTRL_PD_DATA_ENTRY_PENDING_SHIFT (40U) +#define ROGUE_MMUCTRL_PD_DATA_ENTRY_PENDING_CLRMSK (0xFFFFFEFFFFFFFFFFULL) +#define ROGUE_MMUCTRL_PD_DATA_ENTRY_PENDING_EN (0x0000010000000000ULL) +#define ROGUE_MMUCTRL_PD_DATA_PT_BASE_SHIFT (5U) +#define ROGUE_MMUCTRL_PD_DATA_PT_BASE_CLRMSK (0xFFFFFF000000001FULL) +#define ROGUE_MMUCTRL_PD_DATA_PAGE_SIZE_SHIFT (1U) +#define ROGUE_MMUCTRL_PD_DATA_PAGE_SIZE_CLRMSK (0xFFFFFFFFFFFFFFF1ULL) +#define ROGUE_MMUCTRL_PD_DATA_PAGE_SIZE_4KB (0x0000000000000000ULL) +#define ROGUE_MMUCTRL_PD_DATA_PAGE_SIZE_16KB (0x0000000000000002ULL) +#define ROGUE_MMUCTRL_PD_DATA_PAGE_SIZE_64KB (0x0000000000000004ULL) +#define ROGUE_MMUCTRL_PD_DATA_PAGE_SIZE_256KB (0x0000000000000006ULL) +#define ROGUE_MMUCTRL_PD_DATA_PAGE_SIZE_1MB (0x0000000000000008ULL) +#define ROGUE_MMUCTRL_PD_DATA_PAGE_SIZE_2MB (0x000000000000000aULL) +#define ROGUE_MMUCTRL_PD_DATA_VALID_SHIFT (0U) +#define ROGUE_MMUCTRL_PD_DATA_VALID_CLRMSK (0xFFFFFFFFFFFFFFFEULL) +#define ROGUE_MMUCTRL_PD_DATA_VALID_EN (0x0000000000000001ULL) + +#define ROGUE_MMUCTRL_PC_DATA_PD_BASE_SHIFT (4U) +#define ROGUE_MMUCTRL_PC_DATA_PD_BASE_CLRMSK (0x0000000FU) +#define ROGUE_MMUCTRL_PC_DATA_PD_BASE_ALIGNSHIFT (12U) +#define ROGUE_MMUCTRL_PC_DATA_PD_BASE_ALIGNSIZE (4096U) +#define ROGUE_MMUCTRL_PC_DATA_ENTRY_PENDING_SHIFT (1U) +#define ROGUE_MMUCTRL_PC_DATA_ENTRY_PENDING_CLRMSK (0xFFFFFFFDU) +#define ROGUE_MMUCTRL_PC_DATA_ENTRY_PENDING_EN (0x00000002U) +#define ROGUE_MMUCTRL_PC_DATA_VALID_SHIFT (0U) +#define ROGUE_MMUCTRL_PC_DATA_VALID_CLRMSK (0xFFFFFFFEU) +#define ROGUE_MMUCTRL_PC_DATA_VALID_EN (0x00000001U) + +#endif /* PVR_ROGUE_MMU_DEFS_H */ diff --git a/drivers/gpu/drm/imagination/pvr_stream.c b/drivers/gpu/drm/imagination/pvr_stream.c new file mode 100644 index 00000000000000..975336a4facfd0 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_stream.c @@ -0,0 +1,285 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_device.h" +#include "pvr_rogue_fwif_stream.h" +#include "pvr_stream.h" + +#include +#include +#include +#include + +static __always_inline bool +stream_def_is_supported(struct pvr_device *pvr_dev, const struct pvr_stream_def *stream_def) +{ + if (stream_def->feature == PVR_FEATURE_NONE) + return true; + + if (!(stream_def->feature & PVR_FEATURE_NOT) && + pvr_device_has_feature(pvr_dev, stream_def->feature)) { + return true; + } + + if ((stream_def->feature & PVR_FEATURE_NOT) && + !pvr_device_has_feature(pvr_dev, stream_def->feature & ~PVR_FEATURE_NOT)) { + return true; + } + + return false; +} + +static int +pvr_stream_get_data(u8 *stream, u32 *stream_offset, u32 stream_size, u32 data_size, u32 align_size, + void *dest) +{ + *stream_offset = ALIGN(*stream_offset, align_size); + + if ((*stream_offset + data_size) > stream_size) + return -EINVAL; + + memcpy(dest, stream + *stream_offset, data_size); + + (*stream_offset) += data_size; + + return 0; +} + +/** + * pvr_stream_process_1() - Process a single stream and fill destination structure + * @pvr_dev: Device pointer. + * @stream_def: Stream definition. + * @nr_entries: Number of entries in &stream_def. + * @stream: Pointer to stream. + * @stream_offset: Starting offset within stream. + * @stream_size: Size of input stream, in bytes. + * @dest: Pointer to destination structure. + * @dest_size: Size of destination structure. + * @stream_offset_out: Pointer to variable to write updated stream offset to. May be NULL. + * + * Returns: + * * 0 on success, or + * * -%EINVAL on malformed stream. + */ +static int +pvr_stream_process_1(struct pvr_device *pvr_dev, const struct pvr_stream_def *stream_def, + u32 nr_entries, u8 *stream, u32 stream_offset, u32 stream_size, + u8 *dest, u32 dest_size, u32 *stream_offset_out) +{ + int err = 0; + u32 i; + + for (i = 0; i < nr_entries; i++) { + if (stream_def[i].offset >= dest_size) { + err = -EINVAL; + break; + } + + if (!stream_def_is_supported(pvr_dev, &stream_def[i])) + continue; + + switch (stream_def[i].size) { + case PVR_STREAM_SIZE_8: + err = pvr_stream_get_data(stream, &stream_offset, stream_size, sizeof(u8), + sizeof(u8), dest + stream_def[i].offset); + if (err) + return err; + break; + + case PVR_STREAM_SIZE_16: + err = pvr_stream_get_data(stream, &stream_offset, stream_size, sizeof(u16), + sizeof(u16), dest + stream_def[i].offset); + if (err) + return err; + break; + + case PVR_STREAM_SIZE_32: + err = pvr_stream_get_data(stream, &stream_offset, stream_size, sizeof(u32), + sizeof(u32), dest + stream_def[i].offset); + if (err) + return err; + break; + + case PVR_STREAM_SIZE_64: + err = pvr_stream_get_data(stream, &stream_offset, stream_size, sizeof(u64), + sizeof(u64), dest + stream_def[i].offset); + if (err) + return err; + break; + + case PVR_STREAM_SIZE_ARRAY: + err = pvr_stream_get_data(stream, &stream_offset, stream_size, + stream_def[i].array_size, sizeof(u64), + dest + stream_def[i].offset); + if (err) + return err; + break; + } + } + + if (stream_offset_out) + *stream_offset_out = stream_offset; + + return err; +} + +static int +pvr_stream_process_ext_stream(struct pvr_device *pvr_dev, + const struct pvr_stream_cmd_defs *cmd_defs, void *ext_stream, + u32 stream_offset, u32 ext_stream_size, void *dest) +{ + u32 musthave_masks[PVR_STREAM_EXTHDR_TYPE_MAX]; + u32 ext_header; + int err = 0; + u32 i; + + /* Copy "must have" mask from device. We clear this as we process the stream. */ + memcpy(musthave_masks, pvr_dev->stream_musthave_quirks[cmd_defs->type], + sizeof(musthave_masks)); + + do { + const struct pvr_stream_ext_header *header; + u32 type; + u32 data; + + err = pvr_stream_get_data(ext_stream, &stream_offset, ext_stream_size, sizeof(u32), + sizeof(ext_header), &ext_header); + if (err) + return err; + + type = (ext_header & PVR_STREAM_EXTHDR_TYPE_MASK) >> PVR_STREAM_EXTHDR_TYPE_SHIFT; + data = ext_header & PVR_STREAM_EXTHDR_DATA_MASK; + + if (type >= cmd_defs->ext_nr_headers) + return -EINVAL; + + header = &cmd_defs->ext_headers[type]; + if (data & ~header->valid_mask) + return -EINVAL; + + musthave_masks[type] &= ~data; + + for (i = 0; i < header->ext_streams_num; i++) { + const struct pvr_stream_ext_def *ext_def = &header->ext_streams[i]; + + if (!(ext_header & ext_def->header_mask)) + continue; + + if (!pvr_device_has_uapi_quirk(pvr_dev, ext_def->quirk)) + return -EINVAL; + + err = pvr_stream_process_1(pvr_dev, ext_def->stream, ext_def->stream_len, + ext_stream, stream_offset, + ext_stream_size, dest, + cmd_defs->dest_size, &stream_offset); + if (err) + return err; + } + } while (ext_header & PVR_STREAM_EXTHDR_CONTINUATION); + + /* + * Verify that "must have" mask is now zero. If it isn't then one of the "must have" quirks + * for this command was not present. + */ + for (i = 0; i < cmd_defs->ext_nr_headers; i++) { + if (musthave_masks[i]) + return -EINVAL; + } + + return 0; +} + +/** + * pvr_stream_process() - Build FW structure from stream + * @pvr_dev: Device pointer. + * @cmd_defs: Stream definition. + * @stream: Pointer to command stream. + * @stream_size: Size of command stream, in bytes. + * @dest_out: Pointer to destination buffer. + * + * Caller is responsible for freeing the output structure. + * + * Returns: + * * 0 on success, + * * -%ENOMEM on out of memory, or + * * -%EINVAL on malformed stream. + */ +int +pvr_stream_process(struct pvr_device *pvr_dev, const struct pvr_stream_cmd_defs *cmd_defs, + void *stream, u32 stream_size, void *dest_out) +{ + u32 stream_offset = 0; + u32 main_stream_len; + u32 padding; + int err; + + if (!stream || !stream_size) + return -EINVAL; + + err = pvr_stream_get_data(stream, &stream_offset, stream_size, sizeof(u32), + sizeof(u32), &main_stream_len); + if (err) + return err; + + /* + * u32 after stream length is padding to ensure u64 alignment, but may be used for expansion + * in the future. Verify it's zero. + */ + err = pvr_stream_get_data(stream, &stream_offset, stream_size, sizeof(u32), + sizeof(u32), &padding); + if (err) + return err; + + if (main_stream_len < stream_offset || main_stream_len > stream_size || padding) + return -EINVAL; + + err = pvr_stream_process_1(pvr_dev, cmd_defs->main_stream, cmd_defs->main_stream_len, + stream, stream_offset, main_stream_len, dest_out, + cmd_defs->dest_size, &stream_offset); + if (err) + return err; + + if (stream_offset < stream_size) { + err = pvr_stream_process_ext_stream(pvr_dev, cmd_defs, stream, stream_offset, + stream_size, dest_out); + if (err) + return err; + } else { + u32 i; + + /* + * If we don't have an extension stream then there must not be any "must have" + * quirks for this command. + */ + for (i = 0; i < cmd_defs->ext_nr_headers; i++) { + if (pvr_dev->stream_musthave_quirks[cmd_defs->type][i]) + return -EINVAL; + } + } + + return 0; +} + +/** + * pvr_stream_create_musthave_masks() - Create "must have" masks for streams based on current device + * quirks + * @pvr_dev: Device pointer. + */ +void +pvr_stream_create_musthave_masks(struct pvr_device *pvr_dev) +{ + memset(pvr_dev->stream_musthave_quirks, 0, sizeof(pvr_dev->stream_musthave_quirks)); + + if (pvr_device_has_uapi_quirk(pvr_dev, 47217)) + pvr_dev->stream_musthave_quirks[PVR_STREAM_TYPE_FRAG][0] |= + PVR_STREAM_EXTHDR_FRAG0_BRN47217; + + if (pvr_device_has_uapi_quirk(pvr_dev, 49927)) { + pvr_dev->stream_musthave_quirks[PVR_STREAM_TYPE_GEOM][0] |= + PVR_STREAM_EXTHDR_GEOM0_BRN49927; + pvr_dev->stream_musthave_quirks[PVR_STREAM_TYPE_FRAG][0] |= + PVR_STREAM_EXTHDR_FRAG0_BRN49927; + pvr_dev->stream_musthave_quirks[PVR_STREAM_TYPE_COMPUTE][0] |= + PVR_STREAM_EXTHDR_COMPUTE0_BRN49927; + } +} diff --git a/drivers/gpu/drm/imagination/pvr_stream.h b/drivers/gpu/drm/imagination/pvr_stream.h new file mode 100644 index 00000000000000..d92acb3a61d7f7 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_stream.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_STREAM_H +#define PVR_STREAM_H + +#include +#include +#include + +struct pvr_device; + +struct pvr_job; + +enum pvr_stream_type { + PVR_STREAM_TYPE_GEOM = 0, + PVR_STREAM_TYPE_FRAG, + PVR_STREAM_TYPE_COMPUTE, + PVR_STREAM_TYPE_TRANSFER, + PVR_STREAM_TYPE_STATIC_RENDER_CONTEXT, + PVR_STREAM_TYPE_STATIC_COMPUTE_CONTEXT, + + PVR_STREAM_TYPE_MAX +}; + +enum pvr_stream_size { + PVR_STREAM_SIZE_8 = 0, + PVR_STREAM_SIZE_16, + PVR_STREAM_SIZE_32, + PVR_STREAM_SIZE_64, + PVR_STREAM_SIZE_ARRAY, +}; + +#define PVR_FEATURE_NOT BIT(31) +#define PVR_FEATURE_NONE U32_MAX + +struct pvr_stream_def { + u32 offset; + enum pvr_stream_size size; + u32 array_size; + u32 feature; +}; + +struct pvr_stream_ext_def { + const struct pvr_stream_def *stream; + u32 stream_len; + u32 header_mask; + u32 quirk; +}; + +struct pvr_stream_ext_header { + const struct pvr_stream_ext_def *ext_streams; + u32 ext_streams_num; + u32 valid_mask; +}; + +struct pvr_stream_cmd_defs { + enum pvr_stream_type type; + + const struct pvr_stream_def *main_stream; + u32 main_stream_len; + + u32 ext_nr_headers; + const struct pvr_stream_ext_header *ext_headers; + + size_t dest_size; +}; + +int +pvr_stream_process(struct pvr_device *pvr_dev, const struct pvr_stream_cmd_defs *cmd_defs, + void *stream, u32 stream_size, void *dest_out); +void +pvr_stream_create_musthave_masks(struct pvr_device *pvr_dev); + +#endif /* PVR_STREAM_H */ diff --git a/drivers/gpu/drm/imagination/pvr_stream_defs.c b/drivers/gpu/drm/imagination/pvr_stream_defs.c new file mode 100644 index 00000000000000..f8bd1a8c01db48 --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_stream_defs.c @@ -0,0 +1,351 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_device_info.h" +#include "pvr_rogue_fwif_client.h" +#include "pvr_rogue_fwif_stream.h" +#include "pvr_stream.h" +#include "pvr_stream_defs.h" + +#include +#include + +#define PVR_STREAM_DEF_SET(owner, member, _size, _array_size, _feature) \ + { .offset = offsetof(struct owner, member), \ + .size = (_size), \ + .array_size = (_array_size), \ + .feature = (_feature) } + +#define PVR_STREAM_DEF(owner, member, member_size) \ + PVR_STREAM_DEF_SET(owner, member, PVR_STREAM_SIZE_ ## member_size, 0, PVR_FEATURE_NONE) + +#define PVR_STREAM_DEF_FEATURE(owner, member, member_size, feature) \ + PVR_STREAM_DEF_SET(owner, member, PVR_STREAM_SIZE_ ## member_size, 0, feature) + +#define PVR_STREAM_DEF_NOT_FEATURE(owner, member, member_size, feature) \ + PVR_STREAM_DEF_SET(owner, member, PVR_STREAM_SIZE_ ## member_size, 0, \ + (feature) | PVR_FEATURE_NOT) + +#define PVR_STREAM_DEF_ARRAY(owner, member) \ + PVR_STREAM_DEF_SET(owner, member, PVR_STREAM_SIZE_ARRAY, \ + sizeof(((struct owner *)0)->member), PVR_FEATURE_NONE) + +#define PVR_STREAM_DEF_ARRAY_FEATURE(owner, member, feature) \ + PVR_STREAM_DEF_SET(owner, member, PVR_STREAM_SIZE_ARRAY, \ + sizeof(((struct owner *)0)->member), feature) + +#define PVR_STREAM_DEF_ARRAY_NOT_FEATURE(owner, member, feature) \ + PVR_STREAM_DEF_SET(owner, member, PVR_STREAM_SIZE_ARRAY, \ + sizeof(((struct owner *)0)->member), (feature) | PVR_FEATURE_NOT) + +/* + * When adding new parameters to the stream definition, the new parameters must go after the + * existing parameters, to preserve order. As parameters are naturally aligned, care must be taken + * with respect to implicit padding in the stream; padding should be minimised as much as possible. + */ +static const struct pvr_stream_def rogue_fwif_cmd_geom_stream[] = { + PVR_STREAM_DEF(rogue_fwif_cmd_geom, regs.vdm_ctrl_stream_base, 64), + PVR_STREAM_DEF(rogue_fwif_cmd_geom, regs.tpu_border_colour_table, 64), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_geom, regs.vdm_draw_indirect0, 64, + PVR_FEATURE_VDM_DRAWINDIRECT), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_geom, regs.vdm_draw_indirect1, 32, + PVR_FEATURE_VDM_DRAWINDIRECT), + PVR_STREAM_DEF(rogue_fwif_cmd_geom, regs.ppp_ctrl, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_geom, regs.te_psg, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_geom, regs.vdm_context_resume_task0_size, 32), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_geom, regs.vdm_context_resume_task3_size, 32, + PVR_FEATURE_VDM_OBJECT_LEVEL_LLS), + PVR_STREAM_DEF(rogue_fwif_cmd_geom, regs.view_idx, 32), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_geom, regs.pds_coeff_free_prog, 32, + PVR_FEATURE_TESSELLATION), +}; + +static const struct pvr_stream_def rogue_fwif_cmd_geom_stream_brn49927[] = { + PVR_STREAM_DEF(rogue_fwif_cmd_geom, regs.tpu, 32), +}; + +static const struct pvr_stream_ext_def cmd_geom_ext_streams_0[] = { + { + .stream = rogue_fwif_cmd_geom_stream_brn49927, + .stream_len = ARRAY_SIZE(rogue_fwif_cmd_geom_stream_brn49927), + .header_mask = PVR_STREAM_EXTHDR_GEOM0_BRN49927, + .quirk = 49927, + }, +}; + +static const struct pvr_stream_ext_header cmd_geom_ext_headers[] = { + { + .ext_streams = cmd_geom_ext_streams_0, + .ext_streams_num = ARRAY_SIZE(cmd_geom_ext_streams_0), + .valid_mask = PVR_STREAM_EXTHDR_GEOM0_VALID, + }, +}; + +const struct pvr_stream_cmd_defs pvr_cmd_geom_stream = { + .type = PVR_STREAM_TYPE_GEOM, + + .main_stream = rogue_fwif_cmd_geom_stream, + .main_stream_len = ARRAY_SIZE(rogue_fwif_cmd_geom_stream), + + .ext_nr_headers = ARRAY_SIZE(cmd_geom_ext_headers), + .ext_headers = cmd_geom_ext_headers, + + .dest_size = sizeof(struct rogue_fwif_cmd_geom), +}; + +static const struct pvr_stream_def rogue_fwif_cmd_frag_stream[] = { + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.isp_scissor_base, 64), + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.isp_dbias_base, 64), + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.isp_oclqry_base, 64), + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.isp_zlsctl, 64), + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.isp_zload_store_base, 64), + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.isp_stencil_load_store_base, 64), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_frag, regs.fb_cdc_zls, 64, + PVR_FEATURE_REQUIRES_FB_CDC_ZLS_SETUP), + PVR_STREAM_DEF_ARRAY(rogue_fwif_cmd_frag, regs.pbe_word), + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.tpu_border_colour_table, 64), + PVR_STREAM_DEF_ARRAY(rogue_fwif_cmd_frag, regs.pds_bgnd), + PVR_STREAM_DEF_ARRAY(rogue_fwif_cmd_frag, regs.pds_pr_bgnd), + PVR_STREAM_DEF_ARRAY(rogue_fwif_cmd_frag, regs.usc_clear_register), + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.usc_pixel_output_ctrl, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.isp_bgobjdepth, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.isp_bgobjvals, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.isp_aa, 32), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_frag, regs.isp_xtp_pipe_enable, 32, + PVR_FEATURE_S7_TOP_INFRASTRUCTURE), + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.isp_ctl, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.event_pixel_pds_info, 32), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_frag, regs.pixel_phantom, 32, + PVR_FEATURE_CLUSTER_GROUPING), + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.view_idx, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.event_pixel_pds_data, 32), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_frag, regs.isp_oclqry_stride, 32, + PVR_FEATURE_GPU_MULTICORE_SUPPORT), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_frag, regs.isp_zls_pixels, 32, + PVR_FEATURE_ZLS_SUBTILE), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_frag, regs.rgx_cr_blackpearl_fix, 32, + PVR_FEATURE_ISP_ZLS_D24_S8_PACKING_OGL_MODE), + PVR_STREAM_DEF(rogue_fwif_cmd_frag, zls_stride, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_frag, sls_stride, 32), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_frag, execute_count, 32, + PVR_FEATURE_GPU_MULTICORE_SUPPORT), +}; + +static const struct pvr_stream_def rogue_fwif_cmd_frag_stream_brn47217[] = { + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.isp_oclqry_stride, 32), +}; + +static const struct pvr_stream_def rogue_fwif_cmd_frag_stream_brn49927[] = { + PVR_STREAM_DEF(rogue_fwif_cmd_frag, regs.tpu, 32), +}; + +static const struct pvr_stream_ext_def cmd_frag_ext_streams_0[] = { + { + .stream = rogue_fwif_cmd_frag_stream_brn47217, + .stream_len = ARRAY_SIZE(rogue_fwif_cmd_frag_stream_brn47217), + .header_mask = PVR_STREAM_EXTHDR_FRAG0_BRN47217, + .quirk = 47217, + }, + { + .stream = rogue_fwif_cmd_frag_stream_brn49927, + .stream_len = ARRAY_SIZE(rogue_fwif_cmd_frag_stream_brn49927), + .header_mask = PVR_STREAM_EXTHDR_FRAG0_BRN49927, + .quirk = 49927, + }, +}; + +static const struct pvr_stream_ext_header cmd_frag_ext_headers[] = { + { + .ext_streams = cmd_frag_ext_streams_0, + .ext_streams_num = ARRAY_SIZE(cmd_frag_ext_streams_0), + .valid_mask = PVR_STREAM_EXTHDR_FRAG0_VALID, + }, +}; + +const struct pvr_stream_cmd_defs pvr_cmd_frag_stream = { + .type = PVR_STREAM_TYPE_FRAG, + + .main_stream = rogue_fwif_cmd_frag_stream, + .main_stream_len = ARRAY_SIZE(rogue_fwif_cmd_frag_stream), + + .ext_nr_headers = ARRAY_SIZE(cmd_frag_ext_headers), + .ext_headers = cmd_frag_ext_headers, + + .dest_size = sizeof(struct rogue_fwif_cmd_frag), +}; + +static const struct pvr_stream_def rogue_fwif_cmd_compute_stream[] = { + PVR_STREAM_DEF(rogue_fwif_cmd_compute, regs.tpu_border_colour_table, 64), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_compute, regs.cdm_cb_queue, 64, + PVR_FEATURE_CDM_USER_MODE_QUEUE), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_compute, regs.cdm_cb_base, 64, + PVR_FEATURE_CDM_USER_MODE_QUEUE), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_compute, regs.cdm_cb, 64, + PVR_FEATURE_CDM_USER_MODE_QUEUE), + PVR_STREAM_DEF_NOT_FEATURE(rogue_fwif_cmd_compute, regs.cdm_ctrl_stream_base, 64, + PVR_FEATURE_CDM_USER_MODE_QUEUE), + PVR_STREAM_DEF(rogue_fwif_cmd_compute, regs.cdm_context_state_base_addr, 64), + PVR_STREAM_DEF(rogue_fwif_cmd_compute, regs.cdm_resume_pds1, 32), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_compute, regs.cdm_item, 32, + PVR_FEATURE_COMPUTE_MORTON_CAPABLE), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_compute, regs.compute_cluster, 32, + PVR_FEATURE_CLUSTER_GROUPING), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_compute, regs.tpu_tag_cdm_ctrl, 32, + PVR_FEATURE_TPU_DM_GLOBAL_REGISTERS), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_compute, stream_start_offset, 32, + PVR_FEATURE_CDM_USER_MODE_QUEUE), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_compute, execute_count, 32, + PVR_FEATURE_GPU_MULTICORE_SUPPORT), +}; + +static const struct pvr_stream_def rogue_fwif_cmd_compute_stream_brn49927[] = { + PVR_STREAM_DEF(rogue_fwif_cmd_compute, regs.tpu, 32), +}; + +static const struct pvr_stream_ext_def cmd_compute_ext_streams_0[] = { + { + .stream = rogue_fwif_cmd_compute_stream_brn49927, + .stream_len = ARRAY_SIZE(rogue_fwif_cmd_compute_stream_brn49927), + .header_mask = PVR_STREAM_EXTHDR_COMPUTE0_BRN49927, + .quirk = 49927, + }, +}; + +static const struct pvr_stream_ext_header cmd_compute_ext_headers[] = { + { + .ext_streams = cmd_compute_ext_streams_0, + .ext_streams_num = ARRAY_SIZE(cmd_compute_ext_streams_0), + .valid_mask = PVR_STREAM_EXTHDR_COMPUTE0_VALID, + }, +}; + +const struct pvr_stream_cmd_defs pvr_cmd_compute_stream = { + .type = PVR_STREAM_TYPE_COMPUTE, + + .main_stream = rogue_fwif_cmd_compute_stream, + .main_stream_len = ARRAY_SIZE(rogue_fwif_cmd_compute_stream), + + .ext_nr_headers = ARRAY_SIZE(cmd_compute_ext_headers), + .ext_headers = cmd_compute_ext_headers, + + .dest_size = sizeof(struct rogue_fwif_cmd_compute), +}; + +static const struct pvr_stream_def rogue_fwif_cmd_transfer_stream[] = { + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.pds_bgnd0_base, 64), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.pds_bgnd1_base, 64), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.pds_bgnd3_sizeinfo, 64), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.isp_mtile_base, 64), + PVR_STREAM_DEF_ARRAY(rogue_fwif_cmd_transfer, regs.pbe_wordx_mrty), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.isp_bgobjvals, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.usc_pixel_output_ctrl, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.usc_clear_register0, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.usc_clear_register1, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.usc_clear_register2, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.usc_clear_register3, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.isp_mtile_size, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.isp_render_origin, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.isp_ctl, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.isp_aa, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.event_pixel_pds_info, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.event_pixel_pds_code, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.event_pixel_pds_data, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.isp_render, 32), + PVR_STREAM_DEF(rogue_fwif_cmd_transfer, regs.isp_rgn, 32), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_transfer, regs.isp_xtp_pipe_enable, 32, + PVR_FEATURE_S7_TOP_INFRASTRUCTURE), + PVR_STREAM_DEF_FEATURE(rogue_fwif_cmd_transfer, regs.frag_screen, 32, + PVR_FEATURE_GPU_MULTICORE_SUPPORT), +}; + +const struct pvr_stream_cmd_defs pvr_cmd_transfer_stream = { + .type = PVR_STREAM_TYPE_TRANSFER, + + .main_stream = rogue_fwif_cmd_transfer_stream, + .main_stream_len = ARRAY_SIZE(rogue_fwif_cmd_transfer_stream), + + .ext_nr_headers = 0, + + .dest_size = sizeof(struct rogue_fwif_cmd_transfer), +}; + +static const struct pvr_stream_def rogue_fwif_static_render_context_state_stream[] = { + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_reg_vdm_context_state_base_addr, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_reg_vdm_context_state_resume_addr, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_reg_ta_context_state_base_addr, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_store_task0, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_store_task1, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_store_task2, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_store_task3, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_store_task4, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_resume_task0, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_resume_task1, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_resume_task2, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_resume_task3, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[0].geom_reg_vdm_context_resume_task4, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_store_task0, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_store_task1, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_store_task2, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_store_task3, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_store_task4, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_resume_task0, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_resume_task1, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_resume_task2, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_resume_task3, 64), + PVR_STREAM_DEF(rogue_fwif_geom_registers_caswitch, + geom_state[1].geom_reg_vdm_context_resume_task4, 64), +}; + +const struct pvr_stream_cmd_defs pvr_static_render_context_state_stream = { + .type = PVR_STREAM_TYPE_STATIC_RENDER_CONTEXT, + + .main_stream = rogue_fwif_static_render_context_state_stream, + .main_stream_len = ARRAY_SIZE(rogue_fwif_static_render_context_state_stream), + + .ext_nr_headers = 0, + + .dest_size = sizeof(struct rogue_fwif_geom_registers_caswitch), +}; + +static const struct pvr_stream_def rogue_fwif_static_compute_context_state_stream[] = { + PVR_STREAM_DEF(rogue_fwif_cdm_registers_cswitch, cdmreg_cdm_context_pds0, 64), + PVR_STREAM_DEF(rogue_fwif_cdm_registers_cswitch, cdmreg_cdm_context_pds1, 64), + PVR_STREAM_DEF(rogue_fwif_cdm_registers_cswitch, cdmreg_cdm_terminate_pds, 64), + PVR_STREAM_DEF(rogue_fwif_cdm_registers_cswitch, cdmreg_cdm_terminate_pds1, 64), + PVR_STREAM_DEF(rogue_fwif_cdm_registers_cswitch, cdmreg_cdm_resume_pds0, 64), + PVR_STREAM_DEF(rogue_fwif_cdm_registers_cswitch, cdmreg_cdm_context_pds0_b, 64), + PVR_STREAM_DEF(rogue_fwif_cdm_registers_cswitch, cdmreg_cdm_resume_pds0_b, 64), +}; + +const struct pvr_stream_cmd_defs pvr_static_compute_context_state_stream = { + .type = PVR_STREAM_TYPE_STATIC_COMPUTE_CONTEXT, + + .main_stream = rogue_fwif_static_compute_context_state_stream, + .main_stream_len = ARRAY_SIZE(rogue_fwif_static_compute_context_state_stream), + + .ext_nr_headers = 0, + + .dest_size = sizeof(struct rogue_fwif_cdm_registers_cswitch), +}; diff --git a/drivers/gpu/drm/imagination/pvr_stream_defs.h b/drivers/gpu/drm/imagination/pvr_stream_defs.h new file mode 100644 index 00000000000000..f33b821658334f --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_stream_defs.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_STREAM_DEFS_H +#define PVR_STREAM_DEFS_H + +#include "pvr_stream.h" + +extern const struct pvr_stream_cmd_defs pvr_cmd_geom_stream; +extern const struct pvr_stream_cmd_defs pvr_cmd_frag_stream; +extern const struct pvr_stream_cmd_defs pvr_cmd_compute_stream; +extern const struct pvr_stream_cmd_defs pvr_cmd_transfer_stream; +extern const struct pvr_stream_cmd_defs pvr_static_render_context_state_stream; +extern const struct pvr_stream_cmd_defs pvr_static_compute_context_state_stream; + +#endif /* PVR_STREAM_DEFS_H */ diff --git a/drivers/gpu/drm/imagination/pvr_sync.c b/drivers/gpu/drm/imagination/pvr_sync.c new file mode 100644 index 00000000000000..129f646d14ba1c --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_sync.c @@ -0,0 +1,289 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include + +#include +#include +#include +#include + +#include "pvr_device.h" +#include "pvr_queue.h" +#include "pvr_sync.h" + +static int +pvr_check_sync_op(const struct drm_pvr_sync_op *sync_op) +{ + u8 handle_type; + + if (sync_op->flags & ~DRM_PVR_SYNC_OP_FLAGS_MASK) + return -EINVAL; + + handle_type = sync_op->flags & DRM_PVR_SYNC_OP_FLAG_HANDLE_TYPE_MASK; + if (handle_type != DRM_PVR_SYNC_OP_FLAG_HANDLE_TYPE_SYNCOBJ && + handle_type != DRM_PVR_SYNC_OP_FLAG_HANDLE_TYPE_TIMELINE_SYNCOBJ) + return -EINVAL; + + if (handle_type == DRM_PVR_SYNC_OP_FLAG_HANDLE_TYPE_SYNCOBJ && + sync_op->value != 0) + return -EINVAL; + + return 0; +} + +static void +pvr_sync_signal_free(struct pvr_sync_signal *sig_sync) +{ + if (!sig_sync) + return; + + drm_syncobj_put(sig_sync->syncobj); + dma_fence_chain_free(sig_sync->chain); + dma_fence_put(sig_sync->fence); + kfree(sig_sync); +} + +void +pvr_sync_signal_array_cleanup(struct xarray *array) +{ + struct pvr_sync_signal *sig_sync; + unsigned long i; + + xa_for_each(array, i, sig_sync) + pvr_sync_signal_free(sig_sync); + + xa_destroy(array); +} + +static struct pvr_sync_signal * +pvr_sync_signal_array_add(struct xarray *array, struct drm_file *file, u32 handle, u64 point) +{ + struct pvr_sync_signal *sig_sync; + struct dma_fence *cur_fence; + int err; + u32 id; + + sig_sync = kzalloc(sizeof(*sig_sync), GFP_KERNEL); + if (!sig_sync) + return ERR_PTR(-ENOMEM); + + sig_sync->handle = handle; + sig_sync->point = point; + + if (point > 0) { + sig_sync->chain = dma_fence_chain_alloc(); + if (!sig_sync->chain) { + err = -ENOMEM; + goto err_free_sig_sync; + } + } + + sig_sync->syncobj = drm_syncobj_find(file, handle); + if (!sig_sync->syncobj) { + err = -EINVAL; + goto err_free_sig_sync; + } + + /* Retrieve the current fence attached to that point. It's + * perfectly fine to get a NULL fence here, it just means there's + * no fence attached to that point yet. + */ + if (!drm_syncobj_find_fence(file, handle, point, 0, &cur_fence)) + sig_sync->fence = cur_fence; + + err = xa_alloc(array, &id, sig_sync, xa_limit_32b, GFP_KERNEL); + if (err) + goto err_free_sig_sync; + + return sig_sync; + +err_free_sig_sync: + pvr_sync_signal_free(sig_sync); + return ERR_PTR(err); +} + +static struct pvr_sync_signal * +pvr_sync_signal_array_search(struct xarray *array, u32 handle, u64 point) +{ + struct pvr_sync_signal *sig_sync; + unsigned long i; + + xa_for_each(array, i, sig_sync) { + if (handle == sig_sync->handle && point == sig_sync->point) + return sig_sync; + } + + return NULL; +} + +static struct pvr_sync_signal * +pvr_sync_signal_array_get(struct xarray *array, struct drm_file *file, u32 handle, u64 point) +{ + struct pvr_sync_signal *sig_sync; + + sig_sync = pvr_sync_signal_array_search(array, handle, point); + if (sig_sync) + return sig_sync; + + return pvr_sync_signal_array_add(array, file, handle, point); +} + +int +pvr_sync_signal_array_collect_ops(struct xarray *array, + struct drm_file *file, + u32 sync_op_count, + const struct drm_pvr_sync_op *sync_ops) +{ + for (u32 i = 0; i < sync_op_count; i++) { + struct pvr_sync_signal *sig_sync; + int ret; + + if (!(sync_ops[i].flags & DRM_PVR_SYNC_OP_FLAG_SIGNAL)) + continue; + + ret = pvr_check_sync_op(&sync_ops[i]); + if (ret) + return ret; + + sig_sync = pvr_sync_signal_array_get(array, file, + sync_ops[i].handle, + sync_ops[i].value); + if (IS_ERR(sig_sync)) + return PTR_ERR(sig_sync); + } + + return 0; +} + +int +pvr_sync_signal_array_update_fences(struct xarray *array, + u32 sync_op_count, + const struct drm_pvr_sync_op *sync_ops, + struct dma_fence *done_fence) +{ + for (u32 i = 0; i < sync_op_count; i++) { + struct dma_fence *old_fence; + struct pvr_sync_signal *sig_sync; + + if (!(sync_ops[i].flags & DRM_PVR_SYNC_OP_FLAG_SIGNAL)) + continue; + + sig_sync = pvr_sync_signal_array_search(array, sync_ops[i].handle, + sync_ops[i].value); + if (WARN_ON(!sig_sync)) + return -EINVAL; + + old_fence = sig_sync->fence; + sig_sync->fence = dma_fence_get(done_fence); + dma_fence_put(old_fence); + + if (WARN_ON(!sig_sync->fence)) + return -EINVAL; + } + + return 0; +} + +void +pvr_sync_signal_array_push_fences(struct xarray *array) +{ + struct pvr_sync_signal *sig_sync; + unsigned long i; + + xa_for_each(array, i, sig_sync) { + if (sig_sync->chain) { + drm_syncobj_add_point(sig_sync->syncobj, sig_sync->chain, + sig_sync->fence, sig_sync->point); + sig_sync->chain = NULL; + } else { + drm_syncobj_replace_fence(sig_sync->syncobj, sig_sync->fence); + } + } +} + +static int +pvr_sync_add_dep_to_job(struct drm_sched_job *job, struct dma_fence *f) +{ + struct dma_fence_unwrap iter; + u32 native_fence_count = 0; + struct dma_fence *uf; + int err = 0; + + dma_fence_unwrap_for_each(uf, &iter, f) { + if (pvr_queue_fence_is_ufo_backed(uf)) + native_fence_count++; + } + + /* No need to unwrap the fence if it's fully non-native. */ + if (!native_fence_count) + return drm_sched_job_add_dependency(job, f); + + dma_fence_unwrap_for_each(uf, &iter, f) { + /* There's no dma_fence_unwrap_stop() helper cleaning up the refs + * owned by dma_fence_unwrap(), so let's just iterate over all + * entries without doing anything when something failed. + */ + if (err) + continue; + + if (pvr_queue_fence_is_ufo_backed(uf)) { + struct drm_sched_fence *s_fence = to_drm_sched_fence(uf); + + /* If this is a native dependency, we wait for the scheduled fence, + * and we will let pvr_queue_run_job() issue FW waits. + */ + err = drm_sched_job_add_dependency(job, + dma_fence_get(&s_fence->scheduled)); + } else { + err = drm_sched_job_add_dependency(job, dma_fence_get(uf)); + } + } + + dma_fence_put(f); + return err; +} + +int +pvr_sync_add_deps_to_job(struct pvr_file *pvr_file, struct drm_sched_job *job, + u32 sync_op_count, + const struct drm_pvr_sync_op *sync_ops, + struct xarray *signal_array) +{ + int err = 0; + + if (!sync_op_count) + return 0; + + for (u32 i = 0; i < sync_op_count; i++) { + struct pvr_sync_signal *sig_sync; + struct dma_fence *fence; + + if (sync_ops[i].flags & DRM_PVR_SYNC_OP_FLAG_SIGNAL) + continue; + + err = pvr_check_sync_op(&sync_ops[i]); + if (err) + return err; + + sig_sync = pvr_sync_signal_array_search(signal_array, sync_ops[i].handle, + sync_ops[i].value); + if (sig_sync) { + if (WARN_ON(!sig_sync->fence)) + return -EINVAL; + + fence = dma_fence_get(sig_sync->fence); + } else { + err = drm_syncobj_find_fence(from_pvr_file(pvr_file), sync_ops[i].handle, + sync_ops[i].value, 0, &fence); + if (err) + return err; + } + + err = pvr_sync_add_dep_to_job(job, fence); + if (err) + return err; + } + + return 0; +} diff --git a/drivers/gpu/drm/imagination/pvr_sync.h b/drivers/gpu/drm/imagination/pvr_sync.h new file mode 100644 index 00000000000000..db6ccfda104a3a --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_sync.h @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_SYNC_H +#define PVR_SYNC_H + +#include + +/* Forward declaration from . */ +struct xarray; + +/* Forward declaration from . */ +struct drm_file; + +/* Forward declaration from . */ +struct drm_sched_job; + +/* Forward declaration from "pvr_device.h". */ +struct pvr_file; + +/** + * struct pvr_sync_signal - Object encoding a syncobj signal operation + * + * The job submission logic collects all signal operations in an array of + * pvr_sync_signal objects. This array also serves as a cache to get the + * latest dma_fence when multiple jobs are submitted at once, and one job + * signals a syncobj point that's later waited on by a subsequent job. + */ +struct pvr_sync_signal { + /** @handle: Handle of the syncobj to signal. */ + u32 handle; + + /** + * @point: Point to signal in the syncobj. + * + * Only relevant for timeline syncobjs. + */ + u64 point; + + /** @syncobj: Syncobj retrieved from the handle. */ + struct drm_syncobj *syncobj; + + /** + * @chain: Chain object used to link the new fence with the + * existing timeline syncobj. + * + * Should be zero when manipulating a regular syncobj. + */ + struct dma_fence_chain *chain; + + /** + * @fence: New fence object to attach to the syncobj. + * + * This pointer starts with the current fence bound to + * the pair. + */ + struct dma_fence *fence; +}; + +void +pvr_sync_signal_array_cleanup(struct xarray *array); + +int +pvr_sync_signal_array_collect_ops(struct xarray *array, + struct drm_file *file, + u32 sync_op_count, + const struct drm_pvr_sync_op *sync_ops); + +int +pvr_sync_signal_array_update_fences(struct xarray *array, + u32 sync_op_count, + const struct drm_pvr_sync_op *sync_ops, + struct dma_fence *done_fence); + +void +pvr_sync_signal_array_push_fences(struct xarray *array); + +int +pvr_sync_add_deps_to_job(struct pvr_file *pvr_file, struct drm_sched_job *job, + u32 sync_op_count, + const struct drm_pvr_sync_op *sync_ops, + struct xarray *signal_array); + +#endif /* PVR_SYNC_H */ diff --git a/drivers/gpu/drm/imagination/pvr_vm.c b/drivers/gpu/drm/imagination/pvr_vm.c new file mode 100644 index 00000000000000..e59517ba039efd --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_vm.c @@ -0,0 +1,1090 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_vm.h" + +#include "pvr_device.h" +#include "pvr_drv.h" +#include "pvr_gem.h" +#include "pvr_mmu.h" +#include "pvr_rogue_fwif.h" +#include "pvr_rogue_heap_config.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/** + * DOC: Memory context + * + * This is the "top level" datatype in the VM code. It's exposed in the public + * API as an opaque handle. + */ + +/** + * struct pvr_vm_context - Context type used to represent a single VM. + */ +struct pvr_vm_context { + /** + * @pvr_dev: The PowerVR device to which this context is bound. + * This binding is immutable for the life of the context. + */ + struct pvr_device *pvr_dev; + + /** @mmu_ctx: The context for binding to physical memory. */ + struct pvr_mmu_context *mmu_ctx; + + /** @gpuvm_mgr: GPUVM object associated with this context. */ + struct drm_gpuvm gpuvm_mgr; + + /** @lock: Global lock on this VM. */ + struct mutex lock; + + /** + * @fw_mem_ctx_obj: Firmware object representing firmware memory + * context. + */ + struct pvr_fw_object *fw_mem_ctx_obj; + + /** @ref_count: Reference count of object. */ + struct kref ref_count; + + /** + * @dummy_gem: GEM object to enable VM reservation. All private BOs + * should use the @dummy_gem.resv and not their own _resv field. + */ + struct drm_gem_object dummy_gem; +}; + +static inline +struct pvr_vm_context *to_pvr_vm_context(struct drm_gpuvm *gpuvm) +{ + return container_of(gpuvm, struct pvr_vm_context, gpuvm_mgr); +} + +struct pvr_vm_context *pvr_vm_context_get(struct pvr_vm_context *vm_ctx) +{ + if (vm_ctx) + kref_get(&vm_ctx->ref_count); + + return vm_ctx; +} + +/** + * pvr_vm_get_page_table_root_addr() - Get the DMA address of the root of the + * page table structure behind a VM context. + * @vm_ctx: Target VM context. + */ +dma_addr_t pvr_vm_get_page_table_root_addr(struct pvr_vm_context *vm_ctx) +{ + return pvr_mmu_get_root_table_dma_addr(vm_ctx->mmu_ctx); +} + +/** + * pvr_vm_get_dma_resv() - Expose the dma_resv owned by the VM context. + * @vm_ctx: Target VM context. + * + * This is used to allow private BOs to share a dma_resv for faster fence + * updates. + * + * Returns: The dma_resv pointer. + */ +struct dma_resv *pvr_vm_get_dma_resv(struct pvr_vm_context *vm_ctx) +{ + return vm_ctx->dummy_gem.resv; +} + +/** + * DOC: Memory mappings + */ + +/** + * struct pvr_vm_gpuva - Wrapper type representing a single VM mapping. + */ +struct pvr_vm_gpuva { + /** @base: The wrapped drm_gpuva object. */ + struct drm_gpuva base; +}; + +enum pvr_vm_bind_type { + PVR_VM_BIND_TYPE_MAP, + PVR_VM_BIND_TYPE_UNMAP, +}; + +/** + * struct pvr_vm_bind_op - Context of a map/unmap operation. + */ +struct pvr_vm_bind_op { + /** @type: Map or unmap. */ + enum pvr_vm_bind_type type; + + /** @pvr_obj: Object associated with mapping (map only). */ + struct pvr_gem_object *pvr_obj; + + /** + * @vm_ctx: VM context where the mapping will be created or destroyed. + */ + struct pvr_vm_context *vm_ctx; + + /** @mmu_op_ctx: MMU op context. */ + struct pvr_mmu_op_context *mmu_op_ctx; + + /** @gpuvm_bo: Prealloced wrapped BO for attaching to the gpuvm. */ + struct drm_gpuvm_bo *gpuvm_bo; + + /** + * @new_va: Prealloced VA mapping object (init in callback). + * Used when creating a mapping. + */ + struct pvr_vm_gpuva *new_va; + + /** + * @prev_va: Prealloced VA mapping object (init in callback). + * Used when a mapping or unmapping operation overlaps an existing + * mapping and splits away the beginning into a new mapping. + */ + struct pvr_vm_gpuva *prev_va; + + /** + * @next_va: Prealloced VA mapping object (init in callback). + * Used when a mapping or unmapping operation overlaps an existing + * mapping and splits away the end into a new mapping. + */ + struct pvr_vm_gpuva *next_va; + + /** @offset: Offset into @pvr_obj to begin mapping from. */ + u64 offset; + + /** @device_addr: Device-virtual address at the start of the mapping. */ + u64 device_addr; + + /** @size: Size of the desired mapping. */ + u64 size; +}; + +/** + * pvr_vm_bind_op_exec() - Execute a single bind op. + * @bind_op: Bind op context. + * + * Returns: + * * 0 on success, + * * Any error code returned by drm_gpuva_sm_map(), drm_gpuva_sm_unmap(), or + * a callback function. + */ +static int pvr_vm_bind_op_exec(struct pvr_vm_bind_op *bind_op) +{ + switch (bind_op->type) { + case PVR_VM_BIND_TYPE_MAP: + return drm_gpuvm_sm_map(&bind_op->vm_ctx->gpuvm_mgr, + bind_op, bind_op->device_addr, + bind_op->size, + gem_from_pvr_gem(bind_op->pvr_obj), + bind_op->offset); + + case PVR_VM_BIND_TYPE_UNMAP: + return drm_gpuvm_sm_unmap(&bind_op->vm_ctx->gpuvm_mgr, + bind_op, bind_op->device_addr, + bind_op->size); + } + + /* + * This shouldn't happen unless something went wrong + * in drm_sched. + */ + WARN_ON(1); + return -EINVAL; +} + +static void pvr_vm_bind_op_fini(struct pvr_vm_bind_op *bind_op) +{ + drm_gpuvm_bo_put(bind_op->gpuvm_bo); + + kfree(bind_op->new_va); + kfree(bind_op->prev_va); + kfree(bind_op->next_va); + + if (bind_op->pvr_obj) + pvr_gem_object_put(bind_op->pvr_obj); + + if (bind_op->mmu_op_ctx) + pvr_mmu_op_context_destroy(bind_op->mmu_op_ctx); +} + +static int +pvr_vm_bind_op_map_init(struct pvr_vm_bind_op *bind_op, + struct pvr_vm_context *vm_ctx, + struct pvr_gem_object *pvr_obj, u64 offset, + u64 device_addr, u64 size) +{ + struct drm_gem_object *obj = gem_from_pvr_gem(pvr_obj); + const bool is_user = vm_ctx != vm_ctx->pvr_dev->kernel_vm_ctx; + const u64 pvr_obj_size = pvr_gem_object_size(pvr_obj); + struct sg_table *sgt; + u64 offset_plus_size; + int err; + + if (check_add_overflow(offset, size, &offset_plus_size)) + return -EINVAL; + + if (is_user && + !pvr_find_heap_containing(vm_ctx->pvr_dev, device_addr, size)) { + return -EINVAL; + } + + if (!pvr_device_addr_and_size_are_valid(vm_ctx, device_addr, size) || + offset & ~PAGE_MASK || size & ~PAGE_MASK || + offset >= pvr_obj_size || offset_plus_size > pvr_obj_size) + return -EINVAL; + + bind_op->type = PVR_VM_BIND_TYPE_MAP; + + dma_resv_lock(obj->resv, NULL); + bind_op->gpuvm_bo = drm_gpuvm_bo_obtain(&vm_ctx->gpuvm_mgr, obj); + dma_resv_unlock(obj->resv); + if (IS_ERR(bind_op->gpuvm_bo)) + return PTR_ERR(bind_op->gpuvm_bo); + + bind_op->new_va = kzalloc(sizeof(*bind_op->new_va), GFP_KERNEL); + bind_op->prev_va = kzalloc(sizeof(*bind_op->prev_va), GFP_KERNEL); + bind_op->next_va = kzalloc(sizeof(*bind_op->next_va), GFP_KERNEL); + if (!bind_op->new_va || !bind_op->prev_va || !bind_op->next_va) { + err = -ENOMEM; + goto err_bind_op_fini; + } + + /* Pin pages so they're ready for use. */ + sgt = pvr_gem_object_get_pages_sgt(pvr_obj); + err = PTR_ERR_OR_ZERO(sgt); + if (err) + goto err_bind_op_fini; + + bind_op->mmu_op_ctx = + pvr_mmu_op_context_create(vm_ctx->mmu_ctx, sgt, offset, size); + err = PTR_ERR_OR_ZERO(bind_op->mmu_op_ctx); + if (err) { + bind_op->mmu_op_ctx = NULL; + goto err_bind_op_fini; + } + + bind_op->pvr_obj = pvr_obj; + bind_op->vm_ctx = vm_ctx; + bind_op->device_addr = device_addr; + bind_op->size = size; + bind_op->offset = offset; + + return 0; + +err_bind_op_fini: + pvr_vm_bind_op_fini(bind_op); + + return err; +} + +static int +pvr_vm_bind_op_unmap_init(struct pvr_vm_bind_op *bind_op, + struct pvr_vm_context *vm_ctx, u64 device_addr, + u64 size) +{ + int err; + + if (!pvr_device_addr_and_size_are_valid(vm_ctx, device_addr, size)) + return -EINVAL; + + bind_op->type = PVR_VM_BIND_TYPE_UNMAP; + + bind_op->prev_va = kzalloc(sizeof(*bind_op->prev_va), GFP_KERNEL); + bind_op->next_va = kzalloc(sizeof(*bind_op->next_va), GFP_KERNEL); + if (!bind_op->prev_va || !bind_op->next_va) { + err = -ENOMEM; + goto err_bind_op_fini; + } + + bind_op->mmu_op_ctx = + pvr_mmu_op_context_create(vm_ctx->mmu_ctx, NULL, 0, 0); + err = PTR_ERR_OR_ZERO(bind_op->mmu_op_ctx); + if (err) { + bind_op->mmu_op_ctx = NULL; + goto err_bind_op_fini; + } + + bind_op->vm_ctx = vm_ctx; + bind_op->device_addr = device_addr; + bind_op->size = size; + + return 0; + +err_bind_op_fini: + pvr_vm_bind_op_fini(bind_op); + + return err; +} + +/** + * pvr_vm_gpuva_map() - Insert a mapping into a memory context. + * @op: gpuva op containing the remap details. + * @op_ctx: Operation context. + * + * Context: Called by drm_gpuvm_sm_map following a successful mapping while + * @op_ctx.vm_ctx mutex is held. + * + * Return: + * * 0 on success, or + * * Any error returned by pvr_mmu_map(). + */ +static int +pvr_vm_gpuva_map(struct drm_gpuva_op *op, void *op_ctx) +{ + struct pvr_gem_object *pvr_gem = gem_to_pvr_gem(op->map.gem.obj); + struct pvr_vm_bind_op *ctx = op_ctx; + int err; + + if ((op->map.gem.offset | op->map.va.range) & ~PVR_DEVICE_PAGE_MASK) + return -EINVAL; + + err = pvr_mmu_map(ctx->mmu_op_ctx, op->map.va.range, pvr_gem->flags, + op->map.va.addr); + if (err) + return err; + + drm_gpuva_map(&ctx->vm_ctx->gpuvm_mgr, &ctx->new_va->base, &op->map); + drm_gpuva_link(&ctx->new_va->base, ctx->gpuvm_bo); + ctx->new_va = NULL; + + return 0; +} + +/** + * pvr_vm_gpuva_unmap() - Remove a mapping from a memory context. + * @op: gpuva op containing the unmap details. + * @op_ctx: Operation context. + * + * Context: Called by drm_gpuvm_sm_unmap following a successful unmapping while + * @op_ctx.vm_ctx mutex is held. + * + * Return: + * * 0 on success, or + * * Any error returned by pvr_mmu_unmap(). + */ +static int +pvr_vm_gpuva_unmap(struct drm_gpuva_op *op, void *op_ctx) +{ + struct pvr_vm_bind_op *ctx = op_ctx; + + int err = pvr_mmu_unmap(ctx->mmu_op_ctx, op->unmap.va->va.addr, + op->unmap.va->va.range); + + if (err) + return err; + + drm_gpuva_unmap(&op->unmap); + drm_gpuva_unlink(op->unmap.va); + + return 0; +} + +/** + * pvr_vm_gpuva_remap() - Remap a mapping within a memory context. + * @op: gpuva op containing the remap details. + * @op_ctx: Operation context. + * + * Context: Called by either drm_gpuvm_sm_map or drm_gpuvm_sm_unmap when a + * mapping or unmapping operation causes a region to be split. The + * @op_ctx.vm_ctx mutex is held. + * + * Return: + * * 0 on success, or + * * Any error returned by pvr_vm_gpuva_unmap() or pvr_vm_gpuva_unmap(). + */ +static int +pvr_vm_gpuva_remap(struct drm_gpuva_op *op, void *op_ctx) +{ + struct pvr_vm_bind_op *ctx = op_ctx; + u64 va_start = 0, va_range = 0; + int err; + + drm_gpuva_op_remap_to_unmap_range(&op->remap, &va_start, &va_range); + err = pvr_mmu_unmap(ctx->mmu_op_ctx, va_start, va_range); + if (err) + return err; + + /* No actual remap required: the page table tree depth is fixed to 3, + * and we use 4k page table entries only for now. + */ + drm_gpuva_remap(&ctx->prev_va->base, &ctx->next_va->base, &op->remap); + + if (op->remap.prev) { + pvr_gem_object_get(gem_to_pvr_gem(ctx->prev_va->base.gem.obj)); + drm_gpuva_link(&ctx->prev_va->base, ctx->gpuvm_bo); + ctx->prev_va = NULL; + } + + if (op->remap.next) { + pvr_gem_object_get(gem_to_pvr_gem(ctx->next_va->base.gem.obj)); + drm_gpuva_link(&ctx->next_va->base, ctx->gpuvm_bo); + ctx->next_va = NULL; + } + + drm_gpuva_unlink(op->remap.unmap->va); + + return 0; +} + +/* + * Public API + * + * For an overview of these functions, see *DOC: Public API* in "pvr_vm.h". + */ + +/** + * pvr_device_addr_is_valid() - Tests whether a device-virtual address + * is valid. + * @device_addr: Virtual device address to test. + * + * Return: + * * %true if @device_addr is within the valid range for a device page + * table and is aligned to the device page size, or + * * %false otherwise. + */ +bool +pvr_device_addr_is_valid(u64 device_addr) +{ + return (device_addr & ~PVR_PAGE_TABLE_ADDR_MASK) == 0 && + (device_addr & ~PVR_DEVICE_PAGE_MASK) == 0; +} + +/** + * pvr_device_addr_and_size_are_valid() - Tests whether a device-virtual + * address and associated size are both valid. + * @vm_ctx: Target VM context. + * @device_addr: Virtual device address to test. + * @size: Size of the range based at @device_addr to test. + * + * Calling pvr_device_addr_is_valid() twice (once on @size, and again on + * @device_addr + @size) to verify a device-virtual address range initially + * seems intuitive, but it produces a false-negative when the address range + * is right at the end of device-virtual address space. + * + * This function catches that corner case, as well as checking that + * @size is non-zero. + * + * Return: + * * %true if @device_addr is device page aligned; @size is device page + * aligned; the range specified by @device_addr and @size is within the + * bounds of the device-virtual address space, and @size is non-zero, or + * * %false otherwise. + */ +bool +pvr_device_addr_and_size_are_valid(struct pvr_vm_context *vm_ctx, + u64 device_addr, u64 size) +{ + return pvr_device_addr_is_valid(device_addr) && + drm_gpuvm_range_valid(&vm_ctx->gpuvm_mgr, device_addr, size) && + size != 0 && (size & ~PVR_DEVICE_PAGE_MASK) == 0 && + (device_addr + size <= PVR_PAGE_TABLE_ADDR_SPACE_SIZE); +} + +static void pvr_gpuvm_free(struct drm_gpuvm *gpuvm) +{ + kfree(to_pvr_vm_context(gpuvm)); +} + +static const struct drm_gpuvm_ops pvr_vm_gpuva_ops = { + .vm_free = pvr_gpuvm_free, + .sm_step_map = pvr_vm_gpuva_map, + .sm_step_remap = pvr_vm_gpuva_remap, + .sm_step_unmap = pvr_vm_gpuva_unmap, +}; + +static void +fw_mem_context_init(void *cpu_ptr, void *priv) +{ + struct rogue_fwif_fwmemcontext *fw_mem_ctx = cpu_ptr; + struct pvr_vm_context *vm_ctx = priv; + + fw_mem_ctx->pc_dev_paddr = pvr_vm_get_page_table_root_addr(vm_ctx); + fw_mem_ctx->page_cat_base_reg_set = ROGUE_FW_BIF_INVALID_PCSET; +} + +/** + * pvr_vm_create_context() - Create a new VM context. + * @pvr_dev: Target PowerVR device. + * @is_userspace_context: %true if this context is for userspace. This will + * create a firmware memory context for the VM context + * and disable warnings when tearing down mappings. + * + * Return: + * * A handle to the newly-minted VM context on success, + * * -%EINVAL if the feature "virtual address space bits" on @pvr_dev is + * missing or has an unsupported value, + * * -%ENOMEM if allocation of the structure behind the opaque handle fails, + * or + * * Any error encountered while setting up internal structures. + */ +struct pvr_vm_context * +pvr_vm_create_context(struct pvr_device *pvr_dev, bool is_userspace_context) +{ + struct drm_device *drm_dev = from_pvr_device(pvr_dev); + + struct pvr_vm_context *vm_ctx; + u16 device_addr_bits; + + int err; + + err = PVR_FEATURE_VALUE(pvr_dev, virtual_address_space_bits, + &device_addr_bits); + if (err) { + drm_err(drm_dev, + "Failed to get device virtual address space bits\n"); + return ERR_PTR(err); + } + + if (device_addr_bits != PVR_PAGE_TABLE_ADDR_BITS) { + drm_err(drm_dev, + "Device has unsupported virtual address space size\n"); + return ERR_PTR(-EINVAL); + } + + vm_ctx = kzalloc(sizeof(*vm_ctx), GFP_KERNEL); + if (!vm_ctx) + return ERR_PTR(-ENOMEM); + + vm_ctx->pvr_dev = pvr_dev; + + vm_ctx->mmu_ctx = pvr_mmu_context_create(pvr_dev); + err = PTR_ERR_OR_ZERO(vm_ctx->mmu_ctx); + if (err) + goto err_free; + + if (is_userspace_context) { + err = pvr_fw_object_create(pvr_dev, sizeof(struct rogue_fwif_fwmemcontext), + PVR_BO_FW_FLAGS_DEVICE_UNCACHED, + fw_mem_context_init, vm_ctx, &vm_ctx->fw_mem_ctx_obj); + + if (err) + goto err_page_table_destroy; + } + + drm_gem_private_object_init(&pvr_dev->base, &vm_ctx->dummy_gem, 0); + drm_gpuvm_init(&vm_ctx->gpuvm_mgr, + is_userspace_context ? "PowerVR-user-VM" : "PowerVR-FW-VM", + 0, &pvr_dev->base, &vm_ctx->dummy_gem, + 0, 1ULL << device_addr_bits, 0, 0, &pvr_vm_gpuva_ops); + + mutex_init(&vm_ctx->lock); + kref_init(&vm_ctx->ref_count); + + return vm_ctx; + +err_page_table_destroy: + pvr_mmu_context_destroy(vm_ctx->mmu_ctx); + +err_free: + kfree(vm_ctx); + + return ERR_PTR(err); +} + +/** + * pvr_vm_context_release() - Teardown a VM context. + * @ref_count: Pointer to reference counter of the VM context. + * + * This function ensures that no mappings are left dangling by unmapping them + * all in order of ascending device-virtual address. + */ +static void +pvr_vm_context_release(struct kref *ref_count) +{ + struct pvr_vm_context *vm_ctx = + container_of(ref_count, struct pvr_vm_context, ref_count); + + if (vm_ctx->fw_mem_ctx_obj) + pvr_fw_object_destroy(vm_ctx->fw_mem_ctx_obj); + + WARN_ON(pvr_vm_unmap(vm_ctx, vm_ctx->gpuvm_mgr.mm_start, + vm_ctx->gpuvm_mgr.mm_range)); + + pvr_mmu_context_destroy(vm_ctx->mmu_ctx); + drm_gem_private_object_fini(&vm_ctx->dummy_gem); + mutex_destroy(&vm_ctx->lock); + + drm_gpuvm_put(&vm_ctx->gpuvm_mgr); +} + +/** + * pvr_vm_context_lookup() - Look up VM context from handle + * @pvr_file: Pointer to pvr_file structure. + * @handle: Object handle. + * + * Takes reference on VM context object. Call pvr_vm_context_put() to release. + * + * Returns: + * * The requested object on success, or + * * %NULL on failure (object does not exist in list, or is not a VM context) + */ +struct pvr_vm_context * +pvr_vm_context_lookup(struct pvr_file *pvr_file, u32 handle) +{ + struct pvr_vm_context *vm_ctx; + + xa_lock(&pvr_file->vm_ctx_handles); + vm_ctx = xa_load(&pvr_file->vm_ctx_handles, handle); + if (vm_ctx) + kref_get(&vm_ctx->ref_count); + + xa_unlock(&pvr_file->vm_ctx_handles); + + return vm_ctx; +} + +/** + * pvr_vm_context_put() - Release a reference on a VM context + * @vm_ctx: Target VM context. + * + * Returns: + * * %true if the VM context was destroyed, or + * * %false if there are any references still remaining. + */ +bool +pvr_vm_context_put(struct pvr_vm_context *vm_ctx) +{ + if (vm_ctx) + return kref_put(&vm_ctx->ref_count, pvr_vm_context_release); + + return true; +} + +/** + * pvr_destroy_vm_contexts_for_file: Destroy any VM contexts associated with the + * given file. + * @pvr_file: Pointer to pvr_file structure. + * + * Removes all vm_contexts associated with @pvr_file from the device VM context + * list and drops initial references. vm_contexts will then be destroyed once + * all outstanding references are dropped. + */ +void pvr_destroy_vm_contexts_for_file(struct pvr_file *pvr_file) +{ + struct pvr_vm_context *vm_ctx; + unsigned long handle; + + xa_for_each(&pvr_file->vm_ctx_handles, handle, vm_ctx) { + /* vm_ctx is not used here because that would create a race with xa_erase */ + pvr_vm_context_put(xa_erase(&pvr_file->vm_ctx_handles, handle)); + } +} + +static int +pvr_vm_lock_extra(struct drm_gpuvm_exec *vm_exec) +{ + struct pvr_vm_bind_op *bind_op = vm_exec->extra.priv; + struct pvr_gem_object *pvr_obj = bind_op->pvr_obj; + + /* Unmap operations don't have an object to lock. */ + if (!pvr_obj) + return 0; + + /* Acquire lock on the GEM being mapped. */ + return drm_exec_lock_obj(&vm_exec->exec, gem_from_pvr_gem(pvr_obj)); +} + +/** + * pvr_vm_map() - Map a section of physical memory into a section of + * device-virtual memory. + * @vm_ctx: Target VM context. + * @pvr_obj: Target PowerVR memory object. + * @pvr_obj_offset: Offset into @pvr_obj to map from. + * @device_addr: Virtual device address at the start of the requested mapping. + * @size: Size of the requested mapping. + * + * No handle is returned to represent the mapping. Instead, callers should + * remember @device_addr and use that as a handle. + * + * Return: + * * 0 on success, + * * -%EINVAL if @device_addr is not a valid page-aligned device-virtual + * address; the region specified by @pvr_obj_offset and @size does not fall + * entirely within @pvr_obj, or any part of the specified region of @pvr_obj + * is not device-virtual page-aligned, + * * Any error encountered while performing internal operations required to + * destroy the mapping (returned from pvr_vm_gpuva_map or + * pvr_vm_gpuva_remap). + */ +int +pvr_vm_map(struct pvr_vm_context *vm_ctx, struct pvr_gem_object *pvr_obj, + u64 pvr_obj_offset, u64 device_addr, u64 size) +{ + struct pvr_vm_bind_op bind_op = {0}; + struct drm_gpuvm_exec vm_exec = { + .vm = &vm_ctx->gpuvm_mgr, + .flags = DRM_EXEC_INTERRUPTIBLE_WAIT | + DRM_EXEC_IGNORE_DUPLICATES, + .extra = { + .fn = pvr_vm_lock_extra, + .priv = &bind_op, + }, + }; + + int err = pvr_vm_bind_op_map_init(&bind_op, vm_ctx, pvr_obj, + pvr_obj_offset, device_addr, + size); + + if (err) + return err; + + pvr_gem_object_get(pvr_obj); + + err = drm_gpuvm_exec_lock(&vm_exec); + if (err) + goto err_cleanup; + + err = pvr_vm_bind_op_exec(&bind_op); + + drm_gpuvm_exec_unlock(&vm_exec); + +err_cleanup: + pvr_vm_bind_op_fini(&bind_op); + + return err; +} + +/** + * pvr_vm_unmap() - Unmap an already mapped section of device-virtual memory. + * @vm_ctx: Target VM context. + * @device_addr: Virtual device address at the start of the target mapping. + * @size: Size of the target mapping. + * + * Return: + * * 0 on success, + * * -%EINVAL if @device_addr is not a valid page-aligned device-virtual + * address, + * * Any error encountered while performing internal operations required to + * destroy the mapping (returned from pvr_vm_gpuva_unmap or + * pvr_vm_gpuva_remap). + */ +int +pvr_vm_unmap(struct pvr_vm_context *vm_ctx, u64 device_addr, u64 size) +{ + struct pvr_vm_bind_op bind_op = {0}; + struct drm_gpuvm_exec vm_exec = { + .vm = &vm_ctx->gpuvm_mgr, + .flags = DRM_EXEC_INTERRUPTIBLE_WAIT | + DRM_EXEC_IGNORE_DUPLICATES, + .extra = { + .fn = pvr_vm_lock_extra, + .priv = &bind_op, + }, + }; + + int err = pvr_vm_bind_op_unmap_init(&bind_op, vm_ctx, device_addr, + size); + if (err) + return err; + + err = drm_gpuvm_exec_lock(&vm_exec); + if (err) + goto err_cleanup; + + err = pvr_vm_bind_op_exec(&bind_op); + + drm_gpuvm_exec_unlock(&vm_exec); + +err_cleanup: + pvr_vm_bind_op_fini(&bind_op); + + return err; +} + +/* Static data areas are determined by firmware. */ +static const struct drm_pvr_static_data_area static_data_areas[] = { + { + .area_usage = DRM_PVR_STATIC_DATA_AREA_FENCE, + .location_heap_id = DRM_PVR_HEAP_GENERAL, + .offset = 0, + .size = 128, + }, + { + .area_usage = DRM_PVR_STATIC_DATA_AREA_YUV_CSC, + .location_heap_id = DRM_PVR_HEAP_GENERAL, + .offset = 128, + .size = 1024, + }, + { + .area_usage = DRM_PVR_STATIC_DATA_AREA_VDM_SYNC, + .location_heap_id = DRM_PVR_HEAP_PDS_CODE_DATA, + .offset = 0, + .size = 128, + }, + { + .area_usage = DRM_PVR_STATIC_DATA_AREA_EOT, + .location_heap_id = DRM_PVR_HEAP_PDS_CODE_DATA, + .offset = 128, + .size = 128, + }, + { + .area_usage = DRM_PVR_STATIC_DATA_AREA_VDM_SYNC, + .location_heap_id = DRM_PVR_HEAP_USC_CODE, + .offset = 0, + .size = 128, + }, +}; + +#define GET_RESERVED_SIZE(last_offset, last_size) round_up((last_offset) + (last_size), PAGE_SIZE) + +/* + * The values given to GET_RESERVED_SIZE() are taken from the last entry in the corresponding + * static data area for each heap. + */ +static const struct drm_pvr_heap pvr_heaps[] = { + [DRM_PVR_HEAP_GENERAL] = { + .base = ROGUE_GENERAL_HEAP_BASE, + .size = ROGUE_GENERAL_HEAP_SIZE, + .flags = 0, + .page_size_log2 = PVR_DEVICE_PAGE_SHIFT, + }, + [DRM_PVR_HEAP_PDS_CODE_DATA] = { + .base = ROGUE_PDSCODEDATA_HEAP_BASE, + .size = ROGUE_PDSCODEDATA_HEAP_SIZE, + .flags = 0, + .page_size_log2 = PVR_DEVICE_PAGE_SHIFT, + }, + [DRM_PVR_HEAP_USC_CODE] = { + .base = ROGUE_USCCODE_HEAP_BASE, + .size = ROGUE_USCCODE_HEAP_SIZE, + .flags = 0, + .page_size_log2 = PVR_DEVICE_PAGE_SHIFT, + }, + [DRM_PVR_HEAP_RGNHDR] = { + .base = ROGUE_RGNHDR_HEAP_BASE, + .size = ROGUE_RGNHDR_HEAP_SIZE, + .flags = 0, + .page_size_log2 = PVR_DEVICE_PAGE_SHIFT, + }, + [DRM_PVR_HEAP_VIS_TEST] = { + .base = ROGUE_VISTEST_HEAP_BASE, + .size = ROGUE_VISTEST_HEAP_SIZE, + .flags = 0, + .page_size_log2 = PVR_DEVICE_PAGE_SHIFT, + }, + [DRM_PVR_HEAP_TRANSFER_FRAG] = { + .base = ROGUE_TRANSFER_FRAG_HEAP_BASE, + .size = ROGUE_TRANSFER_FRAG_HEAP_SIZE, + .flags = 0, + .page_size_log2 = PVR_DEVICE_PAGE_SHIFT, + }, +}; + +int +pvr_static_data_areas_get(const struct pvr_device *pvr_dev, + struct drm_pvr_ioctl_dev_query_args *args) +{ + struct drm_pvr_dev_query_static_data_areas query = {0}; + int err; + + if (!args->pointer) { + args->size = sizeof(struct drm_pvr_dev_query_static_data_areas); + return 0; + } + + err = PVR_UOBJ_GET(query, args->size, args->pointer); + if (err < 0) + return err; + + if (!query.static_data_areas.array) { + query.static_data_areas.count = ARRAY_SIZE(static_data_areas); + query.static_data_areas.stride = sizeof(struct drm_pvr_static_data_area); + goto copy_out; + } + + if (query.static_data_areas.count > ARRAY_SIZE(static_data_areas)) + query.static_data_areas.count = ARRAY_SIZE(static_data_areas); + + err = PVR_UOBJ_SET_ARRAY(&query.static_data_areas, static_data_areas); + if (err < 0) + return err; + +copy_out: + err = PVR_UOBJ_SET(args->pointer, args->size, query); + if (err < 0) + return err; + + args->size = sizeof(query); + return 0; +} + +int +pvr_heap_info_get(const struct pvr_device *pvr_dev, + struct drm_pvr_ioctl_dev_query_args *args) +{ + struct drm_pvr_dev_query_heap_info query = {0}; + u64 dest; + int err; + + if (!args->pointer) { + args->size = sizeof(struct drm_pvr_dev_query_heap_info); + return 0; + } + + err = PVR_UOBJ_GET(query, args->size, args->pointer); + if (err < 0) + return err; + + if (!query.heaps.array) { + query.heaps.count = ARRAY_SIZE(pvr_heaps); + query.heaps.stride = sizeof(struct drm_pvr_heap); + goto copy_out; + } + + if (query.heaps.count > ARRAY_SIZE(pvr_heaps)) + query.heaps.count = ARRAY_SIZE(pvr_heaps); + + /* Region header heap is only present if BRN63142 is present. */ + dest = query.heaps.array; + for (size_t i = 0; i < query.heaps.count; i++) { + struct drm_pvr_heap heap = pvr_heaps[i]; + + if (i == DRM_PVR_HEAP_RGNHDR && !PVR_HAS_QUIRK(pvr_dev, 63142)) + heap.size = 0; + + err = PVR_UOBJ_SET(dest, query.heaps.stride, heap); + if (err < 0) + return err; + + dest += query.heaps.stride; + } + +copy_out: + err = PVR_UOBJ_SET(args->pointer, args->size, query); + if (err < 0) + return err; + + args->size = sizeof(query); + return 0; +} + +/** + * pvr_heap_contains_range() - Determine if a given heap contains the specified + * device-virtual address range. + * @pvr_heap: Target heap. + * @start: Inclusive start of the target range. + * @end: Inclusive end of the target range. + * + * It is an error to call this function with values of @start and @end that do + * not satisfy the condition @start <= @end. + */ +static __always_inline bool +pvr_heap_contains_range(const struct drm_pvr_heap *pvr_heap, u64 start, u64 end) +{ + return pvr_heap->base <= start && end < pvr_heap->base + pvr_heap->size; +} + +/** + * pvr_find_heap_containing() - Find a heap which contains the specified + * device-virtual address range. + * @pvr_dev: Target PowerVR device. + * @start: Start of the target range. + * @size: Size of the target range. + * + * Return: + * * A pointer to a constant instance of struct drm_pvr_heap representing the + * heap containing the entire range specified by @start and @size on + * success, or + * * %NULL if no such heap exists. + */ +const struct drm_pvr_heap * +pvr_find_heap_containing(struct pvr_device *pvr_dev, u64 start, u64 size) +{ + u64 end; + + if (check_add_overflow(start, size - 1, &end)) + return NULL; + + /* + * There are no guarantees about the order of address ranges in + * &pvr_heaps, so iterate over the entire array for a heap whose + * range completely encompasses the given range. + */ + for (u32 heap_id = 0; heap_id < ARRAY_SIZE(pvr_heaps); heap_id++) { + /* Filter heaps that present only with an associated quirk */ + if (heap_id == DRM_PVR_HEAP_RGNHDR && + !PVR_HAS_QUIRK(pvr_dev, 63142)) { + continue; + } + + if (pvr_heap_contains_range(&pvr_heaps[heap_id], start, end)) + return &pvr_heaps[heap_id]; + } + + return NULL; +} + +/** + * pvr_vm_find_gem_object() - Look up a buffer object from a given + * device-virtual address. + * @vm_ctx: [IN] Target VM context. + * @device_addr: [IN] Virtual device address at the start of the required + * object. + * @mapped_offset_out: [OUT] Pointer to location to write offset of the start + * of the mapped region within the buffer object. May be + * %NULL if this information is not required. + * @mapped_size_out: [OUT] Pointer to location to write size of the mapped + * region. May be %NULL if this information is not required. + * + * If successful, a reference will be taken on the buffer object. The caller + * must drop the reference with pvr_gem_object_put(). + * + * Return: + * * The PowerVR buffer object mapped at @device_addr if one exists, or + * * %NULL otherwise. + */ +struct pvr_gem_object * +pvr_vm_find_gem_object(struct pvr_vm_context *vm_ctx, u64 device_addr, + u64 *mapped_offset_out, u64 *mapped_size_out) +{ + struct pvr_gem_object *pvr_obj; + struct drm_gpuva *va; + + mutex_lock(&vm_ctx->lock); + + va = drm_gpuva_find_first(&vm_ctx->gpuvm_mgr, device_addr, 1); + if (!va) + goto err_unlock; + + pvr_obj = gem_to_pvr_gem(va->gem.obj); + pvr_gem_object_get(pvr_obj); + + if (mapped_offset_out) + *mapped_offset_out = va->gem.offset; + if (mapped_size_out) + *mapped_size_out = va->va.range; + + mutex_unlock(&vm_ctx->lock); + + return pvr_obj; + +err_unlock: + mutex_unlock(&vm_ctx->lock); + + return NULL; +} + +/** + * pvr_vm_get_fw_mem_context: Get object representing firmware memory context + * @vm_ctx: Target VM context. + * + * Returns: + * * FW object representing firmware memory context, or + * * %NULL if this VM context does not have a firmware memory context. + */ +struct pvr_fw_object * +pvr_vm_get_fw_mem_context(struct pvr_vm_context *vm_ctx) +{ + return vm_ctx->fw_mem_ctx_obj; +} diff --git a/drivers/gpu/drm/imagination/pvr_vm.h b/drivers/gpu/drm/imagination/pvr_vm.h new file mode 100644 index 00000000000000..f2a6463f2b059e --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_vm.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_VM_H +#define PVR_VM_H + +#include "pvr_rogue_mmu_defs.h" + +#include + +#include + +/* Forward declaration from "pvr_device.h" */ +struct pvr_device; +struct pvr_file; + +/* Forward declaration from "pvr_gem.h" */ +struct pvr_gem_object; + +/* Forward declaration from "pvr_vm.c" */ +struct pvr_vm_context; + +/* Forward declaration from */ +struct drm_pvr_ioctl_get_heap_info_args; + +/* Forward declaration from */ +struct drm_exec; + +/* Functions defined in pvr_vm.c */ + +bool pvr_device_addr_is_valid(u64 device_addr); +bool pvr_device_addr_and_size_are_valid(struct pvr_vm_context *vm_ctx, + u64 device_addr, u64 size); + +struct pvr_vm_context *pvr_vm_create_context(struct pvr_device *pvr_dev, + bool is_userspace_context); + +int pvr_vm_map(struct pvr_vm_context *vm_ctx, + struct pvr_gem_object *pvr_obj, u64 pvr_obj_offset, + u64 device_addr, u64 size); +int pvr_vm_unmap(struct pvr_vm_context *vm_ctx, u64 device_addr, u64 size); + +dma_addr_t pvr_vm_get_page_table_root_addr(struct pvr_vm_context *vm_ctx); +struct dma_resv *pvr_vm_get_dma_resv(struct pvr_vm_context *vm_ctx); + +int pvr_static_data_areas_get(const struct pvr_device *pvr_dev, + struct drm_pvr_ioctl_dev_query_args *args); +int pvr_heap_info_get(const struct pvr_device *pvr_dev, + struct drm_pvr_ioctl_dev_query_args *args); +const struct drm_pvr_heap *pvr_find_heap_containing(struct pvr_device *pvr_dev, + u64 addr, u64 size); + +struct pvr_gem_object *pvr_vm_find_gem_object(struct pvr_vm_context *vm_ctx, + u64 device_addr, + u64 *mapped_offset_out, + u64 *mapped_size_out); + +struct pvr_fw_object * +pvr_vm_get_fw_mem_context(struct pvr_vm_context *vm_ctx); + +struct pvr_vm_context *pvr_vm_context_lookup(struct pvr_file *pvr_file, u32 handle); +struct pvr_vm_context *pvr_vm_context_get(struct pvr_vm_context *vm_ctx); +bool pvr_vm_context_put(struct pvr_vm_context *vm_ctx); +void pvr_destroy_vm_contexts_for_file(struct pvr_file *pvr_file); + +#endif /* PVR_VM_H */ diff --git a/drivers/gpu/drm/imagination/pvr_vm_mips.c b/drivers/gpu/drm/imagination/pvr_vm_mips.c new file mode 100644 index 00000000000000..b7fef3c797e6ca --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_vm_mips.c @@ -0,0 +1,237 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#include "pvr_device.h" +#include "pvr_fw_mips.h" +#include "pvr_gem.h" +#include "pvr_mmu.h" +#include "pvr_rogue_mips.h" +#include "pvr_vm.h" +#include "pvr_vm_mips.h" + +#include +#include +#include +#include +#include + +/** + * pvr_vm_mips_init() - Initialise MIPS FW pagetable + * @pvr_dev: Target PowerVR device. + * + * Returns: + * * 0 on success, + * * -%EINVAL, + * * Any error returned by pvr_gem_object_create(), or + * * And error returned by pvr_gem_object_vmap(). + */ +int +pvr_vm_mips_init(struct pvr_device *pvr_dev) +{ + u32 pt_size = 1 << ROGUE_MIPSFW_LOG2_PAGETABLE_SIZE_4K(pvr_dev); + struct device *dev = from_pvr_device(pvr_dev)->dev; + struct pvr_fw_mips_data *mips_data; + u32 phys_bus_width; + int page_nr; + int err; + + /* Page table size must be at most ROGUE_MIPSFW_MAX_NUM_PAGETABLE_PAGES * 4k pages. */ + if (pt_size > ROGUE_MIPSFW_MAX_NUM_PAGETABLE_PAGES * SZ_4K) + return -EINVAL; + + if (PVR_FEATURE_VALUE(pvr_dev, phys_bus_width, &phys_bus_width)) + return -EINVAL; + + mips_data = drmm_kzalloc(from_pvr_device(pvr_dev), sizeof(*mips_data), GFP_KERNEL); + if (!mips_data) + return -ENOMEM; + + for (page_nr = 0; page_nr < ARRAY_SIZE(mips_data->pt_pages); page_nr++) { + mips_data->pt_pages[page_nr] = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (!mips_data->pt_pages[page_nr]) { + err = -ENOMEM; + goto err_free_pages; + } + + mips_data->pt_dma_addr[page_nr] = dma_map_page(dev, mips_data->pt_pages[page_nr], 0, + PAGE_SIZE, DMA_TO_DEVICE); + if (dma_mapping_error(dev, mips_data->pt_dma_addr[page_nr])) { + err = -ENOMEM; + __free_page(mips_data->pt_pages[page_nr]); + goto err_free_pages; + } + } + + mips_data->pt = vmap(mips_data->pt_pages, pt_size >> PAGE_SHIFT, VM_MAP, + pgprot_writecombine(PAGE_KERNEL)); + if (!mips_data->pt) { + err = -ENOMEM; + goto err_free_pages; + } + + mips_data->pfn_mask = (phys_bus_width > 32) ? ROGUE_MIPSFW_ENTRYLO_PFN_MASK_ABOVE_32BIT : + ROGUE_MIPSFW_ENTRYLO_PFN_MASK; + + mips_data->cache_policy = (phys_bus_width > 32) ? ROGUE_MIPSFW_CACHED_POLICY_ABOVE_32BIT : + ROGUE_MIPSFW_CACHED_POLICY; + + pvr_dev->fw_dev.processor_data.mips_data = mips_data; + + return 0; + +err_free_pages: + while (--page_nr >= 0) { + dma_unmap_page(from_pvr_device(pvr_dev)->dev, + mips_data->pt_dma_addr[page_nr], PAGE_SIZE, DMA_TO_DEVICE); + + __free_page(mips_data->pt_pages[page_nr]); + } + + return err; +} + +/** + * pvr_vm_mips_fini() - Release MIPS FW pagetable + * @pvr_dev: Target PowerVR device. + */ +void +pvr_vm_mips_fini(struct pvr_device *pvr_dev) +{ + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + struct pvr_fw_mips_data *mips_data = fw_dev->processor_data.mips_data; + int page_nr; + + vunmap(mips_data->pt); + for (page_nr = ARRAY_SIZE(mips_data->pt_pages) - 1; page_nr >= 0; page_nr--) { + dma_unmap_page(from_pvr_device(pvr_dev)->dev, + mips_data->pt_dma_addr[page_nr], PAGE_SIZE, DMA_TO_DEVICE); + + __free_page(mips_data->pt_pages[page_nr]); + } + + fw_dev->processor_data.mips_data = NULL; +} + +static u32 +get_mips_pte_flags(bool read, bool write, u32 cache_policy) +{ + u32 flags = 0; + + if (read && write) /* Read/write. */ + flags |= ROGUE_MIPSFW_ENTRYLO_DIRTY_EN; + else if (write) /* Write only. */ + flags |= ROGUE_MIPSFW_ENTRYLO_READ_INHIBIT_EN; + else + WARN_ON(!read); + + flags |= cache_policy << ROGUE_MIPSFW_ENTRYLO_CACHE_POLICY_SHIFT; + + flags |= ROGUE_MIPSFW_ENTRYLO_VALID_EN | ROGUE_MIPSFW_ENTRYLO_GLOBAL_EN; + + return flags; +} + +/** + * pvr_vm_mips_map() - Map a FW object into MIPS address space + * @pvr_dev: Target PowerVR device. + * @fw_obj: FW object to map. + * + * Returns: + * * 0 on success, + * * -%EINVAL if object does not reside within FW address space, or + * * Any error returned by pvr_fw_object_get_dma_addr(). + */ +int +pvr_vm_mips_map(struct pvr_device *pvr_dev, struct pvr_fw_object *fw_obj) +{ + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + struct pvr_fw_mips_data *mips_data = fw_dev->processor_data.mips_data; + struct pvr_gem_object *pvr_obj = fw_obj->gem; + const u64 start = fw_obj->fw_mm_node.start; + const u64 size = fw_obj->fw_mm_node.size; + u64 end; + u32 cache_policy; + u32 pte_flags; + s32 start_pfn; + s32 end_pfn; + s32 pfn; + int err; + + if (check_add_overflow(start, size - 1, &end)) + return -EINVAL; + + if (start < ROGUE_FW_HEAP_BASE || + start >= ROGUE_FW_HEAP_BASE + fw_dev->fw_heap_info.raw_size || + end < ROGUE_FW_HEAP_BASE || + end >= ROGUE_FW_HEAP_BASE + fw_dev->fw_heap_info.raw_size || + (start & ROGUE_MIPSFW_PAGE_MASK_4K) || + ((end + 1) & ROGUE_MIPSFW_PAGE_MASK_4K)) + return -EINVAL; + + start_pfn = (start & fw_dev->fw_heap_info.offset_mask) >> ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K; + end_pfn = (end & fw_dev->fw_heap_info.offset_mask) >> ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K; + + if (pvr_obj->flags & PVR_BO_FW_FLAGS_DEVICE_UNCACHED) + cache_policy = ROGUE_MIPSFW_UNCACHED_CACHE_POLICY; + else + cache_policy = mips_data->cache_policy; + + pte_flags = get_mips_pte_flags(true, true, cache_policy); + + for (pfn = start_pfn; pfn <= end_pfn; pfn++) { + dma_addr_t dma_addr; + u32 pte; + + err = pvr_fw_object_get_dma_addr(fw_obj, + (pfn - start_pfn) << + ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K, + &dma_addr); + if (err) + goto err_unmap_pages; + + pte = ((dma_addr >> ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K) + << ROGUE_MIPSFW_ENTRYLO_PFN_SHIFT) & mips_data->pfn_mask; + pte |= pte_flags; + + WRITE_ONCE(mips_data->pt[pfn], pte); + } + + pvr_mmu_flush_request_all(pvr_dev); + + return 0; + +err_unmap_pages: + while (--pfn >= start_pfn) + WRITE_ONCE(mips_data->pt[pfn], 0); + + pvr_mmu_flush_request_all(pvr_dev); + WARN_ON(pvr_mmu_flush_exec(pvr_dev, true)); + + return err; +} + +/** + * pvr_vm_mips_unmap() - Unmap a FW object into MIPS address space + * @pvr_dev: Target PowerVR device. + * @fw_obj: FW object to unmap. + */ +void +pvr_vm_mips_unmap(struct pvr_device *pvr_dev, struct pvr_fw_object *fw_obj) +{ + struct pvr_fw_device *fw_dev = &pvr_dev->fw_dev; + struct pvr_fw_mips_data *mips_data = fw_dev->processor_data.mips_data; + const u64 start = fw_obj->fw_mm_node.start; + const u64 size = fw_obj->fw_mm_node.size; + const u64 end = start + size; + + const u32 start_pfn = (start & fw_dev->fw_heap_info.offset_mask) >> + ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K; + const u32 end_pfn = (end & fw_dev->fw_heap_info.offset_mask) >> + ROGUE_MIPSFW_LOG2_PAGE_SIZE_4K; + + for (u32 pfn = start_pfn; pfn < end_pfn; pfn++) + WRITE_ONCE(mips_data->pt[pfn], 0); + + pvr_mmu_flush_request_all(pvr_dev); + WARN_ON(pvr_mmu_flush_exec(pvr_dev, true)); +} diff --git a/drivers/gpu/drm/imagination/pvr_vm_mips.h b/drivers/gpu/drm/imagination/pvr_vm_mips.h new file mode 100644 index 00000000000000..0fd59f68fb5b8e --- /dev/null +++ b/drivers/gpu/drm/imagination/pvr_vm_mips.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR MIT */ +/* Copyright (c) 2023 Imagination Technologies Ltd. */ + +#ifndef PVR_VM_MIPS_H +#define PVR_VM_MIPS_H + +/* Forward declaration from pvr_device.h. */ +struct pvr_device; + +/* Forward declaration from pvr_gem.h. */ +struct pvr_fw_object; + +int +pvr_vm_mips_init(struct pvr_device *pvr_dev); +void +pvr_vm_mips_fini(struct pvr_device *pvr_dev); +int +pvr_vm_mips_map(struct pvr_device *pvr_dev, struct pvr_fw_object *fw_obj); +void +pvr_vm_mips_unmap(struct pvr_device *pvr_dev, struct pvr_fw_object *fw_obj); + +#endif /* PVR_VM_MIPS_H */ diff --git a/drivers/gpu/drm/imx/dcss/dcss-drv.c b/drivers/gpu/drm/imx/dcss/dcss-drv.c index b61cec0cc79d9e..ad5f29ea8f6a15 100644 --- a/drivers/gpu/drm/imx/dcss/dcss-drv.c +++ b/drivers/gpu/drm/imx/dcss/dcss-drv.c @@ -80,7 +80,7 @@ err: return err; } -static int dcss_drv_platform_remove(struct platform_device *pdev) +static void dcss_drv_platform_remove(struct platform_device *pdev) { struct dcss_drv *mdrv = dev_get_drvdata(&pdev->dev); @@ -88,8 +88,6 @@ static int dcss_drv_platform_remove(struct platform_device *pdev) dcss_dev_destroy(mdrv->dcss); kfree(mdrv); - - return 0; } static void dcss_drv_platform_shutdown(struct platform_device *pdev) @@ -120,7 +118,7 @@ MODULE_DEVICE_TABLE(of, dcss_of_match); static struct platform_driver dcss_platform_driver = { .probe = dcss_drv_platform_probe, - .remove = dcss_drv_platform_remove, + .remove_new = dcss_drv_platform_remove, .shutdown = dcss_drv_platform_shutdown, .driver = { .name = "imx-dcss", diff --git a/drivers/gpu/drm/imx/ipuv3/imx-ldb.c b/drivers/gpu/drm/imx/ipuv3/imx-ldb.c index 989eca32d3252a..53840ab054c725 100644 --- a/drivers/gpu/drm/imx/ipuv3/imx-ldb.c +++ b/drivers/gpu/drm/imx/ipuv3/imx-ldb.c @@ -12,8 +12,10 @@ #include #include #include -#include +#include #include +#include +#include #include #include @@ -617,7 +619,6 @@ static int imx_ldb_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; - const struct of_device_id *of_id = of_match_device(imx_ldb_dt_ids, dev); struct device_node *child; struct imx_ldb *imx_ldb; int dual; @@ -638,9 +639,7 @@ static int imx_ldb_probe(struct platform_device *pdev) regmap_write(imx_ldb->regmap, IOMUXC_GPR2, 0); imx_ldb->dev = dev; - - if (of_id) - imx_ldb->lvds_mux = of_id->data; + imx_ldb->lvds_mux = device_get_match_data(dev); dual = of_property_read_bool(np, "fsl,dual-channel"); if (dual) diff --git a/drivers/gpu/drm/imx/lcdc/imx-lcdc.c b/drivers/gpu/drm/imx/lcdc/imx-lcdc.c index 22b65f4a0e3034..43ddf3a9810b6d 100644 --- a/drivers/gpu/drm/imx/lcdc/imx-lcdc.c +++ b/drivers/gpu/drm/imx/lcdc/imx-lcdc.c @@ -342,21 +342,12 @@ static const struct drm_mode_config_helper_funcs imx_lcdc_mode_config_helpers = .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, }; -static void imx_lcdc_release(struct drm_device *drm) -{ - struct imx_lcdc *lcdc = imx_lcdc_from_drmdev(drm); - - drm_kms_helper_poll_fini(drm); - kfree(lcdc); -} - DEFINE_DRM_GEM_DMA_FOPS(imx_lcdc_drm_fops); static struct drm_driver imx_lcdc_drm_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, .fops = &imx_lcdc_drm_fops, DRM_GEM_DMA_DRIVER_OPS_VMAP, - .release = imx_lcdc_release, .name = "imx-lcdc", .desc = "i.MX LCDC driver", .date = "20200716", @@ -515,14 +506,12 @@ static int imx_lcdc_probe(struct platform_device *pdev) return 0; } -static int imx_lcdc_remove(struct platform_device *pdev) +static void imx_lcdc_remove(struct platform_device *pdev) { struct drm_device *drm = platform_get_drvdata(pdev); drm_dev_unregister(drm); drm_atomic_helper_shutdown(drm); - - return 0; } static void imx_lcdc_shutdown(struct platform_device *pdev) @@ -536,7 +525,7 @@ static struct platform_driver imx_lcdc_driver = { .of_match_table = imx_lcdc_of_dev_id, }, .probe = imx_lcdc_probe, - .remove = imx_lcdc_remove, + .remove_new = imx_lcdc_remove, .shutdown = imx_lcdc_shutdown, }; module_platform_driver(imx_lcdc_driver); diff --git a/drivers/gpu/drm/kmb/kmb_drv.c b/drivers/gpu/drm/kmb/kmb_drv.c index 24035b53441cc5..169b83987ce258 100644 --- a/drivers/gpu/drm/kmb/kmb_drv.c +++ b/drivers/gpu/drm/kmb/kmb_drv.c @@ -448,7 +448,7 @@ static const struct drm_driver kmb_driver = { .minor = DRIVER_MINOR, }; -static int kmb_remove(struct platform_device *pdev) +static void kmb_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct drm_device *drm = dev_get_drvdata(dev); @@ -473,7 +473,6 @@ static int kmb_remove(struct platform_device *pdev) /* Unregister DSI host */ kmb_dsi_host_unregister(kmb->kmb_dsi); drm_atomic_helper_shutdown(drm); - return 0; } static int kmb_probe(struct platform_device *pdev) @@ -621,7 +620,7 @@ static SIMPLE_DEV_PM_OPS(kmb_pm_ops, kmb_pm_suspend, kmb_pm_resume); static struct platform_driver kmb_platform_driver = { .probe = kmb_probe, - .remove = kmb_remove, + .remove_new = kmb_remove, .driver = { .name = "kmb-drm", .pm = &kmb_pm_ops, diff --git a/drivers/gpu/drm/lima/lima_ctx.c b/drivers/gpu/drm/lima/lima_ctx.c index 891d5cd5019a74..8389f2d7d021fb 100644 --- a/drivers/gpu/drm/lima/lima_ctx.c +++ b/drivers/gpu/drm/lima/lima_ctx.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR MIT /* Copyright 2018-2019 Qiang Yu */ +#include #include #include "lima_device.h" diff --git a/drivers/gpu/drm/lima/lima_device.c b/drivers/gpu/drm/lima/lima_device.c index 02cef0cea6572b..0bf7105c8748b4 100644 --- a/drivers/gpu/drm/lima/lima_device.c +++ b/drivers/gpu/drm/lima/lima_device.c @@ -514,7 +514,7 @@ int lima_device_suspend(struct device *dev) /* check any task running */ for (i = 0; i < lima_pipe_num; i++) { - if (atomic_read(&ldev->pipe[i].base.hw_rq_count)) + if (atomic_read(&ldev->pipe[i].base.credit_count)) return -EBUSY; } diff --git a/drivers/gpu/drm/lima/lima_sched.c b/drivers/gpu/drm/lima/lima_sched.c index 295f0353a02e58..c3bf8cda84982c 100644 --- a/drivers/gpu/drm/lima/lima_sched.c +++ b/drivers/gpu/drm/lima/lima_sched.c @@ -123,7 +123,7 @@ int lima_sched_task_init(struct lima_sched_task *task, for (i = 0; i < num_bos; i++) drm_gem_object_get(&bos[i]->base.base); - err = drm_sched_job_init(&task->base, &context->base, vm); + err = drm_sched_job_init(&task->base, &context->base, 1, vm); if (err) { kfree(task->bos); return err; @@ -488,7 +488,7 @@ int lima_sched_pipe_init(struct lima_sched_pipe *pipe, const char *name) INIT_WORK(&pipe->recover_work, lima_sched_recover_work); - return drm_sched_init(&pipe->base, &lima_sched_ops, + return drm_sched_init(&pipe->base, &lima_sched_ops, NULL, DRM_SCHED_PRIORITY_COUNT, 1, lima_job_hang_limit, diff --git a/drivers/gpu/drm/loongson/Kconfig b/drivers/gpu/drm/loongson/Kconfig index df6946d505facf..8e59753e532de2 100644 --- a/drivers/gpu/drm/loongson/Kconfig +++ b/drivers/gpu/drm/loongson/Kconfig @@ -3,6 +3,7 @@ config DRM_LOONGSON tristate "DRM support for Loongson Graphics" depends on DRM && PCI && MMU + depends on LOONGARCH || MIPS || COMPILE_TEST select DRM_KMS_HELPER select DRM_TTM select I2C diff --git a/drivers/gpu/drm/loongson/lsdc_i2c.c b/drivers/gpu/drm/loongson/lsdc_i2c.c index 9625d0b1d0b4d8..ce90c25536d240 100644 --- a/drivers/gpu/drm/loongson/lsdc_i2c.c +++ b/drivers/gpu/drm/loongson/lsdc_i2c.c @@ -154,7 +154,6 @@ int lsdc_create_i2c_chan(struct drm_device *ddev, adapter = &li2c->adapter; adapter->algo_data = &li2c->bit; adapter->owner = THIS_MODULE; - adapter->class = I2C_CLASS_DDC; adapter->dev.parent = ddev->dev; adapter->nr = -1; diff --git a/drivers/gpu/drm/loongson/lsdc_plane.c b/drivers/gpu/drm/loongson/lsdc_plane.c index 0d509463322293..d227a2c1dcf16a 100644 --- a/drivers/gpu/drm/loongson/lsdc_plane.c +++ b/drivers/gpu/drm/loongson/lsdc_plane.c @@ -9,7 +9,6 @@ #include #include #include -#include #include "lsdc_drv.h" #include "lsdc_regs.h" diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile index d4d193f60271cb..5e4436403b8d22 100644 --- a/drivers/gpu/drm/mediatek/Makefile +++ b/drivers/gpu/drm/mediatek/Makefile @@ -16,7 +16,8 @@ mediatek-drm-y := mtk_disp_aal.o \ mtk_dsi.o \ mtk_dpi.o \ mtk_ethdr.o \ - mtk_mdp_rdma.o + mtk_mdp_rdma.o \ + mtk_padding.o obj-$(CONFIG_DRM_MEDIATEK) += mediatek-drm.o diff --git a/drivers/gpu/drm/mediatek/mtk_cec.c b/drivers/gpu/drm/mediatek/mtk_cec.c index f47f417d8ba673..8519e9bade361c 100644 --- a/drivers/gpu/drm/mediatek/mtk_cec.c +++ b/drivers/gpu/drm/mediatek/mtk_cec.c @@ -185,7 +185,6 @@ static int mtk_cec_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct mtk_cec *cec; - struct resource *res; int ret; cec = devm_kzalloc(dev, sizeof(*cec), GFP_KERNEL); @@ -195,8 +194,7 @@ static int mtk_cec_probe(struct platform_device *pdev) platform_set_drvdata(pdev, cec); spin_lock_init(&cec->lock); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - cec->regs = devm_ioremap_resource(dev, res); + cec->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(cec->regs)) { ret = PTR_ERR(cec->regs); dev_err(dev, "Failed to ioremap cec: %d\n", ret); diff --git a/drivers/gpu/drm/mediatek/mtk_disp_aal.c b/drivers/gpu/drm/mediatek/mtk_disp_aal.c index 2209159d885572..40fe403086c3d4 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_aal.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_aal.c @@ -168,7 +168,6 @@ static int mtk_disp_aal_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct mtk_disp_aal *priv; - struct resource *res; int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -181,8 +180,7 @@ static int mtk_disp_aal_probe(struct platform_device *pdev) return PTR_ERR(priv->clk); } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->regs = devm_ioremap_resource(dev, res); + priv->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->regs)) { dev_err(dev, "failed to ioremap aal\n"); return PTR_ERR(priv->regs); diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c b/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c index 4234ff7485e884..465cddce0d3241 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c @@ -153,7 +153,6 @@ static int mtk_disp_ccorr_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct mtk_disp_ccorr *priv; - struct resource *res; int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -166,8 +165,7 @@ static int mtk_disp_ccorr_probe(struct platform_device *pdev) return PTR_ERR(priv->clk); } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->regs = devm_ioremap_resource(dev, res); + priv->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->regs)) { dev_err(dev, "failed to ioremap ccorr\n"); return PTR_ERR(priv->regs); diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/mediatek/mtk_disp_drv.h index 1311562d25cc2f..74fa5633938319 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h +++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h @@ -110,6 +110,8 @@ void mtk_ovl_adaptor_connect(struct device *dev, struct device *mmsys_dev, unsigned int next); void mtk_ovl_adaptor_disconnect(struct device *dev, struct device *mmsys_dev, unsigned int next); +int mtk_ovl_adaptor_power_on(struct device *dev); +void mtk_ovl_adaptor_power_off(struct device *dev); int mtk_ovl_adaptor_clk_enable(struct device *dev); void mtk_ovl_adaptor_clk_disable(struct device *dev); void mtk_ovl_adaptor_config(struct device *dev, unsigned int w, @@ -151,6 +153,8 @@ void mtk_rdma_disable_vblank(struct device *dev); const u32 *mtk_rdma_get_formats(struct device *dev); size_t mtk_rdma_get_num_formats(struct device *dev); +int mtk_mdp_rdma_power_on(struct device *dev); +void mtk_mdp_rdma_power_off(struct device *dev); int mtk_mdp_rdma_clk_enable(struct device *dev); void mtk_mdp_rdma_clk_disable(struct device *dev); void mtk_mdp_rdma_start(struct device *dev, struct cmdq_pkt *cmdq_pkt); @@ -160,4 +164,8 @@ void mtk_mdp_rdma_config(struct device *dev, struct mtk_mdp_rdma_cfg *cfg, const u32 *mtk_mdp_rdma_get_formats(struct device *dev); size_t mtk_mdp_rdma_get_num_formats(struct device *dev); +int mtk_padding_clk_enable(struct device *dev); +void mtk_padding_clk_disable(struct device *dev); +void mtk_padding_start(struct device *dev); +void mtk_padding_stop(struct device *dev); #endif diff --git a/drivers/gpu/drm/mediatek/mtk_disp_merge.c b/drivers/gpu/drm/mediatek/mtk_disp_merge.c index e525a6b9e5b0bc..22f768d923d5ab 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_merge.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_merge.c @@ -103,7 +103,7 @@ void mtk_merge_stop_cmdq(struct device *dev, struct cmdq_pkt *cmdq_pkt) mtk_ddp_write(cmdq_pkt, 0, &priv->cmdq_reg, priv->regs, DISP_REG_MERGE_CTRL); - if (priv->async_clk) + if (!cmdq_pkt && priv->async_clk) reset_control_reset(priv->reset_ctl); } diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c index 6bf6367853fbae..12a37f740bf45e 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c @@ -27,13 +27,14 @@ #define MTK_OVL_ADAPTOR_LAYER_NUM 4 enum mtk_ovl_adaptor_comp_type { - OVL_ADAPTOR_TYPE_RDMA = 0, - OVL_ADAPTOR_TYPE_MERGE, OVL_ADAPTOR_TYPE_ETHDR, + OVL_ADAPTOR_TYPE_MDP_RDMA, + OVL_ADAPTOR_TYPE_MERGE, OVL_ADAPTOR_TYPE_NUM, }; enum mtk_ovl_adaptor_comp_id { + OVL_ADAPTOR_ETHDR0, OVL_ADAPTOR_MDP_RDMA0, OVL_ADAPTOR_MDP_RDMA1, OVL_ADAPTOR_MDP_RDMA2, @@ -46,13 +47,14 @@ enum mtk_ovl_adaptor_comp_id { OVL_ADAPTOR_MERGE1, OVL_ADAPTOR_MERGE2, OVL_ADAPTOR_MERGE3, - OVL_ADAPTOR_ETHDR0, OVL_ADAPTOR_ID_MAX }; struct ovl_adaptor_comp_match { enum mtk_ovl_adaptor_comp_type type; + enum mtk_ddp_comp_id comp_id; int alias_id; + const struct mtk_ddp_comp_funcs *funcs; }; struct mtk_disp_ovl_adaptor { @@ -62,25 +64,44 @@ struct mtk_disp_ovl_adaptor { }; static const char * const private_comp_stem[OVL_ADAPTOR_TYPE_NUM] = { - [OVL_ADAPTOR_TYPE_RDMA] = "vdo1-rdma", - [OVL_ADAPTOR_TYPE_MERGE] = "merge", [OVL_ADAPTOR_TYPE_ETHDR] = "ethdr", + [OVL_ADAPTOR_TYPE_MDP_RDMA] = "vdo1-rdma", + [OVL_ADAPTOR_TYPE_MERGE] = "merge", +}; + +static const struct mtk_ddp_comp_funcs ethdr = { + .clk_enable = mtk_ethdr_clk_enable, + .clk_disable = mtk_ethdr_clk_disable, + .start = mtk_ethdr_start, + .stop = mtk_ethdr_stop, +}; + +static const struct mtk_ddp_comp_funcs merge = { + .clk_enable = mtk_merge_clk_enable, + .clk_disable = mtk_merge_clk_disable, +}; + +static const struct mtk_ddp_comp_funcs rdma = { + .power_on = mtk_mdp_rdma_power_on, + .power_off = mtk_mdp_rdma_power_off, + .clk_enable = mtk_mdp_rdma_clk_enable, + .clk_disable = mtk_mdp_rdma_clk_disable, }; static const struct ovl_adaptor_comp_match comp_matches[OVL_ADAPTOR_ID_MAX] = { - [OVL_ADAPTOR_MDP_RDMA0] = { OVL_ADAPTOR_TYPE_RDMA, 0 }, - [OVL_ADAPTOR_MDP_RDMA1] = { OVL_ADAPTOR_TYPE_RDMA, 1 }, - [OVL_ADAPTOR_MDP_RDMA2] = { OVL_ADAPTOR_TYPE_RDMA, 2 }, - [OVL_ADAPTOR_MDP_RDMA3] = { OVL_ADAPTOR_TYPE_RDMA, 3 }, - [OVL_ADAPTOR_MDP_RDMA4] = { OVL_ADAPTOR_TYPE_RDMA, 4 }, - [OVL_ADAPTOR_MDP_RDMA5] = { OVL_ADAPTOR_TYPE_RDMA, 5 }, - [OVL_ADAPTOR_MDP_RDMA6] = { OVL_ADAPTOR_TYPE_RDMA, 6 }, - [OVL_ADAPTOR_MDP_RDMA7] = { OVL_ADAPTOR_TYPE_RDMA, 7 }, - [OVL_ADAPTOR_MERGE0] = { OVL_ADAPTOR_TYPE_MERGE, 1 }, - [OVL_ADAPTOR_MERGE1] = { OVL_ADAPTOR_TYPE_MERGE, 2 }, - [OVL_ADAPTOR_MERGE2] = { OVL_ADAPTOR_TYPE_MERGE, 3 }, - [OVL_ADAPTOR_MERGE3] = { OVL_ADAPTOR_TYPE_MERGE, 4 }, - [OVL_ADAPTOR_ETHDR0] = { OVL_ADAPTOR_TYPE_ETHDR, 0 }, + [OVL_ADAPTOR_ETHDR0] = { OVL_ADAPTOR_TYPE_ETHDR, DDP_COMPONENT_ETHDR_MIXER, 0, ðdr }, + [OVL_ADAPTOR_MDP_RDMA0] = { OVL_ADAPTOR_TYPE_MDP_RDMA, DDP_COMPONENT_MDP_RDMA0, 0, &rdma }, + [OVL_ADAPTOR_MDP_RDMA1] = { OVL_ADAPTOR_TYPE_MDP_RDMA, DDP_COMPONENT_MDP_RDMA1, 1, &rdma }, + [OVL_ADAPTOR_MDP_RDMA2] = { OVL_ADAPTOR_TYPE_MDP_RDMA, DDP_COMPONENT_MDP_RDMA2, 2, &rdma }, + [OVL_ADAPTOR_MDP_RDMA3] = { OVL_ADAPTOR_TYPE_MDP_RDMA, DDP_COMPONENT_MDP_RDMA3, 3, &rdma }, + [OVL_ADAPTOR_MDP_RDMA4] = { OVL_ADAPTOR_TYPE_MDP_RDMA, DDP_COMPONENT_MDP_RDMA4, 4, &rdma }, + [OVL_ADAPTOR_MDP_RDMA5] = { OVL_ADAPTOR_TYPE_MDP_RDMA, DDP_COMPONENT_MDP_RDMA5, 5, &rdma }, + [OVL_ADAPTOR_MDP_RDMA6] = { OVL_ADAPTOR_TYPE_MDP_RDMA, DDP_COMPONENT_MDP_RDMA6, 6, &rdma }, + [OVL_ADAPTOR_MDP_RDMA7] = { OVL_ADAPTOR_TYPE_MDP_RDMA, DDP_COMPONENT_MDP_RDMA7, 7, &rdma }, + [OVL_ADAPTOR_MERGE0] = { OVL_ADAPTOR_TYPE_MERGE, DDP_COMPONENT_MERGE1, 1, &merge }, + [OVL_ADAPTOR_MERGE1] = { OVL_ADAPTOR_TYPE_MERGE, DDP_COMPONENT_MERGE2, 2, &merge }, + [OVL_ADAPTOR_MERGE2] = { OVL_ADAPTOR_TYPE_MERGE, DDP_COMPONENT_MERGE3, 3, &merge }, + [OVL_ADAPTOR_MERGE3] = { OVL_ADAPTOR_TYPE_MERGE, DDP_COMPONENT_MERGE4, 4, &merge }, }; void mtk_ovl_adaptor_layer_config(struct device *dev, unsigned int idx, @@ -172,68 +193,112 @@ void mtk_ovl_adaptor_config(struct device *dev, unsigned int w, void mtk_ovl_adaptor_start(struct device *dev) { + int i; struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev); - mtk_ethdr_start(ovl_adaptor->ovl_adaptor_comp[OVL_ADAPTOR_ETHDR0]); + for (i = 0; i < OVL_ADAPTOR_ID_MAX; i++) { + if (!ovl_adaptor->ovl_adaptor_comp[i] || + !comp_matches[i].funcs->start) + continue; + + comp_matches[i].funcs->start(ovl_adaptor->ovl_adaptor_comp[i]); + } } void mtk_ovl_adaptor_stop(struct device *dev) { + int i; struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev); - mtk_ethdr_stop(ovl_adaptor->ovl_adaptor_comp[OVL_ADAPTOR_ETHDR0]); + for (i = 0; i < OVL_ADAPTOR_ID_MAX; i++) { + if (!ovl_adaptor->ovl_adaptor_comp[i] || + !comp_matches[i].funcs->stop) + continue; + + comp_matches[i].funcs->stop(ovl_adaptor->ovl_adaptor_comp[i]); + } } -int mtk_ovl_adaptor_clk_enable(struct device *dev) +/** + * power_off - Power off the devices in OVL adaptor + * @dev: Device to be powered off + * @num: Number of the devices to be powered off + * + * Calls the .power_off() ovl_adaptor component callback if it is present. + */ +static inline void power_off(struct device *dev, int num) { struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev); - struct device *comp; - int ret; int i; - for (i = 0; i < OVL_ADAPTOR_MERGE0; i++) { - comp = ovl_adaptor->ovl_adaptor_comp[i]; - ret = pm_runtime_get_sync(comp); + if (num > OVL_ADAPTOR_ID_MAX) + num = OVL_ADAPTOR_ID_MAX; + + for (i = num - 1; i >= 0; i--) { + if (!ovl_adaptor->ovl_adaptor_comp[i] || + !comp_matches[i].funcs->power_off) + continue; + + comp_matches[i].funcs->power_off(ovl_adaptor->ovl_adaptor_comp[i]); + } +} + +/** + * mtk_ovl_adaptor_power_on - Power on the devices in OVL adaptor + * @dev: Device to be powered on + * + * Different from OVL, OVL adaptor is a pseudo device so + * we didn't define it in the device tree, pm_runtime_resume_and_get() + * called by .atomic_enable() power on no device in OVL adaptor, + * we have to implement a function to do the job instead. + * + * Return: Zero for success or negative number for failure. + */ +int mtk_ovl_adaptor_power_on(struct device *dev) +{ + struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev); + int i, ret; + + for (i = 0; i < OVL_ADAPTOR_ID_MAX; i++) { + if (!ovl_adaptor->ovl_adaptor_comp[i] || + !comp_matches[i].funcs->power_on) + continue; + + ret = comp_matches[i].funcs->power_on(ovl_adaptor->ovl_adaptor_comp[i]); if (ret < 0) { dev_err(dev, "Failed to enable power domain %d, err %d\n", i, ret); - goto pwr_err; + power_off(dev, i); + return ret; } } + return 0; +} + +void mtk_ovl_adaptor_power_off(struct device *dev) +{ + power_off(dev, OVL_ADAPTOR_ID_MAX); +} + +int mtk_ovl_adaptor_clk_enable(struct device *dev) +{ + struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev); + struct device *comp; + int ret; + int i; for (i = 0; i < OVL_ADAPTOR_ID_MAX; i++) { comp = ovl_adaptor->ovl_adaptor_comp[i]; - - if (i < OVL_ADAPTOR_MERGE0) - ret = mtk_mdp_rdma_clk_enable(comp); - else if (i < OVL_ADAPTOR_ETHDR0) - ret = mtk_merge_clk_enable(comp); - else - ret = mtk_ethdr_clk_enable(comp); + if (!comp || !comp_matches[i].funcs->clk_enable) + continue; + ret = comp_matches[i].funcs->clk_enable(comp); if (ret) { dev_err(dev, "Failed to enable clock %d, err %d\n", i, ret); - goto clk_err; + while (--i >= 0) + comp_matches[i].funcs->clk_disable(comp); + return ret; } } - - return ret; - -clk_err: - while (--i >= 0) { - comp = ovl_adaptor->ovl_adaptor_comp[i]; - if (i < OVL_ADAPTOR_MERGE0) - mtk_mdp_rdma_clk_disable(comp); - else if (i < OVL_ADAPTOR_ETHDR0) - mtk_merge_clk_disable(comp); - else - mtk_ethdr_clk_disable(comp); - } - i = OVL_ADAPTOR_MERGE0; - -pwr_err: - while (--i >= 0) - pm_runtime_put(ovl_adaptor->ovl_adaptor_comp[i]); - - return ret; + return 0; } void mtk_ovl_adaptor_clk_disable(struct device *dev) @@ -244,15 +309,11 @@ void mtk_ovl_adaptor_clk_disable(struct device *dev) for (i = 0; i < OVL_ADAPTOR_ID_MAX; i++) { comp = ovl_adaptor->ovl_adaptor_comp[i]; - - if (i < OVL_ADAPTOR_MERGE0) { - mtk_mdp_rdma_clk_disable(comp); + if (!comp || !comp_matches[i].funcs->clk_disable) + continue; + comp_matches[i].funcs->clk_disable(comp); + if (i < OVL_ADAPTOR_MERGE0) pm_runtime_put(comp); - } else if (i < OVL_ADAPTOR_ETHDR0) { - mtk_merge_clk_disable(comp); - } else { - mtk_ethdr_clk_disable(comp); - } } } @@ -314,40 +375,31 @@ size_t mtk_ovl_adaptor_get_num_formats(struct device *dev) void mtk_ovl_adaptor_add_comp(struct device *dev, struct mtk_mutex *mutex) { - mtk_mutex_add_comp(mutex, DDP_COMPONENT_MDP_RDMA0); - mtk_mutex_add_comp(mutex, DDP_COMPONENT_MDP_RDMA1); - mtk_mutex_add_comp(mutex, DDP_COMPONENT_MDP_RDMA2); - mtk_mutex_add_comp(mutex, DDP_COMPONENT_MDP_RDMA3); - mtk_mutex_add_comp(mutex, DDP_COMPONENT_MDP_RDMA4); - mtk_mutex_add_comp(mutex, DDP_COMPONENT_MDP_RDMA5); - mtk_mutex_add_comp(mutex, DDP_COMPONENT_MDP_RDMA6); - mtk_mutex_add_comp(mutex, DDP_COMPONENT_MDP_RDMA7); - mtk_mutex_add_comp(mutex, DDP_COMPONENT_MERGE1); - mtk_mutex_add_comp(mutex, DDP_COMPONENT_MERGE2); - mtk_mutex_add_comp(mutex, DDP_COMPONENT_MERGE3); - mtk_mutex_add_comp(mutex, DDP_COMPONENT_MERGE4); - mtk_mutex_add_comp(mutex, DDP_COMPONENT_ETHDR_MIXER); + int i; + struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev); + + for (i = 0; i < OVL_ADAPTOR_ID_MAX; i++) { + if (!ovl_adaptor->ovl_adaptor_comp[i]) + continue; + mtk_mutex_add_comp(mutex, comp_matches[i].comp_id); + } } void mtk_ovl_adaptor_remove_comp(struct device *dev, struct mtk_mutex *mutex) { - mtk_mutex_remove_comp(mutex, DDP_COMPONENT_MDP_RDMA0); - mtk_mutex_remove_comp(mutex, DDP_COMPONENT_MDP_RDMA1); - mtk_mutex_remove_comp(mutex, DDP_COMPONENT_MDP_RDMA2); - mtk_mutex_remove_comp(mutex, DDP_COMPONENT_MDP_RDMA3); - mtk_mutex_remove_comp(mutex, DDP_COMPONENT_MDP_RDMA4); - mtk_mutex_remove_comp(mutex, DDP_COMPONENT_MDP_RDMA5); - mtk_mutex_remove_comp(mutex, DDP_COMPONENT_MDP_RDMA6); - mtk_mutex_remove_comp(mutex, DDP_COMPONENT_MDP_RDMA7); - mtk_mutex_remove_comp(mutex, DDP_COMPONENT_MERGE1); - mtk_mutex_remove_comp(mutex, DDP_COMPONENT_MERGE2); - mtk_mutex_remove_comp(mutex, DDP_COMPONENT_MERGE3); - mtk_mutex_remove_comp(mutex, DDP_COMPONENT_MERGE4); - mtk_mutex_remove_comp(mutex, DDP_COMPONENT_ETHDR_MIXER); + int i; + struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev); + + for (i = 0; i < OVL_ADAPTOR_ID_MAX; i++) { + if (!ovl_adaptor->ovl_adaptor_comp[i]) + continue; + mtk_mutex_remove_comp(mutex, comp_matches[i].comp_id); + } } void mtk_ovl_adaptor_connect(struct device *dev, struct device *mmsys_dev, unsigned int next) { + mtk_mmsys_ddp_connect(mmsys_dev, DDP_COMPONENT_ETHDR_MIXER, next); mtk_mmsys_ddp_connect(mmsys_dev, DDP_COMPONENT_MDP_RDMA0, DDP_COMPONENT_MERGE1); mtk_mmsys_ddp_connect(mmsys_dev, DDP_COMPONENT_MDP_RDMA1, DDP_COMPONENT_MERGE1); mtk_mmsys_ddp_connect(mmsys_dev, DDP_COMPONENT_MDP_RDMA2, DDP_COMPONENT_MERGE2); @@ -355,11 +407,11 @@ void mtk_ovl_adaptor_connect(struct device *dev, struct device *mmsys_dev, unsig mtk_mmsys_ddp_connect(mmsys_dev, DDP_COMPONENT_MERGE2, DDP_COMPONENT_ETHDR_MIXER); mtk_mmsys_ddp_connect(mmsys_dev, DDP_COMPONENT_MERGE3, DDP_COMPONENT_ETHDR_MIXER); mtk_mmsys_ddp_connect(mmsys_dev, DDP_COMPONENT_MERGE4, DDP_COMPONENT_ETHDR_MIXER); - mtk_mmsys_ddp_connect(mmsys_dev, DDP_COMPONENT_ETHDR_MIXER, next); } void mtk_ovl_adaptor_disconnect(struct device *dev, struct device *mmsys_dev, unsigned int next) { + mtk_mmsys_ddp_disconnect(mmsys_dev, DDP_COMPONENT_ETHDR_MIXER, next); mtk_mmsys_ddp_disconnect(mmsys_dev, DDP_COMPONENT_MDP_RDMA0, DDP_COMPONENT_MERGE1); mtk_mmsys_ddp_disconnect(mmsys_dev, DDP_COMPONENT_MDP_RDMA1, DDP_COMPONENT_MERGE1); mtk_mmsys_ddp_disconnect(mmsys_dev, DDP_COMPONENT_MDP_RDMA2, DDP_COMPONENT_MERGE2); @@ -367,7 +419,6 @@ void mtk_ovl_adaptor_disconnect(struct device *dev, struct device *mmsys_dev, un mtk_mmsys_ddp_disconnect(mmsys_dev, DDP_COMPONENT_MERGE2, DDP_COMPONENT_ETHDR_MIXER); mtk_mmsys_ddp_disconnect(mmsys_dev, DDP_COMPONENT_MERGE3, DDP_COMPONENT_ETHDR_MIXER); mtk_mmsys_ddp_disconnect(mmsys_dev, DDP_COMPONENT_MERGE4, DDP_COMPONENT_ETHDR_MIXER); - mtk_mmsys_ddp_disconnect(mmsys_dev, DDP_COMPONENT_ETHDR_MIXER, next); } static int ovl_adaptor_comp_get_id(struct device *dev, struct device_node *node, @@ -386,17 +437,10 @@ static int ovl_adaptor_comp_get_id(struct device *dev, struct device_node *node, } static const struct of_device_id mtk_ovl_adaptor_comp_dt_ids[] = { - { - .compatible = "mediatek,mt8195-vdo1-rdma", - .data = (void *)OVL_ADAPTOR_TYPE_RDMA, - }, { - .compatible = "mediatek,mt8195-disp-merge", - .data = (void *)OVL_ADAPTOR_TYPE_MERGE, - }, { - .compatible = "mediatek,mt8195-disp-ethdr", - .data = (void *)OVL_ADAPTOR_TYPE_ETHDR, - }, - {}, + { .compatible = "mediatek,mt8195-disp-ethdr", .data = (void *)OVL_ADAPTOR_TYPE_ETHDR }, + { .compatible = "mediatek,mt8195-disp-merge", .data = (void *)OVL_ADAPTOR_TYPE_MERGE }, + { .compatible = "mediatek,mt8195-vdo1-rdma", .data = (void *)OVL_ADAPTOR_TYPE_MDP_RDMA }, + { /* sentinel */ } }; static int compare_of(struct device *dev, void *data) @@ -531,16 +575,15 @@ static int mtk_disp_ovl_adaptor_probe(struct platform_device *pdev) return ret; } -static int mtk_disp_ovl_adaptor_remove(struct platform_device *pdev) +static void mtk_disp_ovl_adaptor_remove(struct platform_device *pdev) { component_master_del(&pdev->dev, &mtk_disp_ovl_adaptor_master_ops); pm_runtime_disable(&pdev->dev); - return 0; } struct platform_driver mtk_disp_ovl_adaptor_driver = { .probe = mtk_disp_ovl_adaptor_probe, - .remove = mtk_disp_ovl_adaptor_remove, + .remove_new = mtk_disp_ovl_adaptor_remove, .driver = { .name = "mediatek-disp-ovl-adaptor", .owner = THIS_MODULE, diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c index e4c16ba9902dc0..2136a596efa185 100644 --- a/drivers/gpu/drm/mediatek/mtk_dp.c +++ b/drivers/gpu/drm/mediatek/mtk_dp.c @@ -2818,3 +2818,4 @@ MODULE_AUTHOR("Markus Schneider-Pargmann "); MODULE_AUTHOR("Bo-Chen Chen "); MODULE_DESCRIPTION("MediaTek DisplayPort Driver"); MODULE_LICENSE("GPL"); +MODULE_SOFTDEP("pre: phy_mtk_dp"); diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c index 4e3d9f7b4d8c9a..beb7d9d08e9715 100644 --- a/drivers/gpu/drm/mediatek/mtk_dpi.c +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c @@ -966,20 +966,6 @@ static const struct mtk_dpi_conf mt8186_conf = { .csc_enable_bit = CSC_ENABLE, }; -static const struct mtk_dpi_conf mt8188_dpintf_conf = { - .cal_factor = mt8195_dpintf_calculate_factor, - .max_clock_khz = 600000, - .output_fmts = mt8195_output_fmts, - .num_output_fmts = ARRAY_SIZE(mt8195_output_fmts), - .pixels_per_iter = 4, - .input_2pixel = false, - .dimension_mask = DPINTF_HPW_MASK, - .hvsize_mask = DPINTF_HSIZE_MASK, - .channel_swap_shift = DPINTF_CH_SWAP, - .yuv422_en_bit = DPINTF_YUV422_EN, - .csc_enable_bit = DPINTF_CSC_ENABLE, -}; - static const struct mtk_dpi_conf mt8192_conf = { .cal_factor = mt8183_calculate_factor, .reg_h_fre_con = 0xe0, @@ -1103,7 +1089,7 @@ static const struct of_device_id mtk_dpi_of_ids[] = { { .compatible = "mediatek,mt8173-dpi", .data = &mt8173_conf }, { .compatible = "mediatek,mt8183-dpi", .data = &mt8183_conf }, { .compatible = "mediatek,mt8186-dpi", .data = &mt8186_conf }, - { .compatible = "mediatek,mt8188-dp-intf", .data = &mt8188_dpintf_conf }, + { .compatible = "mediatek,mt8188-dp-intf", .data = &mt8195_dpintf_conf }, { .compatible = "mediatek,mt8192-dpi", .data = &mt8192_conf }, { .compatible = "mediatek,mt8195-dp-intf", .data = &mt8195_dpintf_conf }, { /* sentinel */ }, diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c index db43f9dff912e4..c729af3b982246 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c @@ -721,7 +721,7 @@ static void mtk_drm_crtc_atomic_enable(struct drm_crtc *crtc, DRM_DEBUG_DRIVER("%s %d\n", __func__, crtc->base.id); - ret = pm_runtime_resume_and_get(comp->dev); + ret = mtk_ddp_comp_power_on(comp); if (ret < 0) { DRM_DEV_ERROR(comp->dev, "Failed to enable power domain: %d\n", ret); return; @@ -731,7 +731,7 @@ static void mtk_drm_crtc_atomic_enable(struct drm_crtc *crtc, ret = mtk_crtc_ddp_hw_init(mtk_crtc); if (ret) { - pm_runtime_put(comp->dev); + mtk_ddp_comp_power_off(comp); return; } @@ -744,7 +744,7 @@ static void mtk_drm_crtc_atomic_disable(struct drm_crtc *crtc, { struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc); struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0]; - int i, ret; + int i; DRM_DEBUG_DRIVER("%s %d\n", __func__, crtc->base.id); if (!mtk_crtc->enabled) @@ -774,9 +774,7 @@ static void mtk_drm_crtc_atomic_disable(struct drm_crtc *crtc, drm_crtc_vblank_off(crtc); mtk_crtc_ddp_hw_fini(mtk_crtc); - ret = pm_runtime_put(comp->dev); - if (ret < 0) - DRM_DEV_ERROR(comp->dev, "Failed to disable power domain: %d\n", ret); + mtk_ddp_comp_power_off(comp); mtk_crtc->enabled = false; } diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c index 3046c0409353be..a9b5a21cde2da9 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c @@ -398,6 +398,8 @@ static const struct mtk_ddp_comp_funcs ddp_ufoe = { }; static const struct mtk_ddp_comp_funcs ddp_ovl_adaptor = { + .power_on = mtk_ovl_adaptor_power_on, + .power_off = mtk_ovl_adaptor_power_off, .clk_enable = mtk_ovl_adaptor_clk_enable, .clk_disable = mtk_ovl_adaptor_clk_disable, .config = mtk_ovl_adaptor_config, diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h index 4bae55bdb034e6..15b2eafff43840 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h @@ -7,6 +7,7 @@ #define MTK_DRM_DDP_COMP_H #include +#include #include #include #include @@ -46,6 +47,8 @@ enum mtk_ddp_comp_type { struct mtk_ddp_comp; struct cmdq_pkt; struct mtk_ddp_comp_funcs { + int (*power_on)(struct device *dev); + void (*power_off)(struct device *dev); int (*clk_enable)(struct device *dev); void (*clk_disable)(struct device *dev); void (*config)(struct device *dev, unsigned int w, @@ -92,6 +95,23 @@ struct mtk_ddp_comp { const struct mtk_ddp_comp_funcs *funcs; }; +static inline int mtk_ddp_comp_power_on(struct mtk_ddp_comp *comp) +{ + if (comp->funcs && comp->funcs->power_on) + return comp->funcs->power_on(comp->dev); + else + return pm_runtime_resume_and_get(comp->dev); + return 0; +} + +static inline void mtk_ddp_comp_power_off(struct mtk_ddp_comp *comp) +{ + if (comp->funcs && comp->funcs->power_off) + comp->funcs->power_off(comp->dev); + else + pm_runtime_put(comp->dev); +} + static inline int mtk_ddp_comp_clk_enable(struct mtk_ddp_comp *comp) { if (comp->funcs && comp->funcs->clk_enable) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index 2b0c35cacbc6da..14a1e0157cc4b2 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include @@ -611,9 +610,6 @@ static int mtk_drm_bind(struct device *dev) struct drm_device *drm; int ret, i; - if (!iommu_present(&platform_bus_type)) - return -EPROBE_DEFER; - pdev = of_find_device_by_node(private->mutex_node); if (!pdev) { dev_err(dev, "Waiting for disp-mutex device %pOF\n", @@ -1003,6 +999,7 @@ static struct platform_driver * const mtk_drm_drivers[] = { &mtk_dsi_driver, &mtk_ethdr_driver, &mtk_mdp_rdma_driver, + &mtk_padding_driver, }; static int __init mtk_drm_init(void) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h index 6f98fff4f1a4c7..33fadb08dc1c7b 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h @@ -77,5 +77,5 @@ extern struct platform_driver mtk_dpi_driver; extern struct platform_driver mtk_dsi_driver; extern struct platform_driver mtk_ethdr_driver; extern struct platform_driver mtk_mdp_rdma_driver; - +extern struct platform_driver mtk_padding_driver; #endif /* MTK_DRM_DRV_H */ diff --git a/drivers/gpu/drm/mediatek/mtk_ethdr.c b/drivers/gpu/drm/mediatek/mtk_ethdr.c index db7ac666ec5e11..6a5d0c345aab96 100644 --- a/drivers/gpu/drm/mediatek/mtk_ethdr.c +++ b/drivers/gpu/drm/mediatek/mtk_ethdr.c @@ -346,10 +346,9 @@ static int mtk_ethdr_probe(struct platform_device *pdev) return ret; } -static int mtk_ethdr_remove(struct platform_device *pdev) +static void mtk_ethdr_remove(struct platform_device *pdev) { component_del(&pdev->dev, &mtk_ethdr_component_ops); - return 0; } static const struct of_device_id mtk_ethdr_driver_dt_match[] = { @@ -361,7 +360,7 @@ MODULE_DEVICE_TABLE(of, mtk_ethdr_driver_dt_match); struct platform_driver mtk_ethdr_driver = { .probe = mtk_ethdr_probe, - .remove = mtk_ethdr_remove, + .remove_new = mtk_ethdr_remove, .driver = { .name = "mediatek-disp-ethdr", .owner = THIS_MODULE, diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c b/drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c index d675c954befe3c..54e46e440e0f0d 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_ddc.c @@ -297,7 +297,6 @@ static int mtk_hdmi_ddc_probe(struct platform_device *pdev) strscpy(ddc->adap.name, "mediatek-hdmi-ddc", sizeof(ddc->adap.name)); ddc->adap.owner = THIS_MODULE; - ddc->adap.class = I2C_CLASS_DDC; ddc->adap.algo = &mtk_hdmi_ddc_algorithm; ddc->adap.retries = 3; ddc->adap.dev.of_node = dev->of_node; diff --git a/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c b/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c index c3adaeefd551a2..ee9ce9b6d07864 100644 --- a/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c +++ b/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c @@ -242,12 +242,27 @@ size_t mtk_mdp_rdma_get_num_formats(struct device *dev) return ARRAY_SIZE(formats); } +int mtk_mdp_rdma_power_on(struct device *dev) +{ + int ret = pm_runtime_resume_and_get(dev); + + if (ret < 0) { + dev_err(dev, "Failed to power on: %d\n", ret); + return ret; + } + return 0; +} + +void mtk_mdp_rdma_power_off(struct device *dev) +{ + pm_runtime_put(dev); +} + int mtk_mdp_rdma_clk_enable(struct device *dev) { struct mtk_mdp_rdma *rdma = dev_get_drvdata(dev); - clk_prepare_enable(rdma->clk); - return 0; + return clk_prepare_enable(rdma->clk); } void mtk_mdp_rdma_clk_disable(struct device *dev) diff --git a/drivers/gpu/drm/mediatek/mtk_padding.c b/drivers/gpu/drm/mediatek/mtk_padding.c new file mode 100644 index 00000000000000..0d6451c149b672 --- /dev/null +++ b/drivers/gpu/drm/mediatek/mtk_padding.c @@ -0,0 +1,160 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 MediaTek Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "mtk_disp_drv.h" +#include "mtk_drm_crtc.h" +#include "mtk_drm_ddp_comp.h" + +#define PADDING_CONTROL_REG 0x00 +#define PADDING_BYPASS BIT(0) +#define PADDING_ENABLE BIT(1) +#define PADDING_PIC_SIZE_REG 0x04 +#define PADDING_H_REG 0x08 /* horizontal */ +#define PADDING_V_REG 0x0c /* vertical */ +#define PADDING_COLOR_REG 0x10 + +/** + * struct mtk_padding - Basic information of the Padding + * @clk: Clock of the module + * @reg: Virtual address of the Padding for CPU to access + * @cmdq_reg: CMDQ setting of the Padding + * + * Every Padding should have different clock source, register base, and + * CMDQ settings, we stored these differences all together. + */ +struct mtk_padding { + struct clk *clk; + void __iomem *reg; + struct cmdq_client_reg cmdq_reg; +}; + +int mtk_padding_clk_enable(struct device *dev) +{ + struct mtk_padding *padding = dev_get_drvdata(dev); + + return clk_prepare_enable(padding->clk); +} + +void mtk_padding_clk_disable(struct device *dev) +{ + struct mtk_padding *padding = dev_get_drvdata(dev); + + clk_disable_unprepare(padding->clk); +} + +void mtk_padding_start(struct device *dev) +{ + struct mtk_padding *padding = dev_get_drvdata(dev); + + writel(PADDING_ENABLE | PADDING_BYPASS, + padding->reg + PADDING_CONTROL_REG); + + /* + * Notice that even the padding is in bypass mode, + * all the settings must be cleared to 0 or + * undefined behaviors could happen + */ + writel(0, padding->reg + PADDING_PIC_SIZE_REG); + writel(0, padding->reg + PADDING_H_REG); + writel(0, padding->reg + PADDING_V_REG); + writel(0, padding->reg + PADDING_COLOR_REG); +} + +void mtk_padding_stop(struct device *dev) +{ + struct mtk_padding *padding = dev_get_drvdata(dev); + + writel(0, padding->reg + PADDING_CONTROL_REG); +} + +static int mtk_padding_bind(struct device *dev, struct device *master, void *data) +{ + return 0; +} + +static void mtk_padding_unbind(struct device *dev, struct device *master, void *data) +{ +} + +static const struct component_ops mtk_padding_component_ops = { + .bind = mtk_padding_bind, + .unbind = mtk_padding_unbind, +}; + +static int mtk_padding_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mtk_padding *priv; + struct resource *res; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) { + dev_err(dev, "failed to get clk\n"); + return PTR_ERR(priv->clk); + } + + priv->reg = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(priv->reg)) { + dev_err(dev, "failed to do ioremap\n"); + return PTR_ERR(priv->reg); + } + +#if IS_REACHABLE(CONFIG_MTK_CMDQ) + ret = cmdq_dev_get_client_reg(dev, &priv->cmdq_reg, 0); + if (ret) { + dev_err(dev, "failed to get gce client reg\n"); + return ret; + } +#endif + + platform_set_drvdata(pdev, priv); + + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; + + ret = component_add(dev, &mtk_padding_component_ops); + if (ret) { + pm_runtime_disable(dev); + return dev_err_probe(dev, ret, "failed to add component\n"); + } + + return 0; +} + +static int mtk_padding_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &mtk_padding_component_ops); + return 0; +} + +static const struct of_device_id mtk_padding_driver_dt_match[] = { + { .compatible = "mediatek,mt8188-disp-padding" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mtk_padding_driver_dt_match); + +struct platform_driver mtk_padding_driver = { + .probe = mtk_padding_probe, + .remove = mtk_padding_remove, + .driver = { + .name = "mediatek-disp-padding", + .owner = THIS_MODULE, + .of_match_table = mtk_padding_driver_dt_match, + }, +}; diff --git a/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c b/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c index e5fe4e994f43b1..a6bc1bdb3d0d84 100644 --- a/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c +++ b/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c @@ -323,13 +323,11 @@ static int meson_dw_mipi_dsi_probe(struct platform_device *pdev) return 0; } -static int meson_dw_mipi_dsi_remove(struct platform_device *pdev) +static void meson_dw_mipi_dsi_remove(struct platform_device *pdev) { struct meson_dw_mipi_dsi *mipi_dsi = platform_get_drvdata(pdev); dw_mipi_dsi_remove(mipi_dsi->dmd); - - return 0; } static const struct of_device_id meson_dw_mipi_dsi_of_table[] = { @@ -340,7 +338,7 @@ MODULE_DEVICE_TABLE(of, meson_dw_mipi_dsi_of_table); static struct platform_driver meson_dw_mipi_dsi_platform_driver = { .probe = meson_dw_mipi_dsi_probe, - .remove = meson_dw_mipi_dsi_remove, + .remove_new = meson_dw_mipi_dsi_remove, .driver = { .name = DRIVER_NAME, .of_match_table = meson_dw_mipi_dsi_of_table, diff --git a/drivers/gpu/drm/mgag200/mgag200_i2c.c b/drivers/gpu/drm/mgag200/mgag200_i2c.c index 0c48bdf3e7f800..423eb302be7eb9 100644 --- a/drivers/gpu/drm/mgag200/mgag200_i2c.c +++ b/drivers/gpu/drm/mgag200/mgag200_i2c.c @@ -106,7 +106,6 @@ int mgag200_i2c_init(struct mga_device *mdev, struct mga_i2c_chan *i2c) i2c->data = BIT(info->i2c.data_bit); i2c->clock = BIT(info->i2c.clock_bit); i2c->adapter.owner = THIS_MODULE; - i2c->adapter.class = I2C_CLASS_DDC; i2c->adapter.dev.parent = dev->dev; i2c->dev = dev; i2c_set_adapdata(&i2c->adapter, i2c); diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index 6309a857ca3128..f202f26adab2a2 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -6,6 +6,7 @@ config DRM_MSM depends on ARCH_QCOM || SOC_IMX5 || COMPILE_TEST depends on COMMON_CLK depends on IOMMU_SUPPORT + depends on QCOM_AOSS_QMP || QCOM_AOSS_QMP=n depends on QCOM_OCMEM || QCOM_OCMEM=n depends on QCOM_LLCC || QCOM_LLCC=n depends on QCOM_COMMAND_DB || QCOM_COMMAND_DB=n @@ -16,6 +17,7 @@ config DRM_MSM select DRM_DP_AUX_BUS select DRM_DISPLAY_DP_HELPER select DRM_DISPLAY_HELPER + select DRM_EXEC select DRM_KMS_HELPER select DRM_PANEL select DRM_BRIDGE diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index 49671364fdcfb9..b1173128b5b97f 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -63,6 +63,7 @@ msm-$(CONFIG_DRM_MSM_DPU) += \ disp/dpu1/dpu_encoder_phys_wb.o \ disp/dpu1/dpu_formats.o \ disp/dpu1/dpu_hw_catalog.o \ + disp/dpu1/dpu_hw_cdm.o \ disp/dpu1/dpu_hw_ctl.o \ disp/dpu1/dpu_hw_dsc.o \ disp/dpu1/dpu_hw_dsc_1_2.o \ diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c index e5916c10679679..c003f970189b06 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c @@ -684,7 +684,7 @@ static int a5xx_hw_init(struct msm_gpu *gpu) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu); - u32 regbit; + u32 hbb; int ret; gpu_write(gpu, REG_A5XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x00000003); @@ -820,18 +820,15 @@ static int a5xx_hw_init(struct msm_gpu *gpu) gpu_write(gpu, REG_A5XX_RBBM_AHB_CNTL2, 0x0000003F); - /* Set the highest bank bit */ - if (adreno_is_a540(adreno_gpu) || adreno_is_a530(adreno_gpu)) - regbit = 2; - else - regbit = 1; + BUG_ON(adreno_gpu->ubwc_config.highest_bank_bit < 13); + hbb = adreno_gpu->ubwc_config.highest_bank_bit - 13; - gpu_write(gpu, REG_A5XX_TPL1_MODE_CNTL, regbit << 7); - gpu_write(gpu, REG_A5XX_RB_MODE_CNTL, regbit << 1); + gpu_write(gpu, REG_A5XX_TPL1_MODE_CNTL, hbb << 7); + gpu_write(gpu, REG_A5XX_RB_MODE_CNTL, hbb << 1); if (adreno_is_a509(adreno_gpu) || adreno_is_a512(adreno_gpu) || adreno_is_a540(adreno_gpu)) - gpu_write(gpu, REG_A5XX_UCHE_DBG_ECO_CNTL_2, regbit); + gpu_write(gpu, REG_A5XX_UCHE_DBG_ECO_CNTL_2, hbb); /* Disable All flat shading optimization (ALLFLATOPTDIS) */ gpu_rmw(gpu, REG_A5XX_VPC_DBG_ECO_CNTL, 0, (1 << 10)); @@ -1785,5 +1782,11 @@ struct msm_gpu *a5xx_gpu_init(struct drm_device *dev) /* Set up the preemption specific bits and pieces for each ringbuffer */ a5xx_preempt_init(gpu); + /* Set the highest bank bit */ + if (adreno_is_a540(adreno_gpu) || adreno_is_a530(adreno_gpu)) + adreno_gpu->ubwc_config.highest_bank_bit = 15; + else + adreno_gpu->ubwc_config.highest_bank_bit = 14; + return gpu; } diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c index 7a0220d29a235b..c0bc924cd3025d 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c @@ -1270,87 +1270,92 @@ static void a6xx_set_cp_protect(struct msm_gpu *gpu) gpu_write(gpu, REG_A6XX_CP_PROTECT(count_max - 1), regs[i]); } -static void a6xx_set_ubwc_config(struct msm_gpu *gpu) +static void a6xx_calc_ubwc_config(struct adreno_gpu *gpu) { - struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); /* Unknown, introduced with A650 family, related to UBWC mode/ver 4 */ - u32 rgb565_predicator = 0; + gpu->ubwc_config.rgb565_predicator = 0; /* Unknown, introduced with A650 family */ - u32 uavflagprd_inv = 0; + gpu->ubwc_config.uavflagprd_inv = 0; /* Whether the minimum access length is 64 bits */ - u32 min_acc_len = 0; + gpu->ubwc_config.min_acc_len = 0; /* Entirely magic, per-GPU-gen value */ - u32 ubwc_mode = 0; + gpu->ubwc_config.ubwc_mode = 0; /* * The Highest Bank Bit value represents the bit of the highest DDR bank. - * We then subtract 13 from it (13 is the minimum value allowed by hw) and - * write the lowest two bits of the remaining value as hbb_lo and the - * one above it as hbb_hi to the hardware. This should ideally use DRAM - * type detection. + * This should ideally use DRAM type detection. */ - u32 hbb_hi = 0; - u32 hbb_lo = 2; - /* Unknown, introduced with A640/680 */ - u32 amsbc = 0; + gpu->ubwc_config.highest_bank_bit = 15; - if (adreno_is_a610(adreno_gpu)) { - /* HBB = 14 */ - hbb_lo = 1; - min_acc_len = 1; - ubwc_mode = 1; + if (adreno_is_a610(gpu)) { + gpu->ubwc_config.highest_bank_bit = 14; + gpu->ubwc_config.min_acc_len = 1; + gpu->ubwc_config.ubwc_mode = 1; } /* a618 is using the hw default values */ - if (adreno_is_a618(adreno_gpu)) + if (adreno_is_a618(gpu)) return; - if (adreno_is_a619_holi(adreno_gpu)) - hbb_lo = 0; + if (adreno_is_a619_holi(gpu)) + gpu->ubwc_config.highest_bank_bit = 13; - if (adreno_is_a640_family(adreno_gpu)) - amsbc = 1; + if (adreno_is_a640_family(gpu)) + gpu->ubwc_config.amsbc = 1; - if (adreno_is_a650(adreno_gpu) || - adreno_is_a660(adreno_gpu) || - adreno_is_a730(adreno_gpu) || - adreno_is_a740_family(adreno_gpu)) { + if (adreno_is_a650(gpu) || + adreno_is_a660(gpu) || + adreno_is_a690(gpu) || + adreno_is_a730(gpu) || + adreno_is_a740_family(gpu)) { /* TODO: get ddr type from bootloader and use 2 for LPDDR4 */ - hbb_lo = 3; - amsbc = 1; - rgb565_predicator = 1; - uavflagprd_inv = 2; + gpu->ubwc_config.highest_bank_bit = 16; + gpu->ubwc_config.amsbc = 1; + gpu->ubwc_config.rgb565_predicator = 1; + gpu->ubwc_config.uavflagprd_inv = 2; } - if (adreno_is_a690(adreno_gpu)) { - hbb_lo = 2; - amsbc = 1; - rgb565_predicator = 1; - uavflagprd_inv = 2; + if (adreno_is_7c3(gpu)) { + gpu->ubwc_config.highest_bank_bit = 14; + gpu->ubwc_config.amsbc = 1; + gpu->ubwc_config.rgb565_predicator = 1; + gpu->ubwc_config.uavflagprd_inv = 2; } +} - if (adreno_is_7c3(adreno_gpu)) { - hbb_lo = 1; - amsbc = 1; - rgb565_predicator = 1; - uavflagprd_inv = 2; - } +static void a6xx_set_ubwc_config(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + /* + * We subtract 13 from the highest bank bit (13 is the minimum value + * allowed by hw) and write the lowest two bits of the remaining value + * as hbb_lo and the one above it as hbb_hi to the hardware. + */ + BUG_ON(adreno_gpu->ubwc_config.highest_bank_bit < 13); + u32 hbb = adreno_gpu->ubwc_config.highest_bank_bit - 13; + u32 hbb_hi = hbb >> 2; + u32 hbb_lo = hbb & 3; gpu_write(gpu, REG_A6XX_RB_NC_MODE_CNTL, - rgb565_predicator << 11 | hbb_hi << 10 | amsbc << 4 | - min_acc_len << 3 | hbb_lo << 1 | ubwc_mode); + adreno_gpu->ubwc_config.rgb565_predicator << 11 | + hbb_hi << 10 | adreno_gpu->ubwc_config.amsbc << 4 | + adreno_gpu->ubwc_config.min_acc_len << 3 | + hbb_lo << 1 | adreno_gpu->ubwc_config.ubwc_mode); gpu_write(gpu, REG_A6XX_TPL1_NC_MODE_CNTL, hbb_hi << 4 | - min_acc_len << 3 | hbb_lo << 1 | ubwc_mode); + adreno_gpu->ubwc_config.min_acc_len << 3 | + hbb_lo << 1 | adreno_gpu->ubwc_config.ubwc_mode); gpu_write(gpu, REG_A6XX_SP_NC_MODE_CNTL, hbb_hi << 10 | - uavflagprd_inv << 4 | min_acc_len << 3 | - hbb_lo << 1 | ubwc_mode); + adreno_gpu->ubwc_config.uavflagprd_inv << 4 | + adreno_gpu->ubwc_config.min_acc_len << 3 | + hbb_lo << 1 | adreno_gpu->ubwc_config.ubwc_mode); if (adreno_is_a7xx(adreno_gpu)) gpu_write(gpu, REG_A7XX_GRAS_NC_MODE_CNTL, FIELD_PREP(GENMASK(8, 5), hbb_lo)); - gpu_write(gpu, REG_A6XX_UCHE_MODE_CNTL, min_acc_len << 23 | hbb_lo << 21); + gpu_write(gpu, REG_A6XX_UCHE_MODE_CNTL, + adreno_gpu->ubwc_config.min_acc_len << 23 | hbb_lo << 21); } static int a6xx_cp_init(struct msm_gpu *gpu) @@ -1741,7 +1746,9 @@ static int hw_init(struct msm_gpu *gpu) /* Setting the primFifo thresholds default values, * and vccCacheSkipDis=1 bit (0x200) for A640 and newer */ - if (adreno_is_a650(adreno_gpu) || adreno_is_a660(adreno_gpu) || adreno_is_a690(adreno_gpu)) + if (adreno_is_a690(adreno_gpu)) + gpu_write(gpu, REG_A6XX_PC_DBG_ECO_CNTL, 0x00800200); + else if (adreno_is_a650(adreno_gpu) || adreno_is_a660(adreno_gpu)) gpu_write(gpu, REG_A6XX_PC_DBG_ECO_CNTL, 0x00300200); else if (adreno_is_a640_family(adreno_gpu) || adreno_is_7c3(adreno_gpu)) gpu_write(gpu, REG_A6XX_PC_DBG_ECO_CNTL, 0x00200200); @@ -1775,6 +1782,8 @@ static int hw_init(struct msm_gpu *gpu) if (adreno_is_a730(adreno_gpu) || adreno_is_a740_family(adreno_gpu)) gpu_write(gpu, REG_A6XX_RBBM_INTERFACE_HANG_INT_CNTL, (1 << 30) | 0xcfffff); + else if (adreno_is_a690(adreno_gpu)) + gpu_write(gpu, REG_A6XX_RBBM_INTERFACE_HANG_INT_CNTL, (1 << 30) | 0x4fffff); else if (adreno_is_a619(adreno_gpu)) gpu_write(gpu, REG_A6XX_RBBM_INTERFACE_HANG_INT_CNTL, (1 << 30) | 0x3fffff); else if (adreno_is_a610(adreno_gpu)) @@ -1782,7 +1791,7 @@ static int hw_init(struct msm_gpu *gpu) else gpu_write(gpu, REG_A6XX_RBBM_INTERFACE_HANG_INT_CNTL, (1 << 30) | 0x1fffff); - gpu_write(gpu, REG_A6XX_UCHE_CLIENT_PF, 1); + gpu_write(gpu, REG_A6XX_UCHE_CLIENT_PF, BIT(7) | 0x1); /* Set weights for bicubic filtering */ if (adreno_is_a650_family(adreno_gpu)) { @@ -1808,12 +1817,17 @@ static int hw_init(struct msm_gpu *gpu) a6xx_set_cp_protect(gpu); if (adreno_is_a660_family(adreno_gpu)) { - gpu_write(gpu, REG_A6XX_CP_CHICKEN_DBG, 0x1); + if (adreno_is_a690(adreno_gpu)) + gpu_write(gpu, REG_A6XX_CP_CHICKEN_DBG, 0x00028801); + else + gpu_write(gpu, REG_A6XX_CP_CHICKEN_DBG, 0x1); gpu_write(gpu, REG_A6XX_RBBM_GBIF_CLIENT_QOS_CNTL, 0x0); } + if (adreno_is_a690(adreno_gpu)) + gpu_write(gpu, REG_A6XX_UCHE_CMDQ_CONFIG, 0x90); /* Set dualQ + disable afull for A660 GPU */ - if (adreno_is_a660(adreno_gpu)) + else if (adreno_is_a660(adreno_gpu)) gpu_write(gpu, REG_A6XX_UCHE_CMDQ_CONFIG, 0x66906); else if (adreno_is_a7xx(adreno_gpu)) gpu_write(gpu, REG_A6XX_UCHE_CMDQ_CONFIG, @@ -2908,5 +2922,7 @@ struct msm_gpu *a6xx_gpu_init(struct drm_device *dev) msm_mmu_set_fault_handler(gpu->aspace->mmu, gpu, a6xx_fault_handler); + a6xx_calc_ubwc_config(adreno_gpu); + return gpu; } diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c index 41b13dec9befcc..2ce7d7b1690dc8 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_device.c +++ b/drivers/gpu/drm/msm/adreno/adreno_device.c @@ -464,7 +464,7 @@ static const struct adreno_info gpulist[] = { { 190, 1 }, ), }, { - .chip_ids = ADRENO_CHIP_IDS(0x06080000), + .chip_ids = ADRENO_CHIP_IDS(0x06080001), .family = ADRENO_6XX_GEN2, .revn = 680, .fw = { @@ -841,7 +841,8 @@ static void suspend_scheduler(struct msm_gpu *gpu) */ for (i = 0; i < gpu->nr_rings; i++) { struct drm_gpu_scheduler *sched = &gpu->rb[i]->sched; - kthread_park(sched->thread); + + drm_sched_wqueue_stop(sched); } } @@ -851,7 +852,8 @@ static void resume_scheduler(struct msm_gpu *gpu) for (i = 0; i < gpu->nr_rings; i++) { struct drm_gpu_scheduler *sched = &gpu->rb[i]->sched; - kthread_unpark(sched->thread); + + drm_sched_wqueue_start(sched); } } diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 3fe9fd240cc73c..074fb498706f26 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -373,6 +373,9 @@ int adreno_get_param(struct msm_gpu *gpu, struct msm_file_private *ctx, return -EINVAL; *value = ctx->aspace->va_size; return 0; + case MSM_PARAM_HIGHEST_BANK_BIT: + *value = adreno_gpu->ubwc_config.highest_bank_bit; + return 0; default: DBG("%s: invalid param: %u", gpu->name, param); return -EINVAL; diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index 80b3f6312116ee..bc14df96feb013 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -165,6 +165,15 @@ struct adreno_gpu { /* firmware: */ const struct firmware *fw[ADRENO_FW_MAX]; + struct { + u32 rgb565_predicator; + u32 uavflagprd_inv; + u32 min_acc_len; + u32 ubwc_mode; + u32 highest_bank_bit; + u32 amsbc; + } ubwc_config; + /* * Register offsets are different between some GPUs. * GPU specific offsets will be exported by GPU specific diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_10_0_sm8650.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_10_0_sm8650.h new file mode 100644 index 00000000000000..eb5dfff2ec4f48 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_10_0_sm8650.h @@ -0,0 +1,457 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022. Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2015-2018, 2020 The Linux Foundation. All rights reserved. + */ + +#ifndef _DPU_10_0_SM8650_H +#define _DPU_10_0_SM8650_H + +static const struct dpu_caps sm8650_dpu_caps = { + .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, + .max_mixer_blendstages = 0xb, + .has_src_split = true, + .has_dim_layer = true, + .has_idle_pc = true, + .has_3d_merge = true, + .max_linewidth = 8192, + .pixel_ram_size = DEFAULT_PIXEL_RAM_SIZE, +}; + +static const struct dpu_mdp_cfg sm8650_mdp = { + .name = "top_0", + .base = 0, .len = 0x494, + .features = BIT(DPU_MDP_PERIPH_0_REMOVED), + .clk_ctrls = { + [DPU_CLK_CTRL_REG_DMA] = { .reg_off = 0x2bc, .bit_off = 20 }, + }, +}; + +/* FIXME: get rid of DPU_CTL_SPLIT_DISPLAY in favour of proper ACTIVE_CTL support */ +static const struct dpu_ctl_cfg sm8650_ctl[] = { + { + .name = "ctl_0", .id = CTL_0, + .base = 0x15000, .len = 0x1000, + .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 = 0x1000, + .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 = 0x1000, + .features = CTL_SM8550_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 11), + }, { + .name = "ctl_3", .id = CTL_3, + .base = 0x18000, .len = 0x1000, + .features = CTL_SM8550_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 12), + }, { + .name = "ctl_4", .id = CTL_4, + .base = 0x19000, .len = 0x1000, + .features = CTL_SM8550_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 13), + }, { + .name = "ctl_5", .id = CTL_5, + .base = 0x1a000, .len = 0x1000, + .features = CTL_SM8550_MASK, + .intr_start = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 23), + }, +}; + +static const struct dpu_sspp_cfg sm8650_sspp[] = { + { + .name = "sspp_0", .id = SSPP_VIG0, + .base = 0x4000, .len = 0x344, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_3, + .xin_id = 0, + .type = SSPP_TYPE_VIG, + }, { + .name = "sspp_1", .id = SSPP_VIG1, + .base = 0x6000, .len = 0x344, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_3, + .xin_id = 4, + .type = SSPP_TYPE_VIG, + }, { + .name = "sspp_2", .id = SSPP_VIG2, + .base = 0x8000, .len = 0x344, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_3, + .xin_id = 8, + .type = SSPP_TYPE_VIG, + }, { + .name = "sspp_3", .id = SSPP_VIG3, + .base = 0xa000, .len = 0x344, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_3, + .xin_id = 12, + .type = SSPP_TYPE_VIG, + }, { + .name = "sspp_8", .id = SSPP_DMA0, + .base = 0x24000, .len = 0x344, + .features = DMA_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 1, + .type = SSPP_TYPE_DMA, + }, { + .name = "sspp_9", .id = SSPP_DMA1, + .base = 0x26000, .len = 0x344, + .features = DMA_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 5, + .type = SSPP_TYPE_DMA, + }, { + .name = "sspp_10", .id = SSPP_DMA2, + .base = 0x28000, .len = 0x344, + .features = DMA_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 9, + .type = SSPP_TYPE_DMA, + }, { + .name = "sspp_11", .id = SSPP_DMA3, + .base = 0x2a000, .len = 0x344, + .features = DMA_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 13, + .type = SSPP_TYPE_DMA, + }, { + .name = "sspp_12", .id = SSPP_DMA4, + .base = 0x2c000, .len = 0x344, + .features = DMA_CURSOR_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 14, + .type = SSPP_TYPE_DMA, + }, { + .name = "sspp_13", .id = SSPP_DMA5, + .base = 0x2e000, .len = 0x344, + .features = DMA_CURSOR_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 15, + .type = SSPP_TYPE_DMA, + }, +}; + +static const struct dpu_lm_cfg sm8650_lm[] = { + { + .name = "lm_0", .id = LM_0, + .base = 0x44000, .len = 0x400, + .features = MIXER_SDM845_MASK, + .sblk = &sdm845_lm_sblk, + .lm_pair = LM_1, + .pingpong = PINGPONG_0, + .dspp = DSPP_0, + }, { + .name = "lm_1", .id = LM_1, + .base = 0x45000, .len = 0x400, + .features = MIXER_SDM845_MASK, + .sblk = &sdm845_lm_sblk, + .lm_pair = LM_0, + .pingpong = PINGPONG_1, + .dspp = DSPP_1, + }, { + .name = "lm_2", .id = LM_2, + .base = 0x46000, .len = 0x400, + .features = MIXER_SDM845_MASK, + .sblk = &sdm845_lm_sblk, + .lm_pair = LM_3, + .pingpong = PINGPONG_2, + }, { + .name = "lm_3", .id = LM_3, + .base = 0x47000, .len = 0x400, + .features = MIXER_SDM845_MASK, + .sblk = &sdm845_lm_sblk, + .lm_pair = LM_2, + .pingpong = PINGPONG_3, + }, { + .name = "lm_4", .id = LM_4, + .base = 0x48000, .len = 0x400, + .features = MIXER_SDM845_MASK, + .sblk = &sdm845_lm_sblk, + .lm_pair = LM_5, + .pingpong = PINGPONG_4, + }, { + .name = "lm_5", .id = LM_5, + .base = 0x49000, .len = 0x400, + .features = MIXER_SDM845_MASK, + .sblk = &sdm845_lm_sblk, + .lm_pair = LM_4, + .pingpong = PINGPONG_5, + }, +}; + +static const struct dpu_dspp_cfg sm8650_dspp[] = { + { + .name = "dspp_0", .id = DSPP_0, + .base = 0x54000, .len = 0x1800, + .features = DSPP_SC7180_MASK, + .sblk = &sdm845_dspp_sblk, + }, { + .name = "dspp_1", .id = DSPP_1, + .base = 0x56000, .len = 0x1800, + .features = DSPP_SC7180_MASK, + .sblk = &sdm845_dspp_sblk, + }, { + .name = "dspp_2", .id = DSPP_2, + .base = 0x58000, .len = 0x1800, + .features = DSPP_SC7180_MASK, + .sblk = &sdm845_dspp_sblk, + }, { + .name = "dspp_3", .id = DSPP_3, + .base = 0x5a000, .len = 0x1800, + .features = DSPP_SC7180_MASK, + .sblk = &sdm845_dspp_sblk, + }, +}; + +static const struct dpu_pingpong_cfg sm8650_pp[] = { + { + .name = "pingpong_0", .id = PINGPONG_0, + .base = 0x69000, .len = 0, + .features = BIT(DPU_PINGPONG_DITHER), + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_0, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 8), + }, { + .name = "pingpong_1", .id = PINGPONG_1, + .base = 0x6a000, .len = 0, + .features = BIT(DPU_PINGPONG_DITHER), + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_0, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 9), + }, { + .name = "pingpong_2", .id = PINGPONG_2, + .base = 0x6b000, .len = 0, + .features = BIT(DPU_PINGPONG_DITHER), + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_1, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 10), + }, { + .name = "pingpong_3", .id = PINGPONG_3, + .base = 0x6c000, .len = 0, + .features = BIT(DPU_PINGPONG_DITHER), + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_1, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 11), + }, { + .name = "pingpong_4", .id = PINGPONG_4, + .base = 0x6d000, .len = 0, + .features = BIT(DPU_PINGPONG_DITHER), + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_2, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 30), + }, { + .name = "pingpong_5", .id = PINGPONG_5, + .base = 0x6e000, .len = 0, + .features = BIT(DPU_PINGPONG_DITHER), + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_2, + .intr_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR2, 31), + }, { + .name = "pingpong_6", .id = PINGPONG_6, + .base = 0x66000, .len = 0, + .features = BIT(DPU_PINGPONG_DITHER), + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_3, + }, { + .name = "pingpong_7", .id = PINGPONG_7, + .base = 0x66400, .len = 0, + .features = BIT(DPU_PINGPONG_DITHER), + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_3, + }, { + .name = "pingpong_8", .id = PINGPONG_8, + .base = 0x7e000, .len = 0, + .features = BIT(DPU_PINGPONG_DITHER), + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_4, + }, { + .name = "pingpong_9", .id = PINGPONG_9, + .base = 0x7e400, .len = 0, + .features = BIT(DPU_PINGPONG_DITHER), + .sblk = &sc7280_pp_sblk, + .merge_3d = MERGE_3D_4, + }, +}; + +static const struct dpu_merge_3d_cfg sm8650_merge_3d[] = { + { + .name = "merge_3d_0", .id = MERGE_3D_0, + .base = 0x4e000, .len = 0x8, + }, { + .name = "merge_3d_1", .id = MERGE_3D_1, + .base = 0x4f000, .len = 0x8, + }, { + .name = "merge_3d_2", .id = MERGE_3D_2, + .base = 0x50000, .len = 0x8, + }, { + .name = "merge_3d_3", .id = MERGE_3D_3, + .base = 0x66700, .len = 0x8, + }, { + .name = "merge_3d_4", .id = MERGE_3D_4, + .base = 0x7e700, .len = 0x8, + }, +}; + +/* + * NOTE: Each display compression engine (DCE) contains dual hard + * slice DSC encoders so both share same base address but with + * its own different sub block address. + */ +static const struct dpu_dsc_cfg sm8650_dsc[] = { + { + .name = "dce_0_0", .id = DSC_0, + .base = 0x80000, .len = 0x6, + .features = BIT(DPU_DSC_HW_REV_1_2) | BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &dsc_sblk_0, + }, { + .name = "dce_0_1", .id = DSC_1, + .base = 0x80000, .len = 0x6, + .features = BIT(DPU_DSC_HW_REV_1_2) | BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &dsc_sblk_1, + }, { + .name = "dce_1_0", .id = DSC_2, + .base = 0x81000, .len = 0x6, + .features = BIT(DPU_DSC_HW_REV_1_2) | BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &dsc_sblk_0, + }, { + .name = "dce_1_1", .id = DSC_3, + .base = 0x81000, .len = 0x6, + .features = BIT(DPU_DSC_HW_REV_1_2) | BIT(DPU_DSC_NATIVE_42x_EN), + .sblk = &dsc_sblk_1, + }, { + .name = "dce_2_0", .id = DSC_4, + .base = 0x82000, .len = 0x6, + .features = BIT(DPU_DSC_HW_REV_1_2), + .sblk = &dsc_sblk_0, + }, { + .name = "dce_2_1", .id = DSC_5, + .base = 0x82000, .len = 0x6, + .features = BIT(DPU_DSC_HW_REV_1_2), + .sblk = &dsc_sblk_1, + }, +}; + +static const struct dpu_wb_cfg sm8650_wb[] = { + { + .name = "wb_2", .id = WB_2, + .base = 0x65000, .len = 0x2c8, + .features = WB_SM8250_MASK, + .format_list = wb2_formats_rgb, + .num_formats = ARRAY_SIZE(wb2_formats_rgb), + .xin_id = 6, + .vbif_idx = VBIF_RT, + .maxlinewidth = 4096, + .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 4), + }, +}; + +static const struct dpu_intf_cfg sm8650_intf[] = { + { + .name = "intf_0", .id = INTF_0, + .base = 0x34000, .len = 0x280, + .features = INTF_SC7280_MASK, + .type = INTF_DP, + .controller_id = MSM_DP_CONTROLLER_0, + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 24), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 25), + }, { + .name = "intf_1", .id = INTF_1, + .base = 0x35000, .len = 0x300, + .features = INTF_SC7280_MASK, + .type = INTF_DSI, + .controller_id = MSM_DSI_CONTROLLER_0, + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 26), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 27), + .intr_tear_rd_ptr = DPU_IRQ_IDX(MDP_INTF1_TEAR_INTR, 2), + }, { + .name = "intf_2", .id = INTF_2, + .base = 0x36000, .len = 0x300, + .features = INTF_SC7280_MASK, + .type = INTF_DSI, + .controller_id = MSM_DSI_CONTROLLER_1, + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 28), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 29), + .intr_tear_rd_ptr = DPU_IRQ_IDX(MDP_INTF2_TEAR_INTR, 2), + }, { + .name = "intf_3", .id = INTF_3, + .base = 0x37000, .len = 0x280, + .features = INTF_SC7280_MASK, + .type = INTF_DP, + .controller_id = MSM_DP_CONTROLLER_1, + .prog_fetch_lines_worst_case = 24, + .intr_underrun = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 30), + .intr_vsync = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 31), + }, +}; + +static const struct dpu_perf_cfg sm8650_perf_data = { + .max_bw_low = 17000000, + .max_bw_high = 27000000, + .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_mdss_version sm8650_mdss_ver = { + .core_major_ver = 10, + .core_minor_ver = 0, +}; + +const struct dpu_mdss_cfg dpu_sm8650_cfg = { + .mdss_ver = &sm8650_mdss_ver, + .caps = &sm8650_dpu_caps, + .mdp = &sm8650_mdp, + .ctl_count = ARRAY_SIZE(sm8650_ctl), + .ctl = sm8650_ctl, + .sspp_count = ARRAY_SIZE(sm8650_sspp), + .sspp = sm8650_sspp, + .mixer_count = ARRAY_SIZE(sm8650_lm), + .mixer = sm8650_lm, + .dspp_count = ARRAY_SIZE(sm8650_dspp), + .dspp = sm8650_dspp, + .pingpong_count = ARRAY_SIZE(sm8650_pp), + .pingpong = sm8650_pp, + .dsc_count = ARRAY_SIZE(sm8650_dsc), + .dsc = sm8650_dsc, + .merge_3d_count = ARRAY_SIZE(sm8650_merge_3d), + .merge_3d = sm8650_merge_3d, + .wb_count = ARRAY_SIZE(sm8650_wb), + .wb = sm8650_wb, + .intf_count = ARRAY_SIZE(sm8650_intf), + .intf = sm8650_intf, + .vbif_count = ARRAY_SIZE(sm8650_vbif), + .vbif = sm8650_vbif, + .perf = &sm8650_perf_data, +}; + +#endif diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h index aa1867943c9fdc..1d3e9666c7411e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_3_0_msm8998.h @@ -10,7 +10,6 @@ static const struct dpu_caps msm8998_dpu_caps = { .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, .max_mixer_blendstages = 0x7, - .qseed_type = DPU_SSPP_SCALER_QSEED3, .has_src_split = true, .has_dim_layer = true, .has_idle_pc = true, @@ -70,7 +69,7 @@ static const struct dpu_sspp_cfg msm8998_sspp[] = { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1ac, .features = VIG_MSM8998_MASK, - .sblk = &msm8998_vig_sblk_0, + .sblk = &dpu_vig_sblk_qseed3_1_2, .xin_id = 0, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG0, @@ -78,7 +77,7 @@ static const struct dpu_sspp_cfg msm8998_sspp[] = { .name = "sspp_1", .id = SSPP_VIG1, .base = 0x6000, .len = 0x1ac, .features = VIG_MSM8998_MASK, - .sblk = &msm8998_vig_sblk_1, + .sblk = &dpu_vig_sblk_qseed3_1_2, .xin_id = 4, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG1, @@ -86,7 +85,7 @@ static const struct dpu_sspp_cfg msm8998_sspp[] = { .name = "sspp_2", .id = SSPP_VIG2, .base = 0x8000, .len = 0x1ac, .features = VIG_MSM8998_MASK, - .sblk = &msm8998_vig_sblk_2, + .sblk = &dpu_vig_sblk_qseed3_1_2, .xin_id = 8, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG2, @@ -94,7 +93,7 @@ static const struct dpu_sspp_cfg msm8998_sspp[] = { .name = "sspp_3", .id = SSPP_VIG3, .base = 0xa000, .len = 0x1ac, .features = VIG_MSM8998_MASK, - .sblk = &msm8998_vig_sblk_3, + .sblk = &dpu_vig_sblk_qseed3_1_2, .xin_id = 12, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG3, @@ -102,7 +101,7 @@ static const struct dpu_sspp_cfg msm8998_sspp[] = { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x1ac, .features = DMA_MSM8998_MASK, - .sblk = &sdm845_dma_sblk_0, + .sblk = &dpu_dma_sblk, .xin_id = 1, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA0, @@ -110,7 +109,7 @@ static const struct dpu_sspp_cfg msm8998_sspp[] = { .name = "sspp_9", .id = SSPP_DMA1, .base = 0x26000, .len = 0x1ac, .features = DMA_MSM8998_MASK, - .sblk = &sdm845_dma_sblk_1, + .sblk = &dpu_dma_sblk, .xin_id = 5, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA1, @@ -118,7 +117,7 @@ static const struct dpu_sspp_cfg msm8998_sspp[] = { .name = "sspp_10", .id = SSPP_DMA2, .base = 0x28000, .len = 0x1ac, .features = DMA_CURSOR_MSM8998_MASK, - .sblk = &sdm845_dma_sblk_2, + .sblk = &dpu_dma_sblk, .xin_id = 9, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA2, @@ -126,7 +125,7 @@ static const struct dpu_sspp_cfg msm8998_sspp[] = { .name = "sspp_11", .id = SSPP_DMA3, .base = 0x2a000, .len = 0x1ac, .features = DMA_CURSOR_MSM8998_MASK, - .sblk = &sdm845_dma_sblk_3, + .sblk = &dpu_dma_sblk, .xin_id = 13, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA3, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_0_sdm845.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_0_sdm845.h index 38ac0c1a134bff..7a23389a573272 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_0_sdm845.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_0_sdm845.h @@ -10,7 +10,6 @@ static const struct dpu_caps sdm845_dpu_caps = { .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, .max_mixer_blendstages = 0xb, - .qseed_type = DPU_SSPP_SCALER_QSEED3, .has_src_split = true, .has_dim_layer = true, .has_idle_pc = true, @@ -68,7 +67,7 @@ static const struct dpu_sspp_cfg sdm845_sspp[] = { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1c8, .features = VIG_SDM845_MASK_SDMA, - .sblk = &sdm845_vig_sblk_0, + .sblk = &dpu_vig_sblk_qseed3_1_3, .xin_id = 0, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG0, @@ -76,7 +75,7 @@ static const struct dpu_sspp_cfg sdm845_sspp[] = { .name = "sspp_1", .id = SSPP_VIG1, .base = 0x6000, .len = 0x1c8, .features = VIG_SDM845_MASK_SDMA, - .sblk = &sdm845_vig_sblk_1, + .sblk = &dpu_vig_sblk_qseed3_1_3, .xin_id = 4, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG1, @@ -84,7 +83,7 @@ static const struct dpu_sspp_cfg sdm845_sspp[] = { .name = "sspp_2", .id = SSPP_VIG2, .base = 0x8000, .len = 0x1c8, .features = VIG_SDM845_MASK_SDMA, - .sblk = &sdm845_vig_sblk_2, + .sblk = &dpu_vig_sblk_qseed3_1_3, .xin_id = 8, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG2, @@ -92,7 +91,7 @@ static const struct dpu_sspp_cfg sdm845_sspp[] = { .name = "sspp_3", .id = SSPP_VIG3, .base = 0xa000, .len = 0x1c8, .features = VIG_SDM845_MASK_SDMA, - .sblk = &sdm845_vig_sblk_3, + .sblk = &dpu_vig_sblk_qseed3_1_3, .xin_id = 12, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG3, @@ -100,7 +99,7 @@ static const struct dpu_sspp_cfg sdm845_sspp[] = { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x1c8, .features = DMA_SDM845_MASK_SDMA, - .sblk = &sdm845_dma_sblk_0, + .sblk = &dpu_dma_sblk, .xin_id = 1, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA0, @@ -108,7 +107,7 @@ static const struct dpu_sspp_cfg sdm845_sspp[] = { .name = "sspp_9", .id = SSPP_DMA1, .base = 0x26000, .len = 0x1c8, .features = DMA_SDM845_MASK_SDMA, - .sblk = &sdm845_dma_sblk_1, + .sblk = &dpu_dma_sblk, .xin_id = 5, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA1, @@ -116,7 +115,7 @@ static const struct dpu_sspp_cfg sdm845_sspp[] = { .name = "sspp_10", .id = SSPP_DMA2, .base = 0x28000, .len = 0x1c8, .features = DMA_CURSOR_SDM845_MASK_SDMA, - .sblk = &sdm845_dma_sblk_2, + .sblk = &dpu_dma_sblk, .xin_id = 9, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA2, @@ -124,7 +123,7 @@ static const struct dpu_sspp_cfg sdm845_sspp[] = { .name = "sspp_11", .id = SSPP_DMA3, .base = 0x2a000, .len = 0x1c8, .features = DMA_CURSOR_SDM845_MASK_SDMA, - .sblk = &sdm845_dma_sblk_3, + .sblk = &dpu_dma_sblk, .xin_id = 13, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA3, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_1_sdm670.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_1_sdm670.h new file mode 100644 index 00000000000000..cbbdaebe357ec4 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_4_1_sdm670.h @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2022. Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2023, Richard Acayan. All rights reserved. + */ + +#ifndef _DPU_4_1_SDM670_H +#define _DPU_4_1_SDM670_H + +static const struct dpu_mdp_cfg sdm670_mdp = { + .name = "top_0", + .base = 0x0, .len = 0x45c, + .features = BIT(DPU_MDP_AUDIO_SELECT), + .clk_ctrls = { + [DPU_CLK_CTRL_VIG0] = { .reg_off = 0x2ac, .bit_off = 0 }, + [DPU_CLK_CTRL_VIG1] = { .reg_off = 0x2b4, .bit_off = 0 }, + [DPU_CLK_CTRL_DMA0] = { .reg_off = 0x2ac, .bit_off = 8 }, + [DPU_CLK_CTRL_DMA1] = { .reg_off = 0x2b4, .bit_off = 8 }, + [DPU_CLK_CTRL_DMA2] = { .reg_off = 0x2bc, .bit_off = 8 }, + }, +}; + +static const struct dpu_sspp_cfg sdm670_sspp[] = { + { + .name = "sspp_0", .id = SSPP_VIG0, + .base = 0x4000, .len = 0x1c8, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_1_3, + .xin_id = 0, + .type = SSPP_TYPE_VIG, + .clk_ctrl = DPU_CLK_CTRL_VIG0, + }, { + .name = "sspp_1", .id = SSPP_VIG1, + .base = 0x6000, .len = 0x1c8, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_1_3, + .xin_id = 4, + .type = SSPP_TYPE_VIG, + .clk_ctrl = DPU_CLK_CTRL_VIG0, + }, { + .name = "sspp_8", .id = SSPP_DMA0, + .base = 0x24000, .len = 0x1c8, + .features = DMA_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 1, + .type = SSPP_TYPE_DMA, + .clk_ctrl = DPU_CLK_CTRL_DMA0, + }, { + .name = "sspp_9", .id = SSPP_DMA1, + .base = 0x26000, .len = 0x1c8, + .features = DMA_CURSOR_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 5, + .type = SSPP_TYPE_DMA, + .clk_ctrl = DPU_CLK_CTRL_DMA1, + }, { + .name = "sspp_10", .id = SSPP_DMA2, + .base = 0x28000, .len = 0x1c8, + .features = DMA_CURSOR_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, + .xin_id = 9, + .type = SSPP_TYPE_DMA, + .clk_ctrl = DPU_CLK_CTRL_DMA2, + }, +}; + +static const struct dpu_dsc_cfg sdm670_dsc[] = { + { + .name = "dsc_0", .id = DSC_0, + .base = 0x80000, .len = 0x140, + }, { + .name = "dsc_1", .id = DSC_1, + .base = 0x80400, .len = 0x140, + }, +}; + +static const struct dpu_mdss_version sdm670_mdss_ver = { + .core_major_ver = 4, + .core_minor_ver = 1, +}; + +const struct dpu_mdss_cfg dpu_sdm670_cfg = { + .mdss_ver = &sdm670_mdss_ver, + .caps = &sdm845_dpu_caps, + .mdp = &sdm670_mdp, + .ctl_count = ARRAY_SIZE(sdm845_ctl), + .ctl = sdm845_ctl, + .sspp_count = ARRAY_SIZE(sdm670_sspp), + .sspp = sdm670_sspp, + .mixer_count = ARRAY_SIZE(sdm845_lm), + .mixer = sdm845_lm, + .pingpong_count = ARRAY_SIZE(sdm845_pp), + .pingpong = sdm845_pp, + .dsc_count = ARRAY_SIZE(sdm670_dsc), + .dsc = sdm670_dsc, + .intf_count = ARRAY_SIZE(sdm845_intf), + .intf = sdm845_intf, + .vbif_count = ARRAY_SIZE(sdm845_vbif), + .vbif = sdm845_vbif, + .perf = &sdm845_perf_data, +}; + +#endif diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_0_sm8150.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_0_sm8150.h index 9392ad2b4d3fef..145f3d5953a30d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_0_sm8150.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_0_sm8150.h @@ -10,7 +10,6 @@ static const struct dpu_caps sm8150_dpu_caps = { .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, .max_mixer_blendstages = 0xb, - .qseed_type = DPU_SSPP_SCALER_QSEED3, .has_src_split = true, .has_dim_layer = true, .has_idle_pc = true, @@ -77,7 +76,7 @@ static const struct dpu_sspp_cfg sm8150_sspp[] = { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1f0, .features = VIG_SDM845_MASK, - .sblk = &sdm845_vig_sblk_0, + .sblk = &dpu_vig_sblk_qseed3_1_4, .xin_id = 0, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG0, @@ -85,7 +84,7 @@ static const struct dpu_sspp_cfg sm8150_sspp[] = { .name = "sspp_1", .id = SSPP_VIG1, .base = 0x6000, .len = 0x1f0, .features = VIG_SDM845_MASK, - .sblk = &sdm845_vig_sblk_1, + .sblk = &dpu_vig_sblk_qseed3_1_4, .xin_id = 4, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG1, @@ -93,7 +92,7 @@ static const struct dpu_sspp_cfg sm8150_sspp[] = { .name = "sspp_2", .id = SSPP_VIG2, .base = 0x8000, .len = 0x1f0, .features = VIG_SDM845_MASK, - .sblk = &sdm845_vig_sblk_2, + .sblk = &dpu_vig_sblk_qseed3_1_4, .xin_id = 8, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG2, @@ -101,7 +100,7 @@ static const struct dpu_sspp_cfg sm8150_sspp[] = { .name = "sspp_3", .id = SSPP_VIG3, .base = 0xa000, .len = 0x1f0, .features = VIG_SDM845_MASK, - .sblk = &sdm845_vig_sblk_3, + .sblk = &dpu_vig_sblk_qseed3_1_4, .xin_id = 12, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG3, @@ -109,7 +108,7 @@ static const struct dpu_sspp_cfg sm8150_sspp[] = { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x1f0, .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_0, + .sblk = &dpu_dma_sblk, .xin_id = 1, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA0, @@ -117,7 +116,7 @@ static const struct dpu_sspp_cfg sm8150_sspp[] = { .name = "sspp_9", .id = SSPP_DMA1, .base = 0x26000, .len = 0x1f0, .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_1, + .sblk = &dpu_dma_sblk, .xin_id = 5, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA1, @@ -125,7 +124,7 @@ static const struct dpu_sspp_cfg sm8150_sspp[] = { .name = "sspp_10", .id = SSPP_DMA2, .base = 0x28000, .len = 0x1f0, .features = DMA_CURSOR_SDM845_MASK, - .sblk = &sdm845_dma_sblk_2, + .sblk = &dpu_dma_sblk, .xin_id = 9, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA2, @@ -133,7 +132,7 @@ static const struct dpu_sspp_cfg sm8150_sspp[] = { .name = "sspp_11", .id = SSPP_DMA3, .base = 0x2a000, .len = 0x1f0, .features = DMA_CURSOR_SDM845_MASK, - .sblk = &sdm845_dma_sblk_3, + .sblk = &dpu_dma_sblk, .xin_id = 13, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA3, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h index e07f4c8c25b9f9..9e3bec8bc12188 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_1_sc8180x.h @@ -10,7 +10,6 @@ static const struct dpu_caps sc8180x_dpu_caps = { .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, .max_mixer_blendstages = 0xb, - .qseed_type = DPU_SSPP_SCALER_QSEED3, .has_src_split = true, .has_dim_layer = true, .has_idle_pc = true, @@ -76,7 +75,7 @@ static const struct dpu_sspp_cfg sc8180x_sspp[] = { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1f0, .features = VIG_SDM845_MASK, - .sblk = &sdm845_vig_sblk_0, + .sblk = &dpu_vig_sblk_qseed3_1_4, .xin_id = 0, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG0, @@ -84,7 +83,7 @@ static const struct dpu_sspp_cfg sc8180x_sspp[] = { .name = "sspp_1", .id = SSPP_VIG1, .base = 0x6000, .len = 0x1f0, .features = VIG_SDM845_MASK, - .sblk = &sdm845_vig_sblk_1, + .sblk = &dpu_vig_sblk_qseed3_1_4, .xin_id = 4, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG1, @@ -92,7 +91,7 @@ static const struct dpu_sspp_cfg sc8180x_sspp[] = { .name = "sspp_2", .id = SSPP_VIG2, .base = 0x8000, .len = 0x1f0, .features = VIG_SDM845_MASK, - .sblk = &sdm845_vig_sblk_2, + .sblk = &dpu_vig_sblk_qseed3_1_4, .xin_id = 8, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG2, @@ -100,7 +99,7 @@ static const struct dpu_sspp_cfg sc8180x_sspp[] = { .name = "sspp_3", .id = SSPP_VIG3, .base = 0xa000, .len = 0x1f0, .features = VIG_SDM845_MASK, - .sblk = &sdm845_vig_sblk_3, + .sblk = &dpu_vig_sblk_qseed3_1_4, .xin_id = 12, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG3, @@ -108,7 +107,7 @@ static const struct dpu_sspp_cfg sc8180x_sspp[] = { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x1f0, .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_0, + .sblk = &dpu_dma_sblk, .xin_id = 1, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA0, @@ -116,7 +115,7 @@ static const struct dpu_sspp_cfg sc8180x_sspp[] = { .name = "sspp_9", .id = SSPP_DMA1, .base = 0x26000, .len = 0x1f0, .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_1, + .sblk = &dpu_dma_sblk, .xin_id = 5, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA1, @@ -124,7 +123,7 @@ static const struct dpu_sspp_cfg sc8180x_sspp[] = { .name = "sspp_10", .id = SSPP_DMA2, .base = 0x28000, .len = 0x1f0, .features = DMA_CURSOR_SDM845_MASK, - .sblk = &sdm845_dma_sblk_2, + .sblk = &dpu_dma_sblk, .xin_id = 9, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA2, @@ -132,7 +131,7 @@ static const struct dpu_sspp_cfg sc8180x_sspp[] = { .name = "sspp_11", .id = SSPP_DMA3, .base = 0x2a000, .len = 0x1f0, .features = DMA_CURSOR_SDM845_MASK, - .sblk = &sdm845_dma_sblk_3, + .sblk = &dpu_dma_sblk, .xin_id = 13, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA3, @@ -367,6 +366,7 @@ static const struct dpu_perf_cfg sc8180x_perf_data = { .min_llcc_ib = 800000, .min_dram_ib = 800000, .danger_lut_tbl = {0xf, 0xffff, 0x0}, + .safe_lut_tbl = {0xfff0, 0xf000, 0xffff}, .qos_lut_tbl = { {.nentry = ARRAY_SIZE(sc7180_qos_linear), .entries = sc7180_qos_linear diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_4_sm6125.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_4_sm6125.h index cec7af6667dc92..76b2ec0d2489b3 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_4_sm6125.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_5_4_sm6125.h @@ -68,8 +68,8 @@ static const struct dpu_sspp_cfg sm6125_sspp[] = { { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1f0, - .features = VIG_SM6125_MASK, - .sblk = &sm6125_vig_sblk_0, + .features = VIG_SDM845_MASK, + .sblk = &dpu_vig_sblk_qseed3_2_4, .xin_id = 0, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG0, @@ -77,7 +77,7 @@ static const struct dpu_sspp_cfg sm6125_sspp[] = { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x1f0, .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_0, + .sblk = &dpu_dma_sblk, .xin_id = 1, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA0, @@ -85,7 +85,7 @@ static const struct dpu_sspp_cfg sm6125_sspp[] = { .name = "sspp_9", .id = SSPP_DMA1, .base = 0x26000, .len = 0x1f0, .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_1, + .sblk = &dpu_dma_sblk, .xin_id = 5, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA1, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h index 94278a3e3483c6..a57d50b1f02807 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_0_sm8250.h @@ -10,7 +10,6 @@ static const struct dpu_caps sm8250_dpu_caps = { .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, .max_mixer_blendstages = 0xb, - .qseed_type = DPU_SSPP_SCALER_QSEED4, .has_src_split = true, .has_dim_layer = true, .has_idle_pc = true, @@ -32,7 +31,7 @@ static const struct dpu_mdp_cfg sm8250_mdp = { [DPU_CLK_CTRL_DMA2] = { .reg_off = 0x2bc, .bit_off = 8 }, [DPU_CLK_CTRL_DMA3] = { .reg_off = 0x2c4, .bit_off = 8 }, [DPU_CLK_CTRL_REG_DMA] = { .reg_off = 0x2bc, .bit_off = 20 }, - [DPU_CLK_CTRL_WB2] = { .reg_off = 0x3b8, .bit_off = 24 }, + [DPU_CLK_CTRL_WB2] = { .reg_off = 0x2bc, .bit_off = 16 }, }, }; @@ -75,32 +74,32 @@ static const struct dpu_sspp_cfg sm8250_sspp[] = { { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1f8, - .features = VIG_SC7180_MASK_SDMA, - .sblk = &sm8250_vig_sblk_0, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 0, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG0, }, { .name = "sspp_1", .id = SSPP_VIG1, .base = 0x6000, .len = 0x1f8, - .features = VIG_SC7180_MASK_SDMA, - .sblk = &sm8250_vig_sblk_1, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 4, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG1, }, { .name = "sspp_2", .id = SSPP_VIG2, .base = 0x8000, .len = 0x1f8, - .features = VIG_SC7180_MASK_SDMA, - .sblk = &sm8250_vig_sblk_2, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 8, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG2, }, { .name = "sspp_3", .id = SSPP_VIG3, .base = 0xa000, .len = 0x1f8, - .features = VIG_SC7180_MASK_SDMA, - .sblk = &sm8250_vig_sblk_3, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 12, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG3, @@ -108,7 +107,7 @@ static const struct dpu_sspp_cfg sm8250_sspp[] = { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x1f8, .features = DMA_SDM845_MASK_SDMA, - .sblk = &sdm845_dma_sblk_0, + .sblk = &dpu_dma_sblk, .xin_id = 1, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA0, @@ -116,7 +115,7 @@ static const struct dpu_sspp_cfg sm8250_sspp[] = { .name = "sspp_9", .id = SSPP_DMA1, .base = 0x26000, .len = 0x1f8, .features = DMA_SDM845_MASK_SDMA, - .sblk = &sdm845_dma_sblk_1, + .sblk = &dpu_dma_sblk, .xin_id = 5, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA1, @@ -124,7 +123,7 @@ static const struct dpu_sspp_cfg sm8250_sspp[] = { .name = "sspp_10", .id = SSPP_DMA2, .base = 0x28000, .len = 0x1f8, .features = DMA_CURSOR_SDM845_MASK_SDMA, - .sblk = &sdm845_dma_sblk_2, + .sblk = &dpu_dma_sblk, .xin_id = 9, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA2, @@ -132,7 +131,7 @@ static const struct dpu_sspp_cfg sm8250_sspp[] = { .name = "sspp_11", .id = SSPP_DMA3, .base = 0x2a000, .len = 0x1f8, .features = DMA_CURSOR_SDM845_MASK_SDMA, - .sblk = &sdm845_dma_sblk_3, + .sblk = &dpu_dma_sblk, .xin_id = 13, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA3, @@ -337,8 +336,8 @@ static const struct dpu_wb_cfg sm8250_wb[] = { .name = "wb_2", .id = WB_2, .base = 0x65000, .len = 0x2c8, .features = WB_SM8250_MASK, - .format_list = wb2_formats, - .num_formats = ARRAY_SIZE(wb2_formats), + .format_list = wb2_formats_rgb_yuv, + .num_formats = ARRAY_SIZE(wb2_formats_rgb_yuv), .clk_ctrl = DPU_CLK_CTRL_WB2, .xin_id = 6, .vbif_idx = VBIF_RT, @@ -385,6 +384,7 @@ const struct dpu_mdss_cfg dpu_sm8250_cfg = { .mdss_ver = &sm8250_mdss_ver, .caps = &sm8250_dpu_caps, .mdp = &sm8250_mdp, + .cdm = &sc7280_cdm, .ctl_count = ARRAY_SIZE(sm8250_ctl), .ctl = sm8250_ctl, .sspp_count = ARRAY_SIZE(sm8250_sspp), diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h index c0d88ddccb28c6..7382ebb6e5b2a0 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_2_sc7180.h @@ -10,7 +10,6 @@ static const struct dpu_caps sc7180_dpu_caps = { .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, .max_mixer_blendstages = 0x9, - .qseed_type = DPU_SSPP_SCALER_QSEED4, .has_dim_layer = true, .has_idle_pc = true, .max_linewidth = DEFAULT_DPU_OUTPUT_LINE_WIDTH, @@ -25,7 +24,7 @@ static const struct dpu_mdp_cfg sc7180_mdp = { [DPU_CLK_CTRL_DMA0] = { .reg_off = 0x2ac, .bit_off = 8 }, [DPU_CLK_CTRL_DMA1] = { .reg_off = 0x2b4, .bit_off = 8 }, [DPU_CLK_CTRL_DMA2] = { .reg_off = 0x2c4, .bit_off = 8 }, - [DPU_CLK_CTRL_WB2] = { .reg_off = 0x3b8, .bit_off = 24 }, + [DPU_CLK_CTRL_WB2] = { .reg_off = 0x2bc, .bit_off = 16 }, }, }; @@ -52,8 +51,8 @@ static const struct dpu_sspp_cfg sc7180_sspp[] = { { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1f8, - .features = VIG_SC7180_MASK, - .sblk = &sc7180_vig_sblk_0, + .features = VIG_SDM845_MASK, + .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 0, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG0, @@ -61,7 +60,7 @@ static const struct dpu_sspp_cfg sc7180_sspp[] = { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x1f8, .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_0, + .sblk = &dpu_dma_sblk, .xin_id = 1, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA0, @@ -69,7 +68,7 @@ static const struct dpu_sspp_cfg sc7180_sspp[] = { .name = "sspp_9", .id = SSPP_DMA1, .base = 0x26000, .len = 0x1f8, .features = DMA_CURSOR_SDM845_MASK, - .sblk = &sdm845_dma_sblk_1, + .sblk = &dpu_dma_sblk, .xin_id = 5, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA1, @@ -77,7 +76,7 @@ static const struct dpu_sspp_cfg sc7180_sspp[] = { .name = "sspp_10", .id = SSPP_DMA2, .base = 0x28000, .len = 0x1f8, .features = DMA_CURSOR_SDM845_MASK, - .sblk = &sdm845_dma_sblk_2, + .sblk = &dpu_dma_sblk, .xin_id = 9, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA2, @@ -158,8 +157,8 @@ static const struct dpu_wb_cfg sc7180_wb[] = { .name = "wb_2", .id = WB_2, .base = 0x65000, .len = 0x2c8, .features = WB_SM8250_MASK, - .format_list = wb2_formats, - .num_formats = ARRAY_SIZE(wb2_formats), + .format_list = wb2_formats_rgb, + .num_formats = ARRAY_SIZE(wb2_formats_rgb), .clk_ctrl = DPU_CLK_CTRL_WB2, .xin_id = 6, .vbif_idx = VBIF_RT, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_3_sm6115.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_3_sm6115.h index 57ce14c18defb7..43f64a005f5a89 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_3_sm6115.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_3_sm6115.h @@ -10,7 +10,6 @@ static const struct dpu_caps sm6115_dpu_caps = { .max_mixer_width = DEFAULT_DPU_LINE_WIDTH, .max_mixer_blendstages = 0x4, - .qseed_type = DPU_SSPP_SCALER_QSEED4, .has_dim_layer = true, .has_idle_pc = true, .max_linewidth = 2160, @@ -39,8 +38,8 @@ static const struct dpu_sspp_cfg sm6115_sspp[] = { { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1f8, - .features = VIG_SC7180_MASK, - .sblk = &sm6115_vig_sblk_0, + .features = VIG_SDM845_MASK, + .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 0, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG0, @@ -48,7 +47,7 @@ static const struct dpu_sspp_cfg sm6115_sspp[] = { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x1f8, .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_0, + .sblk = &dpu_dma_sblk, .xin_id = 1, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA0, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_4_sm6350.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_4_sm6350.h index 62db84bd15f24a..e17a30be752535 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_4_sm6350.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_4_sm6350.h @@ -11,7 +11,6 @@ static const struct dpu_caps sm6350_dpu_caps = { .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, .max_mixer_blendstages = 0x7, - .qseed_type = DPU_SSPP_SCALER_QSEED4, .has_src_split = true, .has_dim_layer = true, .has_idle_pc = true, @@ -59,8 +58,8 @@ static const struct dpu_sspp_cfg sm6350_sspp[] = { { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1f8, - .features = VIG_SC7180_MASK, - .sblk = &sc7180_vig_sblk_0, + .features = VIG_SDM845_MASK, + .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 0, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG0, @@ -68,7 +67,7 @@ static const struct dpu_sspp_cfg sm6350_sspp[] = { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x1f8, .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_0, + .sblk = &dpu_dma_sblk, .xin_id = 1, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA0, @@ -76,7 +75,7 @@ static const struct dpu_sspp_cfg sm6350_sspp[] = { .name = "sspp_9", .id = SSPP_DMA1, .base = 0x26000, .len = 0x1f8, .features = DMA_CURSOR_SDM845_MASK, - .sblk = &sdm845_dma_sblk_1, + .sblk = &dpu_dma_sblk, .xin_id = 5, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA1, @@ -84,7 +83,7 @@ static const struct dpu_sspp_cfg sm6350_sspp[] = { .name = "sspp_10", .id = SSPP_DMA2, .base = 0x28000, .len = 0x1f8, .features = DMA_CURSOR_SDM845_MASK, - .sblk = &sdm845_dma_sblk_2, + .sblk = &dpu_dma_sblk, .xin_id = 9, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA2, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_5_qcm2290.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_5_qcm2290.h index fb36fba5171cf5..3cbb2fe8aba24c 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_5_qcm2290.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_5_qcm2290.h @@ -39,7 +39,7 @@ static const struct dpu_sspp_cfg qcm2290_sspp[] = { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1f8, .features = VIG_QCM2290_MASK, - .sblk = &qcm2290_vig_sblk_0, + .sblk = &dpu_vig_sblk_noscale, .xin_id = 0, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG0, @@ -47,7 +47,7 @@ static const struct dpu_sspp_cfg qcm2290_sspp[] = { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x1f8, .features = DMA_SDM845_MASK, - .sblk = &qcm2290_dma_sblk_0, + .sblk = &dpu_dma_sblk, .xin_id = 1, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA0, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_9_sm6375.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_9_sm6375.h index 5a3aad364c7894..a06c8634d2d777 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_9_sm6375.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_6_9_sm6375.h @@ -11,7 +11,6 @@ static const struct dpu_caps sm6375_dpu_caps = { .max_mixer_width = DEFAULT_DPU_LINE_WIDTH, .max_mixer_blendstages = 0x4, - .qseed_type = DPU_SSPP_SCALER_QSEED4, .has_dim_layer = true, .has_idle_pc = true, .max_linewidth = 2160, @@ -40,8 +39,8 @@ static const struct dpu_sspp_cfg sm6375_sspp[] = { { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1f8, - .features = VIG_SC7180_MASK, - .sblk = &sm6115_vig_sblk_0, + .features = VIG_SDM845_MASK, + .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 0, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG0, @@ -49,7 +48,7 @@ static const struct dpu_sspp_cfg sm6375_sspp[] = { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x1f8, .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_0, + .sblk = &dpu_dma_sblk, .xin_id = 1, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA0, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h index 1709ba57f38402..aced16e350daa1 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_0_sm8350.h @@ -10,7 +10,6 @@ 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_QSEED4, .has_src_split = true, .has_dim_layer = true, .has_idle_pc = true, @@ -31,6 +30,7 @@ static const struct dpu_mdp_cfg sm8350_mdp = { [DPU_CLK_CTRL_DMA1] = { .reg_off = 0x2b4, .bit_off = 8 }, [DPU_CLK_CTRL_DMA2] = { .reg_off = 0x2bc, .bit_off = 8 }, [DPU_CLK_CTRL_DMA3] = { .reg_off = 0x2c4, .bit_off = 8 }, + [DPU_CLK_CTRL_WB2] = { .reg_off = 0x2bc, .bit_off = 16 }, [DPU_CLK_CTRL_REG_DMA] = { .reg_off = 0x2bc, .bit_off = 20 }, }, }; @@ -74,64 +74,64 @@ static const struct dpu_sspp_cfg sm8350_sspp[] = { { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1f8, - .features = VIG_SC7180_MASK, - .sblk = &sm8250_vig_sblk_0, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 0, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG0, }, { .name = "sspp_1", .id = SSPP_VIG1, .base = 0x6000, .len = 0x1f8, - .features = VIG_SC7180_MASK, - .sblk = &sm8250_vig_sblk_1, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 4, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG1, }, { .name = "sspp_2", .id = SSPP_VIG2, .base = 0x8000, .len = 0x1f8, - .features = VIG_SC7180_MASK, - .sblk = &sm8250_vig_sblk_2, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 8, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG2, }, { .name = "sspp_3", .id = SSPP_VIG3, .base = 0xa000, .len = 0x1f8, - .features = VIG_SC7180_MASK, - .sblk = &sm8250_vig_sblk_3, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 12, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG3, }, { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x1f8, - .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_0, + .features = DMA_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, .xin_id = 1, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA0, }, { .name = "sspp_9", .id = SSPP_DMA1, .base = 0x26000, .len = 0x1f8, - .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_1, + .features = DMA_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, .xin_id = 5, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA1, }, { .name = "sspp_10", .id = SSPP_DMA2, .base = 0x28000, .len = 0x1f8, - .features = DMA_CURSOR_SDM845_MASK, - .sblk = &sdm845_dma_sblk_2, + .features = DMA_CURSOR_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, .xin_id = 9, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA2, }, { .name = "sspp_11", .id = SSPP_DMA3, .base = 0x2a000, .len = 0x1f8, - .features = DMA_CURSOR_SDM845_MASK, - .sblk = &sdm845_dma_sblk_3, + .features = DMA_CURSOR_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, .xin_id = 13, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA3, @@ -298,6 +298,21 @@ static const struct dpu_dsc_cfg sm8350_dsc[] = { }, }; +static const struct dpu_wb_cfg sm8350_wb[] = { + { + .name = "wb_2", .id = WB_2, + .base = 0x65000, .len = 0x2c8, + .features = WB_SM8250_MASK, + .format_list = wb2_formats_rgb, + .num_formats = ARRAY_SIZE(wb2_formats_rgb), + .clk_ctrl = DPU_CLK_CTRL_WB2, + .xin_id = 6, + .vbif_idx = VBIF_RT, + .maxlinewidth = 4096, + .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 4), + }, +}; + static const struct dpu_intf_cfg sm8350_intf[] = { { .name = "intf_0", .id = INTF_0, @@ -393,6 +408,8 @@ const struct dpu_mdss_cfg dpu_sm8350_cfg = { .dsc = sm8350_dsc, .merge_3d_count = ARRAY_SIZE(sm8350_merge_3d), .merge_3d = sm8350_merge_3d, + .wb_count = ARRAY_SIZE(sm8350_wb), + .wb = sm8350_wb, .intf_count = ARRAY_SIZE(sm8350_intf), .intf = sm8350_intf, .vbif_count = ARRAY_SIZE(sdm845_vbif), diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h index 15942fa5a8e06f..2f153e0b5c6a9e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_7_2_sc7280.h @@ -10,7 +10,6 @@ static const struct dpu_caps sc7280_dpu_caps = { .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, .max_mixer_blendstages = 0x7, - .qseed_type = DPU_SSPP_SCALER_QSEED4, .has_dim_layer = true, .has_idle_pc = true, .max_linewidth = 2400, @@ -25,7 +24,7 @@ static const struct dpu_mdp_cfg sc7280_mdp = { [DPU_CLK_CTRL_DMA0] = { .reg_off = 0x2ac, .bit_off = 8 }, [DPU_CLK_CTRL_DMA1] = { .reg_off = 0x2b4, .bit_off = 8 }, [DPU_CLK_CTRL_DMA2] = { .reg_off = 0x2c4, .bit_off = 8 }, - [DPU_CLK_CTRL_WB2] = { .reg_off = 0x3b8, .bit_off = 24 }, + [DPU_CLK_CTRL_WB2] = { .reg_off = 0x2bc, .bit_off = 16 }, }, }; @@ -58,7 +57,7 @@ static const struct dpu_sspp_cfg sc7280_sspp[] = { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x1f8, .features = VIG_SC7280_MASK_SDMA, - .sblk = &sc7280_vig_sblk_0, + .sblk = &dpu_vig_sblk_qseed3_3_0_rot_v2, .xin_id = 0, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG0, @@ -66,7 +65,7 @@ static const struct dpu_sspp_cfg sc7280_sspp[] = { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x1f8, .features = DMA_SDM845_MASK_SDMA, - .sblk = &sdm845_dma_sblk_0, + .sblk = &dpu_dma_sblk, .xin_id = 1, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA0, @@ -74,7 +73,7 @@ static const struct dpu_sspp_cfg sc7280_sspp[] = { .name = "sspp_9", .id = SSPP_DMA1, .base = 0x26000, .len = 0x1f8, .features = DMA_CURSOR_SDM845_MASK_SDMA, - .sblk = &sdm845_dma_sblk_1, + .sblk = &dpu_dma_sblk, .xin_id = 5, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA1, @@ -82,7 +81,7 @@ static const struct dpu_sspp_cfg sc7280_sspp[] = { .name = "sspp_10", .id = SSPP_DMA2, .base = 0x28000, .len = 0x1f8, .features = DMA_CURSOR_SDM845_MASK_SDMA, - .sblk = &sdm845_dma_sblk_2, + .sblk = &dpu_dma_sblk, .xin_id = 9, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA2, @@ -170,8 +169,8 @@ static const struct dpu_wb_cfg sc7280_wb[] = { .name = "wb_2", .id = WB_2, .base = 0x65000, .len = 0x2c8, .features = WB_SM8250_MASK, - .format_list = wb2_formats, - .num_formats = ARRAY_SIZE(wb2_formats), + .format_list = wb2_formats_rgb_yuv, + .num_formats = ARRAY_SIZE(wb2_formats_rgb_yuv), .clk_ctrl = DPU_CLK_CTRL_WB2, .xin_id = 6, .vbif_idx = VBIF_RT, @@ -249,6 +248,7 @@ const struct dpu_mdss_cfg dpu_sc7280_cfg = { .mdss_ver = &sc7280_mdss_ver, .caps = &sc7280_dpu_caps, .mdp = &sc7280_mdp, + .cdm = &sc7280_cdm, .ctl_count = ARRAY_SIZE(sc7280_ctl), .ctl = sc7280_ctl, .sspp_count = ARRAY_SIZE(sc7280_sspp), diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h index 4c0528794e7a7e..0d143e390eca96 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h @@ -10,7 +10,6 @@ static const struct dpu_caps sc8280xp_dpu_caps = { .max_mixer_width = DEFAULT_DPU_OUTPUT_LINE_WIDTH, .max_mixer_blendstages = 11, - .qseed_type = DPU_SSPP_SCALER_QSEED4, .has_src_split = true, .has_dim_layer = true, .has_idle_pc = true, @@ -75,32 +74,32 @@ static const struct dpu_sspp_cfg sc8280xp_sspp[] = { { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x2ac, - .features = VIG_SC7180_MASK, - .sblk = &sm8250_vig_sblk_0, + .features = VIG_SDM845_MASK, + .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 0, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG0, }, { .name = "sspp_1", .id = SSPP_VIG1, .base = 0x6000, .len = 0x2ac, - .features = VIG_SC7180_MASK, - .sblk = &sm8250_vig_sblk_1, + .features = VIG_SDM845_MASK, + .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 4, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG1, }, { .name = "sspp_2", .id = SSPP_VIG2, .base = 0x8000, .len = 0x2ac, - .features = VIG_SC7180_MASK, - .sblk = &sm8250_vig_sblk_2, + .features = VIG_SDM845_MASK, + .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 8, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG2, }, { .name = "sspp_3", .id = SSPP_VIG3, .base = 0xa000, .len = 0x2ac, - .features = VIG_SC7180_MASK, - .sblk = &sm8250_vig_sblk_3, + .features = VIG_SDM845_MASK, + .sblk = &dpu_vig_sblk_qseed3_3_0, .xin_id = 12, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG3, @@ -108,7 +107,7 @@ static const struct dpu_sspp_cfg sc8280xp_sspp[] = { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x2ac, .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_0, + .sblk = &dpu_dma_sblk, .xin_id = 1, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA0, @@ -116,7 +115,7 @@ static const struct dpu_sspp_cfg sc8280xp_sspp[] = { .name = "sspp_9", .id = SSPP_DMA1, .base = 0x26000, .len = 0x2ac, .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_1, + .sblk = &dpu_dma_sblk, .xin_id = 5, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA1, @@ -124,7 +123,7 @@ static const struct dpu_sspp_cfg sc8280xp_sspp[] = { .name = "sspp_10", .id = SSPP_DMA2, .base = 0x28000, .len = 0x2ac, .features = DMA_CURSOR_SDM845_MASK, - .sblk = &sdm845_dma_sblk_2, + .sblk = &dpu_dma_sblk, .xin_id = 9, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA2, @@ -132,7 +131,7 @@ static const struct dpu_sspp_cfg sc8280xp_sspp[] = { .name = "sspp_11", .id = SSPP_DMA3, .base = 0x2a000, .len = 0x2ac, .features = DMA_CURSOR_SDM845_MASK, - .sblk = &sdm845_dma_sblk_3, + .sblk = &dpu_dma_sblk, .xin_id = 13, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA3, diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h index 7742f52be859b4..a1779c5597ae70 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_1_sm8450.h @@ -10,7 +10,6 @@ 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, .has_src_split = true, .has_dim_layer = true, .has_idle_pc = true, @@ -32,6 +31,7 @@ static const struct dpu_mdp_cfg sm8450_mdp = { [DPU_CLK_CTRL_DMA1] = { .reg_off = 0x2b4, .bit_off = 8 }, [DPU_CLK_CTRL_DMA2] = { .reg_off = 0x2bc, .bit_off = 8 }, [DPU_CLK_CTRL_DMA3] = { .reg_off = 0x2c4, .bit_off = 8 }, + [DPU_CLK_CTRL_WB2] = { .reg_off = 0x2bc, .bit_off = 16 }, [DPU_CLK_CTRL_REG_DMA] = { .reg_off = 0x2bc, .bit_off = 20 }, }, }; @@ -75,64 +75,64 @@ static const struct dpu_sspp_cfg sm8450_sspp[] = { { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x32c, - .features = VIG_SC7180_MASK, - .sblk = &sm8250_vig_sblk_0, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_1, .xin_id = 0, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG0, }, { .name = "sspp_1", .id = SSPP_VIG1, .base = 0x6000, .len = 0x32c, - .features = VIG_SC7180_MASK, - .sblk = &sm8250_vig_sblk_1, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_1, .xin_id = 4, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG1, }, { .name = "sspp_2", .id = SSPP_VIG2, .base = 0x8000, .len = 0x32c, - .features = VIG_SC7180_MASK, - .sblk = &sm8250_vig_sblk_2, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_1, .xin_id = 8, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG2, }, { .name = "sspp_3", .id = SSPP_VIG3, .base = 0xa000, .len = 0x32c, - .features = VIG_SC7180_MASK, - .sblk = &sm8250_vig_sblk_3, + .features = VIG_SDM845_MASK_SDMA, + .sblk = &dpu_vig_sblk_qseed3_3_1, .xin_id = 12, .type = SSPP_TYPE_VIG, .clk_ctrl = DPU_CLK_CTRL_VIG3, }, { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x32c, - .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_0, + .features = DMA_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, .xin_id = 1, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA0, }, { .name = "sspp_9", .id = SSPP_DMA1, .base = 0x26000, .len = 0x32c, - .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_1, + .features = DMA_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, .xin_id = 5, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA1, }, { .name = "sspp_10", .id = SSPP_DMA2, .base = 0x28000, .len = 0x32c, - .features = DMA_CURSOR_SDM845_MASK, - .sblk = &sdm845_dma_sblk_2, + .features = DMA_CURSOR_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, .xin_id = 9, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA2, }, { .name = "sspp_11", .id = SSPP_DMA3, .base = 0x2a000, .len = 0x32c, - .features = DMA_CURSOR_SDM845_MASK, - .sblk = &sdm845_dma_sblk_3, + .features = DMA_CURSOR_SDM845_MASK_SDMA, + .sblk = &dpu_dma_sblk, .xin_id = 13, .type = SSPP_TYPE_DMA, .clk_ctrl = DPU_CLK_CTRL_DMA3, @@ -316,6 +316,21 @@ static const struct dpu_dsc_cfg sm8450_dsc[] = { }, }; +static const struct dpu_wb_cfg sm8450_wb[] = { + { + .name = "wb_2", .id = WB_2, + .base = 0x65000, .len = 0x2c8, + .features = WB_SM8250_MASK, + .format_list = wb2_formats_rgb, + .num_formats = ARRAY_SIZE(wb2_formats_rgb), + .clk_ctrl = DPU_CLK_CTRL_WB2, + .xin_id = 6, + .vbif_idx = VBIF_RT, + .maxlinewidth = 4096, + .intr_wb_done = DPU_IRQ_IDX(MDP_SSPP_TOP0_INTR, 4), + }, +}; + static const struct dpu_intf_cfg sm8450_intf[] = { { .name = "intf_0", .id = INTF_0, @@ -411,6 +426,8 @@ const struct dpu_mdss_cfg dpu_sm8450_cfg = { .dsc = sm8450_dsc, .merge_3d_count = ARRAY_SIZE(sm8450_merge_3d), .merge_3d = sm8450_merge_3d, + .wb_count = ARRAY_SIZE(sm8450_wb), + .wb = sm8450_wb, .intf_count = ARRAY_SIZE(sm8450_intf), .intf = sm8450_intf, .vbif_count = ARRAY_SIZE(sdm845_vbif), diff --git a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h index 69b80af6566a68..ad48defa154f7d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h +++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_9_0_sm8550.h @@ -10,7 +10,6 @@ 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_QSEED4, .has_src_split = true, .has_dim_layer = true, .has_idle_pc = true, @@ -67,71 +66,71 @@ static const struct dpu_sspp_cfg sm8550_sspp[] = { { .name = "sspp_0", .id = SSPP_VIG0, .base = 0x4000, .len = 0x344, - .features = VIG_SC7180_MASK, - .sblk = &sm8550_vig_sblk_0, + .features = VIG_SDM845_MASK, + .sblk = &dpu_vig_sblk_qseed3_3_2, .xin_id = 0, .type = SSPP_TYPE_VIG, }, { .name = "sspp_1", .id = SSPP_VIG1, .base = 0x6000, .len = 0x344, - .features = VIG_SC7180_MASK, - .sblk = &sm8550_vig_sblk_1, + .features = VIG_SDM845_MASK, + .sblk = &dpu_vig_sblk_qseed3_3_2, .xin_id = 4, .type = SSPP_TYPE_VIG, }, { .name = "sspp_2", .id = SSPP_VIG2, .base = 0x8000, .len = 0x344, - .features = VIG_SC7180_MASK, - .sblk = &sm8550_vig_sblk_2, + .features = VIG_SDM845_MASK, + .sblk = &dpu_vig_sblk_qseed3_3_2, .xin_id = 8, .type = SSPP_TYPE_VIG, }, { .name = "sspp_3", .id = SSPP_VIG3, .base = 0xa000, .len = 0x344, - .features = VIG_SC7180_MASK, - .sblk = &sm8550_vig_sblk_3, + .features = VIG_SDM845_MASK, + .sblk = &dpu_vig_sblk_qseed3_3_2, .xin_id = 12, .type = SSPP_TYPE_VIG, }, { .name = "sspp_8", .id = SSPP_DMA0, .base = 0x24000, .len = 0x344, .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_0, + .sblk = &dpu_dma_sblk, .xin_id = 1, .type = SSPP_TYPE_DMA, }, { .name = "sspp_9", .id = SSPP_DMA1, .base = 0x26000, .len = 0x344, .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_1, + .sblk = &dpu_dma_sblk, .xin_id = 5, .type = SSPP_TYPE_DMA, }, { .name = "sspp_10", .id = SSPP_DMA2, .base = 0x28000, .len = 0x344, .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_2, + .sblk = &dpu_dma_sblk, .xin_id = 9, .type = SSPP_TYPE_DMA, }, { .name = "sspp_11", .id = SSPP_DMA3, .base = 0x2a000, .len = 0x344, .features = DMA_SDM845_MASK, - .sblk = &sdm845_dma_sblk_3, + .sblk = &dpu_dma_sblk, .xin_id = 13, .type = SSPP_TYPE_DMA, }, { .name = "sspp_12", .id = SSPP_DMA4, .base = 0x2c000, .len = 0x344, .features = DMA_CURSOR_SDM845_MASK, - .sblk = &sm8550_dma_sblk_4, + .sblk = &dpu_dma_sblk, .xin_id = 14, .type = SSPP_TYPE_DMA, }, { .name = "sspp_13", .id = SSPP_DMA5, .base = 0x2e000, .len = 0x344, .features = DMA_CURSOR_SDM845_MASK, - .sblk = &sm8550_dma_sblk_5, + .sblk = &dpu_dma_sblk, .xin_id = 15, .type = SSPP_TYPE_DMA, }, @@ -316,8 +315,8 @@ static const struct dpu_wb_cfg sm8550_wb[] = { .name = "wb_2", .id = WB_2, .base = 0x65000, .len = 0x2c8, .features = WB_SM8250_MASK, - .format_list = wb2_formats, - .num_formats = ARRAY_SIZE(wb2_formats), + .format_list = wb2_formats_rgb, + .num_formats = ARRAY_SIZE(wb2_formats_rgb), .xin_id = 6, .vbif_idx = VBIF_RT, .maxlinewidth = 4096, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 3c475f8042b037..88c2e51ab16620 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark @@ -51,17 +51,6 @@ static struct dpu_kms *_dpu_crtc_get_kms(struct drm_crtc *crtc) return to_dpu_kms(priv->kms); } -static void dpu_crtc_destroy(struct drm_crtc *crtc) -{ - struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc); - - if (!crtc) - return; - - drm_crtc_cleanup(crtc); - kfree(dpu_crtc); -} - static struct drm_encoder *get_encoder_from_crtc(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -125,7 +114,7 @@ static void dpu_crtc_setup_lm_misr(struct dpu_crtc_state *crtc_state) continue; /* Calculate MISR over 1 frame */ - m->hw_lm->ops.setup_misr(m->hw_lm, true, 1); + m->hw_lm->ops.setup_misr(m->hw_lm); } } @@ -1435,7 +1424,6 @@ static int dpu_crtc_late_register(struct drm_crtc *crtc) static const struct drm_crtc_funcs dpu_crtc_funcs = { .set_config = drm_atomic_helper_set_config, - .destroy = dpu_crtc_destroy, .page_flip = drm_atomic_helper_page_flip, .reset = dpu_crtc_reset, .atomic_duplicate_state = dpu_crtc_duplicate_state, @@ -1469,9 +1457,13 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane *plane, struct dpu_crtc *dpu_crtc; int i, ret; - dpu_crtc = kzalloc(sizeof(*dpu_crtc), GFP_KERNEL); - if (!dpu_crtc) - return ERR_PTR(-ENOMEM); + dpu_crtc = drmm_crtc_alloc_with_planes(dev, struct dpu_crtc, base, + plane, cursor, + &dpu_crtc_funcs, + NULL); + + if (IS_ERR(dpu_crtc)) + return ERR_CAST(dpu_crtc); crtc = &dpu_crtc->base; crtc->dev = dev; @@ -1491,9 +1483,6 @@ struct drm_crtc *dpu_crtc_init(struct drm_device *dev, struct drm_plane *plane, dpu_crtc_frame_event_work); } - drm_crtc_init_with_planes(dev, crtc, plane, cursor, &dpu_crtc_funcs, - NULL); - drm_crtc_helper_add(crtc, &dpu_crtc_helper_funcs); if (dpu_kms->catalog->dspp_count) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 1cf7ff6caff4ef..83380bc92a00a9 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -2,7 +2,7 @@ /* * Copyright (C) 2013 Red Hat * Copyright (c) 2014-2018, 2020-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. * * Author: Rob Clark */ @@ -16,6 +16,7 @@ #include #include #include +#include #include "msm_drv.h" #include "dpu_kms.h" @@ -26,6 +27,7 @@ #include "dpu_hw_dspp.h" #include "dpu_hw_dsc.h" #include "dpu_hw_merge3d.h" +#include "dpu_hw_cdm.h" #include "dpu_formats.h" #include "dpu_encoder_phys.h" #include "dpu_crtc.h" @@ -39,6 +41,9 @@ #define DPU_ERROR_ENC(e, fmt, ...) DPU_ERROR("enc%d " fmt,\ (e) ? (e)->base.base.id : -1, ##__VA_ARGS__) +#define DPU_ERROR_ENC_RATELIMITED(e, fmt, ...) DPU_ERROR_RATELIMITED("enc%d " fmt,\ + (e) ? (e)->base.base.id : -1, ##__VA_ARGS__) + /* * Two to anticipate panels that can do cmd/vid dynamic switching * plan is to create all possible physical encoder types, and switch between @@ -151,6 +156,8 @@ enum dpu_enc_rc_states { * @crtc_frame_event_cb: callback handler for frame event * @crtc_frame_event_cb_data: callback handler private data * @frame_done_timeout_ms: frame done timeout in ms + * @frame_done_timeout_cnt: atomic counter tracking the number of frame + * done timeouts * @frame_done_timer: watchdog timer for frame done event * @disp_info: local copy of msm_display_info struct * @idle_pc_supported: indicate if idle power collaps is supported @@ -184,13 +191,13 @@ struct dpu_encoder_virt { struct drm_crtc *crtc; struct drm_connector *connector; - struct dentry *debugfs_root; struct mutex enc_lock; DECLARE_BITMAP(frame_busy_mask, MAX_PHYS_ENCODERS_PER_VIRTUAL); void (*crtc_frame_event_cb)(void *, u32 event); void *crtc_frame_event_cb_data; atomic_t frame_done_timeout_ms; + atomic_t frame_done_timeout_cnt; struct timer_list frame_done_timer; struct msm_display_info disp_info; @@ -255,7 +262,7 @@ void dpu_encoder_setup_misr(const struct drm_encoder *drm_enc) if (!phys->hw_intf || !phys->hw_intf->ops.setup_misr) continue; - phys->hw_intf->ops.setup_misr(phys->hw_intf, true, 1); + phys->hw_intf->ops.setup_misr(phys->hw_intf); } } @@ -439,41 +446,6 @@ int dpu_encoder_get_linecount(struct drm_encoder *drm_enc) return linecount; } -static void dpu_encoder_destroy(struct drm_encoder *drm_enc) -{ - struct dpu_encoder_virt *dpu_enc = NULL; - int i = 0; - - if (!drm_enc) { - DPU_ERROR("invalid encoder\n"); - return; - } - - dpu_enc = to_dpu_encoder_virt(drm_enc); - DPU_DEBUG_ENC(dpu_enc, "\n"); - - mutex_lock(&dpu_enc->enc_lock); - - for (i = 0; i < dpu_enc->num_phys_encs; i++) { - struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; - - if (phys->ops.destroy) { - phys->ops.destroy(phys); - --dpu_enc->num_phys_encs; - dpu_enc->phys_encs[i] = NULL; - } - } - - if (dpu_enc->num_phys_encs) - DPU_ERROR_ENC(dpu_enc, "expected 0 num_phys_encs not %d\n", - dpu_enc->num_phys_encs); - dpu_enc->num_phys_encs = 0; - mutex_unlock(&dpu_enc->enc_lock); - - drm_encoder_cleanup(drm_enc); - mutex_destroy(&dpu_enc->enc_lock); -} - void dpu_encoder_helper_split_config( struct dpu_encoder_phys *phys_enc, enum dpu_intf interface) @@ -614,6 +586,7 @@ static int dpu_encoder_virt_atomic_check( struct drm_display_mode *adj_mode; struct msm_display_topology topology; struct dpu_global_state *global_state; + struct drm_framebuffer *fb; struct drm_dsc_config *dsc; int i = 0; int ret = 0; @@ -654,6 +627,22 @@ static int dpu_encoder_virt_atomic_check( topology = dpu_encoder_get_topology(dpu_enc, dpu_kms, adj_mode, crtc_state, dsc); + /* + * Use CDM only for writeback at the moment as other interfaces cannot handle it. + * if writeback itself cannot handle cdm for some reason it will fail in its atomic_check() + * earlier. + */ + if (dpu_enc->disp_info.intf_type == INTF_WB && conn_state->writeback_job) { + fb = conn_state->writeback_job->fb; + + if (fb && DPU_FORMAT_IS_YUV(to_dpu_format(msm_framebuffer_format(fb)))) + topology.needs_cdm = true; + if (topology.needs_cdm && !dpu_enc->cur_master->hw_cdm) + crtc_state->mode_changed = true; + else if (!topology.needs_cdm && dpu_enc->cur_master->hw_cdm) + crtc_state->mode_changed = true; + } + /* * Release and Allocate resources on every modeset * Dont allocate when active is false. @@ -1094,6 +1083,15 @@ static void dpu_encoder_virt_atomic_mode_set(struct drm_encoder *drm_enc, dpu_enc->dsc_mask = dsc_mask; + if (dpu_enc->disp_info.intf_type == INTF_WB && conn_state->writeback_job) { + struct dpu_hw_blk *hw_cdm = NULL; + + dpu_rm_get_assigned_resources(&dpu_kms->rm, global_state, + drm_enc->base.id, DPU_HW_BLK_CDM, + &hw_cdm, 1); + dpu_enc->cur_master->hw_cdm = hw_cdm ? to_dpu_hw_cdm(hw_cdm) : NULL; + } + cstate = to_dpu_crtc_state(crtc_state); for (i = 0; i < num_lm; i++) { @@ -1204,6 +1202,8 @@ static void dpu_encoder_virt_atomic_enable(struct drm_encoder *drm_enc, dpu_enc->dsc = dpu_encoder_get_dsc_config(drm_enc); + atomic_set(&dpu_enc->frame_done_timeout_cnt, 0); + if (disp_info->intf_type == INTF_DP) dpu_enc->wide_bus_en = msm_dp_wide_bus_available(priv->dp[index]); else if (disp_info->intf_type == INTF_DSI) @@ -2080,6 +2080,15 @@ void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc) phys_enc->hw_pp->merge_3d->idx); } + if (phys_enc->hw_cdm) { + if (phys_enc->hw_cdm->ops.bind_pingpong_blk && phys_enc->hw_pp) + phys_enc->hw_cdm->ops.bind_pingpong_blk(phys_enc->hw_cdm, + PINGPONG_NONE); + if (phys_enc->hw_ctl->ops.update_pending_flush_cdm) + phys_enc->hw_ctl->ops.update_pending_flush_cdm(phys_enc->hw_ctl, + phys_enc->hw_cdm->idx); + } + if (dpu_enc->dsc) { dpu_encoder_unprep_dsc(dpu_enc); dpu_enc->dsc = NULL; @@ -2108,18 +2117,20 @@ void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc) #ifdef CONFIG_DEBUG_FS static int _dpu_encoder_status_show(struct seq_file *s, void *data) { - struct dpu_encoder_virt *dpu_enc = s->private; + struct drm_encoder *drm_enc = s->private; + struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc); int i; mutex_lock(&dpu_enc->enc_lock); for (i = 0; i < dpu_enc->num_phys_encs; i++) { struct dpu_encoder_phys *phys = dpu_enc->phys_encs[i]; - seq_printf(s, "intf:%d wb:%d vsync:%8d underrun:%8d ", + seq_printf(s, "intf:%d wb:%d vsync:%8d underrun:%8d frame_done_cnt:%d", phys->hw_intf ? phys->hw_intf->idx - INTF_0 : -1, phys->hw_wb ? phys->hw_wb->idx - WB_0 : -1, atomic_read(&phys->vsync_cnt), - atomic_read(&phys->underrun_cnt)); + atomic_read(&phys->underrun_cnt), + atomic_read(&dpu_enc->frame_done_timeout_cnt)); seq_printf(s, "mode: %s\n", dpu_encoder_helper_get_intf_type(phys->intf_mode)); } @@ -2130,49 +2141,18 @@ static int _dpu_encoder_status_show(struct seq_file *s, void *data) DEFINE_SHOW_ATTRIBUTE(_dpu_encoder_status); -static int _dpu_encoder_init_debugfs(struct drm_encoder *drm_enc) +static void dpu_encoder_debugfs_init(struct drm_encoder *drm_enc, struct dentry *root) { - struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc); - - char name[12]; - - if (!drm_enc->dev) { - DPU_ERROR("invalid encoder or kms\n"); - return -EINVAL; - } - - snprintf(name, sizeof(name), "encoder%u", drm_enc->base.id); - - /* create overall sub-directory for the encoder */ - dpu_enc->debugfs_root = debugfs_create_dir(name, - drm_enc->dev->primary->debugfs_root); - /* don't error check these */ debugfs_create_file("status", 0600, - dpu_enc->debugfs_root, dpu_enc, &_dpu_encoder_status_fops); - - return 0; + root, drm_enc, &_dpu_encoder_status_fops); } #else -static int _dpu_encoder_init_debugfs(struct drm_encoder *drm_enc) -{ - return 0; -} +#define dpu_encoder_debugfs_init NULL #endif -static int dpu_encoder_late_register(struct drm_encoder *encoder) -{ - return _dpu_encoder_init_debugfs(encoder); -} - -static void dpu_encoder_early_unregister(struct drm_encoder *encoder) -{ - struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(encoder); - - debugfs_remove_recursive(dpu_enc->debugfs_root); -} - static int dpu_encoder_virt_add_phys_encs( + struct drm_device *dev, struct msm_display_info *disp_info, struct dpu_encoder_virt *dpu_enc, struct dpu_enc_phys_init_params *params) @@ -2194,7 +2174,7 @@ static int dpu_encoder_virt_add_phys_encs( if (disp_info->intf_type == INTF_WB) { - enc = dpu_encoder_phys_wb_init(params); + enc = dpu_encoder_phys_wb_init(dev, params); if (IS_ERR(enc)) { DPU_ERROR_ENC(dpu_enc, "failed to init wb enc: %ld\n", @@ -2205,7 +2185,7 @@ static int dpu_encoder_virt_add_phys_encs( dpu_enc->phys_encs[dpu_enc->num_phys_encs] = enc; ++dpu_enc->num_phys_encs; } else if (disp_info->is_cmd_mode) { - enc = dpu_encoder_phys_cmd_init(params); + enc = dpu_encoder_phys_cmd_init(dev, params); if (IS_ERR(enc)) { DPU_ERROR_ENC(dpu_enc, "failed to init cmd enc: %ld\n", @@ -2216,7 +2196,7 @@ static int dpu_encoder_virt_add_phys_encs( dpu_enc->phys_encs[dpu_enc->num_phys_encs] = enc; ++dpu_enc->num_phys_encs; } else { - enc = dpu_encoder_phys_vid_init(params); + enc = dpu_encoder_phys_vid_init(dev, params); if (IS_ERR(enc)) { DPU_ERROR_ENC(dpu_enc, "failed to init vid enc: %ld\n", @@ -2305,7 +2285,7 @@ static int dpu_encoder_setup_display(struct dpu_encoder_virt *dpu_enc, break; } - ret = dpu_encoder_virt_add_phys_encs(disp_info, + ret = dpu_encoder_virt_add_phys_encs(dpu_kms->dev, disp_info, dpu_enc, &phys_params); if (ret) { DPU_ERROR_ENC(dpu_enc, "failed to add phys encs\n"); @@ -2339,7 +2319,10 @@ static void dpu_encoder_frame_done_timeout(struct timer_list *t) return; } - DPU_ERROR_ENC(dpu_enc, "frame done timeout\n"); + DPU_ERROR_ENC_RATELIMITED(dpu_enc, "frame done timeout\n"); + + if (atomic_inc_return(&dpu_enc->frame_done_timeout_cnt) == 1) + msm_disp_snapshot_state(drm_enc->dev); event = DPU_ENCODER_FRAME_EVENT_ERROR; trace_dpu_enc_frame_done_timeout(DRMID(drm_enc), event); @@ -2354,9 +2337,7 @@ static const struct drm_encoder_helper_funcs dpu_encoder_helper_funcs = { }; static const struct drm_encoder_funcs dpu_encoder_funcs = { - .destroy = dpu_encoder_destroy, - .late_register = dpu_encoder_late_register, - .early_unregister = dpu_encoder_early_unregister, + .debugfs_init = dpu_encoder_debugfs_init, }; struct drm_encoder *dpu_encoder_init(struct drm_device *dev, @@ -2365,20 +2346,13 @@ struct drm_encoder *dpu_encoder_init(struct drm_device *dev, { struct msm_drm_private *priv = dev->dev_private; struct dpu_kms *dpu_kms = to_dpu_kms(priv->kms); - struct drm_encoder *drm_enc = NULL; - struct dpu_encoder_virt *dpu_enc = NULL; - int ret = 0; - - dpu_enc = devm_kzalloc(dev->dev, sizeof(*dpu_enc), GFP_KERNEL); - if (!dpu_enc) - return ERR_PTR(-ENOMEM); + struct dpu_encoder_virt *dpu_enc; + int ret; - ret = drm_encoder_init(dev, &dpu_enc->base, &dpu_encoder_funcs, - drm_enc_mode, NULL); - if (ret) { - devm_kfree(dev->dev, dpu_enc); - return ERR_PTR(ret); - } + dpu_enc = drmm_encoder_alloc(dev, struct dpu_encoder_virt, base, + &dpu_encoder_funcs, drm_enc_mode, NULL); + if (IS_ERR(dpu_enc)) + return ERR_CAST(dpu_enc); drm_encoder_helper_add(&dpu_enc->base, &dpu_encoder_helper_funcs); @@ -2388,10 +2362,13 @@ struct drm_encoder *dpu_encoder_init(struct drm_device *dev, mutex_init(&dpu_enc->rc_lock); ret = dpu_encoder_setup_display(dpu_enc, dpu_kms, disp_info); - if (ret) - goto fail; + if (ret) { + DPU_ERROR("failed to setup encoder\n"); + return ERR_PTR(-ENOMEM); + } atomic_set(&dpu_enc->frame_done_timeout_ms, 0); + atomic_set(&dpu_enc->frame_done_timeout_cnt, 0); timer_setup(&dpu_enc->frame_done_timer, dpu_encoder_frame_done_timeout, 0); @@ -2404,13 +2381,6 @@ struct drm_encoder *dpu_encoder_init(struct drm_device *dev, DPU_DEBUG_ENC(dpu_enc, "created\n"); return &dpu_enc->base; - -fail: - DPU_ERROR("failed to create encoder\n"); - if (drm_enc) - dpu_encoder_destroy(drm_enc); - - return ERR_PTR(ret); } int dpu_encoder_wait_for_event(struct drm_encoder *drm_enc, @@ -2437,9 +2407,6 @@ int dpu_encoder_wait_for_event(struct drm_encoder *drm_enc, case MSM_ENC_TX_COMPLETE: fn_wait = phys->ops.wait_for_tx_complete; break; - case MSM_ENC_VBLANK: - fn_wait = phys->ops.wait_for_vblank; - break; default: DPU_ERROR_ENC(dpu_enc, "unknown wait event %d\n", event); @@ -2497,7 +2464,6 @@ void dpu_encoder_phys_init(struct dpu_encoder_phys *phys_enc, phys_enc->enc_spinlock = p->enc_spinlock; phys_enc->enable_state = DPU_ENC_DISABLED; - atomic_set(&phys_enc->vblank_refcount, 0); atomic_set(&phys_enc->pending_kickoff_cnt, 0); atomic_set(&phys_enc->pending_ctlstart_cnt, 0); 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 6f04c3d56e77c6..993f263433314d 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h @@ -14,8 +14,10 @@ #include "dpu_hw_intf.h" #include "dpu_hw_wb.h" #include "dpu_hw_pingpong.h" +#include "dpu_hw_cdm.h" #include "dpu_hw_ctl.h" #include "dpu_hw_top.h" +#include "dpu_hw_util.h" #include "dpu_encoder.h" #include "dpu_crtc.h" @@ -72,7 +74,6 @@ struct dpu_encoder_phys; * @enable: DRM Call. Enable a DRM mode. * @disable: DRM Call. Disable mode. * @atomic_check: DRM Call. Atomic check new DRM state. - * @destroy: DRM Call. Destroy and release resources. * @control_vblank_irq Register/Deregister for VBLANK IRQ * @wait_for_commit_done: Wait for hardware to have flushed the * current pending frames to hardware @@ -102,11 +103,9 @@ struct dpu_encoder_phys_ops { int (*atomic_check)(struct dpu_encoder_phys *encoder, struct drm_crtc_state *crtc_state, struct drm_connector_state *conn_state); - void (*destroy)(struct dpu_encoder_phys *encoder); int (*control_vblank_irq)(struct dpu_encoder_phys *enc, bool enable); int (*wait_for_commit_done)(struct dpu_encoder_phys *phys_enc); int (*wait_for_tx_complete)(struct dpu_encoder_phys *phys_enc); - int (*wait_for_vblank)(struct dpu_encoder_phys *phys_enc); void (*prepare_for_kickoff)(struct dpu_encoder_phys *phys_enc); void (*handle_post_kickoff)(struct dpu_encoder_phys *phys_enc); void (*trigger_start)(struct dpu_encoder_phys *phys_enc); @@ -153,8 +152,10 @@ enum dpu_intr_idx { * @hw_pp: Hardware interface to the ping pong registers * @hw_intf: Hardware interface to the intf registers * @hw_wb: Hardware interface to the wb registers + * @hw_cdm: Hardware interface to the CDM registers * @dpu_kms: Pointer to the dpu_kms top level * @cached_mode: DRM mode cached at mode_set time, acted on in enable + * @vblank_ctl_lock: Vblank ctl mutex lock to protect vblank_refcount * @enabled: Whether the encoder has enabled and running a mode * @split_role: Role to play in a split-panel configuration * @intf_mode: Interface mode @@ -181,13 +182,15 @@ struct dpu_encoder_phys { struct dpu_hw_pingpong *hw_pp; struct dpu_hw_intf *hw_intf; struct dpu_hw_wb *hw_wb; + struct dpu_hw_cdm *hw_cdm; struct dpu_kms *dpu_kms; struct drm_display_mode cached_mode; + struct mutex vblank_ctl_lock; enum dpu_enc_split_role split_role; enum dpu_intf_mode intf_mode; spinlock_t *enc_spinlock; enum dpu_enc_enable_state enable_state; - atomic_t vblank_refcount; + int vblank_refcount; atomic_t vsync_cnt; atomic_t underrun_cnt; atomic_t pending_ctlstart_cnt; @@ -210,6 +213,7 @@ static inline int dpu_encoder_phys_inc_pending(struct dpu_encoder_phys *phys) * @wbirq_refcount: Reference count of writeback interrupt * @wb_done_timeout_cnt: number of wb done irq timeout errors * @wb_cfg: writeback block config to store fb related details + * @cdm_cfg: cdm block config needed to store writeback block's CDM configuration * @wb_conn: backpointer to writeback connector * @wb_job: backpointer to current writeback job * @dest: dpu buffer layout for current writeback output buffer @@ -219,6 +223,7 @@ struct dpu_encoder_phys_wb { atomic_t wbirq_refcount; int wb_done_timeout_cnt; struct dpu_hw_wb_cfg wb_cfg; + struct dpu_hw_cdm_cfg cdm_cfg; struct drm_writeback_connector *wb_conn; struct drm_writeback_job *wb_job; struct dpu_hw_fmt_layout dest; @@ -281,22 +286,24 @@ struct dpu_encoder_wait_info { * @p: Pointer to init params structure * Return: Error code or newly allocated encoder */ -struct dpu_encoder_phys *dpu_encoder_phys_vid_init( +struct dpu_encoder_phys *dpu_encoder_phys_vid_init(struct drm_device *dev, struct dpu_enc_phys_init_params *p); /** * dpu_encoder_phys_cmd_init - Construct a new command mode physical encoder + * @dev: Corresponding device for devres management * @p: Pointer to init params structure * Return: Error code or newly allocated encoder */ -struct dpu_encoder_phys *dpu_encoder_phys_cmd_init( +struct dpu_encoder_phys *dpu_encoder_phys_cmd_init(struct drm_device *dev, struct dpu_enc_phys_init_params *p); /** * dpu_encoder_phys_wb_init - initialize writeback encoder + * @dev: Corresponding device for devres management * @init: Pointer to init info structure with initialization params */ -struct dpu_encoder_phys *dpu_encoder_phys_wb_init( +struct dpu_encoder_phys *dpu_encoder_phys_wb_init(struct drm_device *dev, struct dpu_enc_phys_init_params *p); /** 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 be185fe69793b6..a301e2833177a2 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 @@ -13,6 +13,8 @@ #include "dpu_trace.h" #include "disp/msm_disp_snapshot.h" +#include + #define DPU_DEBUG_CMDENC(e, fmt, ...) DPU_DEBUG("enc%d intf%d " fmt, \ (e) && (e)->base.parent ? \ (e)->base.parent->base.id : -1, \ @@ -244,7 +246,8 @@ static int dpu_encoder_phys_cmd_control_vblank_irq( return -EINVAL; } - refcount = atomic_read(&phys_enc->vblank_refcount); + mutex_lock(&phys_enc->vblank_ctl_lock); + refcount = phys_enc->vblank_refcount; /* Slave encoders don't report vblank */ if (!dpu_encoder_phys_cmd_is_master(phys_enc)) @@ -260,16 +263,24 @@ static int dpu_encoder_phys_cmd_control_vblank_irq( phys_enc->hw_pp->idx - PINGPONG_0, enable ? "true" : "false", refcount); - if (enable && atomic_inc_return(&phys_enc->vblank_refcount) == 1) - ret = dpu_core_irq_register_callback(phys_enc->dpu_kms, - phys_enc->irq[INTR_IDX_RDPTR], - dpu_encoder_phys_cmd_te_rd_ptr_irq, - phys_enc); - else if (!enable && atomic_dec_return(&phys_enc->vblank_refcount) == 0) - ret = dpu_core_irq_unregister_callback(phys_enc->dpu_kms, - phys_enc->irq[INTR_IDX_RDPTR]); + if (enable) { + if (phys_enc->vblank_refcount == 0) + ret = dpu_core_irq_register_callback(phys_enc->dpu_kms, + phys_enc->irq[INTR_IDX_RDPTR], + dpu_encoder_phys_cmd_te_rd_ptr_irq, + phys_enc); + if (!ret) + phys_enc->vblank_refcount++; + } else if (!enable) { + if (phys_enc->vblank_refcount == 1) + ret = dpu_core_irq_unregister_callback(phys_enc->dpu_kms, + phys_enc->irq[INTR_IDX_RDPTR]); + if (!ret) + phys_enc->vblank_refcount--; + } end: + mutex_unlock(&phys_enc->vblank_ctl_lock); if (ret) { DRM_ERROR("vblank irq err id:%u pp:%d ret:%d, enable %s/%d\n", DRMID(phys_enc->parent), @@ -285,7 +296,7 @@ static void dpu_encoder_phys_cmd_irq_control(struct dpu_encoder_phys *phys_enc, { trace_dpu_enc_phys_cmd_irq_ctrl(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0, - enable, atomic_read(&phys_enc->vblank_refcount)); + enable, phys_enc->vblank_refcount); if (enable) { dpu_core_irq_register_callback(phys_enc->dpu_kms, @@ -558,14 +569,6 @@ static void dpu_encoder_phys_cmd_disable(struct dpu_encoder_phys *phys_enc) phys_enc->enable_state = DPU_ENC_DISABLED; } -static void dpu_encoder_phys_cmd_destroy(struct dpu_encoder_phys *phys_enc) -{ - struct dpu_encoder_phys_cmd *cmd_enc = - to_dpu_encoder_phys_cmd(phys_enc); - - kfree(cmd_enc); -} - static void dpu_encoder_phys_cmd_prepare_for_kickoff( struct dpu_encoder_phys *phys_enc) { @@ -681,33 +684,6 @@ static int dpu_encoder_phys_cmd_wait_for_commit_done( return _dpu_encoder_phys_cmd_wait_for_ctl_start(phys_enc); } -static int dpu_encoder_phys_cmd_wait_for_vblank( - struct dpu_encoder_phys *phys_enc) -{ - int rc = 0; - struct dpu_encoder_phys_cmd *cmd_enc; - struct dpu_encoder_wait_info wait_info; - - cmd_enc = to_dpu_encoder_phys_cmd(phys_enc); - - /* only required for master controller */ - if (!dpu_encoder_phys_cmd_is_master(phys_enc)) - return rc; - - wait_info.wq = &cmd_enc->pending_vblank_wq; - wait_info.atomic_cnt = &cmd_enc->pending_vblank_cnt; - wait_info.timeout_ms = KICKOFF_TIMEOUT_MS; - - atomic_inc(&cmd_enc->pending_vblank_cnt); - - rc = dpu_encoder_helper_wait_for_irq(phys_enc, - phys_enc->irq[INTR_IDX_RDPTR], - dpu_encoder_phys_cmd_te_rd_ptr_irq, - &wait_info); - - return rc; -} - static void dpu_encoder_phys_cmd_handle_post_kickoff( struct dpu_encoder_phys *phys_enc) { @@ -731,12 +707,10 @@ static void dpu_encoder_phys_cmd_init_ops( ops->atomic_mode_set = dpu_encoder_phys_cmd_atomic_mode_set; ops->enable = dpu_encoder_phys_cmd_enable; ops->disable = dpu_encoder_phys_cmd_disable; - ops->destroy = dpu_encoder_phys_cmd_destroy; ops->control_vblank_irq = dpu_encoder_phys_cmd_control_vblank_irq; ops->wait_for_commit_done = dpu_encoder_phys_cmd_wait_for_commit_done; ops->prepare_for_kickoff = dpu_encoder_phys_cmd_prepare_for_kickoff; ops->wait_for_tx_complete = dpu_encoder_phys_cmd_wait_for_tx_complete; - ops->wait_for_vblank = dpu_encoder_phys_cmd_wait_for_vblank; ops->trigger_start = dpu_encoder_phys_cmd_trigger_start; ops->needs_single_flush = dpu_encoder_phys_cmd_needs_single_flush; ops->irq_control = dpu_encoder_phys_cmd_irq_control; @@ -746,7 +720,7 @@ static void dpu_encoder_phys_cmd_init_ops( ops->get_line_count = dpu_encoder_phys_cmd_get_line_count; } -struct dpu_encoder_phys *dpu_encoder_phys_cmd_init( +struct dpu_encoder_phys *dpu_encoder_phys_cmd_init(struct drm_device *dev, struct dpu_enc_phys_init_params *p) { struct dpu_encoder_phys *phys_enc = NULL; @@ -754,7 +728,7 @@ struct dpu_encoder_phys *dpu_encoder_phys_cmd_init( DPU_DEBUG("intf\n"); - cmd_enc = kzalloc(sizeof(*cmd_enc), GFP_KERNEL); + cmd_enc = drmm_kzalloc(dev, sizeof(*cmd_enc), GFP_KERNEL); if (!cmd_enc) { DPU_ERROR("failed to allocate\n"); return ERR_PTR(-ENOMEM); @@ -763,6 +737,9 @@ struct dpu_encoder_phys *dpu_encoder_phys_cmd_init( dpu_encoder_phys_init(phys_enc, p); + mutex_init(&phys_enc->vblank_ctl_lock); + phys_enc->vblank_refcount = 0; + dpu_encoder_phys_cmd_init_ops(&phys_enc->ops); phys_enc->intf_mode = INTF_MODE_CMD; cmd_enc->stream_sel = 0; 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 a01fda7118835f..d0f56c5c4cce96 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 @@ -11,6 +11,8 @@ #include "dpu_trace.h" #include "disp/msm_disp_snapshot.h" +#include + #define DPU_DEBUG_VIDENC(e, fmt, ...) DPU_DEBUG("enc%d intf%d " fmt, \ (e) && (e)->parent ? \ (e)->parent->base.id : -1, \ @@ -364,7 +366,8 @@ static int dpu_encoder_phys_vid_control_vblank_irq( int ret = 0; int refcount; - refcount = atomic_read(&phys_enc->vblank_refcount); + mutex_lock(&phys_enc->vblank_ctl_lock); + refcount = phys_enc->vblank_refcount; /* Slave encoders don't report vblank */ if (!dpu_encoder_phys_vid_is_master(phys_enc)) @@ -377,18 +380,26 @@ static int dpu_encoder_phys_vid_control_vblank_irq( } DRM_DEBUG_VBL("id:%u enable=%d/%d\n", DRMID(phys_enc->parent), enable, - atomic_read(&phys_enc->vblank_refcount)); + refcount); - if (enable && atomic_inc_return(&phys_enc->vblank_refcount) == 1) - ret = dpu_core_irq_register_callback(phys_enc->dpu_kms, - phys_enc->irq[INTR_IDX_VSYNC], - dpu_encoder_phys_vid_vblank_irq, - phys_enc); - else if (!enable && atomic_dec_return(&phys_enc->vblank_refcount) == 0) - ret = dpu_core_irq_unregister_callback(phys_enc->dpu_kms, - phys_enc->irq[INTR_IDX_VSYNC]); + if (enable) { + if (phys_enc->vblank_refcount == 0) + ret = dpu_core_irq_register_callback(phys_enc->dpu_kms, + phys_enc->irq[INTR_IDX_VSYNC], + dpu_encoder_phys_vid_vblank_irq, + phys_enc); + if (!ret) + phys_enc->vblank_refcount++; + } else if (!enable) { + if (phys_enc->vblank_refcount == 1) + ret = dpu_core_irq_unregister_callback(phys_enc->dpu_kms, + phys_enc->irq[INTR_IDX_VSYNC]); + if (!ret) + phys_enc->vblank_refcount--; + } end: + mutex_unlock(&phys_enc->vblank_ctl_lock); if (ret) { DRM_ERROR("failed: id:%u intf:%d ret:%d enable:%d refcnt:%d\n", DRMID(phys_enc->parent), @@ -438,13 +449,7 @@ skip_flush: phys_enc->enable_state = DPU_ENC_ENABLING; } -static void dpu_encoder_phys_vid_destroy(struct dpu_encoder_phys *phys_enc) -{ - DPU_DEBUG_VIDENC(phys_enc, "\n"); - kfree(phys_enc); -} - -static int dpu_encoder_phys_vid_wait_for_vblank( +static int dpu_encoder_phys_vid_wait_for_tx_complete( struct dpu_encoder_phys *phys_enc) { struct dpu_encoder_wait_info wait_info; @@ -558,7 +563,7 @@ static void dpu_encoder_phys_vid_disable(struct dpu_encoder_phys *phys_enc) * scanout buffer) don't latch properly.. */ if (dpu_encoder_phys_vid_is_master(phys_enc)) { - ret = dpu_encoder_phys_vid_wait_for_vblank(phys_enc); + ret = dpu_encoder_phys_vid_wait_for_tx_complete(phys_enc); if (ret) { atomic_set(&phys_enc->pending_kickoff_cnt, 0); DRM_ERROR("wait disable failed: id:%u intf:%d ret:%d\n", @@ -578,7 +583,7 @@ static void dpu_encoder_phys_vid_disable(struct dpu_encoder_phys *phys_enc) spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags); dpu_encoder_phys_inc_pending(phys_enc); spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags); - ret = dpu_encoder_phys_vid_wait_for_vblank(phys_enc); + ret = dpu_encoder_phys_vid_wait_for_tx_complete(phys_enc); if (ret) { atomic_set(&phys_enc->pending_kickoff_cnt, 0); DRM_ERROR("wait disable failed: id:%u intf:%d ret:%d\n", @@ -618,7 +623,7 @@ static void dpu_encoder_phys_vid_irq_control(struct dpu_encoder_phys *phys_enc, trace_dpu_enc_phys_vid_irq_ctrl(DRMID(phys_enc->parent), phys_enc->hw_intf->idx - INTF_0, enable, - atomic_read(&phys_enc->vblank_refcount)); + phys_enc->vblank_refcount); if (enable) { ret = dpu_encoder_phys_vid_control_vblank_irq(phys_enc, true); @@ -681,11 +686,9 @@ static void dpu_encoder_phys_vid_init_ops(struct dpu_encoder_phys_ops *ops) ops->atomic_mode_set = dpu_encoder_phys_vid_atomic_mode_set; ops->enable = dpu_encoder_phys_vid_enable; ops->disable = dpu_encoder_phys_vid_disable; - ops->destroy = dpu_encoder_phys_vid_destroy; ops->control_vblank_irq = dpu_encoder_phys_vid_control_vblank_irq; ops->wait_for_commit_done = dpu_encoder_phys_vid_wait_for_commit_done; - ops->wait_for_vblank = dpu_encoder_phys_vid_wait_for_vblank; - ops->wait_for_tx_complete = dpu_encoder_phys_vid_wait_for_vblank; + ops->wait_for_tx_complete = dpu_encoder_phys_vid_wait_for_tx_complete; ops->irq_control = dpu_encoder_phys_vid_irq_control; ops->prepare_for_kickoff = dpu_encoder_phys_vid_prepare_for_kickoff; ops->handle_post_kickoff = dpu_encoder_phys_vid_handle_post_kickoff; @@ -694,7 +697,7 @@ static void dpu_encoder_phys_vid_init_ops(struct dpu_encoder_phys_ops *ops) ops->get_frame_count = dpu_encoder_phys_vid_get_frame_count; } -struct dpu_encoder_phys *dpu_encoder_phys_vid_init( +struct dpu_encoder_phys *dpu_encoder_phys_vid_init(struct drm_device *dev, struct dpu_enc_phys_init_params *p) { struct dpu_encoder_phys *phys_enc = NULL; @@ -704,7 +707,7 @@ struct dpu_encoder_phys *dpu_encoder_phys_vid_init( return ERR_PTR(-EINVAL); } - phys_enc = kzalloc(sizeof(*phys_enc), GFP_KERNEL); + phys_enc = drmm_kzalloc(dev, sizeof(*phys_enc), GFP_KERNEL); if (!phys_enc) { DPU_ERROR("failed to create encoder due to memory allocation error\n"); return ERR_PTR(-ENOMEM); @@ -713,6 +716,8 @@ struct dpu_encoder_phys *dpu_encoder_phys_vid_init( DPU_DEBUG_VIDENC(phys_enc, "\n"); dpu_encoder_phys_init(phys_enc, p); + mutex_init(&phys_enc->vblank_ctl_lock); + phys_enc->vblank_refcount = 0; dpu_encoder_phys_vid_init_ops(&phys_enc->ops); 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 0b6a761d68b798..4cd2d9e3131a43 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 @@ -8,6 +8,7 @@ #include #include +#include #include "dpu_encoder_phys.h" #include "dpu_formats.h" @@ -206,13 +207,14 @@ static void dpu_encoder_phys_wb_setup_fb(struct dpu_encoder_phys *phys_enc, } /** - * dpu_encoder_phys_wb_setup_cdp - setup chroma down prefetch block + * dpu_encoder_phys_wb_setup_ctl - setup wb pipeline for ctl path * @phys_enc:Pointer to physical encoder */ -static void dpu_encoder_phys_wb_setup_cdp(struct dpu_encoder_phys *phys_enc) +static void dpu_encoder_phys_wb_setup_ctl(struct dpu_encoder_phys *phys_enc) { struct dpu_hw_wb *hw_wb; struct dpu_hw_ctl *ctl; + struct dpu_hw_cdm *hw_cdm; if (!phys_enc) { DPU_ERROR("invalid encoder\n"); @@ -221,6 +223,7 @@ static void dpu_encoder_phys_wb_setup_cdp(struct dpu_encoder_phys *phys_enc) hw_wb = phys_enc->hw_wb; ctl = phys_enc->hw_ctl; + hw_cdm = phys_enc->hw_cdm; if (test_bit(DPU_CTL_ACTIVE_CFG, &ctl->caps->features) && (phys_enc->hw_ctl && @@ -237,6 +240,9 @@ static void dpu_encoder_phys_wb_setup_cdp(struct dpu_encoder_phys *phys_enc) if (mode_3d && hw_pp && hw_pp->merge_3d) intf_cfg.merge_3d = hw_pp->merge_3d->idx; + if (hw_cdm) + intf_cfg.cdm = hw_cdm->idx; + if (phys_enc->hw_pp->merge_3d && phys_enc->hw_pp->merge_3d->ops.setup_3d_mode) phys_enc->hw_pp->merge_3d->ops.setup_3d_mode(phys_enc->hw_pp->merge_3d, mode_3d); @@ -258,6 +264,96 @@ static void dpu_encoder_phys_wb_setup_cdp(struct dpu_encoder_phys *phys_enc) } } +/** + * dpu_encoder_helper_phys_setup_cdm - setup chroma down sampling block + * This API does not handle DPU_CHROMA_H1V2. + * @phys_enc:Pointer to physical encoder + */ +static void dpu_encoder_helper_phys_setup_cdm(struct dpu_encoder_phys *phys_enc) +{ + struct dpu_hw_cdm *hw_cdm; + struct dpu_hw_cdm_cfg *cdm_cfg; + struct dpu_hw_pingpong *hw_pp; + struct dpu_encoder_phys_wb *wb_enc; + const struct msm_format *format; + const struct dpu_format *dpu_fmt; + struct drm_writeback_job *wb_job; + int ret; + + if (!phys_enc) + return; + + wb_enc = to_dpu_encoder_phys_wb(phys_enc); + cdm_cfg = &wb_enc->cdm_cfg; + hw_pp = phys_enc->hw_pp; + hw_cdm = phys_enc->hw_cdm; + wb_job = wb_enc->wb_job; + + format = msm_framebuffer_format(wb_enc->wb_job->fb); + dpu_fmt = dpu_get_dpu_format_ext(format->pixel_format, wb_job->fb->modifier); + + if (!hw_cdm) + return; + + if (!DPU_FORMAT_IS_YUV(dpu_fmt)) { + DPU_DEBUG("[enc:%d] cdm_disable fmt:%x\n", DRMID(phys_enc->parent), + dpu_fmt->base.pixel_format); + if (hw_cdm->ops.bind_pingpong_blk) + hw_cdm->ops.bind_pingpong_blk(hw_cdm, PINGPONG_NONE); + + return; + } + + memset(cdm_cfg, 0, sizeof(struct dpu_hw_cdm_cfg)); + + cdm_cfg->output_width = wb_job->fb->width; + cdm_cfg->output_height = wb_job->fb->height; + cdm_cfg->output_fmt = dpu_fmt; + cdm_cfg->output_type = CDM_CDWN_OUTPUT_WB; + cdm_cfg->output_bit_depth = DPU_FORMAT_IS_DX(dpu_fmt) ? + CDM_CDWN_OUTPUT_10BIT : CDM_CDWN_OUTPUT_8BIT; + cdm_cfg->csc_cfg = &dpu_csc10_rgb2yuv_601l; + + /* enable 10 bit logic */ + switch (cdm_cfg->output_fmt->chroma_sample) { + case DPU_CHROMA_RGB: + cdm_cfg->h_cdwn_type = CDM_CDWN_DISABLE; + cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE; + break; + case DPU_CHROMA_H2V1: + cdm_cfg->h_cdwn_type = CDM_CDWN_COSITE; + cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE; + break; + case DPU_CHROMA_420: + cdm_cfg->h_cdwn_type = CDM_CDWN_COSITE; + cdm_cfg->v_cdwn_type = CDM_CDWN_OFFSITE; + break; + case DPU_CHROMA_H1V2: + default: + DPU_ERROR("[enc:%d] unsupported chroma sampling type\n", + DRMID(phys_enc->parent)); + cdm_cfg->h_cdwn_type = CDM_CDWN_DISABLE; + cdm_cfg->v_cdwn_type = CDM_CDWN_DISABLE; + break; + } + + DPU_DEBUG("[enc:%d] cdm_enable:%d,%d,%X,%d,%d,%d,%d]\n", + DRMID(phys_enc->parent), cdm_cfg->output_width, + cdm_cfg->output_height, cdm_cfg->output_fmt->base.pixel_format, + cdm_cfg->output_type, cdm_cfg->output_bit_depth, + cdm_cfg->h_cdwn_type, cdm_cfg->v_cdwn_type); + + if (hw_cdm->ops.enable) { + cdm_cfg->pp_id = hw_pp->idx; + ret = hw_cdm->ops.enable(hw_cdm, cdm_cfg); + if (ret < 0) { + DPU_ERROR("[enc:%d] failed to enable CDM; ret:%d\n", + DRMID(phys_enc->parent), ret); + return; + } + } +} + /** * dpu_encoder_phys_wb_atomic_check - verify and fixup given atomic states * @phys_enc: Pointer to physical encoder @@ -307,7 +403,7 @@ static int dpu_encoder_phys_wb_atomic_check( return -EINVAL; } - return 0; + return drm_atomic_helper_check_wb_connector_state(conn_state->connector, conn_state->state); } @@ -320,6 +416,7 @@ static void _dpu_encoder_phys_wb_update_flush(struct dpu_encoder_phys *phys_enc) struct dpu_hw_wb *hw_wb; struct dpu_hw_ctl *hw_ctl; struct dpu_hw_pingpong *hw_pp; + struct dpu_hw_cdm *hw_cdm; u32 pending_flush = 0; if (!phys_enc) @@ -328,6 +425,7 @@ static void _dpu_encoder_phys_wb_update_flush(struct dpu_encoder_phys *phys_enc) hw_wb = phys_enc->hw_wb; hw_pp = phys_enc->hw_pp; hw_ctl = phys_enc->hw_ctl; + hw_cdm = phys_enc->hw_cdm; DPU_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0); @@ -343,6 +441,9 @@ static void _dpu_encoder_phys_wb_update_flush(struct dpu_encoder_phys *phys_enc) hw_ctl->ops.update_pending_flush_merge_3d(hw_ctl, hw_pp->merge_3d->idx); + if (hw_cdm && hw_ctl->ops.update_pending_flush_cdm) + hw_ctl->ops.update_pending_flush_cdm(hw_ctl, hw_cdm->idx); + if (hw_ctl->ops.get_pending_flush) pending_flush = hw_ctl->ops.get_pending_flush(hw_ctl); @@ -374,8 +475,9 @@ static void dpu_encoder_phys_wb_setup( dpu_encoder_phys_wb_setup_fb(phys_enc, fb); - dpu_encoder_phys_wb_setup_cdp(phys_enc); + dpu_encoder_helper_phys_setup_cdm(phys_enc); + dpu_encoder_phys_wb_setup_ctl(phys_enc); } /** @@ -580,20 +682,6 @@ static void dpu_encoder_phys_wb_disable(struct dpu_encoder_phys *phys_enc) phys_enc->enable_state = DPU_ENC_DISABLED; } -/** - * dpu_encoder_phys_wb_destroy - destroy writeback encoder - * @phys_enc: Pointer to physical encoder - */ -static void dpu_encoder_phys_wb_destroy(struct dpu_encoder_phys *phys_enc) -{ - if (!phys_enc) - return; - - DPU_DEBUG("[wb:%d]\n", phys_enc->hw_wb->idx - WB_0); - - kfree(phys_enc); -} - static void dpu_encoder_phys_wb_prepare_wb_job(struct dpu_encoder_phys *phys_enc, struct drm_writeback_job *job) { @@ -689,7 +777,6 @@ static void dpu_encoder_phys_wb_init_ops(struct dpu_encoder_phys_ops *ops) ops->atomic_mode_set = dpu_encoder_phys_wb_atomic_mode_set; ops->enable = dpu_encoder_phys_wb_enable; ops->disable = dpu_encoder_phys_wb_disable; - ops->destroy = dpu_encoder_phys_wb_destroy; ops->atomic_check = dpu_encoder_phys_wb_atomic_check; ops->wait_for_commit_done = dpu_encoder_phys_wb_wait_for_commit_done; ops->prepare_for_kickoff = dpu_encoder_phys_wb_prepare_for_kickoff; @@ -705,9 +792,10 @@ static void dpu_encoder_phys_wb_init_ops(struct dpu_encoder_phys_ops *ops) /** * dpu_encoder_phys_wb_init - initialize writeback encoder + * @dev: Corresponding device for devres management * @p: Pointer to init info structure with initialization params */ -struct dpu_encoder_phys *dpu_encoder_phys_wb_init( +struct dpu_encoder_phys *dpu_encoder_phys_wb_init(struct drm_device *dev, struct dpu_enc_phys_init_params *p) { struct dpu_encoder_phys *phys_enc = NULL; @@ -720,7 +808,7 @@ struct dpu_encoder_phys *dpu_encoder_phys_wb_init( return ERR_PTR(-EINVAL); } - wb_enc = kzalloc(sizeof(*wb_enc), GFP_KERNEL); + wb_enc = drmm_kzalloc(dev, sizeof(*wb_enc), GFP_KERNEL); if (!wb_enc) { DPU_ERROR("failed to allocate wb phys_enc enc\n"); return ERR_PTR(-ENOMEM); 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 a1aada6307808c..54e8717403a0ac 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.c @@ -22,23 +22,14 @@ BIT(DPU_SSPP_CSC_10BIT)) #define VIG_MSM8998_MASK \ - (VIG_MASK | BIT(DPU_SSPP_SCALER_QSEED3)) + (VIG_MASK | BIT(DPU_SSPP_SCALER_QSEED3_COMPATIBLE)) #define VIG_SDM845_MASK \ - (VIG_MASK | BIT(DPU_SSPP_QOS_8LVL) | BIT(DPU_SSPP_SCALER_QSEED3)) + (VIG_MASK | BIT(DPU_SSPP_QOS_8LVL) | BIT(DPU_SSPP_SCALER_QSEED3_COMPATIBLE)) #define VIG_SDM845_MASK_SDMA \ (VIG_SDM845_MASK | BIT(DPU_SSPP_SMART_DMA_V2)) -#define VIG_SC7180_MASK \ - (VIG_MASK | BIT(DPU_SSPP_QOS_8LVL) | BIT(DPU_SSPP_SCALER_QSEED4)) - -#define VIG_SM6125_MASK \ - (VIG_MASK | BIT(DPU_SSPP_QOS_8LVL) | BIT(DPU_SSPP_SCALER_QSEED3LITE)) - -#define VIG_SC7180_MASK_SDMA \ - (VIG_SC7180_MASK | BIT(DPU_SSPP_SMART_DMA_V2)) - #define VIG_QCM2290_MASK (VIG_BASE_MASK | BIT(DPU_SSPP_QOS_8LVL)) #define DMA_MSM8998_MASK \ @@ -47,7 +38,7 @@ BIT(DPU_SSPP_CDP) | BIT(DPU_SSPP_EXCL_RECT)) #define VIG_SC7280_MASK \ - (VIG_SC7180_MASK | BIT(DPU_SSPP_INLINE_ROTATION)) + (VIG_SDM845_MASK | BIT(DPU_SSPP_INLINE_ROTATION)) #define VIG_SC7280_MASK_SDMA \ (VIG_SC7280_MASK | BIT(DPU_SSPP_SMART_DMA_V2)) @@ -211,7 +202,7 @@ static const u32 rotation_v2_formats[] = { /* TODO add formats after validation */ }; -static const uint32_t wb2_formats[] = { +static const u32 wb2_formats_rgb[] = { DRM_FORMAT_RGB565, DRM_FORMAT_BGR565, DRM_FORMAT_RGB888, @@ -245,21 +236,56 @@ static const uint32_t wb2_formats[] = { DRM_FORMAT_XBGR4444, }; +static const u32 wb2_formats_rgb_yuv[] = { + DRM_FORMAT_RGB565, + DRM_FORMAT_BGR565, + DRM_FORMAT_RGB888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_RGBA8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_RGBX8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_ARGB1555, + DRM_FORMAT_RGBA5551, + DRM_FORMAT_XRGB1555, + DRM_FORMAT_RGBX5551, + DRM_FORMAT_ARGB4444, + DRM_FORMAT_RGBA4444, + DRM_FORMAT_RGBX4444, + DRM_FORMAT_XRGB4444, + DRM_FORMAT_BGR565, + DRM_FORMAT_BGR888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_BGRA8888, + DRM_FORMAT_BGRX8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_ABGR1555, + DRM_FORMAT_BGRA5551, + DRM_FORMAT_XBGR1555, + DRM_FORMAT_BGRX5551, + DRM_FORMAT_ABGR4444, + DRM_FORMAT_BGRA4444, + DRM_FORMAT_BGRX4444, + DRM_FORMAT_XBGR4444, + DRM_FORMAT_NV12, +}; + /************************************************************* * SSPP sub blocks config *************************************************************/ +#define SSPP_SCALER_VER(maj, min) (((maj) << 16) | (min)) + /* SSPP common configuration */ -#define _VIG_SBLK(sdma_pri, qseed_ver) \ +#define _VIG_SBLK(scaler_ver) \ { \ .maxdwnscale = MAX_DOWNSCALE_RATIO, \ .maxupscale = MAX_UPSCALE_RATIO, \ - .smart_dma_priority = sdma_pri, \ .scaler_blk = {.name = "scaler", \ - .id = qseed_ver, \ + .version = scaler_ver, \ .base = 0xa00, .len = 0xa0,}, \ .csc_blk = {.name = "csc", \ - .id = DPU_SSPP_CSC_10BIT, \ .base = 0x1a00, .len = 0x100,}, \ .format_list = plane_formats_yuv, \ .num_formats = ARRAY_SIZE(plane_formats_yuv), \ @@ -268,16 +294,14 @@ static const uint32_t wb2_formats[] = { .rotation_cfg = NULL, \ } -#define _VIG_SBLK_ROT(sdma_pri, qseed_ver, rot_cfg) \ +#define _VIG_SBLK_ROT(scaler_ver, rot_cfg) \ { \ .maxdwnscale = MAX_DOWNSCALE_RATIO, \ .maxupscale = MAX_UPSCALE_RATIO, \ - .smart_dma_priority = sdma_pri, \ .scaler_blk = {.name = "scaler", \ - .id = qseed_ver, \ + .version = scaler_ver, \ .base = 0xa00, .len = 0xa0,}, \ .csc_blk = {.name = "csc", \ - .id = DPU_SSPP_CSC_10BIT, \ .base = 0x1a00, .len = 0x100,}, \ .format_list = plane_formats_yuv, \ .num_formats = ARRAY_SIZE(plane_formats_yuv), \ @@ -286,91 +310,64 @@ static const uint32_t wb2_formats[] = { .rotation_cfg = rot_cfg, \ } -#define _DMA_SBLK(sdma_pri) \ +#define _VIG_SBLK_NOSCALE() \ + { \ + .maxdwnscale = SSPP_UNITY_SCALE, \ + .maxupscale = SSPP_UNITY_SCALE, \ + .format_list = plane_formats_yuv, \ + .num_formats = ARRAY_SIZE(plane_formats_yuv), \ + .virt_format_list = plane_formats, \ + .virt_num_formats = ARRAY_SIZE(plane_formats), \ + } + +#define _DMA_SBLK() \ { \ .maxdwnscale = SSPP_UNITY_SCALE, \ .maxupscale = SSPP_UNITY_SCALE, \ - .smart_dma_priority = sdma_pri, \ .format_list = plane_formats, \ .num_formats = ARRAY_SIZE(plane_formats), \ .virt_format_list = plane_formats, \ .virt_num_formats = ARRAY_SIZE(plane_formats), \ } -static const struct dpu_sspp_sub_blks msm8998_vig_sblk_0 = - _VIG_SBLK(0, DPU_SSPP_SCALER_QSEED3); -static const struct dpu_sspp_sub_blks msm8998_vig_sblk_1 = - _VIG_SBLK(0, DPU_SSPP_SCALER_QSEED3); -static const struct dpu_sspp_sub_blks msm8998_vig_sblk_2 = - _VIG_SBLK(0, DPU_SSPP_SCALER_QSEED3); -static const struct dpu_sspp_sub_blks msm8998_vig_sblk_3 = - _VIG_SBLK(0, DPU_SSPP_SCALER_QSEED3); - static const struct dpu_rotation_cfg dpu_rot_sc7280_cfg_v2 = { .rot_maxheight = 1088, .rot_num_formats = ARRAY_SIZE(rotation_v2_formats), .rot_format_list = rotation_v2_formats, }; -static const struct dpu_sspp_sub_blks sdm845_vig_sblk_0 = - _VIG_SBLK(5, DPU_SSPP_SCALER_QSEED3); -static const struct dpu_sspp_sub_blks sdm845_vig_sblk_1 = - _VIG_SBLK(6, DPU_SSPP_SCALER_QSEED3); -static const struct dpu_sspp_sub_blks sdm845_vig_sblk_2 = - _VIG_SBLK(7, DPU_SSPP_SCALER_QSEED3); -static const struct dpu_sspp_sub_blks sdm845_vig_sblk_3 = - _VIG_SBLK(8, DPU_SSPP_SCALER_QSEED3); - -static const struct dpu_sspp_sub_blks sdm845_dma_sblk_0 = _DMA_SBLK(1); -static const struct dpu_sspp_sub_blks sdm845_dma_sblk_1 = _DMA_SBLK(2); -static const struct dpu_sspp_sub_blks sdm845_dma_sblk_2 = _DMA_SBLK(3); -static const struct dpu_sspp_sub_blks sdm845_dma_sblk_3 = _DMA_SBLK(4); - -static const struct dpu_sspp_sub_blks sc7180_vig_sblk_0 = - _VIG_SBLK(4, DPU_SSPP_SCALER_QSEED4); - -static const struct dpu_sspp_sub_blks sc7280_vig_sblk_0 = - _VIG_SBLK_ROT(4, DPU_SSPP_SCALER_QSEED4, &dpu_rot_sc7280_cfg_v2); - -static const struct dpu_sspp_sub_blks sm6115_vig_sblk_0 = - _VIG_SBLK(2, DPU_SSPP_SCALER_QSEED4); - -static const struct dpu_sspp_sub_blks sm6125_vig_sblk_0 = - _VIG_SBLK(3, DPU_SSPP_SCALER_QSEED3LITE); - -static const struct dpu_sspp_sub_blks sm8250_vig_sblk_0 = - _VIG_SBLK(5, DPU_SSPP_SCALER_QSEED4); -static const struct dpu_sspp_sub_blks sm8250_vig_sblk_1 = - _VIG_SBLK(6, DPU_SSPP_SCALER_QSEED4); -static const struct dpu_sspp_sub_blks sm8250_vig_sblk_2 = - _VIG_SBLK(7, DPU_SSPP_SCALER_QSEED4); -static const struct dpu_sspp_sub_blks sm8250_vig_sblk_3 = - _VIG_SBLK(8, DPU_SSPP_SCALER_QSEED4); - -static const struct dpu_sspp_sub_blks sm8550_vig_sblk_0 = - _VIG_SBLK(7, DPU_SSPP_SCALER_QSEED4); -static const struct dpu_sspp_sub_blks sm8550_vig_sblk_1 = - _VIG_SBLK(8, DPU_SSPP_SCALER_QSEED4); -static const struct dpu_sspp_sub_blks sm8550_vig_sblk_2 = - _VIG_SBLK(9, DPU_SSPP_SCALER_QSEED4); -static const struct dpu_sspp_sub_blks sm8550_vig_sblk_3 = - _VIG_SBLK(10, DPU_SSPP_SCALER_QSEED4); -static const struct dpu_sspp_sub_blks sm8550_dma_sblk_4 = _DMA_SBLK(5); -static const struct dpu_sspp_sub_blks sm8550_dma_sblk_5 = _DMA_SBLK(6); - -#define _VIG_SBLK_NOSCALE(sdma_pri) \ - { \ - .maxdwnscale = SSPP_UNITY_SCALE, \ - .maxupscale = SSPP_UNITY_SCALE, \ - .smart_dma_priority = sdma_pri, \ - .format_list = plane_formats_yuv, \ - .num_formats = ARRAY_SIZE(plane_formats_yuv), \ - .virt_format_list = plane_formats, \ - .virt_num_formats = ARRAY_SIZE(plane_formats), \ - } +static const struct dpu_sspp_sub_blks dpu_vig_sblk_noscale = + _VIG_SBLK_NOSCALE(); + +static const struct dpu_sspp_sub_blks dpu_vig_sblk_qseed3_1_2 = + _VIG_SBLK(SSPP_SCALER_VER(1, 2)); + +static const struct dpu_sspp_sub_blks dpu_vig_sblk_qseed3_1_3 = + _VIG_SBLK(SSPP_SCALER_VER(1, 3)); + +static const struct dpu_sspp_sub_blks dpu_vig_sblk_qseed3_1_4 = + _VIG_SBLK(SSPP_SCALER_VER(1, 4)); + +static const struct dpu_sspp_sub_blks dpu_vig_sblk_qseed3_2_4 = + _VIG_SBLK(SSPP_SCALER_VER(2, 4)); + +static const struct dpu_sspp_sub_blks dpu_vig_sblk_qseed3_3_0 = + _VIG_SBLK(SSPP_SCALER_VER(3, 0)); + +static const struct dpu_sspp_sub_blks dpu_vig_sblk_qseed3_3_0_rot_v2 = + _VIG_SBLK_ROT(SSPP_SCALER_VER(3, 0), + &dpu_rot_sc7280_cfg_v2); + +static const struct dpu_sspp_sub_blks dpu_vig_sblk_qseed3_3_1 = + _VIG_SBLK(SSPP_SCALER_VER(3, 1)); + +static const struct dpu_sspp_sub_blks dpu_vig_sblk_qseed3_3_2 = + _VIG_SBLK(SSPP_SCALER_VER(3, 2)); + +static const struct dpu_sspp_sub_blks dpu_vig_sblk_qseed3_3_3 = + _VIG_SBLK(SSPP_SCALER_VER(3, 3)); -static const struct dpu_sspp_sub_blks qcm2290_vig_sblk_0 = _VIG_SBLK_NOSCALE(2); -static const struct dpu_sspp_sub_blks qcm2290_dma_sblk_0 = _DMA_SBLK(1); +static const struct dpu_sspp_sub_blks dpu_dma_sblk = _DMA_SBLK(); /************************************************************* * MIXER sub blocks config @@ -422,12 +419,12 @@ static const struct dpu_lm_sub_blks qcm2290_lm_sblk = { * DSPP sub blocks config *************************************************************/ static const struct dpu_dspp_sub_blks msm8998_dspp_sblk = { - .pcc = {.name = "pcc", .id = DPU_DSPP_PCC, .base = 0x1700, + .pcc = {.name = "pcc", .base = 0x1700, .len = 0x90, .version = 0x10007}, }; static const struct dpu_dspp_sub_blks sdm845_dspp_sblk = { - .pcc = {.name = "pcc", .id = DPU_DSPP_PCC, .base = 0x1700, + .pcc = {.name = "pcc", .base = 0x1700, .len = 0x90, .version = 0x40000}, }; @@ -435,19 +432,19 @@ static const struct dpu_dspp_sub_blks sdm845_dspp_sblk = { * PINGPONG sub blocks config *************************************************************/ static const struct dpu_pingpong_sub_blks sdm845_pp_sblk_te = { - .te2 = {.name = "te2", .id = DPU_PINGPONG_TE2, .base = 0x2000, .len = 0x0, + .te2 = {.name = "te2", .base = 0x2000, .len = 0x0, .version = 0x1}, - .dither = {.name = "dither", .id = DPU_PINGPONG_DITHER, .base = 0x30e0, + .dither = {.name = "dither", .base = 0x30e0, .len = 0x20, .version = 0x10000}, }; static const struct dpu_pingpong_sub_blks sdm845_pp_sblk = { - .dither = {.name = "dither", .id = DPU_PINGPONG_DITHER, .base = 0x30e0, + .dither = {.name = "dither", .base = 0x30e0, .len = 0x20, .version = 0x10000}, }; static const struct dpu_pingpong_sub_blks sc7280_pp_sblk = { - .dither = {.name = "dither", .id = DPU_PINGPONG_DITHER, .base = 0xe0, + .dither = {.name = "dither", .base = 0xe0, .len = 0x20, .version = 0x20000}, }; @@ -464,6 +461,16 @@ static const struct dpu_dsc_sub_blks dsc_sblk_1 = { .ctl = {.name = "ctl", .base = 0xF80, .len = 0x10}, }; +/************************************************************* + * CDM block config + *************************************************************/ +static const struct dpu_cdm_cfg sc7280_cdm = { + .name = "cdm_0", + .id = CDM_0, + .len = 0x228, + .base = 0x79200, +}; + /************************************************************* * VBIF sub blocks config *************************************************************/ @@ -472,6 +479,7 @@ static const u32 msm8998_rt_pri_lvl[] = {1, 2, 2, 2}; static const u32 msm8998_nrt_pri_lvl[] = {1, 1, 1, 1}; static const u32 sdm845_rt_pri_lvl[] = {3, 3, 4, 4, 5, 5, 6, 6}; static const u32 sdm845_nrt_pri_lvl[] = {3, 3, 3, 3, 3, 3, 3, 3}; +static const u32 sm8650_rt_pri_lvl[] = {4, 4, 5, 5, 5, 5, 5, 6}; static const struct dpu_vbif_dynamic_ot_cfg msm8998_ot_rdwr_cfg[] = { { @@ -558,6 +566,26 @@ static const struct dpu_vbif_cfg sm8550_vbif[] = { }, }; +static const struct dpu_vbif_cfg sm8650_vbif[] = { + { + .name = "vbif_rt", .id = VBIF_RT, + .base = 0, .len = 0x1074, + .features = BIT(DPU_VBIF_QOS_REMAP), + .xin_halt_timeout = 0x4000, + .qos_rp_remap_size = 0x40, + .qos_rt_tbl = { + .npriority_lvl = ARRAY_SIZE(sm8650_rt_pri_lvl), + .priority_lvl = sm8650_rt_pri_lvl, + }, + .qos_nrt_tbl = { + .npriority_lvl = ARRAY_SIZE(sdm845_nrt_pri_lvl), + .priority_lvl = sdm845_nrt_pri_lvl, + }, + .memtype_count = 16, + .memtype = {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}, + }, +}; + /************************************************************* * PERF data config *************************************************************/ @@ -654,6 +682,7 @@ static const struct dpu_qos_lut_entry sc7180_qos_nrt[] = { #include "catalog/dpu_3_0_msm8998.h" #include "catalog/dpu_4_0_sdm845.h" +#include "catalog/dpu_4_1_sdm670.h" #include "catalog/dpu_5_0_sm8150.h" #include "catalog/dpu_5_1_sc8180x.h" @@ -673,3 +702,5 @@ static const struct dpu_qos_lut_entry sc7180_qos_nrt[] = { #include "catalog/dpu_8_1_sm8450.h" #include "catalog/dpu_9_0_sm8550.h" + +#include "catalog/dpu_10_0_sm8650.h" 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 df024e10d3a32b..ba82ef4560a6dd 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h @@ -51,9 +51,7 @@ enum { /** * SSPP sub-blocks/features * @DPU_SSPP_SCALER_QSEED2, QSEED2 algorithm support - * @DPU_SSPP_SCALER_QSEED3, QSEED3 alogorithm support - * @DPU_SSPP_SCALER_QSEED3LITE, QSEED3 Lite alogorithm support - * @DPU_SSPP_SCALER_QSEED4, QSEED4 algorithm support + * @DPU_SSPP_SCALER_QSEED3_COMPATIBLE, QSEED3-compatible alogorithm support (includes QSEED3, QSEED3LITE and QSEED4) * @DPU_SSPP_SCALER_RGB, RGB Scaler, supported by RGB pipes * @DPU_SSPP_CSC, Support of Color space converion * @DPU_SSPP_CSC_10BIT, Support of 10-bit Color space conversion @@ -71,9 +69,7 @@ enum { */ enum { DPU_SSPP_SCALER_QSEED2 = 0x1, - DPU_SSPP_SCALER_QSEED3, - DPU_SSPP_SCALER_QSEED3LITE, - DPU_SSPP_SCALER_QSEED4, + DPU_SSPP_SCALER_QSEED3_COMPATIBLE, DPU_SSPP_SCALER_RGB, DPU_SSPP_CSC, DPU_SSPP_CSC_10BIT, @@ -248,50 +244,51 @@ enum { u32 len; \ unsigned long features -/** - * MACRO DPU_HW_SUBBLK_INFO - information of HW sub-block inside DPU - * @name: string name for debug purposes - * @id: enum identifying this sub-block - * @base: offset of this sub-block relative to the block - * offset - * @len register block length of this sub-block - */ -#define DPU_HW_SUBBLK_INFO \ - char name[DPU_HW_BLK_NAME_LEN]; \ - u32 id; \ - u32 base; \ - u32 len - /** * struct dpu_scaler_blk: Scaler information - * @info: HW register and features supported by this sub-blk - * @version: qseed block revision + * @name: string name for debug purposes + * @base: offset of this sub-block relative to the block offset + * @len: register block length of this sub-block + * @version: qseed block revision, on QSEED3+ platforms this is the value of + * scaler_blk.base + QSEED3_HW_VERSION registers. */ struct dpu_scaler_blk { - DPU_HW_SUBBLK_INFO; + char name[DPU_HW_BLK_NAME_LEN]; + u32 base; + u32 len; u32 version; }; struct dpu_csc_blk { - DPU_HW_SUBBLK_INFO; + char name[DPU_HW_BLK_NAME_LEN]; + u32 base; + u32 len; }; /** * struct dpu_pp_blk : Pixel processing sub-blk information - * @info: HW register and features supported by this sub-blk + * @name: string name for debug purposes + * @base: offset of this sub-block relative to the block offset + * @len: register block length of this sub-block * @version: HW Algorithm version */ struct dpu_pp_blk { - DPU_HW_SUBBLK_INFO; + char name[DPU_HW_BLK_NAME_LEN]; + u32 base; + u32 len; u32 version; }; /** * struct dpu_dsc_blk - DSC Encoder sub-blk information - * @info: HW register and features supported by this sub-blk + * @name: string name for debug purposes + * @base: offset of this sub-block relative to the block offset + * @len: register block length of this sub-block */ struct dpu_dsc_blk { - DPU_HW_SUBBLK_INFO; + char name[DPU_HW_BLK_NAME_LEN]; + u32 base; + u32 len; }; /** @@ -341,7 +338,6 @@ struct dpu_rotation_cfg { * @max_mixer_width max layer mixer line width support. * @max_mixer_blendstages max layer mixer blend stages or * supported z order - * @qseed_type qseed2 or qseed3 support. * @has_src_split source split feature status * @has_dim_layer dim layer feature status * @has_idle_pc indicate if idle power collapse feature is supported @@ -354,7 +350,6 @@ struct dpu_rotation_cfg { struct dpu_caps { u32 max_mixer_width; u32 max_mixer_blendstages; - u32 qseed_type; bool has_src_split; bool has_dim_layer; bool has_idle_pc; @@ -371,7 +366,6 @@ struct dpu_caps { * common: Pointer to common configurations shared by sub blocks * @maxdwnscale: max downscale ratio supported(without DECIMATION) * @maxupscale: maxupscale ratio supported - * @smart_dma_priority: hw priority of rect1 of multirect pipe * @max_per_pipe_bw: maximum allowable bandwidth of this pipe in kBps * @qseed_ver: qseed version * @scaler_blk: @@ -385,7 +379,6 @@ struct dpu_caps { struct dpu_sspp_sub_blks { u32 maxdwnscale; u32 maxupscale; - u32 smart_dma_priority; u32 max_per_pipe_bw; u32 qseed_ver; struct dpu_scaler_blk scaler_blk; @@ -689,6 +682,17 @@ struct dpu_vbif_cfg { u32 memtype[MAX_XIN_COUNT]; }; +/** + * struct dpu_cdm_cfg - information of chroma down blocks + * @name string name for debug purposes + * @id enum identifying this block + * @base register offset of this block + * @features bit mask identifying sub-blocks/features + */ +struct dpu_cdm_cfg { + DPU_HW_BLK_INFO; +}; + /** * Define CDP use cases * @DPU_PERF_CDP_UDAGE_RT: real-time use cases @@ -812,6 +816,8 @@ struct dpu_mdss_cfg { u32 wb_count; const struct dpu_wb_cfg *wb; + const struct dpu_cdm_cfg *cdm; + u32 ad_count; u32 dspp_count; @@ -827,6 +833,7 @@ struct dpu_mdss_cfg { extern const struct dpu_mdss_cfg dpu_msm8998_cfg; extern const struct dpu_mdss_cfg dpu_sdm845_cfg; +extern const struct dpu_mdss_cfg dpu_sdm670_cfg; extern const struct dpu_mdss_cfg dpu_sm8150_cfg; extern const struct dpu_mdss_cfg dpu_sc8180x_cfg; extern const struct dpu_mdss_cfg dpu_sm8250_cfg; @@ -841,5 +848,6 @@ extern const struct dpu_mdss_cfg dpu_sc7280_cfg; extern const struct dpu_mdss_cfg dpu_sc8280xp_cfg; extern const struct dpu_mdss_cfg dpu_sm8450_cfg; extern const struct dpu_mdss_cfg dpu_sm8550_cfg; +extern const struct dpu_mdss_cfg dpu_sm8650_cfg; #endif /* _DPU_HW_CATALOG_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c new file mode 100644 index 00000000000000..e9cdc7934a4996 --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.c @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023, The Linux Foundation. All rights reserved. + */ + +#include + +#include + +#include "dpu_hw_mdss.h" +#include "dpu_hw_util.h" +#include "dpu_hw_catalog.h" +#include "dpu_hw_cdm.h" +#include "dpu_kms.h" + +#define CDM_CSC_10_OPMODE 0x000 +#define CDM_CSC_10_BASE 0x004 + +#define CDM_CDWN2_OP_MODE 0x100 +#define CDM_CDWN2_CLAMP_OUT 0x104 +#define CDM_CDWN2_PARAMS_3D_0 0x108 +#define CDM_CDWN2_PARAMS_3D_1 0x10C +#define CDM_CDWN2_COEFF_COSITE_H_0 0x110 +#define CDM_CDWN2_COEFF_COSITE_H_1 0x114 +#define CDM_CDWN2_COEFF_COSITE_H_2 0x118 +#define CDM_CDWN2_COEFF_OFFSITE_H_0 0x11C +#define CDM_CDWN2_COEFF_OFFSITE_H_1 0x120 +#define CDM_CDWN2_COEFF_OFFSITE_H_2 0x124 +#define CDM_CDWN2_COEFF_COSITE_V 0x128 +#define CDM_CDWN2_COEFF_OFFSITE_V 0x12C +#define CDM_CDWN2_OUT_SIZE 0x130 + +#define CDM_HDMI_PACK_OP_MODE 0x200 +#define CDM_CSC_10_MATRIX_COEFF_0 0x004 + +#define CDM_MUX 0x224 + +/* CDM CDWN2 sub-block bit definitions */ +#define CDM_CDWN2_OP_MODE_EN BIT(0) +#define CDM_CDWN2_OP_MODE_ENABLE_H BIT(1) +#define CDM_CDWN2_OP_MODE_ENABLE_V BIT(2) +#define CDM_CDWN2_OP_MODE_BITS_OUT_8BIT BIT(7) +#define CDM_CDWN2_V_PIXEL_METHOD_MASK GENMASK(6, 5) +#define CDM_CDWN2_H_PIXEL_METHOD_MASK GENMASK(4, 3) + +/* CDM CSC10 sub-block bit definitions */ +#define CDM_CSC10_OP_MODE_EN BIT(0) +#define CDM_CSC10_OP_MODE_SRC_FMT_YUV BIT(1) +#define CDM_CSC10_OP_MODE_DST_FMT_YUV BIT(2) + +/* CDM HDMI pack sub-block bit definitions */ +#define CDM_HDMI_PACK_OP_MODE_EN BIT(0) + +/* + * Horizontal coefficients for cosite chroma downscale + * s13 representation of coefficients + */ +static u32 cosite_h_coeff[] = {0x00000016, 0x000001cc, 0x0100009e}; + +/* + * Horizontal coefficients for offsite chroma downscale + */ +static u32 offsite_h_coeff[] = {0x000b0005, 0x01db01eb, 0x00e40046}; + +/* + * Vertical coefficients for cosite chroma downscale + */ +static u32 cosite_v_coeff[] = {0x00080004}; +/* + * Vertical coefficients for offsite chroma downscale + */ +static u32 offsite_v_coeff[] = {0x00060002}; + +static int dpu_hw_cdm_setup_cdwn(struct dpu_hw_cdm *ctx, struct dpu_hw_cdm_cfg *cfg) +{ + struct dpu_hw_blk_reg_map *c = &ctx->hw; + u32 opmode; + u32 out_size; + + switch (cfg->h_cdwn_type) { + case CDM_CDWN_DISABLE: + opmode = 0; + break; + case CDM_CDWN_PIXEL_DROP: + opmode = CDM_CDWN2_OP_MODE_ENABLE_H | + FIELD_PREP(CDM_CDWN2_H_PIXEL_METHOD_MASK, + CDM_CDWN2_METHOD_PIXEL_DROP); + break; + case CDM_CDWN_AVG: + opmode = CDM_CDWN2_OP_MODE_ENABLE_H | + FIELD_PREP(CDM_CDWN2_H_PIXEL_METHOD_MASK, + CDM_CDWN2_METHOD_AVG); + break; + case CDM_CDWN_COSITE: + opmode = CDM_CDWN2_OP_MODE_ENABLE_H | + FIELD_PREP(CDM_CDWN2_H_PIXEL_METHOD_MASK, + CDM_CDWN2_METHOD_COSITE); + DPU_REG_WRITE(c, CDM_CDWN2_COEFF_COSITE_H_0, + cosite_h_coeff[0]); + DPU_REG_WRITE(c, CDM_CDWN2_COEFF_COSITE_H_1, + cosite_h_coeff[1]); + DPU_REG_WRITE(c, CDM_CDWN2_COEFF_COSITE_H_2, + cosite_h_coeff[2]); + break; + case CDM_CDWN_OFFSITE: + opmode = CDM_CDWN2_OP_MODE_ENABLE_H | + FIELD_PREP(CDM_CDWN2_H_PIXEL_METHOD_MASK, CDM_CDWN2_METHOD_OFFSITE); + DPU_REG_WRITE(c, CDM_CDWN2_COEFF_OFFSITE_H_0, + offsite_h_coeff[0]); + DPU_REG_WRITE(c, CDM_CDWN2_COEFF_OFFSITE_H_1, + offsite_h_coeff[1]); + DPU_REG_WRITE(c, CDM_CDWN2_COEFF_OFFSITE_H_2, + offsite_h_coeff[2]); + break; + default: + DPU_ERROR("%s invalid horz down sampling type\n", __func__); + return -EINVAL; + } + + switch (cfg->v_cdwn_type) { + case CDM_CDWN_DISABLE: + /* if its only Horizontal downsample, we dont need to do anything here */ + break; + case CDM_CDWN_PIXEL_DROP: + opmode |= CDM_CDWN2_OP_MODE_ENABLE_V | + FIELD_PREP(CDM_CDWN2_V_PIXEL_METHOD_MASK, + CDM_CDWN2_METHOD_PIXEL_DROP); + break; + case CDM_CDWN_AVG: + opmode |= CDM_CDWN2_OP_MODE_ENABLE_V | + FIELD_PREP(CDM_CDWN2_V_PIXEL_METHOD_MASK, + CDM_CDWN2_METHOD_AVG); + break; + case CDM_CDWN_COSITE: + opmode |= CDM_CDWN2_OP_MODE_ENABLE_V | + FIELD_PREP(CDM_CDWN2_V_PIXEL_METHOD_MASK, + CDM_CDWN2_METHOD_COSITE); + DPU_REG_WRITE(c, + CDM_CDWN2_COEFF_COSITE_V, + cosite_v_coeff[0]); + break; + case CDM_CDWN_OFFSITE: + opmode |= CDM_CDWN2_OP_MODE_ENABLE_V | + FIELD_PREP(CDM_CDWN2_V_PIXEL_METHOD_MASK, + CDM_CDWN2_METHOD_OFFSITE); + DPU_REG_WRITE(c, + CDM_CDWN2_COEFF_OFFSITE_V, + offsite_v_coeff[0]); + break; + default: + return -EINVAL; + } + + if (cfg->output_bit_depth != CDM_CDWN_OUTPUT_10BIT) + opmode |= CDM_CDWN2_OP_MODE_BITS_OUT_8BIT; + + if (cfg->v_cdwn_type || cfg->h_cdwn_type) + opmode |= CDM_CDWN2_OP_MODE_EN; /* EN CDWN module */ + else + opmode &= ~CDM_CDWN2_OP_MODE_EN; + + out_size = (cfg->output_width & 0xFFFF) | ((cfg->output_height & 0xFFFF) << 16); + DPU_REG_WRITE(c, CDM_CDWN2_OUT_SIZE, out_size); + DPU_REG_WRITE(c, CDM_CDWN2_OP_MODE, opmode); + DPU_REG_WRITE(c, CDM_CDWN2_CLAMP_OUT, ((0x3FF << 16) | 0x0)); + + return 0; +} + +static int dpu_hw_cdm_enable(struct dpu_hw_cdm *ctx, struct dpu_hw_cdm_cfg *cdm) +{ + struct dpu_hw_blk_reg_map *c = &ctx->hw; + const struct dpu_format *fmt; + u32 opmode = 0; + u32 csc = 0; + + if (!ctx || !cdm) + return -EINVAL; + + fmt = cdm->output_fmt; + + if (!DPU_FORMAT_IS_YUV(fmt)) + return -EINVAL; + + dpu_hw_csc_setup(&ctx->hw, CDM_CSC_10_MATRIX_COEFF_0, cdm->csc_cfg, true); + dpu_hw_cdm_setup_cdwn(ctx, cdm); + + if (cdm->output_type == CDM_CDWN_OUTPUT_HDMI) { + if (fmt->chroma_sample != DPU_CHROMA_H1V2) + return -EINVAL; /*unsupported format */ + opmode = CDM_HDMI_PACK_OP_MODE_EN; + opmode |= (fmt->chroma_sample << 1); + } + + csc |= CDM_CSC10_OP_MODE_DST_FMT_YUV; + csc &= ~CDM_CSC10_OP_MODE_SRC_FMT_YUV; + csc |= CDM_CSC10_OP_MODE_EN; + + if (ctx && ctx->ops.bind_pingpong_blk) + ctx->ops.bind_pingpong_blk(ctx, cdm->pp_id); + + DPU_REG_WRITE(c, CDM_CSC_10_OPMODE, csc); + DPU_REG_WRITE(c, CDM_HDMI_PACK_OP_MODE, opmode); + return 0; +} + +static void dpu_hw_cdm_bind_pingpong_blk(struct dpu_hw_cdm *ctx, const enum dpu_pingpong pp) +{ + struct dpu_hw_blk_reg_map *c; + int mux_cfg; + + c = &ctx->hw; + + mux_cfg = DPU_REG_READ(c, CDM_MUX); + mux_cfg &= ~0xf; + + if (pp) + mux_cfg |= (pp - PINGPONG_0) & 0x7; + else + mux_cfg |= 0xf; + + DPU_REG_WRITE(c, CDM_MUX, mux_cfg); +} + +struct dpu_hw_cdm *dpu_hw_cdm_init(struct drm_device *dev, + const struct dpu_cdm_cfg *cfg, void __iomem *addr, + const struct dpu_mdss_version *mdss_rev) +{ + struct dpu_hw_cdm *c; + + c = drmm_kzalloc(dev, sizeof(*c), GFP_KERNEL); + if (!c) + return ERR_PTR(-ENOMEM); + + c->hw.blk_addr = addr + cfg->base; + c->hw.log_mask = DPU_DBG_MASK_CDM; + + /* Assign ops */ + c->idx = cfg->id; + c->caps = cfg; + + c->ops.enable = dpu_hw_cdm_enable; + if (mdss_rev->core_major_ver >= 5) + c->ops.bind_pingpong_blk = dpu_hw_cdm_bind_pingpong_blk; + + return c; +} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.h new file mode 100644 index 00000000000000..348424df87c66a --- /dev/null +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.h @@ -0,0 +1,142 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2023, The Linux Foundation. All rights reserved. + */ + +#ifndef _DPU_HW_CDM_H +#define _DPU_HW_CDM_H + +#include "dpu_hw_mdss.h" +#include "dpu_hw_top.h" + +struct dpu_hw_cdm; + +/** + * struct dpu_hw_cdm_cfg : current configuration of CDM block + * + * @output_width: output ROI width of CDM block + * @output_height: output ROI height of CDM block + * @output_bit_depth: output bit-depth of CDM block + * @h_cdwn_type: downsample type used for horizontal pixels + * @v_cdwn_type: downsample type used for vertical pixels + * @output_fmt: handle to dpu_format of CDM block + * @csc_cfg: handle to CSC matrix programmed for CDM block + * @output_type: interface to which CDM is paired (HDMI/WB) + * @pp_id: ping-pong block to which CDM is bound to + */ +struct dpu_hw_cdm_cfg { + u32 output_width; + u32 output_height; + u32 output_bit_depth; + u32 h_cdwn_type; + u32 v_cdwn_type; + const struct dpu_format *output_fmt; + const struct dpu_csc_cfg *csc_cfg; + u32 output_type; + int pp_id; +}; + +/* + * These values are used indicate which type of downsample is used + * in the horizontal/vertical direction for the CDM block. + */ +enum dpu_hw_cdwn_type { + CDM_CDWN_DISABLE, + CDM_CDWN_PIXEL_DROP, + CDM_CDWN_AVG, + CDM_CDWN_COSITE, + CDM_CDWN_OFFSITE, +}; + +/* + * CDM block can be paired with WB or HDMI block. These values match + * the input with which the CDM block is paired. + */ +enum dpu_hw_cdwn_output_type { + CDM_CDWN_OUTPUT_HDMI, + CDM_CDWN_OUTPUT_WB, +}; + +/* + * CDM block can give an 8-bit or 10-bit output. These values + * are used to indicate the output bit depth of CDM block + */ +enum dpu_hw_cdwn_output_bit_depth { + CDM_CDWN_OUTPUT_8BIT, + CDM_CDWN_OUTPUT_10BIT, +}; + +/* + * CDM block can downsample using different methods. These values + * are used to indicate the downsample method which can be used + * either in the horizontal or vertical direction. + */ +enum dpu_hw_cdwn_op_mode_method_h_v { + CDM_CDWN2_METHOD_PIXEL_DROP, + CDM_CDWN2_METHOD_AVG, + CDM_CDWN2_METHOD_COSITE, + CDM_CDWN2_METHOD_OFFSITE +}; + +/** + * struct dpu_hw_cdm_ops : Interface to the chroma down Hw driver functions + * Assumption is these functions will be called after + * clocks are enabled + * @enable: Enables the output to interface and programs the + * output packer + * @bind_pingpong_blk: enable/disable the connection with pingpong which + * will feed pixels to this cdm + */ +struct dpu_hw_cdm_ops { + /** + * Enable the CDM module + * @cdm Pointer to chroma down context + */ + int (*enable)(struct dpu_hw_cdm *cdm, struct dpu_hw_cdm_cfg *cfg); + + /** + * Enable/disable the connection with pingpong + * @cdm Pointer to chroma down context + * @pp pingpong block id. + */ + void (*bind_pingpong_blk)(struct dpu_hw_cdm *cdm, const enum dpu_pingpong pp); +}; + +/** + * struct dpu_hw_cdm - cdm description + * @base: Hardware block base structure + * @hw: Block hardware details + * @idx: CDM index + * @caps: Pointer to cdm_cfg + * @ops: handle to operations possible for this CDM + */ +struct dpu_hw_cdm { + struct dpu_hw_blk base; + struct dpu_hw_blk_reg_map hw; + + /* chroma down */ + const struct dpu_cdm_cfg *caps; + enum dpu_cdm idx; + + /* ops */ + struct dpu_hw_cdm_ops ops; +}; + +/** + * dpu_hw_cdm_init - initializes the cdm hw driver object. + * should be called once before accessing every cdm. + * @dev: DRM device handle + * @cdm: CDM catalog entry for which driver object is required + * @addr : mapped register io address of MDSS + * @mdss_rev: mdss hw core revision + */ +struct dpu_hw_cdm *dpu_hw_cdm_init(struct drm_device *dev, + const struct dpu_cdm_cfg *cdm, void __iomem *addr, + const struct dpu_mdss_version *mdss_rev); + +static inline struct dpu_hw_cdm *to_dpu_hw_cdm(struct dpu_hw_blk *hw) +{ + return container_of(hw, struct dpu_hw_cdm, base); +} + +#endif /*_DPU_HW_CDM_H */ 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 86182c73460603..e76565c3e6a439 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c @@ -4,6 +4,9 @@ */ #include + +#include + #include "dpu_hwio.h" #include "dpu_hw_ctl.h" #include "dpu_kms.h" @@ -29,11 +32,13 @@ #define CTL_DSC_ACTIVE 0x0E8 #define CTL_WB_ACTIVE 0x0EC #define CTL_INTF_ACTIVE 0x0F4 +#define CTL_CDM_ACTIVE 0x0F8 #define CTL_FETCH_PIPE_ACTIVE 0x0FC #define CTL_MERGE_3D_FLUSH 0x100 #define CTL_DSC_FLUSH 0x104 #define CTL_WB_FLUSH 0x108 #define CTL_INTF_FLUSH 0x110 +#define CTL_CDM_FLUSH 0x114 #define CTL_INTF_MASTER 0x134 #define CTL_DSPP_n_FLUSH(n) ((0x13C) + ((n) * 4)) @@ -43,6 +48,7 @@ #define DPU_REG_RESET_TIMEOUT_US 2000 #define MERGE_3D_IDX 23 #define DSC_IDX 22 +#define CDM_IDX 26 #define INTF_IDX 31 #define WB_IDX 16 #define DSPP_IDX 29 /* From DPU hw rev 7.x.x */ @@ -104,6 +110,7 @@ static inline void dpu_hw_ctl_clear_pending_flush(struct dpu_hw_ctl *ctx) ctx->pending_wb_flush_mask = 0; ctx->pending_merge_3d_flush_mask = 0; ctx->pending_dsc_flush_mask = 0; + ctx->pending_cdm_flush_mask = 0; memset(ctx->pending_dspp_flush_mask, 0, sizeof(ctx->pending_dspp_flush_mask)); @@ -148,6 +155,10 @@ static inline void dpu_hw_ctl_trigger_flush_v1(struct dpu_hw_ctl *ctx) DPU_REG_WRITE(&ctx->hw, CTL_DSC_FLUSH, ctx->pending_dsc_flush_mask); + if (ctx->pending_flush_mask & BIT(CDM_IDX)) + DPU_REG_WRITE(&ctx->hw, CTL_CDM_FLUSH, + ctx->pending_cdm_flush_mask); + DPU_REG_WRITE(&ctx->hw, CTL_FLUSH, ctx->pending_flush_mask); } @@ -279,6 +290,13 @@ static void dpu_hw_ctl_update_pending_flush_wb(struct dpu_hw_ctl *ctx, } } +static void dpu_hw_ctl_update_pending_flush_cdm(struct dpu_hw_ctl *ctx, enum dpu_cdm cdm_num) +{ + /* update pending flush only if CDM_0 is flushed */ + if (cdm_num == CDM_0) + ctx->pending_flush_mask |= BIT(CDM_IDX); +} + static void dpu_hw_ctl_update_pending_flush_wb_v1(struct dpu_hw_ctl *ctx, enum dpu_wb wb) { @@ -307,6 +325,12 @@ static void dpu_hw_ctl_update_pending_flush_dsc_v1(struct dpu_hw_ctl *ctx, ctx->pending_flush_mask |= BIT(DSC_IDX); } +static void dpu_hw_ctl_update_pending_flush_cdm_v1(struct dpu_hw_ctl *ctx, enum dpu_cdm cdm_num) +{ + ctx->pending_cdm_flush_mask |= BIT(cdm_num - CDM_0); + ctx->pending_flush_mask |= BIT(CDM_IDX); +} + static void dpu_hw_ctl_update_pending_flush_dspp(struct dpu_hw_ctl *ctx, enum dpu_dspp dspp, u32 dspp_sub_blk) { @@ -540,6 +564,9 @@ static void dpu_hw_ctl_intf_cfg_v1(struct dpu_hw_ctl *ctx, if (cfg->dsc) DPU_REG_WRITE(c, CTL_DSC_ACTIVE, cfg->dsc); + + if (cfg->cdm) + DPU_REG_WRITE(c, CTL_CDM_ACTIVE, cfg->cdm); } static void dpu_hw_ctl_intf_cfg(struct dpu_hw_ctl *ctx, @@ -583,6 +610,7 @@ static void dpu_hw_ctl_reset_intf_cfg_v1(struct dpu_hw_ctl *ctx, u32 wb_active = 0; u32 merge3d_active = 0; u32 dsc_active; + u32 cdm_active; /* * This API resets each portion of the CTL path namely, @@ -618,6 +646,12 @@ static void dpu_hw_ctl_reset_intf_cfg_v1(struct dpu_hw_ctl *ctx, dsc_active &= ~cfg->dsc; DPU_REG_WRITE(c, CTL_DSC_ACTIVE, dsc_active); } + + if (cfg->cdm) { + cdm_active = DPU_REG_READ(c, CTL_CDM_ACTIVE); + cdm_active &= ~cfg->cdm; + DPU_REG_WRITE(c, CTL_CDM_ACTIVE, cdm_active); + } } static void dpu_hw_ctl_set_fetch_pipe_active(struct dpu_hw_ctl *ctx, @@ -651,12 +685,14 @@ static void _setup_ctl_ops(struct dpu_hw_ctl_ops *ops, ops->update_pending_flush_wb = dpu_hw_ctl_update_pending_flush_wb_v1; ops->update_pending_flush_dsc = dpu_hw_ctl_update_pending_flush_dsc_v1; + ops->update_pending_flush_cdm = dpu_hw_ctl_update_pending_flush_cdm_v1; } else { ops->trigger_flush = dpu_hw_ctl_trigger_flush; ops->setup_intf_cfg = dpu_hw_ctl_intf_cfg; ops->update_pending_flush_intf = dpu_hw_ctl_update_pending_flush_intf; ops->update_pending_flush_wb = dpu_hw_ctl_update_pending_flush_wb; + ops->update_pending_flush_cdm = dpu_hw_ctl_update_pending_flush_cdm; } ops->clear_pending_flush = dpu_hw_ctl_clear_pending_flush; ops->update_pending_flush = dpu_hw_ctl_update_pending_flush; @@ -680,14 +716,15 @@ static void _setup_ctl_ops(struct dpu_hw_ctl_ops *ops, ops->set_active_pipes = dpu_hw_ctl_set_fetch_pipe_active; }; -struct dpu_hw_ctl *dpu_hw_ctl_init(const struct dpu_ctl_cfg *cfg, - void __iomem *addr, - u32 mixer_count, - const struct dpu_lm_cfg *mixer) +struct dpu_hw_ctl *dpu_hw_ctl_init(struct drm_device *dev, + const struct dpu_ctl_cfg *cfg, + void __iomem *addr, + u32 mixer_count, + const struct dpu_lm_cfg *mixer) { struct dpu_hw_ctl *c; - c = kzalloc(sizeof(*c), GFP_KERNEL); + c = drmm_kzalloc(dev, sizeof(*c), GFP_KERNEL); if (!c) return ERR_PTR(-ENOMEM); @@ -702,8 +739,3 @@ struct dpu_hw_ctl *dpu_hw_ctl_init(const struct dpu_ctl_cfg *cfg, return c; } - -void dpu_hw_ctl_destroy(struct dpu_hw_ctl *ctx) -{ - kfree(ctx); -} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h index 1c242298ff2ee0..ff85b5ee0acf83 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h @@ -39,6 +39,7 @@ struct dpu_hw_stage_cfg { * @mode_3d: 3d mux configuration * @merge_3d: 3d merge block used * @intf_mode_sel: Interface mode, cmd / vid + * @cdm: CDM block used * @stream_sel: Stream selection for multi-stream interfaces * @dsc: DSC BIT masks used */ @@ -48,6 +49,7 @@ struct dpu_hw_intf_cfg { enum dpu_3d_blend_mode mode_3d; enum dpu_merge_3d merge_3d; enum dpu_ctl_mode_sel intf_mode_sel; + enum dpu_cdm cdm; int stream_sel; unsigned int dsc; }; @@ -166,6 +168,14 @@ struct dpu_hw_ctl_ops { void (*update_pending_flush_dsc)(struct dpu_hw_ctl *ctx, enum dpu_dsc blk); + /** + * OR in the given flushbits to the cached pending_(cdm_)flush_mask + * No effect on hardware + * @ctx: ctl path ctx pointer + * @cdm_num: idx of cdm to be flushed + */ + void (*update_pending_flush_cdm)(struct dpu_hw_ctl *ctx, enum dpu_cdm cdm_num); + /** * Write the value of the pending_flush_mask to hardware * @ctx : ctl path ctx pointer @@ -239,6 +249,7 @@ struct dpu_hw_ctl_ops { * @pending_intf_flush_mask: pending INTF flush * @pending_wb_flush_mask: pending WB flush * @pending_dsc_flush_mask: pending DSC flush + * @pending_cdm_flush_mask: pending CDM flush * @ops: operation list */ struct dpu_hw_ctl { @@ -256,6 +267,7 @@ struct dpu_hw_ctl { u32 pending_merge_3d_flush_mask; u32 pending_dspp_flush_mask[DSPP_MAX - DSPP_0]; u32 pending_dsc_flush_mask; + u32 pending_cdm_flush_mask; /* ops */ struct dpu_hw_ctl_ops ops; @@ -274,20 +286,16 @@ static inline struct dpu_hw_ctl *to_dpu_hw_ctl(struct dpu_hw_blk *hw) /** * dpu_hw_ctl_init() - Initializes the ctl_path hw driver object. * Should be called before accessing any ctl_path register. + * @dev: Corresponding device for devres management * @cfg: ctl_path catalog entry for which driver object is required * @addr: mapped register io address of MDP * @mixer_count: Number of mixers in @mixer * @mixer: Pointer to an array of Layer Mixers defined in the catalog */ -struct dpu_hw_ctl *dpu_hw_ctl_init(const struct dpu_ctl_cfg *cfg, - void __iomem *addr, - u32 mixer_count, - const struct dpu_lm_cfg *mixer); - -/** - * dpu_hw_ctl_destroy(): Destroys ctl driver context - * should be called to free the context - */ -void dpu_hw_ctl_destroy(struct dpu_hw_ctl *ctx); +struct dpu_hw_ctl *dpu_hw_ctl_init(struct drm_device *dev, + const struct dpu_ctl_cfg *cfg, + void __iomem *addr, + u32 mixer_count, + const struct dpu_lm_cfg *mixer); #endif /*_DPU_HW_CTL_H */ 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 509dbaa51d8786..5e9aad1b2aa283 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.c @@ -3,6 +3,8 @@ * Copyright (c) 2020-2022, Linaro Limited */ +#include + #include #include "dpu_kms.h" @@ -188,12 +190,13 @@ static void _setup_dsc_ops(struct dpu_hw_dsc_ops *ops, ops->dsc_bind_pingpong_blk = dpu_hw_dsc_bind_pingpong_blk; }; -struct dpu_hw_dsc *dpu_hw_dsc_init(const struct dpu_dsc_cfg *cfg, +struct dpu_hw_dsc *dpu_hw_dsc_init(struct drm_device *dev, + const struct dpu_dsc_cfg *cfg, void __iomem *addr) { struct dpu_hw_dsc *c; - c = kzalloc(sizeof(*c), GFP_KERNEL); + c = drmm_kzalloc(dev, sizeof(*c), GFP_KERNEL); if (!c) return ERR_PTR(-ENOMEM); @@ -206,8 +209,3 @@ struct dpu_hw_dsc *dpu_hw_dsc_init(const struct dpu_dsc_cfg *cfg, return c; } - -void dpu_hw_dsc_destroy(struct dpu_hw_dsc *dsc) -{ - kfree(dsc); -} 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 d5b597ab8c5ca1..989c88d2449b6a 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h @@ -64,20 +64,24 @@ struct dpu_hw_dsc { /** * dpu_hw_dsc_init() - Initializes the DSC hw driver object. + * @dev: Corresponding device for devres management * @cfg: DSC catalog entry for which driver object is required * @addr: Mapped register io address of MDP * Return: Error code or allocated dpu_hw_dsc context */ -struct dpu_hw_dsc *dpu_hw_dsc_init(const struct dpu_dsc_cfg *cfg, - void __iomem *addr); +struct dpu_hw_dsc *dpu_hw_dsc_init(struct drm_device *dev, + const struct dpu_dsc_cfg *cfg, + void __iomem *addr); /** * dpu_hw_dsc_init_1_2() - initializes the v1.2 DSC hw driver object + * @dev: Corresponding device for devres management * @cfg: DSC catalog entry for which driver object is required * @addr: Mapped register io address of MDP * Returns: Error code or allocated dpu_hw_dsc context */ -struct dpu_hw_dsc *dpu_hw_dsc_init_1_2(const struct dpu_dsc_cfg *cfg, +struct dpu_hw_dsc *dpu_hw_dsc_init_1_2(struct drm_device *dev, + const struct dpu_dsc_cfg *cfg, void __iomem *addr); /** diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c index 24fe1d98eb86ae..ba193b0376fe82 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc_1_2.c @@ -4,6 +4,8 @@ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved */ +#include + #include #include "dpu_kms.h" @@ -367,12 +369,13 @@ static void _setup_dcs_ops_1_2(struct dpu_hw_dsc_ops *ops, ops->dsc_bind_pingpong_blk = dpu_hw_dsc_bind_pingpong_blk_1_2; } -struct dpu_hw_dsc *dpu_hw_dsc_init_1_2(const struct dpu_dsc_cfg *cfg, +struct dpu_hw_dsc *dpu_hw_dsc_init_1_2(struct drm_device *dev, + const struct dpu_dsc_cfg *cfg, void __iomem *addr) { struct dpu_hw_dsc *c; - c = kzalloc(sizeof(*c), GFP_KERNEL); + c = drmm_kzalloc(dev, sizeof(*c), GFP_KERNEL); if (!c) return ERR_PTR(-ENOMEM); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c index 9419b2209af88e..b1da88e2935f46 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.c @@ -2,6 +2,8 @@ /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. */ +#include + #include "dpu_hwio.h" #include "dpu_hw_catalog.h" #include "dpu_hw_lm.h" @@ -68,15 +70,16 @@ static void _setup_dspp_ops(struct dpu_hw_dspp *c, c->ops.setup_pcc = dpu_setup_dspp_pcc; } -struct dpu_hw_dspp *dpu_hw_dspp_init(const struct dpu_dspp_cfg *cfg, - void __iomem *addr) +struct dpu_hw_dspp *dpu_hw_dspp_init(struct drm_device *dev, + const struct dpu_dspp_cfg *cfg, + void __iomem *addr) { struct dpu_hw_dspp *c; if (!addr) return ERR_PTR(-EINVAL); - c = kzalloc(sizeof(*c), GFP_KERNEL); + c = drmm_kzalloc(dev, sizeof(*c), GFP_KERNEL); if (!c) return ERR_PTR(-ENOMEM); @@ -90,10 +93,3 @@ struct dpu_hw_dspp *dpu_hw_dspp_init(const struct dpu_dspp_cfg *cfg, return c; } - -void dpu_hw_dspp_destroy(struct dpu_hw_dspp *dspp) -{ - kfree(dspp); -} - - diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h index bea96568133011..3b435690b6ccbf 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h @@ -81,18 +81,14 @@ static inline struct dpu_hw_dspp *to_dpu_hw_dspp(struct dpu_hw_blk *hw) /** * dpu_hw_dspp_init() - Initializes the DSPP hw driver object. * should be called once before accessing every DSPP. + * @dev: Corresponding device for devres management * @cfg: DSPP catalog entry for which driver object is required * @addr: Mapped register io address of MDP * Return: pointer to structure or ERR_PTR */ -struct dpu_hw_dspp *dpu_hw_dspp_init(const struct dpu_dspp_cfg *cfg, - void __iomem *addr); - -/** - * dpu_hw_dspp_destroy(): Destroys DSPP driver context - * @dspp: Pointer to DSPP driver context - */ -void dpu_hw_dspp_destroy(struct dpu_hw_dspp *dspp); +struct dpu_hw_dspp *dpu_hw_dspp_init(struct drm_device *dev, + const struct dpu_dspp_cfg *cfg, + void __iomem *addr); #endif /*_DPU_HW_DSPP_H */ 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 088807db2c83d9..946dd0135dffcf 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.c @@ -6,6 +6,8 @@ #include #include +#include + #include "dpu_core_irq.h" #include "dpu_kms.h" #include "dpu_hw_interrupts.h" @@ -472,8 +474,9 @@ u32 dpu_core_irq_read(struct dpu_kms *dpu_kms, return intr_status; } -struct dpu_hw_intr *dpu_hw_intr_init(void __iomem *addr, - const struct dpu_mdss_cfg *m) +struct dpu_hw_intr *dpu_hw_intr_init(struct drm_device *dev, + void __iomem *addr, + const struct dpu_mdss_cfg *m) { struct dpu_hw_intr *intr; unsigned int i; @@ -481,7 +484,7 @@ struct dpu_hw_intr *dpu_hw_intr_init(void __iomem *addr, if (!addr || !m) return ERR_PTR(-EINVAL); - intr = kzalloc(sizeof(*intr), GFP_KERNEL); + intr = drmm_kzalloc(dev, sizeof(*intr), GFP_KERNEL); if (!intr) return ERR_PTR(-ENOMEM); @@ -512,11 +515,6 @@ struct dpu_hw_intr *dpu_hw_intr_init(void __iomem *addr, return intr; } -void dpu_hw_intr_destroy(struct dpu_hw_intr *intr) -{ - kfree(intr); -} - int dpu_core_irq_register_callback(struct dpu_kms *dpu_kms, unsigned int irq_idx, void (*irq_cb)(void *arg), 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 53a21ebc57e8b9..564b750a28fe28 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h @@ -70,15 +70,12 @@ struct dpu_hw_intr { /** * dpu_hw_intr_init(): Initializes the interrupts hw object + * @dev: Corresponding device for devres management * @addr: mapped register io address of MDP * @m: pointer to MDSS catalog data */ -struct dpu_hw_intr *dpu_hw_intr_init(void __iomem *addr, - const struct dpu_mdss_cfg *m); +struct dpu_hw_intr *dpu_hw_intr_init(struct drm_device *dev, + void __iomem *addr, + const struct dpu_mdss_cfg *m); -/** - * dpu_hw_intr_destroy(): Cleanup interrutps hw object - * @intr: pointer to interrupts hw object - */ -void dpu_hw_intr_destroy(struct dpu_hw_intr *intr); #endif diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c index e8b8908d3e1226..6bba531d6dc41e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. */ @@ -12,6 +12,8 @@ #include +#include + #define INTF_TIMING_ENGINE_EN 0x000 #define INTF_CONFIG 0x004 #define INTF_HSYNC_CTL 0x008 @@ -318,9 +320,9 @@ static u32 dpu_hw_intf_get_line_count(struct dpu_hw_intf *intf) return DPU_REG_READ(c, INTF_LINE_COUNT); } -static void dpu_hw_intf_setup_misr(struct dpu_hw_intf *intf, bool enable, u32 frame_count) +static void dpu_hw_intf_setup_misr(struct dpu_hw_intf *intf) { - dpu_hw_setup_misr(&intf->hw, INTF_MISR_CTRL, enable, frame_count); + dpu_hw_setup_misr(&intf->hw, INTF_MISR_CTRL, 0x1); } static int dpu_hw_intf_collect_misr(struct dpu_hw_intf *intf, u32 *misr_value) @@ -527,8 +529,10 @@ static void dpu_hw_intf_program_intf_cmd_cfg(struct dpu_hw_intf *ctx, DPU_REG_WRITE(&ctx->hw, INTF_CONFIG2, intf_cfg2); } -struct dpu_hw_intf *dpu_hw_intf_init(const struct dpu_intf_cfg *cfg, - void __iomem *addr, const struct dpu_mdss_version *mdss_rev) +struct dpu_hw_intf *dpu_hw_intf_init(struct drm_device *dev, + const struct dpu_intf_cfg *cfg, + void __iomem *addr, + const struct dpu_mdss_version *mdss_rev) { struct dpu_hw_intf *c; @@ -537,7 +541,7 @@ struct dpu_hw_intf *dpu_hw_intf_init(const struct dpu_intf_cfg *cfg, return NULL; } - c = kzalloc(sizeof(*c), GFP_KERNEL); + c = drmm_kzalloc(dev, sizeof(*c), GFP_KERNEL); if (!c) return ERR_PTR(-ENOMEM); @@ -581,9 +585,3 @@ struct dpu_hw_intf *dpu_hw_intf_init(const struct dpu_intf_cfg *cfg, return c; } - -void dpu_hw_intf_destroy(struct dpu_hw_intf *intf) -{ - kfree(intf); -} - diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h index c539025c418bb1..0bd57a32144a61 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. */ @@ -95,7 +95,7 @@ struct dpu_hw_intf_ops { void (*bind_pingpong_blk)(struct dpu_hw_intf *intf, const enum dpu_pingpong pp); - void (*setup_misr)(struct dpu_hw_intf *intf, bool enable, u32 frame_count); + void (*setup_misr)(struct dpu_hw_intf *intf); int (*collect_misr)(struct dpu_hw_intf *intf, u32 *misr_value); // Tearcheck on INTF since DPU 5.0.0 @@ -131,17 +131,14 @@ struct dpu_hw_intf { /** * dpu_hw_intf_init() - Initializes the INTF driver for the passed * interface catalog entry. + * @dev: Corresponding device for devres management * @cfg: interface catalog entry for which driver object is required * @addr: mapped register io address of MDP * @mdss_rev: dpu core's major and minor versions */ -struct dpu_hw_intf *dpu_hw_intf_init(const struct dpu_intf_cfg *cfg, - void __iomem *addr, const struct dpu_mdss_version *mdss_rev); - -/** - * dpu_hw_intf_destroy(): Destroys INTF driver context - * @intf: Pointer to INTF driver context - */ -void dpu_hw_intf_destroy(struct dpu_hw_intf *intf); +struct dpu_hw_intf *dpu_hw_intf_init(struct drm_device *dev, + const struct dpu_intf_cfg *cfg, + void __iomem *addr, + const struct dpu_mdss_version *mdss_rev); #endif /*_DPU_HW_INTF_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c index d1c3bd8379ea94..1d3ccf3228c62c 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.c @@ -1,9 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ +#include + #include "dpu_kms.h" #include "dpu_hw_catalog.h" #include "dpu_hwio.h" @@ -81,9 +83,9 @@ static void dpu_hw_lm_setup_border_color(struct dpu_hw_mixer *ctx, } } -static void dpu_hw_lm_setup_misr(struct dpu_hw_mixer *ctx, bool enable, u32 frame_count) +static void dpu_hw_lm_setup_misr(struct dpu_hw_mixer *ctx) { - dpu_hw_setup_misr(&ctx->hw, LM_MISR_CTRL, enable, frame_count); + dpu_hw_setup_misr(&ctx->hw, LM_MISR_CTRL, 0x0); } static int dpu_hw_lm_collect_misr(struct dpu_hw_mixer *ctx, u32 *misr_value) @@ -156,8 +158,9 @@ static void _setup_mixer_ops(struct dpu_hw_lm_ops *ops, ops->collect_misr = dpu_hw_lm_collect_misr; } -struct dpu_hw_mixer *dpu_hw_lm_init(const struct dpu_lm_cfg *cfg, - void __iomem *addr) +struct dpu_hw_mixer *dpu_hw_lm_init(struct drm_device *dev, + const struct dpu_lm_cfg *cfg, + void __iomem *addr) { struct dpu_hw_mixer *c; @@ -166,7 +169,7 @@ struct dpu_hw_mixer *dpu_hw_lm_init(const struct dpu_lm_cfg *cfg, return NULL; } - c = kzalloc(sizeof(*c), GFP_KERNEL); + c = drmm_kzalloc(dev, sizeof(*c), GFP_KERNEL); if (!c) return ERR_PTR(-ENOMEM); @@ -180,8 +183,3 @@ struct dpu_hw_mixer *dpu_hw_lm_init(const struct dpu_lm_cfg *cfg, return c; } - -void dpu_hw_lm_destroy(struct dpu_hw_mixer *lm) -{ - kfree(lm); -} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h index 36992d046a533b..0a33817552499a 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ @@ -57,7 +58,7 @@ struct dpu_hw_lm_ops { /** * setup_misr: Enable/disable MISR */ - void (*setup_misr)(struct dpu_hw_mixer *ctx, bool enable, u32 frame_count); + void (*setup_misr)(struct dpu_hw_mixer *ctx); /** * collect_misr: Read MISR signature @@ -95,16 +96,12 @@ static inline struct dpu_hw_mixer *to_dpu_hw_mixer(struct dpu_hw_blk *hw) /** * dpu_hw_lm_init() - Initializes the mixer hw driver object. * should be called once before accessing every mixer. + * @dev: Corresponding device for devres management * @cfg: mixer catalog entry for which driver object is required * @addr: mapped register io address of MDP */ -struct dpu_hw_mixer *dpu_hw_lm_init(const struct dpu_lm_cfg *cfg, - void __iomem *addr); - -/** - * dpu_hw_lm_destroy(): Destroys layer mixer driver context - * @lm: Pointer to LM driver context - */ -void dpu_hw_lm_destroy(struct dpu_hw_mixer *lm); +struct dpu_hw_mixer *dpu_hw_lm_init(struct drm_device *dev, + const struct dpu_lm_cfg *cfg, + void __iomem *addr); #endif /*_DPU_HW_LM_H */ 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 d85157acfbf8f0..5df54590405726 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h @@ -98,6 +98,7 @@ enum dpu_hw_blk_type { DPU_HW_BLK_DSPP, DPU_HW_BLK_MERGE_3D, DPU_HW_BLK_DSC, + DPU_HW_BLK_CDM, DPU_HW_BLK_MAX, }; @@ -185,6 +186,11 @@ enum dpu_dsc { DSC_MAX }; +enum dpu_cdm { + CDM_0 = 1, + CDM_MAX +}; + enum dpu_pingpong { PINGPONG_NONE, PINGPONG_0, @@ -195,6 +201,8 @@ enum dpu_pingpong { PINGPONG_5, PINGPONG_6, PINGPONG_7, + PINGPONG_8, + PINGPONG_9, PINGPONG_S0, PINGPONG_MAX }; @@ -204,6 +212,7 @@ enum dpu_merge_3d { MERGE_3D_1, MERGE_3D_2, MERGE_3D_3, + MERGE_3D_4, MERGE_3D_MAX }; @@ -458,6 +467,7 @@ struct dpu_mdss_color { #define DPU_DBG_MASK_ROT (1 << 9) #define DPU_DBG_MASK_DSPP (1 << 10) #define DPU_DBG_MASK_DSC (1 << 11) +#define DPU_DBG_MASK_CDM (1 << 12) /** * struct dpu_hw_tear_check - Struct contains parameters to configure diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.c index 90e0e05eff8d31..ddfa40a959cbd0 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.c @@ -4,6 +4,8 @@ #include +#include + #include "dpu_hw_mdss.h" #include "dpu_hwio.h" #include "dpu_hw_catalog.h" @@ -37,12 +39,13 @@ static void _setup_merge_3d_ops(struct dpu_hw_merge_3d *c, c->ops.setup_3d_mode = dpu_hw_merge_3d_setup_3d_mode; }; -struct dpu_hw_merge_3d *dpu_hw_merge_3d_init(const struct dpu_merge_3d_cfg *cfg, - void __iomem *addr) +struct dpu_hw_merge_3d *dpu_hw_merge_3d_init(struct drm_device *dev, + const struct dpu_merge_3d_cfg *cfg, + void __iomem *addr) { struct dpu_hw_merge_3d *c; - c = kzalloc(sizeof(*c), GFP_KERNEL); + c = drmm_kzalloc(dev, sizeof(*c), GFP_KERNEL); if (!c) return ERR_PTR(-ENOMEM); @@ -55,8 +58,3 @@ struct dpu_hw_merge_3d *dpu_hw_merge_3d_init(const struct dpu_merge_3d_cfg *cfg, return c; } - -void dpu_hw_merge_3d_destroy(struct dpu_hw_merge_3d *hw) -{ - kfree(hw); -} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.h index 19cec5e8872219..c192f02ec1abcc 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.h @@ -48,18 +48,13 @@ static inline struct dpu_hw_merge_3d *to_dpu_hw_merge_3d(struct dpu_hw_blk *hw) /** * dpu_hw_merge_3d_init() - Initializes the merge_3d driver for the passed * merge3d catalog entry. + * @dev: Corresponding device for devres management * @cfg: Pingpong catalog entry for which driver object is required * @addr: Mapped register io address of MDP * Return: Error code or allocated dpu_hw_merge_3d context */ -struct dpu_hw_merge_3d *dpu_hw_merge_3d_init(const struct dpu_merge_3d_cfg *cfg, - void __iomem *addr); - -/** - * dpu_hw_merge_3d_destroy - destroys merge_3d driver context - * should be called to free the context - * @pp: Pointer to PP driver context returned by dpu_hw_merge_3d_init - */ -void dpu_hw_merge_3d_destroy(struct dpu_hw_merge_3d *pp); +struct dpu_hw_merge_3d *dpu_hw_merge_3d_init(struct drm_device *dev, + const struct dpu_merge_3d_cfg *cfg, + void __iomem *addr); #endif /*_DPU_HW_MERGE3D_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c index 057cac7f5d936f..2db4c6fba37ac1 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.c @@ -4,6 +4,8 @@ #include +#include + #include "dpu_hw_mdss.h" #include "dpu_hwio.h" #include "dpu_hw_catalog.h" @@ -281,12 +283,14 @@ static int dpu_hw_pp_setup_dsc(struct dpu_hw_pingpong *pp) return 0; } -struct dpu_hw_pingpong *dpu_hw_pingpong_init(const struct dpu_pingpong_cfg *cfg, - void __iomem *addr, const struct dpu_mdss_version *mdss_rev) +struct dpu_hw_pingpong *dpu_hw_pingpong_init(struct drm_device *dev, + const struct dpu_pingpong_cfg *cfg, + void __iomem *addr, + const struct dpu_mdss_version *mdss_rev) { struct dpu_hw_pingpong *c; - c = kzalloc(sizeof(*c), GFP_KERNEL); + c = drmm_kzalloc(dev, sizeof(*c), GFP_KERNEL); if (!c) return ERR_PTR(-ENOMEM); @@ -317,8 +321,3 @@ struct dpu_hw_pingpong *dpu_hw_pingpong_init(const struct dpu_pingpong_cfg *cfg, return c; } - -void dpu_hw_pingpong_destroy(struct dpu_hw_pingpong *pp) -{ - kfree(pp); -} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h index 0d541ca5b05669..a48b69fd79a3b4 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h @@ -121,19 +121,15 @@ static inline struct dpu_hw_pingpong *to_dpu_hw_pingpong(struct dpu_hw_blk *hw) /** * dpu_hw_pingpong_init() - initializes the pingpong driver for the passed * pingpong catalog entry. + * @dev: Corresponding device for devres management * @cfg: Pingpong catalog entry for which driver object is required * @addr: Mapped register io address of MDP * @mdss_rev: dpu core's major and minor versions * Return: Error code or allocated dpu_hw_pingpong context */ -struct dpu_hw_pingpong *dpu_hw_pingpong_init(const struct dpu_pingpong_cfg *cfg, - void __iomem *addr, const struct dpu_mdss_version *mdss_rev); - -/** - * dpu_hw_pingpong_destroy - destroys pingpong driver context - * should be called to free the context - * @pp: Pointer to PP driver context returned by dpu_hw_pingpong_init - */ -void dpu_hw_pingpong_destroy(struct dpu_hw_pingpong *pp); +struct dpu_hw_pingpong *dpu_hw_pingpong_init(struct drm_device *dev, + const struct dpu_pingpong_cfg *cfg, + void __iomem *addr, + const struct dpu_mdss_version *mdss_rev); #endif /*_DPU_HW_PINGPONG_H */ 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 8e3c65989c4989..0bf8a83e8df368 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c @@ -11,6 +11,7 @@ #include "msm_mdss.h" #include +#include #define DPU_FETCH_CONFIG_RESET_VALUE 0x00000087 @@ -395,15 +396,6 @@ static void _dpu_hw_sspp_setup_scaler3(struct dpu_hw_sspp *ctx, format); } -static u32 _dpu_hw_sspp_get_scaler3_ver(struct dpu_hw_sspp *ctx) -{ - if (!ctx) - return 0; - - return dpu_hw_get_scaler3_ver(&ctx->hw, - ctx->cap->sblk->scaler_blk.base); -} - /* * dpu_hw_sspp_setup_rects() */ @@ -614,12 +606,8 @@ static void _setup_layer_ops(struct dpu_hw_sspp *c, test_bit(DPU_SSPP_SMART_DMA_V2, &c->cap->features)) c->ops.setup_multirect = dpu_hw_sspp_setup_multirect; - if (test_bit(DPU_SSPP_SCALER_QSEED3, &features) || - test_bit(DPU_SSPP_SCALER_QSEED3LITE, &features) || - test_bit(DPU_SSPP_SCALER_QSEED4, &features)) { + if (test_bit(DPU_SSPP_SCALER_QSEED3_COMPATIBLE, &features)) c->ops.setup_scaler = _dpu_hw_sspp_setup_scaler3; - c->ops.get_scaler_ver = _dpu_hw_sspp_get_scaler3_ver; - } if (test_bit(DPU_SSPP_CDP, &features)) c->ops.setup_cdp = dpu_hw_sspp_setup_cdp; @@ -654,10 +642,7 @@ int _dpu_hw_sspp_init_debugfs(struct dpu_hw_sspp *hw_pipe, struct dpu_kms *kms, cfg->len, kms); - if (cfg->features & BIT(DPU_SSPP_SCALER_QSEED3) || - cfg->features & BIT(DPU_SSPP_SCALER_QSEED3LITE) || - cfg->features & BIT(DPU_SSPP_SCALER_QSEED2) || - cfg->features & BIT(DPU_SSPP_SCALER_QSEED4)) + if (sblk->scaler_blk.len) dpu_debugfs_create_regset32("scaler_blk", 0400, debugfs_root, sblk->scaler_blk.base + cfg->base, @@ -685,16 +670,18 @@ int _dpu_hw_sspp_init_debugfs(struct dpu_hw_sspp *hw_pipe, struct dpu_kms *kms, } #endif -struct dpu_hw_sspp *dpu_hw_sspp_init(const struct dpu_sspp_cfg *cfg, - void __iomem *addr, const struct msm_mdss_data *mdss_data, - const struct dpu_mdss_version *mdss_rev) +struct dpu_hw_sspp *dpu_hw_sspp_init(struct drm_device *dev, + const struct dpu_sspp_cfg *cfg, + void __iomem *addr, + const struct msm_mdss_data *mdss_data, + const struct dpu_mdss_version *mdss_rev) { struct dpu_hw_sspp *hw_pipe; if (!addr) return ERR_PTR(-EINVAL); - hw_pipe = kzalloc(sizeof(*hw_pipe), GFP_KERNEL); + hw_pipe = drmm_kzalloc(dev, sizeof(*hw_pipe), GFP_KERNEL); if (!hw_pipe) return ERR_PTR(-ENOMEM); @@ -709,9 +696,3 @@ struct dpu_hw_sspp *dpu_hw_sspp_init(const struct dpu_sspp_cfg *cfg, return hw_pipe; } - -void dpu_hw_sspp_destroy(struct dpu_hw_sspp *ctx) -{ - kfree(ctx); -} - diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h index f93969fddb2254..b7dc52312c3924 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h @@ -21,21 +21,6 @@ struct dpu_hw_sspp; #define DPU_SSPP_ROT_90 BIT(3) #define DPU_SSPP_SOLID_FILL BIT(4) -/** - * Define all scaler feature bits in catalog - */ -#define DPU_SSPP_SCALER (BIT(DPU_SSPP_SCALER_RGB) | \ - BIT(DPU_SSPP_SCALER_QSEED2) | \ - BIT(DPU_SSPP_SCALER_QSEED3) | \ - BIT(DPU_SSPP_SCALER_QSEED3LITE) | \ - BIT(DPU_SSPP_SCALER_QSEED4)) - -/* - * Define all CSC feature bits in catalog - */ -#define DPU_SSPP_CSC_ANY (BIT(DPU_SSPP_CSC) | \ - BIT(DPU_SSPP_CSC_10BIT)) - /** * Component indices */ @@ -296,12 +281,6 @@ struct dpu_hw_sspp_ops { struct dpu_hw_scaler3_cfg *scaler3_cfg, const struct dpu_format *format); - /** - * get_scaler_ver - get scaler h/w version - * @ctx: Pointer to pipe context - */ - u32 (*get_scaler_ver)(struct dpu_hw_sspp *ctx); - /** * setup_cdp - setup client driven prefetch * @pipe: Pointer to software pipe context @@ -339,21 +318,17 @@ struct dpu_kms; /** * dpu_hw_sspp_init() - Initializes the sspp hw driver object. * Should be called once before accessing every pipe. + * @dev: Corresponding device for devres management * @cfg: Pipe catalog entry for which driver object is required * @addr: Mapped register io address of MDP * @mdss_data: UBWC / MDSS configuration data * @mdss_rev: dpu core's major and minor versions */ -struct dpu_hw_sspp *dpu_hw_sspp_init(const struct dpu_sspp_cfg *cfg, - void __iomem *addr, const struct msm_mdss_data *mdss_data, - const struct dpu_mdss_version *mdss_rev); - -/** - * dpu_hw_sspp_destroy(): Destroys SSPP driver context - * should be called during Hw pipe cleanup. - * @ctx: Pointer to SSPP driver context returned by dpu_hw_sspp_init - */ -void dpu_hw_sspp_destroy(struct dpu_hw_sspp *ctx); +struct dpu_hw_sspp *dpu_hw_sspp_init(struct drm_device *dev, + const struct dpu_sspp_cfg *cfg, + void __iomem *addr, + const struct msm_mdss_data *mdss_data, + const struct dpu_mdss_version *mdss_rev); int _dpu_hw_sspp_init_debugfs(struct dpu_hw_sspp *hw_pipe, struct dpu_kms *kms, struct dentry *entry); 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 24e734768a7276..05e48cf4ec1d24 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.c @@ -2,6 +2,8 @@ /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. */ +#include + #include "dpu_hwio.h" #include "dpu_hw_catalog.h" #include "dpu_hw_top.h" @@ -247,16 +249,17 @@ static void _setup_mdp_ops(struct dpu_hw_mdp_ops *ops, ops->intf_audio_select = dpu_hw_intf_audio_select; } -struct dpu_hw_mdp *dpu_hw_mdptop_init(const struct dpu_mdp_cfg *cfg, - void __iomem *addr, - const struct dpu_mdss_cfg *m) +struct dpu_hw_mdp *dpu_hw_mdptop_init(struct drm_device *dev, + const struct dpu_mdp_cfg *cfg, + void __iomem *addr, + const struct dpu_mdss_cfg *m) { struct dpu_hw_mdp *mdp; if (!addr) return ERR_PTR(-EINVAL); - mdp = kzalloc(sizeof(*mdp), GFP_KERNEL); + mdp = drmm_kzalloc(dev, sizeof(*mdp), GFP_KERNEL); if (!mdp) return ERR_PTR(-ENOMEM); @@ -271,9 +274,3 @@ struct dpu_hw_mdp *dpu_hw_mdptop_init(const struct dpu_mdp_cfg *cfg, return mdp; } - -void dpu_hw_mdp_destroy(struct dpu_hw_mdp *mdp) -{ - kfree(mdp); -} - diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h index 8b1463d2b2f0b0..6f3dc98087dfea 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h @@ -145,13 +145,15 @@ struct dpu_hw_mdp { /** * dpu_hw_mdptop_init - initializes the top driver for the passed config + * @dev: Corresponding device for devres management * @cfg: MDP TOP configuration from catalog * @addr: Mapped register io address of MDP * @m: Pointer to mdss catalog data */ -struct dpu_hw_mdp *dpu_hw_mdptop_init(const struct dpu_mdp_cfg *cfg, - void __iomem *addr, - const struct dpu_mdss_cfg *m); +struct dpu_hw_mdp *dpu_hw_mdptop_init(struct drm_device *dev, + const struct dpu_mdp_cfg *cfg, + void __iomem *addr, + const struct dpu_mdss_cfg *m); void dpu_hw_mdp_destroy(struct dpu_hw_mdp *mdp); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c index 18b16b2d2bf52f..dd475827314ec5 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ @@ -381,12 +381,6 @@ end: DPU_REG_WRITE(c, QSEED3_OP_MODE + scaler_offset, op_mode); } -u32 dpu_hw_get_scaler3_ver(struct dpu_hw_blk_reg_map *c, - u32 scaler_offset) -{ - return DPU_REG_READ(c, QSEED3_HW_VERSION + scaler_offset); -} - void dpu_hw_csc_setup(struct dpu_hw_blk_reg_map *c, u32 csc_reg_off, const struct dpu_csc_cfg *data, bool csc10) @@ -481,9 +475,11 @@ void _dpu_hw_setup_qos_lut(struct dpu_hw_blk_reg_map *c, u32 offset, cfg->danger_safe_en ? QOS_QOS_CTRL_DANGER_SAFE_EN : 0); } +/* + * note: Aside from encoders, input_sel should be set to 0x0 by default + */ void dpu_hw_setup_misr(struct dpu_hw_blk_reg_map *c, - u32 misr_ctrl_offset, - bool enable, u32 frame_count) + u32 misr_ctrl_offset, u8 input_sel) { u32 config = 0; @@ -492,15 +488,9 @@ void dpu_hw_setup_misr(struct dpu_hw_blk_reg_map *c, /* Clear old MISR value (in case it's read before a new value is calculated)*/ wmb(); - if (enable) { - config = (frame_count & MISR_FRAME_COUNT_MASK) | - MISR_CTRL_ENABLE | MISR_CTRL_FREE_RUN_MASK; - - DPU_REG_WRITE(c, misr_ctrl_offset, config); - } else { - DPU_REG_WRITE(c, misr_ctrl_offset, 0); - } - + config = MISR_FRAME_COUNT | MISR_CTRL_ENABLE | MISR_CTRL_FREE_RUN_MASK | + ((input_sel & 0xF) << 24); + DPU_REG_WRITE(c, misr_ctrl_offset, config); } int dpu_hw_collect_misr(struct dpu_hw_blk_reg_map *c, @@ -567,3 +557,47 @@ bool dpu_hw_clk_force_ctrl(struct dpu_hw_blk_reg_map *c, return clk_forced_on; } + +#define TO_S15D16(_x_)((_x_) << 7) + +const struct dpu_csc_cfg dpu_csc_YUV2RGB_601L = { + { + /* S15.16 format */ + 0x00012A00, 0x00000000, 0x00019880, + 0x00012A00, 0xFFFF9B80, 0xFFFF3000, + 0x00012A00, 0x00020480, 0x00000000, + }, + /* signed bias */ + { 0xfff0, 0xff80, 0xff80,}, + { 0x0, 0x0, 0x0,}, + /* unsigned clamp */ + { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,}, + { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,}, +}; + +const struct dpu_csc_cfg dpu_csc10_YUV2RGB_601L = { + { + /* S15.16 format */ + 0x00012A00, 0x00000000, 0x00019880, + 0x00012A00, 0xFFFF9B80, 0xFFFF3000, + 0x00012A00, 0x00020480, 0x00000000, + }, + /* signed bias */ + { 0xffc0, 0xfe00, 0xfe00,}, + { 0x0, 0x0, 0x0,}, + /* unsigned clamp */ + { 0x40, 0x3ac, 0x40, 0x3c0, 0x40, 0x3c0,}, + { 0x00, 0x3ff, 0x00, 0x3ff, 0x00, 0x3ff,}, +}; + +const struct dpu_csc_cfg dpu_csc10_rgb2yuv_601l = { + { + TO_S15D16(0x0083), TO_S15D16(0x0102), TO_S15D16(0x0032), + TO_S15D16(0x1fb5), TO_S15D16(0x1f6c), TO_S15D16(0x00e1), + TO_S15D16(0x00e1), TO_S15D16(0x1f45), TO_S15D16(0x1fdc) + }, + { 0x00, 0x00, 0x00 }, + { 0x0040, 0x0200, 0x0200 }, + { 0x000, 0x3ff, 0x000, 0x3ff, 0x000, 0x3ff }, + { 0x040, 0x3ac, 0x040, 0x3c0, 0x040, 0x3c0 }, +}; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h index 4bea139081bcd6..64ded69fa903e3 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_util.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ @@ -13,12 +13,18 @@ #include "dpu_hw_catalog.h" #define REG_MASK(n) ((BIT(n)) - 1) -#define MISR_FRAME_COUNT_MASK 0xFF +#define MISR_FRAME_COUNT 0x1 #define MISR_CTRL_ENABLE BIT(8) #define MISR_CTRL_STATUS BIT(9) #define MISR_CTRL_STATUS_CLEAR BIT(10) #define MISR_CTRL_FREE_RUN_MASK BIT(31) +#define TO_S15D16(_x_)((_x_) << 7) + +extern const struct dpu_csc_cfg dpu_csc_YUV2RGB_601L; +extern const struct dpu_csc_cfg dpu_csc10_YUV2RGB_601L; +extern const struct dpu_csc_cfg dpu_csc10_rgb2yuv_601l; + /* * This is the common struct maintained by each sub block * for mapping the register offsets in this block to the @@ -340,9 +346,6 @@ void dpu_hw_setup_scaler3(struct dpu_hw_blk_reg_map *c, u32 scaler_offset, u32 scaler_version, const struct dpu_format *format); -u32 dpu_hw_get_scaler3_ver(struct dpu_hw_blk_reg_map *c, - u32 scaler_offset); - void dpu_hw_csc_setup(struct dpu_hw_blk_reg_map *c, u32 csc_reg_off, const struct dpu_csc_cfg *data, bool csc10); @@ -358,9 +361,7 @@ void _dpu_hw_setup_qos_lut(struct dpu_hw_blk_reg_map *c, u32 offset, const struct dpu_hw_qos_cfg *cfg); void dpu_hw_setup_misr(struct dpu_hw_blk_reg_map *c, - u32 misr_ctrl_offset, - bool enable, - u32 frame_count); + u32 misr_ctrl_offset, u8 input_sel); int dpu_hw_collect_misr(struct dpu_hw_blk_reg_map *c, u32 misr_ctrl_offset, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.c index a5121a50b2bbf8..98e34afde2d259 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.c @@ -2,6 +2,8 @@ /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. */ +#include + #include "dpu_hwio.h" #include "dpu_hw_catalog.h" #include "dpu_hw_vbif.h" @@ -211,12 +213,13 @@ static void _setup_vbif_ops(struct dpu_hw_vbif_ops *ops, ops->set_write_gather_en = dpu_hw_set_write_gather_en; } -struct dpu_hw_vbif *dpu_hw_vbif_init(const struct dpu_vbif_cfg *cfg, - void __iomem *addr) +struct dpu_hw_vbif *dpu_hw_vbif_init(struct drm_device *dev, + const struct dpu_vbif_cfg *cfg, + void __iomem *addr) { struct dpu_hw_vbif *c; - c = kzalloc(sizeof(*c), GFP_KERNEL); + c = drmm_kzalloc(dev, sizeof(*c), GFP_KERNEL); if (!c) return ERR_PTR(-ENOMEM); @@ -234,8 +237,3 @@ struct dpu_hw_vbif *dpu_hw_vbif_init(const struct dpu_vbif_cfg *cfg, return c; } - -void dpu_hw_vbif_destroy(struct dpu_hw_vbif *vbif) -{ - kfree(vbif); -} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h index 7e10d2a172b45a..e2b4307500e42f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h @@ -108,12 +108,12 @@ struct dpu_hw_vbif { /** * dpu_hw_vbif_init() - Initializes the VBIF driver for the passed * VBIF catalog entry. + * @dev: Corresponding device for devres management * @cfg: VBIF catalog entry for which driver object is required * @addr: Mapped register io address of MDSS */ -struct dpu_hw_vbif *dpu_hw_vbif_init(const struct dpu_vbif_cfg *cfg, - void __iomem *addr); - -void dpu_hw_vbif_destroy(struct dpu_hw_vbif *vbif); +struct dpu_hw_vbif *dpu_hw_vbif_init(struct drm_device *dev, + const struct dpu_vbif_cfg *cfg, + void __iomem *addr); #endif /*_DPU_HW_VBIF_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c index 9668fb97c0478b..e75995f7fcea96 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.c @@ -3,6 +3,8 @@ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved */ +#include + #include "dpu_hw_mdss.h" #include "dpu_hwio.h" #include "dpu_hw_catalog.h" @@ -87,6 +89,9 @@ static void dpu_hw_wb_setup_format(struct dpu_hw_wb *ctx, dst_format |= BIT(14); /* DST_ALPHA_X */ } + if (DPU_FORMAT_IS_YUV(fmt)) + dst_format |= BIT(15); + pattern = (fmt->element[3] << 24) | (fmt->element[2] << 16) | (fmt->element[1] << 8) | @@ -208,15 +213,17 @@ static void _setup_wb_ops(struct dpu_hw_wb_ops *ops, ops->setup_clk_force_ctrl = dpu_hw_wb_setup_clk_force_ctrl; } -struct dpu_hw_wb *dpu_hw_wb_init(const struct dpu_wb_cfg *cfg, - void __iomem *addr, const struct dpu_mdss_version *mdss_rev) +struct dpu_hw_wb *dpu_hw_wb_init(struct drm_device *dev, + const struct dpu_wb_cfg *cfg, + void __iomem *addr, + const struct dpu_mdss_version *mdss_rev) { struct dpu_hw_wb *c; if (!addr) return ERR_PTR(-EINVAL); - c = kzalloc(sizeof(*c), GFP_KERNEL); + c = drmm_kzalloc(dev, sizeof(*c), GFP_KERNEL); if (!c) return ERR_PTR(-ENOMEM); @@ -230,8 +237,3 @@ struct dpu_hw_wb *dpu_hw_wb_init(const struct dpu_wb_cfg *cfg, return c; } - -void dpu_hw_wb_destroy(struct dpu_hw_wb *hw_wb) -{ - kfree(hw_wb); -} diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h index 88792f450a9271..e671796ea379ce 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h @@ -76,18 +76,15 @@ struct dpu_hw_wb { /** * dpu_hw_wb_init() - Initializes the writeback hw driver object. + * @dev: Corresponding device for devres management * @cfg: wb_path catalog entry for which driver object is required * @addr: mapped register io address of MDP * @mdss_rev: dpu core's major and minor versions * Return: Error code or allocated dpu_hw_wb context */ -struct dpu_hw_wb *dpu_hw_wb_init(const struct dpu_wb_cfg *cfg, - void __iomem *addr, const struct dpu_mdss_version *mdss_rev); - -/** - * dpu_hw_wb_destroy(): Destroy writeback hw driver object. - * @hw_wb: Pointer to writeback hw driver object - */ -void dpu_hw_wb_destroy(struct dpu_hw_wb *hw_wb); +struct dpu_hw_wb *dpu_hw_wb_init(struct drm_device *dev, + const struct dpu_wb_cfg *cfg, + void __iomem *addr, + const struct dpu_mdss_version *mdss_rev); #endif /*_DPU_HW_WB_H */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c index fe7267b3bff536..723cc1d8214310 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.c @@ -274,9 +274,6 @@ static int dpu_kms_debugfs_init(struct msm_kms *kms, struct drm_minor *minor) struct dpu_kms *dpu_kms = to_dpu_kms(kms); void *p = dpu_hw_util_get_log_mask_ptr(); struct dentry *entry; - struct drm_device *dev; - struct msm_drm_private *priv; - int i; if (!p) return -EINVAL; @@ -285,9 +282,6 @@ static int dpu_kms_debugfs_init(struct msm_kms *kms, struct drm_minor *minor) if (minor->type != DRM_MINOR_PRIMARY) return 0; - dev = dpu_kms->dev; - priv = dev->dev_private; - entry = debugfs_create_dir("debug", minor->debugfs_root); debugfs_create_x32(DPU_DEBUGFS_HWMASKNAME, 0600, entry, p); @@ -297,11 +291,6 @@ static int dpu_kms_debugfs_init(struct msm_kms *kms, struct drm_minor *minor) dpu_debugfs_core_irq_init(dpu_kms, entry); dpu_debugfs_sspp_init(dpu_kms, entry); - for (i = 0; i < ARRAY_SIZE(priv->dp); i++) { - if (priv->dp[i]) - msm_dp_debugfs_init(priv->dp[i], minor); - } - return dpu_core_perf_debugfs_init(dpu_kms, entry); } #endif @@ -597,7 +586,6 @@ static int _dpu_kms_initialize_displayport(struct drm_device *dev, rc = msm_dp_modeset_init(priv->dp[i], dev, encoder); if (rc) { DPU_ERROR("modeset_init failed for DP, rc = %d\n", rc); - drm_encoder_cleanup(encoder); return rc; } } @@ -630,7 +618,6 @@ static int _dpu_kms_initialize_hdmi(struct drm_device *dev, rc = msm_hdmi_modeset_init(priv->hdmi, dev, encoder); if (rc) { DPU_ERROR("modeset_init failed for DP, rc = %d\n", rc); - drm_encoder_cleanup(encoder); return rc; } @@ -662,7 +649,6 @@ static int _dpu_kms_initialize_writeback(struct drm_device *dev, n_formats); if (rc) { DPU_ERROR("dpu_writeback_init, rc = %d\n", rc); - drm_encoder_cleanup(encoder); return rc; } @@ -806,30 +792,17 @@ static void _dpu_kms_hw_destroy(struct dpu_kms *dpu_kms) { int i; - if (dpu_kms->hw_intr) - dpu_hw_intr_destroy(dpu_kms->hw_intr); dpu_kms->hw_intr = NULL; /* safe to call these more than once during shutdown */ _dpu_kms_mmu_destroy(dpu_kms); - if (dpu_kms->catalog) { - for (i = 0; i < ARRAY_SIZE(dpu_kms->hw_vbif); i++) { - if (dpu_kms->hw_vbif[i]) { - dpu_hw_vbif_destroy(dpu_kms->hw_vbif[i]); - dpu_kms->hw_vbif[i] = NULL; - } - } + for (i = 0; i < ARRAY_SIZE(dpu_kms->hw_vbif); i++) { + dpu_kms->hw_vbif[i] = NULL; } - if (dpu_kms->rm_init) - dpu_rm_destroy(&dpu_kms->rm); - dpu_kms->rm_init = false; - dpu_kms->catalog = NULL; - if (dpu_kms->hw_mdp) - dpu_hw_mdp_destroy(dpu_kms->hw_mdp); dpu_kms->hw_mdp = NULL; } @@ -856,7 +829,6 @@ static int dpu_irq_postinstall(struct msm_kms *kms) { struct msm_drm_private *priv; struct dpu_kms *dpu_kms = to_dpu_kms(kms); - int i; if (!dpu_kms || !dpu_kms->dev) return -EINVAL; @@ -865,9 +837,6 @@ static int dpu_irq_postinstall(struct msm_kms *kms) if (!priv) return -EINVAL; - for (i = 0; i < ARRAY_SIZE(priv->dp); i++) - msm_dp_irq_postinstall(priv->dp[i]); - return 0; } @@ -975,6 +944,10 @@ static void dpu_kms_mdp_snapshot(struct msm_disp_state *disp_state, struct msm_k } } + if (cat->cdm) + msm_disp_snapshot_add_block(disp_state, cat->cdm->len, + dpu_kms->mmio + cat->cdm->base, cat->cdm->name); + pm_runtime_put_sync(&dpu_kms->pdev->dev); } @@ -1078,7 +1051,7 @@ static int dpu_kms_hw_init(struct msm_kms *kms) if (!dpu_kms->catalog) { DPU_ERROR("device config not known!\n"); rc = -EINVAL; - goto power_error; + goto err_pm_put; } /* @@ -1088,49 +1061,48 @@ static int dpu_kms_hw_init(struct msm_kms *kms) rc = _dpu_kms_mmu_init(dpu_kms); if (rc) { DPU_ERROR("dpu_kms_mmu_init failed: %d\n", rc); - goto power_error; + goto err_pm_put; } dpu_kms->mdss = msm_mdss_get_mdss_data(dpu_kms->pdev->dev.parent); if (IS_ERR(dpu_kms->mdss)) { rc = PTR_ERR(dpu_kms->mdss); DPU_ERROR("failed to get MDSS data: %d\n", rc); - goto power_error; + goto err_pm_put; } if (!dpu_kms->mdss) { rc = -EINVAL; DPU_ERROR("NULL MDSS data\n"); - goto power_error; + goto err_pm_put; } - rc = dpu_rm_init(&dpu_kms->rm, dpu_kms->catalog, dpu_kms->mdss, dpu_kms->mmio); + rc = dpu_rm_init(dev, &dpu_kms->rm, dpu_kms->catalog, dpu_kms->mdss, dpu_kms->mmio); if (rc) { DPU_ERROR("rm init failed: %d\n", rc); - goto power_error; + goto err_pm_put; } - dpu_kms->rm_init = true; - - dpu_kms->hw_mdp = dpu_hw_mdptop_init(dpu_kms->catalog->mdp, + dpu_kms->hw_mdp = dpu_hw_mdptop_init(dev, + dpu_kms->catalog->mdp, dpu_kms->mmio, dpu_kms->catalog); if (IS_ERR(dpu_kms->hw_mdp)) { rc = PTR_ERR(dpu_kms->hw_mdp); DPU_ERROR("failed to get hw_mdp: %d\n", rc); dpu_kms->hw_mdp = NULL; - goto power_error; + goto err_pm_put; } for (i = 0; i < dpu_kms->catalog->vbif_count; i++) { struct dpu_hw_vbif *hw; const struct dpu_vbif_cfg *vbif = &dpu_kms->catalog->vbif[i]; - hw = dpu_hw_vbif_init(vbif, dpu_kms->vbif[vbif->id]); + hw = dpu_hw_vbif_init(dev, vbif, dpu_kms->vbif[vbif->id]); if (IS_ERR(hw)) { rc = PTR_ERR(hw); DPU_ERROR("failed to init vbif %d: %d\n", vbif->id, rc); - goto power_error; + goto err_pm_put; } dpu_kms->hw_vbif[vbif->id] = hw; @@ -1146,15 +1118,15 @@ static int dpu_kms_hw_init(struct msm_kms *kms) rc = dpu_core_perf_init(&dpu_kms->perf, dpu_kms->catalog->perf, max_core_clk_rate); if (rc) { DPU_ERROR("failed to init perf %d\n", rc); - goto perf_err; + goto err_pm_put; } - dpu_kms->hw_intr = dpu_hw_intr_init(dpu_kms->mmio, dpu_kms->catalog); - if (IS_ERR_OR_NULL(dpu_kms->hw_intr)) { + dpu_kms->hw_intr = dpu_hw_intr_init(dev, dpu_kms->mmio, dpu_kms->catalog); + if (IS_ERR(dpu_kms->hw_intr)) { rc = PTR_ERR(dpu_kms->hw_intr); DPU_ERROR("hw_intr init failed: %d\n", rc); dpu_kms->hw_intr = NULL; - goto hw_intr_init_err; + goto err_pm_put; } dev->mode_config.min_width = 0; @@ -1179,7 +1151,7 @@ static int dpu_kms_hw_init(struct msm_kms *kms) rc = _dpu_kms_drm_obj_init(dpu_kms); if (rc) { DPU_ERROR("modeset init failed: %d\n", rc); - goto drm_obj_init_err; + goto err_pm_put; } dpu_vbif_init_memtypes(dpu_kms); @@ -1188,10 +1160,7 @@ static int dpu_kms_hw_init(struct msm_kms *kms) return 0; -drm_obj_init_err: -hw_intr_init_err: -perf_err: -power_error: +err_pm_put: pm_runtime_put_sync(&dpu_kms->pdev->dev); error: _dpu_kms_hw_destroy(dpu_kms); @@ -1349,6 +1318,7 @@ static const struct dev_pm_ops dpu_pm_ops = { static const struct of_device_id dpu_dt_match[] = { { .compatible = "qcom,msm8998-dpu", .data = &dpu_msm8998_cfg, }, { .compatible = "qcom,qcm2290-dpu", .data = &dpu_qcm2290_cfg, }, + { .compatible = "qcom,sdm670-dpu", .data = &dpu_sdm670_cfg, }, { .compatible = "qcom,sdm845-dpu", .data = &dpu_sdm845_cfg, }, { .compatible = "qcom,sc7180-dpu", .data = &dpu_sc7180_cfg, }, { .compatible = "qcom,sc7280-dpu", .data = &dpu_sc7280_cfg, }, @@ -1363,6 +1333,7 @@ static const struct of_device_id dpu_dt_match[] = { { .compatible = "qcom,sm8350-dpu", .data = &dpu_sm8350_cfg, }, { .compatible = "qcom,sm8450-dpu", .data = &dpu_sm8450_cfg, }, { .compatible = "qcom,sm8550-dpu", .data = &dpu_sm8550_cfg, }, + { .compatible = "qcom,sm8650-dpu", .data = &dpu_sm8650_cfg, }, {} }; MODULE_DEVICE_TABLE(of, dpu_dt_match); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h index b6f53ca6e96285..d1207f4ec3ae51 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_kms.h @@ -51,6 +51,7 @@ } while (0) #define DPU_ERROR(fmt, ...) pr_err("[dpu error]" fmt, ##__VA_ARGS__) +#define DPU_ERROR_RATELIMITED(fmt, ...) pr_err_ratelimited("[dpu error]" fmt, ##__VA_ARGS__) /** * ktime_compare_safe - compare two ktime structures @@ -88,7 +89,6 @@ struct dpu_kms { struct drm_private_obj global_state; struct dpu_rm rm; - bool rm_init; struct dpu_hw_vbif *hw_vbif[VBIF_MAX]; struct dpu_hw_mdp *hw_mdp; @@ -136,6 +136,7 @@ struct dpu_global_state { uint32_t ctl_to_enc_id[CTL_MAX - CTL_0]; uint32_t dspp_to_enc_id[DSPP_MAX - DSPP_0]; uint32_t dsc_to_enc_id[DSC_MAX - DSC_0]; + uint32_t cdm_to_enc_id; }; struct dpu_global_state diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c index 3eef5e025e12e0..ff975ad5114565 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -21,6 +21,7 @@ #include "dpu_kms.h" #include "dpu_formats.h" #include "dpu_hw_sspp.h" +#include "dpu_hw_util.h" #include "dpu_trace.h" #include "dpu_crtc.h" #include "dpu_vbif.h" @@ -78,8 +79,6 @@ static const uint32_t qcom_compressed_supported_formats[] = { struct dpu_plane { struct drm_plane base; - struct mutex lock; - enum dpu_sspp pipe; uint32_t color_fill; @@ -470,8 +469,7 @@ static void _dpu_plane_setup_scaler3(struct dpu_hw_sspp *pipe_hw, scale_cfg->src_height[i] /= chroma_subsmpl_v; } - if (pipe_hw->cap->features & - BIT(DPU_SSPP_SCALER_QSEED4)) { + if (pipe_hw->cap->sblk->scaler_blk.version >= 0x3000) { scale_cfg->preload_x[i] = DPU_QSEED4_DEFAULT_PRELOAD_H; scale_cfg->preload_y[i] = DPU_QSEED4_DEFAULT_PRELOAD_V; } else { @@ -511,36 +509,6 @@ static void _dpu_plane_setup_pixel_ext(struct dpu_hw_scaler3_cfg *scale_cfg, } } -static const struct dpu_csc_cfg dpu_csc_YUV2RGB_601L = { - { - /* S15.16 format */ - 0x00012A00, 0x00000000, 0x00019880, - 0x00012A00, 0xFFFF9B80, 0xFFFF3000, - 0x00012A00, 0x00020480, 0x00000000, - }, - /* signed bias */ - { 0xfff0, 0xff80, 0xff80,}, - { 0x0, 0x0, 0x0,}, - /* unsigned clamp */ - { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0,}, - { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,}, -}; - -static const struct dpu_csc_cfg dpu_csc10_YUV2RGB_601L = { - { - /* S15.16 format */ - 0x00012A00, 0x00000000, 0x00019880, - 0x00012A00, 0xFFFF9B80, 0xFFFF3000, - 0x00012A00, 0x00020480, 0x00000000, - }, - /* signed bias */ - { 0xffc0, 0xfe00, 0xfe00,}, - { 0x0, 0x0, 0x0,}, - /* unsigned clamp */ - { 0x40, 0x3ac, 0x40, 0x3c0, 0x40, 0x3c0,}, - { 0x00, 0x3ff, 0x00, 0x3ff, 0x00, 0x3ff,}, -}; - static const struct dpu_csc_cfg *_dpu_plane_get_csc(struct dpu_sw_pipe *pipe, const struct dpu_format *fmt) { @@ -774,8 +742,8 @@ static int dpu_plane_atomic_check_pipe(struct dpu_plane *pdpu, min_src_size = DPU_FORMAT_IS_YUV(fmt) ? 2 : 1; if (DPU_FORMAT_IS_YUV(fmt) && - (!(pipe->sspp->cap->features & DPU_SSPP_SCALER) || - !(pipe->sspp->cap->features & DPU_SSPP_CSC_ANY))) { + (!pipe->sspp->cap->sblk->scaler_blk.len || + !pipe->sspp->cap->sblk->csc_blk.len)) { DPU_DEBUG_PLANE(pdpu, "plane doesn't have scaler/csc for yuv\n"); return -EINVAL; @@ -824,6 +792,8 @@ static int dpu_plane_atomic_check(struct drm_plane *plane, plane); int ret = 0, min_scale; struct dpu_plane *pdpu = to_dpu_plane(plane); + struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base); + u64 max_mdp_clk_rate = kms->perf.max_core_clk_rate; struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state); struct dpu_sw_pipe *pipe = &pstate->pipe; struct dpu_sw_pipe *r_pipe = &pstate->r_pipe; @@ -892,14 +862,16 @@ static int dpu_plane_atomic_check(struct drm_plane *plane, max_linewidth = pdpu->catalog->caps->max_linewidth; - if (drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) { + if ((drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) || + _dpu_plane_calc_clk(&crtc_state->adjusted_mode, pipe_cfg) > max_mdp_clk_rate) { /* * In parallel multirect case only the half of the usual width * is supported for tiled formats. If we are here, we know that * full width is more than max_linewidth, thus each rect is * wider than allowed. */ - if (DPU_FORMAT_IS_UBWC(fmt)) { + if (DPU_FORMAT_IS_UBWC(fmt) && + drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) { DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u, tiled format\n", DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth); return -E2BIG; @@ -1213,29 +1185,6 @@ static void dpu_plane_atomic_update(struct drm_plane *plane, } } -static void dpu_plane_destroy(struct drm_plane *plane) -{ - struct dpu_plane *pdpu = plane ? to_dpu_plane(plane) : NULL; - struct dpu_plane_state *pstate; - - DPU_DEBUG_PLANE(pdpu, "\n"); - - if (pdpu) { - pstate = to_dpu_plane_state(plane->state); - _dpu_plane_set_qos_ctrl(plane, &pstate->pipe, false); - - if (pstate->r_pipe.sspp) - _dpu_plane_set_qos_ctrl(plane, &pstate->r_pipe, false); - - mutex_destroy(&pdpu->lock); - - /* this will destroy the states as well */ - drm_plane_cleanup(plane); - - kfree(pdpu); - } -} - static void dpu_plane_destroy_state(struct drm_plane *plane, struct drm_plane_state *state) { @@ -1405,7 +1354,6 @@ static bool dpu_plane_format_mod_supported(struct drm_plane *plane, static const struct drm_plane_funcs dpu_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, - .destroy = dpu_plane_destroy, .reset = dpu_plane_reset, .atomic_duplicate_state = dpu_plane_duplicate_state, .atomic_destroy_state = dpu_plane_destroy_state, @@ -1433,35 +1381,28 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev, struct dpu_hw_sspp *pipe_hw; uint32_t num_formats; uint32_t supported_rotations; - int ret = -EINVAL; - - /* create and zero local structure */ - pdpu = kzalloc(sizeof(*pdpu), GFP_KERNEL); - if (!pdpu) { - DPU_ERROR("[%u]failed to allocate local plane struct\n", pipe); - ret = -ENOMEM; - return ERR_PTR(ret); - } - - /* cache local stuff for later */ - plane = &pdpu->base; - pdpu->pipe = pipe; + int ret; /* initialize underlying h/w driver */ pipe_hw = dpu_rm_get_sspp(&kms->rm, pipe); if (!pipe_hw || !pipe_hw->cap || !pipe_hw->cap->sblk) { DPU_ERROR("[%u]SSPP is invalid\n", pipe); - goto clean_plane; + return ERR_PTR(-EINVAL); } format_list = pipe_hw->cap->sblk->format_list; num_formats = pipe_hw->cap->sblk->num_formats; - ret = drm_universal_plane_init(dev, plane, 0xff, &dpu_plane_funcs, + pdpu = drmm_universal_plane_alloc(dev, struct dpu_plane, base, + 0xff, &dpu_plane_funcs, format_list, num_formats, supported_format_modifiers, type, NULL); - if (ret) - goto clean_plane; + if (IS_ERR(pdpu)) + return ERR_CAST(pdpu); + + /* cache local stuff for later */ + plane = &pdpu->base; + pdpu->pipe = pipe; pdpu->catalog = kms->catalog; @@ -1488,13 +1429,7 @@ struct drm_plane *dpu_plane_init(struct drm_device *dev, /* success! finalize initialization */ drm_plane_helper_add(plane, &dpu_plane_helper_funcs); - mutex_init(&pdpu->lock); - DPU_DEBUG("%s created for pipe:%u id:%u\n", plane->name, pipe, plane->base.id); return plane; - -clean_plane: - kfree(pdpu); - return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c index 8759466e2f3799..b58a9c2ae326ca 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.c @@ -8,6 +8,7 @@ #include "dpu_kms.h" #include "dpu_hw_lm.h" #include "dpu_hw_ctl.h" +#include "dpu_hw_cdm.h" #include "dpu_hw_pingpong.h" #include "dpu_hw_sspp.h" #include "dpu_hw_intf.h" @@ -34,72 +35,8 @@ struct dpu_rm_requirements { struct msm_display_topology topology; }; -int dpu_rm_destroy(struct dpu_rm *rm) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(rm->dspp_blks); i++) { - struct dpu_hw_dspp *hw; - - if (rm->dspp_blks[i]) { - hw = to_dpu_hw_dspp(rm->dspp_blks[i]); - dpu_hw_dspp_destroy(hw); - } - } - for (i = 0; i < ARRAY_SIZE(rm->pingpong_blks); i++) { - struct dpu_hw_pingpong *hw; - - if (rm->pingpong_blks[i]) { - hw = to_dpu_hw_pingpong(rm->pingpong_blks[i]); - dpu_hw_pingpong_destroy(hw); - } - } - for (i = 0; i < ARRAY_SIZE(rm->merge_3d_blks); i++) { - struct dpu_hw_merge_3d *hw; - - if (rm->merge_3d_blks[i]) { - hw = to_dpu_hw_merge_3d(rm->merge_3d_blks[i]); - dpu_hw_merge_3d_destroy(hw); - } - } - for (i = 0; i < ARRAY_SIZE(rm->mixer_blks); i++) { - struct dpu_hw_mixer *hw; - - if (rm->mixer_blks[i]) { - hw = to_dpu_hw_mixer(rm->mixer_blks[i]); - dpu_hw_lm_destroy(hw); - } - } - for (i = 0; i < ARRAY_SIZE(rm->ctl_blks); i++) { - struct dpu_hw_ctl *hw; - - if (rm->ctl_blks[i]) { - hw = to_dpu_hw_ctl(rm->ctl_blks[i]); - dpu_hw_ctl_destroy(hw); - } - } - for (i = 0; i < ARRAY_SIZE(rm->hw_intf); i++) - dpu_hw_intf_destroy(rm->hw_intf[i]); - - for (i = 0; i < ARRAY_SIZE(rm->dsc_blks); i++) { - struct dpu_hw_dsc *hw; - - if (rm->dsc_blks[i]) { - hw = to_dpu_hw_dsc(rm->dsc_blks[i]); - dpu_hw_dsc_destroy(hw); - } - } - - for (i = 0; i < ARRAY_SIZE(rm->hw_wb); i++) - dpu_hw_wb_destroy(rm->hw_wb[i]); - - for (i = 0; i < ARRAY_SIZE(rm->hw_sspp); i++) - dpu_hw_sspp_destroy(rm->hw_sspp[i]); - - return 0; -} - -int dpu_rm_init(struct dpu_rm *rm, +int dpu_rm_init(struct drm_device *dev, + struct dpu_rm *rm, const struct dpu_mdss_cfg *cat, const struct msm_mdss_data *mdss_data, void __iomem *mmio) @@ -119,7 +56,7 @@ int dpu_rm_init(struct dpu_rm *rm, struct dpu_hw_mixer *hw; const struct dpu_lm_cfg *lm = &cat->mixer[i]; - hw = dpu_hw_lm_init(lm, mmio); + hw = dpu_hw_lm_init(dev, lm, mmio); if (IS_ERR(hw)) { rc = PTR_ERR(hw); DPU_ERROR("failed lm object creation: err %d\n", rc); @@ -132,7 +69,7 @@ int dpu_rm_init(struct dpu_rm *rm, struct dpu_hw_merge_3d *hw; const struct dpu_merge_3d_cfg *merge_3d = &cat->merge_3d[i]; - hw = dpu_hw_merge_3d_init(merge_3d, mmio); + hw = dpu_hw_merge_3d_init(dev, merge_3d, mmio); if (IS_ERR(hw)) { rc = PTR_ERR(hw); DPU_ERROR("failed merge_3d object creation: err %d\n", @@ -146,7 +83,7 @@ int dpu_rm_init(struct dpu_rm *rm, struct dpu_hw_pingpong *hw; const struct dpu_pingpong_cfg *pp = &cat->pingpong[i]; - hw = dpu_hw_pingpong_init(pp, mmio, cat->mdss_ver); + hw = dpu_hw_pingpong_init(dev, pp, mmio, cat->mdss_ver); if (IS_ERR(hw)) { rc = PTR_ERR(hw); DPU_ERROR("failed pingpong object creation: err %d\n", @@ -162,7 +99,7 @@ int dpu_rm_init(struct dpu_rm *rm, struct dpu_hw_intf *hw; const struct dpu_intf_cfg *intf = &cat->intf[i]; - hw = dpu_hw_intf_init(intf, mmio, cat->mdss_ver); + hw = dpu_hw_intf_init(dev, intf, mmio, cat->mdss_ver); if (IS_ERR(hw)) { rc = PTR_ERR(hw); DPU_ERROR("failed intf object creation: err %d\n", rc); @@ -175,7 +112,7 @@ int dpu_rm_init(struct dpu_rm *rm, struct dpu_hw_wb *hw; const struct dpu_wb_cfg *wb = &cat->wb[i]; - hw = dpu_hw_wb_init(wb, mmio, cat->mdss_ver); + hw = dpu_hw_wb_init(dev, wb, mmio, cat->mdss_ver); if (IS_ERR(hw)) { rc = PTR_ERR(hw); DPU_ERROR("failed wb object creation: err %d\n", rc); @@ -188,7 +125,7 @@ int dpu_rm_init(struct dpu_rm *rm, struct dpu_hw_ctl *hw; const struct dpu_ctl_cfg *ctl = &cat->ctl[i]; - hw = dpu_hw_ctl_init(ctl, mmio, cat->mixer_count, cat->mixer); + hw = dpu_hw_ctl_init(dev, ctl, mmio, cat->mixer_count, cat->mixer); if (IS_ERR(hw)) { rc = PTR_ERR(hw); DPU_ERROR("failed ctl object creation: err %d\n", rc); @@ -201,7 +138,7 @@ int dpu_rm_init(struct dpu_rm *rm, struct dpu_hw_dspp *hw; const struct dpu_dspp_cfg *dspp = &cat->dspp[i]; - hw = dpu_hw_dspp_init(dspp, mmio); + hw = dpu_hw_dspp_init(dev, dspp, mmio); if (IS_ERR(hw)) { rc = PTR_ERR(hw); DPU_ERROR("failed dspp object creation: err %d\n", rc); @@ -215,9 +152,9 @@ int dpu_rm_init(struct dpu_rm *rm, const struct dpu_dsc_cfg *dsc = &cat->dsc[i]; if (test_bit(DPU_DSC_HW_REV_1_2, &dsc->features)) - hw = dpu_hw_dsc_init_1_2(dsc, mmio); + hw = dpu_hw_dsc_init_1_2(dev, dsc, mmio); else - hw = dpu_hw_dsc_init(dsc, mmio); + hw = dpu_hw_dsc_init(dev, dsc, mmio); if (IS_ERR(hw)) { rc = PTR_ERR(hw); @@ -231,7 +168,7 @@ int dpu_rm_init(struct dpu_rm *rm, struct dpu_hw_sspp *hw; const struct dpu_sspp_cfg *sspp = &cat->sspp[i]; - hw = dpu_hw_sspp_init(sspp, mmio, mdss_data, cat->mdss_ver); + hw = dpu_hw_sspp_init(dev, sspp, mmio, mdss_data, cat->mdss_ver); if (IS_ERR(hw)) { rc = PTR_ERR(hw); DPU_ERROR("failed sspp object creation: err %d\n", rc); @@ -240,11 +177,21 @@ int dpu_rm_init(struct dpu_rm *rm, rm->hw_sspp[sspp->id - SSPP_NONE] = hw; } + if (cat->cdm) { + struct dpu_hw_cdm *hw; + + hw = dpu_hw_cdm_init(dev, cat->cdm, mmio, cat->mdss_ver); + if (IS_ERR(hw)) { + rc = PTR_ERR(hw); + DPU_ERROR("failed cdm object creation: err %d\n", rc); + goto fail; + } + rm->cdm_blk = &hw->base; + } + return 0; fail: - dpu_rm_destroy(rm); - return rc ? rc : -EFAULT; } @@ -488,6 +435,26 @@ static int _dpu_rm_reserve_dsc(struct dpu_rm *rm, return 0; } +static int _dpu_rm_reserve_cdm(struct dpu_rm *rm, + struct dpu_global_state *global_state, + struct drm_encoder *enc) +{ + /* try allocating only one CDM block */ + if (!rm->cdm_blk) { + DPU_ERROR("CDM block does not exist\n"); + return -EIO; + } + + if (global_state->cdm_to_enc_id) { + DPU_ERROR("CDM_0 is already allocated\n"); + return -EIO; + } + + global_state->cdm_to_enc_id = enc->base.id; + + return 0; +} + static int _dpu_rm_make_reservation( struct dpu_rm *rm, struct dpu_global_state *global_state, @@ -513,6 +480,14 @@ static int _dpu_rm_make_reservation( if (ret) return ret; + if (reqs->topology.needs_cdm) { + ret = _dpu_rm_reserve_cdm(rm, global_state, enc); + if (ret) { + DPU_ERROR("unable to find CDM blk\n"); + return ret; + } + } + return ret; } @@ -523,9 +498,9 @@ static int _dpu_rm_populate_requirements( { reqs->topology = req_topology; - DRM_DEBUG_KMS("num_lm: %d num_dsc: %d num_intf: %d\n", + DRM_DEBUG_KMS("num_lm: %d num_dsc: %d num_intf: %d cdm: %d\n", reqs->topology.num_lm, reqs->topology.num_dsc, - reqs->topology.num_intf); + reqs->topology.num_intf, reqs->topology.needs_cdm); return 0; } @@ -554,6 +529,7 @@ void dpu_rm_release(struct dpu_global_state *global_state, ARRAY_SIZE(global_state->dsc_to_enc_id), enc->base.id); _dpu_rm_clear_mapping(global_state->dspp_to_enc_id, ARRAY_SIZE(global_state->dspp_to_enc_id), enc->base.id); + _dpu_rm_clear_mapping(&global_state->cdm_to_enc_id, 1, enc->base.id); } int dpu_rm_reserve( @@ -627,6 +603,11 @@ int dpu_rm_get_assigned_resources(struct dpu_rm *rm, hw_to_enc_id = global_state->dsc_to_enc_id; max_blks = ARRAY_SIZE(rm->dsc_blks); break; + case DPU_HW_BLK_CDM: + hw_blks = &rm->cdm_blk; + hw_to_enc_id = &global_state->cdm_to_enc_id; + max_blks = 1; + break; default: DPU_ERROR("blk type %d not managed by rm\n", type); return 0; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h index 2b551566cbf486..e3f83ebc656b3e 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_rm.h @@ -22,6 +22,7 @@ struct dpu_global_state; * @hw_wb: array of wb hardware resources * @dspp_blks: array of dspp hardware resources * @hw_sspp: array of sspp hardware resources + * @cdm_blk: cdm hardware resource */ struct dpu_rm { struct dpu_hw_blk *pingpong_blks[PINGPONG_MAX - PINGPONG_0]; @@ -33,29 +34,25 @@ struct dpu_rm { struct dpu_hw_blk *merge_3d_blks[MERGE_3D_MAX - MERGE_3D_0]; struct dpu_hw_blk *dsc_blks[DSC_MAX - DSC_0]; struct dpu_hw_sspp *hw_sspp[SSPP_MAX - SSPP_NONE]; + struct dpu_hw_blk *cdm_blk; }; /** * dpu_rm_init - Read hardware catalog and create reservation tracking objects * for all HW blocks. + * @dev: Corresponding device for devres management * @rm: DPU Resource Manager handle * @cat: Pointer to hardware catalog * @mdss_data: Pointer to MDSS / UBWC configuration * @mmio: mapped register io address of MDP * @Return: 0 on Success otherwise -ERROR */ -int dpu_rm_init(struct dpu_rm *rm, +int dpu_rm_init(struct drm_device *dev, + struct dpu_rm *rm, const struct dpu_mdss_cfg *cat, const struct msm_mdss_data *mdss_data, void __iomem *mmio); -/** - * dpu_rm_destroy - Free all memory allocated by dpu_rm_init - * @rm: DPU Resource Manager handle - * @Return: 0 on Success otherwise -ERROR - */ -int dpu_rm_destroy(struct dpu_rm *rm); - /** * dpu_rm_reserve - Given a CRTC->Encoder->Connector display chain, analyze * the use connections and user requirements, specified through related diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c index 169f9de4a12a73..75f93e34628255 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -123,16 +124,6 @@ static void unref_cursor_worker(struct drm_flip_work *work, void *val) drm_gem_object_put(val); } -static void mdp4_crtc_destroy(struct drm_crtc *crtc) -{ - struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); - - drm_crtc_cleanup(crtc); - drm_flip_work_cleanup(&mdp4_crtc->unref_cursor_work); - - kfree(mdp4_crtc); -} - /* statically (for now) map planes to mixer stage (z-order): */ static const int idxs[] = { [VG1] = 1, @@ -269,6 +260,7 @@ static void mdp4_crtc_atomic_disable(struct drm_crtc *crtc, { struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); struct mdp4_kms *mdp4_kms = get_kms(crtc); + unsigned long flags; DBG("%s", mdp4_crtc->name); @@ -281,6 +273,14 @@ static void mdp4_crtc_atomic_disable(struct drm_crtc *crtc, mdp_irq_unregister(&mdp4_kms->base, &mdp4_crtc->err); mdp4_disable(mdp4_kms); + if (crtc->state->event && !crtc->state->active) { + WARN_ON(mdp4_crtc->event); + spin_lock_irqsave(&mdp4_kms->dev->event_lock, flags); + drm_crtc_send_vblank_event(crtc, crtc->state->event); + crtc->state->event = NULL; + spin_unlock_irqrestore(&mdp4_kms->dev->event_lock, flags); + } + mdp4_crtc->enabled = false; } @@ -475,7 +475,6 @@ static int mdp4_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) static const struct drm_crtc_funcs mdp4_crtc_funcs = { .set_config = drm_atomic_helper_set_config, - .destroy = mdp4_crtc_destroy, .page_flip = drm_atomic_helper_page_flip, .cursor_set = mdp4_crtc_cursor_set, .cursor_move = mdp4_crtc_cursor_move, @@ -616,6 +615,13 @@ static const char *dma_names[] = { "DMA_P", "DMA_S", "DMA_E", }; +static void mdp4_crtc_flip_cleanup(struct drm_device *dev, void *ptr) +{ + struct mdp4_crtc *mdp4_crtc = ptr; + + drm_flip_work_cleanup(&mdp4_crtc->unref_cursor_work); +} + /* initialize crtc */ struct drm_crtc *mdp4_crtc_init(struct drm_device *dev, struct drm_plane *plane, int id, int ovlp_id, @@ -623,10 +629,13 @@ struct drm_crtc *mdp4_crtc_init(struct drm_device *dev, { struct drm_crtc *crtc = NULL; struct mdp4_crtc *mdp4_crtc; + int ret; - mdp4_crtc = kzalloc(sizeof(*mdp4_crtc), GFP_KERNEL); - if (!mdp4_crtc) - return ERR_PTR(-ENOMEM); + mdp4_crtc = drmm_crtc_alloc_with_planes(dev, struct mdp4_crtc, base, + plane, NULL, + &mdp4_crtc_funcs, NULL); + if (IS_ERR(mdp4_crtc)) + return ERR_CAST(mdp4_crtc); crtc = &mdp4_crtc->base; @@ -648,9 +657,10 @@ struct drm_crtc *mdp4_crtc_init(struct drm_device *dev, drm_flip_work_init(&mdp4_crtc->unref_cursor_work, "unref cursor", unref_cursor_worker); + ret = drmm_add_action_or_reset(dev, mdp4_crtc_flip_cleanup, mdp4_crtc); + if (ret) + return ERR_PTR(ret); - drm_crtc_init_with_planes(dev, crtc, plane, NULL, &mdp4_crtc_funcs, - NULL); drm_crtc_helper_add(crtc, &mdp4_crtc_helper_funcs); return crtc; diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c index 39b8fe53c29de4..74dafe7106be01 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dsi_encoder.c @@ -26,18 +26,6 @@ static struct mdp4_kms *get_kms(struct drm_encoder *encoder) return to_mdp4_kms(to_mdp_kms(priv->kms)); } -static void mdp4_dsi_encoder_destroy(struct drm_encoder *encoder) -{ - struct mdp4_dsi_encoder *mdp4_dsi_encoder = to_mdp4_dsi_encoder(encoder); - - drm_encoder_cleanup(encoder); - kfree(mdp4_dsi_encoder); -} - -static const struct drm_encoder_funcs mdp4_dsi_encoder_funcs = { - .destroy = mdp4_dsi_encoder_destroy, -}; - static void mdp4_dsi_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -148,28 +136,18 @@ static const struct drm_encoder_helper_funcs mdp4_dsi_encoder_helper_funcs = { /* initialize encoder */ struct drm_encoder *mdp4_dsi_encoder_init(struct drm_device *dev) { - struct drm_encoder *encoder = NULL; + struct drm_encoder *encoder; struct mdp4_dsi_encoder *mdp4_dsi_encoder; - int ret; - mdp4_dsi_encoder = kzalloc(sizeof(*mdp4_dsi_encoder), GFP_KERNEL); - if (!mdp4_dsi_encoder) { - ret = -ENOMEM; - goto fail; - } + mdp4_dsi_encoder = drmm_encoder_alloc(dev, struct mdp4_dsi_encoder, base, + NULL, DRM_MODE_ENCODER_DSI, NULL); + if (IS_ERR(mdp4_dsi_encoder)) + return ERR_CAST(mdp4_dsi_encoder); encoder = &mdp4_dsi_encoder->base; - drm_encoder_init(dev, encoder, &mdp4_dsi_encoder_funcs, - DRM_MODE_ENCODER_DSI, NULL); drm_encoder_helper_add(encoder, &mdp4_dsi_encoder_helper_funcs); return encoder; - -fail: - if (encoder) - mdp4_dsi_encoder_destroy(encoder); - - return ERR_PTR(ret); } #endif /* CONFIG_DRM_MSM_DSI */ diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c index 88645dbc3785b9..3b70764b48c47f 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_dtv_encoder.c @@ -25,17 +25,6 @@ static struct mdp4_kms *get_kms(struct drm_encoder *encoder) return to_mdp4_kms(to_mdp_kms(priv->kms)); } -static void mdp4_dtv_encoder_destroy(struct drm_encoder *encoder) -{ - struct mdp4_dtv_encoder *mdp4_dtv_encoder = to_mdp4_dtv_encoder(encoder); - drm_encoder_cleanup(encoder); - kfree(mdp4_dtv_encoder); -} - -static const struct drm_encoder_funcs mdp4_dtv_encoder_funcs = { - .destroy = mdp4_dtv_encoder_destroy, -}; - static void mdp4_dtv_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -173,41 +162,29 @@ long mdp4_dtv_round_pixclk(struct drm_encoder *encoder, unsigned long rate) /* initialize encoder */ struct drm_encoder *mdp4_dtv_encoder_init(struct drm_device *dev) { - struct drm_encoder *encoder = NULL; + struct drm_encoder *encoder; struct mdp4_dtv_encoder *mdp4_dtv_encoder; - int ret; - mdp4_dtv_encoder = kzalloc(sizeof(*mdp4_dtv_encoder), GFP_KERNEL); - if (!mdp4_dtv_encoder) { - ret = -ENOMEM; - goto fail; - } + mdp4_dtv_encoder = drmm_encoder_alloc(dev, struct mdp4_dtv_encoder, base, + NULL, DRM_MODE_ENCODER_TMDS, NULL); + if (IS_ERR(mdp4_dtv_encoder)) + return ERR_CAST(mdp4_dtv_encoder); encoder = &mdp4_dtv_encoder->base; - drm_encoder_init(dev, encoder, &mdp4_dtv_encoder_funcs, - DRM_MODE_ENCODER_TMDS, NULL); drm_encoder_helper_add(encoder, &mdp4_dtv_encoder_helper_funcs); mdp4_dtv_encoder->hdmi_clk = devm_clk_get(dev->dev, "hdmi_clk"); if (IS_ERR(mdp4_dtv_encoder->hdmi_clk)) { DRM_DEV_ERROR(dev->dev, "failed to get hdmi_clk\n"); - ret = PTR_ERR(mdp4_dtv_encoder->hdmi_clk); - goto fail; + return ERR_CAST(mdp4_dtv_encoder->hdmi_clk); } mdp4_dtv_encoder->mdp_clk = devm_clk_get(dev->dev, "tv_clk"); if (IS_ERR(mdp4_dtv_encoder->mdp_clk)) { DRM_DEV_ERROR(dev->dev, "failed to get tv_clk\n"); - ret = PTR_ERR(mdp4_dtv_encoder->mdp_clk); - goto fail; + return ERR_CAST(mdp4_dtv_encoder->mdp_clk); } return encoder; - -fail: - if (encoder) - mdp4_dtv_encoder_destroy(encoder); - - return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c index 10eb3e5b218efa..576995ddce37e9 100644 --- a/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c +++ b/drivers/gpu/drm/msm/disp/mdp4/mdp4_lcdc_encoder.c @@ -18,7 +18,7 @@ struct mdp4_lcdc_encoder { struct drm_panel *panel; struct clk *lcdc_clk; unsigned long int pixclock; - struct regulator *regs[3]; + struct regulator_bulk_data regs[3]; bool enabled; uint32_t bsc; }; @@ -30,18 +30,6 @@ static struct mdp4_kms *get_kms(struct drm_encoder *encoder) return to_mdp4_kms(to_mdp_kms(priv->kms)); } -static void mdp4_lcdc_encoder_destroy(struct drm_encoder *encoder) -{ - struct mdp4_lcdc_encoder *mdp4_lcdc_encoder = - to_mdp4_lcdc_encoder(encoder); - drm_encoder_cleanup(encoder); - kfree(mdp4_lcdc_encoder); -} - -static const struct drm_encoder_funcs mdp4_lcdc_encoder_funcs = { - .destroy = mdp4_lcdc_encoder_destroy, -}; - /* this should probably be a helper: */ static struct drm_connector *get_connector(struct drm_encoder *encoder) { @@ -271,12 +259,10 @@ static void mdp4_lcdc_encoder_mode_set(struct drm_encoder *encoder, static void mdp4_lcdc_encoder_disable(struct drm_encoder *encoder) { - struct drm_device *dev = encoder->dev; struct mdp4_lcdc_encoder *mdp4_lcdc_encoder = to_mdp4_lcdc_encoder(encoder); struct mdp4_kms *mdp4_kms = get_kms(encoder); struct drm_panel *panel; - int i, ret; if (WARN_ON(!mdp4_lcdc_encoder->enabled)) return; @@ -301,11 +287,8 @@ static void mdp4_lcdc_encoder_disable(struct drm_encoder *encoder) clk_disable_unprepare(mdp4_lcdc_encoder->lcdc_clk); - for (i = 0; i < ARRAY_SIZE(mdp4_lcdc_encoder->regs); i++) { - ret = regulator_disable(mdp4_lcdc_encoder->regs[i]); - if (ret) - DRM_DEV_ERROR(dev->dev, "failed to disable regulator: %d\n", ret); - } + regulator_bulk_disable(ARRAY_SIZE(mdp4_lcdc_encoder->regs), + mdp4_lcdc_encoder->regs); mdp4_lcdc_encoder->enabled = false; } @@ -319,7 +302,7 @@ static void mdp4_lcdc_encoder_enable(struct drm_encoder *encoder) struct mdp4_kms *mdp4_kms = get_kms(encoder); struct drm_panel *panel; uint32_t config; - int i, ret; + int ret; if (WARN_ON(mdp4_lcdc_encoder->enabled)) return; @@ -339,11 +322,10 @@ static void mdp4_lcdc_encoder_enable(struct drm_encoder *encoder) mdp4_crtc_set_config(encoder->crtc, config); mdp4_crtc_set_intf(encoder->crtc, INTF_LCDC_DTV, 0); - for (i = 0; i < ARRAY_SIZE(mdp4_lcdc_encoder->regs); i++) { - ret = regulator_enable(mdp4_lcdc_encoder->regs[i]); - if (ret) - DRM_DEV_ERROR(dev->dev, "failed to enable regulator: %d\n", ret); - } + ret = regulator_bulk_enable(ARRAY_SIZE(mdp4_lcdc_encoder->regs), + mdp4_lcdc_encoder->regs); + if (ret) + DRM_DEV_ERROR(dev->dev, "failed to enable regulators: %d\n", ret); DBG("setting lcdc_clk=%lu", pc); ret = clk_set_rate(mdp4_lcdc_encoder->lcdc_clk, pc); @@ -383,63 +365,38 @@ long mdp4_lcdc_round_pixclk(struct drm_encoder *encoder, unsigned long rate) struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev, struct device_node *panel_node) { - struct drm_encoder *encoder = NULL; + struct drm_encoder *encoder; struct mdp4_lcdc_encoder *mdp4_lcdc_encoder; - struct regulator *reg; int ret; - mdp4_lcdc_encoder = kzalloc(sizeof(*mdp4_lcdc_encoder), GFP_KERNEL); - if (!mdp4_lcdc_encoder) { - ret = -ENOMEM; - goto fail; - } + mdp4_lcdc_encoder = drmm_encoder_alloc(dev, struct mdp4_lcdc_encoder, base, + NULL, DRM_MODE_ENCODER_LVDS, NULL); + if (IS_ERR(mdp4_lcdc_encoder)) + return ERR_CAST(mdp4_lcdc_encoder); mdp4_lcdc_encoder->panel_node = panel_node; encoder = &mdp4_lcdc_encoder->base; - drm_encoder_init(dev, encoder, &mdp4_lcdc_encoder_funcs, - DRM_MODE_ENCODER_LVDS, NULL); drm_encoder_helper_add(encoder, &mdp4_lcdc_encoder_helper_funcs); /* TODO: do we need different pll in other cases? */ mdp4_lcdc_encoder->lcdc_clk = mpd4_lvds_pll_init(dev); if (IS_ERR(mdp4_lcdc_encoder->lcdc_clk)) { DRM_DEV_ERROR(dev->dev, "failed to get lvds_clk\n"); - ret = PTR_ERR(mdp4_lcdc_encoder->lcdc_clk); - goto fail; + return ERR_CAST(mdp4_lcdc_encoder->lcdc_clk); } /* TODO: different regulators in other cases? */ - reg = devm_regulator_get(dev->dev, "lvds-vccs-3p3v"); - if (IS_ERR(reg)) { - ret = PTR_ERR(reg); - DRM_DEV_ERROR(dev->dev, "failed to get lvds-vccs-3p3v: %d\n", ret); - goto fail; - } - mdp4_lcdc_encoder->regs[0] = reg; - - reg = devm_regulator_get(dev->dev, "lvds-pll-vdda"); - if (IS_ERR(reg)) { - ret = PTR_ERR(reg); - DRM_DEV_ERROR(dev->dev, "failed to get lvds-pll-vdda: %d\n", ret); - goto fail; - } - mdp4_lcdc_encoder->regs[1] = reg; + mdp4_lcdc_encoder->regs[0].supply = "lvds-vccs-3p3v"; + mdp4_lcdc_encoder->regs[1].supply = "lvds-vccs-3p3v"; + mdp4_lcdc_encoder->regs[2].supply = "lvds-vdda"; - reg = devm_regulator_get(dev->dev, "lvds-vdda"); - if (IS_ERR(reg)) { - ret = PTR_ERR(reg); - DRM_DEV_ERROR(dev->dev, "failed to get lvds-vdda: %d\n", ret); - goto fail; - } - mdp4_lcdc_encoder->regs[2] = reg; + ret = devm_regulator_bulk_get(dev->dev, + ARRAY_SIZE(mdp4_lcdc_encoder->regs), + mdp4_lcdc_encoder->regs); + if (ret) + return ERR_PTR(ret); return encoder; - -fail: - if (encoder) - mdp4_lcdc_encoder_destroy(encoder); - - return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c index 694d5434133741..c5179e4c393ca6 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.c @@ -1350,23 +1350,17 @@ int mdp5_cfg_get_hw_rev(struct mdp5_cfg_handler *cfg_handler) return cfg_handler->revision; } -void mdp5_cfg_destroy(struct mdp5_cfg_handler *cfg_handler) -{ - kfree(cfg_handler); -} - struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms, uint32_t major, uint32_t minor) { struct drm_device *dev = mdp5_kms->dev; struct mdp5_cfg_handler *cfg_handler; const struct mdp5_cfg_handler *cfg_handlers; - int i, ret = 0, num_handlers; + int i, num_handlers; - cfg_handler = kzalloc(sizeof(*cfg_handler), GFP_KERNEL); + cfg_handler = devm_kzalloc(dev->dev, sizeof(*cfg_handler), GFP_KERNEL); if (unlikely(!cfg_handler)) { - ret = -ENOMEM; - goto fail; + return ERR_PTR(-ENOMEM); } switch (major) { @@ -1381,8 +1375,7 @@ struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms, default: DRM_DEV_ERROR(dev->dev, "unexpected MDP major version: v%d.%d\n", major, minor); - ret = -ENXIO; - goto fail; + return ERR_PTR(-ENXIO); } /* only after mdp5_cfg global pointer's init can we access the hw */ @@ -1396,8 +1389,7 @@ struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms, if (unlikely(!mdp5_cfg)) { DRM_DEV_ERROR(dev->dev, "unexpected MDP minor revision: v%d.%d\n", major, minor); - ret = -ENXIO; - goto fail; + return ERR_PTR(-ENXIO); } cfg_handler->revision = minor; @@ -1406,10 +1398,4 @@ struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms, DBG("MDP5: %s hw config selected", mdp5_cfg->name); return cfg_handler; - -fail: - if (cfg_handler) - mdp5_cfg_destroy(cfg_handler); - - return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.h index c2502cc338646a..26c5d8b4ab4632 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.h +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_cfg.h @@ -121,6 +121,5 @@ int mdp5_cfg_get_hw_rev(struct mdp5_cfg_handler *cfg_hnd); struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms, uint32_t major, uint32_t minor); -void mdp5_cfg_destroy(struct mdp5_cfg_handler *cfg_hnd); #endif /* __MDP5_CFG_H__ */ diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c index 86036dd4e1e82b..4a3db2ea16895d 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_crtc.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -172,14 +173,11 @@ static void unref_cursor_worker(struct drm_flip_work *work, void *val) drm_gem_object_put(val); } -static void mdp5_crtc_destroy(struct drm_crtc *crtc) +static void mdp5_crtc_flip_cleanup(struct drm_device *dev, void *ptr) { - struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); + struct mdp5_crtc *mdp5_crtc = ptr; - drm_crtc_cleanup(crtc); drm_flip_work_cleanup(&mdp5_crtc->unref_cursor_work); - - kfree(mdp5_crtc); } static inline u32 mdp5_lm_use_fg_alpha_mask(enum mdp_mixer_stage_id stage) @@ -1147,7 +1145,6 @@ static void mdp5_crtc_reset(struct drm_crtc *crtc) static const struct drm_crtc_funcs mdp5_crtc_no_lm_cursor_funcs = { .set_config = drm_atomic_helper_set_config, - .destroy = mdp5_crtc_destroy, .page_flip = drm_atomic_helper_page_flip, .reset = mdp5_crtc_reset, .atomic_duplicate_state = mdp5_crtc_duplicate_state, @@ -1161,7 +1158,6 @@ static const struct drm_crtc_funcs mdp5_crtc_no_lm_cursor_funcs = { static const struct drm_crtc_funcs mdp5_crtc_funcs = { .set_config = drm_atomic_helper_set_config, - .destroy = mdp5_crtc_destroy, .page_flip = drm_atomic_helper_page_flip, .reset = mdp5_crtc_reset, .atomic_duplicate_state = mdp5_crtc_duplicate_state, @@ -1327,10 +1323,16 @@ struct drm_crtc *mdp5_crtc_init(struct drm_device *dev, { struct drm_crtc *crtc = NULL; struct mdp5_crtc *mdp5_crtc; + int ret; - mdp5_crtc = kzalloc(sizeof(*mdp5_crtc), GFP_KERNEL); - if (!mdp5_crtc) - return ERR_PTR(-ENOMEM); + mdp5_crtc = drmm_crtc_alloc_with_planes(dev, struct mdp5_crtc, base, + plane, cursor_plane, + cursor_plane ? + &mdp5_crtc_no_lm_cursor_funcs : + &mdp5_crtc_funcs, + NULL); + if (IS_ERR(mdp5_crtc)) + return ERR_CAST(mdp5_crtc); crtc = &mdp5_crtc->base; @@ -1346,13 +1348,11 @@ struct drm_crtc *mdp5_crtc_init(struct drm_device *dev, mdp5_crtc->lm_cursor_enabled = cursor_plane ? false : true; - drm_crtc_init_with_planes(dev, crtc, plane, cursor_plane, - cursor_plane ? - &mdp5_crtc_no_lm_cursor_funcs : - &mdp5_crtc_funcs, NULL); - drm_flip_work_init(&mdp5_crtc->unref_cursor_work, "unref cursor", unref_cursor_worker); + ret = drmm_add_action_or_reset(dev, mdp5_crtc_flip_cleanup, mdp5_crtc); + if (ret) + return ERR_PTR(ret); drm_crtc_helper_add(crtc, &mdp5_crtc_helper_funcs); diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.c index 1220f2b20e05cb..666de99a46a5b1 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.c @@ -681,11 +681,6 @@ void mdp5_ctlm_hw_reset(struct mdp5_ctl_manager *ctl_mgr) } } -void mdp5_ctlm_destroy(struct mdp5_ctl_manager *ctl_mgr) -{ - kfree(ctl_mgr); -} - struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev, void __iomem *mmio_base, struct mdp5_cfg_handler *cfg_hnd) { @@ -697,18 +692,16 @@ struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev, unsigned long flags; int c, ret; - ctl_mgr = kzalloc(sizeof(*ctl_mgr), GFP_KERNEL); + ctl_mgr = devm_kzalloc(dev->dev, sizeof(*ctl_mgr), GFP_KERNEL); if (!ctl_mgr) { DRM_DEV_ERROR(dev->dev, "failed to allocate CTL manager\n"); - ret = -ENOMEM; - goto fail; + return ERR_PTR(-ENOMEM); } if (WARN_ON(ctl_cfg->count > MAX_CTL)) { DRM_DEV_ERROR(dev->dev, "Increase static pool size to at least %d\n", ctl_cfg->count); - ret = -ENOSPC; - goto fail; + return ERR_PTR(-ENOSPC); } /* initialize the CTL manager: */ @@ -727,7 +720,7 @@ struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev, DRM_DEV_ERROR(dev->dev, "CTL_%d: base is null!\n", c); ret = -EINVAL; spin_unlock_irqrestore(&ctl_mgr->pool_lock, flags); - goto fail; + return ERR_PTR(ret); } ctl->ctlm = ctl_mgr; ctl->id = c; @@ -755,10 +748,4 @@ struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev, DBG("Pool of %d CTLs created.", ctl_mgr->nctl); return ctl_mgr; - -fail: - if (ctl_mgr) - mdp5_ctlm_destroy(ctl_mgr); - - return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.h index c2af68aa77aed3..9020e8efc4e4b6 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.h +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_ctl.h @@ -17,7 +17,6 @@ struct mdp5_ctl_manager; struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev, void __iomem *mmio_base, struct mdp5_cfg_handler *cfg_hnd); void mdp5_ctlm_hw_reset(struct mdp5_ctl_manager *ctlm); -void mdp5_ctlm_destroy(struct mdp5_ctl_manager *ctlm); /* * CTL prototypes: diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c index 79d67c495780fb..8db97083e14db7 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_encoder.c @@ -16,17 +16,6 @@ static struct mdp5_kms *get_kms(struct drm_encoder *encoder) return to_mdp5_kms(to_mdp_kms(priv->kms)); } -static void mdp5_encoder_destroy(struct drm_encoder *encoder) -{ - struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder); - drm_encoder_cleanup(encoder); - kfree(mdp5_encoder); -} - -static const struct drm_encoder_funcs mdp5_encoder_funcs = { - .destroy = mdp5_encoder_destroy, -}; - static void mdp5_vid_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -342,13 +331,11 @@ struct drm_encoder *mdp5_encoder_init(struct drm_device *dev, struct mdp5_encoder *mdp5_encoder; int enc_type = (intf->type == INTF_DSI) ? DRM_MODE_ENCODER_DSI : DRM_MODE_ENCODER_TMDS; - int ret; - mdp5_encoder = kzalloc(sizeof(*mdp5_encoder), GFP_KERNEL); - if (!mdp5_encoder) { - ret = -ENOMEM; - goto fail; - } + mdp5_encoder = drmm_encoder_alloc(dev, struct mdp5_encoder, base, + NULL, enc_type, NULL); + if (IS_ERR(mdp5_encoder)) + return ERR_CAST(mdp5_encoder); encoder = &mdp5_encoder->base; mdp5_encoder->ctl = ctl; @@ -356,15 +343,7 @@ struct drm_encoder *mdp5_encoder_init(struct drm_device *dev, spin_lock_init(&mdp5_encoder->intf_lock); - drm_encoder_init(dev, encoder, &mdp5_encoder_funcs, enc_type, NULL); - drm_encoder_helper_add(encoder, &mdp5_encoder_helper_funcs); return encoder; - -fail: - if (encoder) - mdp5_encoder_destroy(encoder); - - return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c index ec933d597e20cf..0827634664aef0 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_kms.c @@ -209,13 +209,6 @@ static void mdp5_kms_destroy(struct msm_kms *kms) { struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); struct msm_gem_address_space *aspace = kms->aspace; - int i; - - for (i = 0; i < mdp5_kms->num_hwmixers; i++) - mdp5_mixer_destroy(mdp5_kms->hwmixers[i]); - - for (i = 0; i < mdp5_kms->num_hwpipes; i++) - mdp5_pipe_destroy(mdp5_kms->hwpipes[i]); if (aspace) { aspace->mmu->funcs->detach(aspace->mmu); @@ -623,18 +616,6 @@ fail: static void mdp5_destroy(struct mdp5_kms *mdp5_kms) { - int i; - - if (mdp5_kms->ctlm) - mdp5_ctlm_destroy(mdp5_kms->ctlm); - if (mdp5_kms->smp) - mdp5_smp_destroy(mdp5_kms->smp); - if (mdp5_kms->cfg) - mdp5_cfg_destroy(mdp5_kms->cfg); - - for (i = 0; i < mdp5_kms->num_intfs; i++) - kfree(mdp5_kms->intfs[i]); - if (mdp5_kms->rpm_enabled) pm_runtime_disable(&mdp5_kms->pdev->dev); @@ -652,7 +633,7 @@ static int construct_pipes(struct mdp5_kms *mdp5_kms, int cnt, for (i = 0; i < cnt; i++) { struct mdp5_hw_pipe *hwpipe; - hwpipe = mdp5_pipe_init(pipes[i], offsets[i], caps); + hwpipe = mdp5_pipe_init(dev, pipes[i], offsets[i], caps); if (IS_ERR(hwpipe)) { ret = PTR_ERR(hwpipe); DRM_DEV_ERROR(dev->dev, "failed to construct pipe for %s (%d)\n", @@ -724,7 +705,7 @@ static int hwmixer_init(struct mdp5_kms *mdp5_kms) for (i = 0; i < hw_cfg->lm.count; i++) { struct mdp5_hw_mixer *mixer; - mixer = mdp5_mixer_init(&hw_cfg->lm.instances[i]); + mixer = mdp5_mixer_init(dev, &hw_cfg->lm.instances[i]); if (IS_ERR(mixer)) { ret = PTR_ERR(mixer); DRM_DEV_ERROR(dev->dev, "failed to construct LM%d (%d)\n", @@ -755,7 +736,7 @@ static int interface_init(struct mdp5_kms *mdp5_kms) if (intf_types[i] == INTF_DISABLED) continue; - intf = kzalloc(sizeof(*intf), GFP_KERNEL); + intf = devm_kzalloc(dev->dev, sizeof(*intf), GFP_KERNEL); if (!intf) { DRM_DEV_ERROR(dev->dev, "failed to construct INTF%d\n", i); return -ENOMEM; diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.c index 2536def2a0005d..2822b533f80774 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.c @@ -140,20 +140,16 @@ int mdp5_mixer_release(struct drm_atomic_state *s, struct mdp5_hw_mixer *mixer) return 0; } -void mdp5_mixer_destroy(struct mdp5_hw_mixer *mixer) -{ - kfree(mixer); -} - static const char * const mixer_names[] = { "LM0", "LM1", "LM2", "LM3", "LM4", "LM5", }; -struct mdp5_hw_mixer *mdp5_mixer_init(const struct mdp5_lm_instance *lm) +struct mdp5_hw_mixer *mdp5_mixer_init(struct drm_device *dev, + const struct mdp5_lm_instance *lm) { struct mdp5_hw_mixer *mixer; - mixer = kzalloc(sizeof(*mixer), GFP_KERNEL); + mixer = devm_kzalloc(dev->dev, sizeof(*mixer), GFP_KERNEL); if (!mixer) return ERR_PTR(-ENOMEM); diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.h index 545ee223b9d740..2bedd75835bcd9 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.h +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_mixer.h @@ -25,8 +25,8 @@ struct mdp5_hw_mixer_state { struct drm_crtc *hwmixer_to_crtc[8]; }; -struct mdp5_hw_mixer *mdp5_mixer_init(const struct mdp5_lm_instance *lm); -void mdp5_mixer_destroy(struct mdp5_hw_mixer *lm); +struct mdp5_hw_mixer *mdp5_mixer_init(struct drm_device *dev, + const struct mdp5_lm_instance *lm); int mdp5_mixer_assign(struct drm_atomic_state *s, struct drm_crtc *crtc, uint32_t caps, struct mdp5_hw_mixer **mixer, struct mdp5_hw_mixer **r_mixer); diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.c index e4b8a789835a43..99b2c30b1d486e 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.c @@ -151,17 +151,13 @@ int mdp5_pipe_release(struct drm_atomic_state *s, struct mdp5_hw_pipe *hwpipe) return 0; } -void mdp5_pipe_destroy(struct mdp5_hw_pipe *hwpipe) -{ - kfree(hwpipe); -} - -struct mdp5_hw_pipe *mdp5_pipe_init(enum mdp5_pipe pipe, +struct mdp5_hw_pipe *mdp5_pipe_init(struct drm_device *dev, + enum mdp5_pipe pipe, uint32_t reg_offset, uint32_t caps) { struct mdp5_hw_pipe *hwpipe; - hwpipe = kzalloc(sizeof(*hwpipe), GFP_KERNEL); + hwpipe = devm_kzalloc(dev->dev, sizeof(*hwpipe), GFP_KERNEL); if (!hwpipe) return ERR_PTR(-ENOMEM); diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.h index cca67938cab213..452138821f6008 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.h +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_pipe.h @@ -39,8 +39,8 @@ int mdp5_pipe_assign(struct drm_atomic_state *s, struct drm_plane *plane, struct mdp5_hw_pipe **r_hwpipe); int mdp5_pipe_release(struct drm_atomic_state *s, struct mdp5_hw_pipe *hwpipe); -struct mdp5_hw_pipe *mdp5_pipe_init(enum mdp5_pipe pipe, +struct mdp5_hw_pipe *mdp5_pipe_init(struct drm_device *dev, + enum mdp5_pipe pipe, uint32_t reg_offset, uint32_t caps); -void mdp5_pipe_destroy(struct mdp5_hw_pipe *hwpipe); #endif /* __MDP5_PIPE_H__ */ diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c index b68682c1b5bcfa..8b59562e29e284 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.c @@ -370,23 +370,17 @@ void mdp5_smp_dump(struct mdp5_smp *smp, struct drm_printer *p) drm_modeset_unlock(&mdp5_kms->glob_state_lock); } -void mdp5_smp_destroy(struct mdp5_smp *smp) -{ - kfree(smp); -} struct mdp5_smp *mdp5_smp_init(struct mdp5_kms *mdp5_kms, const struct mdp5_smp_block *cfg) { + struct drm_device *dev = mdp5_kms->dev; struct mdp5_smp_state *state; struct mdp5_global_state *global_state; struct mdp5_smp *smp; - int ret; - smp = kzalloc(sizeof(*smp), GFP_KERNEL); - if (unlikely(!smp)) { - ret = -ENOMEM; - goto fail; - } + smp = devm_kzalloc(dev->dev, sizeof(*smp), GFP_KERNEL); + if (unlikely(!smp)) + return ERR_PTR(-ENOMEM); smp->dev = mdp5_kms->dev; smp->blk_cnt = cfg->mmb_count; @@ -400,9 +394,4 @@ struct mdp5_smp *mdp5_smp_init(struct mdp5_kms *mdp5_kms, const struct mdp5_smp_ memcpy(smp->reserved, cfg->reserved, sizeof(smp->reserved)); return smp; -fail: - if (smp) - mdp5_smp_destroy(smp); - - return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.h b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.h index ba5618e136c3d8..d8b6a11413d931 100644 --- a/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.h +++ b/drivers/gpu/drm/msm/disp/mdp5/mdp5_smp.h @@ -68,7 +68,6 @@ struct mdp5_smp; struct mdp5_smp *mdp5_smp_init(struct mdp5_kms *mdp5_kms, const struct mdp5_smp_block *cfg); -void mdp5_smp_destroy(struct mdp5_smp *smp); void mdp5_smp_dump(struct mdp5_smp *smp, struct drm_printer *p); diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c index 8e3b677f35e64f..03f4951c49f42d 100644 --- a/drivers/gpu/drm/msm/dp/dp_aux.c +++ b/drivers/gpu/drm/msm/dp/dp_aux.c @@ -291,6 +291,10 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *dp_aux, return -EINVAL; } + ret = pm_runtime_resume_and_get(dp_aux->dev); + if (ret) + return ret; + mutex_lock(&aux->mutex); if (!aux->initted) { ret = -EIO; @@ -364,6 +368,7 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *dp_aux, exit: mutex_unlock(&aux->mutex); + pm_runtime_put_sync(dp_aux->dev); return ret; } @@ -474,7 +479,6 @@ void dp_aux_deinit(struct drm_dp_aux *dp_aux) int dp_aux_register(struct drm_dp_aux *dp_aux) { - struct dp_aux_private *aux; int ret; if (!dp_aux) { @@ -482,12 +486,7 @@ int dp_aux_register(struct drm_dp_aux *dp_aux) return -EINVAL; } - aux = container_of(dp_aux, struct dp_aux_private, dp_aux); - - aux->dp_aux.name = "dpu_dp_aux"; - aux->dp_aux.dev = aux->dev; - aux->dp_aux.transfer = dp_aux_transfer; - ret = drm_dp_aux_register(&aux->dp_aux); + ret = drm_dp_aux_register(dp_aux); if (ret) { DRM_ERROR("%s: failed to register drm aux: %d\n", __func__, ret); @@ -502,6 +501,21 @@ void dp_aux_unregister(struct drm_dp_aux *dp_aux) drm_dp_aux_unregister(dp_aux); } +static int dp_wait_hpd_asserted(struct drm_dp_aux *dp_aux, + unsigned long wait_us) +{ + int ret; + struct dp_aux_private *aux; + + aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + + pm_runtime_get_sync(aux->dev); + ret = dp_catalog_aux_wait_for_hpd_connect_state(aux->catalog); + pm_runtime_put_sync(aux->dev); + + return ret; +} + struct drm_dp_aux *dp_aux_get(struct device *dev, struct dp_catalog *catalog, bool is_edp) { @@ -525,6 +539,17 @@ struct drm_dp_aux *dp_aux_get(struct device *dev, struct dp_catalog *catalog, aux->catalog = catalog; aux->retry_cnt = 0; + /* + * Use the drm_dp_aux_init() to use the aux adapter + * before registering AUX with the DRM device so that + * msm eDP panel can be detected by generic_dep_panel_probe(). + */ + aux->dp_aux.name = "dpu_dp_aux"; + aux->dp_aux.dev = dev; + aux->dp_aux.transfer = dp_aux_transfer; + aux->dp_aux.wait_hpd_asserted = dp_wait_hpd_asserted; + drm_dp_aux_init(&aux->dp_aux); + return &aux->dp_aux; } diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c b/drivers/gpu/drm/msm/dp/dp_debug.c index 3bba901afe3354..6c281dc095b9a0 100644 --- a/drivers/gpu/drm/msm/dp/dp_debug.c +++ b/drivers/gpu/drm/msm/dp/dp_debug.c @@ -19,13 +19,9 @@ #define DEBUG_NAME "msm_dp" struct dp_debug_private { - struct dentry *root; - struct dp_link *link; struct dp_panel *panel; struct drm_connector *connector; - struct device *dev; - struct drm_device *drm_dev; struct dp_debug dp_debug; }; @@ -204,35 +200,33 @@ static const struct file_operations test_active_fops = { .write = dp_test_active_write }; -static void dp_debug_init(struct dp_debug *dp_debug, struct drm_minor *minor) +static void dp_debug_init(struct dp_debug *dp_debug, struct dentry *root, bool is_edp) { - char path[64]; struct dp_debug_private *debug = container_of(dp_debug, struct dp_debug_private, dp_debug); - snprintf(path, sizeof(path), "msm_dp-%s", debug->connector->name); - - debug->root = debugfs_create_dir(path, minor->debugfs_root); - - debugfs_create_file("dp_debug", 0444, debug->root, + debugfs_create_file("dp_debug", 0444, root, debug, &dp_debug_fops); - debugfs_create_file("msm_dp_test_active", 0444, - debug->root, - debug, &test_active_fops); + if (!is_edp) { + debugfs_create_file("msm_dp_test_active", 0444, + root, + debug, &test_active_fops); - debugfs_create_file("msm_dp_test_data", 0444, - debug->root, - debug, &dp_test_data_fops); + debugfs_create_file("msm_dp_test_data", 0444, + root, + debug, &dp_test_data_fops); - debugfs_create_file("msm_dp_test_type", 0444, - debug->root, - debug, &dp_test_type_fops); + debugfs_create_file("msm_dp_test_type", 0444, + root, + debug, &dp_test_type_fops); + } } struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel, struct dp_link *link, - struct drm_connector *connector, struct drm_minor *minor) + struct drm_connector *connector, + struct dentry *root, bool is_edp) { struct dp_debug_private *debug; struct dp_debug *dp_debug; @@ -253,46 +247,15 @@ struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel, debug->dp_debug.debug_en = false; debug->link = link; debug->panel = panel; - debug->dev = dev; - debug->drm_dev = minor->dev; - debug->connector = connector; dp_debug = &debug->dp_debug; dp_debug->vdisplay = 0; dp_debug->hdisplay = 0; dp_debug->vrefresh = 0; - dp_debug_init(dp_debug, minor); + dp_debug_init(dp_debug, root, is_edp); return dp_debug; error: return ERR_PTR(rc); } - -static int dp_debug_deinit(struct dp_debug *dp_debug) -{ - struct dp_debug_private *debug; - - if (!dp_debug) - return -EINVAL; - - debug = container_of(dp_debug, struct dp_debug_private, dp_debug); - - debugfs_remove_recursive(debug->root); - - return 0; -} - -void dp_debug_put(struct dp_debug *dp_debug) -{ - struct dp_debug_private *debug; - - if (!dp_debug) - return; - - debug = container_of(dp_debug, struct dp_debug_private, dp_debug); - - dp_debug_deinit(dp_debug); - - devm_kfree(debug->dev, debug); -} diff --git a/drivers/gpu/drm/msm/dp/dp_debug.h b/drivers/gpu/drm/msm/dp/dp_debug.h index 124227873d58cb..9b3b2e702f6550 100644 --- a/drivers/gpu/drm/msm/dp/dp_debug.h +++ b/drivers/gpu/drm/msm/dp/dp_debug.h @@ -34,7 +34,8 @@ struct dp_debug { * @panel: instance of panel module * @link: instance of link module * @connector: double pointer to display connector - * @minor: pointer to drm minor number after device registration + * @root: connector's debugfs root + * @is_edp: set for eDP connectors / panels * return: pointer to allocated debug module data * * This function sets up the debug module and provides a way @@ -43,31 +44,21 @@ struct dp_debug { struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel, struct dp_link *link, struct drm_connector *connector, - struct drm_minor *minor); - -/** - * dp_debug_put() - * - * Cleans up dp_debug instance - * - * @dp_debug: instance of dp_debug - */ -void dp_debug_put(struct dp_debug *dp_debug); + struct dentry *root, + bool is_edp); #else static inline struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel, struct dp_link *link, - struct drm_connector *connector, struct drm_minor *minor) + struct drm_connector *connector, + struct dentry *root, + bool is_edp) { return ERR_PTR(-EINVAL); } -static inline void dp_debug_put(struct dp_debug *dp_debug) -{ -} - #endif /* defined(CONFIG_DEBUG_FS) */ #endif /* _DP_DEBUG_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 1b88fb52726f24..d37d599aec273b 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -49,13 +49,11 @@ enum { ST_CONNECTED, ST_DISCONNECT_PENDING, ST_DISPLAY_OFF, - ST_SUSPENDED, }; enum { EV_NO_EVENT, /* hpd events */ - EV_HPD_INIT_SETUP, EV_HPD_PLUG_INT, EV_IRQ_HPD_INT, EV_HPD_UNPLUG_INT, @@ -170,6 +168,11 @@ static const struct msm_dp_desc sm8350_dp_descs[] = { {} }; +static const struct msm_dp_desc sm8650_dp_descs[] = { + { .io_start = 0x0af54000, .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_descs }, { .compatible = "qcom,sc7280-dp", .data = &sc7280_dp_descs }, @@ -180,6 +183,7 @@ static const struct of_device_id dp_dt_match[] = { { .compatible = "qcom,sc8280xp-edp", .data = &sc8280xp_edp_descs }, { .compatible = "qcom,sdm845-dp", .data = &sc7180_dp_descs }, { .compatible = "qcom,sm8350-dp", .data = &sm8350_dp_descs }, + { .compatible = "qcom,sm8650-dp", .data = &sm8650_dp_descs }, {} }; @@ -275,11 +279,6 @@ static int dp_display_bind(struct device *dev, struct device *master, dp->dp_display.drm_dev = drm; priv->dp[dp->id] = &dp->dp_display; - rc = dp->parser->parse(dp->parser); - if (rc) { - DRM_ERROR("device tree parsing failed\n"); - goto end; - } dp->drm_dev = drm; @@ -290,11 +289,6 @@ static int dp_display_bind(struct device *dev, struct device *master, goto end; } - rc = dp_power_client_init(dp->power); - if (rc) { - DRM_ERROR("Power client create failed\n"); - goto end; - } rc = dp_register_audio_driver(dev, dp->audio); if (rc) { @@ -319,15 +313,10 @@ static void dp_display_unbind(struct device *dev, struct device *master, struct dp_display_private *dp = dev_get_dp_display_private(dev); struct msm_drm_private *priv = dev_get_drvdata(master); - /* disable all HPD interrupts */ - if (dp->core_initialized) - dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_INT_MASK, false); - kthread_stop(dp->ev_tsk); of_dp_aux_depopulate_bus(dp->aux); - dp_power_client_deinit(dp->power); dp_unregister_audio_driver(dev, dp->audio); dp_aux_unregister(dp->aux); dp->drm_dev = NULL; @@ -340,27 +329,10 @@ static const struct component_ops dp_display_comp_ops = { .unbind = dp_display_unbind, }; -static void dp_display_send_hpd_event(struct msm_dp *dp_display) -{ - struct dp_display_private *dp; - struct drm_connector *connector; - - dp = container_of(dp_display, struct dp_display_private, dp_display); - - connector = dp->dp_display.connector; - drm_helper_hpd_irq_event(connector->dev); -} - - static int dp_display_send_hpd_notification(struct dp_display_private *dp, bool hpd) { - if ((hpd && dp->dp_display.is_connected) || - (!hpd && !dp->dp_display.is_connected)) { - drm_dbg_dp(dp->drm_dev, "HPD already %s\n", - (hpd ? "on" : "off")); - return 0; - } + struct drm_bridge *bridge = dp->dp_display.bridge; /* reset video pattern flag on disconnect */ if (!hpd) { @@ -372,11 +344,11 @@ static int dp_display_send_hpd_notification(struct dp_display_private *dp, dp->panel->downstream_ports); } - dp->dp_display.is_connected = hpd; + dp->dp_display.link_ready = hpd; drm_dbg_dp(dp->drm_dev, "type=%d hpd=%d\n", dp->dp_display.connector_type, hpd); - dp_display_send_hpd_event(&dp->dp_display); + drm_bridge_hpd_notify(bridge, dp->dp_display.link_ready); return 0; } @@ -575,6 +547,7 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) { u32 state; int ret; + struct platform_device *pdev = dp->dp_display.pdev; mutex_lock(&dp->event_mutex); @@ -582,7 +555,7 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n", dp->dp_display.connector_type, state); - if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) { + if (state == ST_DISPLAY_OFF) { mutex_unlock(&dp->event_mutex); return 0; } @@ -599,7 +572,14 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data) return 0; } - ret = dp_display_usbpd_configure_cb(&dp->dp_display.pdev->dev); + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret) { + DRM_ERROR("failed to pm_runtime_resume\n"); + mutex_unlock(&dp->event_mutex); + return ret; + } + + ret = dp_display_usbpd_configure_cb(&pdev->dev); if (ret) { /* link train failed */ dp->hpd_state = ST_DISCONNECTED; } else { @@ -631,6 +611,7 @@ static void dp_display_handle_plugged_change(struct msm_dp *dp_display, static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) { u32 state; + struct platform_device *pdev = dp->dp_display.pdev; mutex_lock(&dp->event_mutex); @@ -681,6 +662,7 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data) dp->dp_display.connector_type, state); /* uevent will complete disconnection part */ + pm_runtime_put_sync(&pdev->dev); mutex_unlock(&dp->event_mutex); return 0; } @@ -696,7 +678,7 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data) drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n", dp->dp_display.connector_type, state); - if (state == ST_DISPLAY_OFF || state == ST_SUSPENDED) { + if (state == ST_DISPLAY_OFF) { mutex_unlock(&dp->event_mutex); return 0; } @@ -720,7 +702,6 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data) static void dp_display_deinit_sub_modules(struct dp_display_private *dp) { - dp_debug_put(dp->debug); dp_audio_put(dp->audio); dp_panel_put(dp->panel); dp_aux_put(dp->aux); @@ -918,7 +899,7 @@ int dp_display_set_plugged_cb(struct msm_dp *dp_display, dp_display->plugged_cb = fn; dp_display->codec_dev = codec_dev; - plugged = dp_display->is_connected; + plugged = dp_display->link_ready; dp_display_handle_plugged_change(dp_display, plugged); return 0; @@ -1108,9 +1089,6 @@ static int hpd_event_thread(void *data) spin_unlock_irqrestore(&dp_priv->event_lock, flag); switch (todo->event_id) { - case EV_HPD_INIT_SETUP: - dp_display_host_init(dp_priv); - break; case EV_HPD_PLUG_INT: dp_hpd_plug_handle(dp_priv, todo->data); break; @@ -1189,27 +1167,21 @@ static irqreturn_t dp_display_irq_handler(int irq, void *dev_id) return ret; } -int dp_display_request_irq(struct msm_dp *dp_display) +static int dp_display_request_irq(struct dp_display_private *dp) { int rc = 0; - struct dp_display_private *dp; - - if (!dp_display) { - DRM_ERROR("invalid input\n"); - return -EINVAL; - } + struct platform_device *pdev = dp->dp_display.pdev; - dp = container_of(dp_display, struct dp_display_private, dp_display); - - dp->irq = irq_of_parse_and_map(dp->dp_display.pdev->dev.of_node, 0); - if (!dp->irq) { + dp->irq = platform_get_irq(pdev, 0); + if (dp->irq < 0) { DRM_ERROR("failed to get irq\n"); - return -EINVAL; + return dp->irq; } - rc = devm_request_irq(dp_display->drm_dev->dev, dp->irq, - dp_display_irq_handler, - IRQF_TRIGGER_HIGH, "dp_display_isr", dp); + rc = devm_request_irq(&pdev->dev, dp->irq, dp_display_irq_handler, + IRQF_TRIGGER_HIGH|IRQF_NO_AUTOEN, + "dp_display_isr", dp); + if (rc < 0) { DRM_ERROR("failed to request IRQ%u: %d\n", dp->irq, rc); @@ -1238,6 +1210,29 @@ static const struct msm_dp_desc *dp_display_get_desc(struct platform_device *pde return NULL; } +static int dp_display_get_next_bridge(struct msm_dp *dp); + +static int dp_display_probe_tail(struct device *dev) +{ + struct msm_dp *dp = dev_get_drvdata(dev); + int ret; + + ret = dp_display_get_next_bridge(dp); + if (ret) + return ret; + + ret = component_add(dev, &dp_display_comp_ops); + if (ret) + DRM_ERROR("component add failed, rc=%d\n", ret); + + return ret; +} + +static int dp_auxbus_done_probe(struct drm_dp_aux *aux) +{ + return dp_display_probe_tail(aux->dev); +} + static int dp_display_probe(struct platform_device *pdev) { int rc = 0; @@ -1271,6 +1266,18 @@ static int dp_display_probe(struct platform_device *pdev) return -EPROBE_DEFER; } + rc = dp->parser->parse(dp->parser); + if (rc) { + DRM_ERROR("device tree parsing failed\n"); + goto err; + } + + rc = dp_power_client_init(dp->power); + if (rc) { + DRM_ERROR("Power client create failed\n"); + goto err; + } + /* setup event q */ mutex_init(&dp->event_mutex); init_waitqueue_head(&dp->event_q); @@ -1283,13 +1290,31 @@ static int dp_display_probe(struct platform_device *pdev) platform_set_drvdata(pdev, &dp->dp_display); - rc = component_add(&pdev->dev, &dp_display_comp_ops); - if (rc) { - DRM_ERROR("component add failed, rc=%d\n", rc); - dp_display_deinit_sub_modules(dp); + rc = devm_pm_runtime_enable(&pdev->dev); + if (rc) + goto err; + + rc = dp_display_request_irq(dp); + if (rc) + goto err; + + if (dp->dp_display.is_edp) { + rc = devm_of_dp_aux_populate_bus(dp->aux, dp_auxbus_done_probe); + if (rc) { + DRM_ERROR("eDP auxbus population failed, rc=%d\n", rc); + goto err; + } + } else { + rc = dp_display_probe_tail(&pdev->dev); + if (rc) + goto err; } return rc; + +err: + dp_display_deinit_sub_modules(dp); + return rc; } static void dp_display_remove(struct platform_device *pdev) @@ -1298,113 +1323,50 @@ static void dp_display_remove(struct platform_device *pdev) component_del(&pdev->dev, &dp_display_comp_ops); dp_display_deinit_sub_modules(dp); - platform_set_drvdata(pdev, NULL); } -static int dp_pm_resume(struct device *dev) +static int dp_pm_runtime_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct msm_dp *dp_display = platform_get_drvdata(pdev); - struct dp_display_private *dp; - int sink_count = 0; - - dp = container_of(dp_display, struct dp_display_private, dp_display); - - mutex_lock(&dp->event_mutex); - - drm_dbg_dp(dp->drm_dev, - "Before, type=%d core_inited=%d phy_inited=%d power_on=%d\n", - dp->dp_display.connector_type, dp->core_initialized, - dp->phy_initialized, dp_display->power_on); - - /* start from disconnected state */ - dp->hpd_state = ST_DISCONNECTED; - - /* turn on dp ctrl/phy */ - dp_display_host_init(dp); - - if (dp_display->is_edp) - dp_catalog_ctrl_hpd_enable(dp->catalog); + struct dp_display_private *dp = dev_get_dp_display_private(dev); - if (dp_catalog_link_is_connected(dp->catalog)) { - /* - * set sink to normal operation mode -- D0 - * before dpcd read - */ - dp_display_host_phy_init(dp); - dp_link_psm_config(dp->link, &dp->panel->link_info, false); - sink_count = drm_dp_read_sink_count(dp->aux); - if (sink_count < 0) - sink_count = 0; + disable_irq(dp->irq); + if (dp->dp_display.is_edp) { dp_display_host_phy_exit(dp); + dp_catalog_ctrl_hpd_disable(dp->catalog); } - - dp->link->sink_count = sink_count; - /* - * can not declared display is connected unless - * HDMI cable is plugged in and sink_count of - * dongle become 1 - * also only signal audio when disconnected - */ - if (dp->link->sink_count) { - dp->dp_display.is_connected = true; - } else { - dp->dp_display.is_connected = false; - dp_display_handle_plugged_change(dp_display, false); - } - - drm_dbg_dp(dp->drm_dev, - "After, type=%d sink=%d conn=%d core_init=%d phy_init=%d power=%d\n", - dp->dp_display.connector_type, dp->link->sink_count, - dp->dp_display.is_connected, dp->core_initialized, - dp->phy_initialized, dp_display->power_on); - - mutex_unlock(&dp->event_mutex); + dp_display_host_deinit(dp); return 0; } -static int dp_pm_suspend(struct device *dev) +static int dp_pm_runtime_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct msm_dp *dp_display = platform_get_drvdata(pdev); - struct dp_display_private *dp; - - dp = container_of(dp_display, struct dp_display_private, dp_display); - - mutex_lock(&dp->event_mutex); - - drm_dbg_dp(dp->drm_dev, - "Before, type=%d core_inited=%d phy_inited=%d power_on=%d\n", - dp->dp_display.connector_type, dp->core_initialized, - dp->phy_initialized, dp_display->power_on); - - /* mainlink enabled */ - if (dp_power_clk_status(dp->power, DP_CTRL_PM)) - dp_ctrl_off_link_stream(dp->ctrl); - - dp_display_host_phy_exit(dp); - - /* host_init will be called at pm_resume */ - dp_display_host_deinit(dp); - - dp->hpd_state = ST_SUSPENDED; - - drm_dbg_dp(dp->drm_dev, - "After, type=%d core_inited=%d phy_inited=%d power_on=%d\n", - dp->dp_display.connector_type, dp->core_initialized, - dp->phy_initialized, dp_display->power_on); + struct dp_display_private *dp = dev_get_dp_display_private(dev); - mutex_unlock(&dp->event_mutex); + /* + * for eDP, host cotroller, HPD block and PHY are enabled here + * but with HPD irq disabled + * + * for DP, only host controller is enabled here. + * HPD block is enabled at dp_bridge_hpd_enable() + * PHY will be enabled at plugin handler later + */ + dp_display_host_init(dp); + if (dp->dp_display.is_edp) { + dp_catalog_ctrl_hpd_enable(dp->catalog); + dp_display_host_phy_init(dp); + } + enable_irq(dp->irq); return 0; } static const struct dev_pm_ops dp_pm_ops = { - .suspend = dp_pm_suspend, - .resume = dp_pm_resume, + SET_RUNTIME_PM_OPS(dp_pm_runtime_suspend, dp_pm_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; static struct platform_driver dp_display_driver = { @@ -1434,19 +1396,6 @@ void __exit msm_dp_unregister(void) platform_driver_unregister(&dp_display_driver); } -void msm_dp_irq_postinstall(struct msm_dp *dp_display) -{ - struct dp_display_private *dp; - - if (!dp_display) - return; - - 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, 0); -} - bool msm_dp_wide_bus_available(const struct msm_dp *dp_display) { struct dp_display_private *dp; @@ -1456,7 +1405,7 @@ bool msm_dp_wide_bus_available(const struct msm_dp *dp_display) return dp->wide_bus_en; } -void msm_dp_debugfs_init(struct msm_dp *dp_display, struct drm_minor *minor) +void dp_display_debugfs_init(struct msm_dp *dp_display, struct dentry *root, bool is_edp) { struct dp_display_private *dp; struct device *dev; @@ -1467,7 +1416,7 @@ void msm_dp_debugfs_init(struct msm_dp *dp_display, struct drm_minor *minor) dp->debug = dp_debug_get(dev, dp->panel, dp->link, dp->dp_display.connector, - minor); + root, is_edp); if (IS_ERR(dp->debug)) { rc = PTR_ERR(dp->debug); DRM_ERROR("failed to initialize debug, rc = %d\n", rc); @@ -1479,33 +1428,8 @@ static int dp_display_get_next_bridge(struct msm_dp *dp) { int rc; struct dp_display_private *dp_priv; - struct device_node *aux_bus; - struct device *dev; dp_priv = container_of(dp, struct dp_display_private, dp_display); - dev = &dp_priv->dp_display.pdev->dev; - aux_bus = of_get_child_by_name(dev->of_node, "aux-bus"); - - if (aux_bus && dp->is_edp) { - dp_display_host_init(dp_priv); - dp_catalog_ctrl_hpd_enable(dp_priv->catalog); - dp_display_host_phy_init(dp_priv); - - /* - * The code below assumes that the panel will finish probing - * by the time devm_of_dp_aux_populate_ep_devices() returns. - * This isn't a great assumption since it will fail if the - * panel driver is probed asynchronously but is the best we - * can do without a bigger driver reorganization. - */ - rc = of_dp_aux_populate_bus(dp_priv->aux, NULL); - of_node_put(aux_bus); - if (rc) - goto error; - } else if (dp->is_edp) { - DRM_ERROR("eDP aux_bus not found\n"); - return -ENODEV; - } /* * External bridges are mandatory for eDP interfaces: one has to @@ -1514,21 +1438,13 @@ static int dp_display_get_next_bridge(struct msm_dp *dp) * For DisplayPort interfaces external bridges are optional, so * silently ignore an error if one is not present (-ENODEV). */ - rc = devm_dp_parser_find_next_bridge(dp->drm_dev->dev, dp_priv->parser); + rc = devm_dp_parser_find_next_bridge(&dp->pdev->dev, dp_priv->parser); if (!dp->is_edp && rc == -ENODEV) return 0; - if (!rc) { + if (!rc) dp->next_bridge = dp_priv->parser->next_bridge; - return 0; - } -error: - if (dp->is_edp) { - of_dp_aux_depopulate_bus(dp_priv->aux); - dp_display_host_phy_exit(dp_priv); - dp_display_host_deinit(dp_priv); - } return rc; } @@ -1542,16 +1458,6 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev, dp_priv = container_of(dp_display, struct dp_display_private, dp_display); - ret = dp_display_request_irq(dp_display); - if (ret) { - DRM_ERROR("request_irq failed, ret=%d\n", ret); - return ret; - } - - ret = dp_display_get_next_bridge(dp_display); - if (ret) - return ret; - ret = dp_bridge_init(dp_display, dev, encoder); if (ret) { DRM_DEV_ERROR(dev->dev, @@ -1593,6 +1499,11 @@ void dp_bridge_atomic_enable(struct drm_bridge *drm_bridge, dp_hpd_plug_handle(dp_display, 0); mutex_lock(&dp_display->event_mutex); + if (pm_runtime_resume_and_get(&dp->pdev->dev)) { + DRM_ERROR("failed to pm_runtime_resume\n"); + mutex_unlock(&dp_display->event_mutex); + return; + } state = dp_display->hpd_state; if (state != ST_DISPLAY_OFF && state != ST_MAINLINK_READY) { @@ -1657,10 +1568,9 @@ void dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge, mutex_lock(&dp_display->event_mutex); state = dp_display->hpd_state; - if (state != ST_DISCONNECT_PENDING && state != ST_CONNECTED) { - mutex_unlock(&dp_display->event_mutex); - return; - } + if (state != ST_DISCONNECT_PENDING && state != ST_CONNECTED) + drm_dbg_dp(dp->drm_dev, "type=%d wrong hpd_state=%d\n", + dp->connector_type, state); dp_display_disable(dp_display); @@ -1673,6 +1583,8 @@ void dp_bridge_atomic_post_disable(struct drm_bridge *drm_bridge, } drm_dbg_dp(dp->drm_dev, "type=%d Done\n", dp->connector_type); + + pm_runtime_put_sync(&dp->pdev->dev); mutex_unlock(&dp_display->event_mutex); } @@ -1711,7 +1623,21 @@ void dp_bridge_hpd_enable(struct drm_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); + /* + * this is for external DP with hpd irq enabled case, + * step-1: dp_pm_runtime_resume() enable dp host only + * step-2: enable hdp block and have hpd irq enabled here + * step-3: waiting for plugin irq while phy is not initialized + * step-4: DP PHY is initialized at plugin handler before link training + * + */ mutex_lock(&dp->event_mutex); + if (pm_runtime_resume_and_get(&dp_display->pdev->dev)) { + DRM_ERROR("failed to resume power\n"); + mutex_unlock(&dp->event_mutex); + return; + } + dp_catalog_ctrl_hpd_enable(dp->catalog); /* enable HDP interrupts */ @@ -1733,6 +1659,8 @@ void dp_bridge_hpd_disable(struct drm_bridge *bridge) dp_catalog_ctrl_hpd_disable(dp->catalog); dp_display->internal_hpd = false; + + pm_runtime_put_sync(&dp_display->pdev->dev); mutex_unlock(&dp->event_mutex); } @@ -1747,13 +1675,8 @@ void dp_bridge_hpd_notify(struct drm_bridge *bridge, 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) + if (!dp_display->link_ready && status == connector_status_connected) dp_add_event(dp, EV_HPD_PLUG_INT, 0, 0); - else if (dp_display->is_connected && status == connector_status_disconnected) + else if (dp_display->link_ready && 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 f66cdbc357856b..102f3507d82474 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.h +++ b/drivers/gpu/drm/msm/dp/dp_display.h @@ -17,7 +17,7 @@ struct msm_dp { struct drm_bridge *bridge; struct drm_connector *connector; struct drm_bridge *next_bridge; - bool is_connected; + bool link_ready; bool audio_enabled; bool power_on; unsigned int connector_type; @@ -36,11 +36,11 @@ struct msm_dp { int dp_display_set_plugged_cb(struct msm_dp *dp_display, hdmi_codec_plugged_cb fn, struct device *codec_dev); int dp_display_get_modes(struct msm_dp *dp_display); -int dp_display_request_irq(struct msm_dp *dp_display); bool dp_display_check_video_test(struct msm_dp *dp_display); int dp_display_get_test_bpp(struct msm_dp *dp_display); void dp_display_signal_audio_start(struct msm_dp *dp_display); void dp_display_signal_audio_complete(struct msm_dp *dp_display); void dp_display_set_psr(struct msm_dp *dp, bool enter); +void dp_display_debugfs_init(struct msm_dp *dp_display, struct dentry *dentry, bool is_edp); #endif /* _DP_DISPLAY_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c index e3bdd7dd4cdc7d..46e6889037e888 100644 --- a/drivers/gpu/drm/msm/dp/dp_drm.c +++ b/drivers/gpu/drm/msm/dp/dp_drm.c @@ -24,10 +24,10 @@ static enum drm_connector_status dp_bridge_detect(struct drm_bridge *bridge) dp = to_dp_bridge(bridge)->dp_display; - drm_dbg_dp(dp->drm_dev, "is_connected = %s\n", - (dp->is_connected) ? "true" : "false"); + drm_dbg_dp(dp->drm_dev, "link_ready = %s\n", + (dp->link_ready) ? "true" : "false"); - return (dp->is_connected) ? connector_status_connected : + return (dp->link_ready) ? connector_status_connected : connector_status_disconnected; } @@ -40,8 +40,8 @@ static int dp_bridge_atomic_check(struct drm_bridge *bridge, dp = to_dp_bridge(bridge)->dp_display; - drm_dbg_dp(dp->drm_dev, "is_connected = %s\n", - (dp->is_connected) ? "true" : "false"); + drm_dbg_dp(dp->drm_dev, "link_ready = %s\n", + (dp->link_ready) ? "true" : "false"); /* * There is no protection in the DRM framework to check if the display @@ -55,7 +55,7 @@ static int dp_bridge_atomic_check(struct drm_bridge *bridge, * After that this piece of code can be removed. */ if (bridge->ops & DRM_BRIDGE_OP_HPD) - return (dp->is_connected) ? 0 : -ENOTCONN; + return (dp->link_ready) ? 0 : -ENOTCONN; return 0; } @@ -78,7 +78,7 @@ static int dp_bridge_get_modes(struct drm_bridge *bridge, struct drm_connector * dp = to_dp_bridge(bridge)->dp_display; /* pluggable case assumes EDID is read when HPD */ - if (dp->is_connected) { + if (dp->link_ready) { rc = dp_display_get_modes(dp); if (rc <= 0) { DRM_ERROR("failed to get DP sink modes, rc=%d\n", rc); @@ -90,6 +90,13 @@ static int dp_bridge_get_modes(struct drm_bridge *bridge, struct drm_connector * return rc; } +static void dp_bridge_debugfs_init(struct drm_bridge *bridge, struct dentry *root) +{ + struct msm_dp *dp = to_dp_bridge(bridge)->dp_display; + + dp_display_debugfs_init(dp, root, false); +} + static const struct drm_bridge_funcs dp_bridge_ops = { .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, @@ -105,6 +112,7 @@ static const struct drm_bridge_funcs dp_bridge_ops = { .hpd_enable = dp_bridge_hpd_enable, .hpd_disable = dp_bridge_hpd_disable, .hpd_notify = dp_bridge_hpd_notify, + .debugfs_init = dp_bridge_debugfs_init, }; static int edp_bridge_atomic_check(struct drm_bridge *drm_bridge, @@ -260,6 +268,13 @@ static enum drm_mode_status edp_bridge_mode_valid(struct drm_bridge *bridge, return MODE_OK; } +static void edp_bridge_debugfs_init(struct drm_bridge *bridge, struct dentry *root) +{ + struct msm_dp *dp = to_dp_bridge(bridge)->dp_display; + + dp_display_debugfs_init(dp, root, true); +} + static const struct drm_bridge_funcs edp_bridge_ops = { .atomic_enable = edp_bridge_atomic_enable, .atomic_disable = edp_bridge_atomic_disable, @@ -270,6 +285,7 @@ static const struct drm_bridge_funcs edp_bridge_ops = { .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, .atomic_check = edp_bridge_atomic_check, + .debugfs_init = edp_bridge_debugfs_init, }; int dp_bridge_init(struct msm_dp *dp_display, struct drm_device *dev, diff --git a/drivers/gpu/drm/msm/dp/dp_power.c b/drivers/gpu/drm/msm/dp/dp_power.c index 5cb84ca40e9ed6..c4843dd69f4797 100644 --- a/drivers/gpu/drm/msm/dp/dp_power.c +++ b/drivers/gpu/drm/msm/dp/dp_power.c @@ -152,45 +152,17 @@ int dp_power_client_init(struct dp_power *dp_power) power = container_of(dp_power, struct dp_power_private, dp_power); - pm_runtime_enable(power->dev); - return dp_power_clk_init(power); } -void dp_power_client_deinit(struct dp_power *dp_power) -{ - struct dp_power_private *power; - - power = container_of(dp_power, struct dp_power_private, dp_power); - - pm_runtime_disable(power->dev); -} - int dp_power_init(struct dp_power *dp_power) { - int rc = 0; - struct dp_power_private *power = NULL; - - power = container_of(dp_power, struct dp_power_private, dp_power); - - pm_runtime_get_sync(power->dev); - - rc = dp_power_clk_enable(dp_power, DP_CORE_PM, true); - if (rc) - pm_runtime_put_sync(power->dev); - - return rc; + return dp_power_clk_enable(dp_power, DP_CORE_PM, true); } int dp_power_deinit(struct dp_power *dp_power) { - struct dp_power_private *power; - - power = container_of(dp_power, struct dp_power_private, dp_power); - - dp_power_clk_enable(dp_power, DP_CORE_PM, false); - pm_runtime_put_sync(power->dev); - return 0; + return dp_power_clk_enable(dp_power, DP_CORE_PM, false); } struct dp_power *dp_power_get(struct device *dev, struct dp_parser *parser) diff --git a/drivers/gpu/drm/msm/dp/dp_power.h b/drivers/gpu/drm/msm/dp/dp_power.h index a3dec200785e5f..55ada51edb57ba 100644 --- a/drivers/gpu/drm/msm/dp/dp_power.h +++ b/drivers/gpu/drm/msm/dp/dp_power.h @@ -80,17 +80,6 @@ int dp_power_clk_enable(struct dp_power *power, enum dp_pm_type pm_type, */ int dp_power_client_init(struct dp_power *power); -/** - * dp_power_clinet_deinit() - de-initialize clock and regulator modules - * - * @power: instance of power module - * return: 0 for success, error for failure. - * - * This API will de-initialize the DisplayPort's clocks and regulator - * modules. - */ -void dp_power_client_deinit(struct dp_power *power); - /** * dp_power_get() - configure and get the DisplayPort power module data * diff --git a/drivers/gpu/drm/msm/dsi/dsi_cfg.c b/drivers/gpu/drm/msm/dsi/dsi_cfg.c index 1f98ff74ceb09d..10ba7d153d1cfc 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_cfg.c +++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.c @@ -190,6 +190,21 @@ static const struct msm_dsi_config sm8550_dsi_cfg = { }, }; +static const struct regulator_bulk_data sm8650_dsi_regulators[] = { + { .supply = "vdda", .init_load_uA = 16600 }, /* 1.2 V */ +}; + +static const struct msm_dsi_config sm8650_dsi_cfg = { + .io_offset = DSI_6G_REG_SHIFT, + .regulator_data = sm8650_dsi_regulators, + .num_regulators = ARRAY_SIZE(sm8650_dsi_regulators), + .bus_clk_names = dsi_v2_4_clk_names, + .num_bus_clks = ARRAY_SIZE(dsi_v2_4_clk_names), + .io_start = { + { 0xae94000, 0xae96000 }, + }, +}; + static const struct regulator_bulk_data sc7280_dsi_regulators[] = { { .supply = "vdda", .init_load_uA = 8350 }, /* 1.2 V */ { .supply = "refgen" }, @@ -281,6 +296,8 @@ static const struct msm_dsi_cfg_handler dsi_cfg_handlers[] = { &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}, + {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V2_8_0, + &sm8650_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 43f0dd74edb656..4c9b4b37681b06 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_cfg.h +++ b/drivers/gpu/drm/msm/dsi/dsi_cfg.h @@ -28,6 +28,7 @@ #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_6G_VER_MINOR_V2_8_0 0x20080000 #define MSM_DSI_V2_VER_MINOR_8064 0x0 diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c index 05621e5e7d6343..24a347fe29984b 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.c @@ -516,7 +516,9 @@ static int dsi_phy_enable_resource(struct msm_dsi_phy *phy) struct device *dev = &phy->pdev->dev; int ret; - pm_runtime_get_sync(dev); + ret = pm_runtime_resume_and_get(dev); + if (ret) + return ret; ret = clk_prepare_enable(phy->ahb_clk); if (ret) { @@ -585,6 +587,8 @@ static const struct of_device_id dsi_phy_dt_match[] = { .data = &dsi_phy_5nm_8450_cfgs }, { .compatible = "qcom,sm8550-dsi-phy-4nm", .data = &dsi_phy_4nm_8550_cfgs }, + { .compatible = "qcom,sm8650-dsi-phy-4nm", + .data = &dsi_phy_4nm_8650_cfgs }, #endif {} }; @@ -689,6 +693,10 @@ static int dsi_phy_driver_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(phy->ahb_clk), "Unable to get ahb clk\n"); + ret = devm_pm_runtime_enable(&pdev->dev); + if (ret) + return ret; + /* PLL init will call into clk_register which requires * register access, so we need to enable power and ahb clock. */ diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h index 8b640d17478516..e4275d3ad58191 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy.h @@ -62,6 +62,7 @@ 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; +extern const struct msm_dsi_phy_cfg dsi_phy_4nm_8650_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 89a6344bc8653d..82d015aa2d634c 100644 --- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c +++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_7nm.c @@ -1121,6 +1121,10 @@ 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_98000uA_regulators[] = { + { .supply = "vdds", .init_load_uA = 98000 }, +}; + static const struct regulator_bulk_data dsi_phy_7nm_97800uA_regulators[] = { { .supply = "vdds", .init_load_uA = 97800 }, }; @@ -1281,3 +1285,26 @@ const struct msm_dsi_phy_cfg dsi_phy_4nm_8550_cfgs = { .num_dsi_phy = 2, .quirks = DSI_PHY_7NM_QUIRK_V5_2, }; + +const struct msm_dsi_phy_cfg dsi_phy_4nm_8650_cfgs = { + .has_phy_lane = true, + .regulator_data = dsi_phy_7nm_98000uA_regulators, + .num_regulators = ARRAY_SIZE(dsi_phy_7nm_98000uA_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_i2c.c b/drivers/gpu/drm/msm/hdmi/hdmi_i2c.c index de182c00484349..7aa500d24240ff 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_i2c.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_i2c.c @@ -249,7 +249,6 @@ struct i2c_adapter *msm_hdmi_i2c_init(struct hdmi *hdmi) i2c->owner = THIS_MODULE; - i2c->class = I2C_CLASS_DDC; snprintf(i2c->name, sizeof(i2c->name), "msm hdmi i2c"); i2c->dev.parent = &hdmi->pdev->dev; i2c->algo = &msm_hdmi_i2c_algorithm; diff --git a/drivers/gpu/drm/msm/msm_debugfs.c b/drivers/gpu/drm/msm/msm_debugfs.c index 04d304eed22371..4494f6d1c7cbbc 100644 --- a/drivers/gpu/drm/msm/msm_debugfs.c +++ b/drivers/gpu/drm/msm/msm_debugfs.c @@ -304,36 +304,21 @@ int msm_debugfs_late_init(struct drm_device *dev) return ret; } -void msm_debugfs_init(struct drm_minor *minor) +static void msm_debugfs_gpu_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), - minor->debugfs_root, minor); - debugfs_create_file("gpu", S_IRUSR, minor->debugfs_root, dev, &msm_gpu_fops); - if (priv->kms) { - drm_debugfs_create_files(msm_kms_debugfs_list, - ARRAY_SIZE(msm_kms_debugfs_list), - minor->debugfs_root, minor); - debugfs_create_file("kms", S_IRUSR, minor->debugfs_root, - dev, &msm_kms_fops); - } - debugfs_create_u32("hangcheck_period_ms", 0600, minor->debugfs_root, &priv->hangcheck_period); debugfs_create_bool("disable_err_irq", 0600, minor->debugfs_root, &priv->disable_err_irq); - 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, @@ -344,6 +329,30 @@ void msm_debugfs_init(struct drm_minor *minor) debugfs_create_u32("downdifferential",0600, gpu_devfreq, &priv->gpu_devfreq_config.downdifferential); +} + +void msm_debugfs_init(struct drm_minor *minor) +{ + struct drm_device *dev = minor->dev; + struct msm_drm_private *priv = dev->dev_private; + + drm_debugfs_create_files(msm_debugfs_list, + ARRAY_SIZE(msm_debugfs_list), + minor->debugfs_root, minor); + + if (priv->gpu_pdev) + msm_debugfs_gpu_init(minor); + + if (priv->kms) { + drm_debugfs_create_files(msm_kms_debugfs_list, + ARRAY_SIZE(msm_kms_debugfs_list), + minor->debugfs_root, minor); + debugfs_create_file("kms", S_IRUSR, minor->debugfs_root, + dev, &msm_kms_fops); + } + + debugfs_create_file("shrink", S_IRWXU, minor->debugfs_root, + dev, &shrink_fops); 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 3f217b57829347..50b65ffc24b1cf 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -37,9 +37,10 @@ * - 1.9.0 - Add MSM_SUBMIT_FENCE_SN_IN * - 1.10.0 - Add MSM_SUBMIT_BO_NO_IMPLICIT * - 1.11.0 - Add wait boost (MSM_WAIT_FENCE_BOOST, MSM_PREP_BOOST) + * - 1.12.0 - Add MSM_INFO_SET_METADATA and MSM_INFO_GET_METADATA */ #define MSM_VERSION_MAJOR 1 -#define MSM_VERSION_MINOR 10 +#define MSM_VERSION_MINOR 12 #define MSM_VERSION_PATCHLEVEL 0 static void msm_deinit_vram(struct drm_device *ddev); @@ -544,6 +545,85 @@ static int msm_ioctl_gem_info_set_iova(struct drm_device *dev, return msm_gem_set_iova(obj, ctx->aspace, iova); } +static int msm_ioctl_gem_info_set_metadata(struct drm_gem_object *obj, + __user void *metadata, + u32 metadata_size) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + void *buf; + int ret; + + /* Impose a moderate upper bound on metadata size: */ + if (metadata_size > 128) { + return -EOVERFLOW; + } + + /* Use a temporary buf to keep copy_from_user() outside of gem obj lock: */ + buf = memdup_user(metadata, metadata_size); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + ret = msm_gem_lock_interruptible(obj); + if (ret) + goto out; + + msm_obj->metadata = + krealloc(msm_obj->metadata, metadata_size, GFP_KERNEL); + msm_obj->metadata_size = metadata_size; + memcpy(msm_obj->metadata, buf, metadata_size); + + msm_gem_unlock(obj); + +out: + kfree(buf); + + return ret; +} + +static int msm_ioctl_gem_info_get_metadata(struct drm_gem_object *obj, + __user void *metadata, + u32 *metadata_size) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + void *buf; + int ret, len; + + if (!metadata) { + /* + * Querying the size is inherently racey, but + * EXT_external_objects expects the app to confirm + * via device and driver UUIDs that the exporter and + * importer versions match. All we can do from the + * kernel side is check the length under obj lock + * when userspace tries to retrieve the metadata + */ + *metadata_size = msm_obj->metadata_size; + return 0; + } + + ret = msm_gem_lock_interruptible(obj); + if (ret) + return ret; + + /* Avoid copy_to_user() under gem obj lock: */ + len = msm_obj->metadata_size; + buf = kmemdup(msm_obj->metadata, len, GFP_KERNEL); + + msm_gem_unlock(obj); + + if (*metadata_size < len) { + ret = -ETOOSMALL; + } else if (copy_to_user(metadata, buf, len)) { + ret = -EFAULT; + } else { + *metadata_size = len; + } + + kfree(buf); + + return 0; +} + static int msm_ioctl_gem_info(struct drm_device *dev, void *data, struct drm_file *file) { @@ -566,6 +646,8 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data, break; case MSM_INFO_SET_NAME: case MSM_INFO_GET_NAME: + case MSM_INFO_SET_METADATA: + case MSM_INFO_GET_METADATA: break; default: return -EINVAL; @@ -618,7 +700,7 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data, break; case MSM_INFO_GET_NAME: if (args->value && (args->len < strlen(msm_obj->name))) { - ret = -EINVAL; + ret = -ETOOSMALL; break; } args->len = strlen(msm_obj->name); @@ -628,6 +710,14 @@ static int msm_ioctl_gem_info(struct drm_device *dev, void *data, ret = -EFAULT; } break; + case MSM_INFO_SET_METADATA: + ret = msm_ioctl_gem_info_set_metadata( + obj, u64_to_user_ptr(args->value), args->len); + break; + case MSM_INFO_GET_METADATA: + ret = msm_ioctl_gem_info_get_metadata( + obj, u64_to_user_ptr(args->value), &args->len); + break; } drm_gem_object_put(obj); diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index cd5bf658df669e..16a7cbc0b7dd8b 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -78,12 +78,10 @@ enum msm_dsi_controller { * enum msm_event_wait - type of HW events to wait for * @MSM_ENC_COMMIT_DONE - wait for the driver to flush the registers to HW * @MSM_ENC_TX_COMPLETE - wait for the HW to transfer the frame to panel - * @MSM_ENC_VBLANK - wait for the HW VBLANK event (for driver-internal waiters) */ enum msm_event_wait { MSM_ENC_COMMIT_DONE = 0, MSM_ENC_TX_COMPLETE, - MSM_ENC_VBLANK, }; /** @@ -92,12 +90,14 @@ enum msm_event_wait { * @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 + * @needs_cdm: indicates whether cdm block is needed for this display topology */ struct msm_display_topology { u32 num_lm; u32 num_intf; u32 num_dspp; u32 num_dsc; + bool needs_cdm; }; /* Commit/Event thread specific structure */ @@ -386,10 +386,8 @@ int __init msm_dp_register(void); void __exit msm_dp_unregister(void); int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev, struct drm_encoder *encoder); -void msm_dp_irq_postinstall(struct msm_dp *dp_display); void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm_dp *dp_display); -void msm_dp_debugfs_init(struct msm_dp *dp_display, struct drm_minor *minor); bool msm_dp_wide_bus_available(const struct msm_dp *dp_display); #else @@ -407,19 +405,10 @@ static inline int msm_dp_modeset_init(struct msm_dp *dp_display, return -EINVAL; } -static inline void msm_dp_irq_postinstall(struct msm_dp *dp_display) -{ -} - static inline void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm_dp *dp_display) { } -static inline void msm_dp_debugfs_init(struct msm_dp *dp_display, - struct drm_minor *minor) -{ -} - static inline bool msm_dp_wide_bus_available(const struct msm_dp *dp_display) { return false; diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index db1e748daa753f..175ee4ab8a6f7a 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -226,9 +226,9 @@ static struct page **msm_gem_pin_pages_locked(struct drm_gem_object *obj, msm_gem_assert_locked(obj); - if (GEM_WARN_ON(msm_obj->madv > madv)) { - DRM_DEV_ERROR(obj->dev->dev, "Invalid madv state: %u vs %u\n", - msm_obj->madv, madv); + if (msm_obj->madv > madv) { + DRM_DEV_DEBUG_DRIVER(obj->dev->dev, "Invalid madv state: %u vs %u\n", + msm_obj->madv, madv); return ERR_PTR(-EBUSY); } @@ -1058,6 +1058,7 @@ static void msm_gem_free_object(struct drm_gem_object *obj) drm_gem_object_release(obj); + kfree(msm_obj->metadata); kfree(msm_obj); } diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index 8ddef544314083..8d414b072c29da 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -9,6 +9,7 @@ #include #include +#include "drm/drm_exec.h" #include "drm/gpu_scheduler.h" #include "msm_drv.h" @@ -108,6 +109,10 @@ struct msm_gem_object { char name[32]; /* Identifier to print for the debugfs files */ + /* userspace metadata backchannel */ + void *metadata; + u32 metadata_size; + /** * pin_count: Number of times the pages are pinned * @@ -254,7 +259,7 @@ struct msm_gem_submit { struct msm_gpu *gpu; struct msm_gem_address_space *aspace; struct list_head node; /* node in ring submit list */ - struct ww_acquire_ctx ticket; + struct drm_exec exec; uint32_t seqno; /* Sequence number of the submit on the ring */ /* Hw fence, which is created when the scheduler executes the job, and @@ -270,9 +275,9 @@ struct msm_gem_submit { int fence_id; /* key into queue->fence_idr */ struct msm_gpu_submitqueue *queue; struct pid *pid; /* submitting process */ - bool fault_dumped; /* Limit devcoredump dumping to one per submit */ - bool valid; /* true if no cmdstream patching needed */ - bool in_rb; /* "sudo" mode, copy cmds into RB */ + bool bos_pinned : 1; + bool fault_dumped:1;/* Limit devcoredump dumping to one per submit */ + bool in_rb : 1; /* "sudo" mode, copy cmds into RB */ struct msm_ringbuffer *ring; unsigned int nr_cmds; unsigned int nr_bos; @@ -287,10 +292,6 @@ struct msm_gem_submit { struct drm_msm_gem_submit_reloc *relocs; } *cmd; /* array of size nr_cmds */ struct { -/* make sure these don't conflict w/ MSM_SUBMIT_BO_x */ -#define BO_VALID 0x8000 /* is current addr in cmdstream correct/valid? */ -#define BO_LOCKED 0x4000 /* obj lock is held */ -#define BO_PINNED 0x2000 /* obj (pages) is pinned and on active list */ uint32_t flags; union { struct drm_gem_object *obj; diff --git a/drivers/gpu/drm/msm/msm_gem_shrinker.c b/drivers/gpu/drm/msm/msm_gem_shrinker.c index 5a7d48c02c4b96..07ca4ddfe4e373 100644 --- a/drivers/gpu/drm/msm/msm_gem_shrinker.c +++ b/drivers/gpu/drm/msm/msm_gem_shrinker.c @@ -75,7 +75,7 @@ static bool wait_for_idle(struct drm_gem_object *obj) { enum dma_resv_usage usage = dma_resv_usage_rw(true); - return dma_resv_wait_timeout(obj->resv, usage, false, 1000) > 0; + return dma_resv_wait_timeout(obj->resv, usage, false, 10) > 0; } static bool diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 99744de6c05a1b..fba78193127dee 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -17,6 +17,12 @@ #include "msm_gem.h" #include "msm_gpu_trace.h" +/* For userspace errors, use DRM_UT_DRIVER.. so that userspace can enable + * error msgs for debugging, but we don't spam dmesg by default + */ +#define SUBMIT_ERROR(submit, fmt, ...) \ + DRM_DEV_DEBUG_DRIVER((submit)->dev->dev, fmt, ##__VA_ARGS__) + /* * Cmdstream submission: */ @@ -37,7 +43,7 @@ static struct msm_gem_submit *submit_create(struct drm_device *dev, if (sz > SIZE_MAX) return ERR_PTR(-ENOMEM); - submit = kzalloc(sz, GFP_KERNEL); + submit = kzalloc(sz, GFP_KERNEL | __GFP_NOWARN); if (!submit) return ERR_PTR(-ENOMEM); @@ -48,7 +54,7 @@ static struct msm_gem_submit *submit_create(struct drm_device *dev, return ERR_PTR(ret); } - ret = drm_sched_job_init(&submit->base, queue->entity, queue); + ret = drm_sched_job_init(&submit->base, queue->entity, 1, queue); if (ret) { kfree(submit->hw_fence); kfree(submit); @@ -136,7 +142,7 @@ static int submit_lookup_objects(struct msm_gem_submit *submit, if ((submit_bo.flags & ~MSM_SUBMIT_BO_FLAGS) || !(submit_bo.flags & MANDATORY_FLAGS)) { - DRM_ERROR("invalid flags: %x\n", submit_bo.flags); + SUBMIT_ERROR(submit, "invalid flags: %x\n", submit_bo.flags); ret = -EINVAL; i = 0; goto out; @@ -144,8 +150,6 @@ static int submit_lookup_objects(struct msm_gem_submit *submit, submit->bos[i].handle = submit_bo.handle; submit->bos[i].flags = submit_bo.flags; - /* in validate_objects() we figure out if this is true: */ - submit->bos[i].iova = submit_bo.presumed; } spin_lock(&file->table_lock); @@ -158,7 +162,7 @@ static int submit_lookup_objects(struct msm_gem_submit *submit, */ obj = idr_find(&file->object_idr, submit->bos[i].handle); if (!obj) { - DRM_ERROR("invalid handle %u at index %u\n", submit->bos[i].handle, i); + SUBMIT_ERROR(submit, "invalid handle %u at index %u\n", submit->bos[i].handle, i); ret = -EINVAL; goto out_unlock; } @@ -202,13 +206,13 @@ static int submit_lookup_cmds(struct msm_gem_submit *submit, case MSM_SUBMIT_CMD_CTX_RESTORE_BUF: break; default: - DRM_ERROR("invalid type: %08x\n", submit_cmd.type); + SUBMIT_ERROR(submit, "invalid type: %08x\n", submit_cmd.type); return -EINVAL; } if (submit_cmd.size % 4) { - DRM_ERROR("non-aligned cmdstream buffer size: %u\n", - submit_cmd.size); + SUBMIT_ERROR(submit, "non-aligned cmdstream buffer size: %u\n", + submit_cmd.size); ret = -EINVAL; goto out; } @@ -228,7 +232,7 @@ static int submit_lookup_cmds(struct msm_gem_submit *submit, ret = -ENOMEM; goto out; } - submit->cmd[i].relocs = kmalloc(sz, GFP_KERNEL); + submit->cmd[i].relocs = kmalloc(sz, GFP_KERNEL | __GFP_NOWARN); if (!submit->cmd[i].relocs) { ret = -ENOMEM; goto out; @@ -244,101 +248,30 @@ out: return ret; } -/* Unwind bo state, according to cleanup_flags. In the success case, only - * the lock is dropped at the end of the submit (and active/pin ref is dropped - * later when the submit is retired). - */ -static void submit_cleanup_bo(struct msm_gem_submit *submit, int i, - unsigned cleanup_flags) -{ - struct drm_gem_object *obj = submit->bos[i].obj; - unsigned flags = submit->bos[i].flags & cleanup_flags; - - /* - * Clear flags bit before dropping lock, so that the msm_job_run() - * path isn't racing with submit_cleanup() (ie. the read/modify/ - * write is protected by the obj lock in all paths) - */ - submit->bos[i].flags &= ~cleanup_flags; - - if (flags & BO_PINNED) - msm_gem_unpin_locked(obj); - - if (flags & BO_LOCKED) - dma_resv_unlock(obj->resv); -} - -static void submit_unlock_unpin_bo(struct msm_gem_submit *submit, int i) -{ - unsigned cleanup_flags = BO_PINNED | BO_LOCKED; - submit_cleanup_bo(submit, i, cleanup_flags); - - if (!(submit->bos[i].flags & BO_VALID)) - submit->bos[i].iova = 0; -} - /* This is where we make sure all the bo's are reserved and pin'd: */ static int submit_lock_objects(struct msm_gem_submit *submit) { - int contended, slow_locked = -1, i, ret = 0; - -retry: - for (i = 0; i < submit->nr_bos; i++) { - struct drm_gem_object *obj = submit->bos[i].obj; - - if (slow_locked == i) - slow_locked = -1; + int ret; - contended = i; + drm_exec_init(&submit->exec, DRM_EXEC_INTERRUPTIBLE_WAIT, submit->nr_bos); - if (!(submit->bos[i].flags & BO_LOCKED)) { - ret = dma_resv_lock_interruptible(obj->resv, - &submit->ticket); + drm_exec_until_all_locked (&submit->exec) { + for (unsigned i = 0; i < submit->nr_bos; i++) { + struct drm_gem_object *obj = submit->bos[i].obj; + ret = drm_exec_prepare_obj(&submit->exec, obj, 1); + drm_exec_retry_on_contention(&submit->exec); if (ret) - goto fail; - submit->bos[i].flags |= BO_LOCKED; + goto error; } } - ww_acquire_done(&submit->ticket); - return 0; -fail: - if (ret == -EALREADY) { - DRM_ERROR("handle %u at index %u already on submit list\n", - submit->bos[i].handle, i); - ret = -EINVAL; - } - - for (; i >= 0; i--) - submit_unlock_unpin_bo(submit, i); - - if (slow_locked > 0) - submit_unlock_unpin_bo(submit, slow_locked); - - if (ret == -EDEADLK) { - struct drm_gem_object *obj = submit->bos[contended].obj; - /* we lost out in a seqno race, lock and retry.. */ - ret = dma_resv_lock_slow_interruptible(obj->resv, - &submit->ticket); - if (!ret) { - submit->bos[contended].flags |= BO_LOCKED; - slow_locked = contended; - goto retry; - } - - /* Not expecting -EALREADY here, if the bo was already - * locked, we should have gotten -EALREADY already from - * the dma_resv_lock_interruptable() call. - */ - WARN_ON_ONCE(ret == -EALREADY); - } - +error: return ret; } -static int submit_fence_sync(struct msm_gem_submit *submit, bool no_implicit) +static int submit_fence_sync(struct msm_gem_submit *submit) { int i, ret = 0; @@ -346,22 +279,6 @@ static int submit_fence_sync(struct msm_gem_submit *submit, bool no_implicit) struct drm_gem_object *obj = submit->bos[i].obj; bool write = submit->bos[i].flags & MSM_SUBMIT_BO_WRITE; - /* NOTE: _reserve_shared() must happen before - * _add_shared_fence(), which makes this a slightly - * strange place to call it. OTOH this is a - * convenient can-fail point to hook it in. - */ - ret = dma_resv_reserve_fences(obj->resv, 1); - 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. @@ -384,8 +301,6 @@ static int submit_pin_objects(struct msm_gem_submit *submit) struct msm_drm_private *priv = submit->dev->dev_private; int i, ret = 0; - submit->valid = true; - for (i = 0; i < submit->nr_bos; i++) { struct drm_gem_object *obj = submit->bos[i].obj; struct msm_gem_vma *vma; @@ -401,14 +316,7 @@ static int submit_pin_objects(struct msm_gem_submit *submit) if (ret) break; - if (vma->iova == submit->bos[i].iova) { - submit->bos[i].flags |= BO_VALID; - } else { - submit->bos[i].iova = vma->iova; - /* iova changed, so address in cmdstream is not valid: */ - submit->bos[i].flags &= ~BO_VALID; - submit->valid = false; - } + submit->bos[i].iova = vma->iova; } /* @@ -421,13 +329,28 @@ static int submit_pin_objects(struct msm_gem_submit *submit) mutex_lock(&priv->lru.lock); for (i = 0; i < submit->nr_bos; i++) { msm_gem_pin_obj_locked(submit->bos[i].obj); - submit->bos[i].flags |= BO_PINNED; } mutex_unlock(&priv->lru.lock); + submit->bos_pinned = true; + return ret; } +static void submit_unpin_objects(struct msm_gem_submit *submit) +{ + if (!submit->bos_pinned) + return; + + for (int i = 0; i < submit->nr_bos; i++) { + struct drm_gem_object *obj = submit->bos[i].obj; + + msm_gem_unpin_locked(obj); + } + + submit->bos_pinned = false; +} + static void submit_attach_object_fences(struct msm_gem_submit *submit) { int i; @@ -445,11 +368,11 @@ static void submit_attach_object_fences(struct msm_gem_submit *submit) } static int submit_bo(struct msm_gem_submit *submit, uint32_t idx, - struct drm_gem_object **obj, uint64_t *iova, bool *valid) + struct drm_gem_object **obj, uint64_t *iova) { if (idx >= submit->nr_bos) { - DRM_ERROR("invalid buffer index: %u (out of %u)\n", - idx, submit->nr_bos); + SUBMIT_ERROR(submit, "invalid buffer index: %u (out of %u)\n", + idx, submit->nr_bos); return -EINVAL; } @@ -457,8 +380,6 @@ static int submit_bo(struct msm_gem_submit *submit, uint32_t idx, *obj = submit->bos[idx].obj; if (iova) *iova = submit->bos[idx].iova; - if (valid) - *valid = !!(submit->bos[idx].flags & BO_VALID); return 0; } @@ -471,11 +392,8 @@ static int submit_reloc(struct msm_gem_submit *submit, struct drm_gem_object *ob uint32_t *ptr; int ret = 0; - if (!nr_relocs) - return 0; - if (offset % 4) { - DRM_ERROR("non-aligned cmdstream buffer: %u\n", offset); + SUBMIT_ERROR(submit, "non-aligned cmdstream buffer: %u\n", offset); return -EINVAL; } @@ -494,11 +412,10 @@ static int submit_reloc(struct msm_gem_submit *submit, struct drm_gem_object *ob struct drm_msm_gem_submit_reloc submit_reloc = relocs[i]; uint32_t off; uint64_t iova; - bool valid; if (submit_reloc.submit_offset % 4) { - DRM_ERROR("non-aligned reloc offset: %u\n", - submit_reloc.submit_offset); + SUBMIT_ERROR(submit, "non-aligned reloc offset: %u\n", + submit_reloc.submit_offset); ret = -EINVAL; goto out; } @@ -508,18 +425,15 @@ static int submit_reloc(struct msm_gem_submit *submit, struct drm_gem_object *ob if ((off >= (obj->size / 4)) || (off < last_offset)) { - DRM_ERROR("invalid offset %u at reloc %u\n", off, i); + SUBMIT_ERROR(submit, "invalid offset %u at reloc %u\n", off, i); ret = -EINVAL; goto out; } - ret = submit_bo(submit, submit_reloc.reloc_idx, NULL, &iova, &valid); + ret = submit_bo(submit, submit_reloc.reloc_idx, NULL, &iova); if (ret) goto out; - if (valid) - continue; - iova += submit_reloc.reloc_offset; if (submit_reloc.shift < 0) @@ -544,18 +458,14 @@ out: */ static void submit_cleanup(struct msm_gem_submit *submit, bool error) { - unsigned cleanup_flags = BO_LOCKED; - unsigned i; - - if (error) - cleanup_flags |= BO_PINNED; - - for (i = 0; i < submit->nr_bos; i++) { - struct drm_gem_object *obj = submit->bos[i].obj; - submit_cleanup_bo(submit, i, cleanup_flags); - if (error) - drm_gem_object_put(obj); + if (error) { + submit_unpin_objects(submit); + /* job wasn't enqueued to scheduler, so early retirement: */ + msm_submit_retire(submit); } + + if (submit->exec.objects) + drm_exec_fini(&submit->exec); } void msm_submit_retire(struct msm_gem_submit *submit) @@ -749,7 +659,6 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, struct msm_submit_post_dep *post_deps = NULL; struct drm_syncobj **syncobjs_to_reset = NULL; int out_fence_fd = -1; - bool has_ww_ticket = false; unsigned i; int ret; @@ -855,15 +764,15 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, goto out; /* copy_*_user while holding a ww ticket upsets lockdep */ - ww_acquire_init(&submit->ticket, &reservation_ww_class); - has_ww_ticket = true; ret = submit_lock_objects(submit); if (ret) goto out; - ret = submit_fence_sync(submit, !!(args->flags & MSM_SUBMIT_NO_IMPLICIT)); - if (ret) - goto out; + if (!(args->flags & MSM_SUBMIT_NO_IMPLICIT)) { + ret = submit_fence_sync(submit); + if (ret) + goto out; + } ret = submit_pin_objects(submit); if (ret) @@ -873,32 +782,27 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, struct drm_gem_object *obj; uint64_t iova; - ret = submit_bo(submit, submit->cmd[i].idx, - &obj, &iova, NULL); + ret = submit_bo(submit, submit->cmd[i].idx, &obj, &iova); if (ret) goto out; if (!submit->cmd[i].size || ((submit->cmd[i].size + submit->cmd[i].offset) > obj->size / 4)) { - DRM_ERROR("invalid cmdstream size: %u\n", submit->cmd[i].size * 4); + SUBMIT_ERROR(submit, "invalid cmdstream size: %u\n", submit->cmd[i].size * 4); ret = -EINVAL; goto out; } submit->cmd[i].iova = iova + (submit->cmd[i].offset * 4); - if (submit->valid) + if (likely(!submit->cmd[i].nr_relocs)) continue; if (!gpu->allow_relocs) { - if (submit->cmd[i].nr_relocs) { - DRM_ERROR("relocs not allowed\n"); - ret = -EINVAL; - goto out; - } - - continue; + SUBMIT_ERROR(submit, "relocs not allowed\n"); + ret = -EINVAL; + goto out; } ret = submit_reloc(submit, obj, submit->cmd[i].offset * 4, @@ -974,6 +878,9 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, } } + if (ret) + goto out; + submit_attach_object_fences(submit); /* The scheduler owns a ref now: */ @@ -993,8 +900,6 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, out: submit_cleanup(submit, !!ret); - if (has_ww_ticket) - ww_acquire_fini(&submit->ticket); out_unlock: mutex_unlock(&queue->lock); out_post_unlock: diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 7f64c66673002f..095390774f22b5 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -292,8 +292,7 @@ static void msm_gpu_crashstate_capture(struct msm_gpu *gpu, /* Set the active crash state to be dumped on failure */ gpu->crashstate = state; - /* FIXME: Release the crashstate if this errors out? */ - dev_coredumpm(gpu->dev->dev, THIS_MODULE, gpu, 0, GFP_KERNEL, + dev_coredumpm(&gpu->pdev->dev, THIS_MODULE, gpu, 0, GFP_KERNEL, msm_gpu_devcoredump_read, msm_gpu_devcoredump_free); } #else @@ -366,29 +365,31 @@ static void recover_worker(struct kthread_work *work) DRM_DEV_ERROR(dev->dev, "%s: hangcheck recover!\n", gpu->name); submit = find_submit(cur_ring, cur_ring->memptrs->fence + 1); - if (submit) { - /* Increment the fault counts */ - submit->queue->faults++; - if (submit->aspace) - submit->aspace->faults++; - get_comm_cmdline(submit, &comm, &cmd); + /* + * If the submit retired while we were waiting for the worker to run, + * or waiting to acquire the gpu lock, then nothing more to do. + */ + if (!submit) + goto out_unlock; - if (comm && cmd) { - DRM_DEV_ERROR(dev->dev, "%s: offending task: %s (%s)\n", - gpu->name, comm, cmd); + /* Increment the fault counts */ + submit->queue->faults++; + if (submit->aspace) + submit->aspace->faults++; - msm_rd_dump_submit(priv->hangrd, submit, - "offending task: %s (%s)", comm, cmd); - } else { - msm_rd_dump_submit(priv->hangrd, submit, NULL); - } + get_comm_cmdline(submit, &comm, &cmd); + + if (comm && cmd) { + DRM_DEV_ERROR(dev->dev, "%s: offending task: %s (%s)\n", + gpu->name, comm, cmd); + + msm_rd_dump_submit(priv->hangrd, submit, + "offending task: %s (%s)", comm, cmd); } else { - /* - * We couldn't attribute this fault to any particular context, - * so increment the global fault count instead. - */ - gpu->global_faults++; + DRM_DEV_ERROR(dev->dev, "%s: offending task: unknown\n", gpu->name); + + msm_rd_dump_submit(priv->hangrd, submit, NULL); } /* Record the crash state */ @@ -441,6 +442,7 @@ static void recover_worker(struct kthread_work *work) pm_runtime_put(&gpu->pdev->dev); +out_unlock: mutex_unlock(&gpu->lock); msm_gpu_retire(gpu); diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index 4252e3839fbc83..2bfcb222e35338 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -347,7 +347,7 @@ struct msm_gpu_perfcntr { * DRM_SCHED_PRIORITY_KERNEL priority level is treated specially in some * cases, so we don't use it (no need for kernel generated jobs). */ -#define NR_SCHED_PRIORITIES (1 + DRM_SCHED_PRIORITY_HIGH - DRM_SCHED_PRIORITY_MIN) +#define NR_SCHED_PRIORITIES (1 + DRM_SCHED_PRIORITY_LOW - DRM_SCHED_PRIORITY_HIGH) /** * struct msm_file_private - per-drm_file context diff --git a/drivers/gpu/drm/msm/msm_mdss.c b/drivers/gpu/drm/msm/msm_mdss.c index 6865db1e3ce892..455b2e3a0cdd48 100644 --- a/drivers/gpu/drm/msm/msm_mdss.c +++ b/drivers/gpu/drm/msm/msm_mdss.c @@ -28,6 +28,8 @@ #define MIN_IB_BW 400000000UL /* Min ib vote 400MB */ +#define DEFAULT_REG_BW 153600 /* Used in mdss fbdev driver */ + struct msm_mdss { struct device *dev; @@ -40,8 +42,9 @@ struct msm_mdss { struct irq_domain *domain; } irq_controller; const struct msm_mdss_data *mdss_data; - struct icc_path *path[2]; - u32 num_paths; + struct icc_path *mdp_path[2]; + u32 num_mdp_paths; + struct icc_path *reg_bus_path; }; static int msm_mdss_parse_data_bus_icc_path(struct device *dev, @@ -49,38 +52,26 @@ static int msm_mdss_parse_data_bus_icc_path(struct device *dev, { struct icc_path *path0; struct icc_path *path1; + struct icc_path *reg_bus_path; - path0 = of_icc_get(dev, "mdp0-mem"); + path0 = devm_of_icc_get(dev, "mdp0-mem"); if (IS_ERR_OR_NULL(path0)) return PTR_ERR_OR_ZERO(path0); - msm_mdss->path[0] = path0; - msm_mdss->num_paths = 1; + msm_mdss->mdp_path[0] = path0; + msm_mdss->num_mdp_paths = 1; - path1 = of_icc_get(dev, "mdp1-mem"); + path1 = devm_of_icc_get(dev, "mdp1-mem"); if (!IS_ERR_OR_NULL(path1)) { - msm_mdss->path[1] = path1; - msm_mdss->num_paths++; + msm_mdss->mdp_path[1] = path1; + msm_mdss->num_mdp_paths++; } - return 0; -} - -static void msm_mdss_put_icc_path(void *data) -{ - struct msm_mdss *msm_mdss = data; - int i; - - for (i = 0; i < msm_mdss->num_paths; i++) - icc_put(msm_mdss->path[i]); -} - -static void msm_mdss_icc_request_bw(struct msm_mdss *msm_mdss, unsigned long bw) -{ - int i; + reg_bus_path = of_icc_get(dev, "cpu-cfg"); + if (!IS_ERR_OR_NULL(reg_bus_path)) + msm_mdss->reg_bus_path = reg_bus_path; - for (i = 0; i < msm_mdss->num_paths; i++) - icc_set_bw(msm_mdss->path[i], 0, Bps_to_icc(bw)); + return 0; } static void msm_mdss_irq(struct irq_desc *desc) @@ -236,14 +227,22 @@ const struct msm_mdss_data *msm_mdss_get_mdss_data(struct device *dev) static int msm_mdss_enable(struct msm_mdss *msm_mdss) { - int ret; + int ret, i; /* * Several components have AXI clocks that can only be turned on if * the interconnect is enabled (non-zero bandwidth). Let's make sure * that the interconnects are at least at a minimum amount. */ - msm_mdss_icc_request_bw(msm_mdss, MIN_IB_BW); + for (i = 0; i < msm_mdss->num_mdp_paths; i++) + icc_set_bw(msm_mdss->mdp_path[i], 0, Bps_to_icc(MIN_IB_BW)); + + if (msm_mdss->mdss_data && msm_mdss->mdss_data->reg_bus_bw) + icc_set_bw(msm_mdss->reg_bus_path, 0, + msm_mdss->mdss_data->reg_bus_bw); + else + icc_set_bw(msm_mdss->reg_bus_path, 0, + DEFAULT_REG_BW); ret = clk_bulk_prepare_enable(msm_mdss->num_clocks, msm_mdss->clocks); if (ret) { @@ -295,8 +294,15 @@ static int msm_mdss_enable(struct msm_mdss *msm_mdss) static int msm_mdss_disable(struct msm_mdss *msm_mdss) { + int i; + clk_bulk_disable_unprepare(msm_mdss->num_clocks, msm_mdss->clocks); - msm_mdss_icc_request_bw(msm_mdss, 0); + + for (i = 0; i < msm_mdss->num_mdp_paths; i++) + icc_set_bw(msm_mdss->mdp_path[i], 0, 0); + + if (msm_mdss->reg_bus_path) + icc_set_bw(msm_mdss->reg_bus_path, 0, 0); return 0; } @@ -384,6 +390,8 @@ static struct msm_mdss *msm_mdss_init(struct platform_device *pdev, bool is_mdp5 if (!msm_mdss) return ERR_PTR(-ENOMEM); + msm_mdss->mdss_data = of_device_get_match_data(&pdev->dev); + msm_mdss->mmio = devm_platform_ioremap_resource_byname(pdev, is_mdp5 ? "mdss_phys" : "mdss"); if (IS_ERR(msm_mdss->mmio)) return ERR_CAST(msm_mdss->mmio); @@ -391,9 +399,6 @@ static struct msm_mdss *msm_mdss_init(struct platform_device *pdev, bool is_mdp5 dev_dbg(&pdev->dev, "mapped mdss address space @%pK\n", msm_mdss->mmio); ret = msm_mdss_parse_data_bus_icc_path(&pdev->dev, msm_mdss); - if (ret) - return ERR_PTR(ret); - ret = devm_add_action_or_reset(&pdev->dev, msm_mdss_put_icc_path, msm_mdss); if (ret) return ERR_PTR(ret); @@ -477,8 +482,6 @@ static int mdss_probe(struct platform_device *pdev) if (IS_ERR(mdss)) return PTR_ERR(mdss); - mdss->mdss_data = of_device_get_match_data(&pdev->dev); - platform_set_drvdata(pdev, mdss); /* @@ -510,11 +513,13 @@ static const struct msm_mdss_data msm8998_data = { .ubwc_enc_version = UBWC_1_0, .ubwc_dec_version = UBWC_1_0, .highest_bank_bit = 2, + .reg_bus_bw = 76800, }; static const struct msm_mdss_data qcm2290_data = { /* no UBWC */ .highest_bank_bit = 0x2, + .reg_bus_bw = 76800, }; static const struct msm_mdss_data sc7180_data = { @@ -522,6 +527,7 @@ static const struct msm_mdss_data sc7180_data = { .ubwc_dec_version = UBWC_2_0, .ubwc_static = 0x1e, .highest_bank_bit = 0x3, + .reg_bus_bw = 76800, }; static const struct msm_mdss_data sc7280_data = { @@ -531,6 +537,7 @@ static const struct msm_mdss_data sc7280_data = { .ubwc_static = 1, .highest_bank_bit = 1, .macrotile_mode = 1, + .reg_bus_bw = 74000, }; static const struct msm_mdss_data sc8180x_data = { @@ -538,6 +545,7 @@ static const struct msm_mdss_data sc8180x_data = { .ubwc_dec_version = UBWC_3_0, .highest_bank_bit = 3, .macrotile_mode = 1, + .reg_bus_bw = 76800, }; static const struct msm_mdss_data sc8280xp_data = { @@ -545,14 +553,22 @@ static const struct msm_mdss_data sc8280xp_data = { .ubwc_dec_version = UBWC_4_0, .ubwc_swizzle = 6, .ubwc_static = 1, - .highest_bank_bit = 2, + .highest_bank_bit = 3, .macrotile_mode = 1, + .reg_bus_bw = 76800, +}; + +static const struct msm_mdss_data sdm670_data = { + .ubwc_enc_version = UBWC_2_0, + .ubwc_dec_version = UBWC_2_0, + .highest_bank_bit = 1, }; static const struct msm_mdss_data sdm845_data = { .ubwc_enc_version = UBWC_2_0, .ubwc_dec_version = UBWC_2_0, .highest_bank_bit = 2, + .reg_bus_bw = 76800, }; static const struct msm_mdss_data sm6350_data = { @@ -561,12 +577,14 @@ static const struct msm_mdss_data sm6350_data = { .ubwc_swizzle = 6, .ubwc_static = 0x1e, .highest_bank_bit = 1, + .reg_bus_bw = 76800, }; static const struct msm_mdss_data sm8150_data = { .ubwc_enc_version = UBWC_3_0, .ubwc_dec_version = UBWC_3_0, .highest_bank_bit = 2, + .reg_bus_bw = 76800, }; static const struct msm_mdss_data sm6115_data = { @@ -575,6 +593,7 @@ static const struct msm_mdss_data sm6115_data = { .ubwc_swizzle = 7, .ubwc_static = 0x11f, .highest_bank_bit = 0x1, + .reg_bus_bw = 76800, }; static const struct msm_mdss_data sm6125_data = { @@ -592,6 +611,18 @@ static const struct msm_mdss_data sm8250_data = { /* TODO: highest_bank_bit = 2 for LP_DDR4 */ .highest_bank_bit = 3, .macrotile_mode = 1, + .reg_bus_bw = 76800, +}; + +static const struct msm_mdss_data sm8350_data = { + .ubwc_enc_version = UBWC_4_0, + .ubwc_dec_version = UBWC_4_0, + .ubwc_swizzle = 6, + .ubwc_static = 1, + /* TODO: highest_bank_bit = 2 for LP_DDR4 */ + .highest_bank_bit = 3, + .macrotile_mode = 1, + .reg_bus_bw = 74000, }; static const struct msm_mdss_data sm8550_data = { @@ -602,11 +633,13 @@ static const struct msm_mdss_data sm8550_data = { /* TODO: highest_bank_bit = 2 for LP_DDR4 */ .highest_bank_bit = 3, .macrotile_mode = 1, + .reg_bus_bw = 57000, }; static const struct of_device_id mdss_dt_match[] = { { .compatible = "qcom,mdss" }, { .compatible = "qcom,msm8998-mdss", .data = &msm8998_data }, { .compatible = "qcom,qcm2290-mdss", .data = &qcm2290_data }, + { .compatible = "qcom,sdm670-mdss", .data = &sdm670_data }, { .compatible = "qcom,sdm845-mdss", .data = &sdm845_data }, { .compatible = "qcom,sc7180-mdss", .data = &sc7180_data }, { .compatible = "qcom,sc7280-mdss", .data = &sc7280_data }, @@ -618,9 +651,10 @@ static const struct of_device_id mdss_dt_match[] = { { .compatible = "qcom,sm6375-mdss", .data = &sm6350_data }, { .compatible = "qcom,sm8150-mdss", .data = &sm8150_data }, { .compatible = "qcom,sm8250-mdss", .data = &sm8250_data }, - { .compatible = "qcom,sm8350-mdss", .data = &sm8250_data }, - { .compatible = "qcom,sm8450-mdss", .data = &sm8250_data }, + { .compatible = "qcom,sm8350-mdss", .data = &sm8350_data }, + { .compatible = "qcom,sm8450-mdss", .data = &sm8350_data }, { .compatible = "qcom,sm8550-mdss", .data = &sm8550_data }, + { .compatible = "qcom,sm8650-mdss", .data = &sm8550_data}, {} }; MODULE_DEVICE_TABLE(of, mdss_dt_match); diff --git a/drivers/gpu/drm/msm/msm_mdss.h b/drivers/gpu/drm/msm/msm_mdss.h index 02bbab42adbc0e..3afef4b1786d28 100644 --- a/drivers/gpu/drm/msm/msm_mdss.h +++ b/drivers/gpu/drm/msm/msm_mdss.h @@ -14,6 +14,7 @@ struct msm_mdss_data { u32 ubwc_static; u32 highest_bank_bit; u32 macrotile_mode; + u32 reg_bus_bw; }; #define UBWC_1_0 0x10000000 diff --git a/drivers/gpu/drm/msm/msm_rd.c b/drivers/gpu/drm/msm/msm_rd.c index 5adc51f7ab592d..ca44fd291c5ba4 100644 --- a/drivers/gpu/drm/msm/msm_rd.c +++ b/drivers/gpu/drm/msm/msm_rd.c @@ -270,6 +270,9 @@ int msm_rd_debugfs_init(struct drm_minor *minor) struct msm_rd_state *rd; int ret; + if (!priv->gpu_pdev) + return 0; + /* only create on first minor: */ if (priv->rd) return 0; diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.c b/drivers/gpu/drm/msm/msm_ringbuffer.c index 95257ab0185dc4..4bc13f7d005ab7 100644 --- a/drivers/gpu/drm/msm/msm_ringbuffer.c +++ b/drivers/gpu/drm/msm/msm_ringbuffer.c @@ -29,9 +29,10 @@ static struct dma_fence *msm_job_run(struct drm_sched_job *job) struct drm_gem_object *obj = submit->bos[i].obj; msm_gem_unpin_active(obj); - submit->bos[i].flags &= ~BO_PINNED; } + submit->bos_pinned = false; + mutex_unlock(&priv->lru.lock); msm_gpu_submit(gpu, submit); @@ -94,7 +95,7 @@ struct msm_ringbuffer *msm_ringbuffer_new(struct msm_gpu *gpu, int id, /* currently managing hangcheck ourselves: */ sched_timeout = MAX_SCHEDULE_TIMEOUT; - ret = drm_sched_init(&ring->sched, &msm_sched_ops, + ret = drm_sched_init(&ring->sched, &msm_sched_ops, NULL, DRM_SCHED_PRIORITY_COUNT, num_hw_submissions, 0, sched_timeout, NULL, NULL, to_msm_bo(ring->bo)->name, gpu->dev->dev); diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.c b/drivers/gpu/drm/mxsfb/mxsfb_drv.c index 625c1bfc41733b..b483ef48216aa1 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.c @@ -11,9 +11,10 @@ #include #include #include +#include #include -#include #include +#include #include #include @@ -346,18 +347,13 @@ MODULE_DEVICE_TABLE(of, mxsfb_dt_ids); static int mxsfb_probe(struct platform_device *pdev) { struct drm_device *drm; - const struct of_device_id *of_id = - of_match_device(mxsfb_dt_ids, &pdev->dev); int ret; - if (!pdev->dev.of_node) - return -ENODEV; - drm = drm_dev_alloc(&mxsfb_driver, &pdev->dev); if (IS_ERR(drm)) return PTR_ERR(drm); - ret = mxsfb_load(drm, of_id->data); + ret = mxsfb_load(drm, device_get_match_data(&pdev->dev)); if (ret) goto err_free; diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 118807e38422b6..8d37a694b77248 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -38,7 +38,9 @@ #include #include #include +#include #include +#include #include #include @@ -945,7 +947,8 @@ nv50_msto_prepare(struct drm_atomic_state *state, if (ret == 0) { nvif_outp_dp_mst_vcpi(&mstm->outp->outp, msto->head->base.index, payload->vc_start_slot, payload->time_slots, - payload->pbn, payload->time_slots * mst_state->pbn_div); + payload->pbn, + payload->time_slots * dfixed_trunc(mst_state->pbn_div)); } else { nvif_outp_dp_mst_vcpi(&mstm->outp->outp, msto->head->base.index, 0, 0, 0, 0); } @@ -982,15 +985,14 @@ nv50_msto_atomic_check(struct drm_encoder *encoder, const int clock = crtc_state->adjusted_mode.clock; asyh->or.bpc = connector->display_info.bpc; - asyh->dp.pbn = drm_dp_calc_pbn_mode(clock, asyh->or.bpc * 3, - false); + asyh->dp.pbn = drm_dp_calc_pbn_mode(clock, asyh->or.bpc * 3 << 4); } mst_state = drm_atomic_get_mst_topology_state(state, &mstm->mgr); if (IS_ERR(mst_state)) return PTR_ERR(mst_state); - if (!mst_state->pbn_div) { + if (!mst_state->pbn_div.full) { struct nouveau_encoder *outp = mstc->mstm->outp; mst_state->pbn_div = drm_dp_get_vc_payload_bw(&mstm->mgr, diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index 2edd7bb13faea5..a04156ca8390ba 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -127,21 +127,14 @@ nouveau_abi16_chan_fini(struct nouveau_abi16 *abi16, { struct nouveau_abi16_ntfy *ntfy, *temp; - /* When a client exits without waiting for it's queued up jobs to - * finish it might happen that we fault the channel. This is due to - * drm_file_free() calling drm_gem_release() before the postclose() - * callback. Hence, we can't tear down this scheduler entity before - * uvmm mappings are unmapped. Currently, we can't detect this case. - * - * However, this should be rare and harmless, since the channel isn't - * needed anymore. - */ - nouveau_sched_entity_fini(&chan->sched_entity); + /* Cancel all jobs from the entity's queue. */ + drm_sched_entity_fini(&chan->sched.entity); - /* wait for all activity to stop before cleaning up */ if (chan->chan) nouveau_channel_idle(chan->chan); + nouveau_sched_fini(&chan->sched); + /* cleanup notifier state */ list_for_each_entry_safe(ntfy, temp, &chan->notifiers, head) { nouveau_abi16_ntfy_fini(chan, ntfy); @@ -344,8 +337,8 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) if (ret) goto done; - ret = nouveau_sched_entity_init(&chan->sched_entity, &drm->sched, - drm->sched_wq); + ret = nouveau_sched_init(&chan->sched, drm, drm->sched_wq, + chan->chan->dma.ib_max); if (ret) goto done; diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.h b/drivers/gpu/drm/nouveau/nouveau_abi16.h index 9f538486c10e37..1f5e243c0c759e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.h +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.h @@ -26,7 +26,7 @@ struct nouveau_abi16_chan { struct nouveau_bo *ntfy; struct nouveau_vma *ntfy_vma; struct nvkm_mm heap; - struct nouveau_sched_entity sched_entity; + struct nouveau_sched sched; }; struct nouveau_abi16 { diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 280d1d9a559bad..00cc7d1abaa39b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -148,10 +148,17 @@ nouveau_bo_del_ttm(struct ttm_buffer_object *bo) * If nouveau_bo_new() allocated this buffer, the GEM object was never * initialized, so don't attempt to release it. */ - if (bo->base.dev) + if (bo->base.dev) { + /* Gem objects not being shared with other VMs get their + * dma_resv from a root GEM object. + */ + if (nvbo->no_share) + drm_gem_object_put(nvbo->r_obj); + drm_gem_object_release(&bo->base); - else + } else { dma_resv_fini(&bo->base._resv); + } kfree(nvbo); } @@ -1055,17 +1062,18 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, { struct nouveau_drm *drm = nouveau_bdev(bo->bdev); struct nouveau_bo *nvbo = nouveau_bo(bo); + struct drm_gem_object *obj = &bo->base; struct ttm_resource *old_reg = bo->resource; struct nouveau_drm_tile *new_tile = NULL; int ret = 0; - if (new_reg->mem_type == TTM_PL_TT) { ret = nouveau_ttm_tt_bind(bo->bdev, bo->ttm, new_reg); if (ret) return ret; } + drm_gpuvm_bo_gem_evict(obj, evict); nouveau_bo_move_ntfy(bo, new_reg); ret = ttm_bo_wait_ctx(bo, ctx); if (ret) @@ -1130,6 +1138,7 @@ out: out_ntfy: if (ret) { nouveau_bo_move_ntfy(bo, bo->resource); + drm_gpuvm_bo_gem_evict(obj, !evict); } return ret; } diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.h b/drivers/gpu/drm/nouveau/nouveau_bo.h index 07f671cf895e04..70c551921a9ee9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.h +++ b/drivers/gpu/drm/nouveau/nouveau_bo.h @@ -26,6 +26,11 @@ struct nouveau_bo { struct list_head entry; int pbbo_index; bool validate_mapped; + + /* Root GEM object we derive the dma_resv of in case this BO is not + * shared between VMs. + */ + struct drm_gem_object *r_obj; bool no_share; /* GPU address space is independent of CPU word size */ diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 50589f982d1a45..6f6c31a9937b2f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -190,6 +190,8 @@ nouveau_cli_work_queue(struct nouveau_cli *cli, struct dma_fence *fence, static void nouveau_cli_fini(struct nouveau_cli *cli) { + struct nouveau_uvmm *uvmm = nouveau_cli_uvmm_locked(cli); + /* All our channels are dead now, which means all the fences they * own are signalled, and all callback functions have been called. * @@ -199,8 +201,9 @@ nouveau_cli_fini(struct nouveau_cli *cli) WARN_ON(!list_empty(&cli->worker)); usif_client_fini(cli); - nouveau_uvmm_fini(&cli->uvmm); - nouveau_sched_entity_fini(&cli->sched_entity); + nouveau_sched_fini(&cli->sched); + if (uvmm) + nouveau_uvmm_fini(uvmm); nouveau_vmm_fini(&cli->svm); nouveau_vmm_fini(&cli->vmm); nvif_mmu_dtor(&cli->mmu); @@ -307,8 +310,17 @@ nouveau_cli_init(struct nouveau_drm *drm, const char *sname, cli->mem = &mems[ret]; - ret = nouveau_sched_entity_init(&cli->sched_entity, &drm->sched, - drm->sched_wq); + /* Don't pass in the (shared) sched_wq in order to let + * nouveau_sched_init() create a dedicated one for VM_BIND jobs. + * + * This is required to ensure that for VM_BIND jobs free_job() work and + * run_job() work can always run concurrently and hence, free_job() work + * can never stall run_job() work. For EXEC jobs we don't have this + * requirement, since EXEC job's free_job() does not require to take any + * locks which indirectly or directly are held for allocations + * elsewhere. + */ + ret = nouveau_sched_init(&cli->sched, drm, NULL, 1); if (ret) goto done; @@ -579,13 +591,16 @@ nouveau_drm_device_init(struct drm_device *dev) nvif_parent_ctor(&nouveau_parent, &drm->parent); drm->master.base.object.parent = &drm->parent; - ret = nouveau_sched_init(drm); - if (ret) + drm->sched_wq = alloc_workqueue("nouveau_sched_wq_shared", 0, + WQ_MAX_ACTIVE); + if (!drm->sched_wq) { + ret = -ENOMEM; goto fail_alloc; + } ret = nouveau_cli_init(drm, "DRM-master", &drm->master); if (ret) - goto fail_sched; + goto fail_wq; ret = nouveau_cli_init(drm, "DRM", &drm->client); if (ret) @@ -655,8 +670,8 @@ fail_ttm: nouveau_cli_fini(&drm->client); fail_master: nouveau_cli_fini(&drm->master); -fail_sched: - nouveau_sched_fini(drm); +fail_wq: + destroy_workqueue(drm->sched_wq); fail_alloc: nvif_parent_dtor(&drm->parent); kfree(drm); @@ -708,10 +723,9 @@ nouveau_drm_device_fini(struct drm_device *dev) } mutex_unlock(&drm->clients_lock); - nouveau_sched_fini(drm); - nouveau_cli_fini(&drm->client); nouveau_cli_fini(&drm->master); + destroy_workqueue(drm->sched_wq); nvif_parent_dtor(&drm->parent); mutex_destroy(&drm->clients_lock); kfree(drm); diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index e73a233c657232..8a6d94c8b1631f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -93,9 +93,12 @@ struct nouveau_cli { struct nvif_mmu mmu; struct nouveau_vmm vmm; struct nouveau_vmm svm; - struct nouveau_uvmm uvmm; + struct { + struct nouveau_uvmm *ptr; + bool disabled; + } uvmm; - struct nouveau_sched_entity sched_entity; + struct nouveau_sched sched; const struct nvif_mclass *mem; @@ -121,10 +124,7 @@ struct nouveau_cli_work { static inline struct nouveau_uvmm * nouveau_cli_uvmm(struct nouveau_cli *cli) { - if (!cli || !cli->uvmm.vmm.cli) - return NULL; - - return &cli->uvmm; + return cli ? cli->uvmm.ptr : NULL; } static inline struct nouveau_uvmm * @@ -258,6 +258,9 @@ struct nouveau_drm { u64 context_base; } *runl; + /* Workqueue used for channel schedulers. */ + struct workqueue_struct *sched_wq; + /* context for accelerated drm-internal operations */ struct nouveau_channel *cechan; struct nouveau_channel *channel; @@ -298,10 +301,6 @@ struct nouveau_drm { struct mutex lock; bool component_registered; } audio; - - struct drm_gpu_scheduler sched; - struct workqueue_struct *sched_wq; - }; static inline struct nouveau_drm * diff --git a/drivers/gpu/drm/nouveau/nouveau_exec.c b/drivers/gpu/drm/nouveau/nouveau_exec.c index 9a5ef574744b34..bc5d71b79ab203 100644 --- a/drivers/gpu/drm/nouveau/nouveau_exec.c +++ b/drivers/gpu/drm/nouveau/nouveau_exec.c @@ -1,7 +1,5 @@ // SPDX-License-Identifier: MIT -#include - #include "nouveau_drv.h" #include "nouveau_gem.h" #include "nouveau_mem.h" @@ -86,14 +84,12 @@ */ static int -nouveau_exec_job_submit(struct nouveau_job *job) +nouveau_exec_job_submit(struct nouveau_job *job, + struct drm_gpuvm_exec *vme) { struct nouveau_exec_job *exec_job = to_nouveau_exec_job(job); struct nouveau_cli *cli = job->cli; struct nouveau_uvmm *uvmm = nouveau_cli_uvmm(cli); - struct drm_exec *exec = &job->exec; - struct drm_gem_object *obj; - unsigned long index; int ret; /* Create a new fence, but do not emit yet. */ @@ -102,52 +98,29 @@ nouveau_exec_job_submit(struct nouveau_job *job) return ret; nouveau_uvmm_lock(uvmm); - drm_exec_init(exec, DRM_EXEC_INTERRUPTIBLE_WAIT | - DRM_EXEC_IGNORE_DUPLICATES); - drm_exec_until_all_locked(exec) { - struct drm_gpuva *va; - - drm_gpuvm_for_each_va(va, &uvmm->base) { - if (unlikely(va == &uvmm->base.kernel_alloc_node)) - continue; - - ret = drm_exec_prepare_obj(exec, va->gem.obj, 1); - drm_exec_retry_on_contention(exec); - if (ret) - goto err_uvmm_unlock; - } + ret = drm_gpuvm_exec_lock(vme); + if (ret) { + nouveau_uvmm_unlock(uvmm); + return ret; } nouveau_uvmm_unlock(uvmm); - drm_exec_for_each_locked_object(exec, index, obj) { - struct nouveau_bo *nvbo = nouveau_gem_object(obj); - - ret = nouveau_bo_validate(nvbo, true, false); - if (ret) - goto err_exec_fini; + ret = drm_gpuvm_exec_validate(vme); + if (ret) { + drm_gpuvm_exec_unlock(vme); + return ret; } return 0; - -err_uvmm_unlock: - nouveau_uvmm_unlock(uvmm); -err_exec_fini: - drm_exec_fini(exec); - return ret; - } static void -nouveau_exec_job_armed_submit(struct nouveau_job *job) +nouveau_exec_job_armed_submit(struct nouveau_job *job, + struct drm_gpuvm_exec *vme) { - struct drm_exec *exec = &job->exec; - struct drm_gem_object *obj; - unsigned long index; - - drm_exec_for_each_locked_object(exec, index, obj) - dma_resv_add_fence(obj->resv, job->done_fence, job->resv_usage); - - drm_exec_fini(exec); + drm_gpuvm_exec_resv_add_fence(vme, job->done_fence, + job->resv_usage, job->resv_usage); + drm_gpuvm_exec_unlock(vme); } static struct dma_fence * @@ -192,6 +165,7 @@ nouveau_exec_job_free(struct nouveau_job *job) { struct nouveau_exec_job *exec_job = to_nouveau_exec_job(job); + nouveau_job_done(job); nouveau_job_free(job); kfree(exec_job->fence); @@ -211,8 +185,6 @@ nouveau_exec_job_timeout(struct nouveau_job *job) NV_PRINTK(warn, job->cli, "job timeout, channel %d killed!\n", chan->chid); - nouveau_sched_entity_fini(job->entity); - return DRM_GPU_SCHED_STAT_NOMINAL; } @@ -259,10 +231,12 @@ nouveau_exec_job_init(struct nouveau_exec_job **pjob, } } + args.file_priv = __args->file_priv; job->chan = __args->chan; - args.sched_entity = __args->sched_entity; - args.file_priv = __args->file_priv; + args.sched = __args->sched; + /* Plus one to account for the HW fence. */ + args.credits = job->push.count + 1; args.in_sync.count = __args->in_sync.count; args.in_sync.s = __args->in_sync.s; @@ -415,7 +389,7 @@ nouveau_exec_ioctl_exec(struct drm_device *dev, if (ret) goto out; - args.sched_entity = &chan16->sched_entity; + args.sched = &chan16->sched; args.file_priv = file_priv; args.chan = chan; diff --git a/drivers/gpu/drm/nouveau/nouveau_exec.h b/drivers/gpu/drm/nouveau/nouveau_exec.h index 5488d337bcc0e2..9b3b151facfd8a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_exec.h +++ b/drivers/gpu/drm/nouveau/nouveau_exec.h @@ -3,16 +3,12 @@ #ifndef __NOUVEAU_EXEC_H__ #define __NOUVEAU_EXEC_H__ -#include - #include "nouveau_drv.h" #include "nouveau_sched.h" struct nouveau_exec_job_args { struct drm_file *file_priv; - struct nouveau_sched_entity *sched_entity; - - struct drm_exec exec; + struct nouveau_sched *sched; struct nouveau_channel *chan; struct { diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 5057d976fa578c..ca762ea5541361 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -62,7 +62,7 @@ nouveau_fence_signal(struct nouveau_fence *fence) if (test_bit(DMA_FENCE_FLAG_USER_BITS, &fence->base.flags)) { struct nouveau_fence_chan *fctx = nouveau_fctx(fence); - if (atomic_dec_and_test(&fctx->notify_ref)) + if (!--fctx->notify_ref) drop = 1; } @@ -103,7 +103,6 @@ nouveau_fence_context_kill(struct nouveau_fence_chan *fctx, int error) void nouveau_fence_context_del(struct nouveau_fence_chan *fctx) { - cancel_work_sync(&fctx->allow_block_work); nouveau_fence_context_kill(fctx, 0); nvif_event_dtor(&fctx->event); fctx->dead = 1; @@ -168,18 +167,6 @@ nouveau_fence_wait_uevent_handler(struct nvif_event *event, void *repv, u32 repc return ret; } -static void -nouveau_fence_work_allow_block(struct work_struct *work) -{ - struct nouveau_fence_chan *fctx = container_of(work, struct nouveau_fence_chan, - allow_block_work); - - if (atomic_read(&fctx->notify_ref) == 0) - nvif_event_block(&fctx->event); - else - nvif_event_allow(&fctx->event); -} - void nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_chan *fctx) { @@ -191,7 +178,6 @@ nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_cha } args; int ret; - INIT_WORK(&fctx->allow_block_work, nouveau_fence_work_allow_block); INIT_LIST_HEAD(&fctx->flip); INIT_LIST_HEAD(&fctx->pending); spin_lock_init(&fctx->lock); @@ -535,19 +521,15 @@ static bool nouveau_fence_enable_signaling(struct dma_fence *f) struct nouveau_fence *fence = from_fence(f); struct nouveau_fence_chan *fctx = nouveau_fctx(fence); bool ret; - bool do_work; - if (atomic_inc_return(&fctx->notify_ref) == 0) - do_work = true; + if (!fctx->notify_ref++) + nvif_event_allow(&fctx->event); ret = nouveau_fence_no_signaling(f); if (ret) set_bit(DMA_FENCE_FLAG_USER_BITS, &fence->base.flags); - else if (atomic_dec_and_test(&fctx->notify_ref)) - do_work = true; - - if (do_work) - schedule_work(&fctx->allow_block_work); + else if (!--fctx->notify_ref) + nvif_event_block(&fctx->event); return ret; } diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.h b/drivers/gpu/drm/nouveau/nouveau_fence.h index 28f5cf013b8983..64d33ae7f35610 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.h +++ b/drivers/gpu/drm/nouveau/nouveau_fence.h @@ -3,7 +3,6 @@ #define __NOUVEAU_FENCE_H__ #include -#include #include struct nouveau_drm; @@ -46,9 +45,7 @@ struct nouveau_fence_chan { char name[32]; struct nvif_event event; - struct work_struct allow_block_work; - atomic_t notify_ref; - int dead, killed; + int notify_ref, dead, killed; }; struct nouveau_fence_priv { diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index a0d303e5ce3d8d..49c2bcbef1299d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -111,7 +111,8 @@ nouveau_gem_object_open(struct drm_gem_object *gem, struct drm_file *file_priv) if (vmm->vmm.object.oclass < NVIF_CLASS_VMM_NV50) return 0; - if (nvbo->no_share && uvmm && &uvmm->resv != nvbo->bo.base.resv) + if (nvbo->no_share && uvmm && + drm_gpuvm_resv(&uvmm->base) != nvbo->bo.base.resv) return -EPERM; ret = ttm_bo_reserve(&nvbo->bo, false, false, NULL); @@ -245,7 +246,7 @@ nouveau_gem_new(struct nouveau_cli *cli, u64 size, int align, uint32_t domain, if (unlikely(!uvmm)) return -EINVAL; - resv = &uvmm->resv; + resv = drm_gpuvm_resv(&uvmm->base); } if (!(domain & (NOUVEAU_GEM_DOMAIN_VRAM | NOUVEAU_GEM_DOMAIN_GART))) @@ -288,6 +289,11 @@ nouveau_gem_new(struct nouveau_cli *cli, u64 size, int align, uint32_t domain, if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) nvbo->valid_domains &= domain; + if (nvbo->no_share) { + nvbo->r_obj = drm_gpuvm_resv_obj(&uvmm->base); + drm_gem_object_get(nvbo->r_obj); + } + *pnvbo = nvbo; return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_platform.c b/drivers/gpu/drm/nouveau/nouveau_platform.c index 23cd43a7fd19a9..bf2dc7567ea40d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_platform.c +++ b/drivers/gpu/drm/nouveau/nouveau_platform.c @@ -43,11 +43,10 @@ static int nouveau_platform_probe(struct platform_device *pdev) return 0; } -static int nouveau_platform_remove(struct platform_device *pdev) +static void nouveau_platform_remove(struct platform_device *pdev) { struct drm_device *dev = platform_get_drvdata(pdev); nouveau_drm_device_remove(dev); - return 0; } #if IS_ENABLED(CONFIG_OF) @@ -93,5 +92,5 @@ struct platform_driver nouveau_platform_driver = { .of_match_table = of_match_ptr(nouveau_platform_match), }, .probe = nouveau_platform_probe, - .remove = nouveau_platform_remove, + .remove_new = nouveau_platform_remove, }; diff --git a/drivers/gpu/drm/nouveau/nouveau_sched.c b/drivers/gpu/drm/nouveau/nouveau_sched.c index 7c376c4ccdcf9b..dd98f6910f9cab 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sched.c +++ b/drivers/gpu/drm/nouveau/nouveau_sched.c @@ -12,30 +12,28 @@ #include "nouveau_abi16.h" #include "nouveau_sched.h" -/* FIXME - * - * We want to make sure that jobs currently executing can't be deferred by - * other jobs competing for the hardware. Otherwise we might end up with job - * timeouts just because of too many clients submitting too many jobs. We don't - * want jobs to time out because of system load, but because of the job being - * too bulky. - * - * For now allow for up to 16 concurrent jobs in flight until we know how many - * rings the hardware can process in parallel. - */ -#define NOUVEAU_SCHED_HW_SUBMISSIONS 16 #define NOUVEAU_SCHED_JOB_TIMEOUT_MS 10000 +/* Starts at 0, since the DRM scheduler interprets those parameters as (initial) + * index to the run-queue array. + */ +enum nouveau_sched_priority { + NOUVEAU_SCHED_PRIORITY_SINGLE = DRM_SCHED_PRIORITY_KERNEL, + NOUVEAU_SCHED_PRIORITY_COUNT, +}; + int nouveau_job_init(struct nouveau_job *job, struct nouveau_job_args *args) { - struct nouveau_sched_entity *entity = args->sched_entity; + struct nouveau_sched *sched = args->sched; int ret; + INIT_LIST_HEAD(&job->entry); + job->file_priv = args->file_priv; job->cli = nouveau_cli(args->file_priv); - job->entity = entity; + job->sched = sched; job->sync = args->sync; job->resv_usage = args->resv_usage; @@ -86,10 +84,10 @@ nouveau_job_init(struct nouveau_job *job, ret = -ENOMEM; goto err_free_objs; } - } - ret = drm_sched_job_init(&job->base, &entity->base, NULL); + ret = drm_sched_job_init(&job->base, &sched->entity, + args->credits, NULL); if (ret) goto err_free_chains; @@ -108,6 +106,27 @@ err_free_in_sync: return ret; } +void +nouveau_job_fini(struct nouveau_job *job) +{ + dma_fence_put(job->done_fence); + drm_sched_job_cleanup(&job->base); + + job->ops->free(job); +} + +void +nouveau_job_done(struct nouveau_job *job) +{ + struct nouveau_sched *sched = job->sched; + + spin_lock(&sched->job.list.lock); + list_del(&job->entry); + spin_unlock(&sched->job.list.lock); + + wake_up(&sched->job.wq); +} + void nouveau_job_free(struct nouveau_job *job) { @@ -117,13 +136,6 @@ nouveau_job_free(struct nouveau_job *job) kfree(job->out_sync.chains); } -void nouveau_job_fini(struct nouveau_job *job) -{ - dma_fence_put(job->done_fence); - drm_sched_job_cleanup(&job->base); - job->ops->free(job); -} - static int sync_find_fence(struct nouveau_job *job, struct drm_nouveau_sync *sync, @@ -261,8 +273,13 @@ nouveau_job_fence_attach(struct nouveau_job *job) int nouveau_job_submit(struct nouveau_job *job) { - struct nouveau_sched_entity *entity = to_nouveau_sched_entity(job->base.entity); + struct nouveau_sched *sched = job->sched; struct dma_fence *done_fence = NULL; + struct drm_gpuvm_exec vm_exec = { + .vm = &nouveau_cli_uvmm(job->cli)->base, + .flags = DRM_EXEC_IGNORE_DUPLICATES, + .num_fences = 1, + }; int ret; ret = nouveau_job_add_deps(job); @@ -276,46 +293,29 @@ nouveau_job_submit(struct nouveau_job *job) /* Make sure the job appears on the sched_entity's queue in the same * order as it was submitted. */ - mutex_lock(&entity->mutex); + mutex_lock(&sched->mutex); /* Guarantee we won't fail after the submit() callback returned * successfully. */ if (job->ops->submit) { - ret = job->ops->submit(job); + ret = job->ops->submit(job, &vm_exec); if (ret) goto err_cleanup; } + /* Submit was successful; add the job to the schedulers job list. */ + spin_lock(&sched->job.list.lock); + list_add(&job->entry, &sched->job.list.head); + spin_unlock(&sched->job.list.lock); + drm_sched_job_arm(&job->base); job->done_fence = dma_fence_get(&job->base.s_fence->finished); if (job->sync) done_fence = dma_fence_get(job->done_fence); - /* If a sched job depends on a dma-fence from a job from the same GPU - * scheduler instance, but a different scheduler entity, the GPU - * scheduler does only wait for the particular job to be scheduled, - * rather than for the job to fully complete. This is due to the GPU - * scheduler assuming that there is a scheduler instance per ring. - * However, the current implementation, in order to avoid arbitrary - * amounts of kthreads, has a single scheduler instance while scheduler - * entities represent rings. - * - * As a workaround, set the DRM_SCHED_FENCE_DONT_PIPELINE for all - * out-fences in order to force the scheduler to wait for full job - * completion for dependent jobs from different entities and same - * scheduler instance. - * - * There is some work in progress [1] to address the issues of firmware - * schedulers; once it is in-tree the scheduler topology in Nouveau - * should be re-worked accordingly. - * - * [1] https://lore.kernel.org/dri-devel/20230801205103.627779-1-matthew.brost@intel.com/ - */ - set_bit(DRM_SCHED_FENCE_DONT_PIPELINE, &job->done_fence->flags); - if (job->ops->armed_submit) - job->ops->armed_submit(job); + job->ops->armed_submit(job, &vm_exec); nouveau_job_fence_attach(job); @@ -326,7 +326,7 @@ nouveau_job_submit(struct nouveau_job *job) drm_sched_entity_push_job(&job->base); - mutex_unlock(&entity->mutex); + mutex_unlock(&sched->mutex); if (done_fence) { dma_fence_wait(done_fence, true); @@ -336,20 +336,13 @@ nouveau_job_submit(struct nouveau_job *job) return 0; err_cleanup: - mutex_unlock(&entity->mutex); + mutex_unlock(&sched->mutex); nouveau_job_fence_attach_cleanup(job); err: job->state = NOUVEAU_JOB_SUBMIT_FAILED; return ret; } -bool -nouveau_sched_entity_qwork(struct nouveau_sched_entity *entity, - struct work_struct *work) -{ - return queue_work(entity->sched_wq, work); -} - static struct dma_fence * nouveau_job_run(struct nouveau_job *job) { @@ -399,50 +392,82 @@ nouveau_sched_free_job(struct drm_sched_job *sched_job) nouveau_job_fini(job); } -int nouveau_sched_entity_init(struct nouveau_sched_entity *entity, - struct drm_gpu_scheduler *sched, - struct workqueue_struct *sched_wq) -{ - mutex_init(&entity->mutex); - spin_lock_init(&entity->job.list.lock); - INIT_LIST_HEAD(&entity->job.list.head); - init_waitqueue_head(&entity->job.wq); - - entity->sched_wq = sched_wq; - return drm_sched_entity_init(&entity->base, - DRM_SCHED_PRIORITY_NORMAL, - &sched, 1, NULL); -} - -void -nouveau_sched_entity_fini(struct nouveau_sched_entity *entity) -{ - drm_sched_entity_destroy(&entity->base); -} - static const struct drm_sched_backend_ops nouveau_sched_ops = { .run_job = nouveau_sched_run_job, .timedout_job = nouveau_sched_timedout_job, .free_job = nouveau_sched_free_job, }; -int nouveau_sched_init(struct nouveau_drm *drm) +int +nouveau_sched_init(struct nouveau_sched *sched, struct nouveau_drm *drm, + struct workqueue_struct *wq, u32 credit_limit) { - struct drm_gpu_scheduler *sched = &drm->sched; + struct drm_gpu_scheduler *drm_sched = &sched->base; + struct drm_sched_entity *entity = &sched->entity; long job_hang_limit = msecs_to_jiffies(NOUVEAU_SCHED_JOB_TIMEOUT_MS); + int ret; - drm->sched_wq = create_singlethread_workqueue("nouveau_sched_wq"); - if (!drm->sched_wq) - return -ENOMEM; + if (!wq) { + wq = alloc_workqueue("nouveau_sched_wq_%d", 0, WQ_MAX_ACTIVE, + current->pid); + if (!wq) + return -ENOMEM; + + sched->wq = wq; + } - return drm_sched_init(sched, &nouveau_sched_ops, - DRM_SCHED_PRIORITY_COUNT, - NOUVEAU_SCHED_HW_SUBMISSIONS, 0, job_hang_limit, - NULL, NULL, "nouveau_sched", drm->dev->dev); + ret = drm_sched_init(drm_sched, &nouveau_sched_ops, wq, + NOUVEAU_SCHED_PRIORITY_COUNT, + credit_limit, 0, job_hang_limit, + NULL, NULL, "nouveau_sched", drm->dev->dev); + if (ret) + goto fail_wq; + + /* Using DRM_SCHED_PRIORITY_KERNEL, since that's what we're required to use + * when we want to have a single run-queue only. + * + * It's not documented, but one will find out when trying to use any + * other priority running into faults, because the scheduler uses the + * priority as array index. + * + * Can't use NOUVEAU_SCHED_PRIORITY_SINGLE either, because it's not + * matching the enum type used in drm_sched_entity_init(). + */ + ret = drm_sched_entity_init(entity, DRM_SCHED_PRIORITY_KERNEL, + &drm_sched, 1, NULL); + if (ret) + goto fail_sched; + + mutex_init(&sched->mutex); + spin_lock_init(&sched->job.list.lock); + INIT_LIST_HEAD(&sched->job.list.head); + init_waitqueue_head(&sched->job.wq); + + return 0; + +fail_sched: + drm_sched_fini(drm_sched); +fail_wq: + if (sched->wq) + destroy_workqueue(sched->wq); + return ret; } -void nouveau_sched_fini(struct nouveau_drm *drm) +void +nouveau_sched_fini(struct nouveau_sched *sched) { - destroy_workqueue(drm->sched_wq); - drm_sched_fini(&drm->sched); + struct drm_gpu_scheduler *drm_sched = &sched->base; + struct drm_sched_entity *entity = &sched->entity; + + rmb(); /* for list_empty to work without lock */ + wait_event(sched->job.wq, list_empty(&sched->job.list.head)); + + drm_sched_entity_fini(entity); + drm_sched_fini(drm_sched); + + /* Destroy workqueue after scheduler tear down, otherwise it might still + * be in use. + */ + if (sched->wq) + destroy_workqueue(sched->wq); } diff --git a/drivers/gpu/drm/nouveau/nouveau_sched.h b/drivers/gpu/drm/nouveau/nouveau_sched.h index 27ac19792597bd..a6528f5981e6a6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sched.h +++ b/drivers/gpu/drm/nouveau/nouveau_sched.h @@ -5,7 +5,7 @@ #include -#include +#include #include #include "nouveau_drv.h" @@ -26,7 +26,8 @@ enum nouveau_job_state { struct nouveau_job_args { struct drm_file *file_priv; - struct nouveau_sched_entity *sched_entity; + struct nouveau_sched *sched; + u32 credits; enum dma_resv_usage resv_usage; bool sync; @@ -49,12 +50,12 @@ struct nouveau_job { enum nouveau_job_state state; - struct nouveau_sched_entity *entity; + struct nouveau_sched *sched; + struct list_head entry; struct drm_file *file_priv; struct nouveau_cli *cli; - struct drm_exec exec; enum dma_resv_usage resv_usage; struct dma_fence *done_fence; @@ -76,8 +77,8 @@ struct nouveau_job { /* If .submit() returns without any error, it is guaranteed that * armed_submit() is called. */ - int (*submit)(struct nouveau_job *); - void (*armed_submit)(struct nouveau_job *); + int (*submit)(struct nouveau_job *, struct drm_gpuvm_exec *); + void (*armed_submit)(struct nouveau_job *, struct drm_gpuvm_exec *); struct dma_fence *(*run)(struct nouveau_job *); void (*free)(struct nouveau_job *); enum drm_gpu_sched_stat (*timeout)(struct nouveau_job *); @@ -90,20 +91,17 @@ int nouveau_job_ucopy_syncs(struct nouveau_job_args *args, int nouveau_job_init(struct nouveau_job *job, struct nouveau_job_args *args); -void nouveau_job_free(struct nouveau_job *job); - -int nouveau_job_submit(struct nouveau_job *job); void nouveau_job_fini(struct nouveau_job *job); +int nouveau_job_submit(struct nouveau_job *job); +void nouveau_job_done(struct nouveau_job *job); +void nouveau_job_free(struct nouveau_job *job); -#define to_nouveau_sched_entity(entity) \ - container_of((entity), struct nouveau_sched_entity, base) - -struct nouveau_sched_entity { - struct drm_sched_entity base; +struct nouveau_sched { + struct drm_gpu_scheduler base; + struct drm_sched_entity entity; + struct workqueue_struct *wq; struct mutex mutex; - struct workqueue_struct *sched_wq; - struct { struct { struct list_head head; @@ -113,15 +111,8 @@ struct nouveau_sched_entity { } job; }; -int nouveau_sched_entity_init(struct nouveau_sched_entity *entity, - struct drm_gpu_scheduler *sched, - struct workqueue_struct *sched_wq); -void nouveau_sched_entity_fini(struct nouveau_sched_entity *entity); - -bool nouveau_sched_entity_qwork(struct nouveau_sched_entity *entity, - struct work_struct *work); - -int nouveau_sched_init(struct nouveau_drm *drm); -void nouveau_sched_fini(struct nouveau_drm *drm); +int nouveau_sched_init(struct nouveau_sched *sched, struct nouveau_drm *drm, + struct workqueue_struct *wq, u32 credit_limit); +void nouveau_sched_fini(struct nouveau_sched *sched); #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.c b/drivers/gpu/drm/nouveau/nouveau_uvmm.c index 5cf892c50f43ca..4f223c972c6a8c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_uvmm.c +++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.c @@ -62,6 +62,8 @@ struct bind_job_op { enum vm_bind_op op; u32 flags; + struct drm_gpuvm_bo *vm_bo; + struct { u64 addr; u64 range; @@ -436,8 +438,9 @@ nouveau_uvma_region_complete(struct nouveau_uvma_region *reg) static void op_map_prepare_unwind(struct nouveau_uvma *uvma) { + struct drm_gpuva *va = &uvma->va; nouveau_uvma_gem_put(uvma); - drm_gpuva_remove(&uvma->va); + drm_gpuva_remove(va); nouveau_uvma_free(uvma); } @@ -466,6 +469,7 @@ nouveau_uvmm_sm_prepare_unwind(struct nouveau_uvmm *uvmm, break; case DRM_GPUVA_OP_REMAP: { struct drm_gpuva_op_remap *r = &op->remap; + struct drm_gpuva *va = r->unmap->va; if (r->next) op_map_prepare_unwind(new->next); @@ -473,7 +477,7 @@ nouveau_uvmm_sm_prepare_unwind(struct nouveau_uvmm *uvmm, if (r->prev) op_map_prepare_unwind(new->prev); - op_unmap_prepare_unwind(r->unmap->va); + op_unmap_prepare_unwind(va); break; } case DRM_GPUVA_OP_UNMAP: @@ -604,6 +608,9 @@ op_unmap_prepare(struct drm_gpuva_op_unmap *u) drm_gpuva_unmap(u); } +/* + * Note: @args should not be NULL when calling for a map operation. + */ static int nouveau_uvmm_sm_prepare(struct nouveau_uvmm *uvmm, struct nouveau_uvma_prealloc *new, @@ -624,7 +631,7 @@ nouveau_uvmm_sm_prepare(struct nouveau_uvmm *uvmm, if (ret) goto unwind; - if (args && vmm_get_range) { + if (vmm_get_range) { ret = nouveau_uvmm_vmm_get(uvmm, vmm_get_start, vmm_get_range); if (ret) { @@ -632,6 +639,7 @@ nouveau_uvmm_sm_prepare(struct nouveau_uvmm *uvmm, goto unwind; } } + break; } case DRM_GPUVA_OP_REMAP: { @@ -929,25 +937,13 @@ nouveau_uvmm_sm_unmap_cleanup(struct nouveau_uvmm *uvmm, static int nouveau_uvmm_validate_range(struct nouveau_uvmm *uvmm, u64 addr, u64 range) { - u64 end = addr + range; - u64 kernel_managed_end = uvmm->kernel_managed_addr + - uvmm->kernel_managed_size; - if (addr & ~PAGE_MASK) return -EINVAL; if (range & ~PAGE_MASK) return -EINVAL; - if (end <= addr) - return -EINVAL; - - if (addr < NOUVEAU_VA_SPACE_START || - end > NOUVEAU_VA_SPACE_END) - return -EINVAL; - - if (addr < kernel_managed_end && - end > uvmm->kernel_managed_addr) + if (!drm_gpuvm_range_valid(&uvmm->base, addr, range)) return -EINVAL; return 0; @@ -970,6 +966,12 @@ nouveau_uvmm_bind_job_free(struct kref *kref) { struct nouveau_uvmm_bind_job *job = container_of(kref, struct nouveau_uvmm_bind_job, kref); + struct bind_job_op *op, *next; + + list_for_each_op_safe(op, next, &job->ops) { + list_del(&op->entry); + kfree(op); + } nouveau_job_free(&job->base); kfree(job); @@ -1011,14 +1013,16 @@ bind_validate_op(struct nouveau_job *job, static void bind_validate_map_sparse(struct nouveau_job *job, u64 addr, u64 range) { - struct nouveau_uvmm_bind_job *bind_job; - struct nouveau_sched_entity *entity = job->entity; + struct nouveau_sched *sched = job->sched; + struct nouveau_job *__job; struct bind_job_op *op; u64 end = addr + range; again: - spin_lock(&entity->job.list.lock); - list_for_each_entry(bind_job, &entity->job.list.head, entry) { + spin_lock(&sched->job.list.lock); + list_for_each_entry(__job, &sched->job.list.head, entry) { + struct nouveau_uvmm_bind_job *bind_job = to_uvmm_bind_job(__job); + list_for_each_op(op, &bind_job->ops) { if (op->op == OP_UNMAP) { u64 op_addr = op->va.addr; @@ -1026,7 +1030,7 @@ again: if (!(end <= op_addr || addr >= op_end)) { nouveau_uvmm_bind_job_get(bind_job); - spin_unlock(&entity->job.list.lock); + spin_unlock(&sched->job.list.lock); wait_for_completion(&bind_job->complete); nouveau_uvmm_bind_job_put(bind_job); goto again; @@ -1034,7 +1038,7 @@ again: } } } - spin_unlock(&entity->job.list.lock); + spin_unlock(&sched->job.list.lock); } static int @@ -1113,22 +1117,28 @@ bind_validate_region(struct nouveau_job *job) } static void -bind_link_gpuvas(struct drm_gpuva_ops *ops, struct nouveau_uvma_prealloc *new) +bind_link_gpuvas(struct bind_job_op *bop) { + struct nouveau_uvma_prealloc *new = &bop->new; + struct drm_gpuvm_bo *vm_bo = bop->vm_bo; + struct drm_gpuva_ops *ops = bop->ops; struct drm_gpuva_op *op; drm_gpuva_for_each_op(op, ops) { switch (op->op) { case DRM_GPUVA_OP_MAP: - drm_gpuva_link(&new->map->va); + drm_gpuva_link(&new->map->va, vm_bo); break; - case DRM_GPUVA_OP_REMAP: + case DRM_GPUVA_OP_REMAP: { + struct drm_gpuva *va = op->remap.unmap->va; + if (op->remap.prev) - drm_gpuva_link(&new->prev->va); + drm_gpuva_link(&new->prev->va, va->vm_bo); if (op->remap.next) - drm_gpuva_link(&new->next->va); - drm_gpuva_unlink(op->remap.unmap->va); + drm_gpuva_link(&new->next->va, va->vm_bo); + drm_gpuva_unlink(va); break; + } case DRM_GPUVA_OP_UNMAP: drm_gpuva_unlink(op->unmap.va); break; @@ -1139,21 +1149,70 @@ bind_link_gpuvas(struct drm_gpuva_ops *ops, struct nouveau_uvma_prealloc *new) } static int -nouveau_uvmm_bind_job_submit(struct nouveau_job *job) +bind_lock_validate(struct nouveau_job *job, struct drm_exec *exec, + unsigned int num_fences) +{ + struct nouveau_uvmm_bind_job *bind_job = to_uvmm_bind_job(job); + struct bind_job_op *op; + int ret; + + list_for_each_op(op, &bind_job->ops) { + struct drm_gpuva_op *va_op; + + if (!op->ops) + continue; + + drm_gpuva_for_each_op(va_op, op->ops) { + struct drm_gem_object *obj = op_gem_obj(va_op); + + if (unlikely(!obj)) + continue; + + ret = drm_exec_prepare_obj(exec, obj, num_fences); + if (ret) + return ret; + + /* Don't validate GEMs backing mappings we're about to + * unmap, it's not worth the effort. + */ + if (va_op->op == DRM_GPUVA_OP_UNMAP) + continue; + + ret = nouveau_bo_validate(nouveau_gem_object(obj), + true, false); + if (ret) + return ret; + } + } + + return 0; +} + +static int +nouveau_uvmm_bind_job_submit(struct nouveau_job *job, + struct drm_gpuvm_exec *vme) { struct nouveau_uvmm *uvmm = nouveau_cli_uvmm(job->cli); struct nouveau_uvmm_bind_job *bind_job = to_uvmm_bind_job(job); - struct nouveau_sched_entity *entity = job->entity; - struct drm_exec *exec = &job->exec; + struct drm_exec *exec = &vme->exec; struct bind_job_op *op; int ret; list_for_each_op(op, &bind_job->ops) { if (op->op == OP_MAP) { - op->gem.obj = drm_gem_object_lookup(job->file_priv, - op->gem.handle); - if (!op->gem.obj) + struct drm_gem_object *obj = op->gem.obj = + drm_gem_object_lookup(job->file_priv, + op->gem.handle); + if (!obj) return -ENOENT; + + dma_resv_lock(obj->resv, NULL); + op->vm_bo = drm_gpuvm_bo_obtain(&uvmm->base, obj); + dma_resv_unlock(obj->resv); + if (IS_ERR(op->vm_bo)) + return PTR_ERR(op->vm_bo); + + drm_gpuvm_bo_extobj_add(op->vm_bo); } ret = bind_validate_op(job, op); @@ -1176,6 +1235,7 @@ nouveau_uvmm_bind_job_submit(struct nouveau_job *job) * unwind all GPU VA space changes on failure. */ nouveau_uvmm_lock(uvmm); + list_for_each_op(op, &bind_job->ops) { switch (op->op) { case OP_MAP_SPARSE: @@ -1287,55 +1347,13 @@ nouveau_uvmm_bind_job_submit(struct nouveau_job *job) } } - drm_exec_init(exec, DRM_EXEC_INTERRUPTIBLE_WAIT | - DRM_EXEC_IGNORE_DUPLICATES); + drm_exec_init(exec, vme->flags, 0); drm_exec_until_all_locked(exec) { - list_for_each_op(op, &bind_job->ops) { - struct drm_gpuva_op *va_op; - - if (IS_ERR_OR_NULL(op->ops)) - continue; - - drm_gpuva_for_each_op(va_op, op->ops) { - struct drm_gem_object *obj = op_gem_obj(va_op); - - if (unlikely(!obj)) - continue; - - ret = drm_exec_prepare_obj(exec, obj, 1); - drm_exec_retry_on_contention(exec); - if (ret) { - op = list_last_op(&bind_job->ops); - goto unwind; - } - } - } - } - - list_for_each_op(op, &bind_job->ops) { - struct drm_gpuva_op *va_op; - - if (IS_ERR_OR_NULL(op->ops)) - continue; - - drm_gpuva_for_each_op(va_op, op->ops) { - struct drm_gem_object *obj = op_gem_obj(va_op); - - if (unlikely(!obj)) - continue; - - /* Don't validate GEMs backing mappings we're about to - * unmap, it's not worth the effort. - */ - if (unlikely(va_op->op == DRM_GPUVA_OP_UNMAP)) - continue; - - ret = nouveau_bo_validate(nouveau_gem_object(obj), - true, false); - if (ret) { - op = list_last_op(&bind_job->ops); - goto unwind; - } + ret = bind_lock_validate(job, exec, vme->num_fences); + drm_exec_retry_on_contention(exec); + if (ret) { + op = list_last_op(&bind_job->ops); + goto unwind; } } @@ -1364,7 +1382,7 @@ nouveau_uvmm_bind_job_submit(struct nouveau_job *job) case OP_UNMAP_SPARSE: case OP_MAP: case OP_UNMAP: - bind_link_gpuvas(op->ops, &op->new); + bind_link_gpuvas(op); break; default: break; @@ -1372,10 +1390,6 @@ nouveau_uvmm_bind_job_submit(struct nouveau_job *job) } nouveau_uvmm_unlock(uvmm); - spin_lock(&entity->job.list.lock); - list_add(&bind_job->entry, &entity->job.list.head); - spin_unlock(&entity->job.list.lock); - return 0; unwind_continue: @@ -1410,21 +1424,17 @@ unwind: } nouveau_uvmm_unlock(uvmm); - drm_exec_fini(exec); + drm_gpuvm_exec_unlock(vme); return ret; } static void -nouveau_uvmm_bind_job_armed_submit(struct nouveau_job *job) +nouveau_uvmm_bind_job_armed_submit(struct nouveau_job *job, + struct drm_gpuvm_exec *vme) { - struct drm_exec *exec = &job->exec; - struct drm_gem_object *obj; - unsigned long index; - - drm_exec_for_each_locked_object(exec, index, obj) - dma_resv_add_fence(obj->resv, job->done_fence, job->resv_usage); - - drm_exec_fini(exec); + drm_gpuvm_exec_resv_add_fence(vme, job->done_fence, + job->resv_usage, job->resv_usage); + drm_gpuvm_exec_unlock(vme); } static struct dma_fence * @@ -1462,14 +1472,11 @@ out: } static void -nouveau_uvmm_bind_job_free_work_fn(struct work_struct *work) +nouveau_uvmm_bind_job_cleanup(struct nouveau_job *job) { - struct nouveau_uvmm_bind_job *bind_job = - container_of(work, struct nouveau_uvmm_bind_job, work); - struct nouveau_job *job = &bind_job->base; + struct nouveau_uvmm_bind_job *bind_job = to_uvmm_bind_job(job); struct nouveau_uvmm *uvmm = nouveau_cli_uvmm(job->cli); - struct nouveau_sched_entity *entity = job->entity; - struct bind_job_op *op, *next; + struct bind_job_op *op; list_for_each_op(op, &bind_job->ops) { struct drm_gem_object *obj = op->gem.obj; @@ -1511,42 +1518,27 @@ nouveau_uvmm_bind_job_free_work_fn(struct work_struct *work) if (!IS_ERR_OR_NULL(op->ops)) drm_gpuva_ops_free(&uvmm->base, op->ops); + if (!IS_ERR_OR_NULL(op->vm_bo)) { + dma_resv_lock(obj->resv, NULL); + drm_gpuvm_bo_put(op->vm_bo); + dma_resv_unlock(obj->resv); + } + if (obj) drm_gem_object_put(obj); } - spin_lock(&entity->job.list.lock); - list_del(&bind_job->entry); - spin_unlock(&entity->job.list.lock); - + nouveau_job_done(job); complete_all(&bind_job->complete); - wake_up(&entity->job.wq); - - /* Remove and free ops after removing the bind job from the job list to - * avoid races against bind_validate_map_sparse(). - */ - list_for_each_op_safe(op, next, &bind_job->ops) { - list_del(&op->entry); - kfree(op); - } nouveau_uvmm_bind_job_put(bind_job); } -static void -nouveau_uvmm_bind_job_free_qwork(struct nouveau_job *job) -{ - struct nouveau_uvmm_bind_job *bind_job = to_uvmm_bind_job(job); - struct nouveau_sched_entity *entity = job->entity; - - nouveau_sched_entity_qwork(entity, &bind_job->work); -} - static struct nouveau_job_ops nouveau_bind_job_ops = { .submit = nouveau_uvmm_bind_job_submit, .armed_submit = nouveau_uvmm_bind_job_armed_submit, .run = nouveau_uvmm_bind_job_run, - .free = nouveau_uvmm_bind_job_free_qwork, + .free = nouveau_uvmm_bind_job_cleanup, }; static int @@ -1607,7 +1599,6 @@ nouveau_uvmm_bind_job_init(struct nouveau_uvmm_bind_job **pjob, return ret; INIT_LIST_HEAD(&job->ops); - INIT_LIST_HEAD(&job->entry); for (i = 0; i < __args->op.count; i++) { ret = bind_job_op_from_uop(&op, &__args->op.s[i]); @@ -1618,11 +1609,12 @@ nouveau_uvmm_bind_job_init(struct nouveau_uvmm_bind_job **pjob, } init_completion(&job->complete); - INIT_WORK(&job->work, nouveau_uvmm_bind_job_free_work_fn); - args.sched_entity = __args->sched_entity; args.file_priv = __args->file_priv; + args.sched = __args->sched; + args.credits = 1; + args.in_sync.count = __args->in_sync.count; args.in_sync.s = __args->in_sync.s; @@ -1648,18 +1640,6 @@ err_free: return ret; } -int -nouveau_uvmm_ioctl_vm_init(struct drm_device *dev, - void *data, - struct drm_file *file_priv) -{ - struct nouveau_cli *cli = nouveau_cli(file_priv); - struct drm_nouveau_vm_init *init = data; - - return nouveau_uvmm_init(&cli->uvmm, cli, init->kernel_managed_addr, - init->kernel_managed_size); -} - static int nouveau_uvmm_vm_bind(struct nouveau_uvmm_bind_job_args *args) { @@ -1760,7 +1740,7 @@ nouveau_uvmm_ioctl_vm_bind(struct drm_device *dev, if (ret) return ret; - args.sched_entity = &cli->sched_entity; + args.sched = &cli->sched; args.file_priv = file_priv; ret = nouveau_uvmm_vm_bind(&args); @@ -1776,15 +1756,18 @@ void nouveau_uvmm_bo_map_all(struct nouveau_bo *nvbo, struct nouveau_mem *mem) { struct drm_gem_object *obj = &nvbo->bo.base; + struct drm_gpuvm_bo *vm_bo; struct drm_gpuva *va; dma_resv_assert_held(obj->resv); - drm_gem_for_each_gpuva(va, obj) { - struct nouveau_uvma *uvma = uvma_from_va(va); + drm_gem_for_each_gpuvm_bo(vm_bo, obj) { + drm_gpuvm_bo_for_each_va(va, vm_bo) { + struct nouveau_uvma *uvma = uvma_from_va(va); - nouveau_uvma_map(uvma, mem); - drm_gpuva_invalidate(va, false); + nouveau_uvma_map(uvma, mem); + drm_gpuva_invalidate(va, false); + } } } @@ -1792,29 +1775,62 @@ void nouveau_uvmm_bo_unmap_all(struct nouveau_bo *nvbo) { struct drm_gem_object *obj = &nvbo->bo.base; + struct drm_gpuvm_bo *vm_bo; struct drm_gpuva *va; dma_resv_assert_held(obj->resv); - drm_gem_for_each_gpuva(va, obj) { - struct nouveau_uvma *uvma = uvma_from_va(va); + drm_gem_for_each_gpuvm_bo(vm_bo, obj) { + drm_gpuvm_bo_for_each_va(va, vm_bo) { + struct nouveau_uvma *uvma = uvma_from_va(va); - nouveau_uvma_unmap(uvma); - drm_gpuva_invalidate(va, true); + nouveau_uvma_unmap(uvma); + drm_gpuva_invalidate(va, true); + } } } +static void +nouveau_uvmm_free(struct drm_gpuvm *gpuvm) +{ + struct nouveau_uvmm *uvmm = uvmm_from_gpuvm(gpuvm); + + kfree(uvmm); +} + +static int +nouveau_uvmm_bo_validate(struct drm_gpuvm_bo *vm_bo, struct drm_exec *exec) +{ + struct nouveau_bo *nvbo = nouveau_gem_object(vm_bo->obj); + + return nouveau_bo_validate(nvbo, true, false); +} + +static const struct drm_gpuvm_ops gpuvm_ops = { + .vm_free = nouveau_uvmm_free, + .vm_bo_validate = nouveau_uvmm_bo_validate, +}; + int -nouveau_uvmm_init(struct nouveau_uvmm *uvmm, struct nouveau_cli *cli, - u64 kernel_managed_addr, u64 kernel_managed_size) +nouveau_uvmm_ioctl_vm_init(struct drm_device *dev, + void *data, + struct drm_file *file_priv) { + struct nouveau_uvmm *uvmm; + struct nouveau_cli *cli = nouveau_cli(file_priv); + struct drm_device *drm = cli->drm->dev; + struct drm_gem_object *r_obj; + struct drm_nouveau_vm_init *init = data; + u64 kernel_managed_end; int ret; - u64 kernel_managed_end = kernel_managed_addr + kernel_managed_size; - mutex_init(&uvmm->mutex); - dma_resv_init(&uvmm->resv); - mt_init_flags(&uvmm->region_mt, MT_FLAGS_LOCK_EXTERN); - mt_set_external_lock(&uvmm->region_mt, &uvmm->mutex); + if (check_add_overflow(init->kernel_managed_addr, + init->kernel_managed_size, + &kernel_managed_end)) + return -EINVAL; + + if (kernel_managed_end > NOUVEAU_VA_SPACE_END) + return -EINVAL; mutex_lock(&cli->mutex); @@ -1823,39 +1839,48 @@ nouveau_uvmm_init(struct nouveau_uvmm *uvmm, struct nouveau_cli *cli, goto out_unlock; } - if (kernel_managed_end <= kernel_managed_addr) { - ret = -EINVAL; + uvmm = kzalloc(sizeof(*uvmm), GFP_KERNEL); + if (!uvmm) { + ret = -ENOMEM; goto out_unlock; } - if (kernel_managed_end > NOUVEAU_VA_SPACE_END) { - ret = -EINVAL; + r_obj = drm_gpuvm_resv_object_alloc(drm); + if (!r_obj) { + kfree(uvmm); + ret = -ENOMEM; goto out_unlock; } - uvmm->kernel_managed_addr = kernel_managed_addr; - uvmm->kernel_managed_size = kernel_managed_size; + mutex_init(&uvmm->mutex); + mt_init_flags(&uvmm->region_mt, MT_FLAGS_LOCK_EXTERN); + mt_set_external_lock(&uvmm->region_mt, &uvmm->mutex); - drm_gpuvm_init(&uvmm->base, cli->name, + drm_gpuvm_init(&uvmm->base, cli->name, 0, drm, r_obj, NOUVEAU_VA_SPACE_START, NOUVEAU_VA_SPACE_END, - kernel_managed_addr, kernel_managed_size, - NULL); + init->kernel_managed_addr, + init->kernel_managed_size, + &gpuvm_ops); + /* GPUVM takes care from here on. */ + drm_gem_object_put(r_obj); ret = nvif_vmm_ctor(&cli->mmu, "uvmm", cli->vmm.vmm.object.oclass, RAW, - kernel_managed_addr, kernel_managed_size, - NULL, 0, &cli->uvmm.vmm.vmm); + init->kernel_managed_addr, + init->kernel_managed_size, + NULL, 0, &uvmm->vmm.vmm); if (ret) - goto out_free_gpuva_mgr; + goto out_gpuvm_fini; - cli->uvmm.vmm.cli = cli; + uvmm->vmm.cli = cli; + cli->uvmm.ptr = uvmm; mutex_unlock(&cli->mutex); return 0; -out_free_gpuva_mgr: - drm_gpuvm_destroy(&uvmm->base); +out_gpuvm_fini: + drm_gpuvm_put(&uvmm->base); out_unlock: mutex_unlock(&cli->mutex); return ret; @@ -1867,15 +1892,8 @@ nouveau_uvmm_fini(struct nouveau_uvmm *uvmm) MA_STATE(mas, &uvmm->region_mt, 0, 0); struct nouveau_uvma_region *reg; struct nouveau_cli *cli = uvmm->vmm.cli; - struct nouveau_sched_entity *entity = &cli->sched_entity; struct drm_gpuva *va, *next; - if (!cli) - return; - - rmb(); /* for list_empty to work without lock */ - wait_event(entity->job.wq, list_empty(&entity->job.list.head)); - nouveau_uvmm_lock(uvmm); drm_gpuvm_for_each_va_safe(va, next, &uvmm->base) { struct nouveau_uvma *uvma = uvma_from_va(va); @@ -1910,8 +1928,6 @@ nouveau_uvmm_fini(struct nouveau_uvmm *uvmm) mutex_lock(&cli->mutex); nouveau_vmm_fini(&uvmm->vmm); - drm_gpuvm_destroy(&uvmm->base); + drm_gpuvm_put(&uvmm->base); mutex_unlock(&cli->mutex); - - dma_resv_fini(&uvmm->resv); } diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.h b/drivers/gpu/drm/nouveau/nouveau_uvmm.h index a308c59760a54a..9d3c348581eb34 100644 --- a/drivers/gpu/drm/nouveau/nouveau_uvmm.h +++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.h @@ -12,12 +12,6 @@ struct nouveau_uvmm { struct nouveau_vmm vmm; struct maple_tree region_mt; struct mutex mutex; - struct dma_resv resv; - - u64 kernel_managed_addr; - u64 kernel_managed_size; - - bool disabled; }; struct nouveau_uvma_region { @@ -50,8 +44,6 @@ struct nouveau_uvmm_bind_job { struct nouveau_job base; struct kref kref; - struct list_head entry; - struct work_struct work; struct completion complete; /* struct bind_job_op */ @@ -60,7 +52,7 @@ struct nouveau_uvmm_bind_job { struct nouveau_uvmm_bind_job_args { struct drm_file *file_priv; - struct nouveau_sched_entity *sched_entity; + struct nouveau_sched *sched; unsigned int flags; @@ -82,8 +74,6 @@ struct nouveau_uvmm_bind_job_args { #define to_uvmm_bind_job(job) container_of((job), struct nouveau_uvmm_bind_job, base) -int nouveau_uvmm_init(struct nouveau_uvmm *uvmm, struct nouveau_cli *cli, - u64 kernel_managed_addr, u64 kernel_managed_size); void nouveau_uvmm_fini(struct nouveau_uvmm *uvmm); void nouveau_uvmm_bo_map_all(struct nouveau_bo *nvbov, struct nouveau_mem *mem); diff --git a/drivers/gpu/drm/nouveau/nouveau_vmm.c b/drivers/gpu/drm/nouveau/nouveau_vmm.c index a6602c01267156..3dda885df5b223 100644 --- a/drivers/gpu/drm/nouveau/nouveau_vmm.c +++ b/drivers/gpu/drm/nouveau/nouveau_vmm.c @@ -108,6 +108,9 @@ nouveau_vma_new(struct nouveau_bo *nvbo, struct nouveau_vmm *vmm, } else { ret = nvif_vmm_get(&vmm->vmm, PTES, false, mem->mem.page, 0, mem->mem.size, &tmp); + if (ret) + goto done; + vma->addr = tmp.addr; } diff --git a/drivers/gpu/drm/nouveau/nv04_fence.c b/drivers/gpu/drm/nouveau/nv04_fence.c index 5b71a5a5cd85ce..cdbc75e3d1f669 100644 --- a/drivers/gpu/drm/nouveau/nv04_fence.c +++ b/drivers/gpu/drm/nouveau/nv04_fence.c @@ -39,7 +39,7 @@ struct nv04_fence_priv { static int nv04_fence_emit(struct nouveau_fence *fence) { - struct nvif_push *push = fence->channel->chan.push; + struct nvif_push *push = unrcu_pointer(fence->channel)->chan.push; int ret = PUSH_WAIT(push, 2); if (ret == 0) { PUSH_NVSQ(push, NV_SW, 0x0150, fence->base.seqno); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c index 87a62d4ff4bda4..7d4716dcd51299 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c @@ -24,7 +24,6 @@ #include "chan.h" #include "chid.h" #include "cgrp.h" -#include "chid.h" #include "runl.h" #include "priv.h" diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga100.c index c8ce7ff187135b..e74493a4569edb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/ga100.c @@ -550,6 +550,10 @@ ga100_fifo_nonstall_ctor(struct nvkm_fifo *fifo) struct nvkm_engn *engn = list_first_entry(&runl->engns, typeof(*engn), head); runl->nonstall.vector = engn->func->nonstall(engn); + + /* if no nonstall vector just keep going */ + if (runl->nonstall.vector == -1) + continue; if (runl->nonstall.vector < 0) { RUNL_ERROR(runl, "nonstall %d", runl->nonstall.vector); return runl->nonstall.vector; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/r535.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/r535.c index b903785056b5de..3454c7d2950295 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/r535.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/r535.c @@ -351,7 +351,7 @@ r535_engn_nonstall(struct nvkm_engn *engn) int ret; ret = nvkm_gsp_intr_nonstall(subdev->device->gsp, subdev->type, subdev->inst); - WARN_ON(ret < 0); + WARN_ON(ret == -ENOENT); return ret; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/base.c index 04bceaa28a197d..da1bebb896f7fb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/base.c @@ -25,12 +25,8 @@ int nvkm_gsp_intr_nonstall(struct nvkm_gsp *gsp, enum nvkm_subdev_type type, int inst) { for (int i = 0; i < gsp->intr_nr; i++) { - if (gsp->intr[i].type == type && gsp->intr[i].inst == inst) { - if (gsp->intr[i].nonstall != ~0) - return gsp->intr[i].nonstall; - - return -EINVAL; - } + if (gsp->intr[i].type == type && gsp->intr[i].inst == inst) + return gsp->intr[i].nonstall; } return -ENOENT; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp10b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp10b.c index e7e8fdf3adab7a..29682722b0b36b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp10b.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gp10b.c @@ -28,19 +28,14 @@ static void gp10b_ltc_init(struct nvkm_ltc *ltc) { struct nvkm_device *device = ltc->subdev.device; - struct iommu_fwspec *spec; + u32 sid; nvkm_wr32(device, 0x17e27c, ltc->ltc_nr); nvkm_wr32(device, 0x17e000, ltc->ltc_nr); nvkm_wr32(device, 0x100800, ltc->ltc_nr); - spec = dev_iommu_fwspec_get(device->dev); - if (spec) { - u32 sid = spec->ids[0] & 0xffff; - - /* stream ID */ + if (tegra_dev_iommu_get_stream_id(device->dev, &sid)) nvkm_wr32(device, 0x160000, sid << 2); - } } static const struct nvkm_ltc_func diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index c26aab4939fa00..993691b3cc7ead 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -22,11 +22,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include @@ -4765,7 +4765,7 @@ static int dispc_bind(struct device *dev, struct device *master, void *data) if (soc) dispc->feat = soc->data; else - dispc->feat = of_match_device(dispc_of_match, &pdev->dev)->data; + dispc->feat = device_get_match_data(&pdev->dev); r = dispc_errata_i734_wa_init(dispc); if (r) diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c index 02955f97684596..988888e164d7b3 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -22,12 +22,13 @@ #include #include #include +#include #include #include #include #include #include -#include +#include #include #include #include @@ -1445,7 +1446,7 @@ static int dss_probe(struct platform_device *pdev) if (soc) dss->feat = soc->data; else - dss->feat = of_match_device(dss_of_match, &pdev->dev)->data; + dss->feat = device_get_match_data(&pdev->dev); /* Map I/O registers, get and setup clocks. */ dss->base = devm_platform_ioremap_resource(pdev, 0); diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index b2835b3ea6f58b..6598c9c08ba11e 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -69,7 +69,6 @@ static void omap_atomic_commit_tail(struct drm_atomic_state *old_state) { struct drm_device *dev = old_state->dev; struct omap_drm_private *priv = dev->dev_private; - bool fence_cookie = dma_fence_begin_signalling(); dispc_runtime_get(priv->dispc); @@ -92,6 +91,8 @@ static void omap_atomic_commit_tail(struct drm_atomic_state *old_state) omap_atomic_wait_for_completion(dev, old_state); drm_atomic_helper_commit_planes(dev, old_state, 0); + + drm_atomic_helper_commit_hw_done(old_state); } else { /* * OMAP3 DSS seems to have issues with the work-around above, @@ -101,11 +102,9 @@ static void omap_atomic_commit_tail(struct drm_atomic_state *old_state) drm_atomic_helper_commit_planes(dev, old_state, 0); drm_atomic_helper_commit_modeset_enables(dev, old_state); - } - drm_atomic_helper_commit_hw_done(old_state); - - dma_fence_end_signalling(fence_cookie); + drm_atomic_helper_commit_hw_done(old_state); + } /* * Wait for completion of the page flips to ensure that old buffers diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index c48fa531ca321c..3421e8389222a4 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -48,7 +48,7 @@ struct omap_gem_object { * OMAP_BO_MEM_DMA_API flag set) * * - buffers imported from dmabuf (with the OMAP_BO_MEM_DMABUF flag set) - * if they are physically contiguous (when sgt->orig_nents == 1) + * if they are physically contiguous * * - buffers mapped through the TILER when pin_cnt is not zero, in which * case the DMA address points to the TILER aperture @@ -148,12 +148,18 @@ u64 omap_gem_mmap_offset(struct drm_gem_object *obj) return drm_vma_node_offset_addr(&obj->vma_node); } +static bool omap_gem_sgt_is_contiguous(struct sg_table *sgt, size_t size) +{ + return !(drm_prime_get_contiguous_size(sgt) < size); +} + static bool omap_gem_is_contiguous(struct omap_gem_object *omap_obj) { if (omap_obj->flags & OMAP_BO_MEM_DMA_API) return true; - if ((omap_obj->flags & OMAP_BO_MEM_DMABUF) && omap_obj->sgt->nents == 1) + if ((omap_obj->flags & OMAP_BO_MEM_DMABUF) && + omap_gem_sgt_is_contiguous(omap_obj->sgt, omap_obj->base.size)) return true; return false; @@ -1385,7 +1391,7 @@ struct drm_gem_object *omap_gem_new_dmabuf(struct drm_device *dev, size_t size, union omap_gem_size gsize; /* Without a DMM only physically contiguous buffers can be supported. */ - if (sgt->orig_nents != 1 && !priv->has_dmm) + if (!omap_gem_sgt_is_contiguous(sgt, size) && !priv->has_dmm) return ERR_PTR(-EINVAL); gsize.bytes = PAGE_ALIGN(size); @@ -1399,7 +1405,7 @@ struct drm_gem_object *omap_gem_new_dmabuf(struct drm_device *dev, size_t size, omap_obj->sgt = sgt; - if (sgt->orig_nents == 1) { + if (omap_gem_sgt_is_contiguous(sgt, size)) { omap_obj->dma_addr = sg_dma_address(sgt->sgl); } else { /* Create pages list from sgt */ diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 99e14dc212ecbe..8f3783742208b6 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -194,6 +194,15 @@ config DRM_PANEL_ILITEK_ILI9341 QVGA (240x320) RGB panels. support serial & parallel rgb interface. +config DRM_PANEL_ILITEK_ILI9805 + tristate "Ilitek ILI9805-based 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 + Ilitek ILI9805 controller. + config DRM_PANEL_ILITEK_ILI9881C tristate "Ilitek ILI9881C-based panels" depends on OF @@ -530,6 +539,8 @@ config DRM_PANEL_RAYDIUM_RM692E5 depends on OF depends on DRM_MIPI_DSI depends on BACKLIGHT_CLASS_DEVICE + select DRM_DISPLAY_DP_HELPER + select DRM_DISPLAY_HELPER help Say Y here if you want to enable support for Raydium RM692E5-based display panels, such as the one found in the Fairphone 5 smartphone. @@ -735,6 +746,15 @@ config DRM_PANEL_SITRONIX_ST7789V Say Y here if you want to enable support for the Sitronix ST7789V controller for 240x320 LCD panels +config DRM_PANEL_SYNAPTICS_R63353 + tristate "Synaptics R63353-based 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 + Synaptics R63353 controller. + config DRM_PANEL_SONY_ACX565AKM tristate "Sony ACX565AKM panel" depends on GPIOLIB && OF && SPI diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index d10c3de51c6dba..d94a644d0a6cea 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_DRM_PANEL_FEIYANG_FY07024DI26A30D) += panel-feiyang-fy07024di26a30d 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_ILI9805) += panel-ilitek-ili9805.o obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9881C) += panel-ilitek-ili9881c.o obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9882T) += panel-ilitek-ili9882t.o obj-$(CONFIG_DRM_PANEL_INNOLUX_EJ030NA) += panel-innolux-ej030na.o @@ -74,6 +75,7 @@ obj-$(CONFIG_DRM_PANEL_SHARP_LS060T1SX01) += panel-sharp-ls060t1sx01.o obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7701) += panel-sitronix-st7701.o obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7703) += panel-sitronix-st7703.o obj-$(CONFIG_DRM_PANEL_SITRONIX_ST7789V) += panel-sitronix-st7789v.o +obj-$(CONFIG_DRM_PANEL_SYNAPTICS_R63353) += panel-synaptics-r63353.o obj-$(CONFIG_DRM_PANEL_SONY_ACX565AKM) += panel-sony-acx565akm.o obj-$(CONFIG_DRM_PANEL_SONY_TD4353_JDI) += panel-sony-td4353-jdi.o obj-$(CONFIG_DRM_PANEL_SONY_TULIP_TRULY_NT35521) += panel-sony-tulip-truly-nt35521.o diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index 95c8472d878a99..a0b6f69b916f92 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -203,6 +203,9 @@ struct edp_panel_entry { /** @name: Name of this panel (for printing to logs). */ const char *name; + + /** @override_edid_mode: Override the mode obtained by edid. */ + const struct drm_display_mode *override_edid_mode; }; struct panel_edp { @@ -301,6 +304,24 @@ static unsigned int panel_edp_get_display_modes(struct panel_edp *panel, return num; } +static int panel_edp_override_edid_mode(struct panel_edp *panel, + struct drm_connector *connector, + const struct drm_display_mode *override_mode) +{ + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(connector->dev, override_mode); + if (!mode) { + dev_err(panel->base.dev, "failed to add additional mode\n"); + return 0; + } + + mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; + drm_mode_set_name(mode); + drm_mode_probed_add(connector, mode); + return 1; +} + static int panel_edp_get_non_edid_modes(struct panel_edp *panel, struct drm_connector *connector) { @@ -568,6 +589,10 @@ static int panel_edp_get_modes(struct drm_panel *panel, { struct panel_edp *p = to_panel_edp(panel); int num = 0; + bool has_hard_coded_modes = p->desc->num_timings || p->desc->num_modes; + bool has_override_edid_mode = p->detected_panel && + p->detected_panel != ERR_PTR(-EINVAL) && + p->detected_panel->override_edid_mode; /* probe EDID if a DDC bus is available */ if (p->ddc) { @@ -575,20 +600,28 @@ static int panel_edp_get_modes(struct drm_panel *panel, if (!p->edid) p->edid = drm_get_edid(connector, p->ddc); - - if (p->edid) - num += drm_add_edid_modes(connector, p->edid); + /* + * If both edid and hard-coded modes exists, skip edid modes to + * avoid multiple preferred modes. + */ + if (p->edid && !has_hard_coded_modes) { + if (has_override_edid_mode) { + /* + * override_edid_mode is specified. Use + * override_edid_mode instead of from edid. + */ + num += panel_edp_override_edid_mode(p, connector, + p->detected_panel->override_edid_mode); + } else { + num += drm_add_edid_modes(connector, p->edid); + } + } pm_runtime_mark_last_busy(panel->dev); pm_runtime_put_autosuspend(panel->dev); } - /* - * Add hard-coded panel modes. Don't call this if there are no timings - * and no modes (the generic edp-panel case) because it will clobber - * the display_info that was already set by drm_add_edid_modes(). - */ - if (p->desc->num_timings || p->desc->num_modes) + if (has_hard_coded_modes) num += panel_edp_get_non_edid_modes(p, connector); else if (!num) dev_warn(p->base.dev, "No display modes\n"); @@ -950,6 +983,19 @@ static const struct panel_desc auo_b101ean01 = { }, }; +static const struct drm_display_mode auo_b116xa3_mode = { + .clock = 70589, + .hdisplay = 1366, + .hsync_start = 1366 + 40, + .hsync_end = 1366 + 40 + 40, + .htotal = 1366 + 40 + 40 + 32, + .vdisplay = 768, + .vsync_start = 768 + 10, + .vsync_end = 768 + 10 + 12, + .vtotal = 768 + 10 + 12 + 6, + .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC, +}; + static const struct drm_display_mode auo_b116xak01_mode = { .clock = 69300, .hdisplay = 1366, @@ -973,6 +1019,8 @@ static const struct panel_desc auo_b116xak01 = { }, .delay = { .hpd_absent = 200, + .unprepare = 500, + .enable = 50, }, }; @@ -1801,6 +1849,12 @@ static const struct panel_delay delay_200_500_e50 = { .enable = 50, }; +static const struct panel_delay delay_200_500_e80 = { + .hpd_absent = 200, + .unprepare = 500, + .enable = 80, +}; + static const struct panel_delay delay_200_500_e80_d50 = { .hpd_absent = 200, .unprepare = 500, @@ -1820,6 +1874,19 @@ static const struct panel_delay delay_200_500_e200 = { .enable = 200, }; +static const struct panel_delay delay_200_500_e200_d10 = { + .hpd_absent = 200, + .unprepare = 500, + .enable = 200, + .disable = 10, +}; + +static const struct panel_delay delay_200_150_e200 = { + .hpd_absent = 200, + .unprepare = 150, + .enable = 200, +}; + #define EDP_PANEL_ENTRY(vend_chr_0, vend_chr_1, vend_chr_2, product_id, _delay, _name) \ { \ .name = _name, \ @@ -1828,6 +1895,15 @@ static const struct panel_delay delay_200_500_e200 = { .delay = _delay \ } +#define EDP_PANEL_ENTRY2(vend_chr_0, vend_chr_1, vend_chr_2, product_id, _delay, _name, _mode) \ +{ \ + .name = _name, \ + .panel_id = drm_edid_encode_panel_id(vend_chr_0, vend_chr_1, vend_chr_2, \ + product_id), \ + .delay = _delay, \ + .override_edid_mode = _mode \ +} + /* * This table is used to figure out power sequencing delays for panels that * are detected by EDID. Entries here may point to entries in the @@ -1840,36 +1916,76 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('A', 'U', 'O', 0x145c, &delay_200_500_e50, "B116XAB01.4"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, &delay_200_500_e50, "B133UAN02.1"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x1ea5, &delay_200_500_e50, "B116XAK01.6"), - EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, &auo_b116xak01.delay, "B116XAK01"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x208d, &delay_200_500_e50, "B140HTN02.1"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x235c, &delay_200_500_e50, "B116XTN02.3"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x239b, &delay_200_500_e50, "B116XAN06.1"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x255c, &delay_200_500_e50, "B116XTN02.5"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x403d, &delay_200_500_e50, "B140HAN04.0"), + EDP_PANEL_ENTRY2('A', 'U', 'O', 0x405c, &auo_b116xak01.delay, "B116XAK01.0", + &auo_b116xa3_mode), EDP_PANEL_ENTRY('A', 'U', 'O', 0x582d, &delay_200_500_e50, "B133UAN01.0"), - EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, &delay_200_500_e50, "B116XAN06.1"), + EDP_PANEL_ENTRY2('A', 'U', 'O', 0x615c, &delay_200_500_e50, "B116XAN06.1", + &auo_b116xa3_mode), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x635c, &delay_200_500_e50, "B116XAN06.3"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0x639c, &delay_200_500_e50, "B140HAK02.7"), EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, &delay_200_500_e50, "B133UAN01.0"), + EDP_PANEL_ENTRY('A', 'U', 'O', 0xf390, &delay_200_500_e50, "B140XTN07.7"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0715, &delay_200_150_e200, "NT116WHM-N21"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0731, &delay_200_500_e80, "NT116WHM-N42"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0741, &delay_200_500_e200, "NT116WHM-N44"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0786, &delay_200_500_p2e80, "NV116WHM-T01"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x07d1, &boe_nv133fhm_n61.delay, "NV133FHM-N61"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x07f6, &delay_200_500_e200, "NT140FHM-N44"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x082d, &boe_nv133fhm_n61.delay, "NV133FHM-N62"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x08b2, &delay_200_500_e200, "NT140WHM-N49"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x09c3, &delay_200_500_e50, "NT116WHM-N21,836X2"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x094b, &delay_200_500_e50, "NT116WHM-N21"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0951, &delay_200_500_e80, "NV116WHM-N47"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x095f, &delay_200_500_e50, "NE135FBM-N41 v8.1"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0979, &delay_200_500_e50, "NV116WHM-N49 V8.0"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x098d, &boe_nv110wtm_n61.delay, "NV110WTM-N61"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x09ae, &delay_200_500_e200, "NT140FHM-N45"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x09dd, &delay_200_500_e50, "NT116WHM-N21"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a5d, &delay_200_500_e50, "NV116WHM-N45"), EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ac5, &delay_200_500_e50, "NV116WHM-N4C"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b43, &delay_200_500_e200, "NV140FHM-T09"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0b56, &delay_200_500_e80, "NT140FHM-N47"), + EDP_PANEL_ENTRY('B', 'O', 'E', 0x0c20, &delay_200_500_e80, "NT140FHM-N47"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1132, &delay_200_500_e80_d50, "N116BGE-EA2"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1138, &innolux_n116bca_ea1.delay, "N116BCA-EA1-RC4"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1139, &delay_200_500_e80_d50, "N116BGE-EA2"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1145, &delay_200_500_e80_d50, "N116BCN-EB1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x114c, &innolux_n116bca_ea1.delay, "N116BCA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1152, &delay_200_500_e80_d50, "N116BCN-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1153, &delay_200_500_e80_d50, "N116BGE-EA2"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1154, &delay_200_500_e80_d50, "N116BCA-EA2"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1157, &delay_200_500_e80_d50, "N116BGE-EA2"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x115b, &delay_200_500_e80_d50, "N116BCN-EB1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x1247, &delay_200_500_e80_d50, "N120ACA-EA1"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x142b, &delay_200_500_e80_d50, "N140HCA-EAC"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x144f, &delay_200_500_e80_d50, "N140HGA-EA1"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x1468, &delay_200_500_e80, "N140HGA-EA1"), EDP_PANEL_ENTRY('C', 'M', 'N', 0x14d4, &delay_200_500_e80_d50, "N140HCA-EAC"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x14d6, &delay_200_500_e80_d50, "N140BGA-EA4"), + EDP_PANEL_ENTRY('C', 'M', 'N', 0x14e5, &delay_200_500_e80_d50, "N140HGA-EA1"), + + EDP_PANEL_ENTRY('H', 'K', 'C', 0x2d5c, &delay_200_500_e200, "MB116AN01-2"), + EDP_PANEL_ENTRY('I', 'V', 'O', 0x048e, &delay_200_500_e200_d10, "M116NWR6 R5"), EDP_PANEL_ENTRY('I', 'V', 'O', 0x057d, &delay_200_500_e200, "R140NWF5 RH"), 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('I', 'V', 'O', 0x8c4d, &delay_200_150_e200, "R140NWFM R1"), 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"), + EDP_PANEL_ENTRY('K', 'D', 'C', 0x0809, &delay_200_500_e50, "KD116N2930A15"), + + EDP_PANEL_ENTRY('S', 'D', 'C', 0x416d, &delay_100_500_e200, "ATNA45AF01"), + EDP_PANEL_ENTRY('S', 'H', 'P', 0x1511, &delay_200_500_e50, "LQ140M1JW48"), EDP_PANEL_ENTRY('S', 'H', 'P', 0x1523, &sharp_lq140m1jw46.delay, "LQ140M1JW46"), EDP_PANEL_ENTRY('S', 'H', 'P', 0x154c, &delay_200_500_p2e100, "LQ116M1JW10"), diff --git a/drivers/gpu/drm/panel/panel-elida-kd35t133.c b/drivers/gpu/drm/panel/panel-elida-kd35t133.c index e7be15b681021e..00791ea81e90cd 100644 --- a/drivers/gpu/drm/panel/panel-elida-kd35t133.c +++ b/drivers/gpu/drm/panel/panel-elida-kd35t133.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Elida kd35t133 5.5" MIPI-DSI panel driver + * Elida kd35t133 3.5" MIPI-DSI panel driver * Copyright (C) 2020 Theobroma Systems Design und Consulting GmbH * * based on @@ -43,7 +43,6 @@ struct kd35t133 { struct regulator *vdd; struct regulator *iovcc; enum drm_panel_orientation orientation; - bool prepared; }; static inline struct kd35t133 *panel_to_kd35t133(struct drm_panel *panel) @@ -91,9 +90,6 @@ static int kd35t133_unprepare(struct drm_panel *panel) struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); int ret; - if (!ctx->prepared) - return 0; - ret = mipi_dsi_dcs_set_display_off(dsi); if (ret < 0) dev_err(ctx->dev, "failed to set display off: %d\n", ret); @@ -104,11 +100,11 @@ static int kd35t133_unprepare(struct drm_panel *panel) return ret; } + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_disable(ctx->iovcc); regulator_disable(ctx->vdd); - ctx->prepared = false; - return 0; } @@ -118,9 +114,6 @@ static int kd35t133_prepare(struct drm_panel *panel) struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); int ret; - if (ctx->prepared) - return 0; - dev_dbg(ctx->dev, "Resetting the panel\n"); ret = regulator_enable(ctx->vdd); if (ret < 0) { @@ -164,8 +157,6 @@ static int kd35t133_prepare(struct drm_panel *panel) msleep(50); - ctx->prepared = true; - return 0; disable_iovcc: @@ -209,11 +200,6 @@ static int kd35t133_get_modes(struct drm_panel *panel, connector->display_info.width_mm = mode->width_mm; connector->display_info.height_mm = mode->height_mm; drm_mode_probed_add(connector, mode); - /* - * TODO: Remove once all drm drivers call - * drm_connector_set_orientation_from_panel() - */ - drm_connector_set_panel_orientation(connector, ctx->orientation); return 1; } @@ -299,27 +285,11 @@ static int kd35t133_probe(struct mipi_dsi_device *dsi) return 0; } -static void kd35t133_shutdown(struct mipi_dsi_device *dsi) -{ - struct kd35t133 *ctx = mipi_dsi_get_drvdata(dsi); - int ret; - - ret = drm_panel_unprepare(&ctx->panel); - if (ret < 0) - dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret); - - ret = drm_panel_disable(&ctx->panel); - if (ret < 0) - dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret); -} - static void kd35t133_remove(struct mipi_dsi_device *dsi) { struct kd35t133 *ctx = mipi_dsi_get_drvdata(dsi); int ret; - kd35t133_shutdown(dsi); - ret = mipi_dsi_detach(dsi); if (ret < 0) dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); @@ -340,7 +310,6 @@ static struct mipi_dsi_driver kd35t133_driver = { }, .probe = kd35t133_probe, .remove = kd35t133_remove, - .shutdown = kd35t133_shutdown, }; module_mipi_dsi_driver(kd35t133_driver); diff --git a/drivers/gpu/drm/panel/panel-himax-hx8394.c b/drivers/gpu/drm/panel/panel-himax-hx8394.c index c73243d85de718..ff0dc08b98297a 100644 --- a/drivers/gpu/drm/panel/panel-himax-hx8394.c +++ b/drivers/gpu/drm/panel/panel-himax-hx8394.c @@ -38,6 +38,7 @@ #define HX8394_CMD_SETMIPI 0xba #define HX8394_CMD_SETOTP 0xbb #define HX8394_CMD_SETREGBANK 0xbd +#define HX8394_CMD_UNKNOWN5 0xbf #define HX8394_CMD_UNKNOWN1 0xc0 #define HX8394_CMD_SETDGCLUT 0xc1 #define HX8394_CMD_SETID 0xc3 @@ -52,6 +53,7 @@ #define HX8394_CMD_SETGIP1 0xd5 #define HX8394_CMD_SETGIP2 0xd6 #define HX8394_CMD_SETGPO 0xd6 +#define HX8394_CMD_UNKNOWN4 0xd8 #define HX8394_CMD_SETSCALING 0xdd #define HX8394_CMD_SETIDLE 0xdf #define HX8394_CMD_SETGAMMA 0xe0 @@ -68,7 +70,7 @@ struct hx8394 { struct gpio_desc *reset_gpio; struct regulator *vcc; struct regulator *iovcc; - bool prepared; + enum drm_panel_orientation orientation; const struct hx8394_panel_desc *desc; }; @@ -203,6 +205,140 @@ static const struct hx8394_panel_desc hsd060bhw4_desc = { .init_sequence = hsd060bhw4_init_sequence, }; +static int powkiddy_x55_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.9 SETMIPI: Set MIPI control (BAh) */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETMIPI, + 0x63, 0x03, 0x68, 0x6b, 0xb2, 0xc0); + + /* 5.19.2 SETPOWER: Set power (B1h) */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETPOWER, + 0x48, 0x12, 0x72, 0x09, 0x32, 0x54, 0x71, 0x71, 0x57, 0x47); + + /* 5.19.3 SETDISP: Set display related register (B2h) */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETDISP, + 0x00, 0x80, 0x64, 0x2c, 0x16, 0x2f); + + /* 5.19.4 SETCYC: Set display waveform cycles (B4h) */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETCYC, + 0x73, 0x74, 0x73, 0x74, 0x73, 0x74, 0x01, 0x0c, 0x86, 0x75, + 0x00, 0x3f, 0x73, 0x74, 0x73, 0x74, 0x73, 0x74, 0x01, 0x0c, + 0x86); + + /* 5.19.5 SETVCOM: Set VCOM voltage (B6h) */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETVCOM, + 0x6e, 0x6e); + + /* 5.19.19 SETGIP0: Set GIP Option0 (D3h) */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP0, + 0x00, 0x00, 0x07, 0x07, 0x40, 0x07, 0x0c, 0x00, 0x08, 0x10, + 0x08, 0x00, 0x08, 0x54, 0x15, 0x0a, 0x05, 0x0a, 0x02, 0x15, + 0x06, 0x05, 0x06, 0x47, 0x44, 0x0a, 0x0a, 0x4b, 0x10, 0x07, + 0x07, 0x0c, 0x40); + + /* 5.19.20 Set GIP Option1 (D5h) */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP1, + 0x1c, 0x1c, 0x1d, 0x1d, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x24, 0x25, 0x18, 0x18, + 0x26, 0x27, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x20, 0x21, + 0x18, 0x18, 0x18, 0x18); + + /* 5.19.21 Set GIP Option2 (D6h) */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGIP2, + 0x1c, 0x1c, 0x1d, 0x1d, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, + 0x01, 0x00, 0x0b, 0x0a, 0x09, 0x08, 0x21, 0x20, 0x18, 0x18, + 0x27, 0x26, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x25, 0x24, + 0x18, 0x18, 0x18, 0x18); + + /* 5.19.25 SETGAMMA: Set gamma curve related setting (E0h) */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETGAMMA, + 0x00, 0x0a, 0x15, 0x1b, 0x1e, 0x21, 0x24, 0x22, 0x47, 0x56, + 0x65, 0x66, 0x6e, 0x82, 0x88, 0x8b, 0x9a, 0x9d, 0x98, 0xa8, + 0xb9, 0x5d, 0x5c, 0x61, 0x66, 0x6a, 0x6f, 0x7f, 0x7f, 0x00, + 0x0a, 0x15, 0x1b, 0x1e, 0x21, 0x24, 0x22, 0x47, 0x56, 0x65, + 0x65, 0x6e, 0x81, 0x87, 0x8b, 0x98, 0x9d, 0x99, 0xa8, 0xba, + 0x5d, 0x5d, 0x62, 0x67, 0x6b, 0x72, 0x7f, 0x7f); + + /* Unknown command, not listed in the HX8394-F datasheet */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN1, + 0x1f, 0x31); + + /* 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_UNKNOWN3, + 0x02); + + /* 5.19.11 Set register bank (BDh) */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK, + 0x02); + + /* Unknown command, not listed in the HX8394-F datasheet */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN4, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff); + + /* 5.19.11 Set register bank (BDh) */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_SETREGBANK, + 0x00); + + /* 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_UNKNOWN5, + 0x40, 0x81, 0x50, 0x00, 0x1a, 0xfc, 0x01); + + /* Unknown command, not listed in the HX8394-F datasheet */ + mipi_dsi_dcs_write_seq(dsi, HX8394_CMD_UNKNOWN2, + 0xed); + + return 0; +} + +static const struct drm_display_mode powkiddy_x55_mode = { + .hdisplay = 720, + .hsync_start = 720 + 44, + .hsync_end = 720 + 44 + 20, + .htotal = 720 + 44 + 20 + 20, + .vdisplay = 1280, + .vsync_start = 1280 + 12, + .vsync_end = 1280 + 12 + 10, + .vtotal = 1280 + 12 + 10 + 10, + .clock = 63290, + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, + .width_mm = 67, + .height_mm = 121, +}; + +static const struct hx8394_panel_desc powkiddy_x55_desc = { + .mode = &powkiddy_x55_mode, + .lanes = 4, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET, + .format = MIPI_DSI_FMT_RGB888, + .init_sequence = powkiddy_x55_init_sequence, +}; + static int hx8394_enable(struct drm_panel *panel) { struct hx8394 *ctx = panel_to_hx8394(panel); @@ -262,16 +398,11 @@ 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; } @@ -280,9 +411,6 @@ 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); @@ -301,8 +429,6 @@ static int hx8394_prepare(struct drm_panel *panel) msleep(180); - ctx->prepared = true; - return 0; disable_vcc: @@ -335,12 +461,20 @@ static int hx8394_get_modes(struct drm_panel *panel, return 1; } +static enum drm_panel_orientation hx8394_get_orientation(struct drm_panel *panel) +{ + struct hx8394 *ctx = panel_to_hx8394(panel); + + return ctx->orientation; +} + 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, + .get_orientation = hx8394_get_orientation, }; static int hx8394_probe(struct mipi_dsi_device *dsi) @@ -358,6 +492,12 @@ static int hx8394_probe(struct mipi_dsi_device *dsi) return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "Failed to get reset gpio\n"); + ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation); + if (ret < 0) { + dev_err(dev, "%pOF: failed to get orientation %d\n", dev->of_node, ret); + return ret; + } + mipi_dsi_set_drvdata(dsi, ctx); ctx->dev = dev; @@ -401,27 +541,11 @@ static int hx8394_probe(struct mipi_dsi_device *dsi) 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); @@ -431,6 +555,7 @@ static void hx8394_remove(struct mipi_dsi_device *dsi) static const struct of_device_id hx8394_of_match[] = { { .compatible = "hannstar,hsd060bhw4", .data = &hsd060bhw4_desc }, + { .compatible = "powkiddy,x55-panel", .data = &powkiddy_x55_desc }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, hx8394_of_match); @@ -438,7 +563,6 @@ 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, diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9805.c b/drivers/gpu/drm/panel/panel-ilitek-ili9805.c new file mode 100644 index 00000000000000..1cbc25758bd2bc --- /dev/null +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9805.c @@ -0,0 +1,405 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 BSH Hausgerate GmbH + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include